From b0445d145952b6d9a058860e1891a74852a68e18 Mon Sep 17 00:00:00 2001 From: Shivendra Kakrania Date: Mon, 5 Mar 2018 11:46:05 -0800 Subject: [PATCH 0001/1635] msm: vidc: Updating Video BW calculations for SM8150 Updatng video bandwidth calculations for video session. These changes are for SM8150. CRs-Fixed: 2201248 Change-Id: Ic3c8531db21ab2e30e197faa4f021da1f133242d Signed-off-by: Shivendra Kakrania --- .../msm/vidc/governors/msm_vidc_dyn_gov.c | 471 +++++++++--------- .../platform/msm/vidc/msm_vidc_platform.c | 2 +- 2 files changed, 235 insertions(+), 238 deletions(-) diff --git a/drivers/media/platform/msm/vidc/governors/msm_vidc_dyn_gov.c b/drivers/media/platform/msm/vidc/governors/msm_vidc_dyn_gov.c index f7234de25fd7..d0601e1cdfdd 100644 --- a/drivers/media/platform/msm/vidc/governors/msm_vidc_dyn_gov.c +++ b/drivers/media/platform/msm/vidc/governors/msm_vidc_dyn_gov.c @@ -332,6 +332,7 @@ static int __bpp(enum hal_uncompressed_format f) case HAL_COLOR_FORMAT_NV12_UBWC: return 8; case HAL_COLOR_FORMAT_NV12_TP10_UBWC: + case HAL_COLOR_FORMAT_P010: return 10; default: dprintk(VIDC_ERR, @@ -350,34 +351,35 @@ static unsigned long __calculate_decoder(struct vidc_bus_vote_data *d, * measured heuristics and hardcoded numbers taken from the firmware. */ /* Decoder parameters */ - int width, height, lcu_size, dpb_bpp, opb_bpp, fps, opb_factor; - bool unified_dpb_opb, dpb_compression_enabled, opb_compression_enabled, + int width, height, lcu_size, fps, dpb_bpp; + bool unified_dpb_opb, dpb_compression_enabled, + opb_compression_enabled = false, llc_ref_read_l2_cache_enabled = false, - llc_vpss_ds_line_buf_enabled = false; - fp_t dpb_opb_scaling_ratio, dpb_read_compression_factor, - dpb_write_compression_factor, opb_compression_factor, - qsmmu_bw_overhead_factor, height_ratio; + llc_top_line_buf_enabled = false; + fp_t dpb_read_compression_factor, dpb_opb_scaling_ratio, + dpb_write_compression_factor, opb_write_compression_factor, + qsmmu_bw_overhead_factor; /* Derived parameters */ - int lcu_per_frame, tnbr_per_lcu, colocated_bytes_per_lcu; + int lcu_per_frame, collocated_bytes_per_lcu, tnbr_per_lcu; unsigned long bitrate; - fp_t bins_to_bit_factor, dpb_write_factor, ten_bpc_packing_factor, - ten_bpc_bpp_factor, vsp_read_factor, vsp_write_factor, - bw_for_1x_8bpc, dpb_bw_for_1x, - motion_vector_complexity = 0, row_cache_penalty = 0, opb_bw = 0, - dpb_total = 0; + fp_t bins_to_bit_factor, vsp_read_factor, vsp_write_factor, + dpb_factor, dpb_write_factor, + y_bw_no_ubwc_8bpp, y_bw_no_ubwc_10bpp, + motion_vector_complexity = 0; + fp_t dpb_total = 0; /* Output parameters */ struct { fp_t vsp_read, vsp_write, collocated_read, collocated_write, - line_buffer_read, line_buffer_write, recon_read, - recon_write, opb_read, opb_write, dpb_read, dpb_write, + dpb_read, dpb_write, opb_read, opb_write, + line_buffer_read, line_buffer_write, total; } ddr = {0}; struct { - fp_t dpb_read, opb_read, total; + fp_t dpb_read, line_buffer_read, line_buffer_write, total; } llc = {0}; unsigned long ret = 0; @@ -386,31 +388,27 @@ static unsigned long __calculate_decoder(struct vidc_bus_vote_data *d, width = max(d->input_width, BASELINE_DIMENSIONS.width); height = max(d->input_height, BASELINE_DIMENSIONS.height); + fps = d->fps; + lcu_size = d->lcu_size; dpb_bpp = d->num_formats >= 1 ? __bpp(d->color_formats[0]) : INT_MAX; - opb_bpp = d->num_formats >= 2 ? __bpp(d->color_formats[1]) : dpb_bpp; - - fps = d->fps; unified_dpb_opb = d->num_formats == 1; dpb_opb_scaling_ratio = fp_div(FP_INT(d->input_width * d->input_height), FP_INT(d->output_width * d->output_height)); - height_ratio = fp_div(d->input_height, d->output_height); - dpb_compression_enabled = d->num_formats >= 1 && - __ubwc(d->color_formats[0]); opb_compression_enabled = d->num_formats >= 2 && __ubwc(d->color_formats[1]); /* - * Convert Q16 number into Integer and Fractional part upto 2 places. - * Ex : 105752 / 65536 = 1.61; 1.61 in Q16 = 105752; - * Integer part = 105752 / 65536 = 1; - * Reminder = 105752 - 1 * 65536 = 40216; - * Fractional part = 40216 * 100 / 65536 = 61; - * Now converto to FP(1, 61, 100) for below code. + * convert q16 number into integer and fractional part upto 2 places. + * ex : 105752 / 65536 = 1.61; 1.61 in q16 = 105752; + * integer part = 105752 / 65536 = 1; + * reminder = 105752 - 1 * 65536 = 40216; + * fractional part = 40216 * 100 / 65536 = 61; + * now converto to fp(1, 61, 100) for below code. */ integer_part = d->compression_ratio >> 16; @@ -426,19 +424,18 @@ static unsigned long __calculate_decoder(struct vidc_bus_vote_data *d, motion_vector_complexity = FP(integer_part, frac_part, 100); dpb_write_compression_factor = !dpb_compression_enabled ? FP_ONE : - __compression_ratio(__lut(width, height, fps), opb_bpp); + __compression_ratio(__lut(width, height, fps), dpb_bpp); dpb_write_compression_factor = d->use_dpb_read ? dpb_read_compression_factor : dpb_write_compression_factor; + opb_write_compression_factor = opb_compression_enabled ? + dpb_write_compression_factor : FP_ONE; - opb_compression_factor = !opb_compression_enabled ? FP_ONE : - __compression_ratio(__lut(width, height, fps), opb_bpp); - - llc_ref_read_l2_cache_enabled = llc_vpss_ds_line_buf_enabled = false; if (d->use_sys_cache) { llc_ref_read_l2_cache_enabled = true; - llc_vpss_ds_line_buf_enabled = true; + if (d->codec == HAL_VIDEO_CODEC_H264) + llc_top_line_buf_enabled = true; } /* Derived parameters setup */ @@ -449,142 +446,135 @@ static unsigned long __calculate_decoder(struct vidc_bus_vote_data *d, bins_to_bit_factor = d->work_mode == VIDC_WORK_MODE_1 ? FP_INT(0) : FP_INT(4); - + vsp_write_factor = bins_to_bit_factor; vsp_read_factor = bins_to_bit_factor + FP_INT(2); - dpb_write_factor = FP(1, 5, 100); - - ten_bpc_packing_factor = FP(1, 67, 1000); - ten_bpc_bpp_factor = FP(1, 1, 4); + collocated_bytes_per_lcu = lcu_size == 16 ? 16 : + lcu_size == 32 ? 64 : 256; - vsp_write_factor = bins_to_bit_factor; + dpb_factor = FP(1, 50, 100); + dpb_write_factor = FP(1, 5, 100); tnbr_per_lcu = lcu_size == 16 ? 128 : lcu_size == 32 ? 64 : 128; - colocated_bytes_per_lcu = lcu_size == 16 ? 16 : - lcu_size == 32 ? 64 : 256; - - /* ........................................ for DDR */ + /* .... For DDR & LLC ...... */ ddr.vsp_read = fp_div(fp_mult(FP_INT(bitrate), vsp_read_factor), FP_INT(8)); ddr.vsp_write = fp_div(fp_mult(FP_INT(bitrate), vsp_write_factor), FP_INT(8)); ddr.collocated_read = FP_INT(lcu_per_frame * - colocated_bytes_per_lcu * fps / bps(1)); - ddr.collocated_write = FP_INT(lcu_per_frame * - colocated_bytes_per_lcu * fps / bps(1)); - - ddr.line_buffer_read = FP_INT(tnbr_per_lcu * - lcu_per_frame * fps / bps(1)); - ddr.line_buffer_write = ddr.line_buffer_read; - - bw_for_1x_8bpc = fp_div(FP_INT(width * height), FP_INT(32 * 8)); - - bw_for_1x_8bpc = fp_mult(bw_for_1x_8bpc, - fp_div(FP_INT(((int)(256 * fps))), FP_INT(1000 * 1000))); + collocated_bytes_per_lcu * fps / bps(1)); + ddr.collocated_write = ddr.collocated_read; - dpb_bw_for_1x = dpb_bpp == 8 ? bw_for_1x_8bpc : - fp_mult(bw_for_1x_8bpc, fp_mult(ten_bpc_packing_factor, - ten_bpc_bpp_factor)); + y_bw_no_ubwc_8bpp = fp_div(fp_div(fp_mult( + FP_INT((int)(width * height)), FP_INT((int)(256 * fps))), + FP_INT(32 * 8)), FP_INT(1000 * 1000)); + y_bw_no_ubwc_10bpp = fp_div(fp_div(fp_mult( + FP_INT((int)(width * height)), FP_INT((int)(256 * fps))), + FP_INT(48 * 4)), FP_INT(1000 * 1000)); - ddr.dpb_read = fp_div(fp_mult(fp_mult(dpb_bw_for_1x, - motion_vector_complexity), dpb_write_factor), + ddr.dpb_read = dpb_bpp == 8 ? y_bw_no_ubwc_8bpp : y_bw_no_ubwc_10bpp; + ddr.dpb_read = fp_div(fp_mult(ddr.dpb_read, + fp_mult(dpb_factor, motion_vector_complexity)), dpb_read_compression_factor); - ddr.dpb_write = fp_div(fp_mult(dpb_bw_for_1x, dpb_write_factor), - dpb_write_compression_factor); + ddr.dpb_write = dpb_bpp == 8 ? y_bw_no_ubwc_8bpp : y_bw_no_ubwc_10bpp; + ddr.dpb_write = fp_div(fp_mult(ddr.dpb_write, + fp_mult(dpb_factor, dpb_write_factor)), + dpb_write_compression_factor); + dpb_total = ddr.dpb_read + ddr.dpb_write; + if (llc_ref_read_l2_cache_enabled) { - row_cache_penalty = FP(1, 30, 100); - ddr.dpb_read = fp_div(ddr.dpb_read, row_cache_penalty); + ddr.dpb_read = fp_div(ddr.dpb_read, + d->codec == HAL_VIDEO_CODEC_H264 ? FP(0, 15, 100) : + FP(0, 30, 100)); llc.dpb_read = dpb_total - ddr.dpb_read; } - opb_factor = dpb_bpp == 8 ? 8 : 4; - - ddr.opb_read = unified_dpb_opb ? 0 : opb_compression_enabled ? - fp_div(fp_mult(fp_div(dpb_bw_for_1x, dpb_opb_scaling_ratio), - FP_INT(opb_factor)), height_ratio) : 0; - ddr.opb_write = unified_dpb_opb ? 0 : opb_compression_enabled ? - ddr.dpb_read : fp_div(fp_div(fp_mult(dpb_bw_for_1x, - FP(1, 50, 100)), dpb_opb_scaling_ratio), - opb_compression_factor); + ddr.opb_read = FP_ZERO; + ddr.opb_write = unified_dpb_opb ? FP_ZERO : (dpb_bpp == 8 ? + y_bw_no_ubwc_8bpp : y_bw_no_ubwc_10bpp); + ddr.opb_write = fp_div(ddr.opb_write, + fp_mult(dpb_opb_scaling_ratio, opb_write_compression_factor)); - if (llc_vpss_ds_line_buf_enabled) { - llc.opb_read = ddr.opb_read; - ddr.opb_write -= ddr.opb_read; - ddr.opb_read = 0; + ddr.line_buffer_read = FP_INT(tnbr_per_lcu * + lcu_per_frame * fps / bps(1)); + ddr.line_buffer_write = ddr.line_buffer_read; + if (llc_top_line_buf_enabled) { + llc.line_buffer_read = ddr.line_buffer_read; + llc.line_buffer_write = ddr.line_buffer_write; + ddr.line_buffer_write = ddr.line_buffer_read = FP_ZERO; } + ddr.total = ddr.vsp_read + ddr.vsp_write + ddr.collocated_read + ddr.collocated_write + + ddr.dpb_read + ddr.dpb_write + ddr.opb_read + ddr.opb_write + - ddr.dpb_read + ddr.dpb_write; + ddr.line_buffer_read + ddr.line_buffer_write; qsmmu_bw_overhead_factor = FP(1, 3, 100); ddr.total = fp_mult(ddr.total, qsmmu_bw_overhead_factor); - llc.total = llc.dpb_read + llc.opb_read; + llc.total = llc.dpb_read + llc.line_buffer_read + llc.line_buffer_write; /* Dump all the variables for easier debugging */ if (debug) { struct dump dump[] = { {"DECODER PARAMETERS", "", DUMP_HEADER_MAGIC}, - {"LCU size", "%d", lcu_size}, - {"DPB bitdepth", "%d", dpb_bpp}, + {"lcu size", "%d", lcu_size}, + {"dpb bitdepth", "%d", dpb_bpp}, {"frame rate", "%d", fps}, - {"DPB/OPB unified", "%d", unified_dpb_opb}, - {"DPB/OPB downscaling ratio", DUMP_FP_FMT, + {"dpb/opb unified", "%d", unified_dpb_opb}, + {"dpb/opb downscaling ratio", DUMP_FP_FMT, dpb_opb_scaling_ratio}, - {"DPB compression", "%d", dpb_compression_enabled}, - {"OPB compression", "%d", opb_compression_enabled}, - {"DPB Read compression factor", DUMP_FP_FMT, + {"dpb compression", "%d", dpb_compression_enabled}, + {"opb compression", "%d", opb_compression_enabled}, + {"dpb read compression factor", DUMP_FP_FMT, dpb_read_compression_factor}, - {"DPB Write compression factor", DUMP_FP_FMT, + {"dpb write compression factor", DUMP_FP_FMT, dpb_write_compression_factor}, - {"OPB compression factor", DUMP_FP_FMT, - opb_compression_factor}, {"frame width", "%d", width}, {"frame height", "%d", height}, + {"llc ref read l2 cache enabled", "%d", + llc_ref_read_l2_cache_enabled}, + {"llc top line buf enabled", "%d", + llc_top_line_buf_enabled}, {"DERIVED PARAMETERS (1)", "", DUMP_HEADER_MAGIC}, - {"LCUs/frame", "%d", lcu_per_frame}, + {"lcus/frame", "%d", lcu_per_frame}, {"bitrate (Mbit/sec)", "%d", bitrate}, {"bins to bit factor", DUMP_FP_FMT, bins_to_bit_factor}, - {"DPB write factor", DUMP_FP_FMT, dpb_write_factor}, - {"10bpc packing factor", DUMP_FP_FMT, - ten_bpc_packing_factor}, - {"10bpc,BPP factor", DUMP_FP_FMT, ten_bpc_bpp_factor}, - {"VSP read factor", DUMP_FP_FMT, vsp_read_factor}, - {"VSP write factor", DUMP_FP_FMT, vsp_write_factor}, - {"TNBR/LCU", "%d", tnbr_per_lcu}, - {"colocated bytes/LCU", "%d", colocated_bytes_per_lcu}, - {"B/W for 1x (NV12 8bpc)", DUMP_FP_FMT, bw_for_1x_8bpc}, - {"DPB B/W For 1x (NV12)", DUMP_FP_FMT, dpb_bw_for_1x}, + {"dpb write factor", DUMP_FP_FMT, dpb_write_factor}, + {"vsp read factor", DUMP_FP_FMT, vsp_read_factor}, + {"vsp write factor", DUMP_FP_FMT, vsp_write_factor}, + {"tnbr/lcu", "%d", tnbr_per_lcu}, + {"collocated bytes/LCU", "%d", collocated_bytes_per_lcu}, + {"bw for NV12 8bpc)", DUMP_FP_FMT, y_bw_no_ubwc_8bpp}, + {"bw for NV12 10bpc)", DUMP_FP_FMT, y_bw_no_ubwc_10bpp}, {"DERIVED PARAMETERS (2)", "", DUMP_HEADER_MAGIC}, - {"MV complexity", DUMP_FP_FMT, motion_vector_complexity}, - {"row cache penalty", DUMP_FP_FMT, row_cache_penalty}, + {"mv complexity", DUMP_FP_FMT, motion_vector_complexity}, {"qsmmu_bw_overhead_factor", DUMP_FP_FMT, qsmmu_bw_overhead_factor}, - {"OPB B/W (single instance)", DUMP_FP_FMT, opb_bw}, {"INTERMEDIATE DDR B/W", "", DUMP_HEADER_MAGIC}, - {"VSP read", DUMP_FP_FMT, ddr.vsp_read}, - {"VSP write", DUMP_FP_FMT, ddr.vsp_write}, + {"vsp read", DUMP_FP_FMT, ddr.vsp_read}, + {"vsp write", DUMP_FP_FMT, ddr.vsp_write}, {"collocated read", DUMP_FP_FMT, ddr.collocated_read}, {"collocated write", DUMP_FP_FMT, ddr.collocated_write}, {"line buffer read", DUMP_FP_FMT, ddr.line_buffer_read}, {"line buffer write", DUMP_FP_FMT, ddr.line_buffer_write}, - {"recon read", DUMP_FP_FMT, ddr.recon_read}, - {"recon write", DUMP_FP_FMT, ddr.recon_write}, - {"OPB read", DUMP_FP_FMT, ddr.opb_read}, - {"OPB write", DUMP_FP_FMT, ddr.opb_write}, - {"DPB read", DUMP_FP_FMT, ddr.dpb_read}, - {"DPB write", DUMP_FP_FMT, ddr.dpb_write}, - {"LLC DPB read", DUMP_FP_FMT, llc.dpb_read}, - {"LLC OPB read", DUMP_FP_FMT, llc.opb_read}, + {"opb read", DUMP_FP_FMT, ddr.opb_read}, + {"opb write", DUMP_FP_FMT, ddr.opb_write}, + {"dpb read", DUMP_FP_FMT, ddr.dpb_read}, + {"dbb write", DUMP_FP_FMT, ddr.dpb_write}, + {"INTERMEDIATE LLC B/W", "", DUMP_HEADER_MAGIC}, + {"llc dpb read", DUMP_FP_FMT, llc.dpb_read}, + {"llc line buffer read", DUMP_FP_FMT, llc.line_buffer_read}, + {"llc line buffer write", DUMP_FP_FMT, llc.line_buffer_write}, }; __dump(dump, ARRAY_SIZE(dump)); @@ -613,76 +603,88 @@ static unsigned long __calculate_encoder(struct vidc_bus_vote_data *d, * measured heuristics and hardcoded numbers taken from the firmware. */ /* Encoder Parameters */ - - int width, height, fps, dpb_bpp, lcu_per_frame, lcu_size, - vertical_tile_width, colocated_bytes_per_lcu, bitrate, - ref_overlap_bw_factor; - enum hal_uncompressed_format dpb_color_format, original_color_format; - bool dpb_compression_enabled, original_compression_enabled, - work_mode_1, low_power, rotation, cropping_or_scaling, + int width, height, fps, lcu_size, bitrate, lcu_per_frame, + collocated_bytes_per_lcu, tnbr_per_lcu, dpb_bpp, + original_color_format, dpb_ubwc_tile_width, + dpb_ubwc_tile_height, vertical_tile_width; + bool work_mode_1, original_compression_enabled, + low_power, rotation, cropping_or_scaling, b_frames_enabled = false, - llc_dual_core_ref_read_buf_enabled = false, + llc_ref_chroma_cache_enabled = false, llc_top_line_buf_enabled = false, - llc_ref_chroma_cache_enabled = false; - fp_t dpb_compression_factor, original_compression_factor, - input_compression_factor, qsmmu_bw_overhead_factor, - ref_y_bw_factor, ref_cb_cr_bw_factor, ten_bpc_bpp_factor, - bw_for_1x_8bpc, dpb_bw_for_1x, ref_cb_cr_read, - bins_to_bit_factor, ref_y_read, ten_bpc_packing_factor, - dpb_write_factor, ref_overlap_bw, llc_ref_y_read, - llc_ref_cb_cr_read; + llc_vpss_rot_line_buf_enabled = false; + + fp_t bins_to_bit_factor, dpb_compression_factor, + original_compression_factor, + y_bw_no_ubwc_8bpp, y_bw_no_ubwc_10bpp, + input_compression_factor, + ref_y_read_bw_factor, ref_cbcr_read_bw_factor, + recon_write_bw_factor, mese_read_factor, + total_ref_read_crcb, + qsmmu_bw_overhead_factor; fp_t integer_part, frac_part; unsigned long ret = 0; /* Output parameters */ struct { fp_t vsp_read, vsp_write, collocated_read, collocated_write, - line_buffer_read, line_buffer_write, original_read, - original_write, dpb_read, dpb_write, total; + ref_read_y, ref_read_crcb, ref_write, + ref_write_overlap, orig_read, + line_buffer_read, line_buffer_write, + mese_read, mese_write, + total; } ddr = {0}; struct { - fp_t dpb_read, line_buffer, total; + fp_t ref_read_crcb, line_buffer, total; } llc = {0}; /* Encoder Parameters setup */ - ten_bpc_packing_factor = FP(1, 67, 1000); - ten_bpc_bpp_factor = FP(1, 1, 4); rotation = false; cropping_or_scaling = false; vertical_tile_width = 960; - ref_y_bw_factor = FP(1, 30, 100); - ref_cb_cr_bw_factor = FP(1, 50, 100); - dpb_write_factor = FP(1, 8, 100); + recon_write_bw_factor = FP(1, 8, 100); + ref_y_read_bw_factor = FP(1, 30, 100); + ref_cbcr_read_bw_factor = FP(1, 50, 100); /* Derived Parameters */ - lcu_size = d->lcu_size; fps = d->fps; - b_frames_enabled = d->b_frames_enabled; width = max(d->input_width, BASELINE_DIMENSIONS.width); height = max(d->input_height, BASELINE_DIMENSIONS.height); bitrate = __lut(width, height, fps)->bitrate; + lcu_size = d->lcu_size; lcu_per_frame = DIV_ROUND_UP(width, lcu_size) * DIV_ROUND_UP(height, lcu_size); + tnbr_per_lcu = lcu_size == 16 ? 128 : + lcu_size == 32 ? 64 : 128; + + y_bw_no_ubwc_8bpp = fp_div(fp_div(fp_mult( + FP_INT((int)(width * height)), FP_INT((int)(256 * fps))), + FP_INT(32 * 8)), FP_INT(1000 * 1000)); + y_bw_no_ubwc_10bpp = fp_div(fp_div(fp_mult( + FP_INT((int)(width * height)), FP_INT((int)(256 * fps))), + FP_INT(48 * 4)), FP_INT(1000 * 1000)); - dpb_color_format = HAL_COLOR_FORMAT_NV12_UBWC; + b_frames_enabled = d->b_frames_enabled; original_color_format = d->num_formats >= 1 ? d->color_formats[0] : HAL_UNUSED_COLOR; dpb_bpp = d->num_formats >= 1 ? __bpp(d->color_formats[0]) : INT_MAX; - dpb_compression_enabled = __ubwc(dpb_color_format); original_compression_enabled = __ubwc(original_color_format); work_mode_1 = d->work_mode == VIDC_WORK_MODE_1; low_power = d->power_mode == VIDC_POWER_LOW; bins_to_bit_factor = work_mode_1 ? FP_INT(0) : FP_INT(4); + dpb_ubwc_tile_width = dpb_bpp == 8 ? 32 : 48; + dpb_ubwc_tile_height = dpb_bpp == 8 ? 8 : 4; if (d->use_sys_cache) { - llc_dual_core_ref_read_buf_enabled = true; llc_ref_chroma_cache_enabled = true; + llc_top_line_buf_enabled = true, + llc_vpss_rot_line_buf_enabled = true; } /* @@ -711,103 +713,89 @@ static unsigned long __calculate_encoder(struct vidc_bus_vote_data *d, dpb_compression_factor : input_compression_factor : FP_ONE; - ddr.vsp_read = fp_mult(fp_div(FP_INT(bitrate), FP_INT(8)), - bins_to_bit_factor); + mese_read_factor = fp_div(FP_INT((width * height * fps)/4), + original_compression_factor); + mese_read_factor = fp_div(fp_mult(mese_read_factor, FP(2, 53, 100)), + FP_INT(1000 * 1000)); + + ddr.vsp_read = fp_div(fp_mult(FP_INT(bitrate), bins_to_bit_factor), + FP_INT(8)); ddr.vsp_write = ddr.vsp_read + fp_div(FP_INT(bitrate), FP_INT(8)); - colocated_bytes_per_lcu = lcu_size == 16 ? 16 : + collocated_bytes_per_lcu = lcu_size == 16 ? 16 : lcu_size == 32 ? 64 : 256; ddr.collocated_read = FP_INT(lcu_per_frame * - colocated_bytes_per_lcu * fps / bps(1)); + collocated_bytes_per_lcu * fps / bps(1)); ddr.collocated_write = ddr.collocated_read; - ddr.line_buffer_read = FP_INT(16 * lcu_per_frame * fps / bps(1)); + ddr.ref_read_y = ddr.ref_read_crcb = dpb_bpp == 8 ? + y_bw_no_ubwc_8bpp : y_bw_no_ubwc_10bpp; - ddr.line_buffer_write = ddr.line_buffer_read; + if (width != vertical_tile_width) { + ddr.ref_read_y = fp_mult(ddr.ref_read_y, + ref_y_read_bw_factor); + } - llc.line_buffer = ddr.line_buffer_read + ddr.line_buffer_write; - if (llc_top_line_buf_enabled) - ddr.line_buffer_read = ddr.line_buffer_write = FP_INT(0); + ddr.ref_read_y = fp_div(ddr.ref_read_y, dpb_compression_factor); + if (b_frames_enabled) + ddr.ref_read_y = fp_mult(ddr.ref_read_y, FP_INT(2)); - llc.line_buffer -= (ddr.line_buffer_read + ddr.line_buffer_write); + ddr.ref_read_crcb = fp_mult(ddr.ref_read_crcb, FP(0, 50, 100)); + ddr.ref_read_crcb = fp_div(ddr.ref_read_crcb, dpb_compression_factor); + if (b_frames_enabled) + ddr.ref_read_crcb = fp_mult(ddr.ref_read_crcb, FP_INT(2)); - bw_for_1x_8bpc = fp_div(FP_INT(width * height), FP_INT(32 * 8)); + if (llc_ref_chroma_cache_enabled) { + total_ref_read_crcb = ddr.ref_read_crcb; + ddr.ref_read_crcb = fp_div(ddr.ref_read_crcb, + ref_cbcr_read_bw_factor); + llc.ref_read_crcb = total_ref_read_crcb - ddr.ref_read_crcb; + } - bw_for_1x_8bpc = fp_mult(bw_for_1x_8bpc, - fp_div(FP_INT(((int)(256 * fps))), FP_INT(1000 * 1000))); + ddr.ref_write = dpb_bpp == 8 ? y_bw_no_ubwc_8bpp : y_bw_no_ubwc_10bpp; + ddr.ref_write = fp_mult(ddr.ref_write, + (fp_div(FP(1, 50, 100), dpb_compression_factor))); - dpb_bw_for_1x = dpb_bpp == 8 ? bw_for_1x_8bpc : - fp_mult(bw_for_1x_8bpc, fp_mult(ten_bpc_packing_factor, - ten_bpc_bpp_factor)); + ddr.ref_write_overlap = fp_div(fp_mult(ddr.ref_write, + (recon_write_bw_factor - FP_ONE)), + recon_write_bw_factor); - ddr.original_read = fp_div(fp_mult(FP(1, 50, 100), dpb_bw_for_1x), + ddr.orig_read = dpb_bpp == 8 ? y_bw_no_ubwc_8bpp : y_bw_no_ubwc_10bpp; + ddr.orig_read = fp_div(fp_mult(ddr.orig_read, FP(1, 50, 100)), input_compression_factor); - ddr.original_write = FP_ZERO; - - ref_y_bw_factor = - width == vertical_tile_width ? FP_INT(1) : ref_y_bw_factor; - - ref_y_read = fp_mult(ref_y_bw_factor, dpb_bw_for_1x); - - ref_y_read = fp_div(ref_y_read, dpb_compression_factor); - - ref_y_read = - b_frames_enabled ? fp_mult(ref_y_read, FP_INT(2)) : ref_y_read; - - llc_ref_y_read = ref_y_read; - if (llc_dual_core_ref_read_buf_enabled) - ref_y_read = fp_div(ref_y_read, FP_INT(2)); - - llc_ref_y_read -= ref_y_read; - - ref_cb_cr_read = fp_mult(ref_cb_cr_bw_factor, dpb_bw_for_1x); - - ref_cb_cr_read = fp_div(ref_cb_cr_read, dpb_compression_factor); - - ref_cb_cr_read = - b_frames_enabled ? fp_mult(ref_cb_cr_read, FP_INT(2)) : - ref_cb_cr_read; - - llc_ref_cb_cr_read = ref_cb_cr_read; - - if (llc_ref_chroma_cache_enabled) - ref_cb_cr_read = fp_div(ref_cb_cr_read, ref_cb_cr_bw_factor); - - if (llc_dual_core_ref_read_buf_enabled) - ref_cb_cr_read = fp_div(ref_cb_cr_read, FP_INT(2)); - - llc_ref_cb_cr_read -= ref_cb_cr_read; + ddr.line_buffer_read = FP_INT(tnbr_per_lcu * lcu_per_frame * + fps / bps(1)); - ddr.dpb_write = fp_mult(dpb_write_factor, dpb_bw_for_1x); - - ddr.dpb_write = fp_mult(ddr.dpb_write, FP(1, 50, 100)); - - ddr.dpb_write = fp_div(ddr.dpb_write, input_compression_factor); - - ref_overlap_bw_factor = - width <= vertical_tile_width ? FP_INT(0) : FP_INT(1); - - ref_overlap_bw = fp_mult(ddr.dpb_write, ref_overlap_bw_factor); - - ref_overlap_bw = fp_div(ref_overlap_bw, dpb_write_factor); - - ref_overlap_bw = fp_mult(ref_overlap_bw, - (dpb_write_factor - FP_INT(1))); + ddr.line_buffer_write = ddr.line_buffer_read; + if (llc_top_line_buf_enabled) { + llc.line_buffer = ddr.line_buffer_read + ddr.line_buffer_write; + ddr.line_buffer_read = ddr.line_buffer_write = FP_ZERO; + } - ddr.dpb_read = ref_y_read + ref_cb_cr_read + ref_overlap_bw; + ddr.mese_read = dpb_bpp == 8 ? y_bw_no_ubwc_8bpp : y_bw_no_ubwc_10bpp; + ddr.mese_read = fp_div(ddr.mese_read, + fp_mult(FP(1, 37, 100), original_compression_factor)) + + mese_read_factor; - llc.dpb_read = llc_ref_y_read + llc_ref_cb_cr_read; + ddr.mese_write = FP_INT((width * height)/512) + + fp_div(FP_INT((width * height)/4), + original_compression_factor) + + FP_INT((width * height)/128); + ddr.mese_write = fp_div(fp_mult(ddr.mese_write, FP_INT(fps)), + FP_INT(1000 * 1000)); ddr.total = ddr.vsp_read + ddr.vsp_write + ddr.collocated_read + ddr.collocated_write + + ddr.ref_read_y + ddr.ref_read_crcb + + ddr.ref_write + ddr.ref_write_overlap + + ddr.orig_read + ddr.line_buffer_read + ddr.line_buffer_write + - ddr.original_read + ddr.original_write + - ddr.dpb_read + ddr.dpb_write; + ddr.mese_read + ddr.mese_write; - llc.total = llc.dpb_read + llc.line_buffer; + llc.total = llc.ref_read_crcb + llc.line_buffer; qsmmu_bw_overhead_factor = FP(1, 3, 100); ddr.total = fp_mult(ddr.total, qsmmu_bw_overhead_factor); @@ -817,44 +805,53 @@ static unsigned long __calculate_encoder(struct vidc_bus_vote_data *d, {"ENCODER PARAMETERS", "", DUMP_HEADER_MAGIC}, {"width", "%d", width}, {"height", "%d", height}, - {"DPB format", "%#x", dpb_color_format}, - {"original frame format", "%#x", original_color_format}, {"fps", "%d", fps}, - {"DPB compression enable", "%d", dpb_compression_enabled}, - {"original compression enable", "%d", - original_compression_enabled}, - {"low power mode", "%d", low_power}, - {"Work Mode", "%d", work_mode_1}, - {"DPB compression factor", DUMP_FP_FMT, - dpb_compression_factor}, - {"original compression factor", DUMP_FP_FMT, - original_compression_factor}, {"rotation", "%d", rotation}, {"cropping or scaling", "%d", cropping_or_scaling}, + {"low power mode", "%d", low_power}, + {"work Mode", "%d", work_mode_1}, + {"original frame format", "%#x", original_color_format}, + {"original compression enabled", "%d", + original_compression_enabled}, + {"dpb compression factor", DUMP_FP_FMT, + dpb_compression_factor}, + {"input compression factor", DUMP_FP_FMT, + input_compression_factor}, + {"llc ref chroma cache enabled", DUMP_FP_FMT, + llc_ref_chroma_cache_enabled}, + {"llc top line buf enabled", DUMP_FP_FMT, + llc_top_line_buf_enabled}, + {"llc vpss rot line buf enabled ", DUMP_FP_FMT, + llc_vpss_rot_line_buf_enabled}, {"DERIVED PARAMETERS", "", DUMP_HEADER_MAGIC}, - {"LCU size", "%d", lcu_size}, + {"lcu size", "%d", lcu_size}, {"bitrate (Mbit/sec)", "%lu", bitrate}, {"bins to bit factor", DUMP_FP_FMT, bins_to_bit_factor}, + {"original compression factor", DUMP_FP_FMT, + original_compression_factor}, + {"mese read factor", DUMP_FP_FMT, + mese_read_factor}, {"qsmmu_bw_overhead_factor", DUMP_FP_FMT, qsmmu_bw_overhead_factor}, {"INTERMEDIATE B/W DDR", "", DUMP_HEADER_MAGIC}, - {"ref_y_read", DUMP_FP_FMT, ref_y_read}, - {"ref_cb_cr_read", DUMP_FP_FMT, ref_cb_cr_read}, - {"ref_overlap_bw", DUMP_FP_FMT, ref_overlap_bw}, - {"VSP read", DUMP_FP_FMT, ddr.vsp_read}, - {"VSP write", DUMP_FP_FMT, ddr.vsp_write}, + {"vsp read", DUMP_FP_FMT, ddr.vsp_read}, + {"vsp write", DUMP_FP_FMT, ddr.vsp_write}, {"collocated read", DUMP_FP_FMT, ddr.collocated_read}, {"collocated write", DUMP_FP_FMT, ddr.collocated_write}, + {"ref read y", DUMP_FP_FMT, ddr.ref_read_y}, + {"ref read crcb", DUMP_FP_FMT, ddr.ref_read_crcb}, + {"ref write", DUMP_FP_FMT, ddr.ref_write}, + {"ref write overlap", DUMP_FP_FMT, ddr.ref_write_overlap}, + {"original read", DUMP_FP_FMT, ddr.orig_read}, {"line buffer read", DUMP_FP_FMT, ddr.line_buffer_read}, {"line buffer write", DUMP_FP_FMT, ddr.line_buffer_write}, - {"original read", DUMP_FP_FMT, ddr.original_read}, - {"original write", DUMP_FP_FMT, ddr.original_write}, - {"DPB read", DUMP_FP_FMT, ddr.dpb_read}, - {"DPB write", DUMP_FP_FMT, ddr.dpb_write}, - {"LLC DPB read", DUMP_FP_FMT, llc.dpb_read}, - {"LLC Line buffer", DUMP_FP_FMT, llc.line_buffer}, + {"mese read", DUMP_FP_FMT, ddr.mese_read}, + {"mese write", DUMP_FP_FMT, ddr.mese_write}, + {"INTERMEDIATE LLC B/W", "", DUMP_HEADER_MAGIC}, + {"llc ref read crcb", DUMP_FP_FMT, llc.ref_read_crcb}, + {"llc line buffer", DUMP_FP_FMT, llc.line_buffer}, }; __dump(dump, ARRAY_SIZE(dump)); } diff --git a/drivers/media/platform/msm/vidc/msm_vidc_platform.c b/drivers/media/platform/msm/vidc/msm_vidc_platform.c index 0f32ac000997..0bc64536a3da 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc_platform.c +++ b/drivers/media/platform/msm/vidc/msm_vidc_platform.c @@ -133,7 +133,7 @@ static struct msm_vidc_common_data sdm855_common_data[] = { }, { .key = "qcom,max-hw-load", - .value = 4147200, /* 4096x2160@120 */ + .value = 3110400, /* 4096x2160@90 */ }, { .key = "qcom,max-hq-mbs-per-frame", -- GitLab From 23c38c9534c8a457462a8f97017f43a5e7602424 Mon Sep 17 00:00:00 2001 From: Jack Pham Date: Fri, 16 Mar 2018 18:40:49 -0700 Subject: [PATCH 0002/1635] usb: pd: Set PROP_PR_SWAP before forcing role On newer PMICs forcing the current role prior to a PR Swap causes the Type-C state machine to re-run. During this time debounce is happening and PD PHY messages will fail to be transmitted. This is remedied by first sending the Accept message before setting PROP_PR_SWAP which temporarily reduces debounce delay, so that then forcing role can happen in a short time and not interfere with PD PHY operation. While at it consolidate the handling of all of the above in the PE_SRC_SNK_TRANSITION_TO_OFF and PE_SNK_SRC_TRANSITION_TO_OFF cases in usbpd_set_state() to remove redundant code. Change-Id: Id4d196d121a285cabedfff74aaa9768bb73595e4 Signed-off-by: Jack Pham --- drivers/usb/pd/policy_engine.c | 45 ++++++++++++++++------------------ 1 file changed, 21 insertions(+), 24 deletions(-) diff --git a/drivers/usb/pd/policy_engine.c b/drivers/usb/pd/policy_engine.c index dedb956ac8b2..f5e91bd30e79 100644 --- a/drivers/usb/pd/policy_engine.c +++ b/drivers/usb/pd/policy_engine.c @@ -1251,6 +1251,18 @@ static void usbpd_set_state(struct usbpd *pd, enum usbpd_state next_state) dual_role_instance_changed(pd->dual_role); break; + case PE_PRS_SRC_SNK_TRANSITION_TO_OFF: + val.intval = pd->in_pr_swap = true; + power_supply_set_property(pd->usb_psy, + POWER_SUPPLY_PROP_PR_SWAP, &val); + pd->in_explicit_contract = false; + + /* lock in current mode */ + set_power_role(pd, pd->current_pr); + + kick_sm(pd, SRC_TRANSITION_TIME); + break; + case PE_SRC_HARD_RESET: case PE_SNK_HARD_RESET: /* are we still connected? */ @@ -1414,6 +1426,13 @@ static void usbpd_set_state(struct usbpd *pd, enum usbpd_state next_state) break; case PE_PRS_SNK_SRC_TRANSITION_TO_OFF: + val.intval = pd->in_pr_swap = true; + power_supply_set_property(pd->usb_psy, + POWER_SUPPLY_PROP_PR_SWAP, &val); + + /* lock in current mode */ + set_power_role(pd, pd->current_pr); + val.intval = pd->requested_current = 0; /* suspend charging */ power_supply_set_property(pd->usb_psy, POWER_SUPPLY_PROP_PD_CURRENT_MAX, &val); @@ -2187,9 +2206,6 @@ static void usbpd_sm(struct work_struct *w) dr_swap(pd); } else if (IS_CTRL(rx_msg, MSG_PR_SWAP)) { - /* lock in current mode */ - set_power_role(pd, pd->current_pr); - /* we'll happily accept Src->Sink requests anytime */ ret = pd_send_msg(pd, MSG_ACCEPT, NULL, 0, SOP_MSG); if (ret) { @@ -2198,8 +2214,7 @@ static void usbpd_sm(struct work_struct *w) break; } - pd->current_state = PE_PRS_SRC_SNK_TRANSITION_TO_OFF; - kick_sm(pd, SRC_TRANSITION_TIME); + usbpd_set_state(pd, PE_PRS_SRC_SNK_TRANSITION_TO_OFF); break; } else if (IS_CTRL(rx_msg, MSG_VCONN_SWAP)) { ret = pd_send_msg(pd, MSG_ACCEPT, NULL, 0, SOP_MSG); @@ -2478,9 +2493,6 @@ static void usbpd_sm(struct work_struct *w) dr_swap(pd); } else if (IS_CTRL(rx_msg, MSG_PR_SWAP) && pd->spec_rev == USBPD_REV_20) { - /* lock in current mode */ - set_power_role(pd, pd->current_pr); - /* TODO: should we Reject in certain circumstances? */ ret = pd_send_msg(pd, MSG_ACCEPT, NULL, 0, SOP_MSG); if (ret) { @@ -2489,10 +2501,6 @@ static void usbpd_sm(struct work_struct *w) break; } - pd->in_pr_swap = true; - val.intval = 1; - power_supply_set_property(pd->usb_psy, - POWER_SUPPLY_PROP_PR_SWAP, &val); usbpd_set_state(pd, PE_PRS_SNK_SRC_TRANSITION_TO_OFF); break; } else if (IS_CTRL(rx_msg, MSG_VCONN_SWAP) && @@ -2745,17 +2753,10 @@ static void usbpd_sm(struct work_struct *w) break; } - pd->current_state = PE_PRS_SRC_SNK_TRANSITION_TO_OFF; - kick_sm(pd, SRC_TRANSITION_TIME); + usbpd_set_state(pd, PE_PRS_SRC_SNK_TRANSITION_TO_OFF); break; case PE_PRS_SRC_SNK_TRANSITION_TO_OFF: - pd->in_pr_swap = true; - val.intval = 1; - power_supply_set_property(pd->usb_psy, - POWER_SUPPLY_PROP_PR_SWAP, &val); - pd->in_explicit_contract = false; - if (pd->vbus_enabled) { regulator_disable(pd->vbus); pd->vbus_enabled = false; @@ -2793,10 +2794,6 @@ static void usbpd_sm(struct work_struct *w) break; } - pd->in_pr_swap = true; - val.intval = 1; - power_supply_set_property(pd->usb_psy, - POWER_SUPPLY_PROP_PR_SWAP, &val); usbpd_set_state(pd, PE_PRS_SNK_SRC_TRANSITION_TO_OFF); break; -- GitLab From 1d645c6a15faa682a6a24216419ed885715fd9b4 Mon Sep 17 00:00:00 2001 From: Dhaval Patel Date: Mon, 12 Mar 2018 14:26:09 -0700 Subject: [PATCH 0003/1635] drm/msm/sde: update rgba4444 and rgba5551 color component order fix rgba4444 and rgba5551 color component order. Change-Id: I49d1ecb51a53f1535ff2d68a5e7375eba0cc8f48 Signed-off-by: Dhaval Patel --- drivers/gpu/drm/msm/sde/sde_formats.c | 34 +++++++++++++-------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/drivers/gpu/drm/msm/sde/sde_formats.c b/drivers/gpu/drm/msm/sde/sde_formats.c index a819a6d1a0ee..741f7e00e903 100644 --- a/drivers/gpu/drm/msm/sde/sde_formats.c +++ b/drivers/gpu/drm/msm/sde/sde_formats.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -275,97 +275,97 @@ static const struct sde_format sde_format_map[] = { INTERLEAVED_RGB_FMT(ARGB1555, COLOR_ALPHA_1BIT, COLOR_5BIT, COLOR_5BIT, COLOR_5BIT, - C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4, + C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb, 4, true, 2, 0, SDE_FETCH_LINEAR, 1), INTERLEAVED_RGB_FMT(ABGR1555, COLOR_ALPHA_1BIT, COLOR_5BIT, COLOR_5BIT, COLOR_5BIT, - C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA, 4, + C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr, 4, true, 2, 0, SDE_FETCH_LINEAR, 1), INTERLEAVED_RGB_FMT(RGBA5551, COLOR_ALPHA_1BIT, COLOR_5BIT, COLOR_5BIT, COLOR_5BIT, - C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb, 4, + C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4, true, 2, 0, SDE_FETCH_LINEAR, 1), INTERLEAVED_RGB_FMT(BGRA5551, COLOR_ALPHA_1BIT, COLOR_5BIT, COLOR_5BIT, COLOR_5BIT, - C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr, 4, + C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA, 4, true, 2, 0, SDE_FETCH_LINEAR, 1), INTERLEAVED_RGB_FMT(XRGB1555, COLOR_ALPHA_1BIT, COLOR_5BIT, COLOR_5BIT, COLOR_5BIT, - C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4, + C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb, 4, false, 2, 0, SDE_FETCH_LINEAR, 1), INTERLEAVED_RGB_FMT(XBGR1555, COLOR_ALPHA_1BIT, COLOR_5BIT, COLOR_5BIT, COLOR_5BIT, - C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA, 4, + C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr, 4, false, 2, 0, SDE_FETCH_LINEAR, 1), INTERLEAVED_RGB_FMT(RGBX5551, COLOR_ALPHA_1BIT, COLOR_5BIT, COLOR_5BIT, COLOR_5BIT, - C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb, 4, + C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4, false, 2, 0, SDE_FETCH_LINEAR, 1), INTERLEAVED_RGB_FMT(BGRX5551, COLOR_ALPHA_1BIT, COLOR_5BIT, COLOR_5BIT, COLOR_5BIT, - C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr, 4, + C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA, 4, false, 2, 0, SDE_FETCH_LINEAR, 1), INTERLEAVED_RGB_FMT(ARGB4444, COLOR_ALPHA_4BIT, COLOR_4BIT, COLOR_4BIT, COLOR_4BIT, - C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4, + C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb, 4, true, 2, 0, SDE_FETCH_LINEAR, 1), INTERLEAVED_RGB_FMT(ABGR4444, COLOR_ALPHA_4BIT, COLOR_4BIT, COLOR_4BIT, COLOR_4BIT, - C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA, 4, + C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr, 4, true, 2, 0, SDE_FETCH_LINEAR, 1), INTERLEAVED_RGB_FMT(RGBA4444, COLOR_ALPHA_4BIT, COLOR_4BIT, COLOR_4BIT, COLOR_4BIT, - C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb, 4, + C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4, true, 2, 0, SDE_FETCH_LINEAR, 1), INTERLEAVED_RGB_FMT(BGRA4444, COLOR_ALPHA_4BIT, COLOR_4BIT, COLOR_4BIT, COLOR_4BIT, - C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr, 4, + C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA, 4, true, 2, 0, SDE_FETCH_LINEAR, 1), INTERLEAVED_RGB_FMT(XRGB4444, COLOR_ALPHA_4BIT, COLOR_4BIT, COLOR_4BIT, COLOR_4BIT, - C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4, + C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb, 4, false, 2, 0, SDE_FETCH_LINEAR, 1), INTERLEAVED_RGB_FMT(XBGR4444, COLOR_ALPHA_4BIT, COLOR_4BIT, COLOR_4BIT, COLOR_4BIT, - C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA, 4, + C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr, 4, false, 2, 0, SDE_FETCH_LINEAR, 1), INTERLEAVED_RGB_FMT(RGBX4444, COLOR_ALPHA_4BIT, COLOR_4BIT, COLOR_4BIT, COLOR_4BIT, - C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb, 4, + C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4, false, 2, 0, SDE_FETCH_LINEAR, 1), INTERLEAVED_RGB_FMT(BGRX4444, COLOR_ALPHA_4BIT, COLOR_4BIT, COLOR_4BIT, COLOR_4BIT, - C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr, 4, + C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA, 4, false, 2, 0, SDE_FETCH_LINEAR, 1), -- GitLab From 1ab48c37e3a6e0e40676d72dc934640171c84a19 Mon Sep 17 00:00:00 2001 From: Patrick Daly Date: Wed, 10 May 2017 15:42:30 -0700 Subject: [PATCH 0004/1635] iommu: arm-smmu: Support ECATS during context fault The TBU will complete the halt sequence only if there are no pending transactions. This includes transactions stalled by an ongoing context fault. When halting the TBU, disable stall on fault and fault interrupt reporting. Clear any pending faults via terminate register. Additionally, add an error message for maximum address range. Change-Id: If1a6059594f8ec98c91ea0be59d8c7c6bf2f55a3 Signed-off-by: Patrick Daly Signed-off-by: Sudarshan Rajagopalan --- drivers/iommu/arm-smmu.c | 100 ++++++++++++++++++++++++++------------- 1 file changed, 68 insertions(+), 32 deletions(-) diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c index 0493852050bd..74b06567f607 100644 --- a/drivers/iommu/arm-smmu.c +++ b/drivers/iommu/arm-smmu.c @@ -4441,7 +4441,7 @@ IOMMU_OF_DECLARE(cavium_smmuv2, "cavium,smmu-v2", arm_smmu_of_init); #define DEBUG_PAR_PA_SHIFT 12 #define DEBUG_PAR_FAULT_VAL 0x1 -#define TBU_DBG_TIMEOUT_US 30000 +#define TBU_DBG_TIMEOUT_US 100 #define QSMMUV500_ACTLR_DEEP_PREFETCH_MASK 0x3 #define QSMMUV500_ACTLR_DEEP_PREFETCH_SHIFT 0x8 @@ -4504,11 +4504,12 @@ static bool arm_smmu_fwspec_match_smr(struct iommu_fwspec *fwspec, return false; } -static int qsmmuv500_tbu_halt(struct qsmmuv500_tbu_device *tbu) +static int qsmmuv500_tbu_halt(struct qsmmuv500_tbu_device *tbu, + struct arm_smmu_domain *smmu_domain) { unsigned long flags; - u32 val; - void __iomem *base; + u32 halt, fsr, sctlr_orig, sctlr, status; + void __iomem *base, *cb_base; spin_lock_irqsave(&tbu->halt_lock, flags); if (tbu->halt_count) { @@ -4517,19 +4518,48 @@ static int qsmmuv500_tbu_halt(struct qsmmuv500_tbu_device *tbu) return 0; } + cb_base = ARM_SMMU_CB(smmu_domain->smmu, smmu_domain->cfg.cbndx); base = tbu->base; - val = readl_relaxed(base + DEBUG_SID_HALT_REG); - val |= DEBUG_SID_HALT_VAL; - writel_relaxed(val, base + DEBUG_SID_HALT_REG); + halt = readl_relaxed(base + DEBUG_SID_HALT_REG); + halt |= DEBUG_SID_HALT_VAL; + writel_relaxed(halt, base + DEBUG_SID_HALT_REG); - if (readl_poll_timeout_atomic(base + DEBUG_SR_HALT_ACK_REG, - val, (val & DEBUG_SR_HALT_ACK_VAL), - 0, TBU_DBG_TIMEOUT_US)) { + if (!readl_poll_timeout_atomic(base + DEBUG_SR_HALT_ACK_REG, status, + (status & DEBUG_SR_HALT_ACK_VAL), + 0, TBU_DBG_TIMEOUT_US)) + goto out; + + fsr = readl_relaxed(cb_base + ARM_SMMU_CB_FSR); + if (!(fsr & FSR_FAULT)) { dev_err(tbu->dev, "Couldn't halt TBU!\n"); spin_unlock_irqrestore(&tbu->halt_lock, flags); return -ETIMEDOUT; } + /* + * We are in a fault; Our request to halt the bus will not complete + * until transactions in front of us (such as the fault itself) have + * completed. Disable iommu faults and terminate any existing + * transactions. + */ + sctlr_orig = readl_relaxed(cb_base + ARM_SMMU_CB_SCTLR); + sctlr = sctlr_orig & ~(SCTLR_CFCFG | SCTLR_CFIE); + writel_relaxed(sctlr, cb_base + ARM_SMMU_CB_SCTLR); + + writel_relaxed(fsr, cb_base + ARM_SMMU_CB_FSR); + writel_relaxed(RESUME_TERMINATE, cb_base + ARM_SMMU_CB_RESUME); + + if (readl_poll_timeout_atomic(base + DEBUG_SR_HALT_ACK_REG, status, + (status & DEBUG_SR_HALT_ACK_VAL), + 0, TBU_DBG_TIMEOUT_US)) { + dev_err(tbu->dev, "Couldn't halt TBU from fault context!\n"); + writel_relaxed(sctlr_orig, cb_base + ARM_SMMU_CB_SCTLR); + spin_unlock_irqrestore(&tbu->halt_lock, flags); + return -ETIMEDOUT; + } + + writel_relaxed(sctlr_orig, cb_base + ARM_SMMU_CB_SCTLR); +out: tbu->halt_count = 1; spin_unlock_irqrestore(&tbu->halt_lock, flags); return 0; @@ -4630,6 +4660,14 @@ static phys_addr_t qsmmuv500_iova_to_phys( void __iomem *cb_base; u32 sctlr_orig, sctlr; int needs_redo = 0; + ktime_t timeout; + + /* only 36 bit iova is supported */ + if (iova >= (1ULL << 36)) { + dev_err_ratelimited(smmu->dev, "ECATS: address too large: %pad\n", + &iova); + return 0; + } cb_base = ARM_SMMU_CB(smmu, cfg->cbndx); tbu = qsmmuv500_find_tbu(smmu, sid); @@ -4640,35 +4678,23 @@ static phys_addr_t qsmmuv500_iova_to_phys( if (ret) return 0; - /* - * Disable client transactions & wait for existing operations to - * complete. - */ - ret = qsmmuv500_tbu_halt(tbu); + ret = qsmmuv500_tbu_halt(tbu, smmu_domain); if (ret) goto out_power_off; - /* Only one concurrent atos operation */ - ret = qsmmuv500_ecats_lock(smmu_domain, tbu, &flags); - if (ret) - goto out_resume; - /* - * We can be called from an interrupt handler with FSR already set - * so terminate the faulting transaction prior to starting ecats. - * No new racing faults can occur since we in the halted state. * ECATS can trigger the fault interrupt, so disable it temporarily * and check for an interrupt manually. */ - fsr = readl_relaxed(cb_base + ARM_SMMU_CB_FSR); - if (fsr & FSR_FAULT) { - writel_relaxed(fsr, cb_base + ARM_SMMU_CB_FSR); - writel_relaxed(RESUME_TERMINATE, cb_base + ARM_SMMU_CB_RESUME); - } sctlr_orig = readl_relaxed(cb_base + ARM_SMMU_CB_SCTLR); sctlr = sctlr_orig & ~(SCTLR_CFCFG | SCTLR_CFIE); writel_relaxed(sctlr, cb_base + ARM_SMMU_CB_SCTLR); + /* Only one concurrent atos operation */ + ret = qsmmuv500_ecats_lock(smmu_domain, tbu, &flags); + if (ret) + goto out_resume; + redo: /* Set address and stream-id */ val = readq_relaxed(tbu->base + DEBUG_SID_HALT_REG); @@ -4687,10 +4713,20 @@ static phys_addr_t qsmmuv500_iova_to_phys( writeq_relaxed(val, tbu->base + DEBUG_TXN_TRIGG_REG); ret = 0; - if (readl_poll_timeout_atomic(tbu->base + DEBUG_SR_HALT_ACK_REG, - val, !(val & DEBUG_SR_ECATS_RUNNING_VAL), - 0, TBU_DBG_TIMEOUT_US)) { - dev_err(tbu->dev, "ECATS translation timed out!\n"); + //based on readx_poll_timeout_atomic + timeout = ktime_add_us(ktime_get(), TBU_DBG_TIMEOUT_US); + for (;;) { + val = readl_relaxed(tbu->base + DEBUG_SR_HALT_ACK_REG); + if (!(val & DEBUG_SR_ECATS_RUNNING_VAL)) + break; + val = readl_relaxed(cb_base + ARM_SMMU_CB_FSR); + if (val & FSR_FAULT) + break; + if (ktime_compare(ktime_get(), timeout) > 0) { + dev_err(tbu->dev, "ECATS translation timed out!\n"); + ret = -ETIMEDOUT; + break; + } } fsr = readl_relaxed(cb_base + ARM_SMMU_CB_FSR); -- GitLab From d384058f7914683c6157ec05b909c098d2f66613 Mon Sep 17 00:00:00 2001 From: Sudarshan Rajagopalan Date: Fri, 16 Mar 2018 14:35:49 -0700 Subject: [PATCH 0005/1635] iommu: arm-smmu: Implement eCATS translation fault errata workaround Currently due to hardware issue, eCATS reports a false positive translation fault error. Instead of relying on eCATS fault status, check the context bank specific Fault Status Register (FSR) for translation faults. Change-Id: I1920b69404b8bc2d10f84c6a4f4e30977fff45ab Signed-off-by: Sudarshan Rajagopalan --- drivers/iommu/arm-smmu.c | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c index 74b06567f607..cdccc4a1ae15 100644 --- a/drivers/iommu/arm-smmu.c +++ b/drivers/iommu/arm-smmu.c @@ -4654,7 +4654,7 @@ static phys_addr_t qsmmuv500_iova_to_phys( struct arm_smmu_cfg *cfg = &smmu_domain->cfg; struct qsmmuv500_tbu_device *tbu; int ret; - phys_addr_t phys = 0; + phys_addr_t phys; u64 val, fsr; unsigned long flags; void __iomem *cb_base; @@ -4713,7 +4713,6 @@ static phys_addr_t qsmmuv500_iova_to_phys( writeq_relaxed(val, tbu->base + DEBUG_TXN_TRIGG_REG); ret = 0; - //based on readx_poll_timeout_atomic timeout = ktime_add_us(ktime_get(), TBU_DBG_TIMEOUT_US); for (;;) { val = readl_relaxed(tbu->base + DEBUG_SR_HALT_ACK_REG); @@ -4729,26 +4728,25 @@ static phys_addr_t qsmmuv500_iova_to_phys( } } + val = readq_relaxed(tbu->base + DEBUG_PAR_REG); fsr = readl_relaxed(cb_base + ARM_SMMU_CB_FSR); if (fsr & FSR_FAULT) { dev_err(tbu->dev, "ECATS generated a fault interrupt! FSR = %llx\n", - fsr); - ret = -EINVAL; + fsr); - writel_relaxed(val, cb_base + ARM_SMMU_CB_FSR); + /* Clear pending interrupts */ + writel_relaxed(fsr, cb_base + ARM_SMMU_CB_FSR); /* - * Clear pending interrupts * Barrier required to ensure that the FSR is cleared - * before resuming SMMU operation + * before resuming SMMU operation. */ wmb(); writel_relaxed(RESUME_TERMINATE, cb_base + ARM_SMMU_CB_RESUME); - } - val = readq_relaxed(tbu->base + DEBUG_PAR_REG); - if (val & DEBUG_PAR_FAULT_VAL) { - dev_err(tbu->dev, "ECATS translation failed! PAR = %llx\n", - val); + /* Check if ECATS translation failed */ + if (val & DEBUG_PAR_FAULT_VAL) + dev_err(tbu->dev, "ECATS translation failed! PAR = %llx\n", + val); ret = -EINVAL; } -- GitLab From bb84307949fdeaaadfebf509bafbd33de4bd8fb3 Mon Sep 17 00:00:00 2001 From: Maulik Shah Date: Wed, 22 Nov 2017 10:23:04 +0530 Subject: [PATCH 0006/1635] drivers: cpuidle: lpm-levels: Remove unused code Remove code and trace events that are no longer needed. Change-Id: I74201fa1338a3955c30f93b204cbb79ea6436a97 Signed-off-by: Maulik Shah --- drivers/cpuidle/lpm-levels.c | 3 --- drivers/cpuidle/lpm-levels.h | 1 - include/trace/events/trace_msm_low_power.h | 20 +------------------- 3 files changed, 1 insertion(+), 23 deletions(-) diff --git a/drivers/cpuidle/lpm-levels.c b/drivers/cpuidle/lpm-levels.c index 2ed2c49d0417..ed1985377465 100644 --- a/drivers/cpuidle/lpm-levels.c +++ b/drivers/cpuidle/lpm-levels.c @@ -121,9 +121,6 @@ static void cluster_prepare(struct lpm_cluster *cluster, const struct cpumask *cpu, int child_idx, bool from_idle, int64_t time); -static bool menu_select; -module_param_named(menu_select, menu_select, bool, 0664); - static int msm_pm_sleep_time_override; module_param_named(sleep_time_override, msm_pm_sleep_time_override, int, 0664); diff --git a/drivers/cpuidle/lpm-levels.h b/drivers/cpuidle/lpm-levels.h index 21b5783bdbae..67aaa91db1d7 100644 --- a/drivers/cpuidle/lpm-levels.h +++ b/drivers/cpuidle/lpm-levels.h @@ -32,7 +32,6 @@ struct lpm_cpu_level { struct power_params pwr; unsigned int psci_id; bool is_reset; - bool hyp_psci; int reset_level; }; diff --git a/include/trace/events/trace_msm_low_power.h b/include/trace/events/trace_msm_low_power.h index 97eefc665130..c25da0e5e71c 100644 --- a/include/trace/events/trace_msm_low_power.h +++ b/include/trace/events/trace_msm_low_power.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2012, 2014-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012, 2014-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -250,24 +250,6 @@ TRACE_EVENT(cluster_pred_hist, __entry->sample, __entry->tmr) ); -TRACE_EVENT(pre_pc_cb, - - TP_PROTO(int tzflag), - - TP_ARGS(tzflag), - - TP_STRUCT__entry( - __field(int, tzflag) - ), - - TP_fast_assign( - __entry->tzflag = tzflag; - ), - - TP_printk("tzflag:%d", - __entry->tzflag - ) -); #endif #define TRACE_INCLUDE_FILE trace_msm_low_power #include -- GitLab From 78268e861e50e217d9a40bd6f385474f6886c1d8 Mon Sep 17 00:00:00 2001 From: Maulik Shah Date: Mon, 27 Nov 2017 13:55:41 +0530 Subject: [PATCH 0007/1635] cpuidle: lpm-levels: Correctly check if its okay to do cluster LPM Currently cluster mode that is not supporting system level lpm can also check if its okay to do system level lpm based on reset state. Update to check if rpm handshake is enabled instead of reset state. Change-Id: Ica95fd837b4e2829bfc1f822aee8f290dc021d6e Signed-off-by: Maulik Shah --- drivers/cpuidle/lpm-levels.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/cpuidle/lpm-levels.c b/drivers/cpuidle/lpm-levels.c index ed1985377465..41f25bc26532 100644 --- a/drivers/cpuidle/lpm-levels.c +++ b/drivers/cpuidle/lpm-levels.c @@ -974,6 +974,9 @@ static int cluster_select(struct lpm_cluster *cluster, bool from_idle, if (suspend_in_progress && from_idle && level->notify_rpm) continue; + if (level->notify_rpm && !system_sleep_allowed()) + continue; + best_level = i; if (from_idle && -- GitLab From 5f92cd09307371a640925b3b16f0fbc5a0d00125 Mon Sep 17 00:00:00 2001 From: Srinivas Rao L Date: Fri, 13 Oct 2017 23:11:21 +0530 Subject: [PATCH 0008/1635] drivers: cpuidle: lpm-levels: LPM prediction tuning Update the tunables for LPM prediction for better power consumption. Change-Id: I20fb32e7101f26fc9904aeeb577b2044075ffd3c Signed-off-by: Srinivas Rao L --- drivers/cpuidle/lpm-levels.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/drivers/cpuidle/lpm-levels.c b/drivers/cpuidle/lpm-levels.c index 80ef4f9820aa..2882d2674089 100644 --- a/drivers/cpuidle/lpm-levels.c +++ b/drivers/cpuidle/lpm-levels.c @@ -84,12 +84,13 @@ struct lpm_cluster *lpm_root_node; static bool lpm_prediction = true; module_param_named(lpm_prediction, lpm_prediction, bool, 0664); -static uint32_t ref_stddev = 100; +static uint32_t ref_stddev = 500; module_param_named(ref_stddev, ref_stddev, uint, 0664); -static uint32_t tmr_add = 100; +static uint32_t tmr_add = 1000; module_param_named(tmr_add, tmr_add, uint, 0664); +static uint32_t ref_premature_cnt = 1; static uint32_t bias_hyst; module_param_named(bias_hyst, bias_hyst, uint, 0664); @@ -436,6 +437,7 @@ static uint64_t lpm_cpuidle_predict(struct cpuidle_device *dev, int64_t thresh = LLONG_MAX; struct lpm_history *history = &per_cpu(hist, dev->cpu); uint32_t *min_residency = get_per_cpu_min_residency(dev->cpu); + uint32_t *max_residency = get_per_cpu_max_residency(dev->cpu); if (!lpm_prediction) return 0; @@ -522,9 +524,17 @@ static uint64_t lpm_cpuidle_predict(struct cpuidle_device *dev, total += history->resi[i]; } } - if (failed > (MAXSAMPLES/2)) { + if (failed >= ref_premature_cnt) { *idx_restrict = j; do_div(total, failed); + for (i = 0; i < j; i++) { + if (total < max_residency[i]) { + *idx_restrict = i+1; + total = max_residency[i]; + break; + } + } + *idx_restrict_time = total; history->stime = ktime_to_us(ktime_get()) + *idx_restrict_time; -- GitLab From 218dc74604b1174df7e8ceabf72833a8045b739f Mon Sep 17 00:00:00 2001 From: Maulik Shah Date: Thu, 30 Nov 2017 17:09:29 +0530 Subject: [PATCH 0009/1635] cpuidle: lpm-levels: Do not predict LPM for isolated cpus Prediction can select shallower low power mode for isolated cpu based on historical data. Do not predict LPMs for isolated cpus. Change-Id: I998008ef3c578c1dccfacae8513a15dfbe397e16 Signed-off-by: Maulik Shah --- drivers/cpuidle/lpm-levels.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/cpuidle/lpm-levels.c b/drivers/cpuidle/lpm-levels.c index 41f25bc26532..f09dc6981b27 100644 --- a/drivers/cpuidle/lpm-levels.c +++ b/drivers/cpuidle/lpm-levels.c @@ -637,7 +637,7 @@ static int cpu_power_select(struct cpuidle_device *dev, next_wakeup_us = next_event_us - lvl_latency_us; } - if (!i) { + if (!i && !cpu_isolated(dev->cpu)) { /* * If the next_wake_us itself is not sufficient for * deeper low power modes than clock gating do not -- GitLab From 64eb509d8f2341805e262a1a49ff1e28e091606d Mon Sep 17 00:00:00 2001 From: Mahesh Sivasubramanian Date: Mon, 16 Oct 2017 16:46:56 -0600 Subject: [PATCH 0010/1635] drivers: cpuidle: lpm-levels: Add support per cluster prediction Add feature to enable/disable CPU prediction on a cluster level. This allows more finer tuning based on power/perf requirements. Change-Id: I1ce26c04fd3a25ee1f724da5814074308484baca Signed-off-by: Mahesh Sivasubramanian --- Documentation/devicetree/bindings/arm/msm/lpm-levels.txt | 2 ++ drivers/cpuidle/lpm-levels-of.c | 3 +++ drivers/cpuidle/lpm-levels.c | 4 ++-- drivers/cpuidle/lpm-levels.h | 1 + 4 files changed, 8 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/arm/msm/lpm-levels.txt b/Documentation/devicetree/bindings/arm/msm/lpm-levels.txt index c7572331026a..55d06b25b2de 100644 --- a/Documentation/devicetree/bindings/arm/msm/lpm-levels.txt +++ b/Documentation/devicetree/bindings/arm/msm/lpm-levels.txt @@ -77,6 +77,8 @@ that share the parameters.It contains the following properties. - qcom,pm-cpu-levels: The different low power modes that a CPU could enter. The following section explains the required properties of this node. + -qcom,use-prediction: This optional property is used to indicate the + the LPM governor is to apply sleep prediction to this cluster. [Node bindings for qcom,pm-cpu-levels] Required properties: diff --git a/drivers/cpuidle/lpm-levels-of.c b/drivers/cpuidle/lpm-levels-of.c index 4ea5f8964211..030aacb7cba8 100644 --- a/drivers/cpuidle/lpm-levels-of.c +++ b/drivers/cpuidle/lpm-levels-of.c @@ -711,6 +711,9 @@ static int parse_cpu_levels(struct device_node *node, struct lpm_cluster *c) if (ret) goto failed_parse_params; + key = "qcom,use-prediction"; + cpu->lpm_prediction = of_property_read_bool(node, key); + key = "parse_cpu"; ret = parse_cpu(node, cpu); if (ret) diff --git a/drivers/cpuidle/lpm-levels.c b/drivers/cpuidle/lpm-levels.c index 2882d2674089..ac74e6c325d2 100644 --- a/drivers/cpuidle/lpm-levels.c +++ b/drivers/cpuidle/lpm-levels.c @@ -439,7 +439,7 @@ static uint64_t lpm_cpuidle_predict(struct cpuidle_device *dev, uint32_t *min_residency = get_per_cpu_min_residency(dev->cpu); uint32_t *max_residency = get_per_cpu_max_residency(dev->cpu); - if (!lpm_prediction) + if (!lpm_prediction || !cpu->lpm_prediction) return 0; /* @@ -621,7 +621,7 @@ static int cpu_power_select(struct cpuidle_device *dev, struct power_params *pwr_params = &level->pwr; bool allow; - allow = lpm_cpu_mode_allow(dev->cpu, i, true); + allow = i ? lpm_cpu_mode_allow(dev->cpu, i, true) : true; if (!allow) continue; diff --git a/drivers/cpuidle/lpm-levels.h b/drivers/cpuidle/lpm-levels.h index 10567e70ac4e..5039682f496d 100644 --- a/drivers/cpuidle/lpm-levels.h +++ b/drivers/cpuidle/lpm-levels.h @@ -43,6 +43,7 @@ struct lpm_cpu { int nlevels; unsigned int psci_mode_shift; unsigned int psci_mode_mask; + bool lpm_prediction; struct cpuidle_driver *drv; struct lpm_cluster *parent; }; -- GitLab From 1dd0857f2d3ab57fea2b5546798c1a3b2f67a1ac Mon Sep 17 00:00:00 2001 From: Lina Iyer Date: Thu, 9 Nov 2017 00:57:38 +0000 Subject: [PATCH 0011/1635] drivers: qcom: fix compilation errors Fix compilation errors when compiling with 4.9 kernel on arm architectures. do_div() likes its argument to be a uint64_t instead of a signed value. Change-Id: I81cf23fd649120a35a21f1aabc9d82192e330b67 Signed-off-by: Lina Iyer --- drivers/cpuidle/lpm-levels.c | 7 +++---- drivers/cpuidle/lpm-levels.h | 2 +- drivers/soc/qcom/lpm-stats.c | 4 ++-- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/drivers/cpuidle/lpm-levels.c b/drivers/cpuidle/lpm-levels.c index ac74e6c325d2..2ed2c49d0417 100644 --- a/drivers/cpuidle/lpm-levels.c +++ b/drivers/cpuidle/lpm-levels.c @@ -1343,7 +1343,8 @@ static int lpm_cpuidle_enter(struct cpuidle_device *dev, struct lpm_cpu *cpu = per_cpu(cpu_lpm, dev->cpu); bool success = true; const struct cpumask *cpumask = get_cpu_mask(dev->cpu); - int64_t start_time = ktime_to_ns(ktime_get()), end_time; + ktime_t start = ktime_get(); + uint64_t start_time = ktime_to_ns(start), end_time; struct power_params *pwr_params; pwr_params = &cpu->levels[idx].pwr; @@ -1365,9 +1366,7 @@ static int lpm_cpuidle_enter(struct cpuidle_device *dev, cluster_unprepare(cpu->parent, cpumask, idx, true, end_time); cpu_unprepare(cpu, idx, true); - end_time = ktime_to_ns(ktime_get()) - start_time; - do_div(end_time, 1000); - dev->last_residency = end_time; + dev->last_residency = ktime_us_delta(ktime_get(), start); update_history(dev, idx); trace_cpu_idle_exit(idx, success); local_irq_enable(); diff --git a/drivers/cpuidle/lpm-levels.h b/drivers/cpuidle/lpm-levels.h index 5039682f496d..21b5783bdbae 100644 --- a/drivers/cpuidle/lpm-levels.h +++ b/drivers/cpuidle/lpm-levels.h @@ -124,7 +124,7 @@ uint32_t *get_per_cpu_max_residency(int cpu); uint32_t *get_per_cpu_min_residency(int cpu); extern struct lpm_cluster *lpm_root_node; -#if CONFIG_SMP +#if defined(CONFIG_SMP) extern DEFINE_PER_CPU(bool, pending_ipi); static inline bool is_IPI_pending(const struct cpumask *mask) { diff --git a/drivers/soc/qcom/lpm-stats.c b/drivers/soc/qcom/lpm-stats.c index 2a86aeb07139..09bb4269aea9 100644 --- a/drivers/soc/qcom/lpm-stats.c +++ b/drivers/soc/qcom/lpm-stats.c @@ -44,7 +44,7 @@ struct level_stats { int64_t max_time[CONFIG_MSM_IDLE_STATS_BUCKET_COUNT]; int success_count; int failed_count; - int64_t total_time; + uint64_t total_time; uint64_t enter_time; }; @@ -103,7 +103,7 @@ static void level_stats_print(struct seq_file *m, struct level_stats *stats) int i = 0; int64_t bucket_time = 0; char seqs[MAX_STR_LEN] = {0}; - int64_t s = stats->total_time; + uint64_t s = stats->total_time; uint32_t ns = do_div(s, NSEC_PER_SEC); snprintf(seqs, MAX_STR_LEN, -- GitLab From 5a38caa6a95622c891562c1d5a16bfc6db238821 Mon Sep 17 00:00:00 2001 From: Nitin Bandwar Date: Mon, 8 Jan 2018 15:38:31 -0800 Subject: [PATCH 0012/1635] drivers: cpuidle: lpm-levels: Ignore sleep bias for isolated cpus For isolated cpus, do not consider sleep bias. Sleep bias is used to prevent active cores from entering low power modes with longer latencies. Isolated CPUs are not considered for scheduling and as such should enter deepest low power mode. Change-Id: Ic8c20ca761c6f09dc86317fc5df872a37eb86aa9 Signed-off-by: Nitin Bandwar Signed-off-by: Mahesh Sivasubramanian --- drivers/cpuidle/lpm-levels.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/cpuidle/lpm-levels.c b/drivers/cpuidle/lpm-levels.c index f09dc6981b27..116b1a9e5eea 100644 --- a/drivers/cpuidle/lpm-levels.c +++ b/drivers/cpuidle/lpm-levels.c @@ -608,10 +608,8 @@ static int cpu_power_select(struct cpuidle_device *dev, next_event_us = (uint32_t)(ktime_to_us(get_next_event_time(dev->cpu))); - if (is_cpu_biased(dev->cpu)) { - best_level = 0; + if (is_cpu_biased(dev->cpu) && (!cpu_isolated(dev->cpu))) goto done_select; - } for (i = 0; i < cpu->nlevels; i++) { struct lpm_cpu_level *level = &cpu->levels[i]; -- GitLab From 383d922ccc0511b1e88a7f63c490c7f9d7fe4bf9 Mon Sep 17 00:00:00 2001 From: Lina Iyer Date: Wed, 13 Dec 2017 22:37:36 +0000 Subject: [PATCH 0013/1635] drivers: arm: cpuidle: support ARMv7 targets for lpm governor QCOM's low power mode cpuidle driver support ARM v8 targets primarily. The initialization of PSCI for ARM v7 targets is done through the generic ARM cpuidle driver. Since LPM driver replaces the ARM's default driver for QCOM SoC's including the ARM v7 variants, we now have the responsibility of initializing the PSCI cpuidle ops. Also, since QCOM SoCs do not use ARM idle state definitions as suggested in [1], the initialization of PSCI cpuidle ops would fail. Make the PSCI cpuidle ops initialization conditional. [1]. Documentation/devicetree/bindings/arm/idle-states.txt Change-Id: Ifef6c5bdd76e93d34af45b51efbe12f784421746 Signed-off-by: Lina Iyer --- arch/arm/Kconfig | 1 + drivers/cpuidle/lpm-levels.c | 12 ++++++++++++ drivers/firmware/psci.c | 7 ++++++- 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 858638134bfa..7696a09f0188 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -19,6 +19,7 @@ config ARM select ARCH_USE_BUILTIN_BSWAP select ARCH_USE_CMPXCHG_LOCKREF select ARCH_WANT_IPC_PARSE_VERSION + select ARM_PSCI_FW if PM select BUILDTIME_EXTABLE_SORT if MMU select CLONE_BACKWARDS select CPU_PM if (SUSPEND || CPU_IDLE) diff --git a/drivers/cpuidle/lpm-levels.c b/drivers/cpuidle/lpm-levels.c index 116b1a9e5eea..8bd1c90db29a 100644 --- a/drivers/cpuidle/lpm-levels.c +++ b/drivers/cpuidle/lpm-levels.c @@ -1702,6 +1702,18 @@ static int __init lpm_levels_module_init(void) { int rc; +#ifdef CONFIG_ARM + int cpu; + + for_each_possible_cpu(cpu) { + rc = arm_cpuidle_init(smp_processor_id()); + if (rc) { + pr_err("CPU%d ARM CPUidle init failed (%d)\n", cpu, rc); + return rc; + } + } +#endif + rc = platform_driver_register(&lpm_driver); if (rc) { pr_info("Error registering %s\n", lpm_driver.driver.name); diff --git a/drivers/firmware/psci.c b/drivers/firmware/psci.c index 0863996e38df..5f4a81e7858f 100644 --- a/drivers/firmware/psci.c +++ b/drivers/firmware/psci.c @@ -268,8 +268,9 @@ static int __init psci_features(u32 psci_func_id) } #ifdef CONFIG_CPU_IDLE -static DEFINE_PER_CPU_READ_MOSTLY(u32 *, psci_power_state); +static __maybe_unused DEFINE_PER_CPU_READ_MOSTLY(u32 *, psci_power_state); +#ifdef CONFIG_DT_IDLE_STATES static int psci_dt_cpu_init_idle(struct device_node *cpu_node, int cpu) { int i, ret, count = 0; @@ -322,6 +323,10 @@ static int psci_dt_cpu_init_idle(struct device_node *cpu_node, int cpu) kfree(psci_states); return ret; } +#else +static int psci_dt_cpu_init_idle(struct device_node *cpu_node, int cpu) +{ return 0; } +#endif #ifdef CONFIG_ACPI #include -- GitLab From 123f674842eeb194d17d3c646d7c635689f44386 Mon Sep 17 00:00:00 2001 From: Liam Mark Date: Tue, 3 Apr 2018 15:12:05 -0700 Subject: [PATCH 0014/1635] staging: android: ion: Ensure ION supports concurrent CMO requests ION userspace clients can request cache maintenance on an ION buffer at any time using the DMA_BUF_IOCTL_SYNC IOCTL. Ensure that the ION buffer is not in the process of being detached, dma mapped or dma unmapped when client requested cache maintenance is carried out. Change-Id: I8d414af02dbfe8f6e81e0d518f9819b574a8da9f Signed-off-by: Liam Mark --- drivers/staging/android/ion/ion.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/staging/android/ion/ion.c b/drivers/staging/android/ion/ion.c index 295611223d53..71f333c8bb38 100644 --- a/drivers/staging/android/ion/ion.c +++ b/drivers/staging/android/ion/ion.c @@ -311,8 +311,8 @@ static void ion_dma_buf_detatch(struct dma_buf *dmabuf, struct ion_dma_buf_attachment *a = attachment->priv; struct ion_buffer *buffer = dmabuf->priv; - free_duped_table(a->table); mutex_lock(&buffer->lock); + free_duped_table(a->table); list_del(&a->list); mutex_unlock(&buffer->lock); @@ -335,6 +335,7 @@ static struct sg_table *ion_map_dma_buf(struct dma_buf_attachment *attachment, !hlos_accessible_buffer(buffer)) map_attrs |= DMA_ATTR_SKIP_CPU_SYNC; + mutex_lock(&buffer->lock); if (map_attrs & DMA_ATTR_SKIP_CPU_SYNC) trace_ion_dma_map_cmo_skip(attachment->dev, attachment->dmabuf->name, @@ -364,6 +365,7 @@ static struct sg_table *ion_map_dma_buf(struct dma_buf_attachment *attachment, return ERR_PTR(-ENOMEM); a->dma_mapped = true; + mutex_unlock(&buffer->lock); return table; } @@ -380,6 +382,7 @@ static void ion_unmap_dma_buf(struct dma_buf_attachment *attachment, !hlos_accessible_buffer(buffer)) map_attrs |= DMA_ATTR_SKIP_CPU_SYNC; + mutex_lock(&buffer->lock); if (map_attrs & DMA_ATTR_SKIP_CPU_SYNC) trace_ion_dma_unmap_cmo_skip(attachment->dev, attachment->dmabuf->name, @@ -404,6 +407,7 @@ static void ion_unmap_dma_buf(struct dma_buf_attachment *attachment, dma_unmap_sg_attrs(attachment->dev, table->sgl, table->nents, direction, map_attrs); a->dma_mapped = false; + mutex_unlock(&buffer->lock); } void ion_pages_sync_for_device(struct device *dev, struct page *page, -- GitLab From 622a5430b969b749edd01b8fc7b4ff00fb591989 Mon Sep 17 00:00:00 2001 From: Tharun Kumar Merugu Date: Wed, 4 Apr 2018 10:39:18 +0530 Subject: [PATCH 0015/1635] adsprpc: optimize number of SGL entries during map create Set proper DMA segment size and boundary during mem map creation to reduce number of SGL entries to 1. Change-Id: I92392e62766c83ab49a4ec217e5762d5601af425 Acked-by: Thyagarajan Venkatanarayanan Signed-off-by: Tharun Kumar Merugu --- drivers/char/adsprpc.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/char/adsprpc.c b/drivers/char/adsprpc.c index 10c29acecfca..8ba91478b4aa 100644 --- a/drivers/char/adsprpc.c +++ b/drivers/char/adsprpc.c @@ -3004,8 +3004,15 @@ static int fastrpc_cb_probe(struct device *dev) VERIFY(err, !arm_iommu_attach_device(dev, sess->smmu.mapping)); if (err) goto bail; + sess->smmu.dev = dev; sess->smmu.enabled = 1; + if (!sess->smmu.dev->dma_parms) + sess->smmu.dev->dma_parms = devm_kzalloc(sess->smmu.dev, + sizeof(*sess->smmu.dev->dma_parms), GFP_KERNEL); + dma_set_max_seg_size(sess->smmu.dev, DMA_BIT_MASK(32)); + dma_set_seg_boundary(sess->smmu.dev, DMA_BIT_MASK(64)); + chan->sesscount++; debugfs_global_file = debugfs_create_file("global", 0644, debugfs_root, NULL, &debugfs_fops); -- GitLab From 55893aa21797f831ec1fde10350c6cf65c68827d Mon Sep 17 00:00:00 2001 From: Pavankumar Kondeti Date: Tue, 13 Mar 2018 09:29:39 +0530 Subject: [PATCH 0016/1635] sched: Make sure window start passed to schedutil is consistent The scheduler sends some notifications for individual CPUs. If these events happen close to the window boundary, the window_start passed to schedutil may go out of order. Change-Id: Ib6338bd4bc3b1c41c424ec959056c57c0ed7507e Signed-off-by: Pavankumar Kondeti --- kernel/sched/sched.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h index f6a6f8333fa9..825c88345567 100644 --- a/kernel/sched/sched.h +++ b/kernel/sched/sched.h @@ -1999,7 +1999,7 @@ cpu_util_freq_walt(int cpu, struct sched_walt_cpu_load *walt_load) walt_load->prev_window_util = util; walt_load->nl = nl; walt_load->pl = pl; - walt_load->ws = rq->window_start; + walt_load->ws = rq->load_reported_window; } return (util >= capacity) ? capacity : util; @@ -2460,7 +2460,8 @@ static inline void cpufreq_update_util(struct rq *rq, unsigned int flags) (rq->load_reported_window == rq->window_start) && !(flags & exception_flags)) return; - rq->load_reported_window = rq->window_start; + if (!(flags & exception_flags)) + rq->load_reported_window = rq->window_start; #endif data = rcu_dereference_sched(*per_cpu_ptr(&cpufreq_update_util_data, -- GitLab From 722168b5f8c8b9f86498d29121aa6944ed1b760b Mon Sep 17 00:00:00 2001 From: Chinmay Sawarkar Date: Wed, 28 Mar 2018 15:14:53 -0700 Subject: [PATCH 0017/1635] uapi/media: Update yuv buffer size based on hardware requirement 1. Update buffer layout based on HW spec. 2. Remove padding at end of each buffer. 3. Align the buffer size with video firmware spec. CRs-Fixed: 2214722 Change-Id: I51eca554fcd5316a0968dcf505df8883a656a2bb Signed-off-by: Chinmay Sawarkar --- include/uapi/media/msm_media_info.h | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/include/uapi/media/msm_media_info.h b/include/uapi/media/msm_media_info.h index 4847a6599ac5..f50332666f0d 100644 --- a/include/uapi/media/msm_media_info.h +++ b/include/uapi/media/msm_media_info.h @@ -1284,7 +1284,6 @@ static inline unsigned int VENUS_RGB_META_SCANLINES(int color_fmt, int height) static inline unsigned int VENUS_BUFFER_SIZE( int color_fmt, int width, int height) { - const unsigned int extra_size = VENUS_EXTRADATA_SIZE(width, height); unsigned int uv_alignment = 0, size = 0; unsigned int y_plane, uv_plane, y_stride, uv_stride, y_sclines, uv_sclines; @@ -1313,8 +1312,7 @@ static inline unsigned int VENUS_BUFFER_SIZE( uv_alignment = 4096; y_plane = y_stride * y_sclines; uv_plane = uv_stride * uv_sclines + uv_alignment; - size = y_plane + uv_plane + - MSM_MEDIA_MAX(extra_size, 8 * y_stride); + size = y_plane + uv_plane; size = MSM_MEDIA_ALIGN(size, 4096); break; case COLOR_FMT_NV12_MVTB: @@ -1322,7 +1320,7 @@ static inline unsigned int VENUS_BUFFER_SIZE( y_plane = y_stride * y_sclines; uv_plane = uv_stride * uv_sclines + uv_alignment; size = y_plane + uv_plane; - size = 2 * size + extra_size; + size = 2 * size; size = MSM_MEDIA_ALIGN(size, 4096); break; case COLOR_FMT_NV12_UBWC: @@ -1342,8 +1340,7 @@ static inline unsigned int VENUS_BUFFER_SIZE( uv_meta_scanlines, 4096); size = (y_ubwc_plane + uv_ubwc_plane + y_meta_plane + - uv_meta_plane)*2 + - MSM_MEDIA_MAX(extra_size + 8192, 48 * y_stride); + uv_meta_plane)*2; size = MSM_MEDIA_ALIGN(size, 4096); break; case COLOR_FMT_NV12_BPP10_UBWC: @@ -1359,8 +1356,7 @@ static inline unsigned int VENUS_BUFFER_SIZE( uv_meta_scanlines, 4096); size = y_ubwc_plane + uv_ubwc_plane + y_meta_plane + - uv_meta_plane + - MSM_MEDIA_MAX(extra_size + 8192, 48 * y_stride); + uv_meta_plane; size = MSM_MEDIA_ALIGN(size, 4096); break; case COLOR_FMT_P010_UBWC: -- GitLab From a5cc08bd1c8cd42bc97d73e9386e75fe4eb850b1 Mon Sep 17 00:00:00 2001 From: David Collins Date: Mon, 2 Apr 2018 15:18:32 -0700 Subject: [PATCH 0018/1635] ARM: dts: msm: add refgen regulator device for sdmshrike Add a refgen-regulator device for the South refgen used by the DSI PHY. Change-Id: I1437ea6eb225e58b63d6ef2f4f53c8043d1a42fa Signed-off-by: David Collins --- arch/arm64/boot/dts/qcom/sdmshrike-regulators.dtsi | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sdmshrike-regulators.dtsi b/arch/arm64/boot/dts/qcom/sdmshrike-regulators.dtsi index 4bc18acb3e18..ca4ef48c6c4d 100644 --- a/arch/arm64/boot/dts/qcom/sdmshrike-regulators.dtsi +++ b/arch/arm64/boot/dts/qcom/sdmshrike-regulators.dtsi @@ -872,4 +872,11 @@ qcom,init-mode = ; }; }; + + refgen: refgen-regulator@88e7000 { + compatible = "qcom,refgen-regulator"; + reg = <0x88e7000 0x60>; + regulator-name = "refgen"; + regulator-enable-ramp-delay = <5>; + }; }; -- GitLab From 2804e6736c284f8916a9c17d5f19e1f9a4b3beaa Mon Sep 17 00:00:00 2001 From: Prasad Sodagudi Date: Fri, 6 Apr 2018 09:25:25 -0700 Subject: [PATCH 0019/1635] timer: Remove a BUG_ON check in migrates timers __migrate_timers() can be called from both hotplug and core isolation contexts. When isolatoins is happening, the other core may be processing the timers simultaniously, So remove a BUG_ON(old_base->running_timer) check in __migrate_timers() function. Change-Id: I6483fe0d95d0ce57d9f8d478ac9df64d47bff0fe Signed-off-by: Prasad Sodagudi --- kernel/time/timer.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/kernel/time/timer.c b/kernel/time/timer.c index 26c58dad1ff1..61e8baf7ea90 100644 --- a/kernel/time/timer.c +++ b/kernel/time/timer.c @@ -1904,8 +1904,6 @@ static void __migrate_timers(unsigned int cpu, bool remove_pinned) */ forward_timer_base(new_base); - BUG_ON(old_base->running_timer); - for (i = 0; i < WHEEL_SIZE; i++) migrate_timer_list(new_base, old_base->vectors + i, remove_pinned); -- GitLab From 7e6dae99241b1b3e0a8fb1000e64946e60fc3c07 Mon Sep 17 00:00:00 2001 From: Kyle Piefer Date: Fri, 30 Mar 2018 10:35:21 -0700 Subject: [PATCH 0020/1635] msm: kgsl: Enable hardware clock gating Hardware clock gating is now supported, so enable it in the power control flags. Change-Id: Ib88f325e73e7e83f6ce71d7965c6d5aa2688f0c7 Signed-off-by: Kyle Piefer --- drivers/gpu/msm/adreno.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c index 0763926c1378..50a52d9e2572 100644 --- a/drivers/gpu/msm/adreno.c +++ b/drivers/gpu/msm/adreno.c @@ -107,7 +107,7 @@ static struct adreno_device device_3d0 = { .input_work = __WORK_INITIALIZER(device_3d0.input_work, adreno_input_work), .pwrctrl_flag = BIT(ADRENO_SPTP_PC_CTRL) | BIT(ADRENO_PPD_CTRL) | - BIT(ADRENO_LM_CTRL) | + BIT(ADRENO_LM_CTRL) | BIT(ADRENO_HWCG_CTRL) | BIT(ADRENO_THROTTLING_CTRL), .profile.enabled = false, .active_list = LIST_HEAD_INIT(device_3d0.active_list), -- GitLab From b60e42beec62b298be9de12dc2c62280378fd885 Mon Sep 17 00:00:00 2001 From: Kyle Piefer Date: Wed, 4 Apr 2018 13:45:19 -0700 Subject: [PATCH 0021/1635] msm: kgsl: Enable power scaling DCVS is now supported. Enable power scaling to use it. Change-Id: Ifad9007536ec6a1a8a26ba64a304834eccd3e75c Signed-off-by: Kyle Piefer --- drivers/gpu/msm/adreno.c | 2 ++ drivers/gpu/msm/kgsl_pwrscale.c | 15 +++++++++++++-- drivers/gpu/msm/kgsl_pwrscale.h | 2 +- 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c index 0763926c1378..a9ccc09326f9 100644 --- a/drivers/gpu/msm/adreno.c +++ b/drivers/gpu/msm/adreno.c @@ -1263,6 +1263,8 @@ static int adreno_probe(struct platform_device *pdev) adreno_sysfs_init(adreno_dev); + kgsl_pwrscale_init(&pdev->dev, CONFIG_QCOM_ADRENO_DEFAULT_GOVERNOR); + /* Initialize coresight for the target */ adreno_coresight_init(adreno_dev); diff --git a/drivers/gpu/msm/kgsl_pwrscale.c b/drivers/gpu/msm/kgsl_pwrscale.c index 5b376a406f54..b5249b366db9 100644 --- a/drivers/gpu/msm/kgsl_pwrscale.c +++ b/drivers/gpu/msm/kgsl_pwrscale.c @@ -288,8 +288,19 @@ void kgsl_pwrscale_enable(struct kgsl_device *device) if (WARN_ON(!mutex_is_locked(&device->mutex))) return; - device->pwrscale.enabled = false; - return; + if (device->pwrscale.devfreqptr) { + queue_work(device->pwrscale.devfreq_wq, + &device->pwrscale.devfreq_resume_ws); + device->pwrscale.enabled = true; + } else { + /* + * Don't enable it if devfreq is not set and let the device + * run at default level; + */ + kgsl_pwrctrl_pwrlevel_change(device, + device->pwrctrl.default_pwrlevel); + device->pwrscale.enabled = false; + } } EXPORT_SYMBOL(kgsl_pwrscale_enable); diff --git a/drivers/gpu/msm/kgsl_pwrscale.h b/drivers/gpu/msm/kgsl_pwrscale.h index 604a779dabb9..f74f7315bac6 100644 --- a/drivers/gpu/msm/kgsl_pwrscale.h +++ b/drivers/gpu/msm/kgsl_pwrscale.h @@ -144,7 +144,7 @@ bool kgsl_popp_check(struct kgsl_device *device); #define KGSL_PWRSCALE_INIT(_priv_data) { \ - .enabled = false, \ + .enabled = true, \ .gpu_profile = { \ .private_data = _priv_data, \ .profile = { \ -- GitLab From 802d80cd74a91699b376dea336aa8dc4dcd911d4 Mon Sep 17 00:00:00 2001 From: Ritesh Harjani Date: Mon, 19 Mar 2018 15:49:54 +0530 Subject: [PATCH 0022/1635] ANDROID: sdcardfs: Fix sdcardfs to stop creating cases-sensitive duplicate entries. sdcardfs_name_match gets a 'name' argument from the underlying FS. This need not be null terminated string. So in sdcardfs_name_match -> qstr_case_eq -> we should use str_n_case_eq. This happens because few of the entries in lower level FS may not be NULL terminated and may have some garbage characters passed while doing sdcardfs_name_match. For e.g. # dmesg |grep Download [ 103.646386] sdcardfs_name_match: q1->name=.nomedia, q1->len=8, q2->name=Download\x17\x80\x03, q2->len=8 [ 104.021340] sdcardfs_name_match: q1->name=.nomedia, q1->len=8, q2->name=Download\x17\x80\x03, q2->len=8 [ 105.196864] sdcardfs_name_match: q1->name=.nomedia, q1->len=8, q2->name=Download\x17\x80\x03, q2->len=8 [ 109.113521] sdcardfs_name_match: q1->name=logs, q1->len=4, q2->name=Download\x17\x80\x03, q2->len=8 Now when we try to create a directory with different case for a such files. SDCARDFS creates a entry if it could not find the underlying entry in it's dcache. To reproduce:- 1. bootup the device wait for some time after sdcardfs mounting to complete. 2. cd /storage/emulated/0 3. echo 3 > /proc/sys/vm/drop_caches 4. mkdir download We now start seeing two entries with name. Download & download. Change-Id: I976d92a220a607dd8cdb96c01c2041c5c2bc3326 Signed-off-by: Ritesh Harjani bug: 75987238 --- fs/sdcardfs/sdcardfs.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/sdcardfs/sdcardfs.h b/fs/sdcardfs/sdcardfs.h index 610466ad153d..826afb5c7e88 100644 --- a/fs/sdcardfs/sdcardfs.h +++ b/fs/sdcardfs/sdcardfs.h @@ -669,7 +669,7 @@ static inline bool str_n_case_eq(const char *s1, const char *s2, size_t len) static inline bool qstr_case_eq(const struct qstr *q1, const struct qstr *q2) { - return q1->len == q2->len && str_case_eq(q1->name, q2->name); + return q1->len == q2->len && str_n_case_eq(q1->name, q2->name, q2->len); } #define QSTR_LITERAL(string) QSTR_INIT(string, sizeof(string)-1) -- GitLab From 4f5fd95e4062492f036a442ec1a66503de5a601f Mon Sep 17 00:00:00 2001 From: Sameer Thalappil Date: Thu, 30 Nov 2017 17:31:16 -0800 Subject: [PATCH 0023/1635] cnss: Add support to program MAC address thru debugfs MAC addresses provisioning thru CNSS is usually done by OEM drivers. Debugfs interfaces can be used for internal testing. Change-Id: I1a2693835ac09619baf03ee7d2e1b69dbe48559f Signed-off-by: Sameer Thalappil --- drivers/net/wireless/cnss_utils/cnss_utils.c | 137 ++++++++++++++++++- 1 file changed, 136 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/cnss_utils/cnss_utils.c b/drivers/net/wireless/cnss_utils/cnss_utils.c index 49551309c42c..77a58c8cb6a4 100644 --- a/drivers/net/wireless/cnss_utils/cnss_utils.c +++ b/drivers/net/wireless/cnss_utils/cnss_utils.c @@ -13,8 +13,10 @@ #define pr_fmt(fmt) "cnss_utils: " fmt #include +#include #include #include +#include #include #define CNSS_MAX_CH_NUM 45 @@ -29,6 +31,7 @@ struct cnss_dfs_nol_info { }; #define MAX_NO_OF_MAC_ADDR 4 +#define MAC_PREFIX_LEN 2 struct cnss_wlan_mac_addr { u8 mac_addr[MAX_NO_OF_MAC_ADDR][ETH_ALEN]; u32 no_of_mac_addr_set; @@ -50,6 +53,7 @@ static struct cnss_utils_priv { struct cnss_wlan_mac_addr wlan_mac_addr; struct cnss_wlan_mac_addr wlan_der_mac_addr; enum cnss_utils_cc_src cc_source; + struct dentry *root_dentry; } *cnss_utils_priv; int cnss_utils_set_wlan_unsafe_channel(struct device *dev, @@ -317,6 +321,137 @@ enum cnss_utils_cc_src cnss_utils_get_cc_source(struct device *dev) } EXPORT_SYMBOL(cnss_utils_get_cc_source); +static ssize_t cnss_utils_mac_write(struct file *fp, + const char __user *user_buf, + size_t count, loff_t *off) +{ + struct cnss_utils_priv *priv = + ((struct seq_file *)fp->private_data)->private; + char buf[128]; + char *input, *mac_type, *mac_address; + u8 *dest_mac; + u8 val; + const char *delim = " \n"; + size_t len = 0; + char temp[3] = ""; + + len = min_t(size_t, count, sizeof(buf) - 1); + if (copy_from_user(buf, user_buf, len)) + return -EINVAL; + buf[len] = '\0'; + + input = buf; + + mac_type = strsep(&input, delim); + if (!mac_type) + return -EINVAL; + if (!input) + return -EINVAL; + + mac_address = strsep(&input, delim); + if (!mac_address) + return -EINVAL; + if (strncmp("0x", mac_address, MAC_PREFIX_LEN)) { + pr_err("Invalid MAC prefix\n"); + return -EINVAL; + } + + len = strlen(mac_address); + mac_address += MAC_PREFIX_LEN; + len -= MAC_PREFIX_LEN; + if (len < ETH_ALEN * 2 || len > ETH_ALEN * 2 * MAX_NO_OF_MAC_ADDR || + len % (ETH_ALEN * 2) != 0) { + pr_err("Invalid MAC address length %zu\n", len); + return -EINVAL; + } + + if (!strcmp("provisioned", mac_type)) { + dest_mac = &priv->wlan_mac_addr.mac_addr[0][0]; + priv->wlan_mac_addr.no_of_mac_addr_set = len / (ETH_ALEN * 2); + } else if (!strcmp("derived", mac_type)) { + dest_mac = &priv->wlan_der_mac_addr.mac_addr[0][0]; + priv->wlan_der_mac_addr.no_of_mac_addr_set = + len / (ETH_ALEN * 2); + } else { + pr_err("Invalid MAC address type %s\n", mac_type); + return -EINVAL; + } + + while (len--) { + temp[0] = *mac_address++; + temp[1] = *mac_address++; + if (kstrtou8(temp, 16, &val)) + return -EINVAL; + *dest_mac++ = val; + } + return count; +} + +static int cnss_utils_mac_show(struct seq_file *s, void *data) +{ + u8 mac[6]; + int i; + struct cnss_utils_priv *priv = s->private; + struct cnss_wlan_mac_addr *addr = NULL; + + addr = &priv->wlan_mac_addr; + if (addr->no_of_mac_addr_set) { + seq_puts(s, "\nProvisioned MAC addresseses\n"); + for (i = 0; i < addr->no_of_mac_addr_set; i++) { + ether_addr_copy(mac, addr->mac_addr[i]); + seq_printf(s, "MAC_ADDR:%02x:%02x:%02x:%02x:%02x:%02x\n", + mac[0], mac[1], mac[2], + mac[3], mac[4], mac[5]); + } + } + + addr = &priv->wlan_der_mac_addr; + if (addr->no_of_mac_addr_set) { + seq_puts(s, "\nDerived MAC addresseses\n"); + for (i = 0; i < addr->no_of_mac_addr_set; i++) { + ether_addr_copy(mac, addr->mac_addr[i]); + seq_printf(s, "MAC_ADDR:%02x:%02x:%02x:%02x:%02x:%02x\n", + mac[0], mac[1], mac[2], + mac[3], mac[4], mac[5]); + } + } + + return 0; +} + +static int cnss_utils_mac_open(struct inode *inode, struct file *file) +{ + return single_open(file, cnss_utils_mac_show, inode->i_private); +} + +static const struct file_operations cnss_utils_mac_fops = { + .read = seq_read, + .write = cnss_utils_mac_write, + .release = single_release, + .open = cnss_utils_mac_open, + .owner = THIS_MODULE, + .llseek = seq_lseek, +}; + +static int cnss_utils_debugfs_create(struct cnss_utils_priv *priv) +{ + int ret = 0; + struct dentry *root_dentry; + + root_dentry = debugfs_create_dir("cnss_utils", NULL); + + if (IS_ERR(root_dentry)) { + ret = PTR_ERR(root_dentry); + pr_err("Unable to create debugfs %d\n", ret); + goto out; + } + priv->root_dentry = root_dentry; + debugfs_create_file("mac_address", 0600, root_dentry, priv, + &cnss_utils_mac_fops); +out: + return ret; +} + static int __init cnss_utils_init(void) { struct cnss_utils_priv *priv = NULL; @@ -329,7 +464,7 @@ static int __init cnss_utils_init(void) mutex_init(&priv->unsafe_channel_list_lock); spin_lock_init(&priv->dfs_nol_info_lock); - + cnss_utils_debugfs_create(priv); cnss_utils_priv = priv; return 0; -- GitLab From f956575ffd112277366c0cb91ed30e118a0b49fb Mon Sep 17 00:00:00 2001 From: Ritesh Harjani Date: Mon, 19 Mar 2018 16:03:09 +0530 Subject: [PATCH 0024/1635] ANDROID: fuse: Add null terminator to path in canonical path to avoid issue page allocated in fuse_dentry_canonical_path to be handled in fuse_dev_do_write is allocated using __get_free_pages(GFP_KERNEL). This may not return a page with data filled with 0. Now this page may not have a null terminator at all. If this happens and userspace fuse daemon screws up by passing a string to kernel which is not NULL terminated (or did not fill anything), then inside fuse driver in kernel when we try to do strlen(fuse_dev_write->kern_path->getname_kernel) on that page data -> it may give us issue with kernel paging request. Unable to handle kernel paging request at virtual address ------------[ cut here ]------------ <..> PC is at strlen+0x10/0x90 LR is at getname_kernel+0x2c/0xf4 <..> strlen+0x10/0x90 kern_path+0x28/0x4c fuse_dev_do_write+0x5b8/0x694 fuse_dev_write+0x74/0x94 do_iter_readv_writev+0x80/0xb8 do_readv_writev+0xec/0x1cc vfs_writev+0x54/0x64 SyS_writev+0x64/0xe4 el0_svc_naked+0x24/0x28 To avoid this we should ensure in case of FUSE_CANONICAL_PATH, the page is null terminated. Change-Id: I33ca7cc76b4472eaa982c67bb20685df451121f5 Signed-off-by: Ritesh Harjani Bug: 75984715 [Daniel - small edit, using args size ] Signed-off-by: Daniel Rosenberg --- fs/fuse/dev.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c index 032485010a05..968b79823502 100644 --- a/fs/fuse/dev.c +++ b/fs/fuse/dev.c @@ -1892,8 +1892,10 @@ static ssize_t fuse_dev_do_write(struct fuse_dev *fud, err = copy_out_args(cs, &req->out, nbytes); if (req->in.h.opcode == FUSE_CANONICAL_PATH) { - req->out.h.error = kern_path((char *)req->out.args[0].value, 0, - req->canonical_path); + char *path = (char *)req->out.args[0].value; + + path[req->out.args[0].size - 1] = 0; + req->out.h.error = kern_path(path, 0, req->canonical_path); } fuse_copy_finish(cs); -- GitLab From a4941a5fbcf0f4560ce7dda6c7e5f39b7c51761f Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Wed, 21 Mar 2018 08:16:29 -0700 Subject: [PATCH 0025/1635] ARM: OMAP: Fix SRAM W+X mapping commit eb85a355c3afd9379f5953cfe2df73632d14c884 upstream. We are still using custom SRAM code for some SoCs and are not marking the PM code mapped to SRAM as read-only and executable after we're done. With CONFIG_DEBUG_WX=y, we will get "Found insecure W+X mapping at address" warning. Let's fix this issue the same way as commit 728bbe75c82f ("misc: sram: Introduce support code for protect-exec sram type") is doing for drivers/misc/sram-exec.c. On omap3, we need to restore SRAM when returning from off mode after idle, so init time configuration is not enough. And as we no longer have users for omap_sram_push_address() we can make it static while at it. Note that eventually we should be using sram-exec.c for all SoCs. Cc: stable@vger.kernel.org # v4.12+ Cc: Dave Gerlach Reported-by: Pavel Machek Signed-off-by: Tony Lindgren Signed-off-by: Greg Kroah-Hartman --- arch/arm/plat-omap/include/plat/sram.h | 11 +------- arch/arm/plat-omap/sram.c | 36 +++++++++++++++++++++++++- 2 files changed, 36 insertions(+), 11 deletions(-) diff --git a/arch/arm/plat-omap/include/plat/sram.h b/arch/arm/plat-omap/include/plat/sram.h index fb061cf0d736..30a07730807a 100644 --- a/arch/arm/plat-omap/include/plat/sram.h +++ b/arch/arm/plat-omap/include/plat/sram.h @@ -5,13 +5,4 @@ void omap_map_sram(unsigned long start, unsigned long size, unsigned long skip, int cached); void omap_sram_reset(void); -extern void *omap_sram_push_address(unsigned long size); - -/* Macro to push a function to the internal SRAM, using the fncpy API */ -#define omap_sram_push(funcp, size) ({ \ - typeof(&(funcp)) _res = NULL; \ - void *_sram_address = omap_sram_push_address(size); \ - if (_sram_address) \ - _res = fncpy(_sram_address, &(funcp), size); \ - _res; \ -}) +extern void *omap_sram_push(void *funcp, unsigned long size); diff --git a/arch/arm/plat-omap/sram.c b/arch/arm/plat-omap/sram.c index a5bc92d7e476..921840acf65c 100644 --- a/arch/arm/plat-omap/sram.c +++ b/arch/arm/plat-omap/sram.c @@ -23,6 +23,7 @@ #include #include #include +#include #include @@ -42,7 +43,7 @@ static void __iomem *omap_sram_ceil; * Note that fncpy requires the returned address to be aligned * to an 8-byte boundary. */ -void *omap_sram_push_address(unsigned long size) +static void *omap_sram_push_address(unsigned long size) { unsigned long available, new_ceil = (unsigned long)omap_sram_ceil; @@ -60,6 +61,30 @@ void *omap_sram_push_address(unsigned long size) return (void *)omap_sram_ceil; } +void *omap_sram_push(void *funcp, unsigned long size) +{ + void *sram; + unsigned long base; + int pages; + void *dst = NULL; + + sram = omap_sram_push_address(size); + if (!sram) + return NULL; + + base = (unsigned long)sram & PAGE_MASK; + pages = PAGE_ALIGN(size) / PAGE_SIZE; + + set_memory_rw(base, pages); + + dst = fncpy(sram, funcp, size); + + set_memory_ro(base, pages); + set_memory_x(base, pages); + + return dst; +} + /* * The SRAM context is lost during off-idle and stack * needs to be reset. @@ -75,6 +100,9 @@ void omap_sram_reset(void) void __init omap_map_sram(unsigned long start, unsigned long size, unsigned long skip, int cached) { + unsigned long base; + int pages; + if (size == 0) return; @@ -95,4 +123,10 @@ void __init omap_map_sram(unsigned long start, unsigned long size, */ memset_io(omap_sram_base + omap_sram_skip, 0, omap_sram_size - omap_sram_skip); + + base = (unsigned long)omap_sram_base; + pages = PAGE_ALIGN(omap_sram_size) / PAGE_SIZE; + + set_memory_ro(base, pages); + set_memory_x(base, pages); } -- GitLab From d377d3d041b7793cc9083b5029e85dffed90afa8 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Mon, 22 Jan 2018 12:20:26 +0100 Subject: [PATCH 0026/1635] ARM: 8746/1: vfp: Go back to clearing vfp_current_hw_state[] commit 1328f02005bbbaed15b9d5b7f3ab5ec9d4d5268a upstream. Commit 384b38b66947 ("ARM: 7873/1: vfp: clear vfp_current_hw_state for dying cpu") fixed the cpu dying notifier by clearing vfp_current_hw_state[]. However commit e5b61bafe704 ("arm: Convert VFP hotplug notifiers to state machine") incorrectly used the original vfp_force_reload() function in the cpu dying notifier. Fix it by going back to clearing vfp_current_hw_state[]. Fixes: e5b61bafe704 ("arm: Convert VFP hotplug notifiers to state machine") Cc: linux-stable Reported-by: Kohji Okuno Signed-off-by: Fabio Estevam Signed-off-by: Russell King Signed-off-by: Greg Kroah-Hartman --- arch/arm/vfp/vfpmodule.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/vfp/vfpmodule.c b/arch/arm/vfp/vfpmodule.c index a71a48e71fff..aa7496be311d 100644 --- a/arch/arm/vfp/vfpmodule.c +++ b/arch/arm/vfp/vfpmodule.c @@ -648,7 +648,7 @@ int vfp_restore_user_hwstate(struct user_vfp __user *ufp, */ static int vfp_dying_cpu(unsigned int cpu) { - vfp_force_reload(cpu, current_thread_info()); + vfp_current_hw_state[cpu] = NULL; return 0; } -- GitLab From 46e10c38af0c843766dc0f25d333363aa2ebc71c Mon Sep 17 00:00:00 2001 From: Philipp Rossak Date: Wed, 14 Feb 2018 15:10:24 +0100 Subject: [PATCH 0027/1635] ARM: dts: sun6i: a31s: bpi-m2: improve pmic properties commit b23af6ad8d2f708c4c3f92dd8f82c233247ba8bf upstream. The eldoin is supplied from the dcdc1 regulator. The N_VBUSEN pin is connected to an external power regulator (SY6280AAC). With this commit we update the pmic binding properties to support those features. Fixes: 7daa21370075 ("ARM: dts: sunxi: Add regulators for Sinovoip BPI-M2") Cc: Signed-off-by: Philipp Rossak Signed-off-by: Maxime Ripard Signed-off-by: Greg Kroah-Hartman --- arch/arm/boot/dts/sun6i-a31s-sinovoip-bpi-m2.dts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm/boot/dts/sun6i-a31s-sinovoip-bpi-m2.dts b/arch/arm/boot/dts/sun6i-a31s-sinovoip-bpi-m2.dts index 51e6f1d21c32..fb34f32502cf 100644 --- a/arch/arm/boot/dts/sun6i-a31s-sinovoip-bpi-m2.dts +++ b/arch/arm/boot/dts/sun6i-a31s-sinovoip-bpi-m2.dts @@ -163,6 +163,8 @@ reg = <0x68>; interrupt-parent = <&nmi_intc>; interrupts = <0 IRQ_TYPE_LEVEL_LOW>; + eldoin-supply = <®_dcdc1>; + x-powers,drive-vbus-en; }; }; -- GitLab From 67356ab6e6a9aea6aa2d0783b2e46e46d7c09e6a Mon Sep 17 00:00:00 2001 From: Philipp Rossak Date: Wed, 14 Feb 2018 15:10:25 +0100 Subject: [PATCH 0028/1635] ARM: dts: sun6i: a31s: bpi-m2: add missing regulators commit 70b8d21496758dd7ff600ec9de0ee3812fac7a40 upstream. This patch fixes a bootproblem with the Bananapi M2 board. Since there are some regulators missing we add them right now. Those values come from the schematic, below you can find a small overview: * reg_aldo1: 3,3V, powers the wifi * reg_aldo2: 2,5V, powers the IO of the RTL8211E * reg_aldo3: 3,3V, powers the audio * reg_dldo1: 3,0V, powers the RTL8211E * reg_dldo2: 2,8V, powers the analog part of the csi * reg_dldo3: 3,3V, powers misc * reg_eldo1: 1,8V, powers the csi * reg_ldo_io1:1,8V, powers the gpio * reg_dc5ldo: needs to be always on This patch updates also the vmmc-supply properties on the mmc0 and mmc2 node to use the allready existent regulators. We can now remove the sunxi-common-regulators.dtsi include since we don't need it anymore. Fixes: 7daa21370075 ("ARM: dts: sunxi: Add regulators for Sinovoip BPI-M2") Cc: Signed-off-by: Philipp Rossak Signed-off-by: Maxime Ripard Signed-off-by: Greg Kroah-Hartman --- .../boot/dts/sun6i-a31s-sinovoip-bpi-m2.dts | 61 ++++++++++++++++++- 1 file changed, 58 insertions(+), 3 deletions(-) diff --git a/arch/arm/boot/dts/sun6i-a31s-sinovoip-bpi-m2.dts b/arch/arm/boot/dts/sun6i-a31s-sinovoip-bpi-m2.dts index fb34f32502cf..b2758dd8ce43 100644 --- a/arch/arm/boot/dts/sun6i-a31s-sinovoip-bpi-m2.dts +++ b/arch/arm/boot/dts/sun6i-a31s-sinovoip-bpi-m2.dts @@ -42,7 +42,6 @@ /dts-v1/; #include "sun6i-a31s.dtsi" -#include "sunxi-common-regulators.dtsi" #include / { @@ -99,6 +98,7 @@ pinctrl-0 = <&gmac_pins_rgmii_a>, <&gmac_phy_reset_pin_bpi_m2>; phy = <&phy1>; phy-mode = "rgmii"; + phy-supply = <®_dldo1>; snps,reset-gpio = <&pio 0 21 GPIO_ACTIVE_HIGH>; /* PA21 */ snps,reset-active-low; snps,reset-delays-us = <0 10000 30000>; @@ -118,7 +118,7 @@ &mmc0 { pinctrl-names = "default"; pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_bpi_m2>; - vmmc-supply = <®_vcc3v0>; + vmmc-supply = <®_dcdc1>; bus-width = <4>; cd-gpios = <&pio 0 4 GPIO_ACTIVE_HIGH>; /* PA4 */ cd-inverted; @@ -132,7 +132,7 @@ &mmc2 { pinctrl-names = "default"; pinctrl-0 = <&mmc2_pins_a>; - vmmc-supply = <®_vcc3v0>; + vmmc-supply = <®_aldo1>; mmc-pwrseq = <&mmc2_pwrseq>; bus-width = <4>; non-removable; @@ -195,7 +195,28 @@ #include "axp22x.dtsi" +®_aldo1 { + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-name = "vcc-wifi"; +}; + +®_aldo2 { + regulator-always-on; + regulator-min-microvolt = <2500000>; + regulator-max-microvolt = <2500000>; + regulator-name = "vcc-gmac"; +}; + +®_aldo3 { + regulator-always-on; + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <3000000>; + regulator-name = "avcc"; +}; + ®_dc5ldo { + regulator-always-on; regulator-min-microvolt = <700000>; regulator-max-microvolt = <1320000>; regulator-name = "vdd-cpus"; @@ -235,6 +256,40 @@ regulator-name = "vcc-dram"; }; +®_dldo1 { + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <3000000>; + regulator-name = "vcc-mac"; +}; + +®_dldo2 { + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; + regulator-name = "avdd-csi"; +}; + +®_dldo3 { + regulator-always-on; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-name = "vcc-pb"; +}; + +®_eldo1 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-name = "vdd-csi"; + status = "okay"; +}; + +®_ldo_io1 { + regulator-always-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-name = "vcc-pm-cpus"; + status = "okay"; +}; + &uart0 { pinctrl-names = "default"; pinctrl-0 = <&uart0_pins_a>; -- GitLab From e9eddb705648015118c5a8bce8d9c34f8f182ba8 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Sat, 3 Mar 2018 23:29:03 +0100 Subject: [PATCH 0029/1635] mtd: jedec_probe: Fix crash in jedec_read_mfr() commit 87a73eb5b56fd6e07c8e499fe8608ef2d8912b82 upstream. It turns out that the loop where we read manufacturer jedec_read_mfd() can under some circumstances get a CFI_MFR_CONTINUATION repeatedly, making the loop go over all banks and eventually hit the end of the map and crash because of an access violation: Unable to handle kernel paging request at virtual address c4980000 pgd = (ptrval) [c4980000] *pgd=03808811, *pte=00000000, *ppte=00000000 Internal error: Oops: 7 [#1] PREEMPT ARM CPU: 0 PID: 1 Comm: swapper Not tainted 4.16.0-rc1+ #150 Hardware name: Gemini (Device Tree) PC is at jedec_probe_chip+0x6ec/0xcd0 LR is at 0x4 pc : [] lr : [<00000004>] psr: 60000013 sp : c382dd18 ip : 0000ffff fp : 00000000 r10: c0626388 r9 : 00020000 r8 : c0626340 r7 : 00000000 r6 : 00000001 r5 : c3a71afc r4 : c382dd70 r3 : 00000001 r2 : c4900000 r1 : 00000002 r0 : 00080000 Flags: nZCv IRQs on FIQs on Mode SVC_32 ISA ARM Segment none Control: 0000397f Table: 00004000 DAC: 00000053 Process swapper (pid: 1, stack limit = 0x(ptrval)) Fix this by breaking the loop with a return 0 if the offset exceeds the map size. Fixes: 5c9c11e1c47c ("[MTD] [NOR] Add support for flash chips with ID in bank other than 0") Cc: Signed-off-by: Linus Walleij Signed-off-by: Boris Brezillon Signed-off-by: Greg Kroah-Hartman --- drivers/mtd/chips/jedec_probe.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/mtd/chips/jedec_probe.c b/drivers/mtd/chips/jedec_probe.c index 7c0b27d132b1..b479bd81120b 100644 --- a/drivers/mtd/chips/jedec_probe.c +++ b/drivers/mtd/chips/jedec_probe.c @@ -1889,6 +1889,8 @@ static inline u32 jedec_read_mfr(struct map_info *map, uint32_t base, do { uint32_t ofs = cfi_build_cmd_addr(0 + (bank << 8), map, cfi); mask = (1 << (cfi->device_type * 8)) - 1; + if (ofs >= map->size) + return 0; result = map_read(map, base + ofs); bank++; } while ((result.x[0] & mask) == CFI_MFR_CONTINUATION); -- GitLab From be0fdc488672ab1a0e7dad9f7b884df60142cda7 Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Tue, 27 Mar 2018 19:01:58 +0200 Subject: [PATCH 0030/1635] mtd: nand: atmel: Fix get_sectorsize() function commit 2b1b1b4ac716fd929a2d221bd4ade62263bed915 upstream. get_sectorsize() was not using the appropriate macro to extract the ECC sector size from the config cache, which led to buggy ECC when using 1024 byte sectors. Fixes: f88fc122cc34 ("mtd: nand: Cleanup/rework the atmel_nand driver") Cc: Reported-by: Olivier Schonken Signed-off-by: Boris Brezillon Reviewed-by: Richard Weinberger Acked-by: Nicolas Ferre Tested-by: Olivier Schonken Signed-off-by: Greg Kroah-Hartman --- drivers/mtd/nand/atmel/pmecc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mtd/nand/atmel/pmecc.c b/drivers/mtd/nand/atmel/pmecc.c index 8268636675ef..4124bf91bee6 100644 --- a/drivers/mtd/nand/atmel/pmecc.c +++ b/drivers/mtd/nand/atmel/pmecc.c @@ -426,7 +426,7 @@ static int get_strength(struct atmel_pmecc_user *user) static int get_sectorsize(struct atmel_pmecc_user *user) { - return user->cache.cfg & PMECC_LOOKUP_TABLE_SIZE_1024 ? 1024 : 512; + return user->cache.cfg & PMECC_CFG_SECTOR1024 ? 1024 : 512; } static void atmel_pmecc_gen_syndrome(struct atmel_pmecc_user *user, int sector) -- GitLab From ba0b1c7761b464fcfa979393ffd905613cd2d672 Mon Sep 17 00:00:00 2001 From: Nobutaka Okabe Date: Fri, 23 Mar 2018 19:49:44 +0900 Subject: [PATCH 0031/1635] ALSA: usb-audio: Add native DSD support for TEAC UD-301 commit b00214865d65100163574ba250008f182cf90869 upstream. Add native DSD support quirk for TEAC UD-301 DAC, by adding the PID/VID 0644:804a. Signed-off-by: Nobutaka Okabe Cc: Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/usb/quirks.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c index ed56cd307059..58f94f399efb 100644 --- a/sound/usb/quirks.c +++ b/sound/usb/quirks.c @@ -1177,6 +1177,7 @@ static bool is_teac_dsd_dac(unsigned int id) switch (id) { case USB_ID(0x0644, 0x8043): /* TEAC UD-501/UD-503/NT-503 */ case USB_ID(0x0644, 0x8044): /* Esoteric D-05X */ + case USB_ID(0x0644, 0x804a): /* TEAC UD-301 */ return true; } return false; -- GitLab From 17c9ea37cb6068765e770a3b4b8dc33f69a8c935 Mon Sep 17 00:00:00 2001 From: Stefan Roese Date: Mon, 26 Mar 2018 16:10:21 +0200 Subject: [PATCH 0032/1635] ALSA: pcm: Use dma_bytes as size parameter in dma_mmap_coherent() commit 9066ae7ff5d89c0b5daa271e2d573540097a94fa upstream. When trying to use the driver (e.g. aplay *.wav), the 4MiB DMA buffer will get mmapp'ed in 16KiB chunks. But this fails with the 2nd 16KiB area, as the page offset is outside of the VMA range (size), which is currently used as size parameter in snd_pcm_lib_default_mmap(). By using the DMA buffer size (dma_bytes) instead, the complete DMA buffer can be mmapp'ed and the issue is fixed. This issue was detected on an ARM platform (TI AM57xx) using the RME HDSP MADI PCIe soundcard. Fixes: 657b1989dacf ("ALSA: pcm - Use dma_mmap_coherent() if available") Signed-off-by: Stefan Roese Cc: Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/core/pcm_native.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 499f75b18e09..eba2bedcbc81 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -3424,7 +3424,7 @@ int snd_pcm_lib_default_mmap(struct snd_pcm_substream *substream, area, substream->runtime->dma_area, substream->runtime->dma_addr, - area->vm_end - area->vm_start); + substream->runtime->dma_bytes); #endif /* CONFIG_X86 */ /* mmap with fault handler */ area->vm_ops = &snd_pcm_vm_ops_data_fault; -- GitLab From 58eaa556bd0a8d1c6a9b06a37758ab147cd55501 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 27 Mar 2018 16:07:52 +0300 Subject: [PATCH 0033/1635] ALSA: pcm: potential uninitialized return values commit 5607dddbfca774fb38bffadcb077fe03aa4ac5c6 upstream. Smatch complains that "tmp" can be uninitialized if we do a zero size write. Fixes: 02a5d6925cd3 ("ALSA: pcm: Avoid potential races between OSS ioctls and read/write") Signed-off-by: Dan Carpenter Cc: Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/core/oss/pcm_oss.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c index 012881461058..d6e9a18fd821 100644 --- a/sound/core/oss/pcm_oss.c +++ b/sound/core/oss/pcm_oss.c @@ -1326,7 +1326,7 @@ static ssize_t snd_pcm_oss_write2(struct snd_pcm_substream *substream, const cha static ssize_t snd_pcm_oss_write1(struct snd_pcm_substream *substream, const char __user *buf, size_t bytes) { size_t xfer = 0; - ssize_t tmp; + ssize_t tmp = 0; struct snd_pcm_runtime *runtime = substream->runtime; if (atomic_read(&substream->mmap_count)) @@ -1433,7 +1433,7 @@ static ssize_t snd_pcm_oss_read2(struct snd_pcm_substream *substream, char *buf, static ssize_t snd_pcm_oss_read1(struct snd_pcm_substream *substream, char __user *buf, size_t bytes) { size_t xfer = 0; - ssize_t tmp; + ssize_t tmp = 0; struct snd_pcm_runtime *runtime = substream->runtime; if (atomic_read(&substream->mmap_count)) -- GitLab From b276b34655314d0c9df9941357f75382e2847be1 Mon Sep 17 00:00:00 2001 From: Andrew Banman Date: Tue, 27 Mar 2018 17:09:06 -0500 Subject: [PATCH 0034/1635] x86/platform/uv/BAU: Add APIC idt entry commit 151ad17fbe5e56afa59709f41980508672c777ce upstream. BAU uses the old alloc_initr_gate90 method to setup its interrupt. This fails silently as the BAU vector is in the range of APIC vectors that are registered to the spurious interrupt handler. As a consequence BAU broadcasts are not handled, and the broadcast source CPU hangs. Update BAU to use new idt structure. Fixes: dc20b2d52653 ("x86/idt: Move interrupt gate initialization to IDT code") Signed-off-by: Andrew Banman Signed-off-by: Thomas Gleixner Acked-by: Mike Travis Cc: Dimitri Sivanich Cc: Russ Anderson Cc: stable@vger.kernel.org Cc: "H. Peter Anvin" Link: https://lkml.kernel.org/r/1522188546-196177-1-git-send-email-abanman@hpe.com Signed-off-by: Greg Kroah-Hartman --- arch/x86/include/asm/hw_irq.h | 1 + arch/x86/kernel/idt.c | 3 +++ arch/x86/platform/uv/tlb_uv.c | 2 -- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/arch/x86/include/asm/hw_irq.h b/arch/x86/include/asm/hw_irq.h index 8ec99a55e6b9..bf253ad93bbc 100644 --- a/arch/x86/include/asm/hw_irq.h +++ b/arch/x86/include/asm/hw_irq.h @@ -34,6 +34,7 @@ extern asmlinkage void kvm_posted_intr_wakeup_ipi(void); extern asmlinkage void kvm_posted_intr_nested_ipi(void); extern asmlinkage void error_interrupt(void); extern asmlinkage void irq_work_interrupt(void); +extern asmlinkage void uv_bau_message_intr1(void); extern asmlinkage void spurious_interrupt(void); extern asmlinkage void thermal_interrupt(void); diff --git a/arch/x86/kernel/idt.c b/arch/x86/kernel/idt.c index a59624080015..0c5256653d6c 100644 --- a/arch/x86/kernel/idt.c +++ b/arch/x86/kernel/idt.c @@ -140,6 +140,9 @@ static const __initconst struct idt_data apic_idts[] = { # ifdef CONFIG_IRQ_WORK INTG(IRQ_WORK_VECTOR, irq_work_interrupt), # endif +#ifdef CONFIG_X86_UV + INTG(UV_BAU_MESSAGE, uv_bau_message_intr1), +#endif INTG(SPURIOUS_APIC_VECTOR, spurious_interrupt), INTG(ERROR_APIC_VECTOR, error_interrupt), #endif diff --git a/arch/x86/platform/uv/tlb_uv.c b/arch/x86/platform/uv/tlb_uv.c index 7d5d53f36a7a..0b530c53de1f 100644 --- a/arch/x86/platform/uv/tlb_uv.c +++ b/arch/x86/platform/uv/tlb_uv.c @@ -2254,8 +2254,6 @@ static int __init uv_bau_init(void) init_uvhub(uvhub, vector, uv_base_pnode); } - alloc_intr_gate(vector, uv_bau_message_intr1); - for_each_possible_blade(uvhub) { if (uv_blade_nr_possible_cpus(uvhub)) { unsigned long val; -- GitLab From ca04476df8fd39c71818352db43090bd17dd1d58 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Mon, 26 Mar 2018 15:39:07 -1000 Subject: [PATCH 0035/1635] perf/hwbp: Simplify the perf-hwbp code, fix documentation commit f67b15037a7a50c57f72e69a6d59941ad90a0f0f upstream. Annoyingly, modify_user_hw_breakpoint() unnecessarily complicates the modification of a breakpoint - simplify it and remove the pointless local variables. Also update the stale Docbook while at it. Signed-off-by: Linus Torvalds Acked-by: Thomas Gleixner Cc: Cc: Alexander Shishkin Cc: Andy Lutomirski Cc: Arnaldo Carvalho de Melo Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Vince Weaver Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman --- kernel/events/hw_breakpoint.c | 30 +++++++----------------------- 1 file changed, 7 insertions(+), 23 deletions(-) diff --git a/kernel/events/hw_breakpoint.c b/kernel/events/hw_breakpoint.c index 3f8cb1e14588..253ae2da13c3 100644 --- a/kernel/events/hw_breakpoint.c +++ b/kernel/events/hw_breakpoint.c @@ -427,16 +427,9 @@ EXPORT_SYMBOL_GPL(register_user_hw_breakpoint); * modify_user_hw_breakpoint - modify a user-space hardware breakpoint * @bp: the breakpoint structure to modify * @attr: new breakpoint attributes - * @triggered: callback to trigger when we hit the breakpoint - * @tsk: pointer to 'task_struct' of the process to which the address belongs */ int modify_user_hw_breakpoint(struct perf_event *bp, struct perf_event_attr *attr) { - u64 old_addr = bp->attr.bp_addr; - u64 old_len = bp->attr.bp_len; - int old_type = bp->attr.bp_type; - int err = 0; - /* * modify_user_hw_breakpoint can be invoked with IRQs disabled and hence it * will not be possible to raise IPIs that invoke __perf_event_disable. @@ -451,27 +444,18 @@ int modify_user_hw_breakpoint(struct perf_event *bp, struct perf_event_attr *att bp->attr.bp_addr = attr->bp_addr; bp->attr.bp_type = attr->bp_type; bp->attr.bp_len = attr->bp_len; + bp->attr.disabled = 1; - if (attr->disabled) - goto end; - - err = validate_hw_breakpoint(bp); - if (!err) - perf_event_enable(bp); + if (!attr->disabled) { + int err = validate_hw_breakpoint(bp); - if (err) { - bp->attr.bp_addr = old_addr; - bp->attr.bp_type = old_type; - bp->attr.bp_len = old_len; - if (!bp->attr.disabled) - perf_event_enable(bp); + if (err) + return err; - return err; + perf_event_enable(bp); + bp->attr.disabled = 0; } -end: - bp->attr.disabled = attr->disabled; - return 0; } EXPORT_SYMBOL_GPL(modify_user_hw_breakpoint); -- GitLab From f00a344718dddd1a60e3926f4900d31d1b3ff182 Mon Sep 17 00:00:00 2001 From: "Yan, Zheng" Date: Fri, 16 Mar 2018 11:22:29 +0800 Subject: [PATCH 0036/1635] ceph: only dirty ITER_IOVEC pages for direct read commit 85784f9395987a422fa04263e7c0fb13da11eb5c upstream. If a page is already locked, attempting to dirty it leads to a deadlock in lock_page(). This is what currently happens to ITER_BVEC pages when a dio-enabled loop device is backed by ceph: $ losetup --direct-io /dev/loop0 /mnt/cephfs/img $ xfs_io -c 'pread 0 4k' /dev/loop0 Follow other file systems and only dirty ITER_IOVEC pages. Cc: stable@kernel.org Signed-off-by: "Yan, Zheng" Reviewed-by: Ilya Dryomov Signed-off-by: Ilya Dryomov Signed-off-by: Greg Kroah-Hartman --- fs/ceph/file.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/fs/ceph/file.c b/fs/ceph/file.c index 5c17125f45c7..0024d3e61bcd 100644 --- a/fs/ceph/file.c +++ b/fs/ceph/file.c @@ -635,7 +635,8 @@ static ssize_t ceph_sync_read(struct kiocb *iocb, struct iov_iter *to, struct ceph_aio_request { struct kiocb *iocb; size_t total_len; - int write; + bool write; + bool should_dirty; int error; struct list_head osd_reqs; unsigned num_reqs; @@ -745,7 +746,7 @@ static void ceph_aio_complete_req(struct ceph_osd_request *req) } } - ceph_put_page_vector(osd_data->pages, num_pages, !aio_req->write); + ceph_put_page_vector(osd_data->pages, num_pages, aio_req->should_dirty); ceph_osdc_put_request(req); if (rc < 0) @@ -842,6 +843,7 @@ ceph_direct_read_write(struct kiocb *iocb, struct iov_iter *iter, size_t count = iov_iter_count(iter); loff_t pos = iocb->ki_pos; bool write = iov_iter_rw(iter) == WRITE; + bool should_dirty = !write && iter_is_iovec(iter); if (write && ceph_snap(file_inode(file)) != CEPH_NOSNAP) return -EROFS; @@ -909,6 +911,7 @@ ceph_direct_read_write(struct kiocb *iocb, struct iov_iter *iter, if (aio_req) { aio_req->iocb = iocb; aio_req->write = write; + aio_req->should_dirty = should_dirty; INIT_LIST_HEAD(&aio_req->osd_reqs); if (write) { aio_req->mtime = mtime; @@ -966,7 +969,7 @@ ceph_direct_read_write(struct kiocb *iocb, struct iov_iter *iter, len = ret; } - ceph_put_page_vector(pages, num_pages, !write); + ceph_put_page_vector(pages, num_pages, should_dirty); ceph_osdc_put_request(req); if (ret < 0) -- GitLab From f025072cbfe3aec5b6e13618b1c3275868a4a541 Mon Sep 17 00:00:00 2001 From: Mike Kravetz Date: Wed, 28 Mar 2018 16:01:01 -0700 Subject: [PATCH 0037/1635] ipc/shm.c: add split function to shm_vm_ops commit 3d942ee079b917b24e2a0c5f18d35ac8ec9fee48 upstream. If System V shmget/shmat operations are used to create a hugetlbfs backed mapping, it is possible to munmap part of the mapping and split the underlying vma such that it is not huge page aligned. This will untimately result in the following BUG: kernel BUG at /build/linux-jWa1Fv/linux-4.15.0/mm/hugetlb.c:3310! Oops: Exception in kernel mode, sig: 5 [#1] LE SMP NR_CPUS=2048 NUMA PowerNV Modules linked in: kcm nfc af_alg caif_socket caif phonet fcrypt CPU: 18 PID: 43243 Comm: trinity-subchil Tainted: G C E 4.15.0-10-generic #11-Ubuntu NIP: c00000000036e764 LR: c00000000036ee48 CTR: 0000000000000009 REGS: c000003fbcdcf810 TRAP: 0700 Tainted: G C E (4.15.0-10-generic) MSR: 9000000000029033 CR: 24002222 XER: 20040000 CFAR: c00000000036ee44 SOFTE: 1 NIP __unmap_hugepage_range+0xa4/0x760 LR __unmap_hugepage_range_final+0x28/0x50 Call Trace: 0x7115e4e00000 (unreliable) __unmap_hugepage_range_final+0x28/0x50 unmap_single_vma+0x11c/0x190 unmap_vmas+0x94/0x140 exit_mmap+0x9c/0x1d0 mmput+0xa8/0x1d0 do_exit+0x360/0xc80 do_group_exit+0x60/0x100 SyS_exit_group+0x24/0x30 system_call+0x58/0x6c ---[ end trace ee88f958a1c62605 ]--- This bug was introduced by commit 31383c6865a5 ("mm, hugetlbfs: introduce ->split() to vm_operations_struct"). A split function was added to vm_operations_struct to determine if a mapping can be split. This was mostly for device-dax and hugetlbfs mappings which have specific alignment constraints. Mappings initiated via shmget/shmat have their original vm_ops overwritten with shm_vm_ops. shm_vm_ops functions will call back to the original vm_ops if needed. Add such a split function to shm_vm_ops. Link: http://lkml.kernel.org/r/20180321161314.7711-1-mike.kravetz@oracle.com Fixes: 31383c6865a5 ("mm, hugetlbfs: introduce ->split() to vm_operations_struct") Signed-off-by: Mike Kravetz Reported-by: Laurent Dufour Reviewed-by: Laurent Dufour Tested-by: Laurent Dufour Reviewed-by: Dan Williams Acked-by: Michal Hocko Cc: Davidlohr Bueso Cc: Manfred Spraul Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- ipc/shm.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/ipc/shm.c b/ipc/shm.c index bd652755d32c..b469e910f887 100644 --- a/ipc/shm.c +++ b/ipc/shm.c @@ -386,6 +386,17 @@ static int shm_fault(struct vm_fault *vmf) return sfd->vm_ops->fault(vmf); } +static int shm_split(struct vm_area_struct *vma, unsigned long addr) +{ + struct file *file = vma->vm_file; + struct shm_file_data *sfd = shm_file_data(file); + + if (sfd->vm_ops && sfd->vm_ops->split) + return sfd->vm_ops->split(vma, addr); + + return 0; +} + #ifdef CONFIG_NUMA static int shm_set_policy(struct vm_area_struct *vma, struct mempolicy *new) { @@ -510,6 +521,7 @@ static const struct vm_operations_struct shm_vm_ops = { .open = shm_open, /* callback for a new vm-area open */ .close = shm_close, /* callback for when the vm-area is released */ .fault = shm_fault, + .split = shm_split, #if defined(CONFIG_NUMA) .set_policy = shm_set_policy, .get_policy = shm_get_policy, -- GitLab From 834a06e59896aef1fe05d603eb0e161a4d969d84 Mon Sep 17 00:00:00 2001 From: Pierre-Yves MORDRET Date: Wed, 21 Mar 2018 17:48:40 +0100 Subject: [PATCH 0038/1635] i2c: i2c-stm32f7: fix no check on returned setup commit 771b7bf05339081019d22452ebcab6929372e13e upstream. Before assigning returned setup structure check if not null Fixes: 463a9215f3ca7600b5ff ("i2c: stm32f7: fix setup structure") Signed-off-by: Pierre-Yves MORDRET Acked-by: Alexandre TORGUE Signed-off-by: Wolfram Sang Cc: stable@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/i2c/busses/i2c-stm32f7.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/i2c/busses/i2c-stm32f7.c b/drivers/i2c/busses/i2c-stm32f7.c index d4a6e9c2e9aa..124f9b1cf1b0 100644 --- a/drivers/i2c/busses/i2c-stm32f7.c +++ b/drivers/i2c/busses/i2c-stm32f7.c @@ -887,6 +887,11 @@ static int stm32f7_i2c_probe(struct platform_device *pdev) } setup = of_device_get_match_data(&pdev->dev); + if (!setup) { + dev_err(&pdev->dev, "Can't get device data\n"); + ret = -ENODEV; + goto clk_free; + } i2c_dev->setup = *setup; ret = device_property_read_u32(i2c_dev->dev, "i2c-scl-rising-time-ns", -- GitLab From 4c6d2518e1fedcdc2755457eb630a1977769e810 Mon Sep 17 00:00:00 2001 From: Nicholas Piggin Date: Wed, 21 Mar 2018 12:22:28 +1000 Subject: [PATCH 0039/1635] powerpc/64s: Fix lost pending interrupt due to race causing lost update to irq_happened commit ff6781fd1bb404d8a551c02c35c70cec1da17ff1 upstream. force_external_irq_replay() can be called in the do_IRQ path with interrupts hard enabled and soft disabled if may_hard_irq_enable() set MSR[EE]=1. It updates local_paca->irq_happened with a load, modify, store sequence. If a maskable interrupt hits during this sequence, it will go to the masked handler to be marked pending in irq_happened. This update will be lost when the interrupt returns and the store instruction executes. This can result in unpredictable latencies, timeouts, lockups, etc. Fix this by ensuring hard interrupts are disabled before modifying irq_happened. This could cause any maskable asynchronous interrupt to get lost, but it was noticed on P9 SMP system doing RDMA NVMe target over 100GbE, so very high external interrupt rate and high IPI rate. The hang was bisected down to enabling doorbell interrupts for IPIs. These provided an interrupt type that could run at high rates in the do_IRQ path, stressing the race. Fixes: 1d607bb3bd60 ("powerpc/irq: Add mechanism to force a replay of interrupts") Cc: stable@vger.kernel.org # v4.8+ Reported-by: Carol L. Soto Signed-off-by: Nicholas Piggin Signed-off-by: Michael Ellerman Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/kernel/irq.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c index 4e65bf82f5e0..0ce8b0e5d7ba 100644 --- a/arch/powerpc/kernel/irq.c +++ b/arch/powerpc/kernel/irq.c @@ -430,6 +430,14 @@ void force_external_irq_replay(void) */ WARN_ON(!arch_irqs_disabled()); + /* + * Interrupts must always be hard disabled before irq_happened is + * modified (to prevent lost update in case of interrupt between + * load and store). + */ + __hard_irq_disable(); + local_paca->irq_happened |= PACA_IRQ_HARD_DIS; + /* Indicate in the PACA that we have an interrupt to replay */ local_paca->irq_happened |= PACA_IRQ_EE; } -- GitLab From 0726ba0491ca3e6e6bd88b332c0fcfda7aedd48f Mon Sep 17 00:00:00 2001 From: Nicholas Piggin Date: Fri, 23 Mar 2018 15:53:38 +1000 Subject: [PATCH 0040/1635] powerpc/64s: Fix i-side SLB miss bad address handler saving nonvolatile GPRs commit 52396500f97c53860164debc7d4f759077853423 upstream. The SLB bad address handler's trap number fixup does not preserve the low bit that indicates nonvolatile GPRs have not been saved. This leads save_nvgprs to skip saving them, and subsequent functions and return from interrupt will think they are saved. This causes kernel branch-to-garbage debugging to not have correct registers, can also cause userspace to have its registers clobbered after a segfault. Fixes: f0f558b131db ("powerpc/mm: Preserve CFAR value on SLB miss caused by access to bogus address") Cc: stable@vger.kernel.org # v4.9+ Signed-off-by: Nicholas Piggin Signed-off-by: Michael Ellerman Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/kernel/exceptions-64s.S | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/powerpc/kernel/exceptions-64s.S b/arch/powerpc/kernel/exceptions-64s.S index e91b40aa5417..f9ca4bb3d48e 100644 --- a/arch/powerpc/kernel/exceptions-64s.S +++ b/arch/powerpc/kernel/exceptions-64s.S @@ -704,7 +704,7 @@ EXC_COMMON_BEGIN(bad_addr_slb) ld r3, PACA_EXSLB+EX_DAR(r13) std r3, _DAR(r1) beq cr6, 2f - li r10, 0x480 /* fix trap number for I-SLB miss */ + li r10, 0x481 /* fix trap number for I-SLB miss */ std r10, _TRAP(r1) 2: bl save_nvgprs addi r3, r1, STACK_FRAME_OVERHEAD -- GitLab From ac2cb9f3de88f7c85f7880b92ee7db0fb7d641ac Mon Sep 17 00:00:00 2001 From: Richard Narron Date: Wed, 10 Jan 2018 09:12:16 -0700 Subject: [PATCH 0041/1635] partitions/msdos: Unable to mount UFS 44bsd partitions commit 5f15684bd5e5ef39d4337988864fec8012471dda upstream. UFS partitions from newer versions of FreeBSD 10 and 11 use relative addressing for their subpartitions. But older versions of FreeBSD still use absolute addressing just like OpenBSD and NetBSD. Instead of simply testing for a FreeBSD partition, the code needs to also test if the starting offset of the C subpartition is zero. https://bugzilla.kernel.org/show_bug.cgi?id=197733 Signed-off-by: Richard Narron Signed-off-by: Jens Axboe Signed-off-by: Greg Kroah-Hartman --- block/partitions/msdos.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/block/partitions/msdos.c b/block/partitions/msdos.c index 0af3a3db6fb0..82c44f7df911 100644 --- a/block/partitions/msdos.c +++ b/block/partitions/msdos.c @@ -301,7 +301,9 @@ static void parse_bsd(struct parsed_partitions *state, continue; bsd_start = le32_to_cpu(p->p_offset); bsd_size = le32_to_cpu(p->p_size); - if (memcmp(flavour, "bsd\0", 4) == 0) + /* FreeBSD has relative offset if C partition offset is zero */ + if (memcmp(flavour, "bsd\0", 4) == 0 && + le32_to_cpu(l->d_partitions[2].p_offset) == 0) bsd_start += offset; if (offset == bsd_start && size == bsd_size) /* full parent partition, we have it already */ -- GitLab From 25fd02ea40db52e6a50edca42b7e1e9aac12096e Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Mon, 12 Feb 2018 14:42:01 +0100 Subject: [PATCH 0042/1635] xfrm_user: uncoditionally validate esn replay attribute struct commit d97ca5d714a5334aecadadf696875da40f1fbf3e upstream. The sanity test added in ecd7918745234 can be bypassed, validation only occurs if XFRM_STATE_ESN flag is set, but rest of code doesn't care and just checks if the attribute itself is present. So always validate. Alternative is to reject if we have the attribute without the flag but that would change abi. Reported-by: syzbot+0ab777c27d2bb7588f73@syzkaller.appspotmail.com Cc: Mathias Krause Fixes: ecd7918745234 ("xfrm_user: ensure user supplied esn replay window is valid") Fixes: d8647b79c3b7e ("xfrm: Add user interface for esn and big anti-replay windows") Signed-off-by: Florian Westphal Signed-off-by: Steffen Klassert Signed-off-by: Greg Kroah-Hartman --- net/xfrm/xfrm_user.c | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index 0edf38d2afd9..dbfcfefd6d69 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c @@ -121,22 +121,17 @@ static inline int verify_replay(struct xfrm_usersa_info *p, struct nlattr *rt = attrs[XFRMA_REPLAY_ESN_VAL]; struct xfrm_replay_state_esn *rs; - if (p->flags & XFRM_STATE_ESN) { - if (!rt) - return -EINVAL; + if (!rt) + return (p->flags & XFRM_STATE_ESN) ? -EINVAL : 0; - rs = nla_data(rt); + rs = nla_data(rt); - if (rs->bmp_len > XFRMA_REPLAY_ESN_MAX / sizeof(rs->bmp[0]) / 8) - return -EINVAL; - - if (nla_len(rt) < xfrm_replay_state_esn_len(rs) && - nla_len(rt) != sizeof(*rs)) - return -EINVAL; - } + if (rs->bmp_len > XFRMA_REPLAY_ESN_MAX / sizeof(rs->bmp[0]) / 8) + return -EINVAL; - if (!rt) - return 0; + if (nla_len(rt) < xfrm_replay_state_esn_len(rs) && + nla_len(rt) != sizeof(*rs)) + return -EINVAL; /* As only ESP and AH support ESN feature. */ if ((p->id.proto != IPPROTO_ESP) && (p->id.proto != IPPROTO_AH)) -- GitLab From 123f9f8981d2e0271d285ddfa75389a2a4a79c64 Mon Sep 17 00:00:00 2001 From: Leon Romanovsky Date: Thu, 15 Mar 2018 15:33:02 +0200 Subject: [PATCH 0043/1635] RDMA/ucma: Check AF family prior resolving address commit 2975d5de6428ff6d9317e9948f0968f7d42e5d74 upstream. Garbage supplied by user will cause to UCMA module provide zero memory size for memcpy(), because it wasn't checked, it will produce unpredictable results in rdma_resolve_addr(). [ 42.873814] BUG: KASAN: null-ptr-deref in rdma_resolve_addr+0xc8/0xfb0 [ 42.874816] Write of size 28 at addr 00000000000000a0 by task resaddr/1044 [ 42.876765] [ 42.876960] CPU: 1 PID: 1044 Comm: resaddr Not tainted 4.16.0-rc1-00057-gaa56a5293d7e #34 [ 42.877840] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.11.0-0-g63451fca13-prebuilt.qemu-project.org 04/01/2014 [ 42.879691] Call Trace: [ 42.880236] dump_stack+0x5c/0x77 [ 42.880664] kasan_report+0x163/0x380 [ 42.881354] ? rdma_resolve_addr+0xc8/0xfb0 [ 42.881864] memcpy+0x34/0x50 [ 42.882692] rdma_resolve_addr+0xc8/0xfb0 [ 42.883366] ? deref_stack_reg+0x88/0xd0 [ 42.883856] ? vsnprintf+0x31a/0x770 [ 42.884686] ? rdma_bind_addr+0xc40/0xc40 [ 42.885327] ? num_to_str+0x130/0x130 [ 42.885773] ? deref_stack_reg+0x88/0xd0 [ 42.886217] ? __read_once_size_nocheck.constprop.6+0x10/0x10 [ 42.887698] ? unwind_get_return_address_ptr+0x50/0x50 [ 42.888302] ? replace_slot+0x147/0x170 [ 42.889176] ? delete_node+0x12c/0x340 [ 42.890223] ? __radix_tree_lookup+0xa9/0x160 [ 42.891196] ? ucma_resolve_ip+0xb7/0x110 [ 42.891917] ucma_resolve_ip+0xb7/0x110 [ 42.893003] ? ucma_resolve_addr+0x190/0x190 [ 42.893531] ? _copy_from_user+0x5e/0x90 [ 42.894204] ucma_write+0x174/0x1f0 [ 42.895162] ? ucma_resolve_route+0xf0/0xf0 [ 42.896309] ? dequeue_task_fair+0x67e/0xd90 [ 42.897192] ? put_prev_entity+0x7d/0x170 [ 42.897870] ? ring_buffer_record_is_on+0xd/0x20 [ 42.898439] ? tracing_record_taskinfo_skip+0x20/0x50 [ 42.899686] __vfs_write+0xc4/0x350 [ 42.900142] ? kernel_read+0xa0/0xa0 [ 42.900602] ? firmware_map_remove+0xdf/0xdf [ 42.901135] ? do_task_dead+0x5d/0x60 [ 42.901598] ? do_exit+0xcc6/0x1220 [ 42.902789] ? __fget+0xa8/0xf0 [ 42.903190] vfs_write+0xf7/0x280 [ 42.903600] SyS_write+0xa1/0x120 [ 42.904206] ? SyS_read+0x120/0x120 [ 42.905710] ? compat_start_thread+0x60/0x60 [ 42.906423] ? SyS_read+0x120/0x120 [ 42.908716] do_syscall_64+0xeb/0x250 [ 42.910760] entry_SYSCALL_64_after_hwframe+0x21/0x86 [ 42.912735] RIP: 0033:0x7f138b0afe99 [ 42.914734] RSP: 002b:00007f138b799e98 EFLAGS: 00000287 ORIG_RAX: 0000000000000001 [ 42.917134] RAX: ffffffffffffffda RBX: 0000000000000000 RCX: 00007f138b0afe99 [ 42.919487] RDX: 000000000000002e RSI: 0000000020000c40 RDI: 0000000000000004 [ 42.922393] RBP: 00007f138b799ec0 R08: 00007f138b79a700 R09: 0000000000000000 [ 42.925266] R10: 00007f138b79a700 R11: 0000000000000287 R12: 00007f138b799fc0 [ 42.927570] R13: 0000000000000000 R14: 00007ffdbae757c0 R15: 00007f138b79a9c0 [ 42.930047] [ 42.932681] Disabling lock debugging due to kernel taint [ 42.934795] BUG: unable to handle kernel NULL pointer dereference at 00000000000000a0 [ 42.936939] IP: memcpy_erms+0x6/0x10 [ 42.938864] PGD 80000001bea92067 P4D 80000001bea92067 PUD 1bea96067 PMD 0 [ 42.941576] Oops: 0002 [#1] SMP KASAN PTI [ 42.943952] CPU: 1 PID: 1044 Comm: resaddr Tainted: G B 4.16.0-rc1-00057-gaa56a5293d7e #34 [ 42.946964] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.11.0-0-g63451fca13-prebuilt.qemu-project.org 04/01/2014 [ 42.952336] RIP: 0010:memcpy_erms+0x6/0x10 [ 42.954707] RSP: 0018:ffff8801c8b479c8 EFLAGS: 00010286 [ 42.957227] RAX: 00000000000000a0 RBX: ffff8801c8b47ba0 RCX: 000000000000001c [ 42.960543] RDX: 000000000000001c RSI: ffff8801c8b47bbc RDI: 00000000000000a0 [ 42.963867] RBP: ffff8801c8b47b60 R08: 0000000000000000 R09: ffffed0039168ed1 [ 42.967303] R10: 0000000000000001 R11: ffffed0039168ed0 R12: ffff8801c8b47bbc [ 42.970685] R13: 00000000000000a0 R14: 1ffff10039168f4a R15: 0000000000000000 [ 42.973631] FS: 00007f138b79a700(0000) GS:ffff8801e5d00000(0000) knlGS:0000000000000000 [ 42.976831] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 42.979239] CR2: 00000000000000a0 CR3: 00000001be908002 CR4: 00000000003606a0 [ 42.982060] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 [ 42.984877] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 [ 42.988033] Call Trace: [ 42.990487] rdma_resolve_addr+0xc8/0xfb0 [ 42.993202] ? deref_stack_reg+0x88/0xd0 [ 42.996055] ? vsnprintf+0x31a/0x770 [ 42.998707] ? rdma_bind_addr+0xc40/0xc40 [ 43.000985] ? num_to_str+0x130/0x130 [ 43.003410] ? deref_stack_reg+0x88/0xd0 [ 43.006302] ? __read_once_size_nocheck.constprop.6+0x10/0x10 [ 43.008780] ? unwind_get_return_address_ptr+0x50/0x50 [ 43.011178] ? replace_slot+0x147/0x170 [ 43.013517] ? delete_node+0x12c/0x340 [ 43.016019] ? __radix_tree_lookup+0xa9/0x160 [ 43.018755] ? ucma_resolve_ip+0xb7/0x110 [ 43.021270] ucma_resolve_ip+0xb7/0x110 [ 43.023968] ? ucma_resolve_addr+0x190/0x190 [ 43.026312] ? _copy_from_user+0x5e/0x90 [ 43.029384] ucma_write+0x174/0x1f0 [ 43.031861] ? ucma_resolve_route+0xf0/0xf0 [ 43.034782] ? dequeue_task_fair+0x67e/0xd90 [ 43.037483] ? put_prev_entity+0x7d/0x170 [ 43.040215] ? ring_buffer_record_is_on+0xd/0x20 [ 43.042990] ? tracing_record_taskinfo_skip+0x20/0x50 [ 43.045595] __vfs_write+0xc4/0x350 [ 43.048624] ? kernel_read+0xa0/0xa0 [ 43.051604] ? firmware_map_remove+0xdf/0xdf [ 43.055379] ? do_task_dead+0x5d/0x60 [ 43.058000] ? do_exit+0xcc6/0x1220 [ 43.060783] ? __fget+0xa8/0xf0 [ 43.063133] vfs_write+0xf7/0x280 [ 43.065677] SyS_write+0xa1/0x120 [ 43.068647] ? SyS_read+0x120/0x120 [ 43.071179] ? compat_start_thread+0x60/0x60 [ 43.074025] ? SyS_read+0x120/0x120 [ 43.076705] do_syscall_64+0xeb/0x250 [ 43.079006] entry_SYSCALL_64_after_hwframe+0x21/0x86 [ 43.081606] RIP: 0033:0x7f138b0afe99 [ 43.083679] RSP: 002b:00007f138b799e98 EFLAGS: 00000287 ORIG_RAX: 0000000000000001 [ 43.086802] RAX: ffffffffffffffda RBX: 0000000000000000 RCX: 00007f138b0afe99 [ 43.089989] RDX: 000000000000002e RSI: 0000000020000c40 RDI: 0000000000000004 [ 43.092866] RBP: 00007f138b799ec0 R08: 00007f138b79a700 R09: 0000000000000000 [ 43.096233] R10: 00007f138b79a700 R11: 0000000000000287 R12: 00007f138b799fc0 [ 43.098913] R13: 0000000000000000 R14: 00007ffdbae757c0 R15: 00007f138b79a9c0 [ 43.101809] Code: 90 90 90 90 90 eb 1e 0f 1f 00 48 89 f8 48 89 d1 48 c1 e9 03 83 e2 07 f3 48 a5 89 d1 f3 a4 c3 66 0f 1f 44 00 00 48 89 f8 48 89 d1 a4 c3 0f 1f 80 00 00 00 00 48 89 f8 48 83 fa 20 72 7e 40 38 [ 43.107950] RIP: memcpy_erms+0x6/0x10 RSP: ffff8801c8b479c8 Reported-by: Fixes: 75216638572f ("RDMA/cma: Export rdma cm interface to userspace") Signed-off-by: Leon Romanovsky Reviewed-by: Sean Hefty Signed-off-by: Jason Gunthorpe Signed-off-by: Greg Kroah-Hartman --- drivers/infiniband/core/ucma.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/drivers/infiniband/core/ucma.c b/drivers/infiniband/core/ucma.c index 77ca9da570a2..1c0f3f780812 100644 --- a/drivers/infiniband/core/ucma.c +++ b/drivers/infiniband/core/ucma.c @@ -664,19 +664,23 @@ static ssize_t ucma_resolve_ip(struct ucma_file *file, int in_len, int out_len) { struct rdma_ucm_resolve_ip cmd; + struct sockaddr *src, *dst; struct ucma_context *ctx; int ret; if (copy_from_user(&cmd, inbuf, sizeof(cmd))) return -EFAULT; + src = (struct sockaddr *) &cmd.src_addr; + dst = (struct sockaddr *) &cmd.dst_addr; + if (!rdma_addr_size(src) || !rdma_addr_size(dst)) + return -EINVAL; + ctx = ucma_get_ctx(file, cmd.id); if (IS_ERR(ctx)) return PTR_ERR(ctx); - ret = rdma_resolve_addr(ctx->cm_id, (struct sockaddr *) &cmd.src_addr, - (struct sockaddr *) &cmd.dst_addr, - cmd.timeout_ms); + ret = rdma_resolve_addr(ctx->cm_id, src, dst, cmd.timeout_ms); ucma_put_ctx(ctx); return ret; } -- GitLab From ac895355571a158c7120c7b9b3ba6a94d2bc803e Mon Sep 17 00:00:00 2001 From: Leon Romanovsky Date: Mon, 19 Mar 2018 14:20:15 +0200 Subject: [PATCH 0044/1635] RDMA/ucma: Fix use-after-free access in ucma_close commit ed65a4dc22083e73bac599ded6a262318cad7baf upstream. The error in ucma_create_id() left ctx in the list of contexts belong to ucma file descriptor. The attempt to close this file descriptor causes to use-after-free accesses while iterating over such list. Fixes: 75216638572f ("RDMA/cma: Export rdma cm interface to userspace") Reported-by: Signed-off-by: Leon Romanovsky Reviewed-by: Sean Hefty Signed-off-by: Jason Gunthorpe Signed-off-by: Greg Kroah-Hartman --- drivers/infiniband/core/ucma.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/infiniband/core/ucma.c b/drivers/infiniband/core/ucma.c index 1c0f3f780812..058726348392 100644 --- a/drivers/infiniband/core/ucma.c +++ b/drivers/infiniband/core/ucma.c @@ -497,6 +497,9 @@ static ssize_t ucma_create_id(struct ucma_file *file, const char __user *inbuf, mutex_lock(&mut); idr_remove(&ctx_idr, ctx->id); mutex_unlock(&mut); + mutex_lock(&file->mut); + list_del(&ctx->list); + mutex_unlock(&file->mut); kfree(ctx); return ret; } -- GitLab From 4cd0242812a953407cb29971583801e76e060b58 Mon Sep 17 00:00:00 2001 From: Leon Romanovsky Date: Tue, 20 Mar 2018 17:05:13 +0200 Subject: [PATCH 0045/1635] RDMA/ucma: Ensure that CM_ID exists prior to access it commit e8980d67d6017c8eee8f9c35f782c4bd68e004c9 upstream. Prior to access UCMA commands, the context should be initialized and connected to CM_ID with ucma_create_id(). In case user skips this step, he can provide non-valid ctx without CM_ID and cause to multiple NULL dereferences. Also there are situations where the create_id can be raced with other user access, ensure that the context is only shared to other threads once it is fully initialized to avoid the races. [ 109.088108] BUG: unable to handle kernel NULL pointer dereference at 0000000000000020 [ 109.090315] IP: ucma_connect+0x138/0x1d0 [ 109.092595] PGD 80000001dc02d067 P4D 80000001dc02d067 PUD 1da9ef067 PMD 0 [ 109.095384] Oops: 0000 [#1] SMP KASAN PTI [ 109.097834] CPU: 0 PID: 663 Comm: uclose Tainted: G B 4.16.0-rc1-00062-g2975d5de6428 #45 [ 109.100816] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.11.0-0-g63451fca13-prebuilt.qemu-project.org 04/01/2014 [ 109.105943] RIP: 0010:ucma_connect+0x138/0x1d0 [ 109.108850] RSP: 0018:ffff8801c8567a80 EFLAGS: 00010246 [ 109.111484] RAX: 0000000000000000 RBX: 1ffff100390acf50 RCX: ffffffff9d7812e2 [ 109.114496] RDX: 1ffffffff3f507a5 RSI: 0000000000000297 RDI: 0000000000000297 [ 109.117490] RBP: ffff8801daa15600 R08: 0000000000000000 R09: ffffed00390aceeb [ 109.120429] R10: 0000000000000001 R11: ffffed00390aceea R12: 0000000000000000 [ 109.123318] R13: 0000000000000120 R14: ffff8801de6459c0 R15: 0000000000000118 [ 109.126221] FS: 00007fabb68d6700(0000) GS:ffff8801e5c00000(0000) knlGS:0000000000000000 [ 109.129468] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 109.132523] CR2: 0000000000000020 CR3: 00000001d45d8003 CR4: 00000000003606b0 [ 109.135573] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 [ 109.138716] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 [ 109.142057] Call Trace: [ 109.144160] ? ucma_listen+0x110/0x110 [ 109.146386] ? wake_up_q+0x59/0x90 [ 109.148853] ? futex_wake+0x10b/0x2a0 [ 109.151297] ? save_stack+0x89/0xb0 [ 109.153489] ? _copy_from_user+0x5e/0x90 [ 109.155500] ucma_write+0x174/0x1f0 [ 109.157933] ? ucma_resolve_route+0xf0/0xf0 [ 109.160389] ? __mod_node_page_state+0x1d/0x80 [ 109.162706] __vfs_write+0xc4/0x350 [ 109.164911] ? kernel_read+0xa0/0xa0 [ 109.167121] ? path_openat+0x1b10/0x1b10 [ 109.169355] ? fsnotify+0x899/0x8f0 [ 109.171567] ? fsnotify_unmount_inodes+0x170/0x170 [ 109.174145] ? __fget+0xa8/0xf0 [ 109.177110] vfs_write+0xf7/0x280 [ 109.179532] SyS_write+0xa1/0x120 [ 109.181885] ? SyS_read+0x120/0x120 [ 109.184482] ? compat_start_thread+0x60/0x60 [ 109.187124] ? SyS_read+0x120/0x120 [ 109.189548] do_syscall_64+0xeb/0x250 [ 109.192178] entry_SYSCALL_64_after_hwframe+0x21/0x86 [ 109.194725] RIP: 0033:0x7fabb61ebe99 [ 109.197040] RSP: 002b:00007fabb68d5e98 EFLAGS: 00000202 ORIG_RAX: 0000000000000001 [ 109.200294] RAX: ffffffffffffffda RBX: 0000000000000000 RCX: 00007fabb61ebe99 [ 109.203399] RDX: 0000000000000120 RSI: 00000000200001c0 RDI: 0000000000000004 [ 109.206548] RBP: 00007fabb68d5ec0 R08: 0000000000000000 R09: 0000000000000000 [ 109.209902] R10: 0000000000000000 R11: 0000000000000202 R12: 00007fabb68d5fc0 [ 109.213327] R13: 0000000000000000 R14: 00007fff40ab2430 R15: 00007fabb68d69c0 [ 109.216613] Code: 88 44 24 2c 0f b6 84 24 6e 01 00 00 88 44 24 2d 0f b6 84 24 69 01 00 00 88 44 24 2e 8b 44 24 60 89 44 24 30 e8 da f6 06 ff 31 c0 <66> 41 83 7c 24 20 1b 75 04 8b 44 24 64 48 8d 74 24 20 4c 89 e7 [ 109.223602] RIP: ucma_connect+0x138/0x1d0 RSP: ffff8801c8567a80 [ 109.226256] CR2: 0000000000000020 Fixes: 75216638572f ("RDMA/cma: Export rdma cm interface to userspace") Reported-by: Signed-off-by: Leon Romanovsky Signed-off-by: Jason Gunthorpe Signed-off-by: Greg Kroah-Hartman --- drivers/infiniband/core/ucma.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/drivers/infiniband/core/ucma.c b/drivers/infiniband/core/ucma.c index 058726348392..fcbd4ec082bc 100644 --- a/drivers/infiniband/core/ucma.c +++ b/drivers/infiniband/core/ucma.c @@ -132,7 +132,7 @@ static inline struct ucma_context *_ucma_find_context(int id, ctx = idr_find(&ctx_idr, id); if (!ctx) ctx = ERR_PTR(-ENOENT); - else if (ctx->file != file) + else if (ctx->file != file || !ctx->cm_id) ctx = ERR_PTR(-EINVAL); return ctx; } @@ -456,6 +456,7 @@ static ssize_t ucma_create_id(struct ucma_file *file, const char __user *inbuf, struct rdma_ucm_create_id cmd; struct rdma_ucm_create_id_resp resp; struct ucma_context *ctx; + struct rdma_cm_id *cm_id; enum ib_qp_type qp_type; int ret; @@ -476,10 +477,10 @@ static ssize_t ucma_create_id(struct ucma_file *file, const char __user *inbuf, return -ENOMEM; ctx->uid = cmd.uid; - ctx->cm_id = rdma_create_id(current->nsproxy->net_ns, - ucma_event_handler, ctx, cmd.ps, qp_type); - if (IS_ERR(ctx->cm_id)) { - ret = PTR_ERR(ctx->cm_id); + cm_id = rdma_create_id(current->nsproxy->net_ns, + ucma_event_handler, ctx, cmd.ps, qp_type); + if (IS_ERR(cm_id)) { + ret = PTR_ERR(cm_id); goto err1; } @@ -489,10 +490,12 @@ static ssize_t ucma_create_id(struct ucma_file *file, const char __user *inbuf, ret = -EFAULT; goto err2; } + + ctx->cm_id = cm_id; return 0; err2: - rdma_destroy_id(ctx->cm_id); + rdma_destroy_id(cm_id); err1: mutex_lock(&mut); idr_remove(&ctx_idr, ctx->id); -- GitLab From 6c2c0da62b5df2089fdaa3322abdd1c06ae8fd84 Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe Date: Thu, 22 Mar 2018 14:04:23 -0600 Subject: [PATCH 0046/1635] RDMA/rdma_cm: Fix use after free race with process_one_req commit 9137108cc3d64ade13e753108ec611a0daed16a0 upstream. process_one_req() can race with rdma_addr_cancel(): CPU0 CPU1 ==== ==== process_one_work() debug_work_deactivate(work); process_one_req() rdma_addr_cancel() mutex_lock(&lock); set_timeout(&req->work,..); __queue_work() debug_work_activate(work); mutex_unlock(&lock); mutex_lock(&lock); [..] list_del(&req->list); mutex_unlock(&lock); [..] // ODEBUG explodes since the work is still queued. kfree(req); Causing ODEBUG to detect the use after free: ODEBUG: free active (active state 0) object type: work_struct hint: process_one_req+0x0/0x6c0 include/net/dst.h:165 WARNING: CPU: 0 PID: 79 at lib/debugobjects.c:291 debug_print_object+0x166/0x220 lib/debugobjects.c:288 kvm: emulating exchange as write Kernel panic - not syncing: panic_on_warn set ... CPU: 0 PID: 79 Comm: kworker/u4:3 Not tainted 4.16.0-rc6+ #361 Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/01/2011 Workqueue: ib_addr process_one_req Call Trace: __dump_stack lib/dump_stack.c:17 [inline] dump_stack+0x194/0x24d lib/dump_stack.c:53 panic+0x1e4/0x41c kernel/panic.c:183 __warn+0x1dc/0x200 kernel/panic.c:547 report_bug+0x1f4/0x2b0 lib/bug.c:186 fixup_bug.part.11+0x37/0x80 arch/x86/kernel/traps.c:178 fixup_bug arch/x86/kernel/traps.c:247 [inline] do_error_trap+0x2d7/0x3e0 arch/x86/kernel/traps.c:296 do_invalid_op+0x1b/0x20 arch/x86/kernel/traps.c:315 invalid_op+0x1b/0x40 arch/x86/entry/entry_64.S:986 RIP: 0010:debug_print_object+0x166/0x220 lib/debugobjects.c:288 RSP: 0000:ffff8801d966f210 EFLAGS: 00010086 RAX: dffffc0000000008 RBX: 0000000000000003 RCX: ffffffff815acd6e RDX: 0000000000000000 RSI: 1ffff1003b2cddf2 RDI: 0000000000000000 RBP: ffff8801d966f250 R08: 0000000000000000 R09: 1ffff1003b2cddc8 R10: ffffed003b2cde71 R11: ffffffff86f39a98 R12: 0000000000000001 R13: ffffffff86f15540 R14: ffffffff86408700 R15: ffffffff8147c0a0 __debug_check_no_obj_freed lib/debugobjects.c:745 [inline] debug_check_no_obj_freed+0x662/0xf1f lib/debugobjects.c:774 kfree+0xc7/0x260 mm/slab.c:3799 process_one_req+0x2e7/0x6c0 drivers/infiniband/core/addr.c:592 process_one_work+0xc47/0x1bb0 kernel/workqueue.c:2113 worker_thread+0x223/0x1990 kernel/workqueue.c:2247 kthread+0x33c/0x400 kernel/kthread.c:238 ret_from_fork+0x3a/0x50 arch/x86/entry/entry_64.S:406 Fixes: 5fff41e1f89d ("IB/core: Fix race condition in resolving IP to MAC") Reported-by: Signed-off-by: Jason Gunthorpe Signed-off-by: Greg Kroah-Hartman --- drivers/infiniband/core/addr.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/infiniband/core/addr.c b/drivers/infiniband/core/addr.c index d2f74721b3ba..7d39bfccdd92 100644 --- a/drivers/infiniband/core/addr.c +++ b/drivers/infiniband/core/addr.c @@ -597,6 +597,15 @@ static void process_one_req(struct work_struct *_work) list_del(&req->list); mutex_unlock(&lock); + /* + * Although the work will normally have been canceled by the + * workqueue, it can still be requeued as long as it is on the + * req_list, so it could have been requeued before we grabbed &lock. + * We need to cancel it after it is removed from req_list to really be + * sure it is safe to free. + */ + cancel_delayed_work(&req->work); + req->callback(req->status, (struct sockaddr *)&req->src_addr, req->addr, req->context); put_client(req->client); -- GitLab From 4dba68fd1dfefc4dfbf3f6f5fcda99c13668c671 Mon Sep 17 00:00:00 2001 From: Leon Romanovsky Date: Sun, 25 Mar 2018 11:23:55 +0300 Subject: [PATCH 0047/1635] RDMA/ucma: Check that device is connected prior to access it commit 4b658d1bbc16605330694bb3ef2570c465ef383d upstream. Add missing check that device is connected prior to access it. [ 55.358652] BUG: KASAN: null-ptr-deref in rdma_init_qp_attr+0x4a/0x2c0 [ 55.359389] Read of size 8 at addr 00000000000000b0 by task qp/618 [ 55.360255] [ 55.360432] CPU: 1 PID: 618 Comm: qp Not tainted 4.16.0-rc1-00071-gcaf61b1b8b88 #91 [ 55.361693] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.11.0-0-g63451fca13-prebuilt.qemu-project.org 04/01/2014 [ 55.363264] Call Trace: [ 55.363833] dump_stack+0x5c/0x77 [ 55.364215] kasan_report+0x163/0x380 [ 55.364610] ? rdma_init_qp_attr+0x4a/0x2c0 [ 55.365238] rdma_init_qp_attr+0x4a/0x2c0 [ 55.366410] ucma_init_qp_attr+0x111/0x200 [ 55.366846] ? ucma_notify+0xf0/0xf0 [ 55.367405] ? _get_random_bytes+0xea/0x1b0 [ 55.367846] ? urandom_read+0x2f0/0x2f0 [ 55.368436] ? kmem_cache_alloc_trace+0xd2/0x1e0 [ 55.369104] ? refcount_inc_not_zero+0x9/0x60 [ 55.369583] ? refcount_inc+0x5/0x30 [ 55.370155] ? rdma_create_id+0x215/0x240 [ 55.370937] ? _copy_to_user+0x4f/0x60 [ 55.371620] ? mem_cgroup_commit_charge+0x1f5/0x290 [ 55.372127] ? _copy_from_user+0x5e/0x90 [ 55.372720] ucma_write+0x174/0x1f0 [ 55.373090] ? ucma_close_id+0x40/0x40 [ 55.373805] ? __lru_cache_add+0xa8/0xd0 [ 55.374403] __vfs_write+0xc4/0x350 [ 55.374774] ? kernel_read+0xa0/0xa0 [ 55.375173] ? fsnotify+0x899/0x8f0 [ 55.375544] ? fsnotify_unmount_inodes+0x170/0x170 [ 55.376689] ? __fsnotify_update_child_dentry_flags+0x30/0x30 [ 55.377522] ? handle_mm_fault+0x174/0x320 [ 55.378169] vfs_write+0xf7/0x280 [ 55.378864] SyS_write+0xa1/0x120 [ 55.379270] ? SyS_read+0x120/0x120 [ 55.379643] ? mm_fault_error+0x180/0x180 [ 55.380071] ? task_work_run+0x7d/0xd0 [ 55.380910] ? __task_pid_nr_ns+0x120/0x140 [ 55.381366] ? SyS_read+0x120/0x120 [ 55.381739] do_syscall_64+0xeb/0x250 [ 55.382143] entry_SYSCALL_64_after_hwframe+0x21/0x86 [ 55.382841] RIP: 0033:0x7fc2ef803e99 [ 55.383227] RSP: 002b:00007fffcc5f3be8 EFLAGS: 00000217 ORIG_RAX: 0000000000000001 [ 55.384173] RAX: ffffffffffffffda RBX: 0000000000000000 RCX: 00007fc2ef803e99 [ 55.386145] RDX: 0000000000000057 RSI: 0000000020000080 RDI: 0000000000000003 [ 55.388418] RBP: 00007fffcc5f3c00 R08: 0000000000000000 R09: 0000000000000000 [ 55.390542] R10: 0000000000000000 R11: 0000000000000217 R12: 0000000000400480 [ 55.392916] R13: 00007fffcc5f3cf0 R14: 0000000000000000 R15: 0000000000000000 [ 55.521088] Code: e5 4d 1e ff 48 89 df 44 0f b6 b3 b8 01 00 00 e8 65 50 1e ff 4c 8b 2b 49 8d bd b0 00 00 00 e8 56 50 1e ff 41 0f b6 c6 48 c1 e0 04 <49> 03 85 b0 00 00 00 48 8d 78 08 48 89 04 24 e8 3a 4f 1e ff 48 [ 55.525980] RIP: rdma_init_qp_attr+0x52/0x2c0 RSP: ffff8801e2c2f9d8 [ 55.532648] CR2: 00000000000000b0 [ 55.534396] ---[ end trace 70cee64090251c0b ]--- Fixes: 75216638572f ("RDMA/cma: Export rdma cm interface to userspace") Fixes: d541e45500bd ("IB/core: Convert ah_attr from OPA to IB when copying to user") Reported-by: Signed-off-by: Leon Romanovsky Signed-off-by: Jason Gunthorpe Signed-off-by: Greg Kroah-Hartman --- drivers/infiniband/core/ucma.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/infiniband/core/ucma.c b/drivers/infiniband/core/ucma.c index fcbd4ec082bc..87f5f35e0793 100644 --- a/drivers/infiniband/core/ucma.c +++ b/drivers/infiniband/core/ucma.c @@ -1165,6 +1165,11 @@ static ssize_t ucma_init_qp_attr(struct ucma_file *file, if (IS_ERR(ctx)) return PTR_ERR(ctx); + if (!ctx->cm_id->device) { + ret = -EINVAL; + goto out; + } + resp.qp_attr_mask = 0; memset(&qp_attr, 0, sizeof qp_attr); qp_attr.qp_state = cmd.qp_state; -- GitLab From 4fbf77d7a9fed2f53d0e77cd959987b977f13dec Mon Sep 17 00:00:00 2001 From: Leon Romanovsky Date: Sun, 25 Mar 2018 11:39:05 +0300 Subject: [PATCH 0048/1635] RDMA/ucma: Check that device exists prior to accessing it commit c8d3bcbfc5eab3f01cf373d039af725f3b488813 upstream. Ensure that device exists prior to accessing its properties. Reported-by: Fixes: 75216638572f ("RDMA/cma: Export rdma cm interface to userspace") Signed-off-by: Leon Romanovsky Signed-off-by: Jason Gunthorpe Signed-off-by: Greg Kroah-Hartman --- drivers/infiniband/core/ucma.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/infiniband/core/ucma.c b/drivers/infiniband/core/ucma.c index 87f5f35e0793..6cd51274ba21 100644 --- a/drivers/infiniband/core/ucma.c +++ b/drivers/infiniband/core/ucma.c @@ -1335,7 +1335,7 @@ static ssize_t ucma_notify(struct ucma_file *file, const char __user *inbuf, { struct rdma_ucm_notify cmd; struct ucma_context *ctx; - int ret; + int ret = -EINVAL; if (copy_from_user(&cmd, inbuf, sizeof(cmd))) return -EFAULT; @@ -1344,7 +1344,9 @@ static ssize_t ucma_notify(struct ucma_file *file, const char __user *inbuf, if (IS_ERR(ctx)) return PTR_ERR(ctx); - ret = rdma_notify(ctx->cm_id, (enum ib_event_type) cmd.event); + if (ctx->cm_id->device) + ret = rdma_notify(ctx->cm_id, (enum ib_event_type)cmd.event); + ucma_put_ctx(ctx); return ret; } -- GitLab From b0d95e686f454c3af6a908707c2e047796ea4280 Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Wed, 28 Mar 2018 11:27:22 -0700 Subject: [PATCH 0049/1635] RDMA/ucma: Introduce safer rdma_addr_size() variants commit 84652aefb347297aa08e91e283adf7b18f77c2d5 upstream. There are several places in the ucma ABI where userspace can pass in a sockaddr but set the address family to AF_IB. When that happens, rdma_addr_size() will return a size bigger than sizeof struct sockaddr_in6, and the ucma kernel code might end up copying past the end of a buffer not sized for a struct sockaddr_ib. Fix this by introducing new variants int rdma_addr_size_in6(struct sockaddr_in6 *addr); int rdma_addr_size_kss(struct __kernel_sockaddr_storage *addr); that are type-safe for the types used in the ucma ABI and return 0 if the size computed is bigger than the size of the type passed in. We can use these new variants to check what size userspace has passed in before copying any addresses. Reported-by: Signed-off-by: Roland Dreier Signed-off-by: Jason Gunthorpe Signed-off-by: Greg Kroah-Hartman --- drivers/infiniband/core/addr.c | 16 ++++++++++++++++ drivers/infiniband/core/ucma.c | 34 +++++++++++++++++----------------- include/rdma/ib_addr.h | 2 ++ 3 files changed, 35 insertions(+), 17 deletions(-) diff --git a/drivers/infiniband/core/addr.c b/drivers/infiniband/core/addr.c index 7d39bfccdd92..40475ebf3a61 100644 --- a/drivers/infiniband/core/addr.c +++ b/drivers/infiniband/core/addr.c @@ -207,6 +207,22 @@ int rdma_addr_size(struct sockaddr *addr) } EXPORT_SYMBOL(rdma_addr_size); +int rdma_addr_size_in6(struct sockaddr_in6 *addr) +{ + int ret = rdma_addr_size((struct sockaddr *) addr); + + return ret <= sizeof(*addr) ? ret : 0; +} +EXPORT_SYMBOL(rdma_addr_size_in6); + +int rdma_addr_size_kss(struct __kernel_sockaddr_storage *addr) +{ + int ret = rdma_addr_size((struct sockaddr *) addr); + + return ret <= sizeof(*addr) ? ret : 0; +} +EXPORT_SYMBOL(rdma_addr_size_kss); + static struct rdma_addr_client self; void rdma_addr_register_client(struct rdma_addr_client *client) diff --git a/drivers/infiniband/core/ucma.c b/drivers/infiniband/core/ucma.c index 6cd51274ba21..722235bed075 100644 --- a/drivers/infiniband/core/ucma.c +++ b/drivers/infiniband/core/ucma.c @@ -632,6 +632,9 @@ static ssize_t ucma_bind_ip(struct ucma_file *file, const char __user *inbuf, if (copy_from_user(&cmd, inbuf, sizeof(cmd))) return -EFAULT; + if (!rdma_addr_size_in6(&cmd.addr)) + return -EINVAL; + ctx = ucma_get_ctx(file, cmd.id); if (IS_ERR(ctx)) return PTR_ERR(ctx); @@ -645,22 +648,21 @@ static ssize_t ucma_bind(struct ucma_file *file, const char __user *inbuf, int in_len, int out_len) { struct rdma_ucm_bind cmd; - struct sockaddr *addr; struct ucma_context *ctx; int ret; if (copy_from_user(&cmd, inbuf, sizeof(cmd))) return -EFAULT; - addr = (struct sockaddr *) &cmd.addr; - if (cmd.reserved || !cmd.addr_size || (cmd.addr_size != rdma_addr_size(addr))) + if (cmd.reserved || !cmd.addr_size || + cmd.addr_size != rdma_addr_size_kss(&cmd.addr)) return -EINVAL; ctx = ucma_get_ctx(file, cmd.id); if (IS_ERR(ctx)) return PTR_ERR(ctx); - ret = rdma_bind_addr(ctx->cm_id, addr); + ret = rdma_bind_addr(ctx->cm_id, (struct sockaddr *) &cmd.addr); ucma_put_ctx(ctx); return ret; } @@ -670,23 +672,22 @@ static ssize_t ucma_resolve_ip(struct ucma_file *file, int in_len, int out_len) { struct rdma_ucm_resolve_ip cmd; - struct sockaddr *src, *dst; struct ucma_context *ctx; int ret; if (copy_from_user(&cmd, inbuf, sizeof(cmd))) return -EFAULT; - src = (struct sockaddr *) &cmd.src_addr; - dst = (struct sockaddr *) &cmd.dst_addr; - if (!rdma_addr_size(src) || !rdma_addr_size(dst)) + if (!rdma_addr_size_in6(&cmd.src_addr) || + !rdma_addr_size_in6(&cmd.dst_addr)) return -EINVAL; ctx = ucma_get_ctx(file, cmd.id); if (IS_ERR(ctx)) return PTR_ERR(ctx); - ret = rdma_resolve_addr(ctx->cm_id, src, dst, cmd.timeout_ms); + ret = rdma_resolve_addr(ctx->cm_id, (struct sockaddr *) &cmd.src_addr, + (struct sockaddr *) &cmd.dst_addr, cmd.timeout_ms); ucma_put_ctx(ctx); return ret; } @@ -696,24 +697,23 @@ static ssize_t ucma_resolve_addr(struct ucma_file *file, int in_len, int out_len) { struct rdma_ucm_resolve_addr cmd; - struct sockaddr *src, *dst; struct ucma_context *ctx; int ret; if (copy_from_user(&cmd, inbuf, sizeof(cmd))) return -EFAULT; - src = (struct sockaddr *) &cmd.src_addr; - dst = (struct sockaddr *) &cmd.dst_addr; - if (cmd.reserved || (cmd.src_size && (cmd.src_size != rdma_addr_size(src))) || - !cmd.dst_size || (cmd.dst_size != rdma_addr_size(dst))) + if (cmd.reserved || + (cmd.src_size && (cmd.src_size != rdma_addr_size_kss(&cmd.src_addr))) || + !cmd.dst_size || (cmd.dst_size != rdma_addr_size_kss(&cmd.dst_addr))) return -EINVAL; ctx = ucma_get_ctx(file, cmd.id); if (IS_ERR(ctx)) return PTR_ERR(ctx); - ret = rdma_resolve_addr(ctx->cm_id, src, dst, cmd.timeout_ms); + ret = rdma_resolve_addr(ctx->cm_id, (struct sockaddr *) &cmd.src_addr, + (struct sockaddr *) &cmd.dst_addr, cmd.timeout_ms); ucma_put_ctx(ctx); return ret; } @@ -1432,7 +1432,7 @@ static ssize_t ucma_join_ip_multicast(struct ucma_file *file, join_cmd.response = cmd.response; join_cmd.uid = cmd.uid; join_cmd.id = cmd.id; - join_cmd.addr_size = rdma_addr_size((struct sockaddr *) &cmd.addr); + join_cmd.addr_size = rdma_addr_size_in6(&cmd.addr); if (!join_cmd.addr_size) return -EINVAL; @@ -1451,7 +1451,7 @@ static ssize_t ucma_join_multicast(struct ucma_file *file, if (copy_from_user(&cmd, inbuf, sizeof(cmd))) return -EFAULT; - if (!rdma_addr_size((struct sockaddr *)&cmd.addr)) + if (!rdma_addr_size_kss(&cmd.addr)) return -EINVAL; return ucma_process_join(file, &cmd, out_len); diff --git a/include/rdma/ib_addr.h b/include/rdma/ib_addr.h index b2a10c762304..bec461bd6472 100644 --- a/include/rdma/ib_addr.h +++ b/include/rdma/ib_addr.h @@ -129,6 +129,8 @@ int rdma_copy_addr(struct rdma_dev_addr *dev_addr, struct net_device *dev, const unsigned char *dst_dev_addr); int rdma_addr_size(struct sockaddr *addr); +int rdma_addr_size_in6(struct sockaddr_in6 *addr); +int rdma_addr_size_kss(struct __kernel_sockaddr_storage *addr); int rdma_addr_find_smac_by_sgid(union ib_gid *sgid, u8 *smac, u16 *vlan_id); int rdma_addr_find_l2_eth_by_grh(const union ib_gid *sgid, -- GitLab From a6232ffa2a021d7e8ce6822fad3a51d4728de9fa Mon Sep 17 00:00:00 2001 From: Greg Hackmann Date: Wed, 7 Mar 2018 14:42:53 -0800 Subject: [PATCH 0050/1635] net: xfrm: use preempt-safe this_cpu_read() in ipcomp_alloc_tfms() commit 0dcd7876029b58770f769cbb7b484e88e4a305e5 upstream. f7c83bcbfaf5 ("net: xfrm: use __this_cpu_read per-cpu helper") added a __this_cpu_read() call inside ipcomp_alloc_tfms(). At the time, __this_cpu_read() required the caller to either not care about races or to handle preemption/interrupt issues. 3.15 tightened the rules around some per-cpu operations, and now __this_cpu_read() should never be used in a preemptible context. On 3.15 and later, we need to use this_cpu_read() instead. syzkaller reported this leading to the following kernel BUG while fuzzing sendmsg: BUG: using __this_cpu_read() in preemptible [00000000] code: repro/3101 caller is ipcomp_init_state+0x185/0x990 CPU: 3 PID: 3101 Comm: repro Not tainted 4.16.0-rc4-00123-g86f84779d8e9 #154 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.10.2-1 04/01/2014 Call Trace: dump_stack+0xb9/0x115 check_preemption_disabled+0x1cb/0x1f0 ipcomp_init_state+0x185/0x990 ? __xfrm_init_state+0x876/0xc20 ? lock_downgrade+0x5e0/0x5e0 ipcomp4_init_state+0xaa/0x7c0 __xfrm_init_state+0x3eb/0xc20 xfrm_init_state+0x19/0x60 pfkey_add+0x20df/0x36f0 ? pfkey_broadcast+0x3dd/0x600 ? pfkey_sock_destruct+0x340/0x340 ? pfkey_seq_stop+0x80/0x80 ? __skb_clone+0x236/0x750 ? kmem_cache_alloc+0x1f6/0x260 ? pfkey_sock_destruct+0x340/0x340 ? pfkey_process+0x62a/0x6f0 pfkey_process+0x62a/0x6f0 ? pfkey_send_new_mapping+0x11c0/0x11c0 ? mutex_lock_io_nested+0x1390/0x1390 pfkey_sendmsg+0x383/0x750 ? dump_sp+0x430/0x430 sock_sendmsg+0xc0/0x100 ___sys_sendmsg+0x6c8/0x8b0 ? copy_msghdr_from_user+0x3b0/0x3b0 ? pagevec_lru_move_fn+0x144/0x1f0 ? find_held_lock+0x32/0x1c0 ? do_huge_pmd_anonymous_page+0xc43/0x11e0 ? lock_downgrade+0x5e0/0x5e0 ? get_kernel_page+0xb0/0xb0 ? _raw_spin_unlock+0x29/0x40 ? do_huge_pmd_anonymous_page+0x400/0x11e0 ? __handle_mm_fault+0x553/0x2460 ? __fget_light+0x163/0x1f0 ? __sys_sendmsg+0xc7/0x170 __sys_sendmsg+0xc7/0x170 ? SyS_shutdown+0x1a0/0x1a0 ? __do_page_fault+0x5a0/0xca0 ? lock_downgrade+0x5e0/0x5e0 SyS_sendmsg+0x27/0x40 ? __sys_sendmsg+0x170/0x170 do_syscall_64+0x19f/0x640 entry_SYSCALL_64_after_hwframe+0x42/0xb7 RIP: 0033:0x7f0ee73dfb79 RSP: 002b:00007ffe14fc15a8 EFLAGS: 00000207 ORIG_RAX: 000000000000002e RAX: ffffffffffffffda RBX: 0000000000000000 RCX: 00007f0ee73dfb79 RDX: 0000000000000000 RSI: 00000000208befc8 RDI: 0000000000000004 RBP: 00007ffe14fc15b0 R08: 00007ffe14fc15c0 R09: 00007ffe14fc15c0 R10: 0000000000000000 R11: 0000000000000207 R12: 0000000000400440 R13: 00007ffe14fc16b0 R14: 0000000000000000 R15: 0000000000000000 Signed-off-by: Greg Hackmann Signed-off-by: Steffen Klassert Signed-off-by: Greg Kroah-Hartman --- net/xfrm/xfrm_ipcomp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/xfrm/xfrm_ipcomp.c b/net/xfrm/xfrm_ipcomp.c index ccfdc7115a83..a00ec715aa46 100644 --- a/net/xfrm/xfrm_ipcomp.c +++ b/net/xfrm/xfrm_ipcomp.c @@ -283,7 +283,7 @@ static struct crypto_comp * __percpu *ipcomp_alloc_tfms(const char *alg_name) struct crypto_comp *tfm; /* This can be any valid CPU ID so we don't need locking. */ - tfm = __this_cpu_read(*pos->tfms); + tfm = this_cpu_read(*pos->tfms); if (!strcmp(crypto_comp_name(tfm), alg_name)) { pos->users++; -- GitLab From dffe655ddb48ee1b2165ca9250a54376199e3764 Mon Sep 17 00:00:00 2001 From: Steffen Klassert Date: Thu, 1 Feb 2018 08:49:23 +0100 Subject: [PATCH 0051/1635] xfrm: Refuse to insert 32 bit userspace socket policies on 64 bit systems commit 19d7df69fdb2636856dc8919de72fc1bf8f79598 upstream. We don't have a compat layer for xfrm, so userspace and kernel structures have different sizes in this case. This results in a broken configuration, so refuse to configure socket policies when trying to insert from 32 bit userspace as we do it already with policies inserted via netlink. Reported-and-tested-by: syzbot+e1a1577ca8bcb47b769a@syzkaller.appspotmail.com Signed-off-by: Steffen Klassert Signed-off-by: Greg Kroah-Hartman --- net/xfrm/xfrm_state.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c index bab20c626943..8f13fb57eab5 100644 --- a/net/xfrm/xfrm_state.c +++ b/net/xfrm/xfrm_state.c @@ -2050,6 +2050,11 @@ int xfrm_user_policy(struct sock *sk, int optname, u8 __user *optval, int optlen struct xfrm_mgr *km; struct xfrm_policy *pol = NULL; +#ifdef CONFIG_COMPAT + if (in_compat_syscall()) + return -EOPNOTSUPP; +#endif + if (!optval && !optlen) { xfrm_sk_policy_insert(sk, XFRM_POLICY_IN, NULL); xfrm_sk_policy_insert(sk, XFRM_POLICY_OUT, NULL); -- GitLab From 72682b162dae7804b3c0b97ec5bc1ebb600a7fc2 Mon Sep 17 00:00:00 2001 From: Dennis Zhou Date: Fri, 16 Feb 2018 12:07:19 -0600 Subject: [PATCH 0052/1635] percpu: add __GFP_NORETRY semantics to the percpu balancing path commit 47504ee04b9241548ae2c28be7d0b01cff3b7aa6 upstream. Percpu memory using the vmalloc area based chunk allocator lazily populates chunks by first requesting the full virtual address space required for the chunk and subsequently adding pages as allocations come through. To ensure atomic allocations can succeed, a workqueue item is used to maintain a minimum number of empty pages. In certain scenarios, such as reported in [1], it is possible that physical memory becomes quite scarce which can result in either a rather long time spent trying to find free pages or worse, a kernel panic. This patch adds support for __GFP_NORETRY and __GFP_NOWARN passing them through to the underlying allocators. This should prevent any unnecessary panics potentially caused by the workqueue item. The passing of gfp around is as additional flags rather than a full set of flags. The next patch will change these to caller passed semantics. V2: Added const modifier to gfp flags in the balance path. Removed an extra whitespace. [1] https://lkml.org/lkml/2018/2/12/551 Signed-off-by: Dennis Zhou Suggested-by: Daniel Borkmann Reported-by: syzbot+adb03f3f0bb57ce3acda@syzkaller.appspotmail.com Acked-by: Christoph Lameter Signed-off-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman --- mm/percpu-km.c | 8 ++++---- mm/percpu-vm.c | 18 +++++++++++------- mm/percpu.c | 45 ++++++++++++++++++++++++++++----------------- 3 files changed, 43 insertions(+), 28 deletions(-) diff --git a/mm/percpu-km.c b/mm/percpu-km.c index d2a76642c4ae..0d88d7bd5706 100644 --- a/mm/percpu-km.c +++ b/mm/percpu-km.c @@ -34,7 +34,7 @@ #include static int pcpu_populate_chunk(struct pcpu_chunk *chunk, - int page_start, int page_end) + int page_start, int page_end, gfp_t gfp) { return 0; } @@ -45,18 +45,18 @@ static void pcpu_depopulate_chunk(struct pcpu_chunk *chunk, /* nada */ } -static struct pcpu_chunk *pcpu_create_chunk(void) +static struct pcpu_chunk *pcpu_create_chunk(gfp_t gfp) { const int nr_pages = pcpu_group_sizes[0] >> PAGE_SHIFT; struct pcpu_chunk *chunk; struct page *pages; int i; - chunk = pcpu_alloc_chunk(); + chunk = pcpu_alloc_chunk(gfp); if (!chunk) return NULL; - pages = alloc_pages(GFP_KERNEL, order_base_2(nr_pages)); + pages = alloc_pages(gfp | GFP_KERNEL, order_base_2(nr_pages)); if (!pages) { pcpu_free_chunk(chunk); return NULL; diff --git a/mm/percpu-vm.c b/mm/percpu-vm.c index 15dab691ea70..f48ff9fc86fe 100644 --- a/mm/percpu-vm.c +++ b/mm/percpu-vm.c @@ -37,7 +37,7 @@ static struct page **pcpu_get_pages(void) lockdep_assert_held(&pcpu_alloc_mutex); if (!pages) - pages = pcpu_mem_zalloc(pages_size); + pages = pcpu_mem_zalloc(pages_size, 0); return pages; } @@ -73,18 +73,21 @@ static void pcpu_free_pages(struct pcpu_chunk *chunk, * @pages: array to put the allocated pages into, indexed by pcpu_page_idx() * @page_start: page index of the first page to be allocated * @page_end: page index of the last page to be allocated + 1 + * @gfp: allocation flags passed to the underlying allocator * * Allocate pages [@page_start,@page_end) into @pages for all units. * The allocation is for @chunk. Percpu core doesn't care about the * content of @pages and will pass it verbatim to pcpu_map_pages(). */ static int pcpu_alloc_pages(struct pcpu_chunk *chunk, - struct page **pages, int page_start, int page_end) + struct page **pages, int page_start, int page_end, + gfp_t gfp) { - const gfp_t gfp = GFP_KERNEL | __GFP_HIGHMEM | __GFP_COLD; unsigned int cpu, tcpu; int i; + gfp |= GFP_KERNEL | __GFP_HIGHMEM | __GFP_COLD; + for_each_possible_cpu(cpu) { for (i = page_start; i < page_end; i++) { struct page **pagep = &pages[pcpu_page_idx(cpu, i)]; @@ -262,6 +265,7 @@ static void pcpu_post_map_flush(struct pcpu_chunk *chunk, * @chunk: chunk of interest * @page_start: the start page * @page_end: the end page + * @gfp: allocation flags passed to the underlying memory allocator * * For each cpu, populate and map pages [@page_start,@page_end) into * @chunk. @@ -270,7 +274,7 @@ static void pcpu_post_map_flush(struct pcpu_chunk *chunk, * pcpu_alloc_mutex, does GFP_KERNEL allocation. */ static int pcpu_populate_chunk(struct pcpu_chunk *chunk, - int page_start, int page_end) + int page_start, int page_end, gfp_t gfp) { struct page **pages; @@ -278,7 +282,7 @@ static int pcpu_populate_chunk(struct pcpu_chunk *chunk, if (!pages) return -ENOMEM; - if (pcpu_alloc_pages(chunk, pages, page_start, page_end)) + if (pcpu_alloc_pages(chunk, pages, page_start, page_end, gfp)) return -ENOMEM; if (pcpu_map_pages(chunk, pages, page_start, page_end)) { @@ -325,12 +329,12 @@ static void pcpu_depopulate_chunk(struct pcpu_chunk *chunk, pcpu_free_pages(chunk, pages, page_start, page_end); } -static struct pcpu_chunk *pcpu_create_chunk(void) +static struct pcpu_chunk *pcpu_create_chunk(gfp_t gfp) { struct pcpu_chunk *chunk; struct vm_struct **vms; - chunk = pcpu_alloc_chunk(); + chunk = pcpu_alloc_chunk(gfp); if (!chunk) return NULL; diff --git a/mm/percpu.c b/mm/percpu.c index a0e0c82c1e4c..c80e796bf35c 100644 --- a/mm/percpu.c +++ b/mm/percpu.c @@ -447,10 +447,12 @@ static void pcpu_next_fit_region(struct pcpu_chunk *chunk, int alloc_bits, /** * pcpu_mem_zalloc - allocate memory * @size: bytes to allocate + * @gfp: allocation flags * * Allocate @size bytes. If @size is smaller than PAGE_SIZE, - * kzalloc() is used; otherwise, vzalloc() is used. The returned - * memory is always zeroed. + * kzalloc() is used; otherwise, the equivalent of vzalloc() is used. + * This is to facilitate passing through whitelisted flags. The + * returned memory is always zeroed. * * CONTEXT: * Does GFP_KERNEL allocation. @@ -458,15 +460,16 @@ static void pcpu_next_fit_region(struct pcpu_chunk *chunk, int alloc_bits, * RETURNS: * Pointer to the allocated area on success, NULL on failure. */ -static void *pcpu_mem_zalloc(size_t size) +static void *pcpu_mem_zalloc(size_t size, gfp_t gfp) { if (WARN_ON_ONCE(!slab_is_available())) return NULL; if (size <= PAGE_SIZE) - return kzalloc(size, GFP_KERNEL); + return kzalloc(size, gfp | GFP_KERNEL); else - return vzalloc(size); + return __vmalloc(size, gfp | GFP_KERNEL | __GFP_ZERO, + PAGE_KERNEL); } /** @@ -1154,12 +1157,12 @@ static struct pcpu_chunk * __init pcpu_alloc_first_chunk(unsigned long tmp_addr, return chunk; } -static struct pcpu_chunk *pcpu_alloc_chunk(void) +static struct pcpu_chunk *pcpu_alloc_chunk(gfp_t gfp) { struct pcpu_chunk *chunk; int region_bits; - chunk = pcpu_mem_zalloc(pcpu_chunk_struct_size); + chunk = pcpu_mem_zalloc(pcpu_chunk_struct_size, gfp); if (!chunk) return NULL; @@ -1168,17 +1171,17 @@ static struct pcpu_chunk *pcpu_alloc_chunk(void) region_bits = pcpu_chunk_map_bits(chunk); chunk->alloc_map = pcpu_mem_zalloc(BITS_TO_LONGS(region_bits) * - sizeof(chunk->alloc_map[0])); + sizeof(chunk->alloc_map[0]), gfp); if (!chunk->alloc_map) goto alloc_map_fail; chunk->bound_map = pcpu_mem_zalloc(BITS_TO_LONGS(region_bits + 1) * - sizeof(chunk->bound_map[0])); + sizeof(chunk->bound_map[0]), gfp); if (!chunk->bound_map) goto bound_map_fail; chunk->md_blocks = pcpu_mem_zalloc(pcpu_chunk_nr_blocks(chunk) * - sizeof(chunk->md_blocks[0])); + sizeof(chunk->md_blocks[0]), gfp); if (!chunk->md_blocks) goto md_blocks_fail; @@ -1277,9 +1280,10 @@ static void pcpu_chunk_depopulated(struct pcpu_chunk *chunk, * pcpu_addr_to_page - translate address to physical address * pcpu_verify_alloc_info - check alloc_info is acceptable during init */ -static int pcpu_populate_chunk(struct pcpu_chunk *chunk, int off, int size); +static int pcpu_populate_chunk(struct pcpu_chunk *chunk, int off, int size, + gfp_t gfp); static void pcpu_depopulate_chunk(struct pcpu_chunk *chunk, int off, int size); -static struct pcpu_chunk *pcpu_create_chunk(void); +static struct pcpu_chunk *pcpu_create_chunk(gfp_t gfp); static void pcpu_destroy_chunk(struct pcpu_chunk *chunk); static struct page *pcpu_addr_to_page(void *addr); static int __init pcpu_verify_alloc_info(const struct pcpu_alloc_info *ai); @@ -1421,7 +1425,7 @@ static void __percpu *pcpu_alloc(size_t size, size_t align, bool reserved, } if (list_empty(&pcpu_slot[pcpu_nr_slots - 1])) { - chunk = pcpu_create_chunk(); + chunk = pcpu_create_chunk(0); if (!chunk) { err = "failed to allocate new chunk"; goto fail; @@ -1450,7 +1454,7 @@ static void __percpu *pcpu_alloc(size_t size, size_t align, bool reserved, page_start, page_end) { WARN_ON(chunk->immutable); - ret = pcpu_populate_chunk(chunk, rs, re); + ret = pcpu_populate_chunk(chunk, rs, re, 0); spin_lock_irqsave(&pcpu_lock, flags); if (ret) { @@ -1561,10 +1565,17 @@ void __percpu *__alloc_reserved_percpu(size_t size, size_t align) * pcpu_balance_workfn - manage the amount of free chunks and populated pages * @work: unused * - * Reclaim all fully free chunks except for the first one. + * Reclaim all fully free chunks except for the first one. This is also + * responsible for maintaining the pool of empty populated pages. However, + * it is possible that this is called when physical memory is scarce causing + * OOM killer to be triggered. We should avoid doing so until an actual + * allocation causes the failure as it is possible that requests can be + * serviced from already backed regions. */ static void pcpu_balance_workfn(struct work_struct *work) { + /* gfp flags passed to underlying allocators */ + const gfp_t gfp = __GFP_NORETRY | __GFP_NOWARN; LIST_HEAD(to_free); struct list_head *free_head = &pcpu_slot[pcpu_nr_slots - 1]; struct pcpu_chunk *chunk, *next; @@ -1645,7 +1656,7 @@ static void pcpu_balance_workfn(struct work_struct *work) chunk->nr_pages) { int nr = min(re - rs, nr_to_pop); - ret = pcpu_populate_chunk(chunk, rs, rs + nr); + ret = pcpu_populate_chunk(chunk, rs, rs + nr, gfp); if (!ret) { nr_to_pop -= nr; spin_lock_irq(&pcpu_lock); @@ -1662,7 +1673,7 @@ static void pcpu_balance_workfn(struct work_struct *work) if (nr_to_pop) { /* ran out of chunks to populate, create a new one and retry */ - chunk = pcpu_create_chunk(); + chunk = pcpu_create_chunk(gfp); if (chunk) { spin_lock_irq(&pcpu_lock); pcpu_chunk_relocate(chunk, -1); -- GitLab From 546ade704a98bfdcb7c6df76af14100a4ca53263 Mon Sep 17 00:00:00 2001 From: Michal Hocko Date: Tue, 30 Jan 2018 11:30:11 -0800 Subject: [PATCH 0053/1635] netfilter: x_tables: make allocation less aggressive commit 0537250fdc6c876ed4cbbe874c739aebef493ee2 upstream. syzbot has noticed that xt_alloc_table_info can allocate a lot of memory. This is an admin only interface but an admin in a namespace is sufficient as well. eacd86ca3b03 ("net/netfilter/x_tables.c: use kvmalloc() in xt_alloc_table_info()") has changed the opencoded kmalloc->vmalloc fallback into kvmalloc. It has dropped __GFP_NORETRY on the way because vmalloc has simply never fully supported __GFP_NORETRY semantic. This is still the case because e.g. page tables backing the vmalloc area are hardcoded GFP_KERNEL. Revert back to __GFP_NORETRY as a poors man defence against excessively large allocation request here. We will not rule out the OOM killer completely but __GFP_NORETRY should at least stop the large request in most cases. [akpm@linux-foundation.org: coding-style fixes] Fixes: eacd86ca3b03 ("net/netfilter/x_tables.c: use kvmalloc() in xt_alloc_tableLink: http://lkml.kernel.org/r/20180130140104.GE21609@dhcp22.suse.cz Signed-off-by: Michal Hocko Acked-by: Florian Westphal Reviewed-by: Andrew Morton Cc: David S. Miller Signed-off-by: Andrew Morton Signed-off-by: Pablo Neira Ayuso Signed-off-by: Greg Kroah-Hartman --- net/netfilter/x_tables.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c index 60c92158a2cd..8a4947ff2ebf 100644 --- a/net/netfilter/x_tables.c +++ b/net/netfilter/x_tables.c @@ -1008,7 +1008,12 @@ struct xt_table_info *xt_alloc_table_info(unsigned int size) if ((size >> PAGE_SHIFT) + 2 > totalram_pages) return NULL; - info = kvmalloc(sz, GFP_KERNEL); + /* __GFP_NORETRY is not fully supported by kvmalloc but it should + * work reasonably well if sz is too large and bail out rather + * than shoot all processes down before realizing there is nothing + * more to reclaim. + */ + info = kvmalloc(sz, GFP_KERNEL | __GFP_NORETRY); if (!info) return NULL; -- GitLab From bbfbc396f07680d5ca76a3a6e5e378e92f7d5ff7 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Fri, 9 Mar 2018 14:27:31 +0100 Subject: [PATCH 0054/1635] netfilter: bridge: ebt_among: add more missing match size checks commit c8d70a700a5b486bfa8e5a7d33d805389f6e59f9 upstream. ebt_among is special, it has a dynamic match size and is exempt from the central size checks. commit c4585a2823edf ("bridge: ebt_among: add missing match size checks") added validation for pool size, but missed fact that the macros ebt_among_wh_src/dst can already return out-of-bound result because they do not check value of wh_src/dst_ofs (an offset) vs. the size of the match that userspace gave to us. v2: check that offset has correct alignment. Paolo Abeni points out that we should also check that src/dst wormhash arrays do not overlap, and src + length lines up with start of dst (or vice versa). v3: compact wormhash_sizes_valid() part NB: Fixes tag is intentionally wrong, this bug exists from day one when match was added for 2.6 kernel. Tag is there so stable maintainers will notice this one too. Tested with same rules from the earlier patch. Fixes: c4585a2823edf ("bridge: ebt_among: add missing match size checks") Reported-by: Signed-off-by: Florian Westphal Reviewed-by: Eric Dumazet Signed-off-by: Pablo Neira Ayuso Signed-off-by: Greg Kroah-Hartman --- net/bridge/netfilter/ebt_among.c | 34 ++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/net/bridge/netfilter/ebt_among.c b/net/bridge/netfilter/ebt_among.c index 59baaecd3e54..0b589a6b365c 100644 --- a/net/bridge/netfilter/ebt_among.c +++ b/net/bridge/netfilter/ebt_among.c @@ -177,6 +177,28 @@ static bool poolsize_invalid(const struct ebt_mac_wormhash *w) return w && w->poolsize >= (INT_MAX / sizeof(struct ebt_mac_wormhash_tuple)); } +static bool wormhash_offset_invalid(int off, unsigned int len) +{ + if (off == 0) /* not present */ + return false; + + if (off < (int)sizeof(struct ebt_among_info) || + off % __alignof__(struct ebt_mac_wormhash)) + return true; + + off += sizeof(struct ebt_mac_wormhash); + + return off > len; +} + +static bool wormhash_sizes_valid(const struct ebt_mac_wormhash *wh, int a, int b) +{ + if (a == 0) + a = sizeof(struct ebt_among_info); + + return ebt_mac_wormhash_size(wh) + a == b; +} + static int ebt_among_mt_check(const struct xt_mtchk_param *par) { const struct ebt_among_info *info = par->matchinfo; @@ -189,6 +211,10 @@ static int ebt_among_mt_check(const struct xt_mtchk_param *par) if (expected_length > em->match_size) return -EINVAL; + if (wormhash_offset_invalid(info->wh_dst_ofs, em->match_size) || + wormhash_offset_invalid(info->wh_src_ofs, em->match_size)) + return -EINVAL; + wh_dst = ebt_among_wh_dst(info); if (poolsize_invalid(wh_dst)) return -EINVAL; @@ -201,6 +227,14 @@ static int ebt_among_mt_check(const struct xt_mtchk_param *par) if (poolsize_invalid(wh_src)) return -EINVAL; + if (info->wh_src_ofs < info->wh_dst_ofs) { + if (!wormhash_sizes_valid(wh_src, info->wh_src_ofs, info->wh_dst_ofs)) + return -EINVAL; + } else { + if (!wormhash_sizes_valid(wh_dst, info->wh_dst_ofs, info->wh_src_ofs)) + return -EINVAL; + } + expected_length += ebt_mac_wormhash_size(wh_src); if (em->match_size != EBT_ALIGN(expected_length)) { -- GitLab From b0850604cc5dac60754cc2fcdf7d2ca97a68a4dc Mon Sep 17 00:00:00 2001 From: Paolo Abeni Date: Mon, 12 Mar 2018 14:54:24 +0100 Subject: [PATCH 0055/1635] l2tp: fix races with ipv4-mapped ipv6 addresses commit b954f94023dcc61388c8384f0f14eb8e42c863c5 upstream. The l2tp_tunnel_create() function checks for v4mapped ipv6 sockets and cache that flag, so that l2tp core code can reusing it at xmit time. If the socket is provided by the userspace, the connection status of the tunnel sockets can change between the tunnel creation and the xmit call, so that syzbot is able to trigger the following splat: BUG: KASAN: use-after-free in ip6_dst_idev include/net/ip6_fib.h:192 [inline] BUG: KASAN: use-after-free in ip6_xmit+0x1f76/0x2260 net/ipv6/ip6_output.c:264 Read of size 8 at addr ffff8801bd949318 by task syz-executor4/23448 CPU: 0 PID: 23448 Comm: syz-executor4 Not tainted 4.16.0-rc4+ #65 Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/01/2011 Call Trace: __dump_stack lib/dump_stack.c:17 [inline] dump_stack+0x194/0x24d lib/dump_stack.c:53 print_address_description+0x73/0x250 mm/kasan/report.c:256 kasan_report_error mm/kasan/report.c:354 [inline] kasan_report+0x23c/0x360 mm/kasan/report.c:412 __asan_report_load8_noabort+0x14/0x20 mm/kasan/report.c:433 ip6_dst_idev include/net/ip6_fib.h:192 [inline] ip6_xmit+0x1f76/0x2260 net/ipv6/ip6_output.c:264 inet6_csk_xmit+0x2fc/0x580 net/ipv6/inet6_connection_sock.c:139 l2tp_xmit_core net/l2tp/l2tp_core.c:1053 [inline] l2tp_xmit_skb+0x105f/0x1410 net/l2tp/l2tp_core.c:1148 pppol2tp_sendmsg+0x470/0x670 net/l2tp/l2tp_ppp.c:341 sock_sendmsg_nosec net/socket.c:630 [inline] sock_sendmsg+0xca/0x110 net/socket.c:640 ___sys_sendmsg+0x767/0x8b0 net/socket.c:2046 __sys_sendmsg+0xe5/0x210 net/socket.c:2080 SYSC_sendmsg net/socket.c:2091 [inline] SyS_sendmsg+0x2d/0x50 net/socket.c:2087 do_syscall_64+0x281/0x940 arch/x86/entry/common.c:287 entry_SYSCALL_64_after_hwframe+0x42/0xb7 RIP: 0033:0x453e69 RSP: 002b:00007f819593cc68 EFLAGS: 00000246 ORIG_RAX: 000000000000002e RAX: ffffffffffffffda RBX: 00007f819593d6d4 RCX: 0000000000453e69 RDX: 0000000000000081 RSI: 000000002037ffc8 RDI: 0000000000000004 RBP: 000000000072bea0 R08: 0000000000000000 R09: 0000000000000000 R10: 0000000000000000 R11: 0000000000000246 R12: 00000000ffffffff R13: 00000000000004c3 R14: 00000000006f72e8 R15: 0000000000000000 This change addresses the issues: * explicitly checking for TCP_ESTABLISHED for user space provided sockets * dropping the v4mapped flag usage - it can become outdated - and explicitly invoking ipv6_addr_v4mapped() instead The issue is apparently there since ancient times. v1 -> v2: (many thanks to Guillaume) - with csum issue introduced in v1 - replace pr_err with pr_debug - fix build issue with IPV6 disabled - move l2tp_sk_is_v4mapped in l2tp_core.c v2 -> v3: - don't update inet_daddr for v4mapped address, unneeded - drop rendundant check at creation time Reported-and-tested-by: syzbot+92fa328176eb07e4ac1a@syzkaller.appspotmail.com Fixes: 3557baabf280 ("[L2TP]: PPP over L2TP driver core") Signed-off-by: Paolo Abeni Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/l2tp/l2tp_core.c | 38 ++++++++++++++++++-------------------- net/l2tp/l2tp_core.h | 3 --- 2 files changed, 18 insertions(+), 23 deletions(-) diff --git a/net/l2tp/l2tp_core.c b/net/l2tp/l2tp_core.c index 490d7360222e..316869df91e8 100644 --- a/net/l2tp/l2tp_core.c +++ b/net/l2tp/l2tp_core.c @@ -113,6 +113,13 @@ struct l2tp_net { spinlock_t l2tp_session_hlist_lock; }; +#if IS_ENABLED(CONFIG_IPV6) +static bool l2tp_sk_is_v6(struct sock *sk) +{ + return sk->sk_family == PF_INET6 && + !ipv6_addr_v4mapped(&sk->sk_v6_daddr); +} +#endif static inline struct l2tp_tunnel *l2tp_tunnel(struct sock *sk) { @@ -1130,7 +1137,7 @@ static int l2tp_xmit_core(struct l2tp_session *session, struct sk_buff *skb, /* Queue the packet to IP for output */ skb->ignore_df = 1; #if IS_ENABLED(CONFIG_IPV6) - if (tunnel->sock->sk_family == PF_INET6 && !tunnel->v4mapped) + if (l2tp_sk_is_v6(tunnel->sock)) error = inet6_csk_xmit(tunnel->sock, skb, NULL); else #endif @@ -1193,6 +1200,15 @@ int l2tp_xmit_skb(struct l2tp_session *session, struct sk_buff *skb, int hdr_len goto out_unlock; } + /* The user-space may change the connection status for the user-space + * provided socket at run time: we must check it under the socket lock + */ + if (tunnel->fd >= 0 && sk->sk_state != TCP_ESTABLISHED) { + kfree_skb(skb); + ret = NET_XMIT_DROP; + goto out_unlock; + } + /* Get routing info from the tunnel socket */ skb_dst_drop(skb); skb_dst_set(skb, dst_clone(__sk_dst_check(sk, 0))); @@ -1212,7 +1228,7 @@ int l2tp_xmit_skb(struct l2tp_session *session, struct sk_buff *skb, int hdr_len /* Calculate UDP checksum if configured to do so */ #if IS_ENABLED(CONFIG_IPV6) - if (sk->sk_family == PF_INET6 && !tunnel->v4mapped) + if (l2tp_sk_is_v6(sk)) udp6_set_csum(udp_get_no_check6_tx(sk), skb, &inet6_sk(sk)->saddr, &sk->sk_v6_daddr, udp_len); @@ -1616,24 +1632,6 @@ int l2tp_tunnel_create(struct net *net, int fd, int version, u32 tunnel_id, u32 if (cfg != NULL) tunnel->debug = cfg->debug; -#if IS_ENABLED(CONFIG_IPV6) - if (sk->sk_family == PF_INET6) { - struct ipv6_pinfo *np = inet6_sk(sk); - - if (ipv6_addr_v4mapped(&np->saddr) && - ipv6_addr_v4mapped(&sk->sk_v6_daddr)) { - struct inet_sock *inet = inet_sk(sk); - - tunnel->v4mapped = true; - inet->inet_saddr = np->saddr.s6_addr32[3]; - inet->inet_rcv_saddr = sk->sk_v6_rcv_saddr.s6_addr32[3]; - inet->inet_daddr = sk->sk_v6_daddr.s6_addr32[3]; - } else { - tunnel->v4mapped = false; - } - } -#endif - /* Mark socket as an encapsulation socket. See net/ipv4/udp.c */ tunnel->encap = encap; if (encap == L2TP_ENCAPTYPE_UDP) { diff --git a/net/l2tp/l2tp_core.h b/net/l2tp/l2tp_core.h index 67c79d9b5c6c..9e2f1fda1b03 100644 --- a/net/l2tp/l2tp_core.h +++ b/net/l2tp/l2tp_core.h @@ -195,9 +195,6 @@ struct l2tp_tunnel { struct sock *sock; /* Parent socket */ int fd; /* Parent fd, if tunnel socket * was created by userspace */ -#if IS_ENABLED(CONFIG_IPV6) - bool v4mapped; -#endif struct work_struct del_work; -- GitLab From 2a55ad7440e6ecf182884b6afd950adb15f273fc Mon Sep 17 00:00:00 2001 From: Paolo Abeni Date: Thu, 22 Mar 2018 11:08:50 +0100 Subject: [PATCH 0056/1635] netfilter: drop template ct when conntrack is skipped. commit aebfa52a925d701114afd6af0def35bab16d4f47 upstream. The ipv4 nf_ct code currently skips the nf_conntrak_in() call for fragmented packets. As a results later matches/target can end up manipulating template ct entry instead of 'real' ones. Exploiting the above, syzbot found a way to trigger the following splat: WARNING: CPU: 1 PID: 4242 at net/netfilter/xt_cluster.c:55 xt_cluster_mt+0x6c1/0x840 net/netfilter/xt_cluster.c:127 Kernel panic - not syncing: panic_on_warn set ... CPU: 1 PID: 4242 Comm: syzkaller027971 Not tainted 4.16.0-rc2+ #243 Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/01/2011 Call Trace: __dump_stack lib/dump_stack.c:17 [inline] dump_stack+0x194/0x24d lib/dump_stack.c:53 panic+0x1e4/0x41c kernel/panic.c:183 __warn+0x1dc/0x200 kernel/panic.c:547 report_bug+0x211/0x2d0 lib/bug.c:184 fixup_bug.part.11+0x37/0x80 arch/x86/kernel/traps.c:178 fixup_bug arch/x86/kernel/traps.c:247 [inline] do_error_trap+0x2d7/0x3e0 arch/x86/kernel/traps.c:296 do_invalid_op+0x1b/0x20 arch/x86/kernel/traps.c:315 invalid_op+0x58/0x80 arch/x86/entry/entry_64.S:957 RIP: 0010:xt_cluster_hash net/netfilter/xt_cluster.c:55 [inline] RIP: 0010:xt_cluster_mt+0x6c1/0x840 net/netfilter/xt_cluster.c:127 RSP: 0018:ffff8801d2f6f2d0 EFLAGS: 00010293 RAX: ffff8801af700540 RBX: 0000000000000000 RCX: ffffffff84a2d1e1 RDX: 0000000000000000 RSI: ffff8801d2f6f478 RDI: ffff8801cafd336a RBP: ffff8801d2f6f2e8 R08: 0000000000000000 R09: 0000000000000001 R10: 0000000000000000 R11: 0000000000000000 R12: ffff8801b03b3d18 R13: ffff8801cafd3300 R14: dffffc0000000000 R15: ffff8801d2f6f478 ipt_do_table+0xa91/0x19b0 net/ipv4/netfilter/ip_tables.c:296 iptable_filter_hook+0x65/0x80 net/ipv4/netfilter/iptable_filter.c:41 nf_hook_entry_hookfn include/linux/netfilter.h:120 [inline] nf_hook_slow+0xba/0x1a0 net/netfilter/core.c:483 nf_hook include/linux/netfilter.h:243 [inline] NF_HOOK include/linux/netfilter.h:286 [inline] raw_send_hdrinc.isra.17+0xf39/0x1880 net/ipv4/raw.c:432 raw_sendmsg+0x14cd/0x26b0 net/ipv4/raw.c:669 inet_sendmsg+0x11f/0x5e0 net/ipv4/af_inet.c:763 sock_sendmsg_nosec net/socket.c:629 [inline] sock_sendmsg+0xca/0x110 net/socket.c:639 SYSC_sendto+0x361/0x5c0 net/socket.c:1748 SyS_sendto+0x40/0x50 net/socket.c:1716 do_syscall_64+0x280/0x940 arch/x86/entry/common.c:287 entry_SYSCALL_64_after_hwframe+0x42/0xb7 RIP: 0033:0x441b49 RSP: 002b:00007ffff5ca8b18 EFLAGS: 00000216 ORIG_RAX: 000000000000002c RAX: ffffffffffffffda RBX: 00000000004002c8 RCX: 0000000000441b49 RDX: 0000000000000030 RSI: 0000000020ff7000 RDI: 0000000000000003 RBP: 00000000006cc018 R08: 000000002066354c R09: 0000000000000010 R10: 0000000000000000 R11: 0000000000000216 R12: 0000000000403470 R13: 0000000000403500 R14: 0000000000000000 R15: 0000000000000000 Dumping ftrace buffer: (ftrace buffer empty) Kernel Offset: disabled Rebooting in 86400 seconds.. Instead of adding checks for template ct on every target/match manipulating skb->_nfct, simply drop the template ct when skipping nf_conntrack_in(). Fixes: 7b4fdf77a450ec ("netfilter: don't track fragmented packets") Reported-and-tested-by: syzbot+0346441ae0545cfcea3a@syzkaller.appspotmail.com Signed-off-by: Paolo Abeni Acked-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso Signed-off-by: Greg Kroah-Hartman --- net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c index 997a96896f1a..37fef48c8826 100644 --- a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c +++ b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c @@ -159,8 +159,20 @@ static unsigned int ipv4_conntrack_local(void *priv, ip_hdrlen(skb) < sizeof(struct iphdr)) return NF_ACCEPT; - if (ip_is_fragment(ip_hdr(skb))) /* IP_NODEFRAG setsockopt set */ + if (ip_is_fragment(ip_hdr(skb))) { /* IP_NODEFRAG setsockopt set */ + enum ip_conntrack_info ctinfo; + struct nf_conn *tmpl; + + tmpl = nf_ct_get(skb, &ctinfo); + if (tmpl && nf_ct_is_template(tmpl)) { + /* when skipping ct, clear templates to avoid fooling + * later targets/matches + */ + skb->_nfct = 0; + nf_ct_put(tmpl); + } return NF_ACCEPT; + } return nf_conntrack_in(state->net, PF_INET, state->hook, skb); } -- GitLab From 839a4c3b4a48805af8d8fd84a203cd6b0e53105c Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Sat, 10 Mar 2018 01:15:45 +0100 Subject: [PATCH 0057/1635] netfilter: x_tables: add and use xt_check_proc_name commit b1d0a5d0cba4597c0394997b2d5fced3e3841b4e upstream. recent and hashlimit both create /proc files, but only check that name is 0 terminated. This can trigger WARN() from procfs when name is "" or "/". Add helper for this and then use it for both. Cc: Eric Dumazet Reported-by: Eric Dumazet Reported-by: Signed-off-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso Signed-off-by: Greg Kroah-Hartman --- include/linux/netfilter/x_tables.h | 2 ++ net/netfilter/x_tables.c | 30 ++++++++++++++++++++++++++++++ net/netfilter/xt_hashlimit.c | 16 ++++++++++------ net/netfilter/xt_recent.c | 6 +++--- 4 files changed, 45 insertions(+), 9 deletions(-) diff --git a/include/linux/netfilter/x_tables.h b/include/linux/netfilter/x_tables.h index 33f7530f96b9..8e46c35d654b 100644 --- a/include/linux/netfilter/x_tables.h +++ b/include/linux/netfilter/x_tables.h @@ -285,6 +285,8 @@ unsigned int *xt_alloc_entry_offsets(unsigned int size); bool xt_find_jump_offset(const unsigned int *offsets, unsigned int target, unsigned int size); +int xt_check_proc_name(const char *name, unsigned int size); + int xt_check_match(struct xt_mtchk_param *, unsigned int size, u_int8_t proto, bool inv_proto); int xt_check_target(struct xt_tgchk_param *, unsigned int size, u_int8_t proto, diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c index 8a4947ff2ebf..a450a1c8804b 100644 --- a/net/netfilter/x_tables.c +++ b/net/netfilter/x_tables.c @@ -423,6 +423,36 @@ textify_hooks(char *buf, size_t size, unsigned int mask, uint8_t nfproto) return buf; } +/** + * xt_check_proc_name - check that name is suitable for /proc file creation + * + * @name: file name candidate + * @size: length of buffer + * + * some x_tables modules wish to create a file in /proc. + * This function makes sure that the name is suitable for this + * purpose, it checks that name is NUL terminated and isn't a 'special' + * name, like "..". + * + * returns negative number on error or 0 if name is useable. + */ +int xt_check_proc_name(const char *name, unsigned int size) +{ + if (name[0] == '\0') + return -EINVAL; + + if (strnlen(name, size) == size) + return -ENAMETOOLONG; + + if (strcmp(name, ".") == 0 || + strcmp(name, "..") == 0 || + strchr(name, '/')) + return -EINVAL; + + return 0; +} +EXPORT_SYMBOL(xt_check_proc_name); + int xt_check_match(struct xt_mtchk_param *par, unsigned int size, u_int8_t proto, bool inv_proto) { diff --git a/net/netfilter/xt_hashlimit.c b/net/netfilter/xt_hashlimit.c index b8a3e740ffd4..0c034597b9b8 100644 --- a/net/netfilter/xt_hashlimit.c +++ b/net/netfilter/xt_hashlimit.c @@ -915,8 +915,9 @@ static int hashlimit_mt_check_v1(const struct xt_mtchk_param *par) struct hashlimit_cfg3 cfg = {}; int ret; - if (info->name[sizeof(info->name) - 1] != '\0') - return -EINVAL; + ret = xt_check_proc_name(info->name, sizeof(info->name)); + if (ret) + return ret; ret = cfg_copy(&cfg, (void *)&info->cfg, 1); @@ -933,8 +934,9 @@ static int hashlimit_mt_check_v2(const struct xt_mtchk_param *par) struct hashlimit_cfg3 cfg = {}; int ret; - if (info->name[sizeof(info->name) - 1] != '\0') - return -EINVAL; + ret = xt_check_proc_name(info->name, sizeof(info->name)); + if (ret) + return ret; ret = cfg_copy(&cfg, (void *)&info->cfg, 2); @@ -948,9 +950,11 @@ static int hashlimit_mt_check_v2(const struct xt_mtchk_param *par) static int hashlimit_mt_check(const struct xt_mtchk_param *par) { struct xt_hashlimit_mtinfo3 *info = par->matchinfo; + int ret; - if (info->name[sizeof(info->name) - 1] != '\0') - return -EINVAL; + ret = xt_check_proc_name(info->name, sizeof(info->name)); + if (ret) + return ret; return hashlimit_mt_check_common(par, &info->hinfo, &info->cfg, info->name, 3); diff --git a/net/netfilter/xt_recent.c b/net/netfilter/xt_recent.c index 245fa350a7a8..cf96d230e5a3 100644 --- a/net/netfilter/xt_recent.c +++ b/net/netfilter/xt_recent.c @@ -361,9 +361,9 @@ static int recent_mt_check(const struct xt_mtchk_param *par, info->hit_count, XT_RECENT_MAX_NSTAMPS - 1); return -EINVAL; } - if (info->name[0] == '\0' || - strnlen(info->name, XT_RECENT_NAME_LEN) == XT_RECENT_NAME_LEN) - return -EINVAL; + ret = xt_check_proc_name(info->name, sizeof(info->name)); + if (ret) + return ret; if (ip_pkt_list_tot && info->hit_count < ip_pkt_list_tot) nstamp_mask = roundup_pow_of_two(ip_pkt_list_tot) - 1; -- GitLab From cf88ae752cd38cf645d6389d9cd051596b5184bd Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 10 Jan 2018 17:35:43 +0100 Subject: [PATCH 0058/1635] phy: qcom-ufs: add MODULE_LICENSE tag commit 59fba0869acae06ff594dd7e9808ed673f53538a upstream. While the specific UFS PHY drivers (14nm and 20nm) have a module license, the common base module does not, leading to a Kbuild failure: WARNING: modpost: missing MODULE_LICENSE() in drivers/phy/qualcomm/phy-qcom-ufs.o FATAL: modpost: GPL-incompatible module phy-qcom-ufs.ko uses GPL-only symbol 'clk_enable' This adds a module description and license tag to fix the build. I added both Yaniv and Vivek as authors here, as Yaniv sent the initial submission, while Vivek did most of the work since. Signed-off-by: Arnd Bergmann Acked-by: Bjorn Andersson Signed-off-by: Kishon Vijay Abraham I Signed-off-by: Greg Kroah-Hartman --- drivers/phy/qualcomm/phy-qcom-ufs.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/phy/qualcomm/phy-qcom-ufs.c b/drivers/phy/qualcomm/phy-qcom-ufs.c index 43865ef340e2..3afba145f2e6 100644 --- a/drivers/phy/qualcomm/phy-qcom-ufs.c +++ b/drivers/phy/qualcomm/phy-qcom-ufs.c @@ -689,3 +689,8 @@ int ufs_qcom_phy_power_off(struct phy *generic_phy) return 0; } EXPORT_SYMBOL_GPL(ufs_qcom_phy_power_off); + +MODULE_AUTHOR("Yaniv Gardi "); +MODULE_AUTHOR("Vivek Gautam "); +MODULE_DESCRIPTION("Universal Flash Storage (UFS) QCOM PHY"); +MODULE_LICENSE("GPL v2"); -- GitLab From 87a97ab15e4482be29593561ef6c4f772a8d9d05 Mon Sep 17 00:00:00 2001 From: Szymon Janc Date: Mon, 26 Feb 2018 15:41:53 +0100 Subject: [PATCH 0059/1635] Bluetooth: Fix missing encryption refresh on Security Request commit 64e759f58f128730b97a3c3a26d283c075ad7c86 upstream. If Security Request is received on connection that is already encrypted with sufficient security master should perform encryption key refresh procedure instead of just ignoring Slave Security Request (Core Spec 5.0 Vol 3 Part H 2.4.6). > ACL Data RX: Handle 3585 flags 0x02 dlen 6 SMP: Security Request (0x0b) len 1 Authentication requirement: Bonding, No MITM, SC, No Keypresses (0x09) < HCI Command: LE Start Encryption (0x08|0x0019) plen 28 Handle: 3585 Random number: 0x0000000000000000 Encrypted diversifier: 0x0000 Long term key: 44264272a5c426a9e868f034cf0e69f3 > HCI Event: Command Status (0x0f) plen 4 LE Start Encryption (0x08|0x0019) ncmd 1 Status: Success (0x00) > HCI Event: Encryption Key Refresh Complete (0x30) plen 3 Status: Success (0x00) Handle: 3585 Signed-off-by: Szymon Janc Signed-off-by: Marcel Holtmann Signed-off-by: Greg Kroah-Hartman --- net/bluetooth/smp.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index a0ef89772c36..a27704ff13a9 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -2287,8 +2287,14 @@ static u8 smp_cmd_security_req(struct l2cap_conn *conn, struct sk_buff *skb) else sec_level = authreq_to_seclevel(auth); - if (smp_sufficient_security(hcon, sec_level, SMP_USE_LTK)) + if (smp_sufficient_security(hcon, sec_level, SMP_USE_LTK)) { + /* If link is already encrypted with sufficient security we + * still need refresh encryption as per Core Spec 5.0 Vol 3, + * Part H 2.4.6 + */ + smp_ltk_encrypt(conn, hcon->sec_level); return 0; + } if (sec_level > hcon->pending_sec_level) hcon->pending_sec_level = sec_level; -- GitLab From 52a0c9a14f52ee478e6cb8c51e4a5a36f7de7cbb Mon Sep 17 00:00:00 2001 From: John Stultz Date: Mon, 23 Oct 2017 14:32:48 -0700 Subject: [PATCH 0060/1635] usb: dwc2: Improve gadget state disconnection handling commit d2471d4a24dfbff5e463d382e2c6fec7d7e25a09 upstream. In the earlier commit dad3f793f20f ("usb: dwc2: Make sure we disconnect the gadget state"), I was trying to fix up the fact that we somehow weren't disconnecting the gadget state, so that when the OTG port was plugged in the second time we would get warnings about the state tracking being wrong. (This seems to be due to a quirk of the HiKey board where we do not ever get any otg interrupts, particularly the session end detected signal. Instead we only see status change interrupt.) The fix there was somewhat simple, as it just made sure to call dwc2_hsotg_disconnect() before we connected things up in OTG mode, ensuring the state handling didn't throw errors. But in looking at a different issue I was seeing with UDC state handling, I realized that it would be much better to call dwc2_hsotg_disconnect when we get the state change signal moving to host mode. Thus, this patch removes the earlier disconnect call I added and moves it (and the needed locking) to the host mode transition. Cc: Wei Xu Cc: Guodong Xu Cc: Amit Pundir Cc: YongQin Liu Cc: John Youn Cc: Minas Harutyunyan Cc: Douglas Anderson Cc: Chen Yu Cc: Felipe Balbi Cc: Greg Kroah-Hartman Cc: linux-usb@vger.kernel.org Acked-by: Minas Harutyunyan Tested-by: Minas Harutyunyan Signed-off-by: John Stultz Signed-off-by: Felipe Balbi Cc: Ben Hutchings Signed-off-by: Greg Kroah-Hartman --- drivers/usb/dwc2/hcd.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c index c2631145f404..9bd60ec83ac6 100644 --- a/drivers/usb/dwc2/hcd.c +++ b/drivers/usb/dwc2/hcd.c @@ -3277,7 +3277,6 @@ static void dwc2_conn_id_status_change(struct work_struct *work) dwc2_core_init(hsotg, false); dwc2_enable_global_interrupts(hsotg); spin_lock_irqsave(&hsotg->lock, flags); - dwc2_hsotg_disconnect(hsotg); dwc2_hsotg_core_init_disconnected(hsotg, false); spin_unlock_irqrestore(&hsotg->lock, flags); dwc2_hsotg_core_connect(hsotg); @@ -3296,8 +3295,12 @@ static void dwc2_conn_id_status_change(struct work_struct *work) if (count > 250) dev_err(hsotg->dev, "Connection id status change timed out\n"); - hsotg->op_state = OTG_STATE_A_HOST; + spin_lock_irqsave(&hsotg->lock, flags); + dwc2_hsotg_disconnect(hsotg); + spin_unlock_irqrestore(&hsotg->lock, flags); + + hsotg->op_state = OTG_STATE_A_HOST; /* Initialize the Core for Host mode */ dwc2_core_init(hsotg, false); dwc2_enable_global_interrupts(hsotg); -- GitLab From ac5a36bb69570bc5bdd68f21c6793abc0b110cb7 Mon Sep 17 00:00:00 2001 From: Omar Sandoval Date: Mon, 2 Apr 2018 15:58:31 -0700 Subject: [PATCH 0061/1635] bitmap: fix memset optimization on big-endian systems commit 21035965f60b0502fc6537b232839389bb4ce664 upstream. Commit 2a98dc028f91 ("include/linux/bitmap.h: turn bitmap_set and bitmap_clear into memset when possible") introduced an optimization to bitmap_{set,clear}() which uses memset() when the start and length are constants aligned to a byte. This is wrong on big-endian systems; our bitmaps are arrays of unsigned long, so bit n is not at byte n / 8 in memory. This was caught by the Btrfs selftests, but the bitmap selftests also fail when run on a big-endian machine. We can still use memset if the start and length are aligned to an unsigned long, so do that on big-endian. The same problem applies to the memcmp in bitmap_equal(), so fix it there, too. Fixes: 2a98dc028f91 ("include/linux/bitmap.h: turn bitmap_set and bitmap_clear into memset when possible") Fixes: 2c6deb01525a ("bitmap: use memcmp optimisation in more situations") Cc: stable@kernel.org Reported-by: "Erhard F." Cc: Matthew Wilcox Cc: Rasmus Villemoes Cc: Andrew Morton Cc: Arnd Bergmann Signed-off-by: Omar Sandoval Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- include/linux/bitmap.h | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/include/linux/bitmap.h b/include/linux/bitmap.h index 19748a5b0e77..835c2271196a 100644 --- a/include/linux/bitmap.h +++ b/include/linux/bitmap.h @@ -262,12 +262,20 @@ static inline void bitmap_complement(unsigned long *dst, const unsigned long *sr __bitmap_complement(dst, src, nbits); } +#ifdef __LITTLE_ENDIAN +#define BITMAP_MEM_ALIGNMENT 8 +#else +#define BITMAP_MEM_ALIGNMENT (8 * sizeof(unsigned long)) +#endif +#define BITMAP_MEM_MASK (BITMAP_MEM_ALIGNMENT - 1) + static inline int bitmap_equal(const unsigned long *src1, const unsigned long *src2, unsigned int nbits) { if (small_const_nbits(nbits)) return !((*src1 ^ *src2) & BITMAP_LAST_WORD_MASK(nbits)); - if (__builtin_constant_p(nbits & 7) && IS_ALIGNED(nbits, 8)) + if (__builtin_constant_p(nbits & BITMAP_MEM_MASK) && + IS_ALIGNED(nbits, BITMAP_MEM_ALIGNMENT)) return !memcmp(src1, src2, nbits / 8); return __bitmap_equal(src1, src2, nbits); } @@ -318,8 +326,10 @@ static __always_inline void bitmap_set(unsigned long *map, unsigned int start, { if (__builtin_constant_p(nbits) && nbits == 1) __set_bit(start, map); - else if (__builtin_constant_p(start & 7) && IS_ALIGNED(start, 8) && - __builtin_constant_p(nbits & 7) && IS_ALIGNED(nbits, 8)) + else if (__builtin_constant_p(start & BITMAP_MEM_MASK) && + IS_ALIGNED(start, BITMAP_MEM_ALIGNMENT) && + __builtin_constant_p(nbits & BITMAP_MEM_MASK) && + IS_ALIGNED(nbits, BITMAP_MEM_ALIGNMENT)) memset((char *)map + start / 8, 0xff, nbits / 8); else __bitmap_set(map, start, nbits); @@ -330,8 +340,10 @@ static __always_inline void bitmap_clear(unsigned long *map, unsigned int start, { if (__builtin_constant_p(nbits) && nbits == 1) __clear_bit(start, map); - else if (__builtin_constant_p(start & 7) && IS_ALIGNED(start, 8) && - __builtin_constant_p(nbits & 7) && IS_ALIGNED(nbits, 8)) + else if (__builtin_constant_p(start & BITMAP_MEM_MASK) && + IS_ALIGNED(start, BITMAP_MEM_ALIGNMENT) && + __builtin_constant_p(nbits & BITMAP_MEM_MASK) && + IS_ALIGNED(nbits, BITMAP_MEM_ALIGNMENT)) memset((char *)map + start / 8, 0, nbits / 8); else __bitmap_clear(map, start, nbits); -- GitLab From e1e87ebd5b79537ef3b6f3204041a45f82f6feb7 Mon Sep 17 00:00:00 2001 From: Major Hayden Date: Fri, 23 Feb 2018 14:29:54 -0600 Subject: [PATCH 0062/1635] USB: serial: ftdi_sio: add RT Systems VX-8 cable commit 9608e5c0f079390473b484ef92334dfd3431bb89 upstream. This patch adds a device ID for the RT Systems cable used to program Yaesu VX-8R/VX-8DR handheld radios. It uses the main FTDI VID instead of the common RT Systems VID. Signed-off-by: Major Hayden Cc: stable Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/ftdi_sio.c | 1 + drivers/usb/serial/ftdi_sio_ids.h | 3 +++ 2 files changed, 4 insertions(+) diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index d038e543c246..df4a6d01b5b8 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -773,6 +773,7 @@ static const struct usb_device_id id_table_combined[] = { .driver_info = (kernel_ulong_t)&ftdi_NDI_device_quirk }, { USB_DEVICE(TELLDUS_VID, TELLDUS_TELLSTICK_PID) }, { USB_DEVICE(NOVITUS_VID, NOVITUS_BONO_E_PID) }, + { USB_DEVICE(FTDI_VID, RTSYSTEMS_USB_VX8_PID) }, { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_S03_PID) }, { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_59_PID) }, { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_57A_PID) }, diff --git a/drivers/usb/serial/ftdi_sio_ids.h b/drivers/usb/serial/ftdi_sio_ids.h index 8b4ecd2bd297..598c2317c3d4 100644 --- a/drivers/usb/serial/ftdi_sio_ids.h +++ b/drivers/usb/serial/ftdi_sio_ids.h @@ -923,6 +923,9 @@ /* * RT Systems programming cables for various ham radios */ +/* This device uses the VID of FTDI */ +#define RTSYSTEMS_USB_VX8_PID 0x9e50 /* USB-VX8 USB to 7 pin modular plug for Yaesu VX-8 radio */ + #define RTSYSTEMS_VID 0x2100 /* Vendor ID */ #define RTSYSTEMS_USB_S03_PID 0x9001 /* RTS-03 USB to Serial Adapter */ #define RTSYSTEMS_USB_59_PID 0x9e50 /* USB-59 USB to 8 pin plug */ -- GitLab From f4d01432eeda10436887023e36d75e1d7f9d626b Mon Sep 17 00:00:00 2001 From: Clemens Werther Date: Fri, 16 Mar 2018 10:20:46 +0100 Subject: [PATCH 0063/1635] USB: serial: ftdi_sio: add support for Harman FirmwareHubEmulator commit 6555ad13a01952c16485c82a52ad1f3e07e34b3a upstream. Add device id for Harman FirmwareHubEmulator to make the device auto-detectable by the driver. Signed-off-by: Clemens Werther Cc: stable Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/ftdi_sio.c | 1 + drivers/usb/serial/ftdi_sio_ids.h | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index df4a6d01b5b8..a2a5232751cb 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -936,6 +936,7 @@ static const struct usb_device_id id_table_combined[] = { { USB_DEVICE(FTDI_VID, FTDI_SCIENCESCOPE_LS_LOGBOOK_PID) }, { USB_DEVICE(FTDI_VID, FTDI_SCIENCESCOPE_HS_LOGBOOK_PID) }, { USB_DEVICE(FTDI_VID, FTDI_CINTERION_MC55I_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_FHE_PID) }, { USB_DEVICE(FTDI_VID, FTDI_DOTEC_PID) }, { USB_DEVICE(QIHARDWARE_VID, MILKYMISTONE_JTAGSERIAL_PID), .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, diff --git a/drivers/usb/serial/ftdi_sio_ids.h b/drivers/usb/serial/ftdi_sio_ids.h index 598c2317c3d4..975d02666c5a 100644 --- a/drivers/usb/serial/ftdi_sio_ids.h +++ b/drivers/usb/serial/ftdi_sio_ids.h @@ -1444,6 +1444,12 @@ */ #define FTDI_CINTERION_MC55I_PID 0xA951 +/* + * Product: FirmwareHubEmulator + * Manufacturer: Harman Becker Automotive Systems + */ +#define FTDI_FHE_PID 0xA9A0 + /* * Product: Comet Caller ID decoder * Manufacturer: Crucible Technologies -- GitLab From c0aed3667b3d55a8c49d4411627a41d1fbfb73e0 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Tue, 6 Mar 2018 09:32:43 +0100 Subject: [PATCH 0064/1635] USB: serial: cp210x: add ELDAT Easywave RX09 id commit 1f1e82f74c0947e40144688c9e36abe4b3999f49 upstream. Add device id for ELDAT Easywave RX09 tranceiver. Reported-by: Jan Jansen Cc: stable Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/cp210x.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c index aed182d24d23..2836acf73a07 100644 --- a/drivers/usb/serial/cp210x.c +++ b/drivers/usb/serial/cp210x.c @@ -158,6 +158,7 @@ static const struct usb_device_id id_table[] = { { USB_DEVICE(0x12B8, 0xEC62) }, /* Link G4+ ECU */ { USB_DEVICE(0x13AD, 0x9999) }, /* Baltech card reader */ { USB_DEVICE(0x1555, 0x0004) }, /* Owen AC4 USB-RS485 Converter */ + { USB_DEVICE(0x155A, 0x1006) }, /* ELDAT Easywave RX09 */ { USB_DEVICE(0x166A, 0x0201) }, /* Clipsal 5500PACA C-Bus Pascal Automation Controller */ { USB_DEVICE(0x166A, 0x0301) }, /* Clipsal 5800PC C-Bus Wireless PC Interface */ { USB_DEVICE(0x166A, 0x0303) }, /* Clipsal 5500PCU C-Bus USB interface */ -- GitLab From cbf733ca587c93aebb4f4aa721dba95a11725a69 Mon Sep 17 00:00:00 2001 From: Joel Stanley Date: Mon, 5 Mar 2018 22:17:38 +1030 Subject: [PATCH 0065/1635] serial: 8250: Add Nuvoton NPCM UART commit f597fbce38d230af95384f4a04e0a13a1d0ad45d upstream. The Nuvoton UART is almost compatible with the 8250 driver when probed via the 8250_of driver, however it requires some extra configuration at startup. Reviewed-by: Rob Herring Signed-off-by: Joel Stanley Cc: stable Signed-off-by: Greg Kroah-Hartman --- .../devicetree/bindings/serial/8250.txt | 1 + drivers/tty/serial/8250/8250_of.c | 1 + drivers/tty/serial/8250/8250_port.c | 33 +++++++++++++++++++ include/uapi/linux/serial_core.h | 3 ++ 4 files changed, 38 insertions(+) diff --git a/Documentation/devicetree/bindings/serial/8250.txt b/Documentation/devicetree/bindings/serial/8250.txt index dad3b2ec66d4..aeb6db4e35c3 100644 --- a/Documentation/devicetree/bindings/serial/8250.txt +++ b/Documentation/devicetree/bindings/serial/8250.txt @@ -24,6 +24,7 @@ Required properties: - "ti,da830-uart" - "aspeed,ast2400-vuart" - "aspeed,ast2500-vuart" + - "nuvoton,npcm750-uart" - "serial" if the port type is unknown. - reg : offset and length of the register set for the device. - interrupts : should contain uart interrupt. diff --git a/drivers/tty/serial/8250/8250_of.c b/drivers/tty/serial/8250/8250_of.c index 951680640ad5..3613a6aabfb3 100644 --- a/drivers/tty/serial/8250/8250_of.c +++ b/drivers/tty/serial/8250/8250_of.c @@ -321,6 +321,7 @@ static const struct of_device_id of_platform_serial_table[] = { { .compatible = "mrvl,mmp-uart", .data = (void *)PORT_XSCALE, }, { .compatible = "ti,da830-uart", .data = (void *)PORT_DA830, }, + { .compatible = "nuvoton,npcm750-uart", .data = (void *)PORT_NPCM, }, { /* end of list */ }, }; MODULE_DEVICE_TABLE(of, of_platform_serial_table); diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c index 8dcfd4978a03..fde34c84e707 100644 --- a/drivers/tty/serial/8250/8250_port.c +++ b/drivers/tty/serial/8250/8250_port.c @@ -51,6 +51,10 @@ #define UART_EXAR_SLEEP 0x8b /* Sleep mode */ #define UART_EXAR_DVID 0x8d /* Device identification */ +/* Nuvoton NPCM timeout register */ +#define UART_NPCM_TOR 7 +#define UART_NPCM_TOIE BIT(7) /* Timeout Interrupt Enable */ + /* * Debugging. */ @@ -297,6 +301,15 @@ static const struct serial8250_config uart_config[] = { UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT, .flags = UART_CAP_FIFO, }, + [PORT_NPCM] = { + .name = "Nuvoton 16550", + .fifo_size = 16, + .tx_loadsz = 16, + .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10 | + UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT, + .rxtrig_bytes = {1, 4, 8, 14}, + .flags = UART_CAP_FIFO, + }, }; /* Uart divisor latch read */ @@ -2168,6 +2181,15 @@ int serial8250_do_startup(struct uart_port *port) UART_DA830_PWREMU_MGMT_FREE); } + if (port->type == PORT_NPCM) { + /* + * Nuvoton calls the scratch register 'UART_TOR' (timeout + * register). Enable it, and set TIOC (timeout interrupt + * comparator) to be 0x20 for correct operation. + */ + serial_port_out(port, UART_NPCM_TOR, UART_NPCM_TOIE | 0x20); + } + #ifdef CONFIG_SERIAL_8250_RSA /* * If this is an RSA port, see if we can kick it up to the @@ -2490,6 +2512,15 @@ static unsigned int xr17v35x_get_divisor(struct uart_8250_port *up, return quot_16 >> 4; } +/* Nuvoton NPCM UARTs have a custom divisor calculation */ +static unsigned int npcm_get_divisor(struct uart_8250_port *up, + unsigned int baud) +{ + struct uart_port *port = &up->port; + + return DIV_ROUND_CLOSEST(port->uartclk, 16 * baud + 2) - 2; +} + static unsigned int serial8250_get_divisor(struct uart_8250_port *up, unsigned int baud, unsigned int *frac) @@ -2510,6 +2541,8 @@ static unsigned int serial8250_get_divisor(struct uart_8250_port *up, quot = 0x8002; else if (up->port.type == PORT_XR17V35X) quot = xr17v35x_get_divisor(up, baud, frac); + else if (up->port.type == PORT_NPCM) + quot = npcm_get_divisor(up, baud); else quot = uart_get_divisor(port, baud); diff --git a/include/uapi/linux/serial_core.h b/include/uapi/linux/serial_core.h index 1c8413f93e3d..dce5f9dae121 100644 --- a/include/uapi/linux/serial_core.h +++ b/include/uapi/linux/serial_core.h @@ -76,6 +76,9 @@ #define PORT_SUNZILOG 38 #define PORT_SUNSAB 39 +/* Nuvoton UART */ +#define PORT_NPCM 40 + /* Intel EG20 */ #define PORT_PCH_8LINE 44 #define PORT_PCH_2LINE 45 -- GitLab From 66a65ca5b8fda6f5c55a9cf83e0fcb8e613baaa9 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Tue, 27 Feb 2018 16:21:05 +0000 Subject: [PATCH 0066/1635] mei: remove dev_err message on an unsupported ioctl commit bb0829a741792b56c908d7745bc0b2b540293bcc upstream. Currently the driver spams the kernel log on unsupported ioctls which is unnecessary as the ioctl returns -ENOIOCTLCMD to indicate this anyway. I suspect this was originally for debugging purposes but it really is not required so remove it. Signed-off-by: Colin Ian King Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/misc/mei/main.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/misc/mei/main.c b/drivers/misc/mei/main.c index e825f013e54e..22efc039f302 100644 --- a/drivers/misc/mei/main.c +++ b/drivers/misc/mei/main.c @@ -507,7 +507,6 @@ static long mei_ioctl(struct file *file, unsigned int cmd, unsigned long data) break; default: - dev_err(dev->dev, ": unsupported ioctl %d.\n", cmd); rets = -ENOIOCTLCMD; } -- GitLab From 5f834dd24baec1f9926e8a06609e0906fd607b06 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Tue, 27 Mar 2018 14:06:14 -0700 Subject: [PATCH 0067/1635] /dev/mem: Avoid overwriting "err" in read_mem() commit b5b38200ebe54879a7264cb6f33821f61c586a7e upstream. Successes in probe_kernel_read() would mask failures in copy_to_user() during read_mem(). Reported-by: Brad Spengler Fixes: 22ec1a2aea73 ("/dev/mem: Add bounce buffer for copy-out") Cc: stable@vger.kernel.org Signed-off-by: Kees Cook Signed-off-by: Greg Kroah-Hartman --- drivers/char/mem.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/char/mem.c b/drivers/char/mem.c index 3a70dba2c645..f11224a5dc5c 100644 --- a/drivers/char/mem.c +++ b/drivers/char/mem.c @@ -137,7 +137,7 @@ static ssize_t read_mem(struct file *file, char __user *buf, while (count > 0) { unsigned long remaining; - int allowed; + int allowed, probe; sz = size_inside_page(p, count); @@ -160,9 +160,9 @@ static ssize_t read_mem(struct file *file, char __user *buf, if (!ptr) goto failed; - err = probe_kernel_read(bounce, ptr, sz); + probe = probe_kernel_read(bounce, ptr, sz); unxlate_dev_mem_ptr(p, ptr); - if (err) + if (probe) goto failed; remaining = copy_to_user(buf, bounce, sz); -- GitLab From 1f17d5033fe3c435556d8fb731f3a51ca073ce85 Mon Sep 17 00:00:00 2001 From: Oliver Neukum Date: Mon, 8 Jan 2018 09:21:07 -0500 Subject: [PATCH 0068/1635] media: usbtv: prevent double free in error case commit 50e7044535537b2a54c7ab798cd34c7f6d900bd2 upstream. Quoting the original report: It looks like there is a double-free vulnerability in Linux usbtv driver on an error path of usbtv_probe function. When audio registration fails, usbtv_video_free function ends up freeing usbtv data structure, which gets freed the second time under usbtv_video_fail label. usbtv_audio_fail: usbtv_video_free(usbtv); => v4l2_device_put(&usbtv->v4l2_dev); => v4l2_device_put => kref_put => v4l2_device_release => usbtv_release (CALLBACK) => kfree(usbtv) (1st time) usbtv_video_fail: usb_set_intfdata(intf, NULL); usb_put_dev(usbtv->udev); kfree(usbtv); (2nd time) So, as we have refcounting, use it Reported-by: Yavuz, Tuba Signed-off-by: Oliver Neukum CC: stable@vger.kernel.org Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Greg Kroah-Hartman --- drivers/media/usb/usbtv/usbtv-core.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/media/usb/usbtv/usbtv-core.c b/drivers/media/usb/usbtv/usbtv-core.c index 71fb5734995b..68df16b3ce72 100644 --- a/drivers/media/usb/usbtv/usbtv-core.c +++ b/drivers/media/usb/usbtv/usbtv-core.c @@ -112,6 +112,8 @@ static int usbtv_probe(struct usb_interface *intf, return 0; usbtv_audio_fail: + /* we must not free at this point */ + usb_get_dev(usbtv->udev); usbtv_video_free(usbtv); usbtv_video_fail: -- GitLab From 3c6096ca8e491a2c5a6d578fd4f191e94961dc20 Mon Sep 17 00:00:00 2001 From: Alexander Gerasiov Date: Sun, 4 Feb 2018 02:50:22 +0300 Subject: [PATCH 0069/1635] parport_pc: Add support for WCH CH382L PCI-E single parallel port card. commit 823f7923833c6cc2b16e601546d607dcfb368004 upstream. WCH CH382L is a PCI-E adapter with 1 parallel port. It is similair to CH382 but serial ports are not soldered on board. Detected as Serial controller: Device 1c00:3050 (rev 10) (prog-if 05 [16850]) Signed-off-by: Alexander Gerasiov Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/parport/parport_pc.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/parport/parport_pc.c b/drivers/parport/parport_pc.c index 489492b608cf..380916bff9e0 100644 --- a/drivers/parport/parport_pc.c +++ b/drivers/parport/parport_pc.c @@ -2646,6 +2646,7 @@ enum parport_pc_pci_cards { netmos_9901, netmos_9865, quatech_sppxp100, + wch_ch382l, }; @@ -2708,6 +2709,7 @@ static struct parport_pc_pci { /* netmos_9901 */ { 1, { { 0, -1 }, } }, /* netmos_9865 */ { 1, { { 0, -1 }, } }, /* quatech_sppxp100 */ { 1, { { 0, 1 }, } }, + /* wch_ch382l */ { 1, { { 2, -1 }, } }, }; static const struct pci_device_id parport_pc_pci_tbl[] = { @@ -2797,6 +2799,8 @@ static const struct pci_device_id parport_pc_pci_tbl[] = { /* Quatech SPPXP-100 Parallel port PCI ExpressCard */ { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_SPPXP_100, PCI_ANY_ID, PCI_ANY_ID, 0, 0, quatech_sppxp100 }, + /* WCH CH382L PCI-E single parallel port card */ + { 0x1c00, 0x3050, 0x1c00, 0x3050, 0, 0, wch_ch382l }, { 0, } /* terminate list */ }; MODULE_DEVICE_TABLE(pci, parport_pc_pci_tbl); -- GitLab From 77827f3d63d0b12d840ed27b362f877e049dbbf5 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Fri, 23 Mar 2018 08:14:44 +0800 Subject: [PATCH 0070/1635] crypto: lrw - Free rctx->ext with kzfree commit 8c9bdab21289c211ca1ca6a5f9b7537b4a600a02 upstream. The buffer rctx->ext contains potentially sensitive data and should be freed with kzfree. Cc: Fixes: 700cb3f5fe75 ("crypto: lrw - Convert to skcipher") Reported-by: Dan Carpenter Signed-off-by: Herbert Xu Signed-off-by: Greg Kroah-Hartman --- crypto/lrw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crypto/lrw.c b/crypto/lrw.c index eb681e9fe574..fdba6dd6db63 100644 --- a/crypto/lrw.c +++ b/crypto/lrw.c @@ -313,7 +313,7 @@ static void exit_crypt(struct skcipher_request *req) rctx->left = 0; if (rctx->ext) - kfree(rctx->ext); + kzfree(rctx->ext); } static int do_encrypt(struct skcipher_request *req, int err) -- GitLab From 41e960b042fcf5e24ad68df669e58c69b5c42d21 Mon Sep 17 00:00:00 2001 From: Gregory CLEMENT Date: Tue, 13 Mar 2018 17:48:40 +0100 Subject: [PATCH 0071/1635] crypto: inside-secure - fix clock management commit f962eb46e7a9b98a58d2483f5eb216e738fec732 upstream. In this driver the clock is got but never put when the driver is removed or if there is an error in the probe. Using the managed version of clk_get() allows to let the kernel take care of it. Fixes: 1b44c5a60c13 ("crypto: inside-secure - add SafeXcel EIP197 crypto engine driver") cc: stable@vger.kernel.org Signed-off-by: Gregory CLEMENT Signed-off-by: Herbert Xu Signed-off-by: Greg Kroah-Hartman --- drivers/crypto/inside-secure/safexcel.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/crypto/inside-secure/safexcel.c b/drivers/crypto/inside-secure/safexcel.c index 4bcef78a08aa..d4c81cb73bee 100644 --- a/drivers/crypto/inside-secure/safexcel.c +++ b/drivers/crypto/inside-secure/safexcel.c @@ -789,7 +789,7 @@ static int safexcel_probe(struct platform_device *pdev) return PTR_ERR(priv->base); } - priv->clk = of_clk_get(dev->of_node, 0); + priv->clk = devm_clk_get(&pdev->dev, NULL); if (!IS_ERR(priv->clk)) { ret = clk_prepare_enable(priv->clk); if (ret) { -- GitLab From ad35fdc00a7cca4e53e70b5d2eb419f2661d92b5 Mon Sep 17 00:00:00 2001 From: Conor McLoughlin Date: Tue, 13 Feb 2018 08:29:56 +0000 Subject: [PATCH 0072/1635] crypto: testmgr - Fix incorrect values in PKCS#1 test vector commit 333e18c5cc74438f8940c7f3a8b3573748a371f9 upstream. The RSA private key for the first form should have version, prime1, prime2, exponent1, exponent2, coefficient values 0. With non-zero values for prime1,2, exponent 1,2 and coefficient the Intel QAT driver will assume that values are provided for the private key second form. This will result in signature verification failures for modules where QAT device is present and the modules are signed with rsa,sha256. Cc: Signed-off-by: Giovanni Cabiddu Signed-off-by: Conor McLoughlin Reviewed-by: Stephan Mueller Signed-off-by: Herbert Xu Signed-off-by: Greg Kroah-Hartman --- crypto/testmgr.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/crypto/testmgr.h b/crypto/testmgr.h index d54971d2d1c8..fbc0fab5e79e 100644 --- a/crypto/testmgr.h +++ b/crypto/testmgr.h @@ -548,7 +548,7 @@ static const struct akcipher_testvec rsa_tv_template[] = { static const struct akcipher_testvec pkcs1pad_rsa_tv_template[] = { { .key = - "\x30\x82\x03\x1f\x02\x01\x10\x02\x82\x01\x01\x00\xd7\x1e\x77\x82" + "\x30\x82\x03\x1f\x02\x01\x00\x02\x82\x01\x01\x00\xd7\x1e\x77\x82" "\x8c\x92\x31\xe7\x69\x02\xa2\xd5\x5c\x78\xde\xa2\x0c\x8f\xfe\x28" "\x59\x31\xdf\x40\x9c\x60\x61\x06\xb9\x2f\x62\x40\x80\x76\xcb\x67" "\x4a\xb5\x59\x56\x69\x17\x07\xfa\xf9\x4c\xbd\x6c\x37\x7a\x46\x7d" @@ -597,8 +597,8 @@ static const struct akcipher_testvec pkcs1pad_rsa_tv_template[] = { "\xfe\xf8\x27\x1b\xd6\x55\x60\x5e\x48\xb7\x6d\x9a\xa8\x37\xf9\x7a" "\xde\x1b\xcd\x5d\x1a\x30\xd4\xe9\x9e\x5b\x3c\x15\xf8\x9c\x1f\xda" "\xd1\x86\x48\x55\xce\x83\xee\x8e\x51\xc7\xde\x32\x12\x47\x7d\x46" - "\xb8\x35\xdf\x41\x02\x01\x30\x02\x01\x30\x02\x01\x30\x02\x01\x30" - "\x02\x01\x30", + "\xb8\x35\xdf\x41\x02\x01\x00\x02\x01\x00\x02\x01\x00\x02\x01\x00" + "\x02\x01\x00", .key_len = 804, /* * m is SHA256 hash of following message: -- GitLab From c3657fd0c15f54437fc16cc4b838574970a8fa05 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Mon, 26 Mar 2018 08:53:25 +0800 Subject: [PATCH 0073/1635] crypto: ahash - Fix early termination in hash walk commit 900a081f6912a8985dc15380ec912752cb66025a upstream. When we have an unaligned SG list entry where there is no leftover aligned data, the hash walk code will incorrectly return zero as if the entire SG list has been processed. This patch fixes it by moving onto the next page instead. Reported-by: Eli Cooper Cc: Signed-off-by: Herbert Xu Signed-off-by: Greg Kroah-Hartman --- crypto/ahash.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/crypto/ahash.c b/crypto/ahash.c index f75b5c1f7152..3980e9e45289 100644 --- a/crypto/ahash.c +++ b/crypto/ahash.c @@ -92,13 +92,14 @@ int crypto_hash_walk_done(struct crypto_hash_walk *walk, int err) if (nbytes && walk->offset & alignmask && !err) { walk->offset = ALIGN(walk->offset, alignmask + 1); - walk->data += walk->offset; - nbytes = min(nbytes, ((unsigned int)(PAGE_SIZE)) - walk->offset); walk->entrylen -= nbytes; - return nbytes; + if (nbytes) { + walk->data += walk->offset; + return nbytes; + } } if (walk->flags & CRYPTO_ALG_ASYNC) -- GitLab From 056f3bd2399b72d34f02a470c4dcb9f7415f7d42 Mon Sep 17 00:00:00 2001 From: Rui Miguel Silva Date: Thu, 22 Feb 2018 14:22:47 +0000 Subject: [PATCH 0074/1635] crypto: caam - Fix null dereference at error path MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit b85149f6f5d5a9279f29a73b2e95342f4d465e73 upstream. caam_remove already removes the debugfs entry, so we need to remove the one immediately before calling caam_remove. This fix a NULL dereference at error paths is caam_probe fail. Fixes: 67c2315def06 ("crypto: caam - add Queue Interface (QI) backend support") Tested-by: Ryan Harkin Cc: "Horia Geantă" Cc: Aymen Sghaier Cc: Fabio Estevam Cc: Peng Fan Cc: "David S. Miller" Cc: Lukas Auer Cc: # 4.12+ Reviewed-by: Horia Geantă Signed-off-by: Rui Miguel Silva Signed-off-by: Herbert Xu Signed-off-by: Greg Kroah-Hartman --- drivers/crypto/caam/ctrl.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/crypto/caam/ctrl.c b/drivers/crypto/caam/ctrl.c index e1d4ae1153c4..39f70411f28f 100644 --- a/drivers/crypto/caam/ctrl.c +++ b/drivers/crypto/caam/ctrl.c @@ -813,9 +813,6 @@ static int caam_probe(struct platform_device *pdev) return 0; caam_remove: -#ifdef CONFIG_DEBUG_FS - debugfs_remove_recursive(ctrlpriv->dfs_root); -#endif caam_remove(pdev); return ret; -- GitLab From ee54953ecd47a7d699cd132999efd6db3965a794 Mon Sep 17 00:00:00 2001 From: "Maciej S. Szmigiero" Date: Sat, 24 Feb 2018 17:03:21 +0100 Subject: [PATCH 0075/1635] crypto: ccp - return an actual key size from RSA max_size callback commit 0a9eb80e643064266868bd2fb2cd608e669309b0 upstream. rsa-pkcs1pad uses a value returned from a RSA implementation max_size callback as a size of an input buffer passed to the RSA implementation for encrypt and sign operations. CCP RSA implementation uses a hardware input buffer which size depends only on the current RSA key length, so it should return this key length in the max_size callback, too. This also matches what the kernel software RSA implementation does. Previously, the value returned from this callback was always the maximum RSA key size the CCP hardware supports. This resulted in this huge buffer being passed by rsa-pkcs1pad to CCP even for smaller key sizes and then in a buffer overflow when ccp_run_rsa_cmd() tried to copy this large input buffer into a RSA key length-sized hardware input buffer. Signed-off-by: Maciej S. Szmigiero Fixes: ceeec0afd684 ("crypto: ccp - Add support for RSA on the CCP") Cc: stable@vger.kernel.org Acked-by: Gary R Hook Signed-off-by: Herbert Xu Signed-off-by: Greg Kroah-Hartman --- drivers/crypto/ccp/ccp-crypto-rsa.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/crypto/ccp/ccp-crypto-rsa.c b/drivers/crypto/ccp/ccp-crypto-rsa.c index e6db8672d89c..05850dfd7940 100644 --- a/drivers/crypto/ccp/ccp-crypto-rsa.c +++ b/drivers/crypto/ccp/ccp-crypto-rsa.c @@ -60,10 +60,9 @@ static int ccp_rsa_complete(struct crypto_async_request *async_req, int ret) static unsigned int ccp_rsa_maxsize(struct crypto_akcipher *tfm) { - if (ccp_version() > CCP_VERSION(3, 0)) - return CCP5_RSA_MAXMOD; - else - return CCP_RSA_MAXMOD; + struct ccp_ctx *ctx = akcipher_tfm_ctx(tfm); + + return ctx->u.rsa.n_len; } static int ccp_rsa_crypt(struct akcipher_request *req, bool encrypt) -- GitLab From b5a8883909984b60ab9274ef52e364051bd6177a Mon Sep 17 00:00:00 2001 From: Leonard Crestez Date: Tue, 13 Mar 2018 22:17:23 +0200 Subject: [PATCH 0076/1635] crypto: arm,arm64 - Fix random regeneration of S_shipped commit 6aaf49b495b446ff6eec0ac983f781ca0dc56a73 upstream. The decision to rebuild .S_shipped is made based on the relative timestamps of .S_shipped and .pl files but git makes this essentially random. This means that the perl script might run anyway (usually at most once per checkout), defeating the whole purpose of _shipped. Fix by skipping the rule unless explicit make variables are provided: REGENERATE_ARM_CRYPTO or REGENERATE_ARM64_CRYPTO. This can produce nasty occasional build failures downstream, for example for toolchains with broken perl. The solution is minimally intrusive to make it easier to push into stable. Another report on a similar issue here: https://lkml.org/lkml/2018/3/8/1379 Signed-off-by: Leonard Crestez Cc: Reviewed-by: Masahiro Yamada Acked-by: Ard Biesheuvel Signed-off-by: Herbert Xu Signed-off-by: Greg Kroah-Hartman --- arch/arm/crypto/Makefile | 2 ++ arch/arm64/crypto/Makefile | 2 ++ 2 files changed, 4 insertions(+) diff --git a/arch/arm/crypto/Makefile b/arch/arm/crypto/Makefile index 30ef8e291271..c9919c2b7ad1 100644 --- a/arch/arm/crypto/Makefile +++ b/arch/arm/crypto/Makefile @@ -54,6 +54,7 @@ crct10dif-arm-ce-y := crct10dif-ce-core.o crct10dif-ce-glue.o crc32-arm-ce-y:= crc32-ce-core.o crc32-ce-glue.o chacha20-neon-y := chacha20-neon-core.o chacha20-neon-glue.o +ifdef REGENERATE_ARM_CRYPTO quiet_cmd_perl = PERL $@ cmd_perl = $(PERL) $(<) > $(@) @@ -62,5 +63,6 @@ $(src)/sha256-core.S_shipped: $(src)/sha256-armv4.pl $(src)/sha512-core.S_shipped: $(src)/sha512-armv4.pl $(call cmd,perl) +endif .PRECIOUS: $(obj)/sha256-core.S $(obj)/sha512-core.S diff --git a/arch/arm64/crypto/Makefile b/arch/arm64/crypto/Makefile index b5edc5918c28..12fd81af1d1c 100644 --- a/arch/arm64/crypto/Makefile +++ b/arch/arm64/crypto/Makefile @@ -58,6 +58,7 @@ CFLAGS_aes-glue-ce.o := -DUSE_V8_CRYPTO_EXTENSIONS $(obj)/aes-glue-%.o: $(src)/aes-glue.c FORCE $(call if_changed_rule,cc_o_c) +ifdef REGENERATE_ARM64_CRYPTO quiet_cmd_perlasm = PERLASM $@ cmd_perlasm = $(PERL) $(<) void $(@) @@ -66,5 +67,6 @@ $(src)/sha256-core.S_shipped: $(src)/sha512-armv8.pl $(src)/sha512-core.S_shipped: $(src)/sha512-armv8.pl $(call cmd,perlasm) +endif .PRECIOUS: $(obj)/sha256-core.S $(obj)/sha512-core.S -- GitLab From 62532640c8e15b25250889a18512fdeffd0bab33 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Mon, 19 Feb 2018 23:48:12 -0800 Subject: [PATCH 0077/1635] crypto: x86/cast5-avx - fix ECB encryption when long sg follows short one commit 8f461b1e02ed546fbd0f11611138da67fd85a30f upstream. With ecb-cast5-avx, if a 128+ byte scatterlist element followed a shorter one, then the algorithm accidentally encrypted/decrypted only 8 bytes instead of the expected 128 bytes. Fix it by setting the encryption/decryption 'fn' correctly. Fixes: c12ab20b162c ("crypto: cast5/avx - avoid using temporary stack buffers") Cc: # v3.8+ Signed-off-by: Eric Biggers Signed-off-by: Herbert Xu Signed-off-by: Greg Kroah-Hartman --- arch/x86/crypto/cast5_avx_glue.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/arch/x86/crypto/cast5_avx_glue.c b/arch/x86/crypto/cast5_avx_glue.c index dbea6020ffe7..575292a33bdf 100644 --- a/arch/x86/crypto/cast5_avx_glue.c +++ b/arch/x86/crypto/cast5_avx_glue.c @@ -66,8 +66,6 @@ static int ecb_crypt(struct blkcipher_desc *desc, struct blkcipher_walk *walk, void (*fn)(struct cast5_ctx *ctx, u8 *dst, const u8 *src); int err; - fn = (enc) ? cast5_ecb_enc_16way : cast5_ecb_dec_16way; - err = blkcipher_walk_virt(desc, walk); desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP; @@ -79,6 +77,7 @@ static int ecb_crypt(struct blkcipher_desc *desc, struct blkcipher_walk *walk, /* Process multi-block batch */ if (nbytes >= bsize * CAST5_PARALLEL_BLOCKS) { + fn = (enc) ? cast5_ecb_enc_16way : cast5_ecb_dec_16way; do { fn(ctx, wdst, wsrc); -- GitLab From 4be89529c013f22f95ea43b59a34cfc643432826 Mon Sep 17 00:00:00 2001 From: Liu Bo Date: Wed, 31 Jan 2018 17:09:13 -0700 Subject: [PATCH 0078/1635] Btrfs: fix unexpected cow in run_delalloc_nocow commit 5811375325420052fcadd944792a416a43072b7f upstream. Fstests generic/475 provides a way to fail metadata reads while checking if checksum exists for the inode inside run_delalloc_nocow(), and csum_exist_in_range() interprets error (-EIO) as inode having checksum and makes its caller enter the cow path. In case of free space inode, this ends up with a warning in cow_file_range(). The same problem applies to btrfs_cross_ref_exist() since it may also read metadata in between. With this, run_delalloc_nocow() bails out when errors occur at the two places. cc: v2.6.28+ Fixes: 17d217fe970d ("Btrfs: fix nodatasum handling in balancing code") Signed-off-by: Liu Bo Signed-off-by: David Sterba Signed-off-by: Greg Kroah-Hartman --- fs/btrfs/inode.c | 37 ++++++++++++++++++++++++++++++++----- 1 file changed, 32 insertions(+), 5 deletions(-) diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 59a01a0844c9..dfa360d18ae2 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -1257,6 +1257,8 @@ static noinline int csum_exist_in_range(struct btrfs_fs_info *fs_info, list_del(&sums->list); kfree(sums); } + if (ret < 0) + return ret; return 1; } @@ -1389,10 +1391,23 @@ static noinline int run_delalloc_nocow(struct inode *inode, goto out_check; if (btrfs_extent_readonly(fs_info, disk_bytenr)) goto out_check; - if (btrfs_cross_ref_exist(root, ino, - found_key.offset - - extent_offset, disk_bytenr)) + ret = btrfs_cross_ref_exist(root, ino, + found_key.offset - + extent_offset, disk_bytenr); + if (ret) { + /* + * ret could be -EIO if the above fails to read + * metadata. + */ + if (ret < 0) { + if (cow_start != (u64)-1) + cur_offset = cow_start; + goto error; + } + + WARN_ON_ONCE(nolock); goto out_check; + } disk_bytenr += extent_offset; disk_bytenr += cur_offset - found_key.offset; num_bytes = min(end + 1, extent_end) - cur_offset; @@ -1410,10 +1425,22 @@ static noinline int run_delalloc_nocow(struct inode *inode, * this ensure that csum for a given extent are * either valid or do not exist. */ - if (csum_exist_in_range(fs_info, disk_bytenr, - num_bytes)) { + ret = csum_exist_in_range(fs_info, disk_bytenr, + num_bytes); + if (ret) { if (!nolock) btrfs_end_write_no_snapshotting(root); + + /* + * ret could be -EIO if the above fails to read + * metadata. + */ + if (ret < 0) { + if (cow_start != (u64)-1) + cur_offset = cow_start; + goto error; + } + WARN_ON_ONCE(nolock); goto out_check; } if (!btrfs_inc_nocow_writers(fs_info, disk_bytenr)) { -- GitLab From a59779368b33874df5857603e8863801296c3a7f Mon Sep 17 00:00:00 2001 From: Frank Mori Hess Date: Thu, 15 Mar 2018 10:25:44 +0000 Subject: [PATCH 0079/1635] staging: comedi: ni_mio_common: ack ai fifo error interrupts. commit e1d9fc04c41840a4688ef6ce90b6dcca157ea4d7 upstream. Ack ai fifo error interrupts in interrupt handler to clear interrupt after fifo overflow. It should prevent lock-ups after the ai fifo overflows. Cc: # v4.2+ Signed-off-by: Frank Mori Hess Signed-off-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman --- drivers/staging/comedi/drivers/ni_mio_common.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/staging/comedi/drivers/ni_mio_common.c b/drivers/staging/comedi/drivers/ni_mio_common.c index 398347fedc47..2cac160993bb 100644 --- a/drivers/staging/comedi/drivers/ni_mio_common.c +++ b/drivers/staging/comedi/drivers/ni_mio_common.c @@ -1284,6 +1284,8 @@ static void ack_a_interrupt(struct comedi_device *dev, unsigned short a_status) ack |= NISTC_INTA_ACK_AI_START; if (a_status & NISTC_AI_STATUS1_STOP) ack |= NISTC_INTA_ACK_AI_STOP; + if (a_status & NISTC_AI_STATUS1_OVER) + ack |= NISTC_INTA_ACK_AI_ERR; if (ack) ni_stc_writew(dev, ack, NISTC_INTA_ACK_REG); } -- GitLab From 0d3f8c0217f98d20665c7d1718a4a000158c8878 Mon Sep 17 00:00:00 2001 From: Gaku Inami Date: Tue, 13 Feb 2018 11:06:40 +0900 Subject: [PATCH 0080/1635] Revert "base: arch_topology: fix section mismatch build warnings" commit 9de9a449482677a75f1edd2049268a7efc40fc96 upstream. This reverts commit 452562abb5b7 ("base: arch_topology: fix section mismatch build warnings"). It causes the notifier call hangs in some use-cases. In some cases with using maxcpus, some of cpus are booted first and then the remaining cpus are booted. As an example, some users who want to realize fast boot up often use the following procedure. 1) Define all CPUs on device tree (CA57x4 + CA53x4) 2) Add "maxcpus=4" in bootargs 3) Kernel boot up with CA57x4 4) After kernel boot up, CA53x4 is booted from user When kernel init was finished, CPUFREQ_POLICY_NOTIFIER was not still unregisterd. This means that "__init init_cpu_capacity_callback()" will be called after kernel init sequence. To avoid this problem, it needs to remove __init{,data} annotations by reverting this commit. Also, this commit was needed to fix kernel compile issue below. However, this issue was also fixed by another patch: commit 82d8ba717ccb ("arch_topology: Fix section miss match warning due to free_raw_capacity()") in v4.15 as well. Whereas commit 452562abb5b7 added all the missing __init annotations, commit 82d8ba717ccb removed it from free_raw_capacity(). WARNING: vmlinux.o(.text+0x548f24): Section mismatch in reference from the function init_cpu_capacity_callback() to the variable .init.text:$x The function init_cpu_capacity_callback() references the variable __init $x. This is often because init_cpu_capacity_callback lacks a __init annotation or the annotation of $x is wrong. Fixes: 82d8ba717ccb ("arch_topology: Fix section miss match warning due to free_raw_capacity()") Cc: stable Signed-off-by: Gaku Inami Reviewed-by: Dietmar Eggemann Tested-by: Dietmar Eggemann Acked-by: Sudeep Holla Signed-off-by: Greg Kroah-Hartman --- drivers/base/arch_topology.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/base/arch_topology.c b/drivers/base/arch_topology.c index 6df7d6676a48..41be9ff7d70a 100644 --- a/drivers/base/arch_topology.c +++ b/drivers/base/arch_topology.c @@ -166,11 +166,11 @@ bool __init topology_parse_cpu_capacity(struct device_node *cpu_node, int cpu) } #ifdef CONFIG_CPU_FREQ -static cpumask_var_t cpus_to_visit __initdata; -static void __init parsing_done_workfn(struct work_struct *work); -static __initdata DECLARE_WORK(parsing_done_work, parsing_done_workfn); +static cpumask_var_t cpus_to_visit; +static void parsing_done_workfn(struct work_struct *work); +static DECLARE_WORK(parsing_done_work, parsing_done_workfn); -static int __init +static int init_cpu_capacity_callback(struct notifier_block *nb, unsigned long val, void *data) @@ -206,7 +206,7 @@ init_cpu_capacity_callback(struct notifier_block *nb, return 0; } -static struct notifier_block init_cpu_capacity_notifier __initdata = { +static struct notifier_block init_cpu_capacity_notifier = { .notifier_call = init_cpu_capacity_callback, }; @@ -232,7 +232,7 @@ static int __init register_cpufreq_notifier(void) } core_initcall(register_cpufreq_notifier); -static void __init parsing_done_workfn(struct work_struct *work) +static void parsing_done_workfn(struct work_struct *work) { cpufreq_unregister_notifier(&init_cpu_capacity_notifier, CPUFREQ_POLICY_NOTIFIER); -- GitLab From ac72f0080c1a6bf28b21ca1b43093d61acd14a57 Mon Sep 17 00:00:00 2001 From: Masaki Ota Date: Mon, 29 Jan 2018 14:36:54 -0800 Subject: [PATCH 0081/1635] Input: ALPS - fix TrackStick detection on Thinkpad L570 and Latitude 7370 commit 567b9b549cfa1cbc202762ae97b5385c29ade1e3 upstream. The primary interface for the touchpad device in Thinkpad L570 is SMBus, so ALPS overlooked PS2 interface Firmware setting of TrackStick, and shipped with TrackStick otp bit is disabled. The address 0xD7 contains device number information, so we can identify the device by checking this value, but to access it we need to enable Command mode, and then re-enable the device. Devices shipped in Thinkpad L570 report either 0x0C or 0x1D as device numbers, if we see them we assume that the devices are DualPoints. The same issue exists on Dell Latitude 7370. Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=196929 Fixes: 646580f793 ("Input: ALPS - fix multi-touch decoding on SS4 plus touchpads") Signed-off-by: Masaki Ota Tested-by: Aaron Ma Tested-by: Jonathan Liu Tested-by: Jaak Ristioja Cc: stable@vger.kernel.org Signed-off-by: Dmitry Torokhov Signed-off-by: Greg Kroah-Hartman --- drivers/input/mouse/alps.c | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c index 3d9c294e84db..9a234da8cac2 100644 --- a/drivers/input/mouse/alps.c +++ b/drivers/input/mouse/alps.c @@ -2544,13 +2544,31 @@ static int alps_update_btn_info_ss4_v2(unsigned char otp[][4], } static int alps_update_dual_info_ss4_v2(unsigned char otp[][4], - struct alps_data *priv) + struct alps_data *priv, + struct psmouse *psmouse) { bool is_dual = false; + int reg_val = 0; + struct ps2dev *ps2dev = &psmouse->ps2dev; - if (IS_SS4PLUS_DEV(priv->dev_id)) + if (IS_SS4PLUS_DEV(priv->dev_id)) { is_dual = (otp[0][0] >> 4) & 0x01; + if (!is_dual) { + /* For support TrackStick of Thinkpad L/E series */ + if (alps_exit_command_mode(psmouse) == 0 && + alps_enter_command_mode(psmouse) == 0) { + reg_val = alps_command_mode_read_reg(psmouse, + 0xD7); + } + alps_exit_command_mode(psmouse); + ps2_command(ps2dev, NULL, PSMOUSE_CMD_ENABLE); + + if (reg_val == 0x0C || reg_val == 0x1D) + is_dual = true; + } + } + if (is_dual) priv->flags |= ALPS_DUALPOINT | ALPS_DUALPOINT_WITH_PRESSURE; @@ -2573,7 +2591,7 @@ static int alps_set_defaults_ss4_v2(struct psmouse *psmouse, alps_update_btn_info_ss4_v2(otp, priv); - alps_update_dual_info_ss4_v2(otp, priv); + alps_update_dual_info_ss4_v2(otp, priv, psmouse); return 0; } -- GitLab From 4043155add4041cc1da285c8cbaafe8f9a23098a Mon Sep 17 00:00:00 2001 From: Dennis Wassenberg Date: Thu, 8 Mar 2018 15:32:09 -0800 Subject: [PATCH 0082/1635] Input: i8042 - add Lenovo ThinkPad L460 to i8042 reset list commit b56af54ac78c54a519d82813836f305d7f76ef27 upstream. Reset i8042 before probing because of insufficient BIOS initialisation of the i8042 serial controller. This makes Synaptics touchpad detection possible. Without resetting the Synaptics touchpad is not detected because there are always NACK messages from AUX port. Signed-off-by: Dennis Wassenberg Cc: stable@vger.kernel.org Signed-off-by: Dmitry Torokhov Signed-off-by: Greg Kroah-Hartman --- drivers/input/serio/i8042-x86ia64io.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/input/serio/i8042-x86ia64io.h b/drivers/input/serio/i8042-x86ia64io.h index 6cbbdc6e9687..6ca00f9ef224 100644 --- a/drivers/input/serio/i8042-x86ia64io.h +++ b/drivers/input/serio/i8042-x86ia64io.h @@ -620,6 +620,13 @@ static const struct dmi_system_id __initconst i8042_dmi_reset_table[] = { DMI_MATCH(DMI_PRODUCT_NAME, "20046"), }, }, + { + /* Lenovo ThinkPad L460 */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad L460"), + }, + }, { /* Clevo P650RS, 650RP6, Sager NP8152-S, and others */ .matches = { -- GitLab From 8ac678a4b36318603d7e2991ce8694b3ba976608 Mon Sep 17 00:00:00 2001 From: Ondrej Zary Date: Tue, 3 Apr 2018 10:24:34 -0700 Subject: [PATCH 0083/1635] Input: i8042 - enable MUX on Sony VAIO VGN-CS series to fix touchpad commit 04bb1719c4de94700056241d4c0fe3c1413f5aff upstream. The touch sensor buttons on Sony VAIO VGN-CS series laptops (e.g. VGN-CS31S) are a separate PS/2 device. As the MUX is disabled for all VAIO machines by the nomux blacklist, the data from touch sensor buttons and touchpad are combined. The protocol used by the buttons is probably similar to the touchpad protocol (both are Synaptics) so both devices get enabled. The controller combines the data, creating a mess which results in random button clicks, touchpad stopping working and lost sync error messages: psmouse serio1: TouchPad at isa0060/serio1/input0 lost sync at byte 4 psmouse serio1: TouchPad at isa0060/serio1/input0 lost sync at byte 1 psmouse serio1: TouchPad at isa0060/serio1/input0 lost sync at byte 1 psmouse serio1: TouchPad at isa0060/serio1/input0 lost sync at byte 1 psmouse serio1: TouchPad at isa0060/serio1/input0 lost sync at byte 1 psmouse serio1: issuing reconnect request Add a new i8042_dmi_forcemux_table whitelist with VGN-CS. With MUX enabled, touch sensor buttons are detected as separate device (and left disabled as there's currently no driver), fixing all touchpad problems. Signed-off-by: Ondrej Zary Cc: stable@vger.kernel.org Signed-off-by: Dmitry Torokhov Signed-off-by: Greg Kroah-Hartman --- drivers/input/serio/i8042-x86ia64io.h | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/drivers/input/serio/i8042-x86ia64io.h b/drivers/input/serio/i8042-x86ia64io.h index 6ca00f9ef224..b353d494ad40 100644 --- a/drivers/input/serio/i8042-x86ia64io.h +++ b/drivers/input/serio/i8042-x86ia64io.h @@ -530,6 +530,20 @@ static const struct dmi_system_id __initconst i8042_dmi_nomux_table[] = { { } }; +static const struct dmi_system_id i8042_dmi_forcemux_table[] __initconst = { + { + /* + * Sony Vaio VGN-CS series require MUX or the touch sensor + * buttons will disturb touchpad operation + */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), + DMI_MATCH(DMI_PRODUCT_NAME, "VGN-CS"), + }, + }, + { } +}; + /* * On some Asus laptops, just running self tests cause problems. */ @@ -1170,6 +1184,9 @@ static int __init i8042_platform_init(void) if (dmi_check_system(i8042_dmi_nomux_table)) i8042_nomux = true; + if (dmi_check_system(i8042_dmi_forcemux_table)) + i8042_nomux = false; + if (dmi_check_system(i8042_dmi_notimeout_table)) i8042_notimeout = true; -- GitLab From 52dcf4a6afbc490e35a9fa43e985f71eaa382fd1 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Mon, 29 Jan 2018 17:08:21 -0500 Subject: [PATCH 0084/1635] vt: change SGR 21 to follow the standards commit 65d9982d7e523a1a8e7c9af012da0d166f72fc56 upstream. ECMA-48 [1] (aka ISO 6429) has defined SGR 21 as "doubly underlined" since at least March 1984. The Linux kernel has treated it as SGR 22 "normal intensity" since it was added in Linux-0.96b in June 1992. Before that, it was simply ignored. Other terminal emulators have either ignored it, or treat it as double underline now. xterm for example added support in its 304 release (May 2014) [2] where it was previously ignoring it. Changing this behavior shouldn't be an issue: - It isn't a named capability in ncurses's terminfo database, so no script is using libtinfo/libcurses to look this up, or using tput to query & output the right sequence. - Any script assuming SGR 21 will reset intensity in all terminals already do not work correctly on non-Linux VTs (including running under screen/tmux/etc...). - If someone has written a script that only runs in the Linux VT, and they're using SGR 21 (instead of SGR 22), the output should still be readable. imo it's important to change this as the Linux VT's non-conformance is sometimes used as an argument for other terminal emulators to not implement SGR 21 at all, or do so incorrectly. [1]: https://www.ecma-international.org/publications/standards/Ecma-048.htm [2]: https://github.com/ThomasDickey/xterm-snapshots/commit/2fd29cb98d214cb536bcafbee00bc73b3f1eeb9d Signed-off-by: Mike Frysinger Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/vt.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index 5a5813d01cf8..de67abbda921 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -1352,6 +1352,11 @@ static void csi_m(struct vc_data *vc) case 3: vc->vc_italic = 1; break; + case 21: + /* + * No console drivers support double underline, so + * convert it to a single underline. + */ case 4: vc->vc_underline = 1; break; @@ -1387,7 +1392,6 @@ static void csi_m(struct vc_data *vc) vc->vc_disp_ctrl = 1; vc->vc_toggle_meta = 1; break; - case 21: case 22: vc->vc_intensity = 1; break; -- GitLab From 9b47e99ac970c56078775ce9ace0cd2b673f10e8 Mon Sep 17 00:00:00 2001 From: Keerthy Date: Tue, 24 Oct 2017 14:14:08 +0530 Subject: [PATCH 0085/1635] ARM: dts: DRA76-EVM: Set powerhold property for tps65917 commit aac4619d028e2c444ac1217fc2d05b0322079dff upstream. Set powerhold property for tps65917 Signed-off-by: Keerthy Signed-off-by: Tony Lindgren Cc: Ben Hutchings Signed-off-by: Greg Kroah-Hartman --- arch/arm/boot/dts/dra76-evm.dts | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/boot/dts/dra76-evm.dts b/arch/arm/boot/dts/dra76-evm.dts index b024a65c6e27..f64aab450315 100644 --- a/arch/arm/boot/dts/dra76-evm.dts +++ b/arch/arm/boot/dts/dra76-evm.dts @@ -148,6 +148,7 @@ compatible = "ti,tps65917"; reg = <0x58>; ti,system-power-controller; + ti,palmas-override-powerhold; interrupt-controller; #interrupt-cells = <2>; -- GitLab From b31397c9b945218f13c3cd9c64a4261830c4781a Mon Sep 17 00:00:00 2001 From: Matthias Brugger Date: Thu, 15 Mar 2018 17:54:20 +0100 Subject: [PATCH 0086/1635] net: hns: Fix ethtool private flags commit d61d263c8d82db7c4404a29ebc29674b1c0c05c9 upstream. The driver implementation returns support for private flags, while no private flags are present. When asked for the number of private flags it returns the number of statistic flag names. Fix this by returning EOPNOTSUPP for not implemented ethtool flags. Signed-off-by: Matthias Brugger Signed-off-by: David S. Miller Cc: Ben Hutchings Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/hisilicon/hns/hns_dsaf_gmac.c | 2 +- drivers/net/ethernet/hisilicon/hns/hns_dsaf_ppe.c | 2 +- drivers/net/ethernet/hisilicon/hns/hns_dsaf_rcb.c | 2 +- drivers/net/ethernet/hisilicon/hns/hns_ethtool.c | 4 +++- 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_gmac.c b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_gmac.c index 86944bc3b273..74bd260ca02a 100644 --- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_gmac.c +++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_gmac.c @@ -666,7 +666,7 @@ static void hns_gmac_get_strings(u32 stringset, u8 *data) static int hns_gmac_get_sset_count(int stringset) { - if (stringset == ETH_SS_STATS || stringset == ETH_SS_PRIV_FLAGS) + if (stringset == ETH_SS_STATS) return ARRAY_SIZE(g_gmac_stats_string); return 0; diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_ppe.c b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_ppe.c index b62816c1574e..93e71e27401b 100644 --- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_ppe.c +++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_ppe.c @@ -422,7 +422,7 @@ void hns_ppe_update_stats(struct hns_ppe_cb *ppe_cb) int hns_ppe_get_sset_count(int stringset) { - if (stringset == ETH_SS_STATS || stringset == ETH_SS_PRIV_FLAGS) + if (stringset == ETH_SS_STATS) return ETH_PPE_STATIC_NUM; return 0; } diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_rcb.c b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_rcb.c index 6f3570cfb501..e2e28532e4dc 100644 --- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_rcb.c +++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_rcb.c @@ -876,7 +876,7 @@ void hns_rcb_get_stats(struct hnae_queue *queue, u64 *data) */ int hns_rcb_get_ring_sset_count(int stringset) { - if (stringset == ETH_SS_STATS || stringset == ETH_SS_PRIV_FLAGS) + if (stringset == ETH_SS_STATS) return HNS_RING_STATIC_REG_NUM; return 0; diff --git a/drivers/net/ethernet/hisilicon/hns/hns_ethtool.c b/drivers/net/ethernet/hisilicon/hns/hns_ethtool.c index 7ea7f8a4aa2a..2e14a3ae1d8b 100644 --- a/drivers/net/ethernet/hisilicon/hns/hns_ethtool.c +++ b/drivers/net/ethernet/hisilicon/hns/hns_ethtool.c @@ -993,8 +993,10 @@ int hns_get_sset_count(struct net_device *netdev, int stringset) cnt--; return cnt; - } else { + } else if (stringset == ETH_SS_STATS) { return (HNS_NET_STATS_CNT + ops->get_sset_count(h, stringset)); + } else { + return -EOPNOTSUPP; } } -- GitLab From 92e3d3f67d79207b24105edaa12fef32740ef1e6 Mon Sep 17 00:00:00 2001 From: Mikulas Patocka Date: Wed, 21 Mar 2018 12:49:29 -0400 Subject: [PATCH 0087/1635] Fix slab name "biovec-(1<<(21-12))" commit bd5c4facf59648581d2f1692dad7b107bf429954 upstream. I'm getting a slab named "biovec-(1<<(21-12))". It is caused by unintended expansion of the macro BIO_MAX_PAGES. This patch renames it to biovec-max. Signed-off-by: Mikulas Patocka Cc: stable@vger.kernel.org # v4.14+ Signed-off-by: Jens Axboe Signed-off-by: Greg Kroah-Hartman --- block/bio.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/block/bio.c b/block/bio.c index 7f978eac9a7a..dbaa82c967f4 100644 --- a/block/bio.c +++ b/block/bio.c @@ -43,9 +43,9 @@ * break badly! cannot be bigger than what you can fit into an * unsigned short */ -#define BV(x) { .nr_vecs = x, .name = "biovec-"__stringify(x) } +#define BV(x, n) { .nr_vecs = x, .name = "biovec-"#n } static struct biovec_slab bvec_slabs[BVEC_POOL_NR] __read_mostly = { - BV(1), BV(4), BV(16), BV(64), BV(128), BV(BIO_MAX_PAGES), + BV(1, 1), BV(4, 4), BV(16, 16), BV(64, 64), BV(128, 128), BV(BIO_MAX_PAGES, max), }; #undef BV -- GitLab From 118118eb3818229812f083918584f6c16cc961bf Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Fri, 6 Apr 2018 08:48:11 +0200 Subject: [PATCH 0088/1635] Revert "ARM: dts: am335x-pepper: Fix the audio CODEC's reset pin" This reverts commit 0ed43f944a4070d04eddacded8629d0ddb9c8003 which was comit e153db03c6b7a035c797bcdf35262586f003ee93 upstream. It requires a driver that was not merged until 4.16, so remove it from this stable tree as it is pointless. Reported-by: Ben Hutchings Cc: Andrew F. Davis Cc: Tony Lindgren Cc: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/arm/boot/dts/am335x-pepper.dts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/am335x-pepper.dts b/arch/arm/boot/dts/am335x-pepper.dts index 9fb7426070ce..03c7d77023c6 100644 --- a/arch/arm/boot/dts/am335x-pepper.dts +++ b/arch/arm/boot/dts/am335x-pepper.dts @@ -139,7 +139,7 @@ &audio_codec { status = "okay"; - reset-gpios = <&gpio1 16 GPIO_ACTIVE_LOW>; + gpio-reset = <&gpio1 16 GPIO_ACTIVE_LOW>; AVDD-supply = <&ldo3_reg>; IOVDD-supply = <&ldo3_reg>; DRVDD-supply = <&ldo3_reg>; -- GitLab From a99aaeccdefdeed566861b867f43cdd18573ad29 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Fri, 6 Apr 2018 08:56:07 +0200 Subject: [PATCH 0089/1635] Revert "ARM: dts: omap3-n900: Fix the audio CODEC's reset pin" This reverts commit 2f1f60c4b903f0f5464560783655ff74c9663a92 which was commit 7be4b5dc7ffa9499ac6ef33a5ffa9ff43f9b7057 upstream. It requires a driver that was not merged until 4.16, so remove it from this stable tree as it is pointless. Reported-by: Ben Hutchings Cc: Andrew F. Davis Cc: Tony Lindgren Cc: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/arm/boot/dts/omap3-n900.dts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/boot/dts/omap3-n900.dts b/arch/arm/boot/dts/omap3-n900.dts index c66ee8432a85..4acd32a1c4ef 100644 --- a/arch/arm/boot/dts/omap3-n900.dts +++ b/arch/arm/boot/dts/omap3-n900.dts @@ -558,7 +558,7 @@ tlv320aic3x: tlv320aic3x@18 { compatible = "ti,tlv320aic3x"; reg = <0x18>; - reset-gpios = <&gpio2 28 GPIO_ACTIVE_LOW>; /* 60 */ + gpio-reset = <&gpio2 28 GPIO_ACTIVE_HIGH>; /* 60 */ ai3x-gpio-func = < 0 /* AIC3X_GPIO1_FUNC_DISABLED */ 5 /* AIC3X_GPIO2_FUNC_DIGITAL_MIC_INPUT */ @@ -575,7 +575,7 @@ tlv320aic3x_aux: tlv320aic3x@19 { compatible = "ti,tlv320aic3x"; reg = <0x19>; - reset-gpios = <&gpio2 28 GPIO_ACTIVE_LOW>; /* 60 */ + gpio-reset = <&gpio2 28 GPIO_ACTIVE_HIGH>; /* 60 */ AVDD-supply = <&vmmc2>; DRVDD-supply = <&vmmc2>; -- GitLab From cfbed9b55636334f19059660b197fdffd40b8865 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Fri, 6 Apr 2018 09:06:23 +0200 Subject: [PATCH 0090/1635] Revert "cpufreq: Fix governor module removal race" This reverts commit 0049457bfde661cf47410eaacad65845c9a2bb45 which was commit a8b149d32b663c1a4105273295184b78f53d33cf upstream. The backport was not correct, so just drop it entirely. Reported-by: Ben Hutchings Cc: Rafael J. Wysocki Cc: Viresh Kumar Cc: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/cpufreq/cpufreq.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index bb1e148ebfd4..ea43b147a7fe 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -631,8 +631,6 @@ static int cpufreq_parse_governor(char *str_governor, unsigned int *policy, *governor = t; err = 0; } - if (t && !try_module_get(t->owner)) - t = NULL; mutex_unlock(&cpufreq_governor_mutex); } @@ -761,10 +759,6 @@ static ssize_t store_scaling_governor(struct cpufreq_policy *policy, return -EINVAL; ret = cpufreq_set_policy(policy, &new_policy); - - if (new_policy.governor) - module_put(new_policy.governor->owner); - return ret ? ret : count; } -- GitLab From 6bc3a54e06c66509a4e1fa4d2c8e0d5372b8a74e Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Fri, 6 Apr 2018 09:45:56 +0200 Subject: [PATCH 0091/1635] Revert "ip6_vti: adjust vti mtu according to mtu of lower device" This reverts commit e6cfc525163ea3375113a9dcc234c2cdd8dbf643 which is commit 53c81e95df1793933f87748d36070a721f6cb287 upstream. Ben writes that there are a number of follow-on patches needed to fix this up, but they get complex to backport, and some custom fixes are needed, so let's just revert this and wait for a "real" set of patches to resolve this to be submitted if it is really needed. Reported-by: Ben Hutchings Cc: Petr Vorel Cc: Alexey Kodanev Cc: David S. Miller Cc: Stefano Brivio Signed-off-by: Greg Kroah-Hartman --- net/ipv6/ip6_vti.c | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/net/ipv6/ip6_vti.c b/net/ipv6/ip6_vti.c index 413f01be0c9b..bcdc2d557de1 100644 --- a/net/ipv6/ip6_vti.c +++ b/net/ipv6/ip6_vti.c @@ -626,7 +626,6 @@ static void vti6_link_config(struct ip6_tnl *t) { struct net_device *dev = t->dev; struct __ip6_tnl_parm *p = &t->parms; - struct net_device *tdev = NULL; memcpy(dev->dev_addr, &p->laddr, sizeof(struct in6_addr)); memcpy(dev->broadcast, &p->raddr, sizeof(struct in6_addr)); @@ -639,25 +638,6 @@ static void vti6_link_config(struct ip6_tnl *t) dev->flags |= IFF_POINTOPOINT; else dev->flags &= ~IFF_POINTOPOINT; - - if (p->flags & IP6_TNL_F_CAP_XMIT) { - int strict = (ipv6_addr_type(&p->raddr) & - (IPV6_ADDR_MULTICAST | IPV6_ADDR_LINKLOCAL)); - struct rt6_info *rt = rt6_lookup(t->net, - &p->raddr, &p->laddr, - p->link, strict); - - if (rt) - tdev = rt->dst.dev; - ip6_rt_put(rt); - } - - if (!tdev && p->link) - tdev = __dev_get_by_index(t->net, p->link); - - if (tdev) - dev->mtu = max_t(int, tdev->mtu - dev->hard_header_len, - IPV6_MIN_MTU); } /** -- GitLab From b867b7a7e5904064e76eea88396bfcd50428bdb5 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Sun, 8 Apr 2018 14:26:34 +0200 Subject: [PATCH 0092/1635] Linux 4.14.33 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index c4c681b53ff0..00dd6af8eab4 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 VERSION = 4 PATCHLEVEL = 14 -SUBLEVEL = 32 +SUBLEVEL = 33 EXTRAVERSION = NAME = Petit Gorille -- GitLab From af015918bd0892b6d253364cbec71b01351a3e20 Mon Sep 17 00:00:00 2001 From: Tingwei Zhang Date: Fri, 30 Mar 2018 17:30:15 +0800 Subject: [PATCH 0093/1635] coresight: tmc: add scatter-gather support for tmc etr Add support to configure ETR device in scatter-gather mode. In scatter-gather mode trace buffer can be configured to use bigger buffer size without need of bigger contiguous memory. Change-Id: I5d9f37b47c5bdd711161e7482ca3446549709406 Signed-off-by: Tingwei Zhang --- .../hwtracing/coresight/coresight-tmc-etr.c | 484 +++++++++++++++++- drivers/hwtracing/coresight/coresight-tmc.c | 62 ++- drivers/hwtracing/coresight/coresight-tmc.h | 20 + 3 files changed, 532 insertions(+), 34 deletions(-) diff --git a/drivers/hwtracing/coresight/coresight-tmc-etr.c b/drivers/hwtracing/coresight/coresight-tmc-etr.c index 7e6cd8954b8c..a66689535271 100644 --- a/drivers/hwtracing/coresight/coresight-tmc-etr.c +++ b/drivers/hwtracing/coresight/coresight-tmc-etr.c @@ -21,12 +21,408 @@ #include "coresight-priv.h" #include "coresight-tmc.h" +static void tmc_etr_sg_tbl_free(uint32_t *vaddr, uint32_t size, uint32_t ents) +{ + uint32_t i = 0, pte_n = 0, last_pte; + uint32_t *virt_st_tbl, *virt_pte; + void *virt_blk; + phys_addr_t phys_pte; + int total_ents = DIV_ROUND_UP(size, PAGE_SIZE); + int ents_per_blk = PAGE_SIZE/sizeof(uint32_t); + + virt_st_tbl = vaddr; + + while (i < total_ents) { + last_pte = ((i + ents_per_blk) > total_ents) ? + total_ents : (i + ents_per_blk); + while (i < last_pte) { + virt_pte = virt_st_tbl + pte_n; + + /* Do not go beyond number of entries allocated */ + if (i == ents) { + free_page((unsigned long)virt_st_tbl); + return; + } + + phys_pte = TMC_ETR_SG_ENT_TO_BLK(*virt_pte); + virt_blk = phys_to_virt(phys_pte); + + if ((last_pte - i) > 1) { + free_page((unsigned long)virt_blk); + pte_n++; + } else if (last_pte == total_ents) { + free_page((unsigned long)virt_blk); + free_page((unsigned long)virt_st_tbl); + } else { + free_page((unsigned long)virt_st_tbl); + virt_st_tbl = (uint32_t *)virt_blk; + pte_n = 0; + break; + } + i++; + } + } +} + +static void tmc_etr_sg_tbl_flush(uint32_t *vaddr, uint32_t size) +{ + uint32_t i = 0, pte_n = 0, last_pte; + uint32_t *virt_st_tbl, *virt_pte; + void *virt_blk; + phys_addr_t phys_pte; + int total_ents = DIV_ROUND_UP(size, PAGE_SIZE); + int ents_per_blk = PAGE_SIZE/sizeof(uint32_t); + + virt_st_tbl = vaddr; + dmac_flush_range((void *)virt_st_tbl, (void *)virt_st_tbl + PAGE_SIZE); + + while (i < total_ents) { + last_pte = ((i + ents_per_blk) > total_ents) ? + total_ents : (i + ents_per_blk); + while (i < last_pte) { + virt_pte = virt_st_tbl + pte_n; + phys_pte = TMC_ETR_SG_ENT_TO_BLK(*virt_pte); + virt_blk = phys_to_virt(phys_pte); + + dmac_flush_range(virt_blk, virt_blk + PAGE_SIZE); + + if ((last_pte - i) > 1) { + pte_n++; + } else if (last_pte != total_ents) { + virt_st_tbl = (uint32_t *)virt_blk; + pte_n = 0; + break; + } + i++; + } + } +} + +/* + * Scatter gather table layout in memory: + * 1. Table contains 32-bit entries + * 2. Each entry in the table points to 4K block of memory + * 3. Last entry in the table points to next table + * 4. (*) Based on mem_size requested, if there is no need for next level of + * table, last entry in the table points directly to 4K block of memory. + * + * sg_tbl_num=0 + * |---------------|<-- drvdata->vaddr + * | blk_num=0 | + * |---------------| + * | blk_num=1 | + * |---------------| + * | blk_num=2 | + * |---------------| sg_tbl_num=1 + * |(*)Nxt Tbl Addr|------>|---------------| + * |---------------| | blk_num=3 | + * |---------------| + * | blk_num=4 | + * |---------------| + * | blk_num=5 | + * |---------------| sg_tbl_num=2 + * |(*)Nxt Tbl Addr|------>|---------------| + * |---------------| | blk_num=6 | + * |---------------| + * | blk_num=7 | + * |---------------| + * | blk_num=8 | + * |---------------| + * | |End of + * |---------------|----- + * Table + * For simplicity above diagram assumes following: + * a. mem_size = 36KB --> total_ents = 9 + * b. ents_per_blk = 4 + */ + +static int tmc_etr_sg_tbl_alloc(struct tmc_drvdata *drvdata) +{ + int ret; + uint32_t i = 0, last_pte; + uint32_t *virt_pgdir, *virt_st_tbl; + void *virt_pte; + int total_ents = DIV_ROUND_UP(drvdata->size, PAGE_SIZE); + int ents_per_blk = PAGE_SIZE/sizeof(uint32_t); + + virt_pgdir = (uint32_t *)get_zeroed_page(GFP_KERNEL); + if (!virt_pgdir) + return -ENOMEM; + + virt_st_tbl = virt_pgdir; + + while (i < total_ents) { + last_pte = ((i + ents_per_blk) > total_ents) ? + total_ents : (i + ents_per_blk); + while (i < last_pte) { + virt_pte = (void *)get_zeroed_page(GFP_KERNEL); + if (!virt_pte) { + ret = -ENOMEM; + goto err; + } + + if ((last_pte - i) > 1) { + *virt_st_tbl = + TMC_ETR_SG_ENT(virt_to_phys(virt_pte)); + virt_st_tbl++; + } else if (last_pte == total_ents) { + *virt_st_tbl = + TMC_ETR_SG_LST_ENT(virt_to_phys(virt_pte)); + } else { + *virt_st_tbl = + TMC_ETR_SG_NXT_TBL(virt_to_phys(virt_pte)); + virt_st_tbl = (uint32_t *)virt_pte; + break; + } + i++; + } + } + + drvdata->vaddr = virt_pgdir; + drvdata->paddr = virt_to_phys(virt_pgdir); + + /* Flush the dcache before proceeding */ + tmc_etr_sg_tbl_flush((uint32_t *)drvdata->vaddr, drvdata->size); + + dev_dbg(drvdata->dev, "%s: table starts at %#lx, total entries %d\n", + __func__, (unsigned long)drvdata->paddr, total_ents); + + return 0; +err: + tmc_etr_sg_tbl_free(virt_pgdir, drvdata->size, i); + return ret; +} + +/* + * TMC read logic when scatter gather feature is enabled: + * + * sg_tbl_num=0 + * |---------------|<-- drvdata->vaddr + * | blk_num=0 | + * | blk_num_rel=5 | + * |---------------| + * | blk_num=1 | + * | blk_num_rel=6 | + * |---------------| + * | blk_num=2 | + * | blk_num_rel=7 | + * |---------------| sg_tbl_num=1 + * | Next Table |------>|---------------| + * | Addr | | blk_num=3 | + * |---------------| | blk_num_rel=8 | + * |---------------| + * 4k Block Addr | blk_num=4 | + * |--------------| blk_num_rel=0 | + * | |---------------| + * | | blk_num=5 | + * | | blk_num_rel=1 | + * | |---------------| sg_tbl_num=2 + * |---------------| | Next Table |------>|---------------| + * | | | Addr | | blk_num=6 | + * | | |---------------| | blk_num_rel=2 | + * | read_off | |---------------| + * | | | blk_num=7 | + * | | ppos | blk_num_rel=3 | + * |---------------|----- |---------------| + * | | | blk_num=8 | + * | delta_up | | blk_num_rel=4 | + * | | RWP/drvdata->buf |---------------| + * |---------------|----------------- | | + * | | | | |End of + * | | | |---------------|----- + * | | drvdata->delta_bottom Table + * | | | + * |_______________| _|_ + * 4K Block + * + * For simplicity above diagram assumes following: + * a. mem_size = 36KB --> total_ents = 9 + * b. ents_per_blk = 4 + * c. RWP is on 5th block (blk_num = 5); so we have to start reading from RWP + * position + */ + +void tmc_etr_sg_compute_read(struct tmc_drvdata *drvdata, loff_t *ppos, + char **bufpp, size_t *len) +{ + uint32_t i = 0, blk_num_rel = 0, read_len = 0; + uint32_t blk_num, sg_tbl_num, blk_num_loc, read_off; + uint32_t *virt_pte, *virt_st_tbl; + void *virt_blk; + phys_addr_t phys_pte = 0; + int total_ents = DIV_ROUND_UP(drvdata->size, PAGE_SIZE); + int ents_per_blk = PAGE_SIZE/sizeof(uint32_t); + + /* + * Find relative block number from ppos and reading offset + * within block and find actual block number based on relative + * block number + */ + if (drvdata->buf == drvdata->vaddr) { + blk_num = *ppos / PAGE_SIZE; + read_off = *ppos % PAGE_SIZE; + } else { + if (*ppos < drvdata->delta_bottom) { + read_off = PAGE_SIZE - drvdata->delta_bottom; + } else { + blk_num_rel = (*ppos / PAGE_SIZE) + 1; + read_off = (*ppos - drvdata->delta_bottom) % PAGE_SIZE; + } + + blk_num = (drvdata->sg_blk_num + blk_num_rel) % total_ents; + } + + virt_st_tbl = (uint32_t *)drvdata->vaddr; + + /* Compute table index and block entry index within that table */ + if (blk_num && (blk_num == (total_ents - 1)) && + !(blk_num % (ents_per_blk - 1))) { + sg_tbl_num = blk_num / ents_per_blk; + blk_num_loc = ents_per_blk - 1; + } else { + sg_tbl_num = blk_num / (ents_per_blk - 1); + blk_num_loc = blk_num % (ents_per_blk - 1); + } + + for (i = 0; i < sg_tbl_num; i++) { + virt_pte = virt_st_tbl + (ents_per_blk - 1); + phys_pte = TMC_ETR_SG_ENT_TO_BLK(*virt_pte); + virt_st_tbl = (uint32_t *)phys_to_virt(phys_pte); + } + + virt_pte = virt_st_tbl + blk_num_loc; + phys_pte = TMC_ETR_SG_ENT_TO_BLK(*virt_pte); + virt_blk = phys_to_virt(phys_pte); + + *bufpp = virt_blk + read_off; + + if (*len > (PAGE_SIZE - read_off)) + *len = PAGE_SIZE - read_off; + + /* + * When buffer is wrapped around and trying to read last relative + * block (i.e. delta_up), compute len differently + */ + if (blk_num_rel && (blk_num == drvdata->sg_blk_num)) { + read_len = PAGE_SIZE - drvdata->delta_bottom - read_off; + if (*len > read_len) + *len = read_len; + } + + dev_dbg_ratelimited(drvdata->dev, + "%s: read at %p, phys %pa len %zu blk %d, rel blk %d RWP blk %d\n", + __func__, *bufpp, &phys_pte, *len, blk_num, blk_num_rel, + drvdata->sg_blk_num); +} + +static void tmc_etr_sg_mem_reset(uint32_t *vaddr, uint32_t size) +{ + uint32_t i = 0, pte_n = 0, last_pte; + uint32_t *virt_st_tbl, *virt_pte; + void *virt_blk; + phys_addr_t phys_pte; + int total_ents = DIV_ROUND_UP(size, PAGE_SIZE); + int ents_per_blk = PAGE_SIZE/sizeof(uint32_t); + + virt_st_tbl = vaddr; + + while (i < total_ents) { + last_pte = ((i + ents_per_blk) > total_ents) ? + total_ents : (i + ents_per_blk); + while (i < last_pte) { + virt_pte = virt_st_tbl + pte_n; + phys_pte = TMC_ETR_SG_ENT_TO_BLK(*virt_pte); + virt_blk = phys_to_virt(phys_pte); + + if ((last_pte - i) > 1) { + memset(virt_blk, 0, PAGE_SIZE); + pte_n++; + } else if (last_pte == total_ents) { + memset(virt_blk, 0, PAGE_SIZE); + } else { + virt_st_tbl = (uint32_t *)virt_blk; + pte_n = 0; + break; + } + i++; + } + } + + /* Flush the dcache before proceeding */ + tmc_etr_sg_tbl_flush(vaddr, size); +} + +void tmc_etr_sg_rwp_pos(struct tmc_drvdata *drvdata, uint32_t rwp) +{ + uint32_t i = 0, pte_n = 0, last_pte; + uint32_t *virt_st_tbl, *virt_pte; + void *virt_blk; + bool found = false; + phys_addr_t phys_pte; + int total_ents = DIV_ROUND_UP(drvdata->size, PAGE_SIZE); + int ents_per_blk = PAGE_SIZE/sizeof(uint32_t); + + virt_st_tbl = drvdata->vaddr; + + while (i < total_ents) { + last_pte = ((i + ents_per_blk) > total_ents) ? + total_ents : (i + ents_per_blk); + while (i < last_pte) { + virt_pte = virt_st_tbl + pte_n; + phys_pte = TMC_ETR_SG_ENT_TO_BLK(*virt_pte); + + /* + * When the trace buffer is full; RWP could be on any + * 4K block from scatter gather table. Compute below - + * 1. Block number where RWP is currently residing + * 2. RWP position in that 4K block + * 3. Delta offset from current RWP position to end of + * block. + */ + if (phys_pte <= rwp && rwp < (phys_pte + PAGE_SIZE)) { + virt_blk = phys_to_virt(phys_pte); + drvdata->sg_blk_num = i; + drvdata->buf = virt_blk + rwp - phys_pte; + drvdata->delta_bottom = + phys_pte + PAGE_SIZE - rwp; + found = true; + break; + } + + if ((last_pte - i) > 1) { + pte_n++; + } else if (i < (total_ents - 1)) { + virt_blk = phys_to_virt(phys_pte); + virt_st_tbl = (uint32_t *)virt_blk; + pte_n = 0; + break; + } + + i++; + } + if (found) + break; + } +} +EXPORT_SYMBOL(tmc_etr_sg_rwp_pos); + +static void tmc_etr_mem_reset(struct tmc_drvdata *drvdata) +{ + if (drvdata->vaddr) { + if (drvdata->memtype == TMC_ETR_MEM_TYPE_CONTIG) + memset(drvdata->vaddr, 0, drvdata->size); + else + tmc_etr_sg_mem_reset((uint32_t *)drvdata->vaddr, + drvdata->size); + } +} + void tmc_etr_enable_hw(struct tmc_drvdata *drvdata) { u32 axictl, sts; /* Zero out the memory to help with debug */ - memset(drvdata->vaddr, 0, drvdata->size); + tmc_etr_mem_reset(drvdata); CS_UNLOCK(drvdata->base); @@ -37,6 +433,11 @@ void tmc_etr_enable_hw(struct tmc_drvdata *drvdata) writel_relaxed(TMC_MODE_CIRCULAR_BUFFER, drvdata->base + TMC_MODE); axictl = readl_relaxed(drvdata->base + TMC_AXICTL); + if (drvdata->memtype == TMC_ETR_MEM_TYPE_CONTIG) + axictl &= ~TMC_AXICTL_SCT_GAT_MODE; + else + axictl |= TMC_AXICTL_SCT_GAT_MODE; + writel_relaxed(axictl, drvdata->base + TMC_AXICTL); axictl &= ~TMC_AXICTL_CLEAR_MASK; axictl |= (TMC_AXICTL_PROT_CTL_B1 | TMC_AXICTL_WR_BURST_16); axictl |= TMC_AXICTL_AXCACHE_OS; @@ -87,26 +488,41 @@ static void tmc_etr_dump_hw(struct tmc_drvdata *drvdata) rwp = tmc_read_rwp(drvdata); val = readl_relaxed(drvdata->base + TMC_STS); - /* - * Adjust the buffer to point to the beginning of the trace data - * and update the available trace data. - */ - if (val & TMC_STS_FULL) { - drvdata->buf = drvdata->vaddr + rwp - drvdata->paddr; - drvdata->len = drvdata->size; + if (drvdata->memtype == TMC_ETR_MEM_TYPE_CONTIG) { + /* + * Adjust the buffer to point to the beginning of the trace data + * and update the available trace data. + */ + if (val & TMC_STS_FULL) { + drvdata->buf = drvdata->vaddr + rwp - drvdata->paddr; + drvdata->len = drvdata->size; - barrier = barrier_pkt; - temp = (u32 *)drvdata->buf; + barrier = barrier_pkt; + temp = (u32 *)drvdata->buf; - while (*barrier) { - *temp = *barrier; - temp++; - barrier++; - } + while (*barrier) { + *temp = *barrier; + temp++; + barrier++; + } + } else { + drvdata->buf = drvdata->vaddr; + drvdata->len = rwp - drvdata->paddr; + } } else { - drvdata->buf = drvdata->vaddr; - drvdata->len = rwp - drvdata->paddr; + /* + * Reset these variables before computing since we + * rely on their values during tmc read + */ + drvdata->sg_blk_num = 0; + drvdata->delta_bottom = 0; + drvdata->len = drvdata->size; + + if (val & TMC_STS_FULL) + tmc_etr_sg_rwp_pos(drvdata, rwp); + else + drvdata->buf = drvdata->vaddr; } } @@ -131,13 +547,19 @@ static int tmc_etr_alloc_mem(struct tmc_drvdata *drvdata) int ret; if (!drvdata->vaddr) { - drvdata->vaddr = dma_zalloc_coherent(drvdata->dev, - drvdata->size, - &drvdata->paddr, - GFP_KERNEL); - if (!drvdata->vaddr) { - ret = -ENOMEM; - goto err; + if (drvdata->memtype == TMC_ETR_MEM_TYPE_CONTIG) { + drvdata->vaddr = dma_zalloc_coherent(drvdata->dev, + drvdata->size, + &drvdata->paddr, + GFP_KERNEL); + if (!drvdata->vaddr) { + ret = -ENOMEM; + goto err; + } + } else { + ret = tmc_etr_sg_tbl_alloc(drvdata); + if (ret) + goto err; } } /* @@ -154,8 +576,13 @@ static int tmc_etr_alloc_mem(struct tmc_drvdata *drvdata) static void tmc_etr_free_mem(struct tmc_drvdata *drvdata) { if (drvdata->vaddr) { - dma_free_coherent(drvdata->dev, drvdata->size, - drvdata->vaddr, drvdata->paddr); + if (drvdata->memtype == TMC_ETR_MEM_TYPE_CONTIG) + dma_free_coherent(drvdata->dev, drvdata->size, + drvdata->vaddr, drvdata->paddr); + else + tmc_etr_sg_tbl_free((uint32_t *)drvdata->vaddr, + drvdata->size, + DIV_ROUND_UP(drvdata->size, PAGE_SIZE)); drvdata->vaddr = 0; drvdata->paddr = 0; } @@ -393,6 +820,7 @@ static int tmc_enable_etr_sink_sysfs(struct coresight_device *csdev) if (drvdata->size != drvdata->mem_size) { tmc_etr_free_mem(drvdata); drvdata->size = drvdata->mem_size; + drvdata->memtype = drvdata->mem_type; } ret = tmc_etr_alloc_mem(drvdata); @@ -451,7 +879,7 @@ static int tmc_enable_etr_sink_sysfs(struct coresight_device *csdev) /* Free memory outside the spinlock if need be */ if (!used && vaddr) - dma_free_coherent(drvdata->dev, drvdata->size, vaddr, paddr); + tmc_etr_free_mem(drvdata); if (drvdata->out_mode == TMC_ETR_OUT_MODE_MEM) tmc_etr_byte_cntr_start(drvdata->byte_cntr); @@ -660,7 +1088,7 @@ int tmc_read_unprepare_etr(struct tmc_drvdata *drvdata) /* Free allocated memory out side of the spinlock */ if (vaddr) - dma_free_coherent(drvdata->dev, drvdata->size, vaddr, paddr); + tmc_etr_free_mem(drvdata); mutex_unlock(&drvdata->mem_lock); diff --git a/drivers/hwtracing/coresight/coresight-tmc.c b/drivers/hwtracing/coresight/coresight-tmc.c index 4027473dc9f5..54b208b8809a 100644 --- a/drivers/hwtracing/coresight/coresight-tmc.c +++ b/drivers/hwtracing/coresight/coresight-tmc.c @@ -153,12 +153,19 @@ static ssize_t tmc_read(struct file *file, char __user *data, size_t len, len = drvdata->len - *ppos; if (drvdata->config_type == TMC_CONFIG_TYPE_ETR) { - if (bufp == (char *)(drvdata->vaddr + drvdata->size)) - bufp = drvdata->vaddr; - else if (bufp > (char *)(drvdata->vaddr + drvdata->size)) - bufp -= drvdata->size; - if ((bufp + len) > (char *)(drvdata->vaddr + drvdata->size)) - len = (char *)(drvdata->vaddr + drvdata->size) - bufp; + if (drvdata->memtype == TMC_ETR_MEM_TYPE_CONTIG) { + if (bufp == (char *)(drvdata->vaddr + drvdata->size)) + bufp = drvdata->vaddr; + else if (bufp > (char *)(drvdata->vaddr + + drvdata->size)) + bufp -= drvdata->size; + if ((bufp + len) > (char *)(drvdata->vaddr + + drvdata->size)) + len = (char *)(drvdata->vaddr + drvdata->size) - + bufp; + } else { + tmc_etr_sg_compute_read(drvdata, ppos, &bufp, &len); + } } if (copy_to_user(data, bufp, len)) { @@ -422,6 +429,43 @@ static ssize_t available_out_modes_show(struct device *dev, } static DEVICE_ATTR_RO(available_out_modes); +static ssize_t mem_type_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct tmc_drvdata *drvdata = dev_get_drvdata(dev->parent); + + return scnprintf(buf, PAGE_SIZE, "%s\n", + str_tmc_etr_mem_type[drvdata->mem_type]); +} + +static ssize_t mem_type_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t size) +{ + struct tmc_drvdata *drvdata = dev_get_drvdata(dev->parent); + char str[10] = ""; + + if (strlen(buf) >= 10) + return -EINVAL; + if (sscanf(buf, "%10s", str) != 1) + return -EINVAL; + + mutex_lock(&drvdata->mem_lock); + if (!strcmp(str, str_tmc_etr_mem_type[TMC_ETR_MEM_TYPE_CONTIG])) + drvdata->mem_type = TMC_ETR_MEM_TYPE_CONTIG; + else if (!strcmp(str, str_tmc_etr_mem_type[TMC_ETR_MEM_TYPE_SG])) + drvdata->mem_type = TMC_ETR_MEM_TYPE_SG; + else + size = -EINVAL; + + mutex_unlock(&drvdata->mem_lock); + + return size; +} +static DEVICE_ATTR_RW(mem_type); + static ssize_t block_size_show(struct device *dev, struct device_attribute *attr, char *buf) @@ -517,6 +561,7 @@ static struct attribute *coresight_tmc_etf_attrs[] = { static struct attribute *coresight_tmc_etr_attrs[] = { &dev_attr_mem_size.attr, + &dev_attr_mem_type.attr, &dev_attr_trigger_cntr.attr, &dev_attr_out_mode.attr, &dev_attr_available_out_modes.attr, @@ -635,7 +680,12 @@ static int tmc_probe(struct amba_device *adev, const struct amba_id *id) if (ret) drvdata->size = SZ_1M; + if (of_property_read_bool(np, "arm,sg-enable")) + drvdata->memtype = TMC_ETR_MEM_TYPE_SG; + else + drvdata->memtype = TMC_ETR_MEM_TYPE_CONTIG; drvdata->mem_size = drvdata->size; + drvdata->mem_type = drvdata->memtype; drvdata->out_mode = TMC_ETR_OUT_MODE_MEM; } else { drvdata->size = readl_relaxed(drvdata->base + TMC_RSZ) * 4; diff --git a/drivers/hwtracing/coresight/coresight-tmc.h b/drivers/hwtracing/coresight/coresight-tmc.h index 3c4b3b78cb55..b4aa7d69ae87 100644 --- a/drivers/hwtracing/coresight/coresight-tmc.h +++ b/drivers/hwtracing/coresight/coresight-tmc.h @@ -101,6 +101,11 @@ #define TMC_FFCR_TRIGON_TRIGIN BIT(8) #define TMC_FFCR_STOP_ON_FLUSH BIT(12) +#define TMC_ETR_SG_ENT_TO_BLK(phys_pte) (((phys_addr_t)phys_pte >> 4) \ + << PAGE_SHIFT) +#define TMC_ETR_SG_ENT(phys_pte) (((phys_pte >> PAGE_SHIFT) << 4) | 0x2) +#define TMC_ETR_SG_NXT_TBL(phys_pte) (((phys_pte >> PAGE_SHIFT) << 4) | 0x3) +#define TMC_ETR_SG_LST_ENT(phys_pte) (((phys_pte >> PAGE_SHIFT) << 4) | 0x1) #define TMC_DEVID_NOSCAT BIT(24) @@ -147,6 +152,15 @@ enum tmc_mem_intf_width { #define CORESIGHT_SOC_600_ETR_CAPS \ (TMC_ETR_SAVE_RESTORE | TMC_ETR_AXI_ARCACHE) +enum tmc_etr_mem_type { + TMC_ETR_MEM_TYPE_CONTIG, + TMC_ETR_MEM_TYPE_SG, +}; + +static const char * const str_tmc_etr_mem_type[] = { + [TMC_ETR_MEM_TYPE_CONTIG] = "contig", + [TMC_ETR_MEM_TYPE_SG] = "sg", +}; enum tmc_etr_out_mode { TMC_ETR_OUT_MODE_NONE, TMC_ETR_OUT_MODE_MEM, @@ -210,8 +224,11 @@ struct tmc_drvdata { struct mutex mem_lock; u32 mem_size; u32 trigger_cntr; + enum tmc_etr_mem_type mem_type; + enum tmc_etr_mem_type memtype; u32 etr_caps; u32 delta_bottom; + int sg_blk_num; enum tmc_etr_out_mode out_mode; struct usb_qdss_ch *usbch; struct tmc_etr_bam_data *bamdata; @@ -238,6 +255,8 @@ extern const struct coresight_ops tmc_etb_cs_ops; extern const struct coresight_ops tmc_etf_cs_ops; /* ETR functions */ +void tmc_etr_sg_compute_read(struct tmc_drvdata *drvdata, loff_t *ppos, + char **bufpp, size_t *len); int tmc_read_prepare_etr(struct tmc_drvdata *drvdata); int tmc_read_unprepare_etr(struct tmc_drvdata *drvdata); void __tmc_etr_disable_to_bam(struct tmc_drvdata *drvdata); @@ -251,6 +270,7 @@ int tmc_etr_bam_init(struct amba_device *adev, extern struct byte_cntr *byte_cntr_init(struct amba_device *adev, struct tmc_drvdata *drvdata); extern const struct coresight_ops tmc_etr_cs_ops; +extern void tmc_etr_sg_rwp_pos(struct tmc_drvdata *drvdata, uint32_t rwp); #define TMC_REG_PAIR(name, lo_off, hi_off) \ -- GitLab From cff3061206a4cbfcedbf972a454db6d03ca72114 Mon Sep 17 00:00:00 2001 From: Tingwei Zhang Date: Mon, 9 Apr 2018 18:46:44 +0800 Subject: [PATCH 0094/1635] coresight: byte-cntr: Add scatter-gather support for byte-counter Since we add scatter-gather mode in ETR memory type, add scatter-gather mode support for byte-counter function as well. Change-Id: Ibca5113fe09d5de1164a99e891fe0599706954e7 Signed-off-by: Tingwei Zhang --- .../hwtracing/coresight/coresight-byte-cntr.c | 124 ++++++++++++++++-- .../hwtracing/coresight/coresight-tmc-etr.c | 3 +- drivers/hwtracing/coresight/coresight-tmc.h | 1 + 3 files changed, 113 insertions(+), 15 deletions(-) diff --git a/drivers/hwtracing/coresight/coresight-byte-cntr.c b/drivers/hwtracing/coresight/coresight-byte-cntr.c index d36d874435b9..6fb00de35464 100644 --- a/drivers/hwtracing/coresight/coresight-byte-cntr.c +++ b/drivers/hwtracing/coresight/coresight-byte-cntr.c @@ -24,17 +24,94 @@ static struct tmc_drvdata *tmcdrvdata; static void tmc_etr_read_bytes(struct byte_cntr *byte_cntr_data, loff_t *ppos, - size_t bytes, size_t *len) + size_t bytes, size_t *len, char **bufp) { - if (*len >= bytes) { - atomic_dec(&byte_cntr_data->irq_cnt); + + if (*bufp >= (char *)(tmcdrvdata->vaddr + tmcdrvdata->size)) + *bufp = tmcdrvdata->vaddr; + + if (*len >= bytes) *len = bytes; + else if (((uint32_t)*ppos % bytes) + *len > bytes) + *len = bytes - ((uint32_t)*ppos % bytes); + + if ((*bufp + *len) > (char *)(tmcdrvdata->vaddr + + tmcdrvdata->size)) + *len = (char *)(tmcdrvdata->vaddr + tmcdrvdata->size) - + *bufp; + if (*len == bytes || (*len + (uint32_t)*ppos) % bytes == 0) + atomic_dec(&byte_cntr_data->irq_cnt); +} + +static void tmc_etr_sg_read_pos(loff_t *ppos, + size_t bytes, bool noirq, size_t *len, + char **bufpp) +{ + uint32_t rwp, i = 0; + uint32_t blk_num, sg_tbl_num, blk_num_loc, read_off; + uint32_t *virt_pte, *virt_st_tbl; + void *virt_blk; + phys_addr_t phys_pte; + int total_ents = DIV_ROUND_UP(tmcdrvdata->size, PAGE_SIZE); + int ents_per_pg = PAGE_SIZE/sizeof(uint32_t); + + if (*len == 0) + return; + + blk_num = *ppos / PAGE_SIZE; + read_off = *ppos % PAGE_SIZE; + + virt_st_tbl = (uint32_t *)tmcdrvdata->vaddr; + + /* Compute table index and block entry index within that table */ + if (blk_num && (blk_num == (total_ents - 1)) && + !(blk_num % (ents_per_pg - 1))) { + sg_tbl_num = blk_num / ents_per_pg; + blk_num_loc = ents_per_pg - 1; + } else { + sg_tbl_num = blk_num / (ents_per_pg - 1); + blk_num_loc = blk_num % (ents_per_pg - 1); + } + + for (i = 0; i < sg_tbl_num; i++) { + virt_pte = virt_st_tbl + (ents_per_pg - 1); + phys_pte = TMC_ETR_SG_ENT_TO_BLK(*virt_pte); + virt_st_tbl = (uint32_t *)phys_to_virt(phys_pte); + } + + virt_pte = virt_st_tbl + blk_num_loc; + phys_pte = TMC_ETR_SG_ENT_TO_BLK(*virt_pte); + virt_blk = phys_to_virt(phys_pte); + + *bufpp = (char *)(virt_blk + read_off); + + if (noirq) { + rwp = readl_relaxed(tmcdrvdata->base + TMC_RWP); + tmc_etr_sg_rwp_pos(tmcdrvdata, rwp); + if (tmcdrvdata->sg_blk_num == blk_num && + rwp >= (phys_pte + read_off)) + *len = rwp - phys_pte - read_off; + else if (tmcdrvdata->sg_blk_num > blk_num) + *len = PAGE_SIZE - read_off; + else + *len = bytes; } else { - if (((uint32_t)*ppos % bytes) + *len > bytes) + + if (*len > (PAGE_SIZE - read_off)) + *len = PAGE_SIZE - read_off; + + if (*len >= (bytes - ((uint32_t)*ppos % bytes))) *len = bytes - ((uint32_t)*ppos % bytes); - if ((*len + (uint32_t)*ppos) % bytes == 0) - atomic_dec(&byte_cntr_data->irq_cnt); + + if (*len == bytes || (*len + (uint32_t)*ppos) % bytes == 0) + atomic_dec(&tmcdrvdata->byte_cntr->irq_cnt); } + + /* + * Invalidate cache range before reading. This will make sure that CPU + * reads latest contents from DDR + */ + dmac_inv_range((void *)(*bufpp), (void *)(*bufpp) + *len); } static irqreturn_t etr_handler(int irq, void *data) @@ -73,6 +150,8 @@ static ssize_t tmc_etr_byte_cntr_read(struct file *fp, char __user *data, if (!byte_cntr_data->read_active) goto err0; + bufp = (char *)(tmcdrvdata->buf + *ppos); + if (byte_cntr_data->enable) { if (!atomic_read(&byte_cntr_data->irq_cnt)) { mutex_unlock(&byte_cntr_data->byte_cntr_lock); @@ -83,19 +162,38 @@ static ssize_t tmc_etr_byte_cntr_read(struct file *fp, char __user *data, if (!byte_cntr_data->read_active) goto err0; } - bufp = (char *)(tmcdrvdata->vaddr + *ppos); - tmc_etr_read_bytes(byte_cntr_data, ppos, - byte_cntr_data->block_size, &len); + if (tmcdrvdata->mem_type == TMC_ETR_MEM_TYPE_CONTIG) + tmc_etr_read_bytes(byte_cntr_data, ppos, + byte_cntr_data->block_size, &len, + &bufp); + else + tmc_etr_sg_read_pos(ppos, byte_cntr_data->block_size, 0, + &len, &bufp); + } else { if (!atomic_read(&byte_cntr_data->irq_cnt)) { - tmc_etr_flush_bytes(ppos, byte_cntr_data->block_size, - &len); + if (tmcdrvdata->mem_type == TMC_ETR_MEM_TYPE_CONTIG) + tmc_etr_flush_bytes(ppos, + byte_cntr_data->block_size, + &len); + else + tmc_etr_sg_read_pos(ppos, + byte_cntr_data->block_size, + 1, + &len, &bufp); if (!len) goto err0; } else { - tmc_etr_read_bytes(byte_cntr_data, ppos, - byte_cntr_data->block_size, &len); + if (tmcdrvdata->mem_type == TMC_ETR_MEM_TYPE_CONTIG) + tmc_etr_read_bytes(byte_cntr_data, ppos, + byte_cntr_data->block_size, + &len, &bufp); + else + tmc_etr_sg_read_pos(ppos, + byte_cntr_data->block_size, + 1, + &len, &bufp); } } diff --git a/drivers/hwtracing/coresight/coresight-tmc-etr.c b/drivers/hwtracing/coresight/coresight-tmc-etr.c index a66689535271..8e925919e300 100644 --- a/drivers/hwtracing/coresight/coresight-tmc-etr.c +++ b/drivers/hwtracing/coresight/coresight-tmc-etr.c @@ -433,12 +433,11 @@ void tmc_etr_enable_hw(struct tmc_drvdata *drvdata) writel_relaxed(TMC_MODE_CIRCULAR_BUFFER, drvdata->base + TMC_MODE); axictl = readl_relaxed(drvdata->base + TMC_AXICTL); + axictl &= ~TMC_AXICTL_CLEAR_MASK; if (drvdata->memtype == TMC_ETR_MEM_TYPE_CONTIG) axictl &= ~TMC_AXICTL_SCT_GAT_MODE; else axictl |= TMC_AXICTL_SCT_GAT_MODE; - writel_relaxed(axictl, drvdata->base + TMC_AXICTL); - axictl &= ~TMC_AXICTL_CLEAR_MASK; axictl |= (TMC_AXICTL_PROT_CTL_B1 | TMC_AXICTL_WR_BURST_16); axictl |= TMC_AXICTL_AXCACHE_OS; diff --git a/drivers/hwtracing/coresight/coresight-tmc.h b/drivers/hwtracing/coresight/coresight-tmc.h index b4aa7d69ae87..df02b7b46b68 100644 --- a/drivers/hwtracing/coresight/coresight-tmc.h +++ b/drivers/hwtracing/coresight/coresight-tmc.h @@ -272,6 +272,7 @@ extern struct byte_cntr *byte_cntr_init(struct amba_device *adev, extern const struct coresight_ops tmc_etr_cs_ops; extern void tmc_etr_sg_rwp_pos(struct tmc_drvdata *drvdata, uint32_t rwp); +extern const struct coresight_ops tmc_etr_cs_ops; #define TMC_REG_PAIR(name, lo_off, hi_off) \ static inline u64 \ -- GitLab From fc30e9639c750f129d1eb34018f03da5ffc2efb3 Mon Sep 17 00:00:00 2001 From: Liam Mark Date: Mon, 9 Apr 2018 09:14:48 -0700 Subject: [PATCH 0095/1635] iommu: iommu-debug: Fix dma map bounds check Fix so that size of map is taken into account. Change-Id: Id4262525e746b36ef6353c03367ba0c3b187a54c Signed-off-by: Liam Mark --- drivers/iommu/iommu-debug.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/iommu/iommu-debug.c b/drivers/iommu/iommu-debug.c index 9801a6ef7213..1b84e1374eb3 100644 --- a/drivers/iommu/iommu-debug.c +++ b/drivers/iommu/iommu-debug.c @@ -1862,7 +1862,7 @@ static ssize_t iommu_debug_dma_map_write(struct file *file, if (kstrtouint(comma2 + 1, 0, &attr)) goto invalid_format; - if (v_addr < test_virt_addr || v_addr > (test_virt_addr + SZ_1M - 1)) + if (v_addr < test_virt_addr || v_addr + size > test_virt_addr + SZ_1M) goto invalid_addr; if (attr == 0) -- GitLab From bbb636686a3f79f1f39203137290c7c3e658cd31 Mon Sep 17 00:00:00 2001 From: Jeevan Shriram Date: Mon, 9 Apr 2018 10:50:38 -0700 Subject: [PATCH 0096/1635] ARM: dts: msm: Enable PSCI enable method for SDMSHRIKE Enable PSCI enable method for the CPUs for supporting SMP mode on SDMSHRIKE target. Change-Id: Idf10fc8c16d3ecf58f0401820bc6ef1fa8ecade0 Signed-off-by: Jeevan Shriram --- arch/arm64/boot/dts/qcom/sdmshrike.dtsi | 29 +++++++++++-------------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sdmshrike.dtsi b/arch/arm64/boot/dts/qcom/sdmshrike.dtsi index 783876962a41..293bc58fd688 100644 --- a/arch/arm64/boot/dts/qcom/sdmshrike.dtsi +++ b/arch/arm64/boot/dts/qcom/sdmshrike.dtsi @@ -44,8 +44,7 @@ device_type = "cpu"; compatible = "arm,armv8"; reg = <0x0 0x0>; - enable-method = "spin-table"; - cpu-release-addr = <0x0 0x90000000>; + enable-method = "psci"; cache-size = <0x8000>; next-level-cache = <&L2_0>; L2_0: l2-cache { @@ -66,8 +65,7 @@ device_type = "cpu"; compatible = "arm,armv8"; reg = <0x0 0x100>; - enable-method = "spin-table"; - cpu-release-addr = <0x0 0x90000000>; + enable-method = "psci"; cache-size = <0x8000>; next-level-cache = <&L2_1>; L2_1: l2-cache { @@ -82,8 +80,7 @@ device_type = "cpu"; compatible = "arm,armv8"; reg = <0x0 0x200>; - enable-method = "spin-table"; - cpu-release-addr = <0x0 0x90000000>; + enable-method = "psci"; cache-size = <0x8000>; next-level-cache = <&L2_2>; L2_2: l2-cache { @@ -98,8 +95,7 @@ device_type = "cpu"; compatible = "arm,armv8"; reg = <0x0 0x300>; - enable-method = "spin-table"; - cpu-release-addr = <0x0 0x90000000>; + enable-method = "psci"; cache-size = <0x8000>; next-level-cache = <&L2_3>; L2_3: l2-cache { @@ -114,8 +110,7 @@ device_type = "cpu"; compatible = "arm,armv8"; reg = <0x0 0x400>; - enable-method = "spin-table"; - cpu-release-addr = <0x0 0x90000000>; + enable-method = "psci"; cache-size = <0x20000>; next-level-cache = <&L2_4>; L2_4: l2-cache { @@ -130,8 +125,7 @@ device_type = "cpu"; compatible = "arm,armv8"; reg = <0x0 0x500>; - enable-method = "spin-table"; - cpu-release-addr = <0x0 0x90000000>; + enable-method = "psci"; cache-size = <0x20000>; next-level-cache = <&L2_5>; L2_5: l2-cache { @@ -146,8 +140,7 @@ device_type = "cpu"; compatible = "arm,armv8"; reg = <0x0 0x600>; - enable-method = "spin-table"; - cpu-release-addr = <0x0 0x90000000>; + enable-method = "psci"; cache-size = <0x20000>; next-level-cache = <&L2_6>; L2_6: l2-cache { @@ -162,8 +155,7 @@ device_type = "cpu"; compatible = "arm,armv8"; reg = <0x0 0x700>; - enable-method = "spin-table"; - cpu-release-addr = <0x0 0x90000000>; + enable-method = "psci"; cache-size = <0x20000>; next-level-cache = <&L2_7>; L2_7: l2-cache { @@ -211,6 +203,11 @@ }; }; }; + + psci { + compatible = "arm,psci-1.0"; + method = "smc"; + }; }; reserved-memory { -- GitLab From b84aa7d828c7303ce045f779e01a864de65e6bc0 Mon Sep 17 00:00:00 2001 From: Jeevan Shriram Date: Mon, 9 Apr 2018 19:30:51 -0700 Subject: [PATCH 0097/1635] defconfig: sdmshrike: Enable configs required for Android Enable defconfigs required for sdmshrike target to boot into Android. Change-Id: I46aba320f3af3e9ff81e84069e278f1da47c6c9e Signed-off-by: Jeevan Shriram --- arch/arm64/configs/sdmshrike-perf_defconfig | 7 +++++++ arch/arm64/configs/sdmshrike_defconfig | 7 +++++++ 2 files changed, 14 insertions(+) diff --git a/arch/arm64/configs/sdmshrike-perf_defconfig b/arch/arm64/configs/sdmshrike-perf_defconfig index 87438e66ce7d..2302b033c416 100644 --- a/arch/arm64/configs/sdmshrike-perf_defconfig +++ b/arch/arm64/configs/sdmshrike-perf_defconfig @@ -11,6 +11,8 @@ CONFIG_RCU_FAST_NO_HZ=y CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y CONFIG_LOG_CPU_MAX_BUF_SHIFT=17 +CONFIG_MEMCG=y +CONFIG_MEMCG_SWAP=y CONFIG_RT_GROUP_SCHED=y CONFIG_CGROUP_FREEZER=y CONFIG_CGROUP_CPUACCT=y @@ -132,13 +134,16 @@ CONFIG_NETFILTER_XT_MATCH_MARK=y CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y CONFIG_NETFILTER_XT_MATCH_POLICY=y CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y +CONFIG_NETFILTER_XT_MATCH_QTAGUID=y CONFIG_NETFILTER_XT_MATCH_QUOTA=y +CONFIG_NETFILTER_XT_MATCH_SOCKET=y CONFIG_NETFILTER_XT_MATCH_STATE=y CONFIG_NETFILTER_XT_MATCH_STATISTIC=y CONFIG_NETFILTER_XT_MATCH_STRING=y CONFIG_NETFILTER_XT_MATCH_TIME=y CONFIG_NETFILTER_XT_MATCH_U32=y CONFIG_NF_CONNTRACK_IPV4=y +CONFIG_NF_SOCKET_IPV4=y CONFIG_IP_NF_IPTABLES=y CONFIG_IP_NF_MATCH_AH=y CONFIG_IP_NF_MATCH_ECN=y @@ -156,6 +161,7 @@ CONFIG_IP_NF_ARPTABLES=y CONFIG_IP_NF_ARPFILTER=y CONFIG_IP_NF_ARP_MANGLE=y CONFIG_NF_CONNTRACK_IPV6=y +CONFIG_NF_SOCKET_IPV6=y CONFIG_IP6_NF_IPTABLES=y CONFIG_IP6_NF_FILTER=y CONFIG_IP6_NF_TARGET_REJECT=y @@ -388,6 +394,7 @@ CONFIG_TMPFS=y CONFIG_TMPFS_POSIX_ACL=y CONFIG_ECRYPT_FS=y CONFIG_ECRYPT_FS_MESSAGING=y +CONFIG_SDCARD_FS=y CONFIG_NLS_CODEPAGE_437=y CONFIG_NLS_ISO8859_1=y CONFIG_PRINTK_TIME=y diff --git a/arch/arm64/configs/sdmshrike_defconfig b/arch/arm64/configs/sdmshrike_defconfig index fcf4e978e6ed..ff61c2cdd926 100644 --- a/arch/arm64/configs/sdmshrike_defconfig +++ b/arch/arm64/configs/sdmshrike_defconfig @@ -10,6 +10,8 @@ CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y CONFIG_LOG_CPU_MAX_BUF_SHIFT=17 CONFIG_CGROUPS=y +CONFIG_MEMCG=y +CONFIG_MEMCG_SWAP=y CONFIG_CGROUP_SCHED=y CONFIG_RT_GROUP_SCHED=y CONFIG_CGROUP_FREEZER=y @@ -137,13 +139,16 @@ CONFIG_NETFILTER_XT_MATCH_MARK=y CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y CONFIG_NETFILTER_XT_MATCH_POLICY=y CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y +CONFIG_NETFILTER_XT_MATCH_QTAGUID=y CONFIG_NETFILTER_XT_MATCH_QUOTA=y +CONFIG_NETFILTER_XT_MATCH_SOCKET=y CONFIG_NETFILTER_XT_MATCH_STATE=y CONFIG_NETFILTER_XT_MATCH_STATISTIC=y CONFIG_NETFILTER_XT_MATCH_STRING=y CONFIG_NETFILTER_XT_MATCH_TIME=y CONFIG_NETFILTER_XT_MATCH_U32=y CONFIG_NF_CONNTRACK_IPV4=y +CONFIG_NF_SOCKET_IPV4=y CONFIG_IP_NF_IPTABLES=y CONFIG_IP_NF_MATCH_AH=y CONFIG_IP_NF_MATCH_ECN=y @@ -161,6 +166,7 @@ CONFIG_IP_NF_ARPTABLES=y CONFIG_IP_NF_ARPFILTER=y CONFIG_IP_NF_ARP_MANGLE=y CONFIG_NF_CONNTRACK_IPV6=y +CONFIG_NF_SOCKET_IPV6=y CONFIG_IP6_NF_IPTABLES=y CONFIG_IP6_NF_FILTER=y CONFIG_IP6_NF_TARGET_REJECT=y @@ -404,6 +410,7 @@ CONFIG_TMPFS_POSIX_ACL=y CONFIG_EFIVAR_FS=y CONFIG_ECRYPT_FS=y CONFIG_ECRYPT_FS_MESSAGING=y +CONFIG_SDCARD_FS=y # CONFIG_NETWORK_FILESYSTEMS is not set CONFIG_NLS_CODEPAGE_437=y CONFIG_NLS_ISO8859_1=y -- GitLab From 6b68b280c5d81a869b5efd3ad4f1b6e8efd60c27 Mon Sep 17 00:00:00 2001 From: Tharun Kumar Merugu Date: Thu, 5 Apr 2018 11:06:56 +0530 Subject: [PATCH 0098/1635] ARM: dts: msm: use proper iommu SID value and mask for sm8150 Use appropriate iommu SID values and masks for fastrpc context banks. Change-Id: I0d88766e40531ca4d19257bdc2cf71c5e3176a4b Acked-by: Thyagarajan Venkatanarayanan Signed-off-by: Tharun Kumar Merugu Signed-off-by: Ashwini Muduganti --- arch/arm64/boot/dts/qcom/sm8150.dtsi | 60 ++++++++++------------------ 1 file changed, 20 insertions(+), 40 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sm8150.dtsi b/arch/arm64/boot/dts/qcom/sm8150.dtsi index 8e6abaca41ae..c12bc5c953c1 100644 --- a/arch/arm64/boot/dts/qcom/sm8150.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150.dtsi @@ -2068,80 +2068,55 @@ qcom,msm_fastrpc_compute_cb1 { compatible = "qcom,msm-fastrpc-compute-cb"; label = "cdsprpc-smd"; - iommus = <&apps_smmu 0x1401 0x40>, + iommus = <&apps_smmu 0x1401 0x2040>, <&apps_smmu 0x1421 0x0>, - <&apps_smmu 0x2001 0x20>, + <&apps_smmu 0x2001 0x420>, <&apps_smmu 0x2041 0x0>; dma-coherent; }; - qcom,msm_fastrpc_compute_cb2 { - compatible = "qcom,msm-fastrpc-compute-cb"; - label = "cdsprpc-smd"; - iommus = <&apps_smmu 0x1402 0x40>, - <&apps_smmu 0x1422 0x0>, - <&apps_smmu 0x2002 0x20>, - <&apps_smmu 0x2042 0x0>; - dma-coherent; - }; - qcom,msm_fastrpc_compute_cb3 { compatible = "qcom,msm-fastrpc-compute-cb"; label = "cdsprpc-smd"; - iommus = <&apps_smmu 0x1403 0x40>, - <&apps_smmu 0x1423 0x0>, - <&apps_smmu 0x2003 0x20>, - <&apps_smmu 0x2043 0x0>; + iommus = <&apps_smmu 0x3 0x3440>, + <&apps_smmu 0x23 0x3400>; dma-coherent; }; qcom,msm_fastrpc_compute_cb4 { compatible = "qcom,msm-fastrpc-compute-cb"; label = "cdsprpc-smd"; - iommus = <&apps_smmu 0x1404 0x40>, - <&apps_smmu 0x1424 0x0>, - <&apps_smmu 0x2004 0x20>, - <&apps_smmu 0x2044 0x0>; + iommus = <&apps_smmu 0x4 0x3440>, + <&apps_smmu 0x24 0x3400>; dma-coherent; }; qcom,msm_fastrpc_compute_cb5 { compatible = "qcom,msm-fastrpc-compute-cb"; label = "cdsprpc-smd"; - iommus = <&apps_smmu 0x1405 0x40>, - <&apps_smmu 0x1425 0x0>, - <&apps_smmu 0x2005 0x20>, - <&apps_smmu 0x2045 0x0>; + iommus = <&apps_smmu 0x5 0x3440>, + <&apps_smmu 0x25 0x3400>; dma-coherent; }; qcom,msm_fastrpc_compute_cb6 { compatible = "qcom,msm-fastrpc-compute-cb"; label = "cdsprpc-smd"; - iommus = <&apps_smmu 0x1406 0x40>, - <&apps_smmu 0x1426 0x0>, - <&apps_smmu 0x2006 0x20>, - <&apps_smmu 0x2046 0x0>; + iommus = <&apps_smmu 0x6 0x3460>; dma-coherent; }; qcom,msm_fastrpc_compute_cb7 { compatible = "qcom,msm-fastrpc-compute-cb"; label = "cdsprpc-smd"; - iommus = <&apps_smmu 0x1407 0x40>, - <&apps_smmu 0x1427 0x0>, - <&apps_smmu 0x2007 0x20>, - <&apps_smmu 0x2047 0x0>; + iommus = <&apps_smmu 0x7 0x3460>; dma-coherent; }; qcom,msm_fastrpc_compute_cb8 { compatible = "qcom,msm-fastrpc-compute-cb"; label = "cdsprpc-smd"; - iommus = <&apps_smmu 0x1408 0x40>, - <&apps_smmu 0x1428 0x0>, - <&apps_smmu 0x2008 0x20>, - <&apps_smmu 0x2048 0x0>; + iommus = <&apps_smmu 0x8 0x3460>; dma-coherent; }; @@ -2149,10 +2124,15 @@ compatible = "qcom,msm-fastrpc-compute-cb"; label = "cdsprpc-smd"; qcom,secure-context-bank; - iommus = <&apps_smmu 0x1409 0x40>, - <&apps_smmu 0x1429 0x0>, - <&apps_smmu 0x2009 0x20>, - <&apps_smmu 0x2049 0x0>; + iommus = <&apps_smmu 0x9 0x3460>; + dma-coherent; + }; + + qcom,msm_fastrpc_compute_cb2 { + compatible = "qcom,msm-fastrpc-compute-cb"; + label = "cdsprpc-smd"; + iommus = <&apps_smmu 0x2 0x3440>, + <&apps_smmu 0x22 0x3400>; dma-coherent; }; -- GitLab From 5d2e90419fd2d03ebadb9d25cbf8c35bc88e3008 Mon Sep 17 00:00:00 2001 From: Chong Gu Date: Tue, 10 Apr 2018 11:22:36 +0800 Subject: [PATCH 0099/1635] ARM: dts: msm: add ST touch node for SM8150 add ST touch node with required configuration. Change-Id: Ia5d560ee8dedd8f0f67abf80cd307ba5c88a5542 Signed-off-by: Chong Gu --- arch/arm64/boot/dts/qcom/sm8150-pinctrl.dtsi | 42 ++++++++++++++++++++ arch/arm64/boot/dts/qcom/sm8150-qrd.dtsi | 20 ++++++++++ 2 files changed, 62 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sm8150-pinctrl.dtsi b/arch/arm64/boot/dts/qcom/sm8150-pinctrl.dtsi index c1189d70af53..80d43a2cf622 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-pinctrl.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-pinctrl.dtsi @@ -283,6 +283,48 @@ }; }; + pmx_ts_active { + ts_active: ts_active { + mux { + pins = "gpio122", "gpio54"; + function = "gpio"; + }; + config { + pins = "gpio122", "gpio54"; + drive-strength = <8>; + bias-pull-up; + }; + }; + }; + + pmx_ts_int_suspend { + ts_int_suspend: ts_int_suspend { + mux { + pins = "gpio122"; + function = "gpio"; + }; + config { + pins = "gpio122"; + drive-strength = <2>; + bias-pull-down; + }; + }; + }; + + pmx_ts_reset_suspend { + ts_reset_suspend: ts_reset_suspend { + mux { + pins = "gpio54"; + function = "gpio"; + }; + config { + pins = "gpio54"; + drive-strength = <2>; + bias-pull-down; + }; + }; + }; + pcie0 { pcie0_clkreq_default: pcie0_clkreq_default { mux { diff --git a/arch/arm64/boot/dts/qcom/sm8150-qrd.dtsi b/arch/arm64/boot/dts/qcom/sm8150-qrd.dtsi index 5ef91a3b0907..290cade59ab0 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-qrd.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-qrd.dtsi @@ -54,6 +54,26 @@ #cooling-cells = <2>; }; +&qupv3_se17_i2c { + status = "ok"; + + st_fts@49 { + compatible = "st,fts"; + reg = <0x49>; + interrupt-parent = <&tlmm>; + interrupts = <122 0x2008>; + vdd-supply = <&pm855_s4>; + avdd-supply = <&pm855_l17>; + pinctrl-names = "pmx_ts_active", "pmx_ts_suspend"; + pinctrl-0 = <&ts_active>; + pinctrl-1 = <&ts_int_suspend &ts_reset_suspend>; + st,irq-gpio = <&tlmm 122 0x2008>; + st,reset-gpio = <&tlmm 54 0x00>; + st,regulator_dvdd = "vdd"; + st,regulator_avdd = "avdd"; + }; +}; + &snd_9360 { qcom,model = "sm8150-pahu-qrd-snd-card"; qcom,audio-routing = -- GitLab From 35153078ec12559237092d8ce03a6d2c918e582d Mon Sep 17 00:00:00 2001 From: Liam Mark Date: Tue, 10 Apr 2018 09:55:20 -0700 Subject: [PATCH 0100/1635] Revert "iommu/arm-smmu-v3: Implement shutdown method" This reverts commit 7aa8619a66ae ("iommu/arm-smmu-v3: Implement shutdown method"). Disabling the SMMU during shutdown is currently causing issues because there are SMMU clients who don't currently support shutdown and there is currently no guarantee that shutdown will be called on SMMU clients before shutdown is called on the SMMU. We don't need to support kexec so revert SMMU shutdown support until it can be cleanly handled. Change-Id: Ia042ea29e6432d14d42e3536f82775161a934b9c Signed-off-by: Liam Mark --- drivers/iommu/arm-smmu-v3.c | 7 ------- drivers/iommu/arm-smmu.c | 6 ------ 2 files changed, 13 deletions(-) diff --git a/drivers/iommu/arm-smmu-v3.c b/drivers/iommu/arm-smmu-v3.c index 8f7a3c00b6cf..fa58f4060751 100644 --- a/drivers/iommu/arm-smmu-v3.c +++ b/drivers/iommu/arm-smmu-v3.c @@ -2861,15 +2861,9 @@ static int arm_smmu_device_remove(struct platform_device *pdev) struct arm_smmu_device *smmu = platform_get_drvdata(pdev); arm_smmu_device_disable(smmu); - return 0; } -static void arm_smmu_device_shutdown(struct platform_device *pdev) -{ - arm_smmu_device_remove(pdev); -} - static const struct of_device_id arm_smmu_of_match[] = { { .compatible = "arm,smmu-v3", }, { }, @@ -2883,7 +2877,6 @@ static struct platform_driver arm_smmu_driver = { }, .probe = arm_smmu_device_probe, .remove = arm_smmu_device_remove, - .shutdown = arm_smmu_device_shutdown, }; module_platform_driver(arm_smmu_driver); diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c index 0493852050bd..061277e74abf 100644 --- a/drivers/iommu/arm-smmu.c +++ b/drivers/iommu/arm-smmu.c @@ -4346,11 +4346,6 @@ static int arm_smmu_device_remove(struct platform_device *pdev) return 0; } -static void arm_smmu_device_shutdown(struct platform_device *pdev) -{ - arm_smmu_device_remove(pdev); -} - static int __maybe_unused arm_smmu_pm_resume(struct device *dev) { struct arm_smmu_device *smmu = dev_get_drvdata(dev); @@ -4369,7 +4364,6 @@ static struct platform_driver arm_smmu_driver = { }, .probe = arm_smmu_device_dt_probe, .remove = arm_smmu_device_remove, - .shutdown = arm_smmu_device_shutdown, }; static struct platform_driver qsmmuv500_tbu_driver; -- GitLab From 3cd017658fae1b110de2927156010d80d2761b08 Mon Sep 17 00:00:00 2001 From: Satya Durga Srinivasu Prabhala Date: Wed, 4 Apr 2018 17:54:18 -0700 Subject: [PATCH 0101/1635] sched: fix compilation error in task_fits_capacity for !SCHED_WALT When SCHED_WALT is disabled, max_capacity won't be available and results in compilation error. Fix this by defining the max_capcity locally. Change-Id: I211a255adb574bdea9db1ff2f5797f849050df73 Signed-off-by: Satya Durga Srinivasu Prabhala --- kernel/sched/fair.c | 1 + 1 file changed, 1 insertion(+) diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index 398249a3f2cf..3acf2085ac2e 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -6966,6 +6966,7 @@ static inline int task_fits_capacity(struct task_struct *p, int cpu) { unsigned int margin; + unsigned long max_capacity = cpu_rq(cpu)->rd->max_cpu_capacity; if (capacity == max_capacity) return true; -- GitLab From 8e2a0d8b27c4951792732fbf9c859345ddcf6af3 Mon Sep 17 00:00:00 2001 From: Vikram Mulukutla Date: Thu, 21 Sep 2017 17:24:24 -0700 Subject: [PATCH 0102/1635] Revert "ANDROID: sched/tune: Initialize raw_spin_lock in boosted_groups" This reverts commit c5616f2f874faa20b59b116177b99bf3948586df. If we re-init the per-cpu boostgroup spinlock every time that we add a new boosted cgroup, we can easily wipe out (reinit) a spinlock struct while in a critical section. We should only be setting up the per-cpu boostgroup data, and the spin_lock initialization need only happen once - which we're already doing in a postcore_initcall. For example: -------- CPU 0 -------- | -------- CPU1 -------- cgroupX boost group added | schedtune_enqueue_task | acquires(bg->lock) | cgroupY boost group added | for_each_cpu() | raw_spin_lock_init(bg->lock) releases(bg->lock) | BUG (already unlocked) | | This results in the following BUG from the debug spinlock code: BUG: spinlock already unlocked on CPU#5, rcuop/6/68 Bug: 32668852 Change-Id: I3016702780b461a0cd95e26c538cd18df27d6316 Signed-off-by: Vikram Mulukutla --- kernel/sched/tune.c | 1 - 1 file changed, 1 deletion(-) diff --git a/kernel/sched/tune.c b/kernel/sched/tune.c index 2e6ef5faaad0..57fd9173d6b5 100644 --- a/kernel/sched/tune.c +++ b/kernel/sched/tune.c @@ -451,7 +451,6 @@ schedtune_boostgroup_init(struct schedtune *st) bg = &per_cpu(cpu_boost_groups, cpu); bg->group[st->idx].boost = 0; bg->group[st->idx].tasks = 0; - raw_spin_lock_init(&bg->lock); } return 0; -- GitLab From 499359b921e72a1115e8337db23092b3a777f495 Mon Sep 17 00:00:00 2001 From: Subbaraman Narayanamurthy Date: Tue, 10 Apr 2018 11:04:02 -0700 Subject: [PATCH 0103/1635] power: qpnp-fg-gen4: Fix a possible NULL pointer dereference Currently, in get_batt_psy_props(), batt_psy can be used even before it can be obtained. Fix it. CRs-Fixed: 2221940 Change-Id: Icc86695f89a53802d60a6e2c4dd97b58922d267f Signed-off-by: Subbaraman Narayanamurthy --- drivers/power/supply/qcom/qpnp-fg-gen4.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/power/supply/qcom/qpnp-fg-gen4.c b/drivers/power/supply/qcom/qpnp-fg-gen4.c index d8bc88bcbf89..36573f04cf66 100644 --- a/drivers/power/supply/qcom/qpnp-fg-gen4.c +++ b/drivers/power/supply/qcom/qpnp-fg-gen4.c @@ -913,6 +913,9 @@ static void get_batt_psy_props(struct fg_dev *fg) union power_supply_propval prop = {0, }; int rc; + if (!batt_psy_initialized(fg)) + return; + rc = power_supply_get_property(fg->batt_psy, POWER_SUPPLY_PROP_STATUS, &prop); if (rc < 0) { -- GitLab From f368db2298e9af507bcbc583cc23b92cf5726ca7 Mon Sep 17 00:00:00 2001 From: Kyle Piefer Date: Fri, 6 Apr 2018 16:42:36 -0700 Subject: [PATCH 0104/1635] ARM: dts: msm: Remove TURBO_L1 power level for SM8150 The highest power level, TURBO_L1, might be unstable. To be safe, remove it from SM8150 for now. Change-Id: I00f1028e5482ab8f853ed9b24a36b64ee4d4dd77 Signed-off-by: Kyle Piefer --- arch/arm64/boot/dts/qcom/sm8150-gpu.dtsi | 38 ++++++++---------------- 1 file changed, 12 insertions(+), 26 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sm8150-gpu.dtsi b/arch/arm64/boot/dts/qcom/sm8150-gpu.dtsi index d4e541997c65..01c7d4d62fc1 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-gpu.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-gpu.dtsi @@ -45,11 +45,6 @@ gpu_opp_table: gpu-opp-table { compatible = "operating-points-v2"; - opp-620000000 { - opp-hz = /bits/ 64 <620000000>; - opp-microvolt = ; - }; - opp-600000000 { opp-hz = /bits/ 64 <600000000>; opp-microvolt = ; @@ -204,23 +199,14 @@ qcom,gpu-pwrlevel@0 { reg = <0>; - qcom,gpu-freq = <620000000>; - qcom,bus-freq = <12>; - qcom,bus-min = <11>; - qcom,bus-max = <12>; - }; - - - qcom,gpu-pwrlevel@1 { - reg = <1>; qcom,gpu-freq = <600000000>; qcom,bus-freq = <12>; qcom,bus-min = <10>; qcom,bus-max = <12>; }; - qcom,gpu-pwrlevel@2 { - reg = <2>; + qcom,gpu-pwrlevel@1 { + reg = <1>; qcom,gpu-freq = <553850000>; qcom,bus-freq = <10>; qcom,bus-min = <9>; @@ -228,16 +214,16 @@ }; - qcom,gpu-pwrlevel@3 { - reg = <3>; + qcom,gpu-pwrlevel@2 { + reg = <2>; qcom,gpu-freq = <486460000>; qcom,bus-freq = <9>; qcom,bus-min = <8>; qcom,bus-max = <10>; }; - qcom,gpu-pwrlevel@4 { - reg = <4>; + qcom,gpu-pwrlevel@3 { + reg = <3>; qcom,gpu-freq = <379650000>; qcom,bus-freq = <8>; qcom,bus-min = <7>; @@ -245,24 +231,24 @@ }; - qcom,gpu-pwrlevel@5 { - reg = <5>; + qcom,gpu-pwrlevel@4 { + reg = <4>; qcom,gpu-freq = <309110000>; qcom,bus-freq = <5>; qcom,bus-min = <5>; qcom,bus-max = <7>; }; - qcom,gpu-pwrlevel@6 { - reg = <6>; + qcom,gpu-pwrlevel@5 { + reg = <5>; qcom,gpu-freq = <215000000>; qcom,bus-freq = <4>; qcom,bus-min = <3>; qcom,bus-max = <5>; }; - qcom,gpu-pwrlevel@7 { - reg = <7>; + qcom,gpu-pwrlevel@6 { + reg = <6>; qcom,gpu-freq = <0>; qcom,bus-freq = <0>; qcom,bus-min = <0>; -- GitLab From 3ce275bf4e18231e1eebef046c345b94832cefd5 Mon Sep 17 00:00:00 2001 From: Liam Mark Date: Mon, 2 Apr 2018 14:55:58 -0700 Subject: [PATCH 0105/1635] staging: android: ion: Support iommu mappings with one segment Ensure that ION supports iommu mappings with one segment. Unfortunately with partial cache maintenance it is not possible to support mappings with multiple segments as these mappings could include IOVA padding and this makes it very difficult to calculate the IOVA for an offset in an SG entry. This limitation should not be a problem as we expect ION clients to only use mappings with one segment. Change-Id: I3cb88398cd41a68faa77fb64ddcfdee9d9ecdfbd Signed-off-by: Liam Mark --- drivers/iommu/msm_dma_iommu_mapping.c | 16 +- drivers/staging/android/ion/ion.c | 217 ++++++++++++++++++-------- 2 files changed, 170 insertions(+), 63 deletions(-) diff --git a/drivers/iommu/msm_dma_iommu_mapping.c b/drivers/iommu/msm_dma_iommu_mapping.c index 58fa6019a81c..84e0330dbbdb 100644 --- a/drivers/iommu/msm_dma_iommu_mapping.c +++ b/drivers/iommu/msm_dma_iommu_mapping.c @@ -236,8 +236,20 @@ static inline int __msm_dma_map_sg(struct device *dev, struct scatterlist *sg, (attrs & ~DMA_ATTR_SKIP_CPU_SYNC) == (iommu_map->attrs & ~DMA_ATTR_SKIP_CPU_SYNC) && sg_phys(sg) == iommu_map->buf_start_addr) { - sg->dma_address = iommu_map->sgl->dma_address; - sg->dma_length = iommu_map->sgl->dma_length; + struct scatterlist *sg_tmp = sg; + struct scatterlist *map_sg; + int i; + + for_each_sg(iommu_map->sgl, map_sg, nents, i) { + sg_dma_address(sg_tmp) = sg_dma_address(map_sg); + sg_dma_len(sg_tmp) = sg_dma_len(map_sg); + if (sg_dma_len(map_sg) == 0) + break; + + sg_tmp = sg_next(sg_tmp); + if (sg == NULL) + break; + } kref_get(&iommu_map->ref); diff --git a/drivers/staging/android/ion/ion.c b/drivers/staging/android/ion/ion.c index 295611223d53..aedad870bb4d 100644 --- a/drivers/staging/android/ion/ion.c +++ b/drivers/staging/android/ion/ion.c @@ -254,7 +254,8 @@ static struct sg_table *dup_sg_table(struct sg_table *table) new_sg = new_table->sgl; for_each_sg(table->sgl, sg, table->nents, i) { memcpy(new_sg, sg, sizeof(*sg)); - new_sg->dma_address = 0; + sg_dma_address(new_sg) = 0; + sg_dma_len(new_sg) = 0; new_sg = sg_next(new_sg); } @@ -519,18 +520,35 @@ static void ion_dma_buf_vunmap(struct dma_buf *dmabuf, void *vaddr) { } -static void ion_sgl_sync_range(struct device *dev, struct scatterlist *sgl, - unsigned int nents, unsigned long offset, - unsigned long length, - enum dma_data_direction dir, bool for_cpu) +static int ion_sgl_sync_range(struct device *dev, struct scatterlist *sgl, + unsigned int nents, unsigned long offset, + unsigned long length, + enum dma_data_direction dir, bool for_cpu) { int i; struct scatterlist *sg; unsigned int len = 0; + dma_addr_t sg_dma_addr; + + for_each_sg(sgl, sg, nents, i) { + if (sg_dma_len(sg) == 0) + break; + + if (i > 0) { + pr_warn("Partial cmo only supported with 1 segment\n" + "is dma_set_max_seg_size being set on dev:%s\n", + dev_name(dev)); + return -EINVAL; + } + } + for_each_sg(sgl, sg, nents, i) { unsigned int sg_offset, sg_left, size = 0; + if (i == 0) + sg_dma_addr = sg_dma_address(sg); + len += sg->length; if (len <= offset) continue; @@ -540,32 +558,42 @@ static void ion_sgl_sync_range(struct device *dev, struct scatterlist *sgl, size = (length < sg_left) ? length : sg_left; if (for_cpu) - dma_sync_single_range_for_cpu(dev, sg->dma_address, + dma_sync_single_range_for_cpu(dev, sg_dma_addr, sg_offset, size, dir); else - dma_sync_single_range_for_device(dev, sg->dma_address, + dma_sync_single_range_for_device(dev, sg_dma_addr, sg_offset, size, dir); offset += size; length -= size; + sg_dma_addr += sg->length; if (length == 0) break; } + + return 0; } -static void ion_sgl_sync_mapped(struct device *dev, struct scatterlist *sgl, - unsigned int nents, struct list_head *vmas, - enum dma_data_direction dir, bool for_cpu) +static int ion_sgl_sync_mapped(struct device *dev, struct scatterlist *sgl, + unsigned int nents, struct list_head *vmas, + enum dma_data_direction dir, bool for_cpu) { struct ion_vma_list *vma_list; + int ret = 0; list_for_each_entry(vma_list, vmas, list) { struct vm_area_struct *vma = vma_list->vma; - ion_sgl_sync_range(dev, sgl, nents, vma->vm_pgoff * PAGE_SIZE, - vma->vm_end - vma->vm_start, dir, for_cpu); + ret = ion_sgl_sync_range(dev, sgl, nents, + vma->vm_pgoff * PAGE_SIZE, + vma->vm_end - vma->vm_start, dir, + for_cpu); + if (ret) + break; } + + return ret; } static int __ion_dma_buf_begin_cpu_access(struct dma_buf *dmabuf, @@ -608,23 +636,31 @@ static int __ion_dma_buf_begin_cpu_access(struct dma_buf *dmabuf, struct device *dev = buffer->heap->priv; struct sg_table *table = buffer->sg_table; - trace_ion_begin_cpu_access_cmo_apply(dev, dmabuf->name, - true, true, direction, - sync_only_mapped); - if (sync_only_mapped) - ion_sgl_sync_mapped(dev, table->sgl, - table->nents, &buffer->vmas, - direction, true); + ret = ion_sgl_sync_mapped(dev, table->sgl, + table->nents, &buffer->vmas, + direction, true); else dma_sync_sg_for_cpu(dev, table->sgl, table->nents, direction); + if (!ret) + trace_ion_begin_cpu_access_cmo_apply(dev, dmabuf->name, + true, true, + direction, + sync_only_mapped); + else + trace_ion_begin_cpu_access_cmo_skip(dev, dmabuf->name, + true, true, + direction, + sync_only_mapped); mutex_unlock(&buffer->lock); goto out; } list_for_each_entry(a, &buffer->attachments, list) { + int tmp = 0; + if (!a->dma_mapped) { trace_ion_begin_cpu_access_notmapped(a->dev, dmabuf->name, @@ -634,17 +670,29 @@ static int __ion_dma_buf_begin_cpu_access(struct dma_buf *dmabuf, continue; } - trace_ion_begin_cpu_access_cmo_apply(a->dev, dmabuf->name, - true, true, direction, - sync_only_mapped); - if (sync_only_mapped) - ion_sgl_sync_mapped(a->dev, a->table->sgl, - a->table->nents, &buffer->vmas, - direction, true); + tmp = ion_sgl_sync_mapped(a->dev, a->table->sgl, + a->table->nents, + &buffer->vmas, + direction, true); else dma_sync_sg_for_cpu(a->dev, a->table->sgl, a->table->nents, direction); + + if (!tmp) { + trace_ion_begin_cpu_access_cmo_apply(a->dev, + dmabuf->name, + true, true, + direction, + sync_only_mapped); + } else { + trace_ion_begin_cpu_access_cmo_skip(a->dev, + dmabuf->name, true, + true, direction, + sync_only_mapped); + ret = tmp; + } + } mutex_unlock(&buffer->lock); @@ -687,22 +735,30 @@ static int __ion_dma_buf_end_cpu_access(struct dma_buf *dmabuf, struct device *dev = buffer->heap->priv; struct sg_table *table = buffer->sg_table; - trace_ion_end_cpu_access_cmo_apply(dev, dmabuf->name, - true, true, direction, - sync_only_mapped); - if (sync_only_mapped) - ion_sgl_sync_mapped(dev, table->sgl, - table->nents, &buffer->vmas, - direction, false); + ret = ion_sgl_sync_mapped(dev, table->sgl, + table->nents, &buffer->vmas, + direction, false); else dma_sync_sg_for_device(dev, table->sgl, table->nents, direction); + + if (!ret) + trace_ion_end_cpu_access_cmo_apply(dev, dmabuf->name, + true, true, + direction, + sync_only_mapped); + else + trace_ion_end_cpu_access_cmo_skip(dev, dmabuf->name, + true, true, direction, + sync_only_mapped); mutex_unlock(&buffer->lock); goto out; } list_for_each_entry(a, &buffer->attachments, list) { + int tmp = 0; + if (!a->dma_mapped) { trace_ion_end_cpu_access_notmapped(a->dev, dmabuf->name, @@ -712,17 +768,26 @@ static int __ion_dma_buf_end_cpu_access(struct dma_buf *dmabuf, continue; } - trace_ion_end_cpu_access_cmo_apply(a->dev, dmabuf->name, - true, true, direction, - sync_only_mapped); - if (sync_only_mapped) - ion_sgl_sync_mapped(a->dev, a->table->sgl, - a->table->nents, &buffer->vmas, - direction, false); + tmp = ion_sgl_sync_mapped(a->dev, a->table->sgl, + a->table->nents, + &buffer->vmas, direction, + false); else dma_sync_sg_for_device(a->dev, a->table->sgl, a->table->nents, direction); + + if (!tmp) { + trace_ion_end_cpu_access_cmo_apply(a->dev, dmabuf->name, + true, true, + direction, + sync_only_mapped); + } else { + trace_ion_end_cpu_access_cmo_skip(a->dev, dmabuf->name, + true, true, direction, + sync_only_mapped); + ret = tmp; + } } mutex_unlock(&buffer->lock); @@ -794,18 +859,24 @@ static int ion_dma_buf_begin_cpu_access_partial(struct dma_buf *dmabuf, struct device *dev = buffer->heap->priv; struct sg_table *table = buffer->sg_table; - trace_ion_begin_cpu_access_cmo_apply(dev, dmabuf->name, - true, true, dir, - false); - - ion_sgl_sync_range(dev, table->sgl, table->nents, - offset, len, dir, true); + ret = ion_sgl_sync_range(dev, table->sgl, table->nents, + offset, len, dir, true); + if (!ret) + trace_ion_begin_cpu_access_cmo_apply(dev, dmabuf->name, + true, true, dir, + false); + else + trace_ion_begin_cpu_access_cmo_skip(dev, dmabuf->name, + true, true, dir, + false); mutex_unlock(&buffer->lock); goto out; } list_for_each_entry(a, &buffer->attachments, list) { + int tmp = 0; + if (!a->dma_mapped) { trace_ion_begin_cpu_access_notmapped(a->dev, dmabuf->name, @@ -815,12 +886,22 @@ static int ion_dma_buf_begin_cpu_access_partial(struct dma_buf *dmabuf, continue; } - trace_ion_begin_cpu_access_cmo_apply(a->dev, dmabuf->name, - true, true, dir, - false); + tmp = ion_sgl_sync_range(a->dev, a->table->sgl, a->table->nents, + offset, len, dir, true); + + if (!tmp) { + trace_ion_begin_cpu_access_cmo_apply(a->dev, + dmabuf->name, + true, true, dir, + false); + } else { + trace_ion_begin_cpu_access_cmo_skip(a->dev, + dmabuf->name, + true, true, dir, + false); + ret = tmp; + } - ion_sgl_sync_range(a->dev, a->table->sgl, a->table->nents, - offset, len, dir, true); } mutex_unlock(&buffer->lock); @@ -864,18 +945,25 @@ static int ion_dma_buf_end_cpu_access_partial(struct dma_buf *dmabuf, struct device *dev = buffer->heap->priv; struct sg_table *table = buffer->sg_table; - trace_ion_end_cpu_access_cmo_apply(dev, dmabuf->name, - true, true, direction, - false); + ret = ion_sgl_sync_range(dev, table->sgl, table->nents, + offset, len, direction, false); - ion_sgl_sync_range(dev, table->sgl, table->nents, - offset, len, direction, false); + if (!ret) + trace_ion_end_cpu_access_cmo_apply(dev, dmabuf->name, + true, true, + direction, false); + else + trace_ion_end_cpu_access_cmo_skip(dev, dmabuf->name, + true, true, + direction, false); mutex_unlock(&buffer->lock); goto out; } list_for_each_entry(a, &buffer->attachments, list) { + int tmp = 0; + if (!a->dma_mapped) { trace_ion_end_cpu_access_notmapped(a->dev, dmabuf->name, @@ -885,13 +973,20 @@ static int ion_dma_buf_end_cpu_access_partial(struct dma_buf *dmabuf, continue; } - trace_ion_end_cpu_access_cmo_apply(a->dev, dmabuf->name, - true, true, direction, - false); + tmp = ion_sgl_sync_range(a->dev, a->table->sgl, a->table->nents, + offset, len, direction, false); - ion_sgl_sync_range(a->dev, a->table->sgl, a->table->nents, - offset, len, direction, false); + if (!tmp) { + trace_ion_end_cpu_access_cmo_apply(a->dev, dmabuf->name, + true, true, + direction, false); + } else { + trace_ion_end_cpu_access_cmo_skip(a->dev, dmabuf->name, + true, true, direction, + false); + ret = tmp; + } } mutex_unlock(&buffer->lock); -- GitLab From 9db357aebd9a17ff8f199068e23286b60d4e798d Mon Sep 17 00:00:00 2001 From: Michael Adisumarta Date: Thu, 5 Apr 2018 17:59:09 -0700 Subject: [PATCH 0106/1635] msm: ipa4: USB_CONS QMB update Change USB CONS register to use DDR instead of PCIE Change-Id: I1f6c629daad13904501357dbc80499267b05a304 Crs-fixed: 2219398 Signed-off-by: Michael Adisumarta --- drivers/platform/msm/ipa/ipa_v3/ipa_utils.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c index ab4ba8a1ca90..f9f5a30792a5 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c @@ -1253,7 +1253,7 @@ static const struct ipa_ep_configuration ipa3_ep_mapping true, IPA_v4_0_GROUP_UL_DL, false, IPA_DPS_HPS_SEQ_TYPE_INVALID, - QMB_MASTER_SELECT_PCIE, + QMB_MASTER_SELECT_DDR, { 19, 12, 9, 9, IPA_EE_AP } }, [IPA_4_0][IPA_CLIENT_USB_DPL_CONS] = { true, IPA_v4_0_GROUP_UL_DL, -- GitLab From 8981aed5f3348193b2fe468726d96abc976ec8fe Mon Sep 17 00:00:00 2001 From: Jigarkumar Zala Date: Wed, 21 Mar 2018 15:52:03 -0700 Subject: [PATCH 0107/1635] msm: camera: Enable support for flash module Enabling flash probe support for camera modules. Also, fix compliation issues for flash driver. Change-Id: Iddd9b4ed46a63535dbde3f4b3d4d6d47967b8fab Signed-off-by: Jigarkumar Zala --- drivers/media/platform/msm/camera/cam_sensor_module/Makefile | 2 +- .../msm/camera/cam_sensor_module/cam_flash/cam_flash_core.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/Makefile b/drivers/media/platform/msm/camera/cam_sensor_module/Makefile index a97e2a0a68eb..65c23274e5ae 100644 --- a/drivers/media/platform/msm/camera/cam_sensor_module/Makefile +++ b/drivers/media/platform/msm/camera/cam_sensor_module/Makefile @@ -5,6 +5,6 @@ obj-$(CONFIG_SPECTRA_CAMERA) += cam_sensor_io/ obj-$(CONFIG_SPECTRA_CAMERA) += cam_csiphy/ obj-$(CONFIG_SPECTRA_CAMERA) += cam_actuator/ obj-$(CONFIG_SPECTRA_CAMERA) += cam_sensor/ -#obj-$(CONFIG_SPECTRA_CAMERA) += cam_flash/ +obj-$(CONFIG_SPECTRA_CAMERA) += cam_flash/ obj-$(CONFIG_SPECTRA_CAMERA) += cam_eeprom/ obj-$(CONFIG_SPECTRA_CAMERA) += cam_ois/ diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_flash/cam_flash_core.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_flash/cam_flash_core.c index fd0f8fceba0c..d26de2be19be 100644 --- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_flash/cam_flash_core.c +++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_flash/cam_flash_core.c @@ -184,7 +184,7 @@ static int cam_flash_ops(struct cam_flash_ctrl *flash_ctrl, if (flash_ctrl->switch_trigger) cam_res_mgr_led_trigger_event( flash_ctrl->switch_trigger, - LED_SWITCH_ON); + (enum led_brightness)LED_SWITCH_ON); return 0; } @@ -212,7 +212,7 @@ int cam_flash_off(struct cam_flash_ctrl *flash_ctrl) if (flash_ctrl->switch_trigger) cam_res_mgr_led_trigger_event(flash_ctrl->switch_trigger, - LED_SWITCH_OFF); + (enum led_brightness)LED_SWITCH_OFF); flash_ctrl->flash_state = CAM_FLASH_STATE_START; return 0; -- GitLab From 2b5e39c9033f258c8ef0b99f07bd26b58d9a427e Mon Sep 17 00:00:00 2001 From: Satya Durga Srinivasu Prabhala Date: Wed, 4 Apr 2018 16:00:26 -0700 Subject: [PATCH 0108/1635] sched/fair: move task_fits_max out of SCHED_WALT task_fits_max is called outside of SCHED_WALT and results in compilation failure if SCHED_WALT is disabled. Change-Id: I12a0b93a714d041716fc651b461e6388a676f4a2 Signed-off-by: Satya Durga Srinivasu Prabhala --- kernel/sched/fair.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index 3acf2085ac2e..210977130d09 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -40,9 +40,12 @@ #include "tune.h" #include "walt.h" +#ifdef CONFIG_SMP +static inline bool task_fits_max(struct task_struct *p, int cpu); +#endif /* CONFIG_SMP */ + #ifdef CONFIG_SCHED_WALT -static inline bool task_fits_max(struct task_struct *p, int cpu); static void walt_fixup_sched_stats_fair(struct rq *rq, struct task_struct *p, u32 new_task_load, u32 new_pred_demand); static void walt_fixup_nr_big_tasks(struct rq *rq, struct task_struct *p, -- GitLab From 0bb1b96bf33772cb237b94a437591669d938d117 Mon Sep 17 00:00:00 2001 From: Satya Durga Srinivasu Prabhala Date: Wed, 4 Apr 2018 16:23:29 -0700 Subject: [PATCH 0109/1635] sched: Fix compilation error with task_in_cum_window_demand for !SCHED_WALT task_in_cum_window_demand is a WALT specific function, accessing it when SCHED_WALT not enabled results in compilation error. Fix the issue by adding task_in_cum_window_demand when SCHED_WALT is disabled. Change-Id: I3876c1cb766daa549ddc7edd5da2d45617656024 Signed-off-by: Satya Durga Srinivasu Prabhala --- kernel/sched/sched.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h index 0c948ead46cc..ae7b3e6f5017 100644 --- a/kernel/sched/sched.h +++ b/kernel/sched/sched.h @@ -2921,6 +2921,12 @@ static inline int sched_boost(void) return 0; } +static inline bool +task_in_cum_window_demand(struct rq *rq, struct task_struct *p) +{ + return false; +} + static inline bool hmp_capable(void) { return false; } static inline bool is_max_capacity_cpu(int cpu) { return true; } static inline bool is_min_capacity_cpu(int cpu) { return true; } -- GitLab From 0893d9da6dfdfaf3d19f6d885702ab9af92d76b3 Mon Sep 17 00:00:00 2001 From: Zhen Kong Date: Tue, 3 Apr 2018 16:52:12 -0700 Subject: [PATCH 0110/1635] soc: qcom: scm: QHEE SMC call to enable kernel memory protection Invoke an SMC call immediately after self-modification of code region due to arm errata to protect kernel's memory regions in stage 2 memory mappings. Change-Id: I4706ab50ca8f6fa558990564ff8dd4ff967add26 Acked-by: Dane Pitkin Signed-off-by: Zhen Kong --- arch/arm64/kernel/smp.c | 3 +++ drivers/soc/qcom/Kconfig | 9 +++++++++ drivers/soc/qcom/scm.c | 41 ++++++++++++++++++++++++++++++++++++++++ include/soc/qcom/scm.h | 9 ++++++++- 4 files changed, 61 insertions(+), 1 deletion(-) diff --git a/arch/arm64/kernel/smp.c b/arch/arm64/kernel/smp.c index 0fdbecd8fd11..fb528be54ddf 100644 --- a/arch/arm64/kernel/smp.c +++ b/arch/arm64/kernel/smp.c @@ -59,6 +59,8 @@ #include #include +#include + #define CREATE_TRACE_POINTS #include @@ -437,6 +439,7 @@ void __init smp_cpus_done(unsigned int max_cpus) setup_cpu_features(); hyp_mode_check(); apply_alternatives_all(); + scm_enable_mem_protection(); mark_linear_text_alias_ro(); } diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig index 6814d6c865a1..88fb5151602e 100644 --- a/drivers/soc/qcom/Kconfig +++ b/drivers/soc/qcom/Kconfig @@ -585,4 +585,13 @@ config QMP_DEBUGFS_CLIENT help This options enables a driver which allows clients to send messages to Alway On processor using QMP transport. + +config QCOM_QHEE_ENABLE_MEM_PROTECTION + bool "QHEE enable kernel memory protection" + depends on QCOM_SCM + default y + help + When this option is enabled, an SCM call will be invoked to enable + kernel memory protection in stage 2 memory mappings on kernel boot. + This is part of a security feature enabled in QHEE. endmenu diff --git a/drivers/soc/qcom/scm.c b/drivers/soc/qcom/scm.c index e82861ee563b..bf5afb2e9567 100644 --- a/drivers/soc/qcom/scm.c +++ b/drivers/soc/qcom/scm.c @@ -618,3 +618,44 @@ bool scm_is_secure_device(void) return false; } EXPORT_SYMBOL(scm_is_secure_device); + +/* + * SCM call command ID to protect kernel memory + * in Hyp Stage 2 page tables. + * Return zero for success. + * Return non-zero for failure. + */ +#define TZ_RTIC_ENABLE_MEM_PROTECTION 0x4 +#if IS_ENABLED(CONFIG_QCOM_QHEE_ENABLE_MEM_PROTECTION) +int scm_enable_mem_protection(void) +{ + struct scm_desc desc = {0}; + int ret = 0, resp; + + desc.args[0] = 0; + desc.arginfo = 0; + ret = scm_call2(SCM_SIP_FNID(SCM_SVC_RTIC, + TZ_RTIC_ENABLE_MEM_PROTECTION), + &desc); + resp = desc.ret[0]; + + if (ret == -1) { + pr_err("%s: SCM call not supported\n", __func__); + return ret; + } else if (ret || resp) { + pr_err("%s: SCM call failed\n", __func__); + if (ret) + return ret; + else + return resp; + } + + return resp; +} +#else +inline int scm_enable_mem_protection(void) +{ + return 0; +} +#endif +EXPORT_SYMBOL(scm_enable_mem_protection); diff --git a/include/soc/qcom/scm.h b/include/soc/qcom/scm.h index 646687d21c04..d8c0998c19c2 100644 --- a/include/soc/qcom/scm.h +++ b/include/soc/qcom/scm.h @@ -29,6 +29,7 @@ #define SCM_SVC_LMH 0x13 #define SCM_SVC_SMMU_PROGRAM 0x15 #define SCM_SVC_QDSS 0x16 +#define SCM_SVC_RTIC 0x19 #define SCM_SVC_TZSCHEDULER 0xFC #define SCM_FUSE_READ 0x7 @@ -105,6 +106,7 @@ extern int scm_is_call_available(u32 svc_id, u32 cmd_id); extern u32 scm_io_read(phys_addr_t address); extern int scm_io_write(phys_addr_t address, u32 val); extern bool scm_is_secure_device(void); +extern int scm_enable_mem_protection(void); extern struct mutex scm_lmh_lock; @@ -150,9 +152,14 @@ static inline int scm_io_write(phys_addr_t address, u32 val) return 0; } -inline bool scm_is_secure_device(void) +static inline bool scm_is_secure_device(void) { return false; } + +static inline int scm_enable_mem_protection(void) +{ + return 0; +} #endif #endif -- GitLab From 0e970954d63483e73fb61897060bdc9a5aa50bc2 Mon Sep 17 00:00:00 2001 From: Jack Pham Date: Tue, 10 Apr 2018 15:45:53 -0700 Subject: [PATCH 0111/1635] ARM: dts: msm: remove redundant USB extcon on sm8150 The driver code now attempts to register both USB and USB_HOST on each extcon phandle provided, so there is no need to specify duplicate entries. Otherwise the same callbacks would end up getting registered multiple times. Remove the duplicate &pm855b_pdphy phandle from the USB node's extcon property. Change-Id: I4039e4b3e4e50de18e28afb3230d5b9295aa58b0 Signed-off-by: Jack Pham --- arch/arm64/boot/dts/qcom/sm8150-pmic-overlay.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/sm8150-pmic-overlay.dtsi b/arch/arm64/boot/dts/qcom/sm8150-pmic-overlay.dtsi index d2d119e59898..bb75c2ad6c82 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-pmic-overlay.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-pmic-overlay.dtsi @@ -68,5 +68,5 @@ }; &usb0 { - extcon = <&pm855b_pdphy>, <&pm855b_pdphy>, <&eud>; + extcon = <&pm855b_pdphy>, <&eud>; }; -- GitLab From f9af0f62b1353ed7f8ff41e2a748cbc4feb894c4 Mon Sep 17 00:00:00 2001 From: Chris Lew Date: Fri, 30 Mar 2018 16:10:15 -0700 Subject: [PATCH 0112/1635] ARM: dts: msm: Add MPROC stack nodes for sdmshrike Add device tree nodes to enable IPC to the remote processors. Nodes for the SMEM, SMP2P, RPMSG GLINK and GLINK PKT drivers are added in this commit. Change-Id: I8114140359160facf659b21e37bd3a1422a6783d Signed-off-by: Chris Lew --- arch/arm64/boot/dts/qcom/sdmshrike-smp2p.dtsi | 96 +++++++++++ arch/arm64/boot/dts/qcom/sdmshrike.dtsi | 162 ++++++++++++++++++ 2 files changed, 258 insertions(+) create mode 100644 arch/arm64/boot/dts/qcom/sdmshrike-smp2p.dtsi diff --git a/arch/arm64/boot/dts/qcom/sdmshrike-smp2p.dtsi b/arch/arm64/boot/dts/qcom/sdmshrike-smp2p.dtsi new file mode 100644 index 000000000000..5e42f0056eec --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdmshrike-smp2p.dtsi @@ -0,0 +1,96 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include + +&soc { + + qcom,smp2p-modem { + compatible = "qcom,smp2p"; + qcom,smem = <435>, <428>; + interrupts = ; + qcom,ipc = <&apcs 0 14>; + qcom,local-pid = <0>; + qcom,remote-pid = <1>; + + modem_smp2p_out: master-kernel { + qcom,entry-name = "master-kernel"; + #qcom,smem-state-cells = <1>; + }; + + modem_smp2p_in: slave-kernel { + qcom,entry-name = "slave-kernel"; + interrupt-controller; + #interrupt-cells = <2>; + }; + }; + + qcom,smp2p-adsp { + compatible = "qcom,smp2p"; + qcom,smem = <443>, <429>; + interrupts = ; + qcom,ipc = <&apcs 0 10>; + qcom,local-pid = <0>; + qcom,remote-pid = <2>; + + adsp_smp2p_out: master-kernel { + qcom,entry-name = "master-kernel"; + #qcom,smem-state-cells = <1>; + }; + + adsp_smp2p_in: slave-kernel { + qcom,entry-name = "slave-kernel"; + interrupt-controller; + #interrupt-cells = <2>; + }; + }; + + qcom,smp2p-dsps { + compatible = "qcom,smp2p"; + qcom,smem = <481>, <430>; + interrupts = ; + qcom,ipc = <&apcs 0 26>; + qcom,local-pid = <0>; + qcom,remote-pid = <3>; + + dsps_smp2p_out: master-kernel { + qcom,entry-name = "master-kernel"; + #qcom,smem-state-cells = <1>; + }; + + dsps_smp2p_in: slave-kernel { + qcom,entry-name = "slave-kernel"; + interrupt-controller; + #interrupt-cells = <2>; + }; + }; + + qcom,smp2p-cdsp { + compatible = "qcom,smp2p"; + qcom,smem = <94>, <432>; + interrupts = ; + qcom,ipc = <&apcs 0 6>; + qcom,local-pid = <0>; + qcom,remote-pid = <5>; + + cdsp_smp2p_out: master-kernel { + qcom,entry-name = "master-kernel"; + #qcom,smem-state-cells = <1>; + }; + + cdsp_smp2p_in: slave-kernel { + qcom,entry-name = "slave-kernel"; + interrupt-controller; + #interrupt-cells = <2>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/sdmshrike.dtsi b/arch/arm64/boot/dts/qcom/sdmshrike.dtsi index de3abbc75bd9..95f8062feaa1 100644 --- a/arch/arm64/boot/dts/qcom/sdmshrike.dtsi +++ b/arch/arm64/boot/dts/qcom/sdmshrike.dtsi @@ -534,6 +534,167 @@ #mbox-cells = <1>; }; + tcsr_mutex_block: syscon@1f40000 { + compatible = "syscon"; + reg = <0x1f40000 0x20000>; + }; + + tcsr_mutex: qcom,hwlock { + compatible = "qcom,tcsr-mutex"; + syscon = <&tcsr_mutex_block 0 0x1000>; + #hwlock-cells = <1>; + }; + + smem: qcom,smem { + compatible = "qcom,smem"; + memory-region = <&smem_region>; + hwlocks = <&tcsr_mutex 3>; + }; + + apcs: syscon@17c0000c { + compatible = "syscon"; + reg = <0x17c0000c 0x4>; + }; + + apcs_glb: mailbox@17c00000 { + compatible = "qcom,sm8150-apcs-hmss-global"; + reg = <0x17c00000 0x1000>; + + #mbox-cells = <1>; + }; + + qcom,glink { + compatible = "qcom,glink"; + modem { + qcom,remote-pid = <1>; + transport = "smem"; + mboxes = <&apcs_glb 12>; + mbox-names = "mpss_smem"; + interrupts = ; + + modem_qrtr { + qcom,glink-channels = "IPCRTR"; + qcom,intents = <0x800 5 + 0x2000 3 + 0x4400 2>; + }; + + qcom,msm_fastrpc_rpmsg { + compatible = "qcom,msm-fastrpc-rpmsg"; + qcom,glink-channels = "fastrpcglink-apps-dsp"; + qcom,intents = <0x64 64>; + }; + }; + + adsp { + qcom,remote-pid = <2>; + transport = "smem"; + mboxes = <&apcs_glb 8>; + mbox-names = "adsp_smem"; + interrupts = ; + + adsp_qrtr { + qcom,glink-channels = "IPCRTR"; + qcom,intents = <0x800 5 + 0x2000 3 + 0x4400 2>; + }; + + apr_tal_rpmsg { + qcom,glink-channels = "apr_audio_svc"; + qcom,intents = <0x200 20>; + }; + + qcom,msm_fastrpc_rpmsg { + compatible = "qcom,msm-fastrpc-rpmsg"; + qcom,glink-channels = "fastrpcglink-apps-dsp"; + qcom,intents = <0x64 64>; + }; + }; + + dsps { + qcom,remote-pid = <3>; + transport = "smem"; + mboxes = <&apcs_glb 24>; + mbox-names = "dsps_smem"; + interrupts = ; + + dsps_qrtr { + qcom,glink-channels = "IPCRTR"; + qcom,intents = <0x800 5 + 0x2000 3 + 0x4400 2>; + }; + + qcom,msm_fastrpc_rpmsg { + compatible = "qcom,msm-fastrpc-rpmsg"; + qcom,glink-channels = "fastrpcglink-apps-dsp"; + qcom,intents = <0x64 64>; + }; + }; + + cdsp { + qcom,remote-pid = <5>; + transport = "smem"; + mboxes = <&apcs_glb 4>; + mbox-names = "cdsp_smem"; + interrupts = ; + + cdsp_qrtr { + qcom,glink-channels = "IPCRTR"; + qcom,intents = <0x800 5 + 0x2000 3 + 0x4400 2>; + }; + + qcom,msm_fastrpc_rpmsg { + compatible = "qcom,msm-fastrpc-rpmsg"; + qcom,glink-channels = "fastrpcglink-apps-dsp"; + qcom,intents = <0x64 64>; + }; + }; + }; + + qcom,glinkpkt { + compatible = "qcom,glinkpkt"; + + qcom,glinkpkt-at-mdm0 { + qcom,glinkpkt-edge = "mpss"; + qcom,glinkpkt-ch-name = "DS"; + qcom,glinkpkt-dev-name = "at_mdm0"; + }; + + qcom,glinkpkt-apr-apps2 { + qcom,glinkpkt-edge = "adsp"; + qcom,glinkpkt-ch-name = "apr_apps2"; + qcom,glinkpkt-dev-name = "apr_apps2"; + }; + + qcom,glinkpkt-data40-cntl { + qcom,glinkpkt-edge = "mpss"; + qcom,glinkpkt-ch-name = "DATA40_CNTL"; + qcom,glinkpkt-dev-name = "smdcntl8"; + }; + + qcom,glinkpkt-data1 { + qcom,glinkpkt-edge = "mpss"; + qcom,glinkpkt-ch-name = "DATA1"; + qcom,glinkpkt-dev-name = "smd7"; + }; + + qcom,glinkpkt-data4 { + qcom,glinkpkt-edge = "mpss"; + qcom,glinkpkt-ch-name = "DATA4"; + qcom,glinkpkt-dev-name = "smd8"; + }; + + qcom,glinkpkt-data11 { + qcom,glinkpkt-edge = "mpss"; + qcom,glinkpkt-ch-name = "DATA11"; + qcom,glinkpkt-dev-name = "smd11"; + }; + }; + slim_aud: slim@171c0000 { cell-index = <1>; compatible = "qcom,slim-ngd"; @@ -907,6 +1068,7 @@ status = "ok"; }; +#include "sdmshrike-smp2p.dtsi" #include "sdmshrike-pinctrl.dtsi" #include "sdmshrike-regulators.dtsi" #include "sdmshrike-ion.dtsi" -- GitLab From f6f378d650d221aed7f1f145c269a23779dcd820 Mon Sep 17 00:00:00 2001 From: Tatenda Chipeperekwa Date: Tue, 10 Apr 2018 17:51:29 -0700 Subject: [PATCH 0113/1635] drm/msm/dp: fix HDCP error handling Fix the HDCP error handling by removing a call to destroy the shared workqueue. The shared workqueue is needed for other driver events and is destroyed only when the driver is being removed. Change-Id: I568d45fab0580870382c4386814560c88d1902f4 Signed-off-by: Tatenda Chipeperekwa --- drivers/gpu/drm/msm/dp/dp_display.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/msm/dp/dp_display.c b/drivers/gpu/drm/msm/dp/dp_display.c index 14ed515cc791..0e7e6ec931f3 100644 --- a/drivers/gpu/drm/msm/dp/dp_display.c +++ b/drivers/gpu/drm/msm/dp/dp_display.c @@ -203,12 +203,6 @@ static void dp_display_notify_hdcp_status_cb(void *ptr, queue_delayed_work(dp->wq, &dp->hdcp_cb_work, HZ/4); } -static void dp_display_destroy_hdcp_workqueue(struct dp_display_private *dp) -{ - if (dp->wq) - destroy_workqueue(dp->wq); -} - static void dp_display_update_hdcp_info(struct dp_display_private *dp) { void *fd = NULL; @@ -270,7 +264,6 @@ static void dp_display_deinitialize_hdcp(struct dp_display_private *dp) } sde_dp_hdcp2p2_deinit(dp->hdcp.data); - dp_display_destroy_hdcp_workqueue(dp); mutex_destroy(&dp->hdcp_mutex); } @@ -1976,6 +1969,9 @@ static int dp_display_remove(struct platform_device *pdev) dp_display_deinit_sub_modules(dp); + if (dp->wq) + destroy_workqueue(dp->wq); + platform_set_drvdata(pdev, NULL); devm_kfree(&pdev->dev, dp); -- GitLab From 856f908b7b7026d126a7fc6ef58e612bff53112f Mon Sep 17 00:00:00 2001 From: Sungjun Park Date: Tue, 10 Apr 2018 18:16:54 -0700 Subject: [PATCH 0114/1635] defconfig: sm8150: Add support for BT uhid drivers Add support for BT uhid drivers CRs-Fixed: 2218607 Change-Id: I2b414c29ee6f4eedd1c411d2a9c6c16de189cabe Signed-off-by: Sungjun Park --- arch/arm64/configs/sm8150-perf_defconfig | 4 ++++ arch/arm64/configs/sm8150_defconfig | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/arch/arm64/configs/sm8150-perf_defconfig b/arch/arm64/configs/sm8150-perf_defconfig index 926d06fd7b66..bc97892cb5a8 100644 --- a/arch/arm64/configs/sm8150-perf_defconfig +++ b/arch/arm64/configs/sm8150-perf_defconfig @@ -366,7 +366,11 @@ CONFIG_SND_USB_AUDIO_QMI=y CONFIG_SND_SOC=y CONFIG_UHID=y CONFIG_HID_APPLE=y +CONFIG_HID_ELECOM=y +CONFIG_HID_MAGICMOUSE=y CONFIG_HID_MICROSOFT=y +CONFIG_HID_MULTITOUCH=y +CONFIG_HID_PLANTRONICS=y CONFIG_USB=y CONFIG_USB_ANNOUNCE_NEW_DEVICES=y CONFIG_USB_XHCI_HCD=y diff --git a/arch/arm64/configs/sm8150_defconfig b/arch/arm64/configs/sm8150_defconfig index 1557925a6bf9..bc24ba3e0a63 100644 --- a/arch/arm64/configs/sm8150_defconfig +++ b/arch/arm64/configs/sm8150_defconfig @@ -377,7 +377,11 @@ CONFIG_SND_USB_AUDIO_QMI=y CONFIG_SND_SOC=y CONFIG_UHID=y CONFIG_HID_APPLE=y +CONFIG_HID_ELECOM=y +CONFIG_HID_MAGICMOUSE=y CONFIG_HID_MICROSOFT=y +CONFIG_HID_MULTITOUCH=y +CONFIG_HID_PLANTRONICS=y CONFIG_USB=y CONFIG_USB_ANNOUNCE_NEW_DEVICES=y CONFIG_USB_XHCI_HCD=y -- GitLab From e98e812aff57ab3207cbee9b1ca4cdbb2c644cb4 Mon Sep 17 00:00:00 2001 From: muluhe Date: Mon, 9 Apr 2018 17:46:20 +0800 Subject: [PATCH 0115/1635] ARM: dts: msm: coresight: Add spss node for sm8150 Enable spss funnel and spss tpdm for sm8150. Change-Id: I5ae7920099e876e6900287aad6f2cbad71900b46 Signed-off-by: Mulu He --- .../arm64/boot/dts/qcom/sm8150-coresight.dtsi | 100 +++++++++++++++++- 1 file changed, 99 insertions(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/sm8150-coresight.dtsi b/arch/arm64/boot/dts/qcom/sm8150-coresight.dtsi index 07ab05a24ae0..20fb37632442 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-coresight.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-coresight.dtsi @@ -523,6 +523,15 @@ }; port@1 { + reg = <1>; + funnel_in0_in_funnel_spss: endpoint { + slave-mode; + remote-endpoint = + <&funnel_spss_out_funnel_in0>; + }; + }; + + port@2 { reg = <6>; funnel_in0_in_funnel_qatb: endpoint { slave-mode; @@ -531,7 +540,7 @@ }; }; - port@2 { + port@3 { reg = <7>; funnel_in0_in_stm: endpoint { slave-mode; @@ -1016,6 +1025,95 @@ }; }; + funnel_spss: funnel@6883000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b908>; + + reg = <0x6883000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-spss"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + funnel_spss_out_funnel_in0: endpoint { + remote-endpoint = + <&funnel_in0_in_funnel_spss>; + }; + }; + + port@1 { + reg = <0>; + funnel_spss_in_tpda_spss: endpoint { + slave-mode; + remote-endpoint = + <&tpda_spss_out_funnel_spss>; + }; + }; + }; + }; + + tpda_spss: tpda@6882000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b969>; + reg = <0x06882000 0x1000>; + reg-names = "tpda-base"; + + coresight-name = "coresight-tpda-spss"; + + qcom,tpda-atid = <70>; + qcom,cmb-elem-size = <0 32>; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + tpda_spss_out_funnel_spss: endpoint { + remote-endpoint = + <&funnel_spss_in_tpda_spss>; + }; + }; + + port@1 { + reg = <0>; + tpda_spss_in_tpdm_spss: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_spss_out_tpda_spss>; + }; + }; + }; + }; + + tpdm_spss: tpdm@6880000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + reg = <0x6880000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-spss"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + tpdm_spss_out_tpda_spss: endpoint { + remote-endpoint = <&tpda_spss_in_tpdm_spss>; + }; + }; + }; + tpdm_qm: tpdm@69d0000 { compatible = "arm,primecell"; arm,primecell-periphid = <0x0003b968>; -- GitLab From 34301a03ea98288f67fd310e1008456078eab629 Mon Sep 17 00:00:00 2001 From: Gopikrishnaiah Anandan Date: Tue, 10 Apr 2018 19:24:56 -0700 Subject: [PATCH 0116/1635] drm/msm/sde: Update LUT dma under-run handling LUT dma under-run is a recoverable error, remove the panic and add a event log to capture status. Change-Id: I30084df24344cb68df4d874643bb7e3da3c196f3 Signed-off-by: Gopikrishnaiah Anandan --- drivers/gpu/drm/msm/sde/sde_hw_reg_dma_v1.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/msm/sde/sde_hw_reg_dma_v1.c b/drivers/gpu/drm/msm/sde/sde_hw_reg_dma_v1.c index 333a7fda464d..9f2073cb9ca8 100644 --- a/drivers/gpu/drm/msm/sde/sde_hw_reg_dma_v1.c +++ b/drivers/gpu/drm/msm/sde/sde_hw_reg_dma_v1.c @@ -68,6 +68,7 @@ static uint32_t reg_dma_intr_4_status_offset; static uint32_t reg_dma_intr_clear_offset; static uint32_t reg_dma_ctl_trigger_offset; static uint32_t reg_dma_ctl0_reset_offset; +static uint32_t reg_dma_error_clear_mask; typedef int (*reg_dma_internal_ops) (struct sde_reg_dma_setup_ops_cfg *cfg); @@ -530,8 +531,13 @@ static int write_kick_off_v1(struct sde_reg_dma_kickoff_cfg *cfg) SET_UP_REG_DMA_REG(hw, reg_dma); SDE_REG_WRITE(&hw, reg_dma_opmode_offset, BIT(0)); val = SDE_REG_READ(&hw, reg_dma_intr_4_status_offset); - if (val) - SDE_DBG_DUMP("all", "dbg_bus", "vbif_dbg_bus", "panic"); + if (val) { + DRM_DEBUG("LUT dma status %x\n", val); + mask = reg_dma_error_clear_mask; + SDE_REG_WRITE(&hw, reg_dma_intr_clear_offset + sizeof(u32) * 4, + mask); + SDE_EVT32(val); + } SDE_REG_WRITE(&hw, reg_dma_ctl_queue_off[cfg->ctl->idx], cfg->dma_buf->iova); @@ -599,6 +605,7 @@ int init_v1(struct sde_hw_reg_dma *cfg) reg_dma_intr_clear_offset = 0xb0; reg_dma_ctl_trigger_offset = 0xd4; reg_dma_ctl0_reset_offset = 0xe4; + reg_dma_error_clear_mask = BIT(0) | BIT(1) | BIT(2) | BIT(16); reg_dma_ctl_queue_off[CTL_0] = reg_dma_ctl0_queue0_cmd0_offset; for (i = CTL_1; i < ARRAY_SIZE(reg_dma_ctl_queue_off); i++) @@ -628,6 +635,8 @@ int init_v11(struct sde_hw_reg_dma *cfg) reg_dma_intr_clear_offset = 0x1a0; reg_dma_ctl_trigger_offset = 0xd4; reg_dma_ctl0_reset_offset = 0x200; + reg_dma_error_clear_mask = BIT(0) | BIT(1) | BIT(2) | BIT(16) | + BIT(17) | BIT(18); reg_dma_ctl_queue_off[CTL_0] = reg_dma_ctl0_queue0_cmd0_offset; for (i = CTL_1; i < ARRAY_SIZE(reg_dma_ctl_queue_off); i++) -- GitLab From ee84a2e4eec5a0840ade0c7f9071ac3e1c062f87 Mon Sep 17 00:00:00 2001 From: Sujeev Dias Date: Thu, 5 Apr 2018 16:43:29 -0700 Subject: [PATCH 0117/1635] mhi: core: add support for collecting device ram dump during panic For debugging purpose, we'd like to collect device ram dump context when kernel panic happens. This patch adds support for such requirement. CRs-Fixed: 2221004 Change-Id: Ie0e829bd53f777da8d7d94e3261f2f7668e7a844 Signed-off-by: Sujeev Dias --- drivers/bus/mhi/core/mhi_boot.c | 95 +++++++++++++++++++++++++++++ drivers/bus/mhi/core/mhi_internal.h | 1 + drivers/bus/mhi/core/mhi_pm.c | 3 +- 3 files changed, 97 insertions(+), 2 deletions(-) diff --git a/drivers/bus/mhi/core/mhi_boot.c b/drivers/bus/mhi/core/mhi_boot.c index 43efe15a7d38..47276a3ed03e 100644 --- a/drivers/bus/mhi/core/mhi_boot.c +++ b/drivers/bus/mhi/core/mhi_boot.c @@ -11,6 +11,7 @@ */ #include +#include #include #include #include @@ -42,6 +43,97 @@ static void mhi_rddm_prepare(struct mhi_controller *mhi_cntrl, } } +/* collect rddm during kernel panic */ +static int __mhi_download_rddm_in_panic(struct mhi_controller *mhi_cntrl) +{ + int ret; + struct mhi_buf *mhi_buf; + u32 sequence_id; + u32 rx_status; + enum MHI_EE ee; + struct image_info *rddm_image = mhi_cntrl->rddm_image; + const u32 delayus = 100; + u32 retry = (mhi_cntrl->timeout_ms * 1000) / delayus; + void __iomem *base = mhi_cntrl->bhi; + + MHI_LOG("Entered with pm_state:%s dev_state:%s ee:%s\n", + to_mhi_pm_state_str(mhi_cntrl->pm_state), + TO_MHI_STATE_STR(mhi_cntrl->dev_state), + TO_MHI_EXEC_STR(mhi_cntrl->ee)); + + /* + * This should only be executing during a kernel panic, we expect all + * other cores to shutdown while we're collecting rddm buffer. After + * returning from this function, we expect device to reset. + * + * Normaly, we would read/write pm_state only after grabbing + * pm_lock, since we're in a panic, skipping it. + */ + + if (!MHI_REG_ACCESS_VALID(mhi_cntrl->pm_state)) + return -EIO; + + /* + * There is no gurantee this state change would take effect since + * we're setting it w/o grabbing pmlock, it's best effort + */ + mhi_cntrl->pm_state = MHI_PM_LD_ERR_FATAL_DETECT; + /* update should take the effect immediately */ + smp_wmb(); + + /* setup the RX vector table */ + mhi_rddm_prepare(mhi_cntrl, rddm_image); + mhi_buf = &rddm_image->mhi_buf[rddm_image->entries - 1]; + + MHI_LOG("Starting BHIe programming for RDDM\n"); + + mhi_write_reg(mhi_cntrl, base, BHIE_RXVECADDR_HIGH_OFFS, + upper_32_bits(mhi_buf->dma_addr)); + + mhi_write_reg(mhi_cntrl, base, BHIE_RXVECADDR_LOW_OFFS, + lower_32_bits(mhi_buf->dma_addr)); + + mhi_write_reg(mhi_cntrl, base, BHIE_RXVECSIZE_OFFS, mhi_buf->len); + sequence_id = prandom_u32() & BHIE_RXVECSTATUS_SEQNUM_BMSK; + + if (unlikely(!sequence_id)) + sequence_id = 1; + + + mhi_write_reg_field(mhi_cntrl, base, BHIE_RXVECDB_OFFS, + BHIE_RXVECDB_SEQNUM_BMSK, BHIE_RXVECDB_SEQNUM_SHFT, + sequence_id); + + MHI_LOG("Trigger device into RDDM mode\n"); + mhi_set_mhi_state(mhi_cntrl, MHI_STATE_SYS_ERR); + + MHI_LOG("Waiting for image download completion\n"); + while (retry--) { + ret = mhi_read_reg_field(mhi_cntrl, base, BHIE_RXVECSTATUS_OFFS, + BHIE_RXVECSTATUS_STATUS_BMSK, + BHIE_RXVECSTATUS_STATUS_SHFT, + &rx_status); + if (ret) + return -EIO; + + if (rx_status == BHIE_RXVECSTATUS_STATUS_XFER_COMPL) { + MHI_LOG("RDDM successfully collected\n"); + return 0; + } + + udelay(delayus); + } + + ee = mhi_get_exec_env(mhi_cntrl); + ret = mhi_read_reg(mhi_cntrl, base, BHIE_RXVECSTATUS_OFFS, &rx_status); + + MHI_ERR("Did not complete RDDM transfer\n"); + MHI_ERR("Current EE:%s\n", TO_MHI_EXEC_STR(ee)); + MHI_ERR("RXVEC_STATUS:0x%x, ret:%d\n", rx_status, ret); + + return -EIO; +} + /* download ramdump image from device */ int mhi_download_rddm_img(struct mhi_controller *mhi_cntrl, bool in_panic) { @@ -56,6 +148,9 @@ int mhi_download_rddm_img(struct mhi_controller *mhi_cntrl, bool in_panic) if (!rddm_image) return -ENOMEM; + if (in_panic) + return __mhi_download_rddm_in_panic(mhi_cntrl); + MHI_LOG("Waiting for device to enter RDDM state from EE:%s\n", TO_MHI_EXEC_STR(mhi_cntrl->ee)); diff --git a/drivers/bus/mhi/core/mhi_internal.h b/drivers/bus/mhi/core/mhi_internal.h index 6b4815f48dbe..62cfe2ab8f5f 100644 --- a/drivers/bus/mhi/core/mhi_internal.h +++ b/drivers/bus/mhi/core/mhi_internal.h @@ -654,6 +654,7 @@ void mhi_write_db(struct mhi_controller *mhi_cntrl, void __iomem *db_addr, void mhi_ring_cmd_db(struct mhi_controller *mhi_cntrl, struct mhi_cmd *mhi_cmd); void mhi_ring_chan_db(struct mhi_controller *mhi_cntrl, struct mhi_chan *mhi_chan); +void mhi_set_mhi_state(struct mhi_controller *mhi_cntrl, enum MHI_STATE state); /* memory allocation methods */ static inline void *mhi_alloc_coherent(struct mhi_controller *mhi_cntrl, diff --git a/drivers/bus/mhi/core/mhi_pm.c b/drivers/bus/mhi/core/mhi_pm.c index 5dee57f117fd..c476a204f28f 100644 --- a/drivers/bus/mhi/core/mhi_pm.c +++ b/drivers/bus/mhi/core/mhi_pm.c @@ -161,8 +161,7 @@ enum MHI_PM_STATE __must_check mhi_tryset_pm_state( return mhi_cntrl->pm_state; } -static void mhi_set_mhi_state(struct mhi_controller *mhi_cntrl, - enum MHI_STATE state) +void mhi_set_mhi_state(struct mhi_controller *mhi_cntrl, enum MHI_STATE state) { if (state == MHI_STATE_RESET) { mhi_write_reg_field(mhi_cntrl, mhi_cntrl->regs, MHICTRL, -- GitLab From 0c3c8033be6a9d4fcd0c5c70eedf0fa6030e674d Mon Sep 17 00:00:00 2001 From: Sujeev Dias Date: Wed, 4 Apr 2018 18:22:23 -0700 Subject: [PATCH 0118/1635] mhi_bus: core: add support for pre-allocating buffers for DL channels Like other transport layers such as rpmsg, add support to pre-allocate buffers for DL data path. So, client drivers do not need to drastically change their implementation when switching to a different transport layer. CRs-Fixed: 2221013 Change-Id: I2e10089295c003a43d1b6f46c7c877a5321f5bc9 Signed-off-by: Sujeev Dias --- Documentation/devicetree/bindings/bus/mhi.txt | 3 ++ drivers/bus/mhi/core/mhi_init.c | 10 ++++ drivers/bus/mhi/core/mhi_internal.h | 2 + drivers/bus/mhi/core/mhi_main.c | 54 +++++++++++++++++++ 4 files changed, 69 insertions(+) diff --git a/Documentation/devicetree/bindings/bus/mhi.txt b/Documentation/devicetree/bindings/bus/mhi.txt index 69a351e84e5c..172ae7b79de4 100644 --- a/Documentation/devicetree/bindings/bus/mhi.txt +++ b/Documentation/devicetree/bindings/bus/mhi.txt @@ -52,6 +52,9 @@ Main node properties: the data pipe. Not involved in active data transfer. BIT(2) : Must switch to doorbell mode whenever MHI M0 state transition happens. + BIT(3) : MHI bus driver pre-allocate buffer for this channel. + If set, clients not allowed to queue buffers. Valid only for DL + direction. - mhi,chan-names Usage: required diff --git a/drivers/bus/mhi/core/mhi_init.c b/drivers/bus/mhi/core/mhi_init.c index 4d5cb568fe88..8f103ed81cd1 100644 --- a/drivers/bus/mhi/core/mhi_init.c +++ b/drivers/bus/mhi/core/mhi_init.c @@ -823,6 +823,16 @@ static int of_parse_ch_cfg(struct mhi_controller *mhi_cntrl, mhi_chan->offload_ch = !!(bit_cfg & MHI_CH_CFG_BIT_OFFLOAD_CH); mhi_chan->db_cfg.reset_req = !!(bit_cfg & MHI_CH_CFG_BIT_DBMODE_RESET_CH); + mhi_chan->pre_alloc = !!(bit_cfg & MHI_CH_CFG_BIT_PRE_ALLOC); + + if (mhi_chan->pre_alloc && + (mhi_chan->dir != DMA_FROM_DEVICE || + mhi_chan->xfer_type != MHI_XFER_BUFFER)) + goto error_chan_cfg; + + /* if mhi host allocate the buffers then client cannot queue */ + if (mhi_chan->pre_alloc) + mhi_chan->queue_xfer = mhi_queue_nop; ret = of_property_read_string_index(of_node, "mhi,chan-names", i, &mhi_chan->name); diff --git a/drivers/bus/mhi/core/mhi_internal.h b/drivers/bus/mhi/core/mhi_internal.h index 62cfe2ab8f5f..f35162baa2de 100644 --- a/drivers/bus/mhi/core/mhi_internal.h +++ b/drivers/bus/mhi/core/mhi_internal.h @@ -339,6 +339,7 @@ enum MHI_CH_CFG { #define MHI_CH_CFG_BIT_LPM_NOTIFY BIT(0) /* require LPM notification */ #define MHI_CH_CFG_BIT_OFFLOAD_CH BIT(1) /* satellite mhi devices */ #define MHI_CH_CFG_BIT_DBMODE_RESET_CH BIT(2) /* require db mode to reset */ +#define MHI_CH_CFG_BIT_PRE_ALLOC BIT(3) /* host allocate buffers for DL */ enum MHI_EV_CFG { MHI_EV_CFG_ELEMENTS = 0, @@ -565,6 +566,7 @@ struct mhi_chan { bool lpm_notify; bool configured; bool offload_ch; + bool pre_alloc; /* functions that generate the transfer ring elements */ int (*gen_tre)(struct mhi_controller *, struct mhi_chan *, void *, void *, size_t, enum MHI_FLAGS); diff --git a/drivers/bus/mhi/core/mhi_main.c b/drivers/bus/mhi/core/mhi_main.c index 82f09418fca3..dede18d63d78 100644 --- a/drivers/bus/mhi/core/mhi_main.c +++ b/drivers/bus/mhi/core/mhi_main.c @@ -23,6 +23,9 @@ #include #include "mhi_internal.h" +static void __mhi_unprepare_channel(struct mhi_controller *mhi_cntrl, + struct mhi_chan *mhi_chan); + int __must_check mhi_read_reg(struct mhi_controller *mhi_cntrl, void __iomem *base, u32 offset, @@ -661,6 +664,22 @@ static int parse_xfer_event(struct mhi_controller *mhi_cntrl, mhi_cntrl->wake_put(mhi_cntrl, false); read_unlock_bh(&mhi_cntrl->pm_lock); } + + /* + * recycle the buffer if buffer is pre-allocated, + * if there is error, not much we can do apart from + * dropping the packet + */ + if (mhi_chan->pre_alloc) { + if (mhi_queue_buf(mhi_chan->mhi_dev, mhi_chan, + buf_info->cb_buf, + buf_info->len, MHI_EOT)) { + MHI_ERR( + "Error recycling buffer for chan:%d\n", + mhi_chan->chan); + kfree(buf_info->cb_buf); + } + } }; break; } /* CC_EOT */ @@ -1086,6 +1105,32 @@ static int __mhi_prepare_channel(struct mhi_controller *mhi_cntrl, mhi_cntrl->wake_put(mhi_cntrl, false); read_unlock_bh(&mhi_cntrl->pm_lock); + /* pre allocate buffer for xfer ring */ + if (mhi_chan->pre_alloc) { + struct mhi_device *mhi_dev = mhi_chan->mhi_dev; + int nr_el = get_nr_avail_ring_elements(mhi_cntrl, + &mhi_chan->tre_ring); + + while (nr_el--) { + void *buf; + + buf = kmalloc(MHI_MAX_MTU, GFP_KERNEL); + if (!buf) { + ret = -ENOMEM; + goto error_pre_alloc; + } + + ret = mhi_queue_buf(mhi_dev, mhi_chan, buf, MHI_MAX_MTU, + MHI_EOT); + if (ret) { + MHI_ERR("Chan:%d error queue buffer\n", + mhi_chan->chan); + kfree(buf); + goto error_pre_alloc; + } + } + } + mutex_unlock(&mhi_chan->mutex); MHI_LOG("Chan:%d successfully moved to start state\n", mhi_chan->chan); @@ -1104,6 +1149,12 @@ static int __mhi_prepare_channel(struct mhi_controller *mhi_cntrl, error_init_chan: mutex_unlock(&mhi_chan->mutex); + return ret; + +error_pre_alloc: + mutex_unlock(&mhi_chan->mutex); + __mhi_unprepare_channel(mhi_cntrl, mhi_chan); + return ret; } @@ -1169,6 +1220,9 @@ void mhi_reset_chan(struct mhi_controller *mhi_cntrl, struct mhi_chan *mhi_chan) buf_info->len, buf_info->dir); mhi_del_ring_element(mhi_cntrl, buf_ring); mhi_del_ring_element(mhi_cntrl, tre_ring); + + if (mhi_chan->pre_alloc) + kfree(buf_info->cb_buf); } read_unlock_bh(&mhi_cntrl->pm_lock); -- GitLab From 2cc0aa9f5ce7b4b8950bcabdea40e75fa70819e2 Mon Sep 17 00:00:00 2001 From: Kiran Gunda Date: Mon, 5 Mar 2018 12:57:59 +0530 Subject: [PATCH 0119/1635] regulator: qpnp-lcdb: Fix LCDB boost voltage configuration The newer version of LCDB uses a 25mV voltage step size for boost, instead of 50mV. Identify the LCDB version and use the appropriate step-size. Change-Id: Ie79b3cc60e937d6ec15d29e599f1bc50a4c32958 Signed-off-by: Kiran Gunda --- drivers/regulator/qpnp-lcdb-regulator.c | 29 ++++++++++++++++++------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/drivers/regulator/qpnp-lcdb-regulator.c b/drivers/regulator/qpnp-lcdb-regulator.c index d263193ab805..2c4003945d4d 100644 --- a/drivers/regulator/qpnp-lcdb-regulator.c +++ b/drivers/regulator/qpnp-lcdb-regulator.c @@ -998,12 +998,13 @@ static irqreturn_t qpnp_lcdb_sc_irq_handler(int irq, void *data) #define VOLTAGE_MIN_STEP_50_MV 4950 #define VOLTAGE_STEP_100_MV 100 #define VOLTAGE_STEP_50_MV 50 +#define VOLTAGE_STEP_25_MV 25 #define VOLTAGE_STEP_50MV_OFFSET 0xA static int qpnp_lcdb_set_bst_voltage(struct qpnp_lcdb *lcdb, int voltage_mv, u8 type) { int rc = 0; - u8 val, mask = 0; + u8 val, voltage_step, mask = 0; int bst_voltage_mv; u16 pmic_subtype = lcdb->pmic_rev_id->pmic_subtype; struct ldo_regulator *ldo = &lcdb->ldo; @@ -1020,10 +1021,16 @@ static int qpnp_lcdb_set_bst_voltage(struct qpnp_lcdb *lcdb, bst_voltage_mv = MAX_BST_VOLTAGE_MV; if (bst_voltage_mv != bst->voltage_mv) { + if (pmic_subtype == PM660L_SUBTYPE) { + mask = PM660_BST_OUTPUT_VOLTAGE_MASK; + voltage_step = VOLTAGE_STEP_50_MV; + } else { + mask = BST_OUTPUT_VOLTAGE_MASK; + voltage_step = VOLTAGE_STEP_25_MV; + } + val = DIV_ROUND_UP(bst_voltage_mv - MIN_BST_VOLTAGE_MV, - VOLTAGE_STEP_50_MV); - mask = (pmic_subtype == PM660L_SUBTYPE) ? - PM660_BST_OUTPUT_VOLTAGE_MASK : BST_OUTPUT_VOLTAGE_MASK; + voltage_step); rc = qpnp_lcdb_masked_write(lcdb, lcdb->base + LCDB_BST_OUTPUT_VOLTAGE_REG, mask, val); @@ -1044,7 +1051,7 @@ static int qpnp_lcdb_get_bst_voltage(struct qpnp_lcdb *lcdb, int *voltage_mv) { int rc; - u8 val, mask = 0; + u8 val, voltage_step, mask = 0; u16 pmic_subtype = lcdb->pmic_rev_id->pmic_subtype; rc = qpnp_lcdb_read(lcdb, lcdb->base + LCDB_BST_OUTPUT_VOLTAGE_REG, @@ -1054,10 +1061,16 @@ static int qpnp_lcdb_get_bst_voltage(struct qpnp_lcdb *lcdb, return rc; } - mask = (pmic_subtype == PM660L_SUBTYPE) ? - PM660_BST_OUTPUT_VOLTAGE_MASK : BST_OUTPUT_VOLTAGE_MASK; + if (pmic_subtype == PM660L_SUBTYPE) { + mask = PM660_BST_OUTPUT_VOLTAGE_MASK; + voltage_step = VOLTAGE_STEP_50_MV; + } else { + mask = BST_OUTPUT_VOLTAGE_MASK; + voltage_step = VOLTAGE_STEP_25_MV; + } + val &= mask; - *voltage_mv = (val * VOLTAGE_STEP_50_MV) + MIN_BST_VOLTAGE_MV; + *voltage_mv = (val * voltage_step) + MIN_BST_VOLTAGE_MV; return 0; } -- GitLab From 924b28ab7b0672e1b7b87407ade695b729c79874 Mon Sep 17 00:00:00 2001 From: Sujeev Dias Date: Thu, 5 Apr 2018 21:18:53 -0700 Subject: [PATCH 0120/1635] mhi_bus: core: notify clients when dropping queued packets MHI clients not required to keep a submitted buffer list, so bus master must callback client with all queued buffer during channel reset. CRs-Fixed: 2221018 Change-Id: I2ac035f6de5951b9656514213b8e03e559d88e95 Signed-off-by: Sujeev Dias --- drivers/bus/mhi/core/mhi_main.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/bus/mhi/core/mhi_main.c b/drivers/bus/mhi/core/mhi_main.c index dede18d63d78..761c0600dd40 100644 --- a/drivers/bus/mhi/core/mhi_main.c +++ b/drivers/bus/mhi/core/mhi_main.c @@ -1166,6 +1166,7 @@ void mhi_reset_chan(struct mhi_controller *mhi_cntrl, struct mhi_chan *mhi_chan) struct mhi_ring *ev_ring, *buf_ring, *tre_ring; unsigned long flags; int chan = mhi_chan->chan; + struct mhi_result result; /* nothing to reset, client don't queue buffers */ if (mhi_chan->offload_ch) @@ -1210,6 +1211,8 @@ void mhi_reset_chan(struct mhi_controller *mhi_cntrl, struct mhi_chan *mhi_chan) /* reset any pending buffers */ buf_ring = &mhi_chan->buf_ring; tre_ring = &mhi_chan->tre_ring; + result.transaction_status = -ENOTCONN; + result.bytes_xferd = 0; while (tre_ring->rp != tre_ring->wp) { struct mhi_buf_info *buf_info = buf_ring->rp; @@ -1221,8 +1224,12 @@ void mhi_reset_chan(struct mhi_controller *mhi_cntrl, struct mhi_chan *mhi_chan) mhi_del_ring_element(mhi_cntrl, buf_ring); mhi_del_ring_element(mhi_cntrl, tre_ring); - if (mhi_chan->pre_alloc) + if (mhi_chan->pre_alloc) { kfree(buf_info->cb_buf); + } else { + result.buf_addr = buf_info->cb_buf; + mhi_chan->xfer_cb(mhi_chan->mhi_dev, &result); + } } read_unlock_bh(&mhi_cntrl->pm_lock); -- GitLab From 1e22c8a7e8d139832f57e9cee34fb96af5458811 Mon Sep 17 00:00:00 2001 From: Mayank Rana Date: Fri, 6 Apr 2018 09:04:58 -0700 Subject: [PATCH 0121/1635] ARM: dts: msm: Fix used SID value with USB audio device on SM8150 Currently USB audio device is using SID as 0x182f. Crash is seen when ADSP is trying to map provided memory. Fix this issue by using correct SID value 0x1b2f with it. Change-Id: I49ad4418b37d8feaa4249eb02b870b54931f58a4 Signed-off-by: Mayank Rana --- arch/arm64/boot/dts/qcom/sm8150-usb.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/sm8150-usb.dtsi b/arch/arm64/boot/dts/qcom/sm8150-usb.dtsi index 38791aeea3da..ccc4391910ed 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-usb.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-usb.dtsi @@ -303,7 +303,7 @@ usb_audio_qmi_dev { compatible = "qcom,usb-audio-qmi-dev"; - iommus = <&apps_smmu 0x182f 0x0>; + iommus = <&apps_smmu 0x1b2f 0x0>; qcom,usb-audio-stream-id = <0xf>; qcom,usb-audio-intr-num = <2>; }; -- GitLab From 0aadcfc5f59f262ec936fd19d1dbdec19e728ee8 Mon Sep 17 00:00:00 2001 From: Mayank Rana Date: Mon, 9 Apr 2018 15:07:25 -0700 Subject: [PATCH 0122/1635] sound: usb: Fix sending disconnect notification to client Client's sockaddress related params are not cached but pointer to sockaddress is cached on receiving request from client. Client's sockaddress pointer is valid only when request related callback is called from QMI framework. Due to invalid sockaddress param USB headset disconnect notification to client is failing. There is unhandle page fault seen when client is sending more request when USB headset is already disconnected. Hence fix this issue by storing sockaddress related params within driver, and use it while sending unsolicited message to client using qmi_send_indication() i.e. USB headset disconnect notification. Change-Id: I569f6aaba9063f3153276bdd4e436644b056cef0 Signed-off-by: Mayank Rana --- sound/usb/usb_audio_qmi_svc.c | 32 +++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/sound/usb/usb_audio_qmi_svc.c b/sound/usb/usb_audio_qmi_svc.c index a422c9b3b628..77a8c62a2e34 100644 --- a/sound/usb/usb_audio_qmi_svc.c +++ b/sound/usb/usb_audio_qmi_svc.c @@ -123,7 +123,8 @@ struct uaudio_qmi_svc { struct qmi_handle *uaudio_svc_hdl; struct work_struct qmi_disconnect_work; struct workqueue_struct *uaudio_wq; - struct sockaddr_qrtr *client_sq; + struct sockaddr_qrtr client_sq; + bool client_connected; ktime_t t_request_recvd; ktime_t t_resp_sent; }; @@ -857,13 +858,15 @@ static void uaudio_disconnect_cb(struct snd_usb_audio *chip) if (atomic_read(&dev->in_use)) { mutex_unlock(&chip->dev_lock); - pr_debug("%s: sending qmi indication disconnect\n", __func__); + pr_debug("%s: sq->sq_family:%x sq->sq_node:%x sq->sq_port:%x\n", + __func__, svc->client_sq.sq_family, + svc->client_sq.sq_node, svc->client_sq.sq_port); disconnect_ind.dev_event = USB_AUDIO_DEV_DISCONNECT_V01; disconnect_ind.slot_id = dev->udev->slot_id; disconnect_ind.controller_num = dev->usb_core_id; disconnect_ind.controller_num_valid = 1; - ret = qmi_send_indication(svc->uaudio_svc_hdl, svc->client_sq, + ret = qmi_send_indication(svc->uaudio_svc_hdl, &svc->client_sq, QMI_UADUIO_STREAM_IND_V01, QMI_UAUDIO_STREAM_IND_MSG_V01_MAX_MSG_LEN, qmi_uaudio_stream_ind_msg_v01_ei, @@ -1017,8 +1020,14 @@ static void handle_uaudio_stream_req(struct qmi_handle *handle, u8 pcm_card_num, pcm_dev_num, direction; int info_idx = -EINVAL, datainterval = -EINVAL, ret = 0; - req_msg = (struct qmi_uaudio_stream_req_msg_v01 *)decoded_msg; + pr_debug("%s: sq_node:%x sq_port:%x sq_family:%x\n", + __func__, sq->sq_node, sq->sq_port, sq->sq_family); + if (!svc->client_connected) { + svc->client_sq = *sq; + svc->client_connected = true; + } + req_msg = (struct qmi_uaudio_stream_req_msg_v01 *)decoded_msg; if (!req_msg->audio_format_valid || !req_msg->bit_rate_valid || !req_msg->number_of_ch_valid || !req_msg->xfer_buff_size_valid) { pr_err("%s: invalid request msg\n", __func__); @@ -1049,7 +1058,6 @@ static void handle_uaudio_stream_req(struct qmi_handle *handle, goto response; } - svc->client_sq = sq; subs = find_snd_usb_substream(pcm_card_num, pcm_dev_num, direction, &chip, uaudio_disconnect_cb); if (!subs || !chip || atomic_read(&chip->shutdown)) { @@ -1185,15 +1193,13 @@ static void uaudio_qmi_svc_disconnect_cb(struct qmi_handle *handle, return; } - if (svc->client_sq == NULL) { - pr_debug("%s: client is not connected.\n", __func__); - return; - } - - if (svc->client_sq->sq_node == node && - svc->client_sq->sq_port == port) { + if (svc->client_connected && svc->client_sq.sq_node == node && + svc->client_sq.sq_port == port) { queue_work(svc->uaudio_wq, &svc->qmi_disconnect_work); - svc->client_sq = NULL; + svc->client_sq.sq_node = 0; + svc->client_sq.sq_port = 0; + svc->client_sq.sq_family = 0; + svc->client_connected = false; } } -- GitLab From f65a79666ff6ab877db3f532975728091a529c4a Mon Sep 17 00:00:00 2001 From: Rama Krishna Phani A Date: Wed, 21 Mar 2018 15:37:56 +0530 Subject: [PATCH 0123/1635] msm: pcie: Add proper check before accessing variables Add proper check before accessing variables. Change-Id: Idb4aec6e276d7c82a4311be733fcb13b875ae6c8 Signed-off-by: Rama Krishna Phani A --- drivers/pci/host/pci-msm.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/drivers/pci/host/pci-msm.c b/drivers/pci/host/pci-msm.c index 86a179f0fe3b..1201f208d2c2 100644 --- a/drivers/pci/host/pci-msm.c +++ b/drivers/pci/host/pci-msm.c @@ -1549,6 +1549,13 @@ static void msm_pcie_sel_debug_testcase(struct msm_pcie_dev_t *dev, break; } + if (((base_sel - 1) >= MSM_PCIE_MAX_RES) || + (!dev->res[base_sel - 1].resource)) { + PCIE_DBG_FS(dev, "PCIe: RC%d Resource does not exist\n", + dev->rc_idx); + break; + } + PCIE_DBG_FS(dev, "base: %s: 0x%pK\nwr_offset: 0x%x\nwr_mask: 0x%x\nwr_value: 0x%x\n", dev->res[base_sel - 1].name, @@ -1568,6 +1575,13 @@ static void msm_pcie_sel_debug_testcase(struct msm_pcie_dev_t *dev, break; case MSM_PCIE_DUMP_PCIE_REGISTER_SPACE: + if (((base_sel - 1) >= MSM_PCIE_MAX_RES) || + (!dev->res[base_sel - 1].resource)) { + PCIE_DBG_FS(dev, "PCIe: RC%d Resource does not exist\n", + dev->rc_idx); + break; + } + if (!base_sel) { PCIE_DBG_FS(dev, "Invalid base_sel: 0x%x\n", base_sel); break; -- GitLab From 5d5c2e53d3563bb4e630d1e0ebba35beda8f15db Mon Sep 17 00:00:00 2001 From: Govinda Rajulu Chenna Date: Tue, 10 Apr 2018 17:16:27 -0400 Subject: [PATCH 0124/1635] drm/msm/dp: fix atomic_best_enc select for DP MST connectors Use already selected encoder for mst connector in case atomic_best_encoder op is called multiple times during drm atomic commit cycle. CRs-Fixed: 2192818 Change-Id: I7f9093c8edd101221025acc4e395d1a1478e2070 Signed-off-by: Govinda Rajulu Chenna --- drivers/gpu/drm/msm/dp/dp_mst_drm.c | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/msm/dp/dp_mst_drm.c b/drivers/gpu/drm/msm/dp/dp_mst_drm.c index f2909e6d7dcf..c9726552e216 100644 --- a/drivers/gpu/drm/msm/dp/dp_mst_drm.c +++ b/drivers/gpu/drm/msm/dp/dp_mst_drm.c @@ -366,7 +366,7 @@ static bool _dp_mst_compute_config(struct dp_mst_bridge *dp_bridge) dp_bridge->slots = slots; - DP_MST_DEBUG("mst bridge [%d] pbn: %d slots: %d", dp_bridge->id, + DP_MST_DEBUG("mst bridge [%d] pbn: %d slots: %d\n", dp_bridge->id, mst_pbn, slots); return true; @@ -798,24 +798,35 @@ dp_mst_atomic_best_encoder(struct drm_connector *connector, struct dp_display *dp_display = display; struct dp_mst_private *mst = dp_display->dp_mst_prv_info; struct sde_connector *conn = to_sde_connector(connector); + struct drm_encoder *enc = NULL; u32 i; - DP_MST_DEBUG("mst connector:%d atomic best encoder\n", - connector->base.id); + for (i = 0; i < MAX_DP_MST_DRM_BRIDGES; i++) { + if (mst->mst_bridge[i].connector == connector) { + enc = mst->mst_bridge[i].encoder; + goto end; + } + } for (i = 0; i < MAX_DP_MST_DRM_BRIDGES; i++) { if (!mst->mst_bridge[i].encoder_active_sts) { mst->mst_bridge[i].encoder_active_sts = true; mst->mst_bridge[i].connector = connector; mst->mst_bridge[i].dp_panel = conn->drv_panel; - return mst->mst_bridge[i].encoder; + enc = mst->mst_bridge[i].encoder; + break; } } - DP_MST_DEBUG("mst connector:%d atomic best encoder failed\n", - connector->base.id); +end: + if (enc) + DP_MST_DEBUG("mst connector:%d atomic best encoder:%d\n", + connector->base.id, i); + else + DP_MST_DEBUG("mst connector:%d atomic best encoder failed\n", + connector->base.id); - return NULL; + return enc; } static struct dp_mst_bridge *_dp_mst_get_bridge_from_encoder( -- GitLab From 28cc1a89e6ca9f398defaab07d837d182b5274b8 Mon Sep 17 00:00:00 2001 From: Govinda Rajulu Chenna Date: Tue, 10 Apr 2018 13:28:30 -0400 Subject: [PATCH 0125/1635] ARM: dts: msm: enable DP MST mode for sm8150 Add mst-enable node to enable DisplayPort multi stream transport support for sm8150. CRs-Fixed: 2192818 Change-Id: I72186544d9c0d8a7a1927a95d4ec3aef15ec92df Signed-off-by: Govinda Rajulu Chenna --- arch/arm64/boot/dts/qcom/sm8150-sde.dtsi | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sm8150-sde.dtsi b/arch/arm64/boot/dts/qcom/sm8150-sde.dtsi index e9aecdb0046f..f217c1b50857 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-sde.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-sde.dtsi @@ -671,6 +671,8 @@ qcom,max-pclk-frequency-khz = <675000>; + qcom,mst-enable; + qcom,ctrl-supply-entries { #address-cells = <1>; #size-cells = <0>; -- GitLab From 2a624ee5ae9915b2f33d3214972fd817f446ae57 Mon Sep 17 00:00:00 2001 From: Avaneesh Kumar Dwivedi Date: Tue, 10 Apr 2018 23:24:42 +0530 Subject: [PATCH 0126/1635] drivers: soc: qcom: Add missing SCM call parameters Add additional register to save arguments during secure call. Change-Id: I712a708ba0e82ce28de0de37a517379d0d3f4a4c Signed-off-by: Avaneesh Kumar Dwivedi --- drivers/soc/qcom/scm.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/soc/qcom/scm.c b/drivers/soc/qcom/scm.c index e82861ee563b..0e04600364e5 100644 --- a/drivers/soc/qcom/scm.c +++ b/drivers/soc/qcom/scm.c @@ -80,6 +80,7 @@ DEFINE_MUTEX(scm_lmh_lock); #define R3_STR "r3" #define R4_STR "r4" #define R5_STR "r5" +#define R6_STR "r6" #endif -- GitLab From 9bfe631c23a5d66275dbb71c3319d29c8be60b12 Mon Sep 17 00:00:00 2001 From: Avaneesh Kumar Dwivedi Date: Tue, 20 Mar 2018 13:47:56 +0530 Subject: [PATCH 0127/1635] arm: process: Fix compilation issue due to repetition of code Remove the repeated set of functions. Change-Id: I4438b745dbdfa787d880c4236ce7930513f91f06 Signed-off-by: Avaneesh Kumar Dwivedi --- arch/arm/kernel/process.c | 71 --------------------------------------- 1 file changed, 71 deletions(-) diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c index b07664f750ea..02f9924de7f2 100644 --- a/arch/arm/kernel/process.c +++ b/arch/arm/kernel/process.c @@ -167,77 +167,6 @@ static void show_extra_register_data(struct pt_regs *regs, int nbytes) set_fs(fs); } -/* - * dump a block of kernel memory from around the given address - */ -static void show_data(unsigned long addr, int nbytes, const char *name) -{ - int i, j; - int nlines; - u32 *p; - - /* - * don't attempt to dump non-kernel addresses or - * values that are probably just small negative numbers - */ - if (addr < PAGE_OFFSET || addr > -256UL) - return; - - printk("\n%s: %#lx:\n", name, addr); - - /* - * round address down to a 32 bit boundary - * and always dump a multiple of 32 bytes - */ - p = (u32 *)(addr & ~(sizeof(u32) - 1)); - nbytes += (addr & (sizeof(u32) - 1)); - nlines = (nbytes + 31) / 32; - - - for (i = 0; i < nlines; i++) { - /* - * just display low 16 bits of address to keep - * each line of the dump < 80 characters - */ - printk("%04lx ", (unsigned long)p & 0xffff); - for (j = 0; j < 8; j++) { - u32 data; - if (probe_kernel_address(p, data)) { - printk(" ********"); - } else { - printk(" %08x", data); - } - ++p; - } - printk("\n"); - } -} - -static void show_extra_register_data(struct pt_regs *regs, int nbytes) -{ - mm_segment_t fs; - - fs = get_fs(); - set_fs(KERNEL_DS); - show_data(regs->ARM_pc - nbytes, nbytes * 2, "PC"); - show_data(regs->ARM_lr - nbytes, nbytes * 2, "LR"); - show_data(regs->ARM_sp - nbytes, nbytes * 2, "SP"); - show_data(regs->ARM_ip - nbytes, nbytes * 2, "IP"); - show_data(regs->ARM_fp - nbytes, nbytes * 2, "FP"); - show_data(regs->ARM_r0 - nbytes, nbytes * 2, "R0"); - show_data(regs->ARM_r1 - nbytes, nbytes * 2, "R1"); - show_data(regs->ARM_r2 - nbytes, nbytes * 2, "R2"); - show_data(regs->ARM_r3 - nbytes, nbytes * 2, "R3"); - show_data(regs->ARM_r4 - nbytes, nbytes * 2, "R4"); - show_data(regs->ARM_r5 - nbytes, nbytes * 2, "R5"); - show_data(regs->ARM_r6 - nbytes, nbytes * 2, "R6"); - show_data(regs->ARM_r7 - nbytes, nbytes * 2, "R7"); - show_data(regs->ARM_r8 - nbytes, nbytes * 2, "R8"); - show_data(regs->ARM_r9 - nbytes, nbytes * 2, "R9"); - show_data(regs->ARM_r10 - nbytes, nbytes * 2, "R10"); - set_fs(fs); -} - void __show_regs(struct pt_regs *regs) { unsigned long flags; -- GitLab From 904335e7645432c7300c3d1074bd1935f12cc3ee Mon Sep 17 00:00:00 2001 From: Maria Yu Date: Tue, 26 Sep 2017 14:29:02 +0800 Subject: [PATCH 0128/1635] PM / wakeup: Fix error when CONFIG_QCOM_SHOW_RESUME_IRQ not defined Set msm_show_resume_irq_mask to 0 when CONFIG_QCOM_SHOW_RESUME_IRQ is not defined. Change-Id: I6637d384051665f02a0e36d24189429813c88188 Signed-off-by: Maria Yu --- drivers/base/power/power.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/base/power/power.h b/drivers/base/power/power.h index 635f26b61a87..6ea0115f69e8 100644 --- a/drivers/base/power/power.h +++ b/drivers/base/power/power.h @@ -132,7 +132,11 @@ extern int pm_async_enabled; /* drivers/base/power/main.c */ extern struct list_head dpm_list; /* The active device list */ +#ifdef CONFIG_QCOM_SHOW_RESUME_IRQ extern int msm_show_resume_irq_mask; +#else +#define msm_show_resume_irq_mask 0 +#endif static inline struct device *to_device(struct list_head *entry) { -- GitLab From 311544c2d05a5a30c9ffea7a1a820588b7ee8412 Mon Sep 17 00:00:00 2001 From: Avaneesh Kumar Dwivedi Date: Tue, 10 Apr 2018 23:12:45 +0530 Subject: [PATCH 0129/1635] defconfig: qcs405: enable required configs for SMP enablement Enable PSCI, SCM and CPUIDLE configs to boot SMP. Change-Id: Iffb2141a2c13137991b5ef1c52c0c8293cec0b4c Signed-off-by: Avaneesh Kumar Dwivedi --- arch/arm/configs/qcs405-perf_defconfig | 3 +++ arch/arm/configs/qcs405_defconfig | 3 +++ arch/arm64/configs/qcs405-perf_defconfig | 3 +++ arch/arm64/configs/qcs405_defconfig | 3 +++ 4 files changed, 12 insertions(+) diff --git a/arch/arm/configs/qcs405-perf_defconfig b/arch/arm/configs/qcs405-perf_defconfig index 4cc91738ca57..524888761576 100644 --- a/arch/arm/configs/qcs405-perf_defconfig +++ b/arch/arm/configs/qcs405-perf_defconfig @@ -30,6 +30,7 @@ CONFIG_PARTITION_ADVANCED=y CONFIG_ARCH_QCOM=y CONFIG_ARCH_QCS405=y # CONFIG_VDSO is not set +CONFIG_ARM_PSCI=y CONFIG_PREEMPT=y CONFIG_CLEANCACHE=y CONFIG_CMA=y @@ -37,6 +38,7 @@ CONFIG_ZSMALLOC=y CONFIG_SECCOMP=y CONFIG_BUILD_ARM_APPENDED_DTB_IMAGE=y CONFIG_CPU_IDLE=y +CONFIG_ARM_CPUIDLE=y CONFIG_VFP=y # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set CONFIG_PM_AUTOSLEEP=y @@ -310,6 +312,7 @@ CONFIG_ION=y CONFIG_HWSPINLOCK=y CONFIG_MAILBOX=y CONFIG_QCOM_SMEM=y +CONFIG_QCOM_SCM=y CONFIG_MSM_SUBSYSTEM_RESTART=y CONFIG_MSM_PIL=y CONFIG_MSM_BOOT_STATS=y diff --git a/arch/arm/configs/qcs405_defconfig b/arch/arm/configs/qcs405_defconfig index d03f31a38a59..3b1846324784 100644 --- a/arch/arm/configs/qcs405_defconfig +++ b/arch/arm/configs/qcs405_defconfig @@ -33,6 +33,7 @@ CONFIG_ARCH_QCOM=y CONFIG_ARCH_QCS405=y # CONFIG_VDSO is not set CONFIG_SMP=y +CONFIG_ARM_PSCI=y CONFIG_PREEMPT=y CONFIG_CLEANCACHE=y CONFIG_CMA=y @@ -41,6 +42,7 @@ CONFIG_ZSMALLOC=y CONFIG_SECCOMP=y CONFIG_BUILD_ARM_APPENDED_DTB_IMAGE=y CONFIG_CPU_IDLE=y +CONFIG_ARM_CPUIDLE=y CONFIG_VFP=y # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set CONFIG_PM_AUTOSLEEP=y @@ -323,6 +325,7 @@ CONFIG_QCOM_LAZY_MAPPING=y CONFIG_IOMMU_DEBUG=y CONFIG_QCOM_IOMMU=y CONFIG_QCOM_SMEM=y +CONFIG_QCOM_SCM=y CONFIG_MSM_SUBSYSTEM_RESTART=y CONFIG_MSM_PIL=y CONFIG_MSM_BOOT_STATS=y diff --git a/arch/arm64/configs/qcs405-perf_defconfig b/arch/arm64/configs/qcs405-perf_defconfig index f693c01d810f..96bb84b3af43 100644 --- a/arch/arm64/configs/qcs405-perf_defconfig +++ b/arch/arm64/configs/qcs405-perf_defconfig @@ -42,6 +42,7 @@ CONFIG_PM_WAKELOCKS=y CONFIG_PM_WAKELOCKS_LIMIT=0 # CONFIG_PM_WAKELOCKS_GC is not set CONFIG_CPU_IDLE=y +CONFIG_ARM_CPUIDLE=y CONFIG_NET=y CONFIG_PACKET=y CONFIG_UNIX=y @@ -165,6 +166,7 @@ CONFIG_NET_EMATCH_U32=y CONFIG_NET_EMATCH_META=y CONFIG_NET_EMATCH_TEXT=y CONFIG_NET_CLS_ACT=y +CONFIG_QRTR=y CONFIG_RMNET_DATA=y CONFIG_RMNET_DATA_FC=y CONFIG_BT=y @@ -312,6 +314,7 @@ CONFIG_ION=y CONFIG_HWSPINLOCK=y CONFIG_MAILBOX=y CONFIG_IOMMU_IO_PGTABLE_LPAE=y +CONFIG_QCOM_QMI_HELPERS=y CONFIG_QCOM_SMEM=y CONFIG_QCOM_SCM=y CONFIG_MSM_SUBSYSTEM_RESTART=y diff --git a/arch/arm64/configs/qcs405_defconfig b/arch/arm64/configs/qcs405_defconfig index 4c23c8ff8396..d0b57cdf51d2 100644 --- a/arch/arm64/configs/qcs405_defconfig +++ b/arch/arm64/configs/qcs405_defconfig @@ -48,6 +48,7 @@ CONFIG_PM_WAKELOCKS_LIMIT=0 # CONFIG_PM_WAKELOCKS_GC is not set CONFIG_PM_DEBUG=y CONFIG_CPU_IDLE=y +CONFIG_ARM_CPUIDLE=y CONFIG_NET=y CONFIG_PACKET=y CONFIG_UNIX=y @@ -172,6 +173,7 @@ CONFIG_NET_EMATCH_U32=y CONFIG_NET_EMATCH_META=y CONFIG_NET_EMATCH_TEXT=y CONFIG_NET_CLS_ACT=y +CONFIG_QRTR=y CONFIG_RMNET_DATA=y CONFIG_RMNET_DATA_FC=y CONFIG_RMNET_DATA_DEBUG_PKT=y @@ -325,6 +327,7 @@ CONFIG_HWSPINLOCK=y CONFIG_MAILBOX=y CONFIG_IOMMU_IO_PGTABLE_LPAE=y CONFIG_QCOM_LAZY_MAPPING=y +CONFIG_QCOM_QMI_HELPERS=y CONFIG_QCOM_SMEM=y CONFIG_QCOM_SCM=y CONFIG_MSM_SUBSYSTEM_RESTART=y -- GitLab From d826849b08fb32f849de52ca0f4bba64e4fcd971 Mon Sep 17 00:00:00 2001 From: Yuan Zhao Date: Wed, 11 Apr 2018 15:39:49 +0800 Subject: [PATCH 0130/1635] ARM: dts: msm: modify the panel setting for SM8150 QRD device Remove the brightness setting code from panel initialize parameters and enable ESD check. Change-Id: I255ff37a0d65d3d437aed6ad806db4478cdb06a1 Signed-off-by: Yuan Zhao --- .../dts/qcom/dsi-panel-sw43404-amoled-dsc-wqhd-cmd.dtsi | 5 ++--- arch/arm64/boot/dts/qcom/sm8150-qrd.dtsi | 2 +- arch/arm64/boot/dts/qcom/sm8150-sde-display.dtsi | 9 ++++++++- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-sw43404-amoled-dsc-wqhd-cmd.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-sw43404-amoled-dsc-wqhd-cmd.dtsi index f536c227f161..c7e17b531b90 100644 --- a/arch/arm64/boot/dts/qcom/dsi-panel-sw43404-amoled-dsc-wqhd-cmd.dtsi +++ b/arch/arm64/boot/dts/qcom/dsi-panel-sw43404-amoled-dsc-wqhd-cmd.dtsi @@ -33,7 +33,7 @@ qcom,mdss-dsi-dma-trigger = "trigger_sw"; qcom,mdss-dsi-mdp-trigger = "none"; qcom,mdss-dsi-reset-sequence = <1 10>, <0 10>, <1 10>; - qcom,mdss-dsi-bl-max-level = <255>; + qcom,mdss-dsi-bl-max-level = <1023>; qcom,mdss-dsi-te-pin-select = <1>; qcom,mdss-dsi-wr-mem-start = <0x2c>; qcom,mdss-dsi-wr-mem-continue = <0x3c>; @@ -80,8 +80,7 @@ 05 01 00 00 1e 00 02 11 00 39 01 00 00 00 00 03 b0 a5 00 05 01 00 00 78 00 02 35 00 - 05 01 00 00 00 00 02 29 00 - 39 01 00 00 3c 00 03 51 80 03 + 05 01 00 00 3c 00 02 29 00 ]; qcom,mdss-dsi-off-command = [ diff --git a/arch/arm64/boot/dts/qcom/sm8150-qrd.dtsi b/arch/arm64/boot/dts/qcom/sm8150-qrd.dtsi index 5ef91a3b0907..5a4c35e1acc2 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-qrd.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-qrd.dtsi @@ -160,7 +160,7 @@ qcom,panel-supply-entries = <&dsi_panel_pwr_supply_vdd_no_labibb>; qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; qcom,mdss-dsi-bl-min-level = <1>; - qcom,mdss-dsi-bl-max-level = <255>; + qcom,mdss-dsi-bl-max-level = <1023>; qcom,mdss-dsi-mode-sel-gpio-state = "single_port"; qcom,panel-mode-gpio = <&tlmm 7 0>; qcom,platform-te-gpio = <&tlmm 8 0>; diff --git a/arch/arm64/boot/dts/qcom/sm8150-sde-display.dtsi b/arch/arm64/boot/dts/qcom/sm8150-sde-display.dtsi index f81aafcb168b..e3d26edf7e10 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-sde-display.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-sde-display.dtsi @@ -760,11 +760,18 @@ &dsi_sw43404_amoled_cmd { qcom,mdss-dsi-t-clk-post = <0x16>; qcom,mdss-dsi-t-clk-pre = <0x16>; + qcom,esd-check-enabled; + qcom,mdss-dsi-panel-status-check-mode = "reg_read"; + qcom,mdss-dsi-panel-status-command = [06 01 00 01 00 00 01 0a]; + qcom,mdss-dsi-panel-status-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-status-value = <0x9c>; + qcom,mdss-dsi-panel-on-check-value = <0x9c>; + qcom,mdss-dsi-panel-status-read-length = <1>; qcom,mdss-dsi-display-timings { timing@0 { qcom,mdss-dsi-panel-phy-timings = [00 1a 07 06 22 21 07 07 04 03 04 00 16 16]; - qcom,display-topology = <2 2 1>; + qcom,display-topology = <1 1 1>; qcom,default-topology-index = <0>; }; }; -- GitLab From 294f32a767456d1b673cbe711e1ed67e07eb0784 Mon Sep 17 00:00:00 2001 From: Gidon Studinski Date: Wed, 11 Apr 2018 15:28:21 +0300 Subject: [PATCH 0131/1635] wil6210: initialize TX and RX enhanced DMA rings Enhanced DMA design includes the following rings: - Single RX descriptor ring is used for all VIFs - Multiple RX status rings are supported, to allow RSS - TX descriptor ring is allocated per connection - A single TX status ring is used for all TX descriptor rings This patch initializes and frees the above descriptor and status rings. The RX SKBs are handled by a new entity of RX buffers manager, which handles RX buffers, each one points to an allocated SKB. During Rx completion processing, the driver extracts a buffer ID which is used as an index to the buffers array. After the SKB is freed the buffer is moved from the 'active' list to the 'free' list, indicating it can be used for another descriptor. During Rx refill, SKBs are allocated and attached to 'free' buffers. Those buffers are attached to new descriptors and moved to the 'active' list. Change-Id: Ia87d1c7197c97951e54f7be930ae808682e2644f Signed-off-by: Gidon Studinski Signed-off-by: Maya Erez --- drivers/net/wireless/ath/wil6210/Makefile | 1 + drivers/net/wireless/ath/wil6210/debugfs.c | 1 + drivers/net/wireless/ath/wil6210/ethtool.c | 2 +- drivers/net/wireless/ath/wil6210/interrupt.c | 21 + drivers/net/wireless/ath/wil6210/main.c | 74 +- drivers/net/wireless/ath/wil6210/pcie_bus.c | 51 +- drivers/net/wireless/ath/wil6210/txrx.c | 90 ++- drivers/net/wireless/ath/wil6210/txrx.h | 8 + drivers/net/wireless/ath/wil6210/txrx_edma.c | 741 +++++++++++++++++++ drivers/net/wireless/ath/wil6210/txrx_edma.h | 46 +- drivers/net/wireless/ath/wil6210/wil6210.h | 81 +- drivers/net/wireless/ath/wil6210/wmi.c | 311 +++++++- drivers/net/wireless/ath/wil6210/wmi.h | 166 ++++- 13 files changed, 1465 insertions(+), 128 deletions(-) create mode 100644 drivers/net/wireless/ath/wil6210/txrx_edma.c diff --git a/drivers/net/wireless/ath/wil6210/Makefile b/drivers/net/wireless/ath/wil6210/Makefile index 7193eddadbba..2bca87b06c65 100644 --- a/drivers/net/wireless/ath/wil6210/Makefile +++ b/drivers/net/wireless/ath/wil6210/Makefile @@ -10,6 +10,7 @@ wil6210-y += sysfs.o wil6210-y += wmi.o wil6210-y += interrupt.o wil6210-y += txrx.o +wil6210-y += txrx_edma.o wil6210-y += debug.o wil6210-y += rx_reorder.o wil6210-y += ioctl.o diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c index 193de567cdd5..484e15df04de 100644 --- a/drivers/net/wireless/ath/wil6210/debugfs.c +++ b/drivers/net/wireless/ath/wil6210/debugfs.c @@ -1899,6 +1899,7 @@ static const struct dbg_off dbg_wil_off[] = { WIL_FIELD(abft_len, 0644, doff_u8), WIL_FIELD(wakeup_trigger, 0644, doff_u8), WIL_FIELD(ring_idle_trsh, 0644, doff_u32), + WIL_FIELD(num_rx_status_rings, 0644, doff_u8), {}, }; diff --git a/drivers/net/wireless/ath/wil6210/ethtool.c b/drivers/net/wireless/ath/wil6210/ethtool.c index e7ff41e623d2..a04c87ffd37b 100644 --- a/drivers/net/wireless/ath/wil6210/ethtool.c +++ b/drivers/net/wireless/ath/wil6210/ethtool.c @@ -101,7 +101,7 @@ static int wil_ethtoolops_set_coalesce(struct net_device *ndev, if (ret < 0) return ret; - wil_configure_interrupt_moderation(wil); + wil->txrx_ops.configure_interrupt_moderation(wil); wil_pm_runtime_put(wil); diff --git a/drivers/net/wireless/ath/wil6210/interrupt.c b/drivers/net/wireless/ath/wil6210/interrupt.c index 84e9840c1752..311d48233165 100644 --- a/drivers/net/wireless/ath/wil6210/interrupt.c +++ b/drivers/net/wireless/ath/wil6210/interrupt.c @@ -186,6 +186,27 @@ void wil_unmask_irq(struct wil6210_priv *wil) wil6210_unmask_irq_misc(wil, true); } +void wil_configure_interrupt_moderation_edma(struct wil6210_priv *wil) +{ + u32 moderation; + + wil_s(wil, RGF_INT_GEN_IDLE_TIME_LIMIT, WIL_EDMA_IDLE_TIME_LIMIT_USEC); + + wil_s(wil, RGF_INT_GEN_TIME_UNIT_LIMIT, WIL_EDMA_TIME_UNIT_CLK_CYCLES); + + /* Update RX and TX moderation */ + moderation = wil->rx_max_burst_duration | + (WIL_EDMA_AGG_WATERMARK << WIL_EDMA_AGG_WATERMARK_POS); + wil_w(wil, RGF_INT_CTRL_INT_GEN_CFG_0, moderation); + wil_w(wil, RGF_INT_CTRL_INT_GEN_CFG_1, moderation); + + /* Treat special events as regular + * (set bit 0 to 0x1 and clear bits 1-8) + */ + wil_c(wil, RGF_INT_COUNT_ON_SPECIAL_EVT, 0x1FE); + wil_s(wil, RGF_INT_COUNT_ON_SPECIAL_EVT, 0x1); +} + void wil_configure_interrupt_moderation(struct wil6210_priv *wil) { struct wireless_dev *wdev = wil->main_ndev->ieee80211_ptr; diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index 2f397f3aede8..96e250eaecdc 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c @@ -21,11 +21,13 @@ #include "wil6210.h" #include "txrx.h" +#include "txrx_edma.h" #include "wmi.h" #include "boot_loader.h" #define WAIT_FOR_HALP_VOTE_MS 100 #define WAIT_FOR_SCAN_ABORT_MS 1000 +#define WIL_DEFAULT_NUM_RX_STATUS_RINGS 1 bool debug_fw; /* = false; */ module_param(debug_fw, bool, 0444); @@ -77,9 +79,9 @@ static const struct kernel_param_ops mtu_max_ops = { module_param_cb(mtu_max, &mtu_max_ops, &mtu_max, 0444); MODULE_PARM_DESC(mtu_max, " Max MTU value."); -static uint rx_ring_order = WIL_RX_RING_SIZE_ORDER_DEFAULT; -static uint tx_ring_order = WIL_TX_RING_SIZE_ORDER_DEFAULT; -static uint bcast_ring_order = WIL_BCAST_RING_SIZE_ORDER_DEFAULT; +static uint rx_ring_order = WIL_RX_RING_SIZE_ORDER_DEFAULT; +static uint tx_ring_order = WIL_TX_RING_SIZE_ORDER_DEFAULT; +static uint bcast_ring_order = WIL_BCAST_RING_SIZE_ORDER_DEFAULT; static int ring_order_set(const char *val, const struct kernel_param *kp) { @@ -160,6 +162,37 @@ void wil_memcpy_toio_32(volatile void __iomem *dst, const void *src, } } +static void wil_ring_fini_tx(struct wil6210_priv *wil, int id) +{ + struct wil_ring *ring = &wil->ring_tx[id]; + struct wil_ring_tx_data *txdata = &wil->ring_tx_data[id]; + + lockdep_assert_held(&wil->mutex); + + if (!ring->va) + return; + + wil_dbg_misc(wil, "vring_fini_tx: id=%d\n", id); + + spin_lock_bh(&txdata->lock); + txdata->dot1x_open = false; + txdata->mid = U8_MAX; + txdata->enabled = 0; /* no Tx can be in progress or start anew */ + spin_unlock_bh(&txdata->lock); + /* napi_synchronize waits for completion of the current NAPI but will + * not prevent the next NAPI run. + * Add a memory barrier to guarantee that txdata->enabled is zeroed + * before napi_synchronize so that the next scheduled NAPI will not + * handle this vring + */ + wmb(); + /* make sure NAPI won't touch this vring */ + if (test_bit(wil_status_napi_en, wil->status)) + napi_synchronize(&wil->napi_tx); + + wil->txrx_ops.ring_fini_tx(wil, ring); +} + static void wil_disconnect_cid(struct wil6210_vif *vif, int cid, u16 reason_code, bool from_event) __acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock) @@ -456,15 +489,16 @@ static void wil_fw_error_worker(struct work_struct *work) static int wil_find_free_ring(struct wil6210_priv *wil) { int i; + int min_ring_id = wil_get_min_tx_ring_id(wil); - for (i = 0; i < WIL6210_MAX_TX_RINGS; i++) { + for (i = min_ring_id; i < WIL6210_MAX_TX_RINGS; i++) { if (!wil->ring_tx[i].va) return i; } return -EINVAL; } -int wil_tx_init(struct wil6210_vif *vif, int cid) +int wil_ring_init_tx(struct wil6210_vif *vif, int cid) { struct wil6210_priv *wil = vif_to_wil(vif); int rc = -EINVAL, ringid; @@ -482,7 +516,8 @@ int wil_tx_init(struct wil6210_vif *vif, int cid) wil_dbg_wmi(wil, "Configure for connection CID %d MID %d ring %d\n", cid, vif->mid, ringid); - rc = wil_vring_init_tx(vif, ringid, 1 << tx_ring_order, cid, 0); + rc = wil->txrx_ops.ring_init_tx(vif, ringid, 1 << tx_ring_order, + cid, 0); if (rc) wil_err(wil, "init TX for CID %d MID %d vring %d failed\n", cid, vif->mid, ringid); @@ -504,7 +539,7 @@ int wil_bcast_init(struct wil6210_vif *vif) return ri; vif->bcast_ring = ri; - rc = wil_vring_init_bcast(vif, ri, 1 << bcast_ring_order); + rc = wil->txrx_ops.ring_init_bcast(vif, ri, 1 << bcast_ring_order); if (rc) vif->bcast_ring = -1; @@ -594,6 +629,9 @@ int wil_priv_init(struct wil6210_priv *wil) wil->reply_mid = U8_MAX; wil->max_vifs = 1; + /* num of rx srings can be updated via debugfs before allocation */ + wil->num_rx_status_rings = WIL_DEFAULT_NUM_RX_STATUS_RINGS; + return 0; out_wmi_wq: @@ -1321,7 +1359,8 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw) rc = wil_target_reset(wil, no_flash); wil6210_clear_irq(wil); wil_enable_irq(wil); - wil_rx_fini(wil); + wil->txrx_ops.rx_fini(wil); + wil->txrx_ops.tx_fini(wil); if (rc) { if (!no_flash) wil_bl_crash_info(wil, true); @@ -1374,7 +1413,6 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw) clear_bit(wil_status_resetting, wil->status); if (load_fw) { - wil_configure_interrupt_moderation(wil); wil_unmask_irq(wil); /* we just started MAC, wait for FW ready */ @@ -1389,6 +1427,8 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw) return rc; } + wil->txrx_ops.configure_interrupt_moderation(wil); + rc = wil_restore_vifs(wil); if (rc) { wil_err(wil, "failed to restore vifs, rc %d\n", rc); @@ -1450,8 +1490,12 @@ int __wil_up(struct wil6210_priv *wil) if (rc) return rc; - /* Rx VRING. After MAC and beacon */ - rc = wil_rx_init(wil, 1 << rx_ring_order); + /* Rx RING. After MAC and beacon */ + rc = wil->txrx_ops.rx_init(wil, 1 << rx_ring_order); + if (rc) + return rc; + + rc = wil->txrx_ops.tx_init(wil); if (rc) return rc; @@ -1613,3 +1657,11 @@ void wil_halp_unvote(struct wil6210_priv *wil) mutex_unlock(&wil->halp.lock); } + +void wil_init_txrx_ops(struct wil6210_priv *wil) +{ + if (wil->use_enhanced_dma_hw) + wil_init_txrx_ops_edma(wil); + else + wil_init_txrx_ops_legacy_dma(wil); +} diff --git a/drivers/net/wireless/ath/wil6210/pcie_bus.c b/drivers/net/wireless/ath/wil6210/pcie_bus.c index 19cf79212a6a..128f4b73adc9 100644 --- a/drivers/net/wireless/ath/wil6210/pcie_bus.c +++ b/drivers/net/wireless/ath/wil6210/pcie_bus.c @@ -32,6 +32,10 @@ static bool ftm_mode; module_param(ftm_mode, bool, 0444); MODULE_PARM_DESC(ftm_mode, " Set factory test mode, default - false"); +static bool use_enhanced_dma_hw = true; +module_param(use_enhanced_dma_hw, bool, 0444); +MODULE_PARM_DESC(use_enhanced_dma_hw, " Use enhanced or legacy DMA HW. Default: true when available"); + #ifdef CONFIG_PM #ifdef CONFIG_PM_SLEEP static int wil6210_pm_notify(struct notifier_block *notify_block, @@ -106,6 +110,7 @@ int wil_set_capabilities(struct wil6210_priv *wil) wil->rgf_fw_assert_code_addr = TALYN_RGF_FW_ASSERT_CODE; wil->rgf_ucode_assert_code_addr = TALYN_RGF_UCODE_ASSERT_CODE; set_bit(hw_capa_no_flash, wil->hw_capa); + wil->use_enhanced_dma_hw = use_enhanced_dma_hw; break; default: wil_err(wil, "Unknown board hardware, chip_id 0x%08x, chip_revision 0x%08x\n", @@ -115,6 +120,8 @@ int wil_set_capabilities(struct wil6210_priv *wil) return -EINVAL; } + wil_init_txrx_ops(wil); + iccm_section = wil_find_fw_mapping("fw_code"); if (!iccm_section) { wil_err(wil, "fw_code section not found in fw_mapping\n"); @@ -270,8 +277,8 @@ static int wil_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id) .fw_recovery = wil_platform_rop_fw_recovery, }; u32 bar_size = pci_resource_len(pdev, 0); - int dma_addr_size[] = {48, 40, 32}; /* keep descending order */ - int i; + int dma_addr_size[] = {64, 48, 40, 32}; /* keep descending order */ + int i, start_idx; /* check HW */ dev_info(&pdev->dev, WIL_NAME @@ -306,24 +313,6 @@ static int wil_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id) goto if_free; } /* rollback to err_plat */ - - /* device supports >32bit addresses */ - for (i = 0; i < ARRAY_SIZE(dma_addr_size); i++) { - rc = dma_set_mask_and_coherent(dev, - DMA_BIT_MASK(dma_addr_size[i])); - if (rc) { - dev_err(dev, "dma_set_mask_and_coherent(%d) failed: %d\n", - dma_addr_size[i], rc); - continue; - } - dev_info(dev, "using dma mask %d", dma_addr_size[i]); - wil->dma_addr_size = dma_addr_size[i]; - break; - } - - if (wil->dma_addr_size == 0) - goto err_plat; - rc = pci_enable_device(pdev); if (rc && pdev->msi_enabled == 0) { wil_err(wil, @@ -363,6 +352,28 @@ static int wil_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id) wil_err(wil, "wil_set_capabilities failed, rc %d\n", rc); goto err_iounmap; } + + /* device supports >32bit addresses. + * for legacy DMA start from 48 bit. + */ + start_idx = wil->use_enhanced_dma_hw ? 0 : 1; + + for (i = start_idx; i < ARRAY_SIZE(dma_addr_size); i++) { + rc = dma_set_mask_and_coherent(dev, + DMA_BIT_MASK(dma_addr_size[i])); + if (rc) { + dev_err(dev, "dma_set_mask_and_coherent(%d) failed: %d\n", + dma_addr_size[i], rc); + continue; + } + dev_info(dev, "using dma mask %d", dma_addr_size[i]); + wil->dma_addr_size = dma_addr_size[i]; + break; + } + + if (wil->dma_addr_size == 0) + goto err_iounmap; + wil6210_clear_irq(wil); /* FW should raise IRQ when ready */ diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c index 6ce9e44fffe2..64a4b1f6e681 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.c +++ b/drivers/net/wireless/ath/wil6210/txrx.c @@ -202,14 +202,13 @@ static void wil_txdesc_unmap(struct device *dev, struct vring_tx_desc *d, } } -static void wil_vring_free(struct wil6210_priv *wil, struct wil_ring *vring, - int tx) +static void wil_vring_free(struct wil6210_priv *wil, struct wil_ring *vring) { struct device *dev = wil_to_dev(wil); size_t sz = vring->size * sizeof(vring->va[0]); lockdep_assert_held(&wil->mutex); - if (tx) { + if (!vring->is_rx) { int vring_index = vring - wil->ring_tx; wil_dbg_misc(wil, "free Tx vring %d [%d] 0x%p:%pad 0x%p\n", @@ -226,7 +225,7 @@ static void wil_vring_free(struct wil6210_priv *wil, struct wil_ring *vring, u16 dmalen; struct wil_ctx *ctx; - if (tx) { + if (!vring->is_rx) { struct vring_tx_desc dd, *d = ⅆ volatile struct vring_tx_desc *_d = &vring->va[vring->swtail].tx.legacy; @@ -843,7 +842,7 @@ static void wil_rx_buf_len_init(struct wil6210_priv *wil) } } -int wil_rx_init(struct wil6210_priv *wil, u16 size) +static int wil_rx_init(struct wil6210_priv *wil, u16 size) { struct wil_ring *vring = &wil->ring_rx; int rc; @@ -858,6 +857,7 @@ int wil_rx_init(struct wil6210_priv *wil, u16 size) wil_rx_buf_len_init(wil); vring->size = size; + vring->is_rx = true; rc = wil_vring_alloc(wil, vring); if (rc) return rc; @@ -872,22 +872,22 @@ int wil_rx_init(struct wil6210_priv *wil, u16 size) return 0; err_free: - wil_vring_free(wil, vring, 0); + wil_vring_free(wil, vring); return rc; } -void wil_rx_fini(struct wil6210_priv *wil) +static void wil_rx_fini(struct wil6210_priv *wil) { struct wil_ring *vring = &wil->ring_rx; wil_dbg_misc(wil, "rx_fini\n"); if (vring->va) - wil_vring_free(wil, vring, 0); + wil_vring_free(wil, vring); } -static inline void wil_tx_data_init(struct wil_ring_tx_data *txdata) +void wil_tx_data_init(struct wil_ring_tx_data *txdata) { spin_lock_bh(&txdata->lock); txdata->dot1x_open = 0; @@ -903,8 +903,8 @@ static inline void wil_tx_data_init(struct wil_ring_tx_data *txdata) spin_unlock_bh(&txdata->lock); } -int wil_vring_init_tx(struct wil6210_vif *vif, int id, int size, - int cid, int tid) +static int wil_vring_init_tx(struct wil6210_vif *vif, int id, int size, + int cid, int tid) { struct wil6210_priv *wil = vif_to_wil(vif); int rc; @@ -946,6 +946,7 @@ int wil_vring_init_tx(struct wil6210_vif *vif, int id, int size, } wil_tx_data_init(txdata); + vring->is_rx = false; vring->size = size; rc = wil_vring_alloc(wil, vring); if (rc) @@ -985,7 +986,7 @@ int wil_vring_init_tx(struct wil6210_vif *vif, int id, int size, txdata->dot1x_open = false; txdata->enabled = 0; spin_unlock_bh(&txdata->lock); - wil_vring_free(wil, vring, 1); + wil_vring_free(wil, vring); wil->ring2cid_tid[id][0] = WIL6210_MAX_CID; wil->ring2cid_tid[id][1] = 0; @@ -1028,6 +1029,7 @@ int wil_vring_init_bcast(struct wil6210_vif *vif, int id, int size) } wil_tx_data_init(txdata); + vring->is_rx = false; vring->size = size; rc = wil_vring_alloc(wil, vring); if (rc) @@ -1065,43 +1067,12 @@ int wil_vring_init_bcast(struct wil6210_vif *vif, int id, int size) txdata->enabled = 0; txdata->dot1x_open = false; spin_unlock_bh(&txdata->lock); - wil_vring_free(wil, vring, 1); + wil_vring_free(wil, vring); out: return rc; } -void wil_ring_fini_tx(struct wil6210_priv *wil, int id) -{ - struct wil_ring *vring = &wil->ring_tx[id]; - struct wil_ring_tx_data *txdata = &wil->ring_tx_data[id]; - - lockdep_assert_held(&wil->mutex); - - if (!vring->va) - return; - - wil_dbg_misc(wil, "vring_fini_tx: id=%d\n", id); - - spin_lock_bh(&txdata->lock); - txdata->dot1x_open = false; - txdata->mid = U8_MAX; - txdata->enabled = 0; /* no Tx can be in progress or start anew */ - spin_unlock_bh(&txdata->lock); - /* napi_synchronize waits for completion of the current NAPI but will - * not prevent the next NAPI run. - * Add a memory barrier to guarantee that txdata->enabled is zeroed - * before napi_synchronize so that the next scheduled NAPI will not - * handle this vring - */ - wmb(); - /* make sure NAPI won't touch this vring */ - if (test_bit(wil_status_napi_en, wil->status)) - napi_synchronize(&wil->napi_tx); - - wil_vring_free(wil, vring, 1); -} - static struct wil_ring *wil_find_tx_ucast(struct wil6210_priv *wil, struct wil6210_vif *vif, struct sk_buff *skb) @@ -1109,12 +1080,13 @@ static struct wil_ring *wil_find_tx_ucast(struct wil6210_priv *wil, int i; struct ethhdr *eth = (void *)skb->data; int cid = wil_find_cid(wil, vif->mid, eth->h_dest); + int min_ring_id = wil_get_min_tx_ring_id(wil); if (cid < 0) return NULL; /* TODO: fix for multiple TID */ - for (i = 0; i < ARRAY_SIZE(wil->ring2cid_tid); i++) { + for (i = min_ring_id; i < ARRAY_SIZE(wil->ring2cid_tid); i++) { if (!wil->ring_tx_data[i].dot1x_open && skb->protocol != cpu_to_be16(ETH_P_PAE)) continue; @@ -1149,12 +1121,13 @@ static struct wil_ring *wil_find_tx_ring_sta(struct wil6210_priv *wil, int i; u8 cid; struct wil_ring_tx_data *txdata; + int min_ring_id = wil_get_min_tx_ring_id(wil); /* In the STA mode, it is expected to have only 1 VRING * for the AP we connected to. * find 1-st vring eligible for this skb and use it. */ - for (i = 0; i < WIL6210_MAX_TX_RINGS; i++) { + for (i = min_ring_id; i < WIL6210_MAX_TX_RINGS; i++) { ring = &wil->ring_tx[i]; txdata = &wil->ring_tx_data[i]; if (!ring->va || !txdata->enabled || txdata->mid != vif->mid) @@ -1230,9 +1203,10 @@ static struct wil_ring *wil_find_tx_bcast_2(struct wil6210_priv *wil, struct ethhdr *eth = (void *)skb->data; char *src = eth->h_source; struct wil_ring_tx_data *txdata, *txdata2; + int min_ring_id = wil_get_min_tx_ring_id(wil); /* find 1-st vring eligible for data */ - for (i = 0; i < WIL6210_MAX_TX_RINGS; i++) { + for (i = min_ring_id; i < WIL6210_MAX_TX_RINGS; i++) { v = &wil->ring_tx[i]; txdata = &wil->ring_tx_data[i]; if (!v->va || !txdata->enabled || txdata->mid != vif->mid) @@ -2197,3 +2171,25 @@ int wil_tx_complete(struct wil6210_vif *vif, int ringid) return done; } + +static inline int wil_tx_init(struct wil6210_priv *wil) +{ + return 0; +} + +static inline void wil_tx_fini(struct wil6210_priv *wil) {} + +void wil_init_txrx_ops_legacy_dma(struct wil6210_priv *wil) +{ + wil->txrx_ops.configure_interrupt_moderation = + wil_configure_interrupt_moderation; + /* TX ops */ + wil->txrx_ops.ring_init_tx = wil_vring_init_tx; + wil->txrx_ops.ring_fini_tx = wil_vring_free; + wil->txrx_ops.ring_init_bcast = wil_vring_init_bcast; + wil->txrx_ops.tx_init = wil_tx_init; + wil->txrx_ops.tx_fini = wil_tx_fini; + /* RX ops */ + wil->txrx_ops.rx_init = wil_rx_init; + wil->txrx_ops.rx_fini = wil_rx_fini; +} diff --git a/drivers/net/wireless/ath/wil6210/txrx.h b/drivers/net/wireless/ath/wil6210/txrx.h index 66217f815726..4e3781d9e7ec 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.h +++ b/drivers/net/wireless/ath/wil6210/txrx.h @@ -570,6 +570,12 @@ static inline int wil_ring_avail_tx(struct wil_ring *ring) return ring->size - wil_ring_used_tx(ring) - 1; } +static inline int wil_get_min_tx_ring_id(struct wil6210_priv *wil) +{ + /* In Enhanced DMA ring 0 is reserved for RX */ + return wil->use_enhanced_dma_hw ? 1 : 0; +} + void wil_netif_rx_any(struct sk_buff *skb, struct net_device *ndev); void wil_rx_reorder(struct wil6210_priv *wil, struct sk_buff *skb); void wil_rx_bar(struct wil6210_priv *wil, struct wil6210_vif *vif, @@ -578,5 +584,7 @@ struct wil_tid_ampdu_rx *wil_tid_ampdu_rx_alloc(struct wil6210_priv *wil, int size, u16 ssn); void wil_tid_ampdu_rx_free(struct wil6210_priv *wil, struct wil_tid_ampdu_rx *r); +void wil_tx_data_init(struct wil_ring_tx_data *txdata); +void wil_init_txrx_ops_legacy_dma(struct wil6210_priv *wil); #endif /* WIL6210_TXRX_H */ diff --git a/drivers/net/wireless/ath/wil6210/txrx_edma.c b/drivers/net/wireless/ath/wil6210/txrx_edma.c new file mode 100644 index 000000000000..b78edf5575b6 --- /dev/null +++ b/drivers/net/wireless/ath/wil6210/txrx_edma.c @@ -0,0 +1,741 @@ +/* + * Copyright (c) 2012-2018 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include "wil6210.h" +#include "txrx_edma.h" +#include "txrx.h" + +/* limit status ring size in range [ring size..max ring size] */ +#define WIL_SRING_SIZE_ORDER_MIN (WIL_RING_SIZE_ORDER_MIN) +#define WIL_SRING_SIZE_ORDER_MAX (WIL_RING_SIZE_ORDER_MAX) +#define WIL_RX_SRING_SIZE_ORDER_DEFAULT (10) +#define WIL_TX_SRING_SIZE_ORDER_DEFAULT (12) +#define WIL_EDMA_MAX_DATA_OFFSET (2) + +bool use_compressed_rx_status = true; +module_param(use_compressed_rx_status, bool, 0444); +MODULE_PARM_DESC(use_compressed_rx_status, " Use compressed or extended Rx status message. Default: true"); + +static int sring_order_set(const char *val, const struct kernel_param *kp) +{ + int ret; + uint x; + + ret = kstrtouint(val, 0, &x); + if (ret) + return ret; + + if (x < WIL_SRING_SIZE_ORDER_MIN || x > WIL_SRING_SIZE_ORDER_MAX) + return -EINVAL; + + *((uint *)kp->arg) = x; + + return 0; +} + +static const struct kernel_param_ops sring_order_ops = { + .set = sring_order_set, + .get = param_get_uint, +}; + +static uint rx_status_ring_order = WIL_RX_SRING_SIZE_ORDER_DEFAULT; +module_param_cb(rx_status_ring_order, &sring_order_ops, &rx_status_ring_order, + 0444); +MODULE_PARM_DESC(rx_status_ring_order, " Rx status ring order; size = 1 << order. Default: 10"); + +static uint tx_status_ring_order = WIL_TX_SRING_SIZE_ORDER_DEFAULT; +module_param_cb(tx_status_ring_order, &sring_order_ops, &tx_status_ring_order, + 0444); +MODULE_PARM_DESC(tx_status_ring_order, " Tx status ring order; size = 1 << order. Default: 12"); + +static void wil_tx_desc_unmap_edma(struct device *dev, + struct wil_tx_enhanced_desc *d, + struct wil_ctx *ctx) +{ + dma_addr_t pa = wil_tx_desc_get_addr_edma(&d->dma); + u16 dmalen = le16_to_cpu(d->dma.length); + + switch (ctx->mapped_as) { + case wil_mapped_as_single: + dma_unmap_single(dev, pa, dmalen, DMA_TO_DEVICE); + break; + case wil_mapped_as_page: + dma_unmap_page(dev, pa, dmalen, DMA_TO_DEVICE); + break; + default: + break; + } +} + +static int wil_find_free_sring(struct wil6210_priv *wil) +{ + int i; + + for (i = 0; i < WIL6210_MAX_STATUS_RINGS; i++) { + if (!wil->srings[i].va) + return i; + } + + return -EINVAL; +} + +static void wil_sring_free(struct wil6210_priv *wil, + struct wil_status_ring *sring) +{ + struct device *dev = wil_to_dev(wil); + size_t sz; + + if (!sring || !sring->va) + return; + + sz = sring->elem_size * sring->size; + + wil_dbg_misc(wil, "status_ring_free, size(bytes)=%zu, 0x%p:%pad\n", + sz, sring->va, &sring->pa); + + dma_free_coherent(dev, sz, (void *)sring->va, sring->pa); + sring->pa = 0; + sring->va = NULL; +} + +static int wil_sring_alloc(struct wil6210_priv *wil, + struct wil_status_ring *sring) +{ + struct device *dev = wil_to_dev(wil); + size_t sz = sring->elem_size * sring->size; + + wil_dbg_misc(wil, "status_ring_alloc: size=%zu\n", sz); + + if (sz == 0) { + wil_err(wil, "Cannot allocate a zero size status ring\n"); + return -EINVAL; + } + + sring->swhead = 0; + + /* Status messages are allocated and initialized to 0. This is necessary + * since DR bit should be initialized to 0. + */ + sring->va = dma_zalloc_coherent(dev, sz, &sring->pa, GFP_KERNEL); + if (!sring->va) + return -ENOMEM; + + wil_dbg_misc(wil, "status_ring[%d] 0x%p:%pad\n", sring->size, sring->va, + &sring->pa); + + return 0; +} + +static int wil_tx_init_edma(struct wil6210_priv *wil) +{ + int ring_id = wil_find_free_sring(wil); + struct wil_status_ring *sring; + int rc; + u16 status_ring_size = 1 << tx_status_ring_order; + + wil_dbg_misc(wil, "init TX sring: size=%u, ring_id=%u\n", + status_ring_size, ring_id); + + if (ring_id < 0) + return ring_id; + + /* Allocate Tx status ring. Tx descriptor rings will be + * allocated on WMI connect event + */ + sring = &wil->srings[ring_id]; + + sring->is_rx = false; + sring->size = status_ring_size; + sring->elem_size = sizeof(struct wil_ring_tx_status); + rc = wil_sring_alloc(wil, sring); + if (rc) + return rc; + + rc = wil_wmi_tx_sring_cfg(wil, ring_id); + if (rc) + goto out_free; + + sring->desc_rdy_pol = 1; + wil->tx_sring_idx = ring_id; + + return 0; +out_free: + wil_sring_free(wil, sring); + return rc; +} + +/** + * Allocate one skb for Rx descriptor RING + */ +static int wil_ring_alloc_skb_edma(struct wil6210_priv *wil, + struct wil_ring *ring, u32 i) +{ + struct device *dev = wil_to_dev(wil); + unsigned int sz = wil->rx_buf_len + ETH_HLEN + + WIL_EDMA_MAX_DATA_OFFSET; + dma_addr_t pa; + u16 buff_id; + struct list_head *active = &wil->rx_buff_mgmt.active; + struct list_head *free = &wil->rx_buff_mgmt.free; + struct wil_rx_buff *rx_buff; + struct wil_rx_buff *buff_arr = wil->rx_buff_mgmt.buff_arr; + struct sk_buff *skb; + struct wil_rx_enhanced_desc dd, *d = ⅆ + struct wil_rx_enhanced_desc *_d = (struct wil_rx_enhanced_desc *) + &ring->va[i].rx.enhanced; + + if (unlikely(list_empty(free))) { + wil->rx_buff_mgmt.free_list_empty_cnt++; + return -EAGAIN; + } + + skb = dev_alloc_skb(sz); + if (unlikely(!skb)) + return -ENOMEM; + + skb_put(skb, sz); + + pa = dma_map_single(dev, skb->data, skb->len, DMA_FROM_DEVICE); + if (unlikely(dma_mapping_error(dev, pa))) { + kfree_skb(skb); + return -ENOMEM; + } + + /* Get the buffer ID - the index of the rx buffer in the buff_arr */ + rx_buff = list_first_entry(free, struct wil_rx_buff, list); + buff_id = rx_buff->id; + + /* Move a buffer from the free list to the active list */ + list_move(&rx_buff->list, active); + + buff_arr[buff_id].skb = skb; + + wil_desc_set_addr_edma(&d->dma.addr, &d->dma.addr_high_high, pa); + d->dma.length = cpu_to_le16(sz); + d->mac.buff_id = cpu_to_le16(buff_id); + *_d = *d; + + /* Save the physical address in skb->cb for later use in dma_unmap */ + memcpy(skb->cb, &pa, sizeof(pa)); + + return 0; +} + +static int wil_rx_refill_edma(struct wil6210_priv *wil) +{ + struct wil_ring *ring = &wil->ring_rx; + u32 next_head; + int rc = 0; + u32 swtail = *ring->edma_rx_swtail.va; + + for (; next_head = wil_ring_next_head(ring), (next_head != swtail); + ring->swhead = next_head) { + rc = wil_ring_alloc_skb_edma(wil, ring, ring->swhead); + if (unlikely(rc)) { + if (rc == -EAGAIN) + wil_err_ratelimited(wil, + "No free buffer IDs found\n"); + else + wil_err_ratelimited(wil, + "Error %d in refill desc[%d]\n", + rc, ring->swhead); + break; + } + } + + /* make sure all writes to descriptors (shared memory) are done before + * committing them to HW + */ + wmb(); + + wil_w(wil, ring->hwtail, ring->swhead); + + return rc; +} + +static void wil_move_all_rx_buff_to_free_list(struct wil6210_priv *wil, + struct wil_ring *ring) +{ + struct device *dev = wil_to_dev(wil); + u32 next_tail; + u32 swhead = (ring->swhead + 1) % ring->size; + dma_addr_t pa; + u16 dmalen; + + for (; next_tail = wil_ring_next_tail(ring), (next_tail != swhead); + ring->swtail = next_tail) { + struct wil_rx_enhanced_desc dd, *d = ⅆ + struct wil_rx_enhanced_desc *_d = + (struct wil_rx_enhanced_desc *) + &ring->va[ring->swtail].rx.enhanced; + struct sk_buff *skb; + u16 buff_id; + + *d = *_d; + pa = wil_rx_desc_get_addr_edma(&d->dma); + dmalen = le16_to_cpu(d->dma.length); + dma_unmap_single(dev, pa, dmalen, DMA_FROM_DEVICE); + + /* Extract the SKB from the rx_buff management array */ + buff_id = __le16_to_cpu(d->mac.buff_id); + if (buff_id >= wil->rx_buff_mgmt.size) { + wil_err(wil, "invalid buff_id %d\n", buff_id); + continue; + } + skb = wil->rx_buff_mgmt.buff_arr[buff_id].skb; + wil->rx_buff_mgmt.buff_arr[buff_id].skb = NULL; + if (unlikely(!skb)) + wil_err(wil, "No Rx skb at buff_id %d\n", buff_id); + else + kfree_skb(skb); + + /* Move the buffer from the active to the free list */ + list_move(&wil->rx_buff_mgmt.buff_arr[buff_id].list, + &wil->rx_buff_mgmt.free); + } +} + +static void wil_free_rx_buff_arr(struct wil6210_priv *wil) +{ + struct wil_ring *ring = &wil->ring_rx; + + if (!wil->rx_buff_mgmt.buff_arr) + return; + + /* Move all the buffers to the free list in case active list is + * not empty in order to release all SKBs before deleting the array + */ + wil_move_all_rx_buff_to_free_list(wil, ring); + + kfree(wil->rx_buff_mgmt.buff_arr); + wil->rx_buff_mgmt.buff_arr = NULL; +} + +static int wil_init_rx_buff_arr(struct wil6210_priv *wil, + size_t size) +{ + struct wil_rx_buff *buff_arr; + struct list_head *active = &wil->rx_buff_mgmt.active; + struct list_head *free = &wil->rx_buff_mgmt.free; + int i; + + wil->rx_buff_mgmt.buff_arr = kcalloc(size, sizeof(struct wil_rx_buff), + GFP_KERNEL); + if (!wil->rx_buff_mgmt.buff_arr) + return -ENOMEM; + + /* Set list heads */ + INIT_LIST_HEAD(active); + INIT_LIST_HEAD(free); + + /* Linkify the list */ + buff_arr = wil->rx_buff_mgmt.buff_arr; + for (i = 0; i < size; i++) { + list_add(&buff_arr[i].list, free); + buff_arr[i].id = i; + } + + wil->rx_buff_mgmt.size = size; + + return 0; +} + +static int wil_init_rx_sring(struct wil6210_priv *wil, + u16 status_ring_size, + size_t elem_size, + u16 ring_id) +{ + struct wil_status_ring *sring = &wil->srings[ring_id]; + int rc; + + wil_dbg_misc(wil, "init RX sring: size=%u, ring_id=%u\n", sring->size, + ring_id); + + memset(&sring->rx_data, 0, sizeof(sring->rx_data)); + + sring->is_rx = true; + sring->size = status_ring_size; + sring->elem_size = elem_size; + rc = wil_sring_alloc(wil, sring); + if (rc) + return rc; + + rc = wil_wmi_rx_sring_add(wil, ring_id); + if (rc) + goto out_free; + + sring->desc_rdy_pol = 1; + + return 0; +out_free: + wil_sring_free(wil, sring); + return rc; +} + +static int wil_ring_alloc_desc_ring(struct wil6210_priv *wil, + struct wil_ring *ring) +{ + struct device *dev = wil_to_dev(wil); + size_t sz = ring->size * sizeof(ring->va[0]); + + wil_dbg_misc(wil, "alloc_desc_ring:\n"); + + BUILD_BUG_ON(sizeof(ring->va[0]) != 32); + + ring->swhead = 0; + ring->swtail = 0; + ring->ctx = kcalloc(ring->size, sizeof(ring->ctx[0]), GFP_KERNEL); + if (!ring->ctx) + goto err; + + ring->va = dma_zalloc_coherent(dev, sz, &ring->pa, GFP_KERNEL); + if (!ring->va) + goto err_free_ctx; + + if (ring->is_rx) { + sz = sizeof(*ring->edma_rx_swtail.va); + ring->edma_rx_swtail.va = + dma_zalloc_coherent(dev, sz, &ring->edma_rx_swtail.pa, + GFP_KERNEL); + if (!ring->edma_rx_swtail.va) + goto err_free_va; + } + + wil_dbg_misc(wil, "%s ring[%d] 0x%p:%pad 0x%p\n", + ring->is_rx ? "RX" : "TX", + ring->size, ring->va, &ring->pa, ring->ctx); + + return 0; +err_free_va: + dma_free_coherent(dev, ring->size * sizeof(ring->va[0]), + (void *)ring->va, ring->pa); + ring->va = NULL; +err_free_ctx: + kfree(ring->ctx); + ring->ctx = NULL; +err: + return -ENOMEM; +} + +static void wil_ring_free_edma(struct wil6210_priv *wil, struct wil_ring *ring) +{ + struct device *dev = wil_to_dev(wil); + size_t sz; + int ring_index = 0; + + if (!ring->va) + return; + + sz = ring->size * sizeof(ring->va[0]); + + lockdep_assert_held(&wil->mutex); + if (ring->is_rx) { + wil_dbg_misc(wil, "free Rx ring [%d] 0x%p:%pad 0x%p\n", + ring->size, ring->va, + &ring->pa, ring->ctx); + + wil_move_all_rx_buff_to_free_list(wil, ring); + goto out; + } + + /* TX ring */ + ring_index = ring - wil->ring_tx; + + wil_dbg_misc(wil, "free Tx ring %d [%d] 0x%p:%pad 0x%p\n", + ring_index, ring->size, ring->va, + &ring->pa, ring->ctx); + + while (!wil_ring_is_empty(ring)) { + struct wil_ctx *ctx; + + struct wil_tx_enhanced_desc dd, *d = ⅆ + struct wil_tx_enhanced_desc *_d = + (struct wil_tx_enhanced_desc *) + &ring->va[ring->swtail].tx.enhanced; + + ctx = &ring->ctx[ring->swtail]; + if (!ctx) { + wil_dbg_txrx(wil, + "ctx(%d) was already completed\n", + ring->swtail); + ring->swtail = wil_ring_next_tail(ring); + continue; + } + *d = *_d; + wil_tx_desc_unmap_edma(dev, d, ctx); + if (ctx->skb) + dev_kfree_skb_any(ctx->skb); + ring->swtail = wil_ring_next_tail(ring); + } + +out: + dma_free_coherent(dev, sz, (void *)ring->va, ring->pa); + kfree(ring->ctx); + ring->pa = 0; + ring->va = NULL; + ring->ctx = NULL; +} + +static int wil_init_rx_desc_ring(struct wil6210_priv *wil, u16 desc_ring_size, + int status_ring_id) +{ + struct wil_ring *ring = &wil->ring_rx; + int rc; + + wil_dbg_misc(wil, "init RX desc ring\n"); + + ring->size = desc_ring_size; + ring->is_rx = true; + rc = wil_ring_alloc_desc_ring(wil, ring); + if (rc) + return rc; + + rc = wil_wmi_rx_desc_ring_add(wil, status_ring_id); + if (rc) + goto out_free; + + return 0; +out_free: + wil_ring_free_edma(wil, ring); + return rc; +} + +static void wil_rx_buf_len_init_edma(struct wil6210_priv *wil) +{ + wil->rx_buf_len = rx_large_buf ? + WIL_MAX_ETH_MTU : TXRX_BUF_LEN_DEFAULT - WIL_MAX_MPDU_OVERHEAD; +} + +static int wil_rx_init_edma(struct wil6210_priv *wil, u16 desc_ring_size) +{ + u16 status_ring_size = 1 << rx_status_ring_order; + struct wil_ring *ring = &wil->ring_rx; + int rc; + size_t elem_size = use_compressed_rx_status ? + sizeof(struct wil_rx_status_compressed) : + sizeof(struct wil_rx_status_extended); + int i; + u16 max_rx_pl_per_desc; + + wil_dbg_misc(wil, + "rx_init, desc_ring_size=%u, status_ring_size=%u, elem_size=%zu\n", + desc_ring_size, status_ring_size, elem_size); + + wil_rx_buf_len_init_edma(wil); + + max_rx_pl_per_desc = wil->rx_buf_len + ETH_HLEN + + WIL_EDMA_MAX_DATA_OFFSET; + + /* Use debugfs dbg_num_rx_srings if set, reserve one sring for TX */ + if (wil->num_rx_status_rings > WIL6210_MAX_STATUS_RINGS - 1) + wil->num_rx_status_rings = WIL6210_MAX_STATUS_RINGS - 1; + + wil_dbg_misc(wil, "rx_init: allocate %d status rings\n", + wil->num_rx_status_rings); + + rc = wil_wmi_cfg_def_rx_offload(wil, max_rx_pl_per_desc); + if (rc) + return rc; + + /* Allocate status ring */ + for (i = 0; i < wil->num_rx_status_rings; i++) { + int sring_id = wil_find_free_sring(wil); + + if (sring_id < 0) { + rc = -EFAULT; + goto err_free_status; + } + rc = wil_init_rx_sring(wil, status_ring_size, elem_size, + sring_id); + if (rc) + goto err_free_status; + } + + /* Allocate descriptor ring */ + rc = wil_init_rx_desc_ring(wil, desc_ring_size, + WIL_DEFAULT_RX_STATUS_RING_ID); + if (rc) + goto err_free_status; + + /* Allocate Rx buffer array */ + rc = wil_init_rx_buff_arr(wil, desc_ring_size + status_ring_size); + if (rc) + goto err_free_desc; + + /* Fill descriptor ring with credits */ + rc = wil_rx_refill_edma(wil); + if (rc) + goto err_free_rx_buff_arr; + + return 0; +err_free_rx_buff_arr: + wil_free_rx_buff_arr(wil); +err_free_desc: + wil_ring_free_edma(wil, ring); +err_free_status: + for (i = 0; i < wil->num_rx_status_rings; i++) + wil_sring_free(wil, &wil->srings[i]); + + return rc; +} + +static int wil_ring_init_tx_edma(struct wil6210_vif *vif, int ring_id, + int size, int cid, int tid) +{ + struct wil6210_priv *wil = vif_to_wil(vif); + int rc; + struct wil_ring *ring = &wil->ring_tx[ring_id]; + struct wil_ring_tx_data *txdata = &wil->ring_tx_data[ring_id]; + + lockdep_assert_held(&wil->mutex); + + wil_dbg_misc(wil, + "init TX ring: ring_id=%u, cid=%u, tid=%u, sring_id=%u\n", + ring_id, cid, tid, wil->tx_sring_idx); + + wil_tx_data_init(txdata); + ring->size = size; + rc = wil_ring_alloc_desc_ring(wil, ring); + if (rc) + goto out; + + wil->ring2cid_tid[ring_id][0] = cid; + wil->ring2cid_tid[ring_id][1] = tid; + if (!vif->privacy) + txdata->dot1x_open = true; + + rc = wil_wmi_tx_desc_ring_add(vif, ring_id, cid, tid); + if (rc) { + wil_err(wil, "WMI_TX_DESC_RING_ADD_CMD failed\n"); + goto out_free; + } + + if (txdata->dot1x_open && agg_wsize >= 0) + wil_addba_tx_request(wil, ring_id, agg_wsize); + + return 0; + out_free: + spin_lock_bh(&txdata->lock); + txdata->dot1x_open = false; + txdata->enabled = 0; + spin_unlock_bh(&txdata->lock); + wil_ring_free_edma(wil, ring); + wil->ring2cid_tid[ring_id][0] = WIL6210_MAX_CID; + wil->ring2cid_tid[ring_id][1] = 0; + + out: + return rc; +} + +static int wil_ring_init_bcast_edma(struct wil6210_vif *vif, int ring_id, + int size) +{ + struct wil6210_priv *wil = vif_to_wil(vif); + struct wil_ring *ring = &wil->ring_tx[ring_id]; + int rc; + struct wil_ring_tx_data *txdata = &wil->ring_tx_data[ring_id]; + + wil_dbg_misc(wil, "init bcast: ring_id=%d, sring_id=%d\n", + ring_id, wil->tx_sring_idx); + + lockdep_assert_held(&wil->mutex); + + wil_tx_data_init(txdata); + ring->size = size; + ring->is_rx = false; + rc = wil_ring_alloc_desc_ring(wil, ring); + if (rc) + goto out; + + wil->ring2cid_tid[ring_id][0] = WIL6210_MAX_CID; /* CID */ + wil->ring2cid_tid[ring_id][1] = 0; /* TID */ + if (!vif->privacy) + txdata->dot1x_open = true; + + rc = wil_wmi_bcast_desc_ring_add(vif, ring_id); + if (rc) + goto out_free; + + return 0; + + out_free: + spin_lock_bh(&txdata->lock); + txdata->enabled = 0; + txdata->dot1x_open = false; + spin_unlock_bh(&txdata->lock); + wil_ring_free_edma(wil, ring); + +out: + return rc; +} + +static void wil_tx_fini_edma(struct wil6210_priv *wil) +{ + struct wil_status_ring *sring = &wil->srings[wil->tx_sring_idx]; + + wil_dbg_misc(wil, "free TX sring\n"); + + wil_sring_free(wil, sring); +} + +static void wil_rx_data_free(struct wil_status_ring *sring) +{ + if (!sring) + return; + + kfree_skb(sring->rx_data.skb); + sring->rx_data.skb = NULL; +} + +static void wil_rx_fini_edma(struct wil6210_priv *wil) +{ + struct wil_ring *ring = &wil->ring_rx; + int i; + + wil_dbg_misc(wil, "rx_fini_edma\n"); + + wil_ring_free_edma(wil, ring); + + for (i = 0; i < wil->num_rx_status_rings; i++) { + wil_rx_data_free(&wil->srings[i]); + wil_sring_free(wil, &wil->srings[i]); + } + + wil_free_rx_buff_arr(wil); +} + +void wil_init_txrx_ops_edma(struct wil6210_priv *wil) +{ + wil->txrx_ops.configure_interrupt_moderation = + wil_configure_interrupt_moderation_edma; + /* TX ops */ + wil->txrx_ops.ring_init_tx = wil_ring_init_tx_edma; + wil->txrx_ops.ring_fini_tx = wil_ring_free_edma; + wil->txrx_ops.ring_init_bcast = wil_ring_init_bcast_edma; + wil->txrx_ops.tx_init = wil_tx_init_edma; + wil->txrx_ops.tx_fini = wil_tx_fini_edma; + /* RX ops */ + wil->txrx_ops.rx_init = wil_rx_init_edma; + wil->txrx_ops.rx_fini = wil_rx_fini_edma; +} + diff --git a/drivers/net/wireless/ath/wil6210/txrx_edma.h b/drivers/net/wireless/ath/wil6210/txrx_edma.h index 14e0b6ce6dc4..645ba1797707 100644 --- a/drivers/net/wireless/ath/wil6210/txrx_edma.h +++ b/drivers/net/wireless/ath/wil6210/txrx_edma.h @@ -19,6 +19,17 @@ #include "wil6210.h" +#define WIL_DEFAULT_RX_STATUS_RING_ID 0 +#define WIL_RX_DESC_RING_ID 0 +#define WIL_RX_STATUS_IRQ_IDX 0 +#define WIL_TX_STATUS_IRQ_IDX 1 + +#define WIL_EDMA_AGG_WATERMARK (0xffff) +#define WIL_EDMA_AGG_WATERMARK_POS (16) + +#define WIL_EDMA_IDLE_TIME_LIMIT_USEC (50) +#define WIL_EDMA_TIME_UNIT_CLK_CYCLES (330) /* fits 1 usec */ + /* Enhanced Rx descriptor - MAC part * [dword 0] : Reserved * [dword 1] : Reserved @@ -216,7 +227,7 @@ struct wil_ring_tx_status { * bit 22..23 : CB mode:2 - The CB Mode: 0-DMG, 1-EDMG, 2-Wide * bit 24..27 : Data Offset:4 - The data offset, a code that describe the * payload shift from the beginning of the buffer: - * 0 - 0 Bytes, 1 - 2 Bytes, 2 - 6 Bytes + * 0 - 0 Bytes, 3 - 2 Bytes * bit 28 : A-MSDU Present:1 - The QoS (b7) A-MSDU present field * bit 29 : A-MSDU Type:1 The QoS (b8) A-MSDU Type field * bit 30 : A-MPDU:1 - Packet is part of aggregated MPDU @@ -286,5 +297,38 @@ struct wil_rx_status_extended { struct wil_rx_status_extension ext; }; +static inline u32 wil_ring_next_head(struct wil_ring *ring) +{ + return (ring->swhead + 1) % ring->size; +} + +static inline void wil_desc_set_addr_edma(struct wil_ring_dma_addr *addr, + __le16 *addr_high_high, + dma_addr_t pa) +{ + addr->addr_low = cpu_to_le32(lower_32_bits(pa)); + addr->addr_high = cpu_to_le16((u16)upper_32_bits(pa)); + *addr_high_high = cpu_to_le16((u16)(upper_32_bits(pa) >> 16)); +} + +static inline +dma_addr_t wil_tx_desc_get_addr_edma(struct wil_ring_tx_enhanced_dma *dma) +{ + return le32_to_cpu(dma->addr.addr_low) | + ((u64)le16_to_cpu(dma->addr.addr_high) << 32) | + ((u64)le16_to_cpu(dma->addr_high_high) << 48); +} + +static inline +dma_addr_t wil_rx_desc_get_addr_edma(struct wil_ring_rx_enhanced_dma *dma) +{ + return le32_to_cpu(dma->addr.addr_low) | + ((u64)le16_to_cpu(dma->addr.addr_high) << 32) | + ((u64)le16_to_cpu(dma->addr_high_high) << 48); +} + +void wil_configure_interrupt_moderation_edma(struct wil6210_priv *wil); +void wil_init_txrx_ops_edma(struct wil6210_priv *wil); + #endif /* WIL6210_TXRX_EDMA_H */ diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index 0638d7eacdf9..ab454099aafd 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -37,6 +37,10 @@ extern bool rx_align_2; extern bool rx_large_buf; extern bool debug_fw; extern bool disable_ap_sme; +extern bool use_compressed_rx_status; + +struct wil6210_priv; +struct wil6210_vif; #define WIL_NAME "wil6210" @@ -308,6 +312,18 @@ struct RGF_ICR { #define RGF_CAF_PLL_LOCK_STATUS (0x88afec) #define BIT_CAF_OSC_DIG_XTAL_STABLE BIT(0) +/* eDMA */ +#define RGF_INT_COUNT_ON_SPECIAL_EVT (0x8b62d8) + +#define RGF_INT_CTRL_INT_GEN_CFG_0 (0x8bc000) +#define RGF_INT_CTRL_INT_GEN_CFG_1 (0x8bc004) +#define RGF_INT_GEN_TIME_UNIT_LIMIT (0x8bc0c8) + +#define RGF_INT_GEN_CTRL (0x8bc0ec) + #define BIT_CONTROL_0 BIT(0) + +#define RGF_INT_GEN_IDLE_TIME_LIMIT (0x8bc134) + #define USER_EXT_USER_PMU_3 (0x88d00c) #define BIT_PMU_DEVICE_RDY BIT(0) @@ -486,6 +502,17 @@ struct wil_ring { bool is_rx; }; +/** + * Additional data for Rx ring. + * Used for enhanced DMA RX chaining. + */ +struct wil_ring_rx_data { + /* the skb being assembled */ + struct sk_buff *skb; + /* true if we are skipping a bad fragmented packet */ + bool skipping; +}; + /** * Status ring structure, used for enhanced DMA completions for RX and TX. */ @@ -498,6 +525,25 @@ struct wil_status_ring { u32 hwtail; /* write here to inform hw */ bool is_rx; u8 desc_rdy_pol; /* Expected descriptor ready bit polarity */ + struct wil_ring_rx_data rx_data; +}; + +/** + * struct tx_rx_ops - different TX/RX ops for legacy and enhanced + * DMA flow + */ +struct wil_txrx_ops { + void (*configure_interrupt_moderation)(struct wil6210_priv *wil); + /* TX ops */ + int (*ring_init_tx)(struct wil6210_vif *vif, int ring_id, + int size, int cid, int tid); + void (*ring_fini_tx)(struct wil6210_priv *wil, struct wil_ring *ring); + int (*ring_init_bcast)(struct wil6210_vif *vif, int id, int size); + int (*tx_init)(struct wil6210_priv *wil); + void (*tx_fini)(struct wil6210_priv *wil); + /* RX ops */ + int (*rx_init)(struct wil6210_priv *wil, u16 ring_size); + void (*rx_fini)(struct wil6210_priv *wil); }; /** @@ -515,18 +561,6 @@ struct wil_ring_tx_data { spinlock_t lock; }; -/** - * Additional data for Rx ring. - * Used for enhanced DMA RX chaining. - */ -struct wil_ring_rx_data { - /* the skb being assembled */ - struct sk_buff *skb; - /* true if we are skipping a bad fragmented packet */ - bool skipping; - u16 buff_size; -}; - enum { /* for wil6210_priv.status */ wil_status_fwready = 0, /* FW operational */ wil_status_dontscan, @@ -862,12 +896,15 @@ struct wil6210_priv { struct wil_ring ring_tx[WIL6210_MAX_TX_RINGS]; struct wil_ring_tx_data ring_tx_data[WIL6210_MAX_TX_RINGS]; struct wil_status_ring srings[WIL6210_MAX_STATUS_RINGS]; - int num_rx_status_rings; + u8 num_rx_status_rings; + int tx_sring_idx; u8 ring2cid_tid[WIL6210_MAX_TX_RINGS][2]; /* [0] - CID, [1] - TID */ struct wil_sta_info sta[WIL6210_MAX_CID]; u32 ring_idle_trsh; /* HW fetches up to 16 descriptors at once */ u32 dma_addr_size; /* indicates dma addr size */ struct wil_rx_buff_mgmt rx_buff_mgmt; + bool use_enhanced_dma_hw; + struct wil_txrx_ops txrx_ops; struct mutex mutex; /* for wil6210_priv access in wil_{up|down} */ /* statistics */ @@ -1199,14 +1236,10 @@ void wil_probe_client_flush(struct wil6210_vif *vif); void wil_probe_client_worker(struct work_struct *work); void wil_disconnect_worker(struct work_struct *work); -int wil_rx_init(struct wil6210_priv *wil, u16 size); -void wil_rx_fini(struct wil6210_priv *wil); +void wil_init_txrx_ops(struct wil6210_priv *wil); /* TX API */ -int wil_vring_init_tx(struct wil6210_vif *vif, int id, int size, - int cid, int tid); -void wil_ring_fini_tx(struct wil6210_priv *wil, int id); -int wil_tx_init(struct wil6210_vif *vif, int cid); +int wil_ring_init_tx(struct wil6210_vif *vif, int cid); int wil_vring_init_bcast(struct wil6210_vif *vif, int id, int size); int wil_bcast_init(struct wil6210_vif *vif); void wil_bcast_fini(struct wil6210_vif *vif); @@ -1278,4 +1311,14 @@ int wmi_start_sched_scan(struct wil6210_priv *wil, struct cfg80211_sched_scan_request *request); int wmi_stop_sched_scan(struct wil6210_priv *wil); +/* WMI for enhanced DMA */ +int wil_wmi_tx_sring_cfg(struct wil6210_priv *wil, int ring_id); +int wil_wmi_cfg_def_rx_offload(struct wil6210_priv *wil, + u16 max_rx_pl_per_desc); +int wil_wmi_rx_sring_add(struct wil6210_priv *wil, u16 ring_id); +int wil_wmi_rx_desc_ring_add(struct wil6210_priv *wil, int status_ring_id); +int wil_wmi_tx_desc_ring_add(struct wil6210_vif *vif, int ring_id, int cid, + int tid); +int wil_wmi_bcast_desc_ring_add(struct wil6210_vif *vif, int ring_id); + #endif /* __WIL6210_H__ */ diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c index 3b2eef059a44..6d5bee308de7 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.c +++ b/drivers/net/wireless/ath/wil6210/wmi.c @@ -421,10 +421,10 @@ static const char *cmdid2name(u16 cmdid) return "WMI_DEL_STA_CMD"; case WMI_DISCONNECT_STA_CMDID: return "WMI_DISCONNECT_STA_CMD"; - case WMI_VRING_BA_EN_CMDID: - return "WMI_VRING_BA_EN_CMD"; - case WMI_VRING_BA_DIS_CMDID: - return "WMI_VRING_BA_DIS_CMD"; + case WMI_RING_BA_EN_CMDID: + return "WMI_RING_BA_EN_CMD"; + case WMI_RING_BA_DIS_CMDID: + return "WMI_RING_BA_DIS_CMD"; case WMI_RCP_DELBA_CMDID: return "WMI_RCP_DELBA_CMD"; case WMI_RCP_ADDBA_RESP_CMDID: @@ -451,6 +451,18 @@ static const char *cmdid2name(u16 cmdid) return "WMI_START_SCHED_SCAN_CMD"; case WMI_STOP_SCHED_SCAN_CMDID: return "WMI_STOP_SCHED_SCAN_CMD"; + case WMI_TX_STATUS_RING_ADD_CMDID: + return "WMI_TX_STATUS_RING_ADD_CMD"; + case WMI_RX_STATUS_RING_ADD_CMDID: + return "WMI_RX_STATUS_RING_ADD_CMD"; + case WMI_TX_DESC_RING_ADD_CMDID: + return "WMI_TX_DESC_RING_ADD_CMD"; + case WMI_RX_DESC_RING_ADD_CMDID: + return "WMI_RX_DESC_RING_ADD_CMD"; + case WMI_BCAST_DESC_RING_ADD_CMDID: + return "WMI_BCAST_DESC_RING_ADD_CMD"; + case WMI_CFG_DEF_RX_OFFLOAD_CMDID: + return "WMI_CFG_DEF_RX_OFFLOAD_CMD"; default: return "Untracked CMD"; } @@ -505,8 +517,8 @@ static const char *eventid2name(u16 eventid) return "WMI_RCP_ADDBA_REQ_EVENT"; case WMI_DELBA_EVENTID: return "WMI_DELBA_EVENT"; - case WMI_VRING_EN_EVENTID: - return "WMI_VRING_EN_EVENT"; + case WMI_RING_EN_EVENTID: + return "WMI_RING_EN_EVENT"; case WMI_DATA_PORT_OPEN_EVENTID: return "WMI_DATA_PORT_OPEN_EVENT"; case WMI_AOA_MEAS_EVENTID: @@ -575,6 +587,16 @@ static const char *eventid2name(u16 eventid) return "WMI_STOP_SCHED_SCAN_EVENT"; case WMI_SCHED_SCAN_RESULT_EVENTID: return "WMI_SCHED_SCAN_RESULT_EVENT"; + case WMI_TX_STATUS_RING_CFG_DONE_EVENTID: + return "WMI_TX_STATUS_RING_CFG_DONE_EVENT"; + case WMI_RX_STATUS_RING_CFG_DONE_EVENTID: + return "WMI_RX_STATUS_RING_CFG_DONE_EVENT"; + case WMI_TX_DESC_RING_CFG_DONE_EVENTID: + return "WMI_TX_DESC_RING_CFG_DONE_EVENT"; + case WMI_RX_DESC_RING_CFG_DONE_EVENTID: + return "WMI_RX_DESC_RING_CFG_DONE_EVENT"; + case WMI_CFG_DEF_RX_OFFLOAD_DONE_EVENTID: + return "WMI_CFG_DEF_RX_OFFLOAD_DONE_EVENT"; default: return "Untracked EVENT"; } @@ -967,7 +989,7 @@ static void wmi_evt_connect(struct wil6210_vif *vif, int id, void *d, int len) wil->sta[evt->cid].mid = vif->mid; wil->sta[evt->cid].status = wil_sta_conn_pending; - rc = wil_tx_init(vif, evt->cid); + rc = wil_ring_init_tx(vif, evt->cid); if (rc) { wil_err(wil, "config tx vring failed for CID %d, rc (%d)\n", evt->cid, rc); @@ -1117,11 +1139,11 @@ static void wmi_evt_eapol_rx(struct wil6210_vif *vif, int id, void *d, int len) } } -static void wmi_evt_vring_en(struct wil6210_vif *vif, int id, void *d, int len) +static void wmi_evt_ring_en(struct wil6210_vif *vif, int id, void *d, int len) { struct wil6210_priv *wil = vif_to_wil(vif); - struct wmi_vring_en_event *evt = d; - u8 vri = evt->vring_index; + struct wmi_ring_en_event *evt = d; + u8 vri = evt->ring_index; struct wireless_dev *wdev = vif_to_wdev(vif); wil_dbg_wmi(wil, "Enable vring %d MID %d\n", vri, vif->mid); @@ -1354,7 +1376,7 @@ static const struct { {WMI_BA_STATUS_EVENTID, wmi_evt_ba_status}, {WMI_RCP_ADDBA_REQ_EVENTID, wmi_evt_addba_rx_req}, {WMI_DELBA_EVENTID, wmi_evt_delba}, - {WMI_VRING_EN_EVENTID, wmi_evt_vring_en}, + {WMI_RING_EN_EVENTID, wmi_evt_ring_en}, {WMI_DATA_PORT_OPEN_EVENTID, wmi_evt_ignore}, {WMI_AOA_MEAS_EVENTID, wmi_evt_aoa_meas}, {WMI_TOF_SESSION_END_EVENTID, wmi_evt_ftm_session_ended}, @@ -2124,8 +2146,8 @@ int wmi_disconnect_sta(struct wil6210_vif *vif, const u8 *mac, int wmi_addba(struct wil6210_priv *wil, u8 mid, u8 ringid, u8 size, u16 timeout) { - struct wmi_vring_ba_en_cmd cmd = { - .ringid = ringid, + struct wmi_ring_ba_en_cmd cmd = { + .ring_id = ringid, .agg_max_wsize = size, .ba_timeout = cpu_to_le16(timeout), .amsdu = 0, @@ -2134,19 +2156,19 @@ int wmi_addba(struct wil6210_priv *wil, u8 mid, wil_dbg_wmi(wil, "addba: (ring %d size %d timeout %d)\n", ringid, size, timeout); - return wmi_send(wil, WMI_VRING_BA_EN_CMDID, mid, &cmd, sizeof(cmd)); + return wmi_send(wil, WMI_RING_BA_EN_CMDID, mid, &cmd, sizeof(cmd)); } int wmi_delba_tx(struct wil6210_priv *wil, u8 mid, u8 ringid, u16 reason) { - struct wmi_vring_ba_dis_cmd cmd = { - .ringid = ringid, + struct wmi_ring_ba_dis_cmd cmd = { + .ring_id = ringid, .reason = cpu_to_le16(reason), }; wil_dbg_wmi(wil, "delba_tx: (ring %d reason %d)\n", ringid, reason); - return wmi_send(wil, WMI_VRING_BA_DIS_CMDID, mid, &cmd, sizeof(cmd)); + return wmi_send(wil, WMI_RING_BA_DIS_CMDID, mid, &cmd, sizeof(cmd)); } int wmi_delba_rx(struct wil6210_priv *wil, u8 mid, u8 cidxtid, u16 reason) @@ -3017,3 +3039,258 @@ int wmi_stop_sched_scan(struct wil6210_priv *wil) return 0; } + +int wil_wmi_tx_sring_cfg(struct wil6210_priv *wil, int ring_id) +{ + int rc; + struct wil6210_vif *vif = ndev_to_vif(wil->main_ndev); + struct wil_status_ring *sring = &wil->srings[ring_id]; + struct wmi_tx_status_ring_add_cmd cmd = { + .ring_cfg = { + .ring_size = cpu_to_le16(sring->size), + }, + .irq_index = WIL_TX_STATUS_IRQ_IDX + }; + struct { + struct wmi_cmd_hdr hdr; + struct wmi_tx_status_ring_cfg_done_event evt; + } __packed reply; + + cmd.ring_cfg.ring_id = ring_id; + + cmd.ring_cfg.ring_mem_base = cpu_to_le64(sring->pa); + reply.evt.status = WMI_FW_STATUS_FAILURE; + rc = wmi_call(wil, WMI_TX_STATUS_RING_ADD_CMDID, vif->mid, &cmd, + sizeof(cmd), WMI_TX_STATUS_RING_CFG_DONE_EVENTID, + &reply, sizeof(reply), WIL_WMI_CALL_GENERAL_TO_MS); + if (rc) { + wil_err(wil, "TX_STATUS_RING_ADD_CMD failed, rc %d\n", rc); + return rc; + } + + if (reply.evt.status != WMI_FW_STATUS_SUCCESS) { + wil_err(wil, "TX_STATUS_RING_ADD_CMD failed, status %d\n", + reply.evt.status); + return -EINVAL; + } + + sring->hwtail = le32_to_cpu(reply.evt.ring_tail_ptr); + + return 0; +} + +int wil_wmi_cfg_def_rx_offload(struct wil6210_priv *wil, u16 max_rx_pl_per_desc) +{ + struct net_device *ndev = wil->main_ndev; + struct wil6210_vif *vif = ndev_to_vif(ndev); + int rc; + struct wmi_cfg_def_rx_offload_cmd cmd = { + .max_msdu_size = cpu_to_le16(wil_mtu2macbuf(WIL_MAX_ETH_MTU)), + .max_rx_pl_per_desc = cpu_to_le16(max_rx_pl_per_desc), + .decap_trans_type = WMI_DECAP_TYPE_802_3, + .l2_802_3_offload_ctrl = 0, + .l3_l4_ctrl = 1 << L3_L4_CTRL_TCPIP_CHECKSUM_EN_POS, + }; + struct { + struct wmi_cmd_hdr hdr; + struct wmi_cfg_def_rx_offload_done_event evt; + } __packed reply = { + .evt = {.status = WMI_FW_STATUS_FAILURE}, + }; + + rc = wmi_call(wil, WMI_CFG_DEF_RX_OFFLOAD_CMDID, vif->mid, &cmd, + sizeof(cmd), WMI_CFG_DEF_RX_OFFLOAD_DONE_EVENTID, &reply, + sizeof(reply), WIL_WMI_CALL_GENERAL_TO_MS); + if (rc) { + wil_err(wil, "WMI_CFG_DEF_RX_OFFLOAD_CMD failed, rc %d\n", rc); + return rc; + } + + if (reply.evt.status != WMI_FW_STATUS_SUCCESS) { + wil_err(wil, "WMI_CFG_DEF_RX_OFFLOAD_CMD failed, status %d\n", + reply.evt.status); + return -EINVAL; + } + + return 0; +} + +int wil_wmi_rx_sring_add(struct wil6210_priv *wil, u16 ring_id) +{ + struct net_device *ndev = wil->main_ndev; + struct wil6210_vif *vif = ndev_to_vif(ndev); + struct wil_status_ring *sring = &wil->srings[ring_id]; + int rc; + struct wmi_rx_status_ring_add_cmd cmd = { + .ring_cfg = { + .ring_size = cpu_to_le16(sring->size), + .ring_id = ring_id, + }, + .rx_msg_type = use_compressed_rx_status ? + WMI_RX_MSG_TYPE_COMPRESSED : + WMI_RX_MSG_TYPE_EXTENDED, + .irq_index = WIL_RX_STATUS_IRQ_IDX, + }; + struct { + struct wmi_cmd_hdr hdr; + struct wmi_rx_status_ring_cfg_done_event evt; + } __packed reply; + + cmd.ring_cfg.ring_mem_base = cpu_to_le64(sring->pa); + reply.evt.status = WMI_FW_STATUS_FAILURE; + rc = wmi_call(wil, WMI_RX_STATUS_RING_ADD_CMDID, vif->mid, &cmd, + sizeof(cmd), WMI_RX_STATUS_RING_CFG_DONE_EVENTID, &reply, + sizeof(reply), WIL_WMI_CALL_GENERAL_TO_MS); + if (rc) { + wil_err(wil, "RX_STATUS_RING_ADD_CMD failed, rc %d\n", rc); + return rc; + } + + if (reply.evt.status != WMI_FW_STATUS_SUCCESS) { + wil_err(wil, "RX_STATUS_RING_ADD_CMD failed, status %d\n", + reply.evt.status); + return -EINVAL; + } + + sring->hwtail = le32_to_cpu(reply.evt.ring_tail_ptr); + + return 0; +} + +int wil_wmi_rx_desc_ring_add(struct wil6210_priv *wil, int status_ring_id) +{ + struct net_device *ndev = wil->main_ndev; + struct wil6210_vif *vif = ndev_to_vif(ndev); + struct wil_ring *ring = &wil->ring_rx; + int rc; + struct wmi_rx_desc_ring_add_cmd cmd = { + .ring_cfg = { + .ring_size = cpu_to_le16(ring->size), + .ring_id = WIL_RX_DESC_RING_ID, + }, + .status_ring_id = status_ring_id, + .irq_index = WIL_RX_STATUS_IRQ_IDX, + }; + struct { + struct wmi_cmd_hdr hdr; + struct wmi_rx_desc_ring_cfg_done_event evt; + } __packed reply; + + cmd.ring_cfg.ring_mem_base = cpu_to_le64(ring->pa); + cmd.sw_tail_host_addr = cpu_to_le64(ring->edma_rx_swtail.pa); + reply.evt.status = WMI_FW_STATUS_FAILURE; + rc = wmi_call(wil, WMI_RX_DESC_RING_ADD_CMDID, vif->mid, &cmd, + sizeof(cmd), WMI_RX_DESC_RING_CFG_DONE_EVENTID, &reply, + sizeof(reply), WIL_WMI_CALL_GENERAL_TO_MS); + if (rc) { + wil_err(wil, "WMI_RX_DESC_RING_ADD_CMD failed, rc %d\n", rc); + return rc; + } + + if (reply.evt.status != WMI_FW_STATUS_SUCCESS) { + wil_err(wil, "WMI_RX_DESC_RING_ADD_CMD failed, status %d\n", + reply.evt.status); + return -EINVAL; + } + + ring->hwtail = le32_to_cpu(reply.evt.ring_tail_ptr); + + return 0; +} + +int wil_wmi_tx_desc_ring_add(struct wil6210_vif *vif, int ring_id, int cid, + int tid) +{ + struct wil6210_priv *wil = vif_to_wil(vif); + int sring_id = wil->tx_sring_idx; /* there is only one TX sring */ + int rc; + struct wil_ring *ring = &wil->ring_tx[ring_id]; + struct wil_ring_tx_data *txdata = &wil->ring_tx_data[ring_id]; + struct wmi_tx_desc_ring_add_cmd cmd = { + .ring_cfg = { + .ring_size = cpu_to_le16(ring->size), + .ring_id = ring_id, + }, + .status_ring_id = sring_id, + .cid = cid, + .tid = tid, + .encap_trans_type = WMI_VRING_ENC_TYPE_802_3, + .max_msdu_size = cpu_to_le16(wil_mtu2macbuf(mtu_max)), + .schd_params = { + .priority = cpu_to_le16(0), + .timeslot_us = cpu_to_le16(0xfff), + } + }; + struct { + struct wmi_cmd_hdr hdr; + struct wmi_tx_desc_ring_cfg_done_event evt; + } __packed reply; + + cmd.ring_cfg.ring_mem_base = cpu_to_le64(ring->pa); + reply.evt.status = WMI_FW_STATUS_FAILURE; + rc = wmi_call(wil, WMI_TX_DESC_RING_ADD_CMDID, vif->mid, &cmd, + sizeof(cmd), WMI_TX_DESC_RING_CFG_DONE_EVENTID, &reply, + sizeof(reply), WIL_WMI_CALL_GENERAL_TO_MS); + if (rc) { + wil_err(wil, "WMI_TX_DESC_RING_ADD_CMD failed, rc %d\n", rc); + return rc; + } + + if (reply.evt.status != WMI_FW_STATUS_SUCCESS) { + wil_err(wil, "WMI_TX_DESC_RING_ADD_CMD failed, status %d\n", + reply.evt.status); + return -EINVAL; + } + + spin_lock_bh(&txdata->lock); + ring->hwtail = le32_to_cpu(reply.evt.ring_tail_ptr); + txdata->mid = vif->mid; + txdata->enabled = 1; + spin_unlock_bh(&txdata->lock); + + return 0; +} + +int wil_wmi_bcast_desc_ring_add(struct wil6210_vif *vif, int ring_id) +{ + struct wil6210_priv *wil = vif_to_wil(vif); + struct wil_ring *ring = &wil->ring_tx[ring_id]; + int rc; + struct wmi_bcast_desc_ring_add_cmd cmd = { + .ring_cfg = { + .ring_size = cpu_to_le16(ring->size), + .ring_id = ring_id, + }, + .status_ring_id = wil->tx_sring_idx, + .encap_trans_type = WMI_VRING_ENC_TYPE_802_3, + }; + struct { + struct wmi_cmd_hdr hdr; + struct wmi_rx_desc_ring_cfg_done_event evt; + } __packed reply; + struct wil_ring_tx_data *txdata = &wil->ring_tx_data[ring_id]; + + cmd.ring_cfg.ring_mem_base = cpu_to_le64(ring->pa); + reply.evt.status = WMI_FW_STATUS_FAILURE; + rc = wmi_call(wil, WMI_BCAST_DESC_RING_ADD_CMDID, vif->mid, &cmd, + sizeof(cmd), WMI_TX_DESC_RING_CFG_DONE_EVENTID, &reply, + sizeof(reply), WIL_WMI_CALL_GENERAL_TO_MS); + if (rc) { + wil_err(wil, "WMI_BCAST_DESC_RING_ADD_CMD failed, rc %d\n", rc); + return rc; + } + + if (reply.evt.status != WMI_FW_STATUS_SUCCESS) { + wil_err(wil, "Broadcast Tx config failed, status %d\n", + reply.evt.status); + return -EINVAL; + } + + spin_lock_bh(&txdata->lock); + ring->hwtail = le32_to_cpu(reply.evt.ring_tail_ptr); + txdata->mid = vif->mid; + txdata->enabled = 1; + spin_unlock_bh(&txdata->lock); + + return 0; +} diff --git a/drivers/net/wireless/ath/wil6210/wmi.h b/drivers/net/wireless/ath/wil6210/wmi.h index 28568dc15d7a..93f9e08b7710 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.h +++ b/drivers/net/wireless/ath/wil6210/wmi.h @@ -136,8 +136,8 @@ enum wmi_command_id { WMI_CFG_RX_CHAIN_CMDID = 0x820, WMI_VRING_CFG_CMDID = 0x821, WMI_BCAST_VRING_CFG_CMDID = 0x822, - WMI_VRING_BA_EN_CMDID = 0x823, - WMI_VRING_BA_DIS_CMDID = 0x824, + WMI_RING_BA_EN_CMDID = 0x823, + WMI_RING_BA_DIS_CMDID = 0x824, WMI_RCP_ADDBA_RESP_CMDID = 0x825, WMI_RCP_DELBA_CMDID = 0x826, WMI_SET_SSID_CMDID = 0x827, @@ -151,6 +151,7 @@ enum wmi_command_id { WMI_BF_SM_MGMT_CMDID = 0x838, WMI_BF_RXSS_MGMT_CMDID = 0x839, WMI_BF_TRIG_CMDID = 0x83A, + WMI_RCP_ADDBA_RESP_EDMA_CMDID = 0x83B, WMI_LINK_MAINTAIN_CFG_WRITE_CMDID = 0x842, WMI_LINK_MAINTAIN_CFG_READ_CMDID = 0x843, WMI_SET_SECTORS_CMDID = 0x849, @@ -219,6 +220,12 @@ enum wmi_command_id { WMI_PRIO_TX_SECTORS_ORDER_CMDID = 0x9A5, WMI_PRIO_TX_SECTORS_NUMBER_CMDID = 0x9A6, WMI_PRIO_TX_SECTORS_SET_DEFAULT_CFG_CMDID = 0x9A7, + WMI_TX_STATUS_RING_ADD_CMDID = 0x9C0, + WMI_RX_STATUS_RING_ADD_CMDID = 0x9C1, + WMI_TX_DESC_RING_ADD_CMDID = 0x9C2, + WMI_RX_DESC_RING_ADD_CMDID = 0x9C3, + WMI_BCAST_DESC_RING_ADD_CMDID = 0x9C4, + WMI_CFG_DEF_RX_OFFLOAD_CMDID = 0x9C5, WMI_SCHEDULING_SCHEME_CMDID = 0xA01, WMI_FIXED_SCHEDULING_CONFIG_CMDID = 0xA02, WMI_ENABLE_FIXED_SCHEDULING_CMDID = 0xA03, @@ -716,18 +723,90 @@ struct wmi_lo_power_calib_from_otp_event { u8 reserved[3]; } __packed; -/* WMI_VRING_BA_EN_CMDID */ -struct wmi_vring_ba_en_cmd { - u8 ringid; +struct wmi_edma_ring_cfg { + __le64 ring_mem_base; + /* size in number of items */ + __le16 ring_size; + u8 ring_id; + u8 reserved; +} __packed; + +enum wmi_rx_msg_type { + WMI_RX_MSG_TYPE_COMPRESSED = 0x00, + WMI_RX_MSG_TYPE_EXTENDED = 0x01, +}; + +struct wmi_tx_status_ring_add_cmd { + struct wmi_edma_ring_cfg ring_cfg; + u8 irq_index; + u8 reserved[3]; +} __packed; + +struct wmi_rx_status_ring_add_cmd { + struct wmi_edma_ring_cfg ring_cfg; + u8 irq_index; + /* wmi_rx_msg_type */ + u8 rx_msg_type; + u8 reserved[2]; +} __packed; + +struct wmi_cfg_def_rx_offload_cmd { + __le16 max_msdu_size; + __le16 max_rx_pl_per_desc; + u8 decap_trans_type; + u8 l2_802_3_offload_ctrl; + u8 l2_nwifi_offload_ctrl; + u8 vlan_id; + u8 nwifi_ds_trans_type; + u8 l3_l4_ctrl; + u8 reserved[6]; +} __packed; + +struct wmi_tx_desc_ring_add_cmd { + struct wmi_edma_ring_cfg ring_cfg; + __le16 max_msdu_size; + /* Correlated status ring (0-63) */ + u8 status_ring_id; + u8 cid; + u8 tid; + u8 encap_trans_type; + u8 mac_ctrl; + u8 to_resolution; + u8 agg_max_wsize; + u8 reserved[3]; + struct wmi_vring_cfg_schd schd_params; +} __packed; + +struct wmi_rx_desc_ring_add_cmd { + struct wmi_edma_ring_cfg ring_cfg; + u8 irq_index; + /* 0-63 status rings */ + u8 status_ring_id; + u8 reserved[2]; + __le64 sw_tail_host_addr; +} __packed; + +struct wmi_bcast_desc_ring_add_cmd { + struct wmi_edma_ring_cfg ring_cfg; + __le16 max_msdu_size; + /* Correlated status ring (0-63) */ + u8 status_ring_id; + u8 encap_trans_type; + u8 reserved[4]; +} __packed; + +/* WMI_RING_BA_EN_CMDID */ +struct wmi_ring_ba_en_cmd { + u8 ring_id; u8 agg_max_wsize; __le16 ba_timeout; u8 amsdu; u8 reserved[3]; } __packed; -/* WMI_VRING_BA_DIS_CMDID */ -struct wmi_vring_ba_dis_cmd { - u8 ringid; +/* WMI_RING_BA_DIS_CMDID */ +struct wmi_ring_ba_dis_cmd { + u8 ring_id; u8 reserved; __le16 reason; } __packed; @@ -877,6 +956,21 @@ struct wmi_rcp_addba_resp_cmd { __le16 ba_timeout; } __packed; +/* WMI_RCP_ADDBA_RESP_EDMA_CMDID */ +struct wmi_rcp_addba_resp_edma_cmd { + u8 cid; + u8 tid; + u8 dialog_token; + u8 reserved; + __le16 status_code; + /* ieee80211_ba_parameterset field to send */ + __le16 ba_param_set; + __le16 ba_timeout; + u8 status_ring_id; + /* wmi_cfg_rx_chain_cmd_reorder_type */ + u8 reorder_type; +} __packed; + /* WMI_RCP_DELBA_CMDID */ struct wmi_rcp_delba_cmd { u8 cidxtid; @@ -1332,7 +1426,7 @@ enum wmi_event_id { WMI_BF_CTRL_DONE_EVENTID = 0x1862, WMI_NOTIFY_REQ_DONE_EVENTID = 0x1863, WMI_GET_STATUS_DONE_EVENTID = 0x1864, - WMI_VRING_EN_EVENTID = 0x1865, + WMI_RING_EN_EVENTID = 0x1865, WMI_GET_RF_STATUS_EVENTID = 0x1866, WMI_GET_BASEBAND_TYPE_EVENTID = 0x1867, WMI_UNIT_TEST_EVENTID = 0x1900, @@ -1381,6 +1475,11 @@ enum wmi_event_id { WMI_PRIO_TX_SECTORS_ORDER_EVENTID = 0x19A5, WMI_PRIO_TX_SECTORS_NUMBER_EVENTID = 0x19A6, WMI_PRIO_TX_SECTORS_SET_DEFAULT_CFG_EVENTID = 0x19A7, + WMI_TX_STATUS_RING_CFG_DONE_EVENTID = 0x19C0, + WMI_RX_STATUS_RING_CFG_DONE_EVENTID = 0x19C1, + WMI_TX_DESC_RING_CFG_DONE_EVENTID = 0x19C2, + WMI_RX_DESC_RING_CFG_DONE_EVENTID = 0x19C3, + WMI_CFG_DEF_RX_OFFLOAD_DONE_EVENTID = 0x19C5, WMI_SCHEDULING_SCHEME_EVENTID = 0x1A01, WMI_FIXED_SCHEDULING_CONFIG_COMPLETE_EVENTID = 0x1A02, WMI_ENABLE_FIXED_SCHEDULING_COMPLETE_EVENTID = 0x1A03, @@ -1760,6 +1859,49 @@ struct wmi_rcp_addba_resp_sent_event { __le16 status; } __packed; +/* WMI_TX_STATUS_RING_CFG_DONE_EVENTID */ +struct wmi_tx_status_ring_cfg_done_event { + u8 ring_id; + /* wmi_fw_status */ + u8 status; + u8 reserved[2]; + __le32 ring_tail_ptr; +} __packed; + +/* WMI_RX_STATUS_RING_CFG_DONE_EVENTID */ +struct wmi_rx_status_ring_cfg_done_event { + u8 ring_id; + /* wmi_fw_status */ + u8 status; + u8 reserved[2]; + __le32 ring_tail_ptr; +} __packed; + +/* WMI_CFG_DEF_RX_OFFLOAD_DONE_EVENTID */ +struct wmi_cfg_def_rx_offload_done_event { + /* wmi_fw_status */ + u8 status; + u8 reserved[3]; +} __packed; + +/* WMI_TX_DESC_RING_CFG_DONE_EVENTID */ +struct wmi_tx_desc_ring_cfg_done_event { + u8 ring_id; + /* wmi_fw_status */ + u8 status; + u8 reserved[2]; + __le32 ring_tail_ptr; +} __packed; + +/* WMI_RX_DESC_RING_CFG_DONE_EVENTID */ +struct wmi_rx_desc_ring_cfg_done_event { + u8 ring_id; + /* wmi_fw_status */ + u8 status; + u8 reserved[2]; + __le32 ring_tail_ptr; +} __packed; + /* WMI_RCP_ADDBA_REQ_EVENTID */ struct wmi_rcp_addba_req_event { u8 cidxtid; @@ -1802,9 +1944,9 @@ struct wmi_data_port_open_event { u8 reserved[3]; } __packed; -/* WMI_VRING_EN_EVENTID */ -struct wmi_vring_en_event { - u8 vring_index; +/* WMI_RING_EN_EVENTID */ +struct wmi_ring_en_event { + u8 ring_index; u8 reserved[3]; } __packed; -- GitLab From 0099376d8534a7fb08f7012e899e0855ccb16313 Mon Sep 17 00:00:00 2001 From: Maya Erez Date: Sun, 18 Feb 2018 16:01:10 +0200 Subject: [PATCH 0132/1635] wil6210: add support for enhanced DMA TX data flows The enhanced DMA TX data path is handled using a descriptor ring per connection and a single status ring. The driver gets TX completions via the TX status ring. Each status message points to the completed descriptor ring and includes the number of completed descriptors in this ring. Non TSO enhanced DMA TX descriptors are similar to legacy DMA TX descriptors, hence the same transmit function can be used. However, enhanced DMA TSO frames division is performed by the HW, hence a new function is added to handle enhanced DMA TSO. Change-Id: I5049c5c2dc062e11334faae0ef6d45ed712882c8 Signed-off-by: Gidon Studinski Signed-off-by: Maya Erez --- drivers/net/wireless/ath/wil6210/interrupt.c | 126 +++++- drivers/net/wireless/ath/wil6210/netdev.c | 36 +- drivers/net/wireless/ath/wil6210/trace.h | 25 ++ drivers/net/wireless/ath/wil6210/txrx.c | 194 ++++----- drivers/net/wireless/ath/wil6210/txrx.h | 22 + drivers/net/wireless/ath/wil6210/txrx_edma.c | 425 ++++++++++++++++++- drivers/net/wireless/ath/wil6210/txrx_edma.h | 33 +- drivers/net/wireless/ath/wil6210/wil6210.h | 15 + 8 files changed, 748 insertions(+), 128 deletions(-) diff --git a/drivers/net/wireless/ath/wil6210/interrupt.c b/drivers/net/wireless/ath/wil6210/interrupt.c index 311d48233165..1603b9f7feb9 100644 --- a/drivers/net/wireless/ath/wil6210/interrupt.c +++ b/drivers/net/wireless/ath/wil6210/interrupt.c @@ -44,6 +44,7 @@ (~(BIT_DMA_EP_RX_ICR_RX_HTRSH))) #define WIL6210_IMC_TX (BIT_DMA_EP_TX_ICR_TX_DONE | \ BIT_DMA_EP_TX_ICR_TX_DONE_N(0)) +#define WIL6210_IMC_TX_EDMA BIT_TX_STATUS_IRQ #define WIL6210_IMC_MISC_NO_HALP (ISR_MISC_FW_READY | \ ISR_MISC_MBOX_EVT | \ ISR_MISC_FW_ERROR) @@ -87,6 +88,12 @@ static void wil6210_mask_irq_tx(struct wil6210_priv *wil) WIL6210_IRQ_DISABLE); } +static void wil6210_mask_irq_tx_edma(struct wil6210_priv *wil) +{ + wil_w(wil, RGF_INT_GEN_TX_ICR + offsetof(struct RGF_ICR, IMS), + WIL6210_IRQ_DISABLE); +} + static void wil6210_mask_irq_rx(struct wil6210_priv *wil) { wil_w(wil, RGF_DMA_EP_RX_ICR + offsetof(struct RGF_ICR, IMS), @@ -125,6 +132,12 @@ void wil6210_unmask_irq_tx(struct wil6210_priv *wil) WIL6210_IMC_TX); } +void wil6210_unmask_irq_tx_edma(struct wil6210_priv *wil) +{ + wil_w(wil, RGF_INT_GEN_TX_ICR + offsetof(struct RGF_ICR, IMC), + WIL6210_IMC_TX_EDMA); +} + void wil6210_unmask_irq_rx(struct wil6210_priv *wil) { bool unmask_rx_htrsh = atomic_read(&wil->connected_vifs) > 0; @@ -164,6 +177,7 @@ void wil_mask_irq(struct wil6210_priv *wil) wil_dbg_irq(wil, "mask_irq\n"); wil6210_mask_irq_tx(wil); + wil6210_mask_irq_tx_edma(wil); wil6210_mask_irq_rx(wil); wil6210_mask_irq_misc(wil, true); wil6210_mask_irq_pseudo(wil); @@ -179,10 +193,16 @@ void wil_unmask_irq(struct wil6210_priv *wil) WIL_ICR_ICC_VALUE); wil_w(wil, RGF_DMA_EP_MISC_ICR + offsetof(struct RGF_ICR, ICC), WIL_ICR_ICC_MISC_VALUE); + wil_w(wil, RGF_INT_GEN_TX_ICR + offsetof(struct RGF_ICR, ICC), + WIL_ICR_ICC_VALUE); wil6210_unmask_irq_pseudo(wil); - wil6210_unmask_irq_tx(wil); - wil6210_unmask_irq_rx(wil); + if (wil->use_enhanced_dma_hw) { + wil6210_unmask_irq_tx_edma(wil); + } else { + wil6210_unmask_irq_tx(wil); + wil6210_unmask_irq_rx(wil); + } wil6210_unmask_irq_misc(wil, true); } @@ -315,6 +335,49 @@ static irqreturn_t wil6210_irq_rx(int irq, void *cookie) return IRQ_HANDLED; } +static irqreturn_t wil6210_irq_tx_edma(int irq, void *cookie) +{ + struct wil6210_priv *wil = cookie; + u32 isr = wil_ioread32_and_clear(wil->csr + + HOSTADDR(RGF_INT_GEN_TX_ICR) + + offsetof(struct RGF_ICR, ICR)); + bool need_unmask = true; + + trace_wil6210_irq_tx(isr); + wil_dbg_irq(wil, "ISR TX 0x%08x\n", isr); + + if (unlikely(!isr)) { + wil_err(wil, "spurious IRQ: TX\n"); + return IRQ_NONE; + } + + wil6210_mask_irq_tx_edma(wil); + + if (likely(isr & BIT_TX_STATUS_IRQ)) { + wil_dbg_irq(wil, "TX status ring\n"); + isr &= ~BIT_TX_STATUS_IRQ; + if (likely(test_bit(wil_status_fwready, wil->status))) { + wil_dbg_txrx(wil, "NAPI(Tx) schedule\n"); + need_unmask = false; + napi_schedule(&wil->napi_tx); + } else { + wil_err(wil, "Got Tx status ring IRQ while in reset\n"); + } + } + + if (unlikely(isr)) + wil_err(wil, "un-handled TX ISR bits 0x%08x\n", isr); + + /* Tx IRQ will be enabled when NAPI processing finished */ + + atomic_inc(&wil->isr_count_tx); + + if (unlikely(need_unmask)) + wil6210_unmask_irq_tx_edma(wil); + + return IRQ_HANDLED; +} + static irqreturn_t wil6210_irq_tx(int irq, void *cookie) { struct wil6210_priv *wil = cookie; @@ -531,30 +594,45 @@ static irqreturn_t wil6210_thread_irq(int irq, void *cookie) */ static int wil6210_debug_irq_mask(struct wil6210_priv *wil, u32 pseudo_cause) { + u32 icm_rx = 0, icr_rx = 0, imv_rx = 0; + u32 icm_tx, icr_tx, imv_tx; + u32 icm_misc, icr_misc, imv_misc; + if (!test_bit(wil_status_irqen, wil->status)) { - u32 icm_rx = wil_ioread32_and_clear(wil->csr + - HOSTADDR(RGF_DMA_EP_RX_ICR) + - offsetof(struct RGF_ICR, ICM)); - u32 icr_rx = wil_ioread32_and_clear(wil->csr + - HOSTADDR(RGF_DMA_EP_RX_ICR) + - offsetof(struct RGF_ICR, ICR)); - u32 imv_rx = wil_r(wil, RGF_DMA_EP_RX_ICR + - offsetof(struct RGF_ICR, IMV)); - u32 icm_tx = wil_ioread32_and_clear(wil->csr + - HOSTADDR(RGF_DMA_EP_TX_ICR) + - offsetof(struct RGF_ICR, ICM)); - u32 icr_tx = wil_ioread32_and_clear(wil->csr + - HOSTADDR(RGF_DMA_EP_TX_ICR) + - offsetof(struct RGF_ICR, ICR)); - u32 imv_tx = wil_r(wil, RGF_DMA_EP_TX_ICR + + if (wil->use_enhanced_dma_hw) { + icm_tx = wil_ioread32_and_clear(wil->csr + + HOSTADDR(RGF_INT_GEN_TX_ICR) + + offsetof(struct RGF_ICR, ICM)); + icr_tx = wil_ioread32_and_clear(wil->csr + + HOSTADDR(RGF_INT_GEN_TX_ICR) + + offsetof(struct RGF_ICR, ICR)); + imv_tx = wil_r(wil, RGF_INT_GEN_TX_ICR + + offsetof(struct RGF_ICR, IMV)); + } else { + icm_rx = wil_ioread32_and_clear(wil->csr + + HOSTADDR(RGF_DMA_EP_RX_ICR) + + offsetof(struct RGF_ICR, ICM)); + icr_rx = wil_ioread32_and_clear(wil->csr + + HOSTADDR(RGF_DMA_EP_RX_ICR) + + offsetof(struct RGF_ICR, ICR)); + imv_rx = wil_r(wil, RGF_DMA_EP_RX_ICR + offsetof(struct RGF_ICR, IMV)); - u32 icm_misc = wil_ioread32_and_clear(wil->csr + + icm_tx = wil_ioread32_and_clear(wil->csr + + HOSTADDR(RGF_DMA_EP_TX_ICR) + + offsetof(struct RGF_ICR, ICM)); + icr_tx = wil_ioread32_and_clear(wil->csr + + HOSTADDR(RGF_DMA_EP_TX_ICR) + + offsetof(struct RGF_ICR, ICR)); + imv_tx = wil_r(wil, RGF_DMA_EP_TX_ICR + + offsetof(struct RGF_ICR, IMV)); + } + icm_misc = wil_ioread32_and_clear(wil->csr + HOSTADDR(RGF_DMA_EP_MISC_ICR) + offsetof(struct RGF_ICR, ICM)); - u32 icr_misc = wil_ioread32_and_clear(wil->csr + + icr_misc = wil_ioread32_and_clear(wil->csr + HOSTADDR(RGF_DMA_EP_MISC_ICR) + offsetof(struct RGF_ICR, ICR)); - u32 imv_misc = wil_r(wil, RGF_DMA_EP_MISC_ICR + + imv_misc = wil_r(wil, RGF_DMA_EP_MISC_ICR + offsetof(struct RGF_ICR, IMV)); /* HALP interrupt can be unmasked when misc interrupts are @@ -617,7 +695,7 @@ static irqreturn_t wil6210_hardirq(int irq, void *cookie) rc = IRQ_WAKE_THREAD; if ((pseudo_cause & BIT_DMA_PSEUDO_CAUSE_TX) && - (wil6210_irq_tx(irq, cookie) == IRQ_WAKE_THREAD)) + (wil->txrx_ops.irq_tx(irq, cookie) == IRQ_WAKE_THREAD)) rc = IRQ_WAKE_THREAD; if ((pseudo_cause & BIT_DMA_PSEUDO_CAUSE_MISC) && @@ -645,6 +723,8 @@ void wil6210_clear_irq(struct wil6210_priv *wil) offsetof(struct RGF_ICR, ICR)); wil_clear32(wil->csr + HOSTADDR(RGF_DMA_EP_TX_ICR) + offsetof(struct RGF_ICR, ICR)); + wil_clear32(wil->csr + HOSTADDR(RGF_INT_GEN_TX_ICR) + + offsetof(struct RGF_ICR, ICR)); wil_clear32(wil->csr + HOSTADDR(RGF_DMA_EP_MISC_ICR) + offsetof(struct RGF_ICR, ICR)); wmb(); /* make sure write completed */ @@ -673,6 +753,10 @@ int wil6210_init_irq(struct wil6210_priv *wil, int irq, bool use_msi) wil_dbg_misc(wil, "init_irq: %s\n", use_msi ? "MSI" : "INTx"); + if (wil->use_enhanced_dma_hw) + wil->txrx_ops.irq_tx = wil6210_irq_tx_edma; + else + wil->txrx_ops.irq_tx = wil6210_irq_tx; rc = request_threaded_irq(irq, wil6210_hardirq, wil6210_thread_irq, use_msi ? 0 : IRQF_SHARED, diff --git a/drivers/net/wireless/ath/wil6210/netdev.c b/drivers/net/wireless/ath/wil6210/netdev.c index df575cd99a8f..8482a6b2288d 100644 --- a/drivers/net/wireless/ath/wil6210/netdev.c +++ b/drivers/net/wireless/ath/wil6210/netdev.c @@ -170,6 +170,30 @@ static int wil6210_netdev_poll_tx(struct napi_struct *napi, int budget) return min(tx_done, budget); } +static int wil6210_netdev_poll_tx_edma(struct napi_struct *napi, int budget) +{ + struct wil6210_priv *wil = container_of(napi, struct wil6210_priv, + napi_tx); + int tx_done; + /* There is only one status TX ring */ + struct wil_status_ring *sring = &wil->srings[wil->tx_sring_idx]; + + if (!sring->va) + return 0; + + tx_done = wil_tx_sring_handler(wil, sring); + + if (tx_done < budget) { + napi_complete(napi); + wil6210_unmask_irq_tx_edma(wil); + wil_dbg_txrx(wil, "NAPI TX complete\n"); + } + + wil_dbg_txrx(wil, "NAPI TX poll(%d) done %d\n", budget, tx_done); + + return min(tx_done, budget); +} + static void wil_dev_setup(struct net_device *dev) { ether_setup(dev); @@ -437,9 +461,15 @@ int wil_if_add(struct wil6210_priv *wil) init_dummy_netdev(&wil->napi_ndev); netif_napi_add(&wil->napi_ndev, &wil->napi_rx, wil6210_netdev_poll_rx, WIL6210_NAPI_BUDGET); - netif_tx_napi_add(&wil->napi_ndev, - &wil->napi_tx, wil6210_netdev_poll_tx, - WIL6210_NAPI_BUDGET); + if (wil->use_enhanced_dma_hw) + netif_tx_napi_add(&wil->napi_ndev, + &wil->napi_tx, wil6210_netdev_poll_tx_edma, + WIL6210_NAPI_BUDGET); + else + netif_tx_napi_add(&wil->napi_ndev, + &wil->napi_tx, wil6210_netdev_poll_tx, + WIL6210_NAPI_BUDGET); + wil_update_net_queues_bh(wil, vif, NULL, true); diff --git a/drivers/net/wireless/ath/wil6210/trace.h b/drivers/net/wireless/ath/wil6210/trace.h index c4db2a9d9f7f..6aed2461b0d4 100644 --- a/drivers/net/wireless/ath/wil6210/trace.h +++ b/drivers/net/wireless/ath/wil6210/trace.h @@ -226,6 +226,31 @@ TRACE_EVENT(wil6210_tx_done, __entry->err) ); +TRACE_EVENT(wil6210_tx_status, + TP_PROTO(struct wil_ring_tx_status *msg, u16 index, + unsigned int len), + TP_ARGS(msg, index, len), + TP_STRUCT__entry(__field(u16, index) + __field(unsigned int, len) + __field(u8, num_descs) + __field(u8, ring_id) + __field(u8, status) + __field(u8, mcs) + + ), + TP_fast_assign(__entry->index = index; + __entry->len = len; + __entry->num_descs = msg->num_descriptors; + __entry->ring_id = msg->ring_id; + __entry->status = msg->status; + __entry->mcs = wil_tx_status_get_mcs(msg); + ), + TP_printk( + "ring_id %d swtail 0x%x len %d num_descs %d status 0x%x mcs %d", + __entry->ring_id, __entry->index, __entry->len, + __entry->num_descs, __entry->status, __entry->mcs) +); + #endif /* WIL6210_TRACE_H || TRACE_HEADER_MULTI_READ*/ #if defined(CONFIG_WIL6210_TRACING) && !defined(__CHECKER__) diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c index 64a4b1f6e681..9a84f5947d27 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.c +++ b/drivers/net/wireless/ath/wil6210/txrx.c @@ -117,12 +117,6 @@ bool wil_is_tx_idle(struct wil6210_priv *wil) return true; } -/* wil_val_in_range - check if value in [min,max) */ -static inline bool wil_val_in_range(int val, int min, int max) -{ - return val >= min && val < max; -} - static int wil_vring_alloc(struct wil6210_priv *wil, struct wil_ring *vring) { struct device *dev = wil_to_dev(wil); @@ -184,9 +178,10 @@ static int wil_vring_alloc(struct wil6210_priv *wil, struct wil_ring *vring) return 0; } -static void wil_txdesc_unmap(struct device *dev, struct vring_tx_desc *d, +static void wil_txdesc_unmap(struct device *dev, union wil_tx_desc *desc, struct wil_ctx *ctx) { + struct vring_tx_desc *d = &desc->legacy; dma_addr_t pa = wil_desc_addr(&d->dma.addr); u16 dmalen = le16_to_cpu(d->dma.length); @@ -239,7 +234,7 @@ static void wil_vring_free(struct wil6210_priv *wil, struct wil_ring *vring) continue; } *d = *_d; - wil_txdesc_unmap(dev, d, ctx); + wil_txdesc_unmap(dev, (union wil_tx_desc *)d, ctx); if (ctx->skb) dev_kfree_skb_any(ctx->skb); vring->swtail = wil_ring_next_tail(vring); @@ -887,6 +882,30 @@ static void wil_rx_fini(struct wil6210_priv *wil) wil_vring_free(wil, vring); } +static int wil_tx_desc_map(union wil_tx_desc *desc, dma_addr_t pa, + u32 len, int vring_index) +{ + struct vring_tx_desc *d = &desc->legacy; + + wil_desc_addr_set(&d->dma.addr, pa); + d->dma.ip_length = 0; + /* 0..6: mac_length; 7:ip_version 0-IP6 1-IP4*/ + d->dma.b11 = 0/*14 | BIT(7)*/; + d->dma.error = 0; + d->dma.status = 0; /* BIT(0) should be 0 for HW_OWNED */ + d->dma.length = cpu_to_le16((u16)len); + d->dma.d0 = (vring_index << DMA_CFG_DESC_TX_0_QID_POS); + d->mac.d[0] = 0; + d->mac.d[1] = 0; + d->mac.d[2] = 0; + d->mac.ucode_cmd = 0; + /* translation type: 0 - bypass; 1 - 802.3; 2 - native wifi */ + d->mac.d[2] = BIT(MAC_CFG_DESC_TX_2_SNAP_HDR_INSERTION_EN_POS) | + (1 << MAC_CFG_DESC_TX_2_L2_TRANSLATION_TYPE_POS); + + return 0; +} + void wil_tx_data_init(struct wil_ring_tx_data *txdata) { spin_lock_bh(&txdata->lock); @@ -1110,8 +1129,8 @@ static struct wil_ring *wil_find_tx_ucast(struct wil6210_priv *wil, return NULL; } -static int wil_tx_vring(struct wil6210_priv *wil, struct wil6210_vif *vif, - struct wil_ring *vring, struct sk_buff *skb); +static int wil_tx_ring(struct wil6210_priv *wil, struct wil6210_vif *vif, + struct wil_ring *ring, struct sk_buff *skb); static struct wil_ring *wil_find_tx_ring_sta(struct wil6210_priv *wil, struct wil6210_vif *vif, @@ -1254,7 +1273,7 @@ static struct wil_ring *wil_find_tx_bcast_2(struct wil6210_priv *wil, if (skb2) { wil_dbg_txrx(wil, "BCAST DUP -> ring %d\n", i); wil_set_da_for_vring(wil, skb2, i); - wil_tx_vring(wil, vif, v2, skb2); + wil_tx_ring(wil, vif, v2, skb2); } else { wil_err(wil, "skb_copy failed\n"); } @@ -1263,28 +1282,6 @@ static struct wil_ring *wil_find_tx_bcast_2(struct wil6210_priv *wil, return v; } -static int wil_tx_desc_map(struct vring_tx_desc *d, dma_addr_t pa, u32 len, - int vring_index) -{ - wil_desc_addr_set(&d->dma.addr, pa); - d->dma.ip_length = 0; - /* 0..6: mac_length; 7:ip_version 0-IP6 1-IP4*/ - d->dma.b11 = 0/*14 | BIT(7)*/; - d->dma.error = 0; - d->dma.status = 0; /* BIT(0) should be 0 for HW_OWNED */ - d->dma.length = cpu_to_le16((u16)len); - d->dma.d0 = (vring_index << DMA_CFG_DESC_TX_0_QID_POS); - d->mac.d[0] = 0; - d->mac.d[1] = 0; - d->mac.d[2] = 0; - d->mac.ucode_cmd = 0; - /* translation type: 0 - bypass; 1 - 802.3; 2 - native wifi */ - d->mac.d[2] = BIT(MAC_CFG_DESC_TX_2_SNAP_HDR_INSERTION_EN_POS) | - (1 << MAC_CFG_DESC_TX_2_L2_TRANSLATION_TYPE_POS); - - return 0; -} - static inline void wil_tx_desc_set_nr_frags(struct vring_tx_desc *d, int nr_frags) { @@ -1494,7 +1491,8 @@ static int __wil_tx_vring_tso(struct wil6210_priv *wil, struct wil6210_vif *vif, goto err_exit; } - wil_tx_desc_map(hdr_desc, pa, hdrlen, vring_index); + wil->txrx_ops.tx_desc_map((union wil_tx_desc *)hdr_desc, pa, + hdrlen, vring_index); wil_tx_desc_offload_setup_tso(hdr_desc, skb, wil_tso_type_hdr, is_ipv4, tcp_hdr_len, skb_net_hdr_len); wil_tx_last_desc(hdr_desc); @@ -1561,7 +1559,8 @@ static int __wil_tx_vring_tso(struct wil6210_priv *wil, struct wil6210_vif *vif, d = &desc_mem; } - wil_tx_desc_map(d, pa, lenmss, vring_index); + wil->txrx_ops.tx_desc_map((union wil_tx_desc *)d, + pa, lenmss, vring_index); wil_tx_desc_offload_setup_tso(d, skb, desc_tso_type, is_ipv4, tcp_hdr_len, skb_net_hdr_len); @@ -1676,7 +1675,7 @@ static int __wil_tx_vring_tso(struct wil6210_priv *wil, struct wil6210_vif *vif, *d = *_desc; _desc->dma.status = TX_DMA_STATUS_DU; ctx = &vring->ctx[i]; - wil_txdesc_unmap(dev, d, ctx); + wil_txdesc_unmap(dev, (union wil_tx_desc *)d, ctx); memset(ctx, 0, sizeof(*ctx)); descs_used--; } @@ -1684,26 +1683,26 @@ static int __wil_tx_vring_tso(struct wil6210_priv *wil, struct wil6210_vif *vif, return rc; } -static int __wil_tx_vring(struct wil6210_priv *wil, struct wil6210_vif *vif, - struct wil_ring *vring, struct sk_buff *skb) +static int __wil_tx_ring(struct wil6210_priv *wil, struct wil6210_vif *vif, + struct wil_ring *ring, struct sk_buff *skb) { struct device *dev = wil_to_dev(wil); struct vring_tx_desc dd, *d = ⅆ volatile struct vring_tx_desc *_d; - u32 swhead = vring->swhead; - int avail = wil_ring_avail_tx(vring); + u32 swhead = ring->swhead; + int avail = wil_ring_avail_tx(ring); int nr_frags = skb_shinfo(skb)->nr_frags; uint f = 0; - int vring_index = vring - wil->ring_tx; - struct wil_ring_tx_data *txdata = &wil->ring_tx_data[vring_index]; + int ring_index = ring - wil->ring_tx; + struct wil_ring_tx_data *txdata = &wil->ring_tx_data[ring_index]; uint i = swhead; dma_addr_t pa; int used; - bool mcast = (vring_index == vif->bcast_ring); + bool mcast = (ring_index == vif->bcast_ring); uint len = skb_headlen(skb); wil_dbg_txrx(wil, "tx_ring: %d bytes to ring %d, nr_frags %d\n", - skb->len, vring_index, nr_frags); + skb->len, ring_index, nr_frags); if (unlikely(!txdata->enabled)) return -EINVAL; @@ -1711,23 +1710,24 @@ static int __wil_tx_vring(struct wil6210_priv *wil, struct wil6210_vif *vif, if (unlikely(avail < 1 + nr_frags)) { wil_err_ratelimited(wil, "Tx ring[%2d] full. No space for %d fragments\n", - vring_index, 1 + nr_frags); + ring_index, 1 + nr_frags); return -ENOMEM; } - _d = &vring->va[i].tx.legacy; + _d = &ring->va[i].tx.legacy; pa = dma_map_single(dev, skb->data, skb_headlen(skb), DMA_TO_DEVICE); - wil_dbg_txrx(wil, "Tx[%2d] skb %d bytes 0x%p -> %pad\n", vring_index, + wil_dbg_txrx(wil, "Tx[%2d] skb %d bytes 0x%p -> %pad\n", ring_index, skb_headlen(skb), skb->data, &pa); wil_hex_dump_txrx("Tx ", DUMP_PREFIX_OFFSET, 16, 1, skb->data, skb_headlen(skb), false); if (unlikely(dma_mapping_error(dev, pa))) return -EINVAL; - vring->ctx[i].mapped_as = wil_mapped_as_single; + ring->ctx[i].mapped_as = wil_mapped_as_single; /* 1-st segment */ - wil_tx_desc_map(d, pa, len, vring_index); + wil->txrx_ops.tx_desc_map((union wil_tx_desc *)d, pa, len, + ring_index); if (unlikely(mcast)) { d->mac.d[0] |= BIT(MAC_CFG_DESC_TX_0_MCS_EN_POS); /* MCS 0 */ if (unlikely(len > WIL_BCAST_MCS0_LIMIT)) /* set MCS 1 */ @@ -1736,11 +1736,11 @@ static int __wil_tx_vring(struct wil6210_priv *wil, struct wil6210_vif *vif, /* Process TCP/UDP checksum offloading */ if (unlikely(wil_tx_desc_offload_setup(d, skb))) { wil_err(wil, "Tx[%2d] Failed to set cksum, drop packet\n", - vring_index); + ring_index); goto dma_error; } - vring->ctx[i].nr_frags = nr_frags; + ring->ctx[i].nr_frags = nr_frags; wil_tx_desc_set_nr_frags(d, nr_frags + 1); /* middle segments */ @@ -1750,20 +1750,21 @@ static int __wil_tx_vring(struct wil6210_priv *wil, struct wil6210_vif *vif, int len = skb_frag_size(frag); *_d = *d; - wil_dbg_txrx(wil, "Tx[%2d] desc[%4d]\n", vring_index, i); + wil_dbg_txrx(wil, "Tx[%2d] desc[%4d]\n", ring_index, i); wil_hex_dump_txrx("TxD ", DUMP_PREFIX_NONE, 32, 4, (const void *)d, sizeof(*d), false); - i = (swhead + f + 1) % vring->size; - _d = &vring->va[i].tx.legacy; + i = (swhead + f + 1) % ring->size; + _d = &ring->va[i].tx.legacy; pa = skb_frag_dma_map(dev, frag, 0, skb_frag_size(frag), DMA_TO_DEVICE); if (unlikely(dma_mapping_error(dev, pa))) { wil_err(wil, "Tx[%2d] failed to map fragment\n", - vring_index); + ring_index); goto dma_error; } - vring->ctx[i].mapped_as = wil_mapped_as_page; - wil_tx_desc_map(d, pa, len, vring_index); + ring->ctx[i].mapped_as = wil_mapped_as_page; + wil->txrx_ops.tx_desc_map((union wil_tx_desc *)d, + pa, len, ring_index); /* no need to check return code - * if it succeeded for 1-st descriptor, * it will succeed here too @@ -1775,7 +1776,7 @@ static int __wil_tx_vring(struct wil6210_priv *wil, struct wil6210_vif *vif, d->dma.d0 |= BIT(DMA_CFG_DESC_TX_0_CMD_MARK_WB_POS); d->dma.d0 |= BIT(DMA_CFG_DESC_TX_0_CMD_DMA_IT_POS); *_d = *d; - wil_dbg_txrx(wil, "Tx[%2d] desc[%4d]\n", vring_index, i); + wil_dbg_txrx(wil, "Tx[%2d] desc[%4d]\n", ring_index, i); wil_hex_dump_txrx("TxD ", DUMP_PREFIX_NONE, 32, 4, (const void *)d, sizeof(*d), false); @@ -1783,15 +1784,15 @@ static int __wil_tx_vring(struct wil6210_priv *wil, struct wil6210_vif *vif, * to prevent skb release before accounting * in case of immediate "tx done" */ - vring->ctx[i].skb = skb_get(skb); + ring->ctx[i].skb = skb_get(skb); /* performance monitoring */ - used = wil_ring_used_tx(vring); + used = wil_ring_used_tx(ring); if (wil_val_in_range(wil->ring_idle_trsh, used, used + nr_frags + 1)) { txdata->idle += get_cycles() - txdata->last_idle; wil_dbg_txrx(wil, "Ring[%2d] not idle %d -> %d\n", - vring_index, used, used + nr_frags + 1); + ring_index, used, used + nr_frags + 1); } /* Make sure to advance the head only after descriptor update is done. @@ -1802,17 +1803,17 @@ static int __wil_tx_vring(struct wil6210_priv *wil, struct wil6210_vif *vif, wmb(); /* advance swhead */ - wil_ring_advance_head(vring, nr_frags + 1); - wil_dbg_txrx(wil, "Tx[%2d] swhead %d -> %d\n", vring_index, swhead, - vring->swhead); - trace_wil6210_tx(vring_index, swhead, skb->len, nr_frags); + wil_ring_advance_head(ring, nr_frags + 1); + wil_dbg_txrx(wil, "Tx[%2d] swhead %d -> %d\n", ring_index, swhead, + ring->swhead); + trace_wil6210_tx(ring_index, swhead, skb->len, nr_frags); /* make sure all writes to descriptors (shared memory) are done before * committing them to HW */ wmb(); - wil_w(wil, vring->hwtail, vring->swhead); + wil_w(wil, ring->hwtail, ring->swhead); return 0; dma_error: @@ -1821,12 +1822,14 @@ static int __wil_tx_vring(struct wil6210_priv *wil, struct wil6210_vif *vif, for (f = 0; f < nr_frags; f++) { struct wil_ctx *ctx; - i = (swhead + f) % vring->size; - ctx = &vring->ctx[i]; - _d = &vring->va[i].tx.legacy; + i = (swhead + f) % ring->size; + ctx = &ring->ctx[i]; + _d = &ring->va[i].tx.legacy; *d = *_d; _d->dma.status = TX_DMA_STATUS_DU; - wil_txdesc_unmap(dev, d, ctx); + wil->txrx_ops.tx_desc_unmap(dev, + (union wil_tx_desc *)d, + ctx); memset(ctx, 0, sizeof(*ctx)); } @@ -1834,10 +1837,10 @@ static int __wil_tx_vring(struct wil6210_priv *wil, struct wil6210_vif *vif, return -EINVAL; } -static int wil_tx_vring(struct wil6210_priv *wil, struct wil6210_vif *vif, - struct wil_ring *vring, struct sk_buff *skb) +static int wil_tx_ring(struct wil6210_priv *wil, struct wil6210_vif *vif, + struct wil_ring *ring, struct sk_buff *skb) { - int ring_index = vring - wil->ring_tx; + int ring_index = ring - wil->ring_tx; struct wil_ring_tx_data *txdata = &wil->ring_tx_data[ring_index]; int rc; @@ -1852,8 +1855,8 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct wil6210_vif *vif, return -EINVAL; } - rc = (skb_is_gso(skb) ? __wil_tx_vring_tso : __wil_tx_vring) - (wil, vif, vring, skb); + rc = (skb_is_gso(skb) ? wil->txrx_ops.tx_ring_tso : __wil_tx_ring) + (wil, vif, ring, skb); spin_unlock(&txdata->lock); @@ -1960,7 +1963,7 @@ netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev) struct wil6210_priv *wil = vif_to_wil(vif); struct ethhdr *eth = (void *)skb->data; bool bcast = is_multicast_ether_addr(eth->h_dest); - struct wil_ring *vring; + struct wil_ring *ring; static bool pr_once_fw; int rc; @@ -1986,36 +1989,36 @@ netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev) /* find vring */ if (vif->wdev.iftype == NL80211_IFTYPE_STATION && !vif->pbss) { /* in STA mode (ESS), all to same VRING (to AP) */ - vring = wil_find_tx_ring_sta(wil, vif, skb); + ring = wil_find_tx_ring_sta(wil, vif, skb); } else if (bcast) { if (vif->pbss) /* in pbss, no bcast VRING - duplicate skb in * all stations VRINGs */ - vring = wil_find_tx_bcast_2(wil, vif, skb); + ring = wil_find_tx_bcast_2(wil, vif, skb); else if (vif->wdev.iftype == NL80211_IFTYPE_AP) /* AP has a dedicated bcast VRING */ - vring = wil_find_tx_bcast_1(wil, vif, skb); + ring = wil_find_tx_bcast_1(wil, vif, skb); else /* unexpected combination, fallback to duplicating * the skb in all stations VRINGs */ - vring = wil_find_tx_bcast_2(wil, vif, skb); + ring = wil_find_tx_bcast_2(wil, vif, skb); } else { /* unicast, find specific VRING by dest. address */ - vring = wil_find_tx_ucast(wil, vif, skb); + ring = wil_find_tx_ucast(wil, vif, skb); } - if (unlikely(!vring)) { + if (unlikely(!ring)) { wil_dbg_txrx(wil, "No Tx RING found for %pM\n", eth->h_dest); goto drop; } /* set up vring entry */ - rc = wil_tx_vring(wil, vif, vring, skb); + rc = wil_tx_ring(wil, vif, ring, skb); switch (rc) { case 0: /* shall we stop net queues? */ - wil_update_net_queues_bh(wil, vif, vring, true); + wil_update_net_queues_bh(wil, vif, ring, true); /* statistics will be updated on the tx_complete */ dev_kfree_skb_any(skb); return NETDEV_TX_OK; @@ -2031,22 +2034,6 @@ netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev) return NET_XMIT_DROP; } -static inline bool wil_need_txstat(struct sk_buff *skb) -{ - struct ethhdr *eth = (void *)skb->data; - - return is_unicast_ether_addr(eth->h_dest) && skb->sk && - (skb_shinfo(skb)->tx_flags & SKBTX_WIFI_STATUS); -} - -static inline void wil_consume_skb(struct sk_buff *skb, bool acked) -{ - if (unlikely(wil_need_txstat(skb))) - skb_complete_wifi_ack(skb, acked); - else - acked ? dev_consume_skb_any(skb) : dev_kfree_skb_any(skb); -} - /** * Clean up transmitted skb's from the Tx VRING * @@ -2122,7 +2109,9 @@ int wil_tx_complete(struct wil6210_vif *vif, int ringid) wil_hex_dump_txrx("TxCD ", DUMP_PREFIX_NONE, 32, 4, (const void *)d, sizeof(*d), false); - wil_txdesc_unmap(dev, d, ctx); + wil->txrx_ops.tx_desc_unmap(dev, + (union wil_tx_desc *)d, + ctx); if (skb) { if (likely(d->dma.error == 0)) { @@ -2184,6 +2173,9 @@ void wil_init_txrx_ops_legacy_dma(struct wil6210_priv *wil) wil->txrx_ops.configure_interrupt_moderation = wil_configure_interrupt_moderation; /* TX ops */ + wil->txrx_ops.tx_desc_map = wil_tx_desc_map; + wil->txrx_ops.tx_desc_unmap = wil_txdesc_unmap; + wil->txrx_ops.tx_ring_tso = __wil_tx_vring_tso; wil->txrx_ops.ring_init_tx = wil_vring_init_tx; wil->txrx_ops.ring_fini_tx = wil_vring_free; wil->txrx_ops.ring_init_bcast = wil_vring_init_bcast; diff --git a/drivers/net/wireless/ath/wil6210/txrx.h b/drivers/net/wireless/ath/wil6210/txrx.h index 4e3781d9e7ec..62806c5bb930 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.h +++ b/drivers/net/wireless/ath/wil6210/txrx.h @@ -555,6 +555,22 @@ static inline int wil_ring_is_full(struct wil_ring *ring) return wil_ring_next_tail(ring) == ring->swhead; } +static inline bool wil_need_txstat(struct sk_buff *skb) +{ + struct ethhdr *eth = (void *)skb->data; + + return is_unicast_ether_addr(eth->h_dest) && skb->sk && + (skb_shinfo(skb)->tx_flags & SKBTX_WIFI_STATUS); +} + +static inline void wil_consume_skb(struct sk_buff *skb, bool acked) +{ + if (unlikely(wil_need_txstat(skb))) + skb_complete_wifi_ack(skb, acked); + else + acked ? dev_consume_skb_any(skb) : dev_kfree_skb_any(skb); +} + /* Used space in Tx ring */ static inline int wil_ring_used_tx(struct wil_ring *ring) { @@ -576,6 +592,12 @@ static inline int wil_get_min_tx_ring_id(struct wil6210_priv *wil) return wil->use_enhanced_dma_hw ? 1 : 0; } +/* wil_val_in_range - check if value in [min,max) */ +static inline bool wil_val_in_range(int val, int min, int max) +{ + return val >= min && val < max; +} + void wil_netif_rx_any(struct sk_buff *skb, struct net_device *ndev); void wil_rx_reorder(struct wil6210_priv *wil, struct sk_buff *skb); void wil_rx_bar(struct wil6210_priv *wil, struct wil6210_vif *vif, diff --git a/drivers/net/wireless/ath/wil6210/txrx_edma.c b/drivers/net/wireless/ath/wil6210/txrx_edma.c index b78edf5575b6..772f2cf6755f 100644 --- a/drivers/net/wireless/ath/wil6210/txrx_edma.c +++ b/drivers/net/wireless/ath/wil6210/txrx_edma.c @@ -24,6 +24,7 @@ #include "wil6210.h" #include "txrx_edma.h" #include "txrx.h" +#include "trace.h" /* limit status ring size in range [ring size..max ring size] */ #define WIL_SRING_SIZE_ORDER_MIN (WIL_RING_SIZE_ORDER_MIN) @@ -69,9 +70,10 @@ module_param_cb(tx_status_ring_order, &sring_order_ops, &tx_status_ring_order, MODULE_PARM_DESC(tx_status_ring_order, " Tx status ring order; size = 1 << order. Default: 12"); static void wil_tx_desc_unmap_edma(struct device *dev, - struct wil_tx_enhanced_desc *d, + union wil_tx_desc *desc, struct wil_ctx *ctx) { + struct wil_tx_enhanced_desc *d = (struct wil_tx_enhanced_desc *)desc; dma_addr_t pa = wil_tx_desc_get_addr_edma(&d->dma); u16 dmalen = le16_to_cpu(d->dma.length); @@ -241,6 +243,13 @@ static int wil_ring_alloc_skb_edma(struct wil6210_priv *wil, return 0; } +static inline void wil_sring_advance_swhead(struct wil_status_ring *sring) +{ + sring->swhead = (sring->swhead + 1) % sring->size; + if (sring->swhead == 0) + sring->desc_rdy_pol = 1 - sring->desc_rdy_pol; +} + static int wil_rx_refill_edma(struct wil6210_priv *wil) { struct wil_ring *ring = &wil->ring_rx; @@ -482,7 +491,7 @@ static void wil_ring_free_edma(struct wil6210_priv *wil, struct wil_ring *ring) continue; } *d = *_d; - wil_tx_desc_unmap_edma(dev, d, ctx); + wil_tx_desc_unmap_edma(dev, (union wil_tx_desc *)d, ctx); if (ctx->skb) dev_kfree_skb_any(ctx->skb); ring->swtail = wil_ring_next_tail(ring); @@ -647,6 +656,415 @@ static int wil_ring_init_tx_edma(struct wil6210_vif *vif, int ring_id, return rc; } +static int wil_tx_desc_map_edma(union wil_tx_desc *desc, + dma_addr_t pa, + u32 len, + int ring_index) +{ + struct wil_tx_enhanced_desc *d = + (struct wil_tx_enhanced_desc *)&desc->enhanced; + + memset(d, 0, sizeof(struct wil_tx_enhanced_desc)); + + wil_desc_set_addr_edma(&d->dma.addr, &d->dma.addr_high_high, pa); + + /* 0..6: mac_length; 7:ip_version 0-IP6 1-IP4*/ + d->dma.length = cpu_to_le16((u16)len); + d->mac.d[0] = (ring_index << WIL_EDMA_DESC_TX_MAC_CFG_0_QID_POS); + /* translation type: 0 - bypass; 1 - 802.3; 2 - native wifi */ + d->mac.d[2] = BIT(MAC_CFG_DESC_TX_2_SNAP_HDR_INSERTION_EN_POS) | + (1 << MAC_CFG_DESC_TX_2_L2_TRANSLATION_TYPE_POS); + + return 0; +} + +static inline void +wil_get_next_tx_status_msg(struct wil_status_ring *sring, + struct wil_ring_tx_status *msg) +{ + struct wil_ring_tx_status *_msg = (struct wil_ring_tx_status *) + (sring->va + (sring->elem_size * sring->swhead)); + + *msg = *_msg; +} + +/** + * Clean up transmitted skb's from the Tx descriptor RING. + * Return number of descriptors cleared. + */ +int wil_tx_sring_handler(struct wil6210_priv *wil, + struct wil_status_ring *sring) +{ + struct net_device *ndev; + struct device *dev = wil_to_dev(wil); + struct wil_ring *ring = NULL; + struct wil_ring_tx_data *txdata; + /* Total number of completed descriptors in all descriptor rings */ + int desc_cnt = 0; + int cid; + struct wil_net_stats *stats = NULL; + struct wil_tx_enhanced_desc *_d; + unsigned int ring_id; + unsigned int num_descs; + int i; + u8 dr_bit; /* Descriptor Ready bit */ + struct wil_ring_tx_status msg; + struct wil6210_vif *vif; + int used_before_complete; + int used_new; + + wil_get_next_tx_status_msg(sring, &msg); + dr_bit = msg.desc_ready >> TX_STATUS_DESC_READY_POS; + + /* Process completion messages while DR bit has the expected polarity */ + while (dr_bit == sring->desc_rdy_pol) { + num_descs = msg.num_descriptors; + if (!num_descs) { + wil_err(wil, "invalid num_descs 0\n"); + goto again; + } + + /* Find the corresponding descriptor ring */ + ring_id = msg.ring_id; + + if (unlikely(ring_id >= WIL6210_MAX_TX_RINGS)) { + wil_err(wil, "invalid ring id %d\n", ring_id); + goto again; + } + ring = &wil->ring_tx[ring_id]; + if (unlikely(!ring->va)) { + wil_err(wil, "Tx irq[%d]: ring not initialized\n", + ring_id); + goto again; + } + txdata = &wil->ring_tx_data[ring_id]; + if (unlikely(!txdata->enabled)) { + wil_info(wil, "Tx irq[%d]: ring disabled\n", ring_id); + goto again; + } + vif = wil->vifs[txdata->mid]; + if (unlikely(!vif)) { + wil_dbg_txrx(wil, "invalid MID %d for ring %d\n", + txdata->mid, ring_id); + goto again; + } + + ndev = vif_to_ndev(vif); + + cid = wil->ring2cid_tid[ring_id][0]; + if (cid < WIL6210_MAX_CID) + stats = &wil->sta[cid].stats; + + wil_dbg_txrx(wil, + "tx_status: completed desc_ring (%d), num_descs (%d)\n", + ring_id, num_descs); + + used_before_complete = wil_ring_used_tx(ring); + + for (i = 0 ; i < num_descs; ++i) { + struct wil_ctx *ctx = &ring->ctx[ring->swtail]; + struct wil_tx_enhanced_desc dd, *d = ⅆ + u16 dmalen; + struct sk_buff *skb = ctx->skb; + + _d = (struct wil_tx_enhanced_desc *) + &ring->va[ring->swtail].tx.enhanced; + *d = *_d; + + dmalen = le16_to_cpu(d->dma.length); + trace_wil6210_tx_status(&msg, ring->swtail, dmalen); + wil_dbg_txrx(wil, + "TxC[%2d][%3d] : %d bytes, status 0x%02x\n", + ring_id, ring->swtail, dmalen, + msg.status); + wil_hex_dump_txrx("TxS ", DUMP_PREFIX_NONE, 32, 4, + (const void *)&msg, sizeof(msg), + false); + + wil_tx_desc_unmap_edma(dev, + (union wil_tx_desc *)d, + ctx); + + if (skb) { + if (likely(msg.status == 0)) { + ndev->stats.tx_packets++; + ndev->stats.tx_bytes += skb->len; + if (stats) { + stats->tx_packets++; + stats->tx_bytes += skb->len; + } + } else { + ndev->stats.tx_errors++; + if (stats) + stats->tx_errors++; + } + wil_consume_skb(skb, msg.status == 0); + } + memset(ctx, 0, sizeof(*ctx)); + /* Make sure the ctx is zeroed before updating the tail + * to prevent a case where wil_tx_ring will see + * this descriptor as used and handle it before ctx zero + * is completed. + */ + wmb(); + + ring->swtail = wil_ring_next_tail(ring); + + desc_cnt++; + } + + /* performance monitoring */ + used_new = wil_ring_used_tx(ring); + if (wil_val_in_range(wil->ring_idle_trsh, + used_new, used_before_complete)) { + wil_dbg_txrx(wil, "Ring[%2d] idle %d -> %d\n", + ring_id, used_before_complete, used_new); + txdata->last_idle = get_cycles(); + } + +again: + wil_sring_advance_swhead(sring); + + wil_get_next_tx_status_msg(sring, &msg); + dr_bit = msg.desc_ready >> TX_STATUS_DESC_READY_POS; + } + + /* shall we wake net queues? */ + if (desc_cnt) + wil_update_net_queues(wil, vif, NULL, false); + + /* Update the HW tail ptr (RD ptr) */ + wil_w(wil, sring->hwtail, (sring->swhead - 1) % sring->size); + + return desc_cnt; +} + +/** + * Sets the descriptor @d up for csum and/or TSO offloading. The corresponding + * @skb is used to obtain the protocol and headers length. + * @tso_desc_type is a descriptor type for TSO: 0 - a header, 1 - first data, + * 2 - middle, 3 - last descriptor. + */ +static void wil_tx_desc_offload_setup_tso_edma(struct wil_tx_enhanced_desc *d, + int tso_desc_type, bool is_ipv4, + int tcp_hdr_len, + int skb_net_hdr_len, + int mss) +{ + /* Number of descriptors */ + d->mac.d[2] |= 1; + /* Maximum Segment Size */ + d->mac.tso_mss |= cpu_to_le16(mss >> 2); + /* L4 header len: TCP header length */ + d->dma.l4_hdr_len |= tcp_hdr_len & DMA_CFG_DESC_TX_0_L4_LENGTH_MSK; + /* EOP, TSO desc type, Segmentation enable, + * Insert IPv4 and TCP / UDP Checksum + */ + d->dma.cmd |= BIT(WIL_EDMA_DESC_TX_CFG_EOP_POS) | + tso_desc_type << WIL_EDMA_DESC_TX_CFG_TSO_DESC_TYPE_POS | + BIT(WIL_EDMA_DESC_TX_CFG_SEG_EN_POS) | + BIT(WIL_EDMA_DESC_TX_CFG_INSERT_IP_CHKSUM_POS) | + BIT(WIL_EDMA_DESC_TX_CFG_INSERT_TCP_CHKSUM_POS); + /* Calculate pseudo-header */ + d->dma.w1 |= BIT(WIL_EDMA_DESC_TX_CFG_PSEUDO_HEADER_CALC_EN_POS) | + BIT(WIL_EDMA_DESC_TX_CFG_L4_TYPE_POS); + /* IP Header Length */ + d->dma.ip_length |= skb_net_hdr_len; + /* MAC header length and IP address family*/ + d->dma.b11 |= ETH_HLEN | + is_ipv4 << DMA_CFG_DESC_TX_OFFLOAD_CFG_L3T_IPV4_POS; +} + +static int wil_tx_tso_gen_desc(struct wil6210_priv *wil, void *buff_addr, + int len, uint i, int tso_desc_type, + skb_frag_t *frag, struct wil_ring *ring, + struct sk_buff *skb, bool is_ipv4, + int tcp_hdr_len, int skb_net_hdr_len, + int mss, int *descs_used) +{ + struct device *dev = wil_to_dev(wil); + struct wil_tx_enhanced_desc *_desc = (struct wil_tx_enhanced_desc *) + &ring->va[i].tx.enhanced; + struct wil_tx_enhanced_desc desc_mem, *d = &desc_mem; + int ring_index = ring - wil->ring_tx; + dma_addr_t pa; + + if (len == 0) + return 0; + + if (!frag) { + pa = dma_map_single(dev, buff_addr, len, DMA_TO_DEVICE); + ring->ctx[i].mapped_as = wil_mapped_as_single; + } else { + pa = skb_frag_dma_map(dev, frag, 0, len, DMA_TO_DEVICE); + ring->ctx[i].mapped_as = wil_mapped_as_page; + } + if (unlikely(dma_mapping_error(dev, pa))) { + wil_err(wil, "TSO: Skb DMA map error\n"); + return -EINVAL; + } + + wil->txrx_ops.tx_desc_map((union wil_tx_desc *)d, pa, + len, ring_index); + wil_tx_desc_offload_setup_tso_edma(d, tso_desc_type, is_ipv4, + tcp_hdr_len, + skb_net_hdr_len, mss); + + /* hold reference to skb + * to prevent skb release before accounting + * in case of immediate "tx done" + */ + if (tso_desc_type == wil_tso_type_lst) + ring->ctx[i].skb = skb_get(skb); + + wil_hex_dump_txrx("TxD ", DUMP_PREFIX_NONE, 32, 4, + (const void *)d, sizeof(*d), false); + + *_desc = *d; + (*descs_used)++; + + return 0; +} + +static int __wil_tx_ring_tso_edma(struct wil6210_priv *wil, + struct wil6210_vif *vif, + struct wil_ring *ring, + struct sk_buff *skb) +{ + int ring_index = ring - wil->ring_tx; + struct wil_ring_tx_data *txdata = &wil->ring_tx_data[ring_index]; + int nr_frags = skb_shinfo(skb)->nr_frags; + int min_desc_required = nr_frags + 2; /* Headers, Head, Fragments */ + int used, avail = wil_ring_avail_tx(ring); + int f, hdrlen, headlen; + int gso_type; + bool is_ipv4; + u32 swhead = ring->swhead; + int descs_used = 0; /* total number of used descriptors */ + int rc = -EINVAL; + int tcp_hdr_len; + int skb_net_hdr_len; + int mss = skb_shinfo(skb)->gso_size; + + wil_dbg_txrx(wil, "tx_ring_tso: %d bytes to ring %d\n", skb->len, + ring_index); + + if (unlikely(!txdata->enabled)) + return -EINVAL; + + if (unlikely(avail < min_desc_required)) { + wil_err_ratelimited(wil, + "TSO: Tx ring[%2d] full. No space for %d fragments\n", + ring_index, min_desc_required); + return -ENOMEM; + } + + gso_type = skb_shinfo(skb)->gso_type & (SKB_GSO_TCPV6 | SKB_GSO_TCPV4); + switch (gso_type) { + case SKB_GSO_TCPV4: + is_ipv4 = true; + break; + case SKB_GSO_TCPV6: + is_ipv4 = false; + break; + default: + return -EINVAL; + } + + if (skb->ip_summed != CHECKSUM_PARTIAL) + return -EINVAL; + + /* tcp header length and skb network header length are fixed for all + * packet's descriptors - read them once here + */ + tcp_hdr_len = tcp_hdrlen(skb); + skb_net_hdr_len = skb_network_header_len(skb); + + /* First descriptor must contain the header only + * Header Length = MAC header len + IP header len + TCP header len + */ + hdrlen = ETH_HLEN + tcp_hdr_len + skb_net_hdr_len; + wil_dbg_txrx(wil, "TSO: process header descriptor, hdrlen %u\n", + hdrlen); + rc = wil_tx_tso_gen_desc(wil, skb->data, hdrlen, swhead, + wil_tso_type_hdr, NULL, ring, skb, + is_ipv4, tcp_hdr_len, skb_net_hdr_len, + mss, &descs_used); + if (rc) + return -EINVAL; + + /* Second descriptor contains the head */ + headlen = skb_headlen(skb) - hdrlen; + wil_dbg_txrx(wil, "TSO: process skb head, headlen %u\n", headlen); + rc = wil_tx_tso_gen_desc(wil, skb->data + hdrlen, headlen, + (swhead + descs_used) % ring->size, + (nr_frags != 0) ? wil_tso_type_first : + wil_tso_type_lst, NULL, ring, skb, + is_ipv4, tcp_hdr_len, skb_net_hdr_len, + mss, &descs_used); + if (rc) + goto mem_error; + + /* Rest of the descriptors are from the SKB fragments */ + for (f = 0; f < nr_frags; f++) { + skb_frag_t *frag = &skb_shinfo(skb)->frags[f]; + int len = frag->size; + + wil_dbg_txrx(wil, "TSO: frag[%d]: len %u, descs_used %d\n", f, + len, descs_used); + + rc = wil_tx_tso_gen_desc(wil, NULL, len, + (swhead + descs_used) % ring->size, + (f != nr_frags - 1) ? + wil_tso_type_mid : wil_tso_type_lst, + frag, ring, skb, is_ipv4, + tcp_hdr_len, skb_net_hdr_len, + mss, &descs_used); + if (rc) + goto mem_error; + } + + /* performance monitoring */ + used = wil_ring_used_tx(ring); + if (wil_val_in_range(wil->ring_idle_trsh, + used, used + descs_used)) { + txdata->idle += get_cycles() - txdata->last_idle; + wil_dbg_txrx(wil, "Ring[%2d] not idle %d -> %d\n", + ring_index, used, used + descs_used); + } + + /* advance swhead */ + wil_ring_advance_head(ring, descs_used); + wil_dbg_txrx(wil, "TSO: Tx swhead %d -> %d\n", swhead, ring->swhead); + + /* make sure all writes to descriptors (shared memory) are done before + * committing them to HW + */ + wmb(); + + wil_w(wil, ring->hwtail, ring->swhead); + + return 0; + +mem_error: + while (descs_used > 0) { + struct device *dev = wil_to_dev(wil); + struct wil_ctx *ctx; + int i = (swhead + descs_used - 1) % ring->size; + struct wil_tx_enhanced_desc dd, *d = ⅆ + struct wil_tx_enhanced_desc *_desc = + (struct wil_tx_enhanced_desc *) + &ring->va[i].tx.enhanced; + + *d = *_desc; + ctx = &ring->ctx[i]; + wil_tx_desc_unmap_edma(dev, (union wil_tx_desc *)d, ctx); + memset(ctx, 0, sizeof(*ctx)); + descs_used--; + } + return rc; +} + static int wil_ring_init_bcast_edma(struct wil6210_vif *vif, int ring_id, int size) { @@ -734,6 +1152,9 @@ void wil_init_txrx_ops_edma(struct wil6210_priv *wil) wil->txrx_ops.ring_init_bcast = wil_ring_init_bcast_edma; wil->txrx_ops.tx_init = wil_tx_init_edma; wil->txrx_ops.tx_fini = wil_tx_fini_edma; + wil->txrx_ops.tx_desc_map = wil_tx_desc_map_edma; + wil->txrx_ops.tx_desc_unmap = wil_tx_desc_unmap_edma; + wil->txrx_ops.tx_ring_tso = __wil_tx_ring_tso_edma; /* RX ops */ wil->txrx_ops.rx_init = wil_rx_init_edma; wil->txrx_ops.rx_fini = wil_rx_fini_edma; diff --git a/drivers/net/wireless/ath/wil6210/txrx_edma.h b/drivers/net/wireless/ath/wil6210/txrx_edma.h index 645ba1797707..7cdb3e407df3 100644 --- a/drivers/net/wireless/ath/wil6210/txrx_edma.h +++ b/drivers/net/wireless/ath/wil6210/txrx_edma.h @@ -30,6 +30,30 @@ #define WIL_EDMA_IDLE_TIME_LIMIT_USEC (50) #define WIL_EDMA_TIME_UNIT_CLK_CYCLES (330) /* fits 1 usec */ +#define WIL_EDMA_DESC_TX_MAC_CFG_0_QID_POS 16 +#define WIL_EDMA_DESC_TX_MAC_CFG_0_QID_LEN 6 + +#define WIL_EDMA_DESC_TX_CFG_EOP_POS 0 +#define WIL_EDMA_DESC_TX_CFG_EOP_LEN 1 + +#define WIL_EDMA_DESC_TX_CFG_TSO_DESC_TYPE_POS 3 +#define WIL_EDMA_DESC_TX_CFG_TSO_DESC_TYPE_LEN 2 + +#define WIL_EDMA_DESC_TX_CFG_SEG_EN_POS 5 +#define WIL_EDMA_DESC_TX_CFG_SEG_EN_LEN 1 + +#define WIL_EDMA_DESC_TX_CFG_INSERT_IP_CHKSUM_POS 6 +#define WIL_EDMA_DESC_TX_CFG_INSERT_IP_CHKSUM_LEN 1 + +#define WIL_EDMA_DESC_TX_CFG_INSERT_TCP_CHKSUM_POS 7 +#define WIL_EDMA_DESC_TX_CFG_INSERT_TCP_CHKSUM_LEN 1 + +#define WIL_EDMA_DESC_TX_CFG_L4_TYPE_POS 15 +#define WIL_EDMA_DESC_TX_CFG_L4_TYPE_LEN 1 + +#define WIL_EDMA_DESC_TX_CFG_PSEUDO_HEADER_CALC_EN_POS 5 +#define WIL_EDMA_DESC_TX_CFG_PSEUDO_HEADER_CALC_EN_LEN 1 + /* Enhanced Rx descriptor - MAC part * [dword 0] : Reserved * [dword 1] : Reserved @@ -295,7 +319,12 @@ struct wil_rx_status_extension { struct wil_rx_status_extended { struct wil_rx_status_compressed comp; struct wil_rx_status_extension ext; -}; +} __packed; + +static inline u8 wil_tx_status_get_mcs(struct wil_ring_tx_status *msg) +{ + return WIL_GET_BITS(msg->d2, 0, 4); +} static inline u32 wil_ring_next_head(struct wil_ring *ring) { @@ -328,6 +357,8 @@ dma_addr_t wil_rx_desc_get_addr_edma(struct wil_ring_rx_enhanced_dma *dma) } void wil_configure_interrupt_moderation_edma(struct wil6210_priv *wil); +int wil_tx_sring_handler(struct wil6210_priv *wil, + struct wil_status_ring *sring); void wil_init_txrx_ops_edma(struct wil6210_priv *wil); #endif /* WIL6210_TXRX_EDMA_H */ diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index ab454099aafd..0103bc949e40 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -24,6 +24,7 @@ #include #include #include +#include #include "wmi.h" #include "wil_platform.h" #include "ftm.h" @@ -41,6 +42,7 @@ extern bool use_compressed_rx_status; struct wil6210_priv; struct wil6210_vif; +union wil_tx_desc; #define WIL_NAME "wil6210" @@ -322,6 +324,10 @@ struct RGF_ICR { #define RGF_INT_GEN_CTRL (0x8bc0ec) #define BIT_CONTROL_0 BIT(0) +/* eDMA status interrupts */ +#define RGF_INT_GEN_TX_ICR (0x8bc110) + #define BIT_TX_STATUS_IRQ BIT(WIL_TX_STATUS_IRQ_IDX) +#define RGF_INT_CTRL_TX_INT_MASK (0x8bc130) #define RGF_INT_GEN_IDLE_TIME_LIMIT (0x8bc134) #define USER_EXT_USER_PMU_3 (0x88d00c) @@ -541,6 +547,14 @@ struct wil_txrx_ops { int (*ring_init_bcast)(struct wil6210_vif *vif, int id, int size); int (*tx_init)(struct wil6210_priv *wil); void (*tx_fini)(struct wil6210_priv *wil); + int (*tx_desc_map)(union wil_tx_desc *desc, dma_addr_t pa, + u32 len, int ring_index); + void (*tx_desc_unmap)(struct device *dev, + union wil_tx_desc *desc, + struct wil_ctx *ctx); + int (*tx_ring_tso)(struct wil6210_priv *wil, struct wil6210_vif *vif, + struct wil_ring *ring, struct sk_buff *skb); + irqreturn_t (*irq_tx)(int irq, void *cookie); /* RX ops */ int (*rx_init)(struct wil6210_priv *wil, u16 ring_size); void (*rx_fini)(struct wil6210_priv *wil); @@ -1252,6 +1266,7 @@ void wil_update_net_queues_bh(struct wil6210_priv *wil, struct wil6210_vif *vif, netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev); int wil_tx_complete(struct wil6210_vif *vif, int ringid); void wil6210_unmask_irq_tx(struct wil6210_priv *wil); +void wil6210_unmask_irq_tx_edma(struct wil6210_priv *wil); /* RX API */ void wil_rx_handle(struct wil6210_priv *wil, int *quota); -- GitLab From 9a14845e813209090f631021b11a57c6555f3d3e Mon Sep 17 00:00:00 2001 From: Gidon Studinski Date: Wed, 11 Apr 2018 15:33:51 +0300 Subject: [PATCH 0133/1635] wil6210: add support for enhanced DMA RX data flows Enhanced DMA RX data path is handled using a single RX descriptor ring for all VIFs. Multiple RX status rings are supported, to allow RSS and multi MSI support. The driver gets the RX completions via the RX status rings. The RX status message includes the completed RX buffer ID, which points to the allocated SKB. The enhanced DMA RX data flow supports RX chaining, where multiple SKBs are merged into a single packet. Enhanced DMA HW supports RX HW reorder offload, enabled by default and can be disabled via module parameter. Change-Id: Idb645a79df61dc6419d8b6da65333e5f906cfb34 Signed-off-by: Gidon Studinski Signed-off-by: Maya Erez --- drivers/net/wireless/ath/wil6210/interrupt.c | 86 +++- drivers/net/wireless/ath/wil6210/netdev.c | 35 +- drivers/net/wireless/ath/wil6210/pm.c | 6 +- drivers/net/wireless/ath/wil6210/rx_reorder.c | 18 +- drivers/net/wireless/ath/wil6210/trace.h | 32 ++ drivers/net/wireless/ath/wil6210/txrx.c | 52 +- drivers/net/wireless/ath/wil6210/txrx.h | 7 + drivers/net/wireless/ath/wil6210/txrx_edma.c | 453 ++++++++++++++++++ drivers/net/wireless/ath/wil6210/txrx_edma.h | 188 ++++++++ drivers/net/wireless/ath/wil6210/wil6210.h | 23 +- drivers/net/wireless/ath/wil6210/wmi.c | 63 ++- 11 files changed, 923 insertions(+), 40 deletions(-) diff --git a/drivers/net/wireless/ath/wil6210/interrupt.c b/drivers/net/wireless/ath/wil6210/interrupt.c index 1603b9f7feb9..d7e112da6a8d 100644 --- a/drivers/net/wireless/ath/wil6210/interrupt.c +++ b/drivers/net/wireless/ath/wil6210/interrupt.c @@ -45,6 +45,7 @@ #define WIL6210_IMC_TX (BIT_DMA_EP_TX_ICR_TX_DONE | \ BIT_DMA_EP_TX_ICR_TX_DONE_N(0)) #define WIL6210_IMC_TX_EDMA BIT_TX_STATUS_IRQ +#define WIL6210_IMC_RX_EDMA BIT_RX_STATUS_IRQ #define WIL6210_IMC_MISC_NO_HALP (ISR_MISC_FW_READY | \ ISR_MISC_MBOX_EVT | \ ISR_MISC_FW_ERROR) @@ -100,6 +101,12 @@ static void wil6210_mask_irq_rx(struct wil6210_priv *wil) WIL6210_IRQ_DISABLE); } +static void wil6210_mask_irq_rx_edma(struct wil6210_priv *wil) +{ + wil_w(wil, RGF_INT_GEN_RX_ICR + offsetof(struct RGF_ICR, IMS), + WIL6210_IRQ_DISABLE); +} + static void wil6210_mask_irq_misc(struct wil6210_priv *wil, bool mask_halp) { wil_dbg_irq(wil, "mask_irq_misc: mask_halp(%s)\n", @@ -146,6 +153,12 @@ void wil6210_unmask_irq_rx(struct wil6210_priv *wil) unmask_rx_htrsh ? WIL6210_IMC_RX : WIL6210_IMC_RX_NO_RX_HTRSH); } +void wil6210_unmask_irq_rx_edma(struct wil6210_priv *wil) +{ + wil_w(wil, RGF_INT_GEN_RX_ICR + offsetof(struct RGF_ICR, IMC), + WIL6210_IMC_RX_EDMA); +} + static void wil6210_unmask_irq_misc(struct wil6210_priv *wil, bool unmask_halp) { wil_dbg_irq(wil, "unmask_irq_misc: unmask_halp(%s)\n", @@ -179,6 +192,7 @@ void wil_mask_irq(struct wil6210_priv *wil) wil6210_mask_irq_tx(wil); wil6210_mask_irq_tx_edma(wil); wil6210_mask_irq_rx(wil); + wil6210_mask_irq_rx_edma(wil); wil6210_mask_irq_misc(wil, true); wil6210_mask_irq_pseudo(wil); } @@ -195,10 +209,13 @@ void wil_unmask_irq(struct wil6210_priv *wil) WIL_ICR_ICC_MISC_VALUE); wil_w(wil, RGF_INT_GEN_TX_ICR + offsetof(struct RGF_ICR, ICC), WIL_ICR_ICC_VALUE); + wil_w(wil, RGF_INT_GEN_RX_ICR + offsetof(struct RGF_ICR, ICC), + WIL_ICR_ICC_VALUE); wil6210_unmask_irq_pseudo(wil); if (wil->use_enhanced_dma_hw) { wil6210_unmask_irq_tx_edma(wil); + wil6210_unmask_irq_rx_edma(wil); } else { wil6210_unmask_irq_tx(wil); wil6210_unmask_irq_rx(wil); @@ -335,6 +352,54 @@ static irqreturn_t wil6210_irq_rx(int irq, void *cookie) return IRQ_HANDLED; } +static irqreturn_t wil6210_irq_rx_edma(int irq, void *cookie) +{ + struct wil6210_priv *wil = cookie; + u32 isr = wil_ioread32_and_clear(wil->csr + + HOSTADDR(RGF_INT_GEN_RX_ICR) + + offsetof(struct RGF_ICR, ICR)); + bool need_unmask = true; + + trace_wil6210_irq_rx(isr); + wil_dbg_irq(wil, "ISR RX 0x%08x\n", isr); + + if (unlikely(!isr)) { + wil_err(wil, "spurious IRQ: RX\n"); + return IRQ_NONE; + } + + wil6210_mask_irq_rx_edma(wil); + + if (likely(isr & BIT_RX_STATUS_IRQ)) { + wil_dbg_irq(wil, "RX status ring\n"); + isr &= ~BIT_RX_STATUS_IRQ; + if (likely(test_bit(wil_status_fwready, wil->status))) { + if (likely(test_bit(wil_status_napi_en, wil->status))) { + wil_dbg_txrx(wil, "NAPI(Rx) schedule\n"); + need_unmask = false; + napi_schedule(&wil->napi_rx); + } else { + wil_err(wil, + "Got Rx interrupt while stopping interface\n"); + } + } else { + wil_err(wil, "Got Rx interrupt while in reset\n"); + } + } + + if (unlikely(isr)) + wil_err(wil, "un-handled RX ISR bits 0x%08x\n", isr); + + /* Rx IRQ will be enabled when NAPI processing finished */ + + atomic_inc(&wil->isr_count_rx); + + if (unlikely(need_unmask)) + wil6210_unmask_irq_rx_edma(wil); + + return IRQ_HANDLED; +} + static irqreturn_t wil6210_irq_tx_edma(int irq, void *cookie) { struct wil6210_priv *wil = cookie; @@ -594,12 +659,20 @@ static irqreturn_t wil6210_thread_irq(int irq, void *cookie) */ static int wil6210_debug_irq_mask(struct wil6210_priv *wil, u32 pseudo_cause) { - u32 icm_rx = 0, icr_rx = 0, imv_rx = 0; + u32 icm_rx, icr_rx, imv_rx; u32 icm_tx, icr_tx, imv_tx; u32 icm_misc, icr_misc, imv_misc; if (!test_bit(wil_status_irqen, wil->status)) { if (wil->use_enhanced_dma_hw) { + icm_rx = wil_ioread32_and_clear(wil->csr + + HOSTADDR(RGF_INT_GEN_RX_ICR) + + offsetof(struct RGF_ICR, ICM)); + icr_rx = wil_ioread32_and_clear(wil->csr + + HOSTADDR(RGF_INT_GEN_RX_ICR) + + offsetof(struct RGF_ICR, ICR)); + imv_rx = wil_r(wil, RGF_INT_GEN_RX_ICR + + offsetof(struct RGF_ICR, IMV)); icm_tx = wil_ioread32_and_clear(wil->csr + HOSTADDR(RGF_INT_GEN_TX_ICR) + offsetof(struct RGF_ICR, ICM)); @@ -691,7 +764,7 @@ static irqreturn_t wil6210_hardirq(int irq, void *cookie) * voting for wake thread - need at least 1 vote */ if ((pseudo_cause & BIT_DMA_PSEUDO_CAUSE_RX) && - (wil6210_irq_rx(irq, cookie) == IRQ_WAKE_THREAD)) + (wil->txrx_ops.irq_rx(irq, cookie) == IRQ_WAKE_THREAD)) rc = IRQ_WAKE_THREAD; if ((pseudo_cause & BIT_DMA_PSEUDO_CAUSE_TX) && @@ -723,6 +796,8 @@ void wil6210_clear_irq(struct wil6210_priv *wil) offsetof(struct RGF_ICR, ICR)); wil_clear32(wil->csr + HOSTADDR(RGF_DMA_EP_TX_ICR) + offsetof(struct RGF_ICR, ICR)); + wil_clear32(wil->csr + HOSTADDR(RGF_INT_GEN_RX_ICR) + + offsetof(struct RGF_ICR, ICR)); wil_clear32(wil->csr + HOSTADDR(RGF_INT_GEN_TX_ICR) + offsetof(struct RGF_ICR, ICR)); wil_clear32(wil->csr + HOSTADDR(RGF_DMA_EP_MISC_ICR) + @@ -753,10 +828,13 @@ int wil6210_init_irq(struct wil6210_priv *wil, int irq, bool use_msi) wil_dbg_misc(wil, "init_irq: %s\n", use_msi ? "MSI" : "INTx"); - if (wil->use_enhanced_dma_hw) + if (wil->use_enhanced_dma_hw) { wil->txrx_ops.irq_tx = wil6210_irq_tx_edma; - else + wil->txrx_ops.irq_rx = wil6210_irq_rx_edma; + } else { wil->txrx_ops.irq_tx = wil6210_irq_tx; + wil->txrx_ops.irq_rx = wil6210_irq_rx; + } rc = request_threaded_irq(irq, wil6210_hardirq, wil6210_thread_irq, use_msi ? 0 : IRQF_SHARED, diff --git a/drivers/net/wireless/ath/wil6210/netdev.c b/drivers/net/wireless/ath/wil6210/netdev.c index 8482a6b2288d..0e0b8064fe01 100644 --- a/drivers/net/wireless/ath/wil6210/netdev.c +++ b/drivers/net/wireless/ath/wil6210/netdev.c @@ -133,6 +133,27 @@ static int wil6210_netdev_poll_rx(struct napi_struct *napi, int budget) return done; } +static int wil6210_netdev_poll_rx_edma(struct napi_struct *napi, int budget) +{ + struct wil6210_priv *wil = container_of(napi, struct wil6210_priv, + napi_rx); + int quota = budget; + int done; + + wil_rx_handle_edma(wil, "a); + done = budget - quota; + + if (done < budget) { + napi_complete_done(napi, done); + wil6210_unmask_irq_rx_edma(wil); + wil_dbg_txrx(wil, "NAPI RX complete\n"); + } + + wil_dbg_txrx(wil, "NAPI RX poll(%d) done %d\n", budget, done); + + return done; +} + static int wil6210_netdev_poll_tx(struct napi_struct *napi, int budget) { struct wil6210_priv *wil = container_of(napi, struct wil6210_priv, @@ -459,17 +480,21 @@ int wil_if_add(struct wil6210_priv *wil) } init_dummy_netdev(&wil->napi_ndev); - netif_napi_add(&wil->napi_ndev, &wil->napi_rx, wil6210_netdev_poll_rx, - WIL6210_NAPI_BUDGET); - if (wil->use_enhanced_dma_hw) + if (wil->use_enhanced_dma_hw) { + netif_napi_add(&wil->napi_ndev, &wil->napi_rx, + wil6210_netdev_poll_rx_edma, + WIL6210_NAPI_BUDGET); netif_tx_napi_add(&wil->napi_ndev, &wil->napi_tx, wil6210_netdev_poll_tx_edma, WIL6210_NAPI_BUDGET); - else + } else { + netif_napi_add(&wil->napi_ndev, &wil->napi_rx, + wil6210_netdev_poll_rx, + WIL6210_NAPI_BUDGET); netif_tx_napi_add(&wil->napi_ndev, &wil->napi_tx, wil6210_netdev_poll_tx, WIL6210_NAPI_BUDGET); - + } wil_update_net_queues_bh(wil, vif, NULL, true); diff --git a/drivers/net/wireless/ath/wil6210/pm.c b/drivers/net/wireless/ath/wil6210/pm.c index 445f5331e51c..93fcc55bcd22 100644 --- a/drivers/net/wireless/ath/wil6210/pm.c +++ b/drivers/net/wireless/ath/wil6210/pm.c @@ -207,7 +207,7 @@ static int wil_suspend_keep_radio_on(struct wil6210_priv *wil) goto reject_suspend; } - if (!wil_is_rx_idle(wil)) { + if (!wil->txrx_ops.is_rx_idle(wil)) { wil_dbg_pm(wil, "Pending RX data, reject suspend\n"); wil->suspend_stats.rejected_by_host++; goto reject_suspend; @@ -231,9 +231,9 @@ static int wil_suspend_keep_radio_on(struct wil6210_priv *wil) start = jiffies; data_comp_to = jiffies + msecs_to_jiffies(WIL_DATA_COMPLETION_TO_MS); if (test_bit(wil_status_napi_en, wil->status)) { - while (!wil_is_rx_idle(wil)) { + while (!wil->txrx_ops.is_rx_idle(wil)) { if (time_after(jiffies, data_comp_to)) { - if (wil_is_rx_idle(wil)) + if (wil->txrx_ops.is_rx_idle(wil)) break; wil_err(wil, "TO waiting for idle RX, suspend failed\n"); diff --git a/drivers/net/wireless/ath/wil6210/rx_reorder.c b/drivers/net/wireless/ath/wil6210/rx_reorder.c index 3b393f344934..9321b5e91a9c 100644 --- a/drivers/net/wireless/ath/wil6210/rx_reorder.c +++ b/drivers/net/wireless/ath/wil6210/rx_reorder.c @@ -95,17 +95,16 @@ __acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock) { struct wil6210_vif *vif; struct net_device *ndev; - struct vring_rx_desc *d = wil_skb_rxdesc(skb); - int tid = wil_rxdesc_tid(d); - int cid = wil_rxdesc_cid(d); - int mid = wil_rxdesc_mid(d); - u16 seq = wil_rxdesc_seq(d); - int mcast = wil_rxdesc_mcast(d); - struct wil_sta_info *sta = &wil->sta[cid]; + int tid, cid, mid, mcast; + u16 seq; + struct wil_sta_info *sta; struct wil_tid_ampdu_rx *r; u16 hseq; int index; + wil->txrx_ops.get_reorder_params(skb, &tid, &cid, &mid, &seq, &mcast); + sta = &wil->sta[cid]; + wil_dbg_txrx(wil, "MID %d CID %d TID %d Seq 0x%03x mcast %01x\n", mid, cid, tid, seq, mcast); @@ -365,8 +364,9 @@ __acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock) } } - rc = wmi_addba_rx_resp(wil, mid, cid, tid, dialog_token, status, - agg_amsdu, agg_wsize, agg_timeout); + rc = wil->txrx_ops.wmi_addba_rx_resp(wil, mid, cid, tid, dialog_token, + status, agg_amsdu, agg_wsize, + agg_timeout); if (rc || (status != WLAN_STATUS_SUCCESS)) { wil_err(wil, "do not apply ba, rc(%d), status(%d)\n", rc, status); diff --git a/drivers/net/wireless/ath/wil6210/trace.h b/drivers/net/wireless/ath/wil6210/trace.h index 6aed2461b0d4..efd4c7205ef1 100644 --- a/drivers/net/wireless/ath/wil6210/trace.h +++ b/drivers/net/wireless/ath/wil6210/trace.h @@ -187,6 +187,38 @@ TRACE_EVENT(wil6210_rx, __entry->seq, __entry->type, __entry->subtype) ); +TRACE_EVENT(wil6210_rx_status, + TP_PROTO(u8 use_compressed, u16 buff_id, void *msg), + TP_ARGS(use_compressed, buff_id, msg), + TP_STRUCT__entry(__field(u8, use_compressed) + __field(u16, buff_id) + __field(unsigned int, len) + __field(u8, mid) + __field(u8, cid) + __field(u8, tid) + __field(u8, type) + __field(u8, subtype) + __field(u16, seq) + __field(u8, mcs) + ), + TP_fast_assign(__entry->use_compressed = use_compressed; + __entry->buff_id = buff_id; + __entry->len = wil_rx_status_get_length(msg); + __entry->mid = wil_rx_status_get_mid(msg); + __entry->cid = wil_rx_status_get_cid(msg); + __entry->tid = wil_rx_status_get_tid(msg); + __entry->type = wil_rx_status_get_frame_type(msg); + __entry->subtype = wil_rx_status_get_fc1(msg); + __entry->seq = wil_rx_status_get_seq(msg); + __entry->mcs = wil_rx_status_get_mcs(msg); + ), + TP_printk( + "compressed %d buff_id %d len %d mid %d cid %d tid %d mcs %d seq 0x%03x type 0x%1x subtype 0x%1x", + __entry->use_compressed, __entry->buff_id, __entry->len, + __entry->mid, __entry->cid, __entry->tid, __entry->mcs, + __entry->seq, __entry->type, __entry->subtype) +); + TRACE_EVENT(wil6210_tx, TP_PROTO(u8 vring, u16 index, unsigned int len, u8 frags), TP_ARGS(vring, index, len, frags), diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c index 9a84f5947d27..04c9a7261c36 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.c +++ b/drivers/net/wireless/ath/wil6210/txrx.c @@ -28,6 +28,7 @@ #include "wmi.h" #include "txrx.h" #include "trace.h" +#include "txrx_edma.h" static bool rtap_include_phy_info; module_param(rtap_include_phy_info, bool, 0444); @@ -407,14 +408,7 @@ static void wil_rx_add_radiotap_header(struct wil6210_priv *wil, } } -/* similar to ieee80211_ version, but FC contain only 1-st byte */ -static inline int wil_is_back_req(u8 fc) -{ - return (fc & (IEEE80211_FCTL_FTYPE | IEEE80211_FCTL_STYPE)) == - (IEEE80211_FTYPE_CTL | IEEE80211_STYPE_BACK_REQ); -} - -bool wil_is_rx_idle(struct wil6210_priv *wil) +static bool wil_is_rx_idle(struct wil6210_priv *wil) { struct vring_rx_desc *_d; struct wil_ring *ring = &wil->ring_rx; @@ -639,7 +633,7 @@ static int wil_rx_refill(struct wil6210_priv *wil, int count) * Cut'n'paste from original memcmp (see lib/string.c) * with minimal modifications */ -static int reverse_memcmp(const void *cs, const void *ct, size_t count) +int reverse_memcmp(const void *cs, const void *ct, size_t count) { const unsigned char *su1, *su2; int res = 0; @@ -684,6 +678,15 @@ static int wil_rx_crypto_check(struct wil6210_priv *wil, struct sk_buff *skb) return 0; } +static void wil_get_netif_rx_params(struct sk_buff *skb, int *cid, + int *security) +{ + struct vring_rx_desc *d = wil_skb_rxdesc(skb); + + *cid = wil_rxdesc_cid(d); /* always 0..7, no need to check */ + *security = wil_rxdesc_security(d); +} + /* * Pass Rx packet to the netif. Update statistics. * Called in softirq context (NAPI poll). @@ -695,15 +698,14 @@ void wil_netif_rx_any(struct sk_buff *skb, struct net_device *ndev) struct wil6210_priv *wil = ndev_to_wil(ndev); struct wireless_dev *wdev = vif_to_wdev(vif); unsigned int len = skb->len; - struct vring_rx_desc *d = wil_skb_rxdesc(skb); - int cid = wil_rxdesc_cid(d); /* always 0..7, no need to check */ - int security = wil_rxdesc_security(d); + int cid; + int security; struct ethhdr *eth = (void *)skb->data; /* here looking for DA, not A1, thus Rxdesc's 'mcast' indication * is not suitable, need to look at data */ int mcast = is_multicast_ether_addr(eth->h_dest); - struct wil_net_stats *stats = &wil->sta[cid].stats; + struct wil_net_stats *stats; struct sk_buff *xmit_skb = NULL; static const char * const gro_res_str[] = { [GRO_MERGED] = "GRO_MERGED", @@ -713,6 +715,10 @@ void wil_netif_rx_any(struct sk_buff *skb, struct net_device *ndev) [GRO_DROP] = "GRO_DROP", }; + wil->txrx_ops.get_netif_rx_params(skb, &cid, &security); + + stats = &wil->sta[cid].stats; + if (ndev->features & NETIF_F_RXHASH) /* fake L4 to ensure it won't be re-calculated later * set hash to any non-zero value to activate rps @@ -723,7 +729,7 @@ void wil_netif_rx_any(struct sk_buff *skb, struct net_device *ndev) skb_orphan(skb); - if (security && (wil_rx_crypto_check(wil, skb) != 0)) { + if (security && (wil->txrx_ops.rx_crypto_check(wil, skb) != 0)) { rc = GRO_DROP; dev_kfree_skb(skb); stats->rx_replay++; @@ -2168,6 +2174,18 @@ static inline int wil_tx_init(struct wil6210_priv *wil) static inline void wil_tx_fini(struct wil6210_priv *wil) {} +static void wil_get_reorder_params(struct sk_buff *skb, int *tid, int *cid, + int *mid, u16 *seq, int *mcast) +{ + struct vring_rx_desc *d = wil_skb_rxdesc(skb); + + *tid = wil_rxdesc_tid(d); + *cid = wil_rxdesc_cid(d); + *mid = wil_rxdesc_mid(d); + *seq = wil_rxdesc_seq(d); + *mcast = wil_rxdesc_mcast(d); +} + void wil_init_txrx_ops_legacy_dma(struct wil6210_priv *wil) { wil->txrx_ops.configure_interrupt_moderation = @@ -2183,5 +2201,11 @@ void wil_init_txrx_ops_legacy_dma(struct wil6210_priv *wil) wil->txrx_ops.tx_fini = wil_tx_fini; /* RX ops */ wil->txrx_ops.rx_init = wil_rx_init; + wil->txrx_ops.wmi_addba_rx_resp = wmi_addba_rx_resp; + wil->txrx_ops.get_reorder_params = wil_get_reorder_params; + wil->txrx_ops.get_netif_rx_params = + wil_get_netif_rx_params; + wil->txrx_ops.rx_crypto_check = wil_rx_crypto_check; + wil->txrx_ops.is_rx_idle = wil_is_rx_idle; wil->txrx_ops.rx_fini = wil_rx_fini; } diff --git a/drivers/net/wireless/ath/wil6210/txrx.h b/drivers/net/wireless/ath/wil6210/txrx.h index 62806c5bb930..f361423628f5 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.h +++ b/drivers/net/wireless/ath/wil6210/txrx.h @@ -592,6 +592,13 @@ static inline int wil_get_min_tx_ring_id(struct wil6210_priv *wil) return wil->use_enhanced_dma_hw ? 1 : 0; } +/* similar to ieee80211_ version, but FC contain only 1-st byte */ +static inline int wil_is_back_req(u8 fc) +{ + return (fc & (IEEE80211_FCTL_FTYPE | IEEE80211_FCTL_STYPE)) == + (IEEE80211_FTYPE_CTL | IEEE80211_STYPE_BACK_REQ); +} + /* wil_val_in_range - check if value in [min,max) */ static inline bool wil_val_in_range(int val, int min, int max) { diff --git a/drivers/net/wireless/ath/wil6210/txrx_edma.c b/drivers/net/wireless/ath/wil6210/txrx_edma.c index 772f2cf6755f..0600794c2208 100644 --- a/drivers/net/wireless/ath/wil6210/txrx_edma.c +++ b/drivers/net/wireless/ath/wil6210/txrx_edma.c @@ -37,6 +37,10 @@ bool use_compressed_rx_status = true; module_param(use_compressed_rx_status, bool, 0444); MODULE_PARM_DESC(use_compressed_rx_status, " Use compressed or extended Rx status message. Default: true"); +bool use_rx_hw_reordering = true; +module_param(use_rx_hw_reordering, bool, 0444); +MODULE_PARM_DESC(use_rx_hw_reordering, " RX Packet reordering in HW. Default: true"); + static int sring_order_set(const char *val, const struct kernel_param *kp) { int ret; @@ -243,6 +247,13 @@ static int wil_ring_alloc_skb_edma(struct wil6210_priv *wil, return 0; } +static inline +void wil_get_next_rx_status_msg(struct wil_status_ring *sring, void *msg) +{ + memcpy(msg, (void *)(sring->va + (sring->elem_size * sring->swhead)), + sring->elem_size); +} + static inline void wil_sring_advance_swhead(struct wil_status_ring *sring) { sring->swhead = (sring->swhead + 1) % sring->size; @@ -529,6 +540,95 @@ static int wil_init_rx_desc_ring(struct wil6210_priv *wil, u16 desc_ring_size, return rc; } +static void wil_get_reorder_params_edma(struct sk_buff *skb, int *tid, + int *cid, int *mid, u16 *seq, + int *mcast) +{ + struct wil_rx_status_extended *s = wil_skb_rxstatus(skb); + + *tid = wil_rx_status_get_tid(s); + *cid = wil_rx_status_get_cid(s); + *mid = wil_rx_status_get_mid(s); + *seq = le16_to_cpu(wil_rx_status_get_seq(s)); + *mcast = wil_rx_status_get_mcast(s); +} + +static void wil_get_netif_rx_params_edma(struct sk_buff *skb, int *cid, + int *security) +{ + struct wil_rx_status_extended *s = wil_skb_rxstatus(skb); + + *cid = wil_rx_status_get_cid(s); + *security = wil_rx_status_get_security(s); +} + +static int wil_rx_crypto_check_edma(struct wil6210_priv *wil, + struct sk_buff *skb) +{ + struct wil_rx_status_extended *st; + int cid, tid, key_id, mc; + struct wil_sta_info *s; + struct wil_tid_crypto_rx *c; + struct wil_tid_crypto_rx_single *cc; + const u8 *pn; + + /* In HW reorder, HW is responsible for crypto check */ + if (use_rx_hw_reordering) + return 0; + + st = wil_skb_rxstatus(skb); + + cid = wil_rx_status_get_cid(st); + tid = wil_rx_status_get_tid(st); + key_id = wil_rx_status_get_key_id(st); + mc = wil_rx_status_get_mcast(st); + s = &wil->sta[cid]; + c = mc ? &s->group_crypto_rx : &s->tid_crypto_rx[tid]; + cc = &c->key_id[key_id]; + pn = (u8 *)&st->ext.pn_15_0; + + if (!cc->key_set) { + wil_err_ratelimited(wil, + "Key missing. CID %d TID %d MCast %d KEY_ID %d\n", + cid, tid, mc, key_id); + return -EINVAL; + } + + if (reverse_memcmp(pn, cc->pn, IEEE80211_GCMP_PN_LEN) <= 0) { + wil_err_ratelimited(wil, + "Replay attack. CID %d TID %d MCast %d KEY_ID %d PN %6phN last %6phN\n", + cid, tid, mc, key_id, pn, cc->pn); + return -EINVAL; + } + memcpy(cc->pn, pn, IEEE80211_GCMP_PN_LEN); + + return 0; +} + +static bool wil_is_rx_idle_edma(struct wil6210_priv *wil) +{ + struct wil_status_ring *sring; + struct wil_rx_status_extended msg1; + void *msg = &msg1; + u8 dr_bit; + int i; + + for (i = 0; i < wil->num_rx_status_rings; i++) { + sring = &wil->srings[i]; + if (!sring->va) + continue; + + wil_get_next_rx_status_msg(sring, msg); + dr_bit = wil_rx_status_get_desc_rdy_bit(msg); + + /* Check if there are unhandled RX status messages */ + if (dr_bit == sring->desc_rdy_pol) + return false; + } + + return true; +} + static void wil_rx_buf_len_init_edma(struct wil6210_priv *wil) { wil->rx_buf_len = rx_large_buf ? @@ -546,6 +646,13 @@ static int wil_rx_init_edma(struct wil6210_priv *wil, u16 desc_ring_size) int i; u16 max_rx_pl_per_desc; + /* In SW reorder one must use extended status messages */ + if (use_compressed_rx_status && !use_rx_hw_reordering) { + wil_err(wil, + "compressed RX status cannot be used with SW reorder\n"); + return -EINVAL; + } + wil_dbg_misc(wil, "rx_init, desc_ring_size=%u, status_ring_size=%u, elem_size=%zu\n", desc_ring_size, status_ring_size, elem_size); @@ -656,6 +763,347 @@ static int wil_ring_init_tx_edma(struct wil6210_vif *vif, int ring_id, return rc; } +/* This function is used only for RX SW reorder */ +static int wil_check_bar(struct wil6210_priv *wil, void *msg, int cid, + struct sk_buff *skb, struct wil_net_stats *stats) +{ + u8 ftype; + u8 fc1; + int mid; + int tid; + u16 seq; + struct wil6210_vif *vif; + + ftype = wil_rx_status_get_frame_type(msg); + if (ftype == IEEE80211_FTYPE_DATA) + return 0; + + fc1 = wil_rx_status_get_fc1(msg); + mid = wil_rx_status_get_mid(msg); + tid = wil_rx_status_get_tid(msg); + seq = le16_to_cpu(wil_rx_status_get_seq(msg)); + vif = wil->vifs[mid]; + + if (unlikely(!vif)) { + wil_dbg_txrx(wil, "RX descriptor with invalid mid %d", mid); + return -EAGAIN; + } + + wil_dbg_txrx(wil, + "Non-data frame FC[7:0] 0x%02x MID %d CID %d TID %d Seq 0x%03x\n", + fc1, mid, cid, tid, seq); + stats->rx_non_data_frame++; + if (wil_is_back_req(fc1)) { + wil_dbg_txrx(wil, + "BAR: MID %d CID %d TID %d Seq 0x%03x\n", + mid, cid, tid, seq); + wil_rx_bar(wil, vif, cid, tid, seq); + } else { + u32 sz = use_compressed_rx_status ? + sizeof(struct wil_rx_status_compressed) : + sizeof(struct wil_rx_status_extended); + + /* print again all info. One can enable only this + * without overhead for printing every Rx frame + */ + wil_dbg_txrx(wil, + "Unhandled non-data frame FC[7:0] 0x%02x MID %d CID %d TID %d Seq 0x%03x\n", + fc1, mid, cid, tid, seq); + wil_hex_dump_txrx("RxS ", DUMP_PREFIX_NONE, 32, 4, + (const void *)msg, sz, false); + wil_hex_dump_txrx("Rx ", DUMP_PREFIX_OFFSET, 16, 1, + skb->data, skb_headlen(skb), false); + } + + return -EAGAIN; +} + +static int wil_rx_edma_check_errors(struct wil6210_priv *wil, void *msg, + struct wil_net_stats *stats, + struct sk_buff *skb) +{ + int error; + int l2_rx_status; + int l3_rx_status; + int l4_rx_status; + + error = wil_rx_status_get_error(msg); + if (!error) + return 0; + + l2_rx_status = wil_rx_status_get_l2_rx_status(msg); + if (l2_rx_status != 0) { + wil_dbg_txrx(wil, "L2 RX error, l2_rx_status=0x%x\n", + l2_rx_status); + /* Due to HW issue, KEY error will trigger a MIC error */ + if (l2_rx_status & WIL_RX_EDMA_ERROR_MIC) { + wil_dbg_txrx(wil, + "L2 MIC/KEY error, dropping packet\n"); + stats->rx_mic_error++; + } + if (l2_rx_status & WIL_RX_EDMA_ERROR_KEY) { + wil_dbg_txrx(wil, "L2 KEY error, dropping packet\n"); + stats->rx_key_error++; + } + if (l2_rx_status & WIL_RX_EDMA_ERROR_REPLAY) { + wil_dbg_txrx(wil, + "L2 REPLAY error, dropping packet\n"); + stats->rx_replay++; + } + if (l2_rx_status & WIL_RX_EDMA_ERROR_AMSDU) { + wil_dbg_txrx(wil, + "L2 AMSDU error, dropping packet\n"); + stats->rx_amsdu_error++; + } + return -EFAULT; + } + + l3_rx_status = wil_rx_status_get_l3_rx_status(msg); + l4_rx_status = wil_rx_status_get_l4_rx_status(msg); + if (!l3_rx_status && !l4_rx_status) + skb->ip_summed = CHECKSUM_UNNECESSARY; + /* If HW reports bad checksum, let IP stack re-check it + * For example, HW don't understand Microsoft IP stack that + * mis-calculates TCP checksum - if it should be 0x0, + * it writes 0xffff in violation of RFC 1624 + */ + + return 0; +} + +static struct sk_buff *wil_sring_reap_rx_edma(struct wil6210_priv *wil, + struct wil_status_ring *sring) +{ + struct device *dev = wil_to_dev(wil); + struct wil_rx_status_extended msg1; + void *msg = &msg1; + u16 buff_id; + struct sk_buff *skb; + dma_addr_t pa; + struct wil_ring_rx_data *rxdata = &sring->rx_data; + unsigned int sz = wil->rx_buf_len + ETH_HLEN + + WIL_EDMA_MAX_DATA_OFFSET; + struct wil_net_stats *stats; + u16 dmalen; + int cid; + int rc; + bool eop, headstolen; + int delta; + u8 dr_bit; + u8 data_offset; + struct wil_rx_status_extended *s; + u16 sring_idx = sring - wil->srings; + + BUILD_BUG_ON(sizeof(struct wil_rx_status_extended) > sizeof(skb->cb)); + +again: + wil_get_next_rx_status_msg(sring, msg); + dr_bit = wil_rx_status_get_desc_rdy_bit(msg); + + /* Completed handling all the ready status messages */ + if (dr_bit != sring->desc_rdy_pol) + return NULL; + + /* Extract the buffer ID from the status message */ + buff_id = le16_to_cpu(wil_rx_status_get_buff_id(msg)); + if (unlikely(!wil_val_in_range(buff_id, 0, wil->rx_buff_mgmt.size))) { + wil_err(wil, "Corrupt buff_id=%d, sring->swhead=%d\n", + buff_id, sring->swhead); + wil_sring_advance_swhead(sring); + goto again; + } + + wil_sring_advance_swhead(sring); + + /* Extract the SKB from the rx_buff management array */ + skb = wil->rx_buff_mgmt.buff_arr[buff_id].skb; + wil->rx_buff_mgmt.buff_arr[buff_id].skb = NULL; + if (!skb) { + wil_err(wil, "No Rx skb at buff_id %d\n", buff_id); + goto again; + } + + memcpy(&pa, skb->cb, sizeof(pa)); + dma_unmap_single(dev, pa, sz, DMA_FROM_DEVICE); + dmalen = le16_to_cpu(wil_rx_status_get_length(msg)); + + trace_wil6210_rx_status(use_compressed_rx_status, buff_id, msg); + wil_dbg_txrx(wil, "Rx, buff_id=%u, sring_idx=%u, dmalen=%u bytes\n", + buff_id, sring_idx, dmalen); + wil_hex_dump_txrx("RxS ", DUMP_PREFIX_NONE, 32, 4, + (const void *)msg, use_compressed_rx_status ? + sizeof(struct wil_rx_status_compressed) : + sizeof(struct wil_rx_status_extended), false); + + /* Move the buffer from the active list to the free list */ + list_move(&wil->rx_buff_mgmt.buff_arr[buff_id].list, + &wil->rx_buff_mgmt.free); + + eop = wil_rx_status_get_eop(msg); + + cid = wil_rx_status_get_cid(msg); + if (unlikely(!wil_val_in_range(cid, 0, WIL6210_MAX_CID))) { + wil_err(wil, "Corrupt cid=%d, sring->swhead=%d\n", + cid, sring->swhead); + rxdata->skipping = true; + goto skipping; + } + stats = &wil->sta[cid].stats; + + if (unlikely(skb->len < ETH_HLEN)) { + wil_dbg_txrx(wil, "Short frame, len = %d\n", skb->len); + stats->rx_short_frame++; + rxdata->skipping = true; + goto skipping; + } + + /* Check and treat errors reported by HW */ + rc = wil_rx_edma_check_errors(wil, msg, stats, skb); + if (rc) { + rxdata->skipping = true; + goto skipping; + } + + if (unlikely(dmalen > sz)) { + wil_err(wil, "Rx size too large: %d bytes!\n", dmalen); + stats->rx_large_frame++; + rxdata->skipping = true; + } + +skipping: + /* skipping indicates if a certain SKB should be dropped. + * It is set in case there is an error on the current SKB or in case + * of RX chaining: as long as we manage to merge the SKBs it will + * be false. once we have a bad SKB or we don't manage to merge SKBs + * it will be set to the !EOP value of the current SKB. + * This guarantees that all the following SKBs until EOP will also + * get dropped. + */ + if (unlikely(rxdata->skipping)) { + kfree_skb(skb); + if (rxdata->skb) { + kfree_skb(rxdata->skb); + rxdata->skb = NULL; + } + rxdata->skipping = !eop; + goto again; + } + + skb_trim(skb, dmalen); + + prefetch(skb->data); + + if (!rxdata->skb) { + rxdata->skb = skb; + } else { + if (likely(skb_try_coalesce(rxdata->skb, skb, &headstolen, + &delta))) { + kfree_skb_partial(skb, headstolen); + } else { + wil_err(wil, "failed to merge skbs!\n"); + kfree_skb(skb); + kfree_skb(rxdata->skb); + rxdata->skb = NULL; + rxdata->skipping = !eop; + goto again; + } + } + + if (!eop) + goto again; + + /* reaching here rxdata->skb always contains a full packet */ + skb = rxdata->skb; + rxdata->skb = NULL; + rxdata->skipping = false; + + stats->last_mcs_rx = wil_rx_status_get_mcs(msg); + if (stats->last_mcs_rx < ARRAY_SIZE(stats->rx_per_mcs)) + stats->rx_per_mcs[stats->last_mcs_rx]++; + + if (!use_rx_hw_reordering && !use_compressed_rx_status && + wil_check_bar(wil, msg, cid, skb, stats) == -EAGAIN) { + kfree_skb(skb); + goto again; + } + + /* Compensate for the HW data alignment according to the status + * message + */ + data_offset = wil_rx_status_get_data_offset(msg); + if (data_offset == 0xFF || + data_offset > WIL_EDMA_MAX_DATA_OFFSET) { + wil_err(wil, "Unexpected data offset %d\n", data_offset); + kfree_skb(skb); + goto again; + } + + skb_pull(skb, data_offset); + + wil_hex_dump_txrx("Rx ", DUMP_PREFIX_OFFSET, 16, 1, + skb->data, skb_headlen(skb), false); + + /* Has to be done after dma_unmap_single as skb->cb is also + * used for holding the pa + */ + s = wil_skb_rxstatus(skb); + memcpy(s, msg, sring->elem_size); + + return skb; +} + +void wil_rx_handle_edma(struct wil6210_priv *wil, int *quota) +{ + struct net_device *ndev; + struct wil_ring *ring = &wil->ring_rx; + struct wil_status_ring *sring; + struct sk_buff *skb; + int i; + + if (unlikely(!ring->va)) { + wil_err(wil, "Rx IRQ while Rx not yet initialized\n"); + return; + } + wil_dbg_txrx(wil, "rx_handle\n"); + + for (i = 0; i < wil->num_rx_status_rings; i++) { + sring = &wil->srings[i]; + if (unlikely(!sring->va)) { + wil_err(wil, + "Rx IRQ while Rx status ring %d not yet initialized\n", + i); + continue; + } + + while ((*quota > 0) && + (NULL != (skb = + wil_sring_reap_rx_edma(wil, sring)))) { + (*quota)--; + if (use_rx_hw_reordering) { + void *msg = wil_skb_rxstatus(skb); + int mid = wil_rx_status_get_mid(msg); + struct wil6210_vif *vif = wil->vifs[mid]; + + if (unlikely(!vif)) { + wil_dbg_txrx(wil, + "RX desc invalid mid %d", + mid); + kfree_skb(skb); + continue; + } + ndev = vif_to_ndev(vif); + wil_netif_rx_any(skb, ndev); + } else { + wil_rx_reorder(wil, skb); + } + } + + wil_w(wil, sring->hwtail, (sring->swhead - 1) % sring->size); + } + + wil_rx_refill_edma(wil); +} + static int wil_tx_desc_map_edma(union wil_tx_desc *desc, dma_addr_t pa, u32 len, @@ -1157,6 +1605,11 @@ void wil_init_txrx_ops_edma(struct wil6210_priv *wil) wil->txrx_ops.tx_ring_tso = __wil_tx_ring_tso_edma; /* RX ops */ wil->txrx_ops.rx_init = wil_rx_init_edma; + wil->txrx_ops.wmi_addba_rx_resp = wmi_addba_rx_resp_edma; + wil->txrx_ops.get_reorder_params = wil_get_reorder_params_edma; + wil->txrx_ops.get_netif_rx_params = wil_get_netif_rx_params_edma; + wil->txrx_ops.rx_crypto_check = wil_rx_crypto_check_edma; + wil->txrx_ops.is_rx_idle = wil_is_rx_idle_edma; wil->txrx_ops.rx_fini = wil_rx_fini_edma; } diff --git a/drivers/net/wireless/ath/wil6210/txrx_edma.h b/drivers/net/wireless/ath/wil6210/txrx_edma.h index 7cdb3e407df3..4a6398eec607 100644 --- a/drivers/net/wireless/ath/wil6210/txrx_edma.h +++ b/drivers/net/wireless/ath/wil6210/txrx_edma.h @@ -30,6 +30,27 @@ #define WIL_EDMA_IDLE_TIME_LIMIT_USEC (50) #define WIL_EDMA_TIME_UNIT_CLK_CYCLES (330) /* fits 1 usec */ +/* Error field */ +#define WIL_RX_EDMA_ERROR_MIC (1) +#define WIL_RX_EDMA_ERROR_KEY (2) /* Key missing */ +#define WIL_RX_EDMA_ERROR_REPLAY (3) +#define WIL_RX_EDMA_ERROR_AMSDU (4) +#define WIL_RX_EDMA_ERROR_FCS (7) + +#define WIL_RX_EDMA_ERROR_L3_ERR (BIT(0) | BIT(1)) +#define WIL_RX_EDMA_ERROR_L4_ERR (BIT(0) | BIT(1)) + +#define WIL_RX_EDMA_DLPF_LU_MISS_BIT BIT(11) +#define WIL_RX_EDMA_DLPF_LU_MISS_CID_TID_MASK 0x7 +#define WIL_RX_EDMA_DLPF_LU_HIT_CID_TID_MASK 0xf + +#define WIL_RX_EDMA_DLPF_LU_MISS_CID_POS 2 +#define WIL_RX_EDMA_DLPF_LU_HIT_CID_POS 4 + +#define WIL_RX_EDMA_DLPF_LU_MISS_TID_POS 5 + +#define WIL_RX_EDMA_MID_VALID_BIT BIT(22) + #define WIL_EDMA_DESC_TX_MAC_CFG_0_QID_POS 16 #define WIL_EDMA_DESC_TX_MAC_CFG_0_QID_LEN 6 @@ -321,6 +342,172 @@ struct wil_rx_status_extended { struct wil_rx_status_extension ext; } __packed; +static inline void *wil_skb_rxstatus(struct sk_buff *skb) +{ + return (void *)skb->cb; +} + +static inline __le16 wil_rx_status_get_length(void *msg) +{ + return ((struct wil_rx_status_compressed *)msg)->length; +} + +static inline u8 wil_rx_status_get_mcs(void *msg) +{ + return WIL_GET_BITS(((struct wil_rx_status_compressed *)msg)->d1, + 16, 21); +} + +static inline u16 wil_rx_status_get_flow_id(void *msg) +{ + return WIL_GET_BITS(((struct wil_rx_status_compressed *)msg)->d0, + 8, 19); +} + +static inline u8 wil_rx_status_get_mcast(void *msg) +{ + return WIL_GET_BITS(((struct wil_rx_status_compressed *)msg)->d0, + 26, 26); +} + +/** + * In case of DLPF miss the parsing of flow Id should be as follows: + * dest_id:2 + * src_id :3 - cid + * tid:3 + * Otherwise: + * tid:4 + * cid:4 + */ + +static inline u8 wil_rx_status_get_cid(void *msg) +{ + u16 val = wil_rx_status_get_flow_id(msg); + + if (val & WIL_RX_EDMA_DLPF_LU_MISS_BIT) + /* CID is in bits 2..4 */ + return (val >> WIL_RX_EDMA_DLPF_LU_MISS_CID_POS) & + WIL_RX_EDMA_DLPF_LU_MISS_CID_TID_MASK; + else + /* CID is in bits 4..7 */ + return (val >> WIL_RX_EDMA_DLPF_LU_HIT_CID_POS) & + WIL_RX_EDMA_DLPF_LU_HIT_CID_TID_MASK; +} + +static inline u8 wil_rx_status_get_tid(void *msg) +{ + u16 val = wil_rx_status_get_flow_id(msg); + + if (val & WIL_RX_EDMA_DLPF_LU_MISS_BIT) + /* TID is in bits 5..7 */ + return (val >> WIL_RX_EDMA_DLPF_LU_MISS_TID_POS) & + WIL_RX_EDMA_DLPF_LU_MISS_CID_TID_MASK; + else + /* TID is in bits 0..3 */ + return val & WIL_RX_EDMA_DLPF_LU_MISS_CID_TID_MASK; +} + +static inline int wil_rx_status_get_desc_rdy_bit(void *msg) +{ + return WIL_GET_BITS(((struct wil_rx_status_compressed *)msg)->d0, + 31, 31); +} + +static inline int wil_rx_status_get_eop(void *msg) /* EoP = End of Packet */ +{ + return WIL_GET_BITS(((struct wil_rx_status_compressed *)msg)->d0, + 30, 30); +} + +static inline __le16 wil_rx_status_get_buff_id(void *msg) +{ + return ((struct wil_rx_status_compressed *)msg)->buff_id; +} + +static inline u8 wil_rx_status_get_data_offset(void *msg) +{ + u8 val = WIL_GET_BITS(((struct wil_rx_status_compressed *)msg)->d1, + 24, 27); + + switch (val) { + case 0: return 0; + case 3: return 2; + default: return 0xFF; + } +} + +static inline int wil_rx_status_get_frame_type(void *msg) +{ + if (use_compressed_rx_status) + return IEEE80211_FTYPE_DATA; + + return WIL_GET_BITS(((struct wil_rx_status_extended *)msg)->ext.d1, + 0, 1) << 2; +} + +static inline int wil_rx_status_get_fc1(void *msg) +{ + if (use_compressed_rx_status) + return 0; + + return WIL_GET_BITS(((struct wil_rx_status_extended *)msg)->ext.d1, + 0, 5) << 2; +} + +static inline __le16 wil_rx_status_get_seq(void *msg) +{ + if (use_compressed_rx_status) + return 0; + + return ((struct wil_rx_status_extended *)msg)->ext.seq_num; +} + +static inline int wil_rx_status_get_mid(void *msg) +{ + if (!(((struct wil_rx_status_compressed *)msg)->d0 & + WIL_RX_EDMA_MID_VALID_BIT)) + return 0; /* use the default MID */ + + return WIL_GET_BITS(((struct wil_rx_status_compressed *)msg)->d0, + 20, 21); +} + +static inline int wil_rx_status_get_error(void *msg) +{ + return WIL_GET_BITS(((struct wil_rx_status_compressed *)msg)->d0, + 29, 29); +} + +static inline int wil_rx_status_get_l2_rx_status(void *msg) +{ + return WIL_GET_BITS(((struct wil_rx_status_compressed *)msg)->d0, + 0, 2); +} + +static inline int wil_rx_status_get_l3_rx_status(void *msg) +{ + return WIL_GET_BITS(((struct wil_rx_status_compressed *)msg)->d0, + 3, 4); +} + +static inline int wil_rx_status_get_l4_rx_status(void *msg) +{ + return WIL_GET_BITS(((struct wil_rx_status_compressed *)msg)->d0, + 5, 6); +} + +static inline int wil_rx_status_get_security(void *msg) +{ + return WIL_GET_BITS(((struct wil_rx_status_compressed *)msg)->d0, + 28, 28); +} + +static inline u8 wil_rx_status_get_key_id(void *msg) +{ + return WIL_GET_BITS(((struct wil_rx_status_compressed *)msg)->d1, + 31, 31); +} + static inline u8 wil_tx_status_get_mcs(struct wil_ring_tx_status *msg) { return WIL_GET_BITS(msg->d2, 0, 4); @@ -359,6 +546,7 @@ dma_addr_t wil_rx_desc_get_addr_edma(struct wil_ring_rx_enhanced_dma *dma) void wil_configure_interrupt_moderation_edma(struct wil6210_priv *wil); int wil_tx_sring_handler(struct wil6210_priv *wil, struct wil_status_ring *sring); +void wil_rx_handle_edma(struct wil6210_priv *wil, int *quota); void wil_init_txrx_ops_edma(struct wil6210_priv *wil); #endif /* WIL6210_TXRX_EDMA_H */ diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index 0103bc949e40..c9308229250d 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -38,6 +38,7 @@ extern bool rx_align_2; extern bool rx_large_buf; extern bool debug_fw; extern bool disable_ap_sme; +extern bool use_rx_hw_reordering; extern bool use_compressed_rx_status; struct wil6210_priv; @@ -325,9 +326,13 @@ struct RGF_ICR { #define BIT_CONTROL_0 BIT(0) /* eDMA status interrupts */ +#define RGF_INT_GEN_RX_ICR (0x8bc0f4) + #define BIT_RX_STATUS_IRQ BIT(WIL_RX_STATUS_IRQ_IDX) #define RGF_INT_GEN_TX_ICR (0x8bc110) #define BIT_TX_STATUS_IRQ BIT(WIL_TX_STATUS_IRQ_IDX) +#define RGF_INT_CTRL_RX_INT_MASK (0x8bc12c) #define RGF_INT_CTRL_TX_INT_MASK (0x8bc130) + #define RGF_INT_GEN_IDLE_TIME_LIMIT (0x8bc134) #define USER_EXT_USER_PMU_3 (0x88d00c) @@ -558,6 +563,16 @@ struct wil_txrx_ops { /* RX ops */ int (*rx_init)(struct wil6210_priv *wil, u16 ring_size); void (*rx_fini)(struct wil6210_priv *wil); + int (*wmi_addba_rx_resp)(struct wil6210_priv *wil, u8 mid, u8 cid, + u8 tid, u8 token, u16 status, bool amsdu, + u16 agg_wsize, u16 timeout); + void (*get_reorder_params)(struct sk_buff *skb, int *tid, int *cid, + int *mid, u16 *seq, int *mcast); + void (*get_netif_rx_params)(struct sk_buff *skb, + int *cid, int *security); + int (*rx_crypto_check)(struct wil6210_priv *wil, struct sk_buff *skb); + bool (*is_rx_idle)(struct wil6210_priv *wil); + irqreturn_t (*irq_rx)(int irq, void *cookie); }; /** @@ -905,7 +920,6 @@ struct wil6210_priv { /* DMA related */ struct wil_ring ring_rx; - struct wil_ring_rx_data ring_rx_data; unsigned int rx_buf_len; struct wil_ring ring_tx[WIL6210_MAX_TX_RINGS]; struct wil_ring_tx_data ring_tx_data[WIL6210_MAX_TX_RINGS]; @@ -1271,6 +1285,7 @@ void wil6210_unmask_irq_tx_edma(struct wil6210_priv *wil); /* RX API */ void wil_rx_handle(struct wil6210_priv *wil, int *quota); void wil6210_unmask_irq_rx(struct wil6210_priv *wil); +void wil6210_unmask_irq_rx_edma(struct wil6210_priv *wil); int wil_iftype_nl2wmi(enum nl80211_iftype type); @@ -1292,7 +1307,6 @@ bool wil_is_wmi_idle(struct wil6210_priv *wil); int wmi_resume(struct wil6210_priv *wil); int wmi_suspend(struct wil6210_priv *wil); bool wil_is_tx_idle(struct wil6210_priv *wil); -bool wil_is_rx_idle(struct wil6210_priv *wil); int wil_fw_copy_crash_dump(struct wil6210_priv *wil, void *dest, u32 size); void wil_fw_core_dump(struct wil6210_priv *wil); @@ -1326,6 +1340,8 @@ int wmi_start_sched_scan(struct wil6210_priv *wil, struct cfg80211_sched_scan_request *request); int wmi_stop_sched_scan(struct wil6210_priv *wil); +int reverse_memcmp(const void *cs, const void *ct, size_t count); + /* WMI for enhanced DMA */ int wil_wmi_tx_sring_cfg(struct wil6210_priv *wil, int ring_id); int wil_wmi_cfg_def_rx_offload(struct wil6210_priv *wil, @@ -1335,5 +1351,8 @@ int wil_wmi_rx_desc_ring_add(struct wil6210_priv *wil, int status_ring_id); int wil_wmi_tx_desc_ring_add(struct wil6210_vif *vif, int ring_id, int cid, int tid); int wil_wmi_bcast_desc_ring_add(struct wil6210_vif *vif, int ring_id); +int wmi_addba_rx_resp_edma(struct wil6210_priv *wil, u8 mid, u8 cid, + u8 tid, u8 token, u16 status, bool amsdu, + u16 agg_wsize, u16 timeout); #endif /* __WIL6210_H__ */ diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c index 6d5bee308de7..6d87369589db 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.c +++ b/drivers/net/wireless/ath/wil6210/wmi.c @@ -39,6 +39,10 @@ module_param(led_id, byte, 0444); MODULE_PARM_DESC(led_id, " 60G device led enablement. Set the led ID (0-2) to enable"); +static bool amsdu_en; +module_param(amsdu_en, bool, 0444); +MODULE_PARM_DESC(amsdu_en, " enable A-MSDU, default: false"); + #define WIL_WAIT_FOR_SUSPEND_RESUME_COMP 200 #define WIL_WMI_CALL_GENERAL_TO_MS 100 @@ -429,6 +433,8 @@ static const char *cmdid2name(u16 cmdid) return "WMI_RCP_DELBA_CMD"; case WMI_RCP_ADDBA_RESP_CMDID: return "WMI_RCP_ADDBA_RESP_CMD"; + case WMI_RCP_ADDBA_RESP_EDMA_CMDID: + return "WMI_RCP_ADDBA_RESP_EDMA_CMD"; case WMI_PS_DEV_PROFILE_CFG_CMDID: return "WMI_PS_DEV_PROFILE_CFG_CMD"; case WMI_SET_MGMT_RETRY_LIMIT_CMDID: @@ -2146,15 +2152,18 @@ int wmi_disconnect_sta(struct wil6210_vif *vif, const u8 *mac, int wmi_addba(struct wil6210_priv *wil, u8 mid, u8 ringid, u8 size, u16 timeout) { + u8 amsdu = wil->use_enhanced_dma_hw && use_rx_hw_reordering && + amsdu_en ? 1 : 0; + struct wmi_ring_ba_en_cmd cmd = { .ring_id = ringid, .agg_max_wsize = size, .ba_timeout = cpu_to_le16(timeout), - .amsdu = 0, + .amsdu = amsdu, }; - wil_dbg_wmi(wil, "addba: (ring %d size %d timeout %d)\n", ringid, size, - timeout); + wil_dbg_wmi(wil, "addba: (ring %d size %d timeout %d amsdu %d)\n", + ringid, size, timeout, amsdu); return wmi_send(wil, WMI_RING_BA_EN_CMDID, mid, &cmd, sizeof(cmd)); } @@ -2227,6 +2236,54 @@ int wmi_addba_rx_resp(struct wil6210_priv *wil, return rc; } +int wmi_addba_rx_resp_edma(struct wil6210_priv *wil, u8 mid, u8 cid, u8 tid, + u8 token, u16 status, bool amsdu, u16 agg_wsize, + u16 timeout) +{ + int rc; + struct wmi_rcp_addba_resp_edma_cmd cmd = { + .cid = cid, + .tid = tid, + .dialog_token = token, + .status_code = cpu_to_le16(status), + /* bit 0: A-MSDU supported + * bit 1: policy (should be 0 for us) + * bits 2..5: TID + * bits 6..15: buffer size + */ + .ba_param_set = cpu_to_le16((amsdu ? 1 : 0) | (tid << 2) | + (agg_wsize << 6)), + .ba_timeout = cpu_to_le16(timeout), + /* route all the connections to status ring 0 */ + .status_ring_id = WIL_DEFAULT_RX_STATUS_RING_ID, + }; + struct { + struct wmi_cmd_hdr wmi; + struct wmi_rcp_addba_resp_sent_event evt; + } __packed reply = { + .evt = {.status = cpu_to_le16(WMI_FW_STATUS_FAILURE)}, + }; + + wil_dbg_wmi(wil, + "ADDBA response for CID %d TID %d size %d timeout %d status %d AMSDU%s, sring_id %d\n", + cid, tid, agg_wsize, timeout, status, amsdu ? "+" : "-", + WIL_DEFAULT_RX_STATUS_RING_ID); + + rc = wmi_call(wil, WMI_RCP_ADDBA_RESP_EDMA_CMDID, mid, &cmd, + sizeof(cmd), WMI_RCP_ADDBA_RESP_SENT_EVENTID, &reply, + sizeof(reply), WIL_WMI_CALL_GENERAL_TO_MS); + if (rc) + return rc; + + if (reply.evt.status) { + wil_err(wil, "ADDBA response failed with status %d\n", + le16_to_cpu(reply.evt.status)); + rc = -EINVAL; + } + + return rc; +} + int wmi_ps_dev_profile_cfg(struct wil6210_priv *wil, enum wmi_ps_profile_type ps_profile) { -- GitLab From 9c333e5c6d1e5522e985585ebe82e52406d995a2 Mon Sep 17 00:00:00 2001 From: Maya Erez Date: Sun, 8 Apr 2018 22:20:04 +0300 Subject: [PATCH 0134/1635] wil6210: add support for enhanced DMA debugfs Add debugfs support for enhanced DMA TX and RX descriptor rings, TX and RX status rings and RX buffer management. Run the following command to print the TX and RX status rings: cat srings Run the following command in order to select the status ring: echo STATUS_RING_IDX > dbg_sring_index Run the following command in order to select the status message: echo STATUS_MSG_IDX > dbg_status_msg_index Run the following command in order to print the selected status message from the selected status ring: cat status_msg Run the following command in order to print the RX buffer management debug information: cat rx_buff_mgmt Change-Id: I15cca4cb5fb10df2fd618a221111d857a57b08fb Signed-off-by: Gidon Studinski Signed-off-by: Maya Erez --- drivers/net/wireless/ath/wil6210/debugfs.c | 347 ++++++++++++++++++--- 1 file changed, 307 insertions(+), 40 deletions(-) diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c index 484e15df04de..4719dd5a1ef6 100644 --- a/drivers/net/wireless/ath/wil6210/debugfs.c +++ b/drivers/net/wireless/ath/wil6210/debugfs.c @@ -30,6 +30,9 @@ static u32 mem_addr; static u32 dbg_txdesc_index; static u32 dbg_ring_index; /* 24+ for Rx, 0..23 for Tx */ +static u32 dbg_status_msg_index; +/* 0..wil->num_rx_status_rings-1 for Rx, wil->tx_sring_idx for Tx */ +static u32 dbg_sring_index; enum dbg_off_type { doff_u32 = 0, @@ -47,6 +50,36 @@ struct dbg_off { enum dbg_off_type type; }; +static void wil_print_desc_edma(struct seq_file *s, struct wil6210_priv *wil, + struct wil_ring *ring, + char _s, char _h, int idx) +{ + u8 num_of_descs; + bool has_skb = false; + + if (ring->is_rx) { + struct wil_rx_enhanced_desc *rx_d = + (struct wil_rx_enhanced_desc *) + &ring->va[idx].rx.enhanced; + u16 buff_id = le16_to_cpu(rx_d->mac.buff_id); + + has_skb = wil->rx_buff_mgmt.buff_arr[buff_id].skb; + seq_printf(s, "%c", (has_skb) ? _h : _s); + } else { + struct wil_tx_enhanced_desc *d = + (struct wil_tx_enhanced_desc *) + &ring->va[idx].tx.enhanced; + + num_of_descs = (u8)d->mac.d[2]; + has_skb = ring->ctx[idx].skb; + if (num_of_descs >= 1) + seq_printf(s, "%c", ring->ctx[idx].skb ? _h : _s); + else + /* num_of_descs == 0, it's a frag in a list of descs */ + seq_printf(s, "%c", has_skb ? 'h' : _s); + } +} + static void wil_print_ring(struct seq_file *s, struct wil6210_priv *wil, const char *name, struct wil_ring *ring, char _s, char _h) @@ -58,7 +91,10 @@ static void wil_print_ring(struct seq_file *s, struct wil6210_priv *wil, seq_printf(s, " pa = %pad\n", &ring->pa); seq_printf(s, " va = 0x%p\n", ring->va); seq_printf(s, " size = %d\n", ring->size); - seq_printf(s, " swtail = %d\n", ring->swtail); + if (wil->use_enhanced_dma_hw && ring->is_rx) + seq_printf(s, " swtail = %u\n", *ring->edma_rx_swtail.va); + else + seq_printf(s, " swtail = %d\n", ring->swtail); seq_printf(s, " swhead = %d\n", ring->swhead); seq_printf(s, " hwtail = [0x%08x] -> ", ring->hwtail); if (x) { @@ -72,13 +108,16 @@ static void wil_print_ring(struct seq_file *s, struct wil6210_priv *wil, uint i; for (i = 0; i < ring->size; i++) { - volatile struct vring_tx_desc *d = - &ring->va[i].tx.legacy; - - if ((i % 128) == 0 && (i != 0)) + if ((i % 128) == 0 && i != 0) seq_puts(s, "\n"); - seq_printf(s, "%c", (d->dma.status & BIT(0)) ? - _s : (ring->ctx[i].skb ? _h : 'h')); + if (wil->use_enhanced_dma_hw) { + wil_print_desc_edma(s, wil, ring, _s, _h, i); + } else { + volatile struct vring_tx_desc *d = + &ring->va[i].tx.legacy; + seq_printf(s, "%c", (d->dma.status & BIT(0)) ? + _s : (ring->ctx[i].skb ? _h : 'h')); + } } seq_puts(s, "\n"); } @@ -157,6 +196,74 @@ static const struct file_operations fops_ring = { .llseek = seq_lseek, }; +static void wil_print_sring(struct seq_file *s, struct wil6210_priv *wil, + struct wil_status_ring *sring) +{ + void __iomem *x = wmi_addr(wil, sring->hwtail); + int sring_idx = sring - wil->srings; + u32 v; + + seq_printf(s, "Status Ring %s [ %d ] = {\n", + sring->is_rx ? "RX" : "TX", sring_idx); + seq_printf(s, " pa = %pad\n", &sring->pa); + seq_printf(s, " va = 0x%pK\n", sring->va); + seq_printf(s, " size = %d\n", sring->size); + seq_printf(s, " elem_size = %zu\n", sring->elem_size); + seq_printf(s, " swhead = %d\n", sring->swhead); + seq_printf(s, " hwtail = [0x%08x] -> ", sring->hwtail); + if (x) { + v = readl_relaxed(x); + seq_printf(s, "0x%08x = %d\n", v, v); + } else { + seq_puts(s, "???\n"); + } + seq_printf(s, " desc_rdy_pol = %d\n", sring->desc_rdy_pol); + + if (sring->va && (sring->size <= (1 << WIL_RING_SIZE_ORDER_MAX))) { + uint i; + + for (i = 0; i < sring->size; i++) { + u32 *sdword_0 = + (u32 *)(sring->va + (sring->elem_size * i)); + + if ((i % 128) == 0 && i != 0) + seq_puts(s, "\n"); + if (i == sring->swhead) + seq_printf(s, "%c", (*sdword_0 & BIT(31)) ? + 'X' : 'x'); + else + seq_printf(s, "%c", (*sdword_0 & BIT(31)) ? + '1' : '0'); + } + seq_puts(s, "\n"); + } + seq_puts(s, "}\n"); +} + +static int wil_srings_debugfs_show(struct seq_file *s, void *data) +{ + struct wil6210_priv *wil = s->private; + int i = 0; + + for (i = 0; i < WIL6210_MAX_STATUS_RINGS; i++) + if (wil->srings[i].va) + wil_print_sring(s, wil, &wil->srings[i]); + + return 0; +} + +static int wil_srings_seq_open(struct inode *inode, struct file *file) +{ + return single_open(file, wil_srings_debugfs_show, inode->i_private); +} + +static const struct file_operations fops_srings = { + .open = wil_srings_seq_open, + .release = single_release, + .read = seq_read, + .llseek = seq_lseek, +}; + static void wil_seq_hexdump(struct seq_file *s, void *p, int len, const char *prefix) { @@ -975,53 +1082,92 @@ static int wil_txdesc_debugfs_show(struct seq_file *s, void *data) { struct wil6210_priv *wil = s->private; struct wil_ring *ring; - bool tx = (dbg_ring_index < WIL6210_MAX_TX_RINGS); + bool tx; + int ring_idx = dbg_ring_index; + int txdesc_idx = dbg_txdesc_index; + volatile struct vring_tx_desc *d; + volatile u32 *u; + struct sk_buff *skb; + + if (wil->use_enhanced_dma_hw) { + /* RX ring index == 0 */ + if (ring_idx >= WIL6210_MAX_TX_RINGS) { + seq_printf(s, "invalid ring index %d\n", ring_idx); + return 0; + } + tx = ring_idx > 0; /* desc ring 0 is reserved for RX */ + } else { + /* RX ring index == WIL6210_MAX_TX_RINGS */ + if (ring_idx > WIL6210_MAX_TX_RINGS) { + seq_printf(s, "invalid ring index %d\n", ring_idx); + return 0; + } + tx = (ring_idx < WIL6210_MAX_TX_RINGS); + } - ring = tx ? &wil->ring_tx[dbg_ring_index] : &wil->ring_rx; + ring = tx ? &wil->ring_tx[ring_idx] : &wil->ring_rx; if (!ring->va) { if (tx) - seq_printf(s, "No Tx[%2d] VRING\n", dbg_ring_index); + seq_printf(s, "No Tx[%2d] RING\n", ring_idx); else - seq_puts(s, "No Rx VRING\n"); + seq_puts(s, "No Rx RING\n"); return 0; } - if (dbg_txdesc_index < ring->size) { - /* use struct vring_tx_desc for Rx as well, - * only field used, .dma.length, is the same - */ - volatile struct vring_tx_desc *d = - &ring->va[dbg_txdesc_index].tx.legacy; - volatile u32 *u = (volatile u32 *)d; - struct sk_buff *skb = ring->ctx[dbg_txdesc_index].skb; - + if (txdesc_idx >= ring->size) { if (tx) - seq_printf(s, "Tx[%2d][%3d] = {\n", dbg_ring_index, - dbg_txdesc_index); + seq_printf(s, "[%2d] TxDesc index (%d) >= size (%d)\n", + ring_idx, txdesc_idx, ring->size); else - seq_printf(s, "Rx[%3d] = {\n", dbg_txdesc_index); - seq_printf(s, " MAC = 0x%08x 0x%08x 0x%08x 0x%08x\n", - u[0], u[1], u[2], u[3]); - seq_printf(s, " DMA = 0x%08x 0x%08x 0x%08x 0x%08x\n", - u[4], u[5], u[6], u[7]); - seq_printf(s, " SKB = 0x%p\n", skb); + seq_printf(s, "RxDesc index (%d) >= size (%d)\n", + txdesc_idx, ring->size); + return 0; + } + + /* use struct vring_tx_desc for Rx as well, + * only field used, .dma.length, is the same + */ + d = &ring->va[txdesc_idx].tx.legacy; + u = (volatile u32 *)d; + skb = NULL; - if (skb) { - skb_get(skb); - wil_seq_print_skb(s, skb); - kfree_skb(skb); + if (wil->use_enhanced_dma_hw) { + if (tx) { + skb = ring->ctx[txdesc_idx].skb; + } else { + struct wil_rx_enhanced_desc *rx_d = + (struct wil_rx_enhanced_desc *) + &ring->va[txdesc_idx].rx.enhanced; + u16 buff_id = le16_to_cpu(rx_d->mac.buff_id); + + if (!wil_val_in_range(buff_id, 0, + wil->rx_buff_mgmt.size)) { + seq_printf(s, "invalid buff_id %d\n", buff_id); + return 0; + } + skb = wil->rx_buff_mgmt.buff_arr[buff_id].skb; } - seq_puts(s, "}\n"); } else { - if (tx) - seq_printf(s, "[%2d] TxDesc index (%d) >= size (%d)\n", - dbg_ring_index, dbg_txdesc_index, - ring->size); - else - seq_printf(s, "RxDesc index (%d) >= size (%d)\n", - dbg_txdesc_index, ring->size); + skb = ring->ctx[txdesc_idx].skb; + } + if (tx) + seq_printf(s, "Tx[%2d][%3d] = {\n", ring_idx, + txdesc_idx); + else + seq_printf(s, "Rx[%3d] = {\n", txdesc_idx); + seq_printf(s, " MAC = 0x%08x 0x%08x 0x%08x 0x%08x\n", + u[0], u[1], u[2], u[3]); + seq_printf(s, " DMA = 0x%08x 0x%08x 0x%08x 0x%08x\n", + u[4], u[5], u[6], u[7]); + seq_printf(s, " SKB = 0x%p\n", skb); + + if (skb) { + skb_get(skb); + wil_seq_print_skb(s, skb); + kfree_skb(skb); } + seq_puts(s, "}\n"); return 0; } @@ -1038,6 +1184,115 @@ static const struct file_operations fops_txdesc = { .llseek = seq_lseek, }; +/*---------Tx/Rx status message------------*/ +static int wil_status_msg_debugfs_show(struct seq_file *s, void *data) +{ + struct wil6210_priv *wil = s->private; + int sring_idx = dbg_sring_index; + struct wil_status_ring *sring; + bool tx = sring_idx == wil->tx_sring_idx ? 1 : 0; + u32 status_msg_idx = dbg_status_msg_index; + u32 *u; + + if (sring_idx >= WIL6210_MAX_STATUS_RINGS) { + seq_printf(s, "invalid status ring index %d\n", sring_idx); + return 0; + } + + sring = &wil->srings[sring_idx]; + + if (!sring->va) { + seq_printf(s, "No %cX status ring\n", tx ? 'T' : 'R'); + return 0; + } + + if (status_msg_idx >= sring->size) { + seq_printf(s, "%cxDesc index (%d) >= size (%d)\n", + tx ? 'T' : 'R', status_msg_idx, sring->size); + return 0; + } + + u = sring->va + (sring->elem_size * status_msg_idx); + + seq_printf(s, "%cx[%d][%3d] = {\n", + tx ? 'T' : 'R', sring_idx, status_msg_idx); + + seq_printf(s, " 0x%08x 0x%08x 0x%08x 0x%08x\n", + u[0], u[1], u[2], u[3]); + if (!tx && !use_compressed_rx_status) + seq_printf(s, " 0x%08x 0x%08x 0x%08x 0x%08x\n", + u[4], u[5], u[6], u[7]); + + seq_puts(s, "}\n"); + + return 0; +} + +static int wil_status_msg_seq_open(struct inode *inode, struct file *file) +{ + return single_open(file, wil_status_msg_debugfs_show, + inode->i_private); +} + +static const struct file_operations fops_status_msg = { + .open = wil_status_msg_seq_open, + .release = single_release, + .read = seq_read, + .llseek = seq_lseek, +}; + +static int wil_print_rx_buff(struct seq_file *s, struct list_head *lh) +{ + struct wil_rx_buff *it; + int i = 0; + + list_for_each_entry(it, lh, list) { + if ((i % 16) == 0 && i != 0) + seq_puts(s, "\n "); + seq_printf(s, "[%4d] ", it->id); + i++; + } + seq_printf(s, "\nNumber of buffers: %u\n", i); + + return i; +} + +static int wil_rx_buff_mgmt_debugfs_show(struct seq_file *s, void *data) +{ + struct wil6210_priv *wil = s->private; + struct wil_rx_buff_mgmt *rbm = &wil->rx_buff_mgmt; + int num_active; + int num_free; + + seq_printf(s, " size = %zu\n", rbm->size); + seq_printf(s, " free_list_empty_cnt = %lu\n", + rbm->free_list_empty_cnt); + + /* Print active list */ + seq_puts(s, " Active list:\n"); + num_active = wil_print_rx_buff(s, &rbm->active); + seq_puts(s, "\n Free list:\n"); + num_free = wil_print_rx_buff(s, &rbm->free); + + seq_printf(s, " Total number of buffers: %u\n", + num_active + num_free); + + return 0; +} + +static int wil_rx_buff_mgmt_seq_open(struct inode *inode, struct file *file) +{ + return single_open(file, wil_rx_buff_mgmt_debugfs_show, + inode->i_private); +} + +static const struct file_operations fops_rx_buff_mgmt = { + .open = wil_rx_buff_mgmt_seq_open, + .release = single_release, + .read = seq_read, + .llseek = seq_lseek, +}; + /*---------beamforming------------*/ static char *wil_bfstatus_str(u32 status) { @@ -1517,6 +1772,13 @@ __acquires(&p->tid_rx_lock) __releases(&p->tid_rx_lock) p->stats.rx_large_frame, p->stats.rx_replay); + if (wil->use_enhanced_dma_hw) + seq_printf(s, + "mic error %lu, key error %lu, amsdu error %lu\n", + p->stats.rx_mic_error, + p->stats.rx_key_error, + p->stats.rx_amsdu_error); + seq_puts(s, "Rx/MCS:"); for (mcs = 0; mcs < ARRAY_SIZE(p->stats.rx_per_mcs); mcs++) @@ -1853,6 +2115,9 @@ static const struct { {"fw_capabilities", 0444, &fops_fw_capabilities}, {"fw_version", 0444, &fops_fw_version}, {"suspend_stats", 0644, &fops_suspend_stats}, + {"srings", 0444, &fops_srings}, + {"status_msg", 0444, &fops_status_msg}, + {"rx_buff_mgmt", 0444, &fops_rx_buff_mgmt}, }; static void wil6210_debugfs_init_files(struct wil6210_priv *wil, @@ -1916,6 +2181,8 @@ static const struct dbg_off dbg_statics[] = { {"ring_index", 0644, (ulong)&dbg_ring_index, doff_u32}, {"mem_addr", 0644, (ulong)&mem_addr, doff_u32}, {"led_polarity", 0644, (ulong)&led_polarity, doff_u8}, + {"status_index", 0644, (ulong)&dbg_status_msg_index, doff_u32}, + {"sring_index", 0644, (ulong)&dbg_sring_index, doff_u32}, {}, }; -- GitLab From 037e3ab5585c31e704710c560fdabfba52d424c5 Mon Sep 17 00:00:00 2001 From: Maya Erez Date: Tue, 13 Mar 2018 14:44:59 +0200 Subject: [PATCH 0135/1635] wil6210: add support for Talyn-MB boot flow Talyn-MB introduces various of FW download options: FW download via PCIe, SPI or PBL for secured access. The boot and FW download path is determined based on the OTP HW register. Driver reads this register as part of the SW reset flow and performs the appropriate initialization sequence. Change-Id: I368b5c9be4ad8464c273d6c805b49580bdaee484 Signed-off-by: Maya Erez --- drivers/net/wireless/ath/wil6210/main.c | 199 +++++++++++++++++---- drivers/net/wireless/ath/wil6210/wil6210.h | 10 +- 2 files changed, 177 insertions(+), 32 deletions(-) diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index 96e250eaecdc..5d90e99aeaed 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c @@ -112,9 +112,29 @@ MODULE_PARM_DESC(tx_ring_order, " Tx ring order; size = 1 << order"); module_param_cb(bcast_ring_order, &ring_order_ops, &bcast_ring_order, 0444); MODULE_PARM_DESC(bcast_ring_order, " Bcast ring order; size = 1 << order"); -#define RST_DELAY (20) /* msec, for loop in @wil_target_reset */ +enum { + WIL_BOOT_ERR, + WIL_BOOT_VANILLA, + WIL_BOOT_PRODUCTION, + WIL_BOOT_DEVELOPMENT, +}; + +enum { + WIL_SIG_STATUS_VANILLA = 0x0, + WIL_SIG_STATUS_DEVELOPMENT = 0x1, + WIL_SIG_STATUS_PRODUCTION = 0x2, + WIL_SIG_STATUS_CORRUPTED_PRODUCTION = 0x3, +}; + +#define RST_DELAY (20) /* msec, for loop in @wil_wait_device_ready */ #define RST_COUNT (1 + 1000/RST_DELAY) /* round up to be above 1 sec total */ +#define PMU_READY_DELAY_MS (4) /* ms, for sleep in @wil_wait_device_ready */ + +#define OTP_HW_DELAY (200) /* usec, loop in @wil_wait_device_ready_talyn_mb */ +/* round up to be above 2 ms total */ +#define OTP_HW_COUNT (1 + 2000 / OTP_HW_DELAY) + /* * Due to a hardware issue, * one has to read/write to/from NIC in 32-bit chunks; @@ -815,11 +835,146 @@ static void wil_set_oob_mode(struct wil6210_priv *wil, u8 mode) } } -static int wil_target_reset(struct wil6210_priv *wil, int no_flash) +static int wil_wait_device_ready(struct wil6210_priv *wil, int no_flash) { int delay = 0; u32 x, x1 = 0; + /* wait until device ready. */ + if (no_flash) { + msleep(PMU_READY_DELAY_MS); + + wil_dbg_misc(wil, "Reset completed\n"); + } else { + do { + msleep(RST_DELAY); + x = wil_r(wil, RGF_USER_BL + + offsetof(struct bl_dedicated_registers_v0, + boot_loader_ready)); + if (x1 != x) { + wil_dbg_misc(wil, "BL.ready 0x%08x => 0x%08x\n", + x1, x); + x1 = x; + } + if (delay++ > RST_COUNT) { + wil_err(wil, "Reset not completed, bl.ready 0x%08x\n", + x); + return -ETIME; + } + } while (x != BL_READY); + + wil_dbg_misc(wil, "Reset completed in %d ms\n", + delay * RST_DELAY); + } + + return 0; +} + +static int wil_wait_device_ready_talyn_mb(struct wil6210_priv *wil) +{ + u32 otp_hw; + u8 signature_status; + bool otp_signature_err; + bool hw_section_done; + u32 otp_qc_secured; + int delay = 0; + + /* Wait for OTP signature test to complete */ + usleep_range(2000, 2200); + + wil->boot_config = WIL_BOOT_ERR; + + /* Poll until OTP signature status is valid. + * In vanilla and development modes, when signature test is complete + * HW sets BIT_OTP_SIGNATURE_ERR_TALYN_MB. + * In production mode BIT_OTP_SIGNATURE_ERR_TALYN_MB remains 0, poll + * for signature status change to 2 or 3. + */ + do { + otp_hw = wil_r(wil, RGF_USER_OTP_HW_RD_MACHINE_1); + signature_status = WIL_GET_BITS(otp_hw, 8, 9); + otp_signature_err = otp_hw & BIT_OTP_SIGNATURE_ERR_TALYN_MB; + + if (otp_signature_err && + signature_status == WIL_SIG_STATUS_VANILLA) { + wil->boot_config = WIL_BOOT_VANILLA; + break; + } + if (otp_signature_err && + signature_status == WIL_SIG_STATUS_DEVELOPMENT) { + wil->boot_config = WIL_BOOT_DEVELOPMENT; + break; + } + if (!otp_signature_err && + signature_status == WIL_SIG_STATUS_PRODUCTION) { + wil->boot_config = WIL_BOOT_PRODUCTION; + break; + } + if (!otp_signature_err && + signature_status == + WIL_SIG_STATUS_CORRUPTED_PRODUCTION) { + /* Unrecognized OTP signature found. Possibly a + * corrupted production signature, access control + * is applied as in production mode, therefore + * do not fail + */ + wil->boot_config = WIL_BOOT_PRODUCTION; + break; + } + if (delay++ > OTP_HW_COUNT) + break; + + usleep_range(OTP_HW_DELAY, OTP_HW_DELAY + 10); + } while (!otp_signature_err && signature_status == 0); + + if (wil->boot_config == WIL_BOOT_ERR) { + wil_err(wil, + "invalid boot config, signature_status %d otp_signature_err %d\n", + signature_status, otp_signature_err); + return -ETIME; + } + + wil_dbg_misc(wil, + "signature test done in %d usec, otp_hw 0x%x, boot_config %d\n", + delay * OTP_HW_DELAY, otp_hw, wil->boot_config); + + if (wil->boot_config == WIL_BOOT_VANILLA) + /* Assuming not SPI boot (currently not supported) */ + goto out; + + hw_section_done = otp_hw & BIT_OTP_HW_SECTION_DONE_TALYN_MB; + delay = 0; + + while (!hw_section_done) { + msleep(RST_DELAY); + + otp_hw = wil_r(wil, RGF_USER_OTP_HW_RD_MACHINE_1); + hw_section_done = otp_hw & BIT_OTP_HW_SECTION_DONE_TALYN_MB; + + if (delay++ > RST_COUNT) { + wil_err(wil, "TO waiting for hw_section_done\n"); + return -ETIME; + } + } + + wil_dbg_misc(wil, "HW section done in %d ms\n", delay * RST_DELAY); + + otp_qc_secured = wil_r(wil, RGF_OTP_QC_SECURED); + wil->secured_boot = otp_qc_secured & BIT_BOOT_FROM_ROM ? 1 : 0; + wil_dbg_misc(wil, "secured boot is %sabled\n", + wil->secured_boot ? "en" : "dis"); + +out: + wil_dbg_misc(wil, "Reset completed\n"); + + return 0; +} + +static int wil_target_reset(struct wil6210_priv *wil, int no_flash) +{ + u32 x; + int rc; + wil_dbg_misc(wil, "Resetting \"%s\"...\n", wil->hw_name); /* Clear MAC link up */ @@ -885,34 +1040,12 @@ static int wil_target_reset(struct wil6210_priv *wil, int no_flash) wil_w(wil, RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0); - /* wait until device ready. typical time is 20..80 msec */ - if (no_flash) - do { - msleep(RST_DELAY); - x = wil_r(wil, USER_EXT_USER_PMU_3); - if (delay++ > RST_COUNT) { - wil_err(wil, "Reset not completed, PMU_3 0x%08x\n", - x); - return -ETIME; - } - } while ((x & BIT_PMU_DEVICE_RDY) == 0); + if (wil->hw_version == HW_VER_TALYN_MB) + rc = wil_wait_device_ready_talyn_mb(wil); else - do { - msleep(RST_DELAY); - x = wil_r(wil, RGF_USER_BL + - offsetof(struct bl_dedicated_registers_v0, - boot_loader_ready)); - if (x1 != x) { - wil_dbg_misc(wil, "BL.ready 0x%08x => 0x%08x\n", - x1, x); - x1 = x; - } - if (delay++ > RST_COUNT) { - wil_err(wil, "Reset not completed, bl.ready 0x%08x\n", - x); - return -ETIME; - } - } while (x != BL_READY); + rc = wil_wait_device_ready(wil, no_flash); + if (rc) + return rc; wil_c(wil, RGF_USER_CLKS_CTL_0, BIT_USER_CLKS_RST_PWGD); @@ -920,7 +1053,7 @@ static int wil_target_reset(struct wil6210_priv *wil, int no_flash) wil_s(wil, RGF_DMA_OFUL_NID_0, BIT_DMA_OFUL_NID_0_RX_EXT_TR_EN | BIT_DMA_OFUL_NID_0_RX_EXT_A3_SRC); - if (no_flash) { + if (wil->hw_version < HW_VER_TALYN_MB && no_flash) { /* Reset OTP HW vectors to fit 40MHz */ wil_w(wil, RGF_USER_XPM_IFC_RD_TIME1, 0x60001); wil_w(wil, RGF_USER_XPM_IFC_RD_TIME2, 0x20027); @@ -935,7 +1068,6 @@ static int wil_target_reset(struct wil6210_priv *wil, int no_flash) wil_w(wil, RGF_USER_XPM_RD_DOUT_SAMPLE_TIME, 0x57); } - wil_dbg_misc(wil, "Reset completed in %d ms\n", delay * RST_DELAY); return 0; } @@ -1383,6 +1515,11 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw) wil_info(wil, "Use firmware <%s> + board <%s>\n", wil->wil_fw_name, WIL_BOARD_FILE_NAME); + if (wil->secured_boot) { + wil_err(wil, "secured boot is not supported\n"); + return -ENOTSUPP; + } + if (!no_flash) wil_bl_prepare_halt(wil); diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index c9308229250d..fb7c44e366e3 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -213,7 +213,9 @@ struct RGF_ICR { #define RGF_USER_SPARROW_M_4 (0x880c50) /* Sparrow */ #define BIT_SPARROW_M_4_SEL_SLEEP_OR_REF BIT(2) #define RGF_USER_OTP_HW_RD_MACHINE_1 (0x880ce0) - #define BIT_NO_FLASH_INDICATION BIT(8) + #define BIT_OTP_SIGNATURE_ERR_TALYN_MB BIT(0) + #define BIT_OTP_HW_SECTION_DONE_TALYN_MB BIT(2) + #define BIT_NO_FLASH_INDICATION BIT(8) #define RGF_USER_XPM_IFC_RD_TIME1 (0x880cec) #define RGF_USER_XPM_IFC_RD_TIME2 (0x880cf0) #define RGF_USER_XPM_IFC_RD_TIME3 (0x880cf4) @@ -315,6 +317,9 @@ struct RGF_ICR { #define RGF_CAF_PLL_LOCK_STATUS (0x88afec) #define BIT_CAF_OSC_DIG_XTAL_STABLE BIT(0) +#define RGF_OTP_QC_SECURED (0x8a0038) + #define BIT_BOOT_FROM_ROM BIT(31) + /* eDMA */ #define RGF_INT_COUNT_ON_SPECIAL_EVT (0x8b62d8) @@ -986,6 +991,9 @@ struct wil6210_priv { u32 rgf_fw_assert_code_addr; u32 rgf_ucode_assert_code_addr; u32 iccm_base; + + bool secured_boot; + u8 boot_config; }; #define wil_to_wiphy(i) (i->wiphy) -- GitLab From 6e60353f0550c56572d82d92f6342d70a5603e92 Mon Sep 17 00:00:00 2001 From: Maya Erez Date: Tue, 3 Apr 2018 10:22:04 +0300 Subject: [PATCH 0136/1635] wil6210: support Talyn specific FW file FW file name for Talyn device is different from the default name. This patch searches for Talyn specific FW file name and fallback to the default FW file in case it is not present. Change-Id: I85308cc592e29ea44f4adc94b8d35444a7041ed3 Signed-off-by: Maya Erez --- drivers/net/wireless/ath/wil6210/pcie_bus.c | 8 ++++++++ drivers/net/wireless/ath/wil6210/wil6210.h | 3 +++ 2 files changed, 11 insertions(+) diff --git a/drivers/net/wireless/ath/wil6210/pcie_bus.c b/drivers/net/wireless/ath/wil6210/pcie_bus.c index 128f4b73adc9..f534e5e82d06 100644 --- a/drivers/net/wireless/ath/wil6210/pcie_bus.c +++ b/drivers/net/wireless/ath/wil6210/pcie_bus.c @@ -101,6 +101,10 @@ int wil_set_capabilities(struct wil6210_priv *wil) if (wil_r(wil, RGF_USER_OTP_HW_RD_MACHINE_1) & BIT_NO_FLASH_INDICATION) set_bit(hw_capa_no_flash, wil->hw_capa); + wil_fw_name = ftm_mode ? WIL_FW_NAME_FTM_TALYN : + WIL_FW_NAME_TALYN; + if (wil_fw_verify_file_exists(wil, wil_fw_name)) + wil->wil_fw_name = wil_fw_name; break; case JTAG_DEV_ID_TALYN_MB: wil->hw_name = "Talyn-MB"; @@ -111,6 +115,10 @@ int wil_set_capabilities(struct wil6210_priv *wil) wil->rgf_ucode_assert_code_addr = TALYN_RGF_UCODE_ASSERT_CODE; set_bit(hw_capa_no_flash, wil->hw_capa); wil->use_enhanced_dma_hw = use_enhanced_dma_hw; + wil_fw_name = ftm_mode ? WIL_FW_NAME_FTM_TALYN : + WIL_FW_NAME_TALYN; + if (wil_fw_verify_file_exists(wil, wil_fw_name)) + wil->wil_fw_name = wil_fw_name; break; default: wil_err(wil, "Unknown board hardware, chip_id 0x%08x, chip_revision 0x%08x\n", diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index fb7c44e366e3..b9014d20b933 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -53,6 +53,9 @@ union wil_tx_desc; #define WIL_FW_NAME_SPARROW_PLUS "wil6210_sparrow_plus.fw" #define WIL_FW_NAME_FTM_SPARROW_PLUS "wil6210_sparrow_plus_ftm.fw" +#define WIL_FW_NAME_TALYN "wil6436.fw" +#define WIL_FW_NAME_FTM_TALYN "wil6436_ftm.fw" + #define WIL_BOARD_FILE_NAME "wil6210.brd" /* board & radio parameters */ #define WIL_DEFAULT_BUS_REQUEST_KBPS 128000 /* ~1Gbps */ -- GitLab From bc6ea8b7fc1eb29a754e7fc77d66d07947776bce Mon Sep 17 00:00:00 2001 From: Sayali Lokhande Date: Wed, 11 Apr 2018 16:24:42 +0530 Subject: [PATCH 0137/1635] mmc: host: Kconfig: Enable cmdq config Add kconfig option to enable eMMC CMDQ support on msm-4.14. Change-Id: Ib9ee789c11d7a48ebb5c2ecc9734c59ea584b46a Signed-off-by: Sayali Lokhande --- drivers/mmc/host/Kconfig | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig index acbe24be3e5c..09f6823909df 100644 --- a/drivers/mmc/host/Kconfig +++ b/drivers/mmc/host/Kconfig @@ -843,6 +843,19 @@ config MMC_SUNXI This selects support for the SD/MMC Host Controller on Allwinner sunxi SoCs. +config MMC_CQ_HCI + tristate "Command Queue Support" + depends on HAS_DMA + help + This selects the Command Queue Host Controller Interface (CQHCI) + support present in host controllers of Qualcomm Technologies, Inc + amongst others. + This controller supports eMMC devices with command queue support. + + If you have a controller with this interface, say Y or M here. + + If unsure, say N. + config MMC_TOSHIBA_PCI tristate "Toshiba Type A SD/MMC Card Interface Driver" depends on PCI -- GitLab From 6c8198936b5d98d11d65eeef5dd41511088c5e60 Mon Sep 17 00:00:00 2001 From: Mukesh Kumar Savaliya Date: Wed, 11 Apr 2018 20:09:22 +0530 Subject: [PATCH 0138/1635] serial: msm_serial_hs: Remove unwanted header file inclusion Remove unused header file inclusion. Change-Id: Ic68dd1d1eabc35568af57c90fe36f098f1ef7e05 Signed-off-by: Mukesh Kumar Savaliya --- drivers/tty/serial/msm_serial_hs.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/tty/serial/msm_serial_hs.c b/drivers/tty/serial/msm_serial_hs.c index 93b1d9538649..4346ed2c1c4a 100644 --- a/drivers/tty/serial/msm_serial_hs.c +++ b/drivers/tty/serial/msm_serial_hs.c @@ -53,7 +53,6 @@ #include #include #include -#include #include #include #include -- GitLab From cddb61455c94c0063a35bfa327fd180f698b810c Mon Sep 17 00:00:00 2001 From: Siddartha Mohanadoss Date: Wed, 4 Apr 2018 13:26:21 -0700 Subject: [PATCH 0139/1635] iio: adc: Support reading SMB thermistor Add scaling support for reading SMB1390 thermistor from VADC_USR peripheral. Change-Id: I50e6fb54c897d17d648a34c709119d74471753d7 Signed-off-by: Siddartha Mohanadoss --- drivers/iio/adc/qcom-spmi-adc5.c | 8 +++++--- drivers/iio/adc/qcom-vadc-common.c | 32 ++++++++++++++++++++++++++++++ drivers/iio/adc/qcom-vadc-common.h | 5 +++++ 3 files changed, 42 insertions(+), 3 deletions(-) diff --git a/drivers/iio/adc/qcom-spmi-adc5.c b/drivers/iio/adc/qcom-spmi-adc5.c index 309b4c8f5c03..fbf948c245f9 100644 --- a/drivers/iio/adc/qcom-spmi-adc5.c +++ b/drivers/iio/adc/qcom-spmi-adc5.c @@ -529,11 +529,11 @@ static const struct adc_channels adc_chans_pmic5[ADC_MAX_CHANNEL] = { SCALE_HW_CALIB_DEFAULT) [ADC_XO_THERM_PU2] = ADC_CHAN_TEMP("xo_therm", 1, SCALE_HW_CALIB_XOTHERM) - [ADC_AMUX_THM1_PU2] = ADC_CHAN_TEMP("amux_thm1", 1, + [ADC_AMUX_THM1_PU2] = ADC_CHAN_TEMP("amux_thm1_pu2", 1, SCALE_HW_CALIB_THERM_100K_PULLUP) - [ADC_AMUX_THM2_PU2] = ADC_CHAN_TEMP("amux_thm2", 1, + [ADC_AMUX_THM2_PU2] = ADC_CHAN_TEMP("amux_thm2_pu2", 1, SCALE_HW_CALIB_THERM_100K_PULLUP) - [ADC_AMUX_THM3_PU2] = ADC_CHAN_TEMP("amux_thm3", 1, + [ADC_AMUX_THM3_PU2] = ADC_CHAN_TEMP("amux_thm3_pu2", 1, SCALE_HW_CALIB_THERM_100K_PULLUP) [ADC_INT_EXT_ISENSE_VBAT_VDATA] = ADC_CHAN_POWER("int_ext_isense", 1, SCALE_HW_CALIB_CUR) @@ -541,6 +541,8 @@ static const struct adc_channels adc_chans_pmic5[ADC_MAX_CHANNEL] = { SCALE_HW_CALIB_CUR) [ADC_PARALLEL_ISENSE_VBAT_VDATA] = ADC_CHAN_POWER("parallel_isense", 1, SCALE_HW_CALIB_CUR) + [ADC_AMUX_THM2] = ADC_CHAN_TEMP("amux_thm2", 1, + SCALE_HW_CALIB_PM5_SMB_TEMP) }; static const struct adc_channels adc_chans_rev2[ADC_MAX_CHANNEL] = { diff --git a/drivers/iio/adc/qcom-vadc-common.c b/drivers/iio/adc/qcom-vadc-common.c index 6481a7a5a551..7a370350cf0c 100644 --- a/drivers/iio/adc/qcom-vadc-common.c +++ b/drivers/iio/adc/qcom-vadc-common.c @@ -306,6 +306,35 @@ static int qcom_vadc_scale_hw_calib_die_temp( return 0; } +static int qcom_vadc_scale_hw_smb_temp( + const struct vadc_prescale_ratio *prescale, + const struct adc_data *data, + u16 adc_code, int *result_mdec) +{ + s64 voltage = 0, adc_vdd_ref_mv = 1875; + u64 temp; + + if (adc_code > VADC5_MAX_CODE) + adc_code = 0; + + /* (ADC code * vref_vadc (1.875V)) / full_scale_code */ + voltage = (s64) adc_code * adc_vdd_ref_mv * 1000; + voltage = div64_s64(voltage, data->full_scale_code_volt); + if (voltage > 0) { + temp = voltage * prescale->den; + temp *= 100; + do_div(temp, prescale->num * PMIC5_SMB_TEMP_SCALE_FACTOR); + voltage = temp; + } else { + voltage = 0; + } + + voltage = PMIC5_SMB_TEMP_CONSTANT - voltage; + *result_mdec = voltage; + + return 0; +} + static int qcom_vadc_scale_hw_chg5_temp( const struct vadc_prescale_ratio *prescale, const struct adc_data *data, @@ -412,6 +441,9 @@ int qcom_vadc_hw_scale(enum vadc_scale_fn_type scaletype, case SCALE_HW_CALIB_PM5_CHG_TEMP: return qcom_vadc_scale_hw_chg5_temp(prescale, data, adc_code, result); + case SCALE_HW_CALIB_PM5_SMB_TEMP: + return qcom_vadc_scale_hw_smb_temp(prescale, data, + adc_code, result); default: return -EINVAL; } diff --git a/drivers/iio/adc/qcom-vadc-common.h b/drivers/iio/adc/qcom-vadc-common.h index 1a636ab5b964..7391bcddfaf5 100644 --- a/drivers/iio/adc/qcom-vadc-common.h +++ b/drivers/iio/adc/qcom-vadc-common.h @@ -40,6 +40,8 @@ #define KELVINMIL_CELSIUSMIL 273150 #define PMIC5_CHG_TEMP_SCALE_FACTOR 377500 +#define PMIC5_SMB_TEMP_CONSTANT 419400 +#define PMIC5_SMB_TEMP_SCALE_FACTOR 356 #define PMI_CHG_SCALE_1 -138890 #define PMI_CHG_SCALE_2 391750000000LL @@ -114,6 +116,8 @@ struct vadc_prescale_ratio { * SCALE_HW_CALIB_CUR: Returns result in uA for PMIC5. * SCALE_HW_CALIB_PM5_CHG_TEMP: Returns result in millidegrees for PMIC5 * charger temperature. + * SCALE_HW_CALIB_PM5_SMB_TEMP: Returns result in millidegrees for PMIC5 + * SMB1390 temperature. */ enum vadc_scale_fn_type { SCALE_DEFAULT = 0, @@ -127,6 +131,7 @@ enum vadc_scale_fn_type { SCALE_HW_CALIB_PMIC_THERM, SCALE_HW_CALIB_CUR, SCALE_HW_CALIB_PM5_CHG_TEMP, + SCALE_HW_CALIB_PM5_SMB_TEMP, }; struct adc_data { -- GitLab From 2fb10aa76b9b688bf5d915859a59f19cba361684 Mon Sep 17 00:00:00 2001 From: Jeevan Shriram Date: Sat, 31 Mar 2018 16:13:46 -0700 Subject: [PATCH 0140/1635] defconfig: Enable Secure Channel Manager(SCM) for sdmshrike Enable Secure Channel Manager(SCM) for sdmshrike to communicate with secure world. Change-Id: If369f7070f391e0950b9e8de600baa1ecfd31958 Signed-off-by: Jeevan Shriram --- arch/arm64/configs/sdmshrike-perf_defconfig | 1 + arch/arm64/configs/sdmshrike_defconfig | 1 + 2 files changed, 2 insertions(+) diff --git a/arch/arm64/configs/sdmshrike-perf_defconfig b/arch/arm64/configs/sdmshrike-perf_defconfig index 696d6e0dff12..61190bf3071d 100644 --- a/arch/arm64/configs/sdmshrike-perf_defconfig +++ b/arch/arm64/configs/sdmshrike-perf_defconfig @@ -360,6 +360,7 @@ CONFIG_QCOM_LLCC=y CONFIG_QCOM_SDMSHRIKE_LLCC=y CONFIG_QCOM_QMI_HELPERS=y CONFIG_QCOM_SMEM=y +CONFIG_QCOM_SCM=y CONFIG_QCOM_SMP2P=y CONFIG_QCOM_SMSM=y CONFIG_QCOM_BUS_SCALING=y diff --git a/arch/arm64/configs/sdmshrike_defconfig b/arch/arm64/configs/sdmshrike_defconfig index 00d4b73cfafa..41b2da335b88 100644 --- a/arch/arm64/configs/sdmshrike_defconfig +++ b/arch/arm64/configs/sdmshrike_defconfig @@ -373,6 +373,7 @@ CONFIG_QCOM_LLCC=y CONFIG_QCOM_SDMSHRIKE_LLCC=y CONFIG_QCOM_QMI_HELPERS=y CONFIG_QCOM_SMEM=y +CONFIG_QCOM_SCM=y CONFIG_QCOM_SMP2P=y CONFIG_QCOM_SMSM=y CONFIG_QCOM_BUS_SCALING=y -- GitLab From b43008436695d75a7345f213b349b0733c24b66b Mon Sep 17 00:00:00 2001 From: Jeevan Shriram Date: Tue, 10 Apr 2018 18:51:31 -0700 Subject: [PATCH 0141/1635] ARM: dts: msm: Add LPASS PIL node for sdmshrike Add LPASS PIL node for loading adsp firmware, authenticate and bring out of reset on sdmshrike target. Change-Id: I720702f4ab666b6478612c5aa1eaf2f216271364 Signed-off-by: Jeevan Shriram --- arch/arm64/boot/dts/qcom/sdmshrike.dtsi | 37 +++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sdmshrike.dtsi b/arch/arm64/boot/dts/qcom/sdmshrike.dtsi index 95f8062feaa1..9e7315c49540 100644 --- a/arch/arm64/boot/dts/qcom/sdmshrike.dtsi +++ b/arch/arm64/boot/dts/qcom/sdmshrike.dtsi @@ -874,6 +874,43 @@ reg-names = "rmtfs"; qcom,client-id = <0x00000001>; }; + + qcom,lpass@17300000 { + compatible = "qcom,pil-tz-generic"; + reg = <0x17300000 0x00100>; + + vdd_cx-supply = <&pm855_2_s3_level>; + qcom,proxy-reg-names = "vdd_cx"; + + clocks = <&clock_rpmh RPMH_CXO_CLK>; + clock-names = "xo"; + qcom,proxy-clock-names = "xo"; + + qcom,pas-id = <1>; + qcom,proxy-timeout-ms = <10000>; + qcom,smem-id = <423>; + qcom,sysmon-id = <1>; + qcom,ssctl-instance-id = <0x14>; + qcom,firmware-name = "adsp"; + memory-region = <&pil_adsp_mem>; + + /* Inputs from lpass */ + interrupts-extended = <&intc 0 162 1>, + <&adsp_smp2p_in 2 0>, + <&adsp_smp2p_in 1 0>, + <&adsp_smp2p_in 3 0>, + <&adsp_smp2p_in 0 0>; + + interrupt-names = "qcom,wdog", + "qcom,err-fatal", + "qcom,proxy-unvote", + "qcom,err-ready", + "qcom,stop-ack"; + + /* Outputs from lpass */ + qcom,smem-states = <&adsp_smp2p_out 0>; + qcom,smem-state-names = "qcom,force-stop"; + }; }; &emac_gdsc { -- GitLab From dba2effede3ca5f2b6b0325ada9d0b21f9339887 Mon Sep 17 00:00:00 2001 From: Jeevan Shriram Date: Tue, 10 Apr 2018 19:02:34 -0700 Subject: [PATCH 0142/1635] defconfig: Enable PIL driver on sdmshrike target Enable Peripheral Image Loader (PIL) for loading firmware image to bring out of reset on sdmshrike target. Change-Id: I4edd234f27a12bf393e21f01acdc31947fb91260 Signed-off-by: Jeevan Shriram --- arch/arm64/configs/sdmshrike-perf_defconfig | 3 +++ arch/arm64/configs/sdmshrike_defconfig | 3 +++ 2 files changed, 6 insertions(+) diff --git a/arch/arm64/configs/sdmshrike-perf_defconfig b/arch/arm64/configs/sdmshrike-perf_defconfig index 61190bf3071d..c7f059738252 100644 --- a/arch/arm64/configs/sdmshrike-perf_defconfig +++ b/arch/arm64/configs/sdmshrike-perf_defconfig @@ -363,6 +363,9 @@ CONFIG_QCOM_SMEM=y CONFIG_QCOM_SCM=y CONFIG_QCOM_SMP2P=y CONFIG_QCOM_SMSM=y +CONFIG_MSM_SUBSYSTEM_RESTART=y +CONFIG_MSM_PIL=y +CONFIG_MSM_PIL_SSR_GENERIC=y CONFIG_QCOM_BUS_SCALING=y CONFIG_QCOM_BUS_CONFIG_RPMH=y CONFIG_QCOM_COMMAND_DB=y diff --git a/arch/arm64/configs/sdmshrike_defconfig b/arch/arm64/configs/sdmshrike_defconfig index 41b2da335b88..58c7a04bdbc1 100644 --- a/arch/arm64/configs/sdmshrike_defconfig +++ b/arch/arm64/configs/sdmshrike_defconfig @@ -376,6 +376,9 @@ CONFIG_QCOM_SMEM=y CONFIG_QCOM_SCM=y CONFIG_QCOM_SMP2P=y CONFIG_QCOM_SMSM=y +CONFIG_MSM_SUBSYSTEM_RESTART=y +CONFIG_MSM_PIL=y +CONFIG_MSM_PIL_SSR_GENERIC=y CONFIG_QCOM_BUS_SCALING=y CONFIG_QCOM_BUS_CONFIG_RPMH=y CONFIG_QCOM_COMMAND_DB=y -- GitLab From b459a519918e5baf74821d1081a55d9caba513e3 Mon Sep 17 00:00:00 2001 From: Jeevan Shriram Date: Sat, 31 Mar 2018 15:22:15 -0700 Subject: [PATCH 0143/1635] ARM: dts: msm: Add watchdog dt node for sdmshrike Add watchdog bark and bite thresholds used to configure watchdog timer on sdmshrike. If the watchdog is not pet at regular specified intervals, the system is assumed to be un-responsive and need to be reset. Change-Id: I57656152a898e3bf8c3bb2e57d85ce93109fd01a Signed-off-by: Jeevan Shriram --- arch/arm64/boot/dts/qcom/sdmshrike.dtsi | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sdmshrike.dtsi b/arch/arm64/boot/dts/qcom/sdmshrike.dtsi index 9e7315c49540..e209a0520ff3 100644 --- a/arch/arm64/boot/dts/qcom/sdmshrike.dtsi +++ b/arch/arm64/boot/dts/qcom/sdmshrike.dtsi @@ -911,6 +911,17 @@ qcom,smem-states = <&adsp_smp2p_out 0>; qcom,smem-state-names = "qcom,force-stop"; }; + + wdog: qcom,wdt@17c10000 { + compatible = "qcom,msm-watchdog"; + reg = <0x17c10000 0x1000>; + reg-names = "wdt-base"; + interrupts = <0 0 0>, <0 1 0>; + qcom,bark-time = <11000>; + qcom,pet-time = <9360>; + qcom,ipi-ping; + qcom,wakeup-enable; + }; }; &emac_gdsc { -- GitLab From 560b3c70edf996e334cae0202bb0fddc13285ead Mon Sep 17 00:00:00 2001 From: Jeevan Shriram Date: Sat, 31 Mar 2018 15:37:00 -0700 Subject: [PATCH 0144/1635] defconfig: Enable WATCHDOG config for sdmshrike Enable WATCHDOG config to detect and reset the system if the watchdog is not pet within the specified intervals. Change-Id: Idf17998a3766e355ce77fbf1096dda20dc900ad7 Signed-off-by: Jeevan Shriram --- arch/arm64/configs/sdmshrike-perf_defconfig | 2 ++ arch/arm64/configs/sdmshrike_defconfig | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/arch/arm64/configs/sdmshrike-perf_defconfig b/arch/arm64/configs/sdmshrike-perf_defconfig index c7f059738252..637d4e0b52b8 100644 --- a/arch/arm64/configs/sdmshrike-perf_defconfig +++ b/arch/arm64/configs/sdmshrike-perf_defconfig @@ -361,6 +361,8 @@ CONFIG_QCOM_SDMSHRIKE_LLCC=y CONFIG_QCOM_QMI_HELPERS=y CONFIG_QCOM_SMEM=y CONFIG_QCOM_SCM=y +CONFIG_QCOM_WATCHDOG_V2=y +CONFIG_QCOM_FORCE_WDOG_BITE_ON_PANIC=y CONFIG_QCOM_SMP2P=y CONFIG_QCOM_SMSM=y CONFIG_MSM_SUBSYSTEM_RESTART=y diff --git a/arch/arm64/configs/sdmshrike_defconfig b/arch/arm64/configs/sdmshrike_defconfig index 58c7a04bdbc1..9f5abffabb9b 100644 --- a/arch/arm64/configs/sdmshrike_defconfig +++ b/arch/arm64/configs/sdmshrike_defconfig @@ -374,6 +374,9 @@ CONFIG_QCOM_SDMSHRIKE_LLCC=y CONFIG_QCOM_QMI_HELPERS=y CONFIG_QCOM_SMEM=y CONFIG_QCOM_SCM=y +CONFIG_QCOM_WATCHDOG_V2=y +CONFIG_QCOM_FORCE_WDOG_BITE_ON_PANIC=y +CONFIG_QCOM_WDOG_IPI_ENABLE=y CONFIG_QCOM_SMP2P=y CONFIG_QCOM_SMSM=y CONFIG_MSM_SUBSYSTEM_RESTART=y @@ -439,6 +442,7 @@ CONFIG_SCHEDSTATS=y CONFIG_SCHED_STACK_END_CHECK=y # CONFIG_DEBUG_PREEMPT is not set CONFIG_DEBUG_SPINLOCK=y +CONFIG_DEBUG_SPINLOCK_PANIC_ON_BUG=y CONFIG_DEBUG_MUTEXES=y CONFIG_DEBUG_ATOMIC_SLEEP=y CONFIG_DEBUG_LIST=y -- GitLab From 72c5f071558ed396a2fd49c58010b549fa405384 Mon Sep 17 00:00:00 2001 From: Kyle Yan Date: Fri, 4 Aug 2017 16:14:21 -0700 Subject: [PATCH 0145/1635] ARM: dts: msm: Update the revision id for v1 chips on SM8150 Update revision id on SM8150 to 0x10000. Change-Id: Ic10360e02483ed2bc028315ec11eb51437925c9a Signed-off-by: Kyle Yan Signed-off-by: Runmin Wang Signed-off-by: Isaac J. Manjarres --- arch/arm64/boot/dts/qcom/sm8150.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/sm8150.dtsi b/arch/arm64/boot/dts/qcom/sm8150.dtsi index 8e6abaca41ae..ac8b5517bca0 100644 --- a/arch/arm64/boot/dts/qcom/sm8150.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150.dtsi @@ -32,7 +32,7 @@ model = "Qualcomm Technologies, Inc. SM8150"; compatible = "qcom,sm8150"; qcom,msm-name = "SM8150"; - qcom,msm-id = <339 0x0>; + qcom,msm-id = <339 0x10000>; interrupt-parent = <&pdc>; aliases { -- GitLab From a9125e81fbfa406965c82582461a3bb65cfb0ac7 Mon Sep 17 00:00:00 2001 From: Lokesh Batra Date: Thu, 29 Mar 2018 17:37:34 -0700 Subject: [PATCH 0146/1635] ARM: dts: msm: Enable GPU per-process pagetables for SM8150 Enable per-process pagetables feature for KGSL on SM8150. Change-Id: Ie53c556e4e7d70bc9e858f15b5951652b8709f02 Signed-off-by: Lokesh Batra --- arch/arm64/boot/dts/qcom/msm-arm-smmu-sm8150.dtsi | 1 + arch/arm64/boot/dts/qcom/sm8150-gpu.dtsi | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/msm-arm-smmu-sm8150.dtsi b/arch/arm64/boot/dts/qcom/msm-arm-smmu-sm8150.dtsi index be74bea8614a..1af74823cc0b 100644 --- a/arch/arm64/boot/dts/qcom/msm-arm-smmu-sm8150.dtsi +++ b/arch/arm64/boot/dts/qcom/msm-arm-smmu-sm8150.dtsi @@ -20,6 +20,7 @@ <0x2CC2000 0x20>; reg-names = "base", "tcu-base"; #iommu-cells = <2>; + qcom,dynamic; qcom,skip-init; qcom,use-3-lvl-tables; qcom,no-asid-retention; diff --git a/arch/arm64/boot/dts/qcom/sm8150-gpu.dtsi b/arch/arm64/boot/dts/qcom/sm8150-gpu.dtsi index d4e541997c65..19ab4ac17ff2 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-gpu.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-gpu.dtsi @@ -286,7 +286,6 @@ clock-names = "iface_clk", "mem_clk", "mem_iface_clk"; qcom,secure_align_mask = <0xfff>; - qcom,global_pt; qcom,retention; qcom,hyp_secure_alloc; -- GitLab From 1a7eeed7c6802b2352d4c034b2c0045229ab7d6f Mon Sep 17 00:00:00 2001 From: Shivendra Kakrania Date: Mon, 9 Apr 2018 10:25:44 -0700 Subject: [PATCH 0147/1635] ARM: dts: msm: Update video sid masks for SM8150 Video sid masks for non-secure & secure nonpixel iommus have changed. So updating video sid masks accordingly. Change-Id: I4cb83ed75e1db3eba42d61a8f4e543bfdd89667a Signed-off-by: Shivendra Kakrania --- arch/arm64/boot/dts/qcom/sm8150-vidc.dtsi | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sm8150-vidc.dtsi b/arch/arm64/boot/dts/qcom/sm8150-vidc.dtsi index bc406ad1a757..03b5fb009745 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-vidc.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-vidc.dtsi @@ -88,8 +88,7 @@ compatible = "qcom,msm-vidc,context-bank"; label = "venus_ns"; iommus = - <&apps_smmu 0x1300 0x20>, - <&apps_smmu 0x1340 0x0>; + <&apps_smmu 0x1300 0x60>; buffer-types = <0xfff>; virtual-addr-pool = <0x70800000 0x6f800000>; }; @@ -118,8 +117,7 @@ compatible = "qcom,msm-vidc,context-bank"; label = "venus_sec_non_pixel"; iommus = - <&apps_smmu 0x1304 0x20>, - <&apps_smmu 0x1344 0x0>; + <&apps_smmu 0x1304 0x60>; buffer-types = <0x480>; virtual-addr-pool = <0x1000000 0x24800000>; qcom,secure-context-bank; -- GitLab From 3126a5769094a26b6038a2fafd3367c0fb2a12fe Mon Sep 17 00:00:00 2001 From: Subash Abhinov Kasiviswanathan Date: Wed, 15 Apr 2015 14:59:27 -0600 Subject: [PATCH 0148/1635] net: udp: Adjust UDP socket state for encapsulation sockets UDP IPv4 encapsulation sockets will have their state printed as 0xF0 binary ORed with the actual state such that they can be distinguished from regular UDP sockets in /proc/net/udp. CRs-Fixed: 2156182 Change-Id: I240ab1526a4280e5e996d9577a904581684fc84a Signed-off-by: Subash Abhinov Kasiviswanathan --- net/ipv4/udp.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index c79fa6f6b758..6a3cd57e1971 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -2708,14 +2708,19 @@ static void udp4_format_sock(struct sock *sp, struct seq_file *f, int bucket) { struct inet_sock *inet = inet_sk(sp); + struct udp_sock *up = udp_sk(sp); __be32 dest = inet->inet_daddr; __be32 src = inet->inet_rcv_saddr; __u16 destp = ntohs(inet->inet_dport); __u16 srcp = ntohs(inet->inet_sport); + __u8 state = sp->sk_state; + + if (up->encap_rcv) + state |= 0xF0; seq_printf(f, "%5d: %08X:%04X %08X:%04X" " %02X %08X:%08X %02X:%08lX %08X %5u %8d %lu %d %pK %d", - bucket, src, srcp, dest, destp, sp->sk_state, + bucket, src, srcp, dest, destp, state, sk_wmem_alloc_get(sp), sk_rmem_alloc_get(sp), 0, 0L, 0, -- GitLab From 32213322071ab5ac6eb4129bc9bb129c74852ee2 Mon Sep 17 00:00:00 2001 From: Subash Abhinov Kasiviswanathan Date: Fri, 5 Jun 2015 13:23:01 -0600 Subject: [PATCH 0149/1635] net: Indicate whether a socket is a transparent socket Modify the printout functions for IPv4-TCP, IPv4-UDP, IPv6-TCP, IPv6-UDP, such that the state for the socket is printed as state = state | 0x80. The actual socket state is unmodified. This change is required for the user space to determine whether a socket is a transparent socket, and to determine if the socket holder intends to consume packets locally or to forward them to an external processor. CRs-Fixed: 2156182 Change-Id: I2ca403b4c2c74e7ddcdbda53e4ba43613bae9c42 Signed-off-by: Subash Abhinov Kasiviswanathan --- net/ipv4/tcp_ipv4.c | 6 +++++- net/ipv4/udp.c | 2 ++ net/ipv6/datagram.c | 7 ++++++- net/ipv6/tcp_ipv6.c | 6 +++++- 4 files changed, 18 insertions(+), 3 deletions(-) diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index cab4b935e474..32015d3cf69d 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -2254,6 +2254,7 @@ static void get_tcp4_sock(struct sock *sk, struct seq_file *f, int i) __be32 src = inet->inet_rcv_saddr; __u16 destp = ntohs(inet->inet_dport); __u16 srcp = ntohs(inet->inet_sport); + __u8 seq_state = sk->sk_state; int rx_queue; int state; @@ -2273,6 +2274,9 @@ static void get_tcp4_sock(struct sock *sk, struct seq_file *f, int i) timer_expires = jiffies; } + if (inet->transparent) + seq_state |= 0x80; + state = sk_state_load(sk); if (state == TCP_LISTEN) rx_queue = sk->sk_ack_backlog; @@ -2284,7 +2288,7 @@ static void get_tcp4_sock(struct sock *sk, struct seq_file *f, int i) seq_printf(f, "%4d: %08X:%04X %08X:%04X %02X %08X:%08X %02X:%08lX " "%08X %5u %8d %lu %d %pK %lu %lu %u %u %d", - i, src, srcp, dest, destp, state, + i, src, srcp, dest, destp, seq_state, tp->write_seq - tp->snd_una, rx_queue, timer_active, diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 6a3cd57e1971..e09502da6db5 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -2717,6 +2717,8 @@ static void udp4_format_sock(struct sock *sp, struct seq_file *f, if (up->encap_rcv) state |= 0xF0; + else if (inet->transparent) + state |= 0x80; seq_printf(f, "%5d: %08X:%04X %08X:%04X" " %02X %08X:%08X %02X:%08lX %08X %5u %8d %lu %d %pK %d", diff --git a/net/ipv6/datagram.c b/net/ipv6/datagram.c index 287112da3c06..3c3e73fbc88e 100644 --- a/net/ipv6/datagram.c +++ b/net/ipv6/datagram.c @@ -1030,9 +1030,14 @@ void ip6_dgram_sock_seq_show(struct seq_file *seq, struct sock *sp, __u16 srcp, __u16 destp, int bucket) { const struct in6_addr *dest, *src; + __u8 state = sp->sk_state; dest = &sp->sk_v6_daddr; src = &sp->sk_v6_rcv_saddr; + + if (inet_sk(sp) && inet_sk(sp)->transparent) + state |= 0x80; + seq_printf(seq, "%5d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X " "%02X %08X:%08X %02X:%08lX %08X %5u %8d %lu %d %pK %d\n", @@ -1041,7 +1046,7 @@ void ip6_dgram_sock_seq_show(struct seq_file *seq, struct sock *sp, src->s6_addr32[2], src->s6_addr32[3], srcp, dest->s6_addr32[0], dest->s6_addr32[1], dest->s6_addr32[2], dest->s6_addr32[3], destp, - sp->sk_state, + state, sk_wmem_alloc_get(sp), sk_rmem_alloc_get(sp), 0, 0L, 0, diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 237cc6187c5a..99f27598d3c8 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -1766,6 +1766,7 @@ static void get_tcp6_sock(struct seq_file *seq, struct sock *sp, int i) const struct fastopen_queue *fastopenq = &icsk->icsk_accept_queue.fastopenq; int rx_queue; int state; + __u8 state_seq = sp->sk_state; dest = &sp->sk_v6_daddr; src = &sp->sk_v6_rcv_saddr; @@ -1797,6 +1798,9 @@ static void get_tcp6_sock(struct seq_file *seq, struct sock *sp, int i) */ rx_queue = max_t(int, tp->rcv_nxt - tp->copied_seq, 0); + if (inet->transparent) + state_seq |= 0x80; + seq_printf(seq, "%4d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X " "%02X %08X:%08X %02X:%08lX %08X %5u %8d %lu %d %pK %lu %lu %u %u %d\n", @@ -1805,7 +1809,7 @@ static void get_tcp6_sock(struct seq_file *seq, struct sock *sp, int i) src->s6_addr32[2], src->s6_addr32[3], srcp, dest->s6_addr32[0], dest->s6_addr32[1], dest->s6_addr32[2], dest->s6_addr32[3], destp, - state, + state_seq, tp->write_seq - tp->snd_una, rx_queue, timer_active, -- GitLab From 7bc027e590979f7e1c0a2ff704eb20f1920eecf7 Mon Sep 17 00:00:00 2001 From: Subash Abhinov Kasiviswanathan Date: Thu, 1 Jun 2017 13:27:12 -0600 Subject: [PATCH 0150/1635] net: Fail explicit bind to local reserved ports Reserved ports may have some special use cases which are not suitable for use by general userspace applications. Currently, ports specified in ip_local_reserved_ports will not be returned only in case of automatic port assignment. Add a boolean sysctl flag 'reserved_port_bind'. Default value is 1 which preserves the existing behavior. Setting the value to 0 will prevent userspace applications from binding to these ports even when they are explicitly requested. CRs-Fixed: 2156182 BUG=20663075 Change-Id: Ib1071ca5bd437cd3c4f71b56147e4858f3b9ebec Signed-off-by: Subash Abhinov Kasiviswanathan --- Documentation/networking/ip-sysctl.txt | 5 +++++ include/net/ip.h | 2 ++ net/ipv4/af_inet.c | 2 ++ net/ipv4/inet_connection_sock.c | 7 +++++++ net/ipv4/sysctl_net_ipv4.c | 7 +++++++ net/ipv4/udp.c | 5 +++++ 6 files changed, 28 insertions(+) diff --git a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt index b244d6e23fc4..579337f3fbf3 100644 --- a/Documentation/networking/ip-sysctl.txt +++ b/Documentation/networking/ip-sysctl.txt @@ -857,6 +857,11 @@ ip_unprivileged_port_start - INTEGER Default: 1024 +reserved_port_bind - BOOLEAN + If set, allows explicit bind requests to applications requesting + any port within the range of ip_local_reserved_ports. + Default: 1 + ip_nonlocal_bind - BOOLEAN If set, allows processes to bind() to non-local IP addresses, which can be quite useful - but may break some applications. diff --git a/include/net/ip.h b/include/net/ip.h index af8addbaa3c1..9e4a1b639317 100644 --- a/include/net/ip.h +++ b/include/net/ip.h @@ -295,6 +295,8 @@ static inline int inet_prot_sock(struct net *net) __be32 inet_current_timestamp(void); +extern int sysctl_reserved_port_bind; + /* From inetpeer.c */ extern int inet_peer_threshold; extern int inet_peer_minttl; diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index c7e47f40c2ff..6fffcda326b7 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c @@ -136,6 +136,8 @@ static inline int current_has_network(void) } #endif +int sysctl_reserved_port_bind __read_mostly = 1; + /* The inetsw table contains everything that inet_create needs to * build a new socket. */ diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c index 0cc08c512202..f825da654c96 100644 --- a/net/ipv4/inet_connection_sock.c +++ b/net/ipv4/inet_connection_sock.c @@ -301,6 +301,13 @@ int inet_csk_get_port(struct sock *sk, unsigned short snum) head = &hinfo->bhash[inet_bhashfn(net, port, hinfo->bhash_size)]; spin_lock_bh(&head->lock); + + if (inet_is_local_reserved_port(net, snum) && + !sysctl_reserved_port_bind) { + ret = 1; + goto fail_unlock; + } + inet_bind_bucket_for_each(tb, &head->chain) if (net_eq(ib_net(tb), net) && tb->port == port) goto tb_found; diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c index 9a137ca52e23..c5de100e614b 100644 --- a/net/ipv4/sysctl_net_ipv4.c +++ b/net/ipv4/sysctl_net_ipv4.c @@ -893,6 +893,13 @@ static struct ctl_table ipv4_net_table[] = { .mode = 0644, .proc_handler = proc_do_large_bitmap, }, + { + .procname = "reserved_port_bind", + .data = &sysctl_reserved_port_bind, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = proc_dointvec + }, { .procname = "ip_no_pmtu_disc", .data = &init_net.ipv4.sysctl_ip_no_pmtu_disc, diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index e09502da6db5..f521778a7c72 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -293,6 +293,11 @@ int udp_lib_get_port(struct sock *sk, unsigned short snum, } else { hslot = udp_hashslot(udptable, net, snum); spin_lock_bh(&hslot->lock); + + if (inet_is_local_reserved_port(net, snum) && + !sysctl_reserved_port_bind) + goto fail_unlock; + if (hslot->count > 10) { int exist; unsigned int slot2 = udp_sk(sk)->udp_portaddr_hash ^ snum; -- GitLab From e8d76033187f70fa40c13b7127f2064b8d524b50 Mon Sep 17 00:00:00 2001 From: Subash Abhinov Kasiviswanathan Date: Thu, 1 Jun 2017 13:43:25 -0600 Subject: [PATCH 0151/1635] net: add a per-cpu counter for the number of frames coalesced in GRO A low cost method of determining GRO statistics is required. This change introduces a new counter which tracks whenever GRO coalesces ingress packets. The counter is per-CPU and exposed in /proc/net/softnet_stat as the last column of data. No user space impact is expected as a result of this change. However, this change should be reverted if legacy tools have problems with the new column in softnet_stat. CRs-Fixed: 2156182 Change-Id: I05965c0cb150947935d5977884cc4d583b37131d Signed-off-by: Subash Abhinov Kasiviswanathan --- include/linux/netdevice.h | 2 ++ net/core/dev.c | 1 + net/core/net-procfs.c | 12 ++++++------ 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 8aee7ddb9fae..48d0aa647eb3 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -2748,6 +2748,8 @@ struct softnet_data { unsigned int processed; unsigned int time_squeeze; unsigned int received_rps; + unsigned int gro_coalesced; + #ifdef CONFIG_RPS struct softnet_data *rps_ipi_list; #endif diff --git a/net/core/dev.c b/net/core/dev.c index adc11b3b4e1e..fce85617159c 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -4671,6 +4671,7 @@ static int napi_gro_complete(struct sk_buff *skb) } out: + __this_cpu_add(softnet_data.gro_coalesced, NAPI_GRO_CB(skb)->count > 1); return netif_receive_skb_internal(skb); } diff --git a/net/core/net-procfs.c b/net/core/net-procfs.c index 615ccab55f38..280b4e2433e1 100644 --- a/net/core/net-procfs.c +++ b/net/core/net-procfs.c @@ -159,12 +159,12 @@ static int softnet_seq_show(struct seq_file *seq, void *v) rcu_read_unlock(); #endif - seq_printf(seq, - "%08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x\n", - sd->processed, sd->dropped, sd->time_squeeze, 0, - 0, 0, 0, 0, /* was fastroute */ - 0, /* was cpu_collision */ - sd->received_rps, flow_limit_count); + seq_printf + (seq, "%08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x\n", + sd->processed, sd->dropped, sd->time_squeeze, 0, + 0, 0, 0, 0, /* was fastroute */ + 0, /* was cpu_collision */ + sd->received_rps, flow_limit_count, sd->gro_coalesced); return 0; } -- GitLab From ffaa68fa123c68c1c3687d82a7f4afdb137f17f7 Mon Sep 17 00:00:00 2001 From: Subash Abhinov Kasiviswanathan Date: Thu, 1 Jun 2017 13:56:05 -0600 Subject: [PATCH 0152/1635] tun: Set CHECKSUM_UNNECESSARY if userspace passes this indication Userspace may already know that the checksum validation is already completed prior to being passed to the TUN interface. As a result, computing checksum again in network stack may be a redundant operation. Add support to read this information from the TUN header flags to skip checksum validation for these packets only. This is useful in cases where the packet checksum was computed by hardware for IPv4 / IPv6 TCP / UDP packets. Since the packet intergrity was already verified for packets over the wire, subsequent validation within the network stack is redundant work. CRs-Fixed: 2156182 Change-Id: I18ee3408c05910207b205d6205f282e6f3599156 Signed-off-by: Subash Abhinov Kasiviswanathan --- drivers/net/tun.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/net/tun.c b/drivers/net/tun.c index 0fd45ea34312..27897184b2f6 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -1511,6 +1511,10 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile, return -EINVAL; } + if (!(tun->flags & IFF_NO_PI)) + if (pi.flags & htons(CHECKSUM_UNNECESSARY)) + skb->ip_summed = CHECKSUM_UNNECESSARY; + switch (tun->flags & TUN_TYPE_MASK) { case IFF_TUN: if (tun->flags & IFF_NO_PI) { -- GitLab From b71bbbdeb1c879cf4f9f884b619b887dcc98641a Mon Sep 17 00:00:00 2001 From: Subash Abhinov Kasiviswanathan Date: Mon, 26 Jun 2017 19:04:30 -0600 Subject: [PATCH 0153/1635] net: Reset NAPI bit if IPI failed During hotplug if an RPS CPU goes offline, then there is a possibility that the IPI delivery to the RPS core might fail, this happens in the cases when unruly drivers use netif_rx API in the wrong context. This happens due to two reasons a) Firstly using netif_rx API in non preemptive context leads to enough latencies that the IPI delivery might fail to an RPS core. This is because the softIRQ trigger will become unpredictable. b) by using netif_rx it becomes an architectural issue where we are trying to do two things in two different contexts. We set the NAPI bit in context and sent the IPI in other context. Now since the context switch is allowed, the remote CPU is allowed to go finish its hotplug. If there was no context switch in the first place, which typically happens by either using the correct version of netif_rx or switching to NAPI framework, then the remote CPU is not allowed to go to CPU DOWN state. This is by design since hotplug framework causes the remote dying CPU to wait until atleast one context switch happens on all other CPUS. If preemption is disabled then the dying CPU has to wait until preemption is enabled and a context switch happens. This patch catches these unruly drivers and handles IPI misses by clearing NAPI sate on remote RPS CPUs Please refere here for more documentation on hotplug and preemption cases https://lwn.net/Articles/569686/ CRs-Fixed: 2156182 Change-Id: I072f91bdb4d7e444e3624e8e010ef1b66a67b1ed Signed-off-by: Subash Abhinov Kasiviswanathan --- net/core/dev.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/net/core/dev.c b/net/core/dev.c index fce85617159c..cf66124b2cd9 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -5112,8 +5112,14 @@ static void net_rps_send_ipi(struct softnet_data *remsd) while (remsd) { struct softnet_data *next = remsd->rps_ipi_next; - if (cpu_online(remsd->cpu)) + if (cpu_online(remsd->cpu)) { smp_call_function_single_async(remsd->cpu, &remsd->csd); + } else { + pr_err("%s() cpu offline\n", __func__); + rps_lock(remsd); + remsd->backlog.state = 0; + rps_unlock(remsd); + } remsd = next; } #endif -- GitLab From ec9da1d78c1889b5154b23d3f6b8954061fa4f4e Mon Sep 17 00:00:00 2001 From: Subash Abhinov Kasiviswanathan Date: Mon, 26 Jun 2017 18:42:11 -0600 Subject: [PATCH 0154/1635] skb: Adding trace event for gso. This patch adds trace events to help with debug for gso feature by identifying the packets(and their lenghts) that are using the segmentation offload feature. CRs-Fixed: 2156182 Change-Id: Ibfe1194cc63e74c75047040b0c540713d539992e Signed-off-by: Subash Abhinov Kasiviswanathan --- include/trace/events/skb.h | 22 ++++++++++++++++++++++ net/core/dev.c | 1 + 2 files changed, 23 insertions(+) diff --git a/include/trace/events/skb.h b/include/trace/events/skb.h index 9e92f22eb086..6a48c8dfde3d 100644 --- a/include/trace/events/skb.h +++ b/include/trace/events/skb.h @@ -51,6 +51,28 @@ TRACE_EVENT(consume_skb, TP_printk("skbaddr=%p", __entry->skbaddr) ); +TRACE_EVENT(print_skb_gso, + + TP_PROTO(struct sk_buff *skb), + + TP_ARGS(skb), + + TP_STRUCT__entry( + __field(void *, skbaddr) + __field(int, len) + __field(int, data_len) + ), + + TP_fast_assign( + __entry->skbaddr = skb; + __entry->len = skb->len; + __entry->data_len = skb->data_len; + ), + + TP_printk("GSO: skbaddr=%p, len=%d, data_len=%d", + __entry->skbaddr, __entry->len, __entry->data_len) +); + TRACE_EVENT(skb_copy_datagram_iovec, TP_PROTO(const struct sk_buff *skb, int len), diff --git a/net/core/dev.c b/net/core/dev.c index cf66124b2cd9..814ba9f12e3d 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -3050,6 +3050,7 @@ static struct sk_buff *validate_xmit_skb(struct sk_buff *skb, struct net_device if (netif_needs_gso(skb, features)) { struct sk_buff *segs; + trace_print_skb_gso(skb); segs = skb_gso_segment(skb, features); if (IS_ERR(segs)) { goto out_kfree_skb; -- GitLab From f0b89458667ac039895a623177cfbd2bc10ba95a Mon Sep 17 00:00:00 2001 From: Subash Abhinov Kasiviswanathan Date: Mon, 26 Jun 2017 18:46:50 -0600 Subject: [PATCH 0155/1635] skb: printing port numbers with gso trace events Adding source and destination port number info in the gso trace events to differentiate between the flows. CRs-Fixed: 2156182 Change-Id: Idbae7f95dfd56293805b58e3c6626f5f6e07d08a Signed-off-by: Subash Abhinov Kasiviswanathan --- include/trace/events/skb.h | 13 +++++++++---- net/core/dev.c | 7 ++++++- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/include/trace/events/skb.h b/include/trace/events/skb.h index 6a48c8dfde3d..950dede9e484 100644 --- a/include/trace/events/skb.h +++ b/include/trace/events/skb.h @@ -53,24 +53,29 @@ TRACE_EVENT(consume_skb, TRACE_EVENT(print_skb_gso, - TP_PROTO(struct sk_buff *skb), + TP_PROTO(struct sk_buff *skb, __be16 src, __be16 dest), - TP_ARGS(skb), + TP_ARGS(skb, src, dest), TP_STRUCT__entry( __field(void *, skbaddr) __field(int, len) __field(int, data_len) + __field(__be16, src) + __field(__be16, dest) ), TP_fast_assign( __entry->skbaddr = skb; __entry->len = skb->len; __entry->data_len = skb->data_len; + __entry->src = src; + __entry->dest = dest; ), - TP_printk("GSO: skbaddr=%p, len=%d, data_len=%d", - __entry->skbaddr, __entry->len, __entry->data_len) + TP_printk("GSO: skbaddr=%pK, len=%d, data_len=%d, src=%u, dest=%u", + __entry->skbaddr, __entry->len, __entry->data_len, + be16_to_cpu(__entry->src), be16_to_cpu(__entry->dest)) ); TRACE_EVENT(skb_copy_datagram_iovec, diff --git a/net/core/dev.c b/net/core/dev.c index 814ba9f12e3d..2a11cc92024b 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -145,6 +145,8 @@ #include #include #include +#include +#include #include "net-sysfs.h" @@ -3050,7 +3052,10 @@ static struct sk_buff *validate_xmit_skb(struct sk_buff *skb, struct net_device if (netif_needs_gso(skb, features)) { struct sk_buff *segs; - trace_print_skb_gso(skb); + __be16 src_port = tcp_hdr(skb)->source; + __be16 dest_port = tcp_hdr(skb)->dest; + + trace_print_skb_gso(skb, src_port, dest_port); segs = skb_gso_segment(skb, features); if (IS_ERR(segs)) { goto out_kfree_skb; -- GitLab From 03ae3ba1577b13144efea14e4e06110001a13a88 Mon Sep 17 00:00:00 2001 From: Sujeev Dias Date: Thu, 5 Apr 2018 22:14:14 -0700 Subject: [PATCH 0156/1635] mhi_bus: devices: netdev: remove submitted skb list MHI bus driver will always do a callback for each buffer that's queued to hardware. So, no need to keep track of the submitted buffers using submitted list, this patch removes the submitted skb list, and related locks. CRs-Fixed: 2221018 Change-Id: Icc9b61c788e96c57409afa9578025251a146c2cc Signed-off-by: Sujeev Dias --- drivers/bus/mhi/devices/mhi_netdev.c | 69 ++++++++-------------------- 1 file changed, 20 insertions(+), 49 deletions(-) diff --git a/drivers/bus/mhi/devices/mhi_netdev.c b/drivers/bus/mhi/devices/mhi_netdev.c index abd8dd660646..af5c5db4fc05 100644 --- a/drivers/bus/mhi/devices/mhi_netdev.c +++ b/drivers/bus/mhi/devices/mhi_netdev.c @@ -99,7 +99,6 @@ struct mhi_skb_priv { struct mhi_netdev { int alias; struct mhi_device *mhi_dev; - spinlock_t tx_lock; spinlock_t rx_lock; bool enabled; rwlock_t pm_lock; /* state change lock */ @@ -107,8 +106,6 @@ struct mhi_netdev { struct work_struct alloc_work; int wake; - struct sk_buff_head tx_submitted; - struct sk_buff_head rx_submitted; struct sk_buff_head rx_allocated; u32 mru; @@ -196,18 +193,16 @@ static int mhi_netdev_alloc_skb(struct mhi_netdev *mhi_netdev, gfp_t gfp_t) skb->destructor = mhi_netdev_skb_destructor; spin_lock_bh(&mhi_netdev->rx_lock); - skb_queue_tail(&mhi_netdev->rx_submitted, skb); ret = mhi_queue_transfer(mhi_dev, DMA_FROM_DEVICE, skb, skb_priv->size, MHI_EOT); + spin_unlock_bh(&mhi_netdev->rx_lock); + if (ret) { - skb_dequeue_tail(&mhi_netdev->rx_submitted); - spin_unlock_bh(&mhi_netdev->rx_lock); MSG_ERR("Failed to queue skb, ret:%d\n", ret); ret = -EIO; goto error_queue; } - spin_unlock_bh(&mhi_netdev->rx_lock); read_unlock_bh(&mhi_netdev->pm_lock); } @@ -273,14 +268,12 @@ static int mhi_netdev_skb_recycle(struct mhi_netdev *mhi_netdev, gfp_t gfp_t) } skb_priv = (struct mhi_skb_priv *)(skb->cb); - skb_queue_tail(&mhi_netdev->rx_submitted, skb); ret = mhi_queue_transfer(mhi_dev, DMA_FROM_DEVICE, skb, skb_priv->size, MHI_EOT); /* failed to queue buffer */ if (ret) { MSG_ERR("Failed to queue skb, ret:%d\n", ret); - skb_dequeue_tail(&mhi_netdev->rx_submitted); skb_queue_tail(&mhi_netdev->rx_allocated, skb); goto error_queue; } @@ -299,23 +292,11 @@ static void mhi_netdev_dealloc(struct mhi_netdev *mhi_netdev) { struct sk_buff *skb; - skb_queue_purge(&mhi_netdev->tx_submitted); - if (!mhi_netdev->recycle_buf) { - skb_queue_purge(&mhi_netdev->rx_submitted); - } else { - skb = skb_dequeue(&mhi_netdev->rx_submitted); - while (skb) { - skb->destructor = NULL; - kfree_skb(skb); - skb = skb_dequeue(&mhi_netdev->rx_submitted); - } - + skb = skb_dequeue(&mhi_netdev->rx_allocated); + while (skb) { + skb->destructor = NULL; + kfree_skb(skb); skb = skb_dequeue(&mhi_netdev->rx_allocated); - while (skb) { - skb->destructor = NULL; - kfree_skb(skb); - skb = skb_dequeue(&mhi_netdev->rx_allocated); - } } } @@ -431,21 +412,16 @@ static int mhi_netdev_xmit(struct sk_buff *skb, struct net_device *dev) goto mhi_xmit_exit; } - spin_lock_bh(&mhi_netdev->tx_lock); - skb_queue_tail(&mhi_netdev->tx_submitted, skb); res = mhi_queue_transfer(mhi_dev, DMA_TO_DEVICE, skb, skb->len, MHI_EOT); if (res) { MSG_VERB("Failed to queue with reason:%d\n", res); - skb_dequeue_tail(&mhi_netdev->tx_submitted); netif_stop_queue(dev); - spin_unlock_bh(&mhi_netdev->tx_lock); mhi_netdev->stats.tx_full++; res = NETDEV_TX_BUSY; goto mhi_xmit_exit; } - spin_unlock_bh(&mhi_netdev->tx_lock); mhi_netdev->stats.tx_pkts++; mhi_xmit_exit: @@ -639,8 +615,6 @@ static int mhi_netdev_enable_iface(struct mhi_netdev *mhi_netdev) goto net_dev_reg_fail; } - skb_queue_head_init(&mhi_netdev->tx_submitted); - skb_queue_head_init(&mhi_netdev->rx_submitted); skb_queue_head_init(&mhi_netdev->rx_allocated); } @@ -697,21 +671,15 @@ static void mhi_netdev_xfer_ul_cb(struct mhi_device *mhi_dev, struct mhi_result *mhi_result) { struct mhi_netdev *mhi_netdev = mhi_device_get_devdata(mhi_dev); - struct sk_buff *skb = skb_dequeue(&mhi_netdev->tx_submitted); + struct sk_buff *skb = mhi_result->buf_addr; struct net_device *ndev = mhi_netdev->ndev; - unsigned long flags; - - MHI_ASSERT(skb != mhi_result->buf_addr, "ooo ul cb"); ndev->stats.tx_packets++; ndev->stats.tx_bytes += skb->len; dev_kfree_skb(skb); - if (netif_queue_stopped(ndev)) { - spin_lock_irqsave(&mhi_netdev->tx_lock, flags); + if (netif_queue_stopped(ndev)) netif_wake_queue(ndev); - spin_unlock_irqrestore(&mhi_netdev->tx_lock, flags); - } } static int mhi_netdev_process_fragment(struct mhi_netdev *mhi_netdev, @@ -739,12 +707,6 @@ static int mhi_netdev_process_fragment(struct mhi_netdev *mhi_netdev, return -ENOMEM; } - /* recycle the skb */ - if (mhi_netdev->recycle_buf) - mhi_netdev_skb_destructor(skb); - else - dev_kfree_skb(skb); - mhi_netdev->stats.rx_frag++; return 0; @@ -754,11 +716,14 @@ static void mhi_netdev_xfer_dl_cb(struct mhi_device *mhi_dev, struct mhi_result *mhi_result) { struct mhi_netdev *mhi_netdev = mhi_device_get_devdata(mhi_dev); - struct sk_buff *skb = skb_dequeue(&mhi_netdev->rx_submitted); + struct sk_buff *skb = mhi_result->buf_addr; struct net_device *dev = mhi_netdev->ndev; int ret = 0; - MHI_ASSERT(skb != mhi_result->buf_addr, "ooo dl cb"); + if (mhi_result->transaction_status == -ENOTCONN) { + dev_kfree_skb(skb); + return; + } skb_put(skb, mhi_result->bytes_xferd); dev->stats.rx_packets++; @@ -768,6 +733,13 @@ static void mhi_netdev_xfer_dl_cb(struct mhi_device *mhi_dev, if (mhi_result->transaction_status == -EOVERFLOW || mhi_netdev->frag_skb) { ret = mhi_netdev_process_fragment(mhi_netdev, skb); + + /* recycle the skb */ + if (mhi_netdev->recycle_buf) + mhi_netdev_skb_destructor(skb); + else + dev_kfree_skb(skb); + if (ret) return; } @@ -982,7 +954,6 @@ static int mhi_netdev_probe(struct mhi_device *mhi_dev, mhi_netdev->rx_queue = mhi_netdev->recycle_buf ? mhi_netdev_skb_recycle : mhi_netdev_alloc_skb; - spin_lock_init(&mhi_netdev->tx_lock); spin_lock_init(&mhi_netdev->rx_lock); rwlock_init(&mhi_netdev->pm_lock); INIT_WORK(&mhi_netdev->alloc_work, mhi_netdev_alloc_work); -- GitLab From be344eb202658f8d19375d717b2d5af5da2378ee Mon Sep 17 00:00:00 2001 From: Alexei Avshalom Lazar Date: Wed, 11 Apr 2018 23:28:53 +0300 Subject: [PATCH 0157/1635] ARM: dts: msm: add wil6210 device for sm8150 platforms Wil6210 driver is needed for 11ad wireless card. Change-Id: If84e59d9a7145f1fd17ffdef3dedeb4db10e7ccc Signed-off-by: Alexei Avshalom Lazar --- arch/arm64/boot/dts/qcom/sm8150-cdp.dtsi | 4 ++++ arch/arm64/boot/dts/qcom/sm8150-mtp.dtsi | 4 ++++ arch/arm64/boot/dts/qcom/sm8150-qrd.dtsi | 4 ++++ arch/arm64/boot/dts/qcom/sm8150.dtsi | 26 ++++++++++++++++++++++++ 4 files changed, 38 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sm8150-cdp.dtsi b/arch/arm64/boot/dts/qcom/sm8150-cdp.dtsi index 55c7e9b917eb..b34b8bc96bd2 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-cdp.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-cdp.dtsi @@ -503,3 +503,7 @@ }; }; }; + +&wil6210 { + status = "ok"; +}; diff --git a/arch/arm64/boot/dts/qcom/sm8150-mtp.dtsi b/arch/arm64/boot/dts/qcom/sm8150-mtp.dtsi index 95806c047b4d..45562fe9d3c3 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-mtp.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-mtp.dtsi @@ -507,3 +507,7 @@ }; }; }; + +&wil6210 { + status = "ok"; +}; diff --git a/arch/arm64/boot/dts/qcom/sm8150-qrd.dtsi b/arch/arm64/boot/dts/qcom/sm8150-qrd.dtsi index 5ef91a3b0907..d67a1f4da3b4 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-qrd.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-qrd.dtsi @@ -473,3 +473,7 @@ }; }; }; + +&wil6210 { + status = "ok"; +}; diff --git a/arch/arm64/boot/dts/qcom/sm8150.dtsi b/arch/arm64/boot/dts/qcom/sm8150.dtsi index 8e6abaca41ae..472ae5d809f3 100644 --- a/arch/arm64/boot/dts/qcom/sm8150.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150.dtsi @@ -3162,6 +3162,32 @@ qcom,vdd-cx-mx-config = <752000 752000>; qcom,vdd-3.3-ch0-config = <3104000 3312000>; }; + + wil6210: qcom,wil6210 { + compatible = "qcom,wil6210"; + qcom,pcie-parent = <&pcie1>; + pinctrl-names = "default"; + pinctrl-0 = <&wil6210_refclk3_en_pin>; + qcom,wigig-en = <&tlmm 131 0>; + qcom,msm-bus,name = "wil6210"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <100 512 0 0>, + <100 512 600000 800000>; /* ~4.6Gbps (MCS12) */ + qcom,use-ext-supply; + vddio-supply= <&pm855_s5>; + qcom,use-ext-clocks; + clocks = <&clock_rpmh RPMH_RF_CLK3>, + <&clock_rpmh RPMH_RF_CLK3_A>; + clock-names = "rf_clk3_clk", "rf_clk3_pin_clk"; + qcom,smmu-support; + qcom,smmu-mapping = <0x20000000 0xe0000000>; + qcom,smmu-s1-en; + qcom,smmu-fast-map; + qcom,smmu-coherent; + status = "disabled"; + }; }; &emac_gdsc { -- GitLab From 9fde4e0dea35d023bc8bb3c256fc1797c4933c4e Mon Sep 17 00:00:00 2001 From: Jonathan Avila Date: Fri, 1 Dec 2017 16:45:18 -0800 Subject: [PATCH 0158/1635] PM / devfreq: Introduce a sysfs lock Currently, concurrent writes to sysfs entries leave the possibility for race conditions within the devfreq framework. For example, concurrently executing max_freq_store and governor_store can result in attempting to perform an update_devfreq() before the new governor's start handler can be executed. A more concrete case is a race between polling_interval_store and governor_store. Because no lock is used after calling into the event handler of the old governor and there's nothing preventing work from being queued after the monitor is stopped, it's possible to accidentally cause delayed work to be queued on the governor being switched to. This can be seen if you create two threads, one which changes a device's governor between simple_ondemand and performance, and one which changes its polling interval between 45 and 50. All of these races can be addressed with the introduction of a lock that prevents sysfs operations from interleaving in this fashion. Change-Id: Ia6887dcb2d69dc2576837a6c09fed55a28943abc Signed-off-by: Jonathan Avila --- drivers/devfreq/devfreq.c | 14 +++++++++++++- include/linux/devfreq.h | 1 + 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c index 4d134bad6e50..a60919542d5c 100644 --- a/drivers/devfreq/devfreq.c +++ b/drivers/devfreq/devfreq.c @@ -522,6 +522,7 @@ static void devfreq_dev_release(struct device *dev) devfreq->profile->exit(devfreq->dev.parent); mutex_destroy(&devfreq->lock); + mutex_destroy(&devfreq->sysfs_lock); kfree(devfreq); } @@ -564,6 +565,7 @@ struct devfreq *devfreq_add_device(struct device *dev, } mutex_init(&devfreq->lock); + mutex_init(&devfreq->sysfs_lock); mutex_lock(&devfreq->lock); devfreq->dev.parent = dev; devfreq->dev.class = devfreq_class; @@ -962,12 +964,13 @@ static ssize_t governor_store(struct device *dev, struct device_attribute *attr, goto out; } + mutex_lock(&df->sysfs_lock); if (df->governor) { ret = df->governor->event_handler(df, DEVFREQ_GOV_STOP, NULL); if (ret) { dev_warn(dev, "%s: Governor %s not stopped(%d)\n", __func__, df->governor->name, ret); - goto out; + goto gov_stop_out; } } prev_gov = df->governor; @@ -985,6 +988,9 @@ static ssize_t governor_store(struct device *dev, struct device_attribute *attr, NULL); } } + +gov_stop_out: + mutex_unlock(&df->sysfs_lock); out: mutex_unlock(&devfreq_list_lock); @@ -1079,8 +1085,10 @@ static ssize_t polling_interval_store(struct device *dev, if (ret != 1) return -EINVAL; + mutex_lock(&df->sysfs_lock); df->governor->event_handler(df, DEVFREQ_GOV_INTERVAL, &value); ret = count; + mutex_unlock(&df->sysfs_lock); return ret; } @@ -1098,6 +1106,7 @@ static ssize_t min_freq_store(struct device *dev, struct device_attribute *attr, if (ret != 1) return -EINVAL; + mutex_lock(&df->sysfs_lock); mutex_lock(&df->lock); max = df->max_freq; if (value && max && value > max) { @@ -1110,6 +1119,7 @@ static ssize_t min_freq_store(struct device *dev, struct device_attribute *attr, ret = count; unlock: mutex_unlock(&df->lock); + mutex_unlock(&df->sysfs_lock); return ret; } @@ -1125,6 +1135,7 @@ static ssize_t max_freq_store(struct device *dev, struct device_attribute *attr, if (ret != 1) return -EINVAL; + mutex_lock(&df->sysfs_lock); mutex_lock(&df->lock); min = df->min_freq; if (value && min && value < min) { @@ -1137,6 +1148,7 @@ static ssize_t max_freq_store(struct device *dev, struct device_attribute *attr, ret = count; unlock: mutex_unlock(&df->lock); + mutex_unlock(&df->sysfs_lock); return ret; } diff --git a/include/linux/devfreq.h b/include/linux/devfreq.h index ea94e6e5ebc3..64163f23327f 100644 --- a/include/linux/devfreq.h +++ b/include/linux/devfreq.h @@ -139,6 +139,7 @@ struct devfreq { struct list_head node; struct mutex lock; + struct mutex sysfs_lock; struct device dev; struct devfreq_dev_profile *profile; const struct devfreq_governor *governor; -- GitLab From 11be0f38b992189f0c49f1363d4b04af3129e6f2 Mon Sep 17 00:00:00 2001 From: Jigarkumar Zala Date: Tue, 3 Apr 2018 16:22:11 -0700 Subject: [PATCH 0159/1635] ARM: dts: msm: Fix camera flash LED configurations for sm8150 platforms Fix camera led flash PMIC source phandles in order to trigger correct flash/torch node with respective image sensor. Also, correct analog/auto_focus voltage required in order to set regulator voltage correctly. Change-Id: I9a89e04fa02201be2aa43d431f453640d2efd19a Signed-off-by: Jigarkumar Zala --- .../dts/qcom/sm8150-camera-sensor-cdp.dtsi | 44 +++++++++---------- .../dts/qcom/sm8150-camera-sensor-mtp.dtsi | 44 +++++++++---------- 2 files changed, 44 insertions(+), 44 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sm8150-camera-sensor-cdp.dtsi b/arch/arm64/boot/dts/qcom/sm8150-camera-sensor-cdp.dtsi index 29948a4e985d..d1704a1b5d09 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-camera-sensor-cdp.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-camera-sensor-cdp.dtsi @@ -18,7 +18,7 @@ compatible = "qcom,camera-flash"; flash-source = <&pm855l_flash0 &pm855l_flash1>; torch-source = <&pm855l_torch0 &pm855l_torch1>; - switch-source = <&pm855l_switch0>; + switch-source = <&pm855l_switch2>; status = "ok"; }; @@ -28,7 +28,7 @@ compatible = "qcom,camera-flash"; flash-source = <&pm855l_flash0 &pm855l_flash1>; torch-source = <&pm855l_torch0 &pm855l_torch1>; - switch-source = <&pm855l_switch0>; + switch-source = <&pm855l_switch2>; status = "ok"; }; @@ -38,7 +38,7 @@ compatible = "qcom,camera-flash"; flash-source = <&pm855l_flash1>; torch-source = <&pm855l_torch1>; - switch-source = <&pm855l_switch1>; + switch-source = <&pm855l_switch0>; status = "ok"; }; }; @@ -57,8 +57,8 @@ cam_vaf-supply = <&pm8009_s2>; regulator-names = "cam_vaf"; rgltr-cntrl-support; - rgltr-min-voltage = <2850000>; - rgltr-max-voltage = <2850000>; + rgltr-min-voltage = <2856000>; + rgltr-max-voltage = <2856000>; rgltr-load-current = <0>; }; @@ -70,8 +70,8 @@ cam_vaf-supply = <&pm8009_s2>; regulator-names = "cam_vaf"; rgltr-cntrl-support; - rgltr-min-voltage = <2850000>; - rgltr-max-voltage = <2850000>; + rgltr-min-voltage = <2856000>; + rgltr-max-voltage = <2856000>; rgltr-load-current = <0>; }; @@ -83,8 +83,8 @@ cam_vaf-supply = <&pm8009_s2>; regulator-names = "cam_vaf"; rgltr-cntrl-support; - rgltr-min-voltage = <2850000>; - rgltr-max-voltage = <2850000>; + rgltr-min-voltage = <2856000>; + rgltr-max-voltage = <2856000>; rgltr-load-current = <0>; }; @@ -96,8 +96,8 @@ cam_vaf-supply = <&pm8009_s2>; regulator-names = "cam_vaf"; rgltr-cntrl-support; - rgltr-min-voltage = <2850000>; - rgltr-max-voltage = <2850000>; + rgltr-min-voltage = <2856000>; + rgltr-max-voltage = <2856000>; rgltr-load-current = <0>; status = "ok"; }; @@ -114,8 +114,8 @@ regulator-names = "cam_vio", "cam_vana", "cam_vdig", "cam_clk", "cam_vaf"; rgltr-cntrl-support; - rgltr-min-voltage = <0 2800000 1200000 0 2850000>; - rgltr-max-voltage = <0 2800000 1200000 0 2850000>; + rgltr-min-voltage = <0 2800000 1200000 0 2856000>; + rgltr-max-voltage = <0 2800000 1200000 0 2856000>; rgltr-load-current = <0 80000 1200000 0 0>; gpio-no-mux = <0>; pinctrl-names = "cam_default", "cam_suspend"; @@ -152,8 +152,8 @@ regulator-names = "cam_vio", "cam_vana", "cam_vdig", "cam_clk", "cam_vaf"; rgltr-cntrl-support; - rgltr-min-voltage = <0 2850000 1200000 0 2850000>; - rgltr-max-voltage = <0 2850000 1200000 0 2850000>; + rgltr-min-voltage = <0 2850000 1200000 0 2856000>; + rgltr-max-voltage = <0 2850000 1200000 0 2856000>; rgltr-load-current = <0 80000 1200000 0 0>; gpio-no-mux = <0>; pinctrl-names = "cam_default", "cam_suspend"; @@ -190,8 +190,8 @@ regulator-names = "cam_vio", "cam_vana", "cam_vdig", "cam_clk", "cam_vaf"; rgltr-cntrl-support; - rgltr-min-voltage = <0 2850000 1200000 0 2850000>; - rgltr-max-voltage = <0 2850000 1200000 0 2850000>; + rgltr-min-voltage = <0 2850000 1200000 0 2856000>; + rgltr-max-voltage = <0 2850000 1200000 0 2856000>; rgltr-load-current = <0 80000 1200000 0 0>; gpio-no-mux = <0>; pinctrl-names = "cam_default", "cam_suspend"; @@ -278,8 +278,8 @@ regulator-names = "cam_vio", "cam_vana", "cam_vdig", "cam_clk"; rgltr-cntrl-support; - rgltr-min-voltage = <0 2850000 1200000 0>; - rgltr-max-voltage = <0 2850000 1200000 0>; + rgltr-min-voltage = <0 2856000 1200000 0>; + rgltr-max-voltage = <0 2856000 1200000 0>; rgltr-load-current = <0 80000 1200000 0>; gpio-no-mux = <0>; pinctrl-names = "cam_default", "cam_suspend"; @@ -308,7 +308,7 @@ compatible = "qcom,cam-sensor"; reg = <0x02>; csiphy-sd-index = <2>; - sensor-position-roll = <270>; + sensor-position-roll = <90>; sensor-position-pitch = <0>; sensor-position-yaw = <0>; eeprom-src = <&eeprom_front>; @@ -320,8 +320,8 @@ regulator-names = "cam_vio", "cam_vana", "cam_vdig", "cam_clk"; rgltr-cntrl-support; - rgltr-min-voltage = <0 2850000 1200000 0>; - rgltr-max-voltage = <0 2850000 1200000 0>; + rgltr-min-voltage = <0 2856000 1200000 0>; + rgltr-max-voltage = <0 2856000 1200000 0>; rgltr-load-current = <0 80000 1200000 0>; gpio-no-mux = <0>; pinctrl-names = "cam_default", "cam_suspend"; diff --git a/arch/arm64/boot/dts/qcom/sm8150-camera-sensor-mtp.dtsi b/arch/arm64/boot/dts/qcom/sm8150-camera-sensor-mtp.dtsi index 29948a4e985d..d1704a1b5d09 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-camera-sensor-mtp.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-camera-sensor-mtp.dtsi @@ -18,7 +18,7 @@ compatible = "qcom,camera-flash"; flash-source = <&pm855l_flash0 &pm855l_flash1>; torch-source = <&pm855l_torch0 &pm855l_torch1>; - switch-source = <&pm855l_switch0>; + switch-source = <&pm855l_switch2>; status = "ok"; }; @@ -28,7 +28,7 @@ compatible = "qcom,camera-flash"; flash-source = <&pm855l_flash0 &pm855l_flash1>; torch-source = <&pm855l_torch0 &pm855l_torch1>; - switch-source = <&pm855l_switch0>; + switch-source = <&pm855l_switch2>; status = "ok"; }; @@ -38,7 +38,7 @@ compatible = "qcom,camera-flash"; flash-source = <&pm855l_flash1>; torch-source = <&pm855l_torch1>; - switch-source = <&pm855l_switch1>; + switch-source = <&pm855l_switch0>; status = "ok"; }; }; @@ -57,8 +57,8 @@ cam_vaf-supply = <&pm8009_s2>; regulator-names = "cam_vaf"; rgltr-cntrl-support; - rgltr-min-voltage = <2850000>; - rgltr-max-voltage = <2850000>; + rgltr-min-voltage = <2856000>; + rgltr-max-voltage = <2856000>; rgltr-load-current = <0>; }; @@ -70,8 +70,8 @@ cam_vaf-supply = <&pm8009_s2>; regulator-names = "cam_vaf"; rgltr-cntrl-support; - rgltr-min-voltage = <2850000>; - rgltr-max-voltage = <2850000>; + rgltr-min-voltage = <2856000>; + rgltr-max-voltage = <2856000>; rgltr-load-current = <0>; }; @@ -83,8 +83,8 @@ cam_vaf-supply = <&pm8009_s2>; regulator-names = "cam_vaf"; rgltr-cntrl-support; - rgltr-min-voltage = <2850000>; - rgltr-max-voltage = <2850000>; + rgltr-min-voltage = <2856000>; + rgltr-max-voltage = <2856000>; rgltr-load-current = <0>; }; @@ -96,8 +96,8 @@ cam_vaf-supply = <&pm8009_s2>; regulator-names = "cam_vaf"; rgltr-cntrl-support; - rgltr-min-voltage = <2850000>; - rgltr-max-voltage = <2850000>; + rgltr-min-voltage = <2856000>; + rgltr-max-voltage = <2856000>; rgltr-load-current = <0>; status = "ok"; }; @@ -114,8 +114,8 @@ regulator-names = "cam_vio", "cam_vana", "cam_vdig", "cam_clk", "cam_vaf"; rgltr-cntrl-support; - rgltr-min-voltage = <0 2800000 1200000 0 2850000>; - rgltr-max-voltage = <0 2800000 1200000 0 2850000>; + rgltr-min-voltage = <0 2800000 1200000 0 2856000>; + rgltr-max-voltage = <0 2800000 1200000 0 2856000>; rgltr-load-current = <0 80000 1200000 0 0>; gpio-no-mux = <0>; pinctrl-names = "cam_default", "cam_suspend"; @@ -152,8 +152,8 @@ regulator-names = "cam_vio", "cam_vana", "cam_vdig", "cam_clk", "cam_vaf"; rgltr-cntrl-support; - rgltr-min-voltage = <0 2850000 1200000 0 2850000>; - rgltr-max-voltage = <0 2850000 1200000 0 2850000>; + rgltr-min-voltage = <0 2850000 1200000 0 2856000>; + rgltr-max-voltage = <0 2850000 1200000 0 2856000>; rgltr-load-current = <0 80000 1200000 0 0>; gpio-no-mux = <0>; pinctrl-names = "cam_default", "cam_suspend"; @@ -190,8 +190,8 @@ regulator-names = "cam_vio", "cam_vana", "cam_vdig", "cam_clk", "cam_vaf"; rgltr-cntrl-support; - rgltr-min-voltage = <0 2850000 1200000 0 2850000>; - rgltr-max-voltage = <0 2850000 1200000 0 2850000>; + rgltr-min-voltage = <0 2850000 1200000 0 2856000>; + rgltr-max-voltage = <0 2850000 1200000 0 2856000>; rgltr-load-current = <0 80000 1200000 0 0>; gpio-no-mux = <0>; pinctrl-names = "cam_default", "cam_suspend"; @@ -278,8 +278,8 @@ regulator-names = "cam_vio", "cam_vana", "cam_vdig", "cam_clk"; rgltr-cntrl-support; - rgltr-min-voltage = <0 2850000 1200000 0>; - rgltr-max-voltage = <0 2850000 1200000 0>; + rgltr-min-voltage = <0 2856000 1200000 0>; + rgltr-max-voltage = <0 2856000 1200000 0>; rgltr-load-current = <0 80000 1200000 0>; gpio-no-mux = <0>; pinctrl-names = "cam_default", "cam_suspend"; @@ -308,7 +308,7 @@ compatible = "qcom,cam-sensor"; reg = <0x02>; csiphy-sd-index = <2>; - sensor-position-roll = <270>; + sensor-position-roll = <90>; sensor-position-pitch = <0>; sensor-position-yaw = <0>; eeprom-src = <&eeprom_front>; @@ -320,8 +320,8 @@ regulator-names = "cam_vio", "cam_vana", "cam_vdig", "cam_clk"; rgltr-cntrl-support; - rgltr-min-voltage = <0 2850000 1200000 0>; - rgltr-max-voltage = <0 2850000 1200000 0>; + rgltr-min-voltage = <0 2856000 1200000 0>; + rgltr-max-voltage = <0 2856000 1200000 0>; rgltr-load-current = <0 80000 1200000 0>; gpio-no-mux = <0>; pinctrl-names = "cam_default", "cam_suspend"; -- GitLab From f4fa3f487688ca9ef5f0e47f7de4bcd7bb5a55ac Mon Sep 17 00:00:00 2001 From: Chris Lew Date: Wed, 11 Apr 2018 14:32:10 -0700 Subject: [PATCH 0160/1635] ARM: dts: msm: Add wdsp glink node for sdmshrike Add device tree node to enable RPMSG GLINK communication to WDSP. In addition to the normal glink properties, the wdsp glink node must contain the addresses for the tx and rx fifo descriptors. Change-Id: I6677949988092900e2064bd5ffccdf093f2aed6e Signed-off-by: Chris Lew --- arch/arm64/boot/dts/qcom/sdmshrike.dtsi | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sdmshrike.dtsi b/arch/arm64/boot/dts/qcom/sdmshrike.dtsi index 95f8062feaa1..e0658059a3ee 100644 --- a/arch/arm64/boot/dts/qcom/sdmshrike.dtsi +++ b/arch/arm64/boot/dts/qcom/sdmshrike.dtsi @@ -653,6 +653,13 @@ qcom,intents = <0x64 64>; }; }; + + glink_spi_xprt_wdsp: wdsp { + qcom,remote-pid = <10>; + transport = "spi"; + tx-descriptors = <0x12000 0x12004>; + rx-descriptors = <0x1200c 0x12010>; + }; }; qcom,glinkpkt { -- GitLab From 37394e91c1a57b511981c7f39610b364a7043565 Mon Sep 17 00:00:00 2001 From: Siddartha Mohanadoss Date: Wed, 4 Apr 2018 13:29:14 -0700 Subject: [PATCH 0161/1635] ARM: dts: msm: Add VADC channel nodes on PM855B Add VADC channel node to read SMB1390 and SMB1355 thermistor from PM855b VADC_USR peripheral. Change-Id: I4ebbbeb5bae98a41104fc2a6ba487d7cf51f9a39 Signed-off-by: Siddartha Mohanadoss --- arch/arm64/boot/dts/qcom/pm855b.dtsi | 15 +++++++++++++++ arch/arm64/boot/dts/qcom/sm8150-cdp.dtsi | 8 -------- arch/arm64/boot/dts/qcom/sm8150-mtp.dtsi | 8 -------- arch/arm64/boot/dts/qcom/sm8150-qrd.dtsi | 8 -------- 4 files changed, 15 insertions(+), 24 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/pm855b.dtsi b/arch/arm64/boot/dts/qcom/pm855b.dtsi index c9b469aa6e19..82e5e1807823 100644 --- a/arch/arm64/boot/dts/qcom/pm855b.dtsi +++ b/arch/arm64/boot/dts/qcom/pm855b.dtsi @@ -125,6 +125,21 @@ label = "v_i_parallel_vbat_vdata"; qcom,pre-scaling = <1 1>; }; + + smb1390_therm { + reg = ; + label = "smb1390_therm"; + qcom,hw-settle-time = <200>; + qcom,pre-scaling = <1 1>; + }; + + smb1355_therm { + reg = ; + label = "smb1355_therm"; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + qcom,pre-scaling = <1 1>; + }; }; pm855b_charger: qcom,qpnp-smb5 { diff --git a/arch/arm64/boot/dts/qcom/sm8150-cdp.dtsi b/arch/arm64/boot/dts/qcom/sm8150-cdp.dtsi index 55c7e9b917eb..1fb63847c743 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-cdp.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-cdp.dtsi @@ -273,14 +273,6 @@ qcom,pre-scaling = <1 1>; }; - smb_therm { - reg = ; - label = "smb_therm"; - qcom,ratiometric; - qcom,hw-settle-time = <200>; - qcom,pre-scaling = <1 1>; - }; - vcoin { reg = ; label = "vcoin"; diff --git a/arch/arm64/boot/dts/qcom/sm8150-mtp.dtsi b/arch/arm64/boot/dts/qcom/sm8150-mtp.dtsi index 95806c047b4d..a6ac8d8ff946 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-mtp.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-mtp.dtsi @@ -277,14 +277,6 @@ qcom,pre-scaling = <1 1>; }; - smb_therm { - reg = ; - label = "smb_therm"; - qcom,ratiometric; - qcom,hw-settle-time = <200>; - qcom,pre-scaling = <1 1>; - }; - vcoin { reg = ; label = "vcoin"; diff --git a/arch/arm64/boot/dts/qcom/sm8150-qrd.dtsi b/arch/arm64/boot/dts/qcom/sm8150-qrd.dtsi index 5a4c35e1acc2..fedcea9b7a00 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-qrd.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-qrd.dtsi @@ -243,14 +243,6 @@ qcom,pre-scaling = <1 1>; }; - smb_therm { - reg = ; - label = "smb_therm"; - qcom,ratiometric; - qcom,hw-settle-time = <200>; - qcom,pre-scaling = <1 1>; - }; - vcoin { reg = ; label = "vcoin"; -- GitLab From 99c8fb49a12d59b01a41622c4b8b1e107c718c59 Mon Sep 17 00:00:00 2001 From: Vidyakumar Athota Date: Wed, 11 Apr 2018 15:41:11 -0700 Subject: [PATCH 0162/1635] ARM: dts: msm: update current limit for wcd9360 in SM8150 Set current limit to 1000000 microamps for wcd9360 audio codec to force BOB into PFM mode instead of PASS mode. Change-Id: Iedb0113c30f5c7e10e26437b6551fb0a4baaf713 Signed-off-by: Vidyakumar Athota --- arch/arm64/boot/dts/qcom/sm8150-audio-overlay.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/sm8150-audio-overlay.dtsi b/arch/arm64/boot/dts/qcom/sm8150-audio-overlay.dtsi index d99447359638..29da3c5e97ae 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-audio-overlay.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-audio-overlay.dtsi @@ -201,7 +201,7 @@ cdc-vdd-pa-supply = <&pm855l_bob>; qcom,cdc-vdd-pa-voltage = <3300000 3300000>; - qcom,cdc-vdd-pa-current = <230000>; + qcom,cdc-vdd-pa-current = <1000000>; qcom,cdc-static-supplies = "cdc-vdd-buck-sido", "cdc-vdd-px", -- GitLab From f0eebfeaded85fc7d99261fddb9fabeee0dcd46c Mon Sep 17 00:00:00 2001 From: Deepak Katragadda Date: Wed, 11 Apr 2018 16:38:52 -0700 Subject: [PATCH 0163/1635] clk: qcom: clk-alpha-pll: Set the inited flag to avoid PLL reconfiguration When entities outside of the HLOS configure PLLs, set the inited flag to true in order to avoid reconfiguration at a later time. Change-Id: I8fcd382c280a0d67c56f361a76a088b42ad05c2b Signed-off-by: Deepak Katragadda --- drivers/clk/qcom/clk-alpha-pll.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/clk/qcom/clk-alpha-pll.c b/drivers/clk/qcom/clk-alpha-pll.c index 391ca0359c55..ee80e6ee0021 100644 --- a/drivers/clk/qcom/clk-alpha-pll.c +++ b/drivers/clk/qcom/clk-alpha-pll.c @@ -726,6 +726,7 @@ int clk_trion_pll_configure(struct clk_alpha_pll *pll, struct regmap *regmap, if (trion_pll_is_enabled(pll, regmap)) { pr_warn("PLL is already enabled. Skipping configuration.\n"); + pll->inited = true; return ret; } @@ -1039,6 +1040,7 @@ int clk_regera_pll_configure(struct clk_alpha_pll *pll, struct regmap *regmap, if (mode_regval & PLL_LOCK_DET) { pr_warn("PLL is already enabled. Skipping configuration.\n"); + pll->inited = true; return 0; } -- GitLab From 306505cf9a8f4be1d8a776c2242fed1aa4924d5b Mon Sep 17 00:00:00 2001 From: Liam Mark Date: Wed, 11 Apr 2018 09:39:38 -0700 Subject: [PATCH 0164/1635] iommu/iova: Limit IOVA alignment using CONFIG_ARM64_DMA_IOMMU_ALIGNMENT Currently IOVAs are aligned to the next power of two of the size of the allocation. This can result in unnecessary fragmentation of the IOVA space. If defined use CONFIG_ARM64_DMA_IOMMU_ALIGNMENT to limit the maximum IOVA alignment. Change-Id: Ica7f6382237e37acac2d35972a564ca1e1f5e84f Signed-off-by: Liam Mark --- drivers/iommu/iova.c | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/drivers/iommu/iova.c b/drivers/iommu/iova.c index 33edfa794ae9..b36d5aa92a00 100644 --- a/drivers/iommu/iova.c +++ b/drivers/iommu/iova.c @@ -182,14 +182,28 @@ iova_insert_rbtree(struct rb_root *root, struct iova *iova, rb_insert_color(&iova->node, root); } +#ifdef CONFIG_ARM64_DMA_IOMMU_ALIGNMENT +#define MAX_ALIGN(shift) (((1 << CONFIG_ARM64_DMA_IOMMU_ALIGNMENT) * PAGE_SIZE)\ + >> (shift)) +#else +#define MAX_ALIGN(shift) ULONG_MAX +#endif + /* * Computes the padding size required, to make the start address - * naturally aligned on the power-of-two order of its size + * naturally aligned on the minimum of the power-of-two order of its size and + * max_align */ static unsigned int -iova_get_pad_size(unsigned int size, unsigned int limit_pfn) +iova_get_pad_size(unsigned int size, unsigned int limit_pfn, + unsigned int max_align) { - return (limit_pfn - size) & (__roundup_pow_of_two(size) - 1); + unsigned int align = __roundup_pow_of_two(size); + + if (align > max_align) + align = max_align; + + return (limit_pfn - size) & (align - 1); } static int __alloc_and_insert_iova_range(struct iova_domain *iovad, @@ -200,12 +214,14 @@ static int __alloc_and_insert_iova_range(struct iova_domain *iovad, unsigned long flags; unsigned long saved_pfn; unsigned int pad_size = 0; + unsigned long shift = iova_shift(iovad); /* Walk the tree backwards */ spin_lock_irqsave(&iovad->iova_rbtree_lock, flags); saved_pfn = limit_pfn; curr = __get_cached_rbnode(iovad, &limit_pfn); prev = curr; + while (curr) { struct iova *curr_iova = rb_entry(curr, struct iova, node); @@ -213,7 +229,8 @@ static int __alloc_and_insert_iova_range(struct iova_domain *iovad, goto move_left; } else if (limit_pfn > curr_iova->pfn_hi) { if (size_aligned) - pad_size = iova_get_pad_size(size, limit_pfn); + pad_size = iova_get_pad_size(size, limit_pfn, + MAX_ALIGN(shift)); if ((curr_iova->pfn_hi + size + pad_size) < limit_pfn) break; /* found a free slot */ } @@ -225,7 +242,8 @@ static int __alloc_and_insert_iova_range(struct iova_domain *iovad, if (!curr) { if (size_aligned) - pad_size = iova_get_pad_size(size, limit_pfn); + pad_size = iova_get_pad_size(size, limit_pfn, + MAX_ALIGN(shift)); if ((iovad->start_pfn + size + pad_size) > limit_pfn) { spin_unlock_irqrestore(&iovad->iova_rbtree_lock, flags); return -ENOMEM; -- GitLab From d60de9a6928e6de1cf70bfdaed78c4ec1e439510 Mon Sep 17 00:00:00 2001 From: Subbaraman Narayanamurthy Date: Tue, 10 Apr 2018 13:20:56 -0700 Subject: [PATCH 0165/1635] regulator: qpnp-lcdb: Fix boost headroom and max voltage configuration For PM660L, maximum boost voltage is 6250 mV and for PM855L, it is 6275 mV. Fix this. Also, if the child node for boost regulator is not specified in the device tree, boost headroom is set to 0. This is incorrect when there is a request for voltage change in addition to enable/disable LDO/NCP regulators, boost voltage can get set without the required headroom as the headroom was set to 0. Fix this by initializing boost headroom to default values even if the child node for boost is not defined. While at it, add the default boost headroom values for different PMICs in device tree bindings documentation. Change-Id: I79911d88e0fa25d8b520796c8eea61e6e4ab27ae Signed-off-by: Subbaraman Narayanamurthy --- .../bindings/regulator/qpnp-lcdb-regulator.txt | 5 +++-- drivers/regulator/qpnp-lcdb-regulator.c | 17 ++++++++++++++--- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/Documentation/devicetree/bindings/regulator/qpnp-lcdb-regulator.txt b/Documentation/devicetree/bindings/regulator/qpnp-lcdb-regulator.txt index 9798ac60b493..72c4eaf17b5f 100644 --- a/Documentation/devicetree/bindings/regulator/qpnp-lcdb-regulator.txt +++ b/Documentation/devicetree/bindings/regulator/qpnp-lcdb-regulator.txt @@ -212,8 +212,9 @@ Properties below are specific to BOOST subnode only. - qcom,bst-headroom-mv Usage: optional Value type: - Definition: Headroom of the boost (in mV). The minimum headroom is - 200mV and if not specified defaults to 200mV. + Definition: Headroom of the boost (in mV). If not specified, then the + default value is 200 mV (PM660L) or 150 mV (for PM855L or + PMI632). ======= Example diff --git a/drivers/regulator/qpnp-lcdb-regulator.c b/drivers/regulator/qpnp-lcdb-regulator.c index 2c4003945d4d..31a202ec1008 100644 --- a/drivers/regulator/qpnp-lcdb-regulator.c +++ b/drivers/regulator/qpnp-lcdb-regulator.c @@ -991,7 +991,8 @@ static irqreturn_t qpnp_lcdb_sc_irq_handler(int irq, void *data) } #define MIN_BST_VOLTAGE_MV 4700 -#define MAX_BST_VOLTAGE_MV 6250 +#define PM660_MAX_BST_VOLTAGE_MV 6250 +#define MAX_BST_VOLTAGE_MV 6275 #define MIN_VOLTAGE_MV 4000 #define MAX_VOLTAGE_MV 6000 #define VOLTAGE_MIN_STEP_100_MV 4000 @@ -1017,8 +1018,14 @@ static int qpnp_lcdb_set_bst_voltage(struct qpnp_lcdb *lcdb, if (bst_voltage_mv < MIN_BST_VOLTAGE_MV) bst_voltage_mv = MIN_BST_VOLTAGE_MV; - else if (bst_voltage_mv > MAX_BST_VOLTAGE_MV) - bst_voltage_mv = MAX_BST_VOLTAGE_MV; + + if (pmic_subtype == PM660L_SUBTYPE) { + if (bst_voltage_mv > PM660_MAX_BST_VOLTAGE_MV) + bst_voltage_mv = PM660_MAX_BST_VOLTAGE_MV; + } else { + if (bst_voltage_mv > MAX_BST_VOLTAGE_MV) + bst_voltage_mv = MAX_BST_VOLTAGE_MV; + } if (bst_voltage_mv != bst->voltage_mv) { if (pmic_subtype == PM660L_SUBTYPE) { @@ -1883,6 +1890,8 @@ static int qpnp_lcdb_init_bst(struct qpnp_lcdb *lcdb) return rc; } lcdb->bst.soft_start_us = (val & SOFT_START_MASK) * 200 + 200; + if (!lcdb->bst.headroom_mv) + lcdb->bst.headroom_mv = PM660_BST_HEADROOM_DEFAULT_MV; } else { rc = qpnp_lcdb_read(lcdb, lcdb->base + LCDB_BST_SS_CTL_REG, &val, 1); @@ -1891,6 +1900,8 @@ static int qpnp_lcdb_init_bst(struct qpnp_lcdb *lcdb) return rc; } lcdb->bst.soft_start_us = soft_start_us[val & SOFT_START_MASK]; + if (!lcdb->bst.headroom_mv) + lcdb->bst.headroom_mv = BST_HEADROOM_DEFAULT_MV; } return 0; -- GitLab From edc0c32cc095d108523763cdef142525b01fba15 Mon Sep 17 00:00:00 2001 From: Skylar Chang Date: Wed, 11 Apr 2018 18:02:49 -0700 Subject: [PATCH 0166/1635] msm: ipa: enable hdr_metadata_reg_valid for usb Set the hdr_metadata_reg_valid to true on endpoint configuration when usb connected as rndis and ecm protocol for IPA_CLIENT_USB_PROD pipe. Change-Id: Ic08e95cdfdb72cbc8d915bde1f4b430c2edf7b81 Signed-off-by: Skylar Chang --- drivers/platform/msm/ipa/ipa_clients/ecm_ipa.c | 4 ++++ drivers/platform/msm/ipa/ipa_clients/rndis_ipa.c | 7 +++++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/drivers/platform/msm/ipa/ipa_clients/ecm_ipa.c b/drivers/platform/msm/ipa/ipa_clients/ecm_ipa.c index 95f78e45fa5e..f7c4dc43dacf 100644 --- a/drivers/platform/msm/ipa/ipa_clients/ecm_ipa.c +++ b/drivers/platform/msm/ipa/ipa_clients/ecm_ipa.c @@ -1442,6 +1442,10 @@ static int ecm_ipa_ep_registers_cfg(u32 usb_to_ipa_hdl, u32 ipa_to_usb_hdl, usb_to_ipa_ep_cfg.route.rt_tbl_hdl = 0; usb_to_ipa_ep_cfg.mode.dst = IPA_CLIENT_A5_LAN_WAN_CONS; usb_to_ipa_ep_cfg.mode.mode = IPA_BASIC; + + /* enable hdr_metadata_reg_valid */ + usb_to_ipa_ep_cfg.hdr.hdr_metadata_reg_valid = true; + result = ipa_cfg_ep(usb_to_ipa_hdl, &usb_to_ipa_ep_cfg); if (result) { ECM_IPA_ERROR("failed to configure USB to IPA point\n"); diff --git a/drivers/platform/msm/ipa/ipa_clients/rndis_ipa.c b/drivers/platform/msm/ipa/ipa_clients/rndis_ipa.c index ae42f54d9119..d607f9f8cb21 100644 --- a/drivers/platform/msm/ipa/ipa_clients/rndis_ipa.c +++ b/drivers/platform/msm/ipa/ipa_clients/rndis_ipa.c @@ -359,7 +359,7 @@ static struct ipa_ep_cfg usb_to_ipa_ep_cfg_deaggr_dis = { sizeof(struct rndis_pkt_hdr), .hdr_a5_mux = false, .hdr_remove_additional = false, - .hdr_metadata_reg_valid = false, + .hdr_metadata_reg_valid = true, }, .hdr_ext = { .hdr_pad_to_alignment = 0, @@ -406,7 +406,7 @@ static struct ipa_ep_cfg usb_to_ipa_ep_cfg_deaggr_en = { .hdr_ofst_pkt_size = 3 * sizeof(u32), .hdr_a5_mux = false, .hdr_remove_additional = false, - .hdr_metadata_reg_valid = false, + .hdr_metadata_reg_valid = true, }, .hdr_ext = { .hdr_pad_to_alignment = 0, @@ -2166,6 +2166,9 @@ static int rndis_ipa_ep_registers_cfg( ipa_to_usb_ep_cfg.aggr.aggr_time_limit, ipa_to_usb_ep_cfg.aggr.aggr_pkt_limit); + /* enable hdr_metadata_reg_valid */ + usb_to_ipa_ep_cfg->hdr.hdr_metadata_reg_valid = true; + result = ipa_cfg_ep(ipa_to_usb_hdl, &ipa_to_usb_ep_cfg); if (result) { pr_err("failed to configure IPA to USB end-point\n"); -- GitLab From 2ad451a7da32e0909f2c46fb347903736680c12a Mon Sep 17 00:00:00 2001 From: Mao Jinlong Date: Tue, 10 Apr 2018 18:30:52 +0800 Subject: [PATCH 0167/1635] alarmtimer: add rtc irq support for alarm Add the rtc irq support for alarmtimer to wakeup the alarm during system suspend. CRs-Fixed: 2261309 Change-Id: I41b774ed4e788359321e1c6a564551cc9cd40c8e Signed-off-by: Mao Jinlong --- kernel/time/alarmtimer.c | 35 +++++++++++++++++++++++++++++++---- 1 file changed, 31 insertions(+), 4 deletions(-) diff --git a/kernel/time/alarmtimer.c b/kernel/time/alarmtimer.c index ec09ce9a6012..789788cf0ba9 100644 --- a/kernel/time/alarmtimer.c +++ b/kernel/time/alarmtimer.c @@ -65,6 +65,19 @@ static struct rtc_timer rtctimer; static struct rtc_device *rtcdev; static DEFINE_SPINLOCK(rtcdev_lock); +static void alarmtimer_triggered_func(void *p) +{ + struct rtc_device *rtc = rtcdev; + + if (!(rtc->irq_data & RTC_AF)) + return; + __pm_wakeup_event(ws, 2 * MSEC_PER_SEC); +} + +static struct rtc_task alarmtimer_rtc_task = { + .func = alarmtimer_triggered_func +}; + /** * alarmtimer_get_rtcdev - Return selected rtcdevice * @@ -75,7 +88,7 @@ static DEFINE_SPINLOCK(rtcdev_lock); struct rtc_device *alarmtimer_get_rtcdev(void) { unsigned long flags; - struct rtc_device *ret; + struct rtc_device *ret = NULL; spin_lock_irqsave(&rtcdev_lock, flags); ret = rtcdev; @@ -89,6 +102,7 @@ static int alarmtimer_rtc_add_device(struct device *dev, struct class_interface *class_intf) { unsigned long flags; + int err = 0; struct rtc_device *rtc = to_rtc_device(dev); struct wakeup_source *__ws; @@ -97,8 +111,6 @@ static int alarmtimer_rtc_add_device(struct device *dev, if (!rtc->ops->set_alarm) return -1; - if (!device_may_wakeup(rtc->dev.parent)) - return -1; __ws = wakeup_source_register("alarmtimer"); @@ -109,17 +121,31 @@ static int alarmtimer_rtc_add_device(struct device *dev, return -1; } + err = rtc_irq_register(rtc, &alarmtimer_rtc_task); + if (err) + goto rtc_irq_reg_err; + rtcdev = rtc; /* hold a reference so it doesn't go away */ get_device(dev); ws = __ws; __ws = NULL; } + +rtc_irq_reg_err: spin_unlock_irqrestore(&rtcdev_lock, flags); wakeup_source_unregister(__ws); + return err; +} - return 0; +static void alarmtimer_rtc_remove_device(struct device *dev, + struct class_interface *class_intf) +{ + if (rtcdev && dev == &rtcdev->dev) { + rtc_irq_unregister(rtcdev, &alarmtimer_rtc_task); + rtcdev = NULL; + } } static inline void alarmtimer_rtc_timer_init(void) @@ -129,6 +155,7 @@ static inline void alarmtimer_rtc_timer_init(void) static struct class_interface alarmtimer_rtc_interface = { .add_dev = &alarmtimer_rtc_add_device, + .remove_dev = &alarmtimer_rtc_remove_device, }; static int alarmtimer_rtc_interface_setup(void) -- GitLab From 5625de0a643b2ceeb155e671e31abb4981f7d92a Mon Sep 17 00:00:00 2001 From: Fenglin Wu Date: Wed, 11 Apr 2018 08:02:08 +0800 Subject: [PATCH 0168/1635] ARM: dts: msm: Add battery profile data for mlp466076 battery Add the battery profile for mlp466076 battery which will be used on SM8150 QRD platform. Profile data is for GEN4 fuel gauge that is on PM855B based on characterization. Change-Id: I7067af625190a536f151b44b9d3858ac6161f3d6 Signed-off-by: Fenglin Wu --- ...fg-gen4-batterydata-mlp466076-3250mah.dtsi | 139 ++++++++++++++++++ 1 file changed, 139 insertions(+) create mode 100644 arch/arm64/boot/dts/qcom/fg-gen4-batterydata-mlp466076-3250mah.dtsi diff --git a/arch/arm64/boot/dts/qcom/fg-gen4-batterydata-mlp466076-3250mah.dtsi b/arch/arm64/boot/dts/qcom/fg-gen4-batterydata-mlp466076-3250mah.dtsi new file mode 100644 index 000000000000..3a31cbdf6592 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/fg-gen4-batterydata-mlp466076-3250mah.dtsi @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +qcom,mlp466076_3250mah_averaged_masterslave_mar27th2018 { + /* #mlp466076_3250mAh_averaged_MasterSlave_Mar27th2018 */ + qcom,max-voltage-uv = <4400000>; + qcom,fastchg-current-ma = <6000000>; + qcom,jeita-fcc-ranges = <0 150 650000 + 151 450 4875000 + 451 550 1625000>; + qcom,jeita-fv-ranges = <0 150 4150000 + 151 450 4400000 + 451 550 4150000>; + qcom,batt-id-kohm = <133>; + qcom,battery-beta = <4250>; + qcom,therm-room-temp = <100000>; + qcom,fg-cc-cv-threshold-mv = <4390>; + qcom,battery-type = "mlp466076_3250mah_mar27th2018"; + qcom,therm-coefficients = <0x2318 0xd0c 0xdaf7 0xc556 0x848d>; + qcom,therm-center-offset = <0x70>; + qcom,checksum = <0xC5FF>; + qcom,gui-version = "PM855GUI - 0.0.0.32"; + qcom,fg-profile-data = [ + 09 00 31 EA + 85 C4 5A BA + 33 AA 00 00 + EE BC 66 8B + F6 87 AC 95 + 78 9A D2 87 + 2F 00 6C 0C + EF 02 B0 04 + 41 02 CE 07 + 00 00 A6 00 + 70 07 CD 06 + 64 14 66 25 + 55 1C 06 0A + E8 3A C0 43 + 40 00 37 00 + 40 00 4D 00 + 41 00 33 00 + 38 00 3B 00 + 43 00 4C 00 + 40 00 40 00 + 3E 00 3B 00 + 34 00 32 00 + 2F 00 56 00 + 4A 64 42 00 + 49 00 40 08 + 40 00 36 00 + 36 00 40 10 + 3C 10 36 00 + 64 28 4A 48 + 3E 60 39 0C + 40 00 D8 00 + 66 20 C1 0C + C7 02 61 FE + 2A 1C EA 0B + 5A 0D A2 22 + F6 17 3A 42 + 2E 55 7F 02 + 71 13 47 20 + B9 04 2E 0B + 9E 05 D4 1C + D5 03 F7 05 + 4D 02 8C 18 + D4 22 B5 45 + 90 52 7F 14 + AE 20 60 04 + 68 CB 66 AD + DC 1C 7C D1 + B1 05 D3 BA + 78 18 AA 8A + FD 85 18 92 + 8F A0 09 80 + 43 00 82 FC + 33 03 25 02 + 00 F8 FE EC + F4 DB F1 F7 + 68 0B EA 14 + 71 20 20 18 + A6 1E BD 03 + C8 05 54 01 + CE 07 32 00 + 15 03 4D 02 + 90 02 35 04 + 01 03 1D 03 + 47 03 DB 02 + 52 05 40 00 + 3B 00 3E 00 + 3F 64 40 00 + 41 00 3E 08 + 43 F8 40 00 + 40 08 40 10 + 40 10 36 00 + 3F 28 42 48 + 42 60 47 0C + 38 00 39 00 + 3F 08 40 00 + 40 00 40 00 + 2F 10 3D 10 + 3B 00 42 20 + 53 40 37 58 + 3D 0E 41 00 + 40 00 40 08 + D8 00 28 20 + 94 05 44 0A + 23 0D 8F 1C + 08 22 3D 45 + C4 52 4F 18 + 41 02 26 05 + 86 02 6A 11 + 3F 0A EA 1F + 59 05 BC 02 + FA 05 A2 1C + 77 03 92 05 + A5 02 84 18 + A0 03 34 04 + C6 02 67 00 + E9 1F 2B 05 + FE 02 A8 05 + C4 1C 83 02 + F1 04 66 03 + A6 18 FC 02 + 65 05 28 03 + 71 00 61 01 + C0 00 FA 00 + 38 0D 00 00 + ]; +}; -- GitLab From 2b99dc1761849cc50df2160a4bc821396a1734eb Mon Sep 17 00:00:00 2001 From: Srinivas Ramana Date: Wed, 4 Apr 2018 11:42:04 +0530 Subject: [PATCH 0169/1635] drivers: soc: qcom: Add sdm640 SoC llcc driver Add LLCC driver which contains the configuration data required to program the LLCC on SDM640 SoC. The configration data controls the behavior of LLCC by setting priority, size, how the ways are allocated when clients use the LLCC and so on. Platform specific driver calls into the common LLCC driver to program this configuration. Change-Id: Ie53c7087bd90dbdbc5c207c8994a93e6a8479941 Signed-off-by: Srinivas Ramana --- .../devicetree/bindings/arm/msm/qcom,llcc.txt | 4 +- drivers/soc/qcom/Kconfig | 8 ++ drivers/soc/qcom/Makefile | 1 + drivers/soc/qcom/llcc-sdm640.c | 104 ++++++++++++++++++ 4 files changed, 115 insertions(+), 2 deletions(-) create mode 100644 drivers/soc/qcom/llcc-sdm640.c diff --git a/Documentation/devicetree/bindings/arm/msm/qcom,llcc.txt b/Documentation/devicetree/bindings/arm/msm/qcom,llcc.txt index f2d6cd9dfa64..fb96c49c112c 100644 --- a/Documentation/devicetree/bindings/arm/msm/qcom,llcc.txt +++ b/Documentation/devicetree/bindings/arm/msm/qcom,llcc.txt @@ -93,8 +93,8 @@ compatible devices: qcom,sdm845-llcc, qcom,sdm670-llcc, qcom,sm8150-llcc, - qcom,sdmshrike-llcc - + qcom,sdmshrike-llcc, + qcom,sdm640-llcc Example: diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig index 5f7e37bcb8ac..de13a1e48bf0 100644 --- a/drivers/soc/qcom/Kconfig +++ b/drivers/soc/qcom/Kconfig @@ -67,6 +67,14 @@ config QCOM_SDMSHRIKE_LLCC data required to configure LLCC so that clients can start using the LLCC slices. +config QCOM_SDM640_LLCC + tristate "Qualcomm Technologies, Inc. SDM640 LLCC driver" + depends on QCOM_LLCC + help + Say yes here to enable the LLCC driver for SDM640. This is provides + data required to configure LLCC so that clients can start using the + LLCC slices. + config QCOM_LLCC_AMON tristate "Qualcomm Technologies, Inc. LLCC Activity Monitor(AMON) driver" depends on QCOM_LLCC diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile index 7a02a524f99f..0c8797fdee82 100644 --- a/drivers/soc/qcom/Makefile +++ b/drivers/soc/qcom/Makefile @@ -7,6 +7,7 @@ obj-$(CONFIG_QCOM_MDT_LOADER) += mdt_loader.o obj-$(CONFIG_QCOM_LLCC) += llcc-core.o llcc-slice.o obj-$(CONFIG_QCOM_SM8150_LLCC) += llcc-sm8150.o obj-$(CONFIG_QCOM_SDMSHRIKE_LLCC) += llcc-sdmshrike.o +obj-$(CONFIG_QCOM_SDM640_LLCC) += llcc-sdm640.o obj-$(CONFIG_QCOM_LLCC_AMON) += llcc-amon.o obj-$(CONFIG_QCOM_PM) += spm.o obj-$(CONFIG_QCOM_QMI_HELPERS) += qmi_helpers.o diff --git a/drivers/soc/qcom/llcc-sdm640.c b/drivers/soc/qcom/llcc-sdm640.c new file mode 100644 index 000000000000..61c3cae66d9b --- /dev/null +++ b/drivers/soc/qcom/llcc-sdm640.c @@ -0,0 +1,104 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include + +/* + * SCT entry contains of the following parameters + * name: Name of the client's use case for which the llcc slice is used + * uid: Unique id for the client's use case + * slice_id: llcc slice id for each client + * max_cap: The maximum capacity of the cache slice provided in KB + * priority: Priority of the client used to select victim line for replacement + * fixed_size: Determine of the slice has a fixed capacity + * bonus_ways: Bonus ways to be used by any slice, bonus way is used only if + * it't not a reserved way. + * res_ways: Reserved ways for the cache slice, the reserved ways cannot be used + * by any other client than the one its assigned to. + * cache_mode: Each slice operates as a cache, this controls the mode of the + * slice normal or TCM + * probe_target_ways: Determines what ways to probe for access hit. When + * configured to 1 only bonus and reseved ways are probed. + * when configured to 0 all ways in llcc are probed. + * dis_cap_alloc: Disable capacity based allocation for a client + * retain_on_pc: If this bit is set and client has maitained active vote + * then the ways assigned to this client are not flushed on power + * collapse. + * activate_on_init: Activate the slice immidiately after the SCT is programmed + */ +#define SCT_ENTRY(n, uid, sid, mc, p, fs, bway, rway, cmod, ptw, dca, rp, a) \ + { \ + .name = n, \ + .usecase_id = uid, \ + .slice_id = sid, \ + .max_cap = mc, \ + .priority = p, \ + .fixed_size = fs, \ + .bonus_ways = bway, \ + .res_ways = rway, \ + .cache_mode = cmod, \ + .probe_target_ways = ptw, \ + .dis_cap_alloc = dca, \ + .retain_on_pc = rp, \ + .activate_on_init = a, \ + } + +static struct llcc_slice_config sdm640_data[] = { + SCT_ENTRY("cpuss", 1, 1, 256, 1, 0, 0x3, 0x0, 0, 0, 0, 1, 1), + SCT_ENTRY("rotator", 4, 4, 256, 2, 1, 0x3, 0x0, 2, 0, 0, 1, 0), + SCT_ENTRY("voice", 5, 5, 256, 1, 0, 0x3, 0x0, 0, 0, 0, 1, 0), + SCT_ENTRY("audio", 6, 6, 256, 1, 0, 0x3, 0x0, 0, 0, 0, 1, 0), + SCT_ENTRY("modem", 8, 8, 256, 1, 0, 0x3, 0x0, 0, 0, 0, 1, 0), + SCT_ENTRY("gpu", 12, 12, 0, 1, 0, 0x3, 0x0, 0, 0, 0, 1, 0), + SCT_ENTRY("mmuhwt", 13, 13, 256, 1, 0, 0x3, 0x0, 0, 0, 0, 0, 1), + SCT_ENTRY("audiohw", 22, 22, 256, 1, 1, 0x3, 0x0, 0, 0, 0, 1, 0), +}; + +static int sdm640_qcom_llcc_probe(struct platform_device *pdev) +{ + return qcom_llcc_probe(pdev, sdm640_data, + ARRAY_SIZE(sdm640_data)); +} + +static const struct of_device_id sdm640_qcom_llcc_of_match[] = { + { .compatible = "qcom,sdm640-llcc", }, + { }, +}; + +static struct platform_driver sdm640_qcom_llcc_driver = { + .driver = { + .name = "sdm640-llcc", + .owner = THIS_MODULE, + .of_match_table = sdm640_qcom_llcc_of_match, + }, + .probe = sdm640_qcom_llcc_probe, + .remove = qcom_llcc_remove, +}; + +static int __init sdm640_init_qcom_llcc_init(void) +{ + return platform_driver_register(&sdm640_qcom_llcc_driver); +} +module_init(sdm640_init_qcom_llcc_init); + +static void __exit sdm640_exit_qcom_llcc_exit(void) +{ + platform_driver_unregister(&sdm640_qcom_llcc_driver); +} +module_exit(sdm640_exit_qcom_llcc_exit); + +MODULE_DESCRIPTION("Qualcomm Technologies Inc sdm640 LLCC driver"); +MODULE_LICENSE("GPL v2"); -- GitLab From 3075a911f35d961a99c6139821f5273d66116ca0 Mon Sep 17 00:00:00 2001 From: Srinivas Ramana Date: Wed, 4 Apr 2018 11:57:15 +0530 Subject: [PATCH 0170/1635] defconfig: msm: Enable LLCC driver for sdm640 Enable LLC driver in SDM640 defconfig to help program LLCC configuration. Change-Id: I9d9ae7902f2be92477163fba54939f5f744c30e9 Signed-off-by: Srinivas Ramana --- arch/arm64/configs/sdm640-perf_defconfig | 2 +- arch/arm64/configs/sdm640_defconfig | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm64/configs/sdm640-perf_defconfig b/arch/arm64/configs/sdm640-perf_defconfig index ddc26f4d1ad2..4e0728e8e4e2 100644 --- a/arch/arm64/configs/sdm640-perf_defconfig +++ b/arch/arm64/configs/sdm640-perf_defconfig @@ -442,7 +442,7 @@ CONFIG_RPMSG_CHAR=y CONFIG_RPMSG_QCOM_GLINK_SMEM=y CONFIG_QCOM_RUN_QUEUE_STATS=y CONFIG_QCOM_LLCC=y -CONFIG_QCOM_SM8150_LLCC=y +CONFIG_QCOM_SDM640_LLCC=y CONFIG_QCOM_QMI_HELPERS=y CONFIG_QCOM_SMEM=y CONFIG_QCOM_MEMORY_DUMP_V2=y diff --git a/arch/arm64/configs/sdm640_defconfig b/arch/arm64/configs/sdm640_defconfig index f46e79f7f86a..20e542df881a 100644 --- a/arch/arm64/configs/sdm640_defconfig +++ b/arch/arm64/configs/sdm640_defconfig @@ -456,7 +456,7 @@ CONFIG_RPMSG_CHAR=y CONFIG_RPMSG_QCOM_GLINK_SMEM=y CONFIG_QCOM_RUN_QUEUE_STATS=y CONFIG_QCOM_LLCC=y -CONFIG_QCOM_SM8150_LLCC=y +CONFIG_QCOM_SDM640_LLCC=y CONFIG_QCOM_QMI_HELPERS=y CONFIG_QCOM_SMEM=y CONFIG_QCOM_MEMORY_DUMP_V2=y -- GitLab From b4fd8fc10f85608bcf5ede35b2b9f3987578a92e Mon Sep 17 00:00:00 2001 From: Srinivas Ramana Date: Wed, 4 Apr 2018 16:02:13 +0530 Subject: [PATCH 0171/1635] ARM: dts: msm: ADD llcc device node for sdm640 Add llcc device node on sdm640 to enable the llcc driver and thereby llcc configurations. Change-Id: I2fe84a52d93bab37542b6cb9aaa0fe19e80525ae Signed-off-by: Srinivas Ramana --- arch/arm64/boot/dts/qcom/sdm640.dtsi | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sdm640.dtsi b/arch/arm64/boot/dts/qcom/sdm640.dtsi index 7a295f661a3b..45693549627f 100644 --- a/arch/arm64/boot/dts/qcom/sdm640.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm640.dtsi @@ -856,6 +856,31 @@ compatible = "qcom,cmd-db"; reg = <0xc3f000c 8>; }; + + qcom,llcc@9200000 { + compatible = "qcom,llcc-core", "syscon", "simple-mfd"; + reg = <0x9200000 0x450000>; + reg-names = "llcc_base"; + qcom,llcc-banks-off = <0x0>; + qcom,llcc-broadcast-off = <0x400000>; + + llcc: qcom,sdm640-llcc { + compatible = "qcom,sdm640-llcc"; + #cache-cells = <1>; + max-slices = <32>; + cap-based-alloc-and-pwr-collapse; + }; + + qcom,llcc-erp { + compatible = "qcom,llcc-erp"; + interrupt-names = "ecc_irq"; + interrupts = ; + }; + + qcom,llcc-amon { + compatible = "qcom,llcc-amon"; + }; + }; }; #include "sdm640-pinctrl.dtsi" -- GitLab From eb9640dc6687d431ae390fbd2cc3771545aa3b98 Mon Sep 17 00:00:00 2001 From: Srinivas Ramana Date: Wed, 11 Apr 2018 11:02:26 +0530 Subject: [PATCH 0172/1635] ARM: dts: msm: Add device tree overlay for sdm640 Add device tree files required to build sdm640 with overlay support. Change-Id: I51ccd9d34b859d0d3b5b3646586fcd27ee919d18 Signed-off-by: Srinivas Ramana --- arch/arm64/boot/dts/qcom/Makefile | 13 ++++++++++ .../boot/dts/qcom/sdm640-cdp-overlay.dts | 24 +++++++++++++++++++ .../boot/dts/qcom/sdm640-mtp-overlay.dts | 24 +++++++++++++++++++ .../boot/dts/qcom/sdm640-qrd-overlay.dts | 24 +++++++++++++++++++ .../boot/dts/qcom/sdm640-rumi-overlay.dts | 24 +++++++++++++++++++ arch/arm64/boot/dts/qcom/sdm640.dts | 21 ++++++++++++++++ 6 files changed, 130 insertions(+) create mode 100644 arch/arm64/boot/dts/qcom/sdm640-cdp-overlay.dts create mode 100644 arch/arm64/boot/dts/qcom/sdm640-mtp-overlay.dts create mode 100644 arch/arm64/boot/dts/qcom/sdm640-qrd-overlay.dts create mode 100644 arch/arm64/boot/dts/qcom/sdm640-rumi-overlay.dts create mode 100644 arch/arm64/boot/dts/qcom/sdm640.dts diff --git a/arch/arm64/boot/dts/qcom/Makefile b/arch/arm64/boot/dts/qcom/Makefile index 72bc792e22c7..574a1b85fa0e 100644 --- a/arch/arm64/boot/dts/qcom/Makefile +++ b/arch/arm64/boot/dts/qcom/Makefile @@ -40,10 +40,23 @@ dtb-$(CONFIG_ARCH_SDMSHRIKE) += sdmshrike-rumi.dtb \ sdmshrike-mtp.dtb \ sdmshrike-cdp.dtb +ifeq ($(CONFIG_BUILD_ARM64_DT_OVERLAY),y) + dtbo-$(CONFIG_ARCH_SDM640) += \ + sdm640-cdp-overlay.dtbo \ + sdm640-mtp-overlay.dtbo \ + sdm640-rumi-overlay.dtbo \ + sdm640-qrd-overlay.dtbo \ + +sdm640-cdp-overlay.dtbo-base := sdm640.dtb +sdm640-mtp-overlay.dtbo-base := sdm640.dtb +sdm640-rumi-overlay.dtbo-base := sdm640.dtb +sdm640-qrd-overlay.dtbo-base := sdm640.dtb +else dtb-$(CONFIG_ARCH_SDM640) += sdm640-rumi.dtb \ sdm640-mtp.dtb \ sdm640-cdp.dtb \ sdm640-qrd.dtb +endif ifeq ($(CONFIG_ARM64),y) always := $(dtb-y) diff --git a/arch/arm64/boot/dts/qcom/sdm640-cdp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm640-cdp-overlay.dts new file mode 100644 index 000000000000..ee9624342bf1 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm640-cdp-overlay.dts @@ -0,0 +1,24 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/dts-v1/; +/plugin/; + +#include + +#include "sdm640-cdp.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDM640 CDP"; + compatible = "qcom,sdm640-cdp", "qcom,sdm640", "qcom,cdp"; + qcom,board-id = <1 0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm640-mtp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm640-mtp-overlay.dts new file mode 100644 index 000000000000..db566fcc43ab --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm640-mtp-overlay.dts @@ -0,0 +1,24 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/dts-v1/; +/plugin/; + +#include + +#include "sdm640-mtp.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDM640 MTP"; + compatible = "qcom,sdm640-mtp", "qcom,sdm640", "qcom,mtp"; + qcom,board-id = <8 0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm640-qrd-overlay.dts b/arch/arm64/boot/dts/qcom/sdm640-qrd-overlay.dts new file mode 100644 index 000000000000..df0d066520b7 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm640-qrd-overlay.dts @@ -0,0 +1,24 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/dts-v1/; +/plugin/; + +#include + +#include "sdm640-qrd.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDM640 QRD"; + compatible = "qcom,sdm640-qrd", "qcom,sdm640", "qcom,qrd"; + qcom,board-id = <11 0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm640-rumi-overlay.dts b/arch/arm64/boot/dts/qcom/sdm640-rumi-overlay.dts new file mode 100644 index 000000000000..99df00b141ae --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm640-rumi-overlay.dts @@ -0,0 +1,24 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/dts-v1/; +/plugin/; + +#include + +#include "sdm640-rumi.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDM640 RUMI"; + compatible = "qcom,sdm640-rumi", "qcom,sdm640", "qcom,rumi"; + qcom,board-id = <15 0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm640.dts b/arch/arm64/boot/dts/qcom/sdm640.dts new file mode 100644 index 000000000000..e03818f554e1 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm640.dts @@ -0,0 +1,21 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/dts-v1/; + +#include "sdm640.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDM640 SoC"; + compatible = "qcom,sdm640"; + qcom,board-id = <0 0>; +}; -- GitLab From af7e419a9ebfd4031503393d9dac631232bb000d Mon Sep 17 00:00:00 2001 From: Srinivas Ramana Date: Wed, 21 Mar 2018 23:57:51 +0530 Subject: [PATCH 0173/1635] defconfig: msm: use codename for sdm640 defconfigs use code name for sdm640 defconfig files so that android builds doesn't have to expose soc name. Change-Id: I603708d9a49439f7899b6bce36741c79dfd4df95 Signed-off-by: Srinivas Ramana --- .../configs/{sdm640-perf_defconfig => sdmsteppe-perf_defconfig} | 0 arch/arm64/configs/{sdm640_defconfig => sdmsteppe_defconfig} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename arch/arm64/configs/{sdm640-perf_defconfig => sdmsteppe-perf_defconfig} (100%) rename arch/arm64/configs/{sdm640_defconfig => sdmsteppe_defconfig} (100%) diff --git a/arch/arm64/configs/sdm640-perf_defconfig b/arch/arm64/configs/sdmsteppe-perf_defconfig similarity index 100% rename from arch/arm64/configs/sdm640-perf_defconfig rename to arch/arm64/configs/sdmsteppe-perf_defconfig diff --git a/arch/arm64/configs/sdm640_defconfig b/arch/arm64/configs/sdmsteppe_defconfig similarity index 100% rename from arch/arm64/configs/sdm640_defconfig rename to arch/arm64/configs/sdmsteppe_defconfig -- GitLab From 17f79169176093da87699638515c718353d343a7 Mon Sep 17 00:00:00 2001 From: Prateek Sood Date: Wed, 11 Apr 2018 16:35:33 +0530 Subject: [PATCH 0174/1635] ARM: dts: msm: Update IMEM base address for sdm640 Update base address of shared IMEM for sdm640. Change-Id: I2061f57098c3a2d704e40db51cc23e4cc4727108 Signed-off-by: Prateek Sood --- arch/arm64/boot/dts/qcom/sdm640.dtsi | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sdm640.dtsi b/arch/arm64/boot/dts/qcom/sdm640.dtsi index 7a295f661a3b..4dc97222b728 100644 --- a/arch/arm64/boot/dts/qcom/sdm640.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm640.dtsi @@ -617,10 +617,10 @@ interrupts = <1 5 4>; }; - qcom,msm-imem@146bf000 { + qcom,msm-imem@146aa000 { compatible = "qcom,msm-imem"; - reg = <0x146bf000 0x1000>; - ranges = <0x0 0x146bf000 0x1000>; + reg = <0x146aa000 0x1000>; + ranges = <0x0 0x146aa000 0x1000>; #address-cells = <1>; #size-cells = <1>; -- GitLab From 5e4a6df770db08ca41dcdc0dd8ad551a45835583 Mon Sep 17 00:00:00 2001 From: Maria Yu Date: Fri, 22 Sep 2017 16:02:01 +0800 Subject: [PATCH 0175/1635] sched: Fix for 32 bit compilation issue Incompatible pointer type found by the compiler which do_div need to have u64 for first parameter. Change-Id: If44ee3569de70dd63debac46a25a96f0b558c29f Signed-off-by: Maria Yu Signed-off-by: Lingutla Chandrasekhar --- kernel/sched/sched.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h index a42b349d2962..60ed50da5220 100644 --- a/kernel/sched/sched.h +++ b/kernel/sched/sched.h @@ -1953,7 +1953,7 @@ static inline unsigned long cpu_util_freq_pelt(int cpu) { struct rq *rq = cpu_rq(cpu); - unsigned long util = rq->cfs.avg.util_avg; + u64 util = rq->cfs.avg.util_avg; unsigned long capacity = capacity_orig_of(cpu); util *= (100 + per_cpu(sched_load_boost, cpu)); -- GitLab From 5641f26eed0db1edc26822b4a98c252c9c2435fc Mon Sep 17 00:00:00 2001 From: Lingutla Chandrasekhar Date: Mon, 19 Mar 2018 17:05:31 +0530 Subject: [PATCH 0176/1635] sched: fix 32 bit compilation errors arch_update_cpu_capacity() is used without including the corresponding header file, fix the compilation error by including the header. Change-Id: Ib55c200fb3d19603194cd119cabed75d7d7ce6ba Signed-off-by: Lingutla Chandrasekhar --- kernel/sched/energy.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/kernel/sched/energy.c b/kernel/sched/energy.c index ba7bb73a2fec..ad6ec358b86d 100644 --- a/kernel/sched/energy.c +++ b/kernel/sched/energy.c @@ -30,6 +30,8 @@ #include #include +#include "sched.h" + struct sched_group_energy *sge_array[NR_CPUS][NR_SD_LEVELS]; static void free_resources(void) -- GitLab From 3728ae4f44a174d9eb3b7cdedf75304eb5048bc0 Mon Sep 17 00:00:00 2001 From: Pavankumar Kondeti Date: Fri, 23 Feb 2018 09:53:22 +0530 Subject: [PATCH 0177/1635] trace/sched: Fix compilation for 32 bit systems do_div() expects the dividend to be a 64 bit type. We are passing an unsigned long to do_div() from sched_load_avg_task and sched_load_avg_cpu trace points. This breaks compilation on a 32 bit system. Change-Id: I9eb07dba1e62b68d5fc8d12e3f478b22c4ba5e0d Signed-off-by: Pavankumar Kondeti Git-commit: a2ee4e794559cf2ba17dd19117d18787e7c2838d Git-repo: https://android.googlesource.com/kernel/common/ [cslingutla@codeaurora.org: Fixed trivial merge conflicts] Signed-off-by: Lingutla Chandrasekhar --- include/trace/events/sched.h | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/include/trace/events/sched.h b/include/trace/events/sched.h index 720a708c1a17..344917831444 100644 --- a/include/trace/events/sched.h +++ b/include/trace/events/sched.h @@ -810,7 +810,7 @@ TRACE_EVENT(sched_load_avg_cpu, __field( unsigned long, load_avg ) __field( unsigned long, util_avg ) __field( unsigned long, util_avg_pelt ) - __field( unsigned long, util_avg_walt ) + __field( u32, util_avg_walt ) ), TP_fast_assign( @@ -820,16 +820,16 @@ TRACE_EVENT(sched_load_avg_cpu, __entry->util_avg_pelt = cfs_rq->avg.util_avg; __entry->util_avg_walt = 0; #ifdef CONFIG_SCHED_WALT - __entry->util_avg_walt = - cpu_rq(cpu)->prev_runnable_sum << SCHED_CAPACITY_SHIFT; - do_div(__entry->util_avg_walt, sched_ravg_window); + __entry->util_avg_walt = div64_ul(cpu_rq(cpu)->prev_runnable_sum, + sched_ravg_window >> SCHED_CAPACITY_SHIFT); + if (!walt_disabled && sysctl_sched_use_walt_cpu_util) __entry->util_avg = __entry->util_avg_walt; #endif ), TP_printk("cpu=%d load_avg=%lu util_avg=%lu " - "util_avg_pelt=%lu util_avg_walt=%lu", + "util_avg_pelt=%lu util_avg_walt=%u", __entry->cpu, __entry->load_avg, __entry->util_avg, __entry->util_avg_pelt, __entry->util_avg_walt) ); @@ -853,7 +853,7 @@ TRACE_EVENT(sched_load_se, __field( unsigned long, load ) __field( unsigned long, util ) __field( unsigned long, util_pelt ) - __field( unsigned long, util_walt ) + __field( u32, util_walt ) ), TP_fast_assign( @@ -873,8 +873,7 @@ TRACE_EVENT(sched_load_se, #ifdef CONFIG_SCHED_WALT if (!se->my_q) { struct task_struct *p = container_of(se, struct task_struct, se); - __entry->util_walt = ((unsigned long)(p->ravg.demand) << SCHED_CAPACITY_SHIFT); - do_div(__entry->util_walt, sched_ravg_window); + __entry->util_walt = p->ravg.demand / (sched_ravg_window >> SCHED_CAPACITY_SHIFT); if (!walt_disabled && sysctl_sched_use_walt_task_util) __entry->util = __entry->util_walt; } -- GitLab From 93b66a8afe655ea32156fc7bbe642fbb2a7c9bbc Mon Sep 17 00:00:00 2001 From: Mohammed Javid Date: Sat, 3 Mar 2018 11:13:51 +0530 Subject: [PATCH 0178/1635] msm: ipa3: Added retry logic if memory allocate fails Observing the memory allocation fails if no free emergency pool of memory not available. Added retry logic mechanism to allocate memory max 10 retry count with the sleep of 100ms Change-Id: I80f8872437352509d7526fc963c4bd1d7fb0ff06 Acked-by: Ashok Vuyyuru Signed-off-by: Mohammed Javid --- drivers/platform/msm/ipa/ipa_v3/ipa_dp.c | 13 +++++++++---- drivers/platform/msm/ipa/ipa_v3/ipa_utils.c | 18 +++++++++++++++++- 2 files changed, 26 insertions(+), 5 deletions(-) diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c b/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c index c5544e9e74cd..2462d80ad6a0 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c @@ -319,10 +319,12 @@ int ipa3_send(struct ipa3_sys_context *sys, for (i = 0; i < num_desc; i++) { tx_pkt = kmem_cache_zalloc(ipa3_ctx->tx_pkt_wrapper_cache, - mem_flag); - if (!tx_pkt) + GFP_ATOMIC); + if (!tx_pkt) { + IPAERR("failed to alloc tx wrapper\n"); + result = -ENOMEM; goto failure; - + } INIT_LIST_HEAD(&tx_pkt->link); if (i == 0) { @@ -336,6 +338,7 @@ int ipa3_send(struct ipa3_sys_context *sys, if (ipa_populate_tag_field(&desc[i], tx_pkt, &tag_pyld_ret)) { IPAERR("Failed to populate tag field\n"); + result = -EFAULT; goto failure_dma_map; } } @@ -375,6 +378,7 @@ int ipa3_send(struct ipa3_sys_context *sys, } if (dma_mapping_error(ipa3_ctx->pdev, tx_pkt->mem.phys_base)) { IPAERR("failed to do dma map.\n"); + result = -EFAULT; goto failure_dma_map; } @@ -421,6 +425,7 @@ int ipa3_send(struct ipa3_sys_context *sys, gsi_xfer, true); if (result != GSI_STATUS_SUCCESS) { IPAERR("GSI xfer failed.\n"); + result = -EFAULT; goto failure; } @@ -472,7 +477,7 @@ int ipa3_send(struct ipa3_sys_context *sys, } spin_unlock_bh(&sys->spinlock); - return -EFAULT; + return result; } /** diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c index ab4ba8a1ca90..e679d54f975e 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c @@ -4151,6 +4151,9 @@ static void ipa3_tag_free_skb(void *user1, int user2) } #define REQUIRED_TAG_PROCESS_DESCRIPTORS 4 +#define MAX_RETRY_ALLOC 10 +#define ALLOC_MIN_SLEEP_RX 100000 +#define ALLOC_MAX_SLEEP_RX 200000 /* ipa3_tag_process() - Initiates a tag process. Incorporates the input * descriptors @@ -4178,6 +4181,7 @@ int ipa3_tag_process(struct ipa3_desc desc[], int res; struct ipa3_tag_completion *comp; int ep_idx; + u32 retry_cnt = 0; /* Not enough room for the required descriptors for the tag process */ if (IPA_TAG_MAX_DESC - descs_num < REQUIRED_TAG_PROCESS_DESCRIPTORS) { @@ -4283,10 +4287,22 @@ int ipa3_tag_process(struct ipa3_desc desc[], tag_desc[desc_idx].callback = ipa3_tag_free_skb; tag_desc[desc_idx].user1 = dummy_skb; desc_idx++; - +retry_alloc: /* send all descriptors to IPA with single EOT */ res = ipa3_send(sys, desc_idx, tag_desc, true); if (res) { + if (res == -ENOMEM) { + if (retry_cnt < MAX_RETRY_ALLOC) { + IPADBG( + "failed to alloc memory retry cnt = %d\n", + retry_cnt); + retry_cnt++; + usleep_range(ALLOC_MIN_SLEEP_RX, + ALLOC_MAX_SLEEP_RX); + goto retry_alloc; + } + + } IPAERR("failed to send TAG packets %d\n", res); res = -ENOMEM; goto fail_free_skb; -- GitLab From ad437e5c383644d0c232d5518afbd8e0d897a59f Mon Sep 17 00:00:00 2001 From: Mohammed Javid Date: Fri, 16 Mar 2018 15:20:17 +0530 Subject: [PATCH 0179/1635] msm: ipa3: use atomic allocations for setup/teardown pipes Use GFP_ATOMIC flag for dma coherent allocations that can be called from user space. This change is to allow allocations even if the user space process has SIGKILL pending. Change-Id: Ia544252c91e559c47428006ca0522a51a7ab59c0 Acked-by: Ashok Vuyyuru Signed-off-by: Mohammed Javid --- drivers/platform/msm/ipa/ipa_v3/ipa_client.c | 4 ++-- drivers/platform/msm/ipa/ipa_v3/ipa_dp.c | 9 +++++++-- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_client.c b/drivers/platform/msm/ipa/ipa_v3/ipa_client.c index 29481263a1b6..afc30bf7209c 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_client.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_client.c @@ -196,7 +196,7 @@ static int ipa3_reconfigure_channel_to_gpi(struct ipa3_ep_context *ep, chan_props.ring_len = 2 * GSI_CHAN_RE_SIZE_16B; chan_props.ring_base_vaddr = dma_alloc_coherent(ipa3_ctx->pdev, chan_props.ring_len, - &chan_dma_addr, 0); + &chan_dma_addr, GFP_ATOMIC); chan_props.ring_base_addr = chan_dma_addr; chan_dma->base = chan_props.ring_base_vaddr; chan_dma->phys_base = chan_props.ring_base_addr; @@ -299,7 +299,7 @@ static int ipa3_reset_with_open_aggr_frame_wa(u32 clnt_hdl, memset(&xfer_elem, 0, sizeof(struct gsi_xfer_elem)); buff = dma_alloc_coherent(ipa3_ctx->pdev, 1, &dma_addr, - GFP_KERNEL); + GFP_ATOMIC); xfer_elem.addr = dma_addr; xfer_elem.len = 1; xfer_elem.flags = GSI_XFER_FLAG_EOT; diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c b/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c index c5544e9e74cd..10bd98a17dbb 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c @@ -3626,6 +3626,11 @@ static int ipa_gsi_setup_channel(struct ipa_sys_connect_params *in, dma_addr_t dma_addr; dma_addr_t evt_dma_addr; int result; + gfp_t mem_flag = GFP_KERNEL; + + if (in->client == IPA_CLIENT_APPS_WAN_CONS || + in->client == IPA_CLIENT_APPS_WAN_PROD) + mem_flag = GFP_ATOMIC; if (!ep) { IPAERR("EP context is empty\n"); @@ -3663,7 +3668,7 @@ static int ipa_gsi_setup_channel(struct ipa_sys_connect_params *in, gsi_evt_ring_props.ring_base_vaddr = dma_alloc_coherent(ipa3_ctx->pdev, gsi_evt_ring_props.ring_len, - &evt_dma_addr, GFP_KERNEL); + &evt_dma_addr, mem_flag); if (!gsi_evt_ring_props.ring_base_vaddr) { IPAERR("fail to dma alloc %u bytes\n", gsi_evt_ring_props.ring_len); @@ -3738,7 +3743,7 @@ static int ipa_gsi_setup_channel(struct ipa_sys_connect_params *in, gsi_channel_props.ring_len = 2 * in->desc_fifo_sz; gsi_channel_props.ring_base_vaddr = dma_alloc_coherent(ipa3_ctx->pdev, gsi_channel_props.ring_len, - &dma_addr, GFP_KERNEL); + &dma_addr, mem_flag); if (!gsi_channel_props.ring_base_vaddr) { IPAERR("fail to dma alloc %u bytes\n", gsi_channel_props.ring_len); -- GitLab From 0bc82eae125676f85a47f7b23fa26e835182eb73 Mon Sep 17 00:00:00 2001 From: Shiraz Saleem Date: Fri, 22 Dec 2017 09:46:59 -0600 Subject: [PATCH 0180/1635] i40iw: Fix sequence number for the first partial FPDU [ Upstream commit df8b13a1b23356d01dfc4647a5629cdb0f4ce566 ] Partial FPDU processing is broken as the sequence number for the first partial FPDU is wrong due to incorrect Q2 buffer offset. The offset should be 64 rather than 16. Fixes: 786c6adb3a94 ("i40iw: add puda code") Signed-off-by: Shiraz Saleem Signed-off-by: Jason Gunthorpe Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/infiniband/hw/i40iw/i40iw_d.h | 1 + drivers/infiniband/hw/i40iw/i40iw_puda.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/infiniband/hw/i40iw/i40iw_d.h b/drivers/infiniband/hw/i40iw/i40iw_d.h index 24eabcad5e40..019ad3b939f9 100644 --- a/drivers/infiniband/hw/i40iw/i40iw_d.h +++ b/drivers/infiniband/hw/i40iw/i40iw_d.h @@ -93,6 +93,7 @@ #define RDMA_OPCODE_MASK 0x0f #define RDMA_READ_REQ_OPCODE 1 #define Q2_BAD_FRAME_OFFSET 72 +#define Q2_FPSN_OFFSET 64 #define CQE_MAJOR_DRV 0x8000 #define I40IW_TERM_SENT 0x01 diff --git a/drivers/infiniband/hw/i40iw/i40iw_puda.c b/drivers/infiniband/hw/i40iw/i40iw_puda.c index 59f70676f0e0..14d38d733cb4 100644 --- a/drivers/infiniband/hw/i40iw/i40iw_puda.c +++ b/drivers/infiniband/hw/i40iw/i40iw_puda.c @@ -1376,7 +1376,7 @@ static void i40iw_ieq_handle_exception(struct i40iw_puda_rsrc *ieq, u32 *hw_host_ctx = (u32 *)qp->hw_host_ctx; u32 rcv_wnd = hw_host_ctx[23]; /* first partial seq # in q2 */ - u32 fps = qp->q2_buf[16]; + u32 fps = *(u32 *)(qp->q2_buf + Q2_FPSN_OFFSET); struct list_head *rxlist = &pfpdu->rxlist; struct list_head *plist; -- GitLab From c5cd3cc217a914975d969db99edea13ab6265283 Mon Sep 17 00:00:00 2001 From: Shiraz Saleem Date: Fri, 22 Dec 2017 09:46:56 -0600 Subject: [PATCH 0181/1635] i40iw: Correct Q1/XF object count equation [ Upstream commit fe99afd1febd74e0ef1fed7e3283f09effe1f4f0 ] Lower Inbound RDMA Read Queue (Q1) object count by a factor of 2 as it is incorrectly doubled. Also, round up Q1 and Transmit FIFO (XF) object count to power of 2 to satisfy hardware requirement. Fixes: 86dbcd0f12e9 ("i40iw: add file to handle cqp calls") Signed-off-by: Shiraz Saleem Signed-off-by: Jason Gunthorpe Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/infiniband/hw/i40iw/i40iw_ctrl.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/infiniband/hw/i40iw/i40iw_ctrl.c b/drivers/infiniband/hw/i40iw/i40iw_ctrl.c index d86f3e670804..472ef4d6e858 100644 --- a/drivers/infiniband/hw/i40iw/i40iw_ctrl.c +++ b/drivers/infiniband/hw/i40iw/i40iw_ctrl.c @@ -3875,8 +3875,10 @@ enum i40iw_status_code i40iw_config_fpm_values(struct i40iw_sc_dev *dev, u32 qp_ hmc_info->hmc_obj[I40IW_HMC_IW_APBVT_ENTRY].cnt = 1; hmc_info->hmc_obj[I40IW_HMC_IW_MR].cnt = mrwanted; - hmc_info->hmc_obj[I40IW_HMC_IW_XF].cnt = I40IW_MAX_WQ_ENTRIES * qpwanted; - hmc_info->hmc_obj[I40IW_HMC_IW_Q1].cnt = 4 * I40IW_MAX_IRD_SIZE * qpwanted; + hmc_info->hmc_obj[I40IW_HMC_IW_XF].cnt = + roundup_pow_of_two(I40IW_MAX_WQ_ENTRIES * qpwanted); + hmc_info->hmc_obj[I40IW_HMC_IW_Q1].cnt = + roundup_pow_of_two(2 * I40IW_MAX_IRD_SIZE * qpwanted); hmc_info->hmc_obj[I40IW_HMC_IW_XFFL].cnt = hmc_info->hmc_obj[I40IW_HMC_IW_XF].cnt / hmc_fpm_misc->xf_block_size; hmc_info->hmc_obj[I40IW_HMC_IW_Q1FL].cnt = -- GitLab From fbd4d9046a1a0f32b9a3b82871a1b3c7fd52a758 Mon Sep 17 00:00:00 2001 From: Tatyana Nikolova Date: Fri, 22 Dec 2017 09:47:01 -0600 Subject: [PATCH 0182/1635] i40iw: Validate correct IRD/ORD connection parameters [ Upstream commit ce9ce74145aa6814a370a9ff4f5a1d719baaced1 ] Casting to u16 before validating IRD/ORD connection parameters could cause recording wrong IRD/ORD values in the cm_node. Validate the IRD/ORD parameters as they are passed by the application before recording them. Fixes: f27b4746f378 ("i40iw: add connection management code") Signed-off-by: Tatyana Nikolova Signed-off-by: Shiraz Saleem Signed-off-by: Jason Gunthorpe Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/infiniband/hw/i40iw/i40iw_cm.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/infiniband/hw/i40iw/i40iw_cm.c b/drivers/infiniband/hw/i40iw/i40iw_cm.c index d6a1a308c6a0..b7f1ce5333cb 100644 --- a/drivers/infiniband/hw/i40iw/i40iw_cm.c +++ b/drivers/infiniband/hw/i40iw/i40iw_cm.c @@ -125,7 +125,8 @@ static u8 i40iw_derive_hw_ird_setting(u16 cm_ird) * @conn_ird: connection IRD * @conn_ord: connection ORD */ -static void i40iw_record_ird_ord(struct i40iw_cm_node *cm_node, u16 conn_ird, u16 conn_ord) +static void i40iw_record_ird_ord(struct i40iw_cm_node *cm_node, u32 conn_ird, + u32 conn_ord) { if (conn_ird > I40IW_MAX_IRD_SIZE) conn_ird = I40IW_MAX_IRD_SIZE; @@ -3841,7 +3842,7 @@ int i40iw_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param) } cm_node->apbvt_set = true; - i40iw_record_ird_ord(cm_node, (u16)conn_param->ird, (u16)conn_param->ord); + i40iw_record_ird_ord(cm_node, conn_param->ird, conn_param->ord); if (cm_node->send_rdma0_op == SEND_RDMA_READ_ZERO && !cm_node->ord_size) cm_node->ord_size = 1; -- GitLab From 800ffac107546b47329d74a72de71b9156836db2 Mon Sep 17 00:00:00 2001 From: Martin Blumenstingl Date: Sat, 23 Dec 2017 22:38:32 +0100 Subject: [PATCH 0183/1635] clk: meson: mpll: use 64-bit maths in params_from_rate [ Upstream commit 86aacdca66774051cbc0958110a48074b57a060b ] "rem * SDM_DEN" can easily overflow on the 32-bit Meson8 and Meson8b SoCs if the "remainder" (after the division operation) is greater than 262143Hz. This is likely to happen since the input clock for the MPLLs on Meson8 and Meson8b is "fixed_pll", which is running at a rate of 2550MHz. One example where this was observed to be problematic was the Ethernet clock calculation (which takes MPLL2 as input). When requesting a rate of 125MHz there is a remainder of 2500000Hz. The resulting MPLL2 rate before this patch was 127488329Hz. The resulting MPLL2 rate after this patch is 124999103Hz. Commit b609338b26f5 ("clk: meson: mpll: use 64bit math in rate_from_params") already fixed a similar issue in rate_from_params. Fixes: 007e6e5c5f01d3 ("clk: meson: mpll: add rw operation") Signed-off-by: Martin Blumenstingl Signed-off-by: Jerome Brunet Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/clk/meson/clk-mpll.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/meson/clk-mpll.c b/drivers/clk/meson/clk-mpll.c index 44a5a535ca63..5144360e2c80 100644 --- a/drivers/clk/meson/clk-mpll.c +++ b/drivers/clk/meson/clk-mpll.c @@ -98,7 +98,7 @@ static void params_from_rate(unsigned long requested_rate, *sdm = SDM_DEN - 1; } else { *n2 = div; - *sdm = DIV_ROUND_UP(rem * SDM_DEN, requested_rate); + *sdm = DIV_ROUND_UP_ULL((u64)rem * SDM_DEN, requested_rate); } } -- GitLab From 2e9a8b6a7d5263646ee5f45829f078d8a79e5aad Mon Sep 17 00:00:00 2001 From: Rasmus Villemoes Date: Thu, 16 Nov 2017 13:15:26 +0100 Subject: [PATCH 0184/1635] ARM: dts: ls1021a: add "fsl,ls1021a-esdhc" compatible string to esdhc node [ Upstream commit d5c7b4d5ac2237a6da7ced3adfe6b8bf769f8cc6 ] Commit a22950c888e3 (mmc: sdhci-of-esdhc: add quirk SDHCI_QUIRK_BROKEN_TIMEOUT_VAL for ls1021a) added logic to the driver to enable the broken timeout val quirk for ls1021a, but did not add the corresponding compatible string to the device tree, so it didn't really have any effect. Fix that. Signed-off-by: Rasmus Villemoes Signed-off-by: Shawn Guo Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/arm/boot/dts/ls1021a.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/ls1021a.dtsi b/arch/arm/boot/dts/ls1021a.dtsi index 9319e1f0f1d8..379b4a03cfe2 100644 --- a/arch/arm/boot/dts/ls1021a.dtsi +++ b/arch/arm/boot/dts/ls1021a.dtsi @@ -155,7 +155,7 @@ }; esdhc: esdhc@1560000 { - compatible = "fsl,esdhc"; + compatible = "fsl,ls1021a-esdhc", "fsl,esdhc"; reg = <0x0 0x1560000 0x0 0x10000>; interrupts = ; clock-frequency = <0>; -- GitLab From 78728d84f3380aea7569a95a0aa14b6f2cdf9a32 Mon Sep 17 00:00:00 2001 From: Ioan Moldovan Date: Mon, 28 Aug 2017 18:09:39 +0300 Subject: [PATCH 0185/1635] Bluetooth: Add a new 04ca:3015 QCA_ROME device [ Upstream commit 0a03f98b98c201191e3ba15a0e33f46d8660e1fd ] This patch adds the 04ca:3015 (from a QCA9377 board) Bluetooth device to the btusb blacklist and makes the kernel use the btqca module instead of btusb. The patch is necessary because, without it the 04ca:3015 device defaults to using the btusb driver, which makes the WIFI side of the QCA9377 board unusable (obtains 0 MBps in speedtest, when the 04ca:3015 bluetooth is used with an audio headset). /sys/kernel/debug/usb/devices: T: Bus=01 Lev=01 Prnt=01 Port=04 Cnt=01 Dev#= 2 Spd=12 MxCh= 0 D: Ver= 2.01 Cls=e0(wlcon) Sub=01 Prot=01 MxPS=64 #Cfgs= 1 P: Vendor=04ca ProdID=3015 Rev= 0.01 C:* #Ifs= 2 Cfg#= 1 Atr=e0 MxPwr=100mA I:* If#= 0 Alt= 0 #EPs= 3 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=81(I) Atr=03(Int.) MxPS= 16 Ivl=1ms E: Ad=82(I) Atr=02(Bulk) MxPS= 64 Ivl=0ms E: Ad=02(O) Atr=02(Bulk) MxPS= 64 Ivl=0ms I:* If#= 1 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 0 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 0 Ivl=1ms I: If#= 1 Alt= 1 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 9 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 9 Ivl=1ms I: If#= 1 Alt= 2 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 17 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 17 Ivl=1ms I: If#= 1 Alt= 3 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 25 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 25 Ivl=1ms I: If#= 1 Alt= 4 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 33 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 33 Ivl=1ms I: If#= 1 Alt= 5 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 49 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 49 Ivl=1ms Signed-off-by: Ioan Moldovan Signed-off-by: Johan Hedberg Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/bluetooth/btusb.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index b2c0306f97ed..e9dff868c028 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -277,6 +277,7 @@ static const struct usb_device_id blacklist_table[] = { { USB_DEVICE(0x0489, 0xe09f), .driver_info = BTUSB_QCA_ROME }, { USB_DEVICE(0x0489, 0xe0a2), .driver_info = BTUSB_QCA_ROME }, { USB_DEVICE(0x04ca, 0x3011), .driver_info = BTUSB_QCA_ROME }, + { USB_DEVICE(0x04ca, 0x3015), .driver_info = BTUSB_QCA_ROME }, { USB_DEVICE(0x04ca, 0x3016), .driver_info = BTUSB_QCA_ROME }, /* Broadcom BCM2035 */ -- GitLab From fd78be4b37cc6daf81fa19e3b415ca623acacab6 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Thu, 21 Dec 2017 17:32:24 +0100 Subject: [PATCH 0186/1635] ipv6: Reinject IPv6 packets if IPsec policy matches after SNAT [ Upstream commit 09ee9dba9611cd382fd360a99ad1c2fa23bfdca8 ] If SNAT modifies the source address the resulting packet might match an IPsec policy, reinject the packet if that's the case. The exact same thing is already done for IPv4. Signed-off-by: Tobias Brunner Acked-by: Steffen Klassert Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- net/ipv6/ip6_output.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index 3763dc01e374..0f874b48c1b5 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -138,6 +138,14 @@ static int ip6_finish_output(struct net *net, struct sock *sk, struct sk_buff *s return ret; } +#if defined(CONFIG_NETFILTER) && defined(CONFIG_XFRM) + /* Policy lookup after SNAT yielded a new policy */ + if (skb_dst(skb)->xfrm) { + IPCB(skb)->flags |= IPSKB_REROUTED; + return dst_output(net, sk, skb); + } +#endif + if ((skb->len > ip6_skb_dst_mtu(skb) && !skb_is_gso(skb)) || dst_allfrag(skb_dst(skb)) || (IP6CB(skb)->frag_max_size && skb->len > IP6CB(skb)->frag_max_size)) -- GitLab From ea40afb5c3798d9949a48a76f74ff5a5288e6976 Mon Sep 17 00:00:00 2001 From: Yi Zeng Date: Tue, 26 Dec 2017 19:22:26 +0800 Subject: [PATCH 0187/1635] thermal: power_allocator: fix one race condition issue for thermal_instances list [ Upstream commit a5de11d67dcd268b8d0beb73dc374de5e97f0caf ] When invoking allow_maximum_power and traverse tz->thermal_instances, we should grab thermal_zone_device->lock to avoid race condition. For example, during the system reboot, if the mali GPU device implements device shutdown callback and unregister GPU devfreq cooling device, the deleted list head may be accessed to cause panic, as the following log shows: [ 33.551070] c3 25 (kworker/3:0) Unable to handle kernel paging request at virtual address dead000000000070 [ 33.566708] c3 25 (kworker/3:0) pgd = ffffffc0ed290000 [ 33.572071] c3 25 (kworker/3:0) [dead000000000070] *pgd=00000001ed292003, *pud=00000001ed292003, *pmd=0000000000000000 [ 33.581515] c3 25 (kworker/3:0) Internal error: Oops: 96000004 [#1] PREEMPT SMP [ 33.599761] c3 25 (kworker/3:0) CPU: 3 PID: 25 Comm: kworker/3:0 Not tainted 4.4.35+ #912 [ 33.614137] c3 25 (kworker/3:0) Workqueue: events_freezable thermal_zone_device_check [ 33.620245] c3 25 (kworker/3:0) task: ffffffc0f32e4200 ti: ffffffc0f32f0000 task.ti: ffffffc0f32f0000 [ 33.629466] c3 25 (kworker/3:0) PC is at power_allocator_throttle+0x7c8/0x8a4 [ 33.636609] c3 25 (kworker/3:0) LR is at power_allocator_throttle+0x808/0x8a4 [ 33.643742] c3 25 (kworker/3:0) pc : [] lr : [] pstate: 20000145 [ 33.652874] c3 25 (kworker/3:0) sp : ffffffc0f32f3bb0 [ 34.468519] c3 25 (kworker/3:0) Process kworker/3:0 (pid: 25, stack limit = 0xffffffc0f32f0020) [ 34.477220] c3 25 (kworker/3:0) Stack: (0xffffffc0f32f3bb0 to 0xffffffc0f32f4000) [ 34.819822] c3 25 (kworker/3:0) Call trace: [ 34.824021] c3 25 (kworker/3:0) Exception stack(0xffffffc0f32f39c0 to 0xffffffc0f32f3af0) [ 34.924993] c3 25 (kworker/3:0) [] power_allocator_throttle+0x7c8/0x8a4 [ 34.933184] c3 25 (kworker/3:0) [] handle_thermal_trip.part.25+0x70/0x224 [ 34.941545] c3 25 (kworker/3:0) [] thermal_zone_device_update+0xc0/0x20c [ 34.949818] c3 25 (kworker/3:0) [] thermal_zone_device_check+0x20/0x2c [ 34.957924] c3 25 (kworker/3:0) [] process_one_work+0x168/0x458 [ 34.965414] c3 25 (kworker/3:0) [] worker_thread+0x13c/0x4b4 [ 34.972650] c3 25 (kworker/3:0) [] kthread+0xe8/0xfc [ 34.979187] c3 25 (kworker/3:0) [] ret_from_fork+0x10/0x40 [ 34.986244] c3 25 (kworker/3:0) Code: f9405e73 eb1302bf d102e273 54ffc460 (b9402a61) [ 34.994339] c3 25 (kworker/3:0) ---[ end trace 32057901e3b7e1db ]--- Signed-off-by: Yi Zeng Signed-off-by: Zhang Rui Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/thermal/power_allocator.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/thermal/power_allocator.c b/drivers/thermal/power_allocator.c index b4d3116cfdaf..3055f9a12a17 100644 --- a/drivers/thermal/power_allocator.c +++ b/drivers/thermal/power_allocator.c @@ -523,6 +523,7 @@ static void allow_maximum_power(struct thermal_zone_device *tz) struct thermal_instance *instance; struct power_allocator_params *params = tz->governor_data; + mutex_lock(&tz->lock); list_for_each_entry(instance, &tz->thermal_instances, tz_node) { if ((instance->trip != params->trip_max_desired_temperature) || (!cdev_is_power_actor(instance->cdev))) @@ -534,6 +535,7 @@ static void allow_maximum_power(struct thermal_zone_device *tz) mutex_unlock(&instance->cdev->lock); thermal_cdev_update(instance->cdev); } + mutex_unlock(&tz->lock); } /** -- GitLab From 3efc86f667fcf0f35c55cf6ca2461cbd5c94f2c7 Mon Sep 17 00:00:00 2001 From: Masami Hiramatsu Date: Sat, 9 Dec 2017 01:28:12 +0900 Subject: [PATCH 0188/1635] perf probe: Find versioned symbols from map [ Upstream commit 4b3a2716dd785fabb9f6ac80c1d53cb29a88169d ] Commit d80406453ad4 ("perf symbols: Allow user probes on versioned symbols") allows user to find default versioned symbols (with "@@") in map. However, it did not enable normal versioned symbol (with "@") for perf-probe. E.g. ===== # ./perf probe -x /lib64/libc-2.25.so malloc_get_state Failed to find symbol malloc_get_state in /usr/lib64/libc-2.25.so Error: Failed to add events. ===== This solves above issue by improving perf-probe symbol search function, as below. ===== # ./perf probe -x /lib64/libc-2.25.so malloc_get_state Added new event: probe_libc:malloc_get_state (on malloc_get_state in /usr/lib64/libc-2.25.so) You can now use it in all perf tools, such as: perf record -e probe_libc:malloc_get_state -aR sleep 1 # ./perf probe -l probe_libc:malloc_get_state (on malloc_get_state@GLIBC_2.2.5 in /usr/lib64/libc-2.25.so) ===== Signed-off-by: Masami Hiramatsu Reviewed-by: Thomas Richter Acked-by: Ravi Bangoria Tested-by: Arnaldo Carvalho de Melo Cc: Paul Clarke Cc: bhargavb Cc: linux-rt-users@vger.kernel.org Link: http://lkml.kernel.org/r/151275049269.24652.1639103455496216255.stgit@devbox Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- tools/perf/arch/powerpc/util/sym-handling.c | 8 ++++++++ tools/perf/util/probe-event.c | 20 ++++++++++++++++++-- tools/perf/util/symbol.c | 5 +++++ tools/perf/util/symbol.h | 1 + 4 files changed, 32 insertions(+), 2 deletions(-) diff --git a/tools/perf/arch/powerpc/util/sym-handling.c b/tools/perf/arch/powerpc/util/sym-handling.c index 9c4e23d8c8ce..53d83d7e6a09 100644 --- a/tools/perf/arch/powerpc/util/sym-handling.c +++ b/tools/perf/arch/powerpc/util/sym-handling.c @@ -64,6 +64,14 @@ int arch__compare_symbol_names_n(const char *namea, const char *nameb, return strncmp(namea, nameb, n); } + +const char *arch__normalize_symbol_name(const char *name) +{ + /* Skip over initial dot */ + if (name && *name == '.') + name++; + return name; +} #endif #if defined(_CALL_ELF) && _CALL_ELF == 2 diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index b7aaf9b2294d..c3cd3488fee7 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c @@ -2792,16 +2792,32 @@ static int find_probe_functions(struct map *map, char *name, int found = 0; struct symbol *sym; struct rb_node *tmp; + const char *norm, *ver; + char *buf = NULL; if (map__load(map) < 0) return 0; map__for_each_symbol(map, sym, tmp) { - if (strglobmatch(sym->name, name)) { + norm = arch__normalize_symbol_name(sym->name); + if (!norm) + continue; + + /* We don't care about default symbol or not */ + ver = strchr(norm, '@'); + if (ver) { + buf = strndup(norm, ver - norm); + if (!buf) + return -ENOMEM; + norm = buf; + } + if (strglobmatch(norm, name)) { found++; if (syms && found < probe_conf.max_probes) syms[found - 1] = sym; } + if (buf) + zfree(&buf); } return found; @@ -2847,7 +2863,7 @@ static int find_probe_trace_events_from_map(struct perf_probe_event *pev, * same name but different addresses, this lists all the symbols. */ num_matched_functions = find_probe_functions(map, pp->function, syms); - if (num_matched_functions == 0) { + if (num_matched_functions <= 0) { pr_err("Failed to find symbol %s in %s\n", pp->function, pev->target ? : "kernel"); ret = -ENOENT; diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index 6492ef38b090..4e8dd5fd45fd 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -93,6 +93,11 @@ static int prefix_underscores_count(const char *str) return tail - str; } +const char * __weak arch__normalize_symbol_name(const char *name) +{ + return name; +} + int __weak arch__compare_symbol_names(const char *namea, const char *nameb) { return strcmp(namea, nameb); diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h index 6352022593c6..698c65e603a8 100644 --- a/tools/perf/util/symbol.h +++ b/tools/perf/util/symbol.h @@ -347,6 +347,7 @@ bool elf__needs_adjust_symbols(GElf_Ehdr ehdr); void arch__sym_update(struct symbol *s, GElf_Sym *sym); #endif +const char *arch__normalize_symbol_name(const char *name); #define SYMBOL_A 0 #define SYMBOL_B 1 -- GitLab From d606bac136ec4c25a31830269a18aea66bd6cf0c Mon Sep 17 00:00:00 2001 From: Masami Hiramatsu Date: Sat, 9 Dec 2017 01:26:46 +0900 Subject: [PATCH 0189/1635] perf probe: Add warning message if there is unexpected event name [ Upstream commit 9f5c6d8777a2d962b0eeacb2a16f37da6bea545b ] This improve the error message so that user can know event-name error before writing new events to kprobe-events interface. E.g. ====== #./perf probe -x /lib64/libc-2.25.so malloc_get_state* Internal error: "malloc_get_state@GLIBC_2" is an invalid event name. Error: Failed to add events. ====== Reported-by: Arnaldo Carvalho de Melo Signed-off-by: Masami Hiramatsu Acked-by: Ravi Bangoria Reviewed-by: Thomas Richter Tested-by: Arnaldo Carvalho de Melo Cc: Paul Clarke Cc: bhargavb Cc: linux-rt-users@vger.kernel.org Link: http://lkml.kernel.org/r/151275040665.24652.5188568529237584489.stgit@devbox Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- tools/perf/util/probe-event.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index c3cd3488fee7..68786bb7790e 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c @@ -2625,6 +2625,14 @@ static int get_new_event_name(char *buf, size_t len, const char *base, out: free(nbase); + + /* Final validation */ + if (ret >= 0 && !is_c_func_name(buf)) { + pr_warning("Internal error: \"%s\" is an invalid event name.\n", + buf); + ret = -EINVAL; + } + return ret; } -- GitLab From 93b8f4a2302b68d42bd384076c846f86a8decda4 Mon Sep 17 00:00:00 2001 From: Mengting Zhang Date: Wed, 13 Dec 2017 15:01:53 +0800 Subject: [PATCH 0190/1635] perf evsel: Enable ignore_missing_thread for pid option [ Upstream commit ca8000684ec4e66f965e1f9547a3c6cb834154ca ] While monitoring a multithread process with pid option, perf sometimes may return sys_perf_event_open failure with 3(No such process) if any of the process's threads die before we open the event. However, we want perf continue monitoring the remaining threads and do not exit with error. Here, the patch enables perf_evsel::ignore_missing_thread for -p option to ignore complete failure if any of threads die before we open the event. But it may still return sys_perf_event_open failure with 22(Invalid) if we monitors several event groups. sys_perf_event_open: pid 28960 cpu 40 group_fd 118202 flags 0x8 sys_perf_event_open: pid 28961 cpu 40 group_fd 118203 flags 0x8 WARNING: Ignored open failure for pid 28962 sys_perf_event_open: pid 28962 cpu 40 group_fd [118203] flags 0x8 sys_perf_event_open failed, error -22 That is because when we ignore a missing thread, we change the thread_idx without dealing with its fds, FD(evsel, cpu, thread). Then get_group_fd() may return a wrong group_fd for the next thread and sys_perf_event_open() return with 22. sys_perf_event_open(){ ... if (group_fd != -1) perf_fget_light()//to get corresponding group_leader by group_fd ... if (group_leader) if (group_leader->ctx->task != ctx->task)//should on the same task goto err_context ... } This patch also fixes this bug by introducing perf_evsel__remove_fd() and update_fds to allow removing fds for the missing thread. Changes since v1: - Change group_fd__remove() into a more genetic way without changing code logic - Remove redundant condition Changes since v2: - Use a proper function name and add some comment. - Multiline comment style fixes. Committer testing: Before this patch the recently added 'perf stat --per-thread' for system wide counting would race while enumerating all threads using /proc: [root@jouet ~]# perf stat --per-thread failed to parse CPUs map: No such file or directory Usage: perf stat [] [] -C, --cpu list of cpus to monitor in system-wide -a, --all-cpus system-wide collection from all CPUs [root@jouet ~]# perf stat --per-thread failed to parse CPUs map: No such file or directory Usage: perf stat [] [] -C, --cpu list of cpus to monitor in system-wide -a, --all-cpus system-wide collection from all CPUs [root@jouet ~]# When, say, the kernel was being built, so lots of shortlived threads, after this patch this doesn't happen. Signed-off-by: Mengting Zhang Tested-by: Arnaldo Carvalho de Melo Acked-by: Jiri Olsa Cc: Cheng Jian Cc: Li Bin Cc: Wang Nan Link: http://lkml.kernel.org/r/1513148513-6974-1-git-send-email-zhangmengting@huawei.com [ Remove one use 'evlist' alias variable ] Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- tools/perf/builtin-record.c | 4 ++-- tools/perf/util/evsel.c | 47 +++++++++++++++++++++++++++++++++++-- 2 files changed, 47 insertions(+), 4 deletions(-) diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 0c95ffefb6cc..1957abc1c8cf 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -1856,8 +1856,8 @@ int cmd_record(int argc, const char **argv) goto out; } - /* Enable ignoring missing threads when -u option is defined. */ - rec->opts.ignore_missing_thread = rec->opts.target.uid != UINT_MAX; + /* Enable ignoring missing threads when -u/-p option is defined. */ + rec->opts.ignore_missing_thread = rec->opts.target.uid != UINT_MAX || rec->opts.target.pid; err = -ENOMEM; if (perf_evlist__create_maps(rec->evlist, &rec->opts.target) < 0) diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index 1f6beb3d0c68..ac19130c14d8 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c @@ -1591,10 +1591,46 @@ static int __open_attr__fprintf(FILE *fp, const char *name, const char *val, return fprintf(fp, " %-32s %s\n", name, val); } +static void perf_evsel__remove_fd(struct perf_evsel *pos, + int nr_cpus, int nr_threads, + int thread_idx) +{ + for (int cpu = 0; cpu < nr_cpus; cpu++) + for (int thread = thread_idx; thread < nr_threads - 1; thread++) + FD(pos, cpu, thread) = FD(pos, cpu, thread + 1); +} + +static int update_fds(struct perf_evsel *evsel, + int nr_cpus, int cpu_idx, + int nr_threads, int thread_idx) +{ + struct perf_evsel *pos; + + if (cpu_idx >= nr_cpus || thread_idx >= nr_threads) + return -EINVAL; + + evlist__for_each_entry(evsel->evlist, pos) { + nr_cpus = pos != evsel ? nr_cpus : cpu_idx; + + perf_evsel__remove_fd(pos, nr_cpus, nr_threads, thread_idx); + + /* + * Since fds for next evsel has not been created, + * there is no need to iterate whole event list. + */ + if (pos == evsel) + break; + } + return 0; +} + static bool ignore_missing_thread(struct perf_evsel *evsel, + int nr_cpus, int cpu, struct thread_map *threads, int thread, int err) { + pid_t ignore_pid = thread_map__pid(threads, thread); + if (!evsel->ignore_missing_thread) return false; @@ -1610,11 +1646,18 @@ static bool ignore_missing_thread(struct perf_evsel *evsel, if (threads->nr == 1) return false; + /* + * We should remove fd for missing_thread first + * because thread_map__remove() will decrease threads->nr. + */ + if (update_fds(evsel, nr_cpus, cpu, threads->nr, thread)) + return false; + if (thread_map__remove(threads, thread)) return false; pr_warning("WARNING: Ignored open failure for pid %d\n", - thread_map__pid(threads, thread)); + ignore_pid); return true; } @@ -1719,7 +1762,7 @@ int perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus, if (fd < 0) { err = -errno; - if (ignore_missing_thread(evsel, threads, thread, err)) { + if (ignore_missing_thread(evsel, cpus->nr, cpu, threads, thread, err)) { /* * We just removed 1 thread, so take a step * back on thread index and lower the upper -- GitLab From f7b0ea2245a0c7e6b255b0fa6f0a83a04a821da5 Mon Sep 17 00:00:00 2001 From: Peng Li Date: Fri, 22 Dec 2017 12:21:43 +0800 Subject: [PATCH 0191/1635] net: hns3: free the ring_data structrue when change tqps [ Upstream commit 99fdf6b1cadf41bb253408589788f025027274f3 ] This patch fixes a memory leak problems in change tqps process, the function hns3_uninit_all_ring and hns3_init_all_ring may be called many times. Signed-off-by: Peng Li Signed-off-by: Mingguang Qu Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/hisilicon/hns3/hns3pf/hns3_enet.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hns3_enet.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hns3_enet.c index 186772493711..3e7e13b9a385 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hns3_enet.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hns3_enet.c @@ -2687,8 +2687,12 @@ static int hns3_uninit_all_ring(struct hns3_nic_priv *priv) h->ae_algo->ops->reset_queue(h, i); hns3_fini_ring(priv->ring_data[i].ring); + devm_kfree(priv->dev, priv->ring_data[i].ring); hns3_fini_ring(priv->ring_data[i + h->kinfo.num_tqps].ring); + devm_kfree(priv->dev, + priv->ring_data[i + h->kinfo.num_tqps].ring); } + devm_kfree(priv->dev, priv->ring_data); return 0; } -- GitLab From fcb762cb4b5ccee501f10d1d798b26b16cc26a28 Mon Sep 17 00:00:00 2001 From: Fuyun Liang Date: Fri, 22 Dec 2017 12:21:50 +0800 Subject: [PATCH 0192/1635] net: hns3: fix for getting auto-negotiation state in hclge_get_autoneg [ Upstream commit 27b5bf49f0924fd62d2b1ef8467b40773973da34 ] When phy exists, we use the value of phydev.autoneg to represent the auto-negotiation state of hardware. Otherwise, we use the value of mac.autoneg to represent it. This patch fixes for getting a error value of auto-negotiation state in hclge_get_autoneg(). Fixes: 46a3df9f9718 ("net: hns3: Add HNS3 Acceleration Engine & Compatibility Layer Support") Signed-off-by: Fuyun Liang Signed-off-by: Peng Li Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c index a0ef97e7f3c9..ff7a70ffafc6 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c @@ -2092,6 +2092,10 @@ static int hclge_get_autoneg(struct hnae3_handle *handle) { struct hclge_vport *vport = hclge_get_vport(handle); struct hclge_dev *hdev = vport->back; + struct phy_device *phydev = hdev->hw.mac.phydev; + + if (phydev) + return phydev->autoneg; hclge_query_autoneg_result(hdev); -- GitLab From ab4ac0fc47129747d0304d27d720561fe71fe123 Mon Sep 17 00:00:00 2001 From: Hangbin Liu Date: Fri, 22 Dec 2017 15:10:17 +0100 Subject: [PATCH 0193/1635] l2tp: fix missing print session offset info [ Upstream commit 820da5357572715c6235ba3b3daa2d5b43a1198f ] Report offset parameter in L2TP_CMD_SESSION_GET command if it has been configured by userspace Fixes: 309795f4bec ("l2tp: Add netlink control API for L2TP") Reported-by: Jianlin Shi Signed-off-by: Hangbin Liu Signed-off-by: Lorenzo Bianconi Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- net/l2tp/l2tp_netlink.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/net/l2tp/l2tp_netlink.c b/net/l2tp/l2tp_netlink.c index c28223d8092b..fca69c3771f5 100644 --- a/net/l2tp/l2tp_netlink.c +++ b/net/l2tp/l2tp_netlink.c @@ -765,6 +765,8 @@ static int l2tp_nl_session_send(struct sk_buff *skb, u32 portid, u32 seq, int fl if ((session->ifname[0] && nla_put_string(skb, L2TP_ATTR_IFNAME, session->ifname)) || + (session->offset && + nla_put_u16(skb, L2TP_ATTR_OFFSET, session->offset)) || (session->cookie_len && nla_put(skb, L2TP_ATTR_COOKIE, session->cookie_len, &session->cookie[0])) || -- GitLab From ea620e414bdec8f9dda3db588ceb672296467270 Mon Sep 17 00:00:00 2001 From: Sowmini Varadhan Date: Fri, 22 Dec 2017 09:38:59 -0800 Subject: [PATCH 0194/1635] rds; Reset rs->rs_bound_addr in rds_add_bound() failure path [ Upstream commit 7ae0c649c47f1c5d2db8cee6dd75855970af1669 ] If the rds_sock is not added to the bind_hash_table, we must reset rs_bound_addr so that rds_remove_bound will not trip on this rds_sock. rds_add_bound() does a rds_sock_put() in this failure path, so failing to reset rs_bound_addr will result in a socket refcount bug, and will trigger a WARN_ON with the stack shown below when the application subsequently tries to close the PF_RDS socket. WARNING: CPU: 20 PID: 19499 at net/rds/af_rds.c:496 \ rds_sock_destruct+0x15/0x30 [rds] : __sk_destruct+0x21/0x190 rds_remove_bound.part.13+0xb6/0x140 [rds] rds_release+0x71/0x120 [rds] sock_release+0x1a/0x70 sock_close+0xe/0x20 __fput+0xd5/0x210 task_work_run+0x82/0xa0 do_exit+0x2ce/0xb30 ? syscall_trace_enter+0x1cc/0x2b0 do_group_exit+0x39/0xa0 SyS_exit_group+0x10/0x10 do_syscall_64+0x61/0x1a0 Signed-off-by: Sowmini Varadhan Acked-by: Santosh Shilimkar Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- net/rds/bind.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/rds/bind.c b/net/rds/bind.c index 75d43dc8e96b..5aa3a64aa4f0 100644 --- a/net/rds/bind.c +++ b/net/rds/bind.c @@ -114,6 +114,7 @@ static int rds_add_bound(struct rds_sock *rs, __be32 addr, __be16 *port) rs, &addr, (int)ntohs(*port)); break; } else { + rs->rs_bound_addr = 0; rds_sock_put(rs); ret = -ENOMEM; break; -- GitLab From 378259c7d0a2e28176486a2bae611ef5ca5bd114 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sat, 23 Dec 2017 19:41:47 +0100 Subject: [PATCH 0195/1635] ACPI / video: Default lcd_only to true on Win8-ready and newer machines [ Upstream commit 5928c281524fe451114e04f1dfa11246a37e859f ] We're seeing a lot of bogus backlight interfaces on newer machines without a LCD such as desktops, servers and HDMI sticks. This causes userspace to show a non-functional brightness slider in e.g. the GNOME3 system menu, which is undesirable. And, in general, we should simply just not register a non functional backlight interface. Checking the LCD flag causes the bogus acpi_video backlight interfaces to go away (on the machines this was tested on). This change sets the lcd_only option by default on any machines which are Win8-ready, to fix this. This is not entirely without a risk of regressions, but video_detect.c already prefers native-backlight interfaces over the acpi_video one on Win8-ready machines, calling acpi_video_unregister_backlight() as soon as a native interface shows up. This is done because the ACPI backlight interface often is broken on Win8-ready machines, because win8 does not seem to actually use it. So in practice we already end up not registering the ACPI backlight interface on (most) Win8-ready machines with a LCD panel, thus this change does not change anything for (most) machines with a LCD panel and on machines without a LCD panel we actually don't want to register any backlight interfaces. This has been tested on the following machines and fixes a bogus backlight interface showing up there: - Desktop with an Asrock B150M Pro4S/D3 m.b. using i5-6500 builtin gfx - Intel Compute Stick STK1AW32SC - Meegopad T08 HDMI stick Bogus backlight interfaces have also been reported on: - Desktop with Asus H87I-Plus m.b. - Desktop with ASRock B75M-ITX m.b. - Desktop with Gigabyte Z87-D3HP m.b. - Dell PowerEdge T20 desktop Link: https://bugzilla.redhat.com/show_bug.cgi?id=1097436 Link: https://bugzilla.redhat.com/show_bug.cgi?id=1133327 Link: https://bugzilla.redhat.com/show_bug.cgi?id=1133329 Link: https://bugzilla.redhat.com/show_bug.cgi?id=1133646 Signed-off-by: Hans de Goede Signed-off-by: Rafael J. Wysocki Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/acpi/acpi_video.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/drivers/acpi/acpi_video.c b/drivers/acpi/acpi_video.c index 0972ec0e2eb8..f53ccc680238 100644 --- a/drivers/acpi/acpi_video.c +++ b/drivers/acpi/acpi_video.c @@ -80,8 +80,8 @@ MODULE_PARM_DESC(report_key_events, static bool device_id_scheme = false; module_param(device_id_scheme, bool, 0444); -static bool only_lcd = false; -module_param(only_lcd, bool, 0444); +static int only_lcd = -1; +module_param(only_lcd, int, 0444); static int register_count; static DEFINE_MUTEX(register_count_mutex); @@ -2136,6 +2136,16 @@ int acpi_video_register(void) goto leave; } + /* + * We're seeing a lot of bogus backlight interfaces on newer machines + * without a LCD such as desktops, servers and HDMI sticks. Checking + * the lcd flag fixes this, so enable this on any machines which are + * win8 ready (where we also prefer the native backlight driver, so + * normally the acpi_video code should not register there anyways). + */ + if (only_lcd == -1) + only_lcd = acpi_osi_is_win8(); + dmi_check_system(video_dmi_table); ret = acpi_bus_register_driver(&acpi_video_bus); -- GitLab From 87a25a385832b917027298513d47473ce7ef870d Mon Sep 17 00:00:00 2001 From: Moni Shoua Date: Thu, 28 Dec 2017 16:26:11 +0200 Subject: [PATCH 0196/1635] net/mlx4_en: Change default QoS settings [ Upstream commit a42b63c1ac1986f17f71bc91a6b0aaa14d4dae71 ] Change the default mapping between TC and TCG as follows: Prio | TC/TCG | from to | (set by FW) (set by SW) ---------+----------------------------------- 0 | 0/0 0/7 1 | 1/0 0/6 2 | 2/0 0/5 3 | 3/0 0/4 4 | 4/0 0/3 5 | 5/0 0/2 6 | 6/0 0/1 7 | 7/0 0/0 These new settings cause that a pause frame for any prio stops traffic for all prios. Fixes: 564c274c3df0 ("net/mlx4_en: DCB QoS support") Signed-off-by: Moni Shoua Signed-off-by: Maor Gottlieb Signed-off-by: Tariq Toukan Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/mellanox/mlx4/en_dcb_nl.c | 5 +++++ drivers/net/ethernet/mellanox/mlx4/en_netdev.c | 7 +++++++ drivers/net/ethernet/mellanox/mlx4/mlx4_en.h | 1 + 3 files changed, 13 insertions(+) diff --git a/drivers/net/ethernet/mellanox/mlx4/en_dcb_nl.c b/drivers/net/ethernet/mellanox/mlx4/en_dcb_nl.c index 5f41dc92aa68..1a0c3bf86ead 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_dcb_nl.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_dcb_nl.c @@ -310,6 +310,7 @@ static int mlx4_en_ets_validate(struct mlx4_en_priv *priv, struct ieee_ets *ets) } switch (ets->tc_tsa[i]) { + case IEEE_8021QAZ_TSA_VENDOR: case IEEE_8021QAZ_TSA_STRICT: break; case IEEE_8021QAZ_TSA_ETS: @@ -347,6 +348,10 @@ static int mlx4_en_config_port_scheduler(struct mlx4_en_priv *priv, /* higher TC means higher priority => lower pg */ for (i = IEEE_8021QAZ_MAX_TCS - 1; i >= 0; i--) { switch (ets->tc_tsa[i]) { + case IEEE_8021QAZ_TSA_VENDOR: + pg[i] = MLX4_EN_TC_VENDOR; + tc_tx_bw[i] = MLX4_EN_BW_MAX; + break; case IEEE_8021QAZ_TSA_STRICT: pg[i] = num_strict++; tc_tx_bw[i] = MLX4_EN_BW_MAX; diff --git a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c index 9c218f1cfc6c..c097eef41a9c 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c @@ -3335,6 +3335,13 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port, priv->msg_enable = MLX4_EN_MSG_LEVEL; #ifdef CONFIG_MLX4_EN_DCB if (!mlx4_is_slave(priv->mdev->dev)) { + u8 prio; + + for (prio = 0; prio < IEEE_8021QAZ_MAX_TCS; ++prio) { + priv->ets.prio_tc[prio] = prio; + priv->ets.tc_tsa[prio] = IEEE_8021QAZ_TSA_VENDOR; + } + priv->dcbx_cap = DCB_CAP_DCBX_VER_CEE | DCB_CAP_DCBX_HOST | DCB_CAP_DCBX_VER_IEEE; priv->flags |= MLX4_EN_DCB_ENABLED; diff --git a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h index fdb3ad0cbe54..2c1a5ff6acfa 100644 --- a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h +++ b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h @@ -476,6 +476,7 @@ struct mlx4_en_frag_info { #define MLX4_EN_BW_MIN 1 #define MLX4_EN_BW_MAX 100 /* Utilize 100% of the line */ +#define MLX4_EN_TC_VENDOR 0 #define MLX4_EN_TC_ETS 7 enum dcb_pfc_type { -- GitLab From db470ce8c6ee0efdc4fe699a3293ac2c0a5646f6 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Fri, 10 Nov 2017 15:45:41 +1100 Subject: [PATCH 0197/1635] VFS: close race between getcwd() and d_move() [ Upstream commit 61647823aa920e395afcce4b57c32afb51456cab ] d_move() will call __d_drop() and then __d_rehash() on the dentry being moved. This creates a small window when the dentry appears to be unhashed. Many tests of d_unhashed() are made under ->d_lock and so are safe from racing with this window, but some aren't. In particular, getcwd() calls d_unlinked() (which calls d_unhashed()) without d_lock protection, so it can race. This races has been seen in practice with lustre, which uses d_move() as part of name lookup. See: https://jira.hpdd.intel.com/browse/LU-9735 It could race with a regular rename(), and result in ENOENT instead of either the 'before' or 'after' name. The race can be demonstrated with a simple program which has two threads, one renaming a directory back and forth while another calls getcwd() within that directory: it should never fail, but does. See: https://patchwork.kernel.org/patch/9455345/ We could fix this race by taking d_lock and rechecking when d_unhashed() reports true. Alternately when can remove the window, which is the approach this patch takes. ___d_drop() is introduce which does *not* clear d_hash.pprev so the dentry still appears to be hashed. __d_drop() calls ___d_drop(), then clears d_hash.pprev. __d_move() now uses ___d_drop() and only clears d_hash.pprev when not rehashing. Signed-off-by: NeilBrown Signed-off-by: Al Viro Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- fs/dcache.c | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/fs/dcache.c b/fs/dcache.c index a1417787e269..c28b9c91b5cb 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -468,9 +468,11 @@ static void dentry_lru_add(struct dentry *dentry) * d_drop() is used mainly for stuff that wants to invalidate a dentry for some * reason (NFS timeouts or autofs deletes). * - * __d_drop requires dentry->d_lock. + * __d_drop requires dentry->d_lock + * ___d_drop doesn't mark dentry as "unhashed" + * (dentry->d_hash.pprev will be LIST_POISON2, not NULL). */ -void __d_drop(struct dentry *dentry) +static void ___d_drop(struct dentry *dentry) { if (!d_unhashed(dentry)) { struct hlist_bl_head *b; @@ -486,12 +488,17 @@ void __d_drop(struct dentry *dentry) hlist_bl_lock(b); __hlist_bl_del(&dentry->d_hash); - dentry->d_hash.pprev = NULL; hlist_bl_unlock(b); /* After this call, in-progress rcu-walk path lookup will fail. */ write_seqcount_invalidate(&dentry->d_seq); } } + +void __d_drop(struct dentry *dentry) +{ + ___d_drop(dentry); + dentry->d_hash.pprev = NULL; +} EXPORT_SYMBOL(__d_drop); void d_drop(struct dentry *dentry) @@ -2386,7 +2393,7 @@ EXPORT_SYMBOL(d_delete); static void __d_rehash(struct dentry *entry) { struct hlist_bl_head *b = d_hash(entry->d_name.hash); - BUG_ON(!d_unhashed(entry)); + hlist_bl_lock(b); hlist_bl_add_head_rcu(&entry->d_hash, b); hlist_bl_unlock(b); @@ -2821,9 +2828,9 @@ static void __d_move(struct dentry *dentry, struct dentry *target, write_seqcount_begin_nested(&target->d_seq, DENTRY_D_LOCK_NESTED); /* unhash both */ - /* __d_drop does write_seqcount_barrier, but they're OK to nest. */ - __d_drop(dentry); - __d_drop(target); + /* ___d_drop does write_seqcount_barrier, but they're OK to nest. */ + ___d_drop(dentry); + ___d_drop(target); /* Switch the names.. */ if (exchange) @@ -2835,6 +2842,8 @@ static void __d_move(struct dentry *dentry, struct dentry *target, __d_rehash(dentry); if (exchange) __d_rehash(target); + else + target->d_hash.pprev = NULL; /* ... and switch them in the tree */ if (IS_ROOT(dentry)) { -- GitLab From 1cf98fd005f54f480aba21f1d73a0059f460a353 Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Tue, 26 Sep 2017 08:11:22 +0200 Subject: [PATCH 0198/1635] watchdog: dw_wdt: add stop watchdog operation [ Upstream commit 1bfe8889380890efe4943d125124f5a7b48571b0 ] The only way of stopping the watchdog is by resetting it. Add the watchdog op for stopping the device and reset if a reset line is provided. At same time WDOG_HW_RUNNING should be remove from dw_wdt_start. As commented by Guenter Roeck: dw_wdt sets WDOG_HW_RUNNING in its open function. Result is that the kref_get() in watchdog_open() won't be executed. But then kref_put() in close will be called since the watchdog now does stop. This causes the imbalance. Signed-off-by: Oleksij Rempel Cc: Wim Van Sebroeck Cc: Guenter Roeck Cc: linux-watchdog@vger.kernel.org Reviewed-by: Guenter Roeck Signed-off-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/watchdog/dw_wdt.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/drivers/watchdog/dw_wdt.c b/drivers/watchdog/dw_wdt.c index 36be987ff9ef..c2f4ff516230 100644 --- a/drivers/watchdog/dw_wdt.c +++ b/drivers/watchdog/dw_wdt.c @@ -127,14 +127,27 @@ static int dw_wdt_start(struct watchdog_device *wdd) dw_wdt_set_timeout(wdd, wdd->timeout); - set_bit(WDOG_HW_RUNNING, &wdd->status); - writel(WDOG_CONTROL_REG_WDT_EN_MASK, dw_wdt->regs + WDOG_CONTROL_REG_OFFSET); return 0; } +static int dw_wdt_stop(struct watchdog_device *wdd) +{ + struct dw_wdt *dw_wdt = to_dw_wdt(wdd); + + if (!dw_wdt->rst) { + set_bit(WDOG_HW_RUNNING, &wdd->status); + return 0; + } + + reset_control_assert(dw_wdt->rst); + reset_control_deassert(dw_wdt->rst); + + return 0; +} + static int dw_wdt_restart(struct watchdog_device *wdd, unsigned long action, void *data) { @@ -173,6 +186,7 @@ static const struct watchdog_info dw_wdt_ident = { static const struct watchdog_ops dw_wdt_ops = { .owner = THIS_MODULE, .start = dw_wdt_start, + .stop = dw_wdt_stop, .ping = dw_wdt_ping, .set_timeout = dw_wdt_set_timeout, .get_timeleft = dw_wdt_get_timeleft, -- GitLab From e6bc3a4b0c23ed8d754692fa15ceb280e3facc51 Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Thu, 21 Dec 2017 17:30:54 +0100 Subject: [PATCH 0199/1635] clk: divider: fix incorrect usage of container_of [ Upstream commit 12a26c298d2a8b1cab498533fa65198e49e3afd3 ] divider_recalc_rate() is an helper function used by clock divider of different types, so the structure containing the 'hw' pointer is not always a 'struct clk_divider' At the following line: > div = _get_div(table, val, flags, divider->width); in several cases, the value of 'divider->width' is garbage as the actual structure behind this memory is not a 'struct clk_divider' Fortunately, this width value is used by _get_val() only when CLK_DIVIDER_MAX_AT_ZERO flag is set. This has never been the case so far when the structure is not a 'struct clk_divider'. This is probably why we did not notice this bug before Fixes: afe76c8fd030 ("clk: allow a clk divider with max divisor when zero") Signed-off-by: Jerome Brunet Acked-by: Alexandre Belloni Acked-by: Sylvain Lemieux Signed-off-by: Stephen Boyd Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/clk/clk-divider.c | 7 +++---- drivers/clk/hisilicon/clkdivider-hi6220.c | 2 +- drivers/clk/nxp/clk-lpc32xx.c | 2 +- drivers/clk/qcom/clk-regmap-divider.c | 2 +- drivers/clk/sunxi-ng/ccu_div.c | 2 +- drivers/gpu/drm/msm/dsi/pll/dsi_pll_14nm.c | 2 +- drivers/rtc/rtc-ac100.c | 6 ++++-- include/linux/clk-provider.h | 2 +- 8 files changed, 13 insertions(+), 12 deletions(-) diff --git a/drivers/clk/clk-divider.c b/drivers/clk/clk-divider.c index 4ed516cb7276..b49942b9fe50 100644 --- a/drivers/clk/clk-divider.c +++ b/drivers/clk/clk-divider.c @@ -118,12 +118,11 @@ static unsigned int _get_val(const struct clk_div_table *table, unsigned long divider_recalc_rate(struct clk_hw *hw, unsigned long parent_rate, unsigned int val, const struct clk_div_table *table, - unsigned long flags) + unsigned long flags, unsigned long width) { - struct clk_divider *divider = to_clk_divider(hw); unsigned int div; - div = _get_div(table, val, flags, divider->width); + div = _get_div(table, val, flags, width); if (!div) { WARN(!(flags & CLK_DIVIDER_ALLOW_ZERO), "%s: Zero divisor and CLK_DIVIDER_ALLOW_ZERO not set\n", @@ -145,7 +144,7 @@ static unsigned long clk_divider_recalc_rate(struct clk_hw *hw, val &= div_mask(divider->width); return divider_recalc_rate(hw, parent_rate, val, divider->table, - divider->flags); + divider->flags, divider->width); } static bool _is_valid_table_div(const struct clk_div_table *table, diff --git a/drivers/clk/hisilicon/clkdivider-hi6220.c b/drivers/clk/hisilicon/clkdivider-hi6220.c index a1c1f684ad58..9f46cf9dcc65 100644 --- a/drivers/clk/hisilicon/clkdivider-hi6220.c +++ b/drivers/clk/hisilicon/clkdivider-hi6220.c @@ -56,7 +56,7 @@ static unsigned long hi6220_clkdiv_recalc_rate(struct clk_hw *hw, val &= div_mask(dclk->width); return divider_recalc_rate(hw, parent_rate, val, dclk->table, - CLK_DIVIDER_ROUND_CLOSEST); + CLK_DIVIDER_ROUND_CLOSEST, dclk->width); } static long hi6220_clkdiv_round_rate(struct clk_hw *hw, unsigned long rate, diff --git a/drivers/clk/nxp/clk-lpc32xx.c b/drivers/clk/nxp/clk-lpc32xx.c index 7b359afd620e..a6438f50e6db 100644 --- a/drivers/clk/nxp/clk-lpc32xx.c +++ b/drivers/clk/nxp/clk-lpc32xx.c @@ -956,7 +956,7 @@ static unsigned long clk_divider_recalc_rate(struct clk_hw *hw, val &= div_mask(divider->width); return divider_recalc_rate(hw, parent_rate, val, divider->table, - divider->flags); + divider->flags, divider->width); } static long clk_divider_round_rate(struct clk_hw *hw, unsigned long rate, diff --git a/drivers/clk/qcom/clk-regmap-divider.c b/drivers/clk/qcom/clk-regmap-divider.c index 53484912301e..928fcc16ee27 100644 --- a/drivers/clk/qcom/clk-regmap-divider.c +++ b/drivers/clk/qcom/clk-regmap-divider.c @@ -59,7 +59,7 @@ static unsigned long div_recalc_rate(struct clk_hw *hw, div &= BIT(divider->width) - 1; return divider_recalc_rate(hw, parent_rate, div, NULL, - CLK_DIVIDER_ROUND_CLOSEST); + CLK_DIVIDER_ROUND_CLOSEST, divider->width); } const struct clk_ops clk_regmap_div_ops = { diff --git a/drivers/clk/sunxi-ng/ccu_div.c b/drivers/clk/sunxi-ng/ccu_div.c index baa3cf96507b..302a18efd39f 100644 --- a/drivers/clk/sunxi-ng/ccu_div.c +++ b/drivers/clk/sunxi-ng/ccu_div.c @@ -71,7 +71,7 @@ static unsigned long ccu_div_recalc_rate(struct clk_hw *hw, parent_rate); val = divider_recalc_rate(hw, parent_rate, val, cd->div.table, - cd->div.flags); + cd->div.flags, cd->div.width); if (cd->common.features & CCU_FEATURE_FIXED_POSTDIV) val /= cd->fixed_post_div; diff --git a/drivers/gpu/drm/msm/dsi/pll/dsi_pll_14nm.c b/drivers/gpu/drm/msm/dsi/pll/dsi_pll_14nm.c index fe15aa64086f..71fe60e5f01f 100644 --- a/drivers/gpu/drm/msm/dsi/pll/dsi_pll_14nm.c +++ b/drivers/gpu/drm/msm/dsi/pll/dsi_pll_14nm.c @@ -698,7 +698,7 @@ static unsigned long dsi_pll_14nm_postdiv_recalc_rate(struct clk_hw *hw, val &= div_mask(width); return divider_recalc_rate(hw, parent_rate, val, NULL, - postdiv->flags); + postdiv->flags, width); } static long dsi_pll_14nm_postdiv_round_rate(struct clk_hw *hw, diff --git a/drivers/rtc/rtc-ac100.c b/drivers/rtc/rtc-ac100.c index 0e358d4b6738..8ff9dc3fe5bf 100644 --- a/drivers/rtc/rtc-ac100.c +++ b/drivers/rtc/rtc-ac100.c @@ -137,13 +137,15 @@ static unsigned long ac100_clkout_recalc_rate(struct clk_hw *hw, div = (reg >> AC100_CLKOUT_PRE_DIV_SHIFT) & ((1 << AC100_CLKOUT_PRE_DIV_WIDTH) - 1); prate = divider_recalc_rate(hw, prate, div, - ac100_clkout_prediv, 0); + ac100_clkout_prediv, 0, + AC100_CLKOUT_PRE_DIV_WIDTH); } div = (reg >> AC100_CLKOUT_DIV_SHIFT) & (BIT(AC100_CLKOUT_DIV_WIDTH) - 1); return divider_recalc_rate(hw, prate, div, NULL, - CLK_DIVIDER_POWER_OF_TWO); + CLK_DIVIDER_POWER_OF_TWO, + AC100_CLKOUT_DIV_WIDTH); } static long ac100_clkout_round_rate(struct clk_hw *hw, unsigned long rate, diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h index 5100ec1b5d55..86eb33f67618 100644 --- a/include/linux/clk-provider.h +++ b/include/linux/clk-provider.h @@ -412,7 +412,7 @@ extern const struct clk_ops clk_divider_ro_ops; unsigned long divider_recalc_rate(struct clk_hw *hw, unsigned long parent_rate, unsigned int val, const struct clk_div_table *table, - unsigned long flags); + unsigned long flags, unsigned long width); long divider_round_rate_parent(struct clk_hw *hw, struct clk_hw *parent, unsigned long rate, unsigned long *prate, const struct clk_div_table *table, -- GitLab From b72d39b1da82573654b4b4ce938cc6d3d3b89057 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Wed, 6 Dec 2017 14:20:15 -0600 Subject: [PATCH 0200/1635] PM / devfreq: Fix potential NULL pointer dereference in governor_store [ Upstream commit 63f1e05f7fe9ca509c60154d6a833abf96eecdc9 ] df->governor is being dereferenced before it is null checked, hence there is a potential null pointer dereference. Notice that df->governor is being null checked at line 1004: if (df->governor) {, which implies it might be null. Fix this by null checking df->governor before dereferencing it. Addresses-Coverity-ID: 1401988 ("Dereference before null check") Fixes: bcf23c79c4e4 ("PM / devfreq: Fix available_governor sysfs") Signed-off-by: Gustavo A. R. Silva Reviewed-by: Chanwoo Choi Signed-off-by: MyungJoo Ham Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/devfreq/devfreq.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c index 202476fbbc4c..8a411514a7c5 100644 --- a/drivers/devfreq/devfreq.c +++ b/drivers/devfreq/devfreq.c @@ -935,7 +935,8 @@ static ssize_t governor_store(struct device *dev, struct device_attribute *attr, if (df->governor == governor) { ret = 0; goto out; - } else if (df->governor->immutable || governor->immutable) { + } else if ((df->governor && df->governor->immutable) || + governor->immutable) { ret = -EINVAL; goto out; } -- GitLab From 7743aa14305519af65f21759f56fb1eb168bd2bd Mon Sep 17 00:00:00 2001 From: Sowmini Varadhan Date: Mon, 25 Dec 2017 14:43:04 -0800 Subject: [PATCH 0201/1635] selftests/net: fix bugs in address and port initialization [ Upstream commit d36f45e5b46723cf2d4147173e18c52d4143176d ] Address/port initialization should work correctly regardless of the order in which command line arguments are supplied, E.g, cfg_port should be used to connect to the remote host even if it is processed after -D, src/dst address initialization should not require that [-4|-6] be specified before the -S or -D args, receiver should be able to bind to *. Achieve this by making sure that the address/port structures are initialized after all command line options are parsed. Store cfg_port in host-byte order, and use htons() to set up the sin_port/sin6_port before bind/connect, so that the network system calls get the correct values in network-byte order. Signed-off-by: Sowmini Varadhan Acked-by: Willem de Bruijn Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- tools/testing/selftests/net/msg_zerocopy.c | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/tools/testing/selftests/net/msg_zerocopy.c b/tools/testing/selftests/net/msg_zerocopy.c index 3ab6ec403905..e11fe84de0fd 100644 --- a/tools/testing/selftests/net/msg_zerocopy.c +++ b/tools/testing/selftests/net/msg_zerocopy.c @@ -259,22 +259,28 @@ static int setup_ip6h(struct ipv6hdr *ip6h, uint16_t payload_len) return sizeof(*ip6h); } -static void setup_sockaddr(int domain, const char *str_addr, void *sockaddr) + +static void setup_sockaddr(int domain, const char *str_addr, + struct sockaddr_storage *sockaddr) { struct sockaddr_in6 *addr6 = (void *) sockaddr; struct sockaddr_in *addr4 = (void *) sockaddr; switch (domain) { case PF_INET: + memset(addr4, 0, sizeof(*addr4)); addr4->sin_family = AF_INET; addr4->sin_port = htons(cfg_port); - if (inet_pton(AF_INET, str_addr, &(addr4->sin_addr)) != 1) + if (str_addr && + inet_pton(AF_INET, str_addr, &(addr4->sin_addr)) != 1) error(1, 0, "ipv4 parse error: %s", str_addr); break; case PF_INET6: + memset(addr6, 0, sizeof(*addr6)); addr6->sin6_family = AF_INET6; addr6->sin6_port = htons(cfg_port); - if (inet_pton(AF_INET6, str_addr, &(addr6->sin6_addr)) != 1) + if (str_addr && + inet_pton(AF_INET6, str_addr, &(addr6->sin6_addr)) != 1) error(1, 0, "ipv6 parse error: %s", str_addr); break; default: @@ -603,6 +609,7 @@ static void parse_opts(int argc, char **argv) sizeof(struct tcphdr) - 40 /* max tcp options */; int c; + char *daddr = NULL, *saddr = NULL; cfg_payload_len = max_payload_len; @@ -627,7 +634,7 @@ static void parse_opts(int argc, char **argv) cfg_cpu = strtol(optarg, NULL, 0); break; case 'D': - setup_sockaddr(cfg_family, optarg, &cfg_dst_addr); + daddr = optarg; break; case 'i': cfg_ifindex = if_nametoindex(optarg); @@ -638,7 +645,7 @@ static void parse_opts(int argc, char **argv) cfg_cork_mixed = true; break; case 'p': - cfg_port = htons(strtoul(optarg, NULL, 0)); + cfg_port = strtoul(optarg, NULL, 0); break; case 'r': cfg_rx = true; @@ -647,7 +654,7 @@ static void parse_opts(int argc, char **argv) cfg_payload_len = strtoul(optarg, NULL, 0); break; case 'S': - setup_sockaddr(cfg_family, optarg, &cfg_src_addr); + saddr = optarg; break; case 't': cfg_runtime_ms = 200 + strtoul(optarg, NULL, 10) * 1000; @@ -660,6 +667,8 @@ static void parse_opts(int argc, char **argv) break; } } + setup_sockaddr(cfg_family, daddr, &cfg_dst_addr); + setup_sockaddr(cfg_family, saddr, &cfg_src_addr); if (cfg_payload_len > max_payload_len) error(1, 0, "-s: payload exceeds max (%d)", max_payload_len); -- GitLab From ddc09c522035297b711d821e72bebf24a11fb617 Mon Sep 17 00:00:00 2001 From: Leon Romanovsky Date: Mon, 1 Jan 2018 13:07:17 +0200 Subject: [PATCH 0202/1635] RDMA/cma: Mark end of CMA ID messages [ Upstream commit e48e5e198fb6ec77c91047a694022f0fefa45292 ] The commit 1a1c116f3dcf ("RDMA/netlink: Simplify the put_msg and put_attr") removes nlmsg_len calculation in ibnl_put_attr causing netlink messages and caused to miss source and destination addresses. Fixes: 1a1c116f3dcf ("RDMA/netlink: Simplify the put_msg and put_attr") Signed-off-by: Leon Romanovsky Signed-off-by: Jason Gunthorpe Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/infiniband/core/cma.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c index 6cae00ecc905..25de7cc9f49f 100644 --- a/drivers/infiniband/core/cma.c +++ b/drivers/infiniband/core/cma.c @@ -4453,6 +4453,7 @@ static int cma_get_id_stats(struct sk_buff *skb, struct netlink_callback *cb) id_stats->qp_type = id->qp_type; i_id++; + nlmsg_end(skb, nlh); } cb->args[1] = 0; -- GitLab From bd4a96921d8bac60ae51666d587f1f405c9df708 Mon Sep 17 00:00:00 2001 From: Maciej Purski Date: Wed, 22 Nov 2017 16:32:15 +0100 Subject: [PATCH 0203/1635] hwmon: (ina2xx) Make calibration register value fixed [ Upstream commit 5d389b125186cf254ad5b8015763ac07c151aea4 ] Calibration register is used for calculating current register in hardware according to datasheet: current = shunt_volt * calib_register / 2048 (ina 226) current = shunt_volt * calib_register / 4096 (ina 219) Fix calib_register value to 2048 for ina226 and 4096 for ina 219 in order to avoid truncation error and provide best precision allowed by shunt_voltage measurement. Make current scale value follow changes of shunt_resistor from sysfs as calib_register value is now fixed. Power_lsb value should also follow shunt_resistor changes as stated in datasheet: power_lsb = 25 * current_lsb (ina 226) power_lsb = 20 * current_lsb (ina 219) Signed-off-by: Maciej Purski Signed-off-by: Guenter Roeck Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/hwmon/ina2xx.c | 87 ++++++++++++++++++++++++------------------ 1 file changed, 50 insertions(+), 37 deletions(-) diff --git a/drivers/hwmon/ina2xx.c b/drivers/hwmon/ina2xx.c index 62e38fa8cda2..e362a932fe8c 100644 --- a/drivers/hwmon/ina2xx.c +++ b/drivers/hwmon/ina2xx.c @@ -95,18 +95,20 @@ enum ina2xx_ids { ina219, ina226 }; struct ina2xx_config { u16 config_default; - int calibration_factor; + int calibration_value; int registers; int shunt_div; int bus_voltage_shift; int bus_voltage_lsb; /* uV */ - int power_lsb; /* uW */ + int power_lsb_factor; }; struct ina2xx_data { const struct ina2xx_config *config; long rshunt; + long current_lsb_uA; + long power_lsb_uW; struct mutex config_lock; struct regmap *regmap; @@ -116,21 +118,21 @@ struct ina2xx_data { static const struct ina2xx_config ina2xx_config[] = { [ina219] = { .config_default = INA219_CONFIG_DEFAULT, - .calibration_factor = 40960000, + .calibration_value = 4096, .registers = INA219_REGISTERS, .shunt_div = 100, .bus_voltage_shift = 3, .bus_voltage_lsb = 4000, - .power_lsb = 20000, + .power_lsb_factor = 20, }, [ina226] = { .config_default = INA226_CONFIG_DEFAULT, - .calibration_factor = 5120000, + .calibration_value = 2048, .registers = INA226_REGISTERS, .shunt_div = 400, .bus_voltage_shift = 0, .bus_voltage_lsb = 1250, - .power_lsb = 25000, + .power_lsb_factor = 25, }, }; @@ -169,12 +171,16 @@ static u16 ina226_interval_to_reg(int interval) return INA226_SHIFT_AVG(avg_bits); } +/* + * Calibration register is set to the best value, which eliminates + * truncation errors on calculating current register in hardware. + * According to datasheet (eq. 3) the best values are 2048 for + * ina226 and 4096 for ina219. They are hardcoded as calibration_value. + */ static int ina2xx_calibrate(struct ina2xx_data *data) { - u16 val = DIV_ROUND_CLOSEST(data->config->calibration_factor, - data->rshunt); - - return regmap_write(data->regmap, INA2XX_CALIBRATION, val); + return regmap_write(data->regmap, INA2XX_CALIBRATION, + data->config->calibration_value); } /* @@ -187,10 +193,6 @@ static int ina2xx_init(struct ina2xx_data *data) if (ret < 0) return ret; - /* - * Set current LSB to 1mA, shunt is in uOhms - * (equation 13 in datasheet). - */ return ina2xx_calibrate(data); } @@ -268,15 +270,15 @@ static int ina2xx_get_value(struct ina2xx_data *data, u8 reg, val = DIV_ROUND_CLOSEST(val, 1000); break; case INA2XX_POWER: - val = regval * data->config->power_lsb; + val = regval * data->power_lsb_uW; break; case INA2XX_CURRENT: - /* signed register, LSB=1mA (selected), in mA */ - val = (s16)regval; + /* signed register, result in mA */ + val = regval * data->current_lsb_uA; + val = DIV_ROUND_CLOSEST(val, 1000); break; case INA2XX_CALIBRATION: - val = DIV_ROUND_CLOSEST(data->config->calibration_factor, - regval); + val = regval; break; default: /* programmer goofed */ @@ -304,9 +306,32 @@ static ssize_t ina2xx_show_value(struct device *dev, ina2xx_get_value(data, attr->index, regval)); } -static ssize_t ina2xx_set_shunt(struct device *dev, - struct device_attribute *da, - const char *buf, size_t count) +/* + * In order to keep calibration register value fixed, the product + * of current_lsb and shunt_resistor should also be fixed and equal + * to shunt_voltage_lsb = 1 / shunt_div multiplied by 10^9 in order + * to keep the scale. + */ +static int ina2xx_set_shunt(struct ina2xx_data *data, long val) +{ + unsigned int dividend = DIV_ROUND_CLOSEST(1000000000, + data->config->shunt_div); + if (val <= 0 || val > dividend) + return -EINVAL; + + mutex_lock(&data->config_lock); + data->rshunt = val; + data->current_lsb_uA = DIV_ROUND_CLOSEST(dividend, val); + data->power_lsb_uW = data->config->power_lsb_factor * + data->current_lsb_uA; + mutex_unlock(&data->config_lock); + + return 0; +} + +static ssize_t ina2xx_store_shunt(struct device *dev, + struct device_attribute *da, + const char *buf, size_t count) { unsigned long val; int status; @@ -316,18 +341,9 @@ static ssize_t ina2xx_set_shunt(struct device *dev, if (status < 0) return status; - if (val == 0 || - /* Values greater than the calibration factor make no sense. */ - val > data->config->calibration_factor) - return -EINVAL; - - mutex_lock(&data->config_lock); - data->rshunt = val; - status = ina2xx_calibrate(data); - mutex_unlock(&data->config_lock); + status = ina2xx_set_shunt(data, val); if (status < 0) return status; - return count; } @@ -387,7 +403,7 @@ static SENSOR_DEVICE_ATTR(power1_input, S_IRUGO, ina2xx_show_value, NULL, /* shunt resistance */ static SENSOR_DEVICE_ATTR(shunt_resistor, S_IRUGO | S_IWUSR, - ina2xx_show_value, ina2xx_set_shunt, + ina2xx_show_value, ina2xx_store_shunt, INA2XX_CALIBRATION); /* update interval (ina226 only) */ @@ -448,10 +464,7 @@ static int ina2xx_probe(struct i2c_client *client, val = INA2XX_RSHUNT_DEFAULT; } - if (val <= 0 || val > data->config->calibration_factor) - return -ENODEV; - - data->rshunt = val; + ina2xx_set_shunt(data, val); ina2xx_regmap_config.max_register = data->config->registers; -- GitLab From 6e7b07606bfe8201854a1bf5c5ba1cdd3a971783 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jernej=20=C5=A0krabec?= Date: Sat, 30 Dec 2017 22:01:54 +0100 Subject: [PATCH 0204/1635] clk: sunxi-ng: a83t: Add M divider to TCON1 clock [ Upstream commit 7dbc7f5f4904cfddc199af171ea095490a434f15 ] TCON1 also has M divider, contrary to TCON0. And the mux is only 2 bits wide, instead of 3. Fixes: 05359be1176b ("clk: sunxi-ng: Add driver for A83T CCU") Signed-off-by: Jernej Skrabec [wens@csie.org: Add description about mux width difference] Signed-off-by: Chen-Yu Tsai Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/clk/sunxi-ng/ccu-sun8i-a83t.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-a83t.c b/drivers/clk/sunxi-ng/ccu-sun8i-a83t.c index f8203115a6bc..c10160d7a556 100644 --- a/drivers/clk/sunxi-ng/ccu-sun8i-a83t.c +++ b/drivers/clk/sunxi-ng/ccu-sun8i-a83t.c @@ -493,8 +493,8 @@ static SUNXI_CCU_MUX_WITH_GATE(tcon0_clk, "tcon0", tcon0_parents, 0x118, 24, 3, BIT(31), CLK_SET_RATE_PARENT); static const char * const tcon1_parents[] = { "pll-video1" }; -static SUNXI_CCU_MUX_WITH_GATE(tcon1_clk, "tcon1", tcon1_parents, - 0x11c, 24, 3, BIT(31), CLK_SET_RATE_PARENT); +static SUNXI_CCU_M_WITH_MUX_GATE(tcon1_clk, "tcon1", tcon1_parents, + 0x11c, 0, 4, 24, 2, BIT(31), CLK_SET_RATE_PARENT); static SUNXI_CCU_GATE(csi_misc_clk, "csi-misc", "osc24M", 0x130, BIT(16), 0); -- GitLab From 543d317db8be1a9ce50f07f8a3d2118f89eda0d6 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 28 Dec 2017 09:16:47 -0500 Subject: [PATCH 0205/1635] media: videobuf2-core: don't go out of the buffer range [ Upstream commit df93dc61b0d8b19a5c9db545cf3fcc24f88dfde4 ] Currently, there's no check if an invalid buffer range is passed. However, while testing DVB memory mapped apps, I got this: videobuf2_core: VB: num_buffers -2143943680, buffer 33, index -2143943647 unable to handle kernel paging request at ffff888b773c0890 IP: __vb2_queue_alloc+0x134/0x4e0 [videobuf2_core] PGD 4142c7067 P4D 4142c7067 PUD 0 Oops: 0002 [#1] SMP Modules linked in: xt_CHECKSUM iptable_mangle ipt_MASQUERADE nf_nat_masquerade_ipv4 iptable_nat nf_nat_ipv4 nf_nat nf_conntrack_ipv4 nf_defrag_ipv4 xt_conntrack nf_conntrack tun bridge stp llc ebtable_filter ebtables ip6table_filter ip6_tables bluetooth rfkill ecdh_generic binfmt_misc rc_dvbsky sp2 ts2020 intel_rapl x86_pkg_temp_thermal dvb_usb_dvbsky intel_powerclamp dvb_usb_v2 coretemp m88ds3103 kvm_intel i2c_mux dvb_core snd_hda_codec_hdmi crct10dif_pclmul crc32_pclmul videobuf2_vmalloc videobuf2_memops snd_hda_intel ghash_clmulni_intel videobuf2_core snd_hda_codec rc_core mei_me intel_cstate snd_hwdep snd_hda_core videodev intel_uncore snd_pcm mei media tpm_tis tpm_tis_core intel_rapl_perf tpm snd_timer lpc_ich snd soundcore kvm irqbypass libcrc32c i915 i2c_algo_bit drm_kms_helper e1000e ptp drm crc32c_intel video pps_core CPU: 3 PID: 1776 Comm: dvbv5-zap Not tainted 4.14.0+ #78 Hardware name: /NUC5i7RYB, BIOS RYBDWi35.86A.0364.2017.0511.0949 05/11/2017 task: ffff88877c73bc80 task.stack: ffffb7c402418000 RIP: 0010:__vb2_queue_alloc+0x134/0x4e0 [videobuf2_core] RSP: 0018:ffffb7c40241bc60 EFLAGS: 00010246 RAX: 0000000080360421 RBX: 0000000000000021 RCX: 000000000000000a RDX: ffffb7c40241bcf4 RSI: ffff888780362c60 RDI: ffff888796d8e130 RBP: ffffb7c40241bcc8 R08: 0000000000000316 R09: 0000000000000004 R10: ffff888780362c00 R11: 0000000000000001 R12: 000000000002f000 R13: ffff8887758be700 R14: 0000000000021000 R15: 0000000000000001 FS: 00007f2849024740(0000) GS:ffff888796d80000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: ffff888b773c0890 CR3: 000000043beb2005 CR4: 00000000003606e0 Call Trace: vb2_core_reqbufs+0x226/0x420 [videobuf2_core] dvb_vb2_reqbufs+0x2d/0xc0 [dvb_core] dvb_dvr_do_ioctl+0x98/0x1d0 [dvb_core] dvb_usercopy+0x53/0x1b0 [dvb_core] ? dvb_demux_ioctl+0x20/0x20 [dvb_core] ? tty_ldisc_deref+0x16/0x20 ? tty_write+0x1f9/0x310 ? process_echoes+0x70/0x70 dvb_dvr_ioctl+0x15/0x20 [dvb_core] do_vfs_ioctl+0xa5/0x600 SyS_ioctl+0x79/0x90 entry_SYSCALL_64_fastpath+0x1a/0xa5 RIP: 0033:0x7f28486f7ea7 RSP: 002b:00007ffc13b2db18 EFLAGS: 00000246 ORIG_RAX: 0000000000000010 RAX: ffffffffffffffda RBX: 000055b10fc06130 RCX: 00007f28486f7ea7 RDX: 00007ffc13b2db48 RSI: 00000000c0086f3c RDI: 0000000000000007 RBP: 0000000000000203 R08: 000055b10df1e02c R09: 000000000000002e R10: 0036b42415108357 R11: 0000000000000246 R12: 0000000000000000 R13: 00007f2849062f60 R14: 00000000000001f1 R15: 00007ffc13b2da54 Code: 74 0a 60 8b 0a 48 83 c0 30 48 83 c2 04 89 48 d0 89 48 d4 48 39 f0 75 eb 41 8b 42 08 83 7d d4 01 41 c7 82 ec 01 00 00 ff ff ff ff <4d> 89 94 c5 88 00 00 00 74 14 83 c3 01 41 39 dc 0f 85 f1 fe ff RIP: __vb2_queue_alloc+0x134/0x4e0 [videobuf2_core] RSP: ffffb7c40241bc60 CR2: ffff888b773c0890 So, add a sanity check in order to prevent going past array. Signed-off-by: Mauro Carvalho Chehab Acked-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/media/v4l2-core/videobuf2-core.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/media/v4l2-core/videobuf2-core.c b/drivers/media/v4l2-core/videobuf2-core.c index cb115ba6a1d2..6d9adcaa26ba 100644 --- a/drivers/media/v4l2-core/videobuf2-core.c +++ b/drivers/media/v4l2-core/videobuf2-core.c @@ -332,6 +332,10 @@ static int __vb2_queue_alloc(struct vb2_queue *q, enum vb2_memory memory, struct vb2_buffer *vb; int ret; + /* Ensure that q->num_buffers+num_buffers is below VB2_MAX_FRAME */ + num_buffers = min_t(unsigned int, num_buffers, + VB2_MAX_FRAME - q->num_buffers); + for (buffer = 0; buffer < num_buffers; ++buffer) { /* Allocate videobuf buffer structures */ vb = kzalloc(q->buf_struct_size, GFP_KERNEL); -- GitLab From 522371c28210e8ed6331d76f05c4349077489de9 Mon Sep 17 00:00:00 2001 From: Pardha Saradhi K Date: Tue, 2 Jan 2018 14:59:57 +0530 Subject: [PATCH 0206/1635] ASoC: Intel: Skylake: Disable clock gating during firmware and library download [ Upstream commit d5cc0a1fcbb5ddbef9fdd4c4a978da3254ddbf37 ] During firmware and library download, sometimes it is observed that firmware and library download is timed-out resulting into probe failure. This patch disables dynamic clock gating while firmware and library download. Signed-off-by: Pardha Saradhi K Signed-off-by: Sanyog Kale Signed-off-by: Guneshwor Singh Acked-By: Vinod Koul Signed-off-by: Mark Brown Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- sound/soc/intel/skylake/skl-messages.c | 4 ++++ sound/soc/intel/skylake/skl-pcm.c | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/sound/soc/intel/skylake/skl-messages.c b/sound/soc/intel/skylake/skl-messages.c index 89f70133c8e4..b74a6040cd96 100644 --- a/sound/soc/intel/skylake/skl-messages.c +++ b/sound/soc/intel/skylake/skl-messages.c @@ -404,7 +404,11 @@ int skl_resume_dsp(struct skl *skl) if (skl->skl_sst->is_first_boot == true) return 0; + /* disable dynamic clock gating during fw and lib download */ + ctx->enable_miscbdcge(ctx->dev, false); + ret = skl_dsp_wake(ctx->dsp); + ctx->enable_miscbdcge(ctx->dev, true); if (ret < 0) return ret; diff --git a/sound/soc/intel/skylake/skl-pcm.c b/sound/soc/intel/skylake/skl-pcm.c index 2b1e513b1680..7fe1e8f273a0 100644 --- a/sound/soc/intel/skylake/skl-pcm.c +++ b/sound/soc/intel/skylake/skl-pcm.c @@ -1332,7 +1332,11 @@ static int skl_platform_soc_probe(struct snd_soc_platform *platform) return -EIO; } + /* disable dynamic clock gating during fw and lib download */ + skl->skl_sst->enable_miscbdcge(platform->dev, false); + ret = ops->init_fw(platform->dev, skl->skl_sst); + skl->skl_sst->enable_miscbdcge(platform->dev, true); if (ret < 0) { dev_err(platform->dev, "Failed to boot first fw: %d\n", ret); return ret; -- GitLab From 1d65600e9722e355bd9e3680290ae5a2fe6d0fff Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Tue, 2 Jan 2018 19:53:14 +0100 Subject: [PATCH 0207/1635] ASoC: Intel: cht_bsw_rt5645: Analog Mic support [ Upstream commit b70b309950418437bbd2a30afd169c4f09dee3e5 ] Various Cherry Trail boards with a rt5645 codec have an analog mic connected to IN2P + IN2N. The mic on this boards also needs micbias to be enabled, on some boards micbias1 is used and on others micbias2, so we enable both. This commit adds a new "Int Analog Mic" DAPM widget for this, so that we do not end up enabling micbias on boards with a digital mic which uses the already present "Int Mic" widget. Some existing UCM files already refer to "Int Mic" for their "Internal Analog Microphones" SectionDevice, but these don't work anyways since they enable the RECMIX BST1 Switch instead of the BST2 switch. Signed-off-by: Hans de Goede Signed-off-by: Mark Brown Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- sound/soc/intel/boards/cht_bsw_rt5645.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/sound/soc/intel/boards/cht_bsw_rt5645.c b/sound/soc/intel/boards/cht_bsw_rt5645.c index 5bcde01d15e6..fbfb76ee2346 100644 --- a/sound/soc/intel/boards/cht_bsw_rt5645.c +++ b/sound/soc/intel/boards/cht_bsw_rt5645.c @@ -133,6 +133,7 @@ static const struct snd_soc_dapm_widget cht_dapm_widgets[] = { SND_SOC_DAPM_HP("Headphone", NULL), SND_SOC_DAPM_MIC("Headset Mic", NULL), SND_SOC_DAPM_MIC("Int Mic", NULL), + SND_SOC_DAPM_MIC("Int Analog Mic", NULL), SND_SOC_DAPM_SPK("Ext Spk", NULL), SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0, platform_clock_control, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), @@ -143,6 +144,8 @@ static const struct snd_soc_dapm_route cht_rt5645_audio_map[] = { {"IN1N", NULL, "Headset Mic"}, {"DMIC L1", NULL, "Int Mic"}, {"DMIC R1", NULL, "Int Mic"}, + {"IN2P", NULL, "Int Analog Mic"}, + {"IN2N", NULL, "Int Analog Mic"}, {"Headphone", NULL, "HPOL"}, {"Headphone", NULL, "HPOR"}, {"Ext Spk", NULL, "SPOL"}, @@ -150,6 +153,9 @@ static const struct snd_soc_dapm_route cht_rt5645_audio_map[] = { {"Headphone", NULL, "Platform Clock"}, {"Headset Mic", NULL, "Platform Clock"}, {"Int Mic", NULL, "Platform Clock"}, + {"Int Analog Mic", NULL, "Platform Clock"}, + {"Int Analog Mic", NULL, "micbias1"}, + {"Int Analog Mic", NULL, "micbias2"}, {"Ext Spk", NULL, "Platform Clock"}, }; @@ -204,6 +210,7 @@ static const struct snd_kcontrol_new cht_mc_controls[] = { SOC_DAPM_PIN_SWITCH("Headphone"), SOC_DAPM_PIN_SWITCH("Headset Mic"), SOC_DAPM_PIN_SWITCH("Int Mic"), + SOC_DAPM_PIN_SWITCH("Int Analog Mic"), SOC_DAPM_PIN_SWITCH("Ext Spk"), }; -- GitLab From 978c2812b8053d6bee6a20bcbdd59e76cfaafdbf Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 3 Jan 2018 18:11:14 +0100 Subject: [PATCH 0208/1635] spi: sh-msiof: Fix timeout failures for TX-only DMA transfers [ Upstream commit 89434c3c35081439627baa2225622d5bd12242fe ] When using RX (with or without TX), the DMA interrupt triggers completion when the RX FIFO has been emptied, i.e. after the full transfer has finished. However, when using TX without RX, the DMA interrupt triggers completion as soon as the DMA engine has filled the TX FIFO, i.e. before the full transfer has finished. Then sh_msiof_modify_ctr_wait() will spin until the transfer has really finished and the TFSE bit is cleared, for at most 1 ms. For slow speeds and/or large transfers, this may cause timeouts and transfer failures: spi_sh_msiof e6e10000.spi: failed to shut down hardware 74x164 spi2.0: SPI transfer failed: -110 spi_master spi2: failed to transfer one message from queue 74x164 spi2.0: Failed writing: -110 Fix this by waiting explicitly until the TX FIFO has been emptied. Based on a patch in the BSP by Hiromitsu Yamasaki. Signed-off-by: Geert Uytterhoeven Signed-off-by: Mark Brown Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/spi/spi-sh-msiof.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/drivers/spi/spi-sh-msiof.c b/drivers/spi/spi-sh-msiof.c index 092a5fc85b9a..2770fbd4ce49 100644 --- a/drivers/spi/spi-sh-msiof.c +++ b/drivers/spi/spi-sh-msiof.c @@ -797,11 +797,21 @@ static int sh_msiof_dma_once(struct sh_msiof_spi_priv *p, const void *tx, goto stop_dma; } - /* wait for tx fifo to be emptied / rx fifo to be filled */ + /* wait for tx/rx DMA completion */ ret = sh_msiof_wait_for_completion(p); if (ret) goto stop_reset; + if (!rx) { + reinit_completion(&p->done); + sh_msiof_write(p, IER, IER_TEOFE); + + /* wait for tx fifo to be emptied */ + ret = sh_msiof_wait_for_completion(p); + if (ret) + goto stop_reset; + } + /* clear status bits */ sh_msiof_reset_str(p); -- GitLab From 3807b6fec674e88d9cc653427728581263311141 Mon Sep 17 00:00:00 2001 From: Rafael David Tinoco Date: Thu, 7 Dec 2017 19:59:13 -0200 Subject: [PATCH 0209/1635] scsi: libiscsi: Allow sd_shutdown on bad transport [ Upstream commit d754941225a7dbc61f6dd2173fa9498049f9a7ee ] If, for any reason, userland shuts down iscsi transport interfaces before proper logouts - like when logging in to LUNs manually, without logging out on server shutdown, or when automated scripts can't umount/logout from logged LUNs - kernel will hang forever on its sd_sync_cache() logic, after issuing the SYNCHRONIZE_CACHE cmd to all still existent paths. PID: 1 TASK: ffff8801a69b8000 CPU: 1 COMMAND: "systemd-shutdow" #0 [ffff8801a69c3a30] __schedule at ffffffff8183e9ee #1 [ffff8801a69c3a80] schedule at ffffffff8183f0d5 #2 [ffff8801a69c3a98] schedule_timeout at ffffffff81842199 #3 [ffff8801a69c3b40] io_schedule_timeout at ffffffff8183e604 #4 [ffff8801a69c3b70] wait_for_completion_io_timeout at ffffffff8183fc6c #5 [ffff8801a69c3bd0] blk_execute_rq at ffffffff813cfe10 #6 [ffff8801a69c3c88] scsi_execute at ffffffff815c3fc7 #7 [ffff8801a69c3cc8] scsi_execute_req_flags at ffffffff815c60fe #8 [ffff8801a69c3d30] sd_sync_cache at ffffffff815d37d7 #9 [ffff8801a69c3da8] sd_shutdown at ffffffff815d3c3c This happens because iscsi_eh_cmd_timed_out(), the transport layer timeout helper, would tell the queue timeout function (scsi_times_out) to reset the request timer over and over, until the session state is back to logged in state. Unfortunately, during server shutdown, this might never happen again. Other option would be "not to handle" the issue in the transport layer. That would trigger the error handler logic, which would also need the session state to be logged in again. Best option, for such case, is to tell upper layers that the command was handled during the transport layer error handler helper, marking it as DID_NO_CONNECT, which will allow completion and inform about the problem. After the session was marked as ISCSI_STATE_FAILED, due to the first timeout during the server shutdown phase, all subsequent cmds will fail to be queued, allowing upper logic to fail faster. Signed-off-by: Rafael David Tinoco Reviewed-by: Lee Duncan Signed-off-by: Martin K. Petersen Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/libiscsi.c | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c index f8dc1601efd5..bddbe2da5283 100644 --- a/drivers/scsi/libiscsi.c +++ b/drivers/scsi/libiscsi.c @@ -1696,6 +1696,15 @@ int iscsi_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *sc) */ switch (session->state) { case ISCSI_STATE_FAILED: + /* + * cmds should fail during shutdown, if the session + * state is bad, allowing completion to happen + */ + if (unlikely(system_state != SYSTEM_RUNNING)) { + reason = FAILURE_SESSION_FAILED; + sc->result = DID_NO_CONNECT << 16; + break; + } case ISCSI_STATE_IN_RECOVERY: reason = FAILURE_SESSION_IN_RECOVERY; sc->result = DID_IMM_RETRY << 16; @@ -1980,6 +1989,19 @@ enum blk_eh_timer_return iscsi_eh_cmd_timed_out(struct scsi_cmnd *sc) } if (session->state != ISCSI_STATE_LOGGED_IN) { + /* + * During shutdown, if session is prematurely disconnected, + * recovery won't happen and there will be hung cmds. Not + * handling cmds would trigger EH, also bad in this case. + * Instead, handle cmd, allow completion to happen and let + * upper layer to deal with the result. + */ + if (unlikely(system_state != SYSTEM_RUNNING)) { + sc->result = DID_NO_CONNECT << 16; + ISCSI_DBG_EH(session, "sc on shutdown, handled\n"); + rc = BLK_EH_HANDLED; + goto done; + } /* * We are probably in the middle of iscsi recovery so let * that complete and handle the error. @@ -2084,7 +2106,7 @@ enum blk_eh_timer_return iscsi_eh_cmd_timed_out(struct scsi_cmnd *sc) task->last_timeout = jiffies; spin_unlock(&session->frwd_lock); ISCSI_DBG_EH(session, "return %s\n", rc == BLK_EH_RESET_TIMER ? - "timer reset" : "nh"); + "timer reset" : "shutdown or nh"); return rc; } EXPORT_SYMBOL_GPL(iscsi_eh_cmd_timed_out); -- GitLab From b5d2cafbe359109fdae12415a7d234cd1ffc60cf Mon Sep 17 00:00:00 2001 From: Chaitra P B Date: Wed, 27 Dec 2017 23:09:11 -0800 Subject: [PATCH 0210/1635] scsi: mpt3sas: Proper handling of set/clear of "ATA command pending" flag. [ Upstream commit f49d4aed1315a7b766d855f1367142e682b0cc87 ] 1. In IO path, setting of "ATA command pending" flag early before device removal, invalid device handle etc., checks causes any new commands to be always returned with SAM_STAT_BUSY and when the driver removes the drive the SML issues SYNC Cache command and that command is always returned with SAM_STAT_BUSY and thus making SYNC Cache command to requeued. 2. If the driver gets an ATA PT command for a SATA drive then the driver set "ATA command pending" flag in device specific data structure not to allow any further commands until the ATA PT command is completed. However, after setting the flag if the driver decides to return the command back to upper layers without actually issuing to the firmware (i.e., returns from qcmd failure return paths) then the corresponding flag is not cleared and this prevents the driver from sending any new commands to the drive. This patch fixes above two issues by setting of "ATA command pending" flag after checking for whether device deleted, invalid device handle, device busy with task management. And by setting "ATA command pending" flag to false in all of the qcmd failure return paths after setting the flag. Signed-off-by: Chaitra P B Signed-off-by: Suganath Prabu S Signed-off-by: Martin K. Petersen Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/mpt3sas/mpt3sas_scsih.c | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/drivers/scsi/mpt3sas/mpt3sas_scsih.c b/drivers/scsi/mpt3sas/mpt3sas_scsih.c index beb4bf8fe9b0..139219c994e9 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_scsih.c +++ b/drivers/scsi/mpt3sas/mpt3sas_scsih.c @@ -4106,19 +4106,6 @@ scsih_qcmd(struct Scsi_Host *shost, struct scsi_cmnd *scmd) return 0; } - /* - * Bug work around for firmware SATL handling. The loop - * is based on atomic operations and ensures consistency - * since we're lockless at this point - */ - do { - if (test_bit(0, &sas_device_priv_data->ata_command_pending)) { - scmd->result = SAM_STAT_BUSY; - scmd->scsi_done(scmd); - return 0; - } - } while (_scsih_set_satl_pending(scmd, true)); - sas_target_priv_data = sas_device_priv_data->sas_target; /* invalid device handle */ @@ -4144,6 +4131,19 @@ scsih_qcmd(struct Scsi_Host *shost, struct scsi_cmnd *scmd) sas_device_priv_data->block) return SCSI_MLQUEUE_DEVICE_BUSY; + /* + * Bug work around for firmware SATL handling. The loop + * is based on atomic operations and ensures consistency + * since we're lockless at this point + */ + do { + if (test_bit(0, &sas_device_priv_data->ata_command_pending)) { + scmd->result = SAM_STAT_BUSY; + scmd->scsi_done(scmd); + return 0; + } + } while (_scsih_set_satl_pending(scmd, true)); + if (scmd->sc_data_direction == DMA_FROM_DEVICE) mpi_control = MPI2_SCSIIO_CONTROL_READ; else if (scmd->sc_data_direction == DMA_TO_DEVICE) @@ -4170,6 +4170,7 @@ scsih_qcmd(struct Scsi_Host *shost, struct scsi_cmnd *scmd) if (!smid) { pr_err(MPT3SAS_FMT "%s: failed obtaining a smid\n", ioc->name, __func__); + _scsih_set_satl_pending(scmd, false); goto out; } mpi_request = mpt3sas_base_get_msg_frame(ioc, smid); @@ -4200,6 +4201,7 @@ scsih_qcmd(struct Scsi_Host *shost, struct scsi_cmnd *scmd) if (mpi_request->DataLength) { if (ioc->build_sg_scmd(ioc, scmd, smid)) { mpt3sas_base_free_smid(ioc, smid); + _scsih_set_satl_pending(scmd, false); goto out; } } else -- GitLab From 04568f4df2280cd7f42ce4a9da2789a3eacb779c Mon Sep 17 00:00:00 2001 From: Shanker Donthineni Date: Tue, 5 Dec 2017 13:16:21 -0600 Subject: [PATCH 0211/1635] irqchip/gic-v3: Fix the driver probe() fail due to disabled GICC entry [ Upstream commit ebe2f8718007d5a1238bb3cb8141b5bb2b4d5773 ] The ACPI specification says OS shouldn't attempt to use GICC configuration parameters if the flag ACPI_MADT_ENABLED is cleared. The ARM64-SMP code skips the disabled GICC entries but not causing any issue. However the current GICv3 driver probe bails out causing kernel panic() instead of skipping the disabled GICC interfaces. This issue happens on systems where redistributor regions are not in the always-on power domain and one of GICC interface marked with ACPI_MADT_ENABLED=0. This patch does the two things to fix the panic. - Don't return an error in gic_acpi_match_gicc() for disabled GICC entry. - No need to keep GICR region information for disabled GICC entry. Observed kernel crash on QDF2400 platform GICC entry is disabled. Kernel crash traces: Kernel panic - not syncing: No interrupt controller found. CPU: 0 PID: 0 Comm: swapper/0 Not tainted 4.13.5 #26 [] dump_backtrace+0x0/0x218 [] show_stack+0x14/0x20 [] dump_stack+0x98/0xb8 [] panic+0x118/0x26c [] init_IRQ+0x24/0x2c [] start_kernel+0x230/0x394 [] __primary_switched+0x64/0x6c ---[ end Kernel panic - not syncing: No interrupt controller found. Disabled GICC subtable example: Subtable Type : 0B [Generic Interrupt Controller] Length : 50 Reserved : 0000 CPU Interface Number : 0000003D Processor UID : 0000003D Flags (decoded below) : 00000000 Processor Enabled : 0 Performance Interrupt Trig Mode : 0 Virtual GIC Interrupt Trig Mode : 0 Parking Protocol Version : 00000000 Performance Interrupt : 00000017 Parked Address : 0000000000000000 Base Address : 0000000000000000 Virtual GIC Base Address : 0000000000000000 Hypervisor GIC Base Address : 0000000000000000 Virtual GIC Interrupt : 00000019 Redistributor Base Address : 0000FFFF88F40000 ARM MPIDR : 000000000000000D Efficiency Class : 00 Reserved : 000000 Signed-off-by: Shanker Donthineni Signed-off-by: Marc Zyngier Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/irqchip/irq-gic-v3.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c index ae9ff72e83ee..848fcdf6a112 100644 --- a/drivers/irqchip/irq-gic-v3.c +++ b/drivers/irqchip/irq-gic-v3.c @@ -1297,6 +1297,10 @@ gic_acpi_parse_madt_gicc(struct acpi_subtable_header *header, u32 size = reg == GIC_PIDR2_ARCH_GICv4 ? SZ_64K * 4 : SZ_64K * 2; void __iomem *redist_base; + /* GICC entry which has !ACPI_MADT_ENABLED is not unusable so skip */ + if (!(gicc->flags & ACPI_MADT_ENABLED)) + return 0; + redist_base = ioremap(gicc->gicr_base_address, size); if (!redist_base) return -ENOMEM; @@ -1346,6 +1350,13 @@ static int __init gic_acpi_match_gicc(struct acpi_subtable_header *header, if ((gicc->flags & ACPI_MADT_ENABLED) && gicc->gicr_base_address) return 0; + /* + * It's perfectly valid firmware can pass disabled GICC entry, driver + * should not treat as errors, skip the entry instead of probe fail. + */ + if (!(gicc->flags & ACPI_MADT_ENABLED)) + return 0; + return -ENODEV; } -- GitLab From 74f5124bc3ff2f6c7fa4386901970766faed5dea Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 2 Jan 2018 16:26:31 +0100 Subject: [PATCH 0212/1635] ACPI: EC: Fix debugfs_create_*() usage [ Upstream commit 3522f867c13b63cf62acdf1b8ca5664c549a716a ] acpi_ec.gpe is "unsigned long", hence treating it as "u32" would expose the wrong half on big-endian 64-bit systems. Fix this by changing its type to "u32" and removing the cast, as all other code already uses u32 or sometimes even only u8. Fixes: 1195a098168fcacf (ACPI: Provide /sys/kernel/debug/ec/...) Signed-off-by: Geert Uytterhoeven Signed-off-by: Rafael J. Wysocki Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/acpi/ec.c | 2 +- drivers/acpi/ec_sys.c | 2 +- drivers/acpi/internal.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index df842465634a..6adcda057b36 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -1516,7 +1516,7 @@ static int acpi_ec_setup(struct acpi_ec *ec, bool handle_events) } acpi_handle_info(ec->handle, - "GPE=0x%lx, EC_CMD/EC_SC=0x%lx, EC_DATA=0x%lx\n", + "GPE=0x%x, EC_CMD/EC_SC=0x%lx, EC_DATA=0x%lx\n", ec->gpe, ec->command_addr, ec->data_addr); return ret; } diff --git a/drivers/acpi/ec_sys.c b/drivers/acpi/ec_sys.c index 6c7dd7af789e..dd70d6c2bca0 100644 --- a/drivers/acpi/ec_sys.c +++ b/drivers/acpi/ec_sys.c @@ -128,7 +128,7 @@ static int acpi_ec_add_debugfs(struct acpi_ec *ec, unsigned int ec_device_count) return -ENOMEM; } - if (!debugfs_create_x32("gpe", 0444, dev_dir, (u32 *)&first_ec->gpe)) + if (!debugfs_create_x32("gpe", 0444, dev_dir, &first_ec->gpe)) goto error; if (!debugfs_create_bool("use_global_lock", 0444, dev_dir, &first_ec->global_lock)) diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h index ede83d38beed..2cd2ae152ab7 100644 --- a/drivers/acpi/internal.h +++ b/drivers/acpi/internal.h @@ -159,7 +159,7 @@ static inline void acpi_early_processor_osc(void) {} -------------------------------------------------------------------------- */ struct acpi_ec { acpi_handle handle; - unsigned long gpe; + u32 gpe; unsigned long command_addr; unsigned long data_addr; bool global_lock; -- GitLab From bb23fbd8fb065e309c5ba24cdc93c5260d15c775 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Peter=20Gro=C3=9Fe?= Date: Wed, 13 Dec 2017 18:29:46 +0100 Subject: [PATCH 0213/1635] mac80211: Fix setting TX power on monitor interfaces MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit 3a3713ec360138f806c6fc368d1de570f692b347 ] Instead of calling ieee80211_recalc_txpower on monitor interfaces directly, call it using the virtual monitor interface, if one exists. In case of a single monitor interface given, reject setting TX power, if no virtual monitor interface exists. That being checked, don't warn in ieee80211_bss_info_change_notify, after setting TX power on a monitor interface. Fixes warning: ------------[ cut here ]------------ WARNING: CPU: 0 PID: 2193 at net/mac80211/driver-ops.h:167 ieee80211_bss_info_change_notify+0x111/0x190 Modules linked in: uvcvideo videobuf2_vmalloc videobuf2_memops videobuf2_v4l2 videobuf2_core rndis_host cdc_ether usbnet mii tp_smapi(O) thinkpad_ec(O) ohci_hcd vboxpci(O) vboxnetadp(O) vboxnetflt(O) v boxdrv(O) x86_pkg_temp_thermal kvm_intel kvm irqbypass iwldvm iwlwifi ehci_pci ehci_hcd tpm_tis tpm_tis_core tpm CPU: 0 PID: 2193 Comm: iw Tainted: G O 4.12.12-gentoo #2 task: ffff880186fd5cc0 task.stack: ffffc90001b54000 RIP: 0010:ieee80211_bss_info_change_notify+0x111/0x190 RSP: 0018:ffffc90001b57a10 EFLAGS: 00010246 RAX: 0000000000000006 RBX: ffff8801052ce840 RCX: 0000000000000064 RDX: 00000000fffffffc RSI: 0000000000040000 RDI: ffff8801052ce840 RBP: ffffc90001b57a38 R08: 0000000000000062 R09: 0000000000000000 R10: ffff8802144b5000 R11: ffff880049dc4614 R12: 0000000000040000 R13: 0000000000000064 R14: ffff8802105f0760 R15: ffffc90001b57b48 FS: 00007f92644b4580(0000) GS:ffff88021e200000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 00007f9263c109f0 CR3: 00000001df850000 CR4: 00000000000406f0 Call Trace: ieee80211_recalc_txpower+0x33/0x40 ieee80211_set_tx_power+0x40/0x180 nl80211_set_wiphy+0x32e/0x950 Reported-by: Peter Große Signed-off-by: Peter Große Signed-off-by: Johannes Berg Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- net/mac80211/cfg.c | 28 +++++++++++++++++++++++++++- net/mac80211/driver-ops.h | 3 ++- 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 84f757c5d91a..288640471c2f 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -2373,10 +2373,17 @@ static int ieee80211_set_tx_power(struct wiphy *wiphy, struct ieee80211_sub_if_data *sdata; enum nl80211_tx_power_setting txp_type = type; bool update_txp_type = false; + bool has_monitor = false; if (wdev) { sdata = IEEE80211_WDEV_TO_SUB_IF(wdev); + if (sdata->vif.type == NL80211_IFTYPE_MONITOR) { + sdata = rtnl_dereference(local->monitor_sdata); + if (!sdata) + return -EOPNOTSUPP; + } + switch (type) { case NL80211_TX_POWER_AUTOMATIC: sdata->user_power_level = IEEE80211_UNSET_POWER_LEVEL; @@ -2415,15 +2422,34 @@ static int ieee80211_set_tx_power(struct wiphy *wiphy, mutex_lock(&local->iflist_mtx); list_for_each_entry(sdata, &local->interfaces, list) { + if (sdata->vif.type == NL80211_IFTYPE_MONITOR) { + has_monitor = true; + continue; + } sdata->user_power_level = local->user_power_level; if (txp_type != sdata->vif.bss_conf.txpower_type) update_txp_type = true; sdata->vif.bss_conf.txpower_type = txp_type; } - list_for_each_entry(sdata, &local->interfaces, list) + list_for_each_entry(sdata, &local->interfaces, list) { + if (sdata->vif.type == NL80211_IFTYPE_MONITOR) + continue; ieee80211_recalc_txpower(sdata, update_txp_type); + } mutex_unlock(&local->iflist_mtx); + if (has_monitor) { + sdata = rtnl_dereference(local->monitor_sdata); + if (sdata) { + sdata->user_power_level = local->user_power_level; + if (txp_type != sdata->vif.bss_conf.txpower_type) + update_txp_type = true; + sdata->vif.bss_conf.txpower_type = txp_type; + + ieee80211_recalc_txpower(sdata, update_txp_type); + } + } + return 0; } diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index c7f93fd9ca7a..4d82fe7d627c 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h @@ -165,7 +165,8 @@ static inline void drv_bss_info_changed(struct ieee80211_local *local, if (WARN_ON_ONCE(sdata->vif.type == NL80211_IFTYPE_P2P_DEVICE || sdata->vif.type == NL80211_IFTYPE_NAN || (sdata->vif.type == NL80211_IFTYPE_MONITOR && - !sdata->vif.mu_mimo_owner))) + !sdata->vif.mu_mimo_owner && + !(changed & BSS_CHANGED_TXPOWER)))) return; if (!check_sdata_in_driver(sdata)) -- GitLab From e985dcf4fa1b4962d97455495467e54d05acc150 Mon Sep 17 00:00:00 2001 From: "Pieter \\\"PoroCYon\\\" Sluys" Date: Thu, 4 Jan 2018 16:53:50 +0100 Subject: [PATCH 0214/1635] vfb: fix video mode and line_length being set when loaded [ Upstream commit 7b9faf5df0ac495a1a3d7cdb64921c179f9008ac ] Currently, when loading the vfb module, the newly created fbdev has a line_length of 0, and its video mode would be PSEUDOCOLOR regardless of color depth. (The former could be worked around by calling the FBIOPUT_VSCREENINFO ioctl with having the FBACTIVIATE_FORCE flag set.) This patch automatically sets the line_length correctly, and the video mode is derived from the bit depth now as well. Thanks to Geert Uytterhoeven for confirming the bug and helping me with the patch. Output of `fbset -i' before the patch: mode "1366x768-60" # D: 72.432 MHz, H: 47.403 kHz, V: 60.004 Hz geometry 1366 768 1366 768 32 timings 13806 120 10 14 3 32 5 rgba 8/0,8/8,8/16,8/24 endmode Frame buffer device information: Name : Virtual FB Address : 0xffffaa1405d85000 Size : 4196352 Type : PACKED PIXELS Visual : PSEUDOCOLOR XPanStep : 1 YPanStep : 1 YWrapStep : 1 LineLength : 0 <-- note this Accelerator : No After: mode "1366x768-60" # D: 72.432 MHz, H: 47.403 kHz, V: 60.004 Hz geometry 1366 768 1366 768 32 timings 13806 120 10 14 3 32 5 rgba 8/0,8/8,8/16,8/24 endmode Frame buffer device information: Name : Virtual FB Address : 0xffffaa1405d85000 Size : 4196352 Type : PACKED PIXELS Visual : TRUECOLOR XPanStep : 1 YPanStep : 1 YWrapStep : 1 LineLength : 5464 Accelerator : No Signed-off-by: "Pieter \"PoroCYon\" Sluys" Reviewed-by: Geert Uytterhoeven [b.zolnierkie: minor fixups] Signed-off-by: Bartlomiej Zolnierkiewicz Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/video/fbdev/vfb.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/drivers/video/fbdev/vfb.c b/drivers/video/fbdev/vfb.c index da653a080394..54127905bfe7 100644 --- a/drivers/video/fbdev/vfb.c +++ b/drivers/video/fbdev/vfb.c @@ -239,8 +239,23 @@ static int vfb_check_var(struct fb_var_screeninfo *var, */ static int vfb_set_par(struct fb_info *info) { + switch (info->var.bits_per_pixel) { + case 1: + info->fix.visual = FB_VISUAL_MONO01; + break; + case 8: + info->fix.visual = FB_VISUAL_PSEUDOCOLOR; + break; + case 16: + case 24: + case 32: + info->fix.visual = FB_VISUAL_TRUECOLOR; + break; + } + info->fix.line_length = get_line_length(info->var.xres_virtual, info->var.bits_per_pixel); + return 0; } @@ -450,6 +465,8 @@ static int vfb_probe(struct platform_device *dev) goto err2; platform_set_drvdata(dev, info); + vfb_set_par(info); + fb_info(info, "Virtual frame buffer device, using %ldK of video memory\n", videomemorysize >> 10); return 0; -- GitLab From 1f1e5ca1c737be1bc929811a8d9c0276d1662ece Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Thu, 4 Jan 2018 22:31:11 +0100 Subject: [PATCH 0215/1635] gpio: label descriptors using the device name [ Upstream commit 24e78079bf2250874e33da2e7cfbb6db72d3caf4 ] Some GPIO lines appear named "?" in the lsgpio dump due to their requesting drivers not passing a reasonable label. Most typically this happens if a device tree node just defines gpios = <...> and not foo-gpios = <...>, the former gets named "foo" and the latter gets named "?". However the struct device passed in is always valid so let's just label the GPIO with dev_name() on the device if no proper label was passed. Cc: Reported-by: Jason Kridner Reported-by: Jason Kridner Signed-off-by: Linus Walleij Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/gpio/gpiolib.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index bdd68ff197dc..b4c8b25453a6 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -3340,7 +3340,8 @@ struct gpio_desc *__must_check gpiod_get_index(struct device *dev, return desc; } - status = gpiod_request(desc, con_id); + /* If a connection label was passed use that, else use the device name as label */ + status = gpiod_request(desc, con_id ? con_id : dev_name(dev)); if (status < 0) return ERR_PTR(status); -- GitLab From da5e12ab599a61537cbaafe801e7422d1f43ac53 Mon Sep 17 00:00:00 2001 From: "Gautham R. Shenoy" Date: Wed, 13 Dec 2017 12:27:39 +0530 Subject: [PATCH 0216/1635] powernv-cpufreq: Add helper to extract pstate from PMSR [ Upstream commit ee1f4a7dafa997816ff3de96155c6f3edc21c1e6 ] On POWERNV platform, the fields for pstates in the Power Management Status Register (PMSR) and the Power Management Control Register (PMCR) are 8-bits wide. On POWER8 the pstates are negatively numbered while on POWER9 they are positively numbered. The device-tree exports pstates as 32-bit entries. The device-tree implementation sign-extends the 8-bit pstate values to obtain the corresponding 32-bit entry. Eg: On POWER8, a pstate value 0x82 [-126] is represented in the device-tree as 0xfffffff82 while on POWER9, the same value 0x82 [130] is represented in the device-tree as 0x00000082. The powernv-cpufreq driver implementation represents pstates using the integer type. In multiple places in the driver, the code interprets the pstates extracted from the PMSR as a signed byte and assigns it to a integer variable to get the sign-extention. On POWER9 platforms which have greater than 128 pstates, this results in the driver performing incorrect sign-extention, and thereby treating a legitimate pstate (say 130) as an invalid pstates (since it is interpreted as -126). This patch fixes the issue by implementing a helper function to extract Pstates from PMSR register, and correctly sign-extend it to be consistent with the values provided by the device-tree. Signed-off-by: Gautham R. Shenoy Acked-by: Balbir Singh Signed-off-by: Rafael J. Wysocki Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/cpufreq/powernv-cpufreq.c | 37 +++++++++++++++++++------------ 1 file changed, 23 insertions(+), 14 deletions(-) diff --git a/drivers/cpufreq/powernv-cpufreq.c b/drivers/cpufreq/powernv-cpufreq.c index 7e1e5bbcf430..6b3a63545619 100644 --- a/drivers/cpufreq/powernv-cpufreq.c +++ b/drivers/cpufreq/powernv-cpufreq.c @@ -41,11 +41,9 @@ #define POWERNV_MAX_PSTATES 256 #define PMSR_PSAFE_ENABLE (1UL << 30) #define PMSR_SPR_EM_DISABLE (1UL << 31) -#define PMSR_MAX(x) ((x >> 32) & 0xFF) +#define MAX_PSTATE_SHIFT 32 #define LPSTATE_SHIFT 48 #define GPSTATE_SHIFT 56 -#define GET_LPSTATE(x) (((x) >> LPSTATE_SHIFT) & 0xFF) -#define GET_GPSTATE(x) (((x) >> GPSTATE_SHIFT) & 0xFF) #define MAX_RAMP_DOWN_TIME 5120 /* @@ -93,6 +91,7 @@ struct global_pstate_info { }; static struct cpufreq_frequency_table powernv_freqs[POWERNV_MAX_PSTATES+1]; +u32 pstate_sign_prefix; static bool rebooting, throttled, occ_reset; static const char * const throttle_reason[] = { @@ -147,6 +146,20 @@ static struct powernv_pstate_info { bool wof_enabled; } powernv_pstate_info; +static inline int extract_pstate(u64 pmsr_val, unsigned int shift) +{ + int ret = ((pmsr_val >> shift) & 0xFF); + + if (!ret) + return ret; + + return (pstate_sign_prefix | ret); +} + +#define extract_local_pstate(x) extract_pstate(x, LPSTATE_SHIFT) +#define extract_global_pstate(x) extract_pstate(x, GPSTATE_SHIFT) +#define extract_max_pstate(x) extract_pstate(x, MAX_PSTATE_SHIFT) + /* Use following macros for conversions between pstate_id and index */ static inline int idx_to_pstate(unsigned int i) { @@ -277,6 +290,9 @@ static int init_powernv_pstates(void) powernv_pstate_info.nr_pstates = nr_pstates; pr_debug("NR PStates %d\n", nr_pstates); + + pstate_sign_prefix = pstate_min & ~0xFF; + for (i = 0; i < nr_pstates; i++) { u32 id = be32_to_cpu(pstate_ids[i]); u32 freq = be32_to_cpu(pstate_freqs[i]); @@ -437,17 +453,10 @@ struct powernv_smp_call_data { static void powernv_read_cpu_freq(void *arg) { unsigned long pmspr_val; - s8 local_pstate_id; struct powernv_smp_call_data *freq_data = arg; pmspr_val = get_pmspr(SPRN_PMSR); - - /* - * The local pstate id corresponds bits 48..55 in the PMSR. - * Note: Watch out for the sign! - */ - local_pstate_id = (pmspr_val >> 48) & 0xFF; - freq_data->pstate_id = local_pstate_id; + freq_data->pstate_id = extract_local_pstate(pmspr_val); freq_data->freq = pstate_id_to_freq(freq_data->pstate_id); pr_debug("cpu %d pmsr %016lX pstate_id %d frequency %d kHz\n", @@ -521,7 +530,7 @@ static void powernv_cpufreq_throttle_check(void *data) chip = this_cpu_read(chip_info); /* Check for Pmax Capping */ - pmsr_pmax = (s8)PMSR_MAX(pmsr); + pmsr_pmax = extract_max_pstate(pmsr); pmsr_pmax_idx = pstate_to_idx(pmsr_pmax); if (pmsr_pmax_idx != powernv_pstate_info.max) { if (chip->throttled) @@ -644,8 +653,8 @@ void gpstate_timer_handler(unsigned long data) * value. Hence, read from PMCR to get correct data. */ val = get_pmspr(SPRN_PMCR); - freq_data.gpstate_id = (s8)GET_GPSTATE(val); - freq_data.pstate_id = (s8)GET_LPSTATE(val); + freq_data.gpstate_id = extract_global_pstate(val); + freq_data.pstate_id = extract_local_pstate(val); if (freq_data.gpstate_id == freq_data.pstate_id) { reset_gpstates(policy); spin_unlock(&gpstates->gpstate_lock); -- GitLab From cf4c906936513fd62861fbfffb55e6d136491601 Mon Sep 17 00:00:00 2001 From: Mike Marciniszyn Date: Mon, 18 Dec 2017 19:57:06 -0800 Subject: [PATCH 0217/1635] IB/rdmavt: Allocate CQ memory on the correct node [ Upstream commit db9a2c6f9b6196b889b98e961cb9a37617b11ccf ] CQ allocation does not ensure that completion queue entries and the completion queue structure are allocated on the correct numa node. Fix by allocating the rvt_cq and kernel CQ entries on the device node, leaving the user CQ entries on the default local node. Also ensure CQ resizes use the correct allocator when extending a CQ. Reviewed-by: Sebastian Sanchez Signed-off-by: Mike Marciniszyn Signed-off-by: Dennis Dalessandro Signed-off-by: Doug Ledford Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/infiniband/sw/rdmavt/cq.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/drivers/infiniband/sw/rdmavt/cq.c b/drivers/infiniband/sw/rdmavt/cq.c index 97d71e49c092..88fa4d44ab5f 100644 --- a/drivers/infiniband/sw/rdmavt/cq.c +++ b/drivers/infiniband/sw/rdmavt/cq.c @@ -198,7 +198,7 @@ struct ib_cq *rvt_create_cq(struct ib_device *ibdev, return ERR_PTR(-EINVAL); /* Allocate the completion queue structure. */ - cq = kzalloc(sizeof(*cq), GFP_KERNEL); + cq = kzalloc_node(sizeof(*cq), GFP_KERNEL, rdi->dparms.node); if (!cq) return ERR_PTR(-ENOMEM); @@ -214,7 +214,9 @@ struct ib_cq *rvt_create_cq(struct ib_device *ibdev, sz += sizeof(struct ib_uverbs_wc) * (entries + 1); else sz += sizeof(struct ib_wc) * (entries + 1); - wc = vmalloc_user(sz); + wc = udata ? + vmalloc_user(sz) : + vzalloc_node(sz, rdi->dparms.node); if (!wc) { ret = ERR_PTR(-ENOMEM); goto bail_cq; @@ -369,7 +371,9 @@ int rvt_resize_cq(struct ib_cq *ibcq, int cqe, struct ib_udata *udata) sz += sizeof(struct ib_uverbs_wc) * (cqe + 1); else sz += sizeof(struct ib_wc) * (cqe + 1); - wc = vmalloc_user(sz); + wc = udata ? + vmalloc_user(sz) : + vzalloc_node(sz, rdi->dparms.node); if (!wc) return -ENOMEM; -- GitLab From eaa077800ff61d494a8ff8700fd3f5fc61abb2fd Mon Sep 17 00:00:00 2001 From: Ming Lei Date: Sat, 6 Jan 2018 16:27:39 +0800 Subject: [PATCH 0218/1635] blk-mq: avoid to map CPU into stale hw queue [ Upstream commit 7d4901a90d02500c8011472a060f9b2e60e6e605 ] blk_mq_pci_map_queues() may not map one CPU into any hw queue, but its previous map isn't cleared yet, and may point to one stale hw queue index. This patch fixes the following issue by clearing the mapping table before setting it up in blk_mq_pci_map_queues(). This patches fixes this following issue reported by Zhang Yi: [ 101.202734] BUG: unable to handle kernel NULL pointer dereference at 0000000094d3013f [ 101.211487] IP: blk_mq_map_swqueue+0xbc/0x200 [ 101.216346] PGD 0 P4D 0 [ 101.219171] Oops: 0000 [#1] SMP [ 101.222674] Modules linked in: sunrpc ipmi_ssif vfat fat intel_rapl sb_edac x86_pkg_temp_thermal intel_powerclamp coretemp kvm_intel kvm irqbypass crct10dif_pclmul crc32_pclmul ghash_clmulni_intel intel_cstate intel_uncore mxm_wmi intel_rapl_perf iTCO_wdt ipmi_si ipmi_devintf pcspkr iTCO_vendor_support sg dcdbas ipmi_msghandler wmi mei_me lpc_ich shpchp mei acpi_power_meter dm_multipath ip_tables xfs libcrc32c sd_mod mgag200 i2c_algo_bit drm_kms_helper syscopyarea sysfillrect sysimgblt fb_sys_fops ttm drm ahci libahci crc32c_intel libata tg3 nvme nvme_core megaraid_sas ptp i2c_core pps_core dm_mirror dm_region_hash dm_log dm_mod [ 101.284881] CPU: 0 PID: 504 Comm: kworker/u25:5 Not tainted 4.15.0-rc2 #1 [ 101.292455] Hardware name: Dell Inc. PowerEdge R730xd/072T6D, BIOS 2.5.5 08/16/2017 [ 101.301001] Workqueue: nvme-wq nvme_reset_work [nvme] [ 101.306636] task: 00000000f2c53190 task.stack: 000000002da874f9 [ 101.313241] RIP: 0010:blk_mq_map_swqueue+0xbc/0x200 [ 101.318681] RSP: 0018:ffffc9000234fd70 EFLAGS: 00010282 [ 101.324511] RAX: ffff88047ffc9480 RBX: ffff88047e130850 RCX: 0000000000000000 [ 101.332471] RDX: ffffe8ffffd40580 RSI: ffff88047e509b40 RDI: ffff88046f37a008 [ 101.340432] RBP: 000000000000000b R08: ffff88046f37a008 R09: 0000000011f94280 [ 101.348392] R10: ffff88047ffd4d00 R11: 0000000000000000 R12: ffff88046f37a008 [ 101.356353] R13: ffff88047e130f38 R14: 000000000000000b R15: ffff88046f37a558 [ 101.364314] FS: 0000000000000000(0000) GS:ffff880277c00000(0000) knlGS:0000000000000000 [ 101.373342] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 101.379753] CR2: 0000000000000098 CR3: 000000047f409004 CR4: 00000000001606f0 [ 101.387714] Call Trace: [ 101.390445] blk_mq_update_nr_hw_queues+0xbf/0x130 [ 101.395791] nvme_reset_work+0x6f4/0xc06 [nvme] [ 101.400848] ? pick_next_task_fair+0x290/0x5f0 [ 101.405807] ? __switch_to+0x1f5/0x430 [ 101.409988] ? put_prev_entity+0x2f/0xd0 [ 101.414365] process_one_work+0x141/0x340 [ 101.418836] worker_thread+0x47/0x3e0 [ 101.422921] kthread+0xf5/0x130 [ 101.426424] ? rescuer_thread+0x380/0x380 [ 101.430896] ? kthread_associate_blkcg+0x90/0x90 [ 101.436048] ret_from_fork+0x1f/0x30 [ 101.440034] Code: 48 83 3c ca 00 0f 84 2b 01 00 00 48 63 cd 48 8b 93 10 01 00 00 8b 0c 88 48 8b 83 20 01 00 00 4a 03 14 f5 60 04 af 81 48 8b 0c c8 <48> 8b 81 98 00 00 00 f0 4c 0f ab 30 8b 81 f8 00 00 00 89 42 44 [ 101.461116] RIP: blk_mq_map_swqueue+0xbc/0x200 RSP: ffffc9000234fd70 [ 101.468205] CR2: 0000000000000098 [ 101.471907] ---[ end trace 5fe710f98228a3ca ]--- [ 101.482489] Kernel panic - not syncing: Fatal exception [ 101.488505] Kernel Offset: disabled [ 101.497752] ---[ end Kernel panic - not syncing: Fatal exception Reviewed-by: Christoph Hellwig Suggested-by: Christoph Hellwig Reported-by: Yi Zhang Tested-by: Yi Zhang Signed-off-by: Ming Lei Signed-off-by: Jens Axboe Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- block/blk-mq.c | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/block/blk-mq.c b/block/blk-mq.c index f1fb126a3be5..12bb7a49c5ba 100644 --- a/block/blk-mq.c +++ b/block/blk-mq.c @@ -2528,9 +2528,27 @@ static int blk_mq_alloc_rq_maps(struct blk_mq_tag_set *set) static int blk_mq_update_queue_map(struct blk_mq_tag_set *set) { - if (set->ops->map_queues) + if (set->ops->map_queues) { + int cpu; + /* + * transport .map_queues is usually done in the following + * way: + * + * for (queue = 0; queue < set->nr_hw_queues; queue++) { + * mask = get_cpu_mask(queue) + * for_each_cpu(cpu, mask) + * set->mq_map[cpu] = queue; + * } + * + * When we need to remap, the table has to be cleared for + * killing stale mapping since one CPU may not be mapped + * to any hw queue. + */ + for_each_possible_cpu(cpu) + set->mq_map[cpu] = 0; + return set->ops->map_queues(set); - else + } else return blk_mq_map_queues(set); } -- GitLab From fb1ef85d58855818f6a1799acabff51a55adff22 Mon Sep 17 00:00:00 2001 From: Ming Lei Date: Sat, 6 Jan 2018 16:27:40 +0800 Subject: [PATCH 0219/1635] blk-mq: fix race between updating nr_hw_queues and switching io sched [ Upstream commit fb350e0ad99359768e1e80b4784692031ec340e4 ] In both elevator_switch_mq() and blk_mq_update_nr_hw_queues(), sched tags can be allocated, and q->nr_hw_queue is used, and race is inevitable, for example: blk_mq_init_sched() may trigger use-after-free on hctx, which is freed in blk_mq_realloc_hw_ctxs() when nr_hw_queues is decreased. This patch fixes the race be holding q->sysfs_lock. Reviewed-by: Christoph Hellwig Reported-by: Yi Zhang Tested-by: Yi Zhang Signed-off-by: Ming Lei Signed-off-by: Jens Axboe Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- block/blk-mq.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/block/blk-mq.c b/block/blk-mq.c index 12bb7a49c5ba..c28d6b3088a0 100644 --- a/block/blk-mq.c +++ b/block/blk-mq.c @@ -2314,6 +2314,9 @@ static void blk_mq_realloc_hw_ctxs(struct blk_mq_tag_set *set, struct blk_mq_hw_ctx **hctxs = q->queue_hw_ctx; blk_mq_sysfs_unregister(q); + + /* protect against switching io scheduler */ + mutex_lock(&q->sysfs_lock); for (i = 0; i < set->nr_hw_queues; i++) { int node; @@ -2358,6 +2361,7 @@ static void blk_mq_realloc_hw_ctxs(struct blk_mq_tag_set *set, } } q->nr_hw_queues = i; + mutex_unlock(&q->sysfs_lock); blk_mq_sysfs_register(q); } -- GitLab From dd3e1a4e769ed8175c213582b52a7dfdc6297de0 Mon Sep 17 00:00:00 2001 From: Robert Jarzmik Date: Thu, 28 Dec 2017 09:27:41 +0100 Subject: [PATCH 0220/1635] backlight: tdo24m: Fix the SPI CS between transfers [ Upstream commit 2023b0524a6310e9ea80daf085f51c71bff9289f ] Currently the LCD display (TD035S) on the cm-x300 platform is broken and remains blank. The TD0245S specification requires that the chipselect is toggled between commands sent to the panel. This was also the purpose of the former patch of commit f64dcac0b124 ("backlight: tdo24m: ensure chip select changes between transfers"). Unfortunately, the "cs_change" field of a SPI transfer is misleading. Its true meaning is that for a SPI message holding multiple transfers, the chip select is toggled between each transfer, but for the last transfer it remains asserted. In this driver, all the SPI messages contain exactly one transfer, which means that each transfer is the last of its message, and as a consequence the chip select is never toggled. Actually, there was a second bug hidding the first one, hence the problem was not seen until v4.6. This problem was fixed by commit a52db659c79c ("spi: pxa2xx: Fix cs_change management") for PXA based boards. This fix makes the TD035S work again on a cm-x300 board. The same applies to other PXA boards, ie. corgi and tosa. Fixes: a52db659c79c ("spi: pxa2xx: Fix cs_change management") Reported-by: Andrea Adami Signed-off-by: Robert Jarzmik Acked-by: Daniel Thompson Signed-off-by: Lee Jones Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/video/backlight/corgi_lcd.c | 2 +- drivers/video/backlight/tdo24m.c | 2 +- drivers/video/backlight/tosa_lcd.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/video/backlight/corgi_lcd.c b/drivers/video/backlight/corgi_lcd.c index d7c239ea3d09..f5574060f9c8 100644 --- a/drivers/video/backlight/corgi_lcd.c +++ b/drivers/video/backlight/corgi_lcd.c @@ -177,7 +177,7 @@ static int corgi_ssp_lcdtg_send(struct corgi_lcd *lcd, int adrs, uint8_t data) struct spi_message msg; struct spi_transfer xfer = { .len = 1, - .cs_change = 1, + .cs_change = 0, .tx_buf = lcd->buf, }; diff --git a/drivers/video/backlight/tdo24m.c b/drivers/video/backlight/tdo24m.c index eab1f842f9c0..e4bd63e9db6b 100644 --- a/drivers/video/backlight/tdo24m.c +++ b/drivers/video/backlight/tdo24m.c @@ -369,7 +369,7 @@ static int tdo24m_probe(struct spi_device *spi) spi_message_init(m); - x->cs_change = 1; + x->cs_change = 0; x->tx_buf = &lcd->buf[0]; spi_message_add_tail(x, m); diff --git a/drivers/video/backlight/tosa_lcd.c b/drivers/video/backlight/tosa_lcd.c index 6a41ea92737a..4dc5ee8debeb 100644 --- a/drivers/video/backlight/tosa_lcd.c +++ b/drivers/video/backlight/tosa_lcd.c @@ -49,7 +49,7 @@ static int tosa_tg_send(struct spi_device *spi, int adrs, uint8_t data) struct spi_message msg; struct spi_transfer xfer = { .len = 1, - .cs_change = 1, + .cs_change = 0, .tx_buf = buf, }; -- GitLab From 5391891c0a469e5cca7f779a86cd8b01c70ac91f Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Mon, 1 Jan 2018 13:23:57 +0100 Subject: [PATCH 0221/1635] pinctrl: baytrail: Enable glitch filter for GPIOs used as interrupts [ Upstream commit 9291c65b01d1c67ebd56644cb19317ad665c44b3 ] On some systems, some PCB traces attached to GpioInts are routed in such a way that they pick up enough interference to constantly (many times per second) trigger. Enabling glitch-filtering fixes this. Signed-off-by: Hans de Goede Acked-by: Mika Westerberg Signed-off-by: Linus Walleij Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/pinctrl/intel/pinctrl-baytrail.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/pinctrl/intel/pinctrl-baytrail.c b/drivers/pinctrl/intel/pinctrl-baytrail.c index 0f3a02495aeb..beeb7cbb5015 100644 --- a/drivers/pinctrl/intel/pinctrl-baytrail.c +++ b/drivers/pinctrl/intel/pinctrl-baytrail.c @@ -46,6 +46,9 @@ #define BYT_TRIG_POS BIT(25) #define BYT_TRIG_LVL BIT(24) #define BYT_DEBOUNCE_EN BIT(20) +#define BYT_GLITCH_FILTER_EN BIT(19) +#define BYT_GLITCH_F_SLOW_CLK BIT(17) +#define BYT_GLITCH_F_FAST_CLK BIT(16) #define BYT_PULL_STR_SHIFT 9 #define BYT_PULL_STR_MASK (3 << BYT_PULL_STR_SHIFT) #define BYT_PULL_STR_2K (0 << BYT_PULL_STR_SHIFT) @@ -1579,6 +1582,9 @@ static int byt_irq_type(struct irq_data *d, unsigned int type) */ value &= ~(BYT_DIRECT_IRQ_EN | BYT_TRIG_POS | BYT_TRIG_NEG | BYT_TRIG_LVL); + /* Enable glitch filtering */ + value |= BYT_GLITCH_FILTER_EN | BYT_GLITCH_F_SLOW_CLK | + BYT_GLITCH_F_FAST_CLK; writel(value, reg); -- GitLab From 39ede1fd200f0f43bc87e12bf6cced45de610232 Mon Sep 17 00:00:00 2001 From: James Smart Date: Wed, 29 Nov 2017 16:47:31 -0800 Subject: [PATCH 0222/1635] nvme_fcloop: disassocate local port structs [ Upstream commit 6fda20283e55b9d288cd56822ce39fc8e64f2208 ] The current fcloop driver gets its lport structure from the private area co-allocated with the fc_localport. All is fine except the teardown path, which wants to wait on the completion, which is marked complete by the delete_localport callback performed after unregister_localport. The issue is, the nvme_fc transport frees the localport structure immediately after delete_localport is called, meaning the original routine is trying to wait on a complete that was just freed. Change such that a lport struct is allocated coincident with the addition and registration of a localport. The private area of the localport now contains just a backpointer to the real lport struct. Now, the completion can be waited for, and after completing, the new structure can be kfree'd. Signed-off-by: James Smart Signed-off-by: Christoph Hellwig Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/nvme/target/fcloop.c | 35 +++++++++++++++++++++++++---------- 1 file changed, 25 insertions(+), 10 deletions(-) diff --git a/drivers/nvme/target/fcloop.c b/drivers/nvme/target/fcloop.c index 7b75d9de55ab..5b51653ba9fe 100644 --- a/drivers/nvme/target/fcloop.c +++ b/drivers/nvme/target/fcloop.c @@ -204,6 +204,10 @@ struct fcloop_lport { struct completion unreg_done; }; +struct fcloop_lport_priv { + struct fcloop_lport *lport; +}; + struct fcloop_rport { struct nvme_fc_remote_port *remoteport; struct nvmet_fc_target_port *targetport; @@ -657,7 +661,8 @@ fcloop_nport_get(struct fcloop_nport *nport) static void fcloop_localport_delete(struct nvme_fc_local_port *localport) { - struct fcloop_lport *lport = localport->private; + struct fcloop_lport_priv *lport_priv = localport->private; + struct fcloop_lport *lport = lport_priv->lport; /* release any threads waiting for the unreg to complete */ complete(&lport->unreg_done); @@ -697,7 +702,7 @@ static struct nvme_fc_port_template fctemplate = { .max_dif_sgl_segments = FCLOOP_SGL_SEGS, .dma_boundary = FCLOOP_DMABOUND_4G, /* sizes of additional private data for data structures */ - .local_priv_sz = sizeof(struct fcloop_lport), + .local_priv_sz = sizeof(struct fcloop_lport_priv), .remote_priv_sz = sizeof(struct fcloop_rport), .lsrqst_priv_sz = sizeof(struct fcloop_lsreq), .fcprqst_priv_sz = sizeof(struct fcloop_ini_fcpreq), @@ -728,11 +733,17 @@ fcloop_create_local_port(struct device *dev, struct device_attribute *attr, struct fcloop_ctrl_options *opts; struct nvme_fc_local_port *localport; struct fcloop_lport *lport; - int ret; + struct fcloop_lport_priv *lport_priv; + unsigned long flags; + int ret = -ENOMEM; + + lport = kzalloc(sizeof(*lport), GFP_KERNEL); + if (!lport) + return -ENOMEM; opts = kzalloc(sizeof(*opts), GFP_KERNEL); if (!opts) - return -ENOMEM; + goto out_free_lport; ret = fcloop_parse_options(opts, buf); if (ret) @@ -752,23 +763,25 @@ fcloop_create_local_port(struct device *dev, struct device_attribute *attr, ret = nvme_fc_register_localport(&pinfo, &fctemplate, NULL, &localport); if (!ret) { - unsigned long flags; - /* success */ - lport = localport->private; + lport_priv = localport->private; + lport_priv->lport = lport; + lport->localport = localport; INIT_LIST_HEAD(&lport->lport_list); spin_lock_irqsave(&fcloop_lock, flags); list_add_tail(&lport->lport_list, &fcloop_lports); spin_unlock_irqrestore(&fcloop_lock, flags); - - /* mark all of the input buffer consumed */ - ret = count; } out_free_opts: kfree(opts); +out_free_lport: + /* free only if we're going to fail */ + if (ret) + kfree(lport); + return ret ? ret : count; } @@ -790,6 +803,8 @@ __wait_localport_unreg(struct fcloop_lport *lport) wait_for_completion(&lport->unreg_done); + kfree(lport); + return ret; } -- GitLab From f0504bf54b4dd068e6a8c4c3b3de4a50a4f7da79 Mon Sep 17 00:00:00 2001 From: James Smart Date: Wed, 29 Nov 2017 16:47:30 -0800 Subject: [PATCH 0223/1635] nvme_fcloop: fix abort race condition [ Upstream commit 278e096063f1914fccfc77a617be9fc8dbb31b0e ] A test case revealed a race condition of an i/o completing on a thread parallel to the delete_association generating the aborts for the outstanding ios on the controller. The i/o completion was freeing the target fcloop context, thus the abort task referenced the just-freed memory. Correct by clearing the target/initiator cross pointers in the io completion and abort tasks before calling the callbacks. On aborts that detect already finished io's, ensure the complete context is called. Signed-off-by: James Smart Signed-off-by: Christoph Hellwig Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/nvme/target/fcloop.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/nvme/target/fcloop.c b/drivers/nvme/target/fcloop.c index 5b51653ba9fe..c0080f6ab2f5 100644 --- a/drivers/nvme/target/fcloop.c +++ b/drivers/nvme/target/fcloop.c @@ -374,6 +374,7 @@ fcloop_tgt_fcprqst_done_work(struct work_struct *work) spin_lock(&tfcp_req->reqlock); fcpreq = tfcp_req->fcpreq; + tfcp_req->fcpreq = NULL; spin_unlock(&tfcp_req->reqlock); if (tport->remoteport && fcpreq) { @@ -615,11 +616,7 @@ fcloop_fcp_abort(struct nvme_fc_local_port *localport, if (!tfcp_req) /* abort has already been called */ - return; - - if (rport->targetport) - nvmet_fc_rcv_fcp_abort(rport->targetport, - &tfcp_req->tgt_fcp_req); + goto finish; /* break initiator/target relationship for io */ spin_lock(&tfcp_req->reqlock); @@ -627,6 +624,11 @@ fcloop_fcp_abort(struct nvme_fc_local_port *localport, tfcp_req->fcpreq = NULL; spin_unlock(&tfcp_req->reqlock); + if (rport->targetport) + nvmet_fc_rcv_fcp_abort(rport->targetport, + &tfcp_req->tgt_fcp_req); + +finish: /* post the aborted io completion */ fcpreq->status = -ECANCELED; schedule_work(&inireq->iniwork); -- GitLab From 3b3fb4be7ca15ea8d71844b158ae4430d7aa110f Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Thu, 30 Nov 2017 08:39:07 +0100 Subject: [PATCH 0224/1635] tpm: return a TPM_RC_COMMAND_CODE response if command is not implemented [ Upstream commit 095531f891e627e408606f2da4008d3d53e6748a ] According to the TPM Library Specification, a TPM device must do a command header validation before processing and return a TPM_RC_COMMAND_CODE code if the command is not implemented. So user-space will expect to handle that response as an error. But if the in-kernel resource manager is used (/dev/tpmrm?), an -EINVAL errno code is returned instead if the command isn't implemented. This confuses userspace since it doesn't expect that error value. This also isn't consistent with the behavior when not using TPM spaces and accessing the TPM directly (/dev/tpm?). In this case, the command is sent to the TPM even when not implemented and the TPM responds with an error. Instead of returning an -EINVAL errno code when the tpm_validate_command() function fails, synthesize a TPM command response so user-space can get a TPM_RC_COMMAND_CODE as expected when a chip doesn't implement the command. The TPM only sets 12 of the 32 bits in the TPM_RC response, so the TSS and TAB specifications define that higher layers in the stack should use some of the unused 20 bits to specify from which level of the stack the error is coming from. Since the TPM_RC_COMMAND_CODE response code is sent by the kernel resource manager, set the error level to the TAB/RM layer so user-space is aware of this. Suggested-by: Jason Gunthorpe Signed-off-by: Javier Martinez Canillas Reviewed-by: William Roberts Reviewed-by: Philip Tricca Reviewed-by: Jarkko Sakkinen Tested-by: Jarkko Sakkinen Signed-off-by: Jarkko Sakkinen Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/char/tpm/tpm-interface.c | 28 ++++++++++++++++++++-------- drivers/char/tpm/tpm.h | 5 +++++ 2 files changed, 25 insertions(+), 8 deletions(-) diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c index 5294442505cb..0f1dc35e7078 100644 --- a/drivers/char/tpm/tpm-interface.c +++ b/drivers/char/tpm/tpm-interface.c @@ -328,7 +328,7 @@ unsigned long tpm_calc_ordinal_duration(struct tpm_chip *chip, } EXPORT_SYMBOL_GPL(tpm_calc_ordinal_duration); -static bool tpm_validate_command(struct tpm_chip *chip, +static int tpm_validate_command(struct tpm_chip *chip, struct tpm_space *space, const u8 *cmd, size_t len) @@ -340,10 +340,10 @@ static bool tpm_validate_command(struct tpm_chip *chip, unsigned int nr_handles; if (len < TPM_HEADER_SIZE) - return false; + return -EINVAL; if (!space) - return true; + return 0; if (chip->flags & TPM_CHIP_FLAG_TPM2 && chip->nr_commands) { cc = be32_to_cpu(header->ordinal); @@ -352,7 +352,7 @@ static bool tpm_validate_command(struct tpm_chip *chip, if (i < 0) { dev_dbg(&chip->dev, "0x%04X is an invalid command\n", cc); - return false; + return -EOPNOTSUPP; } attrs = chip->cc_attrs_tbl[i]; @@ -362,11 +362,11 @@ static bool tpm_validate_command(struct tpm_chip *chip, goto err_len; } - return true; + return 0; err_len: dev_dbg(&chip->dev, "%s: insufficient command length %zu", __func__, len); - return false; + return -EINVAL; } /** @@ -391,8 +391,20 @@ ssize_t tpm_transmit(struct tpm_chip *chip, struct tpm_space *space, unsigned long stop; bool need_locality; - if (!tpm_validate_command(chip, space, buf, bufsiz)) - return -EINVAL; + rc = tpm_validate_command(chip, space, buf, bufsiz); + if (rc == -EINVAL) + return rc; + /* + * If the command is not implemented by the TPM, synthesize a + * response with a TPM2_RC_COMMAND_CODE return for user-space. + */ + if (rc == -EOPNOTSUPP) { + header->length = cpu_to_be32(sizeof(*header)); + header->tag = cpu_to_be16(TPM2_ST_NO_SESSIONS); + header->return_code = cpu_to_be32(TPM2_RC_COMMAND_CODE | + TSS2_RESMGR_TPM_RC_LAYER); + return bufsiz; + } if (bufsiz > TPM_BUFSIZE) bufsiz = TPM_BUFSIZE; diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h index 2d5466a72e40..0b5b499f726a 100644 --- a/drivers/char/tpm/tpm.h +++ b/drivers/char/tpm/tpm.h @@ -93,12 +93,17 @@ enum tpm2_structures { TPM2_ST_SESSIONS = 0x8002, }; +/* Indicates from what layer of the software stack the error comes from */ +#define TSS2_RC_LAYER_SHIFT 16 +#define TSS2_RESMGR_TPM_RC_LAYER (11 << TSS2_RC_LAYER_SHIFT) + enum tpm2_return_codes { TPM2_RC_SUCCESS = 0x0000, TPM2_RC_HASH = 0x0083, /* RC_FMT1 */ TPM2_RC_HANDLE = 0x008B, TPM2_RC_INITIALIZE = 0x0100, /* RC_VER1 */ TPM2_RC_DISABLED = 0x0120, + TPM2_RC_COMMAND_CODE = 0x0143, TPM2_RC_TESTING = 0x090A, /* RC_WARN */ TPM2_RC_REFERENCE_H0 = 0x0910, }; -- GitLab From 01ff15fcf4662dce618497778692ad29dd712b45 Mon Sep 17 00:00:00 2001 From: Jin Yao Date: Tue, 26 Dec 2017 18:42:43 +0800 Subject: [PATCH 0225/1635] perf report: Fix a no annotate browser displayed issue [ Upstream commit 40c39e3046411f84bab82f66783ff3593e2bcd9b ] When enabling '-b' option in perf record, for example, perf record -b ... perf report and then browsing the annotate browser from perf report (press 'A'), it would fail (annotate browser can't be displayed). It's because the '.add_entry_cb' op of struct report is overwritten by hist_iter__branch_callback() in builtin-report.c. But this function doesn't do something like mapping symbols and sources. So next, do_annotate() will return directly. notes = symbol__annotation(act->ms.sym); if (!notes->src) return 0; This patch adds the lost code to hist_iter__branch_callback (refer to hist_iter__report_callback). v2: Fix a crash bug when perform 'perf report --stdio'. The reason is that we init the symbol annotation only in browser mode, it doesn't allocate/init resources for stdio mode. So now in hist_iter__branch_callback(), it will return directly if it's not in browser mode. Signed-off-by: Jin Yao Tested-by: Arnaldo Carvalho de Melo Cc: Alexander Shishkin Cc: Andi Kleen Cc: Jiri Olsa Cc: Kan Liang Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1514284963-18587-1-git-send-email-yao.jin@linux.intel.com Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- tools/perf/builtin-report.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index fae4b0340750..183c3ed56e08 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -162,12 +162,28 @@ static int hist_iter__branch_callback(struct hist_entry_iter *iter, struct hist_entry *he = iter->he; struct report *rep = arg; struct branch_info *bi; + struct perf_sample *sample = iter->sample; + struct perf_evsel *evsel = iter->evsel; + int err; + + if (!ui__has_annotation()) + return 0; + + hist__account_cycles(sample->branch_stack, al, sample, + rep->nonany_branch_mode); bi = he->branch_info; + err = addr_map_symbol__inc_samples(&bi->from, sample, evsel->idx); + if (err) + goto out; + + err = addr_map_symbol__inc_samples(&bi->to, sample, evsel->idx); + branch_type_count(&rep->brtype_stat, &bi->flags, bi->from.addr, bi->to.addr); - return 0; +out: + return err; } static int process_sample_event(struct perf_tool *tool, -- GitLab From 89deb4ad015ba32da4d084347752220b23aaee06 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Tue, 19 Dec 2017 10:01:47 +1100 Subject: [PATCH 0226/1635] staging: lustre: disable preempt while sampling processor id. [ Upstream commit dbeccabf5294e80f7cc9ee566746c42211bed736 ] Calling smp_processor_id() without disabling preemption triggers a warning (if CONFIG_DEBUG_PREEMPT). I think the result of cfs_cpt_current() is only used as a hint for load balancing, rather than as a precise and stable indicator of the current CPU. So it doesn't need to be called with preemption disabled. So disable preemption inside cfs_cpt_current() to silence the warning. Signed-off-by: NeilBrown Reviewed-by: Andreas Dilger Signed-off-by: Greg Kroah-Hartman Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- .../staging/lustre/lnet/libcfs/linux/linux-cpu.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/drivers/staging/lustre/lnet/libcfs/linux/linux-cpu.c b/drivers/staging/lustre/lnet/libcfs/linux/linux-cpu.c index 2da051c0d251..a4bb93b440a5 100644 --- a/drivers/staging/lustre/lnet/libcfs/linux/linux-cpu.c +++ b/drivers/staging/lustre/lnet/libcfs/linux/linux-cpu.c @@ -528,19 +528,20 @@ EXPORT_SYMBOL(cfs_cpt_spread_node); int cfs_cpt_current(struct cfs_cpt_table *cptab, int remap) { - int cpu = smp_processor_id(); - int cpt = cptab->ctb_cpu2cpt[cpu]; + int cpu; + int cpt; - if (cpt < 0) { - if (!remap) - return cpt; + preempt_disable(); + cpu = smp_processor_id(); + cpt = cptab->ctb_cpu2cpt[cpu]; + if (cpt < 0 && remap) { /* don't return negative value for safety of upper layer, * instead we shadow the unknown cpu to a valid partition ID */ cpt = cpu % cptab->ctb_nparts; } - + preempt_enable(); return cpt; } EXPORT_SYMBOL(cfs_cpt_current); -- GitLab From 87b9099cf14109b5369ba2fa5435e190efea793c Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Sat, 6 Jan 2018 21:18:24 +0100 Subject: [PATCH 0227/1635] ASoC: Intel: sst: Fix the return value of 'sst_send_byte_stream_mrfld()' [ Upstream commit eaadb1caa966a91128297b754e90b7c92b350a00 ] In some error handling paths, an error code is assiegned to 'ret'. However, the function always return 0. Fix it and return the error code if such an error paths is taken. Fixes: 3d9ff34622ba ("ASoC: Intel: sst: add stream operations") Signed-off-by: Christophe JAILLET Signed-off-by: Mark Brown Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- sound/soc/intel/atom/sst/sst_stream.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/intel/atom/sst/sst_stream.c b/sound/soc/intel/atom/sst/sst_stream.c index 83d8dda15233..4eeb9afdc89f 100644 --- a/sound/soc/intel/atom/sst/sst_stream.c +++ b/sound/soc/intel/atom/sst/sst_stream.c @@ -221,7 +221,7 @@ int sst_send_byte_stream_mrfld(struct intel_sst_drv *sst_drv_ctx, sst_free_block(sst_drv_ctx, block); out: test_and_clear_bit(pvt_id, &sst_drv_ctx->pvt_id); - return 0; + return ret; } /* -- GitLab From 1530dcc90331bfc96a46bb75275775531e8dba54 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Tue, 26 Dec 2017 13:59:09 +0100 Subject: [PATCH 0228/1635] power: supply: axp288_charger: Properly stop work on probe-error / remove [ Upstream commit 165c2357744e41391902a2a72dd170beb60c28d5 ] Properly stop any work we may have queued on probe-errors / remove. Rather then adding a remove driver callback for this, and goto style error handling to probe, use a devm_action for this. The devm_action gets registered before we register any of the extcon notifiers which may queue the work, devm does cleanup in reverse order, so this ensures that the notifiers are removed before we cancel the work. Reviewed-by: Chen-Yu Tsai Signed-off-by: Hans de Goede Signed-off-by: Sebastian Reichel Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/power/supply/axp288_charger.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/drivers/power/supply/axp288_charger.c b/drivers/power/supply/axp288_charger.c index d51ebd1da65e..9dc7590e07cb 100644 --- a/drivers/power/supply/axp288_charger.c +++ b/drivers/power/supply/axp288_charger.c @@ -785,6 +785,14 @@ static int charger_init_hw_regs(struct axp288_chrg_info *info) return 0; } +static void axp288_charger_cancel_work(void *data) +{ + struct axp288_chrg_info *info = data; + + cancel_work_sync(&info->otg.work); + cancel_work_sync(&info->cable.work); +} + static int axp288_charger_probe(struct platform_device *pdev) { int ret, i, pirq; @@ -836,6 +844,11 @@ static int axp288_charger_probe(struct platform_device *pdev) return ret; } + /* Cancel our work on cleanup, register this before the notifiers */ + ret = devm_add_action(dev, axp288_charger_cancel_work, info); + if (ret) + return ret; + /* Register for extcon notification */ INIT_WORK(&info->cable.work, axp288_charger_extcon_evt_worker); info->cable.nb[0].notifier_call = axp288_charger_handle_cable0_evt; -- GitLab From f722a6a611790bb14516e8bbe62953ec04e1a6b5 Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Tue, 19 Dec 2017 12:33:56 +0100 Subject: [PATCH 0229/1635] rt2x00: do not pause queue unconditionally on error path [ Upstream commit 6dd80efd75ce7c2dbd9f117cf585ee2b33a42ee1 ] Pausing queue without checking threshold is racy with txdone path. Moreover we do not need pause queue on any error, but only if queue is full - in case when we send RTS frame ( other cases of almost full queue are already handled in rt2x00queue_write_tx_frame() ). Patch fixes of theoretically possible problem of pausing empty queue. Signed-off-by: Stanislaw Gruszka Tested-by: Enrico Mioso Signed-off-by: Kalle Valo Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- .../net/wireless/ralink/rt2x00/rt2x00mac.c | 22 ++++++++++++------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00mac.c b/drivers/net/wireless/ralink/rt2x00/rt2x00mac.c index ecc96312a370..6fe0c6abe0d6 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2x00mac.c @@ -142,15 +142,25 @@ void rt2x00mac_tx(struct ieee80211_hw *hw, if (!rt2x00dev->ops->hw->set_rts_threshold && (tx_info->control.rates[0].flags & (IEEE80211_TX_RC_USE_RTS_CTS | IEEE80211_TX_RC_USE_CTS_PROTECT))) { - if (rt2x00queue_available(queue) <= 1) - goto exit_fail; + if (rt2x00queue_available(queue) <= 1) { + /* + * Recheck for full queue under lock to avoid race + * conditions with rt2x00lib_txdone(). + */ + spin_lock(&queue->tx_lock); + if (rt2x00queue_threshold(queue)) + rt2x00queue_pause_queue(queue); + spin_unlock(&queue->tx_lock); + + goto exit_free_skb; + } if (rt2x00mac_tx_rts_cts(rt2x00dev, queue, skb)) - goto exit_fail; + goto exit_free_skb; } if (unlikely(rt2x00queue_write_tx_frame(queue, skb, control->sta, false))) - goto exit_fail; + goto exit_free_skb; /* * Pausing queue has to be serialized with rt2x00lib_txdone(). Note @@ -164,10 +174,6 @@ void rt2x00mac_tx(struct ieee80211_hw *hw, return; - exit_fail: - spin_lock(&queue->tx_lock); - rt2x00queue_pause_queue(queue); - spin_unlock(&queue->tx_lock); exit_free_skb: ieee80211_free_txskb(hw, skb); } -- GitLab From 46d19334ca40d73a57d0519b5d9b5762d7e7c491 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Tue, 26 Dec 2017 17:33:18 +0000 Subject: [PATCH 0230/1635] wl1251: check return from call to wl1251_acx_arp_ip_filter [ Upstream commit ac1181c60822292176ab96912208ec9f9819faf8 ] Currently the less than zero error check on ret is incorrect as it is checking a far earlier ret assignment rather than the return from the call to wl1251_acx_arp_ip_filter. Fix this by adding in the missing assginment. Detected by CoverityScan, CID#1164835 ("Logically dead code") Fixes: 204cc5c44fb6 ("wl1251: implement hardware ARP filtering") Signed-off-by: Colin Ian King Signed-off-by: Kalle Valo Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/ti/wl1251/main.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/net/wireless/ti/wl1251/main.c b/drivers/net/wireless/ti/wl1251/main.c index 6d02c660b4ab..037defd10b91 100644 --- a/drivers/net/wireless/ti/wl1251/main.c +++ b/drivers/net/wireless/ti/wl1251/main.c @@ -1200,8 +1200,7 @@ static void wl1251_op_bss_info_changed(struct ieee80211_hw *hw, WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS); enable = bss_conf->arp_addr_cnt == 1 && bss_conf->assoc; - wl1251_acx_arp_ip_filter(wl, enable, addr); - + ret = wl1251_acx_arp_ip_filter(wl, enable, addr); if (ret < 0) goto out_sleep; } -- GitLab From 35a9ebd920aaaa6425436b6660e71ca831531da1 Mon Sep 17 00:00:00 2001 From: Daniel Jurgens Date: Thu, 4 Jan 2018 17:25:31 +0200 Subject: [PATCH 0231/1635] net/mlx5: Fix race for multiple RoCE enable [ Upstream commit 734dc065fc41f6143ff88225aa5d335cb1e0f6aa ] There are two potential problems with the existing implementation. 1. Enable and disable can race after the atomic operations. 2. If a command fails the refcount is left in an inconsistent state. Introduce a lock and perform error checking. Fixes: a6f7d2aff623 ("net/mlx5: Add support for multiple RoCE enable") Signed-off-by: Daniel Jurgens Reviewed-by: Parav Pandit Signed-off-by: Leon Romanovsky Signed-off-by: Jason Gunthorpe Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- .../net/ethernet/mellanox/mlx5/core/vport.c | 33 +++++++++++++++---- include/linux/mlx5/driver.h | 2 +- 2 files changed, 28 insertions(+), 7 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/vport.c b/drivers/net/ethernet/mellanox/mlx5/core/vport.c index a1296a62497d..71153c0f1605 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/vport.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/vport.c @@ -36,6 +36,9 @@ #include #include "mlx5_core.h" +/* Mutex to hold while enabling or disabling RoCE */ +static DEFINE_MUTEX(mlx5_roce_en_lock); + static int _mlx5_query_vport_state(struct mlx5_core_dev *mdev, u8 opmod, u16 vport, u32 *out, int outlen) { @@ -998,17 +1001,35 @@ static int mlx5_nic_vport_update_roce_state(struct mlx5_core_dev *mdev, int mlx5_nic_vport_enable_roce(struct mlx5_core_dev *mdev) { - if (atomic_inc_return(&mdev->roce.roce_en) != 1) - return 0; - return mlx5_nic_vport_update_roce_state(mdev, MLX5_VPORT_ROCE_ENABLED); + int err = 0; + + mutex_lock(&mlx5_roce_en_lock); + if (!mdev->roce.roce_en) + err = mlx5_nic_vport_update_roce_state(mdev, MLX5_VPORT_ROCE_ENABLED); + + if (!err) + mdev->roce.roce_en++; + mutex_unlock(&mlx5_roce_en_lock); + + return err; } EXPORT_SYMBOL_GPL(mlx5_nic_vport_enable_roce); int mlx5_nic_vport_disable_roce(struct mlx5_core_dev *mdev) { - if (atomic_dec_return(&mdev->roce.roce_en) != 0) - return 0; - return mlx5_nic_vport_update_roce_state(mdev, MLX5_VPORT_ROCE_DISABLED); + int err = 0; + + mutex_lock(&mlx5_roce_en_lock); + if (mdev->roce.roce_en) { + mdev->roce.roce_en--; + if (mdev->roce.roce_en == 0) + err = mlx5_nic_vport_update_roce_state(mdev, MLX5_VPORT_ROCE_DISABLED); + + if (err) + mdev->roce.roce_en++; + } + mutex_unlock(&mlx5_roce_en_lock); + return err; } EXPORT_SYMBOL_GPL(mlx5_nic_vport_disable_roce); diff --git a/include/linux/mlx5/driver.h b/include/linux/mlx5/driver.h index bfb4a9d962a5..f2f9e957bf1b 100644 --- a/include/linux/mlx5/driver.h +++ b/include/linux/mlx5/driver.h @@ -794,7 +794,7 @@ struct mlx5_core_dev { struct mlx5e_resources mlx5e_res; struct { struct mlx5_rsvd_gids reserved_gids; - atomic_t roce_en; + u32 roce_en; } roce; #ifdef CONFIG_MLX5_FPGA struct mlx5_fpga_device *fpga; -- GitLab From 5669ec0b9588d00f35ac02149fe871b10dcfa9fc Mon Sep 17 00:00:00 2001 From: Jian Shen Date: Fri, 5 Jan 2018 18:18:12 +0800 Subject: [PATCH 0232/1635] net: hns3: Fix an error of total drop packet statistics [ Upstream commit d2a5dca8404871be683c6bbc175ebf9c56dd2865 ] The dropped tx/rx packets number of each tqp should also be counted into the total drop tx/rx packets numbers. Fixes: 76ad4f0ee74 ("net: hns3: Add support of HNS3 Ethernet Driver for hip08 SoC") Signed-off-by: Jian Shen Signed-off-by: Peng Li Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- .../net/ethernet/hisilicon/hns3/hns3pf/hns3_enet.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hns3_enet.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hns3_enet.c index 3e7e13b9a385..fad480e323dd 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hns3_enet.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hns3_enet.c @@ -1060,6 +1060,8 @@ hns3_nic_get_stats64(struct net_device *netdev, struct rtnl_link_stats64 *stats) u64 rx_bytes = 0; u64 tx_pkts = 0; u64 rx_pkts = 0; + u64 tx_drop = 0; + u64 rx_drop = 0; for (idx = 0; idx < queue_num; idx++) { /* fetch the tx stats */ @@ -1068,6 +1070,8 @@ hns3_nic_get_stats64(struct net_device *netdev, struct rtnl_link_stats64 *stats) start = u64_stats_fetch_begin_irq(&ring->syncp); tx_bytes += ring->stats.tx_bytes; tx_pkts += ring->stats.tx_pkts; + tx_drop += ring->stats.tx_busy; + tx_drop += ring->stats.sw_err_cnt; } while (u64_stats_fetch_retry_irq(&ring->syncp, start)); /* fetch the rx stats */ @@ -1076,6 +1080,9 @@ hns3_nic_get_stats64(struct net_device *netdev, struct rtnl_link_stats64 *stats) start = u64_stats_fetch_begin_irq(&ring->syncp); rx_bytes += ring->stats.rx_bytes; rx_pkts += ring->stats.rx_pkts; + rx_drop += ring->stats.non_vld_descs; + rx_drop += ring->stats.err_pkt_len; + rx_drop += ring->stats.l2_err; } while (u64_stats_fetch_retry_irq(&ring->syncp, start)); } @@ -1091,8 +1098,8 @@ hns3_nic_get_stats64(struct net_device *netdev, struct rtnl_link_stats64 *stats) stats->rx_missed_errors = netdev->stats.rx_missed_errors; stats->tx_errors = netdev->stats.tx_errors; - stats->rx_dropped = netdev->stats.rx_dropped; - stats->tx_dropped = netdev->stats.tx_dropped; + stats->rx_dropped = rx_drop + netdev->stats.rx_dropped; + stats->tx_dropped = tx_drop + netdev->stats.tx_dropped; stats->collisions = netdev->stats.collisions; stats->rx_over_errors = netdev->stats.rx_over_errors; stats->rx_frame_errors = netdev->stats.rx_frame_errors; -- GitLab From 611abba6eb684bf3b858c2a7bd100665d2c85543 Mon Sep 17 00:00:00 2001 From: Jian Shen Date: Fri, 5 Jan 2018 18:18:13 +0800 Subject: [PATCH 0233/1635] net: hns3: Fix a loop index error of tqp statistics query [ Upstream commit 94bfaafac9d2a3c0bcca00d01e38f7597b741799 ] An error loop index was used while querying statistics data of tqps, which may cause call trace. Fixes: 496d03e960ae ("net: hns3: Add Ethtool support to HNS3 driver") Signed-off-by: Jian Shen Signed-off-by: Peng Li Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- .../net/ethernet/hisilicon/hns3/hns3pf/hns3_ethtool.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hns3_ethtool.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hns3_ethtool.c index e590d96e434a..43ed4bc9e456 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hns3_ethtool.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hns3_ethtool.c @@ -189,13 +189,13 @@ static u64 *hns3_get_stats_tqps(struct hnae3_handle *handle, u64 *data) struct hnae3_knic_private_info *kinfo = &handle->kinfo; struct hns3_enet_ring *ring; u8 *stat; - u32 i; + int i, j; /* get stats for Tx */ for (i = 0; i < kinfo->num_tqps; i++) { ring = nic_priv->ring_data[i].ring; - for (i = 0; i < HNS3_TXQ_STATS_COUNT; i++) { - stat = (u8 *)ring + hns3_txq_stats[i].stats_offset; + for (j = 0; j < HNS3_TXQ_STATS_COUNT; j++) { + stat = (u8 *)ring + hns3_txq_stats[j].stats_offset; *data++ = *(u64 *)stat; } } @@ -203,8 +203,8 @@ static u64 *hns3_get_stats_tqps(struct hnae3_handle *handle, u64 *data) /* get stats for Rx */ for (i = 0; i < kinfo->num_tqps; i++) { ring = nic_priv->ring_data[i + kinfo->num_tqps].ring; - for (i = 0; i < HNS3_RXQ_STATS_COUNT; i++) { - stat = (u8 *)ring + hns3_rxq_stats[i].stats_offset; + for (j = 0; j < HNS3_RXQ_STATS_COUNT; j++) { + stat = (u8 *)ring + hns3_rxq_stats[j].stats_offset; *data++ = *(u64 *)stat; } } -- GitLab From be6a161e13028cc18727f187f2396190fbcba049 Mon Sep 17 00:00:00 2001 From: Jian Shen Date: Fri, 5 Jan 2018 18:18:14 +0800 Subject: [PATCH 0234/1635] net: hns3: Fix an error macro definition of HNS3_TQP_STAT [ Upstream commit 57ffee737b36dbb81e8e60a37e01791553157a5e ] The member "stats_offset" was designed to indicate the offset of each member of struct ring_stats in struct hns3_enet_ring, but forgot to add the offset of the member in struct ring_stats. Fixes: 496d03e960a ("net: hns3: Add Ethtool support to HNS3 driver") Signed-off-by: Jian Shen Signed-off-by: Peng Li Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/hisilicon/hns3/hns3pf/hns3_ethtool.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hns3_ethtool.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hns3_ethtool.c index 43ed4bc9e456..a64a5a413d4d 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hns3_ethtool.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hns3_ethtool.c @@ -22,7 +22,8 @@ struct hns3_stats { #define HNS3_TQP_STAT(_string, _member) { \ .stats_string = _string, \ .stats_size = FIELD_SIZEOF(struct ring_stats, _member), \ - .stats_offset = offsetof(struct hns3_enet_ring, stats), \ + .stats_offset = offsetof(struct hns3_enet_ring, stats) +\ + offsetof(struct ring_stats, _member), \ } \ static const struct hns3_stats hns3_txq_stats[] = { -- GitLab From b20482cebfb2b8bdf7cc323f23f4e3c04599c18b Mon Sep 17 00:00:00 2001 From: Fuyun Liang Date: Fri, 5 Jan 2018 18:18:20 +0800 Subject: [PATCH 0235/1635] net: hns3: fix for changing MTU [ Upstream commit 5bad95a1e55f4d5bb41e130db859d57eaf1b1549 ] when changing MTU, The new MTU must need to be set to netdevice. Fixes: a8e8b7ff3517 ("net: hns3: Add support to change MTU in HNS3 hardware") Signed-off-by: Fuyun Liang Signed-off-by: Peng Li Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/hisilicon/hns3/hns3pf/hns3_enet.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hns3_enet.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hns3_enet.c index fad480e323dd..d1e4dcec5db2 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hns3_enet.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hns3_enet.c @@ -1313,6 +1313,8 @@ static int hns3_nic_change_mtu(struct net_device *netdev, int new_mtu) return ret; } + netdev->mtu = new_mtu; + /* if the netdev was running earlier, bring it up again */ if (if_running && hns3_nic_net_open(netdev)) ret = -EINVAL; -- GitLab From 71468ce63dc97f1237e9445c1dadb4b9c45b17b1 Mon Sep 17 00:00:00 2001 From: Rui Hua Date: Mon, 8 Jan 2018 12:21:18 -0800 Subject: [PATCH 0236/1635] bcache: ret IOERR when read meets metadata error [ Upstream commit b221fc130c49c50f4c2250d22e873420765a9fa2 ] The read request might meet error when searching the btree, but the error was not handled in cache_lookup(), and this kind of metadata failure will not go into cached_dev_read_error(), finally, the upper layer will receive bi_status=0. In this patch we judge the metadata error by the return value of bch_btree_map_keys(), there are two potential paths give rise to the error: 1. Because the btree is not totally cached in memery, we maybe get error when read btree node from cache device (see bch_btree_node_get()), the likely errno is -EIO, -ENOMEM 2. When read miss happens, bch_btree_insert_check_key() will be called to insert a "replace_key" to btree(see cached_dev_cache_miss(), just for doing preparatory work before insert the missed data to cache device), a failure can also happen in this situation, the likely errno is -ENOMEM bch_btree_map_keys() will return MAP_DONE in normal scenario, but we will get either -EIO or -ENOMEM in above two cases. if this happened, we should NOT recover data from backing device (when cache device is dirty) because we don't know whether bkeys the read request covered are all clean. And after that happened, s->iop.status is still its initially value(0) before we submit s->bio.bio, we set it to BLK_STS_IOERR, so it can go into cached_dev_read_error(), and finally it can be passed to upper layer, or recovered by reread from backing device. [edit by mlyle: patch formatting, word-wrap, comment spelling, commit log format] Signed-off-by: Hua Rui Reviewed-by: Michael Lyle Signed-off-by: Michael Lyle Signed-off-by: Jens Axboe Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/md/bcache/request.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/drivers/md/bcache/request.c b/drivers/md/bcache/request.c index e9fbf2bcd122..f34ad8720756 100644 --- a/drivers/md/bcache/request.c +++ b/drivers/md/bcache/request.c @@ -568,6 +568,7 @@ static void cache_lookup(struct closure *cl) { struct search *s = container_of(cl, struct search, iop.cl); struct bio *bio = &s->bio.bio; + struct cached_dev *dc; int ret; bch_btree_op_init(&s->op, -1); @@ -580,6 +581,27 @@ static void cache_lookup(struct closure *cl) return; } + /* + * We might meet err when searching the btree, If that happens, we will + * get negative ret, in this scenario we should not recover data from + * backing device (when cache device is dirty) because we don't know + * whether bkeys the read request covered are all clean. + * + * And after that happened, s->iop.status is still its initial value + * before we submit s->bio.bio + */ + if (ret < 0) { + BUG_ON(ret == -EINTR); + if (s->d && s->d->c && + !UUID_FLASH_ONLY(&s->d->c->uuids[s->d->id])) { + dc = container_of(s->d, struct cached_dev, disk); + if (dc && atomic_read(&dc->has_dirty)) + s->recoverable = false; + } + if (!s->iop.status) + s->iop.status = BLK_STS_IOERR; + } + closure_return(cl); } -- GitLab From ef60904109f4b90a2dea0919fed297c6c3fc6c25 Mon Sep 17 00:00:00 2001 From: Tang Junhui Date: Mon, 8 Jan 2018 12:21:19 -0800 Subject: [PATCH 0237/1635] bcache: stop writeback thread after detaching [ Upstream commit 8d29c4426b9f8afaccf28de414fde8a722b35fdf ] Currently, when a cached device detaching from cache, writeback thread is not stopped, and writeback_rate_update work is not canceled. For example, after the following command: echo 1 >/sys/block/sdb/bcache/detach you can still see the writeback thread. Then you attach the device to the cache again, bcache will create another writeback thread, for example, after below command: echo ba0fb5cd-658a-4533-9806-6ce166d883b9 > /sys/block/sdb/bcache/attach then you will see 2 writeback threads. This patch stops writeback thread and cancels writeback_rate_update work when cached device detaching from cache. Compare with patch v1, this v2 patch moves code down into the register lock for safety in case of any future changes as Coly and Mike suggested. [edit by mlyle: commit log spelling/formatting] Signed-off-by: Tang Junhui Reviewed-by: Michael Lyle Signed-off-by: Michael Lyle Signed-off-by: Jens Axboe Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/md/bcache/super.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/md/bcache/super.c b/drivers/md/bcache/super.c index 9417170f180a..5d0430777dda 100644 --- a/drivers/md/bcache/super.c +++ b/drivers/md/bcache/super.c @@ -893,6 +893,12 @@ static void cached_dev_detach_finish(struct work_struct *w) mutex_lock(&bch_register_lock); + cancel_delayed_work_sync(&dc->writeback_rate_update); + if (!IS_ERR_OR_NULL(dc->writeback_thread)) { + kthread_stop(dc->writeback_thread); + dc->writeback_thread = NULL; + } + memset(&dc->sb.set_uuid, 0, 16); SET_BDEV_STATE(&dc->sb, BDEV_STATE_NONE); -- GitLab From fad9bcb1176be5c9068c3ef6f13398de502b35d8 Mon Sep 17 00:00:00 2001 From: Tang Junhui Date: Mon, 8 Jan 2018 12:21:21 -0800 Subject: [PATCH 0238/1635] bcache: segregate flash only volume write streams [ Upstream commit 4eca1cb28d8b0574ca4f1f48e9331c5f852d43b9 ] In such scenario that there are some flash only volumes , and some cached devices, when many tasks request these devices in writeback mode, the write IOs may fall to the same bucket as bellow: | cached data | flash data | cached data | cached data| flash data| then after writeback of these cached devices, the bucket would be like bellow bucket: | free | flash data | free | free | flash data | So, there are many free space in this bucket, but since data of flash only volumes still exists, so this bucket cannot be reclaimable, which would cause waste of bucket space. In this patch, we segregate flash only volume write streams from cached devices, so data from flash only volumes and cached devices can store in different buckets. Compare to v1 patch, this patch do not add a additionally open bucket list, and it is try best to segregate flash only volume write streams from cached devices, sectors of flash only volumes may still be mixed with dirty sectors of cached device, but the number is very small. [mlyle: fixed commit log formatting, permissions, line endings] Signed-off-by: Tang Junhui Reviewed-by: Michael Lyle Signed-off-by: Michael Lyle Signed-off-by: Jens Axboe Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/md/bcache/alloc.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/drivers/md/bcache/alloc.c b/drivers/md/bcache/alloc.c index 934b1fce4ce1..f0dc8e2aee65 100644 --- a/drivers/md/bcache/alloc.c +++ b/drivers/md/bcache/alloc.c @@ -515,15 +515,21 @@ struct open_bucket { /* * We keep multiple buckets open for writes, and try to segregate different - * write streams for better cache utilization: first we look for a bucket where - * the last write to it was sequential with the current write, and failing that - * we look for a bucket that was last used by the same task. + * write streams for better cache utilization: first we try to segregate flash + * only volume write streams from cached devices, secondly we look for a bucket + * where the last write to it was sequential with the current write, and + * failing that we look for a bucket that was last used by the same task. * * The ideas is if you've got multiple tasks pulling data into the cache at the * same time, you'll get better cache utilization if you try to segregate their * data and preserve locality. * - * For example, say you've starting Firefox at the same time you're copying a + * For example, dirty sectors of flash only volume is not reclaimable, if their + * dirty sectors mixed with dirty sectors of cached device, such buckets will + * be marked as dirty and won't be reclaimed, though the dirty data of cached + * device have been written back to backend device. + * + * And say you've starting Firefox at the same time you're copying a * bunch of files. Firefox will likely end up being fairly hot and stay in the * cache awhile, but the data you copied might not be; if you wrote all that * data to the same buckets it'd get invalidated at the same time. @@ -540,7 +546,10 @@ static struct open_bucket *pick_data_bucket(struct cache_set *c, struct open_bucket *ret, *ret_task = NULL; list_for_each_entry_reverse(ret, &c->data_buckets, list) - if (!bkey_cmp(&ret->key, search)) + if (UUID_FLASH_ONLY(&c->uuids[KEY_INODE(&ret->key)]) != + UUID_FLASH_ONLY(&c->uuids[KEY_INODE(search)])) + continue; + else if (!bkey_cmp(&ret->key, search)) goto found; else if (ret->last_write_point == write_point) ret_task = ret; -- GitLab From 8644d14c3240b6875c9e0e72c346146c24a6d8c1 Mon Sep 17 00:00:00 2001 From: Jason Yan Date: Thu, 4 Jan 2018 21:04:31 +0800 Subject: [PATCH 0239/1635] scsi: libsas: fix memory leak in sas_smp_get_phy_events() [ Upstream commit 4a491b1ab11ca0556d2fda1ff1301e862a2d44c4 ] We've got a memory leak with the following producer: while true; do cat /sys/class/sas_phy/phy-1:0:12/invalid_dword_count >/dev/null; done The buffer req is allocated and not freed after we return. Fix it. Fixes: 2908d778ab3e ("[SCSI] aic94xx: new driver") Signed-off-by: Jason Yan CC: John Garry CC: chenqilin CC: chenxiang Reviewed-by: Christoph Hellwig Reviewed-by: Hannes Reinecke Signed-off-by: Martin K. Petersen Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/libsas/sas_expander.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/scsi/libsas/sas_expander.c b/drivers/scsi/libsas/sas_expander.c index 324d8d8c62de..fc17b4a5217e 100644 --- a/drivers/scsi/libsas/sas_expander.c +++ b/drivers/scsi/libsas/sas_expander.c @@ -695,6 +695,7 @@ int sas_smp_get_phy_events(struct sas_phy *phy) phy->phy_reset_problem_count = scsi_to_u32(&resp[24]); out: + kfree(req); kfree(resp); return res; -- GitLab From f890a23603e3b756f182df99161a850682107c84 Mon Sep 17 00:00:00 2001 From: Jason Yan Date: Thu, 4 Jan 2018 21:04:32 +0800 Subject: [PATCH 0240/1635] scsi: libsas: fix error when getting phy events [ Upstream commit 2b23d9509fd7174b362482cf5f3b5f9a2265bc33 ] The intend purpose here was to goto out if smp_execute_task() returned error. Obviously something got screwed up. We will never get these link error statistics below: ~:/sys/class/sas_phy/phy-1:0:12 # cat invalid_dword_count 0 ~:/sys/class/sas_phy/phy-1:0:12 # cat running_disparity_error_count 0 ~:/sys/class/sas_phy/phy-1:0:12 # cat loss_of_dword_sync_count 0 ~:/sys/class/sas_phy/phy-1:0:12 # cat phy_reset_problem_count 0 Obviously we should goto error handler if smp_execute_task() returns non-zero. Fixes: 2908d778ab3e ("[SCSI] aic94xx: new driver") Signed-off-by: Jason Yan CC: John Garry CC: chenqilin CC: chenxiang Reviewed-by: Hannes Reinecke Reviewed-by: Christoph Hellwig Signed-off-by: Martin K. Petersen Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/libsas/sas_expander.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/libsas/sas_expander.c b/drivers/scsi/libsas/sas_expander.c index fc17b4a5217e..6873d8fbc541 100644 --- a/drivers/scsi/libsas/sas_expander.c +++ b/drivers/scsi/libsas/sas_expander.c @@ -686,7 +686,7 @@ int sas_smp_get_phy_events(struct sas_phy *phy) res = smp_execute_task(dev, req, RPEL_REQ_SIZE, resp, RPEL_RESP_SIZE); - if (!res) + if (res) goto out; phy->invalid_dword_count = scsi_to_u32(&resp[12]); -- GitLab From b728b7e24fbcd283b97623167adddcf2ef8c8e2e Mon Sep 17 00:00:00 2001 From: chenxiang Date: Thu, 4 Jan 2018 21:04:33 +0800 Subject: [PATCH 0241/1635] scsi: libsas: initialize sas_phy status according to response of DISCOVER [ Upstream commit affc67788fe5dfffad5cda3d461db5cf2b2ff2b0 ] The status of SAS PHY is in sas_phy->enabled. There is an issue that the status of a remote SAS PHY may be initialized incorrectly: if disable remote SAS PHY through sysfs interface (such as echo 0 > /sys/class/sas_phy/phy-1:0:0/enable), then reboot the system, and we will find the status of remote SAS PHY which is disabled before is 1 (cat /sys/class/sas_phy/phy-1:0:0/enable). But actually the status of remote SAS PHY is disabled and the device attached is not found. In SAS protocol, NEGOTIATED LOGICAL LINK RATE field of DISCOVER response is 0x1 when remote SAS PHY is disabled. So initialize sas_phy->enabled according to the value of NEGOTIATED LOGICAL LINK RATE field. Signed-off-by: chenxiang Reviewed-by: John Garry Signed-off-by: Jason Yan Reviewed-by: Christoph Hellwig Reviewed-by: Hannes Reinecke Signed-off-by: Martin K. Petersen Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/libsas/sas_expander.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/scsi/libsas/sas_expander.c b/drivers/scsi/libsas/sas_expander.c index 6873d8fbc541..e2ea389fbec3 100644 --- a/drivers/scsi/libsas/sas_expander.c +++ b/drivers/scsi/libsas/sas_expander.c @@ -293,6 +293,7 @@ static void sas_set_ex_phy(struct domain_device *dev, int phy_id, void *rsp) phy->phy->minimum_linkrate = dr->pmin_linkrate; phy->phy->maximum_linkrate = dr->pmax_linkrate; phy->phy->negotiated_linkrate = phy->linkrate; + phy->phy->enabled = (phy->linkrate != SAS_PHY_DISABLED); skip: if (new_phy) -- GitLab From 8976d64b2f0fd102822895d9b3ed9e8ab09429e5 Mon Sep 17 00:00:00 2001 From: Ming Lei Date: Tue, 9 Jan 2018 21:28:29 +0800 Subject: [PATCH 0242/1635] blk-mq: fix kernel oops in blk_mq_tag_idle() [ Upstream commit 8ab0b7dc73e1b3e2987d42554b2bff503f692772 ] HW queues may be unmapped in some cases, such as blk_mq_update_nr_hw_queues(), then we need to check it before calling blk_mq_tag_idle(), otherwise the following kernel oops can be triggered, so fix it by checking if the hw queue is unmapped since it doesn't make sense to idle the tags any more after hw queues are unmapped. [ 440.771298] Workqueue: nvme-wq nvme_rdma_del_ctrl_work [nvme_rdma] [ 440.779104] task: ffff894bae755ee0 ti: ffff893bf9bc8000 task.ti: ffff893bf9bc8000 [ 440.788359] RIP: 0010:[] [] __blk_mq_tag_idle+0x24/0x40 [ 440.798697] RSP: 0018:ffff893bf9bcbd10 EFLAGS: 00010286 [ 440.805538] RAX: 0000000000000000 RBX: ffff895bb131dc00 RCX: 000000000000011f [ 440.814426] RDX: 00000000ffffffff RSI: 0000000000000120 RDI: ffff895bb131dc00 [ 440.823301] RBP: ffff893bf9bcbd10 R08: 000000000001b860 R09: 4a51d361c00c0000 [ 440.832193] R10: b5907f32b4cc7003 R11: ffffd6cabfb57000 R12: ffff894bafd1e008 [ 440.841091] R13: 0000000000000001 R14: ffff895baf770000 R15: 0000000000000080 [ 440.849988] FS: 0000000000000000(0000) GS:ffff894bbdcc0000(0000) knlGS:0000000000000000 [ 440.859955] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 440.867274] CR2: 0000000000000008 CR3: 000000103d098000 CR4: 00000000001407e0 [ 440.876169] Call Trace: [ 440.879818] [] blk_mq_exit_hctx+0xd8/0xe0 [ 440.887051] [] blk_mq_free_queue+0xf0/0x160 [ 440.894465] [] blk_cleanup_queue+0xd9/0x150 [ 440.901881] [] nvme_ns_remove+0x5b/0xb0 [nvme_core] [ 440.910068] [] nvme_remove_namespaces+0x3b/0x60 [nvme_core] [ 440.919026] [] __nvme_rdma_remove_ctrl+0x2b/0xb0 [nvme_rdma] [ 440.928079] [] nvme_rdma_del_ctrl_work+0x17/0x20 [nvme_rdma] [ 440.937126] [] process_one_work+0x17a/0x440 [ 440.944517] [] worker_thread+0x278/0x3c0 [ 440.951607] [] ? manage_workers.isra.24+0x2a0/0x2a0 [ 440.959760] [] kthread+0xcf/0xe0 [ 440.966055] [] ? insert_kthread_work+0x40/0x40 [ 440.973715] [] ret_from_fork+0x58/0x90 [ 440.980586] [] ? insert_kthread_work+0x40/0x40 [ 440.988229] Code: 5b 41 5c 5d c3 66 90 0f 1f 44 00 00 48 8b 87 20 01 00 00 f0 0f ba 77 40 01 19 d2 85 d2 75 08 c3 0f 1f 80 00 00 00 00 55 48 89 e5 ff 48 08 48 8d 78 10 e8 7f 0f 05 00 5d c3 0f 1f 00 66 2e 0f [ 441.011620] RIP [] __blk_mq_tag_idle+0x24/0x40 [ 441.019301] RSP [ 441.024052] CR2: 0000000000000008 Reported-by: Zhang Yi Tested-by: Zhang Yi Signed-off-by: Ming Lei Signed-off-by: Jens Axboe Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- block/blk-mq.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/block/blk-mq.c b/block/blk-mq.c index c28d6b3088a0..6f899669cbdd 100644 --- a/block/blk-mq.c +++ b/block/blk-mq.c @@ -1928,7 +1928,8 @@ static void blk_mq_exit_hctx(struct request_queue *q, { blk_mq_debugfs_unregister_hctx(hctx); - blk_mq_tag_idle(hctx); + if (blk_mq_hw_queue_mapped(hctx)) + blk_mq_tag_idle(hctx); if (set->ops->exit_request) set->ops->exit_request(set, hctx->fq->flush_rq, hctx_idx); -- GitLab From 4ed8692bb2d67d38c59eaaae6e346b235690b0f9 Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Wed, 3 Jan 2018 10:18:03 -0800 Subject: [PATCH 0243/1635] tty: n_gsm: Allow ADM response in addition to UA for control dlci [ Upstream commit ea3d8465ab9b3e01be329ac5195970a84bef76c5 ] Some devices have the control dlci stay in ADM mode instead of the UA mode. This can seen at least on droid 4 when trying to open the ts 27.010 mux port. Enabling n_gsm debug mode shows the control dlci always respond with DM to SABM instead of UA: # modprobe n_gsm debug=0xff # ldattach -d GSM0710 /dev/ttyS0 & gsmld_output: 00000000: f9 03 3f 01 1c f9 --> 0) C: SABM(P) gsmld_receive: 00000000: f9 03 1f 01 36 f9 <-- 0) C: DM(P) ... $ minicom -D /dev/gsmtty1 minicom: cannot open /dev/gsmtty1: No error information $ strace minicom -D /dev/gsmtty1 ... open("/dev/gsmtty1", O_RDWR|O_NOCTTY|O_NONBLOCK|O_LARGEFILE) = -1 EL2HLT Note that this is different issue from other n_gsm -EL2HLT issues such as timeouts when the control dlci does not respond at all. The ADM mode seems to be a quite common according to "RF Wireless World" article "GSM Issue-UE sends SABM and gets a DM response instead of UA response": This issue is most commonly observed in GSM networks where in UE sends SABM and expects network to send UA response but it ends up receiving DM response from the network. SABM stands for Set asynchronous balanced mode, UA stands for Unnumbered Acknowledge and DA stands for Disconnected Mode. An RLP entity can be in one of two modes: - Asynchronous Balanced Mode (ABM) - Asynchronous Disconnected Mode (ADM) Currently Linux kernel closes the control dlci after several retries in gsm_dlci_t1() on DM. This causes n_gsm /dev/gsmtty ports to produce error code -EL2HLT when trying to open them as the closing of control dlci has already set gsm->dead. Let's fix the issue by allowing control dlci stay in ADM mode after the retries so the /dev/gsmtty ports can be opened and used. It seems that it might take several attempts to get any response from the control dlci, so it's best to allow ADM mode only after the SABM retries are done. Note that for droid 4 additional patches are needed to mux the ttyS0 pins and to toggle RTS gpio_149 to wake up the mdm6600 modem are also needed to use n_gsm. And the mdm6600 modem needs to be powered on. Cc: linux-serial@vger.kernel.org Cc: Alan Cox Cc: Jiri Prchal Cc: Jiri Slaby Cc: Marcel Partap Cc: Michael Scott Cc: Peter Hurley Cc: Russ Gorby Cc: Sascha Hauer Cc: Sebastian Reichel Signed-off-by: Tony Lindgren Signed-off-by: Greg Kroah-Hartman Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/tty/n_gsm.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c index 0a3c9665e015..7253e8d2c6d9 100644 --- a/drivers/tty/n_gsm.c +++ b/drivers/tty/n_gsm.c @@ -1463,6 +1463,10 @@ static void gsm_dlci_open(struct gsm_dlci *dlci) * in which case an opening port goes back to closed and a closing port * is simply put into closed state (any further frames from the other * end will get a DM response) + * + * Some control dlci can stay in ADM mode with other dlci working just + * fine. In that case we can just keep the control dlci open after the + * DLCI_OPENING retries time out. */ static void gsm_dlci_t1(unsigned long data) @@ -1476,8 +1480,15 @@ static void gsm_dlci_t1(unsigned long data) if (dlci->retries) { gsm_command(dlci->gsm, dlci->addr, SABM|PF); mod_timer(&dlci->t1, jiffies + gsm->t1 * HZ / 100); - } else + } else if (!dlci->addr && gsm->control == (DM | PF)) { + if (debug & 8) + pr_info("DLCI %d opening in ADM mode.\n", + dlci->addr); + gsm_dlci_open(dlci); + } else { gsm_dlci_close(dlci); + } + break; case DLCI_CLOSING: dlci->retries--; @@ -1495,8 +1506,8 @@ static void gsm_dlci_t1(unsigned long data) * @dlci: DLCI to open * * Commence opening a DLCI from the Linux side. We issue SABM messages - * to the modem which should then reply with a UA, at which point we - * will move into open state. Opening is done asynchronously with retry + * to the modem which should then reply with a UA or ADM, at which point + * we will move into open state. Opening is done asynchronously with retry * running off timers and the responses. */ -- GitLab From effbffc91da3c9520e9b2f15fbc099f257d7cf03 Mon Sep 17 00:00:00 2001 From: Paolo Valente Date: Tue, 9 Jan 2018 10:27:58 +0100 Subject: [PATCH 0244/1635] block, bfq: put async queues for root bfq groups too MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit 52257ffbfcaf58d247b13fb148e27ed17c33e526 ] For each pair [device for which bfq is selected as I/O scheduler, group in blkio/io], bfq maintains a corresponding bfq group. Each such bfq group contains a set of async queues, with each async queue created on demand, i.e., when some I/O request arrives for it. On creation, an async queue gets an extra reference, to make sure that the queue is not freed as long as its bfq group exists. Accordingly, to allow the queue to be freed after the group exited, this extra reference must released on group exit. The above holds also for a bfq root group, i.e., for the bfq group corresponding to the root blkio/io root for a given device. Yet, by mistake, the references to the existing async queues of a root group are not released when the latter exits. This causes a memory leak when the instance of bfq for a given device exits. In a similar vein, bfqg_stats_xfer_dead is not executed for a root group. This commit fixes bfq_pd_offline so that the latter executes the above missing operations for a root group too. Reported-by: Holger Hoffstätte Reported-by: Guoqing Jiang Tested-by: Holger Hoffstätte Signed-off-by: Davide Ferrari Signed-off-by: Paolo Valente Signed-off-by: Jens Axboe Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- block/bfq-cgroup.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/block/bfq-cgroup.c b/block/bfq-cgroup.c index ceefb9a706d6..5d53e504acae 100644 --- a/block/bfq-cgroup.c +++ b/block/bfq-cgroup.c @@ -749,10 +749,11 @@ static void bfq_pd_offline(struct blkg_policy_data *pd) unsigned long flags; int i; + spin_lock_irqsave(&bfqd->lock, flags); + if (!entity) /* root group */ - return; + goto put_async_queues; - spin_lock_irqsave(&bfqd->lock, flags); /* * Empty all service_trees belonging to this group before * deactivating the group itself. @@ -783,6 +784,8 @@ static void bfq_pd_offline(struct blkg_policy_data *pd) } __bfq_deactivate_entity(entity, false); + +put_async_queues: bfq_put_async_queues(bfqd, bfqg); spin_unlock_irqrestore(&bfqd->lock, flags); -- GitLab From 28b35f9aa0c068075ca57ab646d87e2f607a9d5c Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Sun, 7 Jan 2018 21:54:00 +0100 Subject: [PATCH 0245/1635] EDAC, mv64x60: Fix an error handling path [ Upstream commit 68fa24f9121c04ef146b5158f538c8b32f285be5 ] We should not call edac_mc_del_mc() if a corresponding call to edac_mc_add_mc() has not been performed yet. So here, we should go to err instead of err2 to branch at the right place of the error handling path. Signed-off-by: Christophe JAILLET Cc: linux-edac Link: http://lkml.kernel.org/r/20180107205400.14068-1-christophe.jaillet@wanadoo.fr Signed-off-by: Borislav Petkov Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/edac/mv64x60_edac.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/edac/mv64x60_edac.c b/drivers/edac/mv64x60_edac.c index ec5d695bbb72..3c68bb525d5d 100644 --- a/drivers/edac/mv64x60_edac.c +++ b/drivers/edac/mv64x60_edac.c @@ -758,7 +758,7 @@ static int mv64x60_mc_err_probe(struct platform_device *pdev) /* Non-ECC RAM? */ printk(KERN_WARNING "%s: No ECC DIMMs discovered\n", __func__); res = -ENODEV; - goto err2; + goto err; } edac_dbg(3, "init mci\n"); -- GitLab From d96a094c987f5409f0037aa4964eab989f6f4ea8 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Tue, 9 Jan 2018 12:57:31 -0800 Subject: [PATCH 0246/1635] uio_hv_generic: check that host supports monitor page [ Upstream commit 06028d15177a1b406b7b075ea47c6a352732f23a ] In order for userspace application to signal host, it needs the host to support the monitor page property. Check for the flag and fail if this is not supported. Signed-off-by: Stephen Hemminger Signed-off-by: Greg Kroah-Hartman Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/uio/uio_hv_generic.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/uio/uio_hv_generic.c b/drivers/uio/uio_hv_generic.c index 48d5327d38d4..fe5cdda80b2c 100644 --- a/drivers/uio/uio_hv_generic.c +++ b/drivers/uio/uio_hv_generic.c @@ -124,6 +124,13 @@ hv_uio_probe(struct hv_device *dev, if (ret) goto fail; + /* Communicating with host has to be via shared memory not hypercall */ + if (!dev->channel->offermsg.monitor_allocated) { + dev_err(&dev->device, "vmbus channel requires hypercall\n"); + ret = -ENOTSUPP; + goto fail_close; + } + dev->channel->inbound.ring_buffer->interrupt_mask = 1; set_channel_read_mode(dev->channel, HV_CALL_DIRECT); -- GitLab From d017aeb58a3e2d0596a758f6c76f2e848bc039ca Mon Sep 17 00:00:00 2001 From: Jacob Keller Date: Fri, 27 Oct 2017 11:06:49 -0400 Subject: [PATCH 0247/1635] i40evf: don't rely on netif_running() outside rtnl_lock() [ Upstream commit 44b034b406211fc103159f82b9e601e05675c739 ] In i40evf_reset_task we use netif_running() to determine whether or not the device is currently up. This allows us to properly free queue memory and shut down things before we request the hardware reset. It turns out that we cannot be guaranteed of netif_running() returning false until the device is fully up, as the kernel core code sets __LINK_STATE_START prior to calling .ndo_open. Since we're not holding the rtnl_lock(), it's possible that the driver's i40evf_open handler function is currently being called while we're resetting. We can't simply hold the rtnl_lock() while checking netif_running() as this could cause a deadlock with the i40evf_open() function. Additionally, we can't avoid the deadlock by holding the rtnl_lock() over the whole reset path, as this essentially serializes all resets, and can cause massive delays if we have multiple VFs on a system. Instead, lets just check our own internal state __I40EVF_RUNNING state field. This allows us to ensure that the state is correct and is only set after we've finished bringing the device up. Without this change we might free data structures about device queues and other memory before they've been fully allocated. Signed-off-by: Jacob Keller Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- .../net/ethernet/intel/i40evf/i40evf_main.c | 20 ++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_main.c b/drivers/net/ethernet/intel/i40evf/i40evf_main.c index 1ccad6f30ebf..4eb6ff60e8fc 100644 --- a/drivers/net/ethernet/intel/i40evf/i40evf_main.c +++ b/drivers/net/ethernet/intel/i40evf/i40evf_main.c @@ -1775,7 +1775,11 @@ static void i40evf_disable_vf(struct i40evf_adapter *adapter) adapter->flags |= I40EVF_FLAG_PF_COMMS_FAILED; - if (netif_running(adapter->netdev)) { + /* We don't use netif_running() because it may be true prior to + * ndo_open() returning, so we can't assume it means all our open + * tasks have finished, since we're not holding the rtnl_lock here. + */ + if (adapter->state == __I40EVF_RUNNING) { set_bit(__I40E_VSI_DOWN, adapter->vsi.state); netif_carrier_off(adapter->netdev); netif_tx_disable(adapter->netdev); @@ -1833,6 +1837,7 @@ static void i40evf_reset_task(struct work_struct *work) struct i40evf_mac_filter *f; u32 reg_val; int i = 0, err; + bool running; while (test_and_set_bit(__I40EVF_IN_CLIENT_TASK, &adapter->crit_section)) @@ -1892,7 +1897,13 @@ static void i40evf_reset_task(struct work_struct *work) } continue_reset: - if (netif_running(netdev)) { + /* We don't use netif_running() because it may be true prior to + * ndo_open() returning, so we can't assume it means all our open + * tasks have finished, since we're not holding the rtnl_lock here. + */ + running = (adapter->state == __I40EVF_RUNNING); + + if (running) { netif_carrier_off(netdev); netif_tx_stop_all_queues(netdev); adapter->link_up = false; @@ -1936,7 +1947,10 @@ static void i40evf_reset_task(struct work_struct *work) mod_timer(&adapter->watchdog_timer, jiffies + 2); - if (netif_running(adapter->netdev)) { + /* We were running when the reset started, so we need to restore some + * state here. + */ + if (running) { /* allocate transmit descriptors */ err = i40evf_setup_all_tx_resources(adapter); if (err) -- GitLab From b432f980596c82f6edbfc36df9f237bdafa6d7ae Mon Sep 17 00:00:00 2001 From: Arjun Vynipadath Date: Wed, 10 Jan 2018 12:02:13 +0530 Subject: [PATCH 0248/1635] cxgb4vf: Fix SGE FL buffer initialization logic for 64K pages [ Upstream commit ea0a42109aee7b92e631c4eb3f2219fadf58acdd ] We'd come in with SGE_FL_BUFFER_SIZE[0] and [1] both equal to 64KB and the extant logic would flag that as an error. This was already fixed in cxgb4 driver with "92ddcc7 cxgb4: Fix some small bugs in t4_sge_init_soft() when our Page Size is 64KB". Original Work by: Casey Leedom Signed-off-by: Arjun Vynipadath Signed-off-by: Ganesh Goudar Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/chelsio/cxgb4vf/sge.c | 23 ++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/drivers/net/ethernet/chelsio/cxgb4vf/sge.c b/drivers/net/ethernet/chelsio/cxgb4vf/sge.c index 05498e7f2840..6246003f9922 100644 --- a/drivers/net/ethernet/chelsio/cxgb4vf/sge.c +++ b/drivers/net/ethernet/chelsio/cxgb4vf/sge.c @@ -2619,8 +2619,8 @@ void t4vf_sge_stop(struct adapter *adapter) int t4vf_sge_init(struct adapter *adapter) { struct sge_params *sge_params = &adapter->params.sge; - u32 fl0 = sge_params->sge_fl_buffer_size[0]; - u32 fl1 = sge_params->sge_fl_buffer_size[1]; + u32 fl_small_pg = sge_params->sge_fl_buffer_size[0]; + u32 fl_large_pg = sge_params->sge_fl_buffer_size[1]; struct sge *s = &adapter->sge; /* @@ -2628,9 +2628,20 @@ int t4vf_sge_init(struct adapter *adapter) * the Physical Function Driver. Ideally we should be able to deal * with _any_ configuration. Practice is different ... */ - if (fl0 != PAGE_SIZE || (fl1 != 0 && fl1 <= fl0)) { + + /* We only bother using the Large Page logic if the Large Page Buffer + * is larger than our Page Size Buffer. + */ + if (fl_large_pg <= fl_small_pg) + fl_large_pg = 0; + + /* The Page Size Buffer must be exactly equal to our Page Size and the + * Large Page Size Buffer should be 0 (per above) or a power of 2. + */ + if (fl_small_pg != PAGE_SIZE || + (fl_large_pg & (fl_large_pg - 1)) != 0) { dev_err(adapter->pdev_dev, "bad SGE FL buffer sizes [%d, %d]\n", - fl0, fl1); + fl_small_pg, fl_large_pg); return -EINVAL; } if ((sge_params->sge_control & RXPKTCPLMODE_F) != @@ -2642,8 +2653,8 @@ int t4vf_sge_init(struct adapter *adapter) /* * Now translate the adapter parameters into our internal forms. */ - if (fl1) - s->fl_pg_order = ilog2(fl1) - PAGE_SHIFT; + if (fl_large_pg) + s->fl_pg_order = ilog2(fl_large_pg) - PAGE_SHIFT; s->stat_len = ((sge_params->sge_control & EGRSTATUSPAGESIZE_F) ? 128 : 64); s->pktshift = PKTSHIFT_G(sge_params->sge_control); -- GitLab From 70077054384df5744d41475392bf4ee4b6292de1 Mon Sep 17 00:00:00 2001 From: Shivasharan S Date: Fri, 5 Jan 2018 05:27:40 -0800 Subject: [PATCH 0249/1635] scsi: megaraid_sas: Error handling for invalid ldcount provided by firmware in RAID map [ Upstream commit 7ada701d0d5e5c6d357e157a72b841db3e8d03f4 ] Currently driver does not validate ldcount provided by firmware. If the value is invalid, fail RAID map validation accordingly. This issue is rare to hit in field and is fixed as part of code review. Signed-off-by: Sumit Saxena Signed-off-by: Shivasharan S Signed-off-by: Martin K. Petersen Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/megaraid/megaraid_sas_fp.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/megaraid/megaraid_sas_fp.c b/drivers/scsi/megaraid/megaraid_sas_fp.c index ecc699a65bac..08945142b9f8 100644 --- a/drivers/scsi/megaraid/megaraid_sas_fp.c +++ b/drivers/scsi/megaraid/megaraid_sas_fp.c @@ -168,7 +168,7 @@ static struct MR_LD_SPAN *MR_LdSpanPtrGet(u32 ld, u32 span, /* * This function will Populate Driver Map using firmware raid map */ -void MR_PopulateDrvRaidMap(struct megasas_instance *instance) +static int MR_PopulateDrvRaidMap(struct megasas_instance *instance) { struct fusion_context *fusion = instance->ctrl_context; struct MR_FW_RAID_MAP_ALL *fw_map_old = NULL; @@ -259,7 +259,7 @@ void MR_PopulateDrvRaidMap(struct megasas_instance *instance) ld_count = (u16)le16_to_cpu(fw_map_ext->ldCount); if (ld_count > MAX_LOGICAL_DRIVES_EXT) { dev_dbg(&instance->pdev->dev, "megaraid_sas: LD count exposed in RAID map in not valid\n"); - return; + return 1; } pDrvRaidMap->ldCount = (__le16)cpu_to_le16(ld_count); @@ -285,6 +285,12 @@ void MR_PopulateDrvRaidMap(struct megasas_instance *instance) fusion->ld_map[(instance->map_id & 1)]; pFwRaidMap = &fw_map_old->raidMap; ld_count = (u16)le32_to_cpu(pFwRaidMap->ldCount); + if (ld_count > MAX_LOGICAL_DRIVES) { + dev_dbg(&instance->pdev->dev, + "LD count exposed in RAID map in not valid\n"); + return 1; + } + pDrvRaidMap->totalSize = pFwRaidMap->totalSize; pDrvRaidMap->ldCount = (__le16)cpu_to_le16(ld_count); pDrvRaidMap->fpPdIoTimeoutSec = pFwRaidMap->fpPdIoTimeoutSec; @@ -300,6 +306,8 @@ void MR_PopulateDrvRaidMap(struct megasas_instance *instance) sizeof(struct MR_DEV_HANDLE_INFO) * MAX_RAIDMAP_PHYSICAL_DEVICES); } + + return 0; } /* @@ -317,8 +325,8 @@ u8 MR_ValidateMapInfo(struct megasas_instance *instance) u16 ld; u32 expected_size; - - MR_PopulateDrvRaidMap(instance); + if (MR_PopulateDrvRaidMap(instance)) + return 0; fusion = instance->ctrl_context; drv_map = fusion->ld_drv_map[(instance->map_id & 1)]; -- GitLab From 15dfb9baba2c8e8d9d92186cb8012a91c0ef897a Mon Sep 17 00:00:00 2001 From: Shivasharan S Date: Fri, 5 Jan 2018 05:27:41 -0800 Subject: [PATCH 0250/1635] scsi: megaraid_sas: unload flag should be set after scsi_remove_host is called [ Upstream commit f3f7920b3910171b2999c7dc2335eb9f583e44f2 ] Issue - Driver returns DID_NO_CONNECT when unload is in progress, indicated using instance->unload flag. In case of dynamic unload of driver, this flag is set before calling scsi_remove_host(). While doing manual driver unload, user will see lots of prints for Sync Cache command with DID_NO_CONNECT status. Fix - Set the instance->unload flag after scsi_remove_host(). Allow device removal process to be completed and do not block any command before that. SCSI commands (like SYNC_CACHE) are received (as part of scsi_remove_host) by driver during unload will be submitted further down to the drives. Signed-off-by: Sumit Saxena Signed-off-by: Shivasharan S Signed-off-by: Martin K. Petersen Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/megaraid/megaraid_sas_base.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c index e518dadc8161..4beb4dd2bee8 100644 --- a/drivers/scsi/megaraid/megaraid_sas_base.c +++ b/drivers/scsi/megaraid/megaraid_sas_base.c @@ -6605,7 +6605,6 @@ static void megasas_detach_one(struct pci_dev *pdev) u32 pd_seq_map_sz; instance = pci_get_drvdata(pdev); - instance->unload = 1; host = instance->host; fusion = instance->ctrl_context; @@ -6616,6 +6615,7 @@ static void megasas_detach_one(struct pci_dev *pdev) if (instance->fw_crash_state != UNAVAILABLE) megasas_free_host_crash_buffer(instance); scsi_remove_host(instance->host); + instance->unload = 1; if (megasas_wait_for_adapter_operational(instance)) goto skip_firing_dcmds; -- GitLab From cfafed12f459daadbfe17ce049180715aef6dab4 Mon Sep 17 00:00:00 2001 From: Parav Pandit Date: Mon, 8 Jan 2018 17:04:48 +0200 Subject: [PATCH 0251/1635] RDMA/cma: Fix rdma_cm path querying for RoCE [ Upstream commit 89838118a515847d3e5c904d2e022779a7173bec ] The 'if' logic in ucma_query_path was broken with OPA was introduced and started to treat RoCE paths as as OPA paths. Invert the logic of the 'if' so only OPA paths are treated as OPA paths. Otherwise the path records returned to rdma_cma users are mangled when in RoCE mode. Fixes: 57520751445b ("IB/SA: Add OPA path record type") Signed-off-by: Parav Pandit Reviewed-by: Mark Bloch Signed-off-by: Leon Romanovsky Signed-off-by: Jason Gunthorpe Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/infiniband/core/ucma.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/infiniband/core/ucma.c b/drivers/infiniband/core/ucma.c index 722235bed075..d6fa38f8604f 100644 --- a/drivers/infiniband/core/ucma.c +++ b/drivers/infiniband/core/ucma.c @@ -914,13 +914,14 @@ static ssize_t ucma_query_path(struct ucma_context *ctx, resp->path_data[i].flags = IB_PATH_GMP | IB_PATH_PRIMARY | IB_PATH_BIDIRECTIONAL; - if (rec->rec_type == SA_PATH_REC_TYPE_IB) { - ib_sa_pack_path(rec, &resp->path_data[i].path_rec); - } else { + if (rec->rec_type == SA_PATH_REC_TYPE_OPA) { struct sa_path_rec ib; sa_convert_path_opa_to_ib(&ib, rec); ib_sa_pack_path(&ib, &resp->path_data[i].path_rec); + + } else { + ib_sa_pack_path(rec, &resp->path_data[i].path_rec); } } -- GitLab From 4aafb8cdcc11e664f7774f0506780cdd9c5d73b6 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Wed, 10 Jan 2018 14:37:13 +0000 Subject: [PATCH 0252/1635] gpio: thunderx: fix error return code in thunderx_gpio_probe() [ Upstream commit 76e28f5ffed82b1e81a86c4eb8d0420515765620 ] Fix to return error code -ENOMEM from the error handling case instead of 0, as done elsewhere in this function. Fixes: 5a2a30024d8c ("gpio: Add gpio driver support for ThunderX and OCTEON-TX") Signed-off-by: Wei Yongjun Acked-by: David Daney Signed-off-by: Linus Walleij Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/gpio/gpio-thunderx.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/gpio/gpio-thunderx.c b/drivers/gpio/gpio-thunderx.c index 57efb251f9c4..10523ce00c38 100644 --- a/drivers/gpio/gpio-thunderx.c +++ b/drivers/gpio/gpio-thunderx.c @@ -566,8 +566,10 @@ static int thunderx_gpio_probe(struct pci_dev *pdev, txgpio->irqd = irq_domain_create_hierarchy(irq_get_irq_data(txgpio->msix_entries[0].vector)->domain, 0, 0, of_node_to_fwnode(dev->of_node), &thunderx_gpio_irqd_ops, txgpio); - if (!txgpio->irqd) + if (!txgpio->irqd) { + err = -ENOMEM; goto out; + } /* Push on irq_data and the domain for each line. */ for (i = 0; i < ngpio; i++) { -- GitLab From 997901406c0a06cd65bcc70ae922160a4ea884cc Mon Sep 17 00:00:00 2001 From: Jiri Bohac Date: Sat, 6 Jan 2018 02:00:13 +0100 Subject: [PATCH 0253/1635] x86/gart: Exclude GART aperture from vmcore [ Upstream commit 2a3e83c6f96c513f43ce5a8c9034608ea584a255 ] On machines where the GART aperture is mapped over physical RAM /proc/vmcore contains the remapped range and reading it may cause hangs or reboots. In the past, the GART region was added into the resource map, implemented by commit 56dd669a138c ("[PATCH] Insert GART region into resource map") However, inserting the iomem_resource from the early GART code caused resource conflicts with some AGP drivers (bko#72201), which got avoided by reverting the patch in commit 707d4eefbdb3 ("Revert [PATCH] Insert GART region into resource map"). This revert introduced the /proc/vmcore bug. The vmcore ELF header is either prepared by the kernel (when using the kexec_file_load syscall) or by the kexec userspace (when using the kexec_load syscall). Since we no longer have the GART iomem resource, the userspace kexec has no way of knowing which region to exclude from the ELF header. Changes from v1 of this patch: Instead of excluding the aperture from the ELF header, this patch makes /proc/vmcore return zeroes in the second kernel when attempting to read the aperture region. This is done by reusing the gart_oldmem_pfn_is_ram infrastructure originally intended to exclude XEN balooned memory. This works for both, the kexec_file_load and kexec_load syscalls. [Note that the GART region is the same in the first and second kernels: regardless whether the first kernel fixed up the northbridge/bios setting and mapped the aperture over physical memory, the second kernel finds the northbridge properly configured by the first kernel and the aperture never overlaps with e820 memory because the second kernel has a fake e820 map created from the crashkernel memory regions. Thus, the second kernel keeps the aperture address/size as configured by the first kernel.] register_oldmem_pfn_is_ram can only register one callback and returns an error if the callback has been registered already. Since XEN used to be the only user of this function, it never checks the return value. Now that we have more than one user, I added a WARN_ON just in case agp, XEN, or any other future user of register_oldmem_pfn_is_ram were to step on each other's toes. Fixes: 707d4eefbdb3 ("Revert [PATCH] Insert GART region into resource map") Signed-off-by: Jiri Bohac Signed-off-by: Thomas Gleixner Cc: Baoquan He Cc: Toshi Kani Cc: David Airlie Cc: yinghai@kernel.org Cc: joro@8bytes.org Cc: kexec@lists.infradead.org Cc: Borislav Petkov Cc: Bjorn Helgaas Cc: Dave Young Cc: Vivek Goyal Link: https://lkml.kernel.org/r/20180106010013.73suskgxm7lox7g6@dwarf.suse.cz Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/x86/kernel/aperture_64.c | 46 ++++++++++++++++++++++++++++++++++- arch/x86/xen/mmu_hvm.c | 2 +- 2 files changed, 46 insertions(+), 2 deletions(-) diff --git a/arch/x86/kernel/aperture_64.c b/arch/x86/kernel/aperture_64.c index f5d92bc3b884..2c4d5ece7456 100644 --- a/arch/x86/kernel/aperture_64.c +++ b/arch/x86/kernel/aperture_64.c @@ -30,6 +30,7 @@ #include #include #include +#include /* * Using 512M as goal, in case kexec will load kernel_big @@ -56,6 +57,33 @@ int fallback_aper_force __initdata; int fix_aperture __initdata = 1; +#ifdef CONFIG_PROC_VMCORE +/* + * If the first kernel maps the aperture over e820 RAM, the kdump kernel will + * use the same range because it will remain configured in the northbridge. + * Trying to dump this area via /proc/vmcore may crash the machine, so exclude + * it from vmcore. + */ +static unsigned long aperture_pfn_start, aperture_page_count; + +static int gart_oldmem_pfn_is_ram(unsigned long pfn) +{ + return likely((pfn < aperture_pfn_start) || + (pfn >= aperture_pfn_start + aperture_page_count)); +} + +static void exclude_from_vmcore(u64 aper_base, u32 aper_order) +{ + aperture_pfn_start = aper_base >> PAGE_SHIFT; + aperture_page_count = (32 * 1024 * 1024) << aper_order >> PAGE_SHIFT; + WARN_ON(register_oldmem_pfn_is_ram(&gart_oldmem_pfn_is_ram)); +} +#else +static void exclude_from_vmcore(u64 aper_base, u32 aper_order) +{ +} +#endif + /* This code runs before the PCI subsystem is initialized, so just access the northbridge directly. */ @@ -435,8 +463,16 @@ int __init gart_iommu_hole_init(void) out: if (!fix && !fallback_aper_force) { - if (last_aper_base) + if (last_aper_base) { + /* + * If this is the kdump kernel, the first kernel + * may have allocated the range over its e820 RAM + * and fixed up the northbridge + */ + exclude_from_vmcore(last_aper_base, last_aper_order); + return 1; + } return 0; } @@ -473,6 +509,14 @@ int __init gart_iommu_hole_init(void) return 0; } + /* + * If this is the kdump kernel _and_ the first kernel did not + * configure the aperture in the northbridge, this range may + * overlap with the first kernel's memory. We can't access the + * range through vmcore even though it should be part of the dump. + */ + exclude_from_vmcore(aper_alloc, aper_order); + /* Fix up the north bridges */ for (i = 0; i < amd_nb_bus_dev_ranges[i].dev_limit; i++) { int bus, dev_base, dev_limit; diff --git a/arch/x86/xen/mmu_hvm.c b/arch/x86/xen/mmu_hvm.c index 2cfcfe4f6b2a..dd2ad82eee80 100644 --- a/arch/x86/xen/mmu_hvm.c +++ b/arch/x86/xen/mmu_hvm.c @@ -75,6 +75,6 @@ void __init xen_hvm_init_mmu_ops(void) if (is_pagetable_dying_supported()) pv_mmu_ops.exit_mmap = xen_hvm_exit_mmap; #ifdef CONFIG_PROC_VMCORE - register_oldmem_pfn_is_ram(&xen_oldmem_pfn_is_ram); + WARN_ON(register_oldmem_pfn_is_ram(&xen_oldmem_pfn_is_ram)); #endif } -- GitLab From 62eaf7e149a54f62cb6016d9f3915d5b1c95197a Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 11 Jan 2018 15:51:58 +0200 Subject: [PATCH 0254/1635] sdhci: Advertise 2.0v supply on SDIO host controller [ Upstream commit 2a609abe71ca59e4bd7139e161eaca2144ae6f2e ] On Intel Edison the Broadcom Wi-Fi card, which is connected to SDIO, requires 2.0v, while the host, according to Intel Merrifield TRM, supports 1.8v supply only. The card announces itself as mmc2: new ultra high speed DDR50 SDIO card at address 0001 Introduce a custom OCR mask for SDIO host controller on Intel Merrifield and add a special case to sdhci_set_power_noreg() to override 2.0v supply by enforcing 1.8v power choice. Signed-off-by: Andy Shevchenko Acked-by: Adrian Hunter Signed-off-by: Ulf Hansson Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/mmc/host/sdhci-pci-core.c | 2 ++ drivers/mmc/host/sdhci.c | 7 +++++++ 2 files changed, 9 insertions(+) diff --git a/drivers/mmc/host/sdhci-pci-core.c b/drivers/mmc/host/sdhci-pci-core.c index 070f5da06fd2..5bedf4b7f0f7 100644 --- a/drivers/mmc/host/sdhci-pci-core.c +++ b/drivers/mmc/host/sdhci-pci-core.c @@ -806,6 +806,8 @@ static int intel_mrfld_mmc_probe_slot(struct sdhci_pci_slot *slot) slot->host->quirks2 |= SDHCI_QUIRK2_NO_1_8_V; break; case INTEL_MRFLD_SDIO: + /* Advertise 2.0v for compatibility with the SDIO card's OCR */ + slot->host->ocr_mask = MMC_VDD_20_21 | MMC_VDD_165_195; slot->host->mmc->caps |= MMC_CAP_NONREMOVABLE | MMC_CAP_POWER_OFF_CARD; break; diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 90cc1977b792..d35deb79965d 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -1470,6 +1470,13 @@ void sdhci_set_power_noreg(struct sdhci_host *host, unsigned char mode, if (mode != MMC_POWER_OFF) { switch (1 << vdd) { case MMC_VDD_165_195: + /* + * Without a regulator, SDHCI does not support 2.0v + * so we only get here if the driver deliberately + * added the 2.0v range to ocr_avail. Map it to 1.8v + * for the purpose of turning on the power. + */ + case MMC_VDD_20_21: pwr = SDHCI_POWER_180; break; case MMC_VDD_29_30: -- GitLab From c427d7e44a32f2fbb2103007cf07f592a215947a Mon Sep 17 00:00:00 2001 From: Nathan Fontenot Date: Wed, 10 Jan 2018 10:40:09 -0600 Subject: [PATCH 0255/1635] ibmvnic: Don't handle RX interrupts when not up. [ Upstream commit 09fb35ead58cd557aa9b20576d15816bc91a4deb ] Initiating a kdump via the command line can cause a pending interrupt to be handled by the ibmvnic driver when initializing the sub-CRQ irqs during driver initialization. NIP [d000000000ca34f0] ibmvnic_interrupt_rx+0x40/0xd0 [ibmvnic] LR [c000000008132ef0] __handle_irq_event_percpu+0xa0/0x2f0 Call Trace: [c000000047fcfde0] [c000000008132ef0] __handle_irq_event_percpu+0xa0/0x2f0 [c000000047fcfea0] [c00000000813317c] handle_irq_event_percpu+0x3c/0x90 [c000000047fcfee0] [c00000000813323c] handle_irq_event+0x6c/0xd0 [c000000047fcff10] [c0000000081385e0] handle_fasteoi_irq+0xf0/0x250 [c000000047fcff40] [c0000000081320a0] generic_handle_irq+0x50/0x80 [c000000047fcff60] [c000000008014984] __do_irq+0x84/0x1d0 [c000000047fcff90] [c000000008027564] call_do_irq+0x14/0x24 [c00000003c92af00] [c000000008014b70] do_IRQ+0xa0/0x120 [c00000003c92af50] [c000000008002594] hardware_interrupt_common+0x114/0x180 Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/ibm/ibmvnic.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/net/ethernet/ibm/ibmvnic.c b/drivers/net/ethernet/ibm/ibmvnic.c index 3b0db01ead1f..3ae02b0620bc 100644 --- a/drivers/net/ethernet/ibm/ibmvnic.c +++ b/drivers/net/ethernet/ibm/ibmvnic.c @@ -2209,6 +2209,12 @@ static irqreturn_t ibmvnic_interrupt_rx(int irq, void *instance) struct ibmvnic_sub_crq_queue *scrq = instance; struct ibmvnic_adapter *adapter = scrq->adapter; + /* When booting a kdump kernel we can hit pending interrupts + * prior to completing driver initialization. + */ + if (unlikely(adapter->state != VNIC_OPEN)) + return IRQ_NONE; + adapter->rx_stats_buffers[scrq->scrq_num].interrupts++; if (napi_schedule_prep(&adapter->napi[scrq->scrq_num])) { -- GitLab From 88f6f0490f8ca3683e51b9fc0f901b0f2424d07f Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 12 Jan 2018 00:36:48 -0800 Subject: [PATCH 0256/1635] Input: goodix - disable IRQs while suspended [ Upstream commit faec44b6838312484d63e82286087cf2d5ebb891 ] We should not try to do any i2c transfers before the controller is resumed (which happens before our resume method gets called). So we need to disable our IRQ while suspended to enforce this. The code paths for devices with GPIOs for the int and reset pins already disable the IRQ the through goodix_free_irq(). This commit also disables the IRQ while suspended for devices without GPIOs for the int and reset pins. This fixes the i2c bus sometimes getting stuck after a suspend/resume causing the touchscreen to sometimes not work after a suspend/resume. This has been tested on a GPD pocked device. BugLink: https://github.com/nexus511/gpd-ubuntu-packages/issues/10 BugLink: https://www.reddit.com/r/GPDPocket/comments/7niut2/fix_for_broken_touch_after_resume_all_linux/ Tested-by: Hans de Goede Signed-off-by: Hans de Goede Reviewed-by: Bastien Nocera Signed-off-by: Dmitry Torokhov Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/input/touchscreen/goodix.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/input/touchscreen/goodix.c b/drivers/input/touchscreen/goodix.c index b3bbad7d2282..5dafafad6351 100644 --- a/drivers/input/touchscreen/goodix.c +++ b/drivers/input/touchscreen/goodix.c @@ -808,8 +808,10 @@ static int __maybe_unused goodix_suspend(struct device *dev) int error; /* We need gpio pins to suspend/resume */ - if (!ts->gpiod_int || !ts->gpiod_rst) + if (!ts->gpiod_int || !ts->gpiod_rst) { + disable_irq(client->irq); return 0; + } wait_for_completion(&ts->firmware_loading_complete); @@ -849,8 +851,10 @@ static int __maybe_unused goodix_resume(struct device *dev) struct goodix_ts_data *ts = i2c_get_clientdata(client); int error; - if (!ts->gpiod_int || !ts->gpiod_rst) + if (!ts->gpiod_int || !ts->gpiod_rst) { + enable_irq(client->irq); return 0; + } /* * Exit sleep mode by outputting HIGH level to INT pin -- GitLab From 3847b9e016dff8d927d703d447915fc8de1d3190 Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Thu, 11 Jan 2018 21:39:20 +0100 Subject: [PATCH 0257/1635] mtd: mtd_oobtest: Handle bitflips during reads [ Upstream commit 12663b442e5ac5aa3d6097cd3f287c71ba46d26e ] Reads from NAND devices usually trigger bitflips, this is an expected behavior. While bitflips are under a given threshold, the MTD core returns 0. However, when the number of corrected bitflips is above this same threshold, -EUCLEAN is returned to inform the upper layer that this block is slightly dying and soon the ECC engine will be overtaken so actions should be taken to move the data out of it. This particular condition should not be treated like an error and the test should continue. Signed-off-by: Miquel Raynal Signed-off-by: Boris Brezillon Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/mtd/tests/oobtest.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/drivers/mtd/tests/oobtest.c b/drivers/mtd/tests/oobtest.c index 1cb3f7758fb6..766b2c385682 100644 --- a/drivers/mtd/tests/oobtest.c +++ b/drivers/mtd/tests/oobtest.c @@ -193,6 +193,9 @@ static int verify_eraseblock(int ebnum) ops.datbuf = NULL; ops.oobbuf = readbuf; err = mtd_read_oob(mtd, addr, &ops); + if (mtd_is_bitflip(err)) + err = 0; + if (err || ops.oobretlen != use_len) { pr_err("error: readoob failed at %#llx\n", (long long)addr); @@ -227,6 +230,9 @@ static int verify_eraseblock(int ebnum) ops.datbuf = NULL; ops.oobbuf = readbuf; err = mtd_read_oob(mtd, addr, &ops); + if (mtd_is_bitflip(err)) + err = 0; + if (err || ops.oobretlen != mtd->oobavail) { pr_err("error: readoob failed at %#llx\n", (long long)addr); @@ -286,6 +292,9 @@ static int verify_eraseblock_in_one_go(int ebnum) /* read entire block's OOB at one go */ err = mtd_read_oob(mtd, addr, &ops); + if (mtd_is_bitflip(err)) + err = 0; + if (err || ops.oobretlen != len) { pr_err("error: readoob failed at %#llx\n", (long long)addr); @@ -527,6 +536,9 @@ static int __init mtd_oobtest_init(void) pr_info("attempting to start read past end of OOB\n"); pr_info("an error is expected...\n"); err = mtd_read_oob(mtd, addr0, &ops); + if (mtd_is_bitflip(err)) + err = 0; + if (err) { pr_info("error occurred as expected\n"); err = 0; @@ -571,6 +583,9 @@ static int __init mtd_oobtest_init(void) pr_info("attempting to read past end of device\n"); pr_info("an error is expected...\n"); err = mtd_read_oob(mtd, mtd->size - mtd->writesize, &ops); + if (mtd_is_bitflip(err)) + err = 0; + if (err) { pr_info("error occurred as expected\n"); err = 0; @@ -615,6 +630,9 @@ static int __init mtd_oobtest_init(void) pr_info("attempting to read past end of device\n"); pr_info("an error is expected...\n"); err = mtd_read_oob(mtd, mtd->size - mtd->writesize, &ops); + if (mtd_is_bitflip(err)) + err = 0; + if (err) { pr_info("error occurred as expected\n"); err = 0; @@ -684,6 +702,9 @@ static int __init mtd_oobtest_init(void) ops.datbuf = NULL; ops.oobbuf = readbuf; err = mtd_read_oob(mtd, addr, &ops); + if (mtd_is_bitflip(err)) + err = 0; + if (err) goto out; if (memcmpshow(addr, readbuf, writebuf, -- GitLab From 7cae67e31292ea0c257e944ba23854d089e860f6 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 3 Jan 2018 23:39:27 +0100 Subject: [PATCH 0258/1635] crypto: aes-generic - build with -Os on gcc-7+ [ Upstream commit 148b974deea927f5dbb6c468af2707b488bfa2de ] While testing other changes, I discovered that gcc-7.2.1 produces badly optimized code for aes_encrypt/aes_decrypt. This is especially true when CONFIG_UBSAN_SANITIZE_ALL is enabled, where it leads to extremely large stack usage that in turn might cause kernel stack overflows: crypto/aes_generic.c: In function 'aes_encrypt': crypto/aes_generic.c:1371:1: warning: the frame size of 4880 bytes is larger than 2048 bytes [-Wframe-larger-than=] crypto/aes_generic.c: In function 'aes_decrypt': crypto/aes_generic.c:1441:1: warning: the frame size of 4864 bytes is larger than 2048 bytes [-Wframe-larger-than=] I verified that this problem exists on all architectures that are supported by gcc-7.2, though arm64 in particular is less affected than the others. I also found that gcc-7.1 and gcc-8 do not show the extreme stack usage but still produce worse code than earlier versions for this file, apparently because of optimization passes that generally provide a substantial improvement in object code quality but understandably fail to find any shortcuts in the AES algorithm. Possible workarounds include a) disabling -ftree-pre and -ftree-sra optimizations, this was an earlier patch I tried, which reliably fixed the stack usage, but caused a serious performance regression in some versions, as later testing found. b) disabling UBSAN on this file or all ciphers, as suggested by Ard Biesheuvel. This would lead to massively better crypto performance in UBSAN-enabled kernels and avoid the stack usage, but there is a concern over whether we should exclude arbitrary files from UBSAN at all. c) Forcing the optimization level in a different way. Similar to a), but rather than deselecting specific optimization stages, this now uses "gcc -Os" for this file, regardless of the CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE/SIZE option. This is a reliable workaround for the stack consumption on all architecture, and I've retested the performance results now on x86, cycles/byte (lower is better) for cbc(aes-generic) with 256 bit keys: -O2 -Os gcc-6.3.1 14.9 15.1 gcc-7.0.1 14.7 15.3 gcc-7.1.1 15.3 14.7 gcc-7.2.1 16.8 15.9 gcc-8.0.0 15.5 15.6 This implements the option c) by enabling forcing -Os on all compiler versions starting with gcc-7.1. As a workaround for PR83356, it would only be needed for gcc-7.2+ with UBSAN enabled, but since it also shows better performance on gcc-7.1 without UBSAN, it seems appropriate to use the faster version here as well. Side note: during testing, I also played with the AES code in libressl, which had a similar performance regression from gcc-6 to gcc-7.2, but was three times slower overall. It might be interesting to investigate that further and possibly port the Linux implementation into that. Link: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=83356 Link: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=83651 Cc: Richard Biener Cc: Jakub Jelinek Cc: Ard Biesheuvel Signed-off-by: Arnd Bergmann Acked-by: Ard Biesheuvel Signed-off-by: Herbert Xu Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- crypto/Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/crypto/Makefile b/crypto/Makefile index da190be60ce2..adaf2c63baeb 100644 --- a/crypto/Makefile +++ b/crypto/Makefile @@ -98,6 +98,7 @@ obj-$(CONFIG_CRYPTO_TWOFISH_COMMON) += twofish_common.o obj-$(CONFIG_CRYPTO_SERPENT) += serpent_generic.o CFLAGS_serpent_generic.o := $(call cc-option,-fsched-pressure) # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=79149 obj-$(CONFIG_CRYPTO_AES) += aes_generic.o +CFLAGS_aes_generic.o := $(call cc-ifversion, -ge, 0701, -Os) # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=83356 obj-$(CONFIG_CRYPTO_AES_TI) += aes_ti.o obj-$(CONFIG_CRYPTO_CAMELLIA) += camellia_generic.o obj-$(CONFIG_CRYPTO_CAST_COMMON) += cast_common.o -- GitLab From 6a88a999c45db9500ab16656a9a15fa601403e17 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Tue, 9 Jan 2018 14:39:23 +0100 Subject: [PATCH 0259/1635] perf tools: Fix copyfile_offset update of output offset [ Upstream commit fa1195ccc0af2d121abe0fe266a1caee8c265eea ] We need to increase output offset in each iteration, not decrease it as we currently do. I guess we were lucky to finish in most cases in first iteration, so the bug never showed. However it shows a lot when working with big (~4GB) size data. Signed-off-by: Jiri Olsa Cc: Alexander Shishkin Cc: Andi Kleen Cc: David Ahern Cc: Namhyung Kim Cc: Peter Zijlstra Fixes: 9c9f5a2f1944 ("perf tools: Introduce copyfile_offset() function") Link: http://lkml.kernel.org/r/20180109133923.25406-1-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- tools/perf/util/util.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c index 3687b720327a..cc57c246eade 100644 --- a/tools/perf/util/util.c +++ b/tools/perf/util/util.c @@ -196,7 +196,7 @@ int copyfile_offset(int ifd, loff_t off_in, int ofd, loff_t off_out, u64 size) size -= ret; off_in += ret; - off_out -= ret; + off_out += ret; } munmap(ptr, off_in + size); -- GitLab From bc166ca4234c241ae28b13bac8583d04bcdf9a9e Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Tue, 28 Nov 2017 12:40:33 -0600 Subject: [PATCH 0260/1635] tcmu: release blocks for partially setup cmds [ Upstream commit 810b8153c4243d2012a6ec002ddd3bbc9a9ae8c2 ] If we cannot setup a cmd because we run out of ring space or global pages release the blocks before sleeping. This prevents a deadlock where dev0 has waiting_blocks set and needs N blocks, but dev1 to devX have each allocated N / X blocks and also hit the global block limit so they went to sleep. find_free_blocks is not able to take the sleeping dev's blocks becaause their waiting_blocks is set and even if it was not the block returned by find_last_bit could equal dbi_max. The latter will probably never happen because DATA_BLOCK_BITS is so high but in the next patches DATA_BLOCK_BITS and TCMU_GLOBAL_MAX_BLOCKS will be settable so it might be lower and could happen. Signed-off-by: Mike Christie Signed-off-by: Nicholas Bellinger Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/target/target_core_user.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/target/target_core_user.c b/drivers/target/target_core_user.c index 942d094269fb..c4a5fb6f038f 100644 --- a/drivers/target/target_core_user.c +++ b/drivers/target/target_core_user.c @@ -796,6 +796,13 @@ tcmu_queue_cmd_ring(struct tcmu_cmd *tcmu_cmd) int ret; DEFINE_WAIT(__wait); + /* + * Don't leave commands partially setup because the unmap + * thread might need the blocks to make forward progress. + */ + tcmu_cmd_free_data(tcmu_cmd, tcmu_cmd->dbi_cur); + tcmu_cmd_reset_dbi_cur(tcmu_cmd); + prepare_to_wait(&udev->wait_cmdr, &__wait, TASK_INTERRUPTIBLE); pr_debug("sleeping for ring space\n"); -- GitLab From 5dff63583f0d86f2923a871d77c71703845d2b1d Mon Sep 17 00:00:00 2001 From: Alexey Khoroshilov Date: Sat, 30 Dec 2017 01:05:21 +0300 Subject: [PATCH 0261/1635] thermal: int3400_thermal: fix error handling in int3400_thermal_probe() [ Upstream commit 0be86969ae385c5c944286bd9f66068525de15ee ] There are resources that are not dealocated on failure path in int3400_thermal_probe(). Found by Linux Driver Verification project (linuxtesting.org). Signed-off-by: Alexey Khoroshilov Signed-off-by: Zhang Rui Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/thermal/int340x_thermal/int3400_thermal.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/drivers/thermal/int340x_thermal/int3400_thermal.c b/drivers/thermal/int340x_thermal/int3400_thermal.c index 8ee38f55c7f3..43b90fd577e4 100644 --- a/drivers/thermal/int340x_thermal/int3400_thermal.c +++ b/drivers/thermal/int340x_thermal/int3400_thermal.c @@ -319,17 +319,21 @@ static int int3400_thermal_probe(struct platform_device *pdev) result = sysfs_create_group(&pdev->dev.kobj, &uuid_attribute_group); if (result) - goto free_zone; + goto free_rel_misc; result = acpi_install_notify_handler( priv->adev->handle, ACPI_DEVICE_NOTIFY, int3400_notify, (void *)priv); if (result) - goto free_zone; + goto free_sysfs; return 0; -free_zone: +free_sysfs: + sysfs_remove_group(&pdev->dev.kobj, &uuid_attribute_group); +free_rel_misc: + if (!priv->rel_misc_dev_res) + acpi_thermal_rel_misc_device_remove(priv->adev->handle); thermal_zone_device_unregister(priv->thermal); free_art_trt: kfree(priv->trts); -- GitLab From f1b46925f59e319e015019f250e170e7a12c548f Mon Sep 17 00:00:00 2001 From: Josh Poimboeuf Date: Thu, 22 Mar 2018 13:00:37 -0500 Subject: [PATCH 0262/1635] objtool: Add Clang support commit 3c1f05835cbf9fdfe60b81c718d82ceb94b6c55e upstream. Since the ORC unwinder was made the default on x86_64, Clang-built defconfig kernels have triggered some new objtool warnings: drivers/gpu/drm/i915/i915_gpu_error.o: warning: objtool: i915_error_printf()+0x6c: return with modified stack frame drivers/gpu/drm/i915/intel_display.o: warning: objtool: pipe_config_err()+0xa6: return with modified stack frame The problem is that objtool has never seen clang-built binaries before. Shockingly enough, objtool is apparently able to follow the code flow mostly fine, except for one instruction sequence. Instead of a LEAVE instruction, clang restores RSP and RBP the long way: 67c: 48 89 ec mov %rbp,%rsp 67f: 5d pop %rbp Teach objtool about this new code sequence. Reported-and-test-by: Matthias Kaehlcke Signed-off-by: Josh Poimboeuf Cc: Linus Torvalds Cc: Matthias Kaehlcke Cc: Peter Zijlstra Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/fce88ce81c356eedcae7f00ed349cfaddb3363cc.1521741586.git.jpoimboe@redhat.com Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman --- tools/objtool/check.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/tools/objtool/check.c b/tools/objtool/check.c index 9d01d0b1084e..c8b8b7101c6f 100644 --- a/tools/objtool/check.c +++ b/tools/objtool/check.c @@ -1385,6 +1385,17 @@ static int update_insn_state(struct instruction *insn, struct insn_state *state) state->vals[op->dest.reg].offset = -state->stack_size; } + else if (op->src.reg == CFI_BP && op->dest.reg == CFI_SP && + cfa->base == CFI_BP) { + + /* + * mov %rbp, %rsp + * + * Restore the original stack pointer (Clang). + */ + state->stack_size = -state->regs[CFI_BP].offset; + } + else if (op->dest.reg == cfa->base) { /* mov %reg, %rsp */ -- GitLab From b6a11be5c4335a28a651c2752eeec5aa00b4a88f Mon Sep 17 00:00:00 2001 From: Ard Biesheuvel Date: Tue, 21 Nov 2017 13:40:17 +0000 Subject: [PATCH 0263/1635] crypto: arm64/aes-ce-cipher - move assembler code to .S file commit 019cd46984d04703a39924178f503a98436ac0d7 upstream. Most crypto drivers involving kernel mode NEON take care to put the code that actually touches the NEON register file in a separate compilation unit, to prevent the compiler from reordering code that preserves or restores the NEON context with code that may corrupt it. This is necessary because we currently have no way to express the restrictions imposed upon use of the NEON in kernel mode in a way that the compiler understands. However, in the case of aes-ce-cipher, it did not seem unreasonable to deviate from this rule, given how it does not seem possible for the compiler to reorder cross object function calls with asm blocks whose in- and output constraints reflect that it reads from and writes to memory. Now that LTO is being proposed for the arm64 kernel, it is time to revisit this. The link time optimization may replace the function calls to kernel_neon_begin() and kernel_neon_end() with instantiations of the IR that make up its implementation, allowing further reordering with the asm block. So let's clean this up, and move the asm() blocks into a separate .S file. Signed-off-by: Ard Biesheuvel Reviewed-By: Nick Desaulniers Signed-off-by: Herbert Xu Cc: Matthias Kaehlcke Signed-off-by: Greg Kroah-Hartman --- arch/arm64/crypto/Makefile | 2 +- arch/arm64/crypto/aes-ce-core.S | 87 +++++++++++++ .../crypto/{aes-ce-cipher.c => aes-ce-glue.c} | 115 ++---------------- 3 files changed, 100 insertions(+), 104 deletions(-) create mode 100644 arch/arm64/crypto/aes-ce-core.S rename arch/arm64/crypto/{aes-ce-cipher.c => aes-ce-glue.c} (62%) diff --git a/arch/arm64/crypto/Makefile b/arch/arm64/crypto/Makefile index 12fd81af1d1c..93dbf4889eb6 100644 --- a/arch/arm64/crypto/Makefile +++ b/arch/arm64/crypto/Makefile @@ -24,7 +24,7 @@ obj-$(CONFIG_CRYPTO_CRC32_ARM64_CE) += crc32-ce.o crc32-ce-y:= crc32-ce-core.o crc32-ce-glue.o obj-$(CONFIG_CRYPTO_AES_ARM64_CE) += aes-ce-cipher.o -CFLAGS_aes-ce-cipher.o += -march=armv8-a+crypto +aes-ce-cipher-y := aes-ce-core.o aes-ce-glue.o obj-$(CONFIG_CRYPTO_AES_ARM64_CE_CCM) += aes-ce-ccm.o aes-ce-ccm-y := aes-ce-ccm-glue.o aes-ce-ccm-core.o diff --git a/arch/arm64/crypto/aes-ce-core.S b/arch/arm64/crypto/aes-ce-core.S new file mode 100644 index 000000000000..8efdfdade393 --- /dev/null +++ b/arch/arm64/crypto/aes-ce-core.S @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2013 - 2017 Linaro Ltd + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include + + .arch armv8-a+crypto + +ENTRY(__aes_ce_encrypt) + sub w3, w3, #2 + ld1 {v0.16b}, [x2] + ld1 {v1.4s}, [x0], #16 + cmp w3, #10 + bmi 0f + bne 3f + mov v3.16b, v1.16b + b 2f +0: mov v2.16b, v1.16b + ld1 {v3.4s}, [x0], #16 +1: aese v0.16b, v2.16b + aesmc v0.16b, v0.16b +2: ld1 {v1.4s}, [x0], #16 + aese v0.16b, v3.16b + aesmc v0.16b, v0.16b +3: ld1 {v2.4s}, [x0], #16 + subs w3, w3, #3 + aese v0.16b, v1.16b + aesmc v0.16b, v0.16b + ld1 {v3.4s}, [x0], #16 + bpl 1b + aese v0.16b, v2.16b + eor v0.16b, v0.16b, v3.16b + st1 {v0.16b}, [x1] + ret +ENDPROC(__aes_ce_encrypt) + +ENTRY(__aes_ce_decrypt) + sub w3, w3, #2 + ld1 {v0.16b}, [x2] + ld1 {v1.4s}, [x0], #16 + cmp w3, #10 + bmi 0f + bne 3f + mov v3.16b, v1.16b + b 2f +0: mov v2.16b, v1.16b + ld1 {v3.4s}, [x0], #16 +1: aesd v0.16b, v2.16b + aesimc v0.16b, v0.16b +2: ld1 {v1.4s}, [x0], #16 + aesd v0.16b, v3.16b + aesimc v0.16b, v0.16b +3: ld1 {v2.4s}, [x0], #16 + subs w3, w3, #3 + aesd v0.16b, v1.16b + aesimc v0.16b, v0.16b + ld1 {v3.4s}, [x0], #16 + bpl 1b + aesd v0.16b, v2.16b + eor v0.16b, v0.16b, v3.16b + st1 {v0.16b}, [x1] + ret +ENDPROC(__aes_ce_decrypt) + +/* + * __aes_ce_sub() - use the aese instruction to perform the AES sbox + * substitution on each byte in 'input' + */ +ENTRY(__aes_ce_sub) + dup v1.4s, w0 + movi v0.16b, #0 + aese v0.16b, v1.16b + umov w0, v0.s[0] + ret +ENDPROC(__aes_ce_sub) + +ENTRY(__aes_ce_invert) + ld1 {v0.4s}, [x1] + aesimc v1.16b, v0.16b + st1 {v1.4s}, [x0] + ret +ENDPROC(__aes_ce_invert) diff --git a/arch/arm64/crypto/aes-ce-cipher.c b/arch/arm64/crypto/aes-ce-glue.c similarity index 62% rename from arch/arm64/crypto/aes-ce-cipher.c rename to arch/arm64/crypto/aes-ce-glue.c index 6a75cd75ed11..e6b3227bbf57 100644 --- a/arch/arm64/crypto/aes-ce-cipher.c +++ b/arch/arm64/crypto/aes-ce-glue.c @@ -29,6 +29,13 @@ struct aes_block { u8 b[AES_BLOCK_SIZE]; }; +asmlinkage void __aes_ce_encrypt(u32 *rk, u8 *out, const u8 *in, int rounds); +asmlinkage void __aes_ce_decrypt(u32 *rk, u8 *out, const u8 *in, int rounds); + +asmlinkage u32 __aes_ce_sub(u32 l); +asmlinkage void __aes_ce_invert(struct aes_block *out, + const struct aes_block *in); + static int num_rounds(struct crypto_aes_ctx *ctx) { /* @@ -44,10 +51,6 @@ static int num_rounds(struct crypto_aes_ctx *ctx) static void aes_cipher_encrypt(struct crypto_tfm *tfm, u8 dst[], u8 const src[]) { struct crypto_aes_ctx *ctx = crypto_tfm_ctx(tfm); - struct aes_block *out = (struct aes_block *)dst; - struct aes_block const *in = (struct aes_block *)src; - void *dummy0; - int dummy1; if (!may_use_simd()) { __aes_arm64_encrypt(ctx->key_enc, dst, src, num_rounds(ctx)); @@ -55,49 +58,13 @@ static void aes_cipher_encrypt(struct crypto_tfm *tfm, u8 dst[], u8 const src[]) } kernel_neon_begin(); - - __asm__(" ld1 {v0.16b}, %[in] ;" - " ld1 {v1.4s}, [%[key]], #16 ;" - " cmp %w[rounds], #10 ;" - " bmi 0f ;" - " bne 3f ;" - " mov v3.16b, v1.16b ;" - " b 2f ;" - "0: mov v2.16b, v1.16b ;" - " ld1 {v3.4s}, [%[key]], #16 ;" - "1: aese v0.16b, v2.16b ;" - " aesmc v0.16b, v0.16b ;" - "2: ld1 {v1.4s}, [%[key]], #16 ;" - " aese v0.16b, v3.16b ;" - " aesmc v0.16b, v0.16b ;" - "3: ld1 {v2.4s}, [%[key]], #16 ;" - " subs %w[rounds], %w[rounds], #3 ;" - " aese v0.16b, v1.16b ;" - " aesmc v0.16b, v0.16b ;" - " ld1 {v3.4s}, [%[key]], #16 ;" - " bpl 1b ;" - " aese v0.16b, v2.16b ;" - " eor v0.16b, v0.16b, v3.16b ;" - " st1 {v0.16b}, %[out] ;" - - : [out] "=Q"(*out), - [key] "=r"(dummy0), - [rounds] "=r"(dummy1) - : [in] "Q"(*in), - "1"(ctx->key_enc), - "2"(num_rounds(ctx) - 2) - : "cc"); - + __aes_ce_encrypt(ctx->key_enc, dst, src, num_rounds(ctx)); kernel_neon_end(); } static void aes_cipher_decrypt(struct crypto_tfm *tfm, u8 dst[], u8 const src[]) { struct crypto_aes_ctx *ctx = crypto_tfm_ctx(tfm); - struct aes_block *out = (struct aes_block *)dst; - struct aes_block const *in = (struct aes_block *)src; - void *dummy0; - int dummy1; if (!may_use_simd()) { __aes_arm64_decrypt(ctx->key_dec, dst, src, num_rounds(ctx)); @@ -105,62 +72,10 @@ static void aes_cipher_decrypt(struct crypto_tfm *tfm, u8 dst[], u8 const src[]) } kernel_neon_begin(); - - __asm__(" ld1 {v0.16b}, %[in] ;" - " ld1 {v1.4s}, [%[key]], #16 ;" - " cmp %w[rounds], #10 ;" - " bmi 0f ;" - " bne 3f ;" - " mov v3.16b, v1.16b ;" - " b 2f ;" - "0: mov v2.16b, v1.16b ;" - " ld1 {v3.4s}, [%[key]], #16 ;" - "1: aesd v0.16b, v2.16b ;" - " aesimc v0.16b, v0.16b ;" - "2: ld1 {v1.4s}, [%[key]], #16 ;" - " aesd v0.16b, v3.16b ;" - " aesimc v0.16b, v0.16b ;" - "3: ld1 {v2.4s}, [%[key]], #16 ;" - " subs %w[rounds], %w[rounds], #3 ;" - " aesd v0.16b, v1.16b ;" - " aesimc v0.16b, v0.16b ;" - " ld1 {v3.4s}, [%[key]], #16 ;" - " bpl 1b ;" - " aesd v0.16b, v2.16b ;" - " eor v0.16b, v0.16b, v3.16b ;" - " st1 {v0.16b}, %[out] ;" - - : [out] "=Q"(*out), - [key] "=r"(dummy0), - [rounds] "=r"(dummy1) - : [in] "Q"(*in), - "1"(ctx->key_dec), - "2"(num_rounds(ctx) - 2) - : "cc"); - + __aes_ce_decrypt(ctx->key_dec, dst, src, num_rounds(ctx)); kernel_neon_end(); } -/* - * aes_sub() - use the aese instruction to perform the AES sbox substitution - * on each byte in 'input' - */ -static u32 aes_sub(u32 input) -{ - u32 ret; - - __asm__("dup v1.4s, %w[in] ;" - "movi v0.16b, #0 ;" - "aese v0.16b, v1.16b ;" - "umov %w[out], v0.4s[0] ;" - - : [out] "=r"(ret) - : [in] "r"(input) - : "v0","v1"); - - return ret; -} - int ce_aes_expandkey(struct crypto_aes_ctx *ctx, const u8 *in_key, unsigned int key_len) { @@ -189,7 +104,7 @@ int ce_aes_expandkey(struct crypto_aes_ctx *ctx, const u8 *in_key, u32 *rki = ctx->key_enc + (i * kwords); u32 *rko = rki + kwords; - rko[0] = ror32(aes_sub(rki[kwords - 1]), 8) ^ rcon[i] ^ rki[0]; + rko[0] = ror32(__aes_ce_sub(rki[kwords - 1]), 8) ^ rcon[i] ^ rki[0]; rko[1] = rko[0] ^ rki[1]; rko[2] = rko[1] ^ rki[2]; rko[3] = rko[2] ^ rki[3]; @@ -202,7 +117,7 @@ int ce_aes_expandkey(struct crypto_aes_ctx *ctx, const u8 *in_key, } else if (key_len == AES_KEYSIZE_256) { if (i >= 6) break; - rko[4] = aes_sub(rko[3]) ^ rki[4]; + rko[4] = __aes_ce_sub(rko[3]) ^ rki[4]; rko[5] = rko[4] ^ rki[5]; rko[6] = rko[5] ^ rki[6]; rko[7] = rko[6] ^ rki[7]; @@ -221,13 +136,7 @@ int ce_aes_expandkey(struct crypto_aes_ctx *ctx, const u8 *in_key, key_dec[0] = key_enc[j]; for (i = 1, j--; j > 0; i++, j--) - __asm__("ld1 {v0.4s}, %[in] ;" - "aesimc v1.16b, v0.16b ;" - "st1 {v1.4s}, %[out] ;" - - : [out] "=Q"(key_dec[i]) - : [in] "Q"(key_enc[j]) - : "v0","v1"); + __aes_ce_invert(key_dec + i, key_enc + j); key_dec[i] = key_enc[0]; kernel_neon_end(); -- GitLab From 962e6b2d16653e55595f1c790e1094413c5ac5e4 Mon Sep 17 00:00:00 2001 From: Borislav Petkov Date: Fri, 16 Feb 2018 12:26:38 +0100 Subject: [PATCH 0264/1635] x86/microcode: Propagate return value from updating functions commit 3f1f576a195aa266813cbd4ca70291deb61e0129 upstream. ... so that callers can know when microcode was updated and act accordingly. Tested-by: Ashok Raj Signed-off-by: Borislav Petkov Reviewed-by: Ashok Raj Cc: Andy Lutomirski Cc: Arjan van de Ven Cc: Borislav Petkov Cc: Dan Williams Cc: Dave Hansen Cc: David Woodhouse Cc: Greg Kroah-Hartman Cc: Josh Poimboeuf Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/20180216112640.11554-2-bp@alien8.de Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman --- arch/x86/include/asm/microcode.h | 9 ++++++-- arch/x86/kernel/cpu/microcode/amd.c | 10 ++++---- arch/x86/kernel/cpu/microcode/core.c | 33 ++++++++++++++------------- arch/x86/kernel/cpu/microcode/intel.c | 10 ++++---- 4 files changed, 34 insertions(+), 28 deletions(-) diff --git a/arch/x86/include/asm/microcode.h b/arch/x86/include/asm/microcode.h index 55520cec8b27..7fb1047d61c7 100644 --- a/arch/x86/include/asm/microcode.h +++ b/arch/x86/include/asm/microcode.h @@ -37,7 +37,12 @@ struct cpu_signature { struct device; -enum ucode_state { UCODE_ERROR, UCODE_OK, UCODE_NFOUND }; +enum ucode_state { + UCODE_OK = 0, + UCODE_UPDATED, + UCODE_NFOUND, + UCODE_ERROR, +}; struct microcode_ops { enum ucode_state (*request_microcode_user) (int cpu, @@ -54,7 +59,7 @@ struct microcode_ops { * are being called. * See also the "Synchronization" section in microcode_core.c. */ - int (*apply_microcode) (int cpu); + enum ucode_state (*apply_microcode) (int cpu); int (*collect_cpu_info) (int cpu, struct cpu_signature *csig); }; diff --git a/arch/x86/kernel/cpu/microcode/amd.c b/arch/x86/kernel/cpu/microcode/amd.c index 330b8462d426..a998e1a7d46f 100644 --- a/arch/x86/kernel/cpu/microcode/amd.c +++ b/arch/x86/kernel/cpu/microcode/amd.c @@ -498,7 +498,7 @@ static unsigned int verify_patch_size(u8 family, u32 patch_size, return patch_size; } -static int apply_microcode_amd(int cpu) +static enum ucode_state apply_microcode_amd(int cpu) { struct cpuinfo_x86 *c = &cpu_data(cpu); struct microcode_amd *mc_amd; @@ -512,7 +512,7 @@ static int apply_microcode_amd(int cpu) p = find_patch(cpu); if (!p) - return 0; + return UCODE_NFOUND; mc_amd = p->data; uci->mc = p->data; @@ -523,13 +523,13 @@ static int apply_microcode_amd(int cpu) if (rev >= mc_amd->hdr.patch_id) { c->microcode = rev; uci->cpu_sig.rev = rev; - return 0; + return UCODE_OK; } if (__apply_microcode_amd(mc_amd)) { pr_err("CPU%d: update failed for patch_level=0x%08x\n", cpu, mc_amd->hdr.patch_id); - return -1; + return UCODE_ERROR; } pr_info("CPU%d: new patch_level=0x%08x\n", cpu, mc_amd->hdr.patch_id); @@ -537,7 +537,7 @@ static int apply_microcode_amd(int cpu) uci->cpu_sig.rev = mc_amd->hdr.patch_id; c->microcode = mc_amd->hdr.patch_id; - return 0; + return UCODE_UPDATED; } static int install_equiv_cpu_table(const u8 *buf) diff --git a/arch/x86/kernel/cpu/microcode/core.c b/arch/x86/kernel/cpu/microcode/core.c index e4fc595cd6ea..7c423269ac49 100644 --- a/arch/x86/kernel/cpu/microcode/core.c +++ b/arch/x86/kernel/cpu/microcode/core.c @@ -374,7 +374,7 @@ static int collect_cpu_info(int cpu) } struct apply_microcode_ctx { - int err; + enum ucode_state err; }; static void apply_microcode_local(void *arg) @@ -489,31 +489,29 @@ static void __exit microcode_dev_exit(void) /* fake device for request_firmware */ static struct platform_device *microcode_pdev; -static int reload_for_cpu(int cpu) +static enum ucode_state reload_for_cpu(int cpu) { struct ucode_cpu_info *uci = ucode_cpu_info + cpu; enum ucode_state ustate; - int err = 0; if (!uci->valid) - return err; + return UCODE_OK; ustate = microcode_ops->request_microcode_fw(cpu, µcode_pdev->dev, true); - if (ustate == UCODE_OK) - apply_microcode_on_target(cpu); - else - if (ustate == UCODE_ERROR) - err = -EINVAL; - return err; + if (ustate != UCODE_OK) + return ustate; + + return apply_microcode_on_target(cpu); } static ssize_t reload_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) { + enum ucode_state tmp_ret = UCODE_OK; unsigned long val; + ssize_t ret = 0; int cpu; - ssize_t ret = 0, tmp_ret; ret = kstrtoul(buf, 0, &val); if (ret) @@ -526,15 +524,18 @@ static ssize_t reload_store(struct device *dev, mutex_lock(µcode_mutex); for_each_online_cpu(cpu) { tmp_ret = reload_for_cpu(cpu); - if (tmp_ret != 0) + if (tmp_ret > UCODE_NFOUND) { pr_warn("Error reloading microcode on CPU %d\n", cpu); - /* save retval of the first encountered reload error */ - if (!ret) - ret = tmp_ret; + /* set retval for the first encountered reload error */ + if (!ret) + ret = -EINVAL; + } } - if (!ret) + + if (!ret && tmp_ret == UCODE_UPDATED) perf_check_microcode(); + mutex_unlock(µcode_mutex); put_online_cpus(); diff --git a/arch/x86/kernel/cpu/microcode/intel.c b/arch/x86/kernel/cpu/microcode/intel.c index a15db2b4e0d6..923054a6b760 100644 --- a/arch/x86/kernel/cpu/microcode/intel.c +++ b/arch/x86/kernel/cpu/microcode/intel.c @@ -772,7 +772,7 @@ static int collect_cpu_info(int cpu_num, struct cpu_signature *csig) return 0; } -static int apply_microcode_intel(int cpu) +static enum ucode_state apply_microcode_intel(int cpu) { struct microcode_intel *mc; struct ucode_cpu_info *uci; @@ -782,7 +782,7 @@ static int apply_microcode_intel(int cpu) /* We should bind the task to the CPU */ if (WARN_ON(raw_smp_processor_id() != cpu)) - return -1; + return UCODE_ERROR; uci = ucode_cpu_info + cpu; mc = uci->mc; @@ -790,7 +790,7 @@ static int apply_microcode_intel(int cpu) /* Look for a newer patch in our cache: */ mc = find_patch(uci); if (!mc) - return 0; + return UCODE_NFOUND; } /* write microcode via MSR 0x79 */ @@ -801,7 +801,7 @@ static int apply_microcode_intel(int cpu) if (rev != mc->hdr.rev) { pr_err("CPU%d update to revision 0x%x failed\n", cpu, mc->hdr.rev); - return -1; + return UCODE_ERROR; } if (rev != prev_rev) { @@ -818,7 +818,7 @@ static int apply_microcode_intel(int cpu) uci->cpu_sig.rev = rev; c->microcode = rev; - return 0; + return UCODE_UPDATED; } static enum ucode_state generic_load_microcode(int cpu, void *data, size_t size, -- GitLab From 00ba4bcf4b92c7b0a77d47834479f39bbd4c5e16 Mon Sep 17 00:00:00 2001 From: Borislav Petkov Date: Fri, 16 Feb 2018 12:26:39 +0100 Subject: [PATCH 0265/1635] x86/CPU: Add a microcode loader callback commit 1008c52c09dcb23d93f8e0ea83a6246265d2cce0 upstream. Add a callback function which the microcode loader calls when microcode has been updated to a newer revision. Do the callback only when no error was encountered during loading. Tested-by: Ashok Raj Signed-off-by: Borislav Petkov Reviewed-by: Ashok Raj Cc: Andy Lutomirski Cc: Arjan van de Ven Cc: Borislav Petkov Cc: Dan Williams Cc: Dave Hansen Cc: David Woodhouse Cc: Greg Kroah-Hartman Cc: Josh Poimboeuf Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/20180216112640.11554-3-bp@alien8.de Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman --- arch/x86/include/asm/processor.h | 1 + arch/x86/kernel/cpu/common.c | 10 ++++++++++ arch/x86/kernel/cpu/microcode/core.c | 8 ++++++-- 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h index 15fc074bd628..3222c7746cb1 100644 --- a/arch/x86/include/asm/processor.h +++ b/arch/x86/include/asm/processor.h @@ -968,4 +968,5 @@ bool xen_set_default_idle(void); void stop_this_cpu(void *dummy); void df_debug(struct pt_regs *regs, long error_code); +void microcode_check(void); #endif /* _ASM_X86_PROCESSOR_H */ diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c index 651b7afed4da..48d8fdd80b51 100644 --- a/arch/x86/kernel/cpu/common.c +++ b/arch/x86/kernel/cpu/common.c @@ -1724,3 +1724,13 @@ static int __init init_cpu_syscore(void) return 0; } core_initcall(init_cpu_syscore); + +/* + * The microcode loader calls this upon late microcode load to recheck features, + * only when microcode has been updated. Caller holds microcode_mutex and CPU + * hotplug lock. + */ +void microcode_check(void) +{ + perf_check_microcode(); +} diff --git a/arch/x86/kernel/cpu/microcode/core.c b/arch/x86/kernel/cpu/microcode/core.c index 7c423269ac49..b40b56e8e146 100644 --- a/arch/x86/kernel/cpu/microcode/core.c +++ b/arch/x86/kernel/cpu/microcode/core.c @@ -509,6 +509,7 @@ static ssize_t reload_store(struct device *dev, const char *buf, size_t size) { enum ucode_state tmp_ret = UCODE_OK; + bool do_callback = false; unsigned long val; ssize_t ret = 0; int cpu; @@ -531,10 +532,13 @@ static ssize_t reload_store(struct device *dev, if (!ret) ret = -EINVAL; } + + if (tmp_ret == UCODE_UPDATED) + do_callback = true; } - if (!ret && tmp_ret == UCODE_UPDATED) - perf_check_microcode(); + if (!ret && do_callback) + microcode_check(); mutex_unlock(µcode_mutex); put_online_cpus(); -- GitLab From 35da0d504a982709f5836cca725096cefcad24e2 Mon Sep 17 00:00:00 2001 From: Borislav Petkov Date: Fri, 16 Feb 2018 12:26:40 +0100 Subject: [PATCH 0266/1635] x86/CPU: Check CPU feature bits after microcode upgrade commit 42ca8082e260dcfd8afa2afa6ec1940b9d41724c upstream. With some microcode upgrades, new CPUID features can become visible on the CPU. Check what the kernel has mirrored now and issue a warning hinting at possible things the user/admin can do to make use of the newly visible features. Originally-by: Ashok Raj Tested-by: Ashok Raj Signed-off-by: Borislav Petkov Reviewed-by: Ashok Raj Cc: Andy Lutomirski Cc: Arjan van de Ven Cc: Borislav Petkov Cc: Dan Williams Cc: Dave Hansen Cc: David Woodhouse Cc: Greg Kroah-Hartman Cc: Josh Poimboeuf Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/20180216112640.11554-4-bp@alien8.de Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman --- arch/x86/kernel/cpu/common.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c index 48d8fdd80b51..cf6380200dc2 100644 --- a/arch/x86/kernel/cpu/common.c +++ b/arch/x86/kernel/cpu/common.c @@ -1732,5 +1732,25 @@ core_initcall(init_cpu_syscore); */ void microcode_check(void) { + struct cpuinfo_x86 info; + perf_check_microcode(); + + /* Reload CPUID max function as it might've changed. */ + info.cpuid_level = cpuid_eax(0); + + /* + * Copy all capability leafs to pick up the synthetic ones so that + * memcmp() below doesn't fail on that. The ones coming from CPUID will + * get overwritten in get_cpu_cap(). + */ + memcpy(&info.x86_capability, &boot_cpu_data.x86_capability, sizeof(info.x86_capability)); + + get_cpu_cap(&info); + + if (!memcmp(&info.x86_capability, &boot_cpu_data.x86_capability, sizeof(info.x86_capability))) + return; + + pr_warn("x86/CPU: CPU features have changed after loading microcode, but might not take effect.\n"); + pr_warn("x86/CPU: Please consider either early loading through initrd/built-in or a potential BIOS update.\n"); } -- GitLab From 22cc8816d013e6cf82e24af9ecaf3dde5800d1c8 Mon Sep 17 00:00:00 2001 From: Borislav Petkov Date: Wed, 28 Feb 2018 11:28:40 +0100 Subject: [PATCH 0267/1635] x86/microcode: Get rid of struct apply_microcode_ctx commit 854857f5944c59a881ff607b37ed9ed41d031a3b upstream. It is a useless remnant from earlier times. Use the ucode_state enum directly. No functional change. Signed-off-by: Borislav Petkov Signed-off-by: Thomas Gleixner Tested-by: Tom Lendacky Tested-by: Ashok Raj Cc: Arjan Van De Ven Link: https://lkml.kernel.org/r/20180228102846.13447-2-bp@alien8.de Signed-off-by: Greg Kroah-Hartman --- arch/x86/kernel/cpu/microcode/core.c | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/arch/x86/kernel/cpu/microcode/core.c b/arch/x86/kernel/cpu/microcode/core.c index b40b56e8e146..cbeace21f249 100644 --- a/arch/x86/kernel/cpu/microcode/core.c +++ b/arch/x86/kernel/cpu/microcode/core.c @@ -373,26 +373,23 @@ static int collect_cpu_info(int cpu) return ret; } -struct apply_microcode_ctx { - enum ucode_state err; -}; - static void apply_microcode_local(void *arg) { - struct apply_microcode_ctx *ctx = arg; + enum ucode_state *err = arg; - ctx->err = microcode_ops->apply_microcode(smp_processor_id()); + *err = microcode_ops->apply_microcode(smp_processor_id()); } static int apply_microcode_on_target(int cpu) { - struct apply_microcode_ctx ctx = { .err = 0 }; + enum ucode_state err; int ret; - ret = smp_call_function_single(cpu, apply_microcode_local, &ctx, 1); - if (!ret) - ret = ctx.err; - + ret = smp_call_function_single(cpu, apply_microcode_local, &err, 1); + if (!ret) { + if (err == UCODE_ERROR) + ret = 1; + } return ret; } -- GitLab From 170f8ec16c223c4e64cff971368fd5136d58dd69 Mon Sep 17 00:00:00 2001 From: Ashok Raj Date: Wed, 28 Feb 2018 11:28:41 +0100 Subject: [PATCH 0268/1635] x86/microcode/intel: Check microcode revision before updating sibling threads commit c182d2b7d0ca48e0d6ff16f7d883161238c447ed upstream. After updating microcode on one of the threads of a core, the other thread sibling automatically gets the update since the microcode resources on a hyperthreaded core are shared between the two threads. Check the microcode revision on the CPU before performing a microcode update and thus save us the WRMSR 0x79 because it is a particularly expensive operation. [ Borislav: Massage changelog and coding style. ] Signed-off-by: Ashok Raj Signed-off-by: Borislav Petkov Signed-off-by: Thomas Gleixner Tested-by: Tom Lendacky Tested-by: Ashok Raj Cc: Arjan Van De Ven Link: http://lkml.kernel.org/r/1519352533-15992-2-git-send-email-ashok.raj@intel.com Link: https://lkml.kernel.org/r/20180228102846.13447-3-bp@alien8.de Signed-off-by: Greg Kroah-Hartman --- arch/x86/kernel/cpu/microcode/intel.c | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/arch/x86/kernel/cpu/microcode/intel.c b/arch/x86/kernel/cpu/microcode/intel.c index 923054a6b760..87bd6dc94081 100644 --- a/arch/x86/kernel/cpu/microcode/intel.c +++ b/arch/x86/kernel/cpu/microcode/intel.c @@ -589,6 +589,17 @@ static int apply_microcode_early(struct ucode_cpu_info *uci, bool early) if (!mc) return 0; + /* + * Save us the MSR write below - which is a particular expensive + * operation - when the other hyperthread has updated the microcode + * already. + */ + rev = intel_get_microcode_revision(); + if (rev >= mc->hdr.rev) { + uci->cpu_sig.rev = rev; + return UCODE_OK; + } + /* write microcode via MSR 0x79 */ native_wrmsrl(MSR_IA32_UCODE_WRITE, (unsigned long)mc->bits); @@ -776,7 +787,7 @@ static enum ucode_state apply_microcode_intel(int cpu) { struct microcode_intel *mc; struct ucode_cpu_info *uci; - struct cpuinfo_x86 *c; + struct cpuinfo_x86 *c = &cpu_data(cpu); static int prev_rev; u32 rev; @@ -793,6 +804,18 @@ static enum ucode_state apply_microcode_intel(int cpu) return UCODE_NFOUND; } + /* + * Save us the MSR write below - which is a particular expensive + * operation - when the other hyperthread has updated the microcode + * already. + */ + rev = intel_get_microcode_revision(); + if (rev >= mc->hdr.rev) { + uci->cpu_sig.rev = rev; + c->microcode = rev; + return UCODE_OK; + } + /* write microcode via MSR 0x79 */ wrmsrl(MSR_IA32_UCODE_WRITE, (unsigned long)mc->bits); @@ -813,8 +836,6 @@ static enum ucode_state apply_microcode_intel(int cpu) prev_rev = rev; } - c = &cpu_data(cpu); - uci->cpu_sig.rev = rev; c->microcode = rev; -- GitLab From 1707112c82fa7f192d3d042003781776322b7a88 Mon Sep 17 00:00:00 2001 From: Ashok Raj Date: Wed, 28 Feb 2018 11:28:42 +0100 Subject: [PATCH 0269/1635] x86/microcode/intel: Writeback and invalidate caches before updating microcode commit 91df9fdf51492aec9fed6b4cbd33160886740f47 upstream. Updating microcode is less error prone when caches have been flushed and depending on what exactly the microcode is updating. For example, some of the issues around certain Broadwell parts can be addressed by doing a full cache flush. [ Borislav: Massage it and use native_wbinvd() in both cases. ] Signed-off-by: Ashok Raj Signed-off-by: Borislav Petkov Signed-off-by: Thomas Gleixner Tested-by: Tom Lendacky Tested-by: Ashok Raj Cc: Arjan Van De Ven Link: http://lkml.kernel.org/r/1519352533-15992-3-git-send-email-ashok.raj@intel.com Link: https://lkml.kernel.org/r/20180228102846.13447-4-bp@alien8.de Signed-off-by: Greg Kroah-Hartman --- arch/x86/kernel/cpu/microcode/intel.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/arch/x86/kernel/cpu/microcode/intel.c b/arch/x86/kernel/cpu/microcode/intel.c index 87bd6dc94081..e2864bc2d575 100644 --- a/arch/x86/kernel/cpu/microcode/intel.c +++ b/arch/x86/kernel/cpu/microcode/intel.c @@ -600,6 +600,12 @@ static int apply_microcode_early(struct ucode_cpu_info *uci, bool early) return UCODE_OK; } + /* + * Writeback and invalidate caches before updating microcode to avoid + * internal issues depending on what the microcode is updating. + */ + native_wbinvd(); + /* write microcode via MSR 0x79 */ native_wrmsrl(MSR_IA32_UCODE_WRITE, (unsigned long)mc->bits); @@ -816,6 +822,12 @@ static enum ucode_state apply_microcode_intel(int cpu) return UCODE_OK; } + /* + * Writeback and invalidate caches before updating microcode to avoid + * internal issues depending on what the microcode is updating. + */ + native_wbinvd(); + /* write microcode via MSR 0x79 */ wrmsrl(MSR_IA32_UCODE_WRITE, (unsigned long)mc->bits); -- GitLab From e87c2b553a35b35d6c000f2ad1300b02cb133e03 Mon Sep 17 00:00:00 2001 From: Ashok Raj Date: Wed, 28 Feb 2018 11:28:43 +0100 Subject: [PATCH 0270/1635] x86/microcode: Do not upload microcode if CPUs are offline commit 30ec26da9967d0d785abc24073129a34c3211777 upstream. Avoid loading microcode if any of the CPUs are offline, and issue a warning. Having different microcode revisions on the system at any time is outright dangerous. [ Borislav: Massage changelog. ] Signed-off-by: Ashok Raj Signed-off-by: Borislav Petkov Signed-off-by: Thomas Gleixner Tested-by: Tom Lendacky Tested-by: Ashok Raj Reviewed-by: Tom Lendacky Cc: Arjan Van De Ven Link: http://lkml.kernel.org/r/1519352533-15992-4-git-send-email-ashok.raj@intel.com Link: https://lkml.kernel.org/r/20180228102846.13447-5-bp@alien8.de Signed-off-by: Greg Kroah-Hartman --- arch/x86/kernel/cpu/microcode/core.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/arch/x86/kernel/cpu/microcode/core.c b/arch/x86/kernel/cpu/microcode/core.c index cbeace21f249..f25c395141d0 100644 --- a/arch/x86/kernel/cpu/microcode/core.c +++ b/arch/x86/kernel/cpu/microcode/core.c @@ -486,6 +486,16 @@ static void __exit microcode_dev_exit(void) /* fake device for request_firmware */ static struct platform_device *microcode_pdev; +static int check_online_cpus(void) +{ + if (num_online_cpus() == num_present_cpus()) + return 0; + + pr_err("Not all CPUs online, aborting microcode update.\n"); + + return -EINVAL; +} + static enum ucode_state reload_for_cpu(int cpu) { struct ucode_cpu_info *uci = ucode_cpu_info + cpu; @@ -519,7 +529,13 @@ static ssize_t reload_store(struct device *dev, return size; get_online_cpus(); + + ret = check_online_cpus(); + if (ret) + goto put; + mutex_lock(µcode_mutex); + for_each_online_cpu(cpu) { tmp_ret = reload_for_cpu(cpu); if (tmp_ret > UCODE_NFOUND) { @@ -538,6 +554,8 @@ static ssize_t reload_store(struct device *dev, microcode_check(); mutex_unlock(µcode_mutex); + +put: put_online_cpus(); if (!ret) -- GitLab From d2725848230d92b0c35219553814b64396717747 Mon Sep 17 00:00:00 2001 From: Borislav Petkov Date: Wed, 28 Feb 2018 11:28:44 +0100 Subject: [PATCH 0271/1635] x86/microcode/intel: Look into the patch cache first commit d8c3b52c00a05036e0a6b315b4b17921a7b67997 upstream. The cache might contain a newer patch - look in there first. A follow-on change will make sure newest patches are loaded into the cache of microcode patches. Signed-off-by: Borislav Petkov Signed-off-by: Thomas Gleixner Tested-by: Tom Lendacky Tested-by: Ashok Raj Cc: Arjan Van De Ven Link: https://lkml.kernel.org/r/20180228102846.13447-6-bp@alien8.de Signed-off-by: Greg Kroah-Hartman --- arch/x86/kernel/cpu/microcode/intel.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/arch/x86/kernel/cpu/microcode/intel.c b/arch/x86/kernel/cpu/microcode/intel.c index e2864bc2d575..2aded9db1d42 100644 --- a/arch/x86/kernel/cpu/microcode/intel.c +++ b/arch/x86/kernel/cpu/microcode/intel.c @@ -791,9 +791,9 @@ static int collect_cpu_info(int cpu_num, struct cpu_signature *csig) static enum ucode_state apply_microcode_intel(int cpu) { - struct microcode_intel *mc; - struct ucode_cpu_info *uci; + struct ucode_cpu_info *uci = ucode_cpu_info + cpu; struct cpuinfo_x86 *c = &cpu_data(cpu); + struct microcode_intel *mc; static int prev_rev; u32 rev; @@ -801,11 +801,10 @@ static enum ucode_state apply_microcode_intel(int cpu) if (WARN_ON(raw_smp_processor_id() != cpu)) return UCODE_ERROR; - uci = ucode_cpu_info + cpu; - mc = uci->mc; + /* Look for a newer patch in our cache: */ + mc = find_patch(uci); if (!mc) { - /* Look for a newer patch in our cache: */ - mc = find_patch(uci); + mc = uci->mc; if (!mc) return UCODE_NFOUND; } -- GitLab From 509df2b865f1ecedbedc5af4400558a50cc79d58 Mon Sep 17 00:00:00 2001 From: Borislav Petkov Date: Wed, 28 Feb 2018 11:28:45 +0100 Subject: [PATCH 0272/1635] x86/microcode: Request microcode on the BSP commit cfb52a5a09c8ae3a1dafb44ce549fde5b69e8117 upstream. ... so that any newer version can land in the cache and can later be fished out by the application functions. Do that before grabbing the hotplug lock. Signed-off-by: Borislav Petkov Signed-off-by: Thomas Gleixner Tested-by: Tom Lendacky Tested-by: Ashok Raj Reviewed-by: Tom Lendacky Cc: Arjan Van De Ven Link: https://lkml.kernel.org/r/20180228102846.13447-7-bp@alien8.de Signed-off-by: Greg Kroah-Hartman --- arch/x86/kernel/cpu/microcode/core.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/arch/x86/kernel/cpu/microcode/core.c b/arch/x86/kernel/cpu/microcode/core.c index f25c395141d0..8adbf439cbfb 100644 --- a/arch/x86/kernel/cpu/microcode/core.c +++ b/arch/x86/kernel/cpu/microcode/core.c @@ -499,15 +499,10 @@ static int check_online_cpus(void) static enum ucode_state reload_for_cpu(int cpu) { struct ucode_cpu_info *uci = ucode_cpu_info + cpu; - enum ucode_state ustate; if (!uci->valid) return UCODE_OK; - ustate = microcode_ops->request_microcode_fw(cpu, µcode_pdev->dev, true); - if (ustate != UCODE_OK) - return ustate; - return apply_microcode_on_target(cpu); } @@ -515,11 +510,11 @@ static ssize_t reload_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) { + int cpu, bsp = boot_cpu_data.cpu_index; enum ucode_state tmp_ret = UCODE_OK; bool do_callback = false; unsigned long val; ssize_t ret = 0; - int cpu; ret = kstrtoul(buf, 0, &val); if (ret) @@ -528,6 +523,10 @@ static ssize_t reload_store(struct device *dev, if (val != 1) return size; + tmp_ret = microcode_ops->request_microcode_fw(bsp, µcode_pdev->dev, true); + if (tmp_ret != UCODE_OK) + return size; + get_online_cpus(); ret = check_online_cpus(); -- GitLab From b0b1ac38e01839bf76db513d4374b608fbd95fc8 Mon Sep 17 00:00:00 2001 From: Ashok Raj Date: Wed, 28 Feb 2018 11:28:46 +0100 Subject: [PATCH 0273/1635] x86/microcode: Synchronize late microcode loading commit a5321aec6412b20b5ad15db2d6b916c05349dbff upstream. Original idea by Ashok, completely rewritten by Borislav. Before you read any further: the early loading method is still the preferred one and you should always do that. The following patch is improving the late loading mechanism for long running jobs and cloud use cases. Gather all cores and serialize the microcode update on them by doing it one-by-one to make the late update process as reliable as possible and avoid potential issues caused by the microcode update. [ Borislav: Rewrite completely. ] Co-developed-by: Borislav Petkov Signed-off-by: Ashok Raj Signed-off-by: Borislav Petkov Signed-off-by: Thomas Gleixner Tested-by: Tom Lendacky Tested-by: Ashok Raj Reviewed-by: Tom Lendacky Cc: Arjan Van De Ven Link: https://lkml.kernel.org/r/20180228102846.13447-8-bp@alien8.de Signed-off-by: Greg Kroah-Hartman --- arch/x86/kernel/cpu/microcode/core.c | 118 +++++++++++++++++++++------ 1 file changed, 92 insertions(+), 26 deletions(-) diff --git a/arch/x86/kernel/cpu/microcode/core.c b/arch/x86/kernel/cpu/microcode/core.c index 8adbf439cbfb..bde629e7b889 100644 --- a/arch/x86/kernel/cpu/microcode/core.c +++ b/arch/x86/kernel/cpu/microcode/core.c @@ -22,13 +22,16 @@ #define pr_fmt(fmt) "microcode: " fmt #include +#include #include #include #include #include #include +#include #include #include +#include #include #include @@ -64,6 +67,11 @@ LIST_HEAD(microcode_cache); */ static DEFINE_MUTEX(microcode_mutex); +/* + * Serialize late loading so that CPUs get updated one-by-one. + */ +static DEFINE_SPINLOCK(update_lock); + struct ucode_cpu_info ucode_cpu_info[NR_CPUS]; struct cpu_info_ctx { @@ -486,6 +494,19 @@ static void __exit microcode_dev_exit(void) /* fake device for request_firmware */ static struct platform_device *microcode_pdev; +/* + * Late loading dance. Why the heavy-handed stomp_machine effort? + * + * - HT siblings must be idle and not execute other code while the other sibling + * is loading microcode in order to avoid any negative interactions caused by + * the loading. + * + * - In addition, microcode update on the cores must be serialized until this + * requirement can be relaxed in the future. Right now, this is conservative + * and good. + */ +#define SPINUNIT 100 /* 100 nsec */ + static int check_online_cpus(void) { if (num_online_cpus() == num_present_cpus()) @@ -496,23 +517,85 @@ static int check_online_cpus(void) return -EINVAL; } -static enum ucode_state reload_for_cpu(int cpu) +static atomic_t late_cpus; + +/* + * Returns: + * < 0 - on error + * 0 - no update done + * 1 - microcode was updated + */ +static int __reload_late(void *info) { - struct ucode_cpu_info *uci = ucode_cpu_info + cpu; + unsigned int timeout = NSEC_PER_SEC; + int all_cpus = num_online_cpus(); + int cpu = smp_processor_id(); + enum ucode_state err; + int ret = 0; - if (!uci->valid) - return UCODE_OK; + atomic_dec(&late_cpus); + + /* + * Wait for all CPUs to arrive. A load will not be attempted unless all + * CPUs show up. + * */ + while (atomic_read(&late_cpus)) { + if (timeout < SPINUNIT) { + pr_err("Timeout while waiting for CPUs rendezvous, remaining: %d\n", + atomic_read(&late_cpus)); + return -1; + } + + ndelay(SPINUNIT); + timeout -= SPINUNIT; + + touch_nmi_watchdog(); + } + + spin_lock(&update_lock); + apply_microcode_local(&err); + spin_unlock(&update_lock); + + if (err > UCODE_NFOUND) { + pr_warn("Error reloading microcode on CPU %d\n", cpu); + ret = -1; + } else if (err == UCODE_UPDATED) { + ret = 1; + } - return apply_microcode_on_target(cpu); + atomic_inc(&late_cpus); + + while (atomic_read(&late_cpus) != all_cpus) + cpu_relax(); + + return ret; +} + +/* + * Reload microcode late on all CPUs. Wait for a sec until they + * all gather together. + */ +static int microcode_reload_late(void) +{ + int ret; + + atomic_set(&late_cpus, num_online_cpus()); + + ret = stop_machine_cpuslocked(__reload_late, NULL, cpu_online_mask); + if (ret < 0) + return ret; + else if (ret > 0) + microcode_check(); + + return ret; } static ssize_t reload_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) { - int cpu, bsp = boot_cpu_data.cpu_index; enum ucode_state tmp_ret = UCODE_OK; - bool do_callback = false; + int bsp = boot_cpu_data.cpu_index; unsigned long val; ssize_t ret = 0; @@ -534,30 +617,13 @@ static ssize_t reload_store(struct device *dev, goto put; mutex_lock(µcode_mutex); - - for_each_online_cpu(cpu) { - tmp_ret = reload_for_cpu(cpu); - if (tmp_ret > UCODE_NFOUND) { - pr_warn("Error reloading microcode on CPU %d\n", cpu); - - /* set retval for the first encountered reload error */ - if (!ret) - ret = -EINVAL; - } - - if (tmp_ret == UCODE_UPDATED) - do_callback = true; - } - - if (!ret && do_callback) - microcode_check(); - + ret = microcode_reload_late(); mutex_unlock(µcode_mutex); put: put_online_cpus(); - if (!ret) + if (ret >= 0) ret = size; return ret; -- GitLab From c81d7069dcd60e5cc4e654c26301063cbc26865c Mon Sep 17 00:00:00 2001 From: Borislav Petkov Date: Wed, 14 Mar 2018 19:36:14 +0100 Subject: [PATCH 0274/1635] x86/microcode: Attempt late loading only when new microcode is present commit 2613f36ed965d0e5a595a1d931fd3b480e82d6fd upstream. Return UCODE_NEW from the scanning functions to denote that new microcode was found and only then attempt the expensive synchronization dance. Reported-by: Emanuel Czirai Signed-off-by: Borislav Petkov Signed-off-by: Thomas Gleixner Tested-by: Emanuel Czirai Tested-by: Ashok Raj Tested-by: Tom Lendacky Link: https://lkml.kernel.org/r/20180314183615.17629-1-bp@alien8.de Signed-off-by: Greg Kroah-Hartman --- arch/x86/include/asm/microcode.h | 1 + arch/x86/kernel/cpu/microcode/amd.c | 34 +++++++++++++++++---------- arch/x86/kernel/cpu/microcode/core.c | 8 +++---- arch/x86/kernel/cpu/microcode/intel.c | 4 +++- 4 files changed, 28 insertions(+), 19 deletions(-) diff --git a/arch/x86/include/asm/microcode.h b/arch/x86/include/asm/microcode.h index 7fb1047d61c7..6cf0e4cb7b97 100644 --- a/arch/x86/include/asm/microcode.h +++ b/arch/x86/include/asm/microcode.h @@ -39,6 +39,7 @@ struct device; enum ucode_state { UCODE_OK = 0, + UCODE_NEW, UCODE_UPDATED, UCODE_NFOUND, UCODE_ERROR, diff --git a/arch/x86/kernel/cpu/microcode/amd.c b/arch/x86/kernel/cpu/microcode/amd.c index a998e1a7d46f..48179928ff38 100644 --- a/arch/x86/kernel/cpu/microcode/amd.c +++ b/arch/x86/kernel/cpu/microcode/amd.c @@ -339,7 +339,7 @@ int __init save_microcode_in_initrd_amd(unsigned int cpuid_1_eax) return -EINVAL; ret = load_microcode_amd(true, x86_family(cpuid_1_eax), desc.data, desc.size); - if (ret != UCODE_OK) + if (ret > UCODE_UPDATED) return -EINVAL; return 0; @@ -683,27 +683,35 @@ static enum ucode_state __load_microcode_amd(u8 family, const u8 *data, static enum ucode_state load_microcode_amd(bool save, u8 family, const u8 *data, size_t size) { + struct ucode_patch *p; enum ucode_state ret; /* free old equiv table */ free_equiv_cpu_table(); ret = __load_microcode_amd(family, data, size); - - if (ret != UCODE_OK) + if (ret != UCODE_OK) { cleanup(); + return ret; + } -#ifdef CONFIG_X86_32 - /* save BSP's matching patch for early load */ - if (save) { - struct ucode_patch *p = find_patch(0); - if (p) { - memset(amd_ucode_patch, 0, PATCH_MAX_SIZE); - memcpy(amd_ucode_patch, p->data, min_t(u32, ksize(p->data), - PATCH_MAX_SIZE)); - } + p = find_patch(0); + if (!p) { + return ret; + } else { + if (boot_cpu_data.microcode == p->patch_id) + return ret; + + ret = UCODE_NEW; } -#endif + + /* save BSP's matching patch for early load */ + if (!save) + return ret; + + memset(amd_ucode_patch, 0, PATCH_MAX_SIZE); + memcpy(amd_ucode_patch, p->data, min_t(u32, ksize(p->data), PATCH_MAX_SIZE)); + return ret; } diff --git a/arch/x86/kernel/cpu/microcode/core.c b/arch/x86/kernel/cpu/microcode/core.c index bde629e7b889..e6d5caabaecc 100644 --- a/arch/x86/kernel/cpu/microcode/core.c +++ b/arch/x86/kernel/cpu/microcode/core.c @@ -607,7 +607,7 @@ static ssize_t reload_store(struct device *dev, return size; tmp_ret = microcode_ops->request_microcode_fw(bsp, µcode_pdev->dev, true); - if (tmp_ret != UCODE_OK) + if (tmp_ret != UCODE_NEW) return size; get_online_cpus(); @@ -691,10 +691,8 @@ static enum ucode_state microcode_init_cpu(int cpu, bool refresh_fw) if (system_state != SYSTEM_RUNNING) return UCODE_NFOUND; - ustate = microcode_ops->request_microcode_fw(cpu, µcode_pdev->dev, - refresh_fw); - - if (ustate == UCODE_OK) { + ustate = microcode_ops->request_microcode_fw(cpu, µcode_pdev->dev, refresh_fw); + if (ustate == UCODE_NEW) { pr_debug("CPU%d updated upon init\n", cpu); apply_microcode_on_target(cpu); } diff --git a/arch/x86/kernel/cpu/microcode/intel.c b/arch/x86/kernel/cpu/microcode/intel.c index 2aded9db1d42..32b8e5724f96 100644 --- a/arch/x86/kernel/cpu/microcode/intel.c +++ b/arch/x86/kernel/cpu/microcode/intel.c @@ -862,6 +862,7 @@ static enum ucode_state generic_load_microcode(int cpu, void *data, size_t size, unsigned int leftover = size; unsigned int curr_mc_size = 0, new_mc_size = 0; unsigned int csig, cpf; + enum ucode_state ret = UCODE_OK; while (leftover) { struct microcode_header_intel mc_header; @@ -903,6 +904,7 @@ static enum ucode_state generic_load_microcode(int cpu, void *data, size_t size, new_mc = mc; new_mc_size = mc_size; mc = NULL; /* trigger new vmalloc */ + ret = UCODE_NEW; } ucode_ptr += mc_size; @@ -932,7 +934,7 @@ static enum ucode_state generic_load_microcode(int cpu, void *data, size_t size, pr_debug("CPU%d found a matching microcode update with version 0x%x (current=0x%x)\n", cpu, new_rev, uci->cpu_sig.rev); - return UCODE_OK; + return ret; } static int get_ucode_fw(void *to, const void *from, size_t n) -- GitLab From 8413a3a63d3717504f2db5d6c3b018cabf15d132 Mon Sep 17 00:00:00 2001 From: Borislav Petkov Date: Wed, 14 Mar 2018 19:36:15 +0100 Subject: [PATCH 0275/1635] x86/microcode: Fix CPU synchronization routine commit bb8c13d61a629276a162c1d2b1a20a815cbcfbb7 upstream. Emanuel reported an issue with a hang during microcode update because my dumb idea to use one atomic synchronization variable for both rendezvous - before and after update - was simply bollocks: microcode: microcode_reload_late: late_cpus: 4 microcode: __reload_late: cpu 2 entered microcode: __reload_late: cpu 1 entered microcode: __reload_late: cpu 3 entered microcode: __reload_late: cpu 0 entered microcode: __reload_late: cpu 1 left microcode: Timeout while waiting for CPUs rendezvous, remaining: 1 CPU1 above would finish, leave and the others will still spin waiting for it to join. So do two synchronization atomics instead, which makes the code a lot more straightforward. Also, since the update is serialized and it also takes quite some time per microcode engine, increase the exit timeout by the number of CPUs on the system. That's ok because the moment all CPUs are done, that timeout will be cut short. Furthermore, panic when some of the CPUs timeout when returning from a microcode update: we can't allow a system with not all cores updated. Also, as an optimization, do not do the exit sync if microcode wasn't updated. Reported-by: Emanuel Czirai Signed-off-by: Borislav Petkov Signed-off-by: Thomas Gleixner Tested-by: Emanuel Czirai Tested-by: Ashok Raj Tested-by: Tom Lendacky Link: https://lkml.kernel.org/r/20180314183615.17629-2-bp@alien8.de Signed-off-by: Greg Kroah-Hartman --- arch/x86/kernel/cpu/microcode/core.c | 68 +++++++++++++++++----------- 1 file changed, 41 insertions(+), 27 deletions(-) diff --git a/arch/x86/kernel/cpu/microcode/core.c b/arch/x86/kernel/cpu/microcode/core.c index e6d5caabaecc..021c90464cc2 100644 --- a/arch/x86/kernel/cpu/microcode/core.c +++ b/arch/x86/kernel/cpu/microcode/core.c @@ -517,7 +517,29 @@ static int check_online_cpus(void) return -EINVAL; } -static atomic_t late_cpus; +static atomic_t late_cpus_in; +static atomic_t late_cpus_out; + +static int __wait_for_cpus(atomic_t *t, long long timeout) +{ + int all_cpus = num_online_cpus(); + + atomic_inc(t); + + while (atomic_read(t) < all_cpus) { + if (timeout < SPINUNIT) { + pr_err("Timeout while waiting for CPUs rendezvous, remaining: %d\n", + all_cpus - atomic_read(t)); + return 1; + } + + ndelay(SPINUNIT); + timeout -= SPINUNIT; + + touch_nmi_watchdog(); + } + return 0; +} /* * Returns: @@ -527,30 +549,16 @@ static atomic_t late_cpus; */ static int __reload_late(void *info) { - unsigned int timeout = NSEC_PER_SEC; - int all_cpus = num_online_cpus(); int cpu = smp_processor_id(); enum ucode_state err; int ret = 0; - atomic_dec(&late_cpus); - /* * Wait for all CPUs to arrive. A load will not be attempted unless all * CPUs show up. * */ - while (atomic_read(&late_cpus)) { - if (timeout < SPINUNIT) { - pr_err("Timeout while waiting for CPUs rendezvous, remaining: %d\n", - atomic_read(&late_cpus)); - return -1; - } - - ndelay(SPINUNIT); - timeout -= SPINUNIT; - - touch_nmi_watchdog(); - } + if (__wait_for_cpus(&late_cpus_in, NSEC_PER_SEC)) + return -1; spin_lock(&update_lock); apply_microcode_local(&err); @@ -558,15 +566,22 @@ static int __reload_late(void *info) if (err > UCODE_NFOUND) { pr_warn("Error reloading microcode on CPU %d\n", cpu); - ret = -1; - } else if (err == UCODE_UPDATED) { + return -1; + /* siblings return UCODE_OK because their engine got updated already */ + } else if (err == UCODE_UPDATED || err == UCODE_OK) { ret = 1; + } else { + return ret; } - atomic_inc(&late_cpus); - - while (atomic_read(&late_cpus) != all_cpus) - cpu_relax(); + /* + * Increase the wait timeout to a safe value here since we're + * serializing the microcode update and that could take a while on a + * large number of CPUs. And that is fine as the *actual* timeout will + * be determined by the last CPU finished updating and thus cut short. + */ + if (__wait_for_cpus(&late_cpus_out, NSEC_PER_SEC * num_online_cpus())) + panic("Timeout during microcode update!\n"); return ret; } @@ -579,12 +594,11 @@ static int microcode_reload_late(void) { int ret; - atomic_set(&late_cpus, num_online_cpus()); + atomic_set(&late_cpus_in, 0); + atomic_set(&late_cpus_out, 0); ret = stop_machine_cpuslocked(__reload_late, NULL, cpu_online_mask); - if (ret < 0) - return ret; - else if (ret > 0) + if (ret > 0) microcode_check(); return ret; -- GitLab From cdd74d6ac80ef50a520b6234947f8e2f6ebca75a Mon Sep 17 00:00:00 2001 From: Miguel Fadon Perlines Date: Thu, 5 Apr 2018 10:25:38 +0200 Subject: [PATCH 0276/1635] arp: fix arp_filter on l3slave devices [ Upstream commit 58b35f27689b5eb514fc293c332966c226b1b6e4 ] arp_filter performs an ip_route_output search for arp source address and checks if output device is the same where the arp request was received, if it is not, the arp request is not answered. This route lookup is always done on main route table so l3slave devices never find the proper route and arp is not answered. Passing l3mdev_master_ifindex_rcu(dev) return value as oif fixes the lookup for l3slave devices while maintaining same behavior for non l3slave devices as this function returns 0 in that case. Fixes: 613d09b30f8b ("net: Use VRF device index for lookups on TX") Signed-off-by: Miguel Fadon Perlines Acked-by: David Ahern Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv4/arp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c index a1d1f50e0e19..7d9cf26f4bb1 100644 --- a/net/ipv4/arp.c +++ b/net/ipv4/arp.c @@ -437,7 +437,7 @@ static int arp_filter(__be32 sip, __be32 tip, struct net_device *dev) /*unsigned long now; */ struct net *net = dev_net(dev); - rt = ip_route_output(net, sip, tip, 0, 0); + rt = ip_route_output(net, sip, tip, 0, l3mdev_master_ifindex_rcu(dev)); if (IS_ERR(rt)) return 1; if (rt->dst.dev != dev) { -- GitLab From 52f0a5ff60e44bf731079f8ceaaa61b42b342122 Mon Sep 17 00:00:00 2001 From: Paolo Abeni Date: Fri, 23 Mar 2018 14:47:30 +0100 Subject: [PATCH 0277/1635] ipv6: the entire IPv6 header chain must fit the first fragment [ Upstream commit 10b8a3de603df7b96004179b1b33b1708c76d144 ] While building ipv6 datagram we currently allow arbitrary large extheaders, even beyond pmtu size. The syzbot has found a way to exploit the above to trigger the following splat: kernel BUG at ./include/linux/skbuff.h:2073! invalid opcode: 0000 [#1] SMP KASAN Dumping ftrace buffer: (ftrace buffer empty) Modules linked in: CPU: 1 PID: 4230 Comm: syzkaller672661 Not tainted 4.16.0-rc2+ #326 Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/01/2011 RIP: 0010:__skb_pull include/linux/skbuff.h:2073 [inline] RIP: 0010:__ip6_make_skb+0x1ac8/0x2190 net/ipv6/ip6_output.c:1636 RSP: 0018:ffff8801bc18f0f0 EFLAGS: 00010293 RAX: ffff8801b17400c0 RBX: 0000000000000738 RCX: ffffffff84f01828 RDX: 0000000000000000 RSI: 0000000000000001 RDI: ffff8801b415ac18 RBP: ffff8801bc18f360 R08: ffff8801b4576844 R09: 0000000000000000 R10: ffff8801bc18f380 R11: ffffed00367aee4e R12: 00000000000000d6 R13: ffff8801b415a740 R14: dffffc0000000000 R15: ffff8801b45767c0 FS: 0000000001535880(0000) GS:ffff8801db300000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 000000002000b000 CR3: 00000001b4123001 CR4: 00000000001606e0 DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 Call Trace: ip6_finish_skb include/net/ipv6.h:969 [inline] udp_v6_push_pending_frames+0x269/0x3b0 net/ipv6/udp.c:1073 udpv6_sendmsg+0x2a96/0x3400 net/ipv6/udp.c:1343 inet_sendmsg+0x11f/0x5e0 net/ipv4/af_inet.c:764 sock_sendmsg_nosec net/socket.c:630 [inline] sock_sendmsg+0xca/0x110 net/socket.c:640 ___sys_sendmsg+0x320/0x8b0 net/socket.c:2046 __sys_sendmmsg+0x1ee/0x620 net/socket.c:2136 SYSC_sendmmsg net/socket.c:2167 [inline] SyS_sendmmsg+0x35/0x60 net/socket.c:2162 do_syscall_64+0x280/0x940 arch/x86/entry/common.c:287 entry_SYSCALL_64_after_hwframe+0x42/0xb7 RIP: 0033:0x4404c9 RSP: 002b:00007ffdce35f948 EFLAGS: 00000217 ORIG_RAX: 0000000000000133 RAX: ffffffffffffffda RBX: 00000000004002c8 RCX: 00000000004404c9 RDX: 0000000000000003 RSI: 0000000020001f00 RDI: 0000000000000003 RBP: 00000000006cb018 R08: 00000000004002c8 R09: 00000000004002c8 R10: 0000000020000080 R11: 0000000000000217 R12: 0000000000401df0 R13: 0000000000401e80 R14: 0000000000000000 R15: 0000000000000000 Code: ff e8 1d 5e b9 fc e9 15 e9 ff ff e8 13 5e b9 fc e9 44 e8 ff ff e8 29 5e b9 fc e9 c0 e6 ff ff e8 3f f3 80 fc 0f 0b e8 38 f3 80 fc <0f> 0b 49 8d 87 80 00 00 00 4d 8d 87 84 00 00 00 48 89 85 20 fe RIP: __skb_pull include/linux/skbuff.h:2073 [inline] RSP: ffff8801bc18f0f0 RIP: __ip6_make_skb+0x1ac8/0x2190 net/ipv6/ip6_output.c:1636 RSP: ffff8801bc18f0f0 As stated by RFC 7112 section 5: When a host fragments an IPv6 datagram, it MUST include the entire IPv6 Header Chain in the First Fragment. So this patch addresses the issue dropping datagrams with excessive extheader length. It also updates the error path to report to the calling socket nonnegative pmtu values. The issue apparently predates git history. v1 -> v2: cleanup error path, as per Eric's suggestion Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Reported-by: syzbot+91e6f9932ff122fa4410@syzkaller.appspotmail.com Signed-off-by: Paolo Abeni Reviewed-by: Eric Dumazet Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv6/ip6_output.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index 0f874b48c1b5..75b8c8a4374c 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -1245,7 +1245,7 @@ static int __ip6_append_data(struct sock *sk, const struct sockcm_cookie *sockc) { struct sk_buff *skb, *skb_prev = NULL; - unsigned int maxfraglen, fragheaderlen, mtu, orig_mtu; + unsigned int maxfraglen, fragheaderlen, mtu, orig_mtu, pmtu; int exthdrlen = 0; int dst_exthdrlen = 0; int hh_len; @@ -1281,6 +1281,12 @@ static int __ip6_append_data(struct sock *sk, sizeof(struct frag_hdr) : 0) + rt->rt6i_nfheader_len; + /* as per RFC 7112 section 5, the entire IPv6 Header Chain must fit + * the first fragment + */ + if (headersize + transhdrlen > mtu) + goto emsgsize; + if (cork->length + length > mtu - headersize && ipc6->dontfrag && (sk->sk_protocol == IPPROTO_UDP || sk->sk_protocol == IPPROTO_RAW)) { @@ -1296,9 +1302,8 @@ static int __ip6_append_data(struct sock *sk, if (cork->length + length > maxnonfragsize - headersize) { emsgsize: - ipv6_local_error(sk, EMSGSIZE, fl6, - mtu - headersize + - sizeof(struct ipv6hdr)); + pmtu = max_t(int, mtu - headersize + sizeof(struct ipv6hdr), 0); + ipv6_local_error(sk, EMSGSIZE, fl6, pmtu); return -EMSGSIZE; } -- GitLab From 629eeaaccb234527e1d7c0e5172215a24c3c9ec7 Mon Sep 17 00:00:00 2001 From: Raghuram Chary J Date: Tue, 27 Mar 2018 14:51:16 +0530 Subject: [PATCH 0278/1635] lan78xx: Crash in lan78xx_writ_reg (Workqueue: events lan78xx_deferred_multicast_write) [ Upstream commit 2d2d99ec13f62d5d2cecb6169dfdb6bbe05356d0 ] Description: Crash was reported with syzkaller pointing to lan78xx_write_reg routine. Root-cause: Proper cleanup of workqueues and init/setup routines was not happening in failure conditions. Fix: Handled the error conditions by cleaning up the queues and init/setup routines. Fixes: 55d7de9de6c3 ("Microchip's LAN7800 family USB 2/3 to 10/100/1000 Ethernet device driver") Reported-by: Andrey Konovalov Signed-off-by: Raghuram Chary J Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/usb/lan78xx.c | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/drivers/net/usb/lan78xx.c b/drivers/net/usb/lan78xx.c index a8dd1c7a08cb..89d82c4ee8df 100644 --- a/drivers/net/usb/lan78xx.c +++ b/drivers/net/usb/lan78xx.c @@ -2863,8 +2863,7 @@ static int lan78xx_bind(struct lan78xx_net *dev, struct usb_interface *intf) if (ret < 0) { netdev_warn(dev->net, "lan78xx_setup_irq_domain() failed : %d", ret); - kfree(pdata); - return ret; + goto out1; } dev->net->hard_header_len += TX_OVERHEAD; @@ -2872,14 +2871,32 @@ static int lan78xx_bind(struct lan78xx_net *dev, struct usb_interface *intf) /* Init all registers */ ret = lan78xx_reset(dev); + if (ret) { + netdev_warn(dev->net, "Registers INIT FAILED...."); + goto out2; + } ret = lan78xx_mdio_init(dev); + if (ret) { + netdev_warn(dev->net, "MDIO INIT FAILED....."); + goto out2; + } dev->net->flags |= IFF_MULTICAST; pdata->wol = WAKE_MAGIC; return ret; + +out2: + lan78xx_remove_irq_domain(dev); + +out1: + netdev_warn(dev->net, "Bind routine FAILED"); + cancel_work_sync(&pdata->set_multicast); + cancel_work_sync(&pdata->set_vlan); + kfree(pdata); + return ret; } static void lan78xx_unbind(struct lan78xx_net *dev, struct usb_interface *intf) @@ -2891,6 +2908,8 @@ static void lan78xx_unbind(struct lan78xx_net *dev, struct usb_interface *intf) lan78xx_remove_mdio(dev); if (pdata) { + cancel_work_sync(&pdata->set_multicast); + cancel_work_sync(&pdata->set_vlan); netif_dbg(dev, ifdown, dev->net, "free pdata"); kfree(pdata); pdata = NULL; -- GitLab From 589a3f3051853da8dc21ce5661b24c6528d9c3e3 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Mon, 26 Mar 2018 08:08:07 -0700 Subject: [PATCH 0279/1635] net: fix possible out-of-bound read in skb_network_protocol() [ Upstream commit 1dfe82ebd7d8fd43dba9948fdfb31f145014baa0 ] skb mac header is not necessarily set at the time skb_network_protocol() is called. Use skb->data instead. BUG: KASAN: slab-out-of-bounds in skb_network_protocol+0x46b/0x4b0 net/core/dev.c:2739 Read of size 2 at addr ffff8801b3097a0b by task syz-executor5/14242 CPU: 1 PID: 14242 Comm: syz-executor5 Not tainted 4.16.0-rc6+ #280 Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/01/2011 Call Trace: __dump_stack lib/dump_stack.c:17 [inline] dump_stack+0x194/0x24d lib/dump_stack.c:53 print_address_description+0x73/0x250 mm/kasan/report.c:256 kasan_report_error mm/kasan/report.c:354 [inline] kasan_report+0x23c/0x360 mm/kasan/report.c:412 __asan_report_load_n_noabort+0xf/0x20 mm/kasan/report.c:443 skb_network_protocol+0x46b/0x4b0 net/core/dev.c:2739 harmonize_features net/core/dev.c:2924 [inline] netif_skb_features+0x509/0x9b0 net/core/dev.c:3011 validate_xmit_skb+0x81/0xb00 net/core/dev.c:3084 validate_xmit_skb_list+0xbf/0x120 net/core/dev.c:3142 packet_direct_xmit+0x117/0x790 net/packet/af_packet.c:256 packet_snd net/packet/af_packet.c:2944 [inline] packet_sendmsg+0x3aed/0x60b0 net/packet/af_packet.c:2969 sock_sendmsg_nosec net/socket.c:629 [inline] sock_sendmsg+0xca/0x110 net/socket.c:639 ___sys_sendmsg+0x767/0x8b0 net/socket.c:2047 __sys_sendmsg+0xe5/0x210 net/socket.c:2081 Fixes: 19acc327258a ("gso: Handle Trans-Ether-Bridging protocol in skb_network_protocol()") Signed-off-by: Eric Dumazet Cc: Pravin B Shelar Reported-by: Reported-by: syzbot Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/core/dev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/core/dev.c b/net/core/dev.c index 387af3415385..ef3337bb71a2 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -2696,7 +2696,7 @@ __be16 skb_network_protocol(struct sk_buff *skb, int *depth) if (unlikely(!pskb_may_pull(skb, sizeof(struct ethhdr)))) return 0; - eth = (struct ethhdr *)skb_mac_header(skb); + eth = (struct ethhdr *)skb->data; type = eth->h_proto; } -- GitLab From d1b820bd98a18ace891099465005d937e7ef992d Mon Sep 17 00:00:00 2001 From: David Ahern Date: Thu, 29 Mar 2018 17:44:57 -0700 Subject: [PATCH 0280/1635] net/ipv6: Fix route leaking between VRFs [ Upstream commit b6cdbc85234b072340b8923e69f49ec293f905dc ] Donald reported that IPv6 route leaking between VRFs is not working. The root cause is the strict argument in the call to rt6_lookup when validating the nexthop spec. ip6_route_check_nh validates the gateway and device (if given) of a route spec. It in turn could call rt6_lookup (e.g., lookup in a given table did not succeed so it falls back to a full lookup) and if so sets the strict argument to 1. That means if the egress device is given, the route lookup needs to return a result with the same device. This strict requirement does not work with VRFs (IPv4 or IPv6) because the oif in the flow struct is overridden with the index of the VRF device to trigger a match on the l3mdev rule and force the lookup to its table. The right long term solution is to add an l3mdev index to the flow struct such that the oif is not overridden. That solution will not backport well, so this patch aims for a simpler solution to relax the strict argument if the route spec device is an l3mdev slave. As done in other places, use the FLOWI_FLAG_SKIP_NH_OIF to know that the RT6_LOOKUP_F_IFACE flag needs to be removed. Fixes: ca254490c8df ("net: Add VRF support to IPv6 stack") Reported-by: Donald Sharp Signed-off-by: David Ahern Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv6/route.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/net/ipv6/route.c b/net/ipv6/route.c index a4a865c8a23c..0126d9bfa670 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -871,6 +871,9 @@ static struct rt6_info *ip6_pol_route_lookup(struct net *net, struct fib6_node *fn; struct rt6_info *rt; + if (fl6->flowi6_flags & FLOWI_FLAG_SKIP_NH_OIF) + flags &= ~RT6_LOOKUP_F_IFACE; + read_lock_bh(&table->tb6_lock); fn = fib6_lookup(&table->tb6_root, &fl6->daddr, &fl6->saddr); restart: -- GitLab From 7948bc92791baac09957a20c70a73a0bfe7b1209 Mon Sep 17 00:00:00 2001 From: Jeff Barnhill <0xeffeff@gmail.com> Date: Thu, 5 Apr 2018 21:29:47 +0000 Subject: [PATCH 0281/1635] net/ipv6: Increment OUTxxx counters after netfilter hook [ Upstream commit 71a1c915238c970cd9bdd5bf158b1279d6b6d55b ] At the end of ip6_forward(), IPSTATS_MIB_OUTFORWDATAGRAMS and IPSTATS_MIB_OUTOCTETS are incremented immediately before the NF_HOOK call for NFPROTO_IPV6 / NF_INET_FORWARD. As a result, these counters get incremented regardless of whether or not the netfilter hook allows the packet to continue being processed. This change increments the counters in ip6_forward_finish() so that it will not happen if the netfilter hook chooses to terminate the packet, which is similar to how IPv4 works. Signed-off-by: Jeff Barnhill <0xeffeff@gmail.com> Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv6/ip6_output.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index 75b8c8a4374c..ffbb81609016 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -375,6 +375,11 @@ static int ip6_forward_proxy_check(struct sk_buff *skb) static inline int ip6_forward_finish(struct net *net, struct sock *sk, struct sk_buff *skb) { + struct dst_entry *dst = skb_dst(skb); + + __IP6_INC_STATS(net, ip6_dst_idev(dst), IPSTATS_MIB_OUTFORWDATAGRAMS); + __IP6_ADD_STATS(net, ip6_dst_idev(dst), IPSTATS_MIB_OUTOCTETS, skb->len); + return dst_output(net, sk, skb); } @@ -568,8 +573,6 @@ int ip6_forward(struct sk_buff *skb) hdr->hop_limit--; - __IP6_INC_STATS(net, ip6_dst_idev(dst), IPSTATS_MIB_OUTFORWDATAGRAMS); - __IP6_ADD_STATS(net, ip6_dst_idev(dst), IPSTATS_MIB_OUTOCTETS, skb->len); return NF_HOOK(NFPROTO_IPV6, NF_INET_FORWARD, net, NULL, skb, skb->dev, dst->dev, ip6_forward_finish); -- GitLab From 787b940625ca497ef6ecfecdadc16311c519d034 Mon Sep 17 00:00:00 2001 From: Alexander Potapenko Date: Fri, 23 Mar 2018 13:49:02 +0100 Subject: [PATCH 0282/1635] netlink: make sure nladdr has correct size in netlink_connect() [ Upstream commit 7880287981b60a6808f39f297bb66936e8bdf57a ] KMSAN reports use of uninitialized memory in the case when |alen| is smaller than sizeof(struct sockaddr_nl), and therefore |nladdr| isn't fully copied from the userspace. Signed-off-by: Alexander Potapenko Fixes: 1da177e4c3f41524 ("Linux-2.6.12-rc2") Reviewed-by: Eric Dumazet Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/netlink/af_netlink.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index 9219bc134109..1b86eccf94b6 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -1053,6 +1053,9 @@ static int netlink_connect(struct socket *sock, struct sockaddr *addr, if (addr->sa_family != AF_NETLINK) return -EINVAL; + if (alen < sizeof(struct sockaddr_nl)) + return -EINVAL; + if ((nladdr->nl_groups || nladdr->nl_pid) && !netlink_allowed(sock, NL_CFG_F_NONROOT_SEND)) return -EPERM; -- GitLab From cd19a9b12ab49414777393e9935455a17852e172 Mon Sep 17 00:00:00 2001 From: Craig Dillabaugh Date: Mon, 26 Mar 2018 14:58:32 -0400 Subject: [PATCH 0283/1635] net sched actions: fix dumping which requires several messages to user space [ Upstream commit 734549eb550c0c720bc89e50501f1b1e98cdd841 ] Fixes a bug in the tcf_dump_walker function that can cause some actions to not be reported when dumping a large number of actions. This issue became more aggrevated when cookies feature was added. In particular this issue is manifest when large cookie values are assigned to the actions and when enough actions are created that the resulting table must be dumped in multiple batches. The number of actions returned in each batch is limited by the total number of actions and the memory buffer size. With small cookies the numeric limit is reached before the buffer size limit, which avoids the code path triggering this bug. When large cookies are used buffer fills before the numeric limit, and the erroneous code path is hit. For example after creating 32 csum actions with the cookie aaaabbbbccccdddd $ tc actions ls action csum total acts 26 action order 0: csum (tcp) action continue index 1 ref 1 bind 0 cookie aaaabbbbccccdddd ..... action order 25: csum (tcp) action continue index 26 ref 1 bind 0 cookie aaaabbbbccccdddd total acts 6 action order 0: csum (tcp) action continue index 28 ref 1 bind 0 cookie aaaabbbbccccdddd ...... action order 5: csum (tcp) action continue index 32 ref 1 bind 0 cookie aaaabbbbccccdddd Note that the action with index 27 is omitted from the report. Fixes: 4b3550ef530c ("[NET_SCHED]: Use nla_nest_start/nla_nest_end")" Signed-off-by: Craig Dillabaugh Acked-by: Jamal Hadi Salim Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/sched/act_api.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/net/sched/act_api.c b/net/sched/act_api.c index 8f2c63514956..4444d7e755e6 100644 --- a/net/sched/act_api.c +++ b/net/sched/act_api.c @@ -133,8 +133,10 @@ static int tcf_dump_walker(struct tcf_idrinfo *idrinfo, struct sk_buff *skb, continue; nest = nla_nest_start(skb, n_i); - if (!nest) + if (!nest) { + index--; goto nla_put_failure; + } err = tcf_action_dump_1(skb, p, 0, 0); if (err < 0) { index--; -- GitLab From 21563c4df30e284e881faa8e7966806003e6d0dd Mon Sep 17 00:00:00 2001 From: Davide Caratti Date: Fri, 6 Apr 2018 01:19:37 +0200 Subject: [PATCH 0284/1635] net/sched: fix NULL dereference in the error path of tcf_bpf_init() [ Upstream commit 3239534a79ee6f20cffd974173a1e62e0730e8ac ] when tcf_bpf_init_from_ops() fails (e.g. because of program having invalid number of instructions), tcf_bpf_cfg_cleanup() calls bpf_prog_put(NULL) or bpf_prog_destroy(NULL). Unless CONFIG_BPF_SYSCALL is unset, this causes the following error: BUG: unable to handle kernel NULL pointer dereference at 0000000000000020 PGD 800000007345a067 P4D 800000007345a067 PUD 340e1067 PMD 0 Oops: 0000 [#1] SMP PTI Modules linked in: act_bpf(E) ip6table_filter ip6_tables iptable_filter binfmt_misc ext4 mbcache jbd2 crct10dif_pclmul crc32_pclmul ghash_clmulni_intel snd_hda_codec_generic pcbc snd_hda_intel snd_hda_codec snd_hda_core snd_hwdep snd_seq snd_seq_device snd_pcm aesni_intel crypto_simd glue_helper cryptd joydev snd_timer snd virtio_balloon pcspkr soundcore i2c_piix4 nfsd auth_rpcgss nfs_acl lockd grace sunrpc ip_tables xfs libcrc32c ata_generic pata_acpi qxl drm_kms_helper syscopyarea sysfillrect sysimgblt fb_sys_fops ttm virtio_blk drm virtio_net virtio_console i2c_core crc32c_intel serio_raw virtio_pci ata_piix libata virtio_ring floppy virtio dm_mirror dm_region_hash dm_log dm_mod [last unloaded: act_bpf] CPU: 3 PID: 5654 Comm: tc Tainted: G E 4.16.0.bpf_test+ #408 Hardware name: Red Hat KVM, BIOS 0.5.1 01/01/2011 RIP: 0010:__bpf_prog_put+0xc/0xc0 RSP: 0018:ffff9594003ef728 EFLAGS: 00010202 RAX: 0000000000000000 RBX: ffff9594003ef758 RCX: 0000000000000024 RDX: 0000000000000000 RSI: 0000000000000001 RDI: 0000000000000000 RBP: 0000000000000000 R08: 0000000000000001 R09: 0000000000000044 R10: 0000000000000220 R11: ffff8a7ab9f17131 R12: 0000000000000000 R13: ffff8a7ab7c3c8e0 R14: 0000000000000001 R15: ffff8a7ab88f1054 FS: 00007fcb2f17c740(0000) GS:ffff8a7abfd80000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 0000000000000020 CR3: 000000007c888006 CR4: 00000000001606e0 Call Trace: tcf_bpf_cfg_cleanup+0x2f/0x40 [act_bpf] tcf_bpf_cleanup+0x4c/0x70 [act_bpf] __tcf_idr_release+0x79/0x140 tcf_bpf_init+0x125/0x330 [act_bpf] tcf_action_init_1+0x2cc/0x430 ? get_page_from_freelist+0x3f0/0x11b0 tcf_action_init+0xd3/0x1b0 tc_ctl_action+0x18b/0x240 rtnetlink_rcv_msg+0x29c/0x310 ? _cond_resched+0x15/0x30 ? __kmalloc_node_track_caller+0x1b9/0x270 ? rtnl_calcit.isra.29+0x100/0x100 netlink_rcv_skb+0xd2/0x110 netlink_unicast+0x17c/0x230 netlink_sendmsg+0x2cd/0x3c0 sock_sendmsg+0x30/0x40 ___sys_sendmsg+0x27a/0x290 ? mem_cgroup_commit_charge+0x80/0x130 ? page_add_new_anon_rmap+0x73/0xc0 ? do_anonymous_page+0x2a2/0x560 ? __handle_mm_fault+0xc75/0xe20 __sys_sendmsg+0x58/0xa0 do_syscall_64+0x6e/0x1a0 entry_SYSCALL_64_after_hwframe+0x3d/0xa2 RIP: 0033:0x7fcb2e58eba0 RSP: 002b:00007ffc93c496c8 EFLAGS: 00000246 ORIG_RAX: 000000000000002e RAX: ffffffffffffffda RBX: 00007ffc93c497f0 RCX: 00007fcb2e58eba0 RDX: 0000000000000000 RSI: 00007ffc93c49740 RDI: 0000000000000003 RBP: 000000005ac6a646 R08: 0000000000000002 R09: 0000000000000000 R10: 00007ffc93c49120 R11: 0000000000000246 R12: 0000000000000000 R13: 00007ffc93c49804 R14: 0000000000000001 R15: 000000000066afa0 Code: 5f 00 48 8b 43 20 48 c7 c7 70 2f 7c b8 c7 40 10 00 00 00 00 5b e9 a5 8b 61 00 0f 1f 44 00 00 0f 1f 44 00 00 41 54 55 48 89 fd 53 <48> 8b 47 20 f0 ff 08 74 05 5b 5d 41 5c c3 41 89 f4 0f 1f 44 00 RIP: __bpf_prog_put+0xc/0xc0 RSP: ffff9594003ef728 CR2: 0000000000000020 Fix it in tcf_bpf_cfg_cleanup(), ensuring that bpf_prog_{put,destroy}(f) is called only when f is not NULL. Fixes: bbc09e7842a5 ("net/sched: fix idr leak on the error path of tcf_bpf_init()") Reported-by: Lucas Bates Signed-off-by: Davide Caratti Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/sched/act_bpf.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/net/sched/act_bpf.c b/net/sched/act_bpf.c index c0c707eb2c96..2b087623fb1d 100644 --- a/net/sched/act_bpf.c +++ b/net/sched/act_bpf.c @@ -248,10 +248,14 @@ static int tcf_bpf_init_from_efd(struct nlattr **tb, struct tcf_bpf_cfg *cfg) static void tcf_bpf_cfg_cleanup(const struct tcf_bpf_cfg *cfg) { - if (cfg->is_ebpf) - bpf_prog_put(cfg->filter); - else - bpf_prog_destroy(cfg->filter); + struct bpf_prog *filter = cfg->filter; + + if (filter) { + if (cfg->is_ebpf) + bpf_prog_put(filter); + else + bpf_prog_destroy(filter); + } kfree(cfg->bpf_ops); kfree(cfg->bpf_name); -- GitLab From a7c8900c1fc2ee872810234c938f051873cc3eba Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Mon, 2 Apr 2018 18:48:37 -0700 Subject: [PATCH 0285/1635] pptp: remove a buggy dst release in pptp_connect() [ Upstream commit bfacfb457b36911a10140b8cb3ce76a74883ac5a ] Once dst has been cached in socket via sk_setup_caps(), it is illegal to call ip_rt_put() (or dst_release()), since sk_setup_caps() did not change dst refcount. We can still dereference it since we hold socket lock. Caugth by syzbot : BUG: KASAN: use-after-free in atomic_dec_return include/asm-generic/atomic-instrumented.h:198 [inline] BUG: KASAN: use-after-free in dst_release+0x27/0xa0 net/core/dst.c:185 Write of size 4 at addr ffff8801c54dc040 by task syz-executor4/20088 CPU: 1 PID: 20088 Comm: syz-executor4 Not tainted 4.16.0+ #376 Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/01/2011 Call Trace: __dump_stack lib/dump_stack.c:17 [inline] dump_stack+0x1a7/0x27d lib/dump_stack.c:53 print_address_description+0x73/0x250 mm/kasan/report.c:256 kasan_report_error mm/kasan/report.c:354 [inline] kasan_report+0x23c/0x360 mm/kasan/report.c:412 check_memory_region_inline mm/kasan/kasan.c:260 [inline] check_memory_region+0x137/0x190 mm/kasan/kasan.c:267 kasan_check_write+0x14/0x20 mm/kasan/kasan.c:278 atomic_dec_return include/asm-generic/atomic-instrumented.h:198 [inline] dst_release+0x27/0xa0 net/core/dst.c:185 sk_dst_set include/net/sock.h:1812 [inline] sk_dst_reset include/net/sock.h:1824 [inline] sock_setbindtodevice net/core/sock.c:610 [inline] sock_setsockopt+0x431/0x1b20 net/core/sock.c:707 SYSC_setsockopt net/socket.c:1845 [inline] SyS_setsockopt+0x2ff/0x360 net/socket.c:1828 do_syscall_64+0x281/0x940 arch/x86/entry/common.c:287 entry_SYSCALL_64_after_hwframe+0x42/0xb7 RIP: 0033:0x4552d9 RSP: 002b:00007f4878126c68 EFLAGS: 00000246 ORIG_RAX: 0000000000000036 RAX: ffffffffffffffda RBX: 00007f48781276d4 RCX: 00000000004552d9 RDX: 0000000000000019 RSI: 0000000000000001 RDI: 0000000000000013 RBP: 000000000072bea0 R08: 0000000000000010 R09: 0000000000000000 R10: 00000000200010c0 R11: 0000000000000246 R12: 00000000ffffffff R13: 0000000000000526 R14: 00000000006fac30 R15: 0000000000000000 Allocated by task 20088: save_stack+0x43/0xd0 mm/kasan/kasan.c:447 set_track mm/kasan/kasan.c:459 [inline] kasan_kmalloc+0xad/0xe0 mm/kasan/kasan.c:552 kasan_slab_alloc+0x12/0x20 mm/kasan/kasan.c:489 kmem_cache_alloc+0x12e/0x760 mm/slab.c:3542 dst_alloc+0x11f/0x1a0 net/core/dst.c:104 rt_dst_alloc+0xe9/0x540 net/ipv4/route.c:1520 __mkroute_output net/ipv4/route.c:2265 [inline] ip_route_output_key_hash_rcu+0xa49/0x2c60 net/ipv4/route.c:2493 ip_route_output_key_hash+0x20b/0x370 net/ipv4/route.c:2322 __ip_route_output_key include/net/route.h:126 [inline] ip_route_output_flow+0x26/0xa0 net/ipv4/route.c:2577 ip_route_output_ports include/net/route.h:163 [inline] pptp_connect+0xa84/0x1170 drivers/net/ppp/pptp.c:453 SYSC_connect+0x213/0x4a0 net/socket.c:1639 SyS_connect+0x24/0x30 net/socket.c:1620 do_syscall_64+0x281/0x940 arch/x86/entry/common.c:287 entry_SYSCALL_64_after_hwframe+0x42/0xb7 Freed by task 20082: save_stack+0x43/0xd0 mm/kasan/kasan.c:447 set_track mm/kasan/kasan.c:459 [inline] __kasan_slab_free+0x11a/0x170 mm/kasan/kasan.c:520 kasan_slab_free+0xe/0x10 mm/kasan/kasan.c:527 __cache_free mm/slab.c:3486 [inline] kmem_cache_free+0x83/0x2a0 mm/slab.c:3744 dst_destroy+0x266/0x380 net/core/dst.c:140 dst_destroy_rcu+0x16/0x20 net/core/dst.c:153 __rcu_reclaim kernel/rcu/rcu.h:178 [inline] rcu_do_batch kernel/rcu/tree.c:2675 [inline] invoke_rcu_callbacks kernel/rcu/tree.c:2930 [inline] __rcu_process_callbacks kernel/rcu/tree.c:2897 [inline] rcu_process_callbacks+0xd6c/0x17b0 kernel/rcu/tree.c:2914 __do_softirq+0x2d7/0xb85 kernel/softirq.c:285 The buggy address belongs to the object at ffff8801c54dc000 which belongs to the cache ip_dst_cache of size 168 The buggy address is located 64 bytes inside of 168-byte region [ffff8801c54dc000, ffff8801c54dc0a8) The buggy address belongs to the page: page:ffffea0007153700 count:1 mapcount:0 mapping:ffff8801c54dc000 index:0x0 flags: 0x2fffc0000000100(slab) raw: 02fffc0000000100 ffff8801c54dc000 0000000000000000 0000000100000010 raw: ffffea0006b34b20 ffffea0006b6c1e0 ffff8801d674a1c0 0000000000000000 page dumped because: kasan: bad access detected Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/ppp/pptp.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/ppp/pptp.c b/drivers/net/ppp/pptp.c index 6dde9a0cfe76..9b70a3af678e 100644 --- a/drivers/net/ppp/pptp.c +++ b/drivers/net/ppp/pptp.c @@ -464,7 +464,6 @@ static int pptp_connect(struct socket *sock, struct sockaddr *uservaddr, po->chan.mtu = dst_mtu(&rt->dst); if (!po->chan.mtu) po->chan.mtu = PPP_MRU; - ip_rt_put(rt); po->chan.mtu -= PPTP_HEADER_OVERHEAD; po->chan.hdrlen = 2 + sizeof(struct pptp_gre_header); -- GitLab From c17f6594abfa8646da11c93e5e4a49ae73f253fc Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Mon, 26 Mar 2018 19:19:30 +0200 Subject: [PATCH 0286/1635] r8169: fix setting driver_data after register_netdev [ Upstream commit 19c9ea363a244f85f90a424f9936e6d56449e33c ] pci_set_drvdata() is called only after registering the net_device, therefore we could run into a NPE if one of the functions using driver_data is called before it's set. Fix this by calling pci_set_drvdata() before registering the net_device. This fix is a candidate for stable. As far as I can see the bug has been there in kernel version 3.2 already, therefore I can't provide a reference which commit is fixed by it. The fix may need small adjustments per kernel version because due to other changes the label which is jumped to if register_netdev() fails has changed over time. Reported-by: David Miller Signed-off-by: Heiner Kallweit Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/realtek/r8169.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/realtek/r8169.c b/drivers/net/ethernet/realtek/r8169.c index 619a1b7281a0..db553d4e8d22 100644 --- a/drivers/net/ethernet/realtek/r8169.c +++ b/drivers/net/ethernet/realtek/r8169.c @@ -8466,12 +8466,12 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) goto err_out_msi_5; } + pci_set_drvdata(pdev, dev); + rc = register_netdev(dev); if (rc < 0) goto err_out_cnt_6; - pci_set_drvdata(pdev, dev); - netif_info(tp, probe, dev, "%s at 0x%p, %pM, XID %08x IRQ %d\n", rtl_chip_infos[chipset].name, ioaddr, dev->dev_addr, (u32)(RTL_R32(TxConfig) & 0x9cf0f8ff), pdev->irq); -- GitLab From 3f80d01bbd87b400aad825268bbf8fc80ff78916 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Sat, 7 Apr 2018 17:15:22 -0700 Subject: [PATCH 0287/1635] sctp: do not leak kernel memory to user space [ Upstream commit 6780db244d6b1537d139dea0ec8aad10cf9e4adb ] syzbot produced a nice report [1] Issue here is that a recvmmsg() managed to leak 8 bytes of kernel memory to user space, because sin_zero (padding field) was not properly cleared. [1] BUG: KMSAN: uninit-value in copy_to_user include/linux/uaccess.h:184 [inline] BUG: KMSAN: uninit-value in move_addr_to_user+0x32e/0x530 net/socket.c:227 CPU: 1 PID: 3586 Comm: syzkaller481044 Not tainted 4.16.0+ #82 Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/01/2011 Call Trace: __dump_stack lib/dump_stack.c:17 [inline] dump_stack+0x185/0x1d0 lib/dump_stack.c:53 kmsan_report+0x142/0x240 mm/kmsan/kmsan.c:1067 kmsan_internal_check_memory+0x164/0x1d0 mm/kmsan/kmsan.c:1176 kmsan_copy_to_user+0x69/0x160 mm/kmsan/kmsan.c:1199 copy_to_user include/linux/uaccess.h:184 [inline] move_addr_to_user+0x32e/0x530 net/socket.c:227 ___sys_recvmsg+0x4e2/0x810 net/socket.c:2211 __sys_recvmmsg+0x54e/0xdb0 net/socket.c:2313 SYSC_recvmmsg+0x29b/0x3e0 net/socket.c:2394 SyS_recvmmsg+0x76/0xa0 net/socket.c:2378 do_syscall_64+0x309/0x430 arch/x86/entry/common.c:287 entry_SYSCALL_64_after_hwframe+0x3d/0xa2 RIP: 0033:0x4401c9 RSP: 002b:00007ffc56f73098 EFLAGS: 00000217 ORIG_RAX: 000000000000012b RAX: ffffffffffffffda RBX: 00000000004002c8 RCX: 00000000004401c9 RDX: 0000000000000001 RSI: 0000000020003ac0 RDI: 0000000000000003 RBP: 00000000006ca018 R08: 0000000020003bc0 R09: 0000000000000010 R10: 0000000000000000 R11: 0000000000000217 R12: 0000000000401af0 R13: 0000000000401b80 R14: 0000000000000000 R15: 0000000000000000 Local variable description: ----addr@___sys_recvmsg Variable was created at: ___sys_recvmsg+0xd5/0x810 net/socket.c:2172 __sys_recvmmsg+0x54e/0xdb0 net/socket.c:2313 Bytes 8-15 of 16 are uninitialized ================================================================== Kernel panic - not syncing: panic_on_warn set ... CPU: 1 PID: 3586 Comm: syzkaller481044 Tainted: G B 4.16.0+ #82 Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/01/2011 Call Trace: __dump_stack lib/dump_stack.c:17 [inline] dump_stack+0x185/0x1d0 lib/dump_stack.c:53 panic+0x39d/0x940 kernel/panic.c:183 kmsan_report+0x238/0x240 mm/kmsan/kmsan.c:1083 kmsan_internal_check_memory+0x164/0x1d0 mm/kmsan/kmsan.c:1176 kmsan_copy_to_user+0x69/0x160 mm/kmsan/kmsan.c:1199 copy_to_user include/linux/uaccess.h:184 [inline] move_addr_to_user+0x32e/0x530 net/socket.c:227 ___sys_recvmsg+0x4e2/0x810 net/socket.c:2211 __sys_recvmmsg+0x54e/0xdb0 net/socket.c:2313 SYSC_recvmmsg+0x29b/0x3e0 net/socket.c:2394 SyS_recvmmsg+0x76/0xa0 net/socket.c:2378 do_syscall_64+0x309/0x430 arch/x86/entry/common.c:287 entry_SYSCALL_64_after_hwframe+0x3d/0xa2 Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Signed-off-by: Eric Dumazet Cc: Vlad Yasevich Cc: Neil Horman Reported-by: syzbot Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/sctp/ipv6.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c index f27a9718554c..08b5705e7381 100644 --- a/net/sctp/ipv6.c +++ b/net/sctp/ipv6.c @@ -728,8 +728,10 @@ static int sctp_v6_addr_to_user(struct sctp_sock *sp, union sctp_addr *addr) sctp_v6_map_v4(addr); } - if (addr->sa.sa_family == AF_INET) + if (addr->sa.sa_family == AF_INET) { + memset(addr->v4.sin_zero, 0, sizeof(addr->v4.sin_zero)); return sizeof(struct sockaddr_in); + } return sizeof(struct sockaddr_in6); } -- GitLab From 3fdd43709d705727ed4e1c77c7f30989fcae013c Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Sun, 8 Apr 2018 07:52:08 -0700 Subject: [PATCH 0288/1635] sctp: sctp_sockaddr_af must check minimal addr length for AF_INET6 [ Upstream commit 81e98370293afcb58340ce8bd71af7b97f925c26 ] Check must happen before call to ipv6_addr_v4mapped() syzbot report was : BUG: KMSAN: uninit-value in sctp_sockaddr_af net/sctp/socket.c:359 [inline] BUG: KMSAN: uninit-value in sctp_do_bind+0x60f/0xdc0 net/sctp/socket.c:384 CPU: 0 PID: 3576 Comm: syzkaller968804 Not tainted 4.16.0+ #82 Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/01/2011 Call Trace: __dump_stack lib/dump_stack.c:17 [inline] dump_stack+0x185/0x1d0 lib/dump_stack.c:53 kmsan_report+0x142/0x240 mm/kmsan/kmsan.c:1067 __msan_warning_32+0x6c/0xb0 mm/kmsan/kmsan_instr.c:676 sctp_sockaddr_af net/sctp/socket.c:359 [inline] sctp_do_bind+0x60f/0xdc0 net/sctp/socket.c:384 sctp_bind+0x149/0x190 net/sctp/socket.c:332 inet6_bind+0x1fd/0x1820 net/ipv6/af_inet6.c:293 SYSC_bind+0x3f2/0x4b0 net/socket.c:1474 SyS_bind+0x54/0x80 net/socket.c:1460 do_syscall_64+0x309/0x430 arch/x86/entry/common.c:287 entry_SYSCALL_64_after_hwframe+0x3d/0xa2 RIP: 0033:0x43fd49 RSP: 002b:00007ffe99df3d28 EFLAGS: 00000213 ORIG_RAX: 0000000000000031 RAX: ffffffffffffffda RBX: 00000000004002c8 RCX: 000000000043fd49 RDX: 0000000000000010 RSI: 0000000020000000 RDI: 0000000000000003 RBP: 00000000006ca018 R08: 00000000004002c8 R09: 00000000004002c8 R10: 00000000004002c8 R11: 0000000000000213 R12: 0000000000401670 R13: 0000000000401700 R14: 0000000000000000 R15: 0000000000000000 Local variable description: ----address@SYSC_bind Variable was created at: SYSC_bind+0x6f/0x4b0 net/socket.c:1461 SyS_bind+0x54/0x80 net/socket.c:1460 Signed-off-by: Eric Dumazet Cc: Vlad Yasevich Cc: Neil Horman Reported-by: syzbot Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/sctp/socket.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 6b3a862706de..2d6f612f32c3 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -337,11 +337,14 @@ static struct sctp_af *sctp_sockaddr_af(struct sctp_sock *opt, if (!opt->pf->af_supported(addr->sa.sa_family, opt)) return NULL; - /* V4 mapped address are really of AF_INET family */ - if (addr->sa.sa_family == AF_INET6 && - ipv6_addr_v4mapped(&addr->v6.sin6_addr) && - !opt->pf->af_supported(AF_INET, opt)) - return NULL; + if (addr->sa.sa_family == AF_INET6) { + if (len < SIN6_LEN_RFC2133) + return NULL; + /* V4 mapped address are really of AF_INET family */ + if (ipv6_addr_v4mapped(&addr->v6.sin6_addr) && + !opt->pf->af_supported(AF_INET, opt)) + return NULL; + } /* If we get this far, af is valid. */ af = sctp_get_af_specific(addr->sa.sa_family); -- GitLab From c5fc4dc51cb04913100323b3c9864bfaca229530 Mon Sep 17 00:00:00 2001 From: Kai-Heng Feng Date: Sat, 31 Mar 2018 23:42:03 +0800 Subject: [PATCH 0289/1635] sky2: Increase D3 delay to sky2 stops working after suspend [ Upstream commit afb133637071be6deeb8b3d0e55593ffbf63c527 ] The sky2 ethernet stops working after system resume from suspend: [ 582.852065] sky2 0000:04:00.0: Refused to change power state, currently in D3 The current 150ms delay is not enough, change it to 200ms can solve the issue. BugLink: https://bugs.launchpad.net/bugs/1758507 Cc: Stable Signed-off-by: Kai-Heng Feng Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/marvell/sky2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/marvell/sky2.c b/drivers/net/ethernet/marvell/sky2.c index 1145cde2274a..b12e3a4f9439 100644 --- a/drivers/net/ethernet/marvell/sky2.c +++ b/drivers/net/ethernet/marvell/sky2.c @@ -5087,7 +5087,7 @@ static int sky2_probe(struct pci_dev *pdev, const struct pci_device_id *ent) INIT_WORK(&hw->restart_work, sky2_restart); pci_set_drvdata(pdev, hw); - pdev->d3_delay = 150; + pdev->d3_delay = 200; return 0; -- GitLab From 4f288c97b5c5c8741144ad00ec7edf44e8bd8997 Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Tue, 27 Mar 2018 20:50:52 +0800 Subject: [PATCH 0290/1635] vhost: correctly remove wait queue during poll failure [ Upstream commit dc6455a71c7fc5117977e197f67f71b49f27baba ] We tried to remove vq poll from wait queue, but do not check whether or not it was in a list before. This will lead double free. Fixing this by switching to use vhost_poll_stop() which zeros poll->wqh after removing poll from waitqueue to make sure it won't be freed twice. Cc: Darren Kenny Reported-by: syzbot+c0272972b01b872e604a@syzkaller.appspotmail.com Fixes: 2b8b328b61c79 ("vhost_net: handle polling errors when setting backend") Signed-off-by: Jason Wang Reviewed-by: Darren Kenny Acked-by: Michael S. Tsirkin Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/vhost/vhost.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c index a827c1a684a9..c1033dc0e3f5 100644 --- a/drivers/vhost/vhost.c +++ b/drivers/vhost/vhost.c @@ -213,8 +213,7 @@ int vhost_poll_start(struct vhost_poll *poll, struct file *file) if (mask) vhost_poll_wakeup(&poll->wait, 0, 0, (void *)mask); if (mask & POLLERR) { - if (poll->wqh) - remove_wait_queue(poll->wqh, &poll->wait); + vhost_poll_stop(poll); ret = -EINVAL; } -- GitLab From 09cb8267add584dc494683989c5ed6881be00ad7 Mon Sep 17 00:00:00 2001 From: Hangbin Liu Date: Fri, 30 Mar 2018 09:44:00 +0800 Subject: [PATCH 0291/1635] vlan: also check phy_driver ts_info for vlan's real device [ Upstream commit ec1d8ccb07deaf30fd0508af6755364ac47dc08d ] Just like function ethtool_get_ts_info(), we should also consider the phy_driver ts_info call back. For example, driver dp83640. Fixes: 37dd9255b2f6 ("vlan: Pass ethtool get_ts_info queries to real device.") Acked-by: Richard Cochran Signed-off-by: Hangbin Liu Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/8021q/vlan_dev.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c index f7e83f6d2e64..236452ebbd9e 100644 --- a/net/8021q/vlan_dev.c +++ b/net/8021q/vlan_dev.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -665,8 +666,11 @@ static int vlan_ethtool_get_ts_info(struct net_device *dev, { const struct vlan_dev_priv *vlan = vlan_dev_priv(dev); const struct ethtool_ops *ops = vlan->real_dev->ethtool_ops; + struct phy_device *phydev = vlan->real_dev->phydev; - if (ops->get_ts_info) { + if (phydev && phydev->drv && phydev->drv->ts_info) { + return phydev->drv->ts_info(phydev, info); + } else if (ops->get_ts_info) { return ops->get_ts_info(vlan->real_dev, info); } else { info->so_timestamping = SOF_TIMESTAMPING_RX_SOFTWARE | -- GitLab From 65c42a2d475d904688436a50aa596f643671461f Mon Sep 17 00:00:00 2001 From: David Ahern Date: Thu, 29 Mar 2018 12:49:52 -0700 Subject: [PATCH 0292/1635] vrf: Fix use after free and double free in vrf_finish_output [ Upstream commit 82dd0d2a9a76fc8fa2b18d80b987d455728bf83a ] Miguel reported an skb use after free / double free in vrf_finish_output when neigh_output returns an error. The vrf driver should return after the call to neigh_output as it takes over the skb on error path as well. Patch is a simplified version of Miguel's patch which was written for 4.9, and updated to top of tree. Fixes: 8f58336d3f78a ("net: Add ethernet header for pass through VRF device") Signed-off-by: Miguel Fadon Perlines Signed-off-by: David Ahern Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/vrf.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/net/vrf.c b/drivers/net/vrf.c index 67ecf2425b88..5c6a8ef54aec 100644 --- a/drivers/net/vrf.c +++ b/drivers/net/vrf.c @@ -579,12 +579,13 @@ static int vrf_finish_output(struct net *net, struct sock *sk, struct sk_buff *s if (!IS_ERR(neigh)) { sock_confirm_neigh(skb, neigh); ret = neigh_output(neigh, skb); + rcu_read_unlock_bh(); + return ret; } rcu_read_unlock_bh(); err: - if (unlikely(ret < 0)) - vrf_tx_error(skb->dev, skb); + vrf_tx_error(skb->dev, skb); return ret; } -- GitLab From d7e7ab42581ee12537092e6d005d78a8295fce14 Mon Sep 17 00:00:00 2001 From: Xin Long Date: Mon, 26 Mar 2018 01:16:45 +0800 Subject: [PATCH 0293/1635] bonding: fix the err path for dev hwaddr sync in bond_enslave [ Upstream commit 5c78f6bfae2b10ff70e21d343e64584ea6280c26 ] vlan_vids_add_by_dev is called right after dev hwaddr sync, so on the err path it should unsync dev hwaddr. Otherwise, the slave dev's hwaddr will never be unsync when this err happens. Fixes: 1ff412ad7714 ("bonding: change the bond's vlan syncing functions with the standard ones") Signed-off-by: Xin Long Reviewed-by: Nikolay Aleksandrov Acked-by: Andy Gospodarek Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/bonding/bond_main.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index b2db581131b2..5c99c0f1f01d 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -1561,7 +1561,7 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) if (res) { netdev_err(bond_dev, "Couldn't add bond vlan ids to %s\n", slave_dev->name); - goto err_close; + goto err_hwaddr_unsync; } prev_slave = bond_last_slave(bond); @@ -1751,9 +1751,6 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) netdev_rx_handler_unregister(slave_dev); err_detach: - if (!bond_uses_primary(bond)) - bond_hw_addr_flush(bond_dev, slave_dev); - vlan_vids_del_by_dev(slave_dev, bond_dev); if (rcu_access_pointer(bond->primary_slave) == new_slave) RCU_INIT_POINTER(bond->primary_slave, NULL); @@ -1767,6 +1764,10 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) synchronize_rcu(); slave_disable_netpoll(new_slave); +err_hwaddr_unsync: + if (!bond_uses_primary(bond)) + bond_hw_addr_flush(bond_dev, slave_dev); + err_close: slave_dev->priv_flags &= ~IFF_BONDING; dev_close(slave_dev); -- GitLab From 22ab1f8751fa079b818d579cfb0bedfea5ba15e2 Mon Sep 17 00:00:00 2001 From: Xin Long Date: Mon, 26 Mar 2018 01:16:46 +0800 Subject: [PATCH 0294/1635] bonding: move dev_mc_sync after master_upper_dev_link in bond_enslave [ Upstream commit ae42cc62a9f07f1f6979054ed92606b9c30f4a2e ] Beniamino found a crash when adding vlan as slave of bond which is also the parent link: ip link add bond1 type bond ip link set bond1 up ip link add link bond1 vlan1 type vlan id 80 ip link set vlan1 master bond1 The call trace is as below: [] queued_spin_lock_slowpath+0xb/0xf [] _raw_spin_lock+0x20/0x30 [] dev_mc_sync+0x37/0x80 [] vlan_dev_set_rx_mode+0x1c/0x30 [8021q] [] __dev_set_rx_mode+0x5a/0xa0 [] dev_mc_sync_multiple+0x78/0x80 [] bond_enslave+0x67c/0x1190 [bonding] [] do_setlink+0x9c9/0xe50 [] rtnl_newlink+0x522/0x880 [] rtnetlink_rcv_msg+0xa7/0x260 [] netlink_rcv_skb+0xab/0xc0 [] rtnetlink_rcv+0x28/0x30 [] netlink_unicast+0x170/0x210 [] netlink_sendmsg+0x308/0x420 [] sock_sendmsg+0xb6/0xf0 This is actually a dead lock caused by sync slave hwaddr from master when the master is the slave's 'slave'. This dead loop check is actually done by netdev_master_upper_dev_link. However, Commit 1f718f0f4f97 ("bonding: populate neighbour's private on enslave") moved it after dev_mc_sync. This patch is to fix it by moving dev_mc_sync after master_upper_dev_link, so that this loop check would be earlier than dev_mc_sync. It also moves if (mode == BOND_MODE_8023AD) into if (!bond_uses_primary) clause as an improvement. Note team driver also has this issue, I will fix it in another patch. Fixes: 1f718f0f4f97 ("bonding: populate neighbour's private on enslave") Reported-by: Beniamino Galvani Signed-off-by: Xin Long Acked-by: Andy Gospodarek Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/bonding/bond_main.c | 73 ++++++++++++++++----------------- 1 file changed, 35 insertions(+), 38 deletions(-) diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 5c99c0f1f01d..b8701a07f4eb 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -1524,44 +1524,11 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) goto err_close; } - /* If the mode uses primary, then the following is handled by - * bond_change_active_slave(). - */ - if (!bond_uses_primary(bond)) { - /* set promiscuity level to new slave */ - if (bond_dev->flags & IFF_PROMISC) { - res = dev_set_promiscuity(slave_dev, 1); - if (res) - goto err_close; - } - - /* set allmulti level to new slave */ - if (bond_dev->flags & IFF_ALLMULTI) { - res = dev_set_allmulti(slave_dev, 1); - if (res) - goto err_close; - } - - netif_addr_lock_bh(bond_dev); - - dev_mc_sync_multiple(slave_dev, bond_dev); - dev_uc_sync_multiple(slave_dev, bond_dev); - - netif_addr_unlock_bh(bond_dev); - } - - if (BOND_MODE(bond) == BOND_MODE_8023AD) { - /* add lacpdu mc addr to mc list */ - u8 lacpdu_multicast[ETH_ALEN] = MULTICAST_LACPDU_ADDR; - - dev_mc_add(slave_dev, lacpdu_multicast); - } - res = vlan_vids_add_by_dev(slave_dev, bond_dev); if (res) { netdev_err(bond_dev, "Couldn't add bond vlan ids to %s\n", slave_dev->name); - goto err_hwaddr_unsync; + goto err_close; } prev_slave = bond_last_slave(bond); @@ -1721,6 +1688,37 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) goto err_upper_unlink; } + /* If the mode uses primary, then the following is handled by + * bond_change_active_slave(). + */ + if (!bond_uses_primary(bond)) { + /* set promiscuity level to new slave */ + if (bond_dev->flags & IFF_PROMISC) { + res = dev_set_promiscuity(slave_dev, 1); + if (res) + goto err_sysfs_del; + } + + /* set allmulti level to new slave */ + if (bond_dev->flags & IFF_ALLMULTI) { + res = dev_set_allmulti(slave_dev, 1); + if (res) + goto err_sysfs_del; + } + + netif_addr_lock_bh(bond_dev); + dev_mc_sync_multiple(slave_dev, bond_dev); + dev_uc_sync_multiple(slave_dev, bond_dev); + netif_addr_unlock_bh(bond_dev); + + if (BOND_MODE(bond) == BOND_MODE_8023AD) { + /* add lacpdu mc addr to mc list */ + u8 lacpdu_multicast[ETH_ALEN] = MULTICAST_LACPDU_ADDR; + + dev_mc_add(slave_dev, lacpdu_multicast); + } + } + bond->slave_cnt++; bond_compute_features(bond); bond_set_carrier(bond); @@ -1744,6 +1742,9 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) return 0; /* Undo stages on error */ +err_sysfs_del: + bond_sysfs_slave_del(new_slave); + err_upper_unlink: bond_upper_dev_unlink(bond, new_slave); @@ -1764,10 +1765,6 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) synchronize_rcu(); slave_disable_netpoll(new_slave); -err_hwaddr_unsync: - if (!bond_uses_primary(bond)) - bond_hw_addr_flush(bond_dev, slave_dev); - err_close: slave_dev->priv_flags &= ~IFF_BONDING; dev_close(slave_dev); -- GitLab From 77b9fc371d4d45e330acab7a1065e9f9b41cf58d Mon Sep 17 00:00:00 2001 From: Xin Long Date: Mon, 26 Mar 2018 01:16:47 +0800 Subject: [PATCH 0295/1635] bonding: process the err returned by dev_set_allmulti properly in bond_enslave [ Upstream commit 9f5a90c107741b864398f4ac0014711a8c1d8474 ] When dev_set_promiscuity(1) succeeds but dev_set_allmulti(1) fails, dev_set_promiscuity(-1) should be done before going to the err path. Otherwise, dev->promiscuity will leak. Fixes: 7e1a1ac1fbaa ("bonding: Check return of dev_set_promiscuity/allmulti") Signed-off-by: Xin Long Acked-by: Andy Gospodarek Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/bonding/bond_main.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index b8701a07f4eb..82f28ffccddf 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -1702,8 +1702,11 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) /* set allmulti level to new slave */ if (bond_dev->flags & IFF_ALLMULTI) { res = dev_set_allmulti(slave_dev, 1); - if (res) + if (res) { + if (bond_dev->flags & IFF_PROMISC) + dev_set_promiscuity(slave_dev, -1); goto err_sysfs_del; + } } netif_addr_lock_bh(bond_dev); -- GitLab From 048a64fbc22973d39568a0f569bf2877310f129e Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 5 Apr 2018 06:39:26 -0700 Subject: [PATCH 0296/1635] net: fool proof dev_valid_name() [ Upstream commit a9d48205d0aedda021fc3728972a9e9934c2b9de ] We want to use dev_valid_name() to validate tunnel names, so better use strnlen(name, IFNAMSIZ) than strlen(name) to make sure to not upset KASAN. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/core/dev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/core/dev.c b/net/core/dev.c index ef3337bb71a2..4be2a4047640 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -1025,7 +1025,7 @@ bool dev_valid_name(const char *name) { if (*name == '\0') return false; - if (strlen(name) >= IFNAMSIZ) + if (strnlen(name, IFNAMSIZ) == IFNAMSIZ) return false; if (!strcmp(name, ".") || !strcmp(name, "..")) return false; -- GitLab From 6816295fe9584a2610cb02a832b40d615366b3a2 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 5 Apr 2018 06:39:27 -0700 Subject: [PATCH 0297/1635] ip_tunnel: better validate user provided tunnel names [ Upstream commit 9cb726a212a82c88c98aa9f0037fd04777cd8fe5 ] Use dev_valid_name() to make sure user does not provide illegal device name. syzbot caught the following bug : BUG: KASAN: stack-out-of-bounds in strlcpy include/linux/string.h:300 [inline] BUG: KASAN: stack-out-of-bounds in __ip_tunnel_create+0xca/0x6b0 net/ipv4/ip_tunnel.c:257 Write of size 20 at addr ffff8801ac79f810 by task syzkaller268107/4482 CPU: 0 PID: 4482 Comm: syzkaller268107 Not tainted 4.16.0+ #1 Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/01/2011 Call Trace: __dump_stack lib/dump_stack.c:17 [inline] dump_stack+0x1b9/0x29f lib/dump_stack.c:53 print_address_description+0x6c/0x20b mm/kasan/report.c:256 kasan_report_error mm/kasan/report.c:354 [inline] kasan_report.cold.7+0xac/0x2f5 mm/kasan/report.c:412 check_memory_region_inline mm/kasan/kasan.c:260 [inline] check_memory_region+0x13e/0x1b0 mm/kasan/kasan.c:267 memcpy+0x37/0x50 mm/kasan/kasan.c:303 strlcpy include/linux/string.h:300 [inline] __ip_tunnel_create+0xca/0x6b0 net/ipv4/ip_tunnel.c:257 ip_tunnel_create net/ipv4/ip_tunnel.c:352 [inline] ip_tunnel_ioctl+0x818/0xd40 net/ipv4/ip_tunnel.c:861 ipip_tunnel_ioctl+0x1c5/0x420 net/ipv4/ipip.c:350 dev_ifsioc+0x43e/0xb90 net/core/dev_ioctl.c:334 dev_ioctl+0x69a/0xcc0 net/core/dev_ioctl.c:525 sock_ioctl+0x47e/0x680 net/socket.c:1015 vfs_ioctl fs/ioctl.c:46 [inline] file_ioctl fs/ioctl.c:500 [inline] do_vfs_ioctl+0x1cf/0x1650 fs/ioctl.c:684 ksys_ioctl+0xa9/0xd0 fs/ioctl.c:701 SYSC_ioctl fs/ioctl.c:708 [inline] SyS_ioctl+0x24/0x30 fs/ioctl.c:706 do_syscall_64+0x29e/0x9d0 arch/x86/entry/common.c:287 entry_SYSCALL_64_after_hwframe+0x42/0xb7 Fixes: c54419321455 ("GRE: Refactor GRE tunneling code.") Signed-off-by: Eric Dumazet Reported-by: syzbot Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv4/ip_tunnel.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/net/ipv4/ip_tunnel.c b/net/ipv4/ip_tunnel.c index 4e90082b23a6..13f7bbc0168d 100644 --- a/net/ipv4/ip_tunnel.c +++ b/net/ipv4/ip_tunnel.c @@ -253,13 +253,14 @@ static struct net_device *__ip_tunnel_create(struct net *net, struct net_device *dev; char name[IFNAMSIZ]; - if (parms->name[0]) + err = -E2BIG; + if (parms->name[0]) { + if (!dev_valid_name(parms->name)) + goto failed; strlcpy(name, parms->name, IFNAMSIZ); - else { - if (strlen(ops->kind) > (IFNAMSIZ - 3)) { - err = -E2BIG; + } else { + if (strlen(ops->kind) > (IFNAMSIZ - 3)) goto failed; - } strlcpy(name, ops->kind, IFNAMSIZ); strncat(name, "%d", 2); } -- GitLab From a7309cad9c2e33376a0d7abb9483c05a3007ec85 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 5 Apr 2018 06:39:28 -0700 Subject: [PATCH 0298/1635] ipv6: sit: better validate user provided tunnel names [ Upstream commit b95211e066fc3494b7c115060b2297b4ba21f025 ] Use dev_valid_name() to make sure user does not provide illegal device name. syzbot caught the following bug : BUG: KASAN: stack-out-of-bounds in strlcpy include/linux/string.h:300 [inline] BUG: KASAN: stack-out-of-bounds in ipip6_tunnel_locate+0x63b/0xaa0 net/ipv6/sit.c:254 Write of size 33 at addr ffff8801b64076d8 by task syzkaller932654/4453 CPU: 0 PID: 4453 Comm: syzkaller932654 Not tainted 4.16.0+ #1 Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/01/2011 Call Trace: __dump_stack lib/dump_stack.c:17 [inline] dump_stack+0x1b9/0x29f lib/dump_stack.c:53 print_address_description+0x6c/0x20b mm/kasan/report.c:256 kasan_report_error mm/kasan/report.c:354 [inline] kasan_report.cold.7+0xac/0x2f5 mm/kasan/report.c:412 check_memory_region_inline mm/kasan/kasan.c:260 [inline] check_memory_region+0x13e/0x1b0 mm/kasan/kasan.c:267 memcpy+0x37/0x50 mm/kasan/kasan.c:303 strlcpy include/linux/string.h:300 [inline] ipip6_tunnel_locate+0x63b/0xaa0 net/ipv6/sit.c:254 ipip6_tunnel_ioctl+0xe71/0x241b net/ipv6/sit.c:1221 dev_ifsioc+0x43e/0xb90 net/core/dev_ioctl.c:334 dev_ioctl+0x69a/0xcc0 net/core/dev_ioctl.c:525 sock_ioctl+0x47e/0x680 net/socket.c:1015 vfs_ioctl fs/ioctl.c:46 [inline] file_ioctl fs/ioctl.c:500 [inline] do_vfs_ioctl+0x1cf/0x1650 fs/ioctl.c:684 ksys_ioctl+0xa9/0xd0 fs/ioctl.c:701 SYSC_ioctl fs/ioctl.c:708 [inline] SyS_ioctl+0x24/0x30 fs/ioctl.c:706 do_syscall_64+0x29e/0x9d0 arch/x86/entry/common.c:287 entry_SYSCALL_64_after_hwframe+0x42/0xb7 Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Signed-off-by: Eric Dumazet Reported-by: syzbot Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv6/sit.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c index cac815cc8600..f03c1a562135 100644 --- a/net/ipv6/sit.c +++ b/net/ipv6/sit.c @@ -244,11 +244,13 @@ static struct ip_tunnel *ipip6_tunnel_locate(struct net *net, if (!create) goto failed; - if (parms->name[0]) + if (parms->name[0]) { + if (!dev_valid_name(parms->name)) + goto failed; strlcpy(name, parms->name, IFNAMSIZ); - else + } else { strcpy(name, "sit%d"); - + } dev = alloc_netdev(sizeof(*t), name, NET_NAME_UNKNOWN, ipip6_tunnel_setup); if (!dev) -- GitLab From 72363c63b0708fb3e8e0ba9fb9e0d405e97153ba Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 5 Apr 2018 06:39:29 -0700 Subject: [PATCH 0299/1635] ip6_gre: better validate user provided tunnel names [ Upstream commit 5f42df013b8bc1b6511af7a04bf93b014884ae2a ] Use dev_valid_name() to make sure user does not provide illegal device name. syzbot caught the following bug : BUG: KASAN: stack-out-of-bounds in strlcpy include/linux/string.h:300 [inline] BUG: KASAN: stack-out-of-bounds in ip6gre_tunnel_locate+0x334/0x860 net/ipv6/ip6_gre.c:339 Write of size 20 at addr ffff8801afb9f7b8 by task syzkaller851048/4466 CPU: 1 PID: 4466 Comm: syzkaller851048 Not tainted 4.16.0+ #1 Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/01/2011 Call Trace: __dump_stack lib/dump_stack.c:17 [inline] dump_stack+0x1b9/0x29f lib/dump_stack.c:53 print_address_description+0x6c/0x20b mm/kasan/report.c:256 kasan_report_error mm/kasan/report.c:354 [inline] kasan_report.cold.7+0xac/0x2f5 mm/kasan/report.c:412 check_memory_region_inline mm/kasan/kasan.c:260 [inline] check_memory_region+0x13e/0x1b0 mm/kasan/kasan.c:267 memcpy+0x37/0x50 mm/kasan/kasan.c:303 strlcpy include/linux/string.h:300 [inline] ip6gre_tunnel_locate+0x334/0x860 net/ipv6/ip6_gre.c:339 ip6gre_tunnel_ioctl+0x69d/0x12e0 net/ipv6/ip6_gre.c:1195 dev_ifsioc+0x43e/0xb90 net/core/dev_ioctl.c:334 dev_ioctl+0x69a/0xcc0 net/core/dev_ioctl.c:525 sock_ioctl+0x47e/0x680 net/socket.c:1015 vfs_ioctl fs/ioctl.c:46 [inline] file_ioctl fs/ioctl.c:500 [inline] do_vfs_ioctl+0x1cf/0x1650 fs/ioctl.c:684 ksys_ioctl+0xa9/0xd0 fs/ioctl.c:701 SYSC_ioctl fs/ioctl.c:708 [inline] SyS_ioctl+0x24/0x30 fs/ioctl.c:706 do_syscall_64+0x29e/0x9d0 arch/x86/entry/common.c:287 entry_SYSCALL_64_after_hwframe+0x42/0xb7 Fixes: c12b395a4664 ("gre: Support GRE over IPv6") Signed-off-by: Eric Dumazet Reported-by: syzbot Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv6/ip6_gre.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/net/ipv6/ip6_gre.c b/net/ipv6/ip6_gre.c index e8ab306794d8..4228f3b2f347 100644 --- a/net/ipv6/ip6_gre.c +++ b/net/ipv6/ip6_gre.c @@ -319,11 +319,13 @@ static struct ip6_tnl *ip6gre_tunnel_locate(struct net *net, if (t || !create) return t; - if (parms->name[0]) + if (parms->name[0]) { + if (!dev_valid_name(parms->name)) + return NULL; strlcpy(name, parms->name, IFNAMSIZ); - else + } else { strcpy(name, "ip6gre%d"); - + } dev = alloc_netdev(sizeof(*t), name, NET_NAME_UNKNOWN, ip6gre_tunnel_setup); if (!dev) -- GitLab From 109dce20c6ed7c29ac56776381d3daf7dd941374 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 5 Apr 2018 06:39:30 -0700 Subject: [PATCH 0300/1635] ip6_tunnel: better validate user provided tunnel names [ Upstream commit db7a65e3ab78e5b1c4b17c0870ebee35a4ee3257 ] Use valid_name() to make sure user does not provide illegal device name. Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv6/ip6_tunnel.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c index 1161fd5630c1..7e11f6a811f5 100644 --- a/net/ipv6/ip6_tunnel.c +++ b/net/ipv6/ip6_tunnel.c @@ -297,13 +297,16 @@ static struct ip6_tnl *ip6_tnl_create(struct net *net, struct __ip6_tnl_parm *p) struct net_device *dev; struct ip6_tnl *t; char name[IFNAMSIZ]; - int err = -ENOMEM; + int err = -E2BIG; - if (p->name[0]) + if (p->name[0]) { + if (!dev_valid_name(p->name)) + goto failed; strlcpy(name, p->name, IFNAMSIZ); - else + } else { sprintf(name, "ip6tnl%%d"); - + } + err = -ENOMEM; dev = alloc_netdev(sizeof(*t), name, NET_NAME_UNKNOWN, ip6_tnl_dev_setup); if (!dev) -- GitLab From b9c6ddda3805602a400319086bfab0d1f0d59ba8 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 5 Apr 2018 06:39:31 -0700 Subject: [PATCH 0301/1635] vti6: better validate user provided tunnel names [ Upstream commit 537b361fbcbcc3cd6fe2bb47069fd292b9256d16 ] Use valid_name() to make sure user does not provide illegal device name. Fixes: ed1efb2aefbb ("ipv6: Add support for IPsec virtual tunnel interfaces") Signed-off-by: Eric Dumazet Cc: Steffen Klassert Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv6/ip6_vti.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/net/ipv6/ip6_vti.c b/net/ipv6/ip6_vti.c index bcdc2d557de1..7c0f647b5195 100644 --- a/net/ipv6/ip6_vti.c +++ b/net/ipv6/ip6_vti.c @@ -212,10 +212,13 @@ static struct ip6_tnl *vti6_tnl_create(struct net *net, struct __ip6_tnl_parm *p char name[IFNAMSIZ]; int err; - if (p->name[0]) + if (p->name[0]) { + if (!dev_valid_name(p->name)) + goto failed; strlcpy(name, p->name, IFNAMSIZ); - else + } else { sprintf(name, "ip6_vti%%d"); + } dev = alloc_netdev(sizeof(*t), name, NET_NAME_UNKNOWN, vti6_dev_setup); if (!dev) -- GitLab From 9282181c1cc5fb43891d0206c2974624590a9446 Mon Sep 17 00:00:00 2001 From: Or Gerlitz Date: Tue, 13 Mar 2018 21:43:43 +0200 Subject: [PATCH 0302/1635] net/mlx5e: Avoid using the ipv6 stub in the TC offload neigh update path [ Upstream commit 423c9db29943cfc43e3a408192e9efa4178af6a1 ] Currently we use the global ipv6_stub var to access the ipv6 global nd table. This practice gets us to troubles when the stub is only partially set e.g when ipv6 is loaded under the disabled policy. In this case, as of commit 343d60aada5a ("ipv6: change ipv6_stub_impl.ipv6_dst_lookup to take net argument") the stub is not null, but stub->nd_tbl is and we crash. As we can access the ipv6 nd_tbl directly, the fix is just to avoid the reference through the stub. There is one place in the code where we issue ipv6 route lookup and keep doing it through the stub, but that mentioned commit makes sure we get -EAFNOSUPPORT from the stack. Fixes: 232c001398ae ("net/mlx5e: Add support to neighbour update flow") Signed-off-by: Or Gerlitz Reviewed-by: Aviv Heller Signed-off-by: Saeed Mahameed Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/mellanox/mlx5/core/en_rep.c | 6 +++--- drivers/net/ethernet/mellanox/mlx5/core/en_tc.c | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c index 45e03c427faf..1db16efa563e 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c @@ -230,7 +230,7 @@ void mlx5e_remove_sqs_fwd_rules(struct mlx5e_priv *priv) static void mlx5e_rep_neigh_update_init_interval(struct mlx5e_rep_priv *rpriv) { #if IS_ENABLED(CONFIG_IPV6) - unsigned long ipv6_interval = NEIGH_VAR(&ipv6_stub->nd_tbl->parms, + unsigned long ipv6_interval = NEIGH_VAR(&nd_tbl.parms, DELAY_PROBE_TIME); #else unsigned long ipv6_interval = ~0UL; @@ -366,7 +366,7 @@ static int mlx5e_rep_netevent_event(struct notifier_block *nb, case NETEVENT_NEIGH_UPDATE: n = ptr; #if IS_ENABLED(CONFIG_IPV6) - if (n->tbl != ipv6_stub->nd_tbl && n->tbl != &arp_tbl) + if (n->tbl != &nd_tbl && n->tbl != &arp_tbl) #else if (n->tbl != &arp_tbl) #endif @@ -414,7 +414,7 @@ static int mlx5e_rep_netevent_event(struct notifier_block *nb, * done per device delay prob time parameter. */ #if IS_ENABLED(CONFIG_IPV6) - if (!p->dev || (p->tbl != ipv6_stub->nd_tbl && p->tbl != &arp_tbl)) + if (!p->dev || (p->tbl != &nd_tbl && p->tbl != &arp_tbl)) #else if (!p->dev || p->tbl != &arp_tbl) #endif diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c index 9ba1f72060aa..38c366ebc23b 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c @@ -484,7 +484,7 @@ void mlx5e_tc_update_neigh_used_value(struct mlx5e_neigh_hash_entry *nhe) tbl = &arp_tbl; #if IS_ENABLED(CONFIG_IPV6) else if (m_neigh->family == AF_INET6) - tbl = ipv6_stub->nd_tbl; + tbl = &nd_tbl; #endif else return; -- GitLab From ddf79878f1e0d0a22e5c26ac341f033f5494fc1c Mon Sep 17 00:00:00 2001 From: Jianbo Liu Date: Thu, 8 Mar 2018 09:20:55 +0000 Subject: [PATCH 0303/1635] net/mlx5e: Fix memory usage issues in offloading TC flows [ Upstream commit af1607c37d9d85a66fbcf43b7f11bf3d94b9bb69 ] For NIC flows, the parsed attributes are not freed when we exit successfully from mlx5e_configure_flower(). There is possible double free for eswitch flows. If error is returned from rhashtable_insert_fast(), the parse attrs will be freed in mlx5e_tc_del_flow(), but they will be freed again before exiting mlx5e_configure_flower(). To fix both issues we do the following: (1) change the condition that determines if to issue the free call to check if this flow is NIC flow, or it does not have encap action. (2) reorder the code such that that the check and free calls are done before we attempt to add into the hash table. Fixes: 232c001398ae ('net/mlx5e: Add support to neighbour update flow') Signed-off-by: Jianbo Liu Reviewed-by: Or Gerlitz Reviewed-by: Roi Dayan Signed-off-by: Saeed Mahameed Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/mellanox/mlx5/core/en_tc.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c index 38c366ebc23b..42bab73a9f40 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c @@ -2091,19 +2091,19 @@ int mlx5e_configure_flower(struct mlx5e_priv *priv, if (err != -EAGAIN) flow->flags |= MLX5E_TC_FLOW_OFFLOADED; + if (!(flow->flags & MLX5E_TC_FLOW_ESWITCH) || + !(flow->esw_attr->action & MLX5_FLOW_CONTEXT_ACTION_ENCAP)) + kvfree(parse_attr); + err = rhashtable_insert_fast(&tc->ht, &flow->node, tc->ht_params); - if (err) - goto err_del_rule; + if (err) { + mlx5e_tc_del_flow(priv, flow); + kfree(flow); + } - if (flow->flags & MLX5E_TC_FLOW_ESWITCH && - !(flow->esw_attr->action & MLX5_FLOW_CONTEXT_ACTION_ENCAP)) - kvfree(parse_attr); return err; -err_del_rule: - mlx5e_tc_del_flow(priv, flow); - err_free: kvfree(parse_attr); kfree(flow); -- GitLab From e52a45bb392ff5f8b7b809a6851b9eab7f0a36b9 Mon Sep 17 00:00:00 2001 From: Dirk van der Merwe Date: Tue, 3 Apr 2018 17:24:23 -0700 Subject: [PATCH 0304/1635] nfp: use full 40 bits of the NSP buffer address [ Upstream commit 1489bbd10e16079ce30a53d3c22a431fd47af791 ] The NSP default buffer is a piece of NFP memory where additional command data can be placed. Its format has been copied from host buffer, but the PCIe selection bits do not make sense in this case. If those get masked out from a NFP address - writes to random place in the chip memory may be issued and crash the device. Even in the general NSP buffer case, it doesn't make sense to have the PCIe selection bits there anymore. These are unused at the moment, and when it becomes necessary, the PCIe selection bits should rather be moved to another register to utilise more bits for the buffer address. This has never been an issue because the buffer used to be allocated in memory with less-than-38-bit-long address but that is about to change. Fixes: 1a64821c6af7 ("nfp: add support for service processor access") Signed-off-by: Dirk van der Merwe Reviewed-by: Jakub Kicinski Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.c b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.c index 37364555c42b..f88ff3f4b661 100644 --- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.c +++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.c @@ -68,10 +68,11 @@ /* CPP address to retrieve the data from */ #define NSP_BUFFER 0x10 #define NSP_BUFFER_CPP GENMASK_ULL(63, 40) -#define NSP_BUFFER_PCIE GENMASK_ULL(39, 38) -#define NSP_BUFFER_ADDRESS GENMASK_ULL(37, 0) +#define NSP_BUFFER_ADDRESS GENMASK_ULL(39, 0) #define NSP_DFLT_BUFFER 0x18 +#define NSP_DFLT_BUFFER_CPP GENMASK_ULL(63, 40) +#define NSP_DFLT_BUFFER_ADDRESS GENMASK_ULL(39, 0) #define NSP_DFLT_BUFFER_CONFIG 0x20 #define NSP_DFLT_BUFFER_SIZE_MB GENMASK_ULL(7, 0) @@ -412,8 +413,8 @@ static int nfp_nsp_command_buf(struct nfp_nsp *nsp, u16 code, u32 option, if (err < 0) return err; - cpp_id = FIELD_GET(NSP_BUFFER_CPP, reg) << 8; - cpp_buf = FIELD_GET(NSP_BUFFER_ADDRESS, reg); + cpp_id = FIELD_GET(NSP_DFLT_BUFFER_CPP, reg) << 8; + cpp_buf = FIELD_GET(NSP_DFLT_BUFFER_ADDRESS, reg); if (in_buf && in_size) { err = nfp_cpp_write(cpp, cpp_id, cpp_buf, in_buf, in_size); -- GitLab From 1ec7966ab7db0467e215fb556f89d062a3c663f4 Mon Sep 17 00:00:00 2001 From: David Lebrun Date: Thu, 29 Mar 2018 17:59:36 +0100 Subject: [PATCH 0305/1635] ipv6: sr: fix seg6 encap performances with TSO enabled [ Upstream commit 5807b22c9164a21cd1077a9bc587f0bba361f72d ] Enabling TSO can lead to abysmal performances when using seg6 in encap mode, such as with the ixgbe driver. This patch adds a call to iptunnel_handle_offloads() to remove the encapsulation bit if needed. Before: root@comp4-seg6bpf:~# iperf3 -c fc00::55 Connecting to host fc00::55, port 5201 [ 4] local fc45::4 port 36592 connected to fc00::55 port 5201 [ ID] Interval Transfer Bandwidth Retr Cwnd [ 4] 0.00-1.00 sec 196 KBytes 1.60 Mbits/sec 47 6.66 KBytes [ 4] 1.00-2.00 sec 304 KBytes 2.49 Mbits/sec 100 5.33 KBytes [ 4] 2.00-3.00 sec 284 KBytes 2.32 Mbits/sec 92 5.33 KBytes After: root@comp4-seg6bpf:~# iperf3 -c fc00::55 Connecting to host fc00::55, port 5201 [ 4] local fc45::4 port 43062 connected to fc00::55 port 5201 [ ID] Interval Transfer Bandwidth Retr Cwnd [ 4] 0.00-1.00 sec 1.03 GBytes 8.89 Gbits/sec 0 743 KBytes [ 4] 1.00-2.00 sec 1.03 GBytes 8.87 Gbits/sec 0 743 KBytes [ 4] 2.00-3.00 sec 1.03 GBytes 8.87 Gbits/sec 0 743 KBytes Reported-by: Tom Herbert Fixes: 6c8702c60b88 ("ipv6: sr: add support for SRH encapsulation and injection with lwtunnels") Signed-off-by: David Lebrun Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv6/seg6_iptunnel.c | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/net/ipv6/seg6_iptunnel.c b/net/ipv6/seg6_iptunnel.c index 7a78dcfda68a..f343e6f0fc95 100644 --- a/net/ipv6/seg6_iptunnel.c +++ b/net/ipv6/seg6_iptunnel.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -211,11 +212,6 @@ static int seg6_do_srh(struct sk_buff *skb) tinfo = seg6_encap_lwtunnel(dst->lwtstate); - if (likely(!skb->encapsulation)) { - skb_reset_inner_headers(skb); - skb->encapsulation = 1; - } - switch (tinfo->mode) { case SEG6_IPTUN_MODE_INLINE: if (skb->protocol != htons(ETH_P_IPV6)) @@ -224,10 +220,12 @@ static int seg6_do_srh(struct sk_buff *skb) err = seg6_do_srh_inline(skb, tinfo->srh); if (err) return err; - - skb_reset_inner_headers(skb); break; case SEG6_IPTUN_MODE_ENCAP: + err = iptunnel_handle_offloads(skb, SKB_GSO_IPXIP6); + if (err) + return err; + if (skb->protocol == htons(ETH_P_IPV6)) proto = IPPROTO_IPV6; else if (skb->protocol == htons(ETH_P_IP)) @@ -239,6 +237,8 @@ static int seg6_do_srh(struct sk_buff *skb) if (err) return err; + skb_set_inner_transport_header(skb, skb_transport_offset(skb)); + skb_set_inner_protocol(skb, skb->protocol); skb->protocol = htons(ETH_P_IPV6); break; case SEG6_IPTUN_MODE_L2ENCAP: @@ -262,8 +262,6 @@ static int seg6_do_srh(struct sk_buff *skb) ipv6_hdr(skb)->payload_len = htons(skb->len - sizeof(struct ipv6hdr)); skb_set_transport_header(skb, sizeof(struct ipv6hdr)); - skb_set_inner_protocol(skb, skb->protocol); - return 0; } -- GitLab From baab1f0c4885854cefec9f2b0da9abc912333a25 Mon Sep 17 00:00:00 2001 From: Jianbo Liu Date: Fri, 2 Mar 2018 02:09:08 +0000 Subject: [PATCH 0306/1635] net/mlx5e: Don't override vport admin link state in switchdev mode The vport admin original link state will be re-applied after returning back to legacy mode, it is not right to change the admin link state value when in switchdev mode. Use direct vport commands to alter logical vport state in netdev representor open/close flows rather than the administrative eswitch API. Fixes: 20a1ea674783 ('net/mlx5e: Support VF vport link state control for SRIOV switchdev mode') Signed-off-by: Jianbo Liu Reviewed-by: Roi Dayan Reviewed-by: Or Gerlitz Signed-off-by: Saeed Mahameed Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/mellanox/mlx5/core/en_rep.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c index 1db16efa563e..adf2b7a795e9 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c @@ -610,7 +610,6 @@ static int mlx5e_rep_open(struct net_device *dev) struct mlx5e_priv *priv = netdev_priv(dev); struct mlx5e_rep_priv *rpriv = priv->ppriv; struct mlx5_eswitch_rep *rep = rpriv->rep; - struct mlx5_eswitch *esw = priv->mdev->priv.eswitch; int err; mutex_lock(&priv->state_lock); @@ -618,8 +617,9 @@ static int mlx5e_rep_open(struct net_device *dev) if (err) goto unlock; - if (!mlx5_eswitch_set_vport_state(esw, rep->vport, - MLX5_ESW_VPORT_ADMIN_STATE_UP)) + if (!mlx5_modify_vport_admin_state(priv->mdev, + MLX5_QUERY_VPORT_STATE_IN_OP_MOD_ESW_VPORT, + rep->vport, MLX5_ESW_VPORT_ADMIN_STATE_UP)) netif_carrier_on(dev); unlock: @@ -632,11 +632,12 @@ static int mlx5e_rep_close(struct net_device *dev) struct mlx5e_priv *priv = netdev_priv(dev); struct mlx5e_rep_priv *rpriv = priv->ppriv; struct mlx5_eswitch_rep *rep = rpriv->rep; - struct mlx5_eswitch *esw = priv->mdev->priv.eswitch; int ret; mutex_lock(&priv->state_lock); - (void)mlx5_eswitch_set_vport_state(esw, rep->vport, MLX5_ESW_VPORT_ADMIN_STATE_DOWN); + mlx5_modify_vport_admin_state(priv->mdev, + MLX5_QUERY_VPORT_STATE_IN_OP_MOD_ESW_VPORT, + rep->vport, MLX5_ESW_VPORT_ADMIN_STATE_DOWN); ret = mlx5e_close_locked(dev); mutex_unlock(&priv->state_lock); return ret; -- GitLab From e096c8bf4fb83c162cb7b52f71b21d00bbe49134 Mon Sep 17 00:00:00 2001 From: Shahar Klein Date: Tue, 20 Mar 2018 14:44:40 +0200 Subject: [PATCH 0307/1635] net/mlx5e: Sync netdev vxlan ports at open [ Upstream commit a117f73dc2430443f23e18367fa545981129c1a6 ] When mlx5_core is loaded it is expected to sync ports with all vxlan devices so it can support vxlan encap/decap. This is done via udp_tunnel_get_rx_info(). Currently this call is set in mlx5e_nic_enable() and if the netdev is not in NETREG_REGISTERED state it will not be called. Normally on load the netdev state is not NETREG_REGISTERED so udp_tunnel_get_rx_info() will not be called. Moving udp_tunnel_get_rx_info() to mlx5e_open() so it will be called on netdev UP event and allow encap/decap. Fixes: 610e89e05c3f ("net/mlx5e: Don't sync netdev state when not registered") Signed-off-by: Shahar Klein Reviewed-by: Roi Dayan Signed-off-by: Saeed Mahameed Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/mellanox/mlx5/core/en_main.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c index a863572882b2..225b2ad3e15f 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c @@ -2718,6 +2718,9 @@ int mlx5e_open(struct net_device *netdev) mlx5_set_port_admin_status(priv->mdev, MLX5_PORT_UP); mutex_unlock(&priv->state_lock); + if (mlx5e_vxlan_allowed(priv->mdev)) + udp_tunnel_get_rx_info(netdev); + return err; } @@ -4276,13 +4279,6 @@ static void mlx5e_nic_enable(struct mlx5e_priv *priv) if (netdev->reg_state != NETREG_REGISTERED) return; - /* Device already registered: sync netdev system state */ - if (mlx5e_vxlan_allowed(mdev)) { - rtnl_lock(); - udp_tunnel_get_rx_info(netdev); - rtnl_unlock(); - } - queue_work(priv->wq, &priv->set_rx_mode_work); rtnl_lock(); -- GitLab From a19024a3f343b848bc01001958d1121b0ad4b5ac Mon Sep 17 00:00:00 2001 From: Davide Caratti Date: Fri, 16 Mar 2018 00:00:55 +0100 Subject: [PATCH 0308/1635] net/sched: fix NULL dereference in the error path of tunnel_key_init() [ Upstream commit abdadd3cfd3e7ea3da61ac774f84777d1f702058 ] when the following command # tc action add action tunnel_key unset index 100 is run for the first time, and tunnel_key_init() fails to allocate struct tcf_tunnel_key_params, tunnel_key_release() dereferences NULL pointers. This causes the following error: BUG: unable to handle kernel NULL pointer dereference at 0000000000000010 IP: tunnel_key_release+0xd/0x40 [act_tunnel_key] PGD 8000000033787067 P4D 8000000033787067 PUD 74646067 PMD 0 Oops: 0000 [#1] SMP PTI Modules linked in: act_tunnel_key(E) act_csum ip6table_filter ip6_tables iptable_filter binfmt_misc ext4 mbcache jbd2 crct10dif_pclmul crc32_pclmul snd_hda_codec_generic ghash_clmulni_intel snd_hda_intel pcbc snd_hda_codec snd_hda_core snd_hwdep snd_seq aesni_intel snd_seq_device crypto_simd glue_helper snd_pcm cryptd joydev snd_timer pcspkr virtio_balloon snd i2c_piix4 soundcore nfsd auth_rpcgss nfs_acl lockd grace sunrpc ip_tables xfs libcrc32c ata_generic pata_acpi qxl drm_kms_helper syscopyarea sysfillrect sysimgblt fb_sys_fops ttm virtio_net virtio_blk drm virtio_console crc32c_intel ata_piix serio_raw i2c_core virtio_pci libata virtio_ring virtio floppy dm_mirror dm_region_hash dm_log dm_mod CPU: 2 PID: 3101 Comm: tc Tainted: G E 4.16.0-rc4.act_vlan.orig+ #403 Hardware name: Red Hat KVM, BIOS 0.5.1 01/01/2011 RIP: 0010:tunnel_key_release+0xd/0x40 [act_tunnel_key] RSP: 0018:ffffba46803b7768 EFLAGS: 00010286 RAX: ffffffffc09010a0 RBX: 0000000000000000 RCX: 0000000000000024 RDX: 0000000000000000 RSI: 0000000000000000 RDI: ffff99ee336d7480 RBP: 0000000000000000 R08: 0000000000000001 R09: 0000000000000044 R10: 0000000000000220 R11: ffff99ee79d73131 R12: 0000000000000000 R13: ffff99ee32d67610 R14: ffff99ee7671dc38 R15: 00000000fffffff4 FS: 00007febcb2cd740(0000) GS:ffff99ee7fd00000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 0000000000000010 CR3: 000000007c8e4005 CR4: 00000000001606e0 Call Trace: __tcf_idr_release+0x79/0xf0 tunnel_key_init+0xd9/0x460 [act_tunnel_key] tcf_action_init_1+0x2cc/0x430 tcf_action_init+0xd3/0x1b0 tc_ctl_action+0x18b/0x240 rtnetlink_rcv_msg+0x29c/0x310 ? _cond_resched+0x15/0x30 ? __kmalloc_node_track_caller+0x1b9/0x270 ? rtnl_calcit.isra.28+0x100/0x100 netlink_rcv_skb+0xd2/0x110 netlink_unicast+0x17c/0x230 netlink_sendmsg+0x2cd/0x3c0 sock_sendmsg+0x30/0x40 ___sys_sendmsg+0x27a/0x290 __sys_sendmsg+0x51/0x90 do_syscall_64+0x6e/0x1a0 entry_SYSCALL_64_after_hwframe+0x3d/0xa2 RIP: 0033:0x7febca6deba0 RSP: 002b:00007ffe7b0dd128 EFLAGS: 00000246 ORIG_RAX: 000000000000002e RAX: ffffffffffffffda RBX: 00007ffe7b0dd250 RCX: 00007febca6deba0 RDX: 0000000000000000 RSI: 00007ffe7b0dd1a0 RDI: 0000000000000003 RBP: 000000005aaa90cb R08: 0000000000000002 R09: 0000000000000000 R10: 00007ffe7b0dcba0 R11: 0000000000000246 R12: 0000000000000000 R13: 00007ffe7b0dd264 R14: 0000000000000001 R15: 0000000000669f60 Code: 44 00 00 8b 0d b5 23 00 00 48 8b 87 48 10 00 00 48 8b 3c c8 e9 a5 e5 d8 c3 0f 1f 44 00 00 0f 1f 44 00 00 53 48 8b 9f b0 00 00 00 <83> 7b 10 01 74 0b 48 89 df 31 f6 5b e9 f2 fa 7f c3 48 8b 7b 18 RIP: tunnel_key_release+0xd/0x40 [act_tunnel_key] RSP: ffffba46803b7768 CR2: 0000000000000010 Fix this in tunnel_key_release(), ensuring 'param' is not NULL before dereferencing it. Fixes: d0f6dd8a914f ("net/sched: Introduce act_tunnel_key") Signed-off-by: Davide Caratti Acked-by: Jiri Pirko Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/sched/act_tunnel_key.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/net/sched/act_tunnel_key.c b/net/sched/act_tunnel_key.c index 22bf1a376b91..7cb63616805d 100644 --- a/net/sched/act_tunnel_key.c +++ b/net/sched/act_tunnel_key.c @@ -208,11 +208,12 @@ static void tunnel_key_release(struct tc_action *a, int bind) struct tcf_tunnel_key_params *params; params = rcu_dereference_protected(t->params, 1); + if (params) { + if (params->tcft_action == TCA_TUNNEL_KEY_ACT_SET) + dst_release(¶ms->tcft_enc_metadata->dst); - if (params->tcft_action == TCA_TUNNEL_KEY_ACT_SET) - dst_release(¶ms->tcft_enc_metadata->dst); - - kfree_rcu(params, rcu); + kfree_rcu(params, rcu); + } } static int tunnel_key_dump_addresses(struct sk_buff *skb, -- GitLab From 1c71bfe84deb1448fee8615ee05a4d7384e63e65 Mon Sep 17 00:00:00 2001 From: Davide Caratti Date: Fri, 16 Mar 2018 00:00:57 +0100 Subject: [PATCH 0309/1635] net/sched: fix NULL dereference on the error path of tcf_skbmod_init() [ Upstream commit 2d433610176d6569e8b3a28f67bc72235bf69efc ] when the following command # tc action replace action skbmod swap mac index 100 is run for the first time, and tcf_skbmod_init() fails to allocate struct tcf_skbmod_params, tcf_skbmod_cleanup() calls kfree_rcu(NULL), thus causing the following error: BUG: unable to handle kernel NULL pointer dereference at 0000000000000008 IP: __call_rcu+0x23/0x2b0 PGD 8000000034057067 P4D 8000000034057067 PUD 74937067 PMD 0 Oops: 0002 [#1] SMP PTI Modules linked in: act_skbmod(E) psample ip6table_filter ip6_tables iptable_filter binfmt_misc ext4 snd_hda_codec_generic snd_hda_intel snd_hda_codec crct10dif_pclmul mbcache jbd2 crc32_pclmul snd_hda_core ghash_clmulni_intel snd_hwdep pcbc snd_seq snd_seq_device snd_pcm aesni_intel snd_timer crypto_simd glue_helper snd cryptd virtio_balloon joydev soundcore pcspkr i2c_piix4 nfsd auth_rpcgss nfs_acl lockd grace sunrpc ip_tables xfs libcrc32c ata_generic pata_acpi qxl drm_kms_helper syscopyarea sysfillrect sysimgblt fb_sys_fops ttm drm virtio_console virtio_net virtio_blk ata_piix libata crc32c_intel virtio_pci serio_raw virtio_ring virtio i2c_core floppy dm_mirror dm_region_hash dm_log dm_mod [last unloaded: act_skbmod] CPU: 3 PID: 3144 Comm: tc Tainted: G E 4.16.0-rc4.act_vlan.orig+ #403 Hardware name: Red Hat KVM, BIOS 0.5.1 01/01/2011 RIP: 0010:__call_rcu+0x23/0x2b0 RSP: 0018:ffffbd2e403e7798 EFLAGS: 00010246 RAX: ffffffffc0872080 RBX: ffff981d34bff780 RCX: 00000000ffffffff RDX: ffffffff922a5f00 RSI: 0000000000000000 RDI: 0000000000000000 RBP: 0000000000000000 R08: 0000000000000001 R09: 000000000000021f R10: 000000003d003000 R11: 0000000000aaaaaa R12: 0000000000000000 R13: ffffffff922a5f00 R14: 0000000000000001 R15: ffff981d3b698c2c FS: 00007f3678292740(0000) GS:ffff981d3fd80000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 0000000000000008 CR3: 000000007c57a006 CR4: 00000000001606e0 Call Trace: __tcf_idr_release+0x79/0xf0 tcf_skbmod_init+0x1d1/0x210 [act_skbmod] tcf_action_init_1+0x2cc/0x430 tcf_action_init+0xd3/0x1b0 tc_ctl_action+0x18b/0x240 rtnetlink_rcv_msg+0x29c/0x310 ? _cond_resched+0x15/0x30 ? __kmalloc_node_track_caller+0x1b9/0x270 ? rtnl_calcit.isra.28+0x100/0x100 netlink_rcv_skb+0xd2/0x110 netlink_unicast+0x17c/0x230 netlink_sendmsg+0x2cd/0x3c0 sock_sendmsg+0x30/0x40 ___sys_sendmsg+0x27a/0x290 ? filemap_map_pages+0x34a/0x3a0 ? __handle_mm_fault+0xbfd/0xe20 __sys_sendmsg+0x51/0x90 do_syscall_64+0x6e/0x1a0 entry_SYSCALL_64_after_hwframe+0x3d/0xa2 RIP: 0033:0x7f36776a3ba0 RSP: 002b:00007fff4703b618 EFLAGS: 00000246 ORIG_RAX: 000000000000002e RAX: ffffffffffffffda RBX: 00007fff4703b740 RCX: 00007f36776a3ba0 RDX: 0000000000000000 RSI: 00007fff4703b690 RDI: 0000000000000003 RBP: 000000005aaaba36 R08: 0000000000000002 R09: 0000000000000000 R10: 00007fff4703b0a0 R11: 0000000000000246 R12: 0000000000000000 R13: 00007fff4703b754 R14: 0000000000000001 R15: 0000000000669f60 Code: 5d e9 42 da ff ff 66 90 0f 1f 44 00 00 41 57 41 56 41 55 49 89 d5 41 54 55 48 89 fd 53 48 83 ec 08 40 f6 c7 07 0f 85 19 02 00 00 <48> 89 75 08 48 c7 45 00 00 00 00 00 9c 58 0f 1f 44 00 00 49 89 RIP: __call_rcu+0x23/0x2b0 RSP: ffffbd2e403e7798 CR2: 0000000000000008 Fix it in tcf_skbmod_cleanup(), ensuring that kfree_rcu(p, ...) is called only when p is not NULL. Fixes: 86da71b57383 ("net_sched: Introduce skbmod action") Signed-off-by: Davide Caratti Acked-by: Jiri Pirko Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/sched/act_skbmod.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/net/sched/act_skbmod.c b/net/sched/act_skbmod.c index b642ad3d39dd..6d10b3af479b 100644 --- a/net/sched/act_skbmod.c +++ b/net/sched/act_skbmod.c @@ -190,7 +190,8 @@ static void tcf_skbmod_cleanup(struct tc_action *a, int bind) struct tcf_skbmod_params *p; p = rcu_dereference_protected(d->skbmod_p, 1); - kfree_rcu(p, rcu); + if (p) + kfree_rcu(p, rcu); } static int tcf_skbmod_dump(struct sk_buff *skb, struct tc_action *a, -- GitLab From 477c73abf26a115cc7c3fba3c27763d4e8c31564 Mon Sep 17 00:00:00 2001 From: Dave Watson Date: Mon, 26 Mar 2018 12:31:21 -0700 Subject: [PATCH 0310/1635] strparser: Fix sign of err codes [ Upstream commit cd00edc179863848abab5cc5683de5b7b5f70954 ] strp_parser_err is called with a negative code everywhere, which then calls abort_parser with a negative code. strp_msg_timeout calls abort_parser directly with a positive code. Negate ETIMEDOUT to match signed-ness of other calls. The default abort_parser callback, strp_abort_strp, sets sk->sk_err to err. Also negate the error here so sk_err always holds a positive value, as the rest of the net code expects. Currently a negative sk_err can result in endless loops, or user code that thinks it actually sent/received err bytes. Found while testing net/tls_sw recv path. Fixes: 43a0c6751a322847 ("strparser: Stream parser for messages") Signed-off-by: Dave Watson Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/strparser/strparser.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/strparser/strparser.c b/net/strparser/strparser.c index c5fda15ba319..4a3a3f1331ee 100644 --- a/net/strparser/strparser.c +++ b/net/strparser/strparser.c @@ -60,7 +60,7 @@ static void strp_abort_strp(struct strparser *strp, int err) struct sock *sk = strp->sk; /* Report an error on the lower socket */ - sk->sk_err = err; + sk->sk_err = -err; sk->sk_error_report(sk); } } @@ -458,7 +458,7 @@ static void strp_msg_timeout(struct work_struct *w) /* Message assembly timed out */ STRP_STATS_INCR(strp->stats.msg_timeouts); strp->cb.lock(strp); - strp->cb.abort_parser(strp, ETIMEDOUT); + strp->cb.abort_parser(strp, -ETIMEDOUT); strp->cb.unlock(strp); } -- GitLab From 9408bceb0649dd48a8bd6fbb763ccd26194f975a Mon Sep 17 00:00:00 2001 From: Eran Ben Elisha Date: Tue, 27 Mar 2018 14:41:18 +0300 Subject: [PATCH 0311/1635] net/mlx4_en: Fix mixed PFC and Global pause user control requests [ Upstream commit 6e8814ceb7e8f468659ef9253bd212c07ae19584 ] Global pause and PFC configuration should be mutually exclusive (i.e. only one of them at most can be set). However, once PFC was turned off, driver automatically turned Global pause on. This is a bug. Fix the driver behaviour to turn off PFC/Global once the user turned the other on. This also fixed a weird behaviour that at a current time, the profile had both PFC and global pause configuration turned on, which is Hardware-wise impossible and caused returning false positive indication to query tools. In addition, fix error code when setting global pause or PFC to change metadata only upon successful change. Also, removed useless debug print. Fixes: af7d51852631 ("net/mlx4_en: Add DCB PFC support through CEE netlink commands") Fixes: c27a02cd94d6 ("mlx4_en: Add driver for Mellanox ConnectX 10GbE NIC") Signed-off-by: Eran Ben Elisha Signed-off-by: Tariq Toukan Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- .../net/ethernet/mellanox/mlx4/en_dcb_nl.c | 72 +++++++++++-------- .../net/ethernet/mellanox/mlx4/en_ethtool.c | 33 +++++---- drivers/net/ethernet/mellanox/mlx4/en_main.c | 4 +- 3 files changed, 62 insertions(+), 47 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx4/en_dcb_nl.c b/drivers/net/ethernet/mellanox/mlx4/en_dcb_nl.c index 1a0c3bf86ead..752a72499b4f 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_dcb_nl.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_dcb_nl.c @@ -156,57 +156,63 @@ static int mlx4_en_dcbnl_getnumtcs(struct net_device *netdev, int tcid, u8 *num) static u8 mlx4_en_dcbnl_set_all(struct net_device *netdev) { struct mlx4_en_priv *priv = netdev_priv(netdev); + struct mlx4_en_port_profile *prof = priv->prof; struct mlx4_en_dev *mdev = priv->mdev; + u8 tx_pause, tx_ppp, rx_pause, rx_ppp; if (!(priv->dcbx_cap & DCB_CAP_DCBX_VER_CEE)) return 1; if (priv->cee_config.pfc_state) { int tc; + rx_ppp = prof->rx_ppp; + tx_ppp = prof->tx_ppp; - priv->prof->rx_pause = 0; - priv->prof->tx_pause = 0; for (tc = 0; tc < CEE_DCBX_MAX_PRIO; tc++) { u8 tc_mask = 1 << tc; switch (priv->cee_config.dcb_pfc[tc]) { case pfc_disabled: - priv->prof->tx_ppp &= ~tc_mask; - priv->prof->rx_ppp &= ~tc_mask; + tx_ppp &= ~tc_mask; + rx_ppp &= ~tc_mask; break; case pfc_enabled_full: - priv->prof->tx_ppp |= tc_mask; - priv->prof->rx_ppp |= tc_mask; + tx_ppp |= tc_mask; + rx_ppp |= tc_mask; break; case pfc_enabled_tx: - priv->prof->tx_ppp |= tc_mask; - priv->prof->rx_ppp &= ~tc_mask; + tx_ppp |= tc_mask; + rx_ppp &= ~tc_mask; break; case pfc_enabled_rx: - priv->prof->tx_ppp &= ~tc_mask; - priv->prof->rx_ppp |= tc_mask; + tx_ppp &= ~tc_mask; + rx_ppp |= tc_mask; break; default: break; } } - en_dbg(DRV, priv, "Set pfc on\n"); + rx_pause = !!(rx_ppp || tx_ppp) ? 0 : prof->rx_pause; + tx_pause = !!(rx_ppp || tx_ppp) ? 0 : prof->tx_pause; } else { - priv->prof->rx_pause = 1; - priv->prof->tx_pause = 1; - en_dbg(DRV, priv, "Set pfc off\n"); + rx_ppp = 0; + tx_ppp = 0; + rx_pause = prof->rx_pause; + tx_pause = prof->tx_pause; } if (mlx4_SET_PORT_general(mdev->dev, priv->port, priv->rx_skb_size + ETH_FCS_LEN, - priv->prof->tx_pause, - priv->prof->tx_ppp, - priv->prof->rx_pause, - priv->prof->rx_ppp)) { + tx_pause, tx_ppp, rx_pause, rx_ppp)) { en_err(priv, "Failed setting pause params\n"); return 1; } + prof->tx_ppp = tx_ppp; + prof->rx_ppp = rx_ppp; + prof->tx_pause = tx_pause; + prof->rx_pause = rx_pause; + return 0; } @@ -408,6 +414,7 @@ static int mlx4_en_dcbnl_ieee_setpfc(struct net_device *dev, struct mlx4_en_priv *priv = netdev_priv(dev); struct mlx4_en_port_profile *prof = priv->prof; struct mlx4_en_dev *mdev = priv->mdev; + u32 tx_pause, tx_ppp, rx_pause, rx_ppp; int err; en_dbg(DRV, priv, "cap: 0x%x en: 0x%x mbc: 0x%x delay: %d\n", @@ -416,23 +423,26 @@ static int mlx4_en_dcbnl_ieee_setpfc(struct net_device *dev, pfc->mbc, pfc->delay); - prof->rx_pause = !pfc->pfc_en; - prof->tx_pause = !pfc->pfc_en; - prof->rx_ppp = pfc->pfc_en; - prof->tx_ppp = pfc->pfc_en; + rx_pause = prof->rx_pause && !pfc->pfc_en; + tx_pause = prof->tx_pause && !pfc->pfc_en; + rx_ppp = pfc->pfc_en; + tx_ppp = pfc->pfc_en; err = mlx4_SET_PORT_general(mdev->dev, priv->port, priv->rx_skb_size + ETH_FCS_LEN, - prof->tx_pause, - prof->tx_ppp, - prof->rx_pause, - prof->rx_ppp); - if (err) + tx_pause, tx_ppp, rx_pause, rx_ppp); + if (err) { en_err(priv, "Failed setting pause params\n"); - else - mlx4_en_update_pfc_stats_bitmap(mdev->dev, &priv->stats_bitmap, - prof->rx_ppp, prof->rx_pause, - prof->tx_ppp, prof->tx_pause); + return err; + } + + mlx4_en_update_pfc_stats_bitmap(mdev->dev, &priv->stats_bitmap, + rx_ppp, rx_pause, tx_ppp, tx_pause); + + prof->tx_ppp = tx_ppp; + prof->rx_ppp = rx_ppp; + prof->rx_pause = rx_pause; + prof->tx_pause = tx_pause; return err; } diff --git a/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c b/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c index 3d4e4a5d00d1..67f74fcb265e 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c @@ -1046,27 +1046,32 @@ static int mlx4_en_set_pauseparam(struct net_device *dev, { struct mlx4_en_priv *priv = netdev_priv(dev); struct mlx4_en_dev *mdev = priv->mdev; + u8 tx_pause, tx_ppp, rx_pause, rx_ppp; int err; if (pause->autoneg) return -EINVAL; - priv->prof->tx_pause = pause->tx_pause != 0; - priv->prof->rx_pause = pause->rx_pause != 0; + tx_pause = !!(pause->tx_pause); + rx_pause = !!(pause->rx_pause); + rx_ppp = priv->prof->rx_ppp && !(tx_pause || rx_pause); + tx_ppp = priv->prof->tx_ppp && !(tx_pause || rx_pause); + err = mlx4_SET_PORT_general(mdev->dev, priv->port, priv->rx_skb_size + ETH_FCS_LEN, - priv->prof->tx_pause, - priv->prof->tx_ppp, - priv->prof->rx_pause, - priv->prof->rx_ppp); - if (err) - en_err(priv, "Failed setting pause params\n"); - else - mlx4_en_update_pfc_stats_bitmap(mdev->dev, &priv->stats_bitmap, - priv->prof->rx_ppp, - priv->prof->rx_pause, - priv->prof->tx_ppp, - priv->prof->tx_pause); + tx_pause, tx_ppp, rx_pause, rx_ppp); + if (err) { + en_err(priv, "Failed setting pause params, err = %d\n", err); + return err; + } + + mlx4_en_update_pfc_stats_bitmap(mdev->dev, &priv->stats_bitmap, + rx_ppp, rx_pause, tx_ppp, tx_pause); + + priv->prof->tx_pause = tx_pause; + priv->prof->rx_pause = rx_pause; + priv->prof->tx_ppp = tx_ppp; + priv->prof->rx_ppp = rx_ppp; return err; } diff --git a/drivers/net/ethernet/mellanox/mlx4/en_main.c b/drivers/net/ethernet/mellanox/mlx4/en_main.c index 686e18de9a97..6b2f7122b3ab 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_main.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_main.c @@ -163,9 +163,9 @@ static void mlx4_en_get_profile(struct mlx4_en_dev *mdev) params->udp_rss = 0; } for (i = 1; i <= MLX4_MAX_PORTS; i++) { - params->prof[i].rx_pause = 1; + params->prof[i].rx_pause = !(pfcrx || pfctx); params->prof[i].rx_ppp = pfcrx; - params->prof[i].tx_pause = 1; + params->prof[i].tx_pause = !(pfcrx || pfctx); params->prof[i].tx_ppp = pfctx; params->prof[i].tx_ring_size = MLX4_EN_DEF_TX_RING_SIZE; params->prof[i].rx_ring_size = MLX4_EN_DEF_RX_RING_SIZE; -- GitLab From 72b880f43990c747aa83ca695f71344718d041f3 Mon Sep 17 00:00:00 2001 From: Roi Dayan Date: Wed, 28 Feb 2018 12:56:42 +0200 Subject: [PATCH 0312/1635] net/mlx5e: Fix traffic being dropped on VF representor [ Upstream commit 4246f698dd58e3c6246fa919ef0b0a1d29a57e4a ] Increase representor netdev RQ size to avoid dropped packets. The current size (two) is just too small to keep up with conventional slow path traffic patterns. Also match the SQ size to the RQ size. Fixes: cb67b832921c ("net/mlx5e: Introduce SRIOV VF representors") Signed-off-by: Roi Dayan Reviewed-by: Paul Blakey Reviewed-by: Or Gerlitz Signed-off-by: Saeed Mahameed Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/mellanox/mlx5/core/en_rep.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c index adf2b7a795e9..5ffd1db4e797 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c @@ -43,6 +43,11 @@ #include "en_tc.h" #include "fs_core.h" +#define MLX5E_REP_PARAMS_LOG_SQ_SIZE \ + max(0x6, MLX5E_PARAMS_MINIMUM_LOG_SQ_SIZE) +#define MLX5E_REP_PARAMS_LOG_RQ_SIZE \ + max(0x6, MLX5E_PARAMS_MINIMUM_LOG_RQ_SIZE) + static const char mlx5e_rep_driver_name[] = "mlx5e_rep"; static void mlx5e_rep_get_drvinfo(struct net_device *dev, @@ -798,9 +803,9 @@ static void mlx5e_build_rep_params(struct mlx5_core_dev *mdev, MLX5_CQ_PERIOD_MODE_START_FROM_CQE : MLX5_CQ_PERIOD_MODE_START_FROM_EQE; - params->log_sq_size = MLX5E_PARAMS_MINIMUM_LOG_SQ_SIZE; + params->log_sq_size = MLX5E_REP_PARAMS_LOG_SQ_SIZE; params->rq_wq_type = MLX5_WQ_TYPE_LINKED_LIST; - params->log_rq_size = MLX5E_PARAMS_MINIMUM_LOG_RQ_SIZE; + params->log_rq_size = MLX5E_REP_PARAMS_LOG_RQ_SIZE; params->rx_am_enabled = MLX5_CAP_GEN(mdev, cq_moderation); mlx5e_set_rx_cq_mode_params(params, cq_period_mode); -- GitLab From 2f8aa659d4c0b6f70d441022e955ff53bb9ffea5 Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Thu, 29 Mar 2018 16:00:04 +0800 Subject: [PATCH 0313/1635] vhost: validate log when IOTLB is enabled [ Upstream commit d65026c6c62e7d9616c8ceb5a53b68bcdc050525 ] Vq log_base is the userspace address of bitmap which has nothing to do with IOTLB. So it needs to be validated unconditionally otherwise we may try use 0 as log_base which may lead to pin pages that will lead unexpected result (e.g trigger BUG_ON() in set_bit_to_user()). Fixes: 6b1e6cc7855b0 ("vhost: new device IOTLB API") Reported-by: syzbot+6304bf97ef436580fede@syzkaller.appspotmail.com Signed-off-by: Jason Wang Acked-by: Michael S. Tsirkin Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/vhost/vhost.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c index c1033dc0e3f5..c692e0b13242 100644 --- a/drivers/vhost/vhost.c +++ b/drivers/vhost/vhost.c @@ -1252,14 +1252,12 @@ static int vq_log_access_ok(struct vhost_virtqueue *vq, /* Caller should have vq mutex and device mutex */ int vhost_vq_access_ok(struct vhost_virtqueue *vq) { - if (vq->iotlb) { - /* When device IOTLB was used, the access validation - * will be validated during prefetching. - */ - return 1; - } - return vq_access_ok(vq, vq->num, vq->desc, vq->avail, vq->used) && - vq_log_access_ok(vq, vq->log_base); + int ret = vq_log_access_ok(vq, vq->log_base); + + if (ret || vq->iotlb) + return ret; + + return vq_access_ok(vq, vq->num, vq->desc, vq->avail, vq->used); } EXPORT_SYMBOL_GPL(vhost_vq_access_ok); -- GitLab From 233ba28e186284638b7946d886b18ad084710c31 Mon Sep 17 00:00:00 2001 From: Xin Long Date: Sun, 1 Apr 2018 22:40:35 +0800 Subject: [PATCH 0314/1635] route: check sysctl_fib_multipath_use_neigh earlier than hash [ Upstream commit 6174a30df1b902e1fedbd728f5343937e83e64e6 ] Prior to this patch, when one packet is hashed into path [1] (hash <= nh_upper_bound) and it's neigh is dead, it will try path [2]. However, if path [2]'s neigh is alive but it's hash > nh_upper_bound, it will not return this alive path. This packet will never be sent even if path [2] is alive. 3.3.3.1/24: nexthop via 1.1.1.254 dev eth1 weight 1 <--[1] (dead neigh) nexthop via 2.2.2.254 dev eth2 weight 1 <--[2] With sysctl_fib_multipath_use_neigh set is supposed to find an available path respecting to the l3/l4 hash. But if there is no available route with this hash, it should at least return an alive route even with other hash. This patch is to fix it by processing fib_multipath_use_neigh earlier than the hash check, so that it will at least return an alive route if there is when fib_multipath_use_neigh is enabled. It's also compatible with before when there are alive routes with the l3/l4 hash. Fixes: a6db4494d218 ("net: ipv4: Consider failed nexthops in multipath routes") Reported-by: Jianlin Shi Signed-off-by: Xin Long Acked-by: David Ahern Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv4/fib_semantics.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c index 1ee6c0d8dde4..f39955913d3f 100644 --- a/net/ipv4/fib_semantics.c +++ b/net/ipv4/fib_semantics.c @@ -1755,18 +1755,20 @@ void fib_select_multipath(struct fib_result *res, int hash) bool first = false; for_nexthops(fi) { + if (net->ipv4.sysctl_fib_multipath_use_neigh) { + if (!fib_good_nh(nh)) + continue; + if (!first) { + res->nh_sel = nhsel; + first = true; + } + } + if (hash > atomic_read(&nh->nh_upper_bound)) continue; - if (!net->ipv4.sysctl_fib_multipath_use_neigh || - fib_good_nh(nh)) { - res->nh_sel = nhsel; - return; - } - if (!first) { - res->nh_sel = nhsel; - first = true; - } + res->nh_sel = nhsel; + return; } endfor_nexthops(fi); } #endif -- GitLab From 8c316b625705dd793ac56cacecd2a69209c8906c Mon Sep 17 00:00:00 2001 From: Xin Long Date: Mon, 26 Mar 2018 01:25:06 +0800 Subject: [PATCH 0315/1635] team: move dev_mc_sync after master_upper_dev_link in team_port_add [ Upstream commit 982cf3b3999d39a2eaca0a65542df33c19b5d814 ] The same fix as in 'bonding: move dev_mc_sync after master_upper_dev_link in bond_enslave' is needed for team driver. The panic can be reproduced easily: ip link add team1 type team ip link set team1 up ip link add link team1 vlan1 type vlan id 80 ip link set vlan1 master team1 Fixes: cb41c997d444 ("team: team should sync the port's uc/mc addrs when add a port") Signed-off-by: Xin Long Acked-by: Jiri Pirko Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/team/team.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/drivers/net/team/team.c b/drivers/net/team/team.c index 23cd41c82210..2a366554c503 100644 --- a/drivers/net/team/team.c +++ b/drivers/net/team/team.c @@ -1197,11 +1197,6 @@ static int team_port_add(struct team *team, struct net_device *port_dev) goto err_dev_open; } - netif_addr_lock_bh(dev); - dev_uc_sync_multiple(port_dev, dev); - dev_mc_sync_multiple(port_dev, dev); - netif_addr_unlock_bh(dev); - err = vlan_vids_add_by_dev(port_dev, dev); if (err) { netdev_err(dev, "Failed to add vlan ids to device %s\n", @@ -1241,6 +1236,11 @@ static int team_port_add(struct team *team, struct net_device *port_dev) goto err_option_port_add; } + netif_addr_lock_bh(dev); + dev_uc_sync_multiple(port_dev, dev); + dev_mc_sync_multiple(port_dev, dev); + netif_addr_unlock_bh(dev); + port->index = -1; list_add_tail_rcu(&port->list, &team->port_list); team_port_enable(team, port); @@ -1265,8 +1265,6 @@ static int team_port_add(struct team *team, struct net_device *port_dev) vlan_vids_del_by_dev(port_dev, dev); err_vids_add: - dev_uc_unsync(port_dev, dev); - dev_mc_unsync(port_dev, dev); dev_close(port_dev); err_dev_open: -- GitLab From 9fdeb33e1913f4d1d2f8cdb9f78565452cbebcfb Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Mon, 26 Mar 2018 16:10:23 +0800 Subject: [PATCH 0316/1635] vhost_net: add missing lock nesting notation [ Upstream commit aaa3149bbee9ba9b4e6f0bd6e3e7d191edeae942 ] We try to hold TX virtqueue mutex in vhost_net_rx_peek_head_len() after RX virtqueue mutex is held in handle_rx(). This requires an appropriate lock nesting notation to calm down deadlock detector. Fixes: 0308813724606 ("vhost_net: basic polling support") Reported-by: syzbot+7f073540b1384a614e09@syzkaller.appspotmail.com Signed-off-by: Jason Wang Acked-by: Michael S. Tsirkin Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/vhost/net.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c index 082891dffd9d..b0d606b2d06c 100644 --- a/drivers/vhost/net.c +++ b/drivers/vhost/net.c @@ -622,7 +622,7 @@ static int vhost_net_rx_peek_head_len(struct vhost_net *net, struct sock *sk) if (!len && vq->busyloop_timeout) { /* Both tx vq and rx socket were polled here */ - mutex_lock(&vq->mutex); + mutex_lock_nested(&vq->mutex, 1); vhost_disable_notify(&net->dev, vq); preempt_disable(); @@ -755,7 +755,7 @@ static void handle_rx(struct vhost_net *net) struct iov_iter fixup; __virtio16 num_buffers; - mutex_lock(&vq->mutex); + mutex_lock_nested(&vq->mutex, 0); sock = vq->private_data; if (!sock) goto out; -- GitLab From fdae5b620566be0637b4b11df0e54c247df094f8 Mon Sep 17 00:00:00 2001 From: Moshe Shemesh Date: Tue, 27 Mar 2018 14:41:19 +0300 Subject: [PATCH 0317/1635] net/mlx4_core: Fix memory leak while delete slave's resources [ Upstream commit 461d5f1b59490ce0096dfda45e10038c122a7892 ] mlx4_delete_all_resources_for_slave in resource tracker should free all memory allocated for a slave. While releasing memory of fs_rule, it misses releasing memory of fs_rule->mirr_mbox. Fixes: 78efed275117 ('net/mlx4_core: Support mirroring VF DMFS rules on both ports') Signed-off-by: Moshe Shemesh Signed-off-by: Tariq Toukan Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/mellanox/mlx4/resource_tracker.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c b/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c index fabb53379727..a069fcc823c3 100644 --- a/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c +++ b/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c @@ -5089,6 +5089,7 @@ static void rem_slave_fs_rule(struct mlx4_dev *dev, int slave) &tracker->res_tree[RES_FS_RULE]); list_del(&fs_rule->com.list); spin_unlock_irq(mlx4_tlock(dev)); + kfree(fs_rule->mirr_mbox); kfree(fs_rule); state = 0; break; -- GitLab From ffebeb0d7c37716ef2732646001522a6a764e284 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 12 Apr 2018 12:32:27 +0200 Subject: [PATCH 0318/1635] Linux 4.14.34 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 00dd6af8eab4..a6906dfb112e 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 VERSION = 4 PATCHLEVEL = 14 -SUBLEVEL = 33 +SUBLEVEL = 34 EXTRAVERSION = NAME = Petit Gorille -- GitLab From a2a9032a98b238059ca04ce40de73b22a8bc1a55 Mon Sep 17 00:00:00 2001 From: Jaegeuk Kim Date: Fri, 5 Jan 2018 10:44:52 -0800 Subject: [PATCH 0319/1635] f2fs/fscrypt: updates to v4.17-rc1 Pull f2fs update from Jaegeuk Kim: "In this round, we've mainly focused on performance tuning and critical bug fixes occurred in low-end devices. Sheng Yong introduced lost_found feature to keep missing files during recovery instead of thrashing them. We're preparing coming fsverity implementation. And, we've got more features to communicate with users for better performance. In low-end devices, some memory-related issues were fixed, and subtle race condtions and corner cases were addressed as well. Enhancements: - large nat bitmaps for more free node ids - add three block allocation policies to pass down write hints given by user - expose extension list to user and introduce hot file extension - tune small devices seamlessly for low-end devices - set readdir_ra by default - give more resources under gc_urgent mode regarding to discard and cleaning - introduce fsync_mode to enforce posix or not - nowait aio support - add lost_found feature to keep dangling inodes - reserve bits for future fsverity feature - add test_dummy_encryption for FBE Bug fixes: - don't use highmem for dentry pages - align memory boundary for bitops - truncate preallocated blocks in write errors - guarantee i_times on fsync call - clear CP_TRIMMED_FLAG correctly - prevent node chain loop during recovery - avoid data race between atomic write and background cleaning - avoid unnecessary selinux violation warnings on resgid option - GFP_NOFS to avoid deadlock in quota and read paths - fix f2fs_skip_inode_update to allow i_size recovery In addition to the above, there are several minor bug fixes and clean-ups" Cherry-pick from origin/upstream-f2fs-stable-linux-4.14.y: de465aa57271 f2fs: remain written times to update inode during fsync d0ebaf0b37b2 f2fs: make assignment of t->dentry_bitmap more readable 7f05fb451696 f2fs: truncate preallocated blocks in error case a0a9a51ecdd1 f2fs: fix a wrong condition in f2fs_skip_inode_update 5dc89047c9e8 f2fs: reserve bits for fs-verity 0751f01376d5 f2fs: Add a segment type check in inplace write 27d9598d4d38 f2fs: no need to initialize zero value for GFP_F2FS_ZERO 42a34ff76240 f2fs: don't track new nat entry in nat set 14040505a620 f2fs: clean up with F2FS_BLK_ALIGN fcea9e00a0ea f2fs: check blkaddr more accuratly before issue a bio 2c217b078fee f2fs: Set GF_NOFS in read_cache_page_gfp while doing f2fs_quota_read 0a8cedc2cea3 f2fs: introduce a new mount option test_dummy_encryption 5786b414a719 f2fs: introduce F2FS_FEATURE_LOST_FOUND feature 9813cae680f0 f2fs: release locks before return in f2fs_ioc_gc_range() cee6482cd12c f2fs: align memory boundary for bitops 8dbfcba5f5d6 f2fs: remove unneeded set_cold_node() 7e93bf8ebc34 f2fs: add nowait aio support 1e64d3ed2753 f2fs: wrap all options with f2fs_sb_info.mount_opt 7f270a67a1da f2fs: Don't overwrite all types of node to keep node chain c6a9e6a41f4f f2fs: introduce mount option for fsync mode 82bebed3c1fd f2fs: fix to restore old mount option in ->remount_fs 808427a63b93 f2fs: wrap sb_rdonly with f2fs_readonly 5ebe362c0c60 f2fs: avoid selinux denial on CAP_SYS_RESOURCE ea34734357a9 f2fs: support hot file extension 2189c2e46468 f2fs: fix to avoid race in between atomic write and background GC 5f6950805928 f2fs: do gc in greedy mode for whole range if gc_urgent mode is set 79f1a15fa536 f2fs: issue discard aggressively in the gc_urgent mode aea8da88a747 f2fs: set readdir_ra by default 8fe06ea28273 f2fs: add auto tuning for small devices 073c145d5bef f2fs: add mount option for segment allocation policy e7efe40d7aa5 f2fs: don't stop GC if GC is contended 882d0e094488 f2fs: expose extension_list sysfs entry 52320a2a28be f2fs: fix to set KEEP_SIZE bit in f2fs_zero_range ef66237f28e9 f2fs: introduce sb_lock to make encrypt pwsalt update exclusive c8e77267ed1f f2fs: remove redundant initialization of pointer 'p' 755dcc3262d4 f2fs: flush cp pack except cp pack 2 page at first 92223ccb699a f2fs: clean up f2fs_sb_has_xxx functions d8ecd46ca803 f2fs: remove redundant check of page type when submit bio 99f512132e54 f2fs: fix to handle looped node chain during recovery 66a2346def3d f2fs: handle quota for orphan inodes bd9e1956d17e f2fs: support passing down write hints to block layer with F2FS policy d8f02c3b68c5 f2fs: support passing down write hints given by users to block layer d4fff1411d4e f2fs: fix to clear CP_TRIMMED_FLAG f50100868cb8 f2fs: support large nat bitmap e9437125502c f2fs: fix to check extent cache in f2fs_drop_extent_tree 5c1d55c37f2c f2fs: restrict inline_xattr_size configuration 74d48dc6ec93 f2fs: fix heap mode to reset it back 68afcb259568 f2fs: fix potential corruption in area before F2FS_SUPER_OFFSET 6b4edfb10398 fscrypt: fix build with pre-4.6 gcc versions 4bcc4865feab fscrypt: remove 'ci' parameter from fscrypt_put_encryption_info() 69e5234f04b6 fscrypt: fix up fscrypt_fname_encrypted_size() for internal use 7919cba92304 fscrypt: define fscrypt_fname_alloc_buffer() to be for presented names aef0017f3b1a fscrypt: calculate NUL-padding length in one place only 5232cae0e922 fscrypt: move fscrypt_symlink_data to fscrypt_private.h 169bd9ba8542 ubifs: switch to fscrypt_get_symlink() 63498ca7def3 ubifs: switch to fscrypt ->symlink() helper functions a85637d12cb1 fscrypt: remove fscrypt_fname_usr_to_disk() 77bb20f72679 ext4: switch to fscrypt_get_symlink() 79b3f39a2e79 ext4: switch to fscrypt ->symlink() helper functions 70fe2fb67bc6 f2fs: switch to fscrypt_get_symlink() 96dda4e02d6b f2fs: switch to fscrypt ->symlink() helper functions 0063988cc044 fscrypt: new helper function - fscrypt_get_symlink() 48a0375c8889 fscrypt: new helper functions for ->symlink() 585a194dd1d0 fscrypt: trim down fscrypt.h includes 411771ab56f4 fscrypt: move fscrypt_is_dot_dotdot() to fs/crypto/fname.c ad35db34396b fscrypt: move fscrypt_valid_enc_modes() to fscrypt_private.h 72b3e1c61d8b fscrypt: move fscrypt_operations declaration to fscrypt_supp.h 2fa9a1f9268a fscrypt: split fscrypt_dummy_context_enabled() into supp/notsupp versions e298b5de1cca fscrypt: move fscrypt_ctx declaration to fscrypt_supp.h 8db0a6de3cf0 fscrypt: move fscrypt_info_cachep declaration to fscrypt_private.h c73c350ade4e fscrypt: move fscrypt_control_page() to supp/notsupp headers ca64f2f4609d fscrypt: move fscrypt_has_encryption_key() to supp/notsupp headers Signed-off-by: Jaegeuk Kim --- Documentation/ABI/testing/sysfs-fs-f2fs | 11 + Documentation/filesystems/f2fs.txt | 17 ++ fs/crypto/crypto.c | 1 + fs/crypto/fname.c | 140 +++++----- fs/crypto/fscrypt_private.h | 31 +++ fs/crypto/hooks.c | 158 +++++++++++ fs/crypto/keyinfo.c | 17 +- fs/ext4/namei.c | 58 +--- fs/ext4/super.c | 4 +- fs/ext4/symlink.c | 43 +-- fs/f2fs/checkpoint.c | 101 ++++--- fs/f2fs/data.c | 85 ++++-- fs/f2fs/dir.c | 9 +- fs/f2fs/extent_cache.c | 5 +- fs/f2fs/f2fs.h | 182 ++++++++----- fs/f2fs/file.c | 94 +++++-- fs/f2fs/gc.c | 23 +- fs/f2fs/inode.c | 11 +- fs/f2fs/namei.c | 247 +++++++++-------- fs/f2fs/node.c | 55 +++- fs/f2fs/node.h | 5 +- fs/f2fs/recovery.c | 14 + fs/f2fs/segment.c | 133 ++++++++- fs/f2fs/segment.h | 27 +- fs/f2fs/super.c | 348 +++++++++++++++++------- fs/f2fs/sysfs.c | 73 ++++- fs/ubifs/dir.c | 55 +--- fs/ubifs/file.c | 36 +-- fs/ubifs/super.c | 4 +- include/linux/f2fs_fs.h | 19 +- include/linux/fscrypt.h | 174 +++++------- include/linux/fscrypt_notsupp.h | 59 ++-- include/linux/fscrypt_supp.h | 68 ++++- 33 files changed, 1489 insertions(+), 818 deletions(-) diff --git a/Documentation/ABI/testing/sysfs-fs-f2fs b/Documentation/ABI/testing/sysfs-fs-f2fs index d870b5514d15..540553c933b6 100644 --- a/Documentation/ABI/testing/sysfs-fs-f2fs +++ b/Documentation/ABI/testing/sysfs-fs-f2fs @@ -192,3 +192,14 @@ Date: November 2017 Contact: "Sheng Yong" Description: Controls readahead inode block in readdir. + +What: /sys/fs/f2fs//extension_list +Date: Feburary 2018 +Contact: "Chao Yu" +Description: + Used to control configure extension list: + - Query: cat /sys/fs/f2fs//extension_list + - Add: echo '[h/c]extension' > /sys/fs/f2fs//extension_list + - Del: echo '[h/c]!extension' > /sys/fs/f2fs//extension_list + - [h] means add/del hot file extension + - [c] means add/del cold file extension diff --git a/Documentation/filesystems/f2fs.txt b/Documentation/filesystems/f2fs.txt index 13c2ff034348..4b6cf4c5e061 100644 --- a/Documentation/filesystems/f2fs.txt +++ b/Documentation/filesystems/f2fs.txt @@ -174,6 +174,23 @@ offgrpjquota Turn off group journelled quota. offprjjquota Turn off project journelled quota. quota Enable plain user disk quota accounting. noquota Disable all plain disk quota option. +whint_mode=%s Control which write hints are passed down to block + layer. This supports "off", "user-based", and + "fs-based". In "off" mode (default), f2fs does not pass + down hints. In "user-based" mode, f2fs tries to pass + down hints given by users. And in "fs-based" mode, f2fs + passes down hints with its policy. +alloc_mode=%s Adjust block allocation policy, which supports "reuse" + and "default". +fsync_mode=%s Control the policy of fsync. Currently supports "posix" + and "strict". In "posix" mode, which is default, fsync + will follow POSIX semantics and does a light operation + to improve the filesystem performance. In "strict" mode, + fsync will be heavy and behaves in line with xfs, ext4 + and btrfs, where xfstest generic/342 will pass, but the + performance will regress. +test_dummy_encryption Enable dummy encryption, which provides a fake fscrypt + context. The fake fscrypt context is used by xfstests. ================================================================================ DEBUGFS ENTRIES diff --git a/fs/crypto/crypto.c b/fs/crypto/crypto.c index 732a786cce9d..ce654526c0fb 100644 --- a/fs/crypto/crypto.c +++ b/fs/crypto/crypto.c @@ -27,6 +27,7 @@ #include #include #include +#include #include "fscrypt_private.h" static unsigned int num_prealloc_crypto_pages = 32; diff --git a/fs/crypto/fname.c b/fs/crypto/fname.c index 305541bcd108..e33f3d3c5ade 100644 --- a/fs/crypto/fname.c +++ b/fs/crypto/fname.c @@ -13,42 +13,46 @@ #include #include +#include #include "fscrypt_private.h" +static inline bool fscrypt_is_dot_dotdot(const struct qstr *str) +{ + if (str->len == 1 && str->name[0] == '.') + return true; + + if (str->len == 2 && str->name[0] == '.' && str->name[1] == '.') + return true; + + return false; +} + /** * fname_encrypt() - encrypt a filename * - * The caller must have allocated sufficient memory for the @oname string. + * The output buffer must be at least as large as the input buffer. + * Any extra space is filled with NUL padding before encryption. * * Return: 0 on success, -errno on failure */ -static int fname_encrypt(struct inode *inode, - const struct qstr *iname, struct fscrypt_str *oname) +int fname_encrypt(struct inode *inode, const struct qstr *iname, + u8 *out, unsigned int olen) { struct skcipher_request *req = NULL; DECLARE_CRYPTO_WAIT(wait); - struct fscrypt_info *ci = inode->i_crypt_info; - struct crypto_skcipher *tfm = ci->ci_ctfm; + struct crypto_skcipher *tfm = inode->i_crypt_info->ci_ctfm; int res = 0; char iv[FS_CRYPTO_BLOCK_SIZE]; struct scatterlist sg; - int padding = 4 << (ci->ci_flags & FS_POLICY_FLAGS_PAD_MASK); - unsigned int lim; - unsigned int cryptlen; - - lim = inode->i_sb->s_cop->max_namelen(inode); - if (iname->len <= 0 || iname->len > lim) - return -EIO; /* * Copy the filename to the output buffer for encrypting in-place and * pad it with the needed number of NUL bytes. */ - cryptlen = max_t(unsigned int, iname->len, FS_CRYPTO_BLOCK_SIZE); - cryptlen = round_up(cryptlen, padding); - cryptlen = min(cryptlen, lim); - memcpy(oname->name, iname->name, iname->len); - memset(oname->name + iname->len, 0, cryptlen - iname->len); + if (WARN_ON(olen < iname->len)) + return -ENOBUFS; + memcpy(out, iname->name, iname->len); + memset(out + iname->len, 0, olen - iname->len); /* Initialize the IV */ memset(iv, 0, FS_CRYPTO_BLOCK_SIZE); @@ -63,8 +67,8 @@ static int fname_encrypt(struct inode *inode, skcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP, crypto_req_done, &wait); - sg_init_one(&sg, oname->name, cryptlen); - skcipher_request_set_crypt(req, &sg, &sg, cryptlen, iv); + sg_init_one(&sg, out, olen); + skcipher_request_set_crypt(req, &sg, &sg, olen, iv); /* Do the encryption */ res = crypto_wait_req(crypto_skcipher_encrypt(req), &wait); @@ -75,7 +79,6 @@ static int fname_encrypt(struct inode *inode, return res; } - oname->len = cryptlen; return 0; } @@ -188,50 +191,52 @@ static int digest_decode(const char *src, int len, char *dst) return cp - dst; } -u32 fscrypt_fname_encrypted_size(const struct inode *inode, u32 ilen) +bool fscrypt_fname_encrypted_size(const struct inode *inode, u32 orig_len, + u32 max_len, u32 *encrypted_len_ret) { - int padding = 32; - struct fscrypt_info *ci = inode->i_crypt_info; - - if (ci) - padding = 4 << (ci->ci_flags & FS_POLICY_FLAGS_PAD_MASK); - ilen = max(ilen, (u32)FS_CRYPTO_BLOCK_SIZE); - return round_up(ilen, padding); + int padding = 4 << (inode->i_crypt_info->ci_flags & + FS_POLICY_FLAGS_PAD_MASK); + u32 encrypted_len; + + if (orig_len > max_len) + return false; + encrypted_len = max(orig_len, (u32)FS_CRYPTO_BLOCK_SIZE); + encrypted_len = round_up(encrypted_len, padding); + *encrypted_len_ret = min(encrypted_len, max_len); + return true; } -EXPORT_SYMBOL(fscrypt_fname_encrypted_size); /** - * fscrypt_fname_crypto_alloc_obuff() - + * fscrypt_fname_alloc_buffer - allocate a buffer for presented filenames + * + * Allocate a buffer that is large enough to hold any decrypted or encoded + * filename (null-terminated), for the given maximum encrypted filename length. * - * Allocates an output buffer that is sufficient for the crypto operation - * specified by the context and the direction. + * Return: 0 on success, -errno on failure */ int fscrypt_fname_alloc_buffer(const struct inode *inode, - u32 ilen, struct fscrypt_str *crypto_str) + u32 max_encrypted_len, + struct fscrypt_str *crypto_str) { - u32 olen = fscrypt_fname_encrypted_size(inode, ilen); const u32 max_encoded_len = max_t(u32, BASE64_CHARS(FSCRYPT_FNAME_MAX_UNDIGESTED_SIZE), 1 + BASE64_CHARS(sizeof(struct fscrypt_digested_name))); + u32 max_presented_len; - crypto_str->len = olen; - olen = max(olen, max_encoded_len); + max_presented_len = max(max_encoded_len, max_encrypted_len); - /* - * Allocated buffer can hold one more character to null-terminate the - * string - */ - crypto_str->name = kmalloc(olen + 1, GFP_NOFS); - if (!(crypto_str->name)) + crypto_str->name = kmalloc(max_presented_len + 1, GFP_NOFS); + if (!crypto_str->name) return -ENOMEM; + crypto_str->len = max_presented_len; return 0; } EXPORT_SYMBOL(fscrypt_fname_alloc_buffer); /** - * fscrypt_fname_crypto_free_buffer() - + * fscrypt_fname_free_buffer - free the buffer for presented filenames * - * Frees the buffer allocated for crypto operation. + * Free the buffer allocated by fscrypt_fname_alloc_buffer(). */ void fscrypt_fname_free_buffer(struct fscrypt_str *crypto_str) { @@ -297,35 +302,6 @@ int fscrypt_fname_disk_to_usr(struct inode *inode, } EXPORT_SYMBOL(fscrypt_fname_disk_to_usr); -/** - * fscrypt_fname_usr_to_disk() - converts a filename from user space to disk - * space - * - * The caller must have allocated sufficient memory for the @oname string. - * - * Return: 0 on success, -errno on failure - */ -int fscrypt_fname_usr_to_disk(struct inode *inode, - const struct qstr *iname, - struct fscrypt_str *oname) -{ - if (fscrypt_is_dot_dotdot(iname)) { - oname->name[0] = '.'; - oname->name[iname->len - 1] = '.'; - oname->len = iname->len; - return 0; - } - if (inode->i_crypt_info) - return fname_encrypt(inode, iname, oname); - /* - * Without a proper key, a user is not allowed to modify the filenames - * in a directory. Consequently, a user space name cannot be mapped to - * a disk-space name - */ - return -ENOKEY; -} -EXPORT_SYMBOL(fscrypt_fname_usr_to_disk); - /** * fscrypt_setup_filename() - prepare to search a possibly encrypted directory * @dir: the directory that will be searched @@ -369,11 +345,17 @@ int fscrypt_setup_filename(struct inode *dir, const struct qstr *iname, return ret; if (dir->i_crypt_info) { - ret = fscrypt_fname_alloc_buffer(dir, iname->len, - &fname->crypto_buf); - if (ret) - return ret; - ret = fname_encrypt(dir, iname, &fname->crypto_buf); + if (!fscrypt_fname_encrypted_size(dir, iname->len, + dir->i_sb->s_cop->max_namelen(dir), + &fname->crypto_buf.len)) + return -ENAMETOOLONG; + fname->crypto_buf.name = kmalloc(fname->crypto_buf.len, + GFP_NOFS); + if (!fname->crypto_buf.name) + return -ENOMEM; + + ret = fname_encrypt(dir, iname, fname->crypto_buf.name, + fname->crypto_buf.len); if (ret) goto errout; fname->disk_name.name = fname->crypto_buf.name; @@ -425,7 +407,7 @@ int fscrypt_setup_filename(struct inode *dir, const struct qstr *iname, return 0; errout: - fscrypt_fname_free_buffer(&fname->crypto_buf); + kfree(fname->crypto_buf.name); return ret; } EXPORT_SYMBOL(fscrypt_setup_filename); diff --git a/fs/crypto/fscrypt_private.h b/fs/crypto/fscrypt_private.h index c0b4f5597e1a..ad6722bae8b7 100644 --- a/fs/crypto/fscrypt_private.h +++ b/fs/crypto/fscrypt_private.h @@ -50,6 +50,15 @@ struct fscrypt_context { #define FS_ENCRYPTION_CONTEXT_FORMAT_V1 1 +/** + * For encrypted symlinks, the ciphertext length is stored at the beginning + * of the string in little-endian format. + */ +struct fscrypt_symlink_data { + __le16 len; + char encrypted_path[1]; +} __packed; + /* * A pointer to this structure is stored in the file system's in-core * representation of an inode. @@ -71,7 +80,22 @@ typedef enum { #define FS_CTX_REQUIRES_FREE_ENCRYPT_FL 0x00000001 #define FS_CTX_HAS_BOUNCE_BUFFER_FL 0x00000002 +static inline bool fscrypt_valid_enc_modes(u32 contents_mode, + u32 filenames_mode) +{ + if (contents_mode == FS_ENCRYPTION_MODE_AES_128_CBC && + filenames_mode == FS_ENCRYPTION_MODE_AES_128_CTS) + return true; + + if (contents_mode == FS_ENCRYPTION_MODE_AES_256_XTS && + filenames_mode == FS_ENCRYPTION_MODE_AES_256_CTS) + return true; + + return false; +} + /* crypto.c */ +extern struct kmem_cache *fscrypt_info_cachep; extern int fscrypt_initialize(unsigned int cop_flags); extern struct workqueue_struct *fscrypt_read_workqueue; extern int fscrypt_do_page_crypto(const struct inode *inode, @@ -83,6 +107,13 @@ extern int fscrypt_do_page_crypto(const struct inode *inode, extern struct page *fscrypt_alloc_bounce_page(struct fscrypt_ctx *ctx, gfp_t gfp_flags); +/* fname.c */ +extern int fname_encrypt(struct inode *inode, const struct qstr *iname, + u8 *out, unsigned int olen); +extern bool fscrypt_fname_encrypted_size(const struct inode *inode, + u32 orig_len, u32 max_len, + u32 *encrypted_len_ret); + /* keyinfo.c */ extern void __exit fscrypt_essiv_cleanup(void); diff --git a/fs/crypto/hooks.c b/fs/crypto/hooks.c index 9f5fb2eb9cf7..bec06490fb13 100644 --- a/fs/crypto/hooks.c +++ b/fs/crypto/hooks.c @@ -110,3 +110,161 @@ int __fscrypt_prepare_lookup(struct inode *dir, struct dentry *dentry) return 0; } EXPORT_SYMBOL_GPL(__fscrypt_prepare_lookup); + +int __fscrypt_prepare_symlink(struct inode *dir, unsigned int len, + unsigned int max_len, + struct fscrypt_str *disk_link) +{ + int err; + + /* + * To calculate the size of the encrypted symlink target we need to know + * the amount of NUL padding, which is determined by the flags set in + * the encryption policy which will be inherited from the directory. + * The easiest way to get access to this is to just load the directory's + * fscrypt_info, since we'll need it to create the dir_entry anyway. + * + * Note: in test_dummy_encryption mode, @dir may be unencrypted. + */ + err = fscrypt_get_encryption_info(dir); + if (err) + return err; + if (!fscrypt_has_encryption_key(dir)) + return -ENOKEY; + + /* + * Calculate the size of the encrypted symlink and verify it won't + * exceed max_len. Note that for historical reasons, encrypted symlink + * targets are prefixed with the ciphertext length, despite this + * actually being redundant with i_size. This decreases by 2 bytes the + * longest symlink target we can accept. + * + * We could recover 1 byte by not counting a null terminator, but + * counting it (even though it is meaningless for ciphertext) is simpler + * for now since filesystems will assume it is there and subtract it. + */ + if (!fscrypt_fname_encrypted_size(dir, len, + max_len - sizeof(struct fscrypt_symlink_data), + &disk_link->len)) + return -ENAMETOOLONG; + disk_link->len += sizeof(struct fscrypt_symlink_data); + + disk_link->name = NULL; + return 0; +} +EXPORT_SYMBOL_GPL(__fscrypt_prepare_symlink); + +int __fscrypt_encrypt_symlink(struct inode *inode, const char *target, + unsigned int len, struct fscrypt_str *disk_link) +{ + int err; + struct qstr iname = QSTR_INIT(target, len); + struct fscrypt_symlink_data *sd; + unsigned int ciphertext_len; + + err = fscrypt_require_key(inode); + if (err) + return err; + + if (disk_link->name) { + /* filesystem-provided buffer */ + sd = (struct fscrypt_symlink_data *)disk_link->name; + } else { + sd = kmalloc(disk_link->len, GFP_NOFS); + if (!sd) + return -ENOMEM; + } + ciphertext_len = disk_link->len - sizeof(*sd); + sd->len = cpu_to_le16(ciphertext_len); + + err = fname_encrypt(inode, &iname, sd->encrypted_path, ciphertext_len); + if (err) { + if (!disk_link->name) + kfree(sd); + return err; + } + /* + * Null-terminating the ciphertext doesn't make sense, but we still + * count the null terminator in the length, so we might as well + * initialize it just in case the filesystem writes it out. + */ + sd->encrypted_path[ciphertext_len] = '\0'; + + if (!disk_link->name) + disk_link->name = (unsigned char *)sd; + return 0; +} +EXPORT_SYMBOL_GPL(__fscrypt_encrypt_symlink); + +/** + * fscrypt_get_symlink - get the target of an encrypted symlink + * @inode: the symlink inode + * @caddr: the on-disk contents of the symlink + * @max_size: size of @caddr buffer + * @done: if successful, will be set up to free the returned target + * + * If the symlink's encryption key is available, we decrypt its target. + * Otherwise, we encode its target for presentation. + * + * This may sleep, so the filesystem must have dropped out of RCU mode already. + * + * Return: the presentable symlink target or an ERR_PTR() + */ +const char *fscrypt_get_symlink(struct inode *inode, const void *caddr, + unsigned int max_size, + struct delayed_call *done) +{ + const struct fscrypt_symlink_data *sd; + struct fscrypt_str cstr, pstr; + int err; + + /* This is for encrypted symlinks only */ + if (WARN_ON(!IS_ENCRYPTED(inode))) + return ERR_PTR(-EINVAL); + + /* + * Try to set up the symlink's encryption key, but we can continue + * regardless of whether the key is available or not. + */ + err = fscrypt_get_encryption_info(inode); + if (err) + return ERR_PTR(err); + + /* + * For historical reasons, encrypted symlink targets are prefixed with + * the ciphertext length, even though this is redundant with i_size. + */ + + if (max_size < sizeof(*sd)) + return ERR_PTR(-EUCLEAN); + sd = caddr; + cstr.name = (unsigned char *)sd->encrypted_path; + cstr.len = le16_to_cpu(sd->len); + + if (cstr.len == 0) + return ERR_PTR(-EUCLEAN); + + if (cstr.len + sizeof(*sd) - 1 > max_size) + return ERR_PTR(-EUCLEAN); + + err = fscrypt_fname_alloc_buffer(inode, cstr.len, &pstr); + if (err) + return ERR_PTR(err); + + err = fscrypt_fname_disk_to_usr(inode, 0, 0, &cstr, &pstr); + if (err) + goto err_kfree; + + err = -EUCLEAN; + if (pstr.name[0] == '\0') + goto err_kfree; + + pstr.name[pstr.len] = '\0'; + set_delayed_call(done, kfree_link, pstr.name); + return pstr.name; + +err_kfree: + kfree(pstr.name); + return ERR_PTR(err); +} +EXPORT_SYMBOL_GPL(fscrypt_get_symlink); diff --git a/fs/crypto/keyinfo.c b/fs/crypto/keyinfo.c index 5e6e846f5a24..05f5ee1f0705 100644 --- a/fs/crypto/keyinfo.c +++ b/fs/crypto/keyinfo.c @@ -14,6 +14,7 @@ #include #include #include +#include #include "fscrypt_private.h" static struct crypto_shash *essiv_hash_tfm; @@ -354,19 +355,9 @@ int fscrypt_get_encryption_info(struct inode *inode) } EXPORT_SYMBOL(fscrypt_get_encryption_info); -void fscrypt_put_encryption_info(struct inode *inode, struct fscrypt_info *ci) +void fscrypt_put_encryption_info(struct inode *inode) { - struct fscrypt_info *prev; - - if (ci == NULL) - ci = READ_ONCE(inode->i_crypt_info); - if (ci == NULL) - return; - - prev = cmpxchg(&inode->i_crypt_info, ci, NULL); - if (prev != ci) - return; - - put_crypt_info(ci); + put_crypt_info(inode->i_crypt_info); + inode->i_crypt_info = NULL; } EXPORT_SYMBOL(fscrypt_put_encryption_info); diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c index fccf295fcb03..5c20f9b6e856 100644 --- a/fs/ext4/namei.c +++ b/fs/ext4/namei.c @@ -3066,39 +3066,19 @@ static int ext4_symlink(struct inode *dir, struct inode *inode; int err, len = strlen(symname); int credits; - bool encryption_required; struct fscrypt_str disk_link; - struct fscrypt_symlink_data *sd = NULL; if (unlikely(ext4_forced_shutdown(EXT4_SB(dir->i_sb)))) return -EIO; - disk_link.len = len + 1; - disk_link.name = (char *) symname; - - encryption_required = (ext4_encrypted_inode(dir) || - DUMMY_ENCRYPTION_ENABLED(EXT4_SB(dir->i_sb))); - if (encryption_required) { - err = fscrypt_get_encryption_info(dir); - if (err) - return err; - if (!fscrypt_has_encryption_key(dir)) - return -ENOKEY; - disk_link.len = (fscrypt_fname_encrypted_size(dir, len) + - sizeof(struct fscrypt_symlink_data)); - sd = kzalloc(disk_link.len, GFP_KERNEL); - if (!sd) - return -ENOMEM; - } - - if (disk_link.len > dir->i_sb->s_blocksize) { - err = -ENAMETOOLONG; - goto err_free_sd; - } + err = fscrypt_prepare_symlink(dir, symname, len, dir->i_sb->s_blocksize, + &disk_link); + if (err) + return err; err = dquot_initialize(dir); if (err) - goto err_free_sd; + return err; if ((disk_link.len > EXT4_N_BLOCKS * 4)) { /* @@ -3127,27 +3107,18 @@ static int ext4_symlink(struct inode *dir, if (IS_ERR(inode)) { if (handle) ext4_journal_stop(handle); - err = PTR_ERR(inode); - goto err_free_sd; + return PTR_ERR(inode); } - if (encryption_required) { - struct qstr istr; - struct fscrypt_str ostr = - FSTR_INIT(sd->encrypted_path, disk_link.len); - - istr.name = (const unsigned char *) symname; - istr.len = len; - err = fscrypt_fname_usr_to_disk(inode, &istr, &ostr); + if (IS_ENCRYPTED(inode)) { + err = fscrypt_encrypt_symlink(inode, symname, len, &disk_link); if (err) goto err_drop_inode; - sd->len = cpu_to_le16(ostr.len); - disk_link.name = (char *) sd; inode->i_op = &ext4_encrypted_symlink_inode_operations; } if ((disk_link.len > EXT4_N_BLOCKS * 4)) { - if (!encryption_required) + if (!IS_ENCRYPTED(inode)) inode->i_op = &ext4_symlink_inode_operations; inode_nohighmem(inode); ext4_set_aops(inode); @@ -3189,7 +3160,7 @@ static int ext4_symlink(struct inode *dir, } else { /* clear the extent format for fast symlink */ ext4_clear_inode_flag(inode, EXT4_INODE_EXTENTS); - if (!encryption_required) { + if (!IS_ENCRYPTED(inode)) { inode->i_op = &ext4_fast_symlink_inode_operations; inode->i_link = (char *)&EXT4_I(inode)->i_data; } @@ -3204,16 +3175,17 @@ static int ext4_symlink(struct inode *dir, if (handle) ext4_journal_stop(handle); - kfree(sd); - return err; + goto out_free_encrypted_link; + err_drop_inode: if (handle) ext4_journal_stop(handle); clear_nlink(inode); unlock_new_inode(inode); iput(inode); -err_free_sd: - kfree(sd); +out_free_encrypted_link: + if (disk_link.name != (unsigned char *)symname) + kfree(disk_link.name); return err; } diff --git a/fs/ext4/super.c b/fs/ext4/super.c index c3c5bf46e5e6..db9ae6edc8fb 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -1070,9 +1070,7 @@ void ext4_clear_inode(struct inode *inode) jbd2_free_inode(EXT4_I(inode)->jinode); EXT4_I(inode)->jinode = NULL; } -#ifdef CONFIG_EXT4_FS_ENCRYPTION - fscrypt_put_encryption_info(inode, NULL); -#endif + fscrypt_put_encryption_info(inode); } static struct inode *ext4_nfs_get_inode(struct super_block *sb, diff --git a/fs/ext4/symlink.c b/fs/ext4/symlink.c index a2006c9af1d9..dd05af983092 100644 --- a/fs/ext4/symlink.c +++ b/fs/ext4/symlink.c @@ -28,59 +28,28 @@ static const char *ext4_encrypted_get_link(struct dentry *dentry, struct delayed_call *done) { struct page *cpage = NULL; - char *caddr, *paddr = NULL; - struct fscrypt_str cstr, pstr; - struct fscrypt_symlink_data *sd; - int res; - u32 max_size = inode->i_sb->s_blocksize; + const void *caddr; + unsigned int max_size; + const char *paddr; if (!dentry) return ERR_PTR(-ECHILD); - res = fscrypt_get_encryption_info(inode); - if (res) - return ERR_PTR(res); - if (ext4_inode_is_fast_symlink(inode)) { - caddr = (char *) EXT4_I(inode)->i_data; + caddr = EXT4_I(inode)->i_data; max_size = sizeof(EXT4_I(inode)->i_data); } else { cpage = read_mapping_page(inode->i_mapping, 0, NULL); if (IS_ERR(cpage)) return ERR_CAST(cpage); caddr = page_address(cpage); + max_size = inode->i_sb->s_blocksize; } - /* Symlink is encrypted */ - sd = (struct fscrypt_symlink_data *)caddr; - cstr.name = sd->encrypted_path; - cstr.len = le16_to_cpu(sd->len); - if ((cstr.len + sizeof(struct fscrypt_symlink_data) - 1) > max_size) { - /* Symlink data on the disk is corrupted */ - res = -EFSCORRUPTED; - goto errout; - } - - res = fscrypt_fname_alloc_buffer(inode, cstr.len, &pstr); - if (res) - goto errout; - paddr = pstr.name; - - res = fscrypt_fname_disk_to_usr(inode, 0, 0, &cstr, &pstr); - if (res) - goto errout; - - /* Null-terminate the name */ - paddr[pstr.len] = '\0'; + paddr = fscrypt_get_symlink(inode, caddr, max_size, done); if (cpage) put_page(cpage); - set_delayed_call(done, kfree_link, paddr); return paddr; -errout: - if (cpage) - put_page(cpage); - kfree(paddr); - return ERR_PTR(res); } const struct inode_operations ext4_encrypted_symlink_inode_operations = { diff --git a/fs/f2fs/checkpoint.c b/fs/f2fs/checkpoint.c index 701781a372f3..6c7b0547a307 100644 --- a/fs/f2fs/checkpoint.c +++ b/fs/f2fs/checkpoint.c @@ -68,6 +68,7 @@ static struct page *__get_meta_page(struct f2fs_sb_info *sbi, pgoff_t index, .old_blkaddr = index, .new_blkaddr = index, .encrypted_page = NULL, + .is_meta = is_meta, }; if (unlikely(!is_meta)) @@ -162,6 +163,7 @@ int ra_meta_pages(struct f2fs_sb_info *sbi, block_t start, int nrpages, .op_flags = sync ? (REQ_META | REQ_PRIO) : REQ_RAHEAD, .encrypted_page = NULL, .in_list = false, + .is_meta = (type != META_POR), }; struct blk_plug plug; @@ -572,13 +574,8 @@ static int recover_orphan_inode(struct f2fs_sb_info *sbi, nid_t ino) struct node_info ni; int err = acquire_orphan_inode(sbi); - if (err) { - set_sbi_flag(sbi, SBI_NEED_FSCK); - f2fs_msg(sbi->sb, KERN_WARNING, - "%s: orphan failed (ino=%x), run fsck to fix.", - __func__, ino); - return err; - } + if (err) + goto err_out; __add_ino_entry(sbi, ino, 0, ORPHAN_INO); @@ -592,6 +589,11 @@ static int recover_orphan_inode(struct f2fs_sb_info *sbi, nid_t ino) return PTR_ERR(inode); } + err = dquot_initialize(inode); + if (err) + goto err_out; + + dquot_initialize(inode); clear_nlink(inode); /* truncate all the data during iput */ @@ -601,14 +603,18 @@ static int recover_orphan_inode(struct f2fs_sb_info *sbi, nid_t ino) /* ENOMEM was fully retried in f2fs_evict_inode. */ if (ni.blk_addr != NULL_ADDR) { - set_sbi_flag(sbi, SBI_NEED_FSCK); - f2fs_msg(sbi->sb, KERN_WARNING, - "%s: orphan failed (ino=%x) by kernel, retry mount.", - __func__, ino); - return -EIO; + err = -EIO; + goto err_out; } __remove_ino_entry(sbi, ino, ORPHAN_INO); return 0; + +err_out: + set_sbi_flag(sbi, SBI_NEED_FSCK); + f2fs_msg(sbi->sb, KERN_WARNING, + "%s: orphan failed (ino=%x), run fsck to fix.", + __func__, ino); + return err; } int recover_orphan_inodes(struct f2fs_sb_info *sbi) @@ -1139,6 +1145,8 @@ static void update_ckpt_flags(struct f2fs_sb_info *sbi, struct cp_control *cpc) if (cpc->reason & CP_TRIMMED) __set_ckpt_flags(ckpt, CP_TRIMMED_FLAG); + else + __clear_ckpt_flags(ckpt, CP_TRIMMED_FLAG); if (cpc->reason & CP_UMOUNT) __set_ckpt_flags(ckpt, CP_UMOUNT_FLAG); @@ -1165,6 +1173,39 @@ static void update_ckpt_flags(struct f2fs_sb_info *sbi, struct cp_control *cpc) spin_unlock_irqrestore(&sbi->cp_lock, flags); } +static void commit_checkpoint(struct f2fs_sb_info *sbi, + void *src, block_t blk_addr) +{ + struct writeback_control wbc = { + .for_reclaim = 0, + }; + + /* + * pagevec_lookup_tag and lock_page again will take + * some extra time. Therefore, update_meta_pages and + * sync_meta_pages are combined in this function. + */ + struct page *page = grab_meta_page(sbi, blk_addr); + int err; + + memcpy(page_address(page), src, PAGE_SIZE); + set_page_dirty(page); + + f2fs_wait_on_page_writeback(page, META, true); + f2fs_bug_on(sbi, PageWriteback(page)); + if (unlikely(!clear_page_dirty_for_io(page))) + f2fs_bug_on(sbi, 1); + + /* writeout cp pack 2 page */ + err = __f2fs_write_meta_page(page, &wbc, FS_CP_META_IO); + f2fs_bug_on(sbi, err); + + f2fs_put_page(page, 0); + + /* submit checkpoint (with barrier if NOBARRIER is not set) */ + f2fs_submit_merged_write(sbi, META_FLUSH); +} + static int do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc) { struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi); @@ -1267,16 +1308,6 @@ static int do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc) } } - /* need to wait for end_io results */ - wait_on_all_pages_writeback(sbi); - if (unlikely(f2fs_cp_error(sbi))) - return -EIO; - - /* flush all device cache */ - err = f2fs_flush_device_cache(sbi); - if (err) - return err; - /* write out checkpoint buffer at block 0 */ update_meta_page(sbi, ckpt, start_blk++); @@ -1304,26 +1335,26 @@ static int do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc) start_blk += NR_CURSEG_NODE_TYPE; } - /* writeout checkpoint block */ - update_meta_page(sbi, ckpt, start_blk); + /* update user_block_counts */ + sbi->last_valid_block_count = sbi->total_valid_block_count; + percpu_counter_set(&sbi->alloc_valid_block_count, 0); + + /* Here, we have one bio having CP pack except cp pack 2 page */ + sync_meta_pages(sbi, META, LONG_MAX, FS_CP_META_IO); - /* wait for previous submitted node/meta pages writeback */ + /* wait for previous submitted meta pages writeback */ wait_on_all_pages_writeback(sbi); if (unlikely(f2fs_cp_error(sbi))) return -EIO; - filemap_fdatawait_range(NODE_MAPPING(sbi), 0, LLONG_MAX); - filemap_fdatawait_range(META_MAPPING(sbi), 0, LLONG_MAX); - - /* update user_block_counts */ - sbi->last_valid_block_count = sbi->total_valid_block_count; - percpu_counter_set(&sbi->alloc_valid_block_count, 0); - - /* Here, we only have one bio having CP pack */ - sync_meta_pages(sbi, META_FLUSH, LONG_MAX, FS_CP_META_IO); + /* flush all device cache */ + err = f2fs_flush_device_cache(sbi); + if (err) + return err; - /* wait for previous submitted meta pages writeback */ + /* barrier and flush checkpoint cp pack 2 page if it can */ + commit_checkpoint(sbi, ckpt, start_blk); wait_on_all_pages_writeback(sbi); release_ino_entry(sbi, false); diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c index da7b00e6559b..b42e8d3539e8 100644 --- a/fs/f2fs/data.c +++ b/fs/f2fs/data.c @@ -176,15 +176,22 @@ static bool __same_bdev(struct f2fs_sb_info *sbi, */ static struct bio *__bio_alloc(struct f2fs_sb_info *sbi, block_t blk_addr, struct writeback_control *wbc, - int npages, bool is_read) + int npages, bool is_read, + enum page_type type, enum temp_type temp) { struct bio *bio; bio = f2fs_bio_alloc(sbi, npages, true); f2fs_target_device(sbi, blk_addr, bio); - bio->bi_end_io = is_read ? f2fs_read_end_io : f2fs_write_end_io; - bio->bi_private = is_read ? NULL : sbi; + if (is_read) { + bio->bi_end_io = f2fs_read_end_io; + bio->bi_private = NULL; + } else { + bio->bi_end_io = f2fs_write_end_io; + bio->bi_private = sbi; + bio->bi_write_hint = io_type_to_rw_hint(sbi, type, temp); + } if (wbc) wbc_init_bio(wbc, bio); @@ -197,13 +204,12 @@ static inline void __submit_bio(struct f2fs_sb_info *sbi, if (!is_read_io(bio_op(bio))) { unsigned int start; - if (f2fs_sb_mounted_blkzoned(sbi->sb) && - current->plug && (type == DATA || type == NODE)) - blk_finish_plug(current->plug); - if (type != DATA && type != NODE) goto submit_io; + if (f2fs_sb_has_blkzoned(sbi->sb) && current->plug) + blk_finish_plug(current->plug); + start = bio->bi_iter.bi_size >> F2FS_BLKSIZE_BITS; start %= F2FS_IO_SIZE(sbi); @@ -378,12 +384,13 @@ int f2fs_submit_page_bio(struct f2fs_io_info *fio) struct page *page = fio->encrypted_page ? fio->encrypted_page : fio->page; + verify_block_addr(fio, fio->new_blkaddr); trace_f2fs_submit_page_bio(page, fio); f2fs_trace_ios(fio, 0); /* Allocate a new bio */ bio = __bio_alloc(fio->sbi, fio->new_blkaddr, fio->io_wbc, - 1, is_read_io(fio->op)); + 1, is_read_io(fio->op), fio->type, fio->temp); if (bio_add_page(bio, page, PAGE_SIZE, 0) < PAGE_SIZE) { bio_put(bio); @@ -423,8 +430,8 @@ int f2fs_submit_page_write(struct f2fs_io_info *fio) } if (fio->old_blkaddr != NEW_ADDR) - verify_block_addr(sbi, fio->old_blkaddr); - verify_block_addr(sbi, fio->new_blkaddr); + verify_block_addr(fio, fio->old_blkaddr); + verify_block_addr(fio, fio->new_blkaddr); bio_page = fio->encrypted_page ? fio->encrypted_page : fio->page; @@ -446,7 +453,8 @@ int f2fs_submit_page_write(struct f2fs_io_info *fio) goto out_fail; } io->bio = __bio_alloc(sbi, fio->new_blkaddr, fio->io_wbc, - BIO_MAX_PAGES, false); + BIO_MAX_PAGES, false, + fio->type, fio->temp); io->fio = *fio; } @@ -833,13 +841,6 @@ static int __allocate_data_block(struct dnode_of_data *dn, int seg_type) return 0; } -static inline bool __force_buffered_io(struct inode *inode, int rw) -{ - return (f2fs_encrypted_file(inode) || - (rw == WRITE && test_opt(F2FS_I_SB(inode), LFS)) || - F2FS_I_SB(inode)->s_ndevs); -} - int f2fs_preallocate_blocks(struct kiocb *iocb, struct iov_iter *from) { struct inode *inode = file_inode(iocb->ki_filp); @@ -871,7 +872,7 @@ int f2fs_preallocate_blocks(struct kiocb *iocb, struct iov_iter *from) if (direct_io) { map.m_seg_type = rw_hint_to_seg_type(iocb->ki_hint); - flag = __force_buffered_io(inode, WRITE) ? + flag = f2fs_force_buffered_io(inode, WRITE) ? F2FS_GET_BLOCK_PRE_AIO : F2FS_GET_BLOCK_PRE_DIO; goto map_blocks; @@ -1115,6 +1116,31 @@ int f2fs_map_blocks(struct inode *inode, struct f2fs_map_blocks *map, return err; } +bool f2fs_overwrite_io(struct inode *inode, loff_t pos, size_t len) +{ + struct f2fs_map_blocks map; + block_t last_lblk; + int err; + + if (pos + len > i_size_read(inode)) + return false; + + map.m_lblk = F2FS_BYTES_TO_BLK(pos); + map.m_next_pgofs = NULL; + map.m_next_extent = NULL; + map.m_seg_type = NO_CHECK_TYPE; + last_lblk = F2FS_BLK_ALIGN(pos + len); + + while (map.m_lblk < last_lblk) { + map.m_len = last_lblk - map.m_lblk; + err = f2fs_map_blocks(inode, &map, 0, F2FS_GET_BLOCK_DEFAULT); + if (err || map.m_len == 0) + return false; + map.m_lblk += map.m_len; + } + return true; +} + static int __get_data_block(struct inode *inode, sector_t iblock, struct buffer_head *bh, int create, int flag, pgoff_t *next_pgofs, int seg_type) @@ -2304,16 +2330,19 @@ static ssize_t f2fs_direct_IO(struct kiocb *iocb, struct iov_iter *iter) { struct address_space *mapping = iocb->ki_filp->f_mapping; struct inode *inode = mapping->host; + struct f2fs_sb_info *sbi = F2FS_I_SB(inode); size_t count = iov_iter_count(iter); loff_t offset = iocb->ki_pos; int rw = iov_iter_rw(iter); int err; + enum rw_hint hint = iocb->ki_hint; + int whint_mode = F2FS_OPTION(sbi).whint_mode; err = check_direct_IO(inode, iter, offset); if (err) return err; - if (__force_buffered_io(inode, rw)) + if (f2fs_force_buffered_io(inode, rw)) return 0; trace_f2fs_direct_IO_enter(inode, offset, count, rw); @@ -2340,12 +2369,24 @@ static ssize_t f2fs_direct_IO(struct kiocb *iocb, struct iov_iter *iter) current->pid, path, current->comm); } + if (rw == WRITE && whint_mode == WHINT_MODE_OFF) + iocb->ki_hint = WRITE_LIFE_NOT_SET; + + if (!down_read_trylock(&F2FS_I(inode)->dio_rwsem[rw])) { + if (iocb->ki_flags & IOCB_NOWAIT) { + iocb->ki_hint = hint; + err = -EAGAIN; + goto out; + } + down_read(&F2FS_I(inode)->dio_rwsem[rw]); + } - down_read(&F2FS_I(inode)->dio_rwsem[rw]); err = blockdev_direct_IO(iocb, inode, iter, get_data_block_dio); up_read(&F2FS_I(inode)->dio_rwsem[rw]); if (rw == WRITE) { + if (whint_mode == WHINT_MODE_OFF) + iocb->ki_hint = hint; if (err > 0) { f2fs_update_iostat(F2FS_I_SB(inode), APP_DIRECT_IO, err); @@ -2354,7 +2395,7 @@ static ssize_t f2fs_direct_IO(struct kiocb *iocb, struct iov_iter *iter) f2fs_write_failed(mapping, offset + count); } } - +out: if (trace_android_fs_dataread_start_enabled() && (rw == READ)) trace_android_fs_dataread_end(inode, offset, count); diff --git a/fs/f2fs/dir.c b/fs/f2fs/dir.c index 797eb05cb538..fe661274ff10 100644 --- a/fs/f2fs/dir.c +++ b/fs/f2fs/dir.c @@ -361,6 +361,7 @@ struct page *init_inode_metadata(struct inode *inode, struct inode *dir, struct page *dpage) { struct page *page; + int dummy_encrypt = DUMMY_ENCRYPTION_ENABLED(F2FS_I_SB(dir)); int err; if (is_inode_flag_set(inode, FI_NEW_INODE)) { @@ -387,7 +388,8 @@ struct page *init_inode_metadata(struct inode *inode, struct inode *dir, if (err) goto put_error; - if (f2fs_encrypted_inode(dir) && f2fs_may_encrypt(inode)) { + if ((f2fs_encrypted_inode(dir) || dummy_encrypt) && + f2fs_may_encrypt(inode)) { err = fscrypt_inherit_context(dir, inode, page, false); if (err) goto put_error; @@ -396,8 +398,6 @@ struct page *init_inode_metadata(struct inode *inode, struct inode *dir, page = get_node_page(F2FS_I_SB(dir), inode->i_ino); if (IS_ERR(page)) return page; - - set_cold_node(inode, page); } if (new_name) { @@ -704,7 +704,8 @@ void f2fs_delete_entry(struct f2fs_dir_entry *dentry, struct page *page, f2fs_update_time(F2FS_I_SB(dir), REQ_TIME); - add_ino_entry(F2FS_I_SB(dir), dir->i_ino, TRANS_DIR_INO); + if (F2FS_OPTION(F2FS_I_SB(dir)).fsync_mode == FSYNC_MODE_STRICT) + add_ino_entry(F2FS_I_SB(dir), dir->i_ino, TRANS_DIR_INO); if (f2fs_has_inline_dentry(dir)) return f2fs_delete_inline_entry(dentry, page, dir, inode); diff --git a/fs/f2fs/extent_cache.c b/fs/f2fs/extent_cache.c index ff2352a0ed15..d5a861bf2b42 100644 --- a/fs/f2fs/extent_cache.c +++ b/fs/f2fs/extent_cache.c @@ -460,7 +460,7 @@ static struct extent_node *__insert_extent_tree(struct inode *inode, struct rb_node *insert_parent) { struct f2fs_sb_info *sbi = F2FS_I_SB(inode); - struct rb_node **p = &et->root.rb_node; + struct rb_node **p; struct rb_node *parent = NULL; struct extent_node *en = NULL; @@ -706,6 +706,9 @@ void f2fs_drop_extent_tree(struct inode *inode) struct f2fs_sb_info *sbi = F2FS_I_SB(inode); struct extent_tree *et = F2FS_I(inode)->extent_tree; + if (!f2fs_may_extent_tree(inode)) + return; + set_inode_flag(inode, FI_NO_EXTENT); write_lock(&et->lock); diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index f633a69c9731..1df7f10476d6 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -98,9 +98,10 @@ extern char *fault_name[FAULT_MAX]; #define F2FS_MOUNT_INLINE_XATTR_SIZE 0x00800000 #define F2FS_MOUNT_RESERVE_ROOT 0x01000000 -#define clear_opt(sbi, option) ((sbi)->mount_opt.opt &= ~F2FS_MOUNT_##option) -#define set_opt(sbi, option) ((sbi)->mount_opt.opt |= F2FS_MOUNT_##option) -#define test_opt(sbi, option) ((sbi)->mount_opt.opt & F2FS_MOUNT_##option) +#define F2FS_OPTION(sbi) ((sbi)->mount_opt) +#define clear_opt(sbi, option) (F2FS_OPTION(sbi).opt &= ~F2FS_MOUNT_##option) +#define set_opt(sbi, option) (F2FS_OPTION(sbi).opt |= F2FS_MOUNT_##option) +#define test_opt(sbi, option) (F2FS_OPTION(sbi).opt & F2FS_MOUNT_##option) #define ver_after(a, b) (typecheck(unsigned long long, a) && \ typecheck(unsigned long long, b) && \ @@ -113,7 +114,26 @@ typedef u32 block_t; /* typedef u32 nid_t; struct f2fs_mount_info { - unsigned int opt; + unsigned int opt; + int write_io_size_bits; /* Write IO size bits */ + block_t root_reserved_blocks; /* root reserved blocks */ + kuid_t s_resuid; /* reserved blocks for uid */ + kgid_t s_resgid; /* reserved blocks for gid */ + int active_logs; /* # of active logs */ + int inline_xattr_size; /* inline xattr size */ +#ifdef CONFIG_F2FS_FAULT_INJECTION + struct f2fs_fault_info fault_info; /* For fault injection */ +#endif +#ifdef CONFIG_QUOTA + /* Names of quota files with journalled quota */ + char *s_qf_names[MAXQUOTAS]; + int s_jquota_fmt; /* Format of quota to use */ +#endif + /* For which write hints are passed down to block layer */ + int whint_mode; + int alloc_mode; /* segment allocation policy */ + int fsync_mode; /* fsync policy */ + bool test_dummy_encryption; /* test dummy encryption */ }; #define F2FS_FEATURE_ENCRYPT 0x0001 @@ -125,6 +145,8 @@ struct f2fs_mount_info { #define F2FS_FEATURE_FLEXIBLE_INLINE_XATTR 0x0040 #define F2FS_FEATURE_QUOTA_INO 0x0080 #define F2FS_FEATURE_INODE_CRTIME 0x0100 +#define F2FS_FEATURE_LOST_FOUND 0x0200 +#define F2FS_FEATURE_VERITY 0x0400 /* reserved */ #define F2FS_HAS_FEATURE(sb, mask) \ ((F2FS_SB(sb)->raw_super->feature & cpu_to_le32(mask)) != 0) @@ -450,7 +472,7 @@ static inline void make_dentry_ptr_block(struct inode *inode, d->inode = inode; d->max = NR_DENTRY_IN_BLOCK; d->nr_bitmap = SIZE_OF_DENTRY_BITMAP; - d->bitmap = &t->dentry_bitmap; + d->bitmap = t->dentry_bitmap; d->dentry = t->dentry; d->filename = t->filename; } @@ -576,6 +598,8 @@ enum { #define FADVISE_ENCRYPT_BIT 0x04 #define FADVISE_ENC_NAME_BIT 0x08 #define FADVISE_KEEP_SIZE_BIT 0x10 +#define FADVISE_HOT_BIT 0x20 +#define FADVISE_VERITY_BIT 0x40 /* reserved */ #define file_is_cold(inode) is_file(inode, FADVISE_COLD_BIT) #define file_wrong_pino(inode) is_file(inode, FADVISE_LOST_PINO_BIT) @@ -590,6 +614,9 @@ enum { #define file_set_enc_name(inode) set_file(inode, FADVISE_ENC_NAME_BIT) #define file_keep_isize(inode) is_file(inode, FADVISE_KEEP_SIZE_BIT) #define file_set_keep_isize(inode) set_file(inode, FADVISE_KEEP_SIZE_BIT) +#define file_is_hot(inode) is_file(inode, FADVISE_HOT_BIT) +#define file_set_hot(inode) set_file(inode, FADVISE_HOT_BIT) +#define file_clear_hot(inode) clear_file(inode, FADVISE_HOT_BIT) #define DEF_DIR_LEVEL 0 @@ -637,6 +664,7 @@ struct f2fs_inode_info { kprojid_t i_projid; /* id for project quota */ int i_inline_xattr_size; /* inline xattr size */ struct timespec i_crtime; /* inode creation time */ + struct timespec i_disk_time[4]; /* inode disk times */ }; static inline void get_extent_info(struct extent_info *ext, @@ -743,7 +771,7 @@ struct f2fs_nm_info { unsigned int nid_cnt[MAX_NID_STATE]; /* the number of free node id */ spinlock_t nid_list_lock; /* protect nid lists ops */ struct mutex build_lock; /* lock for build free nids */ - unsigned char (*free_nid_bitmap)[NAT_ENTRY_BITMAP_SIZE]; + unsigned char **free_nid_bitmap; unsigned char *nat_block_bitmap; unsigned short *free_nid_count; /* free nid count of NAT block */ @@ -976,6 +1004,7 @@ struct f2fs_io_info { bool submitted; /* indicate IO submission */ int need_lock; /* indicate we need to lock cp_rwsem */ bool in_list; /* indicate fio is in io_list */ + bool is_meta; /* indicate borrow meta inode mapping or not */ enum iostat_type io_type; /* io type */ struct writeback_control *io_wbc; /* writeback control */ }; @@ -1037,10 +1066,34 @@ enum { MAX_TIME, }; +enum { + WHINT_MODE_OFF, /* not pass down write hints */ + WHINT_MODE_USER, /* try to pass down hints given by users */ + WHINT_MODE_FS, /* pass down hints with F2FS policy */ +}; + +enum { + ALLOC_MODE_DEFAULT, /* stay default */ + ALLOC_MODE_REUSE, /* reuse segments as much as possible */ +}; + +enum fsync_mode { + FSYNC_MODE_POSIX, /* fsync follows posix semantics */ + FSYNC_MODE_STRICT, /* fsync behaves in line with ext4 */ +}; + +#ifdef CONFIG_F2FS_FS_ENCRYPTION +#define DUMMY_ENCRYPTION_ENABLED(sbi) \ + (unlikely(F2FS_OPTION(sbi).test_dummy_encryption)) +#else +#define DUMMY_ENCRYPTION_ENABLED(sbi) (0) +#endif + struct f2fs_sb_info { struct super_block *sb; /* pointer to VFS super block */ struct proc_dir_entry *s_proc; /* proc entry */ struct f2fs_super_block *raw_super; /* raw super block pointer */ + struct rw_semaphore sb_lock; /* lock for raw super block */ int valid_super_block; /* valid super block no */ unsigned long s_flag; /* flags for sbi */ @@ -1060,7 +1113,6 @@ struct f2fs_sb_info { struct f2fs_bio_info *write_io[NR_PAGE_TYPE]; /* for write bios */ struct mutex wio_mutex[NR_PAGE_TYPE - 1][NR_TEMP_TYPE]; /* bio ordering for NODE/DATA */ - int write_io_size_bits; /* Write IO size bits */ mempool_t *write_io_dummy; /* Dummy pages */ /* for checkpoint */ @@ -1110,9 +1162,7 @@ struct f2fs_sb_info { unsigned int total_node_count; /* total node block count */ unsigned int total_valid_node_count; /* valid node block count */ loff_t max_file_blocks; /* max block index of file */ - int active_logs; /* # of active logs */ int dir_level; /* directory level */ - int inline_xattr_size; /* inline xattr size */ unsigned int trigger_ssr_threshold; /* threshold to trigger ssr */ int readdir_ra; /* readahead inode in readdir */ @@ -1122,9 +1172,6 @@ struct f2fs_sb_info { block_t last_valid_block_count; /* for recovery */ block_t reserved_blocks; /* configurable reserved blocks */ block_t current_reserved_blocks; /* current reserved blocks */ - block_t root_reserved_blocks; /* root reserved blocks */ - kuid_t s_resuid; /* reserved blocks for uid */ - kgid_t s_resgid; /* reserved blocks for gid */ unsigned int nquota_files; /* # of quota sysfile */ @@ -1209,17 +1256,6 @@ struct f2fs_sb_info { /* Precomputed FS UUID checksum for seeding other checksums */ __u32 s_chksum_seed; - - /* For fault injection */ -#ifdef CONFIG_F2FS_FAULT_INJECTION - struct f2fs_fault_info fault_info; -#endif - -#ifdef CONFIG_QUOTA - /* Names of quota files with journalled quota */ - char *s_qf_names[MAXQUOTAS]; - int s_jquota_fmt; /* Format of quota to use */ -#endif }; #ifdef CONFIG_F2FS_FAULT_INJECTION @@ -1229,7 +1265,7 @@ struct f2fs_sb_info { __func__, __builtin_return_address(0)) static inline bool time_to_inject(struct f2fs_sb_info *sbi, int type) { - struct f2fs_fault_info *ffi = &sbi->fault_info; + struct f2fs_fault_info *ffi = &F2FS_OPTION(sbi).fault_info; if (!ffi->inject_rate) return false; @@ -1586,12 +1622,12 @@ static inline bool __allow_reserved_blocks(struct f2fs_sb_info *sbi, return false; if (IS_NOQUOTA(inode)) return true; - if (capable(CAP_SYS_RESOURCE)) + if (uid_eq(F2FS_OPTION(sbi).s_resuid, current_fsuid())) return true; - if (uid_eq(sbi->s_resuid, current_fsuid())) + if (!gid_eq(F2FS_OPTION(sbi).s_resgid, GLOBAL_ROOT_GID) && + in_group_p(F2FS_OPTION(sbi).s_resgid)) return true; - if (!gid_eq(sbi->s_resgid, GLOBAL_ROOT_GID) && - in_group_p(sbi->s_resgid)) + if (capable(CAP_SYS_RESOURCE)) return true; return false; } @@ -1627,7 +1663,7 @@ static inline int inc_valid_block_count(struct f2fs_sb_info *sbi, sbi->current_reserved_blocks; if (!__allow_reserved_blocks(sbi, inode)) - avail_user_block_count -= sbi->root_reserved_blocks; + avail_user_block_count -= F2FS_OPTION(sbi).root_reserved_blocks; if (unlikely(sbi->total_valid_block_count > avail_user_block_count)) { diff = sbi->total_valid_block_count - avail_user_block_count; @@ -1762,6 +1798,12 @@ static inline void *__bitmap_ptr(struct f2fs_sb_info *sbi, int flag) struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi); int offset; + if (is_set_ckpt_flags(sbi, CP_LARGE_NAT_BITMAP_FLAG)) { + offset = (flag == SIT_BITMAP) ? + le32_to_cpu(ckpt->nat_ver_bitmap_bytesize) : 0; + return &ckpt->sit_nat_version_bitmap + offset; + } + if (__cp_payload(sbi) > 0) { if (flag == NAT_BITMAP) return &ckpt->sit_nat_version_bitmap; @@ -1828,7 +1870,7 @@ static inline int inc_valid_node_count(struct f2fs_sb_info *sbi, sbi->current_reserved_blocks + 1; if (!__allow_reserved_blocks(sbi, inode)) - valid_block_count += sbi->root_reserved_blocks; + valid_block_count += F2FS_OPTION(sbi).root_reserved_blocks; if (unlikely(valid_block_count > sbi->user_block_count)) { spin_unlock(&sbi->stat_lock); @@ -2430,7 +2472,17 @@ static inline bool f2fs_skip_inode_update(struct inode *inode, int dsync) } if (!is_inode_flag_set(inode, FI_AUTO_RECOVER) || file_keep_isize(inode) || - i_size_read(inode) & PAGE_MASK) + i_size_read(inode) & ~PAGE_MASK) + return false; + + if (!timespec_equal(F2FS_I(inode)->i_disk_time, &inode->i_atime)) + return false; + if (!timespec_equal(F2FS_I(inode)->i_disk_time + 1, &inode->i_ctime)) + return false; + if (!timespec_equal(F2FS_I(inode)->i_disk_time + 2, &inode->i_mtime)) + return false; + if (!timespec_equal(F2FS_I(inode)->i_disk_time + 3, + &F2FS_I(inode)->i_crtime)) return false; down_read(&F2FS_I(inode)->i_sem); @@ -2440,9 +2492,9 @@ static inline bool f2fs_skip_inode_update(struct inode *inode, int dsync) return ret; } -static inline int f2fs_readonly(struct super_block *sb) +static inline bool f2fs_readonly(struct super_block *sb) { - return sb->s_flags & MS_RDONLY; + return sb_rdonly(sb); } static inline bool f2fs_cp_error(struct f2fs_sb_info *sbi) @@ -2590,6 +2642,8 @@ void handle_failed_inode(struct inode *inode); /* * namei.c */ +int update_extension_list(struct f2fs_sb_info *sbi, const char *name, + bool hot, bool set); struct dentry *f2fs_get_parent(struct dentry *child); /* @@ -2762,6 +2816,8 @@ void destroy_segment_manager(struct f2fs_sb_info *sbi); int __init create_segment_manager_caches(void); void destroy_segment_manager_caches(void); int rw_hint_to_seg_type(enum rw_hint hint); +enum rw_hint io_type_to_rw_hint(struct f2fs_sb_info *sbi, enum page_type type, + enum temp_type temp); /* * checkpoint.c @@ -2844,6 +2900,7 @@ int f2fs_release_page(struct page *page, gfp_t wait); int f2fs_migrate_page(struct address_space *mapping, struct page *newpage, struct page *page, enum migrate_mode mode); #endif +bool f2fs_overwrite_io(struct inode *inode, loff_t pos, size_t len); /* * gc.c @@ -3166,45 +3223,21 @@ static inline bool f2fs_bio_encrypted(struct bio *bio) return bio->bi_private != NULL; } -static inline int f2fs_sb_has_crypto(struct super_block *sb) -{ - return F2FS_HAS_FEATURE(sb, F2FS_FEATURE_ENCRYPT); -} - -static inline int f2fs_sb_mounted_blkzoned(struct super_block *sb) -{ - return F2FS_HAS_FEATURE(sb, F2FS_FEATURE_BLKZONED); -} - -static inline int f2fs_sb_has_extra_attr(struct super_block *sb) -{ - return F2FS_HAS_FEATURE(sb, F2FS_FEATURE_EXTRA_ATTR); +#define F2FS_FEATURE_FUNCS(name, flagname) \ +static inline int f2fs_sb_has_##name(struct super_block *sb) \ +{ \ + return F2FS_HAS_FEATURE(sb, F2FS_FEATURE_##flagname); \ } -static inline int f2fs_sb_has_project_quota(struct super_block *sb) -{ - return F2FS_HAS_FEATURE(sb, F2FS_FEATURE_PRJQUOTA); -} - -static inline int f2fs_sb_has_inode_chksum(struct super_block *sb) -{ - return F2FS_HAS_FEATURE(sb, F2FS_FEATURE_INODE_CHKSUM); -} - -static inline int f2fs_sb_has_flexible_inline_xattr(struct super_block *sb) -{ - return F2FS_HAS_FEATURE(sb, F2FS_FEATURE_FLEXIBLE_INLINE_XATTR); -} - -static inline int f2fs_sb_has_quota_ino(struct super_block *sb) -{ - return F2FS_HAS_FEATURE(sb, F2FS_FEATURE_QUOTA_INO); -} - -static inline int f2fs_sb_has_inode_crtime(struct super_block *sb) -{ - return F2FS_HAS_FEATURE(sb, F2FS_FEATURE_INODE_CRTIME); -} +F2FS_FEATURE_FUNCS(encrypt, ENCRYPT); +F2FS_FEATURE_FUNCS(blkzoned, BLKZONED); +F2FS_FEATURE_FUNCS(extra_attr, EXTRA_ATTR); +F2FS_FEATURE_FUNCS(project_quota, PRJQUOTA); +F2FS_FEATURE_FUNCS(inode_chksum, INODE_CHKSUM); +F2FS_FEATURE_FUNCS(flexible_inline_xattr, FLEXIBLE_INLINE_XATTR); +F2FS_FEATURE_FUNCS(quota_ino, QUOTA_INO); +F2FS_FEATURE_FUNCS(inode_crtime, INODE_CRTIME); +F2FS_FEATURE_FUNCS(lost_found, LOST_FOUND); #ifdef CONFIG_BLK_DEV_ZONED static inline int get_blkz_type(struct f2fs_sb_info *sbi, @@ -3224,7 +3257,7 @@ static inline bool f2fs_discard_en(struct f2fs_sb_info *sbi) { struct request_queue *q = bdev_get_queue(sbi->sb->s_bdev); - return blk_queue_discard(q) || f2fs_sb_mounted_blkzoned(sbi->sb); + return blk_queue_discard(q) || f2fs_sb_has_blkzoned(sbi->sb); } static inline void set_opt_mode(struct f2fs_sb_info *sbi, unsigned int mt) @@ -3253,4 +3286,11 @@ static inline bool f2fs_may_encrypt(struct inode *inode) #endif } +static inline bool f2fs_force_buffered_io(struct inode *inode, int rw) +{ + return (f2fs_encrypted_file(inode) || + (rw == WRITE && test_opt(F2FS_I_SB(inode), LFS)) || + F2FS_I_SB(inode)->s_ndevs); +} + #endif diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c index 1d6a862bd25f..cc88981fbe28 100644 --- a/fs/f2fs/file.c +++ b/fs/f2fs/file.c @@ -163,9 +163,10 @@ static inline enum cp_reason_type need_do_checkpoint(struct inode *inode) cp_reason = CP_NODE_NEED_CP; else if (test_opt(sbi, FASTBOOT)) cp_reason = CP_FASTBOOT_MODE; - else if (sbi->active_logs == 2) + else if (F2FS_OPTION(sbi).active_logs == 2) cp_reason = CP_SPEC_LOG_NUM; - else if (need_dentry_mark(sbi, inode->i_ino) && + else if (F2FS_OPTION(sbi).fsync_mode == FSYNC_MODE_STRICT && + need_dentry_mark(sbi, inode->i_ino) && exist_written_data(sbi, F2FS_I(inode)->i_pino, TRANS_DIR_INO)) cp_reason = CP_RECOVER_DIR; @@ -478,6 +479,9 @@ static int f2fs_file_open(struct inode *inode, struct file *filp) if (err) return err; + + filp->f_mode |= FMODE_NOWAIT; + return dquot_file_open(inode, filp); } @@ -568,7 +572,6 @@ static int truncate_partial_data_page(struct inode *inode, u64 from, int truncate_blocks(struct inode *inode, u64 from, bool lock) { struct f2fs_sb_info *sbi = F2FS_I_SB(inode); - unsigned int blocksize = inode->i_sb->s_blocksize; struct dnode_of_data dn; pgoff_t free_from; int count = 0, err = 0; @@ -577,7 +580,7 @@ int truncate_blocks(struct inode *inode, u64 from, bool lock) trace_f2fs_truncate_blocks_enter(inode, from); - free_from = (pgoff_t)F2FS_BYTES_TO_BLK(from + blocksize - 1); + free_from = (pgoff_t)F2FS_BLK_ALIGN(from); if (free_from >= sbi->max_file_blocks) goto free_partial; @@ -1347,8 +1350,12 @@ static int f2fs_zero_range(struct inode *inode, loff_t offset, loff_t len, } out: - if (!(mode & FALLOC_FL_KEEP_SIZE) && i_size_read(inode) < new_size) - f2fs_i_size_write(inode, new_size); + if (new_size > i_size_read(inode)) { + if (mode & FALLOC_FL_KEEP_SIZE) + file_set_keep_isize(inode); + else + f2fs_i_size_write(inode, new_size); + } out_sem: up_write(&F2FS_I(inode)->i_mmap_sem); @@ -1710,6 +1717,8 @@ static int f2fs_ioc_commit_atomic_write(struct file *filp) inode_lock(inode); + down_write(&F2FS_I(inode)->dio_rwsem[WRITE]); + if (f2fs_is_volatile_file(inode)) goto err_out; @@ -1728,6 +1737,7 @@ static int f2fs_ioc_commit_atomic_write(struct file *filp) ret = f2fs_do_sync_file(filp, 0, LLONG_MAX, 1, false); } err_out: + up_write(&F2FS_I(inode)->dio_rwsem[WRITE]); inode_unlock(inode); mnt_drop_write_file(filp); return ret; @@ -1937,7 +1947,7 @@ static int f2fs_ioc_set_encryption_policy(struct file *filp, unsigned long arg) { struct inode *inode = file_inode(filp); - if (!f2fs_sb_has_crypto(inode->i_sb)) + if (!f2fs_sb_has_encrypt(inode->i_sb)) return -EOPNOTSUPP; f2fs_update_time(F2FS_I_SB(inode), REQ_TIME); @@ -1947,7 +1957,7 @@ static int f2fs_ioc_set_encryption_policy(struct file *filp, unsigned long arg) static int f2fs_ioc_get_encryption_policy(struct file *filp, unsigned long arg) { - if (!f2fs_sb_has_crypto(file_inode(filp)->i_sb)) + if (!f2fs_sb_has_encrypt(file_inode(filp)->i_sb)) return -EOPNOTSUPP; return fscrypt_ioctl_get_policy(filp, (void __user *)arg); } @@ -1958,16 +1968,18 @@ static int f2fs_ioc_get_encryption_pwsalt(struct file *filp, unsigned long arg) struct f2fs_sb_info *sbi = F2FS_I_SB(inode); int err; - if (!f2fs_sb_has_crypto(inode->i_sb)) + if (!f2fs_sb_has_encrypt(inode->i_sb)) return -EOPNOTSUPP; - if (uuid_is_nonzero(sbi->raw_super->encrypt_pw_salt)) - goto got_it; - err = mnt_want_write_file(filp); if (err) return err; + down_write(&sbi->sb_lock); + + if (uuid_is_nonzero(sbi->raw_super->encrypt_pw_salt)) + goto got_it; + /* update superblock with uuid */ generate_random_uuid(sbi->raw_super->encrypt_pw_salt); @@ -1975,15 +1987,16 @@ static int f2fs_ioc_get_encryption_pwsalt(struct file *filp, unsigned long arg) if (err) { /* undo new data */ memset(sbi->raw_super->encrypt_pw_salt, 0, 16); - mnt_drop_write_file(filp); - return err; + goto out_err; } - mnt_drop_write_file(filp); got_it: if (copy_to_user((__u8 __user *)arg, sbi->raw_super->encrypt_pw_salt, 16)) - return -EFAULT; - return 0; + err = -EFAULT; +out_err: + up_write(&sbi->sb_lock); + mnt_drop_write_file(filp); + return err; } static int f2fs_ioc_gc(struct file *filp, unsigned long arg) @@ -2044,8 +2057,10 @@ static int f2fs_ioc_gc_range(struct file *filp, unsigned long arg) return ret; end = range.start + range.len; - if (range.start < MAIN_BLKADDR(sbi) || end >= MAX_BLKADDR(sbi)) - return -EINVAL; + if (range.start < MAIN_BLKADDR(sbi) || end >= MAX_BLKADDR(sbi)) { + ret = -EINVAL; + goto out; + } do_more: if (!range.sync) { if (!mutex_trylock(&sbi->gc_mutex)) { @@ -2884,25 +2899,54 @@ static ssize_t f2fs_file_write_iter(struct kiocb *iocb, struct iov_iter *from) if (unlikely(f2fs_cp_error(F2FS_I_SB(inode)))) return -EIO; - inode_lock(inode); + if ((iocb->ki_flags & IOCB_NOWAIT) && !(iocb->ki_flags & IOCB_DIRECT)) + return -EINVAL; + + if (!inode_trylock(inode)) { + if (iocb->ki_flags & IOCB_NOWAIT) + return -EAGAIN; + inode_lock(inode); + } + ret = generic_write_checks(iocb, from); if (ret > 0) { + bool preallocated = false; + size_t target_size = 0; int err; if (iov_iter_fault_in_readable(from, iov_iter_count(from))) set_inode_flag(inode, FI_NO_PREALLOC); - err = f2fs_preallocate_blocks(iocb, from); - if (err) { - clear_inode_flag(inode, FI_NO_PREALLOC); - inode_unlock(inode); - return err; + if ((iocb->ki_flags & IOCB_NOWAIT) && + (iocb->ki_flags & IOCB_DIRECT)) { + if (!f2fs_overwrite_io(inode, iocb->ki_pos, + iov_iter_count(from)) || + f2fs_has_inline_data(inode) || + f2fs_force_buffered_io(inode, WRITE)) { + inode_unlock(inode); + return -EAGAIN; + } + + } else { + preallocated = true; + target_size = iocb->ki_pos + iov_iter_count(from); + + err = f2fs_preallocate_blocks(iocb, from); + if (err) { + clear_inode_flag(inode, FI_NO_PREALLOC); + inode_unlock(inode); + return err; + } } blk_start_plug(&plug); ret = __generic_file_write_iter(iocb, from); blk_finish_plug(&plug); clear_inode_flag(inode, FI_NO_PREALLOC); + /* if we couldn't write data, we should deallocate blocks. */ + if (preallocated && i_size_read(inode) < target_size) + f2fs_truncate(inode); + if (ret > 0) f2fs_update_iostat(F2FS_I_SB(inode), APP_WRITE_IO, ret); } diff --git a/fs/f2fs/gc.c b/fs/f2fs/gc.c index 3b26aa19430b..0ad8b3a7a74d 100644 --- a/fs/f2fs/gc.c +++ b/fs/f2fs/gc.c @@ -76,14 +76,15 @@ static int gc_thread_func(void *data) * invalidated soon after by user update or deletion. * So, I'd like to wait some time to collect dirty segments. */ - if (!mutex_trylock(&sbi->gc_mutex)) - goto next; - if (gc_th->gc_urgent) { wait_ms = gc_th->urgent_sleep_time; + mutex_lock(&sbi->gc_mutex); goto do_gc; } + if (!mutex_trylock(&sbi->gc_mutex)) + goto next; + if (!is_idle(sbi)) { increase_sleep_time(gc_th, &wait_ms); mutex_unlock(&sbi->gc_mutex); @@ -161,12 +162,17 @@ static int select_gc_type(struct f2fs_gc_kthread *gc_th, int gc_type) { int gc_mode = (gc_type == BG_GC) ? GC_CB : GC_GREEDY; - if (gc_th && gc_th->gc_idle) { + if (!gc_th) + return gc_mode; + + if (gc_th->gc_idle) { if (gc_th->gc_idle == 1) gc_mode = GC_CB; else if (gc_th->gc_idle == 2) gc_mode = GC_GREEDY; } + if (gc_th->gc_urgent) + gc_mode = GC_GREEDY; return gc_mode; } @@ -188,11 +194,14 @@ static void select_policy(struct f2fs_sb_info *sbi, int gc_type, } /* we need to check every dirty segments in the FG_GC case */ - if (gc_type != FG_GC && p->max_search > sbi->max_victim_search) + if (gc_type != FG_GC && + (sbi->gc_thread && !sbi->gc_thread->gc_urgent) && + p->max_search > sbi->max_victim_search) p->max_search = sbi->max_victim_search; - /* let's select beginning hot/small space first */ - if (type == CURSEG_HOT_DATA || IS_NODESEG(type)) + /* let's select beginning hot/small space first in no_heap mode*/ + if (test_opt(sbi, NOHEAP) && + (type == CURSEG_HOT_DATA || IS_NODESEG(type))) p->offset = 0; else p->offset = SIT_I(sbi)->last_victim[p->gc_mode]; diff --git a/fs/f2fs/inode.c b/fs/f2fs/inode.c index 10be247ca421..e0d9e8f27ed2 100644 --- a/fs/f2fs/inode.c +++ b/fs/f2fs/inode.c @@ -284,6 +284,10 @@ static int do_read_inode(struct inode *inode) fi->i_crtime.tv_nsec = le32_to_cpu(ri->i_crtime_nsec); } + F2FS_I(inode)->i_disk_time[0] = inode->i_atime; + F2FS_I(inode)->i_disk_time[1] = inode->i_ctime; + F2FS_I(inode)->i_disk_time[2] = inode->i_mtime; + F2FS_I(inode)->i_disk_time[3] = F2FS_I(inode)->i_crtime; f2fs_put_page(node_page, 1); stat_inc_inline_xattr(inode); @@ -439,12 +443,15 @@ void update_inode(struct inode *inode, struct page *node_page) } __set_inode_rdev(inode, ri); - set_cold_node(inode, node_page); /* deleted inode */ if (inode->i_nlink == 0) clear_inline_node(node_page); + F2FS_I(inode)->i_disk_time[0] = inode->i_atime; + F2FS_I(inode)->i_disk_time[1] = inode->i_ctime; + F2FS_I(inode)->i_disk_time[2] = inode->i_mtime; + F2FS_I(inode)->i_disk_time[3] = F2FS_I(inode)->i_crtime; } void update_inode_page(struct inode *inode) @@ -585,7 +592,7 @@ void f2fs_evict_inode(struct inode *inode) !exist_written_data(sbi, inode->i_ino, ORPHAN_INO)); } out_clear: - fscrypt_put_encryption_info(inode, NULL); + fscrypt_put_encryption_info(inode); clear_inode(inode); } diff --git a/fs/f2fs/namei.c b/fs/f2fs/namei.c index 1ad0349707d7..d5098efe577c 100644 --- a/fs/f2fs/namei.c +++ b/fs/f2fs/namei.c @@ -78,7 +78,8 @@ static struct inode *f2fs_new_inode(struct inode *dir, umode_t mode) set_inode_flag(inode, FI_NEW_INODE); /* If the directory encrypted, then we should encrypt the inode. */ - if (f2fs_encrypted_inode(dir) && f2fs_may_encrypt(inode)) + if ((f2fs_encrypted_inode(dir) || DUMMY_ENCRYPTION_ENABLED(sbi)) && + f2fs_may_encrypt(inode)) f2fs_set_encrypted_inode(inode); if (f2fs_sb_has_extra_attr(sbi->sb)) { @@ -97,7 +98,7 @@ static struct inode *f2fs_new_inode(struct inode *dir, umode_t mode) if (f2fs_sb_has_flexible_inline_xattr(sbi->sb)) { f2fs_bug_on(sbi, !f2fs_has_extra_attr(inode)); if (f2fs_has_inline_xattr(inode)) - xattr_size = sbi->inline_xattr_size; + xattr_size = F2FS_OPTION(sbi).inline_xattr_size; /* Otherwise, will be 0 */ } else if (f2fs_has_inline_xattr(inode) || f2fs_has_inline_dentry(inode)) { @@ -142,7 +143,7 @@ static struct inode *f2fs_new_inode(struct inode *dir, umode_t mode) return ERR_PTR(err); } -static int is_multimedia_file(const unsigned char *s, const char *sub) +static int is_extension_exist(const unsigned char *s, const char *sub) { size_t slen = strlen(s); size_t sublen = strlen(sub); @@ -168,19 +169,94 @@ static int is_multimedia_file(const unsigned char *s, const char *sub) /* * Set multimedia files as cold files for hot/cold data separation */ -static inline void set_cold_files(struct f2fs_sb_info *sbi, struct inode *inode, +static inline void set_file_temperature(struct f2fs_sb_info *sbi, struct inode *inode, const unsigned char *name) { - int i; - __u8 (*extlist)[8] = sbi->raw_super->extension_list; + __u8 (*extlist)[F2FS_EXTENSION_LEN] = sbi->raw_super->extension_list; + int i, cold_count, hot_count; + + down_read(&sbi->sb_lock); + + cold_count = le32_to_cpu(sbi->raw_super->extension_count); + hot_count = sbi->raw_super->hot_ext_count; - int count = le32_to_cpu(sbi->raw_super->extension_count); - for (i = 0; i < count; i++) { - if (is_multimedia_file(name, extlist[i])) { + for (i = 0; i < cold_count + hot_count; i++) { + if (!is_extension_exist(name, extlist[i])) + continue; + if (i < cold_count) file_set_cold(inode); - break; - } + else + file_set_hot(inode); + break; } + + up_read(&sbi->sb_lock); +} + +int update_extension_list(struct f2fs_sb_info *sbi, const char *name, + bool hot, bool set) +{ + __u8 (*extlist)[F2FS_EXTENSION_LEN] = sbi->raw_super->extension_list; + int cold_count = le32_to_cpu(sbi->raw_super->extension_count); + int hot_count = sbi->raw_super->hot_ext_count; + int total_count = cold_count + hot_count; + int start, count; + int i; + + if (set) { + if (total_count == F2FS_MAX_EXTENSION) + return -EINVAL; + } else { + if (!hot && !cold_count) + return -EINVAL; + if (hot && !hot_count) + return -EINVAL; + } + + if (hot) { + start = cold_count; + count = total_count; + } else { + start = 0; + count = cold_count; + } + + for (i = start; i < count; i++) { + if (strcmp(name, extlist[i])) + continue; + + if (set) + return -EINVAL; + + memcpy(extlist[i], extlist[i + 1], + F2FS_EXTENSION_LEN * (total_count - i - 1)); + memset(extlist[total_count - 1], 0, F2FS_EXTENSION_LEN); + if (hot) + sbi->raw_super->hot_ext_count = hot_count - 1; + else + sbi->raw_super->extension_count = + cpu_to_le32(cold_count - 1); + return 0; + } + + if (!set) + return -EINVAL; + + if (hot) { + strncpy(extlist[count], name, strlen(name)); + sbi->raw_super->hot_ext_count = hot_count + 1; + } else { + char buf[F2FS_MAX_EXTENSION][F2FS_EXTENSION_LEN]; + + memcpy(buf, &extlist[cold_count], + F2FS_EXTENSION_LEN * hot_count); + memset(extlist[cold_count], 0, F2FS_EXTENSION_LEN); + strncpy(extlist[cold_count], name, strlen(name)); + memcpy(&extlist[cold_count + 1], buf, + F2FS_EXTENSION_LEN * hot_count); + sbi->raw_super->extension_count = cpu_to_le32(cold_count + 1); + } + return 0; } static int f2fs_create(struct inode *dir, struct dentry *dentry, umode_t mode, @@ -203,7 +279,7 @@ static int f2fs_create(struct inode *dir, struct dentry *dentry, umode_t mode, return PTR_ERR(inode); if (!test_opt(sbi, DISABLE_EXT_IDENTIFY)) - set_cold_files(sbi, inode, dentry->d_name.name); + set_file_temperature(sbi, inode, dentry->d_name.name); inode->i_op = &f2fs_file_inode_operations; inode->i_fop = &f2fs_file_operations; @@ -481,27 +557,16 @@ static int f2fs_symlink(struct inode *dir, struct dentry *dentry, struct f2fs_sb_info *sbi = F2FS_I_SB(dir); struct inode *inode; size_t len = strlen(symname); - struct fscrypt_str disk_link = FSTR_INIT((char *)symname, len + 1); - struct fscrypt_symlink_data *sd = NULL; + struct fscrypt_str disk_link; int err; if (unlikely(f2fs_cp_error(sbi))) return -EIO; - if (f2fs_encrypted_inode(dir)) { - err = fscrypt_get_encryption_info(dir); - if (err) - return err; - - if (!fscrypt_has_encryption_key(dir)) - return -ENOKEY; - - disk_link.len = (fscrypt_fname_encrypted_size(dir, len) + - sizeof(struct fscrypt_symlink_data)); - } - - if (disk_link.len > dir->i_sb->s_blocksize) - return -ENAMETOOLONG; + err = fscrypt_prepare_symlink(dir, symname, len, dir->i_sb->s_blocksize, + &disk_link); + if (err) + return err; err = dquot_initialize(dir); if (err) @@ -511,7 +576,7 @@ static int f2fs_symlink(struct inode *dir, struct dentry *dentry, if (IS_ERR(inode)) return PTR_ERR(inode); - if (f2fs_encrypted_inode(inode)) + if (IS_ENCRYPTED(inode)) inode->i_op = &f2fs_encrypted_symlink_inode_operations; else inode->i_op = &f2fs_symlink_inode_operations; @@ -521,38 +586,13 @@ static int f2fs_symlink(struct inode *dir, struct dentry *dentry, f2fs_lock_op(sbi); err = f2fs_add_link(dentry, inode); if (err) - goto out; + goto out_handle_failed_inode; f2fs_unlock_op(sbi); alloc_nid_done(sbi, inode->i_ino); - if (f2fs_encrypted_inode(inode)) { - struct qstr istr = QSTR_INIT(symname, len); - struct fscrypt_str ostr; - - sd = f2fs_kzalloc(sbi, disk_link.len, GFP_NOFS); - if (!sd) { - err = -ENOMEM; - goto err_out; - } - - err = fscrypt_get_encryption_info(inode); - if (err) - goto err_out; - - if (!fscrypt_has_encryption_key(inode)) { - err = -ENOKEY; - goto err_out; - } - - ostr.name = sd->encrypted_path; - ostr.len = disk_link.len; - err = fscrypt_fname_usr_to_disk(inode, &istr, &ostr); - if (err) - goto err_out; - - sd->len = cpu_to_le16(ostr.len); - disk_link.name = (char *)sd; - } + err = fscrypt_encrypt_symlink(inode, symname, len, &disk_link); + if (err) + goto err_out; err = page_symlink(inode, disk_link.name, disk_link.len); @@ -579,12 +619,14 @@ static int f2fs_symlink(struct inode *dir, struct dentry *dentry, f2fs_unlink(dir, dentry); } - kfree(sd); - f2fs_balance_fs(sbi, true); - return err; -out: + goto out_free_encrypted_link; + +out_handle_failed_inode: handle_failed_inode(inode); +out_free_encrypted_link: + if (disk_link.name != (unsigned char *)symname) + kfree(disk_link.name); return err; } @@ -746,10 +788,12 @@ static int __f2fs_tmpfile(struct inode *dir, struct dentry *dentry, static int f2fs_tmpfile(struct inode *dir, struct dentry *dentry, umode_t mode) { - if (unlikely(f2fs_cp_error(F2FS_I_SB(dir)))) + struct f2fs_sb_info *sbi = F2FS_I_SB(dir); + + if (unlikely(f2fs_cp_error(sbi))) return -EIO; - if (f2fs_encrypted_inode(dir)) { + if (f2fs_encrypted_inode(dir) || DUMMY_ENCRYPTION_ENABLED(sbi)) { int err = fscrypt_get_encryption_info(dir); if (err) return err; @@ -929,7 +973,8 @@ static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry, f2fs_put_page(old_dir_page, 0); f2fs_i_links_write(old_dir, false); } - add_ino_entry(sbi, new_dir->i_ino, TRANS_DIR_INO); + if (F2FS_OPTION(sbi).fsync_mode == FSYNC_MODE_STRICT) + add_ino_entry(sbi, new_dir->i_ino, TRANS_DIR_INO); f2fs_unlock_op(sbi); @@ -1079,8 +1124,10 @@ static int f2fs_cross_rename(struct inode *old_dir, struct dentry *old_dentry, } f2fs_mark_inode_dirty_sync(new_dir, false); - add_ino_entry(sbi, old_dir->i_ino, TRANS_DIR_INO); - add_ino_entry(sbi, new_dir->i_ino, TRANS_DIR_INO); + if (F2FS_OPTION(sbi).fsync_mode == FSYNC_MODE_STRICT) { + add_ino_entry(sbi, old_dir->i_ino, TRANS_DIR_INO); + add_ino_entry(sbi, new_dir->i_ino, TRANS_DIR_INO); + } f2fs_unlock_op(sbi); @@ -1132,68 +1179,20 @@ static const char *f2fs_encrypted_get_link(struct dentry *dentry, struct inode *inode, struct delayed_call *done) { - struct page *cpage = NULL; - char *caddr, *paddr = NULL; - struct fscrypt_str cstr = FSTR_INIT(NULL, 0); - struct fscrypt_str pstr = FSTR_INIT(NULL, 0); - struct fscrypt_symlink_data *sd; - u32 max_size = inode->i_sb->s_blocksize; - int res; + struct page *page; + const char *target; if (!dentry) return ERR_PTR(-ECHILD); - res = fscrypt_get_encryption_info(inode); - if (res) - return ERR_PTR(res); - - cpage = read_mapping_page(inode->i_mapping, 0, NULL); - if (IS_ERR(cpage)) - return ERR_CAST(cpage); - caddr = page_address(cpage); - - /* Symlink is encrypted */ - sd = (struct fscrypt_symlink_data *)caddr; - cstr.name = sd->encrypted_path; - cstr.len = le16_to_cpu(sd->len); - - /* this is broken symlink case */ - if (unlikely(cstr.len == 0)) { - res = -ENOENT; - goto errout; - } - - if ((cstr.len + sizeof(struct fscrypt_symlink_data) - 1) > max_size) { - /* Symlink data on the disk is corrupted */ - res = -EIO; - goto errout; - } - res = fscrypt_fname_alloc_buffer(inode, cstr.len, &pstr); - if (res) - goto errout; - - res = fscrypt_fname_disk_to_usr(inode, 0, 0, &cstr, &pstr); - if (res) - goto errout; - - /* this is broken symlink case */ - if (unlikely(pstr.name[0] == 0)) { - res = -ENOENT; - goto errout; - } - - paddr = pstr.name; - - /* Null-terminate the name */ - paddr[pstr.len] = '\0'; + page = read_mapping_page(inode->i_mapping, 0, NULL); + if (IS_ERR(page)) + return ERR_CAST(page); - put_page(cpage); - set_delayed_call(done, kfree_link, paddr); - return paddr; -errout: - fscrypt_fname_free_buffer(&pstr); - put_page(cpage); - return ERR_PTR(res); + target = fscrypt_get_symlink(inode, page_address(page), + inode->i_sb->s_blocksize, done); + put_page(page); + return target; } const struct inode_operations f2fs_encrypted_symlink_inode_operations = { diff --git a/fs/f2fs/node.c b/fs/f2fs/node.c index 7cded843cf18..199170e2e221 100644 --- a/fs/f2fs/node.c +++ b/fs/f2fs/node.c @@ -193,8 +193,8 @@ static void __del_from_nat_cache(struct f2fs_nm_info *nm_i, struct nat_entry *e) __free_nat_entry(e); } -static void __set_nat_cache_dirty(struct f2fs_nm_info *nm_i, - struct nat_entry *ne) +static struct nat_entry_set *__grab_nat_entry_set(struct f2fs_nm_info *nm_i, + struct nat_entry *ne) { nid_t set = NAT_BLOCK_OFFSET(ne->ni.nid); struct nat_entry_set *head; @@ -209,15 +209,36 @@ static void __set_nat_cache_dirty(struct f2fs_nm_info *nm_i, head->entry_cnt = 0; f2fs_radix_tree_insert(&nm_i->nat_set_root, set, head); } + return head; +} + +static void __set_nat_cache_dirty(struct f2fs_nm_info *nm_i, + struct nat_entry *ne) +{ + struct nat_entry_set *head; + bool new_ne = nat_get_blkaddr(ne) == NEW_ADDR; + + if (!new_ne) + head = __grab_nat_entry_set(nm_i, ne); + + /* + * update entry_cnt in below condition: + * 1. update NEW_ADDR to valid block address; + * 2. update old block address to new one; + */ + if (!new_ne && (get_nat_flag(ne, IS_PREALLOC) || + !get_nat_flag(ne, IS_DIRTY))) + head->entry_cnt++; + + set_nat_flag(ne, IS_PREALLOC, new_ne); if (get_nat_flag(ne, IS_DIRTY)) goto refresh_list; nm_i->dirty_nat_cnt++; - head->entry_cnt++; set_nat_flag(ne, IS_DIRTY, true); refresh_list: - if (nat_get_blkaddr(ne) == NEW_ADDR) + if (new_ne) list_del_init(&ne->list); else list_move_tail(&ne->list, &head->entry_list); @@ -1076,7 +1097,7 @@ struct page *new_node_page(struct dnode_of_data *dn, unsigned int ofs) f2fs_wait_on_page_writeback(page, NODE, true); fill_node_footer(page, dn->nid, dn->inode->i_ino, ofs, true); - set_cold_node(dn->inode, page); + set_cold_node(page, S_ISDIR(dn->inode->i_mode)); if (!PageUptodate(page)) SetPageUptodate(page); if (set_page_dirty(page)) @@ -2310,6 +2331,7 @@ int recover_inode_page(struct f2fs_sb_info *sbi, struct page *page) if (!PageUptodate(ipage)) SetPageUptodate(ipage); fill_node_footer(ipage, ino, ino, 0, true); + set_cold_node(page, false); src = F2FS_INODE(page); dst = F2FS_INODE(ipage); @@ -2599,8 +2621,7 @@ static int __get_nat_bitmaps(struct f2fs_sb_info *sbi) if (!enabled_nat_bits(sbi, NULL)) return 0; - nm_i->nat_bits_blocks = F2FS_BYTES_TO_BLK((nat_bits_bytes << 1) + 8 + - F2FS_BLKSIZE - 1); + nm_i->nat_bits_blocks = F2FS_BLK_ALIGN((nat_bits_bytes << 1) + 8); nm_i->nat_bits = f2fs_kzalloc(sbi, nm_i->nat_bits_blocks << F2FS_BLKSIZE_BITS, GFP_KERNEL); if (!nm_i->nat_bits) @@ -2726,12 +2747,20 @@ static int init_node_manager(struct f2fs_sb_info *sbi) static int init_free_nid_cache(struct f2fs_sb_info *sbi) { struct f2fs_nm_info *nm_i = NM_I(sbi); + int i; - nm_i->free_nid_bitmap = f2fs_kvzalloc(sbi, nm_i->nat_blocks * - NAT_ENTRY_BITMAP_SIZE, GFP_KERNEL); + nm_i->free_nid_bitmap = f2fs_kzalloc(sbi, nm_i->nat_blocks * + sizeof(unsigned char *), GFP_KERNEL); if (!nm_i->free_nid_bitmap) return -ENOMEM; + for (i = 0; i < nm_i->nat_blocks; i++) { + nm_i->free_nid_bitmap[i] = f2fs_kvzalloc(sbi, + NAT_ENTRY_BITMAP_SIZE_ALIGNED, GFP_KERNEL); + if (!nm_i->free_nid_bitmap) + return -ENOMEM; + } + nm_i->nat_block_bitmap = f2fs_kvzalloc(sbi, nm_i->nat_blocks / 8, GFP_KERNEL); if (!nm_i->nat_block_bitmap) @@ -2822,7 +2851,13 @@ void destroy_node_manager(struct f2fs_sb_info *sbi) up_write(&nm_i->nat_tree_lock); kvfree(nm_i->nat_block_bitmap); - kvfree(nm_i->free_nid_bitmap); + if (nm_i->free_nid_bitmap) { + int i; + + for (i = 0; i < nm_i->nat_blocks; i++) + kvfree(nm_i->free_nid_bitmap[i]); + kfree(nm_i->free_nid_bitmap); + } kvfree(nm_i->free_nid_count); kfree(nm_i->nat_bitmap); diff --git a/fs/f2fs/node.h b/fs/f2fs/node.h index 081ef0d672bf..b95e49e4a928 100644 --- a/fs/f2fs/node.h +++ b/fs/f2fs/node.h @@ -44,6 +44,7 @@ enum { HAS_FSYNCED_INODE, /* is the inode fsynced before? */ HAS_LAST_FSYNC, /* has the latest node fsync mark? */ IS_DIRTY, /* this nat entry is dirty? */ + IS_PREALLOC, /* nat entry is preallocated */ }; /* @@ -422,12 +423,12 @@ static inline void clear_inline_node(struct page *page) ClearPageChecked(page); } -static inline void set_cold_node(struct inode *inode, struct page *page) +static inline void set_cold_node(struct page *page, bool is_dir) { struct f2fs_node *rn = F2FS_NODE(page); unsigned int flag = le32_to_cpu(rn->footer.flag); - if (S_ISDIR(inode->i_mode)) + if (is_dir) flag &= ~(0x1 << COLD_BIT_SHIFT); else flag |= (0x1 << COLD_BIT_SHIFT); diff --git a/fs/f2fs/recovery.c b/fs/f2fs/recovery.c index 210de28c9cd2..4ddc2262baf1 100644 --- a/fs/f2fs/recovery.c +++ b/fs/f2fs/recovery.c @@ -242,6 +242,9 @@ static int find_fsync_dnodes(struct f2fs_sb_info *sbi, struct list_head *head, struct curseg_info *curseg; struct page *page = NULL; block_t blkaddr; + unsigned int loop_cnt = 0; + unsigned int free_blocks = sbi->user_block_count - + valid_user_blocks(sbi); int err = 0; /* get node pages in the current segment */ @@ -294,6 +297,17 @@ static int find_fsync_dnodes(struct f2fs_sb_info *sbi, struct list_head *head, if (IS_INODE(page) && is_dent_dnode(page)) entry->last_dentry = blkaddr; next: + /* sanity check in order to detect looped node chain */ + if (++loop_cnt >= free_blocks || + blkaddr == next_blkaddr_of_node(page)) { + f2fs_msg(sbi->sb, KERN_NOTICE, + "%s: detect looped node chain, " + "blkaddr:%u, next:%u", + __func__, blkaddr, next_blkaddr_of_node(page)); + err = -EINVAL; + break; + } + /* check next segment */ blkaddr = next_blkaddr_of_node(page); f2fs_put_page(page, 1); diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c index b16a8e6625aa..5854cc4e1d67 100644 --- a/fs/f2fs/segment.c +++ b/fs/f2fs/segment.c @@ -1411,12 +1411,11 @@ static int issue_discard_thread(void *data) if (kthread_should_stop()) return 0; - if (dcc->discard_wake) { + if (dcc->discard_wake) dcc->discard_wake = 0; - if (sbi->gc_thread && sbi->gc_thread->gc_urgent) - init_discard_policy(&dpolicy, - DPOLICY_FORCE, 1); - } + + if (sbi->gc_thread && sbi->gc_thread->gc_urgent) + init_discard_policy(&dpolicy, DPOLICY_FORCE, 1); sb_start_intwrite(sbi->sb); @@ -1485,7 +1484,7 @@ static int __issue_discard_async(struct f2fs_sb_info *sbi, struct block_device *bdev, block_t blkstart, block_t blklen) { #ifdef CONFIG_BLK_DEV_ZONED - if (f2fs_sb_mounted_blkzoned(sbi->sb) && + if (f2fs_sb_has_blkzoned(sbi->sb) && bdev_zoned_model(bdev) != BLK_ZONED_NONE) return __f2fs_issue_discard_zone(sbi, bdev, blkstart, blklen); #endif @@ -1683,7 +1682,7 @@ void clear_prefree_segments(struct f2fs_sb_info *sbi, struct cp_control *cpc) sbi->blocks_per_seg, cur_pos); len = next_pos - cur_pos; - if (f2fs_sb_mounted_blkzoned(sbi->sb) || + if (f2fs_sb_has_blkzoned(sbi->sb) || (force && len < cpc->trim_minlen)) goto skip; @@ -1727,7 +1726,7 @@ void init_discard_policy(struct discard_policy *dpolicy, } else if (discard_type == DPOLICY_FORCE) { dpolicy->min_interval = DEF_MIN_DISCARD_ISSUE_TIME; dpolicy->max_interval = DEF_MAX_DISCARD_ISSUE_TIME; - dpolicy->io_aware = true; + dpolicy->io_aware = false; } else if (discard_type == DPOLICY_FSTRIM) { dpolicy->io_aware = false; } else if (discard_type == DPOLICY_UMOUNT) { @@ -1863,7 +1862,7 @@ static void update_sit_entry(struct f2fs_sb_info *sbi, block_t blkaddr, int del) sbi->discard_blks--; /* don't overwrite by SSR to keep node chain */ - if (se->type == CURSEG_WARM_NODE) { + if (IS_NODESEG(se->type)) { if (!f2fs_test_and_set_bit(offset, se->ckpt_valid_map)) se->ckpt_valid_blocks++; } @@ -2164,11 +2163,17 @@ static unsigned int __get_next_segno(struct f2fs_sb_info *sbi, int type) if (sbi->segs_per_sec != 1) return CURSEG_I(sbi, type)->segno; - if (type == CURSEG_HOT_DATA || IS_NODESEG(type)) + if (test_opt(sbi, NOHEAP) && + (type == CURSEG_HOT_DATA || IS_NODESEG(type))) return 0; if (SIT_I(sbi)->last_victim[ALLOC_NEXT]) return SIT_I(sbi)->last_victim[ALLOC_NEXT]; + + /* find segments from 0 to reuse freed segments */ + if (F2FS_OPTION(sbi).alloc_mode == ALLOC_MODE_REUSE) + return 0; + return CURSEG_I(sbi, type)->segno; } @@ -2455,6 +2460,101 @@ int rw_hint_to_seg_type(enum rw_hint hint) } } +/* This returns write hints for each segment type. This hints will be + * passed down to block layer. There are mapping tables which depend on + * the mount option 'whint_mode'. + * + * 1) whint_mode=off. F2FS only passes down WRITE_LIFE_NOT_SET. + * + * 2) whint_mode=user-based. F2FS tries to pass down hints given by users. + * + * User F2FS Block + * ---- ---- ----- + * META WRITE_LIFE_NOT_SET + * HOT_NODE " + * WARM_NODE " + * COLD_NODE " + * ioctl(COLD) COLD_DATA WRITE_LIFE_EXTREME + * extension list " " + * + * -- buffered io + * WRITE_LIFE_EXTREME COLD_DATA WRITE_LIFE_EXTREME + * WRITE_LIFE_SHORT HOT_DATA WRITE_LIFE_SHORT + * WRITE_LIFE_NOT_SET WARM_DATA WRITE_LIFE_NOT_SET + * WRITE_LIFE_NONE " " + * WRITE_LIFE_MEDIUM " " + * WRITE_LIFE_LONG " " + * + * -- direct io + * WRITE_LIFE_EXTREME COLD_DATA WRITE_LIFE_EXTREME + * WRITE_LIFE_SHORT HOT_DATA WRITE_LIFE_SHORT + * WRITE_LIFE_NOT_SET WARM_DATA WRITE_LIFE_NOT_SET + * WRITE_LIFE_NONE " WRITE_LIFE_NONE + * WRITE_LIFE_MEDIUM " WRITE_LIFE_MEDIUM + * WRITE_LIFE_LONG " WRITE_LIFE_LONG + * + * 3) whint_mode=fs-based. F2FS passes down hints with its policy. + * + * User F2FS Block + * ---- ---- ----- + * META WRITE_LIFE_MEDIUM; + * HOT_NODE WRITE_LIFE_NOT_SET + * WARM_NODE " + * COLD_NODE WRITE_LIFE_NONE + * ioctl(COLD) COLD_DATA WRITE_LIFE_EXTREME + * extension list " " + * + * -- buffered io + * WRITE_LIFE_EXTREME COLD_DATA WRITE_LIFE_EXTREME + * WRITE_LIFE_SHORT HOT_DATA WRITE_LIFE_SHORT + * WRITE_LIFE_NOT_SET WARM_DATA WRITE_LIFE_LONG + * WRITE_LIFE_NONE " " + * WRITE_LIFE_MEDIUM " " + * WRITE_LIFE_LONG " " + * + * -- direct io + * WRITE_LIFE_EXTREME COLD_DATA WRITE_LIFE_EXTREME + * WRITE_LIFE_SHORT HOT_DATA WRITE_LIFE_SHORT + * WRITE_LIFE_NOT_SET WARM_DATA WRITE_LIFE_NOT_SET + * WRITE_LIFE_NONE " WRITE_LIFE_NONE + * WRITE_LIFE_MEDIUM " WRITE_LIFE_MEDIUM + * WRITE_LIFE_LONG " WRITE_LIFE_LONG + */ + +enum rw_hint io_type_to_rw_hint(struct f2fs_sb_info *sbi, + enum page_type type, enum temp_type temp) +{ + if (F2FS_OPTION(sbi).whint_mode == WHINT_MODE_USER) { + if (type == DATA) { + if (temp == WARM) + return WRITE_LIFE_NOT_SET; + else if (temp == HOT) + return WRITE_LIFE_SHORT; + else if (temp == COLD) + return WRITE_LIFE_EXTREME; + } else { + return WRITE_LIFE_NOT_SET; + } + } else if (F2FS_OPTION(sbi).whint_mode == WHINT_MODE_FS) { + if (type == DATA) { + if (temp == WARM) + return WRITE_LIFE_LONG; + else if (temp == HOT) + return WRITE_LIFE_SHORT; + else if (temp == COLD) + return WRITE_LIFE_EXTREME; + } else if (type == NODE) { + if (temp == WARM || temp == HOT) + return WRITE_LIFE_NOT_SET; + else if (temp == COLD) + return WRITE_LIFE_NONE; + } else if (type == META) { + return WRITE_LIFE_MEDIUM; + } + } + return WRITE_LIFE_NOT_SET; +} + static int __get_segment_type_2(struct f2fs_io_info *fio) { if (fio->type == DATA) @@ -2487,7 +2587,8 @@ static int __get_segment_type_6(struct f2fs_io_info *fio) if (is_cold_data(fio->page) || file_is_cold(inode)) return CURSEG_COLD_DATA; - if (is_inode_flag_set(inode, FI_HOT_DATA)) + if (file_is_hot(inode) || + is_inode_flag_set(inode, FI_HOT_DATA)) return CURSEG_HOT_DATA; return rw_hint_to_seg_type(inode->i_write_hint); } else { @@ -2502,7 +2603,7 @@ static int __get_segment_type(struct f2fs_io_info *fio) { int type = 0; - switch (fio->sbi->active_logs) { + switch (F2FS_OPTION(fio->sbi).active_logs) { case 2: type = __get_segment_type_2(fio); break; @@ -2642,6 +2743,7 @@ void write_meta_page(struct f2fs_sb_info *sbi, struct page *page, struct f2fs_io_info fio = { .sbi = sbi, .type = META, + .temp = HOT, .op = REQ_OP_WRITE, .op_flags = REQ_SYNC | REQ_META | REQ_PRIO, .old_blkaddr = page->index, @@ -2688,8 +2790,15 @@ void write_data_page(struct dnode_of_data *dn, struct f2fs_io_info *fio) int rewrite_data_page(struct f2fs_io_info *fio) { int err; + struct f2fs_sb_info *sbi = fio->sbi; fio->new_blkaddr = fio->old_blkaddr; + /* i/o temperature is needed for passing down write hints */ + __get_segment_type(fio); + + f2fs_bug_on(sbi, !IS_DATASEG(get_seg_entry(sbi, + GET_SEGNO(sbi, fio->new_blkaddr))->type)); + stat_inc_inplace_blocks(fio->sbi); err = f2fs_submit_page_bio(fio); diff --git a/fs/f2fs/segment.h b/fs/f2fs/segment.h index f11c4bc82c78..3325d0769723 100644 --- a/fs/f2fs/segment.h +++ b/fs/f2fs/segment.h @@ -53,13 +53,19 @@ ((secno) == CURSEG_I(sbi, CURSEG_COLD_NODE)->segno / \ (sbi)->segs_per_sec)) \ -#define MAIN_BLKADDR(sbi) (SM_I(sbi)->main_blkaddr) -#define SEG0_BLKADDR(sbi) (SM_I(sbi)->seg0_blkaddr) +#define MAIN_BLKADDR(sbi) \ + (SM_I(sbi) ? SM_I(sbi)->main_blkaddr : \ + le32_to_cpu(F2FS_RAW_SUPER(sbi)->main_blkaddr)) +#define SEG0_BLKADDR(sbi) \ + (SM_I(sbi) ? SM_I(sbi)->seg0_blkaddr : \ + le32_to_cpu(F2FS_RAW_SUPER(sbi)->segment0_blkaddr)) #define MAIN_SEGS(sbi) (SM_I(sbi)->main_segments) #define MAIN_SECS(sbi) ((sbi)->total_sections) -#define TOTAL_SEGS(sbi) (SM_I(sbi)->segment_count) +#define TOTAL_SEGS(sbi) \ + (SM_I(sbi) ? SM_I(sbi)->segment_count : \ + le32_to_cpu(F2FS_RAW_SUPER(sbi)->segment_count)) #define TOTAL_BLKS(sbi) (TOTAL_SEGS(sbi) << (sbi)->log_blocks_per_seg) #define MAX_BLKADDR(sbi) (SEG0_BLKADDR(sbi) + TOTAL_BLKS(sbi)) @@ -596,6 +602,8 @@ static inline int utilization(struct f2fs_sb_info *sbi) #define DEF_MIN_FSYNC_BLOCKS 8 #define DEF_MIN_HOT_BLOCKS 16 +#define SMALL_VOLUME_SEGMENTS (16 * 512) /* 16GB */ + enum { F2FS_IPU_FORCE, F2FS_IPU_SSR, @@ -630,10 +638,17 @@ static inline void check_seg_range(struct f2fs_sb_info *sbi, unsigned int segno) f2fs_bug_on(sbi, segno > TOTAL_SEGS(sbi) - 1); } -static inline void verify_block_addr(struct f2fs_sb_info *sbi, block_t blk_addr) +static inline void verify_block_addr(struct f2fs_io_info *fio, block_t blk_addr) { - BUG_ON(blk_addr < SEG0_BLKADDR(sbi) - || blk_addr >= MAX_BLKADDR(sbi)); + struct f2fs_sb_info *sbi = fio->sbi; + + if (PAGE_TYPE_OF_BIO(fio->type) == META && + (!is_read_io(fio->op) || fio->is_meta)) + BUG_ON(blk_addr < SEG0_BLKADDR(sbi) || + blk_addr >= MAIN_BLKADDR(sbi)); + else + BUG_ON(blk_addr < MAIN_BLKADDR(sbi) || + blk_addr >= MAX_BLKADDR(sbi)); } /* diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c index 0f8945bc4b4b..2717c9c5fdf4 100644 --- a/fs/f2fs/super.c +++ b/fs/f2fs/super.c @@ -60,7 +60,7 @@ char *fault_name[FAULT_MAX] = { static void f2fs_build_fault_attr(struct f2fs_sb_info *sbi, unsigned int rate) { - struct f2fs_fault_info *ffi = &sbi->fault_info; + struct f2fs_fault_info *ffi = &F2FS_OPTION(sbi).fault_info; if (rate) { atomic_set(&ffi->inject_ops, 0); @@ -129,6 +129,10 @@ enum { Opt_jqfmt_vfsold, Opt_jqfmt_vfsv0, Opt_jqfmt_vfsv1, + Opt_whint, + Opt_alloc, + Opt_fsync, + Opt_test_dummy_encryption, Opt_err, }; @@ -182,6 +186,10 @@ static match_table_t f2fs_tokens = { {Opt_jqfmt_vfsold, "jqfmt=vfsold"}, {Opt_jqfmt_vfsv0, "jqfmt=vfsv0"}, {Opt_jqfmt_vfsv1, "jqfmt=vfsv1"}, + {Opt_whint, "whint_mode=%s"}, + {Opt_alloc, "alloc_mode=%s"}, + {Opt_fsync, "fsync_mode=%s"}, + {Opt_test_dummy_encryption, "test_dummy_encryption"}, {Opt_err, NULL}, }; @@ -202,21 +210,24 @@ static inline void limit_reserve_root(struct f2fs_sb_info *sbi) block_t limit = (sbi->user_block_count << 1) / 1000; /* limit is 0.2% */ - if (test_opt(sbi, RESERVE_ROOT) && sbi->root_reserved_blocks > limit) { - sbi->root_reserved_blocks = limit; + if (test_opt(sbi, RESERVE_ROOT) && + F2FS_OPTION(sbi).root_reserved_blocks > limit) { + F2FS_OPTION(sbi).root_reserved_blocks = limit; f2fs_msg(sbi->sb, KERN_INFO, "Reduce reserved blocks for root = %u", - sbi->root_reserved_blocks); + F2FS_OPTION(sbi).root_reserved_blocks); } if (!test_opt(sbi, RESERVE_ROOT) && - (!uid_eq(sbi->s_resuid, + (!uid_eq(F2FS_OPTION(sbi).s_resuid, make_kuid(&init_user_ns, F2FS_DEF_RESUID)) || - !gid_eq(sbi->s_resgid, + !gid_eq(F2FS_OPTION(sbi).s_resgid, make_kgid(&init_user_ns, F2FS_DEF_RESGID)))) f2fs_msg(sbi->sb, KERN_INFO, "Ignore s_resuid=%u, s_resgid=%u w/o reserve_root", - from_kuid_munged(&init_user_ns, sbi->s_resuid), - from_kgid_munged(&init_user_ns, sbi->s_resgid)); + from_kuid_munged(&init_user_ns, + F2FS_OPTION(sbi).s_resuid), + from_kgid_munged(&init_user_ns, + F2FS_OPTION(sbi).s_resgid)); } static void init_once(void *foo) @@ -236,7 +247,7 @@ static int f2fs_set_qf_name(struct super_block *sb, int qtype, char *qname; int ret = -EINVAL; - if (sb_any_quota_loaded(sb) && !sbi->s_qf_names[qtype]) { + if (sb_any_quota_loaded(sb) && !F2FS_OPTION(sbi).s_qf_names[qtype]) { f2fs_msg(sb, KERN_ERR, "Cannot change journaled " "quota options when quota turned on"); @@ -254,8 +265,8 @@ static int f2fs_set_qf_name(struct super_block *sb, int qtype, "Not enough memory for storing quotafile name"); return -EINVAL; } - if (sbi->s_qf_names[qtype]) { - if (strcmp(sbi->s_qf_names[qtype], qname) == 0) + if (F2FS_OPTION(sbi).s_qf_names[qtype]) { + if (strcmp(F2FS_OPTION(sbi).s_qf_names[qtype], qname) == 0) ret = 0; else f2fs_msg(sb, KERN_ERR, @@ -268,7 +279,7 @@ static int f2fs_set_qf_name(struct super_block *sb, int qtype, "quotafile must be on filesystem root"); goto errout; } - sbi->s_qf_names[qtype] = qname; + F2FS_OPTION(sbi).s_qf_names[qtype] = qname; set_opt(sbi, QUOTA); return 0; errout: @@ -280,13 +291,13 @@ static int f2fs_clear_qf_name(struct super_block *sb, int qtype) { struct f2fs_sb_info *sbi = F2FS_SB(sb); - if (sb_any_quota_loaded(sb) && sbi->s_qf_names[qtype]) { + if (sb_any_quota_loaded(sb) && F2FS_OPTION(sbi).s_qf_names[qtype]) { f2fs_msg(sb, KERN_ERR, "Cannot change journaled quota options" " when quota turned on"); return -EINVAL; } - kfree(sbi->s_qf_names[qtype]); - sbi->s_qf_names[qtype] = NULL; + kfree(F2FS_OPTION(sbi).s_qf_names[qtype]); + F2FS_OPTION(sbi).s_qf_names[qtype] = NULL; return 0; } @@ -302,15 +313,19 @@ static int f2fs_check_quota_options(struct f2fs_sb_info *sbi) "Cannot enable project quota enforcement."); return -1; } - if (sbi->s_qf_names[USRQUOTA] || sbi->s_qf_names[GRPQUOTA] || - sbi->s_qf_names[PRJQUOTA]) { - if (test_opt(sbi, USRQUOTA) && sbi->s_qf_names[USRQUOTA]) + if (F2FS_OPTION(sbi).s_qf_names[USRQUOTA] || + F2FS_OPTION(sbi).s_qf_names[GRPQUOTA] || + F2FS_OPTION(sbi).s_qf_names[PRJQUOTA]) { + if (test_opt(sbi, USRQUOTA) && + F2FS_OPTION(sbi).s_qf_names[USRQUOTA]) clear_opt(sbi, USRQUOTA); - if (test_opt(sbi, GRPQUOTA) && sbi->s_qf_names[GRPQUOTA]) + if (test_opt(sbi, GRPQUOTA) && + F2FS_OPTION(sbi).s_qf_names[GRPQUOTA]) clear_opt(sbi, GRPQUOTA); - if (test_opt(sbi, PRJQUOTA) && sbi->s_qf_names[PRJQUOTA]) + if (test_opt(sbi, PRJQUOTA) && + F2FS_OPTION(sbi).s_qf_names[PRJQUOTA]) clear_opt(sbi, PRJQUOTA); if (test_opt(sbi, GRPQUOTA) || test_opt(sbi, USRQUOTA) || @@ -320,19 +335,19 @@ static int f2fs_check_quota_options(struct f2fs_sb_info *sbi) return -1; } - if (!sbi->s_jquota_fmt) { + if (!F2FS_OPTION(sbi).s_jquota_fmt) { f2fs_msg(sbi->sb, KERN_ERR, "journaled quota format " "not specified"); return -1; } } - if (f2fs_sb_has_quota_ino(sbi->sb) && sbi->s_jquota_fmt) { + if (f2fs_sb_has_quota_ino(sbi->sb) && F2FS_OPTION(sbi).s_jquota_fmt) { f2fs_msg(sbi->sb, KERN_INFO, "QUOTA feature is enabled, so ignore jquota_fmt"); - sbi->s_jquota_fmt = 0; + F2FS_OPTION(sbi).s_jquota_fmt = 0; } - if (f2fs_sb_has_quota_ino(sbi->sb) && sb_rdonly(sbi->sb)) { + if (f2fs_sb_has_quota_ino(sbi->sb) && f2fs_readonly(sbi->sb)) { f2fs_msg(sbi->sb, KERN_INFO, "Filesystem with quota feature cannot be mounted RDWR " "without CONFIG_QUOTA"); @@ -403,14 +418,14 @@ static int parse_options(struct super_block *sb, char *options) q = bdev_get_queue(sb->s_bdev); if (blk_queue_discard(q)) { set_opt(sbi, DISCARD); - } else if (!f2fs_sb_mounted_blkzoned(sb)) { + } else if (!f2fs_sb_has_blkzoned(sb)) { f2fs_msg(sb, KERN_WARNING, "mounting with \"discard\" option, but " "the device does not support discard"); } break; case Opt_nodiscard: - if (f2fs_sb_mounted_blkzoned(sb)) { + if (f2fs_sb_has_blkzoned(sb)) { f2fs_msg(sb, KERN_WARNING, "discard is required for zoned block devices"); return -EINVAL; @@ -440,7 +455,7 @@ static int parse_options(struct super_block *sb, char *options) if (args->from && match_int(args, &arg)) return -EINVAL; set_opt(sbi, INLINE_XATTR_SIZE); - sbi->inline_xattr_size = arg; + F2FS_OPTION(sbi).inline_xattr_size = arg; break; #else case Opt_user_xattr: @@ -480,7 +495,7 @@ static int parse_options(struct super_block *sb, char *options) return -EINVAL; if (arg != 2 && arg != 4 && arg != NR_CURSEG_TYPE) return -EINVAL; - sbi->active_logs = arg; + F2FS_OPTION(sbi).active_logs = arg; break; case Opt_disable_ext_identify: set_opt(sbi, DISABLE_EXT_IDENTIFY); @@ -524,9 +539,9 @@ static int parse_options(struct super_block *sb, char *options) if (test_opt(sbi, RESERVE_ROOT)) { f2fs_msg(sb, KERN_INFO, "Preserve previous reserve_root=%u", - sbi->root_reserved_blocks); + F2FS_OPTION(sbi).root_reserved_blocks); } else { - sbi->root_reserved_blocks = arg; + F2FS_OPTION(sbi).root_reserved_blocks = arg; set_opt(sbi, RESERVE_ROOT); } break; @@ -539,7 +554,7 @@ static int parse_options(struct super_block *sb, char *options) "Invalid uid value %d", arg); return -EINVAL; } - sbi->s_resuid = uid; + F2FS_OPTION(sbi).s_resuid = uid; break; case Opt_resgid: if (args->from && match_int(args, &arg)) @@ -550,7 +565,7 @@ static int parse_options(struct super_block *sb, char *options) "Invalid gid value %d", arg); return -EINVAL; } - sbi->s_resgid = gid; + F2FS_OPTION(sbi).s_resgid = gid; break; case Opt_mode: name = match_strdup(&args[0]); @@ -559,7 +574,7 @@ static int parse_options(struct super_block *sb, char *options) return -ENOMEM; if (strlen(name) == 8 && !strncmp(name, "adaptive", 8)) { - if (f2fs_sb_mounted_blkzoned(sb)) { + if (f2fs_sb_has_blkzoned(sb)) { f2fs_msg(sb, KERN_WARNING, "adaptive mode is not allowed with " "zoned block device feature"); @@ -585,7 +600,7 @@ static int parse_options(struct super_block *sb, char *options) 1 << arg, BIO_MAX_PAGES); return -EINVAL; } - sbi->write_io_size_bits = arg; + F2FS_OPTION(sbi).write_io_size_bits = arg; break; case Opt_fault_injection: if (args->from && match_int(args, &arg)) @@ -646,13 +661,13 @@ static int parse_options(struct super_block *sb, char *options) return ret; break; case Opt_jqfmt_vfsold: - sbi->s_jquota_fmt = QFMT_VFS_OLD; + F2FS_OPTION(sbi).s_jquota_fmt = QFMT_VFS_OLD; break; case Opt_jqfmt_vfsv0: - sbi->s_jquota_fmt = QFMT_VFS_V0; + F2FS_OPTION(sbi).s_jquota_fmt = QFMT_VFS_V0; break; case Opt_jqfmt_vfsv1: - sbi->s_jquota_fmt = QFMT_VFS_V1; + F2FS_OPTION(sbi).s_jquota_fmt = QFMT_VFS_V1; break; case Opt_noquota: clear_opt(sbi, QUOTA); @@ -679,6 +694,73 @@ static int parse_options(struct super_block *sb, char *options) "quota operations not supported"); break; #endif + case Opt_whint: + name = match_strdup(&args[0]); + if (!name) + return -ENOMEM; + if (strlen(name) == 10 && + !strncmp(name, "user-based", 10)) { + F2FS_OPTION(sbi).whint_mode = WHINT_MODE_USER; + } else if (strlen(name) == 3 && + !strncmp(name, "off", 3)) { + F2FS_OPTION(sbi).whint_mode = WHINT_MODE_OFF; + } else if (strlen(name) == 8 && + !strncmp(name, "fs-based", 8)) { + F2FS_OPTION(sbi).whint_mode = WHINT_MODE_FS; + } else { + kfree(name); + return -EINVAL; + } + kfree(name); + break; + case Opt_alloc: + name = match_strdup(&args[0]); + if (!name) + return -ENOMEM; + + if (strlen(name) == 7 && + !strncmp(name, "default", 7)) { + F2FS_OPTION(sbi).alloc_mode = ALLOC_MODE_DEFAULT; + } else if (strlen(name) == 5 && + !strncmp(name, "reuse", 5)) { + F2FS_OPTION(sbi).alloc_mode = ALLOC_MODE_REUSE; + } else { + kfree(name); + return -EINVAL; + } + kfree(name); + break; + case Opt_fsync: + name = match_strdup(&args[0]); + if (!name) + return -ENOMEM; + if (strlen(name) == 5 && + !strncmp(name, "posix", 5)) { + F2FS_OPTION(sbi).fsync_mode = FSYNC_MODE_POSIX; + } else if (strlen(name) == 6 && + !strncmp(name, "strict", 6)) { + F2FS_OPTION(sbi).fsync_mode = FSYNC_MODE_STRICT; + } else { + kfree(name); + return -EINVAL; + } + kfree(name); + break; + case Opt_test_dummy_encryption: +#ifdef CONFIG_F2FS_FS_ENCRYPTION + if (!f2fs_sb_has_encrypt(sb)) { + f2fs_msg(sb, KERN_ERR, "Encrypt feature is off"); + return -EINVAL; + } + + F2FS_OPTION(sbi).test_dummy_encryption = true; + f2fs_msg(sb, KERN_INFO, + "Test dummy encryption mode enabled"); +#else + f2fs_msg(sb, KERN_INFO, + "Test dummy encryption mount option ignored"); +#endif + break; default: f2fs_msg(sb, KERN_ERR, "Unrecognized mount option \"%s\" or missing value", @@ -699,14 +781,22 @@ static int parse_options(struct super_block *sb, char *options) } if (test_opt(sbi, INLINE_XATTR_SIZE)) { + if (!f2fs_sb_has_extra_attr(sb) || + !f2fs_sb_has_flexible_inline_xattr(sb)) { + f2fs_msg(sb, KERN_ERR, + "extra_attr or flexible_inline_xattr " + "feature is off"); + return -EINVAL; + } if (!test_opt(sbi, INLINE_XATTR)) { f2fs_msg(sb, KERN_ERR, "inline_xattr_size option should be " "set with inline_xattr option"); return -EINVAL; } - if (!sbi->inline_xattr_size || - sbi->inline_xattr_size >= DEF_ADDRS_PER_INODE - + if (!F2FS_OPTION(sbi).inline_xattr_size || + F2FS_OPTION(sbi).inline_xattr_size >= + DEF_ADDRS_PER_INODE - F2FS_TOTAL_EXTRA_ATTR_SIZE - DEF_INLINE_RESERVED_SIZE - DEF_MIN_INLINE_SIZE) { @@ -715,6 +805,12 @@ static int parse_options(struct super_block *sb, char *options) return -EINVAL; } } + + /* Not pass down write hints if the number of active logs is lesser + * than NR_CURSEG_TYPE. + */ + if (F2FS_OPTION(sbi).active_logs != NR_CURSEG_TYPE) + F2FS_OPTION(sbi).whint_mode = WHINT_MODE_OFF; return 0; } @@ -731,7 +827,6 @@ static struct inode *f2fs_alloc_inode(struct super_block *sb) /* Initialize f2fs-specific inode info */ atomic_set(&fi->dirty_pages, 0); fi->i_current_depth = 1; - fi->i_advise = 0; init_rwsem(&fi->i_sem); INIT_LIST_HEAD(&fi->dirty_list); INIT_LIST_HEAD(&fi->gdirty_list); @@ -743,10 +838,6 @@ static struct inode *f2fs_alloc_inode(struct super_block *sb) init_rwsem(&fi->i_mmap_sem); init_rwsem(&fi->i_xattr_sem); -#ifdef CONFIG_QUOTA - memset(&fi->i_dquot, 0, sizeof(fi->i_dquot)); - fi->i_reserved_quota = 0; -#endif /* Will be used by directory only */ fi->i_dir_level = F2FS_SB(sb)->dir_level; @@ -956,7 +1047,7 @@ static void f2fs_put_super(struct super_block *sb) mempool_destroy(sbi->write_io_dummy); #ifdef CONFIG_QUOTA for (i = 0; i < MAXQUOTAS; i++) - kfree(sbi->s_qf_names[i]); + kfree(F2FS_OPTION(sbi).s_qf_names[i]); #endif destroy_percpu_info(sbi); for (i = 0; i < NR_PAGE_TYPE; i++) @@ -1070,8 +1161,9 @@ static int f2fs_statfs(struct dentry *dentry, struct kstatfs *buf) buf->f_blocks = total_count - start_count; buf->f_bfree = user_block_count - valid_user_blocks(sbi) - sbi->current_reserved_blocks; - if (buf->f_bfree > sbi->root_reserved_blocks) - buf->f_bavail = buf->f_bfree - sbi->root_reserved_blocks; + if (buf->f_bfree > F2FS_OPTION(sbi).root_reserved_blocks) + buf->f_bavail = buf->f_bfree - + F2FS_OPTION(sbi).root_reserved_blocks; else buf->f_bavail = 0; @@ -1106,10 +1198,10 @@ static inline void f2fs_show_quota_options(struct seq_file *seq, #ifdef CONFIG_QUOTA struct f2fs_sb_info *sbi = F2FS_SB(sb); - if (sbi->s_jquota_fmt) { + if (F2FS_OPTION(sbi).s_jquota_fmt) { char *fmtname = ""; - switch (sbi->s_jquota_fmt) { + switch (F2FS_OPTION(sbi).s_jquota_fmt) { case QFMT_VFS_OLD: fmtname = "vfsold"; break; @@ -1123,14 +1215,17 @@ static inline void f2fs_show_quota_options(struct seq_file *seq, seq_printf(seq, ",jqfmt=%s", fmtname); } - if (sbi->s_qf_names[USRQUOTA]) - seq_show_option(seq, "usrjquota", sbi->s_qf_names[USRQUOTA]); + if (F2FS_OPTION(sbi).s_qf_names[USRQUOTA]) + seq_show_option(seq, "usrjquota", + F2FS_OPTION(sbi).s_qf_names[USRQUOTA]); - if (sbi->s_qf_names[GRPQUOTA]) - seq_show_option(seq, "grpjquota", sbi->s_qf_names[GRPQUOTA]); + if (F2FS_OPTION(sbi).s_qf_names[GRPQUOTA]) + seq_show_option(seq, "grpjquota", + F2FS_OPTION(sbi).s_qf_names[GRPQUOTA]); - if (sbi->s_qf_names[PRJQUOTA]) - seq_show_option(seq, "prjjquota", sbi->s_qf_names[PRJQUOTA]); + if (F2FS_OPTION(sbi).s_qf_names[PRJQUOTA]) + seq_show_option(seq, "prjjquota", + F2FS_OPTION(sbi).s_qf_names[PRJQUOTA]); #endif } @@ -1165,7 +1260,7 @@ static int f2fs_show_options(struct seq_file *seq, struct dentry *root) seq_puts(seq, ",noinline_xattr"); if (test_opt(sbi, INLINE_XATTR_SIZE)) seq_printf(seq, ",inline_xattr_size=%u", - sbi->inline_xattr_size); + F2FS_OPTION(sbi).inline_xattr_size); #endif #ifdef CONFIG_F2FS_FS_POSIX_ACL if (test_opt(sbi, POSIX_ACL)) @@ -1201,18 +1296,20 @@ static int f2fs_show_options(struct seq_file *seq, struct dentry *root) seq_puts(seq, "adaptive"); else if (test_opt(sbi, LFS)) seq_puts(seq, "lfs"); - seq_printf(seq, ",active_logs=%u", sbi->active_logs); + seq_printf(seq, ",active_logs=%u", F2FS_OPTION(sbi).active_logs); if (test_opt(sbi, RESERVE_ROOT)) seq_printf(seq, ",reserve_root=%u,resuid=%u,resgid=%u", - sbi->root_reserved_blocks, - from_kuid_munged(&init_user_ns, sbi->s_resuid), - from_kgid_munged(&init_user_ns, sbi->s_resgid)); + F2FS_OPTION(sbi).root_reserved_blocks, + from_kuid_munged(&init_user_ns, + F2FS_OPTION(sbi).s_resuid), + from_kgid_munged(&init_user_ns, + F2FS_OPTION(sbi).s_resgid)); if (F2FS_IO_SIZE_BITS(sbi)) seq_printf(seq, ",io_size=%uKB", F2FS_IO_SIZE_KB(sbi)); #ifdef CONFIG_F2FS_FAULT_INJECTION if (test_opt(sbi, FAULT_INJECTION)) seq_printf(seq, ",fault_injection=%u", - sbi->fault_info.inject_rate); + F2FS_OPTION(sbi).fault_info.inject_rate); #endif #ifdef CONFIG_QUOTA if (test_opt(sbi, QUOTA)) @@ -1225,15 +1322,37 @@ static int f2fs_show_options(struct seq_file *seq, struct dentry *root) seq_puts(seq, ",prjquota"); #endif f2fs_show_quota_options(seq, sbi->sb); + if (F2FS_OPTION(sbi).whint_mode == WHINT_MODE_USER) + seq_printf(seq, ",whint_mode=%s", "user-based"); + else if (F2FS_OPTION(sbi).whint_mode == WHINT_MODE_FS) + seq_printf(seq, ",whint_mode=%s", "fs-based"); +#ifdef CONFIG_F2FS_FS_ENCRYPTION + if (F2FS_OPTION(sbi).test_dummy_encryption) + seq_puts(seq, ",test_dummy_encryption"); +#endif + + if (F2FS_OPTION(sbi).alloc_mode == ALLOC_MODE_DEFAULT) + seq_printf(seq, ",alloc_mode=%s", "default"); + else if (F2FS_OPTION(sbi).alloc_mode == ALLOC_MODE_REUSE) + seq_printf(seq, ",alloc_mode=%s", "reuse"); + if (F2FS_OPTION(sbi).fsync_mode == FSYNC_MODE_POSIX) + seq_printf(seq, ",fsync_mode=%s", "posix"); + else if (F2FS_OPTION(sbi).fsync_mode == FSYNC_MODE_STRICT) + seq_printf(seq, ",fsync_mode=%s", "strict"); return 0; } static void default_options(struct f2fs_sb_info *sbi) { /* init some FS parameters */ - sbi->active_logs = NR_CURSEG_TYPE; - sbi->inline_xattr_size = DEFAULT_INLINE_XATTR_ADDRS; + F2FS_OPTION(sbi).active_logs = NR_CURSEG_TYPE; + F2FS_OPTION(sbi).inline_xattr_size = DEFAULT_INLINE_XATTR_ADDRS; + F2FS_OPTION(sbi).whint_mode = WHINT_MODE_OFF; + F2FS_OPTION(sbi).alloc_mode = ALLOC_MODE_DEFAULT; + F2FS_OPTION(sbi).fsync_mode = FSYNC_MODE_POSIX; + F2FS_OPTION(sbi).test_dummy_encryption = false; + sbi->readdir_ra = 1; set_opt(sbi, BG_GC); set_opt(sbi, INLINE_XATTR); @@ -1243,7 +1362,7 @@ static void default_options(struct f2fs_sb_info *sbi) set_opt(sbi, NOHEAP); sbi->sb->s_flags |= MS_LAZYTIME; set_opt(sbi, FLUSH_MERGE); - if (f2fs_sb_mounted_blkzoned(sbi->sb)) { + if (f2fs_sb_has_blkzoned(sbi->sb)) { set_opt_mode(sbi, F2FS_MOUNT_LFS); set_opt(sbi, DISCARD); } else { @@ -1270,16 +1389,11 @@ static int f2fs_remount(struct super_block *sb, int *flags, char *data) struct f2fs_sb_info *sbi = F2FS_SB(sb); struct f2fs_mount_info org_mount_opt; unsigned long old_sb_flags; - int err, active_logs; + int err; bool need_restart_gc = false; bool need_stop_gc = false; bool no_extent_cache = !test_opt(sbi, EXTENT_CACHE); -#ifdef CONFIG_F2FS_FAULT_INJECTION - struct f2fs_fault_info ffi = sbi->fault_info; -#endif #ifdef CONFIG_QUOTA - int s_jquota_fmt; - char *s_qf_names[MAXQUOTAS]; int i, j; #endif @@ -1289,21 +1403,21 @@ static int f2fs_remount(struct super_block *sb, int *flags, char *data) */ org_mount_opt = sbi->mount_opt; old_sb_flags = sb->s_flags; - active_logs = sbi->active_logs; #ifdef CONFIG_QUOTA - s_jquota_fmt = sbi->s_jquota_fmt; + org_mount_opt.s_jquota_fmt = F2FS_OPTION(sbi).s_jquota_fmt; for (i = 0; i < MAXQUOTAS; i++) { - if (sbi->s_qf_names[i]) { - s_qf_names[i] = kstrdup(sbi->s_qf_names[i], - GFP_KERNEL); - if (!s_qf_names[i]) { + if (F2FS_OPTION(sbi).s_qf_names[i]) { + org_mount_opt.s_qf_names[i] = + kstrdup(F2FS_OPTION(sbi).s_qf_names[i], + GFP_KERNEL); + if (!org_mount_opt.s_qf_names[i]) { for (j = 0; j < i; j++) - kfree(s_qf_names[j]); + kfree(org_mount_opt.s_qf_names[j]); return -ENOMEM; } } else { - s_qf_names[i] = NULL; + org_mount_opt.s_qf_names[i] = NULL; } } #endif @@ -1373,7 +1487,8 @@ static int f2fs_remount(struct super_block *sb, int *flags, char *data) need_stop_gc = true; } - if (*flags & MS_RDONLY) { + if (*flags & MS_RDONLY || + F2FS_OPTION(sbi).whint_mode != org_mount_opt.whint_mode) { writeback_inodes_sb(sb, WB_REASON_SYNC); sync_inodes_sb(sb); @@ -1399,7 +1514,7 @@ static int f2fs_remount(struct super_block *sb, int *flags, char *data) #ifdef CONFIG_QUOTA /* Release old quota file names */ for (i = 0; i < MAXQUOTAS; i++) - kfree(s_qf_names[i]); + kfree(org_mount_opt.s_qf_names[i]); #endif /* Update the POSIXACL Flag */ sb->s_flags = (sb->s_flags & ~MS_POSIXACL) | @@ -1417,18 +1532,14 @@ static int f2fs_remount(struct super_block *sb, int *flags, char *data) } restore_opts: #ifdef CONFIG_QUOTA - sbi->s_jquota_fmt = s_jquota_fmt; + F2FS_OPTION(sbi).s_jquota_fmt = org_mount_opt.s_jquota_fmt; for (i = 0; i < MAXQUOTAS; i++) { - kfree(sbi->s_qf_names[i]); - sbi->s_qf_names[i] = s_qf_names[i]; + kfree(F2FS_OPTION(sbi).s_qf_names[i]); + F2FS_OPTION(sbi).s_qf_names[i] = org_mount_opt.s_qf_names[i]; } #endif sbi->mount_opt = org_mount_opt; - sbi->active_logs = active_logs; sb->s_flags = old_sb_flags; -#ifdef CONFIG_F2FS_FAULT_INJECTION - sbi->fault_info = ffi; -#endif return err; } @@ -1456,7 +1567,7 @@ static ssize_t f2fs_quota_read(struct super_block *sb, int type, char *data, while (toread > 0) { tocopy = min_t(unsigned long, sb->s_blocksize - offset, toread); repeat: - page = read_mapping_page(mapping, blkidx, NULL); + page = read_cache_page_gfp(mapping, blkidx, GFP_NOFS); if (IS_ERR(page)) { if (PTR_ERR(page) == -ENOMEM) { congestion_wait(BLK_RW_ASYNC, HZ/50); @@ -1550,8 +1661,8 @@ static qsize_t *f2fs_get_reserved_space(struct inode *inode) static int f2fs_quota_on_mount(struct f2fs_sb_info *sbi, int type) { - return dquot_quota_on_mount(sbi->sb, sbi->s_qf_names[type], - sbi->s_jquota_fmt, type); + return dquot_quota_on_mount(sbi->sb, F2FS_OPTION(sbi).s_qf_names[type], + F2FS_OPTION(sbi).s_jquota_fmt, type); } int f2fs_enable_quota_files(struct f2fs_sb_info *sbi, bool rdonly) @@ -1570,7 +1681,7 @@ int f2fs_enable_quota_files(struct f2fs_sb_info *sbi, bool rdonly) } for (i = 0; i < MAXQUOTAS; i++) { - if (sbi->s_qf_names[i]) { + if (F2FS_OPTION(sbi).s_qf_names[i]) { err = f2fs_quota_on_mount(sbi, i); if (!err) { enabled = 1; @@ -1797,11 +1908,28 @@ static int f2fs_get_context(struct inode *inode, void *ctx, size_t len) static int f2fs_set_context(struct inode *inode, const void *ctx, size_t len, void *fs_data) { + struct f2fs_sb_info *sbi = F2FS_I_SB(inode); + + /* + * Encrypting the root directory is not allowed because fsck + * expects lost+found directory to exist and remain unencrypted + * if LOST_FOUND feature is enabled. + * + */ + if (f2fs_sb_has_lost_found(sbi->sb) && + inode->i_ino == F2FS_ROOT_INO(sbi)) + return -EPERM; + return f2fs_setxattr(inode, F2FS_XATTR_INDEX_ENCRYPTION, F2FS_XATTR_NAME_ENCRYPTION_CONTEXT, ctx, len, fs_data, XATTR_CREATE); } +static bool f2fs_dummy_context(struct inode *inode) +{ + return DUMMY_ENCRYPTION_ENABLED(F2FS_I_SB(inode)); +} + static unsigned f2fs_max_namelen(struct inode *inode) { return S_ISLNK(inode->i_mode) ? @@ -1812,6 +1940,7 @@ static const struct fscrypt_operations f2fs_cryptops = { .key_prefix = "f2fs:", .get_context = f2fs_get_context, .set_context = f2fs_set_context, + .dummy_context = f2fs_dummy_context, .empty_dir = f2fs_empty_dir, .max_namelen = f2fs_max_namelen, }; @@ -1894,7 +2023,6 @@ static int __f2fs_commit_super(struct buffer_head *bh, lock_buffer(bh); if (super) memcpy(bh->b_data + F2FS_SUPER_OFFSET, super, sizeof(*super)); - set_buffer_uptodate(bh); set_buffer_dirty(bh); unlock_buffer(bh); @@ -2181,6 +2309,8 @@ static void init_sb_info(struct f2fs_sb_info *sbi) sbi->dirty_device = 0; spin_lock_init(&sbi->dev_lock); + + init_rwsem(&sbi->sb_lock); } static int init_percpu_info(struct f2fs_sb_info *sbi) @@ -2206,7 +2336,7 @@ static int init_blkz_info(struct f2fs_sb_info *sbi, int devi) unsigned int n = 0; int err = -EIO; - if (!f2fs_sb_mounted_blkzoned(sbi->sb)) + if (!f2fs_sb_has_blkzoned(sbi->sb)) return 0; if (sbi->blocks_per_blkz && sbi->blocks_per_blkz != @@ -2334,7 +2464,7 @@ int f2fs_commit_super(struct f2fs_sb_info *sbi, bool recover) } /* write back-up superblock first */ - bh = sb_getblk(sbi->sb, sbi->valid_super_block ? 0: 1); + bh = sb_bread(sbi->sb, sbi->valid_super_block ? 0 : 1); if (!bh) return -EIO; err = __f2fs_commit_super(bh, F2FS_RAW_SUPER(sbi)); @@ -2345,7 +2475,7 @@ int f2fs_commit_super(struct f2fs_sb_info *sbi, bool recover) return err; /* write current valid superblock */ - bh = sb_getblk(sbi->sb, sbi->valid_super_block); + bh = sb_bread(sbi->sb, sbi->valid_super_block); if (!bh) return -EIO; err = __f2fs_commit_super(bh, F2FS_RAW_SUPER(sbi)); @@ -2413,7 +2543,7 @@ static int f2fs_scan_devices(struct f2fs_sb_info *sbi) #ifdef CONFIG_BLK_DEV_ZONED if (bdev_zoned_model(FDEV(i).bdev) == BLK_ZONED_HM && - !f2fs_sb_mounted_blkzoned(sbi->sb)) { + !f2fs_sb_has_blkzoned(sbi->sb)) { f2fs_msg(sbi->sb, KERN_ERR, "Zoned block device feature not enabled\n"); return -EINVAL; @@ -2447,6 +2577,18 @@ static int f2fs_scan_devices(struct f2fs_sb_info *sbi) return 0; } +static void f2fs_tuning_parameters(struct f2fs_sb_info *sbi) +{ + struct f2fs_sm_info *sm_i = SM_I(sbi); + + /* adjust parameters according to the volume size */ + if (sm_i->main_segments <= SMALL_VOLUME_SEGMENTS) { + F2FS_OPTION(sbi).alloc_mode = ALLOC_MODE_REUSE; + sm_i->dcc_info->discard_granularity = 1; + sm_i->ipu_policy = 1 << F2FS_IPU_FORCE; + } +} + static int f2fs_fill_super(struct super_block *sb, void *data, int silent) { struct f2fs_sb_info *sbi; @@ -2494,8 +2636,8 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent) sb->s_fs_info = sbi; sbi->raw_super = raw_super; - sbi->s_resuid = make_kuid(&init_user_ns, F2FS_DEF_RESUID); - sbi->s_resgid = make_kgid(&init_user_ns, F2FS_DEF_RESGID); + F2FS_OPTION(sbi).s_resuid = make_kuid(&init_user_ns, F2FS_DEF_RESUID); + F2FS_OPTION(sbi).s_resgid = make_kgid(&init_user_ns, F2FS_DEF_RESGID); /* precompute checksum seed for metadata */ if (f2fs_sb_has_inode_chksum(sb)) @@ -2508,7 +2650,7 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent) * devices, but mandatory for host-managed zoned block devices. */ #ifndef CONFIG_BLK_DEV_ZONED - if (f2fs_sb_mounted_blkzoned(sb)) { + if (f2fs_sb_has_blkzoned(sb)) { f2fs_msg(sb, KERN_ERR, "Zoned block device support is not enabled\n"); err = -EOPNOTSUPP; @@ -2724,7 +2866,7 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent) * Turn on quotas which were not enabled for read-only mounts if * filesystem has quota feature, so that they are updated correctly. */ - if (f2fs_sb_has_quota_ino(sb) && !sb_rdonly(sb)) { + if (f2fs_sb_has_quota_ino(sb) && !f2fs_readonly(sb)) { err = f2fs_enable_quotas(sb); if (err) { f2fs_msg(sb, KERN_ERR, @@ -2799,6 +2941,8 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent) f2fs_join_shrinker(sbi); + f2fs_tuning_parameters(sbi); + f2fs_msg(sbi->sb, KERN_NOTICE, "Mounted with checkpoint version = %llx", cur_cp_version(F2FS_CKPT(sbi))); f2fs_update_time(sbi, CP_TIME); @@ -2807,7 +2951,7 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent) free_meta: #ifdef CONFIG_QUOTA - if (f2fs_sb_has_quota_ino(sb) && !sb_rdonly(sb)) + if (f2fs_sb_has_quota_ino(sb) && !f2fs_readonly(sb)) f2fs_quota_off_umount(sbi->sb); #endif f2fs_sync_inode_meta(sbi); @@ -2851,7 +2995,7 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent) free_options: #ifdef CONFIG_QUOTA for (i = 0; i < MAXQUOTAS; i++) - kfree(sbi->s_qf_names[i]); + kfree(F2FS_OPTION(sbi).s_qf_names[i]); #endif kfree(options); free_sb_buf: diff --git a/fs/f2fs/sysfs.c b/fs/f2fs/sysfs.c index d978c7b6ea04..f33a56d6e6dd 100644 --- a/fs/f2fs/sysfs.c +++ b/fs/f2fs/sysfs.c @@ -58,7 +58,7 @@ static unsigned char *__struct_ptr(struct f2fs_sb_info *sbi, int struct_type) #ifdef CONFIG_F2FS_FAULT_INJECTION else if (struct_type == FAULT_INFO_RATE || struct_type == FAULT_INFO_TYPE) - return (unsigned char *)&sbi->fault_info; + return (unsigned char *)&F2FS_OPTION(sbi).fault_info; #endif return NULL; } @@ -92,10 +92,10 @@ static ssize_t features_show(struct f2fs_attr *a, if (!sb->s_bdev->bd_part) return snprintf(buf, PAGE_SIZE, "0\n"); - if (f2fs_sb_has_crypto(sb)) + if (f2fs_sb_has_encrypt(sb)) len += snprintf(buf, PAGE_SIZE - len, "%s", "encryption"); - if (f2fs_sb_mounted_blkzoned(sb)) + if (f2fs_sb_has_blkzoned(sb)) len += snprintf(buf + len, PAGE_SIZE - len, "%s%s", len ? ", " : "", "blkzoned"); if (f2fs_sb_has_extra_attr(sb)) @@ -116,6 +116,9 @@ static ssize_t features_show(struct f2fs_attr *a, if (f2fs_sb_has_inode_crtime(sb)) len += snprintf(buf + len, PAGE_SIZE - len, "%s%s", len ? ", " : "", "inode_crtime"); + if (f2fs_sb_has_lost_found(sb)) + len += snprintf(buf + len, PAGE_SIZE - len, "%s%s", + len ? ", " : "", "lost_found"); len += snprintf(buf + len, PAGE_SIZE - len, "\n"); return len; } @@ -136,6 +139,27 @@ static ssize_t f2fs_sbi_show(struct f2fs_attr *a, if (!ptr) return -EINVAL; + if (!strcmp(a->attr.name, "extension_list")) { + __u8 (*extlist)[F2FS_EXTENSION_LEN] = + sbi->raw_super->extension_list; + int cold_count = le32_to_cpu(sbi->raw_super->extension_count); + int hot_count = sbi->raw_super->hot_ext_count; + int len = 0, i; + + len += snprintf(buf + len, PAGE_SIZE - len, + "cold file extenstion:\n"); + for (i = 0; i < cold_count; i++) + len += snprintf(buf + len, PAGE_SIZE - len, "%s\n", + extlist[i]); + + len += snprintf(buf + len, PAGE_SIZE - len, + "hot file extenstion:\n"); + for (i = cold_count; i < cold_count + hot_count; i++) + len += snprintf(buf + len, PAGE_SIZE - len, "%s\n", + extlist[i]); + return len; + } + ui = (unsigned int *)(ptr + a->offset); return snprintf(buf, PAGE_SIZE, "%u\n", *ui); @@ -154,6 +178,41 @@ static ssize_t f2fs_sbi_store(struct f2fs_attr *a, if (!ptr) return -EINVAL; + if (!strcmp(a->attr.name, "extension_list")) { + const char *name = strim((char *)buf); + bool set = true, hot; + + if (!strncmp(name, "[h]", 3)) + hot = true; + else if (!strncmp(name, "[c]", 3)) + hot = false; + else + return -EINVAL; + + name += 3; + + if (*name == '!') { + name++; + set = false; + } + + if (strlen(name) >= F2FS_EXTENSION_LEN) + return -EINVAL; + + down_write(&sbi->sb_lock); + + ret = update_extension_list(sbi, name, hot, set); + if (ret) + goto out; + + ret = f2fs_commit_super(sbi, false); + if (ret) + update_extension_list(sbi, name, hot, !set); +out: + up_write(&sbi->sb_lock); + return ret ? ret : count; + } + ui = (unsigned int *)(ptr + a->offset); ret = kstrtoul(skip_spaces(buf), 0, &t); @@ -166,7 +225,7 @@ static ssize_t f2fs_sbi_store(struct f2fs_attr *a, if (a->struct_type == RESERVED_BLOCKS) { spin_lock(&sbi->stat_lock); if (t > (unsigned long)(sbi->user_block_count - - sbi->root_reserved_blocks)) { + F2FS_OPTION(sbi).root_reserved_blocks)) { spin_unlock(&sbi->stat_lock); return -EINVAL; } @@ -236,6 +295,7 @@ enum feat_id { FEAT_FLEXIBLE_INLINE_XATTR, FEAT_QUOTA_INO, FEAT_INODE_CRTIME, + FEAT_LOST_FOUND, }; static ssize_t f2fs_feature_show(struct f2fs_attr *a, @@ -251,6 +311,7 @@ static ssize_t f2fs_feature_show(struct f2fs_attr *a, case FEAT_FLEXIBLE_INLINE_XATTR: case FEAT_QUOTA_INO: case FEAT_INODE_CRTIME: + case FEAT_LOST_FOUND: return snprintf(buf, PAGE_SIZE, "supported\n"); } return 0; @@ -307,6 +368,7 @@ F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, idle_interval, interval_time[REQ_TIME]); F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, iostat_enable, iostat_enable); F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, readdir_ra, readdir_ra); F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, gc_pin_file_thresh, gc_pin_file_threshold); +F2FS_RW_ATTR(F2FS_SBI, f2fs_super_block, extension_list, extension_list); #ifdef CONFIG_F2FS_FAULT_INJECTION F2FS_RW_ATTR(FAULT_INFO_RATE, f2fs_fault_info, inject_rate, inject_rate); F2FS_RW_ATTR(FAULT_INFO_TYPE, f2fs_fault_info, inject_type, inject_type); @@ -329,6 +391,7 @@ F2FS_FEATURE_RO_ATTR(inode_checksum, FEAT_INODE_CHECKSUM); F2FS_FEATURE_RO_ATTR(flexible_inline_xattr, FEAT_FLEXIBLE_INLINE_XATTR); F2FS_FEATURE_RO_ATTR(quota_ino, FEAT_QUOTA_INO); F2FS_FEATURE_RO_ATTR(inode_crtime, FEAT_INODE_CRTIME); +F2FS_FEATURE_RO_ATTR(lost_found, FEAT_LOST_FOUND); #define ATTR_LIST(name) (&f2fs_attr_##name.attr) static struct attribute *f2fs_attrs[] = { @@ -357,6 +420,7 @@ static struct attribute *f2fs_attrs[] = { ATTR_LIST(iostat_enable), ATTR_LIST(readdir_ra), ATTR_LIST(gc_pin_file_thresh), + ATTR_LIST(extension_list), #ifdef CONFIG_F2FS_FAULT_INJECTION ATTR_LIST(inject_rate), ATTR_LIST(inject_type), @@ -383,6 +447,7 @@ static struct attribute *f2fs_feat_attrs[] = { ATTR_LIST(flexible_inline_xattr), ATTR_LIST(quota_ino), ATTR_LIST(inode_crtime), + ATTR_LIST(lost_found), NULL, }; diff --git a/fs/ubifs/dir.c b/fs/ubifs/dir.c index ef820f803176..518c10255881 100644 --- a/fs/ubifs/dir.c +++ b/fs/ubifs/dir.c @@ -1149,38 +1149,24 @@ static int ubifs_symlink(struct inode *dir, struct dentry *dentry, struct ubifs_info *c = dir->i_sb->s_fs_info; int err, len = strlen(symname); int sz_change = CALC_DENT_SIZE(len); - struct fscrypt_str disk_link = FSTR_INIT((char *)symname, len + 1); - struct fscrypt_symlink_data *sd = NULL; + struct fscrypt_str disk_link; struct ubifs_budget_req req = { .new_ino = 1, .new_dent = 1, .new_ino_d = ALIGN(len, 8), .dirtied_ino = 1 }; struct fscrypt_name nm; - if (ubifs_crypt_is_encrypted(dir)) { - err = fscrypt_get_encryption_info(dir); - if (err) - goto out_budg; - - if (!fscrypt_has_encryption_key(dir)) { - err = -EPERM; - goto out_budg; - } + dbg_gen("dent '%pd', target '%s' in dir ino %lu", dentry, + symname, dir->i_ino); - disk_link.len = (fscrypt_fname_encrypted_size(dir, len) + - sizeof(struct fscrypt_symlink_data)); - } + err = fscrypt_prepare_symlink(dir, symname, len, UBIFS_MAX_INO_DATA, + &disk_link); + if (err) + return err; /* * Budget request settings: new inode, new direntry and changing parent * directory inode. */ - - dbg_gen("dent '%pd', target '%s' in dir ino %lu", dentry, - symname, dir->i_ino); - - if (disk_link.len > UBIFS_MAX_INO_DATA) - return -ENAMETOOLONG; - err = ubifs_budget_space(c, &req); if (err) return err; @@ -1202,36 +1188,20 @@ static int ubifs_symlink(struct inode *dir, struct dentry *dentry, goto out_inode; } - if (ubifs_crypt_is_encrypted(dir)) { - struct qstr istr = QSTR_INIT(symname, len); - struct fscrypt_str ostr; - - sd = kzalloc(disk_link.len, GFP_NOFS); - if (!sd) { - err = -ENOMEM; - goto out_inode; - } - - ostr.name = sd->encrypted_path; - ostr.len = disk_link.len; - - err = fscrypt_fname_usr_to_disk(inode, &istr, &ostr); + if (IS_ENCRYPTED(inode)) { + disk_link.name = ui->data; /* encrypt directly into ui->data */ + err = fscrypt_encrypt_symlink(inode, symname, len, &disk_link); if (err) goto out_inode; - - sd->len = cpu_to_le16(ostr.len); - disk_link.name = (char *)sd; } else { + memcpy(ui->data, disk_link.name, disk_link.len); inode->i_link = ui->data; } - memcpy(ui->data, disk_link.name, disk_link.len); - ((char *)ui->data)[disk_link.len - 1] = '\0'; - /* * The terminating zero byte is not written to the flash media and it * is put just to make later in-memory string processing simpler. Thus, - * data length is @len, not @len + %1. + * data length is @disk_link.len - 1, not @disk_link.len. */ ui->data_len = disk_link.len - 1; inode->i_size = ubifs_inode(inode)->ui_size = disk_link.len - 1; @@ -1265,7 +1235,6 @@ static int ubifs_symlink(struct inode *dir, struct dentry *dentry, fscrypt_free_filename(&nm); out_budg: ubifs_release_budget(c, &req); - kfree(sd); return err; } diff --git a/fs/ubifs/file.c b/fs/ubifs/file.c index a02aa59d1e24..ff44fd90d51b 100644 --- a/fs/ubifs/file.c +++ b/fs/ubifs/file.c @@ -1662,49 +1662,17 @@ static const char *ubifs_get_link(struct dentry *dentry, struct inode *inode, struct delayed_call *done) { - int err; - struct fscrypt_symlink_data *sd; struct ubifs_inode *ui = ubifs_inode(inode); - struct fscrypt_str cstr; - struct fscrypt_str pstr; - if (!ubifs_crypt_is_encrypted(inode)) + if (!IS_ENCRYPTED(inode)) return ui->data; if (!dentry) return ERR_PTR(-ECHILD); - err = fscrypt_get_encryption_info(inode); - if (err) - return ERR_PTR(err); - - sd = (struct fscrypt_symlink_data *)ui->data; - cstr.name = sd->encrypted_path; - cstr.len = le16_to_cpu(sd->len); - - if (cstr.len == 0) - return ERR_PTR(-ENOENT); - - if ((cstr.len + sizeof(struct fscrypt_symlink_data) - 1) > ui->data_len) - return ERR_PTR(-EIO); - - err = fscrypt_fname_alloc_buffer(inode, cstr.len, &pstr); - if (err) - return ERR_PTR(err); - - err = fscrypt_fname_disk_to_usr(inode, 0, 0, &cstr, &pstr); - if (err) { - fscrypt_fname_free_buffer(&pstr); - return ERR_PTR(err); - } - - pstr.name[pstr.len] = '\0'; - - set_delayed_call(done, kfree_link, pstr.name); - return pstr.name; + return fscrypt_get_symlink(inode, ui->data, ui->data_len, done); } - const struct address_space_operations ubifs_file_address_operations = { .readpage = ubifs_readpage, .writepage = ubifs_writepage, diff --git a/fs/ubifs/super.c b/fs/ubifs/super.c index 7503e7cdf870..f8dd8803fb15 100644 --- a/fs/ubifs/super.c +++ b/fs/ubifs/super.c @@ -379,9 +379,7 @@ static void ubifs_evict_inode(struct inode *inode) } done: clear_inode(inode); -#ifdef CONFIG_UBIFS_FS_ENCRYPTION - fscrypt_put_encryption_info(inode, NULL); -#endif + fscrypt_put_encryption_info(inode); } static void ubifs_dirty_inode(struct inode *inode, int flags) diff --git a/include/linux/f2fs_fs.h b/include/linux/f2fs_fs.h index 393b880afc9a..aa5db8b5521a 100644 --- a/include/linux/f2fs_fs.h +++ b/include/linux/f2fs_fs.h @@ -21,6 +21,7 @@ #define F2FS_BLKSIZE 4096 /* support only 4KB block */ #define F2FS_BLKSIZE_BITS 12 /* bits for F2FS_BLKSIZE */ #define F2FS_MAX_EXTENSION 64 /* # of extension entries */ +#define F2FS_EXTENSION_LEN 8 /* max size of extension */ #define F2FS_BLK_ALIGN(x) (((x) + F2FS_BLKSIZE - 1) >> F2FS_BLKSIZE_BITS) #define NULL_ADDR ((block_t)0) /* used as block_t addresses */ @@ -38,10 +39,10 @@ #define F2FS_MAX_QUOTAS 3 -#define F2FS_IO_SIZE(sbi) (1 << (sbi)->write_io_size_bits) /* Blocks */ -#define F2FS_IO_SIZE_KB(sbi) (1 << ((sbi)->write_io_size_bits + 2)) /* KB */ -#define F2FS_IO_SIZE_BYTES(sbi) (1 << ((sbi)->write_io_size_bits + 12)) /* B */ -#define F2FS_IO_SIZE_BITS(sbi) ((sbi)->write_io_size_bits) /* power of 2 */ +#define F2FS_IO_SIZE(sbi) (1 << F2FS_OPTION(sbi).write_io_size_bits) /* Blocks */ +#define F2FS_IO_SIZE_KB(sbi) (1 << (F2FS_OPTION(sbi).write_io_size_bits + 2)) /* KB */ +#define F2FS_IO_SIZE_BYTES(sbi) (1 << (F2FS_OPTION(sbi).write_io_size_bits + 12)) /* B */ +#define F2FS_IO_SIZE_BITS(sbi) (F2FS_OPTION(sbi).write_io_size_bits) /* power of 2 */ #define F2FS_IO_SIZE_MASK(sbi) (F2FS_IO_SIZE(sbi) - 1) /* This flag is used by node and meta inodes, and by recovery */ @@ -101,7 +102,7 @@ struct f2fs_super_block { __u8 uuid[16]; /* 128-bit uuid for volume */ __le16 volume_name[MAX_VOLUME_NAME]; /* volume name */ __le32 extension_count; /* # of extensions below */ - __u8 extension_list[F2FS_MAX_EXTENSION][8]; /* extension array */ + __u8 extension_list[F2FS_MAX_EXTENSION][F2FS_EXTENSION_LEN];/* extension array */ __le32 cp_payload; __u8 version[VERSION_LEN]; /* the kernel version */ __u8 init_version[VERSION_LEN]; /* the initial kernel version */ @@ -110,12 +111,14 @@ struct f2fs_super_block { __u8 encrypt_pw_salt[16]; /* Salt used for string2key algorithm */ struct f2fs_device devs[MAX_DEVICES]; /* device list */ __le32 qf_ino[F2FS_MAX_QUOTAS]; /* quota inode numbers */ - __u8 reserved[315]; /* valid reserved region */ + __u8 hot_ext_count; /* # of hot file extension */ + __u8 reserved[314]; /* valid reserved region */ } __packed; /* * For checkpoint */ +#define CP_LARGE_NAT_BITMAP_FLAG 0x00000400 #define CP_NOCRC_RECOVERY_FLAG 0x00000200 #define CP_TRIMMED_FLAG 0x00000100 #define CP_NAT_BITS_FLAG 0x00000080 @@ -302,6 +305,10 @@ struct f2fs_node { */ #define NAT_ENTRY_PER_BLOCK (PAGE_SIZE / sizeof(struct f2fs_nat_entry)) #define NAT_ENTRY_BITMAP_SIZE ((NAT_ENTRY_PER_BLOCK + 7) / 8) +#define NAT_ENTRY_BITMAP_SIZE_ALIGNED \ + ((NAT_ENTRY_BITMAP_SIZE + BITS_PER_LONG - 1) / \ + BITS_PER_LONG * BITS_PER_LONG) + struct f2fs_nat_entry { __u8 version; /* latest version of cached nat entry */ diff --git a/include/linux/fscrypt.h b/include/linux/fscrypt.h index 08b4b40c5aa8..952ab97af325 100644 --- a/include/linux/fscrypt.h +++ b/include/linux/fscrypt.h @@ -14,42 +14,13 @@ #ifndef _LINUX_FSCRYPT_H #define _LINUX_FSCRYPT_H -#include #include -#include -#include -#include -#include -#include #define FS_CRYPTO_BLOCK_SIZE 16 +struct fscrypt_ctx; struct fscrypt_info; -struct fscrypt_ctx { - union { - struct { - struct page *bounce_page; /* Ciphertext page */ - struct page *control_page; /* Original page */ - } w; - struct { - struct bio *bio; - struct work_struct work; - } r; - struct list_head free_list; /* Free list */ - }; - u8 flags; /* Flags */ -}; - -/** - * For encrypted symlinks, the ciphertext length is stored at the beginning - * of the string in little-endian format. - */ -struct fscrypt_symlink_data { - __le16 len; - char encrypted_path[1]; -} __packed; - struct fscrypt_str { unsigned char *name; u32 len; @@ -68,89 +39,14 @@ struct fscrypt_name { #define fname_name(p) ((p)->disk_name.name) #define fname_len(p) ((p)->disk_name.len) -/* - * fscrypt superblock flags - */ -#define FS_CFLG_OWN_PAGES (1U << 1) - -/* - * crypto opertions for filesystems - */ -struct fscrypt_operations { - unsigned int flags; - const char *key_prefix; - int (*get_context)(struct inode *, void *, size_t); - int (*set_context)(struct inode *, const void *, size_t, void *); - bool (*dummy_context)(struct inode *); - bool (*empty_dir)(struct inode *); - unsigned (*max_namelen)(struct inode *); -}; - /* Maximum value for the third parameter of fscrypt_operations.set_context(). */ #define FSCRYPT_SET_CONTEXT_MAX_SIZE 28 -static inline bool fscrypt_dummy_context_enabled(struct inode *inode) -{ - if (inode->i_sb->s_cop->dummy_context && - inode->i_sb->s_cop->dummy_context(inode)) - return true; - return false; -} - -static inline bool fscrypt_valid_enc_modes(u32 contents_mode, - u32 filenames_mode) -{ - if (contents_mode == FS_ENCRYPTION_MODE_AES_128_CBC && - filenames_mode == FS_ENCRYPTION_MODE_AES_128_CTS) - return true; - - if (contents_mode == FS_ENCRYPTION_MODE_AES_256_XTS && - filenames_mode == FS_ENCRYPTION_MODE_AES_256_CTS) - return true; - - return false; -} - -static inline bool fscrypt_is_dot_dotdot(const struct qstr *str) -{ - if (str->len == 1 && str->name[0] == '.') - return true; - - if (str->len == 2 && str->name[0] == '.' && str->name[1] == '.') - return true; - - return false; -} - #if __FS_HAS_ENCRYPTION - -static inline struct page *fscrypt_control_page(struct page *page) -{ - return ((struct fscrypt_ctx *)page_private(page))->w.control_page; -} - -static inline bool fscrypt_has_encryption_key(const struct inode *inode) -{ - return (inode->i_crypt_info != NULL); -} - #include - -#else /* !__FS_HAS_ENCRYPTION */ - -static inline struct page *fscrypt_control_page(struct page *page) -{ - WARN_ON_ONCE(1); - return ERR_PTR(-EINVAL); -} - -static inline bool fscrypt_has_encryption_key(const struct inode *inode) -{ - return 0; -} - +#else #include -#endif /* __FS_HAS_ENCRYPTION */ +#endif /** * fscrypt_require_key - require an inode's encryption key @@ -291,4 +187,68 @@ static inline int fscrypt_prepare_setattr(struct dentry *dentry, return 0; } +/** + * fscrypt_prepare_symlink - prepare to create a possibly-encrypted symlink + * @dir: directory in which the symlink is being created + * @target: plaintext symlink target + * @len: length of @target excluding null terminator + * @max_len: space the filesystem has available to store the symlink target + * @disk_link: (out) the on-disk symlink target being prepared + * + * This function computes the size the symlink target will require on-disk, + * stores it in @disk_link->len, and validates it against @max_len. An + * encrypted symlink may be longer than the original. + * + * Additionally, @disk_link->name is set to @target if the symlink will be + * unencrypted, but left NULL if the symlink will be encrypted. For encrypted + * symlinks, the filesystem must call fscrypt_encrypt_symlink() to create the + * on-disk target later. (The reason for the two-step process is that some + * filesystems need to know the size of the symlink target before creating the + * inode, e.g. to determine whether it will be a "fast" or "slow" symlink.) + * + * Return: 0 on success, -ENAMETOOLONG if the symlink target is too long, + * -ENOKEY if the encryption key is missing, or another -errno code if a problem + * occurred while setting up the encryption key. + */ +static inline int fscrypt_prepare_symlink(struct inode *dir, + const char *target, + unsigned int len, + unsigned int max_len, + struct fscrypt_str *disk_link) +{ + if (IS_ENCRYPTED(dir) || fscrypt_dummy_context_enabled(dir)) + return __fscrypt_prepare_symlink(dir, len, max_len, disk_link); + + disk_link->name = (unsigned char *)target; + disk_link->len = len + 1; + if (disk_link->len > max_len) + return -ENAMETOOLONG; + return 0; +} + +/** + * fscrypt_encrypt_symlink - encrypt the symlink target if needed + * @inode: symlink inode + * @target: plaintext symlink target + * @len: length of @target excluding null terminator + * @disk_link: (in/out) the on-disk symlink target being prepared + * + * If the symlink target needs to be encrypted, then this function encrypts it + * into @disk_link->name. fscrypt_prepare_symlink() must have been called + * previously to compute @disk_link->len. If the filesystem did not allocate a + * buffer for @disk_link->name after calling fscrypt_prepare_link(), then one + * will be kmalloc()'ed and the filesystem will be responsible for freeing it. + * + * Return: 0 on success, -errno on failure + */ +static inline int fscrypt_encrypt_symlink(struct inode *inode, + const char *target, + unsigned int len, + struct fscrypt_str *disk_link) +{ + if (IS_ENCRYPTED(inode)) + return __fscrypt_encrypt_symlink(inode, target, len, disk_link); + return 0; +} + #endif /* _LINUX_FSCRYPT_H */ diff --git a/include/linux/fscrypt_notsupp.h b/include/linux/fscrypt_notsupp.h index 63e58808519a..44b50c04bae9 100644 --- a/include/linux/fscrypt_notsupp.h +++ b/include/linux/fscrypt_notsupp.h @@ -14,6 +14,16 @@ #ifndef _LINUX_FSCRYPT_NOTSUPP_H #define _LINUX_FSCRYPT_NOTSUPP_H +static inline bool fscrypt_has_encryption_key(const struct inode *inode) +{ + return false; +} + +static inline bool fscrypt_dummy_context_enabled(struct inode *inode) +{ + return false; +} + /* crypto.c */ static inline struct fscrypt_ctx *fscrypt_get_ctx(const struct inode *inode, gfp_t gfp_flags) @@ -43,6 +53,11 @@ static inline int fscrypt_decrypt_page(const struct inode *inode, return -EOPNOTSUPP; } +static inline struct page *fscrypt_control_page(struct page *page) +{ + WARN_ON_ONCE(1); + return ERR_PTR(-EINVAL); +} static inline void fscrypt_restore_control_page(struct page *page) { @@ -90,8 +105,7 @@ static inline int fscrypt_get_encryption_info(struct inode *inode) return -EOPNOTSUPP; } -static inline void fscrypt_put_encryption_info(struct inode *inode, - struct fscrypt_info *ci) +static inline void fscrypt_put_encryption_info(struct inode *inode) { return; } @@ -116,16 +130,8 @@ static inline void fscrypt_free_filename(struct fscrypt_name *fname) return; } -static inline u32 fscrypt_fname_encrypted_size(const struct inode *inode, - u32 ilen) -{ - /* never happens */ - WARN_ON(1); - return 0; -} - static inline int fscrypt_fname_alloc_buffer(const struct inode *inode, - u32 ilen, + u32 max_encrypted_len, struct fscrypt_str *crypto_str) { return -EOPNOTSUPP; @@ -144,13 +150,6 @@ static inline int fscrypt_fname_disk_to_usr(struct inode *inode, return -EOPNOTSUPP; } -static inline int fscrypt_fname_usr_to_disk(struct inode *inode, - const struct qstr *iname, - struct fscrypt_str *oname) -{ - return -EOPNOTSUPP; -} - static inline bool fscrypt_match_name(const struct fscrypt_name *fname, const u8 *de_name, u32 de_name_len) { @@ -208,4 +207,28 @@ static inline int __fscrypt_prepare_lookup(struct inode *dir, return -EOPNOTSUPP; } +static inline int __fscrypt_prepare_symlink(struct inode *dir, + unsigned int len, + unsigned int max_len, + struct fscrypt_str *disk_link) +{ + return -EOPNOTSUPP; +} + +static inline int __fscrypt_encrypt_symlink(struct inode *inode, + const char *target, + unsigned int len, + struct fscrypt_str *disk_link) +{ + return -EOPNOTSUPP; +} + +static inline const char *fscrypt_get_symlink(struct inode *inode, + const void *caddr, + unsigned int max_size, + struct delayed_call *done) +{ + return ERR_PTR(-EOPNOTSUPP); +} + #endif /* _LINUX_FSCRYPT_NOTSUPP_H */ diff --git a/include/linux/fscrypt_supp.h b/include/linux/fscrypt_supp.h index cf9e9fc02f0a..477a7a6504d2 100644 --- a/include/linux/fscrypt_supp.h +++ b/include/linux/fscrypt_supp.h @@ -11,8 +11,54 @@ #ifndef _LINUX_FSCRYPT_SUPP_H #define _LINUX_FSCRYPT_SUPP_H +#include +#include + +/* + * fscrypt superblock flags + */ +#define FS_CFLG_OWN_PAGES (1U << 1) + +/* + * crypto operations for filesystems + */ +struct fscrypt_operations { + unsigned int flags; + const char *key_prefix; + int (*get_context)(struct inode *, void *, size_t); + int (*set_context)(struct inode *, const void *, size_t, void *); + bool (*dummy_context)(struct inode *); + bool (*empty_dir)(struct inode *); + unsigned (*max_namelen)(struct inode *); +}; + +struct fscrypt_ctx { + union { + struct { + struct page *bounce_page; /* Ciphertext page */ + struct page *control_page; /* Original page */ + } w; + struct { + struct bio *bio; + struct work_struct work; + } r; + struct list_head free_list; /* Free list */ + }; + u8 flags; /* Flags */ +}; + +static inline bool fscrypt_has_encryption_key(const struct inode *inode) +{ + return (inode->i_crypt_info != NULL); +} + +static inline bool fscrypt_dummy_context_enabled(struct inode *inode) +{ + return inode->i_sb->s_cop->dummy_context && + inode->i_sb->s_cop->dummy_context(inode); +} + /* crypto.c */ -extern struct kmem_cache *fscrypt_info_cachep; extern struct fscrypt_ctx *fscrypt_get_ctx(const struct inode *, gfp_t); extern void fscrypt_release_ctx(struct fscrypt_ctx *); extern struct page *fscrypt_encrypt_page(const struct inode *, struct page *, @@ -20,6 +66,12 @@ extern struct page *fscrypt_encrypt_page(const struct inode *, struct page *, u64, gfp_t); extern int fscrypt_decrypt_page(const struct inode *, struct page *, unsigned int, unsigned int, u64); + +static inline struct page *fscrypt_control_page(struct page *page) +{ + return ((struct fscrypt_ctx *)page_private(page))->w.control_page; +} + extern void fscrypt_restore_control_page(struct page *); extern const struct dentry_operations fscrypt_d_ops; @@ -44,7 +96,7 @@ extern int fscrypt_inherit_context(struct inode *, struct inode *, void *, bool); /* keyinfo.c */ extern int fscrypt_get_encryption_info(struct inode *); -extern void fscrypt_put_encryption_info(struct inode *, struct fscrypt_info *); +extern void fscrypt_put_encryption_info(struct inode *); /* fname.c */ extern int fscrypt_setup_filename(struct inode *, const struct qstr *, @@ -55,14 +107,11 @@ static inline void fscrypt_free_filename(struct fscrypt_name *fname) kfree(fname->crypto_buf.name); } -extern u32 fscrypt_fname_encrypted_size(const struct inode *, u32); extern int fscrypt_fname_alloc_buffer(const struct inode *, u32, struct fscrypt_str *); extern void fscrypt_fname_free_buffer(struct fscrypt_str *); extern int fscrypt_fname_disk_to_usr(struct inode *, u32, u32, const struct fscrypt_str *, struct fscrypt_str *); -extern int fscrypt_fname_usr_to_disk(struct inode *, const struct qstr *, - struct fscrypt_str *); #define FSCRYPT_FNAME_MAX_UNDIGESTED_SIZE 32 @@ -153,5 +202,14 @@ extern int __fscrypt_prepare_rename(struct inode *old_dir, struct dentry *new_dentry, unsigned int flags); extern int __fscrypt_prepare_lookup(struct inode *dir, struct dentry *dentry); +extern int __fscrypt_prepare_symlink(struct inode *dir, unsigned int len, + unsigned int max_len, + struct fscrypt_str *disk_link); +extern int __fscrypt_encrypt_symlink(struct inode *inode, const char *target, + unsigned int len, + struct fscrypt_str *disk_link); +extern const char *fscrypt_get_symlink(struct inode *inode, const void *caddr, + unsigned int max_size, + struct delayed_call *done); #endif /* _LINUX_FSCRYPT_SUPP_H */ -- GitLab From ad747fdc141fb29cf8fcae09b051a128e0464103 Mon Sep 17 00:00:00 2001 From: Karthikeyan Mani Date: Mon, 2 Apr 2018 11:02:58 -0700 Subject: [PATCH 0320/1635] ARM: dts: msm: Add FSA and REGMAP debugfs configs on sdmshrike Enable FSA chip driver and debugfs option for REGMAP on sdmshrike target. Change-Id: I2db930876ed05cbd3c98c586d0e4000cd7ee0266 Signed-off-by: Karthikeyan Mani --- arch/arm64/configs/sdmshrike-perf_defconfig | 1 + arch/arm64/configs/sdmshrike_defconfig | 1 + 2 files changed, 2 insertions(+) diff --git a/arch/arm64/configs/sdmshrike-perf_defconfig b/arch/arm64/configs/sdmshrike-perf_defconfig index 44af27a1279e..6d90ca94032d 100644 --- a/arch/arm64/configs/sdmshrike-perf_defconfig +++ b/arch/arm64/configs/sdmshrike-perf_defconfig @@ -380,6 +380,7 @@ CONFIG_QCOM_COMMAND_DB=y CONFIG_QTI_RPMH_API=y CONFIG_QCOM_GLINK=y CONFIG_QCOM_GLINK_PKT=y +CONFIG_QCOM_FSA4480_I2C=y CONFIG_EXTCON_USB_GPIO=y CONFIG_IIO=y CONFIG_QCOM_SPMI_ADC5=y diff --git a/arch/arm64/configs/sdmshrike_defconfig b/arch/arm64/configs/sdmshrike_defconfig index f42326c64156..006044f1c392 100644 --- a/arch/arm64/configs/sdmshrike_defconfig +++ b/arch/arm64/configs/sdmshrike_defconfig @@ -394,6 +394,7 @@ CONFIG_QCOM_COMMAND_DB=y CONFIG_QTI_RPMH_API=y CONFIG_QCOM_GLINK=y CONFIG_QCOM_GLINK_PKT=y +CONFIG_QCOM_FSA4480_I2C=y CONFIG_EXTCON_USB_GPIO=y CONFIG_IIO=y CONFIG_QCOM_SPMI_ADC5=y -- GitLab From 789a2c1f73a0cfa70f0fda198acc3b6496c26676 Mon Sep 17 00:00:00 2001 From: Jeevan Shriram Date: Sat, 31 Mar 2018 15:41:27 -0700 Subject: [PATCH 0321/1635] ARM: dts: msm: Add imem,restart and sleep counter for sdmshrike Add imem, restart and mpm sleep counter device tree nodes for sdmshrike target. Change-Id: I33430219cb2183581670f1cd5a75e82c68b41dfa Signed-off-by: Jeevan Shriram --- arch/arm64/boot/dts/qcom/sdmshrike.dtsi | 51 +++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sdmshrike.dtsi b/arch/arm64/boot/dts/qcom/sdmshrike.dtsi index e62c0c3ab7db..80e731fbf93f 100644 --- a/arch/arm64/boot/dts/qcom/sdmshrike.dtsi +++ b/arch/arm64/boot/dts/qcom/sdmshrike.dtsi @@ -919,6 +919,57 @@ qcom,ipi-ping; qcom,wakeup-enable; }; + + qcom,msm-imem@146bf000 { + compatible = "qcom,msm-imem"; + reg = <0x146bf000 0x1000>; + ranges = <0x0 0x146bf000 0x1000>; + #address-cells = <1>; + #size-cells = <1>; + + mem_dump_table@10 { + compatible = "qcom,msm-imem-mem_dump_table"; + reg = <0x10 8>; + }; + + restart_reason@65c { + compatible = "qcom,msm-imem-restart_reason"; + reg = <0x65c 4>; + }; + + boot_stats@6b0 { + compatible = "qcom,msm-imem-boot_stats"; + reg = <0x6b0 32>; + }; + + kaslr_offset@6d0 { + compatible = "qcom,msm-imem-kaslr_offset"; + reg = <0x6d0 12>; + }; + + pil@94c { + compatible = "qcom,msm-imem-pil"; + reg = <0x94c 200>; + }; + + diag_dload@c8 { + compatible = "qcom,msm-imem-diag-dload"; + reg = <0xc8 200>; + }; + }; + + restart@c264000 { + compatible = "qcom,pshold"; + reg = <0xc264000 0x4>, + <0x1fd3000 0x4>; + reg-names = "pshold-base", "tcsr-boot-misc-detect"; + }; + + qcom,mpm2-sleep-counter@c221000 { + compatible = "qcom,mpm2-sleep-counter"; + reg = <0xc221000 0x1000>; + clock-frequency = <32768>; + }; }; &emac_gdsc { -- GitLab From 5d09cb476d22e87a34afa7156110f4dcab702fc8 Mon Sep 17 00:00:00 2001 From: Jeevan Shriram Date: Wed, 11 Apr 2018 13:06:56 -0700 Subject: [PATCH 0322/1635] ARM: dts: msm: Update interrupt parent and smp2p bits for LPASS Update interrupt parent and smp2p interrupt bits for LPSS PIL node on sdmshrike target. Change-Id: I4c6be6cb8406070645b57a934005bed697b5d425 Signed-off-by: Jeevan Shriram --- arch/arm64/boot/dts/qcom/sdmshrike.dtsi | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sdmshrike.dtsi b/arch/arm64/boot/dts/qcom/sdmshrike.dtsi index 80e731fbf93f..78dc480965b7 100644 --- a/arch/arm64/boot/dts/qcom/sdmshrike.dtsi +++ b/arch/arm64/boot/dts/qcom/sdmshrike.dtsi @@ -892,11 +892,11 @@ memory-region = <&pil_adsp_mem>; /* Inputs from lpass */ - interrupts-extended = <&intc 0 162 1>, + interrupts-extended = <&pdc 0 162 1>, + <&adsp_smp2p_in 0 0>, <&adsp_smp2p_in 2 0>, <&adsp_smp2p_in 1 0>, - <&adsp_smp2p_in 3 0>, - <&adsp_smp2p_in 0 0>; + <&adsp_smp2p_in 3 0>; interrupt-names = "qcom,wdog", "qcom,err-fatal", @@ -904,7 +904,7 @@ "qcom,err-ready", "qcom,stop-ack"; - /* Outputs from lpass */ + /* Outputs to lpass */ qcom,smem-states = <&adsp_smp2p_out 0>; qcom,smem-state-names = "qcom,force-stop"; }; -- GitLab From 8c3a7f09dbd621022ac3992c4d95f431dc93e15c Mon Sep 17 00:00:00 2001 From: Jeevan Shriram Date: Wed, 11 Apr 2018 13:59:47 -0700 Subject: [PATCH 0323/1635] defconfig: Enable POWEROFF driver on sdmshrike target Enable poweroff driver on sdmshrike target to support reboot and entering into download modes. Change-Id: I3aa636ca871ee5cd42c5f301e7176fb8c640ac75 Signed-off-by: Jeevan Shriram --- arch/arm64/configs/sdmshrike-perf_defconfig | 2 ++ arch/arm64/configs/sdmshrike_defconfig | 2 ++ 2 files changed, 4 insertions(+) diff --git a/arch/arm64/configs/sdmshrike-perf_defconfig b/arch/arm64/configs/sdmshrike-perf_defconfig index 44af27a1279e..4cc4fa5dc1fa 100644 --- a/arch/arm64/configs/sdmshrike-perf_defconfig +++ b/arch/arm64/configs/sdmshrike-perf_defconfig @@ -257,6 +257,8 @@ CONFIG_SLIMBUS_MSM_NGD=y CONFIG_PINCTRL_QCOM_SPMI_PMIC=y CONFIG_PINCTRL_SDMSHRIKE=y CONFIG_GPIO_SYSFS=y +CONFIG_POWER_RESET_QCOM=y +CONFIG_QCOM_DLOAD_MODE=y CONFIG_POWER_RESET_XGENE=y CONFIG_POWER_RESET_SYSCON=y CONFIG_THERMAL=y diff --git a/arch/arm64/configs/sdmshrike_defconfig b/arch/arm64/configs/sdmshrike_defconfig index f42326c64156..fbeb9ab9aae7 100644 --- a/arch/arm64/configs/sdmshrike_defconfig +++ b/arch/arm64/configs/sdmshrike_defconfig @@ -267,6 +267,8 @@ CONFIG_SLIMBUS_MSM_NGD=y CONFIG_PINCTRL_QCOM_SPMI_PMIC=y CONFIG_PINCTRL_SDMSHRIKE=y CONFIG_GPIO_SYSFS=y +CONFIG_POWER_RESET_QCOM=y +CONFIG_QCOM_DLOAD_MODE=y CONFIG_POWER_RESET_XGENE=y CONFIG_POWER_RESET_SYSCON=y CONFIG_THERMAL=y -- GitLab From 64e87bfbdf9ac4d9f9b65cbfa19e25868a0a628f Mon Sep 17 00:00:00 2001 From: Lokesh Batra Date: Wed, 11 Apr 2018 12:07:05 -0700 Subject: [PATCH 0324/1635] msm: kgsl: Set primFifo thresholds value for A640 Set the primFifo thresholds field in GPU_PC_DBG_ECO_CNTL register for A640. Change-Id: I4c87146fb148da522989376ef9f1488a546f889c Signed-off-by: Lokesh Batra --- drivers/gpu/msm/adreno_a6xx.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/msm/adreno_a6xx.c b/drivers/gpu/msm/adreno_a6xx.c index 78e1557ccfc4..a006e8bde13b 100644 --- a/drivers/gpu/msm/adreno_a6xx.c +++ b/drivers/gpu/msm/adreno_a6xx.c @@ -801,8 +801,11 @@ static void a6xx_start(struct adreno_device *adreno_dev) /* Setting the mem pool size */ kgsl_regwrite(device, A6XX_CP_MEM_POOL_SIZE, 128); - /* Setting the primFifo thresholds default values */ - kgsl_regwrite(device, A6XX_PC_DBG_ECO_CNTL, (0x300 << 11)); + /* Setting the primFifo thresholds values */ + if (adreno_is_a640(adreno_dev)) + kgsl_regwrite(device, A6XX_PC_DBG_ECO_CNTL, (0x400 << 11)); + else + kgsl_regwrite(device, A6XX_PC_DBG_ECO_CNTL, (0x300 << 11)); /* Set the AHB default slave response to "ERROR" */ kgsl_regwrite(device, A6XX_CP_AHB_CNTL, 0x1); -- GitLab From 4e1f224dc76de923e7d1b606bf75d3d67c984dee Mon Sep 17 00:00:00 2001 From: Jeevan Shriram Date: Sat, 31 Mar 2018 14:35:23 -0700 Subject: [PATCH 0325/1635] ARM: dts: msm: Add L1 cache definitions to sdmshrike target Ad L1 I/D cache nodes and cpu dump nodes for sdmshrike target. Change-Id: I0381321dc83983812b1cb8f4084c23eb482a653e Signed-off-by: Jeevan Shriram --- arch/arm64/boot/dts/qcom/sdmshrike.dtsi | 164 ++++++++++++++++++++++++ 1 file changed, 164 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sdmshrike.dtsi b/arch/arm64/boot/dts/qcom/sdmshrike.dtsi index 78dc480965b7..583139ea4188 100644 --- a/arch/arm64/boot/dts/qcom/sdmshrike.dtsi +++ b/arch/arm64/boot/dts/qcom/sdmshrike.dtsi @@ -59,6 +59,16 @@ cache-level = <3>; }; }; + + L1_I_0: l1-icache { + compatible = "arm,arch-cache"; + qcom,dump-size = <0xa000>; + }; + + L1_D_0: l1-dcache { + compatible = "arm,arch-cache"; + qcom,dump-size = <0xa000>; + }; }; CPU1: cpu@100 { @@ -74,6 +84,16 @@ cache-level = <2>; next-level-cache = <&L3_0>; }; + + L1_I_100: l1-icache { + compatible = "arm,arch-cache"; + qcom,dump-size = <0xa000>; + }; + + L1_D_100: l1-dcache { + compatible = "arm,arch-cache"; + qcom,dump-size = <0xa000>; + }; }; CPU2: cpu@200 { @@ -89,6 +109,16 @@ cache-level = <2>; next-level-cache = <&L3_0>; }; + + L1_I_200: l1-icache { + compatible = "arm,arch-cache"; + qcom,dump-size = <0xa000>; + }; + + L1_D_200: l1-dcache { + compatible = "arm,arch-cache"; + qcom,dump-size = <0xa000>; + }; }; CPU3: cpu@300 { @@ -104,6 +134,16 @@ cache-level = <2>; next-level-cache = <&L3_0>; }; + + L1_I_300: l1-icache { + compatible = "arm,arch-cache"; + qcom,dump-size = <0xa000>; + }; + + L1_D_300: l1-dcache { + compatible = "arm,arch-cache"; + qcom,dump-size = <0xa000>; + }; }; CPU4: cpu@400 { @@ -119,6 +159,16 @@ cache-level = <2>; next-level-cache = <&L3_0>; }; + + L1_I_400: l1-icache { + compatible = "arm,arch-cache"; + qcom,dump-size = <0x14000>; + }; + + L1_D_400: l1-dcache { + compatible = "arm,arch-cache"; + qcom,dump-size = <0x14000>; + }; }; CPU5: cpu@500 { @@ -134,6 +184,16 @@ cache-level = <2>; next-level-cache = <&L3_0>; }; + + L1_I_500: l1-icache { + compatible = "arm,arch-cache"; + qcom,dump-size = <0x14000>; + }; + + L1_D_500: l1-dcache { + compatible = "arm,arch-cache"; + qcom,dump-size = <0x14000>; + }; }; CPU6: cpu@600 { @@ -149,6 +209,16 @@ cache-level = <2>; next-level-cache = <&L3_0>; }; + + L1_I_600: l1-icache { + compatible = "arm,arch-cache"; + qcom,dump-size = <0x14000>; + }; + + L1_D_600: l1-dcache { + compatible = "arm,arch-cache"; + qcom,dump-size = <0x14000>; + }; }; CPU7: cpu@700 { @@ -164,6 +234,16 @@ cache-level = <2>; next-level-cache = <&L3_0>; }; + + L1_I_700: l1-icache { + compatible = "arm,arch-cache"; + qcom,dump-size = <0x14000>; + }; + + L1_D_700: l1-dcache { + compatible = "arm,arch-cache"; + qcom,dump-size = <0x14000>; + }; }; cpu-map { @@ -210,6 +290,90 @@ }; }; + cpuss_dump { + compatible = "qcom,cpuss-dump"; + + qcom,l1_i_cache0 { + qcom,dump-node = <&L1_I_0>; + qcom,dump-id = <0x60>; + }; + + qcom,l1_i_cache1 { + qcom,dump-node = <&L1_I_100>; + qcom,dump-id = <0x61>; + }; + + qcom,l1_i_cache2 { + qcom,dump-node = <&L1_I_200>; + qcom,dump-id = <0x62>; + }; + + qcom,l1_i_cache3 { + qcom,dump-node = <&L1_I_300>; + qcom,dump-id = <0x63>; + }; + + qcom,l1_i_cache100 { + qcom,dump-node = <&L1_I_400>; + qcom,dump-id = <0x64>; + }; + + qcom,l1_i_cache101 { + qcom,dump-node = <&L1_I_500>; + qcom,dump-id = <0x65>; + }; + + qcom,l1_i_cache102 { + qcom,dump-node = <&L1_I_600>; + qcom,dump-id = <0x66>; + }; + + qcom,l1_i_cache103 { + qcom,dump-node = <&L1_I_700>; + qcom,dump-id = <0x67>; + }; + + qcom,l1_d_cache0 { + qcom,dump-node = <&L1_D_0>; + qcom,dump-id = <0x80>; + }; + + qcom,l1_d_cache1 { + qcom,dump-node = <&L1_D_100>; + qcom,dump-id = <0x81>; + }; + + qcom,l1_d_cache2 { + qcom,dump-node = <&L1_D_200>; + qcom,dump-id = <0x82>; + }; + + qcom,l1_d_cache3 { + qcom,dump-node = <&L1_D_300>; + qcom,dump-id = <0x83>; + }; + + qcom,l1_d_cache100 { + qcom,dump-node = <&L1_D_400>; + qcom,dump-id = <0x84>; + }; + + qcom,l1_d_cache101 { + qcom,dump-node = <&L1_D_500>; + qcom,dump-id = <0x85>; + }; + + qcom,l1_d_cache102 { + qcom,dump-node = <&L1_D_600>; + qcom,dump-id = <0x86>; + }; + + qcom,l1_d_cache103 { + qcom,dump-node = <&L1_D_700>; + qcom,dump-id = <0x87>; + }; + }; + reserved-memory { #address-cells = <2>; #size-cells = <2>; -- GitLab From 08a67b4bbe0f16c6b298bc65e4b672a237709fb7 Mon Sep 17 00:00:00 2001 From: Jeevan Shriram Date: Sat, 31 Mar 2018 15:15:43 -0700 Subject: [PATCH 0326/1635] ARM: dts: msm: Add CPUSS core hang dt node for sdmshrike Add device tree nodes to enable and detect if any CPU is hung. Change-Id: Idd7c2fdcf4886e119800e30f2283cf2f62916b8e Signed-off-by: Jeevan Shriram --- arch/arm64/boot/dts/qcom/sdmshrike.dtsi | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sdmshrike.dtsi b/arch/arm64/boot/dts/qcom/sdmshrike.dtsi index 583139ea4188..dd9fb947ffc3 100644 --- a/arch/arm64/boot/dts/qcom/sdmshrike.dtsi +++ b/arch/arm64/boot/dts/qcom/sdmshrike.dtsi @@ -656,6 +656,24 @@ }; }; + qcom,chd_silver { + compatible = "qcom,core-hang-detect"; + label = "silver"; + qcom,threshold-arr = <0x18000058 0x18010058 + 0x18020058 0x18030058>; + qcom,config-arr = <0x18000060 0x18010060 + 0x18020060 0x18030060>; + }; + + qcom,chd_gold { + compatible = "qcom,core-hang-detect"; + label = "gold"; + qcom,threshold-arr = <0x18040058 0x18050058 + 0x18060058 0x18070058>; + qcom,config-arr = <0x18040060 0x18050060 + 0x18060060 0x18070060>; + }; + qcom,llcc@9200000 { compatible = "qcom,llcc-core", "syscon", "simple-mfd"; reg = <0x9200000 0x450000>; -- GitLab From 1302a3d8ce9cda4a70af3f5a617ca52015d12cab Mon Sep 17 00:00:00 2001 From: Connor O'Brien Date: Wed, 31 Jan 2018 18:11:57 -0800 Subject: [PATCH 0327/1635] ANDROID: cpufreq: track per-task time in state Add time in state data to task structs, and create /proc//time_in_state files to show how long each individual task has run at each frequency. Create a CONFIG_CPU_FREQ_TIMES option to enable/disable this tracking. Signed-off-by: Connor O'Brien Bug: 72339335 Test: Read /proc//time_in_state Change-Id: Ia6456754f4cb1e83b2bc35efa8fbe9f8696febc8 --- drivers/cpufreq/Kconfig | 7 ++ drivers/cpufreq/Makefile | 5 +- drivers/cpufreq/cpufreq.c | 3 + drivers/cpufreq/cpufreq_times.c | 204 ++++++++++++++++++++++++++++++++ fs/proc/base.c | 7 ++ include/linux/cpufreq_times.h | 35 ++++++ include/linux/sched.h | 4 + kernel/exit.c | 4 + kernel/sched/core.c | 5 + kernel/sched/cputime.c | 10 ++ 10 files changed, 283 insertions(+), 1 deletion(-) create mode 100644 drivers/cpufreq/cpufreq_times.c create mode 100644 include/linux/cpufreq_times.h diff --git a/drivers/cpufreq/Kconfig b/drivers/cpufreq/Kconfig index d8addbce40bc..b374515f9813 100644 --- a/drivers/cpufreq/Kconfig +++ b/drivers/cpufreq/Kconfig @@ -37,6 +37,13 @@ config CPU_FREQ_STAT If in doubt, say N. +config CPU_FREQ_TIMES + bool "CPU frequency time-in-state statistics" + help + Export CPU time-in-state information through procfs. + + If in doubt, say N. + choice prompt "Default CPUFreq governor" default CPU_FREQ_DEFAULT_GOV_USERSPACE if ARM_SA1100_CPUFREQ || ARM_SA1110_CPUFREQ diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile index 812f9e0d01a3..3ad8aeb687ef 100644 --- a/drivers/cpufreq/Makefile +++ b/drivers/cpufreq/Makefile @@ -5,7 +5,10 @@ obj-$(CONFIG_CPU_FREQ) += cpufreq.o freq_table.o # CPUfreq stats obj-$(CONFIG_CPU_FREQ_STAT) += cpufreq_stats.o -# CPUfreq governors +# CPUfreq times +obj-$(CONFIG_CPU_FREQ_TIMES) += cpufreq_times.o + +# CPUfreq governors obj-$(CONFIG_CPU_FREQ_GOV_PERFORMANCE) += cpufreq_performance.o obj-$(CONFIG_CPU_FREQ_GOV_POWERSAVE) += cpufreq_powersave.o obj-$(CONFIG_CPU_FREQ_GOV_USERSPACE) += cpufreq_userspace.o diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 183e1edaeece..8e9c2c0f8576 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -19,6 +19,7 @@ #include #include +#include #include #include #include @@ -339,6 +340,7 @@ static void __cpufreq_notify_transition(struct cpufreq_policy *policy, (unsigned long)freqs->new, (unsigned long)freqs->cpu); trace_cpu_frequency(freqs->new, freqs->cpu); cpufreq_stats_record_transition(policy, freqs->new); + cpufreq_times_record_transition(freqs); srcu_notifier_call_chain(&cpufreq_transition_notifier_list, CPUFREQ_POSTCHANGE, freqs); if (likely(policy) && likely(policy->cpu == freqs->cpu)) @@ -1287,6 +1289,7 @@ static int cpufreq_online(unsigned int cpu) goto out_exit_policy; cpufreq_stats_create_table(policy); + cpufreq_times_create_policy(policy); write_lock_irqsave(&cpufreq_driver_lock, flags); list_add(&policy->policy_list, &cpufreq_policy_list); diff --git a/drivers/cpufreq/cpufreq_times.c b/drivers/cpufreq/cpufreq_times.c new file mode 100644 index 000000000000..fa46fcec5388 --- /dev/null +++ b/drivers/cpufreq/cpufreq_times.c @@ -0,0 +1,204 @@ +/* drivers/cpufreq/cpufreq_times.c + * + * Copyright (C) 2018 Google, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +static DEFINE_SPINLOCK(task_time_in_state_lock); /* task->time_in_state */ + +/** + * struct cpu_freqs - per-cpu frequency information + * @offset: start of these freqs' stats in task time_in_state array + * @max_state: number of entries in freq_table + * @last_index: index in freq_table of last frequency switched to + * @freq_table: list of available frequencies + */ +struct cpu_freqs { + unsigned int offset; + unsigned int max_state; + unsigned int last_index; + unsigned int freq_table[0]; +}; + +static struct cpu_freqs *all_freqs[NR_CPUS]; + +static unsigned int next_offset; + +void cpufreq_task_times_init(struct task_struct *p) +{ + void *temp; + unsigned long flags; + unsigned int max_state; + + spin_lock_irqsave(&task_time_in_state_lock, flags); + p->time_in_state = NULL; + spin_unlock_irqrestore(&task_time_in_state_lock, flags); + p->max_state = 0; + + max_state = READ_ONCE(next_offset); + + /* We use one array to avoid multiple allocs per task */ + temp = kcalloc(max_state, sizeof(p->time_in_state[0]), GFP_ATOMIC); + if (!temp) + return; + + spin_lock_irqsave(&task_time_in_state_lock, flags); + p->time_in_state = temp; + spin_unlock_irqrestore(&task_time_in_state_lock, flags); + p->max_state = max_state; +} + +/* Caller must hold task_time_in_state_lock */ +static int cpufreq_task_times_realloc_locked(struct task_struct *p) +{ + void *temp; + unsigned int max_state = READ_ONCE(next_offset); + + temp = krealloc(p->time_in_state, max_state * sizeof(u64), GFP_ATOMIC); + if (!temp) + return -ENOMEM; + p->time_in_state = temp; + memset(p->time_in_state + p->max_state, 0, + (max_state - p->max_state) * sizeof(u64)); + p->max_state = max_state; + return 0; +} + +void cpufreq_task_times_exit(struct task_struct *p) +{ + unsigned long flags; + void *temp; + + spin_lock_irqsave(&task_time_in_state_lock, flags); + temp = p->time_in_state; + p->time_in_state = NULL; + spin_unlock_irqrestore(&task_time_in_state_lock, flags); + kfree(temp); +} + +int proc_time_in_state_show(struct seq_file *m, struct pid_namespace *ns, + struct pid *pid, struct task_struct *p) +{ + unsigned int cpu, i; + u64 cputime; + unsigned long flags; + struct cpu_freqs *freqs; + struct cpu_freqs *last_freqs = NULL; + + spin_lock_irqsave(&task_time_in_state_lock, flags); + for_each_possible_cpu(cpu) { + freqs = all_freqs[cpu]; + if (!freqs || freqs == last_freqs) + continue; + last_freqs = freqs; + + seq_printf(m, "cpu%u\n", cpu); + for (i = 0; i < freqs->max_state; i++) { + if (freqs->freq_table[i] == CPUFREQ_ENTRY_INVALID) + continue; + cputime = 0; + if (freqs->offset + i < p->max_state && + p->time_in_state) + cputime = p->time_in_state[freqs->offset + i]; + seq_printf(m, "%u %lu\n", freqs->freq_table[i], + (unsigned long)nsec_to_clock_t(cputime)); + } + } + spin_unlock_irqrestore(&task_time_in_state_lock, flags); + return 0; +} + +void cpufreq_acct_update_power(struct task_struct *p, u64 cputime) +{ + unsigned long flags; + unsigned int state; + struct cpu_freqs *freqs = all_freqs[task_cpu(p)]; + + if (!freqs || p->flags & PF_EXITING) + return; + + state = freqs->offset + READ_ONCE(freqs->last_index); + + spin_lock_irqsave(&task_time_in_state_lock, flags); + if ((state < p->max_state || !cpufreq_task_times_realloc_locked(p)) && + p->time_in_state) + p->time_in_state[state] += cputime; + spin_unlock_irqrestore(&task_time_in_state_lock, flags); +} + +void cpufreq_times_create_policy(struct cpufreq_policy *policy) +{ + int cpu, index; + unsigned int count = 0; + struct cpufreq_frequency_table *pos, *table; + struct cpu_freqs *freqs; + void *tmp; + + if (all_freqs[policy->cpu]) + return; + + table = policy->freq_table; + if (!table) + return; + + cpufreq_for_each_entry(pos, table) + count++; + + tmp = kzalloc(sizeof(*freqs) + sizeof(freqs->freq_table[0]) * count, + GFP_KERNEL); + if (!tmp) + return; + + freqs = tmp; + freqs->max_state = count; + + index = cpufreq_frequency_table_get_index(policy, policy->cur); + if (index >= 0) + WRITE_ONCE(freqs->last_index, index); + + cpufreq_for_each_entry(pos, table) + freqs->freq_table[pos - table] = pos->frequency; + + freqs->offset = next_offset; + WRITE_ONCE(next_offset, freqs->offset + count); + for_each_cpu(cpu, policy->related_cpus) + all_freqs[cpu] = freqs; +} + +void cpufreq_times_record_transition(struct cpufreq_freqs *freq) +{ + int index; + struct cpu_freqs *freqs = all_freqs[freq->cpu]; + struct cpufreq_policy *policy; + + if (!freqs) + return; + + policy = cpufreq_cpu_get(freq->cpu); + if (!policy) + return; + + index = cpufreq_frequency_table_get_index(policy, freq->new); + if (index >= 0) + WRITE_ONCE(freqs->last_index, index); + + cpufreq_cpu_put(policy); +} diff --git a/fs/proc/base.c b/fs/proc/base.c index 9d357b2ea6cb..b3c05c509ad3 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -93,6 +93,7 @@ #include #include #include +#include #ifdef CONFIG_HARDWALL #include #endif @@ -2989,6 +2990,9 @@ static const struct pid_entry tgid_base_stuff[] = { #ifdef CONFIG_LIVEPATCH ONE("patch_state", S_IRUSR, proc_pid_patch_state), #endif +#ifdef CONFIG_CPU_FREQ_TIMES + ONE("time_in_state", 0444, proc_time_in_state_show), +#endif }; static int proc_tgid_base_readdir(struct file *file, struct dir_context *ctx) @@ -3376,6 +3380,9 @@ static const struct pid_entry tid_base_stuff[] = { #ifdef CONFIG_LIVEPATCH ONE("patch_state", S_IRUSR, proc_pid_patch_state), #endif +#ifdef CONFIG_CPU_FREQ_TIMES + ONE("time_in_state", 0444, proc_time_in_state_show), +#endif }; static int proc_tid_base_readdir(struct file *file, struct dir_context *ctx) diff --git a/include/linux/cpufreq_times.h b/include/linux/cpufreq_times.h new file mode 100644 index 000000000000..8cdbbc8fccec --- /dev/null +++ b/include/linux/cpufreq_times.h @@ -0,0 +1,35 @@ +/* drivers/cpufreq/cpufreq_times.c + * + * Copyright (C) 2018 Google, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef _LINUX_CPUFREQ_TIMES_H +#define _LINUX_CPUFREQ_TIMES_H + +#include +#include + +#ifdef CONFIG_CPU_FREQ_TIMES +void cpufreq_task_times_init(struct task_struct *p); +void cpufreq_task_times_exit(struct task_struct *p); +int proc_time_in_state_show(struct seq_file *m, struct pid_namespace *ns, + struct pid *pid, struct task_struct *p); +void cpufreq_acct_update_power(struct task_struct *p, u64 cputime); +void cpufreq_times_create_policy(struct cpufreq_policy *policy); +void cpufreq_times_record_transition(struct cpufreq_freqs *freq); +#else +static inline void cpufreq_times_create_policy(struct cpufreq_policy *policy) {} +static inline void cpufreq_times_record_transition( + struct cpufreq_freqs *freq) {} +#endif /* CONFIG_CPU_FREQ_TIMES */ +#endif /* _LINUX_CPUFREQ_TIMES_H */ diff --git a/include/linux/sched.h b/include/linux/sched.h index 5d9f33742aab..b4b100872971 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -766,6 +766,10 @@ struct task_struct { u64 stimescaled; #endif u64 gtime; +#ifdef CONFIG_CPU_FREQ_TIMES + u64 *time_in_state; + unsigned int max_state; +#endif struct prev_cputime prev_cputime; #ifdef CONFIG_VIRT_CPU_ACCOUNTING_GEN struct vtime vtime; diff --git a/kernel/exit.c b/kernel/exit.c index e3a08761eb40..1a58e9947f45 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -62,6 +62,7 @@ #include #include #include +#include #include #include @@ -185,6 +186,9 @@ void release_task(struct task_struct *p) { struct task_struct *leader; int zap_leader; +#ifdef CONFIG_CPU_FREQ_TIMES + cpufreq_task_times_exit(p); +#endif repeat: /* don't need to get the RCU readlock here - the process is dead and * can't be modifying its own credentials. But shut RCU-lockdep up */ diff --git a/kernel/sched/core.c b/kernel/sched/core.c index 8a4e64f74bf8..a6e9017b60ca 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -18,6 +18,7 @@ #include #include +#include #include #include #include @@ -2222,6 +2223,10 @@ static void __sched_fork(unsigned long clone_flags, struct task_struct *p) memset(&p->se.statistics, 0, sizeof(p->se.statistics)); #endif +#ifdef CONFIG_CPU_FREQ_TIMES + cpufreq_task_times_init(p); +#endif + RB_CLEAR_NODE(&p->dl.rb_node); init_dl_task_timer(&p->dl); init_dl_inactive_task_timer(&p->dl); diff --git a/kernel/sched/cputime.c b/kernel/sched/cputime.c index 029b505aca49..e7954007b54e 100644 --- a/kernel/sched/cputime.c +++ b/kernel/sched/cputime.c @@ -5,6 +5,7 @@ #include #include #include +#include #include "sched.h" #include "walt.h" @@ -147,6 +148,11 @@ void account_user_time(struct task_struct *p, u64 cputime) /* Account for user time used */ acct_account_cputime(p); + +#ifdef CONFIG_CPU_FREQ_TIMES + /* Account power usage for user time */ + cpufreq_acct_update_power(p, cputime); +#endif } /* @@ -191,6 +197,10 @@ void account_system_index_time(struct task_struct *p, /* Account for system time used */ acct_account_cputime(p); +#ifdef CONFIG_CPU_FREQ_TIMES + /* Account power usage for system time */ + cpufreq_acct_update_power(p, cputime); +#endif } /* -- GitLab From b2ca4f89094256a09a463ee6c3b341f46b5113f8 Mon Sep 17 00:00:00 2001 From: Connor O'Brien Date: Tue, 6 Feb 2018 13:30:27 -0800 Subject: [PATCH 0328/1635] ANDROID: cpufreq: times: track per-uid time in state Add /proc/uid_time_in_state showing per uid/frequency/cluster times. Allow uid removal through /proc/uid_cputime/remove_uid_range. Signed-off-by: Connor O'Brien Bug: 72339335 Test: Read /proc/uid_time_in_state Change-Id: I20ba3546a27c25b7e7991e2a86986e158aafa58c --- drivers/cpufreq/cpufreq_times.c | 208 ++++++++++++++++++++++++++++++++ drivers/misc/uid_sys_stats.c | 5 + include/linux/cpufreq_times.h | 3 + 3 files changed, 216 insertions(+) diff --git a/drivers/cpufreq/cpufreq_times.c b/drivers/cpufreq/cpufreq_times.c index fa46fcec5388..5e19ac5c8157 100644 --- a/drivers/cpufreq/cpufreq_times.c +++ b/drivers/cpufreq/cpufreq_times.c @@ -15,14 +15,30 @@ #include #include +#include +#include #include +#include #include #include #include #include #include +#define UID_HASH_BITS 10 + +static DECLARE_HASHTABLE(uid_hash_table, UID_HASH_BITS); + static DEFINE_SPINLOCK(task_time_in_state_lock); /* task->time_in_state */ +static DEFINE_SPINLOCK(uid_lock); /* uid_hash_table */ + +struct uid_entry { + uid_t uid; + unsigned int max_state; + struct hlist_node hash; + struct rcu_head rcu; + u64 time_in_state[0]; +}; /** * struct cpu_freqs - per-cpu frequency information @@ -42,6 +58,137 @@ static struct cpu_freqs *all_freqs[NR_CPUS]; static unsigned int next_offset; +/* Caller must hold uid lock */ +static struct uid_entry *find_uid_entry_locked(uid_t uid) +{ + struct uid_entry *uid_entry; + + hash_for_each_possible(uid_hash_table, uid_entry, hash, uid) { + if (uid_entry->uid == uid) + return uid_entry; + } + return NULL; +} + +/* Caller must hold uid lock */ +static struct uid_entry *find_or_register_uid_locked(uid_t uid) +{ + struct uid_entry *uid_entry, *temp; + unsigned int max_state = READ_ONCE(next_offset); + size_t alloc_size = sizeof(*uid_entry) + max_state * + sizeof(uid_entry->time_in_state[0]); + + uid_entry = find_uid_entry_locked(uid); + if (uid_entry) { + if (uid_entry->max_state == max_state) + return uid_entry; + /* uid_entry->time_in_state is too small to track all freqs, so + * expand it. + */ + temp = __krealloc(uid_entry, alloc_size, GFP_ATOMIC); + if (!temp) + return uid_entry; + temp->max_state = max_state; + memset(temp->time_in_state + uid_entry->max_state, 0, + (max_state - uid_entry->max_state) * + sizeof(uid_entry->time_in_state[0])); + if (temp != uid_entry) { + hlist_replace_rcu(&uid_entry->hash, &temp->hash); + kfree_rcu(uid_entry, rcu); + } + return temp; + } + + uid_entry = kzalloc(alloc_size, GFP_ATOMIC); + if (!uid_entry) + return NULL; + + uid_entry->uid = uid; + uid_entry->max_state = max_state; + + hash_add_rcu(uid_hash_table, &uid_entry->hash, uid); + + return uid_entry; +} + +static bool freq_index_invalid(unsigned int index) +{ + unsigned int cpu; + struct cpu_freqs *freqs; + + for_each_possible_cpu(cpu) { + freqs = all_freqs[cpu]; + if (!freqs || index < freqs->offset || + freqs->offset + freqs->max_state <= index) + continue; + return freqs->freq_table[index - freqs->offset] == + CPUFREQ_ENTRY_INVALID; + } + return true; +} + +static void *uid_seq_start(struct seq_file *seq, loff_t *pos) +{ + if (*pos >= HASH_SIZE(uid_hash_table)) + return NULL; + + return &uid_hash_table[*pos]; +} + +static void *uid_seq_next(struct seq_file *seq, void *v, loff_t *pos) +{ + (*pos)++; + + if (*pos >= HASH_SIZE(uid_hash_table)) + return NULL; + + return &uid_hash_table[*pos]; +} + +static void uid_seq_stop(struct seq_file *seq, void *v) { } + +static int uid_time_in_state_seq_show(struct seq_file *m, void *v) +{ + struct uid_entry *uid_entry; + struct cpu_freqs *freqs, *last_freqs = NULL; + int i, cpu; + + if (v == uid_hash_table) { + seq_puts(m, "uid:"); + for_each_possible_cpu(cpu) { + freqs = all_freqs[cpu]; + if (!freqs || freqs == last_freqs) + continue; + last_freqs = freqs; + for (i = 0; i < freqs->max_state; i++) { + if (freqs->freq_table[i] == + CPUFREQ_ENTRY_INVALID) + continue; + seq_printf(m, " %d", freqs->freq_table[i]); + } + } + seq_putc(m, '\n'); + } + + rcu_read_lock(); + + hlist_for_each_entry_rcu(uid_entry, (struct hlist_head *)v, hash) { + if (uid_entry->max_state) + seq_printf(m, "%d:", uid_entry->uid); + for (i = 0; i < uid_entry->max_state; ++i) { + if (freq_index_invalid(i)) + continue; + seq_printf(m, " %lu", (unsigned long)nsec_to_clock_t( + uid_entry->time_in_state[i])); + } + if (uid_entry->max_state) + seq_putc(m, '\n'); + } + + rcu_read_unlock(); + return 0; +} + void cpufreq_task_times_init(struct task_struct *p) { void *temp; @@ -87,6 +234,9 @@ void cpufreq_task_times_exit(struct task_struct *p) unsigned long flags; void *temp; + if (!p->time_in_state) + return; + spin_lock_irqsave(&task_time_in_state_lock, flags); temp = p->time_in_state; p->time_in_state = NULL; @@ -130,7 +280,9 @@ void cpufreq_acct_update_power(struct task_struct *p, u64 cputime) { unsigned long flags; unsigned int state; + struct uid_entry *uid_entry; struct cpu_freqs *freqs = all_freqs[task_cpu(p)]; + uid_t uid = from_kuid_munged(current_user_ns(), task_uid(p)); if (!freqs || p->flags & PF_EXITING) return; @@ -142,6 +294,12 @@ void cpufreq_acct_update_power(struct task_struct *p, u64 cputime) p->time_in_state) p->time_in_state[state] += cputime; spin_unlock_irqrestore(&task_time_in_state_lock, flags); + + spin_lock_irqsave(&uid_lock, flags); + uid_entry = find_or_register_uid_locked(uid); + if (uid_entry && state < uid_entry->max_state) + uid_entry->time_in_state[state] += cputime; + spin_unlock_irqrestore(&uid_lock, flags); } void cpufreq_times_create_policy(struct cpufreq_policy *policy) @@ -183,6 +341,27 @@ void cpufreq_times_create_policy(struct cpufreq_policy *policy) all_freqs[cpu] = freqs; } +void cpufreq_task_times_remove_uids(uid_t uid_start, uid_t uid_end) +{ + struct uid_entry *uid_entry; + struct hlist_node *tmp; + unsigned long flags; + + spin_lock_irqsave(&uid_lock, flags); + + for (; uid_start <= uid_end; uid_start++) { + hash_for_each_possible_safe(uid_hash_table, uid_entry, tmp, + hash, uid_start) { + if (uid_start == uid_entry->uid) { + hash_del_rcu(&uid_entry->hash); + kfree_rcu(uid_entry, rcu); + } + } + } + + spin_unlock_irqrestore(&uid_lock, flags); +} + void cpufreq_times_record_transition(struct cpufreq_freqs *freq) { int index; @@ -202,3 +381,32 @@ void cpufreq_times_record_transition(struct cpufreq_freqs *freq) cpufreq_cpu_put(policy); } + +static const struct seq_operations uid_time_in_state_seq_ops = { + .start = uid_seq_start, + .next = uid_seq_next, + .stop = uid_seq_stop, + .show = uid_time_in_state_seq_show, +}; + +static int uid_time_in_state_open(struct inode *inode, struct file *file) +{ + return seq_open(file, &uid_time_in_state_seq_ops); +} + +static const struct file_operations uid_time_in_state_fops = { + .open = uid_time_in_state_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + +static int __init cpufreq_times_init(void) +{ + proc_create_data("uid_time_in_state", 0444, NULL, + &uid_time_in_state_fops, NULL); + + return 0; +} + +early_initcall(cpufreq_times_init); diff --git a/drivers/misc/uid_sys_stats.c b/drivers/misc/uid_sys_stats.c index ace629934821..fbf7db598d55 100644 --- a/drivers/misc/uid_sys_stats.c +++ b/drivers/misc/uid_sys_stats.c @@ -14,6 +14,7 @@ */ #include +#include #include #include #include @@ -419,6 +420,10 @@ static ssize_t uid_remove_write(struct file *file, kstrtol(end_uid, 10, &uid_end) != 0) { return -EINVAL; } + + /* Also remove uids from /proc/uid_time_in_state */ + cpufreq_task_times_remove_uids(uid_start, uid_end); + rt_mutex_lock(&uid_lock); for (; uid_start <= uid_end; uid_start++) { diff --git a/include/linux/cpufreq_times.h b/include/linux/cpufreq_times.h index 8cdbbc8fccec..b7ea7d343317 100644 --- a/include/linux/cpufreq_times.h +++ b/include/linux/cpufreq_times.h @@ -27,9 +27,12 @@ int proc_time_in_state_show(struct seq_file *m, struct pid_namespace *ns, void cpufreq_acct_update_power(struct task_struct *p, u64 cputime); void cpufreq_times_create_policy(struct cpufreq_policy *policy); void cpufreq_times_record_transition(struct cpufreq_freqs *freq); +void cpufreq_task_times_remove_uids(uid_t uid_start, uid_t uid_end); #else static inline void cpufreq_times_create_policy(struct cpufreq_policy *policy) {} static inline void cpufreq_times_record_transition( struct cpufreq_freqs *freq) {} +static inline void cpufreq_task_times_remove_uids(uid_t uid_start, + uid_t uid_end) {} #endif /* CONFIG_CPU_FREQ_TIMES */ #endif /* _LINUX_CPUFREQ_TIMES_H */ -- GitLab From 2c718becc7d503d78024afe41a4453641d6f7a60 Mon Sep 17 00:00:00 2001 From: Connor O'Brien Date: Mon, 16 Oct 2017 10:30:24 -0700 Subject: [PATCH 0329/1635] ANDROID: proc: Add /proc/uid directory Add support for reporting per-uid information through procfs, roughly following the approach used for per-tid and per-tgid directories in fs/proc/base.c. This also entails some new tracking of which uids have been used, to avoid losing information when the last task with a given uid exits. Signed-off-by: Connor O'Brien Bug: 72339335 Test: ls /proc/uid/; compare with UIDs in /proc/uid_time_in_state Change-Id: I0908f0c04438b11ceb673d860e58441bf503d478 --- fs/proc/Kconfig | 7 + fs/proc/Makefile | 1 + fs/proc/internal.h | 9 ++ fs/proc/root.c | 2 +- fs/proc/uid.c | 281 ++++++++++++++++++++++++++++++++++++++++ include/linux/proc_fs.h | 6 + kernel/user.c | 3 + 7 files changed, 308 insertions(+), 1 deletion(-) create mode 100644 fs/proc/uid.c diff --git a/fs/proc/Kconfig b/fs/proc/Kconfig index 1ade1206bb89..08dce22afec1 100644 --- a/fs/proc/Kconfig +++ b/fs/proc/Kconfig @@ -81,3 +81,10 @@ config PROC_CHILDREN Say Y if you are running any user-space software which takes benefit from this interface. For example, rkt is such a piece of software. + +config PROC_UID + bool "Include /proc/uid/ files" + default y + depends on PROC_FS && RT_MUTEXES + help + Provides aggregated per-uid information under /proc/uid. diff --git a/fs/proc/Makefile b/fs/proc/Makefile index f7456c4e7d0f..d8dcb188db6d 100644 --- a/fs/proc/Makefile +++ b/fs/proc/Makefile @@ -26,6 +26,7 @@ proc-y += softirqs.o proc-y += namespaces.o proc-y += self.o proc-y += thread_self.o +proc-$(CONFIG_PROC_UID) += uid.o proc-$(CONFIG_PROC_SYSCTL) += proc_sysctl.o proc-$(CONFIG_NET) += proc_net.o proc-$(CONFIG_PROC_KCORE) += kcore.o diff --git a/fs/proc/internal.h b/fs/proc/internal.h index a34195e92b20..5e55186858c9 100644 --- a/fs/proc/internal.h +++ b/fs/proc/internal.h @@ -248,6 +248,15 @@ static inline void proc_sys_evict_inode(struct inode *inode, struct ctl_table_header *head) { } #endif +/* + * uid.c + */ +#ifdef CONFIG_PROC_UID +extern int proc_uid_init(void); +#else +static inline void proc_uid_init(void) { } +#endif + /* * proc_tty.c */ diff --git a/fs/proc/root.c b/fs/proc/root.c index 4e42aba97f2e..eafe87e010ec 100644 --- a/fs/proc/root.c +++ b/fs/proc/root.c @@ -136,7 +136,7 @@ void __init proc_root_init(void) proc_symlink("mounts", NULL, "self/mounts"); proc_net_init(); - + proc_uid_init(); #ifdef CONFIG_SYSVIPC proc_mkdir("sysvipc", NULL); #endif diff --git a/fs/proc/uid.c b/fs/proc/uid.c new file mode 100644 index 000000000000..ec4e2ae4f6f7 --- /dev/null +++ b/fs/proc/uid.c @@ -0,0 +1,281 @@ +/* + * /proc/uid support + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "internal.h" + +static struct proc_dir_entry *proc_uid; + +#define UID_HASH_BITS 10 + +static DECLARE_HASHTABLE(proc_uid_hash_table, UID_HASH_BITS); + +/* + * use rt_mutex here to avoid priority inversion between high-priority readers + * of these files and tasks calling proc_register_uid(). + */ +static DEFINE_RT_MUTEX(proc_uid_lock); /* proc_uid_hash_table */ + +struct uid_hash_entry { + uid_t uid; + struct hlist_node hash; +}; + +/* Caller must hold proc_uid_lock */ +static bool uid_hash_entry_exists_locked(uid_t uid) +{ + struct uid_hash_entry *entry; + + hash_for_each_possible(proc_uid_hash_table, entry, hash, uid) { + if (entry->uid == uid) + return true; + } + return false; +} + +void proc_register_uid(kuid_t kuid) +{ + struct uid_hash_entry *entry; + bool exists; + uid_t uid = from_kuid_munged(current_user_ns(), kuid); + + rt_mutex_lock(&proc_uid_lock); + exists = uid_hash_entry_exists_locked(uid); + rt_mutex_unlock(&proc_uid_lock); + if (exists) + return; + + entry = kzalloc(sizeof(struct uid_hash_entry), GFP_KERNEL); + if (!entry) + return; + entry->uid = uid; + + rt_mutex_lock(&proc_uid_lock); + if (uid_hash_entry_exists_locked(uid)) + kfree(entry); + else + hash_add(proc_uid_hash_table, &entry->hash, uid); + rt_mutex_unlock(&proc_uid_lock); +} + +struct uid_entry { + const char *name; + int len; + umode_t mode; + const struct inode_operations *iop; + const struct file_operations *fop; +}; + +#define NOD(NAME, MODE, IOP, FOP) { \ + .name = (NAME), \ + .len = sizeof(NAME) - 1, \ + .mode = MODE, \ + .iop = IOP, \ + .fop = FOP, \ +} + +static const struct uid_entry uid_base_stuff[] = {}; + +static const struct inode_operations proc_uid_def_inode_operations = { + .setattr = proc_setattr, +}; + +static struct inode *proc_uid_make_inode(struct super_block *sb, kuid_t kuid) +{ + struct inode *inode; + + inode = new_inode(sb); + if (!inode) + return NULL; + + inode->i_ino = get_next_ino(); + inode->i_mtime = inode->i_atime = inode->i_ctime = current_time(inode); + inode->i_op = &proc_uid_def_inode_operations; + inode->i_uid = kuid; + + return inode; +} + +static int proc_uident_instantiate(struct inode *dir, struct dentry *dentry, + struct task_struct *unused, const void *ptr) +{ + const struct uid_entry *u = ptr; + struct inode *inode; + + inode = proc_uid_make_inode(dir->i_sb, dir->i_uid); + if (!inode) + return -ENOENT; + + inode->i_mode = u->mode; + if (S_ISDIR(inode->i_mode)) + set_nlink(inode, 2); + if (u->iop) + inode->i_op = u->iop; + if (u->fop) + inode->i_fop = u->fop; + d_add(dentry, inode); + return 0; +} + +static struct dentry *proc_uid_base_lookup(struct inode *dir, + struct dentry *dentry, + unsigned int flags) +{ + const struct uid_entry *u, *last; + unsigned int nents = ARRAY_SIZE(uid_base_stuff); + + if (nents == 0) + return ERR_PTR(-ENOENT); + + last = &uid_base_stuff[nents - 1]; + for (u = uid_base_stuff; u <= last; u++) { + if (u->len != dentry->d_name.len) + continue; + if (!memcmp(dentry->d_name.name, u->name, u->len)) + break; + } + if (u > last) + return ERR_PTR(-ENOENT); + + return ERR_PTR(proc_uident_instantiate(dir, dentry, NULL, u)); +} + +static int proc_uid_base_readdir(struct file *file, struct dir_context *ctx) +{ + unsigned int nents = ARRAY_SIZE(uid_base_stuff); + const struct uid_entry *u; + + if (!dir_emit_dots(file, ctx)) + return 0; + + if (ctx->pos >= nents + 2) + return 0; + + for (u = uid_base_stuff + (ctx->pos - 2); + u <= uid_base_stuff + nents - 1; u++) { + if (!proc_fill_cache(file, ctx, u->name, u->len, + proc_uident_instantiate, NULL, u)) + break; + ctx->pos++; + } + + return 0; +} + +static const struct inode_operations proc_uid_base_inode_operations = { + .lookup = proc_uid_base_lookup, + .setattr = proc_setattr, +}; + +static const struct file_operations proc_uid_base_operations = { + .read = generic_read_dir, + .iterate = proc_uid_base_readdir, + .llseek = default_llseek, +}; + +static int proc_uid_instantiate(struct inode *dir, struct dentry *dentry, + struct task_struct *unused, const void *ptr) +{ + unsigned int i, len; + nlink_t nlinks; + kuid_t *kuid = (kuid_t *)ptr; + struct inode *inode = proc_uid_make_inode(dir->i_sb, *kuid); + + if (!inode) + return -ENOENT; + + inode->i_mode = S_IFDIR | 0555; + inode->i_op = &proc_uid_base_inode_operations; + inode->i_fop = &proc_uid_base_operations; + inode->i_flags |= S_IMMUTABLE; + + nlinks = 2; + len = ARRAY_SIZE(uid_base_stuff); + for (i = 0; i < len; ++i) { + if (S_ISDIR(uid_base_stuff[i].mode)) + ++nlinks; + } + set_nlink(inode, nlinks); + + d_add(dentry, inode); + + return 0; +} + +static int proc_uid_readdir(struct file *file, struct dir_context *ctx) +{ + int last_shown, i; + unsigned long bkt; + struct uid_hash_entry *entry; + + if (!dir_emit_dots(file, ctx)) + return 0; + + i = 0; + last_shown = ctx->pos - 2; + rt_mutex_lock(&proc_uid_lock); + hash_for_each(proc_uid_hash_table, bkt, entry, hash) { + int len; + char buf[PROC_NUMBUF]; + + if (i < last_shown) + continue; + len = snprintf(buf, sizeof(buf), "%u", entry->uid); + if (!proc_fill_cache(file, ctx, buf, len, + proc_uid_instantiate, NULL, &entry->uid)) + break; + i++; + ctx->pos++; + } + rt_mutex_unlock(&proc_uid_lock); + return 0; +} + +static struct dentry *proc_uid_lookup(struct inode *dir, struct dentry *dentry, + unsigned int flags) +{ + int result = -ENOENT; + + uid_t uid = name_to_int(&dentry->d_name); + bool uid_exists; + + rt_mutex_lock(&proc_uid_lock); + uid_exists = uid_hash_entry_exists_locked(uid); + rt_mutex_unlock(&proc_uid_lock); + if (uid_exists) { + kuid_t kuid = make_kuid(current_user_ns(), uid); + + result = proc_uid_instantiate(dir, dentry, NULL, &kuid); + } + return ERR_PTR(result); +} + +static const struct file_operations proc_uid_operations = { + .read = generic_read_dir, + .iterate = proc_uid_readdir, + .llseek = default_llseek, +}; + +static const struct inode_operations proc_uid_inode_operations = { + .lookup = proc_uid_lookup, + .setattr = proc_setattr, +}; + +int __init proc_uid_init(void) +{ + proc_uid = proc_mkdir("uid", NULL); + if (!proc_uid) + return -ENOMEM; + proc_uid->proc_iops = &proc_uid_inode_operations; + proc_uid->proc_fops = &proc_uid_operations; + + return 0; +} diff --git a/include/linux/proc_fs.h b/include/linux/proc_fs.h index 928ef9e4d912..d1c705eb4984 100644 --- a/include/linux/proc_fs.h +++ b/include/linux/proc_fs.h @@ -71,6 +71,12 @@ static inline int remove_proc_subtree(const char *name, struct proc_dir_entry *p #endif /* CONFIG_PROC_FS */ +#ifdef CONFIG_PROC_UID +extern void proc_register_uid(kuid_t uid); +#else +static inline void proc_register_uid(kuid_t uid) {} +#endif + struct net; static inline struct proc_dir_entry *proc_net_mkdir( diff --git a/kernel/user.c b/kernel/user.c index 00281add65b2..1a689bf21ae8 100644 --- a/kernel/user.c +++ b/kernel/user.c @@ -17,6 +17,7 @@ #include #include #include +#include #include /* @@ -202,6 +203,7 @@ struct user_struct *alloc_uid(kuid_t uid) } spin_unlock_irq(&uidhash_lock); } + proc_register_uid(uid); return up; @@ -223,6 +225,7 @@ static int __init uid_cache_init(void) spin_lock_irq(&uidhash_lock); uid_hash_insert(&root_user, uidhashentry(GLOBAL_ROOT_UID)); spin_unlock_irq(&uidhash_lock); + proc_register_uid(GLOBAL_ROOT_UID); return 0; } -- GitLab From 5a476c565665a3864110e908e5e09e7b8e2c1cd7 Mon Sep 17 00:00:00 2001 From: Connor O'Brien Date: Mon, 22 Jan 2018 18:28:08 -0800 Subject: [PATCH 0330/1635] ANDROID: cpufreq: Add time_in_state to /proc/uid directories Add per-uid files that report the data in binary format rather than text, to allow faster reading & parsing by userspace. Signed-off-by: Connor O'Brien Bug: 72339335 Test: compare values to those reported in /proc/uid_time_in_state Change-Id: I463039ea7f17b842be4c70024fe772539fe2ce02 --- drivers/cpufreq/cpufreq_times.c | 49 +++++++++++++++++++++++++++++++++ fs/proc/uid.c | 16 ++++++++++- include/linux/cpufreq_times.h | 1 + 3 files changed, 65 insertions(+), 1 deletion(-) diff --git a/drivers/cpufreq/cpufreq_times.c b/drivers/cpufreq/cpufreq_times.c index 5e19ac5c8157..f560e10ba183 100644 --- a/drivers/cpufreq/cpufreq_times.c +++ b/drivers/cpufreq/cpufreq_times.c @@ -58,6 +58,19 @@ static struct cpu_freqs *all_freqs[NR_CPUS]; static unsigned int next_offset; + +/* Caller must hold rcu_read_lock() */ +static struct uid_entry *find_uid_entry_rcu(uid_t uid) +{ + struct uid_entry *uid_entry; + + hash_for_each_possible_rcu(uid_hash_table, uid_entry, hash, uid) { + if (uid_entry->uid == uid) + return uid_entry; + } + return NULL; +} + /* Caller must hold uid lock */ static struct uid_entry *find_uid_entry_locked(uid_t uid) { @@ -127,6 +140,36 @@ static bool freq_index_invalid(unsigned int index) return true; } +static int single_uid_time_in_state_show(struct seq_file *m, void *ptr) +{ + struct uid_entry *uid_entry; + unsigned int i; + u64 time; + uid_t uid = from_kuid_munged(current_user_ns(), *(kuid_t *)m->private); + + if (uid == overflowuid) + return -EINVAL; + + rcu_read_lock(); + + uid_entry = find_uid_entry_rcu(uid); + if (!uid_entry) { + rcu_read_unlock(); + return 0; + } + + for (i = 0; i < uid_entry->max_state; ++i) { + if (freq_index_invalid(i)) + continue; + time = nsec_to_clock_t(uid_entry->time_in_state[i]); + seq_write(m, &time, sizeof(time)); + } + + rcu_read_unlock(); + + return 0; +} + static void *uid_seq_start(struct seq_file *seq, loff_t *pos) { if (*pos >= HASH_SIZE(uid_hash_table)) @@ -394,6 +437,12 @@ static int uid_time_in_state_open(struct inode *inode, struct file *file) return seq_open(file, &uid_time_in_state_seq_ops); } +int single_uid_time_in_state_open(struct inode *inode, struct file *file) +{ + return single_open(file, single_uid_time_in_state_show, + &(inode->i_uid)); +} + static const struct file_operations uid_time_in_state_fops = { .open = uid_time_in_state_open, .read = seq_read, diff --git a/fs/proc/uid.c b/fs/proc/uid.c index ec4e2ae4f6f7..9e15be510d71 100644 --- a/fs/proc/uid.c +++ b/fs/proc/uid.c @@ -2,6 +2,7 @@ * /proc/uid support */ +#include #include #include #include @@ -82,7 +83,20 @@ struct uid_entry { .fop = FOP, \ } -static const struct uid_entry uid_base_stuff[] = {}; +#ifdef CONFIG_CPU_FREQ_TIMES +static const struct file_operations proc_uid_time_in_state_operations = { + .open = single_uid_time_in_state_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; +#endif + +static const struct uid_entry uid_base_stuff[] = { +#ifdef CONFIG_CPU_FREQ_TIMES + NOD("time_in_state", 0444, NULL, &proc_uid_time_in_state_operations), +#endif +}; static const struct inode_operations proc_uid_def_inode_operations = { .setattr = proc_setattr, diff --git a/include/linux/cpufreq_times.h b/include/linux/cpufreq_times.h index b7ea7d343317..e84b576a20d5 100644 --- a/include/linux/cpufreq_times.h +++ b/include/linux/cpufreq_times.h @@ -28,6 +28,7 @@ void cpufreq_acct_update_power(struct task_struct *p, u64 cputime); void cpufreq_times_create_policy(struct cpufreq_policy *policy); void cpufreq_times_record_transition(struct cpufreq_freqs *freq); void cpufreq_task_times_remove_uids(uid_t uid_start, uid_t uid_end); +int single_uid_time_in_state_open(struct inode *inode, struct file *file); #else static inline void cpufreq_times_create_policy(struct cpufreq_policy *policy) {} static inline void cpufreq_times_record_transition( -- GitLab From 282e2eb407b3693631be16210f148e73885fdc98 Mon Sep 17 00:00:00 2001 From: Maheshwar Ajja Date: Thu, 12 Apr 2018 13:26:38 -0700 Subject: [PATCH 0331/1635] msm: vidc: fix cvp session close issue Video driver tries to unregister the buffers which are not unregistered by the userspace client in deinitialization. Unregistering the buffers is not required as the session will be closed anyway. So simply try session close in msm_cvp_inst_deinit() to avoid errors due to unregistering buffers. Change-Id: Id9ae0683498dbbc1451055bf04a7fb7513248391 Signed-off-by: Maheshwar Ajja --- drivers/media/platform/msm/vidc/msm_cvp.c | 49 ++++------------------- 1 file changed, 8 insertions(+), 41 deletions(-) diff --git a/drivers/media/platform/msm/vidc/msm_cvp.c b/drivers/media/platform/msm/vidc/msm_cvp.c index de723b0a637e..8c41bac888a7 100644 --- a/drivers/media/platform/msm/vidc/msm_cvp.c +++ b/drivers/media/platform/msm/vidc/msm_cvp.c @@ -518,62 +518,29 @@ int msm_cvp_ctrl_init(struct msm_vidc_inst *inst, int msm_cvp_inst_deinit(struct msm_vidc_inst *inst) { int rc = 0; - struct hfi_device *hdev; - struct msm_vidc_cvp_buffer *cbuf; - struct vidc_unregister_buffer vbuf; + struct msm_vidc_cvp_buffer *cbuf, *temp; if (!inst || !inst->core) { dprintk(VIDC_ERR, "%s: invalid params\n", __func__); return -EINVAL; } - hdev = inst->core->device; dprintk(VIDC_DBG, "%s: inst %pK (%#x)\n", __func__, inst, hash32_ptr(inst->session)); - do { - mutex_lock(&inst->cvpbufs.lock); - if (list_empty(&inst->cvpbufs.list)) { - mutex_unlock(&inst->cvpbufs.lock); - break; - } - cbuf = list_first_entry(&inst->cvpbufs.list, - struct msm_vidc_cvp_buffer, list); - mutex_unlock(&inst->cvpbufs.lock); + rc = msm_comm_try_state(inst, MSM_VIDC_CLOSE_DONE); + if (rc) + dprintk(VIDC_ERR, "%s: close failed\n", __func__); + mutex_lock(&inst->cvpbufs.lock); + list_for_each_entry_safe(cbuf, temp, &inst->cvpbufs.list, list) { print_cvp_buffer(VIDC_ERR, "unregistered", inst, cbuf); - memset(&vbuf, 0, sizeof(struct vidc_unregister_buffer)); - vbuf.index = cbuf->buf.index; - vbuf.type = get_hal_buftype(__func__, cbuf->buf.type); - vbuf.size = cbuf->buf.size; - vbuf.device_addr = cbuf->smem.device_addr; - vbuf.client_data = cbuf->smem.device_addr; - vbuf.response_required = true; - rc = call_hfi_op(hdev, session_unregister_buffer, - (void *)inst->session, &vbuf); - if (rc) { - dprintk(VIDC_ERR, "%s: unregbuf failed\n", __func__); - } else { - rc = wait_for_completion_timeout( - &inst->completions[ - SESSION_MSG_INDEX( - HAL_SESSION_UNREGISTER_BUFFER_DONE)], - msecs_to_jiffies( - inst->core->resources.msm_vidc_hw_rsp_timeout)); - if (!rc) - dprintk(VIDC_ERR, - "%s: wait timedout for unregbuf done\n", - __func__); - } rc = msm_smem_unmap_dma_buf(inst, &cbuf->smem); if (rc) dprintk(VIDC_ERR, "%s: unmap failed\n", __func__); - - mutex_lock(&inst->cvpbufs.lock); list_del(&cbuf->list); - mutex_unlock(&inst->cvpbufs.lock); kfree(cbuf); - cbuf = NULL; - } while (1); + } + mutex_unlock(&inst->cvpbufs.lock); inst->clk_data.min_freq = 0; inst->clk_data.ddr_bw = 0; -- GitLab From aac89833af95c10b4867c09fdd8c91b35620b482 Mon Sep 17 00:00:00 2001 From: Chris Lew Date: Wed, 11 Apr 2018 15:33:32 -0700 Subject: [PATCH 0332/1635] soc: qcom: qsee_ipc_irq: Fix irq mapping logic The hw irq number should be determined by using the bank index and bit offset of the irq status register. Add a macro to quickly get the hw irq number from this information. Change-Id: Ic5e3a193a2b0d145c8d4a593fbff5208a10b099a Signed-off-by: Chris Lew --- drivers/soc/qcom/qsee_ipc_irq.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/soc/qcom/qsee_ipc_irq.c b/drivers/soc/qcom/qsee_ipc_irq.c index 4242b85e58d7..99a29c61f560 100644 --- a/drivers/soc/qcom/qsee_ipc_irq.c +++ b/drivers/soc/qcom/qsee_ipc_irq.c @@ -26,6 +26,7 @@ #define hwirq_to_index(_irq) (_irq / MAX_BANK_IRQ) #define hwirq_to_bit(_irq) (_irq % MAX_BANK_IRQ) +#define to_hwirq(_index, _bit) ((_index * MAX_BANK_IRQ) + _bit) struct qsee_irq_data { const char *name; @@ -71,6 +72,7 @@ static irqreturn_t qsee_intr(int irq, void *data) u32 status; u32 mask; int i; + int j; for (i = 0; i < qirq->num_banks; i++) { if (qirq->banks[i].irq == irq) { @@ -92,14 +94,14 @@ static irqreturn_t qsee_intr(int irq, void *data) return IRQ_HANDLED; } - for_each_set_bit(i, bank->irq_enabled, bank->data->msb) { - if (!(status & BIT(i))) + for_each_set_bit(j, bank->irq_enabled, bank->data->msb) { + if (!(status & BIT(j))) continue; - irq_pin = irq_find_mapping(qirq->domain, i); + irq_pin = irq_find_mapping(qirq->domain, to_hwirq(i, j)); desc = irq_to_desc(irq_pin); handle_simple_irq(desc); - regmap_write(qirq->regmap, bank->data->clear, BIT(i)); + regmap_write(qirq->regmap, bank->data->clear, BIT(j)); } return IRQ_HANDLED; -- GitLab From 09ddc60f1f784212cd2c3a8d8fb4f6f9c0cf40a5 Mon Sep 17 00:00:00 2001 From: Chris Lew Date: Wed, 11 Apr 2018 18:05:40 -0700 Subject: [PATCH 0333/1635] soc: qcom: glink_pkt: Remove incorrect mutex_unlock When a channel is reset and a client is still reading, glink pkt executes an error case. Remove the incorrect mutex_unlock in this case. Change-Id: I2c28dadf327b09eaa55f9853e8bf1f55017c4e51 Signed-off-by: Chris Lew --- drivers/soc/qcom/glink_pkt.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/soc/qcom/glink_pkt.c b/drivers/soc/qcom/glink_pkt.c index aa95d72d0980..a4fb9c19ff62 100644 --- a/drivers/soc/qcom/glink_pkt.c +++ b/drivers/soc/qcom/glink_pkt.c @@ -352,9 +352,7 @@ ssize_t glink_pkt_read(struct file *file, char __user *buf, if (!completion_done(&gpdev->ch_open)) { GLINK_PKT_ERR("%s channel in reset\n", gpdev->ch_name); - mutex_unlock(&gpdev->lock); return -ENETRESET; - } GLINK_PKT_INFO("begin for %s by %s:%ld ref_cnt[%d]\n", -- GitLab From f2dc86b17140de85d606aa16c636fc355a20b752 Mon Sep 17 00:00:00 2001 From: Chris Lew Date: Fri, 6 Apr 2018 18:08:07 -0700 Subject: [PATCH 0334/1635] soc: qcom: Add snapshot of qsee_ipc_irq_bridge driver This snapshot is taken as of msm-4.9 'commit <34e1614ab73d> ("Merge "thermal: qpnp-adc-tm: Add read_status function for non-HC peripheral"")'. In addition, update copyright and remove wake properties from the interrupt since this will be handled by the qsee_ipc_irq driver. Also change of_get_property to of_property_read_string for names. Change-Id: I36bbc36b3e87548020fe5a52422a5343d83f81cb Signed-off-by: Chris Lew --- .../bindings/arm/msm/qsee_ipc_irq_bridge.txt | 30 + drivers/soc/qcom/Kconfig | 10 + drivers/soc/qcom/Makefile | 1 + drivers/soc/qcom/qsee_ipc_irq_bridge.c | 618 ++++++++++++++++++ 4 files changed, 659 insertions(+) create mode 100644 Documentation/devicetree/bindings/arm/msm/qsee_ipc_irq_bridge.txt create mode 100644 drivers/soc/qcom/qsee_ipc_irq_bridge.c diff --git a/Documentation/devicetree/bindings/arm/msm/qsee_ipc_irq_bridge.txt b/Documentation/devicetree/bindings/arm/msm/qsee_ipc_irq_bridge.txt new file mode 100644 index 000000000000..442ad52b4bf6 --- /dev/null +++ b/Documentation/devicetree/bindings/arm/msm/qsee_ipc_irq_bridge.txt @@ -0,0 +1,30 @@ +Qualcomm Technologies, Inc. Secure Execution Environment IPC Interrupt Bridge + +[Root level node] +Required properties: +-compatible : should be "qcom,qsee-ipc-irq-bridge"; + +[Second level nodes] +qcom,qsee-ipc-irq-subsystem +Required properties: +-qcom,dev-name: the bridge device name +-interrupt: IPC interrupt line from remote subsystem to QSEE +-label : The name of this subsystem. + +Required properties if interrupt type is IRQ_TYPE_LEVEL_HIGH[4]: +-qcom,rx-irq-clr : the register to clear the level triggered rx interrupt +-qcom,rx-irq-clr-mask : the bitmask to clear the rx interrupt + +Example: + + qcom,qsee_ipc_irq_bridge { + compatible = "qcom,qsee-ipc-irq-bridge"; + + qcom,qsee-ipc-irq-spss { + qcom,rx-irq-clr = <0x1d08008 0x4>; + qcom,rx-irq-clr-mask = <0x2>; + qcom,dev-name = "qsee_ipc_irq_spss"; + interrupts = <0 349 4>; + label = "spss"; + }; + }; diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig index 5f7e37bcb8ac..9b7524158e65 100644 --- a/drivers/soc/qcom/Kconfig +++ b/drivers/soc/qcom/Kconfig @@ -445,6 +445,16 @@ config QSEE_IPC_IRQ Clients can use this driver to avoid adding common interrupt handling code. +config QSEE_IPC_IRQ_BRIDGE + tristate "QSEE IPC Interrupt Bridge" + select QSEE_IPC_IRQ + help + This module enables bridging an Inter-Processor Communication(IPC) + interrupt from a remote subsystem directed towards Qualcomm + Technologies, Inc. Secure Execution Environment(QSEE) to userspace. + The interrupt will be propagated through a character device that + userspace clients can poll on. + config QCOM_GLINK tristate "GLINK Probe Helper" depends on RPMSG_QCOM_GLINK_SMEM diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile index 7a02a524f99f..99032318df6d 100644 --- a/drivers/soc/qcom/Makefile +++ b/drivers/soc/qcom/Makefile @@ -57,6 +57,7 @@ ifdef CONFIG_MSM_SUBSYSTEM_RESTART endif obj-$(CONFIG_QCOM_EUD) += eud.o obj-$(CONFIG_QSEE_IPC_IRQ) += qsee_ipc_irq.o +obj-$(CONFIG_QSEE_IPC_IRQ_BRIDGE) += qsee_ipc_irq_bridge.o obj-$(CONFIG_QCOM_GLINK) += glink_probe.o obj-$(CONFIG_QCOM_GLINK_PKT) += glink_pkt.o obj-$(CONFIG_QCOM_QDSS_BRIDGE) += qdss_bridge.o diff --git a/drivers/soc/qcom/qsee_ipc_irq_bridge.c b/drivers/soc/qcom/qsee_ipc_irq_bridge.c new file mode 100644 index 000000000000..6da4b6626d37 --- /dev/null +++ b/drivers/soc/qcom/qsee_ipc_irq_bridge.c @@ -0,0 +1,618 @@ +/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MODULE_NAME "qsee_ipc_irq_bridge" +#define DEVICE_NAME MODULE_NAME +#define NUM_LOG_PAGES 4 + +#define QIIB_DBG(x...) do { \ + if (qiib_info->log_ctx) \ + ipc_log_string(qiib_info->log_ctx, x); \ + else \ + pr_debug(x); \ + } while (0) + +#define QIIB_ERR(x...) do { \ + pr_err(x); \ + if (qiib_info->log_ctx) \ + ipc_log_string(qiib_info->log_ctx, x); \ + } while (0) + +static void qiib_cleanup(void); + +/** + * qiib_dev - QSEE IPC IRQ bridge device + * @dev_list: qiib device list. + * @i: Index to this character device. + * @dev_name: Device node name used by the clients. + * @cdev: structure to the internal character device. + * @devicep: Pointer to the qiib class device structure. + * @poll_wait_queue: poll thread wait queue. + * @irq_num: IRQ number usd for this device. + * @rx_irq_reset_reg: Reference to the register to reset the rx irq + * line, if applicable. + * @irq_mask: Mask written to @rx_irq_reset_reg to clear the irq. + * @irq_pending_count: The number of IRQs pending. + * @irq_pending_count_lock: Lock to protect @irq_pending_cont. + * @ssr_name: Name of the subsystem recognized by the SSR framework. + * @nb: SSR Notifier callback. + * @notifier_handle: SSR Notifier handle. + * @in_reset: Flag to check the SSR state. + */ +struct qiib_dev { + struct list_head dev_list; + uint32_t i; + + const char *dev_name; + struct cdev cdev; + struct device *devicep; + + wait_queue_head_t poll_wait_queue; + + uint32_t irq_line; + void __iomem *rx_irq_reset_reg; + uint32_t irq_mask; + uint32_t irq_pending_count; + spinlock_t irq_pending_count_lock; + + const char *ssr_name; + struct notifier_block nb; + void *notifier_handle; + bool in_reset; +}; + +/** + * qiib_driver_data - QSEE IPC IRQ bridge driver data + * @list: list of all nodes devices. + * @list_lock: lock to synchronize the @list access. + * @nprots: Number of device nodes. + * @classp: Pointer to the device class. + * @dev_num: qiib device number. + * @log_ctx: pointer to the ipc logging context. + */ +struct qiib_driver_data { + struct list_head list; + struct mutex list_lock; + + int nports; + struct class *classp; + dev_t dev_num; + + void *log_ctx; +}; + +static struct qiib_driver_data *qiib_info; + +/** + * qiib_driver_data_init() - Initialize the QIIB driver data. + * + * This function used to initialize the driver specific data + * during the module init. + * + * Return: 0 for success, Standard Linux errors + */ +static int qiib_driver_data_init(void) +{ + qiib_info = kzalloc(sizeof(*qiib_info), GFP_KERNEL); + if (!qiib_info) + return -ENOMEM; + + INIT_LIST_HEAD(&qiib_info->list); + mutex_init(&qiib_info->list_lock); + + qiib_info->log_ctx = ipc_log_context_create(NUM_LOG_PAGES, + "qsee_ipc_irq_bridge", 0); + if (!qiib_info->log_ctx) + QIIB_ERR("%s: unable to create logging context\n", __func__); + + return 0; +} + +/** + * qiib_driver_data_deinit() - De-Initialize the QIIB driver data. + * + * This function used to de-initialize the driver specific data + * during the module exit. + */ +static void qiib_driver_data_deinit(void) +{ + qiib_cleanup(); + if (!qiib_info->log_ctx) + ipc_log_context_destroy(qiib_info->log_ctx); + kfree(qiib_info); + qiib_info = NULL; +} + +/** + * qiib_restart_notifier_cb() - SSR restart notifier callback function + * @this: Notifier block used by the SSR framework + * @code: The SSR code for which stage of restart is occurring + * @data: Structure containing private data - not used here. + * + * This function is a callback for the SSR framework. From here we initiate + * our handling of SSR. + * + * Return: Status of SSR handling + */ +static int qiib_restart_notifier_cb(struct notifier_block *this, + unsigned long code, + void *data) +{ + struct qiib_dev *devp = container_of(this, struct qiib_dev, nb); + + if (code == SUBSYS_BEFORE_SHUTDOWN) { + QIIB_DBG("%s: %s: subsystem restart for %s\n", __func__, + "SUBSYS_BEFORE_SHUTDOWN", + devp->ssr_name); + devp->in_reset = true; + wake_up_interruptible(&devp->poll_wait_queue); + } else if (code == SUBSYS_AFTER_POWERUP) { + QIIB_DBG("%s: %s: subsystem restart for %s\n", __func__, + "SUBSYS_AFTER_POWERUP", + devp->ssr_name); + devp->in_reset = false; + } + return NOTIFY_DONE; +} + +/** + * qiib_poll() - poll() syscall for the qiib device + * @file: Pointer to the file structure. + * @wait: pointer to Poll table. + * + * This function is used to poll on the qiib device when + * userspace client do a poll() system call. All input arguments are + * validated by the virtual file system before calling this function. + * + * Return: POLLIN for interrupt intercepted case and POLLRDHUP for SSR. + */ +static unsigned int qiib_poll(struct file *file, poll_table *wait) +{ + struct qiib_dev *devp = file->private_data; + unsigned int mask = 0; + unsigned long flags; + + if (!devp) { + QIIB_ERR("%s on NULL device\n", __func__); + return POLLERR; + } + + if (devp->in_reset) + return POLLRDHUP; + + poll_wait(file, &devp->poll_wait_queue, wait); + spin_lock_irqsave(&devp->irq_pending_count_lock, flags); + if (devp->irq_pending_count) { + mask |= POLLIN; + QIIB_DBG("%s set POLLIN on [%s] count[%d]\n", + __func__, devp->dev_name, + devp->irq_pending_count); + devp->irq_pending_count = 0; + } + spin_unlock_irqrestore(&devp->irq_pending_count_lock, flags); + + if (devp->in_reset) { + mask |= POLLRDHUP; + QIIB_DBG("%s set POLLRDHUP on [%s] count[%d]\n", + __func__, devp->dev_name, + devp->irq_pending_count); + } + return mask; +} + +/** + * qiib_open() - open() syscall for the qiib device + * @inode: Pointer to the inode structure. + * @file: Pointer to the file structure. + * + * This function is used to open the qiib device when + * userspace client do a open() system call. All input arguments are + * validated by the virtual file system before calling this function. + * + * Return: 0 for success, Standard Linux errors + */ +static int qiib_open(struct inode *inode, struct file *file) +{ + struct qiib_dev *devp = NULL; + + devp = container_of(inode->i_cdev, struct qiib_dev, cdev); + if (!devp) { + QIIB_ERR("%s on NULL device\n", __func__); + return -EINVAL; + } + file->private_data = devp; + QIIB_DBG("%s on [%s]\n", __func__, devp->dev_name); + return 0; +} + +/** + * qiib_release() - release operation on qiibdevice + * @inode: Pointer to the inode structure. + * @file: Pointer to the file structure. + * + * This function is used to release the qiib device when + * userspace client do a close() system call. All input arguments are + * validated by the virtual file system before calling this function. + */ +static int qiib_release(struct inode *inode, struct file *file) +{ + struct qiib_dev *devp = file->private_data; + + if (!devp) { + QIIB_ERR("%s on NULL device\n", __func__); + return -EINVAL; + } + + QIIB_DBG("%s on [%s]\n", __func__, devp->dev_name); + return 0; +} + +static const struct file_operations qiib_fops = { + .owner = THIS_MODULE, + .open = qiib_open, + .release = qiib_release, + .poll = qiib_poll, +}; + +/** + * qiib_add_device() - Initialize qiib device and add cdev + * @devp: pointer to the qiib device. + * @i: index of the qiib device. + * + * Return: 0 for success, Standard Linux errors + */ +static int qiib_add_device(struct qiib_dev *devp, int i) +{ + int ret = 0; + + devp->i = i; + init_waitqueue_head(&devp->poll_wait_queue); + spin_lock_init(&devp->irq_pending_count_lock); + + cdev_init(&devp->cdev, &qiib_fops); + devp->cdev.owner = THIS_MODULE; + + ret = cdev_add(&devp->cdev, qiib_info->dev_num + i, 1); + if (IS_ERR_VALUE((unsigned long)ret)) { + QIIB_ERR("%s: cdev_add() failed for dev [%s] ret:%i\n", + __func__, devp->dev_name, ret); + return ret; + } + + devp->devicep = device_create(qiib_info->classp, + NULL, + (qiib_info->dev_num + i), + NULL, + devp->dev_name); + + if (IS_ERR_OR_NULL(devp->devicep)) { + QIIB_ERR("%s: device_create() failed for dev [%s]\n", + __func__, devp->dev_name); + ret = -ENOMEM; + cdev_del(&devp->cdev); + return ret; + } + + mutex_lock(&qiib_info->list_lock); + list_add(&devp->dev_list, &qiib_info->list); + mutex_unlock(&qiib_info->list_lock); + + return ret; +} + +static irqreturn_t qiib_irq_handler(int irq, void *priv) +{ + struct qiib_dev *devp = priv; + unsigned long flags; + + spin_lock_irqsave(&devp->irq_pending_count_lock, flags); + devp->irq_pending_count++; + spin_unlock_irqrestore(&devp->irq_pending_count_lock, flags); + wake_up_interruptible(&devp->poll_wait_queue); + + if (devp->rx_irq_reset_reg) + writel_relaxed(devp->irq_mask, devp->rx_irq_reset_reg); + + QIIB_DBG("%s name[%s] pend_count[%d]\n", __func__, + devp->dev_name, devp->irq_pending_count); + + return IRQ_HANDLED; +} + +/** + * qiib_parse_node() - parse node from device tree binding + * @node: pointer to device tree node + * @devp: pointer to the qiib device + * + * Return: 0 on success, -ENODEV on failure. + */ +static int qiib_parse_node(struct device_node *node, struct qiib_dev *devp) +{ + char *key; + const char *subsys_name; + const char *dev_name; + uint32_t irqtype; + uint32_t irq_clear[2]; + struct irq_data *irqtype_data; + int ret = -ENODEV; + + key = "qcom,dev-name"; + ret = of_property_read_string(node, key, &dev_name); + if (ret) { + QIIB_ERR("%s: missing key: %s\n", __func__, key); + goto missing_key; + } + QIIB_DBG("%s: %s = %s\n", __func__, key, dev_name); + + key = "interrupts"; + devp->irq_line = irq_of_parse_and_map(node, 0); + if (!devp->irq_line) { + QIIB_ERR("%s: missing key: %s\n", __func__, key); + goto missing_key; + } + QIIB_DBG("%s: %s = %d\n", __func__, key, devp->irq_line); + + irqtype_data = irq_get_irq_data(devp->irq_line); + if (!irqtype_data) { + QIIB_ERR("%s: get irqdata fail:%d\n", __func__, devp->irq_line); + goto missing_key; + } + irqtype = irqd_get_trigger_type(irqtype_data); + QIIB_DBG("%s: irqtype = %d\n", __func__, irqtype); + + key = "label"; + ret = of_property_read_string(node, key, &subsys_name); + if (ret) { + QIIB_ERR("%s: missing key: %s\n", __func__, key); + goto missing_key; + } + QIIB_DBG("%s: %s = %s\n", __func__, key, subsys_name); + + if (irqtype & IRQF_TRIGGER_HIGH) { + key = "qcom,rx-irq-clr-mask"; + ret = of_property_read_u32(node, key, &devp->irq_mask); + if (ret) { + QIIB_ERR("%s: missing key: %s\n", __func__, key); + ret = -ENODEV; + goto missing_key; + } + QIIB_DBG("%s: %s = %d\n", __func__, key, devp->irq_mask); + + key = "qcom,rx-irq-clr"; + ret = of_property_read_u32_array(node, key, irq_clear, + ARRAY_SIZE(irq_clear)); + if (ret) { + QIIB_ERR("%s: missing key: %s\n", __func__, key); + ret = -ENODEV; + goto missing_key; + } + + devp->rx_irq_reset_reg = ioremap_nocache(irq_clear[0], + irq_clear[1]); + if (!devp->rx_irq_reset_reg) { + QIIB_ERR("%s: unable to map rx reset reg\n", __func__); + ret = -ENOMEM; + goto missing_key; + } + } + + devp->dev_name = dev_name; + devp->ssr_name = subsys_name; + devp->nb.notifier_call = qiib_restart_notifier_cb; + + devp->notifier_handle = subsys_notif_register_notifier(devp->ssr_name, + &devp->nb); + if (IS_ERR_OR_NULL(devp->notifier_handle)) { + QIIB_ERR("%s: Could not register SSR notifier cb\n", __func__); + ret = -EINVAL; + goto ssr_reg_fail; + } + + ret = request_irq(devp->irq_line, qiib_irq_handler, irqtype, + devp->dev_name, devp); + if (ret < 0) { + QIIB_ERR("%s: request_irq() failed on %d\n", __func__, + devp->irq_line); + goto req_irq_fail; + } + + return ret; + +req_irq_fail: + subsys_notif_unregister_notifier(devp->notifier_handle, &devp->nb); +ssr_reg_fail: + if (devp->rx_irq_reset_reg) { + iounmap(devp->rx_irq_reset_reg); + devp->rx_irq_reset_reg = NULL; + } +missing_key: + return ret; +} + +/** + * qiib_cleanup - cleanup all the resources + * + * This function remove all the memory and unregister + * the char device region. + */ +static void qiib_cleanup(void) +{ + struct qiib_dev *devp; + struct qiib_dev *index; + + mutex_lock(&qiib_info->list_lock); + list_for_each_entry_safe(devp, index, &qiib_info->list, dev_list) { + cdev_del(&devp->cdev); + list_del(&devp->dev_list); + device_destroy(qiib_info->classp, + MKDEV(MAJOR(qiib_info->dev_num), devp->i)); + if (devp->notifier_handle) + subsys_notif_unregister_notifier(devp->notifier_handle, + &devp->nb); + kfree(devp); + } + mutex_unlock(&qiib_info->list_lock); + + if (!IS_ERR_OR_NULL(qiib_info->classp)) + class_destroy(qiib_info->classp); + + unregister_chrdev_region(MAJOR(qiib_info->dev_num), qiib_info->nports); +} + +/** + * qiib_alloc_chrdev_region() - allocate the char device region + * + * This function allocate memory for qiib character-device region and + * create the class. + */ +static int qiib_alloc_chrdev_region(void) +{ + int ret; + + ret = alloc_chrdev_region(&qiib_info->dev_num, + 0, + qiib_info->nports, + DEVICE_NAME); + if (IS_ERR_VALUE((unsigned long)ret)) { + QIIB_ERR("%s: alloc_chrdev_region() failed ret:%i\n", + __func__, ret); + return ret; + } + + qiib_info->classp = class_create(THIS_MODULE, DEVICE_NAME); + if (IS_ERR(qiib_info->classp)) { + QIIB_ERR("%s: class_create() failed ENOMEM\n", __func__); + ret = -ENOMEM; + unregister_chrdev_region(MAJOR(qiib_info->dev_num), + qiib_info->nports); + return ret; + } + + return 0; +} + +static int qsee_ipc_irq_bridge_probe(struct platform_device *pdev) +{ + int ret; + struct device_node *node; + struct qiib_dev *devp; + int i = 0; + + qiib_info->nports = of_get_available_child_count(pdev->dev.of_node); + if (!qiib_info->nports) { + QIIB_ERR("%s:Fail nports = %d\n", __func__, qiib_info->nports); + return -EINVAL; + } + + ret = qiib_alloc_chrdev_region(); + if (ret) { + QIIB_ERR("%s: chrdev_region allocation failed ret:%i\n", + __func__, ret); + return ret; + } + + for_each_available_child_of_node(pdev->dev.of_node, node) { + devp = kzalloc(sizeof(*devp), GFP_KERNEL); + if (IS_ERR_OR_NULL(devp)) { + QIIB_ERR("%s:Allocation failed id:%d\n", __func__, i); + ret = -ENOMEM; + goto error; + } + + ret = qiib_parse_node(node, devp); + if (ret) { + QIIB_ERR("%s:qiib_parse_node failed %d\n", __func__, i); + kfree(devp); + goto error; + } + + ret = qiib_add_device(devp, i); + if (ret < 0) { + QIIB_ERR("%s: add [%s] device failed ret=%d\n", + __func__, devp->dev_name, ret); + kfree(devp); + goto error; + } + i++; + } + + QIIB_DBG("%s: Driver Initialized.\n", __func__); + return 0; + +error: + qiib_cleanup(); + return ret; +} + +static int qsee_ipc_irq_bridge_remove(struct platform_device *pdev) +{ + qiib_cleanup(); + return 0; +} + +static const struct of_device_id qsee_ipc_irq_bridge_match_table[] = { + { .compatible = "qcom,qsee-ipc-irq-bridge" }, + {}, +}; + +static struct platform_driver qsee_ipc_irq_bridge_driver = { + .probe = qsee_ipc_irq_bridge_probe, + .remove = qsee_ipc_irq_bridge_remove, + .driver = { + .name = MODULE_NAME, + .owner = THIS_MODULE, + .of_match_table = qsee_ipc_irq_bridge_match_table, + }, +}; + +static int __init qsee_ipc_irq_bridge_init(void) +{ + int ret; + + ret = qiib_driver_data_init(); + if (ret) { + QIIB_ERR("%s: driver data init failed %d\n", + __func__, ret); + return ret; + } + + ret = platform_driver_register(&qsee_ipc_irq_bridge_driver); + if (ret) { + QIIB_ERR("%s: platform driver register failed %d\n", + __func__, ret); + return ret; + } + + return 0; +} +module_init(qsee_ipc_irq_bridge_init); + +static void __exit qsee_ipc_irq_bridge_exit(void) +{ + platform_driver_unregister(&qsee_ipc_irq_bridge_driver); + qiib_driver_data_deinit(); +} +module_exit(qsee_ipc_irq_bridge_exit); +MODULE_DESCRIPTION("QSEE IPC interrupt bridge"); +MODULE_LICENSE("GPL v2"); -- GitLab From 020f4b68be88b92c682bac1bf04cc5c39bc1ab61 Mon Sep 17 00:00:00 2001 From: Chris Lew Date: Fri, 6 Apr 2018 18:21:57 -0700 Subject: [PATCH 0335/1635] ARM: dts: msm: Add qsee_ipc_irq_bridge nodes for SM8150 The qsee_ipc_irq_bridge bridges interrupt notifications to userspace by creating a char dev for userspace to poll until an interrupt from QSEE arrives. Change-Id: I2b4150428d59ce4edd038de11a59b36f5f78e958 Signed-off-by: Chris Lew --- arch/arm64/boot/dts/qcom/sm8150.dtsi | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sm8150.dtsi b/arch/arm64/boot/dts/qcom/sm8150.dtsi index 83a1162ce498..80054fc04c1c 100644 --- a/arch/arm64/boot/dts/qcom/sm8150.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150.dtsi @@ -2279,6 +2279,17 @@ #interrupt-cells = <3>; }; + qcom,qsee_irq_bridge { + compatible = "qcom,qsee-ipc-irq-bridge"; + + qcom,qsee-ipc-irq-spss { + qcom,dev-name = "qsee_ipc_irq_spss"; + label = "spss"; + interrupt-parent = <&intsp>; + interrupts = <1 0 IRQ_TYPE_EDGE_RISING>; + }; + }; + qcom,glink { compatible = "qcom,glink"; #address-cells = <1>; -- GitLab From 234e3fc6d551154d9306658289bdd7c3cf1fb8aa Mon Sep 17 00:00:00 2001 From: Chris Lew Date: Sun, 8 Apr 2018 15:07:22 -0700 Subject: [PATCH 0336/1635] defconfig: SM8105: Enable QSEE IPC IRQ bridge The QSEE IPC IRQ bridge forwards interrupts from QSEE to userspace by writing to a char device node. Change-Id: Ib538a19ac8d8d83cf0383bec8bfe3fa899d9a885 Signed-off-by: Chris Lew --- arch/arm64/configs/sm8150-perf_defconfig | 1 + arch/arm64/configs/sm8150_defconfig | 1 + 2 files changed, 2 insertions(+) diff --git a/arch/arm64/configs/sm8150-perf_defconfig b/arch/arm64/configs/sm8150-perf_defconfig index bc97892cb5a8..790e46e3ea54 100644 --- a/arch/arm64/configs/sm8150-perf_defconfig +++ b/arch/arm64/configs/sm8150-perf_defconfig @@ -500,6 +500,7 @@ CONFIG_QCOM_BUS_CONFIG_RPMH=y CONFIG_QCOM_COMMAND_DB=y CONFIG_QCOM_EARLY_RANDOM=y CONFIG_QTI_RPMH_API=y +CONFIG_QSEE_IPC_IRQ_BRIDGE=y CONFIG_QCOM_GLINK=y CONFIG_QCOM_GLINK_PKT=y CONFIG_MSM_CDSP_LOADER=y diff --git a/arch/arm64/configs/sm8150_defconfig b/arch/arm64/configs/sm8150_defconfig index bc24ba3e0a63..1ba01f1cc4dd 100644 --- a/arch/arm64/configs/sm8150_defconfig +++ b/arch/arm64/configs/sm8150_defconfig @@ -521,6 +521,7 @@ CONFIG_QCOM_COMMAND_DB=y CONFIG_QCOM_EARLY_RANDOM=y CONFIG_MSM_SPSS_UTILS=y CONFIG_QTI_RPMH_API=y +CONFIG_QSEE_IPC_IRQ_BRIDGE=y CONFIG_QCOM_GLINK=y CONFIG_QCOM_GLINK_PKT=y CONFIG_MSM_CDSP_LOADER=y -- GitLab From 4fc64a8ee5471365b370b4e2ea8307e8165db4e3 Mon Sep 17 00:00:00 2001 From: Sujeev Dias Date: Wed, 28 Mar 2018 16:55:32 -0700 Subject: [PATCH 0337/1635] trace: ipc_logging: check for existing ipclog ctxt before creating new one Many ipc logging clients does a complete driver reinitialization during shutdown or ssr process. However, these clients prefer to continue use same logging buffer instead of creating a new buffer. So, check if a ipc logging context already exist, if so return the same context instead of creating a new one. CRs-Fixed: 2214790 Change-Id: Ic0508a0dbf2afbdb1c5d7655c7a79a9bfa01f5a2 Signed-off-by: Sujeev Dias --- kernel/trace/ipc_logging.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/kernel/trace/ipc_logging.c b/kernel/trace/ipc_logging.c index 445f473591fb..fb84c6c9b28e 100644 --- a/kernel/trace/ipc_logging.c +++ b/kernel/trace/ipc_logging.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -790,7 +790,7 @@ static void *get_deserialization_func(struct ipc_log_context *ilctxt, } /** - * ipc_log_context_create: Create a debug log context + * ipc_log_context_create: Create a debug log context if context does not exist. * Should not be called from atomic context * * @max_num_pages: Number of pages of logging space required (max. 10) @@ -802,11 +802,23 @@ static void *get_deserialization_func(struct ipc_log_context *ilctxt, void *ipc_log_context_create(int max_num_pages, const char *mod_name, uint16_t user_version) { - struct ipc_log_context *ctxt; + struct ipc_log_context *ctxt = NULL, *tmp; struct ipc_log_page *pg = NULL; int page_cnt; unsigned long flags; + /* check if ipc ctxt already exists */ + read_lock_irq(&context_list_lock_lha1); + list_for_each_entry(tmp, &ipc_log_context_list, list) + if (!strcmp(tmp->name, mod_name)) { + ctxt = tmp; + break; + } + read_unlock_irq(&context_list_lock_lha1); + + if (ctxt) + return ctxt; + ctxt = kzalloc(sizeof(struct ipc_log_context), GFP_KERNEL); if (!ctxt) return 0; -- GitLab From a85b03ba84798bcd42442997d114c28cf039c806 Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Tue, 27 Mar 2018 14:06:42 -0700 Subject: [PATCH 0338/1635] rpmsg: Only invoke announce_create for rpdev with endpoints For special rpmsg devices without a primary endpoint there is nothing to announce so don't call the backend announce create function if we didn't create an endpoint. Change-Id: I42adaa317e408b73061f1c3d392699bec36b193e Signed-off-by: Bjorn Andersson Patch-mainline: linux-arm-msm @ 27/03/2018, 23:07 Signed-off-by: Chris Lew --- drivers/rpmsg/rpmsg_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/rpmsg/rpmsg_core.c b/drivers/rpmsg/rpmsg_core.c index 1b4bc4442083..48913f2a2775 100644 --- a/drivers/rpmsg/rpmsg_core.c +++ b/drivers/rpmsg/rpmsg_core.c @@ -483,7 +483,7 @@ static int rpmsg_dev_probe(struct device *dev) goto out; } - if (rpdev->ops->announce_create) + if (ept && rpdev->ops->announce_create) err = rpdev->ops->announce_create(rpdev); out: return err; -- GitLab From 647f1771fdd39516d2025a7f42cb3fe4248f75dc Mon Sep 17 00:00:00 2001 From: Chris Lew Date: Wed, 11 Apr 2018 18:15:08 -0700 Subject: [PATCH 0339/1635] rpmsg: glink: Put an extra reference during cleanup In a remote processor crash scenario, there is no guarantee the remote processor sent close requests before it went into a bad state. Remove the reference that is normally handled by the close command in the so channel resources can be released. Change-Id: I02980914bfb587990c3277a945193fb89e76c504 Signed-off-by: Chris Lew --- drivers/rpmsg/qcom_glink_native.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/rpmsg/qcom_glink_native.c b/drivers/rpmsg/qcom_glink_native.c index 86863eaf0237..b9e24b030881 100644 --- a/drivers/rpmsg/qcom_glink_native.c +++ b/drivers/rpmsg/qcom_glink_native.c @@ -1845,6 +1845,10 @@ void qcom_glink_native_remove(struct qcom_glink *glink) idr_for_each_entry(&glink->lcids, channel, cid) kref_put(&channel->refcount, qcom_glink_channel_release); + /* Release any defunct local channels, waiting for close-req */ + idr_for_each_entry(&glink->lcids, channel, cid) + kref_put(&channel->refcount, qcom_glink_channel_release); + idr_destroy(&glink->lcids); idr_destroy(&glink->rcids); spin_unlock_irqrestore(&glink->idr_lock, flags); -- GitLab From 5774dd4e276b17d7ad05c1029dacde29f87fe0d7 Mon Sep 17 00:00:00 2001 From: Ram Chandrasekar Date: Wed, 4 Apr 2018 12:40:59 -0600 Subject: [PATCH 0340/1635] drivers: thermal: lmh-dcvsh: Add multiple clock plan support A single LMH DCVSh hardware can mitigate CPUs with different clock plan operating in a single voltage rail. Add support in LMH DCVSh driver to treat individual CPU to have different clock plan. Hence all the throttling frequencies are compared against each individual CPUs. Change-Id: I566985a45007bf6939fa315a9471bbba4e5df7de Signed-off-by: Ram Chandrasekar --- drivers/thermal/qcom/msm_lmh_dcvs.c | 125 ++++++++++++++++------------ 1 file changed, 73 insertions(+), 52 deletions(-) diff --git a/drivers/thermal/qcom/msm_lmh_dcvs.c b/drivers/thermal/qcom/msm_lmh_dcvs.c index 267d27906d1a..f7dfee3a8b7a 100644 --- a/drivers/thermal/qcom/msm_lmh_dcvs.c +++ b/drivers/thermal/qcom/msm_lmh_dcvs.c @@ -89,8 +89,8 @@ struct limits_dcvs_hw { void *min_freq_reg; cpumask_t core_map; struct delayed_work freq_poll_work; - unsigned long max_freq; - unsigned long min_freq; + unsigned long max_freq[NR_CPUS]; + unsigned long min_freq[NR_CPUS]; unsigned long hw_freq_limit; struct device_attribute lmh_freq_attr; struct list_head list; @@ -106,63 +106,80 @@ struct limits_dcvs_hw { LIST_HEAD(lmh_dcvs_hw_list); DEFINE_MUTEX(lmh_dcvs_list_access); -static int limits_dcvs_get_freq_limits(uint32_t cpu, unsigned long *max_freq, - unsigned long *min_freq) +static void limits_dcvs_get_freq_limits(struct limits_dcvs_hw *hw) { unsigned long freq_ceil = UINT_MAX, freq_floor = 0; struct device *cpu_dev = NULL; - int ret = 0; - - cpu_dev = get_cpu_device(cpu); - if (!cpu_dev) { - pr_err("Error in get CPU%d device\n", cpu); - return -ENODEV; - } + uint32_t cpu, idx = 0; - dev_pm_opp_find_freq_floor(cpu_dev, &freq_ceil); - dev_pm_opp_find_freq_ceil(cpu_dev, &freq_floor); + for_each_cpu(cpu, &hw->core_map) { + freq_ceil = UINT_MAX; + freq_floor = 0; + cpu_dev = get_cpu_device(cpu); + if (!cpu_dev) { + pr_err("Error in get CPU%d device\n", cpu); + idx++; + continue; + } - *max_freq = freq_ceil / 1000; - *min_freq = freq_floor / 1000; + dev_pm_opp_find_freq_floor(cpu_dev, &freq_ceil); + dev_pm_opp_find_freq_ceil(cpu_dev, &freq_floor); - return ret; + hw->max_freq[idx] = freq_ceil / 1000; + hw->min_freq[idx] = freq_floor / 1000; + idx++; + } } static unsigned long limits_mitigation_notify(struct limits_dcvs_hw *hw) { - uint32_t val = 0; + uint32_t val = 0, max_cpu_ct = 0, max_cpu_limit = 0, idx = 0, cpu = 0; struct device *cpu_dev = NULL; unsigned long freq_val, max_limit = 0; struct dev_pm_opp *opp_entry; val = readl_relaxed(hw->osm_hw_reg); dcvsh_get_frequency(val, max_limit); - cpu_dev = get_cpu_device(cpumask_first(&hw->core_map)); - if (!cpu_dev) { - pr_err("Error in get CPU%d device\n", - cpumask_first(&hw->core_map)); - goto notify_exit; - } + for_each_cpu(cpu, &hw->core_map) { + cpu_dev = get_cpu_device(cpu); + if (!cpu_dev) { + pr_err("Error in get CPU%d device\n", + cpumask_first(&hw->core_map)); + goto notify_exit; + } - pr_debug("CPU:%d max value read:%lu\n", + pr_debug("CPU:%d max value read:%lu\n", cpumask_first(&hw->core_map), max_limit); - freq_val = FREQ_KHZ_TO_HZ(max_limit); - opp_entry = dev_pm_opp_find_freq_floor(cpu_dev, &freq_val); - /* - * Hardware mitigation frequency can be lower than the lowest - * possible CPU frequency. In that case freq floor call will - * fail with -ERANGE and we need to match to the lowest - * frequency using freq_ceil. - */ - if (IS_ERR(opp_entry) && PTR_ERR(opp_entry) == -ERANGE) { - opp_entry = dev_pm_opp_find_freq_ceil(cpu_dev, &freq_val); - if (IS_ERR(opp_entry)) - dev_err(cpu_dev, "frequency:%lu. opp error:%ld\n", + freq_val = FREQ_KHZ_TO_HZ(max_limit); + opp_entry = dev_pm_opp_find_freq_floor(cpu_dev, &freq_val); + /* + * Hardware mitigation frequency can be lower than the lowest + * possible CPU frequency. In that case freq floor call will + * fail with -ERANGE and we need to match to the lowest + * frequency using freq_ceil. + */ + if (IS_ERR(opp_entry) && PTR_ERR(opp_entry) == -ERANGE) { + opp_entry = dev_pm_opp_find_freq_ceil(cpu_dev, + &freq_val); + if (IS_ERR(opp_entry)) + dev_err(cpu_dev, + "frequency:%lu. opp error:%ld\n", freq_val, PTR_ERR(opp_entry)); + } + if (FREQ_HZ_TO_KHZ(freq_val) == hw->max_freq[idx]) { + max_cpu_ct++; + if (max_cpu_limit < hw->max_freq[idx]) + max_cpu_limit = hw->max_freq[idx]; + idx++; + continue; + } + max_limit = FREQ_HZ_TO_KHZ(freq_val); + break; } - max_limit = FREQ_HZ_TO_KHZ(freq_val); + if (max_cpu_ct == cpumask_weight(&hw->core_map)) + max_limit = max_cpu_limit; sched_update_cpu_freq_min_max(&hw->core_map, 0, max_limit); pr_debug("CPU:%d max limit:%lu\n", cpumask_first(&hw->core_map), max_limit); @@ -179,13 +196,18 @@ static void limits_dcvs_poll(struct work_struct *work) struct limits_dcvs_hw *hw = container_of(work, struct limits_dcvs_hw, freq_poll_work.work); + int cpu_ct = 0, cpu = 0, idx = 0; mutex_lock(&hw->access_lock); - if (hw->max_freq == U32_MAX) - limits_dcvs_get_freq_limits(cpumask_first(&hw->core_map), - &hw->max_freq, &hw->min_freq); + if (hw->max_freq[0] == U32_MAX) + limits_dcvs_get_freq_limits(hw); max_limit = limits_mitigation_notify(hw); - if (max_limit >= hw->max_freq) { + for_each_cpu(cpu, &hw->core_map) { + if (max_limit >= hw->max_freq[idx]) + cpu_ct++; + idx++; + } + if (cpu_ct >= cpumask_weight(&hw->core_map)) { writel_relaxed(0xFF, hw->int_clr_reg); hw->is_irq_enabled = true; enable_irq(hw->irq_num); @@ -343,7 +365,7 @@ static int lmh_set_max_limit(int cpu, u32 freq) * the CPU to use the boost frequencies. */ hw->cdev_data[idx].max_freq = - (freq == hw->max_freq) ? U32_MAX : freq; + (freq == hw->max_freq[idx]) ? U32_MAX : freq; if (max_freq > hw->cdev_data[idx].max_freq) max_freq = hw->cdev_data[idx].max_freq; idx++; @@ -360,8 +382,7 @@ static int lmh_set_max_limit(int cpu, u32 freq) static int lmh_set_min_limit(int cpu, u32 freq) { struct limits_dcvs_hw *hw = get_dcvsh_hw_from_cpu(cpu); - int cpu_idx, idx = 0; - u32 min_freq = 0; + int cpu_idx, idx = 0, cpu_ct = 0; if (!hw) return -EINVAL; @@ -370,11 +391,11 @@ static int lmh_set_min_limit(int cpu, u32 freq) for_each_cpu(cpu_idx, &hw->core_map) { if (cpu_idx == cpu) hw->cdev_data[idx].min_freq = freq; - if (min_freq < hw->cdev_data[idx].min_freq) - min_freq = hw->cdev_data[idx].min_freq; + if (hw->cdev_data[idx].min_freq <= hw->min_freq[idx]) + cpu_ct++; idx++; } - if (min_freq != hw->min_freq) + if (cpu_ct < cpumask_weight(&hw->core_map)) writel_relaxed(0x01, hw->min_freq_reg); else writel_relaxed(0x00, hw->min_freq_reg); @@ -394,9 +415,8 @@ static void register_cooling_device(struct work_struct *work) unsigned int cpu = 0, idx = 0; mutex_lock(&hw->cdev_reg_lock); - if (hw->max_freq == U32_MAX) - limits_dcvs_get_freq_limits(cpumask_first(&hw->core_map), - &hw->max_freq, &hw->min_freq); + if (hw->max_freq[0] == U32_MAX) + limits_dcvs_get_freq_limits(hw); for_each_cpu(cpu, &hw->core_map) { cpumask_t cpu_mask = { CPU_BITS_NONE }; @@ -547,6 +567,8 @@ static int limits_dcvs_probe(struct platform_device *pdev) hw->cdev_data[idx].cdev = NULL; hw->cdev_data[idx].max_freq = U32_MAX; hw->cdev_data[idx].min_freq = 0; + hw->max_freq[idx] = U32_MAX; + hw->min_freq[idx] = 0; idx++; } ret = of_property_read_u32(dn, "qcom,affinity", &affinity); @@ -586,8 +608,7 @@ static int limits_dcvs_probe(struct platform_device *pdev) */ hw->temp_limits[LIMITS_TRIP_HI] = INT_MAX; hw->temp_limits[LIMITS_TRIP_ARM] = 0; - hw->hw_freq_limit = hw->max_freq = U32_MAX; - hw->min_freq = 0; + hw->hw_freq_limit = U32_MAX; snprintf(hw->sensor_name, sizeof(hw->sensor_name), "limits_sensor-%02d", affinity); tzdev = thermal_zone_of_sensor_register(&pdev->dev, 0, hw, -- GitLab From 2f994ded4e87a6ee0950fb5d78c6913d00d3e972 Mon Sep 17 00:00:00 2001 From: Ram Chandrasekar Date: Mon, 9 Apr 2018 14:20:56 -0600 Subject: [PATCH 0341/1635] ARM: dts: msm: Add a test thermal zone for SM8150 Add a sample thermal zone, which mitigates the cooling devices like modem and display backlight for SM8150. This is a sample thermal zone, which will be disabled by default. Change-Id: I866b4c0c0b981960f9579501597d81cf258cd55f Signed-off-by: Ram Chandrasekar --- arch/arm64/boot/dts/qcom/sm8150-thermal.dtsi | 47 ++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sm8150-thermal.dtsi b/arch/arm64/boot/dts/qcom/sm8150-thermal.dtsi index 43cd31adfaaa..f1f86faaa635 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-thermal.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-thermal.dtsi @@ -2197,4 +2197,51 @@ }; }; }; + + pop-mem-test { + polling-delay-passive = <10>; + polling-delay = <0>; + thermal-sensors = <&tsens1 3>; + thermal-governor = "step_wise"; + disable-thermal-zone; + trips { + pop_test_trip: pop-test-trip { + temperature = <95000>; + hysteresis = <0>; + type = "passive"; + }; + }; + cooling-maps { + pop_test_cdev0 { + trip = <&pop_test_trip>; + cooling-device = + <&modem_pa THERMAL_NO_LIMIT + THERMAL_NO_LIMIT>; + }; + pop_test_cdev1 { + trip = <&pop_test_trip>; + cooling-device = + <&modem_proc THERMAL_NO_LIMIT + THERMAL_NO_LIMIT>; + }; + pop_test_cdev2 { + trip = <&pop_test_trip>; + cooling-device = + <&modem_current THERMAL_NO_LIMIT + THERMAL_NO_LIMIT>; + }; + pop_test_cdev3 { + trip = <&pop_test_trip>; + cooling-device = + <&modem_skin THERMAL_NO_LIMIT + THERMAL_NO_LIMIT>; + }; + pop_test_cdev4 { + trip = <&pop_test_trip>; + cooling-device = + <&mdss_mdp THERMAL_NO_LIMIT + THERMAL_NO_LIMIT>; + }; + }; + }; }; -- GitLab From 2656dad6cfadd6eab8830330910698ac7de94f66 Mon Sep 17 00:00:00 2001 From: Ram Chandrasekar Date: Mon, 9 Apr 2018 13:57:20 -0600 Subject: [PATCH 0342/1635] drivers: thermal: lmh-dcvs: Register the cooling device in order The CPU cooling device registration is scheduled for later execution during probe. Due to this, the CPU cooling devices are not created in the same order as CPU logical numbers. This could result in unexpected behavior for thermal-engine. Modify the driver to acquire a lock and ensure that the cooling devices are always registered in the same order as CPU logical numbers. Change-Id: I67dbfa8e386480fc437425386855faf2f6ebdd5d Signed-off-by: Ram Chandrasekar --- drivers/thermal/qcom/msm_lmh_dcvs.c | 68 +++++++++++++++-------------- 1 file changed, 35 insertions(+), 33 deletions(-) diff --git a/drivers/thermal/qcom/msm_lmh_dcvs.c b/drivers/thermal/qcom/msm_lmh_dcvs.c index f7dfee3a8b7a..68d374b5c255 100644 --- a/drivers/thermal/qcom/msm_lmh_dcvs.c +++ b/drivers/thermal/qcom/msm_lmh_dcvs.c @@ -88,6 +88,7 @@ struct limits_dcvs_hw { void *int_clr_reg; void *min_freq_reg; cpumask_t core_map; + cpumask_t online_mask; struct delayed_work freq_poll_work; unsigned long max_freq[NR_CPUS]; unsigned long min_freq[NR_CPUS]; @@ -96,7 +97,6 @@ struct limits_dcvs_hw { struct list_head list; bool is_irq_enabled; struct mutex access_lock; - struct mutex cdev_reg_lock; struct __limits_cdev_data *cdev_data; uint32_t cdev_registered; struct regulator *isens_reg[2]; @@ -335,14 +335,10 @@ static struct limits_dcvs_hw *get_dcvsh_hw_from_cpu(int cpu) { struct limits_dcvs_hw *hw; - mutex_lock(&lmh_dcvs_list_access); list_for_each_entry(hw, &lmh_dcvs_hw_list, list) { - if (cpumask_test_cpu(cpu, &hw->core_map)) { - mutex_unlock(&lmh_dcvs_list_access); + if (cpumask_test_cpu(cpu, &hw->core_map)) return hw; - } } - mutex_unlock(&lmh_dcvs_list_access); return NULL; } @@ -410,37 +406,42 @@ static struct cpu_cooling_ops cd_ops = { static void register_cooling_device(struct work_struct *work) { - struct limits_dcvs_hw *hw = container_of(work, struct limits_dcvs_hw, - cdev_register_work); + struct limits_dcvs_hw *hw; unsigned int cpu = 0, idx = 0; - mutex_lock(&hw->cdev_reg_lock); - if (hw->max_freq[0] == U32_MAX) - limits_dcvs_get_freq_limits(hw); - - for_each_cpu(cpu, &hw->core_map) { - cpumask_t cpu_mask = { CPU_BITS_NONE }; + mutex_lock(&lmh_dcvs_list_access); + list_for_each_entry(hw, &lmh_dcvs_hw_list, list) { + if (hw->max_freq[0] == U32_MAX) + limits_dcvs_get_freq_limits(hw); - if (hw->cdev_data[idx].cdev) { - idx++; + if (cpumask_weight(&hw->online_mask) == 0) continue; + idx = 0; + for_each_cpu(cpu, &hw->core_map) { + cpumask_t cpu_mask = { CPU_BITS_NONE }; + + if (hw->cdev_data[idx].cdev) { + idx++; + continue; + } + cpumask_set_cpu(cpu, &cpu_mask); + hw->cdev_data[idx].max_freq = U32_MAX; + hw->cdev_data[idx].min_freq = 0; + hw->cdev_data[idx].cdev = + cpufreq_platform_cooling_register( + &cpu_mask, &cd_ops); + if (IS_ERR_OR_NULL(hw->cdev_data[idx].cdev)) { + pr_err("CPU:%u cdev register error:%ld\n", + cpu, PTR_ERR(hw->cdev_data[idx].cdev)); + hw->cdev_data[idx].cdev = NULL; + } else { + pr_debug("CPU:%u cdev registered\n", cpu); + hw->cdev_registered++; + } + idx++; } - cpumask_set_cpu(cpu, &cpu_mask); - hw->cdev_data[idx].max_freq = U32_MAX; - hw->cdev_data[idx].min_freq = 0; - hw->cdev_data[idx].cdev = cpufreq_platform_cooling_register( - &cpu_mask, &cd_ops); - if (IS_ERR_OR_NULL(hw->cdev_data[idx].cdev)) { - pr_err("CPU:%u cooling device register error:%ld\n", - cpu, PTR_ERR(hw->cdev_data[idx].cdev)); - hw->cdev_data[idx].cdev = NULL; - } else { - pr_debug("CPU:%u cooling device registered\n", cpu); - hw->cdev_registered++; - } - idx++; } - mutex_unlock(&hw->cdev_reg_lock); + mutex_unlock(&lmh_dcvs_list_access); } static int limits_cpu_online(unsigned int online_cpu) @@ -449,6 +450,7 @@ static int limits_cpu_online(unsigned int online_cpu) if (!hw) return 0; + cpumask_set_cpu(online_cpu, &hw->online_mask); if (hw->cdev_registered != cpumask_weight(&hw->core_map)) queue_work(system_highpri_wq, &hw->cdev_register_work); @@ -562,6 +564,7 @@ static int limits_dcvs_probe(struct platform_device *pdev) return -ENOMEM; cpumask_copy(&hw->core_map, &mask); + cpumask_clear(&hw->online_mask); hw->cdev_registered = 0; for_each_cpu(cpu, &hw->core_map) { hw->cdev_data[idx].cdev = NULL; @@ -624,7 +627,6 @@ static int limits_dcvs_probe(struct platform_device *pdev) } mutex_init(&hw->access_lock); - mutex_init(&hw->cdev_reg_lock); INIT_WORK(&hw->cdev_register_work, register_cooling_device); INIT_DEFERRABLE_WORK(&hw->freq_poll_work, limits_dcvs_poll); hw->osm_hw_reg = devm_ioremap(&pdev->dev, request_reg, 0x4); @@ -661,7 +663,7 @@ static int limits_dcvs_probe(struct platform_device *pdev) probe_exit: mutex_lock(&lmh_dcvs_list_access); INIT_LIST_HEAD(&hw->list); - list_add(&hw->list, &lmh_dcvs_hw_list); + list_add_tail(&hw->list, &lmh_dcvs_hw_list); mutex_unlock(&lmh_dcvs_list_access); lmh_debug_register(pdev); -- GitLab From fde9eeaa3f90bb639fff0dbca9e951483f7051e8 Mon Sep 17 00:00:00 2001 From: Ram Chandrasekar Date: Wed, 11 Apr 2018 10:19:29 -0600 Subject: [PATCH 0343/1635] ARM: dts: msm: Add vbat and soc mitigation for SM8150 Add vbat, vph, ibat and soc mitigation to core isolate gold and gold+ cores for SM8150. Change-Id: Ib44ed357ab6162a6fa6bc9acd236117f0116bb94 Signed-off-by: Ram Chandrasekar --- arch/arm64/boot/dts/qcom/pm855b.dtsi | 24 +- arch/arm64/boot/dts/qcom/pm855l.dtsi | 8 +- arch/arm64/boot/dts/qcom/sm8150-cdp.dtsi | 120 +-------- arch/arm64/boot/dts/qcom/sm8150-mtp.dtsi | 120 +-------- arch/arm64/boot/dts/qcom/sm8150-qrd.dtsi | 120 +-------- .../boot/dts/qcom/sm8150-thermal-overlay.dtsi | 248 ++++++++++++++++++ 6 files changed, 269 insertions(+), 371 deletions(-) create mode 100644 arch/arm64/boot/dts/qcom/sm8150-thermal-overlay.dtsi diff --git a/arch/arm64/boot/dts/qcom/pm855b.dtsi b/arch/arm64/boot/dts/qcom/pm855b.dtsi index 82e5e1807823..10a2f3d53a59 100644 --- a/arch/arm64/boot/dts/qcom/pm855b.dtsi +++ b/arch/arm64/boot/dts/qcom/pm855b.dtsi @@ -498,7 +498,7 @@ }; pm855b-ibat-lvl0 { - polling-delay-passive = <0>; + polling-delay-passive = <100>; polling-delay = <0>; thermal-governor = "step_wise"; thermal-sensors = <&pm855b_bcl 0>; @@ -528,14 +528,15 @@ }; pm855b-vbat-lvl0 { - polling-delay-passive = <0>; + polling-delay-passive = <100>; polling-delay = <0>; - thermal-governor = "step_wise"; + thermal-governor = "low_limits_cap"; thermal-sensors = <&pm855b_bcl 2>; + tracks-low; trips { vbat_lvl0: vbat-lvl0 { - temperature = <3500>; + temperature = <3000>; hysteresis = <200>; type = "passive"; }; @@ -545,12 +546,13 @@ pm855b-vbat-lvl1 { polling-delay-passive = <0>; polling-delay = <0>; - thermal-governor = "step_wise"; + thermal-governor = "low_limits_cap"; thermal-sensors = <&pm855b_bcl 3>; + tracks-low; trips { vbat_lvl1:vbat-lvl1 { - temperature = <3000>; + temperature = <2800>; hysteresis = <200>; type = "passive"; }; @@ -560,12 +562,13 @@ pm855b-vbat-lvl2 { polling-delay-passive = <0>; polling-delay = <0>; - thermal-governor = "step_wise"; + thermal-governor = "low_limits_cap"; thermal-sensors = <&pm855b_bcl 4>; + tracks-low; trips { vbat_lvl2:vbat-lvl2 { - temperature = <2800>; + temperature = <2600>; hysteresis = <200>; type = "passive"; }; @@ -573,10 +576,11 @@ }; soc { - polling-delay-passive = <0>; + polling-delay-passive = <100>; polling-delay = <0>; - thermal-governor = "step_wise"; + thermal-governor = "low_limits_cap"; thermal-sensors = <&bcl_soc>; + tracks-low; trips { soc_trip:soc-trip { diff --git a/arch/arm64/boot/dts/qcom/pm855l.dtsi b/arch/arm64/boot/dts/qcom/pm855l.dtsi index 14786207d4de..fc1359503514 100644 --- a/arch/arm64/boot/dts/qcom/pm855l.dtsi +++ b/arch/arm64/boot/dts/qcom/pm855l.dtsi @@ -337,7 +337,7 @@ }; pm855l-vph-lvl0 { - polling-delay-passive = <0>; + polling-delay-passive = <100>; polling-delay = <0>; thermal-governor = "low_limits_cap"; thermal-sensors = <&pm855l_bcl 2>; @@ -345,7 +345,7 @@ trips { vph_lvl0: vph-lvl0 { - temperature = <3500>; + temperature = <3000>; hysteresis = <200>; type = "passive"; }; @@ -361,7 +361,7 @@ trips { vph_lvl1:vph-lvl1 { - temperature = <3000>; + temperature = <2750>; hysteresis = <200>; type = "passive"; }; @@ -377,7 +377,7 @@ trips { vph_lvl2:vph-lvl2 { - temperature = <2800>; + temperature = <2500>; hysteresis = <200>; type = "passive"; }; diff --git a/arch/arm64/boot/dts/qcom/sm8150-cdp.dtsi b/arch/arm64/boot/dts/qcom/sm8150-cdp.dtsi index 98208f2a82c0..5413b9c75212 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-cdp.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-cdp.dtsi @@ -12,12 +12,12 @@ #include #include -#include #include "sm8150-pmic-overlay.dtsi" #include "sm8150-audio-overlay.dtsi" #include "sm8150-sde-display.dtsi" #include "sm8150-camera-sensor-cdp.dtsi" +#include "sm8150-thermal-overlay.dtsi" &qupv3_se12_2uart { status = "ok"; @@ -88,10 +88,6 @@ }; }; -&mdss_mdp { - #cooling-cells = <2>; -}; - &dsi_sharp_4k_dsc_cmd { qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; @@ -382,120 +378,6 @@ }; }; -&thermal_zones { - pm855b_tz { - cooling-maps { - trip0_bat { - trip = <&pm855b_trip0>; - cooling-device = - <&pm855b_charger (THERMAL_MAX_LIMIT-1) - (THERMAL_MAX_LIMIT-1)>; - }; - trip1_bat { - trip = <&pm855b_trip1>; - cooling-device = - <&pm855b_charger THERMAL_MAX_LIMIT - THERMAL_MAX_LIMIT>; - }; - }; - }; - - pm855_tz { - cooling-maps { - trip0_cpu0 { - trip = <&pm855_trip0>; - cooling-device = - <&CPU0 (THERMAL_MAX_LIMIT-1) - (THERMAL_MAX_LIMIT-1)>; - }; - trip0_cpu1 { - trip = <&pm855_trip0>; - cooling-device = - <&CPU1 (THERMAL_MAX_LIMIT-1) - (THERMAL_MAX_LIMIT-1)>; - }; - trip0_cpu2 { - trip = <&pm855_trip0>; - cooling-device = - <&CPU2 (THERMAL_MAX_LIMIT-1) - (THERMAL_MAX_LIMIT-1)>; - }; - trip0_cpu3 { - trip = <&pm855_trip0>; - cooling-device = - <&CPU3 (THERMAL_MAX_LIMIT-1) - (THERMAL_MAX_LIMIT-1)>; - }; - trip0_cpu4 { - trip = <&pm855_trip0>; - cooling-device = - <&CPU4 (THERMAL_MAX_LIMIT-1) - (THERMAL_MAX_LIMIT-1)>; - }; - trip0_cpu5 { - trip = <&pm855_trip0>; - cooling-device = - <&CPU5 (THERMAL_MAX_LIMIT-1) - (THERMAL_MAX_LIMIT-1)>; - }; - trip0_cpu6 { - trip = <&pm855_trip0>; - cooling-device = - <&CPU6 (THERMAL_MAX_LIMIT-1) - (THERMAL_MAX_LIMIT-1)>; - }; - trip0_cpu7 { - trip = <&pm855_trip0>; - cooling-device = - <&CPU7 (THERMAL_MAX_LIMIT-1) - (THERMAL_MAX_LIMIT-1)>; - }; - trip1_cpu1 { - trip = <&pm855_trip1>; - cooling-device = - <&CPU1 THERMAL_MAX_LIMIT - THERMAL_MAX_LIMIT>; - }; - trip1_cpu2 { - trip = <&pm855_trip1>; - cooling-device = - <&CPU2 THERMAL_MAX_LIMIT - THERMAL_MAX_LIMIT>; - }; - trip1_cpu3 { - trip = <&pm855_trip1>; - cooling-device = - <&CPU3 THERMAL_MAX_LIMIT - THERMAL_MAX_LIMIT>; - }; - trip1_cpu4 { - trip = <&pm855_trip1>; - cooling-device = - <&CPU4 THERMAL_MAX_LIMIT - THERMAL_MAX_LIMIT>; - }; - trip1_cpu5 { - trip = <&pm855_trip1>; - cooling-device = - <&CPU5 THERMAL_MAX_LIMIT - THERMAL_MAX_LIMIT>; - }; - trip1_cpu6 { - trip = <&pm855_trip1>; - cooling-device = - <&CPU6 THERMAL_MAX_LIMIT - THERMAL_MAX_LIMIT>; - }; - trip1_cpu7 { - trip = <&pm855_trip1>; - cooling-device = - <&CPU7 THERMAL_MAX_LIMIT - THERMAL_MAX_LIMIT>; - }; - }; - }; -}; - &wil6210 { status = "ok"; }; diff --git a/arch/arm64/boot/dts/qcom/sm8150-mtp.dtsi b/arch/arm64/boot/dts/qcom/sm8150-mtp.dtsi index 8ae926fcfb4f..308aa137750f 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-mtp.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-mtp.dtsi @@ -12,12 +12,12 @@ #include #include -#include #include "sm8150-pmic-overlay.dtsi" #include "sm8150-audio-overlay.dtsi" #include "sm8150-sde-display.dtsi" #include "sm8150-camera-sensor-mtp.dtsi" +#include "sm8150-thermal-overlay.dtsi" &qupv3_se12_2uart { status = "ok"; @@ -205,10 +205,6 @@ }; }; -&mdss_mdp { - #cooling-cells = <2>; -}; - &ufsphy_mem { compatible = "qcom,ufs-phy-qmp-v4"; @@ -386,120 +382,6 @@ }; }; -&thermal_zones { - pm855b_tz { - cooling-maps { - trip0_bat { - trip = <&pm855b_trip0>; - cooling-device = - <&pm855b_charger (THERMAL_MAX_LIMIT-1) - (THERMAL_MAX_LIMIT-1)>; - }; - trip1_bat { - trip = <&pm855b_trip1>; - cooling-device = - <&pm855b_charger THERMAL_MAX_LIMIT - THERMAL_MAX_LIMIT>; - }; - }; - }; - - pm855_tz { - cooling-maps { - trip0_cpu0 { - trip = <&pm855_trip0>; - cooling-device = - <&CPU0 (THERMAL_MAX_LIMIT-1) - (THERMAL_MAX_LIMIT-1)>; - }; - trip0_cpu1 { - trip = <&pm855_trip0>; - cooling-device = - <&CPU1 (THERMAL_MAX_LIMIT-1) - (THERMAL_MAX_LIMIT-1)>; - }; - trip0_cpu2 { - trip = <&pm855_trip0>; - cooling-device = - <&CPU2 (THERMAL_MAX_LIMIT-1) - (THERMAL_MAX_LIMIT-1)>; - }; - trip0_cpu3 { - trip = <&pm855_trip0>; - cooling-device = - <&CPU3 (THERMAL_MAX_LIMIT-1) - (THERMAL_MAX_LIMIT-1)>; - }; - trip0_cpu4 { - trip = <&pm855_trip0>; - cooling-device = - <&CPU4 (THERMAL_MAX_LIMIT-1) - (THERMAL_MAX_LIMIT-1)>; - }; - trip0_cpu5 { - trip = <&pm855_trip0>; - cooling-device = - <&CPU5 (THERMAL_MAX_LIMIT-1) - (THERMAL_MAX_LIMIT-1)>; - }; - trip0_cpu6 { - trip = <&pm855_trip0>; - cooling-device = - <&CPU6 (THERMAL_MAX_LIMIT-1) - (THERMAL_MAX_LIMIT-1)>; - }; - trip0_cpu7 { - trip = <&pm855_trip0>; - cooling-device = - <&CPU7 (THERMAL_MAX_LIMIT-1) - (THERMAL_MAX_LIMIT-1)>; - }; - trip1_cpu1 { - trip = <&pm855_trip1>; - cooling-device = - <&CPU1 THERMAL_MAX_LIMIT - THERMAL_MAX_LIMIT>; - }; - trip1_cpu2 { - trip = <&pm855_trip1>; - cooling-device = - <&CPU2 THERMAL_MAX_LIMIT - THERMAL_MAX_LIMIT>; - }; - trip1_cpu3 { - trip = <&pm855_trip1>; - cooling-device = - <&CPU3 THERMAL_MAX_LIMIT - THERMAL_MAX_LIMIT>; - }; - trip1_cpu4 { - trip = <&pm855_trip1>; - cooling-device = - <&CPU4 THERMAL_MAX_LIMIT - THERMAL_MAX_LIMIT>; - }; - trip1_cpu5 { - trip = <&pm855_trip1>; - cooling-device = - <&CPU5 THERMAL_MAX_LIMIT - THERMAL_MAX_LIMIT>; - }; - trip1_cpu6 { - trip = <&pm855_trip1>; - cooling-device = - <&CPU6 THERMAL_MAX_LIMIT - THERMAL_MAX_LIMIT>; - }; - trip1_cpu7 { - trip = <&pm855_trip1>; - cooling-device = - <&CPU7 THERMAL_MAX_LIMIT - THERMAL_MAX_LIMIT>; - }; - }; - }; -}; - &wil6210 { status = "ok"; }; diff --git a/arch/arm64/boot/dts/qcom/sm8150-qrd.dtsi b/arch/arm64/boot/dts/qcom/sm8150-qrd.dtsi index 0015edda2ac3..a7432b1d840b 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-qrd.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-qrd.dtsi @@ -12,12 +12,12 @@ #include #include -#include #include "sm8150-pmic-overlay.dtsi" #include "sm8150-audio-overlay.dtsi" #include "sm8150-sde-display.dtsi" #include "sm8150-camera-sensor-qrd.dtsi" +#include "sm8150-thermal-overlay.dtsi" &soc { gpio_keys { @@ -50,10 +50,6 @@ }; }; -&mdss_mdp { - #cooling-cells = <2>; -}; - &qupv3_se17_i2c { status = "ok"; @@ -372,120 +368,6 @@ }; }; -&thermal_zones { - pm855b_tz { - cooling-maps { - trip0_bat { - trip = <&pm855b_trip0>; - cooling-device = - <&pm855b_charger (THERMAL_MAX_LIMIT-1) - (THERMAL_MAX_LIMIT-1)>; - }; - trip1_bat { - trip = <&pm855b_trip1>; - cooling-device = - <&pm855b_charger THERMAL_MAX_LIMIT - THERMAL_MAX_LIMIT>; - }; - }; - }; - - pm855_tz { - cooling-maps { - trip0_cpu0 { - trip = <&pm855_trip0>; - cooling-device = - <&CPU0 (THERMAL_MAX_LIMIT-1) - (THERMAL_MAX_LIMIT-1)>; - }; - trip0_cpu1 { - trip = <&pm855_trip0>; - cooling-device = - <&CPU1 (THERMAL_MAX_LIMIT-1) - (THERMAL_MAX_LIMIT-1)>; - }; - trip0_cpu2 { - trip = <&pm855_trip0>; - cooling-device = - <&CPU2 (THERMAL_MAX_LIMIT-1) - (THERMAL_MAX_LIMIT-1)>; - }; - trip0_cpu3 { - trip = <&pm855_trip0>; - cooling-device = - <&CPU3 (THERMAL_MAX_LIMIT-1) - (THERMAL_MAX_LIMIT-1)>; - }; - trip0_cpu4 { - trip = <&pm855_trip0>; - cooling-device = - <&CPU4 (THERMAL_MAX_LIMIT-1) - (THERMAL_MAX_LIMIT-1)>; - }; - trip0_cpu5 { - trip = <&pm855_trip0>; - cooling-device = - <&CPU5 (THERMAL_MAX_LIMIT-1) - (THERMAL_MAX_LIMIT-1)>; - }; - trip0_cpu6 { - trip = <&pm855_trip0>; - cooling-device = - <&CPU6 (THERMAL_MAX_LIMIT-1) - (THERMAL_MAX_LIMIT-1)>; - }; - trip0_cpu7 { - trip = <&pm855_trip0>; - cooling-device = - <&CPU7 (THERMAL_MAX_LIMIT-1) - (THERMAL_MAX_LIMIT-1)>; - }; - trip1_cpu1 { - trip = <&pm855_trip1>; - cooling-device = - <&CPU1 THERMAL_MAX_LIMIT - THERMAL_MAX_LIMIT>; - }; - trip1_cpu2 { - trip = <&pm855_trip1>; - cooling-device = - <&CPU2 THERMAL_MAX_LIMIT - THERMAL_MAX_LIMIT>; - }; - trip1_cpu3 { - trip = <&pm855_trip1>; - cooling-device = - <&CPU3 THERMAL_MAX_LIMIT - THERMAL_MAX_LIMIT>; - }; - trip1_cpu4 { - trip = <&pm855_trip1>; - cooling-device = - <&CPU4 THERMAL_MAX_LIMIT - THERMAL_MAX_LIMIT>; - }; - trip1_cpu5 { - trip = <&pm855_trip1>; - cooling-device = - <&CPU5 THERMAL_MAX_LIMIT - THERMAL_MAX_LIMIT>; - }; - trip1_cpu6 { - trip = <&pm855_trip1>; - cooling-device = - <&CPU6 THERMAL_MAX_LIMIT - THERMAL_MAX_LIMIT>; - }; - trip1_cpu7 { - trip = <&pm855_trip1>; - cooling-device = - <&CPU7 THERMAL_MAX_LIMIT - THERMAL_MAX_LIMIT>; - }; - }; - }; -}; - &wil6210 { status = "ok"; }; diff --git a/arch/arm64/boot/dts/qcom/sm8150-thermal-overlay.dtsi b/arch/arm64/boot/dts/qcom/sm8150-thermal-overlay.dtsi new file mode 100644 index 000000000000..498979674519 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sm8150-thermal-overlay.dtsi @@ -0,0 +1,248 @@ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#include + +&thermal_zones { + pm855b_tz { + cooling-maps { + trip0_bat { + trip = <&pm855b_trip0>; + cooling-device = + <&pm855b_charger (THERMAL_MAX_LIMIT-1) + (THERMAL_MAX_LIMIT-1)>; + }; + trip1_bat { + trip = <&pm855b_trip1>; + cooling-device = + <&pm855b_charger THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + }; + }; + + pm855_tz { + cooling-maps { + trip0_cpu0 { + trip = <&pm855_trip0>; + cooling-device = + <&CPU0 (THERMAL_MAX_LIMIT-1) + (THERMAL_MAX_LIMIT-1)>; + }; + trip0_cpu1 { + trip = <&pm855_trip0>; + cooling-device = + <&CPU1 (THERMAL_MAX_LIMIT-1) + (THERMAL_MAX_LIMIT-1)>; + }; + trip0_cpu2 { + trip = <&pm855_trip0>; + cooling-device = + <&CPU2 (THERMAL_MAX_LIMIT-1) + (THERMAL_MAX_LIMIT-1)>; + }; + trip0_cpu3 { + trip = <&pm855_trip0>; + cooling-device = + <&CPU3 (THERMAL_MAX_LIMIT-1) + (THERMAL_MAX_LIMIT-1)>; + }; + trip0_cpu4 { + trip = <&pm855_trip0>; + cooling-device = + <&CPU4 (THERMAL_MAX_LIMIT-1) + (THERMAL_MAX_LIMIT-1)>; + }; + trip0_cpu5 { + trip = <&pm855_trip0>; + cooling-device = + <&CPU5 (THERMAL_MAX_LIMIT-1) + (THERMAL_MAX_LIMIT-1)>; + }; + trip0_cpu6 { + trip = <&pm855_trip0>; + cooling-device = + <&CPU6 (THERMAL_MAX_LIMIT-1) + (THERMAL_MAX_LIMIT-1)>; + }; + trip0_cpu7 { + trip = <&pm855_trip0>; + cooling-device = + <&CPU7 (THERMAL_MAX_LIMIT-1) + (THERMAL_MAX_LIMIT-1)>; + }; + trip1_cpu1 { + trip = <&pm855_trip1>; + cooling-device = + <&CPU1 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + trip1_cpu2 { + trip = <&pm855_trip1>; + cooling-device = + <&CPU2 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + trip1_cpu3 { + trip = <&pm855_trip1>; + cooling-device = + <&CPU3 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + trip1_cpu4 { + trip = <&pm855_trip1>; + cooling-device = + <&CPU4 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + trip1_cpu5 { + trip = <&pm855_trip1>; + cooling-device = + <&CPU5 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + trip1_cpu6 { + trip = <&pm855_trip1>; + cooling-device = + <&CPU6 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + trip1_cpu7 { + trip = <&pm855_trip1>; + cooling-device = + <&CPU7 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + }; + }; + + soc { + cooling-maps { + soc_cpu4 { + trip = <&soc_trip>; + cooling-device = + <&CPU4 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + soc_cpu5 { + trip = <&soc_trip>; + cooling-device = + <&CPU5 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + soc_cpu6 { + trip = <&soc_trip>; + cooling-device = + <&CPU6 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + soc_cpu7 { + trip = <&soc_trip>; + cooling-device = + <&CPU7 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + }; + }; + + pm855b-vbat-lvl0 { + cooling-maps { + vbat_cpu4 { + trip = <&vbat_lvl0>; + cooling-device = + <&CPU4 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + vbat_cpu5 { + trip = <&vbat_lvl0>; + cooling-device = + <&CPU5 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + vbat_cpu6 { + trip = <&vbat_lvl0>; + cooling-device = + <&CPU6 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + vbat_cpu7 { + trip = <&vbat_lvl0>; + cooling-device = + <&CPU7 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + }; + }; + + pm855b-ibat-lvl0 { + cooling-maps { + ibat_cpu4 { + trip = <&ibat_lvl0>; + cooling-device = + <&CPU4 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + ibat_cpu5 { + trip = <&ibat_lvl0>; + cooling-device = + <&CPU5 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + ibat_cpu6 { + trip = <&ibat_lvl0>; + cooling-device = + <&CPU6 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + ibat_cpu7 { + trip = <&ibat_lvl0>; + cooling-device = + <&CPU7 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + }; + }; + + pm855l-vph-lvl0 { + disable-thermal-zone; + cooling-maps { + vph_cpu4 { + trip = <&vph_lvl0>; + cooling-device = + <&CPU4 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + vph_cpu5 { + trip = <&vph_lvl0>; + cooling-device = + <&CPU5 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + vph_cpu6 { + trip = <&vph_lvl0>; + cooling-device = + <&CPU6 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + vph_cpu7 { + trip = <&vph_lvl0>; + cooling-device = + <&CPU7 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + }; + }; +}; + +&mdss_mdp { + #cooling-cells = <2>; +}; -- GitLab From c493aef0ef3e4c41a26a99e440dea2905f36aa15 Mon Sep 17 00:00:00 2001 From: Ram Chandrasekar Date: Wed, 11 Apr 2018 17:37:07 -0600 Subject: [PATCH 0344/1635] ARM: dts: msm: Add GPU thermal config for SM8150 Add GPU thermal config for GPU junction temperature mitigation and low temperature voltage restriction for SM8150. Change-Id: I90276072c5dc4c5ea11e00cd66ce25949e2b2f6b Signed-off-by: Ram Chandrasekar --- arch/arm64/boot/dts/qcom/sm8150-thermal.dtsi | 147 +++++++++++++++++++ 1 file changed, 147 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sm8150-thermal.dtsi b/arch/arm64/boot/dts/qcom/sm8150-thermal.dtsi index f1f86faaa635..7b836012a8d1 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-thermal.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-thermal.dtsi @@ -547,6 +547,11 @@ trip = <&aoss0_trip>; cooling-device = <&slpi_vdd 0 0>; }; + gpu_vdd_cdev { + trip = <&aoss0_trip>; + cooling-device = <&msm_gpu (THERMAL_MAX_LIMIT-2) + (THERMAL_MAX_LIMIT-2)>; + }; }; }; @@ -604,6 +609,11 @@ trip = <&cpu00_trip>; cooling-device = <&slpi_vdd 0 0>; }; + gpu_vdd_cdev { + trip = <&cpu00_trip>; + cooling-device = <&msm_gpu (THERMAL_MAX_LIMIT-2) + (THERMAL_MAX_LIMIT-2)>; + }; }; }; @@ -661,6 +671,11 @@ trip = <&cpu01_trip>; cooling-device = <&slpi_vdd 0 0>; }; + gpu_vdd_cdev { + trip = <&cpu01_trip>; + cooling-device = <&msm_gpu (THERMAL_MAX_LIMIT-2) + (THERMAL_MAX_LIMIT-2)>; + }; }; }; @@ -718,6 +733,11 @@ trip = <&cpu02_trip>; cooling-device = <&slpi_vdd 0 0>; }; + gpu_vdd_cdev { + trip = <&cpu02_trip>; + cooling-device = <&msm_gpu (THERMAL_MAX_LIMIT-2) + (THERMAL_MAX_LIMIT-2)>; + }; }; }; @@ -775,6 +795,11 @@ trip = <&cpu03_trip>; cooling-device = <&slpi_vdd 0 0>; }; + gpu_vdd_cdev { + trip = <&cpu03_trip>; + cooling-device = <&msm_gpu (THERMAL_MAX_LIMIT-2) + (THERMAL_MAX_LIMIT-2)>; + }; }; }; @@ -832,6 +857,11 @@ trip = <&cpuss0_trip>; cooling-device = <&slpi_vdd 0 0>; }; + gpu_vdd_cdev { + trip = <&cpuss0_trip>; + cooling-device = <&msm_gpu (THERMAL_MAX_LIMIT-2) + (THERMAL_MAX_LIMIT-2)>; + }; }; }; @@ -889,6 +919,11 @@ trip = <&cpuss1_trip>; cooling-device = <&slpi_vdd 0 0>; }; + gpu_vdd_cdev { + trip = <&cpuss1_trip>; + cooling-device = <&msm_gpu (THERMAL_MAX_LIMIT-2) + (THERMAL_MAX_LIMIT-2)>; + }; }; }; @@ -946,6 +981,11 @@ trip = <&cpu10_trip>; cooling-device = <&slpi_vdd 0 0>; }; + gpu_vdd_cdev { + trip = <&cpu10_trip>; + cooling-device = <&msm_gpu (THERMAL_MAX_LIMIT-2) + (THERMAL_MAX_LIMIT-2)>; + }; }; }; @@ -1003,6 +1043,11 @@ trip = <&cpu11_trip>; cooling-device = <&slpi_vdd 0 0>; }; + gpu_vdd_cdev { + trip = <&cpu11_trip>; + cooling-device = <&msm_gpu (THERMAL_MAX_LIMIT-2) + (THERMAL_MAX_LIMIT-2)>; + }; }; }; @@ -1060,6 +1105,11 @@ trip = <&cpu12_trip>; cooling-device = <&slpi_vdd 0 0>; }; + gpu_vdd_cdev { + trip = <&cpu12_trip>; + cooling-device = <&msm_gpu (THERMAL_MAX_LIMIT-2) + (THERMAL_MAX_LIMIT-2)>; + }; }; }; @@ -1117,6 +1167,11 @@ trip = <&cpu13_trip>; cooling-device = <&slpi_vdd 0 0>; }; + gpu_vdd_cdev { + trip = <&cpu13_trip>; + cooling-device = <&msm_gpu (THERMAL_MAX_LIMIT-2) + (THERMAL_MAX_LIMIT-2)>; + }; }; }; @@ -1174,6 +1229,11 @@ trip = <&cpu14_trip>; cooling-device = <&slpi_vdd 0 0>; }; + gpu_vdd_cdev { + trip = <&cpu14_trip>; + cooling-device = <&msm_gpu (THERMAL_MAX_LIMIT-2) + (THERMAL_MAX_LIMIT-2)>; + }; }; }; @@ -1231,6 +1291,11 @@ trip = <&cpu15_trip>; cooling-device = <&slpi_vdd 0 0>; }; + gpu_vdd_cdev { + trip = <&cpu15_trip>; + cooling-device = <&msm_gpu (THERMAL_MAX_LIMIT-2) + (THERMAL_MAX_LIMIT-2)>; + }; }; }; @@ -1288,6 +1353,11 @@ trip = <&cpu16_trip>; cooling-device = <&slpi_vdd 0 0>; }; + gpu_vdd_cdev { + trip = <&cpu16_trip>; + cooling-device = <&msm_gpu (THERMAL_MAX_LIMIT-2) + (THERMAL_MAX_LIMIT-2)>; + }; }; }; @@ -1345,6 +1415,11 @@ trip = <&cpu17_trip>; cooling-device = <&slpi_vdd 0 0>; }; + gpu_vdd_cdev { + trip = <&cpu17_trip>; + cooling-device = <&msm_gpu (THERMAL_MAX_LIMIT-2) + (THERMAL_MAX_LIMIT-2)>; + }; }; }; @@ -1402,6 +1477,11 @@ trip = <&gpuss0_trip>; cooling-device = <&slpi_vdd 0 0>; }; + gpu_vdd_cdev { + trip = <&gpuss0_trip>; + cooling-device = <&msm_gpu (THERMAL_MAX_LIMIT-2) + (THERMAL_MAX_LIMIT-2)>; + }; }; }; @@ -1459,6 +1539,11 @@ trip = <&aoss1_trip>; cooling-device = <&slpi_vdd 0 0>; }; + gpu_vdd_cdev { + trip = <&aoss1_trip>; + cooling-device = <&msm_gpu (THERMAL_MAX_LIMIT-2) + (THERMAL_MAX_LIMIT-2)>; + }; }; }; @@ -1516,6 +1601,11 @@ trip = <&cwlan_trip>; cooling-device = <&slpi_vdd 0 0>; }; + gpu_vdd_cdev { + trip = <&cwlan_trip>; + cooling-device = <&msm_gpu (THERMAL_MAX_LIMIT-2) + (THERMAL_MAX_LIMIT-2)>; + }; }; }; @@ -1573,6 +1663,11 @@ trip = <&video_trip>; cooling-device = <&slpi_vdd 0 0>; }; + gpu_vdd_cdev { + trip = <&video_trip>; + cooling-device = <&msm_gpu (THERMAL_MAX_LIMIT-2) + (THERMAL_MAX_LIMIT-2)>; + }; }; }; @@ -1630,6 +1725,11 @@ trip = <&ddr_trip>; cooling-device = <&slpi_vdd 0 0>; }; + gpu_vdd_cdev { + trip = <&ddr_trip>; + cooling-device = <&msm_gpu (THERMAL_MAX_LIMIT-2) + (THERMAL_MAX_LIMIT-2)>; + }; }; }; @@ -1687,6 +1787,11 @@ trip = <&q6_trip>; cooling-device = <&slpi_vdd 0 0>; }; + gpu_vdd_cdev { + trip = <&q6_trip>; + cooling-device = <&msm_gpu (THERMAL_MAX_LIMIT-2) + (THERMAL_MAX_LIMIT-2)>; + }; }; }; @@ -1744,6 +1849,11 @@ trip = <&camera_trip>; cooling-device = <&slpi_vdd 0 0>; }; + gpu_vdd_cdev { + trip = <&camera_trip>; + cooling-device = <&msm_gpu (THERMAL_MAX_LIMIT-2) + (THERMAL_MAX_LIMIT-2)>; + }; }; }; @@ -1801,6 +1911,11 @@ trip = <&cmpss_trip>; cooling-device = <&slpi_vdd 0 0>; }; + gpu_vdd_cdev { + trip = <&cmpss_trip>; + cooling-device = <&msm_gpu (THERMAL_MAX_LIMIT-2) + (THERMAL_MAX_LIMIT-2)>; + }; }; }; @@ -1858,6 +1973,11 @@ trip = <&mdm_trip>; cooling-device = <&slpi_vdd 0 0>; }; + gpu_vdd_cdev { + trip = <&mdm_trip>; + cooling-device = <&msm_gpu (THERMAL_MAX_LIMIT-2) + (THERMAL_MAX_LIMIT-2)>; + }; }; }; @@ -1915,6 +2035,11 @@ trip = <&npu_trip>; cooling-device = <&slpi_vdd 0 0>; }; + gpu_vdd_cdev { + trip = <&npu_trip>; + cooling-device = <&msm_gpu (THERMAL_MAX_LIMIT-2) + (THERMAL_MAX_LIMIT-2)>; + }; }; }; @@ -1972,6 +2097,11 @@ trip = <&mdmv_trip>; cooling-device = <&slpi_vdd 0 0>; }; + gpu_vdd_cdev { + trip = <&mdmv_trip>; + cooling-device = <&msm_gpu (THERMAL_MAX_LIMIT-2) + (THERMAL_MAX_LIMIT-2)>; + }; }; }; @@ -2029,6 +2159,11 @@ trip = <&mdms_trip>; cooling-device = <&slpi_vdd 0 0>; }; + gpu_vdd_cdev { + trip = <&mdms_trip>; + cooling-device = <&msm_gpu (THERMAL_MAX_LIMIT-2) + (THERMAL_MAX_LIMIT-2)>; + }; }; }; @@ -2086,6 +2221,11 @@ trip = <&gpuss1_trip>; cooling-device = <&slpi_vdd 0 0>; }; + gpu_vdd_cdev { + trip = <&gpuss1_trip>; + cooling-device = <&msm_gpu (THERMAL_MAX_LIMIT-2) + (THERMAL_MAX_LIMIT-2)>; + }; }; }; @@ -2100,6 +2240,13 @@ type = "passive"; }; }; + cooling-maps { + gpu_cdev { + trip = <&gpu_trip0>; + cooling-device = <&msm_gpu THERMAL_NO_LIMIT + THERMAL_NO_LIMIT>; + }; + }; }; apc-0-max-step { -- GitLab From cce57c4487d612f5c1da14dac28a6c5ffe1c2b90 Mon Sep 17 00:00:00 2001 From: Ram Chandrasekar Date: Tue, 20 Sep 2016 17:09:28 -0600 Subject: [PATCH 0345/1635] drivers: thermal: Aggregate userspace mitigation request Thermal core allows multiple governors to monitor different thermal zones. Each governor's mitigation request shouldn't override other governor's request. But userspace request to mitigate a cooling device will override any previous aggregated request from kernel thermal governors. This will not allow any userspace governor to mitigate along with the kernel governors. The userspace request now will be stored and aggregated with the rest of the requests from the kernel thermal governors. Change-Id: Ib0d55a0ee7ad8f835a5e969b7ef268d420085acf Signed-off-by: Ram Chandrasekar --- drivers/thermal/thermal_sysfs.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/thermal/thermal_sysfs.c b/drivers/thermal/thermal_sysfs.c index 616153756808..3fe10afce2ec 100644 --- a/drivers/thermal/thermal_sysfs.c +++ b/drivers/thermal/thermal_sysfs.c @@ -812,7 +812,6 @@ thermal_cooling_device_cur_state_store(struct device *dev, { struct thermal_cooling_device *cdev = to_cooling_device(dev); unsigned long state; - int result; if (sscanf(buf, "%ld\n", &state) != 1) return -EINVAL; @@ -820,9 +819,13 @@ thermal_cooling_device_cur_state_store(struct device *dev, if ((long)state < 0) return -EINVAL; - result = cdev->ops->set_cur_state(cdev, state); - if (result) - return result; + mutex_lock(&cdev->lock); + cdev->sysfs_cur_state_req = state; + + cdev->updated = false; + mutex_unlock(&cdev->lock); + thermal_cdev_update(cdev); + return count; } -- GitLab From 859b76c18739d3d13412430fba4c1ad40098bc44 Mon Sep 17 00:00:00 2001 From: Lina Iyer Date: Thu, 29 Mar 2018 09:38:08 -0600 Subject: [PATCH 0346/1635] defconfig: msm: Enable RPM sleep stats for SDM8150 Enable sleep stats driver to report XO and system sleep statistics from AOSS. Change-Id: Iee8602d5538ea13d211d24a218c6eb3702398fc4 Signed-off-by: Lina Iyer --- arch/arm64/configs/sm8150-perf_defconfig | 1 + arch/arm64/configs/sm8150_defconfig | 1 + 2 files changed, 2 insertions(+) diff --git a/arch/arm64/configs/sm8150-perf_defconfig b/arch/arm64/configs/sm8150-perf_defconfig index bc97892cb5a8..6f8e83016b3b 100644 --- a/arch/arm64/configs/sm8150-perf_defconfig +++ b/arch/arm64/configs/sm8150-perf_defconfig @@ -502,6 +502,7 @@ CONFIG_QCOM_EARLY_RANDOM=y CONFIG_QTI_RPMH_API=y CONFIG_QCOM_GLINK=y CONFIG_QCOM_GLINK_PKT=y +CONFIG_QTI_RPM_STATS_LOG=y CONFIG_MSM_CDSP_LOADER=y CONFIG_MSM_EVENT_TIMER=y CONFIG_MSM_PM=y diff --git a/arch/arm64/configs/sm8150_defconfig b/arch/arm64/configs/sm8150_defconfig index bc24ba3e0a63..cb0ceb106014 100644 --- a/arch/arm64/configs/sm8150_defconfig +++ b/arch/arm64/configs/sm8150_defconfig @@ -523,6 +523,7 @@ CONFIG_MSM_SPSS_UTILS=y CONFIG_QTI_RPMH_API=y CONFIG_QCOM_GLINK=y CONFIG_QCOM_GLINK_PKT=y +CONFIG_QTI_RPM_STATS_LOG=y CONFIG_MSM_CDSP_LOADER=y CONFIG_MSM_EVENT_TIMER=y CONFIG_MSM_PM=y -- GitLab From 3c4911f18eda0655c1e6ac17d85470860e54eb2d Mon Sep 17 00:00:00 2001 From: Lina Iyer Date: Wed, 4 Apr 2018 15:17:23 -0600 Subject: [PATCH 0347/1635] ARM: dts: msm: Update TCS configuration for SDE RSC in SM8150 Update devicetree bindings for SDE RSC to match the RSC sequencer in SM8150. Change-Id: Ia19bc1d53497e3e5ebd8ee99bb6c56d6150977b2 Signed-off-by: Lina Iyer --- arch/arm64/boot/dts/qcom/sm8150.dtsi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sm8150.dtsi b/arch/arm64/boot/dts/qcom/sm8150.dtsi index 82541b7795ad..90192caef35c 100644 --- a/arch/arm64/boot/dts/qcom/sm8150.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150.dtsi @@ -2240,9 +2240,9 @@ interrupts = <0 129 0>; #mbox-cells = <1>; qcom,drv-id = <0>; - qcom,tcs-config = , - , + qcom,tcs-config = , , + , ; }; -- GitLab From 9079f0fb530f585557983398b4b4375a84ff6222 Mon Sep 17 00:00:00 2001 From: Narendra Muppalla Date: Fri, 6 Apr 2018 13:59:17 -0700 Subject: [PATCH 0348/1635] drm/msm: handle dma_buf attach/map for secure buffers During addfb2 ioctl, buffer is always attached to non-secure context bank. At commit time when the plane property tells the buffer is secure it needs to be attached and map to the secure context bank. This change detects the context bank type and maps the buffer accordingly. Change-Id: Icf3697b31d5ae5d217846fbee16467af55529c86 Signed-off-by: Narendra Muppalla --- drivers/gpu/drm/msm/msm_drv.h | 2 ++ drivers/gpu/drm/msm/msm_gem.c | 38 ++++++++++++++++++++++++++++++- drivers/gpu/drm/msm/msm_gem_vma.c | 10 ++++++++ drivers/gpu/drm/msm/msm_mmu.h | 1 + drivers/gpu/drm/msm/msm_smmu.c | 8 +++++++ 5 files changed, 58 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h index 8f246aad61fc..0df1b3eee15b 100644 --- a/drivers/gpu/drm/msm/msm_drv.h +++ b/drivers/gpu/drm/msm/msm_drv.h @@ -668,6 +668,8 @@ int msm_gem_map_vma(struct msm_gem_address_space *aspace, struct msm_gem_vma *vma, struct sg_table *sgt, int npages, unsigned int flags); +struct device *msm_gem_get_aspace_device(struct msm_gem_address_space *aspace); + void msm_gem_address_space_put(struct msm_gem_address_space *aspace); struct msm_gem_address_space * diff --git a/drivers/gpu/drm/msm/msm_gem.c b/drivers/gpu/drm/msm/msm_gem.c index 48ce0e5ead54..ee81014c6278 100644 --- a/drivers/gpu/drm/msm/msm_gem.c +++ b/drivers/gpu/drm/msm/msm_gem.c @@ -26,6 +26,7 @@ #include "msm_gem.h" #include "msm_gpu.h" #include "msm_mmu.h" +#include "sde_dbg.h" static void msm_gem_vunmap_locked(struct drm_gem_object *obj); @@ -416,9 +417,44 @@ int msm_gem_get_iova(struct drm_gem_object *obj, if (!vma) { struct page **pages; + struct device *dev; + struct dma_buf *dmabuf; + bool reattach = false; + + /* + * both secure/non-secure domains are attached with the default + * devive (non-sec) with dma_buf_attach during + * msm_gem_prime_import. detach and attach the correct device + * to the dma_buf based on the aspace domain. + */ + dev = msm_gem_get_aspace_device(aspace); + if (dev && obj->import_attach && + (dev != obj->import_attach->dev)) { + dmabuf = obj->import_attach->dmabuf; + + DRM_DEBUG("detach nsec-dev:%pK attach sec-dev:%pK\n", + obj->import_attach->dev, dev); + SDE_EVT32(obj->import_attach->dev, dev, msm_obj->sgt); + + + if (msm_obj->sgt) + dma_buf_unmap_attachment(obj->import_attach, + msm_obj->sgt, + DMA_BIDIRECTIONAL); + dma_buf_detach(dmabuf, obj->import_attach); + + obj->import_attach = dma_buf_attach(dmabuf, dev); + if (IS_ERR(obj->import_attach)) { + DRM_ERROR("dma_buf_attach failure, err=%ld\n", + PTR_ERR(obj->import_attach)); + goto unlock; + } + reattach = true; + } /* perform delayed import for buffers without existing sgt */ - if ((msm_obj->flags & MSM_BO_EXTBUF) && !(msm_obj->sgt)) { + if (((msm_obj->flags & MSM_BO_EXTBUF) && !(msm_obj->sgt)) + || reattach) { ret = msm_gem_delayed_import(obj); if (ret) { DRM_ERROR("delayed dma-buf import failed %d\n", diff --git a/drivers/gpu/drm/msm/msm_gem_vma.c b/drivers/gpu/drm/msm/msm_gem_vma.c index ec007fd71674..58fe9bc328d6 100644 --- a/drivers/gpu/drm/msm/msm_gem_vma.c +++ b/drivers/gpu/drm/msm/msm_gem_vma.c @@ -318,6 +318,16 @@ msm_gem_map_vma(struct msm_gem_address_space *aspace, return -EINVAL; } +struct device *msm_gem_get_aspace_device(struct msm_gem_address_space *aspace) +{ + struct device *client_dev = NULL; + + if (aspace && aspace->mmu && aspace->mmu->funcs->get_dev) + client_dev = aspace->mmu->funcs->get_dev(aspace->mmu); + + return client_dev; +} + void msm_gem_add_obj_to_aspace_active_list( struct msm_gem_address_space *aspace, struct drm_gem_object *obj) diff --git a/drivers/gpu/drm/msm/msm_mmu.h b/drivers/gpu/drm/msm/msm_mmu.h index e76d42c5748e..ee6cbcd58079 100644 --- a/drivers/gpu/drm/msm/msm_mmu.h +++ b/drivers/gpu/drm/msm/msm_mmu.h @@ -53,6 +53,7 @@ struct msm_mmu_funcs { uint32_t dest_address, uint32_t size, int prot); int (*one_to_one_unmap)(struct msm_mmu *mmu, uint32_t dest_address, uint32_t size); + struct device *(*get_dev)(struct msm_mmu *mmu); }; struct msm_mmu { diff --git a/drivers/gpu/drm/msm/msm_smmu.c b/drivers/gpu/drm/msm/msm_smmu.c index 72c7caab4643..6ce641e5750d 100644 --- a/drivers/gpu/drm/msm/msm_smmu.c +++ b/drivers/gpu/drm/msm/msm_smmu.c @@ -211,6 +211,13 @@ static void msm_smmu_destroy(struct msm_mmu *mmu) kfree(smmu); } +struct device *msm_smmu_get_dev(struct msm_mmu *mmu) +{ + struct msm_smmu *smmu = to_msm_smmu(mmu); + + return smmu->client_dev; +} + static int msm_smmu_map_dma_buf(struct msm_mmu *mmu, struct sg_table *sgt, int dir, u32 flags) { @@ -292,6 +299,7 @@ static const struct msm_mmu_funcs funcs = { .set_attribute = msm_smmu_set_attribute, .one_to_one_map = msm_smmu_one_to_one_map, .one_to_one_unmap = msm_smmu_one_to_one_unmap, + .get_dev = msm_smmu_get_dev, }; static struct msm_smmu_domain msm_smmu_domains[MSM_SMMU_DOMAIN_MAX] = { -- GitLab From 2bd2fa5c7cd5670f1eb7b414a79e9fc6649b60f8 Mon Sep 17 00:00:00 2001 From: Jeevan Shriram Date: Thu, 12 Apr 2018 12:48:48 -0700 Subject: [PATCH 0349/1635] ARM: dts: msm: Add devicetree overlay files for sdmshrike Add support for devicetree overlay on sdmshrike target. Change-Id: I372d4e8d5cf2940c047c466e59bf7a918801b240 Signed-off-by: Jeevan Shriram --- arch/arm64/boot/dts/qcom/Makefile | 9 +++++++ .../boot/dts/qcom/sdmshrike-cdp-overlay.dts | 26 +++++++++++++++++++ .../boot/dts/qcom/sdmshrike-mtp-overlay.dts | 26 +++++++++++++++++++ arch/arm64/boot/dts/qcom/sdmshrike.dts | 22 ++++++++++++++++ arch/arm64/boot/dts/qcom/sdmshrike.dtsi | 3 ++- 5 files changed, 85 insertions(+), 1 deletion(-) create mode 100644 arch/arm64/boot/dts/qcom/sdmshrike-cdp-overlay.dts create mode 100644 arch/arm64/boot/dts/qcom/sdmshrike-mtp-overlay.dts create mode 100644 arch/arm64/boot/dts/qcom/sdmshrike.dts diff --git a/arch/arm64/boot/dts/qcom/Makefile b/arch/arm64/boot/dts/qcom/Makefile index 72bc792e22c7..148804cc0aef 100644 --- a/arch/arm64/boot/dts/qcom/Makefile +++ b/arch/arm64/boot/dts/qcom/Makefile @@ -36,9 +36,18 @@ dtb-$(CONFIG_ARCH_SM8150) += sm8150-rumi.dtb \ sm8150-v2-qrd.dtb endif +ifeq ($(CONFIG_BUILD_ARM64_DT_OVERLAY),y) + dtbo-$(CONFIG_ARCH_SDMSHRIKE) += \ + sdmshrike-cdp-overlay.dtbo \ + sdmshrike-mtp-overlay.dtbo + +sdmshrike-cdp-overlay.dtbo-base := sdmshrike.dtb +sdmshrike-mtp-overlay.dtbo-base := sdmshrike.dtb +else dtb-$(CONFIG_ARCH_SDMSHRIKE) += sdmshrike-rumi.dtb \ sdmshrike-mtp.dtb \ sdmshrike-cdp.dtb +endif dtb-$(CONFIG_ARCH_SDM640) += sdm640-rumi.dtb \ sdm640-mtp.dtb \ diff --git a/arch/arm64/boot/dts/qcom/sdmshrike-cdp-overlay.dts b/arch/arm64/boot/dts/qcom/sdmshrike-cdp-overlay.dts new file mode 100644 index 000000000000..5c9bb022d0fe --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdmshrike-cdp-overlay.dts @@ -0,0 +1,26 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/dts-v1/; +/plugin/; + +#include +#include +#include + +#include "sdmshrike-cdp.dtsi" + +/ { + model = "CDP"; + compatible = "qcom,sdmshrike-cdp", "qcom,sdmshrike", "qcom,cdp"; + qcom,board-id = <1 0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sdmshrike-mtp-overlay.dts b/arch/arm64/boot/dts/qcom/sdmshrike-mtp-overlay.dts new file mode 100644 index 000000000000..77e99892a90c --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdmshrike-mtp-overlay.dts @@ -0,0 +1,26 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/dts-v1/; +/plugin/; + +#include +#include +#include + +#include "sdmshrike-mtp.dtsi" + +/ { + model = "MTP"; + compatible = "qcom,sdmshrike-mtp", "qcom,sdmshrike", "qcom,mtp"; + qcom,board-id = <8 0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sdmshrike.dts b/arch/arm64/boot/dts/qcom/sdmshrike.dts new file mode 100644 index 000000000000..d6b8cc8035f2 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdmshrike.dts @@ -0,0 +1,22 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/dts-v1/; + +#include "sdmshrike.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDMSHRIKE SoC"; + compatible = "qcom,sdmshrike"; + qcom,pmic-name = "PM855"; + qcom,board-id = <0 0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sdmshrike.dtsi b/arch/arm64/boot/dts/qcom/sdmshrike.dtsi index dd9fb947ffc3..237be5bd59cd 100644 --- a/arch/arm64/boot/dts/qcom/sdmshrike.dtsi +++ b/arch/arm64/boot/dts/qcom/sdmshrike.dtsi @@ -25,7 +25,8 @@ / { model = "Qualcomm Technologies, Inc. SDMSHRIKE"; compatible = "qcom,sdmshrike"; - qcom,msm-id = <340 0x0>; + qcom,msm-name = "SDMSHRIKE"; + qcom,msm-id = <340 0x10000>; interrupt-parent = <&pdc>; aliases { -- GitLab From 23a53504675067042ef148372c6ddb13d628ef91 Mon Sep 17 00:00:00 2001 From: Mayank Rana Date: Wed, 28 Mar 2018 15:29:01 -0700 Subject: [PATCH 0350/1635] dwc3: core: Add ssp u3 u0 link state related quirk USB PHY (qmp super speed phy) is unable to consistently move between the u3 (p3)/u0(p0) states causing controller and phy link level issues resulting in device re-enumeration. Fix the issue by forcing qmp phy to move to P2 state always before moving to P0 from P3 state. Forcing by phy link state is done by enabling Ux_exit_in_Px (BIT:27) and P3ExSigP2 (BIT:10) of GUSB3PIPECTL register. Change-Id: I1edd6c77769d3139863413eed82f2b8b98b33d42 Signed-off-by: Mayank Rana --- Documentation/devicetree/bindings/usb/dwc3.txt | 2 ++ drivers/usb/dwc3/core.c | 6 ++++++ drivers/usb/dwc3/core.h | 2 ++ 3 files changed, 10 insertions(+) diff --git a/Documentation/devicetree/bindings/usb/dwc3.txt b/Documentation/devicetree/bindings/usb/dwc3.txt index 4c20233c5e98..b06acbd49b0d 100644 --- a/Documentation/devicetree/bindings/usb/dwc3.txt +++ b/Documentation/devicetree/bindings/usb/dwc3.txt @@ -48,6 +48,8 @@ Optional properties: from P0 to P1/P2/P3 without delay. - snps,dis-tx-ipgap-linecheck-quirk: when set, disable u2mac linestate check during HS transmit. + - snps,ssp-u3-u0-quirk: when set, core always changes PHY power state + to P2, before attempting a U3 exit handshake. - snps,is-utmi-l1-suspend: true when DWC3 asserts output signal utmi_l1_suspend_n, false when asserts utmi_sleep_n - snps,hird-threshold: HIRD threshold diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index 9198554e8755..b17afab8e01c 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -546,6 +546,10 @@ static int dwc3_phy_setup(struct dwc3 *dwc) if (dwc->dis_del_phy_power_chg_quirk) reg &= ~DWC3_GUSB3PIPECTL_DEPOCHANGE; + if (dwc->ssp_u3_u0_quirk) + reg |= (DWC3_GUSB3PIPECTL_UX_EXIT_PX | + DWC3_GUSB3PIPECTL_P3EXSIGP2); + dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg); reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0)); @@ -1039,6 +1043,8 @@ static void dwc3_get_properties(struct dwc3 *dwc) dwc->tx_de_emphasis_quirk = device_property_read_bool(dev, "snps,tx_de_emphasis_quirk"); + dwc->ssp_u3_u0_quirk = device_property_read_bool(dev, + "snps,ssp-u3-u0-quirk"); device_property_read_u8(dev, "snps,tx_de_emphasis", &tx_de_emphasis); device_property_read_string(dev, "snps,hsphy_interface", diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index 4c41a33c0b35..7aa21a905337 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -253,6 +253,7 @@ #define DWC3_GUSB3PIPECTL_DEP1P2P3_EN DWC3_GUSB3PIPECTL_DEP1P2P3(1) #define DWC3_GUSB3PIPECTL_DEPOCHANGE BIT(18) #define DWC3_GUSB3PIPECTL_SUSPHY BIT(17) +#define DWC3_GUSB3PIPECTL_P3EXSIGP2 BIT(10) #define DWC3_GUSB3PIPECTL_LFPSFILT BIT(9) #define DWC3_GUSB3PIPECTL_RX_DETOPOLL BIT(8) #define DWC3_GUSB3PIPECTL_TX_DEEPH_MASK DWC3_GUSB3PIPECTL_TX_DEEPH(3) @@ -1121,6 +1122,7 @@ struct dwc3 { unsigned dis_tx_ipgap_linecheck_quirk:1; unsigned tx_de_emphasis_quirk:1; + unsigned ssp_u3_u0_quirk:1; unsigned tx_de_emphasis:2; unsigned err_evt_seen:1; unsigned enable_bus_suspend:1; -- GitLab From 01230cef4f6650495c06427e134634847586bf3e Mon Sep 17 00:00:00 2001 From: Mayank Rana Date: Wed, 4 Apr 2018 17:11:50 -0700 Subject: [PATCH 0351/1635] ARM: dts: msm: Set snps,ssp-u3-u0-quirk on SM8150 Enable SSP suspend/resume related quirk with primary USB port on SM8150. Change-Id: I6a0539095f5b72ba6e325cfa4d04af0249f495ad Signed-off-by: Mayank Rana --- arch/arm64/boot/dts/qcom/sm8150-usb.dtsi | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/boot/dts/qcom/sm8150-usb.dtsi b/arch/arm64/boot/dts/qcom/sm8150-usb.dtsi index ccc4391910ed..8643eed8b09c 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-usb.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-usb.dtsi @@ -77,6 +77,7 @@ snps,has-lpm-erratum; snps,hird-threshold = /bits/ 8 <0x10>; snps,usb3_lpm_capable; + snps,ssp-u3-u0-quirk; usb-core-id = <0>; tx-fifo-resize; maximum-speed = "super-speed"; -- GitLab From 64e4647392afbab744bc5e1fb93928a5b20af498 Mon Sep 17 00:00:00 2001 From: "Isaac J. Manjarres" Date: Wed, 4 Apr 2018 14:36:14 -0700 Subject: [PATCH 0352/1635] ARM: dts: msm: Add initial device tree support for SM8150P Introduce DTS files to support APQ version of SM8150 chipset. Change-Id: Id5af8b8973fd01fb0663f4a2fcbfdc4b2857edab Signed-off-by: Isaac J. Manjarres --- .../devicetree/bindings/arm/msm/msm.txt | 3 +++ arch/arm64/boot/dts/qcom/Makefile | 13 ++++++++- .../boot/dts/qcom/sm8150p-cdp-overlay.dts | 27 +++++++++++++++++++ arch/arm64/boot/dts/qcom/sm8150p-cdp.dts | 22 +++++++++++++++ .../boot/dts/qcom/sm8150p-mtp-overlay.dts | 27 +++++++++++++++++++ arch/arm64/boot/dts/qcom/sm8150p-mtp.dts | 22 +++++++++++++++ .../boot/dts/qcom/sm8150p-qrd-overlay.dts | 27 +++++++++++++++++++ arch/arm64/boot/dts/qcom/sm8150p-qrd.dts | 22 +++++++++++++++ arch/arm64/boot/dts/qcom/sm8150p-v2-cdp.dts | 22 +++++++++++++++ arch/arm64/boot/dts/qcom/sm8150p-v2-mtp.dts | 22 +++++++++++++++ arch/arm64/boot/dts/qcom/sm8150p-v2-qrd.dts | 22 +++++++++++++++ arch/arm64/boot/dts/qcom/sm8150p-v2.dts | 22 +++++++++++++++ arch/arm64/boot/dts/qcom/sm8150p-v2.dtsi | 19 +++++++++++++ arch/arm64/boot/dts/qcom/sm8150p.dts | 22 +++++++++++++++ arch/arm64/boot/dts/qcom/sm8150p.dtsi | 19 +++++++++++++ 15 files changed, 310 insertions(+), 1 deletion(-) create mode 100644 arch/arm64/boot/dts/qcom/sm8150p-cdp-overlay.dts create mode 100644 arch/arm64/boot/dts/qcom/sm8150p-cdp.dts create mode 100644 arch/arm64/boot/dts/qcom/sm8150p-mtp-overlay.dts create mode 100644 arch/arm64/boot/dts/qcom/sm8150p-mtp.dts create mode 100644 arch/arm64/boot/dts/qcom/sm8150p-qrd-overlay.dts create mode 100644 arch/arm64/boot/dts/qcom/sm8150p-qrd.dts create mode 100644 arch/arm64/boot/dts/qcom/sm8150p-v2-cdp.dts create mode 100644 arch/arm64/boot/dts/qcom/sm8150p-v2-mtp.dts create mode 100644 arch/arm64/boot/dts/qcom/sm8150p-v2-qrd.dts create mode 100644 arch/arm64/boot/dts/qcom/sm8150p-v2.dts create mode 100644 arch/arm64/boot/dts/qcom/sm8150p-v2.dtsi create mode 100644 arch/arm64/boot/dts/qcom/sm8150p.dts create mode 100644 arch/arm64/boot/dts/qcom/sm8150p.dtsi diff --git a/Documentation/devicetree/bindings/arm/msm/msm.txt b/Documentation/devicetree/bindings/arm/msm/msm.txt index 19a77085ffab..cfae9a1400ff 100644 --- a/Documentation/devicetree/bindings/arm/msm/msm.txt +++ b/Documentation/devicetree/bindings/arm/msm/msm.txt @@ -132,6 +132,9 @@ compatible = "qcom,sm8150-rumi" compatible = "qcom,sm8150-mtp" compatible = "qcom,sm8150-cdp" compatible = "qcom,sm8150-qrd" +compatible = "qcom,sm8150p-cdp" +compatible = "qcom,sm8150p-mtp" +compatible = "qcom,sm8150p-qrd" compatible = "qcom,sdmshrike-rumi" compatible = "qcom,sdmshrike-mtp" compatible = "qcom,sdmshrike-cdp" diff --git a/arch/arm64/boot/dts/qcom/Makefile b/arch/arm64/boot/dts/qcom/Makefile index 72bc792e22c7..a7553f9998c2 100644 --- a/arch/arm64/boot/dts/qcom/Makefile +++ b/arch/arm64/boot/dts/qcom/Makefile @@ -16,6 +16,9 @@ ifeq ($(CONFIG_BUILD_ARM64_DT_OVERLAY),y) sm8150-mtp-overlay.dtbo \ sm8150-rumi-overlay.dtbo \ sm8150-qrd-overlay.dtbo \ + sm8150p-cdp-overlay.dtbo \ + sm8150p-mtp-overlay.dtbo \ + sm8150p-qrd-overlay.dtbo \ sm8150-sdx50m-cdp-overlay.dtbo \ sm8150-sdx50m-mtp-overlay.dtbo @@ -25,6 +28,8 @@ sm8150-rumi-overlay.dtbo-base := sm8150.dtb sm8150-v2.dtb sm8150-qrd-overlay.dtbo-base := sm8150.dtb sm8150-v2.dtb sm8150-sdx50m-cdp-overlay.dtbo-base := sm8150.dtb sm8150-v2.dtb sm8150-sdx50m-mtp-overlay.dtbo-base := sm8150.dtb sm8150-v2.dtb +sm8150p-mtp-overlay.dtbo-base := sm8150p.dtb sm8150p-v2.dtb +sm8150p-qrd-overlay.dtbo-base := sm8150p.dtb sm8150p-v2.dtb else dtb-$(CONFIG_ARCH_SM8150) += sm8150-rumi.dtb \ sm8150-mtp.dtb \ @@ -33,7 +38,13 @@ dtb-$(CONFIG_ARCH_SM8150) += sm8150-rumi.dtb \ sm8150-v2-rumi.dtb \ sm8150-v2-mtp.dtb \ sm8150-v2-cdp.dtb \ - sm8150-v2-qrd.dtb + sm8150-v2-qrd.dtb \ + sm8150p-mtp.dtb \ + sm8150p-cdp.dtb \ + sm8150p-qrd.dtb \ + sm8150p-v2-mtp.dtb \ + sm8150p-v2-cdp.dtb \ + sm8150p-v2-qrd.dtb endif dtb-$(CONFIG_ARCH_SDMSHRIKE) += sdmshrike-rumi.dtb \ diff --git a/arch/arm64/boot/dts/qcom/sm8150p-cdp-overlay.dts b/arch/arm64/boot/dts/qcom/sm8150p-cdp-overlay.dts new file mode 100644 index 000000000000..ee12483bfb65 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sm8150p-cdp-overlay.dts @@ -0,0 +1,27 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/dts-v1/; +/plugin/; + +#include +#include +#include +#include + +#include "sm8150-cdp.dtsi" + +/ { + model = "CDP"; + compatible = "qcom,sm8150p-cdp", "qcom,sm8150p", "qcom,cdp"; + qcom,board-id = <1 0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sm8150p-cdp.dts b/arch/arm64/boot/dts/qcom/sm8150p-cdp.dts new file mode 100644 index 000000000000..0020b813b64d --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sm8150p-cdp.dts @@ -0,0 +1,22 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/dts-v1/; + +#include "sm8150p.dtsi" +#include "sm8150-cdp.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SM8150P CDP"; + compatible = "qcom,sm8150p-cdp", "qcom,sm8150p", "qcom,cdp"; + qcom,board-id = <1 0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sm8150p-mtp-overlay.dts b/arch/arm64/boot/dts/qcom/sm8150p-mtp-overlay.dts new file mode 100644 index 000000000000..d435721f3863 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sm8150p-mtp-overlay.dts @@ -0,0 +1,27 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/dts-v1/; +/plugin/; + +#include +#include +#include +#include + +#include "sm8150-mtp.dtsi" + +/ { + model = "MTP"; + compatible = "qcom,sm8150p-mtp", "qcom,sm8150p", "qcom,mtp"; + qcom,board-id = <8 0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sm8150p-mtp.dts b/arch/arm64/boot/dts/qcom/sm8150p-mtp.dts new file mode 100644 index 000000000000..9a7fd33ae9b2 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sm8150p-mtp.dts @@ -0,0 +1,22 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/dts-v1/; + +#include "sm8150p.dtsi" +#include "sm8150-mtp.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SM8150P MTP"; + compatible = "qcom,sm8150p-mtp", "qcom,sm8150p", "qcom,mtp"; + qcom,board-id = <8 0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sm8150p-qrd-overlay.dts b/arch/arm64/boot/dts/qcom/sm8150p-qrd-overlay.dts new file mode 100644 index 000000000000..b8ea18b755dc --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sm8150p-qrd-overlay.dts @@ -0,0 +1,27 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/dts-v1/; +/plugin/; + +#include +#include +#include +#include + +#include "sm8150-qrd.dtsi" + +/ { + model = "QRD"; + compatible = "qcom,sm8150p-qrd", "qcom,sm8150p", "qcom,qrd"; + qcom,board-id = <11 0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sm8150p-qrd.dts b/arch/arm64/boot/dts/qcom/sm8150p-qrd.dts new file mode 100644 index 000000000000..50039ff12ad8 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sm8150p-qrd.dts @@ -0,0 +1,22 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/dts-v1/; + +#include "sm8150p.dtsi" +#include "sm8150-qrd.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SM8150P QRD"; + compatible = "qcom,sm8150p-qrd", "qcom,sm8150p", "qcom,qrd"; + qcom,board-id = <11 0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sm8150p-v2-cdp.dts b/arch/arm64/boot/dts/qcom/sm8150p-v2-cdp.dts new file mode 100644 index 000000000000..70ff898cfff4 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sm8150p-v2-cdp.dts @@ -0,0 +1,22 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/dts-v1/; + +#include "sm8150p-v2.dtsi" +#include "sm8150-cdp.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SM8150P V2 CDP"; + compatible = "qcom,sm8150p-cdp", "qcom,sm8150p", "qcom,cdp"; + qcom,board-id = <1 0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sm8150p-v2-mtp.dts b/arch/arm64/boot/dts/qcom/sm8150p-v2-mtp.dts new file mode 100644 index 000000000000..a799969fc5a9 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sm8150p-v2-mtp.dts @@ -0,0 +1,22 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/dts-v1/; + +#include "sm8150p-v2.dtsi" +#include "sm8150-mtp.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SM8150P V2 MTP"; + compatible = "qcom,sm8150p-mtp", "qcom,sm8150p", "qcom,mtp"; + qcom,board-id = <8 0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sm8150p-v2-qrd.dts b/arch/arm64/boot/dts/qcom/sm8150p-v2-qrd.dts new file mode 100644 index 000000000000..9e2b45317c81 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sm8150p-v2-qrd.dts @@ -0,0 +1,22 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/dts-v1/; + +#include "sm8150p-v2.dtsi" +#include "sm8150-qrd.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SM8150P V2 QRD"; + compatible = "qcom,sm8150p-qrd", "qcom,sm8150p", "qcom,qrd"; + qcom,board-id = <11 0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sm8150p-v2.dts b/arch/arm64/boot/dts/qcom/sm8150p-v2.dts new file mode 100644 index 000000000000..78791b7a3cc7 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sm8150p-v2.dts @@ -0,0 +1,22 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/dts-v1/; + +#include "sm8150p-v2.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SM8150P v2 SoC"; + compatible = "qcom,sm8150p"; + qcom,pmic-name = "PM855"; + qcom,board-id = <0 0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sm8150p-v2.dtsi b/arch/arm64/boot/dts/qcom/sm8150p-v2.dtsi new file mode 100644 index 000000000000..4351f650b1ea --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sm8150p-v2.dtsi @@ -0,0 +1,19 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "sm8150-v2.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SM8150P v2"; + qcom,msm-name = "SM8150P v2"; + qcom,msm-id = <356 0x20000>; +}; diff --git a/arch/arm64/boot/dts/qcom/sm8150p.dts b/arch/arm64/boot/dts/qcom/sm8150p.dts new file mode 100644 index 000000000000..d069c38c17f3 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sm8150p.dts @@ -0,0 +1,22 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/dts-v1/; + +#include "sm8150p.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SM8150P v1 SoC"; + compatible = "qcom,sm8150p"; + qcom,pmic-name = "PM855"; + qcom,board-id = <0 0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sm8150p.dtsi b/arch/arm64/boot/dts/qcom/sm8150p.dtsi new file mode 100644 index 000000000000..87632a0933e0 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sm8150p.dtsi @@ -0,0 +1,19 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "sm8150.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SM8150P v1"; + qcom,msm-name = "SM8150P v1"; + qcom,msm-id = <356 0x10000>; +}; -- GitLab From 9fd58eb73c883bd8413c43ec1b00fa48cb5129ec Mon Sep 17 00:00:00 2001 From: Deepak Katragadda Date: Tue, 10 Apr 2018 10:53:19 -0700 Subject: [PATCH 0353/1635] clk: qcom: gdsc: Fix issue with dereferencing NULL pointer in gdsc APIs Fix the issue with deferencing the rdev structure for the GDSC prior to it being populated. Replace the qcom,vote-parent-supply-voltage property with vdd_parent-supply and use the regulator handle that's returned from calling regulator_get for the parent regulator directly. Change-Id: I9a80cbeb4fd88b718e6e7509d8868d965253ae5e Signed-off-by: Deepak Katragadda --- .../bindings/regulator/gdsc-regulator.txt | 9 ++-- arch/arm64/boot/dts/qcom/sdmshrike.dtsi | 26 +++++------ arch/arm64/boot/dts/qcom/sm8150.dtsi | 22 ++++----- drivers/clk/qcom/gdsc-regulator.c | 45 +++++++++++-------- 4 files changed, 55 insertions(+), 47 deletions(-) diff --git a/Documentation/devicetree/bindings/regulator/gdsc-regulator.txt b/Documentation/devicetree/bindings/regulator/gdsc-regulator.txt index 0927eee292bf..19a9d35978c6 100644 --- a/Documentation/devicetree/bindings/regulator/gdsc-regulator.txt +++ b/Documentation/devicetree/bindings/regulator/gdsc-regulator.txt @@ -50,10 +50,11 @@ Optional properties: to enable. - qcom,reset-aon-logic: If present, the GPU DEMET cells need to be reset while enabling the GX GDSC. - - qcom,vote-parent-supply-voltage: If present, need to vote for a minimum - operational voltage (LOW_SVS) on the GDSC parent - regulator prior to configuring it. The vote is removed - once the GDSC FSM has latched on to the new state. + - vdd_parent-supply: phandle to the regulator that this GDSC gates. If + present, need to vote for a minimum operational voltage + (LOW_SVS) on the GDSC parent regulator prior to + configuring it. The vote is removed once the GDSC FSM + has latched on to the new state. - resets: reset specifier pair consisting of phandle for the reset controller and reset lines used by this controller. These can be supplied only if we support qcom,skip-logic-collapse. diff --git a/arch/arm64/boot/dts/qcom/sdmshrike.dtsi b/arch/arm64/boot/dts/qcom/sdmshrike.dtsi index 50d45696f779..54103d76eae1 100644 --- a/arch/arm64/boot/dts/qcom/sdmshrike.dtsi +++ b/arch/arm64/boot/dts/qcom/sdmshrike.dtsi @@ -1012,7 +1012,7 @@ clock-names = "ahb_clk"; clocks = <&clock_gcc GCC_CAMERA_AHB_CLK>; parent-supply = <&VDD_MMCX_LEVEL>; - qcom,vote-parent-supply-voltage; + vdd_parent-supply = <&VDD_MMCX_LEVEL>; status = "ok"; }; @@ -1020,7 +1020,7 @@ clock-names = "ahb_clk"; clocks = <&clock_gcc GCC_CAMERA_AHB_CLK>; parent-supply = <&VDD_MMCX_LEVEL>; - qcom,vote-parent-supply-voltage; + vdd_parent-supply = <&VDD_MMCX_LEVEL>; status = "ok"; }; @@ -1028,7 +1028,7 @@ clock-names = "ahb_clk"; clocks = <&clock_gcc GCC_CAMERA_AHB_CLK>; parent-supply = <&VDD_MMCX_LEVEL>; - qcom,vote-parent-supply-voltage; + vdd_parent-supply = <&VDD_MMCX_LEVEL>; status = "ok"; }; @@ -1036,7 +1036,7 @@ clock-names = "ahb_clk"; clocks = <&clock_gcc GCC_CAMERA_AHB_CLK>; parent-supply = <&VDD_MMCX_LEVEL>; - qcom,vote-parent-supply-voltage; + vdd_parent-supply = <&VDD_MMCX_LEVEL>; status = "ok"; }; @@ -1044,7 +1044,7 @@ clock-names = "ahb_clk"; clocks = <&clock_gcc GCC_CAMERA_AHB_CLK>; parent-supply = <&VDD_MMCX_LEVEL>; - qcom,vote-parent-supply-voltage; + vdd_parent-supply = <&VDD_MMCX_LEVEL>; status = "ok"; }; @@ -1052,7 +1052,7 @@ clock-names = "ahb_clk"; clocks = <&clock_gcc GCC_CAMERA_AHB_CLK>; parent-supply = <&VDD_MMCX_LEVEL>; - qcom,vote-parent-supply-voltage; + vdd_parent-supply = <&VDD_MMCX_LEVEL>; status = "ok"; }; @@ -1060,7 +1060,7 @@ clock-names = "ahb_clk"; clocks = <&clock_gcc GCC_CAMERA_AHB_CLK>; parent-supply = <&VDD_MMCX_LEVEL>; - qcom,vote-parent-supply-voltage; + vdd_parent-supply = <&VDD_MMCX_LEVEL>; status = "ok"; }; @@ -1068,7 +1068,7 @@ clock-names = "ahb_clk"; clocks = <&clock_gcc GCC_CAMERA_AHB_CLK>; parent-supply = <&VDD_MMCX_LEVEL>; - qcom,vote-parent-supply-voltage; + vdd_parent-supply = <&VDD_MMCX_LEVEL>; status = "ok"; }; @@ -1076,7 +1076,7 @@ clock-names = "ahb_clk"; clocks = <&clock_gcc GCC_DISP_AHB_CLK>; parent-supply = <&VDD_MMCX_LEVEL>; - qcom,vote-parent-supply-voltage; + vdd_parent-supply = <&VDD_MMCX_LEVEL>; status = "ok"; }; @@ -1086,7 +1086,7 @@ &gpu_gx_gdsc { parent-supply = <&pm855_1_s10_level>; - qcom,vote-parent-supply-voltage; + vdd_parent-supply = <&pm855_1_s10_level>; status = "ok"; }; @@ -1094,7 +1094,7 @@ clock-names = "ahb_clk"; clocks = <&clock_gcc GCC_VIDEO_AHB_CLK>; parent-supply = <&VDD_MMCX_LEVEL>; - qcom,vote-parent-supply-voltage; + vdd_parent-supply = <&VDD_MMCX_LEVEL>; status = "ok"; }; @@ -1102,7 +1102,7 @@ clock-names = "ahb_clk"; clocks = <&clock_gcc GCC_VIDEO_AHB_CLK>; parent-supply = <&VDD_MMCX_LEVEL>; - qcom,vote-parent-supply-voltage; + vdd_parent-supply = <&VDD_MMCX_LEVEL>; status = "ok"; }; @@ -1110,7 +1110,7 @@ clock-names = "ahb_clk"; clocks = <&clock_gcc GCC_VIDEO_AHB_CLK>; parent-supply = <&VDD_MMCX_LEVEL>; - qcom,vote-parent-supply-voltage; + vdd_parent-supply = <&VDD_MMCX_LEVEL>; status = "ok"; }; diff --git a/arch/arm64/boot/dts/qcom/sm8150.dtsi b/arch/arm64/boot/dts/qcom/sm8150.dtsi index 82541b7795ad..dfc08cfe0837 100644 --- a/arch/arm64/boot/dts/qcom/sm8150.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150.dtsi @@ -3234,7 +3234,7 @@ clock-names = "ahb_clk"; clocks = <&clock_gcc GCC_CAMERA_AHB_CLK>; parent-supply = <&VDD_MMCX_LEVEL>; - qcom,vote-parent-supply-voltage; + vdd_parent-supply = <&VDD_MMCX_LEVEL>; status = "ok"; }; @@ -3242,7 +3242,7 @@ clock-names = "ahb_clk"; clocks = <&clock_gcc GCC_CAMERA_AHB_CLK>; parent-supply = <&VDD_MMCX_LEVEL>; - qcom,vote-parent-supply-voltage; + vdd_parent-supply = <&VDD_MMCX_LEVEL>; status = "ok"; }; @@ -3250,7 +3250,7 @@ clock-names = "ahb_clk"; clocks = <&clock_gcc GCC_CAMERA_AHB_CLK>; parent-supply = <&VDD_MMCX_LEVEL>; - qcom,vote-parent-supply-voltage; + vdd_parent-supply = <&VDD_MMCX_LEVEL>; status = "ok"; }; @@ -3258,7 +3258,7 @@ clock-names = "ahb_clk"; clocks = <&clock_gcc GCC_CAMERA_AHB_CLK>; parent-supply = <&VDD_MMCX_LEVEL>; - qcom,vote-parent-supply-voltage; + vdd_parent-supply = <&VDD_MMCX_LEVEL>; status = "ok"; }; @@ -3266,7 +3266,7 @@ clock-names = "ahb_clk"; clocks = <&clock_gcc GCC_CAMERA_AHB_CLK>; parent-supply = <&VDD_MMCX_LEVEL>; - qcom,vote-parent-supply-voltage; + vdd_parent-supply = <&VDD_MMCX_LEVEL>; status = "ok"; }; @@ -3274,7 +3274,7 @@ clock-names = "ahb_clk"; clocks = <&clock_gcc GCC_CAMERA_AHB_CLK>; parent-supply = <&VDD_MMCX_LEVEL>; - qcom,vote-parent-supply-voltage; + vdd_parent-supply = <&VDD_MMCX_LEVEL>; status = "ok"; }; @@ -3282,7 +3282,7 @@ clock-names = "ahb_clk"; clocks = <&clock_gcc GCC_DISP_AHB_CLK>; parent-supply = <&VDD_MMCX_LEVEL>; - qcom,vote-parent-supply-voltage; + vdd_parent-supply = <&VDD_MMCX_LEVEL>; status = "ok"; }; @@ -3292,7 +3292,7 @@ &gpu_gx_gdsc { parent-supply = <&pm855l_s2_level>; - qcom,vote-parent-supply-voltage; + vdd_parent-supply = <&pm855l_s2_level>; status = "ok"; }; @@ -3300,7 +3300,7 @@ clock-names = "ahb_clk"; clocks = <&clock_gcc GCC_VIDEO_AHB_CLK>; parent-supply = <&VDD_MMCX_LEVEL>; - qcom,vote-parent-supply-voltage; + vdd_parent-supply = <&VDD_MMCX_LEVEL>; status = "ok"; }; @@ -3308,7 +3308,7 @@ clock-names = "ahb_clk"; clocks = <&clock_gcc GCC_VIDEO_AHB_CLK>; parent-supply = <&VDD_MMCX_LEVEL>; - qcom,vote-parent-supply-voltage; + vdd_parent-supply = <&VDD_MMCX_LEVEL>; status = "ok"; }; @@ -3316,7 +3316,7 @@ clock-names = "ahb_clk"; clocks = <&clock_gcc GCC_VIDEO_AHB_CLK>; parent-supply = <&VDD_MMCX_LEVEL>; - qcom,vote-parent-supply-voltage; + vdd_parent-supply = <&VDD_MMCX_LEVEL>; status = "ok"; }; diff --git a/drivers/clk/qcom/gdsc-regulator.c b/drivers/clk/qcom/gdsc-regulator.c index 986002050a51..8d845aa9f6b4 100644 --- a/drivers/clk/qcom/gdsc-regulator.c +++ b/drivers/clk/qcom/gdsc-regulator.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -60,6 +60,7 @@ struct gdsc { struct regmap *hw_ctrl; struct regmap *sw_reset; struct clk **clocks; + struct regulator *parent_regulator; struct reset_control **reset_clocks; bool toggle_mem; bool toggle_periph; @@ -71,7 +72,6 @@ struct gdsc { bool is_gdsc_enabled; bool allow_clear; bool reset_aon; - bool vote_supply_voltage; int clock_count; int reset_count; int root_clk_idx; @@ -170,8 +170,8 @@ static int gdsc_enable(struct regulator_dev *rdev) mutex_lock(&gdsc_seq_lock); - if (sc->vote_supply_voltage) { - ret = regulator_set_voltage(sc->rdev->supply, + if (sc->parent_regulator) { + ret = regulator_set_voltage(sc->parent_regulator, RPMH_REGULATOR_LEVEL_LOW_SVS, INT_MAX); if (ret) { mutex_unlock(&gdsc_seq_lock); @@ -316,8 +316,8 @@ static int gdsc_enable(struct regulator_dev *rdev) sc->is_gdsc_enabled = true; end: - if (sc->vote_supply_voltage) - regulator_set_voltage(sc->rdev->supply, 0, INT_MAX); + if (sc->parent_regulator) + regulator_set_voltage(sc->parent_regulator, 0, INT_MAX); mutex_unlock(&gdsc_seq_lock); @@ -332,8 +332,8 @@ static int gdsc_disable(struct regulator_dev *rdev) mutex_lock(&gdsc_seq_lock); - if (sc->vote_supply_voltage) { - ret = regulator_set_voltage(sc->rdev->supply, + if (sc->parent_regulator) { + ret = regulator_set_voltage(sc->parent_regulator, RPMH_REGULATOR_LEVEL_LOW_SVS, INT_MAX); if (ret) { mutex_unlock(&gdsc_seq_lock); @@ -398,8 +398,8 @@ static int gdsc_disable(struct regulator_dev *rdev) if ((sc->is_gdsc_enabled && sc->root_en) || sc->force_root_en) clk_disable_unprepare(sc->clocks[sc->root_clk_idx]); - if (sc->vote_supply_voltage) - regulator_set_voltage(sc->rdev->supply, 0, INT_MAX); + if (sc->parent_regulator) + regulator_set_voltage(sc->parent_regulator, 0, INT_MAX); sc->is_gdsc_enabled = false; @@ -431,8 +431,8 @@ static int gdsc_set_mode(struct regulator_dev *rdev, unsigned int mode) mutex_lock(&gdsc_seq_lock); - if (sc->vote_supply_voltage) { - ret = regulator_set_voltage(sc->rdev->supply, + if (sc->parent_regulator) { + ret = regulator_set_voltage(sc->parent_regulator, RPMH_REGULATOR_LEVEL_LOW_SVS, INT_MAX); if (ret) { mutex_unlock(&gdsc_seq_lock); @@ -483,8 +483,8 @@ static int gdsc_set_mode(struct regulator_dev *rdev, unsigned int mode) break; } - if (sc->vote_supply_voltage) - regulator_set_voltage(sc->rdev->supply, 0, INT_MAX); + if (sc->parent_regulator) + regulator_set_voltage(sc->parent_regulator, 0, INT_MAX); mutex_unlock(&gdsc_seq_lock); @@ -602,8 +602,18 @@ static int gdsc_probe(struct platform_device *pdev) sc->force_root_en = of_property_read_bool(pdev->dev.of_node, "qcom,force-enable-root-clk"); - sc->vote_supply_voltage = of_property_read_bool(pdev->dev.of_node, - "qcom,vote-parent-supply-voltage"); + if (of_find_property(pdev->dev.of_node, "vdd_parent-supply", NULL)) { + sc->parent_regulator = devm_regulator_get(&pdev->dev, + "vdd_parent"); + if (IS_ERR(sc->parent_regulator)) { + ret = PTR_ERR(sc->parent_regulator); + if (ret != -EPROBE_DEFER) + dev_err(&pdev->dev, + "Unable to get vdd_parent regulator, err: %d\n", + ret); + return ret; + } + } for (i = 0; i < sc->clock_count; i++) { const char *clock_name; @@ -749,9 +759,6 @@ static int gdsc_probe(struct platform_device *pdev) return PTR_ERR(sc->rdev); } - if (!sc->rdev->supply) - sc->vote_supply_voltage = false; - return 0; } -- GitLab From 1a17cb597dc6aae77a01657d995690eec285b797 Mon Sep 17 00:00:00 2001 From: Sujeev Dias Date: Fri, 9 Feb 2018 22:15:57 -0800 Subject: [PATCH 0354/1635] mhi_bus: dev: uci: add user space interface driver This module allows user space clients to transfer data between external modem and host using standard file operations. CRs-Fixed: 2204910 Change-Id: I46af0e99a68836e50cc4da4ad3ab85e248d4af4f Signed-off-by: Sujeev Dias --- drivers/bus/mhi/devices/Kconfig | 9 + drivers/bus/mhi/devices/Makefile | 1 + drivers/bus/mhi/devices/mhi_uci.c | 693 ++++++++++++++++++++++++++++++ 3 files changed, 703 insertions(+) create mode 100644 drivers/bus/mhi/devices/mhi_uci.c diff --git a/drivers/bus/mhi/devices/Kconfig b/drivers/bus/mhi/devices/Kconfig index 40f964d4c522..83b96733cc35 100644 --- a/drivers/bus/mhi/devices/Kconfig +++ b/drivers/bus/mhi/devices/Kconfig @@ -7,4 +7,13 @@ config MHI_NETDEV MHI based net device driver for transferring IP traffic between host and modem. By enabling this driver, clients can transfer data using standard network interface. + +config MHI_UCI + tristate "MHI UCI" + depends on MHI_BUS + help + MHI based uci driver is for transferring data between host and + modem using standard file operations from user space. Open, read, + write, ioctl, and close operations are supported by this driver. + endmenu diff --git a/drivers/bus/mhi/devices/Makefile b/drivers/bus/mhi/devices/Makefile index ee12a642bc73..300eed18af8a 100644 --- a/drivers/bus/mhi/devices/Makefile +++ b/drivers/bus/mhi/devices/Makefile @@ -1 +1,2 @@ obj-$(CONFIG_MHI_NETDEV) +=mhi_netdev.o +obj-$(CONFIG_MHI_UCI) +=mhi_uci.o diff --git a/drivers/bus/mhi/devices/mhi_uci.c b/drivers/bus/mhi/devices/mhi_uci.c new file mode 100644 index 000000000000..c8a3fdbfa917 --- /dev/null +++ b/drivers/bus/mhi/devices/mhi_uci.c @@ -0,0 +1,693 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DEVICE_NAME "mhi" +#define MHI_UCI_DRIVER_NAME "mhi_uci" + +struct uci_chan { + wait_queue_head_t wq; + spinlock_t lock; + struct list_head pending; /* user space waiting to read */ + struct uci_buf *cur_buf; /* current buffer user space reading */ + size_t rx_size; +}; + +struct uci_buf { + void *data; + size_t len; + struct list_head node; +}; + +struct uci_dev { + struct list_head node; + dev_t devt; + struct device *dev; + struct mhi_device *mhi_dev; + const char *chan; + struct mutex mutex; /* sync open and close */ + struct uci_chan ul_chan; + struct uci_chan dl_chan; + size_t mtu; + int ref_count; + bool enabled; + void *ipc_log; +}; + +struct mhi_uci_drv { + struct list_head head; + struct mutex lock; + struct class *class; + int major; + dev_t dev_t; +}; + +enum MHI_DEBUG_LEVEL msg_lvl = MHI_MSG_LVL_ERROR; + +#ifdef CONFIG_MHI_DEBUG + +#define IPC_LOG_LVL (MHI_MSG_LVL_VERBOSE) +#define MHI_UCI_IPC_LOG_PAGES (25) + +#else + +#define IPC_LOG_LVL (MHI_MSG_LVL_ERROR) +#define MHI_UCI_IPC_LOG_PAGES (1) + +#endif + +#ifdef CONFIG_MHI_DEBUG + +#define MSG_VERB(fmt, ...) do { \ + if (msg_lvl <= MHI_MSG_LVL_VERBOSE) \ + pr_err("[D][%s] " fmt, __func__, ##__VA_ARGS__); \ + if (uci_dev->ipc_log && (IPC_LOG_LVL <= MHI_MSG_LVL_VERBOSE)) \ + ipc_log_string(uci_dev->ipc_log, "[D][%s] " fmt, \ + __func__, ##__VA_ARGS__); \ + } while (0) + +#else + +#define MSG_VERB(fmt, ...) + +#endif + +#define MSG_LOG(fmt, ...) do { \ + if (msg_lvl <= MHI_MSG_LVL_INFO) \ + pr_err("[I][%s] " fmt, __func__, ##__VA_ARGS__); \ + if (uci_dev->ipc_log && (IPC_LOG_LVL <= MHI_MSG_LVL_INFO)) \ + ipc_log_string(uci_dev->ipc_log, "[I][%s] " fmt, \ + __func__, ##__VA_ARGS__); \ + } while (0) + +#define MSG_ERR(fmt, ...) do { \ + if (msg_lvl <= MHI_MSG_LVL_ERROR) \ + pr_err("[E][%s] " fmt, __func__, ##__VA_ARGS__); \ + if (uci_dev->ipc_log && (IPC_LOG_LVL <= MHI_MSG_LVL_ERROR)) \ + ipc_log_string(uci_dev->ipc_log, "[E][%s] " fmt, \ + __func__, ##__VA_ARGS__); \ + } while (0) + +#define MAX_UCI_DEVICES (64) + +static DECLARE_BITMAP(uci_minors, MAX_UCI_DEVICES); +static struct mhi_uci_drv mhi_uci_drv; + +static int mhi_queue_inbound(struct uci_dev *uci_dev) +{ + struct mhi_device *mhi_dev = uci_dev->mhi_dev; + int nr_trbs = mhi_get_no_free_descriptors(mhi_dev, DMA_FROM_DEVICE); + size_t mtu = uci_dev->mtu; + void *buf; + struct uci_buf *uci_buf; + int ret = -EIO, i; + + for (i = 0; i < nr_trbs; i++) { + buf = kmalloc(mtu + sizeof(*uci_buf), GFP_KERNEL); + if (!buf) + return -ENOMEM; + + uci_buf = buf + mtu; + uci_buf->data = buf; + + MSG_VERB("Allocated buf %d of %d size %ld\n", i, nr_trbs, mtu); + + ret = mhi_queue_transfer(mhi_dev, DMA_FROM_DEVICE, buf, mtu, + MHI_EOT); + if (ret) { + kfree(buf); + MSG_ERR("Failed to queue buffer %d\n", i); + return ret; + } + } + + return ret; +} + +static long mhi_uci_ioctl(struct file *file, + unsigned int cmd, + unsigned long arg) +{ + struct uci_dev *uci_dev = file->private_data; + struct mhi_device *mhi_dev = uci_dev->mhi_dev; + long ret = -ERESTARTSYS; + + mutex_lock(&uci_dev->mutex); + if (uci_dev->enabled) + ret = mhi_ioctl(mhi_dev, cmd, arg); + mutex_unlock(&uci_dev->mutex); + + return ret; +} + +static int mhi_uci_release(struct inode *inode, struct file *file) +{ + struct uci_dev *uci_dev = file->private_data; + + mutex_lock(&uci_dev->mutex); + uci_dev->ref_count--; + if (!uci_dev->ref_count) { + struct uci_buf *itr, *tmp; + struct uci_chan *uci_chan; + + MSG_LOG("Last client left, closing node\n"); + + if (uci_dev->enabled) + mhi_unprepare_from_transfer(uci_dev->mhi_dev); + + /* clean inbound channel */ + uci_chan = &uci_dev->dl_chan; + list_for_each_entry_safe(itr, tmp, &uci_chan->pending, node) { + list_del(&itr->node); + kfree(itr->data); + } + if (uci_chan->cur_buf) + kfree(uci_chan->cur_buf->data); + + uci_chan->cur_buf = NULL; + + if (!uci_dev->enabled) { + MSG_LOG("Node is deleted, freeing dev node\n"); + mutex_unlock(&uci_dev->mutex); + mutex_destroy(&uci_dev->mutex); + clear_bit(MINOR(uci_dev->devt), uci_minors); + kfree(uci_dev); + return 0; + } + } + + mutex_unlock(&uci_dev->mutex); + + MSG_LOG("exit: ref_count:%d\n", uci_dev->ref_count); + + return 0; +} + +static unsigned int mhi_uci_poll(struct file *file, poll_table *wait) +{ + struct uci_dev *uci_dev = file->private_data; + struct mhi_device *mhi_dev = uci_dev->mhi_dev; + struct uci_chan *uci_chan; + unsigned int mask = 0; + + poll_wait(file, &uci_dev->dl_chan.wq, wait); + poll_wait(file, &uci_dev->ul_chan.wq, wait); + + uci_chan = &uci_dev->dl_chan; + spin_lock_bh(&uci_chan->lock); + if (!uci_dev->enabled) { + mask = POLLERR; + } else if (!list_empty(&uci_chan->pending) || uci_chan->cur_buf) { + MSG_VERB("Client can read from node\n"); + mask |= POLLIN | POLLRDNORM; + } + spin_unlock_bh(&uci_chan->lock); + + uci_chan = &uci_dev->ul_chan; + spin_lock_bh(&uci_chan->lock); + if (!uci_dev->enabled) { + mask |= POLLERR; + } else if (mhi_get_no_free_descriptors(mhi_dev, DMA_TO_DEVICE) > 0) { + MSG_VERB("Client can write to node\n"); + mask |= POLLOUT | POLLWRNORM; + } + spin_unlock_bh(&uci_chan->lock); + + MSG_LOG("Client attempted to poll, returning mask 0x%x\n", mask); + + return mask; +} + +static ssize_t mhi_uci_write(struct file *file, + const char __user *buf, + size_t count, + loff_t *offp) +{ + struct uci_dev *uci_dev = file->private_data; + struct mhi_device *mhi_dev = uci_dev->mhi_dev; + struct uci_chan *uci_chan = &uci_dev->ul_chan; + size_t bytes_xfered = 0; + int ret; + + if (!buf || !count) + return -EINVAL; + + /* confirm channel is active */ + spin_lock_bh(&uci_chan->lock); + if (!uci_dev->enabled) { + spin_unlock_bh(&uci_chan->lock); + return -ERESTARTSYS; + } + + MSG_VERB("Enter: to xfer:%lu bytes\n", count); + + while (count) { + size_t xfer_size; + void *kbuf; + enum MHI_FLAGS flags; + + spin_unlock_bh(&uci_chan->lock); + + /* wait for free descriptors */ + ret = wait_event_interruptible(uci_chan->wq, + (!uci_dev->enabled) || + mhi_get_no_free_descriptors + (mhi_dev, DMA_TO_DEVICE) > 0); + + if (ret == -ERESTARTSYS) { + MSG_LOG("Exit signal caught for node\n"); + return -ERESTARTSYS; + } + + xfer_size = min_t(size_t, count, uci_dev->mtu); + kbuf = kmalloc(xfer_size, GFP_KERNEL); + if (!kbuf) { + MSG_ERR("Failed to allocate memory %lu\n", xfer_size); + return -ENOMEM; + } + + ret = copy_from_user(kbuf, buf, xfer_size); + if (unlikely(ret)) { + kfree(kbuf); + return ret; + } + + spin_lock_bh(&uci_chan->lock); + flags = (count - xfer_size) ? MHI_EOB : MHI_EOT; + if (uci_dev->enabled) + ret = mhi_queue_transfer(mhi_dev, DMA_TO_DEVICE, kbuf, + xfer_size, flags); + else + ret = -ERESTARTSYS; + + if (ret) { + kfree(kbuf); + goto sys_interrupt; + } + + bytes_xfered += xfer_size; + count -= xfer_size; + buf += xfer_size; + } + + spin_unlock_bh(&uci_chan->lock); + MSG_VERB("Exit: Number of bytes xferred:%lu\n", bytes_xfered); + + return bytes_xfered; + +sys_interrupt: + spin_unlock_bh(&uci_chan->lock); + + return ret; +} + +static ssize_t mhi_uci_read(struct file *file, + char __user *buf, + size_t count, + loff_t *ppos) +{ + struct uci_dev *uci_dev = file->private_data; + struct mhi_device *mhi_dev = uci_dev->mhi_dev; + struct uci_chan *uci_chan = &uci_dev->dl_chan; + struct uci_buf *uci_buf; + char *ptr; + size_t to_copy; + int ret = 0; + + if (!buf) + return -EINVAL; + + MSG_VERB("Client provided buf len:%lu\n", count); + + /* confirm channel is active */ + spin_lock_bh(&uci_chan->lock); + if (!uci_dev->enabled) { + spin_unlock_bh(&uci_chan->lock); + return -ERESTARTSYS; + } + + /* No data available to read, wait */ + if (!uci_chan->cur_buf && list_empty(&uci_chan->pending)) { + MSG_VERB("No data available to read waiting\n"); + + spin_unlock_bh(&uci_chan->lock); + ret = wait_event_interruptible(uci_chan->wq, + (!uci_dev->enabled || + !list_empty(&uci_chan->pending))); + if (ret == -ERESTARTSYS) { + MSG_LOG("Exit signal caught for node\n"); + return -ERESTARTSYS; + } + + spin_lock_bh(&uci_chan->lock); + if (!uci_dev->enabled) { + MSG_LOG("node is disabled\n"); + ret = -ERESTARTSYS; + goto read_error; + } + } + + /* new read, get the next descriptor from the list */ + if (!uci_chan->cur_buf) { + uci_buf = list_first_entry_or_null(&uci_chan->pending, + struct uci_buf, node); + if (unlikely(!uci_buf)) { + ret = -EIO; + goto read_error; + } + + list_del(&uci_buf->node); + uci_chan->cur_buf = uci_buf; + uci_chan->rx_size = uci_buf->len; + MSG_VERB("Got pkt of size:%zu\n", uci_chan->rx_size); + } + + uci_buf = uci_chan->cur_buf; + spin_unlock_bh(&uci_chan->lock); + + /* Copy the buffer to user space */ + to_copy = min_t(size_t, count, uci_chan->rx_size); + ptr = uci_buf->data + (uci_buf->len - uci_chan->rx_size); + ret = copy_to_user(buf, ptr, to_copy); + if (ret) + return ret; + + MSG_VERB("Copied %lu of %lu bytes\n", to_copy, uci_chan->rx_size); + uci_chan->rx_size -= to_copy; + + /* we finished with this buffer, queue it back to hardware */ + if (!uci_chan->rx_size) { + spin_lock_bh(&uci_chan->lock); + uci_chan->cur_buf = NULL; + + if (uci_dev->enabled) + ret = mhi_queue_transfer(mhi_dev, DMA_FROM_DEVICE, + uci_buf->data, uci_dev->mtu, + MHI_EOT); + else + ret = -ERESTARTSYS; + + if (ret) { + MSG_ERR("Failed to recycle element\n"); + kfree(uci_buf->data); + goto read_error; + } + + spin_unlock_bh(&uci_chan->lock); + } + + MSG_VERB("Returning %lu bytes\n", to_copy); + + return to_copy; + +read_error: + spin_unlock_bh(&uci_chan->lock); + + return ret; +} + +static int mhi_uci_open(struct inode *inode, struct file *filp) +{ + struct uci_dev *uci_dev; + int ret = -EIO; + struct uci_buf *buf_itr, *tmp; + struct uci_chan *dl_chan; + + mutex_lock(&mhi_uci_drv.lock); + list_for_each_entry(uci_dev, &mhi_uci_drv.head, node) { + if (uci_dev->devt == inode->i_rdev) { + ret = 0; + break; + } + } + mutex_unlock(&mhi_uci_drv.lock); + + /* could not find a minor node */ + if (ret) + return ret; + + mutex_lock(&uci_dev->mutex); + if (!uci_dev->enabled) { + MSG_ERR("Node exist, but not in active state!\n"); + goto error_open_chan; + } + + uci_dev->ref_count++; + + MSG_LOG("Node open, ref counts %u\n", uci_dev->ref_count); + + if (uci_dev->ref_count == 1) { + MSG_LOG("Starting channel\n"); + ret = mhi_prepare_for_transfer(uci_dev->mhi_dev); + if (ret) { + MSG_ERR("Error starting transfer channels\n"); + uci_dev->ref_count--; + goto error_open_chan; + } + + ret = mhi_queue_inbound(uci_dev); + if (ret) + goto error_rx_queue; + } + + filp->private_data = uci_dev; + mutex_unlock(&uci_dev->mutex); + + return 0; + + error_rx_queue: + dl_chan = &uci_dev->dl_chan; + mhi_unprepare_from_transfer(uci_dev->mhi_dev); + list_for_each_entry_safe(buf_itr, tmp, &dl_chan->pending, node) { + list_del(&buf_itr->node); + kfree(buf_itr->data); + } + + error_open_chan: + mutex_unlock(&uci_dev->mutex); + + return ret; +} + +static const struct file_operations mhidev_fops = { + .open = mhi_uci_open, + .release = mhi_uci_release, + .read = mhi_uci_read, + .write = mhi_uci_write, + .poll = mhi_uci_poll, + .unlocked_ioctl = mhi_uci_ioctl, +}; + +static void mhi_uci_remove(struct mhi_device *mhi_dev) +{ + struct uci_dev *uci_dev = mhi_device_get_devdata(mhi_dev); + + MSG_LOG("Enter\n"); + + /* disable the node */ + mutex_lock(&uci_dev->mutex); + spin_lock_irq(&uci_dev->dl_chan.lock); + spin_lock_irq(&uci_dev->ul_chan.lock); + uci_dev->enabled = false; + spin_unlock_irq(&uci_dev->ul_chan.lock); + spin_unlock_irq(&uci_dev->dl_chan.lock); + wake_up(&uci_dev->dl_chan.wq); + wake_up(&uci_dev->ul_chan.wq); + + /* delete the node to prevent new opens */ + device_destroy(mhi_uci_drv.class, uci_dev->devt); + uci_dev->dev = NULL; + mutex_lock(&mhi_uci_drv.lock); + list_del(&uci_dev->node); + mutex_unlock(&mhi_uci_drv.lock); + + /* safe to free memory only if all file nodes are closed */ + if (!uci_dev->ref_count) { + mutex_unlock(&uci_dev->mutex); + mutex_destroy(&uci_dev->mutex); + clear_bit(MINOR(uci_dev->devt), uci_minors); + kfree(uci_dev); + return; + } + + mutex_unlock(&uci_dev->mutex); + MSG_LOG("Exit\n"); +} + +static int mhi_uci_probe(struct mhi_device *mhi_dev, + const struct mhi_device_id *id) +{ + struct uci_dev *uci_dev; + int minor; + char node_name[32]; + int dir; + + uci_dev = kzalloc(sizeof(*uci_dev), GFP_KERNEL); + if (!uci_dev) + return -ENOMEM; + + mutex_init(&uci_dev->mutex); + uci_dev->mhi_dev = mhi_dev; + + minor = find_first_zero_bit(uci_minors, MAX_UCI_DEVICES); + if (minor >= MAX_UCI_DEVICES) { + kfree(uci_dev); + return -ENOSPC; + } + + mutex_lock(&uci_dev->mutex); + mutex_lock(&mhi_uci_drv.lock); + + uci_dev->devt = MKDEV(mhi_uci_drv.major, minor); + uci_dev->dev = device_create(mhi_uci_drv.class, &mhi_dev->dev, + uci_dev->devt, uci_dev, + DEVICE_NAME "_%04x_%02u.%02u.%02u%s%d", + mhi_dev->dev_id, mhi_dev->domain, + mhi_dev->bus, mhi_dev->slot, "_pipe_", + mhi_dev->ul_chan_id); + set_bit(minor, uci_minors); + + /* create debugging buffer */ + snprintf(node_name, sizeof(node_name), "mhi_uci_%04x_%02u.%02u.%02u_%d", + mhi_dev->dev_id, mhi_dev->domain, mhi_dev->bus, mhi_dev->slot, + mhi_dev->ul_chan_id); + uci_dev->ipc_log = ipc_log_context_create(MHI_UCI_IPC_LOG_PAGES, + node_name, 0); + + for (dir = 0; dir < 2; dir++) { + struct uci_chan *uci_chan = (dir) ? + &uci_dev->ul_chan : &uci_dev->dl_chan; + spin_lock_init(&uci_chan->lock); + init_waitqueue_head(&uci_chan->wq); + INIT_LIST_HEAD(&uci_chan->pending); + }; + + uci_dev->mtu = id->driver_data; + mhi_device_set_devdata(mhi_dev, uci_dev); + uci_dev->enabled = true; + + list_add(&uci_dev->node, &mhi_uci_drv.head); + mutex_unlock(&mhi_uci_drv.lock); + mutex_unlock(&uci_dev->mutex); + + MSG_LOG("channel:%s successfully probed\n", mhi_dev->chan_name); + + return 0; +}; + +static void mhi_ul_xfer_cb(struct mhi_device *mhi_dev, + struct mhi_result *mhi_result) +{ + struct uci_dev *uci_dev = mhi_device_get_devdata(mhi_dev); + struct uci_chan *uci_chan = &uci_dev->ul_chan; + + MSG_VERB("status:%d xfer_len:%zu\n", mhi_result->transaction_status, + mhi_result->bytes_xferd); + + kfree(mhi_result->buf_addr); + if (!mhi_result->transaction_status) + wake_up(&uci_chan->wq); +} + +static void mhi_dl_xfer_cb(struct mhi_device *mhi_dev, + struct mhi_result *mhi_result) +{ + struct uci_dev *uci_dev = mhi_device_get_devdata(mhi_dev); + struct uci_chan *uci_chan = &uci_dev->dl_chan; + unsigned long flags; + struct uci_buf *buf; + + MSG_VERB("status:%d receive_len:%zu\n", mhi_result->transaction_status, + mhi_result->bytes_xferd); + + if (mhi_result->transaction_status == -ENOTCONN) { + kfree(mhi_result->buf_addr); + return; + } + + spin_lock_irqsave(&uci_chan->lock, flags); + buf = mhi_result->buf_addr + uci_dev->mtu; + buf->data = mhi_result->buf_addr; + buf->len = mhi_result->bytes_xferd; + list_add_tail(&buf->node, &uci_chan->pending); + spin_unlock_irqrestore(&uci_chan->lock, flags); + + wake_up(&uci_chan->wq); +} + +/* .driver_data stores max mtu */ +static const struct mhi_device_id mhi_uci_match_table[] = { + { .chan = "LOOPBACK", .driver_data = 0x1000 }, + { .chan = "SAHARA", .driver_data = 0x8000 }, + { .chan = "EFS", .driver_data = 0x1000 }, + { .chan = "QMI0", .driver_data = 0x1000 }, + { .chan = "QMI1", .driver_data = 0x1000 }, + { .chan = "TF", .driver_data = 0x1000 }, + { .chan = "BL", .driver_data = 0x1000 }, + { .chan = "DUN", .driver_data = 0x1000 }, + { NULL }, +}; + +static struct mhi_driver mhi_uci_driver = { + .id_table = mhi_uci_match_table, + .remove = mhi_uci_remove, + .probe = mhi_uci_probe, + .ul_xfer_cb = mhi_ul_xfer_cb, + .dl_xfer_cb = mhi_dl_xfer_cb, + .driver = { + .name = MHI_UCI_DRIVER_NAME, + .owner = THIS_MODULE, + }, +}; + +static int mhi_uci_init(void) +{ + int ret; + + ret = register_chrdev(0, MHI_UCI_DRIVER_NAME, &mhidev_fops); + if (ret < 0) + return ret; + + mhi_uci_drv.major = ret; + mhi_uci_drv.class = class_create(THIS_MODULE, MHI_UCI_DRIVER_NAME); + if (IS_ERR(mhi_uci_drv.class)) + return -ENODEV; + + mutex_init(&mhi_uci_drv.lock); + INIT_LIST_HEAD(&mhi_uci_drv.head); + + ret = mhi_driver_register(&mhi_uci_driver); + if (ret) + class_destroy(mhi_uci_drv.class); + + return ret; +} + +module_init(mhi_uci_init); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("MHI_UCI"); +MODULE_DESCRIPTION("MHI UCI Driver"); -- GitLab From 0b787611fc20633ef466cac323950dbc08ff0f94 Mon Sep 17 00:00:00 2001 From: Dinesh K Garg Date: Mon, 19 Mar 2018 11:20:33 -0700 Subject: [PATCH 0355/1635] msm: mink: Snapshot of smcinvoke driver This patch is a snapshot of smcinvoke driver taken from msm-4.9 commit a8117effbe0 (Merge "ARM: dts: msm: Disable GPU memory pools for QCS605") Change-Id: I9e2de0c464bc23c48ae8a5a90e289048b0c274ae Signed-off-by: Dinesh K Garg --- drivers/soc/qcom/smcinvoke.c | 575 ++++++++++++++++++++++++++++ drivers/soc/qcom/smcinvoke_object.h | 51 +++ include/uapi/linux/smcinvoke.h | 45 +++ 3 files changed, 671 insertions(+) create mode 100644 drivers/soc/qcom/smcinvoke.c create mode 100644 drivers/soc/qcom/smcinvoke_object.h create mode 100644 include/uapi/linux/smcinvoke.h diff --git a/drivers/soc/qcom/smcinvoke.c b/drivers/soc/qcom/smcinvoke.c new file mode 100644 index 000000000000..28bb85bd3870 --- /dev/null +++ b/drivers/soc/qcom/smcinvoke.c @@ -0,0 +1,575 @@ +/* + * SMC Invoke driver + * + * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "smcinvoke_object.h" +#include "../../misc/qseecom_kernel.h" + +#define SMCINVOKE_DEV "smcinvoke" +#define SMCINVOKE_TZ_PARAM_ID 0x224 +#define SMCINVOKE_TZ_CMD 0x32000600 +#define SMCINVOKE_TZ_ROOT_OBJ 1 +#define SMCINVOKE_TZ_MIN_BUF_SIZE 4096 +#define SMCINVOKE_ARGS_ALIGN_SIZE (sizeof(uint64_t)) +#define SMCINVOKE_TZ_OBJ_NULL 0 + +#define FOR_ARGS(ndxvar, counts, section) \ + for (ndxvar = object_counts_index_##section(counts); \ + ndxvar < (object_counts_index_##section(counts) \ + + object_counts_num_##section(counts)); \ + ++ndxvar) + +static long smcinvoke_ioctl(struct file *, unsigned int, unsigned long); +static int smcinvoke_open(struct inode *, struct file *); +static int smcinvoke_release(struct inode *, struct file *); + +static const struct file_operations smcinvoke_fops = { + .owner = THIS_MODULE, + .unlocked_ioctl = smcinvoke_ioctl, + .compat_ioctl = smcinvoke_ioctl, + .open = smcinvoke_open, + .release = smcinvoke_release, +}; + +struct smcinvoke_buf_hdr { + uint32_t offset; + uint32_t size; +}; + +union smcinvoke_tz_args { + struct smcinvoke_buf_hdr b; + uint32_t tzhandle; +}; +struct smcinvoke_msg_hdr { + uint32_t tzhandle; + uint32_t op; + uint32_t counts; +}; + +struct smcinvoke_tzobj_context { + uint32_t tzhandle; +}; + +static dev_t smcinvoke_device_no; +struct cdev smcinvoke_cdev; +struct class *driver_class; +struct device *class_dev; + +/* + * size_add saturates at SIZE_MAX. If integer overflow is detected, + * this function would return SIZE_MAX otherwise normal a+b is returned. + */ +static inline size_t size_add(size_t a, size_t b) +{ + return (b > (SIZE_MAX - a)) ? SIZE_MAX : a + b; +} + +/* + * pad_size is used along with size_align to define a buffer overflow + * protected version of ALIGN + */ +static inline size_t pad_size(size_t a, size_t b) +{ + return (~a + 1) % b; +} + +/* + * size_align saturates at SIZE_MAX. If integer overflow is detected, this + * function would return SIZE_MAX otherwise next aligned size is returned. + */ +static inline size_t size_align(size_t a, size_t b) +{ + return size_add(a, pad_size(a, b)); +} + +/* + * This function retrieves file pointer corresponding to FD provided. It stores + * retrived file pointer until IOCTL call is concluded. Once call is completed, + * all stored file pointers are released. file pointers are stored to prevent + * other threads from releasing that FD while IOCTL is in progress. + */ +static int get_tzhandle_from_fd(int64_t fd, struct file **filp, + uint32_t *tzhandle) +{ + int ret = -EBADF; + struct file *tmp_filp = NULL; + struct smcinvoke_tzobj_context *tzobj = NULL; + + if (fd == SMCINVOKE_USERSPACE_OBJ_NULL) { + *tzhandle = SMCINVOKE_TZ_OBJ_NULL; + ret = 0; + goto out; + } else if (fd < SMCINVOKE_USERSPACE_OBJ_NULL) { + goto out; + } + + tmp_filp = fget(fd); + if (!tmp_filp) + goto out; + + /* Verify if filp is smcinvoke device's file pointer */ + if (!tmp_filp->f_op || !tmp_filp->private_data || + (tmp_filp->f_op != &smcinvoke_fops)) { + fput(tmp_filp); + goto out; + } + + tzobj = tmp_filp->private_data; + *tzhandle = tzobj->tzhandle; + *filp = tmp_filp; + ret = 0; +out: + return ret; +} + +static int get_fd_from_tzhandle(uint32_t tzhandle, int64_t *fd) +{ + int unused_fd = -1, ret = -1; + struct file *f = NULL; + struct smcinvoke_tzobj_context *cxt = NULL; + + if (tzhandle == SMCINVOKE_TZ_OBJ_NULL) { + *fd = SMCINVOKE_USERSPACE_OBJ_NULL; + ret = 0; + goto out; + } + + cxt = kzalloc(sizeof(*cxt), GFP_KERNEL); + if (!cxt) { + ret = -ENOMEM; + goto out; + } + unused_fd = get_unused_fd_flags(O_RDWR); + if (unused_fd < 0) + goto out; + + f = anon_inode_getfile(SMCINVOKE_DEV, &smcinvoke_fops, cxt, O_RDWR); + if (IS_ERR(f)) + goto out; + + *fd = unused_fd; + fd_install(*fd, f); + ((struct smcinvoke_tzobj_context *) + (f->private_data))->tzhandle = tzhandle; + return 0; +out: + if (unused_fd >= 0) + put_unused_fd(unused_fd); + kfree(cxt); + + return ret; +} + +static int prepare_send_scm_msg(const uint8_t *in_buf, size_t in_buf_len, + const uint8_t *out_buf, size_t out_buf_len, + int32_t *smcinvoke_result) +{ + int ret = 0; + struct scm_desc desc = {0}; + size_t inbuf_flush_size = (1UL << get_order(in_buf_len)) * PAGE_SIZE; + size_t outbuf_flush_size = (1UL << get_order(out_buf_len)) * PAGE_SIZE; + + desc.arginfo = SMCINVOKE_TZ_PARAM_ID; + desc.args[0] = (uint64_t)virt_to_phys(in_buf); + desc.args[1] = inbuf_flush_size; + desc.args[2] = (uint64_t)virt_to_phys(out_buf); + desc.args[3] = outbuf_flush_size; + + dmac_flush_range(in_buf, in_buf + inbuf_flush_size); + dmac_flush_range(out_buf, out_buf + outbuf_flush_size); + + ret = scm_call2(SMCINVOKE_TZ_CMD, &desc); + + /* process listener request */ + if (!ret && (desc.ret[0] == QSEOS_RESULT_INCOMPLETE || + desc.ret[0] == QSEOS_RESULT_BLOCKED_ON_LISTENER)) + ret = qseecom_process_listener_from_smcinvoke(&desc); + + *smcinvoke_result = (int32_t)desc.ret[1]; + if (ret || desc.ret[1] || desc.ret[2] || desc.ret[0]) + pr_err("SCM call failed with ret val = %d %d %d %d\n", + ret, (int)desc.ret[0], + (int)desc.ret[1], (int)desc.ret[2]); + + dmac_inv_range(in_buf, in_buf + inbuf_flush_size); + dmac_inv_range(out_buf, out_buf + outbuf_flush_size); + return ret; +} + +static int marshal_out(void *buf, uint32_t buf_size, + struct smcinvoke_cmd_req *req, + union smcinvoke_arg *args_buf) +{ + int ret = -EINVAL, i = 0; + union smcinvoke_tz_args *tz_args = NULL; + size_t offset = sizeof(struct smcinvoke_msg_hdr) + + object_counts_total(req->counts) * + sizeof(union smcinvoke_tz_args); + + if (offset > buf_size) + goto out; + + tz_args = (union smcinvoke_tz_args *) + (buf + sizeof(struct smcinvoke_msg_hdr)); + + tz_args += object_counts_num_BI(req->counts); + + FOR_ARGS(i, req->counts, BO) { + args_buf[i].b.size = tz_args->b.size; + if ((buf_size - tz_args->b.offset < tz_args->b.size) || + tz_args->b.offset > buf_size) { + pr_err("%s: buffer overflow detected\n", __func__); + goto out; + } + if (copy_to_user((void __user *)(uintptr_t)(args_buf[i].b.addr), + (uint8_t *)(buf) + tz_args->b.offset, + tz_args->b.size)) { + pr_err("Error %d copying ctxt to user\n", ret); + goto out; + } + tz_args++; + } + tz_args += object_counts_num_OI(req->counts); + + FOR_ARGS(i, req->counts, OO) { + /* + * create a new FD and assign to output object's + * context + */ + ret = get_fd_from_tzhandle(tz_args->tzhandle, + &(args_buf[i].o.fd)); + if (ret) + goto out; + tz_args++; + } + ret = 0; +out: + return ret; +} + +/* + * SMC expects arguments in following format + * --------------------------------------------------------------------------- + * | cxt | op | counts | ptr|size |ptr|size...|ORef|ORef|...| rest of payload | + * --------------------------------------------------------------------------- + * cxt: target, op: operation, counts: total arguments + * offset: offset is from beginning of buffer i.e. cxt + * size: size is 8 bytes aligned value + */ +static size_t compute_in_msg_size(const struct smcinvoke_cmd_req *req, + const union smcinvoke_arg *args_buf) +{ + uint32_t i = 0; + + size_t total_size = sizeof(struct smcinvoke_msg_hdr) + + object_counts_total(req->counts) * + sizeof(union smcinvoke_tz_args); + + /* Computed total_size should be 8 bytes aligned from start of buf */ + total_size = ALIGN(total_size, SMCINVOKE_ARGS_ALIGN_SIZE); + + /* each buffer has to be 8 bytes aligned */ + while (i < object_counts_num_buffers(req->counts)) + total_size = size_add(total_size, + size_align(args_buf[i++].b.size, SMCINVOKE_ARGS_ALIGN_SIZE)); + + /* Since we're using get_free_pages, no need for explicit PAGE align */ + return total_size; +} + +static int marshal_in(const struct smcinvoke_cmd_req *req, + const union smcinvoke_arg *args_buf, uint32_t tzhandle, + uint8_t *buf, size_t buf_size, struct file **arr_filp) +{ + int ret = -EINVAL, i = 0; + union smcinvoke_tz_args *tz_args = NULL; + struct smcinvoke_msg_hdr msg_hdr = {tzhandle, req->op, req->counts}; + uint32_t offset = sizeof(struct smcinvoke_msg_hdr) + + sizeof(union smcinvoke_tz_args) * + object_counts_total(req->counts); + + if (buf_size < offset) + goto out; + + *(struct smcinvoke_msg_hdr *)buf = msg_hdr; + tz_args = (union smcinvoke_tz_args *) + (buf + sizeof(struct smcinvoke_msg_hdr)); + + FOR_ARGS(i, req->counts, BI) { + offset = size_align(offset, SMCINVOKE_ARGS_ALIGN_SIZE); + if ((offset > buf_size) || + (args_buf[i].b.size > (buf_size - offset))) + goto out; + + tz_args->b.offset = offset; + tz_args->b.size = args_buf[i].b.size; + tz_args++; + + if (copy_from_user(buf+offset, + (void __user *)(uintptr_t)(args_buf[i].b.addr), + args_buf[i].b.size)) + goto out; + + offset += args_buf[i].b.size; + } + FOR_ARGS(i, req->counts, BO) { + offset = size_align(offset, SMCINVOKE_ARGS_ALIGN_SIZE); + if ((offset > buf_size) || + (args_buf[i].b.size > (buf_size - offset))) + goto out; + + tz_args->b.offset = offset; + tz_args->b.size = args_buf[i].b.size; + tz_args++; + + offset += args_buf[i].b.size; + } + FOR_ARGS(i, req->counts, OI) { + if (get_tzhandle_from_fd(args_buf[i].o.fd, + &arr_filp[i], &(tz_args->tzhandle))) + goto out; + tz_args++; + } + ret = 0; +out: + return ret; +} + +long smcinvoke_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) +{ + int ret = -1, i = 0, nr_args = 0; + struct smcinvoke_cmd_req req = {0}; + void *in_msg = NULL; + size_t inmsg_size = 0; + void *out_msg = NULL; + union smcinvoke_arg *args_buf = NULL; + struct file *filp_to_release[object_counts_max_OO] = {NULL}; + struct smcinvoke_tzobj_context *tzobj = filp->private_data; + + switch (cmd) { + case SMCINVOKE_IOCTL_INVOKE_REQ: + if (_IOC_SIZE(cmd) != sizeof(req)) { + ret = -EINVAL; + goto out; + } + ret = copy_from_user(&req, (void __user *)arg, sizeof(req)); + if (ret) { + ret = -EFAULT; + goto out; + } + + nr_args = object_counts_num_buffers(req.counts) + + object_counts_num_objects(req.counts); + + if (req.argsize != sizeof(union smcinvoke_arg)) { + ret = -EINVAL; + goto out; + } + + if (nr_args) { + + args_buf = kzalloc(nr_args * req.argsize, GFP_KERNEL); + if (!args_buf) { + ret = -ENOMEM; + goto out; + } + + ret = copy_from_user(args_buf, + (void __user *)(uintptr_t)(req.args), + nr_args * req.argsize); + + if (ret) { + ret = -EFAULT; + goto out; + } + } + + inmsg_size = compute_in_msg_size(&req, args_buf); + in_msg = (void *)__get_free_pages(GFP_KERNEL, + get_order(inmsg_size)); + if (!in_msg) { + ret = -ENOMEM; + goto out; + } + + out_msg = (void *)__get_free_page(GFP_KERNEL); + if (!out_msg) { + ret = -ENOMEM; + goto out; + } + + ret = marshal_in(&req, args_buf, tzobj->tzhandle, in_msg, + inmsg_size, filp_to_release); + if (ret) + goto out; + + ret = prepare_send_scm_msg(in_msg, inmsg_size, out_msg, + SMCINVOKE_TZ_MIN_BUF_SIZE, &req.result); + if (ret) + goto out; + + /* + * if invoke op results in an err, no need to marshal_out and + * copy args buf to user space + */ + if (!req.result) { + ret = marshal_out(in_msg, inmsg_size, &req, args_buf); + + ret |= copy_to_user( + (void __user *)(uintptr_t)(req.args), + args_buf, nr_args * req.argsize); + } + ret |= copy_to_user((void __user *)arg, &req, sizeof(req)); + if (ret) + goto out; + + break; + default: + ret = -ENOIOCTLCMD; + break; + } +out: + free_page((long)out_msg); + free_pages((long)in_msg, get_order(inmsg_size)); + kfree(args_buf); + for (i = 0; i < object_counts_max_OO; i++) { + if (filp_to_release[i]) + fput(filp_to_release[i]); + } + + return ret; +} + +static int smcinvoke_open(struct inode *nodp, struct file *filp) +{ + struct smcinvoke_tzobj_context *tzcxt = NULL; + + tzcxt = kzalloc(sizeof(*tzcxt), GFP_KERNEL); + if (!tzcxt) + return -ENOMEM; + + tzcxt->tzhandle = SMCINVOKE_TZ_ROOT_OBJ; + filp->private_data = tzcxt; + + return 0; +} + +static int smcinvoke_release(struct inode *nodp, struct file *filp) +{ + int ret = 0, smcinvoke_result = 0; + uint8_t *in_buf = NULL; + uint8_t *out_buf = NULL; + struct smcinvoke_msg_hdr hdr = {0}; + struct smcinvoke_tzobj_context *tzobj = filp->private_data; + uint32_t tzhandle = tzobj->tzhandle; + + /* Root object is special in sense it is indestructible */ + if (!tzhandle || tzhandle == SMCINVOKE_TZ_ROOT_OBJ) + goto out; + + in_buf = (uint8_t *)__get_free_page(GFP_KERNEL); + out_buf = (uint8_t *)__get_free_page(GFP_KERNEL); + if (!in_buf || !out_buf) + goto out; + + hdr.tzhandle = tzhandle; + hdr.op = object_op_RELEASE; + hdr.counts = 0; + *(struct smcinvoke_msg_hdr *)in_buf = hdr; + + ret = prepare_send_scm_msg(in_buf, SMCINVOKE_TZ_MIN_BUF_SIZE, + out_buf, SMCINVOKE_TZ_MIN_BUF_SIZE, &smcinvoke_result); +out: + kfree(filp->private_data); + free_page((long)in_buf); + free_page((long)out_buf); + + return ret; +} + +static int __init smcinvoke_init(void) +{ + unsigned int baseminor = 0; + unsigned int count = 1; + int rc = 0; + + rc = alloc_chrdev_region(&smcinvoke_device_no, baseminor, count, + SMCINVOKE_DEV); + if (rc < 0) { + pr_err("chrdev_region failed %d for %s\n", rc, SMCINVOKE_DEV); + return rc; + } + driver_class = class_create(THIS_MODULE, SMCINVOKE_DEV); + if (IS_ERR(driver_class)) { + rc = -ENOMEM; + pr_err("class_create failed %d\n", rc); + goto exit_unreg_chrdev_region; + } + class_dev = device_create(driver_class, NULL, smcinvoke_device_no, + NULL, SMCINVOKE_DEV); + if (!class_dev) { + pr_err("class_device_create failed %d\n", rc); + rc = -ENOMEM; + goto exit_destroy_class; + } + + cdev_init(&smcinvoke_cdev, &smcinvoke_fops); + smcinvoke_cdev.owner = THIS_MODULE; + + rc = cdev_add(&smcinvoke_cdev, MKDEV(MAJOR(smcinvoke_device_no), 0), + count); + if (rc < 0) { + pr_err("cdev_add failed %d for %s\n", rc, SMCINVOKE_DEV); + goto exit_destroy_device; + } + return 0; + +exit_destroy_device: + device_destroy(driver_class, smcinvoke_device_no); +exit_destroy_class: + class_destroy(driver_class); +exit_unreg_chrdev_region: + unregister_chrdev_region(smcinvoke_device_no, count); + + return rc; +} + +static void __exit smcinvoke_exit(void) +{ + int count = 1; + + cdev_del(&smcinvoke_cdev); + device_destroy(driver_class, smcinvoke_device_no); + class_destroy(driver_class); + unregister_chrdev_region(smcinvoke_device_no, count); +} +device_initcall(smcinvoke_init); +module_exit(smcinvoke_exit); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("SMC Invoke driver"); diff --git a/drivers/soc/qcom/smcinvoke_object.h b/drivers/soc/qcom/smcinvoke_object.h new file mode 100644 index 000000000000..2761f87e14f5 --- /dev/null +++ b/drivers/soc/qcom/smcinvoke_object.h @@ -0,0 +1,51 @@ +/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#ifndef __SMCINVOKE_OBJECT_H +#define __SMCINVOKE_OBJECT_H + +#include + +#define object_op_METHOD_MASK ((uint32_t)0x0000FFFFu) +#define object_op_RELEASE (object_op_METHOD_MASK - 0) +#define object_op_RETAIN (object_op_METHOD_MASK - 1) + +#define object_counts_max_BI 0xF +#define object_counts_max_BO 0xF +#define object_counts_max_OI 0xF +#define object_counts_max_OO 0xF + +/* unpack counts */ + +#define object_counts_num_BI(k) ((size_t) (((k) >> 0) & object_counts_max_BI)) +#define object_counts_num_BO(k) ((size_t) (((k) >> 4) & object_counts_max_BO)) +#define object_counts_num_OI(k) ((size_t) (((k) >> 8) & object_counts_max_OI)) +#define object_counts_num_OO(k) ((size_t) (((k) >> 12) & object_counts_max_OO)) +#define object_counts_num_buffers(k) \ + (object_counts_num_BI(k) + object_counts_num_BO(k)) + +#define object_counts_num_objects(k) \ + (object_counts_num_OI(k) + object_counts_num_OO(k)) + +/* Indices into args[] */ + +#define object_counts_index_BI(k) 0 +#define object_counts_index_BO(k) \ + (object_counts_index_BI(k) + object_counts_num_BI(k)) +#define object_counts_index_OI(k) \ + (object_counts_index_BO(k) + object_counts_num_BO(k)) +#define object_counts_index_OO(k) \ + (object_counts_index_OI(k) + object_counts_num_OI(k)) +#define object_counts_total(k) \ + (object_counts_index_OO(k) + object_counts_num_OO(k)) + + +#endif /* __SMCINVOKE_OBJECT_H */ diff --git a/include/uapi/linux/smcinvoke.h b/include/uapi/linux/smcinvoke.h new file mode 100644 index 000000000000..1dc9a63c15e5 --- /dev/null +++ b/include/uapi/linux/smcinvoke.h @@ -0,0 +1,45 @@ +#ifndef _UAPI_SMCINVOKE_H_ +#define _UAPI_SMCINVOKE_H_ + +#include +#include + +#define SMCINVOKE_USERSPACE_OBJ_NULL -1 + +struct smcinvoke_buf { + uint64_t addr; + uint64_t size; +}; + +struct smcinvoke_obj { + int64_t fd; + int64_t reserved; +}; + +union smcinvoke_arg { + struct smcinvoke_buf b; + struct smcinvoke_obj o; +}; + +/* + * struct smcinvoke_cmd_req: This structure is transparently sent to TEE + * @op - Operation to be performed + * @counts - number of aruments passed + * @result - result of invoke operation + * @argsize - size of each of arguments + * @args - args is pointer to buffer having all arguments + */ +struct smcinvoke_cmd_req { + uint32_t op; + uint32_t counts; + int32_t result; + uint32_t argsize; + uint64_t __user args; +}; + +#define SMCINVOKE_IOC_MAGIC 0x98 + +#define SMCINVOKE_IOCTL_INVOKE_REQ \ + _IOWR(SMCINVOKE_IOC_MAGIC, 1, struct smcinvoke_cmd_req) + +#endif /* _UAPI_SMCINVOKE_H_ */ -- GitLab From 57eb127f0a5386c31ecc4dc41f7871fb5fae5e4a Mon Sep 17 00:00:00 2001 From: "Isaac J. Manjarres" Date: Thu, 12 Apr 2018 13:33:07 -0700 Subject: [PATCH 0356/1635] ARM: dts: msm: Use proper node names for CPUSS L2 TLB Dumping Currently, the TLB nodes that are used for CPUSS dumping are named L1 TLB nodes, but they are acutally L2 TLB nodes. Update incorrect L1 TLB node names to correct L2 TLB node names on sm8150. Change-Id: I26846723e88ed5a2bf5a9ca8cd655ec8ec1eab1c Signed-off-by: Isaac J. Manjarres --- arch/arm64/boot/dts/qcom/sm8150.dtsi | 48 ++++++++++++++-------------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sm8150.dtsi b/arch/arm64/boot/dts/qcom/sm8150.dtsi index 83a1162ce498..1e4cdc6f24e9 100644 --- a/arch/arm64/boot/dts/qcom/sm8150.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150.dtsi @@ -87,7 +87,7 @@ qcom,dump-size = <0x9000>; }; - L1_TLB_0: l1-tlb { + L2_TLB_0: l2-tlb { qcom,dump-size = <0x5000>; }; }; @@ -120,7 +120,7 @@ qcom,dump-size = <0x9000>; }; - L1_TLB_100: l1-tlb { + L2_TLB_100: l2-tlb { qcom,dump-size = <0x5000>; }; }; @@ -153,7 +153,7 @@ qcom,dump-size = <0x9000>; }; - L1_TLB_200: l1-tlb { + L2_TLB_200: l2-tlb { qcom,dump-size = <0x5000>; }; }; @@ -186,7 +186,7 @@ qcom,dump-size = <0x9000>; }; - L1_TLB_300: l1-tlb { + L2_TLB_300: l2-tlb { qcom,dump-size = <0x5000>; }; }; @@ -219,7 +219,7 @@ qcom,dump-size = <0x12000>; }; - L1_TLB_400: l1-tlb { + L2_TLB_400: l2-tlb { qcom,dump-size = <0x7800>; }; }; @@ -252,7 +252,7 @@ qcom,dump-size = <0x12000>; }; - L1_TLB_500: l1-tlb { + L2_TLB_500: l2-tlb { qcom,dump-size = <0x7800>; }; }; @@ -285,7 +285,7 @@ qcom,dump-size = <0x12000>; }; - L1_TLB_600: l1-tlb { + L2_TLB_600: l2-tlb { qcom,dump-size = <0x7800>; }; }; @@ -318,7 +318,7 @@ qcom,dump-size = <0x12000>; }; - L1_TLB_700: l1-tlb { + L2_TLB_700: l2-tlb { qcom,dump-size = <0x7800>; }; }; @@ -1864,43 +1864,43 @@ qcom,dump-id = <0x87>; }; - qcom,l1_tlb_dump0 { - qcom,dump-node = <&L1_TLB_0>; + qcom,l2_tlb_dump0 { + qcom,dump-node = <&L2_TLB_0>; qcom,dump-id = <0x120>; }; - qcom,l1_tlb_dump100 { - qcom,dump-node = <&L1_TLB_100>; + qcom,l2_tlb_dump100 { + qcom,dump-node = <&L2_TLB_100>; qcom,dump-id = <0x121>; }; - qcom,l1_tlb_dump200 { - qcom,dump-node = <&L1_TLB_200>; + qcom,l2_tlb_dump200 { + qcom,dump-node = <&L2_TLB_200>; qcom,dump-id = <0x122>; }; - qcom,l1_tlb_dump300 { - qcom,dump-node = <&L1_TLB_300>; + qcom,l2_tlb_dump300 { + qcom,dump-node = <&L2_TLB_300>; qcom,dump-id = <0x123>; }; - qcom,l1_tlb_dump400 { - qcom,dump-node = <&L1_TLB_400>; + qcom,l2_tlb_dump400 { + qcom,dump-node = <&L2_TLB_400>; qcom,dump-id = <0x124>; }; - qcom,l1_tlb_dump500 { - qcom,dump-node = <&L1_TLB_500>; + qcom,l2_tlb_dump500 { + qcom,dump-node = <&L2_TLB_500>; qcom,dump-id = <0x125>; }; - qcom,l1_tlb_dump600 { - qcom,dump-node = <&L1_TLB_600>; + qcom,l2_tlb_dump600 { + qcom,dump-node = <&L2_TLB_600>; qcom,dump-id = <0x126>; }; - qcom,l1_tlb_dump700 { - qcom,dump-node = <&L1_TLB_700>; + qcom,l2_tlb_dump700 { + qcom,dump-node = <&L2_TLB_700>; qcom,dump-id = <0x127>; }; }; -- GitLab From 4a68c40892f880bfde21305ef2d91c1b615843a1 Mon Sep 17 00:00:00 2001 From: Mayank Rana Date: Thu, 12 Apr 2018 12:10:52 -0700 Subject: [PATCH 0357/1635] dwc3: gadget: remove usage of wait_event_lock_irq() dwc3_gadget_ep_dequeue() API uses wait_event_lock_irq() which takes mutex_lock(). Hence if function driver calls this API with interrupt and preemption disable, it results into calling sleeping function with preemption disable. wait_event_lock_irq() API is used to wait for stop endpoint command completion, and already existing delay should suffice. Hence fix this issue by removing usage of wait_event_lock_irq() from dwc3_gadget_ep_dequeue() API. Change-Id: If31e045b37334ddeddb6e2dfb23500f356806719 Signed-off-by: Mayank Rana --- drivers/usb/dwc3/gadget.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 59710e1383b0..bbfbb28a2acc 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -1599,10 +1599,6 @@ static int dwc3_gadget_ep_dequeue(struct usb_ep *ep, * consideration so we don't mess up our TRB ring * pointers. */ - wait_event_lock_irq(dep->wait_end_transfer, - !(dep->flags & DWC3_EP_END_TRANSFER_PENDING), - dwc->lock); - if (!r->trb) goto out0; -- GitLab From 355ab5b8b42bbddd176967fa0cef69b7344a2902 Mon Sep 17 00:00:00 2001 From: David Dai Date: Thu, 12 Apr 2018 17:47:29 -0700 Subject: [PATCH 0358/1635] ARM: dts: msm: add cdsp/snoc/cnoc keepalive governor for sdmshrike Keep a small active only vote on system critical resources on behalf of APPS processor. Change-Id: I636714d96928c43790765b6968f83ed41b91f370 Signed-off-by: David Dai --- arch/arm64/boot/dts/qcom/sdmshrike.dtsi | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sdmshrike.dtsi b/arch/arm64/boot/dts/qcom/sdmshrike.dtsi index 50d45696f779..39dbb894f7c5 100644 --- a/arch/arm64/boot/dts/qcom/sdmshrike.dtsi +++ b/arch/arm64/boot/dts/qcom/sdmshrike.dtsi @@ -773,6 +773,24 @@ ; }; + snoc_cnoc_keepalive: qcom,snoc_cnoc_keepalive { + compatible = "qcom,devbw"; + governor = "powersave"; + qcom,src-dst-ports = <1 627>; + qcom,active-only; + status = "ok"; + qcom,bw-tbl = < 1 >; + }; + + cdsp_keepalive: qcom,cdsp_keepalive { + compatible = "qcom,devbw"; + governor = "powersave"; + qcom,src-dst-ports = <154 10070>; + qcom,active-only; + status = "ok"; + qcom,bw-tbl = < 1 >; + }; + clock_rpmh: qcom,rpmhclk { compatible = "qcom,rpmh-clk-sdmshrike"; mboxes = <&apps_rsc 0>; -- GitLab From 044f990ab3cd2e473f8453ae313e030634722228 Mon Sep 17 00:00:00 2001 From: David Dai Date: Mon, 19 Mar 2018 14:02:56 -0700 Subject: [PATCH 0359/1635] ARM: dts: msm: Add ALC mas node for sm8150 Include an ALC node so that we can clear its proxy vote at late_init. Change-Id: I4b9605ec8d6ff5f71a6cc5d6494195b53bb38d80 Signed-off-by: David Dai --- arch/arm64/boot/dts/qcom/sm8150-bus.dtsi | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sm8150-bus.dtsi b/arch/arm64/boot/dts/qcom/sm8150-bus.dtsi index fe60b85216f1..cbe25a940a56 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-bus.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-bus.dtsi @@ -1327,6 +1327,15 @@ qcom,forwarding; }; + mas_alc: mas-alc { + cell-id = ; + label = "mas-alc"; + qcom,buswidth = <1>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_mc_virt>; + qcom,bcms = <&bcm_alc>; + }; + mas_qnm_mnoc_hf_display: mas-qnm-mnoc-hf_display { cell-id = ; label = "mas-qnm-mnoc-hf_display"; -- GitLab From 4b3cba21d8136f0cf032732bd57c741459da1350 Mon Sep 17 00:00:00 2001 From: David Dai Date: Wed, 4 Apr 2018 11:31:54 -0700 Subject: [PATCH 0360/1635] ARM: dts: msm: Change display rsc to use AMC votes for sm8150 Since display RSCs now have their own dedicated AMC TSC, they no longer need to repurpose a single TSC for both wake and AMC. Change-Id: I6aa8c32b167d58214f4965f594857d3fbc911dd7 Signed-off-by: David Dai --- arch/arm64/boot/dts/qcom/sm8150-bus.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/sm8150-bus.dtsi b/arch/arm64/boot/dts/qcom/sm8150-bus.dtsi index fe60b85216f1..c0ba2044d9aa 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-bus.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-bus.dtsi @@ -49,7 +49,7 @@ cell-id = ; label = "disp_rsc"; qcom,rsc-dev; - qcom,req_state = <3>; + qcom,req_state = <2>; }; /*BCMs*/ -- GitLab From 74a84e67c6ad3d586520d5bdf25a61c8c76d4324 Mon Sep 17 00:00:00 2001 From: Skylar Chang Date: Wed, 4 Apr 2018 15:09:34 -0700 Subject: [PATCH 0361/1635] msm: ipa3: add missing dma-coherent description add dma-coherent description to enable dma-coherent feature on SMMU context bank. Change-Id: I1c9cf23806f23e461de1f9cfdb8e7e7b652340f4 Signed-off-by: Skylar Chang --- Documentation/devicetree/bindings/platform/msm/ipa.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/platform/msm/ipa.txt b/Documentation/devicetree/bindings/platform/msm/ipa.txt index d272b7f3426a..7a3f3fd2642d 100644 --- a/Documentation/devicetree/bindings/platform/msm/ipa.txt +++ b/Documentation/devicetree/bindings/platform/msm/ipa.txt @@ -128,6 +128,8 @@ IPA SMMU sub nodes - qcom,smmu-s1-bypass: Boolean context flag to set SMMU to S1 bypass. +- dma-coherent: Indicate using dma-coherent or not in SMMU block + - iommus : the phandle and stream IDs for the SMMU used by this root - qcom,iova-mapping: specifies the start address and size of iova space. -- GitLab From 806e154c9d34c91ef486c88fa6107e42e4e779a0 Mon Sep 17 00:00:00 2001 From: Subbaraman Narayanamurthy Date: Fri, 2 Feb 2018 15:33:07 -0800 Subject: [PATCH 0362/1635] power_supply: add cycle_counts property Currently, cycle_count and cycle_count_id are used to get the cycle counter per SOC bucket. Add a string property cycle_counts that can return all the cycle counters at once without the client setting cycle_count_id. Change-Id: If3014a4f865f94dc0895c1f5f7068ce936a0b62d Signed-off-by: Subbaraman Narayanamurthy --- drivers/power/supply/power_supply_sysfs.c | 1 + include/linux/power_supply.h | 1 + 2 files changed, 2 insertions(+) diff --git a/drivers/power/supply/power_supply_sysfs.c b/drivers/power/supply/power_supply_sysfs.c index f24ac5c2113b..087746014ce9 100644 --- a/drivers/power/supply/power_supply_sysfs.c +++ b/drivers/power/supply/power_supply_sysfs.c @@ -374,6 +374,7 @@ static struct device_attribute power_supply_attrs[] = { POWER_SUPPLY_ATTR(manufacturer), POWER_SUPPLY_ATTR(serial_number), POWER_SUPPLY_ATTR(battery_type), + POWER_SUPPLY_ATTR(cycle_counts), }; static struct attribute * diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h index f7179a1c462c..8f8d700552d2 100644 --- a/include/linux/power_supply.h +++ b/include/linux/power_supply.h @@ -287,6 +287,7 @@ enum power_supply_property { POWER_SUPPLY_PROP_MANUFACTURER, POWER_SUPPLY_PROP_SERIAL_NUMBER, POWER_SUPPLY_PROP_BATTERY_TYPE, + POWER_SUPPLY_PROP_CYCLE_COUNTS, }; enum power_supply_type { -- GitLab From 393511050d160aa4235acf2171ea85e15f0567d6 Mon Sep 17 00:00:00 2001 From: Subbaraman Narayanamurthy Date: Fri, 26 Jan 2018 12:49:57 -0800 Subject: [PATCH 0363/1635] power: qcom: Add support for FG software algorithms Add fg-alg.c and fg-alg.h which can have the common software features and algorithms that can be used by GEN4 FG driver and QG driver later. Change-Id: I5423b9e75c1d5eca9cbc4d9e1e229082f6007a94 Signed-off-by: Subbaraman Narayanamurthy --- drivers/power/supply/qcom/fg-alg.c | 606 +++++++++++++++++++++++++++++ drivers/power/supply/qcom/fg-alg.h | 73 ++++ 2 files changed, 679 insertions(+) create mode 100644 drivers/power/supply/qcom/fg-alg.c create mode 100644 drivers/power/supply/qcom/fg-alg.h diff --git a/drivers/power/supply/qcom/fg-alg.c b/drivers/power/supply/qcom/fg-alg.c new file mode 100644 index 000000000000..3d74f7e4452c --- /dev/null +++ b/drivers/power/supply/qcom/fg-alg.c @@ -0,0 +1,606 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#define pr_fmt(fmt) "ALG: %s: " fmt, __func__ + +#include +#include +#include +#include +#include "fg-alg.h" + +#define FULL_SOC_RAW 255 +#define CAPACITY_DELTA_DECIPCT 500 + +/* Cycle counter APIs */ + +/** + * restore_cycle_count - + * @counter: Cycle counter object + * + * Restores all the counters back from FG/QG during boot + * + */ +int restore_cycle_count(struct cycle_counter *counter) +{ + int rc = 0; + + if (!counter) + return -ENODEV; + + mutex_lock(&counter->lock); + rc = counter->restore_count(counter->data, counter->count, + BUCKET_COUNT); + if (rc < 0) + pr_err("failed to restore cycle counter rc=%d\n", rc); + mutex_unlock(&counter->lock); + + return rc; +} + +/** + * clear_cycle_count - + * @counter: Cycle counter object + * + * Clears all the counters stored by FG/QG when a battery is inserted + * or the profile is re-loaded. + * + */ +void clear_cycle_count(struct cycle_counter *counter) +{ + int rc = 0, i; + + if (!counter) + return; + + mutex_lock(&counter->lock); + memset(counter->count, 0, sizeof(counter->count)); + for (i = 0; i < BUCKET_COUNT; i++) { + counter->started[i] = false; + counter->last_soc[i] = 0; + } + + rc = counter->store_count(counter->data, counter->count, 0, + BUCKET_COUNT * 2); + if (rc < 0) + pr_err("failed to clear cycle counter rc=%d\n", rc); + + mutex_unlock(&counter->lock); +} + +/** + * store_cycle_count - + * @counter: Cycle counter object + * @id: Cycle counter bucket id + * + * Stores the cycle counter for a bucket in FG/QG. + * + */ +static int store_cycle_count(struct cycle_counter *counter, int id) +{ + int rc = 0; + u16 cyc_count; + + if (!counter) + return -ENODEV; + + if (id < 0 || (id > BUCKET_COUNT - 1)) { + pr_err("Invalid id %d\n", id); + return -EINVAL; + } + + cyc_count = counter->count[id]; + cyc_count++; + + rc = counter->store_count(counter->data, &cyc_count, id, 2); + if (rc < 0) { + pr_err("failed to write cycle_count[%d] rc=%d\n", + id, rc); + return rc; + } + + counter->count[id] = cyc_count; + pr_debug("Stored count %d in id %d\n", cyc_count, id); + + return rc; +} + +/** + * cycle_count_update - + * @counter: Cycle counter object + * @batt_soc: Battery State of Charge (SOC) + * @charge_status: Charging status from power supply + * @charge_done: Indicator for charge termination + * @input_present: Indicator for input presence + * + * Called by FG/QG whenever there is a state change (Charging status, SOC) + * + */ +void cycle_count_update(struct cycle_counter *counter, int batt_soc, + int charge_status, bool charge_done, bool input_present) +{ + int rc = 0, id, i, soc_thresh; + + if (!counter) + return; + + mutex_lock(&counter->lock); + + /* Find out which id the SOC falls in */ + id = batt_soc / BUCKET_SOC_PCT; + + if (charge_status == POWER_SUPPLY_STATUS_CHARGING) { + if (!counter->started[id] && id != counter->last_bucket) { + counter->started[id] = true; + counter->last_soc[id] = batt_soc; + } + } else if (charge_done || !input_present) { + for (i = 0; i < BUCKET_COUNT; i++) { + soc_thresh = counter->last_soc[i] + BUCKET_SOC_PCT / 2; + if (counter->started[i] && batt_soc > soc_thresh) { + rc = store_cycle_count(counter, i); + if (rc < 0) + pr_err("Error in storing cycle_ctr rc: %d\n", + rc); + counter->last_soc[i] = 0; + counter->started[i] = false; + counter->last_bucket = i; + } + } + } + + pr_debug("batt_soc: %d id: %d chg_status: %d\n", batt_soc, id, + charge_status); + mutex_unlock(&counter->lock); +} + +/** + * get_cycle_count - + * @counter: Cycle counter object + * + * Returns the cycle counter for a SOC bucket. + * + */ +int get_cycle_count(struct cycle_counter *counter) +{ + int count; + + if (!counter) + return 0; + + if ((counter->id <= 0) || (counter->id > BUCKET_COUNT)) + return -EINVAL; + + mutex_lock(&counter->lock); + count = counter->count[counter->id - 1]; + mutex_unlock(&counter->lock); + return count; +} + +/** + * cycle_count_init - + * @counter: Cycle counter object + * + * FG/QG have to call this during driver probe to validate the required + * parameters after allocating cycle_counter object. + * + */ +int cycle_count_init(struct cycle_counter *counter) +{ + if (!counter) + return -ENODEV; + + if (!counter->data || !counter->restore_count || + !counter->store_count) { + pr_err("Invalid parameters for using cycle counter\n"); + return -EINVAL; + } + + mutex_init(&counter->lock); + counter->last_bucket = -1; + return 0; +} + +/* Capacity learning algorithm APIs */ + +/** + * cap_learning_post_process - + * @cl: Capacity learning object + * + * Does post processing on the learnt capacity based on the user specified + * or default parameters for the capacity learning algorithm. + * + */ +static void cap_learning_post_process(struct cap_learning *cl) +{ + int64_t max_inc_val, min_dec_val, old_cap; + int rc; + + if (cl->dt.skew_decipct) { + pr_debug("applying skew %d on current learnt capacity %lld\n", + cl->dt.skew_decipct, cl->final_cap_uah); + cl->final_cap_uah = cl->final_cap_uah * + (1000 + cl->dt.skew_decipct); + cl->final_cap_uah = div64_u64(cl->final_cap_uah, 1000); + } + + max_inc_val = cl->learned_cap_uah * (1000 + cl->dt.max_cap_inc); + max_inc_val = div64_u64(max_inc_val, 1000); + + min_dec_val = cl->learned_cap_uah * (1000 - cl->dt.max_cap_dec); + min_dec_val = div64_u64(min_dec_val, 1000); + + old_cap = cl->learned_cap_uah; + if (cl->final_cap_uah > max_inc_val) + cl->learned_cap_uah = max_inc_val; + else if (cl->final_cap_uah < min_dec_val) + cl->learned_cap_uah = min_dec_val; + else + cl->learned_cap_uah = cl->final_cap_uah; + + if (cl->dt.max_cap_limit) { + max_inc_val = (int64_t)cl->nom_cap_uah * (1000 + + cl->dt.max_cap_limit); + max_inc_val = div64_u64(max_inc_val, 1000); + if (cl->final_cap_uah > max_inc_val) { + pr_debug("learning capacity %lld goes above max limit %lld\n", + cl->final_cap_uah, max_inc_val); + cl->learned_cap_uah = max_inc_val; + } + } + + if (cl->dt.min_cap_limit) { + min_dec_val = (int64_t)cl->nom_cap_uah * (1000 - + cl->dt.min_cap_limit); + min_dec_val = div64_u64(min_dec_val, 1000); + if (cl->final_cap_uah < min_dec_val) { + pr_debug("learning capacity %lld goes below min limit %lld\n", + cl->final_cap_uah, min_dec_val); + cl->learned_cap_uah = min_dec_val; + } + } + + if (cl->store_learned_capacity) { + rc = cl->store_learned_capacity(cl->data, cl->learned_cap_uah); + if (rc < 0) + pr_err("Error in storing learned_cap_uah, rc=%d\n", rc); + } + + pr_debug("final cap_uah = %lld, learned capacity %lld -> %lld uah\n", + cl->final_cap_uah, old_cap, cl->learned_cap_uah); +} + +/** + * cap_learning_process_full_data - + * @cl: Capacity learning object + * + * Processes the coulomb counter during charge termination and calculates the + * delta w.r.to the coulomb counter obtained earlier when the learning begun. + * + */ +static int cap_learning_process_full_data(struct cap_learning *cl) +{ + int rc, cc_soc_sw, cc_soc_delta_pct; + int64_t delta_cap_uah; + + rc = cl->get_cc_soc(cl->data, &cc_soc_sw); + if (rc < 0) { + pr_err("Error in getting CC_SOC_SW, rc=%d\n", rc); + return rc; + } + + cc_soc_delta_pct = + div64_s64((int64_t)(cc_soc_sw - cl->init_cc_soc_sw) * 100, + cl->cc_soc_max); + + /* If the delta is < 50%, then skip processing full data */ + if (cc_soc_delta_pct < 50) { + pr_err("cc_soc_delta_pct: %d\n", cc_soc_delta_pct); + return -ERANGE; + } + + delta_cap_uah = div64_s64(cl->learned_cap_uah * cc_soc_delta_pct, 100); + cl->final_cap_uah = cl->init_cap_uah + delta_cap_uah; + pr_debug("Current cc_soc=%d cc_soc_delta_pct=%d total_cap_uah=%lld\n", + cc_soc_sw, cc_soc_delta_pct, cl->final_cap_uah); + return 0; +} + +/** + * cap_learning_begin - + * @cl: Capacity learning object + * @batt_soc: Battery State of Charge (SOC) + * + * Gets the coulomb counter from FG/QG when the conditions are suitable for + * beginning capacity learning. Also, primes the coulomb counter based on + * battery SOC if required. + * + */ +static int cap_learning_begin(struct cap_learning *cl, u32 batt_soc) +{ + int rc, cc_soc_sw, batt_soc_msb; + + batt_soc_msb = batt_soc >> 24; + if (DIV_ROUND_CLOSEST(batt_soc_msb * 100, FULL_SOC_RAW) > + cl->dt.start_soc) { + pr_debug("Battery SOC %d is high!, not starting\n", + batt_soc_msb); + return -EINVAL; + } + + cl->init_cap_uah = div64_s64(cl->learned_cap_uah * batt_soc_msb, + FULL_SOC_RAW); + + if (cl->prime_cc_soc) { + /* + * Prime cc_soc_sw with battery SOC when capacity learning + * begins. + */ + rc = cl->prime_cc_soc(cl->data, batt_soc); + if (rc < 0) { + pr_err("Error in writing cc_soc_sw, rc=%d\n", rc); + goto out; + } + } + + rc = cl->get_cc_soc(cl->data, &cc_soc_sw); + if (rc < 0) { + pr_err("Error in getting CC_SOC_SW, rc=%d\n", rc); + goto out; + } + + cl->init_cc_soc_sw = cc_soc_sw; + pr_debug("Capacity learning started @ battery SOC %d init_cc_soc_sw:%d\n", + batt_soc_msb, cl->init_cc_soc_sw); +out: + return rc; +} + +/** + * cap_learning_done - + * @cl: Capacity learning object + * + * Top level function for getting coulomb counter and post processing the + * data once the capacity learning is complete after charge termination. + * + */ +static int cap_learning_done(struct cap_learning *cl) +{ + int rc; + + rc = cap_learning_process_full_data(cl); + if (rc < 0) { + pr_err("Error in processing cap learning full data, rc=%d\n", + rc); + goto out; + } + + if (cl->prime_cc_soc) { + /* Write a FULL value to cc_soc_sw */ + rc = cl->prime_cc_soc(cl->data, cl->cc_soc_max); + if (rc < 0) { + pr_err("Error in writing cc_soc_sw, rc=%d\n", rc); + goto out; + } + } + + cap_learning_post_process(cl); +out: + return rc; +} + +/** + * cap_learning_update - + * @cl: Capacity learning object + * @batt_temp - Battery temperature + * @batt_soc: Battery State of Charge (SOC) + * @charge_status: Charging status from power supply + * @charge_done: Indicator for charge termination + * @input_present: Indicator for input presence + * @qnovo_en: Indicator for Qnovo enable status + * + * Called by FG/QG driver when there is a state change (Charging status, SOC) + * + */ +void cap_learning_update(struct cap_learning *cl, int batt_temp, + int batt_soc, int charge_status, bool charge_done, + bool input_present, bool qnovo_en) +{ + int rc, batt_soc_msb, batt_soc_prime; + bool prime_cc = false; + + if (!cl) + return; + + mutex_lock(&cl->lock); + + if (batt_temp > cl->dt.max_temp || batt_temp < cl->dt.min_temp || + !cl->learned_cap_uah) { + cl->active = false; + cl->init_cap_uah = 0; + goto out; + } + + batt_soc_msb = (u32)batt_soc >> 24; + pr_debug("Charge_status: %d active: %d batt_soc: %d\n", + charge_status, cl->active, batt_soc_msb); + + /* Initialize the starting point of learning capacity */ + if (!cl->active) { + if (charge_status == POWER_SUPPLY_STATUS_CHARGING) { + rc = cap_learning_begin(cl, batt_soc); + cl->active = (rc == 0); + } else { + if (charge_status == POWER_SUPPLY_STATUS_DISCHARGING || + charge_done) + prime_cc = true; + } + } else { + if (charge_done) { + rc = cap_learning_done(cl); + if (rc < 0) + pr_err("Error in completing capacity learning, rc=%d\n", + rc); + + cl->active = false; + cl->init_cap_uah = 0; + } + + if (charge_status == POWER_SUPPLY_STATUS_DISCHARGING) { + if (!input_present) { + pr_debug("Capacity learning aborted @ battery SOC %d\n", + batt_soc_msb); + cl->active = false; + cl->init_cap_uah = 0; + prime_cc = true; + } + } + + if (charge_status == POWER_SUPPLY_STATUS_NOT_CHARGING) { + if (qnovo_en && input_present) { + /* + * Don't abort the capacity learning when qnovo + * is enabled and input is present where the + * charging status can go to "not charging" + * intermittently. + */ + } else { + pr_debug("Capacity learning aborted @ battery SOC %d\n", + batt_soc_msb); + cl->active = false; + cl->init_cap_uah = 0; + prime_cc = true; + } + } + } + + /* + * Prime CC_SOC_SW when the device is not charging or during charge + * termination when the capacity learning is not active. + */ + + if (prime_cc && cl->prime_cc_soc) { + if (charge_done) + batt_soc_prime = cl->cc_soc_max; + else + batt_soc_prime = batt_soc; + + rc = cl->prime_cc_soc(cl->data, batt_soc_prime); + if (rc < 0) + pr_err("Error in writing cc_soc_sw, rc=%d\n", + rc); + } + +out: + mutex_unlock(&cl->lock); +} + +/** + * cap_learning_abort - + * @cl: Capacity learning object + * + * Aborts the capacity learning and initializes variables + * + */ +void cap_learning_abort(struct cap_learning *cl) +{ + if (!cl) + return; + + mutex_lock(&cl->lock); + pr_debug("Aborting cap_learning\n"); + cl->active = false; + cl->init_cap_uah = 0; + mutex_lock(&cl->lock); +} + +/** + * cap_learning_post_profile_init - + * @cl: Capacity learning object + * @nom_cap_uah: Nominal capacity of battery in uAh + * + * Called by FG/QG once the profile load is complete and nominal capacity + * of battery is known. This also gets the last learned capacity back from + * FG/QG to feed back to the algorithm. + * + */ +int cap_learning_post_profile_init(struct cap_learning *cl, int64_t nom_cap_uah) +{ + int64_t delta_cap_uah, pct_nom_cap_uah; + int rc; + + if (!cl || !cl->data) + return -EINVAL; + + mutex_lock(&cl->lock); + cl->nom_cap_uah = nom_cap_uah; + rc = cl->get_learned_capacity(cl->data, &cl->learned_cap_uah); + if (rc < 0) { + pr_err("Couldn't get learned capacity, rc=%d\n", rc); + goto out; + } + + if (cl->learned_cap_uah != cl->nom_cap_uah) { + if (cl->learned_cap_uah == 0) + cl->learned_cap_uah = cl->nom_cap_uah; + + delta_cap_uah = abs(cl->learned_cap_uah - cl->nom_cap_uah); + pct_nom_cap_uah = div64_s64((int64_t)cl->nom_cap_uah * + CAPACITY_DELTA_DECIPCT, 1000); + /* + * If the learned capacity is out of range by 50% from the + * nominal capacity, then overwrite the learned capacity with + * the nominal capacity. + */ + if (cl->nom_cap_uah && delta_cap_uah > pct_nom_cap_uah) { + pr_debug("learned_cap_uah: %lld is higher than expected, capping it to nominal: %lld\n", + cl->learned_cap_uah, cl->nom_cap_uah); + cl->learned_cap_uah = cl->nom_cap_uah; + } + + rc = cl->store_learned_capacity(cl->data, cl->learned_cap_uah); + if (rc < 0) + pr_err("Error in storing learned_cap_uah, rc=%d\n", rc); + } + +out: + mutex_unlock(&cl->lock); + return rc; +} + +/** + * cap_learning_init - + * @cl: Capacity learning object + * + * FG/QG have to call this during driver probe to validate the required + * parameters after allocating cap_learning object. + * + */ +int cap_learning_init(struct cap_learning *cl) +{ + if (!cl) + return -ENODEV; + + if (!cl->get_learned_capacity || !cl->store_learned_capacity || + !cl->get_cc_soc) { + pr_err("Insufficient functions for supporting capacity learning\n"); + return -EINVAL; + } + + if (!cl->cc_soc_max) { + pr_err("Insufficient parameters for supporting capacity learning\n"); + return -EINVAL; + } + + mutex_init(&cl->lock); + return 0; +} diff --git a/drivers/power/supply/qcom/fg-alg.h b/drivers/power/supply/qcom/fg-alg.h new file mode 100644 index 000000000000..ff5becee881b --- /dev/null +++ b/drivers/power/supply/qcom/fg-alg.h @@ -0,0 +1,73 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __FG_ALG_H__ +#define __FG_ALG_H__ + +#define BUCKET_COUNT 8 +#define BUCKET_SOC_PCT (256 / BUCKET_COUNT) + +struct cycle_counter { + void *data; + bool started[BUCKET_COUNT]; + u16 count[BUCKET_COUNT]; + u8 last_soc[BUCKET_COUNT]; + int id; + int last_bucket; + struct mutex lock; + int (*restore_count)(void *data, u16 *buf, int num_bytes); + int (*store_count)(void *data, u16 *buf, int id, int num_bytes); +}; + +struct cl_params { + int start_soc; + int max_temp; + int min_temp; + int max_cap_inc; + int max_cap_dec; + int max_cap_limit; + int min_cap_limit; + int skew_decipct; +}; + +struct cap_learning { + void *data; + int init_cc_soc_sw; + int cc_soc_max; + int64_t nom_cap_uah; + int64_t init_cap_uah; + int64_t final_cap_uah; + int64_t learned_cap_uah; + bool active; + struct mutex lock; + struct cl_params dt; + int (*get_learned_capacity)(void *data, int64_t *learned_cap_uah); + int (*store_learned_capacity)(void *data, int64_t learned_cap_uah); + int (*get_cc_soc)(void *data, int *cc_soc_sw); + int (*prime_cc_soc)(void *data, u32 cc_soc_sw); +}; + +int restore_cycle_count(struct cycle_counter *counter); +void clear_cycle_count(struct cycle_counter *counter); +void cycle_count_update(struct cycle_counter *counter, int batt_soc, + int charge_status, bool charge_done, bool input_present); +int get_cycle_count(struct cycle_counter *counter); +int cycle_count_init(struct cycle_counter *counter); +void cap_learning_abort(struct cap_learning *cl); +void cap_learning_update(struct cap_learning *cl, int batt_temp, + int batt_soc, int charge_status, bool charge_done, + bool input_present, bool qnovo_en); +int cap_learning_init(struct cap_learning *cl); +int cap_learning_post_profile_init(struct cap_learning *cl, + int64_t nom_cap_uah); + +#endif -- GitLab From 7c9e6c4f094d19f91de980019c33680b04b559e9 Mon Sep 17 00:00:00 2001 From: Mulu He Date: Mon, 19 Mar 2018 20:44:02 +0800 Subject: [PATCH 0364/1635] ARM: dts: msm: Add dl_south for sm8150 Add dl_south funnel and dl_south tpdm device node, they are new HW introduced on sm8150 platform. Change-Id: If8a6833c73dfd0aaee792e1bd27324dc2a607722 Signed-off-by: Mulu He --- .../arm64/boot/dts/qcom/sm8150-coresight.dtsi | 64 ++++++++++++++++++- 1 file changed, 62 insertions(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sm8150-coresight.dtsi b/arch/arm64/boot/dts/qcom/sm8150-coresight.dtsi index 20fb37632442..4baf546a2fea 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-coresight.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-coresight.dtsi @@ -574,6 +574,14 @@ }; }; port@1 { + reg = <2>; + funnel_in1_in_funnel_dl_south: endpoint { + slave-mode; + remote-endpoint = + <&funnel_dl_south_out_funnel_in1>; + }; + }; + port@2 { reg = <3>; funnel_in1_in_modem_etm0: endpoint { slave-mode; @@ -581,7 +589,7 @@ <&modem_etm0_out_funnel_in1>; }; }; - port@2 { + port@3 { reg = <4>; funnel_in1_in_replicator_swao: endpoint { slave-mode; @@ -589,7 +597,7 @@ <&replicator_swao_out_funnel_in1>; }; }; - port@3 { + port@4 { reg = <6>; funnel_in1_in_funnel_dl_north: endpoint { slave-mode; @@ -990,6 +998,58 @@ }; }; + funnel_dl_south: funnel@69c2000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b908>; + reg = <0x69c2000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-dl-south"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + funnel_dl_south_out_funnel_in1: endpoint { + remote-endpoint = + <&funnel_in1_in_funnel_dl_south>; + }; + }; + + port@1 { + reg = <0>; + funnel_dl_south_in_tpdm_dl_south: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_dl_south_out_funnel_dl_south>; + }; + }; + }; + }; + + tpdm_dl_south: tpdm@69c0000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + reg = <0x69c0000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-dl-south"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + tpdm_dl_south_out_funnel_dl_south: endpoint { + remote-endpoint = + <&funnel_dl_south_in_tpdm_dl_south>; + }; + }; + }; + funnel_dl_north: funnel@6ac2000 { compatible = "arm,primecell"; arm,primecell-periphid = <0x0003b908>; -- GitLab From fc8a47dd6ede15fcad3784c68f685356bdc951d1 Mon Sep 17 00:00:00 2001 From: Siva Kumar Akkireddi Date: Thu, 12 Apr 2018 16:52:34 +0530 Subject: [PATCH 0365/1635] ARM: dts: msm: Enable TSENS driver for qcs405 Enable temperature controller (TSENS) on qcs405. Thermal clients can read from TSENS temperature sensors, set temperature thresholds and receive notification. Change-Id: I1b8d5d36fbab9519bc056db8fed49cf7f8afe266 Signed-off-by: Siva Kumar Akkireddi --- Documentation/devicetree/bindings/thermal/tsens.txt | 9 ++++++--- arch/arm64/boot/dts/qcom/qcs405.dtsi | 13 +++++++++++++ 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/Documentation/devicetree/bindings/thermal/tsens.txt b/Documentation/devicetree/bindings/thermal/tsens.txt index 355ae18130bb..21932c12b6ea 100644 --- a/Documentation/devicetree/bindings/thermal/tsens.txt +++ b/Documentation/devicetree/bindings/thermal/tsens.txt @@ -25,10 +25,12 @@ Required properties: for the corresponding SoC. - reg : offset and length of the TSENS registers with associated property in reg-names as "tsens_srot_physical" for TSENS SROT physical address region. TSENS TM - physical address region as "tsens_tm_physical". + physical address region as "tsens_tm_physical", and "tsens_eeprom_physical" for the + TSENS calibration fuse register region. - reg-names : resource names used for the physical address of the TSENS registers. Should be "tsens_srot_physical" for physical address of the TSENS - SROT region and "tsens_tm_physical" for physical address of the TM region. + SROT region, "tsens_tm_physical" for physical address of the TM region and + "tsens_eeprom_physical" for the TSENS calibration fuse register region. - interrupts : TSENS interrupt to notify Upper/Lower and Critical temperature threshold. - interrupt-names: Should be "tsens-upper-lower" for temperature threshold. Add "tsens-critical" for Critical temperature threshold notification @@ -42,7 +44,8 @@ tsens@fc4a8000 { reg = <0xfc4a8000 0x10>, <0xfc4b8000 0x1ff>; reg-names = "tsens_srot_physical", - "tsens_tm_physical"; + "tsens_tm_physical", + "tsens_eeprom_physical", interrupts = <0 184 0>; interrupt-names = "tsens-upper-lower"; }; diff --git a/arch/arm64/boot/dts/qcom/qcs405.dtsi b/arch/arm64/boot/dts/qcom/qcs405.dtsi index d6bfe91c3cde..057ef01fd6c4 100644 --- a/arch/arm64/boot/dts/qcom/qcs405.dtsi +++ b/arch/arm64/boot/dts/qcom/qcs405.dtsi @@ -210,4 +210,17 @@ reg = <0x94c 200>; }; }; + + tsens0: tsens@4a8000 { + compatible = "qcom,qcs405-tsens"; + reg = <0x4a8000 0x1000>, + <0x4a9000 0x1000>, + <0xa4000 0x1000>; + reg-names = "tsens_srot_physical", + "tsens_tm_physical", + "tsens_eeprom_physical"; + interrupts = <0 184 0>; + interrupt-names = "tsens-upper-lower"; + #thermal-sensor-cells = <1>; + }; }; -- GitLab From 0fe9dda6357c85b1000414672a8e1e29d1ab8af9 Mon Sep 17 00:00:00 2001 From: Mulu He Date: Thu, 12 Apr 2018 18:09:16 +0800 Subject: [PATCH 0366/1635] ARM: dts: msm: Enable coresight ssc etm for sm8150 Add ssc funnel and ssc remote etm0 node for sm8150, which used to config ssc etm hardware path when catch etm log from ssc core. Change-Id: Ibcb6ab8cf4e48b50af6faa49cd64346e3bdb329b Signed-off-by: Mulu He --- .../arm64/boot/dts/qcom/sm8150-coresight.dtsi | 60 ++++++++++++++++++- 1 file changed, 58 insertions(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sm8150-coresight.dtsi b/arch/arm64/boot/dts/qcom/sm8150-coresight.dtsi index 20fb37632442..02a39e7b7510 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-coresight.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-coresight.dtsi @@ -197,8 +197,15 @@ <&tmc_etf_swao_in_funnel_swao>; }; }; - port@1 { + reg = <5>; + funnel_swao_in_funnel_ssc: endpoint { + slave-mode; + remote-endpoint= + <&funnel_ssc_out_funnel_swao>; + }; + }; + port@2 { reg = <6>; funnel_swao_in_replicator1_out: endpoint { slave-mode; @@ -206,7 +213,7 @@ <&replicator1_out_funnel_swao>; }; }; - port@2 { + port@3 { reg = <7>; funnel_swao_in_tpda_swao: endpoint { slave-mode; @@ -2230,6 +2237,20 @@ }; }; + ssc_etm0 { + compatible = "qcom,coresight-remote-etm"; + + coresight-name = "coresight-ssc-etm0"; + qcom,inst-id = <8>; + + port { + ssc_etm0_out_funnel_ssc: endpoint { + remote-endpoint = + <&funnel_ssc_in_ssc_etm0>; + }; + }; + }; + funnel_apss_merg: funnel@7810000 { compatible = "arm,primecell"; arm,primecell-periphid = <0x0003b908>; @@ -2550,4 +2571,39 @@ }; }; }; + + funnel_ssc: funnel@6b14000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b908>; + + reg = <0x6b14000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-ssc"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + funnel_ssc_out_funnel_swao: endpoint { + remote-endpoint = + <&funnel_swao_in_funnel_ssc>; + }; + }; + + port@1 { + reg = <0>; + funnel_ssc_in_ssc_etm0: endpoint { + slave-mode; + remote-endpoint = + <&ssc_etm0_out_funnel_ssc>; + }; + }; + }; + }; }; -- GitLab From 10e9b127e1a80d744cc1b6414814d29c4beadbee Mon Sep 17 00:00:00 2001 From: Ajay Singh Parmar Date: Mon, 9 Apr 2018 12:58:26 -0700 Subject: [PATCH 0367/1635] drm/msm/dsi-staging: optimize dsi probe Currently every dsi display is probed. Optimize it by having a main dsi device tree node and reference all available displays. Use the command line parameters to identify which display to select for a given target. Change-Id: Ic88d431829b177afdc91b2282b630ea0356d886a Signed-off-by: Ajay Singh Parmar --- .../devicetree/bindings/drm/msm/sde-dsi.txt | 4 + .../boot/dts/qcom/sm8150-sde-display.dtsi | 316 +++-------- drivers/gpu/drm/msm/dsi-staging/dsi_display.c | 500 ++++++++---------- drivers/gpu/drm/msm/dsi-staging/dsi_display.h | 11 +- drivers/gpu/drm/msm/msm_drv.c | 13 - 5 files changed, 326 insertions(+), 518 deletions(-) diff --git a/Documentation/devicetree/bindings/drm/msm/sde-dsi.txt b/Documentation/devicetree/bindings/drm/msm/sde-dsi.txt index 375d856ab73d..0b660ce672d1 100644 --- a/Documentation/devicetree/bindings/drm/msm/sde-dsi.txt +++ b/Documentation/devicetree/bindings/drm/msm/sde-dsi.txt @@ -62,6 +62,10 @@ Optional properties: - qcom,dsi-display-active: Current active display - qcom,dsi-ctrl: handle to dsi controller device - qcom,dsi-phy: handle to dsi phy device +- qcom,dsi-ctrl-num: Specifies the DSI controllers to use +- qcom,dsi-phy-num: Specifies the DSI PHYs to use +- qcom,dsi-select-clocks: Specifies the required clocks to use +- qcom,dsi-display-list: Specifies the list of supported displays. - qcom,dsi-manager: Specifies dsi manager is present - qcom,dsi-display: Specifies dsi display is present - qcom,hdmi-display: Specifies hdmi is present diff --git a/arch/arm64/boot/dts/qcom/sm8150-sde-display.dtsi b/arch/arm64/boot/dts/qcom/sm8150-sde-display.dtsi index e3d26edf7e10..a86d4ff1fc54 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-sde-display.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-sde-display.dtsi @@ -106,376 +106,234 @@ }; dsi_sharp_4k_dsc_video_display: qcom,dsi-display@0 { - compatible = "qcom,dsi-display"; label = "dsi_sharp_4k_dsc_video_display"; qcom,display-type = "primary"; - qcom,dsi-ctrl = <&mdss_dsi0 &mdss_dsi1>; - qcom,dsi-phy = <&mdss_dsi_phy0 &mdss_dsi_phy1>; - clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>, - <&mdss_dsi0_pll PCLK_MUX_0_CLK>; - clock-names = "src_byte_clk", "src_pixel_clk"; - - pinctrl-names = "panel_active", "panel_suspend"; - pinctrl-0 = <&sde_dsi_active &sde_te_active>; - pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend>; - qcom,platform-te-gpio = <&tlmm 8 0>; - qcom,platform-reset-gpio = <&tlmm 6 0>; - qcom,panel-mode-gpio = <&tlmm 7 0>; + qcom,dsi-ctrl-num = <0 1>; + qcom,dsi-phy-num = <0 1>; + qcom,dsi-select-clocks = "src_byte_clk0", "src_pixel_clk0"; qcom,dsi-panel = <&dsi_sharp_4k_dsc_video>; - - vddio-supply = <&pm855_l14>; - lab-supply = <&lcdb_ldo_vreg>; - ibb-supply = <&lcdb_ncp_vreg>; }; dsi_sharp_4k_dsc_cmd_display: qcom,dsi-display@1 { - compatible = "qcom,dsi-display"; label = "dsi_sharp_4k_dsc_cmd_display"; qcom,display-type = "primary"; - qcom,dsi-ctrl = <&mdss_dsi0 &mdss_dsi1>; - qcom,dsi-phy = <&mdss_dsi_phy0 &mdss_dsi_phy1>; - clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>, - <&mdss_dsi0_pll PCLK_MUX_0_CLK>; - clock-names = "src_byte_clk", "src_pixel_clk"; - - pinctrl-names = "panel_active", "panel_suspend"; - pinctrl-0 = <&sde_dsi_active &sde_te_active>; - pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend>; - qcom,platform-te-gpio = <&tlmm 8 0>; - qcom,platform-reset-gpio = <&tlmm 6 0>; - qcom,panel-mode-gpio = <&tlmm 7 0>; + qcom,dsi-ctrl-num = <0 1>; + qcom,dsi-phy-num = <0 1>; + qcom,dsi-select-clocks = "src_byte_clk0", "src_pixel_clk0"; qcom,dsi-panel = <&dsi_sharp_4k_dsc_cmd>; - vddio-supply = <&pm855_l14>; - lab-supply = <&lcdb_ldo_vreg>; - ibb-supply = <&lcdb_ncp_vreg>; }; dsi_sharp_1080_cmd_display: qcom,dsi-display@2 { - compatible = "qcom,dsi-display"; label = "dsi_sharp_1080_cmd_display"; qcom,display-type = "primary"; - qcom,dsi-ctrl = <&mdss_dsi0>; - qcom,dsi-phy = <&mdss_dsi_phy0>; - clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>, - <&mdss_dsi0_pll PCLK_MUX_0_CLK>; - clock-names = "src_byte_clk", "src_pixel_clk"; + qcom,dsi-ctrl-num = <0>; + qcom,dsi-phy-num = <0>; + qcom,dsi-select-clocks = "src_byte_clk0", "src_pixel_clk0"; - pinctrl-names = "panel_active", "panel_suspend"; - pinctrl-0 = <&sde_dsi_active &sde_te_active>; - pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend>; - qcom,platform-te-gpio = <&tlmm 8 0>; - qcom,platform-reset-gpio = <&tlmm 6 0>; - qcom,panel-mode-gpio = <&tlmm 7 0>; qcom,dsi-panel = <&dsi_sharp_1080_cmd>; - - vddio-supply = <&pm855_l14>; - lab-supply = <&lcdb_ldo_vreg>; - ibb-supply = <&lcdb_ncp_vreg>; }; dsi_dual_sharp_1080_120hz_cmd_display: qcom,dsi-display@3 { - compatible = "qcom,dsi-display"; label = "dsi_dual_sharp_1080_120hz_cmd_display"; qcom,display-type = "primary"; - pinctrl-names = "panel_active", "panel_suspend"; - pinctrl-0 = <&sde_dsi_active &sde_te_active>; - pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend>; - qcom,dsi-ctrl = <&mdss_dsi0 &mdss_dsi1>; - qcom,dsi-phy = <&mdss_dsi_phy0 &mdss_dsi_phy1>; - clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>, - <&mdss_dsi0_pll PCLK_MUX_0_CLK>; - clock-names = "src_byte_clk", "src_pixel_clk"; + qcom,dsi-ctrl-num = <0 1>; + qcom,dsi-phy-num = <0 1>; + qcom,dsi-select-clocks = "src_byte_clk0", "src_pixel_clk0"; - qcom,platform-te-gpio = <&tlmm 8 0>; - qcom,platform-reset-gpio = <&tlmm 6 0>; - qcom,panel-mode-gpio = <&tlmm 7 0>; qcom,dsi-panel = <&dsi_dual_sharp_1080_120hz_cmd>; - - vddio-supply = <&pm855_l14>; - lab-supply = <&lcdb_ldo_vreg>; - ibb-supply = <&lcdb_ncp_vreg>; }; dsi_dual_nt35597_truly_video_display: qcom,dsi-display@4 { - compatible = "qcom,dsi-display"; label = "dsi_dual_nt35597_truly_video_display"; qcom,display-type = "primary"; - qcom,dsi-ctrl = <&mdss_dsi0 &mdss_dsi1>; - qcom,dsi-phy = <&mdss_dsi_phy0 &mdss_dsi_phy1>; - clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>, - <&mdss_dsi0_pll PCLK_MUX_0_CLK>; - clock-names = "src_byte_clk", "src_pixel_clk"; + qcom,dsi-ctrl-num = <0 1>; + qcom,dsi-phy-num = <0 1>; + qcom,dsi-select-clocks = "src_byte_clk0", "src_pixel_clk0"; - pinctrl-names = "panel_active", "panel_suspend"; - pinctrl-0 = <&sde_dsi_active &sde_te_active>; - pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend>; - qcom,platform-te-gpio = <&tlmm 8 0>; - qcom,platform-reset-gpio = <&tlmm 6 0>; - qcom,panel-mode-gpio = <&tlmm 7 0>; qcom,dsi-panel = <&dsi_dual_nt35597_truly_video>; - - vddio-supply = <&pm855_l14>; - lab-supply = <&lcdb_ldo_vreg>; - ibb-supply = <&lcdb_ncp_vreg>; }; dsi_dual_nt35597_truly_cmd_display: qcom,dsi-display@5 { - compatible = "qcom,dsi-display"; label = "dsi_dual_nt35597_truly_cmd_display"; qcom,display-type = "primary"; - qcom,dsi-ctrl = <&mdss_dsi0 &mdss_dsi1>; - qcom,dsi-phy = <&mdss_dsi_phy0 &mdss_dsi_phy1>; - clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>, - <&mdss_dsi0_pll PCLK_MUX_0_CLK>; - clock-names = "src_byte_clk", "src_pixel_clk"; + qcom,dsi-ctrl-num = <0 1>; + qcom,dsi-phy-num = <0 1>; + qcom,dsi-select-clocks = "src_byte_clk0", "src_pixel_clk0"; - pinctrl-names = "panel_active", "panel_suspend"; - pinctrl-0 = <&sde_dsi_active &sde_te_active>; - pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend>; - qcom,platform-te-gpio = <&tlmm 8 0>; - qcom,platform-reset-gpio = <&tlmm 6 0>; - qcom,panel-mode-gpio = <&tlmm 7 0>; qcom,dsi-panel = <&dsi_dual_nt35597_truly_cmd>; - - vddio-supply = <&pm855_l14>; - lab-supply = <&lcdb_ldo_vreg>; - ibb-supply = <&lcdb_ncp_vreg>; }; dsi_nt35597_truly_dsc_cmd_display: qcom,dsi-display@6 { - compatible = "qcom,dsi-display"; label = "dsi_nt35597_truly_dsc_cmd_display"; qcom,display-type = "primary"; - qcom,dsi-ctrl = <&mdss_dsi1>; - qcom,dsi-phy = <&mdss_dsi_phy1>; - clocks = <&mdss_dsi1_pll BYTECLK_MUX_1_CLK>, - <&mdss_dsi1_pll PCLK_MUX_1_CLK>; - clock-names = "src_byte_clk", "src_pixel_clk"; + qcom,dsi-ctrl-num = <1>; + qcom,dsi-phy-num = <1>; + qcom,dsi-select-clocks = "src_byte_clk1", "src_pixel_clk1"; - pinctrl-names = "panel_active", "panel_suspend"; - pinctrl-0 = <&sde_dsi_active &sde_te_active>; - pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend>; - qcom,platform-te-gpio = <&tlmm 8 0>; - qcom,platform-reset-gpio = <&tlmm 6 0>; - qcom,panel-mode-gpio = <&tlmm 7 0>; qcom,dsi-panel = <&dsi_nt35597_truly_dsc_cmd>; - - vddio-supply = <&pm855_l14>; - lab-supply = <&lcdb_ldo_vreg>; - ibb-supply = <&lcdb_ncp_vreg>; }; dsi_nt35597_truly_dsc_video_display: qcom,dsi-display@7 { - compatible = "qcom,dsi-display"; label = "dsi_nt35597_truly_dsc_video_display"; qcom,display-type = "primary"; - qcom,dsi-ctrl = <&mdss_dsi1>; - qcom,dsi-phy = <&mdss_dsi_phy1>; - clocks = <&mdss_dsi1_pll BYTECLK_MUX_1_CLK>, - <&mdss_dsi1_pll PCLK_MUX_1_CLK>; - clock-names = "src_byte_clk", "src_pixel_clk"; + qcom,dsi-ctrl-num = <1>; + qcom,dsi-phy-num = <1>; + qcom,dsi-select-clocks = "src_byte_clk1", "src_pixel_clk1"; - pinctrl-names = "panel_active", "panel_suspend"; - pinctrl-0 = <&sde_dsi_active &sde_te_active>; - pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend>; - qcom,platform-te-gpio = <&tlmm 8 0>; - qcom,platform-reset-gpio = <&tlmm 6 0>; - qcom,panel-mode-gpio = <&tlmm 7 0>; qcom,dsi-panel = <&dsi_nt35597_truly_dsc_video>; - - vddio-supply = <&pm855_l14>; - lab-supply = <&lcdb_ldo_vreg>; - ibb-supply = <&lcdb_ncp_vreg>; }; dsi_sim_vid_display: qcom,dsi-display@8 { - compatible = "qcom,dsi-display"; label = "dsi_sim_vid_display"; qcom,display-type = "primary"; - qcom,dsi-ctrl = <&mdss_dsi0>; - qcom,dsi-phy = <&mdss_dsi_phy0>; - clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>, - <&mdss_dsi0_pll PCLK_MUX_0_CLK>; - clock-names = "src_byte_clk", "src_pixel_clk"; - - pinctrl-names = "panel_active", "panel_suspend"; - pinctrl-0 = <&sde_dsi_active &sde_te_active>; - pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend>; + qcom,dsi-ctrl-num = <0>; + qcom,dsi-phy-num = <0>; + qcom,dsi-select-clocks = "src_byte_clk0", "src_pixel_clk0"; qcom,dsi-panel = <&dsi_sim_vid>; }; dsi_dual_sim_vid_display: qcom,dsi-display@9 { - compatible = "qcom,dsi-display"; label = "dsi_dual_sim_vid_display"; qcom,display-type = "primary"; - qcom,dsi-ctrl = <&mdss_dsi0 &mdss_dsi1>; - qcom,dsi-phy = <&mdss_dsi_phy0 &mdss_dsi_phy1>; - clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>, - <&mdss_dsi0_pll PCLK_MUX_0_CLK>; - clock-names = "src_byte_clk", "src_pixel_clk"; - - pinctrl-names = "panel_active", "panel_suspend"; - pinctrl-0 = <&sde_dsi_active &sde_te_active>; - pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend>; + qcom,dsi-ctrl-num = <0 1>; + qcom,dsi-phy-num = <0 1>; + qcom,dsi-select-clocks = "src_byte_clk0", "src_pixel_clk0"; qcom,dsi-panel = <&dsi_dual_sim_vid>; }; dsi_sim_cmd_display: qcom,dsi-display@10 { - compatible = "qcom,dsi-display"; label = "dsi_sim_cmd_display"; qcom,display-type = "primary"; - qcom,dsi-ctrl = <&mdss_dsi0>; - qcom,dsi-phy = <&mdss_dsi_phy0>; - clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>, - <&mdss_dsi0_pll PCLK_MUX_0_CLK>; - clock-names = "src_byte_clk", "src_pixel_clk"; - - pinctrl-names = "panel_active", "panel_suspend"; - pinctrl-0 = <&sde_dsi_active &sde_te_active>; - pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend>; + qcom,dsi-ctrl-num = <0>; + qcom,dsi-phy-num = <0>; + qcom,dsi-select-clocks = "src_byte_clk0", "src_pixel_clk0"; qcom,dsi-panel = <&dsi_sim_cmd>; }; dsi_dual_sim_cmd_display: qcom,dsi-display@11 { - compatible = "qcom,dsi-display"; label = "dsi_dual_sim_cmd_display"; qcom,display-type = "primary"; - qcom,dsi-ctrl = <&mdss_dsi0 &mdss_dsi1>; - qcom,dsi-phy = <&mdss_dsi_phy0 &mdss_dsi_phy1>; - clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>, - <&mdss_dsi0_pll PCLK_MUX_0_CLK>; - clock-names = "src_byte_clk", "src_pixel_clk"; - - pinctrl-names = "panel_active", "panel_suspend"; - pinctrl-0 = <&sde_dsi_active &sde_te_active>; - pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend>; + qcom,dsi-ctrl-num = <0 1>; + qcom,dsi-phy-num = <0 1>; + qcom,dsi-select-clocks = "src_byte_clk0", "src_pixel_clk0"; qcom,dsi-panel = <&dsi_dual_sim_cmd>; }; dsi_sim_dsc_375_cmd_display: qcom,dsi-display@12 { - compatible = "qcom,dsi-display"; label = "dsi_sim_dsc_375_cmd_display"; qcom,display-type = "primary"; - qcom,dsi-ctrl = <&mdss_dsi0>; - qcom,dsi-phy = <&mdss_dsi_phy0>; - clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>, - <&mdss_dsi0_pll PCLK_MUX_0_CLK>; - clock-names = "src_byte_clk", "src_pixel_clk"; - - pinctrl-names = "panel_active", "panel_suspend"; - pinctrl-0 = <&sde_dsi_active &sde_te_active>; - pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend>; + qcom,dsi-ctrl-num = <0>; + qcom,dsi-phy-num = <0>; + qcom,dsi-select-clocks = "src_byte_clk0", "src_pixel_clk0"; qcom,dsi-panel = <&dsi_sim_dsc_375_cmd>; }; dsi_dual_sim_dsc_375_cmd_display: qcom,dsi-display@13 { - compatible = "qcom,dsi-display"; label = "dsi_dual_sim_dsc_375_cmd_display"; qcom,display-type = "primary"; - qcom,dsi-ctrl = <&mdss_dsi0 &mdss_dsi1>; - qcom,dsi-phy = <&mdss_dsi_phy0 &mdss_dsi_phy1>; - clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>, - <&mdss_dsi0_pll PCLK_MUX_0_CLK>; - clock-names = "src_byte_clk", "src_pixel_clk"; - - pinctrl-names = "panel_active", "panel_suspend"; - pinctrl-0 = <&sde_dsi_active &sde_te_active>; - pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend>; + qcom,dsi-ctrl-num = <0 1>; + qcom,dsi-phy-num = <0 1>; + qcom,dsi-select-clocks = "src_byte_clk0", "src_pixel_clk0"; qcom,dsi-panel = <&dsi_dual_sim_dsc_375_cmd>; }; dsi_sw43404_amoled_cmd_display: qcom,dsi-display@14 { - compatible = "qcom,dsi-display"; label = "dsi_sw43404_amoled_cmd_display"; qcom,display-type = "primary"; - qcom,dsi-ctrl = <&mdss_dsi0>; - qcom,dsi-phy = <&mdss_dsi_phy0>; - clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>, - <&mdss_dsi0_pll PCLK_MUX_0_CLK>; - clock-names = "src_byte_clk", "src_pixel_clk"; - - pinctrl-names = "panel_active", "panel_suspend"; - pinctrl-0 = <&sde_dsi_active &sde_te_active>; - pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend>; - qcom,platform-te-gpio = <&tlmm 8 0>; - qcom,platform-reset-gpio = <&tlmm 6 0>; - qcom,panel-mode-gpio = <&tlmm 7 0>; + qcom,dsi-ctrl-num = <0>; + qcom,dsi-phy-num = <0>; + qcom,dsi-select-clocks = "src_byte_clk0", "src_pixel_clk0"; qcom,dsi-panel = <&dsi_sw43404_amoled_cmd>; - vddio-supply = <&pm855_l14>; }; dsi_nt35695b_truly_fhd_cmd_display: qcom,dsi-display@15 { - compatible = "qcom,dsi-display"; label = "dsi_nt35695b_truly_fhd_cmd_display"; qcom,display-type = "primary"; - qcom,dsi-ctrl = <&mdss_dsi0>; - qcom,dsi-phy = <&mdss_dsi_phy0>; - clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>, - <&mdss_dsi0_pll PCLK_MUX_0_CLK>; - clock-names = "src_byte_clk", "src_pixel_clk"; - - pinctrl-names = "panel_active", "panel_suspend"; - pinctrl-0 = <&sde_dsi_active &sde_te_active>; - pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend>; - qcom,platform-te-gpio = <&tlmm 8 0>; - qcom,platform-reset-gpio = <&tlmm 6 0>; - qcom,panel-mode-gpio = <&tlmm 7 0>; + qcom,dsi-ctrl-num = <0>; + qcom,dsi-phy-num = <0>; + qcom,dsi-select-clocks = "src_byte_clk0", "src_pixel_clk0"; qcom,dsi-panel = <&dsi_nt35695b_truly_fhd_cmd>; - vddio-supply = <&pm855_l14>; - lab-supply = <&lcdb_ldo_vreg>; - ibb-supply = <&lcdb_ncp_vreg>; }; dsi_nt35695b_truly_fhd_video_display: qcom,dsi-display@16 { - compatible = "qcom,dsi-display"; label = "dsi_nt35695b_truly_fhd_video_display"; qcom,display-type = "primary"; - qcom,dsi-ctrl = <&mdss_dsi0>; - qcom,dsi-phy = <&mdss_dsi_phy0>; + qcom,dsi-ctrl-num = <0>; + qcom,dsi-phy-num = <0>; + qcom,dsi-select-clocks = "src_byte_clk0", "src_pixel_clk0"; + + qcom,dsi-panel = <&dsi_nt35695b_truly_fhd_video>; + }; + + sde_dsi: qcom,dsi-display { + compatible = "qcom,dsi-display"; + + qcom,dsi-ctrl = <&mdss_dsi0 &mdss_dsi1>; + qcom,dsi-phy = <&mdss_dsi_phy0 &mdss_dsi_phy1>; + clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>, - <&mdss_dsi0_pll PCLK_MUX_0_CLK>; - clock-names = "src_byte_clk", "src_pixel_clk"; + <&mdss_dsi0_pll PCLK_MUX_0_CLK>, + <&mdss_dsi1_pll BYTECLK_MUX_1_CLK>, + <&mdss_dsi1_pll PCLK_MUX_1_CLK>; + clock-names = "src_byte_clk0", "src_pixel_clk0", + "src_byte_clk1", "src_pixel_clk1"; pinctrl-names = "panel_active", "panel_suspend"; pinctrl-0 = <&sde_dsi_active &sde_te_active>; pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend>; - qcom,platform-te-gpio = <&tlmm 8 0>; - qcom,platform-reset-gpio = <&tlmm 6 0>; - qcom,panel-mode-gpio = <&tlmm 7 0>; - qcom,dsi-panel = <&dsi_nt35695b_truly_fhd_video>; + qcom,platform-te-gpio = <&tlmm 8 0>; vddio-supply = <&pm855_l14>; lab-supply = <&lcdb_ldo_vreg>; ibb-supply = <&lcdb_ncp_vreg>; + + qcom,dsi-display-list = + <&dsi_sharp_4k_dsc_video_display + &dsi_sharp_4k_dsc_cmd_display + &dsi_sharp_1080_cmd_display + &dsi_dual_sharp_1080_120hz_cmd_display + &dsi_dual_nt35597_truly_video_display + &dsi_dual_nt35597_truly_cmd_display + &dsi_nt35597_truly_dsc_cmd_display + &dsi_nt35597_truly_dsc_video_display + &dsi_sim_vid_display + &dsi_dual_sim_vid_display + &dsi_sim_cmd_display + &dsi_dual_sim_cmd_display + &dsi_sim_dsc_375_cmd_display + &dsi_dual_sim_dsc_375_cmd_display + &dsi_sw43404_amoled_cmd_display + &dsi_nt35695b_truly_fhd_cmd_display + &dsi_nt35695b_truly_fhd_video_display>; }; sde_wb: qcom,wb-display@0 { @@ -508,7 +366,7 @@ }; &mdss_mdp { - connectors = <&sde_wb &sde_dp>; + connectors = <&sde_wb &sde_dp &sde_dsi>; }; /* PHY TIMINGS REVISION P */ diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_display.c b/drivers/gpu/drm/msm/dsi-staging/dsi_display.c index 6b8995844d1d..3c49b79af708 100644 --- a/drivers/gpu/drm/msm/dsi-staging/dsi_display.c +++ b/drivers/gpu/drm/msm/dsi-staging/dsi_display.c @@ -38,19 +38,16 @@ #define MAX_NAME_SIZE 64 -static DEFINE_MUTEX(dsi_display_list_lock); -static LIST_HEAD(dsi_display_list); static char dsi_display_primary[MAX_CMDLINE_PARAM_LEN]; static char dsi_display_secondary[MAX_CMDLINE_PARAM_LEN]; static struct dsi_display_boot_param boot_displays[MAX_DSI_ACTIVE_DISPLAY]; -static struct device_node *default_active_node; +static struct dsi_display *default_display; +static bool display_from_cmdline; static const struct of_device_id dsi_display_dt_match[] = { {.compatible = "qcom,dsi-display"}, {} }; -static struct dsi_display *main_display; - static void dsi_display_mask_ctrl_error_interrupts(struct dsi_display *display) { int i; @@ -1774,20 +1771,6 @@ static bool validate_dsi_display_selection(void) return true; } -struct device_node *dsi_display_get_boot_display(int index) -{ - - pr_err("index = %d\n", index); - - if (boot_displays[index].node) - return boot_displays[index].node; - else if ((index == (MAX_DSI_ACTIVE_DISPLAY - 1)) - && (default_active_node)) - return default_active_node; - else - return NULL; -} - static int dsi_display_phy_power_on(struct dsi_display *display) { int rc = 0; @@ -2463,87 +2446,72 @@ static int dsi_display_clocks_deinit(struct dsi_display *display) return rc; } +static bool dsi_display_check_prefix(const char *clk_prefix, + const char *clk_name) +{ + return !!strnstr(clk_name, clk_prefix, strlen(clk_name)); +} + static int dsi_display_clocks_init(struct dsi_display *display) { - int rc = 0; + int i, rc = 0, num_clk = 0; + const char *clk_name; + const char *src_byte = "src_byte", *src_pixel = "src_pixel"; + const char *mux_byte = "mux_byte", *mux_pixel = "mux_pixel"; + const char *shadow_byte = "shadow_byte", *shadow_pixel = "shadow_pixel"; + struct clk *dsi_clk; struct dsi_clk_link_set *src = &display->clock_info.src_clks; struct dsi_clk_link_set *mux = &display->clock_info.mux_clks; struct dsi_clk_link_set *shadow = &display->clock_info.shadow_clks; - src->byte_clk = devm_clk_get(&display->pdev->dev, "src_byte_clk"); - if (IS_ERR_OR_NULL(src->byte_clk)) { - rc = PTR_ERR(src->byte_clk); - src->byte_clk = NULL; - pr_err("failed to get src_byte_clk, rc=%d\n", rc); - goto error; - } + num_clk = of_property_count_strings(display->disp_node, + "qcom,dsi-select-clocks"); - src->pixel_clk = devm_clk_get(&display->pdev->dev, "src_pixel_clk"); - if (IS_ERR_OR_NULL(src->pixel_clk)) { - rc = PTR_ERR(src->pixel_clk); - src->pixel_clk = NULL; - pr_err("failed to get src_pixel_clk, rc=%d\n", rc); - goto error; - } + for (i = 0; i < num_clk; i++) { + of_property_read_string_index(display->disp_node, + "qcom,dsi-select-clocks", i, &clk_name); - mux->byte_clk = devm_clk_get(&display->pdev->dev, "mux_byte_clk"); - if (IS_ERR_OR_NULL(mux->byte_clk)) { - rc = PTR_ERR(mux->byte_clk); - pr_debug("failed to get mux_byte_clk, rc=%d\n", rc); - mux->byte_clk = NULL; - /* - * Skip getting rest of clocks since one failed. This is a - * non-critical failure since these clocks are requied only for - * dynamic refresh use cases. - */ - rc = 0; - goto done; - }; + pr_debug("clock name:%s\n", clk_name); - mux->pixel_clk = devm_clk_get(&display->pdev->dev, "mux_pixel_clk"); - if (IS_ERR_OR_NULL(mux->pixel_clk)) { - rc = PTR_ERR(mux->pixel_clk); - mux->pixel_clk = NULL; - pr_debug("failed to get mux_pixel_clk, rc=%d\n", rc); - /* - * Skip getting rest of clocks since one failed. This is a - * non-critical failure since these clocks are requied only for - * dynamic refresh use cases. - */ - rc = 0; - goto done; - }; + dsi_clk = devm_clk_get(&display->pdev->dev, clk_name); + if (IS_ERR_OR_NULL(dsi_clk)) { + rc = PTR_ERR(dsi_clk); - shadow->byte_clk = devm_clk_get(&display->pdev->dev, "shadow_byte_clk"); - if (IS_ERR_OR_NULL(shadow->byte_clk)) { - rc = PTR_ERR(shadow->byte_clk); - shadow->byte_clk = NULL; - pr_err("failed to get shadow_byte_clk, rc=%d\n", rc); - /* - * Skip getting rest of clocks since one failed. This is a - * non-critical failure since these clocks are requied only for - * dynamic refresh use cases. - */ - rc = 0; - goto done; - }; + pr_err("failed to get %s, rc=%d\n", clk_name, rc); + goto error; + } - shadow->pixel_clk = devm_clk_get(&display->pdev->dev, - "shadow_pixel_clk"); - if (IS_ERR_OR_NULL(shadow->pixel_clk)) { - rc = PTR_ERR(shadow->pixel_clk); - shadow->pixel_clk = NULL; - pr_err("failed to get shadow_pixel_clk, rc=%d\n", rc); - /* - * Skip getting rest of clocks since one failed. This is a - * non-critical failure since these clocks are requied only for - * dynamic refresh use cases. - */ - rc = 0; - goto done; - }; + if (dsi_display_check_prefix(src_byte, clk_name)) { + src->byte_clk = dsi_clk; + continue; + } + + if (dsi_display_check_prefix(src_pixel, clk_name)) { + src->pixel_clk = dsi_clk; + continue; + } + + if (dsi_display_check_prefix(mux_byte, clk_name)) { + mux->byte_clk = dsi_clk; + continue; + } + + if (dsi_display_check_prefix(mux_pixel, clk_name)) { + mux->pixel_clk = dsi_clk; + continue; + } + + if (dsi_display_check_prefix(shadow_byte, clk_name)) { + shadow->byte_clk = dsi_clk; + continue; + } + + if (dsi_display_check_prefix(shadow_pixel, clk_name)) { + shadow->pixel_clk = dsi_clk; + continue; + } + } -done: return 0; error: (void)dsi_display_clocks_deinit(display); @@ -2927,62 +2895,83 @@ static int dsi_display_parse_lane_map(struct dsi_display *display) return 0; } +static int dsi_display_get_phandle_index( + struct dsi_display *display, + const char *propname, int count, int index) +{ + struct device_node *disp_node = display->disp_node; + u32 *val = NULL; + int rc = 0; + + val = kzalloc(count, GFP_KERNEL); + if (!val) { + rc = -ENOMEM; + goto end; + } + + if (index >= count) + goto end; + + rc = of_property_read_u32_array(disp_node, propname, val, count); + if (rc) + goto end; + + rc = val[index]; + + pr_debug("%s index=%d\n", propname, rc); +end: + kfree(val); + return rc; +} + static int dsi_display_parse_dt(struct dsi_display *display) { int rc = 0; int i; u32 phy_count = 0; - struct device_node *of_node; - - /* Parse controllers */ - for (i = 0; i < MAX_DSI_CTRLS_PER_DISPLAY; i++) { - of_node = of_parse_phandle(display->pdev->dev.of_node, - "qcom,dsi-ctrl", i); - if (!of_node) { - if (!i) { - pr_err("No controllers present\n"); - return -ENODEV; - } - break; - } + struct device_node *of_node = display->pdev->dev.of_node; + struct device_node *disp_node = display->disp_node; - display->ctrl[i].ctrl_of_node = of_node; - display->ctrl_count++; - } - - /* Parse Phys */ - for (i = 0; i < MAX_DSI_CTRLS_PER_DISPLAY; i++) { - of_node = of_parse_phandle(display->pdev->dev.of_node, - "qcom,dsi-phy", i); - if (!of_node) { - if (!i) { - pr_err("No PHY devices present\n"); - rc = -ENODEV; - goto error; - } - break; - } + display->ctrl_count = of_property_count_u32_elems(disp_node, + "qcom,dsi-ctrl-num"); + phy_count = of_property_count_u32_elems(disp_node, + "qcom,dsi-phy-num"); - display->ctrl[i].phy_of_node = of_node; - phy_count++; + if (!phy_count || !display->ctrl_count) { + pr_err("no ctrl/phys found\n"); + rc = -ENODEV; + goto error; } if (phy_count != display->ctrl_count) { - pr_err("Number of controllers does not match PHYs\n"); + pr_err("different ctrl and phy counts\n"); rc = -ENODEV; goto error; } - of_node = of_parse_phandle(display->pdev->dev.of_node, - "qcom,dsi-panel", 0); - if (!of_node) { + for (i = 0; i < display->ctrl_count; i++) { + struct dsi_display_ctrl *ctrl = &display->ctrl[i]; + int index; + + index = dsi_display_get_phandle_index(display, + "qcom,dsi-ctrl-num", display->ctrl_count, i); + ctrl->ctrl_of_node = of_parse_phandle(of_node, + "qcom,dsi-ctrl", index); + of_node_put(ctrl->ctrl_of_node); + + index = dsi_display_get_phandle_index(display, + "qcom,dsi-phy-num", display->ctrl_count, i); + ctrl->phy_of_node = of_parse_phandle(of_node, + "qcom,dsi-phy", index); + of_node_put(ctrl->phy_of_node); + } + + display->panel_of = of_parse_phandle(disp_node, "qcom,dsi-panel", 0); + if (!display->panel_of) { pr_err("No Panel device present\n"); rc = -ENODEV; goto error; - } else { - display->panel_of = of_node; } - error: return rc; } @@ -3922,122 +3911,133 @@ static struct platform_driver dsi_display_driver = { }, }; -int dsi_display_dev_probe(struct platform_device *pdev) +static void dsi_display_setup(struct dsi_display *display) +{ + struct platform_device *pdev = display->pdev; + + /* use default topology of every mode if not overridden */ + display->cmdline_topology = NO_OVERRIDE; + display->cmdline_timing = 0; + + if (boot_displays[DSI_PRIMARY].boot_disp_en) { + dsi_display_name_compare(pdev->dev.of_node, + display->name, DSI_PRIMARY); + + dsi_display_parse_cmdline_topology(display, DSI_PRIMARY); + boot_displays[DSI_PRIMARY].node = pdev->dev.of_node; + boot_displays[DSI_PRIMARY].disp = display; + } + + if (boot_displays[DSI_SECONDARY].boot_disp_en) { + boot_displays[DSI_SECONDARY].node = pdev->dev.of_node; + boot_displays[DSI_SECONDARY].disp = display; + + if (validate_dsi_display_selection()) + dsi_display_parse_cmdline_topology(display, + DSI_SECONDARY); + else + boot_displays[DSI_SECONDARY].boot_disp_en = false; + + } + + display->display_type = of_get_property(pdev->dev.of_node, + "qcom,display-type", NULL); + if (!display->display_type) + display->display_type = "unknown"; +} + +static int dsi_display_init(struct dsi_display *display, + struct platform_device *pdev) { int rc = 0; - struct dsi_display *display; - static bool display_from_cmdline, boot_displays_parsed; - static bool comp_add_success; - static struct device_node *primary_np, *secondary_np; + + mutex_init(&display->display_lock); + + rc = _dsi_display_dev_init(display); + if (rc) { + pr_err("device init failed, rc=%d\n", rc); + goto end; + } + + rc = component_add(&pdev->dev, &dsi_display_comp_ops); + if (rc) + pr_err("component add failed, rc=%d\n", rc); + + pr_debug("component add success: %s\n", display->name); +end: + return rc; +} + +int dsi_display_dev_probe(struct platform_device *pdev) +{ + struct dsi_display *display = NULL; + struct device_node *node = NULL, *disp_node = NULL; + const char *name = NULL; + const char *disp_list = "qcom,dsi-display-list"; + const char *disp_active = "qcom,dsi-display-active"; + int i, count, rc = 0; if (!pdev || !pdev->dev.of_node) { pr_err("pdev not found\n"); - return -ENODEV; + rc = -ENODEV; + goto end; } display = devm_kzalloc(&pdev->dev, sizeof(*display), GFP_KERNEL); if (!display) return -ENOMEM; - display->name = of_get_property(pdev->dev.of_node, "label", NULL); - if (!display->name) - display->name = "unknown"; + if (boot_displays[DSI_PRIMARY].boot_disp_en) + display_from_cmdline = true; - if (!boot_displays_parsed) { - boot_displays[DSI_PRIMARY].boot_disp_en = false; - boot_displays[DSI_SECONDARY].boot_disp_en = false; - if (dsi_display_parse_boot_display_selection()) - pr_debug("Display Boot param not valid/available\n"); + node = pdev->dev.of_node; + count = of_count_phandle_with_args(node, disp_list, NULL); - boot_displays_parsed = true; - } + for (i = 0; i < count; i++) { + struct device_node *np; - /* use default topology of every mode if not overridden */ - display->cmdline_topology = NO_OVERRIDE; - display->cmdline_timing = 0; + np = of_parse_phandle(node, disp_list, i); + name = of_get_property(np, "label", NULL); - if ((!display_from_cmdline) && - (boot_displays[DSI_PRIMARY].boot_disp_en)) { - display->is_active = dsi_display_name_compare(pdev->dev.of_node, - display->name, DSI_PRIMARY); - if (display->is_active) { - if (comp_add_success) { - (void)_dsi_display_dev_deinit(main_display); - component_del(&main_display->pdev->dev, - &dsi_display_comp_ops); - mutex_lock(&dsi_display_list_lock); - list_del(&main_display->list); - mutex_unlock(&dsi_display_list_lock); - comp_add_success = false; - default_active_node = NULL; - pr_debug("removed the existing comp ops\n"); + if (display_from_cmdline) { + if (name && !strcmp(boot_displays[0].name, name)) { + disp_node = np; + break; + } + } else { + if (of_property_read_bool(np, disp_active)) { + disp_node = np; + break; } - /* - * Need to add component for - * the secondary DSI display - * when more than one DSI display - * is supported. - */ - pr_debug("cmdline primary dsi: %s\n", - display->name); - display_from_cmdline = true; - dsi_display_parse_cmdline_topology(display, - DSI_PRIMARY); - primary_np = pdev->dev.of_node; } + + of_node_put(np); } - if (boot_displays[DSI_SECONDARY].boot_disp_en - && !secondary_np - && dsi_display_name_compare(pdev->dev.of_node, - display->name, DSI_SECONDARY)) { - pr_debug("cmdline secondary dsi: %s\n", - display->name); - secondary_np = pdev->dev.of_node; - if (primary_np) { - if (validate_dsi_display_selection()) { - display->is_active = true; - dsi_display_parse_cmdline_topology( - display, DSI_SECONDARY); - } else { - boot_displays[DSI_SECONDARY] - .boot_disp_en = false; - } - } + if (!name || !disp_node) { + pr_err("display node not found\n"); + rc = -EINVAL; + goto end; } - display->display_type = of_get_property(pdev->dev.of_node, - "qcom,display-type", NULL); - if (!display->display_type) - display->display_type = "unknown"; - mutex_init(&display->display_lock); - display->pdev = pdev; - platform_set_drvdata(pdev, display); - mutex_lock(&dsi_display_list_lock); - list_add(&display->list, &dsi_display_list); - mutex_unlock(&dsi_display_list_lock); + /* decrement ref count */ + of_node_put(disp_node); - if (!display_from_cmdline) - display->is_active = of_property_read_bool(pdev->dev.of_node, - "qcom,dsi-display-active"); + display->disp_node = disp_node; + display->name = name; + display->pdev = pdev; - if (display->is_active) { - main_display = display; - rc = _dsi_display_dev_init(display); - if (rc) { - pr_err("device init failed, rc=%d\n", rc); - return rc; - } + platform_set_drvdata(pdev, display); + default_display = display; - rc = component_add(&pdev->dev, &dsi_display_comp_ops); - if (rc) - pr_err("component add failed, rc=%d\n", rc); + dsi_display_setup(display); + rc = dsi_display_init(display, pdev); + if (rc) + goto end; - comp_add_success = true; - pr_debug("Component_add success: %s\n", display->name); - if (!display_from_cmdline) - default_active_node = pdev->dev.of_node; - } + return 0; +end: + devm_kfree(&pdev->dev, display); return rc; } @@ -4045,7 +4045,6 @@ int dsi_display_dev_remove(struct platform_device *pdev) { int rc = 0; struct dsi_display *display; - struct dsi_display *pos, *tmp; if (!pdev) { pr_err("Invalid device\n"); @@ -4056,15 +4055,6 @@ int dsi_display_dev_remove(struct platform_device *pdev) (void)_dsi_display_dev_deinit(display); - mutex_lock(&dsi_display_list_lock); - list_for_each_entry_safe(pos, tmp, &dsi_display_list, list) { - if (pos == display) { - list_del(&display->list); - break; - } - } - mutex_unlock(&dsi_display_list_lock); - platform_set_drvdata(pdev, NULL); devm_kfree(&pdev->dev, display); return rc; @@ -4072,22 +4062,21 @@ int dsi_display_dev_remove(struct platform_device *pdev) int dsi_display_get_num_of_displays(void) { - int count = 0; - struct dsi_display *display; + int count = 0, i; - mutex_lock(&dsi_display_list_lock); + if (!display_from_cmdline) + return 1; - list_for_each_entry(display, &dsi_display_list, list) { - count++; + for (i = 0; i < MAX_DSI_ACTIVE_DISPLAY; i++) { + if (boot_displays[i].boot_disp_en) + count++; } - mutex_unlock(&dsi_display_list_lock); return count; } int dsi_display_get_active_displays(void **display_array, u32 max_display_count) { - struct dsi_display *pos; int i = 0; if (!display_array || !max_display_count) { @@ -4096,42 +4085,16 @@ int dsi_display_get_active_displays(void **display_array, u32 max_display_count) return 0; } - mutex_lock(&dsi_display_list_lock); - - list_for_each_entry(pos, &dsi_display_list, list) { - if (i >= max_display_count) { - pr_err("capping display count to %d\n", i); - break; - } - if (pos->is_active) - display_array[i++] = pos; + if (!display_from_cmdline) { + display_array[0] = default_display; + return 1; } - mutex_unlock(&dsi_display_list_lock); - return i; -} - -struct dsi_display *dsi_display_get_display_by_name(const char *name) -{ - struct dsi_display *display = NULL, *pos; - - mutex_lock(&dsi_display_list_lock); - - list_for_each_entry(pos, &dsi_display_list, list) { - if (!strcmp(name, pos->name)) - display = pos; + for (i = 0; i < max_display_count; i++) { + if (boot_displays[i].boot_disp_en) + display_array[i] = boot_displays[i].disp; } - - mutex_unlock(&dsi_display_list_lock); - - return display; -} - -void dsi_display_set_active_state(struct dsi_display *display, bool is_active) -{ - mutex_lock(&display->display_lock); - display->is_active = is_active; - mutex_unlock(&display->display_lock); + return i; } int dsi_display_drm_bridge_init(struct dsi_display *display, @@ -5553,6 +5516,9 @@ static int __init dsi_display_register(void) { dsi_phy_drv_register(); dsi_ctrl_drv_register(); + + dsi_display_parse_boot_display_selection(); + return platform_driver_register(&dsi_display_driver); } diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_display.h b/drivers/gpu/drm/msm/dsi-staging/dsi_display.h index 1a184d7ddf64..10e6ae551b1e 100644 --- a/drivers/gpu/drm/msm/dsi-staging/dsi_display.h +++ b/drivers/gpu/drm/msm/dsi-staging/dsi_display.h @@ -107,6 +107,7 @@ struct dsi_display_boot_param { int length; struct device_node *node; int cmdline_topology; + void *disp; }; /** @@ -170,7 +171,6 @@ struct dsi_display { const char *name; const char *display_type; struct list_head list; - bool is_active; bool is_cont_splash_enabled; struct mutex display_lock; @@ -179,6 +179,7 @@ struct dsi_display { /* panel info */ struct dsi_panel *panel; + struct device_node *disp_node; struct device_node *panel_of; struct dsi_display_mode *modes; @@ -247,14 +248,6 @@ int dsi_display_get_num_of_displays(void); int dsi_display_get_active_displays(void **display_array, u32 max_display_count); -/** - * dsi_display_get_boot_display()- get DSI boot display name - * @index: index of display selection - * - * Return: returns the display node pointer - */ -struct device_node *dsi_display_get_boot_display(int index); - /** * dsi_display_get_display_by_name()- finds display by name * @name: name of the display. diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c index 5fff75221018..ec0e0c36cea6 100644 --- a/drivers/gpu/drm/msm/msm_drv.c +++ b/drivers/gpu/drm/msm/msm_drv.c @@ -47,7 +47,6 @@ #include "msm_gpu.h" #include "msm_kms.h" #include "sde_wb.h" -#include "dsi_display.h" /* * MSM driver version: @@ -1824,7 +1823,6 @@ static int add_display_components(struct device *dev, { struct device *mdp_dev = NULL; struct device_node *node; - const char *name; int ret; if (of_device_is_compatible(dev->of_node, "qcom,sde-kms")) { @@ -1839,17 +1837,6 @@ static int add_display_components(struct device *dev, component_match_add(dev, matchptr, compare_of, node); } - for (i = 0; i < MAX_DSI_ACTIVE_DISPLAY; i++) { - node = dsi_display_get_boot_display(i); - - if (node != NULL) { - name = of_get_property(node, "label", NULL); - component_match_add(dev, matchptr, compare_of, - node); - pr_debug("Added component = %s\n", name); - } - } - return 0; } -- GitLab From 28c91970f2e7812cf64e0489c3850b1506e0aa3e Mon Sep 17 00:00:00 2001 From: Mingbo Zhang Date: Fri, 13 Apr 2018 14:56:30 +0800 Subject: [PATCH 0368/1635] ARM: dts: msm: Add bluetooth device node for sm8150 Add Bluetooth device node for WCN3990 chipset for sm8150 Change-Id: I84c17069373bc4684bc7c31fb4da63d8c15a0862 CRs-Fixed: 2223129 Signed-off-by: Mingbo Zhang --- arch/arm64/boot/dts/qcom/sm8150-qrd.dtsi | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sm8150-qrd.dtsi b/arch/arm64/boot/dts/qcom/sm8150-qrd.dtsi index 0015edda2ac3..c742754d47d4 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-qrd.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-qrd.dtsi @@ -19,6 +19,23 @@ #include "sm8150-sde-display.dtsi" #include "sm8150-camera-sensor-qrd.dtsi" +&vendor { + bluetooth: bt_wcn3990 { + compatible = "qca,wcn3990"; + qca,bt-vdd-core-supply = <&pm855_l7>; + qca,bt-vdd-pa-supply = <&pm855l_l2>; + qca,bt-vdd-ldo-supply = <&pm855l_l11>; + + qca,bt-vdd-core-voltage-level = <1800000 1800000>; + qca,bt-vdd-pa-voltage-level = <1304000 1304000>; + qca,bt-vdd-ldo-voltage-level = <3312000 3312000>; + + qca,bt-vdd-core-current-level = <0>; /* LPM/PFM */ + qca,bt-vdd-pa-current-level = <0>; /* LPM/PFM */ + qca,bt-vdd-ldo-current-level = <0>; /* LPM/PFM */ + }; +}; + &soc { gpio_keys { compatible = "gpio-keys"; -- GitLab From f5872e1b6656c1bd05a288e40424ffc447de8eff Mon Sep 17 00:00:00 2001 From: chenx Date: Thu, 12 Apr 2018 16:50:12 +0800 Subject: [PATCH 0369/1635] input: touchscreen: Update ST touch driver Update ST touch driver for chip type FTM4 Signed-off-by: chenx Git-commit: 2e1337310abee3a24bf37fc1211924b7f756af98 Git-repo: https://source.codeaurora.org/quic/la/kernel/msm-4.14/commit/?h=caf/tsoft/STMicroelectronics_ctp_V4.1.0_FTM4&id=2e1337310abee3a24bf37fc1211924b7f756af98 CRs-Fixed: 2210870 Change-Id:Ib0910350cc7a3c0b02222b46cfe28584a8828d25 Signed-off-by: Fei Mao --- drivers/input/touchscreen/st/Kconfig | 20 +- drivers/input/touchscreen/st/Makefile | 2 +- drivers/input/touchscreen/st/fts.c | 4075 ++++++++-- drivers/input/touchscreen/st/fts.h | 324 +- .../input/touchscreen/st/fts_driver_test.c | 1319 ++-- drivers/input/touchscreen/st/fts_fw.h | 6530 ++++++++++++++++- drivers/input/touchscreen/st/fts_gui.c | 354 +- drivers/input/touchscreen/st/fts_lib/Makefile | 3 +- .../touchscreen/st/fts_lib/ftsCompensation.c | 489 +- .../touchscreen/st/fts_lib/ftsCompensation.h | 266 +- .../touchscreen/st/fts_lib/ftsCrossCompile.c | 43 +- .../touchscreen/st/fts_lib/ftsCrossCompile.h | 46 +- .../input/touchscreen/st/fts_lib/ftsError.c | 227 +- .../input/touchscreen/st/fts_lib/ftsError.h | 245 +- .../input/touchscreen/st/fts_lib/ftsFlash.c | 1059 +-- .../input/touchscreen/st/fts_lib/ftsFlash.h | 94 +- .../input/touchscreen/st/fts_lib/ftsFrame.c | 531 +- .../input/touchscreen/st/fts_lib/ftsFrame.h | 88 +- .../input/touchscreen/st/fts_lib/ftsGesture.c | 495 +- .../input/touchscreen/st/fts_lib/ftsGesture.h | 176 +- .../touchscreen/st/fts_lib/ftsHardware.h | 281 +- drivers/input/touchscreen/st/fts_lib/ftsIO.c | 215 +- drivers/input/touchscreen/st/fts_lib/ftsIO.h | 68 +- .../touchscreen/st/fts_lib/ftsSoftware.h | 309 +- .../input/touchscreen/st/fts_lib/ftsTest.c | 3491 ++++++--- .../input/touchscreen/st/fts_lib/ftsTest.h | 228 +- .../input/touchscreen/st/fts_lib/ftsTime.c | 73 +- .../input/touchscreen/st/fts_lib/ftsTime.h | 62 +- .../input/touchscreen/st/fts_lib/ftsTool.c | 1043 ++- .../input/touchscreen/st/fts_lib/ftsTool.h | 86 +- drivers/input/touchscreen/st/fts_limits.h | 1421 +++- 31 files changed, 18935 insertions(+), 4728 deletions(-) diff --git a/drivers/input/touchscreen/st/Kconfig b/drivers/input/touchscreen/st/Kconfig index 817faea01742..10c908538fcf 100644 --- a/drivers/input/touchscreen/st/Kconfig +++ b/drivers/input/touchscreen/st/Kconfig @@ -2,8 +2,24 @@ # STMicroelectronics touchscreen driver configuration # +#config TOUCHSCREEN_ST +# bool "STMicroelectronics Touchscreen Driver" +# default n +# depends on I2C +# help +# Say Y here if you have a STMicroelectronics Touchscreen. +# If unsure, say N. +# + +#if TOUCHSCREEN_ST + config TOUCHSCREEN_ST_I2C - tristate "STMicroelectronics i2c touchscreen" + #tristate "STMicroelectronics i2c touchscreen" + string "STMicroelectronics ts directory name" + default "st" depends on TOUCHSCREEN_ST help - This enables support for ST touch panel over I2C based touchscreens. + This enables support for ST touch panel over I2C based touchscreens. + +#endif + diff --git a/drivers/input/touchscreen/st/Makefile b/drivers/input/touchscreen/st/Makefile index 0aa7b4a364da..f67f9fe9df2f 100644 --- a/drivers/input/touchscreen/st/Makefile +++ b/drivers/input/touchscreen/st/Makefile @@ -2,4 +2,4 @@ ## Makefile for the STMicroelectronics touchscreen driver. # -obj-$(CONFIG_TOUCHSCREEN_ST_I2C) += fts.o fts_gui.o fts_driver_test.o fts_lib/ +obj-$(CONFIG_TOUCHSCREEN_ST) += fts.o fts_gui.o fts_driver_test.o fts_lib/ diff --git a/drivers/input/touchscreen/st/fts.c b/drivers/input/touchscreen/st/fts.c index 08bfb83a9447..eaa804f5a722 100644 --- a/drivers/input/touchscreen/st/fts.c +++ b/drivers/input/touchscreen/st/fts.c @@ -3,7 +3,7 @@ * * FTS Capacitive touch screen controller (FingerTipS) * - * Copyright (C) 2016, STMicroelectronics Limited. + * Copyright (C) 2016-2018, STMicroelectronics Limited. * Authors: AMG(Analog Mems Group) * * marco.cali@st.com @@ -28,18 +28,25 @@ #include #include #include +/*#include */ +#include #include #include #include +#if defined(CONFIG_FB_MSM) #include #include +#else +#include +#endif #ifdef KERNEL_ABOVE_2_6_38 #include #endif + #include "fts.h" #include "fts_lib/ftsCompensation.h" #include "fts_lib/ftsIO.h" @@ -51,24 +58,26 @@ #include "fts_lib/ftsTime.h" #include "fts_lib/ftsTool.h" + + #define LINK_KOBJ_NAME "tp" /* * Uncomment to use polling mode instead of interrupt mode. * */ -/* #define FTS_USE_POLLING_MODE */ +// #define FTS_USE_POLLING_MODE + /* * Event installer helpers */ -#define event_id(_e) EVENTID_##_e +#define event_id(_e) EVENTID_##_e #define handler_name(_h) fts_##_h##_event_handler #define install_handler(_i, _evt, _hnd) \ -do { \ - _i->event_dispatch_table[event_id(_evt)] = handler_name(_hnd); \ -} while (0) + (_i->event_dispatch_table[event_id(_evt)] = handler_name(_hnd)) + /* * Asyncronouns command helper @@ -89,28 +98,47 @@ do { \ static struct class *fts_cmd_class; #endif -extern chipInfo ftsInfo; -unsigned char tune_version_same; +//struct chipInfo ftsInfo; + +/** + * #ifdef PHONE_GESTURE + * extern struct mutex gestureMask_mutex; + * #endif + */ -char tag[8] = "[ FTS ]\0"; +static char tag[8] = "[ FTS ]\0"; -static u32 *typeOfComand; +static char fts_ts_phys[64]; +static u32 typeOfComand[CMD_STR_LEN] = {0}; static int numberParameters; +#ifdef USE_ONE_FILE_NODE static int feature_feasibility = ERROR_OP_NOT_ALLOW; +#endif #ifdef PHONE_GESTURE -static u8 mask[GESTURE_MASK_SIZE+2]; +static u8 mask[GESTURE_MASK_SIZE + 2]; +//extern u16 gesture_coordinates_x[GESTURE_COORDS_REPORT_MAX]; +//extern u16 gesture_coordinates_y[GESTURE_COORDS_REPORT_MAX]; +//extern int gesture_coords_reported; +//extern struct mutex gestureMask_mutex; +#ifdef USE_CUSTOM_GESTURES +static int custom_gesture_res; +#endif +#endif +#ifdef USE_NOISE_PARAM +static u8 noise_params[NOISE_PARAMETERS_SIZE] = {0}; #endif static void fts_interrupt_enable(struct fts_ts_info *info); -static int fts_init_hw(struct fts_ts_info *info); +static int fts_init_afterProbe(struct fts_ts_info *info); static int fts_mode_handler(struct fts_ts_info *info, int force); static int fts_command(struct fts_ts_info *info, unsigned char cmd); + static int fts_chip_initialization(struct fts_ts_info *info); void touch_callback(unsigned int status) { - /* Empty */ + /* Empty */ } unsigned int le_to_uint(const unsigned char *ptr) @@ -123,161 +151,1936 @@ unsigned int be_to_uint(const unsigned char *ptr) return (unsigned int) ptr[1] + (unsigned int) ptr[0] * 0x100; } -/* force update firmware*/ -static ssize_t fts_fw_control_store(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count){ +void release_all_touches(struct fts_ts_info *info) +{ + unsigned int type = MT_TOOL_FINGER; + int i; + + for (i = 0; i < TOUCH_ID_MAX; i++) { +#ifdef STYLUS_MODE + if (test_bit(i, &info->stylus_id)) + type = MT_TOOL_PEN; +#endif + input_mt_slot(info->input_dev, i); + input_mt_report_slot_state(info->input_dev, type, 0); + input_report_abs(info->input_dev, ABS_MT_TRACKING_ID, -1); + } + input_sync(info->input_dev); + info->touch_id = 0; +#ifdef STYLUS_MODE + info->stylus_id = 0; +#endif +} + +/************************* FW UPGGRADE *********************************/ +/* update firmware*/ +/** + * echo 01/00 > fwupdate perform a fw update taking the FW to burn always + * from a bin file stored in /system/etc/firmware, 01= force the FW update + * whicheve fw_version and config_id; 00=perform a fw update only if the fw + * in the file has a greater fw_version or config_id + */ + +/** + * cat fwupdate to show the result of the burning procedure + * (example output in the terminal = "AA00000001BB" if the switch is enabled) + */ + +/** + * echo 01/00 > fwupdate; cat fwupdate to perform both operation stated before + * in just one call + */ +static ssize_t fts_fwupdate_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ int ret, mode; + /*const struct firmware *fw = NULL;*/ + /*char *firmware_name = "st_fts.bin";*/ + struct Firmware fwD; struct i2c_client *client = to_i2c_client(dev); struct fts_ts_info *info = i2c_get_clientdata(client); + int orig_size; + u8 *orig_data; /* reading out firmware upgrade mode */ - sscanf(buf, "%d", &mode); -#ifdef FTM3_CHIP - ret = flashProcedure(PATH_FILE_FW, mode, !mode); -#else - ret = flashProcedure(PATH_FILE_FW, mode, 1); -#endif + ret = kstrtoint(buf, 10, &mode); + if (ret != 0) { + pr_err("%s: ret = %d\n", __func__, ret); + return -EINVAL; + } + + fwD.data = NULL; + ret = getFWdata(PATH_FILE_FW, &orig_data, &orig_size, 0); + if (ret < OK) { + logError(1, "%s %s: impossible retrieve FW... ERROR %08X\n", + tag, __func__, ERROR_MEMH_READ); + ret = (ret | ERROR_MEMH_READ); + goto END; + } + + ret = parseBinFile(orig_data, orig_size, &fwD, !mode); + if (ret < OK) { + logError(1, "%s %s: impossible parse ERROR %08X\n", + tag, __func__, ERROR_MEMH_READ); + ret = (ret | ERROR_MEMH_READ); + goto END; + } + + logError(0, "%s Starting flashing procedure...\n", tag); + ret = flash_burn(fwD, mode, !mode); + + if (ret < OK && ret != (ERROR_FW_NO_UPDATE | ERROR_FLASH_BURN_FAILED)) + logError(1, "%s flashProcedure: ERROR %02X\n", + tag, ERROR_FLASH_PROCEDURE); + logError(0, "%s flashing procedure Finished!\n", tag); + +END: + kfree(fwD.data); info->fwupdate_stat = ret; if (ret < OK) - logError(1, "%s %s :Unable to upgrade firmware\n", tag, __func__); + logError(1, "%s %s Unable to upgrade firmware! ERROR %08X\n", + tag, __func__, ret); + return count; } -static ssize_t fts_sysfs_config_id_show(struct device *dev, struct device_attribute *attr, - char *buf) { +static ssize_t fts_fwupdate_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + struct fts_ts_info *info = i2c_get_clientdata(client); + + //fwupdate_stat: ERROR code Returned by flashProcedure. + return snprintf(buf, PAGE_SIZE, "AA%08XBB\n", info->fwupdate_stat); +} + + +/****UTILITIES (current fw_ver/conf_id, active mode, file fw_ver/conf_id)****/ +/** + * cat appid show on the terminal fw_version.config_id of + * the FW running in the IC + */ +static ssize_t fts_sysfs_config_id_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ int error; - error = snprintf(buf, TSP_BUF_SIZE, "%x.%x\n", ftsInfo.u16_fwVer, ftsInfo.u16_cfgId); + error = snprintf(buf, PAGE_SIZE, "%x.%x\n", ftsInfo.u16_fwVer, + ftsInfo.u16_cfgId); return error; } -static ssize_t fts_sysfs_fwupdate_show(struct device *dev, struct device_attribute *attr, - char *buf) { +/** + * cat mode_active to show the bitmask of which indicate the modes/features + * which are running on the IC in a specific istant oftime (example output in + * the terminal = "AA10000000BB" only senseOn performed) + */ +static ssize_t fts_mode_active_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ struct i2c_client *client = to_i2c_client(dev); struct fts_ts_info *info = i2c_get_clientdata(client); - /* fwupdate_stat: ERROR code Returned by flashProcedure. */ - return snprintf(buf, TSP_BUF_SIZE, "%08X\n", info->fwupdate_stat); + logError(1, "%s Current mode active = %08X\n", tag, info->mode); + //return sprintf(buf, "AA%08XBB\n", info->mode); + return snprintf(buf, PAGE_SIZE, "AA%08XBB\n", info->mode); } -static ssize_t fts_fw_test_show(struct device *dev, struct device_attribute *attr, - char *buf) { - Firmware fw; +/** + * cat fw_file_test show on the terminal fw_version and config_id of the FW + * stored in the fw file/header file + */ +static ssize_t fts_fw_test_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct Firmware fw; int ret; fw.data = NULL; ret = readFwFile(PATH_FILE_FW, &fw, 0); - if (ret < OK) { - logError(1, "%s: Error during reading FW file! ERROR %08X\n", tag, ret); - } else - logError(1, "%s: fw_version = %04X, config_version = %04X, size = %d bytes\n", - tag, fw.fw_ver, fw.config_id, fw.data_size); + if (ret < OK) + logError(1, "%s Error during reading FW file! ERROR %08X\n", + tag, ret); + else { + logError(1, "%s fw_version = %04X, config_version = %04X, ", + tag, fw.fw_ver, fw.config_id); + logError(1, "size = %dbytes\n", fw.data_size); + } kfree(fw.data); return 0; } -/* TODO: edit this function according to the features policy to allow during the screen on/off */ -int check_feature_feasibility(struct fts_ts_info *info, unsigned int feature) + +/** + * cat lockdown_info to show the lockdown info on the terminal + * (example output in the terminal = "AA00000000X1X2..X10BB" ) + * where first 4 bytes correspond t + */ +static ssize_t fts_lockdown_info_show(struct device *dev, + struct device_attribute *attr, char *buf) { - int res = ERROR_OP_NOT_ALLOW; + u8 data[LOCKDOWN_CODE_SIZE] = {0}; + int ret, size = 100; + char buff[CMD_STR_LEN] = {0}; + char all_strbuff[100] = {0}; - if (info->resume_bit == 0) { - switch (feature) { -#ifdef PHONE_GESTURE - case FEAT_GESTURE: - res = OK; - break; -#endif - default: - logError(1, "%s %s: Feature not allowed in this operating mode! ERROR %08X\n", tag, __func__, res); - break; + ret = fts_disableInterrupt(); + if (ret < OK) + goto END; + + ret = lockDownInfo(data); + if (ret < OK) + goto END; + +END: + ret |= fts_enableInterrupt(); + + snprintf(buff, sizeof(buff), "%02X", 0xAA); + strlcat(all_strbuff, buff, size); + snprintf(buff, sizeof(buff), "%08X", ret); + strlcat(all_strbuff, buff, size); + if (ret >= OK) { + for (ret = 0; ret < LOCKDOWN_CODE_SIZE; ret++) { + snprintf(buff, sizeof(buff), "%02X", data[ret]); + strlcat(all_strbuff, buff, size); } - } else{ - switch (feature) { -#ifdef PHONE_GESTURE - case FEAT_GESTURE: + } else { + logError(1, "%s Error while reading lockdown info = %08X\n", + tag, ret); + } + snprintf(buff, sizeof(buff), "%02X", 0xBB); + strlcat(all_strbuff, buff, size); + return snprintf(buf, TSP_BUF_SIZE, "%s\n", all_strbuff); +} + +/** + * cat strength_frame to obtain strength data + * the string returned in the shell is made up as follow: + * AA = start byte + * X1X2X3X4 = 4 bytes in HEX format which represent an + * error code (00000000 no error) + * + * if error code is all 0s + * FF = 1 byte in HEX format number of rows + * SS = 1 byte in HEX format number of columns + * N1, ... = the decimal value of each node separated by a coma + * + * BB = end byte + */ +static ssize_t fts_strength_frame_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + char *p = (char *)buf; + /*unsigned int temp;*/ + /*int res;*/ + /*struct i2c_client *client = to_i2c_client(dev); */ + /*struct fts_ts_info *info = i2c_get_clientdata(client); */ + + if (sscanf(p, "%d ", &typeOfComand[0]) != 1) + return -EINVAL; + + logError(1, "%s %s: Type of Strength Frame selected: %d\n", tag, + __func__, typeOfComand[0]); + return count; +} + + +static ssize_t fts_strength_frame_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct MutualSenseFrame frame; + int res = ERROR_OP_NOT_ALLOW, j, size = 6*2; + int count = 0; + u16 type = 0; + char *all_strbuff = NULL; + char buff[CMD_STR_LEN] = {0}; + struct i2c_client *client = to_i2c_client(dev); + struct fts_ts_info *info = i2c_get_clientdata(client); + + frame.node_data = NULL; + + res = fts_disableInterrupt(); + if (res < OK) + goto END; + + res = senseOn(); +#ifdef PHONE_KEY + res = keyOn(); #endif - case FEAT_GLOVE: - /* glove mode can only activate during sense on */ - res = OK; - break; + if (res < OK) { + logError(1, "%s %s: could not start scanning! ERROR %08X\n", + tag, __func__, res); + goto END; + } + msleep(WAIT_FOR_FRESH_FRAMES); - default: - logError(1, "%s %s: Feature not allowed in this operating mode! ERROR %08X\n", tag, __func__, res); + res = senseOff(); +#ifdef PHONE_KEY + res = keyOff(); +#endif + if (res < OK) { + logError(1, "%s %s: could not finish scanning! ERROR %08X\n", + tag, __func__, res); + goto END; + } + /* mdelay(WAIT_AFTER_SENSEOFF); */ + msleep(WAIT_AFTER_SENSEOFF); + flushFIFO(); + + switch (typeOfComand[0]) { + case 1: + type = ADDR_NORM_TOUCH; + break; +#ifdef PHONE_KEY + case 2: + type = ADDR_NORM_MS_KEY; break; +#endif + default: + logError(1, "%s %s: Strength type %d not valid! ERROR %08X\n", + tag, __func__, typeOfComand[0], ERROR_OP_NOT_ALLOW); + res = ERROR_OP_NOT_ALLOW; + goto END; + } + + res = getMSFrame(type, &frame, 0); + if (res < OK) { + logError(1, "%s %s: could not get the frame! ERROR %08X\n", + tag, __func__, res); + goto END; + } else { + size += (res * 6); + logError(0, "%s The frame size is %d words\n", tag, res); + res = OK; + print_frame_short("MS Strength frame =", + array1dTo2d_short(frame.node_data, + frame.node_data_size, + frame.header.sense_node), + frame.header.force_node, + frame.header.sense_node); + } +END: + flushFIFO(); + release_all_touches(info); + fts_mode_handler(info, 1); + + all_strbuff = kmalloc_array(size, sizeof(char), GFP_KERNEL); + + if (all_strbuff != NULL) { + memset(all_strbuff, 0, size); + snprintf(buff, sizeof(buff), "%02X", 0xAA); + strlcat(all_strbuff, buff, size); + + snprintf(buff, sizeof(buff), "%08X", res); + strlcat(all_strbuff, buff, size); + + if (res >= OK) { + snprintf(buff, sizeof(buff), "%02X", + (u8) frame.header.force_node); + strlcat(all_strbuff, buff, size); + + snprintf(buff, sizeof(buff), "%02X", + (u8) frame.header.sense_node); + strlcat(all_strbuff, buff, size); + + for (j = 0; j < frame.node_data_size; j++) { + snprintf(buff, sizeof(buff), "%d,", + frame.node_data[j]); + strlcat(all_strbuff, buff, size); + } + + kfree(frame.node_data); } + + snprintf(buff, sizeof(buff), "%02X", 0xBB); + strlcat(all_strbuff, buff, size); + + count = snprintf(buf, TSP_BUF_SIZE, "%s\n", all_strbuff); + kfree(all_strbuff); + } else { + logError(1, "%s %s: Unable toallocate all_strbuff!ERROR %08X\n", + tag, ERROR_ALLOC); } - return res; + fts_enableInterrupt(); + return count; +} + +/********** FEATURES *********************/ + +/** + * TODO: edit this function according to the features policy to + * allow during the screen on/off, following is shown an example + * but check always with ST for more details + */ +int check_feature_feasibility(struct fts_ts_info *info, unsigned int feature) +{ + int res = OK; + + /** + * Example based on the status of the screen and + * on the feature that is trying to enable + */ + + /*Example based only on the feature that is going to be activated*/ + switch (feature) { + case FEAT_GESTURE: + if (info->cover_enabled == 1) { + res = ERROR_OP_NOT_ALLOW; + + logError(1, "%s %s:Feature not allowed when in Cover ", + tag, __func__); + logError(1, "mode %08X\n", res); + /** + * for example here can be place a code for + * disabling the cover mode when gesture is + * activated + */ + } + break; + + case FEAT_COVER: + if (info->gesture_enabled == 1) { + res = ERROR_OP_NOT_ALLOW; + /*logError(1,"Feature not allowed*/ + /*when Gestures enabled!");*/ + logError(1, "s %s: Feature not allowed when Gestures ", + tag, __func__); + logError(1, "enabled%08X\n", res); + /** + * for example here can be place a code for + * disabling the gesture mode when cover is + * activated (that means that cover mode has + * an higher priority on gesture mode) + */ + } + break; + default: + logError(1, "%s %s: Feature Allowed!\n", tag, __func__); + } + return res; } -static ssize_t fts_feature_enable_store(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) { +#ifdef USE_ONE_FILE_NODE +/** + * echo XXXX 00/01 > feature_enable + * set the feature to disable/enable. + * XXXX = 4 bytes which identify the feature + * + * cat feature_enable + * set the enabled mode/features in the IC + * and return an error code + * + * echo XXXX 00/01 > feature_enable; + * cat feature_enable to perform both action stated + * before in just one call + */ +static ssize_t fts_feature_enable_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ struct i2c_client *client = to_i2c_client(dev); struct fts_ts_info *info = i2c_get_clientdata(client); char *p = (char *)buf; unsigned int temp; int res = OK; - if ((count + 1) / 3 != 2) { - logError(1, "%s fts_feature_enable: Number of parameter wrong! %d > %d\n", - tag, (count + 1) / 3, 2); - } else{ - sscanf(p, "%02X ", &temp); - p += 3; - res = check_feature_feasibility(info, temp); - if (res >= OK) { - switch (temp) { + if ((count - 8 + 1) / 3 != 1) { + logError(1, "%s fts_feature_enable: ", tag); + logError(1, "Number of parameter wrong! %d > %d\n", + (count - 8 + 1) / 3, 1); + return -EINVAL; + } + + if (sscanf(p, "%08X ", &temp) != 1) + return -EINVAL; + p += 9; + res = check_feature_feasibility(info, temp); + if (res < OK) + return -EINVAL; + + switch (temp) { #ifdef PHONE_GESTURE - case FEAT_GESTURE: - sscanf(p, "%02X ", &info->gesture_enabled); - logError(1, "%s fts_feature_enable: Gesture Enabled = %d\n", tag, - info->gesture_enabled); - break; + case FEAT_GESTURE: + if (sscanf(p, "%02X ", &info->gesture_enabled) != 1) + return -EINVAL; + + logError(1, "%s fts_feature_enable: Gesture Enabled = %d\n", + tag, info->gesture_enabled); + + break; #endif - case FEAT_GLOVE: - sscanf(p, "%02X ", &info->glove_enabled); - logError(1, "%s fts_feature_enable: Glove Enabled = %d\n", + +#ifdef GLOVE_MODE + case FEAT_GLOVE: + if (sscanf(p, "%02X ", &info->glove_enabled) != 1) + return -EINVAL; + + logError(1, "%s fts_feature_enable: Glove Enabled = %d\n", tag, info->glove_enabled); - break; + break; +#endif - default: - logError(1, "%s fts_feature_enable: Feature %02X not valid! ERROR %08X\n", tag, temp, ERROR_OP_NOT_ALLOW); +#ifdef STYLUS_MODE + case FEAT_STYLUS: + if (sscanf(p, "%02X ", &info->stylus_enabled) != 1) + return -EINVAL; - } - feature_feasibility = res; - } + logError(1, "%s fts_feature_enable: Stylus Enabled = %d\n", + tag, info->stylus_enabled); + + break; +#endif + +#ifdef COVER_MODE + case FEAT_COVER: + if (sscanf(p, "%02X ", &info->cover_enabled) != 1) + return -EINVAL; + + logError(1, "%s fts_feature_enable: Cover Enabled = %d\n", + tag, info->cover_enabled); + + break; +#endif + +#ifdef CHARGER_MODE + case FEAT_CHARGER: + if (sscanf(p, "%02X ", &info->charger_enabled) != 1) + return -EINVAL; + + logError(1, "%s fts_feature_enable: Charger Enabled= %d\n", + tag, info->charger_enabled); + + break; +#endif + +#ifdef VR_MODE + case FEAT_VR: + if (sscanf(p, "%02X ", &info->vr_enabled) != 1) + return -EINVAL; + + logError(1, "%s fts_feature_enable: VR Enabled = %d\n", + tag, info->vr_enabled); + + break; +#endif + +#ifdef EDGE_REJ + case FEAT_EDGE_REJECTION: + if (sscanf(p, "%02X ", &info->edge_rej_enabled) != 1) + return -EINVAL; + logError(1, "%s %s: Edge Rejection Enabled= %d\n", + tag, __func__, info->edge_rej_enabled); + + break; +#endif + +#ifdef CORNER_REJ + case FEAT_CORNER_REJECTION: + if (sscanf(p, "%02X ", &info->corner_rej_enabled) != 1) + return -EINVAL; + + logError(1, "%s %s: Corner Rejection Enabled= %d\n", + tag, __func__, info->corner_rej_enabled); + + break; +#endif + +#ifdef EDGE_PALM_REJ + case FEAT_EDGE_PALM_REJECTION: + if (sscanf(p, "%02X", &info->edge_palm_rej_enabled) != 1) + return -EINVAL; + + logError(1, "%s %s:Edge Palm RejectionEnabled= %d\n", + tag, __func__, info->edge_palm_rej_enabled); + + break; +#endif + default: + logError(1, "%s %s: Feature %08X not valid! ERROR %08X\n", + tag, __func__, temp, ERROR_OP_NOT_ALLOW); + res = ERROR_OP_NOT_ALLOW; + } + feature_feasibility = res; + if (feature_feasibility >= OK) + feature_feasibility = fts_mode_handler(info, 1); + else { + logError(1, "%s %s: Call echo XXXX 00/01 > feature_enable ", + tag, __func__); + logError(1, "with a correct feature! ERROR %08X\n", res); } return count; } static ssize_t fts_feature_enable_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + char buff[CMD_STR_LEN] = {0}; + int size = 6 * 2; + u8 *all_strbuff = NULL; + int count = 0; + + if (feature_feasibility < OK) { + logError(1, + "%s %s:Call before echo 00/01 > feature_enable %08X\n", + tag, __func__, feature_feasibility); + } + + + all_strbuff = kmalloc(size, GFP_KERNEL); + if (all_strbuff != NULL) { + memset(all_strbuff, 0, size); + + snprintf(buff, sizeof(buff), "%02X", 0xAA); + strlcat(all_strbuff, buff, size); + + snprintf(buff, sizeof(buff), "%08X", feature_feasibility); + strlcat(all_strbuff, buff, size); + + snprintf(buff, sizeof(buff), "%02X", 0xBB); + strlcat(all_strbuff, buff, size); + + count = snprintf(buf, TSP_BUF_SIZE, "%s\n", all_strbuff); + kfree(all_strbuff); + } else { + logError(1, + "%s %s: Unable to allocate all_strbuff! ERROR %08X\n", + tag, __func__, ERROR_ALLOC); + } + + feature_feasibility = ERROR_OP_NOT_ALLOW; + return count; +} + +#else + +#ifdef EDGE_REJ +/** + * echo 01/00 > edge_rej to enable/disable edge rejection + * cat edge_rej to show the status of the edge_rej_enabled + * switch (example output in the terminal = "AA00000001BB" + * if the switch is enabled) + * + * echo 01/00 > edge_rej; cat edge_rej to enable/disable + * edge rejection and see the switch status in just one call + */ +static ssize_t fts_edge_rej_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + char buff[CMD_STR_LEN] = {0}; + int size = 6 * 2; + u8 *all_strbuff = NULL; + int count = 0; + struct i2c_client *client = to_i2c_client(dev); + struct fts_ts_info *info = i2c_get_clientdata(client); + + logError(0, "%s %s: edge_rej_enabled = %d\n", + tag, __func__, info->edge_rej_enabled); + + all_strbuff = kmalloc(size, GFP_KERNEL); + if (all_strbuff != NULL) { + memset(all_strbuff, 0, size); + + snprintf(buff, sizeof(buff), "%02X", 0xAA); + strlcat(all_strbuff, buff, size); + + snprintf(buff, sizeof(buff), "%08X", info->edge_rej_enabled); + strlcat(all_strbuff, buff, size); + + snprintf(buff, sizeof(buff), "%02X", 0xBB); + strlcat(all_strbuff, buff, size); + + count = snprintf(buf, TSP_BUF_SIZE, "%s\n", all_strbuff); + kfree(all_strbuff); + } else + logError(1, + "%s %s: Unable to allocate all_strbuff! ERROR %08X\n", + tag, __func__, ERROR_ALLOC); + + return count; +} + + +static ssize_t fts_edge_rej_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + char *p = (char *)buf; + unsigned int temp; + int res; + struct i2c_client *client = to_i2c_client(dev); + struct fts_ts_info *info = i2c_get_clientdata(client); + + + /** + * in case of a different elaboration of the input, + * just modify this initial part of the code + */ + if ((count + 1) / 3 != 1) { + logError(1, + "%s %s:Number bytes of parameter wrong!%d != %d byte\n", + tag, __func__, (count + 1) / 3, 1); + return -EINVAL; + } + + if (sscanf(p, "%02X ", &temp) != 1) + return -EINVAL; + + p += 3; + + /** + * this is a standard code that should be always + * used when a feature is enabled! + * + * first step : check if the wanted feature can be enabled + * + * second step: call fts_mode_handler to actually enable it + * NOTE: Disabling a feature is always allowed by default + */ + res = check_feature_feasibility(info, FEAT_EDGE_REJECTION); + if (res < OK && temp != FEAT_DISABLE) + return -EINVAL; + + info->edge_rej_enabled = temp; + res = fts_mode_handler(info, 1); + if (res < OK) { + logError(1, + "%s %s: Error during fts_mode_handler! ERROR %08X\n", + tag, __func__, res); + } + } + + return count; +} +#endif + +#ifdef CORNER_REJ +/** + * echo 01/00 > corner_rej to enable/disable corner rejection + * cat corner_rej to show the status of the + * corner_rej_enabled switch (example output in the terminal + * = "AA00000001BB" if the switch is enabled) + * + * echo 01/00 > corner_rej; cat corner_rej to enable/disable + * corner rejection and see the switch status in just one call + */ +static ssize_t fts_corner_rej_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + char buff[CMD_STR_LEN] = {0}; + int size = 6 * 2; + u8 *all_strbuff = NULL; + int count = 0; + struct i2c_client *client = to_i2c_client(dev); + struct fts_ts_info *info = i2c_get_clientdata(client); + + logError(0, "%s %s: corner_rej_enabled = %d\n", + tag, __func__, info->corner_rej_enabled); + + all_strbuff = kmalloc(size, GFP_KERNEL); + if (all_strbuff != NULL) { + memset(all_strbuff, 0, size); + + snprintf(buff, sizeof(buff), "%02X", 0xAA); + strlcat(all_strbuff, buff, size); + + snprintf(buff, sizeof(buff), "%08X", info->corner_rej_enabled); + strlcat(all_strbuff, buff, size); + + snprintf(buff, sizeof(buff), "%02X", 0xBB); + strlcat(all_strbuff, buff, size); + + count = snprintf(buf, TSP_BUF_SIZE, "%s\n", all_strbuff); + kfree(all_strbuff); + } else { + logError(1, "%s%s:Unable to allocate all_strbuff! ERROR %08X\n", + tag, __func__, ERROR_ALLOC); + } + + return count; +} + + +static ssize_t fts_corner_rej_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + char *p = (char *)buf; + unsigned int temp; + int res; + struct i2c_client *client = to_i2c_client(dev); + struct fts_ts_info *info = i2c_get_clientdata(client); + + /** + * in case of a different elaboration of the input, + * just modify this initial part of the code according + * to customer needs + */ + if ((count + 1) / 3 != 1) { + logError(1, + "%s %s:Number bytes of parameter wrong!%d != %d byte\n", + tag, __func__, (count + 1) / 3, 1); + return -EINVAL; + } + + /*sscanf(p, "%02X ", &temp);*/ + if (sscanf(p, "%02X ", &temp) != 1) + return -EINVAL; + + p += 3; + + /** + * this is a standard code that should be always + * used when a feature is enabled! + * + * first step : check if the wanted feature + * can be enabled + * + * second step: call fts_mode_handler to + * actually enable it + * + * NOTE: Disabling a feature is always + * allowed by default + */ + res = check_feature_feasibility(info, FEAT_CORNER_REJECTION); + if (res >= OK || temp == FEAT_DISABLE) { + info->corner_rej_enabled = temp; + res = fts_mode_handler(info, 1); + if (res < OK) { + logError(1, + "%s %s: During fts_mode_handler!ERROR %08X\n", + tag, __func__, res); + } + } + + return count; +} +#endif + +#ifdef EDGE_PALM_REJ +/** + * echo 01/00 > edge_palm_rej + * to enable/disable edge palm rejection + * + * cat edge_palm_rej to show the status of the + * edge_palm_rej_enabled switch (example output + * in the terminal = "AA00000001BB" if the switch is enabled) + * + * echo 01/00 > edge_palm_rej; cat edge_palm_rej + * to enable/disable edge palm rejection and see + * the switch status in just one call + */ +static ssize_t fts_edge_palm_rej_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + char buff[CMD_STR_LEN] = {0}; + int size = 6 * 2; + u8 *all_strbuff = NULL; + int count = 0; + struct i2c_client *client = to_i2c_client(dev); + struct fts_ts_info *info = i2c_get_clientdata(client); + + logError(0, "%s %s: edge_palm_rej_enabled = %d\n", + tag, __func__, info->edge_palm_rej_enabled); + + all_strbuff = kmalloc(size, GFP_KERNEL); + if (all_strbuff != NULL) { + memset(all_strbuff, 0, size); + + snprintf(buff, sizeof(buff), "%02X", 0xAA); + strlcat(all_strbuff, buff, size); + + snprintf(buff, sizeof(buff), "%08X", + info->edge_palm_rej_enabled); + strlcat(all_strbuff, buff, size); + + snprintf(buff, sizeof(buff), "%02X", 0xBB); + strlcat(all_strbuff, buff, size); + + count = snprintf(buf, TSP_BUF_SIZE, "%s\n", + all_strbuff); + kfree(all_strbuff); + } else { + logError(1, "%s%s:Unable to allocate all_strbuff! %08X\n", + tag, __func__, ERROR_ALLOC); + } + + return count; +} + + +static ssize_t fts_edge_palm_rej_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + char *p = (char *)buf; + unsigned int temp; + int res; + struct i2c_client *client = to_i2c_client(dev); + struct fts_ts_info *info = i2c_get_clientdata(client); + + /** + * in case of a different elaboration of the input, + * just modify this initial part of the code according + * to customer needs + */ + if ((count + 1) / 3 != 1) { + logError(1, + "%s%s:Number bytes of parameter wrong! %d != %d byte\n", + tag, __func__, (count + 1) / 3, 1); + return -EINVAL; + } + /*sscanf(p, "%02X ", &temp);*/ + if (sscanf(p, "%02X ", &temp) != 1) + return -EINVAL; + + p += 3; + + /** + * this is a standard code that should be + * always used when a feature is enabled! + * + * first step : check if the wanted feature can be enabled + * + * second step: call fts_mode_handler to actually enable it + * + * NOTE: Disabling a feature is always allowed by default + */ + res = check_feature_feasibility(info, FEAT_EDGE_PALM_REJECTION); + if (res >= OK || temp == FEAT_DISABLE) { + info->edge_palm_rej_enabled = temp; + res = fts_mode_handler(info, 1); + if (res < OK) { + logError(1, "%s%s:Error in fts_mode_handler!%08X\n", + tag, __func__, res); + } + } + + return count; +} +#endif + +#ifdef CHARGER_MODE +/** + * echo 01/00 > charger_mode to enable/disable charger mode + * + * cat charger_mode to show the status of + * the charger_enabled switch (example output in the terminal + * = "AA00000001BB" if the switch is enabled) + * + * echo 01/00 > charger_mode; cat charger_mode + * to enable/disable charger mode and see the + * switch status in just one call + */ +static ssize_t fts_charger_mode_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + char buff[CMD_STR_LEN] = {0}; + int size = 6 * 2; + u8 *all_strbuff = NULL; + int count = 0; + struct i2c_client *client = to_i2c_client(dev); + struct fts_ts_info *info = i2c_get_clientdata(client); + + logError(0, "%s %s:charger_enabled = %d\n", + tag, __func__, info->charger_enabled); + + all_strbuff = kmalloc(size, GFP_KERNEL); + if (all_strbuff != NULL) { + memset(all_strbuff, 0, size); + + snprintf(buff, sizeof(buff), "%02X", 0xAA); + strlcat(all_strbuff, buff, size); + + snprintf(buff, sizeof(buff), "%08X", info->charger_enabled); + strlcat(all_strbuff, buff, size); + + snprintf(buff, sizeof(buff), "%02X", 0xBB); + strlcat(all_strbuff, buff, size); + + count = snprintf(buf, TSP_BUF_SIZE, "%s\n", all_strbuff); + kfree(all_strbuff); + } else { + logError(1, "%s %s:Unable to allocate all_strbuff! %08X\n", + tag, __func__, ERROR_ALLOC); + } + + return count; +} + + +static ssize_t fts_charger_mode_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + char *p = (char *)buf; + unsigned int temp; + int res; + struct i2c_client *client = to_i2c_client(dev); + struct fts_ts_info *info = i2c_get_clientdata(client); + + /** + * in case of a different elaboration of the input, + * just modify this initial part of the code + * according to customer needs + */ + if ((count + 1) / 3 != 1) { + logError(1, "%s %s:Size of parameter wrong! %d != %d byte\n", + tag, __func__, (count + 1) / 3, 1); + return -EINVAL; + } + /*sscanf(p, "%02X ", &temp);*/ + if (sscanf(p, "%02X ", &temp) != 1) + return -EINVAL; + + p += 3; + + /** + * this is a standard code that should be always + * used when a feature is enabled! + * + * first step : check if the wanted feature + * can be enabled + * second step: call fts_mode_handler to + * actually enable it + * + * NOTE: Disabling a feature is always + * allowed by default + */ + res = check_feature_feasibility(info, FEAT_CHARGER); + if (res >= OK || temp == FEAT_DISABLE) { + info->charger_enabled = temp; + res = fts_mode_handler(info, 1); + if (res < OK) { + logError(1, "%s %s: Error during fts_mode_handler! ", + tag, __func__); + logError(1, "ERROR %08X\n", res); + } + } + + return count; +} +#endif + +#ifdef GLOVE_MODE +/** + * echo 01/00 > glove_mode + * to enable/disable glove mode + * + * cat glove_mode to show the status of + * the glove_enabled switch (example output in the + * terminal = "AA00000001BB" if the switch is enabled) + * + * echo 01/00 > glove_mode; cat glove_mode + * to enable/disable glove mode and see the + * switch status in just one call + */ +static ssize_t fts_glove_mode_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + char buff[CMD_STR_LEN] = {0}; + int size = 6 * 2; + u8 *all_strbuff = NULL; + int count = 0; + struct i2c_client *client = to_i2c_client(dev); + struct fts_ts_info *info = i2c_get_clientdata(client); + + logError(0, "%s %s:glove_enabled = %d\n", + tag, __func__, info->glove_enabled); + + all_strbuff = kmalloc(size, GFP_KERNEL); + if (all_strbuff != NULL) { + memset(all_strbuff, 0, size); + + snprintf(buff, sizeof(buff), "%02X", 0xAA); + strlcat(all_strbuff, buff, size); + + snprintf(buff, sizeof(buff), "%08X", info->glove_enabled); + strlcat(all_strbuff, buff, size); + + snprintf(buff, sizeof(buff), "%02X", 0xBB); + strlcat(all_strbuff, buff, size); + + count = snprintf(buf, TSP_BUF_SIZE, "%s\n", all_strbuff); + kfree(all_strbuff); + } else { + logError(1, "%s %s:Unable to allocate all_strbuff! %08X\n", + tag, __func__, ERROR_ALLOC); + } + + return count; +} + + +static ssize_t fts_glove_mode_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + char *p = (char *)buf; + unsigned int temp; + int res; + struct i2c_client *client = to_i2c_client(dev); + struct fts_ts_info *info = i2c_get_clientdata(client); + + /** + * in case of a different elaboration of the input, + * just modify this initial part of the code + * according to customer needs + */ + if ((count + 1) / 3 != 1) { + logError(1, "%s %s:Size of parameter wrong! %d != %d byte\n", + tag, __func__, (count + 1) / 3, 1); + return -EINVAL; + } + + if (sscanf(p, "%02X ", &temp) != 1) + return -EINVAL; + + p += 3; + + /** + * this is a standard code that should be + * always used when a feature is enabled! + * + * first step : check if the wanted feature can be enabled + * + * second step: call fts_mode_handler to actually enable it + * + * NOTE: Disabling a feature is always allowed by default + */ + res = check_feature_feasibility(info, FEAT_GLOVE); + if (res >= OK || temp == FEAT_DISABLE) { + info->glove_enabled = temp; + res = fts_mode_handler(info, 1); + if (res < OK) { + logError(1, "%s %s: Error during fts_mode_handler! ", + tag, __func__); + logError(1, "ERROR %08X\n", res); + } + } + + return count; +} +#endif + +#ifdef VR_MODE +/** + * echo 01/00 > vr_mode to enable/disable vr mode + * + * cat vr_mode to show the status of + * the vr_enabled switch (example output in the + * terminal = "AA00000001BB" if the switch is enabled) + * + * echo 01/00 > vr_mode; cat vr_mode to enable/disable + * vr mode and see the switch status in just one call + */ +static ssize_t fts_vr_mode_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + char buff[CMD_STR_LEN] = {0}; + int size = 6 * 2; + u8 *all_strbuff = NULL; + int count = 0; + struct i2c_client *client = to_i2c_client(dev); + struct fts_ts_info *info = i2c_get_clientdata(client); + + logError(0, "%s %s: vr_enabled = %d\n", + tag, __func__, info->vr_enabled); + + all_strbuff = kmalloc(size, GFP_KERNEL); + if (all_strbuff != NULL) { + memset(all_strbuff, 0, size); + + snprintf(buff, sizeof(buff), "%02X", 0xAA); + strlcat(all_strbuff, buff, size); + + snprintf(buff, sizeof(buff), "%08X", info->vr_enabled); + strlcat(all_strbuff, buff, size); + + snprintf(buff, sizeof(buff), "%02X", 0xBB); + strlcat(all_strbuff, buff, size); + + count = snprintf(buf, TSP_BUF_SIZE, "%s\n", all_strbuff); + kfree(all_strbuff); + } else { + logError(1, + "%s %s: Unable to allocate all_strbuff! ERROR %08X\n", + tag, __func__, ERROR_ALLOC); + } + + return count; +} + + +static ssize_t fts_vr_mode_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + char *p = (char *)buf; + unsigned int temp; + int res; + struct i2c_client *client = to_i2c_client(dev); + struct fts_ts_info *info = i2c_get_clientdata(client); + + + /** + * in case of a different elaboration of the input, + * just modify this initial part of the code + * according to customer needs + */ + if ((count + 1) / 3 != 1) { + logError(1, + "%s %s:Number bytes of parameter wrong!%d != %d byte\n", + tag, __func__, (count + 1) / 3, 1); + return -EINVAL; + } + + if (sscanf(p, "%02X ", &temp) != 1) + return -EINVAL; + + p += 3; + + /** + * this is a standard code that should be always + * used when a feature is enabled! + * + * first step : check if the wanted feature can be enabled + * second step: call fts_mode_handler to actually enable it + * + * NOTE: Disabling a feature is always allowed by default + */ + res = check_feature_feasibility(info, FEAT_VR); + if (res >= OK || temp == FEAT_DISABLE) { + info->vr_enabled = temp; + res = fts_mode_handler(info, 1); + if (res < OK) { + logError(1, "%s %s: Error in fts_mode_handler!%08X\n", + tag, __func__, res); + } + } + + return count; +} +#endif + +#ifdef COVER_MODE +/** + * echo 01/00 > cover_mode to enable/disable cover mode + * cat cover_mode to show the status of the + * cover_enabled switch (example output in the + * terminal = "AA00000001BB" if the switch is enabled) + * + * echo 01/00 > cover_mode; cat cover_mode to + * enable/disable cover mode and see the switch + * status in just one call + * + * NOTE: the cover can be handled also using a notifier, + * in this case the body of these functions + * should be copied in the notifier callback + */ +static ssize_t fts_cover_mode_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + char buff[CMD_STR_LEN] = {0}; + int size = 6 * 2; + u8 *all_strbuff = NULL; + int count = 0; + struct i2c_client *client = to_i2c_client(dev); + struct fts_ts_info *info = i2c_get_clientdata(client); + + logError(0, "%s %s: cover_enabled = %d\n", + tag, __func__, info->cover_enabled); + + all_strbuff = kmalloc(size, GFP_KERNEL); + if (all_strbuff != NULL) { + memset(all_strbuff, 0, size); + + snprintf(buff, sizeof(buff), "%02X", 0xAA); + strlcat(all_strbuff, buff, size); + + snprintf(buff, sizeof(buff), "%08X", info->cover_enabled); + strlcat(all_strbuff, buff, size); + + snprintf(buff, sizeof(buff), "%02X", 0xBB); + strlcat(all_strbuff, buff, size); + + count = snprintf(buf, TSP_BUF_SIZE, "%s\n", all_strbuff); + kfree(all_strbuff); + } else { + logError(1, + "%s %s:Unable to allocate all_strbuff! ERROR %08X\n", + tag, __func__, ERROR_ALLOC); + } + + return count; +} + + +static ssize_t fts_cover_mode_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + char *p = (char *)buf; + unsigned int temp; + int res; + struct i2c_client *client = to_i2c_client(dev); + struct fts_ts_info *info = i2c_get_clientdata(client); + + + /** + * in case of a different elaboration of the input, + * just modify this initial part of the code according + * to customer needs + */ + if ((count + 1) / 3 != 1) { + logError(1, + "%s %s:Number bytes of parameter wrong!%d != %d byte\n", + tag, __func__, (count + 1) / 3, 1); + return -EINVAL; + + } + + if (sscanf(p, "%02X ", &temp) != 1) + return -EINVAL; + p += 3; + + /** + * this is a standard code that should be + * always used when a feature is enabled! + * + * first step : check if the wanted feature can be enabled + * second step: call fts_mode_handler to actually enable it + * NOTE: Disabling a feature is always allowed by default + */ + res = check_feature_feasibility(info, FEAT_COVER); + if (res >= OK || temp == FEAT_DISABLE) { + info->cover_enabled = temp; + res = fts_mode_handler(info, 1); + if (res < OK) { + logError(1, "%s%s:Error in fts_mode_handler!%08X\n", + tag, __func__, res); + } + } + + + return count; +} +#endif + +#ifdef STYLUS_MODE +/** + * echo 01/00 > stylus_mode to enable/disable stylus mode + * cat stylus_mode to show the status of + * the stylus_enabled switch (example output in the + * terminal = "AA00000001BB" if the switch is enabled) + * + * echo 01/00 > stylus_mode; cat stylus_mode to + * enable/disable stylus mode and see the + * switch status in just one call + */ +static ssize_t fts_stylus_mode_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + char buff[CMD_STR_LEN] = {0}; + int size = 6 * 2; + u8 *all_strbuff = NULL; + int count = 0; + struct i2c_client *client = to_i2c_client(dev); + struct fts_ts_info *info = i2c_get_clientdata(client); + + logError(0, "%s %s: stylus_enabled = %d\n", + tag, __func__, info->stylus_enabled); + + all_strbuff = kmalloc(size, GFP_KERNEL); + if (all_strbuff != NULL) { + memset(all_strbuff, 0, size); + + snprintf(buff, sizeof(buff), "%02X", 0xAA); + strlcat(all_strbuff, buff, size); + + snprintf(buff, sizeof(buff), "%08X", info->stylus_enabled); + strlcat(all_strbuff, buff, size); + + snprintf(buff, sizeof(buff), "%02X", 0xBB); + strlcat(all_strbuff, buff, size); + + count = snprintf(buf, TSP_BUF_SIZE, "%s\n", all_strbuff); + kfree(all_strbuff); + } else { + logError(1, + "%s %s: Unable to allocate all_strbuff! ERROR %08X\n", + tag, __func__, ERROR_ALLOC); + } + + return count; +} + + +static ssize_t fts_stylus_mode_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + char *p = (char *)buf; + unsigned int temp; + int res; + struct i2c_client *client = to_i2c_client(dev); + struct fts_ts_info *info = i2c_get_clientdata(client); + + + /** + * in case of a different elaboration of the input, + * just modify this initial part of the code + * according to customer needs + */ + if ((count + 1) / 3 != 1) { + logError(1, "%s %s:Size of parameter wrong! %d != %d byte\n", + tag, __func__, (count + 1) / 3, 1); + return -EINVAL; + } + + if (sscanf(p, "%02X ", &temp) != 1) + return -EINVAL; + p += 3; + + /** + * this is a standard code that should be + * always used when a feature is enabled! + * + * first step : check if the wanted feature can be enabled + * second step: call fts_mode_handler to actually enable it + * NOTE: Disabling a feature is always allowed by default + */ + res = check_feature_feasibility(info, FEAT_STYLUS); + if (res >= OK || temp == FEAT_DISABLE) { + info->stylus_enabled = temp; + res = fts_mode_handler(info, 1); + if (res < OK) { + logError(1, + "%s %s:Error during fts_mode_handler! %08X\n", + tag, __func__, res); + } + } + + + return count; +} +#endif + +#endif + +/************** GESTURES *************/ +#ifdef PHONE_GESTURE +#ifdef USE_GESTURE_MASK + +/** + * if this define is used, a gesture bit mask + * is used as method to select the gestures + * to enable/disable + */ + +/** + * echo EE X1 X2 ... X8 > gesture_mask set + * the gesture mask to disable/enable; + * EE = 00(disable) or 01(enable); + * X1 ... X8 = gesture mask (example 06 00 ... 00 + * this gesture mask represent the gestures with ID = 1 and 2) + * can be specified from 1 to 8 bytes, if less than 8 bytes + * are specified the remaining bytes are kept as previous settings + * + * cat gesture_mask enable/disable the given mask, + * if one or more gestures is enabled the driver will + * automatically enable the gesture mode. + * If all the gestures are disabled the driver + * automatically will disable the gesture mode. + * At the end an error code will be printed + * (example output in the terminal = "AA00000000BB" + * if there are no errors) + * + * echo EE X1 X2 ... X8 > gesture_mask; + * cat gesture_mask perform in one + * command both actions stated before + */ +static ssize_t fts_gesture_mask_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + char buff[CMD_STR_LEN] = {0}; + int size = 6 * 2; + u8 *all_strbuff = NULL; + int count = 0, res, temp; + struct i2c_client *client = to_i2c_client(dev); + struct fts_ts_info *info = i2c_get_clientdata(client); + + if (mask[0] == 0) { + res = ERROR_OP_NOT_ALLOW; + logError(1, "%s %s:Call before echo enable/disable xx xx >", + tag), __func__; + logError(1, "%s %s: gesture_mask with a correct number of ", + tag, __func__); + logError(1, "parameters! ERROR %08X\n", res); + return -EINVAL; + } + + if (mask[1] == FEAT_ENABLE || mask[1] == FEAT_DISABLE) + res = updateGestureMask(&mask[2], mask[0], mask[1]); + else + res = ERROR_OP_NOT_ALLOW; + + if (res < OK) { + logError(1, "%s fts_gesture_mask_store: ERROR %08X\n", + tag, res); + } + + res |= check_feature_feasibility(info, FEAT_GESTURE); + temp = isAnyGestureActive(); + if (res >= OK || temp == FEAT_DISABLE) + info->gesture_enabled = temp; + + logError(1, "%s fts_gesture_mask_store:Gesture Enabled = %d\n", + tag, info->gesture_enabled); + + all_strbuff = kmalloc(size, GFP_KERNEL); + if (all_strbuff != NULL) { + memset(all_strbuff, 0, size); + + snprintf(buff, sizeof(buff), "%02X", 0xAA); + strlcat(all_strbuff, buff, size); + + snprintf(buff, sizeof(buff), "%08X", res); + strlcat(all_strbuff, buff, size); + + snprintf(buff, sizeof(buff), "%02X", 0xBB); + strlcat(all_strbuff, buff, size); + + count = snprintf(buf, TSP_BUF_SIZE, "%s\n", all_strbuff); + kfree(all_strbuff); + } else { + logError(1, + "%s %s:Unable to allocate all_strbuff! ERROR %08X\n", + tag, __func__, ERROR_ALLOC); + } + + mask[0] = 0; + return count; +} + + +static ssize_t fts_gesture_mask_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + char *p = (char *)buf; + int n; + unsigned int temp; + + if ((count + 1) / 3 > GESTURE_MASK_SIZE + 1) { + logError(1, "%s %s: Number of bytes of parameter wrong! ", tag, + __func__); + logError(1, "%d > (enable/disable + %d )\n", (count + 1) / 3, + GESTURE_MASK_SIZE); + mask[0] = 0; + return -EINVAL; + } + mask[0] = ((count + 1) / 3) - 1; + for (n = 1; n <= (count + 1) / 3; n++) { + if (sscanf(p, "%02X ", &temp) != 1) + return -EINVAL; + p += 3; + mask[n] = (u8)temp; + logError(1, "%s mask[%d] = %02X\n", tag, n, mask[n]); + } + + return count; +} + +#else + +/** + * if this define is not used, + * to select the gestures to enable/disable + * are used the IDs of the gestures + * + * echo EE X1 X2 ... > gesture_mask set + * the gesture to disable/enable; EE = 00(disable) + * or 01(enable); X1 ... = gesture IDs + * (example 01 02 05... represent the gestures with + * ID = 1, 2 and 5) there is no limit of the parameters + * that can be passed, but of course the gesture IDs + * should be valid (all the valid IDs are listed + * in ftsGesture.h) + * + * cat gesture_mask enable/disable the + * given gestures, if one or more gestures is enabled + * the driver will automatically enable the gesture mode. + * If all the gestures are disabled the driver automatically + * will disable the gesture mode. At the end an error code + * will be printed (example output in the terminal = + * "AA00000000BB" if there are no errors) + * + * echo EE X1 X2 ... > gesture_mask; cat gesture_mask + * perform in one command both actions stated before + */ +static ssize_t fts_gesture_mask_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + char buff[CMD_STR_LEN] = {0}; + int size = 6 * 2; + u8 *all_strbuff = NULL; + int count = 0; + struct i2c_client *client = to_i2c_client(dev); + struct fts_ts_info *info = i2c_get_clientdata(client); + + logError(0, "%s %s: gesture_enabled = %d\n", tag, __func__, + info->gesture_enabled); + + all_strbuff = kmalloc(size, GFP_KERNEL); + if (all_strbuff != NULL) { + memset(all_strbuff, 0, size); + + snprintf(buff, sizeof(buff), "%02X", 0xAA); + strlcat(all_strbuff, buff, size); + + snprintf(buff, sizeof(buff), "%08X", info->gesture_enabled); + strlcat(all_strbuff, buff, size); + + snprintf(buff, sizeof(buff), "%02X", 0xBB); + strlcat(all_strbuff, buff, size); + + count = snprintf(buf, TSP_BUF_SIZE, "%s\n", all_strbuff); + kfree(all_strbuff); + } else { + logError(1, + "%s %s: Unable to allocate all_strbuff! ERROR %08X\n", + tag, __func__, ERROR_ALLOC); + } + + return count; +} + + +static ssize_t fts_gesture_mask_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + char *p = (char *)buf; + int n; + unsigned int temp; + int res; + struct i2c_client *client = to_i2c_client(dev); + struct fts_ts_info *info = i2c_get_clientdata(client); + + if ((count + 1) / 3 < 2 || (count + 1) / 3 > GESTURE_MASK_SIZE + 1) { + logError(1, + "%s %s:Number bytes of parameter wrong! %d %d bytes)\n", + tag, __func__, (count + 1) / 3, GESTURE_MASK_SIZE); + mask[0] = 0; + return -EINVAL; + } + + memset(mask, 0, GESTURE_MASK_SIZE + 2); + mask[0] = ((count + 1) / 3) - 1; + if (sscanf(p, "%02X ", &temp) != 1) + return -EINVAL; + + p += 3; + mask[1] = (u8)temp; + for (n = 1; n < (count + 1) / 3; n++) { + /*sscanf(p, "%02X ", &temp);*/ + if (sscanf(p, "%02X ", &temp) != 1) + return -EINVAL; + + p += 3; + gestureIDtoGestureMask((u8)temp, &mask[2]); + } + + for (n = 0; n < GESTURE_MASK_SIZE + 2; n++) + logError(1, "%s mask[%d] = %02X\n", tag, n, mask[n]); + + if (mask[0] == 0) { + res = ERROR_OP_NOT_ALLOW; + logError(1, "%s %s: Call before echo enable/disable xx xx ....", + tag, __func__); + logError(1, " > gesture_mask with parameters! ERROR %08X\n", + res); + + } else { + + if (mask[1] == FEAT_ENABLE || mask[1] == FEAT_DISABLE) + res = updateGestureMask(&mask[2], mask[0], mask[1]); + else + res = ERROR_OP_NOT_ALLOW; + + if (res < OK) + logError(1, "%s %s: ERROR %08X\n", tag, __func__, res); + + } + + res = check_feature_feasibility(info, FEAT_GESTURE); + temp = isAnyGestureActive(); + if (res >= OK || temp == FEAT_DISABLE) + info->gesture_enabled = temp; + res = fts_mode_handler(info, 0); + + return count; +} +#endif + +#ifdef USE_CUSTOM_GESTURES +/** + * allow to use user defined gestures + * + * echo ID X1 Y1 X2 Y2 ... X30 Y30 > + * add_custom_gesture add a custom gesture; + * ID = 1 byte that represent the gesture ID of + * the custom gesture (can be chosen only between + * the custom IDs defined in ftsGesture.h); + * X1 Y1 ... = a series of 30 points (x,y) which + * represent the gesture template. + * The loaded gesture is enabled automatically + * + * cat add_custom_gesture/remove_custom_gesture + * Print the error code of the last operation + * performed with the custom gestures + * (example output in the terminal = "AA00000000BB" + * if there are no errors) + * + * echo ID X1 Y1 X2 Y2 ... X30 Y30 > + * add_custom_gesture; cat add_custom_gesture + * perform in one command both actions stated before + */ +static ssize_t fts_custom_gesture_result_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + char buff[CMD_STR_LEN] = {0}; + int size = 6 * 2; + u8 *all_strbuff = NULL; + int count = 0; + + logError(0, "%s %s:Last Operation Result = %08X\n", + tag, __func__, custom_gesture_res); + + all_strbuff = kmalloc(size, GFP_KERNEL); + if (all_strbuff != NULL) { + memset(all_strbuff, 0, size); + + snprintf(buff, sizeof(buff), "%02X", 0xAA); + strlcat(all_strbuff, buff, size); + + snprintf(buff, sizeof(buff), "%08X", custom_gesture_res); + strlcat(all_strbuff, buff, size); + + snprintf(buff, sizeof(buff), "%02X", 0xBB); + strlcat(all_strbuff, buff, size); + + count = snprintf(buf, TSP_BUF_SIZE, "%s\n", all_strbuff); + kfree(all_strbuff); + } else { + logError(1, + "%s %s:Unable to allocate all_strbuff! ERROR %08X\n", + tag, __func__, ERROR_ALLOC); + } + + return count; +} + + +static ssize_t fts_add_custom_gesture_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + char *p = (char *)buf; + int n; + unsigned int temp; + u8 gestureID; + u8 gestMask[GESTURE_MASK_SIZE] = {0}; + u8 template[GESTURE_CUSTOM_POINTS]; + int res; + /*struct i2c_client *client = to_i2c_client(dev);*/ + /*struct fts_ts_info *info = i2c_get_clientdata(client);*/ + + if ((count + 1) / 3 != GESTURE_CUSTOM_POINTS + 1) { + logError(1, + "%s %s: Number bytes of parameter wrong! %d != %d\n", + tag, __func__, (count + 1) / 3, + GESTURE_CUSTOM_POINTS + 1); + res = ERROR_OP_NOT_ALLOW; + return -EINVAL; + } + if (sscanf(p, "%02X ", &temp) != 1) + return -EINVAL; + p += 3; + gestureID = (u8)temp; + + for (n = 1; n < (count + 1) / 3; n++) { + /*sscanf(p, "%02X ", &temp);*/ + if (sscanf(p, "%02X ", &temp) != 1) + return -EINVAL; + + p += 3; + template[n-1] = (u8)temp; + logError(1, "%s template[%d] = %02X\n", + tag, n-1, template[n-1]); + } + + res = fts_disableInterrupt(); + if (res >= OK) { + logError(1, "%s %s: Adding custom gesture ID = %02X\n", + tag, __func__, gestureID); + res = addCustomGesture(template, + GESTURE_CUSTOM_POINTS, gestureID); + if (res < OK) { + logError(1, + "%s %s:error during add custom gesture ", + tag, __func__); + logError(1, "ERROR %08X\n", res); + } else { + logError(1, + "%s %s:Enabling in the gesture mask...\n", + tag, __func__); + gestureIDtoGestureMask(gestureID, gestMask); + res = enableGesture(gestMask, GESTURE_MASK_SIZE); + if (res < OK) { + logError(1, "%s %s:error during enable gesture", + tag, __func__); + logError(1, " mask: ERROR %08X\n", res); + } else { + /*if(check_feature_feasibility(info,*/ + /*FEAT_GESTURE)==OK)*/ + /*info->gesture_enabled =*/ + /*isAnyGestureActive();*/ + /*uncomment if you want to activate*/ + /* automatically*/ + /*the gesture mode when a custom gesture*/ + /*is loaded*/ + logError(1, "%s %s:Custom Gesture enabled!\n", + tag, __func__, res); + } + } + } + res |= fts_enableInterrupt(); + + custom_gesture_res = res; + + return count; +} + + +/** + * echo ID > remove_custom_gesture + * remove a custom gesture; + * ID = 1 byte that represent the gesture ID + * of the custom gesture (can be chosen only + * between the custom IDs defined in ftsGesture.h); + * the same gesture is disabled automatically + */ +static ssize_t fts_remove_custom_gesture_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + char *p = (char *)buf; + unsigned int temp; + int res; + u8 gestureID; + u8 gestMask[GESTURE_MASK_SIZE] = {0}; + /*struct i2c_client *client = to_i2c_client(dev);*/ + /*struct fts_ts_info *info = i2c_get_clientdata(client);*/ + + if ((count + 1) / 3 < 1) { + logError(1, + "%s %s:Number bytes of parameter wrong! %d != %d\n", + tag, __func__, (count + 1) / 3, 1); + res = ERROR_OP_NOT_ALLOW; + return -EINVAL; + } + + if (sscanf(p, "%02X ", &temp) != 1) + return -EINVAL; + p += 3; + gestureID = (u8)temp; + res = fts_disableInterrupt(); + if (res >= OK) { + logError(1, + "%s %s: Removing custom gesture ID = %02X\n", + tag, __func__, gestureID); + res = removeCustomGesture(gestureID); + if (res < OK) { + logError(1, + "%s %s:error in custom gesture:%08X\n", + tag, __func__, res); + } else { + logError(1, "%s %s: Enabling in the gesture mask...\n", + tag, __func__); + gestureIDtoGestureMask(gestureID, gestMask); + res = disableGesture(gestMask, GESTURE_MASK_SIZE); + if (res < OK) { + logError(1, + "%s %s:error in enable gesture mask:%08X\n", + tag, __func__, res); + } else { + /*if(check_feature_feasibility*/ + /*(info,FEAT_GESTURE)==OK)*/ + /*info->gesture_enabled = */ + /*isAnyGestureActive();*/ + /** + * uncomment if you want to disable + * automatically + * the gesture mode when a custom gesture is + * removed and no other gestures were enabled + */ + logError(1, "%s %s: Custom Gesture disabled!\n", + tag, __func__, res); + } + + } + } + + res |= fts_enableInterrupt(); + + custom_gesture_res = res; + return count; +} +#endif + + +/** + * cat gesture_coordinates to obtain the gesture coordinates + * the string returned in the shell follow this up as follow: + * AA = start byte + * X1X2X3X4 = 4 bytes in HEX format + * which represent an error code (00000000 no error) + */ + /**** if error code is all 0s ****/ +/** + * CC = 1 byte in HEX format number of coords + * (pair of x,y) returned + * + * X1X2 Y1Y2 ... = X1X2 2 bytes in HEX format for + * x[i] and Y1Y2 2 bytes in HEX format for y[i] (MSB first) + */ +/********************************/ +/* BB = end byte*/ +static ssize_t fts_gesture_coordinates_show(struct device *dev, struct device_attribute *attr, char *buf) { char buff[CMD_STR_LEN] = {0}; int size = 6 * 2; + //u8 coords_num; u8 *all_strbuff = NULL; - int count = 0, res; - struct i2c_client *client = to_i2c_client(dev); - struct fts_ts_info *info = i2c_get_clientdata(client); + int count = 0, res, i = 0; - if (feature_feasibility >= OK) - res = fts_mode_handler(info, 1); - else{ - res = feature_feasibility; - logError(1, "%s %s: Call before echo xx xx > feature_enable with a correct feature! ERROR %08X\n", tag, __func__, res); + logError(0, "%s %s: Getting gestures coordinates...\n", tag, __func__); + + if (gesture_coords_reported < OK) { + logError(1, "%s %s:invalid coordinates! ERROR %08X\n", + tag, __func__, gesture_coords_reported); + res = gesture_coords_reported; + } else { + /*coords are pairs of x,y (*2) where each coord*/ + /*is a short(2bytes=4char)(*4) + 1 byte(2char) num*/ + /*of coords (+2)*/ + size += gesture_coords_reported * 2 * 4 + 2; + /*coords_num = res;*/ + res = OK; + /*set error code to OK*/ } - all_strbuff = (u8 *) kmalloc(size, GFP_KERNEL); + all_strbuff = kmalloc(size, GFP_KERNEL); if (all_strbuff != NULL) { memset(all_strbuff, 0, size); @@ -287,126 +2090,67 @@ static ssize_t fts_feature_enable_show(struct device *dev, snprintf(buff, sizeof(buff), "%08X", res); strlcat(all_strbuff, buff, size); - snprintf(buff, sizeof(buff), "%02X", 0xBB); - strlcat(all_strbuff, buff, size); - - count = snprintf(buf, TSP_BUF_SIZE, "%s\n", all_strbuff); - kfree(all_strbuff); - } else{ - logError(1, "%s fts_feature_enable_show: Unable to allocate all_strbuff! ERROR %08X\n", tag, ERROR_ALLOC); - } - - feature_feasibility = ERROR_OP_NOT_ALLOW; - return count; -} - -#ifdef PHONE_GESTURE -static ssize_t fts_gesture_mask_show(struct device *dev, struct device_attribute *attr, char *buf) -{ - char buff[CMD_STR_LEN] = {0}; - int size = 6 * 2; - u8 *all_strbuff = NULL; - int count = 0, res; + if (res >= OK) { + snprintf(buff, sizeof(buff), "%02X", + gesture_coords_reported); + strlcat(all_strbuff, buff, size); - if (mask[0] == 0) { - res = ERROR_OP_NOT_ALLOW; - logError(1, "%s %s: Call before echo enable/disable xx xx .... > gesture_mask with a correct number of parameters! ERROR %08X\n", tag, __func__, res); + for (i = 0; i < gesture_coords_reported; i++) { + snprintf(buff, sizeof(buff), "%04X", + gesture_coordinates_x[i]); + strlcat(all_strbuff, buff, size); - } else{ - res = fts_disableInterrupt(); - if (res >= OK) { - if (mask[1] == FEAT_ENABLE) - res = enableGesture(&mask[2], mask[0]); - else{ - if (mask[1] == FEAT_DISABLE) - res = disableGesture(&mask[2], mask[0]); - else - res = ERROR_OP_NOT_ALLOW; - } - if (res < OK) { - logError(1, "%s fts_gesture_mask_store: ERROR %08X\n", tag, res); + snprintf(buff, sizeof(buff), "%04X", + gesture_coordinates_y[i]); + strlcat(all_strbuff, buff, size); } } - res |= fts_enableInterrupt(); - } - - all_strbuff = (u8 *) kmalloc(size, GFP_KERNEL); - if (all_strbuff != NULL) { - memset(all_strbuff, 0, size); - - snprintf(buff, sizeof(buff), "%02X", 0xAA); - strlcat(all_strbuff, buff, size); - - snprintf(buff, sizeof(buff), "%08X", res); - strlcat(all_strbuff, buff, size); snprintf(buff, sizeof(buff), "%02X", 0xBB); - strlcat(all_strbuff, buff, size); + strlcat(all_strbuff, buff, size); count = snprintf(buf, TSP_BUF_SIZE, "%s\n", all_strbuff); kfree(all_strbuff); - } else{ - logError(1, "%s fts_gesture_mask_show: Unable to allocate all_strbuff! ERROR %08X\n", tag, ERROR_ALLOC); - } - - mask[0] = 0; - return count; -} - -static ssize_t fts_gesture_mask_store(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - char *p = (char *)buf; - int n; - unsigned int temp; - - if ((count + 1) / 3 > GESTURE_MASK_SIZE+1) { - logError(1, "%s fts_gesture_mask_store: Number of bytes of parameter wrong! %d > (enable/disable + %d )\n", tag, (count + 1) / 3, GESTURE_MASK_SIZE); - mask[0] = 0; } else { - mask[0] = ((count + 1) / 3) - 1; - for (n = 1; n <= (count + 1) / 3; n++) { - sscanf(p, "%02X ", &temp); - p += 3; - mask[n] = (u8)temp; - logError(1, "%s mask[%d] = %02X\n", tag, n, mask[n]); - - } - + logError(1, + "%s %s:Unable to allocate all_strbuff! ERROR %08X\n", + tag, ERROR_ALLOC); } return count; } #endif -/************************ PRODUCTION TEST **********************************/ -static ssize_t stm_fts_cmd_store(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) { + + +/***************** PRODUCTION TEST ****************/ +static ssize_t stm_fts_cmd_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ int n; char *p = (char *) buf; - typeOfComand = (u32 *) kmalloc(8 * sizeof (u32), GFP_KERNEL); - if (typeOfComand == NULL) { - logError(1, "%s impossible to allocate typeOfComand!\n", tag); - return count; - } - memset(typeOfComand, 0, 8 * sizeof (u32)); + memset(typeOfComand, 0, CMD_STR_LEN * sizeof(u32)); - logError(1, "%s\n", tag); + logError(1, "%s\n", tag); for (n = 0; n < (count + 1) / 3; n++) { - sscanf(p, "%02X ", &typeOfComand[n]); + + if (sscanf(p, "%02X ", &typeOfComand[n]) != 1) + return -EINVAL; p += 3; - logError(1, "%s typeOfComand[%d] = %02X\n", tag, n, typeOfComand[n]); + logError(1, "%s typeOfComand[%d] = %02X\n", + tag, n, typeOfComand[n]); } numberParameters = n; - logError(1, "%s Number of Parameters = %d\n", tag, numberParameters); + logError(1, "%s Number of Parameters = %d\n", tag, numberParameters); return count; } -static ssize_t stm_fts_cmd_show(struct device *dev, struct device_attribute *attr, - char *buf) { +static ssize_t stm_fts_cmd_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ char buff[CMD_STR_LEN] = {0}; int res, j, doClean = 0, count; @@ -415,15 +2159,16 @@ static ssize_t stm_fts_cmd_show(struct device *dev, struct device_attribute *att struct i2c_client *client = to_i2c_client(dev); struct fts_ts_info *info = i2c_get_clientdata(client); - MutualSenseData compData; - SelfSenseData comData; - MutualSenseFrame frameMS; - SelfSenseFrame frameSS; + struct MutualSenseData compData; + struct SelfSenseData comData; + struct MutualSenseFrame frameMS; + struct SelfSenseFrame frameSS; - /* struct used for defining which test - *perform during the production test + /** + * struct used for defining which test + * perform during the production test */ - TestToDo todoDefault; + struct TestToDo todoDefault; todoDefault.MutualRaw = 1; todoDefault.MutualRawGap = 1; @@ -464,191 +2209,281 @@ static ssize_t stm_fts_cmd_show(struct device *dev, struct device_attribute *att todoDefault.SelfSenseCxTotal = 0; todoDefault.SelfSenseCxTotalAdj = 0; - if (numberParameters >= 1 && typeOfComand != NULL) { + + if (numberParameters >= 1) { res = fts_disableInterrupt(); if (res < 0) { - logError(0, "%s fts_disableInterrupt: ERROR %08X\n", tag, res); + logError(0, "%s fts_disableInterrupt: ERROR %08X\n", + tag, res); res = (res | ERROR_DISABLE_INTER); goto END; } +#if defined(CONFIG_FB_MSM) res = fb_unregister_client(&info->notifier); +#else + res = msm_drm_unregister_client(&info->notifier); +#endif if (res < 0) { - logError(1, "%s ERROR: unregister notifier failed!\n", tag); - goto END; + logError(1, "%s ERROR: unregister notifier failed!\n", + tag); + goto END; } switch (typeOfComand[0]) { - /*ITO TEST*/ + /*ITO TEST*/ case 0x01: res = production_test_ito(); break; - /*PRODUCTION TEST*/ + /*PRODUCTION TEST*/ case 0x00: if (ftsInfo.u32_mpPassFlag != INIT_MP) { - logError(0, "%s MP Flag not set!\n", tag, res); - res = production_test_main(LIMITS_FILE, 1, 1, &todoDefault, INIT_MP); - } else{ - logError(0, "%s MP Flag set!\n", tag, res); - res = production_test_main(LIMITS_FILE, 1, 0, &todoDefault, INIT_MP); - } - break; - /*read mutual raw*/ + logError(0, "%s MP Flag not set!\n", tag, res); + res = production_test_main(LIMITS_FILE, 1, 1, + &todoDefault, INIT_MP); + } else { + logError(0, "%s MP Flag set!\n", tag, res); + res = production_test_main(LIMITS_FILE, 1, 0, + &todoDefault, INIT_MP); + } + break; + /*read mutual raw*/ case 0x13: logError(0, "%s Get 1 MS Frame\n", tag); - /* res = getMSFrame(ADDR_RAW_TOUCH, &frame, 0); */ + //res = getMSFrame(ADDR_RAW_TOUCH, &frame, 0); res = getMSFrame2(MS_TOUCH_ACTIVE, &frameMS); if (res < 0) { - logError(0, "%s Error while taking the MS frame... ERROR %02X\n", tag, res); + logError(0, + "%s Error in taking MS frame.%02X\n", + tag, res); } else { - logError(0, "%s The frame size is %d words\n", tag, res); - size = (res * sizeof (short) + 8)*2; - /* set res to OK because if getMSFrame is - * successful res = number of words read - */ + logError(0, "%s The frame size is %d words\n", + tag, res); + size = (res * sizeof(short) + 8) * 2; + /* set res to OK because if getMSFrame is*/ + /* successful res = number of words read*/ res = OK; + print_frame_short("MS frame =", + array1dTo2d_short(frameMS.node_data, + frameMS.node_data_size, + frameMS.header.sense_node), + frameMS.header.force_node, + frameMS.header.sense_node); } - break; - /*read self raw*/ + break; + /*read self raw*/ case 0x15: logError(0, "%s Get 1 SS Frame\n", tag); res = getSSFrame2(SS_TOUCH, &frameSS); if (res < OK) { - logError(0, "%s Error while taking the SS frame... ERROR %02X\n", tag, res); + logError(0, + "%s Error while taking the SS frame%02X\n", + tag, res); } else { - logError(0, "%s The frame size is %d words\n", tag, res); - size = (res * sizeof (short) + 8)*2+1; - /* set res to OK because if getMSFrame is + logError(0, "%s The frame size is %d words\n", + tag, res); + size = (res * sizeof(short) + 8) * 2 + 1; + /** + * set res to OK because if getMSFrame is * successful res = number of words read */ res = OK; + print_frame_short("SS force frame =", + array1dTo2d_short(frameSS.force_data, + frameSS.header.force_node, 1), + frameSS.header.force_node, 1); + print_frame_short("SS sense frame =", + array1dTo2d_short(frameSS.sense_data, + frameSS.header.sense_node, + frameSS.header.sense_node), + 1, + frameSS.header.sense_node); } - break; - case 0x14: /*read mutual comp data */ + /*read mutual comp data*/ + case 0x14: logError(0, "%s Get MS Compensation Data\n", tag); - res = readMutualSenseCompensationData(MS_TOUCH_ACTIVE, &compData); + res = readMutualSenseCompensationData(MS_TOUCH_ACTIVE, + &compData); if (res < 0) { - logError(0, "%s Error reading MS compensation data ERROR %02X\n", tag, res); + logError(0, + "%s Error MS compensation data%02X\n", + tag, res); } else { - logError(0, "%s MS Compensation Data Reading Finished!\n", tag); - size = ((compData.node_data_size + 9) * sizeof (u8))*2; + logError(0, + "%s MS Data Reading Finished!\n", + tag); + size = ((compData.node_data_size + 9) * + sizeof(u8)) * 2; + print_frame_u8("MS Data (Cx2) =", + array1dTo2d_u8(compData.node_data, + compData.node_data_size, + compData.header.sense_node), + compData.header.force_node, + compData.header.sense_node); } break; - case 0x16: /* read self comp data */ + /*read self comp data*/ + case 0x16: logError(0, "%s Get SS Compensation Data...\n", tag); res = readSelfSenseCompensationData(SS_TOUCH, &comData); if (res < 0) { - logError(0, "%s Error reading SS compensation data ERROR %02X\n", tag, res); + logError(0, "%s Error reading SS data%02X\n", + tag, res); } else { - logError(0, "%s SS Compensation Data Reading Finished!\n", tag); - size = ((comData.header.force_node + comData.header.sense_node)*2 + 12) * sizeof (u8)*2; + logError(0, "%s SS Data Reading Finished!\n", + tag); + size = ((comData.header.force_node + + comData.header.sense_node) * 2 + 12); + size *= sizeof(u8) * 2; + print_frame_u8("SS Data Ix2_fm = ", + array1dTo2d_u8(comData.ix2_fm, + comData.header.force_node, 1), + comData.header.force_node, + 1); + print_frame_u8("SS Data Cx2_fm = ", + array1dTo2d_u8(comData.cx2_fm, + comData.header.force_node, 1), + comData.header.force_node, + 1); + print_frame_u8("SS Data Ix2_sn = ", + array1dTo2d_u8(comData.ix2_sn, + comData.header.sense_node, + comData.header.sense_node), + 1, + comData.header.sense_node); + print_frame_u8("SS Data Cx2_sn = ", + array1dTo2d_u8(comData.cx2_sn, + comData.header.sense_node, + comData.header.sense_node), + 1, + comData.header.sense_node); } break; - case 0x03: /* MS Raw DATA TEST */ + /* MS Raw DATA TEST */ + case 0x03: res = fts_system_reset(); if (res >= OK) - res = production_test_ms_raw(LIMITS_FILE, 1, &todoDefault); + res = production_test_ms_raw(LIMITS_FILE, + 1, &todoDefault); break; - - case 0x04: /* MS CX DATA TEST */ + /* MS CX DATA TEST */ + case 0x04: res = fts_system_reset(); if (res >= OK) - res = production_test_ms_cx(LIMITS_FILE, 1, &todoDefault); + res = production_test_ms_cx(LIMITS_FILE, + 1, &todoDefault); break; - - case 0x05: /* SS RAW DATA TEST */ + /* SS RAW DATA TEST */ + case 0x05: res = fts_system_reset(); if (res >= OK) - res = production_test_ss_raw(LIMITS_FILE, 1, &todoDefault); + res = production_test_ss_raw(LIMITS_FILE, + 1, &todoDefault); break; - - case 0x06: /* SS IX CX DATA TEST */ + /* SS IX CX DATA TEST */ + case 0x06: res = fts_system_reset(); if (res >= OK) - res = production_test_ss_ix_cx(LIMITS_FILE, 1, &todoDefault); + res = production_test_ss_ix_cx(LIMITS_FILE, + 1, &todoDefault); break; case 0xF0: - case 0xF1: /* TOUCH ENABLE/DISABLE */ - doClean = (int) (typeOfComand[0]&0x01); + /* TOUCH ENABLE/DISABLE */ + case 0xF1: + doClean = (int) (typeOfComand[0] & 0x01); res = cleanUp(doClean); - break; default: - logError(1, "%s COMMAND NOT VALID!! Insert a proper value ...\n", tag); + logError(1, + "%s COMMAND NOT VALID!! Insert a proper value\n", + tag); res = ERROR_OP_NOT_ALLOW; break; } doClean = fts_enableInterrupt(); if (doClean < 0) { - logError(0, "%s fts_enableInterrupt: ERROR %08X\n", tag, (doClean|ERROR_ENABLE_INTER)); + logError(0, "%s fts_enableInterrupt: ERROR %08X\n", + tag, (doClean|ERROR_ENABLE_INTER)); } } else { - logError(1, "%s NO COMMAND SPECIFIED!!! do: 'echo [cmd_code] [args] > stm_fts_cmd' before looking for result!\n", tag); + logError(1, "%s NO COMMAND SPECIFIED!!!\n", tag); res = ERROR_OP_NOT_ALLOW; - typeOfComand = NULL; - } - if (fb_register_client(&info->notifier) < 0) { - logError(1, "%s ERROR: register notifier failed!\n", tag); - } +#if defined(CONFIG_FB_MSM) + if (fb_register_client(&info->notifier) < 0) + logError(1, "%s ERROR: register notifier failed!\n", tag); +#else + if (msm_drm_register_client(&info->notifier) < 0) + logError(1, "%s ERROR: register notifier failed!\n", tag); +#endif -END: /* here start the reporting phase, assembling the data to send in the file node */ - all_strbuff = (u8 *) kmalloc(size, GFP_KERNEL); +END: + /*here start the reporting phase,*/ + /* assembling the data to send in the file node */ + all_strbuff = kmalloc(size, GFP_KERNEL); memset(all_strbuff, 0, size); snprintf(buff, sizeof(buff), "%02X", 0xAA); - strlcat(all_strbuff, buff, size); + strlcat(all_strbuff, buff, 2); snprintf(buff, sizeof(buff), "%08X", res); - strlcat(all_strbuff, buff, size); + strlcat(all_strbuff, buff, 8); if (res >= OK) { /*all the other cases are already fine printing only the res.*/ switch (typeOfComand[0]) { case 0x13: - snprintf(buff, sizeof (buff), "%02X", (u8) frameMS.header.force_node); - strlcat(all_strbuff, buff, size); - - snprintf(buff, sizeof(buff), "%02X", (u8) frameMS.header.sense_node); - strlcat(all_strbuff, buff, size); - - for (j = 0; j < frameMS.node_data_size; j++) { - snprintf(buff, sizeof(buff), "%04X", frameMS.node_data[j]); - strlcat(all_strbuff, buff, size); - } + snprintf(buff, sizeof(buff), "%02X", + (u8) frameMS.header.force_node); + strlcat(all_strbuff, buff, 2); + + snprintf(buff, sizeof(buff), "%02X", + (u8) frameMS.header.sense_node); + strlcat(all_strbuff, buff, 2); + + for (j = 0; j < frameMS.node_data_size; j++) { + snprintf(buff, sizeof(buff), "%04X", + frameMS.node_data[j]); + strlcat(all_strbuff, buff, 4); + } - kfree(frameMS.node_data); - break; + kfree(frameMS.node_data); + break; case 0x15: - snprintf(buff, sizeof(buff), "%02X", (u8) frameSS.header.force_node); - strlcat(all_strbuff, buff, size); + snprintf(buff, sizeof(buff), "%02X", + (u8) frameSS.header.force_node); + strlcat(all_strbuff, buff, 2); - snprintf(buff, sizeof(buff), "%02X", (u8) frameSS.header.sense_node); - strlcat(all_strbuff, buff, size); + snprintf(buff, sizeof(buff), "%02X", + (u8) frameSS.header.sense_node); + strlcat(all_strbuff, buff, 2); /* Copying self raw data Force */ for (j = 0; j < frameSS.header.force_node; j++) { - snprintf(buff, sizeof(buff), "%04X", frameSS.force_data[j]); - strlcat(all_strbuff, buff, size); + snprintf(buff, sizeof(buff), "%04X", + frameSS.force_data[j]); + strlcat(all_strbuff, buff, 4); } + /* Copying self raw data Sense */ for (j = 0; j < frameSS.header.sense_node; j++) { - snprintf(buff, sizeof(buff), "%04X", frameSS.sense_data[j]); - strlcat(all_strbuff, buff, size); + snprintf(buff, sizeof(buff), "%04X", + frameSS.sense_data[j]); + strlcat(all_strbuff, buff, 4); } kfree(frameSS.force_data); @@ -656,66 +2491,75 @@ static ssize_t stm_fts_cmd_show(struct device *dev, struct device_attribute *att break; case 0x14: - snprintf(buff, sizeof(buff), "%02X", (u8) compData.header.force_node); - strlcat(all_strbuff, buff, size); + snprintf(buff, sizeof(buff), "%02X", + (u8) compData.header.force_node); + strlcat(all_strbuff, buff, 2); - snprintf(buff, sizeof(buff), "%02X", (u8) compData.header.sense_node); - strlcat(all_strbuff, buff, size); + snprintf(buff, sizeof(buff), "%02X", + (u8) compData.header.sense_node); + strlcat(all_strbuff, buff, 2); /* Cpying CX1 value */ snprintf(buff, sizeof(buff), "%02X", compData.cx1); - strlcat(all_strbuff, buff, size); + strlcat(all_strbuff, buff, 2); /* Copying CX2 values */ for (j = 0; j < compData.node_data_size; j++) { - snprintf(buff, sizeof(buff), "%02X", *(compData.node_data + j)); - strlcat(all_strbuff, buff, size); + snprintf(buff, sizeof(buff), "%02X", + *(compData.node_data + j)); + strlcat(all_strbuff, buff, 2); } kfree(compData.node_data); break; case 0x16: - snprintf(buff, sizeof(buff), "%02X", comData.header.force_node); - strlcat(all_strbuff, buff, size); + snprintf(buff, sizeof(buff), "%02X", + comData.header.force_node); + strlcat(all_strbuff, buff, 2); - snprintf(buff, sizeof(buff), "%02X", comData.header.sense_node); - strlcat(all_strbuff, buff, size); + snprintf(buff, sizeof(buff), "%02X", + comData.header.sense_node); + strlcat(all_strbuff, buff, 2); snprintf(buff, sizeof(buff), "%02X", comData.f_ix1); - strlcat(all_strbuff, buff, size); + strlcat(all_strbuff, buff, 2); snprintf(buff, sizeof(buff), "%02X", comData.s_ix1); - strlcat(all_strbuff, buff, size); + strlcat(all_strbuff, buff, 2); snprintf(buff, sizeof(buff), "%02X", comData.f_cx1); - strlcat(all_strbuff, buff, size); + strlcat(all_strbuff, buff, 2); snprintf(buff, sizeof(buff), "%02X", comData.s_cx1); - strlcat(all_strbuff, buff, size); + strlcat(all_strbuff, buff, 2); /* Copying IX2 Force */ for (j = 0; j < comData.header.force_node; j++) { - snprintf(buff, sizeof(buff), "%02X", comData.ix2_fm[j]); + snprintf(buff, sizeof(buff), "%02X", + comData.ix2_fm[j]); strlcat(all_strbuff, buff, size); } /* Copying IX2 Sense */ for (j = 0; j < comData.header.sense_node; j++) { - snprintf(buff, sizeof(buff), "%02X", comData.ix2_sn[j]); - strlcat(all_strbuff, buff, size); + snprintf(buff, sizeof(buff), "%02X", + comData.ix2_sn[j]); + strlcat(all_strbuff, buff, 2); } /* Copying CX2 Force */ for (j = 0; j < comData.header.force_node; j++) { - snprintf(buff, sizeof(buff), "%02X", comData.cx2_fm[j]); - strlcat(all_strbuff, buff, size); + snprintf(buff, sizeof(buff), "%02X", + comData.cx2_fm[j]); + strlcat(all_strbuff, buff, 2); } - /* Copying CX2 Sense */ + /* Copying CX2 Sense */ for (j = 0; j < comData.header.sense_node; j++) { - snprintf(buff, sizeof(buff), "%02X", comData.cx2_sn[j]); - strlcat(all_strbuff, buff, size); + snprintf(buff, sizeof(buff), "%02X", + comData.cx2_sn[j]); + strlcat(all_strbuff, buff, 2); } kfree(comData.ix2_fm); @@ -726,45 +2570,145 @@ static ssize_t stm_fts_cmd_show(struct device *dev, struct device_attribute *att default: break; - } } snprintf(buff, sizeof(buff), "%02X", 0xBB); - strlcat(all_strbuff, buff, size); + strlcat(all_strbuff, buff, 2); count = snprintf(buf, TSP_BUF_SIZE, "%s\n", all_strbuff); - numberParameters = 0; /* need to reset the number of parameters - * in order to wait the next command, comment - *if you want to repeat the last command sent - *just doing a cat - */ - /* logError(0,"%s numberParameters = %d\n", tag, numberParameters); */ + /** + * need to reset the number of parameters + * in order to wait the next command, + * comment if you want to repeat + * the last command sent just doing a cat + */ + numberParameters = 0; + /* logError(0,"%s numberParameters = %d\n",tag, numberParameters);*/ kfree(all_strbuff); - kfree(typeOfComand); return count; - } -static DEVICE_ATTR(fwupdate, (S_IRUGO | S_IWUSR | S_IWGRP), fts_sysfs_fwupdate_show, fts_fw_control_store); -static DEVICE_ATTR(appid, (S_IRUGO), fts_sysfs_config_id_show, NULL); -static DEVICE_ATTR(fw_file_test, (S_IRUGO), fts_fw_test_show, NULL); -static DEVICE_ATTR(stm_fts_cmd, (S_IRUGO | S_IWUSR | S_IWGRP), stm_fts_cmd_show, stm_fts_cmd_store); -static DEVICE_ATTR(feature_enable, (S_IRUGO | S_IWUSR | S_IWGRP), fts_feature_enable_show, fts_feature_enable_store); +static DEVICE_ATTR(fwupdate, 0664, + fts_fwupdate_show, fts_fwupdate_store); +static DEVICE_ATTR(appid, 0444, fts_sysfs_config_id_show, NULL); +static DEVICE_ATTR(mode_active, 0444, fts_mode_active_show, NULL); +static DEVICE_ATTR(lockdown_info, 0444, fts_lockdown_info_show, NULL); +static DEVICE_ATTR(strength_frame, 0664, + fts_strength_frame_show, fts_strength_frame_store); +static DEVICE_ATTR(fw_file_test, 0444, fts_fw_test_show, NULL); +static DEVICE_ATTR(stm_fts_cmd, 0664, + stm_fts_cmd_show, stm_fts_cmd_store); +#ifdef USE_ONE_FILE_NODE +static DEVICE_ATTR(feature_enable, 0664, + fts_feature_enable_show, fts_feature_enable_store); +#else + +#ifdef EDGE_REJ +static DEVICE_ATTR(edge_rej, 0664, + fts_edge_rej_show, fts_edge_rej_store); +#endif + +#ifdef CORNER_REJ +static DEVICE_ATTR(corner_rej, 0664, + fts_corner_rej_show, fts_corner_rej_store); +#endif + +#ifdef EDGE_PALM_REJ +static DEVICE_ATTR(edge_palm_rej, 0664, + fts_edge_palm_rej_show, fts_edge_palm_rej_store); +#endif + +#ifdef CHARGER_MODE +static DEVICE_ATTR(charger_mode, 0664, + fts_charger_mode_show, fts_charger_mode_store); +#endif + +#ifdef GLOVE_MODE +static DEVICE_ATTR(glove_mode, 0664, + fts_glove_mode_show, fts_glove_mode_store); +#endif + +#ifdef VR_MODE +static DEVICE_ATTR(vr_mode, 0664, + fts_vr_mode_show, fts_vr_mode_store); +#endif + +#ifdef COVER_MODE +static DEVICE_ATTR(cover_mode, 0664, + fts_cover_mode_show, fts_cover_mode_store); +#endif + +#ifdef STYLUS_MODE +static DEVICE_ATTR(stylus_mode, 0664, + fts_stylus_mode_show, fts_stylus_mode_store); +#endif + +#endif + #ifdef PHONE_GESTURE -static DEVICE_ATTR(gesture_mask, (S_IRUGO | S_IWUSR | S_IWGRP), fts_gesture_mask_show, fts_gesture_mask_store); +static DEVICE_ATTR(gesture_mask, 0664, + fts_gesture_mask_show, fts_gesture_mask_store); +static DEVICE_ATTR(gesture_coordinates, 0664, + fts_gesture_coordinates_show, NULL); +#ifdef USE_CUSTOM_GESTURES +static DEVICE_ATTR(add_custom_gesture, 0664, + fts_custom_gesture_result_show, fts_add_custom_gesture_store); +static DEVICE_ATTR(remove_custom_gesture, 0664, + fts_custom_gesture_result_show, + fts_remove_custom_gesture_store); #endif -/* /sys/devices/soc.0/f9928000.i2c/i2c-6/6-0049 */ +#endif + +/* /sys/devices/soc.0/f9928000.i2c/i2c-6/6-0049 */ static struct attribute *fts_attr_group[] = { &dev_attr_fwupdate.attr, &dev_attr_appid.attr, + &dev_attr_mode_active.attr, + &dev_attr_lockdown_info.attr, + &dev_attr_strength_frame.attr, &dev_attr_fw_file_test.attr, - /* &dev_attr_touch_debug.attr, */ &dev_attr_stm_fts_cmd.attr, +#ifdef USE_ONE_FILE_NODE &dev_attr_feature_enable.attr, +#else + +#ifdef EDGE_REJ + &dev_attr_edge_rej.attr, +#endif +#ifdef CORNER_REJ + &dev_attr_corner_rej.attr, +#endif +#ifdef EDGE_PALM_REJ + &dev_attr_edge_palm_rej.attr, +#endif +#ifdef CHARGER_MODE + &dev_attr_charger_mode.attr, +#endif +#ifdef GLOVE_MODE + &dev_attr_glove_mode.attr, +#endif +#ifdef VR_MODE + &dev_attr_vr_mode.attr, +#endif +#ifdef COVER_MODE + &dev_attr_cover_mode.attr, +#endif +#ifdef STYLUS_MODE + &dev_attr_stylus_mode.attr, +#endif + +#endif + #ifdef PHONE_GESTURE &dev_attr_gesture_mask.attr, + &dev_attr_gesture_coordinates.attr, +#ifdef USE_CUSTOM_GESTURES + &dev_attr_add_custom_gesture.attr, + &dev_attr_remove_custom_gesture.attr, +#endif + #endif NULL, }; @@ -776,13 +2720,14 @@ static int fts_command(struct fts_ts_info *info, unsigned char cmd) regAdd = cmd; - ret = fts_writeCmd(®Add, sizeof (regAdd)); /* 0 = ok */ + ret = fts_writeCmd(®Add, sizeof(regAdd)); /* 0 = ok */ logError(0, "%s Issued command 0x%02x, return value %08X\n", cmd, ret); return ret; } + void fts_input_report_key(struct fts_ts_info *info, int key_code) { mutex_lock(&info->input_report_mutex); @@ -793,10 +2738,10 @@ void fts_input_report_key(struct fts_ts_info *info, int key_code) mutex_unlock(&info->input_report_mutex); } + /* * New Interrupt handle implementation */ - static inline unsigned char *fts_next_event(unsigned char *evt) { /* Nothing to do with this event, moving to the next one */ @@ -807,25 +2752,38 @@ static inline unsigned char *fts_next_event(unsigned char *evt) } /* EventId : 0x00 */ -static unsigned char *fts_nop_event_handler(struct fts_ts_info *info, - unsigned char *event) { - /* logError(1, "%s %s Doing nothing for event = %02X %02X %02X %02X %02X %02X %02X %02X\n", - * tag, __func__, event[0], event[1], event[2], event[3], event[4], event[5], event[6], event[7]); - */ - return fts_next_event(event); +static void fts_nop_event_handler(struct fts_ts_info *info, + unsigned char *event) +{ + /** + * logError(1, + * "%s %s Doing nothing for event = + * %02X %02X %02X %02X %02X %02X %02X %02X\n", + * tag, __func__, event[0], event[1], event[2], + * event[3], event[4], event[5], event[6], event[7]); + */ + /* return fts_next_event(event); */ } /* EventId : 0x03 */ -static unsigned char *fts_enter_pointer_event_handler(struct fts_ts_info *info, - unsigned char *event) { +static void fts_enter_pointer_event_handler(struct fts_ts_info *info, + unsigned char *event) +{ unsigned char touchId, touchcount; int x, y, z; + int minor; + int major, distance; + u8 touchsize; + distance = 0; if (!info->resume_bit) goto no_report; touchId = event[1] & 0x0F; touchcount = (event[1] & 0xF0) >> 4; + touchsize = (event[5] & 0xC0) >> 6; + major = (event[5] & 0x1F); // bit0-bit4: major + minor = event[6]; // event6:minor __set_bit(touchId, &info->touch_id); @@ -840,46 +2798,92 @@ static unsigned char *fts_enter_pointer_event_handler(struct fts_ts_info *info, y--; input_mt_slot(info->input_dev, touchId); +/*#ifdef STYLUS_MODE*/ + /** + * TODO: check with ST how FW report a + * stylus touch in the touch event, + * this is an example code + */ + /*if (info->stylus_enabled == 1 && touchsize == STYLUS_SIZE) {*/ + /*__set_bit(touchId, &info->stylus_id);*/ + /*input_mt_report_slot_state(info->input_dev, MT_TOOL_PEN, 1);*/ + /*logError(0, "%s %s : It is a stylus!\n",tag,__func__); */ + /*} else*/ + /*input_mt_report_slot_state(info->input_dev, MT_TOOL_FINGER, 1);*/ +/*#else*/ + /*input_mt_report_slot_state(info->input_dev, MT_TOOL_FINGER, 1);*/ +/*#endif*/ input_mt_report_slot_state(info->input_dev, MT_TOOL_FINGER, 1); - logError(0, "%s %s : TouchID = %d,Touchcount = %d\n", tag, __func__, touchId, touchcount); - if (touchcount == 1) { - input_report_key(info->input_dev, BTN_TOUCH, 1); - input_report_key(info->input_dev, BTN_TOOL_FINGER, 1); - } - /* input_report_abs(info->input_dev, ABS_MT_TRACKING_ID, touchId); */ + /*logError(0,*/ + /*"%s %s:TouchID = %d, Touchcount = %d, minor:%d, major:%d\n",*/ + /*tag, __func__, touchId, touchcount, minor, major);*/ + /*logError(0,*/ + /*"%s %s : TouchID = %d,Touchcount = %d\n",*/ + /*tag, __func__, touchId,touchcount);*/ + /*if (touchcount == 1) {*/ + input_report_key(info->input_dev, BTN_TOUCH, 1); + input_report_key(info->input_dev, BTN_TOOL_FINGER, 1); + /*}*/ + /* input_report_abs(info->input_dev, ABS_MT_TRACKING_ID, touchId);*/ input_report_abs(info->input_dev, ABS_MT_POSITION_X, x); input_report_abs(info->input_dev, ABS_MT_POSITION_Y, y); - input_report_abs(info->input_dev, ABS_MT_TOUCH_MAJOR, z); - input_report_abs(info->input_dev, ABS_MT_TOUCH_MINOR, z); - input_report_abs(info->input_dev, ABS_MT_PRESSURE, z); - logError(0, "%s %s : Event 0x%02x - ID[%d], (x, y, z) = (%3d, %3d, %3d)\n", tag, __func__, *event, touchId, x, y, z); + /*input_report_abs(info->input_dev, ABS_MT_TOUCH_MAJOR, z);*/ + /*input_report_abs(info->input_dev, ABS_MT_TOUCH_MINOR, z);*/ + /*input_report_abs(info->input_dev, ABS_MT_PRESSURE, z);*/ + input_report_abs(info->input_dev, ABS_MT_TOUCH_MAJOR, major); + input_report_abs(info->input_dev, ABS_MT_TOUCH_MINOR, minor); + input_report_abs(info->input_dev, ABS_MT_DISTANCE, distance); + /*logError(0,*/ + /*"%s%s:Event 0x%02x - ID[%d], (x, y, z) = (%3d, %3d, %3d)\n",*/ + /*tag, __func__, *event, touchId, x, y, z);*/ no_report: - return fts_next_event(event); + return; + /* return fts_next_event(event); */ } /* EventId : 0x04 */ -static unsigned char *fts_leave_pointer_event_handler(struct fts_ts_info *info, - unsigned char *event) { +static void fts_leave_pointer_event_handler(struct fts_ts_info *info, + unsigned char *event) +{ unsigned char touchId, touchcount; + u8 touchsize; touchId = event[1] & 0x0F; touchcount = (event[1] & 0xF0) >> 4; + touchsize = (event[5] & 0xC0) >> 6; __clear_bit(touchId, &info->touch_id); input_mt_slot(info->input_dev, touchId); +/*#ifdef STYLUS_MODE*/ + /** + * TODO: check with ST how FW report a stylus touch + * in the touch event, this is an example code + */ + /*if (info->stylus_enabled == 1 && touchsize == STYLUS_SIZE) {*/ + /* __clear_bit(touchId, &info->stylus_id);*/ + /* input_mt_report_slot_state(info->input_dev, MT_TOOL_PEN, 0);*/ + /*logError(0, "%s %s : It is a stylus!\n",tag,__func__);*/ + /*} else*/ + /*input_mt_report_slot_state(info->input_dev, MT_TOOL_FINGER, 0);*/ +/*#else*/ + /*input_mt_report_slot_state(info->input_dev, MT_TOOL_FINGER, 0);*/ +/*#endif*/ input_mt_report_slot_state(info->input_dev, MT_TOOL_FINGER, 0); - logError(0, "%s %s : TouchID = %d, Touchcount = %d\n", tag, __func__, touchId, touchcount); - if (touchcount == 0) { - input_report_key(info->input_dev, BTN_TOUCH, 0); - input_report_key(info->input_dev, BTN_TOOL_FINGER, 0); - } + /* input_mt_report_slot_state(info->input_dev, MT_TOOL_FINGER, 0);*/ + /*logError(0, "%s %s : TouchID = %d, Touchcount = %d\n",*/ + /*tag,__func__,touchId,touchcount);*/ + /*if (touchcount == 0) {*/ + input_report_key(info->input_dev, BTN_TOUCH, 0); + input_report_key(info->input_dev, BTN_TOOL_FINGER, 0); + /*}*/ input_report_abs(info->input_dev, ABS_MT_TRACKING_ID, -1); - logError(0, "%s %s : Event 0x%02x - release ID[%d]\n", tag, __func__, event[0], touchId); + /*logError(0, "%s %s : Event 0x%02x - release ID[%d]\n",*/ + /*tag, __func__, event[0], touchId);*/ - return fts_next_event(event); + /*return fts_next_event(event);*/ } /* EventId : 0x05 */ @@ -887,16 +2891,26 @@ static unsigned char *fts_leave_pointer_event_handler(struct fts_ts_info *info, #ifdef PHONE_KEY /* EventId : 0x0E */ -static unsigned char *fts_key_status_event_handler(struct fts_ts_info *info, unsigned char *event) +static void fts_key_status_event_handler(struct fts_ts_info *info, + unsigned char *event) { int value; - logError(0, "%s %s Received event %02X %02X %02X %02X %02X %02X %02X %02X\n", tag, __func__, event[0], event[1], event[2], event[3], event[4], event[5], event[6], event[7]); - /* TODO: the customer should handle the events coming from the keys according his needs (this is an example that report only the single pressure of one key at time) */ - if (event[2] != 0) { /* event[2] contain the bitmask of the keys that are actually pressed */ + + logError(0, + "%s %sReceived event %02X %02X %02X %02X %02X %02X %02X %02X\n", + tag, __func__, event[0], event[1], event[2], event[3], + event[4], event[5], event[6], event[7]); + /** + * TODO: the customer should handle the events coming + * from the keys according his needs (this is an example + * that report only the single pressure of one key at time) + */ + /* event[2] contain the bitmask of the keys that are actually pressed */ + if (event[2] != 0) { switch (event[2]) { case KEY1: value = KEY_HOMEPAGE; - logError(0, "%s %s: Button HOME !\n", tag, __func__); + logError(0, "%s %s: Button HOME!\n", tag, __func__); break; case KEY2: @@ -910,88 +2924,93 @@ static unsigned char *fts_key_status_event_handler(struct fts_ts_info *info, uns break; default: - logError(0, "%s %s: No valid Button ID or more than one key pressed!\n", tag, __func__); - goto done; + logError(0, + "%s %s:No valid Button ID or more than one key pressed!\n", + tag, __func__); + //goto done; + return; } - fts_input_report_key(info, value); - } else{ + fts_input_report_key(info, value); + } else { logError(0, "%s %s: All buttons released!\n", tag, __func__); } -done: - return fts_next_event(event); +//done: + /* return fts_next_event(event); */ + //return; } #endif /* EventId : 0x0F */ -static unsigned char *fts_error_event_handler(struct fts_ts_info *info, - unsigned char *event) { - int error = 0, i = 0; - logError(0, "%s %s Received event 0x%02x 0x%02x\n", tag, __func__, event[0], event[1]); +static void fts_error_event_handler(struct fts_ts_info *info, + unsigned char *event) +{ + int error = 0; + + logError(0, + "%s %sReceived event:%02X %02X %02X %02X %02X %02X %02X %02X\n", + tag, __func__, event[0], event[1], event[2], event[3], + event[4], event[5], event[6], event[7]); switch (event[1]) { - case EVENT_TYPE_ESD_ERROR: - { - for (i = 0; i < TOUCH_ID_MAX; i++) { - input_mt_slot(info->input_dev, i); - input_mt_report_slot_state(info->input_dev, (i < FINGER_MAX) ? MT_TOOL_FINGER : MT_TOOL_PEN, 0); - } - input_sync(info->input_dev); + case EVENT_TYPE_ESD_ERROR: /* esd */ + /* before reset clear all slot */ + release_all_touches(info); fts_chip_powercycle(info); - error = fts_system_reset(); - error |= fts_mode_handler(info, 0); - error |= fts_enableInterrupt(); + error = fts_system_reset(); + error |= fts_mode_handler(info, 0); + error |= fts_enableInterrupt(); if (error < OK) { - logError(1, "%s %s Cannot restore the device ERROR %08X\n", tag, __func__, error); + logError(1, + "%s %s Cannot restore the device ERROR %08X\n", + tag, __func__, error); } - } - break; - case EVENT_TYPE_WATCHDOG_ERROR: /* watch dog timer */ - { - if (event[2] == 0) { - /* before reset clear all slot */ - for (i = 0; i < TOUCH_ID_MAX; i++) { - input_mt_slot(info->input_dev, i); - input_mt_report_slot_state(info->input_dev, - (i < FINGER_MAX) ? MT_TOOL_FINGER : MT_TOOL_PEN, 0); - } - input_sync(info->input_dev); - error = fts_system_reset(); - error |= fts_mode_handler(info, 0); - error |= fts_enableInterrupt(); - if (error < OK) { - logError(1, "%s %s Cannot reset the device ERROR %08X\n", tag, __func__, error); - } + break; + case EVENT_TYPE_WATCHDOG_ERROR: /*watch dog timer*/ + /*if (event[2] == 0) { */ + dumpErrorInfo(); + /*before reset clear all slot */ + release_all_touches(info); + error = fts_system_reset(); + error |= fts_mode_handler(info, 0); + error |= fts_enableInterrupt(); + if (error < OK) { + logError(1, + "%s %s Cannot reset the device ERROR %08X\n", + tag, __func__, error); } - } - break; - - } - return fts_next_event(event); + /* } */ + break; +} + /* return fts_next_event(event); */ } /* EventId : 0x10 */ -static unsigned char *fts_controller_ready_event_handler( - struct fts_ts_info *info, unsigned char *event) { +static void fts_controller_ready_event_handler(struct fts_ts_info *info, + unsigned char *event) +{ int error; + logError(0, "%s %s Received event 0x%02x\n", tag, __func__, event[0]); - info->touch_id = 0; - input_sync(info->input_dev); + release_all_touches(info); setSystemResettedUp(1); setSystemResettedDown(1); error = fts_mode_handler(info, 0); if (error < OK) { - logError(1, "%s %s Cannot restore the device status ERROR %08X\n", tag, __func__, error); + logError(1, + "%s %s Cannot restore the device status ERROR %08X\n", + tag, __func__, error); } - return fts_next_event(event); + /* return fts_next_event(event); */ } /* EventId : 0x16 */ -static unsigned char *fts_status_event_handler( - struct fts_ts_info *info, unsigned char *event) { - /* logError(1, "%s Received event 0x%02x\n", tag, event[0]); */ +static void fts_status_event_handler(struct fts_ts_info *info, + unsigned char *event) +{ + /*logError(1, "%s Received event 0x%02x\n", tag, event[0]);*/ switch (event[1]) { case EVENT_TYPE_MS_TUNING_CMPL: @@ -1003,61 +3022,77 @@ static unsigned char *fts_status_event_handler( case FTS_WATER_MODE_ON: case FTS_WATER_MODE_OFF: default: - logError(0, - "%s %s Received unhandled status event = %02X %02X %02X %02X %02X %02X %02X %02X\n", - tag, __func__, event[0], event[1], event[2], - event[3], event[4], event[5], event[6], event[7]); - break; + logError(1, "%s %s Received unhandled status event = ", + tag, __func__); + logError(1, "%02X %02X %02X %02X %02X %02X %02X %02X\n", + event[0], event[1], event[2], event[3], event[4], + event[5], event[6], event[7]); + break; } - return fts_next_event(event); + /* return fts_next_event(event); */ } #ifdef PHONE_GESTURE -static unsigned char *fts_gesture_event_handler(struct fts_ts_info *info, unsigned char *event) +/** + * TODO: Customer should implement their own action + * in respons of a gesture event. + * This is an example that simply print the gesture received + */ +static void fts_gesture_event_handler(struct fts_ts_info *info, + unsigned char *event) { unsigned char touchId; int value; + int needCoords = 0; - logError(0, "%s gesture event data: %02X %02X %02X %02X %02X %02X %02X %02X\n", tag, event[0], event[1], event[2], event[3], event[4], event[5], event[6], event[7]); + logError(0, + "%s gesture event: %02X %02X %02X %02X %02X %02X %02X %02X\n", + tag, event[0], event[1], event[2], event[3], + event[4], event[5], event[6], event[7]); if (event[1] == 0x03) { - - logError(1, "%s %s: Gesture ID %02X enable_status = %02X\n", tag, __func__, event[2], event[3]); - + logError(1, "%s %s: Gesture ID %02X enable_status = %02X\n", + tag, __func__, event[2], event[3]); } + if (event[1] == EVENT_TYPE_ENB && event[2] == 0x00) { switch (event[3]) { case GESTURE_ENABLE: - logError(1, "%s %s: Gesture Enabled! res = %02X\n", tag, __func__, event[4]); + logError(1, "%s %s: Gesture Enabled! res = %02X\n", + tag, __func__, event[4]); break; case GESTURE_DISABLE: - logError(1, "%s %s: Gesture Disabled! res = %02X\n", tag, __func__, event[4]); + logError(1, "%s %s: Gesture Disabled! res = %02X\n", + tag, __func__, event[4]); break; default: - logError(1, "%s %s: Event not Valid!\n", tag, __func__); - + logError(1, "%s %s: Event not Valid!\n", tag, __func__); } - } - /* always use touchId zero */ - touchId = 0; - __set_bit(touchId, &info->touch_id); + if (event[0] == EVENTID_GESTURE && (event[1] == EVENT_TYPE_GESTURE_DTC1 + || event[1] == EVENT_TYPE_GESTURE_DTC2)) { + /* always use touchId zero */ + touchId = 0; + __set_bit(touchId, &info->touch_id); - if (event[0] == EVENTID_GESTURE && (event[1] == EVENT_TYPE_GESTURE_DTC1 || event[1] == EVENT_TYPE_GESTURE_DTC2)) { + /* by default read the coordinates*/ + /* for all gestures excluding double tap */ + needCoords = 1; switch (event[2]) { case GES_ID_DBLTAP: value = KEY_WAKEUP; - logError(0, "%s %s: double tap !\n", tag, __func__); + logError(0, "%s %s: double tap!\n", tag, __func__); + needCoords = 0; break; case GES_ID_AT: value = KEY_WWW; - logError(0, "%s %s: @ !\n", tag, __func__); + logError(0, "%s %s: @!\n", tag, __func__); break; case GES_ID_C: @@ -1068,7 +3103,7 @@ static unsigned char *fts_gesture_event_handler(struct fts_ts_info *info, unsign case GES_ID_E: value = KEY_E; logError(0, "%s %s: e !\n", tag, __func__); - break; + break; case GES_ID_F: value = KEY_F; @@ -1165,19 +3200,25 @@ static unsigned char *fts_gesture_event_handler(struct fts_ts_info *info, unsign logError(0, "%s %s: > !\n", tag, __func__); break; default: - logError(0, "%s %s: No valid GestureID!\n", tag, __func__); + logError(0, "%s %s: No valid GestureID!\n", + tag, __func__); goto gesture_done; - } + /*no coordinates for gestures reported by FW */ + if (event[1] == EVENT_TYPE_GESTURE_DTC1) + needCoords = 0; + + if (needCoords == 1) + readGestureCoords(event); + fts_input_report_key(info, value); - gesture_done: +gesture_done: /* Done with gesture event, clear bit. */ __clear_bit(touchId, &info->touch_id); } - - return fts_next_event(event); + /* return fts_next_event(event); */ } #endif @@ -1191,109 +3232,131 @@ static unsigned char *fts_gesture_event_handler(struct fts_ts_info *info, unsign static void fts_event_handler(struct work_struct *work) { struct fts_ts_info *info; - int error, error1; - int left_events; + int error = 0, count = 0; unsigned char regAdd; - unsigned char data[FIFO_EVENT_SIZE * (FIFO_DEPTH)] = {0}; - unsigned char *event = NULL; + unsigned char data[FIFO_EVENT_SIZE] = {0}; unsigned char eventId; + event_dispatch_handler_t event_handler; info = container_of(work, struct fts_ts_info, work); /* - * to avoid reading all FIFO, we read the first event and - * then check how many events left in the FIFO + * read all the FIFO and parsing events */ - + /*wake_lock_timeout(&info->wakelock, HZ); */ + __pm_wakeup_event(&info->wakeup_source, HZ); + /*logError(1, "%s %s: begin\n", tag, __func__);*/ regAdd = FIFO_CMD_READONE; - error = fts_readCmd(®Add, - sizeof (regAdd), data, FIFO_EVENT_SIZE); - - if (!error) { - left_events = data[7] & 0x1F; - if ((left_events > 0) && (left_events < FIFO_DEPTH)) { - /* - * Read remaining events. - */ - regAdd = FIFO_CMD_READALL; - - error1 = fts_readCmd(®Add, sizeof (regAdd), - &data[FIFO_EVENT_SIZE], - left_events * FIFO_EVENT_SIZE); - /* - * Got an error reading remaining events, - * process at least * the first one that was - * reading fine. - */ - if (error1) - data[7] &= 0xE0; - } + for (count = 0; count < FIFO_DEPTH; count++) { + error = fts_readCmd(®Add, sizeof(regAdd), data, + FIFO_EVENT_SIZE); + if (error == OK && data[0] != EVENTID_NO_EVENT) + eventId = data[0]; + else + break; + /* if(data[7]&0x20) */ + /* logError(1, "%s %s overflow ID = %02X Last = %02X\n",*/ + /* tag, __func__, data[0], data[7]);*/ - /* At least one event is available */ - event = data; - do { - eventId = *event; + if (eventId < EVENTID_LAST) { event_handler = info->event_dispatch_table[eventId]; - - if (eventId < EVENTID_LAST) { - event = event_handler(info, (event)); - } else { - event = fts_next_event(event); - } - input_sync(info->input_dev); - } while (event); + event_handler(info, (data)); + } } + input_sync(info->input_dev); - /* - * re-enable interrupts - */ + /*re-enable interrupts */ fts_interrupt_enable(info); } static int cx_crc_check(void) { - unsigned char regAdd1[3] = {FTS_CMD_HW_REG_R, ADDR_CRC_BYTE0, ADDR_CRC_BYTE1}; - unsigned char val = 0; + unsigned char regAdd1[3] = {FTS_CMD_HW_REG_R, ADDR_CRC_BYTE0, + ADDR_CRC_BYTE1}; + unsigned char val[2]; unsigned char crc_status; - unsigned int error; - - error = fts_readCmd(regAdd1, sizeof (regAdd1), &val, 1); - if (error < OK) { - logError(1, "%s %s Cannot read crc status ERROR %08X\n", tag, __func__, error); - return error; + int res; +#ifndef FTM3_CHIP + u8 cmd[4] = { FTS_CMD_HW_REG_W, 0x00, 0x00, SYSTEM_RESET_VALUE }; + int event_to_search[2] = {(int)EVENTID_ERROR_EVENT, + (int)EVENT_TYPE_CHECKSUM_ERROR}; + u8 readData[FIFO_EVENT_SIZE]; +#endif + /*read 2 bytes because the first one is a dummy byte!*/ + res = fts_readCmd(regAdd1, sizeof(regAdd1), val, 2); + if (res < OK) { + logError(1, "%s %s Cannot read crc status ERROR %08X\n", + tag, __func__, res); + return res; } - crc_status = val & CRC_MASK; - if (crc_status != OK) { /* CRC error if crc_status!= 0 */ - logError(1, "%s %s CRC ERROR = %X\n", tag, __func__, crc_status); + crc_status = val[1] & CRC_MASK; + if (crc_status != OK) { + logError(1, "%s %s CRC ERROR = %X\n", + tag, __func__, crc_status); + return crc_status; } - return crc_status; /* return OK if no CRC error, or a number >OK if crc error */ +#ifndef FTM3_CHIP + logError(1, "%s %s: Verifying if Config CRC Error...\n", tag, __func__); + u16ToU8_be(SYSTEM_RESET_ADDRESS, &cmd[1]); + res = fts_writeCmd(cmd, 4); + if (res < OK) { + logError(1, "%s %s Cannot send system resest command:%08X\n", + tag, __func__, res); + return res; + } + setSystemResettedDown(1); + setSystemResettedUp(1); + res = pollForEvent(event_to_search, 2, readData, GENERAL_TIMEOUT); + if (res < OK) { + logError(1, "%s %s: No Config CRC Found!\n", tag, __func__); + } else { + if (readData[2] == CRC_CONFIG_SIGNATURE || + readData[2] == CRC_CONFIG) { + logError(1, "%s:%s: CRC Error for config found! %02X\n", + tag, __func__, readData[2]); + return readData[2]; + } + } +#endif + /*return OK if no CRC error, or a number >OK if crc error*/ + return OK; } static void fts_fw_update_auto(struct work_struct *work) { +#ifndef FTM3_CHIP + u8 cmd[4] = { FTS_CMD_HW_REG_W, 0x00, 0x00, SYSTEM_RESET_VALUE }; + int event_to_search[2] = {(int)EVENTID_ERROR_EVENT, + (int)EVENT_TYPE_CHECKSUM_ERROR}; + u8 readData[FIFO_EVENT_SIZE]; + int flag_init = 0; +#endif int retval = 0; int retval1 = 0; int ret; struct fts_ts_info *info; - struct delayed_work *fwu_work = container_of(work, struct delayed_work, work); + struct delayed_work *fwu_work = container_of(work, + struct delayed_work, work); int crc_status = 0; int error = 0; - info = container_of(fwu_work, struct fts_ts_info, fwu_work); - logError(1, "%s Fw Auto Update is starting...\n", tag); + info = container_of(fwu_work, struct fts_ts_info, fwu_work); + logError(1, "%s Fw Auto Update is starting...\n", tag); /* check CRC status */ ret = cx_crc_check(); if (ret > OK && ftsInfo.u16_fwVer == 0x0000) { - logError(1, "%s %s: CRC Error or NO FW!\n", tag, __func__); + logError(1, "%s %s: CRC Error or NO FW!\n", tag, __func__); crc_status = 1; } else { crc_status = 0; - logError(1, "%s %s: NO CRC Error or Impossible to read CRC register!\n", tag, __func__); + logError(1, + "%s %s:NO Error or Impossible to read CRC register!\n", + tag, __func__); } #ifdef FTM3_CHIP retval = flashProcedure(PATH_FILE_FW, crc_status, !crc_status); @@ -1301,7 +3364,9 @@ static void fts_fw_update_auto(struct work_struct *work) retval = flashProcedure(PATH_FILE_FW, crc_status, 1); #endif if ((retval & 0xFF000000) == ERROR_FLASH_PROCEDURE) { - logError(1, "%s %s: firmware update failed and retry! ERROR %08X\n", tag, __func__, retval); + logError(1, + "%s %s:firmware update failed and retry! ERROR %08X\n", + tag, __func__, retval); fts_chip_powercycle(info); /* power reset */ #ifdef FTM3_CHIP retval1 = flashProcedure(PATH_FILE_FW, crc_status, !crc_status); @@ -1309,29 +3374,72 @@ static void fts_fw_update_auto(struct work_struct *work) retval1 = flashProcedure(PATH_FILE_FW, crc_status, 1); #endif if ((retval1 & 0xFF000000) == ERROR_FLASH_PROCEDURE) { - logError(1, "%s %s: firmware update failed again! ERROR %08X\n", tag, __func__, retval1); - logError(1, "%s Fw Auto Update Failed!\n", tag); + logError(1, + "%s %s: firmware update failed again! %08X\n", + tag, __func__, retval1); + logError(1, "%s Fw Auto Update Failed!\n", tag); /* return; */ } } +#ifndef FTM3_CHIP + logError(1, "%s %s: Verifying if CX CRC Error...\n", + tag, __func__, ret); + u16ToU8_be(SYSTEM_RESET_ADDRESS, &cmd[1]); + ret = fts_writeCmd(cmd, 4); + if (ret < OK) { + logError(1, + "%s %s Cannot send system reset command ERROR %08X\n", + tag, __func__, ret); + } else { + setSystemResettedDown(1); + setSystemResettedUp(1); + ret = pollForEvent(event_to_search, 2, readData, + GENERAL_TIMEOUT); + if (ret < OK) { + logError(1, "%s %s: No CX CRC Found!\n", tag, __func__); + } else { + if (readData[2] == CRC_CX_MEMORY) { + logError(1, "%s %s: CRC Error for CX found! ", + tag, __func__); + logError(1, "ERROR:%02X\n\n", readData[2]); + flag_init = 1; + } + } + } +#endif - if ((ftsInfo.u32_mpPassFlag != INIT_MP) && (ftsInfo.u32_mpPassFlag != INIT_FIELD)) + if (ftsInfo.u8_msScrConfigTuneVer != ftsInfo.u8_msScrCxmemTuneVer || + ftsInfo.u8_ssTchConfigTuneVer != ftsInfo.u8_ssTchCxmemTuneVer) + ret = ERROR_GET_INIT_STATUS; + else if (((ftsInfo.u32_mpPassFlag != INIT_MP) + && (ftsInfo.u32_mpPassFlag != INIT_FIELD)) +#ifndef FTM3_CHIP + || flag_init == 1 +#endif + ) ret = ERROR_GET_INIT_STATUS; else ret = OK; - - if (ret == ERROR_GET_INIT_STATUS) { /* initialization status not correct or after FW complete update, do initialization. */ + /** + * initialization status not correct or + * after FW complete update, do initialization. + */ + if (ret == ERROR_GET_INIT_STATUS) { error = fts_chip_initialization(info); if (error < OK) { - logError(1, "%s %s Cannot initialize the chip ERROR %08X\n", tag, __func__, error); + logError(1, + "%s %s Cannot initialize the chip ERROR %08X\n", + tag, __func__, error); } } - error = fts_init_hw(info); - if (error < OK) { - logError(1, "%s Cannot initialize the hardware device ERROR %08X\n", tag, error); - } - logError(1, "%s Fw Auto Update Finished!\n", tag); + error = fts_init_afterProbe(info); + if (error < OK) { + logError(1, + "%s Cannot initialize the hardware device ERROR %08X\n", + tag, error); + } + logError(1, "%s Fw Auto Update Finished!\n", tag); } static int fts_chip_initialization(struct fts_ts_info *info) @@ -1339,23 +3447,62 @@ static int fts_chip_initialization(struct fts_ts_info *info) int ret2 = 0; int retry; int initretrycnt = 0; + struct TestToDo todoDefault; + + todoDefault.MutualRaw = 1; + todoDefault.MutualRawGap = 1; + todoDefault.MutualCx1 = 0; + todoDefault.MutualCx2 = 1; + todoDefault.MutualCx2Adj = 1; + todoDefault.MutualCxTotal = 0; + todoDefault.MutualCxTotalAdj = 0; + + todoDefault.MutualKeyRaw = 0; + todoDefault.MutualKeyCx1 = 0; + todoDefault.MutualKeyCx2 = 0; + todoDefault.MutualKeyCxTotal = 0; + + todoDefault.SelfForceRaw = 1; + todoDefault.SelfForceRawGap = 0; + todoDefault.SelfForceIx1 = 0; + todoDefault.SelfForceIx2 = 0; + todoDefault.SelfForceIx2Adj = 0; + todoDefault.SelfForceIxTotal = 1; + todoDefault.SelfForceIxTotalAdj = 0; + todoDefault.SelfForceCx1 = 0; + todoDefault.SelfForceCx2 = 0; + todoDefault.SelfForceCx2Adj = 0; + todoDefault.SelfForceCxTotal = 0; + todoDefault.SelfForceCxTotalAdj = 0; + + todoDefault.SelfSenseRaw = 1; + todoDefault.SelfSenseRawGap = 0; + todoDefault.SelfSenseIx1 = 0; + todoDefault.SelfSenseIx2 = 0; + todoDefault.SelfSenseIx2Adj = 0; + todoDefault.SelfSenseIxTotal = 1; + todoDefault.SelfSenseIxTotalAdj = 0; + todoDefault.SelfSenseCx1 = 0; + todoDefault.SelfSenseCx2 = 0; + todoDefault.SelfSenseCx2Adj = 0; + todoDefault.SelfSenseCxTotal = 0; + todoDefault.SelfSenseCxTotalAdj = 0; - /* initialization error, retry initialization */ + /*initialization error, retry initialization */ for (retry = 0; retry <= INIT_FLAG_CNT; retry++) { - ret2 = production_test_initialization(); - if (ret2 == OK) { - ret2 = save_mp_flag(INIT_FIELD); + ret2 = production_test_main(LIMITS_FILE, 1, 1, &todoDefault, + INIT_FIELD); if (ret2 == OK) break; - } initretrycnt++; - logError(1, "%s initialization cycle count = %04d - ERROR %08X\n", tag, initretrycnt, ret2); - fts_chip_powercycle(info); - } - if (ret2 < OK) { /* initialization error */ - logError(1, "%s fts initialization failed 3 times\n", tag); + logError(1, + "%s initialization cycle count = %04d - ERROR %08X\n", + tag, initretrycnt, ret2); + fts_chip_powercycle(info); } - + /* initialization error */ + if (ret2 < OK) + logError(1, "%s fts initialization failed 3 times\n", tag); return ret2; } @@ -1364,7 +3511,7 @@ static int fts_chip_initialization(struct fts_ts_info *info) static enum hrtimer_restart fts_timer_func(struct hrtimer *timer) { struct fts_ts_info *info = - container_of(timer, struct fts_ts_info, timer); + container_of(timer, struct fts_ts_info, timer); queue_work(info->event_wq, &info->work); return HRTIMER_NORESTART; @@ -1374,8 +3521,11 @@ static enum hrtimer_restart fts_timer_func(struct hrtimer *timer) static irqreturn_t fts_interrupt_handler(int irq, void *handle) { struct fts_ts_info *info = handle; + disable_irq_nosync(info->client->irq); + queue_work(info->event_wq, &info->work); + return IRQ_HANDLED; } #endif @@ -1384,17 +3534,16 @@ static int fts_interrupt_install(struct fts_ts_info *info) { int i, error = 0; - info->event_dispatch_table = kzalloc( - sizeof (event_dispatch_handler_t) * EVENTID_LAST, GFP_KERNEL); + info->event_dispatch_table = kzalloc(sizeof(event_dispatch_handler_t) + * EVENTID_LAST, GFP_KERNEL); if (!info->event_dispatch_table) { - logError(1, "%s OOM allocating event dispatch table\n", tag); + logError(1, "%s OOM allocating event dispatch table\n", tag); return -ENOMEM; } for (i = 0; i < EVENTID_LAST; i++) info->event_dispatch_table[i] = fts_nop_event_handler; - install_handler(info, ENTER_POINTER, enter_pointer); install_handler(info, LEAVE_POINTER, leave_pointer); install_handler(info, MOTION_POINTER, motion_pointer); @@ -1407,28 +3556,25 @@ static int fts_interrupt_install(struct fts_ts_info *info) #ifdef PHONE_KEY install_handler(info, KEY_STATUS, key_status); #endif - /* disable interrupts in any case */ error = fts_disableInterrupt(); #ifdef FTS_USE_POLLING_MODE - logError(1, "%s Polling Mode\n"); + logError(1, "%s Polling Mode\n"); hrtimer_init(&info->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); info->timer.function = fts_timer_func; hrtimer_start(&info->timer, ktime_set(1, 0), HRTIMER_MODE_REL); #else - logError(1, "%s Interrupt Mode\n", tag); + logError(1, "%s Interrupt Mode\n", tag); if (request_irq(info->client->irq, fts_interrupt_handler, - IRQF_TRIGGER_LOW, info->client->name, - info)) { - logError(1, "%s Request irq failed\n", tag); + IRQF_TRIGGER_LOW, info->client->name, info)) { + logError(1, "%s Request irq failed\n", tag); kfree(info->event_dispatch_table); error = -EBUSY; - } /*else { - error = fts_enableInterrupt(); - }*/ + } /*else {*/ + /*error = fts_enableInterrupt();*/ + /*}*/ #endif - return error; } @@ -1448,104 +3594,108 @@ static void fts_interrupt_uninstall(struct fts_ts_info *info) static void fts_interrupt_enable(struct fts_ts_info *info) { #ifdef FTS_USE_POLLING_MODE - hrtimer_start(&info->timer, - ktime_set(0, 10000000), HRTIMER_MODE_REL); + hrtimer_start(&info->timer, ktime_set(0, 10000000), HRTIMER_MODE_REL); #else enable_irq(info->client->irq); #endif } -/* -static void fts_interrupt_disable(struct fts_ts_info *info) -{ -#ifdef FTS_USE_POLLING_MODE - hrtimer_cancel(&info->timer); -#else - disable_irq(info->client->irq); -#endif -} -*/ - static int fts_init(struct fts_ts_info *info) { int error; error = fts_system_reset(); if (error < OK && error != (ERROR_TIMEOUT | ERROR_SYSTEM_RESET_FAIL)) { - logError(1, "%s Cannot reset the device! ERROR %08X\n", tag, error); + logError(1, "%s Cannot reset the device! ERROR %08X\n", + tag, error); return error; } if (error == (ERROR_TIMEOUT | ERROR_SYSTEM_RESET_FAIL)) { - logError(1, "%s Setting default Chip INFO!\n", tag); + logError(1, "%s Setting default Chip INFO!\n", tag); defaultChipInfo(0); } else { - error = readChipInfo(0); /* system reset OK */ + error = readChipInfo(0);/*system reset OK*/ if (error < OK) { - logError(1, "%s Cannot read Chip Info! ERROR %08X\n", tag, error); - } + logError(1, "%s Cannot read Chip Info!ERROR:%08X\n", + tag, error); + } } error = fts_interrupt_install(info); if (error != OK) - logError(1, "%s Init (1) error (ERROR = %08X)\n", error); + logError(1, "%s Init (1) error (ERROR = %08X)\n", tag, error); return error; } int fts_chip_powercycle(struct fts_ts_info *info) { - int error, i; + int error = 0; + + logError(1, "%s %s: Power Cycle Starting...\n", tag, __func__); + + /** + * if IRQ pin is short with DVDD a call to + * the ISR will triggered when the regulator is turned off + */ - logError(1, "%s %s: Power Cycle Starting...\n", tag, __func__); + logError(1, "%s %s: Disabling IRQ...\n", tag, __func__); + disable_irq_nosync(info->client->irq); if (info->pwr_reg) { error = regulator_disable(info->pwr_reg); if (error < 0) { - logError(1, "%s %s: Failed to disable DVDD regulator\n", tag, __func__); + logError(1, "%s %s: Failed to disable DVDD regulator\n", + tag, __func__); } } if (info->bus_reg) { error = regulator_disable(info->bus_reg); if (error < 0) { - logError(1, "%s %s: Failed to disable AVDD regulator\n", tag, __func__); + logError(1, "%s %s: Failed to disable AVDD regulator\n", + tag, __func__); } } if (info->bdata->reset_gpio != GPIO_NOT_DEFINED) gpio_set_value(info->bdata->reset_gpio, 0); + else + msleep(300); - msleep(300); if (info->pwr_reg) { error = regulator_enable(info->bus_reg); if (error < 0) { - logError(1, "%s %s: Failed to enable AVDD regulator\n", tag, __func__); + logError(1, "%s %s: Failed to enable AVDD regulator\n", + tag, __func__); } } if (info->bus_reg) { error = regulator_enable(info->pwr_reg); if (error < 0) { - logError(1, "%s %s: Failed to enable DVDD regulator\n", tag, __func__); + logError(1, "%s %s: Failed to enable DVDD regulator\n", + tag, __func__); } } - msleep(300); /* time needed by the regulators for reaching the regime values */ + /*time needed by the regulators for reaching the regime values*/ + msleep(20); + if (info->bdata->reset_gpio != GPIO_NOT_DEFINED) { - msleep(10); /* time to wait before bring up the reset gpio after the power up of the regulators */ + /* time to wait before bring up the reset*/ + /* gpio after the power up of the regulators */ + msleep(20); gpio_set_value(info->bdata->reset_gpio, 1); - /* msleep(300); */ + /* mdelay(300); */ } - /* before reset clear all slot */ - for (i = 0; i < TOUCH_ID_MAX; i++) { - input_mt_slot(info->input_dev, i); - input_mt_report_slot_state(info->input_dev, - (i < FINGER_MAX) ? MT_TOOL_FINGER : MT_TOOL_PEN, 0); - } - input_sync(info->input_dev); + release_all_touches(info); - logError(1, "%s %s: Power Cycle Finished! ERROR CODE = %08x\n", tag, __func__, error); + logError(1, "%s %s: Enabling IRQ...\n", tag, __func__); + enable_irq(info->client->irq); + logError(1, "%s %s: Power Cycle Finished! ERROR CODE = %08x\n", + tag, __func__, error); setSystemResettedUp(1); setSystemResettedDown(1); return error; @@ -1553,160 +3703,430 @@ int fts_chip_powercycle(struct fts_ts_info *info) int fts_chip_powercycle2(struct fts_ts_info *info, unsigned long sleep) { - int error, i; + int error = 0; + + logError(1, "%s %s: Power Cycle Starting...\n", tag, __func__); - logError(1, "%s %s: Power Cycle Starting...\n", tag, __func__); if (info->pwr_reg) { error = regulator_disable(info->pwr_reg); if (error < 0) { - logError(1, "%s %s: Failed to disable DVDD regulator\n", tag, __func__); + logError(1, "%s %s: Failed to disable DVDD regulator\n", + tag, __func__); } } if (info->bus_reg) { error = regulator_disable(info->bus_reg); if (error < 0) { - logError(1, "%s %s: Failed to disable AVDD regulator\n", tag, __func__); + logError(1, "%s %s: Failed to disable AVDD regulator\n", + tag, __func__); } } if (info->bdata->reset_gpio != GPIO_NOT_DEFINED) gpio_set_value(info->bdata->reset_gpio, 0); + /*mdelay(sleep);*/ msleep(sleep); if (info->pwr_reg) { error = regulator_enable(info->bus_reg); if (error < 0) { - logError(1, "%s %s: Failed to enable AVDD regulator\n", tag, __func__); + logError(1, "%s %s: Failed to enable AVDD regulator\n", + tag, __func__); } } if (info->bus_reg) { error = regulator_enable(info->pwr_reg); if (error < 0) { - logError(1, "%s %s: Failed to enable DVDD regulator\n", tag, __func__); + logError(1, "%s %s: Failed to enable DVDD regulator\n", + tag, __func__); } } - msleep(500); /*time needed by the regulators for reaching the regime values */ + /*time needed by the regulators for reaching the regime values*/ + msleep(500); + if (info->bdata->reset_gpio != GPIO_NOT_DEFINED) { - msleep(10); /*time to wait before bring up the reset gpio after the power up of the regulators */ + /** + * time to wait before bring up the reset + * gpio after the power up of the regulators + */ + msleep(20); gpio_set_value(info->bdata->reset_gpio, 1); - /* msleep(300); */ + /*msleep(300);*/ } - /* before reset clear all slot */ - for (i = 0; i < TOUCH_ID_MAX; i++) { - input_mt_slot(info->input_dev, i); - input_mt_report_slot_state(info->input_dev, - (i < FINGER_MAX) ? MT_TOOL_FINGER : MT_TOOL_PEN, 0); - } - input_sync(info->input_dev); + /*before reset clear all slot */ + release_all_touches(info); - logError(1, "%s %s: Power Cycle Finished! ERROR CODE = %08x\n", tag, __func__, error); + logError(1, "%s %s: Power Cycle Finished! ERROR CODE = %08x\n", + tag, __func__, error); setSystemResettedUp(1); setSystemResettedDown(1); return error; } -static int fts_init_hw(struct fts_ts_info *info) +static int fts_init_afterProbe(struct fts_ts_info *info) { int error = 0; - error = cleanUp(1); - if (error < OK) - logError(1, "%s Init (2) error (ERROR = %08X)\n", tag, error); + /* system reset */ + error = cleanUp(0); - info->mode = MODE_NORMAL; + /* enable the features and the sensing */ + error |= fts_mode_handler(info, 0); + + /* enable the interrupt */ + error |= fts_enableInterrupt(); + +#if defined(CONFIG_FB_MSM) + error |= fb_register_client(&info->notifier); +#else + error |= msm_drm_register_client(&info->notifier); +#endif + + if (error < OK) + logError(1, "%s %s Init after Probe error (ERROR = %08X)\n", + tag, __func__, error); return error; } - /* - * TODO: change this function according with the needs of - *customer in temrs of feature to enable/disable - */ +/** + * TODO: change this function according with the needs + * of customer in terms of feature to enable/disable + */ static int fts_mode_handler(struct fts_ts_info *info, int force) { int res = OK; int ret = OK; + /* initialize the mode to Nothing in order*/ + /*to be updated depending on the features enabled */ + info->mode = MODE_NOTHING; + logError(0, "%s %s: Mode Handler starting...\n", tag, __func__); switch (info->resume_bit) { - case 0:/* screen down */ - logError(0, "%s %s: Screen OFF...\n", tag, __func__); + case 0: + /* screen down */ + logError(0, "%s %s: Screen OFF...\n", tag, __func__); + /** + * do sense off in order to avoid the flooding + * of the fifo with touch events if someone is + * touching the panel during suspend + */ + logError(0, "%s %s: Sense OFF!\n", tag, __func__); + /*we need to use fts_command for speed reason*/ + /*(no need to check echo in this case and interrupt*/ + /* can be enabled)*/ + res |= fts_command(info, FTS_CMD_MS_MT_SENSE_OFF); +#ifdef PHONE_KEY + logError(0, "%s %s: Key OFF!\n", tag, __func__); + res |= fts_command(info, FTS_CMD_MS_KEY_OFF); +#endif + #ifdef PHONE_GESTURE - if (info->gesture_enabled == 1) { - logError(0, "%s %s: enter in gesture mode !\n", tag, __func__); - res = enterGestureMode(isSystemResettedDown()); - if (res >= OK) { + if (info->gesture_enabled == 1) { + logError(0, "%s %s: enter in gesture mode!\n", + tag, __func__); + ret = enterGestureMode(isSystemResettedDown()); + if (ret >= OK) { + info->mode |= FEAT_GESTURE; + } else { + logError(1, + "%s %s:enterGestureMode failed!%08X recovery in senseOff\n", + tag, __func__, ret); + } + res |= ret; + } +#endif + if (info->mode != (FEAT_GESTURE|MODE_NOTHING) + || info->gesture_enabled == 0) + info->mode |= MODE_SENSEOFF; + setSystemResettedDown(0); + break; - info->mode = MODE_GESTURE; - /* return OK; */ - } else { - logError(1, "%s %s: enterGestureMode failed! ERROR %08X recovery in senseOff...\n", tag, __func__, res); + case 1: + /* screen up */ + logError(0, "%s %s: Screen ON...\n", tag, __func__); + +#ifdef FEAT_GLOVE + if ((info->glove_enabled == FEAT_ENABLE && + isSystemResettedUp()) || force == 1) { + logError(0, "%s %s: Glove Mode setting...\n", + tag, __func__); + ret = featureEnableDisable(info->glove_enabled, + FEAT_GLOVE); + if (ret < OK) { + logError(1, + "%s %s:error in setting GLOVE_MODE!%08X\n", + tag, __func__, ret); + } + res |= ret; + + if (ret >= OK && info->glove_enabled == FEAT_ENABLE) { + info->mode |= FEAT_GLOVE; + logError(1, "%s %s: GLOVE_MODE Enabled!\n", + tag, __func__); + } else { + logError(1, "%s %s: GLOVE_MODE Disabled!\n", + tag, __func__); + } } - } #endif - if (info->mode != MODE_GESTURE || info->gesture_enabled == 0) { - logError(0, "%s %s: Sense OFF!\n", tag, __func__); - res |= fts_command(info, FTS_CMD_MS_MT_SENSE_OFF); /* we need to use fts_command for speed reason (no need to check echo in this case and interrupt can be enabled) */ -#ifdef PHONE_KEY - logError(0, "%s %s: Key OFF!\n", tag, __func__); - res |= fts_command(info, FTS_CMD_MS_KEY_OFF); +#ifdef FEAT_STYLUS + if ((info->stylus_enabled == FEAT_ENABLE && + isSystemResettedUp()) || force == 1) { + logError(0, "%s %s: Stylus Mode setting...\n", + tag, __func__); + ret = featureEnableDisable(info->stylus_enabled, + FEAT_STYLUS); + if (ret < OK) { + logError(1, + "%s %s:error in set STYLUS_MODE!%08X\n", + tag, __func__, ret); + } + res |= ret; + + if (ret >= OK && info->stylus_enabled == FEAT_ENABLE) { + info->mode |= FEAT_STYLUS; + logError(1, "%s %s: STYLUS_MODE Enabled!\n", + tag, __func__); + } else { + logError(1, "%s %s: STYLUS_MODE Disabled!\n", + tag, __func__); + } + } #endif +#ifdef FEAT_COVER + if ((info->cover_enabled == FEAT_ENABLE && + isSystemResettedUp()) || force == 1) { + logError(0, "%s %s: Cover Mode setting...\n", + tag, __func__); + ret = featureEnableDisable(info->cover_enabled, + FEAT_COVER); + if (ret < OK) { + logError(1, + "%s %s:error setting COVER_MODE!%08X\n", + tag, __func__, ret); + } + res |= ret; - info->mode = MODE_SENSEOFF; + if (ret >= OK && info->cover_enabled == FEAT_ENABLE) { + info->mode |= FEAT_COVER; + logError(1, "%s %s: COVER_MODE Enabled!\n", + tag, __func__); + } else { + logError(1, "%s %s: COVER_MODE Disabled!\n", + tag, __func__); + } + } +#endif +#ifdef FEAT_CHARGER + if ((info->charger_enabled == FEAT_ENABLE && + isSystemResettedUp()) || force == 1) { + logError(0, "%s %s: Charger Mode setting...\n", + tag, __func__); + ret = featureEnableDisable(info->charger_enabled, + FEAT_CHARGER); + if (ret < OK) { + logError(1, + "%s %s:error set CHARGER_MODE!%08X\n", + tag, __func__, ret); + } + res |= ret; - } - setSystemResettedDown(0); - break; + if (ret >= OK && info->charger_enabled == FEAT_ENABLE) { + info->mode |= FEAT_CHARGER; + logError(1, "%s %s: CHARGER_MODE Enabled!\n", + tag, __func__); + } else { + logError(1, "%s %s: CHARGER_MODE Disabled!\n", + tag, __func__); + } + } +#endif +#ifdef FEAT_VR + if ((info->vr_enabled == FEAT_ENABLE && + isSystemResettedUp()) || force == 1) { + logError(0, "%s %s: Vr Mode setting\n", tag, __func__); + ret = featureEnableDisable(info->vr_enabled, FEAT_VR); + if (ret < OK) { + logError(1, + "%s %s:error setting VR_MODE!:%08X\n", + tag, __func__, ret); + } + res |= ret; - case 1: /* screen up */ - logError(0, "%s %s: Screen ON...\n", tag, __func__); + if (ret >= OK && info->vr_enabled == FEAT_ENABLE) { + info->mode |= FEAT_VR; + logError(1, "%s %s: VR_MODE Enabled!\n", + tag, __func__); + } else { + logError(1, "%s %s: VR_MODE Disabled!\n", + tag, __func__); + } + } +#endif +#ifdef FEAT_EDGE_REJECTION + if ((info->edge_rej_enabled == FEAT_ENABLE && + isSystemResettedUp()) || force == 1) { + logError(0, "%s %s: Edge Rejection Mode setting\n", + tag, __func__); + ret = featureEnableDisable(info->edge_rej_enabled, + FEAT_EDGE_REJECTION); + if (ret < OK) { + logError(1, + "%s %s:err set EDGE_REJECTION_MODE!%08X\n", + tag, __func__, ret); + } + res |= ret; + + if (ret >= OK && info->edge_rej_enabled == + FEAT_ENABLE) { + info->mode |= FEAT_EDGE_REJECTION; + logError(1, + "%s %s:EDGE_REJECTION_MODE Enabled!\n", + tag, __func__); + } else { + logError(1, + "%s %s:EDGE_REJECTION_MODE Disabled!\n", + tag, __func__); + } + } +#endif +#ifdef FEAT_CORNER_REJECTION + if ((info->corner_rej_enabled == FEAT_ENABLE && + isSystemResettedUp()) || force == 1) { + logError(0, "%s %s: Corner rejection Mode setting\n", + tag, __func__); + ret = featureEnableDisable(info->corner_rej_enabled, + FEAT_CORNER_REJECTION); + if (ret < OK) { + logError(1, + "%s%s:err CORNER_REJECTION_MODE!%08X\n", + tag, __func__, ret); + } + res |= ret; + + if (ret >= OK && info->corner_rej_enabled == + FEAT_ENABLE) { + info->mode |= FEAT_CORNER_REJECTION; + logError(1, + "%s%s:CORNER_REJECTION_MODE Enabled!\n", + tag, __func__); + } else { + logError(1, + "%s%s:CORNER_REJECTION_MODE Disabled\n", + tag, __func__); + } + } +#endif +#ifdef FEAT_EDGE_PALM_REJECTION + if ((info->edge_palm_rej_enabled == FEAT_ENABLE && + isSystemResettedUp()) || force == 1) { + logError(0, "%s %s:Edge Palm rejection Mode setting\n", + tag, __func__); + ret = featureEnableDisable(info->edge_palm_rej_enabled, + FEAT_EDGE_PALM_REJECTION); + if (ret < OK) { + logError(1, + "%s %s:err EDGE_PALM_REJECTION_MODE!%08X\n", + tag, __func__, ret); + } + res |= ret; + + if (ret >= OK && info->edge_palm_rej_enabled == + FEAT_ENABLE) { + info->mode |= FEAT_EDGE_PALM_REJECTION; + logError(1, + "%s %s:EDGE_PALM_REJECTION_MODE Enabled!\n", + tag, __func__); + } else { + logError(1, + "%s %s:EDGE_PALM_REJECTION_MODE Disabled!\n", + tag, __func__); + } + } +#endif logError(0, "%s %s: Sense ON!\n", tag, __func__); res |= fts_command(info, FTS_CMD_MS_MT_SENSE_ON); + info->mode |= MODE_SENSEON; #ifdef PHONE_KEY logError(0, "%s %s: Key ON!\n", tag, __func__); res |= fts_command(info, FTS_CMD_MS_KEY_ON); #endif - info->mode = MODE_NORMAL; - - if (info->glove_enabled == FEAT_ENABLE || force == 1) { - if (isSystemResettedUp() || force == 1) { - logError(0, "%s %s: Glove Mode setting...\n", tag, __func__); - ret = featureEnableDisable(info->glove_enabled, FEAT_GLOVE); - if (ret < OK) { - logError(1, "%s %s: error during setting GLOVE_MODE! ERROR %08X\n", tag, __func__, ret); - } - res |= ret; - } - if (ret >= OK && info->glove_enabled == FEAT_ENABLE) { - info->mode = MODE_GLOVE; - logError(1, "%s %s: GLOVE_MODE Enabled!\n", tag, __func__); - } else{ - logError(1, "%s %s: GLOVE_MODE Disabled!\n", tag, __func__); - } - } - - setSystemResettedUp(0); - break; + setSystemResettedUp(0); + break; default: - logError(1, "%s %s: invalid resume_bit value = %d! ERROR %08X\n", tag, __func__, info->resume_bit, ERROR_OP_NOT_ALLOW); - res = ERROR_OP_NOT_ALLOW; + logError(1, + "%s %s: invalid resume_bit value = %d! ERROR %08X\n", + tag, __func__, info->resume_bit, ERROR_OP_NOT_ALLOW); + res = ERROR_OP_NOT_ALLOW; } - - logError(0, "%s %s: Mode Handler finished! res = %08X\n", tag, __func__, res); + logError(0, "%s %s: Mode Handler finished! res = %08X\n", tag, __func__, + res); return res; +} + + +static void fts_resume_work(struct work_struct *work) +{ + struct fts_ts_info *info; + + info = container_of(work, struct fts_ts_info, resume_work); + + __pm_wakeup_event(&info->wakeup_source, HZ); + + info->resume_bit = 1; +#ifdef USE_NOISE_PARAM + readNoiseParameters(noise_params); +#endif + fts_system_reset(); + +#ifdef USE_NOISE_PARAM + writeNoiseParameters(noise_params); +#endif + + release_all_touches(info); + + fts_mode_handler(info, 0); + + info->sensor_sleep = false; + + fts_enableInterrupt(); +} + + +static void fts_suspend_work(struct work_struct *work) +{ + struct fts_ts_info *info; + + info = container_of(work, struct fts_ts_info, suspend_work); + + __pm_wakeup_event(&info->wakeup_source, HZ); + + info->resume_bit = 0; + fts_mode_handler(info, 0); + + release_all_touches(info); + info->sensor_sleep = true; + + fts_enableInterrupt(); } -static int fts_fb_state_chg_callback(struct notifier_block *nb, unsigned long val, void *data) + +#if defined(CONFIG_FB_MSM) +static int fts_fb_state_chg_callback(struct notifier_block *nb, + unsigned long val, void *data) { - struct fts_ts_info *info = container_of(nb, struct fts_ts_info, notifier); + + struct fts_ts_info *info = container_of(nb, + struct fts_ts_info, notifier); struct fb_event *evdata = data; - int i; unsigned int blank; if (val != FB_EVENT_BLANK) @@ -1723,23 +4143,10 @@ static int fts_fb_state_chg_callback(struct notifier_block *nb, unsigned long va if (info->sensor_sleep) break; - logError(0, "%s %s: FB_BLANK_POWERDOWN\n", tag, __func__); - - /* Release all slots */ - for (i = 0; i < TOUCH_ID_MAX; i++) { - input_mt_slot(info->input_dev, i); - input_mt_report_slot_state(info->input_dev, - (i < FINGER_MAX) ? MT_TOOL_FINGER : MT_TOOL_PEN, 0); - } - input_sync(info->input_dev); - - info->resume_bit = 0; + logError(0, "%s %s: FB_BLANK_POWERDOWN\n", + tag, __func__); - fts_mode_handler(info, 0); - - info->sensor_sleep = true; - - fts_disableInterrupt(); + queue_work(info->event_wq, &info->suspend_work); break; @@ -1747,41 +4154,66 @@ static int fts_fb_state_chg_callback(struct notifier_block *nb, unsigned long va if (!info->sensor_sleep) break; - logError(0, "%s %s: FB_BLANK_UNBLANK\n", tag, __func__); + logError(0, "%s %s: FB_BLANK_UNBLANK\n", + tag, __func__); - for (i = 0; i < TOUCH_ID_MAX; i++) { - input_mt_slot(info->input_dev, i); - input_mt_report_slot_state(info->input_dev, - (i < FINGER_MAX) ? MT_TOOL_FINGER : MT_TOOL_PEN, 0); - } - input_sync(info->input_dev); + queue_work(info->event_wq, &info->resume_work); + break; + default: + break; + } + } + return NOTIFY_OK; +} + +#else +static int fts_fb_state_chg_callback(struct notifier_block *nb, + unsigned long val, void *data) +{ + struct fts_ts_info *info = container_of(nb, struct fts_ts_info, + notifier); + struct msm_drm_notifier *evdata = data; + unsigned int blank; - info->resume_bit = 1; + if (val != MSM_DRM_EVENT_BLANK) + return 0; + logError(0, "%s %s: fts notifier begin!\n", tag, __func__); - fts_mode_handler(info, 0); + if (evdata && evdata->data && val == MSM_DRM_EVENT_BLANK && info) { + blank = *(int *) (evdata->data); - info->sensor_sleep = false; + switch (blank) { + case MSM_DRM_BLANK_POWERDOWN: + if (info->sensor_sleep) + break; + logError(0, "%s %s: MSM_DRM_BLANK_UNBLANK\n", + tag, __func__); + queue_work(info->event_wq, &info->suspend_work); + break; - fts_enableInterrupt(); + case MSM_DRM_BLANK_UNBLANK: + if (!info->sensor_sleep) + break; + logError(0, "%s %s: MSM_DRM_BLANK_UNBLANK\n", + tag, __func__); + queue_work(info->event_wq, &info->resume_work); break; default: break; - } } return NOTIFY_OK; - } +#endif static struct notifier_block fts_noti_block = { .notifier_call = fts_fb_state_chg_callback, }; -static int fts_get_reg(struct fts_ts_info *rmi4_data, - bool get) { +static int fts_get_reg(struct fts_ts_info *info, bool get) +{ int retval; - const struct fts_i2c_platform_data *bdata = - rmi4_data->bdata; + const struct fts_i2c_platform_data *bdata = info->bdata; if (!get) { retval = 0; @@ -1789,23 +4221,24 @@ static int fts_get_reg(struct fts_ts_info *rmi4_data, } if ((bdata->pwr_reg_name != NULL) && (*bdata->pwr_reg_name != 0)) { - rmi4_data->pwr_reg = regulator_get(rmi4_data->dev, - bdata->pwr_reg_name); - if (IS_ERR(rmi4_data->pwr_reg)) { - logError(1, "%s %s: Failed to get power regulator\n", tag, - __func__); - retval = PTR_ERR(rmi4_data->pwr_reg); + info->pwr_reg = regulator_get(info->dev, + bdata->pwr_reg_name); + if (IS_ERR(info->pwr_reg)) { + logError(1, "%s %s: Failed to get power regulator\n", + tag, __func__); + retval = PTR_ERR(info->pwr_reg); goto regulator_put; } } if ((bdata->bus_reg_name != NULL) && (*bdata->bus_reg_name != 0)) { - rmi4_data->bus_reg = regulator_get(rmi4_data->dev, - bdata->bus_reg_name); - if (IS_ERR(rmi4_data->bus_reg)) { - logError(1, "%s %s: Failed to get bus pullup regulator\n", tag, - __func__); - retval = PTR_ERR(rmi4_data->bus_reg); + info->bus_reg = regulator_get(info->dev, + bdata->bus_reg_name); + if (IS_ERR(info->bus_reg)) { + logError(1, + "%s %s:Failed to get bus pullup regulator\n", + tag, __func__); + retval = PTR_ERR(info->bus_reg); goto regulator_put; } } @@ -1813,21 +4246,22 @@ static int fts_get_reg(struct fts_ts_info *rmi4_data, return 0; regulator_put: - if (rmi4_data->pwr_reg) { - regulator_put(rmi4_data->pwr_reg); - rmi4_data->pwr_reg = NULL; + if (info->pwr_reg) { + regulator_put(info->pwr_reg); + info->pwr_reg = NULL; } - if (rmi4_data->bus_reg) { - regulator_put(rmi4_data->bus_reg); - rmi4_data->bus_reg = NULL; + if (info->bus_reg) { + regulator_put(info->bus_reg); + info->bus_reg = NULL; } return retval; } -static int fts_enable_reg(struct fts_ts_info *rmi4_data, - bool enable) { +static int fts_enable_reg(struct fts_ts_info *info, + bool enable) +{ int retval; if (!enable) { @@ -1835,20 +4269,20 @@ static int fts_enable_reg(struct fts_ts_info *rmi4_data, goto disable_pwr_reg; } - if (rmi4_data->bus_reg) { - retval = regulator_enable(rmi4_data->bus_reg); + if (info->bus_reg) { + retval = regulator_enable(info->bus_reg); if (retval < 0) { - logError(1, "%s %s: Failed to enable bus regulator\n", tag, - __func__); + logError(1, "%s %s: Failed to enable bus regulator\n", + tag, __func__); goto exit; } } - if (rmi4_data->pwr_reg) { - retval = regulator_enable(rmi4_data->pwr_reg); + if (info->pwr_reg) { + retval = regulator_enable(info->pwr_reg); if (retval < 0) { - logError(1, "%s %s: Failed to enable power regulator\n", tag, - __func__); + logError(1, "%s %s: Failed to enable power regulator\n", + tag, __func__); goto disable_bus_reg; } } @@ -1856,12 +4290,12 @@ static int fts_enable_reg(struct fts_ts_info *rmi4_data, return OK; disable_pwr_reg: - if (rmi4_data->pwr_reg) - regulator_disable(rmi4_data->pwr_reg); + if (info->pwr_reg) + regulator_disable(info->pwr_reg); disable_bus_reg: - if (rmi4_data->bus_reg) - regulator_disable(rmi4_data->bus_reg); + if (info->bus_reg) + regulator_disable(info->bus_reg); exit: return retval; @@ -1877,8 +4311,8 @@ static int fts_gpio_setup(int gpio, bool config, int dir, int state) retval = gpio_request(gpio, buf); if (retval) { - logError(1, "%s %s: Failed to get gpio %d (code: %d)", tag, - __func__, gpio, retval); + logError(1, "%s %s: Failed to get gpio %d (code: %d)", + tag, __func__, gpio, retval); return retval; } @@ -1887,8 +4321,8 @@ static int fts_gpio_setup(int gpio, bool config, int dir, int state) else retval = gpio_direction_output(gpio, state); if (retval) { - logError(1, "%s %s: Failed to set gpio %d direction", tag, - __func__, gpio); + logError(1, "%s %s: Failed to set gpio %d direction", + tag, __func__, gpio); return retval; } } else { @@ -1898,28 +4332,30 @@ static int fts_gpio_setup(int gpio, bool config, int dir, int state) return retval; } -static int fts_set_gpio(struct fts_ts_info *rmi4_data) +static int fts_set_gpio(struct fts_ts_info *info) { int retval; const struct fts_i2c_platform_data *bdata = - rmi4_data->bdata; + info->bdata; retval = fts_gpio_setup(bdata->irq_gpio, true, 0, 0); if (retval < 0) { - logError(1, "%s %s: Failed to configure irq GPIO\n", tag, __func__); + logError(1, "%s %s: Failed to configure irq GPIO\n", + tag, __func__); goto err_gpio_irq; } if (bdata->reset_gpio >= 0) { retval = fts_gpio_setup(bdata->reset_gpio, true, 1, 0); if (retval < 0) { - logError(1, "%s %s: Failed to configure reset GPIO\n", tag, __func__); + logError(1, "%s %s: Failed to configure reset GPIO\n", + tag, __func__); goto err_gpio_reset; } } if (bdata->reset_gpio >= 0) { gpio_set_value(bdata->reset_gpio, 0); - msleep(10); + msleep(20); gpio_set_value(bdata->reset_gpio, 1); } @@ -1933,14 +4369,15 @@ static int fts_set_gpio(struct fts_ts_info *rmi4_data) return retval; } -static int parse_dt(struct device *dev, struct fts_i2c_platform_data *bdata) +static int parse_dt(struct device *dev, + struct fts_i2c_platform_data *bdata) { int retval; const char *name; struct device_node *np = dev->of_node; bdata->irq_gpio = of_get_named_gpio_flags(np, - "st,irq-gpio", 0, NULL); + "st,irq-gpio", 0, NULL); logError(0, "%s irq_gpio = %d\n", tag, bdata->irq_gpio); @@ -1949,6 +4386,7 @@ static int parse_dt(struct device *dev, struct fts_i2c_platform_data *bdata) bdata->pwr_reg_name = NULL; else if (retval < 0) return retval; + bdata->pwr_reg_name = name; logError(0, "%s pwr_reg_name = %s\n", tag, name); @@ -1957,6 +4395,7 @@ static int parse_dt(struct device *dev, struct fts_i2c_platform_data *bdata) bdata->bus_reg_name = NULL; else if (retval < 0) return retval; + bdata->bus_reg_name = name; logError(0, "%s bus_reg_name = %s\n", tag, name); @@ -1972,27 +4411,33 @@ static int parse_dt(struct device *dev, struct fts_i2c_platform_data *bdata) } static int fts_probe(struct i2c_client *client, - const struct i2c_device_id *idp) { + const struct i2c_device_id *idp) +{ struct fts_ts_info *info = NULL; - char fts_ts_phys[64]; int error = 0; struct device_node *dp = client->dev.of_node; int retval; + int skip_5_1 = 0; - logError(1, "%s %s: driver probe begin!\n", tag, __func__); + logError(1, "%s %s: driver probe begin!\n", tag, __func__); - logError(1, "%s SET I2C Functionality and Dev INFO:\n", tag); + logError(1, "%s SET I2C Functionality and Dev INFO:\n", tag); openChannel(client); + /* logError(1, "%s driver ver. %s (built on %s, %s)\n", tag,*/ + /* FTS_TS_DRV_VERSION, __DATE__, __TIME__);*/ + logError(1, "%s driver ver. %s (built on)\n", tag, FTS_TS_DRV_VERSION); if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { - logError(1, "%s Unsupported I2C functionality\n", tag); + logError(1, "%s Unsupported I2C functionality\n", tag); error = -EIO; goto ProbeErrorExit_0; } - info = kzalloc(sizeof (struct fts_ts_info), GFP_KERNEL); + info = kzalloc(sizeof(struct fts_ts_info), GFP_KERNEL); if (!info) { - logError(1, "%s Out of memory... Impossible to allocate struct info!\n", tag); + logError(1, + "%s Out of memory, can't to allocate struct info!\n", + tag); error = -ENOMEM; goto ProbeErrorExit_0; } @@ -2000,68 +4445,85 @@ static int fts_probe(struct i2c_client *client, info->client = client; i2c_set_clientdata(client, info); - logError(1, "%s i2c address: %x\n", tag, client->addr); + logError(1, "%s i2c address: %x\n", tag, client->addr); info->dev = &info->client->dev; if (dp) { - info->bdata = devm_kzalloc(&client->dev, sizeof (struct fts_i2c_platform_data), GFP_KERNEL); + info->bdata = devm_kzalloc(&client->dev, + sizeof(struct fts_i2c_platform_data), + GFP_KERNEL); if (!info->bdata) { - logError(1, "%s ERROR:info.bdata kzalloc failed\n", tag); + logError(1, "%s ERROR:info.bdata kzalloc failed\n", + tag); goto ProbeErrorExit_1; } parse_dt(&client->dev, info->bdata); } - logError(1, "%s SET Regulators:\n", tag); + logError(1, "%s SET Regulators:\n", tag); retval = fts_get_reg(info, true); if (retval < 0) { - logError(1, "%s ERROR: %s: Failed to get regulators\n", tag, __func__); + logError(1, "%s ERROR: %s: Failed to get regulators\n", + tag, __func__); goto ProbeErrorExit_1; } retval = fts_enable_reg(info, true); if (retval < 0) { - logError(1, "%s %s: ERROR Failed to enable regulators\n", tag, __func__); + logError(1, "%s %s: ERROR Failed to enable regulators\n", + tag, __func__); goto ProbeErrorExit_2; } - logError(1, "%s SET GPIOS:\n", tag); + logError(1, "%s SET GPIOS:\n", tag); retval = fts_set_gpio(info); if (retval < 0) { - logError(1, "%s %s: ERROR Failed to set up GPIO's\n", tag, __func__); + logError(1, "%s %s: ERROR Failed to set up GPIO's\n", + tag, __func__); goto ProbeErrorExit_2; } info->client->irq = gpio_to_irq(info->bdata->irq_gpio); - logError(1, "%s SET Auto Fw Update:\n", tag); - info->fwu_workqueue = create_singlethread_workqueue("fts-fwu-queue"); + logError(1, "%s SET Auto Fw Update:\n", tag); + /*info->fwu_workqueue =*/ + /*create_singlethread_workqueue("fts-fwu-queue");*/ + info->fwu_workqueue = alloc_workqueue("fts-fwu-queue", + WQ_UNBOUND|WQ_HIGHPRI|WQ_CPU_INTENSIVE, 1); if (!info->fwu_workqueue) { - logError(1, "%s ERROR: Cannot create fwu work thread\n", tag); + logError(1, "%s ERROR: Cannot create fwu work thread\n", tag); goto ProbeErrorExit_3; } INIT_DELAYED_WORK(&info->fwu_work, fts_fw_update_auto); - logError(1, "%s SET Event Handler:\n", tag); - info->event_wq = create_singlethread_workqueue("fts-event-queue"); + logError(1, "%s SET Event Handler:\n", tag); + /*wake_lock_init(&info->wakelock, WAKE_LOCK_SUSPEND, "fts_tp");*/ + wakeup_source_init(&info->wakeup_source, "fts_tp"); + /*info->event_wq = create_singlethread_workqueue("fts-event-queue");*/ + info->event_wq = alloc_workqueue("fts-event-queue", + WQ_UNBOUND|WQ_HIGHPRI|WQ_CPU_INTENSIVE, 1); if (!info->event_wq) { - logError(1, "%s ERROR: Cannot create work thread\n", tag); + logError(1, "%s ERROR: Cannot create work thread\n", tag); error = -ENOMEM; goto ProbeErrorExit_4; } INIT_WORK(&info->work, fts_event_handler); - logError(1, "%s SET Input Device Property:\n", tag); - info->dev = &info->client->dev; + INIT_WORK(&info->resume_work, fts_resume_work); + INIT_WORK(&info->suspend_work, fts_suspend_work); + + logError(1, "%s SET Input Device Property:\n", tag); + /*info->dev = &info->client->dev;*/ info->input_dev = input_allocate_device(); if (!info->input_dev) { - logError(1, "%s ERROR: No such input device defined!\n", tag); + logError(1, "%s ERROR: No such input device defined!\n", + tag); error = -ENODEV; goto ProbeErrorExit_5; } info->input_dev->dev.parent = &client->dev; info->input_dev->name = FTS_TS_DRV_NAME; - snprintf(fts_ts_phys, sizeof (fts_ts_phys), "%s/input0", - info->input_dev->name); + snprintf(fts_ts_phys, sizeof(fts_ts_phys), "%s/input0", + info->input_dev->name); info->input_dev->phys = fts_ts_phys; info->input_dev->id.bustype = BUS_I2C; info->input_dev->id.vendor = 0x0001; @@ -2076,9 +4538,10 @@ static int fts_probe(struct i2c_client *client, input_mt_init_slots(info->input_dev, TOUCH_ID_MAX, INPUT_MT_DIRECT); - /* input_mt_init_slots(info->input_dev, TOUCH_ID_MAX); */ + /*input_mt_init_slots(info->input_dev, TOUCH_ID_MAX);*/ - /* input_set_abs_params(info->input_dev, ABS_MT_TRACKING_ID, 0, FINGER_MAX, 0, 0); */ + /*input_set_abs_params(info->input_dev,*/ + /*ABS_MT_TRACKING_ID, 0, FINGER_MAX, 0, 0);*/ input_set_abs_params(info->input_dev, ABS_MT_POSITION_X, X_AXIS_MIN, X_AXIS_MAX, 0, 0); input_set_abs_params(info->input_dev, ABS_MT_POSITION_Y, @@ -2087,8 +4550,8 @@ static int fts_probe(struct i2c_client *client, AREA_MIN, AREA_MAX, 0, 0); input_set_abs_params(info->input_dev, ABS_MT_TOUCH_MINOR, AREA_MIN, AREA_MAX, 0, 0); - input_set_abs_params(info->input_dev, ABS_MT_PRESSURE, - PRESSURE_MIN, PRESSURE_MAX, 0, 0); + /*input_set_abs_params(info->input_dev, ABS_MT_PRESSURE,*/ + /*PRESSURE_MIN, PRESSURE_MAX, 0, 0);*/ #ifdef PHONE_GESTURE input_set_capability(info->input_dev, EV_KEY, KEY_WAKEUP); @@ -2121,7 +4584,7 @@ static int fts_probe(struct i2c_client *client, #endif #ifdef PHONE_KEY - /* KEY associated to the touch screen buttons */ + /*KEY associated to the touch screen buttons*/ input_set_capability(info->input_dev, EV_KEY, KEY_HOMEPAGE); input_set_capability(info->input_dev, EV_KEY, KEY_BACK); input_set_capability(info->input_dev, EV_KEY, KEY_MENU); @@ -2129,42 +4592,65 @@ static int fts_probe(struct i2c_client *client, mutex_init(&(info->input_report_mutex)); + +#ifdef PHONE_GESTURE + mutex_init(&gestureMask_mutex); +#endif + /* register the multi-touch input device */ error = input_register_device(info->input_dev); if (error) { - logError(1, "%s ERROR: No such input device\n", tag); + logError(1, "%s ERROR: No such input device\n", tag); error = -ENODEV; goto ProbeErrorExit_5_1; } + skip_5_1 = 1; /* track slots */ info->touch_id = 0; +#ifdef STYLUS_MODE + info->stylus_id = 0; +#endif /* init hardware device */ - logError(1, "%s Device Initialization:\n", tag); + logError(1, "%s Device Initialization:\n", tag); error = fts_init(info); if (error < OK) { - logError(1, "%s Cannot initialize the device ERROR %08X\n", tag, error); + logError(1, "%s Cannot initialize the device ERROR %08X\n", + tag, error); error = -ENODEV; goto ProbeErrorExit_6; } + /** + * init feature switches (by default all the features + * are disable, if one feature want to be enabled from + * the start, set the corresponding value to 1) + */ info->gesture_enabled = 0; info->glove_enabled = 0; + info->charger_enabled = 0; + info->stylus_enabled = 0; + info->vr_enabled = 0; + info->cover_enabled = 0; + info->edge_rej_enabled = 0; + info->corner_rej_enabled = 0; + info->edge_palm_rej_enabled = 0; + info->resume_bit = 1; info->notifier = fts_noti_block; - error = fb_register_client(&info->notifier); - if (error) { - logError(1, "%s ERROR: register notifier failed!\n", tag); - goto ProbeErrorExit_6; - } + /*error = fb_register_client(&info->notifier);*/ + /*if (error) {*/ + /*logError(1, "%s ERROR: register notifier failed!\n", tag);*/ + /*goto ProbeErrorExit_6;*/ + /*}*/ - logError(1, "%s SET Device File Nodes:\n", tag); + logError(1, "%s SET Device File Nodes:\n", tag); /* sysfs stuff */ info->attrs.attrs = fts_attr_group; error = sysfs_create_group(&client->dev.kobj, &info->attrs); if (error) { - logError(1, "%s ERROR: Cannot create sysfs structure!\n", tag); + logError(1, "%s ERROR: Cannot create sysfs structure!\n", tag); error = -ENODEV; goto ProbeErrorExit_7; } @@ -2176,7 +4662,9 @@ static int fts_probe(struct i2c_client *client, info->i2c_cmd_dev = device_create(fts_cmd_class, NULL, DCHIP_ID_0, info, "fts_i2c"); if (IS_ERR(info->i2c_cmd_dev)) { - logError(1, "%s ERROR: Failed to create device for the sysfs!\n", tag); + logError(1, + "%s ERROR: Failed to create device for the sysfs!\n", + tag); goto ProbeErrorExit_8; } @@ -2185,19 +4673,21 @@ static int fts_probe(struct i2c_client *client, error = sysfs_create_group(&info->i2c_cmd_dev->kobj, &i2c_cmd_attr_group); if (error) { - logError(1, "%s ERROR: Failed to create sysfs group!\n", tag); + logError(1, "%s ERROR: Failed to create sysfs group!\n", tag); goto ProbeErrorExit_9; } - #endif + #ifdef DRIVER_TEST if (fts_cmd_class == NULL) fts_cmd_class = class_create(THIS_MODULE, FTS_TS_DRV_NAME); info->test_cmd_dev = device_create(fts_cmd_class, NULL, DCHIP_ID_0, info, "fts_driver_test"); if (IS_ERR(info->test_cmd_dev)) { - logError(1, "%s ERROR: Failed to create device for the sysfs!\n", tag); + logError(1, + "%s ERROR: Failed to create device for the sysfs!\n", + tag); goto ProbeErrorExit_10; } @@ -2206,19 +4696,13 @@ static int fts_probe(struct i2c_client *client, error = sysfs_create_group(&info->test_cmd_dev->kobj, &test_cmd_attr_group); if (error) { - logError(1, "%s ERROR: Failed to create sysfs group!\n", tag); + logError(1, "%s ERROR: Failed to create sysfs group!\n", tag); goto ProbeErrorExit_11; } - #endif - /*if wanna auto-update FW when probe, - * please don't comment the following code - */ - - /* queue_delayed_work(info->fwu_workqueue, &info->fwu_work, - * msecs_to_jiffies(EXP_FN_WORK_DELAY_MS)); - */ - logError(1, "%s Probe Finished!\n", tag); + queue_delayed_work(info->fwu_workqueue, &info->fwu_work, + msecs_to_jiffies(EXP_FN_WORK_DELAY_MS)); + logError(1, "%s Probe Finished!\n", tag); return OK; /* error exit path */ @@ -2231,7 +4715,7 @@ static int fts_probe(struct i2c_client *client, ProbeErrorExit_10: #ifndef SCRIPTLESS sysfs_remove_group(&client->dev.kobj, &info->attrs); -#endif +#endif /*if fail before creating the*/ #endif #ifdef SCRIPTLESS @@ -2243,19 +4727,22 @@ static int fts_probe(struct i2c_client *client, #endif ProbeErrorExit_7: - fb_unregister_client(&info->notifier); + /*fb_unregister_client(&info->notifier);*/ ProbeErrorExit_6: input_unregister_device(info->input_dev); ProbeErrorExit_5_1: - /* intput_free_device(info->input_dev ); */ + if (skip_5_1 != 1) + input_free_device(info->input_dev); - ProbeErrorExit_5: - destroy_workqueue(info->event_wq); +ProbeErrorExit_5: + destroy_workqueue(info->event_wq); ProbeErrorExit_4: destroy_workqueue(info->fwu_workqueue); + /* wake_lock_destroy(&info->wakelock); */ + wakeup_source_trash(&info->wakeup_source); ProbeErrorExit_3: fts_enable_reg(info, false); @@ -2267,7 +4754,7 @@ static int fts_probe(struct i2c_client *client, kfree(info); ProbeErrorExit_0: - logError(1, "%s Probe Failed!\n", tag); + logError(1, "%s Probe Failed!\n", tag); return error; } @@ -2283,9 +4770,7 @@ static int fts_remove(struct i2c_client *client) #ifdef SCRIPTLESS /*I2C cmd*/ - sysfs_remove_group(&info->i2c_cmd_dev->kobj, - &i2c_cmd_attr_group); - + sysfs_remove_group(&info->i2c_cmd_dev->kobj, &i2c_cmd_attr_group); #endif #if defined(SCRIPTLESS) || defined(DRIVER_TEST) @@ -2298,12 +4783,16 @@ static int fts_remove(struct i2c_client *client) /* remove interrupt and event handlers */ fts_interrupt_uninstall(info); +#if defined(CONFIG_FB_MSM) fb_unregister_client(&info->notifier); +#else + msm_drm_unregister_client(&info->notifier); +#endif /* unregister the device */ input_unregister_device(info->input_dev); - /* intput_free_device(info->input_dev ); */ + /* input_free_device(info->input_dev ); */ /* Empty the FIFO buffer */ fts_command(info, FIFO_CMD_FLUSH); @@ -2311,6 +4800,8 @@ static int fts_remove(struct i2c_client *client) /* Remove the work thread */ destroy_workqueue(info->event_wq); + /* wake_lock_destroy(&info->wakelock); */ + wakeup_source_trash(&info->wakeup_source); destroy_workqueue(info->fwu_workqueue); fts_enable_reg(info, false); @@ -2322,7 +4813,7 @@ static int fts_remove(struct i2c_client *client) return OK; } -static struct of_device_id fts_of_match_table[] = { +static const struct of_device_id fts_of_match_table[] = { { .compatible = "st,fts", }, @@ -2353,9 +4844,9 @@ static void __exit fts_driver_exit(void) i2c_del_driver(&fts_i2c_driver); } -MODULE_DESCRIPTION("STMicroelectronics MultiTouch IC Driver"); -MODULE_AUTHOR("STMicroelectronics, Inc."); -MODULE_LICENSE("GPL"); late_initcall(fts_driver_init); module_exit(fts_driver_exit); + +MODULE_DESCRIPTION("STMicroelectronics MultiTouch IC Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/input/touchscreen/st/fts.h b/drivers/input/touchscreen/st/fts.h index 7d72d226349f..cf2a2196d024 100644 --- a/drivers/input/touchscreen/st/fts.h +++ b/drivers/input/touchscreen/st/fts.h @@ -1,117 +1,186 @@ /* - * fts.c - * * FTS Capacitive touch screen controller (FingerTipS) * - * Copyright (C) 2016, STMicroelectronics Limited. - * Authors: AMG(Analog Mems Group) + * Copyright (C) 2016-2018, STMicroelectronics Limited. + * Authors: AMG(Analog Mems Group) + * * - * marco.cali@st.com + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . */ #ifndef _LINUX_FTS_I2C_H_ #define _LINUX_FTS_I2C_H_ +/*#include */ +#include + #include "fts_lib/ftsSoftware.h" #include "fts_lib/ftsHardware.h" +#include "fts_lib/ftsGesture.h" -#define FTS_POWER_ON 1 -#define FTS_POWER_OFF 0 +#define FTS_POWER_ON 1 +#define FTS_POWER_OFF 0 /****************** CONFIGURATION SECTION ******************/ -/* #define PHONE_KEY */ -/* #define PHONE_GESTURE */ +/**** CODE CONFIGURATION ****/ -#define SCRIPTLESS +#define FTS_TS_DRV_NAME "fts" +#define FTS_TS_DRV_VERSION "4.2.14" /* version */ + +#define SCRIPTLESS /*allow to work in scriptless mode with the GUI*/ #ifdef SCRIPTLESS #define SCRIPTLESS_DEBUG -/* uncomment this macro definition to print debug -* message for script less support -*/ +/** + * uncomment this macro definition to print debug + * message for script less support + */ #endif #define DRIVER_TEST -#define FW_H_FILE +/* #define FW_H_FILE */ /*include the FW as header file*/ #ifdef FW_H_FILE -#define FW_SIZE_NAME myArray_size -#define FW_ARRAY_NAME myArray + #define FW_SIZE_NAME myArray_size + #define FW_ARRAY_NAME myArray #endif -#define LIMITS_H_FILE +/*#define LIMITS_H_FILE*/ /*include the limits file as header file*/ #ifdef LIMITS_H_FILE -#define LIMITS_SIZE_NAME myArray2_size -#define LIMITS_ARRAY_NAME myArray2 + #define LIMITS_SIZE_NAME myArray2_size + #define LIMITS_ARRAY_NAME myArray2 #endif -#define FTS_TS_DRV_NAME "fts" -#define FTS_TS_DRV_VERSION "4.1.0" +/**** END ****/ + + +/**** FEATURES USED IN THE IC ***/ +#define PHONE_KEY /*enable the keys*/ + +#define PHONE_GESTURE /*allow to use the gestures*/ +#ifdef PHONE_GESTURE + #define USE_GESTURE_MASK + #define USE_CUSTOM_GESTURES +#endif + +#define USE_ONE_FILE_NODE +/*allow to enable/disable all the features just using one file node*/ + +#define EDGE_REJ +/*allow edge rej feature (comment to disable)*/ -#define X_AXIS_MAX 1440 -#define X_AXIS_MIN 0 -#define Y_AXIS_MAX 2560 -#define Y_AXIS_MIN 0 +#define CORNER_REJ +/*allow corn rej feature (comment to disable)*/ -#define PRESSURE_MIN 0 -#define PRESSURE_MAX 127 +#define EDGE_PALM_REJ +/*allow edge palm rej feature (comment to disable)*/ -#define FINGER_MAX 10 -#define STYLUS_MAX 1 -#define TOUCH_ID_MAX (FINGER_MAX + STYLUS_MAX) +#define CHARGER_MODE +/*allow charger mode feature (comment to disable)*/ -#define AREA_MIN PRESSURE_MIN -#define AREA_MAX PRESSURE_MAX +#define GLOVE_MODE +/*allow glove mode feature (comment to disable)*/ + +#define VR_MODE +/*allow vr mode feature (comment to disable)*/ + +#define COVER_MODE +/*allow cover mode feature (comment to disable)*/ + +#define STYLUS_MODE +/*allow stylus mode feature (comment to disable)*/ + +#define USE_NOISE_PARAM +/*set noise params during resume (comment to disable)*/ + +/**** END ****/ + + +/**** PANEL SPECIFICATION ****/ +#define X_AXIS_MAX 1440 +#define X_AXIS_MIN 0 +#define Y_AXIS_MAX 2880 +#define Y_AXIS_MIN 0 + +#define PRESSURE_MIN 0 +#define PRESSURE_MAX 127 + +#define TOUCH_ID_MAX 10 + +#define AREA_MIN PRESSURE_MIN +#define AREA_MAX PRESSURE_MAX +/**** END ****/ /*********************************************************/ /* Flash programming */ -#define INIT_FLAG_CNT 3 +#define INIT_FLAG_CNT 3 /* KEYS */ -#define KEY1 0x02 -#define KEY2 0x01 -#define KEY3 0x04 +#define KEY1 0x02 +#define KEY2 0x01 +#define KEY3 0x04 /* * Configuration mode */ -#define MODE_NORMAL 0 -#define MODE_GESTURE 1 -#define MODE_GLOVE 2 -#define MODE_SENSEOFF 3 +/** + * bitmask which can assume the value defined as + * features in ftsSoftware.h or the following values + */ + +#define MODE_NOTHING 0x00000000 +#define MODE_SENSEON 0x10000000 +#define MODE_SENSEOFF 0x20000000 +#define FEAT_GESTURE 0x40000000 + /* * Status Event Field: - * id of command that triggered the event + * id of command that triggered the event */ -#define FTS_FLASH_WRITE_CONFIG 0x03 -#define FTS_FLASH_WRITE_COMP_MEMORY 0x04 -#define FTS_FORCE_CAL_SELF_MUTUAL 0x05 -#define FTS_FORCE_CAL_SELF 0x06 -#define FTS_WATER_MODE_ON 0x07 -#define FTS_WATER_MODE_OFF 0x08 +#define FTS_FLASH_WRITE_CONFIG 0x03 +#define FTS_FLASH_WRITE_COMP_MEMORY 0x04 +#define FTS_FORCE_CAL_SELF_MUTUAL 0x05 +#define FTS_FORCE_CAL_SELF 0x06 +#define FTS_WATER_MODE_ON 0x07 +#define FTS_WATER_MODE_OFF 0x08 + -#define EXP_FN_WORK_DELAY_MS 1000 +#define EXP_FN_WORK_DELAY_MS 1000 + +#define CMD_STR_LEN 32 -#define CMD_STR_LEN 32 #ifdef SCRIPTLESS /* * I2C Command Read/Write Function */ -#define CMD_RESULT_STR_LEN 2048 +#define CMD_RESULT_STR_LEN 2048 #endif -#define TSP_BUF_SIZE 4096 +#define TSP_BUF_SIZE 4096 + +/*add by guchong*/ +#ifdef PHONE_GESTURE +extern u16 gesture_coordinates_x[GESTURE_COORDS_REPORT_MAX]; +extern u16 gesture_coordinates_y[GESTURE_COORDS_REPORT_MAX]; +extern int gesture_coords_reported; +extern struct mutex gestureMask_mutex; +#endif struct fts_i2c_platform_data { int (*power)(bool on); @@ -119,21 +188,18 @@ struct fts_i2c_platform_data { int reset_gpio; const char *pwr_reg_name; const char *bus_reg_name; - }; /* * Forward declaration */ struct fts_ts_info; -extern char tag[8]; /* * Dispatch event handler */ -typedef unsigned char * (*event_dispatch_handler_t) -(struct fts_ts_info *info, unsigned char *data); - +typedef void (*event_dispatch_handler_t) + (struct fts_ts_info *info, unsigned char *data); /* * struct fts_ts_info - FTS capacitive touch screen device information * @dev: Pointer to the structure device @@ -141,109 +207,113 @@ typedef unsigned char * (*event_dispatch_handler_t) * @input_dev Input device structure * @work Work thread * @event_wq Event queue for work thread - * @cmd_done Asyncronous command notification * @event_dispatch_table Event dispatch table handlers - * @fw_version Firmware version * @attrs SysFS attributes - * @mode Device operating mode + * @mode Device operating mode (bitmask) * @touch_id Bitmask for touch id (mapped to input slots) - * @buttons Bitmask for buttons status + * @stylus_id Bitmask for tracking the stylus touches + * (mapped using the touchId) * @timer Timer when operating in polling mode - * @early_suspend Structure for early suspend functions * @power Power on/off routine + * @bdata HW info retrived from device tree + * @pwr_reg DVDD power regulator + * @bus_reg AVDD power regulator + * @resume_bit Indicate if screen off/on + * @fwupdate_stat Store the result of a fw update triggered by the host + * @notifier Used for be notified from a suspend/resume event + * @sensor_sleep true susped was called, false resume was called + * @wakelock Wake Lock struct + * @input_report_mutex mutex for handling the pressure of keys + * @series of switches to store the enabling status of a particular + * feature from the host */ - struct fts_ts_info { - struct device *dev; - struct i2c_client *client; - struct input_dev *input_dev; + struct device *dev; + struct i2c_client *client; + struct input_dev *input_dev; - struct work_struct work; - struct workqueue_struct *event_wq; + struct work_struct work; + struct work_struct suspend_work; + struct work_struct resume_work; + struct workqueue_struct *event_wq; - struct delayed_work fwu_work; - struct workqueue_struct *fwu_workqueue; - struct completion cmd_done; + struct delayed_work fwu_work; + struct workqueue_struct *fwu_workqueue; + struct completion cmd_done; - event_dispatch_handler_t *event_dispatch_table; + event_dispatch_handler_t *event_dispatch_table; - unsigned int fw_version; - unsigned int config_id; + struct attribute_group attrs; - struct attribute_group attrs; + unsigned int mode; + unsigned long touch_id; +#ifdef STYLUS_MODE + unsigned long stylus_id; +#endif - unsigned int mode; - unsigned long touch_id; - unsigned int buttons; #ifdef FTS_USE_POLLING_MODE - struct hrtimer timer; + struct hrtimer timer; #endif + #ifdef SCRIPTLESS - /*I2C cmd*/ - struct device *i2c_cmd_dev; - char cmd_read_result[CMD_RESULT_STR_LEN]; - char cmd_wr_result[CMD_RESULT_STR_LEN]; - char cmd_write_result[20]; + /*I2C cmd*/ + struct device *i2c_cmd_dev; + char cmd_read_result[CMD_RESULT_STR_LEN]; + char cmd_wr_result[CMD_RESULT_STR_LEN]; + char cmd_write_result[20]; #endif #ifdef DRIVER_TEST - struct device *test_cmd_dev; + struct device *test_cmd_dev; #endif + int (*power)(bool on); - int (*power)(bool on); - - struct fts_i2c_platform_data *bdata; - struct regulator *pwr_reg; - struct regulator *bus_reg; - - bool fw_force; - int debug_enable; - - int resume_bit; - int fwupdate_stat; - int touch_debug; - - struct notifier_block notifier; - bool sensor_sleep; - bool stay_awake; - - /* input lock */ - struct mutex input_report_mutex; - - /* switches */ - int gesture_enabled; - int glove_enabled; - + struct fts_i2c_platform_data *bdata; + struct regulator *pwr_reg; + struct regulator *bus_reg; + + int resume_bit; + int fwupdate_stat; + + struct notifier_block notifier; + bool sensor_sleep; + struct wakeup_source wakeup_source; + + /* input lock */ + struct mutex input_report_mutex; + + /*switches for features*/ + int gesture_enabled; + int glove_enabled; + int charger_enabled; + int stylus_enabled; + int vr_enabled; + int cover_enabled; + int edge_rej_enabled; + int corner_rej_enabled; + int edge_palm_rej_enabled; }; -typedef enum { - ERR_ITO_NO_ERR, /* < 0 No ITO Error */ - ERR_ITO_PANEL_OPEN_FORCE, /* < 1 Panel Open Force */ - ERR_ITO_PANEL_OPEN_SENSE, /* < 2 Panel Open Sense */ - ERR_ITO_F2G, /* < 3 Force short to ground */ - ERR_ITO_S2G, /* < 4 Sense short to ground */ - ERR_ITO_F2VDD, /* < 5 Force short to VDD */ - ERR_ITO_S2VDD, /* < 6 Sense short to VDD */ - ERR_ITO_P2P_FORCE, /* < 7 Pin to Pin short (Force) */ - ERR_ITO_P2P_SENSE, /* < 8 Pin to Pin short (Sense) */ -} errItoSubTypes_t; +extern struct chipInfo ftsInfo; int fts_chip_powercycle(struct fts_ts_info *info); int fts_chip_powercycle2(struct fts_ts_info *info, unsigned long sleep); -int fts_get_fw_version(struct fts_ts_info *info); -extern unsigned int le_to_uint(const unsigned char *ptr); -extern unsigned int be_to_uint(const unsigned char *ptr); +/*int fts_get_fw_version(struct fts_ts_info *info);*/ +/*extern unsigned int le_to_uint(const unsigned char *ptr);*/ +/*extern unsigned int be_to_uint(const unsigned char *ptr);*/ extern int input_register_notifier_client(struct notifier_block *nb); extern int input_unregister_notifier_client(struct notifier_block *nb); #ifdef SCRIPTLESS -extern struct attribute_group i2c_cmd_attr_group; +extern struct attribute_group i2c_cmd_attr_group; #endif #ifdef DRIVER_TEST -extern struct attribute_group test_cmd_attr_group; +extern struct attribute_group test_cmd_attr_group; #endif + #endif + diff --git a/drivers/input/touchscreen/st/fts_driver_test.c b/drivers/input/touchscreen/st/fts_driver_test.c index 5c55d8e4ac88..e8fe81de2911 100644 --- a/drivers/input/touchscreen/st/fts_driver_test.c +++ b/drivers/input/touchscreen/st/fts_driver_test.c @@ -1,17 +1,22 @@ /* - -************************************************************************** -** STMicroelectronics ** -************************************************************************** -** marco.cali@st.com ** -************************************************************************** -* * -* API used by Driver Test Apk * -* * -************************************************************************** -************************************************************************** - -*/ + * FTS Capacitive touch screen controller (FingerTipS) + * + * Copyright (C) 2016-2018, STMicroelectronics Limited. + * Authors: AMG(Analog Mems Group) + * + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + */ #include #include @@ -27,6 +32,8 @@ #include #include #include +/*#include */ +#include #include #include @@ -43,64 +50,64 @@ #ifdef DRIVER_TEST -#define MAX_PARAMS 10 - -/* DEFINE COMMANDS TO TEST */ -#define CMD_READ 0x00 -#define CMD_WRITE 0x01 -#define CMD_READU16 0x02 -#define CMD_READB2 0x03 -#define CMD_READB2U16 0x04 -#define CMD_POLLFOREVENT 0x05 -#define CMD_SYSTEMRESET 0x06 -#define CMD_CLEANUP 0x07 -#define CMD_GETFORCELEN 0x08 -#define CMD_GETSENSELEN 0x09 -#define CMD_GETMSFRAME 0x0A -/* #define CMD_GETMSKEYFRAME 0x0B */ -#define CMD_GETSSFRAME 0x0C -#define CMD_REQCOMPDATA 0x0D -#define CMD_READCOMPDATAHEAD 0x0E -#define CMD_READMSCOMPDATA 0x0F -#define CMD_READSSCOMPDATA 0x10 -#define CMD_READGNCOMPDATA 0x11 -#define CMD_GETFWVER 0x12 -#define CMD_FLASHSTATUS 0x13 -#define CMD_FLASHUNLOCK 0x14 -#define CMD_READFWFILE 0x15 -#define CMD_FLASHPROCEDURE 0x16 -#define CMD_ITOTEST 0x17 -#define CMD_INITTEST 0x18 -#define CMD_MSRAWTEST 0x19 -#define CMD_MSINITDATATEST 0x1A -#define CMD_SSRAWTEST 0x1B -#define CMD_SSINITDATATEST 0x1C -#define CMD_MAINTEST 0x1D -#define CMD_POWERCYCLE 0x1E -#define CMD_FWWRITE 0x1F -#define CMD_READCHIPINFO 0x20 -#define CMD_REQFRAME 0x21 - -u32 *functionToTest; -int numberParam; +#define MAX_PARAMS 50 + +/*DEFINE COMMANDS TO TEST*/ +#define CMD_READ 0x00 +#define CMD_WRITE 0x01 +#define CMD_READU16 0x02 +#define CMD_READB2 0x03 +#define CMD_READB2U16 0x04 +#define CMD_POLLFOREVENT 0x05 +#define CMD_SYSTEMRESET 0x06 +#define CMD_CLEANUP 0x07 +#define CMD_GETFORCELEN 0x08 +#define CMD_GETSENSELEN 0x09 +#define CMD_GETMSFRAME 0x0A +/*#define CMD_GETMSKEYFRAME 0x0B*/ +#define CMD_GETSSFRAME 0x0C +#define CMD_REQCOMPDATA 0x0D +#define CMD_READCOMPDATAHEAD 0x0E +#define CMD_READMSCOMPDATA 0x0F +#define CMD_READSSCOMPDATA 0x10 +#define CMD_READGNCOMPDATA 0x11 +#define CMD_GETFWVER 0x12 +#define CMD_FLASHSTATUS 0x13 +#define CMD_FLASHUNLOCK 0x14 +#define CMD_READFWFILE 0x15 +#define CMD_FLASHPROCEDURE 0x16 +#define CMD_ITOTEST 0x17 +#define CMD_INITTEST 0x18 +#define CMD_MSRAWTEST 0x19 +#define CMD_MSINITDATATEST 0x1A +#define CMD_SSRAWTEST 0x1B +#define CMD_SSINITDATATEST 0x1C +#define CMD_MAINTEST 0x1D +#define CMD_POWERCYCLE 0x1E +#define CMD_FWWRITE 0x1F +#define CMD_READCHIPINFO 0x20 +#define CMD_REQFRAME 0x21 + +static char tag[8] = "[ FTS ]\0"; +static u32 functionToTest[MAX_PARAMS]; +static int numberParam; static ssize_t stm_driver_test_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count) { + struct device_attribute *attr, const char *buf, size_t count) +{ int n; - char *p = (char *) buf; + char *p = (char *)buf; + int ret; - functionToTest = (u32 *) kmalloc(MAX_PARAMS * sizeof (u32), GFP_KERNEL); - if (functionToTest == NULL) { - logError(1, "%s impossible to allocate functionToTest!\n", tag); - return count; - } - memset(functionToTest, 0, MAX_PARAMS * sizeof (u32)); + memset(functionToTest, 0, MAX_PARAMS * sizeof(u32)); for (n = 0; n < (count + 1) / 3 && n < MAX_PARAMS; n++) { - sscanf(p, "%02X ", &functionToTest[n]); + ret = sscanf(p, "%02X ", &functionToTest[n]); + if (ret != 1) + return -EINVAL; p += 3; - logError(1, "%s functionToTest[%d] = %02X\n", tag, n, functionToTest[n]); - + logError(1, "%s functionToTest[%d] = %02X\n", tag, n, + functionToTest[n]); } numberParam = n; @@ -108,34 +115,37 @@ static ssize_t stm_driver_test_store(struct device *dev, return count; } -static ssize_t stm_driver_test_show(struct device *dev, struct device_attribute *attr, - char *buf) { +static ssize_t stm_driver_test_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ char buff[CMD_STR_LEN] = {0}; int res = -1, j, count; - /* int res2; */ int size = 6 * 2; - int temp, i, byteToRead; + int temp = 0; + int i; + int byteToRead = 0; u8 *readData = NULL; u8 *all_strbuff = NULL; - u8 *cmd; + u8 *cmd = NULL; - MutualSenseFrame frameMS; - SelfSenseFrame frameSS; + struct MutualSenseFrame frameMS; + struct SelfSenseFrame frameSS; - DataHeader dataHead; - MutualSenseData compData; - SelfSenseData comData; - GeneralData gnData; + struct DataHeader dataHead; + struct MutualSenseData compData; + struct SelfSenseData comData; + struct GeneralData gnData; u16 address; u16 fw_version; u16 config_id; - Firmware fw; + struct Firmware fw; - /* struct used for defining which test perform during the MP test */ + /*struct used for defining which test*/ + /*perform during the MP test*/ - TestToDo todoDefault; + struct TestToDo todoDefault; struct i2c_client *client = to_i2c_client(dev); struct fts_ts_info *info = i2c_get_clientdata(client); @@ -181,495 +191,661 @@ static ssize_t stm_driver_test_show(struct device *dev, struct device_attribute todoDefault.SelfSenseCxTotal = 0; todoDefault.SelfSenseCxTotalAdj = 0; - if (numberParam >= 1 && functionToTest != NULL) { - res = fts_disableInterrupt(); - if (res < 0) { - logError(0, "%s stm_driver_test_show: ERROR %08X\n", tag, res); - res = (res | ERROR_DISABLE_INTER); - goto END; - } - switch (functionToTest[0]) { - case CMD_READ: - if (numberParam >= 4) { - temp = (int) functionToTest[1]; - if (numberParam == 4 + (temp - 1) && temp != 0) { - cmd = (u8 *) kmalloc(temp * sizeof (u8), GFP_KERNEL); - for (i = 0; i < temp; i++) { - cmd[i] = functionToTest[i + 2]; - } - byteToRead = functionToTest[i + 2]; - readData = (u8 *) kmalloc(byteToRead * sizeof (u8), GFP_KERNEL); - res = fts_readCmd(cmd, temp, readData, byteToRead); - size += (byteToRead * sizeof (u8))*2; - } else { - logError(1, "%s Wrong parameters!\n", tag); - res = ERROR_OP_NOT_ALLOW; - } - - } else { - logError(1, "%s Wrong number of parameters!\n", tag); - res = ERROR_OP_NOT_ALLOW; - } - break; - - case CMD_WRITE: - if (numberParam >= 3) { /* need to pass: cmdLength cmd[0] cmd[1] … cmd[cmdLength-1] */ - temp = (int) functionToTest[1]; - if (numberParam == 3 + (temp - 1) && temp != 0) { - cmd = (u8 *) kmalloc(temp * sizeof (u8), GFP_KERNEL); - for (i = 0; i < temp; i++) { - cmd[i] = functionToTest[i + 2]; - } - res = fts_writeCmd(cmd, temp); - } else { - logError(1, "%s Wrong parameters!\n", tag); - res = ERROR_OP_NOT_ALLOW; - } + if (numberParam < 1) { + logError(1, "%s NO COMMAND SPECIFIED!!! ", tag); + logError(1, "do: 'echo [cmd_code] [args] > stm_fts_cmd' "); + logError(1, "before looking for result!\n"); + res = ERROR_OP_NOT_ALLOW; + goto END; + } - } else { - logError(1, "%s Wrong number of parameters!\n", tag); - res = ERROR_OP_NOT_ALLOW; - } + res = fts_disableInterrupt(); + if (res < 0) { + logError(0, "%s %s: ERROR %08X\n", tag, __func__, res); + res = (res | ERROR_DISABLE_INTER); + goto END; + } + switch (functionToTest[0]) { + case CMD_READ: + if (numberParam != 4) { + logError(1, "%s Wrong number of parameters!\n", tag); + res = ERROR_OP_NOT_ALLOW; break; + } + /** + * need to pass:cmdLength + * cmd[0]cmd[1]…cmd[cmdLength-1] + * byteToRead + */ + temp = (int)functionToTest[1]; + if (numberParam == 4 + (temp - 1) && temp != 0) { + cmd = (u8 *)kmalloc_array(temp, sizeof(u8), GFP_KERNEL); + for (i = 0; i < temp; i++) + cmd[i] = functionToTest[i + 2]; + byteToRead = functionToTest[i + 2]; + readData = (u8 *)kmalloc_array(byteToRead, sizeof(u8), + GFP_KERNEL); + res = fts_readCmd(cmd, temp, readData, byteToRead); + size += (byteToRead * sizeof(u8)) * 2; + kfree(cmd); + } else { + logError(1, "%s Wrong parameters!\n", tag); + res = ERROR_OP_NOT_ALLOW; + } + break; - case CMD_FWWRITE: - if (numberParam >= 3) { /* need to pass: cmdLength cmd[0] cmd[1] … cmd[cmdLength-1] */ - temp = (int) functionToTest[1]; - if (numberParam == 3 + (temp - 1) && temp != 0) { - cmd = (u8 *) kmalloc(temp * sizeof (u8), GFP_KERNEL); - for (i = 0; i < temp; i++) { - cmd[i] = functionToTest[i + 2]; - } - res = fts_writeFwCmd(cmd, temp); - } else { - logError(1, "%s Wrong parameters!\n", tag); - res = ERROR_OP_NOT_ALLOW; - } - - } else { - logError(1, "%s Wrong number of parameters!\n", tag); - res = ERROR_OP_NOT_ALLOW; - } + case CMD_WRITE: + if (numberParam != 3) { + logError(1, "%s Wrong number of parameters!\n", tag); + res = ERROR_OP_NOT_ALLOW; break; + } + /** + * need to pass:cmdLength + * cmd[0] cmd[1]…cmd[cmdLength-1] + */ + temp = (int)functionToTest[1]; + if (numberParam == 3 + (temp - 1) && temp != 0) { + cmd = (u8 *)kmalloc_array(temp, sizeof(u8), GFP_KERNEL); + for (i = 0; i < temp; i++) + cmd[i] = functionToTest[i + 2]; + res = fts_writeCmd(cmd, temp); + kfree(cmd); + } else { + logError(1, "%s Wrong parameters!\n", tag); + res = ERROR_OP_NOT_ALLOW; + } + break; - case CMD_READU16: - if (numberParam == 6) { /* need to pass: cmd addr[0] addr[1] byteToRead hasDummyByte */ - byteToRead = functionToTest[4]; - readData = (u8 *) kmalloc(byteToRead * sizeof (u8), GFP_KERNEL); - res = readCmdU16((u8) functionToTest[1], (u16) ((((u8) functionToTest[2] & 0x00FF) << 8) + ((u8) functionToTest[3] & 0x00FF)), readData, byteToRead, functionToTest[5]); - size += (byteToRead * sizeof (u8))*2; - } else { - logError(1, "%s Wrong number of parameters!\n", tag); - res = ERROR_OP_NOT_ALLOW; - } + case CMD_FWWRITE: + if (numberParam != 3) { + logError(1, "%s Wrong number parameters!\n", tag); + res = ERROR_OP_NOT_ALLOW; break; + } + /** + * need to pass:cmdLength + * cmd[0] cmd[1]…cmd[cmdLength-1] + */ + temp = (int)functionToTest[1]; + if (numberParam == 3 + (temp - 1) && temp != 0) { + cmd = (u8 *)kmalloc_array(temp, sizeof(u8), GFP_KERNEL); + for (i = 0; i < temp; i++) + cmd[i] = functionToTest[i + 2]; + res = fts_writeFwCmd(cmd, temp); + kfree(cmd); + } else { + logError(1, "%s Wrong parameters!\n", tag); + res = ERROR_OP_NOT_ALLOW; + } + break; - case CMD_READB2: - if (numberParam == 4) { /* need to pass: addr[0] addr[1] byteToRead */ - byteToRead = functionToTest[3]; - readData = (u8 *) kmalloc(byteToRead * sizeof (u8), GFP_KERNEL); - res = readB2((u16) ((((u8) functionToTest[1] & 0x00FF) << 8) + ((u8) functionToTest[2] & 0x00FF)), readData, byteToRead); - size += (byteToRead * sizeof (u8))*2; - } else { - logError(1, "%s Wrong number of parameters!\n", tag); - res = ERROR_OP_NOT_ALLOW; - } + case CMD_READU16: + if (numberParam != 6) { + logError(1, "%s Wrong number parameters!\n", tag); + res = ERROR_OP_NOT_ALLOW; break; - - case CMD_READB2U16: - if (numberParam == 4) { /* need to pass: addr[0] addr[1] byteToRead */ - byteToRead = functionToTest[3]; - readData = (u8 *) kmalloc(byteToRead * sizeof (u8), GFP_KERNEL); - res = readB2U16((u16) ((((u8) functionToTest[1] & 0x00FF) << 8) + ((u8) functionToTest[2] & 0x00FF)), readData, byteToRead); - size += (byteToRead * sizeof (u8))*2; - } else { - logError(1, "%s Wrong number of parameters!\n", tag); - res = ERROR_OP_NOT_ALLOW; - } + } + /** + * need to pass: cmd addr[0] addr[1] + * byteToRead hasDummyByte + */ + byteToRead = functionToTest[4]; + readData = kmalloc_array(byteToRead, + sizeof(u8), GFP_KERNEL); + res = readCmdU16((u8)functionToTest[1], + (u16)((((u8) functionToTest[2] + & 0x00FF) << 8) + ((u8) functionToTest[3] + & 0x00FF)), + readData, + byteToRead, + functionToTest[5]); + size += (byteToRead * sizeof(u8)) * 2; + break; + + case CMD_READB2: + if (numberParam != 4) { + logError(1, "%s Wrong number of parameters!\n", tag); + res = ERROR_OP_NOT_ALLOW; break; - - case CMD_POLLFOREVENT: - if (numberParam >= 5) { /* need to pass: eventLength event[0] event[1] event[eventLength-1] timeTowait */ - temp = (int) functionToTest[1]; - if (numberParam == 5 + (temp - 1) && temp != 0) { - readData = (u8 *) kmalloc(FIFO_EVENT_SIZE * sizeof (u8), GFP_KERNEL); - res = pollForEvent((int *) &functionToTest[2], temp, readData, ((functionToTest[temp + 2] & 0x00FF) << 8)+(functionToTest[temp + 3] & 0x00FF)); - if (res >= OK) - res = OK; /* pollForEvent return the number of error found */ - size += (FIFO_EVENT_SIZE * sizeof (u8))*2; - byteToRead = FIFO_EVENT_SIZE; - } else { - logError(1, "%s Wrong parameters!\n", tag); - res = ERROR_OP_NOT_ALLOW; - } - - } else { - logError(1, "%s Wrong number of parameters!\n", tag); - res = ERROR_OP_NOT_ALLOW; - } + } + /*need to pass: addr[0] addr[1] byteToRead*/ + byteToRead = functionToTest[3]; + readData = kmalloc_array(byteToRead, + sizeof(u8), GFP_KERNEL); + res = readB2((u16)( + (((u8)functionToTest[1] & 0x00FF) << 8) + + ((u8) functionToTest[2] & 0x00FF)), + readData, + byteToRead); + size += (byteToRead * sizeof(u8)) * 2; + break; + + case CMD_READB2U16: + if (numberParam != 4) { + logError(1, "%s Wrong number of parameters!\n", tag); + res = ERROR_OP_NOT_ALLOW; break; - - case CMD_SYSTEMRESET: - res = fts_system_reset(); - + } + /*need to pass: addr[0] addr[1] byteToRead*/ + byteToRead = functionToTest[3]; + readData = (u8 *)kmalloc_array(byteToRead, + sizeof(u8), GFP_KERNEL); + res = readB2U16((u16)((((u8)functionToTest[1] + & 0x00FF) << 8) + ((u8)functionToTest[2] + & 0x00FF)), readData, byteToRead); + size += (byteToRead * sizeof(u8)) * 2; + break; + + case CMD_POLLFOREVENT: + if (numberParam < 5) { + logError(1, "%s Wrong number of parameters!\n", tag); + res = ERROR_OP_NOT_ALLOW; break; + } - case CMD_READCHIPINFO: - if (numberParam == 2) { /* need to pass: doRequest */ - res = readChipInfo(functionToTest[1]); - } else { - logError(1, "%s Wrong number of parameters!\n", tag); - res = ERROR_OP_NOT_ALLOW; - } - - break; + /** + * need to pass: eventLength event[0] event[1] + * … event[eventLength-1] timeTowait + */ + temp = (int)functionToTest[1]; + if (numberParam == 5 + (temp - 1) && temp != 0) { + readData = (u8 *)kmalloc_array(FIFO_EVENT_SIZE, + sizeof(u8), GFP_KERNEL); + res = pollForEvent((int *)&functionToTest[2], + temp, + readData, + ((functionToTest[temp + 2] & 0x00FF) << 8) + + (functionToTest[temp + 3] & 0x00FF)); + //pollForEvent return the number of error found + if (res >= OK) + res = OK; + size += (FIFO_EVENT_SIZE * sizeof(u8)) * 2; + byteToRead = FIFO_EVENT_SIZE; + } else { + logError(1, "%s Wrong parameters!\n", tag); + res = ERROR_OP_NOT_ALLOW; + } + break; - case CMD_CLEANUP: /* TOUCH ENABLE/DISABLE */ - if (numberParam == 2) { /* need to pass: enableTouch */ - res = cleanUp(functionToTest[1]); - } else { - logError(1, "%s Wrong number of parameters!\n", tag); - res = ERROR_OP_NOT_ALLOW; - } + case CMD_SYSTEMRESET: + res = fts_system_reset(); + break; + case CMD_READCHIPINFO: + if (numberParam != 2) { + logError(1, "%s Wrong number of parameters!\n", tag); + res = ERROR_OP_NOT_ALLOW; break; - - case CMD_GETFORCELEN: /* read number Tx channels */ - temp = getForceLen(); - if (temp < OK) - res = temp; - else { - size += (1 * sizeof (u8))*2; - res = OK; - } + } + /*need to pass: doRequest */ + res = readChipInfo(functionToTest[1]); + break; + + /* TOUCH ENABLE/DISABLE */ + case CMD_CLEANUP: + if (numberParam != 2) { + logError(1, "%s Wrong number of parameters!\n", tag); + res = ERROR_OP_NOT_ALLOW; break; + } + /* need to pass: enableTouch*/ + res = cleanUp(functionToTest[1]); + break; + + case CMD_GETFORCELEN: + /*read number Tx channels */ + temp = getForceLen(); + if (temp < OK) + res = temp; + else { + size += (1 * sizeof(u8)) * 2; + res = OK; + } + break; + + case CMD_GETSENSELEN: + /* read number Rx channels */ + temp = getSenseLen(); + if (temp < OK) + res = temp; + else { + size += (1 * sizeof(u8)) * 2; + res = OK; + } + break; - case CMD_GETSENSELEN: /* read number Rx channels */ - temp = getSenseLen(); - if (temp < OK) - res = temp; - else { - size += (1 * sizeof (u8))*2; - res = OK; - } + case CMD_REQFRAME: + /* request a frame */ + if (numberParam != 3) { + logError(1, "%s Wrong number of parameters!\n", tag); + res = ERROR_OP_NOT_ALLOW; break; + } + logError(0, "%s Requesting Frame\n", tag); + res = requestFrame((u16)((((u8)functionToTest[1] & 0x00FF) << 8) + + ((u8)functionToTest[2] & 0x00FF))); + + if (res < OK) { + logError(0, "%s Err requesting frame ERROR:%02X\n", + tag, res); + } else { + logError(0, "%s Requesting Frame Finished!\n", tag); + } + break; - case CMD_REQFRAME: /* request a frame */ - if (numberParam == 3) { - logError(0, "%s Requesting Frame\n", tag); - res = requestFrame((u16) ((((u8) functionToTest[1] & 0x00FF) << 8) + ((u8) functionToTest[2] & 0x00FF))); - - if (res < OK) { - logError(0, "%s Error requesting frame ERROR %02X\n", tag, res); - } else { - logError(0, "%s Requesting Frame Finished!\n", tag); - } - } else { - logError(1, "%s Wrong number of parameters!\n", tag); - res = ERROR_OP_NOT_ALLOW; - } - break; - - case CMD_GETMSFRAME: - if (numberParam == 3) { - logError(0, "%s Get 1 MS Frame\n", tag); - flushFIFO(); /* delete the events related to some touch (allow to call this function while touching the sreen without having a flooding of the FIFO) */ - res = getMSFrame2((u16) ((((u8) functionToTest[1] & 0x00FF) << 8) + ((u8) functionToTest[2] & 0x00FF)), &frameMS); - if (res < 0) { - logError(0, "%s Error while taking the MS frame... ERROR %02X\n", tag, res); - - } else { - logError(0, "%s The frame size is %d words\n", tag, res); - size = (res * sizeof (short) + 8)*2; - /* set res to OK because if getMSFrame is - successful res = number of words read - */ - res = OK; - print_frame_short("MS frame =", array1dTo2d_short(frameMS.node_data, frameMS.node_data_size, frameMS.header.sense_node), frameMS.header.force_node, frameMS.header.sense_node); - } - } else { - logError(1, "%s Wrong number of parameters!\n", tag); - res = ERROR_OP_NOT_ALLOW; - } + case CMD_GETMSFRAME: + if (numberParam != 3) { + logError(1, "%s Wrong number of param!\n", tag); + res = ERROR_OP_NOT_ALLOW; break; + } + logError(0, "%s Get 1 MS Frame\n", tag); + flushFIFO(); + /** + * delete the events related to some + * touch (allow to call this function + * while touching the sreen without + * having a flooding of the FIFO) + */ + res = getMSFrame2((u16)((((u8)functionToTest[1] & 0x00FF) << 8) + + ((u8)functionToTest[2] & 0x00FF)), &frameMS); + if (res < 0) { + logError(0, "%s Err while taking MS frame:%02X\n", + tag, res); + } else { + logError(0, "%s:frame size is %d words\n", tag, res); + size = (res * sizeof(short) + 8) * 2; + /*set res to OK because if getMSFrame is*/ + /*successful res = number of words read*/ + res = OK; + print_frame_short("MS frame =", + array1dTo2d_short(frameMS.node_data, + frameMS.node_data_size, + frameMS.header.sense_node), + frameMS.header.force_node, + frameMS.header.sense_node); + } + break; - /*read self raw*/ - case CMD_GETSSFRAME: - if (numberParam == 3) { - logError(0, "%s Get 1 SS Frame\n", tag); - flushFIFO(); /* delete the events related to some touch (allow to call this function while touching the sreen without having a flooding of the FIFO) */ - res = getSSFrame2((u16) ((((u8) functionToTest[1] & 0x00FF) << 8) + ((u8) functionToTest[2] & 0x00FF)), &frameSS); - - if (res < OK) { - logError(0, "%s Error while taking the SS frame... ERROR %02X\n", tag, res); - - } else { - logError(0, "%s The frame size is %d words\n", tag, res); - size = (res * sizeof (short) + 8)*2+1; - /* set res to OK because if getMSFrame is - successful res = number of words read - */ - res = OK; - print_frame_short("SS force frame =", array1dTo2d_short(frameSS.force_data, frameSS.header.force_node, 1), frameSS.header.force_node, 1); - print_frame_short("SS sense frame =", array1dTo2d_short(frameSS.sense_data, frameSS.header.sense_node, frameSS.header.sense_node), 1, frameSS.header.sense_node); - } - } else { - logError(1, "%s Wrong number of parameters!\n", tag); - res = ERROR_OP_NOT_ALLOW; - } + /*read self raw*/ + case CMD_GETSSFRAME: + if (numberParam != 3) { + logError(1, "%s Wrong number of parameters!\n", tag); + res = ERROR_OP_NOT_ALLOW; break; + } - case CMD_REQCOMPDATA: /* request comp data */ - if (numberParam == 3) { - logError(0, "%s Requesting Compensation Data\n", tag); - res = requestCompensationData((u16) ((((u8) functionToTest[1] & 0x00FF) << 8) + ((u8) functionToTest[2] & 0x00FF))); - - if (res < OK) { - logError(0, "%s Error requesting compensation data ERROR %02X\n", tag, res); - } else { - logError(0, "%s Requesting Compensation Data Finished!\n", tag); - } - } else { - logError(1, "%s Wrong number of parameters!\n", tag); - res = ERROR_OP_NOT_ALLOW; - } - break; + logError(0, "%s Get 1 SS Frame\n", tag); + flushFIFO(); + /** + * delete the events related to some + * touch (allow to call this function + * while touching the sreen without + * having a flooding of the FIFO) + */ + res = getSSFrame2((u16)((((u8)functionToTest[1] & 0x00FF) << 8) + + ((u8)functionToTest[2] & 0x00FF)), &frameSS); + + if (res < OK) { + logError(0, + "%s Error while taking the SS frame... ERROR %02X\n", + tag, res); + } else { + logError(0, "%s The frame size is %d words\n", + tag, res); + size = (res * sizeof(short) + 8) * 2 + 1; + + /*set res to OK because if getMSFrame is*/ + /*successful res = number of words read*/ + res = OK; + print_frame_short("SS force frame =", + array1dTo2d_short(frameSS.force_data, + frameSS.header.force_node, 1), + frameSS.header.force_node, + 1); + print_frame_short("SS sense frame =", + array1dTo2d_short(frameSS.sense_data, + frameSS.header.sense_node, + frameSS.header.sense_node), + 1, + frameSS.header.sense_node); + } + break; - case CMD_READCOMPDATAHEAD: /* read comp data header */ - if (numberParam == 3) { - logError(0, "%s Requesting Compensation Data\n", tag); - res = requestCompensationData((u16) ((((u8) functionToTest[1] & 0x00FF) << 8) + ((u8) functionToTest[2] & 0x00FF))); - if (res < OK) { - logError(0, "%s Error requesting compensation data ERROR %02X\n", tag, res); - } else { - logError(0, "%s Requesting Compensation Data Finished!\n", tag); - res = readCompensationDataHeader((u16) ((((u8) functionToTest[1] & 0x00FF) << 8) + ((u8) functionToTest[2] & 0x00FF)), &dataHead, &address); - if (res < OK) { - logError(0, "%s Read Compensation Data Header ERROR %02X\n", tag, res); - } else { - logError(0, "%s Read Compensation Data Header OK!\n", tag); - size += (2 * sizeof (u8))*2; - } - } - } else { - logError(1, "%s Wrong number of parameters!\n", tag); - res = ERROR_OP_NOT_ALLOW; - } + case CMD_REQCOMPDATA: + /*request comp data*/ + if (numberParam != 3) { + logError(1, "%s Wrong number of parameters!\n", tag); + res = ERROR_OP_NOT_ALLOW; break; + } - case CMD_READMSCOMPDATA: /* read mutual comp data */ - if (numberParam == 3) { - logError(0, "%s Get MS Compensation Data\n", tag); - res = readMutualSenseCompensationData((u16) ((((u8) functionToTest[1] & 0x00FF) << 8) + ((u8) functionToTest[2] & 0x00FF)), &compData); + logError(0, "%s Requesting Compensation Data\n", tag); + res = requestCompensationData((u16) + ((((u8)functionToTest[1] & 0x00FF) << 8) + + ((u8)functionToTest[2] & 0x00FF))); + + if (res < OK) { + logError(0, + "%s Error requesting compensation data ERROR %02X\n", + tag, res); + } else { + logError(0, + "%s Requesting Compensation Data Finished!\n", + tag); + } + break; - if (res < OK) { - logError(0, "%s Error reading MS compensation data ERROR %02X\n", tag, res); - } else { - logError(0, "%s MS Compensation Data Reading Finished!\n", tag); - size = ((compData.node_data_size + 9) * sizeof (u8))*2; - print_frame_u8("MS Data (Cx2) =", array1dTo2d_u8(compData.node_data, compData.node_data_size, compData.header.sense_node), compData.header.force_node, compData.header.sense_node); - } - } else { - logError(1, "%s Wrong number of parameters!\n", tag); - res = ERROR_OP_NOT_ALLOW; - } + case CMD_READCOMPDATAHEAD: + /*read comp data header*/ + if (numberParam != 3) { + logError(1, "%s Wrong number of parameters!\n", tag); + res = ERROR_OP_NOT_ALLOW; break; + } - case CMD_READSSCOMPDATA: - if (numberParam == 3) { /* read self comp data */ - logError(0, "%s Get SS Compensation Data...\n", tag); - res = readSelfSenseCompensationData((u16) ((((u8) functionToTest[1] & 0x00FF) << 8) + ((u8) functionToTest[2] & 0x00FF)), &comData); - if (res < OK) { - logError(0, "%s Error reading SS compensation data ERROR %02X\n", tag, res); - } else { - logError(0, "%s SS Compensation Data Reading Finished!\n", tag); - size = ((comData.header.force_node + comData.header.sense_node)*2 + 12) * sizeof (u8)*2; - print_frame_u8("SS Data Ix2_fm = ", array1dTo2d_u8(comData.ix2_fm, comData.header.force_node, comData.header.force_node), 1, comData.header.force_node); - print_frame_u8("SS Data Cx2_fm = ", array1dTo2d_u8(comData.cx2_fm, comData.header.force_node, comData.header.force_node), 1, comData.header.force_node); - print_frame_u8("SS Data Ix2_sn = ", array1dTo2d_u8(comData.ix2_sn, comData.header.sense_node, comData.header.sense_node), 1, comData.header.sense_node); - print_frame_u8("SS Data Cx2_sn = ", array1dTo2d_u8(comData.cx2_sn, comData.header.sense_node, comData.header.sense_node), 1, comData.header.sense_node); - } + logError(0, "%s Requesting Compensation Data\n", tag); + res = requestCompensationData( + (u16) ((((u8)functionToTest[1] & 0x00FF) << 8) + + ((u8)functionToTest[2] & 0x00FF))); + if (res < OK) { + logError(0, "%s Error requesting:%02X\n", tag, res); + } else { + logError(0, + "%s Requesting Compensation Data Finished!\n", tag); + res = readCompensationDataHeader( + (u16)((((u8)functionToTest[1] & 0x00FF) << 8) + +((u8)functionToTest[2] & 0x00FF)), + &dataHead, + &address); + if (res < OK) { + logError(0, "%s Read Header ERROR:%02X\n", + tag, res); } else { - logError(1, "%s Wrong number of parameters!\n", tag); - res = ERROR_OP_NOT_ALLOW; + logError(0, "%s Read Header OK!\n", tag); + size += (2 * sizeof(u8)) * 2; } + } + break; + case CMD_READMSCOMPDATA: + if (numberParam != 3) { + logError(1, "%s Wrong number of parameters!\n", tag); + res = ERROR_OP_NOT_ALLOW; break; - - case CMD_READGNCOMPDATA: - if (numberParam == 3) { /* read self comp data */ - logError(0, "%s Get General Compensation Data...\n", tag); - res = readGeneralCompensationData((u16) ((((u8) functionToTest[1] & 0x00FF) << 8) + ((u8) functionToTest[2] & 0x00FF)), &gnData); - if (res < OK) { - logError(0, "%s Error reading General compensation data ERROR %02X\n", tag, res); - } else { - logError(0, "%s General Compensation Data Reading Finished!\n", tag); - size = (14) * sizeof (u8)*2; - } - } else { - logError(1, "%s Wrong number of parameters!\n", tag); - res = ERROR_OP_NOT_ALLOW; - } + } + /*read mutual comp data */ + logError(0, "%s Get MS Compensation Data\n", tag); + res = readMutualSenseCompensationData( + (u16)((((u8)functionToTest[1] & 0x00FF) << 8) + + ((u8)functionToTest[2] & 0x00FF)), + &compData); + + if (res < OK) { + logError(0, "%s Error reading MS compe data:%02X\n", + tag, res); + } else { + logError(0, "%s MS Compensa Reading Finished!\n", + tag); + + size = ((compData.node_data_size + 9) * sizeof(u8)) * 2; + print_frame_u8("MS Data (Cx2) = ", + array1dTo2d_u8(compData.node_data, + compData.node_data_size, + compData.header.sense_node), + compData.header.force_node, + compData.header.sense_node); + } + break; + case CMD_READSSCOMPDATA: + if (numberParam != 3) { + logError(1, "%sWrong number of parameters!\n", tag); + res = ERROR_OP_NOT_ALLOW; break; + } - case CMD_GETFWVER: - res = getFirmwareVersion(&fw_version, &config_id); - if (res < OK) { - logError(1, "%s Error reading firmware version and config id ERROR %02X\n", tag, res); - } else { - logError(0, "%s getFirmwareVersion Finished!\n", tag); - size += (4) * sizeof (u8)*2; - } + /*read self comp data*/ + logError(0, "%s Get SS Compensation Data...\n", tag); + res = readSelfSenseCompensationData((u16) + ((((u8)functionToTest[1] & 0x00FF) << 8) + + ((u8)functionToTest[2] & 0x00FF)), + &comData); + if (res < OK) { + logError(0, "%s Error reading SS Compensa data %02X\n", + tag, res); + } else { + logError(0, "%s SS Compensa Reading Finished!\n", tag); + size = comData.header.force_node + + comData.header.sense_node; + size = (size * 2 + 12) * sizeof(u8) * 2; + print_frame_u8("SS Data Ix2_fm = ", + array1dTo2d_u8(comData.ix2_fm, + comData.header.force_node, + comData.header.force_node), + 1, + comData.header.force_node); + print_frame_u8("SS Data Cx2_fm = ", + array1dTo2d_u8(comData.cx2_fm, + comData.header.force_node, + comData.header.force_node), + 1, + comData.header.force_node); + print_frame_u8("SS Data Ix2_sn = ", + array1dTo2d_u8(comData.ix2_sn, + comData.header.sense_node, + comData.header.sense_node), + 1, + comData.header.sense_node); + print_frame_u8("SS Data Cx2_sn = ", + array1dTo2d_u8(comData.cx2_sn, + comData.header.sense_node, + comData.header.sense_node), + 1, + comData.header.sense_node); + } + break; + + case CMD_READGNCOMPDATA: + if (numberParam != 3) { + logError(1, "%s Wrong number of parameters!\n", tag); + res = ERROR_OP_NOT_ALLOW; break; + } + /*read self comp data */ + logError(0, "%s Get General Compensation Data...\n", tag); + res = readGeneralCompensationData((u16) + ((((u8)functionToTest[1] + & 0x00FF) << 8) + ((u8)functionToTest[2] + & 0x00FF)), &gnData); + if (res < OK) { + logError(0, + "%s Reading General compensa data ERROR %02X\n", + tag, res); + } else { + logError(0, "%s:General compensa Reading Finished!\n", + tag); + size = (14) * sizeof(u8) * 2; + } + break; + case CMD_GETFWVER: + res = getFirmwareVersion(&fw_version, &config_id); + if (res < OK) { + logError(1, "%s Reading firmware version ERROR %02X\n", + tag, res); + } else { + logError(0, "%s getFirmware Version Finished!\n", tag); + size += (4) * sizeof(u8) * 2; + } + break; #ifdef FTM3_CHIP - case CMD_FLASHSTATUS: - res = flash_status(); /* return 0 = flash ready, 1 = flash busy, <0 error */ - if (res < OK) { - logError(1, "%s Error reading flash status ERROR %02X\n", tag, res); - } else { - logError(0, "%s Flash Status: %d\n", tag, res); - size += (1 * sizeof (u8))*2; - temp = res; /* need to store the value for further display */ - res = OK; /* set res =ok for returning code */ - } - break; + case CMD_FLASHSTATUS: + res = flash_status(); + /*return 0 = flash ready, 1 = flash busy, <0 error*/ + if (res < OK) { + logError(1, "%s Reading flash status ERROR %02X\n", + tag, res); + } else { + logError(0, "%s Flash Status: %d\n", tag, res); + size += (1 * sizeof(u8)) * 2; + /*need to store the value for further display */ + temp = res; + + /*set res =ok for returning code*/ + res = OK; + } + break; #endif - - case CMD_FLASHUNLOCK: - res = flash_unlock(); - if (res < OK) { - logError(1, "%s Impossible Unlock Flash ERROR %02X\n", tag, res); - } else { - logError(0, "%s Flash Unlock OK!\n", tag); - } + case CMD_FLASHUNLOCK: + res = flash_unlock(); + if (res < OK) { + logError(1, "%s:Impossible Unlock Flash ERROR %02X\n", + tag, res); + } else { + logError(0, "%s Flash Unlock OK!\n", tag); + } + break; + case CMD_READFWFILE: + if (numberParam != 2) { + logError(1, "%s Wrong number of parameters!\n", tag); + res = ERROR_OP_NOT_ALLOW; break; - - case CMD_READFWFILE: - if (numberParam == 2) { /* read fw file */ - logError(0, "%s Reading FW File...\n", tag); - res = readFwFile(PATH_FILE_FW, &fw, functionToTest[1]); - if (res < OK) { - logError(0, "%s Error reading FW File ERROR %02X\n", tag, res); - } else { - logError(0, "%s Read FW File Finished!\n", tag); - } + } + /*read fw file */ + logError(0, "%s Reading FW File...\n", tag); + res = readFwFile(PATH_FILE_FW, &fw, functionToTest[1]); + if (res < OK) { + logError(0, "%s Error reading FW File:%02X\n", + tag, res); + } else { + logError(0, "%s Read FW File Finished!\n", tag); + } kfree(fw.data); - } else { - logError(1, "%s Wrong number of parameters!\n", tag); - res = ERROR_OP_NOT_ALLOW; - } - break; - - case CMD_FLASHPROCEDURE: - if (numberParam == 3) { /* flashing procedure */ - logError(0, "%s Starting Flashing Procedure...\n", tag); - res = flashProcedure(PATH_FILE_FW, functionToTest[1], functionToTest[2]); - if (res < OK) { - logError(0, "%s Error during flash procedure ERROR %02X\n", tag, res); - } else { - logError(0, "%s Flash Procedure Finished!\n", tag); - } - } else { - logError(1, "%s Wrong number of parameters!\n", tag); - res = ERROR_OP_NOT_ALLOW; - } - break; - - /*ITO TEST*/ - case CMD_ITOTEST: - res = production_test_ito(); - break; - - /*Initialization*/ - case CMD_INITTEST: - if (numberParam == 2) { /* need to specify if if save value on Flash */ - if (functionToTest[1] == 0x01) - res = production_test_initialization(); - else - res = production_test_splited_initialization(false); - } else { - logError(1, "%s Wrong number of parameters!\n", tag); - res = ERROR_OP_NOT_ALLOW; - } + break; + case CMD_FLASHPROCEDURE: + if (numberParam != 3) { + logError(1, "%s Wrong number of parameters!\n", tag); + res = ERROR_OP_NOT_ALLOW; break; + } + /*flashing procedure*/ + logError(0, "%s Starting Flashing Procedure\n", tag); + res = flashProcedure(PATH_FILE_FW, + functionToTest[1], functionToTest[2]); + if (res < OK) { + logError(0, "%s During flash procedure ERROR %02X", + tag, res); + } else { + logError(0, "%s Flash Procedure Finished!\n", tag); + } + break; - case CMD_MSRAWTEST: /* MS Raw DATA TEST */ - if (numberParam == 2) /* need to specify if stopOnFail */ - res = production_test_ms_raw(LIMITS_FILE, functionToTest[1], &todoDefault); - else { - logError(1, "%s Wrong number of parameters!\n", tag); - res = ERROR_OP_NOT_ALLOW; - } - break; + /*ITO TEST*/ + case CMD_ITOTEST: + res = production_test_ito(); + break; - case CMD_MSINITDATATEST: /* MS CX DATA TEST */ - if (numberParam == 2) /* need to specify if stopOnFail */ - res = production_test_ms_cx(LIMITS_FILE, functionToTest[1], &todoDefault); - else { - logError(1, "%s Wrong number of parameters!\n", tag); - res = ERROR_OP_NOT_ALLOW; - } + /*Initialization*/ + case CMD_INITTEST: + if (numberParam != 2) { + logError(1, "%s Wrong number of parameters!\n", tag); + res = ERROR_OP_NOT_ALLOW; break; - - case CMD_SSRAWTEST: /* SS RAW DATA TEST */ - if (numberParam == 2) /* need to specify if stopOnFail */ - res = production_test_ss_raw(LIMITS_FILE, functionToTest[1], &todoDefault); - else { - logError(1, "%s Wrong number of parameters!\n", tag); - res = ERROR_OP_NOT_ALLOW; - } + } + /*need to specify if if save value on Flash*/ + if (functionToTest[1] == 0x01) + res = production_test_initialization(); + else + res = production_test_split_initialization(false); + break; + + case CMD_MSRAWTEST: + if (numberParam != 2) { + logError(1, "%s Wrong number of parameters!\n", tag); + res = ERROR_OP_NOT_ALLOW; break; - - case CMD_SSINITDATATEST: /* SS IX CX DATA TEST */ - if (numberParam == 2) /* need to specify if stopOnFail */ - res = production_test_ss_ix_cx(LIMITS_FILE, functionToTest[1], &todoDefault); - else { - logError(1, "%s Wrong number of parameters!\n", tag); - res = ERROR_OP_NOT_ALLOW; - } + } + /* MS Raw DATA TEST*/ + /* need to specify if stopOnFail */ + res = production_test_ms_raw(LIMITS_FILE, functionToTest[1], + &todoDefault); + break; + + case CMD_MSINITDATATEST: + /*MS CX DATA TEST*/ + if (numberParam != 2) { + logError(1, "%s Wrong number of parameters!\n", tag); + res = ERROR_OP_NOT_ALLOW; break; - - /*PRODUCTION TEST*/ - case CMD_MAINTEST: - if (numberParam == 3) /* need to specify if stopOnFail and saveInit */ - res = production_test_main(LIMITS_FILE, functionToTest[1], functionToTest[2], &todoDefault, INIT_FIELD); - else { - logError(1, "%s Wrong number of parameters!\n", tag); - res = ERROR_OP_NOT_ALLOW; - } + } + /*need to specify if stopOnFail*/ + res = production_test_ms_cx(LIMITS_FILE, functionToTest[1], + &todoDefault); + break; + + case CMD_SSRAWTEST: + /*SS RAW DATA TEST*/ + if (numberParam != 2) { + logError(1, "%s Wrong number of parameters!\n", tag); + res = ERROR_OP_NOT_ALLOW; break; - - case CMD_POWERCYCLE: - res = fts_chip_powercycle(info); + } + /*need to specify if stopOnFail*/ + res = production_test_ss_raw(LIMITS_FILE, functionToTest[1], + &todoDefault); + break; + + case CMD_SSINITDATATEST: + /*SS IX CX DATA TEST*/ + if (numberParam != 2) { + logError(1, "%s Wrong number of parameters!\n", tag); + res = ERROR_OP_NOT_ALLOW; break; - - default: - logError(1, "%s COMMAND ID NOT VALID!! Inset a value between 00 and 1E..\n", tag); + } + /*need to specify if stopOnFail*/ + res = production_test_ss_ix_cx(LIMITS_FILE, functionToTest[1], + &todoDefault); + break; + + case CMD_MAINTEST: + /*PRODUCTION TEST*/ + if (numberParam != 3) { + logError(1, "%s Wrong number of parameters!\n", tag); res = ERROR_OP_NOT_ALLOW; break; } - - /*res2 = fts_enableInterrupt(); enabling the interrupt was disabled on purpose in this node because it can be used for testing procedure and between one step and another the interrupt wan to be kept disabled - if (res2 < 0) { - logError(0, "%s stm_driver_test_show: ERROR %08X\n", tag, (res2 | ERROR_ENABLE_INTER)); - }*/ - } else { - logError(1, "%s NO COMMAND SPECIFIED!!! do: 'echo [cmd_code] [args] > stm_fts_cmd' before looking for result!\n", tag); + /*need to specify if stopOnFail and saveInit*/ + res = production_test_main(LIMITS_FILE, functionToTest[1], + functionToTest[2], &todoDefault, INIT_FIELD); + break; + + case CMD_POWERCYCLE: + res = fts_chip_powercycle(info); + break; + + default: + logError(1, "%s COMMAND ID NOT VALID!!\n", tag); + logError(1, "%s Inset a value between 00 and 1E.\n", tag); res = ERROR_OP_NOT_ALLOW; - functionToTest = NULL; + break; } -END: /* here start the reporting phase, assembling the data to send in the file node */ - all_strbuff = (u8 *) kmalloc(size, GFP_KERNEL); +END: + /** + * here start the reporting phase, + * assembling the data to send in the file node + */ + all_strbuff = kmalloc(size, GFP_KERNEL); memset(all_strbuff, 0, size); - snprintf(buff, sizeof (buff), "%02X", 0xAA); + snprintf(buff, sizeof(buff), "%02X", 0xAA); strlcat(all_strbuff, buff, size); - snprintf(buff, sizeof (buff), "%08X", res); + snprintf(buff, sizeof(buff), "%08X", res); strlcat(all_strbuff, buff, size); if (res >= OK) { - /*all the other cases are already fine printing only the res.*/ + /*all the other cases are already*/ + /*fine printing only the res.*/ switch (functionToTest[0]) { case CMD_READ: case CMD_READU16: @@ -677,7 +853,8 @@ static ssize_t stm_driver_test_show(struct device *dev, struct device_attribute case CMD_READB2U16: case CMD_POLLFOREVENT: for (j = 0; j < byteToRead; j++) { - snprintf(buff, sizeof (buff), "%02X", readData[j]); + snprintf(buff, sizeof(buff), "%02X", + readData[j]); strlcat(all_strbuff, buff, size); } break; @@ -685,108 +862,121 @@ static ssize_t stm_driver_test_show(struct device *dev, struct device_attribute case CMD_GETFORCELEN: case CMD_GETSENSELEN: case CMD_FLASHSTATUS: - snprintf(buff, sizeof (buff), "%02X", (u8) temp); + snprintf(buff, sizeof(buff), "%02X", (u8)temp); strlcat(all_strbuff, buff, size); break; case CMD_GETMSFRAME: - snprintf(buff, sizeof (buff), "%02X", (u8) frameMS.header.force_node); + snprintf(buff, sizeof(buff), "%02X", + (u8) frameMS.header.force_node); strlcat(all_strbuff, buff, size); - snprintf(buff, sizeof (buff), "%02X", (u8) frameMS.header.sense_node); + snprintf(buff, sizeof(buff), "%02X", + (u8)frameMS.header.sense_node); strlcat(all_strbuff, buff, size); for (j = 0; j < frameMS.node_data_size; j++) { - snprintf(buff, sizeof (buff), "%04X", frameMS.node_data[j]); + snprintf(buff, sizeof(buff), "%04X", + frameMS.node_data[j]); strlcat(all_strbuff, buff, size); } - kfree(frameMS.node_data); break; case CMD_GETSSFRAME: - snprintf(buff, sizeof (buff), "%02X", (u8) frameSS.header.force_node); + snprintf(buff, sizeof(buff), "%02X", + (u8) frameSS.header.force_node); strlcat(all_strbuff, buff, size); - snprintf(buff, sizeof (buff), "%02X", (u8) frameSS.header.sense_node); + snprintf(buff, sizeof(buff), "%02X", + (u8)frameSS.header.sense_node); strlcat(all_strbuff, buff, size); /* Copying self raw data Force */ for (j = 0; j < frameSS.header.force_node; j++) { - snprintf(buff, sizeof (buff), "%04X", frameSS.force_data[j]); + snprintf(buff, sizeof(buff), "%04X", + frameSS.force_data[j]); strlcat(all_strbuff, buff, size); } + /* Copying self raw data Sense */ for (j = 0; j < frameSS.header.sense_node; j++) { - snprintf(buff, sizeof (buff), "%04X", frameSS.sense_data[j]); + snprintf(buff, sizeof(buff), "%04X", + frameSS.sense_data[j]); strlcat(all_strbuff, buff, size); } - kfree(frameSS.force_data); kfree(frameSS.sense_data); break; case CMD_READMSCOMPDATA: - snprintf(buff, sizeof (buff), "%02X", (u8) compData.header.force_node); + snprintf(buff, sizeof(buff), "%02X", + (u8)compData.header.force_node); strlcat(all_strbuff, buff, size); - snprintf(buff, sizeof (buff), "%02X", (u8) compData.header.sense_node); + snprintf(buff, sizeof(buff), "%02X", + (u8)compData.header.sense_node); strlcat(all_strbuff, buff, size); /* Cpying CX1 value */ - snprintf(buff, sizeof (buff), "%02X", compData.cx1); + snprintf(buff, sizeof(buff), "%02X", + compData.cx1); strlcat(all_strbuff, buff, size); /* Copying CX2 values */ for (j = 0; j < compData.node_data_size; j++) { - snprintf(buff, sizeof (buff), "%02X", *(compData.node_data + j)); + snprintf(buff, sizeof(buff), "%02X", + *(compData.node_data + j)); strlcat(all_strbuff, buff, size); } - kfree(compData.node_data); break; case CMD_READSSCOMPDATA: - snprintf(buff, sizeof (buff), "%02X", comData.header.force_node); + snprintf(buff, sizeof(buff), "%02X", + comData.header.force_node); strlcat(all_strbuff, buff, size); - snprintf(buff, sizeof (buff), "%02X", comData.header.sense_node); + snprintf(buff, sizeof(buff), "%02X", + comData.header.sense_node); strlcat(all_strbuff, buff, size); - snprintf(buff, sizeof (buff), "%02X", comData.f_ix1); + snprintf(buff, sizeof(buff), "%02X", comData.f_ix1); strlcat(all_strbuff, buff, size); - snprintf(buff, sizeof (buff), "%02X", comData.s_ix1); + snprintf(buff, sizeof(buff), "%02X", comData.s_ix1); strlcat(all_strbuff, buff, size); - snprintf(buff, sizeof (buff), "%02X", comData.f_cx1); + snprintf(buff, sizeof(buff), "%02X", comData.f_cx1); strlcat(all_strbuff, buff, size); - snprintf(buff, sizeof (buff), "%02X", comData.s_cx1); + snprintf(buff, sizeof(buff), "%02X", comData.s_cx1); strlcat(all_strbuff, buff, size); /* Copying IX2 Force */ for (j = 0; j < comData.header.force_node; j++) { - snprintf(buff, sizeof (buff), "%02X", comData.ix2_fm[j]); + snprintf(buff, sizeof(buff), "%02X", + comData.ix2_fm[j]); strlcat(all_strbuff, buff, size); } - - /* Copying IX2 Sense */ + /* Copying IX2 Sense*/ for (j = 0; j < comData.header.sense_node; j++) { - snprintf(buff, sizeof (buff), "%02X", comData.ix2_sn[j]); + snprintf(buff, sizeof(buff), "%02X", + comData.ix2_sn[j]); strlcat(all_strbuff, buff, size); } - /* Copying CX2 Force */ for (j = 0; j < comData.header.force_node; j++) { - snprintf(buff, sizeof (buff), "%02X", comData.cx2_fm[j]); + snprintf(buff, sizeof(buff), "%02X", + comData.cx2_fm[j]); strlcat(all_strbuff, buff, size); } /* Copying CX2 Sense */ for (j = 0; j < comData.header.sense_node; j++) { - snprintf(buff, sizeof (buff), "%02X", comData.cx2_sn[j]); + snprintf(buff, sizeof(buff), "%02X", + comData.cx2_sn[j]); strlcat(all_strbuff, buff, size); } @@ -797,67 +987,83 @@ static ssize_t stm_driver_test_show(struct device *dev, struct device_attribute break; case CMD_READGNCOMPDATA: - snprintf(buff, sizeof (buff), "%02X", gnData.header.force_node); + snprintf(buff, sizeof(buff), "%02X", + gnData.header.force_node); strlcat(all_strbuff, buff, size); - snprintf(buff, sizeof (buff), "%02X", gnData.header.sense_node); + snprintf(buff, sizeof(buff), "%02X", + gnData.header.sense_node); strlcat(all_strbuff, buff, size); - snprintf(buff, sizeof (buff), "%02X", gnData.ftsd_lp_timer_cal0); + snprintf(buff, sizeof(buff), "%02X", + gnData.ftsd_lp_timer_cal0); strlcat(all_strbuff, buff, size); - snprintf(buff, sizeof (buff), "%02X", gnData.ftsd_lp_timer_cal1); + snprintf(buff, sizeof(buff), "%02X", + gnData.ftsd_lp_timer_cal1); strlcat(all_strbuff, buff, size); - snprintf(buff, sizeof (buff), "%02X", gnData.ftsd_lp_timer_cal2); + snprintf(buff, sizeof(buff), "%02X", + gnData.ftsd_lp_timer_cal2); strlcat(all_strbuff, buff, size); - snprintf(buff, sizeof (buff), "%02X", gnData.ftsd_lp_timer_cal3); + snprintf(buff, sizeof(buff), "%02X", + gnData.ftsd_lp_timer_cal3); strlcat(all_strbuff, buff, size); - snprintf(buff, sizeof (buff), "%02X", gnData.ftsa_lp_timer_cal0); + snprintf(buff, sizeof(buff), "%02X", + gnData.ftsa_lp_timer_cal0); strlcat(all_strbuff, buff, size); - snprintf(buff, sizeof (buff), "%02X", gnData.ftsa_lp_timer_cal1); + snprintf(buff, sizeof(buff), "%02X", + gnData.ftsa_lp_timer_cal1); strlcat(all_strbuff, buff, size); break; case CMD_GETFWVER: - snprintf(buff, sizeof (buff), "%04X", fw_version); + snprintf(buff, sizeof(buff), "%04X", fw_version); strlcat(all_strbuff, buff, size); - snprintf(buff, sizeof (buff), "%04X", config_id); + snprintf(buff, sizeof(buff), "%04X", config_id); strlcat(all_strbuff, buff, size); break; case CMD_READCOMPDATAHEAD: - snprintf(buff, sizeof (buff), "%02X", dataHead.force_node); + snprintf(buff, sizeof(buff), "%02X", + dataHead.force_node); strlcat(all_strbuff, buff, size); - snprintf(buff, sizeof (buff), "%02X", dataHead.sense_node); + snprintf(buff, sizeof(buff), "%02X", + dataHead.sense_node); strlcat(all_strbuff, buff, size); break; default: break; - } } - snprintf(buff, sizeof (buff), "%02X", 0xBB); + snprintf(buff, sizeof(buff), "%02X", 0xBB); strlcat(all_strbuff, buff, size); count = snprintf(buf, TSP_BUF_SIZE, "%s\n", all_strbuff); - numberParam = 0; /* need to reset the number of parameters in order to wait the next comand, comment if you want to repeat the last comand sent just doing a cat */ - /* logError(0,"%s numberParameters = %d\n",tag, numberParam); */ + numberParam = 0; + /** + * need to reset the number of parameters + * in order to wait the next command, + * comment if you want to repeat + * the last command sent just doing a cat + */ + + kfree(readData); kfree(all_strbuff); - kfree(functionToTest); return count; - } -/*static DEVICE_ATTR(stm_driver_test, (S_IRWXU|S_IRWXG), stm_driver_test_show, stm_driver_test_store);*/ -static DEVICE_ATTR(stm_driver_test, (S_IRUGO | S_IWUSR | S_IWGRP), stm_driver_test_show, stm_driver_test_store); + +static DEVICE_ATTR(stm_driver_test, 0664, stm_driver_test_show, + stm_driver_test_store); + static struct attribute *test_cmd_attributes[] = { &dev_attr_stm_driver_test.attr, @@ -867,5 +1073,4 @@ static struct attribute *test_cmd_attributes[] = { struct attribute_group test_cmd_attr_group = { .attrs = test_cmd_attributes, }; - #endif diff --git a/drivers/input/touchscreen/st/fts_fw.h b/drivers/input/touchscreen/st/fts_fw.h index d928a06951ea..51e65f0fe978 100644 --- a/drivers/input/touchscreen/st/fts_fw.h +++ b/drivers/input/touchscreen/st/fts_fw.h @@ -1,10 +1,6532 @@ +/* + * FTS Capacitive touch screen controller (FingerTipS) + * + * Copyright (C) 2016-2018, STMicroelectronics Limited. + * Authors: AMG(Analog Mems Group) + * + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + */ + +/** + * + ************************************************************************** + ** STMicroelectronics ** + ************************************************************************** + ** marco.cali@st.com ** + ************************************************************************** + * fts firmware * + * * + * * + ************************************************************************** + ************************************************************************** + */ + #ifndef FTS_FW_H #define FTS_FW_H -/* This is an auto generated header file -* --->Remember to change the name of the two variables!<--- */ -const uint32_t myArray_size; +//This is an auto generated header file +//--->Remember to change the name of the two variables!<--- +const uint32_t myArray_size = 77860; //size const uint8_t myArray[] = { + 0x55, 0xAA, 0x55, 0xAA, 0x01, 0x00, 0x00, 0x00, 0x36, 0x70, 0x00, 0x00, + 0x00, 0x39, 0x01, 0x30, 0x49, 0xB5, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x16, 0x09, 0x20, 0x15, 0x01, 0x00, 0x00, 0xE0, 0x27, 0x01, 0x00, + 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x9C, 0x79, 0x24, 0xAC, 0x0B, 0xBF, 0x2B, 0xDA, 0xF7, 0x49, 0x00, 0x00, + 0xF4, 0x40, 0xD4, 0x25, 0x08, 0xB6, 0xFF, 0xFF, 0x00, 0x22, 0x10, 0x00, + 0xE1, 0x00, 0x00, 0x00, 0xD9, 0xE0, 0x00, 0x00, 0xD9, 0x01, 0x00, 0x00, + 0x25, 0x02, 0x00, 0x00, 0x71, 0x02, 0x00, 0x00, 0xBD, 0x02, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xDD, 0xE0, 0x00, 0x00, 0xE5, 0xE0, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x09, 0x03, 0x00, 0x00, 0xED, 0xE0, 0x00, 0x00, + 0xF5, 0xE0, 0x00, 0x00, 0x03, 0xE1, 0x00, 0x00, 0x11, 0xE1, 0x00, 0x00, + 0x1F, 0xE1, 0x00, 0x00, 0x2D, 0xE1, 0x00, 0x00, 0x3B, 0xE1, 0x00, 0x00, + 0x43, 0xE1, 0x00, 0x00, 0x51, 0xE1, 0x00, 0x00, 0xA5, 0xE1, 0x00, 0x00, + 0x17, 0x03, 0x00, 0x00, 0x5F, 0xE1, 0x00, 0x00, 0x67, 0xE1, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x77, 0xE1, 0x00, 0x00, 0xA7, 0xE1, 0x00, 0x00, + 0xA9, 0xE1, 0x00, 0x00, 0xB7, 0xE1, 0x00, 0x00, 0xB9, 0xE1, 0x00, 0x00, + 0xBB, 0xE1, 0x00, 0x00, 0x95, 0xE1, 0x00, 0x00, 0x9D, 0xE1, 0x00, 0x00, + 0x85, 0xE1, 0x00, 0x00, 0x8D, 0xE1, 0x00, 0x00, 0xBD, 0xE1, 0x00, 0x00, + 0xBF, 0xE1, 0x00, 0x00, 0xCD, 0xE1, 0x00, 0x00, 0x6F, 0xE1, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x49, 0xB5, 0x00, 0x00, + 0x00, 0x39, 0x01, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x02, 0xF8, 0x00, 0xF0, 0x68, 0xF8, + 0x0A, 0xA0, 0x90, 0xE8, 0x00, 0x0C, 0x82, 0x44, 0x83, 0x44, 0xAA, 0xF1, + 0x01, 0x07, 0xDA, 0x45, 0x01, 0xD1, 0x00, 0xF0, 0x5D, 0xF8, 0xAF, 0xF2, + 0x09, 0x0E, 0xBA, 0xE8, 0x0F, 0x00, 0x13, 0xF0, 0x01, 0x0F, 0x18, 0xBF, + 0xFB, 0x1A, 0x43, 0xF0, 0x01, 0x03, 0x18, 0x47, 0x8C, 0x25, 0x01, 0x00, + 0xBC, 0x25, 0x01, 0x00, 0x0A, 0x44, 0x4F, 0xF0, 0x00, 0x0C, 0x10, 0xF8, + 0x01, 0x3B, 0x13, 0xF0, 0x07, 0x04, 0x08, 0xBF, 0x10, 0xF8, 0x01, 0x4B, + 0x1D, 0x11, 0x08, 0xBF, 0x10, 0xF8, 0x01, 0x5B, 0x64, 0x1E, 0x05, 0xD0, + 0x10, 0xF8, 0x01, 0x6B, 0x64, 0x1E, 0x01, 0xF8, 0x01, 0x6B, 0xF9, 0xD1, + 0x13, 0xF0, 0x08, 0x0F, 0x1E, 0xBF, 0x10, 0xF8, 0x01, 0x4B, 0xAD, 0x1C, + 0x0C, 0x1B, 0x09, 0xD1, 0x6D, 0x1E, 0x58, 0xBF, 0x01, 0xF8, 0x01, 0xCB, + 0xFA, 0xD5, 0x05, 0xE0, 0x14, 0xF8, 0x01, 0x6B, 0x01, 0xF8, 0x01, 0x6B, + 0x6D, 0x1E, 0xF9, 0xD5, 0x91, 0x42, 0xD6, 0xD3, 0x70, 0x47, 0x00, 0x00, + 0x10, 0x3A, 0x24, 0xBF, 0x78, 0xC8, 0x78, 0xC1, 0xFA, 0xD8, 0x52, 0x07, + 0x24, 0xBF, 0x30, 0xC8, 0x30, 0xC1, 0x44, 0xBF, 0x04, 0x68, 0x0C, 0x60, + 0x70, 0x47, 0x00, 0x00, 0x00, 0x23, 0x00, 0x24, 0x00, 0x25, 0x00, 0x26, + 0x10, 0x3A, 0x28, 0xBF, 0x78, 0xC1, 0xFB, 0xD8, 0x52, 0x07, 0x28, 0xBF, + 0x30, 0xC1, 0x48, 0xBF, 0x0B, 0x60, 0x70, 0x47, 0x1F, 0xB5, 0x1F, 0xBD, + 0x10, 0xB5, 0x10, 0xBD, 0xDF, 0xF8, 0x0C, 0xD0, 0xFF, 0xF7, 0xF8, 0xFF, + 0x0E, 0xF0, 0xE8, 0xF8, 0x0F, 0xF0, 0x51, 0xFD, 0x00, 0x22, 0x10, 0x00, + 0x03, 0xB4, 0xFF, 0xF7, 0xF1, 0xFF, 0x03, 0xBC, 0x0F, 0xF0, 0x50, 0xFD, + 0x11, 0x48, 0x4F, 0xF0, 0x0F, 0x01, 0x00, 0xF8, 0x01, 0x1B, 0x4F, 0xF0, + 0x01, 0x01, 0x00, 0xF8, 0x01, 0x1B, 0x4F, 0xF0, 0x02, 0x01, 0x00, 0xF8, + 0x01, 0x1B, 0x4F, 0xF0, 0x00, 0x01, 0x00, 0xF8, 0x01, 0x1B, 0x00, 0xF8, + 0x01, 0x1B, 0x00, 0xF8, 0x01, 0x1B, 0x00, 0xF8, 0x01, 0x1B, 0x00, 0xF8, + 0x01, 0x1B, 0x1E, 0xF0, 0x04, 0x0F, 0x0C, 0xBF, 0xEF, 0xF3, 0x08, 0x80, + 0xEF, 0xF3, 0x09, 0x80, 0x4F, 0xF0, 0x02, 0x01, 0x0B, 0xF0, 0x5A, 0xBD, + 0x00, 0x02, 0x00, 0x20, 0x11, 0x48, 0x4F, 0xF0, 0x0F, 0x01, 0x00, 0xF8, + 0x01, 0x1B, 0x4F, 0xF0, 0x01, 0x01, 0x00, 0xF8, 0x01, 0x1B, 0x4F, 0xF0, + 0x03, 0x01, 0x00, 0xF8, 0x01, 0x1B, 0x4F, 0xF0, 0x00, 0x01, 0x00, 0xF8, + 0x01, 0x1B, 0x00, 0xF8, 0x01, 0x1B, 0x00, 0xF8, 0x01, 0x1B, 0x00, 0xF8, + 0x01, 0x1B, 0x00, 0xF8, 0x01, 0x1B, 0x1E, 0xF0, 0x04, 0x0F, 0x0C, 0xBF, + 0xEF, 0xF3, 0x08, 0x80, 0xEF, 0xF3, 0x09, 0x80, 0x4F, 0xF0, 0x03, 0x01, + 0x0B, 0xF0, 0x34, 0xBD, 0x00, 0x02, 0x00, 0x20, 0x11, 0x48, 0x4F, 0xF0, + 0x0F, 0x01, 0x00, 0xF8, 0x01, 0x1B, 0x4F, 0xF0, 0x01, 0x01, 0x00, 0xF8, + 0x01, 0x1B, 0x4F, 0xF0, 0x04, 0x01, 0x00, 0xF8, 0x01, 0x1B, 0x4F, 0xF0, + 0x00, 0x01, 0x00, 0xF8, 0x01, 0x1B, 0x00, 0xF8, 0x01, 0x1B, 0x00, 0xF8, + 0x01, 0x1B, 0x00, 0xF8, 0x01, 0x1B, 0x00, 0xF8, 0x01, 0x1B, 0x1E, 0xF0, + 0x04, 0x0F, 0x0C, 0xBF, 0xEF, 0xF3, 0x08, 0x80, 0xEF, 0xF3, 0x09, 0x80, + 0x4F, 0xF0, 0x04, 0x01, 0x0B, 0xF0, 0x0E, 0xBD, 0x00, 0x02, 0x00, 0x20, + 0x11, 0x48, 0x4F, 0xF0, 0x0F, 0x01, 0x00, 0xF8, 0x01, 0x1B, 0x4F, 0xF0, + 0x01, 0x01, 0x00, 0xF8, 0x01, 0x1B, 0x4F, 0xF0, 0x05, 0x01, 0x00, 0xF8, + 0x01, 0x1B, 0x4F, 0xF0, 0x00, 0x01, 0x00, 0xF8, 0x01, 0x1B, 0x00, 0xF8, + 0x01, 0x1B, 0x00, 0xF8, 0x01, 0x1B, 0x00, 0xF8, 0x01, 0x1B, 0x00, 0xF8, + 0x01, 0x1B, 0x1E, 0xF0, 0x04, 0x0F, 0x0C, 0xBF, 0xEF, 0xF3, 0x08, 0x80, + 0xEF, 0xF3, 0x09, 0x80, 0x4F, 0xF0, 0x05, 0x01, 0x0B, 0xF0, 0xE8, 0xBC, + 0x00, 0x02, 0x00, 0x20, 0x00, 0xB5, 0x0D, 0xF0, 0xD7, 0xFE, 0x5D, 0xF8, + 0x04, 0xEB, 0x00, 0xF0, 0x2F, 0xB8, 0x1E, 0xF0, 0x04, 0x0F, 0x0C, 0xBF, + 0xEF, 0xF3, 0x08, 0x80, 0xEF, 0xF3, 0x09, 0x80, 0x4F, 0xF0, 0x00, 0x01, + 0x0B, 0xF0, 0xD4, 0xBC, 0x0A, 0x48, 0x4F, 0xF0, 0xFF, 0x01, 0x01, 0x70, + 0x4F, 0xF0, 0x00, 0x00, 0x80, 0xF3, 0x11, 0x88, 0x4F, 0xF0, 0x00, 0x00, + 0x80, 0xF3, 0x09, 0x88, 0x05, 0x48, 0x4F, 0xF0, 0x02, 0x01, 0x01, 0x70, + 0x62, 0xB6, 0x04, 0x48, 0x4F, 0xF0, 0x80, 0x51, 0x01, 0x60, 0x70, 0x47, + 0x22, 0xED, 0x00, 0xE0, 0x44, 0x25, 0x10, 0x00, 0x04, 0xED, 0x00, 0xE0, + 0x02, 0x48, 0x4F, 0xF0, 0x80, 0x51, 0x01, 0x60, 0x70, 0x47, 0x00, 0x00, + 0x04, 0xED, 0x00, 0xE0, 0x4F, 0xF0, 0x20, 0x00, 0x80, 0xF3, 0x11, 0x88, + 0xEF, 0xF3, 0x09, 0x80, 0x98, 0xB1, 0x12, 0x48, 0x00, 0x68, 0x12, 0x49, + 0x09, 0x68, 0x88, 0x42, 0x17, 0xD0, 0xEF, 0xF3, 0x09, 0x80, 0x0E, 0x49, + 0x09, 0x68, 0x20, 0xE9, 0xF0, 0x0F, 0x88, 0x60, 0x00, 0xB5, 0x0B, 0x48, + 0x00, 0x68, 0x0E, 0xF0, 0xE2, 0xF8, 0x5D, 0xF8, 0x04, 0xEB, 0x08, 0x48, + 0x08, 0x49, 0x0A, 0x68, 0x02, 0x60, 0x00, 0x68, 0x81, 0x68, 0xB1, 0xE8, + 0xF0, 0x0F, 0x81, 0xF3, 0x09, 0x88, 0x4E, 0xF0, 0x04, 0x0E, 0x4F, 0xF0, + 0x00, 0x00, 0x80, 0xF3, 0x11, 0x88, 0x70, 0x47, 0x48, 0x25, 0x10, 0x00, + 0x4C, 0x25, 0x10, 0x00, 0xEF, 0xF3, 0x11, 0x80, 0x4F, 0xF0, 0x20, 0x01, + 0x81, 0xF3, 0x11, 0x88, 0x70, 0x47, 0x00, 0x00, 0x4F, 0xF0, 0x00, 0x00, + 0x80, 0xF3, 0x11, 0x88, 0x70, 0x47, 0x00, 0x00, 0x62, 0xB6, 0x70, 0x47, + 0x72, 0xB6, 0x70, 0x47, 0x40, 0xBA, 0x70, 0x47, 0xC0, 0xBA, 0x70, 0x47, + 0x72, 0xB6, 0x78, 0x46, 0x00, 0xF1, 0x0A, 0x00, 0x4D, 0xF8, 0x08, 0x0C, + 0x62, 0xB6, 0x30, 0xBF, 0x00, 0xBF, 0x70, 0x47, 0x10, 0xB5, 0x01, 0x46, + 0x44, 0x22, 0xA5, 0x48, 0x0F, 0xF0, 0x2B, 0xFB, 0x01, 0x21, 0xBD, 0xE8, + 0x10, 0x40, 0x00, 0x20, 0x0E, 0xF0, 0xD0, 0xB8, 0xF8, 0xB5, 0x06, 0x46, + 0xA0, 0x48, 0x9F, 0x4D, 0x03, 0x24, 0x30, 0x60, 0x30, 0x46, 0x0D, 0xF0, + 0xC9, 0xF8, 0x00, 0x22, 0x6B, 0x46, 0x01, 0x21, 0x10, 0x46, 0x0E, 0xF0, + 0x11, 0xF9, 0x01, 0x21, 0x00, 0x20, 0x0E, 0xF0, 0xEC, 0xF8, 0x95, 0xF8, + 0x42, 0x00, 0x00, 0x28, 0x04, 0xD0, 0x0B, 0xF0, 0x6A, 0xFC, 0x64, 0x1E, + 0x00, 0x2C, 0xE9, 0xDC, 0xF8, 0xBD, 0x2D, 0xE9, 0xF0, 0x47, 0xDF, 0xF8, + 0x4C, 0x92, 0x80, 0x46, 0x01, 0x27, 0xD9, 0xF8, 0x00, 0x00, 0x91, 0x4C, + 0x45, 0x7D, 0x01, 0x7D, 0x90, 0xF8, 0x41, 0x00, 0x4D, 0x43, 0xC0, 0xF3, + 0x81, 0x00, 0x87, 0x40, 0xA9, 0x00, 0x20, 0x46, 0x0F, 0xF0, 0x4F, 0xFB, + 0x00, 0x26, 0xDF, 0xF8, 0x1C, 0xA2, 0x12, 0xE0, 0x85, 0x48, 0x44, 0x30, + 0xFF, 0xF7, 0xC6, 0xFF, 0x00, 0x20, 0xDA, 0xF8, 0x00, 0x10, 0x07, 0xE0, + 0x54, 0xF8, 0x20, 0x20, 0x31, 0xF9, 0x10, 0x30, 0x1A, 0x44, 0x44, 0xF8, + 0x20, 0x20, 0x40, 0x1C, 0xA8, 0x42, 0xF5, 0xDB, 0x76, 0x1C, 0xBE, 0x42, + 0xEA, 0xDB, 0x00, 0x20, 0x4B, 0x46, 0x0A, 0xE0, 0x1A, 0x68, 0x54, 0xF8, + 0x20, 0x10, 0x92, 0xF8, 0x41, 0x20, 0xC2, 0xF3, 0x81, 0x02, 0x11, 0x41, + 0x28, 0xF8, 0x10, 0x10, 0x40, 0x1C, 0xA8, 0x42, 0xF2, 0xDB, 0xD9, 0xF8, + 0x00, 0x00, 0x90, 0xF8, 0x30, 0x11, 0x89, 0x07, 0x07, 0xD5, 0x02, 0x7D, + 0x41, 0x7D, 0x40, 0x46, 0xBD, 0xE8, 0xF0, 0x47, 0x71, 0x4B, 0x0C, 0xF0, + 0xB5, 0xBA, 0xBD, 0xE8, 0xF0, 0x87, 0x2D, 0xE9, 0xF0, 0x43, 0x6C, 0x4F, + 0x6C, 0x4C, 0x01, 0x26, 0x38, 0x68, 0x9F, 0xB0, 0x90, 0xF8, 0x41, 0x10, + 0xC1, 0xF3, 0x01, 0x12, 0x41, 0x7D, 0x00, 0x7D, 0x06, 0xFA, 0x02, 0xF9, + 0x04, 0xEB, 0x81, 0x05, 0x08, 0x44, 0x81, 0x00, 0x20, 0x46, 0x0F, 0xF0, + 0x00, 0xFB, 0x60, 0x48, 0x44, 0x30, 0x0D, 0xF0, 0x16, 0xF8, 0x5E, 0x48, + 0x44, 0x30, 0x06, 0x72, 0x00, 0x26, 0x34, 0xE0, 0x5B, 0x48, 0x44, 0x30, + 0xFF, 0xF7, 0x72, 0xFF, 0x38, 0x68, 0xDF, 0xF8, 0x64, 0x81, 0x40, 0x7D, + 0xD8, 0xF8, 0x18, 0x10, 0x42, 0x00, 0x10, 0xA8, 0x0F, 0xF0, 0x48, 0xFA, + 0x38, 0x68, 0xD8, 0xF8, 0x1C, 0x10, 0x00, 0x7D, 0x42, 0x00, 0x68, 0x46, + 0x0F, 0xF0, 0x40, 0xFA, 0x00, 0x20, 0x10, 0xA9, 0x07, 0xE0, 0x54, 0xF8, + 0x20, 0x20, 0x31, 0xF9, 0x10, 0x30, 0x1A, 0x44, 0x44, 0xF8, 0x20, 0x20, + 0x40, 0x1C, 0x3A, 0x68, 0x52, 0x7D, 0x82, 0x42, 0xF3, 0xDC, 0x00, 0x20, + 0x69, 0x46, 0x07, 0xE0, 0x55, 0xF8, 0x20, 0x20, 0x31, 0xF9, 0x10, 0x30, + 0x1A, 0x44, 0x45, 0xF8, 0x20, 0x20, 0x40, 0x1C, 0x3A, 0x68, 0x12, 0x7D, + 0x82, 0x42, 0xF3, 0xDC, 0x76, 0x1C, 0x4E, 0x45, 0xC8, 0xDB, 0x00, 0x20, + 0x44, 0x4B, 0x39, 0x68, 0x09, 0xE0, 0x91, 0xF8, 0x41, 0x60, 0x54, 0xF8, + 0x20, 0x20, 0xC6, 0xF3, 0x01, 0x16, 0x32, 0x41, 0x23, 0xF8, 0x10, 0x20, + 0x40, 0x1C, 0x4A, 0x7D, 0x82, 0x42, 0xF2, 0xDC, 0x00, 0x20, 0x3D, 0x4B, + 0x09, 0xE0, 0x91, 0xF8, 0x41, 0x40, 0x55, 0xF8, 0x20, 0x20, 0xC4, 0xF3, + 0x01, 0x14, 0x22, 0x41, 0x23, 0xF8, 0x10, 0x20, 0x40, 0x1C, 0x0A, 0x7D, + 0x82, 0x42, 0xF2, 0xDC, 0x1F, 0xB0, 0xBD, 0xE8, 0xF0, 0x83, 0x2D, 0xE9, + 0xF0, 0x41, 0x04, 0x46, 0x00, 0x20, 0x0E, 0xF0, 0x96, 0xF8, 0x02, 0x20, + 0x0E, 0xF0, 0x93, 0xF8, 0x29, 0x48, 0x44, 0x30, 0x0C, 0xF0, 0xA9, 0xFF, + 0x2E, 0x49, 0x08, 0x78, 0x02, 0x28, 0x01, 0xD0, 0x03, 0x28, 0x01, 0xD1, + 0x04, 0x20, 0x08, 0x70, 0x25, 0x4D, 0x28, 0x68, 0x90, 0xF8, 0x40, 0x00, + 0x80, 0x07, 0x01, 0xD4, 0x24, 0xF0, 0x01, 0x04, 0x1F, 0x4F, 0xE0, 0x07, + 0x4F, 0xF0, 0x01, 0x08, 0x07, 0xF1, 0x44, 0x07, 0x16, 0xD0, 0x38, 0x46, + 0x0C, 0xF0, 0x8F, 0xFF, 0xA0, 0x06, 0x15, 0xD5, 0x87, 0xF8, 0x08, 0x80, + 0x28, 0x68, 0x00, 0x25, 0x90, 0xF8, 0x41, 0x00, 0x00, 0xF0, 0x03, 0x00, + 0x08, 0xFA, 0x00, 0xF6, 0x04, 0xE0, 0x14, 0x48, 0x44, 0x30, 0xFF, 0xF7, + 0xE3, 0xFE, 0x6D, 0x1C, 0xB5, 0x42, 0xF8, 0xDB, 0xA0, 0x06, 0x01, 0xD5, + 0xFF, 0xF7, 0x47, 0xFF, 0xA0, 0x07, 0x08, 0xD5, 0x0D, 0x48, 0x44, 0x30, + 0x0C, 0xF0, 0x71, 0xFF, 0x87, 0xF8, 0x04, 0x80, 0x12, 0x48, 0xFF, 0xF7, + 0xEE, 0xFE, 0x60, 0x07, 0x08, 0xD5, 0x08, 0x48, 0x44, 0x30, 0x0C, 0xF0, + 0x66, 0xFF, 0x03, 0x20, 0x38, 0x71, 0x0D, 0x48, 0xFF, 0xF7, 0xE3, 0xFE, + 0x00, 0x20, 0x0E, 0xF0, 0x5F, 0xF8, 0xBD, 0xE8, 0xF0, 0x41, 0x02, 0x20, + 0x0E, 0xF0, 0x5A, 0xB8, 0xDC, 0x25, 0x10, 0x00, 0x15, 0x04, 0x00, 0x00, + 0x50, 0x24, 0x10, 0x00, 0x60, 0x54, 0x10, 0x00, 0x48, 0x53, 0x10, 0x00, + 0xFC, 0x22, 0x01, 0x20, 0x38, 0x23, 0x01, 0x20, 0x60, 0x24, 0x10, 0x00, + 0x7C, 0x1B, 0x01, 0x20, 0x10, 0xB5, 0x16, 0x4C, 0x40, 0xF2, 0xFF, 0x11, + 0x20, 0x68, 0x11, 0xF0, 0xFD, 0xFA, 0x21, 0x68, 0xC1, 0xF8, 0xFC, 0x07, + 0x00, 0x21, 0x3F, 0x20, 0x0F, 0xF1, 0x88, 0xFA, 0x21, 0x68, 0xBD, 0xE8, + 0x10, 0x40, 0x3F, 0x23, 0x4F, 0xF4, 0x00, 0x72, 0x0D, 0x48, 0x10, 0xF0, + 0x1D, 0xBE, 0x10, 0xB5, 0x40, 0xF2, 0xFF, 0x31, 0x0B, 0x48, 0x11, 0xF0, + 0xE7, 0xFA, 0x0A, 0x49, 0xC1, 0xF8, 0xFC, 0x0F, 0x01, 0x21, 0x00, 0x20, + 0x0F, 0xF1, 0x72, 0xFA, 0x00, 0x23, 0x4F, 0xF4, 0x80, 0x62, 0xBD, 0xE8, + 0x10, 0x40, 0x04, 0x49, 0x10, 0x02, 0x10, 0xF0, 0x07, 0xBE, 0x00, 0x00, + 0x50, 0x24, 0x10, 0x00, 0xF0, 0xEF, 0x03, 0x00, 0x00, 0x10, 0x10, 0x00, + 0xFE, 0x49, 0x08, 0x70, 0x4F, 0xF4, 0x00, 0x51, 0x00, 0x20, 0x0D, 0xF0, + 0x41, 0xBF, 0x0D, 0xF0, 0x95, 0xB8, 0x30, 0xB5, 0xFA, 0x49, 0x0A, 0x68, + 0x92, 0xF8, 0xB2, 0x34, 0x02, 0x78, 0x63, 0xF3, 0x01, 0x02, 0x02, 0x70, + 0x0B, 0x68, 0x93, 0xF8, 0xB2, 0x34, 0x9B, 0x08, 0x63, 0xF3, 0x82, 0x02, + 0x02, 0x70, 0x0B, 0x68, 0x93, 0xF8, 0xB2, 0x34, 0xDB, 0x08, 0x63, 0xF3, + 0xC3, 0x02, 0x02, 0x70, 0x0B, 0x68, 0x93, 0xF8, 0xB2, 0x34, 0x1B, 0x09, + 0x63, 0xF3, 0x04, 0x12, 0x02, 0x70, 0x0B, 0x68, 0x93, 0xF8, 0xB2, 0x34, + 0x5B, 0x09, 0x63, 0xF3, 0x45, 0x12, 0x02, 0x70, 0x0B, 0x68, 0x93, 0xF8, + 0xB2, 0x34, 0x9B, 0x09, 0x63, 0xF3, 0x86, 0x12, 0x02, 0x70, 0x0B, 0x68, + 0x93, 0xF8, 0xB2, 0x34, 0xDB, 0x09, 0x63, 0xF3, 0xC7, 0x12, 0x02, 0x70, + 0x0A, 0x68, 0x92, 0xF8, 0xAC, 0x34, 0x42, 0x78, 0x63, 0xF3, 0x01, 0x02, + 0x42, 0x70, 0x0B, 0x68, 0x93, 0xF8, 0xAC, 0x34, 0x9B, 0x08, 0x63, 0xF3, + 0x82, 0x02, 0x42, 0x70, 0x0B, 0x68, 0x93, 0xF8, 0xAC, 0x34, 0xDB, 0x08, + 0x63, 0xF3, 0xC3, 0x02, 0x42, 0x70, 0x0B, 0x68, 0x93, 0xF8, 0xAC, 0x34, + 0x1B, 0x09, 0x63, 0xF3, 0x04, 0x12, 0x42, 0x70, 0x0B, 0x68, 0x93, 0xF8, + 0xAC, 0x34, 0x5B, 0x09, 0x63, 0xF3, 0x45, 0x12, 0x42, 0x70, 0x0B, 0x68, + 0x93, 0xF8, 0xAC, 0x34, 0x9B, 0x09, 0x63, 0xF3, 0x86, 0x12, 0x42, 0x70, + 0x0B, 0x68, 0x93, 0xF8, 0xAC, 0x34, 0xDB, 0x09, 0x63, 0xF3, 0xC7, 0x12, + 0x42, 0x70, 0x0A, 0x68, 0x92, 0xF8, 0xC0, 0x24, 0x93, 0x08, 0x82, 0x78, + 0x63, 0xF3, 0x04, 0x12, 0x82, 0x70, 0x0B, 0x68, 0x93, 0xF8, 0xC0, 0x34, + 0xDB, 0x08, 0x63, 0xF3, 0x45, 0x12, 0x82, 0x70, 0x0B, 0x68, 0x93, 0xF8, + 0xC2, 0x34, 0x1B, 0x09, 0x63, 0xF3, 0x87, 0x12, 0x82, 0x70, 0x0B, 0x68, + 0x93, 0xF8, 0xC3, 0x34, 0x1C, 0x09, 0xC3, 0x78, 0x64, 0xF3, 0x01, 0x03, + 0xC3, 0x70, 0x0C, 0x68, 0x94, 0xF8, 0xC1, 0x54, 0xC5, 0x71, 0x94, 0xF8, + 0xC0, 0x44, 0x64, 0x08, 0x64, 0xF3, 0xC3, 0x02, 0x82, 0x70, 0x0A, 0x68, + 0x92, 0xF8, 0xC2, 0x44, 0x04, 0xF0, 0x0F, 0x04, 0x04, 0x71, 0x92, 0xF8, + 0xC3, 0x24, 0x62, 0xF3, 0x84, 0x03, 0xC3, 0x70, 0x42, 0x79, 0x22, 0xF0, + 0x7F, 0x02, 0x42, 0x71, 0x4F, 0xF6, 0x05, 0x22, 0x82, 0x81, 0x09, 0x68, + 0xB1, 0xF8, 0xC8, 0x24, 0xC2, 0x81, 0xB1, 0xF8, 0xCA, 0x24, 0x02, 0x82, + 0xB1, 0xF8, 0xCC, 0x24, 0x42, 0x82, 0xB1, 0xF8, 0xCE, 0x24, 0x82, 0x82, + 0xB1, 0xF8, 0xD0, 0x24, 0xC2, 0x82, 0xB1, 0xF8, 0xD2, 0x24, 0x02, 0x83, + 0xB1, 0xF8, 0xD4, 0x24, 0x42, 0x83, 0xB1, 0xF8, 0xD6, 0x24, 0x82, 0x83, + 0xB1, 0xF8, 0xC4, 0x24, 0x02, 0x81, 0xB1, 0xF8, 0xC6, 0x14, 0x41, 0x81, + 0x30, 0xBD, 0x70, 0xB5, 0x8E, 0xB0, 0x01, 0xA8, 0xFF, 0xF7, 0x3D, 0xFF, + 0x01, 0xA8, 0x10, 0xF0, 0x49, 0xF8, 0x97, 0x4C, 0x00, 0x25, 0x00, 0x21, + 0x25, 0x70, 0x25, 0x63, 0x65, 0x63, 0xA5, 0x63, 0xE5, 0x63, 0x25, 0x64, + 0x65, 0x64, 0xA5, 0x64, 0xC4, 0xE9, 0x14, 0x55, 0xC4, 0xE9, 0x16, 0x55, + 0xC4, 0xE9, 0x18, 0x55, 0xC4, 0xE9, 0x1A, 0x51, 0xC4, 0xE9, 0x1C, 0x11, + 0xC4, 0xE9, 0x1E, 0x11, 0x04, 0xF1, 0x80, 0x00, 0xC0, 0xE9, 0x00, 0x11, + 0x65, 0x60, 0xE5, 0x61, 0x25, 0x62, 0x65, 0x62, 0xA5, 0x62, 0xE5, 0x62, + 0x0C, 0xF0, 0xC3, 0xFF, 0x09, 0x90, 0xFF, 0xF7, 0x12, 0xFF, 0xCD, 0xE9, + 0x0A, 0x01, 0x04, 0x21, 0x09, 0xA8, 0x11, 0xF0, 0xB7, 0xF9, 0x06, 0x46, + 0x08, 0x21, 0x0A, 0xA8, 0x11, 0xF0, 0xB2, 0xF9, 0x00, 0xEB, 0x46, 0x01, + 0xC4, 0xE9, 0x03, 0x16, 0xC4, 0xE9, 0x05, 0x60, 0x4F, 0xF4, 0x00, 0x61, + 0x7C, 0x48, 0x0F, 0xF0, 0xEE, 0xF8, 0x4F, 0xF4, 0xF0, 0x61, 0x7B, 0x48, + 0x0F, 0xF0, 0xC7, 0xF8, 0x00, 0xF0, 0x02, 0xFD, 0xB8, 0xB9, 0x00, 0x22, + 0x4F, 0xF4, 0x00, 0x56, 0x0C, 0xAB, 0x31, 0x46, 0x10, 0x46, 0x0D, 0xF0, + 0x7D, 0xFE, 0x31, 0x46, 0x00, 0x20, 0x0D, 0xF0, 0x58, 0xFE, 0x20, 0x78, + 0x48, 0xB1, 0x0B, 0xF0, 0xD8, 0xF9, 0x00, 0x22, 0x0F, 0x21, 0x05, 0x20, + 0x0B, 0xF0, 0xE8, 0xFA, 0x00, 0x20, 0x0E, 0xB0, 0x70, 0xBD, 0x10, 0xF0, + 0x87, 0xF8, 0x09, 0xAC, 0x00, 0x95, 0x94, 0xE8, 0x0E, 0x00, 0x6A, 0x48, + 0x0F, 0xF0, 0x40, 0xFA, 0x69, 0x48, 0x0F, 0xF0, 0x57, 0xFA, 0x68, 0x48, + 0x3A, 0x30, 0x0F, 0xF0, 0x93, 0xFA, 0x66, 0x48, 0x20, 0x38, 0x0F, 0xF0, + 0x53, 0xFA, 0x64, 0x48, 0x18, 0x30, 0x0F, 0xF0, 0x8F, 0xFA, 0x01, 0x20, + 0xE3, 0xE7, 0x2D, 0xE9, 0xF0, 0x41, 0x0D, 0x46, 0x06, 0x46, 0x4F, 0xF0, + 0xFF, 0x34, 0x0C, 0xF0, 0x68, 0xFF, 0x03, 0x46, 0x00, 0x20, 0xDF, 0xF8, + 0x5C, 0xC1, 0x02, 0x46, 0x01, 0x27, 0x07, 0xFA, 0x02, 0xF1, 0x19, 0x42, + 0x00, 0xD0, 0x64, 0x1C, 0xB4, 0x42, 0x06, 0xD1, 0x01, 0x2D, 0x09, 0xD0, + 0x23, 0xEA, 0x01, 0x00, 0xCC, 0xF8, 0x08, 0x20, 0x1E, 0x22, 0x52, 0x1C, + 0x1E, 0x2A, 0xEE, 0xD9, 0xBD, 0xE8, 0xF0, 0x81, 0x08, 0x46, 0xF5, 0xE7, + 0x2D, 0xE9, 0xF0, 0x5F, 0x8A, 0x46, 0x83, 0x46, 0x4F, 0xF0, 0xFF, 0x35, + 0xFF, 0xF7, 0x97, 0xFE, 0x00, 0x26, 0x81, 0x46, 0x88, 0x46, 0x37, 0x46, + 0x34, 0x46, 0x22, 0x46, 0x01, 0x20, 0x00, 0x21, 0x0E, 0xF0, 0xA7, 0xFF, + 0x02, 0x46, 0x0B, 0x46, 0x00, 0xEA, 0x09, 0x00, 0x01, 0xEA, 0x08, 0x01, + 0x08, 0x43, 0x00, 0xD0, 0x6D, 0x1C, 0x5D, 0x45, 0x09, 0xD1, 0xBA, 0xF1, + 0x01, 0x0F, 0x0D, 0xD0, 0x29, 0xEA, 0x02, 0x06, 0x28, 0xEA, 0x03, 0x07, + 0x38, 0x48, 0x84, 0x60, 0x20, 0x24, 0x64, 0x1C, 0x20, 0x2C, 0xE2, 0xD3, + 0x30, 0x46, 0x39, 0x46, 0xBD, 0xE8, 0xF0, 0x9F, 0x16, 0x46, 0x1F, 0x46, + 0xF2, 0xE7, 0x2D, 0xE9, 0xF0, 0x41, 0x17, 0x46, 0x04, 0x46, 0x0D, 0x46, + 0x00, 0x26, 0x0A, 0xE0, 0xE0, 0x07, 0x04, 0xD0, 0x32, 0x46, 0x39, 0x46, + 0x05, 0x20, 0x0B, 0xF0, 0x69, 0xFA, 0x76, 0x1C, 0x6D, 0x08, 0x4F, 0xEA, + 0x34, 0x04, 0x54, 0xEA, 0x05, 0x00, 0xF1, 0xD1, 0xB4, 0xE7, 0x2D, 0xE9, + 0xF0, 0x5F, 0x26, 0x4C, 0x60, 0x68, 0x00, 0x28, 0x7E, 0xD0, 0xD4, 0xE9, + 0x0D, 0x12, 0x8A, 0x43, 0xA2, 0x63, 0x20, 0x6B, 0x23, 0x6C, 0x88, 0x43, + 0xD4, 0xE9, 0x15, 0x87, 0x98, 0x43, 0xD4, 0xE9, 0x1C, 0x63, 0x25, 0x6D, + 0xD4, 0xF8, 0x5C, 0xC0, 0xBD, 0x43, 0x28, 0xEA, 0x0C, 0x08, 0x90, 0x43, + 0xB5, 0x43, 0x28, 0xEA, 0x03, 0x08, 0x20, 0x63, 0xD4, 0xE9, 0x18, 0x36, + 0x9D, 0x43, 0x28, 0xEA, 0x06, 0x08, 0xC4, 0xE9, 0x14, 0x58, 0xD4, 0xF8, + 0x48, 0xA0, 0x04, 0xF1, 0x80, 0x05, 0x2A, 0xEA, 0x01, 0x0A, 0xD5, 0xE9, + 0x00, 0x89, 0x2A, 0xEA, 0x02, 0x0A, 0xE2, 0x6B, 0x28, 0xEA, 0x07, 0x08, + 0x2A, 0xEA, 0x02, 0x0A, 0x29, 0xEA, 0x0C, 0x09, 0x28, 0xEA, 0x03, 0x08, + 0x29, 0xEA, 0x06, 0x09, 0xC4, 0xF8, 0x48, 0xA0, 0xD4, 0xE9, 0x1A, 0x63, + 0x28, 0xEA, 0x06, 0x08, 0x29, 0xEA, 0x03, 0x09, 0x91, 0x43, 0xC5, 0xE9, + 0x00, 0x89, 0x61, 0x63, 0x01, 0x22, 0x00, 0x21, 0xFF, 0xF7, 0xA1, 0xFF, + 0xD4, 0xE9, 0x14, 0x01, 0x02, 0x22, 0xFF, 0xF7, 0x9C, 0xFF, 0x0B, 0xE0, + 0x08, 0x22, 0x10, 0x00, 0x50, 0x24, 0x10, 0x00, 0x00, 0x10, 0x10, 0x00, + 0x38, 0xA9, 0x01, 0x20, 0x80, 0x13, 0x10, 0x00, 0x54, 0x17, 0x10, 0x00, + 0x03, 0x22, 0x00, 0x21, 0x60, 0x6B, 0xFF, 0xF7, 0x8A, 0xFF, 0xD4, 0xE9, + 0x16, 0x01, 0x04, 0x22, 0xFF, 0xF7, 0x85, 0xFF, 0x05, 0x22, 0x00, 0x21, + 0x20, 0x6C, 0xFF, 0xF7, 0x80, 0xFF, 0xD4, 0xE9, 0x1C, 0x01, 0x06, 0x22, + 0xFF, 0xF7, 0x7B, 0xFF, 0x07, 0x22, 0x00, 0x21, 0xE0, 0x6B, 0xFF, 0xF7, + 0x76, 0xFF, 0xD4, 0xE9, 0x1A, 0x01, 0x08, 0x22, 0xFF, 0xF7, 0x71, 0xFF, + 0x09, 0x22, 0x00, 0x21, 0x60, 0x6C, 0xFF, 0xF7, 0x6C, 0xFF, 0xD4, 0xE9, + 0x1E, 0x01, 0x0A, 0x22, 0xFF, 0xF7, 0x67, 0xFF, 0x0B, 0x22, 0x00, 0xE0, + 0x09, 0xE0, 0x00, 0x21, 0xA0, 0x6C, 0xFF, 0xF7, 0x60, 0xFF, 0xD5, 0xE9, + 0x00, 0x01, 0xBD, 0xE8, 0xF0, 0x5F, 0x0C, 0x22, 0x59, 0xE7, 0xBD, 0xE8, + 0xF0, 0x5F, 0x00, 0x22, 0x11, 0x46, 0x05, 0x20, 0x0B, 0xF0, 0xCA, 0xB9, + 0x2D, 0xE9, 0xF0, 0x41, 0x16, 0x46, 0x1F, 0x46, 0x80, 0x46, 0x4F, 0xF0, + 0xFF, 0x35, 0x00, 0x24, 0x22, 0x46, 0x01, 0x20, 0x00, 0x21, 0x0E, 0xF0, + 0xCE, 0xFE, 0x30, 0x40, 0x39, 0x40, 0x08, 0x43, 0x04, 0xD0, 0x6D, 0x1C, + 0x45, 0x45, 0x01, 0xD1, 0x20, 0x46, 0x07, 0xE7, 0x64, 0x1C, 0x40, 0x2C, + 0xEE, 0xD3, 0x00, 0x20, 0x02, 0xE7, 0x70, 0xB5, 0xFE, 0x4E, 0x01, 0x25, + 0xA6, 0xF1, 0x80, 0x04, 0x0D, 0x28, 0x11, 0xD2, 0xDF, 0xE8, 0x00, 0xF0, + 0xA2, 0x76, 0x80, 0x07, 0x11, 0x23, 0x2D, 0x3F, 0x49, 0x5A, 0x64, 0x91, + 0x96, 0x00, 0x00, 0x23, 0x08, 0x46, 0xE2, 0x6C, 0xFF, 0xF7, 0xD0, 0xFF, + 0x85, 0x40, 0x60, 0x6B, 0x05, 0x43, 0x65, 0x63, 0x90, 0xE0, 0xD6, 0xE9, + 0x02, 0x23, 0x08, 0x46, 0xFF, 0xF7, 0xC6, 0xFF, 0x01, 0x23, 0x02, 0x46, + 0x00, 0x21, 0x18, 0x46, 0x0E, 0xF0, 0x9B, 0xFE, 0xD4, 0xE9, 0x16, 0x23, + 0x10, 0x43, 0x19, 0x43, 0xC4, 0xE9, 0x16, 0x01, 0x7E, 0xE0, 0x00, 0x23, + 0x08, 0x46, 0xE2, 0x6C, 0xFF, 0xF7, 0xB4, 0xFF, 0x85, 0x40, 0x20, 0x6C, + 0x05, 0x43, 0x25, 0x64, 0x74, 0xE0, 0xD6, 0xE9, 0x02, 0x23, 0x08, 0x46, + 0xFF, 0xF7, 0xAA, 0xFF, 0x01, 0x23, 0x02, 0x46, 0x00, 0x21, 0x18, 0x46, + 0x0E, 0xF0, 0x7F, 0xFE, 0xD4, 0xE9, 0x1C, 0x23, 0x10, 0x43, 0x19, 0x43, + 0xC4, 0xE9, 0x1C, 0x01, 0x62, 0xE0, 0x00, 0x23, 0x08, 0x46, 0xE2, 0x6C, + 0xFF, 0xF7, 0x98, 0xFF, 0x85, 0x40, 0xE0, 0x6B, 0x05, 0x43, 0xE5, 0x63, + 0x58, 0xE0, 0xD6, 0xE9, 0x02, 0x23, 0x08, 0x46, 0xFF, 0xF7, 0x8E, 0xFF, + 0x02, 0x46, 0x01, 0x20, 0x00, 0x21, 0x0E, 0xF0, 0x64, 0xFE, 0xD4, 0xE9, + 0x1A, 0x23, 0x10, 0x43, 0x19, 0x43, 0xC4, 0xE9, 0x1A, 0x01, 0x47, 0xE0, + 0x00, 0x23, 0x08, 0x46, 0xE2, 0x6C, 0xFF, 0xF7, 0x7D, 0xFF, 0x85, 0x40, + 0x60, 0x6C, 0x05, 0x43, 0x65, 0x64, 0x3D, 0xE0, 0xD6, 0xE9, 0x02, 0x23, + 0x08, 0x46, 0xFF, 0xF7, 0x73, 0xFF, 0x01, 0x23, 0x02, 0x46, 0x00, 0x21, + 0x18, 0x46, 0x0E, 0xF0, 0x48, 0xFE, 0xD4, 0xE9, 0x1E, 0x23, 0x10, 0x43, + 0x19, 0x43, 0xC4, 0xE9, 0x1E, 0x01, 0x2B, 0xE0, 0x00, 0x23, 0x08, 0x46, + 0xE2, 0x6C, 0xFF, 0xF7, 0x61, 0xFF, 0x85, 0x40, 0x20, 0x6B, 0x05, 0x43, + 0x25, 0x63, 0x21, 0xE0, 0xD6, 0xE9, 0x02, 0x23, 0x08, 0x46, 0xFF, 0xF7, + 0x57, 0xFF, 0x02, 0x46, 0x01, 0x20, 0x00, 0x21, 0x0E, 0xF0, 0x2D, 0xFE, + 0xD4, 0xE9, 0x14, 0x23, 0x10, 0x43, 0x19, 0x43, 0xC4, 0xE9, 0x14, 0x01, + 0x10, 0xE0, 0xA0, 0x6C, 0x8D, 0x40, 0x05, 0x43, 0xA5, 0x64, 0x0B, 0xE0, + 0x00, 0x23, 0x0A, 0x46, 0x01, 0x20, 0x19, 0x46, 0x0E, 0xF0, 0x1B, 0xFE, + 0xD6, 0xE9, 0x00, 0x23, 0x10, 0x43, 0x19, 0x43, 0xC6, 0xE9, 0x00, 0x01, + 0x60, 0x68, 0x40, 0x1C, 0x60, 0x60, 0x70, 0xBD, 0x2D, 0xE9, 0xF8, 0x4F, + 0x82, 0x46, 0x00, 0x20, 0x99, 0x46, 0x93, 0x46, 0x0F, 0x46, 0x06, 0x46, + 0x00, 0x90, 0x52, 0xE0, 0xA2, 0x48, 0x00, 0x24, 0x4F, 0xF0, 0xFF, 0x38, + 0xD0, 0xE9, 0x02, 0x23, 0x30, 0x46, 0xFF, 0xF7, 0x23, 0xFF, 0x02, 0x46, + 0x01, 0x20, 0x00, 0x21, 0x0E, 0xF0, 0xF9, 0xFD, 0x9B, 0x4A, 0x80, 0x3A, + 0xD2, 0xE9, 0x1A, 0x32, 0x18, 0x40, 0x11, 0x40, 0x08, 0x43, 0x3B, 0xD1, + 0x00, 0x25, 0x2A, 0xE0, 0x05, 0xFB, 0x07, 0x60, 0x3B, 0xF9, 0x10, 0x20, + 0xB2, 0xEB, 0x09, 0x1F, 0x22, 0xDA, 0x64, 0x1C, 0xB8, 0xF1, 0xFF, 0x3F, + 0x00, 0xD1, 0xA8, 0x46, 0xAA, 0xF1, 0x01, 0x01, 0x8D, 0x42, 0x19, 0xD1, + 0x01, 0x2C, 0x17, 0xD1, 0x79, 0x1E, 0x8E, 0x42, 0x04, 0xD1, 0x29, 0x46, + 0x0A, 0x98, 0xFF, 0xF7, 0x16, 0xFF, 0x0E, 0xE0, 0x0B, 0xEB, 0x40, 0x00, + 0xB0, 0xF9, 0x02, 0x20, 0xB2, 0xEB, 0x09, 0x1F, 0x05, 0xDB, 0x36, 0xB1, + 0x30, 0xF9, 0x02, 0x1C, 0xB1, 0xEB, 0x09, 0x1F, 0x01, 0xDA, 0x00, 0x24, + 0x00, 0xE0, 0x02, 0x24, 0x6D, 0x1C, 0x55, 0x45, 0xD2, 0xDB, 0xAA, 0xEB, + 0x08, 0x00, 0xA0, 0x42, 0x08, 0xD8, 0x31, 0x46, 0x0B, 0x98, 0xFF, 0xF7, + 0xFA, 0xFE, 0x01, 0x20, 0x00, 0x99, 0xB0, 0x40, 0x08, 0x43, 0x00, 0x90, + 0x76, 0x1C, 0xBE, 0x42, 0xAA, 0xDB, 0x00, 0x25, 0x45, 0xE0, 0x00, 0x26, + 0x34, 0x46, 0x3A, 0xE0, 0xDF, 0xF8, 0xD4, 0x81, 0xA8, 0xF1, 0x80, 0x08, + 0xD8, 0xE9, 0x1A, 0x21, 0xD8, 0xE9, 0x16, 0x30, 0x1A, 0x43, 0x01, 0x43, + 0x0A, 0x43, 0x1F, 0xD0, 0x6F, 0x48, 0xD0, 0xE9, 0x02, 0x23, 0x20, 0x46, + 0xFF, 0xF7, 0xC0, 0xFE, 0x01, 0x23, 0x02, 0x46, 0x00, 0x21, 0x18, 0x46, + 0x0E, 0xF0, 0x95, 0xFD, 0xC6, 0x46, 0xD8, 0xF8, 0x68, 0x80, 0xDE, 0xF8, + 0x6C, 0x20, 0x03, 0x46, 0x8C, 0x46, 0x00, 0xEA, 0x08, 0x00, 0x11, 0x40, + 0x08, 0x43, 0x15, 0xD1, 0xDE, 0xE9, 0x16, 0x10, 0x0B, 0x40, 0x0C, 0xEA, + 0x00, 0x0C, 0x53, 0xEA, 0x0C, 0x03, 0x0D, 0xD1, 0x05, 0xFB, 0x07, 0x41, + 0x3B, 0xF9, 0x11, 0x10, 0xB1, 0xEB, 0x09, 0x1F, 0x06, 0xDA, 0x01, 0x20, + 0x00, 0x9A, 0xA0, 0x40, 0x10, 0x40, 0x00, 0x00, 0x00, 0xD1, 0x76, 0x1C, + 0x64, 0x1C, 0xBC, 0x42, 0xC2, 0xDB, 0x1E, 0xB1, 0x29, 0x46, 0x0A, 0x98, + 0xFF, 0xF7, 0xAB, 0xFE, 0x6D, 0x1C, 0x55, 0x45, 0xB7, 0xDB, 0xBD, 0xE8, + 0xF8, 0x8F, 0x2D, 0xE9, 0xFC, 0x41, 0x0F, 0x46, 0x80, 0x46, 0x00, 0x25, + 0x00, 0xF0, 0x52, 0xFA, 0x4E, 0x4E, 0x80, 0x3E, 0x90, 0xB9, 0x00, 0x22, + 0x4F, 0xF4, 0x00, 0x54, 0x6B, 0x46, 0x21, 0x46, 0x10, 0x46, 0x0D, 0xF0, + 0xCB, 0xFB, 0x21, 0x46, 0x00, 0x20, 0x0D, 0xF0, 0xA6, 0xFB, 0x30, 0x78, + 0x20, 0xB1, 0x0A, 0xF0, 0x26, 0xFF, 0x00, 0x20, 0xBD, 0xE8, 0xFC, 0x81, + 0x03, 0x24, 0x39, 0x46, 0x40, 0x46, 0x0F, 0xF0, 0x45, 0xFB, 0x00, 0x22, + 0x01, 0xAB, 0x01, 0x21, 0x10, 0x46, 0x0D, 0xF0, 0xB5, 0xFB, 0x01, 0x21, + 0x00, 0x20, 0x0D, 0xF0, 0x90, 0xFB, 0x30, 0x78, 0x30, 0xB1, 0x0A, 0xF0, + 0x10, 0xFF, 0x64, 0x1E, 0x00, 0x2C, 0xEA, 0xDC, 0x28, 0x46, 0xE5, 0xE7, + 0x7D, 0x68, 0xFB, 0xE7, 0x36, 0x49, 0x80, 0x39, 0x08, 0x70, 0x01, 0x21, + 0x00, 0x20, 0x0D, 0xF0, 0x4F, 0xBB, 0x70, 0xB5, 0x0D, 0x46, 0x04, 0x46, + 0x50, 0x21, 0x0E, 0xF0, 0xFA, 0xFD, 0x31, 0x48, 0xE4, 0xE8, 0x05, 0x05, + 0x0C, 0xF0, 0xB1, 0xFC, 0x44, 0xF8, 0x0C, 0x0C, 0xFF, 0xF7, 0xFF, 0xFB, + 0x44, 0xE9, 0x01, 0x01, 0x2C, 0x48, 0x00, 0x21, 0x21, 0x71, 0x00, 0x68, + 0xB0, 0xF8, 0xAA, 0x24, 0xE2, 0x80, 0xB0, 0xF8, 0xA6, 0x24, 0x22, 0x81, + 0xB0, 0xF8, 0xA8, 0x24, 0x62, 0x81, 0x90, 0xF8, 0xA4, 0x24, 0x22, 0x73, + 0xA1, 0x73, 0x90, 0xF8, 0xA5, 0x24, 0x02, 0xF0, 0x3F, 0x02, 0xE2, 0x73, + 0x90, 0xF8, 0xA2, 0x24, 0xC2, 0xF3, 0x01, 0x12, 0x22, 0x74, 0x90, 0xF8, + 0xA2, 0x24, 0x92, 0x09, 0x62, 0x74, 0x90, 0xF8, 0xA2, 0x24, 0x02, 0xF0, + 0x03, 0x02, 0xA2, 0x74, 0x90, 0xF8, 0xA2, 0x24, 0xC2, 0xF3, 0x81, 0x02, + 0xE2, 0x74, 0x90, 0xF8, 0xA5, 0x24, 0x02, 0xF0, 0x3F, 0x02, 0x22, 0x75, + 0x90, 0xF8, 0xA3, 0x24, 0xC2, 0xF3, 0x01, 0x12, 0x62, 0x75, 0x90, 0xF8, + 0xA3, 0x24, 0x92, 0x09, 0xA2, 0x75, 0x90, 0xF8, 0xA3, 0x24, 0x02, 0xF0, + 0x03, 0x02, 0xE2, 0x75, 0x90, 0xF8, 0xA3, 0x24, 0xC2, 0xF3, 0x81, 0x02, + 0x22, 0x76, 0x61, 0x76, 0xA1, 0x76, 0xE1, 0x76, 0x21, 0x77, 0x61, 0x77, + 0xA1, 0x77, 0x90, 0xF8, 0xAD, 0x14, 0xE1, 0x77, 0x90, 0xF8, 0xAE, 0x14, + 0x84, 0xF8, 0x20, 0x10, 0xB0, 0xF8, 0xB0, 0x14, 0xE1, 0x85, 0x90, 0xF8, + 0xAF, 0x14, 0xCA, 0x09, 0x21, 0x6B, 0x05, 0xE0, 0x88, 0x22, 0x10, 0x00, + 0x21, 0x0F, 0x00, 0x00, 0x50, 0x24, 0x10, 0x00, 0x62, 0xF3, 0x10, 0x41, + 0x21, 0x63, 0x90, 0xF8, 0xAF, 0x24, 0x92, 0x09, 0x62, 0xF3, 0x51, 0x41, + 0x21, 0x63, 0x90, 0xF8, 0xAF, 0x04, 0x60, 0xF3, 0x92, 0x41, 0x21, 0x63, + 0x70, 0xBD, 0x2D, 0xE9, 0xF0, 0x4F, 0x0D, 0x46, 0xFF, 0x4E, 0xDF, 0xF8, + 0x00, 0xA4, 0xDF, 0xF8, 0x00, 0x84, 0xA5, 0xB0, 0x4F, 0xF0, 0x00, 0x0B, + 0x06, 0xF1, 0x80, 0x07, 0x08, 0xEB, 0x45, 0x09, 0x0A, 0xEB, 0x85, 0x04, + 0x07, 0x28, 0x3E, 0xD2, 0xDF, 0xE8, 0x00, 0xF0, 0x8C, 0x04, 0x11, 0x2E, + 0x3E, 0x50, 0x6E, 0x00, 0x14, 0xA8, 0x00, 0xF0, 0xC1, 0xF9, 0x16, 0x98, + 0xF0, 0x64, 0xDD, 0xE9, 0x18, 0x01, 0xC7, 0xE9, 0x02, 0x01, 0x14, 0xA8, + 0x00, 0xF0, 0x85, 0xF9, 0x2A, 0xE0, 0xEF, 0x49, 0x68, 0x46, 0xFF, 0xF7, + 0x5A, 0xFF, 0x02, 0x98, 0xF0, 0x64, 0xDD, 0xE9, 0x04, 0x01, 0xC7, 0xE9, + 0x02, 0x01, 0x69, 0x46, 0x00, 0x20, 0xFF, 0xF7, 0x12, 0xFF, 0x83, 0x46, + 0x70, 0x69, 0xE7, 0x49, 0x42, 0x00, 0xE7, 0x48, 0x0E, 0xF0, 0xA8, 0xFC, + 0x70, 0x69, 0xB3, 0x69, 0x42, 0x00, 0x0A, 0xEB, 0x40, 0x01, 0x08, 0xEB, + 0x43, 0x00, 0x3C, 0xE0, 0xE1, 0x49, 0x68, 0x46, 0xFF, 0xF7, 0x3D, 0xFF, + 0x02, 0x98, 0xF0, 0x64, 0xDD, 0xE9, 0x04, 0x01, 0xC7, 0xE9, 0x02, 0x01, + 0x69, 0x46, 0x01, 0x20, 0xFF, 0xF7, 0xF5, 0xFE, 0x83, 0x46, 0x4D, 0xE0, + 0x21, 0x46, 0x68, 0x46, 0xFF, 0xF7, 0x2D, 0xFF, 0x02, 0x98, 0xF0, 0x64, + 0x01, 0x21, 0x28, 0x46, 0xFF, 0xF7, 0x73, 0xFC, 0x02, 0x90, 0xDD, 0xE9, + 0x04, 0x01, 0xC7, 0xE9, 0x02, 0x01, 0x69, 0x46, 0x00, 0x20, 0x2F, 0xE0, + 0xCF, 0x49, 0x68, 0x46, 0xFF, 0xF7, 0x1B, 0xFF, 0x02, 0x98, 0xF0, 0x64, + 0x00, 0x21, 0x28, 0x46, 0xFF, 0xF7, 0x61, 0xFC, 0x02, 0x90, 0xDD, 0xE9, + 0x04, 0x01, 0xC7, 0xE9, 0x02, 0x01, 0x69, 0x46, 0x01, 0x20, 0xFF, 0xF7, + 0xCE, 0xFE, 0x83, 0x46, 0xB0, 0x69, 0x42, 0x00, 0x0A, 0xEB, 0x40, 0x01, + 0x45, 0x43, 0x08, 0xEB, 0x45, 0x00, 0x0E, 0xF0, 0x61, 0xFC, 0x1D, 0xE0, + 0x21, 0x46, 0x68, 0x46, 0xFF, 0xF7, 0xFD, 0xFE, 0x02, 0x98, 0xF0, 0x64, + 0xDD, 0xE9, 0x04, 0x01, 0xC7, 0xE9, 0x02, 0x01, 0x01, 0x21, 0x28, 0x46, + 0xFF, 0xF7, 0x62, 0xFC, 0xCD, 0xE9, 0x04, 0x01, 0x69, 0x46, 0x01, 0x20, + 0xFF, 0xF7, 0xAF, 0xFE, 0x22, 0x88, 0xA9, 0xF8, 0x00, 0x20, 0xB1, 0x69, + 0x83, 0x46, 0x29, 0x44, 0x08, 0xEB, 0x41, 0x00, 0x61, 0x88, 0x01, 0x80, + 0x25, 0xB0, 0x58, 0x46, 0xBD, 0xE8, 0xF0, 0x8F, 0x2D, 0xE9, 0xF0, 0x5F, + 0x00, 0x27, 0x0C, 0xF0, 0x96, 0xFB, 0x4F, 0xEA, 0x40, 0x08, 0xFF, 0xF7, + 0xE4, 0xFA, 0x0E, 0x46, 0xA9, 0x49, 0x05, 0x46, 0x4F, 0xEA, 0x58, 0x00, + 0xC8, 0x64, 0x80, 0x31, 0xC1, 0xE9, 0x02, 0x56, 0x0F, 0xF0, 0xBD, 0xFB, + 0x81, 0x46, 0x0F, 0xF0, 0xE5, 0xFB, 0x82, 0x46, 0x0E, 0xF0, 0x8A, 0xFF, + 0x00, 0x24, 0x4F, 0xF0, 0x01, 0x0B, 0x1B, 0xE0, 0x0B, 0xFA, 0x04, 0xF0, + 0x10, 0xEA, 0x08, 0x0F, 0x15, 0xD0, 0xE0, 0xB2, 0x0E, 0xF0, 0xD4, 0xFE, + 0x01, 0x28, 0x04, 0xD0, 0x02, 0x28, 0x05, 0xD0, 0x03, 0x28, 0x06, 0xD0, + 0x09, 0xE0, 0x39, 0x46, 0x05, 0x20, 0x04, 0xE0, 0x39, 0x46, 0x03, 0x20, + 0x01, 0xE0, 0x39, 0x46, 0x07, 0x20, 0xFF, 0xF7, 0x10, 0xFD, 0x7F, 0x1C, + 0xFF, 0xB2, 0x64, 0x1C, 0x4C, 0x45, 0xE1, 0xDB, 0x0E, 0xF0, 0x66, 0xFF, + 0x00, 0x27, 0x3C, 0x46, 0x1F, 0xE0, 0x22, 0x46, 0x01, 0x20, 0x00, 0x21, + 0x0E, 0xF0, 0xC1, 0xFB, 0x28, 0x40, 0x31, 0x40, 0x08, 0x43, 0x15, 0xD0, + 0xE0, 0xB2, 0x0E, 0xF0, 0xFF, 0xFE, 0x01, 0x28, 0x04, 0xD0, 0x02, 0x28, + 0x05, 0xD0, 0x03, 0x28, 0x06, 0xD0, 0x09, 0xE0, 0x39, 0x46, 0x06, 0x20, + 0x04, 0xE0, 0x39, 0x46, 0x04, 0x20, 0x01, 0xE0, 0x39, 0x46, 0x08, 0x20, + 0xFF, 0xF7, 0xE9, 0xFC, 0x7F, 0x1C, 0xFF, 0xB2, 0x64, 0x1C, 0x54, 0x45, + 0xDD, 0xDD, 0xBD, 0xE8, 0xF0, 0x5F, 0x0E, 0xF0, 0x3D, 0xBF, 0xF0, 0xB5, + 0x85, 0xB0, 0x00, 0x20, 0x0D, 0xF0, 0x73, 0xFA, 0xFF, 0xF7, 0x3F, 0xFB, + 0x01, 0x28, 0x79, 0xD1, 0x76, 0x4D, 0x79, 0x4C, 0x68, 0x88, 0x20, 0xB9, + 0x21, 0x68, 0x91, 0xF8, 0xA0, 0x14, 0xC9, 0x07, 0x01, 0xD1, 0xC0, 0x07, + 0x01, 0xD0, 0xFF, 0xF7, 0x83, 0xFF, 0x68, 0x88, 0x20, 0xB9, 0x21, 0x68, + 0x91, 0xF8, 0xA0, 0x14, 0x49, 0x07, 0x01, 0xD4, 0x40, 0x07, 0x03, 0xD5, + 0x00, 0xF0, 0xDC, 0xF9, 0x01, 0x28, 0x69, 0xD1, 0x68, 0x88, 0x20, 0xB9, + 0x21, 0x68, 0x91, 0xF8, 0xA0, 0x14, 0x09, 0x07, 0x01, 0xD4, 0x00, 0x07, + 0x03, 0xD5, 0x00, 0xF0, 0x97, 0xF9, 0x01, 0x28, 0x5C, 0xD1, 0x68, 0x88, + 0x20, 0xB9, 0x21, 0x68, 0x91, 0xF8, 0xA0, 0x14, 0xC9, 0x06, 0x01, 0xD4, + 0xC0, 0x06, 0x03, 0xD5, 0x00, 0xF0, 0x5D, 0xF9, 0x01, 0x28, 0x4F, 0xD1, + 0x68, 0x88, 0x20, 0xB9, 0x21, 0x68, 0x91, 0xF8, 0xA0, 0x14, 0x89, 0x06, + 0x01, 0xD4, 0x80, 0x06, 0x03, 0xD5, 0x00, 0xF0, 0x03, 0xF9, 0x01, 0x28, + 0x42, 0xD1, 0x68, 0x88, 0x20, 0xB9, 0x21, 0x68, 0x91, 0xF8, 0xA0, 0x14, + 0x49, 0x06, 0x01, 0xD4, 0x40, 0x06, 0x03, 0xD5, 0x00, 0xF0, 0xC8, 0xF8, + 0x01, 0x28, 0x35, 0xD1, 0x68, 0x88, 0x20, 0xB9, 0x21, 0x68, 0x91, 0xF8, + 0xA0, 0x14, 0x89, 0x07, 0x01, 0xD4, 0x80, 0x07, 0x2A, 0xD5, 0x00, 0x21, + 0x01, 0x20, 0xFF, 0xF7, 0x90, 0xFE, 0x05, 0x00, 0x1D, 0xD0, 0x0C, 0xF0, + 0xCC, 0xFA, 0x04, 0x90, 0x0C, 0xF0, 0xB2, 0xFA, 0xCD, 0xE9, 0x02, 0x01, + 0x04, 0x21, 0x04, 0xA8, 0x10, 0xF0, 0xC0, 0xFC, 0x07, 0x46, 0x08, 0x21, + 0x02, 0xA8, 0x10, 0xF0, 0xBB, 0xFC, 0x01, 0x46, 0x02, 0x20, 0x01, 0x26, + 0xCD, 0xE9, 0x00, 0x60, 0x20, 0x68, 0x2A, 0x46, 0x90, 0xF8, 0xB3, 0x34, + 0x38, 0x46, 0xFF, 0xF7, 0x0D, 0xFD, 0x06, 0xE0, 0x08, 0xE0, 0x01, 0x22, + 0x0F, 0x21, 0x05, 0x20, 0x0A, 0xF0, 0x06, 0xFE, 0x00, 0x26, 0x0E, 0xB1, + 0xFF, 0xF7, 0xA1, 0xFB, 0x05, 0xB0, 0x00, 0x20, 0xBD, 0xE8, 0xF0, 0x40, + 0x0D, 0xF0, 0x00, 0xBA, 0x10, 0xB5, 0x0F, 0xF0, 0x7F, 0xF8, 0x08, 0xB1, + 0x01, 0x20, 0x10, 0xBD, 0x32, 0x48, 0x0F, 0xF0, 0x99, 0xF8, 0x00, 0x20, + 0x10, 0xBD, 0x2D, 0xE9, 0xFC, 0x41, 0x07, 0x46, 0x00, 0x25, 0xFF, 0xF7, + 0xEF, 0xFF, 0x29, 0x4E, 0x88, 0xB9, 0x00, 0x22, 0x4F, 0xF4, 0x00, 0x54, + 0x6B, 0x46, 0x21, 0x46, 0x10, 0x46, 0x0D, 0xF0, 0x69, 0xF9, 0x21, 0x46, + 0x00, 0x20, 0x0D, 0xF0, 0x44, 0xF9, 0x30, 0x78, 0x18, 0xB1, 0x0A, 0xF0, + 0xC4, 0xFC, 0x00, 0x20, 0x9C, 0xE5, 0x03, 0x24, 0x38, 0x46, 0x0E, 0xF0, + 0x2D, 0xFF, 0x00, 0x22, 0x01, 0xAB, 0x01, 0x21, 0x10, 0x46, 0x0D, 0xF0, + 0x55, 0xF9, 0x01, 0x21, 0x00, 0x20, 0x0D, 0xF0, 0x30, 0xF9, 0x30, 0x78, + 0x30, 0xB1, 0x0A, 0xF0, 0xB0, 0xFC, 0x64, 0x1E, 0x00, 0x2C, 0xEB, 0xDC, + 0x28, 0x46, 0x85, 0xE5, 0x7D, 0x68, 0xFB, 0xE7, 0x1F, 0xB5, 0x04, 0x46, + 0x40, 0x21, 0x0E, 0xF0, 0xA2, 0xFB, 0x68, 0x46, 0x0E, 0xF0, 0x88, 0xFE, + 0x13, 0x48, 0x20, 0x60, 0x0F, 0x48, 0x60, 0x60, 0x0C, 0xF0, 0x55, 0xFA, + 0x44, 0xF8, 0x08, 0x0F, 0x0C, 0xF0, 0x3A, 0xFA, 0xC4, 0xE9, 0x02, 0x01, + 0x00, 0x20, 0x20, 0x74, 0x9D, 0xF8, 0x00, 0x00, 0xA0, 0x74, 0x09, 0x48, + 0x00, 0x68, 0x90, 0xF8, 0xB2, 0x04, 0x60, 0x74, 0x9D, 0xF8, 0x01, 0x00, + 0xE0, 0x74, 0x9D, 0xF8, 0x02, 0x00, 0x20, 0x75, 0x0C, 0xE0, 0x00, 0x00, + 0x08, 0x22, 0x10, 0x00, 0xF0, 0xC7, 0x01, 0x20, 0x38, 0xA9, 0x01, 0x20, + 0x50, 0x24, 0x10, 0x00, 0x3D, 0x07, 0x00, 0x00, 0x21, 0x0F, 0x00, 0x00, + 0x9D, 0xF8, 0x03, 0x00, 0x60, 0x75, 0x9D, 0xF8, 0x07, 0x00, 0x60, 0x76, + 0x9D, 0xF8, 0x08, 0x00, 0xA0, 0x76, 0x9D, 0xF8, 0x09, 0x00, 0xE0, 0x76, + 0x9D, 0xF8, 0x0A, 0x00, 0x20, 0x77, 0x9D, 0xF8, 0x0B, 0x00, 0x60, 0x77, + 0x9D, 0xF8, 0x0D, 0x00, 0xE0, 0x77, 0x9D, 0xF8, 0x0E, 0x00, 0x0E, 0xF0, + 0x5A, 0xFE, 0x1F, 0xBD, 0x2D, 0xE9, 0xF0, 0x41, 0x8A, 0x4E, 0x00, 0x20, + 0x05, 0x46, 0x8A, 0x4F, 0xF0, 0x61, 0x18, 0xE0, 0x29, 0x46, 0x06, 0x20, + 0xFF, 0xF7, 0xCB, 0xFD, 0x04, 0x00, 0x18, 0xD0, 0x39, 0x68, 0xB4, 0xF9, + 0x02, 0x00, 0x91, 0xF8, 0xB8, 0x14, 0xB0, 0xEB, 0x01, 0x1F, 0x03, 0xD9, + 0x29, 0x46, 0x08, 0x20, 0xFF, 0xF7, 0xA9, 0xFB, 0xB4, 0xF9, 0x02, 0x00, + 0xF1, 0x69, 0x88, 0x42, 0x00, 0xDD, 0xF0, 0x61, 0x6D, 0x1C, 0xB0, 0x69, + 0x85, 0x42, 0xE3, 0xD3, 0x01, 0x20, 0xBD, 0xE8, 0xF0, 0x81, 0x06, 0x22, + 0x0F, 0x21, 0x05, 0x20, 0x0A, 0xF0, 0x46, 0xFD, 0x00, 0x20, 0xF6, 0xE7, + 0x2D, 0xE9, 0xF0, 0x41, 0x73, 0x4F, 0x00, 0x20, 0x06, 0x46, 0x78, 0x62, + 0x39, 0xE0, 0x31, 0x46, 0x05, 0x20, 0xFF, 0xF7, 0x9E, 0xFD, 0x05, 0x00, + 0x38, 0xD0, 0x00, 0x24, 0x2D, 0xE0, 0xFF, 0xF7, 0x2A, 0xF9, 0x02, 0x46, + 0x0B, 0x46, 0x20, 0x46, 0xFF, 0xF7, 0x64, 0xFB, 0x02, 0x46, 0x01, 0x20, + 0x00, 0x21, 0x0E, 0xF0, 0x3A, 0xFA, 0xD7, 0xE9, 0x16, 0x23, 0x10, 0x40, + 0x19, 0x40, 0x08, 0x43, 0x1A, 0xD1, 0x65, 0x49, 0xB8, 0x69, 0x09, 0x68, + 0x20, 0x44, 0x35, 0xF9, 0x10, 0x00, 0x91, 0xF8, 0xB7, 0x14, 0xB0, 0xEB, + 0x01, 0x1F, 0x07, 0xD9, 0x31, 0x46, 0x07, 0x20, 0xFF, 0xF7, 0x65, 0xFB, + 0x21, 0x46, 0x08, 0x20, 0xFF, 0xF7, 0x61, 0xFB, 0xB8, 0x69, 0x79, 0x6A, + 0x20, 0x44, 0x35, 0xF9, 0x10, 0x00, 0x88, 0x42, 0x00, 0xDD, 0x78, 0x62, + 0x64, 0x1C, 0xB8, 0x69, 0x84, 0x42, 0xCE, 0xD3, 0x76, 0x1C, 0x78, 0x69, + 0x86, 0x42, 0xC2, 0xD3, 0x01, 0x20, 0xB0, 0xE7, 0x05, 0x22, 0x0F, 0x21, + 0x10, 0x46, 0x0A, 0xF0, 0xF9, 0xFC, 0x00, 0x20, 0xA9, 0xE7, 0x2D, 0xE9, + 0xF0, 0x41, 0x4D, 0x4E, 0x00, 0x20, 0x05, 0x46, 0x4C, 0x4F, 0x30, 0x62, + 0x18, 0xE0, 0x29, 0x46, 0x04, 0x20, 0xFF, 0xF7, 0x50, 0xFD, 0x04, 0x00, + 0x17, 0xD0, 0x39, 0x68, 0xB4, 0xF9, 0x02, 0x00, 0x91, 0xF8, 0xB6, 0x14, + 0xB0, 0xEB, 0x01, 0x1F, 0x03, 0xD9, 0x29, 0x46, 0x07, 0x20, 0xFF, 0xF7, + 0x2E, 0xFB, 0xB4, 0xF9, 0x02, 0x00, 0x31, 0x6A, 0x88, 0x42, 0x00, 0xDD, + 0x30, 0x62, 0x6D, 0x1C, 0x70, 0x69, 0x85, 0x42, 0xE3, 0xD3, 0x01, 0x20, + 0x83, 0xE7, 0x04, 0x22, 0x0F, 0x21, 0x05, 0x20, 0x0A, 0xF0, 0xCC, 0xFC, + 0x00, 0x20, 0x7C, 0xE7, 0x2D, 0xE9, 0xF0, 0x47, 0x00, 0x21, 0x03, 0x20, + 0xFF, 0xF7, 0x29, 0xFD, 0x05, 0x00, 0x28, 0xD0, 0x33, 0x48, 0x08, 0x21, + 0x88, 0x30, 0x10, 0xF0, 0x5F, 0xFB, 0x06, 0x46, 0x00, 0x24, 0xDF, 0xF8, + 0xC0, 0x80, 0xDF, 0xF8, 0xC0, 0x90, 0x17, 0xE0, 0xD9, 0xF8, 0x00, 0x00, + 0x37, 0x19, 0x35, 0xF9, 0x17, 0x10, 0x90, 0xF8, 0xB5, 0x04, 0xB1, 0xEB, + 0x00, 0x1F, 0x03, 0xD9, 0x21, 0x46, 0x04, 0x20, 0xFF, 0xF7, 0xF9, 0xFA, + 0x35, 0xF9, 0x17, 0x00, 0xD8, 0xF8, 0x2C, 0x20, 0x90, 0x42, 0x01, 0xDD, + 0xC8, 0xF8, 0x2C, 0x00, 0x64, 0x1C, 0x64, 0xB2, 0xB4, 0x42, 0xE5, 0xDB, + 0x01, 0x20, 0xBD, 0xE8, 0xF0, 0x87, 0x03, 0x22, 0x0F, 0x21, 0x05, 0x20, + 0x0A, 0xF0, 0x94, 0xFC, 0x00, 0x20, 0xF6, 0xE7, 0x2D, 0xE9, 0xF0, 0x47, + 0x00, 0x21, 0x02, 0x20, 0xFF, 0xF7, 0xF1, 0xFC, 0x05, 0x00, 0x27, 0xD0, + 0x17, 0x48, 0x04, 0x21, 0x4C, 0x30, 0x10, 0xF0, 0x27, 0xFB, 0x06, 0x46, + 0x00, 0x24, 0xDF, 0xF8, 0x50, 0x80, 0xDF, 0xF8, 0x50, 0x90, 0x17, 0xE0, + 0xD9, 0xF8, 0x00, 0x00, 0x37, 0x19, 0x35, 0xF9, 0x17, 0x10, 0x90, 0xF8, + 0xB4, 0x04, 0xB1, 0xEB, 0x00, 0x1F, 0x03, 0xD9, 0x21, 0x46, 0x03, 0x20, + 0xFF, 0xF7, 0xC1, 0xFA, 0x35, 0xF9, 0x17, 0x00, 0xD8, 0xF8, 0x28, 0x20, + 0x90, 0x42, 0x01, 0xDD, 0xC8, 0xF8, 0x28, 0x00, 0x64, 0x1C, 0x64, 0xB2, + 0xB4, 0x42, 0xE5, 0xDB, 0x01, 0x20, 0xC6, 0xE7, 0x02, 0x22, 0x0F, 0x21, + 0x05, 0x20, 0x0A, 0xF0, 0x5D, 0xFC, 0x00, 0x20, 0xBF, 0xE7, 0x00, 0x00, + 0x08, 0x22, 0x10, 0x00, 0x50, 0x24, 0x10, 0x00, 0x10, 0xB5, 0x04, 0x46, + 0x02, 0x21, 0x00, 0x20, 0x0C, 0xF0, 0x88, 0xFF, 0x0F, 0x48, 0x04, 0x60, + 0x10, 0xBD, 0x08, 0xB5, 0x0E, 0x48, 0x10, 0xF0, 0x0F, 0xFA, 0x00, 0x22, + 0x6B, 0x46, 0x02, 0x21, 0x10, 0x46, 0x0C, 0xF0, 0xCB, 0xFF, 0x02, 0x21, + 0x00, 0x20, 0x0C, 0xF0, 0xA6, 0xFF, 0x09, 0x48, 0x55, 0x22, 0x01, 0x68, + 0x05, 0x48, 0x01, 0xF8, 0x20, 0x2F, 0x00, 0x68, 0x48, 0x70, 0x02, 0x0A, + 0x8A, 0x70, 0x02, 0x0C, 0xCA, 0x70, 0x10, 0xF0, 0xBB, 0xFA, 0x08, 0xBD, + 0x98, 0x22, 0x10, 0x00, 0xB1, 0x16, 0x00, 0x00, 0x54, 0x24, 0x10, 0x00, + 0x10, 0xB5, 0x01, 0x46, 0x44, 0x22, 0x36, 0x48, 0x0E, 0xF0, 0xB1, 0xF9, + 0x01, 0x21, 0xBD, 0xE8, 0x10, 0x40, 0x00, 0x20, 0x0C, 0xF0, 0x56, 0xBF, + 0x2D, 0xE9, 0xF0, 0x4F, 0x85, 0xB0, 0x24, 0x21, 0x30, 0x48, 0x0E, 0xF0, + 0xDE, 0xF9, 0x0C, 0x25, 0xDF, 0xF8, 0xBC, 0xB0, 0xDF, 0xF8, 0xB0, 0x90, + 0xDF, 0xF8, 0xB8, 0x80, 0x00, 0x26, 0x4F, 0xF0, 0x07, 0x0A, 0xEC, 0xB2, + 0x68, 0x46, 0x0B, 0xF0, 0x0C, 0xFF, 0xAD, 0xF8, 0x0C, 0x40, 0x8D, 0xF8, + 0x04, 0xA0, 0x03, 0x24, 0x4F, 0x46, 0xCD, 0xF8, 0x00, 0xB0, 0x68, 0x46, + 0x0B, 0xF0, 0x38, 0xFF, 0x00, 0x22, 0x04, 0xAB, 0x01, 0x21, 0x10, 0x46, + 0x0C, 0xF0, 0x80, 0xFF, 0x01, 0x21, 0x00, 0x20, 0x0C, 0xF0, 0x5B, 0xFF, + 0x97, 0xF8, 0x42, 0x00, 0x20, 0xB1, 0x0A, 0xF0, 0xDA, 0xFA, 0x64, 0x1E, + 0x00, 0x2C, 0xEA, 0xDC, 0xD8, 0xF8, 0x00, 0x00, 0xB9, 0x46, 0x3F, 0x68, + 0x90, 0xF8, 0x10, 0x01, 0x80, 0x06, 0x13, 0xD5, 0x01, 0x24, 0xD8, 0xF8, + 0x00, 0x00, 0x01, 0x7D, 0xB0, 0xF9, 0x24, 0x21, 0xCD, 0xE9, 0x00, 0x21, + 0xB0, 0xF9, 0x22, 0x31, 0x61, 0x43, 0x07, 0xEB, 0x41, 0x00, 0x3A, 0x46, + 0x01, 0x46, 0x0B, 0xF0, 0xB1, 0xF9, 0x64, 0x1C, 0x10, 0x2C, 0xEC, 0xDB, + 0xD8, 0xF8, 0x00, 0x00, 0x10, 0x21, 0x02, 0x7D, 0xD9, 0xF8, 0x00, 0x00, + 0x0B, 0xF0, 0x60, 0xFA, 0x07, 0x49, 0x21, 0xF8, 0x16, 0x50, 0x01, 0xEB, + 0x46, 0x01, 0xAD, 0x1C, 0xAD, 0xB2, 0x76, 0x1C, 0x48, 0x82, 0x1C, 0x2D, + 0xAF, 0xD9, 0x05, 0xB0, 0xBD, 0xE8, 0xF0, 0x8F, 0x30, 0x26, 0x10, 0x00, + 0xAC, 0x00, 0x01, 0x20, 0x09, 0x17, 0x00, 0x00, 0x50, 0x24, 0x10, 0x00, + 0x10, 0xB5, 0x01, 0x46, 0x44, 0x22, 0xFE, 0x48, 0x0E, 0xF0, 0x39, 0xF9, + 0x01, 0x21, 0xBD, 0xE8, 0x10, 0x40, 0x00, 0x20, 0x0C, 0xF0, 0xDE, 0xBE, + 0x30, 0xB5, 0x85, 0xB0, 0x04, 0x46, 0x68, 0x46, 0x0B, 0xF0, 0xA3, 0xFE, + 0xF7, 0x48, 0x00, 0x90, 0x24, 0xB3, 0x01, 0x2C, 0x24, 0xD0, 0x02, 0x2C, + 0x24, 0xD0, 0x03, 0x2C, 0x26, 0xD0, 0x04, 0x2C, 0x1A, 0xD1, 0x03, 0x20, + 0x8D, 0xF8, 0x05, 0x00, 0xEF, 0x4D, 0x03, 0x24, 0x68, 0x46, 0x0B, 0xF0, + 0xC7, 0xFE, 0x00, 0x22, 0x04, 0xAB, 0x01, 0x21, 0x10, 0x46, 0x0C, 0xF0, + 0x0F, 0xFF, 0x01, 0x21, 0x00, 0x20, 0x0C, 0xF0, 0xEA, 0xFE, 0x95, 0xF8, + 0x42, 0x00, 0x00, 0x28, 0x04, 0xD0, 0x0A, 0xF0, 0x68, 0xFA, 0x64, 0x1E, + 0x00, 0x2C, 0xE9, 0xDC, 0x05, 0xB0, 0x30, 0xBD, 0x04, 0x20, 0x02, 0xE0, + 0x05, 0x20, 0x00, 0xE0, 0x06, 0x20, 0x8D, 0xF8, 0x04, 0x00, 0xDD, 0xE7, + 0x02, 0x20, 0xD9, 0xE7, 0x2D, 0xE9, 0xF0, 0x5F, 0x91, 0x46, 0xDC, 0x4A, + 0x82, 0x46, 0x01, 0x27, 0x0E, 0x46, 0xDF, 0xF8, 0x70, 0x83, 0x3B, 0x02, + 0x10, 0x68, 0x51, 0x46, 0xBA, 0xF1, 0x06, 0x0F, 0x0C, 0xD2, 0xDF, 0xE8, + 0x0A, 0xF0, 0x06, 0x06, 0x03, 0x09, 0x09, 0x03, 0x04, 0x46, 0x1D, 0x46, + 0x04, 0xE0, 0x04, 0x46, 0x01, 0x25, 0x01, 0xE0, 0x94, 0x68, 0x02, 0x25, + 0x96, 0xF8, 0x00, 0xB0, 0x00, 0x20, 0x30, 0x70, 0x08, 0x46, 0xFF, 0xF7, + 0xA5, 0xFF, 0x4F, 0xEA, 0x49, 0x02, 0x21, 0x46, 0x40, 0x46, 0x0E, 0xF0, + 0x8D, 0xF8, 0x0F, 0x20, 0x30, 0x70, 0x50, 0x46, 0xFF, 0xF7, 0x9A, 0xFF, + 0xC9, 0x49, 0x00, 0x20, 0x0A, 0x68, 0x0D, 0xE0, 0x34, 0xF9, 0x10, 0x30, + 0x38, 0xF9, 0x10, 0x10, 0x59, 0x1A, 0x00, 0xD5, 0x49, 0x42, 0xB2, 0xF9, + 0x26, 0x37, 0x99, 0x42, 0x01, 0xDA, 0x00, 0x27, 0x02, 0xE0, 0x40, 0x1C, + 0x48, 0x45, 0xEF, 0xD3, 0x86, 0xF8, 0x00, 0xB0, 0x1F, 0xB9, 0x29, 0x46, + 0x30, 0x20, 0x0A, 0xF0, 0x2A, 0xFA, 0x38, 0x46, 0xBD, 0xE8, 0xF0, 0x9F, + 0x2D, 0xE9, 0xFF, 0x5F, 0x93, 0x46, 0xB6, 0x4A, 0x9A, 0x46, 0x01, 0x46, + 0x4F, 0xF0, 0x00, 0x09, 0x01, 0x26, 0x33, 0x02, 0x10, 0x68, 0xC8, 0x46, + 0x4F, 0x46, 0x06, 0x29, 0x0C, 0xD2, 0xDF, 0xE8, 0x01, 0xF0, 0x06, 0x06, + 0x03, 0x09, 0x09, 0x03, 0x04, 0x46, 0x1D, 0x46, 0x04, 0xE0, 0x04, 0x46, + 0x01, 0x25, 0x01, 0xE0, 0x94, 0x68, 0x02, 0x25, 0x08, 0x46, 0xFF, 0xF7, + 0x5D, 0xFF, 0x00, 0x20, 0x40, 0xF6, 0xFF, 0x72, 0x11, 0xE0, 0x34, 0xF9, + 0x10, 0x10, 0x21, 0xB1, 0x91, 0x42, 0x04, 0xD1, 0x4F, 0xF0, 0x01, 0x08, + 0x08, 0xE0, 0x01, 0x27, 0x06, 0xE0, 0x59, 0x45, 0x02, 0xDC, 0x01, 0x9B, + 0x99, 0x42, 0x01, 0xDA, 0x4F, 0xF0, 0x01, 0x09, 0x40, 0x1C, 0x50, 0x45, + 0xEB, 0xD3, 0x27, 0xB1, 0x29, 0x46, 0x21, 0x20, 0x0A, 0xF0, 0xEB, 0xF9, + 0x00, 0x26, 0xB8, 0xF1, 0x00, 0x0F, 0x04, 0xD0, 0x29, 0x46, 0x22, 0x20, + 0x0A, 0xF0, 0xE3, 0xF9, 0x00, 0x26, 0xB9, 0xF1, 0x00, 0x0F, 0x04, 0xD0, + 0x29, 0x46, 0x20, 0x20, 0x0A, 0xF0, 0xDB, 0xF9, 0x00, 0x26, 0x30, 0x46, + 0x04, 0xB0, 0xAD, 0xE7, 0x31, 0xB5, 0x0E, 0xF0, 0xAA, 0xFF, 0x04, 0x00, + 0x07, 0xD4, 0x00, 0x98, 0x01, 0x22, 0x02, 0xFA, 0x04, 0xF1, 0x01, 0x42, + 0x01, 0xD1, 0x64, 0x1E, 0xF9, 0xD5, 0x04, 0x21, 0x68, 0x46, 0x10, 0xF0, + 0x63, 0xF9, 0xC0, 0x07, 0x06, 0xD0, 0x07, 0x20, 0x64, 0x1C, 0x00, 0x99, + 0xA0, 0x40, 0x08, 0x43, 0x00, 0x90, 0x38, 0xBD, 0x03, 0x20, 0xF7, 0xE7, + 0x2D, 0xE9, 0xF1, 0x4F, 0x8C, 0xB0, 0x0B, 0xF0, 0x56, 0xFF, 0x04, 0x90, + 0x0B, 0xF0, 0x3C, 0xFF, 0xCD, 0xE9, 0x02, 0x01, 0x7F, 0x4C, 0x0C, 0x98, + 0x40, 0xB1, 0x01, 0x28, 0x06, 0xD0, 0x20, 0x68, 0xB0, 0xF8, 0x34, 0x97, + 0x7C, 0x48, 0x01, 0x90, 0x7C, 0x48, 0x1C, 0xE0, 0x20, 0x68, 0x90, 0xF8, + 0x7E, 0x07, 0x40, 0x07, 0x03, 0xD5, 0x04, 0x98, 0xFF, 0xF7, 0xC6, 0xFF, + 0x04, 0x90, 0x77, 0x48, 0x08, 0x38, 0x00, 0x78, 0x10, 0xB1, 0x01, 0x28, + 0x04, 0xD0, 0x08, 0xE0, 0x20, 0x68, 0xB0, 0xF8, 0x2C, 0x07, 0x03, 0xE0, + 0x20, 0x68, 0x90, 0xF8, 0x23, 0x07, 0x00, 0x01, 0x81, 0x46, 0x70, 0x48, + 0x01, 0x90, 0x6E, 0x48, 0x00, 0x1F, 0x05, 0x90, 0x20, 0x20, 0x0A, 0x90, + 0x40, 0x20, 0x09, 0x90, 0x04, 0x21, 0x04, 0xA8, 0x10, 0xF0, 0x1C, 0xF9, + 0x04, 0x46, 0x08, 0x21, 0x02, 0xA8, 0x10, 0xF0, 0x17, 0xF9, 0x44, 0x43, + 0x62, 0x48, 0x61, 0x00, 0x80, 0x46, 0x0E, 0xF0, 0x36, 0xF8, 0x4F, 0xF4, + 0x80, 0x71, 0x64, 0x48, 0x0E, 0xF0, 0x53, 0xF8, 0x05, 0x98, 0x00, 0x21, + 0x0D, 0x46, 0x01, 0x80, 0x0C, 0x98, 0xFF, 0xF7, 0xBD, 0xFE, 0x58, 0x48, + 0x00, 0x68, 0x08, 0x90, 0x00, 0x20, 0x04, 0x46, 0x00, 0x90, 0x01, 0x20, + 0x00, 0x26, 0x06, 0x90, 0x79, 0xE0, 0x01, 0x20, 0x04, 0x99, 0xB0, 0x40, + 0x08, 0x42, 0x73, 0xD0, 0x00, 0x27, 0x5E, 0xE0, 0x3A, 0x46, 0x01, 0x20, + 0x00, 0x21, 0x0D, 0xF0, 0x5E, 0xFF, 0xDD, 0xE9, 0x02, 0x23, 0x82, 0x46, + 0x8B, 0x46, 0x10, 0x40, 0x19, 0x40, 0x08, 0x43, 0x50, 0xD0, 0x50, 0x48, + 0x00, 0xEB, 0xC6, 0x00, 0x07, 0x90, 0xD0, 0xE9, 0x00, 0x10, 0x01, 0xEA, + 0x0A, 0x01, 0x00, 0xEA, 0x0B, 0x00, 0x01, 0x43, 0x43, 0xD1, 0x00, 0x2D, + 0x0E, 0xDD, 0x08, 0x98, 0x38, 0xF9, 0x14, 0x10, 0x30, 0xF9, 0x14, 0x00, + 0x08, 0x1A, 0x00, 0xD5, 0x40, 0x42, 0x05, 0x99, 0x80, 0xB2, 0x09, 0x88, + 0x81, 0x42, 0x01, 0xD2, 0x05, 0x99, 0x08, 0x80, 0x08, 0x98, 0x30, 0xF9, + 0x14, 0x20, 0x4A, 0x45, 0x22, 0xDC, 0x00, 0x2D, 0x20, 0xDD, 0x38, 0xF9, + 0x14, 0x10, 0xB1, 0xEB, 0x09, 0x00, 0xA2, 0xEB, 0x09, 0x01, 0x00, 0xD5, + 0x40, 0x42, 0x00, 0x29, 0x00, 0xDA, 0x49, 0x42, 0x88, 0x42, 0x07, 0xDC, + 0x68, 0x1E, 0xC3, 0xB2, 0xDD, 0xE9, 0x00, 0x10, 0x3A, 0x46, 0x0E, 0xF0, + 0x08, 0xFA, 0x01, 0xE0, 0x28, 0xF8, 0x14, 0x20, 0x07, 0x98, 0xD0, 0xE9, + 0x00, 0x21, 0x42, 0xEA, 0x0A, 0x02, 0x41, 0xEA, 0x0B, 0x01, 0xC0, 0xE9, + 0x00, 0x21, 0x0A, 0xE0, 0x3F, 0x2D, 0x08, 0xDA, 0x28, 0xF8, 0x14, 0x20, + 0x68, 0x1C, 0xC3, 0xB2, 0xDD, 0xE9, 0x00, 0x10, 0x3A, 0x46, 0x0E, 0xF0, + 0xF0, 0xF9, 0x64, 0x1C, 0x7F, 0x1C, 0x09, 0x98, 0x87, 0x42, 0x9D, 0xDB, + 0x25, 0x48, 0x00, 0xEB, 0xC6, 0x00, 0xD0, 0xE9, 0x00, 0x10, 0xDD, 0xE9, + 0x02, 0x23, 0x51, 0x40, 0x58, 0x40, 0x01, 0x43, 0x01, 0xD0, 0x00, 0x20, + 0x06, 0x90, 0x00, 0x98, 0x40, 0x1C, 0x00, 0x90, 0x76, 0x1C, 0x0A, 0x98, + 0x86, 0x42, 0x82, 0xDB, 0x06, 0x98, 0x01, 0x28, 0x03, 0xD0, 0x6D, 0x1C, + 0x3F, 0x2D, 0x7F, 0xF7, 0x6F, 0xAF, 0x0D, 0xB0, 0xBD, 0xE8, 0xF0, 0x8F, + 0x2D, 0xE9, 0xFF, 0x5F, 0x82, 0x46, 0x0B, 0xF0, 0x72, 0xFE, 0x00, 0x90, + 0x0B, 0xF0, 0x58, 0xFE, 0x13, 0x4D, 0x0E, 0x4C, 0xBA, 0xF1, 0x00, 0x0F, + 0xCD, 0xE9, 0x02, 0x01, 0x38, 0xD0, 0xBA, 0xF1, 0x01, 0x0F, 0x35, 0xD0, + 0x20, 0x68, 0x0B, 0x4F, 0xB0, 0xF8, 0x32, 0x97, 0x28, 0x68, 0xBF, 0x1E, + 0x00, 0xF1, 0x03, 0x08, 0x04, 0x21, 0x68, 0x46, 0x10, 0xF0, 0x56, 0xF8, + 0x06, 0x46, 0x11, 0xE0, 0x78, 0x27, 0x10, 0x00, 0xF9, 0x17, 0x00, 0x00, + 0x60, 0x54, 0x10, 0x00, 0x50, 0x24, 0x10, 0x00, 0x80, 0x13, 0x10, 0x00, + 0xA4, 0x22, 0x10, 0x00, 0x40, 0x10, 0x10, 0x00, 0x78, 0x26, 0x10, 0x00, + 0x54, 0x24, 0x10, 0x00, 0x08, 0x21, 0x02, 0xA8, 0x10, 0xF0, 0x3E, 0xF8, + 0x46, 0x43, 0x00, 0x20, 0x47, 0xF6, 0xFF, 0x75, 0x38, 0x80, 0x04, 0x46, + 0xAB, 0x46, 0x88, 0xF8, 0x00, 0x40, 0x50, 0x46, 0xFF, 0xF7, 0xEA, 0xFD, + 0x84, 0x48, 0xDC, 0x46, 0x59, 0x46, 0x03, 0x68, 0x00, 0x20, 0x16, 0xE0, + 0x20, 0x68, 0x90, 0xF8, 0x7E, 0x07, 0x40, 0x07, 0x03, 0xD5, 0x00, 0x98, + 0xFF, 0xF7, 0xB0, 0xFE, 0x00, 0x90, 0x20, 0x68, 0x7D, 0x4F, 0xB0, 0xF8, + 0x2A, 0x97, 0x28, 0x68, 0x00, 0xF1, 0x01, 0x08, 0xC0, 0xE7, 0x33, 0xF9, + 0x10, 0x20, 0x8A, 0x42, 0x00, 0xDA, 0x11, 0x46, 0x40, 0x1C, 0xB0, 0x42, + 0xF7, 0xDB, 0x65, 0x45, 0x07, 0xD0, 0x68, 0x1A, 0x00, 0xD5, 0x40, 0x42, + 0x3A, 0x88, 0x80, 0xB2, 0x82, 0x42, 0x00, 0xD2, 0x38, 0x80, 0x0D, 0x46, + 0x00, 0x20, 0x0A, 0xE0, 0x33, 0xF9, 0x10, 0x20, 0x4A, 0x45, 0x05, 0xDA, + 0x14, 0xB1, 0x64, 0x1E, 0x88, 0xF8, 0x00, 0x40, 0x01, 0x20, 0x85, 0xE6, + 0x40, 0x1C, 0xB0, 0x42, 0xF2, 0xDB, 0x64, 0x1C, 0xE4, 0xB2, 0x0F, 0x2C, + 0xBD, 0xD9, 0x00, 0x20, 0x7C, 0xE6, 0x2D, 0xE9, 0xFE, 0x43, 0x65, 0x4D, + 0x01, 0x24, 0xAD, 0x1E, 0x28, 0x78, 0x30, 0xB1, 0x01, 0x28, 0x04, 0xD0, + 0x01, 0x21, 0x40, 0x20, 0x0A, 0xF0, 0x49, 0xF8, 0xB9, 0xE0, 0x00, 0x20, + 0x0C, 0xF0, 0x29, 0xFD, 0x28, 0x78, 0x5E, 0x4F, 0x10, 0xB1, 0x01, 0x28, + 0x06, 0xD0, 0x0C, 0xE0, 0x38, 0x68, 0x4F, 0xF0, 0x00, 0x08, 0xB0, 0xF8, + 0x2C, 0x07, 0x05, 0xE0, 0x38, 0x68, 0x4F, 0xF0, 0x01, 0x08, 0x90, 0xF8, + 0x23, 0x07, 0x00, 0x01, 0x68, 0x81, 0x0B, 0xF0, 0xD0, 0xFD, 0x02, 0x90, + 0x0B, 0xF0, 0xB6, 0xFD, 0xCD, 0xE9, 0x00, 0x01, 0x38, 0x68, 0x90, 0xF8, + 0x7E, 0x07, 0x40, 0x07, 0x03, 0xD5, 0x02, 0x98, 0xFF, 0xF7, 0x4C, 0xFE, + 0x02, 0x90, 0x38, 0x68, 0x4D, 0x4E, 0x90, 0xF8, 0x28, 0x17, 0xC9, 0x07, + 0x01, 0xD0, 0x00, 0x20, 0x01, 0xE0, 0x90, 0xF8, 0x2E, 0x07, 0x31, 0x68, + 0x48, 0x70, 0x38, 0x68, 0x90, 0xF8, 0x28, 0x07, 0x80, 0x07, 0x05, 0xD5, + 0xDD, 0xE9, 0x01, 0x31, 0x45, 0x48, 0x00, 0x9A, 0x0D, 0xF0, 0x9A, 0xFF, + 0x38, 0x68, 0x90, 0xF8, 0x28, 0x17, 0xC9, 0x07, 0x0A, 0xD0, 0xB0, 0xF8, + 0x2A, 0x07, 0x68, 0x81, 0x40, 0x46, 0xFF, 0xF7, 0x29, 0xFF, 0x70, 0xB1, + 0x69, 0x88, 0x01, 0x20, 0x0A, 0xF0, 0x1B, 0xFC, 0x38, 0x68, 0xB9, 0x46, + 0x90, 0xF8, 0x28, 0x17, 0x89, 0x07, 0x19, 0xD5, 0x29, 0x78, 0x41, 0xB1, + 0x01, 0x29, 0x09, 0xD0, 0x0C, 0xE0, 0x01, 0x21, 0x08, 0x46, 0x09, 0xF0, + 0xEC, 0xFF, 0x00, 0x24, 0xEE, 0xE7, 0xB0, 0xF8, 0x2C, 0x07, 0x02, 0xE0, + 0x90, 0xF8, 0x23, 0x07, 0x00, 0x01, 0x68, 0x81, 0x40, 0x46, 0xFF, 0xF7, + 0x25, 0xFE, 0x20, 0xB3, 0xA9, 0x88, 0x02, 0x20, 0x0A, 0xF0, 0xFB, 0xFB, + 0x04, 0x21, 0x02, 0xA8, 0x0F, 0xF0, 0x74, 0xFF, 0x07, 0x46, 0x08, 0x21, + 0x68, 0x46, 0x0F, 0xF0, 0x6F, 0xFF, 0x07, 0xFB, 0x00, 0xF3, 0xD9, 0xF8, + 0x00, 0x00, 0x69, 0x89, 0x4F, 0x46, 0x90, 0xF8, 0x2F, 0x07, 0x00, 0xEB, + 0x80, 0x02, 0x40, 0x42, 0x01, 0xEB, 0x42, 0x02, 0x00, 0xEB, 0x80, 0x00, + 0x01, 0xEB, 0x40, 0x00, 0x81, 0xB2, 0x92, 0xB2, 0x40, 0x46, 0xFF, 0xF7, + 0x95, 0xFD, 0x30, 0xB1, 0x06, 0xE0, 0x01, 0x21, 0x02, 0x20, 0x09, 0xF0, + 0xB6, 0xFF, 0x00, 0x24, 0xD8, 0xE7, 0x00, 0x24, 0x04, 0x21, 0x02, 0xA8, + 0x0F, 0xF0, 0x4C, 0xFF, 0x05, 0x46, 0x08, 0x21, 0x68, 0x46, 0x0F, 0xF0, + 0x47, 0xFF, 0x31, 0x68, 0x05, 0xFB, 0x00, 0xF2, 0x40, 0x46, 0x49, 0x1C, + 0xFF, 0xF7, 0x30, 0xFD, 0x00, 0xB9, 0x00, 0x24, 0x40, 0x46, 0xFF, 0xF7, + 0xF3, 0xFC, 0x38, 0x68, 0x31, 0x68, 0x90, 0xF8, 0x29, 0x07, 0x08, 0x70, + 0x38, 0x68, 0x90, 0xF8, 0x30, 0x01, 0x80, 0x07, 0x02, 0xD5, 0x09, 0x48, + 0x0A, 0xF0, 0xC8, 0xFC, 0x00, 0x20, 0x0C, 0xF0, 0x8D, 0xFC, 0x20, 0x46, + 0xBD, 0xE8, 0xFE, 0x83, 0x78, 0x27, 0x10, 0x00, 0x9E, 0x22, 0x10, 0x00, + 0x50, 0x24, 0x10, 0x00, 0x54, 0x24, 0x10, 0x00, 0x40, 0x10, 0x10, 0x00, + 0x70, 0x53, 0x10, 0x00, 0x10, 0xB5, 0x00, 0x23, 0x01, 0x22, 0x19, 0x46, + 0x10, 0x20, 0x0A, 0xF0, 0x7A, 0xFB, 0xFF, 0xF7, 0x24, 0xFC, 0x00, 0x23, + 0x01, 0x22, 0x19, 0x46, 0x20, 0x20, 0x0A, 0xF0, 0x72, 0xFB, 0x00, 0x23, + 0x1A, 0x46, 0x01, 0x21, 0x10, 0x20, 0x0A, 0xF0, 0x6C, 0xFB, 0x25, 0x4C, + 0x20, 0x68, 0x10, 0xF8, 0x3A, 0x1F, 0x21, 0xF0, 0x01, 0x01, 0x01, 0x70, + 0x22, 0x49, 0x00, 0x20, 0x08, 0x70, 0xFF, 0xF7, 0x08, 0xFF, 0x21, 0x68, + 0x01, 0x28, 0x11, 0xF8, 0x3B, 0x2F, 0x60, 0xF3, 0x00, 0x02, 0x0A, 0x70, + 0x1B, 0xD1, 0x00, 0x23, 0x1A, 0x46, 0x01, 0x21, 0x20, 0x20, 0x0A, 0xF0, + 0x52, 0xFB, 0x00, 0x23, 0x10, 0x21, 0x1A, 0x46, 0x08, 0x46, 0x0A, 0xF0, + 0x4C, 0xFB, 0x20, 0x68, 0x10, 0xF8, 0x3A, 0x1F, 0x21, 0xF0, 0x08, 0x01, + 0x01, 0x70, 0x01, 0xF0, 0x12, 0xF8, 0x21, 0x68, 0x01, 0x28, 0x11, 0xF8, + 0x3B, 0x2F, 0x60, 0xF3, 0xC3, 0x02, 0x0A, 0x70, 0x07, 0xD0, 0x00, 0x23, + 0x1A, 0x46, 0x01, 0x21, 0xBD, 0xE8, 0x10, 0x40, 0x07, 0x20, 0x0A, 0xF0, + 0x34, 0xBB, 0x00, 0x23, 0x1A, 0x46, 0x10, 0x21, 0x20, 0x20, 0x0A, 0xF0, + 0x2E, 0xFB, 0xFE, 0xF7, 0xF8, 0xFB, 0x00, 0x23, 0x1A, 0x46, 0x19, 0x46, + 0x04, 0x20, 0x0A, 0xF0, 0x26, 0xFB, 0x00, 0x23, 0x1A, 0x46, 0x19, 0x46, + 0xE8, 0xE7, 0x00, 0x00, 0x54, 0x24, 0x10, 0x00, 0x9C, 0x22, 0x10, 0x00, + 0x10, 0xB5, 0x01, 0x46, 0x44, 0x22, 0xF0, 0x48, 0x0D, 0xF0, 0x9D, 0xFD, + 0x01, 0x21, 0xBD, 0xE8, 0x10, 0x40, 0x00, 0x20, 0x0C, 0xF0, 0x42, 0xBB, + 0xF8, 0xB5, 0x07, 0x46, 0xEB, 0x48, 0x00, 0x25, 0xE9, 0x4E, 0x03, 0x24, + 0x38, 0x60, 0x64, 0x1E, 0x64, 0xB2, 0x38, 0x46, 0x0B, 0xF0, 0x38, 0xFB, + 0x00, 0x22, 0x6B, 0x46, 0x01, 0x21, 0x10, 0x46, 0x0C, 0xF0, 0x80, 0xFB, + 0x01, 0x21, 0x00, 0x20, 0x0C, 0xF0, 0x5B, 0xFB, 0x96, 0xF8, 0x42, 0x00, + 0x28, 0xB1, 0x09, 0xF0, 0xDA, 0xFE, 0x00, 0x2C, 0xE9, 0xDC, 0x28, 0x46, + 0xF8, 0xBD, 0x01, 0x25, 0xFB, 0xE7, 0x2D, 0xE9, 0xF8, 0x43, 0x80, 0x46, + 0xDB, 0x48, 0xDA, 0x49, 0xD8, 0x4F, 0x00, 0x68, 0x90, 0xF8, 0x24, 0x00, + 0xC8, 0xF8, 0x00, 0x10, 0x05, 0x09, 0x03, 0x24, 0x1A, 0xE0, 0x00, 0x26, + 0x13, 0xE0, 0x64, 0x1E, 0xE4, 0xB2, 0x40, 0x46, 0x0B, 0xF0, 0x0E, 0xFB, + 0x00, 0x22, 0x6B, 0x46, 0x01, 0x21, 0x10, 0x46, 0x0C, 0xF0, 0x56, 0xFB, + 0x01, 0x21, 0x00, 0x20, 0x0C, 0xF0, 0x31, 0xFB, 0x97, 0xF8, 0x42, 0x00, + 0x58, 0xB1, 0x09, 0xF0, 0xB0, 0xFE, 0x00, 0x2C, 0xE9, 0xD1, 0x1E, 0xB1, + 0x6D, 0x1E, 0xED, 0xB2, 0x00, 0x2D, 0xE2, 0xD1, 0x30, 0x46, 0xBD, 0xE8, + 0xF8, 0x83, 0x01, 0x26, 0xF6, 0xE7, 0x2D, 0xE9, 0xF0, 0x47, 0xC2, 0x48, + 0x44, 0x30, 0x0B, 0xF0, 0xB6, 0xFA, 0xC0, 0x49, 0xC1, 0x4F, 0x44, 0x31, + 0x01, 0x20, 0x08, 0x71, 0x38, 0x68, 0x46, 0x7D, 0x00, 0x7D, 0x46, 0x43, + 0x08, 0x46, 0xFF, 0xF7, 0xBE, 0xFF, 0xBD, 0x4C, 0xB1, 0x00, 0x20, 0x46, + 0x0D, 0xF0, 0x8B, 0xFD, 0x38, 0x68, 0x01, 0x21, 0xDF, 0xF8, 0xE8, 0x82, + 0x90, 0xF8, 0x24, 0x00, 0xDF, 0xF8, 0xD0, 0x92, 0x00, 0xF0, 0x0F, 0x05, + 0x6D, 0x1C, 0x17, 0xE0, 0xB1, 0x48, 0x44, 0x30, 0xFF, 0xF7, 0x88, 0xFF, + 0x01, 0x46, 0x01, 0x28, 0x14, 0xD1, 0x00, 0x20, 0xD9, 0xF8, 0x00, 0x20, + 0x08, 0xE0, 0x54, 0xF8, 0x20, 0x30, 0x32, 0xF9, 0x10, 0xC0, 0x63, 0x44, + 0x44, 0xF8, 0x20, 0x30, 0x40, 0x1C, 0x80, 0xB2, 0xB0, 0x42, 0xF4, 0xDB, + 0x6D, 0x1E, 0xED, 0xB2, 0x00, 0x2D, 0xE5, 0xD1, 0x01, 0x29, 0x04, 0xD0, + 0x00, 0x23, 0x1A, 0x46, 0x98, 0xF8, 0x00, 0x10, 0x28, 0xE0, 0x4F, 0xF4, + 0xF1, 0x61, 0xA5, 0x48, 0x0D, 0xF0, 0x37, 0xFD, 0x38, 0x68, 0xA3, 0x4A, + 0x90, 0xF8, 0x24, 0x00, 0x08, 0x32, 0x00, 0xF0, 0x0F, 0x03, 0x00, 0x20, + 0x5B, 0x1C, 0x07, 0xE0, 0x54, 0xF8, 0x20, 0x10, 0x91, 0xFB, 0xF3, 0xF1, + 0x22, 0xF8, 0x10, 0x10, 0x40, 0x1C, 0x80, 0xB2, 0xB0, 0x42, 0xF5, 0xDB, + 0x99, 0x4A, 0x02, 0x20, 0xA2, 0xF8, 0x01, 0x00, 0xB5, 0x20, 0x10, 0x70, + 0x98, 0xF8, 0x00, 0x10, 0xD1, 0x70, 0x38, 0x68, 0x43, 0x7D, 0x13, 0x71, + 0x03, 0x7D, 0x53, 0x71, 0x03, 0x7D, 0x42, 0x7D, 0xBD, 0xE8, 0xF0, 0x47, + 0x02, 0x20, 0x0A, 0xF0, 0x83, 0xB8, 0x2D, 0xE9, 0xF0, 0x47, 0x89, 0x48, + 0x44, 0x30, 0x0B, 0xF0, 0x44, 0xFA, 0x87, 0x49, 0x88, 0x4F, 0x44, 0x31, + 0x03, 0x20, 0x08, 0x71, 0x38, 0x68, 0x46, 0x7D, 0x00, 0x7D, 0x46, 0x43, + 0x08, 0x46, 0xFF, 0xF7, 0x4C, 0xFF, 0x84, 0x4C, 0xB1, 0x00, 0x20, 0x46, + 0x0D, 0xF0, 0x19, 0xFD, 0x38, 0x68, 0x01, 0x21, 0xDF, 0xF8, 0x04, 0x82, + 0x90, 0xF8, 0x24, 0x00, 0xDF, 0xF8, 0xEC, 0x91, 0x00, 0xF0, 0x0F, 0x05, + 0x6D, 0x1C, 0x17, 0xE0, 0x78, 0x48, 0x44, 0x30, 0xFF, 0xF7, 0x16, 0xFF, + 0x01, 0x46, 0x01, 0x28, 0x14, 0xD1, 0x00, 0x20, 0xD9, 0xF8, 0x00, 0x20, + 0x08, 0xE0, 0x54, 0xF8, 0x20, 0x30, 0x32, 0xF9, 0x10, 0xC0, 0x63, 0x44, + 0x44, 0xF8, 0x20, 0x30, 0x40, 0x1C, 0x80, 0xB2, 0xB0, 0x42, 0xF4, 0xDB, + 0x6D, 0x1E, 0xED, 0xB2, 0x00, 0x2D, 0xE5, 0xD1, 0x01, 0x29, 0x04, 0xD0, + 0x00, 0x23, 0x1A, 0x46, 0x98, 0xF8, 0x00, 0x10, 0x28, 0xE0, 0x4F, 0xF4, + 0xF1, 0x61, 0x6C, 0x48, 0x0D, 0xF0, 0xC5, 0xFC, 0x38, 0x68, 0x6A, 0x4A, + 0x90, 0xF8, 0x24, 0x00, 0x08, 0x32, 0x00, 0xF0, 0x0F, 0x03, 0x00, 0x20, + 0x5B, 0x1C, 0x07, 0xE0, 0x54, 0xF8, 0x20, 0x10, 0x91, 0xFB, 0xF3, 0xF1, + 0x22, 0xF8, 0x10, 0x10, 0x40, 0x1C, 0x80, 0xB2, 0xB0, 0x42, 0xF5, 0xDB, + 0x60, 0x4A, 0x04, 0x20, 0xA2, 0xF8, 0x01, 0x00, 0xB5, 0x20, 0x10, 0x70, + 0x98, 0xF8, 0x00, 0x10, 0xD1, 0x70, 0x38, 0x68, 0x43, 0x7D, 0x13, 0x71, + 0x03, 0x7D, 0x53, 0x71, 0x03, 0x7D, 0x42, 0x7D, 0xBD, 0xE8, 0xF0, 0x47, + 0x04, 0x20, 0x0A, 0xF0, 0x11, 0xB8, 0x2D, 0xE9, 0xF0, 0x5F, 0x50, 0x48, + 0x44, 0x30, 0x0B, 0xF0, 0xD2, 0xF9, 0x4E, 0x49, 0xDF, 0xF8, 0x3C, 0xA1, + 0x44, 0x31, 0x01, 0x20, 0x08, 0x72, 0xDA, 0xF8, 0x00, 0x00, 0x56, 0x46, + 0x45, 0x7D, 0x07, 0x7D, 0x08, 0x46, 0xFF, 0xF7, 0xD8, 0xFE, 0x4A, 0x4C, + 0x05, 0xEB, 0x07, 0x09, 0x4F, 0xEA, 0x89, 0x01, 0x20, 0x46, 0x0D, 0xF0, + 0xA2, 0xFC, 0x30, 0x68, 0x01, 0x22, 0xDF, 0xF8, 0x18, 0xB1, 0x90, 0xF8, + 0x24, 0x00, 0x00, 0xF0, 0x0F, 0x06, 0x76, 0x1C, 0x29, 0xE0, 0x3E, 0x48, + 0x44, 0x30, 0xFF, 0xF7, 0xA1, 0xFE, 0x02, 0x46, 0x01, 0x28, 0x26, 0xD1, + 0xDF, 0xF8, 0xE8, 0xC0, 0x00, 0x20, 0xDC, 0xF8, 0x18, 0x10, 0x08, 0xE0, + 0x54, 0xF8, 0x20, 0x30, 0x31, 0xF9, 0x10, 0x80, 0x43, 0x44, 0x44, 0xF8, + 0x20, 0x30, 0x40, 0x1C, 0x80, 0xB2, 0xA8, 0x42, 0xF4, 0xD3, 0x00, 0x20, + 0xDC, 0xF8, 0x1C, 0x30, 0x09, 0xE0, 0x29, 0x18, 0x33, 0xF9, 0x10, 0x80, + 0x54, 0xF8, 0x21, 0xC0, 0x40, 0x1C, 0xC4, 0x44, 0x44, 0xF8, 0x21, 0xC0, + 0x80, 0xB2, 0xB8, 0x42, 0xF3, 0xD3, 0x76, 0x1E, 0xF6, 0xB2, 0x00, 0x2E, + 0xD3, 0xD1, 0x01, 0x2A, 0x04, 0xD0, 0x00, 0x23, 0x1A, 0x46, 0x9B, 0xF8, + 0x00, 0x10, 0x26, 0xE0, 0x4F, 0xF4, 0xF1, 0x61, 0x28, 0x48, 0x0D, 0xF0, + 0x3E, 0xFC, 0xDA, 0xF8, 0x00, 0x60, 0x26, 0x4A, 0x96, 0xF8, 0x24, 0x00, + 0x00, 0xF0, 0x0F, 0x03, 0x00, 0x20, 0x5B, 0x1C, 0x09, 0xE0, 0x54, 0xF8, + 0x20, 0x10, 0x02, 0xEB, 0x40, 0x0C, 0x91, 0xFB, 0xF3, 0xF1, 0x40, 0x1C, + 0xAC, 0xF8, 0x08, 0x10, 0x80, 0xB2, 0x81, 0x45, 0xF3, 0xD8, 0x20, 0x20, + 0xA2, 0xF8, 0x01, 0x00, 0xB5, 0x20, 0x10, 0x70, 0x9B, 0xF8, 0x00, 0x10, + 0xD1, 0x70, 0x15, 0x71, 0x57, 0x71, 0x33, 0x7D, 0x72, 0x7D, 0xBD, 0xE8, + 0xF0, 0x5F, 0x20, 0x20, 0x09, 0xF0, 0x8C, 0xBF, 0x10, 0xB5, 0x04, 0x46, + 0x00, 0x20, 0x0C, 0xF0, 0x34, 0xFA, 0x10, 0x48, 0x01, 0x78, 0x49, 0x1C, + 0x01, 0x70, 0x02, 0x2C, 0x04, 0xD0, 0x04, 0x2C, 0x05, 0xD0, 0x20, 0x2C, + 0x06, 0xD0, 0x07, 0xE0, 0xFF, 0xF7, 0x85, 0xFE, 0x04, 0xE0, 0xFF, 0xF7, + 0xF4, 0xFE, 0x01, 0xE0, 0xFF, 0xF7, 0x63, 0xFF, 0xBD, 0xE8, 0x10, 0x40, + 0x00, 0x20, 0x0C, 0xF0, 0x37, 0xBA, 0x00, 0x00, 0xBC, 0x27, 0x10, 0x00, + 0x31, 0x1F, 0x00, 0x00, 0x50, 0x24, 0x10, 0x00, 0x60, 0x54, 0x10, 0x00, + 0xA8, 0x22, 0x10, 0x00, 0x00, 0x80, 0x01, 0x20, 0x70, 0xB5, 0x04, 0x46, + 0x0D, 0x46, 0xC0, 0x07, 0x02, 0xD0, 0x10, 0x20, 0x09, 0xF0, 0x23, 0xFD, + 0xA0, 0x07, 0x03, 0xD5, 0x29, 0x46, 0x11, 0x20, 0x09, 0xF0, 0x1D, 0xFD, + 0x60, 0x07, 0x03, 0xD5, 0x29, 0x46, 0x12, 0x20, 0x09, 0xF0, 0x17, 0xFD, + 0x20, 0x07, 0x03, 0xD5, 0x29, 0x46, 0x13, 0x20, 0x09, 0xF0, 0x11, 0xFD, + 0xE0, 0x06, 0x03, 0xD5, 0x29, 0x46, 0x16, 0x20, 0x09, 0xF0, 0x0B, 0xFD, + 0xA0, 0x06, 0x03, 0xD5, 0x29, 0x46, 0x17, 0x20, 0x09, 0xF0, 0x05, 0xFD, + 0x60, 0x06, 0x03, 0xD5, 0x29, 0x46, 0x18, 0x20, 0x09, 0xF0, 0xFF, 0xFC, + 0x20, 0x06, 0x03, 0xD5, 0x29, 0x46, 0x19, 0x20, 0x09, 0xF0, 0xF9, 0xFC, + 0xE0, 0x05, 0x03, 0xD5, 0x29, 0x46, 0x14, 0x20, 0x09, 0xF0, 0xF3, 0xFC, + 0xA0, 0x05, 0x03, 0xD5, 0x29, 0x46, 0x15, 0x20, 0x09, 0xF0, 0xED, 0xFC, + 0x60, 0x05, 0x03, 0xD5, 0x29, 0x46, 0x20, 0x20, 0x09, 0xF0, 0xE7, 0xFC, + 0x20, 0x05, 0x03, 0xD5, 0x29, 0x46, 0x21, 0x20, 0x09, 0xF0, 0xE1, 0xFC, + 0xE0, 0x04, 0x03, 0xD5, 0x29, 0x46, 0x22, 0x20, 0x09, 0xF0, 0xDB, 0xFC, + 0xA0, 0x04, 0x05, 0xD5, 0x29, 0x46, 0xBD, 0xE8, 0x70, 0x40, 0x30, 0x20, + 0x09, 0xF0, 0xD3, 0xBC, 0x70, 0xBD, 0x10, 0xB5, 0x01, 0x46, 0x44, 0x22, + 0xF8, 0x48, 0x0D, 0xF0, 0x54, 0xFB, 0x01, 0x21, 0xBD, 0xE8, 0x10, 0x40, + 0x00, 0x20, 0x0C, 0xF0, 0xF9, 0xB8, 0x30, 0xB5, 0x85, 0xB0, 0x68, 0x46, + 0x0B, 0xF0, 0xBF, 0xF8, 0xF2, 0x48, 0x02, 0x21, 0x00, 0x78, 0x30, 0xB1, + 0x01, 0x28, 0x07, 0xD0, 0x02, 0x28, 0x09, 0xD0, 0x03, 0x28, 0x0A, 0xD0, + 0x0B, 0xE0, 0x8D, 0xF8, 0x07, 0x10, 0x08, 0xE0, 0x05, 0x20, 0x8D, 0xF8, + 0x08, 0x00, 0x04, 0xE0, 0x8D, 0xF8, 0x09, 0x10, 0x01, 0xE0, 0x8D, 0xF8, + 0x0A, 0x10, 0xE8, 0x48, 0xE5, 0x4D, 0x03, 0x24, 0x00, 0x90, 0x68, 0x46, + 0x0B, 0xF0, 0xD8, 0xF8, 0x00, 0x22, 0x04, 0xAB, 0x01, 0x21, 0x10, 0x46, + 0x0C, 0xF0, 0x20, 0xF9, 0x01, 0x21, 0x00, 0x20, 0x0C, 0xF0, 0xFB, 0xF8, + 0x95, 0xF8, 0x42, 0x00, 0x00, 0x28, 0x04, 0xD0, 0x09, 0xF0, 0x79, 0xFC, + 0x64, 0x1E, 0x00, 0x2C, 0xE9, 0xDC, 0x05, 0xB0, 0x30, 0xBD, 0x2D, 0xE9, + 0xF0, 0x47, 0x00, 0x26, 0x0F, 0x46, 0x81, 0x46, 0x35, 0x46, 0x34, 0x46, + 0xFF, 0xF7, 0xBF, 0xFF, 0xD4, 0x49, 0x40, 0xF6, 0xFF, 0x73, 0x8A, 0x46, + 0xC8, 0x6A, 0x0A, 0x6A, 0xD0, 0xF8, 0x00, 0xC0, 0x00, 0x20, 0x0E, 0xE0, + 0x3C, 0xF9, 0x10, 0x10, 0x19, 0xB1, 0x99, 0x42, 0x03, 0xD1, 0x01, 0x25, + 0x06, 0xE0, 0x01, 0x24, 0x04, 0xE0, 0xB9, 0x42, 0x01, 0xDC, 0x49, 0x45, + 0x00, 0xDA, 0x01, 0x26, 0x40, 0x1C, 0x90, 0x42, 0xEE, 0xDB, 0xDA, 0xF8, + 0x30, 0x00, 0xD4, 0x46, 0x9A, 0x46, 0x02, 0x68, 0x00, 0x20, 0xDC, 0xF8, + 0x24, 0x30, 0x0E, 0xE0, 0x32, 0xF9, 0x10, 0x10, 0x19, 0xB1, 0x51, 0x45, + 0x03, 0xD1, 0x01, 0x25, 0x06, 0xE0, 0x01, 0x24, 0x04, 0xE0, 0xB9, 0x42, + 0x01, 0xDC, 0x49, 0x45, 0x00, 0xDA, 0x01, 0x26, 0x40, 0x1C, 0x98, 0x42, + 0xEE, 0xDB, 0xDC, 0xF8, 0x28, 0x00, 0x20, 0xF4, 0xE0, 0x50, 0xCC, 0xF8, + 0x28, 0x00, 0x1C, 0xB1, 0x40, 0xF4, 0x00, 0x60, 0xCC, 0xF8, 0x28, 0x00, + 0x1D, 0xB1, 0x40, 0xF4, 0x80, 0x50, 0xCC, 0xF8, 0x28, 0x00, 0x00, 0x2E, + 0x03, 0xD0, 0x40, 0xF4, 0x80, 0x60, 0xCC, 0xF8, 0x28, 0x00, 0xBD, 0xE8, + 0xF0, 0x87, 0x2D, 0xE9, 0xF0, 0x47, 0xAD, 0x4B, 0x00, 0x26, 0x35, 0x46, + 0xDC, 0x69, 0x30, 0x46, 0x01, 0x27, 0x07, 0xFA, 0x00, 0xF2, 0x22, 0x42, + 0x04, 0xD0, 0xD9, 0x6B, 0x09, 0x5C, 0xB1, 0x42, 0x00, 0xD9, 0x0E, 0x46, + 0x40, 0x1C, 0x20, 0x28, 0xF3, 0xD3, 0xD3, 0xE9, 0x16, 0x78, 0x00, 0x24, + 0x99, 0x46, 0x22, 0x46, 0x01, 0x20, 0x00, 0x21, 0x0D, 0xF0, 0x27, 0xFA, + 0x38, 0x40, 0x01, 0xEA, 0x08, 0x01, 0x4A, 0x46, 0x08, 0x43, 0x05, 0xD0, + 0xD9, 0xF8, 0x40, 0x00, 0x00, 0x5D, 0xA8, 0x42, 0x00, 0xD9, 0x05, 0x46, + 0x64, 0x1C, 0x40, 0x2C, 0xEB, 0xD3, 0x11, 0x6D, 0x17, 0x46, 0x4F, 0xF0, + 0xFF, 0x0C, 0x0E, 0x70, 0x50, 0x6D, 0x05, 0x70, 0x52, 0x6B, 0xBC, 0x6A, + 0x12, 0x78, 0x24, 0xF4, 0x00, 0x74, 0x93, 0x19, 0xBA, 0x6B, 0x12, 0x78, + 0xBC, 0x62, 0x2A, 0x44, 0x93, 0x42, 0x11, 0xD2, 0xD7, 0xF8, 0x20, 0x80, + 0xB8, 0xF1, 0x00, 0x0F, 0x0C, 0xDD, 0xD2, 0x1A, 0x32, 0x44, 0xFF, 0x2A, + 0x01, 0xD8, 0x0A, 0x70, 0x04, 0xE0, 0x81, 0xF8, 0x00, 0xC0, 0x44, 0xF4, + 0x00, 0x71, 0xB9, 0x62, 0x05, 0x70, 0xAC, 0xE7, 0x9A, 0x42, 0x11, 0xD2, + 0xD7, 0xF8, 0x24, 0x80, 0xB8, 0xF1, 0x00, 0x0F, 0x0C, 0xDD, 0x9A, 0x1A, + 0x2A, 0x44, 0xFF, 0x2A, 0x01, 0xD8, 0x02, 0x70, 0x04, 0xE0, 0x80, 0xF8, + 0x00, 0xC0, 0x44, 0xF4, 0x00, 0x70, 0xB8, 0x62, 0x0E, 0x70, 0x98, 0xE7, + 0x0E, 0x70, 0xE7, 0xE7, 0x2D, 0xE9, 0xF0, 0x5F, 0x79, 0x4F, 0x00, 0x26, + 0x35, 0x46, 0xB8, 0x6B, 0x79, 0x6B, 0x79, 0x4C, 0x90, 0xF8, 0x00, 0xA0, + 0x91, 0xF8, 0x00, 0x90, 0x0E, 0x70, 0x06, 0x70, 0xFF, 0xF7, 0x89, 0xFF, + 0xFF, 0xF7, 0xF9, 0xFE, 0xF8, 0x6A, 0x01, 0x68, 0x38, 0x6A, 0x42, 0x00, + 0x20, 0x46, 0x0D, 0xF0, 0xFB, 0xF9, 0x38, 0x6B, 0x01, 0x68, 0x78, 0x6A, + 0x42, 0x00, 0x38, 0x6A, 0x04, 0xEB, 0x40, 0x00, 0x0D, 0xF0, 0xF2, 0xF9, + 0x79, 0x6B, 0xFF, 0x20, 0x08, 0x70, 0xB9, 0x6B, 0x08, 0x70, 0xFF, 0xF7, + 0x70, 0xFF, 0xFF, 0xF7, 0xE0, 0xFE, 0xF8, 0x6A, 0x67, 0x49, 0x3B, 0x6A, + 0xD0, 0xF8, 0x00, 0xC0, 0x00, 0x20, 0x0A, 0x68, 0x0E, 0xE0, 0x3C, 0xF9, + 0x10, 0x10, 0x34, 0xF9, 0x10, 0x80, 0xB1, 0xEB, 0x08, 0x01, 0x00, 0xD5, + 0x49, 0x42, 0xB2, 0xF9, 0x4A, 0x87, 0x41, 0x45, 0x01, 0xDA, 0x01, 0x25, + 0x02, 0xE0, 0x40, 0x1C, 0x98, 0x42, 0xEE, 0xDB, 0x38, 0x6B, 0xBB, 0x46, + 0x7F, 0x6A, 0xD0, 0xF8, 0x00, 0xC0, 0x00, 0x20, 0x10, 0xE0, 0x03, 0xEB, + 0x00, 0x08, 0x3C, 0xF9, 0x10, 0x10, 0x34, 0xF9, 0x18, 0x80, 0xB1, 0xEB, + 0x08, 0x01, 0x00, 0xD5, 0x49, 0x42, 0xB2, 0xF9, 0x4A, 0x87, 0x41, 0x45, + 0x01, 0xDA, 0x01, 0x26, 0x02, 0xE0, 0x40, 0x1C, 0xB8, 0x42, 0xEC, 0xDB, + 0xDB, 0xF8, 0x34, 0x10, 0x5C, 0x46, 0x81, 0xF8, 0x00, 0x90, 0xDB, 0xF8, + 0x38, 0x10, 0x81, 0xF8, 0x00, 0xA0, 0xFF, 0xF7, 0x30, 0xFF, 0xA0, 0x6A, + 0x35, 0x43, 0x20, 0xF4, 0x00, 0x50, 0xA0, 0x62, 0x02, 0xD0, 0x40, 0xF4, + 0x00, 0x50, 0xA0, 0x62, 0xBD, 0xE8, 0xF0, 0x9F, 0x2D, 0xE9, 0xFF, 0x4F, + 0x81, 0xB0, 0x00, 0x24, 0x06, 0x46, 0xDD, 0xE9, 0x0F, 0x79, 0x01, 0x20, + 0x25, 0x46, 0xDD, 0xF8, 0x44, 0x80, 0xDF, 0xF8, 0xEC, 0xA0, 0x83, 0x46, + 0x00, 0x90, 0x5C, 0xE0, 0x04, 0x98, 0x05, 0xF0, 0x07, 0x01, 0x00, 0xEB, + 0xE5, 0x00, 0x0B, 0xFA, 0x01, 0xF2, 0x00, 0x78, 0x02, 0x42, 0x51, 0xD0, + 0x19, 0xF8, 0x05, 0x00, 0x48, 0xBB, 0x37, 0xF9, 0x14, 0x00, 0x00, 0x28, + 0x0B, 0xDD, 0x36, 0xF9, 0x14, 0x10, 0x40, 0x1A, 0x00, 0xD5, 0x40, 0x42, + 0xB8, 0xF8, 0x00, 0x10, 0x80, 0xB2, 0x81, 0x42, 0x01, 0xD2, 0xA8, 0xF8, + 0x00, 0x00, 0x36, 0xF9, 0x14, 0x20, 0xBA, 0xF8, 0x08, 0x10, 0x8A, 0x42, + 0x1B, 0xDD, 0x29, 0x46, 0x0E, 0x9A, 0x02, 0x98, 0x0D, 0xF0, 0x52, 0xFB, + 0x00, 0x28, 0x0D, 0xDD, 0x00, 0x21, 0x40, 0x1E, 0xC2, 0xB2, 0x00, 0x91, + 0x29, 0x46, 0x0E, 0x9B, 0x02, 0x98, 0x0D, 0xF0, 0x12, 0xFC, 0x36, 0xF8, + 0x14, 0x00, 0x27, 0xF8, 0x14, 0x00, 0x22, 0xE0, 0xDA, 0xF8, 0x28, 0x10, + 0x41, 0xF0, 0x40, 0x01, 0xCA, 0xF8, 0x28, 0x10, 0x1B, 0xE0, 0x37, 0xF9, + 0x14, 0x00, 0x00, 0x28, 0x15, 0xDD, 0x40, 0x1A, 0xA2, 0xEB, 0x01, 0x01, + 0x00, 0xD5, 0x40, 0x42, 0x00, 0x29, 0x00, 0xDA, 0x49, 0x42, 0x88, 0x42, + 0x0B, 0xDC, 0x29, 0x46, 0x0E, 0x9A, 0x02, 0x98, 0x0D, 0xF0, 0x28, 0xFB, + 0x40, 0x1C, 0xC2, 0xB2, 0x29, 0x46, 0x0E, 0x9B, 0x02, 0x98, 0x0D, 0xF0, + 0xEC, 0xFB, 0x09, 0xF8, 0x05, 0xB0, 0x64, 0x1C, 0x6D, 0x1C, 0x03, 0x98, + 0x84, 0x42, 0x9F, 0xDB, 0x00, 0x98, 0x05, 0xB0, 0xBD, 0xE8, 0xF0, 0x8F, + 0x2D, 0xE9, 0xFF, 0x5F, 0x00, 0x25, 0x98, 0x46, 0x91, 0x46, 0x82, 0x46, + 0x2C, 0x46, 0x01, 0x27, 0x02, 0x4E, 0xDD, 0xF8, 0x38, 0xB0, 0x30, 0xE0, + 0x10, 0x28, 0x10, 0x00, 0xB0, 0x22, 0x10, 0x00, 0xC3, 0x23, 0x00, 0x00, + 0x60, 0x54, 0x10, 0x00, 0x50, 0x24, 0x10, 0x00, 0x08, 0xEB, 0xE4, 0x00, + 0x01, 0x22, 0x01, 0x78, 0x04, 0xF0, 0x07, 0x00, 0x82, 0x40, 0x0A, 0x42, + 0x1C, 0xD0, 0x3A, 0xF9, 0x15, 0x00, 0x31, 0x89, 0x88, 0x42, 0x16, 0xDA, + 0x5A, 0x46, 0x21, 0x46, 0x01, 0x98, 0x0D, 0xF0, 0xED, 0xFA, 0x3F, 0x28, + 0x0B, 0xDA, 0x00, 0x27, 0x00, 0x1D, 0x3F, 0x28, 0x00, 0xDD, 0x3F, 0x20, + 0xC2, 0xB2, 0x5B, 0x46, 0x21, 0x46, 0x01, 0x98, 0x0D, 0xF0, 0xAB, 0xFB, + 0x03, 0xE0, 0xB0, 0x6A, 0x40, 0xF0, 0x80, 0x00, 0xB0, 0x62, 0x6D, 0x1C, + 0x64, 0x1C, 0x4D, 0x45, 0xD6, 0xDB, 0x38, 0x46, 0x04, 0xB0, 0x47, 0xE7, + 0x2D, 0xE9, 0xF0, 0x4F, 0x95, 0xB0, 0x8A, 0x46, 0x83, 0x46, 0x20, 0x21, + 0x04, 0xA8, 0x0D, 0xF0, 0x82, 0xF9, 0x20, 0x21, 0x0C, 0xA8, 0x0D, 0xF0, + 0x7E, 0xF9, 0x00, 0x24, 0x25, 0x46, 0x27, 0x46, 0xA0, 0x46, 0xF6, 0x4E, + 0xFF, 0xF7, 0xCD, 0xFD, 0xB0, 0x6A, 0x20, 0xF0, 0x80, 0x00, 0xB0, 0x62, + 0x54, 0xB9, 0xCD, 0xF8, 0x00, 0x80, 0xF0, 0x6A, 0xF0, 0x4B, 0x32, 0x6A, + 0x00, 0x68, 0x1C, 0x33, 0xB1, 0x6C, 0xFF, 0xF7, 0x9B, 0xFF, 0x04, 0x46, + 0x55, 0xB9, 0x01, 0x20, 0x00, 0x90, 0x30, 0x6B, 0xEA, 0x4B, 0x72, 0x6A, + 0x00, 0x68, 0x58, 0x33, 0xF1, 0x6C, 0xFF, 0xF7, 0x8F, 0xFF, 0x05, 0x46, + 0x04, 0xB1, 0x55, 0xB9, 0xFF, 0xF7, 0x3B, 0xFE, 0xB0, 0x6C, 0x0D, 0xF0, + 0xE9, 0xFA, 0xF0, 0x6C, 0x0D, 0xF0, 0x26, 0xFB, 0x7F, 0x1C, 0x18, 0x2F, + 0xD4, 0xDB, 0x00, 0x24, 0xDF, 0xF8, 0x80, 0x93, 0xAB, 0xF8, 0x00, 0x40, + 0xAA, 0xF8, 0x00, 0x40, 0x25, 0x46, 0x09, 0xF5, 0x08, 0x68, 0x48, 0x46, + 0x31, 0x6A, 0x0D, 0xF0, 0x1E, 0xF9, 0x40, 0x46, 0x71, 0x6A, 0x0D, 0xF0, + 0x1A, 0xF9, 0x00, 0x27, 0xFF, 0xF7, 0x8F, 0xFD, 0xB0, 0x6A, 0x20, 0xF0, + 0x40, 0x00, 0xB0, 0x62, 0x74, 0xB9, 0x04, 0xAB, 0xCD, 0xE9, 0x02, 0x3B, + 0x00, 0x22, 0xCD, 0xE9, 0x00, 0x29, 0xF0, 0x6A, 0xCF, 0x4B, 0x32, 0x6A, + 0x00, 0x68, 0x1C, 0x33, 0xB1, 0x6C, 0xFF, 0xF7, 0xE5, 0xFE, 0x04, 0x46, + 0x75, 0xB9, 0x0C, 0xAB, 0xCD, 0xE9, 0x02, 0x3A, 0x01, 0x22, 0xCD, 0xE9, + 0x00, 0x28, 0x30, 0x6B, 0xC7, 0x4B, 0x72, 0x6A, 0x00, 0x68, 0x58, 0x33, + 0xF1, 0x6C, 0xFF, 0xF7, 0xD5, 0xFE, 0x05, 0x46, 0x24, 0xB1, 0x1D, 0xB1, + 0xFF, 0xF7, 0xF5, 0xFD, 0x15, 0xB0, 0x3F, 0xE7, 0xFF, 0xF7, 0xF1, 0xFD, + 0xB0, 0x6C, 0x0D, 0xF0, 0x9F, 0xFA, 0xF0, 0x6C, 0x0D, 0xF0, 0xDC, 0xFA, + 0x7F, 0x1C, 0x18, 0x2F, 0xC8, 0xDB, 0xF1, 0xE7, 0x2D, 0xE9, 0xF0, 0x5F, + 0x00, 0x25, 0x82, 0x46, 0x89, 0x46, 0xAA, 0xF8, 0x00, 0x50, 0x4F, 0xF0, + 0x01, 0x0B, 0x2E, 0x46, 0x0D, 0x80, 0x2F, 0x46, 0xFF, 0xF7, 0x4B, 0xFD, + 0xB3, 0x4A, 0xD0, 0x6A, 0xD2, 0xF8, 0x20, 0xC0, 0x04, 0x68, 0xBC, 0xF1, + 0x00, 0x0F, 0x02, 0xDD, 0xB4, 0xF9, 0x00, 0x00, 0x01, 0xE0, 0x4F, 0xF6, + 0xFF, 0x70, 0x00, 0xB2, 0x01, 0x21, 0x05, 0xE0, 0x34, 0xF9, 0x11, 0x30, + 0x83, 0x42, 0x00, 0xDD, 0x18, 0x46, 0x49, 0x1C, 0x61, 0x45, 0xF7, 0xDB, + 0x11, 0x6B, 0x53, 0x6A, 0xD1, 0xF8, 0x00, 0x80, 0x00, 0x2B, 0x02, 0xDD, + 0xB8, 0xF9, 0x00, 0x10, 0x01, 0xE0, 0x4F, 0xF6, 0xFF, 0x71, 0x0C, 0xB2, + 0x01, 0x21, 0x96, 0x46, 0x05, 0xE0, 0x38, 0xF9, 0x11, 0x20, 0xA2, 0x42, + 0x00, 0xDD, 0x14, 0x46, 0x49, 0x1C, 0x99, 0x42, 0xF7, 0xDB, 0xA0, 0x42, + 0x01, 0xDD, 0x02, 0x46, 0x00, 0xE0, 0x22, 0x46, 0xDE, 0xF8, 0x28, 0x80, + 0xBB, 0xF1, 0x00, 0x0F, 0x28, 0xF0, 0x30, 0x08, 0xCE, 0xF8, 0x28, 0x80, + 0x0E, 0xD0, 0x05, 0x46, 0xBE, 0xF8, 0x06, 0x00, 0x26, 0x46, 0x82, 0x42, + 0x05, 0xDB, 0x92, 0x48, 0x81, 0x6A, 0x41, 0xF0, 0x10, 0x01, 0x81, 0x62, + 0x68, 0xE6, 0x4F, 0xF0, 0x00, 0x0B, 0x1A, 0xE0, 0xBC, 0xF1, 0x00, 0x0F, + 0x0A, 0xDD, 0x41, 0x1B, 0x00, 0xD5, 0x49, 0x42, 0xBA, 0xF8, 0x00, 0x50, + 0x89, 0xB2, 0x8D, 0x42, 0x01, 0xD2, 0xAA, 0xF8, 0x00, 0x10, 0x05, 0x46, + 0x00, 0x2B, 0x0A, 0xDD, 0xA0, 0x1B, 0x00, 0xD5, 0x40, 0x42, 0xB9, 0xF8, + 0x00, 0x10, 0x80, 0xB2, 0x81, 0x42, 0x01, 0xD2, 0xA9, 0xF8, 0x00, 0x00, + 0x26, 0x46, 0xBE, 0xF8, 0x06, 0x00, 0x73, 0x46, 0x82, 0x42, 0x07, 0xDD, + 0x7D, 0x48, 0x41, 0x6C, 0x08, 0x78, 0x00, 0x28, 0xD6, 0xD0, 0x40, 0x1E, + 0x08, 0x70, 0x3D, 0xE6, 0x59, 0x6C, 0x08, 0x78, 0x0F, 0x28, 0x02, 0xD2, + 0x40, 0x1C, 0x08, 0x70, 0x03, 0xE0, 0x48, 0xF0, 0x20, 0x00, 0xCE, 0xF8, + 0x28, 0x00, 0x7F, 0x1C, 0x18, 0x2F, 0xFF, 0xF6, 0x7B, 0xAF, 0x2D, 0xE6, + 0xF0, 0xB5, 0x00, 0x25, 0x2C, 0x46, 0x01, 0x27, 0x12, 0xE0, 0x02, 0xEB, + 0xE4, 0x06, 0x04, 0xF0, 0x07, 0x0C, 0x36, 0x78, 0x07, 0xFA, 0x0C, 0xFE, + 0x1E, 0xEA, 0x06, 0x0F, 0x07, 0xD0, 0x06, 0x5D, 0x9E, 0x42, 0x01, 0xD9, + 0xF6, 0x1A, 0x00, 0xE0, 0x00, 0x26, 0x06, 0x55, 0x6D, 0x1C, 0x64, 0x1C, + 0x8D, 0x42, 0xEA, 0xDB, 0xF0, 0xBD, 0x2D, 0xE9, 0xFF, 0x4F, 0x81, 0xB0, + 0x00, 0x24, 0x06, 0x46, 0xDD, 0xE9, 0x0F, 0x79, 0x01, 0x20, 0x25, 0x46, + 0xDD, 0xF8, 0x44, 0x80, 0xDF, 0xF8, 0x78, 0xA1, 0x83, 0x46, 0x00, 0x90, + 0x5C, 0xE0, 0x04, 0x98, 0x05, 0xF0, 0x07, 0x01, 0x00, 0xEB, 0xE5, 0x00, + 0x0B, 0xFA, 0x01, 0xF2, 0x00, 0x78, 0x02, 0x42, 0x51, 0xD0, 0x19, 0xF8, + 0x05, 0x00, 0x48, 0xBB, 0x37, 0xF9, 0x14, 0x00, 0x00, 0x28, 0x0B, 0xDD, + 0x36, 0xF9, 0x14, 0x10, 0x08, 0x1A, 0x00, 0xD5, 0x40, 0x42, 0xB8, 0xF8, + 0x00, 0x10, 0x80, 0xB2, 0x81, 0x42, 0x01, 0xD2, 0xA8, 0xF8, 0x00, 0x00, + 0x36, 0xF9, 0x14, 0x20, 0xBA, 0xF8, 0x04, 0x10, 0x8A, 0x42, 0x1B, 0xDA, + 0x29, 0x46, 0x0E, 0x9A, 0x02, 0x98, 0x0D, 0xF0, 0x6B, 0xF9, 0xFF, 0x28, + 0x0D, 0xDA, 0x00, 0x21, 0x40, 0x1C, 0xC2, 0xB2, 0x00, 0x91, 0x29, 0x46, + 0x0E, 0x9B, 0x02, 0x98, 0x0D, 0xF0, 0x2C, 0xFA, 0x36, 0xF8, 0x14, 0x00, + 0x27, 0xF8, 0x14, 0x00, 0x22, 0xE0, 0xDA, 0xF8, 0x28, 0x10, 0x41, 0xF0, + 0x08, 0x01, 0xCA, 0xF8, 0x28, 0x10, 0x1B, 0xE0, 0x37, 0xF9, 0x14, 0x00, + 0x00, 0x28, 0x15, 0xDD, 0x40, 0x1A, 0xA2, 0xEB, 0x01, 0x01, 0x00, 0xD5, + 0x40, 0x42, 0x00, 0x29, 0x00, 0xDA, 0x49, 0x42, 0x88, 0x42, 0x0B, 0xDC, + 0x29, 0x46, 0x0E, 0x9A, 0x02, 0x98, 0x0D, 0xF0, 0x41, 0xF9, 0x40, 0x1E, + 0xC2, 0xB2, 0x29, 0x46, 0x0E, 0x9B, 0x02, 0x98, 0x0D, 0xF0, 0x06, 0xFA, + 0x09, 0xF8, 0x05, 0xB0, 0x64, 0x1C, 0x6D, 0x1C, 0x03, 0x98, 0x84, 0x42, + 0x9F, 0xDB, 0x00, 0x98, 0x13, 0xE6, 0x2D, 0xE9, 0xFF, 0x5F, 0x00, 0x25, + 0x98, 0x46, 0x91, 0x46, 0x82, 0x46, 0x2C, 0x46, 0x01, 0x27, 0x27, 0x4E, + 0xDD, 0xF8, 0x38, 0xB0, 0x27, 0xE0, 0x08, 0xEB, 0xE4, 0x00, 0x01, 0x22, + 0x01, 0x78, 0x04, 0xF0, 0x07, 0x00, 0x82, 0x40, 0x0A, 0x42, 0x1D, 0xD0, + 0x3A, 0xF9, 0x15, 0x00, 0xB1, 0x88, 0x88, 0x42, 0x17, 0xDD, 0x5A, 0x46, + 0x21, 0x46, 0x01, 0x98, 0x0D, 0xF0, 0x12, 0xF9, 0x00, 0x28, 0x0C, 0xDD, + 0x00, 0x27, 0x04, 0x28, 0x01, 0xDB, 0x00, 0x1F, 0x00, 0xE0, 0x00, 0x20, + 0xC2, 0xB2, 0x5B, 0x46, 0x21, 0x46, 0x01, 0x98, 0x0D, 0xF0, 0xD0, 0xF9, + 0x03, 0xE0, 0xB0, 0x6A, 0x40, 0xF0, 0x04, 0x00, 0xB0, 0x62, 0x6D, 0x1C, + 0x64, 0x1C, 0x4D, 0x45, 0xD5, 0xDB, 0x38, 0x46, 0x1E, 0xE6, 0xF0, 0xB5, + 0x00, 0x24, 0x07, 0x46, 0x01, 0x20, 0x21, 0x46, 0x84, 0x46, 0xDF, 0xF8, + 0x30, 0xE0, 0x12, 0xE0, 0x03, 0xEB, 0xE1, 0x05, 0x2E, 0x78, 0x01, 0xF0, + 0x07, 0x05, 0x0C, 0xFA, 0x05, 0xF5, 0x35, 0x42, 0x08, 0xD0, 0x37, 0xF9, + 0x14, 0x50, 0xBE, 0xF8, 0x04, 0x60, 0xB5, 0x42, 0x01, 0xDC, 0x00, 0x20, + 0xF0, 0xBD, 0x64, 0x1C, 0x49, 0x1C, 0x94, 0x42, 0xEA, 0xDB, 0xF0, 0xBD, + 0xB0, 0x22, 0x10, 0x00, 0x60, 0x54, 0x10, 0x00, 0x2D, 0xE9, 0xF0, 0x4F, + 0x95, 0xB0, 0x8A, 0x46, 0x83, 0x46, 0x20, 0x21, 0x04, 0xA8, 0x0C, 0xF0, + 0x80, 0xFF, 0x20, 0x21, 0x0C, 0xA8, 0x0C, 0xF0, 0x7C, 0xFF, 0x00, 0x24, + 0x25, 0x46, 0xFF, 0x23, 0xFE, 0x4A, 0xA2, 0xF1, 0x1C, 0x06, 0x31, 0x6A, + 0xF0, 0x6B, 0x00, 0xF0, 0xB0, 0xFA, 0xFF, 0x23, 0x06, 0xF1, 0x58, 0x02, + 0x71, 0x6A, 0x30, 0x6C, 0x00, 0xF0, 0xA9, 0xFA, 0xFF, 0xF7, 0x4D, 0xFC, + 0xFF, 0xF7, 0xBD, 0xFB, 0xF0, 0x6A, 0xF5, 0x4B, 0x32, 0x6A, 0x00, 0x68, + 0xF1, 0x6B, 0xFF, 0xF7, 0xB4, 0xFF, 0x00, 0xF0, 0x01, 0x07, 0x30, 0x6B, + 0x06, 0xF1, 0x58, 0x03, 0x72, 0x6A, 0x00, 0x68, 0x31, 0x6C, 0xFF, 0xF7, + 0xAA, 0xFF, 0x38, 0x42, 0xB0, 0x6A, 0x20, 0xF0, 0x08, 0x00, 0xB0, 0x62, + 0x03, 0xD1, 0x40, 0xF0, 0x08, 0x00, 0xB0, 0x62, 0x3A, 0xE6, 0x00, 0x27, + 0xB8, 0x46, 0xFF, 0xF7, 0x9E, 0xFB, 0xB0, 0x6A, 0x20, 0xF0, 0x04, 0x00, + 0xB0, 0x62, 0x4C, 0xB9, 0xCD, 0xF8, 0x00, 0x80, 0xF0, 0x6A, 0xE2, 0x4B, + 0x32, 0x6A, 0x00, 0x68, 0xF1, 0x6B, 0xFF, 0xF7, 0x56, 0xFF, 0x04, 0x46, + 0x55, 0xB9, 0x01, 0x20, 0x00, 0x90, 0x30, 0x6B, 0xDC, 0x4B, 0x72, 0x6A, + 0x00, 0x68, 0x3C, 0x33, 0x31, 0x6C, 0xFF, 0xF7, 0x4A, 0xFF, 0x05, 0x46, + 0x04, 0xB1, 0x25, 0xB9, 0xFF, 0xF7, 0x0D, 0xFC, 0x7F, 0x1C, 0x60, 0x2F, + 0xDB, 0xDB, 0x00, 0x24, 0xDF, 0xF8, 0x54, 0x93, 0xAB, 0xF8, 0x00, 0x40, + 0xAA, 0xF8, 0x00, 0x40, 0x25, 0x46, 0x09, 0xF5, 0x08, 0x68, 0x48, 0x46, + 0x31, 0x6A, 0x0C, 0xF0, 0xF6, 0xFE, 0x40, 0x46, 0x71, 0x6A, 0x0C, 0xF0, + 0xF2, 0xFE, 0x00, 0x27, 0xFF, 0xF7, 0x67, 0xFB, 0xB0, 0x6A, 0x20, 0xF0, + 0x08, 0x00, 0xB0, 0x62, 0x6C, 0xB9, 0x04, 0xAB, 0x00, 0x22, 0xCD, 0xE9, + 0x02, 0x3B, 0xCD, 0xE9, 0x00, 0x29, 0xF0, 0x6A, 0xC4, 0x4B, 0x32, 0x6A, + 0x00, 0x68, 0xF1, 0x6B, 0xFF, 0xF7, 0xA9, 0xFE, 0x04, 0x46, 0x75, 0xB9, + 0x0C, 0xAB, 0xCD, 0xE9, 0x02, 0x3A, 0x01, 0x22, 0xCD, 0xE9, 0x00, 0x28, + 0x30, 0x6B, 0xBD, 0x4B, 0x72, 0x6A, 0x00, 0x68, 0x3C, 0x33, 0x31, 0x6C, + 0xFF, 0xF7, 0x99, 0xFE, 0x05, 0x46, 0x1C, 0xB1, 0x15, 0xB1, 0xFF, 0xF7, + 0xCE, 0xFB, 0xD7, 0xE5, 0xFF, 0xF7, 0xCB, 0xFB, 0x7F, 0x1C, 0x60, 0x2F, + 0xD0, 0xDB, 0xD1, 0xE5, 0xF0, 0xB5, 0x00, 0x2A, 0x05, 0x9F, 0x2A, 0xDD, + 0xB0, 0xF9, 0x00, 0x50, 0x01, 0x24, 0x05, 0xE0, 0x30, 0xF9, 0x14, 0x60, + 0xAE, 0x42, 0x00, 0xDD, 0x35, 0x46, 0x64, 0x1C, 0x94, 0x42, 0xF7, 0xDB, + 0xB7, 0xF9, 0x00, 0x00, 0x38, 0xB1, 0x28, 0x1A, 0x00, 0xD5, 0x40, 0x42, + 0x1A, 0x88, 0x80, 0xB2, 0x82, 0x42, 0x00, 0xD2, 0x18, 0x80, 0xA6, 0x4A, + 0x3D, 0x80, 0x1C, 0x3A, 0x50, 0x88, 0x85, 0x42, 0x08, 0x78, 0x0A, 0xDA, + 0xFF, 0x28, 0x03, 0xD2, 0x40, 0x1C, 0x08, 0x70, 0x00, 0x20, 0xF0, 0xBD, + 0x90, 0x6A, 0x40, 0xF0, 0x02, 0x00, 0x90, 0x62, 0x01, 0xE0, 0x40, 0x1E, + 0x08, 0x70, 0x01, 0x20, 0xF0, 0xBD, 0x30, 0xB5, 0xB0, 0xF9, 0x00, 0x40, + 0x01, 0x23, 0x05, 0xE0, 0x30, 0xF9, 0x13, 0x50, 0xA5, 0x42, 0x00, 0xDD, + 0x2C, 0x46, 0x5B, 0x1C, 0x93, 0x42, 0xF7, 0xDB, 0x00, 0x2A, 0x12, 0xDD, + 0x93, 0x4A, 0x1C, 0x3A, 0x50, 0x88, 0x84, 0x42, 0x0D, 0xDD, 0x08, 0x78, + 0x38, 0xB1, 0x10, 0x28, 0x01, 0xD3, 0x10, 0x38, 0x00, 0xE0, 0x00, 0x20, + 0x08, 0x70, 0x00, 0x20, 0x30, 0xBD, 0x90, 0x6A, 0x40, 0xF0, 0x01, 0x00, + 0x90, 0x62, 0x01, 0x20, 0x30, 0xBD, 0x2D, 0xE9, 0xFE, 0x43, 0x88, 0x4F, + 0x88, 0x46, 0x1C, 0x3F, 0x81, 0x46, 0x79, 0x6B, 0xFF, 0x20, 0x00, 0x25, + 0x08, 0x70, 0xB9, 0x6B, 0x2E, 0x46, 0x08, 0x70, 0xFF, 0xF7, 0x63, 0xFB, + 0xFF, 0xF7, 0xD3, 0xFA, 0xF8, 0x6A, 0x3A, 0x6A, 0x79, 0x6B, 0x00, 0x68, + 0x00, 0xF0, 0xCB, 0xF9, 0x00, 0xF0, 0x01, 0x04, 0x38, 0x6B, 0x7A, 0x6A, + 0xB9, 0x6B, 0x00, 0x68, 0x00, 0xF0, 0xC3, 0xF9, 0x20, 0x42, 0xB8, 0x6A, + 0x20, 0xF0, 0x02, 0x00, 0xB8, 0x62, 0x04, 0xD1, 0x40, 0xF0, 0x02, 0x00, + 0xB8, 0x62, 0xBD, 0xE8, 0xFE, 0x83, 0x00, 0x24, 0xFF, 0xF7, 0xB7, 0xFA, + 0xB8, 0x6A, 0x20, 0xF0, 0x01, 0x00, 0xB8, 0x62, 0x35, 0xB9, 0xF8, 0x6A, + 0x3A, 0x6A, 0x79, 0x6B, 0x00, 0x68, 0xFF, 0xF7, 0xA4, 0xFF, 0x05, 0x46, + 0x36, 0xB9, 0x38, 0x6B, 0x7A, 0x6A, 0xB9, 0x6B, 0x00, 0x68, 0xFF, 0xF7, + 0x9C, 0xFF, 0x06, 0x46, 0x05, 0xB1, 0x26, 0xB9, 0xFF, 0xF7, 0x2D, 0xFB, + 0x64, 0x1C, 0x18, 0x2C, 0xE2, 0xDB, 0x00, 0x24, 0xA9, 0xF8, 0x00, 0x40, + 0xA8, 0xF8, 0x00, 0x40, 0x25, 0x46, 0xAD, 0xF8, 0x04, 0x40, 0xAD, 0xF8, + 0x08, 0x40, 0x26, 0x46, 0xFF, 0xF7, 0x8F, 0xFA, 0xB8, 0x6A, 0x20, 0xF0, + 0x02, 0x00, 0xB8, 0x62, 0x4C, 0xB9, 0x01, 0xA8, 0x00, 0x90, 0xF8, 0x6A, + 0x4B, 0x46, 0x3A, 0x6A, 0x00, 0x68, 0x79, 0x6B, 0xFF, 0xF7, 0x48, 0xFF, + 0x04, 0x46, 0x4D, 0xB9, 0x02, 0xA8, 0x00, 0x90, 0x38, 0x6B, 0x43, 0x46, + 0x7A, 0x6A, 0x00, 0x68, 0xB9, 0x6B, 0xFF, 0xF7, 0x3D, 0xFF, 0x05, 0x46, + 0x1C, 0xB1, 0x15, 0xB1, 0xFF, 0xF7, 0xFF, 0xFA, 0xB3, 0xE7, 0xFF, 0xF7, + 0xFC, 0xFA, 0x76, 0x1C, 0x18, 0x2E, 0xD9, 0xDB, 0xAD, 0xE7, 0x2D, 0xE9, + 0xF0, 0x41, 0x4B, 0x4C, 0x00, 0x25, 0x1C, 0x3C, 0x01, 0x26, 0x28, 0x46, + 0xA5, 0x62, 0x0B, 0xF0, 0x0A, 0xFC, 0x0A, 0xF0, 0xD2, 0xFE, 0xE0, 0x61, + 0x0A, 0xF0, 0xB8, 0xFE, 0xC4, 0xE9, 0x16, 0x01, 0x04, 0x21, 0x43, 0x48, + 0x0E, 0xF0, 0xB8, 0xFE, 0x20, 0x62, 0x08, 0x21, 0x04, 0xF1, 0x58, 0x00, + 0x0E, 0xF0, 0xB2, 0xFE, 0xDF, 0xF8, 0x00, 0x81, 0x60, 0x62, 0x40, 0x48, + 0xD8, 0xF8, 0x00, 0x10, 0x00, 0xF1, 0x38, 0x07, 0x01, 0xF1, 0x12, 0x03, + 0x5A, 0x1C, 0xA2, 0x63, 0xC4, 0xE9, 0x0F, 0x07, 0x97, 0x1E, 0x67, 0x64, + 0x00, 0xF1, 0x20, 0x07, 0xA7, 0x64, 0x3A, 0x37, 0xE7, 0x64, 0x57, 0x1C, + 0x15, 0x31, 0xC4, 0xE9, 0x14, 0x71, 0x36, 0x49, 0xE1, 0x62, 0x09, 0x1D, + 0xC4, 0xE9, 0x0C, 0x13, 0x34, 0x4F, 0x01, 0x21, 0x21, 0x70, 0x39, 0x68, + 0x91, 0xF8, 0x4C, 0xC7, 0x5F, 0xEA, 0xCC, 0x7C, 0x02, 0xD0, 0x1D, 0x70, + 0x15, 0x70, 0x06, 0xE0, 0x91, 0xF8, 0x56, 0x17, 0x19, 0x70, 0x39, 0x68, + 0x91, 0xF8, 0x57, 0x17, 0x11, 0x70, 0x39, 0x68, 0x91, 0xF8, 0x4C, 0x17, + 0x89, 0x07, 0x0B, 0xD5, 0x00, 0x23, 0x23, 0x4A, 0x21, 0x6A, 0x00, 0xF0, + 0xFC, 0xF8, 0x21, 0x4A, 0x00, 0x23, 0x3C, 0x32, 0x61, 0x6A, 0x20, 0x6C, + 0x00, 0xF0, 0xF5, 0xF8, 0x38, 0x68, 0x90, 0xF8, 0x4C, 0x17, 0x49, 0x07, + 0x02, 0xD5, 0x60, 0x6C, 0x05, 0x70, 0x03, 0xE0, 0x61, 0x6C, 0x90, 0xF8, + 0x58, 0x07, 0x08, 0x70, 0x38, 0x68, 0x90, 0xF8, 0x4C, 0x07, 0x00, 0x07, + 0x0C, 0xD5, 0x00, 0x23, 0x14, 0x49, 0x22, 0x6A, 0xA0, 0x6C, 0x0C, 0xF0, + 0x93, 0xFE, 0x12, 0x49, 0x01, 0x23, 0x3C, 0x31, 0x62, 0x6A, 0xE0, 0x6C, + 0x0C, 0xF0, 0x8C, 0xFE, 0xFF, 0xF7, 0x7B, 0xFA, 0x38, 0x68, 0x90, 0xF8, + 0x4C, 0x17, 0xC9, 0x07, 0x0F, 0xD0, 0x0B, 0x49, 0xB0, 0xF8, 0x4E, 0x07, + 0x60, 0x80, 0x10, 0x39, 0x88, 0x1E, 0xFF, 0xF7, 0xFC, 0xFE, 0x61, 0x89, + 0x05, 0x20, 0x09, 0xF0, 0xC2, 0xFA, 0xA1, 0x89, 0x06, 0x20, 0x09, 0xF0, + 0xBE, 0xFA, 0x38, 0x68, 0x90, 0xF8, 0x4C, 0x17, 0x89, 0x07, 0x1C, 0xD5, + 0x0C, 0xE0, 0x00, 0x00, 0xCC, 0x22, 0x10, 0x00, 0x60, 0x54, 0x10, 0x00, + 0x54, 0x24, 0x10, 0x00, 0x34, 0x17, 0x10, 0x00, 0x28, 0x28, 0x10, 0x00, + 0x50, 0x24, 0x10, 0x00, 0xB0, 0xF8, 0x50, 0x07, 0x6C, 0x49, 0xA0, 0x80, + 0x88, 0x1E, 0xFF, 0xF7, 0xDF, 0xFD, 0xE1, 0x89, 0x07, 0x20, 0x09, 0xF0, + 0xA0, 0xFA, 0x21, 0x8A, 0x08, 0x20, 0x09, 0xF0, 0x9C, 0xFA, 0x3A, 0x68, + 0x92, 0xF8, 0x4C, 0x07, 0xC1, 0x07, 0x18, 0xD0, 0x40, 0x07, 0x16, 0xD5, + 0x60, 0x6B, 0x92, 0xF8, 0x59, 0x27, 0x01, 0x78, 0x91, 0x42, 0x02, 0xD9, + 0x89, 0x1A, 0x01, 0x70, 0x00, 0xE0, 0x05, 0x70, 0xA0, 0x6B, 0x3A, 0x68, + 0x01, 0x78, 0x92, 0xF8, 0x59, 0x27, 0x91, 0x42, 0x02, 0xD9, 0x89, 0x1A, + 0x01, 0x70, 0x00, 0xE0, 0x05, 0x70, 0xFF, 0xF7, 0x26, 0xFA, 0x38, 0x68, + 0x90, 0xF8, 0x4C, 0x17, 0x8A, 0x07, 0x14, 0xD5, 0x09, 0x07, 0x12, 0xD5, + 0x53, 0x4A, 0x90, 0xF8, 0x5A, 0x37, 0x0C, 0x32, 0x21, 0x6A, 0xE0, 0x6B, + 0xFF, 0xF7, 0xC2, 0xFC, 0x38, 0x68, 0x4F, 0x4A, 0x61, 0x6A, 0x90, 0xF8, + 0x5A, 0x37, 0x48, 0x32, 0x20, 0x6C, 0xFF, 0xF7, 0xB9, 0xFC, 0xFF, 0xF7, + 0x0C, 0xFA, 0x38, 0x68, 0x90, 0xF8, 0x4C, 0x17, 0x49, 0x07, 0x0F, 0xD5, + 0x47, 0x49, 0xB0, 0xF8, 0x52, 0x07, 0xE0, 0x80, 0x09, 0x1D, 0x88, 0x1E, + 0xFF, 0xF7, 0x18, 0xFC, 0x61, 0x8A, 0x09, 0x20, 0x09, 0xF0, 0x53, 0xFA, + 0xA1, 0x8A, 0x0A, 0x20, 0x09, 0xF0, 0x4F, 0xFA, 0x38, 0x68, 0x90, 0xF8, + 0x4C, 0x17, 0x09, 0x07, 0x0F, 0xD5, 0x3D, 0x49, 0xB0, 0xF8, 0x54, 0x07, + 0x20, 0x81, 0x08, 0x31, 0x88, 0x1E, 0xFF, 0xF7, 0x7B, 0xFB, 0xE1, 0x8A, + 0x0B, 0x20, 0x09, 0xF0, 0x3E, 0xFA, 0x21, 0x8B, 0x0C, 0x20, 0x09, 0xF0, + 0x3A, 0xFA, 0x38, 0x68, 0xD8, 0xF8, 0x00, 0x10, 0x90, 0xF8, 0x4D, 0x27, + 0x0A, 0x74, 0x90, 0xF8, 0x4C, 0x17, 0x0A, 0x07, 0x02, 0xD5, 0xB0, 0xF8, + 0x54, 0x07, 0x0D, 0xE0, 0x4A, 0x07, 0x02, 0xD5, 0xB0, 0xF8, 0x52, 0x07, + 0x08, 0xE0, 0x8A, 0x07, 0x02, 0xD5, 0xB0, 0xF8, 0x50, 0x07, 0x03, 0xE0, + 0xC9, 0x07, 0xF0, 0xD0, 0xB0, 0xF8, 0x4E, 0x07, 0x60, 0x83, 0xFF, 0xF7, + 0x2B, 0xFA, 0x38, 0x68, 0x62, 0x8B, 0x90, 0xF8, 0x5B, 0x07, 0x00, 0xEB, + 0x80, 0x01, 0x40, 0x42, 0x00, 0xEB, 0x80, 0x00, 0x02, 0xEB, 0x41, 0x01, + 0x02, 0xEB, 0x40, 0x00, 0x89, 0xB2, 0x80, 0xB2, 0xFF, 0xF7, 0x5D, 0xF9, + 0x10, 0x21, 0xA0, 0x6A, 0xFF, 0xF7, 0xBC, 0xF8, 0x00, 0x20, 0x0B, 0xF0, + 0xE3, 0xFA, 0xA0, 0x6A, 0x00, 0xB1, 0x00, 0x26, 0x30, 0x46, 0xBD, 0xE8, + 0xF0, 0x81, 0xF0, 0xB5, 0x00, 0x25, 0x2C, 0x46, 0x4F, 0xF0, 0x01, 0x0C, + 0x0C, 0xE0, 0x02, 0xEB, 0xE4, 0x06, 0x04, 0xF0, 0x07, 0x07, 0x36, 0x78, + 0x0C, 0xFA, 0x07, 0xFE, 0x1E, 0xEA, 0x06, 0x0F, 0x01, 0xD0, 0x03, 0x55, + 0x6D, 0x1C, 0x64, 0x1C, 0x8D, 0x42, 0xF0, 0xDB, 0xF0, 0xBD, 0x10, 0xB5, + 0xB0, 0xF9, 0x00, 0x30, 0x01, 0x21, 0x05, 0xE0, 0x30, 0xF9, 0x11, 0x40, + 0x9C, 0x42, 0x00, 0xDD, 0x23, 0x46, 0x49, 0x1C, 0x91, 0x42, 0xF7, 0xDB, + 0x00, 0x2A, 0x06, 0xDD, 0x04, 0x48, 0x10, 0x38, 0x40, 0x88, 0x83, 0x42, + 0x01, 0xDC, 0x00, 0x20, 0x10, 0xBD, 0x01, 0x20, 0x10, 0xBD, 0x00, 0x00, + 0xC0, 0x22, 0x10, 0x00, 0x6C, 0x48, 0x08, 0xB5, 0x00, 0x26, 0x06, 0x80, + 0x6B, 0x48, 0x6C, 0x4F, 0x6C, 0x4D, 0x06, 0x70, 0x00, 0x22, 0x6B, 0x46, + 0x39, 0x46, 0x10, 0x46, 0x0B, 0xF0, 0x22, 0xFA, 0x00, 0x98, 0x40, 0x07, + 0x17, 0xD5, 0x28, 0x68, 0x10, 0xF8, 0x3A, 0x1F, 0x21, 0xF0, 0x01, 0x01, + 0x01, 0x70, 0xFE, 0xF7, 0x3E, 0xFD, 0x29, 0x68, 0x00, 0x23, 0x11, 0xF8, + 0x3B, 0x2F, 0x60, 0xF3, 0x00, 0x02, 0x0A, 0x70, 0x1A, 0x46, 0x01, 0x21, + 0x20, 0x20, 0x09, 0xF0, 0x8A, 0xF9, 0x04, 0x21, 0x00, 0x20, 0x0B, 0xF0, + 0xE6, 0xF9, 0x00, 0x98, 0xC0, 0x06, 0x17, 0xD5, 0x28, 0x68, 0x10, 0xF8, + 0x3A, 0x1F, 0x21, 0xF0, 0x08, 0x01, 0x01, 0x70, 0xFF, 0xF7, 0x49, 0xFE, + 0x29, 0x68, 0x00, 0x23, 0x11, 0xF8, 0x3B, 0x2F, 0x60, 0xF3, 0xC3, 0x02, + 0x0A, 0x70, 0x1A, 0x46, 0x10, 0x21, 0x20, 0x20, 0x09, 0xF0, 0x6F, 0xF9, + 0x10, 0x21, 0x00, 0x20, 0x0B, 0xF0, 0xCB, 0xF9, 0x00, 0x98, 0x80, 0x06, + 0x03, 0xD5, 0x20, 0x21, 0x00, 0x20, 0x0B, 0xF0, 0xC4, 0xF9, 0x00, 0x98, + 0x40, 0x06, 0x03, 0xD5, 0x40, 0x21, 0x00, 0x20, 0x0B, 0xF0, 0xBD, 0xF9, + 0x00, 0x98, 0x00, 0x04, 0x04, 0xD5, 0x4F, 0xF4, 0x00, 0x41, 0x00, 0x20, + 0x0B, 0xF0, 0xB5, 0xF9, 0x00, 0x98, 0x00, 0x07, 0x03, 0xD5, 0x08, 0x21, + 0x00, 0x20, 0x0B, 0xF0, 0xAE, 0xF9, 0x00, 0x98, 0x00, 0x06, 0x05, 0xD5, + 0xFE, 0xF7, 0x24, 0xFA, 0x80, 0x21, 0x00, 0x20, 0x0B, 0xF0, 0xA5, 0xF9, + 0x00, 0x98, 0xC0, 0x05, 0x06, 0xD5, 0x4F, 0xF4, 0x80, 0x71, 0x00, 0x20, + 0x0B, 0xF0, 0x9D, 0xF9, 0xFD, 0xF7, 0xA5, 0xFF, 0x00, 0x98, 0x80, 0x05, + 0x18, 0xD5, 0x35, 0x48, 0x04, 0x68, 0x06, 0x60, 0x20, 0x46, 0xFD, 0xF7, + 0x78, 0xF9, 0x4F, 0xF4, 0x00, 0x71, 0x00, 0x20, 0x0B, 0xF0, 0x8D, 0xF9, + 0xE1, 0xB2, 0x00, 0x23, 0xC4, 0xF3, 0x07, 0x22, 0x06, 0x20, 0x09, 0xF0, + 0x26, 0xF9, 0x2D, 0x48, 0x00, 0x68, 0x90, 0xF8, 0xA8, 0x13, 0x07, 0x20, + 0x08, 0xF0, 0x93, 0xF8, 0x00, 0x98, 0x40, 0x05, 0x0C, 0xD5, 0xFE, 0xF7, + 0xC6, 0xF9, 0x00, 0x23, 0x01, 0x22, 0x19, 0x46, 0x20, 0x20, 0x09, 0xF0, + 0x14, 0xF9, 0x4F, 0xF4, 0x80, 0x61, 0x00, 0x20, 0x0B, 0xF0, 0x6F, 0xF9, + 0x00, 0x98, 0x00, 0x05, 0x06, 0xD5, 0xFD, 0xF7, 0xBF, 0xF9, 0x4F, 0xF4, + 0x00, 0x61, 0x00, 0x20, 0x0B, 0xF0, 0x65, 0xF9, 0x00, 0x98, 0xC0, 0x04, + 0x06, 0xD5, 0xFD, 0xF7, 0xCC, 0xF9, 0x4F, 0xF4, 0x80, 0x51, 0x00, 0x20, + 0x0B, 0xF0, 0x5B, 0xF9, 0x00, 0x98, 0x40, 0x04, 0x09, 0xD5, 0x08, 0xF0, + 0x99, 0xFD, 0x08, 0xB9, 0x08, 0xF0, 0x61, 0xFD, 0x4F, 0xF4, 0x80, 0x41, + 0x00, 0x20, 0x0B, 0xF0, 0x4E, 0xF9, 0x00, 0x98, 0x80, 0x03, 0x06, 0xD5, + 0xFE, 0xF7, 0x68, 0xFD, 0x4F, 0xF4, 0x00, 0x31, 0x00, 0x20, 0x0B, 0xF0, + 0x44, 0xF9, 0x00, 0x98, 0x00, 0x03, 0x7F, 0xF5, 0x39, 0xAF, 0x0B, 0x48, + 0x00, 0x68, 0xFE, 0xF7, 0x85, 0xFF, 0x4F, 0xF4, 0x00, 0x21, 0x00, 0x20, + 0x0B, 0xF0, 0x37, 0xF9, 0x2E, 0xE7, 0x00, 0x00, 0x0A, 0x22, 0x10, 0x00, + 0x9C, 0x22, 0x10, 0x00, 0xFF, 0xDF, 0x0E, 0x00, 0x54, 0x24, 0x10, 0x00, + 0x64, 0x24, 0x10, 0x00, 0x50, 0x24, 0x10, 0x00, 0x68, 0x24, 0x10, 0x00, + 0x08, 0xB5, 0x6B, 0x46, 0x00, 0x22, 0x01, 0x21, 0x03, 0x20, 0x0B, 0xF0, + 0x41, 0xF9, 0x00, 0x98, 0xC0, 0x07, 0xF6, 0xD0, 0x01, 0x21, 0x03, 0x20, + 0x0B, 0xF0, 0x19, 0xF9, 0xF1, 0xE7, 0x00, 0x00, 0x0E, 0xF0, 0xC2, 0xB9, + 0x10, 0xB5, 0xD1, 0x48, 0xD1, 0x4C, 0x00, 0x68, 0x10, 0xB1, 0x04, 0x20, + 0x20, 0x70, 0x10, 0xBD, 0x0E, 0xF0, 0xB8, 0xF9, 0x01, 0x21, 0x08, 0x46, + 0x0B, 0xF0, 0x07, 0xF9, 0x00, 0xF0, 0xD0, 0xFB, 0x01, 0x20, 0xF3, 0xE7, + 0x10, 0xB5, 0x0E, 0xF0, 0xAD, 0xF9, 0x01, 0x21, 0xBD, 0xE8, 0x10, 0x40, + 0x08, 0x46, 0x0B, 0xF0, 0xCB, 0xB8, 0x08, 0xB5, 0x00, 0x20, 0x0B, 0xF0, + 0x78, 0xF9, 0x00, 0xF0, 0x7B, 0xFC, 0x00, 0xF0, 0x1E, 0xF9, 0xC2, 0x49, + 0x0E, 0xF0, 0x84, 0xF9, 0x00, 0xF0, 0x26, 0xFD, 0x01, 0x28, 0x0E, 0xD1, + 0x6B, 0x46, 0x00, 0x22, 0x08, 0x21, 0x0B, 0xF0, 0x07, 0xF9, 0x08, 0x21, + 0x01, 0x20, 0x0B, 0xF0, 0xE2, 0xF8, 0xBB, 0x48, 0x90, 0xF8, 0x42, 0x00, + 0x28, 0xB1, 0x08, 0xF0, 0x60, 0xFC, 0x00, 0x20, 0x0B, 0xF0, 0x76, 0xF9, + 0x08, 0xBD, 0xB7, 0x48, 0x01, 0x68, 0xB7, 0x48, 0x00, 0x68, 0x00, 0xF0, + 0x47, 0xFB, 0xF4, 0xE7, 0xF8, 0xB5, 0xB5, 0x48, 0x00, 0x25, 0x04, 0x68, + 0xAD, 0x4E, 0x30, 0x68, 0x90, 0xEA, 0x04, 0x0F, 0x66, 0xD0, 0x00, 0xB9, + 0x01, 0x25, 0x20, 0x46, 0x00, 0xF0, 0x20, 0xF9, 0x34, 0x60, 0xFF, 0xF7, + 0xAB, 0xFF, 0x00, 0x2D, 0x5B, 0xD0, 0xFF, 0xF7, 0xC2, 0xFF, 0xAC, 0x4F, + 0x3C, 0x68, 0x94, 0xF8, 0xE8, 0x07, 0x40, 0x06, 0x04, 0xD5, 0x4F, 0xF4, + 0xF0, 0x61, 0xA9, 0x48, 0x0C, 0xF0, 0x11, 0xFB, 0x60, 0x7D, 0x21, 0x7D, + 0xA7, 0x4D, 0x48, 0x43, 0x64, 0x26, 0x01, 0xE0, 0x25, 0xF8, 0x10, 0x60, + 0x40, 0x1E, 0xFB, 0xD2, 0x94, 0xF8, 0x30, 0x01, 0x80, 0x06, 0x08, 0xD5, + 0x20, 0x7D, 0x00, 0x90, 0xA0, 0x49, 0x63, 0x7D, 0x94, 0xF8, 0x4A, 0x21, + 0x08, 0x46, 0x02, 0xF0, 0xF7, 0xFC, 0x38, 0x68, 0x90, 0xF8, 0x30, 0x11, + 0x49, 0x06, 0x08, 0xD5, 0x01, 0x7D, 0x00, 0x91, 0x99, 0x49, 0x43, 0x7D, + 0x90, 0xF8, 0x4B, 0x21, 0x08, 0x46, 0x02, 0xF0, 0x1A, 0xFD, 0x3A, 0x68, + 0x92, 0xF8, 0x2F, 0x01, 0xC0, 0x07, 0x08, 0xD0, 0x10, 0x7D, 0x00, 0x90, + 0x92, 0x49, 0x53, 0x7D, 0x08, 0x46, 0x02, 0xF2, 0xC9, 0x32, 0x02, 0xF0, + 0x39, 0xFD, 0x3A, 0x68, 0x92, 0xF8, 0x2F, 0x01, 0x80, 0x07, 0x08, 0xD5, + 0x10, 0x7D, 0x00, 0x90, 0x8B, 0x49, 0x53, 0x7D, 0x08, 0x46, 0x02, 0xF2, + 0xAB, 0x32, 0x02, 0xF0, 0x65, 0xFD, 0x39, 0x68, 0x48, 0x7D, 0x09, 0x7D, + 0x48, 0x43, 0x06, 0xE0, 0x35, 0xF9, 0x10, 0x10, 0xC9, 0x01, 0xB1, 0xFB, + 0xF6, 0xF1, 0x25, 0xF8, 0x10, 0x10, 0x40, 0x1E, 0xF6, 0xD2, 0xF8, 0xBD, + 0x00, 0x2C, 0xFC, 0xD1, 0x77, 0x48, 0x00, 0x78, 0x07, 0x28, 0x03, 0xD0, + 0x05, 0x28, 0x01, 0xD0, 0x06, 0x28, 0xF4, 0xD1, 0x34, 0x60, 0xBD, 0xE8, + 0xF8, 0x40, 0x3D, 0xE7, 0x70, 0xB5, 0x7A, 0x48, 0x05, 0x68, 0x7A, 0x4E, + 0x31, 0x68, 0x91, 0xEA, 0x05, 0x04, 0x49, 0xD0, 0x73, 0x48, 0xA2, 0x07, + 0x00, 0x68, 0x08, 0xD5, 0xAA, 0x07, 0x16, 0xD5, 0x90, 0xF8, 0xD0, 0x21, + 0xD2, 0x07, 0x02, 0xD0, 0x41, 0xF0, 0x02, 0x01, 0x31, 0x60, 0xE1, 0x07, + 0x14, 0xD0, 0xE9, 0x07, 0x0E, 0xD0, 0x90, 0xF8, 0xEA, 0x11, 0xC9, 0x07, + 0x0E, 0xD0, 0x31, 0x68, 0x62, 0x4A, 0x41, 0xF0, 0x01, 0x01, 0x31, 0x60, + 0x04, 0x21, 0x11, 0x70, 0x06, 0xE0, 0x21, 0xF0, 0x02, 0x01, 0xEB, 0xE7, + 0x31, 0x68, 0x21, 0xF0, 0x01, 0x01, 0x31, 0x60, 0x21, 0x07, 0x0F, 0xD5, + 0x29, 0x07, 0x15, 0xD5, 0x90, 0xF8, 0xAF, 0x02, 0xC0, 0x07, 0x09, 0xD0, + 0x30, 0x68, 0x00, 0x23, 0x40, 0xF0, 0x08, 0x00, 0x30, 0x60, 0x1A, 0x46, + 0x19, 0x46, 0xCC, 0x20, 0x08, 0xF0, 0xB5, 0xFF, 0xE0, 0x03, 0x11, 0xD5, + 0xE8, 0x03, 0x30, 0x68, 0x0B, 0xD5, 0x40, 0xF4, 0x80, 0x30, 0x0A, 0xE0, + 0x30, 0x68, 0x00, 0x23, 0x20, 0xF0, 0x08, 0x00, 0x30, 0x60, 0x1A, 0x46, + 0x19, 0x46, 0xCD, 0x20, 0xEC, 0xE7, 0x20, 0xF4, 0x80, 0x30, 0x30, 0x60, + 0x70, 0xBD, 0x2D, 0xE9, 0xF0, 0x41, 0xDF, 0xF8, 0x48, 0x81, 0x46, 0x4F, + 0x44, 0x48, 0x98, 0xF8, 0x00, 0x50, 0x3C, 0x78, 0x00, 0x26, 0x06, 0x60, + 0xFF, 0xF7, 0xDE, 0xFE, 0x05, 0x20, 0x38, 0x70, 0x4C, 0x48, 0x05, 0x2C, + 0x06, 0x70, 0x13, 0xD0, 0x07, 0x2C, 0x11, 0xD0, 0x06, 0x2C, 0x0F, 0xD0, + 0x49, 0x49, 0x08, 0x68, 0x20, 0xF0, 0x02, 0x00, 0x40, 0xF0, 0x04, 0x00, + 0x08, 0x60, 0x01, 0x21, 0x08, 0xF0, 0x98, 0xFF, 0x4F, 0xF4, 0x00, 0x71, + 0x00, 0x20, 0x0A, 0xF0, 0xAB, 0xFF, 0x01, 0xE0, 0x88, 0xF8, 0x00, 0x50, + 0xBD, 0xE8, 0xF0, 0x41, 0xD9, 0xE6, 0x38, 0xB5, 0x31, 0x48, 0x01, 0x78, + 0x36, 0x48, 0x89, 0x1E, 0x06, 0x29, 0x00, 0x68, 0x13, 0xD2, 0xDF, 0xE8, + 0x01, 0xF0, 0x03, 0x06, 0x09, 0x0C, 0x0F, 0x0C, 0x90, 0xF8, 0x28, 0x40, + 0x0C, 0xE0, 0x90, 0xF8, 0x27, 0x40, 0x09, 0xE0, 0x90, 0xF8, 0x26, 0x40, + 0x06, 0xE0, 0x90, 0xF8, 0x29, 0x40, 0x03, 0xE0, 0x90, 0xF8, 0x2A, 0x40, + 0x00, 0xE0, 0x01, 0x24, 0x00, 0x25, 0x0D, 0xF0, 0x83, 0xFF, 0x00, 0xB1, + 0x01, 0x25, 0x69, 0x46, 0x04, 0x20, 0x0A, 0xF0, 0xBE, 0xFF, 0x00, 0x98, + 0x00, 0xB9, 0x1D, 0xB1, 0x14, 0x2C, 0x01, 0xD2, 0x14, 0x24, 0x01, 0xE0, + 0x04, 0xB9, 0x01, 0x24, 0x20, 0x46, 0x38, 0xBD, 0x70, 0xB5, 0x18, 0x4D, + 0x04, 0x46, 0x28, 0x68, 0x50, 0xB9, 0x4C, 0xB1, 0x0E, 0xF0, 0x48, 0xF8, + 0x01, 0x21, 0x08, 0x46, 0x0A, 0xF0, 0x97, 0xFF, 0x00, 0xF0, 0xBE, 0xFA, + 0x00, 0xF0, 0x42, 0xF8, 0x28, 0x78, 0x84, 0x43, 0xE0, 0x07, 0x1C, 0xD0, + 0x1D, 0x49, 0x01, 0x20, 0x08, 0x70, 0x14, 0x48, 0x03, 0x21, 0x00, 0x68, + 0x90, 0xF8, 0xB0, 0x20, 0xD2, 0x07, 0x03, 0xD1, 0x90, 0xF8, 0xD4, 0x00, + 0xC0, 0x07, 0x00, 0xD0, 0x23, 0x21, 0x15, 0x4A, 0x10, 0x68, 0x08, 0x43, + 0x01, 0x21, 0x10, 0x60, 0x08, 0xF0, 0x32, 0xFF, 0xBD, 0xE8, 0x70, 0x40, + 0x4F, 0xF4, 0x00, 0x71, 0x00, 0x20, 0x0A, 0xF0, 0x43, 0xBF, 0x70, 0xBD, + 0x24, 0x23, 0x10, 0x00, 0x60, 0x24, 0x10, 0x00, 0x25, 0x34, 0x00, 0x00, + 0x90, 0x46, 0x10, 0x00, 0x2C, 0x23, 0x10, 0x00, 0x28, 0x23, 0x10, 0x00, + 0x58, 0x24, 0x10, 0x00, 0x50, 0x24, 0x10, 0x00, 0x38, 0x9C, 0x01, 0x20, + 0x3C, 0x88, 0x01, 0x20, 0x5C, 0x24, 0x10, 0x00, 0x30, 0x23, 0x10, 0x00, + 0x34, 0x23, 0x10, 0x00, 0x10, 0x23, 0x10, 0x00, 0x64, 0x24, 0x10, 0x00, + 0x61, 0x24, 0x10, 0x00, 0xFD, 0x49, 0x01, 0x20, 0x08, 0x70, 0xFD, 0x49, + 0x00, 0x20, 0x08, 0x70, 0xFC, 0x49, 0x08, 0x70, 0x48, 0x70, 0x70, 0x47, + 0xFB, 0x48, 0x10, 0xB5, 0x00, 0x68, 0x90, 0xF8, 0xAF, 0x02, 0xC1, 0x07, + 0x15, 0xD0, 0x81, 0x07, 0x13, 0xD5, 0x00, 0x24, 0x40, 0x09, 0x0D, 0xF0, + 0xA7, 0xFE, 0x00, 0xB1, 0x01, 0x24, 0xF3, 0x48, 0x01, 0x78, 0x8C, 0x42, + 0x09, 0xD0, 0x04, 0x70, 0x0C, 0xB1, 0x02, 0x21, 0x00, 0xE0, 0x04, 0x21, + 0xBD, 0xE8, 0x10, 0x40, 0x04, 0x20, 0x0A, 0xF0, 0xFB, 0xBE, 0x10, 0xBD, + 0x70, 0xB5, 0xEE, 0x4C, 0xEC, 0x48, 0xEF, 0x4D, 0x20, 0x61, 0xED, 0x48, + 0xA0, 0x60, 0x3C, 0x30, 0xE0, 0x60, 0xE8, 0x48, 0x00, 0x68, 0x41, 0x7D, + 0x84, 0xF8, 0x2F, 0x10, 0x01, 0x7D, 0x84, 0xF8, 0x30, 0x10, 0x40, 0x7D, + 0x29, 0x6A, 0x42, 0x00, 0xE3, 0x48, 0x0C, 0xF0, 0xF3, 0xF8, 0x94, 0xF8, + 0x2F, 0x00, 0xA9, 0x69, 0x42, 0x00, 0xE2, 0x48, 0x0C, 0xF0, 0xEC, 0xF8, + 0x94, 0xF8, 0x30, 0x00, 0xE9, 0x69, 0x42, 0x00, 0xBD, 0xE8, 0x70, 0x40, + 0xDD, 0x48, 0x3C, 0x30, 0x0C, 0xF0, 0xE2, 0xB8, 0x2D, 0xE9, 0xF0, 0x41, + 0x0F, 0x46, 0x04, 0x46, 0x40, 0xEA, 0x07, 0x05, 0x00, 0x26, 0x03, 0x20, + 0x0A, 0xF0, 0x79, 0xFF, 0x34, 0x21, 0xD5, 0x48, 0x0C, 0xF0, 0x75, 0xF9, + 0xE8, 0x07, 0x06, 0xD0, 0x28, 0x46, 0x00, 0xF0, 0xDE, 0xF9, 0xE8, 0x06, + 0x03, 0xD4, 0x01, 0x26, 0x04, 0xE0, 0xE8, 0x06, 0x02, 0xD5, 0xFF, 0xF7, + 0xBD, 0xFF, 0xF8, 0xE7, 0xCF, 0x48, 0xCC, 0x4D, 0xCD, 0x49, 0x00, 0x68, + 0xE8, 0x61, 0xCE, 0x48, 0xDF, 0xF8, 0x38, 0x83, 0x00, 0x78, 0x85, 0xF8, + 0x33, 0x00, 0xC5, 0xE9, 0x08, 0x47, 0xC8, 0x6B, 0xA8, 0x62, 0x98, 0xF8, + 0x00, 0x00, 0x85, 0xF8, 0x2C, 0x00, 0x91, 0xF8, 0x41, 0x10, 0xC1, 0xF3, + 0x00, 0x11, 0x85, 0xF8, 0x2D, 0x10, 0xE1, 0x07, 0x01, 0xD0, 0xE1, 0x06, + 0x05, 0xD4, 0x02, 0x28, 0x13, 0xD1, 0xF8, 0x07, 0x11, 0xD0, 0xE0, 0x06, + 0x0F, 0xD5, 0x00, 0xF0, 0x8D, 0xFA, 0x01, 0x28, 0x03, 0xD1, 0xE8, 0x69, + 0x40, 0xF0, 0x10, 0x00, 0xE8, 0x61, 0x00, 0xF0, 0x93, 0xFA, 0x01, 0x28, + 0x03, 0xD1, 0xE8, 0x69, 0x40, 0xF0, 0x20, 0x00, 0xE8, 0x61, 0x03, 0x20, + 0x0A, 0xF0, 0x4C, 0xFF, 0x00, 0xF0, 0x4A, 0xFB, 0x00, 0x2E, 0x0F, 0xD0, + 0x98, 0xF8, 0x00, 0x00, 0x05, 0x28, 0x09, 0xD0, 0x06, 0x28, 0x07, 0xD0, + 0x07, 0x28, 0x05, 0xD0, 0x01, 0x21, 0xBD, 0xE8, 0xF0, 0x41, 0x02, 0x20, + 0x0A, 0xF0, 0x6E, 0xBE, 0x02, 0x21, 0xF8, 0xE7, 0xBD, 0xE8, 0xF0, 0x81, + 0x70, 0xB5, 0xA4, 0x4B, 0x00, 0x22, 0xC1, 0xB2, 0x1B, 0x68, 0xAA, 0x4C, + 0x5D, 0x7D, 0x28, 0x1A, 0x0D, 0xE0, 0x34, 0xF9, 0x11, 0x50, 0xDE, 0x8E, + 0xB5, 0x42, 0x06, 0xDD, 0x93, 0xF8, 0x35, 0x50, 0x52, 0x1C, 0x95, 0x42, + 0x01, 0xDC, 0x01, 0x20, 0x70, 0xBD, 0x49, 0x1C, 0xC9, 0xB2, 0x88, 0x42, + 0xEF, 0xDC, 0x00, 0x20, 0x70, 0xBD, 0x2D, 0xE9, 0xF0, 0x41, 0x96, 0x4C, + 0x0E, 0x46, 0x13, 0x46, 0x21, 0x68, 0x91, 0xF8, 0x3C, 0x20, 0x19, 0x46, + 0x09, 0xF0, 0xA4, 0xF8, 0x00, 0x21, 0x90, 0x4D, 0x01, 0x28, 0x04, 0xD0, + 0x69, 0x70, 0x98, 0x49, 0x68, 0x78, 0x88, 0x71, 0xCE, 0xE7, 0x68, 0x78, + 0x40, 0x1C, 0xC0, 0xB2, 0x68, 0x70, 0x22, 0x68, 0x92, 0xF8, 0x3D, 0x20, + 0x82, 0x42, 0xF2, 0xD2, 0x8F, 0x48, 0x69, 0x70, 0x91, 0x4F, 0x04, 0x78, + 0x02, 0x2C, 0x1F, 0xD0, 0x03, 0x2C, 0x1D, 0xD0, 0x38, 0x68, 0x40, 0xF0, + 0x04, 0x00, 0x38, 0x60, 0x8A, 0x48, 0x3C, 0x22, 0x31, 0x46, 0x78, 0x38, + 0x0C, 0xF0, 0x30, 0xF8, 0x87, 0x48, 0x3C, 0x22, 0x31, 0x46, 0x3C, 0x38, + 0x0C, 0xF0, 0x2A, 0xF8, 0x02, 0x2C, 0x0F, 0xD0, 0x03, 0x2C, 0x0D, 0xD0, + 0x22, 0x21, 0x38, 0x68, 0x08, 0xF0, 0xFA, 0xFD, 0x4F, 0xF4, 0x00, 0x71, + 0x00, 0x20, 0x0A, 0xF0, 0x0D, 0xFE, 0xCC, 0xE7, 0x38, 0x68, 0x40, 0xF0, + 0x22, 0x00, 0xE0, 0xE7, 0x23, 0x21, 0xF0, 0xE7, 0x7C, 0xB5, 0x06, 0x46, + 0x6F, 0x48, 0x71, 0x4C, 0x0D, 0x46, 0x00, 0x78, 0x50, 0xB9, 0x80, 0x20, + 0xCD, 0xE9, 0x00, 0x05, 0x20, 0x68, 0x7F, 0x23, 0x31, 0x46, 0x42, 0x7D, + 0x73, 0x48, 0x78, 0x38, 0x09, 0xF0, 0xF2, 0xF8, 0x21, 0x68, 0x91, 0xF8, + 0x34, 0x00, 0xC0, 0x07, 0x00, 0xD0, 0x6D, 0xB1, 0x6E, 0x48, 0x3C, 0x22, + 0x31, 0x46, 0x3C, 0x38, 0x0B, 0xF0, 0xF8, 0xFF, 0x6B, 0x4D, 0x00, 0x20, + 0x78, 0x3D, 0x05, 0xF1, 0x3C, 0x03, 0x69, 0x49, 0x24, 0x68, 0x16, 0xE0, + 0x4A, 0x7D, 0xB1, 0xF9, 0x3A, 0x00, 0xCD, 0xE9, 0x00, 0x02, 0x65, 0x4A, + 0xB1, 0xF9, 0x38, 0x30, 0x78, 0x3A, 0x31, 0x46, 0x02, 0xF1, 0x3C, 0x00, + 0x09, 0xF0, 0x78, 0xF8, 0xE8, 0xE7, 0x35, 0xF8, 0x10, 0x20, 0x33, 0xF8, + 0x10, 0x60, 0x92, 0x1B, 0x21, 0xF8, 0x10, 0x20, 0x40, 0x1C, 0x62, 0x7D, + 0x82, 0x42, 0xF4, 0xDC, 0x7C, 0xBD, 0x2D, 0xE9, 0xF0, 0x47, 0x55, 0x48, + 0x57, 0x4F, 0xDF, 0xF8, 0x34, 0x81, 0xD0, 0xF8, 0x18, 0x90, 0x38, 0x78, + 0x00, 0x21, 0x98, 0xF8, 0x00, 0x20, 0x4C, 0x4D, 0x49, 0x4E, 0x02, 0x28, + 0x0C, 0xD0, 0x03, 0x28, 0x0A, 0xD0, 0x05, 0x28, 0x23, 0xD0, 0x06, 0x28, + 0x21, 0xD0, 0x00, 0x24, 0x34, 0x70, 0x39, 0x78, 0x88, 0xF8, 0x00, 0x10, + 0xBD, 0xE8, 0xF0, 0x87, 0x82, 0x42, 0x04, 0xD0, 0x04, 0x2A, 0x01, 0xD0, + 0x01, 0x2A, 0x00, 0xD1, 0x01, 0x21, 0x48, 0x46, 0xFF, 0xF7, 0x98, 0xFF, + 0x28, 0x68, 0x90, 0xF8, 0x34, 0x10, 0x49, 0x07, 0x04, 0xD5, 0x42, 0x7D, + 0x49, 0x46, 0x43, 0x48, 0xFF, 0xF7, 0x45, 0xFF, 0x00, 0x20, 0xFF, 0xF7, + 0x27, 0xFF, 0x04, 0x46, 0x01, 0x28, 0x2A, 0xD0, 0xDE, 0xE7, 0x06, 0x2A, + 0x02, 0xD0, 0x05, 0x2A, 0x00, 0xD0, 0x01, 0x21, 0x05, 0x28, 0x03, 0xD0, + 0x06, 0x28, 0xD5, 0xD1, 0x01, 0x24, 0xD3, 0xE7, 0x48, 0x46, 0xFF, 0xF7, + 0x79, 0xFF, 0x28, 0x68, 0x90, 0xF8, 0x34, 0x10, 0x89, 0x07, 0x04, 0xD5, + 0x42, 0x7D, 0x49, 0x46, 0x33, 0x48, 0xFF, 0xF7, 0x26, 0xFF, 0x28, 0x68, + 0x90, 0xF9, 0x93, 0x02, 0xFF, 0xF7, 0x06, 0xFF, 0x30, 0x4B, 0x04, 0x46, + 0x31, 0x78, 0x5A, 0x79, 0x01, 0x28, 0x64, 0xF3, 0x00, 0x02, 0x61, 0xF3, + 0x41, 0x02, 0x5A, 0x71, 0xB6, 0xD1, 0x00, 0x29, 0xB4, 0xD1, 0xFF, 0xF7, + 0x79, 0xFC, 0x01, 0x21, 0x08, 0x46, 0x0A, 0xF0, 0x5D, 0xFD, 0xAD, 0xE7, + 0x70, 0xB5, 0x26, 0x4C, 0x0D, 0x46, 0x06, 0x46, 0x61, 0x88, 0x00, 0x20, + 0x20, 0x60, 0x60, 0x60, 0x20, 0x81, 0x61, 0x80, 0x29, 0x46, 0x30, 0x46, + 0xFF, 0xF7, 0x89, 0xFF, 0x29, 0x46, 0x30, 0x46, 0xFF, 0xF7, 0x78, 0xFE, + 0x04, 0x20, 0x0A, 0xF0, 0xF8, 0xFD, 0x2C, 0x21, 0x1D, 0x48, 0x0B, 0xF0, + 0xF4, 0xFF, 0x04, 0x20, 0x0A, 0xF0, 0x0C, 0xFE, 0xFF, 0xF7, 0x26, 0xFE, + 0x06, 0x20, 0x20, 0x80, 0x60, 0x88, 0x40, 0x1C, 0x60, 0x80, 0x13, 0x48, + 0x00, 0x78, 0x20, 0x71, 0x0A, 0x48, 0x00, 0x68, 0x90, 0xF8, 0xE9, 0x07, + 0x06, 0x28, 0x07, 0xD1, 0x13, 0x48, 0x21, 0x68, 0x00, 0x68, 0x01, 0x60, + 0x61, 0x68, 0x41, 0x60, 0x21, 0x89, 0x01, 0x81, 0x70, 0xBD, 0x00, 0x00, + 0x35, 0x23, 0x10, 0x00, 0x34, 0x23, 0x10, 0x00, 0x11, 0x23, 0x10, 0x00, + 0x50, 0x24, 0x10, 0x00, 0x54, 0x46, 0x10, 0x00, 0xE4, 0x52, 0x10, 0x00, + 0xB8, 0xA3, 0x01, 0x20, 0x90, 0x46, 0x10, 0x00, 0x30, 0x23, 0x10, 0x00, + 0x14, 0x23, 0x10, 0x00, 0x60, 0x24, 0x10, 0x00, 0x00, 0x88, 0x01, 0x20, + 0xD0, 0x25, 0x10, 0x00, 0x64, 0x24, 0x10, 0x00, 0x18, 0x53, 0x10, 0x00, + 0x74, 0x24, 0x10, 0x00, 0x10, 0xB5, 0xFF, 0xF7, 0xE1, 0xFD, 0x03, 0x20, + 0x0A, 0xF0, 0xB1, 0xFD, 0x34, 0x21, 0x25, 0x48, 0x0B, 0xF0, 0xAD, 0xFF, + 0x23, 0x49, 0x01, 0x20, 0x81, 0xF8, 0x2C, 0x00, 0x03, 0x20, 0x0A, 0xF0, + 0xC1, 0xFD, 0x01, 0x21, 0x02, 0x20, 0x0A, 0xF0, 0xF1, 0xFC, 0x04, 0x20, + 0x0A, 0xF0, 0x9F, 0xFD, 0x2C, 0x21, 0x1D, 0x48, 0x0B, 0xF0, 0x9B, 0xFF, + 0x04, 0x20, 0x0A, 0xF0, 0xB3, 0xFD, 0x01, 0x21, 0xBD, 0xE8, 0x10, 0x40, + 0x03, 0x20, 0x0A, 0xF0, 0xE1, 0xBC, 0x70, 0xB5, 0x17, 0x49, 0x15, 0x4C, + 0x17, 0x4D, 0x09, 0x68, 0x40, 0x07, 0x4A, 0x7D, 0x84, 0xF8, 0x2F, 0x20, + 0x0B, 0x7D, 0x84, 0xF8, 0x30, 0x30, 0x95, 0xF8, 0x40, 0x20, 0x84, 0xF8, + 0x2E, 0x20, 0x12, 0x4A, 0x62, 0x60, 0x09, 0xD5, 0x91, 0xF8, 0x11, 0x01, + 0x69, 0x68, 0x80, 0x07, 0x42, 0x0F, 0x92, 0x1C, 0x5A, 0x43, 0x0D, 0x48, + 0x0B, 0xF0, 0xD4, 0xFE, 0x0C, 0x48, 0x44, 0xF8, 0x11, 0x0B, 0x29, 0x68, + 0xE2, 0x7F, 0x60, 0x7F, 0x42, 0x43, 0xA0, 0x7F, 0xBD, 0xE8, 0x70, 0x40, + 0x40, 0x00, 0x42, 0x43, 0x06, 0x48, 0x0B, 0xF0, 0xC5, 0xBE, 0x00, 0x00, + 0xE4, 0x52, 0x10, 0x00, 0x18, 0x53, 0x10, 0x00, 0x50, 0x24, 0x10, 0x00, + 0x90, 0x46, 0x10, 0x00, 0xD0, 0x00, 0x01, 0x20, 0x54, 0x28, 0x10, 0x00, + 0xFE, 0x48, 0x00, 0x21, 0x01, 0x22, 0x81, 0x60, 0xC1, 0x60, 0x41, 0x70, + 0x82, 0x70, 0xFC, 0x4A, 0x12, 0x68, 0x92, 0xF8, 0xA2, 0x23, 0xC2, 0x70, + 0x01, 0x71, 0x70, 0x47, 0x2D, 0xE9, 0xF0, 0x41, 0xF8, 0x48, 0x00, 0x78, + 0x18, 0xB9, 0x07, 0xF0, 0xB4, 0xFB, 0x00, 0xB1, 0x01, 0x20, 0x00, 0x25, + 0xF5, 0x4E, 0xF3, 0x4A, 0xF1, 0x4C, 0x01, 0x28, 0x03, 0xD0, 0xF4, 0x48, + 0x01, 0x68, 0xC8, 0x03, 0x0A, 0xD5, 0x30, 0x78, 0x04, 0x28, 0x05, 0xD0, + 0x10, 0x68, 0x90, 0xF8, 0xA2, 0x13, 0x01, 0x20, 0x00, 0xF0, 0x6B, 0xF9, + 0x04, 0x20, 0x14, 0xE0, 0x30, 0x78, 0x02, 0x23, 0x04, 0x28, 0x02, 0xD0, + 0x03, 0x28, 0x27, 0xD0, 0x23, 0xE0, 0x10, 0x68, 0x90, 0xF8, 0x30, 0x20, + 0x97, 0x07, 0x0A, 0xD5, 0xA1, 0x68, 0x49, 0x1C, 0xA1, 0x60, 0x90, 0xF8, + 0x31, 0x00, 0x0A, 0x30, 0x81, 0x42, 0x17, 0xDD, 0x03, 0x20, 0x30, 0x70, + 0x13, 0xE0, 0xD2, 0x07, 0x12, 0xD0, 0x90, 0xF8, 0xEA, 0x21, 0xC2, 0xF3, + 0x00, 0x12, 0x0A, 0x42, 0x0C, 0xD1, 0xA1, 0x68, 0x49, 0x1C, 0xA1, 0x60, + 0x90, 0xF8, 0x32, 0x00, 0x40, 0x1C, 0x00, 0xEB, 0x80, 0x00, 0xB1, 0xEB, + 0x40, 0x0F, 0x01, 0xDD, 0x33, 0x70, 0xA5, 0x60, 0xBD, 0xE8, 0xF0, 0x81, + 0x10, 0x68, 0x90, 0xF8, 0x30, 0x20, 0xE4, 0xE7, 0xD2, 0x49, 0x08, 0x78, + 0x04, 0x28, 0x0C, 0xD0, 0x03, 0x28, 0x0A, 0xD0, 0x02, 0x28, 0x08, 0xD0, + 0x05, 0x28, 0x0A, 0xD1, 0xCC, 0x48, 0xCA, 0x4A, 0x00, 0x78, 0x28, 0xB1, + 0x53, 0x78, 0x0B, 0xB1, 0x02, 0xE0, 0x9D, 0xE7, 0x06, 0x23, 0x0B, 0x70, + 0x50, 0x70, 0x70, 0x47, 0x2D, 0xE9, 0xF0, 0x41, 0xC4, 0x4E, 0x01, 0x24, + 0x30, 0x68, 0x90, 0xF8, 0x9F, 0x03, 0xC0, 0x07, 0x24, 0xD0, 0xC3, 0x48, + 0x00, 0x78, 0x04, 0x28, 0x20, 0xD1, 0xC3, 0x4D, 0x00, 0x24, 0x28, 0x78, + 0x38, 0xB1, 0x29, 0x78, 0xC1, 0x4F, 0x38, 0x78, 0x00, 0xF0, 0x0B, 0xF9, + 0x00, 0x20, 0x28, 0x70, 0x38, 0x70, 0xB8, 0x49, 0xC8, 0x78, 0x08, 0xB1, + 0x01, 0x24, 0x0F, 0xE0, 0x30, 0x68, 0x90, 0xF8, 0x9F, 0x23, 0x92, 0x07, + 0x0A, 0xD5, 0x90, 0xF8, 0xA0, 0x23, 0x09, 0x79, 0x8A, 0x42, 0x05, 0xD2, + 0x90, 0xF8, 0xA1, 0x13, 0x08, 0x20, 0x00, 0xF0, 0xF4, 0xF8, 0xED, 0xE7, + 0x20, 0x46, 0xB3, 0xE7, 0xAD, 0x48, 0x10, 0xB5, 0x00, 0x68, 0x90, 0xF8, + 0xB0, 0x00, 0xC0, 0x07, 0x04, 0xD0, 0xFF, 0xF7, 0xC7, 0xFF, 0x08, 0xB1, + 0x01, 0x20, 0x10, 0xBD, 0x00, 0x20, 0x10, 0xBD, 0xA6, 0x48, 0x10, 0xB5, + 0x00, 0x68, 0x90, 0xF8, 0xD4, 0x00, 0xC0, 0x07, 0x04, 0xD0, 0xFF, 0xF7, + 0xB9, 0xFF, 0x08, 0xB1, 0x01, 0x20, 0x10, 0xBD, 0x00, 0x20, 0x10, 0xBD, + 0x2D, 0xE9, 0xF0, 0x41, 0x9E, 0x4E, 0x00, 0x24, 0x30, 0x68, 0x90, 0xF8, + 0x40, 0x00, 0xC0, 0x07, 0x38, 0xD0, 0x9D, 0x4F, 0x99, 0x4D, 0xA0, 0x46, + 0x38, 0x78, 0x05, 0x28, 0x0B, 0xD0, 0x07, 0x28, 0x09, 0xD0, 0x9D, 0x48, + 0x00, 0x78, 0xC0, 0x07, 0x20, 0xD0, 0x01, 0x24, 0xFF, 0xF7, 0xCC, 0xFF, + 0x01, 0x28, 0x02, 0xD0, 0x02, 0xE0, 0x01, 0x24, 0x07, 0xE0, 0x11, 0x24, + 0xFF, 0xF7, 0xD2, 0xFF, 0x01, 0x28, 0x01, 0xD1, 0x44, 0xF0, 0x10, 0x04, + 0x84, 0xB1, 0x38, 0x78, 0x02, 0x28, 0x14, 0xD0, 0x04, 0x28, 0x03, 0xD0, + 0x05, 0x28, 0x0C, 0xD0, 0x06, 0x28, 0x0A, 0xD0, 0x30, 0x68, 0x90, 0xF8, + 0x43, 0x00, 0xE9, 0x68, 0x49, 0x1C, 0xE9, 0x60, 0x81, 0x42, 0x0A, 0xDD, + 0xC5, 0xF8, 0x0C, 0x80, 0x08, 0xE0, 0x30, 0x68, 0x90, 0xF8, 0x45, 0x00, + 0xF3, 0xE7, 0x30, 0x68, 0x90, 0xF8, 0x44, 0x00, 0xEF, 0xE7, 0x00, 0x24, + 0x20, 0x46, 0x53, 0xE7, 0x10, 0xB5, 0x01, 0x46, 0x44, 0x22, 0x83, 0x48, + 0x0B, 0xF0, 0xF3, 0xFD, 0x08, 0x21, 0xBD, 0xE8, 0x10, 0x40, 0x01, 0x20, + 0x0A, 0xF0, 0x98, 0xBB, 0x2D, 0xE9, 0xFF, 0x41, 0x78, 0x48, 0x03, 0x24, + 0x7D, 0x4D, 0x00, 0x78, 0xDF, 0xF8, 0xF4, 0x81, 0x01, 0x26, 0x02, 0x28, + 0x19, 0xD0, 0x03, 0x28, 0x13, 0xD0, 0x05, 0x28, 0x31, 0xD0, 0x06, 0x28, + 0x68, 0x46, 0x45, 0xD0, 0x00, 0xF0, 0x78, 0xF8, 0x77, 0x48, 0x00, 0x90, + 0x68, 0x46, 0x09, 0xF0, 0x81, 0xFB, 0x76, 0x49, 0x69, 0x4A, 0x89, 0x78, + 0x11, 0x70, 0x88, 0xB3, 0x00, 0x20, 0x04, 0xB0, 0x26, 0xE7, 0x68, 0x46, + 0x00, 0xF0, 0xA0, 0xF8, 0xEE, 0xE7, 0x68, 0x46, 0x00, 0x27, 0x09, 0xF0, + 0x3A, 0xFB, 0xFF, 0xF7, 0x85, 0xFF, 0x68, 0x49, 0x09, 0x78, 0xC9, 0x07, + 0x00, 0xD0, 0x10, 0x27, 0xC1, 0x07, 0x01, 0xD0, 0x8D, 0xF8, 0x04, 0x60, + 0xC1, 0x06, 0x02, 0xD5, 0x8D, 0xF8, 0x08, 0x60, 0x03, 0xE0, 0xF9, 0x06, + 0x01, 0xD5, 0x8D, 0xF8, 0x08, 0x40, 0x28, 0x60, 0xC8, 0xF8, 0x00, 0x70, + 0xD2, 0xE7, 0x68, 0x46, 0x09, 0xF0, 0x1F, 0xFB, 0xFF, 0xF7, 0x6A, 0xFF, + 0x10, 0x21, 0xC2, 0x07, 0x01, 0xD0, 0x8D, 0xF8, 0x04, 0x40, 0xC2, 0x06, + 0x03, 0xD5, 0x8D, 0xF8, 0x08, 0x60, 0x03, 0xE0, 0x10, 0xE0, 0x04, 0x22, + 0x8D, 0xF8, 0x08, 0x20, 0x28, 0x60, 0xC8, 0xF8, 0x00, 0x10, 0xBB, 0xE7, + 0x00, 0x26, 0x09, 0xF0, 0x08, 0xFB, 0x8D, 0xF8, 0x04, 0x40, 0x01, 0x20, + 0x2E, 0x60, 0xC8, 0xF8, 0x00, 0x00, 0xB1, 0xE7, 0x01, 0x20, 0xBA, 0xE7, + 0x44, 0x49, 0x51, 0x4A, 0x8B, 0x78, 0x10, 0x7A, 0x63, 0xF3, 0x03, 0x00, + 0x10, 0x72, 0xC8, 0x78, 0x50, 0x72, 0x00, 0x22, 0x28, 0xB1, 0x40, 0x1E, + 0x10, 0xF0, 0xFF, 0x00, 0xC8, 0x70, 0x00, 0xD1, 0x8A, 0x70, 0x3D, 0x48, + 0x00, 0x68, 0x90, 0xF8, 0x9F, 0x33, 0x9B, 0x07, 0x08, 0xD5, 0x90, 0xF8, + 0xA0, 0x03, 0x0B, 0x79, 0x98, 0x42, 0x00, 0xD2, 0x0A, 0x71, 0x08, 0x79, + 0x40, 0x1C, 0x08, 0x71, 0x70, 0x47, 0x34, 0x4A, 0xD3, 0x78, 0x99, 0x42, + 0x01, 0xD9, 0xD1, 0x70, 0x90, 0x70, 0x70, 0x47, 0x2D, 0xE9, 0xF0, 0x41, + 0x00, 0x26, 0x05, 0x46, 0x34, 0x46, 0x09, 0xF0, 0xD0, 0xFA, 0x34, 0x48, + 0x2D, 0x4F, 0x00, 0x78, 0xC0, 0x07, 0x12, 0xD0, 0x01, 0x24, 0xFF, 0xF7, + 0xF9, 0xFE, 0x01, 0x28, 0x00, 0xD1, 0x11, 0x24, 0xFF, 0xF7, 0x02, 0xFF, + 0x01, 0x28, 0x01, 0xD1, 0x44, 0xF0, 0x10, 0x04, 0x38, 0x68, 0x90, 0xF8, + 0x10, 0x01, 0xC0, 0x07, 0x01, 0xD0, 0x44, 0xF0, 0x04, 0x04, 0xE1, 0x07, + 0x4F, 0xF0, 0x01, 0x00, 0x09, 0xD0, 0x28, 0x71, 0x39, 0x68, 0x91, 0xF8, + 0x25, 0x10, 0xC9, 0x07, 0x03, 0xD0, 0x2A, 0x49, 0x09, 0x78, 0x01, 0xB1, + 0xA8, 0x73, 0x61, 0x07, 0x00, 0xD5, 0xA8, 0x71, 0xE1, 0x06, 0x00, 0xD5, + 0x28, 0x72, 0x20, 0x48, 0x06, 0x60, 0x20, 0x48, 0x04, 0x60, 0x83, 0xE6, + 0x70, 0xB5, 0x06, 0x46, 0x00, 0x24, 0x09, 0xF0, 0x9A, 0xFA, 0xFF, 0xF7, + 0xE5, 0xFE, 0x05, 0x46, 0x17, 0x48, 0x00, 0x78, 0xC0, 0x07, 0x13, 0xD0, + 0x01, 0x24, 0xFF, 0xF7, 0xC1, 0xFE, 0x01, 0x28, 0x00, 0xD1, 0x11, 0x24, + 0xFF, 0xF7, 0xCA, 0xFE, 0x01, 0x28, 0x01, 0xD1, 0x44, 0xF0, 0x10, 0x04, + 0x09, 0x48, 0x00, 0x68, 0x90, 0xF8, 0x10, 0x01, 0xC0, 0x07, 0x01, 0xD0, + 0x44, 0xF0, 0x04, 0x04, 0x45, 0xEA, 0x04, 0x00, 0xC1, 0x07, 0x4F, 0xF0, + 0x02, 0x00, 0x00, 0xD0, 0x30, 0x71, 0x62, 0x07, 0x1E, 0xE0, 0x00, 0x00, + 0x14, 0x23, 0x10, 0x00, 0x50, 0x24, 0x10, 0x00, 0x34, 0x23, 0x10, 0x00, + 0x60, 0x24, 0x10, 0x00, 0x30, 0x23, 0x10, 0x00, 0x0A, 0x24, 0x10, 0x00, + 0x0B, 0x24, 0x10, 0x00, 0x24, 0x23, 0x10, 0x00, 0x90, 0x46, 0x10, 0x00, + 0x2C, 0x23, 0x10, 0x00, 0x28, 0x23, 0x10, 0x00, 0x85, 0x3E, 0x00, 0x00, + 0x6C, 0x24, 0x10, 0x00, 0xD0, 0x25, 0x10, 0x00, 0xB8, 0x23, 0x10, 0x00, + 0x4F, 0xF0, 0x01, 0x01, 0x00, 0xD5, 0xB1, 0x71, 0xEA, 0x06, 0x01, 0xD5, + 0x31, 0x72, 0x02, 0xE0, 0xE1, 0x06, 0x00, 0xD5, 0x30, 0x72, 0x02, 0x48, + 0x05, 0x60, 0x02, 0x48, 0x04, 0x60, 0x70, 0xBD, 0x2C, 0x23, 0x10, 0x00, + 0x28, 0x23, 0x10, 0x00, 0x08, 0xB5, 0x17, 0x49, 0x17, 0x4B, 0x00, 0x20, + 0x01, 0x22, 0x08, 0x60, 0x1A, 0x70, 0x48, 0x60, 0x88, 0x60, 0x41, 0x1E, + 0x11, 0xE0, 0x6B, 0x46, 0x00, 0x22, 0x17, 0x21, 0x01, 0x20, 0x0A, 0xF0, + 0xB7, 0xFA, 0x00, 0x98, 0x81, 0x07, 0x03, 0xD5, 0xFF, 0xF7, 0xC0, 0xF9, + 0x02, 0x21, 0x04, 0xE0, 0x41, 0x07, 0x06, 0xD5, 0xFF, 0xF7, 0x38, 0xFA, + 0x04, 0x21, 0x01, 0x20, 0x0A, 0xF0, 0x87, 0xFA, 0xE9, 0xE7, 0xC1, 0x06, + 0x03, 0xD5, 0xFF, 0xF7, 0x82, 0xFA, 0x10, 0x21, 0xF5, 0xE7, 0xC0, 0x07, + 0xE1, 0xD0, 0x01, 0x21, 0x08, 0x46, 0x0A, 0xF0, 0x7A, 0xFA, 0xFF, 0xF7, + 0x7E, 0xF9, 0xDA, 0xE7, 0x24, 0x23, 0x10, 0x00, 0x60, 0x24, 0x10, 0x00, + 0x10, 0xB5, 0x01, 0xF0, 0x00, 0xF9, 0x45, 0x48, 0x00, 0x21, 0x01, 0x70, + 0x41, 0x60, 0xBD, 0xE8, 0x10, 0x40, 0x00, 0xF0, 0xB0, 0xBB, 0x2D, 0xE9, + 0xF1, 0x4F, 0x41, 0x48, 0x4F, 0xF0, 0x00, 0x0A, 0x84, 0xB0, 0x00, 0x68, + 0xD1, 0x46, 0x54, 0x46, 0x90, 0xF8, 0xD4, 0x10, 0x89, 0x07, 0x01, 0xD5, + 0x4F, 0xF0, 0x01, 0x09, 0x3B, 0x4D, 0xDF, 0xF8, 0xF0, 0x80, 0xDF, 0xF8, + 0xF0, 0xB0, 0x2A, 0x7E, 0x98, 0xF8, 0x18, 0x10, 0xCA, 0x42, 0x25, 0xD1, + 0x39, 0x4F, 0xB0, 0xF8, 0xDA, 0x60, 0x3B, 0x46, 0x38, 0x89, 0x30, 0x44, + 0x02, 0xB2, 0x37, 0x48, 0x01, 0x78, 0x37, 0x48, 0x01, 0xF0, 0x01, 0xF8, + 0x02, 0x90, 0x78, 0x89, 0x3B, 0x1D, 0x30, 0x44, 0x02, 0xB2, 0x34, 0x48, + 0x01, 0x78, 0x34, 0x48, 0x00, 0xF0, 0xF7, 0xFF, 0x02, 0x99, 0x01, 0x29, + 0x07, 0xD1, 0x01, 0x28, 0x05, 0xD1, 0x4B, 0x46, 0x3A, 0x46, 0x2F, 0x49, + 0x2C, 0x48, 0x00, 0xF0, 0xB2, 0xFB, 0x29, 0x7E, 0x98, 0xF8, 0x18, 0x00, + 0xC1, 0x42, 0x3C, 0xD0, 0x00, 0x20, 0x00, 0x90, 0x01, 0x90, 0x01, 0xAA, + 0x69, 0x46, 0x04, 0x98, 0x00, 0xF0, 0x7A, 0xFB, 0x00, 0x9E, 0x96, 0xB3, + 0x01, 0x9A, 0x82, 0xB3, 0x7F, 0x24, 0x01, 0x20, 0x03, 0x46, 0x2F, 0x7E, + 0x09, 0xE0, 0x03, 0xFA, 0x00, 0xF1, 0x31, 0x42, 0x04, 0xD0, 0x29, 0x18, + 0x09, 0x7B, 0xA1, 0x42, 0x00, 0xD2, 0x0C, 0x46, 0x40, 0x1C, 0x87, 0x42, + 0xF3, 0xD2, 0x01, 0x20, 0x1F, 0x46, 0x45, 0x46, 0x98, 0xF8, 0x18, 0x60, + 0x09, 0xE0, 0x07, 0xFA, 0x00, 0xF3, 0x13, 0x42, 0x04, 0xD0, 0x29, 0x18, + 0x09, 0x7B, 0xA1, 0x42, 0x00, 0xD2, 0x0C, 0x46, 0x40, 0x1C, 0x86, 0x42, + 0xF3, 0xD2, 0x0B, 0x48, 0x00, 0x68, 0x90, 0xF8, 0xDC, 0x00, 0xA0, 0x42, + 0x07, 0xD2, 0x9B, 0xF8, 0x0A, 0x10, 0x4F, 0xF0, 0x01, 0x0A, 0x41, 0xF0, + 0x10, 0x01, 0x8B, 0xF8, 0x0A, 0x10, 0x8B, 0xF8, 0x1B, 0x40, 0x05, 0xB0, + 0x50, 0x46, 0xBD, 0xE8, 0xF0, 0x8F, 0x00, 0x00, 0x38, 0x23, 0x10, 0x00, + 0x50, 0x24, 0x10, 0x00, 0xDD, 0x46, 0x10, 0x00, 0xF6, 0x46, 0x10, 0x00, + 0x8A, 0x25, 0x10, 0x00, 0xA4, 0x48, 0x10, 0x00, 0x00, 0x24, 0x10, 0x00, + 0x80, 0x0A, 0x01, 0x20, 0x01, 0x24, 0x10, 0x00, 0xBC, 0x0A, 0x01, 0x20, + 0x2D, 0xE9, 0xF0, 0x5F, 0x9B, 0x46, 0x75, 0x4B, 0x8A, 0x46, 0xDD, 0xE9, + 0x0A, 0x91, 0x1B, 0x68, 0x01, 0x26, 0xB3, 0xF8, 0xAA, 0x30, 0x19, 0x44, + 0x30, 0xF9, 0x12, 0x30, 0x0F, 0xFA, 0x81, 0xF8, 0x03, 0xFB, 0x02, 0xF4, + 0x31, 0x46, 0x2B, 0xE0, 0x55, 0x1A, 0x6D, 0xB2, 0x00, 0x2D, 0x10, 0xDB, + 0x01, 0x2E, 0x0E, 0xD1, 0x30, 0xF9, 0x15, 0x70, 0x47, 0x45, 0x09, 0xDD, + 0x00, 0xEB, 0x45, 0x0C, 0xBC, 0xF9, 0x02, 0xC0, 0x67, 0x45, 0x03, 0xDC, + 0x07, 0xFB, 0x05, 0x44, 0x3B, 0x44, 0x00, 0xE0, 0x00, 0x26, 0x55, 0x18, + 0x6D, 0xB2, 0x55, 0x45, 0x10, 0xDA, 0x01, 0x2E, 0x0E, 0xD1, 0x30, 0xF9, + 0x15, 0x70, 0x47, 0x45, 0x09, 0xDD, 0x00, 0xEB, 0x45, 0x0C, 0x3C, 0xF9, + 0x02, 0xCC, 0x67, 0x45, 0x03, 0xDC, 0x07, 0xFB, 0x05, 0x44, 0x3B, 0x44, + 0x00, 0xE0, 0x00, 0x26, 0x49, 0x1C, 0xC9, 0xB2, 0x59, 0x45, 0xD1, 0xD9, + 0xAA, 0xF1, 0x01, 0x00, 0x83, 0xFB, 0x00, 0x23, 0x84, 0xFB, 0x09, 0x01, + 0x0B, 0xF0, 0x44, 0xFB, 0x00, 0x28, 0x00, 0xDA, 0x00, 0x20, 0xA9, 0xF1, + 0x01, 0x01, 0x88, 0x42, 0x00, 0xDD, 0x08, 0x46, 0xBD, 0xE8, 0xF0, 0x9F, + 0x2D, 0xE9, 0xF0, 0x41, 0x92, 0xB0, 0x00, 0x24, 0xDF, 0xF8, 0x2C, 0x81, + 0x3B, 0xE0, 0x22, 0x46, 0x49, 0x49, 0x02, 0xA8, 0x00, 0xF0, 0x60, 0xF8, + 0x46, 0x4F, 0x48, 0x4E, 0x25, 0x44, 0x38, 0x68, 0xB6, 0xF9, 0x08, 0x20, + 0xB0, 0xF9, 0x18, 0x10, 0xCD, 0xE9, 0x00, 0x12, 0x90, 0xF8, 0xAC, 0x30, + 0x43, 0x48, 0x95, 0xF9, 0x01, 0x20, 0x01, 0x78, 0x42, 0x48, 0xFF, 0xF7, + 0x8D, 0xFF, 0x0F, 0x90, 0x38, 0x68, 0xB6, 0xF9, 0x0A, 0x20, 0xB0, 0xF9, + 0x16, 0x10, 0xCD, 0xE9, 0x00, 0x12, 0x90, 0xF8, 0xAC, 0x30, 0x3D, 0x48, + 0x95, 0xF9, 0x03, 0x20, 0x01, 0x78, 0x3C, 0x48, 0xFF, 0xF7, 0x7C, 0xFF, + 0x10, 0x90, 0x0F, 0xA8, 0x04, 0xF0, 0xA4, 0xF8, 0x10, 0x98, 0xAD, 0xF8, + 0x0A, 0x00, 0x0F, 0x99, 0xAD, 0xF8, 0x0E, 0x00, 0xAD, 0xF8, 0x08, 0x10, + 0xAD, 0xF8, 0x0C, 0x10, 0x02, 0xA8, 0x03, 0xF0, 0x5D, 0xFA, 0x64, 0x1C, + 0xE4, 0xB2, 0x98, 0xF8, 0x00, 0x00, 0x45, 0x46, 0xA0, 0x42, 0xBE, 0xD8, + 0x12, 0xB0, 0xBD, 0xE8, 0xF0, 0x81, 0x2E, 0x49, 0x01, 0x20, 0x08, 0x70, + 0x26, 0x48, 0x00, 0x21, 0x01, 0x60, 0x41, 0x60, 0x01, 0x72, 0x70, 0x47, + 0x29, 0x48, 0x10, 0xB5, 0x00, 0x78, 0x00, 0x24, 0x01, 0x28, 0x0D, 0xD0, + 0x20, 0x48, 0x00, 0x78, 0x10, 0xB1, 0x01, 0x24, 0xFF, 0xF7, 0xA0, 0xFF, + 0x24, 0x49, 0x00, 0x20, 0x08, 0x70, 0x24, 0x49, 0x0C, 0x70, 0x24, 0x49, + 0x08, 0x70, 0x10, 0xBD, 0x00, 0xF0, 0xCC, 0xFB, 0x04, 0x46, 0xF3, 0xE7, + 0x10, 0xB5, 0x00, 0x23, 0x0A, 0x44, 0x03, 0x60, 0x51, 0x79, 0xD3, 0x79, + 0x59, 0x43, 0x02, 0x23, 0x83, 0x73, 0x1D, 0x4B, 0x1B, 0x88, 0x5B, 0x1C, + 0x03, 0x85, 0x43, 0x8B, 0x43, 0xF0, 0x08, 0x03, 0x43, 0x83, 0x81, 0x83, + 0x01, 0x84, 0x49, 0x1C, 0xC1, 0x83, 0x41, 0xF2, 0x88, 0x31, 0x01, 0x63, + 0xC1, 0x62, 0x51, 0x79, 0xD3, 0x79, 0x84, 0x8B, 0xCA, 0x18, 0x4C, 0x43, + 0x61, 0x00, 0xB1, 0xFB, 0xF2, 0xF1, 0x84, 0x8B, 0x5C, 0x43, 0x63, 0x00, + 0xB3, 0xFB, 0xF2, 0xF2, 0x91, 0x42, 0x02, 0xD9, 0x81, 0x84, 0xC2, 0x84, + 0x10, 0xBD, 0x82, 0x84, 0xC1, 0x84, 0x10, 0xBD, 0x50, 0x24, 0x10, 0x00, + 0xD4, 0x46, 0x10, 0x00, 0xA4, 0x48, 0x10, 0x00, 0x00, 0x24, 0x10, 0x00, + 0x80, 0x0A, 0x01, 0x20, 0x01, 0x24, 0x10, 0x00, 0xBC, 0x0A, 0x01, 0x20, + 0x40, 0x23, 0x10, 0x00, 0x05, 0x24, 0x10, 0x00, 0x06, 0x24, 0x10, 0x00, + 0x07, 0x24, 0x10, 0x00, 0xC6, 0x23, 0x10, 0x00, 0xF0, 0xB5, 0x05, 0x9E, + 0x34, 0x46, 0x0F, 0xE0, 0x50, 0xF8, 0x24, 0x50, 0x95, 0x42, 0x0B, 0xDA, + 0x67, 0x1C, 0xB7, 0x42, 0x05, 0xD2, 0x00, 0xEB, 0x84, 0x07, 0x7D, 0x60, + 0x0F, 0x19, 0x0D, 0x5D, 0x7D, 0x70, 0x40, 0xF8, 0x24, 0x20, 0x0B, 0x55, + 0x64, 0x1E, 0xED, 0xD2, 0xF0, 0xBD, 0x2D, 0xE9, 0xFF, 0x4F, 0x91, 0xB0, + 0x00, 0x20, 0x0E, 0x46, 0x0F, 0x90, 0x9B, 0x46, 0x14, 0x21, 0x06, 0xA8, + 0x0B, 0xF0, 0x2B, 0xFB, 0x00, 0x20, 0x0D, 0x90, 0x82, 0x46, 0x01, 0x22, + 0x0E, 0x90, 0x11, 0x46, 0x1E, 0x98, 0x00, 0xF0, 0xF6, 0xFB, 0x01, 0x20, + 0x62, 0xE0, 0x13, 0x99, 0x01, 0x25, 0x01, 0xEB, 0x49, 0x08, 0x57, 0xE0, + 0x0B, 0xEB, 0x45, 0x07, 0x14, 0x21, 0x01, 0xA8, 0x0B, 0xF0, 0x15, 0xFB, + 0x00, 0x20, 0x0B, 0x90, 0x01, 0x24, 0x0C, 0x90, 0x23, 0xE0, 0x06, 0xEB, + 0x84, 0x02, 0x98, 0xF8, 0x00, 0x00, 0x91, 0x78, 0x81, 0x42, 0x1B, 0xD3, + 0xD1, 0x78, 0x98, 0xF8, 0x01, 0x00, 0x81, 0x42, 0x16, 0xD8, 0x16, 0xF8, + 0x24, 0x00, 0x39, 0x78, 0x88, 0x42, 0x11, 0xD3, 0x50, 0x78, 0x79, 0x78, + 0x88, 0x42, 0x0D, 0xD8, 0xE1, 0xB2, 0x1E, 0x9B, 0x11, 0x98, 0x04, 0xF0, + 0x19, 0xFB, 0x05, 0x20, 0x00, 0x90, 0x1E, 0x98, 0xE3, 0xB2, 0x0B, 0xA9, + 0xC2, 0x6A, 0x01, 0xA8, 0xFF, 0xF7, 0xA0, 0xFF, 0x64, 0x1C, 0x96, 0xF8, + 0x0E, 0x01, 0xA0, 0x42, 0xD7, 0xD2, 0x01, 0x98, 0x00, 0x28, 0x20, 0xDD, + 0x01, 0x46, 0xFE, 0x48, 0x02, 0x68, 0x92, 0xF8, 0xC6, 0x20, 0x51, 0x43, + 0x64, 0x22, 0x91, 0xFB, 0xF2, 0xF7, 0x00, 0x24, 0x0B, 0xA8, 0x03, 0x5D, + 0x9B, 0xB1, 0x01, 0xA8, 0x50, 0xF8, 0x24, 0x20, 0xBA, 0x42, 0x0E, 0xDB, + 0x05, 0x20, 0x00, 0x90, 0x0D, 0xA9, 0x06, 0xA8, 0xFF, 0xF7, 0x80, 0xFF, + 0xF2, 0x48, 0x00, 0x68, 0x90, 0xF8, 0xB0, 0x00, 0xC0, 0x06, 0x02, 0xD4, + 0x64, 0x1C, 0x05, 0x2C, 0xE8, 0xD3, 0x6D, 0x1C, 0x9B, 0xF8, 0x18, 0x00, + 0xA8, 0x42, 0xA3, 0xD2, 0x09, 0xF1, 0x01, 0x00, 0x81, 0x46, 0x13, 0x98, + 0x01, 0x7E, 0x49, 0x45, 0x97, 0xD2, 0xE8, 0x49, 0x05, 0x20, 0x0D, 0xAC, + 0x01, 0x25, 0x0B, 0x68, 0x11, 0xE0, 0x21, 0x5C, 0x79, 0xB1, 0x05, 0xFA, + 0x01, 0xF2, 0x0F, 0x99, 0x0A, 0x43, 0x0A, 0xF1, 0x01, 0x01, 0x01, 0xF0, + 0xFF, 0x0A, 0x0F, 0x92, 0x93, 0xF8, 0xB0, 0x10, 0x89, 0x06, 0x02, 0xD5, + 0xBA, 0xF1, 0x02, 0x0F, 0x01, 0xD2, 0x40, 0x1E, 0xEB, 0xD2, 0x0F, 0x98, + 0x15, 0xB0, 0xBD, 0xE8, 0xF0, 0x8F, 0x2D, 0xE9, 0xF0, 0x5F, 0x83, 0x46, + 0x46, 0x1C, 0xD8, 0x48, 0x0C, 0x46, 0x90, 0x46, 0x01, 0x78, 0xD5, 0x48, + 0x01, 0x29, 0x00, 0x68, 0x67, 0xD0, 0x90, 0xF8, 0xEA, 0x90, 0xB0, 0xF8, + 0xE4, 0x00, 0x18, 0x44, 0x07, 0xB2, 0x00, 0x20, 0x82, 0x46, 0x11, 0x46, + 0x20, 0x46, 0x00, 0xF0, 0xB3, 0xFE, 0x05, 0x46, 0x41, 0x46, 0x20, 0x46, + 0x00, 0xF0, 0x9F, 0xFE, 0xBD, 0x42, 0x00, 0xDA, 0x3D, 0x46, 0xB8, 0x42, + 0x00, 0xDA, 0x38, 0x46, 0x28, 0x1A, 0x00, 0xFB, 0x09, 0xF2, 0x64, 0x21, + 0x92, 0xFB, 0xF1, 0xF2, 0x3A, 0x44, 0x17, 0xB2, 0xC4, 0x4A, 0x12, 0x78, + 0x01, 0x2A, 0x4C, 0xD0, 0xC3, 0x4A, 0x12, 0x78, 0x00, 0x2A, 0xC0, 0x4A, + 0x12, 0x68, 0x4B, 0xD0, 0x92, 0xF8, 0xE7, 0x20, 0x4F, 0xF0, 0x01, 0x09, + 0x50, 0x43, 0x90, 0xFB, 0xF1, 0xF0, 0x03, 0xB2, 0xB4, 0xF9, 0x00, 0x00, + 0xB8, 0x42, 0x01, 0xDD, 0x86, 0xF8, 0x00, 0x90, 0x04, 0xEB, 0x48, 0x00, + 0x0B, 0xF1, 0x01, 0x01, 0x30, 0xF9, 0x02, 0x2C, 0x41, 0x44, 0xBA, 0x42, + 0x01, 0xDD, 0x01, 0xF8, 0x01, 0x9C, 0xB4, 0xF9, 0x02, 0xC0, 0x0C, 0xEB, + 0x03, 0x02, 0x12, 0xB2, 0xBC, 0x45, 0x09, 0xDD, 0xB4, 0xF9, 0x00, 0xC0, + 0x94, 0x45, 0x03, 0xDD, 0xB4, 0xF9, 0x04, 0xC0, 0x94, 0x45, 0x01, 0xDC, + 0x86, 0xF8, 0x01, 0x90, 0x30, 0xF9, 0x04, 0xCC, 0x0C, 0xEB, 0x03, 0x02, + 0x12, 0xB2, 0xBC, 0x45, 0x09, 0xDD, 0x30, 0xF9, 0x06, 0xCC, 0x94, 0x45, + 0x03, 0xDD, 0x30, 0xF9, 0x02, 0x0C, 0x90, 0x42, 0x01, 0xDC, 0x01, 0xF8, + 0x02, 0x9C, 0x02, 0x22, 0xA8, 0xF1, 0x02, 0x0E, 0x42, 0xE0, 0x90, 0xF8, + 0xBC, 0x90, 0xB0, 0xF8, 0xBD, 0x00, 0x18, 0x44, 0x07, 0xB2, 0x01, 0x20, + 0x96, 0xE7, 0x9B, 0x4A, 0x12, 0x68, 0x92, 0xF8, 0xC0, 0x20, 0xB5, 0xE7, + 0x92, 0xF8, 0xE6, 0x20, 0xB2, 0xE7, 0x34, 0xF9, 0x12, 0xC0, 0xBC, 0x45, + 0x2D, 0xDD, 0x04, 0xEB, 0x42, 0x01, 0x0C, 0xEB, 0x03, 0x00, 0x31, 0xF9, + 0x02, 0xBC, 0x00, 0xB2, 0x83, 0x45, 0x03, 0xDD, 0xB1, 0xF9, 0x02, 0x80, + 0x80, 0x45, 0x0D, 0xDC, 0x31, 0xF9, 0x04, 0x8C, 0x80, 0x45, 0x03, 0xDD, + 0xB1, 0xF9, 0x02, 0x80, 0x80, 0x45, 0x05, 0xDC, 0x83, 0x45, 0x14, 0xDD, + 0xB1, 0xF9, 0x04, 0x10, 0x81, 0x42, 0x10, 0xDD, 0xBA, 0xF1, 0x00, 0x0F, + 0x0F, 0xD0, 0x00, 0x2D, 0x0D, 0xDD, 0x85, 0x48, 0x00, 0x68, 0x90, 0xF8, + 0xBF, 0x00, 0x40, 0xB1, 0x64, 0x21, 0x0C, 0xFB, 0x01, 0xFC, 0x9C, 0xFB, + 0xF5, 0xF1, 0x81, 0x42, 0x01, 0xDD, 0x06, 0xF8, 0x02, 0x90, 0x52, 0x1C, + 0x72, 0x45, 0xCA, 0xD3, 0xBD, 0xE8, 0xF0, 0x9F, 0x30, 0xB5, 0x01, 0x25, + 0x40, 0x1C, 0x05, 0xE0, 0x14, 0x68, 0x05, 0xFA, 0x01, 0xF3, 0x1C, 0x42, + 0x00, 0xD0, 0x45, 0x54, 0x49, 0x1E, 0xF7, 0xD2, 0x30, 0xBD, 0x2D, 0xE9, + 0xF8, 0x4F, 0x1C, 0x46, 0x89, 0x46, 0xDD, 0xE9, 0x0A, 0x63, 0x06, 0x21, + 0x00, 0x25, 0x92, 0x46, 0xCF, 0x1F, 0xDF, 0xF8, 0xCC, 0xC1, 0x08, 0xE0, + 0x62, 0x18, 0x15, 0x73, 0x97, 0x74, 0x04, 0xEB, 0x41, 0x02, 0xBC, 0xF8, + 0x00, 0x80, 0xA2, 0xF8, 0x00, 0x80, 0x49, 0x1E, 0xF4, 0xD2, 0x6A, 0x49, + 0x25, 0x76, 0x0A, 0x78, 0x67, 0x49, 0x01, 0x2A, 0x09, 0x68, 0x08, 0xD0, + 0xB1, 0xF8, 0xE8, 0x10, 0x01, 0x22, 0x19, 0x44, 0x0F, 0xB2, 0x00, 0x21, + 0x93, 0x46, 0x00, 0x95, 0x15, 0xE0, 0xB1, 0xF8, 0xC1, 0x10, 0xF5, 0xE7, + 0x43, 0x18, 0x93, 0xF8, 0x01, 0xC0, 0xBC, 0xF1, 0x00, 0x0F, 0x15, 0xD0, + 0x5A, 0x70, 0x39, 0xF9, 0x11, 0x30, 0xBB, 0x42, 0x06, 0xDD, 0xDD, 0xF8, + 0x00, 0xC0, 0x0B, 0xFA, 0x02, 0xF3, 0x43, 0xEA, 0x0C, 0x03, 0x00, 0x93, + 0x49, 0x1C, 0x51, 0x45, 0xEA, 0xD3, 0x01, 0x23, 0x1A, 0x46, 0x58, 0x4F, + 0xAE, 0x46, 0x00, 0x21, 0x35, 0x60, 0x47, 0xE0, 0x43, 0x5C, 0x00, 0x2B, + 0xF2, 0xD0, 0x52, 0x1C, 0xD2, 0xB2, 0xEF, 0xE7, 0x45, 0x18, 0x95, 0xF8, + 0x01, 0xC0, 0xBC, 0xF1, 0x00, 0x0F, 0x24, 0xD0, 0xDD, 0xF8, 0x00, 0x80, + 0x0B, 0xFA, 0x03, 0xFC, 0x1C, 0xEA, 0x08, 0x0F, 0x31, 0xD0, 0x6A, 0x70, + 0xD6, 0xF8, 0x00, 0xC0, 0x0B, 0xFA, 0x01, 0xF5, 0x4C, 0xEA, 0x05, 0x0C, + 0xA5, 0x18, 0xC6, 0xF8, 0x00, 0xC0, 0x95, 0xF8, 0x0C, 0xC0, 0x0C, 0xF1, + 0x01, 0x0C, 0x85, 0xF8, 0x0C, 0xC0, 0x39, 0xF9, 0x11, 0xC0, 0xBC, 0x45, + 0x01, 0xDD, 0x67, 0x46, 0xA9, 0x74, 0x04, 0xEB, 0x42, 0x05, 0x95, 0xF8, + 0x00, 0xC0, 0xBC, 0xF1, 0xFF, 0x0F, 0x11, 0xD0, 0x11, 0xE0, 0x3D, 0x4F, + 0x45, 0x5C, 0x95, 0xB1, 0xDD, 0xF8, 0x00, 0xC0, 0x0B, 0xFA, 0x03, 0xF5, + 0x15, 0xEA, 0x0C, 0x0F, 0x03, 0xD0, 0x05, 0x2A, 0x01, 0xD2, 0x52, 0x1C, + 0xD2, 0xB2, 0x5B, 0x1C, 0xDB, 0xB2, 0x04, 0xE0, 0x29, 0x70, 0x69, 0x70, + 0x01, 0xE0, 0x85, 0xF8, 0x01, 0xE0, 0x49, 0x1C, 0x51, 0x45, 0xBB, 0xD3, + 0x04, 0x21, 0x68, 0x46, 0x0D, 0xF0, 0xF6, 0xF9, 0x20, 0x76, 0xBD, 0xE8, + 0xF8, 0x8F, 0x2F, 0x48, 0x10, 0xB5, 0x2D, 0x49, 0x01, 0x60, 0x2E, 0x49, + 0x41, 0x60, 0x19, 0x21, 0x2D, 0x48, 0x0B, 0xF0, 0x0E, 0xF9, 0x2C, 0x48, + 0x19, 0x21, 0xBD, 0xE8, 0x10, 0x40, 0x19, 0x30, 0x0B, 0xF0, 0x07, 0xB9, + 0xF0, 0xB5, 0x4F, 0xF0, 0x00, 0x0C, 0x25, 0x4E, 0xC1, 0xF8, 0x00, 0xC0, + 0x83, 0x78, 0x01, 0x25, 0x37, 0x68, 0x0B, 0xE0, 0xFC, 0x18, 0x64, 0x78, + 0x3C, 0xB1, 0xD1, 0xF8, 0x00, 0xE0, 0x05, 0xFA, 0x04, 0xF4, 0x4E, 0xEA, + 0x04, 0x0E, 0xC1, 0xF8, 0x00, 0xE0, 0x5B, 0x1C, 0xC4, 0x78, 0x9C, 0x42, + 0xF0, 0xD2, 0xC2, 0xF8, 0x00, 0xC0, 0x01, 0x78, 0x09, 0xE0, 0x73, 0x68, + 0x0B, 0x44, 0x5B, 0x78, 0x23, 0xB1, 0x14, 0x68, 0x05, 0xFA, 0x03, 0xF3, + 0x1C, 0x43, 0x14, 0x60, 0x49, 0x1C, 0x43, 0x78, 0x8B, 0x42, 0xF2, 0xD2, + 0xF0, 0xBD, 0x2D, 0xE9, 0xFC, 0x47, 0x10, 0x4D, 0x8A, 0x46, 0x81, 0x46, + 0x98, 0x46, 0x14, 0x46, 0x20, 0x21, 0x28, 0x68, 0x0B, 0xF0, 0xD1, 0xF8, + 0x22, 0x21, 0x68, 0x68, 0x0B, 0xF0, 0xCD, 0xF8, 0x0C, 0x4E, 0x0D, 0x4F, + 0xB8, 0xF1, 0x01, 0x0F, 0x38, 0xD0, 0x22, 0x46, 0x31, 0x78, 0x15, 0xE0, + 0x50, 0x24, 0x10, 0x00, 0x55, 0x23, 0x10, 0x00, 0x4C, 0x23, 0x10, 0x00, + 0x14, 0x1D, 0x01, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x1E, 0x48, 0x10, 0x00, + 0x44, 0x23, 0x10, 0x00, 0x5E, 0x48, 0x10, 0x00, 0xDD, 0x46, 0x10, 0x00, + 0x00, 0x24, 0x10, 0x00, 0x01, 0x24, 0x10, 0x00, 0x28, 0x68, 0xFF, 0xF7, + 0xEF, 0xFE, 0x22, 0x1D, 0x39, 0x78, 0x68, 0x68, 0xFF, 0xF7, 0xEA, 0xFE, + 0xB4, 0xF9, 0x08, 0x00, 0xD5, 0x4B, 0xCD, 0xE9, 0x00, 0x40, 0x32, 0x78, + 0x49, 0x46, 0x28, 0x68, 0xFF, 0xF7, 0xED, 0xFE, 0xB4, 0xF9, 0x0A, 0x00, + 0x24, 0x1D, 0xCD, 0xE9, 0x00, 0x40, 0xCF, 0x4B, 0x3A, 0x78, 0x19, 0x33, + 0x51, 0x46, 0x68, 0x68, 0xFF, 0xF7, 0xE1, 0xFE, 0xBD, 0xE8, 0xFC, 0x87, + 0xB4, 0xF9, 0x08, 0x30, 0x32, 0x78, 0x49, 0x46, 0x28, 0x68, 0xFF, 0xF7, + 0x10, 0xFE, 0xB4, 0xF9, 0x0A, 0x30, 0x3A, 0x78, 0x51, 0x46, 0x68, 0x68, + 0xFF, 0xF7, 0x09, 0xFE, 0xD8, 0xE7, 0x70, 0xB5, 0x04, 0x46, 0xC3, 0x48, + 0x00, 0x78, 0x00, 0x07, 0x09, 0xD5, 0xC2, 0x48, 0x00, 0x68, 0x90, 0xF8, + 0xB4, 0x02, 0x60, 0x43, 0x64, 0x21, 0x90, 0xFB, 0xF1, 0xF0, 0x20, 0x44, + 0x04, 0xB2, 0xBE, 0x4D, 0x2B, 0x46, 0x28, 0x89, 0x20, 0x44, 0x02, 0xB2, + 0xBC, 0x48, 0x01, 0x78, 0xBC, 0x48, 0x00, 0xF0, 0xC4, 0xFB, 0x68, 0x89, + 0x2B, 0x1D, 0x20, 0x44, 0x02, 0xB2, 0xBA, 0x48, 0x01, 0x78, 0xBA, 0x48, + 0x00, 0xF0, 0xBB, 0xFB, 0x28, 0x46, 0x00, 0xF0, 0xBB, 0xFC, 0x28, 0x1D, + 0xBD, 0xE8, 0x70, 0x40, 0x00, 0xF0, 0xB6, 0xBC, 0x2D, 0xE9, 0xFF, 0x5F, + 0xB4, 0x48, 0xD3, 0xE9, 0x00, 0x87, 0x00, 0x78, 0x8B, 0x46, 0x01, 0x28, + 0x05, 0xD1, 0xB2, 0x48, 0x00, 0x78, 0x10, 0xB9, 0x4F, 0xF0, 0xFF, 0x37, + 0xB8, 0x46, 0xB0, 0x48, 0x4F, 0xF4, 0x88, 0x61, 0x00, 0x68, 0x0B, 0xF0, + 0x40, 0xF8, 0xA7, 0x48, 0x00, 0x26, 0x35, 0x46, 0x04, 0x78, 0x4F, 0xF0, + 0x01, 0x09, 0x23, 0xE0, 0x09, 0xFA, 0x04, 0xF0, 0x10, 0xEA, 0x08, 0x0F, + 0x1E, 0xD0, 0xA7, 0x48, 0xE1, 0xB2, 0x00, 0x68, 0x0C, 0xF0, 0xAA, 0xFE, + 0x82, 0x46, 0xE1, 0xB2, 0x00, 0x98, 0x0C, 0xF0, 0xAF, 0xFE, 0x01, 0x46, + 0x9D, 0x48, 0x4B, 0x46, 0x00, 0x78, 0x0D, 0xE0, 0x03, 0xFA, 0x00, 0xF2, + 0x3A, 0x42, 0x09, 0xD0, 0x31, 0xF9, 0x10, 0xC0, 0xDC, 0x45, 0x05, 0xDD, + 0x0A, 0xF8, 0x00, 0x30, 0x31, 0xF9, 0x10, 0x20, 0x76, 0x1C, 0x15, 0x44, + 0x40, 0x1E, 0xEF, 0xD2, 0x64, 0x1E, 0xD9, 0xD2, 0x02, 0x98, 0x05, 0x60, + 0x30, 0x46, 0x04, 0xB0, 0x4E, 0xE6, 0x2D, 0xE9, 0xFF, 0x4F, 0x89, 0x4F, + 0x93, 0x48, 0x32, 0x37, 0x83, 0xB0, 0x00, 0x68, 0x4F, 0xF0, 0x00, 0x0A, + 0x38, 0x60, 0x99, 0x46, 0x8B, 0x46, 0x55, 0x46, 0x01, 0x20, 0x80, 0x46, + 0x03, 0x98, 0x01, 0x7E, 0x41, 0x45, 0x50, 0xD3, 0x03, 0x98, 0x01, 0x26, + 0x10, 0xF8, 0x18, 0x00, 0xB8, 0x70, 0x03, 0x98, 0x00, 0xEB, 0x48, 0x00, + 0x40, 0x78, 0xF8, 0x70, 0x3E, 0xE0, 0x1B, 0xF8, 0x16, 0x00, 0x38, 0x70, + 0x0B, 0xEB, 0x46, 0x00, 0x84, 0x49, 0x40, 0x78, 0x78, 0x70, 0x01, 0x20, + 0xCD, 0xE9, 0x00, 0x01, 0x03, 0x46, 0x7F, 0x48, 0x74, 0x49, 0x00, 0x22, + 0x32, 0x31, 0x00, 0x68, 0x04, 0xF0, 0x94, 0xFC, 0x00, 0x21, 0x29, 0xF8, + 0x15, 0x10, 0x01, 0x24, 0x1D, 0xE0, 0x00, 0xEB, 0x44, 0x00, 0x00, 0x90, + 0xB0, 0xF8, 0xB4, 0x10, 0x05, 0x98, 0x81, 0x42, 0x04, 0xD9, 0x0A, 0xF1, + 0x01, 0x00, 0x00, 0xF0, 0xFF, 0x0A, 0x07, 0xE0, 0x72, 0x48, 0x68, 0x4A, + 0xE1, 0xB2, 0x73, 0x4B, 0x32, 0x32, 0x00, 0x68, 0x04, 0xF0, 0x5B, 0xFD, + 0x00, 0x98, 0x39, 0xF8, 0x15, 0x10, 0x64, 0x1C, 0xB0, 0xF8, 0xB4, 0x00, + 0x08, 0x44, 0x29, 0xF8, 0x15, 0x00, 0x60, 0x48, 0x32, 0x30, 0x90, 0xF8, + 0x0E, 0x11, 0xA1, 0x42, 0xDB, 0xD2, 0x6D, 0x1C, 0xED, 0xB2, 0x76, 0x1C, + 0x9B, 0xF8, 0x18, 0x00, 0xB0, 0x42, 0xBC, 0xD2, 0x08, 0xF1, 0x01, 0x00, + 0xA9, 0xE7, 0x50, 0x46, 0x07, 0xB0, 0x2C, 0xE5, 0x2D, 0xE9, 0xF0, 0x4F, + 0x97, 0xB0, 0x61, 0x49, 0x00, 0x20, 0xCD, 0xE9, 0x00, 0x01, 0x5D, 0x4E, + 0x52, 0x49, 0x02, 0x46, 0x01, 0x23, 0x32, 0x31, 0x30, 0x68, 0x04, 0xF0, + 0x4F, 0xFC, 0x5C, 0x48, 0x4E, 0x4F, 0x4F, 0xF0, 0xFF, 0x35, 0x00, 0x78, + 0x32, 0x37, 0x0D, 0xF1, 0x0C, 0x09, 0x01, 0x28, 0x0E, 0xD1, 0xCD, 0xF8, + 0x00, 0x90, 0xA7, 0xF1, 0x19, 0x03, 0x48, 0x4A, 0x39, 0x46, 0x30, 0x68, + 0xFF, 0xF7, 0x71, 0xFC, 0x53, 0x49, 0x05, 0x46, 0x97, 0xF8, 0x0E, 0x01, + 0x08, 0x76, 0x4D, 0x76, 0x48, 0x48, 0x4F, 0xF0, 0x00, 0x08, 0xBB, 0x46, + 0x00, 0x78, 0x8D, 0xF8, 0x52, 0x00, 0x0D, 0xF1, 0x2E, 0x00, 0x10, 0x90, + 0x0C, 0xA8, 0x11, 0x90, 0x80, 0x1C, 0x12, 0x90, 0x0D, 0x38, 0x01, 0x24, + 0x13, 0x90, 0x3B, 0xE0, 0x01, 0x21, 0xA1, 0x40, 0x29, 0x42, 0x36, 0xD0, + 0x00, 0xEB, 0x84, 0x0A, 0x0B, 0xEB, 0x44, 0x00, 0xE1, 0xB2, 0xB0, 0xF8, + 0xB4, 0x20, 0x03, 0xA8, 0x00, 0xF0, 0x55, 0xF8, 0xE1, 0xB2, 0x03, 0xAB, + 0x52, 0x46, 0x30, 0x68, 0x03, 0xF0, 0x9E, 0xFF, 0x3E, 0x4F, 0x15, 0xAA, + 0x53, 0x46, 0xB7, 0xF9, 0x00, 0x10, 0xCD, 0xF8, 0x08, 0x90, 0xCD, 0xE9, + 0x00, 0x21, 0x31, 0x68, 0xE2, 0xB2, 0x08, 0x46, 0x03, 0xF0, 0x13, 0xFE, + 0xBD, 0xF8, 0x28, 0x00, 0xA8, 0xB1, 0xBD, 0xF9, 0x34, 0x10, 0xB7, 0xF9, + 0x00, 0x20, 0x91, 0x42, 0x0F, 0xDD, 0xAD, 0xF8, 0x50, 0x00, 0x4F, 0xF0, + 0x01, 0x08, 0xE1, 0xB2, 0x10, 0xAB, 0x52, 0x46, 0x30, 0x68, 0x09, 0xF0, + 0x8A, 0xFE, 0xE1, 0xB2, 0x03, 0xAB, 0x52, 0x46, 0x30, 0x68, 0x03, 0xF0, + 0x39, 0xFD, 0x64, 0x1C, 0x9B, 0xF8, 0x0E, 0x11, 0x58, 0x46, 0xA1, 0x42, + 0xBE, 0xD2, 0x40, 0x46, 0x17, 0xB0, 0xAE, 0xE4, 0x70, 0xB5, 0x01, 0x21, + 0x1C, 0x4C, 0x19, 0x4B, 0x0A, 0x46, 0x4E, 0x1E, 0x1D, 0x68, 0x02, 0xFA, + 0x06, 0xF6, 0x35, 0x42, 0x03, 0xD0, 0x25, 0x78, 0xAD, 0x1C, 0x4D, 0x43, + 0x42, 0x55, 0x49, 0x1C, 0x20, 0x29, 0xF2, 0xD3, 0x01, 0x21, 0x16, 0x46, + 0x4D, 0x1E, 0x5C, 0x68, 0x06, 0xFA, 0x05, 0xF2, 0x14, 0x42, 0x00, 0xD0, + 0x46, 0x54, 0x49, 0x1C, 0x22, 0x29, 0xF5, 0xD3, 0x70, 0xBD, 0x70, 0xB5, + 0x0E, 0x46, 0x15, 0x46, 0x04, 0x46, 0x34, 0x21, 0x0A, 0xF0, 0x25, 0xFF, + 0x02, 0x20, 0xA0, 0x73, 0x13, 0x48, 0x00, 0x68, 0x20, 0x61, 0x60, 0x61, + 0x26, 0x76, 0x25, 0x84, 0xA5, 0x83, 0x70, 0xBD, 0xDD, 0x46, 0x10, 0x00, + 0x1C, 0x24, 0x10, 0x00, 0x50, 0x24, 0x10, 0x00, 0xA4, 0x48, 0x10, 0x00, + 0x00, 0x24, 0x10, 0x00, 0x80, 0x0A, 0x01, 0x20, 0x01, 0x24, 0x10, 0x00, + 0xBC, 0x0A, 0x01, 0x20, 0x71, 0x23, 0x10, 0x00, 0x6D, 0x23, 0x10, 0x00, + 0xA0, 0x23, 0x10, 0x00, 0x60, 0x1D, 0x01, 0x00, 0xAC, 0x23, 0x10, 0x00, + 0x55, 0x23, 0x10, 0x00, 0x8A, 0x25, 0x10, 0x00, 0xCC, 0x23, 0x10, 0x00, + 0x5C, 0x23, 0x10, 0x00, 0x64, 0x4A, 0x30, 0xB4, 0x12, 0x68, 0x00, 0x21, + 0xB2, 0xF8, 0x7C, 0x30, 0x83, 0x42, 0x05, 0xDA, 0x92, 0xF8, 0x78, 0x30, + 0x5B, 0x07, 0x01, 0xD5, 0x02, 0x21, 0x08, 0xE0, 0xB2, 0xF8, 0x7A, 0x30, + 0x83, 0x42, 0x04, 0xDA, 0x92, 0xF8, 0x78, 0x00, 0x80, 0x07, 0x00, 0xD5, + 0x01, 0x21, 0x5A, 0x4B, 0x58, 0x78, 0x81, 0x42, 0x14, 0xD1, 0x1C, 0x78, + 0x84, 0x42, 0x1D, 0xD0, 0x57, 0x4D, 0x2D, 0x78, 0x28, 0x43, 0x57, 0x4D, + 0x2D, 0x78, 0x28, 0x43, 0x07, 0xD0, 0x58, 0x68, 0x40, 0x1E, 0x58, 0x60, + 0x00, 0x28, 0x11, 0xDC, 0x58, 0x78, 0x18, 0x70, 0x0E, 0xE0, 0x5C, 0x70, + 0x58, 0x68, 0xF7, 0xE7, 0x99, 0xB1, 0x02, 0x29, 0x01, 0xD1, 0x01, 0x28, + 0x0F, 0xD0, 0x92, 0xF8, 0x1A, 0x01, 0x58, 0x60, 0x59, 0x70, 0x00, 0x28, + 0x00, 0xDC, 0x19, 0x70, 0x18, 0x78, 0x01, 0x43, 0x08, 0xD0, 0x92, 0xF8, + 0xA7, 0x13, 0x30, 0xBC, 0x06, 0x20, 0x06, 0xF0, 0x46, 0xBB, 0x92, 0xF8, + 0x1B, 0x01, 0xEE, 0xE7, 0x30, 0xBC, 0x70, 0x47, 0x40, 0x48, 0x00, 0x21, + 0x01, 0x70, 0x41, 0x70, 0x41, 0x60, 0x70, 0x47, 0x2D, 0xE9, 0xFC, 0x41, + 0x3F, 0x4E, 0x07, 0x46, 0x0D, 0x46, 0x30, 0x78, 0x3E, 0x49, 0x42, 0x00, + 0x00, 0x24, 0x01, 0xF1, 0x3C, 0x00, 0x0A, 0xF0, 0xFB, 0xFD, 0x30, 0x78, + 0x39, 0x46, 0x42, 0x00, 0x39, 0x48, 0x0A, 0xF0, 0xF5, 0xFD, 0x28, 0x46, + 0x37, 0x4D, 0x78, 0x35, 0x01, 0x28, 0x0F, 0xD0, 0x31, 0x78, 0x00, 0x20, + 0xCD, 0xE9, 0x00, 0x01, 0x03, 0x46, 0xA5, 0xF1, 0x3C, 0x02, 0x39, 0x46, + 0x32, 0x48, 0x07, 0xF0, 0x7B, 0xFE, 0x00, 0x20, 0xDF, 0xF8, 0xA8, 0xC0, + 0x37, 0x78, 0x35, 0xE0, 0x30, 0x78, 0x39, 0x46, 0x42, 0x00, 0x2C, 0x48, + 0x3C, 0x30, 0x0A, 0xF0, 0xD9, 0xFD, 0x30, 0x78, 0x41, 0x00, 0x29, 0x48, + 0x78, 0x30, 0x0A, 0xF0, 0x52, 0xFE, 0x29, 0xE0, 0x26, 0x49, 0x27, 0x4A, + 0x3C, 0x31, 0x31, 0xF9, 0x10, 0x10, 0x32, 0xF9, 0x10, 0x20, 0x89, 0x1A, + 0x00, 0xD5, 0x49, 0x42, 0x35, 0xF9, 0x10, 0x30, 0x09, 0xB2, 0xDC, 0xF8, + 0x00, 0x20, 0x8B, 0x42, 0x02, 0xDA, 0x92, 0xF8, 0x7E, 0x20, 0x01, 0xE0, + 0x92, 0xF8, 0x7F, 0x20, 0x53, 0x43, 0xC2, 0xF5, 0x80, 0x72, 0x01, 0xFB, + 0x02, 0x31, 0xCA, 0x17, 0x01, 0xEB, 0x12, 0x61, 0x09, 0x12, 0x25, 0xF8, + 0x10, 0x10, 0x35, 0xF9, 0x10, 0x10, 0xA1, 0x42, 0x00, 0xDD, 0x0C, 0x46, + 0x40, 0x1C, 0x00, 0xB2, 0xB8, 0x42, 0xD5, 0xDB, 0x20, 0x46, 0xFF, 0xF7, + 0x4D, 0xFF, 0x0C, 0x4F, 0x11, 0x49, 0x12, 0x4B, 0x38, 0x78, 0x4A, 0x7C, + 0x60, 0xF3, 0x03, 0x02, 0x4A, 0x74, 0xDA, 0x7C, 0x60, 0xF3, 0x07, 0x12, + 0xDA, 0x74, 0x3A, 0x79, 0xCA, 0x74, 0xCC, 0x82, 0x31, 0x78, 0x25, 0xF8, + 0x11, 0x00, 0x05, 0xEB, 0x41, 0x00, 0x44, 0x80, 0xBD, 0xE8, 0xFC, 0x81, + 0x50, 0x24, 0x10, 0x00, 0x4C, 0x23, 0x10, 0x00, 0x29, 0x24, 0x10, 0x00, + 0x57, 0x23, 0x10, 0x00, 0x00, 0x24, 0x10, 0x00, 0xD0, 0x01, 0x01, 0x20, + 0x1E, 0x48, 0x10, 0x00, 0x6C, 0x25, 0x10, 0x00, 0x58, 0x25, 0x10, 0x00, + 0x2D, 0xE9, 0xF0, 0x4F, 0x47, 0xF6, 0xFF, 0x76, 0xDD, 0xE9, 0x09, 0xB5, + 0xF4, 0x43, 0x9A, 0x46, 0x01, 0x27, 0x81, 0x46, 0xBC, 0x46, 0x2B, 0x46, + 0x14, 0xE0, 0x32, 0xF8, 0x13, 0x00, 0x31, 0xF8, 0x13, 0x80, 0xA0, 0xEB, + 0x08, 0x00, 0x00, 0xB2, 0xB0, 0x42, 0x00, 0xDA, 0x06, 0x46, 0xA0, 0x42, + 0x00, 0xDD, 0x04, 0x46, 0x00, 0x28, 0x02, 0xDD, 0x4F, 0xF0, 0x00, 0x0C, + 0x02, 0xE0, 0x01, 0xDA, 0x4F, 0xF0, 0x00, 0x07, 0x5B, 0x1E, 0xE8, 0xD2, + 0x27, 0xB1, 0xBC, 0xF1, 0x00, 0x0F, 0x01, 0xD0, 0x00, 0x20, 0x09, 0xE0, + 0x57, 0xEA, 0x0C, 0x00, 0x06, 0xD0, 0x27, 0xB9, 0xBC, 0xF1, 0x00, 0x0F, + 0x01, 0xD0, 0x20, 0x46, 0x00, 0xE0, 0x30, 0x46, 0x00, 0x23, 0x1E, 0x46, + 0x2C, 0x46, 0xCB, 0xF1, 0x00, 0x0C, 0x0D, 0xE0, 0x32, 0xF8, 0x14, 0x70, + 0x31, 0xF8, 0x14, 0x80, 0xA7, 0xEB, 0x08, 0x07, 0x3F, 0x1A, 0x3F, 0xB2, + 0x57, 0x45, 0x03, 0xDA, 0x67, 0x45, 0x01, 0xDD, 0x3B, 0x44, 0x76, 0x1C, + 0x64, 0x1E, 0xEF, 0xD2, 0x06, 0xB9, 0x01, 0x26, 0x93, 0xFB, 0xF6, 0xF2, + 0x13, 0x18, 0x04, 0xE0, 0x31, 0xF8, 0x15, 0x00, 0x18, 0x44, 0x29, 0xF8, + 0x15, 0x00, 0x6D, 0x1E, 0xF8, 0xD2, 0xBD, 0xE8, 0xF0, 0x8F, 0xF0, 0xB5, + 0x00, 0x25, 0x2E, 0x46, 0x0D, 0xE0, 0x30, 0xF9, 0x11, 0x40, 0x00, 0x2C, + 0x01, 0xDB, 0x27, 0x46, 0x00, 0xE0, 0x67, 0x42, 0x97, 0x42, 0x04, 0xDD, + 0x00, 0x2C, 0x01, 0xDD, 0x26, 0x44, 0x00, 0xE0, 0x25, 0x44, 0x49, 0x1E, + 0xEF, 0xD2, 0x00, 0x2D, 0x00, 0xDA, 0x6D, 0x42, 0xB5, 0x42, 0x01, 0xDD, + 0x01, 0x20, 0x18, 0x70, 0xF0, 0xBD, 0x2D, 0xE9, 0xFC, 0x41, 0x00, 0x25, + 0x0F, 0x46, 0x8D, 0xF8, 0x00, 0x50, 0x8D, 0xF8, 0x04, 0x50, 0x2C, 0x46, + 0xFE, 0x4E, 0x6B, 0x46, 0x31, 0x68, 0xB1, 0xF9, 0x84, 0x20, 0xFD, 0x49, + 0x09, 0x78, 0xFF, 0xF7, 0xD2, 0xFF, 0x30, 0x68, 0x01, 0xAB, 0xB0, 0xF9, + 0x84, 0x20, 0xFA, 0x48, 0x01, 0x78, 0x38, 0x46, 0xFF, 0xF7, 0xC9, 0xFF, + 0xF8, 0x4A, 0xD0, 0x79, 0x68, 0xB1, 0x50, 0x69, 0x40, 0x1C, 0x50, 0x61, + 0x31, 0x68, 0x91, 0xF8, 0x87, 0x10, 0x81, 0x42, 0x02, 0xDA, 0x55, 0x61, + 0xD5, 0x71, 0x01, 0x24, 0x20, 0x46, 0xBD, 0xE8, 0xFC, 0x81, 0x9D, 0xF8, + 0x00, 0x00, 0x01, 0x28, 0x03, 0xD1, 0x9D, 0xF8, 0x04, 0x00, 0x01, 0x28, + 0x01, 0xD0, 0x55, 0x61, 0xF2, 0xE7, 0x51, 0x69, 0x49, 0x1C, 0x51, 0x61, + 0x30, 0x68, 0x90, 0xF8, 0x86, 0x30, 0x8B, 0x42, 0x07, 0xDA, 0x01, 0x21, + 0x55, 0x61, 0xD1, 0x71, 0x90, 0xF8, 0x87, 0x10, 0x09, 0xB9, 0xD5, 0x71, + 0x01, 0x24, 0x90, 0xF8, 0xA8, 0x13, 0x07, 0x20, 0x06, 0xF0, 0xEF, 0xF9, + 0xDC, 0xE7, 0x70, 0xB5, 0x00, 0x24, 0x25, 0x46, 0x52, 0x42, 0x05, 0xE0, + 0x30, 0xF9, 0x11, 0x60, 0x96, 0x42, 0x01, 0xDC, 0x64, 0x1C, 0xE4, 0xB2, + 0x49, 0x1E, 0xF7, 0xD2, 0x9C, 0x42, 0x00, 0xD3, 0x01, 0x25, 0x28, 0x46, + 0x70, 0xBD, 0x10, 0xB5, 0x01, 0x24, 0x05, 0xE0, 0x30, 0xF9, 0x11, 0x30, + 0x93, 0x42, 0x01, 0xDA, 0x00, 0x24, 0x01, 0xE0, 0x49, 0x1E, 0xF7, 0xD2, + 0x20, 0x46, 0x10, 0xBD, 0x2D, 0xE9, 0xFC, 0x47, 0x10, 0x26, 0xCD, 0xE9, + 0x00, 0x62, 0xCF, 0x4F, 0xCB, 0x4D, 0x89, 0x46, 0x14, 0x46, 0x01, 0x46, + 0x4F, 0xF0, 0x00, 0x08, 0x2A, 0x78, 0xCC, 0x48, 0x3B, 0x68, 0x07, 0xF0, + 0x79, 0xFD, 0xCD, 0xE9, 0x00, 0x64, 0xC6, 0x4E, 0xC8, 0x48, 0x49, 0x46, + 0x32, 0x78, 0x3C, 0x30, 0x3B, 0x68, 0x07, 0xF0, 0x6F, 0xFD, 0xC0, 0x4C, + 0x20, 0x68, 0x90, 0xF8, 0x82, 0x10, 0x89, 0x07, 0x19, 0xD5, 0x2A, 0x78, + 0xB0, 0xF9, 0x8A, 0x10, 0xCD, 0xE9, 0x00, 0x12, 0xBF, 0x49, 0xB0, 0xF9, + 0x88, 0x30, 0xBF, 0x4A, 0x08, 0x46, 0xFF, 0xF7, 0xF3, 0xFE, 0x20, 0x68, + 0x32, 0x78, 0xB0, 0xF9, 0x8E, 0x10, 0xCD, 0xE9, 0x00, 0x12, 0xB9, 0x49, + 0xB0, 0xF9, 0x8C, 0x30, 0x3C, 0x31, 0xB9, 0x4A, 0x08, 0x46, 0xFF, 0xF7, + 0xE5, 0xFE, 0xB5, 0x49, 0x2B, 0x78, 0xB5, 0x4A, 0x01, 0xF1, 0x7C, 0x00, + 0x07, 0xF0, 0x33, 0xFB, 0xB1, 0x49, 0x33, 0x78, 0x3C, 0x31, 0xB2, 0x4A, + 0x01, 0xF1, 0x7C, 0x00, 0x07, 0xF0, 0x2B, 0xFB, 0x20, 0x68, 0x90, 0xF8, + 0x82, 0x10, 0x09, 0x07, 0x06, 0xD4, 0xAE, 0x49, 0x09, 0x78, 0xA1, 0xB1, + 0x90, 0xF8, 0xB0, 0x10, 0x49, 0x06, 0x10, 0xD5, 0xA7, 0x49, 0x90, 0xF8, + 0xAD, 0x30, 0x7C, 0x31, 0x2A, 0x78, 0x08, 0x46, 0x07, 0xF0, 0x47, 0xFD, + 0x20, 0x68, 0xA3, 0x49, 0x32, 0x78, 0x90, 0xF8, 0xAD, 0x30, 0xB8, 0x31, + 0x08, 0x46, 0x07, 0xF0, 0x3E, 0xFD, 0x20, 0x68, 0x90, 0xF8, 0x82, 0x00, + 0xC0, 0x07, 0x09, 0xD0, 0x9C, 0x49, 0xB8, 0x31, 0xA1, 0xF1, 0x3C, 0x00, + 0xFF, 0xF7, 0x23, 0xFF, 0x97, 0x49, 0x80, 0x46, 0x20, 0x20, 0x48, 0x71, + 0x40, 0x46, 0xBD, 0xE8, 0xFC, 0x87, 0xF0, 0xB5, 0x06, 0x46, 0x00, 0x20, + 0x01, 0x24, 0x18, 0x60, 0x09, 0xE0, 0x36, 0xF9, 0x11, 0x50, 0x95, 0x42, + 0x05, 0xDD, 0x1D, 0x68, 0x01, 0x20, 0x04, 0xFA, 0x01, 0xF7, 0x3D, 0x43, + 0x1D, 0x60, 0x49, 0x1E, 0xF3, 0xD2, 0xF0, 0xBD, 0x2D, 0xE9, 0xFF, 0x5F, + 0x87, 0x49, 0x91, 0x46, 0xDF, 0xF8, 0x38, 0xB2, 0x0A, 0x78, 0xDF, 0xF8, + 0x24, 0x82, 0x00, 0x24, 0x94, 0x46, 0x4F, 0xF0, 0x01, 0x0A, 0x5D, 0x46, + 0x08, 0xF1, 0xF8, 0x08, 0x92, 0x1E, 0x1A, 0xD0, 0x80, 0x49, 0xAC, 0xF1, + 0x02, 0x0C, 0x0E, 0x78, 0x02, 0xFB, 0x06, 0xF1, 0x00, 0xEB, 0x41, 0x07, + 0x31, 0x46, 0x0C, 0xE0, 0x37, 0xF9, 0x11, 0x30, 0xAB, 0x42, 0x00, 0xDD, + 0x1D, 0x46, 0x01, 0x2A, 0x01, 0xD0, 0x62, 0x45, 0x03, 0xD1, 0x28, 0xF8, + 0x14, 0x30, 0x64, 0x1C, 0xE4, 0xB2, 0x49, 0x1E, 0xF0, 0xD2, 0x52, 0x1E, + 0xE8, 0xD1, 0x76, 0x48, 0x21, 0x46, 0xF8, 0x30, 0x07, 0xF0, 0x72, 0xFA, + 0x08, 0xEB, 0x44, 0x01, 0x64, 0x1C, 0x0B, 0x88, 0xE2, 0xB2, 0x5B, 0x1C, + 0x0B, 0x80, 0x28, 0xF8, 0x12, 0x00, 0x6B, 0x49, 0x28, 0x1A, 0x05, 0xB2, + 0x09, 0x78, 0x01, 0x20, 0x5C, 0x46, 0x4B, 0x1E, 0x05, 0xE0, 0x39, 0xF9, + 0x10, 0x20, 0xA2, 0x42, 0x00, 0xDD, 0x14, 0x46, 0x40, 0x1C, 0x98, 0x42, + 0xF7, 0xD3, 0x48, 0x46, 0x49, 0x1E, 0x07, 0xF0, 0x55, 0xFA, 0x6A, 0x49, + 0x20, 0x1A, 0x00, 0xB2, 0xCD, 0x80, 0x08, 0x81, 0x01, 0x99, 0x8D, 0x42, + 0x04, 0xDD, 0x03, 0x99, 0x88, 0x42, 0x01, 0xDA, 0x4F, 0xF0, 0x00, 0x0A, + 0x04, 0xB0, 0x50, 0x46, 0xBD, 0xE8, 0xF0, 0x9F, 0x10, 0xB5, 0x00, 0x24, + 0x05, 0xE0, 0x30, 0xF9, 0x11, 0x30, 0x93, 0x42, 0x01, 0xDD, 0x01, 0x24, + 0x01, 0xE0, 0x49, 0x1E, 0xF7, 0xD2, 0x20, 0x46, 0x10, 0xBD, 0x2D, 0xE9, + 0xF0, 0x47, 0x58, 0x48, 0x00, 0x24, 0x52, 0x4E, 0x00, 0x78, 0xDF, 0xF8, + 0x38, 0x81, 0x9C, 0x46, 0x92, 0x46, 0x27, 0x46, 0x01, 0x28, 0x1B, 0xD0, + 0xD8, 0xF8, 0x00, 0x00, 0xB0, 0xF8, 0xF8, 0x50, 0xBC, 0xF8, 0x08, 0x00, + 0x28, 0x44, 0x02, 0xB2, 0x47, 0x48, 0x01, 0x78, 0x4A, 0x48, 0x7C, 0x30, + 0xFF, 0xF7, 0xD8, 0xFF, 0x81, 0x46, 0xBC, 0xF8, 0x0A, 0x00, 0x28, 0x44, + 0x02, 0xB2, 0x43, 0x48, 0x01, 0x78, 0x45, 0x48, 0xB8, 0x30, 0xFF, 0xF7, + 0xCD, 0xFF, 0x01, 0x28, 0x02, 0xD0, 0x05, 0xE0, 0xF4, 0x78, 0x03, 0xE0, + 0xB9, 0xF1, 0x01, 0x0F, 0x00, 0xD1, 0x01, 0x24, 0xD8, 0xF8, 0x00, 0x00, + 0x45, 0x46, 0xB0, 0xF9, 0xF2, 0x10, 0x42, 0x48, 0xB0, 0xF9, 0x00, 0x20, + 0x50, 0x46, 0x01, 0xF0, 0xC8, 0xF9, 0x00, 0x22, 0x0C, 0xB9, 0x01, 0x28, + 0x03, 0xD0, 0xF2, 0x60, 0x38, 0x46, 0xBD, 0xE8, 0xF0, 0x87, 0xF0, 0x68, + 0x40, 0x1C, 0xF0, 0x60, 0x29, 0x68, 0x91, 0xF8, 0xF4, 0x30, 0x83, 0x42, + 0x01, 0xDA, 0x01, 0x27, 0xF2, 0x60, 0x91, 0xF8, 0xA8, 0x13, 0x07, 0x20, + 0x06, 0xF0, 0x85, 0xF8, 0xEC, 0xE7, 0x30, 0xB5, 0x2A, 0x48, 0x01, 0x21, + 0x32, 0x4A, 0x81, 0x70, 0x00, 0x21, 0xC1, 0x70, 0x01, 0x71, 0x41, 0x70, + 0x82, 0x60, 0x31, 0x4B, 0x2F, 0x4A, 0x38, 0xCB, 0x82, 0xE8, 0x38, 0x00, + 0x41, 0x71, 0x01, 0x61, 0x41, 0x61, 0xC1, 0x71, 0x30, 0xBD, 0x03, 0x46, + 0x47, 0xF6, 0xFF, 0x70, 0x04, 0xE0, 0x33, 0xF9, 0x11, 0x20, 0x82, 0x42, + 0x00, 0xDA, 0x10, 0x46, 0x49, 0x1E, 0xF8, 0xD2, 0x00, 0x28, 0x00, 0xDA, + 0x00, 0x20, 0x70, 0x47, 0x03, 0x46, 0x1F, 0x48, 0x04, 0xE0, 0x33, 0xF9, + 0x11, 0x20, 0x82, 0x42, 0x00, 0xDD, 0x10, 0x46, 0x49, 0x1E, 0xF8, 0xD2, + 0x00, 0x28, 0x00, 0xDA, 0x00, 0x20, 0x70, 0x47, 0x01, 0x68, 0x41, 0xEA, + 0x51, 0x01, 0x41, 0xEA, 0x41, 0x01, 0x01, 0x60, 0x70, 0x47, 0x2D, 0xE9, + 0xFF, 0x4F, 0x83, 0xB0, 0x0D, 0x4C, 0x10, 0x9E, 0x4F, 0xF0, 0x00, 0x08, + 0x82, 0x46, 0x86, 0xF8, 0x00, 0x80, 0xA5, 0x78, 0x11, 0x48, 0x84, 0xF8, + 0x02, 0x80, 0x84, 0xF8, 0x05, 0x80, 0xB0, 0xF9, 0x00, 0x00, 0x0F, 0x46, + 0x42, 0x00, 0x4F, 0xF0, 0x01, 0x09, 0x19, 0x46, 0xA0, 0x68, 0x1D, 0xE0, + 0x50, 0x24, 0x10, 0x00, 0x00, 0x24, 0x10, 0x00, 0x01, 0x24, 0x10, 0x00, + 0x54, 0x23, 0x10, 0x00, 0xBC, 0x23, 0x10, 0x00, 0x04, 0x0A, 0x01, 0x20, + 0xFC, 0x22, 0x01, 0x20, 0x38, 0x23, 0x01, 0x20, 0x6D, 0x23, 0x10, 0x00, + 0x00, 0x80, 0xFF, 0xFF, 0x8A, 0x25, 0x10, 0x00, 0x0C, 0x24, 0x10, 0x00, + 0x84, 0x02, 0x01, 0x20, 0xA4, 0x48, 0x10, 0x00, 0x18, 0x1D, 0x01, 0x00, + 0x0A, 0xF0, 0xE0, 0xFA, 0x2A, 0x46, 0x39, 0x46, 0x50, 0x46, 0xFF, 0xF7, + 0x3F, 0xFE, 0x01, 0x28, 0x47, 0xD0, 0xA4, 0x49, 0xA2, 0x4A, 0xA1, 0xF1, + 0x3C, 0x00, 0x00, 0xF0, 0x71, 0xF8, 0xE0, 0x70, 0xA0, 0x48, 0xA1, 0x4D, + 0x3C, 0x38, 0x02, 0x90, 0x29, 0x68, 0xDF, 0xF8, 0x78, 0xB2, 0x9C, 0x4F, + 0x91, 0xF8, 0xF0, 0x10, 0x00, 0x20, 0xD4, 0xF8, 0x08, 0xA0, 0xC9, 0x07, + 0x0B, 0xD0, 0x3B, 0x46, 0x52, 0x46, 0x59, 0x46, 0x02, 0x98, 0xFF, 0xF7, + 0x1A, 0xFF, 0x01, 0x28, 0x01, 0xD0, 0x10, 0xB1, 0x10, 0xE0, 0x28, 0x21, + 0x0D, 0xE0, 0x29, 0x68, 0x91, 0xF8, 0xF0, 0x10, 0x89, 0x07, 0x09, 0xD5, + 0x3B, 0x46, 0x52, 0x46, 0x59, 0x46, 0x02, 0x98, 0x00, 0xF0, 0xDD, 0xF8, + 0x01, 0x28, 0x01, 0xD1, 0x29, 0x21, 0x61, 0x71, 0x07, 0x46, 0x01, 0x28, + 0x10, 0xD0, 0x28, 0x68, 0x8B, 0x4A, 0x8C, 0x4E, 0xB0, 0xF9, 0x96, 0x10, + 0x12, 0x78, 0xB0, 0xF9, 0xAE, 0x30, 0x01, 0x2A, 0x0B, 0xD0, 0xA2, 0x79, + 0x62, 0xB1, 0x32, 0x78, 0x72, 0xB1, 0xB0, 0xF9, 0x98, 0x10, 0x0B, 0xE0, + 0x01, 0x20, 0x30, 0x70, 0x00, 0x20, 0x07, 0xB0, 0x69, 0xE5, 0xB0, 0xF9, + 0x94, 0x10, 0x03, 0xE0, 0x31, 0x78, 0x21, 0xB3, 0xB0, 0xF9, 0x9C, 0x10, + 0x7F, 0x48, 0x00, 0x78, 0x02, 0x28, 0x04, 0xD9, 0x7E, 0x4A, 0x05, 0x98, + 0xFF, 0xF7, 0x70, 0xFE, 0x81, 0x46, 0x69, 0x46, 0xA0, 0x68, 0x00, 0xF0, + 0x4A, 0xF8, 0xE2, 0x78, 0x49, 0x46, 0x68, 0x46, 0x00, 0xF0, 0x72, 0xF8, + 0x78, 0x49, 0x60, 0x70, 0x81, 0xF8, 0x18, 0x80, 0x77, 0x49, 0x81, 0xF8, + 0x18, 0x80, 0x30, 0x78, 0x28, 0xB1, 0x28, 0x68, 0x90, 0xF8, 0xA6, 0x13, + 0x04, 0x20, 0x05, 0xF0, 0x9A, 0xFF, 0x38, 0x46, 0xD3, 0xE7, 0xB0, 0xF9, + 0x9A, 0x10, 0xD9, 0xE7, 0xF0, 0xB5, 0x84, 0x46, 0x00, 0x26, 0x6F, 0x48, + 0x16, 0x81, 0x15, 0x46, 0x56, 0x81, 0x02, 0x78, 0x65, 0x48, 0x0F, 0x46, + 0x31, 0x46, 0x00, 0x68, 0xDA, 0xB1, 0x6B, 0x4A, 0x52, 0x78, 0x01, 0x2A, + 0x17, 0xD0, 0xB0, 0xF9, 0x92, 0x40, 0x2B, 0x46, 0x08, 0x19, 0x02, 0xB2, + 0x61, 0x48, 0x01, 0x78, 0x60, 0x46, 0xFF, 0xF7, 0x24, 0xFE, 0x84, 0x46, + 0x68, 0x89, 0x2B, 0x1D, 0x20, 0x44, 0x02, 0xB2, 0x62, 0x48, 0x01, 0x78, + 0x38, 0x46, 0xFF, 0xF7, 0x1A, 0xFE, 0xBC, 0xF1, 0x01, 0x0F, 0x03, 0xD0, + 0x05, 0xE0, 0xB0, 0xF9, 0x90, 0x40, 0xE6, 0xE7, 0x01, 0x28, 0x00, 0xD1, + 0x01, 0x26, 0x30, 0x46, 0xF0, 0xBD, 0x30, 0xB5, 0x50, 0x4A, 0x12, 0x68, + 0xB2, 0xF9, 0xB7, 0x30, 0x00, 0x22, 0xCA, 0x80, 0x8A, 0x80, 0x0A, 0x60, + 0x56, 0x4A, 0x5C, 0x42, 0xB2, 0xF9, 0x00, 0x20, 0x12, 0xE0, 0x30, 0xF9, + 0x12, 0x30, 0x00, 0x2B, 0x0E, 0xDA, 0x8B, 0x88, 0x5B, 0x1C, 0x8B, 0x80, + 0x30, 0xF9, 0x12, 0x50, 0x0B, 0x68, 0x2B, 0x44, 0x0B, 0x60, 0x30, 0xF9, + 0x12, 0x30, 0xA3, 0x42, 0x02, 0xDA, 0xCB, 0x88, 0x5B, 0x1C, 0xCB, 0x80, + 0x52, 0x1E, 0xEA, 0xD2, 0x08, 0x68, 0x00, 0x28, 0x00, 0xDA, 0x40, 0x42, + 0x48, 0x4A, 0x08, 0x60, 0x90, 0x81, 0x88, 0x79, 0xD0, 0x72, 0x30, 0xBD, + 0x70, 0xB5, 0x45, 0x48, 0x00, 0x24, 0x82, 0x7A, 0x61, 0xF3, 0x82, 0x02, + 0x82, 0x72, 0x43, 0x48, 0x00, 0x78, 0xC0, 0x06, 0x24, 0xD5, 0x37, 0x4D, + 0x49, 0xB1, 0x00, 0xF0, 0x1F, 0xF9, 0x2C, 0x78, 0x3A, 0x4E, 0x28, 0x78, + 0x31, 0x78, 0x88, 0x42, 0x18, 0xD0, 0x21, 0xB1, 0x0B, 0xE0, 0x00, 0xF0, + 0xF6, 0xF8, 0x01, 0x24, 0xF4, 0xE7, 0x01, 0x28, 0x10, 0xD1, 0x00, 0x23, + 0x1A, 0x46, 0x19, 0x46, 0xE1, 0x20, 0x06, 0xF0, 0xA0, 0xFF, 0x30, 0x78, + 0x01, 0x28, 0x07, 0xD1, 0x28, 0x78, 0x28, 0xB9, 0x00, 0x23, 0x1A, 0x46, + 0x19, 0x46, 0xE2, 0x20, 0x06, 0xF0, 0x95, 0xFF, 0x28, 0x78, 0x30, 0x70, + 0x00, 0x20, 0x01, 0x2C, 0x00, 0xD1, 0x01, 0x20, 0x70, 0xBD, 0x2D, 0xE9, + 0xF0, 0x41, 0x1F, 0x4E, 0x90, 0x46, 0x00, 0x24, 0x30, 0x68, 0x25, 0x46, + 0x90, 0xF8, 0xF6, 0xC0, 0x1E, 0x48, 0x62, 0x46, 0x01, 0x78, 0x19, 0x48, + 0x3C, 0x38, 0xFF, 0xF7, 0x0F, 0xFE, 0x07, 0x46, 0x20, 0x48, 0x62, 0x46, + 0x01, 0x78, 0x15, 0x48, 0xFF, 0xF7, 0x08, 0xFE, 0x01, 0x28, 0x01, 0xD0, + 0x01, 0x2F, 0x00, 0xD1, 0x01, 0x24, 0x30, 0x68, 0x90, 0xF8, 0xF7, 0x10, + 0x1A, 0x48, 0xB0, 0xF9, 0x00, 0x20, 0x40, 0x46, 0x01, 0xF0, 0x09, 0xF8, + 0x15, 0x4B, 0x00, 0x27, 0x04, 0xB1, 0x18, 0xB1, 0x1F, 0x61, 0x28, 0x46, + 0xBD, 0xE8, 0xF0, 0x81, 0x19, 0x69, 0x49, 0x1C, 0x19, 0x61, 0x32, 0x68, + 0x92, 0xF8, 0xF5, 0x00, 0x88, 0x42, 0x01, 0xDA, 0x01, 0x25, 0x1F, 0x61, + 0x92, 0xF8, 0xA8, 0x13, 0x07, 0x20, 0x05, 0xF0, 0xC6, 0xFE, 0xEC, 0xE7, + 0xA4, 0x48, 0x10, 0x00, 0xBC, 0x0A, 0x01, 0x20, 0x50, 0x24, 0x10, 0x00, + 0x71, 0x23, 0x10, 0x00, 0x6D, 0x23, 0x10, 0x00, 0x00, 0x24, 0x10, 0x00, + 0xFC, 0x22, 0x01, 0x20, 0xDD, 0x46, 0x10, 0x00, 0xF6, 0x46, 0x10, 0x00, + 0xB8, 0x23, 0x10, 0x00, 0x54, 0x23, 0x10, 0x00, 0x01, 0x24, 0x10, 0x00, + 0x0C, 0x24, 0x10, 0x00, 0x8A, 0x25, 0x10, 0x00, 0x1C, 0x24, 0x10, 0x00, + 0xF0, 0xB5, 0x00, 0x24, 0x1C, 0x70, 0x04, 0x7E, 0x0D, 0x7E, 0x4F, 0xF0, + 0xFF, 0x36, 0x6C, 0x43, 0xE7, 0xB2, 0x4F, 0xF0, 0x00, 0x0E, 0x35, 0x46, + 0x74, 0x46, 0x07, 0xE0, 0x32, 0xF8, 0x14, 0xC0, 0xF4, 0x45, 0x01, 0xD9, + 0xE6, 0x46, 0x65, 0xB2, 0x64, 0x1C, 0xE4, 0xB2, 0xBC, 0x42, 0xF5, 0xD3, + 0x00, 0x2D, 0x1B, 0xDB, 0x01, 0x24, 0x1C, 0x70, 0x0C, 0x7E, 0x95, 0xFB, + 0xF4, 0xF4, 0x64, 0x1C, 0xE4, 0xB2, 0x04, 0x44, 0x94, 0xF8, 0x12, 0xC0, + 0x83, 0xF8, 0x01, 0xC0, 0x24, 0x7B, 0x5C, 0x71, 0x0C, 0x7E, 0x95, 0xFB, + 0xF4, 0xFC, 0x04, 0xFB, 0x1C, 0x54, 0x64, 0x1C, 0xE4, 0xB2, 0x0C, 0x44, + 0x94, 0xF8, 0x12, 0xC0, 0x83, 0xF8, 0x03, 0xC0, 0x24, 0x7B, 0xDC, 0x71, + 0x01, 0x2F, 0x2F, 0xD9, 0xFE, 0x4C, 0x24, 0x68, 0x94, 0xF8, 0xB0, 0x40, + 0xA4, 0x07, 0x29, 0xD5, 0x4F, 0xF0, 0x00, 0x0E, 0x74, 0x46, 0x09, 0xE0, + 0x32, 0xF8, 0x14, 0xC0, 0xF4, 0x45, 0x03, 0xD9, 0xA5, 0x42, 0x01, 0xD0, + 0xE6, 0x46, 0x66, 0xB2, 0x64, 0x1C, 0xE4, 0xB2, 0xBC, 0x42, 0xF3, 0xD3, + 0x00, 0x2E, 0x17, 0xDB, 0x02, 0x22, 0x1A, 0x70, 0x0A, 0x7E, 0x96, 0xFB, + 0xF2, 0xF2, 0x52, 0x1C, 0xD2, 0xB2, 0x10, 0x44, 0x82, 0x7C, 0x9A, 0x70, + 0x00, 0x7B, 0x98, 0x71, 0x08, 0x7E, 0x96, 0xFB, 0xF0, 0xF2, 0x00, 0xFB, + 0x12, 0x60, 0x40, 0x1C, 0xC0, 0xB2, 0x08, 0x44, 0x81, 0x7C, 0x19, 0x71, + 0x00, 0x7B, 0x18, 0x72, 0xF0, 0xBD, 0x70, 0xB5, 0xFF, 0xF7, 0xB7, 0xFD, + 0xE5, 0x4C, 0x00, 0x25, 0x78, 0x21, 0x25, 0x70, 0xA5, 0x70, 0xE5, 0x70, + 0x65, 0x70, 0x25, 0x71, 0xE2, 0x48, 0x0A, 0xF0, 0x9E, 0xF9, 0x65, 0x71, + 0xA5, 0x71, 0xFF, 0xF7, 0x60, 0xF8, 0xBD, 0xE8, 0x70, 0x40, 0xFE, 0xF7, + 0xE2, 0xBD, 0x70, 0xB5, 0xDB, 0x4C, 0xDA, 0x4E, 0x00, 0x25, 0xE5, 0x70, + 0x30, 0x68, 0x90, 0xF8, 0xA6, 0x13, 0x04, 0x20, 0x05, 0xF0, 0x1D, 0xFE, + 0x20, 0x78, 0x68, 0xB9, 0xA0, 0x78, 0x40, 0x1C, 0xC0, 0xB2, 0xA0, 0x70, + 0x31, 0x68, 0x91, 0xF8, 0xC8, 0x10, 0x01, 0xF0, 0x0F, 0x01, 0x81, 0x42, + 0x04, 0xD2, 0x01, 0x20, 0x20, 0x70, 0xA5, 0x70, 0x01, 0x20, 0x70, 0xBD, + 0x00, 0x20, 0x70, 0xBD, 0xCC, 0x49, 0x00, 0x22, 0x8A, 0x70, 0x08, 0x78, + 0x01, 0x28, 0x0C, 0xD1, 0xC8, 0x78, 0xC8, 0x4B, 0x40, 0x1C, 0xC0, 0xB2, + 0xC8, 0x70, 0x1B, 0x68, 0x93, 0xF8, 0xC8, 0x30, 0xB0, 0xEB, 0x13, 0x1F, + 0x03, 0xD9, 0x0A, 0x70, 0xCA, 0x70, 0x01, 0x20, 0x70, 0x47, 0x00, 0x20, + 0x70, 0x47, 0x2D, 0xE9, 0xF0, 0x4F, 0x0F, 0x46, 0xA3, 0xB0, 0x00, 0x21, + 0xBD, 0x4A, 0x88, 0x46, 0x21, 0x91, 0x11, 0x68, 0x4F, 0xF0, 0x01, 0x09, + 0x91, 0xF8, 0xB0, 0x30, 0x5B, 0x07, 0x55, 0xD5, 0xBB, 0x4B, 0x1B, 0x78, + 0xA3, 0xBB, 0xB1, 0xF8, 0xB5, 0x20, 0xFB, 0x6A, 0x93, 0x42, 0x4D, 0xDA, + 0xD7, 0xF8, 0x0A, 0x10, 0x20, 0x91, 0x01, 0x46, 0x80, 0x22, 0x68, 0x46, + 0x0A, 0xF0, 0xE5, 0xF8, 0x3A, 0x46, 0x20, 0xA9, 0x68, 0x46, 0x02, 0xF0, + 0xBE, 0xFE, 0x00, 0x26, 0x35, 0x46, 0x9D, 0xF8, 0x82, 0x40, 0x23, 0xE0, + 0xE1, 0xB2, 0x38, 0x69, 0x0B, 0xF0, 0x96, 0xFF, 0x9D, 0xF8, 0x80, 0x10, + 0xEA, 0x46, 0xDF, 0xF8, 0xA8, 0xB2, 0x9D, 0xF8, 0x81, 0xC0, 0x14, 0xE0, + 0x5A, 0xF8, 0x24, 0x20, 0x09, 0xFA, 0x01, 0xF3, 0x1A, 0x42, 0x0D, 0xD0, + 0x30, 0xF9, 0x11, 0x20, 0x00, 0x2A, 0x08, 0xDB, 0x16, 0x44, 0x5B, 0xF8, + 0x24, 0x20, 0x1A, 0x42, 0x04, 0xD0, 0x4F, 0xF0, 0x01, 0x08, 0x01, 0xE0, + 0x1C, 0xE0, 0x15, 0x44, 0x49, 0x1C, 0x8C, 0x45, 0xE8, 0xDA, 0x64, 0x1C, + 0x9D, 0xF8, 0x83, 0x00, 0xA0, 0x42, 0xD7, 0xDA, 0x0D, 0xB9, 0x4F, 0xF0, + 0xFF, 0x35, 0x64, 0x20, 0x46, 0x43, 0x95, 0x49, 0x68, 0x42, 0x96, 0xFB, + 0xF0, 0xF0, 0x09, 0x68, 0xB1, 0xF8, 0xB3, 0x10, 0x81, 0x42, 0x11, 0xDD, + 0x91, 0x49, 0x01, 0x20, 0x21, 0x90, 0x81, 0xF8, 0x05, 0x80, 0x0B, 0xE0, + 0xB1, 0xF8, 0xB5, 0x10, 0xF8, 0x6A, 0x88, 0x42, 0x03, 0xDB, 0x8C, 0x48, + 0x00, 0x21, 0x41, 0x71, 0x02, 0xE0, 0x8A, 0x49, 0x81, 0xF8, 0x05, 0x90, + 0x21, 0x98, 0x23, 0xB0, 0xBD, 0xE8, 0xF0, 0x8F, 0x2D, 0xE9, 0xF0, 0x43, + 0x4F, 0xF0, 0x00, 0x0C, 0x8A, 0x78, 0x87, 0x4E, 0x4F, 0xF0, 0x01, 0x09, + 0x1E, 0xE0, 0x0B, 0x78, 0x09, 0xFA, 0x02, 0xF7, 0x16, 0xE0, 0x50, 0xF8, + 0x22, 0x40, 0x09, 0xFA, 0x03, 0xF5, 0x2C, 0x42, 0x0F, 0xD0, 0xD6, 0xF8, + 0x00, 0x80, 0x18, 0xEA, 0x07, 0x0F, 0x07, 0xD0, 0xD6, 0xF8, 0x04, 0x80, + 0x18, 0xEA, 0x05, 0x0F, 0x02, 0xD0, 0x4F, 0xF0, 0x01, 0x0C, 0x02, 0xE0, + 0xAC, 0x43, 0x40, 0xF8, 0x22, 0x40, 0x5B, 0x1C, 0x4C, 0x78, 0x9C, 0x42, + 0xE5, 0xDA, 0x52, 0x1C, 0xCB, 0x78, 0x93, 0x42, 0xDD, 0xDA, 0x60, 0x46, + 0xBD, 0xE8, 0xF0, 0x83, 0xF0, 0xB5, 0x82, 0x78, 0x01, 0x25, 0x6F, 0x4F, + 0xDF, 0xF8, 0xB4, 0xC1, 0x90, 0xF8, 0x03, 0xE0, 0x0E, 0xE0, 0x01, 0x78, + 0x46, 0x78, 0x08, 0xE0, 0x57, 0xF8, 0x22, 0x40, 0x05, 0xFA, 0x01, 0xF3, + 0x1C, 0x42, 0x01, 0xD0, 0x8C, 0xF8, 0x05, 0x50, 0x49, 0x1C, 0x8E, 0x42, + 0xF4, 0xDA, 0x52, 0x1C, 0x96, 0x45, 0xEE, 0xDA, 0xF0, 0xBD, 0x2D, 0xE9, + 0xFC, 0x47, 0x82, 0x46, 0x10, 0x68, 0x00, 0x90, 0x50, 0x68, 0x01, 0x90, + 0x89, 0x46, 0x68, 0x46, 0xFF, 0xF7, 0xD6, 0xFC, 0x68, 0x46, 0xFF, 0xF7, + 0xD3, 0xFC, 0x01, 0xA8, 0xFF, 0xF7, 0xD0, 0xFC, 0x01, 0xA8, 0xFF, 0xF7, + 0xCD, 0xFC, 0x00, 0x24, 0x01, 0x26, 0xDF, 0xF8, 0x6C, 0x81, 0x21, 0xE0, + 0xE1, 0xB2, 0x50, 0x46, 0x0B, 0xF0, 0xE8, 0xFE, 0x05, 0x46, 0xE1, 0xB2, + 0x48, 0x46, 0x0B, 0xF0, 0xE3, 0xFE, 0x03, 0x46, 0x00, 0x21, 0x06, 0xFA, + 0x04, 0xF0, 0x54, 0x4F, 0x0E, 0xE0, 0x00, 0x9A, 0x10, 0x42, 0x06, 0xD0, + 0xDD, 0xF8, 0x04, 0xC0, 0x06, 0xFA, 0x01, 0xF2, 0x12, 0xEA, 0x0C, 0x0F, + 0x03, 0xD1, 0x35, 0xF8, 0x11, 0x20, 0x23, 0xF8, 0x11, 0x20, 0x49, 0x1C, + 0x3A, 0x78, 0x91, 0x42, 0xED, 0xDB, 0x64, 0x1C, 0x98, 0xF8, 0x00, 0x00, + 0x84, 0x42, 0xD9, 0xDB, 0xBD, 0xE8, 0xFC, 0x87, 0x70, 0xB5, 0x47, 0x49, + 0x00, 0x20, 0x45, 0x4A, 0x09, 0x68, 0x46, 0x4C, 0x42, 0x4D, 0x07, 0xE0, + 0x13, 0x78, 0x34, 0xF8, 0x10, 0x60, 0x43, 0x43, 0x40, 0x1C, 0x21, 0xF8, + 0x13, 0x60, 0xC0, 0xB2, 0x2B, 0x78, 0x98, 0x42, 0xF4, 0xD3, 0x00, 0x20, + 0x3F, 0x4B, 0x05, 0xE0, 0x33, 0xF8, 0x10, 0x40, 0x21, 0xF8, 0x10, 0x40, + 0x40, 0x1C, 0xC0, 0xB2, 0x14, 0x78, 0xA0, 0x42, 0xF6, 0xD3, 0x70, 0xBD, + 0x3A, 0x48, 0x03, 0x21, 0x01, 0x80, 0x41, 0x88, 0x49, 0x1C, 0x41, 0x80, + 0x38, 0x49, 0x0A, 0x78, 0x01, 0x79, 0x62, 0xF3, 0x03, 0x01, 0x2C, 0x4A, + 0x13, 0x78, 0x63, 0xF3, 0x45, 0x11, 0x13, 0x79, 0x82, 0x7A, 0x63, 0xF3, + 0x00, 0x02, 0x82, 0x72, 0x32, 0x4A, 0x12, 0x78, 0x62, 0xF3, 0x04, 0x11, + 0x01, 0x71, 0x31, 0x49, 0x09, 0x7E, 0x81, 0x73, 0x30, 0x49, 0x09, 0x7E, + 0xC1, 0x73, 0x30, 0x49, 0x0A, 0x78, 0x82, 0x74, 0x4A, 0x78, 0x02, 0x75, + 0x8A, 0x78, 0x42, 0x75, 0xCA, 0x78, 0x82, 0x75, 0x09, 0x79, 0xC1, 0x75, + 0x2B, 0x49, 0x09, 0x78, 0x41, 0x71, 0x70, 0x47, 0x2D, 0xE9, 0xF1, 0x4F, + 0x18, 0x48, 0x00, 0x27, 0x01, 0x26, 0x00, 0x68, 0x8E, 0xB0, 0x3D, 0x46, + 0x30, 0xF9, 0xC3, 0xAF, 0x3B, 0x46, 0x90, 0xF8, 0x02, 0xB0, 0x10, 0xF8, + 0x13, 0x0C, 0x80, 0x07, 0x00, 0xD5, 0x01, 0x23, 0x1D, 0x4C, 0xDF, 0xF8, + 0x78, 0x80, 0x21, 0x7E, 0x98, 0xF8, 0x18, 0x00, 0xC1, 0x42, 0x04, 0xD1, + 0x10, 0x4A, 0x15, 0x49, 0x13, 0x48, 0xFE, 0xF7, 0xF6, 0xFE, 0x20, 0x7E, + 0x98, 0xF8, 0x18, 0x10, 0x00, 0xFB, 0x01, 0xF2, 0xD4, 0xB2, 0x06, 0xF0, + 0x3B, 0xFE, 0x00, 0xF0, 0xFF, 0x08, 0x61, 0x00, 0x68, 0x46, 0x09, 0xF0, + 0xE6, 0xFF, 0x12, 0x49, 0x00, 0x20, 0x4F, 0xF0, 0x01, 0x09, 0x08, 0x70, + 0xDC, 0xB3, 0x21, 0xE0, 0x50, 0x24, 0x10, 0x00, 0x6D, 0x23, 0x10, 0x00, + 0xB0, 0x48, 0x10, 0x00, 0xB8, 0x23, 0x10, 0x00, 0xA4, 0x48, 0x10, 0x00, + 0x00, 0x24, 0x10, 0x00, 0x01, 0x24, 0x10, 0x00, 0x10, 0x24, 0x10, 0x00, + 0x80, 0x0A, 0x01, 0x20, 0xBC, 0x0A, 0x01, 0x20, 0x8A, 0x25, 0x10, 0x00, + 0x55, 0x23, 0x10, 0x00, 0x57, 0x23, 0x10, 0x00, 0xDD, 0x46, 0x10, 0x00, + 0xF6, 0x46, 0x10, 0x00, 0xD4, 0x46, 0x10, 0x00, 0x08, 0x24, 0x10, 0x00, + 0x19, 0x2C, 0x20, 0xD2, 0x1B, 0x48, 0x19, 0x4B, 0x19, 0x4A, 0x51, 0x46, + 0x00, 0x68, 0xFE, 0xF7, 0x3D, 0xFF, 0x19, 0x49, 0x6B, 0x46, 0x5A, 0x46, + 0x08, 0x60, 0x18, 0x49, 0x18, 0x48, 0xFE, 0xF7, 0x7C, 0xFF, 0x05, 0x46, + 0xA8, 0x45, 0x05, 0xD8, 0xA5, 0x42, 0x03, 0xD8, 0x01, 0x2C, 0x01, 0xD9, + 0x02, 0x27, 0x0F, 0xE0, 0x00, 0x26, 0x02, 0x27, 0x12, 0x4B, 0x6A, 0x46, + 0x0F, 0x49, 0x10, 0x48, 0xFF, 0xF7, 0x86, 0xFD, 0x06, 0xE0, 0x0E, 0x99, + 0x2A, 0x20, 0x00, 0x26, 0x81, 0xF8, 0x00, 0x90, 0x0D, 0x49, 0x08, 0x70, + 0x0D, 0x48, 0x05, 0x74, 0x41, 0x7C, 0x66, 0xF3, 0x00, 0x01, 0x41, 0x74, + 0x0B, 0x49, 0x38, 0x46, 0x81, 0xF8, 0x00, 0x90, 0x0F, 0xB0, 0x99, 0xE6, + 0xA4, 0x48, 0x10, 0x00, 0xD8, 0x23, 0x10, 0x00, 0x5C, 0x23, 0x10, 0x00, + 0xC0, 0x23, 0x10, 0x00, 0xF6, 0x46, 0x10, 0x00, 0xDD, 0x46, 0x10, 0x00, + 0xD4, 0x46, 0x10, 0x00, 0x59, 0x23, 0x10, 0x00, 0x8A, 0x25, 0x10, 0x00, + 0x40, 0x23, 0x10, 0x00, 0x2D, 0xE9, 0xFF, 0x5F, 0x1C, 0x46, 0xDD, 0xE9, + 0x0E, 0x36, 0xCD, 0xE9, 0x02, 0x03, 0x0D, 0x46, 0x91, 0x46, 0xB2, 0xE0, + 0x47, 0xF6, 0xFF, 0x72, 0xD3, 0x43, 0x00, 0x27, 0x31, 0x46, 0x0B, 0xE0, + 0x39, 0xF9, 0x11, 0x00, 0x35, 0xF9, 0x11, 0xC0, 0xA0, 0xEB, 0x0C, 0x00, + 0x90, 0x42, 0x00, 0xDA, 0x02, 0x46, 0x98, 0x42, 0x00, 0xDD, 0x03, 0x46, + 0x49, 0x1E, 0xF1, 0xD2, 0x00, 0x2B, 0x01, 0xDA, 0x1F, 0x46, 0x02, 0xE0, + 0x00, 0x2A, 0x00, 0xDD, 0x17, 0x46, 0x4F, 0xF0, 0x00, 0x08, 0x30, 0x46, + 0x0E, 0xE0, 0x39, 0xF9, 0x10, 0x10, 0x35, 0xF9, 0x10, 0x20, 0x89, 0x1A, + 0xC9, 0x1B, 0xA1, 0x42, 0x06, 0xDA, 0x21, 0x44, 0x00, 0x29, 0x03, 0xDD, + 0x01, 0x21, 0x81, 0x40, 0x41, 0xEA, 0x08, 0x08, 0x40, 0x1E, 0xEE, 0xD2, + 0xDF, 0xF8, 0xB8, 0xA7, 0xDA, 0xF8, 0x00, 0x00, 0x90, 0xF8, 0x31, 0x11, + 0x09, 0x06, 0x0F, 0xD5, 0x00, 0x96, 0xB0, 0xF8, 0x61, 0x21, 0x49, 0x46, + 0x13, 0x46, 0x28, 0x46, 0x07, 0xF0, 0x1F, 0xF8, 0xDA, 0xF8, 0x00, 0x10, + 0x91, 0xF8, 0x63, 0x11, 0x21, 0xB1, 0x07, 0xF0, 0x41, 0xF8, 0x01, 0xE0, + 0x4F, 0xF0, 0xFF, 0x30, 0x08, 0xEA, 0x00, 0x01, 0x01, 0x91, 0x04, 0x21, + 0x01, 0xA8, 0x0B, 0xF0, 0xD1, 0xFF, 0xDA, 0xF8, 0x00, 0x10, 0x91, 0xF8, + 0x7C, 0x11, 0x88, 0x42, 0x01, 0xDA, 0xCD, 0xF8, 0x04, 0x80, 0x00, 0x21, + 0x0A, 0x46, 0x0B, 0x46, 0x8B, 0x46, 0x8A, 0x46, 0x30, 0x46, 0xDD, 0xF8, + 0x04, 0xE0, 0x16, 0xE0, 0x4F, 0xF0, 0x01, 0x0C, 0x0C, 0xFA, 0x00, 0xFC, + 0x1C, 0xEA, 0x0E, 0x0F, 0x0F, 0xD0, 0x39, 0xF9, 0x10, 0xC0, 0x35, 0xF9, + 0x10, 0x80, 0x00, 0xFB, 0x00, 0x22, 0xAC, 0xEB, 0x08, 0x0C, 0xAC, 0xEB, + 0x07, 0x0C, 0x00, 0xFB, 0x0C, 0xBB, 0x01, 0x44, 0x63, 0x44, 0x0A, 0xF1, + 0x01, 0x0A, 0x40, 0x1E, 0xE6, 0xD2, 0x02, 0xFB, 0x0A, 0xF0, 0x01, 0xFB, + 0x11, 0x0C, 0x0B, 0xFB, 0x0A, 0xF0, 0x01, 0xFB, 0x13, 0x08, 0x5A, 0x43, + 0x0B, 0xFB, 0x11, 0x20, 0xBC, 0xF1, 0x00, 0x0F, 0x05, 0xD0, 0x90, 0xFB, + 0xFC, 0xF2, 0x31, 0x46, 0xC4, 0xF1, 0x00, 0x0A, 0x19, 0xE0, 0x00, 0x22, + 0xF9, 0xE7, 0xBC, 0xF1, 0x00, 0x0F, 0x08, 0xD0, 0x08, 0xFB, 0x01, 0xF0, + 0x90, 0xFB, 0xFC, 0xF0, 0x10, 0x44, 0xA0, 0x42, 0x03, 0xDD, 0x20, 0x46, + 0x04, 0xE0, 0x00, 0x20, 0xF9, 0xE7, 0xE0, 0x42, 0x00, 0xD5, 0x50, 0x46, + 0x35, 0xF8, 0x11, 0x30, 0x38, 0x44, 0x18, 0x44, 0x02, 0x9B, 0x23, 0xF8, + 0x11, 0x00, 0x49, 0x1E, 0xE5, 0xD2, 0x02, 0x98, 0x05, 0xEB, 0x46, 0x05, + 0x00, 0xEB, 0x46, 0x00, 0x09, 0xEB, 0x46, 0x09, 0x02, 0x90, 0x03, 0x98, + 0x40, 0x1E, 0x03, 0x90, 0x40, 0x1C, 0x7F, 0xF4, 0x47, 0xAF, 0xBD, 0xE8, + 0xFF, 0x9F, 0x2D, 0xE9, 0xFF, 0x4F, 0x9A, 0x46, 0xDD, 0xE9, 0x0D, 0x97, + 0x86, 0x46, 0x58, 0xE0, 0x01, 0x99, 0x09, 0xFB, 0x07, 0xF0, 0x01, 0xEB, + 0x40, 0x06, 0x02, 0x99, 0x47, 0xF6, 0xFF, 0x75, 0x01, 0xEB, 0x40, 0x03, + 0x01, 0x24, 0x0E, 0xEB, 0x40, 0x0B, 0x6F, 0xEA, 0x05, 0x0C, 0x22, 0x46, + 0x39, 0x46, 0x14, 0xE0, 0x33, 0xF8, 0x11, 0x00, 0x36, 0xF8, 0x11, 0x80, + 0xA0, 0xEB, 0x08, 0x00, 0x00, 0xB2, 0xA8, 0x42, 0x00, 0xDA, 0x05, 0x46, + 0x60, 0x45, 0x00, 0xDD, 0x84, 0x46, 0x00, 0x28, 0x02, 0xDD, 0x4F, 0xF0, + 0x00, 0x02, 0x02, 0xE0, 0x01, 0xDA, 0x4F, 0xF0, 0x00, 0x04, 0x49, 0x1E, + 0xE8, 0xD2, 0x14, 0xB1, 0x0A, 0xB1, 0x00, 0x20, 0x07, 0xE0, 0x54, 0xEA, + 0x02, 0x00, 0x04, 0xD0, 0x14, 0xB9, 0x0A, 0xB1, 0x60, 0x46, 0x00, 0xE0, + 0x28, 0x46, 0x00, 0x21, 0x0C, 0x46, 0x3A, 0x46, 0xCA, 0xF1, 0x00, 0x08, + 0x0D, 0xE0, 0x33, 0xF8, 0x12, 0x50, 0x36, 0xF8, 0x12, 0xC0, 0xA5, 0xEB, + 0x0C, 0x05, 0x2D, 0x1A, 0x2D, 0xB2, 0x55, 0x45, 0x03, 0xDA, 0x45, 0x45, + 0x01, 0xDD, 0x29, 0x44, 0x64, 0x1C, 0x52, 0x1E, 0xEF, 0xD2, 0x04, 0xB9, + 0x01, 0x24, 0x91, 0xFB, 0xF4, 0xF1, 0x0A, 0x18, 0x3B, 0x46, 0x04, 0xE0, + 0x36, 0xF8, 0x13, 0x00, 0x10, 0x44, 0x2B, 0xF8, 0x13, 0x00, 0x5B, 0x1E, + 0xF8, 0xD2, 0xB9, 0xF1, 0x01, 0x09, 0xA3, 0xD2, 0xBD, 0xE8, 0xFF, 0x8F, + 0xF0, 0xB5, 0x1E, 0x46, 0x1D, 0xE0, 0x00, 0x24, 0x94, 0x46, 0x09, 0xE0, + 0x0C, 0xFB, 0x03, 0x65, 0x31, 0xF9, 0x15, 0x50, 0x00, 0x2D, 0x14, 0xDD, + 0x0C, 0xB1, 0xA5, 0x42, 0x00, 0xDA, 0x2C, 0x46, 0xBC, 0xF1, 0x01, 0x0C, + 0xF2, 0xD2, 0x00, 0x2C, 0x0B, 0xDD, 0x17, 0x46, 0x07, 0xE0, 0x07, 0xFB, + 0x03, 0x65, 0x31, 0xF8, 0x15, 0xC0, 0xAC, 0xEB, 0x04, 0x0C, 0x20, 0xF8, + 0x15, 0xC0, 0x7F, 0x1E, 0xF5, 0xD2, 0x76, 0x1E, 0xDF, 0xD2, 0xF0, 0xBD, + 0x2D, 0xE9, 0xF0, 0x47, 0x8A, 0x46, 0x81, 0x46, 0x1C, 0x46, 0xDD, 0xF8, + 0x20, 0xC0, 0x24, 0xE0, 0x64, 0x2A, 0x05, 0xDD, 0xC2, 0xF1, 0x64, 0x00, + 0x60, 0x43, 0x90, 0xFB, 0xF3, 0xF1, 0x06, 0xE0, 0xA2, 0xF1, 0x64, 0x00, + 0x00, 0xFB, 0x04, 0xF1, 0x91, 0xFB, 0xF3, 0xF1, 0x41, 0x1A, 0x04, 0xFB, + 0x0C, 0xF0, 0x0A, 0xEB, 0x40, 0x07, 0x09, 0xEB, 0x40, 0x05, 0x64, 0x31, + 0x60, 0x46, 0x4F, 0xF0, 0x64, 0x08, 0x08, 0xE0, 0x37, 0xF9, 0x10, 0x60, + 0x00, 0x2E, 0x04, 0xDD, 0x4E, 0x43, 0x96, 0xFB, 0xF8, 0xF6, 0x25, 0xF8, + 0x10, 0x60, 0x40, 0x1E, 0xF4, 0xD2, 0x64, 0x1E, 0xD8, 0xD2, 0xBD, 0xE8, + 0xF0, 0x87, 0x2D, 0xE9, 0xF0, 0x43, 0x99, 0x46, 0x07, 0x9E, 0x33, 0x46, + 0x22, 0xE0, 0x64, 0x2A, 0x05, 0xDD, 0xC2, 0xF1, 0x64, 0x04, 0x5C, 0x43, + 0x94, 0xFB, 0xF6, 0xF7, 0x06, 0xE0, 0xA2, 0xF1, 0x64, 0x04, 0x04, 0xFB, + 0x03, 0xF5, 0x95, 0xFB, 0xF6, 0xF5, 0x67, 0x1B, 0x64, 0x37, 0x4C, 0x46, + 0x4F, 0xF0, 0x64, 0x08, 0x0C, 0xE0, 0x04, 0xFB, 0x06, 0x35, 0x31, 0xF9, + 0x15, 0xC0, 0xBC, 0xF1, 0x00, 0x0F, 0x05, 0xDD, 0x0C, 0xFB, 0x07, 0xFC, + 0x9C, 0xFB, 0xF8, 0xFC, 0x20, 0xF8, 0x15, 0xC0, 0x64, 0x1E, 0xF0, 0xD2, + 0x5B, 0x1E, 0xDA, 0xD2, 0xBD, 0xE8, 0xF0, 0x83, 0x2D, 0xE9, 0xF0, 0x47, + 0xA3, 0xF1, 0x01, 0x08, 0x08, 0x9D, 0x8A, 0x46, 0x81, 0x46, 0x56, 0x19, + 0x08, 0xFB, 0x05, 0xF8, 0x2F, 0x46, 0x29, 0xE0, 0x08, 0xEB, 0x07, 0x00, + 0x0A, 0xEB, 0x40, 0x01, 0x09, 0xEB, 0x40, 0x00, 0x1C, 0x46, 0x1F, 0xE0, + 0x32, 0x78, 0x64, 0x2A, 0x05, 0xD9, 0xC2, 0xF1, 0x64, 0x02, 0x62, 0x43, + 0x92, 0xFB, 0xF3, 0xF2, 0x06, 0xE0, 0x64, 0x3A, 0x02, 0xFB, 0x04, 0xFC, + 0x9C, 0xFB, 0xF3, 0xFC, 0xA2, 0xEB, 0x0C, 0x02, 0xB1, 0xF9, 0x00, 0xC0, + 0x64, 0x32, 0xBC, 0xF1, 0x00, 0x0F, 0x05, 0xDD, 0x0C, 0xFB, 0x02, 0xFC, + 0x64, 0x22, 0x9C, 0xFB, 0xF2, 0xF2, 0x02, 0x80, 0xA1, 0xEB, 0x45, 0x01, + 0xA0, 0xEB, 0x45, 0x00, 0x64, 0x1E, 0xDD, 0xD2, 0x76, 0x1E, 0x7F, 0x1E, + 0xD2, 0xD2, 0x96, 0xE7, 0xF0, 0xB5, 0x5C, 0x1E, 0x05, 0x9D, 0x1A, 0x44, + 0x6C, 0x43, 0x01, 0xEB, 0x44, 0x01, 0x00, 0xEB, 0x44, 0x06, 0x52, 0x1E, + 0x5B, 0x1E, 0x22, 0xD3, 0x2C, 0x46, 0x19, 0xE0, 0x10, 0x78, 0x64, 0x28, + 0x05, 0xD9, 0xC0, 0xF1, 0x64, 0x00, 0x60, 0x43, 0x90, 0xFB, 0xF5, 0xF0, + 0x05, 0xE0, 0x64, 0x38, 0x00, 0xFB, 0x04, 0xF7, 0x97, 0xFB, 0xF5, 0xF7, + 0xC0, 0x1B, 0x31, 0xF9, 0x14, 0x70, 0x64, 0x30, 0x00, 0x2F, 0x05, 0xDD, + 0x47, 0x43, 0x64, 0x20, 0x97, 0xFB, 0xF0, 0xF0, 0x26, 0xF8, 0x14, 0x00, + 0x64, 0x1E, 0xE3, 0xD2, 0xA1, 0xEB, 0x45, 0x01, 0xA6, 0xEB, 0x45, 0x06, + 0xD9, 0xE7, 0xF0, 0xBD, 0x2D, 0xE9, 0xFC, 0x47, 0xFF, 0x4F, 0x91, 0x46, + 0x00, 0x26, 0x39, 0x68, 0xB1, 0xF8, 0x3E, 0xA1, 0xFD, 0x4D, 0x4F, 0xF0, + 0x01, 0x08, 0x2C, 0x46, 0x22, 0x46, 0xFC, 0x49, 0xCD, 0xE9, 0x00, 0x28, + 0x0A, 0x78, 0xFB, 0x49, 0x2B, 0x46, 0x09, 0x78, 0x06, 0xF0, 0x1D, 0xFC, + 0x20, 0x69, 0x29, 0x68, 0x6A, 0x68, 0x40, 0x1A, 0x61, 0x69, 0x89, 0x1A, + 0x08, 0x44, 0xA1, 0x69, 0xAA, 0x68, 0x89, 0x1A, 0x08, 0x44, 0xE1, 0x69, + 0xEA, 0x68, 0x89, 0x1A, 0x08, 0x44, 0x50, 0x45, 0x00, 0xDD, 0x01, 0x26, + 0xF0, 0x4A, 0x00, 0x23, 0x10, 0x78, 0x70, 0xB1, 0x90, 0x68, 0x40, 0x1C, + 0x90, 0x60, 0x39, 0x68, 0x91, 0xF8, 0x44, 0x11, 0x81, 0x42, 0x03, 0xDA, + 0x93, 0x60, 0x13, 0x70, 0x89, 0xF8, 0x00, 0x80, 0x30, 0x46, 0xBD, 0xE8, + 0xFC, 0x87, 0xC6, 0xB1, 0x90, 0x68, 0x40, 0x1C, 0x90, 0x60, 0x39, 0x68, + 0x91, 0xF8, 0x43, 0x41, 0x84, 0x42, 0x09, 0xDA, 0x93, 0x60, 0x82, 0xF8, + 0x00, 0x80, 0x91, 0xF8, 0x44, 0x11, 0x40, 0x46, 0x11, 0xB9, 0x13, 0x70, + 0x89, 0xF8, 0x00, 0x00, 0x38, 0x68, 0x90, 0xF8, 0xA8, 0x13, 0x07, 0x20, + 0x05, 0xF0, 0x9B, 0xF9, 0xE2, 0xE7, 0x93, 0x60, 0xE0, 0xE7, 0x2D, 0xE9, + 0xF0, 0x43, 0x00, 0x25, 0xDD, 0xE9, 0x07, 0xC9, 0x2C, 0x46, 0x0D, 0xE0, + 0x31, 0xF9, 0x12, 0x70, 0x30, 0xF9, 0x12, 0x60, 0x07, 0xEB, 0x03, 0x08, + 0x46, 0x45, 0x01, 0xDD, 0x6D, 0x1C, 0x03, 0xE0, 0xFF, 0x1A, 0xBE, 0x42, + 0x00, 0xDA, 0x64, 0x1C, 0x52, 0x1E, 0xEF, 0xD2, 0x65, 0x45, 0x01, 0xD8, + 0x64, 0x45, 0x02, 0xD9, 0x01, 0x21, 0x89, 0xF8, 0x00, 0x10, 0x1D, 0xE7, + 0xFE, 0xB5, 0x00, 0x25, 0x8D, 0xF8, 0x08, 0x50, 0xDF, 0xF8, 0x20, 0xC3, + 0xDF, 0xF8, 0x20, 0xE3, 0xC1, 0x4E, 0x9C, 0xF8, 0x00, 0xC0, 0x9E, 0xF8, + 0x00, 0xE0, 0x34, 0x68, 0x4C, 0xEA, 0x0E, 0x0C, 0xDF, 0xF8, 0x10, 0xE3, + 0x17, 0x46, 0x94, 0xF8, 0x45, 0x21, 0xB4, 0xF9, 0x46, 0x31, 0x9E, 0xF8, + 0x00, 0xE0, 0x52, 0x00, 0x94, 0xF8, 0x48, 0x41, 0x5C, 0xEA, 0x0E, 0x0C, + 0x08, 0xD1, 0x0D, 0xF1, 0x08, 0x0C, 0xCD, 0xE9, 0x00, 0x2C, 0xBC, 0x4A, + 0xB2, 0xF9, 0x00, 0x20, 0xFF, 0xF7, 0xB9, 0xFF, 0xB5, 0x49, 0x01, 0x22, + 0x48, 0x78, 0x68, 0xB1, 0xC8, 0x68, 0x40, 0x1C, 0xC8, 0x60, 0x33, 0x68, + 0x93, 0xF8, 0x49, 0x31, 0x83, 0x42, 0x02, 0xDA, 0xCD, 0x60, 0x4D, 0x70, + 0x3A, 0x70, 0x9D, 0xF8, 0x08, 0x00, 0xFE, 0xBD, 0x9D, 0xF8, 0x08, 0x00, + 0x01, 0x28, 0x01, 0xD0, 0xCD, 0x60, 0xF6, 0xE7, 0xC8, 0x68, 0x40, 0x1C, + 0xC8, 0x60, 0xA0, 0x42, 0x07, 0xDD, 0xCD, 0x60, 0x4A, 0x70, 0x30, 0x68, + 0x90, 0xF8, 0x49, 0x01, 0x08, 0xB9, 0x4D, 0x70, 0x3A, 0x70, 0x30, 0x68, + 0x90, 0xF8, 0xA8, 0x13, 0x07, 0x20, 0x05, 0xF0, 0x26, 0xF9, 0xE2, 0xE7, + 0x2D, 0xE9, 0xF0, 0x5F, 0x9A, 0x48, 0xA3, 0x4B, 0x9F, 0x4C, 0x01, 0x68, + 0x1B, 0x68, 0x25, 0x78, 0xB1, 0xF9, 0x52, 0x21, 0xB1, 0xF9, 0xD2, 0xC1, + 0xDE, 0x07, 0x02, 0xD0, 0x0D, 0xB9, 0xB1, 0xF9, 0x0A, 0x22, 0x9D, 0x4C, + 0x24, 0x78, 0x01, 0x2C, 0x01, 0xD1, 0xB1, 0xF9, 0x08, 0x22, 0x82, 0x46, + 0x9A, 0x48, 0xB1, 0xF9, 0xF6, 0x61, 0x04, 0x78, 0x01, 0x2C, 0x4A, 0xD0, + 0x02, 0x2C, 0x04, 0xD3, 0xB1, 0xF8, 0x56, 0x01, 0x08, 0xB1, 0xB1, 0xF9, + 0x56, 0x21, 0x18, 0x07, 0x14, 0xD5, 0x91, 0xF8, 0xB5, 0x02, 0x64, 0x27, + 0x00, 0xFB, 0x02, 0xF8, 0x98, 0xFB, 0xF7, 0xF8, 0x42, 0x44, 0x00, 0xFB, + 0x0C, 0xF8, 0x70, 0x43, 0x98, 0xFB, 0xF7, 0xF8, 0x90, 0xFB, 0xF7, 0xF0, + 0xC4, 0x44, 0x30, 0x44, 0x12, 0xB2, 0x0F, 0xFA, 0x8C, 0xFC, 0x06, 0xB2, + 0x89, 0x48, 0x8A, 0x4F, 0xDF, 0xF8, 0x28, 0x92, 0x02, 0x80, 0xA7, 0xF8, + 0x00, 0xC0, 0xA9, 0xF8, 0x00, 0x60, 0xD8, 0x07, 0x00, 0xD0, 0x75, 0xB3, + 0x91, 0xF8, 0x54, 0x01, 0x91, 0xF8, 0xD4, 0x81, 0xD3, 0x46, 0xAC, 0xEB, + 0x08, 0x0A, 0x91, 0xF8, 0xF8, 0xC1, 0x10, 0x1A, 0xA6, 0xEB, 0x0C, 0x08, + 0x80, 0x4E, 0x00, 0xB2, 0xDF, 0xF8, 0x04, 0xC2, 0x30, 0x80, 0x7F, 0x4E, + 0xA6, 0xF8, 0x00, 0xA0, 0xAC, 0xF8, 0x00, 0x80, 0x5F, 0xEA, 0x83, 0x78, + 0x01, 0xD5, 0x02, 0x2C, 0x01, 0xD3, 0x3A, 0x80, 0x30, 0x80, 0x13, 0xF0, + 0x05, 0x0F, 0x12, 0xD0, 0x14, 0xE0, 0x91, 0xF8, 0x55, 0x01, 0x10, 0x44, + 0x02, 0xB2, 0x91, 0xF8, 0xD5, 0x01, 0x60, 0x44, 0x0F, 0xFA, 0x80, 0xFC, + 0x91, 0xF8, 0xF9, 0x01, 0x30, 0x44, 0x06, 0xB2, 0xAD, 0xE7, 0xFF, 0xE7, + 0x91, 0xF8, 0x0C, 0x02, 0xCE, 0xE7, 0x5F, 0xEA, 0xC3, 0x58, 0x01, 0xD5, + 0x02, 0x2C, 0x03, 0xD3, 0xA9, 0xF8, 0x00, 0x20, 0xAC, 0xF8, 0x00, 0x00, + 0xDF, 0xF8, 0xAC, 0xA1, 0x6B, 0x4C, 0x5F, 0xEA, 0x83, 0x68, 0x01, 0xD5, + 0x1B, 0x07, 0x03, 0xD5, 0xAA, 0xF8, 0x00, 0x20, 0x20, 0x80, 0x06, 0xE0, + 0x31, 0xF8, 0xD6, 0x3F, 0xAA, 0xF8, 0x00, 0x30, 0x89, 0x78, 0x59, 0x1A, + 0x21, 0x80, 0x01, 0x2D, 0x03, 0xD0, 0x63, 0x49, 0x09, 0x78, 0x01, 0x29, + 0x05, 0xD1, 0x3A, 0x80, 0x30, 0x80, 0xA9, 0xF8, 0x00, 0x20, 0xAC, 0xF8, + 0x00, 0x00, 0xBC, 0xF9, 0x00, 0x20, 0xB6, 0xF9, 0x00, 0x10, 0x06, 0xF0, + 0x2E, 0xFA, 0x5C, 0x4D, 0x00, 0xB2, 0x28, 0x80, 0xDB, 0xF8, 0x00, 0x10, + 0x91, 0xF8, 0xD4, 0x20, 0x52, 0x07, 0x05, 0xD5, 0xB1, 0xF8, 0xEC, 0x10, + 0x11, 0xB1, 0x06, 0xF0, 0x27, 0xFA, 0x28, 0x80, 0xB4, 0xF9, 0x00, 0x10, + 0xB5, 0xF9, 0x00, 0x00, 0x06, 0xF0, 0x20, 0xFA, 0x28, 0x80, 0xBD, 0xE8, + 0xF0, 0x9F, 0x2D, 0xE9, 0xF0, 0x4F, 0xA5, 0xB0, 0x0E, 0x46, 0x07, 0x46, + 0x9A, 0x46, 0x15, 0x46, 0x00, 0x24, 0x20, 0x21, 0x1D, 0xA8, 0x09, 0xF0, + 0xC6, 0xFB, 0x24, 0x21, 0x14, 0xA8, 0x09, 0xF0, 0xC2, 0xFB, 0x28, 0x21, + 0x68, 0x46, 0x09, 0xF0, 0xBE, 0xFB, 0x28, 0x21, 0x0A, 0xA8, 0x09, 0xF0, + 0xBA, 0xFB, 0x32, 0x4A, 0x01, 0x21, 0x00, 0x20, 0x0D, 0xF1, 0x74, 0x08, + 0x13, 0x78, 0x06, 0xE0, 0x37, 0xF9, 0x10, 0x20, 0xAA, 0x42, 0x01, 0xDD, + 0x08, 0xF8, 0x00, 0x10, 0x40, 0x1C, 0x98, 0x42, 0xF6, 0xDB, 0x29, 0x4A, + 0x00, 0x20, 0x0D, 0xF1, 0x50, 0x0E, 0x12, 0x78, 0x06, 0xE0, 0x36, 0xF9, + 0x10, 0xC0, 0xAC, 0x45, 0x01, 0xDD, 0x0E, 0xF8, 0x00, 0x10, 0x40, 0x1C, + 0x90, 0x42, 0xF6, 0xDB, 0x01, 0x21, 0x00, 0x20, 0xA3, 0xF1, 0x01, 0x09, + 0xEB, 0x46, 0x14, 0xE0, 0x18, 0xF8, 0x00, 0x30, 0x7B, 0xB1, 0x08, 0xF8, + 0x00, 0x10, 0x0B, 0xEB, 0x81, 0x03, 0x37, 0xF9, 0x10, 0xC0, 0x53, 0xF8, + 0x04, 0x5D, 0x65, 0x44, 0x1D, 0x60, 0x08, 0xEB, 0x00, 0x03, 0x5B, 0x78, + 0x0B, 0xB9, 0x49, 0x1C, 0xC9, 0xB2, 0x40, 0x1C, 0xC0, 0xB2, 0x48, 0x45, + 0xE8, 0xDB, 0x01, 0x21, 0x00, 0x20, 0x0D, 0xF1, 0x28, 0x0C, 0x77, 0x46, + 0x52, 0x1E, 0x11, 0xE0, 0x3B, 0x5C, 0x6B, 0xB1, 0x39, 0x54, 0x0C, 0xEB, + 0x81, 0x03, 0x36, 0xF9, 0x10, 0x80, 0x53, 0xF8, 0x04, 0x5D, 0x45, 0x44, + 0x1D, 0x60, 0x3B, 0x18, 0x5B, 0x78, 0x0B, 0xB9, 0x49, 0x1C, 0xC9, 0xB2, + 0x40, 0x1C, 0xC0, 0xB2, 0x90, 0x42, 0xEB, 0xDB, 0x00, 0x21, 0x5D, 0x46, + 0x00, 0x20, 0x55, 0xF8, 0x21, 0x20, 0x5C, 0xF8, 0x20, 0x30, 0x2B, 0xE0, + 0x50, 0x24, 0x10, 0x00, 0x48, 0x53, 0x10, 0x00, 0x01, 0x24, 0x10, 0x00, + 0x00, 0x24, 0x10, 0x00, 0x74, 0x23, 0x10, 0x00, 0x08, 0x24, 0x10, 0x00, + 0x6D, 0x23, 0x10, 0x00, 0x06, 0x24, 0x10, 0x00, 0x0C, 0x24, 0x10, 0x00, + 0x1C, 0x24, 0x10, 0x00, 0x07, 0x24, 0x10, 0x00, 0xB8, 0x23, 0x10, 0x00, + 0xC6, 0x23, 0x10, 0x00, 0xC8, 0x23, 0x10, 0x00, 0xCA, 0x23, 0x10, 0x00, + 0xCC, 0x23, 0x10, 0x00, 0xCE, 0x23, 0x10, 0x00, 0xD0, 0x23, 0x10, 0x00, + 0xD4, 0x23, 0x10, 0x00, 0xD6, 0x23, 0x10, 0x00, 0x6E, 0x23, 0x10, 0x00, + 0xD2, 0x23, 0x10, 0x00, 0xD6, 0x18, 0x56, 0x45, 0x00, 0xDD, 0x01, 0x24, + 0x40, 0x1C, 0xC0, 0xB2, 0x0A, 0x28, 0xC8, 0xD3, 0x49, 0x1C, 0xC9, 0xB2, + 0x0A, 0x29, 0xC1, 0xD3, 0x25, 0xB0, 0x20, 0x46, 0xBD, 0xE8, 0xF0, 0x8F, + 0x70, 0xB5, 0xFE, 0x4C, 0xFE, 0x4D, 0xE2, 0x78, 0x2B, 0x68, 0x01, 0x2A, + 0x15, 0xD0, 0x33, 0xF9, 0xFA, 0x2F, 0xB3, 0xF9, 0x04, 0x30, 0xFF, 0xF7, + 0x40, 0xFF, 0x00, 0x21, 0x01, 0x28, 0x0F, 0xD0, 0xE0, 0x78, 0x01, 0x28, + 0x18, 0xD0, 0xA1, 0x80, 0xE1, 0x80, 0xF6, 0x49, 0xE2, 0x78, 0xC8, 0x7B, + 0x62, 0xF3, 0x04, 0x10, 0xC8, 0x73, 0x00, 0x20, 0x70, 0xBD, 0x33, 0xF9, + 0xFC, 0x2F, 0xE8, 0xE7, 0xA0, 0x88, 0x40, 0x1C, 0x80, 0xB2, 0xA0, 0x80, + 0x2A, 0x68, 0x92, 0xF8, 0x02, 0x21, 0x82, 0x42, 0xEB, 0xD2, 0x01, 0x20, + 0xE0, 0x70, 0xE7, 0xE7, 0xE0, 0x88, 0x40, 0x1C, 0x80, 0xB2, 0xE0, 0x80, + 0x2A, 0x68, 0x92, 0xF8, 0x03, 0x21, 0x82, 0x42, 0xDF, 0xD2, 0xE1, 0x70, + 0xA1, 0x80, 0xE1, 0x80, 0x01, 0x20, 0x70, 0xBD, 0xF0, 0xB5, 0xE2, 0x4E, + 0x00, 0x24, 0x27, 0x46, 0x33, 0x68, 0xB3, 0xF9, 0x4C, 0x51, 0xE1, 0x4B, + 0xB3, 0xF9, 0x00, 0x30, 0x0B, 0xE0, 0x31, 0xF8, 0x13, 0xC0, 0x20, 0xF8, + 0x13, 0xC0, 0x31, 0xF9, 0x13, 0xC0, 0xAC, 0x45, 0x02, 0xDA, 0x20, 0xF8, + 0x13, 0x70, 0x00, 0xE0, 0x64, 0x1C, 0x5B, 0x1E, 0xF1, 0xD2, 0x30, 0x68, + 0x90, 0xF8, 0x31, 0x11, 0xC9, 0x07, 0x05, 0xD0, 0xB0, 0xF8, 0x4E, 0x01, + 0xA0, 0x42, 0x01, 0xDA, 0x01, 0x20, 0x10, 0x70, 0xF0, 0xBD, 0xD3, 0x4A, + 0x10, 0xB5, 0x10, 0x68, 0xCE, 0x49, 0x40, 0xF0, 0x02, 0x00, 0x10, 0x60, + 0x09, 0x68, 0x91, 0xF8, 0xB0, 0x30, 0xDB, 0x07, 0x03, 0xD1, 0x91, 0xF8, + 0xD4, 0x10, 0xC9, 0x07, 0x02, 0xD0, 0x40, 0xF0, 0x20, 0x00, 0x10, 0x60, + 0xC5, 0x48, 0x81, 0x78, 0x10, 0x68, 0x05, 0xF0, 0xDF, 0xFF, 0xBD, 0xE8, + 0x10, 0x40, 0x4F, 0xF4, 0x00, 0x71, 0x00, 0x20, 0x07, 0xF0, 0xF0, 0xBF, + 0x2D, 0xE9, 0xF0, 0x5F, 0xDF, 0xF8, 0x0C, 0x93, 0x88, 0x46, 0x83, 0x46, + 0x92, 0x46, 0x4F, 0xF4, 0x88, 0x61, 0xD9, 0xF8, 0x00, 0x00, 0x09, 0xF0, + 0x72, 0xFA, 0xBF, 0x48, 0x00, 0x26, 0x35, 0x46, 0x04, 0x78, 0x19, 0xE0, + 0xE1, 0xB2, 0xD9, 0xF8, 0x00, 0x00, 0x0B, 0xF0, 0xE3, 0xF8, 0x07, 0x46, + 0xE1, 0xB2, 0x58, 0x46, 0x0B, 0xF0, 0xE8, 0xF8, 0x01, 0x46, 0xB8, 0x48, + 0x01, 0x22, 0x00, 0x78, 0x08, 0xE0, 0x31, 0xF9, 0x10, 0xC0, 0xC4, 0x45, + 0x04, 0xDD, 0x3A, 0x54, 0x31, 0xF9, 0x10, 0x30, 0x76, 0x1C, 0x1D, 0x44, + 0x40, 0x1E, 0xF4, 0xD2, 0x64, 0x1E, 0xE3, 0xD2, 0x30, 0x46, 0xCA, 0xF8, + 0x00, 0x50, 0x9A, 0xE6, 0x70, 0xB5, 0x0D, 0x46, 0xAB, 0x49, 0x14, 0x46, + 0x09, 0x78, 0x4A, 0x00, 0x01, 0x46, 0xAB, 0x48, 0x09, 0xF0, 0xC4, 0xF9, + 0xA8, 0x48, 0x29, 0x46, 0x00, 0x78, 0x42, 0x00, 0xA8, 0x48, 0x09, 0xF0, + 0xBD, 0xF9, 0xA1, 0x48, 0x21, 0x46, 0xB0, 0xF9, 0x00, 0x00, 0x42, 0x00, + 0xA5, 0x48, 0x00, 0x68, 0x09, 0xF0, 0xB4, 0xF9, 0xA4, 0x49, 0x01, 0x20, + 0x08, 0x70, 0xA4, 0x49, 0x08, 0x70, 0x70, 0xBD, 0x10, 0xB5, 0x00, 0x24, + 0x05, 0xE0, 0x30, 0xF9, 0x12, 0x30, 0x8B, 0x42, 0x01, 0xDD, 0x01, 0x24, + 0x01, 0xE0, 0x52, 0x1E, 0xF7, 0xD2, 0x20, 0x46, 0x10, 0xBD, 0x30, 0xB5, + 0x04, 0x46, 0x00, 0x20, 0x4D, 0x42, 0x07, 0xE0, 0x34, 0xF9, 0x12, 0x30, + 0x8B, 0x42, 0x01, 0xDC, 0xAB, 0x42, 0x01, 0xDA, 0x01, 0x20, 0x30, 0xBD, + 0x52, 0x1E, 0xF5, 0xD2, 0x30, 0xBD, 0x88, 0x49, 0x94, 0x48, 0x95, 0x4A, + 0x08, 0x61, 0x00, 0x20, 0x10, 0x70, 0x94, 0x4A, 0x10, 0x70, 0xC8, 0x70, + 0x88, 0x80, 0xC8, 0x80, 0x88, 0x60, 0x08, 0x70, 0xC8, 0x60, 0x48, 0x70, + 0x00, 0xF0, 0x2F, 0xBA, 0x2D, 0xE9, 0xF7, 0x4F, 0x8C, 0xB0, 0x8E, 0x49, + 0x4F, 0xF0, 0x00, 0x09, 0x8D, 0xF8, 0x14, 0x90, 0x91, 0xF8, 0x00, 0x80, + 0x7A, 0x4C, 0x85, 0x49, 0x7A, 0x48, 0x84, 0xF8, 0x02, 0x90, 0x0A, 0x78, + 0x02, 0x92, 0x81, 0xF8, 0x00, 0x90, 0x00, 0x68, 0x86, 0x4D, 0xDF, 0xF8, + 0xF0, 0xB1, 0x90, 0xF8, 0x31, 0x01, 0xDF, 0xF8, 0xF4, 0xA1, 0x4F, 0x46, + 0x4E, 0x46, 0x40, 0x06, 0x1C, 0xD5, 0x82, 0x48, 0xB0, 0xF9, 0x00, 0x20, + 0x81, 0x48, 0xB0, 0xF9, 0x00, 0x10, 0x81, 0x48, 0xB0, 0xF9, 0x00, 0x00, + 0x06, 0xF0, 0x3B, 0xF8, 0x03, 0xB2, 0x70, 0x48, 0x9B, 0xF8, 0x00, 0x10, + 0x00, 0x78, 0xCD, 0xE9, 0x00, 0x01, 0xDA, 0xF8, 0x00, 0x20, 0x0C, 0x99, + 0x20, 0x69, 0xFF, 0xF7, 0x77, 0xFA, 0x79, 0x48, 0x02, 0x9B, 0x21, 0x69, + 0x02, 0x68, 0x03, 0xE0, 0x76, 0x48, 0x13, 0x46, 0x0C, 0x99, 0x02, 0x68, + 0x28, 0x68, 0x00, 0xF0, 0xE1, 0xF9, 0x02, 0x20, 0x07, 0xF0, 0xDB, 0xFF, + 0x5D, 0x48, 0x00, 0x68, 0x90, 0xF8, 0x30, 0x01, 0x80, 0x07, 0x08, 0xD5, + 0xB8, 0xF1, 0x00, 0x0F, 0x05, 0xD1, 0x05, 0xAA, 0x02, 0x99, 0x28, 0x68, + 0xFF, 0xF7, 0x70, 0xFC, 0x07, 0x46, 0x56, 0x48, 0x00, 0x68, 0x90, 0xF8, + 0x30, 0x01, 0x40, 0x07, 0x09, 0xD5, 0xB8, 0xF1, 0x00, 0x0F, 0x06, 0xD1, + 0x05, 0xAA, 0xDA, 0xF8, 0x00, 0x10, 0x28, 0x68, 0xFF, 0xF7, 0xD6, 0xFC, + 0x06, 0x46, 0x01, 0x2F, 0x46, 0xD0, 0x01, 0x2E, 0x44, 0xD0, 0xFF, 0xF7, + 0x23, 0xFD, 0x4B, 0x4F, 0x38, 0x68, 0x90, 0xF8, 0x30, 0x01, 0x00, 0x07, + 0x17, 0xD5, 0x59, 0x48, 0xB0, 0xF9, 0x00, 0x20, 0x58, 0x48, 0xB0, 0xF9, + 0x00, 0x10, 0x58, 0x48, 0xB0, 0xF9, 0x00, 0x00, 0x05, 0xF0, 0xE9, 0xFF, + 0x03, 0xB2, 0x47, 0x48, 0x9B, 0xF8, 0x00, 0x10, 0x00, 0x78, 0xCD, 0xE9, + 0x00, 0x01, 0x29, 0x68, 0xDA, 0xF8, 0x00, 0x20, 0x08, 0x46, 0xFF, 0xF7, + 0xEA, 0xFA, 0x3E, 0x4E, 0xDA, 0xF8, 0x00, 0x20, 0x29, 0x68, 0xB6, 0xF9, + 0x00, 0x30, 0x20, 0x69, 0x05, 0xF0, 0xC7, 0xFF, 0x02, 0x20, 0x07, 0xF0, + 0xA7, 0xFF, 0x38, 0x68, 0x90, 0xF8, 0x30, 0x01, 0xC0, 0x06, 0x07, 0xD5, + 0x38, 0x48, 0x21, 0x69, 0x9B, 0xF8, 0x00, 0x30, 0x02, 0x78, 0x08, 0x46, + 0xFF, 0xF7, 0x36, 0xFB, 0x38, 0x68, 0x90, 0xF8, 0x30, 0x11, 0x8A, 0x06, + 0x1A, 0xD4, 0x49, 0x06, 0x18, 0xD4, 0x90, 0xF8, 0x2F, 0x01, 0xC1, 0x07, + 0x14, 0xD1, 0x11, 0xE0, 0x02, 0x20, 0x07, 0xF0, 0x8B, 0xFF, 0x9D, 0xF8, + 0x14, 0x00, 0x01, 0x28, 0x09, 0xD1, 0x01, 0x2F, 0x01, 0xD1, 0x12, 0x20, + 0xA0, 0x70, 0x01, 0x2E, 0x01, 0xD1, 0x11, 0x20, 0x4B, 0xE1, 0xFF, 0xF7, + 0xA2, 0xFE, 0xA7, 0xE0, 0x80, 0x07, 0x06, 0xD5, 0x21, 0x69, 0xB6, 0xF9, + 0x00, 0x30, 0x33, 0x4A, 0x08, 0x46, 0x00, 0xF0, 0x4E, 0xF9, 0xDF, 0xF8, + 0xC8, 0xA0, 0x32, 0x4D, 0x9A, 0xF8, 0x00, 0x00, 0x10, 0xF0, 0x30, 0x0F, + 0x29, 0xD0, 0x02, 0x98, 0x8D, 0xF8, 0x04, 0x90, 0x01, 0x28, 0x01, 0xD1, + 0x20, 0x49, 0x08, 0x70, 0x02, 0x20, 0x07, 0xF0, 0x46, 0xFF, 0x01, 0xA8, + 0x00, 0x90, 0x1B, 0x48, 0x23, 0x69, 0x02, 0x68, 0xDD, 0xE9, 0x0D, 0x01, + 0xFE, 0xF7, 0x83, 0xFD, 0x8D, 0xF8, 0x14, 0x00, 0x02, 0x20, 0x07, 0xF0, + 0x53, 0xFF, 0x9D, 0xF8, 0x14, 0x00, 0xDF, 0xF8, 0x8C, 0x80, 0x01, 0x28, + 0x65, 0xD0, 0x9D, 0xF8, 0x04, 0x00, 0x01, 0x28, 0x64, 0xD0, 0x9A, 0xF8, + 0x00, 0x00, 0xC0, 0x06, 0x03, 0xD5, 0x1E, 0x48, 0x00, 0x78, 0x01, 0x28, + 0x70, 0xD0, 0x38, 0x68, 0x90, 0xF8, 0xF0, 0x00, 0x40, 0x07, 0x35, 0xE0, + 0x74, 0x23, 0x10, 0x00, 0x50, 0x24, 0x10, 0x00, 0x58, 0x25, 0x10, 0x00, + 0x0C, 0x24, 0x10, 0x00, 0x64, 0x24, 0x10, 0x00, 0xA0, 0x23, 0x10, 0x00, + 0x00, 0x24, 0x10, 0x00, 0x01, 0x24, 0x10, 0x00, 0xFC, 0x22, 0x01, 0x20, + 0x38, 0x23, 0x01, 0x20, 0x18, 0x24, 0x10, 0x00, 0x61, 0x24, 0x10, 0x00, + 0x56, 0x23, 0x10, 0x00, 0x60, 0x54, 0x10, 0x00, 0x29, 0x24, 0x10, 0x00, + 0x28, 0x24, 0x10, 0x00, 0x6D, 0x23, 0x10, 0x00, 0x14, 0x24, 0x10, 0x00, + 0xCA, 0x23, 0x10, 0x00, 0xC8, 0x23, 0x10, 0x00, 0xC6, 0x23, 0x10, 0x00, + 0xBC, 0x23, 0x10, 0x00, 0x3C, 0x88, 0x01, 0x20, 0x1C, 0x24, 0x10, 0x00, + 0x10, 0x24, 0x10, 0x00, 0x59, 0x23, 0x10, 0x00, 0x55, 0x23, 0x10, 0x00, + 0x0B, 0xD5, 0x9A, 0xF8, 0x00, 0x00, 0x80, 0x06, 0x07, 0xD5, 0x86, 0x49, + 0x86, 0x48, 0xFF, 0xF7, 0xC3, 0xFD, 0x8D, 0xF8, 0x14, 0x00, 0x01, 0x28, + 0x54, 0xD0, 0x84, 0x48, 0x00, 0x78, 0x02, 0x28, 0x38, 0x68, 0x7C, 0xD3, + 0x90, 0xF8, 0x30, 0x01, 0x00, 0x06, 0x04, 0xD5, 0x21, 0x69, 0x05, 0xAA, + 0x08, 0x46, 0xFF, 0xF7, 0xEB, 0xFD, 0x9D, 0xF8, 0x14, 0x00, 0xE8, 0xB3, + 0x92, 0xE0, 0x98, 0xF8, 0x00, 0x00, 0xB0, 0xE0, 0x02, 0x20, 0x07, 0xF0, + 0xC6, 0xFE, 0x98, 0xF8, 0x00, 0x10, 0x22, 0x20, 0x05, 0xF0, 0xF8, 0xFD, + 0xDD, 0xE9, 0x0D, 0x01, 0x0C, 0x9A, 0xFF, 0xF7, 0x4D, 0xFE, 0x02, 0x20, + 0x07, 0xF0, 0xD4, 0xFE, 0x00, 0x20, 0x0F, 0xB0, 0x94, 0xE5, 0xFF, 0xE7, + 0x01, 0xA8, 0xFF, 0xF7, 0x9F, 0xF8, 0x6F, 0x49, 0x82, 0x46, 0x81, 0xF8, + 0x00, 0x90, 0xB6, 0xF9, 0x00, 0x00, 0x21, 0x69, 0x42, 0x00, 0x28, 0x68, + 0x09, 0xF0, 0x06, 0xF8, 0xFF, 0xF7, 0x44, 0xF8, 0x9D, 0xF8, 0x04, 0x00, + 0x01, 0x28, 0xD7, 0xD0, 0x38, 0x68, 0x90, 0xF8, 0xF1, 0x00, 0xC0, 0x07, + 0x10, 0xD0, 0x65, 0x48, 0x00, 0x78, 0x68, 0xB1, 0x02, 0x20, 0x07, 0xF0, + 0x96, 0xFE, 0x64, 0x48, 0x62, 0x4A, 0x01, 0x68, 0x0C, 0x98, 0xFE, 0xF7, + 0xEE, 0xFF, 0x00, 0xE0, 0x06, 0xE0, 0x02, 0x20, 0x07, 0xF0, 0xA6, 0xFE, + 0x50, 0x46, 0xD0, 0xE7, 0x24, 0x20, 0x6E, 0xE0, 0x3F, 0x68, 0x97, 0xF8, + 0x31, 0x01, 0x80, 0x07, 0x48, 0xD5, 0x14, 0x22, 0x5A, 0x49, 0x06, 0xA8, + 0x09, 0xF0, 0x21, 0xF8, 0x2A, 0x68, 0xB7, 0xF8, 0x50, 0x71, 0x23, 0x69, + 0x8D, 0xF8, 0x2C, 0x90, 0x8D, 0xF8, 0x2E, 0x90, 0x9B, 0xF8, 0x00, 0x00, + 0x0D, 0xF1, 0x18, 0x0C, 0x41, 0x1E, 0x8D, 0xF8, 0x2D, 0x10, 0x52, 0x49, + 0x09, 0x78, 0xA1, 0xF1, 0x01, 0x08, 0x8D, 0xF8, 0x2F, 0x80, 0x8D, 0xE8, + 0x0C, 0x10, 0xAD, 0xF8, 0x10, 0x70, 0x8D, 0xF8, 0x13, 0x10, 0x0B, 0xAA, + 0x8D, 0xF8, 0x12, 0x00, 0x03, 0x92, 0x68, 0x46, 0x00, 0xE0, 0x02, 0xE0, + 0x08, 0xF0, 0xA2, 0xF8, 0x25, 0xE0, 0x90, 0xF8, 0xE8, 0x17, 0x49, 0x06, + 0x10, 0xD5, 0xB6, 0xF9, 0x00, 0x00, 0x2A, 0x68, 0x08, 0xE0, 0x21, 0x69, + 0x32, 0xF9, 0x10, 0x30, 0x31, 0xF9, 0x10, 0x10, 0x99, 0x42, 0x01, 0xDD, + 0x22, 0xF8, 0x10, 0x10, 0x40, 0x1E, 0x00, 0xB2, 0xF3, 0xD2, 0x10, 0xE0, + 0x90, 0xF8, 0x30, 0x01, 0x00, 0x06, 0x05, 0xD5, 0x05, 0xAA, 0x21, 0x69, + 0x28, 0x68, 0xFF, 0xF7, 0x55, 0xFD, 0x06, 0xE0, 0xB6, 0xF9, 0x00, 0x00, + 0x21, 0x69, 0x42, 0x00, 0x28, 0x68, 0x08, 0xF0, 0x91, 0xFF, 0x9D, 0xF8, + 0x14, 0x00, 0x01, 0x28, 0x14, 0xD0, 0xB6, 0xF9, 0x00, 0x20, 0x32, 0x4E, + 0x28, 0x68, 0xB6, 0xF9, 0x00, 0x10, 0xFF, 0xF7, 0xD7, 0xFD, 0x01, 0x28, + 0x0D, 0xD0, 0x28, 0x49, 0x00, 0x24, 0x81, 0xF8, 0x00, 0x90, 0x2D, 0x49, + 0x08, 0x78, 0x08, 0xB1, 0x40, 0x1E, 0x08, 0x70, 0x20, 0x46, 0x60, 0xE7, + 0x13, 0x20, 0xA0, 0x70, 0xB1, 0xE6, 0x21, 0x49, 0x01, 0x24, 0x28, 0x4A, + 0x0C, 0x70, 0xB6, 0xF9, 0x00, 0x10, 0x28, 0x68, 0xFF, 0xF7, 0x6C, 0xFD, + 0x25, 0x49, 0x08, 0x60, 0xEE, 0xE7, 0x30, 0xB5, 0x07, 0xE0, 0x31, 0xF9, + 0x13, 0x40, 0x32, 0xF9, 0x13, 0x50, 0x6C, 0x43, 0xE4, 0x11, 0x20, 0xF8, + 0x13, 0x40, 0x5B, 0x1E, 0xF5, 0xD2, 0x30, 0xBD, 0x1C, 0xB5, 0x10, 0x24, + 0xCD, 0xE9, 0x00, 0x43, 0x13, 0x46, 0x1C, 0x4A, 0xB2, 0xF9, 0x00, 0x20, + 0x06, 0xF0, 0x40, 0xF8, 0x1C, 0xBD, 0x1A, 0x48, 0x1A, 0x4A, 0x1B, 0x4B, + 0x01, 0x68, 0xB1, 0xF8, 0x52, 0x01, 0x10, 0x80, 0xB1, 0xF8, 0xD2, 0x21, + 0x1A, 0x80, 0x18, 0x4B, 0xB1, 0xF8, 0xF6, 0x11, 0x19, 0x80, 0x17, 0x4B, + 0x18, 0x80, 0x17, 0x4B, 0x1A, 0x80, 0x17, 0x4A, 0x11, 0x80, 0x17, 0x49, + 0x08, 0x80, 0x17, 0x49, 0x08, 0x80, 0x70, 0x47, 0xBC, 0x0A, 0x01, 0x20, + 0x80, 0x0A, 0x01, 0x20, 0xB8, 0x23, 0x10, 0x00, 0x29, 0x24, 0x10, 0x00, + 0x08, 0x24, 0x10, 0x00, 0xA4, 0x48, 0x10, 0x00, 0x18, 0x24, 0x10, 0x00, + 0x24, 0x1D, 0x01, 0x00, 0x00, 0x24, 0x10, 0x00, 0xD2, 0x23, 0x10, 0x00, + 0xE0, 0x23, 0x10, 0x00, 0xD8, 0x23, 0x10, 0x00, 0xC0, 0x23, 0x10, 0x00, + 0x0C, 0x24, 0x10, 0x00, 0x50, 0x24, 0x10, 0x00, 0xC6, 0x23, 0x10, 0x00, + 0xC8, 0x23, 0x10, 0x00, 0xCA, 0x23, 0x10, 0x00, 0xCC, 0x23, 0x10, 0x00, + 0xCE, 0x23, 0x10, 0x00, 0xD0, 0x23, 0x10, 0x00, 0xD4, 0x23, 0x10, 0x00, + 0xD6, 0x23, 0x10, 0x00, 0x70, 0xB5, 0x04, 0x46, 0xDE, 0x4B, 0x00, 0x20, + 0x84, 0xF8, 0x29, 0x00, 0x93, 0xF9, 0x00, 0x00, 0x00, 0x28, 0x01, 0xDD, + 0x40, 0x1E, 0x18, 0x70, 0xDA, 0x48, 0xDB, 0x4D, 0x94, 0xF8, 0x25, 0x60, + 0x02, 0x78, 0x28, 0x68, 0x04, 0x2E, 0x06, 0xD0, 0x93, 0xF9, 0x00, 0x30, + 0x00, 0x2B, 0x21, 0xDD, 0x90, 0xF8, 0x8B, 0x01, 0x15, 0xE0, 0xD5, 0x4B, + 0x1B, 0x78, 0x43, 0xB1, 0x00, 0x2A, 0x94, 0xF9, 0x26, 0x20, 0x07, 0xD0, + 0x90, 0xF8, 0x01, 0x02, 0x8A, 0x42, 0x07, 0xD0, 0x09, 0xE0, 0x90, 0xF8, + 0xFF, 0x01, 0x03, 0xE0, 0x90, 0xF8, 0x00, 0x02, 0x8A, 0x42, 0x02, 0xD1, + 0x00, 0xF0, 0x0F, 0x00, 0x00, 0xE0, 0x00, 0x09, 0x84, 0xF8, 0x29, 0x00, + 0x20, 0x46, 0x00, 0xF0, 0x34, 0xF9, 0x01, 0x28, 0x1B, 0xD0, 0x24, 0xE0, + 0x00, 0x2A, 0x94, 0xF9, 0x26, 0x20, 0x04, 0xD0, 0x8A, 0x42, 0x11, 0xD1, + 0x90, 0xF8, 0x89, 0x01, 0xED, 0xE7, 0x8A, 0x42, 0x02, 0xD1, 0x90, 0xF8, + 0x89, 0x01, 0xE5, 0xE7, 0x90, 0xF8, 0x8A, 0x11, 0x01, 0xF0, 0x0F, 0x01, + 0x84, 0xF8, 0x29, 0x10, 0xBC, 0x49, 0x09, 0x78, 0x01, 0x29, 0xE1, 0xD1, + 0x90, 0xF8, 0x8A, 0x01, 0xDB, 0xE7, 0x29, 0x68, 0x94, 0xF8, 0x29, 0x00, + 0x91, 0xF8, 0x8B, 0x11, 0x01, 0xF0, 0x0F, 0x01, 0x08, 0x44, 0x84, 0xF8, + 0x29, 0x00, 0xB5, 0x48, 0x00, 0x78, 0x01, 0x28, 0x08, 0xD1, 0x29, 0x68, + 0x14, 0xF8, 0x29, 0x0F, 0x91, 0xF8, 0xCB, 0x10, 0x01, 0xF0, 0x0F, 0x01, + 0x08, 0x44, 0x20, 0x70, 0x70, 0xBD, 0xAC, 0x49, 0x00, 0x20, 0x08, 0x70, + 0xAD, 0x49, 0x05, 0x20, 0x08, 0x70, 0x70, 0x47, 0xAC, 0x49, 0x08, 0x78, + 0x20, 0xB1, 0x40, 0x1E, 0x10, 0xF0, 0xFF, 0x00, 0x08, 0x70, 0x04, 0xD1, + 0xA9, 0x49, 0x00, 0x20, 0x08, 0x70, 0xA9, 0x49, 0x08, 0x60, 0x70, 0x47, + 0xA1, 0x4A, 0x10, 0xB5, 0x14, 0x78, 0x9F, 0x4A, 0x90, 0xF8, 0x29, 0x10, + 0x12, 0x68, 0x92, 0xF8, 0x89, 0x31, 0x03, 0xF0, 0x0F, 0x03, 0x5C, 0xB1, + 0x92, 0xF8, 0x00, 0x22, 0x02, 0xF0, 0x0F, 0x02, 0xD2, 0x1A, 0x89, 0x1A, + 0x00, 0x29, 0x00, 0xDC, 0x00, 0x21, 0x80, 0xF8, 0x29, 0x10, 0x10, 0xBD, + 0x92, 0xF8, 0xFF, 0x21, 0xF2, 0xE7, 0x98, 0x49, 0x00, 0x20, 0x08, 0x70, + 0x92, 0x49, 0x08, 0x70, 0x70, 0x47, 0x2D, 0xE9, 0xF8, 0x4F, 0x06, 0x46, + 0x00, 0x88, 0xDF, 0xF8, 0x4C, 0xB2, 0x00, 0x04, 0x00, 0x0C, 0x13, 0xD0, + 0x00, 0x24, 0x0A, 0x22, 0x35, 0x68, 0x20, 0x46, 0x01, 0x27, 0x07, 0xFA, + 0x00, 0xF1, 0x0D, 0x42, 0x19, 0xD0, 0x65, 0x21, 0x01, 0xFB, 0x00, 0x61, + 0x91, 0xF8, 0x2D, 0x30, 0x09, 0x31, 0x01, 0x2B, 0x07, 0xD0, 0x0A, 0x22, + 0x10, 0x46, 0x0E, 0xE0, 0x00, 0x20, 0x8B, 0xF8, 0x00, 0x00, 0xBD, 0xE8, + 0xF8, 0x8F, 0x0B, 0x6D, 0xB1, 0xF8, 0x31, 0x10, 0x93, 0xFB, 0xF1, 0xFC, + 0xA4, 0x45, 0x02, 0xDD, 0x93, 0xFB, 0xF1, 0xF4, 0x42, 0xB2, 0x40, 0x1C, + 0x0A, 0x28, 0xDE, 0xDB, 0x0A, 0x25, 0x4F, 0xF0, 0x02, 0x09, 0xDF, 0xF8, + 0xDC, 0x81, 0x4F, 0xF0, 0x08, 0x0A, 0x00, 0x92, 0x8B, 0xE0, 0x30, 0x68, + 0x07, 0xFA, 0x05, 0xF1, 0x08, 0x42, 0x6C, 0xD0, 0x65, 0x20, 0x05, 0xFB, + 0x00, 0x64, 0x94, 0xF8, 0x2D, 0x00, 0x09, 0x34, 0x01, 0x28, 0x08, 0xD0, + 0x05, 0x28, 0x15, 0xD0, 0x02, 0x28, 0x0A, 0xD0, 0x06, 0x28, 0x17, 0xD0, + 0x07, 0x28, 0x5D, 0xD0, 0x60, 0xE0, 0x20, 0x46, 0x00, 0x99, 0xFF, 0xF7, + 0x0B, 0xFF, 0x84, 0xF8, 0x24, 0x90, 0x94, 0xF8, 0x2F, 0x00, 0xC0, 0x07, + 0x1B, 0xD0, 0x20, 0x46, 0x00, 0xF0, 0x6D, 0xF8, 0x50, 0xB1, 0x16, 0xE0, + 0x20, 0x46, 0x00, 0xF0, 0x84, 0xF8, 0x06, 0x20, 0x84, 0xF8, 0x24, 0x00, + 0x94, 0xF8, 0x2A, 0x00, 0xC0, 0xB3, 0x58, 0xE0, 0xD8, 0xF8, 0x00, 0x10, + 0x94, 0xF8, 0x29, 0x00, 0x91, 0xF8, 0x8B, 0x11, 0x01, 0xF0, 0x0F, 0x01, + 0x88, 0x42, 0x06, 0xD9, 0x40, 0x1A, 0x84, 0xF8, 0x29, 0x00, 0x94, 0xF8, + 0x29, 0x00, 0x18, 0xB1, 0x10, 0xE0, 0x00, 0x20, 0x84, 0xF8, 0x29, 0x00, + 0x03, 0x20, 0x84, 0xF8, 0x24, 0x00, 0x9B, 0xF8, 0x00, 0x10, 0x49, 0x1C, + 0x8B, 0xF8, 0x00, 0x10, 0x94, 0xF8, 0x25, 0x00, 0x04, 0x28, 0x18, 0xD0, + 0xFF, 0xF7, 0x41, 0xFF, 0xD8, 0xF8, 0x00, 0x00, 0x90, 0xF8, 0x9F, 0x03, + 0xC2, 0x07, 0x1F, 0xD0, 0x40, 0x07, 0x1D, 0xD5, 0x94, 0xF8, 0x2F, 0x00, + 0x00, 0x06, 0x19, 0xD4, 0x84, 0xF8, 0x24, 0x90, 0xD8, 0xF8, 0x00, 0x00, + 0x90, 0xF8, 0xA3, 0x13, 0x02, 0x20, 0x04, 0xF0, 0xFC, 0xFA, 0x0F, 0xE0, + 0x02, 0xE0, 0x41, 0x48, 0x07, 0x70, 0xE5, 0xE7, 0x94, 0xF8, 0x2F, 0x00, + 0x80, 0x07, 0x03, 0xD5, 0x07, 0x20, 0x84, 0xF8, 0x24, 0x00, 0x18, 0xE0, + 0x84, 0xF8, 0x24, 0xA0, 0xFF, 0xF7, 0x22, 0xFF, 0x94, 0xF8, 0x24, 0x00, + 0x02, 0x28, 0x02, 0xD0, 0x06, 0x28, 0x0E, 0xD1, 0x06, 0xE0, 0x94, 0xF8, + 0x29, 0x00, 0x50, 0xB1, 0x40, 0x1E, 0x84, 0xF8, 0x29, 0x00, 0x06, 0xE0, + 0x94, 0xF8, 0x2A, 0x00, 0x18, 0xB1, 0xC0, 0xB2, 0x40, 0x1E, 0x84, 0xF8, + 0x2A, 0x00, 0x6D, 0x1E, 0xBF, 0xF4, 0x71, 0xAF, 0x57, 0xE7, 0x90, 0xF8, + 0x21, 0x10, 0x90, 0xF8, 0x20, 0x20, 0x8A, 0x1A, 0xB0, 0xF8, 0x2F, 0x10, + 0x52, 0x1C, 0x02, 0x2A, 0x0B, 0xD9, 0x90, 0xF8, 0x23, 0x20, 0x90, 0xF8, + 0x22, 0x30, 0x9A, 0x42, 0x05, 0xD1, 0x41, 0xF0, 0x01, 0x01, 0xA0, 0xF8, + 0x2F, 0x10, 0x01, 0x20, 0x70, 0x47, 0x21, 0xF0, 0x01, 0x01, 0xA0, 0xF8, + 0x2F, 0x10, 0x00, 0x20, 0x70, 0x47, 0x10, 0xB5, 0x00, 0x21, 0x80, 0xF8, + 0x2A, 0x10, 0x1B, 0x49, 0x0A, 0x78, 0x1B, 0x49, 0x00, 0x2A, 0x09, 0x68, + 0x91, 0xF8, 0x8C, 0x21, 0x07, 0xD0, 0x12, 0x09, 0x80, 0xF8, 0x2A, 0x20, + 0x90, 0xF8, 0x25, 0x20, 0x04, 0x2A, 0x03, 0xD0, 0x0A, 0xE0, 0x02, 0xF0, + 0x0F, 0x02, 0xF5, 0xE7, 0x90, 0xF8, 0x2A, 0x20, 0x91, 0xF8, 0xFF, 0x31, + 0x02, 0xEB, 0x13, 0x12, 0x80, 0xF8, 0x2A, 0x20, 0x91, 0xF8, 0x8D, 0x21, + 0x83, 0x6D, 0x02, 0xF0, 0x0F, 0x04, 0xA3, 0x42, 0x05, 0xDD, 0x90, 0xF8, + 0x2A, 0x30, 0x03, 0xEB, 0x12, 0x12, 0x80, 0xF8, 0x2A, 0x20, 0x0B, 0x4A, + 0x12, 0x78, 0x01, 0x2A, 0x06, 0xD1, 0x10, 0xF8, 0x2A, 0x2F, 0x91, 0xF8, + 0xCB, 0x10, 0x02, 0xEB, 0x11, 0x11, 0x01, 0x70, 0x10, 0xBD, 0x00, 0x00, + 0x88, 0x23, 0x10, 0x00, 0xB8, 0x23, 0x10, 0x00, 0x50, 0x24, 0x10, 0x00, + 0x2A, 0x24, 0x10, 0x00, 0x6E, 0x23, 0x10, 0x00, 0x6D, 0x23, 0x10, 0x00, + 0xE0, 0x23, 0x10, 0x00, 0x08, 0x24, 0x10, 0x00, 0x38, 0x23, 0x10, 0x00, + 0x3C, 0x23, 0x10, 0x00, 0xF6, 0x4A, 0x10, 0xB5, 0x13, 0x78, 0xF6, 0x4A, + 0x12, 0x68, 0x53, 0xB1, 0x92, 0xF8, 0x9B, 0x01, 0xB2, 0xF8, 0x9C, 0x31, + 0x00, 0xF0, 0x0F, 0x04, 0x00, 0x09, 0x5B, 0x43, 0xB2, 0xF8, 0x9E, 0x21, + 0x13, 0xE0, 0x90, 0xF8, 0x25, 0x00, 0x01, 0x28, 0x16, 0xD0, 0x04, 0x28, + 0x17, 0xD0, 0xED, 0x48, 0x00, 0x78, 0x01, 0x28, 0x1E, 0xD0, 0x92, 0xF8, + 0x9A, 0x01, 0xB2, 0xF8, 0xA4, 0x31, 0x00, 0xF0, 0x0F, 0x04, 0x00, 0x09, + 0xB2, 0xF8, 0xA6, 0x21, 0x5B, 0x43, 0x52, 0x43, 0x99, 0x42, 0x02, 0xDD, + 0x91, 0x42, 0x12, 0xDB, 0x20, 0x46, 0x10, 0xBD, 0x92, 0xF8, 0xE6, 0x01, + 0xED, 0xE7, 0x92, 0xF8, 0x06, 0x02, 0xB2, 0xF8, 0x02, 0x32, 0x00, 0xF0, + 0x0F, 0x04, 0x00, 0x09, 0x5B, 0x43, 0xB2, 0xF8, 0x04, 0x22, 0xEA, 0xE7, + 0x92, 0xF8, 0xCC, 0x00, 0xDF, 0xE7, 0x9A, 0x42, 0x00, 0xD1, 0x52, 0x1C, + 0xC9, 0x1A, 0x04, 0x1B, 0x61, 0x43, 0xD2, 0x1A, 0x91, 0xFB, 0xF2, 0xF1, + 0x40, 0x1A, 0x10, 0xBD, 0xD2, 0x49, 0xD3, 0x4A, 0x0B, 0x78, 0xC1, 0x78, + 0x00, 0x2B, 0x02, 0xD0, 0x41, 0xF0, 0x04, 0x01, 0x01, 0xE0, 0x21, 0xF0, + 0x04, 0x01, 0xC1, 0x70, 0x16, 0xD0, 0x41, 0xF0, 0x04, 0x01, 0xC1, 0x70, + 0x13, 0x68, 0x93, 0xF8, 0xB0, 0x31, 0x4F, 0xEA, 0x93, 0x03, 0x63, 0xF3, + 0x01, 0x01, 0xC1, 0x70, 0x11, 0x68, 0x91, 0xF8, 0xB2, 0x11, 0x41, 0x70, + 0x11, 0x68, 0x91, 0xF8, 0xB1, 0x11, 0x01, 0x70, 0x11, 0x68, 0x91, 0xF8, + 0xB0, 0x11, 0x15, 0xE0, 0x21, 0xF0, 0x04, 0x01, 0xC1, 0x70, 0x13, 0x68, + 0x93, 0xF8, 0xAD, 0x31, 0x4F, 0xEA, 0x93, 0x03, 0x63, 0xF3, 0x01, 0x01, + 0xC1, 0x70, 0x11, 0x68, 0x91, 0xF8, 0xAF, 0x11, 0x41, 0x70, 0x11, 0x68, + 0x91, 0xF8, 0xAE, 0x11, 0x01, 0x70, 0x11, 0x68, 0x91, 0xF8, 0xAD, 0x11, + 0x4F, 0xEA, 0x11, 0x11, 0x81, 0x70, 0x11, 0x68, 0x91, 0xF8, 0xB3, 0x21, + 0x42, 0x71, 0x91, 0xF8, 0xB4, 0x11, 0x01, 0x71, 0x70, 0x47, 0x2D, 0xE9, + 0xF0, 0x41, 0xB0, 0x4F, 0x05, 0x46, 0xDF, 0xF8, 0xC4, 0x82, 0x38, 0x68, + 0x0C, 0x46, 0x16, 0x46, 0x90, 0xF8, 0x81, 0x01, 0x80, 0x06, 0x26, 0xD5, + 0x95, 0xF8, 0x24, 0x00, 0x29, 0x46, 0x03, 0x28, 0x0A, 0xD0, 0x02, 0x28, + 0x08, 0xD0, 0x04, 0x28, 0x0D, 0xD0, 0x06, 0x28, 0x13, 0xD0, 0x07, 0x28, + 0x11, 0xD0, 0x08, 0x28, 0x0F, 0xD0, 0x13, 0xE0, 0xA4, 0x4A, 0x91, 0xF9, + 0x26, 0x00, 0x0C, 0x32, 0x07, 0xF0, 0x82, 0xFE, 0x0C, 0xE0, 0xA1, 0x4A, + 0x95, 0xF9, 0x26, 0x00, 0x0C, 0x32, 0x21, 0x46, 0x07, 0xF0, 0xB5, 0xFE, + 0x04, 0xE0, 0x95, 0xF9, 0x26, 0x00, 0x21, 0x46, 0x07, 0xF0, 0xD5, 0xFF, + 0x21, 0x68, 0xC8, 0xF8, 0x04, 0x10, 0x38, 0x68, 0x90, 0xF8, 0x81, 0x01, + 0x40, 0x06, 0x2A, 0xD5, 0xEA, 0x6D, 0x21, 0x46, 0x52, 0x1C, 0xEA, 0x65, + 0x95, 0xF8, 0x24, 0x00, 0x03, 0x28, 0x08, 0xD0, 0x05, 0x2A, 0x16, 0xDD, + 0x04, 0x28, 0x0C, 0xD0, 0x06, 0x28, 0x0A, 0xD0, 0x07, 0x28, 0x08, 0xD0, + 0x16, 0xE0, 0x95, 0xF9, 0x26, 0x00, 0x8E, 0x4A, 0x29, 0x46, 0x08, 0xF0, + 0x3C, 0xF8, 0x00, 0x21, 0x05, 0xE0, 0x95, 0xF9, 0x26, 0x00, 0x8A, 0x4A, + 0x08, 0xF0, 0xE8, 0xFA, 0x06, 0x21, 0xE9, 0x65, 0x06, 0xE0, 0x04, 0x28, + 0x04, 0xD1, 0x95, 0xF9, 0x26, 0x00, 0x85, 0x4A, 0x08, 0xF0, 0x7F, 0xF8, + 0x21, 0x68, 0xC8, 0xF8, 0x08, 0x10, 0x38, 0x68, 0x90, 0xF8, 0x81, 0x01, + 0xC0, 0x07, 0x2A, 0xD0, 0x95, 0xF8, 0x24, 0x00, 0x03, 0x28, 0x06, 0xD0, + 0x04, 0x28, 0x0A, 0xD0, 0x07, 0x28, 0x17, 0xD0, 0x08, 0x28, 0x1B, 0xD0, + 0x1F, 0xE0, 0x95, 0xF9, 0x26, 0x00, 0x21, 0x46, 0x07, 0xF0, 0xC1, 0xFF, + 0x19, 0xE0, 0x29, 0x46, 0x28, 0x1D, 0x00, 0xF0, 0xAF, 0xFC, 0x01, 0x46, + 0x28, 0x46, 0xFF, 0xF7, 0xF1, 0xFE, 0x02, 0x46, 0x95, 0xF9, 0x26, 0x00, + 0x21, 0x46, 0x07, 0xF0, 0xB7, 0xFF, 0x0A, 0xE0, 0x95, 0xF9, 0x26, 0x00, + 0x21, 0x46, 0x07, 0xF0, 0xCC, 0xFF, 0x04, 0xE0, 0x95, 0xF9, 0x26, 0x00, + 0x21, 0x46, 0x07, 0xF0, 0xCB, 0xFF, 0x38, 0x68, 0xB0, 0xF9, 0x16, 0x10, + 0xB4, 0xF9, 0x02, 0x00, 0x05, 0xF0, 0x3F, 0xFD, 0x60, 0x80, 0x38, 0x68, + 0xB0, 0xF9, 0x18, 0x10, 0xB4, 0xF9, 0x00, 0x00, 0x05, 0xF0, 0x37, 0xFD, + 0x20, 0x80, 0x95, 0xF8, 0x24, 0x00, 0x03, 0x28, 0x0A, 0xD0, 0x04, 0x28, + 0x0C, 0xD0, 0x07, 0x28, 0x01, 0xD0, 0x08, 0x28, 0x02, 0xD1, 0xB5, 0xF8, + 0x3F, 0x00, 0x30, 0x80, 0xBD, 0xE8, 0xF0, 0x81, 0x30, 0x88, 0xA5, 0xF8, + 0x3F, 0x00, 0xF9, 0xE7, 0x38, 0x68, 0x35, 0xF8, 0x3F, 0x2F, 0x90, 0xF8, + 0x8E, 0x01, 0x00, 0xF0, 0x0F, 0x00, 0xC0, 0xF1, 0x10, 0x01, 0x42, 0x43, + 0x30, 0x88, 0x00, 0xFB, 0x01, 0x20, 0x00, 0x09, 0x28, 0x80, 0xE8, 0xE7, + 0x70, 0xB5, 0x04, 0x46, 0x90, 0xF8, 0x47, 0x00, 0x0D, 0x46, 0x7F, 0x28, + 0x0F, 0xD1, 0x21, 0x46, 0x20, 0x1D, 0x00, 0xF0, 0x5B, 0xFC, 0x01, 0x46, + 0x20, 0x46, 0x00, 0xF0, 0x46, 0xF9, 0x40, 0xB2, 0x84, 0xF8, 0x47, 0x00, + 0x0F, 0x28, 0x02, 0xDD, 0x0F, 0x20, 0x84, 0xF8, 0x47, 0x00, 0x94, 0xF9, + 0x47, 0x00, 0xB5, 0xF9, 0x02, 0x20, 0xC0, 0xF1, 0x10, 0x01, 0x51, 0x43, + 0xB4, 0xF9, 0x12, 0x20, 0x00, 0xFB, 0x02, 0x10, 0x00, 0x11, 0x68, 0x80, + 0x94, 0xF9, 0x47, 0x00, 0xB5, 0xF9, 0x00, 0x20, 0xC0, 0xF1, 0x10, 0x01, + 0x51, 0x43, 0xB4, 0xF9, 0x10, 0x20, 0x00, 0xFB, 0x02, 0x10, 0x36, 0x49, + 0x00, 0x11, 0x28, 0x80, 0x09, 0x68, 0x94, 0xF8, 0x47, 0x00, 0x91, 0xF8, + 0x8F, 0x11, 0x01, 0xF0, 0x0F, 0x01, 0x40, 0x1A, 0x40, 0xB2, 0x84, 0xF8, + 0x47, 0x00, 0x00, 0x28, 0x02, 0xDA, 0x00, 0x20, 0x84, 0xF8, 0x47, 0x00, + 0x28, 0x68, 0x20, 0x61, 0x70, 0xBD, 0xF8, 0xB5, 0x04, 0x46, 0x29, 0x48, + 0x29, 0x4F, 0x0D, 0x46, 0x01, 0x78, 0x38, 0x68, 0x01, 0x26, 0xE1, 0xB1, + 0x90, 0xF8, 0xA2, 0x11, 0xAD, 0xF8, 0x02, 0x10, 0x90, 0xF8, 0xA3, 0x01, + 0xAD, 0xF8, 0x00, 0x00, 0x6A, 0x46, 0x29, 0x46, 0x04, 0xF1, 0x10, 0x00, + 0x00, 0xF0, 0xE9, 0xF8, 0xA0, 0xB1, 0x39, 0x68, 0xB4, 0xF8, 0x41, 0x00, + 0x91, 0xF8, 0xC4, 0x11, 0x01, 0xF0, 0x0F, 0x02, 0x90, 0x42, 0x1B, 0xD2, + 0x00, 0xF1, 0x01, 0x00, 0xA4, 0xF8, 0x41, 0x00, 0x2C, 0xE0, 0x90, 0xF8, + 0xA0, 0x11, 0xAD, 0xF8, 0x02, 0x10, 0x90, 0xF8, 0xA1, 0x01, 0xE1, 0xE7, + 0xB4, 0xF8, 0x43, 0x00, 0x38, 0xB1, 0xA0, 0xF1, 0x01, 0x00, 0xA4, 0xF8, + 0x43, 0x00, 0x20, 0x69, 0x28, 0x60, 0x38, 0x68, 0x15, 0xE0, 0x28, 0x68, + 0x20, 0x61, 0x4F, 0xF0, 0x00, 0x00, 0xE5, 0xE7, 0x07, 0xD1, 0x09, 0x07, + 0x05, 0xD0, 0x40, 0x1C, 0xA4, 0xF8, 0x41, 0x00, 0x28, 0x68, 0x20, 0x61, + 0x0C, 0xE0, 0x20, 0x69, 0x28, 0x60, 0x38, 0x68, 0x90, 0xF8, 0xC4, 0x11, + 0x09, 0x09, 0xA4, 0xF8, 0x43, 0x10, 0x90, 0xF8, 0x81, 0x01, 0x40, 0x07, + 0x00, 0xD4, 0x00, 0x26, 0x30, 0x46, 0xF8, 0xBD, 0xB8, 0x23, 0x10, 0x00, + 0x50, 0x24, 0x10, 0x00, 0x6D, 0x23, 0x10, 0x00, 0x89, 0x23, 0x10, 0x00, + 0x28, 0x49, 0x10, 0x00, 0x70, 0xB5, 0x04, 0x46, 0xFD, 0x4E, 0x0D, 0x46, + 0x01, 0x20, 0x94, 0xF8, 0x24, 0x10, 0x32, 0x68, 0x03, 0x46, 0x03, 0x29, + 0x08, 0xD0, 0x04, 0x29, 0x28, 0xD0, 0x07, 0x29, 0x26, 0xD0, 0x08, 0x29, + 0x01, 0xD1, 0xE1, 0x68, 0x29, 0x60, 0x70, 0xBD, 0x29, 0x68, 0x21, 0x61, + 0x92, 0xF8, 0x80, 0x11, 0x8D, 0x06, 0x4F, 0xF0, 0x00, 0x01, 0x06, 0xD5, + 0x92, 0xF8, 0xC4, 0x51, 0x2D, 0x09, 0xA4, 0xF8, 0x43, 0x50, 0xA4, 0xF8, + 0x41, 0x10, 0x92, 0xF8, 0x81, 0x51, 0x2D, 0x07, 0x06, 0xD5, 0x84, 0xF8, + 0x45, 0x10, 0x84, 0xF8, 0x46, 0x30, 0x7F, 0x23, 0x84, 0xF8, 0x47, 0x30, + 0x92, 0xF8, 0x80, 0x21, 0xD2, 0x06, 0xE0, 0xD5, 0x24, 0xF8, 0x48, 0x1F, + 0x61, 0x80, 0x70, 0xBD, 0x92, 0xF8, 0x81, 0x11, 0x09, 0x07, 0x08, 0xD5, + 0x29, 0x46, 0x20, 0x46, 0x00, 0xF0, 0xA0, 0xF8, 0x94, 0xF8, 0x45, 0x10, + 0x01, 0x29, 0x02, 0xD0, 0x70, 0xBD, 0x84, 0xF8, 0x45, 0x30, 0x31, 0x68, + 0x91, 0xF8, 0x80, 0x11, 0x8A, 0x06, 0x04, 0xD5, 0x29, 0x46, 0x20, 0x46, + 0xBD, 0xE8, 0x70, 0x40, 0x51, 0xE7, 0xC9, 0x06, 0xF0, 0xD5, 0x29, 0x46, + 0x20, 0x46, 0xBD, 0xE8, 0x70, 0x40, 0x00, 0xF0, 0xC8, 0xB8, 0x10, 0xB5, + 0xD3, 0x49, 0xD2, 0x4C, 0x00, 0x20, 0x08, 0x60, 0x20, 0x68, 0x90, 0xF8, + 0x81, 0x01, 0x80, 0x06, 0x05, 0xD5, 0xD0, 0x48, 0xFF, 0xF7, 0xEC, 0xFD, + 0xCE, 0x48, 0x07, 0xF0, 0xCD, 0xFC, 0x20, 0x68, 0x90, 0xF8, 0x81, 0x01, + 0x40, 0x06, 0x05, 0xD5, 0xCB, 0x48, 0x00, 0xF0, 0x25, 0xF8, 0xCA, 0x48, + 0x07, 0xF0, 0x9E, 0xFE, 0xBD, 0xE8, 0x10, 0x40, 0x07, 0xF0, 0x55, 0xBE, + 0x38, 0xB5, 0x05, 0x46, 0xC2, 0x4C, 0x00, 0x20, 0x00, 0x90, 0x21, 0x68, + 0x91, 0xF8, 0x81, 0x01, 0x80, 0x06, 0x02, 0xD5, 0xC0, 0x48, 0xFF, 0xF7, + 0xCD, 0xFD, 0x20, 0x68, 0x90, 0xF8, 0x81, 0x01, 0x40, 0x06, 0x02, 0xD5, + 0xBD, 0x48, 0x00, 0xF0, 0x09, 0xF8, 0x69, 0x46, 0x28, 0x46, 0x00, 0xF0, + 0xE7, 0xF8, 0x69, 0x46, 0x28, 0x46, 0x00, 0xF0, 0x4A, 0xF9, 0x38, 0xBD, + 0xB4, 0x49, 0x0A, 0x68, 0xB2, 0xF8, 0xB6, 0x21, 0x02, 0x80, 0x09, 0x68, + 0xD1, 0xF8, 0xB8, 0x21, 0x42, 0x60, 0x91, 0xF8, 0xB5, 0x11, 0x01, 0x72, + 0x70, 0x47, 0x10, 0xB5, 0xB2, 0xF9, 0x02, 0x30, 0xB2, 0xF9, 0x00, 0x20, + 0x5B, 0x43, 0x02, 0xFB, 0x02, 0x34, 0x00, 0xF0, 0x17, 0xFB, 0xA0, 0x42, + 0x01, 0xDD, 0x00, 0x20, 0x10, 0xBD, 0x01, 0x20, 0x10, 0xBD, 0xAA, 0x48, + 0x10, 0xB5, 0x03, 0x78, 0xA4, 0x48, 0x02, 0x68, 0x83, 0xB1, 0x92, 0xF8, + 0x99, 0x01, 0x92, 0xF8, 0x96, 0x31, 0x00, 0xF0, 0x0F, 0x04, 0x00, 0x09, + 0x92, 0xF8, 0x97, 0x21, 0x5B, 0x43, 0x52, 0x43, 0x99, 0x42, 0x02, 0xDD, + 0x91, 0x42, 0x0C, 0xDB, 0x20, 0x46, 0x10, 0xBD, 0x92, 0xF8, 0x98, 0x01, + 0x92, 0xF8, 0x94, 0x31, 0x00, 0xF0, 0x0F, 0x04, 0x00, 0x09, 0x5B, 0x43, + 0x92, 0xF8, 0x95, 0x21, 0xED, 0xE7, 0x9A, 0x42, 0x00, 0xD1, 0x52, 0x1C, + 0xC9, 0x1A, 0x04, 0x1B, 0x61, 0x43, 0xD2, 0x1A, 0x91, 0xFB, 0xF2, 0xF1, + 0x40, 0x1A, 0x10, 0xBD, 0xF8, 0xB5, 0x04, 0x46, 0x90, 0xF9, 0x47, 0x00, + 0x0F, 0x46, 0x01, 0x25, 0x20, 0xB1, 0x94, 0xF8, 0x46, 0x10, 0x01, 0x29, + 0x04, 0xD0, 0x2C, 0xE0, 0x01, 0x20, 0x84, 0xF8, 0x45, 0x00, 0xF8, 0xBD, + 0x8B, 0x48, 0x87, 0x4E, 0x01, 0x78, 0x30, 0x68, 0xB9, 0xB1, 0x90, 0xF8, + 0x92, 0x11, 0xAD, 0xF8, 0x02, 0x10, 0x90, 0xF8, 0x93, 0x01, 0xAD, 0xF8, + 0x00, 0x00, 0x6A, 0x46, 0x39, 0x46, 0x04, 0xF1, 0x10, 0x00, 0xFF, 0xF7, + 0xA0, 0xFF, 0x78, 0xB1, 0x20, 0x69, 0x38, 0x60, 0x30, 0x68, 0x90, 0xF8, + 0x81, 0x01, 0x40, 0x07, 0x13, 0xD4, 0x00, 0x25, 0x11, 0xE0, 0x90, 0xF8, + 0x90, 0x11, 0xAD, 0xF8, 0x02, 0x10, 0x90, 0xF8, 0x91, 0x01, 0xE6, 0xE7, + 0x00, 0x20, 0x84, 0xF8, 0x46, 0x00, 0x94, 0xF9, 0x47, 0x00, 0x00, 0x28, + 0x03, 0xDD, 0x39, 0x46, 0x20, 0x46, 0xFF, 0xF7, 0x3F, 0xFE, 0x28, 0x46, + 0xF8, 0xBD, 0xF0, 0xB5, 0x72, 0x4A, 0x6E, 0x4E, 0x01, 0x25, 0x13, 0x78, + 0x32, 0x68, 0xA3, 0xB1, 0x92, 0xF8, 0xC2, 0x31, 0x92, 0xF8, 0xC3, 0x41, + 0xB1, 0xF9, 0x02, 0x20, 0xB0, 0xF9, 0x12, 0x70, 0xD2, 0x1B, 0x00, 0xD5, + 0x52, 0x42, 0x12, 0xB2, 0x00, 0x27, 0x01, 0x2A, 0x0A, 0xDB, 0xB0, 0xF8, + 0x48, 0xC0, 0x62, 0x44, 0xA0, 0xF8, 0x48, 0x20, 0x06, 0xE0, 0x92, 0xF8, + 0xC0, 0x31, 0x92, 0xF8, 0xC1, 0x41, 0xE9, 0xE7, 0xA0, 0xF8, 0x48, 0x70, + 0xB1, 0xF9, 0x00, 0x20, 0xB0, 0xF9, 0x10, 0xC0, 0xB2, 0xEB, 0x0C, 0x02, + 0x00, 0xD5, 0x52, 0x42, 0x12, 0xB2, 0x01, 0x2A, 0x05, 0xDB, 0xB0, 0xF8, + 0x4A, 0xC0, 0x62, 0x44, 0xA0, 0xF8, 0x4A, 0x20, 0x01, 0xE0, 0xA0, 0xF8, + 0x4A, 0x70, 0xB0, 0xF8, 0x48, 0x20, 0x9A, 0x42, 0x03, 0xD8, 0xB0, 0xF8, + 0x4A, 0xC0, 0xA4, 0x45, 0x0E, 0xD9, 0x9A, 0x42, 0x03, 0xD9, 0x4A, 0x88, + 0x42, 0x82, 0xA0, 0xF8, 0x48, 0x70, 0xB0, 0xF8, 0x4A, 0x20, 0xA2, 0x42, + 0x0C, 0xD9, 0x09, 0x88, 0x01, 0x82, 0xA0, 0xF8, 0x4A, 0x70, 0x07, 0xE0, + 0x00, 0x69, 0x08, 0x60, 0x30, 0x68, 0x90, 0xF8, 0x81, 0x01, 0x40, 0x07, + 0x00, 0xD4, 0x00, 0x25, 0x28, 0x46, 0xF0, 0xBD, 0x2D, 0xE9, 0xFC, 0x47, + 0x0E, 0x46, 0xDF, 0xF8, 0x0C, 0xA1, 0x00, 0x21, 0x80, 0x46, 0x0A, 0x25, + 0x4F, 0xF0, 0x01, 0x09, 0xCA, 0xF8, 0x00, 0x10, 0x55, 0xE0, 0xD8, 0xF8, + 0x00, 0x10, 0x09, 0xFA, 0x05, 0xF0, 0x01, 0x42, 0x4F, 0xD0, 0x65, 0x20, + 0x05, 0xFB, 0x00, 0x84, 0x94, 0xF8, 0x2D, 0x00, 0x09, 0x34, 0x03, 0x28, + 0x05, 0xD0, 0x04, 0x28, 0x03, 0xD0, 0x07, 0x28, 0x01, 0xD0, 0x08, 0x28, + 0x41, 0xD1, 0x20, 0x68, 0x00, 0x90, 0x34, 0x48, 0x21, 0x68, 0x0C, 0x38, + 0x01, 0x27, 0x01, 0x60, 0xB4, 0xF8, 0x3D, 0x00, 0xAD, 0xF8, 0x04, 0x00, + 0x21, 0x46, 0x20, 0x1D, 0x00, 0xF0, 0x1C, 0xFA, 0xDA, 0xF8, 0x00, 0x20, + 0x90, 0x42, 0x01, 0xDD, 0xCA, 0xF8, 0x00, 0x00, 0x01, 0xAA, 0x69, 0x46, + 0x20, 0x46, 0xFF, 0xF7, 0xE4, 0xFC, 0x26, 0x48, 0x00, 0x68, 0x90, 0xF8, + 0x81, 0x01, 0x80, 0x07, 0x04, 0xD5, 0x69, 0x46, 0x20, 0x46, 0xFF, 0xF7, + 0x45, 0xFE, 0x07, 0x46, 0x94, 0xF8, 0x25, 0x00, 0x04, 0x28, 0x07, 0xD1, + 0x23, 0x48, 0x00, 0x78, 0x20, 0xB9, 0x94, 0xF8, 0x24, 0x00, 0x08, 0x28, + 0x00, 0xD0, 0x00, 0x27, 0x00, 0x98, 0x60, 0x61, 0xBD, 0xF8, 0x04, 0x00, + 0xA4, 0xF8, 0x3F, 0x00, 0x01, 0x2F, 0x08, 0xD1, 0x00, 0x98, 0xE0, 0x60, + 0x94, 0xF8, 0x26, 0x20, 0x31, 0x68, 0x09, 0xFA, 0x02, 0xF0, 0x01, 0x43, + 0x31, 0x60, 0x6D, 0x1E, 0xA7, 0xD2, 0xBD, 0xE8, 0xFC, 0x87, 0x2D, 0xE9, + 0xF0, 0x47, 0x89, 0x46, 0x07, 0x46, 0x04, 0x21, 0x00, 0x1D, 0x0A, 0xF0, + 0xB3, 0xFA, 0xC6, 0xB2, 0x00, 0x24, 0x4F, 0xF0, 0x01, 0x08, 0x39, 0x68, + 0x08, 0xFA, 0x04, 0xF0, 0x01, 0x42, 0x49, 0xD0, 0x65, 0x20, 0x04, 0xFB, + 0x00, 0x75, 0x95, 0xF8, 0x2D, 0x00, 0x09, 0x35, 0x03, 0x28, 0x13, 0xD0, + 0x04, 0x28, 0x17, 0xD0, 0x07, 0x28, 0x15, 0xD0, 0x08, 0x28, 0x13, 0xD0, + 0x3A, 0xE0, 0x00, 0x00, 0x50, 0x24, 0x10, 0x00, 0xDC, 0x23, 0x10, 0x00, + 0x95, 0x23, 0x10, 0x00, 0x28, 0x49, 0x10, 0x00, 0xB8, 0x23, 0x10, 0x00, + 0x2A, 0x24, 0x10, 0x00, 0x29, 0x46, 0x38, 0x46, 0x00, 0xF0, 0xA8, 0xF8, + 0x76, 0x1C, 0xF6, 0xB2, 0x95, 0xF8, 0x26, 0x20, 0xD9, 0xF8, 0x00, 0x10, + 0x08, 0xFA, 0x02, 0xF0, 0x01, 0x42, 0x13, 0xD0, 0x95, 0xF8, 0x24, 0x00, + 0x08, 0x28, 0x01, 0xD1, 0x76, 0x1E, 0xF6, 0xB2, 0x31, 0x46, 0x28, 0x46, + 0x04, 0xF0, 0x43, 0xFD, 0x0D, 0x48, 0x00, 0x68, 0x90, 0xF8, 0xE8, 0x07, + 0xC0, 0x06, 0x03, 0xD5, 0x31, 0x46, 0x28, 0x46, 0x04, 0xF0, 0xC4, 0xFD, + 0x95, 0xF8, 0x24, 0x00, 0x08, 0x28, 0x07, 0xD1, 0x29, 0x46, 0x38, 0x46, + 0x00, 0xF0, 0x97, 0xF8, 0x29, 0x46, 0x38, 0x46, 0x00, 0xF0, 0x72, 0xF8, + 0x64, 0x1C, 0x0A, 0x2C, 0xAD, 0xDB, 0xBD, 0xE8, 0xF0, 0x87, 0x00, 0x00, + 0x50, 0x24, 0x10, 0x00, 0x10, 0xB5, 0x4F, 0xF4, 0x7F, 0x71, 0x49, 0x48, + 0x08, 0xF0, 0x99, 0xF9, 0x4F, 0xF4, 0x44, 0x71, 0x47, 0x48, 0x08, 0xF0, + 0x94, 0xF9, 0x00, 0xF0, 0xEE, 0xFA, 0x00, 0xF0, 0x8D, 0xF8, 0xFF, 0xF7, + 0x80, 0xFA, 0xBD, 0xE8, 0x10, 0x40, 0xFF, 0xF7, 0x02, 0xBE, 0x10, 0xB5, + 0x41, 0x48, 0x00, 0x24, 0x44, 0x72, 0x3E, 0x48, 0x00, 0xF0, 0xE3, 0xFA, + 0x3C, 0x48, 0xFF, 0xF7, 0x78, 0xFA, 0x3B, 0x48, 0xFF, 0xF7, 0x14, 0xFE, + 0x3A, 0x48, 0x04, 0x70, 0x10, 0xBD, 0x10, 0xB5, 0x38, 0x4C, 0x20, 0x78, + 0x88, 0xB1, 0x38, 0x49, 0x48, 0x72, 0x21, 0x46, 0x34, 0x48, 0x00, 0xF0, + 0x30, 0xFB, 0x33, 0x48, 0x00, 0xF0, 0x6B, 0xF8, 0x31, 0x48, 0xFF, 0xF7, + 0x62, 0xFA, 0x30, 0x48, 0xFF, 0xF7, 0xFE, 0xFD, 0x00, 0x20, 0x20, 0x70, + 0x10, 0xBD, 0xBD, 0xE8, 0x10, 0x40, 0xD6, 0xE7, 0x10, 0xB5, 0x2C, 0x4C, + 0x01, 0x46, 0x20, 0x78, 0x0F, 0x28, 0x0C, 0xD2, 0x00, 0xEB, 0x80, 0x02, + 0x02, 0xEB, 0xC0, 0x00, 0x04, 0xEB, 0x80, 0x00, 0x34, 0x22, 0x00, 0x1D, + 0x08, 0xF0, 0xF5, 0xF8, 0x20, 0x78, 0x40, 0x1C, 0x20, 0x70, 0x10, 0xBD, + 0x22, 0x48, 0x00, 0x78, 0x70, 0x47, 0x21, 0x48, 0x70, 0x47, 0x10, 0xB5, + 0x00, 0x21, 0x02, 0x68, 0x01, 0x24, 0x04, 0xFA, 0x01, 0xF3, 0x1A, 0x42, + 0x04, 0xD1, 0x8C, 0x40, 0x22, 0x43, 0x02, 0x60, 0x48, 0xB2, 0x10, 0xBD, + 0x49, 0x1C, 0x0A, 0x29, 0xF3, 0xDB, 0x4F, 0xF0, 0xFF, 0x30, 0x10, 0xBD, + 0x10, 0xB5, 0x91, 0xF8, 0x26, 0x40, 0x01, 0x23, 0x02, 0x68, 0xA3, 0x40, + 0x9A, 0x43, 0x02, 0x60, 0x00, 0x20, 0x81, 0xF8, 0x24, 0x00, 0x10, 0xBD, + 0x30, 0xB5, 0x00, 0x22, 0x43, 0x68, 0x01, 0x25, 0x05, 0xFA, 0x02, 0xF4, + 0x23, 0x42, 0x05, 0xD1, 0x95, 0x40, 0x2B, 0x43, 0x43, 0x60, 0x81, 0xF8, + 0x27, 0x20, 0x30, 0xBD, 0x52, 0x1C, 0x0A, 0x2A, 0xF2, 0xDB, 0xFF, 0x20, + 0x81, 0xF8, 0x27, 0x00, 0x30, 0xBD, 0x10, 0xB5, 0x11, 0xF8, 0x27, 0x4F, + 0x42, 0x68, 0x01, 0x23, 0xA3, 0x40, 0x9A, 0x43, 0x42, 0x60, 0xFF, 0x20, + 0x08, 0x70, 0x10, 0xBD, 0x34, 0x49, 0x10, 0x00, 0x30, 0x4D, 0x10, 0x00, + 0x58, 0x25, 0x10, 0x00, 0x70, 0x47, 0x2D, 0xE9, 0xF0, 0x41, 0x0A, 0x25, + 0x06, 0x46, 0x01, 0x27, 0xDF, 0xF8, 0xA0, 0x80, 0x49, 0xE0, 0x30, 0x68, + 0x07, 0xFA, 0x05, 0xF1, 0x08, 0x42, 0x44, 0xD0, 0x65, 0x20, 0x05, 0xFB, + 0x00, 0x64, 0x94, 0xF8, 0x2D, 0x00, 0x09, 0x34, 0x01, 0x28, 0x01, 0xD0, + 0x02, 0x28, 0x3A, 0xD1, 0x94, 0xF8, 0x25, 0x00, 0x02, 0x28, 0x06, 0xD0, + 0x03, 0x28, 0x04, 0xD0, 0x01, 0x28, 0x1E, 0xD0, 0x04, 0x28, 0x30, 0xD1, + 0x25, 0xE0, 0x1B, 0x48, 0x94, 0xF8, 0x2D, 0x10, 0xB0, 0xF9, 0x00, 0x00, + 0xC9, 0x06, 0x02, 0xD5, 0x18, 0x48, 0xB0, 0xF9, 0x00, 0x00, 0xB4, 0xF9, + 0x4C, 0x10, 0x81, 0x42, 0x21, 0xDA, 0xB8, 0xF9, 0x00, 0x00, 0x81, 0x42, + 0x19, 0xDB, 0x00, 0xF0, 0x67, 0xFF, 0x01, 0x28, 0x15, 0xD1, 0x04, 0x20, + 0x84, 0xF8, 0x25, 0x00, 0x10, 0x48, 0x07, 0x70, 0x13, 0xE0, 0xB4, 0xF8, + 0x2D, 0x10, 0xB4, 0xF9, 0x4E, 0x00, 0x00, 0x22, 0x01, 0xF0, 0xA6, 0xFE, + 0xB4, 0xF9, 0x4C, 0x10, 0x03, 0xE0, 0xB4, 0xF9, 0x4C, 0x10, 0xB8, 0xF9, + 0x00, 0x00, 0x81, 0x42, 0x03, 0xDA, 0x21, 0x46, 0x30, 0x46, 0xFF, 0xF7, + 0x7B, 0xFF, 0x6D, 0x1E, 0xB3, 0xD2, 0xBD, 0xE8, 0xF0, 0x81, 0x00, 0x00, + 0xCA, 0x23, 0x10, 0x00, 0xC6, 0x23, 0x10, 0x00, 0xD4, 0x23, 0x10, 0x00, + 0x07, 0x24, 0x10, 0x00, 0x70, 0xB5, 0x16, 0x46, 0x0D, 0x46, 0x04, 0x46, + 0x01, 0x2B, 0x05, 0xD0, 0x00, 0xF0, 0xCA, 0xFA, 0xA8, 0x7B, 0x01, 0x28, + 0x28, 0xD0, 0x29, 0xE0, 0x01, 0x20, 0x84, 0xF8, 0x24, 0x00, 0xA8, 0x7B, + 0x84, 0xF8, 0x25, 0x00, 0x00, 0x20, 0xA4, 0xF8, 0x2F, 0x00, 0xA0, 0x65, + 0x84, 0xF8, 0x60, 0x00, 0xA4, 0xF8, 0x61, 0x00, 0xA4, 0xF8, 0x63, 0x00, + 0x84, 0xF8, 0x2C, 0x00, 0xA8, 0x7B, 0x01, 0x28, 0x01, 0xD1, 0x68, 0x68, + 0x28, 0x60, 0x21, 0x46, 0x03, 0x20, 0x03, 0xE0, 0x01, 0xEB, 0x80, 0x02, + 0x2B, 0x68, 0x13, 0x60, 0x40, 0x1E, 0xF9, 0xD2, 0xF7, 0x48, 0x00, 0x68, + 0x90, 0xF8, 0xA3, 0x13, 0x02, 0x20, 0x03, 0xF0, 0x02, 0xFD, 0x0E, 0xE0, + 0x68, 0x68, 0x28, 0x60, 0xA0, 0x6D, 0x40, 0x1C, 0xA0, 0x65, 0x02, 0x20, + 0x04, 0xEB, 0x80, 0x01, 0x40, 0x1E, 0x51, 0xF8, 0x04, 0x2C, 0x0A, 0x60, + 0xF8, 0xD1, 0x29, 0x68, 0x21, 0x60, 0x84, 0xF8, 0x26, 0x60, 0x68, 0x7E, + 0x84, 0xF8, 0x28, 0x00, 0x28, 0x7E, 0x84, 0xF8, 0x2B, 0x00, 0x68, 0x8C, + 0xA4, 0xF8, 0x37, 0x00, 0xA8, 0x8B, 0xA4, 0xF8, 0x31, 0x00, 0x28, 0x8C, + 0xA4, 0xF8, 0x35, 0x00, 0xE8, 0x8B, 0xA4, 0xF8, 0x33, 0x00, 0xA8, 0x8C, + 0xA4, 0xF8, 0x39, 0x00, 0xE8, 0x8C, 0xA4, 0xF8, 0x3B, 0x00, 0xA8, 0x8D, + 0xA4, 0xF8, 0x3D, 0x00, 0x28, 0x8D, 0xA4, 0xF8, 0x4C, 0x00, 0xE8, 0x6A, + 0x20, 0x65, 0x28, 0x6B, 0x60, 0x65, 0x68, 0x8D, 0xA4, 0xF8, 0x4E, 0x00, + 0x68, 0x8B, 0xA4, 0xF8, 0x2D, 0x00, 0xD8, 0x48, 0x00, 0x78, 0x10, 0xF0, + 0x30, 0x0F, 0x05, 0xD0, 0xB4, 0xF8, 0x2F, 0x00, 0x40, 0xF0, 0x80, 0x00, + 0xA4, 0xF8, 0x2F, 0x00, 0xD5, 0xF8, 0x0A, 0x00, 0x20, 0x62, 0x70, 0xBD, + 0x10, 0xB5, 0x53, 0x88, 0x4C, 0x88, 0x1B, 0x1B, 0x43, 0x80, 0x12, 0x88, + 0x09, 0x88, 0x51, 0x1A, 0x01, 0x80, 0x10, 0xBD, 0x08, 0xB5, 0x0A, 0x46, + 0x01, 0x46, 0x68, 0x46, 0xFF, 0xF7, 0xF0, 0xFF, 0xBD, 0xF9, 0x00, 0x10, + 0xBD, 0xF9, 0x02, 0x00, 0x49, 0x43, 0x00, 0xFB, 0x00, 0x10, 0x08, 0xBD, + 0x2D, 0xE9, 0xFF, 0x4F, 0xC2, 0x48, 0x88, 0x46, 0xAD, 0xF5, 0x69, 0x7D, + 0x00, 0x68, 0x4F, 0xF0, 0x00, 0x0A, 0x9B, 0x46, 0xC1, 0x8B, 0xCD, 0xF8, + 0x00, 0xA0, 0x01, 0xEB, 0x81, 0x01, 0xC1, 0xF3, 0x97, 0x11, 0x01, 0xFB, + 0x01, 0xF9, 0xBC, 0x49, 0x6F, 0x46, 0x09, 0x78, 0x31, 0xB1, 0xB0, 0xF8, + 0x84, 0x61, 0xBA, 0x4A, 0x11, 0x78, 0x01, 0x29, 0x03, 0xD0, 0x0A, 0xE0, + 0xB0, 0xF8, 0x82, 0x61, 0xF7, 0xE7, 0xB0, 0xF8, 0x86, 0x11, 0x21, 0xB1, + 0x0E, 0x46, 0x00, 0x21, 0x11, 0x70, 0x4F, 0xF0, 0x01, 0x0A, 0xB3, 0x49, + 0x09, 0x78, 0x01, 0x29, 0x01, 0xD1, 0xB0, 0xF8, 0xC9, 0x60, 0x90, 0xF8, + 0x88, 0x01, 0x76, 0x43, 0x00, 0x25, 0xE5, 0x90, 0xE9, 0x98, 0x01, 0x68, + 0x01, 0x20, 0xA8, 0x40, 0x01, 0x42, 0x6C, 0xD0, 0x65, 0x20, 0xE9, 0x99, + 0x68, 0x43, 0x00, 0xEB, 0x01, 0x0C, 0x9C, 0xF8, 0x2D, 0x00, 0x0C, 0xF1, + 0x09, 0x0C, 0x07, 0x28, 0xF3, 0xD0, 0x61, 0x46, 0x08, 0x1D, 0xFF, 0xF7, + 0xA9, 0xFF, 0xE5, 0x99, 0x48, 0x43, 0x00, 0xFB, 0x01, 0xF4, 0xB4, 0x42, + 0x00, 0xDA, 0x34, 0x46, 0x62, 0x46, 0x11, 0x1D, 0xE3, 0xA8, 0xFF, 0xF7, + 0x93, 0xFF, 0x0C, 0xF1, 0x04, 0x02, 0x11, 0x1D, 0xE6, 0xA8, 0xFF, 0xF7, + 0x8D, 0xFF, 0x00, 0x20, 0xAD, 0xF8, 0x8A, 0x03, 0xAD, 0xF8, 0x88, 0x03, + 0x9C, 0xF8, 0x24, 0x00, 0x06, 0x28, 0x07, 0xD1, 0x03, 0x20, 0x8C, 0xF8, + 0x60, 0x00, 0x00, 0x20, 0xAC, 0xF8, 0x61, 0x00, 0xAC, 0xF8, 0x63, 0x00, + 0xDC, 0xF8, 0x58, 0x10, 0x01, 0x29, 0x3D, 0xDD, 0x9C, 0xF8, 0x60, 0x00, + 0x90, 0xBB, 0xE3, 0xAA, 0xE6, 0xA9, 0xE2, 0xA8, 0xFF, 0xF7, 0x70, 0xFF, + 0x00, 0x20, 0xAD, 0xF8, 0x92, 0x03, 0xAD, 0xF8, 0x90, 0x03, 0xBC, 0xF9, + 0x61, 0x00, 0xBD, 0xF9, 0x8A, 0x13, 0x08, 0x44, 0x40, 0x10, 0xAC, 0xF8, + 0x61, 0x00, 0xBC, 0xF9, 0x63, 0x00, 0xBD, 0xF9, 0x88, 0x13, 0x08, 0x44, + 0x40, 0x10, 0xAC, 0xF8, 0x63, 0x00, 0xE3, 0xA9, 0xE4, 0xA8, 0xFF, 0xF7, + 0x61, 0xFF, 0x48, 0x45, 0x05, 0xD8, 0xE2, 0xA9, 0xE4, 0xA8, 0xFF, 0xF7, + 0x5B, 0xFF, 0x48, 0x45, 0x0E, 0xD9, 0xBD, 0xF8, 0x8E, 0x03, 0xBC, 0xF8, + 0x61, 0x10, 0x08, 0x44, 0xAD, 0xF8, 0x8A, 0x03, 0xBD, 0xF8, 0x8C, 0x03, + 0xBC, 0xF8, 0x63, 0x10, 0x08, 0x44, 0x04, 0xE0, 0x07, 0xE0, 0x75, 0xE0, + 0x00, 0x20, 0xAD, 0xF8, 0x8A, 0x03, 0xAD, 0xF8, 0x88, 0x03, 0x3A, 0xE0, + 0x09, 0xD0, 0x9C, 0xF8, 0x60, 0x00, 0x03, 0x28, 0x05, 0xD0, 0x01, 0x28, + 0x03, 0xD0, 0x49, 0xB3, 0x02, 0x28, 0x27, 0xD0, 0x2F, 0xE0, 0x00, 0x20, + 0xAD, 0xF8, 0x92, 0x03, 0xAD, 0xF8, 0x90, 0x03, 0xE3, 0xA9, 0xE4, 0xA8, + 0xFF, 0xF7, 0x30, 0xFF, 0x48, 0x45, 0x24, 0xD9, 0xBD, 0xF8, 0x8E, 0x03, + 0xAD, 0xF8, 0x8A, 0x03, 0xBD, 0xF8, 0x8C, 0x03, 0xAD, 0xF8, 0x88, 0x03, + 0xBA, 0xF1, 0x00, 0x0F, 0x19, 0xD1, 0x9C, 0xF8, 0x60, 0x00, 0x28, 0xB1, + 0xC6, 0xEB, 0xC6, 0x00, 0xA0, 0x42, 0x15, 0xDD, 0x04, 0x46, 0x13, 0xE0, + 0x06, 0xEB, 0xC6, 0x00, 0x00, 0xEB, 0x06, 0x10, 0xA0, 0x42, 0x12, 0xDD, + 0x04, 0x46, 0x10, 0xE0, 0xBA, 0xF1, 0x00, 0x0F, 0x05, 0xD1, 0x02, 0x28, + 0x16, 0xD0, 0x06, 0xEB, 0x06, 0x10, 0x00, 0xEB, 0x46, 0x14, 0x9C, 0xF8, + 0x60, 0x00, 0x20, 0xB1, 0x9C, 0xF8, 0x60, 0x00, 0x40, 0x1E, 0x8C, 0xF8, + 0x60, 0x00, 0xBD, 0xF9, 0x88, 0x33, 0xBD, 0xF9, 0x8A, 0x23, 0x61, 0x46, + 0xE7, 0xA8, 0x00, 0xF0, 0xA5, 0xF9, 0x4F, 0xF0, 0x00, 0x0C, 0x1D, 0xE0, + 0xC6, 0xEB, 0xC6, 0x04, 0xEC, 0xE7, 0x0C, 0xEB, 0x8C, 0x00, 0x00, 0xEB, + 0xCC, 0x01, 0x08, 0xEB, 0x81, 0x01, 0xE7, 0xA8, 0x09, 0x1D, 0xFF, 0xF7, + 0xE9, 0xFE, 0x01, 0x46, 0xA0, 0x42, 0x0B, 0xDA, 0x38, 0x68, 0x00, 0xEB, + 0x40, 0x00, 0x07, 0xEB, 0x40, 0x00, 0x41, 0x60, 0x80, 0xF8, 0x09, 0xC0, + 0x05, 0x72, 0x38, 0x68, 0x40, 0x1C, 0x38, 0x60, 0x0C, 0xF1, 0x01, 0x0C, + 0x98, 0xF8, 0x00, 0x00, 0x60, 0x45, 0xE0, 0xD8, 0x6D, 0x1C, 0x0A, 0x2D, + 0xFF, 0xF4, 0x12, 0xAF, 0x38, 0x68, 0x00, 0x28, 0x41, 0xD0, 0x38, 0x46, + 0x00, 0xF0, 0x52, 0xF9, 0x00, 0x24, 0x39, 0xE0, 0x04, 0xEB, 0x44, 0x00, + 0x07, 0xEB, 0x40, 0x00, 0xEB, 0x9A, 0x90, 0xF9, 0x08, 0x10, 0x01, 0x23, + 0x15, 0x68, 0x90, 0xF9, 0x09, 0x00, 0x03, 0xFA, 0x01, 0xF2, 0x15, 0x42, + 0x29, 0xD1, 0xDB, 0xF8, 0x00, 0x60, 0x83, 0x40, 0x1E, 0x42, 0x24, 0xD1, + 0x15, 0x43, 0xEB, 0x9A, 0x15, 0x60, 0xDB, 0xF8, 0x00, 0x20, 0x1A, 0x43, + 0xCB, 0xF8, 0x00, 0x20, 0x65, 0x22, 0x51, 0x43, 0xE9, 0x9A, 0x00, 0x23, + 0x8D, 0x18, 0x00, 0xEB, 0x80, 0x01, 0x01, 0xEB, 0xC0, 0x01, 0x95, 0xF9, + 0x2F, 0x20, 0x08, 0xEB, 0x81, 0x01, 0x09, 0x35, 0x28, 0x46, 0x09, 0x1D, + 0xFF, 0xF7, 0x14, 0xFE, 0x95, 0xF8, 0x24, 0x00, 0x03, 0x28, 0x03, 0xD0, + 0x06, 0x28, 0x01, 0xD0, 0x04, 0x28, 0x02, 0xD1, 0x04, 0x20, 0x85, 0xF8, + 0x24, 0x00, 0x64, 0x1C, 0x38, 0x68, 0xA0, 0x42, 0xC2, 0xDC, 0x0D, 0xF5, + 0x6D, 0x7D, 0xBD, 0xE8, 0xF0, 0x8F, 0x11, 0x49, 0x00, 0x20, 0x08, 0x70, + 0x70, 0x47, 0x2D, 0xE9, 0xF0, 0x41, 0x0B, 0x4F, 0x06, 0x46, 0x00, 0x25, + 0x4F, 0xF0, 0x01, 0x08, 0x31, 0x68, 0x08, 0xFA, 0x05, 0xF0, 0x01, 0x42, + 0x4E, 0xD0, 0x65, 0x20, 0x05, 0xFB, 0x00, 0x64, 0x94, 0xF8, 0x2D, 0x00, + 0x09, 0x34, 0x03, 0x28, 0x0E, 0xD0, 0x04, 0x28, 0x0C, 0xD0, 0x02, 0x28, + 0x38, 0xD0, 0x41, 0xE0, 0x50, 0x24, 0x10, 0x00, 0x1C, 0x24, 0x10, 0x00, + 0xB8, 0x23, 0x10, 0x00, 0xC4, 0x23, 0x10, 0x00, 0x6D, 0x23, 0x10, 0x00, + 0x05, 0x20, 0x84, 0xF8, 0x24, 0x00, 0x38, 0x68, 0x90, 0xF8, 0xA4, 0x13, + 0x03, 0x20, 0x03, 0xF0, 0x06, 0xFB, 0x38, 0x68, 0x90, 0xF8, 0x81, 0x11, + 0xC9, 0x06, 0x07, 0xD4, 0x90, 0xF8, 0x80, 0x01, 0xC0, 0x07, 0x25, 0xD0, + 0x9F, 0x48, 0x00, 0x78, 0x01, 0x28, 0x21, 0xD1, 0x21, 0x46, 0x20, 0x1D, + 0xFF, 0xF7, 0x46, 0xFE, 0x01, 0x46, 0x9C, 0x48, 0x00, 0x78, 0x00, 0x28, + 0x38, 0x68, 0x0A, 0xD0, 0xB0, 0xF8, 0xAA, 0x01, 0x40, 0x43, 0x81, 0x42, + 0x12, 0xDD, 0x34, 0xF8, 0x2F, 0x0F, 0x40, 0xF0, 0x02, 0x00, 0x20, 0x80, + 0x0C, 0xE0, 0xB0, 0xF8, 0xA8, 0x01, 0xF3, 0xE7, 0x38, 0x68, 0x90, 0xF8, + 0xA4, 0x13, 0x03, 0x20, 0x03, 0xF0, 0xDB, 0xFA, 0x21, 0x46, 0x30, 0x46, + 0xFF, 0xF7, 0x10, 0xFD, 0x6D, 0x1C, 0x0A, 0x2D, 0xA8, 0xD3, 0xBD, 0xE8, + 0xF0, 0x81, 0x2D, 0xE9, 0xFC, 0x47, 0x05, 0x46, 0x00, 0x68, 0x0E, 0x46, + 0x10, 0xB3, 0x00, 0x20, 0x00, 0x90, 0x01, 0x90, 0x6B, 0x46, 0x01, 0xAA, + 0x28, 0x46, 0xFF, 0xF7, 0x23, 0xFE, 0x00, 0x24, 0xDF, 0xF8, 0x10, 0x92, + 0x4F, 0xF0, 0x05, 0x08, 0x01, 0x27, 0x29, 0x68, 0x07, 0xFA, 0x04, 0xF0, + 0x01, 0x42, 0x35, 0xD0, 0x01, 0x99, 0x08, 0x42, 0x32, 0xD1, 0x65, 0x20, + 0x04, 0xFB, 0x00, 0x51, 0x91, 0xF8, 0x2D, 0x00, 0x09, 0x31, 0x03, 0x28, + 0x1D, 0xD0, 0x04, 0x28, 0x1B, 0xD0, 0x02, 0x28, 0x23, 0xD0, 0x25, 0xE0, + 0x34, 0x78, 0x12, 0xE0, 0x28, 0x46, 0xFF, 0xF7, 0xCA, 0xFC, 0x02, 0x00, + 0x0D, 0xD4, 0x65, 0x20, 0x04, 0xEB, 0x84, 0x01, 0x00, 0xFB, 0x02, 0x50, + 0x01, 0xEB, 0xC4, 0x01, 0x06, 0xEB, 0x81, 0x01, 0x01, 0x23, 0x09, 0x30, + 0x09, 0x1D, 0xFF, 0xF7, 0x5F, 0xFD, 0x64, 0x1E, 0xEA, 0xD2, 0xBD, 0xE8, + 0xFC, 0x87, 0x81, 0xF8, 0x24, 0x80, 0xD9, 0xF8, 0x00, 0x00, 0x90, 0xF8, + 0xA4, 0x13, 0x03, 0x20, 0x03, 0xF0, 0x87, 0xFA, 0x02, 0xE0, 0x28, 0x46, + 0xFF, 0xF7, 0xBC, 0xFC, 0x64, 0x1C, 0x0A, 0x2C, 0xC1, 0xD3, 0x34, 0x78, + 0x17, 0xE0, 0x00, 0x99, 0x07, 0xFA, 0x04, 0xF0, 0x08, 0x42, 0x12, 0xD1, + 0x28, 0x46, 0xFF, 0xF7, 0x9C, 0xFC, 0x02, 0x00, 0x0D, 0xD4, 0x65, 0x20, + 0x04, 0xEB, 0x84, 0x01, 0x00, 0xFB, 0x02, 0x50, 0x01, 0xEB, 0xC4, 0x01, + 0x06, 0xEB, 0x81, 0x01, 0x01, 0x23, 0x09, 0x30, 0x09, 0x1D, 0xFF, 0xF7, + 0x31, 0xFD, 0x64, 0x1E, 0xE5, 0xD2, 0xD0, 0xE7, 0x70, 0xB5, 0x04, 0x46, + 0x90, 0xF8, 0x25, 0x00, 0x0D, 0x46, 0x04, 0x28, 0x33, 0xD1, 0xA8, 0x7B, + 0x00, 0x26, 0x04, 0x28, 0x2D, 0xD0, 0x94, 0xF8, 0x24, 0x00, 0x02, 0x28, + 0x14, 0xD0, 0x03, 0x28, 0x01, 0xD0, 0x04, 0x28, 0x27, 0xD1, 0x4B, 0x48, + 0x94, 0xF8, 0x2C, 0x10, 0x00, 0x68, 0x90, 0xF8, 0xFF, 0x01, 0x00, 0xF0, + 0x0F, 0x02, 0x48, 0x48, 0x91, 0x42, 0x00, 0x78, 0x0B, 0xD9, 0x84, 0xF8, + 0x2C, 0x60, 0x01, 0x28, 0x04, 0xD0, 0x11, 0xE0, 0x20, 0x46, 0xFE, 0xF7, + 0x81, 0xFE, 0x09, 0xE0, 0xFE, 0xF7, 0x69, 0xFE, 0x06, 0xE0, 0x01, 0x28, + 0x0D, 0xD1, 0x49, 0x1C, 0x84, 0xF8, 0x2C, 0x10, 0x04, 0x20, 0xA8, 0x73, + 0x94, 0xF8, 0x25, 0x00, 0x04, 0x28, 0x04, 0xD1, 0xA8, 0x7B, 0x04, 0x28, + 0x01, 0xD1, 0x84, 0xF8, 0x2C, 0x60, 0x70, 0xBD, 0x7C, 0xB5, 0x00, 0x22, + 0x1C, 0xE0, 0x02, 0xEB, 0x42, 0x03, 0x51, 0x1C, 0x00, 0xEB, 0x43, 0x03, + 0x12, 0xE0, 0x01, 0xEB, 0x41, 0x04, 0x00, 0xEB, 0x44, 0x04, 0x5E, 0x68, + 0x65, 0x68, 0xAE, 0x42, 0x09, 0xDD, 0x00, 0x96, 0x1E, 0x89, 0xAD, 0xF8, + 0x04, 0x60, 0x5D, 0x60, 0x25, 0x89, 0x1D, 0x81, 0x00, 0x9D, 0x65, 0x60, + 0x26, 0x81, 0x49, 0x1C, 0x04, 0x68, 0x8C, 0x42, 0xE9, 0xDC, 0x52, 0x1C, + 0x01, 0x68, 0x91, 0x42, 0xDF, 0xDC, 0x7C, 0xBD, 0xF0, 0xB5, 0x24, 0x4C, + 0xB1, 0xF9, 0x02, 0x60, 0x24, 0x68, 0x16, 0xEB, 0x02, 0x0C, 0xB4, 0xF9, + 0x16, 0x50, 0xB4, 0xF9, 0x18, 0x70, 0x4F, 0xF4, 0x80, 0x74, 0x01, 0xD5, + 0x35, 0x02, 0x03, 0xE0, 0xAC, 0x45, 0x07, 0xDD, 0xAD, 0x1B, 0x2D, 0x02, + 0x95, 0xFB, 0xF2, 0xF5, 0x00, 0x2D, 0x02, 0xDA, 0x6D, 0x42, 0x00, 0xE0, + 0x25, 0x46, 0xB1, 0xF9, 0x00, 0xC0, 0x1C, 0xEB, 0x03, 0x0E, 0x02, 0xD5, + 0x4F, 0xEA, 0x0C, 0x24, 0x04, 0xE0, 0xBE, 0x45, 0x07, 0xDD, 0xA7, 0xEB, + 0x0C, 0x04, 0x24, 0x02, 0x94, 0xFB, 0xF3, 0xF4, 0x00, 0x2C, 0x00, 0xDA, + 0x64, 0x42, 0xA5, 0x42, 0x06, 0xDA, 0x02, 0xFB, 0x05, 0xF2, 0x4F, 0xEA, + 0x22, 0x22, 0x03, 0xFB, 0x05, 0xF3, 0x06, 0xE0, 0x07, 0xDD, 0x02, 0xFB, + 0x04, 0xF2, 0x4F, 0xEA, 0x22, 0x22, 0x03, 0xFB, 0x04, 0xF3, 0x4F, 0xEA, + 0x23, 0x23, 0x32, 0x44, 0x42, 0x80, 0x09, 0x88, 0x19, 0x44, 0x01, 0x80, + 0xF0, 0xBD, 0x00, 0x00, 0x55, 0x23, 0x10, 0x00, 0xB8, 0x23, 0x10, 0x00, + 0x50, 0x24, 0x10, 0x00, 0x2A, 0x24, 0x10, 0x00, 0x2D, 0xE9, 0xF0, 0x47, + 0x99, 0x46, 0x15, 0x46, 0x0F, 0x46, 0x82, 0x46, 0x00, 0x26, 0x94, 0x78, + 0x4F, 0xF0, 0x01, 0x08, 0x16, 0xE0, 0xE1, 0xB2, 0x50, 0x46, 0x09, 0xF0, + 0x6D, 0xFB, 0x03, 0x46, 0x00, 0x21, 0x28, 0x78, 0x95, 0xF8, 0x01, 0xC0, + 0x07, 0xE0, 0x1A, 0x5C, 0xBA, 0x42, 0x03, 0xD1, 0x08, 0xFA, 0x00, 0xF2, + 0x11, 0x43, 0x01, 0x26, 0x40, 0x1C, 0x84, 0x45, 0xF5, 0xD2, 0x49, 0xF8, + 0x24, 0x10, 0x64, 0x1C, 0xE8, 0x78, 0xA0, 0x42, 0xE5, 0xD2, 0x30, 0x46, + 0xBD, 0xE8, 0xF0, 0x87, 0x2D, 0xE9, 0xFF, 0x4F, 0xFF, 0x48, 0x4F, 0xF0, + 0x00, 0x0B, 0x83, 0xB0, 0x00, 0x68, 0x89, 0x46, 0x4F, 0xF4, 0x80, 0x3A, + 0xB0, 0xF8, 0x4C, 0x01, 0x00, 0x90, 0xD8, 0x46, 0x5D, 0x46, 0x5F, 0x46, + 0x5E, 0x46, 0x8C, 0x78, 0x26, 0xE0, 0x05, 0x98, 0xE1, 0xB2, 0x00, 0x69, + 0x09, 0xF0, 0x46, 0xFB, 0x99, 0xF8, 0x00, 0x10, 0x4F, 0xF0, 0x01, 0x0E, + 0x99, 0xF8, 0x01, 0x30, 0x17, 0xE0, 0x03, 0x9A, 0x52, 0xF8, 0x24, 0xC0, + 0x0E, 0xFA, 0x01, 0xF2, 0x1C, 0xEA, 0x02, 0x0F, 0x0E, 0xD0, 0x30, 0xF9, + 0x11, 0x20, 0xDD, 0xF8, 0x00, 0xC0, 0x62, 0x45, 0x08, 0xDD, 0x01, 0xFB, + 0x02, 0x77, 0x04, 0xFB, 0x02, 0x66, 0x15, 0x44, 0x08, 0xF1, 0x01, 0x02, + 0x1F, 0xFA, 0x82, 0xF8, 0x49, 0x1C, 0x8B, 0x42, 0xE5, 0xDA, 0x64, 0x1C, + 0x99, 0xF8, 0x03, 0x00, 0xA0, 0x42, 0xD4, 0xDA, 0xE1, 0x48, 0x00, 0x21, + 0xF3, 0x17, 0x02, 0x68, 0x91, 0x46, 0x10, 0x8B, 0xA0, 0xFB, 0x06, 0x24, + 0x01, 0xFB, 0x06, 0x41, 0x00, 0xFB, 0x03, 0x14, 0xA2, 0xFB, 0x0A, 0x06, + 0x04, 0xFB, 0x0A, 0x61, 0x02, 0xFB, 0x0B, 0x11, 0x99, 0xF8, 0x15, 0x20, + 0x52, 0x1E, 0x85, 0xFB, 0x02, 0x23, 0x07, 0xF0, 0xDF, 0xFB, 0x0E, 0x46, + 0x04, 0x46, 0x02, 0x22, 0x00, 0x23, 0x50, 0x46, 0x59, 0x46, 0x07, 0xF0, + 0xD7, 0xFB, 0xCD, 0xE9, 0x00, 0x10, 0x00, 0x19, 0x71, 0x41, 0x52, 0x46, + 0x5B, 0x46, 0x07, 0xF0, 0xCF, 0xFB, 0x02, 0x90, 0xB9, 0xF8, 0x16, 0x00, + 0x00, 0x21, 0xA0, 0xFB, 0x07, 0x24, 0x01, 0xFB, 0x07, 0x41, 0xFB, 0x17, + 0x00, 0xFB, 0x03, 0x14, 0xA2, 0xFB, 0x0A, 0x06, 0x04, 0xFB, 0x0A, 0x61, + 0x02, 0xFB, 0x0B, 0x11, 0x99, 0xF8, 0x14, 0x20, 0x52, 0x1E, 0x85, 0xFB, + 0x02, 0x23, 0x07, 0xF0, 0xB7, 0xFB, 0x03, 0x46, 0x0A, 0x46, 0xDD, 0xE9, + 0x00, 0x10, 0xC0, 0x18, 0x51, 0x41, 0x52, 0x46, 0x5B, 0x46, 0x07, 0xF0, + 0xAD, 0xFB, 0x05, 0x99, 0x0D, 0x63, 0x05, 0x9A, 0xA2, 0xF8, 0x1E, 0x80, + 0x06, 0x99, 0x48, 0x60, 0x06, 0x99, 0x02, 0x98, 0x08, 0x60, 0x07, 0xB0, + 0xBD, 0xE8, 0xF0, 0x8F, 0x2D, 0xE9, 0xFF, 0x4F, 0x82, 0x46, 0xB4, 0x48, + 0x4F, 0xF0, 0x00, 0x09, 0x93, 0xB0, 0x00, 0x68, 0x14, 0x46, 0x8E, 0x46, + 0x90, 0xF8, 0xD0, 0x01, 0x4F, 0xF4, 0x80, 0x35, 0xCC, 0x46, 0x4F, 0x46, + 0x40, 0x07, 0xA1, 0xF1, 0x01, 0x06, 0x39, 0xD5, 0x11, 0x92, 0xD0, 0x46, + 0x68, 0x46, 0x73, 0x46, 0x72, 0x46, 0x04, 0xE0, 0x00, 0xEB, 0x42, 0x04, + 0x38, 0xF8, 0x12, 0x10, 0x61, 0x80, 0x52, 0x1E, 0xF8, 0xD2, 0x41, 0x88, + 0x01, 0x80, 0x00, 0xEB, 0x43, 0x02, 0x30, 0xF8, 0x13, 0x10, 0x51, 0x80, + 0x19, 0x46, 0x0C, 0xE0, 0x00, 0xEB, 0x41, 0x0B, 0x30, 0xF8, 0x11, 0x40, + 0xBB, 0xF8, 0x04, 0x20, 0x14, 0x44, 0xBB, 0xF8, 0x02, 0x20, 0x04, 0xEB, + 0x42, 0x02, 0x28, 0xF8, 0x11, 0x20, 0x49, 0x1E, 0xF0, 0xD2, 0x9A, 0x48, + 0x11, 0x9C, 0x05, 0xE0, 0x38, 0xF9, 0x13, 0x10, 0x81, 0x42, 0x01, 0xDD, + 0x08, 0x46, 0xDC, 0xB2, 0x5B, 0x1E, 0xF7, 0xD2, 0x0C, 0xB9, 0xBD, 0xF9, + 0x00, 0xC0, 0xB4, 0x42, 0x04, 0xDB, 0x69, 0x46, 0x01, 0xEB, 0x4E, 0x00, + 0x30, 0xF9, 0x02, 0x7C, 0x1C, 0xB1, 0x0A, 0xEB, 0x44, 0x00, 0x30, 0xF9, + 0x02, 0xCC, 0x3A, 0xF9, 0x14, 0xB0, 0xB4, 0x42, 0x03, 0xDA, 0x0A, 0xEB, + 0x44, 0x00, 0xB0, 0xF9, 0x02, 0x70, 0x60, 0x46, 0x3A, 0x46, 0xBC, 0x45, + 0x01, 0xDD, 0x02, 0x46, 0x38, 0x46, 0xA7, 0xEB, 0x0C, 0x01, 0xA1, 0xFB, + 0x05, 0x78, 0x4F, 0xEA, 0xE1, 0x7C, 0x0C, 0xFB, 0x05, 0x8C, 0x5A, 0x44, + 0x40, 0x42, 0x02, 0xEB, 0x40, 0x02, 0x01, 0xFB, 0x09, 0xC1, 0xD3, 0x17, + 0x38, 0x46, 0x07, 0xF0, 0x2D, 0xFB, 0xA4, 0xFB, 0x05, 0x3C, 0x00, 0x27, + 0x07, 0xFB, 0x05, 0xC7, 0x04, 0xFB, 0x09, 0x72, 0x18, 0x18, 0x4A, 0x41, + 0x16, 0x99, 0xA0, 0xFB, 0x01, 0x47, 0xCB, 0x17, 0x02, 0xFB, 0x01, 0x71, + 0x00, 0xFB, 0x03, 0x11, 0xF3, 0x17, 0x32, 0x46, 0x20, 0x46, 0x07, 0xF0, + 0x17, 0xFB, 0x04, 0x46, 0x0E, 0x46, 0x02, 0x22, 0x00, 0x23, 0x28, 0x46, + 0x49, 0x46, 0x07, 0xF0, 0x0F, 0xFB, 0x00, 0x19, 0x71, 0x41, 0x2A, 0x46, + 0x4B, 0x46, 0x07, 0xF0, 0x09, 0xFB, 0x17, 0xB0, 0x64, 0xE7, 0x2D, 0xE9, + 0xFF, 0x4F, 0x00, 0x27, 0x91, 0xB0, 0x16, 0x46, 0x0C, 0x46, 0x83, 0x46, + 0xB9, 0x46, 0xBA, 0x46, 0x8D, 0x78, 0x1A, 0xE0, 0xE9, 0xB2, 0x30, 0x69, + 0x09, 0xF0, 0x20, 0xFA, 0x21, 0x78, 0x4F, 0xF0, 0x01, 0x08, 0x94, 0xF8, + 0x01, 0xC0, 0x0D, 0xE0, 0x5B, 0xF8, 0x25, 0x20, 0x08, 0xFA, 0x01, 0xF3, + 0x1A, 0x42, 0x06, 0xD0, 0x30, 0xF9, 0x11, 0x20, 0x52, 0x45, 0x02, 0xDD, + 0x7F, 0x1C, 0x91, 0x44, 0xBF, 0xB2, 0x49, 0x1C, 0x8C, 0x45, 0xEF, 0xD2, + 0x6D, 0x1C, 0xE0, 0x78, 0xA8, 0x42, 0xE1, 0xD2, 0xC6, 0xF8, 0x30, 0x90, + 0xF7, 0x83, 0x37, 0x7A, 0x96, 0xF8, 0x09, 0x90, 0x40, 0x21, 0x68, 0x46, + 0x07, 0xF0, 0x99, 0xFB, 0xA5, 0x78, 0xE8, 0x46, 0x08, 0xE0, 0xE9, 0xB2, + 0x30, 0x69, 0x09, 0xF0, 0xF5, 0xF9, 0x30, 0xF8, 0x17, 0x10, 0x28, 0xF8, + 0x15, 0x10, 0x6D, 0x1C, 0xE0, 0x78, 0xA8, 0x42, 0xF3, 0xD2, 0x48, 0x4D, + 0x4A, 0x46, 0x28, 0x68, 0xB0, 0xF9, 0x18, 0x30, 0x41, 0x7D, 0x68, 0x46, + 0xFF, 0xF7, 0x1C, 0xFF, 0x14, 0x99, 0x08, 0x60, 0x40, 0x21, 0x68, 0x46, + 0x07, 0xF0, 0x7B, 0xFB, 0x49, 0x46, 0x30, 0x69, 0x09, 0xF0, 0xDA, 0xF9, + 0x21, 0x78, 0x42, 0x46, 0x04, 0xE0, 0x30, 0xF8, 0x11, 0x30, 0x22, 0xF8, + 0x11, 0x30, 0x49, 0x1C, 0x63, 0x78, 0x8B, 0x42, 0xF7, 0xD2, 0x28, 0x68, + 0x3A, 0x46, 0xB0, 0xF9, 0x16, 0x30, 0x01, 0x7D, 0x68, 0x46, 0xFF, 0xF7, + 0xFF, 0xFE, 0x14, 0x99, 0x48, 0x60, 0x15, 0xB0, 0xF8, 0xE6, 0xF0, 0xB5, + 0x32, 0x4C, 0x01, 0x2B, 0x24, 0x68, 0x0E, 0xD0, 0x94, 0xF8, 0x94, 0x36, + 0xB4, 0xF8, 0x90, 0x66, 0x03, 0xF0, 0x0F, 0x05, 0x1F, 0x09, 0xB4, 0xF8, + 0x92, 0x36, 0xB2, 0x42, 0x17, 0xDD, 0x9A, 0x42, 0x0B, 0xDB, 0x3D, 0x46, + 0x13, 0xE0, 0x94, 0xF8, 0xDD, 0x31, 0xB4, 0xF8, 0xDE, 0x61, 0x03, 0xF0, + 0x0F, 0x05, 0x1F, 0x09, 0xB4, 0xF8, 0xE0, 0x31, 0xEF, 0xE7, 0xB3, 0x42, + 0x00, 0xD1, 0x5B, 0x1C, 0x92, 0x1B, 0x7C, 0x1B, 0x62, 0x43, 0x9B, 0x1B, + 0x92, 0xFB, 0xF3, 0xF2, 0x15, 0x44, 0x43, 0x68, 0x4C, 0x68, 0xC5, 0xF1, + 0x10, 0x02, 0x6B, 0x43, 0x04, 0xFB, 0x02, 0x33, 0x1B, 0x11, 0x4B, 0x60, + 0x00, 0x68, 0x0B, 0x68, 0x68, 0x43, 0x03, 0xFB, 0x02, 0x00, 0x00, 0x11, + 0x08, 0x60, 0xF0, 0xBD, 0x10, 0xB5, 0x41, 0x68, 0x00, 0x23, 0x00, 0x29, + 0x00, 0xDA, 0x43, 0x60, 0x13, 0x4A, 0x44, 0x68, 0x11, 0x68, 0xC9, 0x8A, + 0x8C, 0x42, 0x00, 0xDD, 0x41, 0x60, 0x01, 0x68, 0x00, 0x29, 0x01, 0xDB, + 0x03, 0x68, 0x00, 0xE0, 0x03, 0x60, 0x11, 0x68, 0x09, 0x8B, 0x8B, 0x42, + 0x00, 0xDD, 0x01, 0x60, 0x10, 0xBD, 0x2D, 0xE9, 0xFF, 0x41, 0x14, 0x46, + 0x0E, 0x46, 0x07, 0x46, 0x02, 0xAB, 0xFF, 0xF7, 0x0B, 0xFE, 0xA0, 0x7B, + 0x05, 0x4D, 0x02, 0x28, 0x0C, 0xD0, 0x01, 0x28, 0x1E, 0xD0, 0x04, 0x28, + 0x39, 0xD0, 0xDD, 0xE9, 0x02, 0x01, 0xCD, 0xE9, 0x00, 0x01, 0x2E, 0xE0, + 0x50, 0x24, 0x10, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x28, 0x68, 0x90, 0xF8, + 0x80, 0x11, 0x89, 0x07, 0x25, 0xD5, 0xDD, 0xE9, 0x02, 0x12, 0xCD, 0xE9, + 0x00, 0x12, 0x90, 0xF8, 0xFA, 0x04, 0x80, 0x07, 0x1D, 0xD5, 0x01, 0x21, + 0x68, 0x46, 0x01, 0xF0, 0x8D, 0xF8, 0x18, 0xE0, 0x00, 0x21, 0x22, 0xE0, + 0x28, 0x68, 0x90, 0xF8, 0xD0, 0x11, 0x89, 0x07, 0xEB, 0xD5, 0x6B, 0x46, + 0x22, 0x46, 0x31, 0x46, 0x38, 0x46, 0xFF, 0xF7, 0x0A, 0xFF, 0x28, 0x68, + 0x90, 0xF8, 0xFA, 0x04, 0x80, 0x07, 0x03, 0xD5, 0x01, 0x21, 0x68, 0x46, + 0x01, 0xF0, 0x76, 0xF8, 0x68, 0x46, 0xFF, 0xF7, 0xA3, 0xFF, 0x28, 0x68, + 0x90, 0xF8, 0xFA, 0x04, 0xC0, 0x07, 0xE1, 0xD1, 0x08, 0xE0, 0x28, 0x68, + 0x90, 0xF8, 0xFA, 0x04, 0x40, 0x07, 0x03, 0xD5, 0x02, 0x21, 0x02, 0xA8, + 0x01, 0xF0, 0x64, 0xF8, 0x02, 0xA8, 0xFF, 0xF7, 0x91, 0xFF, 0xA0, 0x7B, + 0x01, 0x28, 0x0C, 0xD1, 0x28, 0x68, 0x90, 0xF8, 0xFA, 0x04, 0x81, 0x07, + 0x1E, 0xD5, 0xC0, 0x07, 0x1C, 0xD0, 0x01, 0x23, 0x69, 0x46, 0x02, 0xA8, + 0x22, 0x6B, 0xFF, 0xF7, 0x48, 0xFF, 0xA0, 0x7B, 0x02, 0x28, 0x10, 0xD1, + 0x28, 0x68, 0x90, 0xF8, 0x80, 0x11, 0x89, 0x07, 0x13, 0xD5, 0x90, 0xF8, + 0xFA, 0x04, 0x81, 0x07, 0x13, 0xD5, 0xC0, 0x07, 0x11, 0xD0, 0x00, 0x23, + 0x69, 0x46, 0x02, 0xA8, 0x22, 0x6B, 0xFF, 0xF7, 0x34, 0xFF, 0xA0, 0x7B, + 0x04, 0x28, 0x04, 0xD0, 0x28, 0x68, 0x90, 0xF8, 0x80, 0x01, 0x80, 0x07, + 0x03, 0xD4, 0x03, 0x98, 0x60, 0x80, 0x02, 0x98, 0x02, 0xE0, 0x01, 0x98, + 0x60, 0x80, 0x00, 0x98, 0x20, 0x80, 0x01, 0x98, 0xE0, 0x80, 0x00, 0x98, + 0xA0, 0x80, 0xBD, 0xE8, 0xFF, 0x81, 0x2D, 0xE9, 0xF0, 0x41, 0x06, 0x46, + 0x90, 0x7E, 0xDF, 0xF8, 0x74, 0x81, 0x5D, 0x4F, 0x8C, 0x78, 0xA0, 0xB0, + 0x0D, 0x46, 0x40, 0x07, 0x0F, 0xD5, 0x00, 0x2C, 0x51, 0xD0, 0x98, 0xF8, + 0x00, 0x00, 0xE9, 0x78, 0x40, 0x1E, 0x81, 0x42, 0x4B, 0xD0, 0x28, 0x78, + 0x00, 0x28, 0x48, 0xD0, 0x38, 0x78, 0x69, 0x78, 0x40, 0x1E, 0x81, 0x42, + 0x43, 0xD0, 0x80, 0x21, 0x68, 0x46, 0x07, 0xF0, 0x5E, 0xFA, 0x6A, 0x46, + 0xEB, 0x78, 0x1A, 0xE0, 0x56, 0xF8, 0x24, 0x10, 0xB1, 0xB1, 0x48, 0x08, + 0x40, 0xEA, 0x41, 0x00, 0x08, 0x43, 0x52, 0xF8, 0x24, 0x10, 0x01, 0x43, + 0x42, 0xF8, 0x24, 0x10, 0x02, 0xEB, 0x84, 0x01, 0xD1, 0xF8, 0x04, 0xC0, + 0x4C, 0xEA, 0x00, 0x0C, 0xC1, 0xF8, 0x04, 0xC0, 0xD1, 0xF8, 0x08, 0xC0, + 0x4C, 0xEA, 0x00, 0x0C, 0xC1, 0xF8, 0x08, 0xC0, 0x64, 0x1C, 0xA3, 0x42, + 0xE2, 0xD2, 0x20, 0x20, 0x04, 0xE0, 0x02, 0xEB, 0x80, 0x01, 0x49, 0x68, + 0x46, 0xF8, 0x20, 0x10, 0x40, 0x1E, 0xF8, 0xD2, 0x28, 0x78, 0x08, 0xB1, + 0x40, 0x1E, 0x28, 0x70, 0x39, 0x78, 0x68, 0x78, 0x49, 0x1E, 0x88, 0x42, + 0x01, 0xDA, 0x40, 0x1C, 0x68, 0x70, 0xA8, 0x78, 0x08, 0xB1, 0x40, 0x1E, + 0xA8, 0x70, 0x98, 0xF8, 0x00, 0x10, 0xE8, 0x78, 0x49, 0x1E, 0x88, 0x42, + 0x01, 0xDA, 0x40, 0x1C, 0xE8, 0x70, 0x20, 0xB0, 0xBD, 0xE8, 0xF0, 0x81, + 0x2D, 0xE9, 0xF0, 0x4F, 0xA1, 0xB0, 0x9B, 0x46, 0x15, 0x46, 0x6B, 0x46, + 0xFF, 0xF7, 0xF0, 0xFC, 0x00, 0x28, 0x4B, 0xD0, 0x29, 0x68, 0xCB, 0xF8, + 0x0A, 0x10, 0xCD, 0xF8, 0x80, 0xD0, 0xDF, 0xF8, 0xA0, 0x90, 0x0B, 0xF1, + 0x08, 0x07, 0x00, 0x26, 0xAC, 0x78, 0x4F, 0xF0, 0x01, 0x08, 0x1E, 0xE0, + 0x20, 0x98, 0xE1, 0xB2, 0x50, 0xF8, 0x24, 0xA0, 0xDB, 0xF8, 0x10, 0x00, + 0x09, 0xF0, 0x5E, 0xF8, 0x29, 0x78, 0x04, 0xF0, 0xFF, 0x0C, 0x0E, 0xE0, + 0x08, 0xFA, 0x01, 0xF2, 0x12, 0xEA, 0x0A, 0x0F, 0x08, 0xD0, 0x30, 0xF9, + 0x11, 0x20, 0x16, 0x44, 0x4A, 0x45, 0x03, 0xDD, 0x39, 0x70, 0x91, 0x46, + 0x87, 0xF8, 0x01, 0xC0, 0x49, 0x1C, 0x6A, 0x78, 0x8A, 0x42, 0xED, 0xD2, + 0x64, 0x1C, 0xE8, 0x78, 0xA0, 0x42, 0xDD, 0xD2, 0x13, 0x48, 0xCB, 0xF8, + 0x2C, 0x60, 0x00, 0x78, 0xC0, 0x06, 0x08, 0xD5, 0x11, 0x48, 0x00, 0x78, + 0x28, 0xB9, 0x59, 0x46, 0x68, 0x46, 0xFD, 0xF7, 0x74, 0xF8, 0x01, 0x28, + 0x0E, 0xD0, 0x5A, 0x46, 0x29, 0x46, 0x68, 0x46, 0xFF, 0xF7, 0x4F, 0xFF, + 0x5A, 0x46, 0x29, 0x46, 0x68, 0x46, 0xFF, 0xF7, 0xBA, 0xFE, 0x58, 0x46, + 0xFF, 0xF7, 0x64, 0xF8, 0x21, 0xB0, 0x5B, 0xE5, 0x06, 0x49, 0x81, 0xF8, + 0x00, 0x80, 0xF9, 0xE7, 0x00, 0x24, 0x10, 0x00, 0x01, 0x24, 0x10, 0x00, + 0x00, 0x80, 0xFF, 0xFF, 0x1C, 0x24, 0x10, 0x00, 0xB8, 0x23, 0x10, 0x00, + 0x6E, 0x23, 0x10, 0x00, 0x70, 0xB5, 0x8A, 0xB0, 0x0E, 0x46, 0x04, 0x46, + 0x14, 0x22, 0xFE, 0x49, 0x05, 0xA8, 0x07, 0xF0, 0x4E, 0xF9, 0xFD, 0x4D, + 0xE8, 0x68, 0x00, 0x90, 0xFC, 0x48, 0x00, 0x68, 0x01, 0x90, 0x05, 0xA8, + 0x02, 0x90, 0xFB, 0x48, 0x00, 0x68, 0xB0, 0xF8, 0x6C, 0x01, 0xAD, 0xF8, + 0x10, 0x00, 0xF9, 0x48, 0x03, 0x94, 0x00, 0x78, 0x8D, 0xF8, 0x13, 0x00, + 0xF7, 0x48, 0x00, 0x78, 0x8D, 0xF8, 0x12, 0x00, 0x68, 0x46, 0x06, 0xF0, + 0xD9, 0xF9, 0xE8, 0x68, 0x70, 0x61, 0x0A, 0xB0, 0x70, 0xBD, 0x70, 0xB5, + 0x0E, 0x46, 0xEC, 0x49, 0x8A, 0xB0, 0x04, 0x46, 0x14, 0x22, 0x14, 0x31, + 0x05, 0xA8, 0x07, 0xF0, 0x26, 0xF9, 0xE9, 0x4D, 0xE8, 0x68, 0x00, 0x90, + 0xE8, 0x48, 0x00, 0x68, 0x01, 0x90, 0x05, 0xA8, 0x02, 0x90, 0xE7, 0x48, + 0x00, 0x68, 0xB0, 0xF8, 0x6C, 0x01, 0xAD, 0xF8, 0x10, 0x00, 0xE5, 0x48, + 0x03, 0x94, 0x00, 0x78, 0x8D, 0xF8, 0x13, 0x00, 0xE3, 0x48, 0x00, 0x78, + 0x8D, 0xF8, 0x12, 0x00, 0x68, 0x46, 0x06, 0xF0, 0xB1, 0xF9, 0xE8, 0x68, + 0x30, 0x61, 0xD6, 0xE7, 0xDF, 0x49, 0x01, 0x20, 0x09, 0x78, 0xC9, 0x07, + 0x03, 0xD0, 0xDE, 0x49, 0x09, 0x78, 0x00, 0x29, 0x00, 0xD0, 0x00, 0x20, + 0x70, 0x47, 0x2D, 0xE9, 0xFF, 0x4F, 0x81, 0xB0, 0xDA, 0x48, 0x0E, 0x9D, + 0x10, 0x9F, 0x00, 0x68, 0x28, 0x60, 0x4F, 0xF0, 0x00, 0x08, 0xC7, 0xF8, + 0x2C, 0x80, 0x99, 0x46, 0x9E, 0x78, 0x47, 0xE0, 0xF1, 0xB2, 0x01, 0x98, + 0x08, 0xF0, 0xA0, 0xFF, 0x83, 0x46, 0xF1, 0xB2, 0x02, 0x98, 0x08, 0xF0, + 0x9B, 0xFF, 0x00, 0x90, 0xCC, 0x4A, 0xF0, 0xB2, 0x39, 0x69, 0x12, 0x78, + 0x99, 0xF8, 0x00, 0x40, 0x50, 0x43, 0x01, 0xEB, 0x40, 0x0A, 0x2E, 0xE0, + 0x00, 0x98, 0x01, 0x5D, 0x03, 0x98, 0x81, 0x42, 0x28, 0xD1, 0x3A, 0xF9, + 0x14, 0x10, 0x0F, 0x98, 0x81, 0x42, 0x20, 0xDD, 0x03, 0x98, 0x0B, 0xF8, + 0x04, 0x00, 0x29, 0x78, 0x20, 0x46, 0x03, 0xF0, 0x71, 0xFF, 0x28, 0x70, + 0x69, 0x78, 0x20, 0x46, 0x03, 0xF0, 0x70, 0xFF, 0x68, 0x70, 0xA9, 0x78, + 0x30, 0x46, 0x03, 0xF0, 0x67, 0xFF, 0xA8, 0x70, 0xE9, 0x78, 0x30, 0x46, + 0x03, 0xF0, 0x66, 0xFF, 0xE8, 0x70, 0x08, 0xF1, 0x01, 0x00, 0x1F, 0xFA, + 0x80, 0xF8, 0x3A, 0xF9, 0x14, 0x00, 0xF9, 0x6A, 0x08, 0x44, 0xF8, 0x62, + 0x02, 0xE0, 0x00, 0x20, 0x0B, 0xF8, 0x04, 0x00, 0x64, 0x1C, 0x99, 0xF8, + 0x01, 0x00, 0xA0, 0x42, 0xCC, 0xD2, 0x76, 0x1C, 0x99, 0xF8, 0x03, 0x00, + 0xB0, 0x42, 0xB3, 0xD2, 0xA7, 0xF8, 0x1C, 0x80, 0x05, 0xB0, 0xBD, 0xE8, + 0xF0, 0x8F, 0x2D, 0xE9, 0xFF, 0x47, 0x15, 0x46, 0x0C, 0xAA, 0x81, 0x46, + 0x92, 0xE8, 0x41, 0x01, 0xA9, 0x4A, 0x00, 0x27, 0xB2, 0xF9, 0x00, 0x20, + 0x9A, 0x42, 0x2B, 0xDA, 0x03, 0xAA, 0x00, 0x92, 0xCD, 0xE9, 0x01, 0x30, + 0x05, 0xEB, 0x81, 0x04, 0x0A, 0x46, 0x49, 0x46, 0x23, 0x46, 0x08, 0x46, + 0xFF, 0xF7, 0x87, 0xFF, 0x03, 0x98, 0x20, 0x60, 0xB8, 0xF1, 0x01, 0x0F, + 0x1A, 0xD1, 0x95, 0xF8, 0x0E, 0x41, 0x03, 0x98, 0x28, 0x60, 0x94, 0x48, + 0x01, 0x27, 0x10, 0x30, 0xCD, 0xE9, 0x00, 0x70, 0x3B, 0x46, 0x22, 0x46, + 0x29, 0x46, 0x48, 0x46, 0x00, 0xF0, 0x62, 0xFD, 0x04, 0xE0, 0x30, 0x68, + 0x07, 0xFA, 0x04, 0xF1, 0x08, 0x43, 0x30, 0x60, 0x95, 0xF8, 0x0E, 0x01, + 0x64, 0x1C, 0xA0, 0x42, 0xF5, 0xD2, 0x01, 0x27, 0x04, 0xB0, 0x38, 0x46, + 0xBD, 0xE8, 0xF0, 0x87, 0x10, 0xB5, 0x88, 0x4A, 0x8E, 0x4C, 0x13, 0x68, + 0x24, 0x78, 0x93, 0xF8, 0x66, 0x21, 0x01, 0x2C, 0x01, 0xD1, 0x93, 0xF8, + 0xCF, 0x20, 0x8B, 0x4C, 0x24, 0x78, 0x44, 0xB1, 0x89, 0x7E, 0x89, 0x07, + 0x02, 0xD5, 0x93, 0xF8, 0x68, 0x11, 0x01, 0xE0, 0x93, 0xF8, 0x67, 0x11, + 0x0A, 0x44, 0x90, 0x42, 0x01, 0xD9, 0x01, 0x20, 0x10, 0xBD, 0x00, 0x20, + 0x10, 0xBD, 0x2D, 0xE9, 0xF0, 0x47, 0x88, 0x46, 0x81, 0x46, 0x50, 0x78, + 0x11, 0x78, 0x77, 0x4F, 0x15, 0x46, 0x42, 0x1A, 0x38, 0x68, 0x73, 0x4E, + 0x52, 0x1C, 0x90, 0xF8, 0xEB, 0x10, 0x1C, 0x46, 0x8A, 0x42, 0x0D, 0xDC, + 0xEA, 0x78, 0xAB, 0x78, 0xD2, 0x1A, 0x52, 0x1C, 0x8A, 0x42, 0x07, 0xDC, + 0xB0, 0xF8, 0xEE, 0x20, 0xE1, 0x6A, 0x91, 0x42, 0x02, 0xDC, 0xA1, 0x8B, + 0x04, 0x29, 0x01, 0xD2, 0x00, 0x20, 0x0C, 0xE0, 0x31, 0x78, 0x59, 0xB9, + 0x90, 0xF8, 0xD4, 0x00, 0x40, 0x07, 0x07, 0xD5, 0x6F, 0x48, 0x21, 0x46, + 0xB0, 0xF9, 0x00, 0x20, 0x28, 0x46, 0x01, 0xF0, 0xA4, 0xFC, 0x30, 0x70, + 0x6C, 0x48, 0xA1, 0x8B, 0x03, 0x46, 0x01, 0x82, 0x62, 0x49, 0x2A, 0x46, + 0x09, 0x78, 0x81, 0x74, 0x04, 0xF1, 0x22, 0x01, 0x01, 0x60, 0x89, 0x1C, + 0x41, 0x60, 0x89, 0x1C, 0x81, 0x60, 0x0D, 0x39, 0xC1, 0x60, 0x41, 0x46, + 0x48, 0x46, 0x05, 0xF0, 0x8C, 0xFF, 0x38, 0x68, 0xA1, 0x8B, 0x90, 0xF8, + 0x69, 0x21, 0x91, 0x42, 0x32, 0xD8, 0x02, 0x21, 0xA1, 0x73, 0x90, 0xF8, + 0x64, 0x21, 0x00, 0x21, 0x93, 0x07, 0x01, 0xD4, 0x53, 0x07, 0x00, 0xD5, + 0x01, 0x21, 0x63, 0x8C, 0xB0, 0xF8, 0x6A, 0x01, 0x83, 0x42, 0x00, 0xD2, + 0x00, 0x21, 0x20, 0x8C, 0x03, 0x28, 0x00, 0xD2, 0x00, 0x21, 0x30, 0x78, + 0x01, 0x28, 0x00, 0xD1, 0x00, 0x21, 0x50, 0x48, 0x00, 0x78, 0x01, 0x28, + 0x0E, 0xD0, 0x69, 0xB1, 0xD0, 0x07, 0x03, 0xD0, 0x21, 0x46, 0x28, 0x46, + 0xFF, 0xF7, 0x80, 0xFE, 0x23, 0x46, 0x2A, 0x46, 0x41, 0x46, 0x48, 0x46, + 0xBD, 0xE8, 0xF0, 0x47, 0x01, 0xF0, 0xD7, 0xBC, 0x23, 0x46, 0x2A, 0x46, + 0x41, 0x46, 0x48, 0x46, 0xBD, 0xE8, 0xF0, 0x47, 0xFF, 0xF7, 0x08, 0xBE, + 0x90, 0xF8, 0x7B, 0x21, 0x03, 0x20, 0x91, 0x42, 0xA0, 0x73, 0x0D, 0xD8, + 0x23, 0x46, 0x2A, 0x46, 0x41, 0x46, 0x48, 0x46, 0x01, 0xF0, 0xC3, 0xFC, + 0xA0, 0x7B, 0x03, 0x28, 0x03, 0xD1, 0x60, 0x8B, 0x40, 0xF0, 0x20, 0x00, + 0x60, 0x83, 0x4F, 0xE7, 0x60, 0x8B, 0x40, 0xF0, 0x20, 0x00, 0x60, 0x83, + 0xDE, 0xE7, 0x37, 0x49, 0x10, 0xB5, 0x09, 0x78, 0xC9, 0xB1, 0x2D, 0x49, + 0x09, 0x68, 0x91, 0xF8, 0x7A, 0x11, 0x0A, 0x07, 0x13, 0xD0, 0x02, 0x78, + 0x43, 0x78, 0x9A, 0x42, 0x03, 0xD1, 0xC2, 0x78, 0x80, 0x78, 0x12, 0x1A, + 0x04, 0xE0, 0x84, 0x78, 0xC0, 0x78, 0x84, 0x42, 0x07, 0xD1, 0x9A, 0x1A, + 0x01, 0xF0, 0x0F, 0x00, 0x40, 0x1E, 0x82, 0x42, 0x01, 0xDD, 0x00, 0x20, + 0x10, 0xBD, 0x01, 0x20, 0x10, 0xBD, 0x1D, 0x48, 0x10, 0xB5, 0x41, 0x68, + 0x4F, 0xF4, 0x88, 0x62, 0x27, 0x48, 0x06, 0xF0, 0x41, 0xFF, 0xBD, 0xE8, + 0x10, 0x40, 0x25, 0x48, 0xFC, 0xF7, 0x92, 0xB8, 0x2D, 0xE9, 0xF0, 0x5F, + 0x83, 0x46, 0x00, 0x20, 0xD8, 0x62, 0x1D, 0x46, 0x17, 0x46, 0x8A, 0x46, + 0x20, 0x4E, 0x03, 0xF1, 0x08, 0x08, 0x94, 0x78, 0x47, 0xE0, 0xE1, 0xB2, + 0x58, 0x46, 0x08, 0xF0, 0x25, 0xFE, 0x12, 0x4B, 0xE1, 0xB2, 0x2A, 0x69, + 0x1B, 0x78, 0x04, 0xF0, 0xFF, 0x09, 0x59, 0x43, 0x02, 0xEB, 0x41, 0x03, + 0x39, 0x78, 0x34, 0xE0, 0x10, 0xF8, 0x01, 0xC0, 0xD4, 0x45, 0x2F, 0xD1, + 0x33, 0xF9, 0x11, 0x20, 0xD5, 0xF8, 0x2C, 0xC0, 0xB2, 0x42, 0x94, 0x44, + 0xC5, 0xF8, 0x2C, 0xC0, 0x26, 0xDD, 0x16, 0x46, 0x20, 0xE0, 0x00, 0x00, + 0x38, 0x1D, 0x01, 0x00, 0x9C, 0x23, 0x10, 0x00, 0x10, 0x24, 0x10, 0x00, + 0x50, 0x24, 0x10, 0x00, 0x00, 0x24, 0x10, 0x00, 0x01, 0x24, 0x10, 0x00, + 0x1C, 0x24, 0x10, 0x00, 0xE0, 0x23, 0x10, 0x00, 0x60, 0x1D, 0x01, 0x00, + 0xD2, 0x23, 0x10, 0x00, 0x6E, 0x23, 0x10, 0x00, 0xB8, 0x23, 0x10, 0x00, + 0xCC, 0x23, 0x10, 0x00, 0x40, 0x50, 0x10, 0x00, 0xBC, 0x8F, 0x01, 0x20, + 0x00, 0x80, 0xFF, 0xFF, 0x88, 0xF8, 0x00, 0x10, 0x88, 0xF8, 0x01, 0x90, + 0x49, 0x1C, 0x7A, 0x78, 0x8A, 0x42, 0xC7, 0xD2, 0x64, 0x1C, 0xF8, 0x78, + 0xA0, 0x42, 0xB4, 0xD2, 0x2E, 0x85, 0xBD, 0xE8, 0xF0, 0x9F, 0x10, 0xB5, + 0xA0, 0xB0, 0x14, 0x46, 0x6B, 0x46, 0xFF, 0xF7, 0x59, 0xFA, 0x00, 0x28, + 0x0C, 0xD0, 0xFE, 0x48, 0x00, 0x68, 0x90, 0xF8, 0x82, 0x00, 0x40, 0x07, + 0x05, 0xD5, 0x21, 0x46, 0x68, 0x46, 0xFC, 0xF7, 0x85, 0xFE, 0x00, 0x28, + 0x00, 0xD0, 0x01, 0x20, 0x20, 0xB0, 0x10, 0xBD, 0xF8, 0x49, 0xF7, 0x48, + 0xF8, 0x4A, 0xC8, 0x60, 0x00, 0xF5, 0x08, 0x60, 0x48, 0x60, 0x00, 0xF5, + 0x88, 0x60, 0x88, 0x60, 0x00, 0x20, 0x10, 0x70, 0xF4, 0x4A, 0x10, 0x70, + 0xF4, 0x4A, 0x10, 0x70, 0x08, 0x70, 0xF4, 0x49, 0x08, 0x70, 0xF4, 0x49, + 0x08, 0x60, 0xF4, 0x49, 0x08, 0x70, 0xEB, 0x48, 0xEC, 0x49, 0x00, 0x68, + 0x10, 0x31, 0x42, 0x7D, 0x0A, 0x70, 0x00, 0x7D, 0x48, 0x70, 0xF0, 0x48, + 0x48, 0x60, 0x70, 0x47, 0x2D, 0xE9, 0xF0, 0x4F, 0xE6, 0x4D, 0xDD, 0xB0, + 0x4F, 0xF4, 0x88, 0x61, 0xA8, 0x68, 0x06, 0xF0, 0x1E, 0xFF, 0xEB, 0x48, + 0xB0, 0xF9, 0x00, 0x00, 0x41, 0x00, 0xE8, 0x68, 0x06, 0xF0, 0x17, 0xFF, + 0x00, 0x21, 0xCD, 0xE9, 0x54, 0x11, 0x56, 0x91, 0x05, 0xF1, 0x10, 0x00, + 0xCD, 0xE9, 0x00, 0x10, 0x58, 0x91, 0x57, 0x91, 0x89, 0x46, 0x0A, 0x46, + 0x01, 0x23, 0x03, 0xA9, 0x68, 0x68, 0x00, 0xF0, 0xBD, 0xFB, 0xE0, 0x49, + 0x9D, 0xF8, 0x1A, 0x01, 0x08, 0x72, 0x01, 0x28, 0x01, 0xD9, 0x00, 0x20, + 0x28, 0x70, 0x01, 0x24, 0x2A, 0xE2, 0x03, 0xA8, 0x00, 0xEB, 0x84, 0x06, + 0x00, 0xEB, 0x44, 0x00, 0xE1, 0xB2, 0xB0, 0xF8, 0xB4, 0x20, 0x47, 0xA8, + 0x00, 0xF0, 0x67, 0xFA, 0xE1, 0xB2, 0x47, 0xAB, 0x32, 0x46, 0x68, 0x68, + 0xFF, 0xF7, 0x30, 0xFF, 0x9D, 0xF8, 0x24, 0x01, 0x60, 0xB1, 0xD2, 0x49, + 0x09, 0x78, 0x49, 0x1E, 0x88, 0x42, 0x07, 0xD0, 0x9D, 0xF8, 0x25, 0x01, + 0x20, 0xB1, 0xCF, 0x49, 0x09, 0x78, 0x49, 0x1E, 0x88, 0x42, 0x05, 0xD1, + 0xBD, 0xF8, 0x36, 0x01, 0x40, 0xF0, 0x01, 0x00, 0xAD, 0xF8, 0x36, 0x01, + 0x30, 0x78, 0x28, 0xB1, 0xC7, 0x48, 0x71, 0x78, 0x00, 0x78, 0x40, 0x1E, + 0x81, 0x42, 0x0D, 0xD1, 0xB0, 0x78, 0x28, 0xB1, 0xC4, 0x48, 0xF1, 0x78, + 0x00, 0x78, 0x40, 0x1E, 0x81, 0x42, 0x05, 0xD1, 0xBD, 0xF8, 0x36, 0x01, + 0x40, 0xF0, 0x02, 0x00, 0xAD, 0xF8, 0x36, 0x01, 0x4F, 0xF0, 0x00, 0x0A, + 0x01, 0x20, 0x54, 0x99, 0x00, 0xFA, 0x04, 0xF8, 0x57, 0x46, 0xD3, 0x46, + 0x18, 0xEA, 0x01, 0x0F, 0x64, 0xD1, 0xBA, 0x48, 0x00, 0x68, 0x81, 0x07, + 0x60, 0xD5, 0xAA, 0x49, 0xB8, 0x4B, 0x09, 0x68, 0x1B, 0x68, 0x91, 0xF8, + 0xD8, 0x21, 0x9A, 0x42, 0xB6, 0x4A, 0x12, 0x78, 0x01, 0xD2, 0xEA, 0xBB, + 0x01, 0xE0, 0x02, 0x2A, 0x52, 0xD2, 0xAB, 0x4A, 0x12, 0x78, 0x01, 0x2A, + 0x4E, 0xD0, 0xAC, 0x4A, 0x10, 0xF0, 0x30, 0x0F, 0x13, 0x7C, 0x43, 0xF0, + 0x01, 0x03, 0x13, 0x74, 0x0A, 0xD0, 0x91, 0xF8, 0xE7, 0x01, 0xFB, 0xF7, + 0x12, 0xFE, 0xE1, 0xB2, 0x47, 0xAB, 0x32, 0x46, 0x68, 0x68, 0xFF, 0xF7, + 0x2C, 0xFF, 0x18, 0xB3, 0xA2, 0x48, 0x47, 0xAA, 0x33, 0x46, 0x01, 0x7C, + 0x41, 0xF0, 0x02, 0x01, 0x01, 0x74, 0x52, 0x98, 0x5B, 0x90, 0xBD, 0xF8, + 0x38, 0x01, 0xA3, 0x49, 0x5A, 0x90, 0x59, 0xA8, 0xB1, 0xF9, 0x00, 0x10, + 0x8D, 0xE8, 0x07, 0x00, 0xD5, 0xE9, 0x01, 0x10, 0xE2, 0xB2, 0xFF, 0xF7, + 0x3C, 0xFD, 0xE1, 0xB2, 0x47, 0xAB, 0x59, 0xAA, 0xA8, 0x68, 0x00, 0xF0, + 0xF5, 0xF9, 0x01, 0x28, 0x17, 0xD1, 0x82, 0x46, 0x58, 0x90, 0xE1, 0xB2, + 0x59, 0xAA, 0x00, 0xE0, 0x16, 0xE0, 0x4F, 0xF0, 0x01, 0x0C, 0xA8, 0x68, + 0x8D, 0xF8, 0x2A, 0xC1, 0x4F, 0xF0, 0x02, 0x0C, 0xAD, 0xF8, 0x40, 0xC1, + 0xAD, 0xF8, 0x42, 0xC1, 0x4F, 0xF0, 0x00, 0x0C, 0x47, 0xAB, 0x8D, 0xF8, + 0x35, 0xC1, 0xFF, 0xF7, 0x5B, 0xFC, 0x5B, 0x98, 0x52, 0x90, 0x5A, 0x98, + 0xAD, 0xF8, 0x38, 0x01, 0x30, 0x46, 0xFF, 0xF7, 0x64, 0xFE, 0x00, 0x28, + 0x74, 0xD0, 0xBA, 0xF1, 0x00, 0x0F, 0x72, 0xD1, 0x87, 0x48, 0xBD, 0xF9, + 0x44, 0x11, 0xB0, 0xF9, 0x00, 0x00, 0x81, 0x42, 0x5D, 0xDD, 0x78, 0x48, + 0x00, 0x78, 0xE8, 0xBB, 0xDF, 0xF8, 0xEC, 0xA1, 0x7D, 0x48, 0x9A, 0xF8, + 0x11, 0x10, 0x41, 0xF0, 0x01, 0x01, 0x8A, 0xF8, 0x11, 0x10, 0x00, 0x78, + 0x10, 0xF0, 0x30, 0x0F, 0x13, 0xD0, 0x6A, 0x48, 0x00, 0x68, 0xB0, 0xF9, + 0xA8, 0x00, 0xFB, 0xF7, 0xAA, 0xFD, 0xE1, 0xB2, 0x47, 0xAB, 0x32, 0x46, + 0x68, 0x68, 0xFF, 0xF7, 0xC4, 0xFE, 0x00, 0x28, 0xD6, 0xD0, 0x9A, 0xF8, + 0x11, 0x10, 0x41, 0xF0, 0x02, 0x01, 0x8A, 0xF8, 0x11, 0x10, 0x60, 0x48, + 0x00, 0x68, 0x90, 0xF8, 0xD4, 0x00, 0x40, 0x07, 0x06, 0xD5, 0xE1, 0xB2, + 0x47, 0xAB, 0x32, 0x46, 0x68, 0x68, 0x00, 0xF0, 0xD3, 0xF9, 0x28, 0x70, + 0x54, 0x99, 0x18, 0xEA, 0x01, 0x0F, 0x21, 0xD1, 0x57, 0x48, 0xBD, 0xF8, + 0x38, 0x11, 0x00, 0x68, 0x90, 0xF8, 0x69, 0x21, 0x91, 0x42, 0x07, 0xD8, + 0x90, 0xF8, 0x64, 0x01, 0x81, 0x07, 0x00, 0xE0, 0x1B, 0xE0, 0x03, 0xD4, + 0x40, 0x07, 0x01, 0xD4, 0x4F, 0xF0, 0x01, 0x0B, 0x54, 0xA9, 0x47, 0xAA, + 0xCD, 0xE9, 0x00, 0x21, 0x5E, 0x48, 0xCD, 0xF8, 0x08, 0xB0, 0xE1, 0xB2, + 0xB0, 0xF9, 0x00, 0x30, 0x03, 0xAA, 0x68, 0x68, 0xFF, 0xF7, 0x13, 0xFD, + 0x07, 0x00, 0x06, 0xD1, 0xBD, 0xF8, 0x38, 0x01, 0x47, 0xA9, 0xFF, 0xF7, + 0x49, 0xFD, 0x01, 0x28, 0x0E, 0xD0, 0xDF, 0xF8, 0x58, 0xB1, 0xBD, 0xF9, + 0x44, 0x11, 0xBB, 0xF9, 0x00, 0x00, 0x81, 0x42, 0x32, 0xDD, 0xFF, 0xF7, + 0x95, 0xFC, 0x01, 0x28, 0x63, 0xD0, 0x2D, 0xE0, 0xDD, 0xE0, 0x5F, 0xE0, + 0x9A, 0xF8, 0x11, 0x10, 0x4E, 0x4F, 0x41, 0xF0, 0x04, 0x01, 0x8A, 0xF8, + 0x11, 0x10, 0xBD, 0xF9, 0x44, 0x01, 0xB7, 0xF9, 0x00, 0x10, 0x4F, 0xF0, + 0x01, 0x09, 0x88, 0x42, 0x01, 0xDD, 0x01, 0x20, 0x55, 0x90, 0xE1, 0xB2, + 0x47, 0xAB, 0x32, 0x46, 0x68, 0x68, 0xFF, 0xF7, 0x3E, 0xFD, 0x42, 0x48, + 0xB0, 0xF9, 0x00, 0x20, 0xFF, 0xF7, 0x74, 0xFC, 0x01, 0x28, 0x01, 0xD1, + 0xB7, 0xF9, 0x00, 0x20, 0xBD, 0xF9, 0x44, 0x01, 0x90, 0x42, 0x01, 0xDD, + 0xFD, 0xF7, 0x91, 0xFE, 0xBD, 0xF9, 0x44, 0x01, 0xB7, 0xF9, 0x00, 0x10, + 0x88, 0x42, 0x33, 0xDA, 0x33, 0x48, 0x00, 0x78, 0x80, 0x06, 0x2F, 0xD5, + 0x38, 0x48, 0xBD, 0xF9, 0x44, 0x11, 0xB0, 0xF9, 0x00, 0x30, 0x99, 0x42, + 0x28, 0xDD, 0x2B, 0x4F, 0x35, 0x48, 0x39, 0x7C, 0x41, 0xF0, 0x10, 0x01, + 0x39, 0x74, 0xB0, 0xF9, 0x00, 0x00, 0x98, 0x42, 0x09, 0xDA, 0x00, 0x22, + 0x54, 0xA9, 0x47, 0xA8, 0x8D, 0xE8, 0x07, 0x00, 0xE1, 0xB2, 0x03, 0xAA, + 0x68, 0x68, 0xFF, 0xF7, 0xB0, 0xFC, 0x2D, 0x49, 0xDF, 0xF8, 0x54, 0xA0, + 0xBD, 0xF8, 0x38, 0x01, 0x88, 0x76, 0xDA, 0xF8, 0x00, 0x10, 0x91, 0xF8, + 0xD9, 0x10, 0x88, 0x42, 0x08, 0xD9, 0x38, 0x7C, 0x40, 0xF0, 0x20, 0x00, + 0x38, 0x74, 0x30, 0x46, 0xFB, 0xF7, 0xAD, 0xF8, 0x01, 0x28, 0x7D, 0xD0, + 0x9B, 0xE0, 0xDF, 0xF8, 0x58, 0xA0, 0x18, 0x48, 0x9A, 0xF8, 0x11, 0x10, + 0x41, 0xF0, 0x10, 0x01, 0x8A, 0xF8, 0x11, 0x10, 0x00, 0x78, 0x10, 0xF0, + 0x30, 0x0F, 0x43, 0xD0, 0x04, 0x48, 0x00, 0x68, 0x90, 0xF8, 0x07, 0x02, + 0xFB, 0xF7, 0xDF, 0xFC, 0xE1, 0xB2, 0x47, 0xAB, 0x32, 0x46, 0x2F, 0xE0, + 0x50, 0x24, 0x10, 0x00, 0x60, 0x54, 0x10, 0x00, 0x9C, 0x23, 0x10, 0x00, + 0x05, 0x24, 0x10, 0x00, 0x06, 0x24, 0x10, 0x00, 0x07, 0x24, 0x10, 0x00, + 0x38, 0x23, 0x10, 0x00, 0x3C, 0x23, 0x10, 0x00, 0x6E, 0x23, 0x10, 0x00, + 0x60, 0x1D, 0x01, 0x00, 0x0C, 0x24, 0x10, 0x00, 0x58, 0x25, 0x10, 0x00, + 0x01, 0x24, 0x10, 0x00, 0x00, 0x24, 0x10, 0x00, 0x1C, 0x24, 0x10, 0x00, + 0xC0, 0x23, 0x10, 0x00, 0xB8, 0x23, 0x10, 0x00, 0xCE, 0x23, 0x10, 0x00, + 0xCC, 0x23, 0x10, 0x00, 0xD0, 0x23, 0x10, 0x00, 0xC6, 0x23, 0x10, 0x00, + 0xD6, 0x23, 0x10, 0x00, 0xD2, 0x23, 0x10, 0x00, 0x8A, 0x25, 0x10, 0x00, + 0x68, 0x68, 0xFF, 0xF7, 0xC8, 0xFD, 0x80, 0xB3, 0x9A, 0xF8, 0x11, 0x10, + 0x41, 0xF0, 0x20, 0x01, 0x8A, 0xF8, 0x11, 0x10, 0x54, 0x9A, 0x01, 0x20, + 0x18, 0xEA, 0x02, 0x0F, 0x0C, 0xD1, 0x47, 0xAA, 0x00, 0x92, 0x54, 0xA9, + 0xCD, 0xE9, 0x01, 0x10, 0xE1, 0xB2, 0xBB, 0xF9, 0x00, 0x30, 0x03, 0xAA, + 0x68, 0x68, 0xFF, 0xF7, 0x38, 0xFC, 0x07, 0x46, 0x00, 0x2F, 0x7F, 0xF4, + 0x36, 0xAF, 0xBD, 0xF8, 0x38, 0x01, 0x47, 0xA9, 0x00, 0xF0, 0x08, 0xF9, + 0x01, 0x28, 0xF6, 0xD1, 0x9A, 0xF8, 0x11, 0x10, 0x47, 0xAB, 0x41, 0xF0, + 0x40, 0x01, 0x8A, 0xF8, 0x11, 0x10, 0x57, 0x90, 0xE1, 0xB2, 0x32, 0x46, + 0x68, 0x68, 0x00, 0xF0, 0x19, 0xF9, 0x20, 0xE0, 0x00, 0xE0, 0x22, 0xE0, + 0x38, 0x7C, 0x40, 0xF0, 0x40, 0x00, 0x38, 0x74, 0xDA, 0xF8, 0x00, 0x00, + 0x90, 0xF8, 0xA5, 0x13, 0x05, 0x20, 0x02, 0xF0, 0x9E, 0xF9, 0xBD, 0xF8, + 0x36, 0x01, 0x4F, 0xF0, 0x01, 0x09, 0x40, 0xF0, 0x10, 0x00, 0xAD, 0xF8, + 0x36, 0x01, 0xBA, 0x48, 0xCD, 0xF8, 0x58, 0x91, 0x00, 0x78, 0x01, 0x28, + 0x05, 0xD1, 0xE1, 0xB2, 0x47, 0xAB, 0x32, 0x46, 0x68, 0x68, 0x00, 0xF0, + 0x36, 0xF9, 0x54, 0x99, 0x48, 0xEA, 0x01, 0x00, 0x54, 0x90, 0x64, 0x1C, + 0x9D, 0xF8, 0x1A, 0x01, 0xA0, 0x42, 0xBF, 0xF4, 0xD0, 0xAD, 0xB0, 0x49, + 0x55, 0x98, 0x60, 0xB9, 0x56, 0x98, 0x50, 0xB1, 0xAE, 0x48, 0x00, 0x68, + 0x90, 0xF8, 0xDD, 0x20, 0x08, 0x68, 0x82, 0x42, 0x07, 0xDA, 0xA9, 0x49, + 0x01, 0x20, 0x08, 0x70, 0x05, 0xE0, 0xA7, 0x4A, 0x00, 0x20, 0x10, 0x70, + 0x00, 0xE0, 0x40, 0x1C, 0x08, 0x60, 0xA7, 0x49, 0x58, 0x98, 0x08, 0x70, + 0xA6, 0x49, 0x81, 0xF8, 0x00, 0x90, 0xA6, 0x49, 0x57, 0x98, 0x08, 0x70, + 0xA5, 0x49, 0x52, 0x98, 0x48, 0x81, 0xA5, 0x48, 0xA5, 0x49, 0x02, 0x78, + 0x88, 0x7A, 0x62, 0xF3, 0x41, 0x00, 0x2A, 0x78, 0x62, 0xF3, 0x45, 0x10, + 0x88, 0x72, 0x5D, 0xB0, 0xBD, 0xE8, 0xF0, 0x8F, 0x9A, 0x49, 0x00, 0x20, + 0x08, 0x70, 0x9A, 0x49, 0x08, 0x70, 0x9A, 0x49, 0x08, 0x70, 0x9D, 0x49, + 0x08, 0x70, 0x99, 0x49, 0x08, 0x72, 0x48, 0x81, 0x91, 0x49, 0x08, 0x70, + 0x91, 0x49, 0x08, 0x60, 0x96, 0x49, 0x08, 0x70, 0x70, 0x47, 0x70, 0xB5, + 0x0E, 0x46, 0x15, 0x46, 0x04, 0x46, 0x34, 0x21, 0x06, 0xF0, 0xA5, 0xFC, + 0x00, 0x20, 0xA0, 0x73, 0x93, 0x48, 0x00, 0x68, 0x20, 0x61, 0x60, 0x61, + 0x26, 0x76, 0x25, 0x84, 0xA5, 0x83, 0x70, 0xBD, 0x2D, 0xE9, 0xF0, 0x41, + 0x86, 0x4C, 0xDF, 0xF8, 0x3C, 0xC2, 0x00, 0x25, 0x24, 0x68, 0x9C, 0xF8, + 0x00, 0xC0, 0x9F, 0x8B, 0x94, 0xF8, 0xD9, 0x61, 0xBC, 0xF1, 0x00, 0x0F, + 0x02, 0xD0, 0x94, 0xF8, 0xDA, 0xC1, 0x66, 0x44, 0x93, 0xF8, 0x1A, 0xE0, + 0x94, 0xF8, 0xDB, 0xC1, 0x5F, 0xEA, 0xCE, 0x7E, 0x01, 0xD0, 0x94, 0xF8, + 0xDC, 0xC1, 0xB7, 0x42, 0x1B, 0xD9, 0x67, 0x45, 0x19, 0xD8, 0x82, 0x4E, + 0xB3, 0xF9, 0x28, 0x70, 0xB6, 0xF9, 0x00, 0x60, 0xB7, 0x42, 0x12, 0xDD, + 0xB4, 0xF8, 0xD6, 0x41, 0xDE, 0x6A, 0xA6, 0x42, 0x0D, 0xDA, 0x76, 0x4C, + 0x26, 0x7C, 0x46, 0xF0, 0x04, 0x06, 0x26, 0x74, 0x00, 0xF0, 0x63, 0xFA, + 0x01, 0x28, 0x04, 0xD1, 0x20, 0x7C, 0x01, 0x25, 0x40, 0xF0, 0x08, 0x00, + 0x20, 0x74, 0x28, 0x46, 0xBD, 0xE8, 0xF0, 0x81, 0x2D, 0xE9, 0xF0, 0x41, + 0x68, 0x4E, 0x0F, 0x46, 0x80, 0x46, 0x31, 0x68, 0x14, 0x46, 0x6D, 0x48, + 0x1D, 0x46, 0xDA, 0x6A, 0xB1, 0xF8, 0xEE, 0x30, 0x00, 0x78, 0x9A, 0x42, + 0x01, 0xDD, 0x00, 0x20, 0xEC, 0xE7, 0xB1, 0xF8, 0xEC, 0x20, 0x00, 0x2A, + 0xE8, 0xD0, 0x6A, 0x4B, 0xB3, 0xF9, 0x00, 0x30, 0x9A, 0x42, 0xE3, 0xDA, + 0xAA, 0x8B, 0x04, 0x2A, 0xE0, 0xD9, 0x00, 0x28, 0xDE, 0xD1, 0xB1, 0xF9, + 0xEC, 0x20, 0x29, 0x46, 0x20, 0x46, 0x01, 0xF0, 0x6C, 0xF8, 0x00, 0x28, + 0xD6, 0xD1, 0x61, 0x78, 0x22, 0x78, 0x8A, 0x1A, 0x31, 0x68, 0x52, 0x1C, + 0x91, 0xF8, 0xEB, 0x10, 0x8A, 0x42, 0xCD, 0xDC, 0xE2, 0x78, 0xA3, 0x78, + 0xD2, 0x1A, 0x52, 0x1C, 0x8A, 0x42, 0xC7, 0xDC, 0x2B, 0x46, 0x22, 0x46, + 0x39, 0x46, 0x40, 0x46, 0xBD, 0xE8, 0xF0, 0x41, 0x00, 0xF0, 0x69, 0xBF, + 0x89, 0x7E, 0x4A, 0x4A, 0xCB, 0x07, 0x55, 0x49, 0x12, 0x68, 0x09, 0x78, + 0x06, 0xD0, 0x11, 0xB1, 0x92, 0xF8, 0xFC, 0x11, 0x05, 0xE0, 0x92, 0xF8, + 0xFD, 0x11, 0x02, 0xE0, 0x59, 0xB1, 0x92, 0xF8, 0xFA, 0x11, 0x4B, 0x4B, + 0x1B, 0x78, 0x13, 0xB1, 0x92, 0xF8, 0xFE, 0x21, 0x11, 0x44, 0x88, 0x42, + 0x04, 0xD9, 0x01, 0x20, 0x70, 0x47, 0x92, 0xF8, 0xFB, 0x11, 0xF2, 0xE7, + 0x00, 0x20, 0x70, 0x47, 0x2D, 0xE9, 0xF0, 0x41, 0x0E, 0x46, 0x80, 0x46, + 0x04, 0x20, 0x45, 0x49, 0x98, 0x73, 0x98, 0x8B, 0x08, 0x82, 0x44, 0x48, + 0x1C, 0x46, 0x15, 0x46, 0x00, 0x78, 0x88, 0x74, 0x03, 0xF1, 0x22, 0x00, + 0x08, 0x60, 0x80, 0x1C, 0x48, 0x60, 0x04, 0xF1, 0x26, 0x00, 0x88, 0x60, + 0x0D, 0x38, 0xC8, 0x60, 0x0B, 0x46, 0x31, 0x46, 0x40, 0x46, 0x05, 0xF0, + 0x14, 0xFB, 0x2C, 0x4F, 0x38, 0x68, 0x90, 0xF8, 0xEA, 0x01, 0x81, 0x07, + 0x04, 0xD5, 0x21, 0x46, 0x28, 0x46, 0xFF, 0xF7, 0x4E, 0xFA, 0x05, 0xE0, + 0x40, 0x07, 0x03, 0xD5, 0x21, 0x46, 0x28, 0x46, 0xFF, 0xF7, 0x20, 0xFA, + 0x38, 0x68, 0x23, 0x46, 0x2A, 0x46, 0x90, 0xF8, 0xEA, 0x01, 0x31, 0x46, + 0x00, 0x07, 0x40, 0x46, 0x03, 0xD5, 0xBD, 0xE8, 0xF0, 0x41, 0x01, 0xF0, + 0x72, 0xB8, 0xBD, 0xE8, 0xF0, 0x41, 0xFF, 0xF7, 0xA7, 0xB9, 0x2D, 0xE9, + 0xF0, 0x41, 0x07, 0x46, 0x02, 0x20, 0x98, 0x73, 0x27, 0x48, 0x15, 0x46, + 0x0E, 0x46, 0xB3, 0xF9, 0x28, 0x10, 0xB0, 0xF9, 0x00, 0x20, 0x58, 0x8B, + 0x1C, 0x46, 0x91, 0x42, 0x02, 0xDD, 0x20, 0xF0, 0x10, 0x00, 0x01, 0xE0, + 0x40, 0xF0, 0x10, 0x00, 0x60, 0x83, 0x1D, 0x48, 0xA1, 0x8B, 0x03, 0x46, + 0x01, 0x82, 0x1C, 0x49, 0x2A, 0x46, 0x09, 0x78, 0x81, 0x74, 0x04, 0xF1, + 0x22, 0x01, 0x01, 0x60, 0x89, 0x1C, 0x41, 0x60, 0x89, 0x1C, 0x81, 0x60, + 0x0D, 0x39, 0xC1, 0x60, 0x31, 0x46, 0x38, 0x46, 0x05, 0xF0, 0xC7, 0xFA, + 0x23, 0x46, 0x2A, 0x46, 0x31, 0x46, 0x38, 0x46, 0xBD, 0xE8, 0xF0, 0x41, + 0xFF, 0xF7, 0x74, 0xB9, 0x38, 0x23, 0x10, 0x00, 0x3C, 0x23, 0x10, 0x00, + 0x50, 0x24, 0x10, 0x00, 0x05, 0x24, 0x10, 0x00, 0x06, 0x24, 0x10, 0x00, + 0x07, 0x24, 0x10, 0x00, 0x58, 0x25, 0x10, 0x00, 0x6E, 0x23, 0x10, 0x00, + 0x8A, 0x25, 0x10, 0x00, 0x9C, 0x23, 0x10, 0x00, 0x10, 0x24, 0x10, 0x00, + 0xB8, 0x23, 0x10, 0x00, 0xCE, 0x23, 0x10, 0x00, 0xCC, 0x23, 0x10, 0x00, + 0x2A, 0x24, 0x10, 0x00, 0x40, 0x50, 0x10, 0x00, 0x01, 0x24, 0x10, 0x00, + 0xC6, 0x23, 0x10, 0x00, 0x2D, 0xE9, 0xFF, 0x4F, 0x91, 0xB0, 0x0F, 0x46, + 0xDD, 0xE9, 0x1E, 0x29, 0x01, 0x2A, 0x99, 0xF8, 0x00, 0x10, 0x99, 0xF8, + 0x01, 0x00, 0x07, 0xD0, 0x00, 0x22, 0x82, 0x46, 0x0C, 0xAB, 0x10, 0x46, + 0x83, 0xE8, 0x07, 0x00, 0x2D, 0x20, 0x12, 0xE0, 0x3A, 0x78, 0x0E, 0x92, + 0x7A, 0x78, 0x82, 0x42, 0x00, 0xD2, 0x50, 0x1C, 0x00, 0xF0, 0xFF, 0x0A, + 0xB8, 0x78, 0x0C, 0x90, 0xF8, 0x78, 0x88, 0x42, 0x00, 0xD2, 0x41, 0x1C, + 0xC8, 0xB2, 0x0D, 0x90, 0xEC, 0xE7, 0x0D, 0xF8, 0x00, 0x00, 0x40, 0x1E, + 0xFB, 0xD2, 0x13, 0x98, 0x0C, 0x9A, 0x40, 0x1C, 0xC5, 0xB2, 0x99, 0xF8, + 0x01, 0x00, 0x11, 0x99, 0x80, 0x1C, 0x02, 0xFB, 0x00, 0x16, 0x50, 0x1C, + 0x3C, 0xE0, 0x99, 0xF8, 0x01, 0x00, 0x11, 0x99, 0xB3, 0x46, 0x80, 0x1C, + 0x08, 0xFB, 0x00, 0x16, 0x0E, 0x9C, 0x2E, 0xE0, 0x31, 0x19, 0x08, 0x68, + 0x80, 0xB1, 0x30, 0x5D, 0x48, 0xB3, 0x11, 0xF8, 0x01, 0x1C, 0x00, 0x20, + 0x01, 0xB1, 0x08, 0x46, 0x1B, 0xF8, 0x04, 0x10, 0x11, 0xB1, 0x6A, 0x46, + 0x00, 0xF0, 0xBB, 0xF8, 0x14, 0x99, 0x01, 0x29, 0x02, 0xD0, 0x10, 0xE0, + 0xE4, 0x1C, 0x18, 0xE0, 0x0B, 0xEB, 0x04, 0x01, 0x0F, 0x91, 0x11, 0xF8, + 0x01, 0x1C, 0x11, 0xB1, 0x6A, 0x46, 0x00, 0xF0, 0xAC, 0xF8, 0x0F, 0x99, + 0x49, 0x78, 0x11, 0xB1, 0x6A, 0x46, 0x00, 0xF0, 0xA6, 0xF8, 0x38, 0xB9, + 0x2D, 0x2D, 0x03, 0xD2, 0x28, 0x46, 0x6D, 0x1C, 0xED, 0xB2, 0x01, 0xE0, + 0x68, 0x1E, 0xC0, 0xB2, 0x30, 0x55, 0x64, 0x1C, 0x54, 0x45, 0xCD, 0xD9, + 0x08, 0xF1, 0x01, 0x00, 0x0D, 0x99, 0x80, 0x46, 0x88, 0x42, 0xBE, 0xD9, + 0x69, 0x46, 0x2C, 0x46, 0x07, 0xE0, 0xE8, 0xB2, 0x0B, 0x46, 0x00, 0xE0, + 0x10, 0x46, 0x1A, 0x5C, 0x82, 0x42, 0xFB, 0xD1, 0x48, 0x55, 0x6D, 0x1E, + 0xF5, 0xD2, 0x00, 0x23, 0x18, 0x46, 0x09, 0xE0, 0x0A, 0x5C, 0x82, 0x42, + 0x03, 0xD1, 0x0B, 0x54, 0x5B, 0x1C, 0xDB, 0xB2, 0x01, 0xE0, 0x8A, 0x5C, + 0x0A, 0x54, 0x40, 0x1C, 0xA0, 0x42, 0xF3, 0xD3, 0x00, 0x22, 0x13, 0x98, + 0x09, 0xE0, 0xD9, 0xF8, 0x04, 0x40, 0x07, 0xEB, 0x80, 0x01, 0x24, 0x68, + 0x0C, 0x60, 0x07, 0xEB, 0x40, 0x01, 0xA1, 0xF8, 0xB4, 0x20, 0x40, 0x1C, + 0x98, 0x42, 0xF2, 0xD3, 0x0C, 0x9A, 0x31, 0xE0, 0x99, 0xF8, 0x01, 0x00, + 0x54, 0x1C, 0x11, 0x99, 0x80, 0x1C, 0x04, 0xFB, 0x00, 0x14, 0x0E, 0x99, + 0x25, 0xE0, 0x65, 0x18, 0x01, 0x20, 0x40, 0x59, 0x68, 0xB3, 0x68, 0x78, + 0xF0, 0xB1, 0x1D, 0xF8, 0x00, 0x00, 0x68, 0x70, 0x07, 0xEB, 0x40, 0x05, + 0x07, 0xEB, 0x80, 0x00, 0x35, 0xF8, 0xB4, 0x6F, 0x76, 0x1C, 0x2E, 0x80, + 0x05, 0x78, 0xA9, 0x42, 0x00, 0xD2, 0x0D, 0x46, 0x05, 0x70, 0x45, 0x78, + 0xA9, 0x42, 0x00, 0xD9, 0x0D, 0x46, 0x45, 0x70, 0x85, 0x78, 0xAA, 0x42, + 0x00, 0xD2, 0x15, 0x46, 0x85, 0x70, 0xC5, 0x78, 0xAA, 0x42, 0x00, 0xD9, + 0x15, 0x46, 0xC5, 0x70, 0x49, 0x1C, 0x51, 0x45, 0xD7, 0xD3, 0x52, 0x1C, + 0x0D, 0x98, 0x82, 0x42, 0xCA, 0xD3, 0x5B, 0x1E, 0x87, 0xF8, 0x0E, 0x31, + 0x15, 0xB0, 0xBD, 0xE8, 0xF0, 0x8F, 0xC9, 0x1C, 0xF0, 0xE7, 0x2D, 0xE9, + 0xF0, 0x43, 0x02, 0xEB, 0x81, 0x04, 0x81, 0x46, 0xA5, 0x78, 0x4F, 0xF0, + 0x00, 0x08, 0x12, 0xE0, 0x58, 0x78, 0x6F, 0x1C, 0x80, 0x1C, 0x07, 0xFB, + 0x00, 0x9C, 0x20, 0x78, 0x07, 0xE0, 0x0C, 0xEB, 0x00, 0x06, 0x77, 0x78, + 0x8F, 0x42, 0x01, 0xD1, 0x86, 0xF8, 0x01, 0x80, 0x40, 0x1C, 0x66, 0x78, + 0x86, 0x42, 0xF4, 0xD2, 0x6D, 0x1C, 0xE0, 0x78, 0xA8, 0x42, 0xE9, 0xD2, + 0x58, 0x68, 0x00, 0x68, 0x20, 0x60, 0x02, 0xEB, 0x41, 0x00, 0xA0, 0xF8, + 0xB4, 0x80, 0xBD, 0xE8, 0xF0, 0x83, 0x38, 0xB1, 0x88, 0x42, 0x02, 0xD2, + 0x0B, 0x46, 0x01, 0x46, 0x18, 0x46, 0x88, 0x42, 0x00, 0xD0, 0x11, 0x54, + 0x08, 0x46, 0x70, 0x47, 0xF0, 0xB5, 0x1E, 0x4A, 0x87, 0xB0, 0x12, 0x68, + 0x02, 0xF5, 0xA0, 0x66, 0x99, 0xB1, 0x01, 0x29, 0x1B, 0xD0, 0x02, 0x29, + 0x23, 0xD0, 0x00, 0x21, 0x0D, 0x46, 0x4A, 0x19, 0xC8, 0x2A, 0x08, 0xDC, + 0x05, 0x97, 0xCD, 0xE9, 0x00, 0x14, 0x02, 0xAA, 0x69, 0x46, 0x82, 0xE8, + 0x28, 0x10, 0x05, 0xF0, 0x3C, 0xF9, 0x07, 0xB0, 0xF0, 0xBD, 0x92, 0xF8, + 0xFB, 0x14, 0x92, 0xF8, 0xFC, 0x54, 0x33, 0x46, 0x06, 0xEB, 0x41, 0x07, + 0x92, 0xF8, 0xFD, 0x24, 0x12, 0xE0, 0x92, 0xF8, 0xFB, 0x14, 0x92, 0xF8, + 0xFC, 0x54, 0x33, 0x46, 0x06, 0xEB, 0x41, 0x07, 0x92, 0xF8, 0xFE, 0x24, + 0x08, 0xE0, 0x92, 0xF8, 0xFB, 0x14, 0x92, 0xF8, 0xFC, 0x54, 0x92, 0xF8, + 0xFF, 0x24, 0x33, 0x46, 0x06, 0xEB, 0x41, 0x07, 0x03, 0xEB, 0x42, 0x04, + 0x04, 0xEB, 0x41, 0x0C, 0xCF, 0xE7, 0x00, 0x00, 0x50, 0x24, 0x10, 0x00, + 0x30, 0xB4, 0x11, 0x4B, 0x04, 0x46, 0x0F, 0x48, 0x1B, 0x68, 0xB0, 0xF9, + 0x00, 0x00, 0x93, 0xF8, 0xD0, 0x31, 0x1B, 0x07, 0x03, 0xD5, 0x20, 0x46, + 0x30, 0xBC, 0x00, 0xF0, 0x17, 0xB8, 0x30, 0xBC, 0x70, 0x47, 0x30, 0xB4, + 0x00, 0x25, 0x5D, 0x85, 0x07, 0x4D, 0x04, 0x46, 0x01, 0x20, 0x2D, 0x68, + 0x95, 0xF8, 0xD0, 0x51, 0x2D, 0x07, 0xF2, 0xD5, 0x20, 0x46, 0x30, 0xBC, + 0x00, 0xF0, 0x79, 0xB8, 0xED, 0xE7, 0x00, 0x00, 0xC8, 0x23, 0x10, 0x00, + 0x50, 0x24, 0x10, 0x00, 0x30, 0xB5, 0x64, 0x49, 0x65, 0x4C, 0xB1, 0xF9, + 0x00, 0x30, 0x24, 0x68, 0x62, 0x49, 0xB4, 0xF9, 0xE2, 0x51, 0xB1, 0xF9, + 0x00, 0x10, 0xB4, 0xF9, 0xE4, 0x41, 0x2A, 0xB9, 0x60, 0x49, 0xB1, 0xF9, + 0x00, 0x30, 0x60, 0x49, 0xB1, 0xF9, 0x00, 0x10, 0xA0, 0x42, 0x01, 0xDD, + 0x08, 0x46, 0x30, 0xBD, 0xA8, 0x42, 0x01, 0xDA, 0x18, 0x46, 0x30, 0xBD, + 0x20, 0x1A, 0xCA, 0x1A, 0x50, 0x43, 0x62, 0x1B, 0x90, 0xFB, 0xF2, 0xF0, + 0x08, 0x1A, 0x00, 0xB2, 0x30, 0xBD, 0x2D, 0xE9, 0xF0, 0x47, 0x47, 0x7A, + 0x89, 0x46, 0x06, 0x46, 0x04, 0x7A, 0x39, 0x46, 0x00, 0x69, 0x08, 0xF0, + 0x25, 0xF8, 0x80, 0x46, 0x78, 0x1E, 0xC1, 0xB2, 0x30, 0x69, 0x08, 0xF0, + 0x1F, 0xF8, 0x05, 0x46, 0x7F, 0x1C, 0xF9, 0xB2, 0x30, 0x69, 0x08, 0xF0, + 0x19, 0xF8, 0x03, 0x46, 0x38, 0xF9, 0x14, 0x60, 0x4F, 0xF0, 0xFF, 0x31, + 0x0A, 0x46, 0x5F, 0xEA, 0x09, 0x00, 0x07, 0xD0, 0x01, 0x28, 0x0A, 0xD0, + 0x02, 0x28, 0x0D, 0xD0, 0xB9, 0xF1, 0x03, 0x0F, 0x1B, 0xD1, 0x12, 0xE0, + 0x35, 0xF9, 0x14, 0x10, 0x33, 0xF9, 0x14, 0x20, 0x15, 0xE0, 0x08, 0xEB, + 0x44, 0x00, 0x30, 0xF9, 0x02, 0x1C, 0x0E, 0xE0, 0x05, 0xEB, 0x44, 0x00, + 0xB0, 0xF9, 0x02, 0x10, 0x03, 0xEB, 0x44, 0x00, 0x30, 0xF9, 0x02, 0x2C, + 0x07, 0xE0, 0x05, 0xEB, 0x44, 0x00, 0x30, 0xF9, 0x02, 0x1C, 0x03, 0xEB, + 0x44, 0x00, 0xB0, 0xF9, 0x02, 0x20, 0x48, 0x1C, 0x00, 0xD1, 0x11, 0x46, + 0x50, 0x1C, 0x00, 0xD1, 0x0A, 0x46, 0x50, 0x18, 0xC0, 0xEB, 0x46, 0x00, + 0x00, 0xB2, 0xBD, 0xE8, 0xF0, 0x87, 0x2D, 0xE9, 0xFC, 0x5F, 0x00, 0x26, + 0x00, 0x96, 0x99, 0x7E, 0x1D, 0x46, 0xB2, 0x46, 0xB0, 0x46, 0x30, 0x46, + 0x89, 0x07, 0x07, 0xD0, 0x27, 0x49, 0x09, 0x68, 0xB1, 0xF8, 0xE4, 0x11, + 0x89, 0x1C, 0x0C, 0xB2, 0x5C, 0x85, 0x35, 0xE0, 0x01, 0x21, 0x18, 0x46, + 0xFF, 0xF7, 0x9B, 0xFF, 0x82, 0x46, 0x00, 0x21, 0x28, 0x46, 0xFF, 0xF7, + 0x96, 0xFF, 0x80, 0x46, 0x50, 0x44, 0x00, 0xB2, 0x01, 0x90, 0x68, 0x7A, + 0x2F, 0x7A, 0x44, 0x1E, 0x07, 0xF1, 0x01, 0x09, 0x00, 0xF1, 0x01, 0x0B, + 0x0E, 0xE0, 0xE1, 0xB2, 0x28, 0x69, 0x07, 0xF0, 0xB5, 0xFF, 0x01, 0x46, + 0x78, 0x1E, 0x04, 0xE0, 0x31, 0xF8, 0x10, 0x20, 0x40, 0x1C, 0x32, 0x44, + 0x16, 0xB2, 0x48, 0x45, 0xF8, 0xDD, 0x64, 0x1C, 0x5C, 0x45, 0xEE, 0xDD, + 0x01, 0x98, 0xFA, 0x21, 0x48, 0x43, 0x90, 0xFB, 0xF6, 0xF0, 0x04, 0xB2, + 0x6C, 0x85, 0x69, 0x8B, 0x01, 0x22, 0x20, 0x46, 0xFF, 0xF7, 0x48, 0xFF, + 0xB5, 0xF9, 0x28, 0x10, 0x81, 0x42, 0x01, 0xDD, 0x01, 0x21, 0x00, 0x91, + 0x0A, 0x49, 0x8C, 0x80, 0xCE, 0x80, 0x08, 0x81, 0xA1, 0xF8, 0x0A, 0x80, + 0xA1, 0xF8, 0x0C, 0xA0, 0x00, 0x98, 0xBD, 0xE8, 0xFC, 0x9F, 0x00, 0x00, + 0xCC, 0x23, 0x10, 0x00, 0xCE, 0x23, 0x10, 0x00, 0x50, 0x24, 0x10, 0x00, + 0xC6, 0x23, 0x10, 0x00, 0xC8, 0x23, 0x10, 0x00, 0xA8, 0x25, 0x10, 0x00, + 0x2D, 0xE9, 0xFF, 0x5F, 0x47, 0xF6, 0xFF, 0x76, 0x9B, 0x46, 0x17, 0x46, + 0x89, 0x46, 0xF5, 0x43, 0x94, 0x78, 0xDD, 0xF8, 0x3C, 0xA0, 0x1C, 0xE0, + 0xE1, 0xB2, 0x00, 0x98, 0x07, 0xF0, 0x64, 0xFF, 0x80, 0x46, 0xE1, 0xB2, + 0xDA, 0xF8, 0x14, 0x00, 0x07, 0xF0, 0x68, 0xFF, 0x39, 0x78, 0x7B, 0x78, + 0x0C, 0xE0, 0x18, 0xF8, 0x01, 0xC0, 0xCC, 0x45, 0x07, 0xD1, 0x30, 0xF9, + 0x11, 0x20, 0xB2, 0x42, 0x00, 0xDA, 0x16, 0x46, 0xAA, 0x42, 0x00, 0xDD, + 0x15, 0x46, 0x49, 0x1C, 0x8B, 0x42, 0xF0, 0xD2, 0x64, 0x1C, 0xF8, 0x78, + 0xA0, 0x42, 0xDF, 0xD2, 0xAB, 0xF8, 0x00, 0x60, 0x0E, 0x98, 0x05, 0x80, + 0xBD, 0xE8, 0xFF, 0x9F, 0x2D, 0xE9, 0xFF, 0x4F, 0xFF, 0x48, 0x85, 0xB0, + 0x1E, 0x46, 0x00, 0x68, 0x15, 0x46, 0x03, 0xAB, 0x90, 0xF8, 0x6E, 0x41, + 0x02, 0xA8, 0xCD, 0xE9, 0x00, 0x06, 0xDD, 0xE9, 0x05, 0x01, 0xFF, 0xF7, + 0xBD, 0xFF, 0xBD, 0xF9, 0x08, 0x10, 0xBD, 0xF9, 0x0C, 0x00, 0x64, 0x22, + 0x09, 0x1A, 0x61, 0x43, 0x91, 0xFB, 0xF2, 0xF1, 0xF4, 0x4F, 0x0C, 0x18, + 0x4F, 0xF4, 0x88, 0x61, 0x38, 0x68, 0x06, 0xF0, 0xA6, 0xF8, 0x05, 0x98, + 0x01, 0x90, 0x38, 0x68, 0x00, 0x90, 0x0F, 0xFA, 0x84, 0xF8, 0xAC, 0x78, + 0x4F, 0xF0, 0x01, 0x0B, 0x06, 0x9F, 0x1F, 0xE0, 0xE1, 0xB2, 0x01, 0x98, + 0x07, 0xF0, 0x12, 0xFF, 0x82, 0x46, 0xE1, 0xB2, 0x00, 0x98, 0x07, 0xF0, + 0x0D, 0xFF, 0x81, 0x46, 0xE1, 0xB2, 0x70, 0x69, 0x07, 0xF0, 0x12, 0xFF, + 0x29, 0x78, 0x5B, 0x46, 0x0A, 0xE0, 0x1A, 0xF8, 0x01, 0x20, 0xBA, 0x42, + 0x05, 0xD1, 0x30, 0xF9, 0x11, 0xC0, 0xC4, 0x45, 0x01, 0xDD, 0x09, 0xF8, + 0x01, 0x30, 0x49, 0x1C, 0x6A, 0x78, 0x8A, 0x42, 0xF1, 0xD2, 0x64, 0x1C, + 0xE8, 0x78, 0xA0, 0x42, 0xDC, 0xD2, 0xDB, 0x4C, 0x00, 0x20, 0xDB, 0x49, + 0x84, 0xF8, 0x0E, 0x01, 0x28, 0x68, 0x20, 0x60, 0xCD, 0xE9, 0x00, 0xB1, + 0xD5, 0x4F, 0x01, 0x23, 0x00, 0x22, 0x21, 0x46, 0x38, 0x68, 0xFF, 0xF7, + 0x1F, 0xFD, 0xD5, 0x49, 0x06, 0xF1, 0x24, 0x00, 0x48, 0x60, 0x80, 0x1C, + 0x88, 0x60, 0x94, 0xF8, 0x0E, 0x01, 0x01, 0x28, 0x1F, 0xD9, 0x01, 0x25, + 0xB9, 0x46, 0x88, 0x46, 0x14, 0xE0, 0x04, 0xEB, 0x45, 0x00, 0xCD, 0x49, + 0xB0, 0xF8, 0xB4, 0x00, 0xB0, 0x83, 0xA8, 0xF8, 0x10, 0x00, 0x04, 0xEB, + 0x85, 0x00, 0x07, 0x46, 0x04, 0xF0, 0x80, 0xFF, 0x3A, 0x46, 0xE9, 0xB2, + 0x33, 0x46, 0xD9, 0xF8, 0x00, 0x00, 0xFE, 0xF7, 0x4D, 0xFE, 0x6D, 0x1C, + 0x94, 0xF8, 0x0E, 0x01, 0xA8, 0x42, 0xE6, 0xD2, 0x09, 0xB0, 0xBD, 0xE8, + 0xF0, 0x8F, 0xDD, 0xE9, 0x05, 0x01, 0x33, 0x46, 0x2A, 0x46, 0xFE, 0xF7, + 0x3F, 0xFE, 0xF5, 0xE7, 0x2D, 0xE9, 0xF0, 0x5F, 0x91, 0x46, 0x02, 0x46, + 0xB6, 0x48, 0x0C, 0x46, 0xBA, 0x49, 0x00, 0x68, 0xDD, 0xE9, 0x0B, 0xB7, + 0x09, 0x78, 0xDD, 0xF8, 0x28, 0x80, 0x90, 0xF8, 0x70, 0xA1, 0x1E, 0x46, + 0x09, 0x07, 0x01, 0xD5, 0x90, 0xF8, 0xB0, 0xA2, 0x41, 0x46, 0x10, 0x46, + 0x07, 0xF0, 0x9A, 0xFE, 0x05, 0x46, 0x41, 0x46, 0x20, 0x46, 0x07, 0xF0, + 0x95, 0xFE, 0x04, 0x46, 0x41, 0x46, 0x78, 0x69, 0x07, 0xF0, 0x9A, 0xFE, + 0x07, 0x46, 0x30, 0x78, 0x73, 0x78, 0x48, 0xB9, 0x29, 0x78, 0x49, 0x45, + 0x05, 0xD1, 0xB7, 0xF9, 0x00, 0x10, 0x59, 0x45, 0x01, 0xDD, 0x01, 0x20, + 0x20, 0x70, 0x01, 0x20, 0xDF, 0xF8, 0x98, 0x82, 0x98, 0xF8, 0x00, 0x10, + 0x49, 0x1E, 0x8B, 0x42, 0x3B, 0xD1, 0xEA, 0x5C, 0x4A, 0x45, 0x05, 0xD1, + 0x37, 0xF9, 0x13, 0x20, 0x5A, 0x45, 0x01, 0xDD, 0x01, 0x21, 0xE1, 0x54, + 0x5B, 0x1E, 0xDB, 0xB2, 0x2F, 0xE0, 0x2A, 0x5C, 0x4A, 0x45, 0x2B, 0xD1, + 0x37, 0xF9, 0x10, 0x10, 0x59, 0x45, 0x27, 0xDD, 0x07, 0xEB, 0x40, 0x02, + 0x51, 0x44, 0x32, 0xF9, 0x02, 0xEC, 0x00, 0x26, 0x09, 0xB2, 0x8E, 0x45, + 0x04, 0xDD, 0xB2, 0xF9, 0x02, 0xC0, 0x8C, 0x45, 0x00, 0xDD, 0x01, 0x26, + 0x01, 0x28, 0x08, 0xD9, 0x32, 0xF9, 0x04, 0xCC, 0x8C, 0x45, 0x04, 0xDD, + 0xB2, 0xF9, 0x02, 0xC0, 0x8C, 0x45, 0x00, 0xDD, 0x01, 0x26, 0x98, 0xF8, + 0x00, 0xC0, 0xAC, 0xF1, 0x02, 0x0C, 0x60, 0x45, 0x05, 0xD2, 0x8E, 0x45, + 0x03, 0xDD, 0xB2, 0xF9, 0x04, 0x20, 0x8A, 0x42, 0x02, 0xDC, 0x0E, 0xB9, + 0x01, 0x21, 0x21, 0x54, 0x40, 0x1C, 0x98, 0x42, 0xCD, 0xD9, 0xBD, 0xE8, + 0xF0, 0x9F, 0x2D, 0xE9, 0xFF, 0x4F, 0x7C, 0x4C, 0x8F, 0xB0, 0x82, 0x4D, + 0x20, 0x68, 0xDD, 0xF8, 0x70, 0xB0, 0x9A, 0x46, 0x90, 0xF8, 0x72, 0x01, + 0xC0, 0xB1, 0x04, 0xA8, 0xCD, 0xE9, 0x00, 0x0B, 0x05, 0xAB, 0x52, 0x46, + 0x11, 0x99, 0x0F, 0x98, 0xFF, 0xF7, 0xB2, 0xFE, 0xBD, 0xF9, 0x10, 0x00, + 0xBD, 0xF9, 0x14, 0x10, 0x40, 0x1A, 0x21, 0x68, 0x91, 0xF8, 0x72, 0x11, + 0x48, 0x43, 0x64, 0x21, 0x90, 0xFB, 0xF1, 0xF0, 0x29, 0x88, 0x08, 0x44, + 0x00, 0xB2, 0x01, 0xE0, 0xB5, 0xF9, 0x00, 0x00, 0x03, 0x90, 0x20, 0x68, + 0x27, 0x46, 0x90, 0xF8, 0x70, 0x11, 0x06, 0x91, 0x90, 0xF8, 0x71, 0x11, + 0x05, 0x91, 0x6A, 0x49, 0x09, 0x78, 0x09, 0x07, 0x05, 0xD5, 0x90, 0xF8, + 0xB0, 0x12, 0x06, 0x91, 0x90, 0xF8, 0xB1, 0x02, 0x05, 0x90, 0x9A, 0xF8, + 0x02, 0x40, 0x9A, 0xF8, 0x03, 0x00, 0x04, 0x90, 0x5C, 0xB9, 0x03, 0x99, + 0x0F, 0xAD, 0xCD, 0xE9, 0x00, 0x41, 0xCD, 0xF8, 0x08, 0xB0, 0x95, 0xE8, + 0x07, 0x00, 0x53, 0x46, 0xFF, 0xF7, 0x3E, 0xFF, 0x01, 0x24, 0x5F, 0x49, + 0x04, 0x98, 0x09, 0x78, 0x49, 0x1E, 0x88, 0x42, 0x0F, 0xD1, 0xDD, 0xE9, + 0x03, 0x12, 0xCD, 0xE9, 0x00, 0x21, 0x0F, 0xAD, 0xCD, 0xF8, 0x08, 0xB0, + 0x95, 0xE8, 0x07, 0x00, 0x53, 0x46, 0xFF, 0xF7, 0x2B, 0xFF, 0x04, 0x98, + 0x40, 0x1E, 0xC0, 0xB2, 0x04, 0x90, 0x60, 0x1E, 0xC1, 0xB2, 0xDB, 0xF8, + 0x14, 0x00, 0x07, 0xF0, 0xDD, 0xFD, 0x06, 0x46, 0x01, 0x2C, 0x07, 0xD9, + 0xA0, 0x1E, 0xC1, 0xB2, 0xDB, 0xF8, 0x14, 0x00, 0x07, 0xF0, 0xD4, 0xFD, + 0x01, 0x90, 0x00, 0xE0, 0x01, 0x96, 0x21, 0x46, 0xDB, 0xF8, 0x14, 0x00, + 0x07, 0xF0, 0xCC, 0xFD, 0x00, 0x90, 0x60, 0x1C, 0xC1, 0xB2, 0xDB, 0xF8, + 0x14, 0x00, 0x07, 0xF0, 0xC5, 0xFD, 0x05, 0x46, 0x01, 0x20, 0x09, 0x90, + 0x38, 0x68, 0x90, 0xF8, 0xD4, 0x10, 0x49, 0x07, 0x17, 0xD5, 0x9A, 0xF8, + 0x01, 0x20, 0x9A, 0xF8, 0x00, 0x10, 0x52, 0x1A, 0x90, 0xF8, 0xEB, 0x10, + 0x52, 0x1C, 0x8A, 0x42, 0x0D, 0xDC, 0x9A, 0xF8, 0x03, 0x30, 0x9A, 0xF8, + 0x02, 0x20, 0x9A, 0x1A, 0x52, 0x1C, 0x8A, 0x42, 0x05, 0xDC, 0xB0, 0xF8, + 0xEE, 0x00, 0xDB, 0xF8, 0x2C, 0x10, 0x81, 0x42, 0x01, 0xDD, 0x00, 0x20, + 0x09, 0x90, 0x00, 0x20, 0x08, 0x90, 0xD4, 0xE0, 0xE1, 0xB2, 0x0F, 0x98, + 0x07, 0xF0, 0x92, 0xFD, 0x0E, 0x90, 0xE1, 0xB2, 0x10, 0x98, 0x07, 0xF0, + 0x8D, 0xFD, 0x07, 0x90, 0xA0, 0x1C, 0xC1, 0xB2, 0xDB, 0xF8, 0x14, 0x00, + 0x07, 0xF0, 0x90, 0xFD, 0x86, 0x46, 0x9A, 0xF8, 0x00, 0x20, 0xB6, 0xE0, + 0x0E, 0x98, 0x81, 0x5C, 0x11, 0x98, 0x81, 0x42, 0x7E, 0xD1, 0x00, 0x98, + 0xDD, 0xF8, 0x14, 0xC0, 0x00, 0x21, 0x30, 0xF9, 0x12, 0x30, 0x06, 0x98, + 0x02, 0x93, 0x18, 0x44, 0x63, 0x44, 0x0F, 0xFA, 0x83, 0xFC, 0x36, 0xF9, + 0x12, 0x30, 0x00, 0xB2, 0x89, 0x46, 0x0F, 0x46, 0x0D, 0x93, 0x83, 0x42, + 0x05, 0xDD, 0x35, 0xF9, 0x12, 0x30, 0x83, 0x42, 0x01, 0xDD, 0x01, 0x21, + 0x0F, 0x46, 0x9A, 0xB3, 0x16, 0x4B, 0x1B, 0x78, 0x0C, 0x93, 0x5B, 0x1E, + 0x9A, 0x42, 0x7A, 0xD0, 0x00, 0x9B, 0x03, 0xEB, 0x42, 0x03, 0x33, 0xF9, + 0x02, 0x8C, 0xCD, 0xF8, 0x2C, 0x80, 0x80, 0x45, 0x05, 0xDD, 0xB3, 0xF9, + 0x02, 0x80, 0x80, 0x45, 0x01, 0xDD, 0x01, 0x21, 0x89, 0x46, 0x06, 0xEB, + 0x42, 0x08, 0xCD, 0xF8, 0x28, 0x80, 0x38, 0xF9, 0x02, 0x8C, 0xE0, 0x45, + 0x1A, 0xDD, 0x05, 0xEB, 0x42, 0x08, 0xB8, 0xF9, 0x02, 0x80, 0x12, 0xE0, + 0x50, 0x24, 0x10, 0x00, 0xA4, 0x23, 0x10, 0x00, 0x54, 0x50, 0x10, 0x00, + 0xAC, 0x23, 0x10, 0x00, 0x40, 0x50, 0x10, 0x00, 0x1C, 0x24, 0x10, 0x00, + 0x01, 0x24, 0x10, 0x00, 0xCC, 0x23, 0x10, 0x00, 0x00, 0x24, 0x10, 0x00, + 0x4B, 0xE0, 0xE0, 0x45, 0x00, 0xDD, 0x01, 0x21, 0xDD, 0xF8, 0x28, 0x80, + 0xB8, 0xF9, 0x02, 0x80, 0xE0, 0x45, 0x05, 0xDD, 0x05, 0xEB, 0x42, 0x08, + 0x38, 0xF9, 0x02, 0x8C, 0xE0, 0x45, 0x47, 0xDC, 0xE9, 0xBB, 0x01, 0x2C, + 0x0B, 0xD9, 0xDD, 0xF8, 0x04, 0xC0, 0x3C, 0xF9, 0x12, 0xC0, 0x84, 0x45, + 0x05, 0xDD, 0x35, 0xF9, 0x12, 0xC0, 0x84, 0x45, 0x01, 0xDD, 0x01, 0x21, + 0x0F, 0x46, 0xDF, 0xF8, 0x78, 0xC5, 0x9C, 0xF8, 0x00, 0xC0, 0xAC, 0xF1, + 0x02, 0x0C, 0x64, 0x45, 0x0B, 0xD2, 0xDD, 0xF8, 0x34, 0xC0, 0x84, 0x45, + 0x07, 0xDD, 0x3E, 0xF9, 0x12, 0xC0, 0x84, 0x45, 0x03, 0xDD, 0x00, 0xE0, + 0x30, 0xE0, 0x01, 0x21, 0x0F, 0x46, 0x01, 0x2A, 0x09, 0xD9, 0x33, 0xF9, + 0x04, 0xCC, 0x84, 0x45, 0x05, 0xDD, 0xB3, 0xF9, 0x02, 0xC0, 0x84, 0x45, + 0x01, 0xDD, 0x01, 0x21, 0x89, 0x46, 0xDD, 0xF8, 0x30, 0xC0, 0xAC, 0xF1, + 0x02, 0x0C, 0x62, 0x45, 0x07, 0xD2, 0xDD, 0xF8, 0x2C, 0xC0, 0x84, 0x45, + 0x03, 0xDD, 0xB3, 0xF9, 0x04, 0x30, 0x83, 0x42, 0x0D, 0xDC, 0x01, 0xB9, + 0x00, 0xE0, 0x07, 0xE0, 0xDD, 0xE9, 0x02, 0x01, 0x88, 0x42, 0x03, 0xDD, + 0x07, 0x98, 0x01, 0x21, 0x81, 0x54, 0x09, 0xE0, 0xB9, 0xF1, 0x00, 0x0F, + 0x06, 0xD0, 0x2F, 0xB1, 0x09, 0x98, 0x18, 0xB1, 0x07, 0x99, 0x01, 0x20, + 0x88, 0x54, 0x08, 0x90, 0x52, 0x1C, 0x9A, 0xF8, 0x01, 0x00, 0x90, 0x42, + 0xBF, 0xF4, 0x44, 0xAF, 0x01, 0x96, 0x00, 0x9E, 0x00, 0x95, 0x75, 0x46, + 0x64, 0x1C, 0x04, 0x98, 0x84, 0x42, 0x7F, 0xF6, 0x27, 0xAF, 0x08, 0x98, + 0x13, 0xB0, 0xFE, 0xE5, 0x2D, 0xE9, 0xF0, 0x47, 0x04, 0x46, 0x91, 0x42, + 0x60, 0xD0, 0x07, 0xD9, 0x01, 0xEB, 0x02, 0x00, 0xA0, 0xEB, 0x02, 0x01, + 0xCA, 0xB2, 0xA0, 0xEB, 0x02, 0x00, 0xC1, 0xB2, 0x01, 0xEB, 0x81, 0x00, + 0x00, 0xEB, 0xC1, 0x00, 0x04, 0xEB, 0x80, 0x01, 0x02, 0xEB, 0x82, 0x00, + 0x00, 0xEB, 0xC2, 0x00, 0x04, 0xEB, 0x80, 0x09, 0xB1, 0xF9, 0x2C, 0x50, + 0xB9, 0xF9, 0x2C, 0x00, 0x09, 0xF1, 0x04, 0x03, 0x01, 0xF1, 0x04, 0x01, + 0x85, 0x42, 0x00, 0xDA, 0x08, 0x85, 0x88, 0x8B, 0x9D, 0x8B, 0x28, 0x44, + 0x88, 0x83, 0xC8, 0x8B, 0xDD, 0x8B, 0x28, 0x44, 0xC8, 0x83, 0x08, 0x8C, + 0x1D, 0x8C, 0x28, 0x44, 0x08, 0x84, 0xC8, 0x6A, 0xDD, 0x6A, 0x28, 0x44, + 0xC8, 0x62, 0x1D, 0x6B, 0x0E, 0x6B, 0x0F, 0x68, 0x1B, 0x68, 0x4F, 0xEA, + 0x27, 0x4C, 0x4F, 0xEA, 0x23, 0x48, 0x0C, 0xFB, 0x06, 0xFC, 0x05, 0xFB, + 0x08, 0xCC, 0x70, 0x19, 0x9C, 0xFB, 0xF0, 0xFC, 0x6C, 0xF3, 0x1F, 0x47, + 0x0F, 0xFA, 0x87, 0xFC, 0x0C, 0xFB, 0x06, 0xFC, 0x1B, 0xB2, 0x05, 0xFB, + 0x03, 0xC3, 0x93, 0xFB, 0xF0, 0xF3, 0x63, 0xF3, 0x0F, 0x07, 0x0F, 0x60, + 0x08, 0x63, 0x20, 0x78, 0x41, 0x1E, 0x91, 0x42, 0x0B, 0xD0, 0x00, 0xEB, + 0x80, 0x01, 0x01, 0xEB, 0xC0, 0x00, 0x04, 0xEB, 0x80, 0x01, 0x09, 0xF1, + 0x04, 0x00, 0x34, 0x22, 0x30, 0x39, 0x05, 0xF0, 0xA2, 0xFD, 0x20, 0x78, + 0x40, 0x1E, 0x20, 0x70, 0xBD, 0xE8, 0xF0, 0x87, 0x2D, 0xE9, 0xFC, 0x5F, + 0x07, 0x46, 0xFF, 0x48, 0x00, 0x24, 0x0D, 0x46, 0x02, 0x68, 0xB2, 0xF8, + 0x74, 0x01, 0x40, 0x43, 0x01, 0x90, 0xFC, 0x48, 0x00, 0x78, 0x00, 0x07, + 0x03, 0xD5, 0xB2, 0xF8, 0xB2, 0x02, 0x40, 0x43, 0x01, 0x90, 0x4F, 0xF0, + 0x64, 0x08, 0x84, 0xE0, 0x01, 0x20, 0xA8, 0x40, 0x2E, 0x46, 0x00, 0x90, + 0x5A, 0xE0, 0x4F, 0xF0, 0x01, 0x0E, 0x00, 0x99, 0x0E, 0xFA, 0x06, 0xF0, + 0x08, 0x42, 0x52, 0xD0, 0x06, 0xEB, 0x86, 0x00, 0x00, 0xEB, 0xC6, 0x00, + 0x07, 0xEB, 0x80, 0x00, 0xD0, 0xF8, 0x04, 0x90, 0x28, 0x46, 0x3D, 0xE0, + 0xB0, 0x42, 0x3A, 0xD0, 0x00, 0xEB, 0x80, 0x01, 0x01, 0xEB, 0xC0, 0x01, + 0x07, 0xEB, 0x81, 0x01, 0x4A, 0x68, 0x13, 0x14, 0xA3, 0xEB, 0x29, 0x41, + 0xE4, 0x4B, 0x09, 0xB2, 0xA2, 0xEB, 0x09, 0x02, 0x1B, 0x68, 0x61, 0xF3, + 0x1F, 0x44, 0x12, 0xB2, 0x93, 0xF8, 0x64, 0xC1, 0x62, 0xF3, 0x0F, 0x04, + 0xE2, 0x46, 0x5F, 0xEA, 0x8C, 0x6C, 0x08, 0xD5, 0x93, 0xF8, 0x73, 0xC1, + 0x02, 0xFB, 0x0C, 0xFC, 0x9C, 0xFB, 0xF8, 0xFC, 0x62, 0x44, 0x62, 0xF3, + 0x0F, 0x04, 0x5F, 0xEA, 0xCA, 0x62, 0x07, 0xD5, 0x93, 0xF8, 0x73, 0x21, + 0x4A, 0x43, 0x92, 0xFB, 0xF8, 0xF2, 0x11, 0x44, 0x61, 0xF3, 0x1F, 0x44, + 0x22, 0x14, 0x52, 0x43, 0x21, 0xB2, 0x01, 0xFB, 0x01, 0x21, 0x01, 0x9A, + 0x91, 0x42, 0x04, 0xD2, 0x00, 0x9A, 0x0E, 0xFA, 0x00, 0xF1, 0x11, 0x43, + 0x00, 0x91, 0x40, 0x1C, 0x83, 0x45, 0xBF, 0xD8, 0x04, 0x21, 0x68, 0x46, + 0x07, 0xF0, 0x42, 0xFE, 0x01, 0x28, 0x02, 0xD1, 0x00, 0x98, 0x40, 0x00, + 0x00, 0x90, 0x76, 0x1C, 0x38, 0x78, 0x83, 0x46, 0xB0, 0x42, 0xA0, 0xD8, + 0x04, 0x21, 0x68, 0x46, 0x07, 0xF0, 0x34, 0xFE, 0x01, 0x28, 0x1E, 0xD0, + 0x00, 0x99, 0x01, 0x22, 0x02, 0xFA, 0x05, 0xF0, 0x08, 0x42, 0x02, 0xD1, + 0x6D, 0x1C, 0xED, 0xB2, 0xF8, 0xE7, 0x3E, 0x78, 0x91, 0x46, 0x09, 0xE0, + 0x00, 0x99, 0x09, 0xFA, 0x06, 0xF0, 0x08, 0x42, 0x04, 0xD0, 0xF2, 0xB2, + 0x29, 0x46, 0x38, 0x46, 0xFF, 0xF7, 0x02, 0xFF, 0x76, 0x1E, 0xAE, 0x42, + 0xF2, 0xD8, 0x6D, 0x1C, 0xED, 0xB2, 0x38, 0x78, 0xA8, 0x42, 0x3F, 0xF6, + 0x77, 0xAF, 0xBD, 0xE8, 0xFC, 0x9F, 0x2D, 0xE9, 0xFF, 0x4F, 0xDF, 0xF8, + 0xC4, 0xA2, 0x83, 0xB0, 0x1D, 0x46, 0x4F, 0xF4, 0x88, 0x61, 0x54, 0x46, + 0xDA, 0xF8, 0x00, 0x00, 0x05, 0xF0, 0x29, 0xFD, 0x00, 0x95, 0xDD, 0xE9, + 0x04, 0x23, 0x21, 0x68, 0x03, 0x98, 0xFF, 0xF7, 0x62, 0xFD, 0x06, 0x46, + 0xA8, 0x4F, 0x00, 0x20, 0xA8, 0x49, 0x87, 0xF8, 0x0E, 0x01, 0x05, 0x98, + 0x4F, 0xF0, 0x01, 0x08, 0x33, 0x46, 0x00, 0x68, 0x38, 0x60, 0xCD, 0xE9, + 0x00, 0x81, 0x00, 0x22, 0x39, 0x46, 0x20, 0x68, 0xFF, 0xF7, 0xC6, 0xF9, + 0x01, 0x2E, 0x02, 0xD1, 0xA0, 0x49, 0x81, 0xF8, 0x00, 0x80, 0x97, 0xF8, + 0x0E, 0x31, 0x00, 0x26, 0x01, 0x2B, 0x63, 0xD9, 0xDF, 0xF8, 0x5C, 0x92, + 0x01, 0x21, 0x08, 0x46, 0xD9, 0xF8, 0x00, 0x20, 0x09, 0xE0, 0x07, 0xEB, + 0x40, 0x04, 0x92, 0xF8, 0x69, 0xC1, 0xB4, 0xF8, 0xB4, 0x40, 0x64, 0x45, + 0x00, 0xD9, 0x00, 0x21, 0x40, 0x1C, 0x83, 0x42, 0xF3, 0xD2, 0x89, 0xB3, + 0x02, 0x20, 0xA8, 0x73, 0xFD, 0xF7, 0xC2, 0xFB, 0xDF, 0xF8, 0x44, 0x82, + 0x05, 0xF1, 0x24, 0x01, 0x83, 0x46, 0xC8, 0xF8, 0x04, 0x10, 0x89, 0x1C, + 0x01, 0x24, 0xC8, 0xF8, 0x08, 0x10, 0x2E, 0xE0, 0xD9, 0xF8, 0x00, 0x10, + 0x07, 0xEB, 0x44, 0x00, 0xB0, 0xF8, 0xB4, 0x20, 0x91, 0xF8, 0x6F, 0x11, + 0x8A, 0x42, 0x18, 0xD9, 0x69, 0x8B, 0x41, 0xF0, 0x04, 0x01, 0x69, 0x83, + 0xB0, 0xF8, 0xB4, 0x00, 0xA8, 0x83, 0xA8, 0xF8, 0x10, 0x00, 0x07, 0xEB, + 0x84, 0x00, 0x06, 0x46, 0x80, 0x49, 0x04, 0xF0, 0xFB, 0xFB, 0x32, 0x46, + 0xE1, 0xB2, 0x2B, 0x46, 0xDA, 0xF8, 0x00, 0x00, 0xFE, 0xF7, 0xC8, 0xFA, + 0x01, 0x26, 0x0B, 0xE0, 0x1A, 0xE0, 0x7B, 0x48, 0x00, 0x78, 0x01, 0x28, + 0x06, 0xD1, 0x7A, 0x48, 0x00, 0x78, 0x18, 0xB9, 0x07, 0xEB, 0x84, 0x00, + 0xFB, 0xF7, 0x18, 0xFC, 0x64, 0x1C, 0x97, 0xF8, 0x0E, 0x01, 0xA0, 0x42, + 0xCC, 0xD2, 0xD9, 0xF8, 0x00, 0x00, 0x90, 0xF8, 0x64, 0x01, 0x00, 0x07, + 0x04, 0xD5, 0xFD, 0xF7, 0x7E, 0xFB, 0x59, 0x46, 0xFF, 0xF7, 0xCC, 0xFE, + 0x00, 0x2E, 0x08, 0xD1, 0x03, 0xAC, 0x2B, 0x46, 0x94, 0xE8, 0x07, 0x00, + 0x07, 0xB0, 0xBD, 0xE8, 0xF0, 0x4F, 0xFE, 0xF7, 0x9F, 0xBA, 0x07, 0xB0, + 0x55, 0xE4, 0x2D, 0xE9, 0xFF, 0x4F, 0x5F, 0x48, 0x87, 0xB0, 0xDF, 0xF8, + 0x74, 0x81, 0x00, 0x68, 0x90, 0xF8, 0x70, 0x01, 0x06, 0x90, 0x94, 0x78, + 0xD0, 0x78, 0x02, 0x90, 0x10, 0x78, 0x00, 0x90, 0x98, 0xF8, 0x00, 0x00, + 0x92, 0xF8, 0x01, 0xB0, 0x40, 0x1E, 0x84, 0x42, 0x01, 0xDA, 0x64, 0x1C, + 0xE4, 0xB2, 0x02, 0x98, 0x10, 0xB1, 0x40, 0x1E, 0xC0, 0xB2, 0x02, 0x90, + 0x5A, 0x49, 0x00, 0x98, 0x09, 0x78, 0x49, 0x1E, 0x88, 0x42, 0x02, 0xDA, + 0x40, 0x1C, 0xC0, 0xB2, 0x00, 0x90, 0xBB, 0xF1, 0x00, 0x0F, 0x03, 0xD0, + 0xAB, 0xF1, 0x01, 0x00, 0x00, 0xF0, 0xFF, 0x0B, 0x0A, 0x98, 0x21, 0x46, + 0x40, 0x69, 0x07, 0xF0, 0xE9, 0xFA, 0x05, 0x46, 0x84, 0xB1, 0x60, 0x1E, + 0xC1, 0xB2, 0x0A, 0x98, 0x40, 0x69, 0x07, 0xF0, 0xE1, 0xFA, 0x81, 0x46, + 0x01, 0x2C, 0x08, 0xD9, 0xA0, 0x1E, 0xC1, 0xB2, 0x0A, 0x98, 0x40, 0x69, + 0x07, 0xF0, 0xD8, 0xFA, 0x82, 0x46, 0x01, 0xE0, 0x81, 0x46, 0xCA, 0x46, + 0x98, 0xF8, 0x00, 0x00, 0x40, 0x1E, 0x84, 0x42, 0x07, 0xDA, 0x60, 0x1C, + 0xC1, 0xB2, 0x0A, 0x98, 0x40, 0x69, 0x07, 0xF0, 0xC9, 0xFA, 0x06, 0x46, + 0x00, 0xE0, 0x2E, 0x46, 0x00, 0x20, 0x03, 0x90, 0x89, 0xE0, 0xE1, 0xB2, + 0x07, 0x98, 0x07, 0xF0, 0xB5, 0xFA, 0x01, 0x90, 0xA0, 0x1C, 0xC1, 0xB2, + 0x0A, 0x98, 0x40, 0x69, 0x07, 0xF0, 0xB8, 0xFA, 0x86, 0x46, 0x00, 0x9A, + 0x74, 0xE0, 0x01, 0x98, 0x81, 0x5C, 0x08, 0x98, 0x81, 0x42, 0x6E, 0xD1, + 0x35, 0xF8, 0x12, 0x10, 0x06, 0x98, 0x00, 0x27, 0x08, 0x44, 0x39, 0xF9, + 0x12, 0x10, 0x00, 0xB2, 0x3B, 0x46, 0x05, 0x91, 0x81, 0x42, 0x04, 0xDD, + 0x36, 0xF9, 0x12, 0x10, 0x81, 0x42, 0x00, 0xDD, 0x01, 0x23, 0x05, 0xEB, + 0x42, 0x01, 0x31, 0xF9, 0x02, 0xCC, 0xCD, 0xF8, 0x10, 0xC0, 0x84, 0x45, + 0x04, 0xDD, 0xB1, 0xF9, 0x02, 0xC0, 0x84, 0x45, 0x00, 0xDD, 0x01, 0x27, + 0x01, 0x2C, 0x08, 0xDD, 0x3A, 0xF9, 0x12, 0xC0, 0x84, 0x45, 0x04, 0xDD, + 0x36, 0xF9, 0x12, 0xC0, 0x84, 0x45, 0x00, 0xDD, 0x01, 0x23, 0x98, 0xF8, + 0x00, 0xC0, 0xAC, 0xF1, 0x02, 0x0C, 0x64, 0x45, 0x08, 0xDA, 0xDD, 0xF8, + 0x14, 0xC0, 0x84, 0x45, 0x04, 0xDD, 0x3E, 0xF9, 0x12, 0xC0, 0x84, 0x45, + 0x00, 0xDD, 0x01, 0x23, 0x01, 0x2A, 0x08, 0xDD, 0x31, 0xF9, 0x04, 0xCC, + 0x84, 0x45, 0x04, 0xDD, 0xB1, 0xF9, 0x02, 0xC0, 0x84, 0x45, 0x00, 0xDD, + 0x01, 0x27, 0xDF, 0xF8, 0x48, 0xC0, 0x9C, 0xF8, 0x00, 0xC0, 0xAC, 0xF1, + 0x02, 0x0C, 0x62, 0x45, 0x07, 0xDA, 0xDD, 0xF8, 0x10, 0xC0, 0x84, 0x45, + 0x03, 0xDD, 0xB1, 0xF9, 0x04, 0x10, 0x81, 0x42, 0x18, 0xDC, 0x16, 0xE0, + 0x00, 0x24, 0x10, 0x00, 0x50, 0x24, 0x10, 0x00, 0x1C, 0x24, 0x10, 0x00, + 0xA4, 0x23, 0x10, 0x00, 0x54, 0x50, 0x10, 0x00, 0xAC, 0x23, 0x10, 0x00, + 0x9C, 0x23, 0x10, 0x00, 0x40, 0x50, 0x10, 0x00, 0x71, 0x23, 0x10, 0x00, + 0x6D, 0x23, 0x10, 0x00, 0x01, 0x24, 0x10, 0x00, 0x03, 0xE0, 0x17, 0xB1, + 0x0B, 0xB1, 0x01, 0x20, 0x03, 0x90, 0x52, 0x1C, 0x5A, 0x45, 0x88, 0xDD, + 0xCA, 0x46, 0xA9, 0x46, 0x35, 0x46, 0x76, 0x46, 0x64, 0x1C, 0x02, 0x98, + 0x84, 0x42, 0x7F, 0xF7, 0x72, 0xAF, 0x03, 0x98, 0x0B, 0xB0, 0xBD, 0xE8, + 0xF0, 0x8F, 0x2D, 0xE9, 0xF7, 0x4F, 0x04, 0x46, 0x40, 0x78, 0x21, 0x78, + 0x86, 0x4F, 0x41, 0x1A, 0x49, 0x1C, 0x38, 0x68, 0x82, 0xB0, 0x91, 0x46, + 0x90, 0xF8, 0xEB, 0x00, 0x81, 0x42, 0x67, 0xDC, 0xE1, 0x78, 0xA2, 0x78, + 0x89, 0x1A, 0x49, 0x1C, 0x81, 0x42, 0x61, 0xDC, 0xDF, 0xF8, 0xFC, 0xA1, + 0x4F, 0xF4, 0x88, 0x61, 0xDA, 0xF8, 0x00, 0x00, 0x05, 0xF0, 0x8F, 0xFB, + 0x00, 0x26, 0xA5, 0x78, 0x4F, 0xF0, 0x01, 0x0B, 0x1F, 0xE0, 0xE9, 0xB2, + 0xDA, 0xF8, 0x00, 0x00, 0x07, 0xF0, 0x00, 0xFA, 0x80, 0x46, 0x03, 0x98, + 0xE9, 0xB2, 0x40, 0x69, 0x07, 0xF0, 0x04, 0xFA, 0x03, 0x46, 0x20, 0x78, + 0xDC, 0x46, 0x0C, 0xE0, 0x3A, 0x68, 0x33, 0xF9, 0x10, 0x10, 0xB2, 0xF8, + 0x4C, 0x21, 0x91, 0x42, 0x04, 0xDD, 0x49, 0x45, 0x02, 0xDA, 0x08, 0xF8, + 0x00, 0xC0, 0x01, 0x26, 0x40, 0x1C, 0x61, 0x78, 0x81, 0x42, 0xEF, 0xD2, + 0x6D, 0x1C, 0xE0, 0x78, 0xA8, 0x42, 0xDC, 0xD2, 0x01, 0x2E, 0x2F, 0xD1, + 0x67, 0x4E, 0x00, 0x20, 0x67, 0x49, 0x86, 0xF8, 0x0E, 0x01, 0x20, 0x68, + 0x30, 0x60, 0xCD, 0xE9, 0x00, 0xB1, 0x00, 0x23, 0x1A, 0x46, 0x31, 0x46, + 0xDA, 0xF8, 0x00, 0x00, 0xFF, 0xF7, 0x0C, 0xF8, 0x01, 0x25, 0x19, 0xE0, + 0x16, 0xF8, 0x25, 0x00, 0x21, 0x78, 0x88, 0x42, 0x13, 0xD9, 0x06, 0xEB, + 0x85, 0x00, 0x62, 0x78, 0x41, 0x78, 0x91, 0x42, 0x0D, 0xD2, 0x81, 0x78, + 0xA2, 0x78, 0x91, 0x42, 0x09, 0xD9, 0xC1, 0x78, 0xE2, 0x78, 0x91, 0x42, + 0x05, 0xD2, 0x4A, 0x46, 0x03, 0x99, 0x00, 0xF0, 0x51, 0xF8, 0x01, 0x28, + 0x05, 0xD0, 0x6D, 0x1C, 0x96, 0xF8, 0x0E, 0x01, 0xA8, 0x42, 0xE1, 0xD2, + 0x00, 0x20, 0x05, 0xB0, 0x83, 0xE7, 0x2D, 0xE9, 0xF0, 0x41, 0x1C, 0x46, + 0x15, 0x46, 0x0E, 0x46, 0x07, 0x46, 0x00, 0xF0, 0x1E, 0xF8, 0xA1, 0x7B, + 0x04, 0x29, 0x05, 0xD0, 0x46, 0x49, 0x09, 0x68, 0x91, 0xF8, 0x64, 0x11, + 0x89, 0x07, 0x07, 0xD5, 0x23, 0x46, 0x2A, 0x46, 0x31, 0x46, 0x38, 0x46, + 0xBD, 0xE8, 0xF0, 0x41, 0xFF, 0xF7, 0x52, 0xBA, 0x01, 0x28, 0x23, 0x46, + 0x2A, 0x46, 0x31, 0x46, 0x38, 0x46, 0x03, 0xD0, 0xBD, 0xE8, 0xF0, 0x41, + 0xFE, 0xF7, 0x16, 0xB9, 0xBD, 0xE8, 0xF0, 0x41, 0xD5, 0xE5, 0x39, 0x49, + 0x01, 0x20, 0x09, 0x68, 0x91, 0xF8, 0x64, 0x21, 0x53, 0x07, 0x0B, 0xD5, + 0x52, 0x06, 0x0A, 0xD5, 0x38, 0x4A, 0x12, 0x78, 0x8A, 0xB1, 0xB1, 0xF8, + 0x78, 0x21, 0x37, 0x4B, 0x52, 0x43, 0x1B, 0x68, 0x93, 0x42, 0x00, 0xDD, + 0x00, 0x20, 0x91, 0xF8, 0xB0, 0x10, 0x09, 0x06, 0x04, 0xD5, 0x33, 0x49, + 0x09, 0x78, 0x00, 0x29, 0x00, 0xD0, 0x00, 0x20, 0x70, 0x47, 0xB1, 0xF8, + 0x76, 0x21, 0xEC, 0xE7, 0x2D, 0xE9, 0xF0, 0x47, 0x05, 0x46, 0x90, 0xF8, + 0x02, 0x80, 0x0F, 0x46, 0x48, 0x69, 0x14, 0x46, 0x01, 0x26, 0x41, 0x46, + 0x07, 0xF0, 0x64, 0xF9, 0x81, 0x46, 0xA8, 0xF1, 0x01, 0x00, 0xC1, 0xB2, + 0x78, 0x69, 0x07, 0xF0, 0x5D, 0xF9, 0x29, 0x78, 0x09, 0xEB, 0x41, 0x02, + 0x32, 0xF9, 0x02, 0x2C, 0xA2, 0x42, 0x03, 0xDB, 0x30, 0xF9, 0x11, 0x10, + 0xA1, 0x42, 0x00, 0xDA, 0x00, 0x26, 0x69, 0x78, 0x09, 0xEB, 0x41, 0x02, + 0xB2, 0xF9, 0x02, 0x20, 0xA2, 0x42, 0x03, 0xDB, 0x30, 0xF9, 0x11, 0x00, + 0xA0, 0x42, 0x00, 0xDA, 0x00, 0x26, 0x95, 0xF8, 0x03, 0x80, 0x78, 0x69, + 0x41, 0x46, 0x07, 0xF0, 0x3F, 0xF9, 0x81, 0x46, 0x08, 0xF1, 0x01, 0x00, + 0xC1, 0xB2, 0x78, 0x69, 0x07, 0xF0, 0x38, 0xF9, 0x29, 0x78, 0x09, 0xEB, + 0x41, 0x02, 0x32, 0xF9, 0x02, 0x2C, 0xA2, 0x42, 0x03, 0xDB, 0x30, 0xF9, + 0x11, 0x10, 0xA1, 0x42, 0x00, 0xDA, 0x00, 0x26, 0x69, 0x78, 0x09, 0xEB, + 0x41, 0x02, 0xB2, 0xF9, 0x02, 0x20, 0xA2, 0x42, 0x03, 0xDB, 0x30, 0xF9, + 0x11, 0x00, 0xA0, 0x42, 0x00, 0xDA, 0x00, 0x26, 0x30, 0x46, 0xBF, 0xE4, + 0x50, 0x24, 0x10, 0x00, 0xA4, 0x23, 0x10, 0x00, 0x54, 0x50, 0x10, 0x00, + 0xAC, 0x23, 0x10, 0x00, 0xB8, 0x23, 0x10, 0x00, 0xDC, 0x23, 0x10, 0x00, + 0x6E, 0x23, 0x10, 0x00, 0xEE, 0x49, 0xEF, 0x4A, 0x00, 0x20, 0x08, 0x70, + 0xEE, 0x4B, 0x10, 0x70, 0x01, 0x22, 0x1A, 0x70, 0x88, 0x70, 0x70, 0x47, + 0x2D, 0xE9, 0xF0, 0x5F, 0x81, 0x46, 0xEB, 0x48, 0xDF, 0xF8, 0xAC, 0xE3, + 0x4F, 0xF0, 0x00, 0x0C, 0x01, 0x78, 0xDE, 0xF8, 0x00, 0x00, 0x05, 0x29, + 0x11, 0xD0, 0xB0, 0xF9, 0x4A, 0x70, 0xB0, 0xF9, 0x4C, 0x60, 0x90, 0xF8, + 0x46, 0x00, 0xDF, 0xF8, 0x98, 0xB3, 0x00, 0xF0, 0x0F, 0x02, 0xE3, 0x48, + 0xC2, 0xF1, 0x10, 0x05, 0x00, 0x21, 0x00, 0x68, 0xBB, 0xF9, 0x00, 0xA0, + 0x15, 0xE0, 0x30, 0xF9, 0x4E, 0x7F, 0xB0, 0xF9, 0x02, 0x60, 0x10, 0xF8, + 0x07, 0x0C, 0xEC, 0xE7, 0x30, 0xF9, 0x11, 0x40, 0x39, 0xF9, 0x11, 0x30, + 0x04, 0xEB, 0x07, 0x08, 0x98, 0x45, 0x02, 0xDB, 0xA4, 0x1B, 0x9C, 0x42, + 0x01, 0xDD, 0x4F, 0xF0, 0x01, 0x0C, 0x49, 0x1C, 0x09, 0xB2, 0x5C, 0x46, + 0x51, 0x45, 0xED, 0xDB, 0xBC, 0xF1, 0x00, 0x0F, 0x20, 0xD1, 0x00, 0x21, + 0x0B, 0xE0, 0x30, 0xF9, 0x11, 0x60, 0x39, 0xF9, 0x11, 0x30, 0x56, 0x43, + 0x03, 0xFB, 0x05, 0x63, 0x1B, 0x11, 0x20, 0xF8, 0x11, 0x30, 0x49, 0x1C, + 0x09, 0xB2, 0xB4, 0xF9, 0x00, 0x30, 0x99, 0x42, 0xEF, 0xDB, 0xDE, 0xF8, + 0x00, 0x10, 0x91, 0xF8, 0x30, 0x11, 0x89, 0x07, 0x08, 0xD5, 0xC8, 0x49, + 0xC6, 0x4B, 0x0A, 0x78, 0xC7, 0x49, 0x09, 0x78, 0xBD, 0xE8, 0xF0, 0x5F, + 0x02, 0xF0, 0xE4, 0xB9, 0xBD, 0xE8, 0xF0, 0x9F, 0x2D, 0xE9, 0xF0, 0x0F, + 0x80, 0x46, 0xBD, 0x48, 0x8C, 0x46, 0x99, 0x46, 0x00, 0x68, 0x01, 0x21, + 0xDD, 0xF8, 0x20, 0xA0, 0x90, 0xF8, 0x48, 0x00, 0x00, 0x23, 0x00, 0xF0, + 0x0F, 0x06, 0xC6, 0xF1, 0x10, 0x00, 0xDF, 0xF8, 0xF0, 0xB2, 0x13, 0xE0, + 0x3C, 0xF9, 0x13, 0x40, 0x38, 0xF9, 0x13, 0x50, 0x04, 0xEB, 0x09, 0x07, + 0xAF, 0x42, 0x16, 0xDB, 0xA4, 0xEB, 0x0A, 0x07, 0xAF, 0x42, 0x12, 0xDC, + 0x74, 0x43, 0x05, 0xFB, 0x00, 0x44, 0x25, 0x11, 0x2B, 0xF8, 0x13, 0x50, + 0x5B, 0x1C, 0x1B, 0xB2, 0x93, 0x42, 0xE9, 0xDB, 0x00, 0x29, 0x06, 0xD0, + 0xBD, 0xE8, 0xF0, 0x0F, 0x52, 0x00, 0xAD, 0x49, 0x60, 0x46, 0x05, 0xF0, + 0x71, 0xB9, 0xBD, 0xE8, 0xF0, 0x0F, 0x70, 0x47, 0x2D, 0xE9, 0xFF, 0x4F, + 0xA2, 0x4D, 0x9F, 0xB0, 0xDF, 0xF8, 0x94, 0x92, 0x28, 0x68, 0x2C, 0x9C, + 0xA4, 0x4E, 0x90, 0xF8, 0x04, 0x01, 0x93, 0x46, 0x0F, 0x46, 0xC0, 0x07, + 0x45, 0xD0, 0xE0, 0x06, 0x43, 0xD5, 0x4F, 0xF0, 0x00, 0x08, 0x33, 0x78, + 0xA0, 0x4A, 0x10, 0xA8, 0x02, 0xF0, 0x2F, 0xF8, 0x99, 0xF8, 0x00, 0x30, + 0x9E, 0x4A, 0x59, 0x46, 0x68, 0x46, 0x02, 0xF0, 0x28, 0xF8, 0x28, 0x68, + 0x31, 0x78, 0x90, 0xF8, 0x0D, 0x31, 0xB0, 0xF9, 0x05, 0x21, 0x10, 0xA8, + 0xFA, 0xF7, 0x8B, 0xFC, 0x82, 0x46, 0x28, 0x68, 0x99, 0xF8, 0x00, 0x10, + 0x90, 0xF8, 0x0E, 0x31, 0xB0, 0xF9, 0x07, 0x21, 0x68, 0x46, 0xFA, 0xF7, + 0x80, 0xFC, 0xBA, 0xF1, 0x01, 0x0F, 0x17, 0xD0, 0x01, 0x28, 0x15, 0xD0, + 0x28, 0x68, 0x31, 0x78, 0xB0, 0xF9, 0x09, 0x21, 0x10, 0xA8, 0xFA, 0xF7, + 0x86, 0xFC, 0x82, 0x46, 0x28, 0x68, 0x99, 0xF8, 0x00, 0x10, 0xB0, 0xF9, + 0x0B, 0x21, 0x68, 0x46, 0xFA, 0xF7, 0x7D, 0xFC, 0xBA, 0xF1, 0x01, 0x0F, + 0x04, 0xD0, 0x01, 0x28, 0x02, 0xD0, 0x03, 0xE0, 0x01, 0x20, 0x00, 0xE0, + 0x02, 0x20, 0x80, 0x46, 0x40, 0x46, 0x00, 0xF0, 0xA7, 0xF8, 0x00, 0xF0, + 0x28, 0xFE, 0xE8, 0xB9, 0xE0, 0x07, 0x02, 0xD0, 0x1F, 0x98, 0xFF, 0xF7, + 0x0F, 0xFF, 0xE0, 0x06, 0x16, 0xD5, 0x28, 0x68, 0xB0, 0xF9, 0x54, 0x10, + 0x00, 0x91, 0xB0, 0xF9, 0x52, 0x30, 0x32, 0x78, 0x77, 0x49, 0x38, 0x46, + 0xFF, 0xF7, 0x60, 0xFF, 0x28, 0x68, 0xB0, 0xF9, 0x58, 0x10, 0x00, 0x91, + 0xB0, 0xF9, 0x56, 0x30, 0x99, 0xF8, 0x00, 0x20, 0x72, 0x49, 0x58, 0x46, + 0xFF, 0xF7, 0x54, 0xFF, 0x00, 0xF0, 0x1A, 0xFE, 0xA0, 0xBB, 0xE0, 0x06, + 0x5A, 0xD5, 0x28, 0x68, 0x4F, 0xF0, 0x00, 0x0A, 0x90, 0xF8, 0x04, 0x01, + 0x80, 0x07, 0x19, 0xD5, 0xDF, 0xF8, 0x7C, 0x81, 0x98, 0xF8, 0x00, 0x00, + 0x01, 0x28, 0x01, 0xD0, 0x02, 0x28, 0x11, 0xD1, 0x67, 0x49, 0x08, 0x68, + 0x40, 0xF0, 0x22, 0x00, 0x08, 0x60, 0x2B, 0x21, 0x01, 0xF0, 0xB4, 0xFE, + 0x4F, 0xF4, 0x00, 0x71, 0x00, 0x20, 0x03, 0xF0, 0xC7, 0xFE, 0x54, 0x48, + 0x88, 0xF8, 0x00, 0xA0, 0x80, 0xF8, 0x00, 0xA0, 0x28, 0x68, 0x90, 0xF8, + 0x82, 0x10, 0xC9, 0x06, 0x34, 0xD5, 0x51, 0x49, 0x09, 0x78, 0xE9, 0xB1, + 0xB0, 0xF9, 0xA2, 0xC0, 0xB0, 0xF9, 0x9E, 0x80, 0x30, 0x78, 0x01, 0x22, + 0xB9, 0x46, 0x13, 0x46, 0x90, 0xB1, 0x0B, 0xE0, 0x26, 0xE0, 0x39, 0xF9, + 0x10, 0x10, 0x61, 0x45, 0x00, 0xDD, 0x00, 0x23, 0x41, 0x45, 0x00, 0xDA, + 0x00, 0x22, 0x52, 0xEA, 0x03, 0x01, 0x05, 0xD0, 0x40, 0x1E, 0xF2, 0xD2, + 0x01, 0x20, 0xA0, 0xB1, 0x00, 0x20, 0x13, 0xE0, 0x50, 0x46, 0xFA, 0xE7, + 0xB0, 0xF9, 0xA4, 0x20, 0xB0, 0xF9, 0xA0, 0x30, 0x30, 0x78, 0x58, 0xB1, + 0x07, 0xE0, 0x37, 0xF9, 0x10, 0x10, 0x99, 0x42, 0x01, 0xDA, 0x91, 0x42, + 0x01, 0xDC, 0x50, 0x46, 0x02, 0xE0, 0x40, 0x1E, 0xF5, 0xD2, 0x01, 0x20, + 0x00, 0xF0, 0x4F, 0xF8, 0x28, 0x68, 0x90, 0xF8, 0xB0, 0x10, 0x09, 0x07, + 0x1D, 0xD5, 0x40, 0x4D, 0x2B, 0x68, 0x13, 0xF0, 0x30, 0x0F, 0x18, 0xD0, + 0xE1, 0x06, 0x16, 0xD5, 0xB0, 0xF9, 0xCD, 0x40, 0x00, 0x22, 0x36, 0x78, + 0x10, 0x46, 0x09, 0xE0, 0x37, 0xF9, 0x10, 0x10, 0xA1, 0x42, 0x01, 0xDA, + 0x00, 0x29, 0x01, 0xDC, 0x01, 0x22, 0x03, 0xE0, 0x40, 0x1C, 0x00, 0xB2, + 0xB0, 0x42, 0xF3, 0xDB, 0x00, 0x2A, 0x02, 0xD0, 0x23, 0xF0, 0x30, 0x00, + 0x28, 0x60, 0x23, 0xB0, 0xBD, 0xE8, 0xF0, 0x8F, 0x30, 0xB4, 0x21, 0x49, + 0x24, 0x4A, 0x21, 0x4C, 0x0B, 0x78, 0x12, 0x68, 0x98, 0x42, 0x0C, 0xD1, + 0x20, 0x78, 0x98, 0x42, 0x48, 0x78, 0x14, 0xD0, 0x20, 0xB1, 0x40, 0x1E, + 0x10, 0xF0, 0xFF, 0x00, 0x48, 0x70, 0x10, 0xD1, 0x23, 0x70, 0x30, 0xBC, + 0x70, 0x47, 0x10, 0xB1, 0x92, 0xF8, 0x0F, 0x31, 0x00, 0xE0, 0x00, 0x23, + 0x4B, 0x70, 0x08, 0x70, 0x13, 0xF0, 0xFF, 0x0F, 0x03, 0xD1, 0x20, 0x70, + 0xF1, 0xE7, 0x00, 0x28, 0xEF, 0xD0, 0x92, 0xF8, 0xA8, 0x13, 0x30, 0xBC, + 0x07, 0x20, 0x00, 0xF0, 0x7C, 0xBD, 0x0F, 0x4B, 0x0C, 0x4A, 0x19, 0x78, + 0x81, 0x42, 0x07, 0xD0, 0x91, 0x78, 0x21, 0xB1, 0x49, 0x1E, 0x11, 0xF0, + 0xFF, 0x01, 0x91, 0x70, 0x00, 0xD1, 0x18, 0x70, 0x19, 0x78, 0x81, 0x42, + 0x08, 0xD1, 0x09, 0x48, 0x00, 0x68, 0x11, 0xB1, 0x90, 0xF8, 0xA6, 0x00, + 0x01, 0xE0, 0x90, 0xF8, 0xA7, 0x00, 0x90, 0x70, 0x70, 0x47, 0x00, 0x00, + 0xB4, 0x23, 0x10, 0x00, 0x6C, 0x23, 0x10, 0x00, 0x5A, 0x23, 0x10, 0x00, + 0x60, 0x24, 0x10, 0x00, 0x50, 0x24, 0x10, 0x00, 0x18, 0x24, 0x10, 0x00, + 0x0C, 0x24, 0x10, 0x00, 0x48, 0x53, 0x10, 0x00, 0x01, 0x24, 0x10, 0x00, + 0x00, 0x24, 0x10, 0x00, 0x5E, 0x48, 0x10, 0x00, 0xFC, 0x22, 0x01, 0x20, + 0x38, 0x23, 0x01, 0x20, 0x64, 0x24, 0x10, 0x00, 0x1C, 0x24, 0x10, 0x00, + 0xF0, 0xB5, 0xFE, 0x4B, 0x40, 0xF6, 0xFF, 0x74, 0x1D, 0x78, 0x00, 0x23, + 0x13, 0x80, 0xFC, 0x4B, 0x1B, 0x78, 0x04, 0x2B, 0x5B, 0xD1, 0xFB, 0x4E, + 0x00, 0x23, 0xB6, 0xF9, 0x00, 0x70, 0x06, 0xE0, 0x31, 0xF9, 0x13, 0x60, + 0xA6, 0x42, 0x00, 0xDA, 0x34, 0x46, 0x5B, 0x1C, 0x1B, 0xB2, 0xBB, 0x42, + 0xF6, 0xDB, 0xF5, 0x4B, 0x1E, 0x68, 0xB6, 0xF8, 0x58, 0x31, 0xA3, 0x42, + 0x47, 0xDC, 0x00, 0x23, 0x43, 0xE0, 0x31, 0xF8, 0x13, 0x40, 0x30, 0xF8, + 0x13, 0xC0, 0xA4, 0xEB, 0x0C, 0x04, 0x96, 0xF8, 0x4B, 0xC1, 0x24, 0xB2, + 0xBC, 0xF1, 0x64, 0x0F, 0x0A, 0xD9, 0x93, 0xFB, 0xF5, 0xFE, 0x05, 0xFB, + 0x1E, 0x3E, 0xCC, 0xF1, 0x64, 0x0C, 0x0E, 0xFB, 0x0C, 0xFE, 0x9E, 0xFB, + 0xF5, 0xFC, 0x0B, 0xE0, 0x93, 0xFB, 0xF5, 0xFE, 0x05, 0xFB, 0x1E, 0x3E, + 0xAC, 0xF1, 0x64, 0x0C, 0x0E, 0xFB, 0x0C, 0xFE, 0x9E, 0xFB, 0xF5, 0xFE, + 0xAC, 0xEB, 0x0E, 0x0C, 0x0C, 0xF1, 0x64, 0x0C, 0x00, 0x2C, 0x0B, 0xDD, + 0x04, 0xFB, 0x0C, 0xF4, 0x4F, 0xF0, 0x64, 0x0C, 0x94, 0xFB, 0xFC, 0xF4, + 0xB6, 0xF9, 0x5A, 0xC1, 0x24, 0xB2, 0xA4, 0x45, 0x0C, 0xDB, 0x0E, 0xE0, + 0x01, 0xDB, 0xA4, 0x46, 0x01, 0xE0, 0xC4, 0xF1, 0x00, 0x0C, 0xB6, 0xF8, + 0x5C, 0xE1, 0xF4, 0x45, 0x05, 0xDD, 0x00, 0x2C, 0x00, 0xDA, 0x64, 0x42, + 0x14, 0x80, 0x00, 0x20, 0xF0, 0xBD, 0x5B, 0x1C, 0x1B, 0xB2, 0xBB, 0x42, + 0xB9, 0xDB, 0x01, 0x20, 0xF0, 0xBD, 0x2D, 0xE9, 0xF7, 0x4F, 0xDF, 0xF8, + 0x30, 0xB3, 0x81, 0x46, 0x00, 0x26, 0xDB, 0xF8, 0x00, 0x00, 0xDF, 0xF8, + 0x20, 0xA3, 0xC9, 0x4F, 0x90, 0xF8, 0x31, 0x01, 0x82, 0xB0, 0x35, 0x46, + 0xB0, 0x46, 0x00, 0x07, 0x17, 0xD5, 0x00, 0x24, 0x11, 0xE0, 0xBA, 0xF9, + 0x00, 0x00, 0xDD, 0xE9, 0x03, 0x12, 0x60, 0x43, 0x09, 0xEB, 0x40, 0x00, + 0xFF, 0xF7, 0x7A, 0xFF, 0x01, 0x28, 0x04, 0xD1, 0xA0, 0x40, 0x30, 0x43, + 0x6D, 0x1C, 0xC6, 0xB2, 0xED, 0xB2, 0x64, 0x1C, 0x24, 0xB2, 0x38, 0x78, + 0x84, 0x42, 0xEA, 0xDB, 0x01, 0xE0, 0x3D, 0x78, 0xFF, 0x26, 0xB9, 0x4A, + 0x00, 0x23, 0x55, 0xB1, 0x53, 0x70, 0x00, 0x95, 0xBA, 0xF8, 0x00, 0x00, + 0x33, 0x46, 0x82, 0xB2, 0x39, 0x78, 0x48, 0x46, 0x01, 0xF0, 0xDB, 0xFF, + 0x30, 0xE0, 0xDB, 0xF8, 0x00, 0x00, 0x4F, 0xF0, 0x01, 0x08, 0x5C, 0x46, + 0x90, 0xF8, 0x31, 0x11, 0xC9, 0x06, 0x21, 0xD5, 0x51, 0x78, 0x49, 0x1C, + 0xC9, 0xB2, 0x51, 0x70, 0x90, 0xF8, 0x60, 0x51, 0x8D, 0x42, 0x19, 0xD2, + 0x53, 0x70, 0xAA, 0x4A, 0x11, 0x68, 0x41, 0xF0, 0x02, 0x01, 0x11, 0x60, + 0x90, 0xF8, 0xB0, 0x30, 0xDB, 0x07, 0x03, 0xD1, 0x90, 0xF8, 0xD4, 0x00, + 0xC0, 0x07, 0x02, 0xD0, 0x41, 0xF0, 0x20, 0x00, 0x10, 0x60, 0x10, 0x21, + 0x10, 0x68, 0x01, 0xF0, 0x1F, 0xFD, 0x4F, 0xF4, 0x00, 0x71, 0x00, 0x20, + 0x03, 0xF0, 0x32, 0xFD, 0x20, 0x68, 0x90, 0xF8, 0xA8, 0x13, 0x07, 0x20, + 0x00, 0xF0, 0x6F, 0xFC, 0x40, 0x46, 0x05, 0xB0, 0xBD, 0xE8, 0xF0, 0x8F, + 0x99, 0x48, 0x10, 0xB5, 0x01, 0x21, 0x01, 0x80, 0x41, 0x88, 0x95, 0x4A, + 0x49, 0x1C, 0x41, 0x80, 0x96, 0x49, 0x09, 0x78, 0x41, 0x71, 0x11, 0x89, + 0xC1, 0x80, 0x95, 0x49, 0x0B, 0x78, 0x01, 0x79, 0x63, 0xF3, 0x04, 0x11, + 0x93, 0x4B, 0x1B, 0x78, 0x63, 0xF3, 0xC7, 0x11, 0x92, 0x4B, 0x1B, 0x78, + 0x63, 0xF3, 0x86, 0x11, 0x91, 0x4B, 0x1B, 0x78, 0x63, 0xF3, 0x45, 0x11, + 0x01, 0x71, 0x11, 0x79, 0xC2, 0x7B, 0x61, 0xF3, 0x03, 0x02, 0x8E, 0x49, + 0xC2, 0x73, 0x0A, 0x78, 0x81, 0x7C, 0x62, 0xF3, 0x03, 0x01, 0x8C, 0x4A, + 0x12, 0x78, 0x62, 0xF3, 0x04, 0x11, 0x8B, 0x4A, 0x12, 0x78, 0x62, 0xF3, + 0x45, 0x11, 0x8A, 0x4A, 0x12, 0x78, 0x62, 0xF3, 0x86, 0x11, 0x81, 0x74, + 0xFA, 0xF7, 0x60, 0xFF, 0x87, 0x48, 0x04, 0x21, 0x78, 0x4C, 0x01, 0x80, + 0x41, 0x88, 0x86, 0x4A, 0x49, 0x1C, 0x41, 0x80, 0x20, 0x68, 0x51, 0x7E, + 0x90, 0xF8, 0x10, 0x31, 0x90, 0xF8, 0x25, 0x00, 0x63, 0xF3, 0x00, 0x01, + 0x80, 0x08, 0x60, 0xF3, 0x41, 0x01, 0x51, 0x76, 0xFD, 0xF7, 0xA1, 0xFF, + 0x20, 0x68, 0x90, 0xF8, 0xE8, 0x17, 0xC9, 0x07, 0x14, 0xD0, 0x90, 0xF8, + 0xE9, 0x07, 0x7B, 0x4B, 0x01, 0x28, 0x10, 0xD0, 0x02, 0x28, 0x11, 0xD0, + 0x03, 0x28, 0x12, 0xD0, 0x04, 0x28, 0x13, 0xD0, 0x05, 0x28, 0x14, 0xD0, + 0x07, 0x28, 0x05, 0xD1, 0x75, 0x49, 0x18, 0x68, 0x0A, 0x68, 0x02, 0x60, + 0x49, 0x68, 0x41, 0x60, 0x10, 0xBD, 0x14, 0x22, 0x64, 0x49, 0x0A, 0xE0, + 0x1E, 0x22, 0x6E, 0x49, 0x07, 0xE0, 0x1E, 0x22, 0x6F, 0x49, 0x04, 0xE0, + 0x14, 0x22, 0x6A, 0x49, 0x01, 0xE0, 0x6E, 0x49, 0x14, 0x22, 0x18, 0x68, + 0xBD, 0xE8, 0x10, 0x40, 0x04, 0xF0, 0xBC, 0xBE, 0x10, 0xB5, 0xFA, 0xF7, + 0xAB, 0xF8, 0xFA, 0xF7, 0xAC, 0xFD, 0xBD, 0xE8, 0x10, 0x40, 0xF9, 0xF7, + 0x5F, 0xBA, 0x10, 0xB5, 0xFB, 0xF7, 0x1F, 0xFD, 0xFD, 0xF7, 0xE4, 0xFF, + 0xFC, 0xF7, 0xAE, 0xFD, 0xFF, 0xF7, 0xEE, 0xFF, 0x14, 0x21, 0x52, 0x48, + 0x04, 0xF0, 0x25, 0xFF, 0x1E, 0x21, 0x5B, 0x48, 0x04, 0xF0, 0x21, 0xFF, + 0x1E, 0x21, 0x5C, 0x48, 0x04, 0xF0, 0x1D, 0xFF, 0x14, 0x21, 0x56, 0x48, + 0x04, 0xF0, 0x19, 0xFF, 0x14, 0x21, 0x59, 0x48, 0x04, 0xF0, 0x37, 0xFF, + 0x55, 0x49, 0x00, 0x20, 0x08, 0x60, 0x48, 0x60, 0x44, 0x49, 0x48, 0x70, + 0x88, 0x70, 0x10, 0xBD, 0x10, 0xB5, 0x80, 0xEA, 0x01, 0x04, 0xE0, 0x06, + 0x01, 0xD5, 0xFA, 0xF7, 0x7C, 0xFD, 0xA0, 0x06, 0x03, 0xD5, 0xBD, 0xE8, + 0x10, 0x40, 0xF9, 0xF7, 0x2D, 0xBA, 0x10, 0xBD, 0x2D, 0xE9, 0xFF, 0x4F, + 0x81, 0xB0, 0x00, 0x25, 0x9A, 0x46, 0x91, 0x46, 0x83, 0x46, 0x2C, 0x46, + 0xAD, 0xF8, 0x00, 0x50, 0x00, 0xF0, 0xC7, 0xF8, 0x33, 0x4F, 0xDF, 0xF8, + 0x1C, 0x81, 0x34, 0x4E, 0x38, 0x68, 0x90, 0xF8, 0x31, 0x01, 0x80, 0x06, + 0x1C, 0xD5, 0x02, 0x20, 0x03, 0xF0, 0x09, 0xFD, 0x42, 0x48, 0x6A, 0x46, + 0x01, 0x68, 0x58, 0x46, 0xFF, 0xF7, 0xBB, 0xFE, 0x05, 0x46, 0x02, 0x20, + 0x03, 0xF0, 0x1A, 0xFD, 0x75, 0xB1, 0xBD, 0xF8, 0x00, 0x00, 0x00, 0x21, + 0xC3, 0xB2, 0xC0, 0xF3, 0x07, 0x22, 0x09, 0x20, 0x01, 0xF0, 0x13, 0xFC, + 0x2F, 0x49, 0x30, 0x78, 0x09, 0x78, 0x08, 0x43, 0x7B, 0xD0, 0x9A, 0xE0, + 0xB4, 0x70, 0x38, 0x68, 0x90, 0xF8, 0x10, 0x01, 0xC0, 0x07, 0x09, 0xD0, + 0x33, 0x48, 0x34, 0x49, 0x00, 0x78, 0x09, 0x78, 0x08, 0x43, 0x40, 0x07, + 0x02, 0xD5, 0x02, 0x98, 0x00, 0xF0, 0x17, 0xFA, 0x30, 0x4C, 0x20, 0x78, + 0x10, 0xF0, 0x30, 0x0F, 0x11, 0xD0, 0x38, 0x68, 0x90, 0xF8, 0x78, 0x00, + 0xC0, 0x07, 0x0C, 0xD0, 0x2C, 0x48, 0x01, 0x78, 0x0E, 0x98, 0xFA, 0xF7, + 0x27, 0xF8, 0x98, 0xF8, 0x00, 0x00, 0x01, 0x28, 0x03, 0xD9, 0x20, 0x68, + 0x20, 0xF0, 0x30, 0x00, 0x20, 0x60, 0x38, 0x68, 0x90, 0xF8, 0x31, 0x01, + 0x40, 0x07, 0x05, 0xD5, 0x24, 0x48, 0x25, 0x49, 0x80, 0x78, 0x09, 0x78, + 0x88, 0x42, 0x69, 0xD1, 0x58, 0x46, 0x49, 0x46, 0x52, 0x46, 0xFB, 0xF7, + 0x97, 0xFC, 0x04, 0x46, 0x01, 0x28, 0x44, 0xD0, 0xF4, 0xB3, 0x3F, 0xE0, + 0x01, 0x24, 0x10, 0x00, 0x04, 0x24, 0x10, 0x00, 0x0C, 0x24, 0x10, 0x00, + 0x50, 0x24, 0x10, 0x00, 0x03, 0x24, 0x10, 0x00, 0xB8, 0x23, 0x10, 0x00, + 0x64, 0x24, 0x10, 0x00, 0x58, 0x25, 0x10, 0x00, 0x08, 0x24, 0x10, 0x00, + 0x29, 0x24, 0x10, 0x00, 0x06, 0x24, 0x10, 0x00, 0x05, 0x24, 0x10, 0x00, + 0x07, 0x24, 0x10, 0x00, 0x55, 0x23, 0x10, 0x00, 0x57, 0x23, 0x10, 0x00, + 0x6D, 0x23, 0x10, 0x00, 0x38, 0x23, 0x10, 0x00, 0xA8, 0x25, 0x10, 0x00, + 0x6C, 0x25, 0x10, 0x00, 0x74, 0x24, 0x10, 0x00, 0x00, 0x22, 0x10, 0x00, + 0x8A, 0x25, 0x10, 0x00, 0xBC, 0x25, 0x10, 0x00, 0x4C, 0x23, 0x10, 0x00, + 0x18, 0x24, 0x10, 0x00, 0x24, 0x24, 0x10, 0x00, 0x20, 0x24, 0x10, 0x00, + 0x1C, 0x24, 0x10, 0x00, 0x61, 0x24, 0x10, 0x00, 0x6C, 0x24, 0x10, 0x00, + 0x02, 0x24, 0x10, 0x00, 0x06, 0xE0, 0x14, 0xE0, 0x02, 0x2C, 0x08, 0xD0, + 0x0B, 0xE0, 0xFD, 0xF7, 0x25, 0xFF, 0x06, 0xE0, 0xFE, 0xF7, 0xAC, 0xF9, + 0xFC, 0xF7, 0xDF, 0xFC, 0x03, 0xE0, 0xF9, 0xF7, 0xBB, 0xFA, 0xFC, 0xF7, + 0xEA, 0xFC, 0x20, 0x48, 0x01, 0x79, 0x64, 0xF3, 0x03, 0x01, 0x01, 0x71, + 0x0A, 0xE0, 0xB0, 0x78, 0x40, 0x1C, 0xC0, 0xB2, 0xB0, 0x70, 0x02, 0x28, + 0x04, 0xD9, 0x01, 0x20, 0x30, 0x70, 0x88, 0xF8, 0x00, 0x00, 0xB4, 0x70, + 0xFF, 0xF7, 0x78, 0xFE, 0x28, 0x46, 0x72, 0xE6, 0x70, 0x47, 0x70, 0xB5, + 0x14, 0x4D, 0x14, 0x21, 0x28, 0x46, 0x6C, 0x88, 0x04, 0xF0, 0x25, 0xFE, + 0x6C, 0x80, 0x12, 0x4D, 0x1E, 0x21, 0x28, 0x46, 0x6C, 0x88, 0x04, 0xF0, + 0x1E, 0xFE, 0x6C, 0x80, 0x0F, 0x4D, 0x1E, 0x21, 0x28, 0x46, 0x6C, 0x88, + 0x04, 0xF0, 0x17, 0xFE, 0x6C, 0x80, 0x0D, 0x4D, 0x14, 0x21, 0x28, 0x46, + 0x6C, 0x88, 0x04, 0xF0, 0x10, 0xFE, 0x6C, 0x80, 0x0A, 0x4D, 0x14, 0x21, + 0x28, 0x46, 0x6C, 0x88, 0x04, 0xF0, 0x2B, 0xFE, 0x08, 0x48, 0x6C, 0x80, + 0x00, 0x21, 0x42, 0x88, 0x01, 0x60, 0x41, 0x60, 0x42, 0x80, 0x70, 0xBD, + 0x58, 0x25, 0x10, 0x00, 0x6C, 0x25, 0x10, 0x00, 0x8A, 0x25, 0x10, 0x00, + 0xA8, 0x25, 0x10, 0x00, 0xBC, 0x25, 0x10, 0x00, 0x00, 0x22, 0x10, 0x00, + 0xF4, 0x48, 0x00, 0x21, 0xF4, 0x4A, 0x01, 0x70, 0xF4, 0x48, 0x51, 0x60, + 0x91, 0x60, 0x11, 0x70, 0x00, 0x68, 0x90, 0xF8, 0x11, 0x31, 0x03, 0xF0, + 0x03, 0x03, 0x53, 0x70, 0x91, 0x70, 0xD1, 0x60, 0x11, 0x61, 0x51, 0x61, + 0x91, 0x61, 0x90, 0xF8, 0x3B, 0x11, 0xED, 0x4A, 0x09, 0x09, 0x11, 0x60, + 0x90, 0xF8, 0x10, 0x11, 0xCA, 0x07, 0xEB, 0x49, 0x02, 0xD0, 0x90, 0xF8, + 0x12, 0x01, 0x01, 0xE0, 0x90, 0xF8, 0x81, 0x07, 0x88, 0x70, 0x70, 0x47, + 0xF0, 0xB5, 0xE4, 0x49, 0xE4, 0x4E, 0x09, 0x68, 0x91, 0xF8, 0x30, 0x21, + 0xD2, 0x07, 0x4F, 0xD0, 0xDE, 0x4A, 0x17, 0x78, 0xE2, 0x4A, 0x12, 0x78, + 0xAF, 0xB1, 0x01, 0x2A, 0x09, 0xD0, 0x91, 0xF8, 0x3B, 0x31, 0xB1, 0xF8, + 0x38, 0x41, 0x03, 0xF0, 0x0F, 0x02, 0x1D, 0x09, 0xB1, 0xF8, 0x36, 0x31, + 0x14, 0xE0, 0x91, 0xF8, 0xF5, 0x31, 0xB1, 0xF8, 0xF2, 0x41, 0x03, 0xF0, + 0x0F, 0x02, 0x1D, 0x09, 0xB1, 0xF8, 0xF0, 0x31, 0x0A, 0xE0, 0x01, 0x2A, + 0x10, 0xD0, 0x91, 0xF8, 0x3A, 0x31, 0xB1, 0xF8, 0x34, 0x41, 0x03, 0xF0, + 0x0F, 0x02, 0x1D, 0x09, 0xB1, 0xF8, 0x32, 0x31, 0xDF, 0xF8, 0x44, 0xC3, + 0x9C, 0xF8, 0x00, 0xC0, 0xBC, 0xF1, 0x03, 0x0F, 0x0A, 0xD0, 0x10, 0xE0, + 0x91, 0xF8, 0xF4, 0x31, 0xB1, 0xF8, 0xEE, 0x41, 0x03, 0xF0, 0x0F, 0x02, + 0x1D, 0x09, 0xB1, 0xF8, 0xEC, 0x31, 0xED, 0xE7, 0x91, 0xF8, 0x3C, 0x11, + 0x0F, 0xB1, 0x0A, 0x09, 0x01, 0xE0, 0x01, 0xF0, 0x0F, 0x02, 0x98, 0x42, + 0x01, 0xDC, 0x32, 0x60, 0xF0, 0xBD, 0xA0, 0x42, 0x01, 0xDB, 0x35, 0x60, + 0xF0, 0xBD, 0xC0, 0x1A, 0xA9, 0x1A, 0x48, 0x43, 0xE1, 0x1A, 0x90, 0xFB, + 0xF1, 0xF0, 0x10, 0x44, 0x30, 0x60, 0xF0, 0xBD, 0x00, 0x20, 0xFB, 0xE7, + 0x70, 0xB5, 0xBC, 0x49, 0x00, 0x22, 0x0B, 0x78, 0xB5, 0x49, 0x01, 0x2B, + 0x09, 0x68, 0x02, 0xD1, 0xB9, 0x4B, 0x1B, 0x78, 0x4B, 0xB1, 0xB1, 0xF8, + 0x20, 0x31, 0x83, 0x42, 0x18, 0xD2, 0x91, 0xF8, 0x10, 0x31, 0x1B, 0x07, + 0x14, 0xD5, 0x03, 0x22, 0x25, 0xE0, 0xB1, 0xF8, 0x2D, 0x31, 0x83, 0x42, + 0x03, 0xD2, 0x91, 0xF8, 0x10, 0x31, 0x1B, 0x07, 0xF5, 0xD4, 0xB1, 0xF8, + 0x2B, 0x31, 0x83, 0x42, 0x03, 0xD2, 0x91, 0xF8, 0x10, 0x31, 0x5B, 0x07, + 0x0A, 0xD4, 0xB1, 0xF8, 0x29, 0x31, 0x0B, 0xE0, 0xB1, 0xF8, 0x1E, 0x31, + 0x83, 0x42, 0x05, 0xD2, 0x91, 0xF8, 0x10, 0x31, 0x5B, 0x07, 0x01, 0xD5, + 0x02, 0x22, 0x08, 0xE0, 0xB1, 0xF8, 0x1C, 0x31, 0x83, 0x42, 0x04, 0xD2, + 0x91, 0xF8, 0x10, 0x01, 0x80, 0x07, 0x00, 0xD5, 0x01, 0x22, 0x99, 0x4B, + 0x97, 0x4C, 0x18, 0x78, 0x82, 0x42, 0x11, 0xD1, 0x25, 0x78, 0x85, 0x42, + 0x1A, 0xD0, 0x9D, 0x4E, 0x36, 0x78, 0x30, 0x43, 0x07, 0xD0, 0x98, 0x68, + 0x40, 0x1E, 0x98, 0x60, 0x00, 0x28, 0x11, 0xDC, 0x18, 0x78, 0x20, 0x70, + 0x0E, 0xE0, 0x1D, 0x70, 0x98, 0x68, 0xF7, 0xE7, 0x0A, 0xB3, 0x02, 0x2A, + 0x01, 0xD1, 0x01, 0x28, 0x1D, 0xD0, 0x91, 0xF8, 0x1A, 0x01, 0x98, 0x60, + 0x1A, 0x70, 0x00, 0x28, 0x00, 0xDC, 0x22, 0x70, 0x20, 0x78, 0x02, 0x43, + 0x04, 0xD0, 0x91, 0xF8, 0xA7, 0x13, 0x06, 0x20, 0x00, 0xF0, 0xC5, 0xF9, + 0x8C, 0x49, 0x20, 0x78, 0x0A, 0x7C, 0x60, 0xF3, 0x03, 0x02, 0x0A, 0x74, + 0x8A, 0x4A, 0xD3, 0x7C, 0x60, 0xF3, 0x03, 0x03, 0x89, 0x48, 0xD3, 0x74, + 0x00, 0x78, 0x08, 0x76, 0x70, 0xBD, 0x91, 0xF8, 0x1B, 0x01, 0xE0, 0xE7, + 0xF0, 0xB5, 0xDF, 0xF8, 0xE8, 0xE1, 0x00, 0x24, 0x0E, 0xF1, 0x14, 0x0C, + 0x9E, 0xF8, 0x02, 0x00, 0x40, 0xF6, 0xFF, 0x71, 0x3C, 0xF8, 0x10, 0x30, + 0x75, 0x48, 0x06, 0x68, 0x96, 0xF8, 0x27, 0x21, 0x96, 0xF8, 0x28, 0x01, + 0x17, 0x09, 0x15, 0x07, 0x11, 0xD0, 0x02, 0xF0, 0x0F, 0x02, 0x70, 0x4D, + 0x83, 0x42, 0x2D, 0x68, 0x95, 0xF8, 0x26, 0x51, 0x04, 0xDB, 0x18, 0x1A, + 0x78, 0x43, 0x90, 0xFB, 0xF2, 0xF0, 0x05, 0x44, 0x9E, 0xF8, 0x01, 0x70, + 0x00, 0x20, 0x7F, 0x1C, 0x08, 0xE0, 0x01, 0x22, 0xED, 0xE7, 0x3C, 0xF8, + 0x10, 0x20, 0x91, 0x42, 0x01, 0xDD, 0x11, 0x46, 0x04, 0x46, 0x40, 0x1C, + 0xB8, 0x42, 0xF6, 0xDB, 0x5A, 0x1A, 0x64, 0x48, 0xAA, 0x42, 0x06, 0xDD, + 0x06, 0xF5, 0x89, 0x76, 0x32, 0x5D, 0x82, 0x70, 0x01, 0x80, 0x8E, 0xF8, + 0x02, 0x40, 0x81, 0x78, 0x65, 0x48, 0x02, 0x22, 0x01, 0x73, 0x43, 0x73, + 0x9E, 0xF8, 0x02, 0x10, 0x81, 0x73, 0x61, 0x48, 0x02, 0x80, 0x42, 0x88, + 0x52, 0x1C, 0x42, 0x80, 0xBC, 0xF8, 0x00, 0x20, 0x82, 0x80, 0xBC, 0xF8, + 0x02, 0x20, 0xC2, 0x80, 0xBC, 0xF8, 0x04, 0x20, 0x02, 0x81, 0xBC, 0xF8, + 0x06, 0x20, 0x42, 0x81, 0x85, 0x81, 0xC1, 0x81, 0xF0, 0xBD, 0x2D, 0xE9, + 0xFC, 0x5F, 0x83, 0x46, 0x58, 0x48, 0x4C, 0x49, 0x10, 0x26, 0x05, 0x78, + 0x48, 0x68, 0x00, 0x24, 0x90, 0xFB, 0xF6, 0xF2, 0x06, 0xFB, 0x12, 0x07, + 0x88, 0x46, 0x28, 0xE0, 0x04, 0xFB, 0x05, 0xF0, 0x0B, 0xEB, 0x40, 0x09, + 0x04, 0xFB, 0x06, 0x70, 0x50, 0x4A, 0x68, 0x43, 0x02, 0xEB, 0x40, 0x0A, + 0x42, 0x48, 0x00, 0x68, 0x90, 0xF8, 0x10, 0x31, 0x9B, 0x06, 0x12, 0xD5, + 0xD8, 0xF8, 0x04, 0x10, 0x00, 0x29, 0x0E, 0xDD, 0x04, 0xFB, 0x06, 0xF1, + 0x69, 0x43, 0x02, 0xEB, 0x41, 0x02, 0xB0, 0xF9, 0x24, 0x11, 0xCD, 0xE9, + 0x00, 0x15, 0xB0, 0xF9, 0x22, 0x31, 0x49, 0x46, 0x08, 0x46, 0x01, 0xF0, + 0x8B, 0xFC, 0x6A, 0x00, 0x49, 0x46, 0x50, 0x46, 0x04, 0xF0, 0xF0, 0xFB, + 0x64, 0x1C, 0x98, 0xF8, 0x01, 0x00, 0x41, 0x46, 0x40, 0x1C, 0x84, 0x42, + 0xD0, 0xDB, 0x48, 0x68, 0x4F, 0xF0, 0xFF, 0x32, 0x40, 0x1C, 0x02, 0xEB, + 0x46, 0x02, 0x48, 0x60, 0x82, 0x42, 0x00, 0xDA, 0x4E, 0x60, 0xD8, 0xF8, + 0x04, 0x00, 0xB0, 0x42, 0x04, 0xDB, 0xBD, 0xE8, 0xFC, 0x5F, 0x34, 0x48, + 0x00, 0xF0, 0x02, 0xB8, 0xBD, 0xE8, 0xFC, 0x9F, 0x2D, 0xE9, 0xF0, 0x5F, + 0xDF, 0xF8, 0xBC, 0xA0, 0x00, 0x25, 0xDF, 0xF8, 0x88, 0x80, 0x83, 0x46, + 0x9A, 0xF8, 0x00, 0x70, 0x10, 0x26, 0x2C, 0x46, 0x08, 0xF1, 0x14, 0x08, + 0xDF, 0xF8, 0x74, 0x90, 0x23, 0xE0, 0x04, 0xFB, 0x06, 0xF0, 0x78, 0x43, + 0x0B, 0xEB, 0x40, 0x00, 0x9A, 0xF8, 0x00, 0x20, 0x31, 0x46, 0x01, 0xF0, + 0x09, 0xFD, 0x17, 0x49, 0x17, 0x4B, 0x0C, 0x31, 0x21, 0xF8, 0x14, 0x00, + 0x1B, 0x68, 0x38, 0xF8, 0x14, 0x10, 0x93, 0xF8, 0x10, 0x31, 0xDB, 0x06, + 0x07, 0xD5, 0x43, 0x1A, 0x00, 0x2B, 0x04, 0xDC, 0xC1, 0xEB, 0xC1, 0x11, + 0x08, 0x44, 0xC0, 0xF3, 0xCF, 0x10, 0x28, 0xF8, 0x14, 0x00, 0xA8, 0x42, + 0x00, 0xD9, 0x05, 0x46, 0x64, 0x1C, 0x99, 0xF8, 0x01, 0x00, 0x40, 0x1C, + 0x84, 0x42, 0xD6, 0xDB, 0xFF, 0xF7, 0x18, 0xFF, 0x99, 0xF8, 0x02, 0x10, + 0x38, 0xF8, 0x11, 0x40, 0x20, 0x46, 0xFF, 0xF7, 0x99, 0xFE, 0x20, 0x46, + 0xBD, 0xE8, 0xF0, 0x5F, 0x3A, 0xE6, 0x00, 0x00, 0xB8, 0x23, 0x10, 0x00, + 0xE4, 0x23, 0x10, 0x00, 0x50, 0x24, 0x10, 0x00, 0xBC, 0x23, 0x10, 0x00, + 0x6C, 0x24, 0x10, 0x00, 0x2A, 0x24, 0x10, 0x00, 0x04, 0x24, 0x10, 0x00, + 0x05, 0x24, 0x10, 0x00, 0x06, 0x24, 0x10, 0x00, 0x29, 0x24, 0x10, 0x00, + 0x6C, 0x25, 0x10, 0x00, 0x58, 0x25, 0x10, 0x00, 0x88, 0x23, 0x10, 0x00, + 0x01, 0x24, 0x10, 0x00, 0x7C, 0x0B, 0x01, 0x20, 0x70, 0xB5, 0xA8, 0x4E, + 0xA8, 0x4D, 0x74, 0x6A, 0x28, 0x6A, 0x44, 0x40, 0xE0, 0x07, 0x01, 0xD0, + 0xFF, 0xF7, 0xB1, 0xFC, 0xE0, 0x06, 0x01, 0xD5, 0xFF, 0xF7, 0xA4, 0xFC, + 0xE9, 0x69, 0xF0, 0x69, 0xFF, 0xF7, 0xCE, 0xFC, 0xE8, 0x69, 0xF0, 0x61, + 0x28, 0x6A, 0x70, 0x62, 0x68, 0x6A, 0x30, 0x62, 0xBD, 0xE8, 0x70, 0x40, + 0x00, 0xF0, 0xDA, 0xB8, 0xF8, 0xB5, 0x00, 0x24, 0x03, 0x20, 0x03, 0xF0, + 0xEE, 0xF9, 0xFF, 0xF7, 0xDD, 0xFF, 0x97, 0x4E, 0x97, 0x4D, 0x96, 0xF8, + 0x24, 0x00, 0x96, 0xF8, 0x20, 0x10, 0x08, 0x43, 0xC0, 0x06, 0x0C, 0xD5, + 0x30, 0x78, 0xA9, 0x68, 0x42, 0x00, 0x93, 0x48, 0x04, 0xF0, 0x3C, 0xFB, + 0x70, 0x78, 0xE9, 0x68, 0x42, 0x00, 0x90, 0x48, 0x3C, 0x30, 0x04, 0xF0, + 0x35, 0xFB, 0x96, 0xF8, 0x20, 0x10, 0x70, 0x6A, 0x01, 0x43, 0xC9, 0x07, + 0x0A, 0xD0, 0x28, 0x69, 0x00, 0x90, 0x8A, 0x4B, 0xD5, 0xE9, 0x00, 0x01, + 0x3C, 0x33, 0x88, 0x4A, 0xFF, 0xF7, 0xA6, 0xFC, 0x04, 0x46, 0x1D, 0xE0, + 0xC0, 0x06, 0x1B, 0xD5, 0x85, 0x48, 0x00, 0x68, 0x90, 0xF8, 0x11, 0x02, + 0x40, 0x06, 0x15, 0xD5, 0x83, 0x48, 0x81, 0x49, 0x02, 0x78, 0x3C, 0x31, + 0x7F, 0x48, 0xF9, 0xF7, 0x79, 0xFE, 0x01, 0x28, 0x0C, 0xD1, 0x80, 0x49, + 0x08, 0x68, 0x40, 0xF0, 0x22, 0x00, 0x08, 0x60, 0x23, 0x21, 0x01, 0xF0, + 0xE3, 0xF8, 0x4F, 0xF4, 0x00, 0x71, 0x00, 0x20, 0x03, 0xF0, 0xF6, 0xF8, + 0x30, 0x6A, 0x78, 0xB1, 0x74, 0xB9, 0x02, 0x20, 0x03, 0xF0, 0xA1, 0xF9, + 0x30, 0x6A, 0x00, 0x90, 0x72, 0x4A, 0x72, 0x49, 0x3C, 0x32, 0x6B, 0x69, + 0x28, 0x68, 0xFF, 0xF7, 0x89, 0xF9, 0x02, 0x20, 0x03, 0xF0, 0xB0, 0xF9, + 0xBD, 0xE8, 0xF8, 0x40, 0x03, 0x20, 0x03, 0xF0, 0xAB, 0xB9, 0x69, 0x48, + 0x41, 0x79, 0x01, 0x29, 0x0C, 0xD0, 0x81, 0x79, 0x01, 0x29, 0x09, 0xD0, + 0xC1, 0x79, 0x01, 0x29, 0x06, 0xD0, 0x6A, 0x49, 0x09, 0x78, 0x01, 0x29, + 0x02, 0xD0, 0x00, 0x7A, 0x00, 0x28, 0x00, 0xD0, 0x01, 0x20, 0x70, 0x47, + 0x5F, 0x48, 0x41, 0x79, 0x01, 0x29, 0x08, 0xD0, 0x81, 0x79, 0x01, 0x29, + 0x05, 0xD0, 0xC1, 0x79, 0x01, 0x29, 0x02, 0xD0, 0x00, 0x7A, 0x00, 0x28, + 0x00, 0xD0, 0x01, 0x20, 0x70, 0x47, 0x58, 0x4A, 0x93, 0x7A, 0x99, 0x42, + 0x01, 0xD9, 0x91, 0x72, 0xD0, 0x72, 0x70, 0x47, 0x54, 0x48, 0x08, 0xB5, + 0x00, 0x21, 0xC1, 0x61, 0x41, 0x62, 0x01, 0x62, 0x00, 0xF0, 0x20, 0xF8, + 0x6B, 0x46, 0x00, 0x22, 0x07, 0x21, 0x02, 0x20, 0x03, 0xF0, 0xF8, 0xF8, + 0x00, 0x98, 0xC1, 0x07, 0x06, 0xD0, 0x01, 0x21, 0x02, 0x20, 0x03, 0xF0, + 0xD0, 0xF8, 0xFF, 0xF7, 0x5D, 0xFF, 0xEF, 0xE7, 0x81, 0x07, 0x06, 0xD5, + 0x02, 0x21, 0x08, 0x46, 0x03, 0xF0, 0xC7, 0xF8, 0x00, 0xF0, 0x55, 0xF8, + 0xE6, 0xE7, 0x40, 0x07, 0xE4, 0xD5, 0x04, 0x21, 0x02, 0x20, 0x03, 0xF0, + 0xBE, 0xF8, 0xDF, 0xE7, 0x43, 0x48, 0x10, 0xB5, 0x01, 0x68, 0x3F, 0x48, + 0x4A, 0x7D, 0x02, 0x70, 0x09, 0x7D, 0x41, 0x70, 0x4A, 0x43, 0x82, 0x81, + 0x42, 0x4A, 0x92, 0x78, 0x82, 0x70, 0x01, 0x22, 0xC2, 0x70, 0x02, 0x71, + 0x00, 0x22, 0xC2, 0x81, 0x42, 0x72, 0x3F, 0x48, 0x02, 0x70, 0xC1, 0xF1, + 0x20, 0x00, 0x3E, 0x49, 0x01, 0xEB, 0x40, 0x00, 0x3D, 0x49, 0x08, 0x60, + 0x3D, 0x48, 0x02, 0x70, 0xFF, 0xF7, 0xCB, 0xFB, 0xFF, 0xF7, 0x06, 0xFD, + 0xBD, 0xE8, 0x10, 0x40, 0xFF, 0xF7, 0x6C, 0xB8, 0x2E, 0x49, 0x2D, 0x48, + 0x91, 0xF8, 0x2F, 0x20, 0x02, 0x70, 0x91, 0xF8, 0x30, 0x30, 0x43, 0x70, + 0x5A, 0x43, 0x82, 0x81, 0x91, 0xF8, 0x33, 0x20, 0x82, 0x70, 0x11, 0xF8, + 0x2C, 0x2F, 0x02, 0x71, 0x8A, 0x78, 0xC2, 0x70, 0x49, 0x78, 0x49, 0xB1, + 0x26, 0x49, 0x09, 0x68, 0x91, 0xF8, 0x80, 0x21, 0x12, 0x07, 0x03, 0xD5, + 0x2B, 0x4A, 0x91, 0xF8, 0xAC, 0x11, 0x11, 0x70, 0x27, 0x49, 0x40, 0x31, + 0x01, 0x61, 0xA1, 0xF5, 0xF8, 0x61, 0x41, 0x61, 0x27, 0x49, 0x81, 0x61, + 0x70, 0x47, 0x38, 0xB5, 0x03, 0x20, 0x03, 0xF0, 0xEE, 0xF8, 0xFF, 0xF7, + 0xDD, 0xFE, 0x17, 0x4C, 0x17, 0x4D, 0x94, 0xF8, 0x24, 0x00, 0x94, 0xF8, + 0x20, 0x10, 0x08, 0x43, 0xC0, 0x06, 0x0C, 0xD5, 0x20, 0x78, 0xA9, 0x68, + 0x42, 0x00, 0x13, 0x48, 0x04, 0xF0, 0x3C, 0xFA, 0x60, 0x78, 0xE9, 0x68, + 0x42, 0x00, 0x10, 0x48, 0x3C, 0x30, 0x04, 0xF0, 0x35, 0xFA, 0x94, 0xF8, + 0x20, 0x00, 0x61, 0x6A, 0x08, 0x43, 0xC0, 0x07, 0x02, 0xD0, 0x28, 0x68, + 0xFF, 0xF7, 0x7E, 0xFC, 0x20, 0x6A, 0x38, 0xB1, 0x00, 0x90, 0x08, 0x4A, + 0x07, 0x49, 0x3C, 0x32, 0x6B, 0x69, 0x28, 0x68, 0xFF, 0xF7, 0xB4, 0xF8, + 0xBD, 0xE8, 0x38, 0x40, 0x03, 0x20, 0x03, 0xF0, 0xD9, 0xB8, 0x00, 0x00, + 0x00, 0x24, 0x10, 0x00, 0xE4, 0x52, 0x10, 0x00, 0xFC, 0x93, 0x01, 0x20, + 0x50, 0x24, 0x10, 0x00, 0x56, 0x23, 0x10, 0x00, 0x64, 0x24, 0x10, 0x00, + 0x57, 0x23, 0x10, 0x00, 0x6C, 0x24, 0x10, 0x00, 0xC5, 0x23, 0x10, 0x00, + 0xF8, 0x9B, 0x01, 0x20, 0x74, 0x24, 0x10, 0x00, 0x88, 0x23, 0x10, 0x00, + 0x7C, 0x1B, 0x01, 0x20, 0x0E, 0x4C, 0x08, 0xB5, 0x00, 0x25, 0x25, 0x60, + 0x20, 0x68, 0x40, 0x1C, 0x20, 0x60, 0x05, 0xF0, 0xF9, 0xFE, 0x01, 0xF0, + 0xB8, 0xF8, 0x05, 0xF0, 0x43, 0xFA, 0x10, 0xB9, 0x06, 0xF0, 0x1C, 0xFB, + 0x20, 0xB1, 0x05, 0xF0, 0xAF, 0xFE, 0xF4, 0xF7, 0xF7, 0xFE, 0xED, 0xE7, + 0x00, 0x95, 0x00, 0xBF, 0x00, 0x98, 0x40, 0x1C, 0x00, 0x90, 0x14, 0x28, + 0xF9, 0xDB, 0xF4, 0xE7, 0x2C, 0x24, 0x10, 0x00, 0x85, 0x49, 0x00, 0x20, + 0x08, 0x60, 0x85, 0x49, 0x08, 0x60, 0x01, 0xF0, 0xF3, 0xBC, 0xD0, 0x21, + 0x4D, 0xF6, 0xC0, 0x62, 0xBA, 0x20, 0x00, 0xF0, 0x70, 0xBC, 0x70, 0xB5, + 0x4F, 0xF4, 0x00, 0x63, 0x98, 0x42, 0x02, 0xD2, 0x7E, 0x4C, 0x24, 0x68, + 0x07, 0xE0, 0xA0, 0xF5, 0x80, 0x50, 0x80, 0xB2, 0x4F, 0xF4, 0x80, 0x53, + 0x98, 0x42, 0x0C, 0xD2, 0x7A, 0x4C, 0x85, 0x18, 0x9D, 0x42, 0x00, 0xDD, + 0x1A, 0x1A, 0x00, 0x23, 0x03, 0xE0, 0xCD, 0x5C, 0x1E, 0x18, 0x5B, 0x1C, + 0xA5, 0x55, 0x93, 0x42, 0xF9, 0xDB, 0x70, 0xBD, 0xB0, 0xF5, 0x80, 0x5F, + 0x04, 0xD2, 0x0A, 0x46, 0x01, 0x46, 0x70, 0x48, 0x00, 0x68, 0x0E, 0xE0, + 0xB0, 0xF5, 0xFE, 0x5F, 0x05, 0xD2, 0x0A, 0x46, 0x01, 0x46, 0x6D, 0x48, + 0x40, 0x30, 0x00, 0xF0, 0xA0, 0xBC, 0xA0, 0xF5, 0xFE, 0x50, 0x80, 0xB2, + 0x0A, 0x46, 0x01, 0x46, 0x68, 0x48, 0x00, 0xF0, 0x6D, 0xBC, 0x01, 0xF0, + 0x9E, 0xBD, 0x10, 0xB5, 0x66, 0x4C, 0x4F, 0xF4, 0x00, 0x21, 0x20, 0x60, + 0x00, 0x20, 0x00, 0xF0, 0xB2, 0xF8, 0x00, 0x20, 0x20, 0x60, 0x10, 0xBD, + 0x10, 0xB5, 0x4F, 0xF4, 0x00, 0x61, 0x00, 0x20, 0x00, 0xF0, 0xA9, 0xF8, + 0x00, 0x23, 0xBD, 0xE8, 0x10, 0x40, 0x1A, 0x46, 0x19, 0x46, 0x03, 0x20, + 0x00, 0xF0, 0x43, 0xBF, 0x10, 0xB5, 0x4F, 0xF4, 0x80, 0x51, 0x00, 0x20, + 0x00, 0xF0, 0x9B, 0xF8, 0x00, 0x23, 0xBD, 0xE8, 0x10, 0x40, 0x1A, 0x46, + 0x19, 0x46, 0x04, 0x20, 0x00, 0xF0, 0x35, 0xBF, 0x4F, 0x49, 0x0A, 0x68, + 0x82, 0x43, 0x0A, 0x60, 0x02, 0x21, 0x01, 0x20, 0x00, 0xF0, 0x8B, 0xB8, + 0x4B, 0x49, 0x0A, 0x68, 0x02, 0x43, 0x0A, 0x60, 0x02, 0x21, 0x01, 0x20, + 0x00, 0xF0, 0x83, 0xB8, 0x48, 0x49, 0x0A, 0x68, 0x82, 0x43, 0x0A, 0x60, + 0x04, 0x21, 0x01, 0x20, 0x00, 0xF0, 0x7B, 0xB8, 0x44, 0x49, 0x0A, 0x68, + 0x02, 0x43, 0x0A, 0x60, 0x04, 0x21, 0x01, 0x20, 0x00, 0xF0, 0x73, 0xB8, + 0x05, 0xF0, 0x86, 0xBF, 0x05, 0xF0, 0x72, 0xBF, 0x10, 0xB5, 0xC0, 0x07, + 0x1B, 0xD0, 0x3E, 0x49, 0x02, 0x20, 0x09, 0x68, 0x91, 0xF8, 0xB0, 0x20, + 0xD2, 0x07, 0x03, 0xD1, 0x91, 0xF8, 0xD4, 0x10, 0xC9, 0x07, 0x00, 0xD0, + 0x22, 0x20, 0x3B, 0x49, 0x0A, 0x68, 0x02, 0x43, 0x42, 0xF0, 0x01, 0x00, + 0x08, 0x60, 0x00, 0x21, 0x00, 0xF0, 0x12, 0xFF, 0xBD, 0xE8, 0x10, 0x40, + 0x4F, 0xF4, 0x00, 0x71, 0x00, 0x20, 0x00, 0xF0, 0x50, 0xB8, 0x10, 0xBD, + 0x10, 0xB5, 0x04, 0x46, 0xC0, 0x07, 0x09, 0xD0, 0x00, 0x23, 0x1A, 0x46, + 0x01, 0x21, 0x10, 0x20, 0x00, 0xF0, 0xE7, 0xFE, 0x04, 0x21, 0x00, 0x20, + 0x00, 0xF0, 0x41, 0xF8, 0xE0, 0x06, 0x0B, 0xD5, 0x00, 0x23, 0x10, 0x21, + 0x1A, 0x46, 0x08, 0x46, 0x00, 0xF0, 0xDB, 0xFE, 0x10, 0x21, 0xBD, 0xE8, + 0x10, 0x40, 0x00, 0x20, 0x00, 0xF0, 0x33, 0xB8, 0x10, 0xBD, 0x25, 0x49, + 0x08, 0x80, 0x4F, 0xF4, 0x80, 0x71, 0x00, 0x20, 0x00, 0xF0, 0x2B, 0xB8, + 0xC0, 0x07, 0x03, 0xD0, 0x80, 0x21, 0x00, 0x20, 0x00, 0xF0, 0x25, 0xB8, + 0x70, 0x47, 0x10, 0xB5, 0x00, 0x22, 0x11, 0x46, 0x97, 0x20, 0x00, 0xF0, + 0x03, 0xFF, 0x00, 0x23, 0x01, 0x22, 0x19, 0x46, 0x10, 0x20, 0x00, 0xF0, + 0xBA, 0xFE, 0xBD, 0xE8, 0x10, 0x40, 0x4F, 0xF4, 0x80, 0x61, 0x00, 0x20, + 0x00, 0xF0, 0x11, 0xB8, 0x10, 0xB5, 0x00, 0x22, 0x11, 0x46, 0xAD, 0x20, + 0x00, 0xF0, 0xF0, 0xFE, 0x10, 0x21, 0xBD, 0xE8, 0x10, 0x40, 0x01, 0x20, + 0x00, 0xF0, 0x05, 0xB8, 0x4F, 0xF4, 0x00, 0x31, 0x00, 0x20, 0xAF, 0xF3, + 0x00, 0x80, 0x38, 0xB5, 0x0C, 0x46, 0x05, 0x46, 0x02, 0xF0, 0xCE, 0xFE, + 0x69, 0x46, 0x28, 0x46, 0x02, 0xF0, 0x09, 0xFF, 0x00, 0x9A, 0x22, 0x42, + 0xF8, 0xD1, 0x38, 0xBD, 0x58, 0x24, 0x10, 0x00, 0x5C, 0x24, 0x10, 0x00, + 0x50, 0x24, 0x10, 0x00, 0x00, 0x10, 0x10, 0x00, 0x68, 0x24, 0x10, 0x00, + 0x64, 0x24, 0x10, 0x00, 0x0A, 0x22, 0x10, 0x00, 0x70, 0xB5, 0x20, 0x21, + 0xF6, 0x48, 0x04, 0xF0, 0x42, 0xF9, 0xF5, 0x48, 0x05, 0xF0, 0x98, 0xFE, + 0xF3, 0x4D, 0x44, 0x1E, 0x15, 0xF8, 0x01, 0x1B, 0xA1, 0xF1, 0x90, 0x02, + 0x1F, 0x2A, 0x03, 0xD8, 0xF0, 0x48, 0x50, 0xF8, 0x22, 0x20, 0x07, 0xE0, + 0xA1, 0xF1, 0xC0, 0x00, 0x0F, 0x28, 0x08, 0xD8, 0xEC, 0x49, 0x80, 0x31, + 0x51, 0xF8, 0x20, 0x20, 0x29, 0x46, 0x20, 0x46, 0xBD, 0xE8, 0x70, 0x40, + 0x10, 0x47, 0xB8, 0x29, 0x3E, 0xD0, 0x11, 0xDC, 0xB0, 0x29, 0x1E, 0xD0, + 0xB2, 0x29, 0x2B, 0xD0, 0xB7, 0x29, 0x4E, 0xD1, 0x02, 0x2C, 0x4C, 0xD1, + 0x22, 0x46, 0x29, 0x46, 0xB7, 0x20, 0x00, 0xF0, 0x99, 0xFE, 0x28, 0x88, + 0xBD, 0xE8, 0x70, 0x40, 0xFF, 0xF7, 0xF5, 0xBE, 0xFB, 0x29, 0x35, 0xD0, + 0xFC, 0x29, 0x3E, 0xD1, 0x00, 0x2C, 0x3C, 0xD1, 0x00, 0x22, 0x11, 0x46, + 0xFC, 0x20, 0x00, 0xF0, 0x89, 0xFE, 0xBD, 0xE8, 0x70, 0x40, 0xFF, 0xF7, + 0xFF, 0xBE, 0x02, 0x2C, 0x31, 0xDD, 0x22, 0x46, 0x29, 0x46, 0xB0, 0x20, + 0x00, 0xF0, 0x7E, 0xFE, 0x28, 0x88, 0xA2, 0x1E, 0xA9, 0x1C, 0xBD, 0xE8, + 0x70, 0x40, 0x40, 0xBA, 0xFF, 0xF7, 0x9F, 0xBE, 0x03, 0x2C, 0x22, 0xD1, + 0x22, 0x46, 0x29, 0x46, 0xB2, 0x20, 0x00, 0xF0, 0x6F, 0xFE, 0x28, 0x88, + 0xA9, 0x78, 0xBD, 0xE8, 0x70, 0x40, 0x40, 0xBA, 0xFF, 0xF7, 0xAE, 0xBE, + 0x02, 0x2C, 0x14, 0xD1, 0x22, 0x46, 0x29, 0x46, 0xB8, 0x20, 0x00, 0xF0, + 0x61, 0xFE, 0x28, 0x88, 0xBD, 0xE8, 0x70, 0x40, 0xFF, 0xF7, 0xBB, 0xBE, + 0x00, 0x2C, 0x08, 0xD1, 0x00, 0x22, 0x11, 0x46, 0xFB, 0x20, 0x00, 0xF0, + 0x55, 0xFE, 0xBD, 0xE8, 0x70, 0x40, 0xFF, 0xF7, 0xBD, 0xBE, 0x70, 0xBD, + 0x0E, 0xB5, 0x01, 0x28, 0x1C, 0xD1, 0x0A, 0x78, 0x01, 0x2A, 0x19, 0xD1, + 0x02, 0x46, 0xC8, 0x20, 0x00, 0xF0, 0x46, 0xFE, 0x01, 0x20, 0x8D, 0xF8, + 0x01, 0x00, 0xB6, 0x48, 0x00, 0x78, 0x8D, 0xF8, 0x02, 0x00, 0xB5, 0x48, + 0x00, 0x78, 0x8D, 0xF8, 0x03, 0x00, 0xB4, 0x48, 0x00, 0x78, 0x8D, 0xF8, + 0x04, 0x00, 0xB3, 0x48, 0x00, 0x78, 0x8D, 0xF8, 0x05, 0x00, 0x68, 0x46, + 0x00, 0xF0, 0xC3, 0xFA, 0x0E, 0xBD, 0x7C, 0xB5, 0x00, 0x25, 0x0C, 0x46, + 0x00, 0x95, 0x01, 0x21, 0x8D, 0xF8, 0x01, 0x10, 0xFF, 0x21, 0x01, 0x95, + 0x8D, 0xF8, 0x02, 0x10, 0x05, 0x28, 0x15, 0xD1, 0x21, 0x78, 0x01, 0x29, + 0x12, 0xD1, 0x02, 0x46, 0x21, 0x46, 0xC7, 0x20, 0x00, 0xF0, 0x1A, 0xFE, + 0xA1, 0x49, 0x60, 0x78, 0x08, 0x70, 0xA1, 0x49, 0xA0, 0x78, 0x08, 0x70, + 0xA0, 0x49, 0xE0, 0x78, 0x08, 0x70, 0xA0, 0x49, 0x20, 0x79, 0x08, 0x60, + 0x8D, 0xF8, 0x02, 0x50, 0x68, 0x46, 0x00, 0xF0, 0x9F, 0xFA, 0x7C, 0xBD, + 0x10, 0xB5, 0x00, 0x22, 0x11, 0x46, 0x93, 0x20, 0x00, 0xF0, 0x02, 0xFE, + 0x01, 0x20, 0xFF, 0xF7, 0x8F, 0xFE, 0xBD, 0xE8, 0x10, 0x40, 0x02, 0x20, + 0xFF, 0xF7, 0x9A, 0xBE, 0x10, 0xB5, 0x00, 0x22, 0x11, 0x46, 0x92, 0x20, + 0x00, 0xF0, 0xF4, 0xFD, 0x01, 0x20, 0xFF, 0xF7, 0x79, 0xFE, 0xBD, 0xE8, + 0x10, 0x40, 0x02, 0x20, 0xFF, 0xF7, 0x84, 0xBE, 0x70, 0x47, 0x70, 0x47, + 0x70, 0x47, 0x70, 0x47, 0x70, 0x47, 0x70, 0x47, 0x10, 0xB5, 0x00, 0x22, + 0x11, 0x46, 0xA8, 0x20, 0x00, 0xF0, 0xE0, 0xFD, 0xBD, 0xE8, 0x10, 0x40, + 0x08, 0x20, 0xFF, 0xF7, 0x7B, 0xBE, 0x10, 0xB5, 0x00, 0x22, 0x11, 0x46, + 0xAB, 0x20, 0x00, 0xF0, 0xD5, 0xFD, 0xBD, 0xE8, 0x10, 0x40, 0x08, 0x20, + 0xFF, 0xF7, 0x68, 0xBE, 0x10, 0xB5, 0x00, 0x22, 0x11, 0x46, 0xA2, 0x20, + 0x00, 0xF0, 0xCA, 0xFD, 0xBD, 0xE8, 0x10, 0x40, 0x3F, 0x20, 0xFF, 0xF7, + 0x71, 0xBE, 0x70, 0xB5, 0x04, 0x46, 0x02, 0x46, 0x0D, 0x46, 0xA3, 0x20, + 0x00, 0xF0, 0xBE, 0xFD, 0x77, 0x48, 0x4C, 0xB1, 0x01, 0x2C, 0x09, 0xD0, + 0xBD, 0xE8, 0x70, 0x40, 0xD0, 0x21, 0x4D, 0xF6, 0xC0, 0x62, 0xBA, 0x20, + 0x00, 0xF0, 0x4B, 0xBA, 0x00, 0x21, 0x00, 0xE0, 0x29, 0x78, 0x01, 0x70, + 0x83, 0x20, 0xFF, 0xF7, 0x77, 0xFE, 0x00, 0x23, 0xBD, 0xE8, 0x70, 0x40, + 0x1A, 0x46, 0x19, 0x46, 0x01, 0x20, 0x00, 0xF0, 0x60, 0xBD, 0x10, 0xB5, + 0x00, 0x22, 0x11, 0x46, 0xA4, 0x20, 0x00, 0xF0, 0x9D, 0xFD, 0x38, 0x20, + 0xFF, 0xF7, 0x66, 0xFE, 0x00, 0x23, 0xBD, 0xE8, 0x10, 0x40, 0x1A, 0x46, + 0x19, 0x46, 0x02, 0x20, 0x00, 0xF0, 0x4F, 0xBD, 0x10, 0xB5, 0x00, 0x22, + 0x11, 0x46, 0xAA, 0x20, 0x00, 0xF0, 0x8C, 0xFD, 0xBD, 0xE8, 0x10, 0x40, + 0x00, 0xF0, 0xBC, 0xBC, 0x10, 0xB5, 0x00, 0x22, 0x11, 0x46, 0xAE, 0x20, + 0x00, 0xF0, 0x82, 0xFD, 0xBD, 0xE8, 0x10, 0x40, 0x01, 0x20, 0xFF, 0xF7, + 0x6D, 0xBE, 0x70, 0xB5, 0x0C, 0x46, 0x4D, 0xF6, 0xC0, 0x65, 0x01, 0x28, + 0x05, 0xDB, 0x02, 0x46, 0xC0, 0x20, 0x00, 0xF0, 0x73, 0xFD, 0x20, 0x78, + 0x30, 0xB1, 0x2A, 0x46, 0xBD, 0xE8, 0x70, 0x40, 0xD0, 0x21, 0xBA, 0x20, + 0x00, 0xF0, 0x03, 0xBA, 0x4E, 0x48, 0x00, 0x21, 0x00, 0x68, 0x40, 0xF8, + 0x36, 0x1F, 0x61, 0x78, 0x01, 0x60, 0xA2, 0x78, 0x41, 0xEA, 0x02, 0x21, + 0x01, 0x60, 0xE2, 0x78, 0x41, 0xEA, 0x02, 0x41, 0x01, 0x60, 0x22, 0x79, + 0x41, 0xEA, 0x02, 0x61, 0x01, 0x60, 0x70, 0xBD, 0x70, 0xB5, 0x05, 0x46, + 0x00, 0x20, 0x02, 0x46, 0x03, 0x46, 0x05, 0xE0, 0xCC, 0x5C, 0xDE, 0x00, + 0xB4, 0x40, 0x22, 0x43, 0x5B, 0x1C, 0xDB, 0xB2, 0xAB, 0x42, 0xF7, 0xDB, + 0xD1, 0x07, 0x01, 0xD0, 0x40, 0xF0, 0x01, 0x00, 0x91, 0x07, 0x01, 0xD5, + 0x40, 0xF0, 0x02, 0x00, 0x51, 0x07, 0x01, 0xD5, 0x40, 0xF0, 0x04, 0x00, + 0x11, 0x07, 0x01, 0xD5, 0x40, 0xF0, 0x08, 0x00, 0xD1, 0x06, 0x01, 0xD5, + 0x40, 0xF4, 0x80, 0x70, 0x91, 0x06, 0x01, 0xD5, 0x40, 0xF4, 0x00, 0x70, + 0xD1, 0x03, 0x01, 0xD5, 0x40, 0xF4, 0x80, 0x30, 0x70, 0xBD, 0x70, 0xB5, + 0x0D, 0x46, 0x04, 0x46, 0x01, 0x28, 0x0B, 0xDB, 0x02, 0x46, 0xC1, 0x20, + 0x00, 0xF0, 0x22, 0xFD, 0x29, 0x46, 0x20, 0x46, 0xFF, 0xF7, 0xC8, 0xFF, + 0xBD, 0xE8, 0x70, 0x40, 0xFF, 0xF7, 0xBA, 0xBD, 0x70, 0xBD, 0x70, 0xB5, + 0x0D, 0x46, 0x04, 0x46, 0x01, 0x28, 0x0B, 0xDB, 0x02, 0x46, 0xC2, 0x20, + 0x00, 0xF0, 0x10, 0xFD, 0x29, 0x46, 0x20, 0x46, 0xFF, 0xF7, 0xB6, 0xFF, + 0xBD, 0xE8, 0x70, 0x40, 0xFF, 0xF7, 0xA0, 0xBD, 0x70, 0xBD, 0x10, 0xB5, + 0x00, 0x22, 0x11, 0x46, 0xA5, 0x20, 0x00, 0xF0, 0x01, 0xFD, 0xBD, 0xE8, + 0x10, 0x40, 0xFF, 0xF7, 0x13, 0xBE, 0x10, 0xB5, 0x00, 0x22, 0x11, 0x46, + 0x91, 0x20, 0x00, 0xF0, 0xF7, 0xFC, 0xBD, 0xE8, 0x10, 0x40, 0x00, 0xF0, + 0xE6, 0xBC, 0x70, 0xB5, 0x04, 0x46, 0x02, 0x46, 0x0D, 0x46, 0xA7, 0x20, + 0x00, 0xF0, 0xEC, 0xFC, 0x00, 0x20, 0x4C, 0xB1, 0x02, 0x2C, 0x0B, 0xD0, + 0xBD, 0xE8, 0x70, 0x40, 0xD0, 0x21, 0x4D, 0xF6, 0xC0, 0x62, 0xBA, 0x20, + 0x00, 0xF0, 0x79, 0xB9, 0xBD, 0xE8, 0x70, 0x40, 0xFF, 0xF7, 0xC5, 0xBD, + 0x28, 0x88, 0xF9, 0xE7, 0x63, 0x51, 0x10, 0x00, 0x64, 0x1D, 0x01, 0x00, + 0xE6, 0x23, 0x10, 0x00, 0xB8, 0x23, 0x10, 0x00, 0x4C, 0x23, 0x10, 0x00, + 0xBC, 0x23, 0x10, 0x00, 0x9C, 0x22, 0x10, 0x00, 0x54, 0x24, 0x10, 0x00, + 0x08, 0xB5, 0xFF, 0xF7, 0xE3, 0xFC, 0x00, 0xF0, 0xCD, 0xFA, 0x1F, 0x21, + 0x6B, 0x46, 0x00, 0x22, 0x04, 0x20, 0x02, 0xF0, 0xFD, 0xFC, 0x00, 0x98, + 0xC0, 0x07, 0x07, 0xD0, 0xFF, 0xF7, 0xF0, 0xFD, 0x01, 0x21, 0x04, 0x20, + 0x02, 0xF0, 0xD3, 0xFC, 0x05, 0xF0, 0x84, 0xFC, 0x00, 0x98, 0x80, 0x07, + 0x0C, 0xD5, 0x08, 0x20, 0xFF, 0xF7, 0x4E, 0xFD, 0x02, 0x21, 0x04, 0x20, + 0x02, 0xF0, 0xC7, 0xFC, 0x00, 0x23, 0x1A, 0x46, 0x19, 0x46, 0xCC, 0x20, + 0x00, 0xF0, 0x61, 0xFC, 0x00, 0x98, 0x40, 0x07, 0xDB, 0xD5, 0x08, 0x20, + 0xFF, 0xF7, 0x36, 0xFD, 0x04, 0x21, 0x08, 0x46, 0x02, 0xF0, 0xB7, 0xFC, + 0x00, 0x23, 0x1A, 0x46, 0x19, 0x46, 0xCD, 0x20, 0x00, 0xF0, 0x51, 0xFC, + 0xCD, 0xE7, 0x01, 0x21, 0x04, 0x20, 0x02, 0xF0, 0x7D, 0xBC, 0x00, 0x00, + 0x30, 0x4D, 0x2F, 0x4E, 0x04, 0x46, 0xC5, 0xE9, 0x00, 0x61, 0x00, 0x68, + 0xA8, 0x60, 0x60, 0x68, 0xE8, 0x60, 0xA0, 0x68, 0x28, 0x61, 0xE0, 0x68, + 0x68, 0x61, 0x20, 0x69, 0xA8, 0x61, 0x60, 0x69, 0xE8, 0x61, 0xA0, 0x69, + 0x28, 0x62, 0xE0, 0x69, 0x68, 0x62, 0x05, 0xF1, 0x28, 0x00, 0x05, 0xF0, + 0x49, 0xFB, 0x02, 0xF0, 0xCA, 0xFD, 0x44, 0x35, 0x85, 0xE8, 0x51, 0x00, + 0xFE, 0xE7, 0x10, 0xB5, 0x01, 0x28, 0x4F, 0xF0, 0x00, 0x02, 0x05, 0xD0, + 0x01, 0x46, 0xBD, 0xE8, 0x10, 0x40, 0x02, 0x20, 0x00, 0xF0, 0xFD, 0xB8, + 0x01, 0x21, 0x02, 0x20, 0x00, 0xF0, 0xF9, 0xF8, 0xFE, 0xE7, 0x01, 0x28, + 0x06, 0xD0, 0x02, 0x28, 0x07, 0xD1, 0x00, 0x22, 0x04, 0x21, 0x02, 0x20, + 0x00, 0xF0, 0xEF, 0xB8, 0x00, 0x22, 0x02, 0x21, 0xF9, 0xE7, 0x70, 0x47, + 0x10, 0xB5, 0x04, 0x46, 0x01, 0x46, 0x00, 0x22, 0x03, 0x20, 0x00, 0xF0, + 0xE4, 0xF8, 0x01, 0x2C, 0x01, 0xD0, 0x02, 0x2C, 0x00, 0xD1, 0xFE, 0xE7, + 0x10, 0xBD, 0x0A, 0x46, 0x01, 0x46, 0x08, 0x20, 0x00, 0xF0, 0xD9, 0xB8, + 0x42, 0xEA, 0x01, 0x42, 0x01, 0x46, 0x09, 0x20, 0x00, 0xF0, 0xD3, 0xB8, + 0x00, 0x22, 0x01, 0x46, 0x06, 0x20, 0x00, 0xF0, 0xCE, 0xB8, 0x01, 0x46, + 0x00, 0x22, 0x07, 0x20, 0x00, 0xF0, 0xC9, 0xF8, 0xFE, 0xE7, 0x00, 0x00, + 0xAF, 0x05, 0x50, 0xFA, 0x5C, 0x00, 0x01, 0x20, 0x10, 0xB5, 0x05, 0xF0, + 0x75, 0xFE, 0xBD, 0xE8, 0x10, 0x40, 0x4F, 0xF4, 0x80, 0x41, 0x00, 0x20, + 0x02, 0xF0, 0x0E, 0xBC, 0x48, 0x49, 0x00, 0x20, 0x81, 0xF8, 0x00, 0x04, + 0x81, 0xF8, 0x01, 0x04, 0x81, 0xF8, 0x02, 0x04, 0x45, 0x49, 0x08, 0x70, + 0x70, 0x47, 0x10, 0xB5, 0x04, 0x46, 0x01, 0x20, 0x02, 0xF0, 0xAF, 0xFC, + 0x40, 0x48, 0x90, 0xF8, 0x02, 0x14, 0x00, 0xEB, 0xC1, 0x02, 0x00, 0x21, + 0x63, 0x5C, 0x53, 0x54, 0x49, 0x1C, 0xC9, 0xB2, 0x08, 0x29, 0xF9, 0xD3, + 0x90, 0xF8, 0x00, 0x14, 0x3A, 0x4A, 0x49, 0x1C, 0xC9, 0xB2, 0x80, 0xF8, + 0x00, 0x14, 0x80, 0x29, 0x04, 0xD1, 0x7F, 0x21, 0x80, 0xF8, 0x00, 0x14, + 0x01, 0x21, 0x11, 0x70, 0x90, 0xF8, 0x02, 0x14, 0x49, 0x1C, 0x01, 0xF0, + 0x7F, 0x01, 0x80, 0xF8, 0x02, 0x14, 0x11, 0x78, 0x01, 0x29, 0x06, 0xD1, + 0x90, 0xF8, 0x01, 0x24, 0x52, 0x1C, 0x02, 0xF0, 0x7F, 0x02, 0x80, 0xF8, + 0x01, 0x24, 0x90, 0xF8, 0x00, 0x04, 0x01, 0x28, 0x06, 0xD1, 0x29, 0xB9, + 0x2A, 0x48, 0x00, 0x68, 0x90, 0xF8, 0x26, 0x00, 0x00, 0xF0, 0x49, 0xF8, + 0xBD, 0xE8, 0x10, 0x40, 0x01, 0x20, 0x02, 0xF0, 0x8F, 0xBC, 0x70, 0xB5, + 0x01, 0x20, 0x02, 0xF0, 0x70, 0xFC, 0x00, 0x25, 0x20, 0x4C, 0x21, 0x4E, + 0x12, 0xE0, 0x94, 0xF8, 0x01, 0x04, 0x04, 0xEB, 0xC0, 0x00, 0x05, 0xF0, + 0xFF, 0xFB, 0x94, 0xF8, 0x01, 0x04, 0x40, 0x1C, 0x00, 0xF0, 0x7F, 0x00, + 0x84, 0xF8, 0x01, 0x04, 0x94, 0xF8, 0x00, 0x04, 0x40, 0x1E, 0x84, 0xF8, + 0x00, 0x04, 0x35, 0x70, 0x94, 0xF8, 0x00, 0x04, 0x88, 0xB1, 0x05, 0xF0, + 0xAD, 0xFB, 0x3E, 0x28, 0xE5, 0xDB, 0x94, 0xF8, 0x00, 0x04, 0x50, 0xB1, + 0x12, 0x48, 0x00, 0x68, 0x90, 0xF8, 0x26, 0x00, 0x00, 0xF0, 0x19, 0xF8, + 0xBD, 0xE8, 0x70, 0x40, 0x01, 0x20, 0x02, 0xF0, 0x5F, 0xBC, 0x84, 0xF8, + 0x01, 0x54, 0x84, 0xF8, 0x02, 0x54, 0xF5, 0xE7, 0x10, 0xB5, 0x00, 0x24, + 0x01, 0x20, 0x02, 0xF0, 0x3A, 0xFC, 0x06, 0x48, 0x90, 0xF8, 0x00, 0x04, + 0x00, 0xB9, 0x01, 0x24, 0x01, 0x20, 0x02, 0xF0, 0x4D, 0xFC, 0x20, 0x46, + 0x10, 0xBD, 0x04, 0x49, 0x05, 0xF0, 0xC6, 0xBD, 0x34, 0xA4, 0x01, 0x20, + 0x30, 0x24, 0x10, 0x00, 0x50, 0x24, 0x10, 0x00, 0x9D, 0xBD, 0x00, 0x00, + 0x10, 0xB5, 0x04, 0x46, 0x05, 0xF0, 0x7A, 0xFB, 0x3E, 0x28, 0x0D, 0xDA, + 0xFF, 0xF7, 0xDE, 0xFF, 0x50, 0xB1, 0x01, 0x20, 0x02, 0xF0, 0x19, 0xFC, + 0x20, 0x46, 0x05, 0xF0, 0xAF, 0xFB, 0xBD, 0xE8, 0x10, 0x40, 0x01, 0x20, + 0x02, 0xF0, 0x2C, 0xBC, 0x20, 0x46, 0xBD, 0xE8, 0x10, 0x40, 0xFF, 0xF7, + 0x58, 0xBF, 0x17, 0x21, 0x01, 0x70, 0xE3, 0xE7, 0x18, 0x21, 0x01, 0x70, + 0xE0, 0xE7, 0x1C, 0xB5, 0x0F, 0x23, 0x8D, 0xF8, 0x00, 0x30, 0x8D, 0xF8, + 0x01, 0x00, 0x8D, 0xF8, 0x02, 0x10, 0x08, 0x0A, 0x8D, 0xF8, 0x03, 0x00, + 0x8D, 0xF8, 0x04, 0x20, 0x10, 0x0A, 0x8D, 0xF8, 0x05, 0x00, 0x10, 0x0C, + 0x8D, 0xF8, 0x06, 0x00, 0x10, 0x0E, 0xF8, 0x49, 0x8D, 0xF8, 0x07, 0x00, + 0x01, 0x20, 0x08, 0x70, 0x68, 0x46, 0x05, 0xF0, 0x83, 0xFB, 0x1C, 0xBD, + 0x1C, 0xB5, 0x00, 0x23, 0x00, 0x93, 0x01, 0x93, 0x0F, 0x23, 0x8D, 0xF8, + 0x00, 0x30, 0x8D, 0xF8, 0x01, 0x00, 0xEF, 0x48, 0x8D, 0xF8, 0x02, 0x10, + 0x8D, 0xF8, 0x03, 0x20, 0x00, 0x78, 0x80, 0x01, 0x8D, 0xF8, 0x07, 0x00, + 0x68, 0x46, 0x05, 0xF0, 0x6D, 0xFB, 0x1C, 0xBD, 0x2D, 0xE9, 0xFC, 0x41, + 0x00, 0x27, 0x06, 0x46, 0x00, 0x97, 0x12, 0x20, 0x15, 0x46, 0x0C, 0x46, + 0x01, 0x97, 0x8D, 0xF8, 0x00, 0x00, 0x1A, 0xE0, 0x20, 0x0A, 0x8D, 0xF8, + 0x01, 0x00, 0xC4, 0xF3, 0x0B, 0x00, 0x8D, 0xF8, 0x02, 0x40, 0x31, 0x5C, + 0x30, 0x44, 0x8D, 0xF8, 0x03, 0x10, 0x41, 0x78, 0x8D, 0xF8, 0x04, 0x10, + 0x81, 0x78, 0x8D, 0xF8, 0x05, 0x10, 0xC0, 0x78, 0x8D, 0xF8, 0x06, 0x00, + 0x8D, 0xF8, 0x07, 0x70, 0x68, 0x46, 0xFF, 0xF7, 0x89, 0xFF, 0x24, 0x1D, + 0x2D, 0x1F, 0x00, 0x2D, 0xE2, 0xDC, 0xBD, 0xE8, 0xFC, 0x81, 0x2D, 0xE9, + 0xF7, 0x4F, 0x86, 0xB0, 0x00, 0x20, 0x02, 0x90, 0x03, 0x90, 0x12, 0x20, + 0x92, 0x46, 0x88, 0x46, 0x8D, 0xF8, 0x08, 0x00, 0xA1, 0xF5, 0x80, 0x57, + 0x01, 0xF0, 0x55, 0xFC, 0x81, 0x46, 0x4F, 0xF0, 0x01, 0x0B, 0xA7, 0xE0, + 0x4F, 0xEA, 0x18, 0x20, 0x8D, 0xF8, 0x09, 0x00, 0x30, 0x20, 0xB7, 0xFB, + 0xF0, 0xF0, 0xC5, 0xB2, 0xB9, 0x00, 0x03, 0x20, 0xB1, 0xFB, 0xF0, 0xF0, + 0x00, 0xF0, 0x3F, 0x04, 0x0B, 0xFA, 0x05, 0xF0, 0x8D, 0xF8, 0x0A, 0x80, + 0x49, 0x46, 0x10, 0xEA, 0x09, 0x0F, 0x03, 0xD1, 0x28, 0x46, 0x00, 0xF0, + 0xFA, 0xFA, 0x05, 0x46, 0x00, 0x26, 0x22, 0x2C, 0x1B, 0xD2, 0x20, 0x2D, + 0x19, 0xD2, 0x1F, 0x20, 0x5B, 0x46, 0xCD, 0xF8, 0x10, 0x90, 0x06, 0xE0, + 0x04, 0x9A, 0x03, 0xFA, 0x00, 0xF1, 0x8A, 0x43, 0x40, 0x1E, 0xC0, 0xB2, + 0x04, 0x92, 0xA8, 0x42, 0xF6, 0xD8, 0x04, 0x21, 0x04, 0xA8, 0x05, 0xF0, + 0x1D, 0xFE, 0x40, 0x1E, 0xC1, 0xB2, 0x22, 0x46, 0x06, 0x98, 0x03, 0xF0, + 0xA5, 0xFE, 0x0D, 0xF8, 0x06, 0x00, 0x3F, 0x2C, 0x04, 0xD0, 0x64, 0x1C, + 0x14, 0xF0, 0xFF, 0x04, 0x02, 0xD0, 0x06, 0xE0, 0x00, 0x24, 0xF9, 0xE7, + 0x49, 0x46, 0x28, 0x46, 0x00, 0xF0, 0xCD, 0xFA, 0x05, 0x46, 0x76, 0x1C, + 0xF6, 0xB2, 0x06, 0x2E, 0xCF, 0xD3, 0x03, 0x20, 0xB7, 0xFB, 0xF0, 0xF1, + 0x00, 0xFB, 0x11, 0x70, 0x20, 0xB1, 0x01, 0x28, 0x25, 0xD0, 0x02, 0x28, + 0x47, 0xD1, 0x58, 0xE0, 0x9D, 0xF8, 0x01, 0x00, 0x9D, 0xF8, 0x00, 0x10, + 0x00, 0xF0, 0x03, 0x02, 0x62, 0xF3, 0x9F, 0x11, 0x8D, 0xF8, 0x0B, 0x10, + 0xC0, 0xF3, 0x83, 0x01, 0x9D, 0xF8, 0x02, 0x00, 0x41, 0xEA, 0x00, 0x11, + 0x8D, 0xF8, 0x0C, 0x10, 0xC0, 0xF3, 0x01, 0x11, 0x9D, 0xF8, 0x03, 0x00, + 0x41, 0xEA, 0x80, 0x00, 0x8D, 0xF8, 0x0D, 0x00, 0x9D, 0xF8, 0x05, 0x00, + 0x00, 0xF0, 0x03, 0x01, 0x9D, 0xF8, 0x04, 0x00, 0x61, 0xF3, 0x9F, 0x10, + 0x21, 0xE0, 0x9D, 0xF8, 0x00, 0x00, 0xC0, 0xF3, 0x83, 0x01, 0x9D, 0xF8, + 0x01, 0x00, 0x41, 0xEA, 0x00, 0x11, 0x8D, 0xF8, 0x0B, 0x10, 0xC0, 0xF3, + 0x01, 0x11, 0x9D, 0xF8, 0x02, 0x00, 0x41, 0xEA, 0x80, 0x00, 0x8D, 0xF8, + 0x0C, 0x00, 0x9D, 0xF8, 0x04, 0x00, 0x9D, 0xF8, 0x03, 0x10, 0x00, 0xF0, + 0x03, 0x02, 0x62, 0xF3, 0x9F, 0x11, 0x8D, 0xF8, 0x0D, 0x10, 0xC0, 0xF3, + 0x83, 0x01, 0x9D, 0xF8, 0x05, 0x00, 0x41, 0xEA, 0x00, 0x10, 0x8D, 0xF8, + 0x0E, 0x00, 0x00, 0x20, 0x8D, 0xF8, 0x0F, 0x00, 0x02, 0xA8, 0xFF, 0xF7, + 0xCD, 0xFE, 0x08, 0xF1, 0x04, 0x08, 0xAA, 0xF1, 0x04, 0x0A, 0x3F, 0x1D, + 0xBA, 0xF1, 0x00, 0x0F, 0x3F, 0xF7, 0x54, 0xAF, 0x09, 0xB0, 0xBD, 0xE8, + 0xF0, 0x8F, 0x9D, 0xF8, 0x00, 0x00, 0xC0, 0xF3, 0x01, 0x11, 0x9D, 0xF8, + 0x01, 0x00, 0x41, 0xEA, 0x80, 0x00, 0x8D, 0xF8, 0x0B, 0x00, 0x9D, 0xF8, + 0x03, 0x00, 0x9D, 0xF8, 0x02, 0x10, 0x00, 0xF0, 0x03, 0x02, 0x62, 0xF3, + 0x9F, 0x11, 0x8D, 0xF8, 0x0C, 0x10, 0xC0, 0xF3, 0x83, 0x01, 0x9D, 0xF8, + 0x04, 0x00, 0x41, 0xEA, 0x00, 0x11, 0x8D, 0xF8, 0x0D, 0x10, 0xC0, 0xF3, + 0x01, 0x11, 0x9D, 0xF8, 0x05, 0x00, 0x41, 0xEA, 0x80, 0x00, 0xC8, 0xE7, + 0x1C, 0xB5, 0x00, 0x24, 0x01, 0x94, 0x00, 0x94, 0x13, 0x24, 0x8D, 0xF8, + 0x00, 0x40, 0x8D, 0xF8, 0x01, 0x00, 0x00, 0x0A, 0x8D, 0xF8, 0x02, 0x00, + 0x8D, 0xF8, 0x04, 0x20, 0x8D, 0xF8, 0x03, 0x10, 0x8D, 0xF8, 0x05, 0x30, + 0x68, 0x46, 0xFF, 0xF7, 0x89, 0xFE, 0x1C, 0xBD, 0x1C, 0xB5, 0x00, 0x24, + 0x01, 0x94, 0x00, 0x94, 0x25, 0x24, 0x8D, 0xF8, 0x00, 0x40, 0x8D, 0xF8, + 0x01, 0x00, 0x00, 0x0A, 0x8D, 0xF8, 0x02, 0x00, 0x8D, 0xF8, 0x04, 0x20, + 0x8D, 0xF8, 0x03, 0x10, 0x8D, 0xF8, 0x05, 0x30, 0x68, 0x46, 0xFF, 0xF7, + 0x73, 0xFE, 0x1C, 0xBD, 0x1C, 0xB5, 0x00, 0x20, 0x4A, 0x49, 0x00, 0x90, + 0x01, 0x90, 0x09, 0x68, 0x10, 0x23, 0x4A, 0x78, 0x89, 0x78, 0x8D, 0xF8, + 0x00, 0x30, 0x8D, 0xF8, 0x04, 0x00, 0x8D, 0xF8, 0x01, 0x00, 0x8D, 0xF8, + 0x05, 0x20, 0x8D, 0xF8, 0x02, 0x00, 0x8D, 0xF8, 0x06, 0x10, 0x8D, 0xF8, + 0x03, 0x00, 0x8D, 0xF8, 0x07, 0x00, 0x68, 0x46, 0xFF, 0xF7, 0x56, 0xFE, + 0x1C, 0xBD, 0x2D, 0xE9, 0xFE, 0x43, 0x04, 0x46, 0x00, 0x20, 0x01, 0x90, + 0x02, 0x90, 0x94, 0xF8, 0x24, 0x00, 0x03, 0x28, 0x02, 0xD0, 0x08, 0x28, + 0x71, 0xD0, 0x05, 0x20, 0x8D, 0xF8, 0x04, 0x00, 0x94, 0xF8, 0x27, 0x20, + 0x9D, 0xF8, 0x05, 0x00, 0x33, 0x4F, 0x62, 0xF3, 0x03, 0x00, 0x61, 0xF3, + 0x07, 0x10, 0x8D, 0xF8, 0x05, 0x00, 0x38, 0x68, 0xB0, 0xF9, 0x16, 0x10, + 0xB4, 0xF9, 0x16, 0x00, 0x00, 0xF0, 0xE9, 0xFC, 0x06, 0x46, 0x38, 0x68, + 0xB0, 0xF9, 0x18, 0x10, 0xB4, 0xF9, 0x14, 0x00, 0x00, 0xF0, 0xE1, 0xFC, + 0x05, 0x46, 0x38, 0x68, 0x90, 0xF8, 0x20, 0x10, 0x4A, 0x07, 0x02, 0xD5, + 0xC2, 0x8A, 0x92, 0x1B, 0x16, 0xB2, 0x8A, 0x07, 0x02, 0xD5, 0x02, 0x8B, + 0x52, 0x1B, 0x15, 0xB2, 0xC9, 0x07, 0x46, 0xD0, 0x01, 0x8B, 0xB0, 0x46, + 0x0A, 0x46, 0x28, 0x46, 0x00, 0xF0, 0xBF, 0xFC, 0x06, 0x46, 0x38, 0x68, + 0xC1, 0x8A, 0x40, 0x46, 0x0A, 0x46, 0x00, 0xF0, 0xB8, 0xFC, 0x31, 0x09, + 0x8D, 0xF8, 0x06, 0x10, 0x01, 0x09, 0x8D, 0xF8, 0x07, 0x10, 0x9D, 0xF8, + 0x08, 0x10, 0x01, 0x23, 0x66, 0xF3, 0x07, 0x11, 0x60, 0xF3, 0x03, 0x01, + 0x8D, 0xF8, 0x08, 0x10, 0xB4, 0xF8, 0x3D, 0x50, 0x3F, 0x20, 0x00, 0x90, + 0x38, 0x68, 0x25, 0x34, 0xB0, 0xF8, 0xBE, 0x21, 0xB0, 0xF8, 0xBC, 0x11, + 0x28, 0x46, 0x00, 0xF0, 0xB0, 0xFC, 0x8D, 0xF8, 0x09, 0x00, 0xE0, 0x78, + 0x00, 0x07, 0x80, 0x0E, 0x8D, 0xF8, 0x0A, 0x00, 0x21, 0x78, 0x40, 0xEA, + 0x81, 0x10, 0x8D, 0xF8, 0x0A, 0x00, 0x05, 0x48, 0x00, 0x78, 0xC0, 0x07, + 0x40, 0x0E, 0x8D, 0xF8, 0x0B, 0x00, 0x01, 0xA8, 0xFF, 0xF7, 0xDE, 0xFD, + 0xBD, 0xE8, 0xFE, 0x83, 0x31, 0x24, 0x10, 0x00, 0x50, 0x24, 0x10, 0x00, + 0xFF, 0xE7, 0x04, 0x20, 0x8C, 0xE7, 0xC1, 0x8A, 0x30, 0x46, 0x0A, 0x46, + 0x00, 0xF0, 0x79, 0xFC, 0x06, 0x46, 0x38, 0x68, 0x01, 0x8B, 0x28, 0x46, + 0x0A, 0x46, 0xB8, 0xE7, 0x2D, 0xE9, 0xFE, 0x43, 0x04, 0x46, 0x00, 0x20, + 0x01, 0x90, 0x02, 0x90, 0x94, 0xF8, 0x24, 0x00, 0x03, 0x28, 0x02, 0xD0, + 0x08, 0x28, 0x6A, 0xD0, 0x05, 0x20, 0x8D, 0xF8, 0x04, 0x00, 0x9D, 0xF8, + 0x05, 0x00, 0xB5, 0x4F, 0x20, 0xF0, 0x0F, 0x00, 0x09, 0x30, 0x61, 0xF3, + 0x07, 0x10, 0x8D, 0xF8, 0x05, 0x00, 0x38, 0x68, 0xB0, 0xF9, 0x16, 0x10, + 0xB4, 0xF9, 0x02, 0x00, 0x00, 0xF0, 0x5F, 0xFC, 0x06, 0x46, 0x38, 0x68, + 0xB0, 0xF9, 0x18, 0x10, 0xB4, 0xF9, 0x00, 0x00, 0x00, 0xF0, 0x57, 0xFC, + 0x05, 0x46, 0x38, 0x68, 0x90, 0xF8, 0x20, 0x10, 0x4A, 0x07, 0x02, 0xD5, + 0xC2, 0x8A, 0x92, 0x1B, 0x16, 0xB2, 0x8A, 0x07, 0x02, 0xD5, 0x02, 0x8B, + 0x52, 0x1B, 0x15, 0xB2, 0xC9, 0x07, 0x40, 0xD0, 0x01, 0x8B, 0xB0, 0x46, + 0x0A, 0x46, 0x28, 0x46, 0x00, 0xF0, 0x35, 0xFC, 0x06, 0x46, 0x38, 0x68, + 0xC1, 0x8A, 0x40, 0x46, 0x0A, 0x46, 0x00, 0xF0, 0x2E, 0xFC, 0x31, 0x09, + 0x8D, 0xF8, 0x06, 0x10, 0x01, 0x09, 0x8D, 0xF8, 0x07, 0x10, 0x9D, 0xF8, + 0x08, 0x10, 0x01, 0x23, 0x66, 0xF3, 0x07, 0x11, 0x60, 0xF3, 0x03, 0x01, + 0x8D, 0xF8, 0x08, 0x10, 0xB4, 0xF8, 0x3D, 0x50, 0x3F, 0x20, 0x00, 0x90, + 0x38, 0x68, 0x25, 0x34, 0xB0, 0xF8, 0xBE, 0x21, 0xB0, 0xF8, 0xBC, 0x11, + 0x28, 0x46, 0x00, 0xF0, 0x26, 0xFC, 0x8D, 0xF8, 0x09, 0x00, 0xE0, 0x78, + 0x00, 0x07, 0x80, 0x0E, 0x8D, 0xF8, 0x0A, 0x00, 0x21, 0x78, 0x40, 0xEA, + 0x81, 0x10, 0x8D, 0xF8, 0x0A, 0x00, 0x88, 0x48, 0x00, 0x78, 0xC0, 0x07, + 0x40, 0x0E, 0x8D, 0xF8, 0x0B, 0x00, 0x01, 0xA8, 0xFF, 0xF7, 0x54, 0xFD, + 0x74, 0xE7, 0x04, 0x20, 0x93, 0xE7, 0xC1, 0x8A, 0x30, 0x46, 0x0A, 0x46, + 0x00, 0xF0, 0xF5, 0xFB, 0x06, 0x46, 0x38, 0x68, 0x01, 0x8B, 0x28, 0x46, + 0x0A, 0x46, 0xBE, 0xE7, 0x70, 0xB5, 0x88, 0xB0, 0x00, 0x24, 0x00, 0x94, + 0x14, 0x20, 0x01, 0x94, 0x8D, 0xF8, 0x00, 0x00, 0x04, 0xF0, 0x91, 0xFF, + 0x8D, 0xF8, 0x01, 0x00, 0x04, 0xF0, 0x46, 0xFA, 0x8D, 0xF8, 0x02, 0x00, + 0x49, 0x20, 0x8D, 0xF8, 0x03, 0x00, 0x72, 0x4E, 0xB5, 0x20, 0x8D, 0xF8, + 0x04, 0x00, 0x30, 0x68, 0x70, 0x4D, 0x41, 0x78, 0x8D, 0xF8, 0x05, 0x10, + 0x80, 0x78, 0x8D, 0xF8, 0x06, 0x00, 0x28, 0x78, 0x80, 0x01, 0x8D, 0xF8, + 0x07, 0x00, 0x68, 0x46, 0xFF, 0xF7, 0x20, 0xFD, 0x00, 0x94, 0x15, 0x20, + 0x01, 0x94, 0x8D, 0xF8, 0x00, 0x00, 0x30, 0x68, 0x90, 0xF8, 0xEC, 0x17, + 0x8D, 0xF8, 0x01, 0x10, 0x90, 0xF8, 0xED, 0x17, 0x8D, 0xF8, 0x02, 0x10, + 0x90, 0xF8, 0xEE, 0x17, 0x8D, 0xF8, 0x03, 0x10, 0x90, 0xF8, 0xEF, 0x07, + 0x8D, 0xF8, 0x04, 0x00, 0x28, 0x78, 0x80, 0x01, 0x8D, 0xF8, 0x07, 0x00, + 0x68, 0x46, 0xFF, 0xF7, 0x03, 0xFD, 0x00, 0x94, 0x02, 0xA8, 0x01, 0x94, + 0x04, 0xF0, 0x56, 0xFE, 0x1B, 0x20, 0x8D, 0xF8, 0x00, 0x00, 0x02, 0x98, + 0x00, 0x0E, 0x8D, 0xF8, 0x01, 0x00, 0x02, 0x98, 0x00, 0x0C, 0x8D, 0xF8, + 0x02, 0x00, 0x02, 0x98, 0x00, 0x0A, 0x8D, 0xF8, 0x03, 0x00, 0x02, 0x98, + 0x8D, 0xF8, 0x04, 0x00, 0x8D, 0xF8, 0x05, 0x40, 0x04, 0x98, 0x8D, 0xF8, + 0x06, 0x00, 0x28, 0x78, 0x80, 0x01, 0x8D, 0xF8, 0x07, 0x00, 0x68, 0x46, + 0xFF, 0xF7, 0xE0, 0xFC, 0x00, 0x94, 0x1C, 0x20, 0x8D, 0xF8, 0x00, 0x00, + 0x03, 0x98, 0x01, 0x94, 0x00, 0x0E, 0x8D, 0xF8, 0x01, 0x00, 0x03, 0x98, + 0x00, 0x0C, 0x8D, 0xF8, 0x02, 0x00, 0x03, 0x98, 0x00, 0x0A, 0x8D, 0xF8, + 0x03, 0x00, 0x03, 0x98, 0x8D, 0xF8, 0x04, 0x00, 0x05, 0x98, 0x8D, 0xF8, + 0x05, 0x00, 0x06, 0x98, 0x8D, 0xF8, 0x06, 0x00, 0x28, 0x78, 0x80, 0x01, + 0x8D, 0xF8, 0x07, 0x00, 0x68, 0x46, 0xFF, 0xF7, 0xBF, 0xFC, 0x08, 0xB0, + 0x70, 0xBD, 0x1C, 0xB5, 0x36, 0x4C, 0x24, 0x68, 0x94, 0xF8, 0xE8, 0x47, + 0xA4, 0x07, 0x10, 0xD5, 0x00, 0x24, 0x01, 0x94, 0x00, 0x94, 0x16, 0x24, + 0x8D, 0xF8, 0x00, 0x40, 0x8D, 0xF8, 0x01, 0x00, 0x8D, 0xF8, 0x02, 0x10, + 0x8D, 0xF8, 0x03, 0x20, 0x8D, 0xF8, 0x04, 0x30, 0x68, 0x46, 0xFF, 0xF7, + 0xA5, 0xFC, 0x1C, 0xBD, 0xC2, 0xB2, 0xC0, 0xF3, 0x07, 0x23, 0x05, 0x20, + 0xE1, 0xE7, 0x1C, 0xB5, 0x27, 0x4A, 0x12, 0x68, 0x92, 0xF8, 0xE8, 0x27, + 0x52, 0x07, 0x0F, 0xD5, 0x00, 0x22, 0x00, 0x92, 0x01, 0x92, 0x1D, 0x22, + 0x8D, 0xF8, 0x00, 0x20, 0x8D, 0xF8, 0x01, 0x00, 0x08, 0x0A, 0x8D, 0xF8, + 0x02, 0x00, 0x8D, 0xF8, 0x03, 0x10, 0x68, 0x46, 0xFF, 0xF7, 0x88, 0xFC, + 0x1C, 0xBD, 0x1C, 0xB5, 0x00, 0x20, 0x00, 0x90, 0x01, 0x90, 0x11, 0x21, + 0x8D, 0xF8, 0x07, 0x00, 0x8D, 0xF8, 0x00, 0x10, 0x68, 0x46, 0xFF, 0xF7, + 0x7B, 0xFC, 0x1C, 0xBD, 0x1C, 0xB5, 0x15, 0x4B, 0x1B, 0x68, 0x93, 0xF8, + 0xE8, 0x37, 0x9B, 0x06, 0x14, 0xD5, 0x00, 0x23, 0x00, 0x93, 0x01, 0x93, + 0xEC, 0x23, 0x8D, 0xF8, 0x00, 0x30, 0x8D, 0xF8, 0x01, 0x00, 0x00, 0x2A, + 0x07, 0xDD, 0x31, 0xB1, 0x06, 0x2A, 0x00, 0xDD, 0x06, 0x22, 0x0D, 0xF1, + 0x02, 0x00, 0x03, 0xF0, 0xE5, 0xF9, 0x68, 0x46, 0xFF, 0xF7, 0x5E, 0xFC, + 0x1C, 0xBD, 0x10, 0xB5, 0x00, 0x22, 0x01, 0x24, 0x40, 0x1C, 0xC0, 0xB2, + 0x04, 0xFA, 0x00, 0xF3, 0x0B, 0x42, 0x00, 0xD0, 0x02, 0x46, 0x0A, 0xB9, + 0x20, 0x28, 0xF5, 0xD3, 0x10, 0x46, 0x10, 0xBD, 0x50, 0x24, 0x10, 0x00, + 0x31, 0x24, 0x10, 0x00, 0x10, 0xB5, 0x5A, 0x21, 0x20, 0x48, 0x03, 0xF0, + 0x48, 0xFA, 0x20, 0x48, 0x20, 0x4A, 0x21, 0x4B, 0x01, 0x68, 0x08, 0x7D, + 0xA2, 0xEB, 0x40, 0x02, 0x1B, 0x48, 0x02, 0x80, 0x0A, 0x7D, 0xA3, 0xEB, + 0x42, 0x02, 0x42, 0x80, 0x0A, 0x7D, 0x1C, 0x4B, 0xA3, 0xEB, 0x42, 0x02, + 0x82, 0x80, 0x09, 0x7D, 0x1A, 0x4A, 0xA2, 0xEB, 0x41, 0x01, 0xC1, 0x80, + 0x00, 0x21, 0x01, 0x81, 0x18, 0x4A, 0x42, 0x83, 0x18, 0x4A, 0x82, 0x83, + 0x18, 0x4A, 0xC2, 0x83, 0x18, 0x4A, 0x02, 0x84, 0x18, 0x4A, 0x42, 0x84, + 0x18, 0x4A, 0x82, 0x84, 0x18, 0x4A, 0xC2, 0x84, 0x18, 0x4A, 0x02, 0x85, + 0x41, 0x87, 0x81, 0x87, 0xC1, 0x87, 0xA0, 0xF8, 0x40, 0x10, 0xA0, 0xF8, + 0x42, 0x10, 0xA0, 0xF8, 0x44, 0x10, 0xA0, 0xF8, 0x46, 0x10, 0xA0, 0xF8, + 0x48, 0x10, 0xA0, 0xF8, 0x4A, 0x10, 0xA0, 0xF8, 0x4C, 0x10, 0x10, 0x49, + 0xA0, 0xF8, 0x50, 0x10, 0x10, 0xBD, 0x00, 0x00, 0x00, 0x00, 0x01, 0x20, + 0x50, 0x24, 0x10, 0x00, 0x38, 0xA9, 0x01, 0x20, 0x78, 0x94, 0x01, 0x20, + 0x38, 0x9C, 0x01, 0x20, 0x7C, 0x1B, 0x01, 0x20, 0xFC, 0x93, 0x01, 0x20, + 0x38, 0x94, 0x01, 0x20, 0x04, 0x0A, 0x01, 0x20, 0x40, 0x0A, 0x01, 0x20, + 0x80, 0x0A, 0x01, 0x20, 0xBC, 0x0A, 0x01, 0x20, 0xFC, 0x22, 0x01, 0x20, + 0x38, 0x23, 0x01, 0x20, 0x00, 0x80, 0x01, 0x20, 0x70, 0xB5, 0x0D, 0x46, + 0xFC, 0x4C, 0x4A, 0x00, 0x01, 0x46, 0x20, 0x46, 0x03, 0xF0, 0x64, 0xF9, + 0x00, 0x21, 0x6E, 0x1E, 0x0F, 0xE0, 0x48, 0x1C, 0x0A, 0xE0, 0x34, 0xF9, + 0x10, 0x20, 0x34, 0xF9, 0x11, 0x30, 0x9A, 0x42, 0x03, 0xDA, 0x24, 0xF8, + 0x11, 0x20, 0x24, 0xF8, 0x10, 0x30, 0x40, 0x1C, 0xA8, 0x42, 0xF2, 0xD3, + 0x49, 0x1C, 0xB1, 0x42, 0xED, 0xD3, 0xE9, 0x07, 0x25, 0xF0, 0x01, 0x00, + 0x01, 0xD0, 0x20, 0x5E, 0x70, 0xBD, 0x21, 0x5E, 0x20, 0x44, 0x30, 0xF9, + 0x02, 0x0C, 0x08, 0x44, 0x00, 0xEB, 0xD0, 0x70, 0x40, 0x10, 0x00, 0xB2, + 0x70, 0xBD, 0x10, 0xB5, 0xF3, 0xF7, 0x40, 0xFE, 0x04, 0xF0, 0x2E, 0xFE, + 0x08, 0xB1, 0x04, 0xF0, 0x56, 0xFE, 0xBD, 0xE8, 0x10, 0x40, 0xF3, 0xF7, + 0x35, 0xBE, 0x10, 0xB5, 0xF3, 0xF7, 0x34, 0xFE, 0x04, 0xF0, 0x22, 0xFE, + 0x08, 0xB9, 0x04, 0xF0, 0x33, 0xFE, 0xBD, 0xE8, 0x10, 0x40, 0xF3, 0xF7, + 0x29, 0xBE, 0x30, 0xB5, 0x06, 0xE0, 0x32, 0xF8, 0x13, 0x40, 0x31, 0xF8, + 0x13, 0x50, 0x64, 0x1B, 0x20, 0xF8, 0x13, 0x40, 0x5B, 0x1E, 0xF6, 0xD2, + 0x30, 0xBD, 0x88, 0x42, 0x00, 0xD3, 0x08, 0x46, 0x90, 0x42, 0x00, 0xD3, + 0x10, 0x46, 0x70, 0x47, 0x88, 0x42, 0x00, 0xD3, 0x08, 0x46, 0x70, 0x47, + 0x88, 0x42, 0x00, 0xD8, 0x08, 0x46, 0x70, 0x47, 0x2D, 0xE9, 0xF1, 0x4F, + 0x86, 0xB0, 0xF0, 0x21, 0x06, 0x98, 0x03, 0xF0, 0xA6, 0xF9, 0x01, 0xF0, + 0x60, 0xF8, 0x02, 0x90, 0x01, 0xF0, 0x46, 0xF8, 0xCD, 0xE9, 0x00, 0x01, + 0x04, 0x21, 0x02, 0xA8, 0x05, 0xF0, 0x54, 0xFA, 0x83, 0x46, 0x08, 0x21, + 0x68, 0x46, 0x05, 0xF0, 0x4F, 0xFA, 0x00, 0x26, 0xB0, 0x46, 0x4F, 0xF0, + 0x01, 0x0A, 0x04, 0x90, 0x2D, 0xE0, 0x42, 0x46, 0x01, 0x20, 0x00, 0x21, + 0x03, 0xF0, 0xB3, 0xF8, 0xDD, 0xE9, 0x00, 0x23, 0x10, 0x40, 0x19, 0x40, + 0x08, 0x43, 0x20, 0xD0, 0x00, 0x27, 0xBA, 0x48, 0x3C, 0x46, 0x3D, 0x46, + 0x0A, 0xFA, 0x06, 0xF9, 0x03, 0x90, 0x15, 0xE0, 0x02, 0x99, 0x0A, 0xFA, + 0x05, 0xF0, 0x08, 0x42, 0x0F, 0xD0, 0x42, 0x46, 0x21, 0x46, 0x03, 0x98, + 0x03, 0xF0, 0xBA, 0xFA, 0xB8, 0x42, 0x06, 0xD0, 0x06, 0x99, 0x01, 0xEB, + 0xC4, 0x01, 0x0B, 0x68, 0x43, 0xEA, 0x09, 0x03, 0x0B, 0x60, 0x07, 0x46, + 0x64, 0x1C, 0x6D, 0x1C, 0x5C, 0x45, 0xE7, 0xD3, 0x76, 0x1C, 0x08, 0xF1, + 0x01, 0x08, 0x04, 0x98, 0x86, 0x42, 0xCE, 0xD3, 0x07, 0xB0, 0xBD, 0xE8, + 0xF0, 0x8F, 0x2D, 0xE9, 0xF0, 0x4F, 0x00, 0x25, 0x9B, 0x46, 0x03, 0xF1, + 0x28, 0x09, 0x8E, 0x46, 0x2C, 0x46, 0x01, 0x23, 0xA2, 0xF1, 0x01, 0x0A, + 0x1C, 0xE0, 0x02, 0x21, 0xAE, 0xF1, 0x01, 0x0C, 0x15, 0xE0, 0x59, 0xF8, + 0x31, 0x70, 0x01, 0x26, 0x9E, 0x40, 0x37, 0x40, 0x3F, 0x00, 0x0D, 0xD0, + 0x4F, 0x1E, 0x01, 0xFB, 0x02, 0x36, 0x07, 0xFB, 0x02, 0x37, 0x30, 0xF9, + 0x16, 0x60, 0x30, 0xF9, 0x17, 0x70, 0xF6, 0x1B, 0x00, 0xD5, 0x76, 0x42, + 0x35, 0x44, 0x64, 0x1C, 0x49, 0x1C, 0x61, 0x45, 0xE7, 0xD3, 0x5B, 0x1C, + 0x53, 0x45, 0xE0, 0xD3, 0x04, 0xB9, 0x01, 0x24, 0x95, 0xFB, 0xF4, 0xF1, + 0xCB, 0xF8, 0x20, 0x10, 0xCB, 0xE7, 0x2D, 0xE9, 0xF0, 0x4F, 0x8D, 0x4C, + 0x88, 0xB0, 0x24, 0x68, 0xDD, 0xE9, 0x11, 0x65, 0x94, 0xF8, 0x42, 0x71, + 0x01, 0x2D, 0x07, 0xF0, 0x0F, 0x0A, 0x01, 0xD1, 0x4F, 0xF0, 0x00, 0x0A, + 0xCA, 0xF1, 0x10, 0x05, 0x49, 0x1E, 0x02, 0x95, 0x04, 0x91, 0x94, 0xF8, + 0x40, 0x51, 0x01, 0xF0, 0xFF, 0x0E, 0x8D, 0x42, 0x00, 0xDA, 0xAE, 0x46, + 0x51, 0x1E, 0x03, 0x91, 0xC9, 0xB2, 0x06, 0x91, 0x94, 0xF8, 0x41, 0x11, + 0x03, 0x9C, 0xA1, 0x42, 0x00, 0xDA, 0x06, 0x91, 0x31, 0x6A, 0x05, 0x91, + 0x00, 0x21, 0x00, 0x91, 0x88, 0x46, 0x89, 0x46, 0x01, 0x91, 0x07, 0x91, + 0x06, 0xF1, 0x28, 0x0B, 0x01, 0x21, 0x7A, 0xE0, 0x00, 0x26, 0x35, 0x46, + 0x02, 0x24, 0x20, 0xE0, 0x5B, 0xF8, 0x34, 0xC0, 0x01, 0x27, 0x8F, 0x40, + 0x0C, 0xEA, 0x07, 0x0C, 0x04, 0xFB, 0x02, 0x17, 0x5F, 0xEA, 0x0C, 0x0C, + 0x30, 0xF9, 0x17, 0xC0, 0xA4, 0xF1, 0x01, 0x07, 0x07, 0xFB, 0x02, 0x17, + 0x30, 0xF9, 0x17, 0x70, 0xAC, 0xEB, 0x07, 0x07, 0x06, 0xD0, 0x00, 0x2F, + 0x00, 0xDA, 0x7F, 0x42, 0xDD, 0xF8, 0x14, 0xC0, 0xA7, 0xEB, 0x0C, 0x07, + 0x00, 0x2F, 0x00, 0xDA, 0x7F, 0x42, 0x3E, 0x44, 0x64, 0x1C, 0x77, 0x46, + 0x74, 0x45, 0xDB, 0xD3, 0x3C, 0x46, 0x20, 0xE0, 0x5B, 0xF8, 0x34, 0xC0, + 0x01, 0x27, 0x8F, 0x40, 0x0C, 0xEA, 0x07, 0x0C, 0x04, 0xFB, 0x02, 0x17, + 0x5F, 0xEA, 0x0C, 0x0C, 0x30, 0xF9, 0x17, 0xC0, 0xA4, 0xF1, 0x01, 0x07, + 0x07, 0xFB, 0x02, 0x17, 0x30, 0xF9, 0x17, 0x70, 0xAC, 0xEB, 0x07, 0x07, + 0x06, 0xD0, 0x00, 0x2F, 0x00, 0xDA, 0x7F, 0x42, 0xDD, 0xF8, 0x14, 0xC0, + 0xA7, 0xEB, 0x0C, 0x07, 0x00, 0x2F, 0x00, 0xDA, 0x7F, 0x42, 0x3D, 0x44, + 0x64, 0x1C, 0x04, 0x9F, 0xBC, 0x42, 0xDB, 0xD3, 0x07, 0x9C, 0x4C, 0xB1, + 0x00, 0x9C, 0xA4, 0x1B, 0x00, 0xD5, 0x64, 0x42, 0xA0, 0x44, 0x01, 0x9C, + 0x64, 0x1B, 0x00, 0xD5, 0x64, 0x42, 0xA1, 0x44, 0xCD, 0xE9, 0x00, 0x65, + 0x06, 0x9C, 0xA1, 0x42, 0x18, 0xD1, 0x1C, 0x68, 0x02, 0x9D, 0x04, 0xFB, + 0x0A, 0xF4, 0x05, 0xFB, 0x08, 0x44, 0xE5, 0x17, 0x04, 0xEB, 0x15, 0x74, + 0x24, 0x11, 0x1C, 0x60, 0x9C, 0x68, 0x02, 0x9D, 0x04, 0xFB, 0x0A, 0xF4, + 0x05, 0xFB, 0x09, 0x44, 0xE5, 0x17, 0x04, 0xEB, 0x15, 0x74, 0x24, 0x11, + 0x4F, 0xF0, 0x00, 0x08, 0xC1, 0x46, 0x9C, 0x60, 0x01, 0x24, 0x49, 0x1C, + 0x07, 0x94, 0x03, 0x9C, 0xA1, 0x42, 0x81, 0xD3, 0x58, 0x68, 0x02, 0x99, + 0x00, 0xFB, 0x0A, 0xF0, 0x01, 0xFB, 0x08, 0x00, 0xC1, 0x17, 0x00, 0xEB, + 0x11, 0x70, 0x00, 0x11, 0x58, 0x60, 0xD8, 0x68, 0x02, 0x99, 0x00, 0xFB, + 0x0A, 0xF0, 0x01, 0xFB, 0x09, 0x00, 0xC1, 0x17, 0x00, 0xEB, 0x11, 0x70, + 0x00, 0x11, 0xD8, 0x60, 0x08, 0xB0, 0x04, 0xE7, 0xFC, 0xB5, 0x1C, 0x46, + 0x15, 0x46, 0x0E, 0x46, 0x07, 0x46, 0xFF, 0xF7, 0x00, 0xFF, 0x01, 0x20, + 0xCD, 0xE9, 0x00, 0x40, 0x2A, 0x46, 0x31, 0x46, 0x38, 0x46, 0x04, 0xF1, + 0x10, 0x03, 0xFF, 0xF7, 0x28, 0xFF, 0xFC, 0xBD, 0xF0, 0xB5, 0x00, 0x24, + 0x06, 0x46, 0x25, 0x46, 0x20, 0x46, 0x0D, 0xE0, 0x36, 0xF9, 0x11, 0x30, + 0x00, 0x2B, 0x01, 0xDB, 0x1F, 0x46, 0x00, 0xE0, 0x5F, 0x42, 0x97, 0x42, + 0x04, 0xDD, 0x00, 0x2B, 0x01, 0xDD, 0x1D, 0x44, 0x00, 0xE0, 0x1C, 0x44, + 0x49, 0x1E, 0xEF, 0xD2, 0x00, 0x2C, 0x00, 0xDA, 0x64, 0x42, 0xAC, 0x42, + 0x00, 0xDD, 0x01, 0x20, 0xF0, 0xBD, 0x2D, 0xE9, 0xF0, 0x43, 0x15, 0x46, + 0x4F, 0xF0, 0x01, 0x08, 0xDD, 0xF8, 0x1C, 0x90, 0x16, 0xE0, 0x00, 0xEB, + 0x45, 0x0C, 0x00, 0x26, 0x0C, 0x46, 0x0B, 0xE0, 0x08, 0xFA, 0x04, 0xF7, + 0x1F, 0x42, 0x07, 0xD0, 0x04, 0xFB, 0x02, 0xF7, 0x00, 0xEB, 0x47, 0x07, + 0x37, 0xF8, 0x15, 0x70, 0x3E, 0x44, 0x36, 0xB2, 0x64, 0x1E, 0xF1, 0xD2, + 0x96, 0xFB, 0xF9, 0xF4, 0xAC, 0xF8, 0x00, 0x40, 0x6D, 0x1E, 0xE6, 0xD2, + 0xBD, 0xE8, 0xF0, 0x83, 0xE0, 0x5C, 0x10, 0x00, 0x40, 0x10, 0x10, 0x00, + 0x50, 0x24, 0x10, 0x00, 0x2D, 0xE9, 0xF0, 0x4F, 0x47, 0xF6, 0xFF, 0x76, + 0xDD, 0xE9, 0x09, 0xB5, 0xF4, 0x43, 0x9A, 0x46, 0x01, 0x27, 0x81, 0x46, + 0xBC, 0x46, 0x2B, 0x46, 0x14, 0xE0, 0x32, 0xF8, 0x13, 0x00, 0x31, 0xF8, + 0x13, 0x80, 0xA0, 0xEB, 0x08, 0x00, 0x00, 0xB2, 0xB0, 0x42, 0x00, 0xDA, + 0x06, 0x46, 0xA0, 0x42, 0x00, 0xDD, 0x04, 0x46, 0x00, 0x28, 0x02, 0xDD, + 0x4F, 0xF0, 0x00, 0x0C, 0x02, 0xE0, 0x01, 0xDA, 0x4F, 0xF0, 0x00, 0x07, + 0x5B, 0x1E, 0xE8, 0xD2, 0x27, 0xB1, 0xBC, 0xF1, 0x00, 0x0F, 0x01, 0xD0, + 0x00, 0x20, 0x09, 0xE0, 0x57, 0xEA, 0x0C, 0x00, 0x06, 0xD0, 0x27, 0xB9, + 0xBC, 0xF1, 0x00, 0x0F, 0x01, 0xD0, 0x20, 0x46, 0x00, 0xE0, 0x30, 0x46, + 0x00, 0x23, 0x1E, 0x46, 0x2C, 0x46, 0xCB, 0xF1, 0x00, 0x0C, 0x0D, 0xE0, + 0x32, 0xF8, 0x14, 0x70, 0x31, 0xF8, 0x14, 0x80, 0xA7, 0xEB, 0x08, 0x07, + 0x3F, 0x1A, 0x3F, 0xB2, 0x57, 0x45, 0x03, 0xDA, 0x67, 0x45, 0x01, 0xDD, + 0x3B, 0x44, 0x76, 0x1C, 0x64, 0x1E, 0xEF, 0xD2, 0x06, 0xB9, 0x01, 0x26, + 0x93, 0xFB, 0xF6, 0xF2, 0x13, 0x18, 0x04, 0xE0, 0x31, 0xF8, 0x15, 0x00, + 0x18, 0x44, 0x29, 0xF8, 0x15, 0x00, 0x6D, 0x1E, 0xF8, 0xD2, 0x54, 0xE6, + 0xF0, 0xB4, 0xDD, 0xE9, 0x04, 0x64, 0x01, 0x2C, 0x02, 0xD0, 0x0B, 0xB1, + 0xF5, 0x1A, 0x0E, 0xE0, 0xF0, 0xBC, 0x52, 0x00, 0x02, 0xF0, 0x06, 0xBF, + 0x30, 0xF9, 0x12, 0x40, 0x31, 0xF9, 0x12, 0x70, 0x5C, 0x43, 0x07, 0xFB, + 0x05, 0x44, 0x94, 0xFB, 0xF6, 0xF4, 0x20, 0xF8, 0x12, 0x40, 0x52, 0x1E, + 0xF2, 0xD2, 0xF0, 0xBC, 0x70, 0x47, 0xF0, 0xB5, 0x16, 0x46, 0x15, 0xE0, + 0x00, 0x27, 0x3D, 0x46, 0xF4, 0x1A, 0x06, 0xEB, 0x03, 0x0C, 0x08, 0xE0, + 0x00, 0x2C, 0x05, 0xDB, 0x94, 0x42, 0x03, 0xDA, 0x31, 0xF9, 0x14, 0xE0, + 0x6D, 0x1C, 0x77, 0x44, 0x64, 0x1C, 0xA4, 0x45, 0xF4, 0xDA, 0x1D, 0xB1, + 0x97, 0xFB, 0xF5, 0xF4, 0x20, 0xF8, 0x16, 0x40, 0x76, 0x1E, 0xE7, 0xD2, + 0xF0, 0xBD, 0x91, 0x42, 0x01, 0xD1, 0x00, 0xB2, 0x70, 0x47, 0x50, 0x43, + 0xB0, 0xFB, 0xF1, 0xF0, 0x00, 0xB2, 0x90, 0x42, 0xF7, 0xD9, 0x10, 0x46, + 0xF5, 0xE7, 0x88, 0x42, 0x01, 0xDD, 0x08, 0x46, 0x70, 0x47, 0x00, 0x28, + 0xFC, 0xDA, 0x00, 0x20, 0x70, 0x47, 0x30, 0xB5, 0x04, 0x46, 0x00, 0x20, + 0x03, 0x9D, 0x8C, 0x42, 0x01, 0xD2, 0x18, 0x46, 0x30, 0xBD, 0x94, 0x42, + 0x01, 0xD9, 0x28, 0x46, 0x30, 0xBD, 0x8A, 0x42, 0xFC, 0xD0, 0x60, 0x1A, + 0xEC, 0x1A, 0x60, 0x43, 0x51, 0x1A, 0x90, 0xFB, 0xF1, 0xF0, 0x18, 0x44, + 0xC0, 0xB2, 0x30, 0xBD, 0xF0, 0xB5, 0xA1, 0xB0, 0x0E, 0x46, 0x07, 0x46, + 0x15, 0x46, 0x80, 0x21, 0x68, 0x46, 0x02, 0xF0, 0x48, 0xFF, 0x2C, 0x46, + 0x6B, 0x46, 0x14, 0xE0, 0x00, 0x20, 0x31, 0x46, 0x09, 0xE0, 0x00, 0xEB, + 0x04, 0x0C, 0x53, 0xF8, 0x24, 0x20, 0x37, 0xF9, 0x1C, 0xC0, 0x28, 0x44, + 0x62, 0x44, 0x43, 0xF8, 0x24, 0x20, 0x49, 0x1E, 0xF3, 0xD2, 0x53, 0xF8, + 0x24, 0x00, 0x90, 0xFB, 0xF6, 0xF0, 0x43, 0xF8, 0x24, 0x00, 0x64, 0x1E, + 0xE8, 0xD2, 0x00, 0x24, 0x29, 0x46, 0x13, 0xE0, 0x00, 0x20, 0x32, 0x46, + 0x0B, 0xE0, 0x02, 0xFB, 0x05, 0x1C, 0x53, 0xF8, 0x21, 0xE0, 0x37, 0xF9, + 0x1C, 0xC0, 0xBC, 0xEB, 0x0E, 0x0C, 0x01, 0xD5, 0xCC, 0xF1, 0x00, 0x0C, + 0x60, 0x44, 0x52, 0x1E, 0xF1, 0xD2, 0xA0, 0x42, 0x00, 0xDD, 0x04, 0x46, + 0x49, 0x1E, 0xE9, 0xD2, 0x94, 0xFB, 0xF6, 0xF0, 0xB0, 0xF5, 0x80, 0x3F, + 0x03, 0xDB, 0x4F, 0xF6, 0xFF, 0x70, 0x21, 0xB0, 0xF0, 0xBD, 0x80, 0xB2, + 0xFB, 0xE7, 0x2D, 0xE9, 0xF0, 0x43, 0x06, 0x46, 0x00, 0x20, 0x07, 0x9F, + 0x04, 0x46, 0x4F, 0xF0, 0x01, 0x09, 0x7F, 0x1E, 0x1B, 0xE0, 0x31, 0xF8, + 0x14, 0x50, 0x36, 0xF8, 0x14, 0xC0, 0x06, 0xEB, 0x44, 0x08, 0xA5, 0xEB, + 0x0C, 0x05, 0x01, 0xEB, 0x44, 0x0C, 0xB8, 0xF8, 0x02, 0x80, 0xBC, 0xF8, + 0x02, 0xC0, 0xAC, 0xEB, 0x08, 0x0C, 0xA5, 0xEB, 0x0C, 0x05, 0x2D, 0xB2, + 0x95, 0x42, 0x05, 0xDA, 0x1D, 0x44, 0x00, 0x2D, 0x02, 0xDD, 0x09, 0xFA, + 0x04, 0xF5, 0x28, 0x43, 0x64, 0x1C, 0xBC, 0x42, 0xE1, 0xDB, 0xCD, 0xE6, + 0x03, 0xE0, 0x00, 0xEA, 0x40, 0x03, 0x03, 0xEA, 0x50, 0x00, 0x49, 0x1E, + 0xF9, 0xD2, 0x70, 0x47, 0x2D, 0xE9, 0xF0, 0x43, 0x04, 0x46, 0x85, 0xB0, + 0xA5, 0x20, 0x04, 0xF8, 0x01, 0x0B, 0x4F, 0xF6, 0xFF, 0x79, 0xDF, 0xF8, + 0x28, 0x84, 0xA4, 0xF8, 0x00, 0x90, 0x01, 0x27, 0xE7, 0x70, 0x98, 0xF8, + 0x00, 0x00, 0xA0, 0x70, 0x04, 0xF0, 0xF1, 0xFA, 0x05, 0x0A, 0x04, 0xF0, + 0xEE, 0xFA, 0x45, 0xEA, 0x00, 0x20, 0xA0, 0x80, 0x04, 0xF0, 0xED, 0xFA, + 0xA0, 0x71, 0x03, 0xF0, 0x9D, 0xFD, 0xE0, 0x71, 0x03, 0xF0, 0xA0, 0xFD, + 0xFE, 0x4D, 0x20, 0x72, 0x28, 0x68, 0x90, 0xF8, 0xEC, 0x17, 0xA1, 0x72, + 0x90, 0xF8, 0xED, 0x17, 0xE1, 0x72, 0x90, 0xF8, 0xEE, 0x17, 0x21, 0x73, + 0x90, 0xF8, 0xEF, 0x17, 0x61, 0x73, 0x90, 0xF8, 0xF0, 0x17, 0xA1, 0x73, + 0x90, 0xF8, 0xF1, 0x17, 0xE1, 0x73, 0x90, 0xF8, 0xF2, 0x17, 0x21, 0x74, + 0x90, 0xF8, 0xF3, 0x07, 0x60, 0x74, 0x68, 0x46, 0x04, 0xF0, 0xCC, 0xF9, + 0x00, 0x98, 0x00, 0x26, 0x00, 0x0E, 0xA0, 0x74, 0x00, 0x98, 0x00, 0x0C, + 0xE0, 0x74, 0x00, 0x98, 0x00, 0x0A, 0x20, 0x75, 0x00, 0x98, 0x60, 0x75, + 0xA6, 0x75, 0x02, 0x98, 0xE0, 0x75, 0x01, 0x98, 0x00, 0x0E, 0x20, 0x76, + 0x01, 0x98, 0x00, 0x0C, 0x60, 0x76, 0x01, 0x98, 0x00, 0x0A, 0xA0, 0x76, + 0x01, 0x98, 0xE0, 0x76, 0x03, 0x98, 0x20, 0x77, 0x04, 0x98, 0x60, 0x77, + 0x02, 0x20, 0x60, 0x72, 0x4B, 0xF2, 0x49, 0x50, 0xE0, 0x83, 0x28, 0x68, + 0xB0, 0xF8, 0x01, 0x10, 0x21, 0x84, 0xDD, 0x49, 0xC4, 0xF8, 0x22, 0x10, + 0xC1, 0x8A, 0xE1, 0x84, 0x01, 0x8B, 0x21, 0x85, 0x41, 0x7D, 0x84, 0xF8, + 0x2A, 0x10, 0x01, 0x7D, 0x84, 0xF8, 0x2B, 0x10, 0x01, 0x7B, 0x42, 0x7B, + 0x43, 0x7C, 0x41, 0xEA, 0x02, 0x21, 0x82, 0x7B, 0x41, 0xEA, 0x02, 0x41, + 0xC2, 0x7B, 0x41, 0xEA, 0x02, 0x61, 0x02, 0x7C, 0x42, 0xEA, 0x03, 0x22, + 0x83, 0x7C, 0x42, 0xEA, 0x03, 0x42, 0xC3, 0x7C, 0xE1, 0x62, 0x42, 0xEA, + 0x03, 0x62, 0x22, 0x63, 0x01, 0x79, 0x42, 0x79, 0x43, 0x7A, 0x41, 0xEA, + 0x02, 0x21, 0x82, 0x79, 0x41, 0xEA, 0x02, 0x41, 0xC2, 0x79, 0x41, 0xEA, + 0x02, 0x61, 0x02, 0x7A, 0x42, 0xEA, 0x03, 0x22, 0x83, 0x7A, 0x42, 0xEA, + 0x03, 0x42, 0xC3, 0x7A, 0x61, 0x63, 0x42, 0xEA, 0x03, 0x62, 0xA2, 0x63, + 0x01, 0x21, 0x00, 0xF2, 0xA3, 0x60, 0x04, 0xF0, 0xED, 0xFE, 0x84, 0xF8, + 0x3C, 0x00, 0x28, 0x68, 0x90, 0xF8, 0x9F, 0x16, 0xD0, 0xF8, 0xA0, 0x26, + 0x41, 0xEA, 0x02, 0x21, 0xCA, 0x17, 0xC4, 0xF8, 0x3D, 0x10, 0xC4, 0xF8, + 0x41, 0x20, 0x90, 0xF8, 0x9B, 0x16, 0xD0, 0xF8, 0x9C, 0x26, 0x00, 0xF2, + 0xE9, 0x60, 0x41, 0xEA, 0x02, 0x21, 0xCA, 0x17, 0xC4, 0xF8, 0x45, 0x10, + 0xC4, 0xF8, 0x49, 0x20, 0x01, 0x21, 0x04, 0xF0, 0xCF, 0xFE, 0x84, 0xF8, + 0x4D, 0x00, 0x28, 0x68, 0x90, 0xF8, 0xE5, 0x16, 0xD0, 0xF8, 0xE6, 0x26, + 0x41, 0xEA, 0x02, 0x21, 0xCA, 0x17, 0xC4, 0xF8, 0x4E, 0x10, 0xC4, 0xF8, + 0x52, 0x20, 0x90, 0xF8, 0xE1, 0x16, 0xD0, 0xF8, 0xE2, 0x26, 0x41, 0xEA, + 0x02, 0x21, 0xCA, 0x17, 0xC4, 0xF8, 0x56, 0x10, 0xC4, 0xF8, 0x5A, 0x20, + 0x90, 0xF8, 0xC1, 0x16, 0x84, 0xF8, 0x5E, 0x10, 0x90, 0xF8, 0xC2, 0x16, + 0x84, 0xF8, 0x5F, 0x10, 0x90, 0xF8, 0xD5, 0x16, 0xD0, 0xF8, 0xD6, 0x26, + 0x41, 0xEA, 0x02, 0x21, 0xCA, 0x17, 0x21, 0x66, 0x62, 0x66, 0x90, 0xF8, + 0xD0, 0x16, 0xD0, 0xF8, 0xD1, 0x26, 0x41, 0xEA, 0x02, 0x21, 0xCA, 0x17, + 0xA1, 0x66, 0x44, 0xF8, 0x6C, 0x2F, 0x90, 0xF8, 0x29, 0x17, 0x21, 0x71, + 0x90, 0xF8, 0x31, 0x17, 0x61, 0x71, 0x90, 0xF8, 0x39, 0x17, 0xA1, 0x71, + 0x90, 0xF8, 0x41, 0x17, 0xE1, 0x71, 0x90, 0xF8, 0x4D, 0x17, 0x21, 0x72, + 0x90, 0xF8, 0x5D, 0x17, 0x61, 0x72, 0x90, 0xF8, 0x6D, 0x17, 0xA1, 0x72, + 0x90, 0xF8, 0x11, 0x07, 0xE0, 0x72, 0x40, 0xF2, 0xFF, 0x31, 0x89, 0x48, + 0x6D, 0x3C, 0x04, 0xF0, 0x9B, 0xFE, 0x87, 0x49, 0xD1, 0xF8, 0xFC, 0x1F, + 0x81, 0x42, 0x1F, 0xD1, 0x85, 0x48, 0x00, 0x68, 0x01, 0x78, 0x84, 0xF8, + 0x79, 0x10, 0x81, 0x78, 0x84, 0xF8, 0x7A, 0x10, 0x01, 0x79, 0x84, 0xF8, + 0x7B, 0x10, 0x81, 0x79, 0x84, 0xF8, 0x7C, 0x10, 0x01, 0x7C, 0x84, 0xF8, + 0x7D, 0x10, 0x01, 0x7E, 0x84, 0xF8, 0x7E, 0x10, 0x90, 0xF8, 0x28, 0x10, + 0x84, 0xF8, 0x7F, 0x10, 0x90, 0xF8, 0x30, 0x10, 0x84, 0xF8, 0x80, 0x10, + 0xD0, 0xF8, 0x36, 0x00, 0xC4, 0xF8, 0x81, 0x00, 0x1B, 0x20, 0xC4, 0xF8, + 0x85, 0x00, 0xC4, 0xF8, 0x89, 0x60, 0x28, 0x68, 0x90, 0xF8, 0xE8, 0x07, + 0x80, 0x06, 0x01, 0xD5, 0xC4, 0xF8, 0x89, 0x70, 0x00, 0x23, 0x1A, 0x46, + 0x98, 0xF8, 0x00, 0x10, 0x48, 0x46, 0xFF, 0xF7, 0xC9, 0xF8, 0x05, 0xB0, + 0xBD, 0xE8, 0xF0, 0x83, 0x6B, 0x48, 0xAD, 0xE6, 0x2D, 0xE9, 0xFF, 0x5F, + 0x04, 0x21, 0x68, 0x46, 0x12, 0x9F, 0x04, 0xF0, 0x39, 0xFE, 0x06, 0x46, + 0x08, 0x21, 0x02, 0xA8, 0x04, 0xF0, 0x34, 0xFE, 0x00, 0x25, 0x82, 0x46, + 0x2C, 0x46, 0xA9, 0x46, 0xA8, 0x46, 0x4F, 0xF0, 0x01, 0x0B, 0x19, 0xE0, + 0x00, 0x99, 0x0B, 0xFA, 0x09, 0xF0, 0x08, 0x42, 0x10, 0xD0, 0x00, 0x22, + 0x49, 0x46, 0x0E, 0x98, 0x02, 0xF0, 0xB6, 0xFE, 0x78, 0x55, 0x00, 0x22, + 0x49, 0x46, 0x0F, 0x98, 0x02, 0xF0, 0xAC, 0xFE, 0xAA, 0x19, 0x02, 0xEB, + 0x0A, 0x01, 0x6D, 0x1C, 0x78, 0x54, 0xED, 0xB2, 0x09, 0xF1, 0x01, 0x00, + 0x00, 0xF0, 0xFF, 0x09, 0xB5, 0x42, 0xE3, 0xDB, 0x21, 0xE0, 0x42, 0x46, + 0x01, 0x20, 0x00, 0x21, 0x02, 0xF0, 0x79, 0xFC, 0xDD, 0xE9, 0x02, 0x23, + 0x10, 0x40, 0x19, 0x40, 0x08, 0x43, 0x12, 0xD0, 0x01, 0x22, 0x41, 0x46, + 0x10, 0x98, 0x02, 0xF0, 0x93, 0xFE, 0xA1, 0x19, 0x01, 0x22, 0x78, 0x54, + 0x41, 0x46, 0x11, 0x98, 0x02, 0xF0, 0x88, 0xFE, 0x04, 0xEB, 0x46, 0x02, + 0x02, 0xEB, 0x0A, 0x01, 0x64, 0x1C, 0x78, 0x54, 0xE4, 0xB2, 0x08, 0xF1, + 0x01, 0x00, 0x00, 0xF0, 0xFF, 0x08, 0x54, 0x45, 0xDB, 0xDB, 0xBD, 0xE8, + 0xFF, 0x9F, 0xF0, 0xB5, 0x89, 0xB0, 0x04, 0x46, 0x00, 0xF0, 0xF5, 0xFD, + 0x08, 0x90, 0x00, 0xF0, 0xDB, 0xFD, 0xCD, 0xE9, 0x06, 0x01, 0x04, 0x21, + 0x08, 0xA8, 0x04, 0xF0, 0xDB, 0xFD, 0x05, 0x46, 0x08, 0x21, 0x06, 0xA8, + 0x04, 0xF0, 0xD6, 0xFD, 0xA5, 0x21, 0x21, 0x70, 0x2F, 0x4F, 0x20, 0x21, + 0xA4, 0xF8, 0x01, 0x10, 0xEE, 0xB2, 0x39, 0x78, 0xC5, 0xB2, 0xE1, 0x70, + 0x2F, 0x48, 0x26, 0x71, 0x65, 0x71, 0x00, 0x68, 0x01, 0x7C, 0x21, 0x72, + 0x81, 0x7C, 0x61, 0x72, 0xC1, 0x7C, 0xA1, 0x72, 0x41, 0x7C, 0xE1, 0x72, + 0x41, 0x7C, 0x21, 0x73, 0x01, 0x7D, 0x61, 0x73, 0x40, 0x7D, 0xA0, 0x73, + 0x28, 0x48, 0x10, 0x34, 0xA0, 0xF1, 0x22, 0x01, 0xCD, 0xE9, 0x02, 0x10, + 0xA0, 0xF1, 0x3A, 0x02, 0x5A, 0x38, 0xCD, 0xE9, 0x00, 0x02, 0x04, 0x94, + 0xDD, 0xE9, 0x07, 0x30, 0x06, 0x9A, 0xFF, 0xF7, 0x69, 0xFF, 0x2B, 0x46, + 0x32, 0x46, 0x39, 0x78, 0x20, 0x20, 0xFF, 0xF7, 0x27, 0xF8, 0x09, 0xB0, + 0xF0, 0xBD, 0x2D, 0xE9, 0xFF, 0x5F, 0x04, 0x21, 0x68, 0x46, 0xDD, 0xF8, + 0x3C, 0xA0, 0x04, 0xF0, 0x99, 0xFD, 0x83, 0x46, 0x08, 0x21, 0x02, 0xA8, + 0x04, 0xF0, 0x94, 0xFD, 0x00, 0x26, 0x80, 0x46, 0x37, 0x46, 0x33, 0xE0, + 0x01, 0x20, 0x00, 0x99, 0xB8, 0x40, 0x08, 0x42, 0x2D, 0xD0, 0x00, 0x24, + 0x25, 0x46, 0x06, 0xFB, 0x08, 0xF9, 0x25, 0xE0, 0x2A, 0x46, 0x01, 0x20, + 0x00, 0x21, 0x02, 0xF0, 0xF0, 0xFB, 0xDD, 0xE9, 0x02, 0x23, 0x10, 0x40, + 0x19, 0x40, 0x08, 0x43, 0x19, 0xD0, 0x2A, 0x46, 0x31, 0x46, 0x0E, 0x98, + 0x02, 0xF0, 0x04, 0xFE, 0x0E, 0xE0, 0x00, 0x00, 0x32, 0x24, 0x10, 0x00, + 0x50, 0x24, 0x10, 0x00, 0x00, 0x39, 0x01, 0x30, 0x00, 0x10, 0x10, 0x00, + 0x54, 0x24, 0x10, 0x00, 0x00, 0x80, 0x01, 0x20, 0x8E, 0x17, 0x10, 0x00, + 0x0A, 0xEB, 0x04, 0x02, 0x64, 0x1C, 0x09, 0xF8, 0x02, 0x00, 0x6D, 0x1C, + 0x44, 0x45, 0xD7, 0xDB, 0x76, 0x1C, 0x7F, 0x1C, 0x5E, 0x45, 0xC9, 0xDB, + 0x6D, 0xE7, 0x10, 0xB5, 0x04, 0x46, 0x4F, 0xF4, 0xF1, 0x61, 0x6C, 0x48, + 0x02, 0xF0, 0x77, 0xFC, 0x6B, 0x48, 0x01, 0x78, 0x49, 0x1C, 0x01, 0x70, + 0xE0, 0x43, 0x00, 0x04, 0x00, 0x0C, 0x06, 0xD0, 0xE0, 0x07, 0x08, 0xD0, + 0xBD, 0xE8, 0x10, 0x40, 0x64, 0x48, 0x00, 0xF0, 0x9C, 0xB8, 0xBD, 0xE8, + 0x10, 0x40, 0x62, 0x48, 0xAC, 0xE5, 0xA0, 0x07, 0x04, 0xD5, 0xBD, 0xE8, + 0x10, 0x40, 0x5F, 0x48, 0x00, 0xF0, 0x49, 0xB8, 0x60, 0x07, 0x04, 0xD5, + 0xBD, 0xE8, 0x10, 0x40, 0x5B, 0x48, 0x00, 0xF0, 0x07, 0xB8, 0xA0, 0x06, + 0x03, 0xD5, 0xBD, 0xE8, 0x10, 0x40, 0x58, 0x48, 0x41, 0xE7, 0x10, 0xBD, + 0xF0, 0xB5, 0x85, 0xB0, 0x04, 0x46, 0x00, 0xF0, 0x28, 0xFB, 0x04, 0x90, + 0x00, 0xF0, 0x0E, 0xFB, 0xCD, 0xE9, 0x02, 0x01, 0x04, 0x21, 0x04, 0xA8, + 0x04, 0xF0, 0x1C, 0xFD, 0x05, 0x46, 0x08, 0x21, 0x02, 0xA8, 0x04, 0xF0, + 0x17, 0xFD, 0xA5, 0x21, 0x04, 0xF8, 0x01, 0x1B, 0x4C, 0x4F, 0x04, 0x21, + 0x24, 0xF8, 0x02, 0x1B, 0x39, 0x78, 0xEE, 0xB2, 0x04, 0xF8, 0x01, 0x1B, + 0xC5, 0xB2, 0x04, 0xF8, 0x04, 0x6B, 0x48, 0x48, 0x04, 0xF8, 0x03, 0x5C, + 0x00, 0x68, 0x81, 0x78, 0x04, 0xF8, 0x08, 0x1B, 0xC0, 0x78, 0x04, 0xF8, + 0x07, 0x0C, 0x44, 0x48, 0xCD, 0xE9, 0x00, 0x04, 0xDD, 0xE9, 0x03, 0x30, + 0x02, 0x9A, 0xFF, 0xF7, 0x56, 0xFF, 0x2B, 0x46, 0x32, 0x46, 0x39, 0x78, + 0x04, 0x20, 0xFE, 0xF7, 0x75, 0xFF, 0x05, 0xB0, 0xF0, 0xBD, 0xF0, 0xB5, + 0x85, 0xB0, 0x04, 0x46, 0x4F, 0xF4, 0xF1, 0x61, 0x02, 0xF0, 0x0D, 0xFC, + 0x00, 0xF0, 0xE9, 0xFA, 0x04, 0x90, 0x00, 0xF0, 0xCF, 0xFA, 0xCD, 0xE9, + 0x02, 0x01, 0x36, 0x48, 0x00, 0x68, 0x90, 0xF8, 0x7E, 0x07, 0x40, 0x07, + 0x03, 0xD5, 0x04, 0x98, 0xF4, 0xF7, 0x64, 0xFB, 0x04, 0x90, 0x04, 0x21, + 0x04, 0xA8, 0x04, 0xF0, 0xD3, 0xFC, 0x05, 0x46, 0x08, 0x21, 0x02, 0xA8, + 0x04, 0xF0, 0xCE, 0xFC, 0xA5, 0x21, 0x04, 0xF8, 0x01, 0x1B, 0x28, 0x4F, + 0x02, 0x21, 0x24, 0xF8, 0x02, 0x1B, 0x39, 0x78, 0xEE, 0xB2, 0x04, 0xF8, + 0x01, 0x1B, 0xC5, 0xB2, 0x04, 0xF8, 0x04, 0x6B, 0x23, 0x48, 0x04, 0xF8, + 0x03, 0x5C, 0x00, 0x68, 0x01, 0x78, 0x04, 0xF8, 0x08, 0x1B, 0x40, 0x78, + 0x04, 0xF8, 0x07, 0x0C, 0x21, 0x48, 0xCD, 0xE9, 0x00, 0x04, 0xDD, 0xE9, + 0x03, 0x30, 0x02, 0x9A, 0xFF, 0xF7, 0x0D, 0xFF, 0x2B, 0x46, 0x32, 0x46, + 0x39, 0x78, 0x02, 0x20, 0xFE, 0xF7, 0x2C, 0xFF, 0xB5, 0xE7, 0x30, 0xB4, + 0xA5, 0x21, 0x01, 0x70, 0x01, 0x21, 0xA0, 0xF8, 0x01, 0x10, 0x13, 0x49, + 0x4F, 0xF0, 0xFF, 0x32, 0x09, 0x78, 0xC1, 0x70, 0x82, 0x60, 0x12, 0x0C, + 0x82, 0x81, 0x10, 0x4A, 0x12, 0x68, 0x92, 0xF8, 0x20, 0x30, 0x55, 0x2B, + 0x08, 0xD1, 0x92, 0xF8, 0x23, 0x30, 0x1C, 0x04, 0x92, 0xF8, 0x21, 0x30, + 0x44, 0xEA, 0x03, 0x24, 0x1C, 0x43, 0x84, 0x60, 0x92, 0xF8, 0x24, 0x30, + 0x55, 0x2B, 0x02, 0xD1, 0x92, 0xF8, 0x25, 0x20, 0x82, 0x81, 0x00, 0x23, + 0x30, 0xBC, 0x1A, 0x46, 0x01, 0x20, 0xFE, 0xF7, 0x01, 0xBF, 0x00, 0x00, + 0x00, 0x80, 0x01, 0x20, 0x32, 0x24, 0x10, 0x00, 0x54, 0x24, 0x10, 0x00, + 0x80, 0x13, 0x10, 0x00, 0x50, 0x24, 0x10, 0x00, 0x40, 0x10, 0x10, 0x00, + 0x30, 0xB5, 0xC1, 0x49, 0x0A, 0x68, 0x92, 0xF8, 0x7D, 0x37, 0x02, 0x78, + 0x63, 0xF3, 0x01, 0x02, 0x02, 0x70, 0x0B, 0x68, 0x93, 0xF8, 0x7D, 0x37, + 0x9B, 0x08, 0x63, 0xF3, 0x82, 0x02, 0x02, 0x70, 0x0B, 0x68, 0x93, 0xF8, + 0x7D, 0x37, 0xDB, 0x08, 0x63, 0xF3, 0xC3, 0x02, 0x02, 0x70, 0x0B, 0x68, + 0x93, 0xF8, 0x7D, 0x37, 0x1B, 0x09, 0x63, 0xF3, 0x04, 0x12, 0x02, 0x70, + 0x0B, 0x68, 0x93, 0xF8, 0x7D, 0x37, 0x5B, 0x09, 0x63, 0xF3, 0x45, 0x12, + 0x02, 0x70, 0x0B, 0x68, 0x93, 0xF8, 0x7D, 0x37, 0x9B, 0x09, 0x63, 0xF3, + 0x86, 0x12, 0x02, 0x70, 0x0B, 0x68, 0x93, 0xF8, 0x7D, 0x37, 0xDB, 0x09, + 0x63, 0xF3, 0xC7, 0x12, 0x02, 0x70, 0x0A, 0x68, 0x92, 0xF8, 0xA0, 0x37, + 0x42, 0x78, 0x63, 0xF3, 0x01, 0x02, 0x42, 0x70, 0x0B, 0x68, 0x93, 0xF8, + 0xA0, 0x37, 0x9B, 0x08, 0x63, 0xF3, 0x82, 0x02, 0x42, 0x70, 0x0B, 0x68, + 0x93, 0xF8, 0xA0, 0x37, 0xDB, 0x08, 0x63, 0xF3, 0xC3, 0x02, 0x42, 0x70, + 0x0B, 0x68, 0x93, 0xF8, 0xA0, 0x37, 0x1B, 0x09, 0x63, 0xF3, 0x04, 0x12, + 0x42, 0x70, 0x0B, 0x68, 0x93, 0xF8, 0xA0, 0x37, 0x5B, 0x09, 0x63, 0xF3, + 0x45, 0x12, 0x42, 0x70, 0x0B, 0x68, 0x93, 0xF8, 0xA0, 0x37, 0x9B, 0x09, + 0x63, 0xF3, 0x86, 0x12, 0x42, 0x70, 0x0B, 0x68, 0x93, 0xF8, 0xA0, 0x37, + 0xDB, 0x09, 0x63, 0xF3, 0xC7, 0x12, 0x42, 0x70, 0x0A, 0x68, 0x92, 0xF8, + 0xC0, 0x24, 0x93, 0x08, 0x82, 0x78, 0x63, 0xF3, 0x04, 0x12, 0x82, 0x70, + 0x0B, 0x68, 0x93, 0xF8, 0xC0, 0x34, 0xDB, 0x08, 0x63, 0xF3, 0x45, 0x12, + 0x82, 0x70, 0x0B, 0x68, 0x93, 0xF8, 0xC2, 0x34, 0x1B, 0x09, 0x63, 0xF3, + 0x87, 0x12, 0x82, 0x70, 0x0B, 0x68, 0x93, 0xF8, 0xC3, 0x34, 0x1C, 0x09, + 0xC3, 0x78, 0x64, 0xF3, 0x01, 0x03, 0xC3, 0x70, 0x0C, 0x68, 0x94, 0xF8, + 0xC1, 0x54, 0xC5, 0x71, 0x94, 0xF8, 0xC0, 0x44, 0x64, 0x08, 0x64, 0xF3, + 0xC3, 0x02, 0x82, 0x70, 0x0A, 0x68, 0x92, 0xF8, 0xC2, 0x44, 0x04, 0xF0, + 0x0F, 0x04, 0x04, 0x71, 0x92, 0xF8, 0xC3, 0x24, 0x62, 0xF3, 0x84, 0x03, + 0xC3, 0x70, 0x42, 0x79, 0x22, 0xF0, 0x7F, 0x02, 0x42, 0x71, 0x4F, 0xF6, + 0x05, 0x22, 0x82, 0x81, 0x09, 0x68, 0xB1, 0xF8, 0xC8, 0x24, 0xC2, 0x81, + 0xB1, 0xF8, 0xCA, 0x24, 0x02, 0x82, 0xB1, 0xF8, 0xCC, 0x24, 0x42, 0x82, + 0xB1, 0xF8, 0xCE, 0x24, 0x82, 0x82, 0xB1, 0xF8, 0xD0, 0x24, 0xC2, 0x82, + 0xB1, 0xF8, 0xD2, 0x24, 0x02, 0x83, 0xB1, 0xF8, 0xD4, 0x24, 0x42, 0x83, + 0xB1, 0xF8, 0xD6, 0x24, 0x82, 0x83, 0xB1, 0xF8, 0xC4, 0x24, 0x02, 0x81, + 0xB1, 0xF8, 0xC6, 0x14, 0x41, 0x81, 0x30, 0xBD, 0x10, 0xB5, 0x63, 0x48, + 0xFF, 0xF7, 0x3E, 0xFF, 0x61, 0x48, 0x03, 0xF0, 0x11, 0xFA, 0x00, 0xF0, + 0xB9, 0xF9, 0x00, 0xF0, 0xC7, 0xF8, 0x00, 0xF0, 0x9B, 0xFB, 0x5E, 0x48, + 0x00, 0x21, 0x41, 0x70, 0x01, 0x70, 0x81, 0x60, 0x10, 0xBD, 0x00, 0x21, + 0x01, 0x60, 0x41, 0x60, 0x81, 0x60, 0xC1, 0x60, 0x70, 0x47, 0xF0, 0xB5, + 0x58, 0x4E, 0x00, 0x23, 0x15, 0x46, 0x4F, 0xF4, 0x00, 0x4C, 0x77, 0x0C, + 0x12, 0xE0, 0x31, 0xF9, 0x13, 0x40, 0x31, 0xF9, 0x15, 0xE0, 0x74, 0x44, + 0x64, 0x45, 0x02, 0xDB, 0x20, 0xF8, 0x13, 0x70, 0x06, 0xE0, 0xB4, 0x42, + 0x02, 0xDA, 0x20, 0xF8, 0x13, 0x60, 0x01, 0xE0, 0x20, 0xF8, 0x13, 0x40, + 0x5B, 0x1C, 0x6D, 0x1C, 0x93, 0x42, 0xEA, 0xDB, 0xF0, 0xBD, 0x70, 0xB5, + 0x06, 0x46, 0x48, 0x4C, 0x49, 0x4D, 0x08, 0xE0, 0x55, 0xF8, 0x21, 0x10, + 0x30, 0x46, 0x88, 0x47, 0x00, 0x28, 0x06, 0xD0, 0x60, 0x68, 0x40, 0x1C, + 0x60, 0x60, 0x61, 0x68, 0x07, 0x29, 0xF3, 0xDB, 0x01, 0x20, 0x70, 0xBD, + 0x10, 0xB5, 0x04, 0x46, 0x00, 0x79, 0x18, 0xB9, 0x20, 0x7A, 0x08, 0xB9, + 0xA0, 0x79, 0xE8, 0xB1, 0x3A, 0x48, 0x44, 0x21, 0x44, 0x38, 0x02, 0xF0, + 0xA2, 0xFA, 0x38, 0x49, 0x1D, 0xCC, 0x54, 0x39, 0x81, 0xE8, 0x1D, 0x00, + 0x08, 0x46, 0x00, 0xF0, 0x83, 0xF9, 0x34, 0x48, 0x54, 0x38, 0x00, 0xF0, + 0x6D, 0xFB, 0x32, 0x48, 0x54, 0x38, 0x00, 0xF0, 0xE1, 0xF8, 0x31, 0x49, + 0x00, 0x20, 0x48, 0x60, 0x2E, 0x48, 0x54, 0x38, 0xFF, 0xF7, 0xC9, 0xFF, + 0x00, 0x20, 0x10, 0xBD, 0x01, 0x20, 0x10, 0xBD, 0x2D, 0xE9, 0xF0, 0x41, + 0x29, 0x4E, 0x2A, 0x4C, 0xA6, 0xF1, 0x44, 0x06, 0x05, 0x00, 0x4F, 0xF0, + 0x00, 0x07, 0xA6, 0xF1, 0x10, 0x08, 0x0E, 0xD0, 0x03, 0xF0, 0x3E, 0xFB, + 0xFF, 0xF7, 0x7E, 0xFF, 0x26, 0x48, 0x01, 0x78, 0x00, 0x79, 0x03, 0xF0, + 0x85, 0xFB, 0x86, 0xF8, 0x42, 0x50, 0xA0, 0x68, 0xF0, 0x63, 0x67, 0x60, + 0x15, 0xE0, 0x20, 0x48, 0x61, 0x68, 0x1C, 0x30, 0x50, 0xF8, 0x21, 0x10, + 0x1A, 0x48, 0x54, 0x38, 0x88, 0x47, 0x01, 0x28, 0x13, 0xD1, 0x60, 0x68, + 0x40, 0x1C, 0x60, 0x60, 0x16, 0x48, 0x54, 0x38, 0xFF, 0xF7, 0x99, 0xFF, + 0x01, 0x28, 0x0A, 0xD1, 0x67, 0x60, 0xA0, 0x68, 0xF0, 0x63, 0x12, 0x48, + 0xD8, 0xF8, 0x00, 0x10, 0x44, 0x38, 0x88, 0x47, 0xA0, 0x68, 0x40, 0x1C, + 0xA0, 0x60, 0xBD, 0xE8, 0xF0, 0x81, 0x01, 0x20, 0x70, 0x47, 0x10, 0xB5, + 0x02, 0xF0, 0xE4, 0xFE, 0x08, 0xB1, 0x01, 0x20, 0x10, 0xBD, 0xAF, 0xF2, + 0x87, 0x00, 0x02, 0xF0, 0xFD, 0xFE, 0x00, 0x20, 0x10, 0xBD, 0x05, 0x48, + 0x10, 0xB5, 0x00, 0x68, 0x90, 0xF8, 0x30, 0x00, 0x40, 0x07, 0x01, 0xD5, + 0x02, 0xF0, 0xDA, 0xFE, 0x01, 0x20, 0x10, 0xBD, 0x50, 0x24, 0x10, 0x00, + 0xD8, 0x51, 0x10, 0x00, 0x34, 0x24, 0x10, 0x00, 0x00, 0x80, 0xFF, 0xFF, + 0x24, 0x1E, 0x01, 0x00, 0xC8, 0x52, 0x10, 0x00, 0x5E, 0x48, 0x5F, 0x49, + 0x00, 0x68, 0x90, 0xF8, 0x11, 0x01, 0x00, 0xF0, 0x03, 0x00, 0x48, 0x70, + 0x70, 0x47, 0x5A, 0x48, 0x01, 0x68, 0x08, 0x79, 0x4A, 0x79, 0x4B, 0x7A, + 0x40, 0xEA, 0x02, 0x20, 0x8A, 0x79, 0x40, 0xEA, 0x02, 0x40, 0xCA, 0x79, + 0x40, 0xEA, 0x02, 0x60, 0x0A, 0x7A, 0x42, 0xEA, 0x03, 0x22, 0x8B, 0x7A, + 0xC9, 0x7A, 0x42, 0xEA, 0x03, 0x42, 0x42, 0xEA, 0x01, 0x61, 0x70, 0x47, + 0x10, 0xB5, 0x04, 0x46, 0x40, 0x21, 0x02, 0xF0, 0x02, 0xFA, 0x4E, 0x48, + 0x01, 0xC4, 0x4E, 0x48, 0x01, 0xC4, 0x01, 0x20, 0x20, 0x60, 0xFF, 0xF7, + 0xDC, 0xFF, 0xC4, 0xE9, 0x02, 0x01, 0x00, 0x20, 0x20, 0x74, 0x46, 0x48, + 0x00, 0x68, 0x90, 0xF8, 0x7D, 0x17, 0x61, 0x74, 0x90, 0xF8, 0x80, 0x17, + 0xA1, 0x74, 0x90, 0xF8, 0x81, 0x17, 0xE1, 0x74, 0x90, 0xF8, 0x82, 0x17, + 0x21, 0x75, 0x90, 0xF8, 0x16, 0x11, 0x61, 0x75, 0x90, 0xF8, 0x84, 0x17, + 0xA1, 0x75, 0x90, 0xF8, 0x17, 0x11, 0x01, 0xF0, 0x0F, 0x01, 0x21, 0x76, + 0x90, 0xF8, 0x19, 0x11, 0x01, 0xF0, 0x3F, 0x01, 0x61, 0x76, 0x90, 0xF8, + 0x18, 0x11, 0xC1, 0xF3, 0x01, 0x11, 0xA1, 0x76, 0x90, 0xF8, 0x18, 0x11, + 0x89, 0x09, 0xE1, 0x76, 0x90, 0xF8, 0x18, 0x11, 0x01, 0xF0, 0x07, 0x01, + 0x21, 0x77, 0x90, 0xF8, 0x19, 0x11, 0x89, 0x09, 0x61, 0x77, 0x32, 0x49, + 0x09, 0x68, 0x49, 0x78, 0xE1, 0x77, 0x90, 0xF8, 0x7F, 0x17, 0xA1, 0x77, + 0x4F, 0xF4, 0x00, 0x61, 0x61, 0x85, 0x90, 0xF8, 0x7E, 0x17, 0xE0, 0x6A, + 0x61, 0xF3, 0x82, 0x00, 0x20, 0xF0, 0x18, 0x00, 0x40, 0xF0, 0x02, 0x00, + 0xE0, 0x62, 0x10, 0xBD, 0x10, 0xB5, 0x80, 0x79, 0x00, 0x28, 0x0B, 0xD0, + 0x22, 0x4C, 0x00, 0x20, 0x20, 0x70, 0x25, 0x48, 0xFF, 0xF7, 0xA0, 0xFF, + 0x23, 0x48, 0x08, 0x21, 0x10, 0x30, 0x04, 0xF0, 0x5B, 0xFA, 0xA0, 0x70, + 0x10, 0xBD, 0x10, 0xB5, 0x1A, 0x4A, 0x80, 0x79, 0x12, 0x68, 0x01, 0x28, + 0x02, 0xF5, 0x89, 0x72, 0x09, 0xD1, 0x18, 0x4B, 0x19, 0x4C, 0x18, 0x78, + 0x9B, 0x78, 0x43, 0x43, 0x04, 0xEB, 0x43, 0x03, 0x4B, 0x60, 0x10, 0x5C, + 0xC8, 0x76, 0x10, 0xBD, 0x10, 0xB5, 0x81, 0x79, 0x39, 0xB1, 0x15, 0x49, + 0xFF, 0xF7, 0xE7, 0xFF, 0x13, 0x48, 0x02, 0xF0, 0xF5, 0xFC, 0x00, 0x20, + 0x10, 0xBD, 0x01, 0x20, 0x10, 0xBD, 0x0C, 0x4A, 0x10, 0xB5, 0x11, 0x78, + 0x53, 0x78, 0x99, 0x42, 0x0B, 0xD2, 0x49, 0x1C, 0x11, 0x70, 0x0C, 0x49, + 0xFF, 0xF7, 0xD5, 0xFF, 0x0A, 0x48, 0xC1, 0x7E, 0x40, 0x68, 0x02, 0xF0, + 0xAB, 0xFC, 0x00, 0x20, 0x10, 0xBD, 0x08, 0x49, 0x04, 0x48, 0x48, 0x60, + 0x01, 0x20, 0x10, 0xBD, 0x50, 0x24, 0x10, 0x00, 0x40, 0x24, 0x10, 0x00, + 0x21, 0xD6, 0x00, 0x00, 0x38, 0xA8, 0x01, 0x20, 0x54, 0x24, 0x10, 0x00, + 0xF8, 0x51, 0x10, 0x00, 0x94, 0x51, 0x10, 0x00, 0xF9, 0x48, 0x01, 0x68, + 0x08, 0x79, 0x4A, 0x79, 0x4B, 0x7A, 0x40, 0xEA, 0x02, 0x20, 0x8A, 0x79, + 0x40, 0xEA, 0x02, 0x40, 0xCA, 0x79, 0x40, 0xEA, 0x02, 0x60, 0x0A, 0x7A, + 0x42, 0xEA, 0x03, 0x22, 0x8B, 0x7A, 0xC9, 0x7A, 0x42, 0xEA, 0x03, 0x42, + 0x42, 0xEA, 0x01, 0x61, 0x70, 0x47, 0xEE, 0x48, 0x00, 0x68, 0x01, 0x7B, + 0x42, 0x7B, 0x41, 0xEA, 0x02, 0x21, 0x82, 0x7B, 0xC0, 0x7B, 0x41, 0xEA, + 0x02, 0x41, 0x41, 0xEA, 0x00, 0x60, 0x70, 0x47, 0x3E, 0xB5, 0xFF, 0xF7, + 0xF0, 0xFF, 0x02, 0x90, 0xFF, 0xF7, 0xD6, 0xFF, 0xCD, 0xE9, 0x00, 0x01, + 0x04, 0x21, 0x02, 0xA8, 0x04, 0xF0, 0xE4, 0xF9, 0xE2, 0x4C, 0x08, 0x21, + 0xA0, 0x70, 0x68, 0x46, 0x04, 0xF0, 0xDE, 0xF9, 0xE0, 0x70, 0x01, 0x20, + 0x60, 0x71, 0xDD, 0x48, 0x00, 0x68, 0x90, 0xF8, 0x10, 0x11, 0xC9, 0x07, + 0x03, 0xD1, 0xDC, 0x49, 0x90, 0xF8, 0x81, 0x07, 0x88, 0x70, 0x3E, 0xBD, + 0xD8, 0x49, 0x00, 0x20, 0x48, 0x70, 0x70, 0x47, 0x10, 0xB5, 0x04, 0x46, + 0x40, 0x21, 0x02, 0xF0, 0x0E, 0xF9, 0xD6, 0x48, 0x20, 0x60, 0xD6, 0x48, + 0x60, 0x60, 0xFF, 0xF7, 0xC4, 0xFF, 0x44, 0xF8, 0x08, 0x0F, 0xFF, 0xF7, + 0xA9, 0xFF, 0xC4, 0xE9, 0x02, 0x01, 0xCD, 0x48, 0x00, 0x68, 0x90, 0xF8, + 0x7D, 0x17, 0x61, 0x74, 0x90, 0xF8, 0x80, 0x17, 0xA1, 0x74, 0xCB, 0x49, + 0x89, 0x78, 0xE1, 0x74, 0x90, 0xF8, 0x82, 0x17, 0x21, 0x75, 0x90, 0xF8, + 0x83, 0x17, 0x61, 0x75, 0x90, 0xF8, 0x84, 0x17, 0xA1, 0x75, 0x90, 0xF8, + 0x85, 0x17, 0x01, 0xF0, 0x0F, 0x01, 0x21, 0x76, 0x90, 0xF8, 0x87, 0x17, + 0x01, 0xF0, 0x3F, 0x01, 0x61, 0x76, 0x90, 0xF8, 0x86, 0x17, 0xC1, 0xF3, + 0x01, 0x11, 0xA1, 0x76, 0x90, 0xF8, 0x86, 0x17, 0x89, 0x09, 0xE1, 0x76, + 0x90, 0xF8, 0x86, 0x17, 0x01, 0xF0, 0x07, 0x01, 0x21, 0x77, 0x90, 0xF8, + 0x87, 0x17, 0x89, 0x09, 0x61, 0x77, 0xBA, 0x49, 0x09, 0x68, 0x49, 0x78, + 0xE1, 0x77, 0x90, 0xF8, 0x7F, 0x17, 0xA1, 0x77, 0xB0, 0xF8, 0x2C, 0x17, + 0x61, 0x85, 0x90, 0xF8, 0x7E, 0x27, 0x54, 0xF8, 0x2C, 0x1F, 0x62, 0xF3, + 0x82, 0x01, 0x44, 0xF8, 0x34, 0x19, 0x90, 0xF8, 0x7E, 0x27, 0x52, 0x07, + 0x02, 0xD5, 0x41, 0xF0, 0x18, 0x01, 0x61, 0x63, 0x00, 0x21, 0x21, 0x76, + 0x90, 0xF8, 0x88, 0x07, 0x00, 0xF0, 0x03, 0x01, 0xA6, 0x48, 0x01, 0x70, + 0x01, 0x21, 0x01, 0x71, 0x10, 0xBD, 0x2D, 0xE9, 0xF0, 0x41, 0x05, 0x46, + 0x0C, 0x46, 0x08, 0x46, 0xFF, 0xF7, 0x94, 0xFF, 0x28, 0x79, 0x00, 0x23, + 0x9E, 0x4A, 0x9F, 0x49, 0x08, 0x28, 0x72, 0xD2, 0xDF, 0xE8, 0x00, 0xF0, + 0x71, 0x04, 0x0E, 0x15, 0x55, 0x55, 0x15, 0x86, 0xA8, 0x7B, 0x01, 0x28, + 0x69, 0xD1, 0x10, 0x68, 0x90, 0xF8, 0x88, 0x07, 0xC0, 0xF3, 0x81, 0x00, + 0x08, 0x70, 0x62, 0xE0, 0x84, 0xF8, 0x20, 0x30, 0xA8, 0x7B, 0x01, 0x28, + 0x5D, 0xD1, 0x0B, 0x70, 0x5B, 0xE0, 0x10, 0x68, 0x90, 0xF8, 0x89, 0x67, + 0x66, 0x77, 0x90, 0xF8, 0x8A, 0x67, 0xA6, 0x77, 0x90, 0xF8, 0x8B, 0x67, + 0x06, 0xF0, 0x0F, 0x06, 0x84, 0xF8, 0x20, 0x60, 0x90, 0xF8, 0x8D, 0x67, + 0x06, 0xF0, 0x3F, 0x06, 0x84, 0xF8, 0x21, 0x60, 0x90, 0xF8, 0x8C, 0x67, + 0xC6, 0xF3, 0x01, 0x16, 0x84, 0xF8, 0x22, 0x60, 0x90, 0xF8, 0x8C, 0x67, + 0xB6, 0x09, 0x84, 0xF8, 0x23, 0x60, 0x90, 0xF8, 0x8C, 0x67, 0x06, 0xF0, + 0x07, 0x06, 0x84, 0xF8, 0x24, 0x60, 0x90, 0xF8, 0x8D, 0x67, 0xB6, 0x09, + 0x84, 0xF8, 0x25, 0x60, 0x81, 0x4E, 0x36, 0x68, 0xF6, 0x78, 0x84, 0xF8, + 0x27, 0x60, 0x0B, 0x70, 0x66, 0x6B, 0x26, 0xF0, 0x18, 0x06, 0x66, 0x63, + 0x2F, 0x79, 0x06, 0x2F, 0x07, 0xD1, 0x90, 0xF8, 0x81, 0x07, 0xE0, 0x76, + 0x84, 0xF8, 0x20, 0x30, 0x26, 0xF0, 0x04, 0x00, 0x60, 0x63, 0x0B, 0x71, + 0x1B, 0xE0, 0x10, 0x68, 0x90, 0xF8, 0x81, 0x67, 0xE6, 0x76, 0x84, 0xF8, + 0x20, 0x30, 0x66, 0x6B, 0x0B, 0x70, 0x26, 0xF0, 0x14, 0x06, 0x66, 0x63, + 0x0B, 0x71, 0x2B, 0x79, 0x05, 0x2B, 0x0C, 0xD1, 0x90, 0xF8, 0x20, 0x37, + 0x23, 0x77, 0x90, 0xF8, 0x22, 0x37, 0x03, 0xF0, 0x0F, 0x03, 0x84, 0xF8, + 0x26, 0x30, 0x90, 0xF8, 0x23, 0x07, 0x00, 0x01, 0x60, 0x86, 0x01, 0x20, + 0x48, 0x71, 0x28, 0x79, 0x04, 0x28, 0x0D, 0xD0, 0x05, 0x28, 0x0B, 0xD0, + 0x10, 0x68, 0x94, 0xF8, 0x20, 0x20, 0x90, 0xF8, 0x85, 0x07, 0x00, 0xF0, + 0x0F, 0x00, 0x40, 0x1C, 0x52, 0x1C, 0xB0, 0xFB, 0xF2, 0xF0, 0x48, 0x71, + 0xBD, 0xE8, 0xF0, 0x81, 0x4F, 0xF6, 0xFF, 0x70, 0xA0, 0x60, 0x10, 0x68, + 0x90, 0xF8, 0x16, 0x61, 0x66, 0x77, 0x2E, 0x7B, 0xE6, 0x76, 0x90, 0xF8, + 0x19, 0x61, 0x06, 0xF0, 0x3F, 0x06, 0x84, 0xF8, 0x21, 0x60, 0x90, 0xF8, + 0x18, 0x61, 0xC6, 0xF3, 0x01, 0x16, 0x84, 0xF8, 0x22, 0x60, 0x90, 0xF8, + 0x18, 0x61, 0xB6, 0x09, 0x84, 0xF8, 0x23, 0x60, 0x90, 0xF8, 0x18, 0x01, + 0x00, 0xF0, 0x07, 0x00, 0x84, 0xF8, 0x24, 0x00, 0x6B, 0xE7, 0xF8, 0xB5, + 0x4D, 0x4F, 0x02, 0x26, 0x03, 0x28, 0x39, 0x78, 0x25, 0xD0, 0x01, 0x22, + 0x04, 0x28, 0x05, 0xD0, 0x05, 0x28, 0x03, 0xD0, 0x06, 0x28, 0x03, 0xD0, + 0x01, 0x29, 0x1E, 0xD0, 0x3A, 0x70, 0x00, 0xE0, 0x3E, 0x70, 0xFF, 0xF7, + 0xA0, 0xFE, 0x84, 0x46, 0xFF, 0xF7, 0x86, 0xFE, 0x0D, 0x46, 0x04, 0x46, + 0x39, 0x78, 0x00, 0x20, 0x02, 0x29, 0x11, 0xD0, 0x39, 0x49, 0x40, 0x4F, + 0x09, 0x68, 0x91, 0xF8, 0x7E, 0x17, 0x49, 0x07, 0x10, 0xD5, 0x60, 0x46, + 0xF3, 0xF7, 0x16, 0xFF, 0x01, 0x46, 0x22, 0x46, 0x2B, 0x46, 0x00, 0x96, + 0x0C, 0xE0, 0x02, 0x29, 0xE2, 0xD1, 0xF8, 0xBD, 0x00, 0x90, 0x22, 0x46, + 0x2B, 0x46, 0x61, 0x46, 0x36, 0x48, 0x04, 0xE0, 0x22, 0x46, 0x2B, 0x46, + 0x61, 0x46, 0x00, 0x90, 0x38, 0x46, 0x02, 0xF0, 0x37, 0xF9, 0xF8, 0xBD, + 0x10, 0xB5, 0x04, 0x46, 0x00, 0x79, 0x58, 0xB1, 0x30, 0x49, 0x20, 0x46, + 0xFF, 0xF7, 0x05, 0xFF, 0x20, 0x79, 0xFF, 0xF7, 0xB8, 0xFF, 0x2D, 0x48, + 0x02, 0xF0, 0x1E, 0xFB, 0x00, 0x20, 0x10, 0xBD, 0x01, 0x20, 0x10, 0xBD, + 0x70, 0x47, 0x2D, 0xE9, 0xF0, 0x41, 0x20, 0x4E, 0x00, 0x24, 0x22, 0x4F, + 0x30, 0x78, 0x41, 0x1C, 0xCD, 0xB2, 0x71, 0x78, 0x49, 0x1C, 0xCB, 0xB2, + 0x31, 0x46, 0x73, 0x70, 0xCA, 0x78, 0x89, 0x78, 0x83, 0x42, 0x07, 0xD8, + 0x4A, 0x43, 0x5A, 0x43, 0x07, 0xEB, 0x42, 0x00, 0x00, 0x21, 0x02, 0xF0, + 0xDD, 0xFA, 0x24, 0xE0, 0x30, 0x79, 0x1D, 0x4C, 0x01, 0x28, 0x10, 0xD0, + 0x27, 0x60, 0x84, 0xF8, 0x40, 0x50, 0x02, 0xF0, 0x7B, 0xFE, 0x84, 0xF8, + 0x41, 0x00, 0x73, 0x79, 0x01, 0x2B, 0x15, 0xD0, 0xB0, 0x78, 0xF1, 0x78, + 0x48, 0x43, 0x68, 0x43, 0x85, 0xB2, 0x00, 0x20, 0x0C, 0xE0, 0x0D, 0x48, + 0xFF, 0xF7, 0xCE, 0xFF, 0x20, 0x60, 0xEA, 0xE7, 0x21, 0x68, 0x31, 0xF8, + 0x10, 0x20, 0x5A, 0x43, 0x21, 0xF8, 0x10, 0x20, 0x40, 0x1C, 0x80, 0xB2, + 0xA8, 0x42, 0xF5, 0xD3, 0x01, 0x24, 0x20, 0x46, 0x4C, 0xE7, 0x00, 0x00, + 0x50, 0x24, 0x10, 0x00, 0x43, 0x24, 0x10, 0x00, 0x6C, 0x24, 0x10, 0x00, + 0x21, 0xD6, 0x00, 0x00, 0x38, 0xA9, 0x01, 0x20, 0x54, 0x24, 0x10, 0x00, + 0x35, 0x24, 0x10, 0x00, 0x40, 0x10, 0x10, 0x00, 0x80, 0x13, 0x10, 0x00, + 0x38, 0x52, 0x10, 0x00, 0x94, 0x51, 0x10, 0x00, 0xFB, 0x49, 0x01, 0x20, + 0xC8, 0x70, 0x70, 0x47, 0xFA, 0x48, 0x01, 0x68, 0x08, 0x79, 0x4A, 0x79, + 0x4B, 0x7A, 0x40, 0xEA, 0x02, 0x20, 0x8A, 0x79, 0x40, 0xEA, 0x02, 0x40, + 0xCA, 0x79, 0x40, 0xEA, 0x02, 0x60, 0x0A, 0x7A, 0x42, 0xEA, 0x03, 0x22, + 0x8B, 0x7A, 0xC9, 0x7A, 0x42, 0xEA, 0x03, 0x42, 0x42, 0xEA, 0x01, 0x61, + 0x70, 0x47, 0xEF, 0x48, 0x00, 0x68, 0x01, 0x7B, 0x42, 0x7B, 0x41, 0xEA, + 0x02, 0x21, 0x82, 0x7B, 0xC0, 0x7B, 0x41, 0xEA, 0x02, 0x41, 0x41, 0xEA, + 0x00, 0x60, 0x70, 0x47, 0x3E, 0xB5, 0x00, 0x7A, 0x00, 0x28, 0x11, 0xD0, + 0xFF, 0xF7, 0xED, 0xFF, 0x02, 0x90, 0xFF, 0xF7, 0xD3, 0xFF, 0xCD, 0xE9, + 0x00, 0x01, 0x04, 0x21, 0x02, 0xA8, 0x03, 0xF0, 0xD3, 0xFF, 0xE0, 0x4C, + 0x08, 0x21, 0x20, 0x70, 0x68, 0x46, 0x03, 0xF0, 0xCD, 0xFF, 0x60, 0x70, + 0x3E, 0xBD, 0x10, 0xB5, 0x04, 0x46, 0x50, 0x21, 0x01, 0xF0, 0x0D, 0xFF, + 0xDB, 0x48, 0x20, 0x60, 0xDB, 0x48, 0x60, 0x60, 0xFF, 0xF7, 0xD1, 0xFF, + 0xA0, 0x60, 0x14, 0x34, 0xFF, 0xF7, 0xB6, 0xFF, 0x44, 0xE9, 0x01, 0x01, + 0xD4, 0x48, 0x00, 0x22, 0x22, 0x71, 0x00, 0x68, 0xB0, 0xF8, 0xA2, 0x17, + 0xE1, 0x80, 0xB0, 0xF8, 0xA4, 0x17, 0x21, 0x81, 0xB0, 0xF8, 0xA6, 0x17, + 0x61, 0x81, 0x90, 0xF8, 0xAB, 0x17, 0x21, 0x73, 0x90, 0xF8, 0xAC, 0x17, + 0x01, 0xF0, 0x0F, 0x01, 0xA1, 0x73, 0x90, 0xF8, 0xAE, 0x17, 0x01, 0xF0, + 0x3F, 0x01, 0xE1, 0x73, 0x90, 0xF8, 0xAD, 0x17, 0xC1, 0xF3, 0x01, 0x11, + 0x21, 0x74, 0x90, 0xF8, 0xAD, 0x17, 0x89, 0x09, 0x61, 0x74, 0x90, 0xF8, + 0xAD, 0x17, 0x01, 0xF0, 0x07, 0x01, 0xA1, 0x74, 0x90, 0xF8, 0xAE, 0x17, + 0x89, 0x09, 0xE1, 0x74, 0x90, 0xF8, 0xB0, 0x17, 0x01, 0xF0, 0x3F, 0x01, + 0x21, 0x75, 0x90, 0xF8, 0xAF, 0x17, 0xC1, 0xF3, 0x01, 0x11, 0x61, 0x75, + 0x90, 0xF8, 0xAF, 0x17, 0x89, 0x09, 0xA1, 0x75, 0x90, 0xF8, 0xAF, 0x17, + 0x01, 0xF0, 0x07, 0x01, 0xE1, 0x75, 0x90, 0xF8, 0xB0, 0x17, 0x89, 0x09, + 0x21, 0x76, 0x90, 0xF8, 0xA8, 0x17, 0x61, 0x76, 0xB4, 0x49, 0x09, 0x68, + 0x4B, 0x7C, 0xA3, 0x76, 0x8B, 0x7C, 0xE3, 0x76, 0xCB, 0x7C, 0x23, 0x77, + 0x0B, 0x7D, 0x63, 0x77, 0x49, 0x7D, 0xA1, 0x77, 0x90, 0xF8, 0xA9, 0x17, + 0xE1, 0x77, 0x90, 0xF8, 0xAA, 0x17, 0x84, 0xF8, 0x20, 0x10, 0xB0, 0xF8, + 0x54, 0x17, 0xE1, 0x85, 0x90, 0xF8, 0xA1, 0x17, 0xCB, 0x09, 0x21, 0x6B, + 0x63, 0xF3, 0x10, 0x41, 0x21, 0x63, 0x90, 0xF8, 0xA1, 0x37, 0x9B, 0x09, + 0x63, 0xF3, 0x51, 0x41, 0x21, 0x63, 0x90, 0xF8, 0xA1, 0x07, 0x60, 0xF3, + 0x92, 0x41, 0x9D, 0x48, 0x21, 0x63, 0x01, 0x21, 0x81, 0x70, 0x02, 0x71, + 0x10, 0xBD, 0x9B, 0x49, 0x10, 0xB5, 0x09, 0x68, 0x91, 0xF8, 0x78, 0x10, + 0xC9, 0x07, 0x10, 0xD0, 0x01, 0x7A, 0x71, 0xB1, 0x03, 0x29, 0x0C, 0xD0, + 0x04, 0x29, 0x0A, 0xD0, 0x05, 0x29, 0x08, 0xD0, 0x97, 0x49, 0x00, 0xF0, + 0xD5, 0xF8, 0x96, 0x49, 0x04, 0x20, 0x02, 0xF0, 0xA1, 0xFB, 0x00, 0x20, + 0x10, 0xBD, 0x01, 0x20, 0x10, 0xBD, 0x10, 0xB5, 0x92, 0x4C, 0x21, 0x78, + 0x02, 0x29, 0x02, 0xD1, 0x00, 0x7A, 0x05, 0x28, 0x10, 0xD1, 0x90, 0x48, + 0x02, 0xF0, 0x02, 0xF8, 0x8E, 0x48, 0x38, 0x30, 0x02, 0xF0, 0x3E, 0xF8, + 0x8C, 0x48, 0x20, 0x30, 0x01, 0xF0, 0xF6, 0xFF, 0x8A, 0x48, 0x5A, 0x30, + 0x02, 0xF0, 0x32, 0xF8, 0x02, 0x20, 0x20, 0x70, 0x10, 0xBD, 0x10, 0xB5, + 0x04, 0x46, 0x00, 0x7A, 0x80, 0xB1, 0x20, 0x46, 0xFF, 0xF7, 0xDF, 0xFF, + 0x81, 0x49, 0x20, 0x46, 0x00, 0xF0, 0xD0, 0xF8, 0x7A, 0x48, 0x7F, 0x49, + 0x80, 0x78, 0x01, 0x28, 0x06, 0xD0, 0x00, 0x20, 0x02, 0xF0, 0x70, 0xFB, + 0x00, 0x20, 0x10, 0xBD, 0x01, 0x20, 0x10, 0xBD, 0x02, 0x20, 0xF7, 0xE7, + 0x73, 0x48, 0x10, 0xB5, 0x00, 0x78, 0x75, 0x49, 0x42, 0x00, 0x01, 0xEB, + 0x40, 0x01, 0x73, 0x48, 0x3C, 0x38, 0x01, 0xF0, 0x95, 0xFD, 0x71, 0x48, + 0x75, 0x49, 0x3C, 0x38, 0x08, 0x62, 0x01, 0x20, 0x10, 0xBD, 0x70, 0x47, + 0x70, 0xB5, 0x6A, 0x4C, 0x05, 0x46, 0x22, 0x46, 0x6B, 0x49, 0xA0, 0x78, + 0x12, 0x78, 0x48, 0xB1, 0xA1, 0xF1, 0xB8, 0x00, 0xFF, 0xF7, 0x43, 0xFB, + 0x28, 0x7A, 0x02, 0x28, 0x0B, 0xD0, 0x03, 0x28, 0x09, 0xD0, 0x0E, 0xE0, + 0x50, 0x00, 0x01, 0xEB, 0x42, 0x01, 0x02, 0x46, 0x62, 0x48, 0xB8, 0x38, + 0x01, 0xF0, 0x74, 0xFD, 0xF0, 0xE7, 0x60, 0x48, 0xE2, 0x78, 0x21, 0x78, + 0xB8, 0x38, 0x00, 0xF0, 0x58, 0xF8, 0x20, 0x79, 0x61, 0x4D, 0x01, 0x28, + 0x04, 0xD0, 0x5B, 0x48, 0xB8, 0x38, 0xA8, 0x61, 0x01, 0x20, 0x70, 0xBD, + 0x58, 0x48, 0x00, 0x22, 0x21, 0x78, 0xB8, 0x38, 0xFF, 0xF7, 0xCF, 0xFF, + 0xF5, 0xE7, 0x10, 0xB5, 0x01, 0x7A, 0x79, 0xB1, 0x03, 0x29, 0x0D, 0xD0, + 0x04, 0x29, 0x0B, 0xD0, 0xFF, 0xF7, 0x81, 0xFF, 0x4D, 0x48, 0x52, 0x49, + 0x80, 0x78, 0x01, 0x28, 0x06, 0xD0, 0x01, 0x20, 0x02, 0xF0, 0x16, 0xFB, + 0x00, 0x20, 0x10, 0xBD, 0x01, 0x20, 0x10, 0xBD, 0x03, 0x20, 0xF7, 0xE7, + 0x70, 0xB5, 0x46, 0x4C, 0x05, 0x46, 0x22, 0x46, 0x47, 0x49, 0xA0, 0x78, + 0x52, 0x78, 0x48, 0xB1, 0xA1, 0xF1, 0x7C, 0x00, 0xFF, 0xF7, 0xFB, 0xFA, + 0x28, 0x7A, 0x02, 0x28, 0x0B, 0xD0, 0x03, 0x28, 0x09, 0xD0, 0x0E, 0xE0, + 0x50, 0x00, 0x01, 0xEB, 0x42, 0x01, 0x02, 0x46, 0x3E, 0x48, 0x7C, 0x38, + 0x01, 0xF0, 0x2C, 0xFD, 0xF0, 0xE7, 0x3C, 0x48, 0xE2, 0x78, 0x61, 0x78, + 0x7C, 0x38, 0x00, 0xF0, 0x10, 0xF8, 0x20, 0x79, 0x3D, 0x4D, 0x01, 0x28, + 0x04, 0xD0, 0x37, 0x48, 0x7C, 0x38, 0xE8, 0x61, 0x01, 0x20, 0x70, 0xBD, + 0x34, 0x48, 0x01, 0x22, 0x61, 0x78, 0x7C, 0x38, 0xFF, 0xF7, 0x87, 0xFF, + 0xF5, 0xE7, 0x10, 0xB5, 0x01, 0x2A, 0x0A, 0xD0, 0x00, 0x23, 0x06, 0xE0, + 0x30, 0xF8, 0x13, 0x40, 0x54, 0x43, 0x20, 0xF8, 0x13, 0x40, 0x5B, 0x1C, + 0x1B, 0xB2, 0x8B, 0x42, 0xF6, 0xDB, 0x10, 0xBD, 0x10, 0xB5, 0x0C, 0x46, + 0x08, 0x46, 0xFF, 0xF7, 0x90, 0xFE, 0x25, 0x48, 0x00, 0x68, 0x90, 0xF8, + 0xB2, 0x17, 0x04, 0xF8, 0x20, 0x1F, 0x90, 0xF8, 0xB3, 0x17, 0x01, 0xF0, + 0x0F, 0x01, 0xA1, 0x70, 0x90, 0xF8, 0xB5, 0x17, 0x01, 0xF0, 0x3F, 0x01, + 0xE1, 0x70, 0x90, 0xF8, 0xB4, 0x17, 0xC1, 0xF3, 0x01, 0x11, 0x21, 0x71, + 0x90, 0xF8, 0xB4, 0x17, 0x89, 0x09, 0x61, 0x71, 0x90, 0xF8, 0xB4, 0x17, + 0x01, 0xF0, 0x07, 0x01, 0xA1, 0x71, 0x90, 0xF8, 0xB5, 0x07, 0x80, 0x09, + 0xE0, 0x71, 0x10, 0xBD, 0x70, 0xB5, 0x05, 0x46, 0x0C, 0x46, 0x08, 0x46, + 0xFF, 0xF7, 0x67, 0xFE, 0x2A, 0x7A, 0x10, 0x48, 0x0E, 0x49, 0x06, 0x2A, + 0x18, 0xD2, 0xDF, 0xE8, 0x02, 0xF0, 0x17, 0x17, 0x03, 0x03, 0x2B, 0x33, + 0x00, 0x68, 0x90, 0xF8, 0xB1, 0x27, 0x02, 0xF0, 0x0F, 0x02, 0x84, 0xF8, + 0x22, 0x20, 0x90, 0xF8, 0xAC, 0x27, 0x90, 0xF8, 0xB1, 0x07, 0x02, 0xF0, + 0x0F, 0x02, 0x00, 0xF0, 0x0F, 0x00, 0x40, 0x1C, 0x52, 0x1C, 0xB2, 0xFB, + 0xF0, 0xF0, 0xC8, 0x70, 0x70, 0xBD, 0x00, 0x00, 0x49, 0x24, 0x10, 0x00, + 0x50, 0x24, 0x10, 0x00, 0x21, 0xD6, 0x00, 0x00, 0xF0, 0xC7, 0x01, 0x20, + 0x54, 0x24, 0x10, 0x00, 0x78, 0x52, 0x10, 0x00, 0x34, 0x24, 0x10, 0x00, + 0x34, 0x17, 0x10, 0x00, 0x94, 0x51, 0x10, 0x00, 0x00, 0x68, 0x90, 0xF8, + 0xB1, 0x07, 0x00, 0xF0, 0x0F, 0x00, 0x84, 0xF8, 0x22, 0x00, 0xE3, 0xE7, + 0x00, 0x20, 0x84, 0xF8, 0x22, 0x00, 0x88, 0x70, 0x08, 0x71, 0xDD, 0xE7, + 0x08, 0xB5, 0x03, 0xF0, 0x55, 0xF9, 0x00, 0x20, 0x00, 0x90, 0x00, 0xBF, + 0x40, 0x1C, 0x00, 0x90, 0x14, 0x28, 0xFA, 0xDB, 0xBD, 0xE8, 0x08, 0x40, + 0xFE, 0xF7, 0x57, 0xBB, 0x01, 0xF1, 0xB4, 0xBD, 0x10, 0xB5, 0xFF, 0xF7, + 0xED, 0xFF, 0x10, 0xBD, 0x10, 0xB5, 0xFF, 0xF7, 0xE9, 0xFF, 0x10, 0xBD, + 0x10, 0xB5, 0xFF, 0xF7, 0xE5, 0xFF, 0x10, 0xBD, 0x10, 0xB5, 0xFF, 0xF7, + 0xE1, 0xFF, 0xBD, 0xE8, 0x10, 0x40, 0xFD, 0xF7, 0xE4, 0xBD, 0x10, 0xB5, + 0xFF, 0xF7, 0xDA, 0xFF, 0xBD, 0xE8, 0x10, 0x40, 0x02, 0xF0, 0xE4, 0xBB, + 0x10, 0xB5, 0xFF, 0xF7, 0xD3, 0xFF, 0xBD, 0xE8, 0x10, 0x40, 0x03, 0xF0, + 0x37, 0xBC, 0x10, 0xB5, 0xFF, 0xF7, 0xCC, 0xFF, 0xBD, 0xE8, 0x10, 0x40, + 0x03, 0xF0, 0x6A, 0xBC, 0x10, 0xB5, 0xFF, 0xF7, 0xC5, 0xFF, 0xBD, 0xE8, + 0x10, 0x40, 0x03, 0xF0, 0xB5, 0xBC, 0x10, 0xB5, 0xFF, 0xF7, 0xBE, 0xFF, + 0x10, 0xBD, 0x10, 0xB5, 0xFF, 0xF7, 0xBA, 0xFF, 0xBD, 0xE8, 0x10, 0x40, + 0x03, 0xF0, 0xD4, 0xBA, 0x10, 0xB5, 0xFF, 0xF7, 0xB3, 0xFF, 0xBD, 0xE8, + 0x10, 0x40, 0x03, 0xF0, 0x1F, 0xBB, 0x10, 0xB5, 0xFF, 0xF7, 0xAC, 0xFF, + 0x10, 0xBD, 0x10, 0xB5, 0xFF, 0xF7, 0xA8, 0xFF, 0x10, 0xBD, 0x10, 0xB5, + 0xFF, 0xF7, 0xA4, 0xFF, 0x10, 0xBD, 0x10, 0xB5, 0xFF, 0xF7, 0xA0, 0xFF, + 0xBD, 0xE8, 0x10, 0x40, 0x03, 0xF0, 0xB2, 0xB9, 0x10, 0xB5, 0xFF, 0xF7, + 0x99, 0xFF, 0x10, 0xBD, 0x10, 0xB5, 0xFF, 0xF7, 0x95, 0xFF, 0x10, 0xBD, + 0x10, 0xB5, 0xFF, 0xF7, 0x91, 0xFF, 0x10, 0xBD, 0x10, 0xB5, 0xFF, 0xF7, + 0x8D, 0xFF, 0x10, 0xBD, 0x70, 0x47, 0x70, 0x47, 0x10, 0xB5, 0xFF, 0xF7, + 0x87, 0xFF, 0xBD, 0xE8, 0x10, 0x40, 0x03, 0xF0, 0x4D, 0xBD, 0x70, 0x47, + 0x70, 0x47, 0x70, 0x47, 0x70, 0x47, 0x10, 0xB5, 0xFF, 0xF7, 0x7C, 0xFF, + 0xBD, 0xE8, 0x10, 0x40, 0x02, 0xF0, 0x86, 0xBB, 0x70, 0x47, 0x00, 0x00, + 0x70, 0xB5, 0x88, 0xB0, 0x0E, 0x26, 0x01, 0x25, 0x34, 0x46, 0x68, 0x46, + 0x02, 0xF0, 0xF6, 0xFF, 0x00, 0x98, 0xC0, 0x1C, 0x30, 0xD0, 0x00, 0x98, + 0x40, 0x1C, 0x2F, 0xD0, 0x00, 0x98, 0x80, 0x1C, 0x2C, 0xD0, 0x00, 0x98, + 0xC6, 0xB2, 0x01, 0x98, 0xC0, 0x1C, 0x2B, 0xD0, 0x01, 0x98, 0x40, 0x1C, + 0x2A, 0xD0, 0x01, 0x98, 0x80, 0x1C, 0x27, 0xD0, 0x01, 0x98, 0xC5, 0xB2, + 0x02, 0x98, 0xC0, 0x1C, 0x26, 0xD0, 0x02, 0x98, 0x40, 0x1C, 0x25, 0xD0, + 0x02, 0x98, 0x80, 0x1C, 0x22, 0xD0, 0x02, 0x98, 0xC4, 0xB2, 0x31, 0x46, + 0x28, 0x46, 0x02, 0xF0, 0x95, 0xFD, 0x20, 0x46, 0x03, 0xF0, 0xF6, 0xF8, + 0x6B, 0x4A, 0x16, 0x60, 0xC2, 0xE9, 0x01, 0x54, 0x04, 0x98, 0x10, 0x61, + 0x05, 0x98, 0x50, 0x61, 0x06, 0x98, 0x90, 0x61, 0x08, 0xB0, 0x70, 0xBD, + 0x11, 0x20, 0x00, 0xE0, 0x10, 0x20, 0xFD, 0xF7, 0x95, 0xFD, 0xD0, 0xE7, + 0x21, 0x20, 0x00, 0xE0, 0x20, 0x20, 0xFD, 0xF7, 0x8F, 0xFD, 0xD5, 0xE7, + 0x31, 0x20, 0x00, 0xE0, 0x30, 0x20, 0xFD, 0xF7, 0x89, 0xFD, 0xDA, 0xE7, + 0x70, 0xB5, 0x01, 0x24, 0x4B, 0xF2, 0x49, 0x50, 0x03, 0xF0, 0xC8, 0xF8, + 0x03, 0xF0, 0x1E, 0xF9, 0xE2, 0x02, 0x59, 0x49, 0x59, 0x48, 0x01, 0xF0, + 0xF8, 0xFB, 0x22, 0x03, 0x91, 0x01, 0x58, 0x48, 0x01, 0xF0, 0xF3, 0xFB, + 0x03, 0xF0, 0xAC, 0xF9, 0x01, 0x20, 0x03, 0xF0, 0xD1, 0xF9, 0x02, 0xF0, + 0x6B, 0xFF, 0xFF, 0xF7, 0x4D, 0xF9, 0x02, 0xF0, 0x27, 0xFB, 0x46, 0x28, + 0x02, 0xD0, 0x01, 0x20, 0xFD, 0xF7, 0x31, 0xFD, 0xFF, 0xF7, 0x8E, 0xFF, + 0x03, 0xF0, 0xA2, 0xF8, 0x03, 0xF0, 0x60, 0xF8, 0x02, 0x21, 0x01, 0x20, + 0x03, 0xF0, 0xBA, 0xF8, 0x4A, 0x4D, 0x28, 0x68, 0x00, 0x78, 0xA5, 0x28, + 0x02, 0xD0, 0x01, 0x20, 0xFD, 0xF7, 0x3C, 0xFD, 0x40, 0xF2, 0xFF, 0x11, + 0x28, 0x68, 0x03, 0xF0, 0xFF, 0xFC, 0x29, 0x68, 0xD1, 0xF8, 0xFC, 0x27, + 0x82, 0x42, 0x03, 0xD0, 0x02, 0x20, 0xFD, 0xF7, 0x2F, 0xFD, 0x04, 0xE0, + 0xB1, 0xF8, 0x01, 0x00, 0x4F, 0xF0, 0x00, 0x51, 0x48, 0x81, 0x40, 0xF2, + 0xFF, 0x31, 0x3B, 0x48, 0x03, 0xF0, 0xEC, 0xFC, 0x39, 0x49, 0xD1, 0xF8, + 0xFC, 0x1F, 0x81, 0x42, 0x03, 0xD0, 0x00, 0x24, 0x03, 0x20, 0xFD, 0xF7, + 0x1B, 0xFD, 0x03, 0xF0, 0x02, 0xF9, 0x02, 0xF0, 0xF7, 0xFA, 0x40, 0xF2, + 0x72, 0x42, 0x01, 0x46, 0x90, 0x42, 0x02, 0xD0, 0x01, 0x20, 0xFD, 0xF7, + 0x21, 0xFD, 0x03, 0xF0, 0xFB, 0xFB, 0x30, 0x4E, 0x34, 0xB3, 0x30, 0x48, + 0x01, 0x68, 0x91, 0xF8, 0x20, 0x00, 0x55, 0x28, 0x22, 0xD0, 0x70, 0x20, + 0xFD, 0xF7, 0x1A, 0xFD, 0x30, 0x46, 0x03, 0xF0, 0x91, 0xFC, 0x01, 0x20, + 0x03, 0xF0, 0x5E, 0xF8, 0x00, 0x22, 0x11, 0x46, 0x10, 0x46, 0x03, 0xF0, + 0x02, 0xF9, 0x01, 0x22, 0x00, 0x21, 0x10, 0x46, 0x03, 0xF0, 0xFD, 0xF8, + 0x28, 0x68, 0x90, 0xF8, 0xAF, 0x02, 0xC1, 0x07, 0x0F, 0xD0, 0x81, 0x07, + 0x0D, 0xD5, 0xBD, 0xE8, 0x70, 0x40, 0x40, 0x09, 0x01, 0x22, 0x00, 0x21, + 0x03, 0xF0, 0xEF, 0xB8, 0x71, 0x20, 0xDD, 0xE7, 0xD1, 0xF8, 0x21, 0x00, + 0x20, 0xF0, 0x7F, 0x46, 0xDA, 0xE7, 0x70, 0xBD, 0x10, 0xB5, 0xF2, 0xF7, + 0x2D, 0xF8, 0xFF, 0xF7, 0x67, 0xFF, 0xFE, 0xF7, 0x57, 0xF9, 0x13, 0x48, + 0x00, 0x68, 0x90, 0xF8, 0x30, 0x01, 0x80, 0x07, 0x02, 0xD5, 0x13, 0x48, + 0xFE, 0xF7, 0x10, 0xFA, 0xFD, 0xF7, 0xFC, 0xFC, 0x01, 0xF0, 0xF0, 0xF9, + 0x4F, 0xF4, 0x58, 0x72, 0x01, 0x46, 0x90, 0x42, 0x02, 0xD0, 0x02, 0x20, + 0xFD, 0xF7, 0xD2, 0xFC, 0x01, 0xF0, 0xE4, 0xF9, 0x00, 0xF0, 0x16, 0xF8, + 0xF2, 0xF7, 0x0C, 0xF8, 0x00, 0xF0, 0x7E, 0xF8, 0x01, 0x20, 0x10, 0xBD, + 0xC8, 0x52, 0x10, 0x00, 0xF0, 0xEF, 0x03, 0x00, 0x00, 0x00, 0x10, 0x00, + 0x00, 0x10, 0x10, 0x00, 0x50, 0x24, 0x10, 0x00, 0x00, 0x77, 0x01, 0x00, + 0x54, 0x24, 0x10, 0x00, 0x70, 0x53, 0x10, 0x00, 0x7F, 0xB5, 0x00, 0xF0, + 0x41, 0xF8, 0x1F, 0x4D, 0x00, 0x24, 0x05, 0xEB, 0x44, 0x10, 0x00, 0xF1, + 0x10, 0x02, 0x01, 0x7F, 0x4C, 0xCA, 0xCD, 0xE9, 0x02, 0x61, 0xCD, 0xE9, + 0x00, 0x23, 0x0F, 0xC8, 0x00, 0xF0, 0xDA, 0xF9, 0x10, 0xB1, 0x02, 0x20, + 0xFD, 0xF7, 0xAD, 0xFC, 0x64, 0x1C, 0x06, 0x2C, 0xEB, 0xDB, 0x14, 0x4D, + 0x00, 0x24, 0xC0, 0x35, 0x04, 0xEB, 0x44, 0x00, 0x05, 0xEB, 0x80, 0x01, + 0x55, 0xF8, 0x20, 0x00, 0x8A, 0x68, 0x49, 0x68, 0x00, 0xF0, 0x46, 0xF9, + 0x10, 0xB1, 0x02, 0x20, 0xFD, 0xF7, 0x99, 0xFC, 0x64, 0x1C, 0x05, 0x2C, + 0xEE, 0xDB, 0x0A, 0x4D, 0x00, 0x24, 0xFC, 0x35, 0x05, 0xEB, 0xC4, 0x00, + 0x41, 0x68, 0x55, 0xF8, 0x34, 0x00, 0x00, 0xF0, 0x8F, 0xF8, 0x10, 0xB1, + 0x02, 0x20, 0xFD, 0xF7, 0x88, 0xFC, 0x64, 0x1C, 0x05, 0x2C, 0xF1, 0xDB, + 0x7F, 0xBD, 0x03, 0x20, 0xFD, 0xF7, 0x81, 0xBC, 0x5C, 0x1E, 0x01, 0x00, + 0x1A, 0x49, 0x10, 0xB5, 0x01, 0x20, 0x08, 0x70, 0x19, 0x49, 0x00, 0x20, + 0x08, 0x60, 0x19, 0x49, 0x08, 0x60, 0x19, 0x49, 0x08, 0x60, 0x19, 0x49, + 0x08, 0x60, 0x00, 0xF0, 0x7D, 0xF9, 0x00, 0xF0, 0x0F, 0xF9, 0x00, 0xF0, + 0x67, 0xF8, 0x00, 0x20, 0x10, 0xBD, 0x10, 0xB5, 0x12, 0x48, 0x01, 0xF0, + 0x9C, 0xF9, 0x10, 0x49, 0x08, 0x60, 0x0E, 0x49, 0x09, 0x68, 0x88, 0x42, + 0x07, 0xD0, 0x0B, 0x48, 0x00, 0x78, 0x02, 0x28, 0x03, 0xD1, 0xBD, 0xE8, + 0x10, 0x40, 0xF1, 0xF7, 0x47, 0xBF, 0x10, 0xBD, 0x10, 0xB5, 0xFF, 0xF7, + 0xEA, 0xFF, 0x05, 0x49, 0x02, 0x20, 0x08, 0x70, 0xF1, 0xF7, 0x22, 0xFF, + 0x4F, 0xF0, 0xFF, 0x30, 0x10, 0xBD, 0x05, 0x20, 0x70, 0x47, 0x00, 0x00, + 0x44, 0x25, 0x10, 0x00, 0x48, 0x25, 0x10, 0x00, 0x4C, 0x25, 0x10, 0x00, + 0x50, 0x25, 0x10, 0x00, 0x54, 0x25, 0x10, 0x00, 0x70, 0xB5, 0x0D, 0x46, + 0x04, 0x46, 0xC1, 0x69, 0x80, 0x68, 0xCC, 0x22, 0x01, 0xF0, 0xE1, 0xFA, + 0xE1, 0x69, 0xA0, 0x68, 0x08, 0x44, 0x40, 0x38, 0x4F, 0xF0, 0x80, 0x71, + 0xC1, 0x63, 0x21, 0x6A, 0x81, 0x63, 0x00, 0x21, 0x41, 0x63, 0x01, 0x63, + 0xC1, 0x62, 0x81, 0x62, 0xC0, 0xE9, 0x08, 0x51, 0x4F, 0xF0, 0x0B, 0x31, + 0xC1, 0x61, 0x4F, 0xF0, 0x0A, 0x31, 0x81, 0x61, 0x4F, 0xF0, 0x09, 0x31, + 0x41, 0x61, 0x4F, 0xF0, 0x08, 0x31, 0x01, 0x61, 0x4F, 0xF0, 0x07, 0x31, + 0xC1, 0x60, 0x4F, 0xF0, 0x06, 0x31, 0x81, 0x60, 0x4F, 0xF0, 0x05, 0x31, + 0x41, 0x60, 0x4F, 0xF0, 0x04, 0x31, 0x01, 0x60, 0x70, 0xBD, 0x82, 0x69, + 0x81, 0x68, 0x91, 0x42, 0x02, 0xD8, 0x40, 0x68, 0xFF, 0xF7, 0x83, 0xBF, + 0x70, 0x47, 0x00, 0x00, 0x10, 0xB5, 0x4F, 0xF4, 0xB4, 0x71, 0x4F, 0x48, + 0x01, 0xF0, 0xD3, 0xFA, 0x00, 0x20, 0x10, 0xBD, 0x70, 0xB5, 0x05, 0x46, + 0x00, 0xEB, 0xC5, 0x01, 0x4A, 0x48, 0x00, 0xEB, 0x81, 0x04, 0xF1, 0xF7, + 0x1B, 0xFF, 0x06, 0x46, 0x20, 0x78, 0x28, 0xB1, 0x30, 0x46, 0xF1, 0xF7, + 0x1D, 0xFF, 0x6F, 0xF0, 0x01, 0x00, 0x70, 0xBD, 0x03, 0x20, 0x20, 0x70, + 0x00, 0x20, 0x65, 0x60, 0x20, 0x62, 0x04, 0xF1, 0x1C, 0x00, 0x01, 0xF0, + 0xF1, 0xF8, 0x30, 0x46, 0xF1, 0xF7, 0x0E, 0xFF, 0x00, 0x20, 0x70, 0xBD, + 0x2D, 0xE9, 0xF0, 0x41, 0x0F, 0x46, 0x3B, 0x49, 0x00, 0x25, 0x00, 0xEB, + 0xC0, 0x00, 0x01, 0xEB, 0x80, 0x04, 0x2E, 0x46, 0xF1, 0xF7, 0xF8, 0xFE, + 0x80, 0x46, 0x20, 0x6A, 0x38, 0x43, 0x20, 0x62, 0x04, 0xF1, 0x1C, 0x00, + 0x07, 0x46, 0x01, 0xF0, 0xFE, 0xF8, 0x0C, 0xE0, 0x21, 0x6A, 0x02, 0x6C, + 0x11, 0x42, 0x03, 0xD0, 0x00, 0xF0, 0x26, 0xF9, 0x01, 0x26, 0x00, 0xE0, + 0x6D, 0x1C, 0x29, 0x46, 0x38, 0x46, 0x01, 0xF0, 0xE6, 0xF8, 0x00, 0x28, + 0xF0, 0xD1, 0x01, 0x2E, 0x01, 0xD1, 0xFF, 0xF7, 0x4A, 0xFF, 0x40, 0x46, + 0xF1, 0xF7, 0xE0, 0xFE, 0x00, 0x20, 0xBD, 0xE8, 0xF0, 0x81, 0x70, 0xB5, + 0x0D, 0x46, 0x24, 0x49, 0x00, 0xEB, 0xC0, 0x00, 0x01, 0xEB, 0x80, 0x04, + 0xF1, 0xF7, 0xCC, 0xFE, 0x21, 0x6A, 0xA9, 0x43, 0x21, 0x62, 0xF1, 0xF7, + 0xCF, 0xFE, 0x00, 0x20, 0x70, 0xBD, 0x70, 0xB5, 0x0C, 0x46, 0x1C, 0x49, + 0x00, 0xEB, 0xC0, 0x00, 0x01, 0xEB, 0x80, 0x05, 0x00, 0x20, 0x20, 0x60, + 0xF1, 0xF7, 0xBA, 0xFE, 0x29, 0x6A, 0x21, 0x60, 0xF1, 0xF7, 0xBE, 0xFE, + 0x00, 0x20, 0x70, 0xBD, 0x2D, 0xE9, 0xF0, 0x41, 0x0D, 0x46, 0x13, 0x49, + 0x00, 0xEB, 0xC0, 0x00, 0x1E, 0x46, 0x90, 0x46, 0x01, 0xEB, 0x80, 0x04, + 0xF1, 0xF7, 0xA8, 0xFE, 0x07, 0x46, 0x0F, 0x48, 0x00, 0x68, 0x05, 0x64, + 0x21, 0x6A, 0x29, 0x42, 0x03, 0xD1, 0x04, 0xF1, 0x1C, 0x01, 0x00, 0xF0, + 0xED, 0xF8, 0x38, 0x46, 0xF1, 0xF7, 0xA2, 0xFE, 0xF1, 0xF7, 0x98, 0xFE, + 0x21, 0x6A, 0x29, 0x40, 0x31, 0x60, 0xB8, 0xF1, 0x01, 0x0F, 0x02, 0xD1, + 0x21, 0x6A, 0xA9, 0x43, 0x21, 0x62, 0xF1, 0xF7, 0x95, 0xFE, 0x00, 0x20, + 0xB3, 0xE7, 0x00, 0x00, 0xF0, 0x7B, 0x10, 0x00, 0x48, 0x25, 0x10, 0x00, + 0x10, 0xB5, 0x4F, 0xF4, 0xC8, 0x71, 0x32, 0x48, 0x01, 0xF0, 0x2D, 0xFA, + 0x00, 0x20, 0x10, 0xBD, 0x2D, 0xE9, 0xF0, 0x41, 0x88, 0x46, 0x05, 0x46, + 0x2D, 0x49, 0x00, 0xEB, 0x85, 0x00, 0x17, 0x46, 0x01, 0xEB, 0xC0, 0x04, + 0xF1, 0xF7, 0x72, 0xFE, 0x06, 0x46, 0x20, 0x78, 0x30, 0xB1, 0x30, 0x46, + 0xF1, 0xF7, 0x74, 0xFE, 0x6F, 0xF0, 0x01, 0x00, 0xBD, 0xE8, 0xF0, 0x81, + 0x02, 0x20, 0x20, 0x70, 0xE7, 0x61, 0x14, 0x22, 0x41, 0x46, 0x04, 0xF1, + 0x08, 0x00, 0x65, 0x60, 0x01, 0xF0, 0x6A, 0xF9, 0x00, 0x20, 0x20, 0x62, + 0x04, 0xF1, 0x24, 0x00, 0x01, 0xF0, 0x40, 0xF8, 0x30, 0x46, 0xF1, 0xF7, + 0x5D, 0xFE, 0x00, 0x20, 0xE8, 0xE7, 0x70, 0xB5, 0x19, 0x49, 0x00, 0xEB, + 0x80, 0x00, 0x01, 0xEB, 0xC0, 0x04, 0xF1, 0xF7, 0x4B, 0xFE, 0x05, 0x46, + 0xD4, 0xE9, 0x07, 0x01, 0x81, 0x42, 0x05, 0xDB, 0x14, 0x48, 0x04, 0xF1, + 0x24, 0x01, 0x00, 0x68, 0x00, 0xF0, 0x90, 0xF8, 0x20, 0x6A, 0x40, 0x1C, + 0x20, 0x62, 0x28, 0x46, 0xF1, 0xF7, 0x42, 0xFE, 0x00, 0x20, 0x70, 0xBD, + 0x70, 0xB5, 0x0C, 0x49, 0x00, 0xEB, 0x80, 0x00, 0x01, 0xEB, 0xC0, 0x04, + 0xF1, 0xF7, 0x30, 0xFE, 0x05, 0x46, 0x20, 0x6A, 0x08, 0xB1, 0x40, 0x1E, + 0x20, 0x62, 0x04, 0xF1, 0x24, 0x00, 0x01, 0xF0, 0x36, 0xF8, 0x10, 0xB1, + 0x60, 0x6A, 0x00, 0xF0, 0x11, 0xF8, 0x28, 0x46, 0xF1, 0xF7, 0x28, 0xFE, + 0x00, 0x20, 0x70, 0xBD, 0x58, 0x7D, 0x10, 0x00, 0x48, 0x25, 0x10, 0x00, + 0x10, 0xB5, 0x4F, 0xF4, 0x2A, 0x71, 0x40, 0x48, 0x01, 0xF0, 0xC1, 0xF9, + 0x00, 0x20, 0x10, 0xBD, 0x10, 0xB5, 0x04, 0x46, 0x90, 0xF8, 0x38, 0x00, + 0x02, 0x28, 0x0B, 0xD0, 0x20, 0x46, 0x01, 0xF0, 0x1A, 0xF8, 0x02, 0x20, + 0x84, 0xF8, 0x38, 0x00, 0x38, 0x49, 0x20, 0x46, 0x00, 0xF0, 0xEE, 0xFF, + 0xFF, 0xF7, 0x6F, 0xFE, 0x00, 0x20, 0x10, 0xBD, 0x2D, 0xE9, 0xF0, 0x5F, + 0x8B, 0x46, 0x06, 0x46, 0x31, 0x49, 0x00, 0xEB, 0x06, 0x10, 0x90, 0x46, + 0xDD, 0xE9, 0x0A, 0xA9, 0x11, 0xF8, 0x20, 0x20, 0x1D, 0x46, 0x1A, 0xB1, + 0x6F, 0xF0, 0x01, 0x00, 0xBD, 0xE8, 0xF0, 0x9F, 0x01, 0xEB, 0x80, 0x04, + 0xF1, 0xF7, 0xE8, 0xFD, 0x07, 0x46, 0x01, 0x20, 0x20, 0x70, 0xC4, 0xE9, + 0x01, 0x65, 0xC4, 0xE9, 0x05, 0x85, 0xC4, 0xE9, 0x07, 0xA9, 0x14, 0x22, + 0x59, 0x46, 0x04, 0xF1, 0x24, 0x00, 0x01, 0xF0, 0xE5, 0xF8, 0x00, 0x20, + 0x84, 0xF8, 0x37, 0x00, 0x84, 0xF8, 0x38, 0x00, 0x61, 0x69, 0xE0, 0x60, + 0x20, 0x61, 0xC4, 0xE9, 0x0F, 0x10, 0x20, 0x46, 0x0C, 0x99, 0xFF, 0xF7, + 0x65, 0xFE, 0xA0, 0x60, 0x20, 0x46, 0xFF, 0xF7, 0xB5, 0xFF, 0x38, 0x46, + 0xF1, 0xF7, 0xCC, 0xFD, 0x00, 0x20, 0xD3, 0xE7, 0x10, 0xB5, 0x04, 0x46, + 0x90, 0xF8, 0x38, 0x00, 0x02, 0x28, 0x09, 0xD0, 0x20, 0x46, 0x00, 0xF0, + 0xCA, 0xFF, 0x02, 0x20, 0x84, 0xF8, 0x38, 0x00, 0x10, 0x49, 0x20, 0x46, + 0x00, 0xF0, 0x9E, 0xFF, 0x00, 0x20, 0x10, 0xBD, 0x70, 0xB5, 0x04, 0x46, + 0x90, 0xF8, 0x38, 0x00, 0x0D, 0x46, 0x02, 0x28, 0x0B, 0xD1, 0x20, 0x46, + 0x00, 0xF0, 0xB7, 0xFF, 0x03, 0x20, 0x84, 0xF8, 0x38, 0x00, 0x29, 0x46, + 0x20, 0x46, 0x00, 0xF0, 0x8B, 0xFF, 0xFF, 0xF7, 0x0C, 0xFE, 0x00, 0x20, + 0x70, 0xBD, 0x04, 0x48, 0x00, 0x68, 0x40, 0x68, 0x70, 0x47, 0x00, 0x00, + 0xE8, 0x7E, 0x10, 0x00, 0x50, 0x25, 0x10, 0x00, 0x48, 0x25, 0x10, 0x00, + 0xF0, 0xB5, 0xD1, 0xE9, 0x00, 0x52, 0x8E, 0x68, 0x11, 0x88, 0x03, 0x68, + 0x99, 0x42, 0x01, 0xDD, 0x31, 0x88, 0x2E, 0xE0, 0x02, 0xEB, 0x45, 0x01, + 0x31, 0xF8, 0x02, 0x4C, 0x9C, 0x42, 0x04, 0xDA, 0x06, 0xEB, 0x45, 0x01, + 0x31, 0xF8, 0x02, 0x1C, 0x23, 0xE0, 0x00, 0x24, 0x21, 0x46, 0x6F, 0x1E, + 0x0C, 0xE0, 0x32, 0xF8, 0x11, 0xC0, 0x9C, 0x45, 0x07, 0xDC, 0x02, 0xEB, + 0x41, 0x0C, 0xBC, 0xF8, 0x02, 0xC0, 0x9C, 0x45, 0x01, 0xDB, 0x0C, 0x46, + 0x29, 0x46, 0x49, 0x1C, 0xB9, 0x42, 0xF0, 0xDB, 0x32, 0xF8, 0x14, 0x10, + 0x02, 0xEB, 0x44, 0x02, 0x5D, 0x1A, 0x06, 0xEB, 0x44, 0x03, 0x52, 0x88, + 0x5F, 0x88, 0x36, 0xF8, 0x14, 0x30, 0xFE, 0x1A, 0x6E, 0x43, 0x51, 0x1A, + 0x96, 0xFB, 0xF1, 0xF1, 0x19, 0x44, 0x01, 0x60, 0xF0, 0xBD, 0x70, 0xB5, + 0x05, 0x46, 0x08, 0x68, 0x0C, 0x46, 0x01, 0x28, 0x02, 0xDD, 0x28, 0x1D, + 0xFF, 0xF7, 0xBC, 0xFF, 0xE0, 0x68, 0x01, 0x28, 0x05, 0xDD, 0x28, 0x46, + 0x04, 0xF1, 0x0C, 0x01, 0xBD, 0xE8, 0x70, 0x40, 0xB2, 0xE7, 0x70, 0xBD, + 0x30, 0xB5, 0x42, 0x78, 0x03, 0x78, 0x0D, 0x8A, 0xD2, 0x1A, 0xC3, 0x78, + 0x80, 0x78, 0x52, 0x1C, 0x1B, 0x1A, 0x5B, 0x1C, 0x05, 0xFB, 0x02, 0xF0, + 0xD4, 0x18, 0x5D, 0x43, 0x40, 0x00, 0x6A, 0x00, 0xB0, 0xFB, 0xF4, 0xF0, + 0xB2, 0xFB, 0xF4, 0xF2, 0x4B, 0x68, 0x90, 0x42, 0x03, 0xD9, 0x18, 0x80, + 0x88, 0x68, 0x02, 0x80, 0x30, 0xBD, 0x1A, 0x80, 0x89, 0x68, 0x08, 0x80, + 0x30, 0xBD, 0x2D, 0xE9, 0xFF, 0x4F, 0x00, 0x26, 0x83, 0xB0, 0x91, 0x46, + 0x35, 0x46, 0x34, 0x46, 0xB4, 0x46, 0x37, 0x46, 0xB0, 0x46, 0x93, 0x78, + 0x92, 0xF8, 0x03, 0xA0, 0x28, 0xE0, 0x06, 0x9A, 0x03, 0x99, 0x58, 0x1C, + 0x92, 0x7C, 0x49, 0x1C, 0x92, 0x1C, 0x00, 0xFB, 0x02, 0x1B, 0x01, 0x90, + 0x99, 0xF8, 0x00, 0x00, 0x00, 0x90, 0x99, 0xF8, 0x01, 0xE0, 0x15, 0xE0, + 0x1B, 0xF8, 0x00, 0x20, 0x04, 0x99, 0x8A, 0x42, 0x0E, 0xD1, 0x00, 0x9A, + 0xAA, 0xEB, 0x03, 0x01, 0x82, 0x1A, 0x52, 0x1C, 0x49, 0x1C, 0x02, 0xFB, + 0x02, 0x77, 0x02, 0xFB, 0x01, 0xCC, 0x01, 0xFB, 0x01, 0x88, 0x15, 0x44, + 0x0C, 0x44, 0x76, 0x1C, 0x40, 0x1C, 0xC0, 0xB2, 0x86, 0x45, 0xE7, 0xD2, + 0x01, 0x98, 0xC3, 0xB2, 0x9A, 0x45, 0xD4, 0xD2, 0x4F, 0xF4, 0x7A, 0x70, + 0x4F, 0xF4, 0x7A, 0x71, 0x68, 0x43, 0x61, 0x43, 0x90, 0xFB, 0xF6, 0xF0, + 0x91, 0xFB, 0xF6, 0xF2, 0x00, 0xFB, 0x04, 0xF3, 0x4F, 0xF4, 0x7A, 0x71, + 0x68, 0x43, 0x90, 0xFB, 0xF1, 0xF0, 0x62, 0x43, 0x93, 0xFB, 0xF1, 0xF3, + 0x3D, 0x1A, 0x92, 0xFB, 0xF1, 0xF0, 0xA8, 0xEB, 0x00, 0x07, 0xAC, 0xEB, + 0x03, 0x06, 0x74, 0x00, 0xE9, 0x1B, 0x88, 0x46, 0x20, 0x46, 0x00, 0xF0, + 0x40, 0xF8, 0x40, 0x10, 0xB8, 0xF1, 0x00, 0x0F, 0x02, 0xD0, 0x0D, 0xDD, + 0x4C, 0xB1, 0x16, 0xE0, 0x00, 0x2C, 0x06, 0xD0, 0x02, 0xDD, 0x4F, 0xF0, + 0x2D, 0x00, 0x10, 0xE0, 0x4F, 0xF0, 0x5A, 0x00, 0x0D, 0xE0, 0x4F, 0xF0, + 0x00, 0x00, 0x0A, 0xE0, 0x00, 0x2C, 0x03, 0xD0, 0x05, 0xDD, 0x00, 0xF1, + 0x5A, 0x00, 0x04, 0xE0, 0x6F, 0xF0, 0x59, 0x00, 0x01, 0xE0, 0xA0, 0xF1, + 0x5A, 0x00, 0x06, 0x99, 0xC9, 0x68, 0x08, 0x70, 0x5F, 0xEA, 0x08, 0x00, + 0x01, 0xD5, 0xC8, 0xF1, 0x00, 0x00, 0x00, 0x2E, 0x00, 0xDA, 0x76, 0x42, + 0x00, 0xEB, 0x46, 0x00, 0xE9, 0x19, 0x0A, 0x18, 0x08, 0x1A, 0x52, 0x10, + 0x40, 0x10, 0x4F, 0xF4, 0x7A, 0x71, 0x48, 0x43, 0x90, 0xFB, 0xF2, 0xF0, + 0x06, 0x99, 0xC0, 0xF5, 0x7A, 0x70, 0x09, 0x68, 0x08, 0x80, 0x06, 0x99, + 0x07, 0xB0, 0x48, 0x46, 0xBD, 0xE8, 0xF0, 0x4F, 0x46, 0xE7, 0x4F, 0xF4, + 0x7A, 0x72, 0x50, 0x43, 0x90, 0xFB, 0xF1, 0xF1, 0x10, 0xB5, 0x42, 0xF6, + 0xA6, 0x40, 0xC1, 0x42, 0x02, 0xDA, 0x6F, 0xF0, 0x59, 0x00, 0x10, 0xBD, + 0x42, 0xF6, 0xA6, 0x40, 0x81, 0x42, 0x01, 0xDD, 0x5A, 0x20, 0x10, 0xBD, + 0x00, 0x22, 0x11, 0x4B, 0x10, 0x46, 0x33, 0xF9, 0x10, 0x40, 0x8C, 0x42, + 0x07, 0xDC, 0x03, 0xEB, 0x40, 0x04, 0xB4, 0xF9, 0x02, 0x40, 0x8C, 0x42, + 0x01, 0xDB, 0x02, 0x46, 0x46, 0x20, 0x40, 0x1C, 0x45, 0x28, 0xF0, 0xD3, + 0x33, 0xF9, 0x12, 0x00, 0x02, 0xEB, 0x82, 0x04, 0x03, 0xEB, 0x42, 0x02, + 0x09, 0x1A, 0xB2, 0xF9, 0x02, 0x20, 0x01, 0xEB, 0x81, 0x01, 0x10, 0x1A, + 0x91, 0xFB, 0xF0, 0xF0, 0x55, 0x3C, 0x20, 0x44, 0x10, 0xBD, 0x00, 0x00, + 0x80, 0x1F, 0x01, 0x00, 0x2D, 0xE9, 0xF8, 0x4F, 0x86, 0x7C, 0xD0, 0xE9, + 0x01, 0xAE, 0x02, 0xFB, 0x06, 0xFC, 0x0A, 0xEB, 0x4C, 0x04, 0x00, 0x25, + 0xB0, 0xF9, 0x10, 0x70, 0x34, 0xF9, 0x11, 0x40, 0xAB, 0x46, 0x2B, 0x46, + 0xBC, 0x42, 0x2C, 0xDD, 0x54, 0x1E, 0x52, 0x1C, 0x64, 0xB2, 0x00, 0x92, + 0x22, 0xE0, 0x00, 0x2C, 0x1B, 0xDB, 0xC2, 0x7C, 0xA2, 0x42, 0x18, 0xDD, + 0xE7, 0xB2, 0x77, 0x43, 0x4A, 0x1E, 0x0A, 0xEB, 0x47, 0x09, 0x52, 0xB2, + 0x4F, 0x1C, 0x0D, 0xE0, 0x00, 0x2A, 0x07, 0xDB, 0x96, 0x42, 0x05, 0xDD, + 0x39, 0xF9, 0x12, 0x80, 0x3E, 0xF9, 0x13, 0xC0, 0x08, 0xFB, 0x0C, 0x55, + 0x5B, 0x1C, 0x52, 0x1C, 0xDB, 0xB2, 0x52, 0xB2, 0xBA, 0x42, 0xEF, 0xDD, + 0x01, 0xE0, 0xDB, 0x1C, 0xDB, 0xB2, 0x64, 0x1C, 0x00, 0x9A, 0x64, 0xB2, + 0x94, 0x42, 0xDA, 0xDD, 0xBB, 0xF1, 0x00, 0x0F, 0x01, 0xD1, 0x4F, 0xF0, + 0x01, 0x0B, 0x95, 0xFB, 0xFB, 0xF0, 0x00, 0xB2, 0xBD, 0xE8, 0xF8, 0x8F, + 0x2D, 0xE9, 0xF0, 0x4F, 0x05, 0x46, 0x85, 0xB0, 0xD5, 0xE9, 0x00, 0xA1, + 0xC0, 0x68, 0x01, 0x91, 0xAC, 0x68, 0x01, 0x78, 0x09, 0xB1, 0x4A, 0x1E, + 0x02, 0x70, 0x89, 0x46, 0x81, 0x78, 0x09, 0xB1, 0x4A, 0x1E, 0x82, 0x70, + 0x8B, 0x46, 0xAA, 0x7C, 0x41, 0x78, 0x53, 0x1E, 0x99, 0x42, 0x02, 0xDA, + 0x4A, 0x1C, 0x42, 0x70, 0x00, 0xE0, 0x51, 0x1E, 0xCE, 0xB2, 0xEA, 0x7C, + 0xC1, 0x78, 0x53, 0x1E, 0x99, 0x42, 0x02, 0xDA, 0x4A, 0x1C, 0xC2, 0x70, + 0x00, 0xE0, 0x51, 0x1E, 0xCF, 0xB2, 0xB9, 0xF1, 0x00, 0x0F, 0x1A, 0xD1, + 0xD8, 0x46, 0x12, 0xE0, 0xAA, 0x7C, 0x08, 0xFB, 0x02, 0xF1, 0x0A, 0xEB, + 0x41, 0x00, 0x00, 0x90, 0x42, 0x46, 0x49, 0x46, 0x28, 0x46, 0xFF, 0xF7, + 0x83, 0xFF, 0x01, 0x46, 0x00, 0x98, 0x20, 0xF8, 0x19, 0x10, 0x08, 0xF1, + 0x01, 0x00, 0x00, 0xF0, 0xFF, 0x08, 0xB8, 0x45, 0xEA, 0xD9, 0x09, 0xF1, + 0x01, 0x00, 0x00, 0xF0, 0xFF, 0x09, 0xA8, 0x7C, 0x40, 0x1E, 0xB0, 0x42, + 0x18, 0xD1, 0xD8, 0x46, 0x12, 0xE0, 0xAA, 0x7C, 0x31, 0x46, 0x08, 0xFB, + 0x02, 0xF0, 0x0A, 0xEB, 0x40, 0x00, 0x00, 0x90, 0x42, 0x46, 0x28, 0x46, + 0xFF, 0xF7, 0x64, 0xFF, 0x01, 0x46, 0x00, 0x98, 0x20, 0xF8, 0x16, 0x10, + 0x08, 0xF1, 0x01, 0x00, 0x00, 0xF0, 0xFF, 0x08, 0xB8, 0x45, 0xEA, 0xD9, + 0x76, 0x1E, 0xF6, 0xB2, 0xBB, 0xF1, 0x00, 0x0F, 0x13, 0xD1, 0x48, 0x46, + 0xC8, 0x46, 0x0A, 0xE0, 0x01, 0x46, 0x5A, 0x46, 0x28, 0x46, 0xFF, 0xF7, + 0x4D, 0xFF, 0x2A, 0xF8, 0x18, 0x00, 0x08, 0xF1, 0x01, 0x00, 0xC0, 0xB2, + 0x80, 0x46, 0xB0, 0x45, 0xF2, 0xD9, 0x0B, 0xF1, 0x01, 0x00, 0x00, 0xF0, + 0xFF, 0x0B, 0xE8, 0x7C, 0x40, 0x1E, 0xB8, 0x42, 0x17, 0xD1, 0xA9, 0x7C, + 0xC8, 0x46, 0x79, 0x43, 0x0A, 0xEB, 0x41, 0x00, 0x00, 0x90, 0x48, 0x46, + 0x0B, 0xE0, 0x01, 0x46, 0x3A, 0x46, 0x28, 0x46, 0xFF, 0xF7, 0x30, 0xFF, + 0x00, 0x99, 0x21, 0xF8, 0x18, 0x00, 0x08, 0xF1, 0x01, 0x00, 0xC0, 0xB2, + 0x80, 0x46, 0xB0, 0x45, 0xF1, 0xD9, 0x7F, 0x1E, 0xFF, 0xB2, 0xB4, 0xF9, + 0x12, 0x00, 0x5F, 0xEA, 0x00, 0x0E, 0x01, 0xD1, 0x4F, 0xF0, 0x01, 0x0E, + 0x5A, 0x46, 0x64, 0xE0, 0xA9, 0x7C, 0x01, 0x9B, 0x02, 0xFB, 0x01, 0xFC, + 0x0A, 0xEB, 0x4C, 0x00, 0x00, 0x90, 0x50, 0x1E, 0xC0, 0xB2, 0x48, 0x43, + 0x03, 0xEB, 0x40, 0x00, 0x04, 0x90, 0x03, 0xEB, 0x4C, 0x00, 0x03, 0x90, + 0x48, 0x46, 0x4E, 0xE0, 0x03, 0x99, 0xB5, 0xF9, 0x10, 0x30, 0x31, 0xF9, + 0x10, 0x10, 0x8B, 0x42, 0x42, 0xDA, 0x04, 0x99, 0xB4, 0xF9, 0x00, 0x80, + 0x01, 0xEB, 0x40, 0x01, 0x00, 0x23, 0x31, 0xF9, 0x02, 0xCD, 0x0C, 0xFB, + 0x08, 0x33, 0xB1, 0xF9, 0x02, 0xC0, 0xB4, 0xF9, 0x02, 0x80, 0x0C, 0xFB, + 0x08, 0x33, 0xB1, 0xF9, 0x04, 0xC0, 0xB4, 0xF9, 0x04, 0x80, 0x0C, 0xFB, + 0x08, 0x3B, 0xAB, 0x7C, 0x02, 0x93, 0x01, 0xEB, 0x43, 0x01, 0xB4, 0xF9, + 0x06, 0x80, 0xB1, 0xF9, 0x00, 0xC0, 0x0C, 0xFB, 0x08, 0xB3, 0xB1, 0xF9, + 0x02, 0xC0, 0xB4, 0xF9, 0x08, 0x80, 0x0C, 0xFB, 0x08, 0x33, 0xB1, 0xF9, + 0x04, 0xC0, 0xB4, 0xF9, 0x0A, 0x80, 0x0C, 0xFB, 0x08, 0x3B, 0x02, 0x9B, + 0xB4, 0xF9, 0x0C, 0x80, 0x01, 0xEB, 0x43, 0x01, 0xB1, 0xF9, 0x00, 0xC0, + 0x0C, 0xFB, 0x08, 0xB3, 0xB1, 0xF9, 0x02, 0xC0, 0xB4, 0xF9, 0x0E, 0x80, + 0xB1, 0xF9, 0x04, 0x10, 0x0C, 0xFB, 0x08, 0x33, 0xB4, 0xF9, 0x10, 0xC0, + 0x01, 0xFB, 0x0C, 0x31, 0x91, 0xFB, 0xFE, 0xF1, 0x00, 0x9B, 0x23, 0xF8, + 0x10, 0x10, 0x40, 0x1C, 0xC0, 0xB2, 0xB0, 0x42, 0xAE, 0xD9, 0x52, 0x1C, + 0xD2, 0xB2, 0xBA, 0x42, 0x98, 0xD9, 0x05, 0xB0, 0xBD, 0xE8, 0xF0, 0x8F, + 0xC7, 0x49, 0xC6, 0x48, 0x48, 0x60, 0x70, 0x47, 0xC5, 0x49, 0x02, 0x78, + 0x0A, 0x70, 0x40, 0x78, 0x48, 0x70, 0x70, 0x47, 0xC0, 0xEB, 0x00, 0x10, + 0xC2, 0x4B, 0x10, 0xB5, 0x00, 0xEB, 0x40, 0x00, 0x18, 0x44, 0x92, 0x78, + 0x80, 0xF8, 0x2C, 0x20, 0x4A, 0x88, 0x42, 0x80, 0x0A, 0x88, 0x02, 0x80, + 0xCA, 0x88, 0xC2, 0x80, 0x8A, 0x88, 0x82, 0x80, 0x4A, 0x89, 0x42, 0x81, + 0x0A, 0x89, 0x02, 0x81, 0xB1, 0xF9, 0x02, 0x20, 0xD3, 0x17, 0x1B, 0x04, + 0x43, 0xEA, 0x12, 0x43, 0x12, 0x04, 0x42, 0x61, 0x83, 0x61, 0xB1, 0xF9, + 0x00, 0x20, 0xD3, 0x17, 0x1B, 0x04, 0x43, 0xEA, 0x12, 0x43, 0x12, 0x04, + 0xC2, 0x60, 0x03, 0x61, 0xB1, 0xF9, 0x02, 0x20, 0xD3, 0x17, 0x1B, 0x04, + 0x43, 0xEA, 0x12, 0x43, 0x12, 0x04, 0x42, 0x62, 0x83, 0x62, 0xB1, 0xF9, + 0x00, 0x10, 0xCA, 0x17, 0x12, 0x04, 0x42, 0xEA, 0x11, 0x42, 0x09, 0x04, + 0xC1, 0x61, 0x02, 0x62, 0x10, 0xBD, 0x2D, 0xE9, 0xF0, 0x4F, 0x8A, 0x46, + 0xC0, 0xEB, 0x00, 0x10, 0xA3, 0x49, 0x00, 0xEB, 0x40, 0x00, 0x00, 0xEB, + 0x01, 0x09, 0xD0, 0x78, 0x8B, 0xB0, 0x81, 0x07, 0x02, 0xD0, 0x00, 0xF0, + 0x03, 0x00, 0x00, 0xE0, 0x01, 0x20, 0x53, 0x79, 0x12, 0x79, 0xB9, 0xF8, + 0x06, 0x40, 0xA9, 0xF8, 0x0A, 0x40, 0xB9, 0xF8, 0x04, 0x40, 0xA9, 0xF8, + 0x08, 0x40, 0xB9, 0xF8, 0x02, 0x40, 0xA9, 0xF8, 0x06, 0x40, 0xB9, 0xF8, + 0x00, 0x40, 0xA9, 0xF8, 0x04, 0x40, 0xBA, 0xF8, 0x02, 0x40, 0xA9, 0xF8, + 0x02, 0x40, 0xBA, 0xF8, 0x00, 0x40, 0xA9, 0xF8, 0x00, 0x40, 0xB9, 0xF8, + 0x02, 0x50, 0xB9, 0xF8, 0x06, 0x10, 0x5B, 0x43, 0x69, 0x1A, 0xB9, 0xF8, + 0x04, 0x50, 0x09, 0xB2, 0x64, 0x1B, 0x24, 0xB2, 0x64, 0x43, 0x01, 0xFB, + 0x01, 0x41, 0x52, 0x43, 0x87, 0x4C, 0x99, 0x42, 0x09, 0xDB, 0x99, 0xF8, + 0x2C, 0x10, 0x08, 0x44, 0x94, 0xF9, 0x01, 0x10, 0x88, 0x42, 0x0D, 0xDA, + 0x89, 0xF8, 0x2C, 0x00, 0x0C, 0xE0, 0x91, 0x42, 0x0A, 0xDC, 0x94, 0xF9, + 0x00, 0x10, 0x99, 0xF8, 0x2C, 0x20, 0x0B, 0x18, 0x9A, 0x42, 0x01, 0xDD, + 0x10, 0x1A, 0xF1, 0xE7, 0x89, 0xF8, 0x2C, 0x10, 0x99, 0xF8, 0x2C, 0x00, + 0x61, 0x68, 0x01, 0xEB, 0x80, 0x00, 0xD0, 0xF8, 0x88, 0x20, 0x0A, 0x92, + 0xD4, 0x17, 0xD0, 0xF8, 0xCC, 0x20, 0xD7, 0x17, 0xCD, 0xE9, 0x04, 0x27, + 0x01, 0x68, 0xCD, 0x17, 0xCD, 0xE9, 0x02, 0x15, 0x41, 0x6C, 0xCA, 0x17, + 0xCD, 0xE9, 0x00, 0x12, 0xD9, 0xF8, 0x18, 0x30, 0xD9, 0xF8, 0x14, 0x20, + 0xCD, 0xE9, 0x06, 0x23, 0x02, 0x99, 0xA2, 0xFB, 0x01, 0x06, 0x03, 0xFB, + 0x01, 0x61, 0x02, 0xFB, 0x05, 0x11, 0x4F, 0xF4, 0x80, 0x32, 0x00, 0x23, + 0x00, 0xF0, 0x28, 0xFD, 0xB9, 0xF9, 0x02, 0x30, 0xB9, 0xF9, 0x0A, 0x20, + 0x13, 0x44, 0xDD, 0xE9, 0x04, 0x27, 0xA3, 0xFB, 0x02, 0x6C, 0xDD, 0x17, + 0x05, 0xFB, 0x02, 0xC2, 0x03, 0xFB, 0x07, 0x25, 0xB9, 0xF9, 0x06, 0x30, + 0x0A, 0x9A, 0xDF, 0x17, 0xA3, 0xFB, 0x02, 0xC8, 0x07, 0xFB, 0x02, 0x82, + 0x03, 0xFB, 0x04, 0x22, 0x16, 0xEB, 0x0C, 0x03, 0x55, 0x41, 0x1E, 0x1A, + 0x65, 0xEB, 0x01, 0x05, 0xDD, 0xE9, 0x00, 0x12, 0xD9, 0xF8, 0x24, 0x30, + 0xD9, 0xF8, 0x28, 0x70, 0xA3, 0xFB, 0x01, 0x0C, 0x07, 0xFB, 0x01, 0xC1, + 0x03, 0xFB, 0x02, 0x11, 0x4F, 0xF4, 0x80, 0x32, 0x00, 0x23, 0x00, 0xF0, + 0xF9, 0xFC, 0x32, 0x1A, 0x08, 0x92, 0x65, 0xEB, 0x01, 0x0B, 0xDD, 0xE9, + 0x02, 0x15, 0xD9, 0xF8, 0x0C, 0x20, 0xD9, 0xF8, 0x10, 0x30, 0xA2, 0xFB, + 0x01, 0x06, 0x03, 0xFB, 0x01, 0x61, 0x02, 0xFB, 0x05, 0x11, 0x4F, 0xF4, + 0x80, 0x32, 0x00, 0x23, 0x00, 0xF0, 0xE4, 0xFC, 0xB9, 0xF9, 0x00, 0x30, + 0xB9, 0xF9, 0x08, 0x20, 0x13, 0x44, 0xDD, 0xE9, 0x04, 0x27, 0xA3, 0xFB, + 0x02, 0x5C, 0xDE, 0x17, 0x06, 0xFB, 0x02, 0xC2, 0x03, 0xFB, 0x07, 0x26, + 0xB9, 0xF9, 0x04, 0x30, 0x0A, 0x9A, 0xDF, 0x17, 0xA3, 0xFB, 0x02, 0xC8, + 0x07, 0xFB, 0x02, 0x82, 0x03, 0xFB, 0x04, 0x22, 0x15, 0xEB, 0x0C, 0x03, + 0x56, 0x41, 0x1C, 0x1A, 0x66, 0xEB, 0x01, 0x06, 0xDD, 0xE9, 0x00, 0x12, + 0xD9, 0xF8, 0x1C, 0x30, 0xD9, 0xF8, 0x20, 0x50, 0xA3, 0xFB, 0x01, 0x07, + 0x05, 0xFB, 0x01, 0x71, 0x03, 0xFB, 0x02, 0x11, 0x4F, 0xF4, 0x80, 0x32, + 0x00, 0x23, 0x00, 0xF0, 0xB5, 0xFC, 0xDD, 0xE9, 0x06, 0x23, 0xC9, 0xF8, + 0x24, 0x20, 0x24, 0x1A, 0xC9, 0xF8, 0x28, 0x30, 0x66, 0xEB, 0x01, 0x06, + 0xD9, 0xF8, 0x0C, 0x10, 0xD9, 0xF8, 0x10, 0x20, 0xC9, 0xF8, 0x1C, 0x10, + 0xC9, 0xF8, 0x20, 0x20, 0x08, 0x9A, 0xC9, 0xF8, 0x14, 0x20, 0xC9, 0xF8, + 0x18, 0xB0, 0xC9, 0xF8, 0x0C, 0x40, 0xC9, 0xF8, 0x10, 0x60, 0x08, 0x9A, + 0x4F, 0xF4, 0x00, 0x40, 0x10, 0x18, 0x4B, 0xF1, 0x00, 0x01, 0x4F, 0xF4, + 0x80, 0x32, 0x00, 0x23, 0x00, 0xF0, 0x90, 0xFC, 0xAA, 0xF8, 0x02, 0x00, + 0x4F, 0xF4, 0x00, 0x40, 0x20, 0x18, 0x46, 0xF1, 0x00, 0x01, 0x4F, 0xF4, + 0x80, 0x32, 0x00, 0x23, 0x00, 0xF0, 0x84, 0xFC, 0xAA, 0xF8, 0x00, 0x00, + 0x0B, 0xB0, 0xBD, 0xE8, 0xF0, 0x8F, 0xC0, 0xEB, 0x00, 0x10, 0x12, 0x4A, + 0x00, 0xEB, 0x40, 0x00, 0x10, 0xB5, 0x10, 0x44, 0x42, 0x69, 0x83, 0x69, + 0x42, 0x62, 0x83, 0x62, 0xC2, 0x68, 0x03, 0x69, 0xC2, 0x61, 0x03, 0x62, + 0xB1, 0xF9, 0x02, 0x20, 0xD3, 0x17, 0x1B, 0x04, 0x43, 0xEA, 0x12, 0x43, + 0x12, 0x04, 0x42, 0x61, 0x83, 0x61, 0xB1, 0xF9, 0x00, 0x10, 0xCA, 0x17, + 0x12, 0x04, 0x42, 0xEA, 0x11, 0x42, 0x09, 0x04, 0xC1, 0x60, 0x02, 0x61, + 0x10, 0xBD, 0x00, 0x00, 0xD8, 0x20, 0x01, 0x00, 0x78, 0x24, 0x10, 0x00, + 0x90, 0x81, 0x10, 0x00, 0xC2, 0xF1, 0x10, 0x03, 0x50, 0x43, 0x01, 0xFB, + 0x03, 0x00, 0x00, 0x11, 0x70, 0x47, 0x50, 0x21, 0x20, 0x48, 0x00, 0xF0, + 0xEE, 0xBC, 0x1F, 0x4A, 0x02, 0xEB, 0xC0, 0x00, 0x00, 0xF0, 0x27, 0xB8, + 0x7C, 0xB5, 0x0E, 0x46, 0x1B, 0x49, 0x15, 0x46, 0x01, 0xEB, 0xC0, 0x04, + 0x31, 0x46, 0x68, 0x46, 0x00, 0xF0, 0x1D, 0xF8, 0x01, 0x99, 0x60, 0x68, + 0x2A, 0x46, 0xFF, 0xF7, 0xE1, 0xFF, 0x60, 0x60, 0x00, 0x99, 0x20, 0x68, + 0x2A, 0x46, 0xFF, 0xF7, 0xDB, 0xFF, 0x20, 0x60, 0x21, 0x46, 0x30, 0x46, + 0x00, 0xF0, 0x16, 0xF8, 0x7C, 0xBD, 0x0F, 0x4A, 0x02, 0xEB, 0xC0, 0x00, + 0x00, 0xF0, 0x07, 0xB8, 0x0A, 0x46, 0x0C, 0x49, 0x01, 0xEB, 0xC0, 0x01, + 0x10, 0x46, 0x00, 0xF0, 0x09, 0xB8, 0xB1, 0xF9, 0x02, 0x20, 0x12, 0x02, + 0x42, 0x60, 0xB1, 0xF9, 0x00, 0x10, 0x09, 0x02, 0x01, 0x60, 0x70, 0x47, + 0x4A, 0x68, 0x80, 0x32, 0x12, 0x12, 0x42, 0x80, 0x09, 0x68, 0x80, 0x31, + 0x09, 0x12, 0x01, 0x80, 0x70, 0x47, 0x00, 0x00, 0x52, 0x83, 0x10, 0x00, + 0x38, 0xB5, 0x04, 0x46, 0x00, 0x88, 0xFF, 0x49, 0x80, 0x08, 0x02, 0x23, + 0x00, 0x90, 0x1A, 0x46, 0xA1, 0xF1, 0x10, 0x00, 0x00, 0xF0, 0x59, 0xFB, + 0xFA, 0x49, 0x60, 0x68, 0x5C, 0x39, 0x08, 0x60, 0x38, 0xBD, 0xF9, 0x4A, + 0x10, 0xB5, 0x00, 0xEB, 0x00, 0x10, 0x02, 0xEB, 0x80, 0x00, 0x4A, 0x88, + 0x42, 0x80, 0x0A, 0x88, 0x20, 0xF8, 0x06, 0x2B, 0xCA, 0x88, 0x20, 0xF8, + 0x02, 0x29, 0x8A, 0x88, 0x20, 0xF8, 0x06, 0x2B, 0x4A, 0x89, 0x20, 0xF8, + 0x0A, 0x2B, 0x0A, 0x89, 0x20, 0xF8, 0x0C, 0x2C, 0x00, 0x22, 0xC2, 0x62, + 0x82, 0x62, 0xB1, 0xF9, 0x02, 0x30, 0x40, 0xE9, 0x02, 0x32, 0xB1, 0xF9, + 0x00, 0x10, 0xE0, 0xE8, 0x02, 0x12, 0xE7, 0x49, 0x5C, 0x39, 0x01, 0xF1, + 0x5C, 0x02, 0x89, 0x6E, 0x1C, 0xCA, 0x1C, 0xC0, 0x1E, 0xC0, 0x01, 0x60, + 0x10, 0xBD, 0x70, 0xB5, 0xB0, 0xF9, 0x02, 0x30, 0xB0, 0xF9, 0x06, 0x20, + 0xB0, 0xF9, 0x0A, 0x40, 0x9B, 0x1A, 0x12, 0x1B, 0x9C, 0x1A, 0xB0, 0xF9, + 0x00, 0x30, 0xB0, 0xF9, 0x04, 0x20, 0xB0, 0xF9, 0x08, 0x50, 0x9B, 0x1A, + 0x52, 0x1B, 0x9D, 0x1A, 0x02, 0x6C, 0xC1, 0xF1, 0x80, 0x03, 0x4A, 0x43, + 0xD6, 0x17, 0x5C, 0x43, 0x02, 0xEB, 0x56, 0x62, 0x04, 0xEB, 0xE2, 0x12, + 0x02, 0x64, 0xC2, 0x6B, 0x6B, 0x43, 0x4A, 0x43, 0xD1, 0x17, 0x02, 0xEB, + 0x51, 0x61, 0x03, 0xEB, 0xE1, 0x11, 0xC1, 0x63, 0x70, 0xBD, 0x70, 0xB5, + 0x15, 0x46, 0xCE, 0x4A, 0x00, 0xEB, 0x00, 0x10, 0x02, 0xEB, 0x80, 0x04, + 0x20, 0x46, 0x00, 0xF0, 0x84, 0xFA, 0x29, 0x7A, 0x20, 0x46, 0xFF, 0xF7, + 0xCA, 0xFF, 0xB4, 0xF9, 0x02, 0x00, 0xE0, 0x60, 0xB4, 0xF9, 0x06, 0x10, + 0x40, 0x1A, 0x20, 0x61, 0xB4, 0xF9, 0x00, 0x00, 0x60, 0x61, 0xB4, 0xF9, + 0x04, 0x10, 0x40, 0x1A, 0xA0, 0x61, 0x70, 0xBD, 0x2D, 0xE9, 0xF7, 0x4F, + 0x8E, 0xB0, 0x00, 0x25, 0x05, 0x95, 0x06, 0x95, 0x07, 0x95, 0x02, 0x24, + 0x08, 0x95, 0x09, 0x95, 0x0A, 0x95, 0x0B, 0x95, 0x05, 0xAF, 0x0C, 0x95, + 0xCD, 0xE9, 0x01, 0x47, 0x8C, 0x46, 0x4F, 0xF0, 0x01, 0x0A, 0xB6, 0x4B, + 0x06, 0x46, 0x03, 0x94, 0x50, 0x3B, 0x52, 0x46, 0x21, 0x46, 0x60, 0x46, + 0xCD, 0xF8, 0x00, 0xA0, 0x04, 0x94, 0x00, 0xF0, 0x24, 0xFB, 0xB0, 0x48, + 0x05, 0xAA, 0x02, 0x23, 0x11, 0x46, 0x20, 0x38, 0x00, 0x94, 0x00, 0xF0, + 0xFA, 0xFA, 0x0D, 0xF1, 0x24, 0x08, 0xCD, 0xE9, 0x01, 0x48, 0x06, 0xF1, + 0x1C, 0x03, 0x02, 0x22, 0x03, 0x94, 0x04, 0x94, 0x9B, 0x46, 0x11, 0x46, + 0x05, 0xA8, 0x00, 0x94, 0x00, 0xF0, 0x0D, 0xFB, 0x4F, 0xF4, 0x7A, 0x79, + 0x02, 0x23, 0x1A, 0x46, 0x59, 0x46, 0x09, 0xA8, 0xCD, 0xF8, 0x00, 0x90, + 0x00, 0xF0, 0x87, 0xFA, 0x05, 0x95, 0x06, 0x95, 0x07, 0x95, 0x08, 0x95, + 0x09, 0x95, 0x0A, 0x95, 0x0B, 0x95, 0x0C, 0x95, 0xCD, 0xE9, 0x01, 0x47, + 0x9A, 0x4B, 0x03, 0x94, 0x50, 0x3B, 0x01, 0x22, 0x02, 0x21, 0xCD, 0xF8, + 0x00, 0xA0, 0x04, 0x94, 0x10, 0x98, 0x00, 0xF0, 0xEE, 0xFA, 0x95, 0x48, + 0x05, 0xAA, 0x02, 0x23, 0x11, 0x46, 0x20, 0x38, 0x00, 0x94, 0x00, 0xF0, + 0xC4, 0xFA, 0xCD, 0xE9, 0x01, 0x48, 0x03, 0x94, 0x04, 0x94, 0x06, 0xF1, + 0x2C, 0x03, 0x00, 0x94, 0x02, 0x22, 0x1C, 0x46, 0x11, 0x46, 0x05, 0xA8, + 0x00, 0xF0, 0xD9, 0xFA, 0x02, 0x23, 0x1A, 0x46, 0x21, 0x46, 0x09, 0xA8, + 0xCD, 0xF8, 0x00, 0x90, 0x00, 0xF0, 0x55, 0xFA, 0x11, 0xB0, 0xBD, 0xE8, + 0xF0, 0x8F, 0x2D, 0xE9, 0xF0, 0x4F, 0x89, 0xB0, 0x00, 0x26, 0x01, 0x24, + 0x05, 0x96, 0x06, 0x96, 0x0D, 0xF1, 0x14, 0x0A, 0x07, 0x96, 0xCD, 0xE9, + 0x01, 0x4A, 0x05, 0x46, 0x00, 0xF1, 0x0C, 0x03, 0x4F, 0xF0, 0x02, 0x09, + 0x7C, 0x48, 0x93, 0x46, 0x0F, 0x46, 0x03, 0x94, 0x98, 0x46, 0x4A, 0x46, + 0x21, 0x46, 0x50, 0x38, 0xCD, 0xF8, 0x00, 0x90, 0x04, 0x94, 0x00, 0xF0, + 0xB0, 0xFA, 0xB5, 0xF9, 0x02, 0x00, 0x05, 0x99, 0x01, 0x23, 0x40, 0x1A, + 0x05, 0x90, 0x00, 0x90, 0x02, 0x22, 0x06, 0xA9, 0x38, 0x46, 0x00, 0xF0, + 0x44, 0xFA, 0x4F, 0xF4, 0x7A, 0x77, 0x41, 0x46, 0x01, 0x23, 0x02, 0x22, + 0x08, 0x46, 0x00, 0x97, 0x00, 0xF0, 0x3B, 0xFA, 0x42, 0x46, 0x02, 0x23, + 0x06, 0xA9, 0x10, 0x46, 0x00, 0x94, 0x00, 0xF0, 0x50, 0xFA, 0x41, 0x46, + 0x01, 0x23, 0x02, 0x22, 0x08, 0x46, 0x00, 0x97, 0x00, 0xF0, 0x11, 0xFA, + 0x05, 0x96, 0x06, 0x96, 0x07, 0x96, 0xCD, 0xE9, 0x01, 0x4A, 0x62, 0x48, + 0x05, 0xF1, 0x14, 0x03, 0x03, 0x94, 0x1E, 0x46, 0x02, 0x22, 0x01, 0x21, + 0x50, 0x38, 0xCD, 0xF8, 0x00, 0x90, 0x04, 0x94, 0x00, 0xF0, 0x7B, 0xFA, + 0xB5, 0xF9, 0x00, 0x00, 0x05, 0x99, 0x01, 0x23, 0x40, 0x1A, 0x05, 0x90, + 0x00, 0x90, 0x02, 0x22, 0x06, 0xA9, 0x58, 0x46, 0x00, 0xF0, 0x0F, 0xFA, + 0x31, 0x46, 0x01, 0x23, 0x02, 0x22, 0x08, 0x46, 0x00, 0x97, 0x00, 0xF0, + 0x08, 0xFA, 0x32, 0x46, 0x02, 0x23, 0x06, 0xA9, 0x10, 0x46, 0x00, 0x94, + 0x00, 0xF0, 0x1D, 0xFA, 0x31, 0x46, 0x01, 0x23, 0x02, 0x22, 0x08, 0x46, + 0x00, 0x97, 0x00, 0xF0, 0xDE, 0xF9, 0x09, 0xB0, 0x87, 0xE7, 0x2D, 0xE9, + 0xF7, 0x4F, 0x8A, 0xB0, 0x00, 0x26, 0x05, 0x96, 0x06, 0x96, 0x08, 0x96, + 0x09, 0x96, 0x01, 0x24, 0x0D, 0xF1, 0x14, 0x08, 0x07, 0x96, 0x02, 0x25, + 0xCD, 0xE9, 0x01, 0x48, 0xCD, 0xE9, 0x03, 0x54, 0x07, 0x46, 0x41, 0x4B, + 0x07, 0xF1, 0x1C, 0x00, 0x48, 0x3B, 0x2A, 0x46, 0x29, 0x46, 0x82, 0x46, + 0x00, 0x95, 0x00, 0xF0, 0x3C, 0xFA, 0x0D, 0xF1, 0x20, 0x09, 0xCD, 0xE9, + 0x01, 0x59, 0x3A, 0x48, 0xCD, 0xE9, 0x03, 0x45, 0x53, 0x46, 0x02, 0x22, + 0x01, 0x21, 0x50, 0x38, 0x00, 0x95, 0x00, 0xF0, 0x2E, 0xFA, 0x07, 0xA8, + 0xCD, 0xE9, 0x01, 0x40, 0x33, 0x4B, 0x03, 0x94, 0x48, 0x3B, 0x02, 0x22, + 0x01, 0x21, 0x08, 0xA8, 0x00, 0x95, 0x04, 0x94, 0x00, 0xF0, 0x21, 0xFA, + 0xDF, 0xF8, 0xB8, 0xA0, 0x07, 0x99, 0xAA, 0xF1, 0x5C, 0x0A, 0x4F, 0xF4, + 0x7A, 0x7B, 0xDA, 0xF8, 0x00, 0x00, 0x01, 0x23, 0x08, 0x44, 0x05, 0xA9, + 0x07, 0x90, 0x02, 0x22, 0xCD, 0xF8, 0x00, 0xB0, 0x08, 0x46, 0x00, 0xF0, + 0xAE, 0xF9, 0x07, 0x98, 0x00, 0x90, 0x01, 0x23, 0x02, 0x22, 0x05, 0xA8, + 0x0B, 0x99, 0x00, 0xF0, 0x8A, 0xF9, 0x08, 0x96, 0x09, 0x96, 0x05, 0x96, + 0x06, 0x96, 0x07, 0x96, 0xCD, 0xE9, 0x01, 0x48, 0xCD, 0xE9, 0x03, 0x54, + 0x02, 0x22, 0x07, 0xF1, 0x2C, 0x00, 0x0A, 0xF1, 0x14, 0x03, 0x11, 0x46, + 0x06, 0x46, 0x00, 0x95, 0x00, 0xF0, 0xF3, 0xF9, 0xCD, 0xE9, 0x01, 0x59, + 0xCD, 0xE9, 0x03, 0x45, 0x33, 0x46, 0x02, 0x22, 0x01, 0x21, 0x0A, 0xF1, + 0x0C, 0x00, 0x00, 0x95, 0x00, 0xF0, 0xE7, 0xF9, 0x07, 0xA8, 0xCD, 0xE9, + 0x01, 0x40, 0x03, 0x94, 0x0A, 0xF1, 0x14, 0x03, 0x02, 0x22, 0x01, 0x21, + 0x08, 0xA8, 0x00, 0x95, 0x04, 0x94, 0x00, 0xF0, 0xDA, 0xF9, 0x07, 0x99, + 0xDA, 0xF8, 0x00, 0x00, 0x01, 0x23, 0x08, 0x44, 0x05, 0xA9, 0x07, 0x90, + 0x02, 0x22, 0xCD, 0xF8, 0x00, 0xB0, 0x08, 0x46, 0x00, 0xF0, 0x6D, 0xF9, + 0x07, 0x98, 0x00, 0x90, 0x01, 0x23, 0x02, 0x22, 0x05, 0xA8, 0x0C, 0x99, + 0x00, 0xF0, 0x49, 0xF9, 0x0D, 0xB0, 0xF2, 0xE6, 0xDC, 0x24, 0x10, 0x00, + 0xA4, 0x83, 0x10, 0x00, 0x2D, 0xE9, 0xF0, 0x43, 0x8D, 0xB0, 0x00, 0x25, + 0x02, 0x24, 0x05, 0x95, 0x06, 0x95, 0x07, 0x95, 0x08, 0x95, 0x09, 0x95, + 0x0A, 0x95, 0x0B, 0x95, 0x05, 0xAF, 0x0C, 0x95, 0xCD, 0xE9, 0x01, 0x47, + 0x06, 0x46, 0x06, 0xF1, 0x1C, 0x03, 0x03, 0x94, 0x04, 0x94, 0x99, 0x46, + 0x22, 0x46, 0x21, 0x46, 0x70, 0x48, 0x00, 0x94, 0x00, 0xF0, 0xA3, 0xF9, + 0x0D, 0xF1, 0x24, 0x08, 0xCD, 0xE9, 0x01, 0x48, 0x6C, 0x4B, 0x02, 0x22, + 0x03, 0x94, 0x04, 0x94, 0x10, 0x33, 0x11, 0x46, 0x05, 0xA8, 0x00, 0x94, + 0x00, 0xF0, 0x95, 0xF9, 0x67, 0x49, 0x02, 0x23, 0x4A, 0x46, 0x40, 0x31, + 0x09, 0xA8, 0x00, 0x94, 0x00, 0xF0, 0x49, 0xF9, 0x05, 0x95, 0x06, 0x95, + 0x07, 0x95, 0x08, 0x95, 0x09, 0x95, 0x0A, 0x95, 0x0B, 0x95, 0x0C, 0x95, + 0xCD, 0xE9, 0x01, 0x47, 0x06, 0xF1, 0x2C, 0x03, 0x02, 0x22, 0x03, 0x94, + 0x04, 0x94, 0x1D, 0x46, 0x11, 0x46, 0x5B, 0x48, 0x00, 0x94, 0x00, 0xF0, + 0x78, 0xF9, 0xCD, 0xE9, 0x01, 0x48, 0x58, 0x4B, 0x02, 0x22, 0x03, 0x94, + 0x04, 0x94, 0x10, 0x33, 0x11, 0x46, 0x05, 0xA8, 0x00, 0x94, 0x00, 0xF0, + 0x6C, 0xF9, 0x53, 0x49, 0x02, 0x23, 0x2A, 0x46, 0x40, 0x31, 0x09, 0xA8, + 0x00, 0x94, 0x00, 0xF0, 0x20, 0xF9, 0x0D, 0xB0, 0xBD, 0xE8, 0xF0, 0x83, + 0x2D, 0xE9, 0xF0, 0x47, 0x8A, 0xB0, 0x00, 0x26, 0x07, 0x96, 0x08, 0x96, + 0x05, 0x96, 0x01, 0x25, 0x0D, 0xF1, 0x1C, 0x08, 0x06, 0x96, 0x02, 0x27, + 0xCD, 0xE9, 0x01, 0x58, 0xCD, 0xE9, 0x03, 0x75, 0x00, 0xF1, 0x0C, 0x03, + 0x04, 0x46, 0x9A, 0x46, 0x3A, 0x46, 0x39, 0x46, 0x42, 0x48, 0x00, 0x97, + 0x00, 0xF0, 0x47, 0xF9, 0x20, 0x6C, 0x00, 0x90, 0x3F, 0x48, 0x01, 0x23, + 0x02, 0x22, 0x05, 0xA9, 0x18, 0x38, 0x00, 0xF0, 0xDE, 0xF8, 0x4F, 0xF4, + 0x80, 0x79, 0x05, 0xA9, 0x01, 0x23, 0x02, 0x22, 0x08, 0x46, 0xCD, 0xF8, + 0x00, 0x90, 0x00, 0xF0, 0xB8, 0xF8, 0x02, 0x23, 0x52, 0x46, 0x05, 0xA9, + 0x07, 0xA8, 0x00, 0x95, 0x00, 0xF0, 0xE9, 0xF8, 0x07, 0x96, 0x08, 0x96, + 0x05, 0x96, 0x06, 0x96, 0xCD, 0xE9, 0x01, 0x58, 0xCD, 0xE9, 0x03, 0x75, + 0x04, 0xF1, 0x14, 0x03, 0x02, 0x22, 0x1E, 0x46, 0x11, 0x46, 0x2D, 0x48, + 0x00, 0x97, 0x00, 0xF0, 0x1C, 0xF9, 0xE0, 0x6B, 0x00, 0x90, 0x2A, 0x48, + 0x01, 0x23, 0x02, 0x22, 0x05, 0xA9, 0x18, 0x38, 0x00, 0xF0, 0xB3, 0xF8, + 0x05, 0xA9, 0x01, 0x23, 0x02, 0x22, 0x08, 0x46, 0xCD, 0xF8, 0x00, 0x90, + 0x00, 0xF0, 0x8F, 0xF8, 0x02, 0x23, 0x32, 0x46, 0x05, 0xA9, 0x07, 0xA8, + 0x00, 0x95, 0x00, 0xF0, 0xC0, 0xF8, 0x0A, 0xB0, 0xBD, 0xE8, 0xF0, 0x87, + 0x7F, 0xB5, 0x0D, 0x46, 0x1D, 0x49, 0x00, 0xEB, 0x00, 0x10, 0x01, 0xEB, + 0x80, 0x04, 0x16, 0x46, 0x29, 0x46, 0x20, 0x46, 0x00, 0xF0, 0x23, 0xF8, + 0x31, 0x7A, 0x20, 0x46, 0xFF, 0xF7, 0x69, 0xFD, 0x20, 0x46, 0xFF, 0xF7, + 0x8D, 0xFF, 0x20, 0x46, 0xFF, 0xF7, 0x2C, 0xFF, 0x00, 0x20, 0x00, 0x90, + 0x01, 0x90, 0x02, 0x90, 0x03, 0x90, 0x02, 0xAA, 0x69, 0x46, 0x20, 0x46, + 0xFF, 0xF7, 0x89, 0xFE, 0x02, 0xAA, 0x69, 0x46, 0x20, 0x46, 0xFF, 0xF7, + 0x0E, 0xFE, 0x02, 0xAA, 0x69, 0x46, 0x20, 0x46, 0xFF, 0xF7, 0x94, 0xFD, + 0xA0, 0x89, 0x68, 0x80, 0xA0, 0x8A, 0x28, 0x80, 0x7F, 0xBD, 0xC2, 0x88, + 0x42, 0x81, 0x82, 0x88, 0x02, 0x81, 0x42, 0x88, 0xC2, 0x80, 0x02, 0x88, + 0x82, 0x80, 0x4A, 0x88, 0x42, 0x80, 0x09, 0x88, 0x01, 0x80, 0x70, 0x47, + 0x9C, 0x24, 0x10, 0x00, 0xA4, 0x83, 0x10, 0x00, 0x00, 0x20, 0x70, 0x47, + 0x4F, 0xF4, 0x58, 0x70, 0x70, 0x47, 0x00, 0x00, 0x00, 0x21, 0x01, 0x60, + 0x08, 0x46, 0x70, 0x47, 0x30, 0xB5, 0x0A, 0x68, 0x12, 0xB1, 0x0B, 0x46, + 0xC4, 0x6B, 0x09, 0xE0, 0x00, 0x22, 0x08, 0x60, 0xC0, 0xE9, 0x03, 0x21, + 0x0B, 0xE0, 0x00, 0xBF, 0x02, 0xF1, 0x0C, 0x03, 0xD2, 0x68, 0x12, 0xB1, + 0xD5, 0x6B, 0xA5, 0x42, 0xF8, 0xDC, 0x1A, 0x68, 0xC0, 0xE9, 0x03, 0x21, + 0x18, 0x60, 0x00, 0x20, 0x30, 0xBD, 0x00, 0x68, 0x00, 0x22, 0x01, 0xE0, + 0xC0, 0x68, 0x52, 0x1C, 0x8A, 0x42, 0x01, 0xD0, 0x00, 0x28, 0xF9, 0xD1, + 0x70, 0x47, 0x00, 0x68, 0x70, 0x47, 0x02, 0x69, 0x0A, 0xB1, 0x11, 0x68, + 0x31, 0xB9, 0x6F, 0xF0, 0x04, 0x00, 0x70, 0x47, 0x01, 0xF1, 0x0C, 0x02, + 0xC9, 0x68, 0x39, 0xB1, 0x81, 0x42, 0xF9, 0xD1, 0xC9, 0x68, 0x11, 0x60, + 0x00, 0x21, 0x01, 0x61, 0x08, 0x46, 0x70, 0x47, 0x6F, 0xF0, 0x03, 0x00, + 0x70, 0x47, 0xF0, 0xB5, 0x00, 0x25, 0xDD, 0xF8, 0x14, 0xE0, 0x13, 0xE0, + 0x05, 0xFB, 0x03, 0xF6, 0x00, 0xEB, 0x86, 0x0C, 0x00, 0x24, 0x01, 0xEB, + 0x86, 0x06, 0x07, 0xE0, 0x5C, 0xF8, 0x24, 0x70, 0x97, 0xFB, 0xFE, 0xF7, + 0x46, 0xF8, 0x24, 0x70, 0x64, 0x1C, 0x64, 0xB2, 0x9C, 0x42, 0xF5, 0xDB, + 0x6D, 0x1C, 0x6D, 0xB2, 0x95, 0x42, 0xE9, 0xDB, 0xF0, 0xBD, 0xF0, 0xB5, + 0x00, 0x25, 0xDD, 0xF8, 0x14, 0xE0, 0x13, 0xE0, 0x05, 0xFB, 0x03, 0xF6, + 0x00, 0xEB, 0x86, 0x0C, 0x00, 0x24, 0x01, 0xEB, 0x86, 0x06, 0x07, 0xE0, + 0x5C, 0xF8, 0x24, 0x70, 0x07, 0xFB, 0x0E, 0xF7, 0x46, 0xF8, 0x24, 0x70, + 0x64, 0x1C, 0x64, 0xB2, 0x9C, 0x42, 0xF5, 0xDB, 0x6D, 0x1C, 0x6D, 0xB2, + 0x95, 0x42, 0xE9, 0xDB, 0xF0, 0xBD, 0x2D, 0xE9, 0xF0, 0x47, 0x9A, 0x46, + 0x91, 0x46, 0x00, 0x23, 0x08, 0x9E, 0x16, 0xE0, 0x03, 0xFB, 0x06, 0xF4, + 0x00, 0xEB, 0x84, 0x07, 0x01, 0xEB, 0x84, 0x05, 0x00, 0x22, 0x09, 0xEB, + 0x84, 0x04, 0x08, 0xE0, 0x57, 0xF8, 0x22, 0xC0, 0x55, 0xF8, 0x22, 0x80, + 0xC4, 0x44, 0x44, 0xF8, 0x22, 0xC0, 0x52, 0x1C, 0x52, 0xB2, 0xB2, 0x42, + 0xF4, 0xDB, 0x5B, 0x1C, 0x5B, 0xB2, 0x53, 0x45, 0xE6, 0xDB, 0xBD, 0xE8, + 0xF0, 0x87, 0x2D, 0xE9, 0xF0, 0x47, 0x9A, 0x46, 0x91, 0x46, 0x00, 0x23, + 0x08, 0x9E, 0x17, 0xE0, 0x03, 0xFB, 0x06, 0xF4, 0x00, 0xEB, 0x84, 0x07, + 0x01, 0xEB, 0x84, 0x05, 0x00, 0x22, 0x09, 0xEB, 0x84, 0x04, 0x09, 0xE0, + 0x57, 0xF8, 0x22, 0xC0, 0x55, 0xF8, 0x22, 0x80, 0xAC, 0xEB, 0x08, 0x0C, + 0x44, 0xF8, 0x22, 0xC0, 0x52, 0x1C, 0x52, 0xB2, 0xB2, 0x42, 0xF3, 0xDB, + 0x5B, 0x1C, 0x5B, 0xB2, 0x53, 0x45, 0xE5, 0xDB, 0xDB, 0xE7, 0x2D, 0xE9, + 0xF0, 0x4F, 0x82, 0x46, 0xDD, 0xE9, 0x09, 0x06, 0x00, 0x24, 0xDD, 0xF8, + 0x34, 0xE0, 0x8B, 0x46, 0x82, 0x42, 0x23, 0xD0, 0xBD, 0xE8, 0xF0, 0x8F, + 0x04, 0xFB, 0x02, 0xF1, 0x0A, 0xEB, 0x81, 0x09, 0x0B, 0x9D, 0x04, 0xFB, + 0x0E, 0xF1, 0x00, 0x20, 0x05, 0xEB, 0x81, 0x05, 0x13, 0xE0, 0x00, 0x21, + 0x0E, 0xE0, 0x01, 0xFB, 0x06, 0xF8, 0x03, 0xEB, 0x88, 0x08, 0x59, 0xF8, + 0x21, 0xC0, 0x55, 0xF8, 0x20, 0x70, 0x58, 0xF8, 0x20, 0x80, 0x49, 0x1C, + 0x0C, 0xFB, 0x08, 0x77, 0x45, 0xF8, 0x20, 0x70, 0x91, 0x42, 0xEE, 0xDB, + 0x40, 0x1C, 0xB0, 0x42, 0xE9, 0xDB, 0x64, 0x1C, 0x5C, 0x45, 0xDB, 0xDB, + 0xD8, 0xE7, 0xB2, 0xF1, 0x20, 0x03, 0x0A, 0xD5, 0xC2, 0xF1, 0x20, 0x03, + 0x01, 0xFA, 0x02, 0xF1, 0x20, 0xFA, 0x03, 0xF3, 0x00, 0xFA, 0x02, 0xF0, + 0x41, 0xEA, 0x03, 0x01, 0x70, 0x47, 0x00, 0xFA, 0x03, 0xF1, 0x4F, 0xF0, + 0x00, 0x00, 0x70, 0x47, 0x10, 0xB5, 0x4C, 0x10, 0x84, 0xEA, 0x53, 0x04, + 0x04, 0xD5, 0x40, 0x42, 0xC1, 0xF1, 0x00, 0x01, 0x38, 0xBF, 0x49, 0x1E, + 0x1B, 0x42, 0x04, 0xD5, 0x52, 0x42, 0xC3, 0xF1, 0x00, 0x03, 0x38, 0xBF, + 0x5B, 0x1E, 0x00, 0xF0, 0xD9, 0xF8, 0x14, 0xF0, 0x80, 0x4F, 0x04, 0xD0, + 0x40, 0x42, 0xC1, 0xF1, 0x00, 0x01, 0x38, 0xBF, 0x49, 0x1E, 0x14, 0xF0, + 0x00, 0x4F, 0x04, 0xD0, 0x52, 0x42, 0xC3, 0xF1, 0x00, 0x03, 0x38, 0xBF, + 0x5B, 0x1E, 0x10, 0xBD, 0x03, 0x2A, 0x40, 0xF2, 0x30, 0x80, 0x10, 0xF0, + 0x03, 0x0C, 0x00, 0xF0, 0x15, 0x80, 0x11, 0xF8, 0x01, 0x3B, 0xBC, 0xF1, + 0x02, 0x0F, 0x62, 0x44, 0x98, 0xBF, 0x11, 0xF8, 0x01, 0xCB, 0x00, 0xF8, + 0x01, 0x3B, 0x38, 0xBF, 0x11, 0xF8, 0x01, 0x3B, 0xA2, 0xF1, 0x04, 0x02, + 0x98, 0xBF, 0x00, 0xF8, 0x01, 0xCB, 0x38, 0xBF, 0x00, 0xF8, 0x01, 0x3B, + 0x11, 0xF0, 0x03, 0x03, 0x00, 0xF0, 0x25, 0x80, 0x08, 0x3A, 0xC0, 0xF0, + 0x08, 0x80, 0x51, 0xF8, 0x04, 0x3B, 0x08, 0x3A, 0x51, 0xF8, 0x04, 0xCB, + 0xA0, 0xE8, 0x08, 0x10, 0xF5, 0xE7, 0x12, 0x1D, 0x5C, 0xBF, 0x51, 0xF8, + 0x04, 0x3B, 0x40, 0xF8, 0x04, 0x3B, 0xAF, 0xF3, 0x00, 0x80, 0xD2, 0x07, + 0x24, 0xBF, 0x11, 0xF8, 0x01, 0x3B, 0x11, 0xF8, 0x01, 0xCB, 0x48, 0xBF, + 0x11, 0xF8, 0x01, 0x2B, 0x24, 0xBF, 0x00, 0xF8, 0x01, 0x3B, 0x00, 0xF8, + 0x01, 0xCB, 0x48, 0xBF, 0x00, 0xF8, 0x01, 0x2B, 0x70, 0x47, 0x10, 0xB5, + 0x20, 0x3A, 0xC0, 0xF0, 0x0B, 0x80, 0xB1, 0xE8, 0x18, 0x50, 0x20, 0x3A, + 0xA0, 0xE8, 0x18, 0x50, 0xB1, 0xE8, 0x18, 0x50, 0xA0, 0xE8, 0x18, 0x50, + 0xBF, 0xF4, 0xF5, 0xAF, 0x5F, 0xEA, 0x02, 0x7C, 0x24, 0xBF, 0xB1, 0xE8, + 0x18, 0x50, 0xA0, 0xE8, 0x18, 0x50, 0x44, 0xBF, 0x18, 0xC9, 0x18, 0xC0, + 0xBD, 0xE8, 0x10, 0x40, 0x5F, 0xEA, 0x82, 0x7C, 0x24, 0xBF, 0x51, 0xF8, + 0x04, 0x3B, 0x40, 0xF8, 0x04, 0x3B, 0x08, 0xBF, 0x70, 0x47, 0xD2, 0x07, + 0x28, 0xBF, 0x31, 0xF8, 0x02, 0x3B, 0x48, 0xBF, 0x11, 0xF8, 0x01, 0x2B, + 0x28, 0xBF, 0x20, 0xF8, 0x02, 0x3B, 0x48, 0xBF, 0x00, 0xF8, 0x01, 0x2B, + 0x70, 0x47, 0x02, 0xF0, 0xFF, 0x03, 0x43, 0xEA, 0x03, 0x22, 0x42, 0xEA, + 0x02, 0x42, 0x00, 0xF0, 0x02, 0xB8, 0x4F, 0xF0, 0x00, 0x02, 0x04, 0x29, + 0xC0, 0xF0, 0x12, 0x80, 0x10, 0xF0, 0x03, 0x0C, 0x00, 0xF0, 0x1B, 0x80, + 0xCC, 0xF1, 0x04, 0x0C, 0xBC, 0xF1, 0x02, 0x0F, 0x18, 0xBF, 0x00, 0xF8, + 0x01, 0x2B, 0xA8, 0xBF, 0x20, 0xF8, 0x02, 0x2B, 0xA1, 0xEB, 0x0C, 0x01, + 0x00, 0xF0, 0x0D, 0xB8, 0x5F, 0xEA, 0xC1, 0x7C, 0x24, 0xBF, 0x00, 0xF8, + 0x01, 0x2B, 0x00, 0xF8, 0x01, 0x2B, 0x48, 0xBF, 0x00, 0xF8, 0x01, 0x2B, + 0x70, 0x47, 0x4F, 0xF0, 0x00, 0x02, 0x00, 0xB5, 0x13, 0x46, 0x94, 0x46, + 0x96, 0x46, 0x20, 0x39, 0x22, 0xBF, 0xA0, 0xE8, 0x0C, 0x50, 0xA0, 0xE8, + 0x0C, 0x50, 0xB1, 0xF1, 0x20, 0x01, 0xBF, 0xF4, 0xF7, 0xAF, 0x09, 0x07, + 0x28, 0xBF, 0xA0, 0xE8, 0x0C, 0x50, 0x48, 0xBF, 0x0C, 0xC0, 0x5D, 0xF8, + 0x04, 0xEB, 0x89, 0x00, 0x28, 0xBF, 0x40, 0xF8, 0x04, 0x2B, 0x08, 0xBF, + 0x70, 0x47, 0x48, 0xBF, 0x20, 0xF8, 0x02, 0x2B, 0x11, 0xF0, 0x80, 0x4F, + 0x18, 0xBF, 0x00, 0xF8, 0x01, 0x2B, 0x70, 0x47, 0x53, 0xEA, 0x02, 0x0C, + 0x00, 0xF0, 0x69, 0x80, 0x2D, 0xE9, 0xF0, 0x4B, 0x4F, 0xF0, 0x00, 0x06, + 0x00, 0x2B, 0x1F, 0xBF, 0xB3, 0xFA, 0x83, 0xF5, 0x03, 0xFA, 0x05, 0xF4, + 0x24, 0xFA, 0x05, 0xF6, 0x5E, 0x40, 0x12, 0xBF, 0x16, 0x43, 0xB2, 0xFA, + 0x82, 0xF5, 0x02, 0xFA, 0x05, 0xF4, 0xC5, 0xF1, 0x20, 0x05, 0x1E, 0xBF, + 0x22, 0xFA, 0x05, 0xFC, 0x44, 0xEA, 0x0C, 0x04, 0x20, 0x35, 0x56, 0xEA, + 0x04, 0x4C, 0x4F, 0xEA, 0x14, 0x44, 0x18, 0xBF, 0x64, 0x1C, 0x4F, 0xF0, + 0x00, 0x08, 0x4F, 0xF0, 0x00, 0x09, 0x90, 0x42, 0x71, 0xEB, 0x03, 0x0C, + 0x39, 0xD3, 0x00, 0x29, 0x19, 0xBF, 0xB1, 0xFA, 0x81, 0xF7, 0x01, 0xFA, + 0x07, 0xF6, 0xB0, 0xFA, 0x80, 0xF7, 0x00, 0xFA, 0x07, 0xF6, 0xC7, 0xF1, + 0x20, 0x07, 0x1E, 0xBF, 0x20, 0xFA, 0x07, 0xFC, 0x46, 0xEA, 0x0C, 0x06, + 0x20, 0x37, 0xB6, 0xFB, 0xF4, 0xFC, 0xA7, 0xEB, 0x05, 0x07, 0x10, 0x3F, + 0x07, 0xF0, 0x1F, 0x0B, 0xCB, 0xF1, 0x20, 0x06, 0x0C, 0xFA, 0x0B, 0xFB, + 0x2C, 0xFA, 0x06, 0xF6, 0x44, 0xBF, 0xB3, 0x46, 0x00, 0x26, 0x20, 0x2F, + 0xA4, 0xBF, 0x5E, 0x46, 0x4F, 0xF0, 0x00, 0x0B, 0x5B, 0xEA, 0x06, 0x0C, + 0x08, 0xBF, 0x4F, 0xF0, 0x01, 0x0B, 0x19, 0xEB, 0x0B, 0x09, 0xAB, 0xFB, + 0x02, 0x7C, 0x48, 0xEB, 0x06, 0x08, 0xC0, 0x1B, 0x06, 0xFB, 0x02, 0xCC, + 0x0B, 0xFB, 0x03, 0xCC, 0x71, 0xEB, 0x0C, 0x01, 0xC1, 0xE7, 0x0B, 0x46, + 0x02, 0x46, 0x41, 0x46, 0x48, 0x46, 0xBD, 0xE8, 0xF0, 0x8B, 0x13, 0xB5, + 0x4F, 0xF0, 0x00, 0x00, 0x4F, 0xF0, 0x00, 0x01, 0xAF, 0xF3, 0x00, 0x80, + 0xBD, 0xE8, 0x1C, 0x40, 0x70, 0x47, 0x04, 0x46, 0xAF, 0xF3, 0x00, 0x80, + 0x20, 0x46, 0xF0, 0xF7, 0xAB, 0xFA, 0x70, 0x47, 0x01, 0x49, 0x18, 0x20, + 0xAB, 0xBE, 0xFE, 0xE7, 0x26, 0x00, 0x02, 0x00, 0x2D, 0xE9, 0xF0, 0x47, + 0x88, 0xB0, 0x16, 0x46, 0x8A, 0x46, 0x05, 0x46, 0x1F, 0x46, 0xFF, 0x22, + 0x1A, 0x21, 0x68, 0x46, 0xFF, 0xF7, 0x1F, 0xFF, 0x00, 0x24, 0x22, 0x46, + 0x01, 0x20, 0x00, 0x21, 0xFF, 0xF7, 0x6B, 0xFE, 0x80, 0x46, 0x89, 0x46, + 0x30, 0x40, 0x39, 0x40, 0x08, 0x43, 0x0C, 0xD0, 0x00, 0x23, 0x22, 0x46, + 0x19, 0x46, 0x68, 0x46, 0x00, 0xF0, 0x49, 0xF9, 0x26, 0xEA, 0x08, 0x06, + 0x27, 0xEA, 0x09, 0x07, 0x56, 0xEA, 0x07, 0x00, 0x02, 0xD0, 0x64, 0x1C, + 0x40, 0x2C, 0xE4, 0xD3, 0x00, 0x22, 0x10, 0x46, 0x4F, 0xF0, 0x01, 0x08, + 0xEC, 0x46, 0x08, 0xFA, 0x02, 0xF1, 0x11, 0xEA, 0x0A, 0x0F, 0x0F, 0xD0, + 0x00, 0xEB, 0x80, 0x03, 0x00, 0x21, 0x03, 0xEB, 0xC0, 0x07, 0x01, 0xEB, + 0x47, 0x03, 0x1C, 0xF8, 0x01, 0x60, 0xEC, 0x5C, 0x49, 0x1C, 0x34, 0x40, + 0xEC, 0x54, 0x1A, 0x29, 0xF5, 0xD3, 0x40, 0x1C, 0x52, 0x1C, 0x20, 0x2A, + 0xE7, 0xD3, 0x08, 0xB0, 0xBD, 0xE8, 0xF0, 0x87, 0x2D, 0xE9, 0xF0, 0x47, + 0x00, 0x25, 0x99, 0x46, 0x16, 0x46, 0x0F, 0x46, 0x82, 0x46, 0x2C, 0x46, + 0x4F, 0xF0, 0x01, 0x08, 0x10, 0xE0, 0x07, 0xEB, 0xE4, 0x00, 0x04, 0xF0, + 0x07, 0x01, 0x00, 0x78, 0x08, 0xFA, 0x01, 0xF2, 0x02, 0x42, 0x06, 0xD0, + 0x4B, 0x46, 0x00, 0x22, 0x21, 0x46, 0x50, 0x46, 0x00, 0xF0, 0x07, 0xF9, + 0x6D, 0x1C, 0x64, 0x1C, 0xB5, 0x42, 0xEC, 0xDB, 0xBD, 0xE8, 0xF0, 0x87, + 0x30, 0xB5, 0x11, 0x24, 0x92, 0xFB, 0xF4, 0xF3, 0x03, 0xEB, 0x83, 0x05, + 0x05, 0xEB, 0xC3, 0x05, 0x92, 0xFB, 0xF4, 0xF3, 0x04, 0xFB, 0x13, 0x22, + 0xD3, 0x17, 0x02, 0xEB, 0x93, 0x73, 0x9C, 0x10, 0x23, 0xF0, 0x03, 0x03, + 0xD2, 0x1A, 0x01, 0xEB, 0x81, 0x03, 0x04, 0xEB, 0x44, 0x04, 0x03, 0xEB, + 0xC1, 0x01, 0x2C, 0x44, 0x00, 0xEB, 0x41, 0x00, 0x12, 0xF0, 0xFF, 0x01, + 0x00, 0x59, 0x07, 0xD0, 0x01, 0x29, 0x08, 0xD0, 0x02, 0x29, 0x09, 0xD0, + 0x03, 0x29, 0x0A, 0xD0, 0x00, 0x20, 0x30, 0xBD, 0x00, 0xF0, 0x3F, 0x00, + 0x30, 0xBD, 0xC0, 0xF3, 0x85, 0x10, 0x30, 0xBD, 0xC0, 0xF3, 0x05, 0x30, + 0x30, 0xBD, 0xC0, 0xF3, 0x85, 0x40, 0x30, 0xBD, 0xFF, 0xF7, 0xCA, 0xBF, + 0x0A, 0x46, 0x00, 0x21, 0xFF, 0xF7, 0xC6, 0xBF, 0x40, 0x5C, 0x70, 0x47, + 0x2D, 0xE9, 0xF0, 0x5F, 0x00, 0x25, 0x17, 0x46, 0x89, 0x46, 0x80, 0x46, + 0x2C, 0x46, 0x11, 0x4E, 0xAA, 0x46, 0x4F, 0xF0, 0x5D, 0x0B, 0x18, 0xE0, + 0x00, 0x20, 0x51, 0x46, 0xBC, 0x42, 0x05, 0xDC, 0x83, 0x19, 0x18, 0xF8, + 0x04, 0x20, 0x83, 0xF8, 0x60, 0x20, 0x02, 0xE0, 0x82, 0x19, 0x82, 0xF8, + 0x60, 0x10, 0x40, 0x1C, 0x64, 0x1C, 0x0D, 0x28, 0xF0, 0xDB, 0x01, 0xF0, + 0x6D, 0xF9, 0x09, 0xEB, 0x05, 0x00, 0xB0, 0x76, 0x86, 0xF8, 0x1B, 0xB0, + 0x6D, 0x1C, 0xBC, 0x42, 0xE4, 0xDB, 0xBD, 0xE8, 0xF0, 0x9F, 0x00, 0x00, + 0x00, 0x00, 0x07, 0x20, 0x2D, 0xE9, 0xF0, 0x47, 0x20, 0x27, 0x00, 0x25, + 0x88, 0x46, 0x06, 0x46, 0x2C, 0x46, 0x4F, 0xF0, 0x01, 0x09, 0x09, 0xFA, + 0x04, 0xF0, 0x10, 0xEA, 0x08, 0x0F, 0x06, 0xD0, 0xE9, 0xB2, 0x1A, 0x22, + 0x30, 0x46, 0xFF, 0xF7, 0xC1, 0xFF, 0xAD, 0x1C, 0x1A, 0x36, 0x64, 0x1C, + 0xBC, 0x42, 0xF0, 0xDB, 0xBD, 0xE8, 0xF0, 0x87, 0x18, 0x22, 0x80, 0x21, + 0xFF, 0xF7, 0xB6, 0xBF, 0x20, 0x22, 0x82, 0x21, 0xAF, 0xF3, 0x00, 0x80, + 0x2D, 0xE9, 0xF7, 0x4F, 0x00, 0x27, 0x93, 0x46, 0x81, 0x46, 0x3E, 0x46, + 0x3C, 0x46, 0x08, 0x25, 0xB8, 0x46, 0xDF, 0xF8, 0x58, 0xA0, 0x25, 0xE0, + 0x00, 0x20, 0x01, 0x46, 0x5C, 0x45, 0x0A, 0xDC, 0x19, 0xF8, 0x04, 0x20, + 0xEE, 0x40, 0x02, 0xFA, 0x08, 0xF2, 0x16, 0x43, 0x00, 0xEB, 0x0A, 0x02, + 0x82, 0xF8, 0x60, 0x60, 0x03, 0xE0, 0x00, 0xEB, 0x0A, 0x02, 0x82, 0xF8, + 0x60, 0x10, 0x19, 0xF8, 0x04, 0x60, 0x40, 0x1C, 0x64, 0x1C, 0x0D, 0x28, + 0xE8, 0xDB, 0xAD, 0x1E, 0xC5, 0xF1, 0x08, 0x08, 0x01, 0xF0, 0x14, 0xF9, + 0x01, 0x98, 0xC1, 0x19, 0x8A, 0xF8, 0x1A, 0x10, 0x5D, 0x21, 0x8A, 0xF8, + 0x1B, 0x10, 0x7F, 0x1C, 0x5C, 0x45, 0xD7, 0xDB, 0xBD, 0xE8, 0xFE, 0x8F, + 0x00, 0x00, 0x07, 0x20, 0x1A, 0x22, 0x85, 0x21, 0xFF, 0xF7, 0x76, 0xBF, + 0x22, 0x22, 0x87, 0x21, 0xFF, 0xF7, 0xC0, 0xBF, 0x70, 0xB5, 0x11, 0x25, + 0x92, 0xFB, 0xF5, 0xF4, 0x04, 0xEB, 0x84, 0x06, 0x06, 0xEB, 0xC4, 0x06, + 0x92, 0xFB, 0xF5, 0xF4, 0x05, 0xFB, 0x14, 0x22, 0xD4, 0x17, 0x02, 0xEB, + 0x94, 0x74, 0xA5, 0x10, 0x24, 0xF0, 0x03, 0x04, 0x14, 0x1B, 0x05, 0xEB, + 0x45, 0x05, 0x01, 0xEB, 0x81, 0x02, 0x35, 0x44, 0x02, 0xEB, 0xC1, 0x01, + 0x05, 0xEB, 0x41, 0x01, 0x0A, 0x18, 0x14, 0xF0, 0xFF, 0x01, 0x10, 0x68, + 0x06, 0xD0, 0x01, 0x29, 0x07, 0xD0, 0x02, 0x29, 0x08, 0xD0, 0x03, 0x29, + 0x0B, 0xD1, 0x08, 0xE0, 0x63, 0xF3, 0x05, 0x00, 0x07, 0xE0, 0x63, 0xF3, + 0x8B, 0x10, 0x04, 0xE0, 0x63, 0xF3, 0x11, 0x30, 0x01, 0xE0, 0x63, 0xF3, + 0x97, 0x40, 0x10, 0x60, 0x70, 0xBD, 0xFF, 0xF7, 0xC9, 0xBF, 0x13, 0x46, + 0x0A, 0x46, 0x00, 0x21, 0xFF, 0xF7, 0xC4, 0xBF, 0x42, 0x54, 0x70, 0x47, + 0xFE, 0xB5, 0x04, 0x46, 0x00, 0x23, 0x01, 0x22, 0x01, 0xA9, 0x18, 0x46, + 0x00, 0xF0, 0x68, 0xFE, 0x9D, 0xF8, 0x04, 0x10, 0x01, 0x20, 0x21, 0xF0, + 0x07, 0x01, 0xA0, 0x40, 0x8D, 0xF8, 0x04, 0x10, 0x02, 0x90, 0x04, 0x22, + 0x02, 0xA9, 0x2B, 0x20, 0x01, 0xF0, 0xD2, 0xF8, 0x9D, 0xF8, 0x04, 0x00, + 0x01, 0x22, 0x40, 0xF0, 0x06, 0x00, 0x8D, 0xF8, 0x00, 0x00, 0x69, 0x46, + 0x00, 0x20, 0x01, 0xF0, 0xC7, 0xF8, 0x17, 0x4E, 0xE0, 0x25, 0x35, 0x73, + 0x4F, 0xF4, 0x20, 0x77, 0x38, 0x46, 0x01, 0xF0, 0x8B, 0xFE, 0x00, 0x23, + 0x01, 0x22, 0x69, 0x46, 0x89, 0x20, 0x00, 0xF0, 0x41, 0xFE, 0x9D, 0xF8, + 0x00, 0x00, 0x01, 0x22, 0x00, 0xF0, 0x01, 0x04, 0x9D, 0xF8, 0x04, 0x00, + 0x69, 0x46, 0x40, 0xF0, 0x07, 0x00, 0x8D, 0xF8, 0x00, 0x00, 0x00, 0x20, + 0x01, 0xF0, 0xAA, 0xF8, 0x35, 0x73, 0x38, 0x46, 0x01, 0xF0, 0x72, 0xFE, + 0x00, 0x23, 0x01, 0x22, 0x69, 0x46, 0x89, 0x20, 0x00, 0xF0, 0x28, 0xFE, + 0x9D, 0xF8, 0x00, 0x00, 0x00, 0xF0, 0x01, 0x00, 0x44, 0xEA, 0x40, 0x00, + 0xFE, 0xBD, 0x00, 0x00, 0x00, 0x00, 0x07, 0x20, 0x2D, 0xE9, 0xFF, 0x41, + 0x04, 0x46, 0x00, 0x23, 0x01, 0x22, 0x01, 0xA9, 0x18, 0x46, 0x00, 0xF0, + 0x15, 0xFE, 0x9D, 0xF8, 0x04, 0x10, 0x22, 0x46, 0x21, 0xF0, 0x07, 0x01, + 0x8D, 0xF8, 0x04, 0x10, 0x01, 0x20, 0x00, 0x21, 0xFF, 0xF7, 0xA7, 0xFC, + 0xCD, 0xE9, 0x02, 0x01, 0x05, 0x22, 0x02, 0xA9, 0x96, 0x20, 0x01, 0xF0, + 0x7B, 0xF8, 0x9D, 0xF8, 0x04, 0x00, 0x01, 0x22, 0x40, 0xF0, 0x06, 0x00, + 0x8D, 0xF8, 0x00, 0x00, 0x69, 0x46, 0x00, 0x20, 0x01, 0xF0, 0x70, 0xF8, + 0x17, 0x4E, 0xE0, 0x25, 0x35, 0x73, 0x4F, 0xF4, 0x20, 0x77, 0x38, 0x46, + 0x01, 0xF0, 0x34, 0xFE, 0x00, 0x23, 0x01, 0x22, 0x69, 0x46, 0x89, 0x20, + 0x00, 0xF0, 0xEA, 0xFD, 0x9D, 0xF8, 0x00, 0x00, 0x01, 0x22, 0x00, 0xF0, + 0x01, 0x04, 0x9D, 0xF8, 0x04, 0x00, 0x69, 0x46, 0x40, 0xF0, 0x07, 0x00, + 0x8D, 0xF8, 0x00, 0x00, 0x00, 0x20, 0x01, 0xF0, 0x53, 0xF8, 0x35, 0x73, + 0x38, 0x46, 0x01, 0xF0, 0x1B, 0xFE, 0x00, 0x23, 0x01, 0x22, 0x69, 0x46, + 0x89, 0x20, 0x00, 0xF0, 0xD1, 0xFD, 0x9D, 0xF8, 0x00, 0x00, 0x04, 0xB0, + 0x00, 0xF0, 0x01, 0x00, 0x44, 0xEA, 0x40, 0x00, 0xBD, 0xE8, 0xF0, 0x81, + 0x00, 0x00, 0x07, 0x20, 0x1C, 0xB5, 0x00, 0x23, 0x01, 0x22, 0x01, 0xA9, + 0x18, 0x46, 0x00, 0xF0, 0xBF, 0xFD, 0x9D, 0xF8, 0x04, 0x00, 0x01, 0x22, + 0x20, 0xF0, 0x07, 0x00, 0x8D, 0xF8, 0x04, 0x00, 0x01, 0xA9, 0x00, 0x20, + 0x01, 0xF0, 0x2C, 0xF8, 0x00, 0x20, 0x00, 0x90, 0x04, 0x22, 0x69, 0x46, + 0x2B, 0x20, 0x01, 0xF0, 0x25, 0xF8, 0x04, 0x22, 0x69, 0x46, 0x96, 0x20, + 0x01, 0xF0, 0x20, 0xF8, 0x01, 0x22, 0x69, 0x46, 0x9A, 0x20, 0x01, 0xF0, + 0x1B, 0xF8, 0x1C, 0xBD, 0x34, 0x21, 0x01, 0x70, 0x0C, 0x21, 0x41, 0x70, + 0x3C, 0x21, 0x81, 0x70, 0x40, 0x21, 0xC1, 0x70, 0x1F, 0x21, 0xC1, 0x71, + 0x01, 0x21, 0x01, 0x72, 0x02, 0x22, 0x42, 0x72, 0x81, 0x72, 0x00, 0x21, + 0xC1, 0x72, 0x41, 0x73, 0x5C, 0x21, 0x81, 0x73, 0x70, 0x47, 0x01, 0xB5, + 0x01, 0x22, 0x69, 0x46, 0x0B, 0x20, 0x00, 0xF0, 0xFF, 0xFF, 0x08, 0xBD, + 0x01, 0x48, 0x01, 0x68, 0x01, 0x20, 0x08, 0x47, 0x70, 0x86, 0x10, 0x00, + 0x0E, 0x48, 0x10, 0xB5, 0x4F, 0xF0, 0x00, 0x52, 0x81, 0x88, 0xA2, 0xF8, + 0xEB, 0x10, 0x90, 0xF8, 0x34, 0x00, 0xE1, 0x24, 0x80, 0x07, 0x00, 0xD5, + 0xE3, 0x24, 0x09, 0x49, 0x03, 0x20, 0x08, 0x70, 0x09, 0x49, 0x08, 0x48, + 0x08, 0x60, 0x00, 0xF0, 0xB3, 0xFF, 0x08, 0x48, 0x04, 0x73, 0xBD, 0xE8, + 0x10, 0x40, 0x07, 0x49, 0x32, 0x20, 0x01, 0xF0, 0x99, 0xBA, 0x00, 0x00, + 0x70, 0x86, 0x10, 0x00, 0x26, 0x25, 0x10, 0x00, 0xE5, 0x01, 0x01, 0x00, + 0x2C, 0x25, 0x10, 0x00, 0x00, 0x00, 0x07, 0x20, 0x39, 0x01, 0x01, 0x00, + 0x01, 0x49, 0x48, 0x60, 0xFF, 0xF7, 0xD2, 0xBF, 0x70, 0x86, 0x10, 0x00, + 0x38, 0xB5, 0x07, 0x4A, 0x04, 0x46, 0x0C, 0x20, 0xD1, 0x76, 0x8D, 0xF8, + 0x00, 0x10, 0x01, 0x22, 0x69, 0x46, 0x00, 0xF0, 0xBD, 0xFF, 0x20, 0x46, + 0xFF, 0xF7, 0xEC, 0xFF, 0x38, 0xBD, 0x00, 0x00, 0x70, 0x86, 0x10, 0x00, + 0x10, 0xB5, 0x04, 0x46, 0x04, 0x48, 0x01, 0x76, 0x08, 0x46, 0x00, 0xF0, + 0xCC, 0xFD, 0x20, 0x46, 0xBD, 0xE8, 0x10, 0x40, 0xFF, 0xF7, 0xDC, 0xBF, + 0x70, 0x86, 0x10, 0x00, 0x10, 0xB5, 0x01, 0xF0, 0x7B, 0xFA, 0x06, 0x49, + 0x02, 0x20, 0x08, 0x70, 0x05, 0x49, 0x00, 0x20, 0x08, 0x60, 0x05, 0x48, + 0x01, 0x68, 0xBD, 0xE8, 0x10, 0x40, 0x00, 0x20, 0x08, 0x47, 0x00, 0x00, + 0x26, 0x25, 0x10, 0x00, 0x2C, 0x25, 0x10, 0x00, 0x70, 0x86, 0x10, 0x00, + 0x10, 0xB5, 0x01, 0x46, 0x40, 0x22, 0x04, 0x48, 0xFF, 0xF7, 0x2D, 0xFC, + 0x00, 0xF0, 0x46, 0xF8, 0xBD, 0xE8, 0x10, 0x40, 0xFF, 0xF7, 0x8E, 0xBF, + 0x70, 0x86, 0x10, 0x00, 0x7C, 0xB5, 0x1C, 0x4E, 0x04, 0x21, 0xB0, 0x68, + 0xC0, 0x00, 0x80, 0x08, 0x01, 0x90, 0x01, 0xA8, 0x01, 0xF0, 0x30, 0xFD, + 0x18, 0x4D, 0x04, 0x46, 0x01, 0x98, 0x68, 0x73, 0x01, 0x0A, 0xA9, 0x73, + 0x01, 0x0C, 0xE9, 0x73, 0x00, 0x0E, 0x28, 0x74, 0x04, 0x22, 0x01, 0xA9, + 0x2B, 0x20, 0x00, 0xF0, 0x6B, 0xFF, 0x70, 0x6B, 0xC1, 0x07, 0x03, 0xD0, + 0x60, 0x1C, 0x64, 0x1C, 0x00, 0x94, 0x0F, 0xE0, 0x01, 0x07, 0x0B, 0xD5, + 0xE1, 0x1C, 0x21, 0xF0, 0x01, 0x01, 0x00, 0x91, 0xC0, 0x06, 0x03, 0xD5, + 0x64, 0x1C, 0x24, 0xF0, 0x01, 0x00, 0x03, 0xE0, 0x08, 0x46, 0x01, 0xE0, + 0x20, 0x46, 0x00, 0x94, 0xA8, 0x74, 0x06, 0x49, 0x01, 0x22, 0x08, 0x70, + 0x69, 0x46, 0x2F, 0x20, 0x00, 0xF0, 0x4C, 0xFF, 0x7C, 0xBD, 0x00, 0x00, + 0x70, 0x86, 0x10, 0x00, 0x00, 0x00, 0x07, 0x20, 0x30, 0x25, 0x10, 0x00, + 0xF0, 0xB5, 0x85, 0xB0, 0x6B, 0x4C, 0xFF, 0xF7, 0xBB, 0xFF, 0x21, 0x46, + 0x4F, 0xF0, 0x00, 0x55, 0x08, 0x69, 0x03, 0x90, 0x09, 0x7D, 0x01, 0xF0, + 0x03, 0x01, 0x04, 0x91, 0x85, 0xF8, 0xE0, 0x00, 0x02, 0x0A, 0x85, 0xF8, + 0xE1, 0x20, 0x02, 0x0C, 0x85, 0xF8, 0xE2, 0x20, 0x00, 0x0E, 0x85, 0xF8, + 0xE3, 0x00, 0x85, 0xF8, 0xE4, 0x10, 0x04, 0x22, 0x03, 0xA9, 0x96, 0x20, + 0x00, 0xF0, 0x24, 0xFF, 0x01, 0x22, 0x04, 0xA9, 0x9A, 0x20, 0x00, 0xF0, + 0x1F, 0xFF, 0x94, 0xF8, 0x34, 0x10, 0x00, 0x20, 0xC9, 0x07, 0x00, 0xD0, + 0x80, 0x20, 0x8D, 0xF8, 0x00, 0x00, 0x94, 0xF8, 0x20, 0x00, 0x00, 0x27, + 0x00, 0xF0, 0x0F, 0x00, 0x40, 0xF0, 0xA0, 0x00, 0x8D, 0xF8, 0x01, 0x00, + 0x60, 0x7F, 0x8D, 0xF8, 0x02, 0x00, 0x94, 0xF8, 0x21, 0x00, 0x8D, 0xF8, + 0x03, 0x00, 0xA0, 0x7E, 0x8D, 0xF8, 0x04, 0x00, 0x8D, 0xF8, 0x05, 0x70, + 0x14, 0xF8, 0x19, 0x0F, 0x8D, 0xF8, 0x06, 0x00, 0x07, 0x22, 0x69, 0x46, + 0x05, 0x20, 0x00, 0xF0, 0xF9, 0xFE, 0xA0, 0x78, 0x8D, 0xF8, 0x00, 0x00, + 0x8D, 0xF8, 0x01, 0x70, 0xE0, 0x78, 0x8D, 0xF8, 0x02, 0x00, 0x8D, 0xF8, + 0x03, 0x70, 0x60, 0x7A, 0x30, 0x21, 0x01, 0xEA, 0x00, 0x10, 0xA1, 0x7A, + 0x09, 0x22, 0x40, 0xEA, 0x81, 0x10, 0xE1, 0x7A, 0x01, 0xF0, 0x03, 0x01, + 0x08, 0x43, 0x8D, 0xF8, 0x04, 0x00, 0xA1, 0x7B, 0x20, 0x7B, 0x01, 0xF0, + 0x0F, 0x01, 0x41, 0xEA, 0x80, 0x10, 0x8D, 0xF8, 0x05, 0x00, 0x8D, 0xF8, + 0x06, 0x70, 0x60, 0x7B, 0x8D, 0xF8, 0x07, 0x00, 0x60, 0x79, 0x8D, 0xF8, + 0x08, 0x00, 0x69, 0x46, 0x0C, 0x20, 0x00, 0xF0, 0xCD, 0xFE, 0x32, 0x48, + 0x00, 0x68, 0x80, 0x79, 0x00, 0xF0, 0x03, 0x00, 0x40, 0xF0, 0x40, 0x00, + 0x8D, 0xF8, 0x00, 0x00, 0xE1, 0x7E, 0x19, 0x3C, 0x49, 0x07, 0x03, 0xD5, + 0x40, 0xF0, 0x0C, 0x00, 0x8D, 0xF8, 0x00, 0x00, 0x01, 0x22, 0x69, 0x46, + 0xB1, 0x20, 0x00, 0xF0, 0xB7, 0xFE, 0x8D, 0xF8, 0x00, 0x70, 0x94, 0xF8, + 0x34, 0x00, 0x4F, 0xF0, 0x01, 0x06, 0x00, 0x07, 0x01, 0xD5, 0x8D, 0xF8, + 0x00, 0x60, 0x01, 0x22, 0x69, 0x46, 0xAA, 0x20, 0x00, 0xF0, 0xA8, 0xFE, + 0x8D, 0xF8, 0x00, 0x70, 0x8D, 0xF8, 0x01, 0x70, 0x60, 0x6B, 0xC1, 0x07, + 0x05, 0xD1, 0x01, 0x07, 0x03, 0xD5, 0xC0, 0x06, 0x01, 0xD5, 0x8D, 0xF8, + 0x00, 0x60, 0x20, 0x20, 0x8D, 0xF8, 0x01, 0x00, 0x02, 0x22, 0x69, 0x46, + 0x30, 0x20, 0x00, 0xF0, 0x73, 0xFE, 0x94, 0xF8, 0x34, 0x00, 0x00, 0x07, + 0x04, 0xD5, 0x95, 0xF8, 0xDF, 0x00, 0x20, 0xF0, 0xF0, 0x00, 0x05, 0xE0, + 0x94, 0xF8, 0x20, 0x10, 0x95, 0xF8, 0xDF, 0x00, 0x61, 0xF3, 0x07, 0x10, + 0x85, 0xF8, 0xDF, 0x00, 0xE0, 0x7F, 0x85, 0xF8, 0xED, 0x00, 0x60, 0x8E, + 0xF0, 0x21, 0x00, 0xF5, 0x80, 0x70, 0x01, 0xEA, 0x10, 0x10, 0x8D, 0xF8, + 0x00, 0x00, 0x00, 0x09, 0x8D, 0xF8, 0x01, 0x00, 0x02, 0x22, 0x69, 0x46, + 0x40, 0x20, 0x00, 0xF0, 0x4F, 0xFE, 0x20, 0x7E, 0x00, 0xF0, 0x89, 0xFC, + 0x05, 0xB0, 0xF0, 0xBD, 0x70, 0x86, 0x10, 0x00, 0x28, 0x25, 0x10, 0x00, + 0x02, 0x48, 0x00, 0x78, 0x00, 0x28, 0x00, 0xD0, 0x01, 0x20, 0x70, 0x47, + 0x26, 0x25, 0x10, 0x00, 0x38, 0xB5, 0x08, 0x49, 0x04, 0x20, 0x08, 0x73, + 0x00, 0x24, 0x8D, 0xF8, 0x00, 0x40, 0x01, 0x22, 0x69, 0x46, 0x03, 0x20, + 0x00, 0xF0, 0x52, 0xFE, 0x03, 0x48, 0x04, 0x70, 0x03, 0x48, 0x04, 0x60, + 0x38, 0xBD, 0x00, 0x00, 0x00, 0x00, 0x07, 0x20, 0x26, 0x25, 0x10, 0x00, + 0x34, 0x25, 0x10, 0x00, 0x05, 0x4A, 0x01, 0x21, 0x11, 0x70, 0x05, 0x49, + 0x08, 0x60, 0x05, 0x49, 0xE4, 0x20, 0x08, 0x73, 0x04, 0x49, 0x03, 0x20, + 0x01, 0xF0, 0x42, 0xBA, 0x26, 0x25, 0x10, 0x00, 0x34, 0x25, 0x10, 0x00, + 0x00, 0x00, 0x07, 0x20, 0xD1, 0x04, 0x01, 0x00, 0x07, 0x48, 0x01, 0x78, + 0x01, 0x29, 0x08, 0xD1, 0x02, 0x21, 0x01, 0x70, 0x05, 0x48, 0x01, 0x68, + 0x19, 0xB1, 0x00, 0x22, 0x02, 0x60, 0x10, 0x46, 0x08, 0x47, 0x00, 0x20, + 0x00, 0xF0, 0xF0, 0xBD, 0x26, 0x25, 0x10, 0x00, 0x34, 0x25, 0x10, 0x00, + 0x01, 0x48, 0x01, 0x68, 0x01, 0x20, 0x08, 0x47, 0xB0, 0x86, 0x10, 0x00, + 0x0D, 0x4B, 0x30, 0xB4, 0x58, 0x78, 0x0D, 0x49, 0x0D, 0x4C, 0x01, 0x28, + 0x0D, 0xD0, 0x04, 0x22, 0x0A, 0x70, 0x0C, 0x49, 0x21, 0x60, 0x0C, 0x4A, + 0x19, 0x78, 0x11, 0x73, 0x00, 0x28, 0x08, 0xD1, 0x30, 0xBC, 0x0A, 0x49, + 0x32, 0x20, 0x01, 0xF0, 0xC1, 0xB8, 0x00, 0x22, 0x0A, 0x70, 0x22, 0x60, + 0xF1, 0xE7, 0x30, 0xBC, 0x70, 0x47, 0x00, 0x00, 0x38, 0x25, 0x10, 0x00, + 0x26, 0x25, 0x10, 0x00, 0x2C, 0x25, 0x10, 0x00, 0x55, 0x05, 0x01, 0x00, + 0x00, 0x00, 0x07, 0x20, 0xF9, 0x04, 0x01, 0x00, 0x10, 0xB5, 0x01, 0xF0, + 0xC3, 0xF8, 0x06, 0x49, 0x02, 0x20, 0x08, 0x70, 0x05, 0x49, 0x00, 0x20, + 0x08, 0x60, 0x05, 0x48, 0x01, 0x68, 0xBD, 0xE8, 0x10, 0x40, 0x00, 0x20, + 0x08, 0x47, 0x00, 0x00, 0x26, 0x25, 0x10, 0x00, 0x2C, 0x25, 0x10, 0x00, + 0xB0, 0x86, 0x10, 0x00, 0x70, 0xB5, 0x0B, 0x4C, 0x05, 0x46, 0x0E, 0x46, + 0x60, 0x71, 0x50, 0x22, 0x09, 0x48, 0xFF, 0xF7, 0x72, 0xFA, 0x70, 0x6C, + 0x00, 0x03, 0x01, 0xD5, 0x01, 0x20, 0x00, 0xE0, 0x00, 0x20, 0x60, 0x70, + 0x28, 0x46, 0x00, 0xF0, 0x09, 0xF9, 0xBD, 0xE8, 0x70, 0x40, 0xFF, 0xF7, + 0xAB, 0xBF, 0x00, 0x00, 0x38, 0x25, 0x10, 0x00, 0xB0, 0x86, 0x10, 0x00, + 0x2D, 0xE9, 0xF0, 0x41, 0x7A, 0x4C, 0x88, 0xB0, 0x80, 0x46, 0x02, 0x25, + 0x20, 0x46, 0x8D, 0xF8, 0x0C, 0x50, 0x80, 0x68, 0x04, 0x21, 0xC0, 0x00, + 0x80, 0x08, 0x05, 0x90, 0x05, 0xA8, 0x01, 0xF0, 0x63, 0xFB, 0x74, 0x4A, + 0x06, 0x90, 0x05, 0x99, 0x51, 0x73, 0x0B, 0x0A, 0x93, 0x73, 0x0B, 0x0C, + 0xD3, 0x73, 0x09, 0x0E, 0x11, 0x74, 0x90, 0x74, 0x04, 0x22, 0x05, 0xA9, + 0x2B, 0x20, 0x00, 0xF0, 0x9D, 0xFD, 0x01, 0x22, 0x06, 0xA9, 0x2F, 0x20, + 0x00, 0xF0, 0x98, 0xFD, 0x21, 0x46, 0x2E, 0x07, 0x08, 0x69, 0x05, 0x90, + 0x09, 0x7D, 0x01, 0xF0, 0x03, 0x01, 0x06, 0x91, 0x06, 0xF8, 0xE0, 0x0F, + 0x02, 0x0A, 0x72, 0x70, 0x02, 0x0C, 0xB2, 0x70, 0x00, 0x0E, 0xF0, 0x70, + 0x31, 0x71, 0x04, 0x22, 0x05, 0xA9, 0x96, 0x20, 0x00, 0xF0, 0x82, 0xFD, + 0x01, 0x22, 0x06, 0xA9, 0x9A, 0x20, 0x00, 0xF0, 0x7D, 0xFD, 0xA0, 0x88, + 0xA6, 0xF8, 0x0B, 0x00, 0x00, 0x27, 0x8D, 0xF8, 0x00, 0x70, 0x94, 0xF8, + 0x22, 0x00, 0x8D, 0xF8, 0x01, 0x00, 0x94, 0xF8, 0x20, 0x00, 0x8D, 0xF8, + 0x02, 0x00, 0x03, 0x22, 0x69, 0x46, 0x05, 0x20, 0xE0, 0x3E, 0x00, 0xF0, + 0x69, 0xFD, 0x60, 0x8B, 0x8D, 0xF8, 0x00, 0x00, 0x00, 0x0A, 0x8D, 0xF8, + 0x01, 0x00, 0x02, 0x22, 0x69, 0x46, 0x09, 0x20, 0x00, 0xF0, 0x5E, 0xFD, + 0x60, 0x6C, 0xC0, 0xF3, 0x00, 0x41, 0xC0, 0xF3, 0x40, 0x42, 0xC9, 0x01, + 0x41, 0xEA, 0x82, 0x11, 0xC0, 0xF3, 0x80, 0x40, 0x01, 0x43, 0x41, 0xF0, + 0x08, 0x00, 0x41, 0x46, 0x8D, 0xF8, 0x10, 0x00, 0x4F, 0xF0, 0x01, 0x08, + 0x0B, 0x29, 0x1D, 0xD2, 0xDF, 0xE8, 0x01, 0xF0, 0x06, 0x06, 0x1C, 0x1C, + 0x09, 0x09, 0x1C, 0x1C, 0x1C, 0x0C, 0x0C, 0x00, 0x8D, 0xF8, 0x0C, 0x50, + 0x08, 0xE0, 0x40, 0xF0, 0x02, 0x00, 0x11, 0xE0, 0x40, 0xF0, 0x04, 0x00, + 0x8D, 0xF8, 0x10, 0x00, 0x8D, 0xF8, 0x0C, 0x80, 0x01, 0x22, 0x04, 0xA9, + 0x17, 0x20, 0x00, 0xF0, 0x31, 0xFD, 0x37, 0x48, 0x40, 0x78, 0x01, 0x28, + 0x05, 0xD0, 0x06, 0xE0, 0x40, 0xF0, 0x04, 0x00, 0x8D, 0xF8, 0x10, 0x00, + 0xE4, 0xE7, 0x8D, 0xF8, 0x0C, 0x80, 0x01, 0x22, 0x03, 0xA9, 0x18, 0x20, + 0x00, 0xF0, 0x20, 0xFD, 0x9D, 0xF8, 0x0C, 0x00, 0x86, 0xF8, 0xEA, 0x00, + 0x94, 0xF8, 0x2D, 0x00, 0x94, 0xF8, 0x2E, 0x10, 0x00, 0xF0, 0x0F, 0x00, + 0x40, 0xEA, 0x01, 0x10, 0x8D, 0xF8, 0x00, 0x00, 0xFF, 0x20, 0x8D, 0xF8, + 0x01, 0x00, 0xA0, 0x8B, 0x8D, 0xF8, 0x02, 0x00, 0x00, 0x0A, 0x8D, 0xF8, + 0x03, 0x00, 0xE0, 0x8B, 0x8D, 0xF8, 0x04, 0x00, 0x00, 0x0A, 0x8D, 0xF8, + 0x05, 0x00, 0x06, 0x22, 0x69, 0x46, 0x19, 0x20, 0x18, 0x34, 0xDF, 0x36, + 0x00, 0xF0, 0xFC, 0xFC, 0x1D, 0x48, 0x01, 0x22, 0x69, 0x46, 0x00, 0x68, + 0x80, 0x79, 0x00, 0xF0, 0x03, 0x00, 0x40, 0xF0, 0x40, 0x00, 0x8D, 0xF8, + 0x00, 0x00, 0xB1, 0x20, 0x00, 0xF0, 0xEE, 0xFC, 0xA1, 0x7A, 0x30, 0x78, + 0x61, 0xF3, 0x07, 0x10, 0x30, 0x70, 0x60, 0x7A, 0xB0, 0x73, 0x8D, 0xF8, + 0x00, 0x70, 0x20, 0x20, 0x8D, 0xF8, 0x01, 0x00, 0x02, 0x22, 0x69, 0x46, + 0x30, 0x20, 0x00, 0xF0, 0xBD, 0xFC, 0x60, 0x8D, 0xF0, 0x21, 0x00, 0xF5, + 0x80, 0x70, 0x01, 0xEA, 0x10, 0x10, 0x8D, 0xF8, 0x00, 0x00, 0x00, 0x09, + 0x8D, 0xF8, 0x01, 0x00, 0x02, 0x22, 0x69, 0x46, 0x40, 0x20, 0x00, 0xF0, + 0xAD, 0xFC, 0x20, 0x78, 0x00, 0xF0, 0xE7, 0xFA, 0x08, 0xB0, 0xBD, 0xE8, + 0xF0, 0x81, 0x00, 0x00, 0xB0, 0x86, 0x10, 0x00, 0x00, 0x00, 0x07, 0x20, + 0x38, 0x25, 0x10, 0x00, 0x28, 0x25, 0x10, 0x00, 0x3E, 0xB5, 0x27, 0x4D, + 0x04, 0x46, 0x68, 0x78, 0x01, 0x28, 0x0E, 0xD0, 0xE1, 0x20, 0x28, 0x70, + 0x20, 0x46, 0xFF, 0xF7, 0xF5, 0xFE, 0x0B, 0x2C, 0x11, 0xD2, 0xDF, 0xE8, + 0x04, 0xF0, 0x10, 0x08, 0x10, 0x08, 0x10, 0x08, 0x10, 0x10, 0x10, 0x10, + 0x08, 0x00, 0x40, 0x20, 0xEF, 0xE7, 0x00, 0xF0, 0x3B, 0xF8, 0x28, 0x78, + 0x40, 0xF0, 0x0C, 0x00, 0x28, 0x70, 0xE8, 0x78, 0x2E, 0xE0, 0x19, 0x4C, + 0x01, 0x22, 0x69, 0x46, 0x14, 0xF8, 0x23, 0x0F, 0x8D, 0xF8, 0x00, 0x00, + 0x08, 0x20, 0x00, 0xF0, 0x95, 0xFC, 0x61, 0x78, 0xA0, 0x78, 0x30, 0x22, + 0x02, 0xEA, 0x01, 0x11, 0x41, 0xEA, 0x80, 0x10, 0xE1, 0x78, 0x22, 0x7C, + 0x01, 0xF0, 0x03, 0x01, 0x08, 0x43, 0x21, 0x79, 0x02, 0xF0, 0x3B, 0x02, + 0x42, 0xEA, 0x81, 0x11, 0xA2, 0x7B, 0x8D, 0xF8, 0x00, 0x20, 0x22, 0x7B, + 0x8D, 0xF8, 0x01, 0x20, 0x8D, 0xF8, 0x02, 0x00, 0x8D, 0xF8, 0x03, 0x10, + 0x04, 0x22, 0x69, 0x46, 0x1F, 0x20, 0x00, 0xF0, 0x75, 0xFC, 0x28, 0x78, + 0x40, 0xF0, 0x08, 0x00, 0x28, 0x70, 0xA8, 0x78, 0x28, 0x71, 0x3E, 0xBD, + 0x38, 0x25, 0x10, 0x00, 0xB0, 0x86, 0x10, 0x00, 0x3E, 0xB5, 0x1C, 0x4C, + 0x01, 0x22, 0x69, 0x46, 0x14, 0xF8, 0x28, 0x0F, 0x8D, 0xF8, 0x00, 0x00, + 0x08, 0x20, 0x00, 0xF0, 0x5F, 0xFC, 0x61, 0x78, 0x30, 0x22, 0xA0, 0x78, + 0x02, 0xEA, 0x01, 0x11, 0x41, 0xEA, 0x80, 0x10, 0xE1, 0x78, 0xE2, 0x7A, + 0x01, 0xF0, 0x03, 0x01, 0x08, 0x43, 0x21, 0x79, 0x02, 0xF0, 0x3B, 0x02, + 0x42, 0xEA, 0x81, 0x11, 0x8D, 0xF8, 0x00, 0x00, 0x8D, 0xF8, 0x01, 0x10, + 0x02, 0x22, 0x69, 0x46, 0x21, 0x20, 0x00, 0xF0, 0x45, 0xFC, 0x20, 0x7B, + 0xA1, 0x7A, 0x8D, 0xF8, 0x00, 0x10, 0x21, 0x7A, 0x8D, 0xF8, 0x01, 0x10, + 0x00, 0x21, 0x8D, 0xF8, 0x02, 0x10, 0x00, 0xF0, 0x3B, 0x00, 0x8D, 0xF8, + 0x03, 0x00, 0x04, 0x22, 0x69, 0x46, 0x27, 0x20, 0x00, 0xF0, 0x32, 0xFC, + 0x3E, 0xBD, 0x00, 0x00, 0xB0, 0x86, 0x10, 0x00, 0x05, 0x48, 0x10, 0xB5, + 0x80, 0x68, 0x10, 0xB1, 0xBD, 0xE8, 0x10, 0x40, 0x00, 0x47, 0x00, 0x20, + 0x00, 0xF0, 0xF2, 0xFB, 0x10, 0xBD, 0x00, 0x00, 0x24, 0x25, 0x10, 0x00, + 0x01, 0x48, 0x00, 0x78, 0x70, 0x47, 0x00, 0x00, 0x24, 0x25, 0x10, 0x00, + 0x01, 0x48, 0x40, 0x78, 0x70, 0x47, 0x00, 0x00, 0x24, 0x25, 0x10, 0x00, + 0x40, 0xF2, 0x72, 0x40, 0x70, 0x47, 0x1E, 0x20, 0x70, 0x47, 0x00, 0x00, + 0x12, 0x49, 0x00, 0x20, 0xCA, 0x78, 0xD2, 0x07, 0x01, 0xD0, 0x40, 0xF0, + 0x01, 0x00, 0xCA, 0x78, 0x12, 0x06, 0x01, 0xD5, 0x40, 0xF0, 0x02, 0x00, + 0xCA, 0x78, 0x52, 0x06, 0x01, 0xD5, 0x40, 0xF0, 0x04, 0x00, 0xCA, 0x78, + 0x92, 0x07, 0x01, 0xD5, 0x40, 0xF0, 0x08, 0x00, 0xCA, 0x78, 0x12, 0x07, + 0x01, 0xD5, 0x40, 0xF0, 0x10, 0x00, 0xCA, 0x78, 0x52, 0x07, 0x01, 0xD5, + 0x40, 0xF0, 0x20, 0x00, 0xC9, 0x78, 0x89, 0x06, 0x01, 0xD5, 0x40, 0xF0, + 0x40, 0x00, 0x70, 0x47, 0x00, 0x00, 0x07, 0x20, 0x22, 0x20, 0x70, 0x47, + 0x38, 0xB5, 0x04, 0x46, 0x01, 0x20, 0x00, 0xF0, 0x7E, 0xFF, 0x0D, 0x20, + 0x00, 0xF0, 0x7B, 0xFF, 0x02, 0x20, 0x00, 0xF0, 0x78, 0xFF, 0x06, 0x20, + 0x00, 0xF0, 0x75, 0xFF, 0x01, 0x20, 0x00, 0xF0, 0x51, 0xFF, 0x0D, 0x20, + 0x00, 0xF0, 0x4E, 0xFF, 0x02, 0x20, 0x00, 0xF0, 0x4B, 0xFF, 0x06, 0x20, + 0x00, 0xF0, 0x48, 0xFF, 0x31, 0x48, 0x00, 0x23, 0x03, 0x60, 0x01, 0x21, + 0x01, 0x60, 0x03, 0x60, 0x2F, 0x49, 0x0A, 0x68, 0x00, 0x2A, 0xFC, 0xD1, + 0x2E, 0x49, 0x04, 0x20, 0x08, 0x73, 0x2E, 0x48, 0x01, 0x22, 0x01, 0x46, + 0x83, 0x70, 0x2B, 0x48, 0x00, 0x23, 0x00, 0x1D, 0x00, 0xF0, 0x5E, 0xF9, + 0x29, 0x49, 0x28, 0x48, 0x00, 0x23, 0x01, 0x22, 0x49, 0x1C, 0x40, 0x1D, + 0x00, 0xF0, 0x56, 0xF9, 0x21, 0x78, 0x21, 0xF0, 0x7F, 0x00, 0xC1, 0xF3, + 0x80, 0x12, 0x40, 0xEA, 0x82, 0x10, 0xC1, 0xF3, 0x00, 0x12, 0x40, 0xEA, + 0x02, 0x10, 0xC1, 0xF3, 0xC0, 0x02, 0x40, 0xEA, 0xC2, 0x00, 0xC1, 0xF3, + 0x80, 0x02, 0x40, 0xEA, 0x82, 0x00, 0x01, 0xF0, 0x03, 0x01, 0x08, 0x43, + 0x40, 0xF0, 0x80, 0x00, 0x8D, 0xF8, 0x00, 0x00, 0x01, 0x22, 0x69, 0x46, + 0x0B, 0x20, 0x00, 0xF0, 0x8D, 0xFB, 0x4F, 0xF4, 0xFA, 0x60, 0x01, 0xF0, + 0x55, 0xF9, 0x20, 0x46, 0x00, 0xF0, 0x28, 0xF8, 0x00, 0xF0, 0x3C, 0xF8, + 0x05, 0x21, 0x01, 0x20, 0x00, 0xF0, 0x6B, 0xFF, 0x05, 0x21, 0x0D, 0x20, + 0x00, 0xF0, 0x67, 0xFF, 0x06, 0x21, 0x02, 0x20, 0x00, 0xF0, 0x63, 0xFF, + 0x06, 0x21, 0x08, 0x46, 0x00, 0xF0, 0x5F, 0xFF, 0x01, 0x20, 0x00, 0xF0, + 0x31, 0xFF, 0x0D, 0x20, 0x00, 0xF0, 0x2E, 0xFF, 0x02, 0x20, 0x00, 0xF0, + 0x2B, 0xFF, 0xBD, 0xE8, 0x38, 0x40, 0x06, 0x20, 0x00, 0xF0, 0x26, 0xBF, + 0x10, 0x05, 0x00, 0x22, 0x9C, 0x1B, 0x00, 0x22, 0x00, 0x00, 0x07, 0x20, + 0x24, 0x25, 0x10, 0x00, 0x01, 0x46, 0x1E, 0x22, 0x01, 0x48, 0xFE, 0xF7, + 0xB5, 0xBF, 0x00, 0x00, 0x4C, 0x86, 0x10, 0x00, 0x05, 0x48, 0x80, 0x78, + 0x03, 0x28, 0x05, 0xD0, 0x04, 0x28, 0x03, 0xD0, 0x05, 0x28, 0x01, 0xD0, + 0x00, 0x20, 0x70, 0x47, 0x01, 0x20, 0x70, 0x47, 0x24, 0x25, 0x10, 0x00, + 0x1E, 0xB5, 0x00, 0x24, 0x8D, 0xF8, 0x00, 0x40, 0x01, 0x22, 0x69, 0x46, + 0x04, 0x20, 0x00, 0xF0, 0x3F, 0xFB, 0x8D, 0xF8, 0x00, 0x40, 0x01, 0x22, + 0x69, 0x46, 0x05, 0x20, 0x00, 0xF0, 0x38, 0xFB, 0x5E, 0x4C, 0x60, 0x68, + 0x00, 0x78, 0x20, 0xF0, 0x7F, 0x01, 0xC0, 0xF3, 0x80, 0x12, 0x41, 0xEA, + 0x82, 0x11, 0xC0, 0xF3, 0x00, 0x12, 0x41, 0xEA, 0x02, 0x11, 0xC0, 0xF3, + 0xC0, 0x02, 0x41, 0xEA, 0xC2, 0x01, 0xC0, 0xF3, 0x80, 0x02, 0x41, 0xEA, + 0x82, 0x01, 0x00, 0xF0, 0x03, 0x00, 0x01, 0x43, 0x8D, 0xF8, 0x00, 0x10, + 0x01, 0x22, 0x69, 0x46, 0x0B, 0x20, 0x00, 0xF0, 0x19, 0xFB, 0x60, 0x68, + 0x40, 0x78, 0x20, 0xF0, 0x7F, 0x01, 0xC0, 0xF3, 0x80, 0x12, 0x41, 0xEA, + 0x82, 0x11, 0xC0, 0xF3, 0x00, 0x12, 0x41, 0xEA, 0x02, 0x11, 0xC0, 0xF3, + 0xC0, 0x02, 0x41, 0xEA, 0xC2, 0x01, 0xC0, 0xF3, 0x80, 0x02, 0x41, 0xEA, + 0x82, 0x01, 0x00, 0xF0, 0x03, 0x00, 0x01, 0x43, 0x8D, 0xF8, 0x00, 0x10, + 0x01, 0x22, 0x69, 0x46, 0x16, 0x20, 0x00, 0xF0, 0xFB, 0xFA, 0x02, 0x20, + 0x8D, 0xF8, 0x00, 0x00, 0x01, 0x22, 0x69, 0x46, 0x18, 0x20, 0x00, 0xF0, + 0xF3, 0xFA, 0x8B, 0x20, 0x8D, 0xF8, 0x00, 0x00, 0x01, 0x22, 0x69, 0x46, + 0xA0, 0x20, 0x00, 0xF0, 0xEB, 0xFA, 0x60, 0x68, 0x02, 0x22, 0x01, 0x7A, + 0x8D, 0xF8, 0x00, 0x10, 0x00, 0x89, 0x69, 0x46, 0x00, 0x0A, 0x8D, 0xF8, + 0x01, 0x00, 0x3F, 0x20, 0x00, 0xF0, 0xDE, 0xFA, 0x60, 0x68, 0x02, 0x22, + 0x69, 0x46, 0x40, 0x89, 0x8D, 0xF8, 0x00, 0x00, 0x00, 0x0A, 0x8D, 0xF8, + 0x01, 0x00, 0x41, 0x20, 0x00, 0xF0, 0xD2, 0xFA, 0x60, 0x68, 0x01, 0x22, + 0x69, 0x46, 0x80, 0x78, 0xC0, 0xF3, 0xC0, 0x00, 0x80, 0x01, 0x8D, 0xF8, + 0x00, 0x00, 0x44, 0x20, 0x00, 0xF0, 0xC6, 0xFA, 0x60, 0x68, 0x01, 0x22, + 0x69, 0x46, 0x00, 0x79, 0x00, 0xF0, 0x0F, 0x00, 0x8D, 0xF8, 0x00, 0x00, + 0x45, 0x20, 0x00, 0xF0, 0xBB, 0xFA, 0x60, 0x68, 0x02, 0x22, 0x69, 0x46, + 0xC0, 0x89, 0x8D, 0xF8, 0x00, 0x00, 0xC0, 0xF3, 0x00, 0x20, 0x8D, 0xF8, + 0x01, 0x00, 0x48, 0x20, 0x00, 0xF0, 0xAE, 0xFA, 0x60, 0x68, 0x01, 0x22, + 0x69, 0x46, 0xC0, 0x78, 0xC0, 0xF3, 0x82, 0x00, 0x8D, 0xF8, 0x00, 0x00, + 0xAD, 0x20, 0x00, 0xF0, 0xA3, 0xFA, 0x60, 0x68, 0x01, 0x22, 0x69, 0x46, + 0x40, 0x79, 0x00, 0xF0, 0x7F, 0x00, 0x8D, 0xF8, 0x00, 0x00, 0xB2, 0x20, + 0x00, 0xF0, 0x98, 0xFA, 0x60, 0x68, 0x01, 0x22, 0x81, 0x78, 0xC0, 0x78, + 0xC1, 0xF3, 0x40, 0x11, 0x49, 0x00, 0x41, 0xEA, 0x80, 0x10, 0x8D, 0xF8, + 0x00, 0x00, 0x69, 0x46, 0xB3, 0x20, 0x00, 0xF0, 0x89, 0xFA, 0x60, 0x68, + 0x01, 0x22, 0x69, 0x46, 0xC0, 0x79, 0x8D, 0xF8, 0x00, 0x00, 0xB4, 0x20, + 0x00, 0xF0, 0x80, 0xFA, 0x22, 0x20, 0x01, 0x07, 0x01, 0xF8, 0xDD, 0x0F, + 0x48, 0x70, 0x1E, 0xBD, 0x24, 0x25, 0x10, 0x00, 0x0E, 0x4B, 0x10, 0xB5, + 0x98, 0x76, 0x02, 0xF0, 0x0F, 0x00, 0xD8, 0x76, 0x0C, 0x48, 0x04, 0x68, + 0x00, 0x2C, 0xFC, 0xD1, 0x01, 0x20, 0x83, 0xF8, 0xE0, 0x00, 0x09, 0x48, + 0x18, 0x30, 0x04, 0x68, 0x00, 0x2C, 0xFC, 0xD1, 0x00, 0x20, 0x05, 0xE0, + 0xC4, 0x18, 0x94, 0xF8, 0x60, 0x40, 0x0C, 0x54, 0x40, 0x1C, 0x40, 0xB2, + 0x90, 0x42, 0xF7, 0xDB, 0x10, 0xBD, 0x00, 0x00, 0x00, 0x00, 0x07, 0x20, + 0x84, 0x1B, 0x00, 0x22, 0x30, 0xB5, 0x00, 0x23, 0x1C, 0x46, 0x03, 0xE0, + 0xC5, 0x18, 0x85, 0xF8, 0x80, 0x40, 0x5B, 0x1C, 0x93, 0x42, 0xF9, 0xDB, + 0x05, 0x4B, 0x1C, 0x68, 0x00, 0x2C, 0xFC, 0xD1, 0x00, 0x23, 0x02, 0xE0, + 0xC4, 0x5C, 0xCC, 0x54, 0x5B, 0x1C, 0x93, 0x42, 0xFA, 0xDB, 0x30, 0xBD, + 0x9C, 0x1B, 0x00, 0x22, 0x70, 0xB5, 0x01, 0x20, 0x00, 0xF0, 0xD9, 0xFD, + 0x02, 0x20, 0x00, 0xF0, 0xD6, 0xFD, 0x06, 0x20, 0x00, 0xF0, 0xD3, 0xFD, + 0x01, 0x20, 0x00, 0xF0, 0xAF, 0xFD, 0x02, 0x20, 0x00, 0xF0, 0xAC, 0xFD, + 0x06, 0x20, 0x00, 0xF0, 0xA9, 0xFD, 0x19, 0x4D, 0x00, 0x24, 0x2C, 0x60, + 0x01, 0x21, 0x29, 0x60, 0x16, 0x48, 0x08, 0x38, 0x04, 0x60, 0x01, 0x60, + 0x04, 0x60, 0x15, 0x48, 0x01, 0x68, 0x00, 0x29, 0xFC, 0xD1, 0x14, 0x48, + 0x01, 0x7B, 0x41, 0xF0, 0x20, 0x01, 0x01, 0x73, 0x01, 0x7B, 0x21, 0xF0, + 0x40, 0x01, 0x01, 0x73, 0x01, 0x7B, 0x21, 0xF0, 0x80, 0x01, 0x01, 0x73, + 0x01, 0x7B, 0x21, 0xF0, 0x20, 0x01, 0x01, 0x73, 0x00, 0xF0, 0x2A, 0xFE, + 0x00, 0xF0, 0xDE, 0xFC, 0x0A, 0x48, 0x84, 0x70, 0x84, 0x60, 0x2C, 0x60, + 0x01, 0x20, 0x00, 0xF0, 0xC1, 0xFD, 0x02, 0x20, 0x00, 0xF0, 0xBE, 0xFD, + 0xBD, 0xE8, 0x70, 0x40, 0x06, 0x20, 0x00, 0xF0, 0xB9, 0xBD, 0x00, 0x00, + 0x18, 0x05, 0x00, 0x22, 0x84, 0x1B, 0x00, 0x22, 0x00, 0x00, 0x07, 0x20, + 0x24, 0x25, 0x10, 0x00, 0x08, 0xB5, 0x00, 0xF0, 0x03, 0x00, 0x40, 0xEA, + 0xC1, 0x01, 0x8D, 0xF8, 0x00, 0x10, 0x01, 0x22, 0x69, 0x46, 0x10, 0x46, + 0x00, 0xF0, 0xE4, 0xF9, 0x08, 0xBD, 0x10, 0xB5, 0x04, 0x46, 0x00, 0xF0, + 0x05, 0xF8, 0x20, 0x46, 0xBD, 0xE8, 0x10, 0x40, 0x00, 0xF0, 0x6C, 0xB9, + 0x2D, 0xE9, 0xF8, 0x43, 0xB3, 0x4C, 0x00, 0x25, 0x02, 0x26, 0x01, 0x27, + 0x61, 0x68, 0x4F, 0xF0, 0x03, 0x09, 0x4F, 0xF0, 0x80, 0x08, 0x15, 0x28, + 0x7A, 0xD2, 0xDF, 0xE8, 0x00, 0xF0, 0x0B, 0xBD, 0x21, 0x24, 0x24, 0x4B, + 0x4B, 0x62, 0x62, 0x7A, 0x7A, 0xBF, 0xBF, 0xD6, 0xD6, 0xFA, 0xFA, 0xF8, + 0xF8, 0xF7, 0xF7, 0x00, 0x88, 0x78, 0xC1, 0x07, 0xC0, 0xF3, 0x80, 0x02, + 0x89, 0x0E, 0x41, 0xEA, 0xC2, 0x01, 0xC0, 0xF3, 0x40, 0x00, 0x41, 0xEA, + 0x80, 0x00, 0x20, 0xF0, 0x10, 0x00, 0x40, 0xF0, 0x40, 0x00, 0x8D, 0xF8, + 0x00, 0x00, 0x01, 0x22, 0x69, 0x46, 0x02, 0x20, 0x00, 0xF0, 0xAA, 0xF9, + 0x8D, 0xF8, 0x00, 0x50, 0xC7, 0xE0, 0x88, 0x78, 0xC1, 0x07, 0xC0, 0xF3, + 0x80, 0x02, 0x89, 0x0E, 0x41, 0xEA, 0xC2, 0x01, 0xC0, 0xF3, 0x40, 0x00, + 0x41, 0xEA, 0x80, 0x00, 0x40, 0xF0, 0x51, 0x00, 0x8D, 0xF8, 0x00, 0x00, + 0x01, 0x22, 0x69, 0x46, 0x02, 0x20, 0x00, 0xF0, 0x93, 0xF9, 0x8D, 0xF8, + 0x00, 0x50, 0x54, 0xE0, 0x8D, 0xF8, 0x00, 0x00, 0x01, 0x22, 0x69, 0x46, + 0x44, 0x20, 0x00, 0xF0, 0x89, 0xF9, 0x60, 0x68, 0x81, 0x78, 0xC0, 0x78, + 0xC1, 0xF3, 0x40, 0x11, 0x49, 0x00, 0x41, 0xEA, 0x80, 0x10, 0x6A, 0xE0, + 0x88, 0x78, 0xC1, 0x07, 0xC0, 0xF3, 0x80, 0x02, 0x89, 0x0E, 0x41, 0xEA, + 0xC2, 0x01, 0xC0, 0xF3, 0x40, 0x00, 0x41, 0xEA, 0x80, 0x00, 0x40, 0xF0, + 0x51, 0x00, 0x8D, 0xF8, 0x00, 0x00, 0x01, 0x22, 0x69, 0x46, 0x02, 0x20, + 0x00, 0xF0, 0x6C, 0xF9, 0x8D, 0xF8, 0x00, 0x50, 0x39, 0xE0, 0x88, 0x78, + 0xC1, 0x07, 0xC0, 0xF3, 0x80, 0x02, 0x89, 0x0E, 0x41, 0xEA, 0xC2, 0x01, + 0xC0, 0xF3, 0x40, 0x00, 0x41, 0xEA, 0x80, 0x00, 0x40, 0xF0, 0x53, 0x00, + 0x8D, 0xF8, 0x00, 0x00, 0x01, 0x22, 0x69, 0x46, 0x02, 0x20, 0x00, 0xF0, + 0x55, 0xF9, 0x8D, 0xF8, 0x00, 0x70, 0x72, 0xE0, 0x42, 0xE0, 0x88, 0x78, + 0xC1, 0x07, 0xC0, 0xF3, 0x80, 0x02, 0x89, 0x0E, 0x41, 0xEA, 0xC2, 0x01, + 0xC0, 0xF3, 0x40, 0x00, 0x41, 0xEA, 0x80, 0x00, 0x40, 0xF0, 0x53, 0x00, + 0x8D, 0xF8, 0x00, 0x00, 0x01, 0x22, 0x69, 0x46, 0x02, 0x20, 0x00, 0xF0, + 0x3D, 0xF9, 0x8D, 0xF8, 0x00, 0x70, 0x01, 0x22, 0x69, 0x46, 0x3D, 0x20, + 0x00, 0xF0, 0x36, 0xF9, 0x60, 0x68, 0x80, 0x78, 0xC0, 0xF3, 0xC0, 0x01, + 0x48, 0xEA, 0x81, 0x10, 0x9E, 0xE7, 0x01, 0x22, 0x69, 0x46, 0x3D, 0x20, + 0x00, 0xF0, 0x2A, 0xF9, 0x60, 0x68, 0x01, 0x22, 0x69, 0x46, 0x80, 0x78, + 0xC0, 0xF3, 0xC0, 0x00, 0x80, 0x01, 0x8D, 0xF8, 0x00, 0x00, 0x44, 0x20, + 0x00, 0xF0, 0x1E, 0xF9, 0x60, 0x68, 0x81, 0x78, 0xC0, 0x78, 0xC1, 0xF3, + 0x40, 0x11, 0x49, 0x00, 0x41, 0xEA, 0x80, 0x10, 0x40, 0x1C, 0x8D, 0xF8, + 0x00, 0x00, 0x01, 0x22, 0x69, 0x46, 0xB3, 0x20, 0x00, 0xF0, 0x0E, 0xF9, + 0xBD, 0xE8, 0xF8, 0x83, 0x88, 0x78, 0xC1, 0x07, 0xC0, 0xF3, 0x80, 0x02, + 0x89, 0x0E, 0x41, 0xEA, 0xC2, 0x01, 0xC0, 0xF3, 0x40, 0x00, 0x41, 0xEA, + 0x80, 0x00, 0x40, 0xF0, 0x53, 0x00, 0x8D, 0xF8, 0x00, 0x00, 0x01, 0x22, + 0x69, 0x46, 0x02, 0x20, 0x00, 0xF0, 0xF8, 0xF8, 0x8D, 0xF8, 0x00, 0x70, + 0xC5, 0xE7, 0x88, 0x78, 0xC1, 0x07, 0xC0, 0xF3, 0x80, 0x02, 0x89, 0x0E, + 0x41, 0xEA, 0xC2, 0x01, 0xC0, 0xF3, 0x40, 0x00, 0x41, 0xEA, 0x80, 0x00, + 0x40, 0xF0, 0x51, 0x00, 0x8D, 0xF8, 0x00, 0x00, 0x01, 0x22, 0x69, 0x46, + 0x02, 0x20, 0x00, 0xF0, 0xE1, 0xF8, 0x8D, 0xF8, 0x00, 0x60, 0x01, 0x22, + 0x69, 0x46, 0x3D, 0x20, 0x00, 0xF0, 0xDA, 0xF8, 0x60, 0x68, 0x80, 0x78, + 0xC0, 0xF3, 0xC0, 0x00, 0x80, 0x01, 0x43, 0xE7, 0x4A, 0xE0, 0x32, 0xE0, + 0xFF, 0xE7, 0x88, 0x78, 0xC1, 0x07, 0xC0, 0xF3, 0x80, 0x02, 0x89, 0x0E, + 0x41, 0xEA, 0xC2, 0x01, 0xC0, 0xF3, 0x40, 0x00, 0x41, 0xEA, 0x80, 0x00, + 0x40, 0xF0, 0x51, 0x00, 0x8D, 0xF8, 0x00, 0x00, 0x01, 0x22, 0x69, 0x46, + 0x02, 0x20, 0x00, 0xF0, 0xBD, 0xF8, 0x8D, 0xF8, 0x00, 0x60, 0x01, 0x22, + 0x69, 0x46, 0x3D, 0x20, 0x00, 0xF0, 0xB6, 0xF8, 0x60, 0x68, 0x01, 0x22, + 0x80, 0x78, 0xC0, 0xF3, 0xC0, 0x01, 0x48, 0xEA, 0x81, 0x10, 0x8D, 0xF8, + 0x00, 0x00, 0x69, 0x46, 0x44, 0x20, 0x00, 0xF0, 0xA9, 0xF8, 0x60, 0x68, + 0x01, 0x22, 0x69, 0x46, 0x00, 0x79, 0x00, 0xF0, 0x0F, 0x00, 0x8D, 0xF8, + 0x00, 0x00, 0x45, 0x20, 0x13, 0xE7, 0x88, 0x78, 0xC1, 0x07, 0xC0, 0xF3, + 0x80, 0x02, 0x89, 0x0E, 0x41, 0xEA, 0xC2, 0x01, 0xC0, 0xF3, 0x40, 0x00, + 0x41, 0xEA, 0x80, 0x00, 0x40, 0xF0, 0x51, 0x00, 0x8D, 0xF8, 0x00, 0x00, + 0x01, 0x22, 0x69, 0x46, 0x02, 0x20, 0x00, 0xF0, 0x8B, 0xF8, 0x8D, 0xF8, + 0x00, 0x60, 0x58, 0xE7, 0x88, 0x78, 0xC1, 0x07, 0xC0, 0xF3, 0x80, 0x02, + 0x89, 0x0E, 0x41, 0xEA, 0xC2, 0x01, 0xC0, 0xF3, 0x40, 0x00, 0x41, 0xEA, + 0x80, 0x00, 0x40, 0xF0, 0x43, 0x00, 0x8D, 0xF8, 0x00, 0x00, 0x01, 0x22, + 0x69, 0x46, 0x02, 0x20, 0x00, 0xF0, 0x74, 0xF8, 0x8D, 0xF8, 0x00, 0x90, + 0x91, 0xE7, 0x00, 0x00, 0x24, 0x25, 0x10, 0x00, 0xF0, 0xB5, 0x1B, 0x49, + 0x1B, 0x4F, 0x0A, 0x1D, 0x00, 0x25, 0x13, 0x1D, 0x01, 0x24, 0x19, 0x4E, + 0x10, 0x37, 0x15, 0x28, 0x1F, 0xD2, 0xDF, 0xE8, 0x00, 0xF0, 0x0B, 0x1E, + 0x1E, 0x0D, 0x21, 0x1F, 0x21, 0x13, 0x17, 0x13, 0x17, 0x13, 0x17, 0x0D, + 0x21, 0x0D, 0x19, 0x1F, 0x21, 0x23, 0x27, 0x00, 0x0D, 0x60, 0x03, 0xE0, + 0x0C, 0x60, 0x15, 0x60, 0x1C, 0x60, 0x0A, 0xE0, 0x15, 0x60, 0x15, 0xE0, + 0x0C, 0x60, 0x12, 0xE0, 0x14, 0x60, 0x0D, 0xE0, 0x0C, 0x60, 0xFB, 0xE7, + 0x0D, 0x60, 0x14, 0x60, 0x1D, 0x60, 0x35, 0x60, 0x3C, 0x60, 0xF0, 0xBD, + 0x0C, 0x60, 0xEF, 0xE7, 0x0D, 0x60, 0xF1, 0xE7, 0x0C, 0x60, 0x15, 0x60, + 0x1C, 0x60, 0xF0, 0xBD, 0x0D, 0x60, 0x14, 0x60, 0x1D, 0x60, 0xF0, 0xBD, + 0x00, 0x08, 0x00, 0x22, 0x64, 0x1B, 0x00, 0x22, 0x70, 0x47, 0x00, 0x00, + 0x02, 0x48, 0x01, 0x68, 0x01, 0x29, 0xFC, 0xD1, 0x70, 0x47, 0x00, 0x00, + 0x80, 0x1B, 0x00, 0x22, 0x02, 0x48, 0x01, 0x68, 0x00, 0x29, 0xFC, 0xD1, + 0x70, 0x47, 0x00, 0x00, 0x84, 0x1B, 0x00, 0x22, 0xF0, 0xB5, 0x00, 0x23, + 0x0C, 0x4E, 0x0D, 0x4C, 0x07, 0xE0, 0x25, 0x68, 0x01, 0x2D, 0xFC, 0xD1, + 0xCD, 0x5C, 0x9F, 0x19, 0x5B, 0x1C, 0x87, 0xF8, 0x60, 0x50, 0x93, 0x42, + 0xF5, 0xDB, 0x07, 0x49, 0x09, 0x1D, 0x0B, 0x68, 0x00, 0x2B, 0xFC, 0xD1, + 0xB0, 0x76, 0x02, 0xF0, 0x0F, 0x00, 0x40, 0xF0, 0xD0, 0x00, 0xF0, 0x76, + 0xF0, 0xBD, 0x00, 0x00, 0x00, 0x00, 0x07, 0x20, 0x80, 0x1B, 0x00, 0x22, + 0xF0, 0xB5, 0x00, 0x23, 0x0C, 0x4E, 0x0D, 0x4C, 0x07, 0xE0, 0x25, 0x68, + 0x01, 0x2D, 0xFC, 0xD1, 0xCD, 0x5C, 0x9F, 0x19, 0x5B, 0x1C, 0x87, 0xF8, + 0x60, 0x50, 0x93, 0x42, 0xF5, 0xDB, 0x07, 0x49, 0x09, 0x1D, 0x0B, 0x68, + 0x00, 0x2B, 0xFC, 0xD1, 0xB0, 0x76, 0x02, 0xF0, 0x0F, 0x00, 0x40, 0xF0, + 0x10, 0x00, 0xF0, 0x76, 0xF0, 0xBD, 0x00, 0x00, 0x00, 0x00, 0x07, 0x20, + 0x80, 0x1B, 0x00, 0x22, 0x4F, 0xF0, 0xE0, 0x21, 0x4F, 0xF4, 0x80, 0x30, + 0xC1, 0xF8, 0x80, 0x01, 0xC1, 0xF8, 0x80, 0x02, 0x02, 0x49, 0xA0, 0x20, + 0x81, 0xF8, 0x00, 0x04, 0x70, 0x47, 0x00, 0x00, 0x10, 0xE0, 0x00, 0xE0, + 0x10, 0xB5, 0x04, 0x46, 0x14, 0x21, 0xFE, 0xF7, 0xC8, 0xFC, 0x0A, 0x48, + 0x00, 0x68, 0x20, 0x60, 0x08, 0x48, 0x00, 0x1F, 0x00, 0x68, 0x60, 0x60, + 0x06, 0x48, 0x00, 0x1D, 0x00, 0x68, 0xA0, 0x60, 0x04, 0x48, 0x08, 0x30, + 0x00, 0x68, 0xE0, 0x60, 0x02, 0x48, 0x0C, 0x30, 0x00, 0x68, 0x20, 0x61, + 0x10, 0xBD, 0x00, 0x00, 0x38, 0x1E, 0x04, 0x00, 0x30, 0xB5, 0x95, 0xB0, + 0x04, 0x46, 0x1C, 0x21, 0xFE, 0xF7, 0xAB, 0xFC, 0x55, 0x48, 0x00, 0x68, + 0x00, 0x90, 0x54, 0x48, 0x00, 0x1D, 0x00, 0x68, 0x01, 0x90, 0x52, 0x48, + 0x08, 0x30, 0x00, 0x68, 0x02, 0x90, 0x50, 0x48, 0x0C, 0x30, 0x00, 0x68, + 0x03, 0x90, 0x4E, 0x48, 0x10, 0x30, 0x00, 0x68, 0x04, 0x90, 0x4C, 0x48, + 0x14, 0x30, 0x00, 0x68, 0x05, 0x90, 0x4A, 0x48, 0x18, 0x30, 0x00, 0x68, + 0x06, 0x90, 0x48, 0x48, 0x1C, 0x30, 0x00, 0x68, 0x07, 0x90, 0x46, 0x48, + 0x20, 0x30, 0x00, 0x68, 0x08, 0x90, 0x44, 0x48, 0x24, 0x30, 0x00, 0x68, + 0x09, 0x90, 0x42, 0x48, 0x28, 0x30, 0x00, 0x68, 0x0A, 0x90, 0x40, 0x48, + 0x2C, 0x30, 0x00, 0x68, 0x0B, 0x90, 0x3E, 0x48, 0x30, 0x30, 0x00, 0x68, + 0x0C, 0x90, 0x3C, 0x48, 0x34, 0x30, 0x00, 0x68, 0x0D, 0x90, 0x3A, 0x48, + 0x38, 0x30, 0x00, 0x68, 0x0E, 0x90, 0x38, 0x48, 0x3C, 0x30, 0x00, 0x68, + 0x0F, 0x90, 0x36, 0x48, 0x40, 0x30, 0x00, 0x68, 0x10, 0x90, 0x34, 0x48, + 0x44, 0x30, 0x00, 0x68, 0x11, 0x90, 0x32, 0x48, 0x48, 0x30, 0x00, 0x68, + 0x12, 0x90, 0x30, 0x48, 0x30, 0x49, 0x4C, 0x30, 0x6F, 0xF0, 0x02, 0x05, + 0x00, 0x68, 0x13, 0x90, 0x00, 0x98, 0x88, 0x42, 0x4D, 0xD1, 0xA8, 0x10, + 0xA0, 0x60, 0x60, 0x60, 0x20, 0x60, 0x60, 0x61, 0xA0, 0x61, 0xE0, 0x60, + 0x20, 0x61, 0x03, 0xA8, 0x02, 0x99, 0x00, 0xF0, 0x21, 0xFD, 0x01, 0x99, + 0x81, 0x42, 0x3E, 0xD1, 0x0B, 0x98, 0x45, 0xF2, 0xAA, 0x51, 0x80, 0xB2, + 0x88, 0x42, 0x08, 0xD1, 0x04, 0x98, 0xC0, 0xB2, 0xA0, 0x60, 0x13, 0x9A, + 0x92, 0xB2, 0x8A, 0x42, 0x00, 0xD0, 0x80, 0x1D, 0xE0, 0x60, 0x0C, 0x98, + 0x80, 0xB2, 0x88, 0x42, 0x17, 0xD1, 0x03, 0x98, 0x03, 0x9A, 0x00, 0xF4, + 0x7F, 0x40, 0xD2, 0xB2, 0x40, 0xEA, 0x02, 0x40, 0x03, 0x9A, 0xC2, 0xF3, + 0x07, 0x42, 0x10, 0x43, 0x16, 0x4A, 0x90, 0x42, 0x03, 0xD3, 0x05, 0x98, + 0xC0, 0xF3, 0x01, 0x20, 0x00, 0xE0, 0x00, 0x20, 0x60, 0x60, 0x05, 0x98, + 0x00, 0xF0, 0x1F, 0x00, 0x20, 0x60, 0x0D, 0x98, 0x80, 0xB2, 0x88, 0x42, + 0x01, 0xD1, 0x06, 0x98, 0x60, 0x61, 0x0E, 0x98, 0x80, 0xB2, 0x88, 0x42, + 0x01, 0xD1, 0x07, 0x98, 0xA0, 0x61, 0x0F, 0x98, 0x80, 0xB2, 0x88, 0x42, + 0x01, 0xD1, 0x08, 0x98, 0x20, 0x61, 0x15, 0xB0, 0x30, 0xBD, 0xA5, 0x60, + 0x65, 0x60, 0x25, 0x60, 0x65, 0x61, 0xA5, 0x61, 0xE5, 0x60, 0x25, 0x61, + 0xF5, 0xE7, 0x00, 0x00, 0xB4, 0x1E, 0x04, 0x00, 0x5C, 0x00, 0x0D, 0x60, + 0x00, 0x01, 0x02, 0x00, 0x30, 0xB5, 0x0A, 0x4C, 0x01, 0x25, 0x25, 0x60, + 0xE5, 0x06, 0x03, 0xF0, 0x3F, 0x03, 0x85, 0xF8, 0x6B, 0x30, 0x00, 0x23, + 0x04, 0xE0, 0x51, 0xF8, 0x23, 0x50, 0x40, 0xF8, 0x23, 0x50, 0x5B, 0x1C, + 0x93, 0x42, 0xF8, 0xDB, 0x00, 0x20, 0x20, 0x60, 0x30, 0xBD, 0x00, 0x00, + 0x44, 0x1B, 0x00, 0x22, 0x02, 0x48, 0x01, 0x68, 0x21, 0xF0, 0x04, 0x01, + 0x01, 0x60, 0x70, 0x47, 0x10, 0xED, 0x00, 0xE0, 0x08, 0x20, 0x81, 0x06, + 0x81, 0xF8, 0x68, 0x00, 0x70, 0x47, 0x4F, 0xF0, 0x00, 0x50, 0x80, 0x88, + 0x70, 0x47, 0x4F, 0xF0, 0x00, 0x50, 0x80, 0x79, 0x70, 0x47, 0x00, 0x00, + 0x0D, 0x49, 0x09, 0x68, 0x01, 0x60, 0x0C, 0x49, 0x10, 0x39, 0x09, 0x68, + 0x41, 0x60, 0x0A, 0x49, 0x0C, 0x39, 0x09, 0x68, 0x81, 0x60, 0x08, 0x49, + 0x08, 0x39, 0x09, 0x68, 0xC1, 0x60, 0x06, 0x49, 0x09, 0x1D, 0x09, 0x68, + 0x01, 0x61, 0x04, 0x49, 0x34, 0x39, 0x09, 0x68, 0x41, 0x61, 0x02, 0x49, + 0x14, 0x39, 0x09, 0x68, 0x81, 0x61, 0x70, 0x47, 0x38, 0xED, 0x00, 0xE0, + 0x4F, 0xF0, 0x00, 0x50, 0xC0, 0x8C, 0xA0, 0xF5, 0xA0, 0x51, 0xA4, 0x39, + 0x01, 0xD0, 0x00, 0x20, 0x70, 0x47, 0x01, 0x20, 0x70, 0x47, 0x00, 0x00, + 0x02, 0x48, 0x01, 0x68, 0x41, 0xF0, 0x04, 0x01, 0x01, 0x60, 0x70, 0x47, + 0x10, 0xED, 0x00, 0xE0, 0x41, 0xF2, 0xA4, 0x40, 0xC1, 0x06, 0xC8, 0x84, + 0x00, 0xF0, 0x2A, 0xB8, 0x4F, 0xF0, 0x00, 0x51, 0x08, 0x81, 0x70, 0x47, + 0x01, 0x49, 0x08, 0x60, 0x70, 0x47, 0x00, 0x00, 0xBC, 0x04, 0x00, 0x22, + 0x4F, 0xF0, 0x00, 0x51, 0x8A, 0x8C, 0x60, 0xF3, 0x04, 0x02, 0x8A, 0x84, + 0x70, 0x47, 0x4F, 0xF0, 0x00, 0x51, 0x40, 0xF2, 0xA6, 0x70, 0xC8, 0x84, + 0x00, 0xF0, 0x12, 0xB8, 0x10, 0xB5, 0x4F, 0xF0, 0x00, 0x54, 0x14, 0xF8, + 0x20, 0x2F, 0x22, 0xF0, 0x87, 0x02, 0x42, 0xEA, 0xC0, 0x13, 0x04, 0x22, + 0x02, 0xEA, 0x80, 0x00, 0x03, 0x43, 0x01, 0xF0, 0x03, 0x00, 0x03, 0x43, + 0x23, 0x70, 0x10, 0xBD, 0x4F, 0xF0, 0x00, 0x51, 0xC8, 0x8C, 0x14, 0x4A, + 0x00, 0xF0, 0x03, 0x00, 0x12, 0x68, 0x7A, 0xB1, 0x01, 0x28, 0x0A, 0xD0, + 0x02, 0x28, 0x06, 0xD0, 0x03, 0x28, 0x02, 0xD0, 0x4F, 0xF4, 0x16, 0x70, + 0x0E, 0xE0, 0x46, 0x20, 0x0C, 0xE0, 0x96, 0x20, 0x0A, 0xE0, 0x4F, 0xF4, + 0x96, 0x70, 0x07, 0xE0, 0x01, 0x28, 0x0E, 0xD0, 0x02, 0x28, 0x0A, 0xD0, + 0x03, 0x28, 0x06, 0xD0, 0x4F, 0xF4, 0xE1, 0x70, 0x40, 0x1E, 0x21, 0xF8, + 0x52, 0x0F, 0x08, 0x80, 0x70, 0x47, 0x32, 0x20, 0xF8, 0xE7, 0x6E, 0x20, + 0xF6, 0xE7, 0xDC, 0x20, 0xF4, 0xE7, 0x00, 0x00, 0xDC, 0x04, 0x00, 0x22, + 0x48, 0xF6, 0x19, 0x71, 0x48, 0x07, 0x20, 0xF8, 0x2A, 0x1F, 0x0B, 0x21, + 0x80, 0xF8, 0x3E, 0x10, 0x00, 0x21, 0x41, 0x83, 0x02, 0x21, 0x80, 0xF8, + 0xC0, 0x10, 0x4F, 0xF0, 0x08, 0x51, 0x01, 0x20, 0xC1, 0xF8, 0xD4, 0x03, + 0x01, 0x49, 0x08, 0x60, 0x70, 0x47, 0x00, 0x00, 0x44, 0x04, 0x00, 0x22, + 0x10, 0xB5, 0x0D, 0x20, 0x00, 0xF0, 0xCC, 0xF9, 0x03, 0x4C, 0x20, 0x68, + 0x00, 0x28, 0x02, 0xD0, 0x80, 0x47, 0x00, 0x20, 0x20, 0x60, 0x10, 0xBD, + 0x40, 0x25, 0x10, 0x00, 0x01, 0x21, 0x81, 0x40, 0xC8, 0xB2, 0x4F, 0xF0, + 0x00, 0x51, 0x91, 0xF8, 0x37, 0x10, 0x01, 0x42, 0x01, 0xD0, 0x01, 0x20, + 0x70, 0x47, 0x00, 0x20, 0x70, 0x47, 0x10, 0xB5, 0x0A, 0x20, 0x00, 0xF0, + 0x9B, 0xF9, 0x0B, 0x20, 0x00, 0xF0, 0x98, 0xF9, 0x0A, 0x20, 0x00, 0xF0, + 0x74, 0xF9, 0x0B, 0x20, 0x00, 0xF0, 0x71, 0xF9, 0x05, 0x21, 0x0A, 0x20, + 0x00, 0xF0, 0xD5, 0xF9, 0x05, 0x21, 0x0B, 0x20, 0x00, 0xF0, 0xD1, 0xF9, + 0x4F, 0xF0, 0x00, 0x50, 0x7F, 0x21, 0x00, 0xF8, 0x35, 0x1F, 0x41, 0x70, + 0xC1, 0x70, 0x00, 0x21, 0xC1, 0x71, 0x01, 0x72, 0x41, 0x72, 0x81, 0x72, + 0x10, 0xBD, 0x01, 0x23, 0x83, 0x40, 0xD8, 0xB2, 0x4F, 0xF0, 0x00, 0x53, + 0x00, 0x29, 0x93, 0xF8, 0x36, 0x10, 0x01, 0xD0, 0x01, 0x43, 0x00, 0xE0, + 0x81, 0x43, 0x83, 0xF8, 0x36, 0x10, 0x13, 0xF8, 0x38, 0x1F, 0x0A, 0xB1, + 0x01, 0x43, 0x00, 0xE0, 0x81, 0x43, 0x19, 0x70, 0x70, 0x47, 0x00, 0x00, + 0x01, 0x49, 0x01, 0x20, 0x08, 0x60, 0x70, 0x47, 0x40, 0x84, 0x00, 0x22, + 0x10, 0xB5, 0x72, 0xB6, 0x08, 0x49, 0x0C, 0x78, 0x00, 0x21, 0x04, 0xE0, + 0x06, 0x4A, 0x52, 0x1C, 0x52, 0x5C, 0x42, 0x54, 0x49, 0x1C, 0xA1, 0x42, + 0xF8, 0xDB, 0x40, 0xF6, 0xFC, 0x00, 0x00, 0xF0, 0x87, 0xFB, 0x62, 0xB6, + 0x20, 0x46, 0x10, 0xBD, 0x00, 0x04, 0x00, 0x20, 0x04, 0x48, 0x00, 0x78, + 0x03, 0x49, 0x49, 0x1C, 0x09, 0x78, 0x40, 0x1A, 0x00, 0xF0, 0x3F, 0x00, + 0x70, 0x47, 0x00, 0x00, 0x20, 0x04, 0x00, 0x20, 0x4F, 0xF0, 0x00, 0x50, + 0x90, 0xF8, 0x23, 0x00, 0x40, 0x08, 0x70, 0x47, 0x00, 0xB5, 0x4F, 0xF0, + 0xE0, 0x22, 0x01, 0x23, 0xC2, 0xF8, 0x80, 0x31, 0x02, 0xF5, 0xC0, 0x72, + 0x00, 0xF0, 0x16, 0xF8, 0x00, 0xF0, 0x0C, 0xF8, 0x04, 0x48, 0x03, 0x60, + 0xA0, 0x20, 0x82, 0xF8, 0x80, 0x02, 0xC2, 0xF8, 0x00, 0x31, 0x42, 0xF8, + 0x80, 0x3C, 0x00, 0xBD, 0x8C, 0x05, 0x00, 0x22, 0x02, 0x48, 0x01, 0x21, + 0x01, 0x60, 0x00, 0x21, 0x01, 0x60, 0x70, 0x47, 0x5C, 0x84, 0x00, 0x22, + 0x02, 0x48, 0x01, 0x21, 0x01, 0x60, 0x00, 0x21, 0x01, 0x60, 0x70, 0x47, + 0x94, 0x05, 0x00, 0x22, 0x03, 0x49, 0x10, 0xB1, 0x00, 0x20, 0x08, 0x60, + 0x70, 0x47, 0x01, 0x20, 0xFB, 0xE7, 0x00, 0x00, 0x8C, 0x05, 0x00, 0x22, + 0x02, 0x48, 0x01, 0x21, 0x01, 0x60, 0x00, 0x21, 0x01, 0x60, 0x70, 0x47, + 0x1C, 0x05, 0x00, 0x22, 0x4F, 0xF0, 0x00, 0x51, 0x02, 0x78, 0x81, 0xF8, + 0x00, 0x22, 0x42, 0x78, 0x81, 0xF8, 0x01, 0x22, 0x82, 0x78, 0x81, 0xF8, + 0x02, 0x22, 0xC2, 0x78, 0x81, 0xF8, 0x03, 0x22, 0x02, 0x79, 0x81, 0xF8, + 0x04, 0x22, 0x42, 0x79, 0x81, 0xF8, 0x05, 0x22, 0x82, 0x79, 0x81, 0xF8, + 0x06, 0x22, 0xC0, 0x79, 0x81, 0xF8, 0x07, 0x02, 0x70, 0x47, 0x00, 0x00, + 0x04, 0x49, 0x00, 0x22, 0x0A, 0x60, 0x4F, 0xF0, 0x00, 0x52, 0xA2, 0xF8, + 0x60, 0x00, 0x01, 0x20, 0x08, 0x60, 0x70, 0x47, 0x50, 0x09, 0x00, 0x22, + 0x0A, 0x4A, 0x51, 0x62, 0x11, 0x68, 0x48, 0x43, 0x0A, 0x21, 0xB0, 0xFB, + 0xF1, 0xF0, 0xB0, 0xF5, 0x80, 0x3F, 0x06, 0xDB, 0xA0, 0xF5, 0x7F, 0x40, + 0xFF, 0x38, 0x10, 0x62, 0x4F, 0xF6, 0xFF, 0x70, 0x02, 0xE0, 0x00, 0x21, + 0x80, 0xB2, 0x11, 0x62, 0xFF, 0xF7, 0xDE, 0xBF, 0xEC, 0x24, 0x10, 0x00, + 0x03, 0x49, 0x00, 0x20, 0x08, 0x60, 0x03, 0x49, 0x08, 0x62, 0x48, 0x62, + 0x70, 0x47, 0x00, 0x00, 0x50, 0x09, 0x00, 0x22, 0xEC, 0x24, 0x10, 0x00, + 0x0F, 0x49, 0x10, 0xB5, 0x08, 0x6A, 0xB0, 0xF5, 0x80, 0x3F, 0x06, 0xD3, + 0xA0, 0xF5, 0x7F, 0x40, 0xFF, 0x38, 0x08, 0x62, 0x4F, 0xF6, 0xFF, 0x70, + 0x03, 0xE0, 0x30, 0xB1, 0x00, 0x22, 0x80, 0xB2, 0x0A, 0x62, 0xBD, 0xE8, + 0x10, 0x40, 0xFF, 0xF7, 0xBB, 0xBF, 0x4A, 0x6A, 0xFF, 0xF7, 0xDC, 0xFF, + 0x12, 0xB1, 0xBD, 0xE8, 0x10, 0x40, 0x10, 0x47, 0x04, 0x20, 0x00, 0xF0, + 0xB3, 0xFA, 0x10, 0xBD, 0xEC, 0x24, 0x10, 0x00, 0x04, 0x49, 0x00, 0x22, + 0x0A, 0x60, 0x4F, 0xF0, 0x00, 0x52, 0xA2, 0xF8, 0x62, 0x00, 0x01, 0x20, + 0x08, 0x60, 0x70, 0x47, 0x54, 0x09, 0x00, 0x22, 0x0A, 0x4A, 0xD1, 0x62, + 0x11, 0x68, 0x48, 0x43, 0x0A, 0x21, 0xB0, 0xFB, 0xF1, 0xF0, 0xB0, 0xF5, + 0x80, 0x3F, 0x06, 0xDB, 0xA0, 0xF5, 0x7F, 0x40, 0xFF, 0x38, 0x90, 0x62, + 0x4F, 0xF6, 0xFF, 0x70, 0x02, 0xE0, 0x00, 0x21, 0x80, 0xB2, 0x91, 0x62, + 0xFF, 0xF7, 0xDE, 0xBF, 0xEC, 0x24, 0x10, 0x00, 0x03, 0x49, 0x00, 0x20, + 0x08, 0x60, 0x03, 0x49, 0x88, 0x62, 0xC8, 0x62, 0x70, 0x47, 0x00, 0x00, + 0x54, 0x09, 0x00, 0x22, 0xEC, 0x24, 0x10, 0x00, 0x0F, 0x49, 0x10, 0xB5, + 0x88, 0x6A, 0xB0, 0xF5, 0x80, 0x3F, 0x06, 0xD3, 0xA0, 0xF5, 0x7F, 0x40, + 0xFF, 0x38, 0x88, 0x62, 0x4F, 0xF6, 0xFF, 0x70, 0x03, 0xE0, 0x30, 0xB1, + 0x00, 0x22, 0x80, 0xB2, 0x8A, 0x62, 0xBD, 0xE8, 0x10, 0x40, 0xFF, 0xF7, + 0xBB, 0xBF, 0xCA, 0x6A, 0xFF, 0xF7, 0xDC, 0xFF, 0x12, 0xB1, 0xBD, 0xE8, + 0x10, 0x40, 0x10, 0x47, 0x05, 0x20, 0x00, 0xF0, 0x61, 0xFA, 0x10, 0xBD, + 0xEC, 0x24, 0x10, 0x00, 0x03, 0x4A, 0x40, 0x1C, 0x49, 0x1C, 0x12, 0x78, + 0x92, 0x1C, 0x01, 0xFB, 0x02, 0x00, 0x70, 0x47, 0x01, 0x24, 0x10, 0x00, + 0x02, 0x4A, 0x12, 0x78, 0x51, 0x43, 0x00, 0xEB, 0x41, 0x00, 0x70, 0x47, + 0x01, 0x24, 0x10, 0x00, 0x00, 0xF0, 0x1F, 0x02, 0x01, 0x21, 0x91, 0x40, + 0x40, 0x09, 0x80, 0x00, 0x00, 0xF1, 0xE0, 0x20, 0xC0, 0xF8, 0x80, 0x12, + 0x70, 0x47, 0x00, 0xF0, 0x1F, 0x02, 0x01, 0x21, 0x91, 0x40, 0x40, 0x09, + 0x80, 0x00, 0x00, 0xF1, 0xE0, 0x20, 0xC0, 0xF8, 0x80, 0x12, 0x70, 0x47, + 0x00, 0xF0, 0x1F, 0x02, 0x01, 0x21, 0x91, 0x40, 0x40, 0x09, 0x80, 0x00, + 0x00, 0xF1, 0xE0, 0x20, 0xC0, 0xF8, 0x80, 0x12, 0x70, 0x47, 0x00, 0xF0, + 0x1F, 0x02, 0x01, 0x21, 0x91, 0x40, 0x40, 0x09, 0x80, 0x00, 0x00, 0xF1, + 0xE0, 0x20, 0xC0, 0xF8, 0x80, 0x11, 0x70, 0x47, 0x00, 0xF0, 0x1F, 0x02, + 0x01, 0x21, 0x91, 0x40, 0x40, 0x09, 0x80, 0x00, 0x00, 0xF1, 0xE0, 0x20, + 0xC0, 0xF8, 0x80, 0x11, 0x70, 0x47, 0x00, 0xF0, 0x1F, 0x02, 0x01, 0x21, + 0x91, 0x40, 0x40, 0x09, 0x80, 0x00, 0x00, 0xF1, 0xE0, 0x20, 0xC0, 0xF8, + 0x80, 0x11, 0x70, 0x47, 0x00, 0xF0, 0x1F, 0x02, 0x01, 0x21, 0x91, 0x40, + 0x40, 0x09, 0x80, 0x00, 0x00, 0xF1, 0xE0, 0x20, 0xC0, 0xF8, 0x80, 0x11, + 0x70, 0x47, 0x00, 0xF0, 0x1F, 0x02, 0x01, 0x21, 0x91, 0x40, 0x40, 0x09, + 0x80, 0x00, 0x00, 0xF1, 0xE0, 0x20, 0xC0, 0xF8, 0x00, 0x11, 0x70, 0x47, + 0x00, 0xF0, 0x1F, 0x02, 0x01, 0x21, 0x91, 0x40, 0x40, 0x09, 0x80, 0x00, + 0x00, 0xF1, 0xE0, 0x20, 0xC0, 0xF8, 0x00, 0x11, 0x70, 0x47, 0x49, 0x07, + 0x09, 0x0E, 0x00, 0x28, 0x06, 0xDA, 0x00, 0xF0, 0x0F, 0x00, 0x00, 0xF1, + 0xE0, 0x20, 0x80, 0xF8, 0x14, 0x1D, 0x70, 0x47, 0x00, 0xF1, 0xE0, 0x20, + 0x80, 0xF8, 0x00, 0x14, 0x70, 0x47, 0x49, 0x07, 0x09, 0x0E, 0x00, 0x28, + 0x06, 0xDA, 0x00, 0xF0, 0x0F, 0x00, 0x00, 0xF1, 0xE0, 0x20, 0x80, 0xF8, + 0x14, 0x1D, 0x70, 0x47, 0x00, 0xF1, 0xE0, 0x20, 0x80, 0xF8, 0x00, 0x14, + 0x70, 0x47, 0x49, 0x07, 0x09, 0x0E, 0x00, 0x28, 0x06, 0xDA, 0x00, 0xF0, + 0x0F, 0x00, 0x00, 0xF1, 0xE0, 0x20, 0x80, 0xF8, 0x14, 0x1D, 0x70, 0x47, + 0x00, 0xF1, 0xE0, 0x20, 0x80, 0xF8, 0x00, 0x14, 0x70, 0x47, 0x00, 0x00, + 0x04, 0x49, 0x00, 0x22, 0x0A, 0x60, 0x4F, 0xF0, 0x00, 0x52, 0xA2, 0xF8, + 0x58, 0x00, 0x01, 0x20, 0x08, 0x60, 0x70, 0x47, 0x40, 0x09, 0x00, 0x22, + 0x0A, 0x4A, 0xD1, 0x60, 0x64, 0x21, 0x48, 0x43, 0x0A, 0x21, 0x90, 0xFB, + 0xF1, 0xF0, 0xB0, 0xF5, 0x80, 0x3F, 0x06, 0xDB, 0xA0, 0xF5, 0x7F, 0x40, + 0xFF, 0x38, 0x90, 0x60, 0x4F, 0xF6, 0xFF, 0x70, 0x02, 0xE0, 0x00, 0x21, + 0x80, 0xB2, 0x91, 0x60, 0xFF, 0xF7, 0xDE, 0xBF, 0xEC, 0x24, 0x10, 0x00, + 0x03, 0x49, 0x00, 0x20, 0x08, 0x60, 0x03, 0x49, 0x88, 0x60, 0xC8, 0x60, + 0x70, 0x47, 0x00, 0x00, 0x40, 0x09, 0x00, 0x22, 0xEC, 0x24, 0x10, 0x00, + 0x0F, 0x49, 0x10, 0xB5, 0x88, 0x68, 0xB0, 0xF5, 0x80, 0x3F, 0x06, 0xDB, + 0xA0, 0xF5, 0x7F, 0x40, 0xFF, 0x38, 0x88, 0x60, 0x4F, 0xF6, 0xFF, 0x70, + 0x03, 0xE0, 0x30, 0xB1, 0x00, 0x22, 0xC0, 0xB2, 0x8A, 0x60, 0xBD, 0xE8, + 0x10, 0x40, 0xFF, 0xF7, 0xBB, 0xBF, 0xCA, 0x68, 0xFF, 0xF7, 0xDC, 0xFF, + 0x12, 0xB1, 0xBD, 0xE8, 0x10, 0x40, 0x10, 0x47, 0x00, 0x20, 0x00, 0xF0, + 0x69, 0xF9, 0x10, 0xBD, 0xEC, 0x24, 0x10, 0x00, 0x04, 0x49, 0x00, 0x22, + 0x0A, 0x60, 0xCA, 0x06, 0xA2, 0xF8, 0x5A, 0x00, 0x01, 0x20, 0x08, 0x60, + 0x70, 0x47, 0x00, 0x00, 0x44, 0x09, 0x00, 0x22, 0x03, 0x49, 0x00, 0x20, + 0x08, 0x60, 0x03, 0x49, 0x08, 0x61, 0x48, 0x61, 0x70, 0x47, 0x00, 0x00, + 0x44, 0x09, 0x00, 0x22, 0xEC, 0x24, 0x10, 0x00, 0x10, 0x49, 0x10, 0xB5, + 0x08, 0x69, 0xB0, 0xF5, 0x80, 0x3F, 0x06, 0xDB, 0xA0, 0xF5, 0x7F, 0x40, + 0xFF, 0x38, 0x08, 0x61, 0x4F, 0xF6, 0xFF, 0x70, 0x04, 0xE0, 0x00, 0x28, + 0x06, 0xDD, 0x00, 0x22, 0x80, 0xB2, 0x0A, 0x61, 0xBD, 0xE8, 0x10, 0x40, + 0xFF, 0xF7, 0xD2, 0xBF, 0x4A, 0x69, 0xFF, 0xF7, 0xDB, 0xFF, 0x12, 0xB1, + 0xBD, 0xE8, 0x10, 0x40, 0x10, 0x47, 0x01, 0x20, 0x00, 0xF0, 0x2E, 0xF9, + 0x10, 0xBD, 0x00, 0x00, 0xEC, 0x24, 0x10, 0x00, 0x04, 0x49, 0x00, 0x22, + 0x0A, 0x60, 0x8A, 0x06, 0xA2, 0xF8, 0x5C, 0x00, 0x01, 0x20, 0x08, 0x60, + 0x70, 0x47, 0x00, 0x00, 0x48, 0x09, 0x00, 0x22, 0x09, 0x4A, 0xD1, 0x61, + 0x64, 0x21, 0x48, 0x43, 0x0A, 0x21, 0x90, 0xFB, 0xF1, 0xF0, 0xB0, 0xF5, + 0x80, 0x3F, 0x03, 0xDB, 0xFF, 0x38, 0x90, 0x61, 0xFF, 0x20, 0x02, 0xE0, + 0x00, 0x21, 0x80, 0xB2, 0x91, 0x61, 0xFF, 0xF7, 0xE1, 0xBF, 0x00, 0x00, + 0xEC, 0x24, 0x10, 0x00, 0x03, 0x49, 0x00, 0x20, 0x08, 0x60, 0x03, 0x49, + 0x88, 0x61, 0xC8, 0x61, 0x70, 0x47, 0x00, 0x00, 0x48, 0x09, 0x00, 0x22, + 0xEC, 0x24, 0x10, 0x00, 0x0F, 0x49, 0x10, 0xB5, 0x88, 0x69, 0xB0, 0xF5, + 0x80, 0x3F, 0x06, 0xDB, 0xA0, 0xF5, 0x7F, 0x40, 0xFF, 0x38, 0x88, 0x61, + 0x4F, 0xF6, 0xFF, 0x70, 0x03, 0xE0, 0x30, 0xB1, 0x00, 0x22, 0x80, 0xB2, + 0x8A, 0x61, 0xBD, 0xE8, 0x10, 0x40, 0xFF, 0xF7, 0xBD, 0xBF, 0xCA, 0x69, + 0xFF, 0xF7, 0xDC, 0xFF, 0x12, 0xB1, 0xBD, 0xE8, 0x10, 0x40, 0x10, 0x47, + 0x02, 0x20, 0x00, 0xF0, 0xDD, 0xF8, 0x10, 0xBD, 0xEC, 0x24, 0x10, 0x00, + 0x10, 0xB5, 0x04, 0x46, 0x0F, 0x20, 0xFF, 0xF7, 0x89, 0xFE, 0x0F, 0x20, + 0xFF, 0xF7, 0xD3, 0xFE, 0x09, 0x48, 0x44, 0x60, 0x4F, 0xF0, 0x00, 0x50, + 0xC1, 0x8C, 0x09, 0x06, 0x02, 0xD5, 0x4E, 0xF6, 0x60, 0x21, 0x01, 0xE0, + 0x4A, 0xF6, 0xC8, 0x71, 0x41, 0x65, 0x04, 0x49, 0x01, 0x20, 0x08, 0x60, + 0x09, 0x1D, 0x08, 0x60, 0x10, 0xBD, 0x00, 0x00, 0xEC, 0x24, 0x10, 0x00, + 0xF8, 0x09, 0x00, 0x22, 0x10, 0xB5, 0x02, 0x20, 0xFF, 0xF7, 0x8B, 0xFE, + 0x03, 0x20, 0xFF, 0xF7, 0x88, 0xFE, 0x04, 0x20, 0xFF, 0xF7, 0x85, 0xFE, + 0x05, 0x20, 0xFF, 0xF7, 0x82, 0xFE, 0x06, 0x20, 0xFF, 0xF7, 0x7F, 0xFE, + 0x07, 0x20, 0xFF, 0xF7, 0x7C, 0xFE, 0x08, 0x20, 0xFF, 0xF7, 0x79, 0xFE, + 0x09, 0x20, 0xFF, 0xF7, 0x76, 0xFE, 0x0F, 0x20, 0xFF, 0xF7, 0x73, 0xFE, + 0x4F, 0xF0, 0x00, 0x51, 0x00, 0x20, 0x01, 0xF8, 0x4A, 0x0F, 0x88, 0x71, + 0xF0, 0x22, 0xCA, 0x71, 0x0F, 0x22, 0x4A, 0x70, 0x31, 0x49, 0x08, 0x62, + 0x88, 0x62, 0x08, 0x63, 0x88, 0x60, 0x08, 0x61, 0x88, 0x61, 0xC8, 0x60, + 0x48, 0x61, 0xC8, 0x61, 0x48, 0x62, 0xC8, 0x62, 0x48, 0x63, 0x06, 0x21, + 0x02, 0x20, 0xFF, 0xF7, 0x9A, 0xFE, 0x06, 0x21, 0x03, 0x20, 0xFF, 0xF7, + 0x96, 0xFE, 0x06, 0x21, 0x04, 0x20, 0xFF, 0xF7, 0x92, 0xFE, 0x06, 0x21, + 0x05, 0x20, 0xFF, 0xF7, 0x8E, 0xFE, 0x06, 0x21, 0x08, 0x46, 0xFF, 0xF7, + 0x8A, 0xFE, 0x06, 0x21, 0x07, 0x20, 0xFF, 0xF7, 0x86, 0xFE, 0x06, 0x21, + 0x08, 0x20, 0xFF, 0xF7, 0x82, 0xFE, 0x04, 0x21, 0x09, 0x20, 0xFF, 0xF7, + 0x7E, 0xFE, 0x06, 0x21, 0x0F, 0x20, 0xFF, 0xF7, 0x7A, 0xFE, 0x02, 0x20, + 0xFF, 0xF7, 0x14, 0xFE, 0x03, 0x20, 0xFF, 0xF7, 0x11, 0xFE, 0x04, 0x20, + 0xFF, 0xF7, 0x0E, 0xFE, 0x05, 0x20, 0xFF, 0xF7, 0x0B, 0xFE, 0x06, 0x20, + 0xFF, 0xF7, 0x08, 0xFE, 0x07, 0x20, 0xFF, 0xF7, 0x05, 0xFE, 0x08, 0x20, + 0xFF, 0xF7, 0x02, 0xFE, 0x09, 0x20, 0xFF, 0xF7, 0xFF, 0xFD, 0x02, 0x20, + 0xFF, 0xF7, 0x49, 0xFE, 0x03, 0x20, 0xFF, 0xF7, 0x46, 0xFE, 0x04, 0x20, + 0xFF, 0xF7, 0x43, 0xFE, 0x05, 0x20, 0xFF, 0xF7, 0x40, 0xFE, 0x06, 0x20, + 0xFF, 0xF7, 0x3D, 0xFE, 0x07, 0x20, 0xFF, 0xF7, 0x3A, 0xFE, 0x08, 0x20, + 0xFF, 0xF7, 0x37, 0xFE, 0xBD, 0xE8, 0x10, 0x40, 0x09, 0x20, 0xFF, 0xF7, + 0x32, 0xBE, 0x00, 0x00, 0xEC, 0x24, 0x10, 0x00, 0x4F, 0xF0, 0x00, 0x50, + 0x90, 0xF8, 0x4A, 0x00, 0x00, 0x07, 0x00, 0xD0, 0x01, 0x20, 0x70, 0x47, + 0x10, 0xB5, 0x0F, 0x20, 0xFF, 0xF7, 0xF7, 0xFD, 0x4F, 0xF0, 0x00, 0x50, + 0xC0, 0x6C, 0x03, 0x49, 0x20, 0xF0, 0x7F, 0x40, 0x49, 0x68, 0xBD, 0xE8, + 0x10, 0x40, 0x08, 0x47, 0xEC, 0x24, 0x10, 0x00, 0x4F, 0xF0, 0x00, 0x51, + 0xC9, 0x8C, 0x4F, 0xEA, 0x90, 0x10, 0x0A, 0x06, 0x04, 0x49, 0x01, 0xD5, + 0x04, 0x4A, 0x00, 0xE0, 0x04, 0x4A, 0xB2, 0xFB, 0xF0, 0xF0, 0x08, 0x60, + 0x70, 0x47, 0x00, 0x00, 0xEC, 0x24, 0x10, 0x00, 0xC0, 0x27, 0x09, 0x00, + 0xD0, 0xDD, 0x06, 0x00, 0x70, 0x47, 0x00, 0x00, 0x70, 0xB5, 0x05, 0x46, + 0x00, 0x20, 0x02, 0x46, 0x07, 0x4C, 0x09, 0xE0, 0xAB, 0x5C, 0x52, 0x1C, + 0x03, 0xF0, 0x0F, 0x06, 0x04, 0xEB, 0x13, 0x13, 0xA6, 0x5D, 0x1B, 0x78, + 0x30, 0x44, 0x18, 0x44, 0x8A, 0x42, 0xF3, 0xDB, 0x70, 0xBD, 0x00, 0x00, + 0xE8, 0x21, 0x01, 0x00, 0x08, 0xB5, 0x00, 0x90, 0x40, 0x1E, 0x00, 0x90, + 0x00, 0x28, 0xFB, 0xDC, 0x08, 0xBD, 0x00, 0x00, 0xF0, 0xB5, 0x07, 0x46, + 0x00, 0x20, 0x03, 0x46, 0x0A, 0x4E, 0x10, 0xE0, 0x57, 0xF8, 0x23, 0x50, + 0x03, 0x22, 0x4F, 0xEA, 0xC2, 0x0C, 0x45, 0xFA, 0x0C, 0xF4, 0x84, 0xEA, + 0x20, 0x64, 0xE4, 0xB2, 0x52, 0x1E, 0x56, 0xF8, 0x24, 0x40, 0x84, 0xEA, + 0x00, 0x20, 0xF2, 0xD5, 0x5B, 0x1C, 0x8B, 0x42, 0xEC, 0xDB, 0xF0, 0xBD, + 0xF8, 0x21, 0x01, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, + 0x01, 0x00, 0x02, 0x00, 0x04, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, + 0x01, 0x00, 0x10, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0x14, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0C, 0x00, + 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x04, 0x00, 0x02, 0x00, + 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x10, 0x00, 0xFF, 0x00, 0xFF, 0x00, + 0x37, 0xB6, 0x00, 0x00, 0xF7, 0xBB, 0x00, 0x00, 0xFD, 0xB9, 0x00, 0x00, + 0xE1, 0xB9, 0x00, 0x00, 0x1B, 0xBA, 0x00, 0x00, 0x19, 0xBA, 0x00, 0x00, + 0x37, 0xB6, 0x00, 0x00, 0xDF, 0xB7, 0x00, 0x00, 0x23, 0xBA, 0x00, 0x00, + 0x21, 0xBA, 0x00, 0x00, 0x1D, 0xBA, 0x00, 0x00, 0x1F, 0xBA, 0x00, 0x00, + 0x37, 0xB6, 0x00, 0x00, 0x37, 0xB6, 0x00, 0x00, 0x37, 0xB6, 0x00, 0x00, + 0x37, 0xB6, 0x00, 0x00, 0x41, 0xB7, 0x00, 0x00, 0x45, 0xB7, 0x00, 0x00, + 0x51, 0xBA, 0x00, 0x00, 0x67, 0xBA, 0x00, 0x00, 0xAB, 0xBA, 0x00, 0x00, + 0xE3, 0xBB, 0x00, 0x00, 0x37, 0xB6, 0x00, 0x00, 0x0B, 0xBC, 0x00, 0x00, + 0x25, 0xBA, 0x00, 0x00, 0x37, 0xB6, 0x00, 0x00, 0xCD, 0xBA, 0x00, 0x00, + 0x3B, 0xBA, 0x00, 0x00, 0x37, 0xB6, 0x00, 0x00, 0x05, 0xB8, 0x00, 0x00, + 0xE1, 0xBA, 0x00, 0x00, 0x37, 0xB6, 0x00, 0x00, 0xF7, 0xBA, 0x00, 0x00, + 0x9B, 0xBB, 0x00, 0x00, 0xBF, 0xBB, 0x00, 0x00, 0x37, 0xB6, 0x00, 0x00, + 0x37, 0xB6, 0x00, 0x00, 0x37, 0xB6, 0x00, 0x00, 0x37, 0xB6, 0x00, 0x00, + 0x93, 0xB9, 0x00, 0x00, 0x51, 0xB9, 0x00, 0x00, 0x37, 0xB6, 0x00, 0x00, + 0x37, 0xB6, 0x00, 0x00, 0x37, 0xB6, 0x00, 0x00, 0x37, 0xB6, 0x00, 0x00, + 0x37, 0xB6, 0x00, 0x00, 0x37, 0xB6, 0x00, 0x00, 0x37, 0xB6, 0x00, 0x00, + 0x9B, 0xD6, 0x00, 0x00, 0x15, 0xD8, 0x00, 0x00, 0x13, 0xDE, 0x00, 0x00, + 0x7B, 0xDE, 0x00, 0x00, 0x33, 0xDF, 0x00, 0x00, 0xB9, 0xDB, 0x00, 0x00, + 0xB3, 0xD6, 0x00, 0x00, 0x97, 0xD6, 0x00, 0x00, 0x2F, 0xD8, 0x00, 0x00, + 0xAD, 0xDE, 0x00, 0x00, 0xD1, 0xDE, 0x00, 0x00, 0x61, 0xDF, 0x00, 0x00, + 0xDF, 0xDB, 0x00, 0x00, 0x97, 0xD6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x26, 0x01, 0x00, 0x06, 0x00, 0x00, 0x00, 0x60, 0x65, 0x10, 0x00, + 0x00, 0x04, 0x00, 0x00, 0x0D, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x60, 0x26, 0x01, 0x00, + 0x05, 0x00, 0x00, 0x00, 0x60, 0x69, 0x10, 0x00, 0x40, 0x06, 0x00, 0x00, + 0xDD, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x98, 0x26, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00, + 0xA0, 0x6F, 0x10, 0x00, 0x00, 0x08, 0x00, 0x00, 0x61, 0xB4, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0xF8, 0x25, 0x01, 0x00, 0x03, 0x00, 0x00, 0x00, 0xA0, 0x77, 0x10, 0x00, + 0xD0, 0x02, 0x00, 0x00, 0xDD, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x20, 0x26, 0x01, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x70, 0x7A, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x5D, 0xBC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x05, 0x00, 0x00, 0x00, 0x30, 0x26, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x70, 0x7B, 0x10, 0x00, 0x80, 0x00, 0x00, 0x00, 0xE9, 0xB5, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x28, 0x26, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x6C, 0x26, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x80, 0x26, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x48, 0x26, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x3C, 0x26, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0C, 0x26, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x54, 0x26, 0x01, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x90, 0x26, 0x01, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x78, 0x26, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00, 0x18, 0x26, 0x01, 0x00, + 0x5A, 0xD3, 0xD9, 0xE9, 0x6C, 0xF1, 0x45, 0xF5, 0x9F, 0xF7, 0x3C, 0xF9, + 0x6C, 0xFA, 0x58, 0xFB, 0x18, 0xFC, 0xB9, 0xFC, 0x44, 0xFD, 0xBF, 0xFD, + 0x2E, 0xFE, 0x94, 0xFE, 0xF4, 0xFE, 0x50, 0xFF, 0xA9, 0xFF, 0x00, 0x00, + 0x57, 0x00, 0xB0, 0x00, 0x0C, 0x01, 0x6C, 0x01, 0xD2, 0x01, 0x41, 0x02, + 0xBC, 0x02, 0x47, 0x03, 0xE8, 0x03, 0xA8, 0x04, 0x94, 0x05, 0xC4, 0x06, + 0x61, 0x08, 0xBB, 0x0A, 0x94, 0x0E, 0x27, 0x16, 0xA6, 0x2C, 0x00, 0x00, + 0xBE, 0x94, 0xFE, 0xFF, 0x27, 0xC4, 0xFE, 0xFF, 0x59, 0xF2, 0xFE, 0xFF, + 0x6B, 0x1F, 0xFF, 0xFF, 0x81, 0x4B, 0xFF, 0xFF, 0xC5, 0x76, 0xFF, 0xFF, + 0x67, 0xA1, 0xFF, 0xFF, 0x97, 0xCB, 0xFF, 0xFF, 0x88, 0xF5, 0xFF, 0xFF, + 0x6C, 0x1F, 0x00, 0x00, 0x76, 0x49, 0x00, 0x00, 0xD9, 0x73, 0x00, 0x00, + 0xC6, 0x9E, 0x00, 0x00, 0x6D, 0xCA, 0x00, 0x00, 0xFC, 0xF6, 0x00, 0x00, + 0x9A, 0x24, 0x01, 0x00, 0x66, 0x53, 0x01, 0x00, 0xA3, 0x8D, 0x00, 0x00, + 0x71, 0x74, 0x00, 0x00, 0x02, 0x60, 0x00, 0x00, 0xA2, 0x4F, 0x00, 0x00, + 0xC8, 0x42, 0x00, 0x00, 0x0C, 0x39, 0x00, 0x00, 0x21, 0x32, 0x00, 0x00, + 0xD2, 0x2D, 0x00, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x9B, 0x2C, 0x00, 0x00, + 0xA9, 0x2F, 0x00, 0x00, 0x40, 0x35, 0x00, 0x00, 0x8B, 0x3D, 0x00, 0x00, + 0xCB, 0x48, 0x00, 0x00, 0x59, 0x57, 0x00, 0x00, 0xAD, 0x69, 0x00, 0x00, + 0x65, 0x80, 0x00, 0x00, 0x30, 0x11, 0x00, 0x00, 0x4C, 0x1C, 0x00, 0x00, + 0x2D, 0x29, 0x00, 0x00, 0x86, 0x37, 0x00, 0x00, 0x24, 0x47, 0x00, 0x00, + 0xE8, 0x57, 0x00, 0x00, 0xC4, 0x69, 0x00, 0x00, 0xB5, 0x7C, 0x00, 0x00, + 0xC4, 0x90, 0x00, 0x00, 0x03, 0xA6, 0x00, 0x00, 0x8F, 0xBC, 0x00, 0x00, + 0x8C, 0xD4, 0x00, 0x00, 0x29, 0xEE, 0x00, 0x00, 0x9C, 0x09, 0x01, 0x00, + 0x2B, 0x27, 0x01, 0x00, 0x24, 0x47, 0x01, 0x00, 0xE6, 0x69, 0x01, 0x00, + 0x98, 0x08, 0x00, 0x00, 0x26, 0x0E, 0x00, 0x00, 0x97, 0x14, 0x00, 0x00, + 0xC3, 0x1B, 0x00, 0x00, 0x92, 0x23, 0x00, 0x00, 0xF4, 0x2B, 0x00, 0x00, + 0xE2, 0x34, 0x00, 0x00, 0x5A, 0x3E, 0x00, 0x00, 0x62, 0x48, 0x00, 0x00, + 0x02, 0x53, 0x00, 0x00, 0x48, 0x5E, 0x00, 0x00, 0x46, 0x6A, 0x00, 0x00, + 0x14, 0x77, 0x00, 0x00, 0xCE, 0x84, 0x00, 0x00, 0x95, 0x93, 0x00, 0x00, + 0x92, 0xA3, 0x00, 0x00, 0xF3, 0xB4, 0x00, 0x00, 0x61, 0x70, 0xFE, 0xFF, + 0xBE, 0x94, 0xFE, 0xFF, 0x6A, 0xB8, 0xFE, 0xFF, 0x66, 0xDB, 0xFE, 0xFF, + 0xB7, 0xFD, 0xFE, 0xFF, 0x6B, 0x1F, 0xFF, 0xFF, 0x91, 0x40, 0xFF, 0xFF, + 0x3A, 0x61, 0xFF, 0xFF, 0x7B, 0x81, 0xFF, 0xFF, 0x67, 0xA1, 0xFF, 0xFF, + 0x13, 0xC1, 0xFF, 0xFF, 0x94, 0xE0, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, + 0x6C, 0x1F, 0x00, 0x00, 0xED, 0x3E, 0x00, 0x00, 0x99, 0x5E, 0x00, 0x00, + 0x85, 0x7E, 0x00, 0x00, 0x30, 0xA4, 0x00, 0x00, 0xA3, 0x8D, 0x00, 0x00, + 0x43, 0x7A, 0x00, 0x00, 0xAD, 0x69, 0x00, 0x00, 0x8E, 0x5B, 0x00, 0x00, + 0xA2, 0x4F, 0x00, 0x00, 0xB0, 0x45, 0x00, 0x00, 0x8B, 0x3D, 0x00, 0x00, + 0x10, 0x37, 0x00, 0x00, 0x21, 0x32, 0x00, 0x00, 0xAA, 0x2E, 0x00, 0x00, + 0x9B, 0x2C, 0x00, 0x00, 0xEC, 0x2B, 0x00, 0x00, 0x9B, 0x2C, 0x00, 0x00, + 0xAA, 0x2E, 0x00, 0x00, 0x21, 0x32, 0x00, 0x00, 0x10, 0x37, 0x00, 0x00, + 0x48, 0x0A, 0x00, 0x00, 0x30, 0x11, 0x00, 0x00, 0x57, 0x19, 0x00, 0x00, + 0x89, 0x22, 0x00, 0x00, 0xA3, 0x2C, 0x00, 0x00, 0x86, 0x37, 0x00, 0x00, + 0x20, 0x43, 0x00, 0x00, 0x63, 0x4F, 0x00, 0x00, 0x45, 0x5C, 0x00, 0x00, + 0xC4, 0x69, 0x00, 0x00, 0xDE, 0x77, 0x00, 0x00, 0x97, 0x86, 0x00, 0x00, + 0xF6, 0x95, 0x00, 0x00, 0x03, 0xA6, 0x00, 0x00, 0xCB, 0xB6, 0x00, 0x00, + 0x5D, 0xC8, 0x00, 0x00, 0xCB, 0xDA, 0x00, 0x00, 0x24, 0x05, 0x00, 0x00, + 0x98, 0x08, 0x00, 0x00, 0xAB, 0x0C, 0x00, 0x00, 0x45, 0x11, 0x00, 0x00, + 0x51, 0x16, 0x00, 0x00, 0xC3, 0x1B, 0x00, 0x00, 0x90, 0x21, 0x00, 0x00, + 0xB1, 0x27, 0x00, 0x00, 0x23, 0x2E, 0x00, 0x00, 0xE2, 0x34, 0x00, 0x00, + 0xEF, 0x3B, 0x00, 0x00, 0x4C, 0x43, 0x00, 0x00, 0xFB, 0x4A, 0x00, 0x00, + 0x02, 0x53, 0x00, 0x00, 0x66, 0x5B, 0x00, 0x00, 0x2F, 0x64, 0x00, 0x00, + 0x65, 0x6D, 0x00, 0x00, 0x00, 0x01, 0x01, 0x02, 0x01, 0x02, 0x02, 0x03, + 0x01, 0x02, 0x02, 0x03, 0x02, 0x03, 0x03, 0x04, 0x00, 0x00, 0x00, 0x00, + 0x1B, 0x00, 0x00, 0x80, 0x2D, 0x00, 0x00, 0x80, 0x36, 0x00, 0x00, 0x00, + 0x41, 0x00, 0x00, 0x80, 0x5A, 0x00, 0x00, 0x00, 0x6C, 0x00, 0x00, 0x00, + 0x77, 0x00, 0x00, 0x80, 0x99, 0x00, 0x00, 0x80, 0x82, 0x00, 0x00, 0x00, + 0xB4, 0x00, 0x00, 0x00, 0xAF, 0x00, 0x00, 0x80, 0xD8, 0x00, 0x00, 0x00, + 0xC3, 0x00, 0x00, 0x80, 0xF5, 0x00, 0x00, 0x80, 0xEE, 0x00, 0x00, 0x00, + 0x29, 0x01, 0x00, 0x80, 0x32, 0x01, 0x00, 0x00, 0x04, 0x01, 0x00, 0x00, + 0x1F, 0x01, 0x00, 0x80, 0x68, 0x01, 0x00, 0x00, 0x73, 0x01, 0x00, 0x80, + 0x45, 0x01, 0x00, 0x80, 0x5E, 0x01, 0x00, 0x00, 0xB0, 0x01, 0x00, 0x00, + 0xAB, 0x01, 0x00, 0x80, 0x9D, 0x01, 0x00, 0x80, 0x86, 0x01, 0x00, 0x00, + 0xF1, 0x01, 0x00, 0x80, 0xEA, 0x01, 0x00, 0x00, 0xDC, 0x01, 0x00, 0x00, + 0xC7, 0x01, 0x00, 0x80, 0x49, 0x02, 0x00, 0x80, 0x52, 0x02, 0x00, 0x00, + 0x64, 0x02, 0x00, 0x00, 0x7F, 0x02, 0x00, 0x80, 0x08, 0x02, 0x00, 0x00, + 0x13, 0x02, 0x00, 0x80, 0x25, 0x02, 0x00, 0x80, 0x3E, 0x02, 0x00, 0x00, + 0xD0, 0x02, 0x00, 0x00, 0xCB, 0x02, 0x00, 0x80, 0xFD, 0x02, 0x00, 0x80, + 0xE6, 0x02, 0x00, 0x00, 0x91, 0x02, 0x00, 0x80, 0x8A, 0x02, 0x00, 0x00, + 0xBC, 0x02, 0x00, 0x00, 0xA7, 0x02, 0x00, 0x80, 0x60, 0x03, 0x00, 0x00, + 0x7B, 0x03, 0x00, 0x80, 0x4D, 0x03, 0x00, 0x80, 0x56, 0x03, 0x00, 0x00, + 0x21, 0x03, 0x00, 0x80, 0x3A, 0x03, 0x00, 0x00, 0x0C, 0x03, 0x00, 0x00, + 0x17, 0x03, 0x00, 0x80, 0xF9, 0x03, 0x00, 0x80, 0xE2, 0x03, 0x00, 0x00, + 0xD4, 0x03, 0x00, 0x00, 0xCF, 0x03, 0x00, 0x80, 0xB8, 0x03, 0x00, 0x00, + 0xA3, 0x03, 0x00, 0x80, 0x95, 0x03, 0x00, 0x80, 0x8E, 0x03, 0x00, 0x00, + 0x89, 0x04, 0x00, 0x80, 0x92, 0x04, 0x00, 0x00, 0xA4, 0x04, 0x00, 0x00, + 0xBF, 0x04, 0x00, 0x80, 0xC8, 0x04, 0x00, 0x00, 0xD3, 0x04, 0x00, 0x80, + 0xE5, 0x04, 0x00, 0x80, 0xFE, 0x04, 0x00, 0x00, 0x10, 0x04, 0x00, 0x00, + 0x0B, 0x04, 0x00, 0x80, 0x3D, 0x04, 0x00, 0x80, 0x26, 0x04, 0x00, 0x00, + 0x51, 0x04, 0x00, 0x80, 0x4A, 0x04, 0x00, 0x00, 0x7C, 0x04, 0x00, 0x00, + 0x67, 0x04, 0x00, 0x80, 0xA0, 0x05, 0x00, 0x00, 0xBB, 0x05, 0x00, 0x80, + 0x8D, 0x05, 0x00, 0x80, 0x96, 0x05, 0x00, 0x00, 0xE1, 0x05, 0x00, 0x80, + 0xFA, 0x05, 0x00, 0x00, 0xCC, 0x05, 0x00, 0x00, 0xD7, 0x05, 0x00, 0x80, + 0x39, 0x05, 0x00, 0x80, 0x22, 0x05, 0x00, 0x00, 0x14, 0x05, 0x00, 0x00, + 0x0F, 0x05, 0x00, 0x80, 0x78, 0x05, 0x00, 0x00, 0x63, 0x05, 0x00, 0x80, + 0x55, 0x05, 0x00, 0x80, 0x4E, 0x05, 0x00, 0x00, 0xC0, 0x06, 0x00, 0x00, + 0xDB, 0x06, 0x00, 0x80, 0xED, 0x06, 0x00, 0x80, 0xF6, 0x06, 0x00, 0x00, + 0x81, 0x06, 0x00, 0x80, 0x9A, 0x06, 0x00, 0x00, 0xAC, 0x06, 0x00, 0x00, + 0xB7, 0x06, 0x00, 0x80, 0x59, 0x06, 0x00, 0x80, 0x42, 0x06, 0x00, 0x00, + 0x74, 0x06, 0x00, 0x00, 0x6F, 0x06, 0x00, 0x80, 0x18, 0x06, 0x00, 0x00, + 0x03, 0x06, 0x00, 0x80, 0x35, 0x06, 0x00, 0x80, 0x2E, 0x06, 0x00, 0x00, + 0xE9, 0x07, 0x00, 0x80, 0xF2, 0x07, 0x00, 0x00, 0xC4, 0x07, 0x00, 0x00, + 0xDF, 0x07, 0x00, 0x80, 0xA8, 0x07, 0x00, 0x00, 0xB3, 0x07, 0x00, 0x80, + 0x85, 0x07, 0x00, 0x80, 0x9E, 0x07, 0x00, 0x00, 0x70, 0x07, 0x00, 0x00, + 0x6B, 0x07, 0x00, 0x80, 0x5D, 0x07, 0x00, 0x80, 0x46, 0x07, 0x00, 0x00, + 0x31, 0x07, 0x00, 0x80, 0x2A, 0x07, 0x00, 0x00, 0x1C, 0x07, 0x00, 0x00, + 0x07, 0x07, 0x00, 0x80, 0x09, 0x09, 0x00, 0x80, 0x12, 0x09, 0x00, 0x00, + 0x24, 0x09, 0x00, 0x00, 0x3F, 0x09, 0x00, 0x80, 0x48, 0x09, 0x00, 0x00, + 0x53, 0x09, 0x00, 0x80, 0x65, 0x09, 0x00, 0x80, 0x7E, 0x09, 0x00, 0x00, + 0x90, 0x09, 0x00, 0x00, 0x8B, 0x09, 0x00, 0x80, 0xBD, 0x09, 0x00, 0x80, + 0xA6, 0x09, 0x00, 0x00, 0xD1, 0x09, 0x00, 0x80, 0xCA, 0x09, 0x00, 0x00, + 0xFC, 0x09, 0x00, 0x00, 0xE7, 0x09, 0x00, 0x80, 0x20, 0x08, 0x00, 0x00, + 0x3B, 0x08, 0x00, 0x80, 0x0D, 0x08, 0x00, 0x80, 0x16, 0x08, 0x00, 0x00, + 0x61, 0x08, 0x00, 0x80, 0x7A, 0x08, 0x00, 0x00, 0x4C, 0x08, 0x00, 0x00, + 0x57, 0x08, 0x00, 0x80, 0xB9, 0x08, 0x00, 0x80, 0xA2, 0x08, 0x00, 0x00, + 0x94, 0x08, 0x00, 0x00, 0x8F, 0x08, 0x00, 0x80, 0xF8, 0x08, 0x00, 0x00, + 0xE3, 0x08, 0x00, 0x80, 0xD5, 0x08, 0x00, 0x80, 0xCE, 0x08, 0x00, 0x00, + 0x40, 0x0B, 0x00, 0x00, 0x5B, 0x0B, 0x00, 0x80, 0x6D, 0x0B, 0x00, 0x80, + 0x76, 0x0B, 0x00, 0x00, 0x01, 0x0B, 0x00, 0x80, 0x1A, 0x0B, 0x00, 0x00, + 0x2C, 0x0B, 0x00, 0x00, 0x37, 0x0B, 0x00, 0x80, 0xD9, 0x0B, 0x00, 0x80, + 0xC2, 0x0B, 0x00, 0x00, 0xF4, 0x0B, 0x00, 0x00, 0xEF, 0x0B, 0x00, 0x80, + 0x98, 0x0B, 0x00, 0x00, 0x83, 0x0B, 0x00, 0x80, 0xB5, 0x0B, 0x00, 0x80, + 0xAE, 0x0B, 0x00, 0x00, 0x69, 0x0A, 0x00, 0x80, 0x72, 0x0A, 0x00, 0x00, + 0x44, 0x0A, 0x00, 0x00, 0x5F, 0x0A, 0x00, 0x80, 0x28, 0x0A, 0x00, 0x00, + 0x33, 0x0A, 0x00, 0x80, 0x05, 0x0A, 0x00, 0x80, 0x1E, 0x0A, 0x00, 0x00, + 0xF0, 0x0A, 0x00, 0x00, 0xEB, 0x0A, 0x00, 0x80, 0xDD, 0x0A, 0x00, 0x80, + 0xC6, 0x0A, 0x00, 0x00, 0xB1, 0x0A, 0x00, 0x80, 0xAA, 0x0A, 0x00, 0x00, + 0x9C, 0x0A, 0x00, 0x00, 0x87, 0x0A, 0x00, 0x80, 0x80, 0x0D, 0x00, 0x00, + 0x9B, 0x0D, 0x00, 0x80, 0xAD, 0x0D, 0x00, 0x80, 0xB6, 0x0D, 0x00, 0x00, + 0xC1, 0x0D, 0x00, 0x80, 0xDA, 0x0D, 0x00, 0x00, 0xEC, 0x0D, 0x00, 0x00, + 0xF7, 0x0D, 0x00, 0x80, 0x19, 0x0D, 0x00, 0x80, 0x02, 0x0D, 0x00, 0x00, + 0x34, 0x0D, 0x00, 0x00, 0x2F, 0x0D, 0x00, 0x80, 0x58, 0x0D, 0x00, 0x00, + 0x43, 0x0D, 0x00, 0x80, 0x75, 0x0D, 0x00, 0x80, 0x6E, 0x0D, 0x00, 0x00, + 0xA9, 0x0C, 0x00, 0x80, 0xB2, 0x0C, 0x00, 0x00, 0x84, 0x0C, 0x00, 0x00, + 0x9F, 0x0C, 0x00, 0x80, 0xE8, 0x0C, 0x00, 0x00, 0xF3, 0x0C, 0x00, 0x80, + 0xC5, 0x0C, 0x00, 0x80, 0xDE, 0x0C, 0x00, 0x00, 0x30, 0x0C, 0x00, 0x00, + 0x2B, 0x0C, 0x00, 0x80, 0x1D, 0x0C, 0x00, 0x80, 0x06, 0x0C, 0x00, 0x00, + 0x71, 0x0C, 0x00, 0x80, 0x6A, 0x0C, 0x00, 0x00, 0x5C, 0x0C, 0x00, 0x00, + 0x47, 0x0C, 0x00, 0x80, 0xC9, 0x0F, 0x00, 0x80, 0xD2, 0x0F, 0x00, 0x00, + 0xE4, 0x0F, 0x00, 0x00, 0xFF, 0x0F, 0x00, 0x80, 0x88, 0x0F, 0x00, 0x00, + 0x93, 0x0F, 0x00, 0x80, 0xA5, 0x0F, 0x00, 0x80, 0xBE, 0x0F, 0x00, 0x00, + 0x50, 0x0F, 0x00, 0x00, 0x4B, 0x0F, 0x00, 0x80, 0x7D, 0x0F, 0x00, 0x80, + 0x66, 0x0F, 0x00, 0x00, 0x11, 0x0F, 0x00, 0x80, 0x0A, 0x0F, 0x00, 0x00, + 0x3C, 0x0F, 0x00, 0x00, 0x27, 0x0F, 0x00, 0x80, 0xE0, 0x0E, 0x00, 0x00, + 0xFB, 0x0E, 0x00, 0x80, 0xCD, 0x0E, 0x00, 0x80, 0xD6, 0x0E, 0x00, 0x00, + 0xA1, 0x0E, 0x00, 0x80, 0xBA, 0x0E, 0x00, 0x00, 0x8C, 0x0E, 0x00, 0x00, + 0x97, 0x0E, 0x00, 0x80, 0x79, 0x0E, 0x00, 0x80, 0x62, 0x0E, 0x00, 0x00, + 0x54, 0x0E, 0x00, 0x00, 0x4F, 0x0E, 0x00, 0x80, 0x38, 0x0E, 0x00, 0x00, + 0x23, 0x0E, 0x00, 0x80, 0x15, 0x0E, 0x00, 0x80, 0x0E, 0x0E, 0x00, 0x00, + 0x54, 0x73, 0x6B, 0x5F, 0x53, 0x53, 0x00, 0x00, 0x54, 0x73, 0x6B, 0x5F, + 0x53, 0x53, 0x76, 0x63, 0x00, 0x00, 0x00, 0x00, 0x45, 0x6C, 0x66, 0x5F, + 0x53, 0x73, 0x76, 0x63, 0x00, 0x00, 0x00, 0x00, 0x45, 0x6C, 0x66, 0x5F, + 0x43, 0x6D, 0x64, 0x00, 0x54, 0x73, 0x6B, 0x5F, 0x43, 0x6D, 0x64, 0x00, + 0x53, 0x65, 0x6D, 0x5F, 0x41, 0x66, 0x65, 0x00, 0x54, 0x73, 0x6B, 0x5F, + 0x49, 0x64, 0x6C, 0x65, 0x00, 0x00, 0x00, 0x00, 0x53, 0x65, 0x6D, 0x5F, + 0x4D, 0x53, 0x42, 0x75, 0x66, 0x66, 0x00, 0x00, 0x53, 0x65, 0x6D, 0x5F, + 0x53, 0x53, 0x42, 0x75, 0x66, 0x66, 0x00, 0x00, 0x45, 0x6C, 0x66, 0x5F, + 0x53, 0x63, 0x61, 0x6E, 0x00, 0x00, 0x00, 0x00, 0x54, 0x73, 0x6B, 0x5F, + 0x53, 0x63, 0x61, 0x6E, 0x00, 0x00, 0x00, 0x00, 0x53, 0x65, 0x6D, 0x5F, + 0x45, 0x76, 0x74, 0x46, 0x69, 0x66, 0x6F, 0x00, 0x45, 0x6C, 0x66, 0x5F, + 0x53, 0x73, 0x00, 0x00, 0x53, 0x65, 0x6D, 0x5F, 0x43, 0x61, 0x6C, 0x69, + 0x62, 0x46, 0x72, 0x61, 0x6D, 0x65, 0x73, 0x00, 0x45, 0x6C, 0x66, 0x5F, + 0x4D, 0x74, 0x00, 0x00, 0x54, 0x73, 0x6B, 0x5F, 0x4D, 0x74, 0x00, 0x00, + 0xD0, 0x26, 0x01, 0x00, 0x00, 0x22, 0x10, 0x00, 0x58, 0x03, 0x00, 0x00, + 0x1C, 0x01, 0x00, 0x00, 0x08, 0x27, 0x01, 0x00, 0x00, 0xFC, 0x10, 0x00, + 0xC8, 0x00, 0x00, 0x00, 0x78, 0x01, 0x00, 0x00, 0x08, 0x27, 0x01, 0x00, + 0x58, 0x25, 0x10, 0x00, 0xA8, 0x61, 0x00, 0x00, 0x94, 0x01, 0x00, 0x00, + 0x01, 0xFF, 0x01, 0xFF, 0x01, 0x54, 0x1A, 0x10, 0x03, 0x19, 0x04, 0x01, + 0x23, 0x14, 0xC8, 0x1F, 0x01, 0x14, 0x90, 0x5F, 0x01, 0x32, 0x01, 0x32, + 0x02, 0x29, 0x08, 0x41, 0xA9, 0x08, 0x09, 0x1A, 0x0C, 0xA3, 0xE8, 0x03, + 0x29, 0x0C, 0x69, 0x48, 0x29, 0x04, 0x5A, 0x04, 0x24, 0xA9, 0x10, 0x01, + 0x3C, 0x0B, 0x24, 0x4C, 0x86, 0xD4, 0x81, 0x00, 0x30, 0xB5, 0x72, 0xB6, + 0x01, 0x25, 0x0D, 0x4C, 0x25, 0x60, 0x00, 0x23, 0x6A, 0x07, 0x01, 0x29, + 0x10, 0xD0, 0x82, 0xF8, 0x6B, 0x30, 0x00, 0xF0, 0x3F, 0x00, 0x82, 0xF8, + 0x6A, 0x00, 0x08, 0x48, 0x05, 0x60, 0x01, 0x68, 0x00, 0x29, 0xFC, 0xD1, + 0x05, 0x48, 0x1C, 0x30, 0x03, 0x60, 0x23, 0x60, 0x62, 0xB6, 0x30, 0xBD, + 0x40, 0x21, 0x82, 0xF8, 0x6B, 0x10, 0xEC, 0xE7, 0x40, 0x1B, 0x00, 0x22, + 0x5C, 0x0D, 0x00, 0x22, 0x3C, 0xB5, 0x4F, 0xF0, 0x00, 0x51, 0xD0, 0x20, + 0x81, 0xF8, 0xC3, 0x00, 0x40, 0xF2, 0xA7, 0x70, 0xC8, 0x84, 0x45, 0x20, + 0xA1, 0xF8, 0x52, 0x00, 0xA1, 0xF8, 0x52, 0x00, 0x40, 0x23, 0x81, 0xF8, + 0x20, 0x30, 0x44, 0x24, 0x81, 0xF8, 0x20, 0x40, 0x4F, 0xF4, 0x96, 0x75, + 0x00, 0x22, 0xCD, 0xE9, 0x00, 0x52, 0x00, 0x98, 0x40, 0x1E, 0x00, 0x90, + 0x01, 0x98, 0x40, 0x1C, 0x01, 0x90, 0xFA, 0x28, 0xF7, 0xDB, 0x0D, 0xE0, + 0x81, 0xF8, 0x20, 0x30, 0x81, 0xF8, 0x20, 0x40, 0xCD, 0xE9, 0x00, 0x52, + 0x00, 0x98, 0x40, 0x1E, 0x00, 0x90, 0x01, 0x98, 0x40, 0x1C, 0x01, 0x90, + 0xFA, 0x28, 0xF7, 0xDB, 0x91, 0xF8, 0x20, 0x00, 0xC0, 0x06, 0xED, 0xD4, + 0x81, 0xF8, 0xC3, 0x20, 0x41, 0xF2, 0xA4, 0x40, 0xC8, 0x84, 0x40, 0xF2, + 0x57, 0x20, 0x21, 0xF8, 0x52, 0x0F, 0x21, 0xF8, 0x32, 0x09, 0x4C, 0x20, + 0x08, 0x70, 0x3C, 0xBD, 0xA5, 0x02, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x07, + 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x1B, 0x16, 0xFF, 0x09, 0x9F, 0x05, 0xFF, 0x09, 0x9F, 0x05, 0x03, 0x02, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x0B, 0x0B, 0x0C, 0x37, 0x11, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x02, 0x32, 0x00, + 0x64, 0x00, 0x64, 0x00, 0x64, 0x10, 0x00, 0x00, 0x03, 0xA9, 0x2A, 0x10, + 0x20, 0x30, 0x0A, 0x08, 0x88, 0x88, 0x00, 0x01, 0x80, 0x00, 0xFF, 0x07, + 0xFF, 0x07, 0xFF, 0x7F, 0x70, 0x00, 0xFF, 0x7F, 0x70, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xB0, 0x00, + 0xB0, 0x00, 0x80, 0x00, 0x10, 0x00, 0x40, 0x00, 0x10, 0x00, 0x18, 0x21, + 0x55, 0x04, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x90, 0x01, 0x00, 0x00, 0x10, 0xFF, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x01, 0x08, 0x01, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0xC8, 0x00, 0xA0, 0x00, 0x00, 0x01, + 0xFF, 0x7F, 0x40, 0x00, 0x20, 0x00, 0x02, 0x01, 0x00, 0x02, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0xC8, 0x00, 0x10, 0x14, + 0x64, 0x00, 0x50, 0x02, 0x00, 0x02, 0xC8, 0x00, 0x02, 0x00, 0x00, 0x02, + 0x11, 0x00, 0xFF, 0x7F, 0x02, 0x00, 0x00, 0x00, 0x05, 0x00, 0xA0, 0x00, + 0x20, 0x04, 0x90, 0x01, 0x02, 0x05, 0x20, 0x03, 0x00, 0x02, 0x04, 0x00, + 0x80, 0x00, 0x50, 0x00, 0x00, 0x01, 0x14, 0x0A, 0x78, 0x00, 0x00, 0x27, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0xC8, 0x00, 0x0A, 0x00, 0x00, 0x00, + 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x09, 0x14, 0x20, 0x00, 0x00, 0x00, + 0x33, 0x02, 0x13, 0x14, 0x15, 0x00, 0x19, 0x00, 0x53, 0x8D, 0x02, 0x64, + 0x2C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x80, 0x00, 0x10, 0x11, + 0x15, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0x02, 0x10, 0x00, + 0x40, 0x00, 0x10, 0x00, 0xC0, 0x00, 0x40, 0x62, 0x00, 0x00, 0x80, 0x03, + 0x08, 0x0E, 0x0A, 0x08, 0x01, 0x0A, 0x00, 0x01, 0x08, 0x01, 0x5A, 0x55, + 0x05, 0x00, 0x00, 0x01, 0x30, 0x00, 0x80, 0x01, 0x50, 0x00, 0x20, 0x03, + 0xDC, 0x05, 0xB0, 0x04, 0x78, 0x05, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, + 0x4C, 0x00, 0x00, 0x02, 0x01, 0x50, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, + 0x32, 0x50, 0x14, 0x09, 0xEC, 0x00, 0x40, 0x01, 0x50, 0x00, 0x00, 0x46, + 0x00, 0x00, 0x00, 0x00, 0x02, 0xF7, 0x00, 0x01, 0x64, 0x00, 0x00, 0x03, + 0x0A, 0x10, 0x51, 0x5A, 0x10, 0x1F, 0x08, 0x01, 0x0A, 0x0A, 0x20, 0x20, + 0x10, 0x64, 0x10, 0x50, 0xF0, 0xF0, 0x00, 0xA4, 0x20, 0x00, 0xC0, 0x00, + 0x02, 0x02, 0x02, 0x02, 0x10, 0x00, 0xC0, 0x00, 0x1E, 0x00, 0x00, 0x00, + 0x02, 0xA4, 0x08, 0x10, 0x84, 0x00, 0x10, 0x1A, 0x16, 0x0A, 0x20, 0x00, + 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x08, 0x08, 0x10, 0x10, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0B, 0x00, 0x80, 0x00, 0x14, 0x00, 0xB0, 0x04, 0x06, 0x00, 0x00, 0x06, + 0x04, 0xF0, 0x10, 0x02, 0xC0, 0x02, 0x50, 0x00, 0x70, 0x00, 0xA4, 0x32, + 0x00, 0x00, 0x02, 0x00, 0x10, 0x00, 0x40, 0x00, 0x10, 0x00, 0x2C, 0x01, + 0x40, 0x84, 0x64, 0x00, 0x5A, 0x00, 0x01, 0x04, 0x00, 0x02, 0x00, 0x03, + 0x11, 0x00, 0x10, 0x00, 0x64, 0x00, 0xD2, 0x32, 0xC2, 0x01, 0x00, 0x01, + 0x30, 0x00, 0x00, 0x00, 0x7F, 0x3E, 0x64, 0x00, 0x64, 0x00, 0x14, 0x14, + 0x32, 0x32, 0x32, 0x32, 0x00, 0x00, 0x02, 0x14, 0x00, 0x01, 0x00, 0xAA, + 0x20, 0x03, 0x32, 0x03, 0x43, 0x0A, 0x32, 0x32, 0x00, 0x08, 0x00, 0x80, + 0x10, 0x10, 0x03, 0x08, 0x00, 0x04, 0xE8, 0x80, 0x20, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x11, 0x0D, 0x0D, 0x81, 0x90, 0x01, + 0x50, 0x08, 0x14, 0x01, 0x90, 0x01, 0xBC, 0x02, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x40, 0x40, 0x40, 0x20, 0x20, 0x00, 0x10, 0xA0, 0x00, 0x00, 0xFF, 0x00, + 0x0A, 0x10, 0x10, 0x10, 0x32, 0x40, 0x00, 0x00, 0x01, 0x20, 0x64, 0x64, + 0x77, 0x30, 0x19, 0x10, 0x10, 0x00, 0x01, 0x12, 0x12, 0x00, 0x20, 0x00, + 0x00, 0x00, 0x03, 0x00, 0x2C, 0x01, 0xFA, 0x00, 0x0A, 0x02, 0x00, 0x00, + 0x01, 0x20, 0x10, 0x10, 0x20, 0xC8, 0x1E, 0x01, 0x06, 0x3C, 0x50, 0x50, + 0x00, 0xFF, 0x80, 0x00, 0x03, 0x7F, 0x05, 0x0A, 0x1A, 0x06, 0x05, 0x0F, + 0x00, 0x00, 0x00, 0x00, 0x0A, 0x0A, 0x05, 0x01, 0x20, 0x30, 0xC8, 0x00, + 0x96, 0x00, 0x00, 0x00, 0x00, 0x01, 0x82, 0x00, 0xFA, 0x00, 0x00, 0x08, + 0x60, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x04, + 0x96, 0x00, 0x32, 0x00, 0xFC, 0x03, 0x3E, 0x01, 0x88, 0x00, 0x31, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x31, 0x00, 0x88, 0x00, 0x3E, 0x01, + 0xFC, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x78, 0xC8, 0xD9, 0xE3, 0xE8, 0xF0, 0xF5, 0xFA, 0xFA, 0xFA, 0xF5, 0xF0, + 0xE8, 0xE3, 0xD9, 0xC8, 0x78, 0x64, 0x64, 0x64, 0x64, 0x64, 0x9C, 0xB6, + 0xBC, 0xC2, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, + 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, + 0xC2, 0xBC, 0xB6, 0x9C, 0x64, 0x64, 0x64, 0x64, 0x64, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x05, 0x03, 0x05, 0x0A, 0x03, + 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0x00, 0x00, 0xFF, 0x0F, 0x00, 0x00, + 0xFF, 0x0F, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0x0F, 0xFF, 0x0F, 0x03, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xA3, 0x2C, 0x01, 0xC8, 0x00, 0x64, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x14, 0x02, 0x05, 0x03, + 0x03, 0x0A, 0x0A, 0x0A, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x05, 0x05, 0x00, 0x00, + 0x01, 0x00, 0x02, 0x00, 0x03, 0x00, 0x04, 0x00, 0x05, 0x00, 0x06, 0x00, + 0x07, 0x00, 0x08, 0x00, 0x09, 0x00, 0x0A, 0x00, 0x0B, 0x00, 0x0C, 0x00, + 0x0D, 0x00, 0x0E, 0x00, 0x0F, 0x00, 0x10, 0x00, 0x11, 0x00, 0x12, 0x00, + 0x13, 0x00, 0x14, 0x00, 0x15, 0x00, 0x16, 0x00, 0x17, 0x00, 0x18, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x7F, 0x00, 0xA2, 0xA2, 0x10, 0x0C, 0xA0, 0x00, 0xA0, 0x00, 0x60, 0x00, + 0x5A, 0x35, 0x35, 0x81, 0xB8, 0x0B, 0x56, 0xBB, 0x28, 0x28, 0x28, 0x28, + 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x10, 0x00, 0x15, 0x00, + 0x1A, 0x00, 0x20, 0x00, 0x25, 0x00, 0x2A, 0x00, 0x0F, 0x03, 0x0E, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x19, 0x19, 0x00, 0x00, 0x32, + 0x00, 0x00, 0x12, 0x00, 0x24, 0x00, 0x37, 0x00, 0x49, 0x00, 0x5B, 0x00, + 0x88, 0x00, 0xB6, 0x00, 0x10, 0x01, 0xC6, 0x01, 0x7C, 0x02, 0x8C, 0x03, + 0xFF, 0x04, 0x73, 0x06, 0x83, 0x07, 0x39, 0x08, 0xEF, 0x08, 0x49, 0x09, + 0x77, 0x09, 0xA4, 0x09, 0xB6, 0x09, 0xC8, 0x09, 0xDB, 0x09, 0xEE, 0x09, + 0xFF, 0x09, 0x00, 0x00, 0x12, 0x00, 0x24, 0x00, 0x36, 0x00, 0x48, 0x00, + 0x5A, 0x00, 0x87, 0x00, 0xB4, 0x00, 0x0E, 0x01, 0x68, 0x01, 0xC2, 0x01, + 0x1C, 0x02, 0xCF, 0x02, 0x83, 0x03, 0xDD, 0x03, 0x37, 0x04, 0x91, 0x04, + 0xEB, 0x04, 0x18, 0x05, 0x45, 0x05, 0x57, 0x05, 0x69, 0x05, 0x7B, 0x05, + 0x8D, 0x05, 0x9F, 0x05, 0x00, 0x00, 0x0F, 0x00, 0x1E, 0x00, 0x2E, 0x00, + 0x3D, 0x00, 0x4C, 0x00, 0x73, 0x00, 0x99, 0x00, 0xE6, 0x00, 0xA5, 0x01, + 0x65, 0x02, 0x84, 0x03, 0xFF, 0x04, 0x7A, 0x06, 0x8F, 0x07, 0x48, 0x08, + 0x02, 0x09, 0x55, 0x09, 0x80, 0x09, 0xAA, 0x09, 0xBB, 0x09, 0xCB, 0x09, + 0xDA, 0x09, 0xEF, 0x09, 0xFF, 0x09, 0x00, 0x00, 0x10, 0x00, 0x20, 0x00, + 0x30, 0x00, 0x40, 0x00, 0x50, 0x00, 0x78, 0x00, 0xA0, 0x00, 0xF0, 0x00, + 0x4F, 0x01, 0xAF, 0x01, 0x0F, 0x02, 0xCF, 0x02, 0x8F, 0x03, 0xEF, 0x03, + 0x4F, 0x04, 0xAF, 0x04, 0xFF, 0x04, 0x27, 0x05, 0x4F, 0x05, 0x5F, 0x05, + 0x6F, 0x05, 0x7F, 0x05, 0x8F, 0x05, 0x9F, 0x05, 0x00, 0x00, 0x04, 0x00, + 0x14, 0x00, 0x1E, 0x00, 0x28, 0x00, 0x39, 0x00, 0x64, 0x00, 0x91, 0x00, + 0xEF, 0x00, 0xAB, 0x01, 0x6C, 0x02, 0x89, 0x03, 0xFF, 0x04, 0x76, 0x06, + 0x93, 0x07, 0x54, 0x08, 0x10, 0x09, 0x6E, 0x09, 0x9B, 0x09, 0xC6, 0x09, + 0xD7, 0x09, 0xE1, 0x09, 0xEB, 0x09, 0xFB, 0x09, 0xFF, 0x09, 0x00, 0x00, + 0x04, 0x00, 0x14, 0x00, 0x1E, 0x00, 0x2A, 0x00, 0x37, 0x00, 0x66, 0x00, + 0x8A, 0x00, 0xE9, 0x00, 0x4A, 0x01, 0xB1, 0x01, 0x10, 0x02, 0xCF, 0x02, + 0x8F, 0x03, 0xEE, 0x03, 0x55, 0x04, 0xB6, 0x04, 0x15, 0x05, 0x39, 0x05, + 0x68, 0x05, 0x75, 0x05, 0x81, 0x05, 0x8B, 0x05, 0x9B, 0x05, 0x9F, 0x05, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xA0, 0x0F, 0xF0, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x08, 0x01, 0x00, 0x00, 0x64, 0x00, 0x64, 0x00, 0x64, 0x00, + 0x64, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x01, 0x02, 0x50, 0x00, + 0xD0, 0x07, 0xD0, 0x07, 0x00, 0x03, 0x21, 0x10, 0xFE, 0x00, 0x00, 0x00, + 0x00, 0x3E, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x08, 0xC8, 0x00, 0x64, 0x00, + 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x01, + 0x02, 0x03, 0x00, 0x05, 0x00, 0x05, 0x00, 0x05, 0x00, 0x05, 0xA0, 0x00, + 0x08, 0x0A, 0x08, 0x22, 0x00, 0x00, 0x00, 0x00, 0x45, 0x02, 0x30, 0x00, + 0x40, 0x00, 0x40, 0x00, 0x3D, 0x00, 0x38, 0x00, 0x82, 0x1A, 0x00, 0x00, + 0x0F, 0x00, 0x00, 0x0C, 0x00, 0x0C, 0x00, 0x0C, 0x00, 0x0C, 0x00, 0x00, + 0x00, 0x04, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE8, 0x03, + 0x02, 0x00, 0xAC, 0x0D, 0xF0, 0x0B, 0x01, 0x20, 0x02, 0x00, 0xAC, 0x0D, + 0xF0, 0x0B, 0x01, 0x32, 0x03, 0x00, 0xB8, 0x0B, 0xB8, 0x0B, 0x00, 0x0A, + 0x03, 0x00, 0xB8, 0x0B, 0xB8, 0x0B, 0x00, 0x0A, 0x00, 0x00, 0xE8, 0x03, + 0x0B, 0x00, 0x00, 0x03, 0x00, 0x05, 0x40, 0x06, 0x40, 0x06, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x0A, 0x0F, 0x00, 0xB8, 0x0B, 0xB8, 0x0B, 0xB8, 0x0B, + 0xB8, 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x0F, 0x00, 0xB8, 0x0B, + 0xB8, 0x0B, 0xB8, 0x0B, 0xB8, 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, + 0x00, 0x1D, 0x00, 0x01, 0x30, 0x0F, 0x20, 0x40, 0x00, 0x01, 0x13, 0x0D, + 0x08, 0x40, 0x00, 0x00, 0x13, 0x0D, 0x00, 0x81, 0x10, 0x10, 0x92, 0x92, + 0x01, 0x60, 0x0F, 0x15, 0x90, 0x00, 0x97, 0x92, 0x0C, 0x0C, 0x00, 0x00, + 0x19, 0x01, 0x30, 0x00, 0x30, 0x00, 0x30, 0x00, 0x01, 0x34, 0x2C, 0x0A, + 0x03, 0x63, 0x16, 0x53, 0x16, 0x00, 0x0A, 0x01, 0x12, 0x16, 0x81, 0x02, + 0x60, 0x00, 0x08, 0x01, 0xA0, 0x00, 0x35, 0x35, 0x06, 0x00, 0x16, 0x18, + 0x16, 0x18, 0x81, 0x02, 0x60, 0x00, 0x08, 0x01, 0xA0, 0x00, 0x35, 0x35, + 0x06, 0x00, 0x96, 0xD8, 0x96, 0xD8, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x23, 0x01, 0x00, 0x00, 0x00, 0x16, 0x09, 0x20, 0x15, 0x01, 0x00, 0x00, + 0x01, 0x39, 0x01, 0x16, 0x09, 0x20, 0x15, 0x00, 0x24, 0x01, 0xA2, 0xD9, + 0x6B, 0x9D, 0x82, 0x06, }; - #endif diff --git a/drivers/input/touchscreen/st/fts_gui.c b/drivers/input/touchscreen/st/fts_gui.c index f695137ada09..ba072183a264 100644 --- a/drivers/input/touchscreen/st/fts_gui.c +++ b/drivers/input/touchscreen/st/fts_gui.c @@ -1,3 +1,24 @@ +/* + * FTS Capacitive touch screen controller (FingerTipS) + * + * Copyright (C) 2016-2018, STMicroelectronics Limited. + * Authors: AMG(Analog Mems Group) + * + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + */ + + #include #include #include @@ -12,17 +33,13 @@ #include #include #include +//#include +#include #include #include #include #include "fts.h" -#include "fts_lib/ftsCompensation.h" #include "fts_lib/ftsIO.h" -#include "fts_lib/ftsError.h" -#include "fts_lib/ftsFrame.h" -#include "fts_lib/ftsTest.h" -#include "fts_lib/ftsTime.h" -#include "fts_lib/ftsTool.h" #ifdef SCRIPTLESS @@ -31,116 +48,131 @@ unsigned char pAddress_i2c[CMD_RESULT_STR_LEN] = {0}; int byte_count_read; char Out_buff[TSP_BUF_SIZE]; + /*I2C CMd functions: functions to interface with GUI without script */ ssize_t fts_i2c_wr_show(struct device *dev, struct device_attribute *attr, - char *buf) + char *buf) { struct i2c_client *client = to_i2c_client(dev); struct fts_ts_info *info = i2c_get_clientdata(client); int i; char buff[16]; + memset(Out_buff, 0x00, ARRAY_SIZE(Out_buff)); if (byte_count_read == 0) { snprintf(Out_buff, sizeof(Out_buff), "{FAILED}"); - return snprintf(buf, TSP_BUF_SIZE, "{%s}\n", Out_buff); + return snprintf(buf, TSP_BUF_SIZE, "%s\n", Out_buff); } #ifdef SCRIPTLESS_DEBUG - printk("%s:DATA READ {", __func__); + pr_err("%s:DATA READ {", __func__); for (i = 0; i < byte_count_read; i++) { - printk(" %02X", (unsigned int)info->cmd_wr_result[i]); - if (i < (byte_count_read-1)) { - printk(" "); - } + pr_err(" %02X", (unsigned int)info->cmd_wr_result[i]); + if (i < (byte_count_read - 1)) + pr_err(" "); } - printk("}\n"); + pr_err("}\n"); #endif snprintf(buff, sizeof(buff), "{"); - strlcat(Out_buff, buff, ARRAY_SIZE(Out_buff)); - for (i = 0; i < (byte_count_read+2); i++) { - if ((i == 0)) { - char temp_byte_count_read = (byte_count_read >> 8) & 0xFF; - snprintf(buff, sizeof(buff), "%02X", temp_byte_count_read); + strlcat(Out_buff, buff, ARRAY_SIZE(Out_buff)); + for (i = 0; i < (byte_count_read + 2); i++) { + char temp_byte_count_read; + + if (i == 0) { + temp_byte_count_read = (byte_count_read >> 8) & 0xFF; + + snprintf(buff, sizeof(buff), "%02X", + temp_byte_count_read); } else if (i == 1) { - char temp_byte_count_read = (byte_count_read) & 0xFF; - snprintf(buff, sizeof(buff), "%02X", temp_byte_count_read); + temp_byte_count_read = (byte_count_read) & 0xFF; + + snprintf(buff, sizeof(buff), "%02X", + temp_byte_count_read); } else { - snprintf(buff, sizeof(buff), "%02X", info->cmd_wr_result[i-2]); + snprintf(buff, sizeof(buff), "%02X", + info->cmd_wr_result[i-2]); } - /* snprintf(buff, sizeof(buff), "%02X", info->cmd_wr_result[i]); */ + //snprintf(buff, sizeof(buff), "%02X", info->cmd_wr_result[i]); strlcat(Out_buff, buff, ARRAY_SIZE(Out_buff)); - if (i < (byte_count_read+1)) { + if (i < (byte_count_read + 1)) { snprintf(buff, sizeof(buff), " "); - strlcat(Out_buff, buff, ARRAY_SIZE(Out_buff)); + strlcat(Out_buff, buff, ARRAY_SIZE(Out_buff)); } } snprintf(buff, sizeof(buff), "}"); - strlcat(Out_buff, buff, ARRAY_SIZE(Out_buff)); + strlcat(Out_buff, buff, ARRAY_SIZE(Out_buff)); return snprintf(buf, TSP_BUF_SIZE, "%s\n", Out_buff); } ssize_t fts_i2c_wr_store(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) + const char *buf, size_t count) { int ret; struct i2c_client *client = to_i2c_client(dev); struct fts_ts_info *info = i2c_get_clientdata(client); - unsigned char pAddress[8] = {0}; - unsigned int byte_count = 0 ; - int i ; + unsigned char pAddress[9] = {0}; + unsigned int byte_count = 0; + int i; + unsigned int data[9] = {0}; - unsigned int data[8] = {0}; memset(data, 0x00, ARRAY_SIZE(data)); memset(info->cmd_wr_result, 0x00, ARRAY_SIZE(info->cmd_wr_result)); - sscanf(buf, "%x %x %x %x %x %x %x %x ", (data+7), (data), (data+1), - (data+2), (data+3), (data+4), (data+5), (data+6)); - - byte_count = data[7]; + ret = sscanf(buf, "%x %x %x %x %x %x %x %x %x ", + (data + 8), (data), (data + 1), (data + 2), (data + 3), + (data + 4), (data + 5), (data + 6), (data + 7)); + if (ret != 9) + return -EINVAL; + byte_count = data[8]; - /*if (sizeof(buf) != byte_count ) - { - printk("%s : Byte count is wrong\n",__func__); - return count; - }*/ + /** + * if(sizeof(buf) != byte_count ) + * { + * printk("%s : Byte count is wrong\n",__func__); + * return count; + * } + */ #ifdef SCRIPTLESS_DEBUG - printk("\n"); - printk("%s: Input Data 1:", __func__); + pr_err("\n"); + pr_err("%s: Input Data 1:", __func__); - for (i = 0 ; i < 7; i++) { - printk(" %02X", data[i]); + for (i = 0 ; i < byte_count; i++) { + pr_err(" %02X", data[i]); pAddress[i] = (unsigned char)data[i]; } - printk("\n"); + pr_err("\n"); #else - for (i = 0 ; i < 7; i++) { + for (i = 0 ; i < byte_count; i++) pAddress[i] = (unsigned char)data[i]; - } #endif - byte_count_read = data[byte_count-1]; + byte_count_read = (((unsigned int)data[byte_count - 2]) << 8) + | data[byte_count - 1]; ret = fts_writeCmd(pAddress, 3); msleep(20); - ret = fts_readCmd(&pAddress[3], (byte_count-4), info->cmd_wr_result, - byte_count_read); + ret = fts_readCmd(&pAddress[3], (byte_count - 5), + info->cmd_wr_result, byte_count_read); #ifdef SCRIPTLESS_DEBUG - printk("%s:DATA READ\n{", __func__); - for (i = 0; i < (2+byte_count_read); i++) { - if ((i == 0)) { - char temp_byte_count_read = (byte_count_read >> 8) & 0xFF; - printk("%02X", (unsigned int)temp_byte_count_read); + pr_err("%s:DATA READ\n{", __func__); + for (i = 0; i < (2 + byte_count_read); i++) { + char temp_byte_count_read; + + if (i == 0) { + temp_byte_count_read = (byte_count_read >> 8) & 0xFF; + pr_err("%02X", (unsigned int)temp_byte_count_read); } else if (i == 1) { - char temp_byte_count_read = (byte_count_read) & 0xFF; - printk("%02X", (unsigned int)temp_byte_count_read); + temp_byte_count_read = (byte_count_read) & 0xFF; + pr_err("%02X", (unsigned int)temp_byte_count_read); } else { - printk("%02X", (unsigned int)info->cmd_read_result[i-2]); - } - if (i < (byte_count_read+1)) { - printk(" "); + pr_err("%02X", + (unsigned int)info->cmd_read_result[i - 2]); } + if (i < (byte_count_read + 1)) + pr_err(" "); + } - printk("}\n"); + pr_err("}\n"); #endif if (ret) dev_err(dev, "Unable to read register\n"); @@ -148,165 +180,188 @@ ssize_t fts_i2c_wr_store(struct device *dev, struct device_attribute *attr, } ssize_t fts_i2c_read_show(struct device *dev, struct device_attribute *attr, - char *buf) + char *buf) { struct i2c_client *client = to_i2c_client(dev); struct fts_ts_info *info = i2c_get_clientdata(client); - int i ; + int i; char buff[16]; memset(Out_buff, 0x00, ARRAY_SIZE(Out_buff)); if (byte_count_read == 0) { snprintf(Out_buff, sizeof(Out_buff), "{FAILED}"); - return snprintf(buf, TSP_BUF_SIZE, "{%s}\n", Out_buff); + return snprintf(buf, TSP_BUF_SIZE, "%s\n", Out_buff); } #ifdef SCRIPTLESS_DEBUG - printk("%s:DATA READ {", __func__); + pr_err("%s:DATA READ {", __func__); for (i = 0; i < byte_count_read; i++) { - printk("%02X", (unsigned int)info->cmd_read_result[i]); - if (i < (byte_count_read-1)) { - printk(" "); - } + pr_err("%02X", (unsigned int)info->cmd_read_result[i]); + if (i < (byte_count_read - 1)) + pr_err(" "); } - printk("}\n"); + pr_err("}\n"); #endif snprintf(buff, sizeof(buff), "{"); - strlcat(Out_buff, buff, ARRAY_SIZE(Out_buff)); - for (i = 0; i < (byte_count_read+2); i++) { - if ((i == 0)) { - char temp_byte_count_read = (byte_count_read >> 8) & 0xFF; - snprintf(buff, sizeof(buff), "%02X", temp_byte_count_read); - } else if (i == 1) { - char temp_byte_count_read = (byte_count_read) & 0xFF; - snprintf(buff, sizeof(buff), "%02X", temp_byte_count_read); + strlcat(Out_buff, buff, ARRAY_SIZE(Out_buff)); + for (i = 0; i < (byte_count_read + 2); i++) { + char temp_byte_count_read; + if (i == 0) { + temp_byte_count_read = (byte_count_read >> 8) & 0xFF; + snprintf(buff, sizeof(buff), "%02X", + temp_byte_count_read); + } else if (i == 1) { + temp_byte_count_read = (byte_count_read) & 0xFF; + snprintf(buff, sizeof(buff), "%02X", + temp_byte_count_read); } else { - snprintf(buff, sizeof(buff), "%02X", info->cmd_read_result[i-2]); + snprintf(buff, sizeof(buff), "%02X", + info->cmd_read_result[i - 2]); } - strlcat(Out_buff, buff, ARRAY_SIZE(Out_buff)); - if (i < (byte_count_read+1)) { + strlcat(Out_buff, buff, ARRAY_SIZE(Out_buff)); + if (i < (byte_count_read + 1)) { snprintf(buff, sizeof(buff), " "); - strlcat(Out_buff, buff, ARRAY_SIZE(Out_buff)); + strlcat(Out_buff, buff, ARRAY_SIZE(Out_buff)); } } snprintf(buff, sizeof(buff), "}"); - strlcat(Out_buff, buff, ARRAY_SIZE(Out_buff)); + strlcat(Out_buff, buff, ARRAY_SIZE(Out_buff)); return snprintf(buf, TSP_BUF_SIZE, "%s\n", Out_buff); } ssize_t fts_i2c_read_store(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) + const char *buf, size_t count) { int ret; struct i2c_client *client = to_i2c_client(dev); struct fts_ts_info *info = i2c_get_clientdata(client); - unsigned char pAddress[8] = {0}; + unsigned char pAddress[9] = {0}; unsigned int byte_count = 0; - int i ; - unsigned int data[8] = {0}; + int i; + unsigned int data[9] = {0}; byte_count_read = 0; memset(data, 0x00, ARRAY_SIZE(data)); memset(info->cmd_read_result, 0x00, ARRAY_SIZE(info->cmd_read_result)); - sscanf(buf, "%x %x %x %x %x %x %x %x ", (data+7), (data), (data+1), (data+2), (data+3), (data+4), (data+5), (data+6)); - byte_count = data[7]; + ret = sscanf(buf, "%x %x %x %x %x %x %x %x %x ", + (data + 8), (data), (data + 1), (data + 2), (data + 3), + (data + 4), (data + 5), (data + 6), (data + 7)); + if (ret != 9) + return -EINVAL; + byte_count = data[8]; - if (byte_count > 7) { + if (byte_count > 8) { #ifdef SCRIPTLESS_DEBUG - printk("%s : Byte count is more than 7\n", __func__); + pr_err("%s:Byte count is more than 8\n", __func__); #endif return count; } - /*if (sizeof(buf) != byte_count ) - { - printk("%s : Byte count is wrong\n",__func__); - return count; - }*/ + /*if(sizeof(buf) != byte_count )*/ + /*{*/ + /* printk("%s : Byte count is wrong\n",__func__);*/ + /* return count;*/ + /*}*/ #ifdef SCRIPTLESS_DEBUG - printk("\n"); - printk("%s: Input Data 1:", __func__); + pr_err("\n"); + pr_err("%s: Input Data 1:", __func__); for (i = 0 ; i < byte_count; i++) { - printk(" %02X", data[i]); + pr_err("%02X", data[i]); pAddress[i] = (unsigned char)data[i]; } - printk("\n"); + pr_err("\n"); #else - for (i = 0 ; i < byte_count; i++) { + for (i = 0 ; i < byte_count; i++) pAddress[i] = (unsigned char)data[i]; - } #endif - byte_count_read = data[byte_count-1]; - ret = fts_readCmd(pAddress, (byte_count-1), info->cmd_read_result, byte_count_read); + byte_count_read = (((unsigned int)data[byte_count - 2]) << 8) + | data[byte_count - 1]; + ret = fts_readCmd(pAddress, (byte_count - 2), info->cmd_read_result, + byte_count_read); #ifdef SCRIPTLESS_DEBUG - printk("%s:DATA READ\n{", __func__); - for (i = 0; i < (byte_count_read+2); i++) { - if ((i == 0)) { - char temp_byte_count_read = (byte_count_read >> 8) & 0xFF; - printk("%02X", (unsigned int)temp_byte_count_read); + pr_err("%s:DATA READ\n{", __func__); + for (i = 0; i < (byte_count_read + 2); i++) { + char temp_byte_count_read; + + if (i == 0) { + temp_byte_count_read = (byte_count_read >> 8) & 0xFF; + + pr_err("%02X", (unsigned int)temp_byte_count_read); } else if (i == 1) { - char temp_byte_count_read = (byte_count_read) & 0xFF; - printk("%02X", (unsigned int)temp_byte_count_read); + temp_byte_count_read = (byte_count_read) & 0xFF; + + pr_err("%02X", (unsigned int)temp_byte_count_read); } else { - printk("%02X", (unsigned int)info->cmd_read_result[i-2]); - } - if (i < (byte_count_read+1)) { - printk(" "); + pr_err("%02X", + (unsigned int)info->cmd_read_result[i - 2]); } + if (i < (byte_count_read + 1)) + pr_err(" "); } - printk("}\n"); + pr_err("}\n"); #endif if (ret) dev_err(dev, "Unable to read register\n"); return count; } -ssize_t fts_i2c_write_show(struct device *dev, struct device_attribute *attr, - char *buf) + +ssize_t fts_i2c_write_show(struct device *dev, + struct device_attribute *attr, char *buf) { struct i2c_client *client = to_i2c_client(dev); struct fts_ts_info *info = i2c_get_clientdata(client); + return snprintf(buf, TSP_BUF_SIZE, "%s", info->cmd_write_result); } ssize_t fts_i2c_write_store(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) + const char *buf, size_t count) { int ret; struct i2c_client *client = to_i2c_client(dev); struct fts_ts_info *info = i2c_get_clientdata(client); unsigned int byte_count = 0; - int i ; + int i; + memset(data, 0x00, ARRAY_SIZE(data)); memset(pAddress_i2c, 0x00, ARRAY_SIZE(pAddress_i2c)); - memset(info->cmd_write_result, 0x00, ARRAY_SIZE(info->cmd_write_result)); - sscanf(buf, "%x %x", data, (data + 1)); + memset(info->cmd_write_result, 0x00, + ARRAY_SIZE(info->cmd_write_result)); + ret = sscanf(buf, "%x %x", data, (data + 1)); + if (ret != 2) + return -EINVAL; byte_count = data[0] << 8 | data[1]; if (byte_count <= ARRAY_SIZE(pAddress_i2c)) { for (i = 0; i < (byte_count); i++) { - sscanf(&buf[3*(i+2)], "%x ", (data+i)); - } } else { + ret = sscanf(&buf[3 * (i + 2)], "%x ", (data + i)); + if (ret != 1) + return -EINVAL; + } + } else { #ifdef SCRIPTLESS_DEBUG - printk("%s : message size is more than allowed limit of 512 bytes\n", __func__); + pr_err("%s:message size is > allowed limit of 512 bytes\n", + __func__); #endif - snprintf(info->cmd_write_result, sizeof(info->cmd_write_result), "{Write NOT OK}\n"); + snprintf(info->cmd_write_result, sizeof(info->cmd_write_result), + "{Write NOT OK}\n"); } #ifdef SCRIPTLESS_DEBUG - printk("\n"); - printk("%s: Byte_count= %02d | Count = %02d | size of buf:%02d\n", __func__, byte_count, (int)count, (int)sizeof(buf)); - printk("%s: Input Data 1:", __func__); + pr_err("\n"); + pr_err("%s:Byte_count = %02d|Count = %02d |size of buf:%02d\n", + __func__, byte_count, (int)count, (int)sizeof(buf)); + pr_err("%s: Input Data 1:", __func__); for (i = 0 ; i < byte_count; i++) { - printk("%02X", data[i]); + pr_err(" %02X", data[i]); pAddress_i2c[i] = (unsigned char)data[i]; } - printk("\n"); + pr_err("\n"); #else - for (i = 0; i < byte_count; i++) { + for (i = 0 ; i < byte_count; i++) pAddress_i2c[i] = (unsigned char)data[i]; - } #endif if ((pAddress_i2c[0] == 0xb3) && (pAddress_i2c[3] == 0xb1)) { ret = fts_writeCmd(pAddress_i2c, 3); @@ -317,30 +372,31 @@ ssize_t fts_i2c_write_store(struct device *dev, struct device_attribute *attr, } #ifdef SCRIPTLESS_DEBUG - printk("%s:DATA :", __func__); - for (i = 0; i < byte_count; i++) { - printk(" %02X", (unsigned int)pAddress_i2c[i]); - } - printk(" byte_count: %02X\n", byte_count); + pr_err("%s:DATA :", __func__); + for (i = 0; i < byte_count; i++) + pr_err(" %02X", (unsigned int)pAddress_i2c[i]); + pr_err(" byte_count: %02X\n", byte_count); #endif if (ret < 0) { dev_err(dev, "{Write NOT OK}\n"); - snprintf(info->cmd_write_result, sizeof(info->cmd_write_result), "{Write NOT OK}\n"); + snprintf(info->cmd_write_result, sizeof(info->cmd_write_result), + "{Write NOT OK}\n"); } else { - snprintf(info->cmd_write_result, sizeof(info->cmd_write_result), "{Write OK}\n"); + snprintf(info->cmd_write_result, sizeof(info->cmd_write_result), + "{Write OK}\n"); #ifdef SCRIPTLESS_DEBUG - printk("%s : {Write OK}\n", __func__); + pr_err("%s : {Write OK}\n", __func__); #endif } return count; } -static DEVICE_ATTR(iread, (S_IWUSR|S_IWGRP), NULL, fts_i2c_read_store); -static DEVICE_ATTR(iread_result, (S_IRUSR|S_IRGRP), fts_i2c_read_show, NULL); -static DEVICE_ATTR(iwr, (S_IWUSR|S_IWGRP), NULL, fts_i2c_wr_store); -static DEVICE_ATTR(iwr_result, (S_IRUSR|S_IRGRP), fts_i2c_wr_show, NULL); -static DEVICE_ATTR(iwrite, (S_IWUSR|S_IWGRP), NULL, fts_i2c_write_store); -static DEVICE_ATTR(iwrite_result, (S_IRUSR|S_IRGRP), fts_i2c_write_show, NULL); +static DEVICE_ATTR(iread, 0664, NULL, fts_i2c_read_store); +static DEVICE_ATTR(iread_result, 0664, fts_i2c_read_show, NULL); +static DEVICE_ATTR(iwr, 0664, NULL, fts_i2c_wr_store); +static DEVICE_ATTR(iwr_result, 0664, fts_i2c_wr_show, NULL); +static DEVICE_ATTR(iwrite, 0664, NULL, fts_i2c_write_store); +static DEVICE_ATTR(iwrite_result, 0664, fts_i2c_write_show, NULL); static struct attribute *i2c_cmd_attributes[] = { &dev_attr_iread.attr, @@ -356,4 +412,4 @@ struct attribute_group i2c_cmd_attr_group = { .attrs = i2c_cmd_attributes, }; -#endif + #endif diff --git a/drivers/input/touchscreen/st/fts_lib/Makefile b/drivers/input/touchscreen/st/fts_lib/Makefile index 24eca48fc3cd..f8bc76c19a91 100644 --- a/drivers/input/touchscreen/st/fts_lib/Makefile +++ b/drivers/input/touchscreen/st/fts_lib/Makefile @@ -2,6 +2,7 @@ # Makefile for the FTS touchscreen driver. # -obj-$(CONFIG_TOUCHSCREEN_ST_I2C) += ftsCompensation.o \ +obj-$(CONFIG_TOUCHSCREEN_ST) += ftsCompensation.o \ ftsCrossCompile.o ftsError.o ftsFrame.o ftsIO.o ftsTest.o \ ftsTime.o ftsTool.o ftsFlash.o ftsGesture.o + diff --git a/drivers/input/touchscreen/st/fts_lib/ftsCompensation.c b/drivers/input/touchscreen/st/fts_lib/ftsCompensation.c index 2ca0067f34b0..d394ca64be40 100644 --- a/drivers/input/touchscreen/st/fts_lib/ftsCompensation.c +++ b/drivers/input/touchscreen/st/fts_lib/ftsCompensation.c @@ -1,24 +1,36 @@ /* -************************************************************************** -** STMicroelectronics ** -************************************************************************** -** marco.cali@st.com ** -************************************************************************** -* * -* FTS functions for getting Initialization Data * -* * -************************************************************************** -************************************************************************** -*/ - -#include "ftsCrossCompile.h" -#include "ftsCompensation.h" -#include "ftsError.h" -#include "ftsFrame.h" -#include "ftsHardware.h" -#include "ftsIO.h" -#include "ftsSoftware.h" -#include "ftsTool.h" + * FTS Capacitive touch screen controller (FingerTipS) + * + * Copyright (C) 2016-2018, STMicroelectronics Limited. + * Authors: AMG(Analog Mems Group) + * + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + */ + +/** + * + ************************************************************************** + ** STMicroelectronics ** + ************************************************************************** + ** marco.cali@st.com ** + ************************************************************************** + * * + * FTS functions for getting Initialization Data * + * * + ************************************************************************** + ************************************************************************** + */ #include #include @@ -44,23 +56,33 @@ #include #include #include -/* #include */ +//#include + +#include "ftsCrossCompile.h" +#include "ftsCompensation.h" +#include "ftsError.h" +#include "ftsFrame.h" +#include "ftsHardware.h" +#include "ftsIO.h" +#include "ftsSoftware.h" +#include "ftsTool.h" -static char tag[8] = "[ FTS ]\0"; -chipInfo ftsInfo; +static char tag[8] = "[ FTS ]\0"; +struct chipInfo ftsInfo; int requestCompensationData(u16 type) { int retry = 0; int ret; + char *temp = NULL; u16 answer; int event_to_search[3]; u8 readEvent[FIFO_EVENT_SIZE]; - u8 cmd[3] = { FTS_CMD_REQU_COMP_DATA, 0x00, 0x00 }; - /* B8 is the command for asking compensation data */ + u8 cmd[3] = { FTS_CMD_REQU_COMP_DATA, 0x00, 0x00}; + /* B8 is the command for asking compensation data*/ u16ToU8(type, &cmd[1]); event_to_search[0] = (int)EVENTID_COMP_DATA_READ; @@ -68,16 +90,23 @@ int requestCompensationData(u16 type) event_to_search[2] = cmd[2]; while (retry < COMP_DATA_READ_RETRY) { - logError(0, "%s %s", tag, printHex("Command = ", cmd, 3)); + temp = printHex("Command = ", cmd, 3); + if (temp != NULL) + logError(0, "%s %s", tag, temp); + kfree(temp); ret = fts_writeFwCmd(cmd, 3); - /* send the request to the chip to load in memory the Compensation Data */ + /*send the request to the chip to load*/ + /*in memory the Compensation Data*/ if (ret < OK) { - logError(1, "%s requestCompensationData: ERROR %02X\n", tag, ERROR_I2C_W); + logError(1, "%s %s:ERROR %02X\n", + tag, __func__, ERROR_I2C_W); return ERROR_I2C_W; } - ret = pollForEvent(event_to_search, 3, readEvent, TIMEOUT_REQU_COMP_DATA); + ret = pollForEvent(event_to_search, 3, readEvent, + TIMEOUT_REQU_COMP_DATA); if (ret < OK) { - logError(0, "%s Event did not Found at %d attemp! \n", tag, retry+1); + logError(0, "%s Event did not Found at %d attemp!\n", + tag, retry + 1); retry += 1; } else { retry = 0; @@ -86,45 +115,55 @@ int requestCompensationData(u16 type) } if (retry == COMP_DATA_READ_RETRY) { - logError(1, "%s requestCompensationData: ERROR %02X\n", tag, ERROR_TIMEOUT); - return ERROR_TIMEOUT; + logError(1, "%s %s: ERROR %02X\n", + tag, __func__, ERROR_TIMEOUT); + return ERROR_TIMEOUT; } u8ToU16_le(&readEvent[1], &answer); if (answer == type) return OK; - logError(1, "%s The event found has a different type of Compensation data ERROR %02X \n", tag, ERROR_DIFF_COMP_TYPE); + + logError(1, "%sThe event found has a different type of ", tag); + logError(1, "Compensation data %02X\n", ERROR_DIFF_COMP_TYPE); return ERROR_DIFF_COMP_TYPE; } -int readCompensationDataHeader(u16 type, DataHeader *header, u16 *address) +int readCompensationDataHeader(u16 type, struct DataHeader *header, + u16 *address) { - u16 offset = ADDR_FRAMEBUFFER_DATA; u16 answer; u8 data[COMP_DATA_HEADER]; - if (readCmdU16(FTS_CMD_FRAMEBUFFER_R, offset, data, COMP_DATA_HEADER, DUMMY_FRAMEBUFFER) < 0) { - logError(1, "%s readCompensationDataHeader: ERROR %02X \n", tag, ERROR_I2C_R); + if (readCmdU16(FTS_CMD_FRAMEBUFFER_R, offset, data, COMP_DATA_HEADER, + DUMMY_FRAMEBUFFER) < 0) { + logError(1, "%s %s: ERROR %02X\n", tag, __func__, ERROR_I2C_R); return ERROR_I2C_R; } - logError(0, "%s Read Data Header done! \n", tag); + logError(0, "%s Read Data Header done!\n", tag); if (data[0] != HEADER_SIGNATURE) { - logError(1, "%s readCompensationDataHeader: ERROR %02X The Header Signature was wrong! %02X != %02X \n", tag, ERROR_WRONG_COMP_SIGN, data[0], HEADER_SIGNATURE); + logError(1, "%s %s:%02X The Header Signature was wrong!", + tag, __func__, ERROR_WRONG_COMP_SIGN); + logError(1, "%02X != %02X\n", data[0], HEADER_SIGNATURE); + return ERROR_WRONG_COMP_SIGN; } + u8ToU16_le(&data[1], &answer); if (answer != type) { - logError(1, "%s readCompensationDataHeader: ERROR %02X\n", tag, ERROR_DIFF_COMP_TYPE); + logError(1, "%s %s:ERROR %02X\n", + tag, __func__, ERROR_DIFF_COMP_TYPE); + return ERROR_DIFF_COMP_TYPE; } - logError(0, "%s Type of Compensation data OK! \n", tag); + logError(0, "%s Type of Compensation data OK!\n", tag); header->type = type; header->force_node = (int)data[4]; @@ -136,110 +175,123 @@ int readCompensationDataHeader(u16 type, DataHeader *header, u16 *address) } -int readMutualSenseGlobalData(u16 *address, MutualSenseData *global) +int readMutualSenseGlobalData(u16 *address, struct MutualSenseData *global) { u8 data[COMP_DATA_GLOBAL]; - logError(0, "%s Address for Global data= %02X \n", tag, *address); + logError(0, "%s Address for Global data= %02X\n", tag, *address); + + if (readCmdU16(FTS_CMD_FRAMEBUFFER_R, *address, data, + COMP_DATA_GLOBAL, DUMMY_FRAMEBUFFER) < 0) { + logError(1, "%s %s: ERROR %02X\n", tag, __func__, ERROR_I2C_R); - if (readCmdU16(FTS_CMD_FRAMEBUFFER_R, *address, data, COMP_DATA_GLOBAL, DUMMY_FRAMEBUFFER) < 0) { - logError(1, "%s readMutualSenseGlobalData: ERROR %02X\n", tag, ERROR_I2C_R); return ERROR_I2C_R; } - logError(0, "%s Global data Read !\n", tag); + logError(0, "%s Global data Read!\n", tag); global->tuning_ver = data[0]; global->cx1 = data[1]; - logError(0, "%s tuning_ver = %d CX1 = %d \n", tag, global->tuning_ver, global->cx1); + logError(0, "%s tuning_ver = %d CX1 = %d\n", + tag, global->tuning_ver, global->cx1); *address += COMP_DATA_GLOBAL; return OK; - } -int readMutualSenseNodeData(u16 address, MutualSenseData *node) -{ + +int readMutualSenseNodeData(u16 address, struct MutualSenseData *node) +{ int size = node->header.force_node*node->header.sense_node; - logError(0, "%s Address for Node data = %02X \n", tag, address); + logError(0, "%s Address for Node data = %02X\n", tag, address); - node->node_data = (u8 *)kmalloc(size*(sizeof(u8)), GFP_KERNEL); + node->node_data = (u8 *)kmalloc_array(size, (sizeof(u8)), GFP_KERNEL); if (node->node_data == NULL) { - logError(1, "%s readMutualSenseNodeData: ERROR %02X", tag, ERROR_ALLOC); + logError(1, "%s %s: ERROR %02X", tag, __func__, ERROR_ALLOC); return ERROR_ALLOC; } - logError(0, "%s Node Data to read %d bytes \n", tag, size); + logError(0, "%s Node Data to read %d bytes\n", tag, size); - if (readCmdU16(FTS_CMD_FRAMEBUFFER_R, address, node->node_data, size, DUMMY_FRAMEBUFFER) < 0) { - logError(1, "%s readMutualSenseNodeData: ERROR %02X \n", tag, ERROR_I2C_R); + if (readCmdU16(FTS_CMD_FRAMEBUFFER_R, address, node->node_data, + size, DUMMY_FRAMEBUFFER) < 0) { + logError(1, "%s %s:ERROR %02X\n", tag, __func__, ERROR_I2C_R); + kfree(node->node_data); return ERROR_I2C_R; } node->node_data_size = size; - logError(0, "%s Read node data ok! \n", tag); + logError(0, "%s Read node data ok!\n", tag); return size; - } -int readMutualSenseCompensationData(u16 type, MutualSenseData *data) -{ +int readMutualSenseCompensationData(u16 type, struct MutualSenseData *data) +{ int ret; u16 address; - if (!(type == MS_TOUCH_ACTIVE || type == MS_TOUCH_LOW_POWER || - type == MS_TOUCH_ULTRA_LOW_POWER || type == MS_KEY)) { - logError(1, "%s readMutualSenseCompensationData: Choose a MS type of compensation data ERROR %02X\n", tag, ERROR_OP_NOT_ALLOW); + data->node_data = NULL; + + if (!(type == MS_TOUCH_ACTIVE || type == MS_TOUCH_LOW_POWER + || type == MS_TOUCH_ULTRA_LOW_POWER || type == MS_KEY)) { + logError(1, "%s %s: Choose a MS type of compensation data ", + tag, __func__); + logError(1, "ERROR %02X\n", ERROR_OP_NOT_ALLOW); return ERROR_OP_NOT_ALLOW; } ret = requestCompensationData(type); if (ret < 0) { - logError(1, "%s readMutualSenseCompensationData: ERROR %02X\n", tag, ERROR_REQU_COMP_DATA); + logError(1, "%s %s: ERROR %02X\n", + tag, __func__, ERROR_REQU_COMP_DATA); return (ret|ERROR_REQU_COMP_DATA); } ret = readCompensationDataHeader(type, &(data->header), &address); if (ret < 0) { - logError(1, "%s readMutualSenseCompensationData: ERROR %02X\n", tag, ERROR_COMP_DATA_HEADER); - return (ret|ERROR_COMP_DATA_HEADER); + logError(1, "%s %s: ERROR %02X\n", + tag, __func__, ERROR_COMP_DATA_HEADER); + return (ret | ERROR_COMP_DATA_HEADER); } ret = readMutualSenseGlobalData(&address, data); if (ret < 0) { - logError(1, "%s readMutualSenseCompensationData: ERROR %02X \n", tag, ERROR_COMP_DATA_GLOBAL); + logError(1, "%s %s: ERROR %02X\n", + tag, __func__, ERROR_COMP_DATA_GLOBAL); return (ret|ERROR_COMP_DATA_GLOBAL); } ret = readMutualSenseNodeData(address, data); if (ret < 0) { - logError(1, "%s readMutualSenseCompensationData: ERROR %02X\n", tag, ERROR_COMP_DATA_NODE); - return (ret|ERROR_COMP_DATA_NODE); + logError(1, "%s %s: ERROR %02X\n", + tag, __func__, ERROR_COMP_DATA_NODE); + return (ret | ERROR_COMP_DATA_NODE); } return OK; - } -int readSelfSenseGlobalData(u16 *address, SelfSenseData *global) -{ +int readSelfSenseGlobalData(u16 *address, struct SelfSenseData *global) +{ u8 data[COMP_DATA_GLOBAL]; - logError(0, "%s Address for Global data= %02X \n", tag, *address); + logError(0, "%s Address for Global data= %02X\n", tag, *address); - if (readCmdU16(FTS_CMD_FRAMEBUFFER_R, *address, data, COMP_DATA_GLOBAL, DUMMY_FRAMEBUFFER) < 0) { - logError(1, "%s readSelfSenseGlobalData: ERROR %02X \n", tag, ERROR_I2C_R); + if (readCmdU16(FTS_CMD_FRAMEBUFFER_R, *address, data, + COMP_DATA_GLOBAL, DUMMY_FRAMEBUFFER) < 0) { + logError(1, "%s %s: ERROR %02X\n", + tag, __func__, ERROR_I2C_R); return ERROR_I2C_R; } - logError(0, "%s Global data Read !\n", tag); + logError(0, "%s Global data Read!\n", tag); global->tuning_ver = data[0]; global->f_ix1 = data[1]; @@ -249,97 +301,141 @@ int readSelfSenseGlobalData(u16 *address, SelfSenseData *global) global->f_max_n = data[5]; global->s_max_n = data[6]; - logError(0, "%s tuning_ver = %d f_ix1 = %d s_ix1 = %d f_cx1 = %d s_cx1 = %d \n", tag, global->tuning_ver, global->f_ix1, global->s_ix1, global->f_cx1, global->s_cx1); - logError(0, "%s max_n = %d s_max_n = %d \n", tag, global->f_max_n, global->s_max_n); + logError(0, + "%stuning_ver = %df_ix1 = %ds_ix1 = %df_cx1 = %d s_cx1 = %d\n", + tag, global->tuning_ver, global->f_ix1, + global->s_ix1, global->f_cx1, global->s_cx1); + logError(0, "%s max_n = %d s_max_n = %d\n", + tag, global->f_max_n, global->s_max_n); *address += COMP_DATA_GLOBAL; - return OK; - } -int readSelfSenseNodeData(u16 address, SelfSenseData *node) +int readSelfSenseNodeData(u16 address, struct SelfSenseData *node) { - - int size = node->header.force_node*2+node->header.sense_node*2; + int size = node->header.force_node * 2 + node->header.sense_node * 2; u8 data[size]; - node->ix2_fm = (u8 *)kmalloc(node->header.force_node*(sizeof(u8)), GFP_KERNEL); - node->cx2_fm = (u8 *)kmalloc(node->header.force_node*(sizeof(u8)), GFP_KERNEL); - node->ix2_sn = (u8 *)kmalloc(node->header.sense_node*(sizeof(u8)), GFP_KERNEL); - node->cx2_sn = (u8 *)kmalloc(node->header.sense_node*(sizeof(u8)), GFP_KERNEL); + node->ix2_fm = (u8 *)kmalloc_array(node->header.force_node, + sizeof(u8), GFP_KERNEL); + if (node->ix2_fm == NULL) { + logError(1, "%s %s: ERROR %02X", tag, __func__, ERROR_ALLOC); + return ERROR_ALLOC; + } - if (node->ix2_fm == NULL || node->cx2_fm == NULL || node->ix2_sn == NULL - || node->cx2_sn == NULL) { - logError(1, "%s readSelfSenseNodeData: ERROR %02X", tag, ERROR_ALLOC); + node->cx2_fm = (u8 *)kmalloc_array(node->header.force_node, + sizeof(u8), GFP_KERNEL); + if (node->cx2_fm == NULL) { + logError(1, "%s %s: ERROR %02X", tag, __func__, ERROR_ALLOC); + kfree(node->ix2_fm); + return ERROR_ALLOC; + } + node->ix2_sn = (u8 *)kmalloc_array(node->header.sense_node, + sizeof(u8), GFP_KERNEL); + if (node->ix2_sn == NULL) { + logError(1, "%s %s: ERROR %02X", tag, __func__, ERROR_ALLOC); + kfree(node->ix2_fm); + kfree(node->cx2_fm); + return ERROR_ALLOC; + } + node->cx2_sn = (u8 *)kmalloc_array(node->header.sense_node, + sizeof(u8), GFP_KERNEL); + if (node->cx2_sn == NULL) { + logError(1, "%s %s: ERROR %02X", tag, __func__, ERROR_ALLOC); + kfree(node->ix2_fm); + kfree(node->cx2_fm); + kfree(node->ix2_sn); return ERROR_ALLOC; } - logError(0, "%s Address for Node data = %02X \n", tag, address); + logError(0, "%s Address for Node data = %02X\n", tag, address); - logError(0, "%s Node Data to read %d bytes \n", tag, size); + logError(0, "%s Node Data to read %d bytes\n", tag, size); - if (readCmdU16(FTS_CMD_FRAMEBUFFER_R, address, data, size, DUMMY_FRAMEBUFFER) < 0) { - logError(1, "%s readSelfSenseNodeData: ERROR %02X\n", tag, ERROR_I2C_R); + if (readCmdU16(FTS_CMD_FRAMEBUFFER_R, address, data, size, + DUMMY_FRAMEBUFFER) < 0) { + logError(1, "%s %s: ERROR %02X\n", tag, __func__, ERROR_I2C_R); + kfree(node->ix2_fm); + kfree(node->cx2_fm); + kfree(node->ix2_sn); + kfree(node->cx2_sn); return ERROR_I2C_R; } - logError(0, "%s Read node data ok! \n", tag); + logError(0, "%s Read node data ok!\n", tag); memcpy(node->ix2_fm, data, node->header.force_node); - memcpy(node->ix2_sn, &data[node->header.force_node], node->header.sense_node); - memcpy(node->cx2_fm, &data[node->header.force_node + node->header.sense_node], node->header.force_node); - memcpy(node->cx2_sn, &data[node->header.force_node*2 + node->header.sense_node], node->header.sense_node); + memcpy(node->ix2_sn, &data[node->header.force_node], + node->header.sense_node); + memcpy(node->cx2_fm, + &data[node->header.force_node + node->header.sense_node], + node->header.force_node); + memcpy(node->cx2_sn, + &data[node->header.force_node * 2 + node->header.sense_node], + node->header.sense_node); return OK; - } -int readSelfSenseCompensationData(u16 type, SelfSenseData *data) +int readSelfSenseCompensationData(u16 type, struct SelfSenseData *data) { int ret; u16 address; - if (!(type == SS_TOUCH || type == SS_KEY || type == SS_HOVER || type == SS_PROXIMITY)) { - logError(1, "%s readSelfSenseCompensationData: Choose a SS type of compensation data ERROR %02X\n", tag, ERROR_OP_NOT_ALLOW); + data->ix2_fm = NULL; + data->cx2_fm = NULL; + data->ix2_sn = NULL; + data->cx2_sn = NULL; + + if (!(type == SS_TOUCH || type == SS_KEY || type == SS_HOVER + || type == SS_PROXIMITY)) { + logError(1, "%s %s:Choose a SS type of compensation data ", + tag, __func__); + logError(1, "ERROR %02X\n", ERROR_OP_NOT_ALLOW); return ERROR_OP_NOT_ALLOW; } ret = requestCompensationData(type); if (ret < 0) { - logError(1, "%s readSelfSenseCompensationData: ERROR %02X\n", tag, ERROR_REQU_COMP_DATA); - return (ret|ERROR_REQU_COMP_DATA); + logError(1, "%s %s: ERROR %02X\n", + tag, __func__, ERROR_REQU_COMP_DATA); + return (ret | ERROR_REQU_COMP_DATA); } ret = readCompensationDataHeader(type, &(data->header), &address); if (ret < 0) { - logError(1, "%s readSelfSenseCompensationData: ERROR %02X\n", tag, ERROR_COMP_DATA_HEADER); + logError(1, "%s %s: ERROR %02X\n", + tag, __func__, ERROR_COMP_DATA_HEADER); return (ret|ERROR_COMP_DATA_HEADER); } ret = readSelfSenseGlobalData(&address, data); if (ret < 0) { - logError(1, "%s readSelfSenseCompensationData: ERROR %02X\n", tag, ERROR_COMP_DATA_GLOBAL); - return (ret|ERROR_COMP_DATA_GLOBAL); + logError(1, "%s %s: ERROR %02X\n", + tag, __func__, ERROR_COMP_DATA_GLOBAL); + return (ret | ERROR_COMP_DATA_GLOBAL); } ret = readSelfSenseNodeData(address, data); if (ret < 0) { - logError(1, "%s readSelfSenseCompensationData: ERROR %02X\n", tag, ERROR_COMP_DATA_NODE); - return (ret|ERROR_COMP_DATA_NODE); + logError(1, "%s %s: ERROR %02X\n", + tag, __func__, ERROR_COMP_DATA_NODE); + return (ret | ERROR_COMP_DATA_NODE); } return OK; - } -int readGeneralGlobalData(u16 address, GeneralData *global) + +int readGeneralGlobalData(u16 address, struct GeneralData *global) { u8 data[COMP_DATA_GLOBAL]; - if (readCmdU16(FTS_CMD_FRAMEBUFFER_R, address, data, COMP_DATA_GLOBAL, DUMMY_FRAMEBUFFER) < 0) { - logError(1, "%s readGeneralGlobalData: ERROR %02X \n", tag, ERROR_I2C_R); + if (readCmdU16(FTS_CMD_FRAMEBUFFER_R, address, data, COMP_DATA_GLOBAL, + DUMMY_FRAMEBUFFER) < 0) { + logError(1, "%s %s: ERROR %02X\n", tag, __func__, ERROR_I2C_R); return ERROR_I2C_R; } @@ -351,35 +447,39 @@ int readGeneralGlobalData(u16 address, GeneralData *global) global->ftsa_lp_timer_cal1 = data[5]; return OK; - } -int readGeneralCompensationData(u16 type, GeneralData *data) -{ +int readGeneralCompensationData(u16 type, struct GeneralData *data) +{ int ret; u16 address; if (!(type == GENERAL_TUNING)) { - logError(1, "%s readGeneralCompensationData: Choose a GENERAL type of compensation data ERROR %02X\n", tag, ERROR_OP_NOT_ALLOW); + logError(1, "%s %s:Choose a GENERAL type of compensation data ", + tag); + logError(1, "ERROR %02X\n", ERROR_OP_NOT_ALLOW); return ERROR_OP_NOT_ALLOW; } ret = requestCompensationData(type); if (ret < 0) { - logError(1, "%s readGeneralCompensationData: ERROR %02X \n", tag, ERROR_REQU_COMP_DATA); + logError(1, "%s %s: ERROR %02X\n", + tag, __func__, ERROR_REQU_COMP_DATA); return ERROR_REQU_COMP_DATA; } ret = readCompensationDataHeader(type, &(data->header), &address); if (ret < 0) { - logError(1, "%s readGeneralCompensationData: ERROR %02X\n", tag, ERROR_COMP_DATA_HEADER); + logError(1, "%s %s: ERROR %02X\n", + tag, __func__, ERROR_COMP_DATA_HEADER); return ERROR_COMP_DATA_HEADER; } ret = readGeneralGlobalData(address, data); if (ret < 0) { - logError(1, "%s readGeneralCompensationData: ERROR %02X\n", tag, ERROR_COMP_DATA_GLOBAL); + logError(1, "%s %s: ERROR %02X\n", + tag, __func__, ERROR_COMP_DATA_GLOBAL); return ERROR_COMP_DATA_GLOBAL; } @@ -387,10 +487,12 @@ int readGeneralCompensationData(u16 type, GeneralData *data) } + int defaultChipInfo(int i2cError) { int i; - logError(0, "%s Setting default Chip Info... \n", tag); + + logError(0, "%s Setting default Chip Info...\n", tag); ftsInfo.u32_echoEn = 0x00000000; ftsInfo.u8_msScrConfigTuneVer = 0; ftsInfo.u8_ssTchConfigTuneVer = 0; @@ -399,54 +501,57 @@ int defaultChipInfo(int i2cError) if (i2cError == 1) { ftsInfo.u16_fwVer = 0xFFFF; ftsInfo.u16_cfgId = 0xFFFF; - for (i = 0; i < EXTERNAL_RELEASE_INFO_SIZE; i++) { + for (i = 0; i < EXTERNAL_RELEASE_INFO_SIZE; i++) ftsInfo.u8_extReleaseInfo[i] = 0xFF; - } } else { ftsInfo.u16_fwVer = 0x0000; ftsInfo.u16_cfgId = 0x0000; - for (i = 0; i < EXTERNAL_RELEASE_INFO_SIZE; i++) { + for (i = 0; i < EXTERNAL_RELEASE_INFO_SIZE; i++) ftsInfo.u8_extReleaseInfo[i] = 0x00; - } } ftsInfo.u32_mpPassFlag = INIT_FIELD; - logError(0, "%s default Chip Info DONE! \n", tag); + ftsInfo.u16_errOffset = INVALID_ERROR_OFFS; + logError(0, "%s default Chip Info DONE!\n", tag); return OK; - } int readChipInfo(int doRequest) { int ret, i; u16 answer; - u8 data[CHIP_INFO_SIZE+3]; - /* +3 because need to read all the field of the struct plus the signature and 2 address bytes */ + u8 data[CHIP_INFO_SIZE + 3]; + /*+3 because need to read all the field of*/ + /*the struct plus the signature and 2 address bytes*/ int index = 0; - logError(0, "%s Starting Read Chip Info... \n", tag); + logError(0, "%s Starting Read Chip Info...\n", tag); if (doRequest == 1) { ret = requestCompensationData(CHIP_INFO); if (ret < 0) { - logError(1, "%s readChipInfo: ERROR %02X\n", tag, ERROR_REQU_COMP_DATA); + logError(1, "%s %s: ERROR %02X\n", + tag, __func__, ERROR_REQU_COMP_DATA); ret = (ret | ERROR_REQU_COMP_DATA); goto FAIL; } } - logError(0, "%s Byte to read = %d bytes \n", tag, CHIP_INFO_SIZE+3); + logError(0, "%s Byte to read = %d bytes\n", tag, CHIP_INFO_SIZE + 3); - if (readCmdU16(FTS_CMD_FRAMEBUFFER_R, ADDR_FRAMEBUFFER_DATA, data, CHIP_INFO_SIZE+3, DUMMY_FRAMEBUFFER) < 0) { - logError(1, "%s readChipInfo: ERROR %02X\n", tag, ERROR_I2C_R); + if (readCmdU16(FTS_CMD_FRAMEBUFFER_R, ADDR_FRAMEBUFFER_DATA, data, + CHIP_INFO_SIZE + 3, DUMMY_FRAMEBUFFER) < 0) { + logError(1, "%s %s: ERROR %02X\n", tag, __func__, ERROR_I2C_R); ret = ERROR_I2C_R; goto FAIL; } - logError(0, "%s Read data ok! \n", tag); + logError(0, "%s Read data ok!\n", tag); - logError(0, "%s Starting parsing of data... \n", tag); + logError(0, "%s Starting parsing of data...\n", tag); if (data[0] != HEADER_SIGNATURE) { - logError(1, "%s readChipInfo: ERROR %02X The Header Signature was wrong! %02X != %02X \n", tag, ERROR_WRONG_COMP_SIGN, data[0], HEADER_SIGNATURE); + logError(1, "%s %s:ERROR ", tag, __func__); + logError(1, "%02X The Header Signature is wrong!%02X != %02X\n", + ERROR_WRONG_COMP_SIGN, data[0], HEADER_SIGNATURE); ret = ERROR_WRONG_COMP_SIGN; goto FAIL; } @@ -454,7 +559,8 @@ int readChipInfo(int doRequest) u8ToU16_le(&data[1], &answer); if (answer != CHIP_INFO) { - logError(1, "%s readChipInfo: ERROR %02X\n", tag, ERROR_DIFF_COMP_TYPE); + logError(1, "%s %s: ERROR %02X\n", + tag, __func__, ERROR_DIFF_COMP_TYPE); ret = ERROR_DIFF_COMP_TYPE; goto FAIL; } @@ -476,19 +582,21 @@ int readChipInfo(int doRequest) } logError(1, "\n"); - for (i = 0; i < sizeof(ftsInfo.u8_custInfo); i++) { + for (i = 0; i < sizeof(ftsInfo.u8_custInfo); i++) ftsInfo.u8_custInfo[i] = data[index++]; - } u8ToU16(&data[index], &ftsInfo.u16_fwVer); index += 2; - logError(1, "%s FW VERSION = %04X \n", tag, ftsInfo.u16_fwVer); + logError(1, "%s FW VERSION = %04X\n", tag, ftsInfo.u16_fwVer); u8ToU16(&data[index], &ftsInfo.u16_cfgId); index += 2; - logError(1, "%s CONFIG ID = %04X \n", tag, ftsInfo.u16_cfgId); + logError(1, "%s CONFIG ID = %04X\n", tag, ftsInfo.u16_cfgId); - ftsInfo.u32_projId = ((data[index + 3] & 0x000000FF) << 24) + ((data[index + 2] & 0x000000FF) << 16) + ((data[index + 1] & 0x000000FF) << 8) + (data[index] & 0x000000FF); + ftsInfo.u32_projId = ((data[index + 3] & 0x000000FF) << 24) + + ((data[index + 2] & 0x000000FF) << 16) + + ((data[index + 1] & 0x000000FF) << 8) + + (data[index] & 0x000000FF); index += 4; u8ToU16(&data[index], &ftsInfo.u16_scrXRes); @@ -498,86 +606,117 @@ int readChipInfo(int doRequest) index += 2; ftsInfo.u8_scrForceLen = data[index++]; - logError(1, "%s Force Len = %d \n", tag, ftsInfo.u8_scrForceLen); + logError(1, "%s Force Len = %d\n", tag, ftsInfo.u8_scrForceLen); ftsInfo.u8_scrSenseLen = data[index++]; - logError(1, "%s Sense Len = %d \n", tag, ftsInfo.u8_scrSenseLen); + logError(1, "%s Sense Len = %d\n", tag, ftsInfo.u8_scrSenseLen); - for (i = 0; i < 8; i++) { + for (i = 0; i < 8; i++) ftsInfo.u64_scrForceEn[i] = data[index++]; - } - for (i = 0; i < 8; i++) { + for (i = 0; i < 8; i++) ftsInfo.u64_scrSenseEn[i] = data[index++]; - } ftsInfo.u8_msKeyLen = data[index++]; - logError(1, "%s MS Key Len = %d \n", tag, ftsInfo.u8_msKeyLen); + logError(1, "%s MS Key Len = %d\n", tag, ftsInfo.u8_msKeyLen); - for (i = 0; i < 8; i++) { + for (i = 0; i < 8; i++) ftsInfo.u64_msKeyForceEn[i] = data[index++]; - } - for (i = 0; i < 8; i++) { + for (i = 0; i < 8; i++) ftsInfo.u64_msKeySenseEn[i] = data[index++]; - } ftsInfo.u8_ssKeyLen = data[index++]; - logError(1, "%s SS Key Len = %d \n", tag, ftsInfo.u8_ssKeyLen); + logError(1, "%s SS Key Len = %d\n", tag, ftsInfo.u8_ssKeyLen); - for (i = 0; i < 8; i++) { + for (i = 0; i < 8; i++) ftsInfo.u64_ssKeyForceEn[i] = data[index++]; - } - for (i = 0; i < 8; i++) { + for (i = 0; i < 8; i++) ftsInfo.u64_ssKeySenseEn[i] = data[index++]; - } ftsInfo.u8_frcTchXLen = data[index++]; ftsInfo.u8_frcTchYLen = data[index++]; - for (i = 0; i < 8; i++) { + for (i = 0; i < 8; i++) ftsInfo.u64_frcTchForceEn[i] = data[index++]; - } - for (i = 0; i < 8; i++) { + for (i = 0; i < 8; i++) ftsInfo.u64_frcTchSenseEn[i] = data[index++]; - } + ftsInfo.u8_msScrConfigTuneVer = data[index++]; - logError(1, "%s CFG MS TUNING VERSION = %02X \n", tag, ftsInfo.u8_msScrConfigTuneVer); + logError(1, "%s CFG MS TUNING VERSION = %02X\n", + tag, ftsInfo.u8_msScrConfigTuneVer); ftsInfo.u8_msScrLpConfigTuneVer = data[index++]; ftsInfo.u8_msScrHwulpConfigTuneVer = data[index++]; ftsInfo.u8_msKeyConfigTuneVer = data[index++]; ftsInfo.u8_ssTchConfigTuneVer = data[index++]; - logError(1, "%s CFG SS TUNING VERSION = %02X \n", tag, ftsInfo.u8_ssTchConfigTuneVer); + logError(1, "%s CFG SS TUNING VERSION = %02X\n", + tag, ftsInfo.u8_ssTchConfigTuneVer); ftsInfo.u8_ssKeyConfigTuneVer = data[index++]; ftsInfo.u8_ssHvrConfigTuneVer = data[index++]; ftsInfo.u8_frcTchConfigTuneVer = data[index++]; ftsInfo.u8_msScrCxmemTuneVer = data[index++]; - logError(1, "%s CX MS TUNING VERSION = %02X \n", tag, ftsInfo.u8_msScrCxmemTuneVer); + logError(1, "%s CX MS TUNING VERSION = %02X\n", + tag, ftsInfo.u8_msScrCxmemTuneVer); ftsInfo.u8_msScrLpCxmemTuneVer = data[index++]; ftsInfo.u8_msScrHwulpCxmemTuneVer = data[index++]; ftsInfo.u8_msKeyCxmemTuneVer = data[index++]; ftsInfo.u8_ssTchCxmemTuneVer = data[index++]; - logError(1, "%s CX SS TUNING VERSION = %02X \n", tag, ftsInfo.u8_ssTchCxmemTuneVer); + logError(1, "%s CX SS TUNING VERSION = %02X\n", + tag, ftsInfo.u8_ssTchCxmemTuneVer); ftsInfo.u8_ssKeyCxmemTuneVer = data[index++]; ftsInfo.u8_ssHvrCxmemTuneVer = data[index++]; ftsInfo.u8_frcTchCxmemTuneVer = data[index++]; - ftsInfo.u32_mpPassFlag = ((data[index + 3] & 0x000000FF) << 24) + ((data[index + 2] & 0x000000FF) << 16) + ((data[index + 1] & 0x000000FF) << 8) + (data[index] & 0x000000FF); + ftsInfo.u32_mpPassFlag = ((data[index + 3] & 0x000000FF) << 24) + + ((data[index + 2] & 0x000000FF) << 16) + + ((data[index + 1] & 0x000000FF) << 8) + + (data[index] & 0x000000FF); index += 4; - logError(1, "%s MP SIGNATURE = %08X \n", tag, ftsInfo.u32_mpPassFlag); - ftsInfo.u32_featEn = ((data[index + 3] & 0x000000FF) << 24) + ((data[index + 2] & 0x000000FF) << 16) + ((data[index + 1] & 0x000000FF) << 8) + (data[index] & 0x000000FF); + logError(1, "%s MP SIGNATURE = %08X\n", tag, ftsInfo.u32_mpPassFlag); + ftsInfo.u32_featEn = ((data[index + 3] & 0x000000FF) << 24) + + ((data[index + 2] & 0x000000FF) << 16) + + ((data[index + 1] & 0x000000FF) << 8) + + (data[index] & 0x000000FF); index += 4; - ftsInfo.u32_echoEn = ((data[index + 3] & 0x000000FF) << 24) + ((data[index + 2] & 0x000000FF) << 16) + ((data[index + 1] & 0x000000FF) << 8) + (data[index] & 0x000000FF); + ftsInfo.u32_echoEn = ((data[index + 3] & 0x000000FF) << 24) + + ((data[index + 2] & 0x000000FF) << 16) + + ((data[index + 1] & 0x000000FF) << 8) + + (data[index] & 0x000000FF); index += 4; - logError(1, "%s FEATURES = %08X \n", tag, ftsInfo.u32_echoEn); + logError(1, "%s FEATURES = %08X\n", tag, ftsInfo.u32_echoEn); + ftsInfo.u8_sideTchConfigTuneVer = data[index++]; + ftsInfo.u8_sideTchCxmemTuneVer = data[index++]; + ftsInfo.u8_sideTchForceLen = data[index++]; + logError(1, "%s Side Touch Force Len = %d\n", + tag, ftsInfo.u8_sideTchForceLen); + ftsInfo.u8_sideTchSenseLen = data[index++]; + logError(1, "%s Side Touch Sense Len = %d\n", + tag, ftsInfo.u8_sideTchSenseLen); + for (i = 0; i < 8; i++) + ftsInfo.u64_sideTchForceEn[i] = data[index++]; + for (i = 0; i < 8; i++) + ftsInfo.u64_sideTchSenseEn[i] = data[index++]; + ftsInfo.u8_errSign = data[index++]; + logError(1, "%s ERROR SIGNATURE = %02X\n", tag, ftsInfo.u8_errSign); + if (ftsInfo.u8_errSign == ERROR_SIGN_HEAD) { + logError(1, "%s Correct Error Signature found!\n", tag); + u8ToU16(&data[index], &ftsInfo.u16_errOffset); + } else { + logError(1, "%s Error Signature NOT FOUND!\n", tag); + ftsInfo.u16_errOffset = INVALID_ERROR_OFFS; + } + logError(1, "%s ERROR OFFSET = %04X\n", tag, ftsInfo.u16_errOffset); + index += 2; + logError(1, "%s Parsed %d bytes!\n", tag, index); - logError(1, "%s Parsed %d bytes! \n", tag, index); if (index != CHIP_INFO_SIZE + 3) { - logError(1, "%s readChipInfo: index = %d different from %d ERROR %02X\n", tag, index, CHIP_INFO_SIZE+3, ERROR_OP_NOT_ALLOW); + logError(1, "%s %s: index = %d different from %d ERROR %02X\n", + tag, __func__, index, CHIP_INFO_SIZE + 3, + ERROR_OP_NOT_ALLOW); return ERROR_OP_NOT_ALLOW; } @@ -587,5 +726,5 @@ int readChipInfo(int doRequest) FAIL: defaultChipInfo(isI2cError(ret)); return ret; - } + diff --git a/drivers/input/touchscreen/st/fts_lib/ftsCompensation.h b/drivers/input/touchscreen/st/fts_lib/ftsCompensation.h index c4cc5913fc18..983d70e312cf 100644 --- a/drivers/input/touchscreen/st/fts_lib/ftsCompensation.h +++ b/drivers/input/touchscreen/st/fts_lib/ftsCompensation.h @@ -1,63 +1,95 @@ /* + * FTS Capacitive touch screen controller (FingerTipS) + * + * Copyright (C) 2016-2018, STMicroelectronics Limited. + * Authors: AMG(Analog Mems Group) + * + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + */ + +/** + * + ************************************************************************** + ** STMicroelectronics ** + ************************************************************************** + ** marco.cali@st.com ** + ************************************************************************** + * * + * FTS API for Flashing the IC * + * * + ************************************************************************** + ************************************************************************** + * + */ + +#ifndef __FTS_COMPENSATION_H +#define __FTS_COMPENSATION_H -************************************************************************** -** STMicroelectronics ** -************************************************************************** -** marco.cali@st.com ** -************************************************************************** -* * -* FTS functions for getting Initialization Data * -* * -************************************************************************** -************************************************************************** - -*/ #include "ftsCrossCompile.h" #include "ftsSoftware.h" -#define COMP_DATA_READ_RETRY 2 -/* Bytes dimension of Compensation Data Format */ +#define COMP_DATA_READ_RETRY 2 + +//Bytes dimension of Compensation Data Format + +#define COMP_DATA_HEADER 8 +#define COMP_DATA_GLOBAL 8 + -#define COMP_DATA_HEADER 8 -#define COMP_DATA_GLOBAL 8 +#define HEADER_SIGNATURE 0xA5 +#define INVALID_ERROR_OFFS 0xFFFF -#define HEADER_SIGNATURE 0xA5 +//Possible Compensation/Frame Data Type +#define GENERAL_TUNING 0x0100 +#define MS_TOUCH_ACTIVE 0x0200 +#define MS_TOUCH_LOW_POWER 0x0400 +#define MS_TOUCH_ULTRA_LOW_POWER 0x0800 +#define MS_KEY 0x1000 +#define SS_TOUCH 0x2000 +#define SS_KEY 0x4000 +#define SS_HOVER 0x8000 +#define SS_PROXIMITY 0x0001 +#define CHIP_INFO 0xFFFF -/* Possible Compensation/Frame Data Type */ -#define GENERAL_TUNING 0x0100 -#define MS_TOUCH_ACTIVE 0x0200 -#define MS_TOUCH_LOW_POWER 0x0400 -#define MS_TOUCH_ULTRA_LOW_POWER 0x0800 -#define MS_KEY 0x1000 -#define SS_TOUCH 0x2000 -#define SS_KEY 0x4000 -#define SS_HOVER 0x8000 -#define SS_PROXIMITY 0x0001 -#define CHIP_INFO 0xFFFF -#define TIMEOUT_REQU_COMP_DATA 1000 /* ms */ +#define TIMEOUT_REQU_COMP_DATA 1000 //ms -/* CHIP INFO */ -#define CHIP_INFO_SIZE 138/* bytes to read from framebuffer (exclude the signature and the type because already checked during the reading) */ -#define EXTERNAL_RELEASE_INFO_SIZE 8/* bytes */ +//CHIP INFO +#define CHIP_INFO_SIZE 161 +/*bytes to read from framebuffer (exclude the signature and the type*/ +/*because already checked during the reading)*/ +#define EXTERNAL_RELEASE_INFO_SIZE 8 //bytes -typedef struct { +struct DataHeader { int force_node, sense_node; u16 type; -} DataHeader; +}; -typedef struct { - DataHeader header; + +struct MutualSenseData { + struct DataHeader header; u8 tuning_ver; u8 cx1; u8 *node_data; int node_data_size; -} MutualSenseData; +}; + -typedef struct { - DataHeader header; +struct SelfSenseData { + struct DataHeader header; u8 tuning_ver; u8 f_ix1, s_ix1; u8 f_cx1, s_cx1; @@ -67,11 +99,11 @@ typedef struct { u8 *ix2_sn; u8 *cx2_fm; u8 *cx2_sn; +}; -} SelfSenseData; -typedef struct { - DataHeader header; +struct GeneralData { + struct DataHeader header; u8 ftsd_lp_timer_cal0; u8 ftsd_lp_timer_cal1; u8 ftsd_lp_timer_cal2; @@ -79,68 +111,96 @@ typedef struct { u8 ftsd_lp_timer_cal3; u8 ftsa_lp_timer_cal0; u8 ftsa_lp_timer_cal1; - -} GeneralData; - -typedef struct { - u8 u8_loadCnt; /* 03 - Load Counter */ - u8 u8_infoVer; /* 04 - New chip info version */ - u16 u16_ftsdId; /* 05 - FTSD ID */ - u8 u8_ftsdVer; /* 07 - FTSD version */ - u8 u8_ftsaId; /* 08 - FTSA ID */ - u8 u8_ftsaVer; /* 09 - FTSA version */ - u8 u8_tchRptVer; /* 0A - Touch report version (e.g. ST, Samsung etc) */ - u8 u8_extReleaseInfo[EXTERNAL_RELEASE_INFO_SIZE]; /* 0B - External release information */ - u8 u8_custInfo[12]; /* 13 - Customer information */ - u16 u16_fwVer; /* 1F - Firmware version */ - u16 u16_cfgId; /* 21 - Configuration ID */ - u32 u32_projId; /* 23 - Project ID */ - u16 u16_scrXRes; /* 27 - X resolution on main screen */ - u16 u16_scrYRes; /* 29 - Y resolution on main screen */ - u8 u8_scrForceLen; /* 2B - Number of force channel on main screen */ - u8 u8_scrSenseLen; /* 2C - Number of sense channel on main screen */ - u8 u64_scrForceEn[8]; /* 2D - Force channel enabled on main screen */ - u8 u64_scrSenseEn[8]; /* 35 - Sense channel enabled on main screen */ - u8 u8_msKeyLen; /* 3D - Number of MS Key channel */ - u8 u64_msKeyForceEn[8]; /* 3E - MS Key force channel enable */ - u8 u64_msKeySenseEn[8]; /* 46 - MS Key sense channel enable */ - u8 u8_ssKeyLen; /* 4E - Number of SS Key channel */ - u8 u64_ssKeyForceEn[8]; /* 4F - SS Key force channel enable */ - u8 u64_ssKeySenseEn[8]; /* 57 - SS Key sense channel enable */ - u8 u8_frcTchXLen; /* 5F - Number of force touch force channel */ - u8 u8_frcTchYLen; /* 60 - Number of force touch sense channel */ - u8 u64_frcTchForceEn[8]; /* 61 - Force touch force channel enable */ - u8 u64_frcTchSenseEn[8]; /* 69 - Force touch sense channel enable */ - u8 u8_msScrConfigTuneVer; /* 71 - MS screen tuning version in config */ - u8 u8_msScrLpConfigTuneVer; /* 72 - MS screen LP mode tuning version in config */ - u8 u8_msScrHwulpConfigTuneVer; /* 73 - MS screen ultra low power mode tuning version in config */ - u8 u8_msKeyConfigTuneVer; /* 74 - MS Key tuning version in config */ - u8 u8_ssTchConfigTuneVer; /* 75 - SS touch tuning version in config */ - u8 u8_ssKeyConfigTuneVer; /* 76 - SS Key tuning version in config */ - u8 u8_ssHvrConfigTuneVer; /* 77 - SS hover tuning version in config */ - u8 u8_frcTchConfigTuneVer; /* 78 - Force touch tuning version in config */ - u8 u8_msScrCxmemTuneVer; /* 79 - MS screen tuning version in cxmem */ - u8 u8_msScrLpCxmemTuneVer; /* 7A - MS screen LP mode tuning version in cxmem */ - u8 u8_msScrHwulpCxmemTuneVer; /* 7B - MS screen ultra low power mode tuning version in cxmem */ - u8 u8_msKeyCxmemTuneVer; /* 7C - MS Key tuning version in cxmem */ - u8 u8_ssTchCxmemTuneVer; /* 7D - SS touch tuning version in cxmem */ - u8 u8_ssKeyCxmemTuneVer; /* 7E - SS Key tuning version in cxmem */ - u8 u8_ssHvrCxmemTuneVer; /* 7F - SS hover tuning version in cxmem */ - u8 u8_frcTchCxmemTuneVer; /* 80 - Force touch tuning version in cxmem */ - u32 u32_mpPassFlag; /* 81 - Mass production pass flag */ - u32 u32_featEn; /* 85 - Supported features */ - u32 u32_echoEn; /* 89 - enable of particular features: first bit is Echo Enables */ -} chipInfo; +}; + +struct chipInfo { + u8 u8_loadCnt; ///< 03 - Load Counter + u8 u8_infoVer; ///< 04 - New chip info version + u16 u16_ftsdId; ///< 05 - FTSD ID + u8 u8_ftsdVer; ///< 07 - FTSD version + u8 u8_ftsaId; ///< 08 - FTSA ID + u8 u8_ftsaVer; ///< 09 - FTSA version + u8 u8_tchRptVer; ///< 0A - Touch report version (e.g. ST, Samsung etc) + + ///< 0B - External release information + u8 u8_extReleaseInfo[EXTERNAL_RELEASE_INFO_SIZE]; + u8 u8_custInfo[12]; ///< 13 - Customer information + u16 u16_fwVer; ///< 1F - Firmware version + u16 u16_cfgId; ///< 21 - Configuration ID + u32 u32_projId; ///< 23 - Project ID + u16 u16_scrXRes; ///< 27 - X resolution on main screen + u16 u16_scrYRes; ///< 29 - Y resolution on main screen + u8 u8_scrForceLen; ///< 2B - Number of force channel on main screen + u8 u8_scrSenseLen; ///< 2C - Number of sense channel on main screen + u8 u64_scrForceEn[8]; ///< 2D - Force channel enabled on main screen + u8 u64_scrSenseEn[8]; ///< 35 - Sense channel enabled on main screen + u8 u8_msKeyLen; ///< 3D - Number of MS Key channel + u8 u64_msKeyForceEn[8]; ///< 3E - MS Key force channel enable + u8 u64_msKeySenseEn[8]; ///< 46 - MS Key sense channel enable + u8 u8_ssKeyLen; ///< 4E - Number of SS Key channel + u8 u64_ssKeyForceEn[8]; ///< 4F - SS Key force channel enable + u8 u64_ssKeySenseEn[8]; ///< 57 - SS Key sense channel enable + u8 u8_frcTchXLen; ///< 5F - Number of force touch force channel + u8 u8_frcTchYLen; ///< 60 - Number of force touch sense channel + u8 u64_frcTchForceEn[8];///< 61 - Force touch force channel enable + u8 u64_frcTchSenseEn[8];///< 69 - Force touch sense channel enable + u8 u8_msScrConfigTuneVer; ///< 71 - MS screen tuning version in config + + ///< 72 - MS screen LP mode tuning version in config + u8 u8_msScrLpConfigTuneVer; + + ///< 73 - MS screen ultra low power mode tuning version in config + u8 u8_msScrHwulpConfigTuneVer; + u8 u8_msKeyConfigTuneVer; ///< 74 - MS Key tuning version in config + u8 u8_ssTchConfigTuneVer; ///< 75 - SS touch tuning version in config + u8 u8_ssKeyConfigTuneVer; ///< 76 - SS Key tuning version in config + u8 u8_ssHvrConfigTuneVer; ///< 77 - SS hover tuning version in config + + ///< 78 - Force touch tuning version in config + u8 u8_frcTchConfigTuneVer; + u8 u8_msScrCxmemTuneVer; ///< 79 - MS screen tuning version in cxmem + + ///< 7A - MS screen LP mode tuning version in cxmem + u8 u8_msScrLpCxmemTuneVer; + + ///< 7B - MS screen ultra low power mode tuning version in cxmem + u8 u8_msScrHwulpCxmemTuneVer; + u8 u8_msKeyCxmemTuneVer; ///< 7C - MS Key tuning version in cxmem + u8 u8_ssTchCxmemTuneVer; ///< 7D - SS touch tuning version in cxmem + u8 u8_ssKeyCxmemTuneVer; ///< 7E - SS Key tuning version in cxmem + u8 u8_ssHvrCxmemTuneVer; ///< 7F - SS hover tuning version in cxmem + + ///< 80 - Force touch tuning version in cxmem + u8 u8_frcTchCxmemTuneVer; + u32 u32_mpPassFlag; ///< 81 - Mass production pass flag + u32 u32_featEn; ///< 85 - Supported features + + ///< 89 - enable of particular features: first bit is Echo Enables + u32 u32_echoEn; + + ///< 8D - Side Touch tuning version in config + u8 u8_sideTchConfigTuneVer; + u8 u8_sideTchCxmemTuneVer; ///< 8E - Side Touch tuning version in cxmem + u8 u8_sideTchForceLen; ///< 8F - Number of force channel on side touch + u8 u8_sideTchSenseLen; ///< 90 - Number of sense channel on side touch + u8 u64_sideTchForceEn[8];///< 91 - Side touch force channel enable + u8 u64_sideTchSenseEn[8];///< 99 - Side touch sense channel enable + u8 u8_errSign; ///< A1 - Signature for error field + u16 u16_errOffset; ///< A2 - Error Offset +}; int requestCompensationData(u16 type); -int readCompensationDataHeader(u16 type, DataHeader *header, u16 *address); -int readMutualSenseGlobalData(u16 *address, MutualSenseData *global); -int readMutualSenseNodeData(u16 address, MutualSenseData *node); -int readMutualSenseCompensationData(u16 type, MutualSenseData *data); -int readSelfSenseGlobalData(u16 *address, SelfSenseData *global); -int readSelfSenseNodeData(u16 address, SelfSenseData *node); -int readSelfSenseCompensationData(u16 type, SelfSenseData *data); -int readGeneralGlobalData(u16 address, GeneralData *global); -int readGeneralCompensationData(u16 type, GeneralData *data); +int readCompensationDataHeader(u16 type, struct DataHeader *header, + u16 *address); +int readMutualSenseGlobalData(u16 *address, struct MutualSenseData *global); +int readMutualSenseNodeData(u16 address, struct MutualSenseData *node); +int readMutualSenseCompensationData(u16 type, struct MutualSenseData *data); +int readSelfSenseGlobalData(u16 *address, struct SelfSenseData *global); +int readSelfSenseNodeData(u16 address, struct SelfSenseData *node); +int readSelfSenseCompensationData(u16 type, struct SelfSenseData *data); +int readGeneralGlobalData(u16 address, struct GeneralData *global); +int readGeneralCompensationData(u16 type, struct GeneralData *data); int defaultChipInfo(int i2cError); int readChipInfo(int doRequest); + +#endif diff --git a/drivers/input/touchscreen/st/fts_lib/ftsCrossCompile.c b/drivers/input/touchscreen/st/fts_lib/ftsCrossCompile.c index 502dace75e4f..6d87148c81b7 100644 --- a/drivers/input/touchscreen/st/fts_lib/ftsCrossCompile.c +++ b/drivers/input/touchscreen/st/fts_lib/ftsCrossCompile.c @@ -1,5 +1,37 @@ -#include "ftsCrossCompile.h" -#include "ftsError.h" +/* + * FTS Capacitive touch screen controller (FingerTipS) + * + * Copyright (C) 2016-2018, STMicroelectronics Limited. + * Authors: AMG(Analog Mems Group) + * + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + */ + +/** + * + ************************************************************************** + ** STMicroelectronics ** + ************************************************************************** + ** marco.cali@st.com ** + ************************************************************************** + * * + * FTS Cross Compile * + * * + ************************************************************************** + ************************************************************************** + * + */ #include #include @@ -23,18 +55,19 @@ #include #include #include -/* #include */ +//#include #include #include #include #include #include -/* static char tag[8]="[ FTS ]\0"; */ +#include "ftsCrossCompile.h" +#include "ftsError.h" + void *stmalloc(size_t size) { return kmalloc(size, GFP_KERNEL); - } void stfree(void *ptr) diff --git a/drivers/input/touchscreen/st/fts_lib/ftsCrossCompile.h b/drivers/input/touchscreen/st/fts_lib/ftsCrossCompile.h index 8b287dd342f8..90420fdc0e69 100644 --- a/drivers/input/touchscreen/st/fts_lib/ftsCrossCompile.h +++ b/drivers/input/touchscreen/st/fts_lib/ftsCrossCompile.h @@ -1,5 +1,43 @@ -/* #define NDK */ -/* #define DEBUG */ +/* + * FTS Capacitive touch screen controller (FingerTipS) + * + * Copyright (C) 2016-2018, STMicroelectronics Limited. + * Authors: AMG(Analog Mems Group) + * + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + */ + +/** + * + ************************************************************************** + ** STMicroelectronics ** + ************************************************************************** + ** marco.cali@st.com ** + ************************************************************************** + * * + * FTS cross compile * + * * + ************************************************************************** + ************************************************************************** + * + */ + +#ifndef __FTS_CROSS_COMPILE_H +#define __FTS_CROSS_COMPILE_H + +//#define NDK +#define DEBUG #include #include @@ -23,7 +61,7 @@ #include #include #include -/* #include */ +//#include #include #include #include @@ -32,3 +70,5 @@ void *stmalloc(size_t size); void stfree(void *ptr); + +#endif diff --git a/drivers/input/touchscreen/st/fts_lib/ftsError.c b/drivers/input/touchscreen/st/fts_lib/ftsError.c index 844e5019fec6..bb2f2808c45b 100644 --- a/drivers/input/touchscreen/st/fts_lib/ftsError.c +++ b/drivers/input/touchscreen/st/fts_lib/ftsError.c @@ -1,15 +1,37 @@ /* -*************************************************************************** -* STMicroelectronics -************************************************************************** -* marco.cali@st.com -************************************************************************** -* -* FTS error/info kernel log reporting -* -************************************************************************** -************************************************************************** -*/ + * FTS Capacitive touch screen controller (FingerTipS) + * + * Copyright (C) 2016-2018, STMicroelectronics Limited. + * Authors: AMG(Analog Mems Group) + * + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + */ + +/** + * + ************************************************************************** + ** STMicroelectronics ** + ************************************************************************** + ** marco.cali@st.com ** + ************************************************************************** + * * + * FTS error/info kernel log reporting * + * * + ************************************************************************** + ************************************************************************** + */ + #include #include @@ -25,6 +47,8 @@ #include #include #include +//#include +#include #include #include @@ -35,15 +59,21 @@ #include "ftsError.h" #include "ftsIO.h" #include "ftsTool.h" +#include "ftsCompensation.h" + +static char tag[8] = "[ FTS ]\0"; + void logError(int force, const char *msg, ...) { + if (force == 1 #ifdef DEBUG || 1 #endif - ) { + ) { va_list args; + va_start(args, msg); vprintk(msg, args); va_end(args); @@ -52,12 +82,55 @@ void logError(int force, const char *msg, ...) int isI2cError(int error) { - if (((error & 0x000000FF) >= (ERROR_I2C_R & 0x000000FF)) && ((error & 0x000000FF) <= (ERROR_I2C_O & 0x000000FF))) + if (((error & 0x000000FF) >= (ERROR_I2C_R & 0x000000FF)) + && ((error & 0x000000FF) <= (ERROR_I2C_O & 0x000000FF))) return 1; else return 0; } +int dumpErrorInfo(void) +{ + int ret, i; + u8 data[ERROR_INFO_SIZE] = {0}; + u32 sign = 0; + + logError(0, "%s %s: Starting dump of error info...\n", tag, __func__); + if (ftsInfo.u16_errOffset == INVALID_ERROR_OFFS) { + logError(1, "%s %s: Invalid error offset ERROR %02X\n", + tag, __func__, ERROR_OP_NOT_ALLOW); + return ERROR_OP_NOT_ALLOW; + } + + ret = readCmdU16(FTS_CMD_FRAMEBUFFER_R, ftsInfo.u16_errOffset, + data, ERROR_INFO_SIZE, DUMMY_FRAMEBUFFER); + if (ret < OK) { + logError(1, "%s %s: reading data ERROR %02X\n", + tag, __func__, ret); + return ret; + } + logError(1, "%s %s: Error Info =\n", tag, __func__); + u8ToU32(data, &sign); + if (sign != ERROR_SIGNATURE) + logError(1, "%s %s:Wrong Signature! Data may be invalid!\n", + tag, __func__); + else + logError(1, "%s %s: Error Signature OK! Data are valid!\n", + tag, __func__); + + for (i = 0; i < ERROR_INFO_SIZE; i++) { + if (i % 4 == 0) + logError(1, KERN_ERR "\n%s %s: %d) ", + tag, __func__, i / 4); + logError(1, "%02X ", data[i]); + } + logError(1, "\n"); + + logError(0, "%s %s: dump of error info FINISHED!\n", tag, __func__); + return OK; + +} + int errorHandler(u8 *event, int size) { int res = OK; @@ -66,40 +139,124 @@ int errorHandler(u8 *event, int size) if (getClient() != NULL) info = i2c_get_clientdata(getClient()); - if (info != NULL && event != NULL && size > 1 && event[0] == EVENTID_ERROR_EVENT) { - logError(1, "%s errorHandler: Starting handling...\n", tag); - switch (event[1]) - /* TODO: write an error log for undefinied command subtype 0xBA*/ - { - case EVENT_TYPE_ESD_ERROR: /* esd */ + if (info == NULL || event == NULL || size <= 1 || event[0] != + EVENTID_ERROR_EVENT) { + logError(1, "%s %s: event Null or not correct size! ", + tag, __func__, ERROR_OP_NOT_ALLOW); + logError(1, "ERROR %08X\n", ERROR_OP_NOT_ALLOW); + return ERROR_OP_NOT_ALLOW; + } + + logError(1, "%s %s: Starting handling...\n", tag, __func__); + //TODO: write an error log for undefinied command subtype 0xBA + switch (event[1]) { + case EVENT_TYPE_ESD_ERROR: //esd res = fts_chip_powercycle(info); if (res < OK) { - logError(1, "%s errorHandler: Error performing powercycle ERROR %08X\n", tag, res); + logError(1, "%s %s: ", tag, res); + logError(1, "Error performing powercycle ERROR %08X\n"); } res = fts_system_reset(); - if (res < OK) { - logError(1, "%s errorHandler: Cannot reset the device ERROR %08X\n", tag, res); - } - res = (ERROR_HANDLER_STOP_PROC|res); + if (res < OK) + logError(1, "%s %s:Cannot reset device ERROR%08X\n", + tag, __func__, res); + res = (ERROR_HANDLER_STOP_PROC | res); break; - case EVENT_TYPE_WATCHDOG_ERROR: /* watchdog */ + case EVENT_TYPE_WATCHDOG_ERROR: //watchdog + dumpErrorInfo(); res = fts_system_reset(); - if (res < OK) { - logError(1, "%s errorHandler: Cannot reset the device ERROR %08X\n", tag, res); - } - res = (ERROR_HANDLER_STOP_PROC|res); + if (res < OK) + logError(1, "%s %s:Cannot reset device:ERROR%08X\n", + tag, __func__, res); + res = (ERROR_HANDLER_STOP_PROC | res); + break; + case EVENT_TYPE_CHECKSUM_ERROR: //CRC ERRORS + switch (event[2]) { + case CRC_CONFIG_SIGNATURE: + logError(1, "%s %s: Config Signature ERROR!\n", + tag, __func__); + break; + case CRC_CONFIG: + logError(1, "%s %s:Config CRC ERROR!\n", tag, __func__); + break; + case CRC_CX_MEMORY: + logError(1, "%s %s: CX CRC ERROR!\n", tag, __func__); + break; + } break; + case EVENT_TYPE_LOCKDOWN_ERROR: + //res = (ERROR_HANDLER_STOP_PROC|res); + //stop lockdown code routines in order to retry + switch (event[2]) { + case 0x01: + logError(1, "%s %s:Lockdown code alredy ", + tag, __func__); + logError(1, "written into the IC!\n"); + break; + case 0x02: + logError(1, "%s %s:Lockdown CRC ", tag, __func__); + logError(1, "check fail during a WRITE!\n"); + break; + case 0x03: + logError(1, + "%s %s:Lockdown WRITE command format wrong!\n", + tag, __func__); + break; + case 0x04: + pr_err("Lockdown Memory Corrupted!"); + logError(1, "%s %s:Please contact ST for support!\n", + tag, __func__); + break; + case 0x11: + logError(1, + "%s %s:NO Lockdown code to READ into the IC!\n", + tag, __func__); + break; + case 0x12: + logError(1, + "%s %s:Lockdown code data corrupted\n", + tag, __func__); + break; + case 0x13: + logError(1, + "%s %s:Lockdown READ command format wrong!\n", + tag, __func__); + break; + case 0x21: + pr_err("Exceeded maximum number of "); + logError(1, + "%s %s:Lockdown code REWRITE into IC!\n", + tag, __func__); + break; + case 0x22: + logError(1, "%s %s:Lockdown CRC check", tag, __func__); + logError(1, " fail during a REWRITE!\n"); + break; + case 0x23: + logError(1, "%s %s:", tag, __func__); + logError(1, "Lockdown REWRITE command format wrong!\n"); + break; + case 0x24: + pr_err("Lockdown Memory Corrupted!"); + logError(1, "%s %s:Please contact ST for support!\n", + tag, __func__); + break; default: - logError(1, "%s errorHandler: No Action taken! \n", tag); + logError(1, "%s %s:No valid error type for LOCKDOWN!\n", + tag, __func__); + } break; - } - logError(1, "%s errorHandler: handling Finished! res = %08X\n", tag, res); - return res; + default: + logError(1, + "%s %s: No Action taken!\n", tag, __func__); + break; } - logError(1, "%s errorHandler: event Null or not correct size! ERROR %08X \n", tag, ERROR_OP_NOT_ALLOW); - return ERROR_OP_NOT_ALLOW; + logError(1, "%s %s: handling Finished! res = %08X\n", + tag, __func__, res); + return res; } + diff --git a/drivers/input/touchscreen/st/fts_lib/ftsError.h b/drivers/input/touchscreen/st/fts_lib/ftsError.h index fc8fa5003158..16f45a7e343c 100644 --- a/drivers/input/touchscreen/st/fts_lib/ftsError.h +++ b/drivers/input/touchscreen/st/fts_lib/ftsError.h @@ -1,75 +1,180 @@ /* -************************************************************************** -** STMicroelectronics -************************************************************************** -** marco.cali@st.com -************************************************************************** -* -* FTS error/info kernel log reporting -* -************************************************************************** -************************************************************************** -*/ - - -/*FIRST LEVEL ERROR CODE*/ -#define OK ((int)0x00000000) /*No ERROR*/ -#define ERROR_ALLOC ((int)0x80000001) /*allocation of memory failed*/ -#define ERROR_I2C_R ((int)0x80000002) /*i2c read failed*/ -#define ERROR_I2C_W ((int)0x80000003) /*i2c write failed*/ -#define ERROR_I2C_WR ((int)0x80000004) /*i2c write/read failed*/ -#define ERROR_I2C_O ((int)0x80000005) /*error during opening a i2c device*/ -#define ERROR_OP_NOT_ALLOW ((int)0x80000006) /*operation not allowed*/ -#define ERROR_TIMEOUT ((int)0x80000007) /*timeout expired! exceed the max number of retries or the max waiting time*/ -#define ERROR_FILE_NOT_FOUND ((int)0x80000008) /*the file that i want to open is not found*/ -#define ERROR_FILE_PARSE ((int)0x80000009) /*error during parsing the file*/ -#define ERROR_FILE_READ ((int)0x8000000A) /*error during reading the file*/ -#define ERROR_LABEL_NOT_FOUND ((int)0x8000000B) /*label not found*/ -#define ERROR_FW_NO_UPDATE ((int)0x8000000C) /*fw in the chip newer than the one in the memmh*/ -#define ERROR_FLASH_UNKNOWN ((int)0x8000000D) /*flash status busy or unknown*/ - -/*SECOND LEVEL ERROR CODE*/ -#define ERROR_DISABLE_INTER ((int)0x80000200) /*unable to disable the interrupt*/ -#define ERROR_ENABLE_INTER ((int)0x80000300) /*unable to activate the interrup*/ -#define ERROR_READ_B2 ((int)0x80000400) /*B2 command failed*/ -#define ERROR_GET_OFFSET ((int)0x80000500) /*unable to read an offset from memory*/ -#define ERROR_GET_FRAME_DATA ((int)0x80000600) /*unable to retrieve the data of a required frame*/ -#define ERROR_DIFF_COMP_TYPE ((int)0x80000700) /*FW answers with an event that has a different address respect the request done*/ -#define ERROR_WRONG_COMP_SIGN ((int)0x80000800) /*the signature of the compensation data is not A5*/ -#define ERROR_SENSE_ON_FAIL ((int)0x80000900) /*the command Sense On failed*/ -#define ERROR_SENSE_OFF_FAIL ((int)0x80000A00) /*the command Sense Off failed*/ -#define ERROR_SYSTEM_RESET_FAIL ((int)0x80000B00) /*the command SYSTEM RESET failed*/ -#define ERROR_FLASH_NOT_READY ((int)0x80000C00) /*flash status not ready within a timeout*/ -#define ERROR_FW_VER_READ ((int)0x80000D00) /*unable to retrieve fw_vers or the config_id*/ -#define ERROR_GESTURE_ENABLE_FAIL ((int)0x80000E00) /*unable to enable/disable the gesture*/ -#define ERROR_GESTURE_START_ADD ((int)0x80000F00) /*unable to start to add custom gesture*/ -#define ERROR_GESTURE_FINISH_ADD ((int)0x80001000) /*unable to finish to add custom gesture*/ -#define ERROR_GESTURE_DATA_ADD ((int)0x80001100) /*unable to add custom gesture data*/ -#define ERROR_GESTURE_REMOVE ((int)0x80001200) /*unable to remove custom gesture data*/ -#define ERROR_FEATURE_ENABLE_DISABLE ((int)0x80001300) /*unable to enable/disable a feature mode in the IC*/ -/*THIRD LEVEL ERROR CODE*/ -#define ERROR_CH_LEN ((int)0x80010000) /*unable to retrieve the force and/or sense length*/ -#define ERROR_REQU_COMP_DATA ((int)0x80020000) /*compensation data request failed*/ -#define ERROR_COMP_DATA_HEADER ((int)0x80030000) /*unable to retrieve the compensation data header*/ -#define ERROR_COMP_DATA_GLOBAL ((int)0x80040000) /*unable to retrieve the global compensation data*/ -#define ERROR_COMP_DATA_NODE ((int)0x80050000) /*unable to retrieve the compensation data for each node*/ -#define ERROR_TEST_CHECK_FAIL ((int)0x80060000) /*check of production limits or of fw answers failed*/ -#define ERROR_MEMH_READ ((int)0x80070000) /*memh reading failed*/ -#define ERROR_FLASH_BURN_FAILED ((int)0x80080000) /*flash burn failed*/ -#define ERROR_MS_TUNING ((int)0x80090000) /*ms tuning failed*/ -#define ERROR_SS_TUNING ((int)0x800A0000) /*ss tuning failed*/ -#define ERROR_LP_TIMER_TUNING ((int)0x800B0000) /*lp timer calibration failed*/ -#define ERROR_SAVE_CX_TUNING ((int)0x800C0000) /*save cx data to flash failed*/ -#define ERROR_HANDLER_STOP_PROC ((int)0x800D0000) /*stop the poll of the FIFO if particular errors are found*/ -#define ERROR_CHECK_ECHO_FAIL ((int)0x800E0000) /*unable to retrieve echo event*/ - -/*FOURTH LEVEL ERROR CODE*/ -#define ERROR_PROD_TEST_DATA ((int)0x81000000) /*production data test failed*/ -#define ERROR_FLASH_PROCEDURE ((int)0x82000000) /*complete flash procedure failed*/ -#define ERROR_PROD_TEST_ITO ((int)0x83000000) /*production ito test failed*/ -#define ERROR_PROD_TEST_INITIALIZATION ((int)0x84000000) /*production initialization test failed*/ -#define ERROR_GET_INIT_STATUS ((int)0x85000000) /*mismatch of the MS or SS tuning_version*/ + * FTS Capacitive touch screen controller (FingerTipS) + * + * Copyright (C) 2016-2018, STMicroelectronics Limited. + * Authors: AMG(Analog Mems Group) + * + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + */ + +/** + * + ************************************************************************** + ** STMicroelectronics ** + ************************************************************************** + ** marco.cali@st.com ** + ************************************************************************** + * * + * FTS error/info kernel log reporting * + * * + ************************************************************************** + ************************************************************************** + */ + +#ifndef __FTS_ERROR_H +#define __FTS_ERROR_H + + +//FIRST LEVEL ERROR CODE +#define OK (int)(0x00000000)/* No ERROR*/ +/*allocation of memory failed*/ +#define ERROR_ALLOC (int)(0x80000001) +#define ERROR_I2C_R (int)(0x80000002)//i2c read failed +#define ERROR_I2C_W (int)(0x80000003)//i2c write failed +#define ERROR_I2C_WR (int)(0x80000004)//i2c write/read failed + +//error during opening i2c device +#define ERROR_I2C_O (int)(0x80000005) +#define ERROR_OP_NOT_ALLOW (int)(0x80000006)//operation not allowed + +//timeout expired! exceed the max number of +//retries or the max waiting time +#define ERROR_TIMEOUT (int)(0x80000007) + +//the file that i want to open is not found +#define ERROR_FILE_NOT_FOUND (int)(0x80000008) +//error during parsing the file +#define ERROR_FILE_PARSE (int)(0x80000009) +//error during reading the file +#define ERROR_FILE_READ (int)(0x8000000A) +#define ERROR_LABEL_NOT_FOUND (int)(0x8000000B)//label not found + +//fw in the chip newer than the one in the memmh +#define ERROR_FW_NO_UPDATE (int)(0x8000000C) +//flash status busy or unknown +#define ERROR_FLASH_UNKNOWN (int)(0x8000000D) + +//SECOND LEVEL ERROR CODE +//unable to disable the interrupt +#define ERROR_DISABLE_INTER (int)(0x80000200) + +//unable to activate the interrupt +#define ERROR_ENABLE_INTER (int)(0x80000300) + +#define ERROR_READ_B2 (int)(0x80000400)//B2 command failed + +//unable to read an offset from memory +#define ERROR_GET_OFFSET (int)(0x80000500) + +//unable to retrieve the data of a required frame +#define ERROR_GET_FRAME_DATA (int)(0x80000600) + +//FW answers with an event that has a +//different address respect the request done +#define ERROR_DIFF_COMP_TYPE (int)(0x80000700) + +//the signature of the compensation data is not A5 +#define ERROR_WRONG_COMP_SIGN (int)(0x80000800) +//the command Sense On failed +#define ERROR_SENSE_ON_FAIL (int)(0x80000900) +//the command Sense Off failed +#define ERROR_SENSE_OFF_FAIL (int)(0x80000A00) + +//the command SYSTEM RESET failed +#define ERROR_SYSTEM_RESET_FAIL (int)(0x80000B00) + +//flash status not ready within a timeout +#define ERROR_FLASH_NOT_READY (int)(0x80000C00) + +//unable to retrieve fw_vers or the config_id +#define ERROR_FW_VER_READ (int)(0x80000D00) + +//unable to enable/disable the gesture +#define ERROR_GESTURE_ENABLE_FAIL (int)(0x80000E00) + +//unable to start to add custom gesture +#define ERROR_GESTURE_START_ADD (int)(0x80000F00) + +//unable to finish to add custom gesture +#define ERROR_GESTURE_FINISH_ADD (int)(0x80001000) + +//unable to add custom gesture data +#define ERROR_GESTURE_DATA_ADD (int)(0x80001100) + +//unable to remove custom gesture data +#define ERROR_GESTURE_REMOVE (int)(0x80001200) + +//unable to enable/disable a feature mode in the IC +#define ERROR_FEATURE_ENABLE_DISABLE (int)(0x80001300) + +//unable to set/read noise parameter in the IC +#define ERROR_NOISE_PARAMETERS (int)(0x80001400) + +//unable to write/rewrite/read lockdown code in the IC +#define ERROR_LOCKDOWN_CODE (int)(0x80001500) + +//THIRD LEVEL ERROR CODE +//unable to retrieve the force and/or sense length +#define ERROR_CH_LEN (int)(0x80010000) + +//compensation data request failed +#define ERROR_REQU_COMP_DATA (int)(0x80020000) + +//unable to retrieve the compensation data header +#define ERROR_COMP_DATA_HEADER (int)(0x80030000) + +//unable to retrieve the global compensation data +#define ERROR_COMP_DATA_GLOBAL (int)(0x80040000) + +//unable to retrieve the compensation data for each node +#define ERROR_COMP_DATA_NODE (int)(0x80050000) + +//check of production limits or of fw answers failed +#define ERROR_TEST_CHECK_FAIL (int)(0x80060000) +#define ERROR_MEMH_READ (int)(0x80070000)//memh reading failed +#define ERROR_FLASH_BURN_FAILED (int)(0x80080000)//flash burn failed +#define ERROR_MS_TUNING (int)(0x80090000)//ms tuning failed +#define ERROR_SS_TUNING (int)(0x800A0000)//ss tuning failed +//lp timer calibration failed +#define ERROR_LP_TIMER_TUNING (int)(0x800B0000) +//save cx data to flash failed +#define ERROR_SAVE_CX_TUNING (int)(0x800C0000) + +//stop the poll of the FIFO if particular errors are found +#define ERROR_HANDLER_STOP_PROC (int)(0x800D0000) +//unable to retrieve echo event +#define ERROR_CHECK_ECHO_FAIL (int)(0x800E0000) + +//FOURTH LEVEL ERROR CODE +//production data test failed +#define ERROR_PROD_TEST_DATA (int)(0x81000000) + +//complete flash procedure failed +#define ERROR_FLASH_PROCEDURE (int)(0x82000000) +//production ito test failed +#define ERROR_PROD_TEST_ITO (int)(0x83000000) + +//production initialization test failed +#define ERROR_PROD_TEST_INITIALIZATION (int)(0x84000000) + +//mismatch of the MS or SS tuning_version +#define ERROR_GET_INIT_STATUS (int)(0x85000000) + void logError(int force, const char *msg, ...); int isI2cError(int error); +int dumpErrorInfo(void); int errorHandler(u8 *event, int size); + +#endif diff --git a/drivers/input/touchscreen/st/fts_lib/ftsFlash.c b/drivers/input/touchscreen/st/fts_lib/ftsFlash.c index f3becac79102..e667968b426a 100644 --- a/drivers/input/touchscreen/st/fts_lib/ftsFlash.c +++ b/drivers/input/touchscreen/st/fts_lib/ftsFlash.c @@ -1,30 +1,38 @@ /* + * FTS Capacitive touch screen controller (FingerTipS) + * + * Copyright (C) 2016-2018, STMicroelectronics Limited. + * Authors: AMG(Analog Mems Group) + * + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + */ +/** + * ************************************************************************** - ** STMicroelectronics ** + ** STMicroelectronics ** ************************************************************************** - ** marco.cali@st.com ** + ** marco.cali@st.com ** ************************************************************************** * * - * FTS API for Flashing the IC * + * FTS API for Flashing the IC * * * ************************************************************************** ************************************************************************** - + * */ -#include "ftsCrossCompile.h" -#include "ftsCompensation.h" -#include "ftsError.h" -#include "ftsFlash.h" -#include "ftsFrame.h" -#include "ftsIO.h" -#include "ftsSoftware.h" -#include "ftsTest.h" -#include "ftsTime.h" -#include "ftsTool.h" -#include "../fts.h" /* needed for the FW_H_FILE define */ - #include #include #include @@ -49,14 +57,27 @@ #include #include #include -/* #include */ + +#include "ftsCrossCompile.h" +#include "ftsCompensation.h" +#include "ftsError.h" +#include "ftsFlash.h" +#include "ftsFrame.h" +#include "ftsIO.h" +#include "ftsSoftware.h" +#include "ftsTest.h" +#include "ftsTime.h" +#include "ftsTool.h" +#include "../fts.h"//needed for including the define FW_H_FILE #ifdef FW_H_FILE #include <../fts_fw.h> +#define LOAD_FW_FROM 1 +#else +#define LOAD_FW_FROM 0 #endif -/* static char tag[8] = "[ FTS ]\0"; */ -extern chipInfo ftsInfo; +static char tag[8] = "[ FTS ]\0"; int getFirmwareVersion(u16 *fw_vers, u16 *config_id) { @@ -64,20 +85,28 @@ int getFirmwareVersion(u16 *fw_vers, u16 *config_id) u8 confid[CONFIG_ID_BYTE]; int res; - res = readCmdU16(FTS_CMD_HW_REG_R, DCHIP_FW_VER_ADDR, fwvers, DCHIP_FW_VER_BYTE, DUMMY_HW_REG); + res = readCmdU16(FTS_CMD_HW_REG_R, DCHIP_FW_VER_ADDR, + fwvers, DCHIP_FW_VER_BYTE, DUMMY_HW_REG); if (res < OK) { - logError(1, "%s getFirmwareVersion: unable to read fw_version ERROR %02X\n", tag, ERROR_FW_VER_READ); + logError(1, + "%s %s:unable to read fw_version ERROR %02X\n", + tag, __func__, ERROR_FW_VER_READ); return (res | ERROR_FW_VER_READ); } - u8ToU16(fwvers, fw_vers); /* fw version use big endian */ - if (*fw_vers != 0) { /* if fw_version is 00 00 means that there is no firmware running in the chip therefore will be impossible find the config_id */ + u8ToU16(fwvers, fw_vers); //fw version use big endian + if (*fw_vers != 0) { + // if fw_version is 00 00 means that there is + //no firmware running in the chip therefore will be + //impossible find the config_id res = readB2(CONFIG_ID_ADDR, confid, CONFIG_ID_BYTE); if (res < OK) { - logError(1, "%s getFirmwareVersion: unable to read config_id ERROR %02X\n", tag, ERROR_FW_VER_READ); + logError(1, "%s %s:unable to read config_id ", + tag, __func__); + logError(1, "ERROR %02X\n", ERROR_FW_VER_READ); return (res | ERROR_FW_VER_READ); } - u8ToU16(confid, config_id); /* config id use little endian */ + u8ToU16(confid, config_id); //config id use little endian } else { *config_id = 0x0000; } @@ -85,26 +114,136 @@ int getFirmwareVersion(u16 *fw_vers, u16 *config_id) logError(0, "%s FW VERS = %04X\n", tag, *fw_vers); logError(0, "%s CONFIG ID = %04X\n", tag, *config_id); return OK; +} + +int getFWdata(const char *pathToFile, u8 **data, int *size, int from) +{ + const struct firmware *fw = NULL; + struct device *dev = NULL; + int res; + + logError(1, "%s %s starting...\n", tag, __func__); + switch (from) { +#ifdef FW_H_FILE + case 1: + logError(1, "%s Read FW from .h file!\n", tag); + *size = FW_SIZE_NAME; + *data = (u8 *)kmalloc_array((*size), sizeof(u8), GFP_KERNEL); + if (*data == NULL) { + logError(1, "%s %s:Impossible to allocate memory! ", + tag, __func__); + logError(1, "ERROR %08X\n", ERROR_ALLOC); + + return ERROR_ALLOC; + } + memcpy(*data, (u8 *)FW_ARRAY_NAME, (*size)); + break; +#endif + default: + logError(1, "%s Read FW from BIN file!\n", tag); + dev = getDev(); + + if (dev != NULL) { + res = request_firmware(&fw, pathToFile, dev); + if (res == 0) { + *size = fw->size; + *data = (u8 *)kmalloc_array((*size), sizeof(u8), + GFP_KERNEL); + if (*data == NULL) { + logError(1, "%s %s:Impossible to ", + tag, __func__); + logError(1, "%allocate! %08X\n", + ERROR_ALLOC); + release_firmware(fw); + return ERROR_ALLOC; + } + memcpy(*data, (u8 *)fw->data, (*size)); + release_firmware(fw); + } else { + logError(1, "%s %s:No File found! ERROR %08X\n", + tag, __func__, ERROR_FILE_NOT_FOUND); + return ERROR_FILE_NOT_FOUND; + } + } else { + logError(1, "%s %s:No device found! ERROR %08X\n", + tag, __func__, ERROR_OP_NOT_ALLOW); + return ERROR_OP_NOT_ALLOW; + } + } + logError(1, "%s %s:Finshed!\n", tag, __func__); + return OK; +} + +int readFwFile(const char *path, struct Firmware *fw, int keep_cx) +{ + int res; + int orig_size; + u8 *orig_data = NULL; + + + res = getFWdata(path, &orig_data, &orig_size, LOAD_FW_FROM); + if (res < OK) { + logError(1, "%s %s:impossible retrieve FW... ERROR %08X\n", + tag, __func__, ERROR_MEMH_READ); + + return (res | ERROR_MEMH_READ); + } + res = parseBinFile(orig_data, orig_size, fw, keep_cx); + + if (res < OK) { + logError(1, "%s %s:impossible parse ERROR %08X\n", + tag, __func__, ERROR_MEMH_READ); + return (res | ERROR_MEMH_READ); + } + return OK; } -#ifdef FTM3_CHIP +int flashProcedure(const char *path, int force, int keep_cx) +{ + struct Firmware fw; + int res; + + fw.data = NULL; + logError(0, "%s Reading Fw file...\n", tag); + res = readFwFile(path, &fw, keep_cx); + if (res < OK) { + logError(1, "%s %s: ERROR %02X\n", + tag, __func__, (res | ERROR_FLASH_PROCEDURE)); + kfree(fw.data); + return (res | ERROR_FLASH_PROCEDURE); + } + logError(0, "%s Fw file read COMPLETED!\n", tag); + logError(0, "%s Starting flashing procedure...\n", tag); + res = flash_burn(fw, force, keep_cx); + if (res < OK && res != (ERROR_FW_NO_UPDATE | ERROR_FLASH_BURN_FAILED)) { + logError(1, "%s %s: ERROR %02X\n", + tag, __func__, ERROR_FLASH_PROCEDURE); + kfree(fw.data); + return (res | ERROR_FLASH_PROCEDURE); + } + logError(0, "%s flashing procedure Finished!\n", tag); + kfree(fw.data); + + return res; +} + +#ifdef FTM3_CHIP int flash_status(void) { u8 cmd[2] = {FLASH_CMD_READSTATUS, 0x00}; - u8 readData = 0; + u8 readData; - logError(0, "%s Reading flash_status...\n", tag); + logError(0, "%s %s:Reading ...\n", tag, __func__); if (fts_readCmd(cmd, 2, &readData, FLASH_STATUS_BYTES) < 0) { - logError(1, "%s flash_status: ERROR % 02X\n", tag, ERROR_I2C_R); + logError(1, "%s %s: ERROR % 02X\n", tag, __func__, ERROR_I2C_R); return ERROR_I2C_R; } readData &= 0x01; - /* logError(0, "%s flash_status = %d\n", tag,readData); */ + logError(0, "%s %s = %d\n", tag, __func__, readData); return (int) readData; - } int flash_status_ready(void) @@ -113,31 +252,34 @@ int flash_status_ready(void) int status = flash_status(); if (status == ERROR_I2C_R) { - logError(1, "%s flash_status_ready: ERROR % 02X\n", tag, ERROR_I2C_R); + logError(1, "%s %s: ERROR % 02X\n", tag, __func__, ERROR_I2C_R); return ERROR_I2C_R; } if (status != FLASH_READY) { - logError(1, "%s flash_status_ready: flash busy or unknown STATUS = % 02X\n", tag, status); + //logError(1, + //"%s %s:flash busy or unknown STATUS = % 02X\n", + //tag, status); return ERROR_FLASH_UNKNOWN; } return FLASH_READY; - } int wait_for_flash_ready(void) { int status; - int(*code)(void); + int (*code)(void); code = flash_status_ready; logError(0, "%s Waiting for flash ready...\n", tag); - status = attempt_function(code, FLASH_WAIT_BEFORE_RETRY, FLASH_RETRY_COUNT); + status = attempt_function(code, FLASH_WAIT_BEFORE_RETRY, + FLASH_RETRY_COUNT); if (status != FLASH_READY) { - logError(1, "%s wait_for_flash_ready: ERROR % 02X\n", tag, ERROR_FLASH_NOT_READY); + logError(1, "%s %s: ERROR % 02X\n", + tag, __func__, ERROR_FLASH_NOT_READY); return (status | ERROR_FLASH_NOT_READY); } @@ -147,204 +289,106 @@ int wait_for_flash_ready(void) int flash_unlock(void) { - int status; - u8 cmd[3] = {FLASH_CMD_UNLOCK, FLASH_UNLOCK_CODE0, FLASH_UNLOCK_CODE1}; /* write the comand to perform the unlock */ + //write the command to perform the unlock + u8 cmd[3] = {FLASH_CMD_UNLOCK, FLASH_UNLOCK_CODE0, + FLASH_UNLOCK_CODE1}; logError(0, "%s Try to unlock flash...\n", tag); status = wait_for_flash_ready(); if (status != OK) { - logError(1, "%s flash_unlock: ERROR % 02X\n", tag, ERROR_FLASH_NOT_READY); - return (status | ERROR_FLASH_NOT_READY); /* Flash not ready within the choosen time, better exit! */ + logError(1, "%s %s: ERROR % 02X\n", + tag, __func__, ERROR_FLASH_NOT_READY); + //Flash not ready within the chosen time, better exit! + return (status | ERROR_FLASH_NOT_READY); } logError(0, "%s Command unlock ...\n", tag); - if (fts_writeCmd(cmd, sizeof (cmd)) < 0) { - logError(1, "%s flash_unlock: ERROR % 02X\n", tag, ERROR_I2C_W); + if (fts_writeCmd(cmd, sizeof(cmd)) < 0) { + logError(1, "%s %s: ERROR % 02X\n", + tag, __func__, ERROR_I2C_W); return ERROR_I2C_W; } status = wait_for_flash_ready(); if (status != OK) { - logError(1, "%s flash_unlock: ERROR % 02X\n", tag, ERROR_FLASH_NOT_READY); - return (status | ERROR_FLASH_NOT_READY); /* Flash not ready within the choosen time, better exit! */ + logError(1, "%s %s: ERROR % 02X\n", + tag, __func__, ERROR_FLASH_NOT_READY); + //Flash not ready within the chosen time, + //better exit! + return (status | ERROR_FLASH_NOT_READY); } - logError(0, "%s Unlock flash DONE!\n", tag); return OK; - } -/*int parseMemhFile(const char *pathToFile, u8** data, int* length, int dimension) +int parseBinFile(u8 *fw_data, int fw_size, Firmware *fwData, int keep_cx) { + int dimension; - int i = 0; - unsigned long ul; - u8* buff = NULL; - int fd = -1; - int n, size, pointer = 0; - char *data_file, *line; - const struct firmware *fw = NULL; - struct device *dev = NULL; - - line = (char *) kmalloc(11 * sizeof (char), GFP_KERNEL); - if (line == NULL) { - logError(1, "%s parseMemhFile: ERROR %02X\n", tag, ERROR_ALLOC); - return ERROR_ALLOC; - } - - logError(0, "%s parseMemhFile: allocating %d bytes\n", tag, dimension); - buff = (u8*) kmalloc(dimension * sizeof (u8), GFP_KERNEL); - if (buff == NULL) { - logError(1, "%s parseMemhFile: ERROR %02X\n", tag, ERROR_ALLOC); - return ERROR_ALLOC; - } - - dev = getDev(); - if (dev != NULL) - fd = request_firmware(&fw, pathToFile, dev); - - if (fd == 0) { - size = fw->size; - logError(0, "%s The size of the firmware file is %d bytes...\n", tag, size); - data_file = (char *) fw->data; - logError(0, "%s Start to reading %s...\n", tag, pathToFile); - - while (size - pointer > 0 && (i * 4 + 4) <= dimension) { - if (readLine(&data_file[pointer], &line, size - pointer, &n) < 0) { - break; - } - pointer += n; - logError(0, "%s Pointer= %d riga = %s\n", tag, pointer, line); - ul = simple_strtoul(line, NULL, 16); - - buff[i * 4] = (u8) ((ul & 0x000000FF) >> 0); - buff[i * 4 + 1] = (u8) ((ul & 0x0000FF00) >> 8); - buff[i * 4 + 2] = (u8) ((ul & 0x00FF0000) >> 16); - buff[i * 4 + 3] = (u8) ((ul & 0xFF000000) >> 24); - i++; - } - - kfree(line); - - *length = i * 4; - if (*length < dimension) { - logError(1, "%s parseMemhFile: Read only %d instead of %d... ERROR %02X\n", tag, *length, dimension, ERROR_FILE_PARSE); - release_firmware(fw); - return ERROR_FILE_PARSE; - } - *data = buff; - - logError(0, "%s READ DONE %d bytes!\n", tag, *length); - release_firmware(fw); - return OK; + if (keep_cx) { + dimension = FW_SIZE - FW_CX_SIZE; + logError(1, "%s %s: Selected 124k Configuration!\n", + tag, __func__); } else { - logError(1, "%s parseProductionTestLimits: ERROR %02X\n", tag, ERROR_FILE_NOT_FOUND); - return ERROR_FILE_NOT_FOUND; + dimension = FW_SIZE; + logError(1, "%s %s: Selected 128k Configuration!\n", + tag, __func__); } -}*/ - -int parseBinFile(const char *pathToFile, u8 **data, int *length, int dimension) -{ - - int fd = -1; - int fw_size = 0; - u8 *fw_data = NULL; - -#ifndef FW_H_FILE - const struct firmware *fw = NULL; - struct device *dev = NULL; - dev = getDev(); - - if (dev != NULL) - fd = request_firmware(&fw, pathToFile, dev); - else { - logError(1, "%s parseBinFile: No device found! ERROR %02X\n", ERROR_FILE_PARSE); + if (fw_size - FW_HEADER_SIZE != FW_SIZE || fw_data == NULL) { + logError(1, "%s %s:Read only %d instead of %d... ERROR %02X\n", + tag, __func__, + fw_size - FW_HEADER_SIZE, + FW_SIZE, ERROR_FILE_PARSE); + kfree(fw_data); return ERROR_FILE_PARSE; } -#else - fd = 0; -#endif - - if (fd == 0) { -#ifndef FW_H_FILE - fw_size = fw->size; - fw_data = (u8 *) (fw->data); -#else - fw_size = FW_SIZE_NAME; - fw_data = (u8 *) FW_ARRAY_NAME; -#endif - if (fw_size - FW_HEADER_SIZE != FW_SIZE) { - logError(1, "%s parseBinFile: Read only %d instead of %d... ERROR %02X\n", tag, fw_size, FW_SIZE, ERROR_FILE_PARSE); -#ifndef FW_H_FILE - release_firmware(fw); -#endif - return ERROR_FILE_PARSE; - } - *data = (u8 *) kmalloc(dimension * sizeof (u8), GFP_KERNEL); - if (*data == NULL) { - logError(1, "%s parseBinFile: ERROR %02X\n", tag, ERROR_ALLOC); -#ifndef FW_H_FILE - release_firmware(fw); -#endif - return ERROR_ALLOC; - } - memcpy(*data, ((u8 *) (fw_data) + FW_HEADER_SIZE), dimension); - *length = dimension; + fwData->data = (u8 *)kmalloc_array(dimension, sizeof(u8), GFP_KERNEL); + if (fwData->data == NULL) { + logError(1, "%s %s: ERROR %02X\n", tag, __func__, ERROR_ALLOC); - logError(0, "%s READ FW DONE %d bytes!\n", tag, *length); -#ifndef FW_H_FILE - release_firmware(fw); -#endif - return OK; - } - logError(1, "%s parseBinFile: File Not Found! ERROR %02X\n", tag, ERROR_FILE_NOT_FOUND); - return ERROR_FILE_NOT_FOUND; -} + kfree(fw_data); + return ERROR_ALLOC; + } -int readFwFile(const char *path, Firmware *fw, int keep_cx) -{ - int res; - int size; + memcpy(fwData->data, ((u8 *)(fw_data) + FW_HEADER_SIZE), + dimension); + fwData->data_size = dimension; - if (keep_cx) { - size = FW_SIZE - FW_CX_SIZE; - logError(1, "%s readFwFile: Selected 124k Configuration!\n", tag); - } else { - size = FW_SIZE; - logError(1, "%s readFwFile: Selected 128k Configuration!\n", tag); - } + fwData->fw_ver = (u16)(((fwData->data[FW_VER_MEMH_BYTE1] & 0x00FF) << 8) + + (fwData->data[FW_VER_MEMH_BYTE0] & 0x00FF)); - /* res = parseMemhFile(path, &(fw->data), &(fw->data_size), size); */ - res = parseBinFile(path, &(fw->data), &(fw->data_size), size); - if (res < OK) { - logError(1, "%s readFwFile: ERROR %02X\n", tag, ERROR_MEMH_READ); - return (res | ERROR_MEMH_READ); - } + fwData->config_id = (u16)(((fwData->data[(FW_CODE_SIZE) + + FW_OFF_CONFID_MEMH_BYTE1] & 0x00FF) << 8) + + (fwData->data[(FW_CODE_SIZE) + + FW_OFF_CONFID_MEMH_BYTE0] & 0x00FF)); - fw->fw_ver = (u16) (((fw->data[FW_VER_MEMH_BYTE1] & 0x00FF) << 8) + (fw->data[FW_VER_MEMH_BYTE0] & 0x00FF)); - fw->config_id = (u16) (((fw->data[(FW_CODE_SIZE) + FW_OFF_CONFID_MEMH_BYTE1] & 0x00FF) << 8) + (fw->data[(FW_CODE_SIZE) + FW_OFF_CONFID_MEMH_BYTE0] & 0x00FF)); + logError(0, "%s %s: FW VERS File = %04X\n", + tag, __func__, fwData->fw_ver); + logError(0, "%s %s: CONFIG ID File = %04X\n", + tag, __func__, fwData->config_id); - logError(0, "%s FW VERS File = %04X\n", tag, fw->fw_ver); - logError(0, "%s CONFIG ID File = %04X\n", tag, fw->config_id); - return OK; + logError(0, "%s READ FW DONE %d bytes!\n", tag, fwData->data_size); + kfree(fw_data); + return OK; } int fillMemory(u32 address, u8 *data, int size) { - int remaining = size; int toWrite = 0; + int delta; - u8 *buff = (u8 *) kmalloc((MEMORY_CHUNK + 3) * sizeof (u8), GFP_KERNEL); + u8 *buff = (u8 *)kmalloc_array((MEMORY_CHUNK + 3), sizeof(u8), + GFP_KERNEL); if (buff == NULL) { - logError(1, "%s fillMemory: ERROR %02X\n", tag, ERROR_ALLOC); + logError(1, "%s %s: ERROR %02X\n", tag, __func__, ERROR_ALLOC); return ERROR_ALLOC; } @@ -356,7 +400,8 @@ int fillMemory(u32 address, u8 *data, int size) remaining -= MEMORY_CHUNK; } else { if (address < FLASH_ADDR_SWITCH_CMD) { - int delta = FLASH_ADDR_SWITCH_CMD - address; + delta = FLASH_ADDR_SWITCH_CMD - address; + buff[0] = FLASH_CMD_WRITE_LOWER_64; toWrite = delta; remaining -= delta; @@ -373,7 +418,8 @@ int fillMemory(u32 address, u8 *data, int size) remaining = 0; } else { if (address < FLASH_ADDR_SWITCH_CMD) { - int delta = FLASH_ADDR_SWITCH_CMD - address; + delta = FLASH_ADDR_SWITCH_CMD - address; + buff[0] = FLASH_CMD_WRITE_LOWER_64; toWrite = delta; remaining -= delta; @@ -388,152 +434,154 @@ int fillMemory(u32 address, u8 *data, int size) buff[1] = (u8) ((address & 0x0000FF00) >> 8); buff[2] = (u8) (address & 0x000000FF); memcpy(buff + 3, data, toWrite); - logError(0, "%s Command = %02X , address = %02X %02X, bytes = %d\n", tag, buff[0], buff[1], buff[2], toWrite); + //logError(0, + //"%s Command = %02X , address = %02X %02X, bytes = %d\n", + //tag, buff[0], buff[1], buff[2], toWrite); if (fts_writeCmd(buff, 3 + toWrite) < 0) { - logError(1, "%s fillMemory: ERROR %02X\n", tag, ERROR_I2C_W); + logError(1, "%s %s: ERROR %02X\n", + tag, __func__, ERROR_I2C_W); + kfree(buff); return ERROR_I2C_W; } - address += toWrite; data += toWrite; - } + kfree(buff); return OK; } -int flash_burn(Firmware fw, int force_burn) +int flash_burn(Firmware fw, int force_burn, int keep_cx) { u8 cmd; int res; - if (!force_burn && (ftsInfo.u16_fwVer >= fw.fw_ver) && (ftsInfo.u16_cfgId >= fw.config_id)) { - logError(1, "%s flash_burn: Firmware in the chip newer or equal to the one to burn! NO UPDATE ERROR %02X\n", tag, ERROR_FW_NO_UPDATE); + if (!force_burn && (ftsInfo.u16_fwVer >= fw.fw_ver) + && (ftsInfo.u16_cfgId >= fw.config_id)) { + logError(1, "Firmware in the chip newer"); + logError(1, " or equal to the one to burn! "); + logError(1, "%s %s:NO UPDATE ERROR %02X\n", + tag, __func__, ERROR_FW_NO_UPDATE); return (ERROR_FW_NO_UPDATE | ERROR_FLASH_BURN_FAILED); } - /* programming procedure start */ + //programming procedure start - logError(0, "%s Programming Procedure for flashing started:\n\n", tag); + logError(0, "%s Programming Procedure for flashing started:\n", tag); logError(0, "%s 1) SYSTEM RESET:\n", tag); res = fts_system_reset(); if (res < 0) { - logError(1, "%s system reset FAILED!\n", tag); - if (res != (ERROR_SYSTEM_RESET_FAIL | ERROR_TIMEOUT)) /* if there is no firmware i will not get the controller ready event and there will be a timeout but i can keep going, but if there is an I2C error i have to exit */ + logError(1, "%s system reset FAILED!\n", tag); + //if there is no firmware i will not + //get the controller ready event and + //there will be a timeout but i can + //keep going, but if there is + //an I2C error i have to exit + if (res != (ERROR_SYSTEM_RESET_FAIL | ERROR_TIMEOUT)) return (res | ERROR_FLASH_BURN_FAILED); } else - logError(0, "%s system reset COMPLETED!\n\n", tag); + logError(0, "%s system reset COMPLETED!\n\n", tag); logError(0, "%s 2) FLASH UNLOCK:\n", tag); res = flash_unlock(); if (res < 0) { - logError(1, "%s flash unlock FAILED! ERROR %02X\n", tag, ERROR_FLASH_BURN_FAILED); + logError(1, "%s flash unlock FAILED! ERROR %02X\n", + tag, ERROR_FLASH_BURN_FAILED); return (res | ERROR_FLASH_BURN_FAILED); } - logError(0, "%s flash unlock COMPLETED!\n\n", tag); + logError(0, "%s flash unlock COMPLETED!\n\n", tag); + - /* Write the lower part of the Program RAM */ + //Write the lower part of the Program RAM logError(0, "%s 3) PREPARING DATA FOR FLASH BURN:\n", tag); res = fillMemory(FLASH_ADDR_CODE, fw.data, fw.data_size); if (res < 0) { - logError(1, "%s Error During filling the memory! ERROR %02X\n", tag, ERROR_FLASH_BURN_FAILED); + logError(1, "%s Error During filling the memory!%02X\n", + tag, ERROR_FLASH_BURN_FAILED); return (res | ERROR_FLASH_BURN_FAILED); } - logError(0, "%s Data copy COMPLETED!\n\n", tag); + logError(0, "%s Data copy COMPLETED!\n\n", tag); logError(0, "%s 4) ERASE FLASH:\n", tag); res = wait_for_flash_ready(); if (res < 0) { - logError(1, "%s Flash not ready! ERROR %02X\n", tag, ERROR_FLASH_BURN_FAILED); + logError(1, "%s Flash not ready! ERROR %02X\n", + tag, ERROR_FLASH_BURN_FAILED); return (res | ERROR_FLASH_BURN_FAILED); } logError(0, "%s Command erase ...\n", tag); cmd = FLASH_CMD_ERASE; if (fts_writeCmd(&cmd, 1) < 0) { - logError(1, "%s Error during erasing flash! ERROR %02X\n", tag, ERROR_FLASH_BURN_FAILED); + logError(1, "%s Error during erasing flash! ERROR %02X\n", + tag, ERROR_FLASH_BURN_FAILED); return (ERROR_I2C_W | ERROR_FLASH_BURN_FAILED); } res = wait_for_flash_ready(); if (res < 0) { - logError(1, "%s Flash not ready 2! ERROR %02X\n", tag, ERROR_FLASH_BURN_FAILED); + logError(1, "%s Flash not ready 2! ERROR %02X\n", + tag, ERROR_FLASH_BURN_FAILED); return (res | ERROR_FLASH_BURN_FAILED); } - logError(0, "%s Flash erase COMPLETED!\n\n", tag); + logError(0, "%s Flash erase COMPLETED!\n\n", tag); logError(0, "%s 5) BURN FLASH:\n", tag); logError(0, "%s Command burn ...\n", tag); cmd = FLASH_CMD_BURN; if (fts_writeCmd(&cmd, 1) < 0) { - logError(1, "%s Error during burning data! ERROR %02X\n", tag, ERROR_FLASH_BURN_FAILED); + logError(1, "%s Error during burning data! ERROR %02X\n", + tag, ERROR_FLASH_BURN_FAILED); return (ERROR_I2C_W | ERROR_FLASH_BURN_FAILED); } res = wait_for_flash_ready(); if (res < 0) { - logError(1, "%s Flash not ready! ERROR %02X\n", tag, ERROR_FLASH_BURN_FAILED); + logError(1, "%s Flash not ready! ERROR %02X\n", + tag, ERROR_FLASH_BURN_FAILED); return (res | ERROR_FLASH_BURN_FAILED); } - logError(0, "%s Flash burn COMPLETED!\n\n", tag); + logError(0, "%s Flash burn COMPLETED!\n\n", tag); logError(0, "%s 6) SYSTEM RESET:\n", tag); res = fts_system_reset(); if (res < 0) { - logError(1, "%s system reset FAILED! ERROR %02X\n", tag, ERROR_FLASH_BURN_FAILED); + logError(1, "%s system reset FAILED! ERROR %02X\n", + tag, ERROR_FLASH_BURN_FAILED); return (res | ERROR_FLASH_BURN_FAILED); } - logError(0, "%s system reset COMPLETED!\n\n", tag); + logError(0, "%s system reset COMPLETED!\n\n", tag); + logError(0, "%s 7) FINAL CHECK:\n", tag); res = readChipInfo(0); if (res < 0) { - logError(1, "%s flash_burn: Unable to retrieve Chip INFO! ERROR %02X\n", tag, ERROR_FLASH_BURN_FAILED); + logError(1, "%s %s:Unable to retrieve Chip INFO!%02X\n", + tag, ERROR_FLASH_BURN_FAILED); return (res | ERROR_FLASH_BURN_FAILED); } - if ((ftsInfo.u16_fwVer != fw.fw_ver) && (ftsInfo.u16_cfgId != fw.config_id)) { - logError(1, "%s Firmware in the chip different from the one that was burn! fw: %x != %x , conf: %x != %x\n", tag, ftsInfo.u16_fwVer, fw.fw_ver, ftsInfo.u16_cfgId, fw.config_id); + if ((ftsInfo.u16_fwVer != fw.fw_ver) + && (ftsInfo.u16_cfgId != fw.config_id)) { + logError(1, "Firmware in the chip different"); + logError(1, " from the one that was burn!"); + logError(1, "%s fw: %x != %x , conf: %x != %x\n", + tag, ftsInfo.u16_fwVer, + fw.fw_ver, + ftsInfo.u16_cfgId, + fw.config_id); return ERROR_FLASH_BURN_FAILED; } - logError(0, "%s Final check OK! fw: %02X , conf: %02X\n", tag, ftsInfo.u16_fwVer, ftsInfo.u16_cfgId); + logError(0, "%s Final check OK! fw: %02X, conf: %02X\n", + tag, ftsInfo.u16_fwVer, ftsInfo.u16_cfgId); return OK; } -int flashProcedure(const char *path, int force, int keep_cx) -{ - Firmware fw; - int res; - - fw.data = NULL; - logError(0, "%s Reading Fw file...\n", tag); - res = readFwFile(path, &fw, keep_cx); - if (res < OK) { - logError(1, "%s flashProcedure: ERROR %02X\n", tag, (res | ERROR_FLASH_PROCEDURE)); - kfree(fw.data); - return (res | ERROR_FLASH_PROCEDURE); - } - logError(0, "%s Fw file read COMPLETED!\n", tag); - - logError(0, "%s Starting flashing procedure...\n", tag); - res = flash_burn(fw, force); - if (res < OK && res != (ERROR_FW_NO_UPDATE | ERROR_FLASH_BURN_FAILED)) { - logError(1, "%s flashProcedure: ERROR %02X\n", tag, ERROR_FLASH_PROCEDURE); - kfree(fw.data); - return (res | ERROR_FLASH_PROCEDURE); - } - logError(0, "%s flashing procedure Finished!\n", tag); - kfree(fw.data); - - /* cleanUp(0); //after talking with Kusuma, the SenseOn should be issued only at the very end of the initialization process, if senso on here it can trigger autotune protection */ - return res; -} - #else int wait_for_flash_ready(u8 type) @@ -544,17 +592,19 @@ int wait_for_flash_ready(u8 type) logError(0, "%s Waiting for flash ready ...\n", tag); for (i = 0; i < FLASH_RETRY_COUNT && res != 0; i++) { - if (fts_readCmd(cmd, sizeof (cmd), &readData, 1) < 0) { - logError(1, "%s wait_for_flash_ready: ERROR % 02X\n", tag, ERROR_I2C_W); - } else{ + if (fts_readCmd(cmd, sizeof(cmd), &readData, 1) < 0) { + logError(1, "%s %s: ERROR % 02X\n", + tag, __func__, ERROR_I2C_R); + } else { res = readData & 0x80; - /* logError(0, "%s flash status = %d \n", tag, res); */ - } + //logError(0, "%s flash status = %d\n", tag, res); + } msleep(FLASH_WAIT_BEFORE_RETRY); } if (i == FLASH_RETRY_COUNT && res != 0) { - logError(1, "%s Wait for flash TIMEOUT! ERROR %02X\n", tag, ERROR_TIMEOUT); + logError(1, "%s Wait for flash TIMEOUT! ERROR %02X\n", + tag, ERROR_TIMEOUT); return ERROR_TIMEOUT; } @@ -564,12 +614,13 @@ int wait_for_flash_ready(u8 type) int fts_warm_boot(void) { + //write the command to perform the warm boot + u8 cmd[4] = {FTS_CMD_HW_REG_W, 0x00, 0x00, WARM_BOOT_VALUE}; - u8 cmd[4] = {FTS_CMD_HW_REG_W, 0x00, 0x00, WARM_BOOT_VALUE}; /* write the command to perform the warm boot */ u16ToU8_be(ADDR_WARM_BOOT, &cmd[1]); logError(0, "%s Command warm boot ...\n", tag); - if (fts_writeCmd(cmd, sizeof (cmd)) < 0) { + if (fts_writeCmd(cmd, sizeof(cmd)) < 0) { logError(1, "%s flash_unlock: ERROR % 02X\n", tag, ERROR_I2C_W); return ERROR_I2C_W; } @@ -579,251 +630,272 @@ int fts_warm_boot(void) return OK; } -int parseBinFile(const char *pathToFile, Firmware *fwData, int keep_cx) +int parseBinFile(u8 *data, int fw_size, + struct Firmware *fwData, int keep_cx) { - - int fd = -1; int dimension, index = 0; u32 temp; - u8 *data; - int res, i, fw_size; - -#ifndef FW_H_FILE - const struct firmware *fw = NULL; - struct device *dev = NULL; - dev = getDev(); - - if (dev != NULL) - fd = request_firmware(&fw, pathToFile, dev); - else { - logError(1, "%s parseBinFile: No device found! ERROR %02X\n", ERROR_FILE_PARSE); - return ERROR_FILE_PARSE; - } - - fw_size = fw->size; -#else -fd = 0; -fw_size = SIZE_NAME; -#endif - - if (fd == 0 && fw_size > 0) { /* the file should contain at least the header plus the content_crc */ - if (fw_size < FW_HEADER_SIZE+FW_BYTES_ALIGN) { - logError(1, "%s parseBinFile: Read only %d instead of %d... ERROR %02X\n", tag, fw_size, FW_HEADER_SIZE+FW_BYTES_ALIGN, ERROR_FILE_PARSE); + int res, i; + + //the file should contain at least the header plus the content_crc + if (fw_size < FW_HEADER_SIZE+FW_BYTES_ALIGN || data == NULL) { + logError(1, "%s %s:Read only %d instead of %d...ERROR %02X\n", + tag, __func__, fw_size, + FW_HEADER_SIZE + FW_BYTES_ALIGN, + ERROR_FILE_PARSE); res = ERROR_FILE_PARSE; goto END; - } else { - /* start parsing of bytes */ -#ifndef FW_H_FILE - data = (u8 *) (fw->data); -#else - data = (u8 *) (ARRAY_NAME); -#endif + } else { + //start parsing of bytes u8ToU32(&data[index], &temp); if (temp != FW_HEADER_SIGNATURE) { - logError(1, "%s parseBinFile: Wrong Signature %08X ... ERROR %02X\n", tag, temp, ERROR_FILE_PARSE); - res = ERROR_FILE_PARSE; + logError(1, "%s %s:Wrong Signature %08X...ERROR %02X\n", + tag, __func__, temp, ERROR_FILE_PARSE); + res = ERROR_FILE_PARSE; goto END; } - logError(0, "%s parseBinFile: Fw Signature OK!\n", tag); + + logError(0, "%s %s: Fw Signature OK!\n", tag, __func__); index += FW_BYTES_ALIGN; u8ToU32(&data[index], &temp); if (temp != FW_FTB_VER) { - logError(1, "%s parseBinFile: Wrong ftb_version %08X ... ERROR %02X\n", tag, temp, ERROR_FILE_PARSE); - res = ERROR_FILE_PARSE; + logError(1, "%s %s:Wrong ftb_version %08X.ERROR %02X\n", + tag, __func__, temp, ERROR_FILE_PARSE); + res = ERROR_FILE_PARSE; goto END; } - logError(0, "%s parseBinFile: ftb_version OK!\n", tag); + logError(0, "%s %s:ftb_version OK!\n", __func__, tag); index += FW_BYTES_ALIGN; if (data[index] != DCHIP_ID_0 || data[index+1] != DCHIP_ID_1) { - logError(1, "%s parseBinFile: Wrong target %02X != %02X %02X != %02X ... ERROR %08X\n", tag, data[index], DCHIP_ID_0, data[index+1], DCHIP_ID_1, ERROR_FILE_PARSE); - res = ERROR_FILE_PARSE; + logError(1, "%s %s:Wrong target %02X != %02X ", + tag, __func__, data[index]); + logError(1, "%%02X != %02X:%08X\n", + DCHIP_ID_0, data[index+1], + DCHIP_ID_1, ERROR_FILE_PARSE); + res = ERROR_FILE_PARSE; goto END; } index += FW_BYTES_ALIGN; u8ToU32(&data[index], &temp); - logError(1, "%s parseBinFile: Fw ID = %08X\n", tag, temp); - + logError(1, "%s %s: Fw ID = %08X\n", tag, __func__, temp); index += FW_BYTES_ALIGN; u8ToU32(&data[index], &temp); fwData->fw_ver = temp; - logError(1, "%s parseBinFile: FILE Fw Version = %04X\n", tag, fwData->fw_ver); + logError(1, "%s %s:FILE Fw Version = %04X\n", + tag, __func__, fwData->fw_ver); index += FW_BYTES_ALIGN; u8ToU32(&data[index], &temp); fwData->config_id = temp; - logError(1, "%s parseBinFile: FILE Config ID = %08X\n", tag, temp); + logError(1, "%s %s:FILE Config ID = %04X\n", + tag, __func__, fwData->config_id); index += FW_BYTES_ALIGN; u8ToU32(&data[index], &temp); - logError(1, "%s parseBinFile: Config Version = %08X\n", tag, temp); - - index += FW_BYTES_ALIGN*2; /* skip reserved data */ - + logError(1, "%s %s:Config Version = %08X\n", + tag, __func__, temp); + //skip reserved data + index += FW_BYTES_ALIGN * 2; index += FW_BYTES_ALIGN; - logError(1, "%s parseBinFile: File External Release = ", tag); + logError(1, "%s %s:File External Release = ", + tag, __func__); for (i = 0; i < EXTERNAL_RELEASE_INFO_SIZE; i++) { fwData->externalRelease[i] = data[index++]; - logError(1, "%02X ", fwData->externalRelease[i]); + logError(1, "%02X", fwData->externalRelease[i]); } logError(1, "\n"); - /* index += FW_BYTES_ALIGN; */ + //index += FW_BYTES_ALIGN; u8ToU32(&data[index], &temp); fwData->sec0_size = temp; - logError(1, "%s parseBinFile: sec0_size = %08X (%d bytes)\n", tag, fwData->sec0_size, fwData->sec0_size); + logError(1, "%s %s:sec0_size = %08X (%d bytes)\n", + tag, __func__, fwData->sec0_size, fwData->sec0_size); index += FW_BYTES_ALIGN; u8ToU32(&data[index], &temp); fwData->sec1_size = temp; - logError(1, "%s parseBinFile: sec1_size = %08X (%d bytes)\n", tag, fwData->sec1_size, fwData->sec1_size); + logError(1, "%s %s:sec1_size = %08X (%d bytes)\n", + tag, __func__, fwData->sec1_size, fwData->sec1_size); index += FW_BYTES_ALIGN; u8ToU32(&data[index], &temp); fwData->sec2_size = temp; - logError(1, "%s parseBinFile: sec2_size = %08X (%d bytes)\n", tag, fwData->sec2_size, fwData->sec2_size); + logError(1, "%s %s:sec2_size = %08X (%d bytes)\n", + tag, __func__, fwData->sec2_size, fwData->sec2_size); index += FW_BYTES_ALIGN; u8ToU32(&data[index], &temp); fwData->sec3_size = temp; - logError(1, "%s parseBinFile: sec3_size = %08X (%d bytes)\n", tag, fwData->sec3_size, fwData->sec3_size); - - index += FW_BYTES_ALIGN; /* skip header crc */ + logError(1, "%s %s:sec3_size = %08X (%d bytes)\n", + tag, __func__, fwData->sec3_size, fwData->sec3_size); + //skip header crc + index += FW_BYTES_ALIGN; if (!keep_cx) { - dimension = fwData->sec0_size + fwData->sec1_size + fwData->sec2_size + fwData->sec3_size; - temp = fw_size; + dimension = fwData->sec0_size + fwData->sec1_size + + fwData->sec2_size + fwData->sec3_size; + temp = fw_size; } else { - dimension = fwData->sec0_size + fwData->sec1_size; /* sec2 may contain cx data (future implementation) sec3 atm not used */ - temp = fw_size - fwData->sec2_size - fwData->sec3_size; + //sec2 may contain cx data (future implementation) + //sec3 atm not used + dimension = fwData->sec0_size + fwData->sec1_size; + temp = fw_size - fwData->sec2_size - fwData->sec3_size; + fwData->sec2_size = 0; + fwData->sec3_size = 0; } - - if (dimension+FW_HEADER_SIZE+FW_BYTES_ALIGN != temp) { - logError(1, "%s parseBinFile: Read only %d instead of %d... ERROR %02X\n", tag, fw_size, dimension+FW_HEADER_SIZE+FW_BYTES_ALIGN, ERROR_FILE_PARSE); + if (dimension + FW_HEADER_SIZE + FW_BYTES_ALIGN != temp) { + logError(1, "%s %s:Read only %d instead of %d...", + tag, __func__, fw_size, + dimension + FW_HEADER_SIZE + FW_BYTES_ALIGN); + logError(1, "ERROR %02X\n", ERROR_FILE_PARSE); res = ERROR_FILE_PARSE; goto END; } - - fwData->data = (u8 *) kmalloc(dimension * sizeof (u8), GFP_KERNEL); - if (fwData->data == NULL) { - logError(1, "%s parseBinFile: ERROR %02X\n", tag, ERROR_ALLOC); - res = ERROR_ALLOC; - goto END; - } - + fwData->data = (u8 *)kmalloc_array(dimension, sizeof(u8), + GFP_KERNEL); + if (fwData->data == NULL) { + logError(1, "%s %s: ERROR %02X\n", + tag, __func__, ERROR_ALLOC); + res = ERROR_ALLOC; + goto END; + } index += FW_BYTES_ALIGN; - memcpy(fwData->data, &data[index], dimension); - fwData->data_size = dimension; - - logError(0, "%s READ FW DONE %d bytes!\n", tag, fwData->data_size); - res = OK; + memcpy(fwData->data, &data[index], dimension); + fwData->data_size = dimension; + logError(0, "%s READ FW DONE %d bytes!\n", + tag, fwData->data_size); + res = OK; goto END; - } - } else { - logError(1, "%s parseBinFile: File Not Found! ERROR %02X\n", tag, ERROR_FILE_NOT_FOUND); - return ERROR_FILE_NOT_FOUND; } - END: -#ifndef FW_H_FILE - release_firmware(fw); -#endif - return res; -} - -int readFwFile(const char *path, Firmware *fw, int keep_cx) -{ - int res; - - res = parseBinFile(path, fw, keep_cx); - if (res < OK) { - logError(1, "%s readFwFile: ERROR %02X\n", tag, ERROR_MEMH_READ); - return (res | ERROR_MEMH_READ); - } - - return OK; - + kfree(data); + return res; } int flash_unlock(void) { - u8 cmd[3] = {FLASH_CMD_UNLOCK, FLASH_UNLOCK_CODE0, FLASH_UNLOCK_CODE1}; /* write the command to perform the unlock */ - + //write the command to perform the unlock + u8 cmd[3] = {FLASH_CMD_UNLOCK, + FLASH_UNLOCK_CODE0, FLASH_UNLOCK_CODE1}; logError(0, "%s Command unlock ...\n", tag); - if (fts_writeCmd(cmd, sizeof (cmd)) < 0) { - logError(1, "%s flash_unlock: ERROR % 02X\n", tag, ERROR_I2C_W); + if (fts_writeCmd(cmd, sizeof(cmd)) < 0) { + logError(1, "%s %s: ERROR % 02X\n", tag, __func__, ERROR_I2C_W); return ERROR_I2C_W; } - - /* msleep(FLASH_WAIT_TIME); */ + //mdelay(FLASH_WAIT_TIME); logError(0, "%s Unlock flash DONE!\n", tag); return OK; - } int flash_erase_unlock(void) { - u8 cmd[3] = {FLASH_CMD_WRITE_REGISTER, FLASH_ERASE_UNLOCK_CODE0, FLASH_ERASE_UNLOCK_CODE1}; /* write the command to perform the unlock for erasing the flash */ + //write the command to perform + //the unlock for erasing the flash + u8 cmd[3] = {FLASH_CMD_WRITE_REGISTER, FLASH_ERASE_UNLOCK_CODE0, + FLASH_ERASE_UNLOCK_CODE1}; logError(0, "%s Try to erase unlock flash...\n", tag); logError(0, "%s Command erase unlock ...\n", tag); - if (fts_writeCmd(cmd, sizeof (cmd)) < 0) { - logError(1, "%s flash_erase_unlock: ERROR % 02X\n", tag, ERROR_I2C_W); + if (fts_writeCmd(cmd, sizeof(cmd)) < 0) { + logError(1, "%s %s:ERROR % 02X\n", tag, __func__, ERROR_I2C_W); return ERROR_I2C_W; } logError(0, "%s Erase Unlock flash DONE!\n", tag); return OK; - } int flash_full_erase(void) { - int status; - u8 cmd[3] = {FLASH_CMD_WRITE_REGISTER, FLASH_ERASE_CODE0, FLASH_ERASE_CODE1}; - /* write the command to erase the flash */ - - logError(0, "%s Command full erase sent ...\n", tag); - if (fts_writeCmd(cmd, sizeof (cmd)) < 0) { - logError(1, "%s flash_full_erase: ERROR % 02X\n", tag, ERROR_I2C_W); + //write the command to erase the flash + u8 cmd[3] = {FLASH_CMD_WRITE_REGISTER, FLASH_ERASE_CODE0, + FLASH_ERASE_CODE1}; + + logError(0, "%s Command full erase sent...\n", + tag); + if (fts_writeCmd(cmd, sizeof(cmd)) < 0) { + logError(1, "%s %s:ERROR % 02X\n", tag, __func__, ERROR_I2C_W); return ERROR_I2C_W; } status = wait_for_flash_ready(FLASH_ERASE_CODE0); if (status != OK) { - logError(1, "%s flash_full_erase: ERROR % 02X\n", tag, ERROR_FLASH_NOT_READY); + logError(1, "%s %s:ERROR % 02X\n", + tag, __func__, ERROR_FLASH_NOT_READY); + //Flash not ready within the chosen time, + //better exit! return (status | ERROR_FLASH_NOT_READY); - /* Flash not ready within the chosen time, better exit! */ } logError(0, "%s Full Erase flash DONE!\n", tag); return OK; +} + +int flash_erase_page_by_page(int keep_cx) +{ + u8 status, i = 0; + //write the command to erase the flash + u8 cmd[4] = {FLASH_CMD_WRITE_REGISTER, FLASH_ERASE_CODE0, 0x00, 0x00}; + + for (i = 0; i < FLASH_NUM_PAGE; i++) { + if (i >= FLASH_CX_PAGE_START && i <= FLASH_CX_PAGE_END + && keep_cx == 1) { + logError(0, "%s Skipping erase page %d!\n", tag, i); + continue; + } + cmd[2] = (0x3F & i) | FLASH_ERASE_START; + logError(0, "Command erase page %d sent", i); + logError(0, "%s:%02X %02X %02X %02X\n", + tag, i, cmd[0], cmd[1], cmd[2], cmd[3]); + if (fts_writeCmd(cmd, sizeof(cmd)) < 0) { + logError(1, + "%s %s:ERROR % 08X\n", + tag, __func__, ERROR_I2C_W); + return ERROR_I2C_W; + } + status = wait_for_flash_ready(FLASH_ERASE_CODE0); + if (status != OK) { + logError(1, "%s %s:ERROR % 08X\n", + tag, __func__, ERROR_FLASH_NOT_READY); + //Flash not ready within the chosen time, + //better exit! + return (status | ERROR_FLASH_NOT_READY); + } + } + + logError(0, "%s Erase flash page by page DONE!\n", tag); + + return OK; } int start_flash_dma(void) { int status; - u8 cmd[3] = {FLASH_CMD_WRITE_REGISTER, FLASH_DMA_CODE0, FLASH_DMA_CODE1}; - /* write the command to erase the flash */ + //write the command to erase the flash + u8 cmd[3] = {FLASH_CMD_WRITE_REGISTER, FLASH_DMA_CODE0, + FLASH_DMA_CODE1}; logError(0, "%s Command flash DMA ...\n", tag); - if (fts_writeCmd(cmd, sizeof (cmd)) < 0) { - logError(1, "%s start_flash_dma: ERROR % 02X\n", tag, ERROR_I2C_W); + if (fts_writeCmd(cmd, sizeof(cmd)) < 0) { + logError(1, "%s %s: ERROR % 02X\n", + tag, __func__, ERROR_I2C_W); return ERROR_I2C_W; } status = wait_for_flash_ready(FLASH_DMA_CODE0); if (status != OK) { - logError(1, "%s start_flash_dma: ERROR % 02X\n", tag, ERROR_FLASH_NOT_READY); + logError(1, "%s %s: ERROR % 02X\n", + tag, __func__, ERROR_FLASH_NOT_READY); + //Flash not ready within the chosen time, better exit! return (status | ERROR_FLASH_NOT_READY); - /* Flash not ready within the chosen time, better exit! */ } logError(0, "%s flash DMA DONE!\n", tag); @@ -833,7 +905,6 @@ int start_flash_dma(void) int fillFlash(u32 address, u8 *data, int size) { - int remaining = size; int toWrite = 0; int byteBlock = 0; @@ -841,26 +912,29 @@ int fillFlash(u32 address, u8 *data, int size) u32 addr = 0; int res; int delta; + u8 *buff = NULL; + u8 buff2[9] = {0}; + - u8 *buff = (u8 *) kmalloc((DMA_CHUNK + 3) * sizeof (u8), GFP_KERNEL); + buff = (u8 *)kmalloc_array((DMA_CHUNK + 3), sizeof(u8), GFP_KERNEL); if (buff == NULL) { - logError(1, "%s fillFlash: ERROR %02X\n", tag, ERROR_ALLOC); + logError(1, "%s %s: ERROR %02X\n", tag, __func__, ERROR_ALLOC); return ERROR_ALLOC; } while (remaining > 0) { - byteBlock = 0; + byteBlock = 0; addr = 0; while (byteBlock < FLASH_CHUNK && remaining > 0) { buff[0] = FLASH_CMD_WRITE_64K; if (remaining >= DMA_CHUNK) { if ((byteBlock + DMA_CHUNK) <= FLASH_CHUNK) { - /* logError(1, "%s fillFlash: 1\n", tag); */ + //logError(1, "%s fillFlash:1\n", tag); toWrite = DMA_CHUNK; remaining -= DMA_CHUNK; byteBlock += DMA_CHUNK; } else { - /* logError(1, "%s fillFlash: 2\n", tag); */ + //logError(1, "%s fillFlash:2\n", tag); delta = FLASH_CHUNK - byteBlock; toWrite = delta; remaining -= delta; @@ -868,13 +942,12 @@ int fillFlash(u32 address, u8 *data, int size) } } else { if ((byteBlock + remaining) <= FLASH_CHUNK) { - /* logError(1, "%s fillFlash: 3\n", tag); */ + //logError(1, "%s fillFlash:3\n", tag); toWrite = remaining; - byteBlock += remaining; + byteBlock += remaining; remaining = 0; - } else { - /* logError(1, "%s fillFlash: 4\n", tag); */ + //logError(1, "%s fillFlash:4\n", tag); delta = FLASH_CHUNK - byteBlock; toWrite = delta; remaining -= delta; @@ -885,187 +958,195 @@ int fillFlash(u32 address, u8 *data, int size) buff[1] = (u8) ((addr & 0x0000FF00) >> 8); buff[2] = (u8) (addr & 0x000000FF); memcpy(&buff[3], data, toWrite); + //logError(0, + //"%s Command = %02X, address = %02X %02X, + //bytes = %d, data = %02X %02X, %02X %02X\n", + //tag, buff[0], buff[1], buff[2], toWrite, + //buff[3], buff[4], buff[3 + toWrite-2], + //buff[3 + toWrite-1]); if (fts_writeCmd(buff, 3 + toWrite) < 0) { - logError(1, "%s fillFlash: ERROR %02X\n", tag, ERROR_I2C_W); + logError(1, "%s %s: ERROR %02X\n", + tag, __func__, ERROR_I2C_W); + kfree(buff); return ERROR_I2C_W; } addr += toWrite; data += toWrite; } - - kfree(buff); - - /* configuring the DMA */ + //configuring the DMA byteBlock = byteBlock / 4 - 1; - buff = (u8 *) kmalloc((9) * sizeof (u8), GFP_KERNEL); - buff[0] = FLASH_CMD_WRITE_REGISTER; - buff[1] = FLASH_DMA_CONFIG; - buff[2] = 0x00; - buff[3] = 0x00; - - addr = address + ((wheel * FLASH_CHUNK)/4); - buff[4] = (u8) ((addr & 0x000000FF)); - buff[5] = (u8) ((addr & 0x0000FF00) >> 8); - buff[6] = (u8) (byteBlock & 0x000000FF); - buff[7] = (u8) ((byteBlock & 0x0000FF00) >> 8); - buff[8] = 0x00; - - logError(0, "%s Command = %02X , address = %02X %02X, words = %02X %02X\n", tag, buff[0], buff[5], buff[4], buff[7], buff[6]); - if (fts_writeCmd(buff, 9) < OK) { - logError(1, "%s Error during filling Flash! ERROR %02X\n", tag, ERROR_I2C_W); + buff2[0] = FLASH_CMD_WRITE_REGISTER; + buff2[1] = FLASH_DMA_CONFIG; + buff2[2] = 0x00; + buff2[3] = 0x00; + + addr = address + ((wheel * FLASH_CHUNK)/4); + buff2[4] = (u8) ((addr & 0x000000FF)); + buff2[5] = (u8) ((addr & 0x0000FF00) >> 8); + buff2[6] = (u8) (byteBlock & 0x000000FF); + buff2[7] = (u8) ((byteBlock & 0x0000FF00) >> 8); + buff2[8] = 0x00; + + logError(0, "%s:Command:%02X, address:%02X %02X, ", + tag, buff2[0], buff2[5], buff2[4]); + logError(0, "words:%02X %02X\n", buff2[7], buff2[6]); + if (fts_writeCmd(buff2, 9) < OK) { + logError(1, "%s Error during filling Flash!:%02X\n", + tag, ERROR_I2C_W); + kfree(buff); return ERROR_I2C_W; } - - /* msleep(FLASH_WAIT_TIME); */ + //mdelay(FLASH_WAIT_TIME); res = start_flash_dma(); if (res < OK) { - logError(1, "%s Error during flashing DMA! ERROR %02X\n", tag, res); + logError(1, "%s Error during flashing DMA!:%02X\n", + tag, res); + kfree(buff); return res; } wheel++; } + kfree(buff); return OK; } -int flash_burn(Firmware fw, int force_burn) +int flash_burn(struct Firmware fw, int force_burn, int keep_cx) { int res; if (!force_burn) { - for (res = EXTERNAL_RELEASE_INFO_SIZE-1; res >= 0; res--) { - if (fw.externalRelease[res] > ftsInfo.u8_extReleaseInfo[res]) - goto start; - } - logError(1, "%s flash_burn: Firmware in the chip newer or equal to the one to burn! NO UPDATE ERROR %02X\n", tag, ERROR_FW_NO_UPDATE); + for (res = EXTERNAL_RELEASE_INFO_SIZE-1; res >= 0; res--) { + if (fw.externalRelease[res] > + ftsInfo.u8_extReleaseInfo[res]) + goto start; + } + logError(1, "Firmware in the chip newer or "); + logError(1, "equal to the one to burn!"); + logError(1, "%s %s:NO UPDATE ERROR %02X\n", + tag, __func__, ERROR_FW_NO_UPDATE); return (ERROR_FW_NO_UPDATE | ERROR_FLASH_BURN_FAILED); } - /* programming procedure start */ + //programming procedure start start: logError(0, "%s Programming Procedure for flashing started:\n\n", tag); logError(0, "%s 1) SYSTEM RESET:\n", tag); res = fts_system_reset(); if (res < 0) { - logError(1, "%s system reset FAILED!\n", tag); + logError(1, "%s system reset FAILED!\n", tag); + /** + * if there is no firmware i will not + * get the controller ready event and + * there will be a timeout but i can + * keep going, but if there is an I2C + * error i have to exit + */ if (res != (ERROR_SYSTEM_RESET_FAIL | ERROR_TIMEOUT)) - /* if there is no firmware i will not get the controller - *ready event and there will be a timeout but i can keep going, - *but if there is an I2C error i have to exit - */ return (res | ERROR_FLASH_BURN_FAILED); } else - logError(0, "%s system reset COMPLETED!\n\n", tag); + logError(0, "%s system reset COMPLETED!\n\n", tag); logError(0, "%s 2) WARM BOOT:\n", tag); res = fts_warm_boot(); if (res < OK) { - logError(1, "%s warm boot FAILED!\n", tag); - return (res | ERROR_FLASH_BURN_FAILED); - } else - logError(0, "%s warm boot COMPLETED!\n\n", tag); + logError(1, "%s warm boot FAILED!\n", tag); + return (res | ERROR_FLASH_BURN_FAILED); + } /*else*/ + logError(0, "%s warm boot COMPLETED!\n\n", tag); - /* msleep(FLASH_WAIT_TIME); */ + //mdelay(FLASH_WAIT_TIME); logError(0, "%s 3) FLASH UNLOCK:\n", tag); res = flash_unlock(); if (res < OK) { - logError(1, "%s flash unlock FAILED! ERROR %02X\n", tag, ERROR_FLASH_BURN_FAILED); + logError(1, "%s flash unlock FAILED! ERROR %02X\n", + tag, ERROR_FLASH_BURN_FAILED); return (res | ERROR_FLASH_BURN_FAILED); } - logError(0, "%s flash unlock COMPLETED!\n\n", tag); + logError(0, "%s flash unlock COMPLETED!\n\n", tag); - /* msleep(200); */ + //mdelay(200); logError(0, "%s 4) FLASH ERASE UNLOCK:\n", tag); res = flash_erase_unlock(); if (res < 0) { - logError(1, "%s flash unlock FAILED! ERROR %02X\n", tag, ERROR_FLASH_BURN_FAILED); + logError(1, "%s flash unlock FAILED! ERROR %02X\n", + tag, ERROR_FLASH_BURN_FAILED); return (res | ERROR_FLASH_BURN_FAILED); } - logError(0, "%s flash unlock COMPLETED!\n\n", tag); + logError(0, "%s flash unlock COMPLETED!\n\n", tag); - /* msleep(FLASH_WAIT_TIME); */ + //mdelay(FLASH_WAIT_TIME); logError(0, "%s 5) FLASH ERASE:\n", tag); - res = flash_full_erase(); + if (keep_cx == 1) + res = flash_erase_page_by_page(keep_cx); + else + res = flash_full_erase(); if (res < 0) { - logError(1, "%s flash erase FAILED! ERROR %02X\n", tag, ERROR_FLASH_BURN_FAILED); + logError(1, "%s flash erase FAILED! ERROR %02X\n", + tag, ERROR_FLASH_BURN_FAILED); return (res | ERROR_FLASH_BURN_FAILED); } - logError(0, "%s flash erase COMPLETED!\n\n", tag); + logError(0, "%s flash erase COMPLETED!\n\n", tag); + - /* msleep(FLASH_WAIT_TIME); */ + //mdelay(FLASH_WAIT_TIME); logError(0, "%s 6) LOAD PROGRAM:\n", tag); - res = fillFlash(FLASH_ADDR_CODE, &fw.data[0], fw.sec0_size); + res = fillFlash(FLASH_ADDR_CODE, &fw.data[0], + fw.sec0_size); if (res < OK) { - logError(1, "%s load program ERROR %02X\n", tag, ERROR_FLASH_BURN_FAILED); + logError(1, "%s load program ERROR %02X\n", + tag, ERROR_FLASH_BURN_FAILED); return (res | ERROR_FLASH_BURN_FAILED); } logError(1, "%s load program DONE!\n", tag); - logError(0, "%s 7) LOAD CONFIG:\n", tag); - res = fillFlash(FLASH_ADDR_CONFIG, &(fw.data[fw.sec0_size]), fw.sec1_size); + res = fillFlash(FLASH_ADDR_CONFIG, + &(fw.data[fw.sec0_size]), fw.sec1_size); if (res < OK) { - logError(1, "%s load config ERROR %02X\n", tag, ERROR_FLASH_BURN_FAILED); + logError(1, "%s load config ERROR %02X\n", + tag, ERROR_FLASH_BURN_FAILED); return (res | ERROR_FLASH_BURN_FAILED); } - logError(1, "%s load config DONE!\n", tag); + logError(1, "%s load config DONE!\n", tag); logError(0, "%s Flash burn COMPLETED!\n\n", tag); logError(0, "%s 8) SYSTEM RESET:\n", tag); res = fts_system_reset(); if (res < 0) { - logError(1, "%s system reset FAILED! ERROR %02X\n", tag, ERROR_FLASH_BURN_FAILED); + logError(1, "%s system reset FAILED! ERROR %02X\n", + tag, ERROR_FLASH_BURN_FAILED); return (res | ERROR_FLASH_BURN_FAILED); } logError(0, "%s system reset COMPLETED!\n\n", tag); + logError(0, "%s 9) FINAL CHECK:\n", tag); res = readChipInfo(0); if (res < 0) { - logError(1, "%s flash_burn: Unable to retrieve Chip INFO! ERROR %02X\n", tag, ERROR_FLASH_BURN_FAILED); + logError(1, "%s %s:Unable to retrieve Chip INFO!:%02X\n", + tag, __func__, ERROR_FLASH_BURN_FAILED); return (res | ERROR_FLASH_BURN_FAILED); } for (res = 0; res < EXTERNAL_RELEASE_INFO_SIZE; res++) { + ////external release is prined during readChipInfo if (fw.externalRelease[res] != ftsInfo.u8_extReleaseInfo[res]) { - /* external release is prined during readChipInfo */ - logError(1, "%s Firmware in the chip different from the one that was burn! fw: %x != %x , conf: %x != %x\n", tag, ftsInfo.u16_fwVer, fw.fw_ver, ftsInfo.u16_cfgId, fw.config_id); - return ERROR_FLASH_BURN_FAILED; + pr_err("Firmware in the chip different from"); + pr_err(" the one that was burn!"); + logError(1, "%s fw: %x != %x, conf: %x != %x\n", + tag, ftsInfo.u16_fwVer, fw.fw_ver, + ftsInfo.u16_cfgId, fw.config_id); + return ERROR_FLASH_BURN_FAILED; } } - logError(0, "%s Final check OK! fw: %02X, conf: %02X\n", tag, ftsInfo.u16_fwVer, ftsInfo.u16_cfgId); + logError(0, "%s Final check OK! fw: %02X , conf: %02X\n", + tag, ftsInfo.u16_fwVer, ftsInfo.u16_cfgId); return OK; } -int flashProcedure(const char *path, int force, int keep_cx) -{ - Firmware fw; - int res; - - fw.data = NULL; - logError(0, "%s Reading Fw file...\n", tag); - res = readFwFile(path, &fw, keep_cx); - if (res < OK) { - logError(1, "%s flashProcedure: ERROR %02X\n", tag, (res | ERROR_FLASH_PROCEDURE)); - kfree(fw.data); - return (res | ERROR_FLASH_PROCEDURE); - } - logError(0, "%s Fw file read COMPLETED!\n", tag); - - logError(0, "%s Starting flashing procedure...\n", tag); - res = flash_burn(fw, force); - if (res < OK && res != (ERROR_FW_NO_UPDATE | ERROR_FLASH_BURN_FAILED)) { - logError(1, "%s flashProcedure: ERROR %02X\n", tag, ERROR_FLASH_PROCEDURE); - kfree(fw.data); - return (res | ERROR_FLASH_PROCEDURE); - } - logError(0, "%s flashing procedure Finished!\n", tag); - kfree(fw.data); - return res; -} - #endif diff --git a/drivers/input/touchscreen/st/fts_lib/ftsFlash.h b/drivers/input/touchscreen/st/fts_lib/ftsFlash.h index 69635e07a9f4..8872e9ad2905 100644 --- a/drivers/input/touchscreen/st/fts_lib/ftsFlash.h +++ b/drivers/input/touchscreen/st/fts_lib/ftsFlash.h @@ -1,47 +1,72 @@ /* + * FTS Capacitive touch screen controller (FingerTipS) + * + * Copyright (C) 2016-2018, STMicroelectronics Limited. + * Authors: AMG(Analog Mems Group) + * + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + */ -************************************************************************** -** STMicroelectronics ** -************************************************************************** -** marco.cali@st.com ** -************************************************************************** -* * -* FTS API for Flashing the IC * -* * -************************************************************************** -************************************************************************** +/** + * + ************************************************************************** + ** STMicroelectronics ** + ************************************************************************** + ** marco.cali@st.com ** + ************************************************************************** + * * + * FTS API for Flashing the IC * + * * + ************************************************************************** + ************************************************************************** + * + */ + +#ifndef __FTS_FLASH_H +#define __FTS_FLASH_H -*/ #include "ftsSoftware.h" -/* Flash possible status */ -#define FLASH_READY 0 -#define FLASH_BUSY 1 -#define FLASH_UNKNOWN -1 +//Flash possible status +#define FLASH_READY 0 +#define FLASH_BUSY 1 +#define FLASH_UNKNOWN -1 +#define FLASH_STATUS_BYTES 1 -#define FLASH_STATUS_BYTES 1 -/* Flash timing parameters */ -#define FLASH_RETRY_COUNT 1000 -#define FLASH_WAIT_BEFORE_RETRY 50 /* ms */ +//Flash timing parameters +#define FLASH_RETRY_COUNT 1000 +#define FLASH_WAIT_BEFORE_RETRY 50 //ms +#define FLASH_WAIT_TIME 200 //ms -#define FLASH_WAIT_TIME 200 /* ms */ -/* PATHS FW FILES */ -/* #define PATH_FILE_FW "fw.memh" */ +//PATHS FW FILES +//#define PATH_FILE_FW "fw.memh" #ifdef FTM3_CHIP -#define PATH_FILE_FW "st_fts.bin" +#define PATH_FILE_FW "st_fts.bin" #else -#define PATH_FILE_FW "st_fts.ftb" /* new bin file structure */ +#define PATH_FILE_FW "st_fts.ftb"//new bin file structure #endif #ifndef FTM3_CHIP -#define FLASH_CHUNK (64*1024) -#define DMA_CHUNK 32 +#define FLASH_CHUNK (64 * 1024) +#define DMA_CHUNK (2 * 1024) #endif -typedef struct { + +struct Firmware { u8 *data; u16 fw_ver; u16 config_id; @@ -53,20 +78,19 @@ typedef struct { u32 sec2_size; u32 sec3_size; #endif -} Firmware; +}; #ifdef FTM3_CHIP int flash_status(void); int flash_status_ready(void); int wait_for_flash_ready(void); -int parseBinFile(const char *pathToFile, u8 **data, int *length, int dimension); -/* int parseMemhFile(const char* pathToFile, u8** data, int* length, int dimension); */ #else int wait_for_flash_ready(u8 type); int fts_warm_boot(void); -int parseBinFile(const char *pathToFile, Firmware *fw, int keep_cx); int flash_erase_unlock(void); int flash_full_erase(void); +int flash_erase_page_by_page(int keep_cx); +//int flash_erase_page_by_page_info(int page); int start_flash_dma(void); int fillFlash(u32 address, u8 *data, int size); #endif @@ -74,6 +98,10 @@ int fillFlash(u32 address, u8 *data, int size); int flash_unlock(void); int fillMemory(u32 address, u8 *data, int size); int getFirmwareVersion(u16 *fw_vers, u16 *config_id); -int readFwFile(const char *path, Firmware *fw, int keep_cx); -int flash_burn(Firmware fw, int force_burn); +int getFWdata(const char *pathToFile, u8 **data, int *size, int from); +int parseBinFile(u8 *fw_data, int fw_size, struct Firmware *fw, int keep_cx); +int readFwFile(const char *path, struct Firmware *fw, int keep_cx); +int flash_burn(struct Firmware fw, int force_burn, int keep_cx); int flashProcedure(const char *path, int force, int keep_cx); + +#endif diff --git a/drivers/input/touchscreen/st/fts_lib/ftsFrame.c b/drivers/input/touchscreen/st/fts_lib/ftsFrame.c index c502559319a0..7e6d51c064be 100644 --- a/drivers/input/touchscreen/st/fts_lib/ftsFrame.c +++ b/drivers/input/touchscreen/st/fts_lib/ftsFrame.c @@ -1,27 +1,36 @@ /* - -************************************************************************** -** STMicroelectronics ** -************************************************************************** -** marco.cali@st.com ** -************************************************************************** -* * -* FTS functions for getting frames * -* * -************************************************************************** -************************************************************************** - -*/ - -#include "ftsCrossCompile.h" -#include "ftsCompensation.h" -#include "ftsError.h" -#include "ftsFrame.h" -#include "ftsHardware.h" -#include "ftsIO.h" -#include "ftsSoftware.h" -#include "ftsTool.h" -#include "ftsTime.h" + * FTS Capacitive touch screen controller (FingerTipS) + * + * Copyright (C) 2016-2018, STMicroelectronics Limited. + * Authors: AMG(Analog Mems Group) + * + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + */ + +/** + * + ************************************************************************** + ** STMicroelectronics ** + ************************************************************************** + ** marco.cali@st.com ** + ************************************************************************** + * * + * FTS functions for getting frames * + * * + ************************************************************************** + ************************************************************************** + */ #include #include @@ -47,69 +56,88 @@ #include #include #include -/* #include */ +//#include + +#include "ftsCrossCompile.h" +#include "ftsCompensation.h" +#include "ftsError.h" +#include "ftsFrame.h" +#include "ftsHardware.h" +#include "ftsIO.h" +#include "ftsSoftware.h" +#include "ftsTool.h" +#include "ftsTime.h" +#include "../fts.h" static char tag[8] = "[ FTS ]\0"; static int sense_len, force_len; -/*int getOffsetFrame(u16 address, u16 *offset) +int getOffsetFrame(u16 address, u16 *offset) { - u8 data[2]; u8 cmd = { FTS_CMD_FRAMEBUFFER_R }; + char *temp = NULL; - if (readCmdU16(cmd, address, data, OFFSET_LENGTH, DUMMY_FRAMEBUFFER) < 0) { - logError(1, "%s getOffsetFrame: ERROR %02X\n", tag, ERROR_I2C_R); + if (readCmdU16(cmd, address, data, OFFSET_LENGTH, + DUMMY_FRAMEBUFFER) < 0) { + logError(1, "%s %S: ERROR %02X\n", tag, __func__, ERROR_I2C_R); return ERROR_I2C_R; } - else { - u8ToU16(data, offset); - logError(0, "%s %s", tag, printHex("Offest = ", data, OFFSET_LENGTH)); - return OK; - } -}*/ + u8ToU16(data, offset); + temp = printHex("Offest = ", data, OFFSET_LENGTH); + if (temp != NULL) + logError(0, "%s %s", tag, temp); + kfree(temp); + return OK; +} int getChannelsLength(void) { - int ret; - u8 *data = (u8 *)kmalloc(2*sizeof(u8), GFP_KERNEL); + u8 *data = (u8 *)kmalloc_array(2, sizeof(u8), GFP_KERNEL); if (data == NULL) { - logError(1, "%s getChannelsLength: ERROR %02X\n", tag, ERROR_ALLOC); + logError(1, "%s %s: ERROR %02X\n", + tag, __func__, ERROR_ALLOC); return ERROR_ALLOC; } ret = readB2(ADDR_SENSE_LEN, data, 2); if (ret < OK) { - logError(1, "%s getChannelsLength: ERROR %02X\n", tag, ERROR_READ_B2); - return (ret|ERROR_READ_B2); + logError(1, "%s %s: ERROR %02X\n", + tag, __func__, ERROR_READ_B2); + kfree(data); + return (ret|ERROR_READ_B2); } sense_len = (int)data[0]; force_len = (int)data[1]; - logError(0, "%s Force_len = %d Sense_Len = %d\n", tag, force_len, sense_len); - + logError(0, "%s Force_len = %d Sense_Len = %d\n", + tag, force_len, sense_len); kfree(data); return OK; } + int getFrameData(u16 address, int size, short **frame) { int i, j, ret; - u8 *data = (u8 *)kmalloc(size*sizeof(u8), GFP_KERNEL); + u8 *data = (u8 *)kmalloc_array(size, sizeof(u8), GFP_KERNEL); + if (data == NULL) { - logError(1, "%s getFrameData: ERROR %02X\n", tag, ERROR_ALLOC); + logError(1, "%s %s: ERROR %02X\n", + tag, __func__, ERROR_ALLOC); return ERROR_ALLOC; } - - ret = readCmdU16(FTS_CMD_FRAMEBUFFER_R, address, data, size, DUMMY_FRAMEBUFFER); + ret = readCmdU16(FTS_CMD_FRAMEBUFFER_R, address, + data, size, DUMMY_FRAMEBUFFER); if (ret < OK) { - logError(1, "%s getFrameData: ERROR %02X\n", tag, ERROR_I2C_R); - kfree(data); + logError(1, "%s %s: ERROR %02X\n", + tag, __func__, ERROR_I2C_R); + kfree(data); return ERROR_I2C_R; } j = 0; @@ -121,238 +149,111 @@ int getFrameData(u16 address, int size, short **frame) return OK; } -/*int getMSFrame(u16 type, short **frame, int keep_first_row) + +int getMSFrame(u16 type, struct MutualSenseFrame *frame, int keep_first_row) { u16 offset; - int size, ret; + int ret; if (getSenseLen() == 0 || getForceLen() == 0) { - ret=getChannelsLength(); - if (retdata.header.sense_node) - size = data.header.force_node; - else - size = data.header.sense_node; - - *frame = (short*)kmalloc(size*sizeof(short), GFP_KERNEL); - if (frame == NULL) { - logError(1, "%s getMSKeyFrame: ERROR %02X\n", tag, ERROR_ALLOC); - return ERROR_ALLOC; - } - - ret = getFrameData(offset, size*BYTES_PER_NODE, frame); - if (retnode_data_size = ((force_len + 1) * sense_len); + frame->header.force_node = force_len + 1; + } else { + frame->node_data_size = ((force_len) * sense_len); + offset += (sense_len * BYTES_PER_NODE); + frame->header.force_node = force_len; } - } - - switch (type) { - case ADDR_RAW_HOVER_FORCE: - case ADDR_FILTER_HOVER_FORCE: - case ADDR_NORM_HOVER_FORCE: - case ADDR_CALIB_HOVER_FORCE: - case ADDR_RAW_PRX_FORCE: - case ADDR_FILTER_PRX_FORCE: - case ADDR_NORM_PRX_FORCE: - case ADDR_CALIB_PRX_FORCE: - size = ((force_len)* 1); + frame->header.sense_node = sense_len; break; - - case ADDR_RAW_HOVER_SENSE: - case ADDR_FILTER_HOVER_SENSE: - case ADDR_NORM_HOVER_SENSE: - case ADDR_CALIB_HOVER_SENSE: - case ADDR_RAW_PRX_SENSE: - case ADDR_FILTER_PRX_SENSE: - case ADDR_NORM_PRX_SENSE: - case ADDR_CALIB_PRX_SENSE: - size = ((1)*sense_len); + case ADDR_NORM_MS_KEY: + case ADDR_RAW_MS_KEY: + frame->header.force_node = 1; + frame->header.sense_node = ftsInfo.u8_msKeyLen; + frame->node_data_size = ftsInfo.u8_msKeyLen; break; - default: - logError(1, "%s getSSFrame: ERROR % 02X\n", tag, ERROR_OP_NOT_ALLOW); + logError(1, "%s %s: ERROR % 02X\n", + tag, __func__, ERROR_OP_NOT_ALLOW); return ERROR_OP_NOT_ALLOW; - } - - ret = getOffsetFrame(type, &offset); - if (retnode_data = (short *)kmalloc_array(frame->node_data_size, + sizeof(short), GFP_KERNEL); + if (frame->node_data == NULL) { + logError(1, "%s %s: ERROR %02X\n", + tag, __func__, ERROR_ALLOC); return ERROR_ALLOC; } - ret = getFrameData(offset, size*BYTES_PER_NODE, frame); - if (retnode_data_size * BYTES_PER_NODE, + &(frame->node_data)); + if (ret < OK) { + logError(1, "%s %s: ERROR %02X\n", + tag, __func__, ERROR_GET_FRAME_DATA); + kfree(frame->node_data); return (ret | ERROR_GET_FRAME_DATA); } - + // if you want to access one node i,j, + //you should compute the offset like: + //offset = i * columns + j => frame[i, j] logError(0, "%s Frame acquired!\n", tag); - return size; - + //return the number of data put inside frame + return frame->node_data_size; } -int getNmsFrame(u16 type, short ***frames, int *size, int keep_first_row, int fs, int n) { - int i; - StopWatch global, local; - int temp; - - *frames = (short **)kmalloc(n*sizeof(short *), GFP_KERNEL); - - if (*frames == NULL) { - logError(1, "%s getNmsFrame: ERROR %02X\n", tag, ERROR_ALLOC); - return ERROR_ALLOC; - } - - fs = (1*1000 / fs) ; - - startStopWatch(&global); - for (i = 0; i < n; i++) { - - startStopWatch(&local); - - *size = getMSFrame(type, ((*frames)+i), keep_first_row); - if (*size < OK) { - logError(1, "%s getNFrame: getFrame failed\n",tag); - return *size; - } - - stopStopWatch(&local); - temp = elapsedMillisecond(&local); - logError(0, "%s Iteration %d performed in %d ms... the process wait for %ld ms\n\n", tag, i, temp, (unsigned long)(fs - temp)); - - if (temp < fs) - msleep((unsigned long)(fs - temp)); - - } - - stopStopWatch(&global); - temp = elapsedMillisecond(&global); - logError(0, "%s Global Iteration performed in %d ms\n", tag, temp); - temp /= n; - logError(0, "%s Mean Iteration performed in %d ms\n", tag, temp); - return (1000 / (temp)); - -}*/ - int getSenseLen(void) { int ret; + if (sense_len != 0) return sense_len; - ret = getChannelsLength(); - if (ret < OK) - return ret; - else - return sense_len; + + if (ftsInfo.u8_scrSenseLen != 0) { + sense_len = ftsInfo.u8_scrSenseLen; + } else { + ret = getChannelsLength(); + if (ret < OK) + return ret; + } + return sense_len; } int getForceLen(void) { int ret; + if (force_len != 0) return force_len; - ret = getChannelsLength(); - if (ret < OK) - return ret; - else - return force_len; + + if (ftsInfo.u8_scrForceLen != 0) { + force_len = ftsInfo.u8_scrForceLen; + } else { + ret = getChannelsLength(); + if (ret < OK) + return ret; + } + return force_len; } int requestFrame(u16 type) @@ -360,70 +261,87 @@ int requestFrame(u16 type) int retry = 0; int ret; u16 answer; + char *temp = NULL; int event_to_search[1]; u8 readEvent[FIFO_EVENT_SIZE]; - u8 cmd[3] = { FTS_CMD_REQU_FRAME_DATA, 0x00, 0x00 }; - /* B7 is the command for asking frame data */ + u8 cmd[3] = { FTS_CMD_REQU_FRAME_DATA, 0x00, 0x00}; + // B7 is the command for asking frame data event_to_search[0] = (int)EVENTID_FRAME_DATA_READ; + u16ToU8(type, &cmd[1]); while (retry < FRAME_DATA_READ_RETRY) { - logError(0, "%s %s", tag, printHex("Command = ", cmd, 3)); + temp = printHex("Command = ", cmd, 3); + if (temp != NULL) + logError(0, "%s %s", tag, temp); + kfree(temp); + + //send the request to the chip to load in memory the Frame Data ret = fts_writeFwCmd(cmd, 3); - /* send the request to the chip to load in memory the Frame Data */ if (ret < OK) { - logError(1, "%s requestFrame: ERROR %02X\n", tag, ERROR_I2C_W); + logError(1, "%s %s: ERROR %02X\n", + tag, __func__, ERROR_I2C_W); return ERROR_I2C_W; } - ret = pollForEvent(event_to_search, 1, readEvent, TIMEOUT_REQU_COMP_DATA); + ret = pollForEvent(event_to_search, + 1, + readEvent, + TIMEOUT_REQU_COMP_DATA); if (ret < OK) { - logError(0, "%s Event did not Found at %d attemp!\n", tag, retry + 1); + logError(0, "%s Event did not Found at %d attemp!\n", + tag, retry + 1); retry += 1; } else { retry = 0; break; } } - if (retry == FRAME_DATA_READ_RETRY) { - logError(1, "%s requestFrame: ERROR %02X\n", tag, ERROR_TIMEOUT); + logError(1, "%s %s: ERROR %02X\n", + tag, __func__, ERROR_TIMEOUT); return ERROR_TIMEOUT; } - u8ToU16_le(&readEvent[1], &answer); if (answer == type) return OK; - logError(1, "%s The event found has a different type of Frame data ERROR %02X\n", tag, ERROR_DIFF_COMP_TYPE); + + logError(1, "%s The event found has a different type of ", tag); + logError(1, "Frame data:%02X\n", ERROR_DIFF_COMP_TYPE); return ERROR_DIFF_COMP_TYPE; } -int readFrameDataHeader(u16 type, DataHeader *header) -{ +int readFrameDataHeader(u16 type, struct DataHeader *header) +{ u16 offset = ADDR_FRAMEBUFFER_DATA; u16 answer; u8 data[FRAME_DATA_HEADER]; - if (readCmdU16(FTS_CMD_FRAMEBUFFER_R, offset, data, FRAME_DATA_HEADER, DUMMY_FRAMEBUFFER) < 0) { - logError(1, "%s readFrameDataHeader: ERROR %02X\n", tag, ERROR_I2C_R); + if (readCmdU16(FTS_CMD_FRAMEBUFFER_R, offset, data, + FRAME_DATA_HEADER, DUMMY_FRAMEBUFFER) < 0) { + logError(1, "%s %s: ERROR %02X\n", + tag, __func__, ERROR_I2C_R); return ERROR_I2C_R; } logError(0, "%s Read Data Header done!\n", tag); if (data[0] != FRAME_HEADER_SIGNATURE) { - logError(1, "%s readFrameDataHeader: ERROR %02X The Header Signature was wrong! %02X != %02X\n", tag, ERROR_WRONG_COMP_SIGN, data[0], HEADER_SIGNATURE); + logError(1, "%s %s %02X Wrong Header Signature !%02X != %02X\n", + tag, __func__, ERROR_WRONG_COMP_SIGN, data[0], + HEADER_SIGNATURE); return ERROR_WRONG_COMP_SIGN; } u8ToU16_le(&data[1], &answer); if (answer != type) { - logError(1, "%s readFrameDataHeader: ERROR %02X\n", tag, ERROR_DIFF_COMP_TYPE); + logError(1, "%s %s: ERROR %02X\n", + tag, __func__, ERROR_DIFF_COMP_TYPE); return ERROR_DIFF_COMP_TYPE; } @@ -434,28 +352,34 @@ int readFrameDataHeader(u16 type, DataHeader *header) header->sense_node = (int)data[5]; return OK; - } -int getMSFrame2(u16 type, MutualSenseFrame *frame) +int getMSFrame2(u16 type, struct MutualSenseFrame *frame) { u16 offset = ADDR_FRAMEBUFFER_DATA+FRAME_DATA_HEADER; int size, ret; - if (!(type == MS_TOUCH_ACTIVE || type == MS_TOUCH_LOW_POWER || type == MS_TOUCH_ULTRA_LOW_POWER || type == MS_KEY)) { - logError(1, "%s getMSFrame: Choose a MS type of frame data ERROR %02X\n", tag, ERROR_OP_NOT_ALLOW); + frame->node_data = NULL; + + if (!(type == MS_TOUCH_ACTIVE || type == MS_TOUCH_LOW_POWER + || type == MS_TOUCH_ULTRA_LOW_POWER + || type == MS_KEY)) { + logError(1, "%s %s:Choose a MS type of frame data ERROR %02X\n", + tag, __func__, ERROR_OP_NOT_ALLOW); return ERROR_OP_NOT_ALLOW; } ret = requestFrame(type); if (ret < 0) { - logError(1, "%s readMutualSenseCompensationData: ERROR %02X\n", tag, ERROR_REQU_COMP_DATA); + logError(1, "%s readMutualSenseCompensation:ERROR %02X\n", + tag, ERROR_REQU_COMP_DATA); return (ret | ERROR_REQU_COMP_DATA); } ret = readFrameDataHeader(type, &(frame->header)); if (ret < 0) { - logError(1, "%s readMutualSenseCompensationData: ERROR %02X\n", tag, ERROR_COMP_DATA_HEADER); + logError(1, "%s readMutualSenseCompensationData:ERROR %02X\n", + tag, ERROR_COMP_DATA_HEADER); return (ret | ERROR_COMP_DATA_HEADER); } @@ -463,62 +387,74 @@ int getMSFrame2(u16 type, MutualSenseFrame *frame) case MS_TOUCH_ACTIVE: case MS_TOUCH_LOW_POWER: case MS_TOUCH_ULTRA_LOW_POWER: - size = frame->header.force_node*frame->header.sense_node; + size = frame->header.force_node * frame->header.sense_node; break; case MS_KEY: + //or use directly the number in the ftsChip if (frame->header.force_node > frame->header.sense_node) - /* or use directly the number in the ftsChip */ size = frame->header.force_node; else size = frame->header.sense_node; - frame->header.force_node = 1; + frame->header.force_node = 1; frame->header.sense_node = size; break; default: - logError(1, "%s getMSFrame: ERROR % 02X\n", tag, ERROR_OP_NOT_ALLOW); + logError(1, "%s %s: ERROR % 02X\n", + tag, __func__, ERROR_OP_NOT_ALLOW); return ERROR_OP_NOT_ALLOW; } - frame->node_data = (short *)kmalloc(size*sizeof(short), GFP_KERNEL); + frame->node_data = (short *)kmalloc_array(size, + sizeof(short), GFP_KERNEL); if (frame->node_data == NULL) { - logError(1, "%s getMSFrame: ERROR %02X\n", tag, ERROR_ALLOC); + logError(1, "%s %s: ERROR %02X\n", tag, __func__, ERROR_ALLOC); return ERROR_ALLOC; } ret = getFrameData(offset, size*BYTES_PER_NODE, &(frame->node_data)); if (ret < OK) { - logError(1, "%s getMSFrame: ERROR %02X\n", tag, ERROR_GET_FRAME_DATA); + logError(1, "%s %s: ERROR %02X\n", + tag, __func__, ERROR_GET_FRAME_DATA); + kfree(frame->node_data); return (ret | ERROR_GET_FRAME_DATA); } - /* if you want to access one node i,j, you should compute the offset like: offset = i*columns + j = > frame[i, j] */ - + // if you want to access one node i,j, + //you should compute the offset like: + //offset = i * columns + j = > frame[i, j] logError(0, "%s Frame acquired!\n", tag); frame->node_data_size = size; - return size; /* return the number of data put inside frame */ + return size;//return the number of data put inside frame } -int getSSFrame2(u16 type, SelfSenseFrame *frame) +int getSSFrame2(u16 type, struct SelfSenseFrame *frame) { u16 offset = ADDR_FRAMEBUFFER_DATA + FRAME_DATA_HEADER; int size, ret; short *temp = NULL; - if (!(type == SS_TOUCH || type == SS_KEY || type == SS_HOVER || type == SS_PROXIMITY)) { - logError(1, "%s getSSFrame: Choose a SS type of frame data ERROR %02X\n", tag, ERROR_OP_NOT_ALLOW); + frame->force_data = NULL; + frame->sense_data = NULL; + + if (!(type == SS_TOUCH || type == SS_KEY || type == SS_HOVER + || type == SS_PROXIMITY)) { + logError(1, "%s %s:Choose a SS type of frame data ERROR %02X\n", + tag, __func__, ERROR_OP_NOT_ALLOW); return ERROR_OP_NOT_ALLOW; } ret = requestFrame(type); if (ret < 0) { - logError(1, "%s getSSFrame: ERROR %02X\n", tag, ERROR_REQU_COMP_DATA); + logError(1, "%s %s: ERROR %02X\n", + tag, __func__, ERROR_REQU_COMP_DATA); return (ret | ERROR_REQU_COMP_DATA); } ret = readFrameDataHeader(type, &(frame->header)); if (ret < 0) { - logError(1, "%s getSSFrame: ERROR %02X\n", tag, ERROR_COMP_DATA_HEADER); + logError(1, "%s %s: ERROR %02X\n", + tag, __func__, ERROR_COMP_DATA_HEADER); return (ret | ERROR_COMP_DATA_HEADER); } @@ -526,44 +462,57 @@ int getSSFrame2(u16 type, SelfSenseFrame *frame) case SS_TOUCH: case SS_HOVER: case SS_PROXIMITY: - size = frame->header.force_node+frame->header.sense_node; + size = frame->header.force_node + frame->header.sense_node; break; default: - logError(1, "%s getSSFrame: ERROR % 02X\n", tag, ERROR_OP_NOT_ALLOW); + logError(1, "%s %s: ERROR % 02X\n", + tag, __func__, ERROR_OP_NOT_ALLOW); return ERROR_OP_NOT_ALLOW; } - temp = (short *)kmalloc(size*sizeof(short), GFP_KERNEL); + + temp = (short *)kmalloc_array(size, sizeof(short), GFP_KERNEL); if (temp == NULL) { - logError(1, "%s getSSFrame: ERROR %02X\n", tag, ERROR_ALLOC); + logError(1, "%s %s: temp ERROR %02X\n", + tag, __func__, ERROR_ALLOC); return ERROR_ALLOC; } ret = getFrameData(offset, size*BYTES_PER_NODE, &temp); if (ret < OK) { - logError(1, "%s getMSFrame: ERROR %02X\n", tag, ERROR_GET_FRAME_DATA); + logError(1, "%s %s: ERROR %02X\n", + tag, __func__, ERROR_GET_FRAME_DATA); + kfree(temp); return (ret | ERROR_GET_FRAME_DATA); } - frame->force_data = (short *)kmalloc(frame->header.force_node*sizeof(short), GFP_KERNEL); + frame->force_data = (short *)kmalloc_array(frame->header.force_node, + sizeof(short), GFP_KERNEL); if (frame->force_data == NULL) { - logError(1, "%s getSSFrame: ERROR %02X\n", tag, ERROR_ALLOC); + logError(1, "%s %s: frame->force_data ERROR %02X\n", + tag, __func__, ERROR_ALLOC); + kfree(temp); return ERROR_ALLOC; } - memcpy(frame->force_data, temp, frame->header.force_node*sizeof(short)); + memcpy(frame->force_data, temp, + frame->header.force_node * sizeof(short)); - frame->sense_data = (short *)kmalloc(frame->header.sense_node*sizeof(short), GFP_KERNEL); + frame->sense_data = (short *)kmalloc_array(frame->header.sense_node, + sizeof(short), GFP_KERNEL); if (frame->sense_data == NULL) { - logError(1, "%s getSSFrame: ERROR %02X\n", tag, ERROR_ALLOC); + logError(1, "%s %s: frame->sense_data ERROR %02X\n", + tag, __func__, ERROR_ALLOC); + kfree(temp); + kfree(frame->force_data); return ERROR_ALLOC; } - memcpy(frame->sense_data, &temp[frame->header.force_node], frame->header.sense_node*sizeof(short)); + memcpy(frame->sense_data, &temp[frame->header.force_node], + frame->header.sense_node * sizeof(short)); logError(0, "%s Frame acquired!\n", tag); kfree(temp); - return size; /* return the number of data put inside frame */ - + return size; //return the number of data put inside frame } diff --git a/drivers/input/touchscreen/st/fts_lib/ftsFrame.h b/drivers/input/touchscreen/st/fts_lib/ftsFrame.h index 89f4e5080a53..8df80ef1dac9 100644 --- a/drivers/input/touchscreen/st/fts_lib/ftsFrame.h +++ b/drivers/input/touchscreen/st/fts_lib/ftsFrame.h @@ -1,49 +1,75 @@ /* + * FTS Capacitive touch screen controller (FingerTipS) + * + * Copyright (C) 2016-2018, STMicroelectronics Limited. + * Authors: AMG(Analog Mems Group) + * + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + */ -************************************************************************** -** STMicroelectronics ** -************************************************************************** -** marco.cali@st.com ** -************************************************************************** -* * -* FTS functions for getting frames * -* * -************************************************************************** -************************************************************************** +/** + * + ************************************************************************** + ** STMicroelectronics ** + ************************************************************************** + ** marco.cali@st.com ** + ************************************************************************** + * * + * FTS functions for getting frames * + * * + ************************************************************************** + ************************************************************************** + */ -*/ +#ifndef __FTS_FRAME_H +#define __FTS_FRAME_H #include "ftsSoftware.h" -/* Number of data bytes for each node */ -#define BYTES_PER_NODE 2 -#define OFFSET_LENGTH 2 -#define FRAME_DATA_HEADER 8 -#define FRAME_HEADER_SIGNATURE 0xB5 -#define FRAME_DATA_READ_RETRY 2 +//Number of data bytes for each node +#define BYTES_PER_NODE 2 +#define OFFSET_LENGTH 2 +#define FRAME_DATA_HEADER 8 +#define FRAME_HEADER_SIGNATURE 0xB5 +#define FRAME_DATA_READ_RETRY 2 -typedef struct { - DataHeader header; +struct MutualSenseFrame { + struct DataHeader header; short *node_data; int node_data_size; -} MutualSenseFrame; +}; -typedef struct { - DataHeader header; +struct SelfSenseFrame { + struct DataHeader header; short *force_data; short *sense_data; -} SelfSenseFrame; +}; -/* int getOffsetFrame(u16 address, u16 *offset); */ +int getOffsetFrame(u16 address, u16 *offset); int getChannelsLength(void); int getFrameData(u16 address, int size, short **frame); -/* int getMSFrame(u16 type, short **frame, int keep_first_row); */ -/* int getMSKeyFrame(u16 type, short **frame); */ -/* int getSSFrame(u16 type, short **frame); */ -/* int getNmsFrame(u16 type, short ***frames, int * sizes, int keep_first_row, int fs, int n); */ +int getMSFrame(u16 type, struct MutualSenseFrame *frame, int keep_first_row); +//int getMSKeyFrame(u16 type, short **frame); +//int getSSFrame(u16 type, short **frame); +//int getNmsFrame(u16 type, short ***frames, int * sizes, +//int keep_first_row, int fs, int n); int getSenseLen(void); int getForceLen(void); int requestFrame(u16 type); -int readFrameDataHeader(u16 type, DataHeader *header); -int getMSFrame2(u16 type, MutualSenseFrame *frame); -int getSSFrame2(u16 type, SelfSenseFrame *frame); +int readFrameDataHeader(u16 type, struct DataHeader *header); +int getMSFrame2(u16 type, struct MutualSenseFrame *frame); +int getSSFrame2(u16 type, struct SelfSenseFrame *frame); + +#endif + diff --git a/drivers/input/touchscreen/st/fts_lib/ftsGesture.c b/drivers/input/touchscreen/st/fts_lib/ftsGesture.c index ee97a417d4cb..77075b4be2a5 100644 --- a/drivers/input/touchscreen/st/fts_lib/ftsGesture.c +++ b/drivers/input/touchscreen/st/fts_lib/ftsGesture.c @@ -1,17 +1,36 @@ /* - -************************************************************************** -** STMicroelectronics ** -************************************************************************** -** marco.cali@st.com ** -************************************************************************** -* * -* FTS Gesture Utilities * -* * -************************************************************************** -************************************************************************** - -*/ + * FTS Capacitive touch screen controller (FingerTipS) + * + * Copyright (C) 2016-2018, STMicroelectronics Limited. + * Authors: AMG(Analog Mems Group) + * + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + */ + +/** + * + ************************************************************************** + ** STMicroelectronics ** + ************************************************************************** + ** marco.cali@st.com ** + ************************************************************************** + * * + * FTS Gesture Utilities * + * * + ************************************************************************** + ************************************************************************** + */ #include "ftsSoftware.h" #include "ftsError.h" @@ -19,145 +38,236 @@ #include "ftsIO.h" #include "ftsTool.h" + static char tag[8] = "[ FTS ]\0"; static u8 gesture_mask[GESTURE_MASK_SIZE] = { 0 }; static u8 custom_gestures[GESTURE_CUSTOM_NUMBER][GESTURE_CUSTOM_POINTS]; static u8 custom_gesture_index[GESTURE_CUSTOM_NUMBER] = { 0 }; +static int refreshGestureMask; + +u16 gesture_coordinates_x[GESTURE_COORDS_REPORT_MAX] = {0}; +u16 gesture_coordinates_y[GESTURE_COORDS_REPORT_MAX] = {0}; +int gesture_coords_reported = ERROR_OP_NOT_ALLOW; +struct mutex gestureMask_mutex; + + +int updateGestureMask(u8 *mask, int size, int en) +{ + u8 temp; + int i; + + if (mask == NULL) { + logError(1, "%s %s: Mask NULL! ERROR %08X\n", + tag, __func__, ERROR_OP_NOT_ALLOW); + return ERROR_OP_NOT_ALLOW; + } + + if (size > GESTURE_MASK_SIZE) { + logError(1, "%s %s:Size not valid! %d > %d ERROR %08X\n", + tag, __func__, size, GESTURE_MASK_SIZE); + return ERROR_OP_NOT_ALLOW; + } + + if (en == FEAT_ENABLE) { + mutex_lock(&gestureMask_mutex); + logError(0, "%s %s:setting gesture mask to enable..\n", + tag, __func__); + if (mask != NULL) { + for (i = 0; i < size; i++) { + //back up the gesture enabled + gesture_mask[i] = gesture_mask[i] | mask[i]; + } + } + refreshGestureMask = 1; + logError(0, "%s %s:gesture mask to enable SET!\n", + tag, __func__); + mutex_unlock(&gestureMask_mutex); + return OK; + } + if (en == FEAT_DISABLE) { + mutex_lock(&gestureMask_mutex); + logError(0, "%s %s:setting gesture ", tag, __func__); + logError(0, "mask to disable...\n"); + for (i = 0; i < size; i++) { + // enabled XOR disabled + temp = gesture_mask[i] ^ mask[i]; + gesture_mask[i] = temp & gesture_mask[i]; + } + logError(0, "%s %s:gesture mask to disable SET!\n", + tag, __func__); + refreshGestureMask = 1; + mutex_unlock(&gestureMask_mutex); + return OK; + } + logError(1, "%s%s:Enable parameter Invalid%d!=%d or%d%:08X", + tag, __func__, FEAT_DISABLE, + FEAT_ENABLE, ERROR_OP_NOT_ALLOW); + return ERROR_OP_NOT_ALLOW; + +} int enableGesture(u8 *mask, int size) { - u8 cmd[size+2]; - u8 readData[FIFO_EVENT_SIZE] = {0}; + u8 cmd[GESTURE_MASK_SIZE + 2]; + u8 readData[FIFO_EVENT_SIZE]; int i, res; - int event_to_search[4] = {EVENTID_GESTURE, EVENT_TYPE_ENB, 0x00, GESTURE_ENABLE}; + int event_to_search[4] = { EVENTID_GESTURE, + EVENT_TYPE_ENB, 0x00, GESTURE_ENABLE }; logError(0, "%s Trying to enable gesture...\n", tag); cmd[0] = FTS_CMD_GESTURE_CMD; cmd[1] = GESTURE_ENABLE; - if (size <= GESTURE_MASK_SIZE) { + + if (size > GESTURE_MASK_SIZE) { + logError(1, "%s %s: Size not valid! %d > %d ERROR %08X\n", + tag, __func__, size, GESTURE_MASK_SIZE); + return ERROR_OP_NOT_ALLOW; + } + + mutex_lock(&gestureMask_mutex); if (mask != NULL) { for (i = 0; i < size; i++) { cmd[i + 2] = mask[i]; - gesture_mask[i] = gesture_mask[i]|mask[i]; - /* back up of the gesture enabled */ + //back up of the gesture enabled + gesture_mask[i] = gesture_mask[i] | mask[i]; } while (i < GESTURE_MASK_SIZE) { cmd[i + 2] = gesture_mask[i]; i++; } } else { - for (i = 0; i < GESTURE_MASK_SIZE; i++) { + for (i = 0; i < GESTURE_MASK_SIZE; i++) cmd[i + 2] = gesture_mask[i]; - } } res = fts_writeFwCmd(cmd, GESTURE_MASK_SIZE + 2); if (res < OK) { - logError(1, "%s enableGesture: ERROR %08X\n", tag, res); - return res; + logError(1, "%s %s: ERROR %08X\n", tag, __func__, res); + goto END; } - res = pollForEvent(event_to_search, 4, readData, GENERAL_TIMEOUT); + res = pollForEvent(event_to_search, 4, + readData, GENERAL_TIMEOUT); if (res < OK) { - logError(1, "%s enableGesture: pollForEvent ERROR %08X\n", tag, res); - return res; + logError(1, "%s %s: pollForEvent ERROR %08X\n", + tag, __func__, res); + goto END; } if (readData[4] != 0x00) { - logError(1, "%s enableGesture: ERROR %08X\n", tag, ERROR_GESTURE_ENABLE_FAIL); - return ERROR_GESTURE_ENABLE_FAIL; + logError(1, "%s %s: ERROR %08X\n", + tag, __func__, ERROR_GESTURE_ENABLE_FAIL); + res = ERROR_GESTURE_ENABLE_FAIL; + goto END; } - logError(0, "%s enableGesture DONE!\n", tag); - return OK; - } else { - logError(1, "%s enableGesture: Size not valid! %d > %d ERROR %08X\n", tag, size, GESTURE_MASK_SIZE); - return ERROR_OP_NOT_ALLOW; - } + logError(0, "%s %s: DONE!\n", tag, __func__); + res = OK; +END: + mutex_unlock(&gestureMask_mutex); + return res; } + int disableGesture(u8 *mask, int size) { - u8 cmd[2+GESTURE_MASK_SIZE]; - u8 readData[FIFO_EVENT_SIZE] = {0}; + u8 cmd[2 + GESTURE_MASK_SIZE]; + u8 readData[FIFO_EVENT_SIZE]; u8 temp; int i, res; - int event_to_search[4] = { EVENTID_GESTURE, EVENT_TYPE_ENB, 0x00, GESTURE_DISABLE }; + int event_to_search[4] = { EVENTID_GESTURE, + EVENT_TYPE_ENB, 0x00, GESTURE_DISABLE }; logError(0, "%s Trying to disable gesture...\n", tag); cmd[0] = FTS_CMD_GESTURE_CMD; cmd[1] = GESTURE_DISABLE; - if (size <= GESTURE_MASK_SIZE) { + if (size > GESTURE_MASK_SIZE) { + logError(1, "%s %s: Size not valid! %d > %d ERROR %08X\n", + tag, __func__, size, GESTURE_MASK_SIZE); + return ERROR_OP_NOT_ALLOW; + } + mutex_lock(&gestureMask_mutex); if (mask != NULL) { for (i = 0; i < size; i++) { cmd[i + 2] = mask[i]; + // enabled XOR disabled temp = gesture_mask[i] ^ mask[i]; - /* enabled XOR disabled */ gesture_mask[i] = temp & gesture_mask[i]; - /* disable the gestures that were enabled */ } while (i < GESTURE_MASK_SIZE) { - cmd[i + 2] = gesture_mask[i]; - /* disable all the other gesture not specified */ - gesture_mask[i] = 0x00; + //cmd[i + 2] = gesture_mask[i]; + //gesture_mask[i] = 0x00; + + cmd[i + 2] = 0x00; + //leave untouched the gestures not specified + i++; } } else { for (i = 0; i < GESTURE_MASK_SIZE; i++) { - cmd[i + 2] = gesture_mask[i]; + //cmd[i + 2] = gesture_mask[i]; + cmd[i + 2] = 0xFF; } } res = fts_writeFwCmd(cmd, 2 + GESTURE_MASK_SIZE); if (res < OK) { - logError(1, "%s disableGesture: ERROR %08X\n", tag, res); - return res; + logError(1, "%s %s:ERROR %08X\n", tag, __func__, res); + goto END; } res = pollForEvent(event_to_search, 4, readData, GENERAL_TIMEOUT); if (res < OK) { - logError(1, "%s disableGesture: pollForEvent ERROR %08X\n", tag, res); - return res; + logError(1, "%s %s: pollForEvent ERROR %08X\n", + tag, __func__, res); + goto END; } if (readData[4] != 0x00) { - logError(1, "%s disableGesture: ERROR %08X\n", tag, ERROR_GESTURE_ENABLE_FAIL); - return ERROR_GESTURE_ENABLE_FAIL; + logError(1, "%s %s:ERROR %08X\n", + tag, __func__, ERROR_GESTURE_ENABLE_FAIL); + res = ERROR_GESTURE_ENABLE_FAIL; + goto END; } - logError(0, "%s disableGesture DONE!\n", tag); - return OK; - } else { - logError(1, "%s disableGesture: Size not valid! %d > %d ERROR %08X\n", tag, size, GESTURE_MASK_SIZE); - return ERROR_OP_NOT_ALLOW; - } + logError(0, "%s %s: DONE!\n", tag, __func__); + res = OK; +END: + mutex_unlock(&gestureMask_mutex); + return res; + } int startAddCustomGesture(u8 gestureID) { - u8 cmd[3] = { FTS_CMD_GESTURE_CMD, GESTURE_START_ADD, gestureID }; + u8 cmd[3] = { FTS_CMD_GESTURE_CMD, GESTURE_START_ADD, gestureID }; int res; - u8 readData[FIFO_EVENT_SIZE] = {0}; - int event_to_search[4] = { EVENTID_GESTURE, EVENT_TYPE_ENB, gestureID, GESTURE_START_ADD }; + u8 readData[FIFO_EVENT_SIZE]; + int event_to_search[4] = { EVENTID_GESTURE, EVENT_TYPE_ENB, + gestureID, GESTURE_START_ADD }; res = fts_writeFwCmd(cmd, 3); if (res < OK) { - logError(1, "%s startAddCustomGesture: Impossible to start adding custom gesture ID = %02X! ERROR %08X\n", tag, gestureID, res); + logError(1, + "%s%s:Impossible to start adding custom gesture ID:%02X %08X\n", + tag, __func__, gestureID, res); return res; } res = pollForEvent(event_to_search, 4, readData, GENERAL_TIMEOUT); if (res < OK) { - logError(1, "%s startAddCustomGesture: start add event not found! ERROR %08X\n", tag, res); + logError(1, "%s %s:start add event not found! ERROR %08X\n", + tag, __func__, res); return res; } - - if (readData[2] != gestureID || readData[4] != 0x00) { /* check of gestureID is redundant */ - logError(1, "%s startAddCustomGesture: start add event status not OK! ERROR %08X\n", tag, readData[4]); + //check of gestureID is redundant + if (readData[2] != gestureID || readData[4] != 0x00) { + logError(1, "%s %s:start add event status not OK! ERROR %08X\n", + tag, __func__, readData[4]); return ERROR_GESTURE_START_ADD; } @@ -166,79 +276,93 @@ int startAddCustomGesture(u8 gestureID) int finishAddCustomGesture(u8 gestureID) { - u8 cmd[3] = { FTS_CMD_GESTURE_CMD, GESTURE_FINISH_ADD, gestureID }; + u8 cmd[3] = { FTS_CMD_GESTURE_CMD, + GESTURE_FINISH_ADD, gestureID }; int res; - u8 readData[FIFO_EVENT_SIZE] = {0}; - int event_to_search[4] = { EVENTID_GESTURE, EVENT_TYPE_ENB, gestureID, GESTURE_FINISH_ADD }; + u8 readData[FIFO_EVENT_SIZE]; + int event_to_search[4] = { EVENTID_GESTURE, EVENT_TYPE_ENB, + gestureID, GESTURE_FINISH_ADD }; res = fts_writeFwCmd(cmd, 3); if (res < OK) { - logError(1, "%s finishAddCustomGesture: Impossible to finish adding custom gesture ID = %02X! ERROR %08X\n", tag, gestureID, res); + logError(1, + "%s%s:Impossible to finish adding custom gestureID:%02X %08X\n", + tag, __func__, gestureID, res); return res; } res = pollForEvent(event_to_search, 4, readData, GENERAL_TIMEOUT); if (res < OK) { - logError(1, "%s finishAddCustomGesture: finish add event not found! ERROR %08X\n", tag, res); + logError(1, "%s %s: finish add event not found! ERROR %08X\n", + tag, __func__, res); return res; } - - if (readData[2] != gestureID || readData[4] != 0x00) { /* check of gestureID is redundant */ - logError(1, "%s finishAddCustomGesture: finish add event status not OK! ERROR %08X\n", tag, readData[4]); + //check of gestureID is redundant + if (readData[2] != gestureID || readData[4] != 0x00) { + logError(1, + "%s %s:finish add event status not OK! ERROR %08X\n", + tag, __func__, readData[4]); return ERROR_GESTURE_FINISH_ADD; } return OK; - } int loadCustomGesture(u8 *template, u8 gestureID) { - int res, i; + int res, i, wheel; int remaining = GESTURE_CUSTOM_POINTS; int toWrite, offset = 0; u8 cmd[TEMPLATE_CHUNK + 5]; - int event_to_search[4] = { EVENTID_GESTURE, EVENT_TYPE_ENB, gestureID, GESTURE_DATA_ADD }; - u8 readData[FIFO_EVENT_SIZE] = {0}; + int event_to_search[4] = { EVENTID_GESTURE, EVENT_TYPE_ENB, + gestureID, GESTURE_DATA_ADD }; + u8 readData[FIFO_EVENT_SIZE]; logError(0, "%s Starting adding custom gesture procedure...\n", tag); res = startAddCustomGesture(gestureID); if (res < OK) { - logError(1, "%s loadCustomGesture: unable to start adding procedure! ERROR %08X\n", tag, res); + logError(1, "%s %s:unable to start adding procedure %08X\n", + tag, __func__, res); return res; } cmd[0] = FTS_CMD_GESTURE_CMD; cmd[1] = GESTURE_DATA_ADD; cmd[2] = gestureID; + wheel = 0; while (remaining > 0) { - if (remaining > TEMPLATE_CHUNK) { + if (remaining > TEMPLATE_CHUNK) toWrite = TEMPLATE_CHUNK; - } else { + else toWrite = remaining; - } cmd[3] = toWrite; cmd[4] = offset; - for (i = 0; i < toWrite; i++) { - cmd[i + 5] = template[i]; - } + for (i = 0; i < toWrite; i++) + cmd[i + 5] = template[wheel++]; res = fts_writeFwCmd(cmd, toWrite + 5); if (res < OK) { - logError(1, "%s loadCustomGesture: unable to start adding procedure! ERROR %08X\n", tag, res); + logError(1, "%s %s:unable to start ", tag, __func__); + logError(1, "adding procedure %08X\n", res); return res; } - res = pollForEvent(event_to_search, 4, readData, GENERAL_TIMEOUT); + res = pollForEvent(event_to_search, + 4, + readData, + GENERAL_TIMEOUT); if (res < OK) { - logError(1, "%s loadCustomGesture: add event not found! ERROR %08X\n", tag, res); + logError(1, "%s %s: add event not found! ERROR %08X\n", + tag, __func__, res); return res; } - - if (readData[2] != gestureID || readData[4] != 0x00) { /* check of gestureID is redundant */ - logError(1, "%s loadCustomGesture: add event status not OK! ERROR %08X\n", tag, readData[4]); + //check of gestureID is redundant + if (readData[2] != gestureID || readData[4] != 0x00) { + logError(1, "%s %s:add event status not OK! ", + tag, __func__); + logError(1, "ERROR %08X\n", readData[4]); return ERROR_GESTURE_DATA_ADD; } @@ -248,7 +372,9 @@ int loadCustomGesture(u8 *template, u8 gestureID) res = finishAddCustomGesture(gestureID); if (res < OK) { - logError(1, "%s loadCustomGesture: unable to finish adding procedure! ERROR %08X\n", tag, res); + logError(1, "%s %s:unable to finish adding procedure! ", + tag, __func__); + logError(1, "ERROR %08X\n", res); return res; } @@ -257,6 +383,7 @@ int loadCustomGesture(u8 *template, u8 gestureID) } + int reloadCustomGesture(void) { int res, i; @@ -265,9 +392,13 @@ int reloadCustomGesture(void) for (i = 0; i < GESTURE_CUSTOM_NUMBER; i++) { if (custom_gesture_index[i] == 1) { - res = loadCustomGesture(custom_gestures[i], GESTURE_CUSTOM_OFFSET+i); + res = loadCustomGesture(custom_gestures[i], + GESTURE_CUSTOM_OFFSET + i); if (res < OK) { - logError(1, "%s reloadCustomGesture: Impossible to load custom gesture ID = %02X! ERROR %08X\n", tag, GESTURE_CUSTOM_OFFSET + i, res); + logError(1, "%s %s:Impossible load gesture ", + tag, __func__); + logError(1, "D:%02X %08X\n", + GESTURE_CUSTOM_OFFSET + i, res); return res; } } @@ -285,34 +416,48 @@ int enterGestureMode(int reload) res = fts_disableInterrupt(); if (res < OK) { - logError(1, "%s enterGestureMode: ERROR %08X\n", tag, res|ERROR_DISABLE_INTER); + logError(1, "%s %s: ERROR %08X\n", + tag, __func__, res | ERROR_DISABLE_INTER); return res | ERROR_DISABLE_INTER; } - if (reload == 1) { - - res = reloadCustomGesture(); - if (res < OK) { - logError(1, "%s enterGestureMode: impossible reload custom gesture! ERROR %08X\n", tag, res); - goto END; + if (reload == 1 || refreshGestureMask == 1) { + if (reload == 1) { + res = reloadCustomGesture(); + if (res < OK) { + logError(1, "%s %s:impossible reload ", + tag, __func__); + logError(1, "custom gesture %08X\n", res); + goto END; + } } + /** + * mandatory steps to set the correct gesture + * mask defined by the user + */ res = disableGesture(NULL, 0); if (res < OK) { - logError(1, "%s enterGestureMode: disableGesture ERROR %08X\n", tag, res); + logError(1, "%s %s:disableGesture ERROR %08X\n", + tag, res); goto END; } res = enableGesture(NULL, 0); if (res < OK) { - logError(1, "%s enterGestureMode: enableGesture ERROR %08X\n", tag, res); + logError(1, "%s %s:enableGesture ERROR %08X\n", + tag, __func__, res); goto END; } + + refreshGestureMask = 0; + /**************************************************/ } res = fts_writeFwCmd(&cmd, 1); if (res < OK) { - logError(1, "%s enterGestureMode: enter gesture mode ERROR %08X\n", tag, res); + logError(1, "%s %s:enter gesture mode ERROR %08X\n", + tag, __func__, res); goto END; } @@ -320,7 +465,8 @@ int enterGestureMode(int reload) END: ret = fts_enableInterrupt(); if (ret < OK) { - logError(1, "%s enterGestureMode: fts_enableInterrupt ERROR %08X\n", tag, res | ERROR_ENABLE_INTER); + logError(1, "%s %s:fts_enableInterrupt ERROR %08X\n", + tag, __func__, res | ERROR_ENABLE_INTER); res |= ret | ERROR_ENABLE_INTER; } @@ -334,18 +480,24 @@ int addCustomGesture(u8 *data, int size, u8 gestureID) index = gestureID - GESTURE_CUSTOM_OFFSET; logError(0, "%s Starting Custom Gesture Adding procedure...\n", tag); - if (size != GESTURE_CUSTOM_POINTS && gestureID != GES_ID_CUST1 && gestureID != GES_ID_CUST2 && gestureID != GES_ID_CUST3 && gestureID != GES_ID_CUST4 && gestureID && GES_ID_CUST5) { - logError(1, "%s addCustomGesture: Invalid size (%d) or Custom GestureID (%02X)! ERROR %08X\n", tag, size, gestureID, ERROR_OP_NOT_ALLOW); + if (size != GESTURE_CUSTOM_POINTS || (gestureID != GES_ID_CUST1 + && gestureID != GES_ID_CUST2 && gestureID != GES_ID_CUST3 + && gestureID != GES_ID_CUST4 && gestureID != GES_ID_CUST5)) { + logError(1, "%s %s:Invalid size(%d) or Custom GestureID ", + tag, __func__, size); + logError(1, "(%02X)!ERROR%08X\n", + size, gestureID, ERROR_OP_NOT_ALLOW); return ERROR_OP_NOT_ALLOW; } - for (i = 0; i < GESTURE_CUSTOM_POINTS; i++) { + for (i = 0; i < GESTURE_CUSTOM_POINTS; i++) custom_gestures[index][i] = data[i]; - } res = loadCustomGesture(custom_gestures[index], gestureID); if (res < OK) { - logError(1, "%s addCustomGesture: impossible to load the custom gesture! ERROR %08X\n", tag, res); + logError(1, "%s %s:impossible to load the custom gesture! ", + tag, __func__); + logError(1, "ERROR %08X\n", res); return res; } @@ -358,31 +510,40 @@ int removeCustomGesture(u8 gestureID) { int res, index; u8 cmd[3] = { FTS_CMD_GESTURE_CMD, GETURE_REMOVE_CUSTOM, gestureID }; - int event_to_search[4] = {EVENTID_GESTURE, EVENT_TYPE_ENB, gestureID, GETURE_REMOVE_CUSTOM }; - u8 readData[FIFO_EVENT_SIZE] = {0}; + int event_to_search[4] = { EVENTID_GESTURE, EVENT_TYPE_ENB, + gestureID, GETURE_REMOVE_CUSTOM }; + u8 readData[FIFO_EVENT_SIZE]; index = gestureID - GESTURE_CUSTOM_OFFSET; logError(0, "%s Starting Custom Gesture Removing procedure...\n", tag); - if (gestureID != GES_ID_CUST1 && gestureID != GES_ID_CUST2 && gestureID != GES_ID_CUST3 && gestureID != GES_ID_CUST4 && gestureID && GES_ID_CUST5) { - logError(1, "%s removeCustomGesture: Invalid size (%d) or Custom GestureID (%02X)! ERROR %08X\n", tag, gestureID, ERROR_OP_NOT_ALLOW); + if (gestureID != GES_ID_CUST1 && gestureID != GES_ID_CUST2 && + gestureID != GES_ID_CUST3 && gestureID != + GES_ID_CUST4 && gestureID != GES_ID_CUST5) { + logError(1, "%s %s:Invalid Custom GestureID (%02X)! ", + tag, __func__, gestureID); + logError(1, "ERROR %08X\n", ERROR_OP_NOT_ALLOW); return ERROR_OP_NOT_ALLOW; } - - res = fts_writeFwCmd(cmd, 3);/* when a gesture is removed, it is also disabled automatically */ + //when a gesture is removed, it is also disabled automatically + res = fts_writeFwCmd(cmd, 3); if (res < OK) { - logError(1, "%s removeCustomGesture: Impossible to remove custom gesture ID = %02X! ERROR %08X\n", tag, gestureID, res); + logError(1, "%s %s:Impossible to remove custom ", + tag, __func__); + logError(1, "%gesture ID:%02X %08X\n", gestureID, res); return res; } res = pollForEvent(event_to_search, 4, readData, GENERAL_TIMEOUT); if (res < OK) { - logError(1, "%s removeCustomGesture: remove event not found! ERROR %08X\n", tag, res); + logError(1, "%s %s:remove event not found! ERROR %08X\n", + tag, __func__, res); return res; } - - if (readData[2] != gestureID || readData[4] != 0x00) { /* check of gestureID is redundant */ - logError(1, "%s removeCustomGesture: remove event status not OK! ERROR %08X\n", tag, readData[4]); + //check of gestureID is redundant + if (readData[2] != gestureID || readData[4] != 0x00) { + logError(1, "%s %s:remove event status not OK! ERROR %08X\n", + tag, __func__, readData[4]); return ERROR_GESTURE_REMOVE; } @@ -391,3 +552,99 @@ int removeCustomGesture(u8 gestureID) return OK; } + +int isAnyGestureActive(void) +{ + int res = 0; + /*-1 because in any case the last gesture mask byte will*/ + /*be evaluated with the following if*/ + while (res < (GESTURE_MASK_SIZE - 1) && gesture_mask[res] == 0) + res++; + + if (gesture_mask[res] == 0) { + logError(0, "%s %s: All Gestures Disabled!\n", tag, __func__); + return FEAT_DISABLE; + } + + logError(0, "%s %s:Active Gestures Found! gesture_mask[%d] = %02X!\n", + tag, __func__, res, gesture_mask[res]); + return FEAT_ENABLE; +} + +int gestureIDtoGestureMask(u8 id, u8 *mask) +{ + logError(0, "%s %s: Index = %d Position = %d!\n", + tag, __func__, ((int)((id) / 8)), (id % 8)); + mask[((int)((id) / 8))] |= 0x01 << (id % 8); + return OK; +} + + +int readGestureCoords(u8 *event) +{ + int i = 0; + u8 rCmd[3] = {FTS_CMD_FRAMEBUFFER_R, 0x00, 0x00 }; + int res; + unsigned char val[GESTURE_COORDS_REPORT_MAX * 4 + 1]; + + //the max coordinates to read are GESTURE_COORDS_REPORT_MAX*4 + //(because each coordinate is a short(*2) and we have x and y) + //+ dummy byte + if (event[0] != EVENTID_GESTURE + || event[1] != EVENT_TYPE_GESTURE_DTC2) { + + logError(1, "%s %s:The event passsed as argument is invalid! ", + tag, __func__); + logError(1, "ERROR %08X\n", ERROR_OP_NOT_ALLOW); + return ERROR_OP_NOT_ALLOW; + } + + rCmd[1] = event[4]; // Offset address L + rCmd[2] = event[3]; // Offset address H + //number of coords reported L + gesture_coords_reported = event[6]; + //number of coords reported H + gesture_coords_reported = (gesture_coords_reported << 8) | event[5]; + if (gesture_coords_reported > GESTURE_COORDS_REPORT_MAX) { + logError(1, "%s%s:FW reported more than:%d points ", + tag, __func__, gesture_coords_reported); + logError(1, "for gestures!\n"); + logError(1, " Decreasing to %d\n", GESTURE_COORDS_REPORT_MAX); + gesture_coords_reported = GESTURE_COORDS_REPORT_MAX; + } + + logError(1, "%s %s: Offset: %02X %02X points = %d\n", tag, + __func__, rCmd[1], rCmd[2], gesture_coords_reported); + res = fts_readCmd(rCmd, 3, (unsigned char *)val, + 1 + (gesture_coords_reported * 2)); + if (res < OK) { + logError(1, "%s %s: Cannot read the coordinates! ERROR %08X\n", + tag, __func__, res); + gesture_coords_reported = ERROR_OP_NOT_ALLOW; + return res; + } + //all the points of the gesture are stored in val + for (i = 0; i < gesture_coords_reported; i++) { + //ignore first byte data because it is a dummy byte + gesture_coordinates_x[i] = (((u16) val[i * 2 + 1 + 1]) + & 0x0F) << 8 | (((u16) val[i * 2 + 1]) & 0xFF); + gesture_coordinates_y[i] = + (((u16)val[gesture_coords_reported * 2 + + i * 2 + 1 + 1]) & 0x0F) << 8 + | (((u16)val[gesture_coords_reported * 2 + + i * 2 + 1]) & 0xFF); + } + + logError(1, "%s %s: Reading Gesture Coordinates DONE!\n", + tag, __func__); + return OK; +} + +int getGestureCoords(u16 *x, u16 *y) +{ + x = gesture_coordinates_x; + y = gesture_coordinates_y; + logError(1, "%s %s:Number of gesture coordinates returned = %d\n", + tag, __func__, gesture_coords_reported); + return gesture_coords_reported; +} diff --git a/drivers/input/touchscreen/st/fts_lib/ftsGesture.h b/drivers/input/touchscreen/st/fts_lib/ftsGesture.h index a9c3e3c05573..3cc86236ad72 100644 --- a/drivers/input/touchscreen/st/fts_lib/ftsGesture.h +++ b/drivers/input/touchscreen/st/fts_lib/ftsGesture.h @@ -1,70 +1,110 @@ /* + * FTS Capacitive touch screen controller (FingerTipS) + * + * Copyright (C) 2016-2018, STMicroelectronics Limited. + * Authors: AMG(Analog Mems Group) + * + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + */ -************************************************************************** -** STMicroelectronics ** -************************************************************************** -** marco.cali@st.com ** -************************************************************************** -* * -* FTS Gesture Utilities * -* * -************************************************************************** -************************************************************************** - -*/ - -#define GESTURE_MASK_SIZE 8 - -#define GESTURE_CUSTOM_POINTS (30*2) -/* for each custom gesture should be provided 30 points (each point is a couple of x,y) */ -#define GESTURE_CUSTOM_NUMBER 5 /* fw support up to 5 custom gestures */ - -#define TEMPLATE_CHUNK (10*2) -/* number of points to transfer with each I2C transaction */ - -/* Gesture IDs */ -#define GES_ID_DBLTAP 0x01 /* Double Tap */ -#define GES_ID_O 0x02 /* 'O' */ -#define GES_ID_C 0x03 /* 'C' */ -#define GES_ID_M 0x04 /* 'M' */ -#define GES_ID_W 0x05 /* 'W' */ -#define GES_ID_E 0x06 /* 'e' */ -#define GES_ID_HFLIP_L2R 0x07 /* Left to right line */ -#define GES_ID_HFLIP_R2L 0x08 /* Right to left line */ -#define GES_ID_VFLIP_T2D 0x09 /* Top to bottom line */ -#define GES_ID_VFLIP_D2T 0x0A /* Bottom to Top line */ -#define GES_ID_L 0x0B /* 'L' */ -#define GES_ID_F 0x0C /* 'F' */ -#define GES_ID_V 0x0D /* 'V' */ -#define GES_ID_AT 0x0E /* '@' */ -#define GES_ID_S 0x0F /* 'S' */ -#define GES_ID_Z 0x10 /* 'Z' */ -#define GES_ID_CUST1 0x11 /* Custom gesture 1 */ -#define GES_ID_CUST2 0x12 /* Custom gesture 2 */ -#define GES_ID_CUST3 0x13 /* Custom gesture 3 */ -#define GES_ID_CUST4 0x14 /* Custom gesture 4 */ -#define GES_ID_CUST5 0x15 /* Custom gesture 5 */ -#define GES_ID_LEFTBRACE 0x20 /* '<' */ -#define GES_ID_RIGHTBRACE 0x21 /* '>' */ - -#define GESTURE_CUSTOM_OFFSET GES_ID_CUST1 - -/* Command sub-type */ -#define GESTURE_ENABLE 0x01 -#define GESTURE_DISABLE 0x02 -#define GESTURE_ENB_CHECK 0x03 -#define GESTURE_START_ADD 0x10 -#define GESTURE_DATA_ADD 0x11 -#define GESTURE_FINISH_ADD 0x12 -#define GETURE_REMOVE_CUSTOM 0x13 -#define GESTURE_CHECK_CUSTOM 0x14 - -/* Event sub-type */ -#define EVENT_TYPE_ENB 0x04 -#define EVENT_TYPE_CHECK_ENB 0x03 -#define EVENT_TYPE_GESTURE_DTC1 0x01 -#define EVENT_TYPE_GESTURE_DTC2 0x02 +/** + * + ************************************************************************** + ** STMicroelectronics ** + ************************************************************************** + ** marco.cali@st.com ** + ************************************************************************** + * * + * FTS Gesture Utilities * + * * + ************************************************************************** + ************************************************************************** + */ +#ifndef _FTS_GESTURE_H_ +#define _FTS_GESTURE_H_ + +#include "ftsHardware.h" + +#define GESTURE_MASK_SIZE 8 + +//max number of gestures coordinates reported +#define GESTURE_COORDS_REPORT_MAX 32 + +// for each custom gesture should be provided 30 +//points (each point is a couple of x,y) +#define GESTURE_CUSTOM_POINTS (30 * 2) + +//fw support up to 5 custom gestures +#define GESTURE_CUSTOM_NUMBER 5 + +#ifdef FTM3 + +//number of points to transfer with each I2C transaction +#define TEMPLATE_CHUNK (10 * 2) +#else +//number of points to transfer with each I2C transaction +#define TEMPLATE_CHUNK (5 * 2) +#endif + + +//Gesture IDs +#define GES_ID_UNKNOWN 0x00 //no meaningful gesture +#define GES_ID_DBLTAP 0x01 //Double Tap +#define GES_ID_O 0x02 //'O' +#define GES_ID_C 0x03 //'C' +#define GES_ID_M 0x04 //'M' +#define GES_ID_W 0x05 //'W' +#define GES_ID_E 0x06 //'e' +#define GES_ID_HFLIP_L2R 0x07 //Left to right line +#define GES_ID_HFLIP_R2L 0x08 //Right to left line +#define GES_ID_VFLIP_T2D 0x09 //Top to bottom line +#define GES_ID_VFLIP_D2T 0x0A //Bottom to Top line +#define GES_ID_L 0x0B //'L' +#define GES_ID_F 0x0C //'F' +#define GES_ID_V 0x0D //'V' +#define GES_ID_AT 0x0E //'@' +#define GES_ID_S 0x0F //'S' +#define GES_ID_Z 0x10 //'Z' +#define GES_ID_CUST1 0x11 //Custom gesture 1 +#define GES_ID_CUST2 0x12 //Custom gesture 2 +#define GES_ID_CUST3 0x13 //Custom gesture 3 +#define GES_ID_CUST4 0x14 //Custom gesture 4 +#define GES_ID_CUST5 0x15 //Custom gesture 5 +#define GES_ID_LEFTBRACE 0x20 //'<' +#define GES_ID_RIGHTBRACE 0x21 //'>' + +#define GESTURE_CUSTOM_OFFSET GES_ID_CUST1 + +//Command sub-type +#define GESTURE_ENABLE 0x01 +#define GESTURE_DISABLE 0x02 +#define GESTURE_ENB_CHECK 0x03 +#define GESTURE_START_ADD 0x10 +#define GESTURE_DATA_ADD 0x11 +#define GESTURE_FINISH_ADD 0x12 +#define GETURE_REMOVE_CUSTOM 0x13 +#define GESTURE_CHECK_CUSTOM 0x14 + + +//Event sub-type +#define EVENT_TYPE_ENB 0x04 +#define EVENT_TYPE_CHECK_ENB 0x03 +#define EVENT_TYPE_GESTURE_DTC1 0x01 +#define EVENT_TYPE_GESTURE_DTC2 0x02 + +int updateGestureMask(u8 *mask, int size, int en); int disableGesture(u8 *mask, int size); int enableGesture(u8 *mask, int size); int startAddCustomGesture(u8 gestureID); @@ -72,3 +112,11 @@ int finishAddCustomGesture(u8 gestureID); int loadCustomGesture(u8 *template, u8 gestureID); int reloadCustomGesture(void); int enterGestureMode(int reload); +int addCustomGesture(u8 *data, int size, u8 gestureID); +int removeCustomGesture(u8 gestureID); +int isAnyGestureActive(void); +int gestureIDtoGestureMask(u8 id, u8 *mask); +int readGestureCoords(u8 *event); +int getGestureCoords(u16 *x, u16 *y); + +#endif diff --git a/drivers/input/touchscreen/st/fts_lib/ftsHardware.h b/drivers/input/touchscreen/st/fts_lib/ftsHardware.h index 933059e671b4..f66555f4cd7a 100644 --- a/drivers/input/touchscreen/st/fts_lib/ftsHardware.h +++ b/drivers/input/touchscreen/st/fts_lib/ftsHardware.h @@ -1,177 +1,212 @@ /* - -************************************************************************** -** STMicroelectronics ** -************************************************************************** -** marco.cali@st.com ** -************************************************************************** -* * -* HW related data * -* * -************************************************************************** -************************************************************************** - -*/ - -#define FTM3_CHIP - -/* DUMMY BYTES DATA */ -#define DUMMY_HW_REG 1 -#define DUMMY_FRAMEBUFFER 1 -#define DUMMY_MEMORY 1 - -/* DIGITAL CHIP INFO */ + * FTS Capacitive touch screen controller (FingerTipS) + * + * Copyright (C) 2016-2018, STMicroelectronics Limited. + * Authors: AMG(Analog Mems Group) + * + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + */ + +/** + ************************************************************************** + ** STMicroelectronics ** + ************************************************************************** + ** marco.cali@st.com ** + ************************************************************************** + * * + * HW related data ** + * * + ************************************************************************** + ************************************************************************** + */ + +#ifndef __FTS_HARDWARE_H +#define __FTS_HARDWARE_H + +//DUMMY BYTES DATA +#define DUMMY_HW_REG 1 +#define DUMMY_FRAMEBUFFER 1 +#define DUMMY_MEMORY 1 + +//DIGITAL CHIP INFO #ifdef FTM3_CHIP -#define DCHIP_ID_0 0x39 -#define DCHIP_ID_1 0x6C +#define DCHIP_ID_0 0x39 +#define DCHIP_ID_1 0x6C #else -#define DCHIP_ID_0 0x36 -#define DCHIP_ID_1 0x70 +#define DCHIP_ID_0 0x36 +#define DCHIP_ID_1 0x70 #endif #ifdef FTM3_CHIP -#define DCHIP_ID_ADDR 0x0007 -#define DCHIP_FW_VER_ADDR 0x000A +#define DCHIP_ID_ADDR 0x0007 +#define DCHIP_FW_VER_ADDR 0x000A #else -#define DCHIP_ID_ADDR 0x0004 -#define DCHIP_FW_VER_ADDR 0x000B +#define DCHIP_ID_ADDR 0x0004 +#define DCHIP_FW_VER_ADDR 0x0008 #endif -#define DCHIP_FW_VER_BYTE 2 +#define DCHIP_FW_VER_BYTE 2 -/* CHUNKS */ -#define READ_CHUNK (2*1024) -#define WRITE_CHUNK (2*1024) -#define MEMORY_CHUNK (2*1024) +//CHUNKS +#define READ_CHUNK (2 * 1024) +#define WRITE_CHUNK (2 * 1024) +#define MEMORY_CHUNK (2 * 1024) -/* PROTOCOL INFO */ +//PROTOCOL INFO #ifdef FTM3_CHIP -#define I2C_SAD 0x49 +#define I2C_SAD 0x49 #else -#define I2C_SAD 0x48 +#define I2C_SAD 0x49 #endif -#define I2C_INTERFACE /* comment if the chip use SPI */ -#define ICR_ADDR 0x0024 -#define ICR_SPI_VALUE 0x02 +#define I2C_INTERFACE //comment if the chip use SPI +#define ICR_ADDR 0x0024 +#define ICR_SPI_VALUE 0x02 -/* SYSTEM RESET INFO */ +//SYSTEM RESET INFO #ifdef FTM3_CHIP -#define SYSTEM_RESET_ADDRESS 0x0023 -#define SYSTEM_RESET_VALUE 0x01 +#define SYSTEM_RESET_ADDRESS 0x0023 +#define SYSTEM_RESET_VALUE 0x01 #else -#define SYSTEM_RESET_ADDRESS 0x0028 -#define SYSTEM_RESET_VALUE 0x80 +#define SYSTEM_RESET_ADDRESS 0x0028 +#define SYSTEM_RESET_VALUE 0x80 #endif -/* INTERRUPT INFO */ +//INTERRUPT INFO #ifdef FTM3_CHIP -#define IER_ADDR 0x001C +#define IER_ADDR 0x001C #else -#define IER_ADDR 0x002C +#define IER_ADDR 0x002C #endif -#define IER_ENABLE 0x41 -#define IER_DISABLE 0x00 +#define IER_ENABLE 0x41 +#define IER_DISABLE 0x00 + +//FLASH COMMAND -/* FLASH COMMAND */ +#define FLASH_CMD_UNLOCK 0xF7 -#define FLASH_CMD_UNLOCK 0xF7 #ifdef FTM3_CHIP -#define FLASH_CMD_WRITE_LOWER_64 0xF0 -#define FLASH_CMD_WRITE_UPPER_64 0xF1 -#define FLASH_CMD_BURN 0xF2 -#define FLASH_CMD_ERASE 0xF3 -#define FLASH_CMD_READSTATUS 0xF4 +#define FLASH_CMD_WRITE_LOWER_64 0xF0 +#define FLASH_CMD_WRITE_UPPER_64 0xF1 +#define FLASH_CMD_BURN 0xF2 +#define FLASH_CMD_ERASE 0xF3 +#define FLASH_CMD_READSTATUS 0xF4 #else -#define FLASH_CMD_WRITE_64K 0xF8 -#define FLASH_CMD_READ_REGISTER 0xF9 -#define FLASH_CMD_WRITE_REGISTER 0xFA +#define FLASH_CMD_WRITE_64K 0xF8 +#define FLASH_CMD_READ_REGISTER 0xF9 +#define FLASH_CMD_WRITE_REGISTER 0xFA #endif -/* FLASH UNLOCK PARAMETER */ -#define FLASH_UNLOCK_CODE0 0x74 -#define FLASH_UNLOCK_CODE1 0x45 +//FLASH UNLOCK PARAMETER +#define FLASH_UNLOCK_CODE0 0x74 +#define FLASH_UNLOCK_CODE1 0x45 #ifndef FTM3_CHIP -/* FLASH ERASE and DMA PARAMETER */ -#define FLASH_ERASE_UNLOCK_CODE0 0x72 -#define FLASH_ERASE_UNLOCK_CODE1 0x03 -#define FLASH_ERASE_UNLOCK_CODE2 0x02 -#define FLASH_ERASE_CODE0 0x02 -#define FLASH_ERASE_CODE1 0xC0 -#define FLASH_DMA_CODE0 0x05 -#define FLASH_DMA_CODE1 0xC0 -#define FLASH_DMA_CONFIG 0x06 +//FLASH ERASE and DMA PARAMETER +#define FLASH_ERASE_UNLOCK_CODE0 0x72 +#define FLASH_ERASE_UNLOCK_CODE1 0x03 +#define FLASH_ERASE_UNLOCK_CODE2 0x02 +#define FLASH_ERASE_CODE0 0x02 +#define FLASH_ERASE_CODE1 0xC0 +#define FLASH_DMA_CODE0 0x05 +#define FLASH_DMA_CODE1 0xC0 +#define FLASH_DMA_CONFIG 0x06 +#define FLASH_ERASE_START 0x80 +#define FLASH_NUM_PAGE 64//number of pages +#define FLASH_CX_PAGE_START 61 +#define FLASH_CX_PAGE_END 62 #endif -/* FLASH ADDRESS */ + +//FLASH ADDRESS #ifdef FTM3_CHIP -#define FLASH_ADDR_SWITCH_CMD 0x00010000 -#define FLASH_ADDR_CODE 0x00000000 -#define FLASH_ADDR_CONFIG 0x0001E800 -#define FLASH_ADDR_CX 0x0001F000 +#define FLASH_ADDR_SWITCH_CMD 0x00010000 +#define FLASH_ADDR_CODE 0x00000000 +#define FLASH_ADDR_CONFIG 0x0001E800 +#define FLASH_ADDR_CX 0x0001F000 #else -#define ADDR_WARM_BOOT 0x001E -#define WARM_BOOT_VALUE 0x38 -#define FLASH_ADDR_CODE 0x00000000 -#define FLASH_ADDR_CONFIG 0x0000FC00 +#define ADDR_WARM_BOOT 0x001E +#define WARM_BOOT_VALUE 0x38 +#define FLASH_ADDR_CODE 0x00000000 +#define FLASH_ADDR_CONFIG 0x0000FC00 #endif -/* CRC ADDR */ + +//CRC ADDR #ifdef FTM3_CHIP -#define ADDR_CRC_BYTE0 0x00 -#define ADDR_CRC_BYTE1 0x86 -#define CRC_MASK 0x02 +#define ADDR_CRC_BYTE0 0x00 +#define ADDR_CRC_BYTE1 0x86 +#define CRC_MASK 0x02 #else -#define ADDR_CRC_BYTE0 0x00 -#define ADDR_CRC_BYTE1 0x74 -#define CRC_MASK 0x03 +#define ADDR_CRC_BYTE0 0x00 +#define ADDR_CRC_BYTE1 0x74 +#define CRC_MASK 0x03 #endif -/* SIZES FW, CODE, CONFIG, MEMH */ +//SIZES FW, CODE, CONFIG, MEMH #ifdef FTM3_CHIP -#define FW_HEADER_SIZE 32 -#define FW_SIZE (int)(128*1024) -#define FW_CODE_SIZE (int)(122*1024) -#define FW_CONFIG_SIZE (int)(2*1024) -#define FW_CX_SIZE (int)(FW_SIZE-FW_CODE_SIZE-FW_CONFIG_SIZE) -#define FW_VER_MEMH_BYTE1 193 -#define FW_VER_MEMH_BYTE0 192 -#define FW_OFF_CONFID_MEMH_BYTE1 2 -#define FW_OFF_CONFID_MEMH_BYTE0 1 -#define FW_BIN_VER_OFFSET 4 -#define FW_BIN_CONFIG_VER_OFFSET (FW_HEADER_SIZE+FW_CODE_SIZE+1) +#define FW_HEADER_SIZE 32 +#define FW_SIZE (int)(128*1024) +#define FW_CODE_SIZE (int)(122*1024) +#define FW_CONFIG_SIZE (int)(2*1024) +#define FW_CX_SIZE (int)(FW_SIZE-FW_CODE_SIZE-FW_CONFIG_SIZE) +#define FW_VER_MEMH_BYTE1 193 +#define FW_VER_MEMH_BYTE0 192 +#define FW_OFF_CONFID_MEMH_BYTE1 2 +#define FW_OFF_CONFID_MEMH_BYTE0 1 +#define FW_BIN_VER_OFFSET 4 +#define FW_BIN_CONFIG_VER_OFFSET (FW_HEADER_SIZE+FW_CODE_SIZE+1) #else -#define FW_HEADER_SIZE 64 -#define FW_HEADER_SIGNATURE 0xAA55AA55 -#define FW_FTB_VER 0x00000001 -#define FW_BYTES_ALIGN 4 -#define FW_BIN_VER_OFFSET 16 -#define FW_BIN_CONFIG_VER_OFFSET 20 +#define FW_HEADER_SIZE 64 +#define FW_HEADER_SIGNATURE 0xAA55AA55 +#define FW_FTB_VER 0x00000001 +#define FW_BYTES_ALIGN 4 +#define FW_BIN_VER_OFFSET 16 +#define FW_BIN_CONFIG_VER_OFFSET 20 #endif -/* FIFO */ -#define FIFO_EVENT_SIZE 8 +//FIFO +#define FIFO_EVENT_SIZE 8 + #ifdef FTM3_CHIP -#define FIFO_DEPTH 32 +#define FIFO_DEPTH 32 #else -#define FIFO_DEPTH 64 +#define FIFO_DEPTH 64 #endif -#define FIFO_CMD_READONE 0x85 -#define FIFO_CMD_READALL 0x86 -#define FIFO_CMD_LAST 0x87 -#define FIFO_CMD_FLUSH 0xA1 +#define FIFO_CMD_READONE 0x85 +#define FIFO_CMD_READALL 0x86 +#define FIFO_CMD_LAST 0x87 +#define FIFO_CMD_FLUSH 0xA1 -/* CONSTANT TOTAL CX */ -#define CX1_WEIGHT 4 -#define CX2_WEIGHT 1 -/* OP CODES FOR MEMORY (based on protocol) */ +//CONSTANT TOTAL CX +#ifdef FTM3_CHIP +#define CX1_WEIGHT 4 +#define CX2_WEIGHT 1 +#else +#define CX1_WEIGHT 8 +#define CX2_WEIGHT 1 +#endif -#define FTS_CMD_HW_REG_R 0xB6 -#define FTS_CMD_HW_REG_W 0xB6 -#define FTS_CMD_FRAMEBUFFER_R 0xD0 -#define FTS_CMD_FRAMEBUFFER_W 0xD0 +//OP CODES FOR MEMORY (based on protocol) + +#define FTS_CMD_HW_REG_R 0xB6 +#define FTS_CMD_HW_REG_W 0xB6 +#define FTS_CMD_FRAMEBUFFER_R 0xD0 +#define FTS_CMD_FRAMEBUFFER_W 0xD0 + +#endif diff --git a/drivers/input/touchscreen/st/fts_lib/ftsIO.c b/drivers/input/touchscreen/st/fts_lib/ftsIO.c index 96ca8cfecd8a..a1f3862d61f4 100644 --- a/drivers/input/touchscreen/st/fts_lib/ftsIO.c +++ b/drivers/input/touchscreen/st/fts_lib/ftsIO.c @@ -1,20 +1,37 @@ /* - -************************************************************************** -** STMicroelectronics ** -************************************************************************** -** marco.cali@st.com ** -************************************************************************** -* * -* I2C/SPI Communication * -* * -************************************************************************** -************************************************************************** - -*/ - -#include "ftsSoftware.h" -#include "ftsCrossCompile.h" + * FTS Capacitive touch screen controller (FingerTipS) + * + * Copyright (C) 2016-2018, STMicroelectronics Limited. + * Authors: AMG(Analog Mems Group) + * + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + */ + +/** + * + ************************************************************************** + ** STMicroelectronics ** + ************************************************************************** + ** marco.cali@st.com ** + ************************************************************************** + * * + * I2C/SPI Communication ** + * * + ************************************************************************** + ************************************************************************** + * + */ #include #include @@ -40,29 +57,31 @@ #include #include #include -/* #include */ #include #include #include -static struct i2c_client *client; -static u16 I2CSAD; +#include "ftsSoftware.h" +#include "ftsCrossCompile.h" #include "ftsError.h" #include "ftsHardware.h" #include "ftsIO.h" #include "ftsTool.h" static char tag[8] = "[ FTS ]\0"; +static struct i2c_client *client; +static u16 I2CSAD; + int openChannel(struct i2c_client *clt) { client = clt; I2CSAD = clt->addr; - logError(1, "%s openChannel: SAD: %02X\n", tag, I2CSAD); + logError(1, "%s %s: SAD: %02X\n", tag, __func__, I2CSAD); return OK; } -struct device *getDev(void) +struct device *getDev() { if (client != NULL) return &(client->dev); @@ -70,7 +89,7 @@ struct device *getDev(void) return NULL; } -struct i2c_client *getClient(void) +struct i2c_client *getClient() { if (client != NULL) return client; @@ -82,15 +101,15 @@ int fts_readCmd(u8 *cmd, int cmdLength, u8 *outBuf, int byteToRead) { int ret = -1; int retry = 0; - struct i2c_msg I2CMsg[2]; + struct i2c_msg I2CMsg[2]; - /* write msg */ + //write msg I2CMsg[0].addr = (__u16)I2CSAD; I2CMsg[0].flags = (__u16)0; I2CMsg[0].len = (__u16)cmdLength; I2CMsg[0].buf = (__u8 *)cmd; - /* read msg */ + //read msg I2CMsg[1].addr = (__u16)I2CSAD; I2CMsg[1].flags = I2C_M_RD; I2CMsg[1].len = byteToRead; @@ -100,13 +119,13 @@ int fts_readCmd(u8 *cmd, int cmdLength, u8 *outBuf, int byteToRead) return ERROR_I2C_O; while (retry < I2C_RETRY && ret < OK) { ret = i2c_transfer(client->adapter, I2CMsg, 2); - if (ret >= OK) - break; retry++; - msleep(I2C_WAIT_BEFORE_RETRY); + if (ret < OK) + msleep(I2C_WAIT_BEFORE_RETRY); } if (ret < 0) { - logError(1, "%s fts_readCmd: ERROR %02X\n", tag, ERROR_I2C_R); + logError(1, "%s %s: ERROR %02X\n", + tag, __func__, ERROR_I2C_R); return ERROR_I2C_R; } return OK; @@ -116,7 +135,7 @@ int fts_writeCmd(u8 *cmd, int cmdLength) { int ret = -1; int retry = 0; - struct i2c_msg I2CMsg[2]; + struct i2c_msg I2CMsg[1]; I2CMsg[0].addr = (__u16)I2CSAD; I2CMsg[0].flags = (__u16)0; @@ -124,17 +143,16 @@ int fts_writeCmd(u8 *cmd, int cmdLength) I2CMsg[0].buf = (__u8 *)cmd; if (client == NULL) -return ERROR_I2C_O; + return ERROR_I2C_O; while (retry < I2C_RETRY && ret < OK) { ret = i2c_transfer(client->adapter, I2CMsg, 1); - if (ret >= OK) - break; retry++; - msleep(I2C_WAIT_BEFORE_RETRY); - /* logError(1, "%s fts_writeCmd: attempt %d\n", tag, retry); */ + if (ret < OK) + msleep(I2C_WAIT_BEFORE_RETRY); + //logError(1,"%s fts_writeCmd: attempt %d\n", tag, retry); } if (ret < 0) { - logError(1, "%s fts_writeCmd: ERROR %02X\n", tag, ERROR_I2C_W); + logError(1, "%s %s: ERROR %02X\n", tag, __func__, ERROR_I2C_W); return ERROR_I2C_W; } return OK; @@ -145,7 +163,7 @@ int fts_writeFwCmd(u8 *cmd, int cmdLength) int ret = -1; int ret2 = -1; int retry = 0; - struct i2c_msg I2CMsg[2]; + struct i2c_msg I2CMsg[1]; I2CMsg[0].addr = (__u16)I2CSAD; I2CMsg[0].flags = (__u16)0; @@ -153,48 +171,49 @@ int fts_writeFwCmd(u8 *cmd, int cmdLength) I2CMsg[0].buf = (__u8 *)cmd; if (client == NULL) -return ERROR_I2C_O; + return ERROR_I2C_O; while (retry < I2C_RETRY && (ret < OK || ret2 < OK)) { ret = i2c_transfer(client->adapter, I2CMsg, 1); retry++; - if (ret >= 0) { + if (ret >= 0) ret2 = checkEcho(cmd, cmdLength); - break; - } - msleep(I2C_WAIT_BEFORE_RETRY); - /* logError(1, "%s fts_writeCmd: attempt %d\n", tag, retry); */ + if (ret < OK || ret2 < OK) + msleep(I2C_WAIT_BEFORE_RETRY); + //logError(1,"%s fts_writeCmd: attempt %d\n", tag, retry); } if (ret < 0) { - logError(1, "%s fts_writeFwCmd: ERROR %02X\n", tag, ERROR_I2C_W); + logError(1, "%s %s: ERROR %02X\n", + tag, __func__, ERROR_I2C_W); return ERROR_I2C_W; } if (ret2 < OK) { - logError(1, "%s fts_writeFwCmd: check echo ERROR %02X\n", tag, ret2); - return (ret|ERROR_I2C_W); + logError(1, "%s %s: check echo ERROR %02X\n", + tag, __func__, ret2); + return (ret | ERROR_I2C_W); } return OK; } + int writeReadCmd(u8 *writeCmd1, int writeCmdLength, u8 *readCmd1, int readCmdLength, u8 *outBuf, int byteToRead) { int ret = -1; int retry = 0; - struct i2c_msg I2CMsg[3]; - - /* write msg */ + struct i2c_msg I2CMsg[3]; + //write msg I2CMsg[0].addr = (__u16)I2CSAD; I2CMsg[0].flags = (__u16)0; I2CMsg[0].len = (__u16)writeCmdLength; I2CMsg[0].buf = (__u8 *)writeCmd1; - /* write msg */ + //write msg I2CMsg[1].addr = (__u16)I2CSAD; I2CMsg[1].flags = (__u16)0; I2CMsg[1].len = (__u16)readCmdLength; I2CMsg[1].buf = (__u8 *)readCmd1; - /* read msg */ + //read msg I2CMsg[2].addr = (__u16)I2CSAD; I2CMsg[2].flags = I2C_M_RD; I2CMsg[2].len = byteToRead; @@ -204,30 +223,31 @@ int writeReadCmd(u8 *writeCmd1, int writeCmdLength, u8 *readCmd1, return ERROR_I2C_O; while (retry < I2C_RETRY && ret < OK) { ret = i2c_transfer(client->adapter, I2CMsg, 3); - if (ret >= OK) - break; retry++; - msleep(I2C_WAIT_BEFORE_RETRY); + if (ret < OK) + msleep(I2C_WAIT_BEFORE_RETRY); } if (ret < 0) { - logError(1, "%s writeReadCmd: ERROR %02X\n", tag, ERROR_I2C_WR); - return ERROR_I2C_WR; + logError(1, "%s %s: ERROR %02X\n", + tag, __func__, ERROR_I2C_WR); + return ERROR_I2C_WR; } return OK; - } -int readCmdU16(u8 cmd, u16 address, u8 *outBuf, int byteToRead, int hasDummyByte) -{ +int readCmdU16(u8 cmd, u16 address, u8 *outBuf, int byteToRead, + int hasDummyByte) +{ int remaining = byteToRead; int toRead = 0; u8 rCmd[3] = { cmd, 0x00, 0x00 }; - u8 *buff = (u8 *)kmalloc((READ_CHUNK + 1)*sizeof(u8), GFP_KERNEL); + u8 *buff = (u8 *)kmalloc_array(READ_CHUNK + 1, sizeof(u8), GFP_KERNEL); + if (buff == NULL) { - logError(1, "%s readCmdU16: ERROR %02X\n", tag, ERROR_ALLOC); + logError(1, "%s %s: ERROR %02X\n", tag, __func__, ERROR_ALLOC); return ERROR_ALLOC; } @@ -245,7 +265,9 @@ int readCmdU16(u8 cmd, u16 address, u8 *outBuf, int byteToRead, int hasDummyByte if (hasDummyByte) { if (fts_readCmd(rCmd, 3, buff, toRead + 1) < 0) { - logError(1, "%s readCmdU16: ERROR %02X\n", tag, ERROR_I2C_R); + logError(1, "%s %s: ERROR %02X\n", + tag, __func__, ERROR_I2C_R); + kfree(buff); return ERROR_I2C_R; } memcpy(outBuf, buff + 1, toRead); @@ -256,24 +278,23 @@ int readCmdU16(u8 cmd, u16 address, u8 *outBuf, int byteToRead, int hasDummyByte } address += toRead; - outBuf += toRead; - } kfree(buff); return OK; } + int writeCmdU16(u8 WriteCmd, u16 address, u8 *dataToWrite, int byteToWrite) { - int remaining = byteToWrite; int toWrite = 0; - u8 *buff = (u8 *)kmalloc((WRITE_CHUNK + 3)*sizeof(u8), GFP_KERNEL); + u8 *buff = (u8 *)kmalloc_array(WRITE_CHUNK + 3, sizeof(u8), GFP_KERNEL); + if (buff == NULL) { - logError(1, "%s writeCmdU16: ERROR %02X\n", tag, ERROR_ALLOC); + logError(1, "%s %s: ERROR %02X\n", tag, __func__, ERROR_ALLOC); return ERROR_ALLOC; } @@ -292,31 +313,38 @@ int writeCmdU16(u8 WriteCmd, u16 address, u8 *dataToWrite, int byteToWrite) buff[2] = (u8)(address & 0xFF); memcpy(buff + 3, dataToWrite, toWrite); if (fts_writeCmd(buff, 3 + toWrite) < 0) { - logError(1, "%s writeCmdU16: ERROR %02\n", tag, ERROR_I2C_W); + logError(1, "%s %s: ERROR %02\n", + tag, __func__, ERROR_I2C_W); + kfree(buff); return ERROR_I2C_W; } address += toWrite; dataToWrite += toWrite; - } + kfree(buff); return OK; } -int writeCmdU32(u8 writeCmd1, u8 writeCmd2, u32 address, u8 *dataToWrite, int byteToWrite) +int writeCmdU32(u8 writeCmd1, u8 writeCmd2, u32 address, u8 *dataToWrite, + int byteToWrite) { - int remaining = byteToWrite; int toWrite = 0; + int ret; u8 buff1[3] = { writeCmd1, 0x00, 0x00 }; - u8 *buff2 = (u8 *)kmalloc((WRITE_CHUNK + 3)*sizeof(u8), GFP_KERNEL); + u8 *buff2 = (u8 *)kmalloc_array(WRITE_CHUNK + 3, + sizeof(u8), GFP_KERNEL); + if (buff2 == NULL) { - logError(1, "%s writeCmdU32: ERROR %02X\n", tag, ERROR_ALLOC); + logError(1, "%s %s: ERROR %02X\n", + tag, __func__, ERROR_ALLOC); return ERROR_ALLOC; } buff2[0] = writeCmd2; + while (remaining > 0) { if (remaining >= WRITE_CHUNK) { toWrite = WRITE_CHUNK; @@ -333,33 +361,41 @@ int writeCmdU32(u8 writeCmd1, u8 writeCmd2, u32 address, u8 *dataToWrite, int by memcpy(buff2 + 3, dataToWrite, toWrite); if (fts_writeCmd(buff1, 3) < 0) { - logError(1, "%s writeCmdU32: ERROR %02X\n", tag, ERROR_I2C_W); - return ERROR_I2C_W; + logError(1, "%s %s: ERROR %02X\n", + tag, __func__, ERROR_I2C_W); + ret = ERROR_I2C_W; + goto END; } if (fts_writeCmd(buff2, 3 + toWrite) < 0) { - logError(1, "%s writeCmdU32: ERROR %02X\n", tag, ERROR_I2C_W); - return ERROR_I2C_W; + logError(1, "%s %s: ERROR %02X\n", + tag, __func__, ERROR_I2C_W); + ret = ERROR_I2C_W; + goto END; } address += toWrite; dataToWrite += toWrite; - } - return OK; + ret = OK; +END: + kfree(buff2); + return ret; } -int writeReadCmdU32(u8 wCmd, u8 rCmd, u32 address, u8 *outBuf, int byteToRead, int hasDummyByte) +int writeReadCmdU32(u8 wCmd, u8 rCmd, u32 address, u8 *outBuf, + int byteToRead, int hasDummyByte) { - int remaining = byteToRead; int toRead = 0; u8 reaCmd[3]; u8 wriCmd[3]; - u8 *buff = (u8 *)kmalloc((READ_CHUNK + 1)*sizeof(u8), GFP_KERNEL); + u8 *buff = (u8 *)kmalloc_array(READ_CHUNK + 1, sizeof(u8), GFP_KERNEL); + if (buff == NULL) { - logError(1, "%s writereadCmd32: ERROR %02X\n", tag, ERROR_ALLOC); + logError(1, "%s writereadCmd32: ERROR %02X\n", + tag, ERROR_ALLOC); return ERROR_ALLOC; } @@ -382,22 +418,25 @@ int writeReadCmdU32(u8 wCmd, u8 rCmd, u32 address, u8 *outBuf, int byteToRead, i reaCmd[2] = (u8)(address & 0x000000FF); if (hasDummyByte) { - if (writeReadCmd(wriCmd, 3, reaCmd, 3, buff, toRead + 1) < 0) { - logError(1, "%s writeCmdU32: ERROR %02X\n", tag, ERROR_I2C_WR); + if (writeReadCmd(wriCmd, 3, reaCmd, 3, + buff, toRead + 1) < 0) { + logError(1, "%s writeCmdU32: ERROR %02X\n", + tag, ERROR_I2C_WR); + kfree(buff); return ERROR_I2C_WR; } memcpy(outBuf, buff + 1, toRead); } else { - if (writeReadCmd(wriCmd, 3, reaCmd, 3, buff, toRead) < 0) + if (writeReadCmd(wriCmd, 3, reaCmd, + 3, buff, toRead) < 0) return ERROR_I2C_WR; memcpy(outBuf, buff, toRead); } address += toRead; - outBuf += toRead; - } + kfree(buff); return OK; } diff --git a/drivers/input/touchscreen/st/fts_lib/ftsIO.h b/drivers/input/touchscreen/st/fts_lib/ftsIO.h index 7bdeda2f9a2d..8e84104e5014 100644 --- a/drivers/input/touchscreen/st/fts_lib/ftsIO.h +++ b/drivers/input/touchscreen/st/fts_lib/ftsIO.h @@ -1,26 +1,48 @@ /* + * FTS Capacitive touch screen controller (FingerTipS) + * + * Copyright (C) 2016-2018, STMicroelectronics Limited. + * Authors: AMG(Analog Mems Group) + * + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + */ -************************************************************************** -** STMicroelectronics ** -************************************************************************** -** marco.cali@st.com ** -************************************************************************** -* * -* I2C/SPI Communication * -* * -************************************************************************** -************************************************************************** +/** + * + ************************************************************************** + ** STMicroelectronics ** + ************************************************************************** + ** marco.cali@st.com ** + ************************************************************************** + * * + * I2C/SPI Communication ** + * * + ************************************************************************** + ************************************************************************** + */ -*/ - -#include "ftsSoftware.h" -#include "ftsCrossCompile.h" +#ifndef __FTS_IO_H +#define __FTS_IO_H #include #include -#define I2C_RETRY 3 /* number */ -#define I2C_WAIT_BEFORE_RETRY 10 /* ms */ +#include "ftsSoftware.h" +#include "ftsCrossCompile.h" + +#define I2C_RETRY 3 //number of retry +#define I2C_WAIT_BEFORE_RETRY 2 //ms int openChannel(struct i2c_client *clt); struct device *getDev(void); @@ -28,8 +50,14 @@ struct i2c_client *getClient(void); int fts_readCmd(u8 *cmd, int cmdLenght, u8 *outBuf, int byteToRead); int fts_writeCmd(u8 *cmd, int cmdLenght); int fts_writeFwCmd(u8 *cmd, int cmdLenght); -int writeReadCmd(u8 *writeCmd, int writeCmdLenght, u8 *readCmd, int readCmdLenght, u8 *outBuf, int byteToRead); -int readCmdU16(u8 cmd, u16 address, u8 *outBuf, int byteToRead, int hasDummyByte); +int writeReadCmd(u8 *writeCmd, int writeCmdLenght, u8 *readCmd, + int readCmdLenght, u8 *outBuf, int byteToRead); +int readCmdU16(u8 cmd, u16 address, u8 *outBuf, int byteToRead, + int hasDummyByte); int writeCmdU16(u8 WriteCmd, u16 address, u8 *dataToWrite, int byteToWrite); -int writeCmdU32(u8 writeCmd1, u8 writeCmd2, u32 address, u8 *dataToWrite, int byteToWrite); -int writeReadCmdU32(u8 wCmd, u8 rCmd, u32 address, u8 *outBuf, int byteToRead, int hasDummyByte); +int writeCmdU32(u8 writeCmd1, u8 writeCmd2, u32 address, u8 *dataToWrite, + int byteToWrite); +int writeReadCmdU32(u8 wCmd, u8 rCmd, u32 address, u8 *outBuf, int byteToRead, + int hasDummyByte); + +#endif diff --git a/drivers/input/touchscreen/st/fts_lib/ftsSoftware.h b/drivers/input/touchscreen/st/fts_lib/ftsSoftware.h index c8bbc8e18d28..82b1d18571cd 100644 --- a/drivers/input/touchscreen/st/fts_lib/ftsSoftware.h +++ b/drivers/input/touchscreen/st/fts_lib/ftsSoftware.h @@ -1,131 +1,190 @@ /* + * FTS Capacitive touch screen controller (FingerTipS) + * + * Copyright (C) 2016-2018, STMicroelectronics Limited. + * Authors: AMG(Analog Mems Group) + * + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + */ -************************************************************************** -** STMicroelectronics ** -************************************************************************** -** marco.cali@st.com ** -************************************************************************** -* * -* FW related data * -* * -************************************************************************** -************************************************************************** +/** + * + ************************************************************************* + ** STMicroelectronics ** + ************************************************************************** + ** marco.cali@st.com ** + ************************************************************************** + * * + * FW related data * + * * + ************************************************************************** + ************************************************************************** + * + */ -*/ +#ifndef __FTS_SOFTWARE_H +#define __FTS_SOFTWARE_H + +#include #include "ftsHardware.h" -typedef unsigned char u8; -typedef unsigned short u16; -typedef unsigned int u32; - -#define ECHO_ENABLED 0x00000001 - -/* chipInfo ftsInfo; */ - -/* FTS FW COMAND */ -#define FTS_CMD_MS_MT_SENSE_OFF 0x92 -#define FTS_CMD_MS_MT_SENSE_ON 0x93 -#define FTS_CMD_SS_HOVER_OFF 0x94 -#define FTS_CMD_SS_HOVER_ON 0x95 -#define FTS_CMD_LP_TIMER_CALIB 0x97 -#define FTS_CMD_MS_KEY_OFF 0x9A -#define FTS_CMD_MS_KEY_ON 0x9B -#define FTS_CMD_MS_COMP_TUNING 0xA3 -#define FTS_CMD_SS_COMP_TUNING 0xA4 -#define FTS_CMD_FULL_INITIALIZATION 0xA5 -#define FTS_CMD_ITO_CHECK 0xA7 -#define FTS_CMD_RELEASE_INFO 0xAA -#define FTS_CMD_GESTURE_MODE 0xAD -#define FTS_CMD_REQU_FW_CONF 0xB2 -#define FTS_CMD_REQU_FRAME_DATA 0xB7 -#define FTS_CMD_REQU_COMP_DATA 0xB8 -#define FTS_CMD_WRITE_MP_FLAG 0xC0 -#define FTS_CMD_FEATURE_ENABLE 0xC1 -#define FTS_CMD_FEATURE_DISABLE 0xC2 -#define FTS_CMD_GESTURE_CMD 0xC3 -#define FTS_CMD_SAVE_CX_TUNING 0xFC - -/* Event ID */ -#define EVENTID_NO_EVENT 0x00 -#define EVENTID_ERROR_EVENT 0x0F -#define EVENTID_CONTROL_READY 0x10 -#define EVENTID_FW_CONFIGURATION 0x12 -#define EVENTID_COMP_DATA_READ 0x13 -#define EVENTID_STATUS_UPDATE 0x16 -#define EVENTID_RELEASE_INFO 0x1C -#define EVENTID_ENTER_POINTER 0x03 -#define EVENTID_LEAVE_POINTER 0x04 -#define EVENTID_MOTION_POINTER 0x05 -#define EVENTID_HOVER_ENTER_POINTER 0x07 -#define EVENTID_HOVER_LEAVE_POINTER 0x08 -#define EVENTID_HOVER_MOTION_POINTER 0x09 -#define EVENTID_PROXIMITY_ENTER 0x0B -#define EVENTID_PROXIMITY_LEAVE 0x0C -#define EVENTID_KEY_STATUS 0x0E -#define EVENTID_GESTURE 0x22 -#define EVENTID_FRAME_DATA_READ 0x25 -#define EVENTID_ECHO 0xEC -#define EVENTID_LAST (EVENTID_FRAME_DATA_READ+1) - -/* EVENT TYPE */ -#define EVENT_TYPE_MS_TUNING_CMPL 0x01 -#define EVENT_TYPE_SS_TUNING_CMPL 0x02 -#define EVENT_TYPE_COMP_DATA_SAVED 0x04 -#define EVENT_TYPE_ITO 0x05 -#define EVENT_TYPE_FULL_INITIALIZATION 0x07 -#define EVENT_TYPE_LPTIMER_TUNING_CMPL 0x20 -#define EVENT_TYPE_ESD_ERROR 0x0A -#define EVENT_TYPE_WATCHDOG_ERROR 0x01 - -/* CONFIG ID INFO */ -#define CONFIG_ID_ADDR 0x0001 -#define CONFIG_ID_BYTE 2 - -/* ADDRESS OFFSET IN SYSINFO */ -#define ADDR_RAW_TOUCH 0x0000 -#define ADDR_FILTER_TOUCH 0x0002 -#define ADDR_NORM_TOUCH 0x0004 -#define ADDR_CALIB_TOUCH 0x0006 -#define ADDR_RAW_HOVER_FORCE 0x000A -#define ADDR_RAW_HOVER_SENSE 0x000C -#define ADDR_FILTER_HOVER_FORCE 0x000E -#define ADDR_FILTER_HOVER_SENSE 0x0010 -#define ADDR_NORM_HOVER_FORCE 0x0012 -#define ADDR_NORM_HOVER_SENSE 0x0014 -#define ADDR_CALIB_HOVER_FORCE 0x0016 -#define ADDR_CALIB_HOVER_SENSE 0x0018 -#define ADDR_RAW_PRX_FORCE 0x001A -#define ADDR_RAW_PRX_SENSE 0x001C -#define ADDR_FILTER_PRX_FORCE 0x001E -#define ADDR_FILTER_PRX_SENSE 0x0020 -#define ADDR_NORM_PRX_FORCE 0x0022 -#define ADDR_NORM_PRX_SENSE 0x0024 -#define ADDR_CALIB_PRX_FORCE 0x0026 -#define ADDR_CALIB_PRX_SENSE 0x0028 -#define ADDR_RAW_MS_KEY 0x0032 -#define ADDR_COMP_DATA 0x0050 -#define ADDR_FRAMEBUFFER_DATA 0x8000 - -/* ADDRESS FW REGISTER */ -#define ADDR_SENSE_LEN 0x0014 -#define ADDR_FORCE_LEN 0x0015 -#define ADDR_MS_TUNING_VER 0x0729 -#define ADDR_SS_TUNING_VER 0x074E - -/* B2 INFO */ -#define B2_DATA_BYTES 4 -#define B2_CHUNK ((FIFO_DEPTH/2)*B2_DATA_BYTES) /* number of bytes */ - -/* FEATURES */ -#define FEAT_GESTURE 0x00 -#define FEAT_GLOVE 0x01 -#define FEAT_STYLUS 0x02 -#define FEAT_COVER 0x04 -#define FEAT_CHARGER 0x08 -#define FEAT_VR 0x10 -#define FEAT_EDGE_REJECTION 0x20 - -/* MP_FLAG_VALUE */ -#define INIT_MP 0xA5A5A501 -#define INIT_FIELD 0xA5A5A502 +#define ECHO_ENABLED 0x00000001 + +//FTS FW COMMAND +#define FTS_CMD_MS_MT_SENSE_OFF 0x92 +#define FTS_CMD_MS_MT_SENSE_ON 0x93 +#define FTS_CMD_SS_HOVER_OFF 0x94 +#define FTS_CMD_SS_HOVER_ON 0x95 +#define FTS_CMD_LP_TIMER_CALIB 0x97 +#define FTS_CMD_MS_KEY_OFF 0x9A +#define FTS_CMD_MS_KEY_ON 0x9B +#define FTS_CMD_MS_COMP_TUNING 0xA3 +#define FTS_CMD_SS_COMP_TUNING 0xA4 +#define FTS_CMD_FULL_INITIALIZATION 0xA5 +#define FTS_CMD_ITO_CHECK 0xA7 +#define FTS_CMD_RELEASE_INFO 0xAA +#define FTS_CMD_GESTURE_MODE 0xAD +#define FTS_CMD_REQU_FW_CONF 0xB2 +#define FTS_CMD_REQU_FRAME_DATA 0xB7 +#define FTS_CMD_REQU_COMP_DATA 0xB8 +#define FTS_CMD_WRITE_MP_FLAG 0xC0 +#define FTS_CMD_FEATURE_ENABLE 0xC1 +#define FTS_CMD_FEATURE_DISABLE 0xC2 +#define FTS_CMD_GESTURE_CMD 0xC3 +#define FTS_CMD_LOCKDOWN_CMD 0xC4 +#define FTS_CMD_NOISE_WRITE 0xC7 +#define FTS_CMD_NOISE_READ 0xC8 +#define FTS_CMD_LOCKDOWN_FILL 0xCA +#define FTS_CMD_LOCKDOWN_WRITE 0xCB +#define FTS_CMD_LOCKDOWN_READ 0xCC +#define FTS_CMD_SAVE_CX_TUNING 0xFC + +//Event ID +#define EVENTID_NO_EVENT 0x00 +#define EVENTID_ERROR_EVENT 0x0F +#define EVENTID_CONTROL_READY 0x10 +#define EVENTID_FW_CONFIGURATION 0x12 +#define EVENTID_COMP_DATA_READ 0x13 +#define EVENTID_STATUS_UPDATE 0x16 +#define EVENTID_RELEASE_INFO 0x1C +#define EVENTID_LOCKDOWN_INFO 0x1E +#define EVENTID_ENTER_POINTER 0x03 +#define EVENTID_LEAVE_POINTER 0x04 +#define EVENTID_MOTION_POINTER 0x05 +#define EVENTID_HOVER_ENTER_POINTER 0x07 +#define EVENTID_HOVER_LEAVE_POINTER 0x08 +#define EVENTID_HOVER_MOTION_POINTER 0x09 +#define EVENTID_PROXIMITY_ENTER 0x0B +#define EVENTID_PROXIMITY_LEAVE 0x0C +#define EVENTID_KEY_STATUS 0x0E +#define EVENTID_LOCKDOWN_INFO_READ 0x1E +#define EVENTID_NOISE_READ 0x17 +#define EVENTID_NOISE_WRITE 0x18 +#define EVENTID_GESTURE 0x22 +#define EVENTID_FRAME_DATA_READ 0x25 +#define EVENTID_ECHO 0xEC +#define EVENTID_LAST (EVENTID_FRAME_DATA_READ+1) + +//EVENT TYPE +#define EVENT_TYPE_MS_TUNING_CMPL 0x01 +#define EVENT_TYPE_SS_TUNING_CMPL 0x02 +#define EVENT_TYPE_COMP_DATA_SAVED 0x04 +#define EVENT_TYPE_ITO 0x05 +#define EVENT_TYPE_FULL_INITIALIZATION 0x07 +#define EVENT_TYPE_LPTIMER_TUNING_CMPL 0x20 +#define EVENT_TYPE_ESD_ERROR 0x0A +#define EVENT_TYPE_WATCHDOG_ERROR 0x01 +#define EVENT_TYPE_CHECKSUM_ERROR 0x03 +#define EVENT_TYPE_LOCKDOWN 0x0A +#define EVENT_TYPE_LOCKDOWN_WRITE 0x08 +#define EVENT_TYPE_LOCKDOWN_ERROR 0x0B + +//CRC type +#define CRC_CONFIG_SIGNATURE 0x01 +#define CRC_CONFIG 0x02 +#define CRC_CX_MEMORY 0x03 + +// CONFIG ID INFO +#define CONFIG_ID_ADDR 0x0001 +#define CONFIG_ID_BYTE 2 + +//ADDRESS OFFSET IN SYSINFO +#define ADDR_RAW_TOUCH 0x0000 +#define ADDR_FILTER_TOUCH 0x0002 +#define ADDR_NORM_TOUCH 0x0004 +#define ADDR_CALIB_TOUCH 0x0006 +#define ADDR_RAW_HOVER_FORCE 0x000A +#define ADDR_RAW_HOVER_SENSE 0x000C +#define ADDR_FILTER_HOVER_FORCE 0x000E +#define ADDR_FILTER_HOVER_SENSE 0x0010 +#define ADDR_NORM_HOVER_FORCE 0x0012 +#define ADDR_NORM_HOVER_SENSE 0x0014 +#define ADDR_CALIB_HOVER_FORCE 0x0016 +#define ADDR_CALIB_HOVER_SENSE 0x0018 +#define ADDR_RAW_PRX_FORCE 0x001A +#define ADDR_RAW_PRX_SENSE 0x001C +#define ADDR_FILTER_PRX_FORCE 0x001E +#define ADDR_FILTER_PRX_SENSE 0x0020 +#define ADDR_NORM_PRX_FORCE 0x0022 +#define ADDR_NORM_PRX_SENSE 0x0024 +#define ADDR_CALIB_PRX_FORCE 0x0026 +#define ADDR_CALIB_PRX_SENSE 0x0028 +#define ADDR_RAW_MS_KEY 0x0032 +#define ADDR_NORM_MS_KEY 0x0036 +#define ADDR_COMP_DATA 0x0050 +#define ADDR_FRAMEBUFFER_DATA 0x8000 + +//ADDRESS FW REGISTER +#define ADDR_SENSE_LEN 0x0014 +#define ADDR_FORCE_LEN 0x0015 +#define ADDR_MS_TUNING_VER 0x0729 +#define ADDR_SS_TUNING_VER 0x074E + +//B2 INFO +#define B2_DATA_BYTES 4 +//number of bytes +#define B2_CHUNK ((FIFO_DEPTH/2)*B2_DATA_BYTES) + +//FEATURES +#define FEAT_GLOVE 0x00000001 +#define FEAT_STYLUS 0x00000002 +#define FEAT_COVER 0x00000004 +#define FEAT_CHARGER 0x00000008 +#define FEAT_VR 0x00000010 +#define FEAT_EDGE_REJECTION 0x00000020 +#define FEAT_CORNER_REJECTION 0x00000040 +#define FEAT_EDGE_PALM_REJECTION 0x00000100 + +//TOUCH SIZE +#define STYLUS_SIZE 0x01 +#define FINGER_SIZE 0x02 +#define LARGE_SIZE 0x03 + +//C7/C8 parameters +#define NOISE_PARAMETERS 0x01 + +//MP_FLAG_VALUE +#define INIT_MP 0xA5A5A501 +#define INIT_FIELD 0xA5A5A502 + +//NOISE PARAMS +#define NOISE_PARAMETERS_SIZE 4 //bytes + +//ERROR INFO +#define ERROR_INFO_SIZE (20*4) // bytes +#define ERROR_SIGNATURE 0xFA5005AF +#define ERROR_SIGN_HEAD 0xA5 + +#endif diff --git a/drivers/input/touchscreen/st/fts_lib/ftsTest.c b/drivers/input/touchscreen/st/fts_lib/ftsTest.c index 3810fd02001a..edcdee2d1dc1 100644 --- a/drivers/input/touchscreen/st/fts_lib/ftsTest.c +++ b/drivers/input/touchscreen/st/fts_lib/ftsTest.c @@ -1,30 +1,38 @@ /* + * FTS Capacitive touch screen controller (FingerTipS) + * + * Copyright (C) 2016-2018, STMicroelectronics Limited. + * Authors: AMG(Analog Mems Group) + * + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + */ +/* + * ************************************************************************** - ** STMicroelectronics ** + ** STMicroelectronics ** ************************************************************************** - ** marco.cali@st.com ** + ** marco.cali@st.com ** ************************************************************************** * * - * FTS API for MP test * + * FTS API for MP test *** * * ************************************************************************** ************************************************************************** - + * */ -#include "ftsCrossCompile.h" -#include "ftsCompensation.h" -#include "ftsError.h" -#include "ftsFrame.h" -#include "ftsHardware.h" -#include "ftsIO.h" -#include "ftsSoftware.h" -#include "ftsTest.h" -#include "ftsTime.h" -#include "ftsTool.h" -#include "../fts.h" - #include #include #include @@ -49,13 +57,25 @@ #include #include #include -/* #include */ +//#include + +#include "ftsCrossCompile.h" +#include "ftsCompensation.h" +#include "ftsError.h" +#include "ftsFrame.h" +#include "ftsHardware.h" +#include "ftsIO.h" +#include "ftsSoftware.h" +#include "ftsTest.h" +#include "ftsTime.h" +#include "ftsTool.h" +#include "../fts.h" #ifdef LIMITS_H_FILE #include <../fts_limits.h> #endif -/* static char tag[8] = "[ FTS ]\0"; */ +static char tag[8] = "[ FTS ]\0"; int computeAdjHoriz(u8 *data, int row, int column, u8 **result) { @@ -63,24 +83,26 @@ int computeAdjHoriz(u8 *data, int row, int column, u8 **result) int size = row * (column - 1); if (column < 2) { - logError(1, "%s computeAdjHoriz: ERROR % 02X\n", tag, ERROR_OP_NOT_ALLOW); + logError(1, "%s %s: ERROR % 02X\n", + tag, __func__, ERROR_OP_NOT_ALLOW); return ERROR_OP_NOT_ALLOW; } - *result = (u8 *) kmalloc(size * sizeof (u8), GFP_KERNEL); + *result = (u8 *) kmalloc_array(size, sizeof(u8), GFP_KERNEL); if (*result == NULL) { - logError(1, "%s computeAdjHoriz: ERROR %02X\n", tag, ERROR_ALLOC); + logError(1, "%s %s: ERROR %02X\n", + tag, __func__, ERROR_ALLOC); return ERROR_ALLOC; } for (i = 0; i < row; i++) { for (j = 1; j < column; j++) { - *(*result + (i * (column - 1) + (j - 1))) = abs(data[i * column + j] - data[i * column + (j - 1)]); - } + *(*result + (i * (column - 1) + (j - 1))) = + abs(data[i * column + j] - + data[i * column + (j - 1)]); + } } - return OK; - } int computeAdjHorizTotal(u16 *data, int row, int column, u16 **result) @@ -89,45 +111,52 @@ int computeAdjHorizTotal(u16 *data, int row, int column, u16 **result) int size = row * (column - 1); if (column < 2) { - logError(1, "%s computeAdjHorizTotal: ERROR % 02X\n", tag, ERROR_OP_NOT_ALLOW); + logError(1, "%s %s: ERROR % 02X\n", + tag, __func__, ERROR_OP_NOT_ALLOW); return ERROR_OP_NOT_ALLOW; } - *result = (u16 *) kmalloc(size * sizeof (u16), GFP_KERNEL); + *result = (u16 *)kmalloc_array(size, sizeof(u16), GFP_KERNEL); if (*result == NULL) { - logError(1, "%s computeAdjHorizTotal: ERROR %02X\n", tag, ERROR_ALLOC); + logError(1, "%s %s: ERROR %02X\n", + tag, __func__, ERROR_ALLOC); return ERROR_ALLOC; } for (i = 0; i < row; i++) { for (j = 1; j < column; j++) { - *(*result + (i * (column - 1) + (j - 1))) = abs(data[i * column + j] - data[i * column + (j - 1)]); + *(*result + (i * (column - 1) + (j - 1))) = + abs(data[i * column + j] - + data[i * column + (j - 1)]); } } return OK; - } int computeAdjVert(u8 *data, int row, int column, u8 **result) { int i, j; - int size = (row - 1)*(column); + int size = (row - 1) * (column); if (row < 2) { - logError(1, "%s computeAdjVert: ERROR % 02X\n", tag, ERROR_OP_NOT_ALLOW); + logError(1, "%s %s: ERROR % 02X\n", + tag, __func__, ERROR_OP_NOT_ALLOW); return ERROR_OP_NOT_ALLOW; } - *result = (u8 *) kmalloc(size * sizeof (u8), GFP_KERNEL); + *result = (u8 *)kmalloc_array(size, sizeof(u8), GFP_KERNEL); if (*result == NULL) { - logError(1, "%s computeAdjVert: ERROR %02X\n", tag, ERROR_ALLOC); + logError(1, "%s %s: ERROR %02X\n", + tag, __func__, ERROR_ALLOC); return ERROR_ALLOC; } for (i = 1; i < row; i++) { for (j = 0; j < column; j++) { - *(*result + ((i - 1) * column + j)) = abs(data[i * column + j] - data[(i - 1) * column + j]); + *(*result + ((i - 1) * column + j)) = + abs(data[i * column + j] - + data[(i - 1) * column + j]); } } @@ -137,42 +166,49 @@ int computeAdjVert(u8 *data, int row, int column, u8 **result) int computeAdjVertTotal(u16 *data, int row, int column, u16 **result) { int i, j; - int size = (row - 1)*(column); + int size = (row - 1) * (column); if (row < 2) { - logError(1, "%s computeAdjVertTotal: ERROR % 02X\n", tag, ERROR_OP_NOT_ALLOW); + logError(1, "%s %s: ERROR % 02X\n", + tag, __func__, ERROR_OP_NOT_ALLOW); return ERROR_OP_NOT_ALLOW; } - *result = (u16 *) kmalloc(size * sizeof (u16), GFP_KERNEL); + *result = (u16 *)kmalloc_array(size, sizeof(u16), GFP_KERNEL); if (*result == NULL) { - logError(1, "%s computeAdjVertTotal: ERROR %02X\n", tag, ERROR_ALLOC); + logError(1, "%s %s: ERROR %02X\n", + tag, __func__, ERROR_ALLOC); return ERROR_ALLOC; } for (i = 1; i < row; i++) { for (j = 0; j < column; j++) { - *(*result + ((i - 1) * column + j)) = abs(data[i * column + j] - data[(i - 1) * column + j]); + *(*result + ((i - 1) * column + j)) = + abs(data[i * column + j] - + data[(i - 1) * column + j]); } } return OK; } -int computeTotal(u8 *data, u8 main, int row, int column, int m, int n, u16 **result) +int computeTotal(u8 *data, u8 main, int row, int column, + int m, int n, u16 **result) { int i, j; - int size = (row)*(column); + int size = (row) * (column); - *result = (u16 *) kmalloc(size * sizeof (u16), GFP_KERNEL); + *result = (u16 *)kmalloc_array(size, sizeof(u16), GFP_KERNEL); if (*result == NULL) { - logError(1, "%s computeTotal : ERROR %02X\n", tag, ERROR_ALLOC); + logError(1, "%s %s : ERROR %02X\n", + tag, __func__, ERROR_ALLOC); return ERROR_ALLOC; } for (i = 0; i < row; i++) { for (j = 0; j < column; j++) { - *(*result + (i * column + j)) = m * main + n * data[i * column + j]; + *(*result + (i * column + j)) = + m * main + n * data[i * column + j]; } } @@ -186,14 +222,17 @@ int checkLimitsMinMax(short *data, int row, int column, int min, int max) for (i = 0; i < row; i++) { for (j = 0; j < column; j++) { - if (data[i * column + j] < min || data[i * column + j] > max) { - logError(1, "%s checkLimitsMinMax: Node[%d,%d] = %d exceed limit [%d, %d]\n", tag, i, j, data[i * column + j], min, max); + if (data[i * column + j] < min + || data[i * column + j] > max) { + logError(1, "%s %s:Node[%d,%d] = %d ", tag, + __func__, i, j, data[i * column + j]); + logError(1, "exceed limit [%d,%d]\n", min, max); count++; } } } - return count; /* if count is 0 = OK, test completed successfully */ + return count;//if count is 0 = OK, test completed successfully } int checkLimitsGap(short *data, int row, int column, int threshold) @@ -203,7 +242,10 @@ int checkLimitsGap(short *data, int row, int column, int threshold) int max_node; if (row == 0 || column == 0) { - logError(1, "%s checkLimitsGap: invalid number of rows = %d or columns = %d ERROR %02\n", tag, row, column, ERROR_OP_NOT_ALLOW); + logError(1, "%s %s:invalid number of rows = %d ", + tag, __func__, row); + logError(1, "or columns = %d %02\n", + column, ERROR_OP_NOT_ALLOW); return ERROR_OP_NOT_ALLOW; } @@ -222,11 +264,11 @@ int checkLimitsGap(short *data, int row, int column, int threshold) } if (max_node - min_node > threshold) { - logError(1, "%s checkLimitsGap: GAP = %d exceed limit %d\n", tag, max_node - min_node, threshold); + logError(1, "%s %s: GAP = %d exceed limit %d\n", + tag, __func__, max_node - min_node, threshold); return ERROR_TEST_CHECK_FAIL; - } else - return OK; - + } + return OK; } int checkLimitsMap(u8 *data, int row, int column, int *min, int *max) @@ -236,14 +278,21 @@ int checkLimitsMap(u8 *data, int row, int column, int *min, int *max) for (i = 0; i < row; i++) { for (j = 0; j < column; j++) { - if (data[i * column + j] < min[i * column + j] || data[i * column + j] > max[i * column + j]) { - logError(1, "%s checkLimitsMap: Node[%d,%d] = %d exceed limit [%d, %d]\n", tag, i, j, data[i * column + j], min[i * column + j], max[i * column + j]); + if (data[i * column + j] < min[i * column + j] + || data[i * column + j] > max[i * column + j]) { + logError(1, "%s %s: Node[%d,%d] = %d ", + tag, __func__, + i, j, + data[i * column + j]); + logError(1, "exceed limit [%d, %d]\n", + min[i * column + j], + max[i * column + j]); count++; } } } - return count; /* if count is 0 = OK, test completed successfully */ + return count; //if count is 0 = OK, test completed successfully } int checkLimitsMapTotal(u16 *data, int row, int column, int *min, int *max) @@ -253,14 +302,20 @@ int checkLimitsMapTotal(u16 *data, int row, int column, int *min, int *max) for (i = 0; i < row; i++) { for (j = 0; j < column; j++) { - if (data[i * column + j] < min[i * column + j] || data[i * column + j] > max[i * column + j]) { - logError(1, "%s checkLimitsMapTotal: Node[%d,%d] = %d exceed limit [%d, %d]\n", tag, i, j, data[i * column + j], min[i * column + j], max[i * column + j]); + if (data[i * column + j] < min[i * column + j] + || data[i * column + j] > max[i * column + j]) { + logError(1, "%s %s:Node[%d,%d] = %d\n", + tag, __func__, i, j, + data[i * column + j]); + logError(1, "exceed limit [%d, %d]\n", + min[i * column + j], + max[i * column + j]); count++; } } } - return count; /* if count is 0 = OK, test completed successfully */ + return count; //if count is 0 = OK, test completed successfully } int checkLimitsMapAdj(u8 *data, int row, int column, int *max) @@ -271,13 +326,17 @@ int checkLimitsMapAdj(u8 *data, int row, int column, int *max) for (i = 0; i < row; i++) { for (j = 0; j < column; j++) { if (data[i * column + j] > max[i * column + j]) { - logError(1, "%s checkLimitsMapAdj: Node[%d,%d] = %d exceed limit > %d\n", tag, i, j, data[i * column + j], max[i * column + j]); + logError(1, "%s %s:Node[%d,%d] = %d ", + tag, __func__, i, j); + logError(1, "exceed limit > %d\n", + data[i * column + j], + max[i * column + j]); count++; } } } - - return count; /* if count is 0 = OK, test completed successfully */ + //if count is 0 = OK, test completed successfully + return count; } int checkLimitsMapAdjTotal(u16 *data, int row, int column, int *max) @@ -288,27 +347,33 @@ int checkLimitsMapAdjTotal(u16 *data, int row, int column, int *max) for (i = 0; i < row; i++) { for (j = 0; j < column; j++) { if (data[i * column + j] > max[i * column + j]) { - logError(1, "%s checkLimitsMapAdjTotal: Node[%d,%d] = %d exceed limit > %d\n", tag, i, j, data[i * column + j], max[i * column + j]); + logError(1, "%s %s:Node[%d,%d] = %d ", + tag, __func__, i, j); + logError(1, "exceed limit > %d\n", + data[i * column + j], + max[i * column + j]); count++; } } } - - return count; /* if count is 0 = OK, test completed successfully */ + //if count is 0 = OK, test completed successfully + return count; } int production_test_ito(void) { int res = OK; u8 cmd; - u8 readData[FIFO_EVENT_SIZE] = {0}; - int eventToSearch[2] = {EVENTID_ERROR_EVENT, EVENT_TYPE_ITO}; /* look for ito event */ + u8 readData[FIFO_EVENT_SIZE]; + //look for ito event + int eventToSearch[2] = {EVENTID_ERROR_EVENT, EVENT_TYPE_ITO}; logError(0, "%s ITO Production test is starting...\n", tag); res = fts_system_reset(); if (res < 0) { - logError(1, "%s production_test_ito: ERROR %02X\n", tag, ERROR_PROD_TEST_ITO); + logError(1, "%s %s: ERROR %02X\n", + tag, __func__, ERROR_PROD_TEST_ITO); return (res | ERROR_PROD_TEST_ITO); } @@ -316,28 +381,33 @@ int production_test_ito(void) logError(0, "%s ITO Check command sent...\n", tag); if (fts_writeFwCmd(&cmd, 1) < 0) { - logError(1, "%s production_test_ito: ERROR %02X\n", tag, (ERROR_I2C_W | ERROR_PROD_TEST_ITO)); + logError(1, "%s %s: ERROR %02X\n", + tag, __func__, (ERROR_I2C_W | ERROR_PROD_TEST_ITO)); return (ERROR_I2C_W | ERROR_PROD_TEST_ITO); } logError(0, "%s Looking for ITO Event...\n", tag); - res = pollForEvent(eventToSearch, 2, readData, TIMEOUT_ITO_TEST_RESULT); + res = pollForEvent(eventToSearch, 2, + readData, TIMEOUT_ITO_TEST_RESULT); if (res < 0) { - logError(1, "%s production_test_ito: ITO Production test failed... ERROR %02X\n", tag, ERROR_PROD_TEST_ITO); + logError(1, "%s %s: ITO Production test failed ERROR %02X\n", + tag, __func__, ERROR_PROD_TEST_ITO); return (res | ERROR_PROD_TEST_ITO); } if (readData[2] != 0x00 || readData[3] != 0x00) { - logError(0, "%s ITO Production testes finished!.................FAILED ERROR %02X\n", tag, (ERROR_TEST_CHECK_FAIL | ERROR_PROD_TEST_ITO)); + logError(0, "%s ITO Production testes finished! ERROR %02X\n", + tag, (ERROR_TEST_CHECK_FAIL | ERROR_PROD_TEST_ITO)); res = (ERROR_TEST_CHECK_FAIL | ERROR_PROD_TEST_ITO); } else { - logError(0, "%s ITO Production test finished!.................OK\n", tag); + logError(0, "%s ITO Production test finished!..OK\n", tag); res = OK; } res |= fts_system_reset(); if (res < 0) { - logError(1, "%s production_test_ito: ERROR %02X\n", tag, ERROR_PROD_TEST_ITO); + logError(1, "%s %s: ERROR %02X\n", + tag, __func__, ERROR_PROD_TEST_ITO); res = (res | ERROR_PROD_TEST_ITO); } return res; @@ -347,78 +417,94 @@ int production_test_initialization(void) { int res; u8 cmd; - u8 readData[FIFO_EVENT_SIZE] = {0}; - int eventToSearch[2] = {EVENTID_STATUS_UPDATE, EVENT_TYPE_FULL_INITIALIZATION}; + u8 readData[FIFO_EVENT_SIZE]; - logError(0, "%s INITIALIZATION Production test is starting...\n", tag); + int eventToSearch[2] = {EVENTID_STATUS_UPDATE, + EVENT_TYPE_FULL_INITIALIZATION}; + logError(0, "%s INITIALIZATION Production test is starting\n", tag); res = fts_system_reset(); if (res < 0) { - logError(1, "%s production_test_initialization: ERROR %02X\n", tag, ERROR_PROD_TEST_INITIALIZATION); + logError(1, "%s %s: ERROR %02X\n", + tag, __func__, ERROR_PROD_TEST_INITIALIZATION); return (res | ERROR_PROD_TEST_INITIALIZATION); } logError(0, "%s INITIALIZATION command sent...\n", tag); cmd = FTS_CMD_FULL_INITIALIZATION; if (fts_writeFwCmd(&cmd, 1) < 0) { - logError(1, "%s production_test_initialization: ERROR %02X\n", tag, (ERROR_I2C_W | ERROR_PROD_TEST_INITIALIZATION)); + logError(1, "%s %s: ERROR %02X\n", tag, __func__, + (ERROR_I2C_W | ERROR_PROD_TEST_INITIALIZATION)); return (ERROR_I2C_W | ERROR_PROD_TEST_INITIALIZATION); } logError(0, "%s Looking for INITIALIZATION Event...\n", tag); - res = pollForEvent(eventToSearch, 2, readData, TIMEOUT_INITIALIZATION_TEST_RESULT); + res = pollForEvent(eventToSearch, 2, readData, + TIMEOUT_INITIALIZATION_TEST_RESULT); if (res < 0) { - logError(1, "%s production_test_initialization: INITIALIZATION Production test failed... ERROR %02X\n", tag, ERROR_PROD_TEST_INITIALIZATION); + logError(1, "%s %s: INITIALIZATION Production ", tag, __func__); + logError(1, "test failed %02X\n", + ERROR_PROD_TEST_INITIALIZATION); return (res | ERROR_PROD_TEST_INITIALIZATION); } if (readData[2] != 0x00) { - logError(0, "%s INITIALIZATION Production testes finished!.................FAILED ERROR %02X\n", tag, (ERROR_TEST_CHECK_FAIL | ERROR_PROD_TEST_INITIALIZATION)); + logError(0, "%sINITIALIZATION Production ", tag); + logError(0, "testes finished! FAILED %02X\n", + (ERROR_TEST_CHECK_FAIL | ERROR_PROD_TEST_INITIALIZATION)); res = (ERROR_TEST_CHECK_FAIL | ERROR_PROD_TEST_INITIALIZATION); } else { - logError(0, "%s INITIALIZATION Production test.................OK\n", tag); + logError(0, "%s INITIALIZATION Production test...OK\n", tag); res = OK; } logError(0, "%s Refresh Chip Info...\n", tag); + //need to update the chipInfo in order to refresh the tuning_versione res |= readChipInfo(1); - /* need to update the chipInfo in order to refresh the tuning_versione */ if (res < 0) { - logError(1, "%s production_test_initialization: read chip info ERROR %02X\n", tag, ERROR_PROD_TEST_INITIALIZATION); - res = (res | ERROR_PROD_TEST_INITIALIZATION); + logError(1, "%s %s: read chip info ERROR %02X\n", + tag, __func__, ERROR_PROD_TEST_INITIALIZATION); + res = (res | ERROR_PROD_TEST_INITIALIZATION); } return res; - } int ms_compensation_tuning(void) { int res; u8 cmd; - u8 readData[FIFO_EVENT_SIZE] = {0}; - int eventToSearch[2] = {EVENTID_STATUS_UPDATE, EVENT_TYPE_MS_TUNING_CMPL}; + u8 readData[FIFO_EVENT_SIZE]; + int eventToSearch[2] = {EVENTID_STATUS_UPDATE, + EVENT_TYPE_MS_TUNING_CMPL}; logError(0, "%s MS INITIALIZATION command sent...\n", tag); cmd = FTS_CMD_MS_COMP_TUNING; if (fts_writeFwCmd(&cmd, 1) < 0) { - logError(1, "%s ms_compensation_tuning 2: ERROR %02X\n", tag, (ERROR_I2C_W | ERROR_MS_TUNING)); + logError(1, "%s %s 2: ERROR %02X\n", + tag, __func__, (ERROR_I2C_W | ERROR_MS_TUNING)); return (ERROR_I2C_W | ERROR_MS_TUNING); } logError(0, "%s Looking for MS INITIALIZATION Event...\n", tag); - res = pollForEvent(eventToSearch, 2, readData, TIMEOUT_INITIALIZATION_TEST_RESULT); + res = pollForEvent(eventToSearch, 2, readData, + TIMEOUT_INITIALIZATION_TEST_RESULT); if (res < 0) { - logError(1, "%s ms_compensation_tuning: MS INITIALIZATION Production test failed... ERROR %02X\n", tag, ERROR_MS_TUNING); + logError(1, "%s %s:MS INITIALIZATION Production\n", + tag, __func__); + logError(1, "test failed %02X\n", ERROR_MS_TUNING); return (res | ERROR_MS_TUNING); } if (readData[2] != 0x00 || readData[3] != 0x00) { - logError(0, "%s MS INITIALIZATION Production test finished!.................FAILED ERROR %02X\n", tag, ERROR_MS_TUNING); + logError(0, "%s MS INITIALIZATION Production ", tag); + logError(0, "test finished! FAILED %02X\n", ERROR_MS_TUNING); res = ERROR_MS_TUNING; } else { - logError(0, "%s MS INITIALIZATION Production test finished!.................OK\n", tag); + logError(0, + "%s MS INITIALIZATION Production test finished! OK\n", + tag); res = OK; } @@ -429,28 +515,37 @@ int ss_compensation_tuning(void) { int res; u8 cmd; - u8 readData[FIFO_EVENT_SIZE] = {0}; - int eventToSearch[2] = {EVENTID_STATUS_UPDATE, EVENT_TYPE_SS_TUNING_CMPL}; + u8 readData[FIFO_EVENT_SIZE]; + + int eventToSearch[2] = {EVENTID_STATUS_UPDATE, + EVENT_TYPE_SS_TUNING_CMPL}; logError(0, "%s SS INITIALIZATION command sent...\n", tag); cmd = FTS_CMD_SS_COMP_TUNING; if (fts_writeFwCmd(&cmd, 1) < 0) { - logError(1, "%s ss_compensation_tuning 2: ERROR %02X\n", tag, (ERROR_I2C_W | ERROR_SS_TUNING)); + logError(1, "%s %s 2: ERROR %02X\n", + tag, __func__, (ERROR_I2C_W | ERROR_SS_TUNING)); return (ERROR_I2C_W | ERROR_SS_TUNING); } logError(0, "%s Looking for SS INITIALIZATION Event...\n", tag); - res = pollForEvent(eventToSearch, 2, readData, TIMEOUT_INITIALIZATION_TEST_RESULT); + res = pollForEvent(eventToSearch, + 2, + readData, + TIMEOUT_INITIALIZATION_TEST_RESULT); if (res < 0) { - logError(1, "%s ms_compensation_tuning: SS INITIALIZATION Production test failed... ERROR %02X\n", tag, ERROR_SS_TUNING); + logError(1, "%s %s:SS INITIALIZATION Production ", + tag, __func__); + logError(1, "test failed %02X\n", ERROR_SS_TUNING); return (res | ERROR_SS_TUNING); } - + logError(0, "%s SS INITIALIZATION Production test finished!", tag); if (readData[2] != 0x00 || readData[3] != 0x00) { - logError(0, "%s SS INITIALIZATION Production test finished!.................FAILED ERROR %02X\n", tag, ERROR_SS_TUNING); + logError(0, "%s.................FAILED ERROR %02X\n", + tag, ERROR_SS_TUNING); res = ERROR_SS_TUNING; } else { - logError(0, "%s SS INITIALIZATION Production test finished!.................OK\n", tag); + logError(0, "%s.................OK\n", tag); res = OK; } @@ -461,28 +556,39 @@ int lp_timer_calibration(void) { int res; u8 cmd; - u8 readData[FIFO_EVENT_SIZE] = {0}; - int eventToSearch[2] = {EVENTID_STATUS_UPDATE, EVENT_TYPE_LPTIMER_TUNING_CMPL}; + u8 readData[FIFO_EVENT_SIZE]; + int eventToSearch[2] = {EVENTID_STATUS_UPDATE, + EVENT_TYPE_LPTIMER_TUNING_CMPL}; logError(0, "%s LP TIMER CALIBRATION command sent...\n", tag); cmd = FTS_CMD_LP_TIMER_CALIB; if (fts_writeFwCmd(&cmd, 1) < 0) { - logError(1, "%s lp_timer_calibration 2: ERROR %02X\n", tag, (ERROR_I2C_W | ERROR_LP_TIMER_TUNING)); + logError(1, "%s %s 2:ERROR %02X\n", tag, __func__, + (ERROR_I2C_W | ERROR_LP_TIMER_TUNING)); return (ERROR_I2C_W | ERROR_LP_TIMER_TUNING); } logError(0, "%s Looking for LP TIMER CALIBRATION Event...\n", tag); - res = pollForEvent(eventToSearch, 2, readData, TIMEOUT_INITIALIZATION_TEST_RESULT); + res = pollForEvent(eventToSearch, + 2, + readData, + TIMEOUT_INITIALIZATION_TEST_RESULT); + if (res < 0) { - logError(1, "%s lp_timer_calibration: LP TIMER CALIBRATION Production test failed... ERROR %02X\n", tag, ERROR_LP_TIMER_TUNING); + logError(1, "%s:LP TIMER CALIBRATION Production test failed\n", + tag); + logError(1, "%s %s: ERROR %02X\n", + tag, __func__, ERROR_LP_TIMER_TUNING); return (res | ERROR_LP_TIMER_TUNING); } + logError(0, "LP TIMER CALIBRATION Production test finished!"); if (readData[2] != 0x00 || readData[3] != 0x01) { - logError(0, "%s LP TIMER CALIBRATION Production test finished!.................FAILED ERROR %02X\n", tag, ERROR_LP_TIMER_TUNING); + logError(0, "%s........FAILED ERROR %02X\n", + tag, ERROR_LP_TIMER_TUNING); res = ERROR_LP_TIMER_TUNING; } else { - logError(0, "%s LP TIMER CALIBRATION Production test finished!.................OK\n", tag); + logError(0, "%s.................OK\n", tag); res = OK; } @@ -493,25 +599,32 @@ int save_cx_tuning(void) { int res; u8 cmd; - u8 readData[FIFO_EVENT_SIZE] = {0}; - int eventToSearch[2] = {EVENTID_STATUS_UPDATE, EVENT_TYPE_COMP_DATA_SAVED}; + u8 readData[FIFO_EVENT_SIZE]; + int eventToSearch[2] = {EVENTID_STATUS_UPDATE, + EVENT_TYPE_COMP_DATA_SAVED}; logError(0, "%s SAVE CX command sent...\n", tag); cmd = FTS_CMD_SAVE_CX_TUNING; if (fts_writeCmd(&cmd, 1) < 0) { - logError(1, "%s save_cx_tuning 2: ERROR %02X\n", tag, (ERROR_I2C_W | ERROR_SAVE_CX_TUNING)); + logError(1, "%s %s 2:ERROR %02X\n", tag, __func__, + (ERROR_I2C_W | ERROR_SAVE_CX_TUNING)); return (ERROR_I2C_W | ERROR_SAVE_CX_TUNING); } logError(0, "%s Looking for SAVE CX Event...\n", tag); - res = pollForEvent(eventToSearch, 2, readData, TIMEOUT_INITIALIZATION_TEST_RESULT); + res = pollForEvent(eventToSearch, + 2, + readData, + TIMEOUT_INITIALIZATION_TEST_RESULT); if (res < 0) { - logError(1, "%s save_cx_tuning: SAVE CX failed... ERROR %02X\n", tag, ERROR_SAVE_CX_TUNING); + logError(1, "%s %s: SAVE CX failed... ERROR %02X\n", + tag, ERROR_SAVE_CX_TUNING); return (res | ERROR_SAVE_CX_TUNING); } if (readData[2] != 0x00 || readData[3] != 0x00) { - logError(0, "%s SAVE CX finished!.................FAILED ERROR %02X\n", tag, ERROR_SAVE_CX_TUNING); + logError(0, "%s SAVE CX finished! FAILED ERROR %02X\n", + tag, ERROR_SAVE_CX_TUNING); res = ERROR_SAVE_CX_TUNING; } else { logError(0, "%s SAVE CX finished!.................OK\n", tag); @@ -521,105 +634,115 @@ int save_cx_tuning(void) return res; } -int production_test_splited_initialization(int saveToFlash) +int production_test_split_initialization(int saveToFlash) { int res; - logError(0, "%s Splitted Initialization test is starting...\n", tag); + logError(0, "%s Split Initialization test is starting...\n", tag); res = fts_system_reset(); if (res < 0) { - logError(1, "%s production_test_initialization: ERROR %02X\n", tag, ERROR_PROD_TEST_INITIALIZATION); - logError(0, "%s LP INITIALIZATION TEST:\n", tag); + logError(1, "%s %s: ERROR %02X\n", tag, __func__, + ERROR_PROD_TEST_INITIALIZATION); return (res | ERROR_PROD_TEST_INITIALIZATION); } logError(0, "%s MS INITIALIZATION TEST:\n", tag); res = ms_compensation_tuning(); if (res < 0) { - logError(0, "%s production_test_splited_initialization: MS INITIALIZATION TEST FAILED! ERROR %02X\n", tag, ERROR_PROD_TEST_INITIALIZATION); + logError(0, "%s %s:MS INITIALIZATION TEST FAILED! ERROR %02X\n", + tag, __func__, ERROR_PROD_TEST_INITIALIZATION); return (res | ERROR_PROD_TEST_INITIALIZATION); } - logError(0, "%s MS INITIALIZATION TEST OK!\n", tag); + logError(0, "%s MS INITIALIZATION TEST OK!\n", tag); logError(0, "%s\n", tag); - logError(0, "%s SS INITIALIZATION TEST:\n", tag); res = ss_compensation_tuning(); if (res < 0) { - logError(0, "%s production_test_splited_initialization: SS INITIALIZATION TEST FAILED! ERROR %02X\n", tag, ERROR_PROD_TEST_INITIALIZATION); + logError(0, "%s %s: SS INITIALIZATION TEST FAILED! ", + tag, __func__); + logError(0, "ERROR %02X\n", ERROR_PROD_TEST_INITIALIZATION); return (res | ERROR_PROD_TEST_INITIALIZATION); } - logError(0, "%s SS INITIALIZATION TEST OK!\n", tag); + logError(0, "%s SS INITIALIZATION TEST OK!\n", tag); logError(0, "%s\n", tag); - logError(0, "%s LP INITIALIZATION TEST:\n", tag); res = lp_timer_calibration(); if (res < 0) { - logError(0, "%s production_test_splited_initialization: LP INITIALIZATION TEST FAILED! ERROR %02X\n", tag, ERROR_PROD_TEST_INITIALIZATION); + logError(0, "%s %s: LP INITIALIZATION TEST FAILED! ", + tag, __func__); + logError(0, "ERROR %02X\n", ERROR_PROD_TEST_INITIALIZATION); return (res | ERROR_PROD_TEST_INITIALIZATION); } + logError(0, "%s LP INITIALIZATION TEST OK!\n", tag); if (saveToFlash) { logError(0, "%s\n", tag); logError(0, "%s SAVE CX TEST:\n", tag); res = save_cx_tuning(); if (res < 0) { - logError(0, "%s production_test_splited_initialization: SAVE CX TEST FAILED! ERROR %02X\n", tag, res); + logError(0, "%s %s: SAVE CX TEST FAILED! ERROR %02X\n", + tag, __func__, res); return (res | ERROR_PROD_TEST_INITIALIZATION); } logError(0, "%s SAVE CX TEST OK!\n", tag); } + logError(0, "%s Refresh Chip Info...\n", tag); res |= readChipInfo(1); if (res < 0) { - logError(1, "%s production_test_initialization: read chip info ERROR %02X\n", tag, ERROR_PROD_TEST_INITIALIZATION); - res = (res | ERROR_PROD_TEST_INITIALIZATION); - } else - logError(0, "%s Splited Initialization test finished!.................OK\n", tag); + logError(1, "%s %s: read chip info ERROR %02X\n", + tag, __func__, ERROR_PROD_TEST_INITIALIZATION); + res = (res | ERROR_PROD_TEST_INITIALIZATION); + } else { + logError(0, "%s Split Initialization test finished! OK\n", tag); + } return res; + } -int production_test_main(char *pathThresholds, int stop_on_fail, - int saveInit, TestToDo *todo, u32 signature) +int production_test_main(char *pathThresholds, int stop_on_fail, int saveInit, + struct TestToDo *todo, u32 signature) { int res, ret; logError(0, "%s MAIN Production test is starting...\n", tag); - logError(0, "%s\n", tag); - logError(0, "%s ITO TEST:\n", tag); + res = production_test_ito(); if (res < 0) { - logError(0, "%s Error during ITO TEST! ERROR %02X\n", tag, (u8) res); - goto END; /* in case of ITO TEST failure is no sense keep going */ - } else { - logError(0, "%s ITO TEST OK!\n", tag); + logError(0, "%s Error during ITO TEST! ERROR %08X\n", tag, res); + //in case of ITO TEST failure is no sense keep going + goto END; } + logError(0, "%s ITO TEST OK!\n", tag); - logError(0, "%s\n", tag); + logError(0, "%s:\n", tag); + logError(0, "%s INITIALIZATION TEST:\n", tag); - logError(0, "%s INITIALIZATION TEST :\n", tag); if (saveInit == 1) { res = production_test_initialization(); - if (res < 0) { - logError(0, "%s Error during INITIALIZATION TEST! ERROR %02X\n", tag, (u8) res); + if (res < 0) { + logError(0, "%s Error during INITIALIZATION TEST!", + tag); + logError(0, "ERROR %08X\n", res); if (stop_on_fail) goto END; } else { logError(0, "%s INITIALIZATION TEST OK!\n", tag); } } else - logError(0, "%s INITIALIZATION TEST :................. SKIPPED\n", tag); + logError(0, "%s INITIALIZATION TEST:..SKIPPED\n", tag); logError(0, "%s\n", tag); - if (saveInit == 1) { logError(0, "%s Cleaning up...\n", tag); ret = cleanUp(0); if (ret < 0) { - logError(1, "%s production_test_main: clean up ERROR %02X\n", tag, ret); + logError(1, "%s %s: clean up ERROR %02X\n", + tag, __func__, ret); res |= ret; if (stop_on_fail) goto END; @@ -630,172 +753,257 @@ int production_test_main(char *pathThresholds, int stop_on_fail, logError(0, "%s PRODUCTION DATA TEST:\n", tag); ret = production_test_data(pathThresholds, stop_on_fail, todo); if (ret < 0) { - logError(0, "%s Error during PRODUCTION DATA TEST! ERROR %02X\n", tag, ret); + logError(0, "%sError during PRODUCTION DATA TEST %08X\n", + tag, ret); } else { logError(0, "%s PRODUCTION DATA TEST OK!\n", tag); } - res |= ret; - /* the OR is important because if the data test is OK but the inizialization test fail, - * the main production test result should = FAIL - */ + // the OR is important because if + //the data test is OK but the inizialization + //test fail, the main production + //test result should = FAIL if (ret == OK && saveInit == 1) { - logError(0, "%s SAVE FLAG:\n", tag); - ret = save_mp_flag(signature); - if (ret < OK) - logError(0, "%s SAVE FLAG:................. FAIL! ERROR %08X\n", tag, ret); - else - logError(0, "%s SAVE FLAG:................. OK!\n", tag); - res |= ret; + logError(0, "%s SAVE FLAG:\n", tag); + ret = save_mp_flag(signature); + if (ret < OK) + logError(0, "%s SAVE FLAG:FAIL! ERROR %08X\n", + tag, ret); + else + logError(0, "%s SAVE FLAG:OK!\n", tag); + res |= ret; + // need to update the MP Flag + ret = readChipInfo(1); + if (ret < OK) + logError(1, "%s %s:read chip info ERROR %08X\n", + tag, __func__, ret); + res |= ret; } - logError(0, "%s\n", tag); END: if (res < 0) { - logError(0, "%s MAIN Production test finished.................FAILED\n", tag); + logError(0, "%s MAIN Production test finished..FAILED\n", tag); return res; } - logError(0, "%s MAIN Production test finished.................OK\n", tag); + logError(0, "%s MAIN Production test finished..OK\n", tag); return OK; } -int production_test_ms_raw(char *path_limits, int stop_on_fail, TestToDo *todo) +int production_test_ms_raw(char *path_limits, int stop_on_fail, + struct TestToDo *todo) { - int ret, count_fail = 0; - MutualSenseFrame msRawFrame; + struct MutualSenseFrame msRawFrame; int *thresholds = NULL; int trows, tcolumns; - /*********************** Mutual Sense Test **********************/ + //****** Mutual Sense Test ************/ logError(0, "%s\n", tag); logError(0, "%s MS RAW DATA TEST is starting...\n", tag); if (todo->MutualRaw == 1 || todo->MutualRawGap == 1) { - ret = getMSFrame2(MS_TOUCH_ACTIVE, &msRawFrame); if (ret < 0) { - logError(1, "%s production_test_data: getMSFrame failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA); + logError(1, "%s %s:getMSFrame failed... ERROR %02X\n", + tag, __func__, ERROR_PROD_TEST_DATA); return (ret | ERROR_PROD_TEST_DATA); } logError(0, "%s MS RAW MIN MAX TEST:\n", tag); if (todo->MutualRaw == 1) { - ret = parseProductionTestLimits(path_limits, MS_RAW_MIN_MAX, &thresholds, &trows, &tcolumns); + ret = parseProductionTestLimits(path_limits, + MS_RAW_MIN_MAX, + &thresholds, + &trows, + &tcolumns); if (ret < 0 || (trows != 1 || tcolumns != 2)) { - logError(1, "%s production_test_data: parseProductionTestLimits MS_RAW_MIN_MAX failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA); - return (ret | ERROR_PROD_TEST_DATA); + logError(1, "%s %s:MS_RAW_MIN_MAX failed...", + tag, __func__); + logError(1, "ERROR %02X\n", + ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; } - ret = checkLimitsMinMax(msRawFrame.node_data, msRawFrame.header.force_node, msRawFrame.header.sense_node, thresholds[0], thresholds[1]); + ret = checkLimitsMinMax(msRawFrame.node_data, + msRawFrame.header.force_node, + msRawFrame.header.sense_node, + thresholds[0], + thresholds[1]); if (ret != OK) { - logError(1, "%s production_test_data: checkLimitsMinMax MS RAW failed... ERROR COUNT = %d\n", tag, ret); - logError(0, "%s MS RAW MIN MAX TEST:.................FAIL\n\n", tag); - count_fail += 1; + logError(1, "%s %s:MS RAW failed...", + tag, __func__); + logError(1, "ERROR COUNT = %d\n", ret); + logError(0, "%s MS RAW MIN MAX TEST:...", tag); + logError(0, "FAIL\n\n", tag); + count_fail += 1; if (stop_on_fail == 1) goto ERROR; - } + } else + logError(0, "%s MS RAW MIN MAX TEST:OK\n", tag); kfree(thresholds); - logError(0, "%s MS RAW MIN MAX TEST:.................OK\n", tag); + thresholds = NULL; } else - logError(0, "%s MS RAW MIN MAX TEST:.................SKIPPED\n", tag); + logError(0, "%s MS RAW MIN MAX TEST:SKIPPED\n", tag); logError(0, "%s\n", tag); logError(0, "%s MS RAW GAP TEST:\n", tag); if (todo->MutualRawGap == 1) { - ret = parseProductionTestLimits(path_limits, MS_RAW_GAP, &thresholds, &trows, &tcolumns); + ret = parseProductionTestLimits(path_limits, + MS_RAW_GAP, + &thresholds, + &trows, + &tcolumns); if (ret < 0 || (trows != 1 || tcolumns != 1)) { - logError(1, "%s production_test_data: parseProductionTestLimits MS_RAW_GAP failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA); - return (ret | ERROR_PROD_TEST_DATA); + logError(1, "%s %s: MS_RAW_GAP failed... ", + tag, __func__); + logError(1, "ERROR %02X\n", + ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; } - ret = checkLimitsGap(msRawFrame.node_data, msRawFrame.header.force_node, msRawFrame.header.sense_node, thresholds[0]); + ret = checkLimitsGap(msRawFrame.node_data, + msRawFrame.header.force_node, + msRawFrame.header.sense_node, + thresholds[0]); if (ret != OK) { - logError(1, "%s production_test_data: checkLimitsGap MS RAW failed... ERROR = %02X\n", tag, ret); - count_fail += 1; + logError(1, "%s %s:checkLimitsGap MS RAW ", + tag, __func__); + logError(1, "failed ERROR:%02X\n", ret); + count_fail += 1; if (stop_on_fail == 1) goto ERROR; - } else - logError(0, "%s MS RAW GAP TEST:.................OK\n\n", tag); + logError(0, "%s MS RAW GAP TEST:....OK\n\n", + tag); kfree(thresholds); + thresholds = NULL; } else - logError(0, "%s MS RAW GAP TEST:.................SKIPPED\n", tag); - - kfree(msRawFrame.node_data); + logError(0, "%s MS RAW GAP TEST:..SKIPPED\n", tag); } else - logError(0, "%s MS RAW FRAME TEST:.................SKIPPED\n", tag); + logError(0, "%s MS RAW FRAME TEST:.SKIPPED\n", tag); logError(0, "%s\n", tag); logError(0, "%s MS KEY RAW TEST:\n", tag); if (todo->MutualKeyRaw == 1) { ret = production_test_ms_key_raw(path_limits); if (ret < 0) { - logError(1, "%s production_test_data: production_test_ms_key_raw failed... ERROR = %02X\n", tag, ret); + logError(1, "%s %s:production_test_ms_key_raw ", + tag, __func__); + logError(1, "failed ERROR:%02X\n", ret); count_fail += 1; + if (count_fail == 1) { + logError(0, "%s MS RAW DATA TEST:FAIL ", tag); + logError(0, "fails_count:%d\n\n", count_fail); + goto ERROR_LIMITS; + } } } else - logError(0, "%s MS KEY RAW TEST:.................SKIPPED\n", tag); - + logError(0, "%s MS KEY RAW TEST:....SKIPPED\n", tag); ERROR: logError(0, "%s\n", tag); if (count_fail == 0) { - logError(0, "%s MS RAW DATA TEST finished!.................OK\n", tag); + kfree(msRawFrame.node_data); + msRawFrame.node_data = NULL; + logError(0, "%s MS RAW DATA TEST finished!.OK\n", tag); return OK; } - print_frame_short("MS Raw frame =", array1dTo2d_short(msRawFrame.node_data, msRawFrame.node_data_size, msRawFrame.header.sense_node), msRawFrame.header.force_node, msRawFrame.header.sense_node); - logError(0, "%s MS RAW DATA TEST:.................FAIL fails_count = %d\n\n", tag, count_fail); + print_frame_short("MS Raw frame =", + array1dTo2d_short(msRawFrame.node_data, + msRawFrame.node_data_size, + msRawFrame.header.sense_node), + msRawFrame.header.force_node, + msRawFrame.header.sense_node); + if (msRawFrame.node_data != NULL) + kfree(msRawFrame.node_data); + if (thresholds != NULL) + kfree(thresholds); + logError(0, "%s MS RAW DATA TEST: FAIL fails_count = %d\n\n", + tag, count_fail); return (ERROR_PROD_TEST_DATA | ERROR_TEST_CHECK_FAIL); + +ERROR_LIMITS: + if (msRawFrame.node_data != NULL) + kfree(msRawFrame.node_data); + if (thresholds != NULL) + kfree(thresholds); + return ret; } int production_test_ms_key_raw(char *path_limits) { - int ret; - MutualSenseFrame msRawFrame; + struct MutualSenseFrame msRawFrame; int *thresholds = NULL; int trows, tcolumns; - /******************************* Mutual Sense Test *******************************/ + //************* Mutual Sense Test ************/ logError(0, "%s MS KEY RAW DATA TEST is starting...\n", tag); ret = getMSFrame2(MS_KEY, &msRawFrame); if (ret < 0) { - logError(1, "%s production_test_data: getMSKeyFrame failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA); + logError(1, "%s %s:getMSKeyFrame failed...ERROR %02X\n", + tag, __func__, ERROR_PROD_TEST_DATA); return (ret | ERROR_PROD_TEST_DATA); } - ret = parseProductionTestLimits(path_limits, MS_KEY_RAW_MIN_MAX, &thresholds, &trows, &tcolumns); + ret = parseProductionTestLimits(path_limits, + MS_KEY_RAW_MIN_MAX, + &thresholds, + &trows, + &tcolumns); if (ret < 0 || (trows != 1 || tcolumns != 2)) { - logError(1, "%s production_test_data: parseProductionTestLimits MS_KEY_RAW_MIN_MAX failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA); - return (ret | ERROR_PROD_TEST_DATA); + logError(1, "%s %s: MS_KEY_RAW_MIN_MAX failed...ERROR %02X\n", + tag, __func__, ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; } - ret = checkLimitsMinMax(msRawFrame.node_data, msRawFrame.header.force_node, msRawFrame.header.sense_node, thresholds[0], thresholds[1]); + ret = checkLimitsMinMax(msRawFrame.node_data, + msRawFrame.header.force_node, + msRawFrame.header.sense_node, + thresholds[0], + thresholds[1]); if (ret != OK) { - logError(1, "%s production_test_data: checkLimitsMinMax MS KEY RAW failed... ERROR COUNT = %d\n", tag, ret); + logError(1, "%s %s:checkLimitsMinMax failed..ERROR COUNT:%d\n", + tag, __func__, ret); goto ERROR; } else logError(0, "%s MS KEY RAW TEST:.................OK\n\n", tag); kfree(thresholds); + thresholds = NULL; kfree(msRawFrame.node_data); - + msRawFrame.node_data = NULL; return OK; - ERROR: - print_frame_short("MS Key Raw frame =", array1dTo2d_short(msRawFrame.node_data, msRawFrame.node_data_size, msRawFrame.header.sense_node), msRawFrame.header.force_node, msRawFrame.header.sense_node); - logError(0, "%s MS KEY RAW TEST:.................FAIL\n\n", tag); + print_frame_short("MS Key Raw frame =", + array1dTo2d_short(msRawFrame.node_data, + msRawFrame.node_data_size, + msRawFrame.header.sense_node), + msRawFrame.header.force_node, + msRawFrame.header.sense_node); + if (msRawFrame.node_data != NULL) + kfree(msRawFrame.node_data); + if (thresholds != NULL) + kfree(thresholds); + logError(0, "%s MS KEY RAW TEST:......FAIL\n\n", tag); return (ERROR_PROD_TEST_DATA | ERROR_TEST_CHECK_FAIL); - +ERROR_LIMITS: + if (msRawFrame.node_data != NULL) + kfree(msRawFrame.node_data); + if (thresholds != NULL) + kfree(thresholds); + return ret; } -int production_test_ms_cx(char *path_limits, int stop_on_fail, TestToDo *todo) +int production_test_ms_cx(char *path_limits, + int stop_on_fail, struct TestToDo *todo) { - int ret; int count_fail = 0; @@ -804,7 +1012,7 @@ int production_test_ms_cx(char *path_limits, int stop_on_fail, TestToDo *todo) int *thresholds_max = NULL; int trows, tcolumns; - MutualSenseData msCompData; + struct MutualSenseData msCompData; u8 *adjhor = NULL; @@ -815,264 +1023,515 @@ int production_test_ms_cx(char *path_limits, int stop_on_fail, TestToDo *todo) u16 *total_adjhor = NULL; u16 *total_adjvert = NULL; - /* MS CX TEST */ + //MS CX TEST logError(0, "%s\n", tag); logError(0, "%s MS CX Testes are starting...\n", tag); - - ret = readMutualSenseCompensationData(MS_TOUCH_ACTIVE, &msCompData); /* read MS compensation data */ + //read MS compensation data + ret = readMutualSenseCompensationData(MS_TOUCH_ACTIVE, &msCompData); if (ret < 0) { - logError(1, "%s production_test_data: readMutualSenseCompensationData failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA); + logError(1, "%s %s:readMutualSenseCompensationData ", + tag, __func__); + logError(1, "failed %02X\n", ERROR_PROD_TEST_DATA); return (ret | ERROR_PROD_TEST_DATA); } logError(0, "%s MS CX1 TEST:\n", tag); if (todo->MutualCx1 == 1) { - - ret = parseProductionTestLimits(path_limits, MS_CX1_MIN_MAX, &thresholds, &trows, &tcolumns); + ret = parseProductionTestLimits(path_limits, + MS_CX1_MIN_MAX, + &thresholds, + &trows, + &tcolumns); if (ret < 0 || (trows != 1 || tcolumns != 2)) { - logError(1, "%s production_test_data: parseProductionTestLimits MS_CX1_MIN_MAX failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA); - return (ret | ERROR_PROD_TEST_DATA); + logError(1, "%s %s:parseProductionTestLimits failed ", + tag, __func__); + logError(1, "ERROR %02X\n", ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; } - container = (u16) msCompData.cx1; - ret = checkLimitsMinMax(&container, 1, 1, thresholds[0], thresholds[1]); /* check the limits */ + container = (u16)msCompData.cx1; + ret = checkLimitsMinMax(&container, + 1, + 1, + thresholds[0], + thresholds[1]); //check the limits if (ret != OK) { - logError(1, "%s production_test_data: checkLimitsMinMax MS CX1 failed... ERROR COUNT = %d\n", tag, ret); - logError(0, "%s MS CX1 TEST:.................FAIL\n\n", tag); + logError(1, "%s %s:checkLimitsMinMax MS CX1 failed ", + tag, __func__); + logError(1, "ERROR COUNT:%d\n", ret); + logError(0, "%s MS CX1 TEST:.........FAIL\n\n", tag); count_fail += 1; if (stop_on_fail) goto ERROR; } else - logError(0, "%s MS CX1 TEST:.................OK\n\n", tag); + logError(0, "%s MS CX1 TEST:..........OK\n\n", tag); } else - logError(0, "%s MS CX1 TEST:.................SKIPPED\n\n", tag); + logError(0, "%s MS CX1 TEST:.......SKIPPED\n\n", tag); kfree(thresholds); + thresholds = NULL; logError(0, "%s MS CX2 MIN MAX TEST:\n", tag); if (todo->MutualCx2 == 1) { - ret = parseProductionTestLimits(path_limits, MS_CX2_MAP_MIN, &thresholds_min, &trows, &tcolumns); /* load min thresholds */ - if (ret < 0 || (trows != msCompData.header.force_node || tcolumns != msCompData.header.sense_node)) { - logError(1, "%s production_test_data: parseProductionTestLimits MS_CX2_MAP_MIN failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA); - return (ret | ERROR_PROD_TEST_DATA); + ret = parseProductionTestLimits(path_limits, + MS_CX2_MAP_MIN, + &thresholds_min, + &trows, + &tcolumns); //load min thresholds + if (ret < 0 || (trows != msCompData.header.force_node + || tcolumns != msCompData.header.sense_node)) { + logError(1, "%s %s:parseProductionTestLimits ", + tag, __func__); + logError(1, "failed %02X\n", ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; } - ret = parseProductionTestLimits(path_limits, MS_CX2_MAP_MAX, &thresholds_max, &trows, &tcolumns); /* load max thresholds */ - if (ret < 0 || (trows != msCompData.header.force_node || tcolumns != msCompData.header.sense_node)) { - logError(1, "%s production_test_data: parseProductionTestLimits MS_CX2_MAP_MAX failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA); - return (ret | ERROR_PROD_TEST_DATA); + ret = parseProductionTestLimits(path_limits, + MS_CX2_MAP_MAX, + &thresholds_max, + &trows, + &tcolumns); //load max thresholds + if (ret < 0 || (trows != msCompData.header.force_node + || tcolumns != msCompData.header.sense_node)) { + logError(1, "%s %s: MS_CX2_MAP_MAX failed ERROR %02X\n", + tag, __func__, ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; } - ret = checkLimitsMap(msCompData.node_data, msCompData.header.force_node, msCompData.header.sense_node, thresholds_min, thresholds_max); /* check the limits */ + ret = checkLimitsMap(msCompData.node_data, + msCompData.header.force_node, + msCompData.header.sense_node, + thresholds_min, + thresholds_max);//check the limits if (ret != OK) { - logError(1, "%s production_test_data: checkLimitsMap MS CX2 MIN MAX failed... ERROR COUNT = %d\n", tag, ret); - logError(0, "%s MS CX2 MIN MAX TEST:.................FAIL\n\n", tag); + logError(1, "%s %s:checkLimitsMap MS CX2 MIN MAX ", + tag, __func__); + logError(1, "failed ERR_COUNT:%d\n", ret); + logError(0, "%s MS CX2 MIN MAX TEST:......FAIL\n\n", + tag); count_fail += 1; if (stop_on_fail) goto ERROR; } else - logError(0, "%s MS CX2 MIN MAX TEST:.................OK\n\n", tag); + logError(0, "%s MS CX2 MIN MAX TEST:....OK\n\n", tag); kfree(thresholds_min); + thresholds_min = NULL; kfree(thresholds_max); + thresholds_max = NULL; } else - logError(0, "%s MS CX2 MIN MAX TEST:.................SKIPPED\n\n", tag); + logError(0, "%s MS CX2 MIN MAX TEST:....SKIPPED\n\n", tag); logError(0, "%s MS CX2 ADJ TEST:\n", tag); if (todo->MutualCx2Adj == 1) { - /* MS CX2 ADJ HORIZ */ + //MS CX2 ADJ HORIZ logError(0, "%s MS CX2 ADJ HORIZ TEST:\n", tag); - ret = computeAdjHoriz(msCompData.node_data, msCompData.header.force_node, msCompData.header.sense_node, &adjhor); + ret = computeAdjHoriz(msCompData.node_data, + msCompData.header.force_node, + msCompData.header.sense_node, + &adjhor); if (ret < 0) { - logError(1, "%s production_test_data: computeAdjHoriz failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA); - return (ret | ERROR_PROD_TEST_DATA); + logError(1, "%s %s:computeAdjHoriz failed...", + tag, __func__); + logError(1, "ERROR %02X\n", ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; } logError(0, "%s MS CX2 ADJ HORIZ computed!\n", tag); - ret = parseProductionTestLimits(path_limits, MS_CX2_ADJH_MAP_MAX, &thresholds_max, &trows, &tcolumns); - if (ret < 0 || (trows != msCompData.header.force_node || tcolumns != msCompData.header.sense_node - 1)) { - logError(1, "%s production_test_data: parseProductionTestLimits MS_CX2_ADJH_MAP_MAX failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA); - return (ret | ERROR_PROD_TEST_DATA); + ret = parseProductionTestLimits(path_limits, + MS_CX2_ADJH_MAP_MAX, + &thresholds_max, &trows, + &tcolumns); + if (ret < 0 || (trows != msCompData.header.force_node + || tcolumns != msCompData.header.sense_node - 1)) { + + logError(1, "%s %s: MS_CX2_ADJH_MAP_MAX failed...", + tag, __func__); + logError(1, "ERROR %02X\n", ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; } - ret = checkLimitsMapAdj(adjhor, msCompData.header.force_node, msCompData.header.sense_node - 1, thresholds_max); + ret = checkLimitsMapAdj(adjhor, + msCompData.header.force_node, + msCompData.header.sense_node - 1, + thresholds_max); if (ret != OK) { - logError(1, "%s production_test_data: checkLimitsMapAdj CX2 ADJH failed... ERROR COUNT = %d\n", tag, ret); - logError(0, "%s MS CX2 ADJ HORIZ TEST:.................FAIL\n\n", tag); + logError(1, "%s %s:checkLimitsMapAdj CX2 ADJH failed ", + tag, __func__); + logError(1, "ERROR COUNT:%d\n", ret); + logError(0, "%s MS CX2 ADJ HORIZ TEST:..FAIL\n\n", tag); count_fail += 1; if (stop_on_fail) goto ERROR; } else - logError(0, "%s MS CX2 ADJ HORIZ TEST:.................OK\n\n", tag); + logError(0, "%s MS CX2 ADJ HORIZ TEST:..OK\n\n", tag); kfree(thresholds_max); + thresholds_max = NULL; kfree(adjhor); + adjhor = NULL; - /* MS CX2 ADJ VERT */ + //MS CX2 ADJ VERT logError(0, "%s MS CX2 ADJ VERT TEST:\n", tag); - - ret = computeAdjVert(msCompData.node_data, msCompData.header.force_node, msCompData.header.sense_node, &adjvert); + ret = computeAdjVert(msCompData.node_data, + msCompData.header.force_node, + msCompData.header.sense_node, + &adjvert); if (ret < 0) { - logError(1, "%s production_test_data: computeAdjVert failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA); - return (ret | ERROR_PROD_TEST_DATA); + logError(1, "%s %s:computeAdjVert failed... ", + tag, __func__); + logError(1, "ERROR %02X\n", ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; } logError(0, "%s MS CX2 ADJ VERT computed!\n", tag); - ret = parseProductionTestLimits(path_limits, MS_CX2_ADJV_MAP_MAX, &thresholds_max, &trows, &tcolumns); - if (ret < 0 || (trows != msCompData.header.force_node - 1 || tcolumns != msCompData.header.sense_node)) { - logError(1, "%s production_test_data: parseProductionTestLimits MS_CX2_ADJV_MAP_MAX failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA); - return (ret | ERROR_PROD_TEST_DATA); + ret = parseProductionTestLimits(path_limits, + MS_CX2_ADJV_MAP_MAX, + &thresholds_max, + &trows, + &tcolumns); + if (ret < 0 || (trows != msCompData.header.force_node - 1 + || tcolumns != msCompData.header.sense_node)) { + logError(1, "%s %s:MS_CX2_ADJV_MAP_MAX failed ", + tag, __func__); + logError(1, "ERROR %02X\n", ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; } - ret = checkLimitsMapAdj(adjvert, msCompData.header.force_node - 1, msCompData.header.sense_node - 1, thresholds_max); + ret = checkLimitsMapAdj(adjvert, + msCompData.header.force_node - 1, + msCompData.header.sense_node - 1, + thresholds_max); if (ret != OK) { - logError(1, "%s production_test_data: checkLimitsMapAdj CX2 ADJV failed... ERROR COUNT = %d\n", tag, ret); - logError(0, "%s MS CX2 ADJ HORIZ TEST:.................FAIL\n\n", tag); + logError(1, "%s %s:checkLimitsMapAdj CX2 ADJV failed ", + tag, __func__); + logError(1, "COUNT:%d\n", ret); + logError(0, "%s MS CX2 ADJ HORIZ TEST:FAIL\n\n", tag); count_fail += 1; if (stop_on_fail) goto ERROR; } else - logError(0, "%s MS CX2 ADJ VERT TEST:.................OK\n\n", tag); + logError(0, "%s MS CX2 ADJ VERT TEST:OK\n\n", tag); kfree(thresholds_max); + thresholds_max = NULL; kfree(adjvert); + adjvert = NULL; } else - logError(0, "%s MS CX2 ADJ TEST:.................SKIPPED\n\n", tag); + logError(0, "%s MS CX2 ADJ TEST:SKIPPED\n\n", tag); - /* START OF TOTAL CHECK */ + //START OF TOTAL CHECK logError(0, "%s MS TOTAL CX TEST:\n", tag); if (todo->MutualCxTotal == 1 || todo->MutualCxTotalAdj == 1) { - ret = computeTotal(msCompData.node_data, msCompData.cx1, msCompData.header.force_node, msCompData.header.sense_node, CX1_WEIGHT, CX2_WEIGHT, &total_cx); + ret = computeTotal(msCompData.node_data, + msCompData.cx1, + msCompData.header.force_node, + msCompData.header.sense_node, + CX1_WEIGHT, + CX2_WEIGHT, + &total_cx); if (ret < 0) { - logError(1, "%s production_test_data: computeTotalCx failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA); - return (ret | ERROR_PROD_TEST_DATA); + logError(1, "%s %s:computeTotalCx failed...", + tag, __func__); + logError(1, "ERROR %02X\n", ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; } logError(0, "%s MS TOTAL CX MIN MAX TEST:\n", tag); if (todo->MutualCxTotal == 1) { - ret = parseProductionTestLimits(path_limits, MS_TOTAL_CX_MAP_MIN, &thresholds_min, &trows, &tcolumns); /* load min thresholds */ - if (ret < 0 || (trows != msCompData.header.force_node || tcolumns != msCompData.header.sense_node)) { - logError(1, "%s production_test_data: parseProductionTestLimits MS_TOTAL_CX_MAP_MIN failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA); - return (ret | ERROR_PROD_TEST_DATA); + ret = parseProductionTestLimits(path_limits, + MS_TOTAL_CX_MAP_MIN, + &thresholds_min, + &trows, + &tcolumns);//load min thresholds + if (ret < 0 || (trows != msCompData.header.force_node + || tcolumns != msCompData.header.sense_node)) { + logError(1, "%s %s:parseProductionTestLimits ", + tag, __func__); + logError(1, "failed %02X\n", + ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; } - - ret = parseProductionTestLimits(path_limits, MS_TOTAL_CX_MAP_MAX, &thresholds_max, &trows, &tcolumns); /* load max thresholds */ - if (ret < 0 || (trows != msCompData.header.force_node || tcolumns != msCompData.header.sense_node)) { - logError(1, "%s production_test_data: parseProductionTestLimits MS_TOTAL_CX_MAP_MAX failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA); - return (ret | ERROR_PROD_TEST_DATA); + //load max thresholds + ret = parseProductionTestLimits(path_limits, + MS_TOTAL_CX_MAP_MAX, + &thresholds_max, + &trows, + &tcolumns); + if (ret < 0 || (trows != msCompData.header.force_node + || tcolumns != msCompData.header.sense_node)) { + logError(1, "%s %s:MS_TOTAL_CX_MAP_MAX failed", + tag, __func__); + logError(1, "...ERROR %02X\n", + ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; } - ret = checkLimitsMapTotal(total_cx, msCompData.header.force_node, msCompData.header.sense_node, thresholds_min, thresholds_max); /* check the limits */ + ret = checkLimitsMapTotal(total_cx, + msCompData.header.force_node, + msCompData.header.sense_node, + thresholds_min, + thresholds_max);//check the limits if (ret != OK) { - logError(1, "%s production_test_data: checkLimitsMap MS TOTAL CX TEST failed... ERROR COUNT = %d\n", tag, ret); - logError(0, "%s MS TOTAL CX MIN MAX TEST:.................FAIL\n\n", tag); + logError(1, "%s %s:MS TOTAL CX TEST failed ", + tag, __func__); + logError(1, "COUNT:%d\n", ret); + logError(0, "%s MS TOTAL CX MIN MAX ", tag); + logError(0, "TEST:FAIL\n\n"); count_fail += 1; if (stop_on_fail) goto ERROR; - } else - logError(0, "%s MS TOTAL CX MIN MAX TEST:.................OK\n\n", tag); + } else { + logError(0, "%s MS TOTAL CX MIN MAX TEST", tag); + logError(0, ":OK\n\n"); + } kfree(thresholds_min); + thresholds_min = NULL; kfree(thresholds_max); + thresholds_max = NULL; } else - logError(0, "%s MS TOTAL CX MIN MAX TEST:.................SKIPPED\n\n", tag); + logError(0, "%s MS TOTAL CX MIN MAX TEST:SKIPPED\n\n", + tag); + logError(0, "%s MS TOTAL CX ADJ TEST:\n", tag); if (todo->MutualCxTotalAdj == 1) { - /* MS TOTAL CX ADJ HORIZ */ + //MS TOTAL CX ADJ HORIZ logError(0, "%s MS TOTAL CX ADJ HORIZ TEST:\n", tag); - /* thresholds_max = NULL; */ - ret = computeAdjHorizTotal(total_cx, msCompData.header.force_node, msCompData.header.sense_node, &total_adjhor); + //thresholds_max = NULL; + ret = computeAdjHorizTotal(total_cx, + msCompData.header.force_node, + msCompData.header.sense_node, + &total_adjhor); if (ret < 0) { - logError(1, "%s production_test_data: computeAdjHoriz failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA); - return (ret | ERROR_PROD_TEST_DATA); + logError(1, "%s production_test_data: ", tag); + logError(1, "computeAdjHoriz failed... "); + logError(1, "ERROR %02X\n", + ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; } - logError(0, "%s MS TOTAL CX ADJ HORIZ computed!\n", tag); - - ret = parseProductionTestLimits(path_limits, MS_TOTAL_CX_ADJH_MAP_MAX, &thresholds_max, &trows, &tcolumns); - if (ret < 0 || (trows != msCompData.header.force_node || tcolumns != msCompData.header.sense_node - 1)) { - logError(1, "%s production_test_data: parseProductionTestLimits MS_TOTAL_CX_ADJH_MAP_MAX failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA); - return (ret | ERROR_PROD_TEST_DATA); + logError(0, "%s MS TOTAL CX ADJ HORIZ computed!\n", + tag); + ret = parseProductionTestLimits(path_limits, + MS_TOTAL_CX_ADJH_MAP_MAX, + &thresholds_max, &trows, + &tcolumns); + if (ret < 0 || (trows != msCompData.header.force_node + || tcolumns != msCompData.header.sense_node - 1)) { + logError(1, "%s production_test_data: ", tag); + logError(1, "parseProductionTestLimits "); + logError(1, "MS_TOTAL_CX_ADJH_MAP_MAX "); + logError(1, "failed...RROR %02X\n", + ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; } - ret = checkLimitsMapAdjTotal(total_adjhor, msCompData.header.force_node, msCompData.header.sense_node - 1, thresholds_max); + ret = checkLimitsMapAdjTotal(total_adjhor, + msCompData.header.force_node, + msCompData.header.sense_node - 1, + thresholds_max); if (ret != OK) { - logError(1, "%s production_test_data: checkLimitsMapAdj MS TOTAL CX ADJH failed... ERROR COUNT = %d\n", tag, ret); - logError(0, "%s MS TOTAL CX ADJ HORIZ TEST:.................FAIL\n\n", tag); + logError(1, "%s production_test_data: ", tag); + logError(1, "checkLimitsMapAdj MS TOTAL "); + logError(1, "CX ADJH failed... "); + logError(1, "ERROR COUNT = %d\n", ret); + logError(0, "%s MS TOTAL CX ADJ HORIZ ", tag); + logError(0, "TEST:.................FAIL\n\n"); count_fail += 1; if (stop_on_fail) goto ERROR; - } else - logError(0, "%s MS TOTAL CX ADJ HORIZ TEST:.................OK\n\n", tag); + } else { + logError(0, "%s MS TOTAL CX ADJ HORIZ ", tag); + logError(0, "TEST:.................OK\n\n"); + } kfree(thresholds_max); + thresholds_max = NULL; kfree(total_adjhor); + total_adjhor = NULL; - /* MS TOTAL CX ADJ VERT */ + //MS TOTAL CX ADJ VERT logError(0, "%s MS TOTAL CX ADJ VERT TEST:\n", tag); - ret = computeAdjVertTotal(total_cx, msCompData.header.force_node, msCompData.header.sense_node, &total_adjvert); + ret = computeAdjVertTotal(total_cx, + msCompData.header.force_node, + msCompData.header.sense_node, + &total_adjvert); if (ret < 0) { - logError(1, "%s production_test_data: computeAdjVert failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA); - return (ret | ERROR_PROD_TEST_DATA); + logError(1, "%s production_test_data: ", tag); + logError(1, "computeAdjVert failed... "); + logError(1, "ERROR %02X\n", + ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; } - logError(0, "%s MS TOTAL CX ADJ VERT computed!\n", tag); - - ret = parseProductionTestLimits(path_limits, MS_TOTAL_CX_ADJV_MAP_MAX, &thresholds_max, &trows, &tcolumns); - if (ret < 0 || (trows != msCompData.header.force_node - 1 || tcolumns != msCompData.header.sense_node)) { - logError(1, "%s production_test_data: parseProductionTestLimits MS_TOTAL_CX_ADJV_MAP_MAX failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA); - return (ret | ERROR_PROD_TEST_DATA); + logError(0, "%s MS TOTAL CX ADJ VERT computed!\n", + tag); + + ret = parseProductionTestLimits(path_limits, + MS_TOTAL_CX_ADJV_MAP_MAX, + &thresholds_max, + &trows, + &tcolumns); + if (ret < 0 || + (trows != msCompData.header.force_node - 1 + || tcolumns != msCompData.header.sense_node)) { + logError(1, "%s production_test_data: ", tag); + logError(1, "parseProductionTestLimits "); + logError(1, "MS_TOTAL_CX_ADJV_MAP_MAX failed"); + logError(1, "... ERROR %02X\n", + ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; } - ret = checkLimitsMapAdjTotal(total_adjvert, msCompData.header.force_node - 1, msCompData.header.sense_node - 1, thresholds_max); + ret = checkLimitsMapAdjTotal(total_adjvert, + msCompData.header.force_node - 1, + msCompData.header.sense_node - 1, + thresholds_max); if (ret != OK) { - logError(1, "%s production_test_data: checkLimitsMapAdj MS TOTAL CX ADJV failed... ERROR COUNT = %d\n", tag, ret); - logError(0, "%s MS TOTAL CX ADJ HORIZ TEST:.................FAIL\n", tag); + logError(1, "%s production_test_data: ", tag); + logError(1, "checkLimitsMapAdj MS TOTAL "); + logError(1, "CX ADJV failed... "); + logError(1, "ERROR COUNT = %d\n", ret); + logError(0, "%s MS TOTAL CX ADJ HORIZ ", tag); + logError(0, "TEST:.................FAIL\n"); count_fail += 1; if (stop_on_fail) goto ERROR; - } else - logError(0, "%s MS TOTAL CX ADJ VERT TEST:.................OK\n", tag); + } else { + logError(0, "%s MS TOTAL CX ADJ VERT ", tag); + logError(0, "TEST:.................OK\n"); + } kfree(thresholds_max); + thresholds_max = NULL; kfree(total_adjvert); - } else - logError(0, "%s MS TOTAL CX ADJ TEST:.................SKIPPED\n", tag); + total_adjvert = NULL; + } else { + logError(0, "%s MS TOTAL CX ADJ ", tag); + logError(0, "TEST:.................SKIPPED\n"); + } kfree(total_cx); + total_cx = NULL; } else - logError(0, "%s MS TOTAL CX TEST:.................SKIPPED\n", tag); + logError(0, "%s MS TOTAL CX TEST:.................SKIPPED\n", + tag); + + if ((todo->MutualKeyCx1 + | todo->MutualKeyCx2 | todo->MutualKeyCxTotal) == 1) { + ret = production_test_ms_key_cx(path_limits, + stop_on_fail, + todo); + if (ret < 0) { + count_fail += 1; + logError(1, "%s production_test_data: ", tag); + logError(1, "production_test_ms_key_cx failed..."); + logError(1, "ERROR = %02X\n", ret); + logError(0, "%s MS CX testes finished!", tag); + logError(0, ".................FAILED "); + logError(0, "fails_count = %d\n\n", count_fail); + return ret; + } + } else + logError(0, "%s MS KEY CX TEST:.................SKIPPED\n", + tag); - kfree(msCompData.node_data); + if ((todo->MutualKeyCx1 | todo->MutualKeyCx2 + | todo->MutualKeyCxTotal) == 1) { + ret = production_test_ms_key_cx(path_limits, + stop_on_fail, + todo); - if ((todo->MutualKeyCx1 | todo->MutualKeyCx2 | todo->MutualKeyCxTotal) == 1) { - ret = production_test_ms_key_cx(path_limits, stop_on_fail, todo); if (ret < 0) { count_fail += 1; - logError(1, "%s production_test_data: production_test_ms_key_cx failed... ERROR = %02X\n", tag, ret); - logError(0, "%s MS CX testes finished!.................FAILED fails_count = %d\n\n", tag, count_fail); + logError(1, "%s %s:production_test_ms_key_cx ", + tag, __func__); + logError(1, "failed :%02X\n", ret); + logError(0, "%s MS CX testes finished! ", tag); + logError(0, "fails_count = %d\n\n", count_fail); return ret; } } else - logError(0, "%s MS KEY CX TEST:.................SKIPPED\n", tag); - + logError(0, "%s MS KEY CX TEST:..SKIPPED\n", tag); ERROR: logError(0, "%s\n", tag); if (count_fail == 0) { - logError(0, "%s MS CX testes finished!.................OK\n", tag); + logError(0, "%s MS CX testes finished! OK\n", tag); + kfree(msCompData.node_data); + msCompData.node_data = NULL; return OK; } - print_frame_u8("MS Init Data (Cx2) =", array1dTo2d_u8(msCompData.node_data, msCompData.node_data_size, msCompData.header.sense_node), msCompData.header.force_node, msCompData.header.sense_node); - logError(0, "%s MS CX testes finished!.................FAILED fails_count = %d\n\n", tag, count_fail); + print_frame_u8("MS Init Data (Cx2) =", + array1dTo2d_u8(msCompData.node_data, + msCompData.node_data_size, + msCompData.header.sense_node), + msCompData.header.force_node, + msCompData.header.sense_node); + logError(0, "%s MS CX testes finished! fails_count = %d\n\n", + tag, count_fail); + if (thresholds != NULL) + kfree(thresholds); + if (thresholds_min != NULL) + kfree(thresholds_min); + if (thresholds_max != NULL) + kfree(thresholds_max); + if (adjhor != NULL) + kfree(adjhor); + if (adjvert != NULL) + kfree(adjvert); + if (total_cx != NULL) + kfree(total_cx); + if (total_adjhor != NULL) + kfree(total_adjhor); + if (total_adjvert != NULL) + kfree(total_adjvert); + if (msCompData.node_data != NULL) + kfree(msCompData.node_data); + return (ERROR_TEST_CHECK_FAIL | ERROR_PROD_TEST_DATA); +ERROR_LIMITS: + if (thresholds != NULL) + kfree(thresholds); + if (thresholds_min != NULL) + kfree(thresholds_min); + if (thresholds_max != NULL) + kfree(thresholds_max); + if (adjhor != NULL) + kfree(adjhor); + if (adjvert != NULL) + kfree(adjvert); + if (total_cx != NULL) + kfree(total_cx); + if (total_adjhor != NULL) + kfree(total_adjhor); + if (total_adjvert != NULL) + kfree(total_adjvert); + if (msCompData.node_data != NULL) + kfree(msCompData.node_data); + return ret; } -int production_test_ms_key_cx(char *path_limits, int stop_on_fail, TestToDo *todo) +int production_test_ms_key_cx(char *path_limits, int stop_on_fail, + struct TestToDo *todo) { - int ret; int count_fail = 0; int num_keys = 0; @@ -1082,22 +1541,27 @@ int production_test_ms_key_cx(char *path_limits, int stop_on_fail, TestToDo *tod int *thresholds_max = NULL; int trows, tcolumns; - MutualSenseData msCompData; + struct MutualSenseData msCompData; u16 container; u16 *total_cx = NULL; - /* MS CX TEST */ + + //MS CX TEST logError(0, "%s MS KEY CX Testes are starting...\n", tag); - ret = readMutualSenseCompensationData(MS_KEY, &msCompData); /* read MS compensation data */ + //read MS compensation data + ret = readMutualSenseCompensationData(MS_KEY, &msCompData); if (ret < 0) { - logError(1, "%s production_test_data: readMutualSenseCompensationData failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA); + logError(1, "%s production_test_data: ", tag); + logError(1, "readMutualSenseCompensationData failed... "); + logError(1, "ERROR %02X\n", ERROR_PROD_TEST_DATA); return (ret | ERROR_PROD_TEST_DATA); } + //the meaningful data are only in the first row, the other rows are + // only a copy of the first one if (msCompData.header.force_node > msCompData.header.sense_node) -/* the meaningful data are only in the first row, the other rows are only a copy of the first one */ num_keys = msCompData.header.force_node; else num_keys = msCompData.header.sense_node; @@ -1105,264 +1569,525 @@ int production_test_ms_key_cx(char *path_limits, int stop_on_fail, TestToDo *tod logError(0, "%s MS KEY CX1 TEST:\n", tag); if (todo->MutualKeyCx1 == 1) { - ret = parseProductionTestLimits(path_limits, MS_KEY_CX1_MIN_MAX, &thresholds, &trows, &tcolumns); + ret = parseProductionTestLimits(path_limits, + MS_KEY_CX1_MIN_MAX, + &thresholds, + &trows, + &tcolumns); if (ret < 0 || (trows != 1 || tcolumns != 2)) { - logError(1, "%s production_test_data: parseProductionTestLimits MS_KEY_CX1_MIN_MAX failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA); - return (ret | ERROR_PROD_TEST_DATA); + logError(1, "%s production_test_data: ", tag); + logError(1, "parseProductionTestLimits "); + logError(1, "MS_KEY_CX1_MIN_MAX failed... "); + logError(1, "ERROR %02X\n", ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; } container = (u16) msCompData.cx1; - ret = checkLimitsMinMax(&container, 1, 1, thresholds[0], thresholds[1]); /* check the limits */ + ret = checkLimitsMinMax(&container, + 1, + 1, + thresholds[0], + thresholds[1]); //check the limits if (ret != OK) { - logError(1, "%s production_test_data: checkLimitsMinMax MS CX1 failed... ERROR COUNT = %d\n", tag, ret); - logError(0, "%s MS KEY CX1 TEST:.................FAIL\n\n", tag); + logError(1, "%s production_test_data: ", tag); + logError(1, "checkLimitsMinMax MS CX1 failed... "); + logError(1, "ERROR COUNT = %d\n", ret); + logError(0, "%s MS KEY CX1 TEST:................", tag); + logError(0, ".FAIL\n\n"); count_fail += 1; if (stop_on_fail) goto ERROR; - } else - logError(0, "%s MS KEY CX1 TEST:.................OK\n\n", tag); + } else { + logError(0, "%s MS KEY CX1 TEST:................", tag); + logError(0, ".OK\n\n"); + } } else - logError(0, "%s MS KEY CX1 TEST:.................SKIPPED\n\n", tag); + logError(0, "%s MS KEY CX1 TEST:.................SKIPPED\n\n", + tag); kfree(thresholds); + thresholds = NULL; logError(0, "%s MS KEY CX2 TEST:\n", tag); if (todo->MutualKeyCx2 == 1) { - ret = parseProductionTestLimits(path_limits, MS_KEY_CX2_MAP_MIN, &thresholds_min, &trows, &tcolumns); /* load min thresholds */ + //load min thresholds + ret = parseProductionTestLimits(path_limits, + MS_KEY_CX2_MAP_MIN, + &thresholds_min, + &trows, + &tcolumns); if (ret < 0 || (trows != 1 || tcolumns != num_keys)) { - logError(1, "%s production_test_data: parseProductionTestLimits MS_KEY_CX2_MAP_MIN failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA); - return (ret | ERROR_PROD_TEST_DATA); + logError(1, "%s production_test_data: ", tag); + logError(1, "parseProductionTestLimits "); + logError(1, "MS_KEY_CX2_MAP_MIN failed... "); + logError(1, "ERROR %02X\n", ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; } - ret = parseProductionTestLimits(path_limits, MS_KEY_CX2_MAP_MAX, &thresholds_max, &trows, &tcolumns); /* load max thresholds */ + //load max thresholds + ret = parseProductionTestLimits(path_limits, + MS_KEY_CX2_MAP_MAX, + &thresholds_max, + &trows, + &tcolumns); if (ret < 0 || (trows != 1 || tcolumns != num_keys)) { - logError(1, "%s production_test_data: parseProductionTestLimits MS_KEY_CX2_MAP_MAX failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA); - return (ret | ERROR_PROD_TEST_DATA); + logError(1, "%s production_test_data: ", tag); + logError(1, "parseProductionTestLimits "); + logError(1, "MS_KEY_CX2_MAP_MAX failed... "); + logError(1, "ERROR %02X\n", ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; } - ret = checkLimitsMap(msCompData.node_data, 1, num_keys, thresholds_min, thresholds_max); /* check the limits */ + //check the limits + ret = checkLimitsMap(msCompData.node_data, + 1, + num_keys, + thresholds_min, + thresholds_max); if (ret != OK) { - logError(1, "%s production_test_data: checkLimitsMap MS KEY CX2 failed... ERROR COUNT = %d\n", tag, ret); - logError(0, "%s MS KEY CX2 TEST:.................FAIL\n\n", tag); + logError(1, "%s production_test_data: ", tag); + logError(1, "checkLimitsMap MS KEY CX2 failed... "); + logError(1, "ERROR COUNT = %d\n", ret); + logError(0, "%s MS KEY CX2 TEST:................", tag); + logError(0, ".FAIL\n\n"); count_fail += 1; if (stop_on_fail) goto ERROR; - } else - logError(0, "%s MS KEY CX2 TEST:.................OK\n\n", tag); + } else { + logError(0, "%s MS KEY CX2 TEST:...............", tag); + logError(0, "..OK\n\n"); + } kfree(thresholds_min); + thresholds_min = NULL; kfree(thresholds_max); + thresholds_max = NULL; } else - logError(0, "%s MS CX2 TEST:.................SKIPPED\n\n", tag); + logError(0, "%s MS CX2 TEST:.................SKIPPED\n\n", + tag); - /* START OF TOTAL CHECK */ + //START OF TOTAL CHECK logError(0, "%s MS KEY TOTAL CX TEST:\n", tag); if (todo->MutualKeyCxTotal == 1) { - ret = computeTotal(msCompData.node_data, msCompData.cx1, 1, num_keys, CX1_WEIGHT, CX2_WEIGHT, &total_cx); + ret = computeTotal(msCompData.node_data, + msCompData.cx1, 1, + num_keys, + CX1_WEIGHT, + CX2_WEIGHT, + &total_cx); if (ret < 0) { - logError(1, "%s production_test_data: computeTotalCx failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA); - return (ret | ERROR_PROD_TEST_DATA); + logError(1, "%s production_test_data: ", tag); + logError(1, "computeTotalCx failed... "); + logError(1, "ERROR %02X\n", ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; } - ret = parseProductionTestLimits(path_limits, MS_KEY_TOTAL_CX_MAP_MIN, &thresholds_min, &trows, &tcolumns); /* load min thresholds */ + //load min thresholds + ret = parseProductionTestLimits(path_limits, + MS_KEY_TOTAL_CX_MAP_MIN, + &thresholds_min, + &trows, + &tcolumns); if (ret < 0 || (trows != 1 || tcolumns != num_keys)) { - logError(1, "%s production_test_data: parseProductionTestLimits MS_KEY_TOTAL_CX_MAP_MIN failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA); - return (ret | ERROR_PROD_TEST_DATA); + logError(1, "%s production_test_data: ", tag); + logError(1, "%parseProductionTestLimits "); + logError(1, "MS_KEY_TOTAL_CX_MAP_MIN failed... "); + logError(1, "ERROR %02X\n", ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; } - ret = parseProductionTestLimits(path_limits, MS_KEY_TOTAL_CX_MAP_MAX, &thresholds_max, &trows, &tcolumns); /* load max thresholds */ + //load max thresholds + ret = parseProductionTestLimits(path_limits, + MS_KEY_TOTAL_CX_MAP_MAX, + &thresholds_max, + &trows, + &tcolumns); if (ret < 0 || (trows != 1 || tcolumns != num_keys)) { - logError(1, "%s production_test_data: parseProductionTestLimits MS_KEY_TOTAL_CX_MAP_MAX failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA); - return (ret | ERROR_PROD_TEST_DATA); + logError(1, "%s production_test_data: ", tag); + logError(1, "parseProductionTestLimits "); + logError(1, "MS_KEY_TOTAL_CX_MAP_MAX failed... "); + logError(1, "ERROR %02X\n", ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; } - ret = checkLimitsMapTotal(total_cx, 1, num_keys, thresholds_min, thresholds_max); /* check the limits */ + //check the limits + ret = checkLimitsMapTotal(total_cx, + 1, + num_keys, + thresholds_min, + thresholds_max); if (ret != OK) { - logError(1, "%s production_test_data: checkLimitsMap MS TOTAL KEY CX TEST failed... ERROR COUNT = %d\n", tag, ret); - logError(0, "%s MS KEY TOTAL CX TEST:.................FAIL\n\n", tag); + logError(1, "%s production_test_data: ", tag); + logError(1, "checkLimitsMap MS TOTAL "); + logError(1, "KEY CX TEST failed... ERROR COUNT = %d\n", + ret); + logError(0, "%s MS KEY TOTAL CX TEST:...........", tag); + logError(0, "......FAIL\n\n"); count_fail += 1; if (stop_on_fail) goto ERROR; - } else - logError(0, "%s MS KEY TOTAL CX TEST:.................OK\n\n", tag); + } else { + logError(0, "%s MS KEY TOTAL CX TEST:...........", tag); + logError(0, "......OK\n\n"); + } kfree(thresholds_min); + thresholds_min = NULL; kfree(thresholds_max); + thresholds_max = NULL; kfree(total_cx); - } else - logError(0, "%s MS KEY TOTAL CX TEST:.................SKIPPED\n", tag); + total_cx = NULL; + } else { + logError(0, "%s MS KEY TOTAL CX TEST:.................", tag); + logError(0, "SKIPPED\n"); + } - kfree(msCompData.node_data); ERROR: logError(0, "%s\n", tag); if (count_fail == 0) { - logError(0, "%s MS KEY CX testes finished!.................OK\n", tag); - return OK; - } - print_frame_u8("MS Key Init Data (Cx2) =", array1dTo2d_u8(msCompData.node_data, msCompData.node_data_size, msCompData.header.sense_node), 1, msCompData.header.sense_node); - logError(0, "%s MS Key CX testes finished!.................FAILED fails_count = %d\n\n", tag, count_fail); - return (ERROR_TEST_CHECK_FAIL | ERROR_PROD_TEST_DATA); + logError(0, + "%s MS KEY CX testes finished! OK\n", tag); + kfree(msCompData.node_data); + msCompData.node_data = NULL; + return OK; + } + print_frame_u8("MS Key Init Data (Cx2) =", + array1dTo2d_u8(msCompData.node_data, + msCompData.node_data_size, + msCompData.header.sense_node), + 1, + msCompData.header.sense_node); + logError(0, "%s MS Key CX testes finished!..............", tag); + logError(0, "...FAILED fails_count = %d\n\n", count_fail); + if (thresholds != NULL) + kfree(thresholds); + if (thresholds_min != NULL) + kfree(thresholds_min); + if (thresholds_max != NULL) + kfree(thresholds_max); + if (msCompData.node_data != NULL) + kfree(msCompData.node_data); + if (total_cx != NULL) + kfree(total_cx); + return (ERROR_TEST_CHECK_FAIL | ERROR_PROD_TEST_DATA); +ERROR_LIMITS: + if (thresholds != NULL) + kfree(thresholds); + if (thresholds_min != NULL) + kfree(thresholds_min); + if (thresholds_max != NULL) + kfree(thresholds_max); + if (msCompData.node_data != NULL) + kfree(msCompData.node_data); + if (total_cx != NULL) + kfree(total_cx); + return ret; } -int production_test_ss_raw(char *path_limits, int stop_on_fail, TestToDo *todo) +int production_test_ss_raw(char *path_limits, + int stop_on_fail, struct TestToDo *todo) { int ret; int count_fail = 0; int rows, columns; - /* short *ssRawFrame = NULL; */ - SelfSenseFrame ssRawFrame; + //short *ssRawFrame = NULL; + struct SelfSenseFrame ssRawFrame; int *thresholds = NULL; int trows, tcolumns; - /* MS SS TEST */ + //MS SS TEST logError(0, "%s\n", tag); logError(0, "%s SS RAW Testes are starting...\n", tag); - /******************************* Self Sense Test *******************************/ - + //******* Self Sense Test ***************/ logError(0, "%s Getting SS Frame...\n", tag); ret = getSSFrame2(SS_TOUCH, &ssRawFrame); - if (ret < 0) { - logError(1, "%s production_test_data: getSSFrame failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA); - return (ret | ERROR_PROD_TEST_DATA); - } + if (ret < 0) { + logError(1, "%s %s:getSSFrame failed...ERROR %02X\n", + tag, __func__, ERROR_PROD_TEST_DATA); + return (ret | ERROR_PROD_TEST_DATA); + } - /* SS RAW (PROXIMITY) FORCE TEST */ + //SS RAW (PROXIMITY) FORCE TEST logError(0, "%s SS RAW (PROXIMITY) FORCE TEST:\n", tag); if (todo->SelfForceRaw == 1 || todo->SelfForceRawGap == 1) { - + //there are no data for the sense + //channels due to the fact that + //the force frame is analized columns = 1; - /* there are no data for the sense channels due to the fact that the force frame is analized */ rows = ssRawFrame.header.force_node; logError(0, "%s SS RAW (PROXIMITY) FORCE MIN MAX TEST:\n", tag); if (todo->SelfForceRaw == 1) { - - ret = parseProductionTestLimits(path_limits, SS_RAW_FORCE_MIN_MAX, &thresholds, &trows, &tcolumns); + ret = parseProductionTestLimits(path_limits, + SS_RAW_FORCE_MIN_MAX, + &thresholds, + &trows, + &tcolumns); if (ret < 0 || (trows != 1 || tcolumns != 2)) { - logError(1, "%s production_test_data: parseProductionTestLimits SS_RAW_FORCE_MIN_MAX failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA); - return (ret | ERROR_PROD_TEST_DATA); + logError(1, "%s %s:parseProductionTestLimits ", + tag, __func__); + logError(1, "failed %02X\n", + ERROR_PROD_TEST_DATA); + //return (ret | ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; } - ret = checkLimitsMinMax(ssRawFrame.force_data, rows, columns, thresholds[0], thresholds[1]); + ret = checkLimitsMinMax(ssRawFrame.force_data, + rows, columns, + thresholds[0], + thresholds[1]); if (ret != OK) { - logError(1, "%s production_test_data: checkLimitsMinMax SS RAW (PROXIMITY) FORCE failed... ERROR COUNT = %d\n", tag, ret); - logError(0, "%s SS RAW (PROXIMITY) FORCE MIN MAX TEST:.................FAIL\n\n", tag); + logError(1, "%s %s:checkLimitsMinMax ", + tag, __func__); + logError(1, "failed ERROR COUNT:%d\n", ret); + logError(0, "%s SS RAW (PROXIMITY) FORCE", tag); + logError(0, " MIN MAX TEST:FAIL\n\n"); count_fail += 1; - print_frame_short("SS Raw force frame =", array1dTo2d_short(ssRawFrame.force_data, rows*columns, columns), rows, columns); - if (stop_on_fail) - return (ERROR_PROD_TEST_DATA | ERROR_TEST_CHECK_FAIL); - } else - logError(0, "%s SS RAW (PROXIMITY) FORCE MIN MAX TEST:.................OK\n\n", tag); + print_frame_short("SS Raw force frame =", + array1dTo2d_short(ssRawFrame.force_data, + rows*columns, columns), + rows, + columns); + if (stop_on_fail) { + ret = ERROR_PROD_TEST_DATA + | ERROR_TEST_CHECK_FAIL; + goto ERROR_LIMITS; + } + } else { + logError(0, "%s SS RAW (PROXIMITY) ", tag); + logError(0, "FORCE MIN MAX TEST:............."); + logError(0, "....OK\n\n"); + } kfree(thresholds); - } else - logError(0, "%s SS RAW (PROXIMITY) FORCE MIN MAX TEST:.................SKIPPED\n\n", tag); + thresholds = NULL; + } else { + logError(0, "%s SS RAW (PROXIMITY) ", tag); + logError(0, "FORCE MIN MAX TEST:................."); + logError(0, "SKIPPED\n\n"); + } logError(0, "%s\n", tag); logError(0, "%s SS RAW (PROXIMITY) FORCE GAP TEST:\n", tag); if (todo->SelfForceRawGap == 1) { - - ret = parseProductionTestLimits(path_limits, SS_RAW_FORCE_GAP, &thresholds, &trows, &tcolumns); + ret = parseProductionTestLimits(path_limits, + SS_RAW_FORCE_GAP, + &thresholds, + &trows, + &tcolumns); if (ret < 0 || (trows != 1 || tcolumns != 1)) { - logError(1, "%s production_test_data: parseProductionTestLimits SS_RAW_FORCE_GAP failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA); - return (ret | ERROR_PROD_TEST_DATA); + logError(1, "%s production_test_data: ", tag); + logError(1, "parseProductionTestLimits "); + logError(1, "SS_RAW_FORCE_GAP failed... "); + logError(1, "ERROR %02X\n", + ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; } - ret = checkLimitsGap(ssRawFrame.force_data, rows, columns, thresholds[0]); + ret = checkLimitsGap(ssRawFrame.force_data, + rows, + columns, + thresholds[0]); + if (ret != OK) { - logError(1, "%s production_test_data: checkLimitsGap SS RAW (PROXIMITY) FORCE GAP failed... ERROR = %02X\n", tag, ret); - logError(0, "%s SS RAW (PROXIMITY) FORCE GAP TEST:.................FAIL\n\n", tag); + logError(1, "%s production_test_data: ", tag); + logError(1, "checkLimitsGap SS RAW "); + logError(1, "(PROXIMITY) FORCE GAP failed..."); + logError(1, "ERROR = %02X\n", ret); + logError(0, "%s SS RAW (PROXIMITY) ", tag); + logError(0, "FORCE GAP TEST:................."); + logError(0, "FAIL\n\n"); count_fail += 1; - print_frame_short("SS Raw force frame =", array1dTo2d_short(ssRawFrame.force_data, rows*columns, columns), rows, columns); - if (stop_on_fail) - return (ERROR_PROD_TEST_DATA | ERROR_TEST_CHECK_FAIL); - } else - logError(0, "%s SS RAW (PROXIMITY) FORCE GAP TEST:.................OK\n\n", tag); + print_frame_short("SS Raw force frame =", + array1dTo2d_short(ssRawFrame.force_data, + rows*columns, columns), + rows, + columns); + if (stop_on_fail) { + ret = ERROR_PROD_TEST_DATA + | ERROR_TEST_CHECK_FAIL; + goto ERROR_LIMITS; + } + } else { + logError(0, "%s SS RAW (PROXIMITY) ", tag); + logError(0, "FORCE GAP TEST:................."); + logError(0, "OK\n\n"); + } kfree(thresholds); - } else - logError(0, "%s SS RAW (PROXIMITY) FORCE GAP TEST:.................SKIPPED\n\n", tag); + thresholds = NULL; + } else { + logError(0, "%s SS RAW (PROXIMITY) ", tag); + logError(0, "FORCE GAP TEST:................."); + logError(0, "SKIPPED\n\n"); + } kfree(ssRawFrame.force_data); - } else - logError(0, "%s SS RAW (PROXIMITY) FORCE TEST:.................SKIPPED\n\n", tag); + ssRawFrame.force_data = NULL; + } else { + logError(0, "%s SS RAW (PROXIMITY) FORCE ", tag); + logError(0, "TEST:.................SKIPPED\n\n"); + } logError(0, "%s\n", tag); - /* SS RAW (PROXIMITY) SENSE TEST */ + //SS RAW (PROXIMITY) SENSE TEST logError(0, "%s SS RAW (PROXIMITY) SENSE TEST:\n", tag); if (todo->SelfSenseRaw == 1 || todo->SelfSenseRawGap == 1) { columns = ssRawFrame.header.sense_node; - rows = 1; /* there are no data for the force channels due to the fact that the sense frame is analized */ + // there are no data for the force channels due + // to the fact that the sense frame is analized + rows = 1; logError(0, "%s SS RAW (PROXIMITY) SENSE MIN MAX TEST:\n", tag); if (todo->SelfSenseRaw == 1) { - ret = parseProductionTestLimits(path_limits, SS_RAW_SENSE_MIN_MAX, &thresholds, &trows, &tcolumns); + ret = parseProductionTestLimits(path_limits, + SS_RAW_SENSE_MIN_MAX, + &thresholds, + &trows, + &tcolumns); if (ret < 0 || (trows != 1 || tcolumns != 2)) { - logError(1, "%s production_test_data: parseProductionTestLimits SS_RAW_SENSE_MIN_MAX failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA); - return (ret | ERROR_PROD_TEST_DATA); + logError(1, "%s production_test_data: ", tag); + logError(1, "parseProductionTestLimits "); + logError(1, "SS_RAW_SENSE_MIN_MAX failed... "); + logError(1, "ERROR %02X\n", + ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; } - ret = checkLimitsMinMax(ssRawFrame.sense_data, rows, columns, thresholds[0], thresholds[1]); + ret = checkLimitsMinMax(ssRawFrame.sense_data, + rows, + columns, + thresholds[0], + thresholds[1]); if (ret != OK) { - logError(1, "%s production_test_data: checkLimitsMinMax SS RAW (PROXIMITY) SENSE failed... ERROR COUNT = %d\n", tag, ret); - logError(0, "%s SS RAW (PROXIMITY) SENSE MIN MAX TEST:.................FAIL\n", tag); + logError(1, "%s production_test_data: ", tag); + logError(1, "checkLimitsMinMax SS RAW "); + logError(1, "(PROXIMITY) SENSE failed... "); + logError(1, "ERROR COUNT = %d\n", ret); + logError(0, "%s SS RAW (PROXIMITY) ", tag); + logError(0, "SENSE MIN MAX TEST:............."); + logError(0, "....FAIL\n"); count_fail += 1; - print_frame_short("SS Raw sense frame =", array1dTo2d_short(ssRawFrame.sense_data, rows*columns, columns), rows, columns); - if (stop_on_fail) - return (ERROR_PROD_TEST_DATA | ERROR_TEST_CHECK_FAIL); - } else - logError(0, "%s SS RAW (PROXIMITY) SENSE MIN MAX TEST:.................OK\n", tag); + print_frame_short("SS Raw sense frame =", + array1dTo2d_short(ssRawFrame.sense_data, + rows*columns, columns), + rows, + columns); + if (stop_on_fail) { + ret = ERROR_PROD_TEST_DATA + | ERROR_TEST_CHECK_FAIL; + goto ERROR_LIMITS; + } + } else { + logError(0, "%s SS RAW (PROXIMITY) ", tag); + logError(0, "SENSE MIN MAX TEST:............."); + logError(0, "....OK\n"); + } kfree(thresholds); - } else - logError(0, "%s SS RAW (PROXIMITY) SENSE MIN MAX TEST:.................SKIPPED\n", tag); + thresholds = NULL; + } else { + logError(0, "%s SS RAW (PROXIMITY) SENSE MIN MAX", tag); + logError(0, " TEST:.................SKIPPED\n"); + } logError(0, "%s\n", tag); logError(0, "%s SS RAW (PROXIMITY) SENSE GAP TEST:\n", tag); if (todo->SelfSenseRawGap == 1) { - ret = parseProductionTestLimits(path_limits, SS_RAW_SENSE_GAP, &thresholds, &trows, &tcolumns); + ret = parseProductionTestLimits(path_limits, + SS_RAW_SENSE_GAP, + &thresholds, + &trows, + &tcolumns); if (ret < 0 || (trows != 1 || tcolumns != 1)) { - logError(1, "%s production_test_data: parseProductionTestLimits SS_RAW_SENSE_GAP failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA); - return (ret | ERROR_PROD_TEST_DATA); + logError(1, "%s production_test_data: ", tag); + logError(1, "parseProductionTestLimits "); + logError(1, "SS_RAW_SENSE_GAP failed... "); + logError(1, "ERROR %02X\n", + ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; } - ret = checkLimitsGap(ssRawFrame.sense_data, rows, columns, thresholds[0]); + ret = checkLimitsGap(ssRawFrame.sense_data, + rows, + columns, + thresholds[0]); if (ret != OK) { - logError(1, "%s production_test_data: checkLimitsGap SS RAW (PROXIMITY) SENSE GAP failed... ERROR = %02X\n", tag, ret); - logError(0, "%s SS RAW (PROXIMITY) SENSE GAP TEST:.................FAIL\n", tag); + logError(1, "%s production_test_data: ", tag); + logError(1, "checkLimitsGap SS RAW "); + logError(1, "(PROXIMITY) SENSE GAP failed... "); + logError(1, "ERROR = %02X\n", ret); + logError(0, "%s SS RAW (PROXIMITY) ", tag); + logError(0, "SENSE GAP TEST:................."); + logError(0, "FAIL\n"); count_fail += 1; - print_frame_short("SS Raw sense frame =", array1dTo2d_short(ssRawFrame.sense_data, rows*columns, columns), rows, columns); - if (stop_on_fail) - return (ERROR_PROD_TEST_DATA | ERROR_TEST_CHECK_FAIL); - } else - logError(0, "%s SS RAW (PROXIMITY) SENSE GAP TEST:.................OK\n", tag); + print_frame_short("SS Raw sense frame =", + array1dTo2d_short(ssRawFrame.sense_data, + rows*columns, columns), + rows, + columns); + if (stop_on_fail) { + ret = ERROR_PROD_TEST_DATA + | ERROR_TEST_CHECK_FAIL; + goto ERROR_LIMITS; + } + } else { + logError(0, "%s SS RAW (PROXIMITY) SENSE", tag); + logError(0, " GAP TEST:.................OK\n"); + } kfree(thresholds); - } else - logError(0, "%s SS RAW (PROXIMITY) SENSE GAP TEST:.................SKIPPED\n", tag); + thresholds = NULL; + } else { + logError(0, "%s SS RAW (PROXIMITY) SENSE GAP ", tag); + logError(0, "TEST:.................SKIPPED\n"); + } kfree(ssRawFrame.sense_data); + ssRawFrame.sense_data = NULL; } logError(0, "%s\n", tag); if (count_fail == 0) { - logError(0, "%s SS RAW testes finished!.................OK\n\n", tag); + logError(0, "%s SS RAW testes finished!.................OK\n\n", + tag); return OK; } - logError(0, "%s SS RAW testes finished!.................FAILED fails_count = %d\n\n", tag, count_fail); + logError(0, "%s SS RAW testes finished!.................", tag); + logError(0, "FAILED fails_count = %d\n\n", count_fail); return (ERROR_TEST_CHECK_FAIL | ERROR_PROD_TEST_DATA); + +ERROR_LIMITS: + if (ssRawFrame.force_data != NULL) + kfree(ssRawFrame.force_data); + if (ssRawFrame.sense_data != NULL) + kfree(ssRawFrame.sense_data); + if (thresholds != NULL) + kfree(thresholds); + return ret; + } -int production_test_ss_ix_cx(char *path_limits, int stop_on_fail, TestToDo *todo) +int production_test_ss_ix_cx(char *path_limits, int stop_on_fail, + struct TestToDo *todo) { - int ret; int count_fail = 0; @@ -1371,13 +2096,14 @@ int production_test_ss_ix_cx(char *path_limits, int stop_on_fail, TestToDo *todo int *thresholds_min = NULL; int *thresholds_max = NULL; - SelfSenseData ssCompData; + struct SelfSenseData ssCompData; u8 *adjhor = NULL; u8 *adjvert = NULL; u16 container; - int *ix1_w, *ix2_w; + int *ix1_w = NULL; + int *ix2_w = NULL; u16 *total_ix = NULL; u16 *total_cx = NULL; @@ -1386,728 +2112,1546 @@ int production_test_ss_ix_cx(char *path_limits, int stop_on_fail, TestToDo *todo logError(0, "%s\n", tag); logError(0, "%s SS IX CX testes are starting...\n", tag); - ret = readSelfSenseCompensationData(SS_TOUCH, &ssCompData); /* read the SS compensation data */ + + //read the SS compensation data + ret = readSelfSenseCompensationData(SS_TOUCH, &ssCompData); if (ret < 0) { - logError(1, "%s production_test_data: readSelfSenseCompensationData failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA); + logError(1, "%s production_test_data: ", tag); + logError(1, "readSelfSenseCompensationData failed... ", tag); + logError(1, "ERROR %02X\n", ERROR_PROD_TEST_DATA); return (ret | ERROR_PROD_TEST_DATA); } - /*************************** SS FORCE IX *************************************/ - /* SS IX1 FORCE TEST */ + //********************** SS FORCE IX *********************************/ + //SS IX1 FORCE TEST logError(0, "%s SS IX1 FORCE TEST:\n", tag); if (todo->SelfForceIx1 == 1) { - - ret = parseProductionTestLimits(path_limits, SS_IX1_FORCE_MIN_MAX, &thresholds, &trows, &tcolumns); + ret = parseProductionTestLimits(path_limits, + SS_IX1_FORCE_MIN_MAX, + &thresholds, + &trows, + &tcolumns); if (ret < 0 || (trows != 1 || tcolumns != 2)) { - logError(1, "%s production_test_data: parseProductionTestLimits SS_IX1_FORCE_MIN_MAX failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA); - return (ret | ERROR_PROD_TEST_DATA); + logError(1, "%s production_test_data: ", tag); + logError(1, "parseProductionTestLimits "); + logError(1, "SS_IX1_FORCE_MIN_MAX failed... "); + logError(1, "ERROR %02X\n", ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; } container = (u16) ssCompData.f_ix1; - ret = checkLimitsMinMax(&container, 1, 1, thresholds[0], thresholds[1]); /* check the limits */ + + //check the limits + ret = checkLimitsMinMax(&container, + 1, + 1, + thresholds[0], + thresholds[1]); if (ret != OK) { - logError(1, "%s production_test_data: checkLimitsMinMax SS IX1 FORCE TEST failed... ERROR COUNT = %d\n", tag, ret); + logError(1, "%s production_test_data: ", tag); + logError(1, "checkLimitsMinMax "); + logError(1, "SS IX1 FORCE TEST failed... "); + logError(1, "ERROR COUNT = %d\n", ret); count_fail += 1; if (stop_on_fail) goto ERROR; } else - logError(0, "%s SS IX1 FORCE TEST:.................OK\n\n", tag); - } else - logError(0, "%s SS IX1 FORCE TEST:.................SKIPPED\n\n", tag); + logError(0, "%s SS IX1 FORCE TEST:......OK\n\n", tag); + } kfree(thresholds); - /* SS IX2 FORCE TEST */ + thresholds = NULL; + //SS IX2 FORCE TEST logError(0, "%s SS IX2 FORCE MIN MAX TEST:\n", tag); if (todo->SelfForceIx2 == 1) { - ret = parseProductionTestLimits(path_limits, SS_IX2_FORCE_MAP_MIN, &thresholds_min, &trows, &tcolumns); /* load the min thresholds */ - if (ret < 0 || (trows != ssCompData.header.force_node || tcolumns != 1)) { - logError(1, "%s production_test_data: parseProductionTestLimits SS_IX2_FORCE_MAP_MIN failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA); - return (ret | ERROR_PROD_TEST_DATA); + //load the min thresholds + ret = parseProductionTestLimits(path_limits, + SS_IX2_FORCE_MAP_MIN, + &thresholds_min, + &trows, + &tcolumns); + if (ret < 0 || (trows != ssCompData.header.force_node + || tcolumns != 1)) { + logError(1, "%s production_test_data: ", tag); + logError(1, "parseProductionTestLimits "); + logError(1, "SS_IX2_FORCE_MAP_MIN "); + logError(1, "failed... ERROR %02X\n", + ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; } - ret = parseProductionTestLimits(path_limits, SS_IX2_FORCE_MAP_MAX, &thresholds_max, &trows, &tcolumns); /* load the max thresholds */ - if (ret < 0 || (trows != ssCompData.header.force_node || tcolumns != 1)) { - logError(1, "%s production_test_data: parseProductionTestLimits SS_IX2_FORCE_MAP_MAX failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA); - return (ret | ERROR_PROD_TEST_DATA); + //load the max thresholds + ret = parseProductionTestLimits(path_limits, + SS_IX2_FORCE_MAP_MAX, + &thresholds_max, + &trows, + &tcolumns); + if (ret < 0 || (trows != ssCompData.header.force_node + || tcolumns != 1)) { + logError(1, "%s production_test_data: ", tag); + logError(1, "parseProductionTestLimits"); + logError(1, "SS_IX2_FORCE_MAP_MAX failed... "); + logError(1, "ERROR %02X\n", ERROR_PROD_TEST_DATA); + + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; } - ret = checkLimitsMap(ssCompData.ix2_fm, ssCompData.header.force_node, 1, thresholds_min, thresholds_max); /* check the values with thresholds */ + //check the values with thresholds + ret = checkLimitsMap(ssCompData.ix2_fm, + ssCompData.header.force_node, + 1, + thresholds_min, + thresholds_max); if (ret != OK) { - logError(1, "%s production_test_data: checkLimitsMap SS IX2 FORCE failed... ERROR COUNT = %d\n", tag, ret); - logError(0, "%s SS IX2 FORCE MIN MAX TEST:.................FAIL\n\n", tag); + logError(1, "%s production_test_data: ", tag); + logError(1, "checkLimitsMap SS IX2 FORCE failed... "); + logError(1, "ERROR COUNT = %d\n", ret); + logError(0, "%s SS IX2 FORCE MIN MAX TEST:.........."); + logError(0, "FAIL\n\n"); count_fail += 1; if (stop_on_fail) goto ERROR; - } else - logError(0, "%s SS IX2 FORCE MIN MAX TEST:.................OK\n\n", tag); + } else { + logError(0, "%s SS IX2 FORCE MIN MAX TEST:.....", tag); + logError(0, "OK\n\n"); + } kfree(thresholds_min); + thresholds_min = NULL; kfree(thresholds_max); - } else - logError(0, "%s SS IX2 FORCE MIN MAX TEST:.................SKIPPED\n\n", tag); + thresholds_max = NULL; + } else { + logError(0, "%s SS IX2 FORCE MIN MAX TEST:...........", tag); + logError(0, "KIPPED\n\n"); + } logError(0, "%s SS IX2 FORCE ADJ TEST:\n", tag); if (todo->SelfForceIx2Adj == 1) { - /* SS IX2 FORCE ADJV TEST */ + //SS IX2 FORCE ADJV TEST logError(0, "%s SS IX2 FORCE ADJVERT TEST:\n", tag); - ret = computeAdjVert(ssCompData.ix2_fm, ssCompData.header.force_node, 1, &adjvert); + ret = computeAdjVert(ssCompData.ix2_fm, + ssCompData.header.force_node, + 1, + &adjvert); if (ret < 0) { - logError(1, "%s production_test_data: computeAdjVert SS IX2 FORCE ADJV failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA); - return (ret | ERROR_PROD_TEST_DATA); + logError(1, "%s production_test_data: ", tag); + logError(1, "computeAdjVert SS IX2 FORCE ADJV "); + logError(1, "failed... ERROR %02X\n", + ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; } logError(0, "%s SS IX2 FORCE ADJV computed!\n", tag); - ret = parseProductionTestLimits(path_limits, SS_IX2_FORCE_ADJV_MAP_MAX, &thresholds_max, &trows, &tcolumns); /* load the max thresholds */ - if (ret < 0 || (trows != ssCompData.header.force_node - 1 || tcolumns != 1)) { - logError(1, "%s production_test_data: parseProductionTestLimits SS_IX2_FORCE_ADJV_MAP_MAX failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA); - return (ret | ERROR_PROD_TEST_DATA); + //load the max thresholds + ret = parseProductionTestLimits(path_limits, + SS_IX2_FORCE_ADJV_MAP_MAX, + &thresholds_max, + &trows, + &tcolumns); + if (ret < 0 || (trows != ssCompData.header.force_node - 1 + || tcolumns != 1)) { + logError(1, "%s production_test_data: ", tag); + logError(1, "parseProductionTestLimits "); + logError(1, "SS_IX2_FORCE_ADJV_MAP_MAX failed... "); + logError(1, "ERROR %02X\n", ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; } - ret = checkLimitsMapAdj(adjvert, ssCompData.header.force_node - 1, 1, thresholds_max); - /* check the values with thresholds */ + //check the values with thresholds + ret = checkLimitsMapAdj(adjvert, + ssCompData.header.force_node - 1, + 1, + thresholds_max); if (ret != OK) { - logError(1, "%s production_test_data: checkLimitsMap SS IX2 FORCE failed... ERROR COUNT = %d\n", tag, ret); - logError(0, "%s SS IX2 FORCE ADJV TEST:.................FAIL\n\n", tag); + logError(1, "%s production_test_data: ", tag); + logError(1, "checkLimitsMap SS IX2 FORCE failed... "); + logError(0, "FAIL\n\n"); count_fail += 1; if (stop_on_fail) goto ERROR; - } else - logError(0, "%s SS IX2 FORCE ADJV TEST:.................OK\n\n", tag); + } else { + logError(0, "%s SS IX2 FORCE ADJV TEST:", tag); + logError(0, ".................OK\n\n"); + } kfree(thresholds_max); + thresholds_max = NULL; kfree(adjvert); + adjvert = NULL; - } else - logError(0, "%s SS IX2 FORCE ADJ TEST:.................SKIPPED\n\n", tag); + } else { + logError(0, "%s SS IX2 FORCE ADJ TEST:", tag); + logError(0, ".................SKIPPED\n\n"); + } - /* SS TOTAL FORCE IX */ + //SS TOTAL FORCE IX logError(0, "%s SS TOTAL IX FORCE TEST:\n", tag); if (todo->SelfForceIxTotal == 1 || todo->SelfForceIxTotalAdj == 1) { logError(0, "%s Reading TOTAL IX FORCE Weights...\n", tag); - ret = parseProductionTestLimits(path_limits, SS_IX1_FORCE_W, &ix1_w, &trows, &tcolumns); /* load the IX1 weight */ + + //load the IX1 weight + ret = parseProductionTestLimits(path_limits, + SS_IX1_FORCE_W, + &ix1_w, + &trows, + &tcolumns); if (ret < 0 || (trows != 1 || tcolumns != 1)) { - logError(1, "%s production_test_data: parseProductionTestLimits SS_IX1_FORCE_W failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA); + logError(1, "%s production_test_data: ", tag); + logError(1, "parseProductionTestLimits "); + logError(1, "SS_IX1_FORCE_W failed... ERROR %02X\n", + tag, ERROR_PROD_TEST_DATA); return (ret | ERROR_PROD_TEST_DATA); } - ret = parseProductionTestLimits(path_limits, SS_IX2_FORCE_W, &ix2_w, &trows, &tcolumns); /* load the IX2 weight */ + //load the IX2 weight + ret = parseProductionTestLimits(path_limits, + SS_IX2_FORCE_W, + &ix2_w, + &trows, + &tcolumns); if (ret < 0 || (trows != 1 || tcolumns != 1)) { - logError(1, "%s production_test_data: parseProductionTestLimits SS_IX1_FORCE_W failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA); + logError(1, "%s production_test_data: ", tag); + logError(1, "parseProductionTestLimits "); + logError(1, "SS_IX1_FORCE_W failed... ERROR %02X\n", + tag, ERROR_PROD_TEST_DATA); return (ret | ERROR_PROD_TEST_DATA); } - logError(0, "%s Weights: IX1_W = %d IX2_W = %d\n", tag, *ix1_w, *ix2_w); - - ret = computeTotal(ssCompData.ix2_fm, ssCompData.f_ix1, ssCompData.header.force_node, 1, *ix1_w, *ix2_w, &total_ix); + logError(0, "%s Weights: IX1_W = %d IX2_W = %d\n", + tag, *ix1_w, *ix2_w); + ret = computeTotal(ssCompData.ix2_fm, ssCompData.f_ix1, + ssCompData.header.force_node, + 1, + *ix1_w, + *ix2_w, + &total_ix); if (ret < 0) { - logError(1, "%s production_test_data: computeTotal Ix Force failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA); - return (ret | ERROR_PROD_TEST_DATA); + logError(1, "%s production_test_data: ", tag); + logError(1, "computeTotal Ix Force failed... "); + logError(1, "ERROR %02X\n", ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; } + kfree(ix1_w); + ix1_w = NULL; + kfree(ix2_w); + ix2_w = NULL; + logError(0, "%s SS TOTAL IX FORCE MIN MAX TEST:\n", tag); if (todo->SelfForceIxTotal == 1) { - ret = parseProductionTestLimits(path_limits, SS_TOTAL_IX_FORCE_MAP_MIN, &thresholds_min, &trows, &tcolumns); /* load the min thresholds */ - if (ret < 0 || (trows != ssCompData.header.force_node || tcolumns != 1)) { - logError(1, "%s production_test_data: parseProductionTestLimits SS_TOTAL_IX_FORCE_MAP_MIN failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA); - return (ret | ERROR_PROD_TEST_DATA); + //load the min thresholds + ret = parseProductionTestLimits(path_limits, + SS_TOTAL_IX_FORCE_MAP_MIN, + &thresholds_min, + &trows, + &tcolumns); + if (ret < 0 || (trows != ssCompData.header.force_node + || tcolumns != 1)) { + logError(1, "%s production_test_data: ", tag); + logError(1, "parseProductionTestLimits "); + logError(1, "SS_TOTAL_IX_FORCE_MAP_MIN "); + logError(1, "failed... ERROR %02X\n", + ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; } - ret = parseProductionTestLimits(path_limits, SS_TOTAL_IX_FORCE_MAP_MAX, &thresholds_max, &trows, &tcolumns); /* load the max thresholds */ - if (ret < 0 || (trows != ssCompData.header.force_node || tcolumns != 1)) { - logError(1, "%s production_test_data: parseProductionTestLimits SS_TOTAL_IX_FORCE_MAP_MAX failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA); - return (ret | ERROR_PROD_TEST_DATA); + //load the max thresholds + ret = parseProductionTestLimits(path_limits, + SS_TOTAL_IX_FORCE_MAP_MAX, + &thresholds_max, + &trows, + &tcolumns); + if (ret < 0 || (trows != ssCompData.header.force_node + || tcolumns != 1)) { + logError(1, "%s production_test_data: ", tag); + logError(1, "parseProductionTestLimits "); + logError(1, "SS_TOTAL_IX_FORCE_MAP_MAX "); + logError(1, "failed... ERROR %02X\n", + ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; } - ret = checkLimitsMapTotal(total_ix, ssCompData.header.force_node, 1, thresholds_min, thresholds_max); /* check the values with thresholds */ + //check the values with thresholds + ret = checkLimitsMapTotal(total_ix, + ssCompData.header.force_node, + 1, + thresholds_min, + thresholds_max); if (ret != OK) { - logError(1, "%s production_test_data: checkLimitsMap SS TOTAL IX FORCE failed... ERROR COUNT = %d\n", tag, ret); - logError(0, "%s SS TOTAL IX FORCE MIN MAX TEST:.................FAIL\n\n", tag); + logError(1, "%s production_test_data: ", tag); + logError(1, "checkLimitsMap SS TOTAL IX FORCE"); + logError(1, "failed... ERROR COUNT = %d\n", + ret); + logError(0, "%s SS TOTAL IX FORCE MIN MAX ", + tag); + logError(0, "TEST:.................FAIL\n\n"); count_fail += 1; if (stop_on_fail) goto ERROR; - } else - logError(0, "%s SS TOTAL IX FORCE MIN MAX TEST:.................OK\n\n", tag); + } else { + logError(0, "%s SS TOTAL IX FORCE MIN MAX ", + tag); + logError(0, "TEST:.................OK\n\n"); + } kfree(thresholds_min); + thresholds_min = NULL; kfree(thresholds_max); - } else - logError(0, "%s SS TOTAL IX FORCE MIN MAX TEST:.................SKIPPED\n", tag); + thresholds_max = NULL; + } else { + logError(0, "%s SS TOTAL IX FORCE MIN MAX TEST:", tag); + logError(0, ".................SKIPPED\n"); + } logError(0, "%s SS TOTAL IX FORCE ADJ TEST:\n", tag); if (todo->SelfForceIxTotalAdj == 1) { - /* SS TOTAL IX FORCE ADJV TEST */ - logError(0, "%s SS TOTAL IX FORCE ADJVERT TEST:\n", tag); - ret = computeAdjVertTotal(total_ix, ssCompData.header.force_node, 1, &total_adjvert); + //SS TOTAL IX FORCE ADJV TEST + logError(0, "%s SS TOTAL IX FORCE ADJVERT TEST:\n", + tag); + ret = computeAdjVertTotal(total_ix, + ssCompData.header.force_node, + 1, + &total_adjvert); if (ret < 0) { - logError(1, "%s production_test_data: computeAdjVert SS TOTAL IX FORCE ADJV failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA); - return (ret | ERROR_PROD_TEST_DATA); + logError(1, "%s production_test_data: ", tag); + logError(1, "computeAdjVert SS TOTAL IX "); + logError(1, "FORCE ADJV failed... "); + logError(1, "ERROR %02X\n", + ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; } - logError(0, "%s SS TOTAL IX FORCE ADJV computed!\n", tag); - - ret = parseProductionTestLimits(path_limits, SS_TOTAL_IX_FORCE_ADJV_MAP_MAX, &thresholds_max, &trows, &tcolumns); /* load the max thresholds */ - if (ret < 0 || (trows != ssCompData.header.force_node - 1 || tcolumns != 1)) { - logError(1, "%s production_test_data: parseProductionTestLimits SS_TOTAL_IX_FORCE_ADJV_MAP_MAX... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA); - return (ret | ERROR_PROD_TEST_DATA); + logError(0, "%s SS TOTAL IX FORCE ADJV computed!\n", + tag); + + //load the max thresholds + ret = parseProductionTestLimits(path_limits, + SS_TOTAL_IX_FORCE_ADJV_MAP_MAX, + &thresholds_max, + &trows, + &tcolumns); + if (ret < 0 + || (trows != ssCompData.header.force_node - 1 + || tcolumns != 1)) { + logError(1, "%s production_test_data: ", tag); + logError(1, "parseProductionTestLimits "); + logError(1, "SS_TOTAL_IX_FORCE_ADJV_MAP_MAX"); + logError(1, "... ERROR %02X\n", + ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; } - ret = checkLimitsMapAdjTotal(total_adjvert, ssCompData.header.force_node - 1, 1, thresholds_max); /* check the values with thresholds */ + //check the values with thresholds + ret = checkLimitsMapAdjTotal(total_adjvert, + ssCompData.header.force_node - 1, + 1, + thresholds_max); if (ret != OK) { - logError(1, "%s production_test_data: checkLimitsMap SS TOTAL IX FORCE failed... ERROR COUNT = %d\n", tag, ret); - logError(0, "%s SS TOTAL IX FORCE ADJV TEST:.................FAIL\n\n", tag); + logError(1, "%s production_test_data: ", tag); + logError(1, "checkLimitsMap SS TOTAL IX "); + logError(1, "FORCE failed... "); + logError(1, "ERROR COUNT = %d\n", ret); + logError(0, "%s SS TOTAL IX FORCE ADJV TEST:", + tag); + logError(0, ".................FAIL\n\n"); count_fail += 1; if (stop_on_fail) goto ERROR; - } else - logError(0, "%s SS TOTAL IX FORCE ADJV TEST:.................OK\n\n", tag); + } else { + logError(0, "%s SS TOTAL IX FORCE ADJV TEST:", + tag); + logError(0, ".................OK\n\n"); + } kfree(thresholds_max); + thresholds_max = NULL; kfree(total_adjvert); - } else - logError(0, "%s SS TOTAL IX FORCE ADJ TEST:.................SKIPPED\n", tag); + total_adjvert = NULL; + } else { + logError(0, "%s SS TOTAL IX FORCE ADJ TEST:"); + logError(0, ".................SKIPPED\n"); + } kfree(total_ix); - } else - logError(0, "%s SS TOTAL IX FORCE TEST:.................SKIPPED\n\n", tag); + total_ix = NULL; + } else { + logError(0, "%s SS TOTAL IX FORCE TEST:", tag); + logError(0, ".................SKIPPED\n\n"); + } - /******************* SS SENSE IX **************************/ - /* SS IX1 SENSE TEST */ + + //************** SS SENSE IX *******************/ + //SS IX1 SENSE TEST logError(0, "%s SS IX1 SENSE TEST:\n", tag); if (todo->SelfSenseIx1 == 1) { - - ret = parseProductionTestLimits(path_limits, SS_IX1_SENSE_MIN_MAX, &thresholds, &trows, &tcolumns); + ret = parseProductionTestLimits(path_limits, + SS_IX1_SENSE_MIN_MAX, + &thresholds, + &trows, + &tcolumns); if (ret < 0 || (trows != 1 || tcolumns != 2)) { - logError(1, "%s production_test_data: parseProductionTestLimits SS_IX1_SENSE_MIN_MAX failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA); - return (ret | ERROR_PROD_TEST_DATA); + logError(1, "%s production_test_data: ", tag); + logError(1, "parseProductionTestLimits "); + logError(1, "SS_IX1_SENSE_MIN_MAX failed... "); + logError(1, "ERROR %02X\n", ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; } container = (u16) ssCompData.s_ix1; - ret = checkLimitsMinMax(&container, 1, 1, thresholds[0], thresholds[1]); /* check the limits */ + ret = checkLimitsMinMax(&container, + 1, + 1, + thresholds[0], + thresholds[1]); //check the limits if (ret != OK) { - logError(1, "%s production_test_data: checkLimitsMinMax SS IX1 SENSE TEST failed... ERROR COUNT = %d\n", tag, ret); + logError(1, "%s production_test_data: ", tag); + logError(1, "checkLimitsMinMax SS IX1 SENSE TEST "); + logError(1, "failed... ERROR COUNT = %d\n", ret); count_fail += 1; if (stop_on_fail) goto ERROR; - } else - logError(0, "%s SS IX1 SENSE TEST:.................OK\n\n", tag); - } else - logError(0, "%s SS IX1 SENSE TEST:.................SKIPPED\n\n", tag); + } else { + logError(0, "%s SS IX1 SENSE TEST:..............", tag); + logError(0, "...OK\n\n"); + } + } else { + logError(0, "%s SS IX1 SENSE TEST:.................", tag); + logError(0, "SKIPPED\n\n"); + } kfree(thresholds); - /* SS IX2 SENSE TEST */ + thresholds = NULL; + //SS IX2 SENSE TEST logError(0, "%s SS IX2 SENSE MIN MAX TEST:\n", tag); if (todo->SelfSenseIx2 == 1) { - ret = parseProductionTestLimits(path_limits, SS_IX2_SENSE_MAP_MIN, &thresholds_min, &trows, &tcolumns); /* load the min thresholds */ - if (ret < 0 || (trows != 1 || tcolumns != ssCompData.header.sense_node)) { - logError(1, "%s production_test_data: parseProductionTestLimits SS_IX2_SENSE_MAP_MIN failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA); - return (ret | ERROR_PROD_TEST_DATA); + ret = parseProductionTestLimits(path_limits, + SS_IX2_SENSE_MAP_MIN, + &thresholds_min, + &trows, + &tcolumns); //load the min thresholds + if (ret < 0 || (trows != 1 + || tcolumns != ssCompData.header.sense_node)) { + logError(1, "%s production_test_data: ", tag); + logError(1, "parseProductionTestLimits "); + logError(1, "S_IX2_SENSE_MAP_MIN failed... "); + logError(1, "ERROR %02X\n", ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; } - ret = parseProductionTestLimits(path_limits, SS_IX2_SENSE_MAP_MAX, &thresholds_max, &trows, &tcolumns); /* load the max thresholds */ - if (ret < 0 || (trows != 1 || tcolumns != ssCompData.header.sense_node)) { - logError(1, "%s production_test_data: parseProductionTestLimits SS_IX2_SENSE_MAP_MAX failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA); - return (ret | ERROR_PROD_TEST_DATA); + ret = parseProductionTestLimits(path_limits, + SS_IX2_SENSE_MAP_MAX, + &thresholds_max, + &trows, + &tcolumns); //load the max thresholds + if (ret < 0 || (trows != 1 + || tcolumns != ssCompData.header.sense_node)) { + logError(1, "%s production_test_data: ", tag); + logError(1, "parseProductionTestLimits "); + logError(1, "SS_IX2_SENSE_MAP_MAX failed... "); + logError(1, "ERROR %02X\n", ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; } - ret = checkLimitsMap(ssCompData.ix2_sn, 1, ssCompData.header.sense_node, thresholds_min, thresholds_max); /* check the values with thresholds */ + //check the values with thresholds + ret = checkLimitsMap(ssCompData.ix2_sn, + 1, + ssCompData.header.sense_node, + thresholds_min, + thresholds_max); if (ret != OK) { - logError(1, "%s production_test_data: checkLimitsMap SS IX2 SENSE failed... ERROR COUNT = %d\n", tag, ret); - logError(0, "%s SS IX2 SENSE MIN MAX TEST:.................FAIL\n\n", tag); + logError(1, "%s production_test_data: ", tag); + logError(1, "checkLimitsMap SS IX2 SENSE failed... "); + logError(1, "ERROR COUNT = %d\n", ret); + logError(0, "%s SS IX2 SENSE MIN MAX TEST:.....", tag); + logError(0, "............FAIL\n\n"); count_fail += 1; if (stop_on_fail) goto ERROR; - } else - logError(0, "%s SS IX2 SENSE MIN MAX TEST:.................OK\n\n", tag); + } else { + logError(0, "%s SS IX2 SENSE MIN MAX TEST:", tag); + logError(0, ".................OK\n\n"); + } kfree(thresholds_min); + thresholds_min = NULL; kfree(thresholds_max); - } else - logError(0, "%s SS IX2 SENSE MIN MAX TEST:.................SKIPPED\n\n", tag); + thresholds_max = NULL; + } else { + logError(0, "%s SS IX2 SENSE MIN MAX TEST:..............", tag); + logError(0, "...SKIPPED\n\n"); + } logError(0, "%s SS IX2 SENSE ADJ TEST:\n", tag); if (todo->SelfSenseIx2Adj == 1) { - /* SS IX2 SENSE ADJH TEST */ + //SS IX2 SENSE ADJH TEST logError(0, "%s SS IX2 SENSE ADJHORIZ TEST:\n", tag); - ret = computeAdjHoriz(ssCompData.ix2_sn, 1, ssCompData.header.sense_node, &adjhor); + ret = computeAdjHoriz(ssCompData.ix2_sn, + 1, + ssCompData.header.sense_node, + &adjhor); if (ret < 0) { - logError(1, "%s production_test_data: computeAdjHoriz SS IX2 SENSE ADJH failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA); - return (ret | ERROR_PROD_TEST_DATA); + logError(1, "%s production_test_data: ", tag); + logError(1, "computeAdjHoriz SS IX2 SENSE ADJH "); + logError(1, "failed... ERROR %02X\n", + ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; } logError(0, "%s SS IX2 SENSE ADJ HORIZ computed!\n", tag); - ret = parseProductionTestLimits(path_limits, SS_IX2_SENSE_ADJH_MAP_MAX, &thresholds_max, &trows, &tcolumns); /* load the max thresholds */ - if (ret < 0 || (trows != 1 || tcolumns != ssCompData.header.sense_node - 1)) { - logError(1, "%s production_test_data: parseProductionTestLimits SS_IX2_SENSE_ADJH_MAP_MAX failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA); - return (ret | ERROR_PROD_TEST_DATA); + ret = parseProductionTestLimits(path_limits, + SS_IX2_SENSE_ADJH_MAP_MAX, + &thresholds_max, + &trows, + &tcolumns); //load the max thresholds + if (ret < 0 || (trows != 1 + || tcolumns != ssCompData.header.sense_node - 1)) { + logError(1, "%s production_test_data: ", tag); + logError(1, "parseProductionTestLimits "); + logError(1, "SS_IX2_SENSE_ADJH_MAP_MAX "); + logError(1, "failed... ERROR %02X\n", + ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; } - ret = checkLimitsMapAdj(adjhor, 1, ssCompData.header.sense_node - 1, thresholds_max); /* check the values with thresholds */ + //check the values with thresholds + ret = checkLimitsMapAdj(adjhor, + 1, + ssCompData.header.sense_node - 1, + thresholds_max); if (ret != OK) { - logError(1, "%s production_test_data: checkLimitsMapAdj SS IX2 SENSE ADJH failed... ERROR COUNT = %d\n", tag, ret); - logError(0, "%s SS IX2 SENSE ADJH TEST:.................FAIL\n\n", tag); + logError(1, "%s production_test_data: ", tag); + logError(1, "checkLimitsMapAdj SS IX2 SENSE ADJH "); + logError(1, "failed... ERROR COUNT = %d\n", ret); + logError(0, "%s SS IX2 SENSE ADJH TEST:.......", tag); + logError(0, "..........FAIL\n\n"); count_fail += 1; if (stop_on_fail) goto ERROR; - } else - logError(0, "%s SS IX2 SENSE ADJH TEST:.................OK\n\n", tag); + } else { + logError(0, "%s SS IX2 SENSE ADJH TEST:........", tag); + logError(0, ".........OK\n\n"); + } kfree(thresholds_max); + thresholds_max = NULL; kfree(adjhor); - } else - logError(0, "%s SS IX2 SENSE ADJ TEST:.................SKIPPED\n", tag); + adjhor = NULL; + } else { + logError(0, "%s SS IX2 SENSE ADJ TEST:.................", tag); + logError(0, "SKIPPED\n", tag); + } - /* SS TOTAL IX SENSE */ + //SS TOTAL IX SENSE logError(0, "%s SS TOTAL IX SENSE TEST:\n", tag); if (todo->SelfSenseIxTotal == 1 || todo->SelfSenseIxTotalAdj == 1) { logError(0, "%s Reading TOTAL IX SENSE Weights...\n", tag); - ret = parseProductionTestLimits(path_limits, SS_IX1_SENSE_W, &ix1_w, &trows, &tcolumns); /* load the IX1 weight */ + //load the IX1 weight + ret = parseProductionTestLimits(path_limits, + SS_IX1_SENSE_W, + &ix1_w, + &trows, + &tcolumns); if (ret < 0 || (trows != 1 || tcolumns != 1)) { - logError(1, "%s production_test_data: parseProductionTestLimits SS_IX1_SENSE_W failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA); - return (ret | ERROR_PROD_TEST_DATA); + logError(1, "%s production_test_data: ", tag); + logError(1, "parseProductionTestLimits "); + logError(1, "SS_IX1_SENSE_W failed... ERROR %02X\n", + ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; } - ret = parseProductionTestLimits(path_limits, SS_IX2_SENSE_W, &ix2_w, &trows, &tcolumns); /* load the IX2 weight */ + //load the IX2 weight + ret = parseProductionTestLimits(path_limits, + SS_IX2_SENSE_W, + &ix2_w, + &trows, + &tcolumns); if (ret < 0 || (trows != 1 || tcolumns != 1)) { - logError(1, "%s production_test_data: parseProductionTestLimits SS_IX1_SENSE_W failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA); - return (ret | ERROR_PROD_TEST_DATA); + logError(1, "%s production_test_data: ", tag); + logError(1, "parseProductionTestLimits "); + logError(1, "SS_IX1_SENSE_W failed... ERROR %02X\n", + ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; } - logError(0, "%s Weights: IX1_W = %d IX2_W = %d\n", tag, *ix1_w, *ix2_w); + logError(0, "%s Weights: IX1_W = %d IX2_W = %d\n", + tag, *ix1_w, *ix2_w); - ret = computeTotal(ssCompData.ix2_sn, ssCompData.s_ix1, 1, ssCompData.header.sense_node, *ix1_w, *ix2_w, &total_ix); + ret = computeTotal(ssCompData.ix2_sn, + ssCompData.s_ix1, + 1, + ssCompData.header.sense_node, + *ix1_w, + *ix2_w, + &total_ix); if (ret < 0) { - logError(1, "%s production_test_data: computeTotal Ix Sense failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA); - return (ret | ERROR_PROD_TEST_DATA); + logError(1, "%s production_test_data: ", tag); + logError(1, "computeTotal Ix Sense "); + logError(1, "failed... ERROR %02X\n", + ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; } + kfree(ix1_w); + ix1_w = NULL; + kfree(ix2_w); + ix2_w = NULL; + logError(0, "%s SS TOTAL IX SENSE MIN MAX TEST:\n", tag); + //load the min thresholds if (todo->SelfSenseIxTotal == 1) { - ret = parseProductionTestLimits(path_limits, SS_TOTAL_IX_SENSE_MAP_MIN, &thresholds_min, &trows, &tcolumns); /* load the min thresholds */ - if (ret < 0 || (trows != 1 || tcolumns != ssCompData.header.sense_node)) { - logError(1, "%s production_test_data: parseProductionTestLimits SS_TOTAL_IX_SENSE_MAP_MIN failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA); - return (ret | ERROR_PROD_TEST_DATA); + ret = parseProductionTestLimits(path_limits, + SS_TOTAL_IX_SENSE_MAP_MIN, + &thresholds_min, + &trows, + &tcolumns); + if (ret < 0 || (trows != 1 + || tcolumns != ssCompData.header.sense_node)) { + logError(1, "%s production_test_data: ", tag); + logError(1, "parseProductionTestLimits "); + logError(1, "SS_TOTAL_IX_SENSE_MAP_MIN "); + logError(1, "failed... ERROR %02X\n", + ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; } - ret = parseProductionTestLimits(path_limits, SS_TOTAL_IX_SENSE_MAP_MAX, &thresholds_max, &trows, &tcolumns); /* load the max thresholds */ - if (ret < 0 || (trows != 1 || tcolumns != ssCompData.header.sense_node)) { - logError(1, "%s production_test_data: parseProductionTestLimits SS_TOTAL_IX_SENSE_MAP_MAX failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA); - return (ret | ERROR_PROD_TEST_DATA); + //load the max thresholds + ret = parseProductionTestLimits(path_limits, + SS_TOTAL_IX_SENSE_MAP_MAX, + &thresholds_max, + &trows, + &tcolumns); + if (ret < 0 || (trows != 1 || + tcolumns != ssCompData.header.sense_node)) { + logError(1, "%s production_test_data: ", tag); + logError(1, "parseProductionTestLimits "); + logError(1, "SS_TOTAL_IX_SENSE_MAP_MAX "); + logError(1, "failed... ERROR %02X\n", + ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; } - ret = checkLimitsMapTotal(total_ix, 1, ssCompData.header.sense_node, thresholds_min, thresholds_max); /* check the values with thresholds */ + //check the values with thresholds + ret = checkLimitsMapTotal(total_ix, + 1, + ssCompData.header.sense_node, + thresholds_min, + thresholds_max); if (ret != OK) { - logError(1, "%s production_test_data: checkLimitsMap SS TOTAL IX SENSE failed... ERROR COUNT = %d\n", tag, ret); - logError(0, "%s SS TOTAL IX SENSE MIN MAX TEST:.................FAIL\n\n", tag); + logError(1, "%s production_test_data: ", tag); + logError(1, "checkLimitsMap SS TOTAL IX SENSE"); + logError(1, " failed... ERROR COUNT = %d\n", + ret); + logError(0, "%s SS TOTAL IX SENSE MIN MAX ", + tag); + logError(0, "TEST:.................FAIL\n\n"); count_fail += 1; if (stop_on_fail) goto ERROR; - } else - logError(0, "%s SS TOTAL IX SENSE MIN MAX TEST:.................OK\n\n", tag); + } else { + logError(0, "%s SS TOTAL IX SENSE MIN MAX ", + tag); + logError(0, "TEST:.................OK\n\n"); + } kfree(thresholds_min); + thresholds_min = NULL; kfree(thresholds_max); - } else - logError(0, "%s SS TOTAL IX SENSE MIN MAX TEST:.................SKIPPED\n", tag); + thresholds_max = NULL; + } else { + logError(0, "%s SS TOTAL IX SENSE MIN MAX ", tag); + logError(0, "TEST:.................SKIPPED\n"); + } + logError(0, "%s SS TOTAL IX SENSE ADJ TEST:\n", tag); if (todo->SelfSenseIxTotalAdj == 1) { - /* SS TOTAL IX SENSE ADJH TEST */ - logError(0, "%s SS TOTAL IX SENSE ADJHORIZ TEST:\n", tag); - ret = computeAdjHorizTotal(total_ix, 1, ssCompData.header.sense_node, &total_adjhor); + //SS TOTAL IX SENSE ADJH TEST + logError(0, "%s SS TOTAL IX SENSE ADJHORIZ TEST:\n", + tag); + ret = computeAdjHorizTotal(total_ix, + 1, + ssCompData.header.sense_node, + &total_adjhor); if (ret < 0) { - logError(1, "%s production_test_data: computeAdjHoriz SS TOTAL IX SENSE ADJH failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA); - return (ret | ERROR_PROD_TEST_DATA); + logError(1, "%s production_test_data: ", tag); + logError(1, "computeAdjHoriz SS TOTAL "); + logError(1, "IXSENSE ADJH failed... "); + logError(1, "ERROR %02X\n", + ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; } - logError(0, "%s SS TOTAL IX SENSE ADJ HORIZ computed!\n", tag); - - ret = parseProductionTestLimits(path_limits, SS_TOTAL_IX_SENSE_ADJH_MAP_MAX, &thresholds_max, &trows, &tcolumns); /* load the max thresholds */ - if (ret < 0 || (trows != 1 || tcolumns != ssCompData.header.sense_node - 1)) { - logError(1, "%s production_test_data: parseProductionTestLimits SS_TOTAL_IX_SENSE_ADJH_MAP_MAX failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA); - return (ret | ERROR_PROD_TEST_DATA); + logError(0, "%s SS TOTAL IX SENSE ADJ HORIZ ", tag); + logError(0, "computed!\n"); + + //load the max thresholds + ret = parseProductionTestLimits(path_limits, + SS_TOTAL_IX_SENSE_ADJH_MAP_MAX, + &thresholds_max, + &trows, + &tcolumns); + if (ret < 0 || (trows != 1 + || tcolumns != ssCompData.header.sense_node - 1)) { + logError(1, "%s production_test_data: ", tag); + logError(1, "parseProductionTestLimits "); + logError(1, "SS_TOTAL_IX_SENSE_ADJH_MAP_MAX "); + logError(1, "failed... ERROR %02X\n", + ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; } - ret = checkLimitsMapAdjTotal(total_adjhor, 1, ssCompData.header.sense_node - 1, thresholds_max); /* check the values with thresholds */ + //check the values with thresholds + ret = checkLimitsMapAdjTotal(total_adjhor, + 1, + ssCompData.header.sense_node - 1, + thresholds_max); if (ret != OK) { - logError(1, "%s production_test_data: checkLimitsMapAdj SS TOTAL IX SENSE ADJH failed... ERROR COUNT = %d\n", tag, ret); - logError(0, "%s SS TOTAL IX SENSE ADJH TEST:.................FAIL\n\n", tag); + logError(1, "%s production_test_data: ", tag); + logError(1, "checkLimitsMapAdj SS TOTAL "); + logError(1, "IX SENSE ADJH failed... "); + logError(1, "ERROR COUNT = %d\n", ret); + logError(0, "%s SS TOTAL IX SENSE ADJH ", tag); + logError(0, "TEST:.................FAIL\n\n"); count_fail += 1; if (stop_on_fail) goto ERROR; - } else - logError(0, "%s SS TOTAL IX SENSE ADJH TEST:.................OK\n\n", tag); + } else { + logError(0, "%s SS TOTAL IX SENSE ADJH ", tag); + logError(0, "TEST:.................OK\n\n"); + } kfree(thresholds_max); + thresholds_max = NULL; kfree(total_adjhor); - } else - logError(0, "%s SS TOTAL IX SENSE ADJ TEST:.................SKIPPED\n", tag); + total_adjhor = NULL; + } else { + logError(0, "%s SS TOTAL IX SENSE ADJ TEST:.....", tag); + logError(0, "............SKIPPED\n"); + } kfree(total_ix); - } else - logError(0, "%s SS TOTAL IX SENSE TEST:.................SKIPPED\n", tag); + total_ix = NULL; + } else { + logError(0, "%s SS TOTAL IX SENSE TEST:............", tag); + logError(0, ".....SKIPPED\n"); + } - /*********************** SS SENSE CX ******************************/ - /* SS CX1 FORCE TEST */ + //************************ SS SENSE CX *******************************/ + //SS CX1 FORCE TEST logError(0, "%s SS CX1 FORCE TEST:\n", tag); if (todo->SelfForceCx1 == 1) { - ret = parseProductionTestLimits(path_limits, SS_CX1_FORCE_MIN_MAX, &thresholds, &trows, &tcolumns); + ret = parseProductionTestLimits(path_limits, + SS_CX1_FORCE_MIN_MAX, + &thresholds, + &trows, + &tcolumns); if (ret < 0 || (trows != 1 || tcolumns != 2)) { - logError(1, "%s production_test_data: parseProductionTestLimits SS_CX1_FORCE_MIN_MAX failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA); - return (ret | ERROR_PROD_TEST_DATA); + logError(1, "%s production_test_data: ", tag); + logError(1, "parseProductionTestLimits "); + logError(1, "SS_CX1_FORCE_MIN_MAX "); + logError(1, "failed... ERROR %02X\n", + ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; } + //check the limits container = (u16) ssCompData.f_cx1; - ret = checkLimitsMinMax(&container, 1, 1, thresholds[0], thresholds[1]); /* check the limits */ + ret = checkLimitsMinMax(&container, + 1, + 1, + thresholds[0], + thresholds[1]); if (ret != OK) { - logError(1, "%s production_test_data: checkLimitsMinMax SS CX1 FORCE TEST failed... ERROR COUNT = %d\n", tag, ret); + logError(1, "%s production_test_data: ", tag); + logError(1, "checkLimitsMinMax SS CX1 FORCE TEST "); + logError(1, "failed... ERROR COUNT = %d\n", ret); count_fail += 1; - /* if (stop_on_fail) return (ERROR_PROD_TEST_DATA | ERROR_TEST_CHECK_FAIL); */ if (stop_on_fail) goto ERROR; - } else - logError(0, "%s SS CX1 FORCE TEST:.................OK\n\n", tag); + } else { + logError(0, "%s SS CX1 FORCE TEST:.............", tag); + logError(0, "....OK\n\n"); + } kfree(thresholds); - } else - logError(0, "%s SS CX1 FORCE TEST:.................SKIPPED\n\n", tag); + thresholds = NULL; + } else { + logError(0, "%s SS CX1 FORCE TEST:.................", tag); + logError(0, "SKIPPED\n\n"); + } - /* SS CX2 FORCE TEST */ + //SS CX2 FORCE TEST logError(0, "%s SS CX2 FORCE MIN MAX TEST:\n", tag); if (todo->SelfForceCx2 == 1) { - ret = parseProductionTestLimits(path_limits, SS_CX2_FORCE_MAP_MIN, &thresholds_min, &trows, &tcolumns); /* load the min thresholds */ - if (ret < 0 || (trows != ssCompData.header.force_node || tcolumns != 1)) { - logError(1, "%s production_test_data: parseProductionTestLimits SS_CX2_FORCE_MAP_MIN failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA); - return (ret | ERROR_PROD_TEST_DATA); + //load the min thresholds + ret = parseProductionTestLimits(path_limits, + SS_CX2_FORCE_MAP_MIN, + &thresholds_min, + &trows, + &tcolumns); + if (ret < 0 || (trows != ssCompData.header.force_node + || tcolumns != 1)) { + logError(1, "%s production_test_data: ", tag); + logError(1, "SS_CX2_FORCE_MAP_MIN "); + logError(1, "failed... ERROR %02X\n", + ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; } - ret = parseProductionTestLimits(path_limits, SS_CX2_FORCE_MAP_MAX, &thresholds_max, &trows, &tcolumns); /* load the max thresholds */ - if (ret < 0 || (trows != ssCompData.header.force_node || tcolumns != 1)) { - logError(1, "%s production_test_data: parseProductionTestLimits SS_CX2_FORCE_MAP_MAX failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA); - return (ret | ERROR_PROD_TEST_DATA); + //load the max thresholds + ret = parseProductionTestLimits(path_limits, + SS_CX2_FORCE_MAP_MAX, + &thresholds_max, + &trows, + &tcolumns); + if (ret < 0 || (trows != ssCompData.header.force_node + || tcolumns != 1)) { + logError(1, "%s production_test_data: ", tag); + logError(1, "parseProductionTestLimits "); + logError(1, "SS_CX2_FORCE_MAP_MAX "); + logError(1, "failed... ERROR %02X\n", + ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; } - ret = checkLimitsMap(ssCompData.cx2_fm, ssCompData.header.force_node, 1, thresholds_min, thresholds_max); /* check the values with thresholds */ + //check the values with thresholds + ret = checkLimitsMap(ssCompData.cx2_fm, + ssCompData.header.force_node, + 1, + thresholds_min, + thresholds_max); if (ret != OK) { - logError(1, "%s production_test_data: checkLimitsMap SS CX2 FORCE failed... ERROR COUNT = %d\n", tag, ret); - logError(0, "%s SS CX2 FORCE MIN MAX TEST:.................FAIL\n\n", tag); + logError(1, "%s production_test_data: ", tag); + logError(1, "%checkLimitsMap SS CX2 FORCE "); + logError(1, "%failed... ERROR COUNT = %d\n", ret); + logError(0, "%s SS CX2 FORCE MIN MAX TEST:.....", tag); + logError(0, "............FAIL\n\n"); count_fail += 1; if (stop_on_fail) goto ERROR; - } else - logError(0, "%s SS CX2 FORCE MIN MAX TEST:.................OK\n\n", tag); + } else { + logError(0, "%s SS CX2 FORCE MIN MAX TEST:......", tag); + logError(0, "...........OK\n\n"); + } kfree(thresholds_min); + thresholds_min = NULL; kfree(thresholds_max); - } else - logError(0, "%s SS CX2 FORCE MIN MAX TEST:.................SKIPPED\n", tag); + thresholds_max = NULL; + } else { + logError(0, "%s SS CX2 FORCE MIN MAX TEST:..............", tag); + logError(0, "...SKIPPED\n"); + } logError(0, "%s SS CX2 FORCE ADJ TEST:\n", tag); if (todo->SelfForceCx2Adj == 1) { - /* SS CX2 FORCE ADJV TEST */ + //SS CX2 FORCE ADJV TEST logError(0, "%s SS CX2 FORCE ADJVERT TEST:\n", tag); - ret = computeAdjVert(ssCompData.cx2_fm, ssCompData.header.force_node, - 1, &adjvert); /* comepute the ADJV for CX2 FORCE */ + //comepute the ADJV for CX2 FORCE + ret = computeAdjVert(ssCompData.cx2_fm, + ssCompData.header.force_node, + 1, + &adjvert); if (ret < 0) { - logError(1, "%s production_test_data: computeAdjVert SS CX2 FORCE ADJV failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA); - return (ret | ERROR_PROD_TEST_DATA); + logError(1, "%s production_test_data: ", tag); + logError(1, "computeAdjVert SS CX2 FORCE ADJV "); + logError(1, "failed... ERROR %02X\n", + ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; } logError(0, "%s SS CX2 FORCE ADJV computed!\n", tag); - ret = parseProductionTestLimits(path_limits, SS_CX2_FORCE_ADJV_MAP_MAX, &thresholds_max, &trows, &tcolumns); /* load the max thresholds */ - if (ret < 0 || (trows != ssCompData.header.force_node - 1 || tcolumns != 1)) { - logError(1, "%s production_test_data: parseProductionTestLimits SS_CX2_FORCE_ADJV_MAP_MAX failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA); - return (ret | ERROR_PROD_TEST_DATA); + //load the max thresholds + ret = parseProductionTestLimits(path_limits, + SS_CX2_FORCE_ADJV_MAP_MAX, + &thresholds_max, + &trows, + &tcolumns); + if (ret < 0 || (trows != ssCompData.header.force_node - 1 + || tcolumns != 1)) { + logError(1, "%s production_test_data: ", tag); + logError(1, "parseProductionTestLimits "); + logError(1, "SS_CX2_FORCE_ADJV_MAP_MAX "); + logError(1, "failed... ERROR %02X\n", + ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; } - ret = checkLimitsMapAdj(adjvert, ssCompData.header.force_node - 1, 1, thresholds_max); /* check the values with thresholds */ + //check the values with thresholds + ret = checkLimitsMapAdj(adjvert, + ssCompData.header.force_node - 1, + 1, + thresholds_max); if (ret != OK) { - logError(1, "%s production_test_data: checkLimitsMap SS IX2 FORCE failed... ERROR COUNT = %d\n", tag, ret); - logError(0, "%s SS CX2 FORCE ADJV TEST:.................FAIL\n\n", tag); + logError(1, "%s production_test_data: ", tag); + logError(1, "checkLimitsMap SS IX2 FORCE "); + logError(1, "failed... ERROR COUNT = %d\n", ret); + logError(0, "%s SS CX2 FORCE ADJV TEST:......", tag); + logError(0, "...........FAIL\n\n"); count_fail += 1; if (stop_on_fail) goto ERROR; - } else - logError(0, "%s SS CX2 FORCE ADJV TEST:.................OK\n\n", tag); + } else { + logError(0, "%s SS CX2 FORCE ADJV TEST:.....", tag); + logError(0, "............OK\n\n"); + } kfree(thresholds_max); + thresholds_max = NULL; kfree(adjvert); - } else - logError(0, "%s SS CX2 FORCE ADJ TEST:.................SKIPPED\n\n", tag); - - /* SS TOTAL CX FORCE */ + adjvert = NULL; + } else { + logError(0, "%s SS CX2 FORCE ADJ TEST:.................", tag); + logError(0, "SKIPPED\n\n"); + } + //SS TOTAL CX FORCE logError(0, "%s SS TOTAL CX FORCE TEST:\n", tag); if (todo->SelfForceCxTotal == 1 || todo->SelfForceCxTotalAdj == 1) { - ret = computeTotal(ssCompData.cx2_fm, ssCompData.f_cx1, ssCompData.header.force_node, 1, CX1_WEIGHT, CX2_WEIGHT, &total_cx); + ret = computeTotal(ssCompData.cx2_fm, + ssCompData.f_cx1, + ssCompData.header.force_node, + 1, + CX1_WEIGHT, + CX2_WEIGHT, + &total_cx); if (ret < 0) { - logError(1, "%s production_test_data: computeTotal Cx Force failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA); + logError(1, "%s production_test_data: ", tag); + logError(1, "computeTotal Cx Force failed... "); + logError(1, "ERROR %02X\n", ERROR_PROD_TEST_DATA); return (ret | ERROR_PROD_TEST_DATA); } logError(0, "%s SS TOTAL CX FORCE MIN MAX TEST:\n", tag); + //load the min thresholds if (todo->SelfForceCxTotal == 1) { - ret = parseProductionTestLimits(path_limits, SS_TOTAL_CX_FORCE_MAP_MIN, &thresholds_min, &trows, &tcolumns); /* load the min thresholds */ - if (ret < 0 || (trows != ssCompData.header.force_node || tcolumns != 1)) { - logError(1, "%s production_test_data: parseProductionTestLimits SS_TOTAL_CX_FORCE_MAP_MIN failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA); - return (ret | ERROR_PROD_TEST_DATA); + ret = parseProductionTestLimits(path_limits, + SS_TOTAL_CX_FORCE_MAP_MIN, + &thresholds_min, + &trows, + &tcolumns); + if (ret < 0 || (trows != ssCompData.header.force_node + || tcolumns != 1)) { + logError(1, "%s production_test_data: ", tag); + logError(1, "parseProductionTestLimits "); + logError(1, "SS_TOTAL_CX_FORCE_MAP_MIN "); + logError(1, "failed... ERROR %02X\n", + ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; } - ret = parseProductionTestLimits(path_limits, SS_TOTAL_CX_FORCE_MAP_MAX, &thresholds_max, &trows, &tcolumns); /* load the max thresholds */ - if (ret < 0 || (trows != ssCompData.header.force_node || tcolumns != 1)) { - logError(1, "%s production_test_data: parseProductionTestLimits SS_TOTAL_CX_FORCE_MAP_MAX failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA); - return (ret | ERROR_PROD_TEST_DATA); + //load the max thresholds + ret = parseProductionTestLimits(path_limits, + SS_TOTAL_CX_FORCE_MAP_MAX, + &thresholds_max, + &trows, + &tcolumns); + if (ret < 0 || (trows != ssCompData.header.force_node + || tcolumns != 1)) { + logError(1, "%s production_test_data: ", tag); + logError(1, "parseProductionTestLimits "); + logError(1, "SS_TOTAL_CX_FORCE_MAP_MAX "); + logError(1, "failed... ERROR %02X\n", + ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; } - ret = checkLimitsMapTotal(total_cx, ssCompData.header.force_node, 1, thresholds_min, thresholds_max); /* check the values with thresholds */ + //check the values with thresholds + ret = checkLimitsMapTotal(total_cx, + ssCompData.header.force_node, + 1, + thresholds_min, + thresholds_max); if (ret != OK) { - logError(1, "%s production_test_data: checkLimitsMap SS TOTAL FORCE failed... ERROR COUNT = %d\n", tag, ret); - logError(0, "%s SS TOTAL FORCE MIN MAX TEST:.................FAIL\n\n", tag); + logError(1, "%s production_test_data: ", tag); + logError(1, "checkLimitsMap SS TOTAL FORCE "); + logError(1, "failed... ERROR COUNT = %d\n", + ret); + logError(0, "%s SS TOTAL FORCE MIN MAX ", tag); + logError(0, "TEST:.................FAIL\n\n"); count_fail += 1; if (stop_on_fail) goto ERROR; - } else - logError(0, "%s SS TOTAL FORCE MIN MAX TEST:.................OK\n\n", tag); + } else { + logError(0, "%s SS TOTAL FORCE MIN MAX ", tag); + logError(0, "TEST:.................OK\n\n"); + } kfree(thresholds_min); + thresholds_min = NULL; kfree(thresholds_max); - } else - logError(0, "%s SS TOTAL CX FORCE MIN MAX TEST:.................SKIPPED\n", tag); + thresholds_max = NULL; + } else { + logError(0, "%s SS TOTAL CX FORCE MIN MAX TEST:", tag); + logError(0, ".................SKIPPED\n"); + } - /* SS TOTAL CX FORCE ADJV TEST */ + //SS TOTAL CX FORCE ADJV TEST logError(0, "%s SS TOTAL CX FORCE ADJ TEST:\n", tag); if (todo->SelfForceCxTotalAdj == 1) { - logError(0, "%s SS TOTAL CX FORCE ADJVERT TEST:\n", tag); - ret = computeAdjVertTotal(total_cx, ssCompData.header.force_node, 1, &total_adjvert); /* comepute the ADJV for CX2 FORCE */ + logError(0, "%s SS TOTAL CX FORCE ADJVERT ", tag); + logError(0, "TEST:\n"); + + //comepute the ADJV for CX2 FORCE + ret = computeAdjVertTotal(total_cx, + ssCompData.header.force_node, + 1, + &total_adjvert); if (ret < 0) { - logError(1, "%s production_test_data: computeAdjVert SS TOTAL CX FORCE ADJV failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA); - return (ret | ERROR_PROD_TEST_DATA); + logError(1, "%s production_test_data: ", tag); + logError(1, "computeAdjVert SS TOTAL CX FORCE"); + logError(1, " ADJV failed... ERROR %02X\n", + ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; } - logError(0, "%s SS TOTAL CX FORCE ADJV computed!\n", tag); - - ret = parseProductionTestLimits(path_limits, SS_TOTAL_CX_FORCE_ADJV_MAP_MAX, &thresholds_max, &trows, &tcolumns); /* load the max thresholds */ - if (ret < 0 || (trows != ssCompData.header.force_node - 1 || tcolumns != 1)) { - logError(1, "%s production_test_data: parseProductionTestLimits SS_TOTAL_CX_FORCE_ADJV_MAP_MAX failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA); - return (ret | ERROR_PROD_TEST_DATA); + logError(0, "%s SS TOTAL CX FORCE ADJV computed!\n", + tag); + + ret = parseProductionTestLimits(path_limits, + SS_TOTAL_CX_FORCE_ADJV_MAP_MAX, + &thresholds_max, + &trows, + &tcolumns); //load the max thresholds + if (ret < 0 + || (trows != ssCompData.header.force_node - 1 + || tcolumns != 1)) { + logError(1, "%s production_test_data: ", tag); + logError(1, "parseProductionTestLimits "); + logError(1, "SS_TOTAL_CX_FORCE_ADJV_MAP_MAX "); + logError(1, "failed... ERROR %02X\n", + ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; } - ret = checkLimitsMapAdjTotal(total_adjvert, ssCompData.header.force_node - 1, 1, thresholds_max); /* check the values with thresholds */ + //check the values with thresholds + ret = checkLimitsMapAdjTotal(total_adjvert, + ssCompData.header.force_node - 1, + 1, + thresholds_max); if (ret != OK) { - logError(1, "%s production_test_data: checkLimitsMap SS TOTAL CX FORCE failed... ERROR COUNT = %d\n", tag, ret); - logError(0, "%s SS TOTAL CX FORCE ADJV TEST:.................FAIL\n\n", tag); + logError(1, "%s production_test_data: ", tag); + logError(1, "checkLimitsMap SS TOTAL CX FORCE"); + logError(1, " failed... ERROR COUNT = %d\n", + ret); + logError(0, "%s SS TOTAL CX FORCE ADJV ", tag); + logError(0, "TEST:.................FAIL\n\n"); count_fail += 1; if (stop_on_fail) goto ERROR; - } else - logError(0, "%s SS TOTAL CX FORCE ADJV TEST:.................OK\n\n", tag); + } else { + logError(0, "%s SS TOTAL CX FORCE ADJV ", tag); + logError(0, "TEST:.................OK\n\n"); + } kfree(thresholds_max); + thresholds_max = NULL; kfree(total_adjvert); + total_adjvert = NULL; - } else - logError(0, "%s SS TOTAL CX FORCE ADJ TEST:.................SKIPPED\n", tag); + } else { + logError(0, "%s SS TOTAL CX FORCE ADJ TEST:......", + tag); + logError(0, "..........SKIPPED\n"); + } kfree(total_cx); - } else - logError(0, "%s SS TOTAL CX FORCE TEST:.................SKIPPED\n\n", tag); + total_cx = NULL; + } else { + logError(0, "%s SS TOTAL CX FORCE TEST:.................", tag); + logError(0, "SKIPPED\n\n"); + } + - /* ********************** SS SENSE CX ************************************/ - /* SS CX1 SENSE TEST */ + //**************** SS SENSE CX **************************************/ + //SS CX1 SENSE TEST logError(0, "%s SS CX1 SENSE TEST:\n", tag); if (todo->SelfSenseCx1 == 1) { - - ret = parseProductionTestLimits(path_limits, SS_CX1_SENSE_MIN_MAX, &thresholds, &trows, &tcolumns); + ret = parseProductionTestLimits(path_limits, + SS_CX1_SENSE_MIN_MAX, + &thresholds, + &trows, + &tcolumns); if (ret < 0 || (trows != 1 || tcolumns != 2)) { - logError(1, "%s production_test_data: parseProductionTestLimits SS_CX1_SENSE_MIN_MAX failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA); - return (ret | ERROR_PROD_TEST_DATA); + logError(1, "%s production_test_data: ", tag); + logError(1, "parseProductionTestLimits "); + logError(1, "SS_CX1_SENSE_MIN_MAX failed"); + logError(1, "... ERROR %02X\n", ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; } container = (u16) ssCompData.s_cx1; - ret = checkLimitsMinMax(&container, 1, 1, thresholds[0], thresholds[1]); /* check the limits */ + //check the limits + ret = checkLimitsMinMax(&container, + 1, + 1, + thresholds[0], + thresholds[1]); if (ret != OK) { - logError(1, "%s production_test_data: checkLimitsMinMax SS CX1 SENSE TEST failed... ERROR COUNT = %d\n", tag, ret); + logError(1, "%s production_test_data: ", tag); + logError(1, "checkLimitsMinMax SS CX1 SENSE TEST "); + logError(1, "failed... ERROR COUNT = %d\n", ret); count_fail += 1; if (stop_on_fail) goto ERROR; - } else - logError(0, "%s SS CX1 SENSE TEST:.................OK\n\n", tag); + } else { + logError(0, "%s SS CX1 SENSE TEST:..............", tag); + logError(0, "...OK\n\n"); + } kfree(thresholds); - } else - logError(0, "%s SS CX1 SENSE TEST:.................SKIPPED\n\n", tag); + thresholds = NULL; + } else { + logError(0, "%s SS CX1 SENSE TEST:.................", tag); + logError(0, "SKIPPED\n\n"); + } + - /* SS CX2 SENSE TEST */ + //SS CX2 SENSE TEST logError(0, "%s SS CX2 SENSE MIN MAX TEST:\n", tag); if (todo->SelfSenseCx2 == 1) { - ret = parseProductionTestLimits(path_limits, SS_CX2_SENSE_MAP_MIN, &thresholds_min, &trows, &tcolumns); /* load the min thresholds */ - if (ret < 0 || (trows != 1 || tcolumns != ssCompData.header.sense_node)) { - logError(1, "%s production_test_data: parseProductionTestLimits SS_CX2_SENSE_MAP_MIN failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA); - return (ret | ERROR_PROD_TEST_DATA); + //load the min thresholds + ret = parseProductionTestLimits(path_limits, + SS_CX2_SENSE_MAP_MIN, + &thresholds_min, + &trows, + &tcolumns); + if (ret < 0 || (trows != 1 + || tcolumns != ssCompData.header.sense_node)) { + logError(1, "%s production_test_data: ", tag); + logError(1, "parseProductionTestLimits "); + logError(1, "SS_CX2_SENSE_MAP_MIN failed... "); + logError(1, "ERROR %02X\n", ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; } - ret = parseProductionTestLimits(path_limits, SS_CX2_SENSE_MAP_MAX, &thresholds_max, &trows, &tcolumns); /* load the max thresholds */ - if (ret < 0 || (trows != 1 || tcolumns != ssCompData.header.sense_node)) { - logError(1, "%s production_test_data: parseProductionTestLimits SS_CX2_SENSE_MAP_MAX failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA); - return (ret | ERROR_PROD_TEST_DATA); + //load the max thresholds + ret = parseProductionTestLimits(path_limits, + SS_CX2_SENSE_MAP_MAX, + &thresholds_max, + &trows, + &tcolumns); + if (ret < 0 || (trows != 1 + || tcolumns != ssCompData.header.sense_node)) { + logError(1, "%s production_test_data: ", tag); + logError(1, "parseProductionTestLimits "); + logError(1, "SS_CX2_SENSE_MAP_MAX failed... "); + logError(1, "ERROR %02X\n", ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; } - ret = checkLimitsMap(ssCompData.cx2_sn, 1, ssCompData.header.sense_node, thresholds_min, thresholds_max); /* check the values with thresholds */ + //check the values with thresholds + ret = checkLimitsMap(ssCompData.cx2_sn, + 1, + ssCompData.header.sense_node, + thresholds_min, + thresholds_max); if (ret != OK) { - logError(1, "%s production_test_data: checkLimitsMap SS CX2 SENSE failed... ERROR COUNT = %d\n", tag, ret); - logError(0, "%s SS CX2 SENSE MIN MAX TEST:.................FAIL\n\n", tag); + logError(1, "%s production_test_data: ", tag); + logError(1, "checkLimitsMap SS CX2 SENSE failed... "); + logError(1, "ERROR COUNT = %d\n", ret); + logError(0, "%s SS CX2 SENSE MIN MAX TEST:......", tag); + logError(0, "...........FAIL\n\n"); count_fail += 1; if (stop_on_fail) goto ERROR; - } else - logError(0, "%s SS CX2 SENSE MIN MAX TEST:.................OK\n\n", tag); + } else { + logError(0, "%s SS CX2 SENSE MIN MAX TEST:", tag); + logError(0, ".................OK\n\n"); + } kfree(thresholds_min); + thresholds_min = NULL; kfree(thresholds_max); - } else - logError(0, "%s SS CX2 SENSE MIN MAX TEST:.................SKIPPED\n", tag); - + thresholds_max = NULL; + } else { + logError(0, "%s SS CX2 SENSE MIN MAX TEST:.........", tag); + logError(0, "........SKIPPED\n"); + } logError(0, "%s SS CX2 SENSE ADJ TEST:\n", tag); if (todo->SelfSenseCx2Adj == 1) { - /* SS CX2 SENSE ADJH TEST */ + //SS CX2 SENSE ADJH TEST logError(0, "%s SS CX2 SENSE ADJHORIZ TEST:\n", tag); - ret = computeAdjHoriz(ssCompData.ix2_sn, 1, ssCompData.header.sense_node, &adjhor); + ret = computeAdjHoriz(ssCompData.cx2_sn, + 1, + ssCompData.header.sense_node, + &adjhor); if (ret < 0) { - logError(1, "%s production_test_data: computeAdjHoriz SS CX2 SENSE ADJH failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA); - return (ret | ERROR_PROD_TEST_DATA); + logError(1, "%s production_test_data: ", tag); + logError(1, "computeAdjHoriz SS CX2 SENSE ADJH "); + logError(1, "failed... ERROR %02X\n", + ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; } logError(0, "%s SS CX2 SENSE ADJH computed!\n", tag); - ret = parseProductionTestLimits(path_limits, SS_CX2_SENSE_ADJH_MAP_MAX, &thresholds_max, &trows, &tcolumns); /* load the max thresholds */ - if (ret < 0 || (trows != 1 || tcolumns != ssCompData.header.sense_node - 1)) { - logError(1, "%s production_test_data: parseProductionTestLimits SS_IX2_SENSE_MAP_MAX failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA); - return (ret | ERROR_PROD_TEST_DATA); + //load the max thresholds + ret = parseProductionTestLimits(path_limits, + SS_CX2_SENSE_ADJH_MAP_MAX, + &thresholds_max, + &trows, + &tcolumns); + if (ret < 0 || (trows != 1 + || tcolumns != ssCompData.header.sense_node - 1)) { + logError(1, "%s production_test_data: ", tag); + logError(1, "parseProductionTestLimits "); + logError(1, "SS_IX2_SENSE_MAP_MAX failed... "); + logError(1, "ERROR %02X\n", ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; } - ret = checkLimitsMapAdj(adjhor, 1, ssCompData.header.sense_node - 1, thresholds_max); /* check the values with thresholds */ + //check the values with thresholds + ret = checkLimitsMapAdj(adjhor, + 1, + ssCompData.header.sense_node - 1, + thresholds_max); if (ret != OK) { - logError(1, "%s production_test_data: checkLimitsMapAdj SS CX2 SENSE ADJH failed... ERROR COUNT = %d\n", tag, ret); - logError(0, "%s SS CX2 SENSE ADJH TEST:.................FAIL\n\n", tag); + logError(1, "%s production_test_data: ", tag); + logError(1, "checkLimitsMapAdj SS CX2 SENSE ADJH "); + logError(1, "failed... ERROR COUNT = %d\n", ret); + logError(0, "%s SS CX2 SENSE ADJH TEST:.........", tag); + logError(0, "........FAIL\n\n"); count_fail += 1; if (stop_on_fail) goto ERROR; - } else - logError(0, "%s SS CX2 SENSE ADJH TEST:.................OK\n", tag); + } else { + logError(0, "%s SS CX2 SENSE ADJH TEST:.........", tag); + logError(0, "........OK\n"); + } kfree(thresholds_max); + thresholds_max = NULL; kfree(adjhor); - } else - logError(0, "%s SS CX2 SENSE ADJ TEST:.................SKIPPED\n\n", tag); + adjhor = NULL; + } else { + logError(0, "%s SS CX2 SENSE ADJ TEST:.................", tag); + logError(0, "SKIPPED\n\n"); + } - /* SS TOTAL CX SENSE */ + //SS TOTAL CX SENSE logError(0, "%s SS TOTAL CX SENSE TEST:\n", tag); if (todo->SelfSenseCxTotal == 1 || todo->SelfSenseCxTotalAdj == 1) { - ret = computeTotal(ssCompData.cx2_sn, ssCompData.s_cx1, 1, ssCompData.header.sense_node, CX1_WEIGHT, CX2_WEIGHT, &total_cx); + ret = computeTotal(ssCompData.cx2_sn, + ssCompData.s_cx1, + 1, + ssCompData.header.sense_node, + CX1_WEIGHT, + CX2_WEIGHT, + &total_cx); if (ret < 0) { - logError(1, "%s production_test_data: computeTotal Cx Sense failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA); - return (ret | ERROR_PROD_TEST_DATA); + logError(1, "%s production_test_data: ", tag); + logError(1, "computeTotal Cx Sense failed... "); + logError(1, "ERROR %02X\n", ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; } logError(0, "%s SS TOTAL CX SENSE MIN MAX TEST:\n", tag); + //load the min thresholds if (todo->SelfSenseCxTotal == 1) { - ret = parseProductionTestLimits(path_limits, SS_TOTAL_CX_SENSE_MAP_MIN, &thresholds_min, &trows, &tcolumns); /* load the min thresholds */ - if (ret < 0 || (trows != 1 || tcolumns != ssCompData.header.sense_node)) { - logError(1, "%s production_test_data: parseProductionTestLimits SS_TOTAL_CX_SENSE_MAP_MIN failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA); - return (ret | ERROR_PROD_TEST_DATA); + ret = parseProductionTestLimits(path_limits, + SS_TOTAL_CX_SENSE_MAP_MIN, + &thresholds_min, + &trows, + &tcolumns); + if (ret < 0 || (trows != 1 + || tcolumns != ssCompData.header.sense_node)) { + logError(1, "%s production_test_data: ", tag); + logError(1, "parseProductionTestLimits "); + logError(1, "SS_TOTAL_CX_SENSE_MAP_MIN "); + logError(1, "failed... ERROR %02X\n", + ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; } - - ret = parseProductionTestLimits(path_limits, SS_TOTAL_CX_SENSE_MAP_MAX, &thresholds_max, &trows, &tcolumns); /* load the max thresholds */ - if (ret < 0 || (trows != 1 || tcolumns != ssCompData.header.sense_node)) { - logError(1, "%s production_test_data: parseProductionTestLimits SS_TOTAL_CX_SENSE_MAP_MAX failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA); - return (ret | ERROR_PROD_TEST_DATA); + //load the max thresholds + ret = parseProductionTestLimits(path_limits, + SS_TOTAL_CX_SENSE_MAP_MAX, + &thresholds_max, + &trows, + &tcolumns); + if (ret < 0 || (trows != 1 + || tcolumns != ssCompData.header.sense_node)) { + logError(1, "%s production_test_data: ", tag); + logError(1, "parseProductionTestLimits "); + logError(1, "SS_TOTAL_CX_SENSE_MAP_MAX "); + logError(1, "failed... ERROR %02X\n", + ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; } - ret = checkLimitsMapTotal(total_cx, 1, ssCompData.header.sense_node, thresholds_min, thresholds_max); /* check the values with thresholds */ + //check the values with thresholds + ret = checkLimitsMapTotal(total_cx, + 1, + ssCompData.header.sense_node, + thresholds_min, + thresholds_max); if (ret != OK) { - logError(1, "%s production_test_data: checkLimitsMap SS TOTAL CX SENSE failed... ERROR COUNT = %d\n", tag, ret); - logError(0, "%s SS TOTAL CX SENSE MIN MAX TEST:.................FAIL\n\n", tag); + logError(1, "%s production_test_data: ", tag); + logError(1, "heckLimitsMap SS TOTAL CX SENSE "); + logError(1, "failed... ERROR COUNT = %d\n", + ret); + logError(0, "%s SS TOTAL CX SENSE MIN ", tag); + logError(0, "MAX TEST:................."); + logError(0, "FAIL\n\n"); count_fail += 1; - if (stop_on_fail) - goto ERROR; - } else - logError(0, "%s SS TOTAL CX SENSE MIN MAX TEST:.................OK\n\n", tag); + if (stop_on_fail) + goto ERROR; + } else { + logError(0, "%s SS TOTAL CX SENSE MIN ", tag); + logError(0, "MAX TEST:................OK\n\n"); + } kfree(thresholds_min); + thresholds_min = NULL; kfree(thresholds_max); - } else - logError(0, "%s SS TOTAL CX SENSE MIN MAX TEST:.................SKIPPED\n", tag); + thresholds_max = NULL; + } else { + logError(0, "%s SS TOTAL CX SENSE MIN MAX TEST:", tag); + logError(0, ".................SKIPPED\n"); + } - /* SS TOTAL IX SENSE ADJH TEST */ + + //SS TOTAL IX SENSE ADJH TEST logError(0, "%s SS TOTAL CX SENSE ADJ TEST:\n", tag); if (todo->SelfSenseCxTotalAdj == 1) { - logError(0, "%s SS TOTAL CX SENSE ADJHORIZ TEST:\n", tag); - ret = computeAdjHorizTotal(total_cx, 1, ssCompData.header.sense_node, &total_adjhor); + logError(0, "%s SS TOTAL CX SENSE ADJHORIZ TEST:\n", + tag); + ret = computeAdjHorizTotal(total_cx, + 1, + ssCompData.header.sense_node, + &total_adjhor); if (ret < 0) { - logError(1, "%s production_test_data: computeAdjHoriz SS TOTAL CX SENSE ADJH failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA); - return (ret | ERROR_PROD_TEST_DATA); + logError(1, "%s production_test_data: ", tag); + logError(1, "computeAdjHoriz SS TOTAL CX "); + logError(1, "SENSE ADJH failed... "); + logError(1, "ERROR %02X\n", + ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; } - logError(0, "%s SS TOTAL CX SENSE ADJ HORIZ computed!\n", tag); - - ret = parseProductionTestLimits(path_limits, SS_TOTAL_CX_SENSE_ADJH_MAP_MAX, &thresholds_max, &trows, &tcolumns); /* load the max thresholds */ - if (ret < 0 || (trows != 1 || tcolumns != ssCompData.header.sense_node - 1)) { - logError(1, "%s production_test_data: parseProductionTestLimits SS_TOTAL_CX_SENSE_ADJH_MAP_MAX failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA); - return (ret | ERROR_PROD_TEST_DATA); + logError(0, "%s SS TOTAL CX SENSE ADJ HORIZ ", tag); + logError(0, "computed!\n"); + + ret = parseProductionTestLimits(path_limits, + SS_TOTAL_CX_SENSE_ADJH_MAP_MAX, + &thresholds_max, + &trows, + &tcolumns); //load the max thresholds + if (ret < 0 || (trows != 1 || + tcolumns != ssCompData.header.sense_node - 1)) { + logError(1, "%s production_test_data: ", tag); + logError(1, "parseProductionTestLimits "); + logError(1, "SS_TOTAL_CX_SENSE_ADJH_MAP_MAX "); + logError(1, "failed... ERROR %02X\n", + ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; } - ret = checkLimitsMapAdjTotal(total_adjhor, 1, ssCompData.header.sense_node - 1, thresholds_max); /* check the values with thresholds */ + //check the values with thresholds + ret = checkLimitsMapAdjTotal(total_adjhor, + 1, + ssCompData.header.sense_node - 1, + thresholds_max); if (ret != OK) { - logError(1, "%s production_test_data: checkLimitsMapAdj SS TOTAL CX SENSE ADJH failed... ERROR COUNT = %d\n", tag, ret); - logError(0, "%s SS TOTAL CX SENSE ADJH TEST:.................FAIL\n\n", tag); + logError(1, "%s production_test_data: ", tag); + logError(1, "checkLimitsMapAdj SS TOTAL "); + logError(1, "CX SENSE ADJH failed... "); + logError(1, "ERROR COUNT = %d\n", ret); + logError(0, "%s SS TOTAL CX SENSE ADJH ", tag); + logError(0, "TEST:...FAIL\n\n"); count_fail += 1; if (stop_on_fail) goto ERROR; - } else - logError(0, "%s SS TOTAL CX SENSE ADJH TEST:.................OK\n\n", tag); + } else { + logError(0, "%s SS TOTAL CX SENSE ADJH TEST:", + tag); + logError(0, ".................OK\n\n"); + } kfree(thresholds_max); + thresholds_max = NULL; kfree(total_adjhor); - } else - logError(0, "%s SS TOTAL CX SENSE ADJ TEST:.................SKIPPED\n", tag); + total_adjhor = NULL; + } else { + logError(0, "%s SS TOTAL CX SENSE ADJ TEST:.", tag); + logError(0, "SKIPPED\n"); + } kfree(total_cx); + total_cx = NULL; } else - logError(0, "%s SS TOTAL CX SENSE TEST:.................SKIPPED\n", tag); - - /* SS compensation data are no usefull anymore */ + logError(0, "%s SS TOTAL CX SENSE TEST:.....SKIPPED\n", tag); - kfree(ssCompData.ix2_fm); - kfree(ssCompData.ix2_sn); - kfree(ssCompData.cx2_fm); - kfree(ssCompData.cx2_sn); ERROR: logError(0, "%s\n", tag); if (count_fail == 0) { - logError(0, "%s SS IX CX testes finished!.................OK\n\n", tag); - return OK; - } - /* print all kind of data in just one row for readability reason */ - print_frame_u8("SS Init Data Ix2_fm = ", array1dTo2d_u8(ssCompData.ix2_fm, ssCompData.header.force_node, ssCompData.header.force_node), 1, ssCompData.header.force_node); - print_frame_u8("SS Init Data Cx2_fm = ", array1dTo2d_u8(ssCompData.cx2_fm, ssCompData.header.force_node, ssCompData.header.force_node), 1, ssCompData.header.force_node); - print_frame_u8("SS Init Data Ix2_sn = ", array1dTo2d_u8(ssCompData.ix2_sn, ssCompData.header.sense_node, ssCompData.header.sense_node), 1, ssCompData.header.sense_node); - print_frame_u8("SS Init Data Cx2_sn = ", array1dTo2d_u8(ssCompData.cx2_sn, ssCompData.header.sense_node, ssCompData.header.sense_node), 1, ssCompData.header.sense_node); - logError(0, "%s SS IX CX testes finished!.................FAILED fails_count = %d\n\n", tag, count_fail); - return (ERROR_TEST_CHECK_FAIL | ERROR_PROD_TEST_DATA); + kfree(ssCompData.ix2_fm); + ssCompData.ix2_fm = NULL; + kfree(ssCompData.ix2_sn); + ssCompData.ix2_sn = NULL; + kfree(ssCompData.cx2_fm); + ssCompData.cx2_fm = NULL; + kfree(ssCompData.cx2_sn); + ssCompData.cx2_sn = NULL; + logError(0, "%s SS IX CX testes finished!........OK\n\n", tag); + ret = OK; + } else { + //print all kind of data in just one row for readability reason + print_frame_u8("SS Init Data Ix2_fm = ", + array1dTo2d_u8(ssCompData.ix2_fm, + ssCompData.header.force_node, + ssCompData.header.force_node), + 1, + ssCompData.header.force_node); + print_frame_u8("SS Init Data Cx2_fm = ", + array1dTo2d_u8(ssCompData.cx2_fm, + ssCompData.header.force_node, + ssCompData.header.force_node), + 1, + ssCompData.header.force_node); + print_frame_u8("SS Init Data Ix2_sn = ", + array1dTo2d_u8(ssCompData.ix2_sn, + ssCompData.header.sense_node, + ssCompData.header.sense_node), + 1, + ssCompData.header.sense_node); + print_frame_u8("SS Init Data Cx2_sn = ", + array1dTo2d_u8(ssCompData.cx2_sn, + ssCompData.header.sense_node, + ssCompData.header.sense_node), + 1, + ssCompData.header.sense_node); + logError(0, "%s SS IX CX testes finished!.................", + tag); + logError(0, "FAILED fails_count = %d\n\n", count_fail); + if (thresholds != NULL) + kfree(thresholds); + if (thresholds_min != NULL) + kfree(thresholds_min); + if (thresholds_max != NULL) + kfree(thresholds_max); + if (adjhor != NULL) + kfree(adjhor); + if (adjvert != NULL) + kfree(adjvert); + if (ix1_w != NULL) + kfree(ix1_w); + if (ix2_w != NULL) + kfree(ix2_w); + if (total_ix != NULL) + kfree(total_ix); + if (total_cx != NULL) + kfree(total_cx); + if (total_adjhor != NULL) + kfree(total_adjhor); + if (total_adjvert != NULL) + kfree(total_adjvert); + if (ssCompData.ix2_fm != NULL) + kfree(ssCompData.ix2_fm); + if (ssCompData.ix2_sn != NULL) + kfree(ssCompData.ix2_sn); + if (ssCompData.cx2_fm != NULL) + kfree(ssCompData.cx2_fm); + if (ssCompData.cx2_sn != NULL) + kfree(ssCompData.cx2_sn); + ret = (ERROR_TEST_CHECK_FAIL | ERROR_PROD_TEST_DATA); + } + return ret; +ERROR_LIMITS: + if (thresholds != NULL) + kfree(thresholds); + if (thresholds_min != NULL) + kfree(thresholds_min); + if (thresholds_max != NULL) + kfree(thresholds_max); + if (adjhor != NULL) + kfree(adjhor); + if (adjvert != NULL) + kfree(adjvert); + if (ix1_w != NULL) + kfree(ix1_w); + if (ix2_w != NULL) + kfree(ix2_w); + if (total_ix != NULL) + kfree(total_ix); + if (total_cx != NULL) + kfree(total_cx); + if (total_adjhor != NULL) + kfree(total_adjhor); + if (total_adjvert != NULL) + kfree(total_adjvert); + if (ssCompData.ix2_fm != NULL) + kfree(ssCompData.ix2_fm); + if (ssCompData.ix2_sn != NULL) + kfree(ssCompData.ix2_sn); + if (ssCompData.cx2_fm != NULL) + kfree(ssCompData.cx2_fm); + if (ssCompData.cx2_sn != NULL) + kfree(ssCompData.cx2_sn); + return ret; } -int production_test_data(char *path_limits, int stop_on_fail, TestToDo *todo) +int production_test_data(char *path_limits, int stop_on_fail, + struct TestToDo *todo) { int res = OK, ret; if (todo == NULL) { - logError(1, "%s production_test_data: No TestToDo specified!! ERROR = %02X\n", tag, (ERROR_OP_NOT_ALLOW | ERROR_PROD_TEST_DATA)); + logError(1, "%s %s: ", tag, __func__); + logError(1, "No TestToDo specified!! "); + logError(1, "ERROR = %02X\n", + (ERROR_OP_NOT_ALLOW | ERROR_PROD_TEST_DATA)); return (ERROR_OP_NOT_ALLOW | ERROR_PROD_TEST_DATA); } logError(0, "%s DATA Production test is starting...\n", tag); - ret = production_test_ms_raw(path_limits, stop_on_fail, todo); res |= ret; if (ret < 0) { - logError(1, "%s production_test_data: production_test_ms_raw failed... ERROR = %02X\n", tag, ret); + logError(1, "%s %s: ", tag, __func__); + logError(1, "production_test_ms_raw failed... "); + logError(1, "ERROR = %02X\n", ret); if (stop_on_fail == 1) goto END; } ret = production_test_ms_cx(path_limits, stop_on_fail, todo); res |= ret; - if (res < 0) { - logError(1, "%s production_test_data: production_test_ms_cx failed... ERROR = %02X\n", tag, ret); + if (ret < 0) { + logError(1, "%s %s: ", tag, __func__); + logError(1, "production_test_ms_cx failed... "); + logError(1, "ERROR = %02X\n", ret); if (stop_on_fail == 1) goto END; } @@ -2115,7 +3659,9 @@ int production_test_data(char *path_limits, int stop_on_fail, TestToDo *todo) ret = production_test_ss_raw(path_limits, stop_on_fail, todo); res |= ret; if (ret < 0) { - logError(1, "%s production_test_data: production_test_ss_raw failed... ERROR = %02X\n", tag, ret); + logError(1, "%s %s: ", tag, __func__); + logError(1, "production_test_ss_raw failed... "); + logError(1, "ERROR = %02X\n", ret); if (stop_on_fail == 1) goto END; } @@ -2123,7 +3669,9 @@ int production_test_data(char *path_limits, int stop_on_fail, TestToDo *todo) ret = production_test_ss_ix_cx(path_limits, stop_on_fail, todo); res |= ret; if (ret < 0) { - logError(1, "%s production_test_data: production_test_ss_ix_cx failed... ERROR = %02X\n", tag, ret); + logError(1, "%s %s: ", tag, __func__); + logError(1, "production_test_ss_ix_cx failed... "); + logError(1, "ERROR = %02X\n", ret); if (stop_on_fail == 1) goto END; } @@ -2136,52 +3684,50 @@ int production_test_data(char *path_limits, int stop_on_fail, TestToDo *todo) return res; } + int save_mp_flag(u32 signature) { - int res = -1, ret; + int res = -1; int i; u8 cmd[6] = {FTS_CMD_WRITE_MP_FLAG, 0x00, 0x00, 0x00, 0x00, 0x00}; u32ToU8(signature, &cmd[2]); - logError(0, "%s Starting Saving Flag with signature = %08X ...\n", tag, signature); + logError(0, "%s Starting Saving Flag with signature = %08X ...\n", + tag, signature); for (i = 0; i < SAVE_FLAG_RETRY && res < OK; i++) { - logError(0, "%s Attempt number %d to save mp flag !\n", tag, i+1); + logError(0, "%s Attempt number %d to save mp flag !\n", + tag, i+1); logError(0, "%s Command write flag sent...\n", tag); res = fts_writeFwCmd(cmd, 6); if (res >= OK) res = save_cx_tuning(); - } - ret = readChipInfo(1); /* need to update the MP Flag */ - if (ret < OK) { - logError(1, "%s save_mp_flag: read chip info ERROR %08X\n", tag, ret); - } - - res |= ret; if (res < OK) { - logError(1, "%s save_mp_flag: ERROR %08X ...\n", tag, res); - return res; + logError(1, "%s %s: ERROR %08X ...\n", tag, __func__, res); + } else { + logError(1, "%s Saving Flag DONE!\n", tag); + res = OK; } - logError(1, "%s Saving Flag DONE!\n", tag); - return OK; + return res; } -int parseProductionTestLimits(char *path, char *label, int **data, int *row, int *column) +int parseProductionTestLimits(char *path, char *label, + int **data, int *row, int *column) { - int find = 0; char *token = NULL; int i = 0; int j = 0; int z = 0; - char *line = NULL; + char *line2 = NULL; + char line[800]; int fd = -1; char *buf = NULL; - int n, size, pointer = 0, ret; + int n, size, pointer = 0, ret = OK; char *data_file = NULL; #ifndef LIMITS_H_FILE const struct firmware *fw = NULL; @@ -2194,131 +3740,174 @@ int parseProductionTestLimits(char *path, char *label, int **data, int *row, int fd = 0; #endif - line = (char *)kmalloc(1800*sizeof(char), GFP_KERNEL); - buf = line; + if (fd != 0) { + logError(1, "%s %s: ERROR %02X\n", + tag, __func__, ERROR_FILE_NOT_FOUND); + return ERROR_FILE_NOT_FOUND; + } - if (fd == 0) { #ifndef LIMITS_H_FILE - size = fw->size; - data_file = (char *)fw->data; - logError(0, "%s Start to reading %s...\n", tag, path); + size = fw->size; + data_file = (char *)fw->data; + logError(0, "%s Start to reading %s...\n", tag, path); #else - size = LIMITS_SIZE_NAME; - data_file = (char *)(LIMITS_ARRAY_NAME); + size = LIMITS_SIZE_NAME; + data_file = (char *)(LIMITS_ARRAY_NAME); #endif + logError(0, "%s The size of the limits file is %d bytes\n", tag, size); - logError(0, "%s The size of the limits file is %d bytes...\n", tag, size); - - while (find == 0) { - /* start to look for the wanted label */ - if (readLine(&data_file[pointer], &line, size-pointer, &n) < 0) { - find = -1; - break; + while (find == 0) { + //start to look for the wanted label + if (readLine(&data_file[pointer], line, size-pointer, &n) < 0) { + find = -1; + break; + } + pointer += n; + //each header row start with + // *ex. *label, n_row, n_colum + if (line[0] != '*') + continue; + + line2 = kstrdup(line, GFP_KERNEL); + if (line2 == NULL) { + logError(1, "%s %s:kstrdup ERR %02X\n", + tag, __func__, ERROR_ALLOC); + ret = ERROR_ALLOC; + goto END; + } + buf = line2; + line2 += 1; + token = strsep(&line2, ","); + //if the row is the wanted one i + //retrieve rows and columns info + if (strcmp(token, label) == 0) { + find = 1; + token = strsep(&line2, ","); + if (token != NULL) { + ret = kstrtoint(token, 10, row); + if (ret != 0) + return -EINVAL; + logError(0, "%s Row = %d\n", tag, *row); + } else { + logError(1, "%s %s 1:ERROR %02X\n", + tag, __func__, ERROR_FILE_PARSE); + //release_firmware(fw); + //return ERROR_FILE_PARSE; + ret = ERROR_FILE_PARSE; + goto END; + } + token = strsep(&line2, ","); + if (token != NULL) { + ret = kstrtoint(token, 10, column); + if (ret != 0) + return -EINVAL; + logError(0, "%s Column = %d\n", tag, *column); + } else { + logError(1, "%s %s 2: ERROR %02X\n", + tag, __func__, ERROR_FILE_PARSE); + //release_firmware(fw); + //return ERROR_FILE_PARSE; + ret = ERROR_FILE_PARSE; + goto END; } - pointer += n; - if (line[0] == '*') { /* each header row start with * ex. *label,n_row,n_colum */ - buf = line; - line += 1; - token = strsep(&line, ","); - if (strcmp(token, label) == 0) { - /* if the row is the wanted one i retrieve rows and columns info */ - find = 1; - token = strsep(&line, ","); - if (token != NULL) { - sscanf(token, "%d", row); - logError(0, "%s Row = %d\n", tag, *row); - } else { - logError(1, "%s parseProductionTestLimits 1: ERROR %02X\n", tag, ERROR_FILE_PARSE); - /* release_firmware(fw); */ - /* return ERROR_FILE_PARSE; */ - ret = ERROR_FILE_PARSE; - goto END; - } - token = strsep(&line, ","); - if (token != NULL) { - sscanf(token, "%d", column); - logError(0, "%s Column = %d\n", tag, *column); - } else { - logError(1, "%s parseProductionTestLimits 2: ERROR %02X\n", tag, ERROR_FILE_PARSE); - /* release_firmware(fw); */ - /* return ERROR_FILE_PARSE; */ - ret = ERROR_FILE_PARSE; - goto END; - } - - *data = (int *)kmalloc(((*row)*(*column))*sizeof(int), GFP_KERNEL); - /* allocate the memory for containing the data */ - j = 0; - if (*data == NULL) { - logError(1, "%s parseProductionTestLimits: ERROR %02X\n", tag, ERROR_ALLOC); - /* release_firmware(fw); */ - /* return ERROR_ALLOC; */ - ret = ERROR_ALLOC; - goto END; - } - - /* start to read the data */ - for (i = 0; i < *row; i++) { - line = buf; - if (readLine(&data_file[pointer], &line, size-pointer, &n) < 0) { - logError(1, "%s parseProductionTestLimits : ERROR %02X\n", tag, ERROR_FILE_READ); - /* release_firmware(fw); */ - /* return ERROR_FILE_READ; */ - ret = ERROR_FILE_READ; - goto END; - } - pointer += n; - token = strsep(&line, ","); - for (z = 0; (z < *column) && (token != NULL); z++) { - sscanf(token, "%d", ((*data) + j)); - j++; - token = strsep(&line, ","); - } - } - if (j == ((*row)*(*column))) { /* check that all the data are read */ - logError(0, "%s READ DONE!\n", tag); - /* release_firmware(fw); */ - /* return OK; */ - ret = OK; - goto END; - } - logError(1, "%s parseProductionTestLimits 3: ERROR %02X\n", tag, ERROR_FILE_PARSE); - /* release_firmware(fw); */ - /* return ERROR_FILE_PARSE; */ - ret = ERROR_FILE_PARSE; + kfree(buf); + buf = NULL; + //allocate memory for containing data + *data = (int *)kmalloc_array(((*row) * (*column)), + sizeof(int), GFP_KERNEL); + j = 0; + if (*data == NULL) { + logError(1, "%s %s: ERROR %02X\n", + tag, __func__, ERROR_ALLOC); + //release_firmware(fw); + //return ERROR_ALLOC; + ret = ERROR_ALLOC; + goto END; + } + //start to read the data + for (i = 0; i < *row; i++) { + //line = buf; + if (readLine(&data_file[pointer], line, + size-pointer, &n) < 0) { + logError(1, "%s %s : ERROR %02X\n", + tag, __func__, ERROR_FILE_READ); + //release_firmware(fw); + //return ERROR_FILE_READ + ret = ERROR_FILE_READ; + goto END; + } + pointer += n; + line2 = kstrdup(line, GFP_KERNEL); + if (line2 == NULL) { + logError(1, "%s %s: kstrdup ", + tag, __func__); + logError(1, "ERROR %02X\n", + ERROR_ALLOC); + ret = ERROR_ALLOC; goto END; } + buf = line2; + token = strsep(&line2, ","); + for (z = 0; + (z < *column) && (token != NULL); z++) { + ret = kstrtoint(token, + 10, + ((*data) + j)); + if (ret != 0) + return -EINVAL; + j++; + token = strsep(&line2, ","); + } + kfree(buf); + buf = NULL; } - + //check that all the data are read + if (j == ((*row) * (*column))) { + logError(0, "%s READ DONE!\n", tag); + //release_firmware(fw); + //return OK; + ret = OK; + goto END; + } + logError(1, "%s %s 3:ERROR %02X\n", + tag, __func__, ERROR_FILE_PARSE); + //release_firmware(fw); + //return ERROR_FILE_PARSE; + ret = ERROR_FILE_PARSE; + goto END; } - logError(1, "%s parseProductionTestLimits: ERROR %02X\n", tag, ERROR_LABEL_NOT_FOUND); - ret = ERROR_LABEL_NOT_FOUND; + kfree(buf); + buf = NULL; + + } + logError(1, "%s %s: ERROR %02X\n", + tag, __func__, ERROR_LABEL_NOT_FOUND); + ret = ERROR_LABEL_NOT_FOUND; END: + if (buf != NULL) + kfree(buf); #ifndef LIMITS_H_FILE - release_firmware(fw); + release_firmware(fw); #endif - return ret; - - } else { - logError(1, "%s parseProductionTestLimits: ERROR %02X\n", tag, ERROR_FILE_NOT_FOUND); - return ERROR_FILE_NOT_FOUND; - } + return ret; } -int readLine(char *data, char **line, int size, int *n) +int readLine(char *data, char *line, int size, int *n) { int i = 0; + if (size < 1) - return 1; + return -EINVAL; - while (data[i] != '\n' && i < size) { - *(*line + i) = data[i]; - i++; - } - *n = i+1; - *(*line + i) = '\0'; + while (data[i] != '\n' && i < size) { + line[i] = data[i]; + i++; + } + *n = i + 1; + line[i] = '\0'; return OK; - } + + diff --git a/drivers/input/touchscreen/st/fts_lib/ftsTest.h b/drivers/input/touchscreen/st/fts_lib/ftsTest.h index 93da901c9f42..a2ee28285572 100644 --- a/drivers/input/touchscreen/st/fts_lib/ftsTest.h +++ b/drivers/input/touchscreen/st/fts_lib/ftsTest.h @@ -1,91 +1,116 @@ /* - -************************************************************************** -** STMicroelectronics ** -************************************************************************** -** marco.cali@st.com ** -************************************************************************** -* * -* FTS API for MP test * -* * -************************************************************************** -************************************************************************** - -*/ + * FTS Capacitive touch screen controller (FingerTipS) + * + * Copyright (C) 2016-2018, STMicroelectronics Limited. + * Authors: AMG(Analog Mems Group) + * + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + */ + +/** + * + ************************************************************************** + ** STMicroelectronics ** + ************************************************************************** + ** marco.cali@st.com ** + ************************************************************************** + * * + * FTS API for MP test ** + * * + ************************************************************************** + ************************************************************************** + */ + +#ifndef __FTS_TEST_H +#define __FTS_TEST_H #include "ftsSoftware.h" -#define LIMITS_FILE "stm_fts_production_limits.csv" - -#define WAIT_FOR_FRESH_FRAMES 100 /* ms */ -#define WAIT_AFTER_SENSEOFF 50 /* ms */ -#define TIMEOUT_ITO_TEST_RESULT 200 /* ms */ -#define TIMEOUT_INITIALIZATION_TEST_RESULT 5000 /* ms */ - -/* LABELS PRODUCTION TEST LIMITS FILE */ -#define MS_RAW_MIN_MAX "MS_RAW_DATA_MIN_MAX" -#define MS_RAW_GAP "MS_RAW_DATA_GAP" -#define MS_CX1_MIN_MAX "MS_TOUCH_ACTIVE_CX1_MIN_MAX" -#define MS_CX2_MAP_MIN "MS_TOUCH_ACTIVE_CX2_MIN" -#define MS_CX2_MAP_MAX "MS_TOUCH_ACTIVE_CX2_MAX" -#define MS_CX2_ADJH_MAP_MAX "MS_TOUCH_ACTIVE_CX2_ADJ_HORIZONTAL" -#define MS_CX2_ADJV_MAP_MAX "MS_TOUCH_ACTIVE_CX2_ADJ_VERTICAL" -#define MS_TOTAL_CX_MAP_MIN "MS_TOUCH_ACTIVE_TOTAL_CX_MIN" -#define MS_TOTAL_CX_MAP_MAX "MS_TOUCH_ACTIVE_TOTAL_CX_MAX" -#define MS_TOTAL_CX_ADJH_MAP_MAX "MS_TOUCH_ACTIVE_TOTAL_CX_ADJ_HORIZONTAL" -#define MS_TOTAL_CX_ADJV_MAP_MAX "MS_TOUCH_ACTIVE_TOTAL_CX_ADJ_VERTICAL" -#define SS_RAW_FORCE_MIN_MAX "SS_RAW_DATA_FORCE_MIN_MAX" -#define SS_RAW_SENSE_MIN_MAX "SS_RAW_DATA_SENSE_MIN_MAX" -#define SS_RAW_FORCE_GAP "SS_RAW_DATA_FORCE_GAP" -#define SS_RAW_SENSE_GAP "SS_RAW_DATA_SENSE_GAP" -#define SS_IX1_FORCE_MIN_MAX "SS_TOUCH_ACTIVE_IX1_FORCE_MIN_MAX" -#define SS_IX1_SENSE_MIN_MAX "SS_TOUCH_ACTIVE_IX1_SENSE_MIN_MAX" -#define SS_CX1_FORCE_MIN_MAX "SS_TOUCH_ACTIVE_CX1_FORCE_MIN_MAX" -#define SS_CX1_SENSE_MIN_MAX "SS_TOUCH_ACTIVE_CX1_SENSE_MIN_MAX" -#define SS_IX2_FORCE_MAP_MIN "SS_TOUCH_ACTIVE_IX2_FORCE_MIN" -#define SS_IX2_FORCE_MAP_MAX "SS_TOUCH_ACTIVE_IX2_FORCE_MAX" -#define SS_IX2_SENSE_MAP_MIN "SS_TOUCH_ACTIVE_IX2_SENSE_MIN" -#define SS_IX2_SENSE_MAP_MAX "SS_TOUCH_ACTIVE_IX2_SENSE_MAX" -#define SS_IX2_FORCE_ADJV_MAP_MAX "SS_TOUCH_ACTIVE_IX2_ADJ_VERTICAL" -#define SS_IX2_SENSE_ADJH_MAP_MAX "SS_TOUCH_ACTIVE_IX2_ADJ_HORIZONTAL" -#define SS_CX2_FORCE_MAP_MIN "SS_TOUCH_ACTIVE_CX2_FORCE_MIN" -#define SS_CX2_FORCE_MAP_MAX "SS_TOUCH_ACTIVE_CX2_FORCE_MAX" -#define SS_CX2_SENSE_MAP_MIN "SS_TOUCH_ACTIVE_CX2_SENSE_MIN" -#define SS_CX2_SENSE_MAP_MAX "SS_TOUCH_ACTIVE_CX2_SENSE_MAX" -#define SS_CX2_FORCE_ADJV_MAP_MAX "SS_TOUCH_ACTIVE_CX2_ADJ_VERTICAL" -#define SS_CX2_SENSE_ADJH_MAP_MAX "SS_TOUCH_ACTIVE_CX2_ADJ_HORIZONTAL" - -/* TOTAL SS */ -#define SS_TOTAL_IX_FORCE_MAP_MIN "SS_TOUCH_ACTIVE_TOTAL_IX_FORCE_MIN" -#define SS_TOTAL_IX_FORCE_MAP_MAX "SS_TOUCH_ACTIVE_TOTAL_IX_FORCE_MAX" -#define SS_TOTAL_IX_SENSE_MAP_MIN "SS_TOUCH_ACTIVE_TOTAL_IX_SENSE_MIN" -#define SS_TOTAL_IX_SENSE_MAP_MAX "SS_TOUCH_ACTIVE_TOTAL_IX_SENSE_MAX" -#define SS_TOTAL_IX_FORCE_ADJV_MAP_MAX "SS_TOUCH_ACTIVE_TOTAL_IX_ADJ_VERTICAL" -#define SS_TOTAL_IX_SENSE_ADJH_MAP_MAX "SS_TOUCH_ACTIVE_TOTAL_IX_ADJ_HORIZONTAL" -#define SS_TOTAL_CX_FORCE_MAP_MIN "SS_TOUCH_ACTIVE_TOTAL_CX_FORCE_MIN" -#define SS_TOTAL_CX_FORCE_MAP_MAX "SS_TOUCH_ACTIVE_TOTAL_CX_FORCE_MAX" -#define SS_TOTAL_CX_SENSE_MAP_MIN "SS_TOUCH_ACTIVE_TOTAL_CX_SENSE_MIN" -#define SS_TOTAL_CX_SENSE_MAP_MAX "SS_TOUCH_ACTIVE_TOTAL_CX_SENSE_MAX" -#define SS_TOTAL_CX_FORCE_ADJV_MAP_MAX "SS_TOUCH_ACTIVE_TOTAL_CX_ADJ_VERTICAL" -#define SS_TOTAL_CX_SENSE_ADJH_MAP_MAX "SS_TOUCH_ACTIVE_TOTAL_CX_ADJ_HORIZONTAL" - -/* KEYS */ -#define MS_KEY_RAW_MIN_MAX "MS_KEY_RAW_DATA_MIN_MAX" -#define MS_KEY_CX1_MIN_MAX "MS_KEY_CX1_MIN_MAX" -#define MS_KEY_CX2_MAP_MIN "MS_KEY_CX2_MIN" -#define MS_KEY_CX2_MAP_MAX "MS_KEY_CX2_MAX" -#define MS_KEY_TOTAL_CX_MAP_MIN "MS_KEY_TOTAL_CX_MIN" -#define MS_KEY_TOTAL_CX_MAP_MAX "MS_KEY_TOTAL_CX_MAX" - -/* CONSTANT TOTAL IX */ -#define SS_IX1_FORCE_W "SS_IX1_FORCE_W" -#define SS_IX2_FORCE_W "SS_IX2_FORCE_W" -#define SS_IX1_SENSE_W "SS_IX1_SENSE_W" -#define SS_IX2_SENSE_W "SS_IX2_SENSE_W" - -#define SAVE_FLAG_RETRY 3 - -typedef struct { +#define LIMITS_FILE "stm_fts_production_limits.csv" + +#define WAIT_FOR_FRESH_FRAMES 100 //ms +#define WAIT_AFTER_SENSEOFF 50 //ms + +#define TIMEOUT_ITO_TEST_RESULT 200 //ms +#define TIMEOUT_INITIALIZATION_TEST_RESULT 5000 //ms + +//LABELS PRODUCTION TEST LIMITS FILE +#define MS_RAW_MIN_MAX "MS_RAW_DATA_MIN_MAX" +#define MS_RAW_GAP "MS_RAW_DATA_GAP" +#define MS_CX1_MIN_MAX "MS_TOUCH_ACTIVE_CX1_MIN_MAX" +#define MS_CX2_MAP_MIN "MS_TOUCH_ACTIVE_CX2_MIN" +#define MS_CX2_MAP_MAX "MS_TOUCH_ACTIVE_CX2_MAX" +#define MS_CX2_ADJH_MAP_MAX "MS_TOUCH_ACTIVE_CX2_ADJ_HORIZONTAL" +#define MS_CX2_ADJV_MAP_MAX "MS_TOUCH_ACTIVE_CX2_ADJ_VERTICAL" +#define MS_TOTAL_CX_MAP_MIN "MS_TOUCH_ACTIVE_TOTAL_CX_MIN" +#define MS_TOTAL_CX_MAP_MAX "MS_TOUCH_ACTIVE_TOTAL_CX_MAX" +#define MS_TOTAL_CX_ADJH_MAP_MAX "MS_TOUCH_ACTIVE_TOTAL_CX_ADJ_HORIZONTAL" +#define MS_TOTAL_CX_ADJV_MAP_MAX "MS_TOUCH_ACTIVE_TOTAL_CX_ADJ_VERTICAL" +#define SS_RAW_FORCE_MIN_MAX "SS_RAW_DATA_FORCE_MIN_MAX" +#define SS_RAW_SENSE_MIN_MAX "SS_RAW_DATA_SENSE_MIN_MAX" +#define SS_RAW_FORCE_GAP "SS_RAW_DATA_FORCE_GAP" +#define SS_RAW_SENSE_GAP "SS_RAW_DATA_SENSE_GAP" +#define SS_IX1_FORCE_MIN_MAX "SS_TOUCH_ACTIVE_IX1_FORCE_MIN_MAX" +#define SS_IX1_SENSE_MIN_MAX "SS_TOUCH_ACTIVE_IX1_SENSE_MIN_MAX" +#define SS_CX1_FORCE_MIN_MAX "SS_TOUCH_ACTIVE_CX1_FORCE_MIN_MAX" +#define SS_CX1_SENSE_MIN_MAX "SS_TOUCH_ACTIVE_CX1_SENSE_MIN_MAX" +#define SS_IX2_FORCE_MAP_MIN "SS_TOUCH_ACTIVE_IX2_FORCE_MIN" +#define SS_IX2_FORCE_MAP_MAX "SS_TOUCH_ACTIVE_IX2_FORCE_MAX" +#define SS_IX2_SENSE_MAP_MIN "SS_TOUCH_ACTIVE_IX2_SENSE_MIN" +#define SS_IX2_SENSE_MAP_MAX "SS_TOUCH_ACTIVE_IX2_SENSE_MAX" +#define SS_IX2_FORCE_ADJV_MAP_MAX "SS_TOUCH_ACTIVE_IX2_ADJ_VERTICAL" +#define SS_IX2_SENSE_ADJH_MAP_MAX "SS_TOUCH_ACTIVE_IX2_ADJ_HORIZONTAL" +#define SS_CX2_FORCE_MAP_MIN "SS_TOUCH_ACTIVE_CX2_FORCE_MIN" +#define SS_CX2_FORCE_MAP_MAX "SS_TOUCH_ACTIVE_CX2_FORCE_MAX" +#define SS_CX2_SENSE_MAP_MIN "SS_TOUCH_ACTIVE_CX2_SENSE_MIN" +#define SS_CX2_SENSE_MAP_MAX "SS_TOUCH_ACTIVE_CX2_SENSE_MAX" +#define SS_CX2_FORCE_ADJV_MAP_MAX "SS_TOUCH_ACTIVE_CX2_ADJ_VERTICAL" +#define SS_CX2_SENSE_ADJH_MAP_MAX "SS_TOUCH_ACTIVE_CX2_ADJ_HORIZONTAL" + +// TOTAL SS +#define SS_TOTAL_IX_FORCE_MAP_MIN "SS_TOUCH_ACTIVE_TOTAL_IX_FORCE_MIN" +#define SS_TOTAL_IX_FORCE_MAP_MAX "SS_TOUCH_ACTIVE_TOTAL_IX_FORCE_MAX" +#define SS_TOTAL_IX_SENSE_MAP_MIN "SS_TOUCH_ACTIVE_TOTAL_IX_SENSE_MIN" +#define SS_TOTAL_IX_SENSE_MAP_MAX "SS_TOUCH_ACTIVE_TOTAL_IX_SENSE_MAX" +#define SS_TOTAL_IX_FORCE_ADJV_MAP_MAX "SS_TOUCH_ACTIVE_TOTAL_IX_ADJ_VERTICAL" +#define SS_TOTAL_IX_SENSE_ADJH_MAP_MAX "SS_TOUCH_ACTIVE_TOTAL_IX_ADJ_HORIZONTAL" +#define SS_TOTAL_CX_FORCE_MAP_MIN "SS_TOUCH_ACTIVE_TOTAL_CX_FORCE_MIN" +#define SS_TOTAL_CX_FORCE_MAP_MAX "SS_TOUCH_ACTIVE_TOTAL_CX_FORCE_MAX" +#define SS_TOTAL_CX_SENSE_MAP_MIN "SS_TOUCH_ACTIVE_TOTAL_CX_SENSE_MIN" +#define SS_TOTAL_CX_SENSE_MAP_MAX "SS_TOUCH_ACTIVE_TOTAL_CX_SENSE_MAX" +#define SS_TOTAL_CX_FORCE_ADJV_MAP_MAX "SS_TOUCH_ACTIVE_TOTAL_CX_ADJ_VERTICAL" +#define SS_TOTAL_CX_SENSE_ADJH_MAP_MAX "SS_TOUCH_ACTIVE_TOTAL_CX_ADJ_HORIZONTAL" + +//KEYS +#define MS_KEY_RAW_MIN_MAX "MS_KEY_RAW_DATA_MIN_MAX" +#define MS_KEY_CX1_MIN_MAX "MS_KEY_CX1_MIN_MAX" +#define MS_KEY_CX2_MAP_MIN "MS_KEY_CX2_MIN" +#define MS_KEY_CX2_MAP_MAX "MS_KEY_CX2_MAX" +#define MS_KEY_TOTAL_CX_MAP_MIN "MS_KEY_TOTAL_CX_MIN" +#define MS_KEY_TOTAL_CX_MAP_MAX "MS_KEY_TOTAL_CX_MAX" + +//CONSTANT TOTAL IX +#define SS_IX1_FORCE_W "IX1_FORCE_W" +#define SS_IX2_FORCE_W "IX2_FORCE_W" +#define SS_IX1_SENSE_W "IX1_SENSE_W" +#define SS_IX2_SENSE_W "IX2_SENSE_W" + + +#define SAVE_FLAG_RETRY 3 + + +struct TestToDo { int MutualRaw; int MutualRawGap; int MutualCx1; @@ -125,13 +150,14 @@ typedef struct { int SelfSenseCxTotal; int SelfSenseCxTotalAdj; -} TestToDo; +}; int computeAdjHoriz(u8 *data, int row, int column, u8 **result); int computeAdjHorizTotal(u16 *data, int row, int column, u16 **result); int computeAdjVert(u8 *data, int row, int column, u8 **result); int computeAdjVertTotal(u16 *data, int row, int column, u16 **result); -int computeTotal(u8 *data, u8 main, int row, int column, int m, int n, u16 **result); +int computeTotal(u8 *data, u8 main, int row, int column, int m, + int n, u16 **result); int checkLimitsMinMax(short *data, int row, int column, int min, int max); int checkLimitsMap(u8 *data, int row, int column, int *min, int *max); int checkLimitsMapTotal(u16 *data, int row, int column, int *min, int *max); @@ -143,16 +169,24 @@ int ms_compensation_tuning(void); int ss_compensation_tuning(void); int lp_timer_calibration(void); int save_cx_tuning(void); -int production_test_splited_initialization(int saveToFlash); -int production_test_main(char *pathThresholds, int stop_on_fail, - int saveInit, TestToDo *todo, u32 signature); -int production_test_ms_raw(char *path_limits, int stop_on_fail, TestToDo *todo); -int production_test_ms_cx(char *path_limits, int stop_on_fail, TestToDo *todo); -int production_test_ss_raw(char *path_limits, int stop_on_fail, TestToDo *todo); -int production_test_ss_ix_cx(char *path_limits, int stop_on_fail, TestToDo *todo); -int production_test_data(char *path_limits, int stop_on_fail, TestToDo *todo); -int production_test_ms_key_cx(char *path_limits, int stop_on_fail, TestToDo *todo); +int production_test_split_initialization(int saveToFlash); +int production_test_main(char *pathThresholds, int stop_on_fail, int saveInit, + struct TestToDo *todo, u32 signature); +int production_test_ms_raw(char *path_limits, int stop_on_fail, + struct TestToDo *todo); +int production_test_ms_cx(char *path_limits, int stop_on_fail, + struct TestToDo *todo); +int production_test_ss_raw(char *path_limits, int stop_on_fail, + struct TestToDo *todo); +int production_test_ss_ix_cx(char *path_limits, int stop_on_fail, + struct TestToDo *todo); +int production_test_data(char *path_limits, int stop_on_fail, + struct TestToDo *todo); +int production_test_ms_key_cx(char *path_limits, int stop_on_fail, + struct TestToDo *todo); int production_test_ms_key_raw(char *path_limits); int save_mp_flag(u32 signature); -int parseProductionTestLimits(char *path, char *label, int **data, int *row, int *column); -int readLine(char *data, char **line, int size, int *n); +int parseProductionTestLimits(char *path, char *label, int **data, + int *row, int *column); +int readLine(char *data, char *line, int size, int *n); +#endif diff --git a/drivers/input/touchscreen/st/fts_lib/ftsTime.c b/drivers/input/touchscreen/st/fts_lib/ftsTime.c index 03a2a39fe10b..a2ec03a17c92 100644 --- a/drivers/input/touchscreen/st/fts_lib/ftsTime.c +++ b/drivers/input/touchscreen/st/fts_lib/ftsTime.c @@ -1,20 +1,36 @@ /* + * FTS Capacitive touch screen controller (FingerTipS) + * + * Copyright (C) 2016-2018, STMicroelectronics Limited. + * Authors: AMG(Analog Mems Group) + * + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + */ -************************************************************************** -** STMicroelectronics ** -************************************************************************** -** marco.cali@st.com ** -************************************************************************** -* * -* FTS Utility for mesuring/handling the time * -* * -************************************************************************** -************************************************************************** - -*/ - -#include "ftsCrossCompile.h" -#include "ftsTime.h" +/** + * + ************************************************************************** + ** STMicroelectronics ** + ************************************************************************** + ** marco.cali@st.com ** + ************************************************************************** + * * + * FTS Utility for mesuring/handling the time * + * * + ************************************************************************** + *************************************************************************** + */ #include #include @@ -40,38 +56,45 @@ #include #include #include -/* #include */ +//#include -void startStopWatch(StopWatch *w) +#include "ftsCrossCompile.h" +#include "ftsTime.h" + + +void startStopWatch(struct StopWatch *w) { w->start = current_kernel_time(); } -void stopStopWatch(StopWatch *w) +void stopStopWatch(struct StopWatch *w) { w->end = current_kernel_time(); } -int elapsedMillisecond(StopWatch *w) +int elapsedMillisecond(struct StopWatch *w) { int result; - result = ((w->end.tv_sec - w->start.tv_sec)*1000) + (w->end.tv_nsec - w->start.tv_nsec) / 1000000; + result = ((w->end.tv_sec - w->start.tv_sec) * 1000) + + (w->end.tv_nsec - w->start.tv_nsec) / 1000000; return result; } -int elapsedNanosecond(StopWatch *w) +int elapsedNanosecond(struct StopWatch *w) { int result; - result = ((w->end.tv_sec - w->start.tv_sec)*1000000000) + (w->end.tv_nsec - w->start.tv_nsec); + result = ((w->end.tv_sec - w->start.tv_sec) * 1000000000) + + (w->end.tv_nsec - w->start.tv_nsec); return result; } -char *timestamp(void) +char *timestamp() { char *result = NULL; - result = (char *)kmalloc((1)*sizeof(char), GFP_KERNEL); + + result = (char *)kmalloc_array(1, sizeof(char), GFP_KERNEL); if (result == NULL) return NULL; result[0] = ' '; @@ -80,5 +103,5 @@ char *timestamp(void) void stdelay(unsigned long ms) { - msleep(ms); + msleep(ms); } diff --git a/drivers/input/touchscreen/st/fts_lib/ftsTime.h b/drivers/input/touchscreen/st/fts_lib/ftsTime.h index 5eeca6eace97..2432cf7b266a 100644 --- a/drivers/input/touchscreen/st/fts_lib/ftsTime.h +++ b/drivers/input/touchscreen/st/fts_lib/ftsTime.h @@ -1,29 +1,53 @@ /* + * FTS Capacitive touch screen controller (FingerTipS) + * + * Copyright (C) 2016-2018, STMicroelectronics Limited. + * Authors: AMG(Analog Mems Group) + * + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + */ -************************************************************************** -** STMicroelectronics ** -************************************************************************** -** marco.cali@st.com ** -************************************************************************** -* * -* FTS Utility for mesuring/handling the time * -* * -************************************************************************** -************************************************************************** +/** + * + ************************************************************************** + ** STMicroelectronics ** + ************************************************************************** + ** marco.cali@st.com ** + ************************************************************************** + * * + * FTS Utility for mesuring/handling the time * + * * + ************************************************************************** + ************************************************************************** + * + */ -*/ - -#include "ftsCrossCompile.h" +#ifndef __FTS_TIME_H +#define __FTS_TIME_H #include -typedef struct { +#include "ftsCrossCompile.h" + +struct StopWatch { struct timespec start, end; -} StopWatch; +}; -void startStopWatch(StopWatch *w); -void stopStopWatch(StopWatch *w); -int elapsedMillisecond(StopWatch *w); -int elapsedNanosecond(StopWatch *w); +void startStopWatch(struct StopWatch *w); +void stopStopWatch(struct StopWatch *w); +int elapsedMillisecond(struct StopWatch *w); +int elapsedNanosecond(struct StopWatch *w); char *timestamp(void); void stdelay(unsigned long ms); +#endif diff --git a/drivers/input/touchscreen/st/fts_lib/ftsTool.c b/drivers/input/touchscreen/st/fts_lib/ftsTool.c index 4c5d54f17ea7..a5b4c01fc312 100644 --- a/drivers/input/touchscreen/st/fts_lib/ftsTool.c +++ b/drivers/input/touchscreen/st/fts_lib/ftsTool.c @@ -1,27 +1,37 @@ /* - -************************************************************************** -** STMicroelectronics ** -************************************************************************** -** marco.cali@st.com ** -************************************************************************** -* * -* FTS Utility Functions * -* * -************************************************************************** -************************************************************************** - -*/ - -#include "ftsCompensation.h" -#include "ftsCrossCompile.h" -#include "ftsError.h" -#include "ftsHardware.h" -#include "ftsIO.h" -#include "ftsSoftware.h" -#include "ftsTime.h" -#include "ftsTool.h" -#include "../fts.h" /* needed for the PHONE_KEY define */ + * FTS Capacitive touch screen controller (FingerTipS) + * + * Copyright (C) 2016-2018, STMicroelectronics Limited. + * Authors: AMG(Analog Mems Group) + * + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + */ + +/** + * + ************************************************************************** + ** STMicroelectronics ** + ************************************************************************** + ** marco.cali@st.com ** + ************************************************************************** + * * + * FTS Utility Functions * + * * + ************************************************************************** + ************************************************************************** + * + */ #include #include @@ -44,11 +54,21 @@ #include #include -/* static char tag[8]="[ FTS ]\0"; */ +#include "ftsCompensation.h" +#include "ftsCrossCompile.h" +#include "ftsError.h" +#include "ftsHardware.h" +#include "ftsIO.h" +#include "ftsSoftware.h" +#include "ftsTime.h" +#include "ftsFlash.h" +#include "ftsTool.h" +#include "../fts.h" + +static char tag[8] = "[ FTS ]\0"; static int reset_gpio = GPIO_NOT_DEFINED; static int system_resetted_up; static int system_resetted_down; -extern chipInfo ftsInfo; int readB2(u16 address, u8 *outBuf, int len) { @@ -57,73 +77,81 @@ int readB2(u16 address, u8 *outBuf, int len) int retry = 0; int ret; int event_to_search[3]; - u8 *readEvent = (u8 *)kmalloc(FIFO_EVENT_SIZE*sizeof(u8), GFP_KERNEL); - u8 cmd[4] = { FTS_CMD_REQU_FW_CONF, 0x00, 0x00, (u8)len }; + char *temp = NULL; + u8 *init_outBuf = outBuf; + u16 init_addr = address; + u8 readEvent[FIFO_EVENT_SIZE] = {0}; + u8 cmd[4] = { FTS_CMD_REQU_FW_CONF, 0x00, 0x00, (u8)len }; if (readEvent == NULL) { - logError(1, "%s readB2: ERROR %02X\n", tag, ERROR_ALLOC); + logError(1, "%s %s:ERROR %02X\n", tag, __func__, ERROR_ALLOC); return ERROR_ALLOC; } - - u16ToU8_be(address, &cmd[1]); - - logError(0, "%s %s", tag, printHex("Command B2 = ", cmd, 4)); - do { - remaining = len; - ret = fts_writeFwCmd(cmd, 4); - if (ret < 0) { - logError(1, "%s readB2: ERROR %02X\n", tag, ERROR_I2C_W); - return ret; - } /* ask to the FW the data */ - logError(0, "%s Command to FW sent!\n", tag); - event_to_search[0] = (int)EVENTID_FW_CONFIGURATION; - - while (remaining > OK) { - event_to_search[1] = (int)((address & 0xFF00)>>8); - event_to_search[2] = (int) (address & 0x00FF); - if (remaining > B2_DATA_BYTES) { - toRead = B2_DATA_BYTES; - remaining -= B2_DATA_BYTES; - } else { - toRead = remaining; - remaining = 0; - } - - ret = pollForEvent(event_to_search, 3, readEvent, GENERAL_TIMEOUT); - if (ret >= OK) { /* start the polling for reading the reply */ - memcpy(outBuf, &readEvent[3], toRead); - retry = 0; - outBuf += toRead; - - } else { - retry += 1; - break; - } - address += B2_DATA_BYTES; + u16ToU8_be(address, &cmd[1]); + temp = printHex("Command B2 = ", cmd, 4); + if (temp != NULL) + logError(0, "%s %s", tag, temp); + kfree(temp); + do { + remaining = len; + ret = fts_writeFwCmd(cmd, 4); + if (ret < 0) { + logError(1, "%s %s: ERROR %02X\n", + tag, __func__, ERROR_I2C_W); + return ret; + } + //ask to the FW the data + logError(0, "%s Command to FW sent!\n", tag); + event_to_search[0] = (int)EVENTID_FW_CONFIGURATION; + while (remaining > OK) { + event_to_search[1] = (int)((address & 0xFF00) >> 8); + event_to_search[2] = (int)(address & 0x00FF); + if (remaining > B2_DATA_BYTES) { + toRead = B2_DATA_BYTES; + remaining -= B2_DATA_BYTES; + } else { + toRead = remaining; + remaining = 0; } - } while (retry < B2_RETRY && retry != 0); - - kfree(readEvent); - if (retry == B2_RETRY) { - logError(1, "%s readB2: ERROR %02X\n", tag, ERROR_TIMEOUT); - return ERROR_TIMEOUT; + ret = pollForEvent(event_to_search, 3, + readEvent, GENERAL_TIMEOUT); + if (ret >= OK) { + //start the polling for reading the reply + memcpy(outBuf, &readEvent[3], toRead); + retry = 0; + outBuf += toRead; + } else { + retry += 1; + break; + } + address += B2_DATA_BYTES; } - logError(0, "%s B2 read %d bytes\n", tag, len); + logError(0, "%s %s:B2 failed...attempt = %d\n", + tag, __func__, retry); + outBuf = init_outBuf; + address = init_addr; + } while (retry < B2_RETRY && retry != 0); + + if (retry == B2_RETRY) { + logError(1, "%s %s:ERROR %02X\n", tag, __func__, ERROR_TIMEOUT); + return ERROR_TIMEOUT; + } + logError(0, "%s B2 read %d bytes\n", tag, len); - return OK; + return OK; } int readB2U16(u16 address, u8 *outBuf, int byteToRead) { - int remaining = byteToRead; int toRead = 0; int ret; - u8 *buff = (u8 *)kmalloc((B2_CHUNK + 1)*sizeof(u8), GFP_KERNEL); + u8 *buff = (u8 *)kmalloc_array((B2_CHUNK + 1), sizeof(u8), GFP_KERNEL); + if (buff == NULL) { - logError(1, "%s readB2U16: ERROR %02X\n", tag, ERROR_ALLOC); + logError(1, "%s %s: ERROR %02X\n", tag, __func__, ERROR_ALLOC); return ERROR_ALLOC; } @@ -137,20 +165,19 @@ int readB2U16(u16 address, u8 *outBuf, int byteToRead) } ret = readB2(address, buff, toRead); - if (ret < 0) + if (ret < 0) { + kfree(buff); return ret; + } memcpy(outBuf, buff, toRead); - address += toRead; - outBuf += toRead; - } - kfree(buff); return OK; } + int releaseInformation(void) { int ret; @@ -160,24 +187,475 @@ int releaseInformation(void) event_to_search[0] = (int)EVENTID_RELEASE_INFO; - logError(0, "%s releaseInformation started... Chip INFO:\n", tag); + logError(0, "%s %s: started... Chip INFO:\n", tag, __func__); ret = fts_writeFwCmd(cmd, 1); if (ret < OK) { - logError(1, "%s releaseInformation: ERROR %02X\n", tag, ret); + logError(1, "%s %s: ERROR %02X\n", tag, __func__, ret); return ret; } - ret = pollForEvent(event_to_search, 1, &readEvent[0], RELEASE_INFO_TIMEOUT); - /* start the polling for reading the reply */ + ret = pollForEvent(event_to_search, 1, &readEvent[0], + RELEASE_INFO_TIMEOUT); + //start the polling for reading the reply if (ret < OK) { - logError(1, "%s releaseInformation: ERROR %02X\n", tag, ret); + logError(1, "%s %s: ERROR %02X\n", tag, __func__, ret); return ret; } - logError(0, "%s releaseInformation: Finished!\n", tag, ret); + logError(0, "%s %s: Finished! %d\n", tag, __func__, ret); + return OK; +} + +int lockDownInfo(u8 *data) +{ + int ret; + int i = 0, num_event; + u8 cmd[1] = { FTS_CMD_LOCKDOWN_CMD }; + int event_to_search[3] = {EVENTID_LOCKDOWN_INFO, + EVENT_TYPE_LOCKDOWN, 0x00}; + u8 readEvent[FIFO_EVENT_SIZE]; + + + logError(0, "%s %s:started...\n", tag, __func__); + + ret = fts_writeFwCmd(cmd, 1); + if (ret < OK) { + logError(1, "%s %s:ERROR %02X\n", tag, __func__, ret); + return ret; + } + + + if (LOCKDOWN_CODE_SIZE <= 4) + num_event = 1; + else if (LOCKDOWN_CODE_SIZE % 4 == 0) + num_event = LOCKDOWN_CODE_SIZE / 4; + else + num_event = (LOCKDOWN_CODE_SIZE) / 4 + 1; + + logError(0, "%s %s:num_event = %d\n", tag, __func__, num_event); + for (i = 0; i < num_event; i++) { + ret = pollForEvent(event_to_search, 3, + &readEvent[0], GENERAL_TIMEOUT); + //start the polling for reading the reply + if (ret < OK) { + logError(1, "%s %s:ERROR %02X\n", tag, __func__, ret); + return ret; + } + data[i * 4] = readEvent[3]; + data[i * 4 + 1] = readEvent[4]; + data[i * 4 + 2] = readEvent[5]; + data[i * 4 + 3] = readEvent[6]; + event_to_search[2] += 4; + //logError(0, "%02X %02X %02X %02X ", readEvent[3], + //readEvent[4], readEvent[5], readEvent[6]); + } + + logError(0, "%s %s:Finished! %d\n", tag, __func__, ret); return OK; +} + + +int calculateCRC8(u8 *u8_srcBuff, int size, u8 *crc) +{ + u8 u8_remainder; + u8 bit; + int i = 0; + + u8_remainder = 0x00; + logError(0, "%s %s: Start CRC computing...\n", tag, __func__); + + if (size == 0 || u8_srcBuff == NULL) { + logError(1, "Arguments passed not valid!"); + logError(1, "%s %s:Data pointer = NULL ", tag, __func__); + logError(1, "or size = 0 (%d) ERROR %08X\n", + size, ERROR_OP_NOT_ALLOW); + return ERROR_OP_NOT_ALLOW; + } + // Perform modulo-2 division, a byte at a time. + //Bring the next byte into the remainder. + for (i = 0; i < size; i++) { + //Perform modulo-2 division, a bit at a time. + u8_remainder ^= u8_srcBuff[i]; + //Try to divide the current data bit. + for (bit = 8; bit > 0; --bit) { + if (u8_remainder & (0x1 << 7)) + u8_remainder = (u8_remainder << 1) ^ 0x9B; + else + u8_remainder = (u8_remainder << 1); + } + } //The final remainder is the CRC result. + *crc = u8_remainder; + logError(0, "%s %s: CRC value = %02X\n", tag, __func__, *crc); + return OK; +} + +int writeLockDownInfo(u8 *data, int size) +{ + int ret, i, toWrite, retry = 0, offset = size; + u8 cmd[2 + LOCKDOWN_CODE_WRITE_CHUNK] = {FTS_CMD_LOCKDOWN_FILL, 0x00}; + u8 crc = 0; + int event_to_search[2] = {EVENTID_STATUS_UPDATE, + EVENT_TYPE_LOCKDOWN_WRITE}; + u8 readEvent[FIFO_EVENT_SIZE]; + char *temp = NULL; + + logError(0, "%s %s: Writing Lockdown code into the IC...\n", + tag, __func__); + + ret = fts_disableInterrupt(); + if (ret < OK) { + logError(1, "%s %s: ERROR %08X\n", tag, __func__, ret); + ret = (ret | ERROR_LOCKDOWN_CODE); + goto ERROR; + } + if (size > LOCKDOWN_CODE_MAX_SIZE) { + logError(1, "%s %s: Lockdown data to write too big! ", + tag, __func__); + logError(1, "%d>%d ERROR %08X\n", + size, LOCKDOWN_CODE_MAX_SIZE, ret); + ret = (ERROR_OP_NOT_ALLOW | ERROR_LOCKDOWN_CODE); + goto ERROR; + } + + temp = printHex("Lockdown Code = ", data, size); + if (temp != NULL) { + logError(0, "%s %s: %s", tag, __func__, temp); + kfree(temp); + } + + for (retry = 0; retry < LOCKDOWN_CODE_RETRY; retry++) { + logError(0, "%s %s: Filling FW buffer...\n", tag, __func__); + i = 0; + offset = size; + cmd[0] = FTS_CMD_LOCKDOWN_FILL; + while (offset > 0) { + if (offset > LOCKDOWN_CODE_WRITE_CHUNK) + toWrite = LOCKDOWN_CODE_WRITE_CHUNK; + else + toWrite = offset; + memcpy(&cmd[2], &data[i], toWrite); + cmd[1] = i; + + temp = printHex("Commmand = ", cmd, 2 + toWrite); + if (temp != NULL) { + logError(0, "%s %s: %s", tag, __func__, temp); + kfree(temp); + } + ret = fts_writeFwCmd(cmd, 2 + toWrite); + if (ret < OK) { + logError(1, "Unable to write Lockdown data "); + logError(1, "%s %s:Lockdown data at %d ", + tag, __func__, i); + logError(1, "iteration.%08X\n", ret); + ret = (ret | ERROR_LOCKDOWN_CODE); + continue; + } + i += toWrite;//update the offset + offset -= toWrite; + } + logError(0, "%s %s: Compute 8bit CRC...\n", tag, __func__); + ret = calculateCRC8(data, size, &crc); + if (ret < OK) { + logError(1, "%s %s:Unable to compute CRC..ERROR %08X\n", + tag, __func__, ret); + ret = (ret | ERROR_LOCKDOWN_CODE); + continue; + } + cmd[0] = FTS_CMD_LOCKDOWN_WRITE; + cmd[1] = 0x00; + cmd[2] = (u8)size; + cmd[3] = crc; + logError(0, "%s %s: Write Lockdown data...\n", + tag, __func__); + temp = printHex("Commmand = ", cmd, 4); + if (temp != NULL) { + logError(0, "%s %s: %s", tag, __func__, temp); + kfree(temp); + } + ret = fts_writeFwCmd(cmd, 4); + if (ret < OK) { + logError(1, "%s%s:Unable to send Lockdown data ", + tag, __func__); + logError(1, "write command%08X\n", ret); + ret = (ret | ERROR_LOCKDOWN_CODE); + continue; + } + + ret = pollForEvent(event_to_search, + 2, + &readEvent[0], + GENERAL_TIMEOUT); + //start the polling for reading the reply + + if (ret < OK) { + logError(1, "%s%s:Cann't find lockdown code ", + tag, __func__); + logError(1, "%write reply %08X\n", ret); + continue; + } + + if (readEvent[2] != 0x00) { + logError(1, "%s %s:Event check FAIL!%02X != 0x00 ", + tag, __func__, readEvent[2]); + logError(1, "%ERR%08X\n", ERROR_LOCKDOWN_CODE); + ret = ERROR_LOCKDOWN_CODE; + continue; + } else { + logError(0, "%s %s:Lockdown Code write DONE!\n", + tag, __func__); + ret = OK; + break; + } + } + +ERROR: + //ret = fts_enableInterrupt(); + //ensure that the interrupt are always renabled when exit from funct + if (fts_enableInterrupt() < OK) { + logError(1, "%s %s: Error while re-enabling the interrupt!\n", + tag, __func__); + } + return ret; +} + +int rewriteLockDownInfo(u8 *data, int size) +{ + int ret, i, toWrite, retry = 0, offset = size; + u8 cmd[2 + LOCKDOWN_CODE_WRITE_CHUNK] = {FTS_CMD_LOCKDOWN_FILL, 0x00}; + u8 crc = 0; + int event_to_search[2] = {EVENTID_STATUS_UPDATE, + EVENT_TYPE_LOCKDOWN_WRITE}; + u8 readEvent[FIFO_EVENT_SIZE]; + char *temp = NULL; + + logError(0, "%s %s: ReWriting Lockdown code into the IC start ...\n", + tag, __func__); + + ret = fts_disableInterrupt(); + if (ret < OK) { + logError(1, "%s %s: ERROR %08X\n", tag, __func__, ret); + ret = (ret | ERROR_LOCKDOWN_CODE); + goto ERROR; + } + if (size > LOCKDOWN_CODE_MAX_SIZE) { + logError(1, "%s %s: Lockdown data to write too big! ", + tag, __func__); + logError(1, "%d>%d ERROR %08X\n", + size, LOCKDOWN_CODE_MAX_SIZE, ret); + ret = (ERROR_OP_NOT_ALLOW | ERROR_LOCKDOWN_CODE); + goto ERROR; + } + + temp = printHex("Lockdown Code = ", data, size); + if (temp != NULL) { + logError(0, "%s %s: %s", tag, __func__, temp); + kfree(temp); + } + + for (retry = 0; retry < LOCKDOWN_CODE_RETRY; retry++) { + logError(0, "%s %s: Filling FW buffer ...\n", tag, __func__); + i = 0; + offset = size; + cmd[0] = FTS_CMD_LOCKDOWN_FILL; + while (offset > 0) { + if (offset > LOCKDOWN_CODE_WRITE_CHUNK) + toWrite = LOCKDOWN_CODE_WRITE_CHUNK; + else + toWrite = offset; + memcpy(&cmd[2], &data[i], toWrite); + cmd[1] = i; + temp = printHex("Commmand = ", cmd, 2 + toWrite); + if (temp != NULL) { + logError(0, "%s %s: %s", tag, __func__, temp); + kfree(temp); + } + ret = fts_writeFwCmd(cmd, 2 + toWrite); + if (ret < OK) { + logError(1, "Unable to rewrite Lockdown data"); + logError(1, "%s %s: at %d iteration ", + tag, __func__, i); + logError(1, "ERROR %08X\n", ret); + ret = (ret | ERROR_LOCKDOWN_CODE); + continue; + } + i += toWrite;//update the offset + offset -= toWrite; + } + logError(0, "%s %s: Compute 8bit CRC...\n", tag, __func__); + ret = calculateCRC8(data, size, &crc); + if (ret < OK) { + logError(1, "%s %s:Unable to compute CRC.. ", + tag, __func__); + logError(1, "ERROR %08X\n", ret); + ret = (ret | ERROR_LOCKDOWN_CODE); + continue; + } + cmd[0] = FTS_CMD_LOCKDOWN_WRITE; + cmd[1] = 0x01; + cmd[2] = (u8)size; + cmd[3] = crc; + + temp = printHex("Commmand = ", cmd, 4); + if (temp != NULL) { + logError(0, "%s %s: %s", tag, __func__, temp); + kfree(temp); + } + logError(0, "%s %s: ReWrite Lockdown data...\n", tag, __func__); + ret = fts_writeFwCmd(cmd, 4); + if (ret < OK) { + logError(1, "Unable to send Lockdown data"); + logError(1, "%s %s:rewrite command... ERROR %08X\n", + tag, __func__, ret); + ret = (ret | ERROR_LOCKDOWN_CODE); + continue; + } + + //start the polling for reading the reply + ret = pollForEvent(event_to_search, 2, + &readEvent[0], GENERAL_TIMEOUT); + if (ret >= OK) { + if (readEvent[2] < 0x00) { + logError(1, "%s %s:Event check FAIL! ", + tag, __func__); + logError(1, "%02X != 0x00 %08X\n", + readEvent[2], ERROR_LOCKDOWN_CODE); + ret = ERROR_LOCKDOWN_CODE; + continue; + } else { + logError(0, "%s %s: Lockdown Code ", + tag, __func__); + logError(0, "rewrite DONE!\n"); + ret = OK; + break; + } + } else { + logError(1, "Can not find lockdown code write "); + logError(1, "reply event!%s %s: ERROR %08X\n", + tag, __func__, ret); + } + } +ERROR: + //ret = fts_enableInterrupt(); + //ensure that the interrupt are always renabled when exit from funct + if (fts_enableInterrupt() < OK) { + logError(1, "%s %s: Error while re-enabling the interrupt!\n", + tag, __func__); + } + return ret; +} + +int readLockDownInfo(u8 *lockData, int *size) +{ + int ret, retry = 0, toRead = 0, byteToRead; + u8 cmd = FTS_CMD_LOCKDOWN_READ; + int event_to_search[3] = {EVENTID_LOCKDOWN_INFO_READ, -1, 0x00}; + u8 readEvent[FIFO_EVENT_SIZE]; + char *temp = NULL; + + lockData = NULL; + logError(0, "%s %s: Reading Lockdown code from the IC...\n", + tag, __func__); + + ret = fts_disableInterrupt(); + if (ret < OK) { + logError(1, "%s %s: ERROR %08X\n", tag, __func__, ret); + ret = (ret | ERROR_LOCKDOWN_CODE); + goto ERROR; + } + for (retry = 0; retry < LOCKDOWN_CODE_RETRY; retry++) { + event_to_search[2] = 0x00; + logError(0, "%s %s: Read Lockdown data.(%d attempt)\n", + tag, __func__, retry + 1); + ret = fts_writeFwCmd(&cmd, 1); + + if (ret < OK) { + logError(1, "%s%s:Unable to send Lockdown data ", + tag, __func__); + logError(1, "write CMD %08X\n", ret); + ret = (ret | ERROR_LOCKDOWN_CODE); + continue; + } + + //start the polling for reading the reply + ret = pollForEvent(event_to_search, 3, + &readEvent[0], GENERAL_TIMEOUT); + + if (ret < OK) { + logError(1, "Cann't find first lockdown code read"); + logError(1, "%s %s:reply event! ERROR %08X\n", + tag, __func__, ret); + continue; + } + + byteToRead = readEvent[1]; + *size = byteToRead; + logError(0, "%s %s:Lockdown Code size = %d\n", + tag, __func__, *size); + lockData = (u8 *)kmalloc_array((byteToRead), + sizeof(u8), GFP_KERNEL); + if (lockData == NULL) { + logError(1, "%s %s:Unable to allocate lockData %08X\n", + tag, __func__, ERROR_ALLOC); + ret = (ERROR_ALLOC | ERROR_LOCKDOWN_CODE); + continue; + } + while (byteToRead > 0) { + if ((readEvent[1] - readEvent[2]) + > LOCKDOWN_CODE_READ_CHUNK) { + toRead = LOCKDOWN_CODE_READ_CHUNK; + } else { + toRead = readEvent[1] - readEvent[2]; + } + byteToRead -= toRead; + memcpy(&lockData[readEvent[2]], + &readEvent[3], toRead); + event_to_search[2] += toRead; + if (byteToRead <= 0) + continue; + + ret = pollForEvent(event_to_search, + 3, + &readEvent[0], + GENERAL_TIMEOUT); + + //start polling for reading reply + if (ret < OK) { + logError(1, "Can not find lockdow"); + logError(1, "code read reply event "); + logError(1, "%s%s:offset%02X%08X\n", + tag, __func__, event_to_search[2], ret); + ret = (ERROR_ALLOC | ERROR_LOCKDOWN_CODE); + break; + } + } + if (byteToRead != 0) { + logError(1, "%s %s:Read Lockdown code FAIL! ", + tag, __func__); + logError(1, "ERROR %08X\n", ret); + continue; + } else { + logError(0, "%s %s: Lockdown Code read DONE!\n", + tag, __func__); + ret = OK; + temp = printHex("Lockdown Code = ", lockData, *size); + if (temp != NULL) { + logError(0, "%s %s: %s", tag, __func__, temp); + kfree(temp); + } + break; + } + } +ERROR: + //ret = fts_enableInterrupt(); + //ensure that the interrupt are always + //renabled when exit from funct + if (fts_enableInterrupt() < OK) { + logError(1, "%s %s:Error while re-enabling the interrupt!\n", + tag, __func__); + } + return ret; } char *printHex(char *label, u8 *buff, int count) @@ -186,24 +664,24 @@ char *printHex(char *label, u8 *buff, int count) char *result = NULL; offset = strlen(label); - result = (char *)kmalloc(((offset + 3 * count) + 1)*sizeof(char), GFP_KERNEL); + result = (char *)kmalloc_array(((offset + 3 * count) + 1), + sizeof(char), GFP_KERNEL); if (result != NULL) { strlcpy(result, label, sizeof(result)); - - for (i = 0; i < count; i++) { + for (i = 0; i < count; i++) snprintf(&result[offset + i * 3], 4, "%02X ", buff[i]); - } strlcat(result, "\n", sizeof(result)); } return result; } -int pollForEvent(int *event_to_search, int event_bytes, u8 *readData, int time_to_wait) +int pollForEvent(int *event_to_search, int event_bytes, + u8 *readData, int time_to_wait) { int i, find, retry, count_err; int time_to_count; int err_handling = OK; - StopWatch clock; + struct StopWatch clock; u8 cmd[1] = { FIFO_CMD_READONE }; char *temp = NULL; @@ -214,32 +692,46 @@ int pollForEvent(int *event_to_search, int event_bytes, u8 *readData, int time_t time_to_count = time_to_wait / TIMEOUT_RESOLUTION; startStopWatch(&clock); - while (find != 1 && retry < time_to_count && fts_readCmd(cmd, 1, readData, FIFO_EVENT_SIZE) >= 0) { - /* Log of errors */ + while (find != 1 && retry < time_to_count + && fts_readCmd(cmd, 1, readData, FIFO_EVENT_SIZE) >= 0) { + if (readData[0] == EVENTID_ERROR_EVENT) { - logError(1, "%s %s", tag, printHex("ERROR EVENT = ", readData, FIFO_EVENT_SIZE)); + temp = printHex("ERROR EVENT = ", + readData, FIFO_EVENT_SIZE); + if (temp != NULL) + logError(1, "%s %s", tag, temp); + kfree(temp); count_err++; err_handling = errorHandler(readData, FIFO_EVENT_SIZE); - if ((err_handling&0xF0FF0000) == ERROR_HANDLER_STOP_PROC) { - logError(1, "%s pollForEvent: forced to be stopped! ERROR %08X\n", tag, err_handling); + if ((err_handling & 0xF0FF0000) + == ERROR_HANDLER_STOP_PROC) { + logError(1, "%s %s: forced to be stopped! ", + tag, __func__); + logError(1, "ERROR %08X\n", err_handling); return err_handling; } } else { if (readData[0] != EVENTID_NO_EVENT) { - logError(1, "%s %s", tag, printHex("READ EVENT = ", readData, FIFO_EVENT_SIZE)); + temp = printHex("READ EVENT = ", + readData, FIFO_EVENT_SIZE); + if (temp != NULL) + logError(1, "%s %s", tag, temp); + kfree(temp); } - if (readData[0] == EVENTID_CONTROL_READY && event_to_search[0] != EVENTID_CONTROL_READY) { - logError(1, "%s pollForEvent: Unmanned Controller Ready Event! Setting reset flags...\n", tag); + if (readData[0] == EVENTID_CONTROL_READY && + event_to_search[0] != EVENTID_CONTROL_READY) { + logError(1, "Unmanned Controller Ready Event!"); + logError(1, "%s %s:Setting reset flags...\n", + tag, __func__); setSystemResettedUp(1); - setSystemResettedDown(1); + setSystemResettedDown(1); } } - find = 1; for (i = 0; i < event_bytes; i++) { - - if (event_to_search[i] != -1 && (int)readData[i] != event_to_search[i]) { + if (event_to_search[i] != -1 + && (int)readData[i] != event_to_search[i]) { find = 0; break; } @@ -250,53 +742,60 @@ int pollForEvent(int *event_to_search, int event_bytes, u8 *readData, int time_t } stopStopWatch(&clock); if ((retry >= time_to_count) && find != 1) { - logError(1, "%s pollForEvent: ERROR %02X\n", tag, ERROR_TIMEOUT); + logError(1, "%s %s: ERROR %02X\n", + tag, __func__, ERROR_TIMEOUT); return ERROR_TIMEOUT; - } else if (find == 1) { + } + if (find == 1) { temp = printHex("FOUND EVENT = ", readData, FIFO_EVENT_SIZE); if (temp != NULL) logError(0, "%s %s", tag, temp); kfree(temp); - logError(0, "%s Event found in %d ms (%d iterations)! Number of errors found = %d\n", tag, elapsedMillisecond(&clock), retry, count_err); + logError(0, "%s Event found in %d ms (%d iterations)!\n", + tag, elapsedMillisecond(&clock), retry); + logError(0, "Number of errors found = %d\n", count_err); return count_err; } - logError(1, "%s pollForEvent: ERROR %02X\n", tag, ERROR_I2C_R); + logError(1, "%s %s: ERROR %02X\n", tag, __func__, ERROR_I2C_R); return ERROR_I2C_R; } int flushFIFO(void) { + u8 cmd = FIFO_CMD_FLUSH; - u8 cmd = FIFO_CMD_FLUSH; /* flush the FIFO */ if (fts_writeCmd(&cmd, 1) < 0) { - logError(1, "%s flushFIFO: ERROR %02X\n", tag, ERROR_I2C_W); + logError(1, "%s %s: ERROR %02X\n", tag, __func__, ERROR_I2C_W); return ERROR_I2C_W; } logError(0, "%s FIFO flushed!\n", tag); return OK; - } int fts_disableInterrupt(void) { - u8 cmd[4] = { FTS_CMD_HW_REG_W, 0x00, 0x00, IER_DISABLE }; /* disable interrupt */ + //disable interrupt + u8 cmd[4] = { FTS_CMD_HW_REG_W, 0x00, 0x00, IER_DISABLE }; + u16ToU8_be(IER_ADDR, &cmd[1]); if (fts_writeCmd(cmd, 4) < OK) { - logError(1, "%s fts_disableInterrupt: ERROR %02X\n", tag, ERROR_I2C_W); + logError(1, "%s %s: ERROR %02X\n", tag, __func__, ERROR_I2C_W); return ERROR_I2C_W; } logError(0, "%s Interrupt Disabled!\n", tag); return OK; } + int fts_enableInterrupt(void) { - u8 cmd[4] = { FTS_CMD_HW_REG_W, 0x00, 0x00, IER_ENABLE }; /* enable interrupt */ + u8 cmd[4] = { FTS_CMD_HW_REG_W, 0x00, 0x00, IER_ENABLE }; + u16ToU8_be(IER_ADDR, &cmd[1]); - if (fts_writeCmd(cmd, 4) < 0) { - logError(1, "%s fts_enableInterrupt: ERROR %02X\n", tag, ERROR_I2C_W); + if (fts_writeCmd(cmd, 4) < 0) { + logError(1, "%s %s: ERROR %02X\n", tag, __func__, ERROR_I2C_W); return ERROR_I2C_W; } logError(0, "%s Interrupt Enabled!\n", tag); @@ -307,11 +806,12 @@ int u8ToU16n(u8 *src, int src_length, u16 *dst) { int i, j; - if (src_length % 2 != 0) { - return 0; - } + if (src_length % 2 != 0) + return -EINVAL; + j = 0; - dst = (u16 *)kmalloc((src_length / 2)*sizeof(u16), GFP_KERNEL); + dst = (u16 *)kmalloc_array((src_length / 2), sizeof(u16), GFP_KERNEL); + for (i = 0; i < src_length; i += 2) { dst[j] = ((src[i+1] & 0x00FF) << 8) + (src[i] & 0x00FF); j++; @@ -335,16 +835,16 @@ int u8ToU16_le(u8 *src, u16 *dst) int u16ToU8n(u16 *src, int src_length, u8 *dst) { int i, j; - dst = (u8 *)kmalloc((2 * src_length)*sizeof(u8), GFP_KERNEL); + + dst = (u8 *)kmalloc_array(2 * src_length, sizeof(u8), GFP_KERNEL); j = 0; for (i = 0; i < src_length; i++) { - dst[j] = (u8) (src[i] & 0xFF00)>>8; + dst[j] = (u8) (src[i] & 0xFF00) >> 8; dst[j+1] = (u8) (src[i] & 0x00FF); j += 2; } return src_length * 2; - } int u16ToU8(u16 src, u8 *dst) @@ -370,7 +870,8 @@ int u16ToU8_le(u16 src, u8 *dst) int u8ToU32(u8 *src, u32 *dst) { - *dst = (u32)(((src[3] & 0x000000FF) << 24) + ((src[2] & 0x000000FF) << 16) + ((src[1] & 0x000000FF) << 8) + (src[0] & 0x000000FF)); + *dst = (u32)(((src[3] & 0xFF) << 24) + ((src[2] & 0xFF) << 16) + + ((src[1] & 0xFF) << 8) + (src[0] & 0xFF)); return 0; } @@ -383,7 +884,8 @@ int u32ToU8(u32 src, u8 *dst) return 0; } -int attempt_function(int(*code)(void), unsigned long wait_before_retry, int retry_count) +int attempt_function(int(*code)(void), unsigned long wait_before_retry, + int retry_count) { int result; int count = 0; @@ -395,16 +897,15 @@ int attempt_function(int(*code)(void), unsigned long wait_before_retry, int retr } while (count < retry_count && result < 0); if (count == retry_count) - return (result | ERROR_TIMEOUT); - else - return result; + result |= ERROR_TIMEOUT; + return result; } void setResetGpio(int gpio) { reset_gpio = gpio; - logError(1, "%s setResetGpio: reset_gpio = %d\n", tag, reset_gpio); + logError(1, "%s %s: reset_gpio = %d\n", tag, __func__, reset_gpio); } int fts_system_reset(void) @@ -414,38 +915,46 @@ int fts_system_reset(void) int res = -1; int i; u8 cmd[4] = { FTS_CMD_HW_REG_W, 0x00, 0x00, SYSTEM_RESET_VALUE }; + event_to_search = (int)EVENTID_CONTROL_READY; u16ToU8_be(SYSTEM_RESET_ADDRESS, &cmd[1]); logError(0, "%s System resetting...\n", tag); for (i = 0; i < SYSTEM_RESET_RETRY && res < 0; i++) { - if (reset_gpio == GPIO_NOT_DEFINED) { +#ifndef FTM3_CHIP + res |= fts_warm_boot(); +#endif res = fts_writeCmd(cmd, 4); } else { gpio_set_value(reset_gpio, 0); - msleep(10); + msleep(20); gpio_set_value(reset_gpio, 1); res = OK; } if (res < OK) { - logError(1, "%s fts_system_reset: ERROR %02X\n", tag, ERROR_I2C_W); + logError(1, "%s %s:ERROR %02X\n", + tag, __func__, ERROR_I2C_W); } else { - res = pollForEvent(&event_to_search, 1, readData, GENERAL_TIMEOUT); + res = pollForEvent(&event_to_search, 1, + readData, GENERAL_TIMEOUT); if (res < OK) { - logError(1, "%s fts_system_reset: ERROR %02X\n", tag, res); + logError(1, "%s %s: ERROR %02X\n", + tag, __func__, res); } } } if (res < OK) { - logError(1, "%s fts_system_reset...failed after 3 attempts: ERROR %02X\n", tag, (res | ERROR_SYSTEM_RESET_FAIL)); - return (res | ERROR_SYSTEM_RESET_FAIL); + logError(1, "%s %s:failed after 3 attempts: ERROR %02X\n", + tag, __func__, (res | ERROR_SYSTEM_RESET_FAIL)); + res = (res | ERROR_SYSTEM_RESET_FAIL); + } else { + logError(0, "%s System reset DONE!\n", tag); + system_resetted_down = 1; + system_resetted_up = 1; + res = OK; } - logError(0, "%s System reset DONE!\n", tag); - system_resetted_down = 1; - system_resetted_up = 1; - return OK; - + return res; } int isSystemResettedDown(void) @@ -475,11 +984,11 @@ int senseOn(void) ret = fts_writeFwCmd(cmd, 1); if (ret < OK) { - logError(1, "%s senseOn: ERROR %02X\n", tag, ERROR_SENSE_ON_FAIL); + logError(1, "%s %s:ERROR %02X\n", + tag, __func__, ERROR_SENSE_ON_FAIL); return (ret|ERROR_SENSE_ON_FAIL); } - - logError(0, "%s senseOn: SENSE ON\n", tag); + logError(0, "%s %s: SENSE ON\n", tag, __func__); return OK; } @@ -490,13 +999,12 @@ int senseOff(void) ret = fts_writeFwCmd(cmd, 1); if (ret < OK) { - logError(1, "%s senseOff: ERROR %02X\n", tag, ERROR_SENSE_OFF_FAIL); + logError(1, "%s %s:ERROR %02X\n", + tag, __func__, ERROR_SENSE_OFF_FAIL); return (ret | ERROR_SENSE_OFF_FAIL); } - - logError(0, "%s senseOff: SENSE OFF\n", tag); + logError(0, "%s %s: SENSE OFF\n", tag, __func__); return OK; - } int keyOn(void) @@ -506,13 +1014,13 @@ int keyOn(void) ret = fts_writeFwCmd(cmd, 1); if (ret < OK) { - logError(1, "%s keyOn: ERROR %02X\n", tag, ERROR_SENSE_ON_FAIL); + logError(1, "%s %s:ERROR %02X\n", + tag, __func__, ERROR_SENSE_ON_FAIL); return (ret | ERROR_SENSE_ON_FAIL); } - logError(0, "%s keyOn: KEY ON\n", tag); + logError(0, "%s %s: KEY ON\n", tag, __func__); return OK; - } int keyOff(void) @@ -522,25 +1030,26 @@ int keyOff(void) ret = fts_writeFwCmd(cmd, 1); if (ret < OK) { - logError(1, "%s keyOff: ERROR %02X\n", tag, ERROR_SENSE_OFF_FAIL); + logError(1, "%s %s:ERROR %02X\n", + tag, __func__, ERROR_SENSE_OFF_FAIL); return (ret | ERROR_SENSE_OFF_FAIL); } - logError(0, "%s keyOff: KEY OFF\n", tag); + logError(0, "%s %s: KEY OFF\n", tag, __func__); return OK; - } int cleanUp(int enableTouch) { int res; - logError(0, "%s cleanUp: system reset...\n", tag); + logError(0, "%s %s: system reset...\n", tag, __func__); res = fts_system_reset(); if (res < OK) return res; + if (enableTouch) { - logError(0, "%s cleanUp: enabling touches...\n", tag); + logError(0, "%s %s:enabling touches...\n", tag, __func__); res = senseOn(); if (res < OK) return res; @@ -549,19 +1058,18 @@ int cleanUp(int enableTouch) if (res < OK) return res; #endif - logError(0, "%s cleanUp: enabling interrupts...\n", tag); + logError(0, "%s %s:enabling interrupts...\n", tag, __func__); res = fts_enableInterrupt(); if (res < OK) return res; } return OK; - } int checkEcho(u8 *cmd, int size) { int ret, i; - int event_to_search[size+1]; + int event_to_search[size + 1]; u8 readData[FIFO_EVENT_SIZE]; if ((ftsInfo.u32_echoEn & 0x00000001) != ECHO_ENABLED) { @@ -569,60 +1077,181 @@ int checkEcho(u8 *cmd, int size) return OK; } if (size < 1) { - logError(1, "%s checkEcho: Error Size = %d not valid! or ECHO not Enabled! ERROR %08X\n", tag, size, ERROR_OP_NOT_ALLOW); + logError(1, "%s:Error Size = %d not valid!", tag, size); + logError(1, " or ECHO not Enabled!%08X\n", ERROR_OP_NOT_ALLOW); return ERROR_OP_NOT_ALLOW; } - if ((size+2) > FIFO_EVENT_SIZE) - size = FIFO_EVENT_SIZE-2; - /* Echo event EC xx xx xx xx xx xx fifo_status therefore for command - *with more than 6 bytes will echo only the first 6 - */ + if ((size + 2) > FIFO_EVENT_SIZE) + size = FIFO_EVENT_SIZE - 2; + //Echo event EC xx xx xx xx xx xx + //fifo_status therefore for command + //with more than 6 bytes will echo only the first 6 event_to_search[0] = EVENTID_ECHO; - for (i = 1; i <= size; i++) { - event_to_search[i] = cmd[i-1]; - } - ret = pollForEvent(event_to_search, size+1, readData, GENERAL_TIMEOUT); + for (i = 1; i <= size; i++) + event_to_search[i] = cmd[i - 1]; + ret = pollForEvent(event_to_search, size + 1, + readData, GENERAL_TIMEOUT); if (ret < OK) { - logError(1, "%s checkEcho: Echo Event not found! ERROR %02X\n", tag, ret); - return (ret | ERROR_CHECK_ECHO_FAIL); + logError(1, "%s %s:Echo Event not found! ERROR %02X\n", + tag, __func__, ret); + return (ret | ERROR_CHECK_ECHO_FAIL); } logError(0, "%s ECHO OK!\n", tag); - return OK; + ret = OK; + return ret; } -int featureEnableDisable(int on_off, u8 feature) +int featureEnableDisable(int on_off, u32 feature) { int ret; - u8 cmd[2] = { 0x00, feature }; + u8 cmd[5]; if (on_off == FEAT_ENABLE) { cmd[0] = FTS_CMD_FEATURE_ENABLE; - logError(0, "%s featureEnableDisable: Enabling feature %02X ...\n", tag, feature); + logError(0, "%s %s: Enabling feature %08X ...\n", + tag, __func__, feature); } else { cmd[0] = FTS_CMD_FEATURE_DISABLE; - logError(0, "%s featureEnableDisable: Disabling feature %02X ...\n", tag, feature); + logError(0, "%s %s: Disabling feature %08X ...\n", + tag, __func__, feature); } + u32ToU8(feature, &cmd[1]); - ret = fts_writeCmd(cmd, 2); /* not use writeFwCmd because this function can be called also during interrupt enable and should be fast */ + //not use writeFwCmd because this function can be + //called also during interrupt enable and should be fast + ret = fts_writeCmd(cmd, 5); if (ret < OK) { - logError(1, "%s featureEnableDisable: ERROR %02X\n", tag, ret); + logError(1, "%s %s: ERROR %02X\n", tag, __func__, ret); return (ret | ERROR_FEATURE_ENABLE_DISABLE); } - logError(0, "%s featureEnableDisable: DONE!\n", tag); + logError(0, "%s %s: DONE!\n", tag, __func__); return OK; +} + +int writeNoiseParameters(u8 *noise) +{ + int ret, i; + u8 cmd[2+NOISE_PARAMETERS_SIZE]; + u8 readData[FIFO_EVENT_SIZE]; + int event_to_search[2] = {EVENTID_NOISE_WRITE, NOISE_PARAMETERS}; + + logError(0, "%s %s: Writing noise parameters to the IC ...\n", + tag, __func__); + ret = fts_disableInterrupt(); + if (ret < OK) { + logError(1, "%s %s: ERROR %08X\n", tag, __func__, ret); + ret = (ret | ERROR_NOISE_PARAMETERS); + goto ERROR; + } + cmd[0] = FTS_CMD_NOISE_WRITE; + cmd[1] = NOISE_PARAMETERS; + logError(0, "%s %s: Noise parameters = ", tag, __func__); + for (i = 0; i < NOISE_PARAMETERS_SIZE; i++) { + cmd[2 + i] = noise[i]; + logError(0, "%02X", cmd[2 + i]); + } + + logError(0, "\n"); + ret = fts_writeCmd(cmd, NOISE_PARAMETERS_SIZE + 2); + //not use writeFwCmd because this function should be fast + if (ret < OK) { + logError(1, "%s %s:impossible write command... ERROR %02X\n", + tag, __func__, ret); + ret = (ret | ERROR_NOISE_PARAMETERS); + goto ERROR; + } + ret = pollForEvent(event_to_search, 2, readData, GENERAL_TIMEOUT); + if (ret < OK) { + logError(1, "%s %s: polling FIFO ERROR %02X\n", + tag, __func__, ret); + ret = (ret | ERROR_NOISE_PARAMETERS); + goto ERROR; + } + + if (readData[2] != 0x00) { + logError(1, "%s %s:Event check FAIL! %02X != 0x00 ERROR%02X\n", + tag, __func__, readData[2], ERROR_NOISE_PARAMETERS); + ret = ERROR_NOISE_PARAMETERS; + goto ERROR; + } + + logError(0, "%s %s:DONE!\n", tag, __func__); + ret = OK; +ERROR: + ret = fts_enableInterrupt(); + //ensure that the interrupt are always renabled when exit from funct + if (ret < OK) { + logError(1, "%s %s: ERROR %02X\n", tag, __func__, ret); + return (ret | ERROR_NOISE_PARAMETERS); + } + return ret; } -short **array1dTo2d_short(short *data, int size, int columns) +int readNoiseParameters(u8 *noise) { + int ret, i; + u8 cmd[2]; + u8 readData[FIFO_EVENT_SIZE]; + int event_to_search[2] = {EVENTID_NOISE_READ, NOISE_PARAMETERS}; + + logError(0, "%s %s:Reading noise parameters from the IC ...\n", + tag, __func__); + ret = fts_disableInterrupt(); + if (ret < OK) { + logError(1, "%s %s: ERROR %02X\n", tag, __func__, ret); + ret = (ret | ERROR_NOISE_PARAMETERS); + goto ERROR; + } + cmd[0] = FTS_CMD_NOISE_READ; + cmd[1] = NOISE_PARAMETERS; + ret = fts_writeCmd(cmd, 2);//not use writeFwCmd should be fast + if (ret < OK) { + logError(1, "%s %s:impossible write command... ERROR %02X\n", + tag, __func__, ret); + ret = (ret | ERROR_NOISE_PARAMETERS); + goto ERROR; + } + + ret = pollForEvent(event_to_search, 2, readData, GENERAL_TIMEOUT); + if (ret < OK) { + logError(1, "%s %s: polling FIFO ERROR %02X\n", + tag, __func__, ret); + ret = (ret | ERROR_NOISE_PARAMETERS); + goto ERROR; + } + logError(0, "%s %s: Noise parameters = ", tag, __func__); + for (i = 0; i < NOISE_PARAMETERS_SIZE; i++) { + noise[i] = readData[2 + i]; + logError(0, "%02X ", noise[i]); + } + + logError(0, "\n"); + logError(0, "%s %s: DONE!\n", tag, __func__); + ret = OK; +ERROR: + ret = fts_enableInterrupt(); + //ensure that the interrupt are always renabled when exit from funct + if (ret < OK) { + logError(1, "%s %s: ERROR %02X\n", tag, __func__, ret); + return (ret | ERROR_NOISE_PARAMETERS); + } + return ret; +} + +short **array1dTo2d_short(short *data, int size, int columns) +{ int i; - short **matrix = (short **)kmalloc(((int)(size / columns))*sizeof(short *), GFP_KERNEL); + int count = size / columns; + short **matrix = (short **)kmalloc_array(count, + sizeof(short *), GFP_KERNEL); if (matrix != NULL) { - for (i = 0; i < (int)(size / columns); i++) { - matrix[i] = (short *)kmalloc(columns*sizeof(short), GFP_KERNEL); + for (i = 0; i < count; i++) { + matrix[i] = (short *)kmalloc_array(columns, + sizeof(short), GFP_KERNEL); } for (i = 0; i < size; i++) @@ -634,12 +1263,14 @@ short **array1dTo2d_short(short *data, int size, int columns) u8 **array1dTo2d_u8(u8 *data, int size, int columns) { - int i; - u8 **matrix = (u8 **)kmalloc(((int)(size / columns))*sizeof(u8 *), GFP_KERNEL); + int count = size / columns; + u8 **matrix = (u8 **)kmalloc_array(count, + sizeof(u8 *), GFP_KERNEL); if (matrix != NULL) { - for (i = 0; i < (int)(size / columns); i++) { - matrix[i] = (u8 *)kmalloc(columns*sizeof(u8), GFP_KERNEL); + for (i = 0; i < count; i++) { + matrix[i] = (u8 *)kmalloc_array(columns, + sizeof(u8), GFP_KERNEL); } for (i = 0; i < size; i++) @@ -652,55 +1283,59 @@ u8 **array1dTo2d_u8(u8 *data, int size, int columns) void print_frame_short(char *label, short **matrix, int row, int column) { int i, j; + logError(0, "%s %s\n", tag, label); for (i = 0; i < row; i++) { logError(0, "%s ", tag); - for (j = 0; j < column; j++) { - printk("%d ", matrix[i][j]); - } + for (j = 0; j < column; j++) + pr_err("%d", matrix[i][j]); logError(0, "\n"); kfree(matrix[i]); } + kfree(matrix); } void print_frame_u8(char *label, u8 **matrix, int row, int column) { int i, j; + logError(0, "%s %s\n", tag, label); - for (i = 0; i < row; i++) { - logError(0, "%s ", tag); - for (j = 0; j < column; j++) { - printk("%d ", matrix[i][j]); - } - logError(0, "\n"); - kfree(matrix[i]); - } + for (i = 0; i < row; i++) { + logError(0, "%s ", tag); + for (j = 0; j < column; j++) + pr_err("%d ", matrix[i][j]); + logError(0, "\n"); + kfree(matrix[i]); + } + kfree(matrix); } void print_frame_u32(char *label, u32 **matrix, int row, int column) { int i, j; + logError(0, "%s %s\n", tag, label); for (i = 0; i < row; i++) { logError(0, "%s ", tag); - for (j = 0; j < column; j++) { - printk("%d ", matrix[i][j]); - } + for (j = 0; j < column; j++) + pr_err("%d ", matrix[i][j]); logError(0, "\n"); kfree(matrix[i]); } + kfree(matrix); } void print_frame_int(char *label, int **matrix, int row, int column) { int i, j; + logError(0, "%s %s\n", tag, label); for (i = 0; i < row; i++) { logError(0, "%s ", tag); - for (j = 0; j < column; j++) { - printk("%d ", matrix[i][j]); - } + for (j = 0; j < column; j++) + pr_err("%d ", matrix[i][j]); logError(0, "\n"); kfree(matrix[i]); } + kfree(matrix); } diff --git a/drivers/input/touchscreen/st/fts_lib/ftsTool.h b/drivers/input/touchscreen/st/fts_lib/ftsTool.h index a90e79fc5607..309785bc0827 100644 --- a/drivers/input/touchscreen/st/fts_lib/ftsTool.h +++ b/drivers/input/touchscreen/st/fts_lib/ftsTool.h @@ -1,35 +1,72 @@ /* + * FTS Capacitive touch screen controller (FingerTipS) + * + * Copyright (C) 2016-2018, STMicroelectronics Limited. + * Authors: AMG(Analog Mems Group) + * + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + */ -************************************************************************** -** STMicroelectronics ** -************************************************************************** -** marco.cali@st.com ** -************************************************************************** -* * -* FTS Utility Functions * -* * -************************************************************************** -************************************************************************** +/** + * + ************************************************************************** + ** STMicroelectronics ** + ************************************************************************** + ** marco.cali@st.com ** + ************************************************************************** + * * + * FTS Utility Functions * + * * + ************************************************************************** + ************************************************************************** + * + */ -*/ -#define GPIO_NOT_DEFINED -1 +#ifndef __FTS_TOOL_H +#define __FTS_TOOL_H -#define TIMEOUT_RESOLUTION 10 /* ms */ -#define GENERAL_TIMEOUT (50*TIMEOUT_RESOLUTION) /* ms */ -#define RELEASE_INFO_TIMEOUT (15*TIMEOUT_RESOLUTION) /* ms */ +#define GPIO_NOT_DEFINED -1 +#define TIMEOUT_RESOLUTION 10 //ms +#define GENERAL_TIMEOUT (50*TIMEOUT_RESOLUTION) //ms +#define RELEASE_INFO_TIMEOUT (15*TIMEOUT_RESOLUTION) //ms -#define FEAT_ENABLE 1 -#define FEAT_DISABLE 0 -#define SYSTEM_RESET_RETRY 3 +#define FEAT_ENABLE 1 +#define FEAT_DISABLE 0 -#define B2_RETRY 2 +#define SYSTEM_RESET_RETRY 3 + +#define B2_RETRY 2 +//for FTM4 can not be greater than 13 bytes +#define LOCKDOWN_CODE_SIZE 10 + +#define LOCKDOWN_CODE_MAX_SIZE 63 +#define LOCKDOWN_CODE_WRITE_CHUNK 12 +#define LOCKDOWN_CODE_READ_CHUNK 4 +#define LOCKDOWN_CODE_RETRY 2 int readB2(u16 address, u8 *outBuf, int len); int readB2U16(u16 address, u8 *outBuf, int byteToRead); int releaseInformation(void); +int lockDownInfo(u8 *data); +int calculateCRC8(u8 *u8_srcBuff, int size, u8 *crc); +int writeLockDownInfo(u8 *data, int size); +int rewriteLockDownInfo(u8 *data, int size); +int readLockDownInfo(u8 *lockData, int *size); char *printHex(char *label, u8 *buff, int count); -int pollForEvent(int *event_to_search, int event_bytes, u8 *readData, int time_to_wait); +int pollForEvent(int *event_to_search, int event_bytes, + u8 *readData, int time_to_wait); int fts_disableInterrupt(void); int fts_enableInterrupt(void); int u8ToU16(u8 *src, u16 *dst); @@ -41,7 +78,8 @@ int u16ToU8_be(u16 src, u8 *dst); int u16ToU8n(u16 *src, int src_length, u8 *dst); int u8ToU32(u8 *src, u32 *dst); int u32ToU8(u32 src, u8 *dst); -int attempt_function(int(*code)(void), unsigned long wait_before_retry, int retry_count); +int attempt_function(int(*code)(void), unsigned long wait_before_retry, + int retry_count); void setResetGpio(int gpio); int fts_system_reset(void); int isSystemResettedUp(void); @@ -52,7 +90,9 @@ int senseOn(void); int senseOff(void); int keyOn(void); int keyOff(void); -int featureEnableDisable(int on_off, u8 feature); +int featureEnableDisable(int on_off, u32 feature); +int writeNoiseParameters(u8 *noise); +int readNoiseParameters(u8 *noise); int checkEcho(u8 *cmd, int size); void print_frame_short(char *label, short **matrix, int row, int column); short **array1dTo2d_short(short *data, int size, int columns); @@ -62,3 +102,5 @@ void print_frame_u32(char *label, u32 **matrix, int row, int column); void print_frame_int(char *label, int **matrix, int row, int column); int cleanUp(int enableTouch); int flushFIFO(void); + +#endif diff --git a/drivers/input/touchscreen/st/fts_limits.h b/drivers/input/touchscreen/st/fts_limits.h index d3be1a2b1e1a..478f17d11e91 100644 --- a/drivers/input/touchscreen/st/fts_limits.h +++ b/drivers/input/touchscreen/st/fts_limits.h @@ -1,10 +1,1425 @@ +/* + * FTS Capacitive touch screen controller (FingerTipS) + * + * Copyright (C) 2016-2018, STMicroelectronics Limited. + * Authors: AMG(Analog Mems Group) + * + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + */ + + #ifndef FTS_LIMITS_H #define FTS_LIMITS_H -/* This is an auto generated header file -* --->Remember to change the name of the two variables!<--- */ -const uint32_t myArray2_size; +//This is an auto generated header file +//--->Remember to change the name of the two variables!<--- +const uint32_t myArray2_size = 16725; const uint8_t myArray2[] = { + 0x2A, 0x53, 0x54, 0x4F, 0x50, 0x5F, 0x4F, 0x4E, 0x5F, 0x46, 0x41, 0x49, + 0x4C, 0x2C, 0x31, 0x2C, 0x31, 0x0A, 0x31, 0x0A, 0x2A, 0x53, 0x54, 0x4F, + 0x50, 0x5F, 0x4F, 0x4E, 0x5F, 0x45, 0x52, 0x52, 0x4F, 0x52, 0x2C, 0x31, + 0x2C, 0x31, 0x0A, 0x31, 0x0A, 0x2A, 0x46, 0x4F, 0x52, 0x43, 0x45, 0x5F, + 0x46, 0x57, 0x5F, 0x55, 0x50, 0x44, 0x41, 0x54, 0x45, 0x2C, 0x31, 0x2C, + 0x31, 0x0A, 0x30, 0x0A, 0x2A, 0x53, 0x53, 0x5F, 0x49, 0x58, 0x31, 0x5F, + 0x46, 0x4F, 0x52, 0x43, 0x45, 0x5F, 0x57, 0x2C, 0x31, 0x2C, 0x31, 0x0A, + 0x32, 0x0A, 0x2A, 0x53, 0x53, 0x5F, 0x49, 0x58, 0x32, 0x5F, 0x46, 0x4F, + 0x52, 0x43, 0x45, 0x5F, 0x57, 0x2C, 0x31, 0x2C, 0x31, 0x0A, 0x31, 0x0A, + 0x2A, 0x53, 0x53, 0x5F, 0x49, 0x58, 0x31, 0x5F, 0x53, 0x45, 0x4E, 0x53, + 0x45, 0x5F, 0x57, 0x2C, 0x31, 0x2C, 0x31, 0x0A, 0x32, 0x0A, 0x2A, 0x53, + 0x53, 0x5F, 0x49, 0x58, 0x32, 0x5F, 0x53, 0x45, 0x4E, 0x53, 0x45, 0x5F, + 0x57, 0x2C, 0x31, 0x2C, 0x31, 0x0A, 0x31, 0x0A, 0x2A, 0x4D, 0x53, 0x5F, + 0x52, 0x41, 0x57, 0x5F, 0x44, 0x41, 0x54, 0x41, 0x5F, 0x4D, 0x49, 0x4E, + 0x5F, 0x4D, 0x41, 0x58, 0x2C, 0x31, 0x2C, 0x32, 0x0A, 0x31, 0x30, 0x30, + 0x30, 0x2C, 0x31, 0x35, 0x30, 0x30, 0x30, 0x0A, 0x2A, 0x4D, 0x53, 0x5F, + 0x52, 0x41, 0x57, 0x5F, 0x44, 0x41, 0x54, 0x41, 0x5F, 0x47, 0x41, 0x50, + 0x2C, 0x31, 0x2C, 0x31, 0x0A, 0x33, 0x30, 0x30, 0x30, 0x0A, 0x2A, 0x4D, + 0x53, 0x5F, 0x54, 0x4F, 0x55, 0x43, 0x48, 0x5F, 0x41, 0x43, 0x54, 0x49, + 0x56, 0x45, 0x5F, 0x43, 0x58, 0x31, 0x5F, 0x4D, 0x49, 0x4E, 0x5F, 0x4D, + 0x41, 0x58, 0x2C, 0x31, 0x2C, 0x32, 0x0A, 0x30, 0x2C, 0x36, 0x33, 0x0A, + 0x2A, 0x4D, 0x53, 0x5F, 0x54, 0x4F, 0x55, 0x43, 0x48, 0x5F, 0x41, 0x43, + 0x54, 0x49, 0x56, 0x45, 0x5F, 0x43, 0x58, 0x32, 0x5F, 0x4D, 0x49, 0x4E, + 0x2C, 0x32, 0x32, 0x2C, 0x32, 0x37, 0x0A, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x0A, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x0A, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x0A, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x0A, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x0A, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x0A, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x0A, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x0A, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x0A, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x0A, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x0A, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x0A, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x0A, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x0A, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x0A, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x0A, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x0A, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x0A, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x0A, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x0A, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x0A, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x0A, 0x2A, 0x4D, 0x53, 0x5F, 0x54, + 0x4F, 0x55, 0x43, 0x48, 0x5F, 0x41, 0x43, 0x54, 0x49, 0x56, 0x45, 0x5F, + 0x43, 0x58, 0x32, 0x5F, 0x4D, 0x41, 0x58, 0x2C, 0x32, 0x32, 0x2C, 0x32, + 0x37, 0x0A, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x0A, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x0A, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x0A, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x0A, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x0A, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x0A, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x0A, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x0A, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x0A, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x0A, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x0A, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x0A, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x0A, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x0A, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x0A, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x0A, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x0A, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x0A, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x0A, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x0A, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x0A, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x0A, 0x2A, 0x4D, 0x53, 0x5F, + 0x54, 0x4F, 0x55, 0x43, 0x48, 0x5F, 0x41, 0x43, 0x54, 0x49, 0x56, 0x45, + 0x5F, 0x43, 0x58, 0x32, 0x5F, 0x41, 0x44, 0x4A, 0x5F, 0x48, 0x4F, 0x52, + 0x49, 0x5A, 0x4F, 0x4E, 0x54, 0x41, 0x4C, 0x2C, 0x32, 0x32, 0x2C, 0x32, + 0x36, 0x0A, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x0A, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x0A, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x0A, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x0A, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x0A, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x0A, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x0A, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x0A, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x0A, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x0A, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x0A, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x0A, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x0A, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x0A, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x0A, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x0A, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x0A, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x0A, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x0A, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x0A, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x0A, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x0A, 0x2A, 0x4D, 0x53, 0x5F, 0x54, 0x4F, 0x55, 0x43, 0x48, 0x5F, + 0x41, 0x43, 0x54, 0x49, 0x56, 0x45, 0x5F, 0x43, 0x58, 0x32, 0x5F, 0x41, + 0x44, 0x4A, 0x5F, 0x56, 0x45, 0x52, 0x54, 0x49, 0x43, 0x41, 0x4C, 0x2C, + 0x32, 0x31, 0x2C, 0x32, 0x37, 0x0A, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x0A, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x0A, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x0A, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x0A, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x0A, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x0A, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x0A, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x0A, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x0A, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x0A, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x0A, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x0A, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x0A, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x0A, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x0A, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x0A, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x0A, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x0A, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x0A, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x0A, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x0A, 0x2A, 0x4D, 0x53, 0x5F, 0x54, 0x4F, 0x55, 0x43, 0x48, + 0x5F, 0x41, 0x43, 0x54, 0x49, 0x56, 0x45, 0x5F, 0x54, 0x4F, 0x54, 0x41, + 0x4C, 0x5F, 0x43, 0x58, 0x5F, 0x4D, 0x49, 0x4E, 0x2C, 0x32, 0x32, 0x2C, + 0x32, 0x37, 0x0A, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x0A, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x0A, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x0A, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x0A, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x0A, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x0A, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x0A, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x0A, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x0A, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x0A, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x0A, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x0A, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x0A, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x0A, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x0A, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x0A, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x0A, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x0A, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x0A, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x0A, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x0A, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x0A, 0x2A, 0x4D, 0x53, 0x5F, 0x54, 0x4F, 0x55, 0x43, 0x48, + 0x5F, 0x41, 0x43, 0x54, 0x49, 0x56, 0x45, 0x5F, 0x54, 0x4F, 0x54, 0x41, + 0x4C, 0x5F, 0x43, 0x58, 0x5F, 0x4D, 0x41, 0x58, 0x2C, 0x32, 0x32, 0x2C, + 0x32, 0x37, 0x0A, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x0A, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x0A, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x0A, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x0A, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x0A, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x0A, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x0A, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x0A, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x0A, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x0A, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x0A, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x0A, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x0A, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x0A, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x0A, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x0A, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x0A, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x0A, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x0A, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x0A, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x0A, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x0A, 0x2A, 0x4D, 0x53, + 0x5F, 0x54, 0x4F, 0x55, 0x43, 0x48, 0x5F, 0x41, 0x43, 0x54, 0x49, 0x56, + 0x45, 0x5F, 0x54, 0x4F, 0x54, 0x41, 0x4C, 0x5F, 0x43, 0x58, 0x5F, 0x41, + 0x44, 0x4A, 0x5F, 0x48, 0x4F, 0x52, 0x49, 0x5A, 0x4F, 0x4E, 0x54, 0x41, + 0x4C, 0x2C, 0x32, 0x32, 0x2C, 0x32, 0x36, 0x0A, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x0A, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x0A, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x0A, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x0A, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x0A, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x0A, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x0A, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x0A, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x0A, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x0A, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x0A, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x0A, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x0A, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x0A, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x0A, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x0A, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x0A, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x0A, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x0A, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x0A, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x0A, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x0A, 0x2A, 0x4D, 0x53, 0x5F, + 0x54, 0x4F, 0x55, 0x43, 0x48, 0x5F, 0x41, 0x43, 0x54, 0x49, 0x56, 0x45, + 0x5F, 0x54, 0x4F, 0x54, 0x41, 0x4C, 0x5F, 0x43, 0x58, 0x5F, 0x41, 0x44, + 0x4A, 0x5F, 0x56, 0x45, 0x52, 0x54, 0x49, 0x43, 0x41, 0x4C, 0x2C, 0x32, + 0x31, 0x2C, 0x32, 0x37, 0x0A, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x0A, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x0A, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x0A, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x0A, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x0A, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x0A, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x0A, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x0A, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x0A, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x0A, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x0A, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x0A, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x0A, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x0A, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x0A, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x0A, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x0A, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x0A, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x0A, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x0A, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x0A, 0x2A, 0x4D, 0x53, 0x5F, 0x4B, 0x45, 0x59, 0x5F, 0x52, 0x41, + 0x57, 0x5F, 0x44, 0x41, 0x54, 0x41, 0x5F, 0x4D, 0x49, 0x4E, 0x5F, 0x4D, + 0x41, 0x58, 0x2C, 0x31, 0x2C, 0x32, 0x0A, 0x30, 0x2C, 0x38, 0x30, 0x30, + 0x30, 0x0A, 0x2A, 0x4D, 0x53, 0x5F, 0x4B, 0x45, 0x59, 0x5F, 0x43, 0x58, + 0x31, 0x5F, 0x4D, 0x49, 0x4E, 0x5F, 0x4D, 0x41, 0x58, 0x2C, 0x31, 0x2C, + 0x32, 0x0A, 0x30, 0x2C, 0x36, 0x34, 0x0A, 0x2A, 0x4D, 0x53, 0x5F, 0x4B, + 0x45, 0x59, 0x5F, 0x43, 0x58, 0x32, 0x5F, 0x4D, 0x49, 0x4E, 0x2C, 0x31, + 0x2C, 0x33, 0x0A, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x0A, 0x2A, 0x4D, 0x53, + 0x5F, 0x4B, 0x45, 0x59, 0x5F, 0x43, 0x58, 0x32, 0x5F, 0x4D, 0x41, 0x58, + 0x2C, 0x31, 0x2C, 0x33, 0x0A, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x0A, 0x2A, 0x4D, 0x53, 0x5F, 0x4B, 0x45, 0x59, 0x5F, 0x54, 0x4F, + 0x54, 0x41, 0x4C, 0x5F, 0x43, 0x58, 0x5F, 0x4D, 0x49, 0x4E, 0x2C, 0x31, + 0x2C, 0x33, 0x0A, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x0A, 0x2A, 0x4D, 0x53, + 0x5F, 0x4B, 0x45, 0x59, 0x5F, 0x54, 0x4F, 0x54, 0x41, 0x4C, 0x5F, 0x43, + 0x58, 0x5F, 0x4D, 0x41, 0x58, 0x2C, 0x31, 0x2C, 0x33, 0x0A, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x0A, 0x2A, 0x53, 0x53, 0x5F, 0x52, + 0x41, 0x57, 0x5F, 0x44, 0x41, 0x54, 0x41, 0x5F, 0x46, 0x4F, 0x52, 0x43, + 0x45, 0x5F, 0x4D, 0x49, 0x4E, 0x5F, 0x4D, 0x41, 0x58, 0x2C, 0x31, 0x2C, + 0x32, 0x0A, 0x31, 0x30, 0x30, 0x30, 0x2C, 0x31, 0x35, 0x30, 0x30, 0x30, + 0x0A, 0x2A, 0x53, 0x53, 0x5F, 0x52, 0x41, 0x57, 0x5F, 0x44, 0x41, 0x54, + 0x41, 0x5F, 0x46, 0x4F, 0x52, 0x43, 0x45, 0x5F, 0x47, 0x41, 0x50, 0x2C, + 0x31, 0x2C, 0x31, 0x0A, 0x33, 0x30, 0x30, 0x0A, 0x2A, 0x53, 0x53, 0x5F, + 0x54, 0x4F, 0x55, 0x43, 0x48, 0x5F, 0x41, 0x43, 0x54, 0x49, 0x56, 0x45, + 0x5F, 0x49, 0x58, 0x31, 0x5F, 0x46, 0x4F, 0x52, 0x43, 0x45, 0x5F, 0x4D, + 0x49, 0x4E, 0x5F, 0x4D, 0x41, 0x58, 0x2C, 0x31, 0x2C, 0x32, 0x0A, 0x30, + 0x2C, 0x36, 0x33, 0x0A, 0x2A, 0x53, 0x53, 0x5F, 0x54, 0x4F, 0x55, 0x43, + 0x48, 0x5F, 0x41, 0x43, 0x54, 0x49, 0x56, 0x45, 0x5F, 0x49, 0x58, 0x32, + 0x5F, 0x46, 0x4F, 0x52, 0x43, 0x45, 0x5F, 0x4D, 0x49, 0x4E, 0x2C, 0x32, + 0x32, 0x2C, 0x31, 0x0A, 0x30, 0x0A, 0x30, 0x0A, 0x30, 0x0A, 0x30, 0x0A, + 0x30, 0x0A, 0x30, 0x0A, 0x30, 0x0A, 0x30, 0x0A, 0x30, 0x0A, 0x30, 0x0A, + 0x30, 0x0A, 0x30, 0x0A, 0x30, 0x0A, 0x30, 0x0A, 0x30, 0x0A, 0x30, 0x0A, + 0x30, 0x0A, 0x30, 0x0A, 0x30, 0x0A, 0x30, 0x0A, 0x30, 0x0A, 0x30, 0x0A, + 0x2A, 0x53, 0x53, 0x5F, 0x54, 0x4F, 0x55, 0x43, 0x48, 0x5F, 0x41, 0x43, + 0x54, 0x49, 0x56, 0x45, 0x5F, 0x49, 0x58, 0x32, 0x5F, 0x46, 0x4F, 0x52, + 0x43, 0x45, 0x5F, 0x4D, 0x41, 0x58, 0x2C, 0x32, 0x32, 0x2C, 0x31, 0x0A, + 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, + 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, + 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, + 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, + 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, + 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, + 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, + 0x32, 0x35, 0x35, 0x0A, 0x2A, 0x53, 0x53, 0x5F, 0x54, 0x4F, 0x55, 0x43, + 0x48, 0x5F, 0x41, 0x43, 0x54, 0x49, 0x56, 0x45, 0x5F, 0x49, 0x58, 0x32, + 0x5F, 0x41, 0x44, 0x4A, 0x5F, 0x56, 0x45, 0x52, 0x54, 0x49, 0x43, 0x41, + 0x4C, 0x2C, 0x32, 0x31, 0x2C, 0x31, 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, + 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, + 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, + 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, + 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, + 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, + 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, + 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x2A, 0x53, 0x53, 0x5F, 0x54, + 0x4F, 0x55, 0x43, 0x48, 0x5F, 0x41, 0x43, 0x54, 0x49, 0x56, 0x45, 0x5F, + 0x54, 0x4F, 0x54, 0x41, 0x4C, 0x5F, 0x49, 0x58, 0x5F, 0x46, 0x4F, 0x52, + 0x43, 0x45, 0x5F, 0x4D, 0x49, 0x4E, 0x2C, 0x32, 0x32, 0x2C, 0x31, 0x0A, + 0x30, 0x0A, 0x30, 0x0A, 0x30, 0x0A, 0x30, 0x0A, 0x30, 0x0A, 0x30, 0x0A, + 0x30, 0x0A, 0x30, 0x0A, 0x30, 0x0A, 0x30, 0x0A, 0x30, 0x0A, 0x30, 0x0A, + 0x30, 0x0A, 0x30, 0x0A, 0x30, 0x0A, 0x30, 0x0A, 0x30, 0x0A, 0x30, 0x0A, + 0x30, 0x0A, 0x30, 0x0A, 0x30, 0x0A, 0x30, 0x0A, 0x2A, 0x53, 0x53, 0x5F, + 0x54, 0x4F, 0x55, 0x43, 0x48, 0x5F, 0x41, 0x43, 0x54, 0x49, 0x56, 0x45, + 0x5F, 0x54, 0x4F, 0x54, 0x41, 0x4C, 0x5F, 0x49, 0x58, 0x5F, 0x46, 0x4F, + 0x52, 0x43, 0x45, 0x5F, 0x4D, 0x41, 0x58, 0x2C, 0x32, 0x32, 0x2C, 0x31, + 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, + 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, + 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, + 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, + 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, + 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, + 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, + 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x2A, 0x53, 0x53, 0x5F, 0x54, 0x4F, 0x55, + 0x43, 0x48, 0x5F, 0x41, 0x43, 0x54, 0x49, 0x56, 0x45, 0x5F, 0x54, 0x4F, + 0x54, 0x41, 0x4C, 0x5F, 0x49, 0x58, 0x5F, 0x41, 0x44, 0x4A, 0x5F, 0x56, + 0x45, 0x52, 0x54, 0x49, 0x43, 0x41, 0x4C, 0x2C, 0x32, 0x31, 0x2C, 0x31, + 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, + 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, + 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, + 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, + 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, + 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, + 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, + 0x0A, 0x2A, 0x53, 0x53, 0x5F, 0x54, 0x4F, 0x55, 0x43, 0x48, 0x5F, 0x41, + 0x43, 0x54, 0x49, 0x56, 0x45, 0x5F, 0x43, 0x58, 0x31, 0x5F, 0x46, 0x4F, + 0x52, 0x43, 0x45, 0x5F, 0x4D, 0x49, 0x4E, 0x5F, 0x4D, 0x41, 0x58, 0x2C, + 0x31, 0x2C, 0x32, 0x0A, 0x30, 0x2C, 0x36, 0x33, 0x0A, 0x2A, 0x53, 0x53, + 0x5F, 0x54, 0x4F, 0x55, 0x43, 0x48, 0x5F, 0x41, 0x43, 0x54, 0x49, 0x56, + 0x45, 0x5F, 0x43, 0x58, 0x32, 0x5F, 0x46, 0x4F, 0x52, 0x43, 0x45, 0x5F, + 0x4D, 0x49, 0x4E, 0x2C, 0x32, 0x32, 0x2C, 0x31, 0x0A, 0x30, 0x0A, 0x30, + 0x0A, 0x30, 0x0A, 0x30, 0x0A, 0x30, 0x0A, 0x30, 0x0A, 0x30, 0x0A, 0x30, + 0x0A, 0x30, 0x0A, 0x30, 0x0A, 0x30, 0x0A, 0x30, 0x0A, 0x30, 0x0A, 0x30, + 0x0A, 0x30, 0x0A, 0x30, 0x0A, 0x30, 0x0A, 0x30, 0x0A, 0x30, 0x0A, 0x30, + 0x0A, 0x30, 0x0A, 0x30, 0x0A, 0x2A, 0x53, 0x53, 0x5F, 0x54, 0x4F, 0x55, + 0x43, 0x48, 0x5F, 0x41, 0x43, 0x54, 0x49, 0x56, 0x45, 0x5F, 0x43, 0x58, + 0x32, 0x5F, 0x46, 0x4F, 0x52, 0x43, 0x45, 0x5F, 0x4D, 0x41, 0x58, 0x2C, + 0x32, 0x32, 0x2C, 0x31, 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, + 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, + 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, + 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, + 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, + 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, + 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, + 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x2A, 0x53, 0x53, + 0x5F, 0x54, 0x4F, 0x55, 0x43, 0x48, 0x5F, 0x41, 0x43, 0x54, 0x49, 0x56, + 0x45, 0x5F, 0x43, 0x58, 0x32, 0x5F, 0x41, 0x44, 0x4A, 0x5F, 0x56, 0x45, + 0x52, 0x54, 0x49, 0x43, 0x41, 0x4C, 0x2C, 0x32, 0x31, 0x2C, 0x31, 0x0A, + 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, + 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, + 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, + 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, + 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, + 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, + 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, + 0x2A, 0x53, 0x53, 0x5F, 0x54, 0x4F, 0x55, 0x43, 0x48, 0x5F, 0x41, 0x43, + 0x54, 0x49, 0x56, 0x45, 0x5F, 0x54, 0x4F, 0x54, 0x41, 0x4C, 0x5F, 0x43, + 0x58, 0x5F, 0x46, 0x4F, 0x52, 0x43, 0x45, 0x5F, 0x4D, 0x49, 0x4E, 0x2C, + 0x32, 0x32, 0x2C, 0x31, 0x0A, 0x30, 0x0A, 0x30, 0x0A, 0x30, 0x0A, 0x30, + 0x0A, 0x30, 0x0A, 0x30, 0x0A, 0x30, 0x0A, 0x30, 0x0A, 0x30, 0x0A, 0x30, + 0x0A, 0x30, 0x0A, 0x30, 0x0A, 0x30, 0x0A, 0x30, 0x0A, 0x30, 0x0A, 0x30, + 0x0A, 0x30, 0x0A, 0x30, 0x0A, 0x30, 0x0A, 0x30, 0x0A, 0x30, 0x0A, 0x30, + 0x0A, 0x2A, 0x53, 0x53, 0x5F, 0x54, 0x4F, 0x55, 0x43, 0x48, 0x5F, 0x41, + 0x43, 0x54, 0x49, 0x56, 0x45, 0x5F, 0x54, 0x4F, 0x54, 0x41, 0x4C, 0x5F, + 0x43, 0x58, 0x5F, 0x46, 0x4F, 0x52, 0x43, 0x45, 0x5F, 0x4D, 0x41, 0x58, + 0x2C, 0x32, 0x32, 0x2C, 0x31, 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, + 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, + 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, + 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, + 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, + 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, + 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, + 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x2A, 0x53, + 0x53, 0x5F, 0x54, 0x4F, 0x55, 0x43, 0x48, 0x5F, 0x41, 0x43, 0x54, 0x49, + 0x56, 0x45, 0x5F, 0x54, 0x4F, 0x54, 0x41, 0x4C, 0x5F, 0x43, 0x58, 0x5F, + 0x41, 0x44, 0x4A, 0x5F, 0x56, 0x45, 0x52, 0x54, 0x49, 0x43, 0x41, 0x4C, + 0x2C, 0x32, 0x31, 0x2C, 0x31, 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, + 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, + 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, + 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, + 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, + 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, + 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, + 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x2A, 0x53, 0x53, 0x5F, 0x52, 0x41, + 0x57, 0x5F, 0x44, 0x41, 0x54, 0x41, 0x5F, 0x53, 0x45, 0x4E, 0x53, 0x45, + 0x5F, 0x4D, 0x49, 0x4E, 0x5F, 0x4D, 0x41, 0x58, 0x2C, 0x31, 0x2C, 0x32, + 0x0A, 0x31, 0x30, 0x30, 0x30, 0x2C, 0x31, 0x35, 0x30, 0x30, 0x30, 0x0A, + 0x2A, 0x53, 0x53, 0x5F, 0x52, 0x41, 0x57, 0x5F, 0x44, 0x41, 0x54, 0x41, + 0x5F, 0x53, 0x45, 0x4E, 0x53, 0x45, 0x5F, 0x47, 0x41, 0x50, 0x2C, 0x31, + 0x2C, 0x31, 0x0A, 0x33, 0x30, 0x30, 0x0A, 0x2A, 0x53, 0x53, 0x5F, 0x54, + 0x4F, 0x55, 0x43, 0x48, 0x5F, 0x41, 0x43, 0x54, 0x49, 0x56, 0x45, 0x5F, + 0x49, 0x58, 0x31, 0x5F, 0x53, 0x45, 0x4E, 0x53, 0x45, 0x5F, 0x4D, 0x49, + 0x4E, 0x5F, 0x4D, 0x41, 0x58, 0x2C, 0x31, 0x2C, 0x32, 0x0A, 0x30, 0x2C, + 0x36, 0x33, 0x0A, 0x2A, 0x53, 0x53, 0x5F, 0x54, 0x4F, 0x55, 0x43, 0x48, + 0x5F, 0x41, 0x43, 0x54, 0x49, 0x56, 0x45, 0x5F, 0x49, 0x58, 0x32, 0x5F, + 0x53, 0x45, 0x4E, 0x53, 0x45, 0x5F, 0x4D, 0x49, 0x4E, 0x2C, 0x31, 0x2C, + 0x32, 0x37, 0x0A, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x0A, 0x2A, 0x53, 0x53, + 0x5F, 0x54, 0x4F, 0x55, 0x43, 0x48, 0x5F, 0x41, 0x43, 0x54, 0x49, 0x56, + 0x45, 0x5F, 0x49, 0x58, 0x32, 0x5F, 0x53, 0x45, 0x4E, 0x53, 0x45, 0x5F, + 0x4D, 0x41, 0x58, 0x2C, 0x31, 0x2C, 0x32, 0x37, 0x0A, 0x32, 0x35, 0x35, + 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, + 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, + 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, + 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, + 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, + 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, + 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, + 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, + 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x0A, 0x2A, 0x53, 0x53, + 0x5F, 0x54, 0x4F, 0x55, 0x43, 0x48, 0x5F, 0x41, 0x43, 0x54, 0x49, 0x56, + 0x45, 0x5F, 0x49, 0x58, 0x32, 0x5F, 0x41, 0x44, 0x4A, 0x5F, 0x48, 0x4F, + 0x52, 0x49, 0x5A, 0x4F, 0x4E, 0x54, 0x41, 0x4C, 0x2C, 0x31, 0x2C, 0x32, + 0x36, 0x0A, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, + 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, + 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, + 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, + 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, + 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, + 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, + 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, + 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x0A, 0x2A, 0x53, + 0x53, 0x5F, 0x54, 0x4F, 0x55, 0x43, 0x48, 0x5F, 0x41, 0x43, 0x54, 0x49, + 0x56, 0x45, 0x5F, 0x54, 0x4F, 0x54, 0x41, 0x4C, 0x5F, 0x49, 0x58, 0x5F, + 0x53, 0x45, 0x4E, 0x53, 0x45, 0x5F, 0x4D, 0x49, 0x4E, 0x2C, 0x31, 0x2C, + 0x32, 0x37, 0x0A, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x0A, 0x2A, 0x53, 0x53, + 0x5F, 0x54, 0x4F, 0x55, 0x43, 0x48, 0x5F, 0x41, 0x43, 0x54, 0x49, 0x56, + 0x45, 0x5F, 0x54, 0x4F, 0x54, 0x41, 0x4C, 0x5F, 0x49, 0x58, 0x5F, 0x53, + 0x45, 0x4E, 0x53, 0x45, 0x5F, 0x4D, 0x41, 0x58, 0x2C, 0x31, 0x2C, 0x32, + 0x37, 0x0A, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, + 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, + 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, + 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, + 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, + 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, + 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, + 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, + 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, + 0x35, 0x0A, 0x2A, 0x53, 0x53, 0x5F, 0x54, 0x4F, 0x55, 0x43, 0x48, 0x5F, + 0x41, 0x43, 0x54, 0x49, 0x56, 0x45, 0x5F, 0x54, 0x4F, 0x54, 0x41, 0x4C, + 0x5F, 0x49, 0x58, 0x5F, 0x41, 0x44, 0x4A, 0x5F, 0x48, 0x4F, 0x52, 0x49, + 0x5A, 0x4F, 0x4E, 0x54, 0x41, 0x4C, 0x2C, 0x31, 0x2C, 0x32, 0x36, 0x0A, + 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, + 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, + 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, + 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, + 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, + 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, + 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, + 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, + 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x0A, 0x2A, 0x53, 0x53, 0x5F, + 0x54, 0x4F, 0x55, 0x43, 0x48, 0x5F, 0x41, 0x43, 0x54, 0x49, 0x56, 0x45, + 0x5F, 0x43, 0x58, 0x31, 0x5F, 0x53, 0x45, 0x4E, 0x53, 0x45, 0x5F, 0x4D, + 0x49, 0x4E, 0x5F, 0x4D, 0x41, 0x58, 0x2C, 0x31, 0x2C, 0x32, 0x0A, 0x30, + 0x2C, 0x36, 0x33, 0x0A, 0x2A, 0x53, 0x53, 0x5F, 0x54, 0x4F, 0x55, 0x43, + 0x48, 0x5F, 0x41, 0x43, 0x54, 0x49, 0x56, 0x45, 0x5F, 0x43, 0x58, 0x32, + 0x5F, 0x53, 0x45, 0x4E, 0x53, 0x45, 0x5F, 0x4D, 0x49, 0x4E, 0x2C, 0x31, + 0x2C, 0x32, 0x37, 0x0A, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, + 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, + 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, + 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, + 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x0A, 0x2A, 0x53, + 0x53, 0x5F, 0x54, 0x4F, 0x55, 0x43, 0x48, 0x5F, 0x41, 0x43, 0x54, 0x49, + 0x56, 0x45, 0x5F, 0x43, 0x58, 0x32, 0x5F, 0x53, 0x45, 0x4E, 0x53, 0x45, + 0x5F, 0x4D, 0x41, 0x58, 0x2C, 0x31, 0x2C, 0x32, 0x37, 0x0A, 0x32, 0x35, + 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, + 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, + 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, + 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, + 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, + 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, + 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, + 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, + 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x0A, 0x2A, 0x53, + 0x53, 0x5F, 0x54, 0x4F, 0x55, 0x43, 0x48, 0x5F, 0x41, 0x43, 0x54, 0x49, + 0x56, 0x45, 0x5F, 0x43, 0x58, 0x32, 0x5F, 0x41, 0x44, 0x4A, 0x5F, 0x48, + 0x4F, 0x52, 0x49, 0x5A, 0x4F, 0x4E, 0x54, 0x41, 0x4C, 0x2C, 0x31, 0x2C, + 0x32, 0x36, 0x0A, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, + 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, + 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, + 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, + 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, + 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, + 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, + 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, + 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x0A, 0x2A, + 0x53, 0x53, 0x5F, 0x54, 0x4F, 0x55, 0x43, 0x48, 0x5F, 0x41, 0x43, 0x54, + 0x49, 0x56, 0x45, 0x5F, 0x54, 0x4F, 0x54, 0x41, 0x4C, 0x5F, 0x43, 0x58, + 0x5F, 0x53, 0x45, 0x4E, 0x53, 0x45, 0x5F, 0x4D, 0x49, 0x4E, 0x2C, 0x31, + 0x2C, 0x32, 0x37, 0x0A, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, + 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, + 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, + 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, + 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x0A, 0x2A, 0x53, + 0x53, 0x5F, 0x54, 0x4F, 0x55, 0x43, 0x48, 0x5F, 0x41, 0x43, 0x54, 0x49, + 0x56, 0x45, 0x5F, 0x54, 0x4F, 0x54, 0x41, 0x4C, 0x5F, 0x43, 0x58, 0x5F, + 0x53, 0x45, 0x4E, 0x53, 0x45, 0x5F, 0x4D, 0x41, 0x58, 0x2C, 0x31, 0x2C, + 0x32, 0x37, 0x0A, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, + 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, + 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, + 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, + 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, + 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, + 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, + 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, + 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, + 0x35, 0x35, 0x0A, 0x2A, 0x53, 0x53, 0x5F, 0x54, 0x4F, 0x55, 0x43, 0x48, + 0x5F, 0x41, 0x43, 0x54, 0x49, 0x56, 0x45, 0x5F, 0x54, 0x4F, 0x54, 0x41, + 0x4C, 0x5F, 0x43, 0x58, 0x5F, 0x41, 0x44, 0x4A, 0x5F, 0x48, 0x4F, 0x52, + 0x49, 0x5A, 0x4F, 0x4E, 0x54, 0x41, 0x4C, 0x2C, 0x31, 0x2C, 0x32, 0x36, + 0x0A, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, + 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, + 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, + 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, + 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, + 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, + 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, + 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, + 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x0A, }; #endif -- GitLab From e2df260dba75006d78e47c2f7c604581a1f5fadd Mon Sep 17 00:00:00 2001 From: Chong Gu Date: Tue, 10 Apr 2018 14:08:42 +0800 Subject: [PATCH 0370/1635] defconfig: sm8150: Enable ST touch driver support Enable ST touch driver for sm8150_defconfig and sm8150-perf_defconfig. Change-Id: I70206d9e865680a1bf5f1d5962d53f682b80a025 Signed-off-by: Chong Gu --- arch/arm64/configs/sm8150-perf_defconfig | 1 + arch/arm64/configs/sm8150_defconfig | 1 + 2 files changed, 2 insertions(+) diff --git a/arch/arm64/configs/sm8150-perf_defconfig b/arch/arm64/configs/sm8150-perf_defconfig index bc97892cb5a8..a6d4e1cc0421 100644 --- a/arch/arm64/configs/sm8150-perf_defconfig +++ b/arch/arm64/configs/sm8150-perf_defconfig @@ -282,6 +282,7 @@ CONFIG_INPUT_EVDEV=y CONFIG_KEYBOARD_GPIO=y # CONFIG_INPUT_MOUSE is not set CONFIG_INPUT_TOUCHSCREEN=y +CONFIG_TOUCHSCREEN_ST=y CONFIG_INPUT_MISC=y CONFIG_INPUT_HBTP_INPUT=y CONFIG_INPUT_QPNP_POWER_ON=y diff --git a/arch/arm64/configs/sm8150_defconfig b/arch/arm64/configs/sm8150_defconfig index bc24ba3e0a63..2e01fb3617e3 100644 --- a/arch/arm64/configs/sm8150_defconfig +++ b/arch/arm64/configs/sm8150_defconfig @@ -289,6 +289,7 @@ CONFIG_KEYBOARD_GPIO=y # CONFIG_INPUT_MOUSE is not set CONFIG_INPUT_JOYSTICK=y CONFIG_INPUT_TOUCHSCREEN=y +CONFIG_TOUCHSCREEN_ST=y CONFIG_INPUT_MISC=y CONFIG_INPUT_HBTP_INPUT=y CONFIG_INPUT_QPNP_POWER_ON=y -- GitLab From c0f18b39d64e9831e5b42bb5221ea4c437dab0ca Mon Sep 17 00:00:00 2001 From: Taniya Das Date: Fri, 13 Apr 2018 12:42:23 +0530 Subject: [PATCH 0371/1635] defconfig: qcs405: Enable the common clock framework Enable common clock framework and syscon for QCS405 device. Change-Id: I3c0f451511fa350a53ceec2e2c25b00384a5a6fd Signed-off-by: Taniya Das --- arch/arm/configs/qcs405-perf_defconfig | 2 ++ arch/arm/configs/qcs405_defconfig | 2 ++ arch/arm64/configs/qcs405-perf_defconfig | 1 + arch/arm64/configs/qcs405_defconfig | 1 + 4 files changed, 6 insertions(+) diff --git a/arch/arm/configs/qcs405-perf_defconfig b/arch/arm/configs/qcs405-perf_defconfig index 4cc91738ca57..a20796581bb6 100644 --- a/arch/arm/configs/qcs405-perf_defconfig +++ b/arch/arm/configs/qcs405-perf_defconfig @@ -246,6 +246,7 @@ CONFIG_SPI_SPIDEV=y CONFIG_PINCTRL_QCS405=y CONFIG_GPIOLIB=y CONFIG_THERMAL=y +CONFIG_MFD_SYSCON=y CONFIG_REGULATOR=y CONFIG_REGULATOR_FIXED_VOLTAGE=y CONFIG_REGULATOR_FAN53555=y @@ -307,6 +308,7 @@ CONFIG_UIO=y CONFIG_STAGING=y CONFIG_ASHMEM=y CONFIG_ION=y +CONFIG_COMMON_CLK_QCOM=y CONFIG_HWSPINLOCK=y CONFIG_MAILBOX=y CONFIG_QCOM_SMEM=y diff --git a/arch/arm/configs/qcs405_defconfig b/arch/arm/configs/qcs405_defconfig index d03f31a38a59..d264642c4cf9 100644 --- a/arch/arm/configs/qcs405_defconfig +++ b/arch/arm/configs/qcs405_defconfig @@ -254,6 +254,7 @@ CONFIG_SPI_SPIDEV=y CONFIG_PINCTRL_QCS405=y CONFIG_GPIOLIB=y CONFIG_THERMAL=y +CONFIG_MFD_SYSCON=y CONFIG_REGULATOR=y CONFIG_REGULATOR_FIXED_VOLTAGE=y CONFIG_REGULATOR_FAN53555=y @@ -317,6 +318,7 @@ CONFIG_UIO=y CONFIG_STAGING=y CONFIG_ASHMEM=y CONFIG_ION=y +CONFIG_COMMON_CLK_QCOM=y CONFIG_HWSPINLOCK=y CONFIG_MAILBOX=y CONFIG_QCOM_LAZY_MAPPING=y diff --git a/arch/arm64/configs/qcs405-perf_defconfig b/arch/arm64/configs/qcs405-perf_defconfig index f693c01d810f..a9fa27770efe 100644 --- a/arch/arm64/configs/qcs405-perf_defconfig +++ b/arch/arm64/configs/qcs405-perf_defconfig @@ -247,6 +247,7 @@ CONFIG_SLIMBUS=y CONFIG_SLIMBUS_MSM_NGD=y CONFIG_PINCTRL_QCS405=y CONFIG_THERMAL=y +CONFIG_MFD_SYSCON=y CONFIG_REGULATOR=y CONFIG_REGULATOR_FIXED_VOLTAGE=y CONFIG_REGULATOR_FAN53555=y diff --git a/arch/arm64/configs/qcs405_defconfig b/arch/arm64/configs/qcs405_defconfig index 4c23c8ff8396..316af5ce17a9 100644 --- a/arch/arm64/configs/qcs405_defconfig +++ b/arch/arm64/configs/qcs405_defconfig @@ -257,6 +257,7 @@ CONFIG_SLIMBUS=y CONFIG_SLIMBUS_MSM_NGD=y CONFIG_PINCTRL_QCS405=y CONFIG_THERMAL=y +CONFIG_MFD_SYSCON=y CONFIG_REGULATOR=y CONFIG_REGULATOR_FIXED_VOLTAGE=y CONFIG_REGULATOR_FAN53555=y -- GitLab From dfe3ae51740ec831b4e59349bde2a139cb68a211 Mon Sep 17 00:00:00 2001 From: Abir Ghosh Date: Sun, 9 Oct 2016 11:47:28 +0300 Subject: [PATCH 0372/1635] soc: qcom: add support for fingerprint sensor driver The QBT1000 driver provides an API for communicating with trustzone applications and handles firmware event interrupts. The driver supports the following features: - loading and unloading trustzone applications. - sending commands to trustzone applications. - voting/un-voting for clocks before/after making a trustzone call. - receiving firmware events, signalled by interrupts, and providing them to the driver client. - sending a key event in response to firmware finger detect events. - support for multiple IPC messages. - retry logic for CBGE interrupt handling. - remove clocks on/off logic. This is snapshot of the qbt1000 driver as of msm-4.4 kernel base 'd93c68b1f0bd (soc: qcom: add support for fingerprint sensor driver)' . Change-Id: I59b4294285edab6e4916528a31d0713d06d5a072 Signed-off-by: Abir Ghosh Signed-off-by: Kota Priyanka --- .../devicetree/bindings/qbt1000/qbt1000.txt | 54 + drivers/soc/qcom/Kconfig | 9 + drivers/soc/qcom/Makefile | 1 + drivers/soc/qcom/qbt1000.c | 1207 +++++++++++++++++ include/uapi/linux/Kbuild | 1 + include/uapi/linux/qbt1000.h | 99 ++ 6 files changed, 1371 insertions(+) create mode 100644 Documentation/devicetree/bindings/qbt1000/qbt1000.txt create mode 100644 drivers/soc/qcom/qbt1000.c create mode 100644 include/uapi/linux/qbt1000.h diff --git a/Documentation/devicetree/bindings/qbt1000/qbt1000.txt b/Documentation/devicetree/bindings/qbt1000/qbt1000.txt new file mode 100644 index 000000000000..c9861e4948f9 --- /dev/null +++ b/Documentation/devicetree/bindings/qbt1000/qbt1000.txt @@ -0,0 +1,54 @@ +Qualcomm Technologies, Inc. QBT1000 Specific Bindings + +QBT is a fingerprint sensor ASIC capable of performing fingerprint image scans +and detecting finger presence on the sensor using programmable firmware. + +======================= +Required Node Structure +======================= + +- compatible + Usage: required + Value type: + Definition: "qcom,qbt1000". + +- clock-names + Usage: required + Value type: + Definition: List of clock names that need to be voted on/off. + +- clocks + Usage: required + Value type: + Definition: Property pair that represents the clock controller and the clock + id. This in combination with the clock-name is used to obtain + the handle for the clock that needs to be voted on/off. + +- clock-frequency + Usage: required + Value type: + Definition: Frequency of clock in Hz. + +- qcom,ipc-gpio + Usage: required + Value type: + Definition: phandle for GPIO to be used for IPC. + +- qcom,finger-detect-gpio + Usage: required + Value type: + Definition: phandle for GPIO to be used for finger detect. + +======= +Example +======= + +qcom,qbt1000 { + compatible = "qcom,qbt1000"; + clock-names = "core", "iface"; + clocks = <&clock_gcc clk_gcc_blsp2_qup6_spi_apps_clk>, + <&clock_gcc clk_gcc_blsp2_ahb_clk>; + clock-frequency = <15000000>; + qcom,ipc-gpio = <&tlmm 121 0>; + qcom,finger-detect-gpio = <&pmcobalt_gpios 2 0>; +}; diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig index de13a1e48bf0..81faf6fd8446 100644 --- a/drivers/soc/qcom/Kconfig +++ b/drivers/soc/qcom/Kconfig @@ -534,6 +534,15 @@ config MSM_NOPM This enables bare minimum support of power management at platform level. i.e WFI +config MSM_QBT1000 + bool "QBT1000 Ultrasonic Fingerprint Sensor" + help + This driver provides services for configuring the fingerprint + sensor hardware and for communicating with the trusted app which + uses it. It enables clocks and provides commands for loading + trusted apps, unloading them and marshalling buffers to the + trusted fingerprint app. + config APSS_CORE_EA depends on CPU_FREQ && PM_OPP bool "Qualcomm Technology Inc specific power aware driver" diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile index 0c8797fdee82..c2fe72a44ec3 100644 --- a/drivers/soc/qcom/Makefile +++ b/drivers/soc/qcom/Makefile @@ -61,6 +61,7 @@ obj-$(CONFIG_QSEE_IPC_IRQ) += qsee_ipc_irq.o obj-$(CONFIG_QCOM_GLINK) += glink_probe.o obj-$(CONFIG_QCOM_GLINK_PKT) += glink_pkt.o obj-$(CONFIG_QCOM_QDSS_BRIDGE) += qdss_bridge.o +obj-$(CONFIG_MSM_QBT1000) += qbt1000.o obj-$(CONFIG_MSM_EVENT_TIMER) += event_timer.o obj-$(CONFIG_MSM_IDLE_STATS) += lpm-stats.o obj-$(CONFIG_QTI_RPM_STATS_LOG) += rpm_stats.o diff --git a/drivers/soc/qcom/qbt1000.c b/drivers/soc/qcom/qbt1000.c new file mode 100644 index 000000000000..c75234141a57 --- /dev/null +++ b/drivers/soc/qcom/qbt1000.c @@ -0,0 +1,1207 @@ +/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#define DEBUG +#define pr_fmt(fmt) "qbt1000:%s: " fmt, __func__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "../../misc/qseecom_kernel.h" + +#define QBT1000_DEV "qbt1000" +#define QBT1000_IN_DEV_NAME "qbt1000_key_input" +#define QBT1000_IN_DEV_VERSION 0x0100 +#define MAX_FW_EVENTS 128 +#define FP_APP_CMD_RX_IPC 132 +#define FW_MAX_IPC_MSG_DATA_SIZE 0x500 +#define IPC_MSG_ID_CBGE_REQUIRED 29 + +/* + * shared buffer size - init with max value, + * user space will provide new value upon tz app load + */ +static uint32_t g_app_buf_size = SZ_256K; +static char const *const FP_APP_NAME = "fingerpr"; + +struct finger_detect_gpio { + int gpio; + int active_low; + int irq; + struct work_struct work; + unsigned int key_code; + int power_key_enabled; + int last_gpio_state; + int event_reported; +}; + +struct fw_event_desc { + enum qbt1000_fw_event ev; +}; + +struct fw_ipc_info { + int gpio; + int irq; +}; + +struct qbt1000_drvdata { + struct class *qbt1000_class; + struct cdev qbt1000_cdev; + struct device *dev; + char *qbt1000_node; + struct clk **clocks; + unsigned int clock_count; + uint8_t clock_state; + unsigned int root_clk_idx; + unsigned int frequency; + atomic_t available; + struct mutex mutex; + struct mutex fw_events_mutex; + struct input_dev *in_dev; + struct fw_ipc_info fw_ipc; + struct finger_detect_gpio fd_gpio; + DECLARE_KFIFO(fw_events, struct fw_event_desc, MAX_FW_EVENTS); + wait_queue_head_t read_wait_queue; + struct qseecom_handle *app_handle; + struct qseecom_handle *fp_app_handle; +}; + +/* + * struct fw_ipc_cmd - + * used to store IPC commands to/from firmware + * @status - indicates whether sending/getting the IPC message was successful + * @msg_type - the type of IPC message + * @msg_len - the length of the message data + * @resp_needed - whether a response is needed for this message + * @msg_data - any extra data associated with the message + */ +struct fw_ipc_cmd { + uint32_t status; + uint32_t numMsgs; + uint8_t msg_data[FW_MAX_IPC_MSG_DATA_SIZE]; +}; + +struct fw_ipc_header { + uint32_t msg_type; + uint32_t msg_len; + uint32_t resp_needed; +}; + +/* + * struct ipc_msg_type_to_fw_event - + * entry in mapping between an IPC message type to a firmware event + * @msg_type - IPC message type, as reported by firmware + * @fw_event - corresponding firmware event code to report to driver client + */ +struct ipc_msg_type_to_fw_event { + uint32_t msg_type; + enum qbt1000_fw_event fw_event; +}; + +/* mapping between firmware IPC message types to HLOS firmware events */ +struct ipc_msg_type_to_fw_event g_msg_to_event[] = { + {IPC_MSG_ID_CBGE_REQUIRED, FW_EVENT_CBGE_REQUIRED} +}; + +/** + * get_cmd_rsp_buffers() - Function sets cmd & rsp buffer pointers and + * aligns buffer lengths + * @hdl: index of qseecom_handle + * @cmd: req buffer - set to qseecom_handle.sbuf + * @cmd_len: ptr to req buffer len + * @rsp: rsp buffer - set to qseecom_handle.sbuf + offset + * @rsp_len: ptr to rsp buffer len + * + * Return: 0 on success. Error code on failure. + */ +static int get_cmd_rsp_buffers(struct qseecom_handle *hdl, + void **cmd, + uint32_t *cmd_len, + void **rsp, + uint32_t *rsp_len) +{ + /* 64 bytes alignment for QSEECOM */ + *cmd_len = ALIGN(*cmd_len, 64); + *rsp_len = ALIGN(*rsp_len, 64); + + if (((uint64_t)*rsp_len + (uint64_t)*cmd_len) + > (uint64_t)g_app_buf_size) { + pr_err("buffer too small to hold cmd=%d and rsp=%d\n", + *cmd_len, *rsp_len); + return -ENOMEM; + } + + *cmd = hdl->sbuf; + *rsp = hdl->sbuf + *cmd_len; + return 0; +} + +/** + * send_tz_cmd() - Function sends a command to TZ + * + * @drvdata: pointer to driver data + * @app_handle: handle to tz app + * @is_user_space: 1 if the cmd buffer is in user space, 0 + * otherwise + * @cmd: command buffer to send + * @cmd_len: length of the command buffer + * @rsp: output, will be set to location of response buffer + * @rsp_len: max size of response + * + * Return: 0 on success. + */ +static int send_tz_cmd(struct qbt1000_drvdata *drvdata, + struct qseecom_handle *app_handle, + int is_user_space, + void *cmd, uint32_t cmd_len, + void **rsp, uint32_t rsp_len) +{ + int rc = 0; + void *aligned_cmd; + void *aligned_rsp; + uint32_t aligned_cmd_len; + uint32_t aligned_rsp_len; + + /* init command and response buffers and align lengths */ + aligned_cmd_len = cmd_len; + aligned_rsp_len = rsp_len; + + rc = get_cmd_rsp_buffers(app_handle, + (void **)&aligned_cmd, + &aligned_cmd_len, + (void **)&aligned_rsp, + &aligned_rsp_len); + + if (rc != 0) + goto end; + + if (!aligned_cmd) { + dev_err(drvdata->dev, "%s: Null command buffer\n", + __func__); + rc = -EINVAL; + goto end; + } + + if (aligned_cmd - cmd + cmd_len > g_app_buf_size) { + rc = -ENOMEM; + goto end; + } + + if (is_user_space) { + rc = copy_from_user(aligned_cmd, (void __user *)cmd, + cmd_len); + if (rc != 0) { + pr_err("failure to copy user space buf %d\n", rc); + rc = -EFAULT; + goto end; + } + } else + memcpy(aligned_cmd, cmd, cmd_len); + + /* send cmd to TZ */ + rc = qseecom_send_command(app_handle, + aligned_cmd, + aligned_cmd_len, + aligned_rsp, + aligned_rsp_len); + + if (rc != 0) { + pr_err("failure to send tz cmd %d\n", rc); + goto end; + } + + *rsp = aligned_rsp; + +end: + return rc; +} + +/** + * qbt1000_open() - Function called when user space opens device. + * Successful if driver not currently open. + * @inode: ptr to inode object + * @file: ptr to file object + * + * Return: 0 on success. Error code on failure. + */ +static int qbt1000_open(struct inode *inode, struct file *file) +{ + int rc = 0; + + struct qbt1000_drvdata *drvdata = container_of(inode->i_cdev, + struct qbt1000_drvdata, + qbt1000_cdev); + file->private_data = drvdata; + + pr_debug("%s begin\n", __func__); + /* disallowing concurrent opens */ + if (!atomic_dec_and_test(&drvdata->available)) { + atomic_inc(&drvdata->available); + rc = -EBUSY; + } + + pr_debug("%s end : %d\n", __func__, rc); + return rc; +} + +/** + * qbt1000_release() - Function called when user space closes device. + + * @inode: ptr to inode object + * @file: ptr to file object + * + * Return: 0 on success. Error code on failure. + */ +static int qbt1000_release(struct inode *inode, struct file *file) +{ + struct qbt1000_drvdata *drvdata; + + if (!file || !file->private_data) { + pr_err("%s: NULL pointer passed", __func__); + return -EINVAL; + } + drvdata = file->private_data; + atomic_inc(&drvdata->available); + return 0; +} + +/** + * qbt1000_ioctl() - Function called when user space calls ioctl. + * @file: struct file - not used + * @cmd: cmd identifier:QBT1000_LOAD_APP,QBT1000_UNLOAD_APP, + * QBT1000_SEND_TZCMD + * @arg: ptr to relevant structe: either qbt1000_app or + * qbt1000_send_tz_cmd depending on which cmd is passed + * + * Return: 0 on success. Error code on failure. + */ +static long qbt1000_ioctl( + struct file *file, unsigned int cmd, unsigned long arg) +{ + int rc = 0; + void __user *priv_arg = (void __user *)arg; + struct qbt1000_drvdata *drvdata; + + if (!file || !file->private_data) { + pr_err("%s: NULL pointer passed", __func__); + return -EINVAL; + } + + drvdata = file->private_data; + + mutex_lock(&drvdata->mutex); + + pr_debug("%s %d\n", __func__, cmd); + + switch (cmd) { + case QBT1000_LOAD_APP: + { + struct qbt1000_app app; + struct qseecom_handle *app_handle; + + if (copy_from_user(&app, priv_arg, + sizeof(app)) != 0) { + rc = -EFAULT; + pr_err("failed copy from user space-LOAD\n"); + goto end; + } + + if (!app.app_handle) { + dev_err(drvdata->dev, "%s: LOAD app_handle is null\n", + __func__); + rc = -EINVAL; + goto end; + } + + if (drvdata->app_handle) { + dev_err(drvdata->dev, "%s: LOAD app already loaded, unloading first\n", + __func__); + drvdata->fp_app_handle = 0; + rc = qseecom_shutdown_app(&drvdata->app_handle); + if (rc != 0) { + dev_err(drvdata->dev, "%s: LOAD current app failed to shutdown\n", + __func__); + goto end; + } + } + + pr_debug("app %s load before\n", app.name); + + /* start the TZ app */ + rc = qseecom_start_app( + &drvdata->app_handle, app.name, app.size); + if (rc == 0) { + g_app_buf_size = app.size; + rc = qseecom_set_bandwidth(drvdata->app_handle, + app.high_band_width == 1 ? true : false); + if (rc != 0) { + /* log error, allow to continue */ + pr_err("App %s failed to set bw\n", app.name); + } + } else { + pr_err("app %s failed to load\n", app.name); + goto end; + } + + /* copy a fake app handle to user */ + app_handle = drvdata->app_handle ? + (struct qseecom_handle *)123456 : 0; + rc = copy_to_user((void __user *)app.app_handle, &app_handle, + sizeof(*app.app_handle)); + + if (rc != 0) { + dev_err(drvdata->dev, + "%s: Failed copy 2us LOAD rc:%d\n", + __func__, rc); + rc = -ENOMEM; + goto end; + } + + pr_debug("app %s load after\n", app.name); + + if (!strcmp(app.name, FP_APP_NAME)) + drvdata->fp_app_handle = drvdata->app_handle; + + break; + } + case QBT1000_UNLOAD_APP: + { + struct qbt1000_app app; + struct qseecom_handle *app_handle = 0; + + if (copy_from_user(&app, priv_arg, + sizeof(app)) != 0) { + rc = -ENOMEM; + pr_err("failed copy from user space-UNLOAD\n"); + goto end; + } + + if (!app.app_handle) { + dev_err(drvdata->dev, "%s: UNLOAD app_handle is null\n", + __func__); + rc = -EINVAL; + goto end; + } + + rc = copy_from_user(&app_handle, app.app_handle, + sizeof(app_handle)); + + if (rc != 0) { + dev_err(drvdata->dev, + "%s: Failed copy from user space-UNLOAD handle rc:%d\n", + __func__, rc); + rc = -ENOMEM; + goto end; + } + + /* if the app hasn't been loaded already, return err */ + if (!drvdata->app_handle) { + pr_err("app not loaded\n"); + rc = -EINVAL; + goto end; + } + + if (drvdata->fp_app_handle == drvdata->app_handle) + drvdata->fp_app_handle = 0; + + /* set bw & shutdown the TZ app */ + qseecom_set_bandwidth(drvdata->app_handle, + app.high_band_width == 1 ? true : false); + rc = qseecom_shutdown_app(&drvdata->app_handle); + if (rc != 0) { + pr_err("app failed to shutdown\n"); + goto end; + } + + /* copy the app handle (should be null) to user */ + rc = copy_to_user((void __user *)app.app_handle, &app_handle, + sizeof(*app.app_handle)); + + if (rc != 0) { + dev_err(drvdata->dev, + "%s: Failed copy 2us UNLOAD rc:%d\n", + __func__, rc); + rc = -ENOMEM; + goto end; + } + + break; + } + case QBT1000_SEND_TZCMD: + { + struct qbt1000_send_tz_cmd tzcmd; + void *rsp_buf; + + if (copy_from_user(&tzcmd, priv_arg, + sizeof(tzcmd)) + != 0) { + rc = -EFAULT; + pr_err("failed copy from user space %d\n", rc); + goto end; + } + + if (tzcmd.req_buf_len > g_app_buf_size || + tzcmd.rsp_buf_len > g_app_buf_size) { + rc = -ENOMEM; + pr_err("invalid cmd buf len, req=%d, rsp=%d\n", + tzcmd.req_buf_len, tzcmd.rsp_buf_len); + goto end; + } + + /* if the app hasn't been loaded already, return err */ + if (!drvdata->app_handle) { + pr_err("app not loaded\n"); + rc = -EINVAL; + goto end; + } + + rc = send_tz_cmd(drvdata, + drvdata->app_handle, 1, + tzcmd.req_buf, tzcmd.req_buf_len, + &rsp_buf, tzcmd.rsp_buf_len); + + if (rc < 0) { + pr_err("failure sending command to tz\n"); + goto end; + } + + /* copy rsp buf back to user space buffer */ + rc = copy_to_user((void __user *)tzcmd.rsp_buf, + rsp_buf, tzcmd.rsp_buf_len); + if (rc != 0) { + pr_err("failed copy 2us rc:%d bytes %d:\n", + rc, tzcmd.rsp_buf_len); + rc = -EFAULT; + goto end; + } + + break; + } + case QBT1000_SET_FINGER_DETECT_KEY: + { + struct qbt1000_set_finger_detect_key set_fd_key; + + if (copy_from_user(&set_fd_key, priv_arg, + sizeof(set_fd_key)) + != 0) { + rc = -EFAULT; + pr_err("failed copy from user space %d\n", rc); + goto end; + } + + drvdata->fd_gpio.key_code = set_fd_key.key_code; + + break; + } + case QBT1000_CONFIGURE_POWER_KEY: + { + struct qbt1000_configure_power_key power_key; + + if (copy_from_user(&power_key, priv_arg, + sizeof(power_key)) + != 0) { + rc = -EFAULT; + pr_err("failed copy from user space %d\n", rc); + goto end; + } + + drvdata->fd_gpio.power_key_enabled = power_key.enable; + + break; + } + default: + pr_err("invalid cmd %d\n", cmd); + rc = -ENOIOCTLCMD; + goto end; + } + +end: + mutex_unlock(&drvdata->mutex); + return rc; +} + +static int get_events_fifo_len_locked(struct qbt1000_drvdata *drvdata) +{ + int len; + + mutex_lock(&drvdata->fw_events_mutex); + len = kfifo_len(&drvdata->fw_events); + mutex_unlock(&drvdata->fw_events_mutex); + + return len; +} + +static ssize_t qbt1000_read(struct file *filp, char __user *ubuf, + size_t cnt, loff_t *ppos) +{ + struct fw_event_desc fw_event; + struct qbt1000_drvdata *drvdata = filp->private_data; + + if (cnt < sizeof(fw_event.ev)) + return -EINVAL; + + mutex_lock(&drvdata->fw_events_mutex); + + while (kfifo_len(&drvdata->fw_events) == 0) { + mutex_unlock(&drvdata->fw_events_mutex); + + if (filp->f_flags & O_NONBLOCK) + return -EAGAIN; + + pr_debug("fw_events fifo: empty, waiting\n"); + + if (wait_event_interruptible(drvdata->read_wait_queue, + (get_events_fifo_len_locked(drvdata) > 0))) + return -ERESTARTSYS; + + mutex_lock(&drvdata->fw_events_mutex); + } + + if (!kfifo_get(&drvdata->fw_events, &fw_event)) { + pr_debug("fw_events fifo: unexpectedly empty\n"); + + mutex_unlock(&drvdata->fw_events_mutex); + return -EINVAL; + } + + mutex_unlock(&drvdata->fw_events_mutex); + + pr_debug("fw_event: %d\n", (int)fw_event.ev); + return copy_to_user(ubuf, &fw_event.ev, sizeof(fw_event.ev)); +} + +static unsigned int qbt1000_poll(struct file *filp, + struct poll_table_struct *wait) +{ + struct qbt1000_drvdata *drvdata = filp->private_data; + unsigned int mask = 0; + + poll_wait(filp, &drvdata->read_wait_queue, wait); + + if (kfifo_len(&drvdata->fw_events) > 0) + mask |= (POLLIN | POLLRDNORM); + + return mask; +} + +static const struct file_operations qbt1000_fops = { + .owner = THIS_MODULE, + .unlocked_ioctl = qbt1000_ioctl, + .open = qbt1000_open, + .release = qbt1000_release, + .read = qbt1000_read, + .poll = qbt1000_poll +}; + +static int qbt1000_dev_register(struct qbt1000_drvdata *drvdata) +{ + dev_t dev_no; + int ret = 0; + size_t node_size; + char *node_name = QBT1000_DEV; + struct device *dev = drvdata->dev; + struct device *device; + + node_size = strlen(node_name) + 1; + + drvdata->qbt1000_node = devm_kzalloc(dev, node_size, GFP_KERNEL); + if (!drvdata->qbt1000_node) { + ret = -ENOMEM; + goto err_alloc; + } + + strlcpy(drvdata->qbt1000_node, node_name, node_size); + + ret = alloc_chrdev_region(&dev_no, 0, 1, drvdata->qbt1000_node); + if (ret) { + pr_err("alloc_chrdev_region failed %d\n", ret); + goto err_alloc; + } + + cdev_init(&drvdata->qbt1000_cdev, &qbt1000_fops); + + drvdata->qbt1000_cdev.owner = THIS_MODULE; + ret = cdev_add(&drvdata->qbt1000_cdev, dev_no, 1); + if (ret) { + pr_err("cdev_add failed %d\n", ret); + goto err_cdev_add; + } + + drvdata->qbt1000_class = class_create(THIS_MODULE, + drvdata->qbt1000_node); + if (IS_ERR(drvdata->qbt1000_class)) { + ret = PTR_ERR(drvdata->qbt1000_class); + pr_err("class_create failed %d\n", ret); + goto err_class_create; + } + + device = device_create(drvdata->qbt1000_class, NULL, + drvdata->qbt1000_cdev.dev, drvdata, + drvdata->qbt1000_node); + if (IS_ERR(device)) { + ret = PTR_ERR(device); + pr_err("device_create failed %d\n", ret); + goto err_dev_create; + } + + return 0; +err_dev_create: + class_destroy(drvdata->qbt1000_class); +err_class_create: + cdev_del(&drvdata->qbt1000_cdev); +err_cdev_add: + unregister_chrdev_region(drvdata->qbt1000_cdev.dev, 1); +err_alloc: + return ret; +} + +/** + * qbt1000_create_input_device() - Function allocates an input + * device, configures it for key events and registers it + * + * @drvdata: ptr to driver data + * + * Return: 0 on success. Error code on failure. + */ +static int qbt1000_create_input_device(struct qbt1000_drvdata *drvdata) +{ + int rc = 0; + + drvdata->in_dev = input_allocate_device(); + if (drvdata->in_dev == NULL) { + dev_err(drvdata->dev, "%s: input_allocate_device() failed\n", + __func__); + rc = -ENOMEM; + goto end; + } + + drvdata->in_dev->name = QBT1000_IN_DEV_NAME; + drvdata->in_dev->phys = NULL; + drvdata->in_dev->id.bustype = BUS_HOST; + drvdata->in_dev->id.vendor = 0x0001; + drvdata->in_dev->id.product = 0x0001; + drvdata->in_dev->id.version = QBT1000_IN_DEV_VERSION; + + drvdata->in_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); + drvdata->in_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); + + drvdata->in_dev->keybit[BIT_WORD(KEY_HOMEPAGE)] |= + BIT_MASK(KEY_HOMEPAGE); + drvdata->in_dev->keybit[BIT_WORD(KEY_CAMERA)] |= + BIT_MASK(KEY_CAMERA); + drvdata->in_dev->keybit[BIT_WORD(KEY_VOLUMEDOWN)] |= + BIT_MASK(KEY_VOLUMEDOWN); + drvdata->in_dev->keybit[BIT_WORD(KEY_POWER)] |= + BIT_MASK(KEY_POWER); + + input_set_abs_params(drvdata->in_dev, ABS_X, + 0, + 1000, + 0, 0); + input_set_abs_params(drvdata->in_dev, ABS_Y, + 0, + 1000, + 0, 0); + + rc = input_register_device(drvdata->in_dev); + if (rc) { + dev_err(drvdata->dev, "%s: input_reg_dev() failed %d\n", + __func__, rc); + goto end; + } + +end: + if (rc) + input_free_device(drvdata->in_dev); + return rc; +} + +static void purge_finger_events(struct qbt1000_drvdata *drvdata) +{ + int i, fifo_len; + struct fw_event_desc fw_event; + + fifo_len = kfifo_len(&drvdata->fw_events); + + for (i = 0; i < fifo_len; i++) { + if (!kfifo_get(&drvdata->fw_events, &fw_event)) + pr_err("fw events fifo: could not remove oldest item\n"); + else if (fw_event.ev != FW_EVENT_FINGER_DOWN + && fw_event.ev != FW_EVENT_FINGER_UP) + kfifo_put(&drvdata->fw_events, fw_event); + } +} + +static void qbt1000_gpio_report_event(struct qbt1000_drvdata *drvdata) +{ + int state; + struct fw_event_desc fw_event; + + state = (__gpio_get_value(drvdata->fd_gpio.gpio) ? 1 : 0) + ^ drvdata->fd_gpio.active_low; + + if (drvdata->fd_gpio.event_reported + && state == drvdata->fd_gpio.last_gpio_state) + return; + + pr_debug("gpio %d: report state %d\n", drvdata->fd_gpio.gpio, state); + + drvdata->fd_gpio.event_reported = 1; + drvdata->fd_gpio.last_gpio_state = state; + + if (drvdata->fd_gpio.key_code) { + input_event(drvdata->in_dev, EV_KEY, + drvdata->fd_gpio.key_code, !!state); + input_sync(drvdata->in_dev); + } + + if (state && drvdata->fd_gpio.power_key_enabled) { + input_event(drvdata->in_dev, EV_KEY, KEY_POWER, 1); + input_sync(drvdata->in_dev); + input_event(drvdata->in_dev, EV_KEY, KEY_POWER, 0); + input_sync(drvdata->in_dev); + } + + fw_event.ev = (state ? FW_EVENT_FINGER_DOWN : FW_EVENT_FINGER_UP); + + mutex_lock(&drvdata->fw_events_mutex); + + if (kfifo_is_full(&drvdata->fw_events)) { + struct fw_event_desc dummy_fw_event; + + pr_warn("fw events fifo: full, dropping oldest item\n"); + if (!kfifo_get(&drvdata->fw_events, &dummy_fw_event)) + pr_err("fw events fifo: could not remove oldest item\n"); + } + + purge_finger_events(drvdata); + + if (!kfifo_put(&drvdata->fw_events, fw_event)) + pr_err("fw events fifo: error adding item\n"); + + mutex_unlock(&drvdata->fw_events_mutex); + wake_up_interruptible(&drvdata->read_wait_queue); +} + +static void qbt1000_gpio_work_func(struct work_struct *work) +{ + struct qbt1000_drvdata *drvdata = + container_of(work, struct qbt1000_drvdata, fd_gpio.work); + + qbt1000_gpio_report_event(drvdata); + + pm_relax(drvdata->dev); +} + +static irqreturn_t qbt1000_gpio_isr(int irq, void *dev_id) +{ + struct qbt1000_drvdata *drvdata = dev_id; + + if (irq != drvdata->fd_gpio.irq) { + pr_warn("invalid irq %d (expected %d)\n", + irq, drvdata->fd_gpio.irq); + return IRQ_HANDLED; + } + + pm_stay_awake(drvdata->dev); + schedule_work(&drvdata->fd_gpio.work); + + return IRQ_HANDLED; +} + +/** + * qbt1000_ipc_irq_handler() - function processes IPC + * interrupts on its own thread + * @irq: the interrupt that occurred + * @dev_id: pointer to the qbt1000_drvdata + * + * Return: IRQ_HANDLED when complete + */ +static irqreturn_t qbt1000_ipc_irq_handler(int irq, void *dev_id) +{ + uint8_t *msg_buffer; + struct fw_ipc_cmd *rx_cmd; + struct fw_ipc_header *header; + int i, j; + uint32_t rxipc = FP_APP_CMD_RX_IPC; + struct qbt1000_drvdata *drvdata = (struct qbt1000_drvdata *)dev_id; + int rc = 0; + uint32_t retry_count = 10; + + pm_stay_awake(drvdata->dev); + + mutex_lock(&drvdata->mutex); + + if (irq != drvdata->fw_ipc.irq) { + pr_warn("invalid irq %d (expected %d)\n", + irq, drvdata->fw_ipc.irq); + goto end; + } + + pr_debug("firmware interrupt received (irq %d)\n", irq); + + if (!drvdata->fp_app_handle) + goto end; + + while (retry_count > 0) { + /* + * send the TZ command to fetch the message from firmware + * TZ will process the message if it can + */ + rc = send_tz_cmd(drvdata, drvdata->fp_app_handle, 0, + &rxipc, sizeof(rxipc), + (void *)&rx_cmd, sizeof(*rx_cmd)); + if (rc < 0) { + msleep(50); // sleep for 50ms before retry + retry_count -= 1; + continue; + } else { + pr_err("retry_count %d\n", retry_count); + break; + } + } + + if (rc < 0) { + pr_err("failure sending tz cmd %d\n", rxipc); + goto end; + } + + if (rx_cmd->status != 0) { + pr_err("tz command failed to complete\n"); + goto end; + } + + msg_buffer = rx_cmd->msg_data; + + for (j = 0; j < rx_cmd->numMsgs; j++) { + header = (struct fw_ipc_header *) msg_buffer; + /* + * given the IPC message type, search for a corresponding + * event for the driver client. If found, add to the events + * FIFO + */ + for (i = 0; i < ARRAY_SIZE(g_msg_to_event); i++) { + if (g_msg_to_event[i].msg_type == header->msg_type) { + enum qbt1000_fw_event ev = + g_msg_to_event[i].fw_event; + struct fw_event_desc fw_ev_desc; + + mutex_lock(&drvdata->fw_events_mutex); + pr_debug("fw events: add %d\n", (int) ev); + fw_ev_desc.ev = ev; + + if (!kfifo_put(&drvdata->fw_events, fw_ev_desc)) + pr_err("fw events: fifo full, drop event %d\n", + (int) ev); + + mutex_unlock(&drvdata->fw_events_mutex); + break; + } + } + msg_buffer += sizeof(*header) + header->msg_len; + } + wake_up_interruptible(&drvdata->read_wait_queue); +end: + mutex_unlock(&drvdata->mutex); + pm_relax(drvdata->dev); + return IRQ_HANDLED; +} + +static int setup_fd_gpio_irq(struct platform_device *pdev, + struct qbt1000_drvdata *drvdata) +{ + int rc = 0; + int irq; + const char *desc = "qbt_finger_detect"; + + rc = devm_gpio_request_one(&pdev->dev, drvdata->fd_gpio.gpio, + GPIOF_IN, desc); + + if (rc < 0) { + pr_err("failed to request gpio %d, error %d\n", + drvdata->fd_gpio.gpio, rc); + goto end; + } + + irq = gpio_to_irq(drvdata->fd_gpio.gpio); + if (irq < 0) { + rc = irq; + pr_err("unable to get irq number for gpio %d, error %d\n", + drvdata->fd_gpio.gpio, rc); + goto end; + } + + drvdata->fd_gpio.irq = irq; + INIT_WORK(&drvdata->fd_gpio.work, qbt1000_gpio_work_func); + + rc = devm_request_any_context_irq(&pdev->dev, drvdata->fd_gpio.irq, + qbt1000_gpio_isr, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, + desc, drvdata); + + if (rc < 0) { + pr_err("unable to claim irq %d; error %d\n", + drvdata->fd_gpio.irq, rc); + goto end; + } + +end: + return rc; +} + +static int setup_ipc_irq(struct platform_device *pdev, + struct qbt1000_drvdata *drvdata) +{ + int rc = 0; + const char *desc = "qbt_ipc"; + + drvdata->fw_ipc.irq = gpio_to_irq(drvdata->fw_ipc.gpio); + pr_debug("\nirq %d gpio %d\n", + drvdata->fw_ipc.irq, drvdata->fw_ipc.gpio); + if (drvdata->fw_ipc.irq < 0) { + rc = drvdata->fw_ipc.irq; + pr_err("no irq for gpio %d, error=%d\n", + drvdata->fw_ipc.gpio, rc); + goto end; + } + + rc = devm_gpio_request_one(&pdev->dev, drvdata->fw_ipc.gpio, + GPIOF_IN, desc); + + if (rc < 0) { + pr_err("failed to request gpio %d, error %d\n", + drvdata->fw_ipc.gpio, rc); + goto end; + } + + rc = devm_request_threaded_irq(&pdev->dev, + drvdata->fw_ipc.irq, + NULL, + qbt1000_ipc_irq_handler, + IRQF_ONESHOT | IRQF_TRIGGER_RISING, + desc, + drvdata); + + if (rc < 0) { + pr_err("failed to register for ipc irq %d, rc = %d\n", + drvdata->fw_ipc.irq, rc); + goto end; + } + +end: + return rc; +} + +/** + * qbt1000_read_device_tree() - Function reads device tree + * properties into driver data + * @pdev: ptr to platform device object + * @drvdata: ptr to driver data + * + * Return: 0 on success. Error code on failure. + */ +static int qbt1000_read_device_tree(struct platform_device *pdev, + struct qbt1000_drvdata *drvdata) +{ + int rc = 0; + uint32_t rate; + int gpio; + enum of_gpio_flags flags; + + /* read clock frequency */ + if (of_property_read_u32(pdev->dev.of_node, + "clock-frequency", &rate) == 0) { + pr_debug("clk frequency %d\n", rate); + drvdata->frequency = rate; + } + + /* read IPC gpio */ + drvdata->fw_ipc.gpio = of_get_named_gpio(pdev->dev.of_node, + "qcom,ipc-gpio", 0); + if (drvdata->fw_ipc.gpio < 0) { + rc = drvdata->fw_ipc.gpio; + pr_err("ipc gpio not found, error=%d\n", rc); + goto end; + } + + /** + * TODO: Need to revisit after adding GPIO in DTSI- read + * finger detect GPIO configuration + */ + + gpio = of_get_named_gpio_flags(pdev->dev.of_node, + "qcom,finger-detect-gpio", 0, &flags); + if (gpio < 0) { + pr_err("failed to get gpio flags\n"); + rc = gpio; + goto end; + } + + drvdata->fd_gpio.gpio = gpio; + drvdata->fd_gpio.active_low = flags & OF_GPIO_ACTIVE_LOW; + +end: + return rc; +} + +/** + * qbt1000_probe() - Function loads hardware config from device tree + * @pdev: ptr to platform device object + * + * Return: 0 on success. Error code on failure. + */ +static int qbt1000_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct qbt1000_drvdata *drvdata; + int rc = 0; + + pr_debug("%s begin\n", __func__); + drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL); + if (!drvdata) + return -ENOMEM; + + drvdata->dev = &pdev->dev; + platform_set_drvdata(pdev, drvdata); + + rc = qbt1000_read_device_tree(pdev, drvdata); + if (rc < 0) + goto end; + + atomic_set(&drvdata->available, 1); + + mutex_init(&drvdata->mutex); + mutex_init(&drvdata->fw_events_mutex); + + rc = qbt1000_dev_register(drvdata); + if (rc < 0) + goto end; + + INIT_KFIFO(drvdata->fw_events); + init_waitqueue_head(&drvdata->read_wait_queue); + + rc = qbt1000_create_input_device(drvdata); + if (rc < 0) + goto end; + + rc = setup_fd_gpio_irq(pdev, drvdata); + if (rc < 0) + goto end; + + rc = setup_ipc_irq(pdev, drvdata); + if (rc < 0) + goto end; + + rc = device_init_wakeup(&pdev->dev, 1); + if (rc < 0) + goto end; + +end: + pr_debug("%s : %d\n", __func__, rc); + return rc; +} + +static int qbt1000_remove(struct platform_device *pdev) +{ + struct qbt1000_drvdata *drvdata = platform_get_drvdata(pdev); + + input_unregister_device(drvdata->in_dev); + + mutex_destroy(&drvdata->mutex); + mutex_destroy(&drvdata->fw_events_mutex); + + device_destroy(drvdata->qbt1000_class, drvdata->qbt1000_cdev.dev); + class_destroy(drvdata->qbt1000_class); + cdev_del(&drvdata->qbt1000_cdev); + unregister_chrdev_region(drvdata->qbt1000_cdev.dev, 1); + + device_init_wakeup(&pdev->dev, 0); + + return 0; +} + +static int qbt1000_suspend(struct platform_device *pdev, pm_message_t state) +{ + int rc = 0; + struct qbt1000_drvdata *drvdata = platform_get_drvdata(pdev); + + /* + * Returning an error code if driver currently making a TZ call. + * Note: The purpose of this driver is to ensure that the clocks are on + * while making a TZ call. Hence the clock check to determine if the + * driver will allow suspend to occur. + */ + if (!mutex_trylock(&drvdata->mutex)) + return -EBUSY; + + if (drvdata->clock_state) + rc = -EBUSY; + else { + enable_irq_wake(drvdata->fd_gpio.irq); + enable_irq_wake(drvdata->fw_ipc.irq); + } + + mutex_unlock(&drvdata->mutex); + + return rc; +} + +static int qbt1000_resume(struct platform_device *pdev) +{ + struct qbt1000_drvdata *drvdata = platform_get_drvdata(pdev); + + disable_irq_wake(drvdata->fd_gpio.irq); + disable_irq_wake(drvdata->fw_ipc.irq); + + return 0; +} + +static const struct of_device_id qbt1000_match[] = { + { .compatible = "qcom,qbt1000" }, + {} +}; + +static struct platform_driver qbt1000_plat_driver = { + .probe = qbt1000_probe, + .remove = qbt1000_remove, + .suspend = qbt1000_suspend, + .resume = qbt1000_resume, + .driver = { + .name = "qbt1000", + .owner = THIS_MODULE, + .of_match_table = qbt1000_match, + }, +}; + +module_platform_driver(qbt1000_plat_driver); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("Qualcomm Technologies, Inc. QBT1000 driver"); diff --git a/include/uapi/linux/Kbuild b/include/uapi/linux/Kbuild index 983370997ced..f6f352105544 100644 --- a/include/uapi/linux/Kbuild +++ b/include/uapi/linux/Kbuild @@ -5,6 +5,7 @@ no-export-headers += a.out.h endif header-y += hbtp_input.h +header-y += qbt1000.h ifeq ($(wildcard $(srctree)/arch/$(SRCARCH)/include/uapi/asm/kvm.h),) no-export-headers += kvm.h diff --git a/include/uapi/linux/qbt1000.h b/include/uapi/linux/qbt1000.h new file mode 100644 index 000000000000..a4f0dcad8b6d --- /dev/null +++ b/include/uapi/linux/qbt1000.h @@ -0,0 +1,99 @@ +#ifndef _UAPI_QBT1000_H_ +#define _UAPI_QBT1000_H_ + +#define MAX_NAME_SIZE 32 + +/* + * enum qbt1000_commands - + * enumeration of command options + * @QBT1000_LOAD_APP - cmd loads TZ app + * @QBT1000_UNLOAD_APP - cmd unloads TZ app + * @QBT1000_SEND_TZCMD - sends cmd to TZ app + * @QBT1000_SET_FINGER_DETECT_KEY - sets the input key to send on finger detect + * @QBT1000_CONFIGURE_POWER_KEY - enables/disables sending the power key on + finger down events +*/ +enum qbt1000_commands { + QBT1000_LOAD_APP = 100, + QBT1000_UNLOAD_APP = 101, + QBT1000_SEND_TZCMD = 102, + QBT1000_SET_FINGER_DETECT_KEY = 103, + QBT1000_CONFIGURE_POWER_KEY = 104 +}; + +/* + * enum qbt1000_fw_event - + * enumeration of firmware events + * @FW_EVENT_FINGER_DOWN - finger down detected + * @FW_EVENT_FINGER_UP - finger up detected + * @FW_EVENT_INDICATION - an indication IPC from the firmware is pending + */ +enum qbt1000_fw_event { + FW_EVENT_FINGER_DOWN = 1, + FW_EVENT_FINGER_UP = 2, + FW_EVENT_CBGE_REQUIRED = 3, +}; + +/* + * struct qbt1000_app - + * used to load and unload apps in TZ + * @app_handle - qseecom handle for clients + * @name - Name of secure app to load + * @size - Size of requested buffer of secure app + * @high_band_width - 1 - for high bandwidth usage + * 0 - for normal bandwidth usage + */ +struct qbt1000_app { + struct qseecom_handle **app_handle; + char name[MAX_NAME_SIZE]; + uint32_t size; + uint8_t high_band_width; +}; + +/* + * struct qbt1000_send_tz_cmd - + * used to cmds to TZ App + * @app_handle - qseecom handle for clients + * @req_buf - Buffer containing request for secure app + * @req_buf_len - Length of request buffer + * @rsp_buf - Buffer containing response from secure app + * @rsp_buf_len - Length of response buffer + */ +struct qbt1000_send_tz_cmd { + struct qseecom_handle *app_handle; + uint8_t *req_buf; + uint32_t req_buf_len; + uint8_t *rsp_buf; + uint32_t rsp_buf_len; +}; + +/* + * struct qbt1000_erie_event - + * used to receive events from Erie + * @buf - Buffer containing event from Erie + * @buf_len - Length of buffer + */ +struct qbt1000_erie_event { + uint8_t *buf; + uint32_t buf_len; +}; + +/* + * struct qbt1000_set_finger_detect_key - + * used to configure the input key which is sent on finger down/up event + * @key_code - Key code to send on finger down/up. 0 disables sending key events + */ +struct qbt1000_set_finger_detect_key { + unsigned int key_code; +}; + +/* + * struct qbt1000_configure_power_key - + * used to configure whether the power key is sent on finger down + * @enable - if non-zero, power key is sent on finger down + */ +struct qbt1000_configure_power_key { + unsigned int enable; +}; + +#endif /* _UAPI_QBT1000_H_ */ -- GitLab From 7b96bcfe6f96b2be4c357af113c3f0c0427981dd Mon Sep 17 00:00:00 2001 From: Abir Ghosh Date: Tue, 2 May 2017 22:41:06 +0530 Subject: [PATCH 0373/1635] qbt1000: Validate FP app name before qseecom_start_app Validate the name of the client app before passing it to qseecom_start_app. CRs-Fixed: 2006695 Change-Id: I9c6b16050d4f6fc94827021c7b0f2ab292452f60 Signed-off-by: Abir Ghosh Signed-off-by: Kota Priyanka --- drivers/soc/qcom/qbt1000.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/drivers/soc/qcom/qbt1000.c b/drivers/soc/qcom/qbt1000.c index c75234141a57..b9e94b5d61dd 100644 --- a/drivers/soc/qcom/qbt1000.c +++ b/drivers/soc/qcom/qbt1000.c @@ -342,6 +342,13 @@ static long qbt1000_ioctl( goto end; } + if (strcmp(app.name, FP_APP_NAME)) { + dev_err(drvdata->dev, "%s: Invalid app name\n", + __func__); + rc = -EINVAL; + goto end; + } + if (drvdata->app_handle) { dev_err(drvdata->dev, "%s: LOAD app already loaded, unloading first\n", __func__); @@ -388,9 +395,7 @@ static long qbt1000_ioctl( pr_debug("app %s load after\n", app.name); - if (!strcmp(app.name, FP_APP_NAME)) - drvdata->fp_app_handle = drvdata->app_handle; - + drvdata->fp_app_handle = drvdata->app_handle; break; } case QBT1000_UNLOAD_APP: -- GitLab From 3c75efaf9b3cf25a70d4474778d3b8e4ceaf297d Mon Sep 17 00:00:00 2001 From: Abir Ghosh Date: Tue, 11 Apr 2017 10:10:23 +0530 Subject: [PATCH 0374/1635] qbt1000: Initialize drvdata structure before usage Fix uninitialized local variable error which might have lead to crash. CRs-Fixed: 2030137 Change-Id: I3fd95cb343c3175e4190c8ebfe209399db0602a6 Signed-off-by: Abir Ghosh Signed-off-by: Kota Priyanka --- drivers/soc/qcom/qbt1000.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/soc/qcom/qbt1000.c b/drivers/soc/qcom/qbt1000.c index b9e94b5d61dd..4e7b759ac810 100644 --- a/drivers/soc/qcom/qbt1000.c +++ b/drivers/soc/qcom/qbt1000.c @@ -318,6 +318,12 @@ static long qbt1000_ioctl( drvdata = file->private_data; + if (IS_ERR(priv_arg)) { + dev_err(drvdata->dev, "%s: invalid user space pointer %lu\n", + __func__, arg); + return -EINVAL; + } + mutex_lock(&drvdata->mutex); pr_debug("%s %d\n", __func__, cmd); -- GitLab From f05c122197e45599a778eeeddd614fad59042020 Mon Sep 17 00:00:00 2001 From: Abir Ghosh Date: Tue, 11 Apr 2017 10:01:15 +0530 Subject: [PATCH 0375/1635] qbt1000: Terminate fingerprint TA name with null Terminate the string, coming from userspace and containing the name of fingerprint trusted app, with null character, to make sure kernel memory does not leak into logs Change-Id: I1668a64fcb6747ce3ef3b1ee6321fa5fa4a1798a CRs-Fixed: 2029409 Signed-off-by: Abir Ghosh Signed-off-by: Kota Priyanka --- drivers/soc/qcom/qbt1000.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/soc/qcom/qbt1000.c b/drivers/soc/qcom/qbt1000.c index 4e7b759ac810..a9a7a19a845c 100644 --- a/drivers/soc/qcom/qbt1000.c +++ b/drivers/soc/qcom/qbt1000.c @@ -368,6 +368,7 @@ static long qbt1000_ioctl( } pr_debug("app %s load before\n", app.name); + app.name[MAX_NAME_SIZE - 1] = '\0'; /* start the TZ app */ rc = qseecom_start_app( @@ -381,7 +382,8 @@ static long qbt1000_ioctl( pr_err("App %s failed to set bw\n", app.name); } } else { - pr_err("app %s failed to load\n", app.name); + dev_err(drvdata->dev, "%s: Fingerprint Trusted App failed to load\n", + __func__); goto end; } -- GitLab From 0e8b39234e25599911424c5b422b6beb97559a55 Mon Sep 17 00:00:00 2001 From: Abir Ghosh Date: Fri, 12 May 2017 09:16:34 +0530 Subject: [PATCH 0376/1635] qbt1000: Fix for incorrect buffer size check and integer overflow Fix an incorrect buffer size check which might have caused integer overflow. CRs-Fixed: 2045285 Change-Id: I3b5b996c7405f51b488d6cbda31c81a9a9905f23 Signed-off-by: Abir Ghosh Signed-off-by: Kota Priyanka --- drivers/soc/qcom/qbt1000.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/drivers/soc/qcom/qbt1000.c b/drivers/soc/qcom/qbt1000.c index a9a7a19a845c..5323a9fe5e77 100644 --- a/drivers/soc/qcom/qbt1000.c +++ b/drivers/soc/qcom/qbt1000.c @@ -150,18 +150,17 @@ static int get_cmd_rsp_buffers(struct qseecom_handle *hdl, uint32_t *rsp_len) { /* 64 bytes alignment for QSEECOM */ - *cmd_len = ALIGN(*cmd_len, 64); - *rsp_len = ALIGN(*rsp_len, 64); + uint64_t aligned_cmd_len = ALIGN((uint64_t)*cmd_len, 64); + uint64_t aligned_rsp_len = ALIGN((uint64_t)*rsp_len, 64); - if (((uint64_t)*rsp_len + (uint64_t)*cmd_len) - > (uint64_t)g_app_buf_size) { - pr_err("buffer too small to hold cmd=%d and rsp=%d\n", - *cmd_len, *rsp_len); + if ((aligned_rsp_len + aligned_cmd_len) > (uint64_t)g_app_buf_size) return -ENOMEM; - } *cmd = hdl->sbuf; + *cmd_len = aligned_cmd_len; *rsp = hdl->sbuf + *cmd_len; + *rsp_len = aligned_rsp_len; + return 0; } -- GitLab From 070659e590d78e02c5609c645c3b6b6dd1463870 Mon Sep 17 00:00:00 2001 From: Stefan Agner Date: Thu, 5 Apr 2018 16:25:38 -0700 Subject: [PATCH 0377/1635] mm/memblock.c: cast constant ULLONG_MAX to phys_addr_t This fixes a warning shown when phys_addr_t is 32-bit int when compiling with clang: mm/memblock.c:927:15: warning: implicit conversion from 'unsigned long long' to 'phys_addr_t' (aka 'unsigned int') changes value from 18446744073709551615 to 4294967295 [-Wconstant-conversion] r->base : ULLONG_MAX; ^~~~~~~~~~ ./include/linux/kernel.h:30:21: note: expanded from macro 'ULLONG_MAX' #define ULLONG_MAX (~0ULL) ^~~~~ Change-Id: I23a1b8b2054ca93ed70d462285af8405fe8fe0b4 Link: http://lkml.kernel.org/r/20180319005645.29051-1-stefan@agner.ch Signed-off-by: Stefan Agner Reviewed-by: Andrew Morton Cc: Michal Hocko Cc: Catalin Marinas Cc: Pavel Tatashin Cc: Ard Biesheuvel Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Git-commit: 644d87dccdc69cf79834a72ed0c889580d6af32a Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git Signed-off-by: Charan Teja Reddy --- mm/memblock.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mm/memblock.c b/mm/memblock.c index cf031550ca6f..0e0e69332dfd 100644 --- a/mm/memblock.c +++ b/mm/memblock.c @@ -928,7 +928,7 @@ void __init_memblock __next_mem_range(u64 *idx, int nid, ulong flags, r = &type_b->regions[idx_b]; r_start = idx_b ? r[-1].base + r[-1].size : 0; r_end = idx_b < type_b->cnt ? - r->base : ULLONG_MAX; + r->base : (phys_addr_t)ULLONG_MAX; /* * if idx_b advanced past idx_a, @@ -1044,7 +1044,7 @@ void __init_memblock __next_mem_range_rev(u64 *idx, int nid, ulong flags, r = &type_b->regions[idx_b]; r_start = idx_b ? r[-1].base + r[-1].size : 0; r_end = idx_b < type_b->cnt ? - r->base : ULLONG_MAX; + r->base : (phys_addr_t)ULLONG_MAX; /* * if idx_b advanced past idx_a, * break out to advance idx_a -- GitLab From 08cd42d6900dc6669d71f1dc52b14e39458300f6 Mon Sep 17 00:00:00 2001 From: Mayank Rana Date: Fri, 13 Apr 2018 09:27:00 -0700 Subject: [PATCH 0378/1635] ARM: dts: msm: Enable SMMU S1 functionality with USB on SM8150 This change enables SMMU S1 functionality with primary USB on SM8150. Change-Id: I6fb9acaba9f789e36fbfb2f4fa9e647c298a0932 Signed-off-by: Mayank Rana --- arch/arm64/boot/dts/qcom/sm8150-usb.dtsi | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/sm8150-usb.dtsi b/arch/arm64/boot/dts/qcom/sm8150-usb.dtsi index ccc4391910ed..4f1fa4d30e0a 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-usb.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-usb.dtsi @@ -22,7 +22,6 @@ reg-names = "core_base"; iommus = <&apps_smmu 0x140 0x0>; - qcom,smmu-s1-bypass; #address-cells = <1>; #size-cells = <1>; ranges; -- GitLab From 67f9bdbed2474203978f214d383b39a419535f26 Mon Sep 17 00:00:00 2001 From: Lingutla Chandrasekhar Date: Mon, 25 Sep 2017 15:56:24 +0530 Subject: [PATCH 0379/1635] soc: qcom: Add Minidump support This enables minidump feature. It allows various client subsystems to register respective dump regions. Registered Minidump dump regions would be collected on system crash. Change-Id: I14377cfba8703f0acadc29e51e2cf7563616571d Signed-off-by: Lingutla Chandrasekhar [isaacm@codeaurora.org: resolve trivial merge conflicts] Signed-off-by: Isaac J. Manjarres --- drivers/soc/qcom/Kconfig | 9 + drivers/soc/qcom/Makefile | 1 + drivers/soc/qcom/msm_minidump.c | 391 ++++++++++++++++++++++++++++++++ include/soc/qcom/minidump.h | 54 +++++ 4 files changed, 455 insertions(+) create mode 100644 drivers/soc/qcom/msm_minidump.c create mode 100644 include/soc/qcom/minidump.h diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig index de13a1e48bf0..e14c6853361f 100644 --- a/drivers/soc/qcom/Kconfig +++ b/drivers/soc/qcom/Kconfig @@ -390,6 +390,15 @@ config QCOM_EUD Embedded USB Debugger (EUD). If unsure, say N. +config QCOM_MINIDUMP + bool "QCOM Minidump Support" + depends on QCOM_SMEM && QCOM_DLOAD_MODE + help + This enables minidump feature. It allows various clients to + register to dump their state at system bad state (panic/WDT,etc.,). + Minidump would dump all registered entries, only when DLOAD mode + is enabled. + config QCOM_BUS_SCALING bool "Bus scaling driver" help diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile index 0c8797fdee82..7b6a2d6bcec5 100644 --- a/drivers/soc/qcom/Makefile +++ b/drivers/soc/qcom/Makefile @@ -28,6 +28,7 @@ obj-$(CONFIG_MSM_CORE_HANG_DETECT) += core_hang_detect.o obj-$(CONFIG_QCOM_DCC_V2) += dcc_v2.o obj-$(CONFIG_MSM_GLADIATOR_HANG_DETECT) += gladiator_hang_detect.o obj-$(CONFIG_MSM_GLADIATOR_ERP) += gladiator_erp.o +obj-$(CONFIG_QCOM_MINIDUMP) += msm_minidump.o obj-$(CONFIG_QCOM_SECURE_BUFFER) += secure_buffer.o obj-$(CONFIG_QCOM_MEMORY_DUMP_V2) += memory_dump_v2.o obj-$(CONFIG_QCOM_WATCHDOG_V2) += watchdog_v2.o diff --git a/drivers/soc/qcom/msm_minidump.c b/drivers/soc/qcom/msm_minidump.c new file mode 100644 index 000000000000..59b97704020e --- /dev/null +++ b/drivers/soc/qcom/msm_minidump.c @@ -0,0 +1,391 @@ +/* Copyright (c) 2017, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#define pr_fmt(fmt) "Minidump: " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#define MAX_NUM_ENTRIES 200 +#define SMEM_ENTRY_SIZE 32 +#define MAX_MEM_LENGTH (SMEM_ENTRY_SIZE * MAX_NUM_ENTRIES) +#define MAX_STRTBL_SIZE (MAX_NUM_ENTRIES * MAX_NAME_LENGTH) +#define SMEM_MINIDUMP_TABLE_ID 602 + +/* Bootloader Minidump table */ +struct md_smem_table { + u32 version; + u32 smem_length; + u64 next_avail_offset; + char reserved[MAX_NAME_LENGTH]; + u64 *region_start; +}; + +/* Bootloader Minidump region */ +struct md_smem_region { + char name[MAX_NAME_LENGTH]; + u64 address; + u64 size; +}; + +/* md_table: APPS minidump table + * @num_regions: Number of entries registered + * @region_base_offset: APPS region start offset smem table + * @md_smem_table: Pointer smem table + * @region: Pointer to APPS region in smem table + * @entry: All registered client entries. + */ + +struct md_table { + u32 num_regions; + u32 region_base_offset; + struct md_smem_table *md_smem_table; + struct md_smem_region *region; + struct md_region entry[MAX_NUM_ENTRIES]; +}; + +/* + * md_elfhdr: Minidump table elf header + * @md_ehdr: elf main header + * @shdr: Section header + * @phdr: Program header + * @elf_offset: section offset in elf + * @strtable_idx: string table current index position + */ +struct md_elfhdr { + struct elfhdr *md_ehdr; + struct elf_shdr *shdr; + struct elf_phdr *phdr; + u64 elf_offset; + u64 strtable_idx; +}; + +/* Protect elfheader and smem table from deferred calls contention */ +static DEFINE_SPINLOCK(mdt_lock); +static struct md_table minidump_table; +static struct md_elfhdr minidump_elfheader; + +bool minidump_enabled; +static unsigned int pendings; +static unsigned int region_idx = 1; /* First entry is ELF header*/ + +static inline struct elf_shdr *elf_sheader(struct elfhdr *hdr) +{ + return (struct elf_shdr *)((size_t)hdr + (size_t)hdr->e_shoff); +} + +static inline struct elf_shdr *elf_section(struct elfhdr *hdr, int idx) +{ + return &elf_sheader(hdr)[idx]; +} + +static inline struct elf_phdr *elf_pheader(struct elfhdr *hdr) +{ + return (struct elf_phdr *)((size_t)hdr + (size_t)hdr->e_phoff); +} + +static inline struct elf_phdr *elf_program(struct elfhdr *hdr, int idx) +{ + return &elf_pheader(hdr)[idx]; +} + +static inline char *elf_str_table(struct elfhdr *hdr) +{ + if (hdr->e_shstrndx == SHN_UNDEF) + return NULL; + return (char *)hdr + elf_section(hdr, hdr->e_shstrndx)->sh_offset; +} + +static inline char *elf_lookup_string(struct elfhdr *hdr, int offset) +{ + char *strtab = elf_str_table(hdr); + + if ((strtab == NULL) || (minidump_elfheader.strtable_idx < offset)) + return NULL; + return strtab + offset; +} + +static inline unsigned int set_section_name(const char *name) +{ + char *strtab = elf_str_table(minidump_elfheader.md_ehdr); + int idx = minidump_elfheader.strtable_idx; + int ret = 0; + + if ((strtab == NULL) || (name == NULL)) + return 0; + + ret = idx; + idx += strlcpy((strtab + idx), name, MAX_NAME_LENGTH); + minidump_elfheader.strtable_idx = idx + 1; + + return ret; +} + +/* return 1 if name already exists */ +static inline bool md_check_name(const char *name) +{ + struct md_region *mde = minidump_table.entry; + int i, regno = minidump_table.num_regions; + + for (i = 0; i < regno; i++, mde++) + if (!strcmp(mde->name, name)) + return true; + return false; +} + +/* Update Mini dump table in SMEM */ +static int md_update_smem_table(const struct md_region *entry) +{ + struct md_smem_region *mdr; + struct elfhdr *hdr = minidump_elfheader.md_ehdr; + struct elf_shdr *shdr = elf_section(hdr, hdr->e_shnum++); + struct elf_phdr *phdr = elf_program(hdr, hdr->e_phnum++); + + mdr = &minidump_table.region[region_idx++]; + + strlcpy(mdr->name, entry->name, sizeof(mdr->name)); + mdr->address = entry->phys_addr; + mdr->size = entry->size; + + /* Update elf header */ + shdr->sh_type = SHT_PROGBITS; + shdr->sh_name = set_section_name(mdr->name); + shdr->sh_addr = (elf_addr_t)entry->virt_addr; + shdr->sh_size = mdr->size; + shdr->sh_flags = SHF_WRITE; + shdr->sh_offset = minidump_elfheader.elf_offset; + shdr->sh_entsize = 0; + + phdr->p_type = PT_LOAD; + phdr->p_offset = minidump_elfheader.elf_offset; + phdr->p_vaddr = entry->virt_addr; + phdr->p_paddr = entry->phys_addr; + phdr->p_filesz = phdr->p_memsz = mdr->size; + phdr->p_flags = PF_R | PF_W; + + minidump_elfheader.elf_offset += shdr->sh_size; + + return 0; +} + +int msm_minidump_add_region(const struct md_region *entry) +{ + u32 entries; + struct md_region *mdr; + int ret = 0; + + if (!entry) + return -EINVAL; + + if (((strlen(entry->name) > MAX_NAME_LENGTH) || + md_check_name(entry->name)) && !entry->virt_addr) { + pr_err("Invalid entry details\n"); + return -EINVAL; + } + + if (!IS_ALIGNED(entry->size, 4)) { + pr_err("size should be 4 byte aligned\n"); + return -EINVAL; + } + + spin_lock(&mdt_lock); + entries = minidump_table.num_regions; + if (entries >= MAX_NUM_ENTRIES) { + pr_err("Maximum entries reached.\n"); + spin_unlock(&mdt_lock); + return -ENOMEM; + } + + mdr = &minidump_table.entry[entries]; + strlcpy(mdr->name, entry->name, sizeof(mdr->name)); + mdr->virt_addr = entry->virt_addr; + mdr->phys_addr = entry->phys_addr; + mdr->size = entry->size; + mdr->id = entry->id; + + minidump_table.num_regions = entries + 1; + + if (minidump_enabled) + ret = md_update_smem_table(entry); + else + pendings++; + + spin_unlock(&mdt_lock); + + pr_debug("Minidump: added %s to %s list\n", + mdr->name, minidump_enabled ? "":"pending"); + return ret; +} +EXPORT_SYMBOL(msm_minidump_add_region); + +static int msm_minidump_add_header(void) +{ + struct md_smem_region *mdreg = &minidump_table.region[0]; + struct elfhdr *md_ehdr; + struct elf_shdr *shdr; + struct elf_phdr *phdr; + unsigned int strtbl_off, elfh_size, phdr_off; + char *banner; + + /* Header buffer contains: + * elf header, MAX_NUM_ENTRIES+1 of section and program elf headers, + * string table section and linux banner. + */ + elfh_size = sizeof(*md_ehdr) + MAX_STRTBL_SIZE + MAX_MEM_LENGTH + + ((sizeof(*shdr) + sizeof(*phdr)) * (MAX_NUM_ENTRIES + 1)); + + minidump_elfheader.md_ehdr = kzalloc(elfh_size, GFP_KERNEL); + if (!minidump_elfheader.md_ehdr) + return -ENOMEM; + + strlcpy(mdreg->name, "KELF_HEADER", sizeof(mdreg->name)); + mdreg->address = virt_to_phys(minidump_elfheader.md_ehdr); + mdreg->size = elfh_size; + + md_ehdr = minidump_elfheader.md_ehdr; + /* Assign section/program headers offset */ + minidump_elfheader.shdr = shdr = (struct elf_shdr *)(md_ehdr + 1); + minidump_elfheader.phdr = phdr = + (struct elf_phdr *)(shdr + MAX_NUM_ENTRIES); + phdr_off = sizeof(*md_ehdr) + (sizeof(*shdr) * MAX_NUM_ENTRIES); + + memcpy(md_ehdr->e_ident, ELFMAG, SELFMAG); + md_ehdr->e_ident[EI_CLASS] = ELF_CLASS; + md_ehdr->e_ident[EI_DATA] = ELF_DATA; + md_ehdr->e_ident[EI_VERSION] = EV_CURRENT; + md_ehdr->e_ident[EI_OSABI] = ELF_OSABI; + md_ehdr->e_type = ET_CORE; + md_ehdr->e_machine = ELF_ARCH; + md_ehdr->e_version = EV_CURRENT; + md_ehdr->e_ehsize = sizeof(*md_ehdr); + md_ehdr->e_phoff = phdr_off; + md_ehdr->e_phentsize = sizeof(*phdr); + md_ehdr->e_shoff = sizeof(*md_ehdr); + md_ehdr->e_shentsize = sizeof(*shdr); + md_ehdr->e_shstrndx = 1; + + minidump_elfheader.elf_offset = elfh_size; + + /* + * First section header should be NULL, + * 2nd section is string table. + */ + minidump_elfheader.strtable_idx = 1; + strtbl_off = sizeof(*md_ehdr) + + ((sizeof(*phdr) + sizeof(*shdr)) * MAX_NUM_ENTRIES); + shdr++; + shdr->sh_type = SHT_STRTAB; + shdr->sh_offset = (elf_addr_t)strtbl_off; + shdr->sh_size = MAX_STRTBL_SIZE; + shdr->sh_entsize = 0; + shdr->sh_flags = 0; + shdr->sh_name = set_section_name("STR_TBL"); + shdr++; + + /* 3rd section is for minidump_table VA, used by parsers */ + shdr->sh_type = SHT_PROGBITS; + shdr->sh_entsize = 0; + shdr->sh_flags = 0; + shdr->sh_addr = (elf_addr_t)&minidump_table; + shdr->sh_name = set_section_name("minidump_table"); + shdr++; + + /* 4th section is linux banner */ + banner = (char *)md_ehdr + strtbl_off + MAX_STRTBL_SIZE; + strlcpy(banner, linux_banner, MAX_MEM_LENGTH); + + shdr->sh_type = SHT_PROGBITS; + shdr->sh_offset = (elf_addr_t)(strtbl_off + MAX_STRTBL_SIZE); + shdr->sh_size = strlen(linux_banner) + 1; + shdr->sh_addr = (elf_addr_t)linux_banner; + shdr->sh_entsize = 0; + shdr->sh_flags = SHF_WRITE; + shdr->sh_name = set_section_name("linux_banner"); + + phdr->p_type = PT_LOAD; + phdr->p_offset = (elf_addr_t)(strtbl_off + MAX_STRTBL_SIZE); + phdr->p_vaddr = (elf_addr_t)linux_banner; + phdr->p_paddr = virt_to_phys(linux_banner); + phdr->p_filesz = phdr->p_memsz = strlen(linux_banner) + 1; + phdr->p_flags = PF_R | PF_W; + + /* Update headers count*/ + md_ehdr->e_phnum = 1; + md_ehdr->e_shnum = 4; + + return 0; +} + +static int __init msm_minidump_init(void) +{ + unsigned int i; + size_t size; + struct md_region *mdr; + struct md_smem_table *smem_table; + + /* Get Minidump table */ + smem_table = qcom_smem_get(QCOM_SMEM_HOST_ANY, SMEM_MINIDUMP_TABLE_ID, + &size); + if (IS_ERR_OR_NULL(smem_table)) { + pr_err("SMEM is not initialized.\n"); + return -ENODEV; + } + + if ((smem_table->next_avail_offset + MAX_MEM_LENGTH) > + smem_table->smem_length) { + pr_err("SMEM memory not available.\n"); + return -ENOMEM; + } + + /* Get next_avail_offset and update it to reserve memory */ + minidump_table.region_base_offset = smem_table->next_avail_offset; + minidump_table.region = (struct md_smem_region *)((uintptr_t)smem_table + + minidump_table.region_base_offset); + + smem_table->next_avail_offset = + minidump_table.region_base_offset + MAX_MEM_LENGTH; + minidump_table.md_smem_table = smem_table; + + msm_minidump_add_header(); + + /* Add pending entries to smem table */ + spin_lock(&mdt_lock); + minidump_enabled = true; + + for (i = 0; i < pendings; i++) { + mdr = &minidump_table.entry[i]; + if (md_update_smem_table(mdr)) { + pr_err("Unable to add entry %s to smem table\n", + mdr->name); + spin_unlock(&mdt_lock); + return -ENOENT; + } + } + + pendings = 0; + spin_unlock(&mdt_lock); + + pr_info("Enabled, region base:%d, region 0x%pK\n", + minidump_table.region_base_offset, minidump_table.region); + + return 0; +} +subsys_initcall(msm_minidump_init) diff --git a/include/soc/qcom/minidump.h b/include/soc/qcom/minidump.h new file mode 100644 index 000000000000..d5970cfef643 --- /dev/null +++ b/include/soc/qcom/minidump.h @@ -0,0 +1,54 @@ +/* Copyright (c) 2017 The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __MINIDUMP_H +#define __MINIDUMP_H + +#define MAX_NAME_LENGTH 16 +/* md_region - Minidump table entry + * @name: Entry name, Minidump will dump binary with this name. + * @id: Entry ID, used only for SDI dumps. + * @virt_addr: Address of the entry. + * @phys_addr: Physical address of the entry to dump. + * @size: Number of byte to dump from @address location + * it should be 4 byte aligned. + */ +struct md_region { + char name[MAX_NAME_LENGTH]; + u32 id; + u64 virt_addr; + u64 phys_addr; + u64 size; +}; + +/* Register an entry in Minidump table + * Returns: + * Zero: on successful addition + * Negetive error number on failures + */ +#ifdef CONFIG_QCOM_MINIDUMP +extern int msm_minidump_add_region(const struct md_region *entry); +/* Sets to true, if minidump table is initialized */ +extern bool minidump_enabled; +extern void dump_stack_minidump(u64 sp); +#else +static inline int msm_minidump_add_region(const struct md_region *entry) +{ + /* Return quietly, if minidump is not supported */ + return 0; +} + +static inline void dump_stack_minidump(u64 sp) {} +#endif + + +#endif -- GitLab From 2f127229bd9345a2de41139e3a0143e87a2a99fb Mon Sep 17 00:00:00 2001 From: Lingutla Chandrasekhar Date: Wed, 27 Sep 2017 18:06:52 +0530 Subject: [PATCH 0380/1635] elf: Add elf headers helpers support ELF header format is been used in multiple places, add helper functions to get section, program headers, and string table section details of the elf header. Change-Id: Ib67b6f25a3a9c32305710eae4ad66bea511d6799 Signed-off-by: Lingutla Chandrasekhar [isaacm@codeaurora.org: Resolve trivial merge conflicts] Signed-off-by: Isaac J. Manjarres --- drivers/soc/qcom/msm_minidump.c | 27 -------- drivers/soc/qcom/ramdump.c | 116 ++++++++++++++++++++++++++++++++ include/linux/elf.h | 33 +++++++++ include/soc/qcom/ramdump.h | 3 +- 4 files changed, 151 insertions(+), 28 deletions(-) diff --git a/drivers/soc/qcom/msm_minidump.c b/drivers/soc/qcom/msm_minidump.c index 59b97704020e..5ee76e642000 100644 --- a/drivers/soc/qcom/msm_minidump.c +++ b/drivers/soc/qcom/msm_minidump.c @@ -87,33 +87,6 @@ bool minidump_enabled; static unsigned int pendings; static unsigned int region_idx = 1; /* First entry is ELF header*/ -static inline struct elf_shdr *elf_sheader(struct elfhdr *hdr) -{ - return (struct elf_shdr *)((size_t)hdr + (size_t)hdr->e_shoff); -} - -static inline struct elf_shdr *elf_section(struct elfhdr *hdr, int idx) -{ - return &elf_sheader(hdr)[idx]; -} - -static inline struct elf_phdr *elf_pheader(struct elfhdr *hdr) -{ - return (struct elf_phdr *)((size_t)hdr + (size_t)hdr->e_phoff); -} - -static inline struct elf_phdr *elf_program(struct elfhdr *hdr, int idx) -{ - return &elf_pheader(hdr)[idx]; -} - -static inline char *elf_str_table(struct elfhdr *hdr) -{ - if (hdr->e_shstrndx == SHN_UNDEF) - return NULL; - return (char *)hdr + elf_section(hdr, hdr->e_shstrndx)->sh_offset; -} - static inline char *elf_lookup_string(struct elfhdr *hdr, int offset) { char *strtab = elf_str_table(hdr); diff --git a/drivers/soc/qcom/ramdump.c b/drivers/soc/qcom/ramdump.c index ec4ff4959fb6..51749d3479f9 100644 --- a/drivers/soc/qcom/ramdump.c +++ b/drivers/soc/qcom/ramdump.c @@ -38,6 +38,8 @@ static DEFINE_MUTEX(rd_minor_mutex); static DEFINE_IDA(rd_minor_id); static bool ramdump_devnode_inited; #define RAMDUMP_WAIT_MSECS 120000 +#define MAX_STRTBL_SIZE 512 +#define MAX_NAME_LENGTH 16 struct ramdump_device { char name[256]; @@ -447,12 +449,126 @@ static int _do_ramdump(void *handle, struct ramdump_segment *segments, } +static inline unsigned int set_section_name(const char *name, + struct elfhdr *ehdr) +{ + char *strtab = elf_str_table(ehdr); + static int strtable_idx = 1; + int idx, ret = 0; + + idx = strtable_idx; + if ((strtab == NULL) || (name == NULL)) + return 0; + + ret = idx; + idx += strlcpy((strtab + idx), name, MAX_NAME_LENGTH); + strtable_idx = idx + 1; + + return ret; +} + +static int _do_minidump(void *handle, struct ramdump_segment *segments, + int nsegments) +{ + int ret, i; + struct ramdump_device *rd_dev = (struct ramdump_device *)handle; + struct elfhdr *ehdr; + struct elf_shdr *shdr; + unsigned long offset, strtbl_off; + + if (!rd_dev->consumer_present) { + pr_err("Ramdump(%s): No consumers. Aborting..\n", rd_dev->name); + return -EPIPE; + } + + rd_dev->segments = segments; + rd_dev->nsegments = nsegments; + + rd_dev->elfcore_size = sizeof(*ehdr) + + (sizeof(*shdr) * (nsegments + 2)) + MAX_STRTBL_SIZE; + ehdr = kzalloc(rd_dev->elfcore_size, GFP_KERNEL); + rd_dev->elfcore_buf = (char *)ehdr; + if (!rd_dev->elfcore_buf) + return -ENOMEM; + + memcpy(ehdr->e_ident, ELFMAG, SELFMAG); + ehdr->e_ident[EI_CLASS] = ELF_CLASS; + ehdr->e_ident[EI_DATA] = ELF_DATA; + ehdr->e_ident[EI_VERSION] = EV_CURRENT; + ehdr->e_ident[EI_OSABI] = ELF_OSABI; + ehdr->e_type = ET_CORE; + ehdr->e_machine = ELF_ARCH; + ehdr->e_version = EV_CURRENT; + ehdr->e_ehsize = sizeof(*ehdr); + ehdr->e_shoff = sizeof(*ehdr); + ehdr->e_shentsize = sizeof(*shdr); + ehdr->e_shstrndx = 1; + + + offset = rd_dev->elfcore_size; + shdr = (struct elf_shdr *)(ehdr + 1); + strtbl_off = sizeof(*ehdr) + sizeof(*shdr) * (nsegments + 2); + shdr++; + shdr->sh_type = SHT_STRTAB; + shdr->sh_offset = (elf_addr_t)strtbl_off; + shdr->sh_size = MAX_STRTBL_SIZE; + shdr->sh_entsize = 0; + shdr->sh_flags = 0; + shdr->sh_name = set_section_name("STR_TBL", ehdr); + shdr++; + + for (i = 0; i < nsegments; i++, shdr++) { + /* Update elf header */ + shdr->sh_type = SHT_PROGBITS; + shdr->sh_name = set_section_name(segments[i].name, ehdr); + shdr->sh_addr = (elf_addr_t)segments[i].address; + shdr->sh_size = segments[i].size; + shdr->sh_flags = SHF_WRITE; + shdr->sh_offset = offset; + shdr->sh_entsize = 0; + offset += shdr->sh_size; + } + ehdr->e_shnum = nsegments + 2; + + rd_dev->data_ready = 1; + rd_dev->ramdump_status = -1; + + reinit_completion(&rd_dev->ramdump_complete); + + /* Tell userspace that the data is ready */ + wake_up(&rd_dev->dump_wait_q); + + /* Wait (with a timeout) to let the ramdump complete */ + ret = wait_for_completion_timeout(&rd_dev->ramdump_complete, + msecs_to_jiffies(RAMDUMP_WAIT_MSECS)); + + if (!ret) { + pr_err("Ramdump(%s): Timed out waiting for userspace.\n", + rd_dev->name); + ret = -EPIPE; + } else { + ret = (rd_dev->ramdump_status == 0) ? 0 : -EPIPE; + } + + rd_dev->data_ready = 0; + rd_dev->elfcore_size = 0; + kfree(rd_dev->elfcore_buf); + rd_dev->elfcore_buf = NULL; + return ret; +} + int do_ramdump(void *handle, struct ramdump_segment *segments, int nsegments) { return _do_ramdump(handle, segments, nsegments, false); } EXPORT_SYMBOL(do_ramdump); +int do_minidump(void *handle, struct ramdump_segment *segments, int nsegments) +{ + return _do_minidump(handle, segments, nsegments); +} +EXPORT_SYMBOL(do_minidump); + int do_elf_ramdump(void *handle, struct ramdump_segment *segments, int nsegments) { diff --git a/include/linux/elf.h b/include/linux/elf.h index e3649b3e970e..986c7bf7e3f3 100644 --- a/include/linux/elf.h +++ b/include/linux/elf.h @@ -45,6 +45,39 @@ extern Elf64_Dyn _DYNAMIC []; #endif +/* Generic helpers for ELF use */ +/* Return first section header */ +static inline struct elf_shdr *elf_sheader(struct elfhdr *hdr) +{ + return (struct elf_shdr *)((size_t)hdr + (size_t)hdr->e_shoff); +} + +/* Return idx section header */ +static inline struct elf_shdr *elf_section(struct elfhdr *hdr, int idx) +{ + return &elf_sheader(hdr)[idx]; +} + +/* Return first program header */ +static inline struct elf_phdr *elf_pheader(struct elfhdr *hdr) +{ + return (struct elf_phdr *)((size_t)hdr + (size_t)hdr->e_phoff); +} + +/* Return idx program header */ +static inline struct elf_phdr *elf_program(struct elfhdr *hdr, int idx) +{ + return &elf_pheader(hdr)[idx]; +} + +/* Retunr section's string table header */ +static inline char *elf_str_table(struct elfhdr *hdr) +{ + if (hdr->e_shstrndx == SHN_UNDEF) + return NULL; + return (char *)hdr + elf_section(hdr, hdr->e_shstrndx)->sh_offset; +} + /* Optional callbacks to write extra ELF notes. */ struct file; struct coredump_params; diff --git a/include/soc/qcom/ramdump.h b/include/soc/qcom/ramdump.h index 50a17c8ad605..6a25cc3aefc1 100644 --- a/include/soc/qcom/ramdump.h +++ b/include/soc/qcom/ramdump.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2014, The Linux Foundation. All rights reserved. +/* Copyright (c) 2011-2014, 2017 The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -16,6 +16,7 @@ struct device; struct ramdump_segment { + char *name; unsigned long address; void *v_address; unsigned long size; -- GitLab From 3cc1fda16e3b7f70fe5cdeca590512793f015c7e Mon Sep 17 00:00:00 2001 From: Raghavendra Rao Ananta Date: Thu, 12 Apr 2018 16:16:46 -0700 Subject: [PATCH 0381/1635] perf: arm: fix IRQ initializations in the driver During the ARM PMU driver's probe, the IRQ number and state are set when requesting for the IRQ lines. However, these values are re-initialized when the driver tries to register with the perf framework later. The bug prevents the driver from re-enabling the interrupts during the CPU hotplug-on case (or any IRQ operation thereafter), thus not triggering any interrupt. Perf sampling events would be mainly impacted by this as they update the samples for every overflow interrupt. Hence, moving the initializations of the IRQ number and state after the arm_pmu structure is allocated. The correct values can be recorded after requesting the IRQ. Change-Id: Ia4361a31e9e960efc7156f813c543574b197ff68 Signed-off-by: Raghavendra Rao Ananta --- drivers/perf/arm_pmu.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/perf/arm_pmu.c b/drivers/perf/arm_pmu.c index e665ea6dcb22..2288889ebfe9 100644 --- a/drivers/perf/arm_pmu.c +++ b/drivers/perf/arm_pmu.c @@ -915,6 +915,9 @@ struct arm_pmu *armpmu_alloc(void) events->percpu_pmu = pmu; } + pmu->pmu_state = ARM_PMU_STATE_OFF; + pmu->percpu_irq = -1; + return pmu; out_free_pmu: @@ -944,9 +947,6 @@ int armpmu_register(struct arm_pmu *pmu) if (!__oprofile_cpu_pmu) __oprofile_cpu_pmu = pmu; - pmu->pmu_state = ARM_PMU_STATE_OFF; - pmu->percpu_irq = -1; - pr_info("enabled with %s PMU driver, %d counters available\n", pmu->name, pmu->num_events); -- GitLab From 26c2a503e52d8ae89f7a54138f2b76f21121ed63 Mon Sep 17 00:00:00 2001 From: Lingutla Chandrasekhar Date: Tue, 3 Oct 2017 15:21:30 +0530 Subject: [PATCH 0382/1635] soc: qcom: Use ToC design for Minidump support The Minidump design is re architected to decentralize, more secure, and to be more scalable. New design uses table of content for each subsystem to decentralize, and encryption status to secure regions. Each subsystem have fixed index in global toc, and its regions table can be located in its own memory. Change-Id: I104596e51cf976000b97b2519ce7dcd43e72abb4 Signed-off-by: Lingutla Chandrasekhar Signed-off-by: Isaac J. Manjarres --- drivers/soc/qcom/Kconfig | 8 + drivers/soc/qcom/minidump_private.h | 85 +++++++++ drivers/soc/qcom/msm_minidump.c | 265 +++++++++++++++------------- include/soc/qcom/minidump.h | 9 +- 4 files changed, 237 insertions(+), 130 deletions(-) create mode 100644 drivers/soc/qcom/minidump_private.h diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig index e14c6853361f..e518fe80ce7a 100644 --- a/drivers/soc/qcom/Kconfig +++ b/drivers/soc/qcom/Kconfig @@ -399,6 +399,14 @@ config QCOM_MINIDUMP Minidump would dump all registered entries, only when DLOAD mode is enabled. +config MINIDUMP_MAX_ENTRIES + int "Minidump Maximum num of entries" + default 200 + depends on QCOM_MINIDUMP + help + This defines maximum number of entries to be allocated for application + subsytem in Minidump table. + config QCOM_BUS_SCALING bool "Bus scaling driver" help diff --git a/drivers/soc/qcom/minidump_private.h b/drivers/soc/qcom/minidump_private.h new file mode 100644 index 000000000000..81ebb1c4ee54 --- /dev/null +++ b/drivers/soc/qcom/minidump_private.h @@ -0,0 +1,85 @@ +/* Copyright (c) 2017, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#ifndef __MINIDUMP_PRIVATE_H +#define __MINIDUMP_PRIVATE_H + +#define MD_REVISION 1 +#define SBL_MINIDUMP_SMEM_ID 602 +#define MAX_NUM_OF_SS 10 +#define MD_SS_HLOS_ID 0 +#define SMEM_ENTRY_SIZE 40 + +/* Bootloader has 16 byte support, 4 bytes reserved for itself */ +#define MAX_REGION_NAME_LENGTH 16 + +#define MD_REGION_VALID ('V' << 24 | 'A' << 16 | 'L' << 8 | 'I' << 0) +#define MD_REGION_INVALID ('I' << 24 | 'N' << 16 | 'V' << 8 | 'A' << 0) +#define MD_REGION_INIT ('I' << 24 | 'N' << 16 | 'I' << 8 | 'T' << 0) +#define MD_REGION_NOINIT 0 + +#define MD_SS_ENCR_REQ (0 << 24 | 'Y' << 16 | 'E' << 8 | 'S' << 0) +#define MD_SS_ENCR_NOTREQ (0 << 24 | 0 << 16 | 'N' << 8 | 'R' << 0) +#define MD_SS_ENCR_NONE ('N' << 24 | 'O' << 16 | 'N' << 8 | 'E' << 0) +#define MD_SS_ENCR_DONE ('D' << 24 | 'O' << 16 | 'N' << 8 | 'E' << 0) +#define MD_SS_ENCR_START ('S' << 24 | 'T' << 16 | 'R' << 8 | 'T' << 0) +#define MD_SS_ENABLED ('E' << 24 | 'N' << 16 | 'B' << 8 | 'L' << 0) +#define MD_SS_DISABLED ('D' << 24 | 'S' << 16 | 'B' << 8 | 'L' << 0) + +/** + * md_ss_region - Minidump region + * @name : Name of the region to be dumped + * @seq_num: : Use to differentiate regions with same name. + * @md_valid : This entry to be dumped (if set to 1) + * @region_base_address : Physical address of region to be dumped + * @region_size : Size of the region + */ +struct md_ss_region { + char name[MAX_REGION_NAME_LENGTH]; + u32 seq_num; + u32 md_valid; + u64 region_base_address; + u64 region_size; +}; + +/** + * md_ss_toc: Sub system SMEM Table of content + * @md_ss_toc_init : SS toc init status + * @md_ss_enable_status : if set to 1, Bootloader would dump this SS regions + * @encryption_status: Encryption status for this subsystem + * @encryption_required : Decides to encrypt the SS regions or not + * @ss_region_count : Number of regions added in this SS toc + * @md_ss_smem_regions_baseptr : regions base pointer of the Subsystem + */ +struct md_ss_toc { + u32 md_ss_toc_init; + u32 md_ss_enable_status; + u32 encryption_status; + u32 encryption_required; + u32 ss_region_count; + struct md_ss_region *md_ss_smem_regions_baseptr; +}; + +/** + * md_global_toc: Global Table of Content + * @md_toc_init : Global Minidump init status + * @md_revision : Minidump revision + * @md_enable_status : Minidump enable status + * @md_ss_toc : Array of subsystems toc + */ +struct md_global_toc { + u32 md_toc_init; + u32 md_revision; + u32 md_enable_status; + struct md_ss_toc md_ss_toc[MAX_NUM_OF_SS]; +}; + +#endif diff --git a/drivers/soc/qcom/msm_minidump.c b/drivers/soc/qcom/msm_minidump.c index 5ee76e642000..e5a1204ec09d 100644 --- a/drivers/soc/qcom/msm_minidump.c +++ b/drivers/soc/qcom/msm_minidump.c @@ -20,72 +20,52 @@ #include #include #include -#include #include - - -#define MAX_NUM_ENTRIES 200 -#define SMEM_ENTRY_SIZE 32 -#define MAX_MEM_LENGTH (SMEM_ENTRY_SIZE * MAX_NUM_ENTRIES) -#define MAX_STRTBL_SIZE (MAX_NUM_ENTRIES * MAX_NAME_LENGTH) -#define SMEM_MINIDUMP_TABLE_ID 602 - -/* Bootloader Minidump table */ -struct md_smem_table { - u32 version; - u32 smem_length; - u64 next_avail_offset; - char reserved[MAX_NAME_LENGTH]; - u64 *region_start; -}; - -/* Bootloader Minidump region */ -struct md_smem_region { - char name[MAX_NAME_LENGTH]; - u64 address; - u64 size; -}; - -/* md_table: APPS minidump table - * @num_regions: Number of entries registered - * @region_base_offset: APPS region start offset smem table - * @md_smem_table: Pointer smem table - * @region: Pointer to APPS region in smem table - * @entry: All registered client entries. +#include "minidump_private.h" + +#define MAX_NUM_ENTRIES (CONFIG_MINIDUMP_MAX_ENTRIES + 1) +#define MAX_STRTBL_SIZE (MAX_NUM_ENTRIES * MAX_REGION_NAME_LENGTH) + +/** + * md_table : Local Minidump toc holder + * @num_regions : Number of regions requested + * @md_ss_toc : HLOS toc pointer + * @md_gbl_toc : Global toc pointer + * @md_regions : HLOS regions base pointer + * @entry : array of HLOS regions requested */ - struct md_table { - u32 num_regions; - u32 region_base_offset; - struct md_smem_table *md_smem_table; - struct md_smem_region *region; - struct md_region entry[MAX_NUM_ENTRIES]; + u32 revision; + u32 num_regions; + struct md_ss_toc *md_ss_toc; + struct md_global_toc *md_gbl_toc; + struct md_ss_region *md_regions; + struct md_region entry[MAX_NUM_ENTRIES]; }; -/* +/** * md_elfhdr: Minidump table elf header - * @md_ehdr: elf main header + * @ehdr: elf main header * @shdr: Section header * @phdr: Program header * @elf_offset: section offset in elf * @strtable_idx: string table current index position */ struct md_elfhdr { - struct elfhdr *md_ehdr; - struct elf_shdr *shdr; - struct elf_phdr *phdr; - u64 elf_offset; - u64 strtable_idx; + struct elfhdr *ehdr; + struct elf_shdr *shdr; + struct elf_phdr *phdr; + u64 elf_offset; + u64 strtable_idx; }; /* Protect elfheader and smem table from deferred calls contention */ static DEFINE_SPINLOCK(mdt_lock); -static struct md_table minidump_table; -static struct md_elfhdr minidump_elfheader; +static struct md_table minidump_table; +static struct md_elfhdr minidump_elfheader; -bool minidump_enabled; +/* Number of pending entries to be added in ToC regions */ static unsigned int pendings; -static unsigned int region_idx = 1; /* First entry is ELF header*/ static inline char *elf_lookup_string(struct elfhdr *hdr, int offset) { @@ -98,7 +78,7 @@ static inline char *elf_lookup_string(struct elfhdr *hdr, int offset) static inline unsigned int set_section_name(const char *name) { - char *strtab = elf_str_table(minidump_elfheader.md_ehdr); + char *strtab = elf_str_table(minidump_elfheader.ehdr); int idx = minidump_elfheader.strtable_idx; int ret = 0; @@ -106,13 +86,12 @@ static inline unsigned int set_section_name(const char *name) return 0; ret = idx; - idx += strlcpy((strtab + idx), name, MAX_NAME_LENGTH); + idx += strlcpy((strtab + idx), name, MAX_REGION_NAME_LENGTH); minidump_elfheader.strtable_idx = idx + 1; return ret; } -/* return 1 if name already exists */ static inline bool md_check_name(const char *name) { struct md_region *mde = minidump_table.entry; @@ -124,25 +103,43 @@ static inline bool md_check_name(const char *name) return false; } +/* Return next seq no, if name already exists in the table */ +static inline int md_get_seq_num(const char *name) +{ + struct md_ss_region *mde = minidump_table.md_regions; + int i, regno = minidump_table.md_ss_toc->ss_region_count; + int seqno = 0; + + for (i = 0; i < (regno - 1); i++, mde++) { + if (!strcmp(mde->name, name)) { + if (mde->seq_num >= seqno) + seqno = mde->seq_num + 1; + } + } + return seqno; +} + /* Update Mini dump table in SMEM */ -static int md_update_smem_table(const struct md_region *entry) +static void md_update_ss_toc(const struct md_region *entry) { - struct md_smem_region *mdr; - struct elfhdr *hdr = minidump_elfheader.md_ehdr; + struct md_ss_region *mdr; + struct elfhdr *hdr = minidump_elfheader.ehdr; struct elf_shdr *shdr = elf_section(hdr, hdr->e_shnum++); struct elf_phdr *phdr = elf_program(hdr, hdr->e_phnum++); + int reg_cnt = minidump_table.md_ss_toc->ss_region_count++; - mdr = &minidump_table.region[region_idx++]; + mdr = &minidump_table.md_regions[reg_cnt]; strlcpy(mdr->name, entry->name, sizeof(mdr->name)); - mdr->address = entry->phys_addr; - mdr->size = entry->size; + mdr->region_base_address = entry->phys_addr; + mdr->region_size = entry->size; + mdr->seq_num = md_get_seq_num(entry->name); /* Update elf header */ shdr->sh_type = SHT_PROGBITS; shdr->sh_name = set_section_name(mdr->name); shdr->sh_addr = (elf_addr_t)entry->virt_addr; - shdr->sh_size = mdr->size; + shdr->sh_size = mdr->region_size; shdr->sh_flags = SHF_WRITE; shdr->sh_offset = minidump_elfheader.elf_offset; shdr->sh_entsize = 0; @@ -151,13 +148,26 @@ static int md_update_smem_table(const struct md_region *entry) phdr->p_offset = minidump_elfheader.elf_offset; phdr->p_vaddr = entry->virt_addr; phdr->p_paddr = entry->phys_addr; - phdr->p_filesz = phdr->p_memsz = mdr->size; + phdr->p_filesz = phdr->p_memsz = mdr->region_size; phdr->p_flags = PF_R | PF_W; minidump_elfheader.elf_offset += shdr->sh_size; + mdr->md_valid = MD_REGION_VALID; +} - return 0; +bool msm_minidump_enabled(void) +{ + bool ret = false; + + spin_lock(&mdt_lock); + if (minidump_table.md_ss_toc && + (minidump_table.md_ss_toc->md_ss_enable_status == + MD_SS_ENABLED)) + ret = true; + spin_unlock(&mdt_lock); + return ret; } +EXPORT_SYMBOL(msm_minidump_enabled); int msm_minidump_add_region(const struct md_region *entry) { @@ -168,8 +178,8 @@ int msm_minidump_add_region(const struct md_region *entry) if (!entry) return -EINVAL; - if (((strlen(entry->name) > MAX_NAME_LENGTH) || - md_check_name(entry->name)) && !entry->virt_addr) { + if ((strlen(entry->name) > MAX_NAME_LENGTH) || + md_check_name(entry->name) || !entry->virt_addr) { pr_err("Invalid entry details\n"); return -EINVAL; } @@ -196,64 +206,65 @@ int msm_minidump_add_region(const struct md_region *entry) minidump_table.num_regions = entries + 1; - if (minidump_enabled) - ret = md_update_smem_table(entry); + if (minidump_table.md_ss_toc && + (minidump_table.md_ss_toc->md_ss_enable_status == + MD_SS_ENABLED)) + md_update_ss_toc(entry); else pendings++; spin_unlock(&mdt_lock); - pr_debug("Minidump: added %s to %s list\n", - mdr->name, minidump_enabled ? "":"pending"); return ret; } EXPORT_SYMBOL(msm_minidump_add_region); static int msm_minidump_add_header(void) { - struct md_smem_region *mdreg = &minidump_table.region[0]; - struct elfhdr *md_ehdr; + struct md_ss_region *mdreg = &minidump_table.md_regions[0]; + struct elfhdr *ehdr; struct elf_shdr *shdr; struct elf_phdr *phdr; unsigned int strtbl_off, elfh_size, phdr_off; char *banner; /* Header buffer contains: - * elf header, MAX_NUM_ENTRIES+1 of section and program elf headers, + * elf header, MAX_NUM_ENTRIES+4 of section and program elf headers, * string table section and linux banner. */ - elfh_size = sizeof(*md_ehdr) + MAX_STRTBL_SIZE + MAX_MEM_LENGTH + - ((sizeof(*shdr) + sizeof(*phdr)) * (MAX_NUM_ENTRIES + 1)); + elfh_size = sizeof(*ehdr) + MAX_STRTBL_SIZE + (strlen(linux_banner) + + 1) + ((sizeof(*shdr) + sizeof(*phdr)) * (MAX_NUM_ENTRIES + 4)); + elfh_size = ALIGN(elfh_size, 4); - minidump_elfheader.md_ehdr = kzalloc(elfh_size, GFP_KERNEL); - if (!minidump_elfheader.md_ehdr) + minidump_elfheader.ehdr = kzalloc(elfh_size, GFP_KERNEL); + if (!minidump_elfheader.ehdr) return -ENOMEM; strlcpy(mdreg->name, "KELF_HEADER", sizeof(mdreg->name)); - mdreg->address = virt_to_phys(minidump_elfheader.md_ehdr); - mdreg->size = elfh_size; + mdreg->region_base_address = virt_to_phys(minidump_elfheader.ehdr); + mdreg->region_size = elfh_size; - md_ehdr = minidump_elfheader.md_ehdr; + ehdr = minidump_elfheader.ehdr; /* Assign section/program headers offset */ - minidump_elfheader.shdr = shdr = (struct elf_shdr *)(md_ehdr + 1); + minidump_elfheader.shdr = shdr = (struct elf_shdr *)(ehdr + 1); minidump_elfheader.phdr = phdr = (struct elf_phdr *)(shdr + MAX_NUM_ENTRIES); - phdr_off = sizeof(*md_ehdr) + (sizeof(*shdr) * MAX_NUM_ENTRIES); - - memcpy(md_ehdr->e_ident, ELFMAG, SELFMAG); - md_ehdr->e_ident[EI_CLASS] = ELF_CLASS; - md_ehdr->e_ident[EI_DATA] = ELF_DATA; - md_ehdr->e_ident[EI_VERSION] = EV_CURRENT; - md_ehdr->e_ident[EI_OSABI] = ELF_OSABI; - md_ehdr->e_type = ET_CORE; - md_ehdr->e_machine = ELF_ARCH; - md_ehdr->e_version = EV_CURRENT; - md_ehdr->e_ehsize = sizeof(*md_ehdr); - md_ehdr->e_phoff = phdr_off; - md_ehdr->e_phentsize = sizeof(*phdr); - md_ehdr->e_shoff = sizeof(*md_ehdr); - md_ehdr->e_shentsize = sizeof(*shdr); - md_ehdr->e_shstrndx = 1; + phdr_off = sizeof(*ehdr) + (sizeof(*shdr) * MAX_NUM_ENTRIES); + + memcpy(ehdr->e_ident, ELFMAG, SELFMAG); + ehdr->e_ident[EI_CLASS] = ELF_CLASS; + ehdr->e_ident[EI_DATA] = ELF_DATA; + ehdr->e_ident[EI_VERSION] = EV_CURRENT; + ehdr->e_ident[EI_OSABI] = ELF_OSABI; + ehdr->e_type = ET_CORE; + ehdr->e_machine = ELF_ARCH; + ehdr->e_version = EV_CURRENT; + ehdr->e_ehsize = sizeof(*ehdr); + ehdr->e_phoff = phdr_off; + ehdr->e_phentsize = sizeof(*phdr); + ehdr->e_shoff = sizeof(*ehdr); + ehdr->e_shentsize = sizeof(*shdr); + ehdr->e_shstrndx = 1; minidump_elfheader.elf_offset = elfh_size; @@ -262,7 +273,7 @@ static int msm_minidump_add_header(void) * 2nd section is string table. */ minidump_elfheader.strtable_idx = 1; - strtbl_off = sizeof(*md_ehdr) + + strtbl_off = sizeof(*ehdr) + ((sizeof(*phdr) + sizeof(*shdr)) * MAX_NUM_ENTRIES); shdr++; shdr->sh_type = SHT_STRTAB; @@ -282,8 +293,8 @@ static int msm_minidump_add_header(void) shdr++; /* 4th section is linux banner */ - banner = (char *)md_ehdr + strtbl_off + MAX_STRTBL_SIZE; - strlcpy(banner, linux_banner, MAX_MEM_LENGTH); + banner = (char *)ehdr + strtbl_off + MAX_STRTBL_SIZE; + strlcpy(banner, linux_banner, strlen(linux_banner) + 1); shdr->sh_type = SHT_PROGBITS; shdr->sh_offset = (elf_addr_t)(strtbl_off + MAX_STRTBL_SIZE); @@ -301,9 +312,10 @@ static int msm_minidump_add_header(void) phdr->p_flags = PF_R | PF_W; /* Update headers count*/ - md_ehdr->e_phnum = 1; - md_ehdr->e_shnum = 4; + ehdr->e_phnum = 1; + ehdr->e_shnum = 4; + mdreg->md_valid = MD_REGION_VALID; return 0; } @@ -312,52 +324,57 @@ static int __init msm_minidump_init(void) unsigned int i; size_t size; struct md_region *mdr; - struct md_smem_table *smem_table; + struct md_global_toc *md_global_toc; + struct md_ss_toc *md_ss_toc; /* Get Minidump table */ - smem_table = qcom_smem_get(QCOM_SMEM_HOST_ANY, SMEM_MINIDUMP_TABLE_ID, - &size); - if (IS_ERR_OR_NULL(smem_table)) { + md_global_toc = qcom_smem_get(QCOM_SMEM_HOST_ANY, SBL_MINIDUMP_SMEM_ID, + &size); + if (IS_ERR_OR_NULL(md_global_toc)) { pr_err("SMEM is not initialized.\n"); return -ENODEV; } - if ((smem_table->next_avail_offset + MAX_MEM_LENGTH) > - smem_table->smem_length) { - pr_err("SMEM memory not available.\n"); - return -ENOMEM; + /*Check global minidump support initialization */ + if (!md_global_toc->md_toc_init) { + pr_err("System Minidump TOC not initialized\n"); + return -ENODEV; } - /* Get next_avail_offset and update it to reserve memory */ - minidump_table.region_base_offset = smem_table->next_avail_offset; - minidump_table.region = (struct md_smem_region *)((uintptr_t)smem_table - + minidump_table.region_base_offset); + minidump_table.md_gbl_toc = md_global_toc; + minidump_table.revision = md_global_toc->md_revision; + md_ss_toc = &md_global_toc->md_ss_toc[MD_SS_HLOS_ID]; - smem_table->next_avail_offset = - minidump_table.region_base_offset + MAX_MEM_LENGTH; - minidump_table.md_smem_table = smem_table; + md_ss_toc->encryption_status = MD_SS_ENCR_NONE; + md_ss_toc->encryption_required = MD_SS_ENCR_REQ; + + minidump_table.md_ss_toc = md_ss_toc; + minidump_table.md_regions = kzalloc((MAX_NUM_ENTRIES * + sizeof(struct md_ss_region)), GFP_KERNEL); + if (!minidump_table.md_regions) + return -ENOMEM; + md_ss_toc->md_ss_smem_regions_baseptr = + (void *)virt_to_phys(minidump_table.md_regions); + + /* First entry would be ELF header */ + md_ss_toc->ss_region_count = 1; msm_minidump_add_header(); - /* Add pending entries to smem table */ + /* Add pending entries to HLOS TOC */ spin_lock(&mdt_lock); - minidump_enabled = true; - + md_ss_toc->md_ss_toc_init = 1; + md_ss_toc->md_ss_enable_status = MD_SS_ENABLED; for (i = 0; i < pendings; i++) { mdr = &minidump_table.entry[i]; - if (md_update_smem_table(mdr)) { - pr_err("Unable to add entry %s to smem table\n", - mdr->name); - spin_unlock(&mdt_lock); - return -ENOENT; - } + md_update_ss_toc(mdr); } pendings = 0; spin_unlock(&mdt_lock); - pr_info("Enabled, region base:%d, region 0x%pK\n", - minidump_table.region_base_offset, minidump_table.region); + pr_info("Enabled with max number of regions %d\n", + CONFIG_MINIDUMP_MAX_ENTRIES); return 0; } diff --git a/include/soc/qcom/minidump.h b/include/soc/qcom/minidump.h index d5970cfef643..5c751e8f1d20 100644 --- a/include/soc/qcom/minidump.h +++ b/include/soc/qcom/minidump.h @@ -13,7 +13,7 @@ #ifndef __MINIDUMP_H #define __MINIDUMP_H -#define MAX_NAME_LENGTH 16 +#define MAX_NAME_LENGTH 12 /* md_region - Minidump table entry * @name: Entry name, Minidump will dump binary with this name. * @id: Entry ID, used only for SDI dumps. @@ -37,8 +37,7 @@ struct md_region { */ #ifdef CONFIG_QCOM_MINIDUMP extern int msm_minidump_add_region(const struct md_region *entry); -/* Sets to true, if minidump table is initialized */ -extern bool minidump_enabled; +extern bool msm_minidump_enabled(void); extern void dump_stack_minidump(u64 sp); #else static inline int msm_minidump_add_region(const struct md_region *entry) @@ -46,9 +45,7 @@ static inline int msm_minidump_add_region(const struct md_region *entry) /* Return quietly, if minidump is not supported */ return 0; } - +static inline bool msm_minidump_enabled(void) { return false; } static inline void dump_stack_minidump(u64 sp) {} #endif - - #endif -- GitLab From 35b06a5f7a9ffec3d184e3185b62f5bd95b42d2b Mon Sep 17 00:00:00 2001 From: Jeevan Shriram Date: Fri, 13 Apr 2018 10:17:05 -0700 Subject: [PATCH 0383/1635] defconfig: Enable service locator and QMI for sdmshrike Enable Serice locator and QMI configs for sdmshrike target for communication between subsystems. Change-Id: Icc6b84557ba13c17234376babfbececf7898b16a Signed-off-by: Jeevan Shriram --- arch/arm64/configs/sdmshrike-perf_defconfig | 3 +++ arch/arm64/configs/sdmshrike_defconfig | 3 +++ 2 files changed, 6 insertions(+) diff --git a/arch/arm64/configs/sdmshrike-perf_defconfig b/arch/arm64/configs/sdmshrike-perf_defconfig index 44af27a1279e..23c0575f8313 100644 --- a/arch/arm64/configs/sdmshrike-perf_defconfig +++ b/arch/arm64/configs/sdmshrike-perf_defconfig @@ -371,8 +371,11 @@ CONFIG_QCOM_WATCHDOG_V2=y CONFIG_QCOM_FORCE_WDOG_BITE_ON_PANIC=y CONFIG_QCOM_SMP2P=y CONFIG_QCOM_SMSM=y +CONFIG_MSM_SERVICE_LOCATOR=y +CONFIG_MSM_SERVICE_NOTIFIER=y CONFIG_MSM_SUBSYSTEM_RESTART=y CONFIG_MSM_PIL=y +CONFIG_MSM_SYSMON_QMI_COMM=y CONFIG_MSM_PIL_SSR_GENERIC=y CONFIG_QCOM_BUS_SCALING=y CONFIG_QCOM_BUS_CONFIG_RPMH=y diff --git a/arch/arm64/configs/sdmshrike_defconfig b/arch/arm64/configs/sdmshrike_defconfig index f42326c64156..10a7419180d9 100644 --- a/arch/arm64/configs/sdmshrike_defconfig +++ b/arch/arm64/configs/sdmshrike_defconfig @@ -385,8 +385,11 @@ CONFIG_QCOM_FORCE_WDOG_BITE_ON_PANIC=y CONFIG_QCOM_WDOG_IPI_ENABLE=y CONFIG_QCOM_SMP2P=y CONFIG_QCOM_SMSM=y +CONFIG_MSM_SERVICE_LOCATOR=y +CONFIG_MSM_SERVICE_NOTIFIER=y CONFIG_MSM_SUBSYSTEM_RESTART=y CONFIG_MSM_PIL=y +CONFIG_MSM_SYSMON_QMI_COMM=y CONFIG_MSM_PIL_SSR_GENERIC=y CONFIG_QCOM_BUS_SCALING=y CONFIG_QCOM_BUS_CONFIG_RPMH=y -- GitLab From 56b547598d41b77fbe57c21fc7d4448cb2bea0e1 Mon Sep 17 00:00:00 2001 From: "Isaac J. Manjarres" Date: Fri, 13 Apr 2018 11:31:22 -0700 Subject: [PATCH 0384/1635] scripts: build-all.py: update regex to compile defconfigs Update regex so targets that use sm*_defconfig can compile with the build-all script. Change-Id: I74612a64e3eb37b84dfdadc53cba97b2f578c39f Signed-off-by: Isaac J. Manjarres --- scripts/build-all.py | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/build-all.py b/scripts/build-all.py index 9e62997ebf79..2f4ad4472762 100755 --- a/scripts/build-all.py +++ b/scripts/build-all.py @@ -313,6 +313,7 @@ def scan_configs(): ) arch64_pats = ( r'msm*_defconfig', + r'sm*_defconfig', r'sdm*_defconfig', r'sdx*_defconfig', ) -- GitLab From ae31c63a3cb2a3f477ac768dfcedc1a9eac01328 Mon Sep 17 00:00:00 2001 From: Shivendra Kakrania Date: Thu, 12 Apr 2018 11:21:19 -0700 Subject: [PATCH 0385/1635] ARM: dts: msm: Update video clock config for sm8150 Video clock config is updated with following changes: 1. Removal of iris ahb clock, since this is enabled by default 2. Removal of 200MHz as this is not supported by display & gpu CRs-Fixed: 2223586 Change-Id: I3cb470edfe9f2d8a1f8fd0cfb1d8d5d38ea6729a Signed-off-by: Shivendra Kakrania --- arch/arm64/boot/dts/qcom/sm8150-vidc.dtsi | 28 +++++++++++------------ 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sm8150-vidc.dtsi b/arch/arm64/boot/dts/qcom/sm8150-vidc.dtsi index 03b5fb009745..27ec7817dcbb 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-vidc.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-vidc.dtsi @@ -31,22 +31,22 @@ cvp-supply = <&mvs1_gdsc>; /* Clocks */ - clock-names = "core_clk", "iface_clk", - "vcodec_clk", "cvp_clk", "gcc_video_axi0", - "gcc_video_axi1", "gcc_video_axic"; - clocks = <&clock_videocc VIDEO_CC_MVSC_CORE_CLK>, - <&clock_videocc VIDEO_CC_IRIS_AHB_CLK>, - <&clock_videocc VIDEO_CC_MVS0_CORE_CLK>, - <&clock_videocc VIDEO_CC_MVS1_CORE_CLK>, + clock-names = "gcc_video_axic", "gcc_video_axi0", + "gcc_video_axi1", "core_clk", "vcodec_clk", + "cvp_clk"; + clocks = <&clock_gcc GCC_VIDEO_AXIC_CLK>, <&clock_gcc GCC_VIDEO_AXI0_CLK>, <&clock_gcc GCC_VIDEO_AXI1_CLK>, - <&clock_gcc GCC_VIDEO_AXIC_CLK>; - qcom,proxy-clock-names = "core_clk", "iface_clk", - "vcodec_clk", "cvp_clk", "gcc_video_axi0", - "gcc_video_axi1", "gcc_video_axic"; - qcom,clock-configs = <0x1 0x0 0x1 0x1 0x0 0x0 0x0>; - qcom,allowed-clock-rates = <200000000 225000000 - 300000000 365000000 432000000 480000000>; + <&clock_videocc VIDEO_CC_MVSC_CORE_CLK>, + <&clock_videocc VIDEO_CC_MVS0_CORE_CLK>, + <&clock_videocc VIDEO_CC_MVS1_CORE_CLK>; + qcom,proxy-clock-names = "gcc_video_axic", + "gcc_video_axi0", "gcc_video_axi1", + "core_clk", "vcodec_clk", "cvp_clk"; + + qcom,clock-configs = <0x0 0x0 0x0 0x1 0x1 0x1>; + qcom,allowed-clock-rates = <225000000 300000000 + 365000000 432000000 480000000>; /* Buses */ bus_cnoc { -- GitLab From 0a4e20a3cc7add84e35ab5dd438fcff239898d86 Mon Sep 17 00:00:00 2001 From: Shivendra Kakrania Date: Wed, 21 Mar 2018 15:50:13 -0700 Subject: [PATCH 0386/1635] ARM: dts: msm: Enable video governor for bw calculation on sm8150 Enabling video governor for DDR & LLC bandwidth calculation according to video session properties. Change-Id: Ide4a024b7ec90be97973c24ebee63769a2d6003c CRs-Fixed: 2201248 Signed-off-by: Shivendra Kakrania --- arch/arm64/boot/dts/qcom/sm8150-vidc.dtsi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sm8150-vidc.dtsi b/arch/arm64/boot/dts/qcom/sm8150-vidc.dtsi index 27ec7817dcbb..b95c24621064 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-vidc.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-vidc.dtsi @@ -63,7 +63,7 @@ label = "venus-ddr"; qcom,bus-master = ; qcom,bus-slave = ; - qcom,bus-governor = "performance"; + qcom,bus-governor = "msm-vidc-ddr"; qcom,bus-range-kbps = <1000 6533000>; }; arm9_bus_ddr { @@ -79,7 +79,7 @@ label = "venus-llcc"; qcom,bus-master = ; qcom,bus-slave = ; - qcom,bus-governor = "performance"; + qcom,bus-governor = "msm-vidc-llcc"; qcom,bus-range-kbps = <1000 1326000>; }; -- GitLab From 6cfda92b21e6deaf9163d339e0b95a2043cd817c Mon Sep 17 00:00:00 2001 From: Venkat Chinta Date: Thu, 12 Apr 2018 15:17:03 -0700 Subject: [PATCH 0387/1635] ARM: dts: msm: Fix UBWC configuration for camera on sm8150 Fix incorrect UBWC config for IPE on sm8150 platform. The bank swizzle config for IPE and IFE need to match. IFE bank swizzle is off by default. This change sets IPE bank swizzle to off as well. Change-Id: I33f4cd5962c3af6924b173241de6231a01ec1494 Signed-off-by: Venkat Chinta --- arch/arm64/boot/dts/qcom/sm8150-camera.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/sm8150-camera.dtsi b/arch/arm64/boot/dts/qcom/sm8150-camera.dtsi index f22a2b002b30..634ecbb354c5 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-camera.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-camera.dtsi @@ -981,7 +981,7 @@ <400000000 0 600000000 0>; clock-cntl-level = "svs", "turbo"; fw_name = "CAMERA_ICP.elf"; - ubwc-cfg = <0x7F 0x1FF>; + ubwc-cfg = <0x7B 0x1EF>; status = "ok"; }; -- GitLab From 71a4d4f0dacfd0a99c66dddcd89647b1cb0f429e Mon Sep 17 00:00:00 2001 From: Tatenda Chipeperekwa Date: Thu, 5 Apr 2018 11:04:09 -0700 Subject: [PATCH 0388/1635] drm/msm/dp: update the DP PHY and controller programming for sm8150 Update the AUX setup sequence for DP PHY on sm8150 in order to enable AUX transactions once the cable is plugged in. Update the values for the voltage swing and pre-emphasis levels used when programming the DP PHY during the link power on sequence. Furthermore, update the controller programming to ensure all controller state transitions happens correctly. Change-Id: I0b16ac79e9679a7aac119548a226531698400935 Signed-off-by: Tatenda Chipeperekwa --- drivers/gpu/drm/msm/dp/dp_catalog_v420.c | 16 ++++++++-------- drivers/gpu/drm/msm/dp/dp_ctrl.c | 4 ++-- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/msm/dp/dp_catalog_v420.c b/drivers/gpu/drm/msm/dp/dp_catalog_v420.c index 53d1eddadf80..54b5f14d965f 100644 --- a/drivers/gpu/drm/msm/dp/dp_catalog_v420.c +++ b/drivers/gpu/drm/msm/dp/dp_catalog_v420.c @@ -27,17 +27,17 @@ #define MAX_PRE_EMP_LEVELS 4 static u8 const vm_pre_emphasis[MAX_VOLTAGE_LEVELS][MAX_PRE_EMP_LEVELS] = { - {0x00, 0x0B, 0x12, 0xFF}, /* pe0, 0 db */ - {0x00, 0x0A, 0x12, 0xFF}, /* pe1, 3.5 db */ - {0x00, 0x0C, 0xFF, 0xFF}, /* pe2, 6.0 db */ + {0x00, 0x0B, 0x14, 0xFF}, /* pe0, 0 db */ + {0x00, 0x0B, 0x12, 0xFF}, /* pe1, 3.5 db */ + {0x00, 0x0B, 0xFF, 0xFF}, /* pe2, 6.0 db */ {0xFF, 0xFF, 0xFF, 0xFF} /* pe3, 9.5 db */ }; /* voltage swing, 0.2v and 1.0v are not support */ static u8 const vm_voltage_swing[MAX_VOLTAGE_LEVELS][MAX_PRE_EMP_LEVELS] = { - {0x07, 0x0F, 0x14, 0xFF}, /* sw0, 0.4v */ - {0x11, 0x1D, 0x1F, 0xFF}, /* sw1, 0.6 v */ - {0x18, 0x1F, 0xFF, 0xFF}, /* sw1, 0.8 v */ + {0x07, 0x0F, 0x16, 0xFF}, /* sw0, 0.4v */ + {0x11, 0x1E, 0x1F, 0xFF}, /* sw1, 0.6 v */ + {0x19, 0x1F, 0xFF, 0xFF}, /* sw1, 0.8 v */ {0xFF, 0xFF, 0xFF, 0xFF} /* sw1, 1.2 v, optional */ }; @@ -108,13 +108,13 @@ static void dp_catalog_aux_setup_v420(struct dp_catalog_aux *aux, catalog = dp_catalog_get_priv_v420(aux); io_data = catalog->io->dp_phy; - dp_write(catalog, io_data, DP_PHY_PD_CTL, 0x65); + dp_write(catalog, io_data, DP_PHY_PD_CTL, 0x67); wmb(); /* make sure PD programming happened */ /* Turn on BIAS current for PHY/PLL */ io_data = catalog->io->dp_pll; dp_write(catalog, io_data, QSERDES_COM_BIAS_EN_CLKBUFLR_EN, 0x17); - wmb(); /* make sure PD programming happened */ + wmb(); /* make sure BIAS programming happened */ io_data = catalog->io->dp_phy; /* DP AUX CFG register programming */ diff --git a/drivers/gpu/drm/msm/dp/dp_ctrl.c b/drivers/gpu/drm/msm/dp/dp_ctrl.c index 08a54fc5d86f..487bddcbef6f 100644 --- a/drivers/gpu/drm/msm/dp/dp_ctrl.c +++ b/drivers/gpu/drm/msm/dp/dp_ctrl.c @@ -115,7 +115,7 @@ static void dp_ctrl_push_idle(struct dp_ctrl *dp_ctrl, enum dp_stream_id strm) { int const idle_pattern_completion_timeout_ms = 3 * HZ / 100; struct dp_ctrl_private *ctrl; - u32 state; + u32 state = 0x0; if (!dp_ctrl) { pr_err("Invalid input data\n"); @@ -139,7 +139,7 @@ static void dp_ctrl_push_idle(struct dp_ctrl *dp_ctrl, enum dp_stream_id strm) return; } - state = (strm == DP_STREAM_0) ? MST_DP0_PUSH_VCPF : MST_DP1_PUSH_VCPF; + state |= (strm == DP_STREAM_0) ? MST_DP0_PUSH_VCPF : MST_DP1_PUSH_VCPF; trigger_idle: reinit_completion(&ctrl->idle_comp); -- GitLab From 23af556226f593a1e2b08fb5ecf93b8361243aec Mon Sep 17 00:00:00 2001 From: Tatenda Chipeperekwa Date: Thu, 12 Apr 2018 13:13:02 -0700 Subject: [PATCH 0389/1635] ARM: dts: msm: update the DisplayPort AUX settings for sm8150 Update the DisplayPort AUX settings to the latest recommended values from the hardware programming guide. This is necessary to ensure that the PHY is programmed correctly in order to enable AUX transactions once the cable is plugged in. Change-Id: I493f29d16f151062d22f7435ee07271c8ef791d7 Signed-off-by: Tatenda Chipeperekwa --- arch/arm64/boot/dts/qcom/sm8150-sde.dtsi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sm8150-sde.dtsi b/arch/arm64/boot/dts/qcom/sm8150-sde.dtsi index f217c1b50857..bfbf0c3a1359 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-sde.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-sde.dtsi @@ -661,12 +661,12 @@ qcom,aux-cfg0-settings = [20 00]; qcom,aux-cfg1-settings = [24 13]; qcom,aux-cfg2-settings = [28 24]; - qcom,aux-cfg3-settings = [2c 10]; + qcom,aux-cfg3-settings = [2c 00]; qcom,aux-cfg4-settings = [30 0a]; qcom,aux-cfg5-settings = [34 26]; qcom,aux-cfg6-settings = [38 0a]; qcom,aux-cfg7-settings = [3c 03]; - qcom,aux-cfg8-settings = [40 bb]; + qcom,aux-cfg8-settings = [40 b7]; qcom,aux-cfg9-settings = [44 03]; qcom,max-pclk-frequency-khz = <675000>; -- GitLab From 0274d931432e3c493506df0e7a58dbd93644f3c2 Mon Sep 17 00:00:00 2001 From: "Isaac J. Manjarres" Date: Fri, 30 Mar 2018 16:53:28 -0700 Subject: [PATCH 0390/1635] soc: qcom: pil: Expose function to get subsys_device pointer There is currently no way to access the subsys_device data structure from an external source, which prevents access to other necessary data structures. Expose function to find the subsys_device data structure associated with a subsystem descriptor, so that it can be accessed. Change-Id: I068c859b2313e4e95347dc3f96625665411e8b96 Signed-off-by: Isaac J. Manjarres --- drivers/soc/qcom/subsystem_restart.c | 21 +++++++++++---------- include/soc/qcom/subsystem_restart.h | 3 ++- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/drivers/soc/qcom/subsystem_restart.c b/drivers/soc/qcom/subsystem_restart.c index 3330d772c684..6b43331d2c9e 100644 --- a/drivers/soc/qcom/subsystem_restart.c +++ b/drivers/soc/qcom/subsystem_restart.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2011-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -707,14 +707,14 @@ static int subsystem_powerup(struct subsys_device *dev, void *data) return 0; } -static int __find_subsys(struct device *dev, void *data) +static int __find_subsys_device(struct device *dev, void *data) { struct subsys_device *subsys = to_subsys(dev); return !strcmp(subsys->desc->name, data); } -static struct subsys_device *find_subsys(const char *str) +struct subsys_device *find_subsys_device(const char *str) { struct device *dev; @@ -722,9 +722,10 @@ static struct subsys_device *find_subsys(const char *str) return NULL; dev = bus_find_device(&subsys_bus_type, NULL, (void *)str, - __find_subsys); + __find_subsys_device); return dev ? to_subsys(dev) : NULL; } +EXPORT_SYMBOL(find_subsys_device); static int subsys_start(struct subsys_device *subsys) { @@ -796,7 +797,7 @@ int subsystem_set_fwname(const char *name, const char *fw_name) if (!fw_name) return -EINVAL; - subsys = find_subsys(name); + subsys = find_subsys_device(name); if (!subsys) return -EINVAL; @@ -816,7 +817,7 @@ int wait_for_shutdown_ack(struct subsys_desc *desc) if (!desc || !desc->shutdown_ack_irq) return 0; - dev = find_subsys(desc->name); + dev = find_subsys_device(desc->name); if (!dev) return 0; @@ -842,7 +843,7 @@ void *__subsystem_get(const char *name, const char *fw_name) if (!name) return NULL; - subsys = retval = find_subsys(name); + subsys = retval = find_subsys_device(name); if (!subsys) return ERR_PTR(-ENODEV); if (!try_module_get(subsys->owner)) { @@ -942,7 +943,7 @@ void subsystem_put(void *subsystem) } mutex_unlock(&track->lock); - subsys_d = find_subsys(subsys->desc->depends_on); + subsys_d = find_subsys_device(subsys->desc->depends_on); if (subsys_d) { subsystem_put(subsys_d); put_device(&subsys_d->dev); @@ -1156,7 +1157,7 @@ EXPORT_SYMBOL(subsystem_restart_dev); int subsystem_restart(const char *name) { int ret; - struct subsys_device *dev = find_subsys(name); + struct subsys_device *dev = find_subsys_device(name); if (!dev) return -ENODEV; @@ -1169,7 +1170,7 @@ EXPORT_SYMBOL(subsystem_restart); int subsystem_crashed(const char *name) { - struct subsys_device *dev = find_subsys(name); + struct subsys_device *dev = find_subsys_device(name); struct subsys_tracking *track; if (!dev) diff --git a/include/soc/qcom/subsystem_restart.h b/include/soc/qcom/subsystem_restart.h index eb227c30ac68..5f791b1a6131 100644 --- a/include/soc/qcom/subsystem_restart.h +++ b/include/soc/qcom/subsystem_restart.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -140,6 +140,7 @@ void notify_proxy_vote(struct device *device); void notify_proxy_unvote(struct device *device); void complete_err_ready(struct subsys_device *subsys); void complete_shutdown_ack(struct subsys_device *subsys); +struct subsys_device *find_subsys_device(const char *str); extern int wait_for_shutdown_ack(struct subsys_desc *desc); #else -- GitLab From d8f0846685329f8d727a9b4cdd7ecff28f4b46de Mon Sep 17 00:00:00 2001 From: "Isaac J. Manjarres" Date: Fri, 30 Mar 2018 16:04:06 -0700 Subject: [PATCH 0391/1635] soc: qcom: pil: Allow timeouts for graceful subsystem shutdown Currently, if a subsystem does not send a response through QMI confirming that it has properly gone through its shutdown sequence within a certain time, it is assumed that something went wrong, and the subsystem could not shutdown gracefully. However, for some subsystems, part of their shutdown sequence may involve disabling the QMI service prior to sending the response, and continuing the rest of the shutdown sequence without any problems. The real indicator of an issue is not receiving either an SMP2P interrupt or an QMI indication that the subsystem has shutdown. Allow for timeouts to be an acceptable cause of a graceful shutdown sequence, and wait for either an SMP2P interrupt or QMI indication that indicate whether the device has shutdown or not. Change-Id: Id870f948f5e99a999965cf83ca225788e01eaf2e Signed-off-by: Isaac J. Manjarres --- drivers/soc/qcom/subsystem_restart.c | 2 +- drivers/soc/qcom/sysmon-qmi.c | 36 +++++++++++----------------- 2 files changed, 15 insertions(+), 23 deletions(-) diff --git a/drivers/soc/qcom/subsystem_restart.c b/drivers/soc/qcom/subsystem_restart.c index 6b43331d2c9e..2d5c8526bb3d 100644 --- a/drivers/soc/qcom/subsystem_restart.c +++ b/drivers/soc/qcom/subsystem_restart.c @@ -814,7 +814,7 @@ int wait_for_shutdown_ack(struct subsys_desc *desc) int ret; struct subsys_device *dev; - if (!desc || !desc->shutdown_ack_irq) + if (!desc) return 0; dev = find_subsys_device(desc->name); diff --git a/drivers/soc/qcom/sysmon-qmi.c b/drivers/soc/qcom/sysmon-qmi.c index 4462e92e90a2..cb603b4d053c 100644 --- a/drivers/soc/qcom/sysmon-qmi.c +++ b/drivers/soc/qcom/sysmon-qmi.c @@ -71,7 +71,6 @@ struct sysmon_qmi_data { struct notifier_block notifier; void *notif_handle; bool legacy_version; - struct completion ind_recv; struct sockaddr_qrtr ssctl; struct list_head list; }; @@ -99,8 +98,13 @@ static void sysmon_ind_cb(struct qmi_handle *qmi, struct sockaddr_qrtr *sq, struct sysmon_qmi_data *qmi_data = container_of(qmi, struct sysmon_qmi_data, clnt_handle); + struct subsys_device *subsys_dev = find_subsys_device(qmi_data->name); pr_info("%s: Indication received from subsystem\n", qmi_data->name); - complete(&qmi_data->ind_recv); + if (subsys_dev) + complete_shutdown_ack(subsys_dev); + else + pr_err("Failed to find subsystem: %s for indication\n", + qmi_data->name); } static struct qmi_msg_handler qmi_indication_handler[] = { @@ -400,8 +404,6 @@ int sysmon_send_shutdown(struct subsys_desc *dest_desc) if (!data->connected) return -EAGAIN; - reinit_completion(&data->ind_recv); - ret = qmi_txn_init(&data->clnt_handle, &txn, qmi_ssctl_shutdown_resp_msg_ei, &resp); @@ -428,11 +430,11 @@ int sysmon_send_shutdown(struct subsys_desc *dest_desc) if (ret < 0) { pr_err("SYSMON QMI txn wait failed to dest %s, ret - %d\n", dest_ss, ret); - goto out; } /* Check the response */ - if (QMI_RESP_BIT_SHIFT(resp.resp.result) != QMI_RESULT_SUCCESS_V01) { + if (ret != -ETIMEDOUT && QMI_RESP_BIT_SHIFT(resp.resp.result) != + QMI_RESULT_SUCCESS_V01) { pr_err("SYSMON QMI request failed 0x%x\n", QMI_RESP_BIT_SHIFT(resp.resp.error)); ret = -EREMOTEIO; @@ -440,21 +442,13 @@ int sysmon_send_shutdown(struct subsys_desc *dest_desc) } shutdown_ack_ret = wait_for_shutdown_ack(dest_desc); - if (shutdown_ack_ret < 0) { - pr_err("shutdown_ack SMP2P bit for %s not set\n", data->name); - if (!data->ind_recv.done) { - pr_err("QMI shutdown indication not received\n"); - ret = shutdown_ack_ret; - } + if (shutdown_ack_ret > 0) { + ret = 0; goto out; - } else if (shutdown_ack_ret > 0) - goto out; - - if (!wait_for_completion_timeout(&data->ind_recv, - msecs_to_jiffies(SHUTDOWN_TIMEOUT))) { - pr_err("Timed out waiting for shutdown indication from %s\n", - data->name); - ret = -ETIMEDOUT; + } else if (shutdown_ack_ret < 0) { + pr_err("shutdown acknowledgment not received for %s\n", + data->name); + ret = shutdown_ack_ret; } out: return ret; @@ -651,8 +645,6 @@ int sysmon_notifier_register(struct subsys_desc *desc) goto add_list; } - init_completion(&data->ind_recv); - rc = qmi_handle_init(&data->clnt_handle, QMI_SSCTL_RESP_MSG_LENGTH, &ssctl_ops, qmi_indication_handler); -- GitLab From 89be34a78b2990d0bc9d6e336bdb83a0361937bf Mon Sep 17 00:00:00 2001 From: Kyle Piefer Date: Thu, 29 Mar 2018 15:00:57 -0700 Subject: [PATCH 0392/1635] msm: kgsl: Enable GPU slumber The slumber feature is now supported. Enable it to save power when the GPU is idle. Change-Id: I6025700c8c4938bc471a711967de0f2b182b34de Signed-off-by: Kyle Piefer --- drivers/gpu/msm/adreno.c | 2 -- drivers/gpu/msm/kgsl.c | 4 +--- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c index 41e545f48b4a..4bc57003ebd5 100644 --- a/drivers/gpu/msm/adreno.c +++ b/drivers/gpu/msm/adreno.c @@ -1035,8 +1035,6 @@ static int adreno_of_get_power(struct adreno_device *adreno_dev, if (of_property_read_u32(node, "qcom,idle-timeout", &timeout)) timeout = 80; - /* Force disable slumber */ - timeout = 10000000; device->pwrctrl.interval_timeout = msecs_to_jiffies(timeout); device->pwrctrl.bus_control = of_property_read_bool(node, diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c index 0bd2ee2c2232..f5971c9efbcd 100644 --- a/drivers/gpu/msm/kgsl.c +++ b/drivers/gpu/msm/kgsl.c @@ -1059,6 +1059,7 @@ static int kgsl_close_device(struct kgsl_device *device) int result = 0; mutex_lock(&device->mutex); + device->open_count--; if (device->open_count == 0) { /* Wait for the active count to go to 0 */ @@ -1158,9 +1159,6 @@ static int kgsl_open_device(struct kgsl_device *device) complete_all(&device->hwaccess_gate); kgsl_pwrctrl_change_state(device, KGSL_STATE_ACTIVE); kgsl_active_count_put(device); - - /* Do not let the device close */ - device->open_count = 1; } device->open_count++; err: -- GitLab From 396bbefb00a815fc1bf172f5ab55aeda47fd4981 Mon Sep 17 00:00:00 2001 From: Jonathan Avila Date: Thu, 10 Aug 2017 13:49:49 -0700 Subject: [PATCH 0393/1635] cpufreq: schedutil: Avoid WALT logic when WALT sysctl flag not set When sysctl_sched_use_walt_cpu_util is set to 0, WALT stats are no longer updated. As a result, the schedutil governor throws warnings which lead to a crash. Fix this by not running any WALT-related logic when sysctl_sched_use_walt_cpu_util is 0. Change-Id: Ibdbc5243c6f3d11071f8ab715ca76e0e840f8090 CRs-Fixed: 2089058 Signed-off-by: Jonathan Avila --- kernel/sched/cpufreq_schedutil.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/kernel/sched/cpufreq_schedutil.c b/kernel/sched/cpufreq_schedutil.c index 439a7713e184..9a30f0e6698a 100644 --- a/kernel/sched/cpufreq_schedutil.c +++ b/kernel/sched/cpufreq_schedutil.c @@ -16,7 +16,7 @@ #include #include #include - +#include #include "sched.h" #define SUGOV_KTHREAD_PRIORITY 50 @@ -147,6 +147,10 @@ static void sugov_track_cycles(struct sugov_policy *sg_policy, u64 upto) { u64 delta_ns, cycles; + + if (unlikely(!sysctl_sched_use_walt_cpu_util)) + return; + /* Track cycles in current window */ delta_ns = upto - sg_policy->last_cyc_update_time; cycles = (prev_freq * delta_ns) / (NSEC_PER_SEC / KHZ); @@ -160,6 +164,9 @@ static void sugov_calc_avg_cap(struct sugov_policy *sg_policy, u64 curr_ws, u64 last_ws = sg_policy->last_ws; unsigned int avg_freq; + if (unlikely(!sysctl_sched_use_walt_cpu_util)) + return; + WARN_ON(curr_ws < last_ws); if (curr_ws <= last_ws) return; @@ -339,6 +346,9 @@ static void sugov_walt_adjust(struct sugov_cpu *sg_cpu, unsigned long *util, unsigned long cpu_util = sg_cpu->util; bool is_hiload; + if (unlikely(!sysctl_sched_use_walt_cpu_util)) + return; + is_hiload = (cpu_util >= mult_frac(sg_policy->avg_cap, sg_policy->tunables->hispeed_load, 100)); -- GitLab From c0701f18e136b0cc6c579d73b7cce5d5f2ad2599 Mon Sep 17 00:00:00 2001 From: Kyle Yan Date: Fri, 13 Apr 2018 14:38:34 -0700 Subject: [PATCH 0394/1635] cpufreq: schedutil: update warn_on with bug_on WARN_ON is used in calculating schedutil average capacity this is called under rq->lock held, when WARN_ON is triggered it tries to wake_up the process on the same CPU for debug prints inturn waits for the rq->lock triggering dead lock Update WARN_ON with BUG_ON avoiding the debug prints. Change-Id: I8db35a2165e68765b4ab2f132a571ad00311ba25 Signed-off-by: Santosh Mardi Signed-off-by: Kyle Yan --- kernel/sched/cpufreq_schedutil.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/sched/cpufreq_schedutil.c b/kernel/sched/cpufreq_schedutil.c index 9a30f0e6698a..51cbbe9bc4cb 100644 --- a/kernel/sched/cpufreq_schedutil.c +++ b/kernel/sched/cpufreq_schedutil.c @@ -167,7 +167,7 @@ static void sugov_calc_avg_cap(struct sugov_policy *sg_policy, u64 curr_ws, if (unlikely(!sysctl_sched_use_walt_cpu_util)) return; - WARN_ON(curr_ws < last_ws); + BUG_ON(curr_ws < last_ws); if (curr_ws <= last_ws) return; -- GitLab From e68686c5b0539f8c4bf506949fa7986d4f9770dd Mon Sep 17 00:00:00 2001 From: Liam Mark Date: Fri, 13 Apr 2018 14:51:12 -0700 Subject: [PATCH 0395/1635] defconfig: sm8150: Enable CMA debugfs Enable CMA debugfs on sm8150_defconfig to enable testing of CMA. Change-Id: I25b6232390f5dc40966aceed9cc53e47e8f50e40 Signed-off-by: Liam Mark --- arch/arm64/configs/sm8150_defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/configs/sm8150_defconfig b/arch/arm64/configs/sm8150_defconfig index 41bf474b81c5..688c01d34049 100644 --- a/arch/arm64/configs/sm8150_defconfig +++ b/arch/arm64/configs/sm8150_defconfig @@ -63,6 +63,7 @@ CONFIG_PREEMPT=y CONFIG_HZ_100=y CONFIG_CLEANCACHE=y CONFIG_CMA=y +CONFIG_CMA_DEBUGFS=y CONFIG_ZSMALLOC=y CONFIG_SECCOMP=y # CONFIG_UNMAP_KERNEL_AT_EL0 is not set -- GitLab From 3b411b7a23f9c40f43d19d75ecc128f0cad4ebda Mon Sep 17 00:00:00 2001 From: Ingrid Gallardo Date: Wed, 4 Apr 2018 15:23:58 -0700 Subject: [PATCH 0396/1635] defconfig: sdmshrike: enable compilation of SDE display driver This patch enables the necessary configs for compiling the SDE DRM driver for sdmshrike. Change-Id: I2bdbd0c2b60ed8e4fd8f974d88e6f1afd73246fe Signed-off-by: Ingrid Gallardo --- arch/arm64/configs/sdmshrike-perf_defconfig | 11 +++++++---- arch/arm64/configs/sdmshrike_defconfig | 11 +++++++---- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/arch/arm64/configs/sdmshrike-perf_defconfig b/arch/arm64/configs/sdmshrike-perf_defconfig index 44af27a1279e..e5d6e65325be 100644 --- a/arch/arm64/configs/sdmshrike-perf_defconfig +++ b/arch/arm64/configs/sdmshrike-perf_defconfig @@ -263,7 +263,6 @@ CONFIG_THERMAL=y CONFIG_QCOM_SPMI_TEMP_ALARM=y CONFIG_THERMAL_TSENS=y CONFIG_MFD_SPMI_PMIC=y -CONFIG_REGULATOR=y CONFIG_REGULATOR_FIXED_VOLTAGE=y CONFIG_REGULATOR_QPNP_LCDB=y CONFIG_REGULATOR_REFGEN=y @@ -276,7 +275,12 @@ CONFIG_VIDEO_V4L2_SUBDEV_API=y CONFIG_VIDEO_ADV_DEBUG=y CONFIG_VIDEO_FIXED_MINOR_RANGES=y CONFIG_V4L_PLATFORM_DRIVERS=y -CONFIG_FB=y +CONFIG_MSM_SDE_ROTATOR=y +CONFIG_MSM_SDE_ROTATOR_EVTLOG_DEBUG=y +CONFIG_DRM=y +CONFIG_DRM_MSM_REGISTER_LOGGING=y +CONFIG_DRM_SDE_EVTLOG_DEBUG=y +CONFIG_DRM_SDE_RSC=y CONFIG_FB_ARMCLCD=y CONFIG_BACKLIGHT_QCOM_SPMI_WLED=y CONFIG_LOGO=y @@ -345,6 +349,7 @@ CONFIG_ASHMEM=y CONFIG_ION=y CONFIG_QCOM_GENI_SE=y CONFIG_QPNP_REVID=y +CONFIG_QCOM_MDSS_PLL=y CONFIG_SPMI_PMIC_CLKDIV=y CONFIG_MSM_CLK_AOP_QMP=y CONFIG_MSM_NPUCC_SM8150=y @@ -366,7 +371,6 @@ CONFIG_QCOM_LLCC=y CONFIG_QCOM_SDMSHRIKE_LLCC=y CONFIG_QCOM_QMI_HELPERS=y CONFIG_QCOM_SMEM=y -CONFIG_QCOM_SCM=y CONFIG_QCOM_WATCHDOG_V2=y CONFIG_QCOM_FORCE_WDOG_BITE_ON_PANIC=y CONFIG_QCOM_SMP2P=y @@ -396,7 +400,6 @@ CONFIG_EXT4_FS_SECURITY=y CONFIG_FUSE_FS=y CONFIG_MSDOS_FS=y CONFIG_VFAT_FS=y -CONFIG_TMPFS=y CONFIG_TMPFS_POSIX_ACL=y CONFIG_ECRYPT_FS=y CONFIG_ECRYPT_FS_MESSAGING=y diff --git a/arch/arm64/configs/sdmshrike_defconfig b/arch/arm64/configs/sdmshrike_defconfig index f42326c64156..2118d99ce800 100644 --- a/arch/arm64/configs/sdmshrike_defconfig +++ b/arch/arm64/configs/sdmshrike_defconfig @@ -273,7 +273,6 @@ CONFIG_THERMAL=y CONFIG_QCOM_SPMI_TEMP_ALARM=y CONFIG_THERMAL_TSENS=y CONFIG_MFD_SPMI_PMIC=y -CONFIG_REGULATOR=y CONFIG_REGULATOR_FIXED_VOLTAGE=y CONFIG_REGULATOR_QPNP_LCDB=y CONFIG_REGULATOR_REFGEN=y @@ -286,7 +285,12 @@ CONFIG_VIDEO_V4L2_SUBDEV_API=y CONFIG_VIDEO_ADV_DEBUG=y CONFIG_VIDEO_FIXED_MINOR_RANGES=y CONFIG_V4L_PLATFORM_DRIVERS=y -CONFIG_FB=y +CONFIG_MSM_SDE_ROTATOR=y +CONFIG_MSM_SDE_ROTATOR_EVTLOG_DEBUG=y +CONFIG_DRM=y +CONFIG_DRM_MSM_REGISTER_LOGGING=y +CONFIG_DRM_SDE_EVTLOG_DEBUG=y +CONFIG_DRM_SDE_RSC=y CONFIG_FB_VIRTUAL=y CONFIG_BACKLIGHT_LCD_SUPPORT=y CONFIG_BACKLIGHT_CLASS_DEVICE=y @@ -358,6 +362,7 @@ CONFIG_ASHMEM=y CONFIG_ION=y CONFIG_QCOM_GENI_SE=y CONFIG_QPNP_REVID=y +CONFIG_QCOM_MDSS_PLL=y CONFIG_SPMI_PMIC_CLKDIV=y CONFIG_MSM_CLK_AOP_QMP=y CONFIG_MSM_NPUCC_SM8150=y @@ -379,7 +384,6 @@ CONFIG_QCOM_LLCC=y CONFIG_QCOM_SDMSHRIKE_LLCC=y CONFIG_QCOM_QMI_HELPERS=y CONFIG_QCOM_SMEM=y -CONFIG_QCOM_SCM=y CONFIG_QCOM_WATCHDOG_V2=y CONFIG_QCOM_FORCE_WDOG_BITE_ON_PANIC=y CONFIG_QCOM_WDOG_IPI_ENABLE=y @@ -412,7 +416,6 @@ CONFIG_EXT4_FS_SECURITY=y CONFIG_FUSE_FS=y CONFIG_MSDOS_FS=y CONFIG_VFAT_FS=y -CONFIG_TMPFS=y CONFIG_TMPFS_POSIX_ACL=y CONFIG_EFIVAR_FS=y CONFIG_ECRYPT_FS=y -- GitLab From f6a8cd9973535bd6c19d1b4d31e1def896718a10 Mon Sep 17 00:00:00 2001 From: Farrukh Qurashi Date: Tue, 27 Mar 2018 18:27:31 -0400 Subject: [PATCH 0397/1635] msm: npu: Add driver functionality to support NPU Add clock control, bandwidth monitor integration, thermal integration, IPC and execution management for operation of the NPU hardware block. The driver provides control of the NPU hardware for execution of neural networks. Change-Id: I6b7616ffd758e8660ac0855d37f53af732f49e48 Signed-off-by: Ken Zhang Signed-off-by: Farrukh Qurashi --- .../bindings/media/msm-npu-pwrlevels.txt | 164 +++ .../devicetree/bindings/media/msm-npu.txt | 231 +++- drivers/media/platform/msm/npu/Makefile | 8 +- drivers/media/platform/msm/npu/npu_common.h | 191 ++- drivers/media/platform/msm/npu/npu_dbg.c | 345 +++++ drivers/media/platform/msm/npu/npu_debugfs.c | 492 +++++++ drivers/media/platform/msm/npu/npu_dev.c | 1199 +++++++++++++++-- drivers/media/platform/msm/npu/npu_firmware.h | 139 ++ drivers/media/platform/msm/npu/npu_host_ipc.c | 414 ++++++ drivers/media/platform/msm/npu/npu_host_ipc.h | 323 +++++ drivers/media/platform/msm/npu/npu_hw.h | 297 ++++ .../media/platform/msm/npu/npu_hw_access.c | 369 +++++ .../media/platform/msm/npu/npu_hw_access.h | 88 ++ drivers/media/platform/msm/npu/npu_mgr.c | 629 +++++++++ drivers/media/platform/msm/npu/npu_mgr.h | 101 ++ include/uapi/linux/msm_npu.h | 132 +- 16 files changed, 4894 insertions(+), 228 deletions(-) create mode 100644 Documentation/devicetree/bindings/media/msm-npu-pwrlevels.txt create mode 100644 drivers/media/platform/msm/npu/npu_dbg.c create mode 100644 drivers/media/platform/msm/npu/npu_debugfs.c create mode 100644 drivers/media/platform/msm/npu/npu_firmware.h create mode 100644 drivers/media/platform/msm/npu/npu_host_ipc.c create mode 100644 drivers/media/platform/msm/npu/npu_host_ipc.h create mode 100644 drivers/media/platform/msm/npu/npu_hw.h create mode 100644 drivers/media/platform/msm/npu/npu_hw_access.c create mode 100644 drivers/media/platform/msm/npu/npu_hw_access.h create mode 100644 drivers/media/platform/msm/npu/npu_mgr.c create mode 100644 drivers/media/platform/msm/npu/npu_mgr.h diff --git a/Documentation/devicetree/bindings/media/msm-npu-pwrlevels.txt b/Documentation/devicetree/bindings/media/msm-npu-pwrlevels.txt new file mode 100644 index 000000000000..9a8a014c95d8 --- /dev/null +++ b/Documentation/devicetree/bindings/media/msm-npu-pwrlevels.txt @@ -0,0 +1,164 @@ +Qualcomm Technologies, Inc. NPU powerlevels + +Powerlevels are defined in sets by qcom,npu-pwrlevels. Each powerlevel defines +a series of clock frequencies. These frequencies are for the corresponding +clocks in the clocks property of the msm_npu device. + +qcom,npu-pwrlevels bindings: + +Required Properties: +- #address-cells: Should be set to 1 +- #size-cells: Should be set to 0 +- compatible: Must be qcom,npu-pwrlevels +- initial-pwrlevel: NPU initial wakeup power level, this is the index of the + child node. + +qcom,npu-pwrlevel: This is a child node defining power levels. +qcom,npu-pwrlevels must contain at least one power level node. Each child node +has the following properties: + +Required Properties: +- reg: Index of the powerlevel (0 = lowest performance) +- clk-freq: List of clock frequencies (in Hz) of each clock for the current + powerlevel. List of clocks and order described in: + Documentation/devicetree/bindings/media/msm-npu.txt + +Example: + qcom,npu-pwrlevels { + #address-cells = <1>; + #size-cells = <0>; + compatible = "qcom,npu-pwrlevels"; + initial-pwrlevel = <4>; + qcom,npu-pwrlevel@0 { + reg = <0>; + clk-freq = <9600000 + 9600000 + 19200000 + 19200000 + 19200000 + 19200000 + 9600000 + 60000000 + 19200000 + 19200000 + 30000000 + 19200000 + 19200000 + 19200000 + 19200000 + 19200000 + 9600000 + 19200000 + 0>; + }; + qcom,npu-pwrlevel@1 { + reg = <1>; + clk-freq = <300000000 + 300000000 + 19200000 + 100000000 + 19200000 + 19200000 + 300000000 + 150000000 + 19200000 + 19200000 + 60000000 + 100000000 + 100000000 + 37500000 + 100000000 + 19200000 + 300000000 + 19200000 + 0>; + }; + qcom,npu-pwrlevel@2 { + reg = <2>; + clk-freq = <350000000 + 350000000 + 19200000 + 150000000 + 19200000 + 19200000 + 350000000 + 200000000 + 37500000 + 19200000 + 120000000 + 150000000 + 150000000 + 75000000 + 150000000 + 19200000 + 350000000 + 19200000 + 0>; + }; + qcom,npu-pwrlevel@3 { + reg = <3>; + clk-freq = <400000000 + 400000000 + 19200000 + 200000000 + 19200000 + 19200000 + 400000000 + 300000000 + 37500000 + 19200000 + 120000000 + 200000000 + 200000000 + 75000000 + 200000000 + 19200000 + 400000000 + 19200000 + 0>; + }; + qcom,npu-pwrlevel@4 { + reg = <4>; + clk-freq = <600000000 + 600000000 + 19200000 + 300000000 + 19200000 + 19200000 + 600000000 + 403000000 + 75000000 + 19200000 + 240000000 + 300000000 + 300000000 + 150000000 + 300000000 + 19200000 + 600000000 + 19200000 + 0>; + }; + qcom,npu-pwrlevel@5 { + reg = <5>; + clk-freq = <715000000 + 715000000 + 19200000 + 350000000 + 19200000 + 19200000 + 715000000 + 533000000 + 75000000 + 19200000 + 240000000 + 350000000 + 350000000 + 150000000 + 350000000 + 19200000 + 715000000 + 19200000 + 0>; + }; + }; diff --git a/Documentation/devicetree/bindings/media/msm-npu.txt b/Documentation/devicetree/bindings/media/msm-npu.txt index 77a276da306a..80e6db79c214 100644 --- a/Documentation/devicetree/bindings/media/msm-npu.txt +++ b/Documentation/devicetree/bindings/media/msm-npu.txt @@ -3,41 +3,226 @@ NPU (Neural Network Processing Unit) applies neural network processing Required properties: -- compatible: - - "qcom,msm-npu" +- compatible: Must be "qcom,msm-npu" - reg: Specify offset and length of the device register sets. - reg-names: Names corresponding to the defined register sets. - - "npu_base": npu base registers + - "npu_base": npu base registers - interrupts: Specify the npu interrupts. -- interrupt-names : should specify relevant names to each interrupts - property defined. -- clocks : clocks required for the device. -- clock-names : names of clocks required for the device. -- vdd-supply : Phandle for vdd regulator device node +- interrupt-names: should specify relevant names to each interrupts + property defined. +- cache-slice-names: A set of names that identify the usecase names of a + client that uses cache slice. These strings are used to look up the + cache slice entries by name +- cache-slices: The tuple has phandle to llcc device as the first argument + and the second argument is the usecase id of the client +- clocks: clocks required for the device. +- clock-names: names of clocks required for the device. +- vdd-supply: Phandle for vdd regulator device node - vdd_'reg'-supply: Reference to the regulator that supplies the corresponding - 'reg' domain, e.g. vdd_cx-supply. + 'reg' domain, e.g. vdd_cx-supply. - qcom,proxy-reg-names: Names of the regulators that need to be turned on/off - during proxy voting/unvoting. + during proxy voting/unvoting. - qcom,vdd_'reg'-uV-uA: Voltage and current values for the 'reg' regulator, - e.g. qcom,vdd_cx-uV-uA. - + e.g. qcom,vdd_cx-uV-uA. +- mboxes: Phandle array for mailbox controllers to be used for IPC +- mbox-names: names of each mailboxes +- #cooling-cells: Should be set to 2 +- qcom,npubw-dev: a phandle to a device representing bus bandwidth requirements + (see devbw.txt) +- qcom,npu-pwrlevels: Container for NPU power levels + (see msm-npu-pwrlevels.txt) Example: - msm_npu: qcom,msm_npu { + msm_npu: qcom,msm_npu@9800000 { compatible = "qcom,msm-npu"; + status = "ok"; reg = <0x9800000 0x800000>; reg-names = "npu_base"; - interrupts = <0 346 0>; - interrupt-names = "single"; - clocks = <&clock_npucc NPU_CC_XO_CLK>, - <&clock_npucc NPU_CC_NPU_CORE_CLK>, - <&clock_npucc NPU_CC_CAL_DP_CLK>, - <&clock_npucc NPU_CC_ARMWIC_CORE_CLK>, - <&clock_npucc NPU_CC_COMP_NOC_AXI_CLK>, - <&clock_npucc NPU_CC_CONF_NOC_AHB_CLK>; - clock-names = "xo", "core", "cal_dp", "armwic", - "axi", "ahb"; + interrupts = ; + iommus = <&apps_smmu 0x1461 0x0>, <&apps_smmu 0x2061 0x0>; + cache-slice-names = "npu"; + cache-slices = <&llcc 23>; + clocks = <&clock_npucc NPU_CC_CAL_DP_CLK>, + <&clock_npucc NPU_CC_CAL_DP_CLK_SRC>, + <&clock_npucc NPU_CC_XO_CLK>, + <&clock_npucc NPU_CC_ARMWIC_CORE_CLK>, + <&clock_npucc NPU_CC_BTO_CORE_CLK>, + <&clock_npucc NPU_CC_BWMON_CLK>, + <&clock_npucc NPU_CC_CAL_DP_CDC_CLK>, + <&clock_npucc NPU_CC_COMP_NOC_AXI_CLK>, + <&clock_npucc NPU_CC_CONF_NOC_AHB_CLK>, + <&clock_npucc NPU_CC_NPU_CORE_APB_CLK>, + <&clock_npucc NPU_CC_NPU_CORE_ATB_CLK>, + <&clock_npucc NPU_CC_NPU_CORE_CLK>, + <&clock_npucc NPU_CC_NPU_CORE_CLK_SRC>, + <&clock_npucc NPU_CC_NPU_CORE_CTI_CLK>, + <&clock_npucc NPU_CC_NPU_CPC_CLK>, + <&clock_npucc NPU_CC_NPU_CPC_TIMER_CLK>, + <&clock_npucc NPU_CC_PERF_CNT_CLK>, + <&clock_npucc NPU_CC_QTIMER_CORE_CLK>, + <&clock_npucc NPU_CC_SLEEP_CLK>; + clock-names = "cal_dp_clk", + "cal_dp_clk_src", + "xo_clk", + "armwic_core_clk", + "bto_core_clk", + "bwmon_clk", + "cal_dp_cdc_clk", + "comp_noc_axi_clk", + "conf_noc_ahb_clk", + "npu_core_apb_clk", + "npu_core_atb_clk", + "npu_core_clk", + "npu_core_clk_src", + "npu_core_cti_clk", + "npu_cpc_clk", + "npu_cpc_timer_clk", + "perf_cnt_clk", + "qtimer_core_clk", + "sleep_clk"; vdd-supply = <&npu_core_gdsc>; vdd_cx-supply = <&pm855l_s6_level>; qcom,proxy-reg-names ="vdd", "vdd_cx"; qcom,vdd_cx-uV-uA = ; + mboxes = <&qmp_npu0 0>, <&qmp_npu1 0>; + mbox-names = "npu_low", "npu_high"; + #cooling-cells = <2>; + qcom,npubw-dev = <&npu_npu_ddr_bw>; + qcom,npu-pwrlevels { + #address-cells = <1>; + #size-cells = <0>; + compatible = "qcom,npu-pwrlevels"; + initial-pwrlevel = <4>; + qcom,npu-pwrlevel@0 { + reg = <0>; + clk-freq = <9600000 + 9600000 + 19200000 + 19200000 + 19200000 + 19200000 + 9600000 + 60000000 + 19200000 + 19200000 + 30000000 + 19200000 + 19200000 + 19200000 + 19200000 + 19200000 + 9600000 + 19200000 + 0>; + }; + qcom,npu-pwrlevel@1 { + reg = <1>; + clk-freq = <300000000 + 300000000 + 19200000 + 100000000 + 19200000 + 19200000 + 300000000 + 150000000 + 19200000 + 19200000 + 60000000 + 100000000 + 100000000 + 37500000 + 100000000 + 19200000 + 300000000 + 19200000 + 0>; + }; + qcom,npu-pwrlevel@2 { + reg = <2>; + clk-freq = <350000000 + 350000000 + 19200000 + 150000000 + 19200000 + 19200000 + 350000000 + 200000000 + 37500000 + 19200000 + 120000000 + 150000000 + 150000000 + 75000000 + 150000000 + 19200000 + 350000000 + 19200000 + 0>; + }; + qcom,npu-pwrlevel@3 { + reg = <3>; + clk-freq = <400000000 + 400000000 + 19200000 + 200000000 + 19200000 + 19200000 + 400000000 + 300000000 + 37500000 + 19200000 + 120000000 + 200000000 + 200000000 + 75000000 + 200000000 + 19200000 + 400000000 + 19200000 + 0>; + }; + qcom,npu-pwrlevel@4 { + reg = <4>; + clk-freq = <600000000 + 600000000 + 19200000 + 300000000 + 19200000 + 19200000 + 600000000 + 403000000 + 75000000 + 19200000 + 240000000 + 300000000 + 300000000 + 150000000 + 300000000 + 19200000 + 600000000 + 19200000 + 0>; + }; + qcom,npu-pwrlevel@5 { + reg = <5>; + clk-freq = <715000000 + 715000000 + 19200000 + 350000000 + 19200000 + 19200000 + 715000000 + 533000000 + 75000000 + 19200000 + 240000000 + 350000000 + 350000000 + 150000000 + 350000000 + 19200000 + 715000000 + 19200000 + 0>; + }; + }; }; diff --git a/drivers/media/platform/msm/npu/Makefile b/drivers/media/platform/msm/npu/Makefile index f80219b4a3fb..712f22e2fca9 100644 --- a/drivers/media/platform/msm/npu/Makefile +++ b/drivers/media/platform/msm/npu/Makefile @@ -1 +1,7 @@ -obj-$(CONFIG_MSM_NPU) += npu_dev.o +obj-$(CONFIG_MSM_NPU) := msm_npu.o +msm_npu-objs := npu_dbg.o \ + npu_dev.o \ + npu_debugfs.o \ + npu_host_ipc.o \ + npu_hw_access.o \ + npu_mgr.o diff --git a/drivers/media/platform/msm/npu/npu_common.h b/drivers/media/platform/msm/npu/npu_common.h index 5c4a6b89ae7b..26b96d7dcb53 100644 --- a/drivers/media/platform/msm/npu/npu_common.h +++ b/drivers/media/platform/msm/npu/npu_common.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -12,35 +12,29 @@ #ifndef _NPU_COMMON_H #define _NPU_COMMON_H -#include -#include -#include -#include + +/* ------------------------------------------------------------------------- + * Includes + * ------------------------------------------------------------------------- + */ +#include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include #include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include #include +#include +#include +#include + +#include "npu_mgr.h" +/* ------------------------------------------------------------------------- + * Defines + * ------------------------------------------------------------------------- + */ /* get npu info */ #define MSM_NPU_GET_INFO_32 \ _IOWR(MSM_NPU_IOCTL_MAGIC, 1, compat_caddr_t) @@ -65,27 +59,109 @@ #define MSM_NPU_EXEC_NETWORK_32 \ _IOWR(MSM_NPU_IOCTL_MAGIC, 6, compat_caddr_t) -#define NPU_MAX_CLK_NUM 8 -#define NPU_MAX_REGULATOR_NUM 4 -#define NPU_MAX_DT_NAME_LEN 16 +#define NPU_MAX_MBOX_NUM 2 +#define NPU_MBOX_LOW_PRI 0 +#define NPU_MBOX_HIGH_PRI 1 -#define NPU_FIRMWARE_VERSION 0x1000 +#define DEFAULT_REG_DUMP_NUM 64 +#define ROW_BYTES 16 +#define GROUP_BYTES 4 + +#define NUM_TOTAL_CLKS 19 +#define NPU_MAX_REGULATOR_NUM 2 +#define NPU_MAX_DT_NAME_LEN 21 +#define NPU_MAX_PWRLEVELS 7 + +/* ------------------------------------------------------------------------- + * Data Structures + * ------------------------------------------------------------------------- + */ +struct npu_smmu_ctx { + int domain; + struct dma_iommu_mapping *mmu_mapping; + struct reg_bus_client *reg_bus_clt; + int32_t attach_cnt; +}; -struct npu_clk_t { +struct npu_ion_buf { + int fd; + struct dma_buf *dma_buf; + struct dma_buf_attachment *attachment; + struct sg_table *table; + dma_addr_t iova; + uint32_t size; + void *phys_addr; + void *buf; + struct list_head list; +}; + +struct npu_clk { struct clk *clk; char clk_name[NPU_MAX_DT_NAME_LEN]; }; -struct npu_regulator_t { +struct npu_regulator { struct regulator *regulator; char regulator_name[NPU_MAX_DT_NAME_LEN]; }; -#define DEFAULT_REG_DUMP_NUM 0x100 -#define ROW_BYTES 16 -#define GROUP_BYTES 4 +struct npu_debugfs_ctx { + struct dentry *root; + uint32_t reg_off; + uint32_t reg_cnt; + char *buf; + size_t buf_len; + uint8_t *log_buf; + struct mutex log_lock; + uint32_t log_num_bytes_buffered; + uint32_t log_read_index; + uint32_t log_write_index; + uint32_t log_buf_size; + bool sys_cache_disable; +}; -struct npu_device_t { +struct npu_mbox { + struct mbox_client client; + struct mbox_chan *chan; + struct npu_device *npu_dev; + uint32_t id; +}; + +/** + * struct npul_pwrlevel - Struct holding different pwrlevel info obtained from + * from dtsi file + * @freq[]: NPU frequency vote in Hz + */ +struct npu_pwrlevel { + long clk_freq[NUM_TOTAL_CLKS]; +}; + +/** + * struct npu_pwrctrl - Power control settings for a NPU device + * @pwr_vote_num - voting information for power enable + * @pwrlevels - List of supported power levels + * @active_pwrlevel - The currently active power level + * @default_pwrlevel - device wake up power level + * @max_pwrlevel - maximum allowable powerlevel per the user + * @min_pwrlevel - minimum allowable powerlevel per the user + * @num_pwrlevels - number of available power levels + * @devbw - bw device + */ +struct npu_pwrctrl { + int32_t pwr_vote_num; + + struct npu_pwrlevel pwrlevels[NPU_MAX_PWRLEVELS]; + uint32_t active_pwrlevel; + uint32_t default_pwrlevel; + uint32_t max_pwrlevel; + uint32_t min_pwrlevel; + uint32_t num_pwrlevels; + + struct device *devbw; + uint32_t bwmon_enabled; +}; + +struct npu_device { struct mutex ctx_lock; struct platform_device *pdev; @@ -97,14 +173,49 @@ struct npu_device_t { size_t reg_size; char __iomem *npu_base; - u32 npu_phys; + uint32_t npu_phys; uint32_t core_clk_num; - struct npu_clk_t core_clks[NPU_MAX_CLK_NUM]; + struct npu_clk core_clks[NUM_TOTAL_CLKS]; uint32_t regulator_num; - struct npu_regulator_t regulators[NPU_MAX_DT_NAME_LEN]; + struct npu_regulator regulators[NPU_MAX_DT_NAME_LEN]; + + uint32_t irq; + + struct npu_ion_buf mapped_buffers; + + struct device *cb_device; - u32 irq; + struct npu_host_ctx host_ctx; + struct npu_smmu_ctx smmu_ctx; + struct npu_debugfs_ctx debugfs_ctx; + + struct npu_mbox mbox[NPU_MAX_MBOX_NUM]; + + struct thermal_cooling_device *tcdev; + struct npu_pwrctrl pwrctrl; + + struct llcc_slice_desc *sys_cache; }; + + +/* ------------------------------------------------------------------------- + * Function Prototypes + * ------------------------------------------------------------------------- + */ +int npu_debugfs_init(struct npu_device *npu_dev); +void npu_debugfs_deinit(struct npu_device *npu_dev); + +int npu_enable_core_power(struct npu_device *npu_dev); +void npu_disable_core_power(struct npu_device *npu_dev); +int npu_enable_post_pil_clocks(struct npu_device *npu_dev); + +irqreturn_t npu_intr_hdler(int irq, void *ptr); + +int npu_set_power_level(struct npu_device *npu_dev, uint32_t pwr_level); + +int fw_init(struct npu_device *npu_dev); +void fw_deinit(struct npu_device *npu_dev); + #endif /* _NPU_COMMON_H */ diff --git a/drivers/media/platform/msm/npu/npu_dbg.c b/drivers/media/platform/msm/npu/npu_dbg.c new file mode 100644 index 000000000000..386433911530 --- /dev/null +++ b/drivers/media/platform/msm/npu/npu_dbg.c @@ -0,0 +1,345 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +/* ------------------------------------------------------------------------- + * Includes + * ------------------------------------------------------------------------- + */ +#include "npu_common.h" +#include "npu_firmware.h" +#include "npu_hw.h" +#include "npu_hw_access.h" +#include "npu_mgr.h" + +/* ------------------------------------------------------------------------- + * File Scope Variables + * ------------------------------------------------------------------------- + */ +static const uint32_t debug_cal_reg_list[] = { + CAL_DP_DMA_WR_RLD_CMD_0, + CAL_DP_DMA_RD_RLD_CMD_0, + CAL_DP_DMA_RD_RLD_CMD_1, + CAL_DP_DMA_RD_RLD_CMD_2, + CAL_DP_DMA_RD_RLD_CMD_3, + CAL_DP_DMA_LOC_RLD_CMD_0, + CAL_DP_DMA_BUS_CFG, + CAL_DP_DMA_BUS_OT_CFG, + CAL_DP_DMA_WR_CFG_0, + CAL_DP_DMA_WR_NUM_CMD_IT_0, + CAL_DP_DMA_WR_START_ADDR_0, + CAL_DP_DMA_WR_MAX_ADDR_0, + CAL_DP_DMA_WR_STRIDE_DIM0_0, + CAL_DP_DMA_WR_STRIDE_DIM1_0, + CAL_DP_DMA_WR_STRIDE_DIM2_0, + CAL_DP_DMA_WR_ROW_INCR_0, + CAL_DP_DMA_WR_DIM0_XSIZE_0, + CAL_DP_DMA_WR_DIM0_INCR_0, + CAL_DP_DMA_WR_DIM0_NUM_BLK_0, + CAL_DP_DMA_WR_DIM1_XSIZE_0, + CAL_DP_DMA_WR_DIM1_YSIZE_0, + CAL_DP_DMA_WR_DIM2_XSIZE_0, + CAL_DP_DMA_WR_DIM2_YSIZE_0, + CAL_DP_DMA_WR_CLIENT_BLK_SIZE_CFG_0, + CAL_DP_DMA_WR_CLIENT_ADDR_CFG_0, + CAL_DP_DMA_WR_CLIENT_BUFF_CFG_0, + CAL_DP_DMA_WR_MMU_CFG_0, + CAL_DP_DMA_RD_CFG_0, + CAL_DP_DMA_RD_NUM_CMD_IT_0, + CAL_DP_DMA_RD_START_ADDR_0, + CAL_DP_DMA_RD_START_ADDR1_0, + CAL_DP_DMA_RD_END_ADDR0_0, + CAL_DP_DMA_RD_MAX_ADDR_0, + CAL_DP_DMA_RD_MAX_ADDR1_0, + CAL_DP_DMA_RD_STRIDE_DIM0_0, + CAL_DP_DMA_RD_STRIDE_DIM0_FIRST_0, + CAL_DP_DMA_RD_STRIDE_DIM1_0, + CAL_DP_DMA_RD_STRIDE_DIM1_FIRST_0, + CAL_DP_DMA_RD_STRIDE_DIM2_0, + CAL_DP_DMA_RD_STRIDE_DIM2_FIRST_0, + CAL_DP_DMA_RD_ROW_INCR_0, + CAL_DP_DMA_RD_DIM0_BLK_SIZE_0, + CAL_DP_DMA_RD_DIM0_INCR_0, + CAL_DP_DMA_RD_DIM0_NUM_BLK_0, + CAL_DP_DMA_RD_DIM1_BLK_SIZE_0, + CAL_DP_DMA_RD_DIM1_STRIPE_SIZE_0, + CAL_DP_DMA_RD_DIM2_BLK_SIZE_0, + CAL_DP_DMA_RD_DIM2_STRIPE_SIZE_0, + CAL_DP_DMA_RD_DIM0_PAD_L_0, + CAL_DP_DMA_RD_DIM0_PAD_R_0, + CAL_DP_DMA_RD_PAD_TB_0, + CAL_DP_DMA_RD_DIM0_CROP_0, + CAL_DP_DMA_RD_CLIENT_ADDR_CFG_0, + CAL_DP_DMA_RD_CLIENT_BUFF_CFG_0, + CAL_DP_DMA_RD_MMU_CFG_0, + CAL_DP_DMA_RD_PAD_VALUE_0, + CAL_DP_DMA_RD_CFG_1, + CAL_DP_DMA_RD_NUM_CMD_IT_1, + CAL_DP_DMA_RD_START_ADDR_1, + CAL_DP_DMA_RD_START_ADDR1_1, + CAL_DP_DMA_RD_END_ADDR0_1, + CAL_DP_DMA_RD_MAX_ADDR_1, + CAL_DP_DMA_RD_MAX_ADDR1_1, + CAL_DP_DMA_RD_STRIDE_DIM0_1, + CAL_DP_DMA_RD_STRIDE_DIM0_FIRST_1, + CAL_DP_DMA_RD_STRIDE_DIM1_1, + CAL_DP_DMA_RD_STRIDE_DIM1_FIRST_1, + CAL_DP_DMA_RD_STRIDE_DIM2_1, + CAL_DP_DMA_RD_STRIDE_DIM2_FIRST_1, + CAL_DP_DMA_RD_ROW_INCR_1, + CAL_DP_DMA_RD_DIM0_BLK_SIZE_1, + CAL_DP_DMA_RD_DIM0_INCR_1, + CAL_DP_DMA_RD_DIM0_NUM_BLK_1, + CAL_DP_DMA_RD_DIM1_BLK_SIZE_1, + CAL_DP_DMA_RD_DIM1_STRIPE_SIZE_1, + CAL_DP_DMA_RD_DIM2_BLK_SIZE_1, + CAL_DP_DMA_RD_DIM2_STRIPE_SIZE_1, + CAL_DP_DMA_RD_DIM0_PAD_L_1, + CAL_DP_DMA_RD_DIM0_PAD_R_1, + CAL_DP_DMA_RD_PAD_TB_1, + CAL_DP_DMA_RD_DIM0_CROP_1, + CAL_DP_DMA_RD_CLIENT_ADDR_CFG_1, + CAL_DP_DMA_RD_CLIENT_BUFF_CFG_1, + CAL_DP_DMA_RD_MMU_CFG_1, + CAL_DP_DMA_RD_PAD_VALUE_1, + CAL_DP_DMA_RD_CFG_2, + CAL_DP_DMA_RD_NUM_CMD_IT_2, + CAL_DP_DMA_RD_START_ADDR_2, + CAL_DP_DMA_RD_START_ADDR1_2, + CAL_DP_DMA_RD_END_ADDR0_2, + CAL_DP_DMA_RD_MAX_ADDR_2, + CAL_DP_DMA_RD_MAX_ADDR1_2, + CAL_DP_DMA_RD_STRIDE_DIM0_2, + CAL_DP_DMA_RD_STRIDE_DIM0_FIRST_2, + CAL_DP_DMA_RD_STRIDE_DIM1_2, + CAL_DP_DMA_RD_STRIDE_DIM1_FIRST_2, + CAL_DP_DMA_RD_STRIDE_DIM2_2, + CAL_DP_DMA_RD_STRIDE_DIM2_FIRST_2, + CAL_DP_DMA_RD_ROW_INCR_2, + CAL_DP_DMA_RD_DIM0_BLK_SIZE_2, + CAL_DP_DMA_RD_DIM0_INCR_2, + CAL_DP_DMA_RD_DIM0_NUM_BLK_2, + CAL_DP_DMA_RD_DIM1_BLK_SIZE_2, + CAL_DP_DMA_RD_DIM1_STRIPE_SIZE_2, + CAL_DP_DMA_RD_DIM2_BLK_SIZE_2, + CAL_DP_DMA_RD_DIM2_STRIPE_SIZE_2, + CAL_DP_DMA_RD_DIM0_PAD_L_2, + CAL_DP_DMA_RD_DIM0_PAD_R_2, + CAL_DP_DMA_RD_PAD_TB_2, + CAL_DP_DMA_RD_DIM0_CROP_2, + CAL_DP_DMA_RD_CLIENT_ADDR_CFG_2, + CAL_DP_DMA_RD_CLIENT_BUFF_CFG_2, + CAL_DP_DMA_RD_MMU_CFG_2, + CAL_DP_DMA_RD_PAD_VALUE_2, + CAL_DP_DMA_RD_CFG_3, + CAL_DP_DMA_RD_NUM_CMD_IT_3, + CAL_DP_DMA_RD_START_ADDR_3, + CAL_DP_DMA_RD_START_ADDR1_3, + CAL_DP_DMA_RD_END_ADDR0_3, + CAL_DP_DMA_RD_MAX_ADDR_3, + CAL_DP_DMA_RD_MAX_ADDR1_3, + CAL_DP_DMA_RD_STRIDE_DIM0_3, + CAL_DP_DMA_RD_STRIDE_DIM0_FIRST_3, + CAL_DP_DMA_RD_STRIDE_DIM1_3, + CAL_DP_DMA_RD_STRIDE_DIM1_FIRST_3, + CAL_DP_DMA_RD_STRIDE_DIM2_3, + CAL_DP_DMA_RD_STRIDE_DIM2_FIRST_3, + CAL_DP_DMA_RD_ROW_INCR_3, + CAL_DP_DMA_RD_DIM0_BLK_SIZE_3, + CAL_DP_DMA_RD_DIM0_INCR_3, + CAL_DP_DMA_RD_DIM0_NUM_BLK_3, + CAL_DP_DMA_RD_DIM1_BLK_SIZE_3, + CAL_DP_DMA_RD_DIM1_STRIPE_SIZE_3, + CAL_DP_DMA_RD_DIM2_BLK_SIZE_3, + CAL_DP_DMA_RD_DIM2_STRIPE_SIZE_3, + CAL_DP_DMA_RD_DIM0_PAD_L_3, + CAL_DP_DMA_RD_DIM0_PAD_R_3, + CAL_DP_DMA_RD_PAD_TB_3, + CAL_DP_DMA_RD_DIM0_CROP_3, + CAL_DP_DMA_RD_CLIENT_ADDR_CFG_3, + CAL_DP_DMA_RD_CLIENT_BUFF_CFG_3, + CAL_DP_DMA_RD_MMU_CFG_3, + CAL_DP_DMA_RD_PAD_VALUE_3, + CAL_DP_DMA_LOC_SRC_ADDR_0, + CAL_DP_DMA_LOC_DEST_ADDR_0, + CAL_DP_DMA_LOC_DATA_SIZE_0, + CAL_DP_DMA_WR_ERR_STATUS_0, + CAL_DP_DMA_WR_MAX_P_CNT_0, + CAL_DP_DMA_WR_STATUS_0_0, + CAL_DP_DMA_WR_STATUS_0_1, + CAL_DP_DMA_WR_STATUS_0_2, + CAL_DP_DMA_WR_STATUS_0_3, + CAL_DP_DMA_RD_ERR_STATUS_0, + CAL_DP_DMA_RD_MAX_P_CNT_0, + CAL_DP_DMA_RD_STATUS_0_0, + CAL_DP_DMA_RD_STATUS_0_1, + CAL_DP_DMA_RD_STATUS_0_2, + CAL_DP_DMA_RD_STATUS_0_3, + CAL_DP_DMA_RD_STATUS_0_4, + CAL_DP_DMA_RD_ERR_STATUS_1, + CAL_DP_DMA_RD_MAX_P_CNT_1, + CAL_DP_DMA_RD_STATUS_1_0, + CAL_DP_DMA_RD_STATUS_1_1, + CAL_DP_DMA_RD_STATUS_1_2, + CAL_DP_DMA_RD_STATUS_1_3, + CAL_DP_DMA_RD_STATUS_1_4, + CAL_DP_DMA_RD_ERR_STATUS_2, + CAL_DP_DMA_RD_MAX_P_CNT_2, + CAL_DP_DMA_RD_STATUS_2_0, + CAL_DP_DMA_RD_STATUS_2_1, + CAL_DP_DMA_RD_STATUS_2_2, + CAL_DP_DMA_RD_STATUS_2_3, + CAL_DP_DMA_RD_STATUS_2_4, + CAL_DP_DMA_RD_ERR_STATUS_3, + CAL_DP_DMA_RD_MAX_P_CNT_3, + CAL_DP_DMA_RD_STATUS_3_0, + CAL_DP_DMA_RD_STATUS_3_1, + CAL_DP_DMA_RD_STATUS_3_2, + CAL_DP_DMA_RD_STATUS_3_3, + CAL_DP_DMA_LOC_ERR_STATUS_0, + CAL_DP_DMA_LOC_STATUS_0_0, + CAL_DP_DMA_LOC_STATUS_0_1, + CAL_DP_DMA_LOC_STATUS_0_2, + CAL_DP_DMA_LOC_STATUS_0_3, + CAL_DP_CALDMA_ADAPT_STATUS_0_0, + CAL_DP_CALDMA_ADAPT_STATUS_0_1, + CAL_DP_SDMA_WR_STATUS_0_0, + CAL_DP_SDMA_WR_STATUS_0_1, + CAL_DP_SDMA_WR_STATUS_0_2, + CAL_DP_SDMA_WR_STATUS_0_3, + CAL_DP_SDMA_WR_STATUS_0_4, + CAL_DP_SDMA_WR_STATUS_0_5, + CAL_DP_SDMA_WR_STATUS_0_6, + CAL_DP_SDMA_WR_STATUS_0_7, + CAL_DP_SDMA_WR_STATUS_0_8, + CAL_DP_SDMA_RD_STATUS_0_0, + CAL_DP_SDMA_RD_STATUS_0_1, + CAL_DP_SDMA_RD_STATUS_0_2, + CAL_DP_SDMA_RD_STATUS_0_3, + CAL_DP_SDMA_RD_STATUS_0_4, + CAL_DP_SDMA_RD_STATUS_0_5, + CAL_DP_SDMA_RD_STATUS_0_6, + CAL_DP_SDMA_RD_STATUS_0_7, + CAL_DP_SDMA_RD_STATUS_0_8, + CAL_DP_SDMA_RD_STATUS_0_9, + CAL_DP_SDMA_RD_STATUS_0_10, + CAL_DP_TCM_SET_CMD, + CAL_DP_TCM_RESET_CMD, + CAL_DP_DTSWC_INT_CLR, + CAL_DP_TCM_INT_CLR, + CAL_DP_DTSWC_INT_SET, + CAL_DP_TCM_INT_SET, + CAL_DP_WD_RSS_CMD, + CAL_DP_RESET_CMD, + CAL_DP_PERF_CNT_CMD, + CAL_DP_DBUF_TRANSFER_CMD, + CAL_DP_CAL_EN_CTRL, + CAL_DP_EN_INT_CTRL, + CAL_DP_EN_TCM_INT_CTRL, + CAL_DP_TCM_VAL_CTRL, + CAL_DP_WD_COUNT_LO, + CAL_DP_WD_COUNT_HI, + CAL_DP_RSS_SEL_CTRL, + CAL_DP_CAL_CFG_W0, + CAL_DP_CAL_CFG_W1, + CAL_DP_CAL_CFG_W2, + CAL_DP_CAL_CFG_W3, + CAL_DP_PERF_CNT_START_SEL, + CAL_DP_PERF_CNT_STOP_SEL, + CAL_DP_PERF_CNT_EVENT_SEL, + CAL_DP_DBUF_RD_SEL, + CAL_DP_LM_CTRL, + CAL_DP_LM_LOOK_AHEAD, + CAL_DP_LM_CUB_TIMER, + CAL_DP_SIGB_STATUS, + CAL_DP_CAL_EN_WD_RSS_STATUS, + CAL_DP_EN_TCM_FLAGS_STATUS, + CAL_DP_VERSION_STATUS, + CAL_DP_CFG_STATUS, + CAL_DP_CUB_SAT_DTCT_STATUS, + CAL_DP_AHB_ERR_ADDR_STATUS, + CAL_DP_WD_STATUS_LO, + CAL_DP_WD_STATUS_HI, + CAL_DP_DTSWC_INT_STATUS, + CAL_DP_DTSWC_TCM_INT_STATUS, + CAL_DP_DTSWC_UM_INT_STATUS, + CAL_DP_DTSWC_TCM_UM_INT_STATUS, + CAL_DP_RSS_STATUS, + CAL_DP_RSS_STATUS_1, + CAL_DP_RSS_STATUS_2, + CAL_DP_RSS_STATUS_3, + CAL_DP_RSS_STATUS_4, + CAL_DP_RSS_STATUS_5, + CAL_DP_RSS_STATUS_6, + CAL_DP_RSS_STATUS_7, + CAL_DP_PERF_CNT0, + CAL_DP_PERF_CNT1, + CAL_DP_PERF_CNT2, + CAL_DP_PERF_CNT3, + CAL_DP_FINAL_MIN, + CAL_DP_FINAL_MAX, + CAL_DP_LM_STATUS +}; + +/* ------------------------------------------------------------------------- + * Function Definitions - Debug + * ------------------------------------------------------------------------- + */ +void npu_dump_debug_timeout_stats(struct npu_device *npu_dev) +{ + uint32_t reg_val; + + reg_val = REGR(npu_dev, REG_FW_JOB_CNT_START); + pr_info("fw jobs execute started count = %d\n", reg_val); + reg_val = REGR(npu_dev, REG_FW_JOB_CNT_END); + pr_info("fw jobs execute finished count = %d\n", reg_val); + reg_val = REGR(npu_dev, REG_NPU_FW_DEBUG_DATA); + pr_info("fw jobs aco parser debug = %d\n", reg_val); + npu_dump_cal_state(npu_dev); +} + +void npu_dump_cal_state(struct npu_device *npu_dev) +{ + uint32_t reg_val; + uint32_t i; + + reg_val = REGR(npu_dev, CAL_DP_DMA_RD_START_ADDR_0); + pr_info("DMA RD 0 Addr: 0x%x\n", reg_val); + reg_val = REGR(npu_dev, CAL_DP_DMA_WR_START_ADDR_0); + pr_info("DMA WR Addr: 0x%x\n", reg_val); + reg_val = REGR(npu_dev, CAL_DP_DMA_RD_START_ADDR_1); + pr_info("DMA RD 1 Addr: 0x%x\n", reg_val); + reg_val = REGR(npu_dev, CAL_DP_DMA_RD_START_ADDR_2); + pr_info("DMA RD 2 Addr: 0x%x\n", reg_val); + + /* mask irq status reg */ + reg_val = REGR(npu_dev, CAL_DP_DTSWC_INT_STATUS); + pr_info("Masked ISR Status: 0x%x\n", reg_val); + + /* unmasked mask irq status reg */ + reg_val = REGR(npu_dev, CAL_DP_DTSWC_UM_INT_STATUS); + pr_info("UnMasked ISR Status: 0x%x\n", reg_val); + + reg_val = REGR(npu_dev, CAL_DP_DMA_RD_ERR_STATUS_0); + pr_info("rd err 0 Status: 0x%x\n", reg_val); + reg_val = REGR(npu_dev, CAL_DP_DMA_RD_ERR_STATUS_1); + pr_info("rd err 1 Status: 0x%x\n", reg_val); + reg_val = REGR(npu_dev, CAL_DP_DMA_RD_ERR_STATUS_2); + pr_info("rd err 2 Status: 0x%x\n", reg_val); + + for (i = 0; i < sizeof(debug_cal_reg_list) / sizeof(uint32_t); i++) { + reg_val = REGR(npu_dev, debug_cal_reg_list[i]); + pr_info("Reg = 0x%x Val = 0x%x\n", debug_cal_reg_list[i], + reg_val); + } +} diff --git a/drivers/media/platform/msm/npu/npu_debugfs.c b/drivers/media/platform/msm/npu/npu_debugfs.c new file mode 100644 index 000000000000..c4a25ab46763 --- /dev/null +++ b/drivers/media/platform/msm/npu/npu_debugfs.c @@ -0,0 +1,492 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +/* ------------------------------------------------------------------------- + * Includes + * ------------------------------------------------------------------------- + */ +#include + +#include "npu_hw_access.h" +#include "npu_common.h" + +/* ------------------------------------------------------------------------- + * Defines + * ------------------------------------------------------------------------- + */ +#define NPU_LOG_BUF_SIZE 4096 + +/* ------------------------------------------------------------------------- + * Function Prototypes + * ------------------------------------------------------------------------- + */ +static int npu_debug_open(struct inode *inode, struct file *file); +static int npu_debug_release(struct inode *inode, struct file *file); +static ssize_t npu_debug_reg_write(struct file *file, + const char __user *user_buf, size_t count, loff_t *ppos); +static ssize_t npu_debug_reg_read(struct file *file, + char __user *user_buf, size_t count, loff_t *ppos); +static ssize_t npu_debug_off_write(struct file *file, + const char __user *user_buf, size_t count, loff_t *ppos); +static ssize_t npu_debug_off_read(struct file *file, + char __user *user_buf, size_t count, loff_t *ppos); +static ssize_t npu_debug_log_read(struct file *file, + char __user *user_buf, size_t count, loff_t *ppos); +static ssize_t npu_debug_ctrl_write(struct file *file, + const char __user *user_buf, size_t count, loff_t *ppos); + +/* ------------------------------------------------------------------------- + * Variables + * ------------------------------------------------------------------------- + */ +struct npu_device *g_npu_dev; + +static const struct file_operations npu_reg_fops = { + .open = npu_debug_open, + .release = npu_debug_release, + .read = npu_debug_reg_read, + .write = npu_debug_reg_write, +}; + +static const struct file_operations npu_off_fops = { + .open = npu_debug_open, + .release = npu_debug_release, + .read = npu_debug_off_read, + .write = npu_debug_off_write, +}; + +static const struct file_operations npu_log_fops = { + .open = npu_debug_open, + .release = npu_debug_release, + .read = npu_debug_log_read, + .write = NULL, +}; + +static const struct file_operations npu_ctrl_fops = { + .open = npu_debug_open, + .release = npu_debug_release, + .read = NULL, + .write = npu_debug_ctrl_write, +}; + +/* ------------------------------------------------------------------------- + * Function Implementations + * ------------------------------------------------------------------------- + */ +static int npu_debug_open(struct inode *inode, struct file *file) +{ + /* non-seekable */ + file->f_mode &= ~(FMODE_LSEEK | FMODE_PREAD | FMODE_PWRITE); + file->private_data = inode->i_private; + return 0; +} + +static int npu_debug_release(struct inode *inode, struct file *file) +{ + struct npu_device *npu_dev = file->private_data; + struct npu_debugfs_ctx *debugfs; + + debugfs = &npu_dev->debugfs_ctx; + + kfree(debugfs->buf); + debugfs->buf_len = 0; + debugfs->buf = NULL; + return 0; +} + +/* ------------------------------------------------------------------------- + * Function Implementations - Reg Read/Write + * ------------------------------------------------------------------------- + */ +static ssize_t npu_debug_reg_write(struct file *file, + const char __user *user_buf, size_t count, loff_t *ppos) +{ + size_t off; + uint32_t data, cnt; + struct npu_device *npu_dev = file->private_data; + char buf[24]; + + if (count >= sizeof(buf)) + return -EINVAL; + + if (copy_from_user(buf, user_buf, count)) + return -EFAULT; + + buf[count] = 0; /* end of string */ + + cnt = sscanf(buf, "%zx %x", &off, &data); + pr_debug("%s %s 0x%zx, 0x%08x\n", __func__, buf, off, data); + + return count; + if (cnt < 2) + return -EINVAL; + + if (npu_enable_core_power(npu_dev)) + return -EPERM; + + REGW(npu_dev, off, data); + + npu_disable_core_power(npu_dev); + + pr_debug("write: addr=%zx data=%x\n", off, data); + + return count; +} + +static ssize_t npu_debug_reg_read(struct file *file, + char __user *user_buf, size_t count, loff_t *ppos) +{ + struct npu_device *npu_dev = file->private_data; + struct npu_debugfs_ctx *debugfs; + size_t len; + + debugfs = &npu_dev->debugfs_ctx; + + if (debugfs->reg_cnt == 0) + return 0; + + if (!debugfs->buf) { + char dump_buf[64]; + char *ptr; + int cnt, tot, off; + + debugfs->buf_len = sizeof(dump_buf) * + DIV_ROUND_UP(debugfs->reg_cnt, ROW_BYTES); + debugfs->buf = kzalloc(debugfs->buf_len, GFP_KERNEL); + + if (!debugfs->buf) + return -ENOMEM; + + ptr = npu_dev->npu_base + debugfs->reg_off; + tot = 0; + off = (int)debugfs->reg_off; + + if (npu_enable_core_power(npu_dev)) + return -EPERM; + + for (cnt = debugfs->reg_cnt * 4; cnt > 0; cnt -= ROW_BYTES) { + hex_dump_to_buffer(ptr, min(cnt, ROW_BYTES), + ROW_BYTES, GROUP_BYTES, dump_buf, + sizeof(dump_buf), false); + len = scnprintf(debugfs->buf + tot, + debugfs->buf_len - tot, "0x%08x: %s\n", + ((int) (unsigned long) ptr) - + ((int) (unsigned long) npu_dev->npu_base), + dump_buf); + + ptr += ROW_BYTES; + tot += len; + if (tot >= debugfs->buf_len) + break; + } + npu_disable_core_power(npu_dev); + + debugfs->buf_len = tot; + } + + if (*ppos >= debugfs->buf_len) + return 0; /* done reading */ + + len = min(count, debugfs->buf_len - (size_t) *ppos); + pr_debug("read %zi %zi", count, debugfs->buf_len - (size_t) *ppos); + if (copy_to_user(user_buf, debugfs->buf + *ppos, len)) { + pr_err("failed to copy to user\n"); + return -EFAULT; + } + + *ppos += len; /* increase offset */ + return len; +} + +/* ------------------------------------------------------------------------- + * Function Implementations - Offset Read/Write + * ------------------------------------------------------------------------- + */ +static ssize_t npu_debug_off_write(struct file *file, + const char __user *user_buf, size_t count, loff_t *ppos) +{ + size_t off = 0; + uint32_t cnt, reg_cnt; + char buf[24]; + struct npu_device *npu_dev = file->private_data; + struct npu_debugfs_ctx *debugfs; + + pr_debug("npu_dev %pK %pK\n", npu_dev, g_npu_dev); + npu_dev = g_npu_dev; + debugfs = &npu_dev->debugfs_ctx; + + if (count >= sizeof(buf)) + return -EINVAL; + + if (copy_from_user(buf, user_buf, count)) + return -EFAULT; + + buf[count] = 0; /* end of string */ + + cnt = sscanf(buf, "%zx %x", &off, ®_cnt); + if (cnt == 1) + reg_cnt = DEFAULT_REG_DUMP_NUM; + pr_debug("reg off = %zx, %d cnt=%d\n", off, reg_cnt, cnt); + if (cnt >= 1) { + debugfs->reg_off = off; + debugfs->reg_cnt = reg_cnt; + } + + return count; +} + +static ssize_t npu_debug_off_read(struct file *file, + char __user *user_buf, size_t count, loff_t *ppos) +{ + size_t len; + char buf[64]; + struct npu_device *npu_dev = file->private_data; + struct npu_debugfs_ctx *debugfs; + + pr_debug("npu_dev %pK %pK\n", npu_dev, g_npu_dev); + npu_dev = g_npu_dev; + debugfs = &npu_dev->debugfs_ctx; + + if (*ppos) + return 0; /* the end */ + + len = scnprintf(buf, sizeof(buf), "offset=0x%08x cnt=%d\n", + debugfs->reg_off, debugfs->reg_cnt); + + if (copy_to_user(user_buf, buf, len)) { + pr_err("failed to copy to user\n"); + return -EFAULT; + } + + *ppos += len; /* increase offset */ + return len; +} + +/* ------------------------------------------------------------------------- + * Function Implementations - DebugFS Log + * ------------------------------------------------------------------------- + */ +static ssize_t npu_debug_log_read(struct file *file, + char __user *user_buf, size_t count, loff_t *ppos) +{ + size_t len = 0; + struct npu_device *npu_dev = file->private_data; + struct npu_debugfs_ctx *debugfs; + + pr_debug("npu_dev %pK %pK\n", npu_dev, g_npu_dev); + npu_dev = g_npu_dev; + debugfs = &npu_dev->debugfs_ctx; + + /* mutex log lock */ + mutex_lock(&debugfs->log_lock); + + if (debugfs->log_num_bytes_buffered != 0) { + if ((debugfs->log_read_index + + debugfs->log_num_bytes_buffered) > + debugfs->log_buf_size) { + /* Wrap around case */ + uint32_t remaining_to_end = debugfs->log_buf_size - + debugfs->log_read_index; + uint8_t *src_addr = debugfs->log_buf + + debugfs->log_read_index; + uint8_t *dst_addr = user_buf; + + if (copy_to_user(dst_addr, src_addr, + remaining_to_end)) { + pr_err("%s failed to copy to user", __func__); + return -EFAULT; + } + src_addr = debugfs->log_buf; + dst_addr = user_buf + remaining_to_end; + if (copy_to_user(dst_addr, src_addr, + debugfs->log_num_bytes_buffered - + remaining_to_end)) { + pr_err("%s failed to copy to user", __func__); + return -EFAULT; + } + debugfs->log_read_index = + debugfs->log_num_bytes_buffered - + remaining_to_end; + } else { + if (copy_to_user(user_buf, (debugfs->log_buf + + debugfs->log_read_index), + debugfs->log_num_bytes_buffered)) { + pr_err("%s failed to copy to user", __func__); + return -EFAULT; + } + debugfs->log_read_index += + debugfs->log_num_bytes_buffered; + if (debugfs->log_read_index == debugfs->log_buf_size) + debugfs->log_read_index = 0; + } + len = debugfs->log_num_bytes_buffered; + debugfs->log_num_bytes_buffered = 0; + } + + /* mutex log unlock */ + mutex_unlock(&debugfs->log_lock); + + return len; +} + +/* ------------------------------------------------------------------------- + * Function Implementations - DebugFS Control + * ------------------------------------------------------------------------- + */ +static ssize_t npu_debug_ctrl_write(struct file *file, + const char __user *user_buf, size_t count, loff_t *ppos) +{ + char buf[24]; + struct npu_device *npu_dev = file->private_data; + struct npu_debugfs_ctx *debugfs; + + pr_debug("npu_dev %pK %pK\n", npu_dev, g_npu_dev); + npu_dev = g_npu_dev; + debugfs = &npu_dev->debugfs_ctx; + + if (count >= sizeof(buf)) + return -EINVAL; + + if (copy_from_user(buf, user_buf, count)) + return -EFAULT; + + buf[count] = 0; /* end of string */ + + if (count >= 2) + buf[count-1] = 0;/* remove line feed */ + + if (strcmp(buf, "on") == 0) { + pr_info("triggering fw_init\n"); + if (fw_init(npu_dev) != 0) + pr_info("error in fw_init\n"); + } else if (strcmp(buf, "off") == 0) { + pr_info("triggering fw_deinit\n"); + fw_deinit(npu_dev); + } else if (strcmp(buf, "0") == 0) { + pr_info("setting power state to 0\n"); + npu_dev->pwrctrl.active_pwrlevel = 0; + } else if (strcmp(buf, "1") == 0) { + pr_info("setting power state to 1\n"); + npu_dev->pwrctrl.active_pwrlevel = 1; + } else if (strcmp(buf, "2") == 0) { + pr_info("setting power state to 2\n"); + npu_dev->pwrctrl.active_pwrlevel = 2; + } else if (strcmp(buf, "3") == 0) { + pr_info("setting power state to 3\n"); + npu_dev->pwrctrl.active_pwrlevel = 3; + } else if (strcmp(buf, "4") == 0) { + pr_info("setting power state to 4\n"); + npu_dev->pwrctrl.active_pwrlevel = 4; + } else if (strcmp(buf, "5") == 0) { + pr_info("setting power state to 5\n"); + npu_dev->pwrctrl.active_pwrlevel = 5; + } else { + pr_info("ctrl invalid value\n"); + } + + return count; +} +/* ------------------------------------------------------------------------- + * Function Implementations - DebugFS + * ------------------------------------------------------------------------- + */ +int npu_debugfs_init(struct npu_device *npu_dev) +{ + struct npu_debugfs_ctx *debugfs = &npu_dev->debugfs_ctx; + struct npu_host_ctx *host_ctx = &npu_dev->host_ctx; + struct npu_pwrctrl *pwr = &npu_dev->pwrctrl; + + g_npu_dev = npu_dev; + debugfs->sys_cache_disable = 1; + + debugfs->root = debugfs_create_dir("npu", NULL); + if (IS_ERR_OR_NULL(debugfs->root)) { + pr_err("debugfs_create_dir for npu failed, error %ld\n", + PTR_ERR(debugfs->root)); + return -ENODEV; + } + + if (!debugfs_create_file("reg", 0644, debugfs->root, + npu_dev, &npu_reg_fops)) { + pr_err("debugfs_create_file reg fail\n"); + goto err; + } + + if (!debugfs_create_file("off", 0644, debugfs->root, + npu_dev, &npu_off_fops)) { + pr_err("debugfs_create_file off fail\n"); + goto err; + } + + if (!debugfs_create_file("log", 0644, debugfs->root, + npu_dev, &npu_log_fops)) { + pr_err("debugfs_create_file log fail\n"); + goto err; + } + + if (!debugfs_create_file("ctrl", 0644, debugfs->root, + npu_dev, &npu_ctrl_fops)) { + pr_err("debugfs_create_file ctrl fail\n"); + goto err; + } + + if (!debugfs_create_bool("sys_cache_disable", 0644, + debugfs->root, &debugfs->sys_cache_disable)) { + pr_err("debugfs_creat_bool fail for sys cache\n"); + goto err; + } + + if (!debugfs_create_bool("fw_state", 0444, + debugfs->root, &(host_ctx->fw_enabled))) { + pr_err("debugfs_creat_bool fail for fw_state\n"); + goto err; + } + + if (!debugfs_create_u32("pwr_level", 0444, + debugfs->root, &(pwr->active_pwrlevel))) { + pr_err("debugfs_creat_bool fail for power level\n"); + goto err; + } + + debugfs->log_num_bytes_buffered = 0; + debugfs->log_read_index = 0; + debugfs->log_write_index = 0; + debugfs->log_buf_size = NPU_LOG_BUF_SIZE; + debugfs->log_buf = kzalloc(debugfs->log_buf_size, GFP_KERNEL); + if (!debugfs->log_buf) + goto err; + mutex_init(&debugfs->log_lock); + + return 0; + +err: + npu_debugfs_deinit(npu_dev); + return -ENODEV; +} + +void npu_debugfs_deinit(struct npu_device *npu_dev) +{ + struct npu_debugfs_ctx *debugfs = &npu_dev->debugfs_ctx; + + debugfs->log_num_bytes_buffered = 0; + debugfs->log_read_index = 0; + debugfs->log_write_index = 0; + debugfs->log_buf_size = 0; + kfree(debugfs->log_buf); + + if (!IS_ERR_OR_NULL(debugfs->root)) { + debugfs_remove_recursive(debugfs->root); + debugfs->root = NULL; + } +} diff --git a/drivers/media/platform/msm/npu/npu_dev.c b/drivers/media/platform/msm/npu/npu_dev.c index 03afbb1ab1d8..f466b0c8b1bc 100644 --- a/drivers/media/platform/msm/npu/npu_dev.c +++ b/drivers/media/platform/msm/npu/npu_dev.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -6,29 +6,156 @@ * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +/* ------------------------------------------------------------------------- + * Includes + * ------------------------------------------------------------------------- + */ +#include +#include +#include +#include +#include +#include +#include +#include + #include "npu_common.h" +#include "npu_hw.h" + +/* ------------------------------------------------------------------------- + * Defines + * ------------------------------------------------------------------------- + */ +#define CLASS_NAME "npu" +#define DRIVER_NAME "msm_npu" +#define DDR_MAPPED_START_ADDR 0x80000000 +#define DDR_MAPPED_SIZE 0x60000000 -#define CLASS_NAME "npu" -#define DRIVER_NAME "msm_npu" +#define POWER_LEVEL_MIN_SVS 0 +#define POWER_LEVEL_LOW_SVS 1 +#define POWER_LEVEL_NOMINAL 4 +/* ------------------------------------------------------------------------- + * File Scope Prototypes + * ------------------------------------------------------------------------- + */ +static int npu_enable_regulators(struct npu_device *npu_dev); +static void npu_disable_regulators(struct npu_device *npu_dev); +static int npu_enable_core_clocks(struct npu_device *npu_dev, bool post_pil); +static void npu_disable_core_clocks(struct npu_device *npu_dev); +static int npu_calc_power_level(struct npu_device *npu_dev, + uint32_t perf_mode); static ssize_t npu_show_capabilities(struct device *dev, - struct device_attribute *attr, char *buf) -{ - size_t ret = 0; + struct device_attribute *attr, char *buf); +static ssize_t npu_show_pwr_state(struct device *dev, + struct device_attribute *attr, + char *buf); +static ssize_t npu_store_pwr_state(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count); +static void npu_suspend_devbw(struct npu_device *npu_dev); +static void npu_resume_devbw(struct npu_device *npu_dev); +static bool npu_is_post_clock(const char *clk_name); +static bool npu_is_exclude_clock(const char *clk_name); +static bool npu_is_exclude_rate_clock(const char *clk_name); +static int npu_get_max_state(struct thermal_cooling_device *cdev, + unsigned long *state); +static int npu_get_cur_state(struct thermal_cooling_device *cdev, + unsigned long *state); +static int npu_set_cur_state(struct thermal_cooling_device *cdev, + unsigned long state); +static int npu_open(struct inode *inode, struct file *file); +static int npu_close(struct inode *inode, struct file *file); +static int npu_get_info(struct npu_device *npu_dev, unsigned long arg); +static int npu_map_buf(struct npu_device *npu_dev, unsigned long arg); +static int npu_unmap_buf(struct npu_device *npu_dev, unsigned long arg); +static int npu_load_network(struct npu_device *npu_dev, unsigned long arg); +static int npu_unload_network(struct npu_device *npu_dev, unsigned long arg); +static int npu_exec_network(struct npu_device *npu_dev, unsigned long arg); +static long npu_ioctl(struct file *file, unsigned int cmd, + unsigned long arg); +static int npu_parse_dt_clock(struct npu_device *npu_dev); +static int npu_parse_dt_regulator(struct npu_device *npu_dev); +static int npu_of_parse_pwrlevels(struct npu_device *npu_dev, + struct device_node *node); +static int npu_pwrctrl_init(struct npu_device *npu_dev); +static int npu_probe(struct platform_device *pdev); +static int npu_remove(struct platform_device *pdev); +static int npu_suspend(struct platform_device *dev, pm_message_t state); +static int npu_resume(struct platform_device *dev); +static int __init npu_init(void); +static void __exit npu_exit(void); - ret = snprintf(buf, PAGE_SIZE, "hw_version :0x%X", - NPU_FIRMWARE_VERSION); - return ret; -} +/* ------------------------------------------------------------------------- + * File Scope Variables + * ------------------------------------------------------------------------- + */ +static const char * const npu_clock_order[] = { + "armwic_core_clk", + "cal_dp_clk_src", + "cal_dp_clk", + "cal_dp_cdc_clk", + "conf_noc_ahb_clk", + "comp_noc_axi_clk", + "npu_core_clk_src", + "npu_core_clk", + "npu_core_cti_clk", + "npu_core_apb_clk", + "npu_core_atb_clk", + "npu_cpc_clk", + "npu_cpc_timer_clk", + "qtimer_core_clk", + "sleep_clk", + "bwmon_clk", + "perf_cnt_clk", + "bto_core_clk", + "xo_clk" +}; + +static const char * const npu_post_clocks[] = { + "npu_cpc_clk", + "npu_cpc_timer_clk" +}; +static const char * const npu_exclude_clocks[] = { + "npu_core_clk_src", + "cal_dp_clk_src", + "perf_cnt_clk", + "npu_core_cti_clk", + "npu_core_apb_clk", + "npu_core_atb_clk" +}; + +static const char * const npu_exclude_rate_clocks[] = { + "sleep_clk", + "xo_clk", + "conf_noc_ahb_clk", + "npu_core_cti_clk", + "npu_core_apb_clk", + "npu_core_atb_clk", + "npu_cpc_timer_clk", + "qtimer_core_clk", + "bwmon_clk", + "bto_core_clk" +}; + +/* ------------------------------------------------------------------------- + * Entry Points for Probe + * ------------------------------------------------------------------------- + */ +/* Sys FS */ static DEVICE_ATTR(caps, 0444, npu_show_capabilities, NULL); +static DEVICE_ATTR(pwr, 0644, npu_show_pwr_state, npu_store_pwr_state); static struct attribute *npu_fs_attrs[] = { &dev_attr_caps.attr, + &dev_attr_pwr.attr, NULL }; @@ -36,135 +163,797 @@ static struct attribute_group npu_fs_attr_group = { .attrs = npu_fs_attrs }; -static int npu_get_info(struct file *file, unsigned int cmd, - unsigned long arg) +static const struct of_device_id npu_dt_match[] = { + { .compatible = "qcom,msm-npu",}, + {} +}; + +static struct platform_driver npu_driver = { + .probe = npu_probe, + .remove = npu_remove, +#if defined(CONFIG_PM) + .suspend = npu_suspend, + .resume = npu_resume, +#endif + .driver = { + .name = "msm_npu", + .owner = THIS_MODULE, + .of_match_table = npu_dt_match, + .pm = NULL, + }, +}; + +static const struct file_operations npu_fops = { + .owner = THIS_MODULE, + .open = npu_open, + .release = npu_close, + .unlocked_ioctl = npu_ioctl, +}; + +static const struct thermal_cooling_device_ops npu_cooling_ops = { + .get_max_state = npu_get_max_state, + .get_cur_state = npu_get_cur_state, + .set_cur_state = npu_set_cur_state, +}; + +/* ------------------------------------------------------------------------- + * SysFS - Capabilities + * ------------------------------------------------------------------------- + */ +static ssize_t npu_show_capabilities(struct device *dev, + struct device_attribute *attr, char *buf) { - struct msm_npu_get_info_ioctl_t req; - void __user *argp = (void __user *)arg; + size_t ret = 0; + struct npu_device *npu_dev = dev_get_drvdata(dev); + + if (!npu_enable_core_power(npu_dev)) { + if (snprintf(buf, PAGE_SIZE, "hw_version :0x%X", + REGR(npu_dev, NPU_HW_VERSION)) < 0) + ret = -EINVAL; + npu_disable_core_power(npu_dev); + } else + ret = -EPERM; + + return ret; +} + +/* ------------------------------------------------------------------------- + * SysFS - Power State + * ------------------------------------------------------------------------- + */ +static ssize_t npu_show_pwr_state(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct npu_device *npu_dev = dev_get_drvdata(dev); + struct npu_pwrctrl *pwr = &npu_dev->pwrctrl; + + return snprintf(buf, PAGE_SIZE, "%s\n", + (pwr->pwr_vote_num > 0) ? "on" : "off"); +} + +static ssize_t npu_store_pwr_state(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct npu_device *npu_dev = dev_get_drvdata(dev); + bool pwr_on = false; + + if (strtobool(buf, &pwr_on) < 0) + return -EINVAL; + + if (pwr_on) { + if (npu_enable_core_power(npu_dev)) + return -EPERM; + } else { + npu_disable_core_power(npu_dev); + } + + return count; +} + +/* ------------------------------------------------------------------------- + * Power Related + * ------------------------------------------------------------------------- + */ +int npu_enable_core_power(struct npu_device *npu_dev) +{ + struct npu_pwrctrl *pwr = &npu_dev->pwrctrl; + int ret = 0; + + if (!pwr->pwr_vote_num) { + ret = npu_enable_regulators(npu_dev); + if (ret) + return ret; + + ret = npu_enable_core_clocks(npu_dev, false); + if (ret) { + npu_disable_regulators(npu_dev); + pwr->pwr_vote_num = 0; + return ret; + } + npu_resume_devbw(npu_dev); + } + pwr->pwr_vote_num++; + + return ret; +} + +void npu_disable_core_power(struct npu_device *npu_dev) +{ + struct npu_pwrctrl *pwr = &npu_dev->pwrctrl; + + if (!pwr->pwr_vote_num) + return; + pwr->pwr_vote_num--; + if (!pwr->pwr_vote_num) { + if (!npu_dev->host_ctx.fw_enabled) + npu_suspend_devbw(npu_dev); + npu_disable_core_clocks(npu_dev); + npu_disable_regulators(npu_dev); + } +} + +int npu_enable_post_pil_clocks(struct npu_device *npu_dev) +{ + return npu_enable_core_clocks(npu_dev, true); +} + +int npu_set_power_level(struct npu_device *npu_dev, + uint32_t pwr_level) +{ + struct npu_pwrctrl *pwr = &npu_dev->pwrctrl; + struct npu_pwrlevel *pwrlevel; + int i, ret = 0; + long clk_rate = 0; + + if (!pwr->pwr_vote_num) { + pr_err("power is not enabled during set request\n"); + return -EINVAL; + } + + if (pwr_level == pwr->active_pwrlevel) + return 0; + + pr_debug("%s to [%d]\n", __func__, pwr_level); + + pwr->active_pwrlevel = pwr_level; + pwrlevel = &npu_dev->pwrctrl.pwrlevels[pwr_level]; + + for (i = 0; i < npu_dev->core_clk_num; i++) { + if (npu_is_exclude_rate_clock( + npu_dev->core_clks[i].clk_name)) + continue; + + if (!npu_dev->host_ctx.fw_enabled) { + if (npu_is_post_clock( + npu_dev->core_clks[i].clk_name)) + continue; + } + + pr_debug("requested rate of clock [%s] to [%ld]\n", + npu_dev->core_clks[i].clk_name, pwrlevel->clk_freq[i]); + + clk_rate = clk_round_rate(npu_dev->core_clks[i].clk, + pwrlevel->clk_freq[i]); + + pr_debug("actual round clk rate [%ld]\n", clk_rate); + ret = clk_set_rate(npu_dev->core_clks[i].clk, clk_rate); + if (ret) { + pr_err("clk_set_rate %s to %ld failed with %d\n", + npu_dev->core_clks[i].clk_name, + clk_rate, ret); + break; + } + } + + return ret; +} + +static int npu_calc_power_level(struct npu_device *npu_dev, + uint32_t perf_mode) +{ + int ret_level; + + if (perf_mode == 0) + ret_level = POWER_LEVEL_NOMINAL; + else if (perf_mode == POWER_LEVEL_MIN_SVS) + /* force to lowsvs, minsvs not supported */ + ret_level = POWER_LEVEL_LOW_SVS; + else + ret_level = perf_mode-1; + + return ret_level; +} + +/* ------------------------------------------------------------------------- + * Bandwidth Related + * ------------------------------------------------------------------------- + */ +static void npu_suspend_devbw(struct npu_device *npu_dev) +{ + struct npu_pwrctrl *pwr = &npu_dev->pwrctrl; int ret; + if (pwr->bwmon_enabled) { + pwr->bwmon_enabled = 0; + ret = devfreq_suspend_devbw(pwr->devbw); + if (ret) + pr_err("devfreq_suspend_devbw failed rc:%d\n", + ret); + } +} + +static void npu_resume_devbw(struct npu_device *npu_dev) +{ + struct npu_pwrctrl *pwr = &npu_dev->pwrctrl; + int ret; + + if (!pwr->bwmon_enabled) { + pwr->bwmon_enabled = 1; + ret = devfreq_resume_devbw(pwr->devbw); + + if (ret) + pr_err("devfreq_resume_devbw failed rc:%d\n", ret); + } +} + +/* ------------------------------------------------------------------------- + * Clocks Related + * ------------------------------------------------------------------------- + */ +static bool npu_is_post_clock(const char *clk_name) +{ + int ret = false; + int i; + + for (i = 0; i < ARRAY_SIZE(npu_post_clocks); i++) { + if (!strcmp(clk_name, npu_post_clocks[i])) { + ret = true; + break; + } + } + return ret; +} + +static bool npu_is_exclude_clock(const char *clk_name) +{ + int ret = false; + int i; + + for (i = 0; i < ARRAY_SIZE(npu_exclude_clocks); i++) { + if (!strcmp(clk_name, npu_exclude_clocks[i])) { + ret = true; + break; + } + } + return ret; +} + +static bool npu_is_exclude_rate_clock(const char *clk_name) +{ + int ret = false; + int i; + + for (i = 0; i < ARRAY_SIZE(npu_exclude_rate_clocks); i++) { + if (!strcmp(clk_name, npu_exclude_rate_clocks[i])) { + ret = true; + break; + } + } + return ret; +} + +static int npu_enable_core_clocks(struct npu_device *npu_dev, bool post_pil) +{ + int i, rc = 0; + struct npu_clk *core_clks = npu_dev->core_clks; + struct npu_pwrctrl *pwr = &npu_dev->pwrctrl; + struct npu_pwrlevel *pwrlevel = + &npu_dev->pwrctrl.pwrlevels[pwr->active_pwrlevel]; + + for (i = 0; i < npu_dev->core_clk_num; i++) { + if (post_pil) { + if (!npu_is_post_clock(core_clks[i].clk_name)) + continue; + } else { + if (npu_is_post_clock(core_clks[i].clk_name)) + continue; + } + + if (npu_is_exclude_clock(core_clks[i].clk_name)) + continue; + + pr_debug("enabling clock [%s]\n", core_clks[i].clk_name); + + rc = clk_prepare_enable(core_clks[i].clk); + if (rc) { + pr_err("%s enable failed\n", + core_clks[i].clk_name); + break; + } + + if (npu_is_exclude_rate_clock(core_clks[i].clk_name)) + continue; + + pr_debug("setting rate of clock [%s] to [%ld]\n", + core_clks[i].clk_name, pwrlevel->clk_freq[i]); + + rc = clk_set_rate(core_clks[i].clk, + pwrlevel->clk_freq[i]); + if (rc) { + pr_debug("clk_set_rate %s to %ld failed\n", + core_clks[i].clk_name, + pwrlevel->clk_freq[i]); + break; + } + } + + return rc; +} + +static void npu_disable_core_clocks(struct npu_device *npu_dev) +{ + int i = 0; + struct npu_clk *core_clks = npu_dev->core_clks; + + for (i = (npu_dev->core_clk_num)-1; i >= 0 ; i--) { + if (npu_is_exclude_clock(core_clks[i].clk_name)) + continue; + pr_debug("disabling clock [%s]\n", core_clks[i].clk_name); + clk_disable_unprepare(core_clks[i].clk); + } +} + +/* ------------------------------------------------------------------------- + * Thermal Functions + * ------------------------------------------------------------------------- + */ +static int npu_get_max_state(struct thermal_cooling_device *cdev, + unsigned long *state) +{ + struct npu_device *npu_dev = cdev->devdata; + struct npu_pwrctrl *pwr = &npu_dev->pwrctrl; + + pr_debug("enter %s\n", __func__); + + *state = pwr->max_pwrlevel; + + return 0; +} + +static int npu_get_cur_state(struct thermal_cooling_device *cdev, + unsigned long *state) +{ + struct npu_device *npu_dev = cdev->devdata; + struct npu_pwrctrl *pwr = &npu_dev->pwrctrl; + + pr_debug("enter %s\n", __func__); + + *state = pwr->max_pwrlevel - pwr->active_pwrlevel; + + return 0; +} + +static int +npu_set_cur_state(struct thermal_cooling_device *cdev, unsigned long state) +{ + struct npu_device *npu_dev = cdev->devdata; + struct npu_pwrctrl *pwr = &npu_dev->pwrctrl; + uint32_t next_pwr_level; + + pr_debug("enter %s %lu\n", __func__, state); + + if (state > pwr->max_pwrlevel) + return -EINVAL; + + next_pwr_level = pwr->max_pwrlevel - state; + + return npu_set_power_level(npu_dev, next_pwr_level); +} + +/* ------------------------------------------------------------------------- + * Regulator Related + * ------------------------------------------------------------------------- + */ +static int npu_enable_regulators(struct npu_device *npu_dev) +{ + int i = 0; + int rc = 0; + struct npu_host_ctx *host_ctx = &npu_dev->host_ctx; + struct npu_regulator *regulators = npu_dev->regulators; + + if (!host_ctx->power_vote_num) { + for (i = 0; i < npu_dev->regulator_num; i++) { + rc = regulator_enable(regulators[i].regulator); + if (rc < 0) { + pr_err("%s enable failed\n", + regulators[i].regulator_name); + break; + } + pr_debug("regulator %s enabled\n", + regulators[i].regulator_name); + } + } + host_ctx->power_vote_num++; + return rc; +} + +static void npu_disable_regulators(struct npu_device *npu_dev) +{ + int i = 0; + struct npu_host_ctx *host_ctx = &npu_dev->host_ctx; + struct npu_regulator *regulators = npu_dev->regulators; + + if (host_ctx->power_vote_num > 0) { + for (i = 0; i < npu_dev->regulator_num; i++) { + regulator_disable(regulators[i].regulator); + pr_debug("regulator %s disabled\n", + regulators[i].regulator_name); + } + host_ctx->power_vote_num--; + } +} + +/* ------------------------------------------------------------------------- + * Interrupt Related + * ------------------------------------------------------------------------- + */ +int npu_enable_irq(struct npu_device *npu_dev) +{ + /* clear pending irq state */ + REGW(npu_dev, NPU_MASTERn_IPC_IRQ_OUT(0), 0x0); + enable_irq(npu_dev->irq); + + return 0; +} + +void npu_disable_irq(struct npu_device *npu_dev) +{ + disable_irq(npu_dev->irq); + /* clear pending irq state */ + REGW(npu_dev, NPU_MASTERn_IPC_IRQ_OUT(0), 0x0); +} + +/* ------------------------------------------------------------------------- + * System Cache + * ------------------------------------------------------------------------- + */ +int npu_enable_sys_cache(struct npu_device *npu_dev) +{ + int rc = 0; + uint32_t reg_val = 0; + + if (!npu_dev->debugfs_ctx.sys_cache_disable) { + npu_dev->sys_cache = llcc_slice_getd(&(npu_dev->pdev->dev), + "npu"); + if (IS_ERR_OR_NULL(npu_dev->sys_cache)) { + pr_debug("unable to init sys cache\n"); + npu_dev->sys_cache = NULL; + return -ENODEV; + } + + /* set npu side regs - program SCID */ + reg_val = NPU_CACHE_ATTR_IDn___POR | SYS_CACHE_SCID; + + REGW(npu_dev, NPU_CACHE_ATTR_IDn(0), reg_val); + REGW(npu_dev, NPU_CACHE_ATTR_IDn(1), reg_val); + REGW(npu_dev, NPU_CACHE_ATTR_IDn(2), reg_val); + REGW(npu_dev, NPU_CACHE_ATTR_IDn(3), reg_val); + REGW(npu_dev, NPU_CACHE_ATTR_IDn(4), reg_val); + + pr_debug("prior to activate sys cache\n"); + rc = llcc_slice_activate(npu_dev->sys_cache); + if (rc) + pr_err("failed to activate sys cache\n"); + else + pr_debug("sys cache activated\n"); + } + + return rc; +} + +void npu_disable_sys_cache(struct npu_device *npu_dev) +{ + int rc = 0; + + if (!npu_dev->debugfs_ctx.sys_cache_disable) { + if (npu_dev->sys_cache) { + rc = llcc_slice_deactivate(npu_dev->sys_cache); + if (rc) { + pr_err("failed to deactivate sys cache\n"); + return; + } + pr_debug("sys cache deactivated\n"); + llcc_slice_putd(npu_dev->sys_cache); + npu_dev->sys_cache = NULL; + } + } +} + +/* ------------------------------------------------------------------------- + * Open/Close + * ------------------------------------------------------------------------- + */ +static int npu_open(struct inode *inode, struct file *file) +{ + struct npu_device *npu_dev = container_of(inode->i_cdev, + struct npu_device, cdev); + + file->private_data = npu_dev; + + return 0; +} + +static int npu_close(struct inode *inode, struct file *file) +{ + return 0; +} + +/* ------------------------------------------------------------------------- + * IOCTL Implementations + * ------------------------------------------------------------------------- + */ +static int npu_get_info(struct npu_device *npu_dev, unsigned long arg) +{ + struct msm_npu_get_info_ioctl req; + void __user *argp = (void __user *)arg; + int ret = 0; + ret = copy_from_user(&req, argp, sizeof(req)); if (ret) { pr_err("fail to copy from user\n"); + return -EFAULT; + } + + ret = npu_host_get_info(npu_dev, &req); + + if (ret) { + pr_err("npu_host_get_info failed\n"); return ret; } - req.firmware_version = NPU_FIRMWARE_VERSION; + ret = copy_to_user(argp, &req, sizeof(req)); if (ret) { pr_err("fail to copy to user\n"); + return -EFAULT; + } + return 0; +} + +static int npu_map_buf(struct npu_device *npu_dev, unsigned long arg) +{ + struct msm_npu_map_buf_ioctl req; + void __user *argp = (void __user *)arg; + int ret = 0; + + ret = copy_from_user(&req, argp, sizeof(req)); + + if (ret) { + pr_err("fail to copy from user\n"); + return -EFAULT; + } + + ret = npu_host_map_buf(npu_dev, &req); + + if (ret) { + pr_err("npu_host_map_buf failed\n"); return ret; } + + ret = copy_to_user(argp, &req, sizeof(req)); + + if (ret) { + pr_err("fail to copy to user\n"); + return -EFAULT; + } return 0; } -static int npu_open(struct inode *inode, struct file *file) +static int npu_unmap_buf(struct npu_device *npu_dev, unsigned long arg) { - struct npu_device_t *npu_dev = container_of(inode->i_cdev, - struct npu_device_t, cdev); + struct msm_npu_unmap_buf_ioctl req; + void __user *argp = (void __user *)arg; + int ret = 0; - file->private_data = npu_dev; + ret = copy_from_user(&req, argp, sizeof(req)); + + if (ret) { + pr_err("fail to copy from user\n"); + return -EFAULT; + } + + ret = npu_host_unmap_buf(npu_dev, &req); + + if (ret) { + pr_err("npu_host_unmap_buf failed\n"); + return ret; + } + + ret = copy_to_user(argp, &req, sizeof(req)); + + if (ret) { + pr_err("fail to copy to user\n"); + return -EFAULT; + } return 0; } -static int npu_close(struct inode *inode, struct file *file) +static int npu_load_network(struct npu_device *npu_dev, unsigned long arg) { + struct msm_npu_load_network_ioctl req; + void __user *argp = (void __user *)arg; + int ret = 0; + uint32_t pwr_level_to_set; + + ret = copy_from_user(&req, argp, sizeof(req)); + + if (ret) { + pr_err("fail to copy from user\n"); + return -EFAULT; + } + + pr_debug("network load with perf request %d\n", req.flags); + + ret = npu_host_load_network(npu_dev, &req); + if (ret) { + pr_err("npu_host_load_network failed\n"); + return ret; + } + + /* get the power level to set */ + pwr_level_to_set = npu_calc_power_level(npu_dev, req.flags); + + /* set the power level */ + ret = npu_set_power_level(npu_dev, pwr_level_to_set); + if (!ret) + pr_debug("network load pwr level set at %d\n", + pwr_level_to_set); + + ret = copy_to_user(argp, &req, sizeof(req)); + if (ret) { + pr_err("fail to copy to user\n"); + return -EFAULT; + } + return 0; +} + +static int npu_unload_network(struct npu_device *npu_dev, unsigned long arg) +{ + struct msm_npu_unload_network_ioctl req; + void __user *argp = (void __user *)arg; + int ret = 0; + + ret = copy_from_user(&req, argp, sizeof(req)); + + if (ret) { + pr_err("fail to copy from user\n"); + return -EFAULT; + } + + ret = npu_host_unload_network(npu_dev, &req); + + if (ret) { + pr_err("npu_host_unload_network failed\n"); + return ret; + } + + ret = copy_to_user(argp, &req, sizeof(req)); + + if (ret) { + pr_err("fail to copy to user\n"); + return -EFAULT; + } + return 0; +} + +static int npu_exec_network(struct npu_device *npu_dev, unsigned long arg) +{ + struct msm_npu_exec_network_ioctl req; + void __user *argp = (void __user *)arg; + int ret = 0; + + ret = copy_from_user(&req, argp, sizeof(req)); + + if (ret) { + pr_err("fail to copy from user\n"); + return -EFAULT; + } + + ret = npu_host_exec_network(npu_dev, &req); + + if (ret) { + pr_err("npu_host_exec_network failed\n"); + return ret; + } + + ret = copy_to_user(argp, &req, sizeof(req)); + + if (ret) { + pr_err("fail to copy to user\n"); + return -EFAULT; + } return 0; } static long npu_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { - int ret = -EPERM; + int ret = -ENOIOCTLCMD; + struct npu_device *npu_dev = file->private_data; switch (cmd) { case MSM_NPU_GET_INFO: - ret = npu_get_info(file, cmd, arg); + ret = npu_get_info(npu_dev, arg); break; case MSM_NPU_MAP_BUF: + ret = npu_map_buf(npu_dev, arg); break; case MSM_NPU_UNMAP_BUF: + ret = npu_unmap_buf(npu_dev, arg); break; case MSM_NPU_LOAD_NETWORK: + ret = npu_load_network(npu_dev, arg); break; case MSM_NPU_UNLOAD_NETWORK: + ret = npu_unload_network(npu_dev, arg); break; case MSM_NPU_EXEC_NETWORK: + ret = npu_exec_network(npu_dev, arg); break; default: - pr_err("unexpected IOCTL %d\n", cmd); - } - - return ret; -} - -/* 32 bit */ -#ifdef CONFIG_COMPAT -static long npu_compat_ioctl(struct file *file, unsigned int cmd, - unsigned long arg) -{ - int ret = -EPERM; - - switch (cmd) { - case MSM_NPU_GET_INFO_32: - ret = npu_get_info(file, cmd, arg); - break; - case MSM_NPU_MAP_BUF_32: - break; - case MSM_NPU_UNMAP_BUF_32: - break; - case MSM_NPU_LOAD_NETWORK_32: - break; - case MSM_NPU_UNLOAD_NETWORK_32: - break; - case MSM_NPU_EXEC_NETWORK_32: - break; - default: - pr_err("unexpected IOCTL %d\n", cmd); + pr_err("unexpected IOCTL %x\n", cmd); } return ret; } -#endif - -static const struct file_operations npu_fops = { - .owner = THIS_MODULE, - .open = npu_open, - .release = npu_close, - .unlocked_ioctl = npu_ioctl, -#ifdef CONFIG_COMPAT - .compat_ioctl = npu_compat_ioctl, -#endif -}; -static int npu_parse_dt_clock(struct npu_device_t *npu_dev) +/* ------------------------------------------------------------------------- + * Device Tree Parsing + * ------------------------------------------------------------------------- + */ +static int npu_parse_dt_clock(struct npu_device *npu_dev) { - u32 i = 0, rc = 0; + int rc = 0; + uint32_t i, j; const char *clock_name; int num_clk; - struct npu_clk_t *core_clks = npu_dev->core_clks; + struct npu_clk *core_clks = npu_dev->core_clks; struct platform_device *pdev = npu_dev->pdev; num_clk = of_property_count_strings(pdev->dev.of_node, "clock-names"); if (num_clk <= 0) { pr_err("clocks are not defined\n"); + rc = -EINVAL; goto clk_err; } - if (num_clk > NPU_MAX_CLK_NUM) { - pr_err("clock number is over the limit %d\n", num_clk); - num_clk = NPU_MAX_CLK_NUM; + if (num_clk != NUM_TOTAL_CLKS) { + pr_err("number of clocks is invalid [%d] should be [%d]\n", + num_clk, NUM_TOTAL_CLKS); + rc = -EINVAL; + goto clk_err; } npu_dev->core_clk_num = num_clk; for (i = 0; i < num_clk; i++) { of_property_read_string_index(pdev->dev.of_node, "clock-names", i, &clock_name); - strlcpy(core_clks[i].clk_name, clock_name, - sizeof(core_clks[i].clk_name)); - core_clks[i].clk = devm_clk_get(&pdev->dev, clock_name); - if (IS_ERR(core_clks[i].clk)) { + for (j = 0; j < num_clk; j++) { + if (!strcmp(npu_clock_order[j], clock_name)) + break; + } + if (j == num_clk) { + pr_err("clock is not in ordered list\n"); + rc = -EINVAL; + goto clk_err; + } + strlcpy(core_clks[j].clk_name, clock_name, + sizeof(core_clks[j].clk_name)); + core_clks[j].clk = devm_clk_get(&pdev->dev, clock_name); + if (IS_ERR(core_clks[j].clk)) { pr_err("unable to get clk: %s\n", clock_name); rc = -EINVAL; break; @@ -175,22 +964,26 @@ static int npu_parse_dt_clock(struct npu_device_t *npu_dev) return rc; } -static int npu_parse_dt_regulator(struct npu_device_t *npu_dev) +static int npu_parse_dt_regulator(struct npu_device *npu_dev) { - u32 i = 0, rc = 0; + int rc = 0; + uint32_t i; const char *name; int num; - struct npu_regulator_t *regulators = npu_dev->regulators; + struct npu_regulator *regulators = npu_dev->regulators; struct platform_device *pdev = npu_dev->pdev; num = of_property_count_strings(pdev->dev.of_node, "qcom,proxy-reg-names"); if (num <= 0) { + rc = -EINVAL; pr_err("regulator not defined\n"); goto regulator_err; } if (num > NPU_MAX_REGULATOR_NUM) { - pr_err("regulator number is over the limit %d", num); + rc = -EINVAL; + pr_err("regulator number %d is over the limit %d\n", num, + NPU_MAX_REGULATOR_NUM); num = NPU_MAX_REGULATOR_NUM; } @@ -212,20 +1005,141 @@ static int npu_parse_dt_regulator(struct npu_device_t *npu_dev) return rc; } +static int npu_of_parse_pwrlevels(struct npu_device *npu_dev, + struct device_node *node) +{ + struct npu_pwrctrl *pwr = &npu_dev->pwrctrl; + struct device_node *child; + uint32_t init_level = 0; + const char *clock_name; + struct platform_device *pdev = npu_dev->pdev; + + pwr->num_pwrlevels = 0; + + for_each_available_child_of_node(node, child) { + uint32_t i = 0; + uint32_t j = 0; + uint32_t index; + uint32_t clk_array_values[NUM_TOTAL_CLKS]; + struct npu_pwrlevel *level; + + if (of_property_read_u32(child, "reg", &index)) + return -EINVAL; + + if (index >= NPU_MAX_PWRLEVELS) { + pr_err("pwrlevel index %d is out of range\n", + index); + continue; + } + + if (index >= pwr->num_pwrlevels) + pwr->num_pwrlevels = index + 1; + + if (of_property_read_u32_array(child, "clk-freq", + clk_array_values, npu_dev->core_clk_num)) { + pr_err("pwrlevel index %d read clk-freq failed %d\n", + index, npu_dev->core_clk_num); + return -EINVAL; + } + + /* sort */ + level = &pwr->pwrlevels[index]; + for (i = 0; i < npu_dev->core_clk_num; i++) { + of_property_read_string_index(pdev->dev.of_node, + "clock-names", i, &clock_name); + + for (j = 0; j < npu_dev->core_clk_num; j++) { + if (!strcmp(npu_clock_order[j], + clock_name)) { + level->clk_freq[j] = + clk_array_values[i]; + break; + } + } + if (j == npu_dev->core_clk_num) { + pr_err("pwrlevel clock is not in ordered list\n"); + return -EINVAL; + } + } + } + + of_property_read_u32(node, "initial-pwrlevel", &init_level); + + if (init_level >= pwr->num_pwrlevels) + init_level = 0; + + pr_debug("init power level %d\n", init_level); + pwr->active_pwrlevel = init_level; + pwr->default_pwrlevel = init_level; + pwr->min_pwrlevel = 0; + pwr->max_pwrlevel = pwr->num_pwrlevels - 1; + + return 0; +} + +static int npu_pwrctrl_init(struct npu_device *npu_dev) +{ + struct platform_device *pdev = npu_dev->pdev; + struct device_node *node; + int ret = 0; + struct platform_device *p2dev; + struct npu_pwrctrl *pwr = &npu_dev->pwrctrl; + + /* Power levels */ + node = of_find_node_by_name(pdev->dev.of_node, "qcom,npu-pwrlevels"); + + if (!node) { + pr_err("unable to find 'qcom,npu-pwrlevels'\n"); + return -EINVAL; + } + + ret = npu_of_parse_pwrlevels(npu_dev, node); + if (ret) + return ret; + + /* Parse Bandwidth */ + node = of_parse_phandle(pdev->dev.of_node, + "qcom,npubw-dev", 0); + + if (node) { + /* Set to 1 initially - we assume bwmon is on */ + pwr->bwmon_enabled = 1; + p2dev = of_find_device_by_node(node); + if (p2dev) { + pwr->devbw = &p2dev->dev; + } else { + pr_err("parser power level failed\n"); + ret = -EINVAL; + return ret; + } + } else { + pr_err("bwdev is not defined in dts\n"); + pwr->devbw = NULL; + ret = -EINVAL; + } + + return ret; +} + +/* ------------------------------------------------------------------------- + * Probe/Remove + * ------------------------------------------------------------------------- + */ static int npu_probe(struct platform_device *pdev) { - int rc; - struct resource *res; - struct npu_device_t *npu_dev; + int rc = 0; + struct resource *res = 0; + struct npu_device *npu_dev = 0; + struct thermal_cooling_device *tcdev = 0; npu_dev = devm_kzalloc(&pdev->dev, - sizeof(struct npu_device_t), GFP_KERNEL); + sizeof(struct npu_device), GFP_KERNEL); if (!npu_dev) return -EFAULT; npu_dev->pdev = pdev; - platform_set_drvdata(pdev, npu_dev); + platform_set_drvdata(pdev, npu_dev); res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "npu_base"); if (!res) { @@ -233,7 +1147,6 @@ static int npu_probe(struct platform_device *pdev) rc = -ENOMEM; goto error_get_dev_num; } - npu_dev->reg_size = resource_size(res); rc = npu_parse_dt_regulator(npu_dev); @@ -244,6 +1157,10 @@ static int npu_probe(struct platform_device *pdev) if (rc) goto error_get_dev_num; + rc = npu_pwrctrl_init(npu_dev); + if (rc) + goto error_get_dev_num; + npu_dev->npu_base = devm_ioremap(&pdev->dev, res->start, npu_dev->reg_size); if (unlikely(!npu_dev->npu_base)) { @@ -251,18 +1168,26 @@ static int npu_probe(struct platform_device *pdev) rc = -ENOMEM; goto error_get_dev_num; } + npu_dev->npu_phys = res->start; - pr_info("NPU HW Base phy_Address=0x%x virt=%pK\n", + pr_debug("hw base phy address=0x%x virt=%pK\n", npu_dev->npu_phys, npu_dev->npu_base); res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); if (!res) { - pr_err("unable to get NPU irq\n"); + pr_err("unable to get irq\n"); rc = -ENOMEM; goto error_get_dev_num; } + rc = devm_request_irq(&pdev->dev, res->start, + npu_intr_hdler, 0x0, "npu", npu_dev); + if (rc) { + pr_err("devm_request_irq() failed\n"); + goto error_get_dev_num; + } + disable_irq(res->start); npu_dev->irq = res->start; - + pr_debug("irq %d\n", npu_dev->irq); /* character device might be optional */ rc = alloc_chrdev_region(&npu_dev->dev_num, 0, 1, DRIVER_NAME); if (rc < 0) { @@ -292,13 +1217,65 @@ static int npu_probe(struct platform_device *pdev) pr_err("cdev_add failed %d\n", rc); goto error_cdev_add; } - + dev_set_drvdata(npu_dev->device, npu_dev); + pr_debug("drvdata %pK %pK\n", dev_get_drvdata(&pdev->dev), + dev_get_drvdata(npu_dev->device)); rc = sysfs_create_group(&npu_dev->device->kobj, &npu_fs_attr_group); if (rc) { pr_err("unable to register npu sysfs nodes\n"); goto error_res_init; } + + if (IS_ENABLED(CONFIG_THERMAL)) { + tcdev = thermal_of_cooling_device_register(pdev->dev.of_node, + "npu", npu_dev, + &npu_cooling_ops); + if (IS_ERR(tcdev)) { + dev_err(&pdev->dev, + "npu: failed to register npu as cooling device"); + rc = PTR_ERR(tcdev); + goto error_driver_init; + } + npu_dev->tcdev = tcdev; + thermal_cdev_update(tcdev); + } + + rc = npu_debugfs_init(npu_dev); + if (rc) + goto error_driver_init; + + npu_dev->smmu_ctx.attach_cnt = 0; + npu_dev->smmu_ctx.mmu_mapping = arm_iommu_create_mapping( + pdev->dev.bus, DDR_MAPPED_START_ADDR, DDR_MAPPED_SIZE); + if (IS_ERR(npu_dev->smmu_ctx.mmu_mapping)) { + pr_err("iommu create mapping failed\n"); + rc = -ENOMEM; + npu_dev->smmu_ctx.mmu_mapping = NULL; + goto error_driver_init; + } + + rc = arm_iommu_attach_device(&(npu_dev->pdev->dev), + npu_dev->smmu_ctx.mmu_mapping); + if (rc) { + pr_err("arm_iommu_attach_device failed\n"); + goto error_driver_init; + } + + INIT_LIST_HEAD(&(npu_dev->mapped_buffers.list)); + + rc = npu_host_init(npu_dev); + if (rc) { + pr_err("unable to init host\n"); + goto error_driver_init; + } + return rc; +error_driver_init: + sysfs_remove_group(&npu_dev->device->kobj, &npu_fs_attr_group); + arm_iommu_detach_device(&(npu_dev->pdev->dev)); + if (!npu_dev->smmu_ctx.mmu_mapping) + arm_iommu_release_mapping(npu_dev->smmu_ctx.mmu_mapping); + sysfs_remove_group(&npu_dev->device->kobj, &npu_fs_attr_group); error_res_init: cdev_del(&npu_dev->cdev); error_cdev_add: @@ -313,44 +1290,50 @@ static int npu_probe(struct platform_device *pdev) static int npu_remove(struct platform_device *pdev) { - struct npu_device_t *npu_dev; + struct npu_device *npu_dev; npu_dev = platform_get_drvdata(pdev); - - platform_set_drvdata(pdev, NULL); + thermal_cooling_device_unregister(npu_dev->tcdev); + npu_debugfs_deinit(npu_dev); + npu_host_deinit(npu_dev); + arm_iommu_release_mapping(npu_dev->smmu_ctx.mmu_mapping); + arm_iommu_detach_device(&(npu_dev->pdev->dev)); sysfs_remove_group(&npu_dev->device->kobj, &npu_fs_attr_group); cdev_del(&npu_dev->cdev); device_destroy(npu_dev->class, npu_dev->dev_num); class_destroy(npu_dev->class); unregister_chrdev_region(npu_dev->dev_num, 1); + platform_set_drvdata(pdev, NULL); return 0; } -static const struct of_device_id npu_dt_match[] = { - { .compatible = "qcom,msm-npu",}, - {} -}; - -MODULE_DEVICE_TABLE(of, npu_dt_match); +/* ------------------------------------------------------------------------- + * Suspend/Resume + * ------------------------------------------------------------------------- + */ +#if defined(CONFIG_PM) +static int npu_suspend(struct platform_device *dev, pm_message_t state) +{ + return 0; +} -static struct platform_driver npu_driver = { - .probe = npu_probe, - .remove = npu_remove, - .driver = { - .name = "msm_npu", - .owner = THIS_MODULE, - .of_match_table = npu_dt_match, - .pm = NULL, - }, -}; +static int npu_resume(struct platform_device *dev) +{ + return 0; +} +#endif +/* ------------------------------------------------------------------------- + * Module Entry Points + * ------------------------------------------------------------------------- + */ static int __init npu_init(void) { int rc; rc = platform_driver_register(&npu_driver); if (rc) - pr_err("npu register failed %d", rc); + pr_err("register failed %d\n", rc); return rc; } @@ -362,5 +1345,7 @@ static void __exit npu_exit(void) module_init(npu_init); module_exit(npu_exit); +MODULE_DEVICE_TABLE(of, npu_dt_match); MODULE_DESCRIPTION("MSM NPU driver"); MODULE_LICENSE("GPL v2"); +MODULE_INFO(intree, "Y"); diff --git a/drivers/media/platform/msm/npu/npu_firmware.h b/drivers/media/platform/msm/npu/npu_firmware.h new file mode 100644 index 000000000000..1d1cc6df23ec --- /dev/null +++ b/drivers/media/platform/msm/npu/npu_firmware.h @@ -0,0 +1,139 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _NPU_FIRMWARE_H +#define _NPU_FIRMWARE_H + +/* ------------------------------------------------------------------------- + * Includes + * ------------------------------------------------------------------------- + */ +#include + +/* ------------------------------------------------------------------------- + * Defines + * ------------------------------------------------------------------------- + */ +/* NPU Firmware Control/Status Register, written by FW and read HOST */ +#define REG_NPU_FW_CTRL_STATUS NPU_GPR0 +/* written by HOST and read by FW for control */ +#define REG_NPU_HOST_CTRL_STATUS NPU_GPR1 +/* Data value for control */ +#define REG_NPU_HOST_CTRL_VALUE NPU_GPR2 +/* Simulates an interrupt for FW->HOST, used for pre-silicon */ +#define REG_FW_TO_HOST_EVENT NPU_GPR3 +/* Data value for debug */ +#define REG_NPU_FW_DEBUG_DATA NPU_GPR4 + +/* Started job count */ +#define REG_FW_JOB_CNT_START NPU_GPR14 +/* Finished job count */ +#define REG_FW_JOB_CNT_END NPU_GPR15 + +/* NPU FW Control/Status Register */ +/* bit fields definitions in CTRL STATUS REG */ +#define FW_CTRL_STATUS_IPC_READY_BIT 0 +#define FW_CTRL_STATUS_LOG_READY_BIT 1 +#define FW_CTRL_STATUS_EXECUTE_THREAD_READY_BIT 2 +#define FW_CTRL_STATUS_MAIN_THREAD_READY_BIT 3 +#define FW_CTRL_STATUS_EXECUTING_ACO 4 + +/* 32 bit values of the bit fields above */ +#define FW_CTRL_STATUS_IPC_READY_VAL (1 << FW_CTRL_STATUS_IPC_READY_BIT) +#define FW_CTRL_STATUS_LOG_READY_VAL (1 << FW_CTRL_STATUS_LOG_READY_BIT) +#define FW_CTRL_STATUS_EXECUTE_THREAD_READY_VAL \ + (1 << FW_CTRL_STATUS_EXECUTE_THREAD_READY_BIT) +#define FW_CTRL_STATUS_MAIN_THREAD_READY_VAL \ + (1 << FW_CTRL_STATUS_MAIN_THREAD_READY_BIT) +#define FW_CTRL_STATUS_EXECUTING_ACO_VAL \ + (1 << FW_CTRL_STATUS_EXECUTING_ACO) + +/* NPU HOST Control/Status Register */ +/* bit fields definitions in CTRL STATUS REG */ +/* Host has programmed IPC address into the REG_NPU_HOST_CTRL_VALUE register */ +#define HOST_CTRL_STATUS_IPC_ADDRESS_READY_BIT 0 +/* Host has enabled logging during boot */ +#define HOST_CTRL_STATUS_BOOT_ENABLE_LOGGING_BIT 1 +/* Host has enabled the clk gating of CAL during boot */ +#define HOST_CTRL_STATUS_BOOT_ENABLE_CLK_GATE_BIT 2 + +/* 32 bit values of the bit fields above */ +#define HOST_CTRL_STATUS_IPC_ADDRESS_READY_VAL \ + (1 << HOST_CTRL_STATUS_IPC_ADDRESS_READY_BIT) +#define HOST_CTRL_STATUS_BOOT_ENABLE_LOGGING_VAL \ + (1 << HOST_CTRL_STATUS_BOOT_ENABLE_LOGGING_BIT) +#define HOST_CTRL_STATUS_BOOT_ENABLE_CLK_GATE_VAL \ + (1 << HOST_CTRL_STATUS_BOOT_ENABLE_CLK_GATE_BIT) + +/* Queue table header definition */ +struct hfi_queue_tbl_header { + uint32_t qtbl_version; /* queue table version number */ + uint32_t qtbl_size; /* total tables+queues size in bytes */ + uint32_t qtbl_qhdr0_offset; /* offset of the 1st queue header entry */ + uint32_t qtbl_qhdr_size; /* queue header size */ + uint32_t qtbl_num_q; /* total number of queues */ + uint32_t qtbl_num_active_q; /* number of active queues */ +}; + +/* Queue header definition */ +struct hfi_queue_header { + uint32_t qhdr_status; /* 0 == inactive, 1 == active */ + /* 4 byte-aligned start offset from start of q table */ + uint32_t qhdr_start_offset; + /* queue type */ + uint32_t qhdr_type; + /* in bytes, value of 0 means packets are variable size.*/ + uint32_t qhdr_q_size; + /* size of the Queue packet entries, in bytes, 0 means variable size */ + uint32_t qhdr_pkt_size; + + uint32_t qhdr_pkt_drop_cnt; + /* receiver watermark in # of queue packets */ + uint32_t qhdr_rx_wm; + /* transmitter watermark in # of queue packets */ + uint32_t qhdr_tx_wm; + /* + * set to request an interrupt from transmitter + * if qhdr_tx_wm is reached + */ + uint32_t qhdr_rx_req; + /* + * set to request an interrupt from receiver + * if qhdr_rx_wm is reached + */ + uint32_t qhdr_tx_req; + uint32_t qhdr_rx_irq_status; /* Not used */ + uint32_t qhdr_tx_irq_status; /* Not used */ + uint32_t qhdr_read_idx; /* read index in bytes */ + uint32_t qhdr_write_idx; /* write index in bytes */ +}; + +/* in bytes */ +#define HFI_QUEUE_TABLE_HEADER_SIZE (sizeof(struct hfi_queue_tbl_header)) +#define HFI_QUEUE_HEADER_SIZE (sizeof(struct hfi_queue_header)) +#define HFI_QUEUE_TABLE_SIZE (HFI_QUEUE_TABLE_HEADER_SIZE + \ + (NPU_HFI_NUMBER_OF_QS * HFI_QUEUE_HEADER_SIZE)) + +/* Queue Indexes */ +#define IPC_QUEUE_CMD_HIGH_PRIORITY 0 /* High priority Queue APPS->M0 */ +#define IPC_QUEUE_APPS_EXEC 1 /* APPS Execute Queue APPS->M0 */ +#define IPC_QUEUE_DSP_EXEC 2 /* DSP Execute Queue DSP->M0 */ +#define IPC_QUEUE_APPS_RSP 3 /* APPS Message Queue M0->APPS */ +#define IPC_QUEUE_DSP_RSP 4 /* DSP Message Queue DSP->APPS */ +#define IPC_QUEUE_LOG 5 /* Log Message Queue M0->APPS */ + +#define NPU_HFI_NUMBER_OF_QS 6 +#define NPU_HFI_NUMBER_OF_ACTIVE_QS 6 + +#define NPU_HFI_QUEUES_PER_CHANNEL 2 + +#endif /* _NPU_FIRMWARE_H */ diff --git a/drivers/media/platform/msm/npu/npu_host_ipc.c b/drivers/media/platform/msm/npu/npu_host_ipc.c new file mode 100644 index 000000000000..0730e2019edc --- /dev/null +++ b/drivers/media/platform/msm/npu/npu_host_ipc.c @@ -0,0 +1,414 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +/* ------------------------------------------------------------------------- + * Includes + * ------------------------------------------------------------------------- + */ +#include "npu_hw_access.h" +#include "npu_mgr.h" +#include "npu_firmware.h" +#include "npu_hw.h" +#include "npu_host_ipc.h" + +/* ------------------------------------------------------------------------- + * Defines + * ------------------------------------------------------------------------- + */ +/* HFI IPC interface */ +#define TX_HDR_TYPE 0x01000000 +#define RX_HDR_TYPE 0x00010000 +#define HFI_QTBL_STATUS_ENABLED 0x00000001 + +#define QUEUE_TBL_VERSION 0x87654321 + +/* ------------------------------------------------------------------------- + * Data Structures + * ------------------------------------------------------------------------- + */ +struct npu_queue_tuple { + uint32_t size; + uint32_t hdr; +}; + +static const struct npu_queue_tuple npu_q_setup[6] = { + { 1024, IPC_QUEUE_CMD_HIGH_PRIORITY | TX_HDR_TYPE | RX_HDR_TYPE }, + { 4096, IPC_QUEUE_APPS_EXEC | TX_HDR_TYPE | RX_HDR_TYPE }, + { 4096, IPC_QUEUE_DSP_EXEC | TX_HDR_TYPE | RX_HDR_TYPE }, + { 4096, IPC_QUEUE_APPS_RSP | TX_HDR_TYPE | RX_HDR_TYPE }, + { 1024, IPC_QUEUE_DSP_RSP | TX_HDR_TYPE | RX_HDR_TYPE }, + { 1024, IPC_QUEUE_LOG | TX_HDR_TYPE | RX_HDR_TYPE }, +}; + +/* ------------------------------------------------------------------------- + * File Scope Function Prototypes + * ------------------------------------------------------------------------- + */ +static int npu_host_ipc_init_hfi(struct npu_device *npu_dev); +static int npu_host_ipc_send_cmd_hfi(struct npu_device *npu_dev, + uint32_t q_idx, void *cmd_ptr); +static int npu_host_ipc_read_msg_hfi(struct npu_device *npu_dev, + uint32_t q_idx, uint32_t *msg_ptr); +static int ipc_queue_read(struct npu_device *npu_dev, uint32_t target_que, + uint8_t *packet, uint8_t *is_tx_req_set); +static int ipc_queue_write(struct npu_device *npu_dev, uint32_t target_que, + uint8_t *packet, uint8_t *is_rx_req_set); + +/* ------------------------------------------------------------------------- + * Function Definitions + * ------------------------------------------------------------------------- + */ +static int npu_host_ipc_init_hfi(struct npu_device *npu_dev) +{ + int status = 0; + struct hfi_queue_tbl_header *q_tbl_hdr = NULL; + struct hfi_queue_header *q_hdr_arr = NULL; + struct hfi_queue_header *q_hdr = NULL; + void *q_tbl_addr = 0; + uint32_t reg_val = 0; + uint32_t q_idx = 0; + uint32_t q_tbl_size = sizeof(struct hfi_queue_tbl_header) + + (NPU_HFI_NUMBER_OF_QS * sizeof(struct hfi_queue_header)); + uint32_t q_size = 0; + uint32_t cur_start_offset = 0; + + reg_val = REGR(npu_dev, REG_NPU_FW_CTRL_STATUS); + + /* + * If the firmware is already running and we're just attaching, + * we do not need to do this + */ + if ((reg_val & FW_CTRL_STATUS_LOG_READY_VAL) != 0) + return status; + + /* check for valid interface queue table start address */ + q_tbl_addr = kzalloc(q_tbl_size, GFP_KERNEL); + if (q_tbl_addr == NULL) + return -ENOMEM; + + /* retrieve interface queue table start address */ + q_tbl_hdr = q_tbl_addr; + q_hdr_arr = (struct hfi_queue_header *)((uint8_t *)q_tbl_addr + + sizeof(struct hfi_queue_tbl_header)); + + /* initialize the interface queue table header */ + q_tbl_hdr->qtbl_version = QUEUE_TBL_VERSION; + q_tbl_hdr->qtbl_size = q_tbl_size; + q_tbl_hdr->qtbl_qhdr0_offset = sizeof(struct hfi_queue_tbl_header); + q_tbl_hdr->qtbl_qhdr_size = sizeof(struct hfi_queue_header); + q_tbl_hdr->qtbl_num_q = NPU_HFI_NUMBER_OF_QS; + q_tbl_hdr->qtbl_num_active_q = NPU_HFI_NUMBER_OF_ACTIVE_QS; + + cur_start_offset = q_tbl_size; + + for (q_idx = IPC_QUEUE_CMD_HIGH_PRIORITY; + q_idx <= IPC_QUEUE_LOG; q_idx++) { + q_hdr = &q_hdr_arr[q_idx]; + /* queue is active */ + q_hdr->qhdr_status = 0x01; + q_hdr->qhdr_start_offset = cur_start_offset; + q_size = npu_q_setup[q_idx].size; + q_hdr->qhdr_type = npu_q_setup[q_idx].hdr; + /* in bytes */ + q_hdr->qhdr_q_size = q_size; + /* variable size packets */ + q_hdr->qhdr_pkt_size = 0; + q_hdr->qhdr_pkt_drop_cnt = 0; + q_hdr->qhdr_rx_wm = 0x1; + q_hdr->qhdr_tx_wm = 0x1; + /* since queue is initially empty */ + q_hdr->qhdr_rx_req = 0x1; + q_hdr->qhdr_tx_req = 0x0; + /* not used */ + q_hdr->qhdr_rx_irq_status = 0; + /* not used */ + q_hdr->qhdr_tx_irq_status = 0; + q_hdr->qhdr_read_idx = 0; + q_hdr->qhdr_write_idx = 0; + cur_start_offset += q_size; + } + + MEMW(npu_dev, IPC_ADDR, (uint8_t *)q_tbl_hdr, q_tbl_size); + kfree(q_tbl_addr); + /* Write in the NPU's address for where IPC starts */ + REGW(npu_dev, (uint32_t)REG_NPU_HOST_CTRL_VALUE, + (uint32_t)IPC_MEM_OFFSET_FROM_SSTCM); + /* Set value bit */ + reg_val = REGR(npu_dev, (uint32_t)REG_NPU_HOST_CTRL_STATUS); + REGW(npu_dev, (uint32_t)REG_NPU_HOST_CTRL_STATUS, reg_val | + HOST_CTRL_STATUS_IPC_ADDRESS_READY_VAL); + return status; +} + +static int npu_host_ipc_send_cmd_hfi(struct npu_device *npu_dev, + uint32_t q_idx, void *cmd_ptr) +{ + int status = 0; + uint8_t is_rx_req_set = 0; + + status = ipc_queue_write(npu_dev, q_idx, (uint8_t *)cmd_ptr, + &is_rx_req_set); + + if (status == -ENOSPC) { + while (status == -ENOSPC) { + status = ipc_queue_write(npu_dev, q_idx, + (uint8_t *)cmd_ptr, &is_rx_req_set); + } + } + + if (status == 0) { + if (is_rx_req_set == 1) + status = INTERRUPT_RAISE_NPU(npu_dev); + } + + if (status == 0) + pr_debug("Cmd Msg put on Command Queue - SUCCESSS"); + else + pr_err("Cmd Msg put on Command Queue - FAILURE"); + + return status; +} + +static int npu_host_ipc_read_msg_hfi(struct npu_device *npu_dev, + uint32_t q_idx, uint32_t *msg_ptr) +{ + int status = 0; + uint8_t is_tx_req_set; + + status = ipc_queue_read(npu_dev, q_idx, (uint8_t *)msg_ptr, + &is_tx_req_set); + + if (status == 0) { + /* raise interrupt if qhdr_tx_req is set */ + if (is_tx_req_set == 1) + status = INTERRUPT_RAISE_NPU(npu_dev); + } + + return status; +} + +static int ipc_queue_read(struct npu_device *npu_dev, + uint32_t target_que, uint8_t *packet, + uint8_t *is_tx_req_set) +{ + int status = 0; + struct hfi_queue_header queue; + uint32_t packet_size, new_read_idx; + size_t read_ptr; + size_t offset = 0; + + offset = (size_t)IPC_ADDR + sizeof(struct hfi_queue_tbl_header) + + target_que * sizeof(struct hfi_queue_header); + + if ((packet == NULL) || (is_tx_req_set == NULL)) + return -EINVAL; + + /* Read the queue */ + MEMR(npu_dev, (void *)((size_t)offset), (uint8_t *)&queue, + HFI_QUEUE_HEADER_SIZE); + /* check if queue is empty */ + if (queue.qhdr_read_idx == queue.qhdr_write_idx) { + /* + * set qhdr_rx_req, to inform the sender that the Interrupt + * needs to be raised with the next packet queued + */ + queue.qhdr_rx_req = 1; + *is_tx_req_set = 0; + status = -EPERM; + goto exit; + } + + read_ptr = ((size_t)(size_t)IPC_ADDR + + queue.qhdr_start_offset + queue.qhdr_read_idx); + + /* Read packet size */ + MEMR(npu_dev, (void *)((size_t)read_ptr), packet, 4); + packet_size = *((uint32_t *)packet); + + pr_debug("target_que: %d, packet_size: %d ", + target_que, + packet_size); + + if (packet_size == 0) { + status = -EPERM; + goto exit; + } + new_read_idx = queue.qhdr_read_idx + packet_size; + + if (new_read_idx < (queue.qhdr_q_size)) { + MEMR(npu_dev, (void *)((size_t)read_ptr), packet, packet_size); + } else { + new_read_idx -= (queue.qhdr_q_size); + + MEMR(npu_dev, (void *)((size_t)read_ptr), packet, + packet_size - new_read_idx); + + MEMR(npu_dev, (void *)((size_t)IPC_ADDR + + queue.qhdr_start_offset), + (void *)((size_t)packet + (packet_size-new_read_idx)), + new_read_idx); + } + + queue.qhdr_read_idx = new_read_idx; + + if (queue.qhdr_read_idx == queue.qhdr_write_idx) + /* + * receiver wants an interrupt from transmitter + * (when next item queued) because queue is empty + */ + queue.qhdr_rx_req = 1; + else + /* clear qhdr_rx_req since the queue is not empty */ + queue.qhdr_rx_req = 0; + + if (queue.qhdr_tx_req == 1) + /* transmitter requested an interrupt */ + *is_tx_req_set = 1; + else + *is_tx_req_set = 0; +exit: + /* Update RX interrupt request -- queue.qhdr_rx_req */ + MEMW(npu_dev, (void *)((size_t)offset + + (uint32_t)((size_t)&(queue.qhdr_rx_req) - + (size_t)&queue)), (uint8_t *)&queue.qhdr_rx_req, + sizeof(queue.qhdr_rx_req)); + /* Update Read pointer -- queue.qhdr_read_idx */ + MEMW(npu_dev, (void *)((size_t)offset + (uint32_t)( + (size_t)&(queue.qhdr_read_idx) - (size_t)&queue)), + (uint8_t *)&queue.qhdr_read_idx, sizeof(queue.qhdr_read_idx)); + + return status; +} + +static int ipc_queue_write(struct npu_device *npu_dev, + uint32_t target_que, uint8_t *packet, + uint8_t *is_rx_req_set) +{ + int status = 0; + struct hfi_queue_header queue; + uint32_t packet_size, new_write_idx; + uint32_t empty_space; + void *write_ptr; + uint32_t read_idx; + + size_t offset = (size_t)IPC_ADDR + + sizeof(struct hfi_queue_tbl_header) + + target_que * sizeof(struct hfi_queue_header); + + if ((packet == NULL) || (is_rx_req_set == NULL)) + return -EINVAL; + + MEMR(npu_dev, (void *)((size_t)offset), (uint8_t *)&queue, + HFI_QUEUE_HEADER_SIZE); + packet_size = (*(uint32_t *)packet); + if (packet_size == 0) { + /* assign failed status and return */ + status = -EPERM; + goto exit; + } + + /* sample Read Idx */ + read_idx = queue.qhdr_read_idx; + + /* Calculate Empty Space(UWord32) in the Queue */ + empty_space = (queue.qhdr_write_idx >= read_idx) ? + ((queue.qhdr_q_size) - (queue.qhdr_write_idx - read_idx)) : + (read_idx - queue.qhdr_write_idx); + + if (empty_space <= packet_size) { + /* + * If Queue is FULL/ no space for message + * set qhdr_tx_req. + */ + queue.qhdr_tx_req = 1; + + /* + * Queue is FULL, force raise an interrupt to Receiver + */ + *is_rx_req_set = 1; + + status = -ENOSPC; + goto exit; + } + + /* + * clear qhdr_tx_req so that receiver does not raise an interrupt + * on reading packets from Queue, since there is space to write + * the next packet + */ + queue.qhdr_tx_req = 0; + + new_write_idx = (queue.qhdr_write_idx + packet_size); + + write_ptr = (void *)(size_t)((size_t)IPC_ADDR + + queue.qhdr_start_offset + queue.qhdr_write_idx); + + if (new_write_idx < queue.qhdr_q_size) { + MEMW(npu_dev, (void *)((size_t)write_ptr), (uint8_t *)packet, + packet_size); + } else { + /* wraparound case */ + new_write_idx -= (queue.qhdr_q_size); + + MEMW(npu_dev, (void *)((size_t)write_ptr), (uint8_t *)packet, + packet_size - new_write_idx); + + MEMW(npu_dev, (void *)((size_t)((size_t)IPC_ADDR + + queue.qhdr_start_offset)), (uint8_t *)(packet + + (packet_size - new_write_idx)), new_write_idx); + } + + /* Update qhdr_write_idx */ + queue.qhdr_write_idx = new_write_idx; + + *is_rx_req_set = (queue.qhdr_rx_req == 1) ? 1 : 0; + + /* Update Write pointer -- queue.qhdr_write_idx */ +exit: + /* Update TX request -- queue.qhdr_tx_req */ + MEMW(npu_dev, (void *)((size_t)(offset + (uint32_t)( + (size_t)&(queue.qhdr_tx_req) - (size_t)&queue))), + &queue.qhdr_tx_req, sizeof(queue.qhdr_tx_req)); + MEMW(npu_dev, (void *)((size_t)(offset + (uint32_t)( + (size_t)&(queue.qhdr_write_idx) - (size_t)&queue))), + &queue.qhdr_write_idx, sizeof(queue.qhdr_write_idx)); + + return status; +} + +/* ------------------------------------------------------------------------- + * IPC Interface functions + * ------------------------------------------------------------------------- + */ +int npu_host_ipc_send_cmd(struct npu_device *npu_dev, uint32_t q_idx, + void *cmd_ptr) +{ + return npu_host_ipc_send_cmd_hfi(npu_dev, q_idx, cmd_ptr); +} + +int npu_host_ipc_read_msg(struct npu_device *npu_dev, uint32_t q_idx, + uint32_t *msg_ptr) +{ + return npu_host_ipc_read_msg_hfi(npu_dev, q_idx, msg_ptr); +} + +int npu_host_ipc_pre_init(struct npu_device *npu_dev) +{ + return npu_host_ipc_init_hfi(npu_dev); +} + +int npu_host_ipc_post_init(struct npu_device *npu_dev) +{ + return 0; +} diff --git a/drivers/media/platform/msm/npu/npu_host_ipc.h b/drivers/media/platform/msm/npu/npu_host_ipc.h new file mode 100644 index 000000000000..2acdced5550a --- /dev/null +++ b/drivers/media/platform/msm/npu/npu_host_ipc.h @@ -0,0 +1,323 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef NPU_HOST_IPC_H +#define NPU_HOST_IPC_H + +/* ------------------------------------------------------------------------- + * Defines + * ------------------------------------------------------------------------- + */ +/* Messages sent **to** NPU */ +/* IPC Message Commands -- uint32_t */ +/* IPC command start base */ +#define NPU_IPC_CMD_BASE 0x00000000 +/* ipc_cmd_load_pkt */ +#define NPU_IPC_CMD_LOAD 0x00000001 +/* ipc_cmd_unload_pkt */ +#define NPU_IPC_CMD_UNLOAD 0x00000002 +/* ipc_cmd_execute_pkt */ +#define NPU_IPC_CMD_EXECUTE 0x00000003 +/* ipc_cmd_set_logging_state */ +#define NPU_IPC_CMD_CONFIG_LOG 0x00000004 +#define NPU_IPC_CMD_CONFIG_PERFORMANCE 0x00000005 +#define NPU_IPC_CMD_CONFIG_DEBUG 0x00000006 +#define NPU_IPC_CMD_SHUTDOWN 0x00000007 + +/* Messages sent **from** NPU */ +/* IPC Message Response -- uint32_t */ +/* IPC response start base */ +#define NPU_IPC_MSG_BASE 0x00010000 +/* ipc_msg_load_pkt */ +#define NPU_IPC_MSG_LOAD_DONE 0x00010001 +/* ipc_msg_header_pkt */ +#define NPU_IPC_MSG_UNLOAD_DONE 0x00010002 +/* ipc_msg_header_pkt */ +#define NPU_IPC_MSG_EXECUTE_DONE 0x00010003 +/* ipc_msg_event_notify_pkt */ +#define NPU_IPC_MSG_EVENT_NOTIFY 0x00010004 + +/* Logging message size */ +/* Number 32-bit elements for the maximum log message size */ +#define NPU_LOG_MSG_MAX_SIZE 4 + +/* Performance */ +/* Performance counters for current network layer */ +/* Amount of data read from all the DMA read channels */ +#define NPU_PERFORMANCE_DMA_DATA_READ 0x01 +/* Amount of data written from all the DMA write channels */ +#define NPU_PERFORMANCE_DMA_DATA_WRITTEN 0x02 +/* Number of blocks read by DMA channels */ +#define NPU_PERFORMANCE_DMA_NUM_BLOCKS_READ 0x03 +/* Number of blocks written by DMA channels */ +#define NPU_PERFORMANCE_DMA_NUM_BLOCKS_WRITTEN 0x04 +/* Number of instructions executed by CAL */ +#define NPU_PERFORMANCE_INSTRUCTIONS_CAL 0x05 +/* Number of instructions executed by CUB */ +#define NPU_PERFORMANCE_INSTRUCTIONS_CUB 0x06 +/* Timestamp of start of network load */ +#define NPU_PERFORMANCE_TIMESTAMP_LOAD_START 0x07 +/* Timestamp of end of network load */ +#define NPU_PERFORMANCE_TIMESTAMP_LOAD_END 0x08 +/* Timestamp of start of network execute */ +#define NPU_PERFORMANCE_TIMESTAMP_EXECUTE_START 0x09 +/* Timestamp of end of network execute */ +#define NPU_PERFORMANCE_TIMESTAMP_EXECUTE_END 0x10 +/* Timestamp of CAL start */ +#define NPU_PERFORMANCE_TIMESTAMP_CAL_START 0x11 +/* Timestamp of CAL end */ +#define NPU_PERFORMANCE_TIMESTAMP_CAL_END 0x12 +/* Timestamp of CUB start */ +#define NPU_PERFORMANCE_TIMESTAMP_CUB_START 0x13 +/* Timestamp of CUB end */ +#define NPU_PERFORMANCE_TIMESTAMP_CUB_END 0x14 + +/* Performance enable */ +/* Select which counters you want back per layer */ + +/* Shutdown */ +/* Immediate shutdown, discard any state, etc */ +#define NPU_SHUTDOWN_IMMEDIATE 0x01 +/* Shutdown after current execution (if any) is completed */ +#define NPU_SHUTDOWN_WAIT_CURRENT_EXECUTION 0x02 + +/* Debug stats */ +#define NUM_LAYER_STATS_PER_EXE_MSG_MAX 110 + +/* ------------------------------------------------------------------------- + * Data Structures + * ------------------------------------------------------------------------- + */ +/* Command Header - Header for all Messages **TO** NPU */ +/* + * command header packet definition for + * messages sent from host->NPU + */ +struct ipc_cmd_header_pkt { + uint32_t size; + uint32_t cmd_type; + uint32_t trans_id; + uint32_t flags; /* TDO what flags and why */ +}; + +/* Message Header - Header for all messages **FROM** NPU */ +/* + * message header packet definition for + * mesasges sent from NPU->host + */ +struct ipc_msg_header_pkt { + uint32_t size; + uint32_t msg_type; + uint32_t status; + uint32_t trans_id; + uint32_t flags; +}; + +/* Execute */ +/* + * FIRMWARE + * keep lastNetworkIDRan = uint32 + * keep wasLastNetworkChunky = BOOLEAN + */ +/* + * ACO Buffer definition + */ +struct npu_aco_buffer { + /* + * used to track if previous network is the same and already loaded, + * we can save a dma + */ + uint32_t network_id; + /* + * size of header + first chunk ACO buffer - + * this saves a dma by dmaing both header and first chunk + */ + uint32_t buf_size; + /* + * SMMU 32-bit mapped address that the DMA engine can read - + * uses lower 32 bits + */ + uint64_t address; +}; + +/* + * ACO Patch Parameters + */ +struct npu_patch_tuple { + uint32_t value; + uint32_t chunk_id; + uint16_t instruction_size_in_bytes; + uint16_t variable_size_in_bits; + uint16_t shift_value_in_bits; + uint32_t loc_offset; +}; + +struct npu_patch_params { + uint32_t num_params; + struct npu_patch_tuple param[2]; +}; + +/* + * LOAD command packet definition + */ +struct ipc_cmd_load_pkt { + struct ipc_cmd_header_pkt header; + struct npu_aco_buffer buf_pkt; +}; + +/* + * UNLOAD command packet definition + */ +struct ipc_cmd_unload_pkt { + struct ipc_cmd_header_pkt header; + uint32_t aco_hdl; +}; + +/* + * Execute packet definition + */ +struct ipc_cmd_execute_pkt { + struct ipc_cmd_header_pkt header; + struct npu_patch_params patch_params; + uint32_t aco_hdl; +}; + +/* + * LOAD response packet definition + */ +struct ipc_msg_load_pkt { + struct ipc_msg_header_pkt header; + uint32_t aco_hdl; +}; + +/* + * UNLOAD response packet definition -- ipc_msg_header_pkt + */ + +/* + * Layer Stats information returned back during EXECUTE_DONE response + */ +struct ipc_layer_stats { + /* + * layer id + * 8 bits enough for the current networks supporting + */ + uint8_t layer_id; + /* + * hardware tick count per layer + */ + uint32_t tick_count; +}; + +struct ipc_execute_layer_stats { + /* + * total number of layers associated with the execution + */ + uint8_t total_num_layers; + /* + * pointer to each layer stats + */ + struct ipc_layer_stats + layer_stats_list[NUM_LAYER_STATS_PER_EXE_MSG_MAX]; +}; + +struct ipc_execute_stats { + /* + * total e2e IPC tick count during EXECUTE cmd + */ + uint32_t e2e_ipc_tick_count; + /* + * tick count on ACO loading + */ + uint32_t aco_load_tick_count; + /* + * tick count on ACO execution + */ + uint32_t aco_execution_tick_count; + /* + * individual layer stats + */ + struct ipc_execute_layer_stats exe_stats; +}; + +/* + * EXECUTE response packet definition + */ +struct ipc_msg_execute_pkt { + struct ipc_msg_header_pkt header; + struct ipc_execute_stats stats; +}; + +/* Logging Related */ + +/* + * ipc_log_state_t - Logging state + */ +struct ipc_log_state { + uint32_t module_msk; + uint32_t level_msk; +}; + +struct ipc_cmd_log_state_pkt { + struct ipc_cmd_header_pkt header; + struct ipc_log_state log_state; +}; + +struct ipc_msg_log_state_pkt { + struct ipc_msg_header_pkt header; + struct ipc_log_state log_state; +}; + +/* + * Logging message + * This is a message from the NPU that contains the + * logging message. The values of part1-4 are not exposed + * the receiver has to refer to the logging implementation to + * intrepret what these mean and how to parse + */ +struct ipc_msg_log_pkt { + struct ipc_msg_header_pkt header; + uint32_t log_msg[NPU_LOG_MSG_MAX_SIZE]; +}; + +/* Performance Related */ + +/* + * Set counter mask of which counters we want + * This is a message from HOST->NPU Firmware + */ +struct ipc_cmd_set_performance_query { + struct ipc_cmd_header_pkt header; + uint32_t cnt_msk; +}; + +/* + * Set counter mask of which counters we want + * This is a message from HOST->NPU Firmware + */ +struct ipc_msg_performance_counters { + struct ipc_cmd_header_pkt header; + uint32_t layer_id; + uint32_t num_tulpes; + /* Array of tuples [HEADER,value] */ + uint32_t cnt_tulpes[1]; +}; + +/* + * ipc_cmd_shutdown - Shutdown command + */ +struct ipc_cmd_shutdown_pkt { + struct ipc_cmd_header_pkt header; + uint32_t shutdown_flags; +}; + +#endif /* NPU_HOST_IPC_H */ diff --git a/drivers/media/platform/msm/npu/npu_hw.h b/drivers/media/platform/msm/npu/npu_hw.h new file mode 100644 index 000000000000..0c1e15bc0095 --- /dev/null +++ b/drivers/media/platform/msm/npu/npu_hw.h @@ -0,0 +1,297 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef NPU_HW_H +#define NPU_HW_H + +/* ------------------------------------------------------------------------- + * Defines + * ------------------------------------------------------------------------- + */ +#define NPU_HW_VERSION (0x00100000) +#define NPU_MASTERn_IPC_IRQ_OUT(n) (0x00101004+0x1000*(n)) +#define NPU_CACHE_ATTR_IDn___POR 0x00011100 +#define NPU_CACHE_ATTR_IDn(n) (0x00100800+0x4*(n)) +#define NPU_MASTERn_IPC_IRQ_IN_CTRL(n) (0x00101008+0x1000*(n)) +#define NPU_MASTER0_IPC_IRQ_IN_CTRL__IRQ_SOURCE_SELECT___S 4 +#define NPU_GPR0 (0x00100100) +#define NPU_GPR1 (0x00100104) +#define NPU_GPR2 (0x00100108) +#define NPU_GPR3 (0x0010010C) +#define NPU_GPR4 (0x00100110) +#define NPU_GPR14 (0x00100138) +#define NPU_GPR15 (0x0010013C) + +#define CAL_DP_DMA_WR_RLD_CMD_0 (0x00580000) +#define CAL_DP_DMA_RD_RLD_CMD_0 (0x00580004) +#define CAL_DP_DMA_RD_RLD_CMD_1 (0x00580008) +#define CAL_DP_DMA_RD_RLD_CMD_2 (0x0058000C) +#define CAL_DP_DMA_RD_RLD_CMD_3 (0x00580010) +#define CAL_DP_DMA_LOC_RLD_CMD_0 (0x00580014) +#define CAL_DP_DMA_BUS_CFG (0x00580200) +#define CAL_DP_DMA_BUS_OT_CFG (0x00580204) +#define CAL_DP_DMA_WR_CFG_0 (0x00580400) +#define CAL_DP_DMA_WR_NUM_CMD_IT_0 (0x00580404) +#define CAL_DP_DMA_WR_START_ADDR_0 (0x00580408) +#define CAL_DP_DMA_WR_MAX_ADDR_0 (0x0058040C) +#define CAL_DP_DMA_WR_STRIDE_DIM0_0 (0x00580410) +#define CAL_DP_DMA_WR_STRIDE_DIM1_0 (0x00580414) +#define CAL_DP_DMA_WR_STRIDE_DIM2_0 (0x00580418) +#define CAL_DP_DMA_WR_ROW_INCR_0 (0x0058041C) +#define CAL_DP_DMA_WR_DIM0_XSIZE_0 (0x00580420) +#define CAL_DP_DMA_WR_DIM0_INCR_0 (0x00580424) +#define CAL_DP_DMA_WR_DIM0_NUM_BLK_0 (0x00580428) +#define CAL_DP_DMA_WR_DIM1_XSIZE_0 (0x0058042C) +#define CAL_DP_DMA_WR_DIM1_YSIZE_0 (0x00580430) +#define CAL_DP_DMA_WR_DIM2_XSIZE_0 (0x00580434) +#define CAL_DP_DMA_WR_DIM2_YSIZE_0 (0x00580438) +#define CAL_DP_DMA_WR_CLIENT_BLK_SIZE_CFG_0 (0x0058043C) +#define CAL_DP_DMA_WR_CLIENT_ADDR_CFG_0 (0x00580440) +#define CAL_DP_DMA_WR_CLIENT_BUFF_CFG_0 (0x00580444) +#define CAL_DP_DMA_WR_MMU_CFG_0 (0x00580448) +#define CAL_DP_DMA_RD_CFG_0 (0x00580600) +#define CAL_DP_DMA_RD_NUM_CMD_IT_0 (0x00580604) +#define CAL_DP_DMA_RD_START_ADDR_0 (0x00580608) +#define CAL_DP_DMA_RD_START_ADDR1_0 (0x0058060C) +#define CAL_DP_DMA_RD_END_ADDR0_0 (0x00580610) +#define CAL_DP_DMA_RD_MAX_ADDR_0 (0x00580614) +#define CAL_DP_DMA_RD_MAX_ADDR1_0 (0x00580618) +#define CAL_DP_DMA_RD_STRIDE_DIM0_0 (0x0058061C) +#define CAL_DP_DMA_RD_STRIDE_DIM0_FIRST_0 (0x00580620) +#define CAL_DP_DMA_RD_STRIDE_DIM1_0 (0x00580624) +#define CAL_DP_DMA_RD_STRIDE_DIM1_FIRST_0 (0x00580628) +#define CAL_DP_DMA_RD_STRIDE_DIM2_0 (0x0058062C) +#define CAL_DP_DMA_RD_STRIDE_DIM2_FIRST_0 (0x00580630) +#define CAL_DP_DMA_RD_ROW_INCR_0 (0x00580634) +#define CAL_DP_DMA_RD_DIM0_BLK_SIZE_0 (0x00580638) +#define CAL_DP_DMA_RD_DIM0_INCR_0 (0x0058063C) +#define CAL_DP_DMA_RD_DIM0_NUM_BLK_0 (0x00580640) +#define CAL_DP_DMA_RD_DIM1_BLK_SIZE_0 (0x00580644) +#define CAL_DP_DMA_RD_DIM1_STRIPE_SIZE_0 (0x00580648) +#define CAL_DP_DMA_RD_DIM2_BLK_SIZE_0 (0x0058064C) +#define CAL_DP_DMA_RD_DIM2_STRIPE_SIZE_0 (0x00580650) +#define CAL_DP_DMA_RD_DIM0_PAD_L_0 (0x00580654) +#define CAL_DP_DMA_RD_DIM0_PAD_R_0 (0x00580658) +#define CAL_DP_DMA_RD_PAD_TB_0 (0x0058065C) +#define CAL_DP_DMA_RD_DIM0_CROP_0 (0x00580660) +#define CAL_DP_DMA_RD_CLIENT_ADDR_CFG_0 (0x00580664) +#define CAL_DP_DMA_RD_CLIENT_BUFF_CFG_0 (0x00580668) +#define CAL_DP_DMA_RD_MMU_CFG_0 (0x0058066C) +#define CAL_DP_DMA_RD_PAD_VALUE_0 (0x00580670) +#define CAL_DP_DMA_RD_CFG_1 (0x00580800) +#define CAL_DP_DMA_RD_NUM_CMD_IT_1 (0x00580804) +#define CAL_DP_DMA_RD_START_ADDR_1 (0x00580808) +#define CAL_DP_DMA_RD_START_ADDR1_1 (0x0058080C) +#define CAL_DP_DMA_RD_END_ADDR0_1 (0x00580810) +#define CAL_DP_DMA_RD_MAX_ADDR_1 (0x00580814) +#define CAL_DP_DMA_RD_MAX_ADDR1_1 (0x00580818) +#define CAL_DP_DMA_RD_STRIDE_DIM0_1 (0x0058081C) +#define CAL_DP_DMA_RD_STRIDE_DIM0_FIRST_1 (0x00580820) +#define CAL_DP_DMA_RD_STRIDE_DIM1_1 (0x00580824) +#define CAL_DP_DMA_RD_STRIDE_DIM1_FIRST_1 (0x00580828) +#define CAL_DP_DMA_RD_STRIDE_DIM2_1 (0x0058082C) +#define CAL_DP_DMA_RD_STRIDE_DIM2_FIRST_1 (0x00580830) +#define CAL_DP_DMA_RD_ROW_INCR_1 (0x00580834) +#define CAL_DP_DMA_RD_DIM0_BLK_SIZE_1 (0x00580838) +#define CAL_DP_DMA_RD_DIM0_INCR_1 (0x0058083C) +#define CAL_DP_DMA_RD_DIM0_NUM_BLK_1 (0x00580840) +#define CAL_DP_DMA_RD_DIM1_BLK_SIZE_1 (0x00580844) +#define CAL_DP_DMA_RD_DIM1_STRIPE_SIZE_1 (0x00580848) +#define CAL_DP_DMA_RD_DIM2_BLK_SIZE_1 (0x0058084C) +#define CAL_DP_DMA_RD_DIM2_STRIPE_SIZE_1 (0x00580850) +#define CAL_DP_DMA_RD_DIM0_PAD_L_1 (0x00580854) +#define CAL_DP_DMA_RD_DIM0_PAD_R_1 (0x00580858) +#define CAL_DP_DMA_RD_PAD_TB_1 (0x0058085C) +#define CAL_DP_DMA_RD_DIM0_CROP_1 (0x00580860) +#define CAL_DP_DMA_RD_CLIENT_ADDR_CFG_1 (0x00580864) +#define CAL_DP_DMA_RD_CLIENT_BUFF_CFG_1 (0x00580868) +#define CAL_DP_DMA_RD_MMU_CFG_1 (0x0058086C) +#define CAL_DP_DMA_RD_PAD_VALUE_1 (0x00580870) +#define CAL_DP_DMA_RD_CFG_2 (0x00580A00) +#define CAL_DP_DMA_RD_NUM_CMD_IT_2 (0x00580A04) +#define CAL_DP_DMA_RD_START_ADDR_2 (0x00580A08) +#define CAL_DP_DMA_RD_START_ADDR1_2 (0x00580A0C) +#define CAL_DP_DMA_RD_END_ADDR0_2 (0x00580A10) +#define CAL_DP_DMA_RD_MAX_ADDR_2 (0x00580A14) +#define CAL_DP_DMA_RD_MAX_ADDR1_2 (0x00580A18) +#define CAL_DP_DMA_RD_STRIDE_DIM0_2 (0x00580A1C) +#define CAL_DP_DMA_RD_STRIDE_DIM0_FIRST_2 (0x00580A20) +#define CAL_DP_DMA_RD_STRIDE_DIM1_2 (0x00580A24) +#define CAL_DP_DMA_RD_STRIDE_DIM1_FIRST_2 (0x00580A28) +#define CAL_DP_DMA_RD_STRIDE_DIM2_2 (0x00580A2C) +#define CAL_DP_DMA_RD_STRIDE_DIM2_FIRST_2 (0x00580A30) +#define CAL_DP_DMA_RD_ROW_INCR_2 (0x00580A34) +#define CAL_DP_DMA_RD_DIM0_BLK_SIZE_2 (0x00580A38) +#define CAL_DP_DMA_RD_DIM0_INCR_2 (0x00580A3C) +#define CAL_DP_DMA_RD_DIM0_NUM_BLK_2 (0x00580A40) +#define CAL_DP_DMA_RD_DIM1_BLK_SIZE_2 (0x00580A44) +#define CAL_DP_DMA_RD_DIM1_STRIPE_SIZE_2 (0x00580A48) +#define CAL_DP_DMA_RD_DIM2_BLK_SIZE_2 (0x00580A4C) +#define CAL_DP_DMA_RD_DIM2_STRIPE_SIZE_2 (0x00580A50) +#define CAL_DP_DMA_RD_DIM0_PAD_L_2 (0x00580A54) +#define CAL_DP_DMA_RD_DIM0_PAD_R_2 (0x00580A58) +#define CAL_DP_DMA_RD_PAD_TB_2 (0x00580A5C) +#define CAL_DP_DMA_RD_DIM0_CROP_2 (0x00580A60) +#define CAL_DP_DMA_RD_CLIENT_ADDR_CFG_2 (0x00580A64) +#define CAL_DP_DMA_RD_CLIENT_BUFF_CFG_2 (0x00580A68) +#define CAL_DP_DMA_RD_MMU_CFG_2 (0x00580A6C) +#define CAL_DP_DMA_RD_PAD_VALUE_2 (0x00580A70) +#define CAL_DP_DMA_RD_CFG_3 (0x00580C00) +#define CAL_DP_DMA_RD_NUM_CMD_IT_3 (0x00580C04) +#define CAL_DP_DMA_RD_START_ADDR_3 (0x00580C08) +#define CAL_DP_DMA_RD_START_ADDR1_3 (0x00580C0C) +#define CAL_DP_DMA_RD_END_ADDR0_3 (0x00580C10) +#define CAL_DP_DMA_RD_MAX_ADDR_3 (0x00580C14) +#define CAL_DP_DMA_RD_MAX_ADDR1_3 (0x00580C18) +#define CAL_DP_DMA_RD_STRIDE_DIM0_3 (0x00580C1C) +#define CAL_DP_DMA_RD_STRIDE_DIM0_FIRST_3 (0x00580C20) +#define CAL_DP_DMA_RD_STRIDE_DIM1_3 (0x00580C24) +#define CAL_DP_DMA_RD_STRIDE_DIM1_FIRST_3 (0x00580C28) +#define CAL_DP_DMA_RD_STRIDE_DIM2_3 (0x00580C2C) +#define CAL_DP_DMA_RD_STRIDE_DIM2_FIRST_3 (0x00580C30) +#define CAL_DP_DMA_RD_ROW_INCR_3 (0x00580C34) +#define CAL_DP_DMA_RD_DIM0_BLK_SIZE_3 (0x00580C38) +#define CAL_DP_DMA_RD_DIM0_INCR_3 (0x00580C3C) +#define CAL_DP_DMA_RD_DIM0_NUM_BLK_3 (0x00580C40) +#define CAL_DP_DMA_RD_DIM1_BLK_SIZE_3 (0x00580C44) +#define CAL_DP_DMA_RD_DIM1_STRIPE_SIZE_3 (0x00580C48) +#define CAL_DP_DMA_RD_DIM2_BLK_SIZE_3 (0x00580C4C) +#define CAL_DP_DMA_RD_DIM2_STRIPE_SIZE_3 (0x00580C50) +#define CAL_DP_DMA_RD_DIM0_PAD_L_3 (0x00580C54) +#define CAL_DP_DMA_RD_DIM0_PAD_R_3 (0x00580C58) +#define CAL_DP_DMA_RD_PAD_TB_3 (0x00580C5C) +#define CAL_DP_DMA_RD_DIM0_CROP_3 (0x00580C60) +#define CAL_DP_DMA_RD_CLIENT_ADDR_CFG_3 (0x00580C64) +#define CAL_DP_DMA_RD_CLIENT_BUFF_CFG_3 (0x00580C68) +#define CAL_DP_DMA_RD_MMU_CFG_3 (0x00580C6C) +#define CAL_DP_DMA_RD_PAD_VALUE_3 (0x00580C70) +#define CAL_DP_DMA_LOC_SRC_ADDR_0 (0x00580E00) +#define CAL_DP_DMA_LOC_DEST_ADDR_0 (0x00580E04) +#define CAL_DP_DMA_LOC_DATA_SIZE_0 (0x00580E08) +#define CAL_DP_DMA_WR_ERR_STATUS_0 (0x00581000) +#define CAL_DP_DMA_WR_MAX_P_CNT_0 (0x00581004) +#define CAL_DP_DMA_WR_STATUS_0_0 (0x00581008) +#define CAL_DP_DMA_WR_STATUS_0_1 (0x0058100C) +#define CAL_DP_DMA_WR_STATUS_0_2 (0x00581010) +#define CAL_DP_DMA_WR_STATUS_0_3 (0x00581014) +#define CAL_DP_DMA_RD_ERR_STATUS_0 (0x00581200) +#define CAL_DP_DMA_RD_MAX_P_CNT_0 (0x00581204) +#define CAL_DP_DMA_RD_STATUS_0_0 (0x00581208) +#define CAL_DP_DMA_RD_STATUS_0_1 (0x0058120C) +#define CAL_DP_DMA_RD_STATUS_0_2 (0x00581210) +#define CAL_DP_DMA_RD_STATUS_0_3 (0x00581214) +#define CAL_DP_DMA_RD_STATUS_0_4 (0x00581218) +#define CAL_DP_DMA_RD_ERR_STATUS_1 (0x00581400) +#define CAL_DP_DMA_RD_MAX_P_CNT_1 (0x00581404) +#define CAL_DP_DMA_RD_STATUS_1_0 (0x00581408) +#define CAL_DP_DMA_RD_STATUS_1_1 (0x0058140C) +#define CAL_DP_DMA_RD_STATUS_1_2 (0x00581410) +#define CAL_DP_DMA_RD_STATUS_1_3 (0x00581414) +#define CAL_DP_DMA_RD_STATUS_1_4 (0x00581418) +#define CAL_DP_DMA_RD_ERR_STATUS_2 (0x00581600) +#define CAL_DP_DMA_RD_MAX_P_CNT_2 (0x00581604) +#define CAL_DP_DMA_RD_STATUS_2_0 (0x00581608) +#define CAL_DP_DMA_RD_STATUS_2_1 (0x0058160C) +#define CAL_DP_DMA_RD_STATUS_2_2 (0x00581610) +#define CAL_DP_DMA_RD_STATUS_2_3 (0x00581614) +#define CAL_DP_DMA_RD_STATUS_2_4 (0x00581618) +#define CAL_DP_DMA_RD_ERR_STATUS_3 (0x00581800) +#define CAL_DP_DMA_RD_MAX_P_CNT_3 (0x00581804) +#define CAL_DP_DMA_RD_STATUS_3_0 (0x00581808) +#define CAL_DP_DMA_RD_STATUS_3_1 (0x0058180C) +#define CAL_DP_DMA_RD_STATUS_3_2 (0x00581810) +#define CAL_DP_DMA_RD_STATUS_3_3 (0x00581814) +#define CAL_DP_DMA_LOC_ERR_STATUS_0 (0x00581A00) +#define CAL_DP_DMA_LOC_STATUS_0_0 (0x00581A04) +#define CAL_DP_DMA_LOC_STATUS_0_1 (0x00581A08) +#define CAL_DP_DMA_LOC_STATUS_0_2 (0x00581A0C) +#define CAL_DP_DMA_LOC_STATUS_0_3 (0x00581A10) +#define CAL_DP_CALDMA_ADAPT_STATUS_0_0 (0x00581C00) +#define CAL_DP_CALDMA_ADAPT_STATUS_0_1 (0x00581C04) +#define CAL_DP_SDMA_WR_STATUS_0_0 (0x00581E00) +#define CAL_DP_SDMA_WR_STATUS_0_1 (0x00581E04) +#define CAL_DP_SDMA_WR_STATUS_0_2 (0x00581E08) +#define CAL_DP_SDMA_WR_STATUS_0_3 (0x00581E0C) +#define CAL_DP_SDMA_WR_STATUS_0_4 (0x00581E10) +#define CAL_DP_SDMA_WR_STATUS_0_5 (0x00581E14) +#define CAL_DP_SDMA_WR_STATUS_0_6 (0x00581E18) +#define CAL_DP_SDMA_WR_STATUS_0_7 (0x00581E1C) +#define CAL_DP_SDMA_WR_STATUS_0_8 (0x00581E20) +#define CAL_DP_SDMA_RD_STATUS_0_0 (0x00581E24) +#define CAL_DP_SDMA_RD_STATUS_0_1 (0x00581E28) +#define CAL_DP_SDMA_RD_STATUS_0_2 (0x00581E2C) +#define CAL_DP_SDMA_RD_STATUS_0_3 (0x00581E30) +#define CAL_DP_SDMA_RD_STATUS_0_4 (0x00581E34) +#define CAL_DP_SDMA_RD_STATUS_0_5 (0x00581E38) +#define CAL_DP_SDMA_RD_STATUS_0_6 (0x00581E3C) +#define CAL_DP_SDMA_RD_STATUS_0_7 (0x00581E40) +#define CAL_DP_SDMA_RD_STATUS_0_8 (0x00581E44) +#define CAL_DP_SDMA_RD_STATUS_0_9 (0x00581E48) +#define CAL_DP_SDMA_RD_STATUS_0_10 (0x00581E4C) +#define CAL_DP_TCM_SET_CMD (0x005A0000) +#define CAL_DP_TCM_RESET_CMD (0x005A0004) +#define CAL_DP_DTSWC_INT_CLR (0x005A0008) +#define CAL_DP_TCM_INT_CLR (0x005A000C) +#define CAL_DP_DTSWC_INT_SET (0x005A0010) +#define CAL_DP_TCM_INT_SET (0x005A0014) +#define CAL_DP_WD_RSS_CMD (0x005A0018) +#define CAL_DP_RESET_CMD (0x005A001C) +#define CAL_DP_PERF_CNT_CMD (0x005A0020) +#define CAL_DP_DBUF_TRANSFER_CMD (0x005A0024) +#define CAL_DP_CAL_EN_CTRL (0x005B0000) +#define CAL_DP_EN_INT_CTRL (0x005B0004) +#define CAL_DP_EN_TCM_INT_CTRL (0x005B0008) +#define CAL_DP_TCM_VAL_CTRL (0x005B000C) +#define CAL_DP_WD_COUNT_LO (0x005B0010) +#define CAL_DP_WD_COUNT_HI (0x005B0014) +#define CAL_DP_RSS_SEL_CTRL (0x005B0018) +#define CAL_DP_CAL_CFG_W0 (0x005B001C) +#define CAL_DP_CAL_CFG_W1 (0x005B0020) +#define CAL_DP_CAL_CFG_W2 (0x005B0024) +#define CAL_DP_CAL_CFG_W3 (0x005B0028) +#define CAL_DP_PERF_CNT_START_SEL (0x005B002C) +#define CAL_DP_PERF_CNT_STOP_SEL (0x005B0030) +#define CAL_DP_PERF_CNT_EVENT_SEL (0x005B0034) +#define CAL_DP_DBUF_RD_SEL (0x005B0038) +#define CAL_DP_LM_CTRL (0x005B003C) +#define CAL_DP_LM_LOOK_AHEAD (0x005B0040) +#define CAL_DP_LM_CUB_TIMER (0x005B0044) +#define CAL_DP_SIGB_STATUS (0x005C0000) +#define CAL_DP_CAL_EN_WD_RSS_STATUS (0x005C0004) +#define CAL_DP_EN_TCM_FLAGS_STATUS (0x005C0008) +#define CAL_DP_VERSION_STATUS (0x005C000C) +#define CAL_DP_CFG_STATUS (0x005C0010) +#define CAL_DP_CUB_SAT_DTCT_STATUS (0x005C0014) +#define CAL_DP_AHB_ERR_ADDR_STATUS (0x005C0018) +#define CAL_DP_WD_STATUS_LO (0x005C001C) +#define CAL_DP_WD_STATUS_HI (0x005C0020) +#define CAL_DP_DTSWC_INT_STATUS (0x005C0024) +#define CAL_DP_DTSWC_TCM_INT_STATUS (0x005C0028) +#define CAL_DP_DTSWC_UM_INT_STATUS (0x005C002C) +#define CAL_DP_DTSWC_TCM_UM_INT_STATUS (0x005C0030) +#define CAL_DP_RSS_STATUS (0x005C0034) +#define CAL_DP_RSS_STATUS_1 (0x005C0038) +#define CAL_DP_RSS_STATUS_2 (0x005C003C) +#define CAL_DP_RSS_STATUS_3 (0x005C0040) +#define CAL_DP_RSS_STATUS_4 (0x005C0044) +#define CAL_DP_RSS_STATUS_5 (0x005C0048) +#define CAL_DP_RSS_STATUS_6 (0x005C004C) +#define CAL_DP_RSS_STATUS_7 (0x005C0050) +#define CAL_DP_PERF_CNT0 (0x005C0054) +#define CAL_DP_PERF_CNT1 (0x005C0058) +#define CAL_DP_PERF_CNT2 (0x005C005C) +#define CAL_DP_PERF_CNT3 (0x005C0060) +#define CAL_DP_FINAL_MIN (0x005C0064) +#define CAL_DP_FINAL_MAX (0x005C0068) +#define CAL_DP_LM_STATUS (0x005C006C) + +#endif /* NPU_HW_H */ diff --git a/drivers/media/platform/msm/npu/npu_hw_access.c b/drivers/media/platform/msm/npu/npu_hw_access.c new file mode 100644 index 000000000000..b3a8f8cb9da5 --- /dev/null +++ b/drivers/media/platform/msm/npu/npu_hw_access.c @@ -0,0 +1,369 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +/* ------------------------------------------------------------------------- + * Includes + * ------------------------------------------------------------------------- + */ +#include +#include +#include +#include + +#include "npu_hw_access.h" +#include "npu_common.h" +#include "npu_hw.h" + +/* ------------------------------------------------------------------------- + * Functions - Register + * ------------------------------------------------------------------------- + */ +uint32_t npu_reg_read(struct npu_device *npu_dev, uint32_t off) +{ + uint32_t ret = 0; + + ret = readl_relaxed(npu_dev->npu_base + off); + __iormb(); + return ret; +} + +void npu_reg_write(struct npu_device *npu_dev, uint32_t off, uint32_t val) +{ + writel_relaxed(val, npu_dev->npu_base + off); + __iowmb(); +} + +/* ------------------------------------------------------------------------- + * Functions - Memory + * ------------------------------------------------------------------------- + */ +void npu_mem_write(struct npu_device *npu_dev, void *dst, void *src, + uint32_t size) +{ + size_t dst_off = (size_t)dst; + uint32_t *src_ptr32 = (uint32_t *)src; + uint8_t *src_ptr8 = 0; + uint32_t i = 0; + uint32_t num = 0; + + num = size/4; + for (i = 0; i < num; i++) { + writel_relaxed(src_ptr32[i], npu_dev->npu_base + dst_off); + dst_off += 4; + } + + if (size%4 != 0) { + src_ptr8 = (uint8_t *)((size_t)src + (num*4)); + num = size%4; + for (i = 0; i < num; i++) { + writeb_relaxed(src_ptr8[i], npu_dev->npu_base + + dst_off); + dst_off += 1; + } + } +} + +int32_t npu_mem_read(struct npu_device *npu_dev, void *src, void *dst, + uint32_t size) +{ + size_t src_off = (size_t)src; + uint32_t *out32 = (uint32_t *)dst; + uint8_t *out8 = 0; + uint32_t i = 0; + uint32_t num = 0; + + num = size/4; + for (i = 0; i < num; i++) { + out32[i] = readl_relaxed(npu_dev->npu_base + src_off); + src_off += 4; + } + + if (size%4 != 0) { + out8 = (uint8_t *)((size_t)dst + (num*4)); + num = size%4; + for (i = 0; i < num; i++) { + out8[i] = readb_relaxed(npu_dev->npu_base + src_off); + src_off += 1; + } + } + return 0; +} + +void *npu_ipc_addr(void) +{ + return (void *)(IPC_MEM_OFFSET_FROM_SSTCM); +} + +/* ------------------------------------------------------------------------- + * Functions - Interrupt + * ------------------------------------------------------------------------- + */ +void npu_interrupt_ack(struct npu_device *npu_dev, uint32_t intr_num) +{ + /* Clear irq state */ + REGW(npu_dev, NPU_MASTERn_IPC_IRQ_OUT(0), 0x0); +} + +int32_t npu_interrupt_raise_m0(struct npu_device *npu_dev) +{ + int ret = 0; + + /* Bit 4 is setting IRQ_SOURCE_SELECT to local + * and we're triggering a pulse to NPU_MASTER0_IPC_IN_IRQ0 + */ + npu_reg_write(npu_dev, NPU_MASTERn_IPC_IRQ_IN_CTRL(0), 0x1 + << NPU_MASTER0_IPC_IRQ_IN_CTRL__IRQ_SOURCE_SELECT___S | 0x1); + + return ret; +} + +/* ------------------------------------------------------------------------- + * Functions - ION Memory + * ------------------------------------------------------------------------- + */ +static struct npu_ion_buf *npu_get_npu_ion_buffer(struct npu_device + *npu_dev) +{ + struct npu_ion_buf *ret_val = 0; + + ret_val = kmalloc(sizeof(struct npu_ion_buf), GFP_KERNEL); + if (ret_val) + list_add(&(ret_val->list), &(npu_dev->mapped_buffers.list)); + + return ret_val; +} + +static struct npu_ion_buf *npu_get_existing_ion_buffer(struct npu_device + *npu_dev, int buf_hdl) +{ + struct list_head *pos = 0; + struct npu_ion_buf *npu_ion_buf = 0; + + list_for_each(pos, &(npu_dev->mapped_buffers.list)) { + npu_ion_buf = list_entry(pos, struct npu_ion_buf, list); + if (npu_ion_buf->fd == buf_hdl) + return npu_ion_buf; + } + + return NULL; +} + +static struct npu_ion_buf *npu_clear_npu_ion_buffer(struct npu_device + *npu_dev, int buf_hdl, uint64_t addr) +{ + struct list_head *pos = 0; + struct npu_ion_buf *npu_ion_buf = 0; + + list_for_each(pos, &(npu_dev->mapped_buffers.list)) { + npu_ion_buf = list_entry(pos, struct npu_ion_buf, list); + if (npu_ion_buf->fd == buf_hdl && + npu_ion_buf->iova == addr) { + list_del(&npu_ion_buf->list); + return npu_ion_buf; + } + } + + return NULL; +} + +int npu_mem_map(struct npu_device *npu_dev, int buf_hdl, uint32_t size, + uint64_t *addr) +{ + int ret = 0; + + struct npu_ion_buf *ion_buf = npu_get_npu_ion_buffer(npu_dev); + struct npu_smmu_ctx *smmu_ctx = &npu_dev->smmu_ctx; + + if (!ion_buf) { + pr_err("%s no more table space\n", __func__); + ret = -ENOMEM; + return ret; + } + ion_buf->fd = buf_hdl; + ion_buf->size = size; + + if (ion_buf->fd == 0) + return -EINVAL; + + smmu_ctx->attach_cnt++; + + ion_buf->dma_buf = dma_buf_get(ion_buf->fd); + if (IS_ERR_OR_NULL(ion_buf->dma_buf)) { + pr_err("dma_buf_get failed %d\n", ion_buf->fd); + ret = -ENOMEM; + ion_buf->dma_buf = NULL; + goto map_end; + } + + ion_buf->attachment = dma_buf_attach(ion_buf->dma_buf, + &(npu_dev->pdev->dev)); + if (IS_ERR(ion_buf->attachment)) { + ret = -ENOMEM; + ion_buf->attachment = NULL; + goto map_end; + } + + ion_buf->attachment->dma_map_attrs = DMA_ATTR_IOMMU_USE_UPSTREAM_HINT; + + ion_buf->table = dma_buf_map_attachment(ion_buf->attachment, + DMA_BIDIRECTIONAL); + if (IS_ERR(ion_buf->table)) { + pr_err("npu dma_buf_map_attachment failed\n"); + ret = -ENOMEM; + ion_buf->table = NULL; + goto map_end; + } + + dma_sync_sg_for_device(&(npu_dev->pdev->dev), ion_buf->table->sgl, + ion_buf->table->nents, DMA_BIDIRECTIONAL); + ion_buf->iova = ion_buf->table->sgl->dma_address; + ion_buf->size = ion_buf->table->sgl->dma_length; +map_end: + if (ret) + npu_mem_unmap(npu_dev, buf_hdl, 0); + + *addr = ion_buf->iova; + return ret; +} + +void npu_mem_invalidate(struct npu_device *npu_dev, int buf_hdl) +{ + struct npu_ion_buf *ion_buf = npu_get_existing_ion_buffer(npu_dev, + buf_hdl); + + if (!ion_buf) + pr_err("%s cant find ion buf\n", __func__); + else + dma_sync_sg_for_cpu(&(npu_dev->pdev->dev), ion_buf->table->sgl, + ion_buf->table->nents, DMA_BIDIRECTIONAL); +} + +void npu_mem_unmap(struct npu_device *npu_dev, int buf_hdl, uint64_t addr) +{ + struct npu_ion_buf *ion_buf = 0; + + /* clear entry and retrieve the corresponding buffer */ + ion_buf = npu_clear_npu_ion_buffer(npu_dev, buf_hdl, addr); + + if (!ion_buf) { + pr_err("%s could not find buffer\n", __func__); + return; + } + if (ion_buf->table) + dma_buf_unmap_attachment(ion_buf->attachment, ion_buf->table, + DMA_BIDIRECTIONAL); + ion_buf->table = 0; + if (ion_buf->dma_buf && ion_buf->attachment) + dma_buf_detach(ion_buf->dma_buf, ion_buf->attachment); + ion_buf->attachment = 0; + if (ion_buf->dma_buf) + dma_buf_put(ion_buf->dma_buf); + ion_buf->dma_buf = 0; + npu_dev->smmu_ctx.attach_cnt--; + kfree(ion_buf); +} + +/* ------------------------------------------------------------------------- + * Functions - Work Queue + * ------------------------------------------------------------------------- + */ +void npu_destroy_wq(struct workqueue_struct *wq) +{ + destroy_workqueue(wq); +} + +struct workqueue_struct *npu_create_wq(struct npu_host_ctx *host_ctx, + const char *name, wq_hdlr_fn hdlr, struct work_struct *irq_work) +{ + struct workqueue_struct *wq = create_workqueue(name); + + INIT_WORK(irq_work, hdlr); + + return wq; +} + +/* ------------------------------------------------------------------------- + * Functions - Features + * ------------------------------------------------------------------------- + */ +uint8_t npu_hw_clk_gating_enabled(void) +{ + return 1; +} + +uint8_t npu_hw_log_enabled(void) +{ + return 0; +} + +/* ------------------------------------------------------------------------- + * Functions - Subsystem/PIL + * ------------------------------------------------------------------------- + */ +void *subsystem_get_local(char *sub_system) +{ + return subsystem_get(sub_system); +} + +void subsystem_put_local(void *sub_system_handle) +{ + return subsystem_put(sub_system_handle); +} + +/* ------------------------------------------------------------------------- + * Functions - Log + * ------------------------------------------------------------------------- + */ +void npu_process_log_message(struct npu_device *npu_dev, uint32_t *message, + uint32_t size) +{ + struct npu_debugfs_ctx *debugfs = &npu_dev->debugfs_ctx; + + /* mutex log lock */ + mutex_lock(&debugfs->log_lock); + + if ((debugfs->log_num_bytes_buffered + size) > + debugfs->log_buf_size) { + /* No more space, invalidate it all and start over */ + debugfs->log_read_index = 0; + debugfs->log_write_index = size; + debugfs->log_num_bytes_buffered = size; + memcpy(debugfs->log_buf, message, size); + } else { + if ((debugfs->log_write_index + size) > + debugfs->log_buf_size) { + /* Wrap around case */ + uint8_t *src_addr = (uint8_t *)message; + uint8_t *dst_addr = 0; + uint32_t remaining_to_end = debugfs->log_buf_size - + debugfs->log_write_index + 1; + dst_addr = debugfs->log_buf + debugfs->log_write_index; + memcpy(dst_addr, src_addr, remaining_to_end); + src_addr = &(src_addr[remaining_to_end]); + dst_addr = debugfs->log_buf; + memcpy(dst_addr, src_addr, size-remaining_to_end); + debugfs->log_write_index = size-remaining_to_end; + } else { + memcpy((debugfs->log_buf + debugfs->log_write_index), + message, size); + debugfs->log_write_index += size; + if (debugfs->log_write_index == debugfs->log_buf_size) + debugfs->log_write_index = 0; + } + debugfs->log_num_bytes_buffered += size; + } + + /* mutex log unlock */ + mutex_unlock(&debugfs->log_lock); +} diff --git a/drivers/media/platform/msm/npu/npu_hw_access.h b/drivers/media/platform/msm/npu/npu_hw_access.h new file mode 100644 index 000000000000..8f3eb332139a --- /dev/null +++ b/drivers/media/platform/msm/npu/npu_hw_access.h @@ -0,0 +1,88 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _NPU_HW_ACCESS_H +#define _NPU_HW_ACCESS_H + +/* ------------------------------------------------------------------------- + * Includes + * ------------------------------------------------------------------------- + */ +#include "npu_common.h" + +/* ------------------------------------------------------------------------- + * Defines + * ------------------------------------------------------------------------- + */ +#define IPC_MEM_OFFSET_FROM_SSTCM 0x00010000 +#define SYS_CACHE_SCID 23 + +#define REGW(npu_dev, off, val) npu_reg_write(npu_dev, off, val) +#define REGR(npu_dev, off) npu_reg_read(npu_dev, off) +#define MEMW(npu_dev, dst, src, size) npu_mem_write(npu_dev, (void *)(dst),\ + (void *)(src), size) +#define MEMR(npu_dev, src, dst, size) npu_mem_read(npu_dev, (void *)(src),\ + (void *)(dst), size) +#define IPC_ADDR npu_ipc_addr() +#define INTERRUPT_ACK(npu_dev, num) npu_interrupt_ack(npu_dev, num) +#define INTERRUPT_RAISE_NPU(npu_dev) npu_interrupt_raise_m0(npu_dev) + +/* ------------------------------------------------------------------------- + * Data Structures + * ------------------------------------------------------------------------- + */ +struct npu_device; +struct npu_ion_buf_t; +struct npu_host_ctx; +typedef irqreturn_t (*intr_hdlr_fn)(int32_t irq, void *ptr); +typedef void (*wq_hdlr_fn) (struct work_struct *work); + +/* ------------------------------------------------------------------------- + * Function Prototypes + * ------------------------------------------------------------------------- + */ +uint32_t npu_reg_read(struct npu_device *npu_dev, uint32_t off); +void npu_reg_write(struct npu_device *npu_dev, uint32_t off, uint32_t val); +void npu_mem_write(struct npu_device *npu_dev, void *dst, void *src, + uint32_t size); +int32_t npu_mem_read(struct npu_device *npu_dev, void *src, void *dst, + uint32_t size); + +int npu_mem_map(struct npu_device *npu_dev, int buf_hdl, uint32_t size, + uint64_t *addr); +void npu_mem_unmap(struct npu_device *npu_dev, int buf_hdl, uint64_t addr); +void npu_mem_invalidate(struct npu_device *npu_dev, int buf_hdl); + +void *npu_ipc_addr(void); +void npu_interrupt_ack(struct npu_device *npu_dev, uint32_t intr_num); +int32_t npu_interrupt_raise_m0(struct npu_device *npu_dev); + +struct workqueue_struct *npu_create_wq(struct npu_host_ctx *host_ctx, + const char *name, wq_hdlr_fn hdlr, struct work_struct *irq_work); +void npu_destroy_wq(struct workqueue_struct *wq); + +uint8_t npu_hw_clk_gating_enabled(void); +uint8_t npu_hw_log_enabled(void); + +int npu_enable_irq(struct npu_device *npu_dev); +void npu_disable_irq(struct npu_device *npu_dev); + +int npu_enable_sys_cache(struct npu_device *npu_dev); +void npu_disable_sys_cache(struct npu_device *npu_dev); + +void *subsystem_get_local(char *sub_system); +void subsystem_put_local(void *sub_system_handle); + +void npu_process_log_message(struct npu_device *npu_dev, uint32_t *msg, + uint32_t size); + +#endif /* _NPU_HW_ACCESS_H*/ diff --git a/drivers/media/platform/msm/npu/npu_mgr.c b/drivers/media/platform/msm/npu/npu_mgr.c new file mode 100644 index 000000000000..ecd742450090 --- /dev/null +++ b/drivers/media/platform/msm/npu/npu_mgr.c @@ -0,0 +1,629 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +/* ------------------------------------------------------------------------- + * Includes + * ------------------------------------------------------------------------- + */ +#include "npu_hw_access.h" +#include "npu_mgr.h" +#include "npu_firmware.h" +#include "npu_hw.h" +#include "npu_host_ipc.h" +#include "npu_common.h" + +/* ------------------------------------------------------------------------- + * Defines + * ------------------------------------------------------------------------- + */ +#define LOG_MSG_HEADER_SIZE 20 +#define LOG_MSG_START_MSG_INDEX 5 +#define LOG_MSG_TOTAL_SIZE_INDEX 0 +#define LOG_MSG_MSG_ID_INDEX 1 + +#define NPU_FW_TIMEOUT_POLL_INTERVAL_MS 20 +#define NPU_FW_TIMEOUT_MS 1000 + +/* ------------------------------------------------------------------------- + * File Scope Function Prototypes + * ------------------------------------------------------------------------- + */ +static void host_irq_wq(struct work_struct *work); +static void turn_off_fw_logging(struct npu_device *npu_dev); +static int wait_for_fw_ready(struct npu_device *npu_dev); +static struct npu_network *alloc_network(struct npu_host_ctx *ctx); +static struct npu_network *get_network(struct npu_host_ctx *ctx, int64_t id); +static void free_network(struct npu_host_ctx *ctx, int64_t id); +static void app_msg_proc(struct npu_host_ctx *host_ctx, uint32_t *msg); +static void log_msg_proc(struct npu_device *npu_dev, uint32_t *msg); +static void host_session_msg_hdlr(struct npu_device *npu_dev); +static void host_session_log_hdlr(struct npu_device *npu_dev); + +/* ------------------------------------------------------------------------- + * Function Definitions - Init / Deinit + * ------------------------------------------------------------------------- + */ +int fw_init(struct npu_device *npu_dev) +{ + uint32_t reg_val = 0; + struct npu_host_ctx *host_ctx = &npu_dev->host_ctx; + + if (host_ctx->fw_enabled) + return 0; + + if (npu_enable_core_power(npu_dev)) + return -EPERM; + + if (npu_enable_sys_cache(npu_dev)) + return -EPERM; + + /* Boot the NPU subsystem */ + host_ctx->subsystem_handle = subsystem_get_local("npu"); + + /* Clear control/status registers */ + REGW(npu_dev, REG_NPU_FW_CTRL_STATUS, 0x0); + REGW(npu_dev, REG_NPU_HOST_CTRL_STATUS, 0x0); + REGW(npu_dev, REG_NPU_HOST_CTRL_VALUE, 0x0); + REGW(npu_dev, REG_FW_TO_HOST_EVENT, 0x0); + + /* Post PIL clocks */ + if (npu_enable_post_pil_clocks(npu_dev)) + return -EPERM; + + /* + * Set logging state and clock gating state + * during FW bootup initialization + */ + reg_val = REGR(npu_dev, REG_NPU_HOST_CTRL_STATUS); + reg_val |= HOST_CTRL_STATUS_BOOT_ENABLE_LOGGING_VAL; + + /* Enable clock gating only if the HW access platform allows it */ + if (npu_hw_clk_gating_enabled()) + reg_val |= HOST_CTRL_STATUS_BOOT_ENABLE_CLK_GATE_VAL; + + REGW(npu_dev, REG_NPU_HOST_CTRL_STATUS, reg_val); + + /* Initialize the host side IPC */ + npu_host_ipc_pre_init(npu_dev); + + /* Keep reading ctrl status until NPU is ready */ + pr_debug("waiting for status ready from fw\n"); + + if (wait_for_fw_ready(npu_dev)) + return -EPERM; + + host_ctx->fw_enabled = 1; + + npu_host_ipc_post_init(npu_dev); + + if (npu_enable_irq(npu_dev)) + return -EPERM; + + /* Set logging state */ + if (!npu_hw_log_enabled()) { + pr_debug("fw logging disabled\n"); + turn_off_fw_logging(npu_dev); + } + + pr_debug("firmware init complete\n"); + return 0; +} + +void fw_deinit(struct npu_device *npu_dev) +{ + struct npu_host_ctx *host_ctx = &npu_dev->host_ctx; + struct ipc_cmd_shutdown_pkt cmd_shutdown_pkt; + int ret = 0; + + if (!host_ctx->fw_enabled) + return; + + /* Command header */ + cmd_shutdown_pkt.header.cmd_type = NPU_IPC_CMD_SHUTDOWN; + cmd_shutdown_pkt.header.size = sizeof(struct ipc_cmd_shutdown_pkt); + cmd_shutdown_pkt.header.trans_id = 1; + cmd_shutdown_pkt.header.flags = 0xF; + ret = npu_host_ipc_send_cmd(npu_dev, IPC_QUEUE_CMD_HIGH_PRIORITY, + &cmd_shutdown_pkt); + + pr_debug("NPU_IPC_CMD_SHUTDOWN sent status: %d\n", ret); + + if (ret) + pr_err("npu_host_ipc_send_cmd failed\n"); + + npu_disable_irq(npu_dev); + npu_disable_sys_cache(npu_dev); + subsystem_put_local(host_ctx->subsystem_handle); + host_ctx->fw_enabled = 0; + npu_disable_core_power(npu_dev); + + pr_debug("firmware deinit complete\n"); +} + +int npu_host_init(struct npu_device *npu_dev) +{ + int sts = 0; + struct npu_host_ctx *host_ctx = &npu_dev->host_ctx; + + init_completion(&host_ctx->exec_done); + init_completion(&host_ctx->load_done); + init_completion(&host_ctx->unload_done); + + host_ctx->wq = npu_create_wq(host_ctx, "irq_hdl", host_irq_wq, + &host_ctx->irq_work); + if (!host_ctx->wq) + sts = -EPERM; + + return sts; +} + +void npu_host_deinit(struct npu_device *npu_dev) +{ + struct npu_host_ctx *host_ctx = &npu_dev->host_ctx; + + npu_destroy_wq(host_ctx->wq); +} + +/* ------------------------------------------------------------------------- + * Function Definitions - Interrupt Handler + * ------------------------------------------------------------------------- + */ +irqreturn_t npu_intr_hdler(int irq, void *ptr) +{ + /* Check the interrupt we received */ + /* Currently this is the IPC interrupt */ + struct npu_device *npu_dev = (struct npu_device *)ptr; + struct npu_host_ctx *host_ctx = &npu_dev->host_ctx; + + INTERRUPT_ACK(npu_dev, irq); + + /* Check that the event thread currently is running */ + if (host_ctx->wq != 0) + queue_work(host_ctx->wq, &host_ctx->irq_work); + + return IRQ_HANDLED; +} + +/* ------------------------------------------------------------------------- + * Function Definitions - Control + * ------------------------------------------------------------------------- + */ +static void host_irq_wq(struct work_struct *work) +{ + struct npu_host_ctx *host_ctx; + struct npu_device *npu_dev; + + host_ctx = container_of(work, struct npu_host_ctx, irq_work); + npu_dev = container_of(host_ctx, struct npu_device, host_ctx); + host_session_log_hdlr(npu_dev); + host_session_msg_hdlr(npu_dev); +} + +static void turn_off_fw_logging(struct npu_device *npu_dev) +{ + struct ipc_cmd_log_state_pkt log_packet; + int ret = 0; + + log_packet.header.cmd_type = NPU_IPC_CMD_CONFIG_LOG; + log_packet.header.size = sizeof(struct ipc_cmd_log_state_pkt); + log_packet.header.trans_id = 1; + log_packet.header.flags = 0xF; + log_packet.log_state.module_msk = 0; + log_packet.log_state.level_msk = 0; + ret = npu_host_ipc_send_cmd(npu_dev, IPC_QUEUE_CMD_HIGH_PRIORITY, + &log_packet); + + pr_debug("NPU_IPC_CMD_CONFIG_LOG sent status: %d\n", ret); + + if (ret) + pr_err("npu_host_ipc_send_cmd failed\n"); +} + +static int wait_for_fw_ready(struct npu_device *npu_dev) +{ + uint32_t ctrl_sts = 0; + uint32_t wait_cnt = 0; + + /* keep reading ctrl status until NPU is ready */ + while (!(ctrl_sts & FW_CTRL_STATUS_MAIN_THREAD_READY_VAL)) { + ctrl_sts = REGR(npu_dev, REG_NPU_FW_CTRL_STATUS); + msleep(NPU_FW_TIMEOUT_POLL_INTERVAL_MS); + wait_cnt += NPU_FW_TIMEOUT_POLL_INTERVAL_MS; + if (wait_cnt >= NPU_FW_TIMEOUT_MS) { + pr_err("timeout in %s\n", __func__); + return -EPERM; + } + } + pr_debug("status ready from fw received\n"); + return 0; +} + +/* ------------------------------------------------------------------------- + * Function Definitions - Network Management + * ------------------------------------------------------------------------- + */ +static struct npu_network *alloc_network(struct npu_host_ctx *ctx) +{ + int32_t i; + struct npu_network *network = ctx->networks; + + for (i = 0; i < MAX_LOADED_NETWORK; i++) { + if (network->id == 0) { + network->id = i + 1; + /* + * -IPC trans ID to start at 1 and increment + * by 1 for the next IPC cmd on the same network + */ + network->ipc_trans_id = 1; + break; + } + network++; + } + if (i >= MAX_LOADED_NETWORK) + return NULL; + ctx->network_num++; + return network; +} + +static struct npu_network *get_network(struct npu_host_ctx *ctx, int64_t id) +{ + if (id >= 1 && id <= MAX_LOADED_NETWORK) + return &ctx->networks[id - 1]; + pr_err("network id invalid %d\n", (int32_t)id); + return NULL; +} + +static void free_network(struct npu_host_ctx *ctx, int64_t id) +{ + struct npu_network *network = get_network(ctx, id); + + if (network) { + memset(network, 0, sizeof(struct npu_network)); + ctx->network_num--; + } +} + +/* ------------------------------------------------------------------------- + * Function Definitions - IPC + * ------------------------------------------------------------------------- + */ +static void app_msg_proc(struct npu_host_ctx *host_ctx, uint32_t *msg) +{ + uint32_t msg_id; + struct ipc_msg_header_pkt *resp_pkt; + struct ipc_msg_load_pkt *load_rsp_pkt; + struct ipc_msg_execute_pkt *exe_rsp_pkt; + + msg_id = msg[1]; + switch (msg_id) { + case NPU_IPC_MSG_EXECUTE_DONE: + exe_rsp_pkt = (struct ipc_msg_execute_pkt *)msg; + + pr_debug("NPU_IPC_MSG_EXECUTE_DONE status: %d\n", + exe_rsp_pkt->header.status); + pr_debug("trans_id : %d", exe_rsp_pkt->header.trans_id); + pr_debug("e2e_IPC_time: %d (in tick count)\n", + exe_rsp_pkt->stats.e2e_ipc_tick_count); + pr_debug("aco_load_time: %d (in tick count)\n", + exe_rsp_pkt->stats.aco_load_tick_count); + pr_debug("aco_execute_time: %d (in tick count)\n", + exe_rsp_pkt->stats.aco_execution_tick_count); + pr_debug("total_num_layers: %d\n", + exe_rsp_pkt->stats.exe_stats.total_num_layers); + complete_all(&host_ctx->exec_done); + break; + case NPU_IPC_MSG_LOAD_DONE: + { + struct npu_network *network = 0; + uint32_t network_id = 0; + + load_rsp_pkt = (struct ipc_msg_load_pkt *)msg; + pr_debug("NPU_IPC_MSG_LOAD_DONE status: %d, trans_id: %d\n", + load_rsp_pkt->header.status, + load_rsp_pkt->header.trans_id); + + /* + * store the returned aco_hdl generated by the firmware + * response header flags filed was TEMP used to store + * the network ID on the way back + */ + network_id = load_rsp_pkt->header.flags; + network = get_network(host_ctx, network_id); + if (!network) { + pr_err("can't find network %d\n", network_id); + break; + } + network->network_hdl = load_rsp_pkt->aco_hdl; + complete_all(&host_ctx->load_done); + break; + } + + case NPU_IPC_MSG_UNLOAD_DONE: + resp_pkt = (struct ipc_msg_header_pkt *)msg; + pr_debug("NPU_IPC_MSG_UNLOAD_DONE status: %d, trans_id: %d\n", + resp_pkt->status, resp_pkt->trans_id); + complete_all(&host_ctx->unload_done); + break; + default: + pr_err("Not supported apps response received %d\n", + msg_id); + break; + } +} + +static void host_session_msg_hdlr(struct npu_device *npu_dev) +{ + uint32_t *msg; + struct npu_host_ctx *host_ctx = &npu_dev->host_ctx; + + msg = kzalloc(sizeof(uint32_t) * NPU_IPC_BUF_LENGTH, GFP_KERNEL); + if (!msg) + return; + while (npu_host_ipc_read_msg(npu_dev, IPC_QUEUE_APPS_RSP, msg) == 0) { + pr_debug("received from msg queue\n"); + app_msg_proc(host_ctx, msg); + } + kfree(msg); +} + +static void log_msg_proc(struct npu_device *npu_dev, uint32_t *msg) +{ + uint32_t msg_id; + uint32_t *log_msg; + uint32_t size; + + msg_id = msg[LOG_MSG_MSG_ID_INDEX]; + size = msg[LOG_MSG_TOTAL_SIZE_INDEX] - LOG_MSG_HEADER_SIZE; + + switch (msg_id) { + case NPU_IPC_MSG_EVENT_NOTIFY: + /* Process the message */ + log_msg = &(msg[LOG_MSG_START_MSG_INDEX]); + npu_process_log_message(npu_dev, log_msg, size); + break; + default: + pr_err("unsupported log response received %d\n", msg_id); + break; + } +} + +static void host_session_log_hdlr(struct npu_device *npu_dev) +{ + uint32_t *msg; + + msg = kzalloc(sizeof(uint32_t) * NPU_IPC_BUF_LENGTH, GFP_KERNEL); + + if (!msg) + return; + while (npu_host_ipc_read_msg(npu_dev, IPC_QUEUE_LOG, msg) == 0) { + pr_debug("received from log queue\n"); + log_msg_proc(npu_dev, msg); + } + kfree(msg); +} + +/* ------------------------------------------------------------------------- + * Function Definitions - Functionality + * ------------------------------------------------------------------------- + */ +int32_t npu_host_get_info(struct npu_device *npu_dev, + struct msm_npu_get_info_ioctl *get_info_ioctl) +{ + get_info_ioctl->firmware_version = FIRMWARE_VERSION; + return 0; +} + +int32_t npu_host_map_buf(struct npu_device *npu_dev, + struct msm_npu_map_buf_ioctl *map_ioctl) +{ + npu_mem_map(npu_dev, map_ioctl->buf_ion_hdl, map_ioctl->size, + &map_ioctl->npu_phys_addr); + return 0; +} + +int32_t npu_host_unmap_buf(struct npu_device *npu_dev, + struct msm_npu_unmap_buf_ioctl *unmap_ioctl) +{ + npu_mem_unmap(npu_dev, unmap_ioctl->buf_ion_hdl, + unmap_ioctl->npu_phys_addr); + return 0; +} + +void host_copy_patch_data(struct npu_patch_tuple *param, uint32_t value, + struct msm_npu_layer *layer_info) +{ + param->value = value; + param->chunk_id = layer_info->patch_info.chunk_id; + param->loc_offset = layer_info->patch_info.loc_offset; + param->instruction_size_in_bytes = + layer_info->patch_info.instruction_size_in_bytes; + param->shift_value_in_bits = + layer_info->patch_info.shift_value_in_bits; + param->variable_size_in_bits = + layer_info->patch_info.variable_size_in_bits; +} + +int32_t npu_host_load_network(struct npu_device *npu_dev, + struct msm_npu_load_network_ioctl *load_ioctl) +{ + int ret = 0; + struct npu_network *network; + struct ipc_cmd_load_pkt load_packet; + struct npu_host_ctx *host_ctx = &npu_dev->host_ctx; + + ret = fw_init(npu_dev); + if (ret) + return ret; + + network = alloc_network(host_ctx); + if (!network) + return -ENOMEM; + + network->buf_hdl = load_ioctl->buf_ion_hdl; + network->size = load_ioctl->buf_size; + network->phy_add = load_ioctl->buf_phys_addr; + network->first_block_size = load_ioctl->first_block_size; + load_ioctl->network_hdl = network->id; + + load_packet.header.cmd_type = NPU_IPC_CMD_LOAD; + load_packet.header.size = sizeof(struct ipc_cmd_load_pkt); + load_packet.header.trans_id = network->ipc_trans_id++; + load_packet.header.flags = 0; + + /* ACO Buffer. Use the npu mapped aco address */ + load_packet.buf_pkt.address = (uint64_t)network->phy_add; + load_packet.buf_pkt.buf_size = network->first_block_size; + load_packet.buf_pkt.network_id = network->id; + + /* NPU_IPC_CMD_LOAD will go onto IPC_QUEUE_APPS_EXEC */ + reinit_completion(&host_ctx->load_done); + ret = npu_host_ipc_send_cmd(npu_dev, + IPC_QUEUE_APPS_EXEC, &load_packet); + + pr_debug("NPU_IPC_CMD_LOAD sent status: %d\n", ret); + + if (ret) + return -EIO; + + if (!wait_for_completion_interruptible_timeout( + &host_ctx->load_done, NW_LOAD_TIMEOUT)) { + pr_err_ratelimited("npu: NPU_IPC_CMD_LOAD time out\n"); + npu_dump_cal_state(npu_dev); + ret = -ETIMEDOUT; + } + + return ret; +} + +int32_t npu_host_unload_network(struct npu_device *npu_dev, + struct msm_npu_unload_network_ioctl *unload) +{ + int ret = 0; + struct ipc_cmd_unload_pkt unload_packet; + struct npu_network *network; + struct npu_host_ctx *host_ctx = &npu_dev->host_ctx; + + /* get the corresponding network for ipc trans id purpose */ + network = get_network(host_ctx, (int64_t)unload->network_hdl); + if (!network) + return -EINVAL; + + /* prepare IPC packet for UNLOAD */ + unload_packet.header.cmd_type = NPU_IPC_CMD_UNLOAD; + unload_packet.header.size = sizeof(struct ipc_cmd_unload_pkt); + unload_packet.header.trans_id = network->ipc_trans_id++; + unload_packet.header.flags = 0; + unload_packet.aco_hdl = (uint32_t)network->network_hdl; + + /* NPU_IPC_CMD_UNLOAD will go onto IPC_QUEUE_APPS_EXEC */ + reinit_completion(&host_ctx->unload_done); + ret = npu_host_ipc_send_cmd(npu_dev, IPC_QUEUE_APPS_EXEC, + &unload_packet); + + pr_debug("NPU_IPC_CMD_UNLOAD sent status: %d\n", ret); + + if (ret) + return -EIO; + + if (!wait_for_completion_interruptible_timeout(&host_ctx->unload_done, + NW_UNLOAD_TIMEOUT)) { + pr_err_ratelimited("npu: NPU_IPC_CMD_UNLOAD time out\n"); + ret = -ETIMEDOUT; + } else { + /* + * free the network on the kernel if the corresponding ACO + * handle is unloaded on the firmware side + */ + free_network(host_ctx, (int64_t)unload->network_hdl); + if (host_ctx->network_num <= 0) { + fw_deinit(npu_dev); + host_ctx->network_num = 0; + } + } + + return ret; +} + +int32_t npu_host_exec_network(struct npu_device *npu_dev, + struct msm_npu_exec_network_ioctl *exec_ioctl) +{ + struct ipc_cmd_execute_pkt exec_packet; + /* npu mapped addr */ + uint64_t input_addr = 0, output_addr = 0; + uint64_t input_off, output_off; + int32_t ret; + struct npu_network *network; + uint32_t timeout = NW_SMALL_EXEC_TIMEOUT; + struct npu_host_ctx *host_ctx = &npu_dev->host_ctx; + int i = 0; + + network = get_network(host_ctx, (int64_t)exec_ioctl->network_hdl); + + if (!network) + return -EINVAL; + + memset(&exec_packet, 0, sizeof(exec_packet)); + if (exec_ioctl->patching_required) { + if (exec_ioctl->input_layer_num == 1) + input_addr = exec_ioctl->input_layers[0].buf_phys_addr; + if (exec_ioctl->output_layer_num == 1) + output_addr = + exec_ioctl->output_layers[0].buf_phys_addr; + exec_packet.patch_params.num_params = 2; + input_off = (uint64_t)input_addr; + output_off = (uint64_t)output_addr; + host_copy_patch_data(&exec_packet.patch_params.param[0], + (uint32_t)input_off, &exec_ioctl->input_layers[0]); + host_copy_patch_data(&exec_packet.patch_params.param[1], + (uint32_t)output_off, &exec_ioctl->output_layers[0]); + } else { + exec_packet.patch_params.num_params = 0; + } + + exec_packet.header.cmd_type = NPU_IPC_CMD_EXECUTE; + exec_packet.header.size = sizeof(struct ipc_cmd_execute_pkt); + exec_packet.header.trans_id = network->ipc_trans_id++; + exec_packet.header.flags = 0xF; + exec_packet.aco_hdl = network->network_hdl; + + /* Send it on the high priority queue */ + reinit_completion(&host_ctx->exec_done); + ret = npu_host_ipc_send_cmd(npu_dev, IPC_QUEUE_APPS_EXEC, &exec_packet); + + pr_debug("NPU_IPC_CMD_EXECUTE sent status: %d\n", ret); + + /* + * If this is a large network set the excecution timeout accordingly + */ + if (network->size > LARGE_NETWORK_SIZE_THRESHOLD) + timeout = NW_LARGE_EXEC_TIMEOUT; + + if (!wait_for_completion_interruptible_timeout( + &host_ctx->exec_done, timeout)) { + pr_err_ratelimited("npu: NPU_IPC_CMD_EXECUTE time out\n"); + /* dump debug stats */ + npu_dump_debug_timeout_stats(npu_dev); + ret = -ETIMEDOUT; + } + + /* Invalidate output buffers */ + for (i = 0; i < exec_ioctl->output_layer_num; i++) { + if (exec_ioctl->output_layer_num == 1) { + npu_mem_invalidate(npu_dev, + exec_ioctl->output_layers[i].buf_hdl); + } + } + + return ret; +} diff --git a/drivers/media/platform/msm/npu/npu_mgr.h b/drivers/media/platform/msm/npu/npu_mgr.h new file mode 100644 index 000000000000..035ac7c47f2d --- /dev/null +++ b/drivers/media/platform/msm/npu/npu_mgr.h @@ -0,0 +1,101 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _NPU_MGR_H +#define _NPU_MGR_H + +/* ------------------------------------------------------------------------- + * Includes + * ------------------------------------------------------------------------- + */ +#include "npu_hw_access.h" + +/* ------------------------------------------------------------------------- + * Defines + * ------------------------------------------------------------------------- + */ +#define NW_SMALL_EXEC_TIMEOUT_MS (1000*300) /* set for 5 min */ +#define NW_SMALL_EXEC_TIMEOUT msecs_to_jiffies(NW_SMALL_EXEC_TIMEOUT_MS) +#define NW_LARGE_EXEC_TIMEOUT_MS (1000*300*12) /* set for 60 min */ +#define NW_LARGE_EXEC_TIMEOUT msecs_to_jiffies(NW_LARGE_EXEC_TIMEOUT_MS) +#define NW_LOAD_TIMEOUT_MS (1000*300) /* set for 5 min */ +#define NW_LOAD_TIMEOUT msecs_to_jiffies(NW_LOAD_TIMEOUT_MS) +#define NW_UNLOAD_TIMEOUT_MS (1000*300) /* set for 5 min */ +#define NW_UNLOAD_TIMEOUT msecs_to_jiffies(NW_UNLOAD_TIMEOUT_MS) +#define FIRMWARE_VERSION 0x00001000 +#define MAX_LOADED_NETWORK 32 +#define LARGE_NETWORK_SIZE_THRESHOLD (5*1024) /* 5 KB */ +#define NPU_IPC_BUF_LENGTH 512 + +/* ------------------------------------------------------------------------- + * Data Structures + * ------------------------------------------------------------------------- + */ +struct npu_network { + uint64_t id; + int buf_hdl; + uint64_t phy_add; + uint32_t size; + uint32_t first_block_size; + uint32_t network_hdl; + uint32_t ipc_trans_id; +}; + +struct npu_host_ctx { + void *subsystem_handle; + bool fw_enabled; + bool power_enabled; + int32_t power_vote_num; + struct work_struct irq_work; + struct workqueue_struct *wq; + struct completion exec_done; + struct completion load_done; + struct completion unload_done; + int32_t network_num; + struct npu_network networks[MAX_LOADED_NETWORK]; +}; + +struct npu_device; + +/* ------------------------------------------------------------------------- + * Function Prototypes + * ------------------------------------------------------------------------- + */ +int npu_host_init(struct npu_device *npu_dev); +void npu_host_deinit(struct npu_device *npu_dev); + +/* Host Driver IPC Interface */ +int npu_host_ipc_pre_init(struct npu_device *npu_dev); +int npu_host_ipc_post_init(struct npu_device *npu_dev); +void npu_host_ipc_deinit(struct npu_device *npu_dev); +int npu_host_ipc_send_cmd(struct npu_device *npu_dev, uint32_t queueIndex, + void *pCmd); +int npu_host_ipc_read_msg(struct npu_device *npu_dev, uint32_t queueIndex, + uint32_t *pMsg); + +int32_t npu_host_get_info(struct npu_device *npu_dev, + struct msm_npu_get_info_ioctl *get_info_ioctl); +int32_t npu_host_map_buf(struct npu_device *npu_dev, + struct msm_npu_map_buf_ioctl *map_ioctl); +int32_t npu_host_unmap_buf(struct npu_device *npu_dev, + struct msm_npu_unmap_buf_ioctl *unmap_ioctl); +int32_t npu_host_load_network(struct npu_device *npu_dev, + struct msm_npu_load_network_ioctl *load_ioctl); +int32_t npu_host_unload_network(struct npu_device *npu_dev, + struct msm_npu_unload_network_ioctl *unload); +int32_t npu_host_exec_network(struct npu_device *npu_dev, + struct msm_npu_exec_network_ioctl *exec_ioctl); + +void npu_dump_debug_timeout_stats(struct npu_device *npu_dev); +void npu_dump_cal_state(struct npu_device *npu_dev); + +#endif /* _NPU_MGR_H */ diff --git a/include/uapi/linux/msm_npu.h b/include/uapi/linux/msm_npu.h index 86707eec3e1e..0ddc1ccfbd72 100644 --- a/include/uapi/linux/msm_npu.h +++ b/include/uapi/linux/msm_npu.h @@ -1,125 +1,143 @@ #ifndef _UAPI_MSM_NPU_H_ #define _UAPI_MSM_NPU_H_ +/* ------------------------------------------------------------------------- + * Includes + * ------------------------------------------------------------------------- + */ +#include + +/* ------------------------------------------------------------------------- + * Defines + * ------------------------------------------------------------------------- + */ #define MSM_NPU_IOCTL_MAGIC 'n' /* get npu info */ #define MSM_NPU_GET_INFO \ - _IOWR(MSM_NPU_IOCTL_MAGIC, 1, struct msm_npu_get_info_ioctl_t *) + _IOWR(MSM_NPU_IOCTL_MAGIC, 1, struct msm_npu_get_info_ioctl) /* map buf */ #define MSM_NPU_MAP_BUF \ - _IOWR(MSM_NPU_IOCTL_MAGIC, 2, struct msm_npu_map_buf_ioctl_t *) + _IOWR(MSM_NPU_IOCTL_MAGIC, 2, struct msm_npu_map_buf_ioctl) /* map buf */ #define MSM_NPU_UNMAP_BUF \ - _IOWR(MSM_NPU_IOCTL_MAGIC, 3, struct msm_npu_unmap_buf_ioctl_t *) + _IOWR(MSM_NPU_IOCTL_MAGIC, 3, struct msm_npu_unmap_buf_ioctl) /* load network */ #define MSM_NPU_LOAD_NETWORK \ - _IOWR(MSM_NPU_IOCTL_MAGIC, 4, struct msm_npu_load_network_ioctl_t *) + _IOWR(MSM_NPU_IOCTL_MAGIC, 4, struct msm_npu_load_network_ioctl) /* unload network */ #define MSM_NPU_UNLOAD_NETWORK \ - _IOWR(MSM_NPU_IOCTL_MAGIC, 5, struct msm_npu_unload_network_ioctl_t *) + _IOWR(MSM_NPU_IOCTL_MAGIC, 5, struct msm_npu_unload_network_ioctl) /* exec network */ #define MSM_NPU_EXEC_NETWORK \ - _IOWR(MSM_NPU_IOCTL_MAGIC, 6, struct msm_npu_exec_network_ioctl_t *) - -struct msm_npu_map_buf_ioctl_t { - /* buffer ion handle */ - void *buf_ion_hdl; - /* buffer size */ - uint32_t size; - /* iommu mapped physical address */ - void *npu_phys_addr; -}; + _IOWR(MSM_NPU_IOCTL_MAGIC, 6, struct msm_npu_exec_network_ioctl) #define MSM_NPU_MAX_INPUT_LAYER_NUM 8 #define MSM_NPU_MAX_OUTPUT_LAYER_NUM 4 -#define MSM_NPU_LAYER_NAME_SIZE 64 - -struct msm_npu_unmap_buf_ioctl_t { - /* buffer ion handle */ - void *buf_ion_hdl; - /* iommu mapped physical address */ - void *npu_phys_addr; -}; +/* ------------------------------------------------------------------------- + * Data Structures + * ------------------------------------------------------------------------- + */ struct msm_npu_patch_info { /* chunk id */ - uint32_t chunk_id; + uint32_t chunk_id; /* instruction size in bytes */ - uint16_t instruction_size_in_bytes; + uint16_t instruction_size_in_bytes; /* variable size in bits */ - uint16_t variable_size_in_bits; + uint16_t variable_size_in_bits; /* shift value in bits */ - uint16_t shift_value_in_bits; + uint16_t shift_value_in_bits; /* location offset */ - uint32_t loc_offset; + uint32_t loc_offset; }; -struct msm_npu_layer_t { +struct msm_npu_layer { /* layer id */ - uint32_t layer_id; + uint32_t layer_id; /* patch information*/ struct msm_npu_patch_info patch_info; /* buffer handle */ - void *buf_hdl; + int32_t buf_hdl; /* buffer size */ - uint32_t buf_size; + uint32_t buf_size; + /* physical address */ + uint64_t buf_phys_addr; }; +/* ------------------------------------------------------------------------- + * Data Structures - IOCTLs + * ------------------------------------------------------------------------- + */ +struct msm_npu_map_buf_ioctl { + /* buffer ion handle */ + int32_t buf_ion_hdl; + /* buffer size */ + uint32_t size; + /* iommu mapped physical address */ + uint64_t npu_phys_addr; +}; + +struct msm_npu_unmap_buf_ioctl { + /* buffer ion handle */ + int32_t buf_ion_hdl; + /* iommu mapped physical address */ + uint64_t npu_phys_addr; +}; -struct msm_npu_get_info_ioctl_t { +struct msm_npu_get_info_ioctl { /* firmware version */ - uint32_t firmware_version; + uint32_t firmware_version; /* reserved */ - uint32_t flags; + uint32_t flags; }; -struct msm_npu_load_network_ioctl_t { +struct msm_npu_load_network_ioctl { /* buffer ion handle */ - void *buf_ion_hdl; + int32_t buf_ion_hdl; /* physical address */ - void *buf_phys_addr; + uint64_t buf_phys_addr; /* buffer size */ - uint32_t buf_size; + uint32_t buf_size; /* first block size */ - uint32_t first_block_size; + uint32_t first_block_size; /* reserved */ - uint32_t flags; + uint32_t flags; /* network handle */ - void *network_hdl; - /* aco buffer handle */ - void *aco_hdl; + uint32_t network_hdl; + /* priority */ + uint32_t priority; + /* perf mode */ + uint32_t perf_mode; }; -struct msm_npu_unload_network_ioctl_t { +struct msm_npu_unload_network_ioctl { /* network handle */ - void *network_hdl; - /* aco buffer handle */ - void *aco_hdl; + uint32_t network_hdl; }; -struct msm_npu_exec_network_ioctl_t { +struct msm_npu_exec_network_ioctl { /* network handle */ - void *network_hdl; + uint32_t network_hdl; /* input layer number */ - uint32_t input_layer_num; + uint32_t input_layer_num; /* input layer info */ - struct msm_npu_layer_t input_layers[MSM_NPU_MAX_INPUT_LAYER_NUM]; + struct msm_npu_layer input_layers[MSM_NPU_MAX_INPUT_LAYER_NUM]; /* output layer number */ - uint32_t output_layer_num; + uint32_t output_layer_num; /* output layer info */ - struct msm_npu_layer_t output_layers[MSM_NPU_MAX_OUTPUT_LAYER_NUM]; + struct msm_npu_layer output_layers[MSM_NPU_MAX_OUTPUT_LAYER_NUM]; /* patching is required */ - int32_t patching_required; + uint32_t patching_required; /* asynchronous execution */ - int32_t async; + uint32_t async; /* reserved */ - uint32_t flags; + uint32_t flags; }; #endif /*_UAPI_MSM_NPU_H_*/ -- GitLab From 2db5a3d9e74acb75cfe1ab85d3e1a21ed9fa0fcc Mon Sep 17 00:00:00 2001 From: Farrukh Qurashi Date: Wed, 11 Apr 2018 13:14:16 -0400 Subject: [PATCH 0398/1635] ARM: dts: msm: Add NPU device configuration on SM8150 Add interrupt, MMU, system cache, clocks and power level device node configurations required by latest NPU driver. The NPU driver uses these nodes for integrating with other various subsystems. Change-Id: If05b547b26ebbe1efe9d0d259f7750a520f7349e Signed-off-by: Farrukh Qurashi --- arch/arm64/boot/dts/qcom/sm8150-npu.dtsi | 197 +++++++++++++++++++++-- 1 file changed, 186 insertions(+), 11 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sm8150-npu.dtsi b/arch/arm64/boot/dts/qcom/sm8150-npu.dtsi index a40378cd0569..9dc312e994e4 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-npu.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-npu.dtsi @@ -6,28 +6,203 @@ * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ &soc { - msm_npu: qcom,msm_npu { + msm_npu: qcom,msm_npu@9800000 { compatible = "qcom,msm-npu"; status = "ok"; reg = <0x9800000 0x800000>; reg-names = "npu_base"; - interrupts = <0 346 0>; - clocks = <&clock_npucc NPU_CC_XO_CLK>, - <&clock_npucc NPU_CC_NPU_CORE_CLK>, - <&clock_npucc NPU_CC_CAL_DP_CLK>, - <&clock_npucc NPU_CC_ARMWIC_CORE_CLK>, - <&clock_npucc NPU_CC_COMP_NOC_AXI_CLK>, - <&clock_npucc NPU_CC_CONF_NOC_AHB_CLK>; - clock-names = "xo", "core", "cal_dp", "armwic", - "axi", "ahb"; + interrupts = ; + iommus = <&apps_smmu 0x1461 0x0>, <&apps_smmu 0x2061 0x0>; + cache-slice-names = "npu"; + cache-slices = <&llcc 23>; + clocks = <&clock_npucc NPU_CC_CAL_DP_CLK>, + <&clock_npucc NPU_CC_CAL_DP_CLK_SRC>, + <&clock_npucc NPU_CC_XO_CLK>, + <&clock_npucc NPU_CC_ARMWIC_CORE_CLK>, + <&clock_npucc NPU_CC_BTO_CORE_CLK>, + <&clock_npucc NPU_CC_BWMON_CLK>, + <&clock_npucc NPU_CC_CAL_DP_CDC_CLK>, + <&clock_npucc NPU_CC_COMP_NOC_AXI_CLK>, + <&clock_npucc NPU_CC_CONF_NOC_AHB_CLK>, + <&clock_npucc NPU_CC_NPU_CORE_APB_CLK>, + <&clock_npucc NPU_CC_NPU_CORE_ATB_CLK>, + <&clock_npucc NPU_CC_NPU_CORE_CLK>, + <&clock_npucc NPU_CC_NPU_CORE_CLK_SRC>, + <&clock_npucc NPU_CC_NPU_CORE_CTI_CLK>, + <&clock_npucc NPU_CC_NPU_CPC_CLK>, + <&clock_npucc NPU_CC_NPU_CPC_TIMER_CLK>, + <&clock_npucc NPU_CC_PERF_CNT_CLK>, + <&clock_npucc NPU_CC_QTIMER_CORE_CLK>, + <&clock_npucc NPU_CC_SLEEP_CLK>; + clock-names = "cal_dp_clk", + "cal_dp_clk_src", + "xo_clk", + "armwic_core_clk", + "bto_core_clk", + "bwmon_clk", + "cal_dp_cdc_clk", + "comp_noc_axi_clk", + "conf_noc_ahb_clk", + "npu_core_apb_clk", + "npu_core_atb_clk", + "npu_core_clk", + "npu_core_clk_src", + "npu_core_cti_clk", + "npu_cpc_clk", + "npu_cpc_timer_clk", + "perf_cnt_clk", + "qtimer_core_clk", + "sleep_clk"; vdd-supply = <&npu_core_gdsc>; vdd_cx-supply = <&VDD_CX_LEVEL>; qcom,proxy-reg-names ="vdd", "vdd_cx"; qcom,vdd_cx-uV-uA = ; + mboxes = <&qmp_npu0 0>, <&qmp_npu1 0>; + mbox-names = "npu_low", "npu_high"; + #cooling-cells = <2>; + qcom,npubw-dev = <&npu_npu_ddr_bw>; + qcom,npu-pwrlevels { + #address-cells = <1>; + #size-cells = <0>; + compatible = "qcom,npu-pwrlevels"; + initial-pwrlevel = <4>; + qcom,npu-pwrlevel@0 { + reg = <0>; + clk-freq = <9600000 + 9600000 + 19200000 + 19200000 + 19200000 + 19200000 + 9600000 + 60000000 + 19200000 + 19200000 + 30000000 + 19200000 + 19200000 + 19200000 + 19200000 + 19200000 + 9600000 + 19200000 + 0>; + }; + qcom,npu-pwrlevel@1 { + reg = <1>; + clk-freq = <300000000 + 300000000 + 19200000 + 100000000 + 19200000 + 19200000 + 300000000 + 150000000 + 19200000 + 19200000 + 60000000 + 100000000 + 100000000 + 37500000 + 100000000 + 19200000 + 300000000 + 19200000 + 0>; + }; + qcom,npu-pwrlevel@2 { + reg = <2>; + clk-freq = <350000000 + 350000000 + 19200000 + 150000000 + 19200000 + 19200000 + 350000000 + 200000000 + 37500000 + 19200000 + 120000000 + 150000000 + 150000000 + 75000000 + 150000000 + 19200000 + 350000000 + 19200000 + 0>; + }; + qcom,npu-pwrlevel@3 { + reg = <3>; + clk-freq = <400000000 + 400000000 + 19200000 + 200000000 + 19200000 + 19200000 + 400000000 + 300000000 + 37500000 + 19200000 + 120000000 + 200000000 + 200000000 + 75000000 + 200000000 + 19200000 + 400000000 + 19200000 + 0>; + }; + qcom,npu-pwrlevel@4 { + reg = <4>; + clk-freq = <600000000 + 600000000 + 19200000 + 300000000 + 19200000 + 19200000 + 600000000 + 403000000 + 75000000 + 19200000 + 240000000 + 300000000 + 300000000 + 150000000 + 300000000 + 19200000 + 600000000 + 19200000 + 0>; + }; + qcom,npu-pwrlevel@5 { + reg = <5>; + clk-freq = <715000000 + 715000000 + 19200000 + 350000000 + 19200000 + 19200000 + 715000000 + 533000000 + 75000000 + 19200000 + 240000000 + 350000000 + 350000000 + 150000000 + 350000000 + 19200000 + 715000000 + 19200000 + 0>; + }; + }; }; }; -- GitLab From f75c433a336d63e32f030ebe8b147bfc8cf942ea Mon Sep 17 00:00:00 2001 From: Greg Hartman Date: Thu, 5 Apr 2018 17:59:11 -0700 Subject: [PATCH 0399/1635] FROMLIST: staging: Android: Add 'vsoc' driver for cuttlefish. The cuttlefish system is a virtual SoC architecture based on QEMU. It uses the QEMU ivshmem feature to share memory regions between guest and host with a custom protocol. Signed-off-by: Greg Hartman [sent upstream via staging https://patchwork.kernel.org/patch/10339507/] Change-Id: Iaf5d7536898329a66d00764d8892d1395164519e Signed-off-by: Alistair Strachan --- drivers/staging/android/Kconfig | 9 + drivers/staging/android/Makefile | 1 + drivers/staging/android/TODO | 10 + drivers/staging/android/uapi/vsoc_shm.h | 303 ++++++ drivers/staging/android/vsoc.c | 1169 +++++++++++++++++++++++ 5 files changed, 1492 insertions(+) create mode 100644 drivers/staging/android/uapi/vsoc_shm.h create mode 100644 drivers/staging/android/vsoc.c diff --git a/drivers/staging/android/Kconfig b/drivers/staging/android/Kconfig index 0a28c7616d53..4630dc85634e 100644 --- a/drivers/staging/android/Kconfig +++ b/drivers/staging/android/Kconfig @@ -14,6 +14,15 @@ config ASHMEM It is, in theory, a good memory allocator for low-memory devices, because it can discard shared memory units when under memory pressure. +config ANDROID_VSOC + tristate "Android Virtual SoC support" + default n + depends on PCI_MSI + ---help--- + This option adds support for the Virtual SoC driver needed to boot + a 'cuttlefish' Android image inside QEmu. The driver interacts with + a QEmu ivshmem device. If built as a module, it will be called vsoc. + source "drivers/staging/android/ion/Kconfig" source "drivers/staging/android/fiq_debugger/Kconfig" diff --git a/drivers/staging/android/Makefile b/drivers/staging/android/Makefile index 9b9b297d7c0e..2638b4a23df4 100644 --- a/drivers/staging/android/Makefile +++ b/drivers/staging/android/Makefile @@ -4,3 +4,4 @@ obj-y += ion/ obj-$(CONFIG_FIQ_DEBUGGER) += fiq_debugger/ obj-$(CONFIG_ASHMEM) += ashmem.o +obj-$(CONFIG_ANDROID_VSOC) += vsoc.o diff --git a/drivers/staging/android/TODO b/drivers/staging/android/TODO index 5f14247392bf..2ea6f97b8f0f 100644 --- a/drivers/staging/android/TODO +++ b/drivers/staging/android/TODO @@ -12,5 +12,15 @@ ion/ - Split /dev/ion up into multiple nodes (e.g. /dev/ion/heap0) - Better test framework (integration with VGEM was suggested) +vsoc.c, uapi/vsoc_shm.h + - The current driver uses the same wait queue for all of the futexes in a + region. This will cause false wakeups in regions with a large number of + waiting threads. We should eventually use multiple queues and select the + queue based on the region. + - Add debugfs support for examining the permissions of regions. + - Use ioremap_wc instead of ioremap_nocache. + - Remove VSOC_WAIT_FOR_INCOMING_INTERRUPT ioctl. This functionality has been + superseded by the futex and is there for legacy reasons. + Please send patches to Greg Kroah-Hartman and Cc: Arve Hjønnevåg and Riley Andrews diff --git a/drivers/staging/android/uapi/vsoc_shm.h b/drivers/staging/android/uapi/vsoc_shm.h new file mode 100644 index 000000000000..741b1387c25b --- /dev/null +++ b/drivers/staging/android/uapi/vsoc_shm.h @@ -0,0 +1,303 @@ +/* + * Copyright (C) 2017 Google, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef _UAPI_LINUX_VSOC_SHM_H +#define _UAPI_LINUX_VSOC_SHM_H + +#include + +/** + * A permission is a token that permits a receiver to read and/or write an area + * of memory within a Vsoc region. + * + * An fd_scoped permission grants both read and write access, and can be + * attached to a file description (see open(2)). + * Ownership of the area can then be shared by passing a file descriptor + * among processes. + * + * begin_offset and end_offset define the area of memory that is controlled by + * the permission. owner_offset points to a word, also in shared memory, that + * controls ownership of the area. + * + * ownership of the region expires when the associated file description is + * released. + * + * At most one permission can be attached to each file description. + * + * This is useful when implementing HALs like gralloc that scope and pass + * ownership of shared resources via file descriptors. + * + * The caller is responsibe for doing any fencing. + * + * The calling process will normally identify a currently free area of + * memory. It will construct a proposed fd_scoped_permission_arg structure: + * + * begin_offset and end_offset describe the area being claimed + * + * owner_offset points to the location in shared memory that indicates the + * owner of the area. + * + * owned_value is the value that will be stored in owner_offset iff the + * permission can be granted. It must be different than VSOC_REGION_FREE. + * + * Two fd_scoped_permission structures are compatible if they vary only by + * their owned_value fields. + * + * The driver ensures that, for any group of simultaneous callers proposing + * compatible fd_scoped_permissions, it will accept exactly one of the + * propopsals. The other callers will get a failure with errno of EAGAIN. + * + * A process receiving a file descriptor can identify the region being + * granted using the VSOC_GET_FD_SCOPED_PERMISSION ioctl. + */ +struct fd_scoped_permission { + __u32 begin_offset; + __u32 end_offset; + __u32 owner_offset; + __u32 owned_value; +}; + +/* + * This value represents a free area of memory. The driver expects to see this + * value at owner_offset when creating a permission otherwise it will not do it, + * and will write this value back once the permission is no longer needed. + */ +#define VSOC_REGION_FREE ((__u32)0) + +/** + * ioctl argument for VSOC_CREATE_FD_SCOPE_PERMISSION + */ +struct fd_scoped_permission_arg { + struct fd_scoped_permission perm; + __s32 managed_region_fd; +}; + +#define VSOC_NODE_FREE ((__u32)0) + +/* + * Describes a signal table in shared memory. Each non-zero entry in the + * table indicates that the receiver should signal the futex at the given + * offset. Offsets are relative to the region, not the shared memory window. + * + * interrupt_signalled_offset is used to reliably signal interrupts across the + * vmm boundary. There are two roles: transmitter and receiver. For example, + * in the host_to_guest_signal_table the host is the transmitter and the + * guest is the receiver. The protocol is as follows: + * + * 1. The transmitter should convert the offset of the futex to an offset + * in the signal table [0, (1 << num_nodes_lg2)) + * The transmitter can choose any appropriate hashing algorithm, including + * hash = futex_offset & ((1 << num_nodes_lg2) - 1) + * + * 3. The transmitter should atomically compare and swap futex_offset with 0 + * at hash. There are 3 possible outcomes + * a. The swap fails because the futex_offset is already in the table. + * The transmitter should stop. + * b. Some other offset is in the table. This is a hash collision. The + * transmitter should move to another table slot and try again. One + * possible algorithm: + * hash = (hash + 1) & ((1 << num_nodes_lg2) - 1) + * c. The swap worked. Continue below. + * + * 3. The transmitter atomically swaps 1 with the value at the + * interrupt_signalled_offset. There are two outcomes: + * a. The prior value was 1. In this case an interrupt has already been + * posted. The transmitter is done. + * b. The prior value was 0, indicating that the receiver may be sleeping. + * The transmitter will issue an interrupt. + * + * 4. On waking the receiver immediately exchanges a 0 with the + * interrupt_signalled_offset. If it receives a 0 then this a spurious + * interrupt. That may occasionally happen in the current protocol, but + * should be rare. + * + * 5. The receiver scans the signal table by atomicaly exchanging 0 at each + * location. If a non-zero offset is returned from the exchange the + * receiver wakes all sleepers at the given offset: + * futex((int*)(region_base + old_value), FUTEX_WAKE, MAX_INT); + * + * 6. The receiver thread then does a conditional wait, waking immediately + * if the value at interrupt_signalled_offset is non-zero. This catches cases + * here additional signals were posted while the table was being scanned. + * On the guest the wait is handled via the VSOC_WAIT_FOR_INCOMING_INTERRUPT + * ioctl. + */ +struct vsoc_signal_table_layout { + /* log_2(Number of signal table entries) */ + __u32 num_nodes_lg2; + /* + * Offset to the first signal table entry relative to the start of the + * region + */ + __u32 futex_uaddr_table_offset; + /* + * Offset to an atomic_t / atomic uint32_t. A non-zero value indicates + * that one or more offsets are currently posted in the table. + * semi-unique access to an entry in the table + */ + __u32 interrupt_signalled_offset; +}; + +#define VSOC_REGION_WHOLE ((__s32)0) +#define VSOC_DEVICE_NAME_SZ 16 + +/** + * Each HAL would (usually) talk to a single device region + * Mulitple entities care about these regions: + * - The ivshmem_server will populate the regions in shared memory + * - The guest kernel will read the region, create minor device nodes, and + * allow interested parties to register for FUTEX_WAKE events in the region + * - HALs will access via the minor device nodes published by the guest kernel + * - Host side processes will access the region via the ivshmem_server: + * 1. Pass name to ivshmem_server at a UNIX socket + * 2. ivshmemserver will reply with 2 fds: + * - host->guest doorbell fd + * - guest->host doorbell fd + * - fd for the shared memory region + * - region offset + * 3. Start a futex receiver thread on the doorbell fd pointed at the + * signal_nodes + */ +struct vsoc_device_region { + __u16 current_version; + __u16 min_compatible_version; + __u32 region_begin_offset; + __u32 region_end_offset; + __u32 offset_of_region_data; + struct vsoc_signal_table_layout guest_to_host_signal_table; + struct vsoc_signal_table_layout host_to_guest_signal_table; + /* Name of the device. Must always be terminated with a '\0', so + * the longest supported device name is 15 characters. + */ + char device_name[VSOC_DEVICE_NAME_SZ]; + /* There are two ways that permissions to access regions are handled: + * - When subdivided_by is VSOC_REGION_WHOLE, any process that can + * open the device node for the region gains complete access to it. + * - When subdivided is set processes that open the region cannot + * access it. Access to a sub-region must be established by invoking + * the VSOC_CREATE_FD_SCOPE_PERMISSION ioctl on the region + * referenced in subdivided_by, providing a fileinstance + * (represented by a fd) opened on this region. + */ + __u32 managed_by; +}; + +/* + * The vsoc layout descriptor. + * The first 4K should be reserved for the shm header and region descriptors. + * The regions should be page aligned. + */ + +struct vsoc_shm_layout_descriptor { + __u16 major_version; + __u16 minor_version; + + /* size of the shm. This may be redundant but nice to have */ + __u32 size; + + /* number of shared memory regions */ + __u32 region_count; + + /* The offset to the start of region descriptors */ + __u32 vsoc_region_desc_offset; +}; + +/* + * This specifies the current version that should be stored in + * vsoc_shm_layout_descriptor.major_version and + * vsoc_shm_layout_descriptor.minor_version. + * It should be updated only if the vsoc_device_region and + * vsoc_shm_layout_descriptor structures have changed. + * Versioning within each region is transferred + * via the min_compatible_version and current_version fields in + * vsoc_device_region. The driver does not consult these fields: they are left + * for the HALs and host processes and will change independently of the layout + * version. + */ +#define CURRENT_VSOC_LAYOUT_MAJOR_VERSION 2 +#define CURRENT_VSOC_LAYOUT_MINOR_VERSION 0 + +#define VSOC_CREATE_FD_SCOPED_PERMISSION \ + _IOW(0xF5, 0, struct fd_scoped_permission) +#define VSOC_GET_FD_SCOPED_PERMISSION _IOR(0xF5, 1, struct fd_scoped_permission) + +/* + * This is used to signal the host to scan the guest_to_host_signal_table + * for new futexes to wake. This sends an interrupt if one is not already + * in flight. + */ +#define VSOC_MAYBE_SEND_INTERRUPT_TO_HOST _IO(0xF5, 2) + +/* + * When this returns the guest will scan host_to_guest_signal_table to + * check for new futexes to wake. + */ +/* TODO(ghartman): Consider moving this to the bottom half */ +#define VSOC_WAIT_FOR_INCOMING_INTERRUPT _IO(0xF5, 3) + +/* + * Guest HALs will use this to retrieve the region description after + * opening their device node. + */ +#define VSOC_DESCRIBE_REGION _IOR(0xF5, 4, struct vsoc_device_region) + +/* + * Wake any threads that may be waiting for a host interrupt on this region. + * This is mostly used during shutdown. + */ +#define VSOC_SELF_INTERRUPT _IO(0xF5, 5) + +/* + * This is used to signal the host to scan the guest_to_host_signal_table + * for new futexes to wake. This sends an interrupt unconditionally. + */ +#define VSOC_SEND_INTERRUPT_TO_HOST _IO(0xF5, 6) + +enum wait_types { + VSOC_WAIT_UNDEFINED = 0, + VSOC_WAIT_IF_EQUAL = 1, + VSOC_WAIT_IF_EQUAL_TIMEOUT = 2 +}; + +/* + * Wait for a condition to be true + * + * Note, this is sized and aligned so the 32 bit and 64 bit layouts are + * identical. + */ +struct vsoc_cond_wait { + /* Input: Offset of the 32 bit word to check */ + __u32 offset; + /* Input: Value that will be compared with the offset */ + __u32 value; + /* Monotonic time to wake at in seconds */ + __u64 wake_time_sec; + /* Input: Monotonic time to wait in nanoseconds */ + __u32 wake_time_nsec; + /* Input: Type of wait */ + __u32 wait_type; + /* Output: Number of times the thread woke before returning. */ + __u32 wakes; + /* Ensure that we're 8-byte aligned and 8 byte length for 32/64 bit + * compatibility. + */ + __u32 reserved_1; +}; + +#define VSOC_COND_WAIT _IOWR(0xF5, 7, struct vsoc_cond_wait) + +/* Wake any local threads waiting at the offset given in arg */ +#define VSOC_COND_WAKE _IO(0xF5, 8) + +#endif /* _UAPI_LINUX_VSOC_SHM_H */ diff --git a/drivers/staging/android/vsoc.c b/drivers/staging/android/vsoc.c new file mode 100644 index 000000000000..587c66d709b9 --- /dev/null +++ b/drivers/staging/android/vsoc.c @@ -0,0 +1,1169 @@ +/* + * drivers/android/staging/vsoc.c + * + * Android Virtual System on a Chip (VSoC) driver + * + * Copyright (C) 2017 Google, Inc. + * + * Author: ghartman@google.com + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * + * Based on drivers/char/kvm_ivshmem.c - driver for KVM Inter-VM shared memory + * Copyright 2009 Cam Macdonell + * + * Based on cirrusfb.c and 8139cp.c: + * Copyright 1999-2001 Jeff Garzik + * Copyright 2001-2004 Jeff Garzik + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "uapi/vsoc_shm.h" + +#define VSOC_DEV_NAME "vsoc" + +/* + * Description of the ivshmem-doorbell PCI device used by QEmu. These + * constants follow docs/specs/ivshmem-spec.txt, which can be found in + * the QEmu repository. This was last reconciled with the version that + * came out with 2.8 + */ + +/* + * These constants are determined KVM Inter-VM shared memory device + * register offsets + */ +enum { + INTR_MASK = 0x00, /* Interrupt Mask */ + INTR_STATUS = 0x04, /* Interrupt Status */ + IV_POSITION = 0x08, /* VM ID */ + DOORBELL = 0x0c, /* Doorbell */ +}; + +static const int REGISTER_BAR; /* Equal to 0 */ +static const int MAX_REGISTER_BAR_LEN = 0x100; +/* + * The MSI-x BAR is not used directly. + * + * static const int MSI_X_BAR = 1; + */ +static const int SHARED_MEMORY_BAR = 2; + +struct vsoc_region_data { + char name[VSOC_DEVICE_NAME_SZ + 1]; + wait_queue_head_t interrupt_wait_queue; + /* TODO(b/73664181): Use multiple futex wait queues */ + wait_queue_head_t futex_wait_queue; + /* Flag indicating that an interrupt has been signalled by the host. */ + atomic_t *incoming_signalled; + /* Flag indicating the guest has signalled the host. */ + atomic_t *outgoing_signalled; + int irq_requested; + int device_created; +}; + +struct vsoc_device { + /* Kernel virtual address of REGISTER_BAR. */ + void __iomem *regs; + /* Physical address of SHARED_MEMORY_BAR. */ + phys_addr_t shm_phys_start; + /* Kernel virtual address of SHARED_MEMORY_BAR. */ + void *kernel_mapped_shm; + /* Size of the entire shared memory window in bytes. */ + size_t shm_size; + /* + * Pointer to the virtual address of the shared memory layout structure. + * This is probably identical to kernel_mapped_shm, but saving this + * here saves a lot of annoying casts. + */ + struct vsoc_shm_layout_descriptor *layout; + /* + * Points to a table of region descriptors in the kernel's virtual + * address space. Calculated from + * vsoc_shm_layout_descriptor.vsoc_region_desc_offset + */ + struct vsoc_device_region *regions; + /* Head of a list of permissions that have been granted. */ + struct list_head permissions; + struct pci_dev *dev; + /* Per-region (and therefore per-interrupt) information. */ + struct vsoc_region_data *regions_data; + /* + * Table of msi-x entries. This has to be separated from struct + * vsoc_region_data because the kernel deals with them as an array. + */ + struct msix_entry *msix_entries; + /* + * Flags that indicate what we've initialzied. These are used to do an + * orderly cleanup of the device. + */ + char enabled_device; + char requested_regions; + char cdev_added; + char class_added; + char msix_enabled; + /* Mutex that protectes the permission list */ + struct mutex mtx; + /* Major number assigned by the kernel */ + int major; + + struct cdev cdev; + struct class *class; +}; + +static struct vsoc_device vsoc_dev; + +/* + * TODO(ghartman): Add a /sys filesystem entry that summarizes the permissions. + */ + +struct fd_scoped_permission_node { + struct fd_scoped_permission permission; + struct list_head list; +}; + +struct vsoc_private_data { + struct fd_scoped_permission_node *fd_scoped_permission_node; +}; + +static long vsoc_ioctl(struct file *, unsigned int, unsigned long); +static int vsoc_mmap(struct file *, struct vm_area_struct *); +static int vsoc_open(struct inode *, struct file *); +static int vsoc_release(struct inode *, struct file *); +static ssize_t vsoc_read(struct file *, char *, size_t, loff_t *); +static ssize_t vsoc_write(struct file *, const char *, size_t, loff_t *); +static loff_t vsoc_lseek(struct file *filp, loff_t offset, int origin); +static int do_create_fd_scoped_permission( + struct vsoc_device_region *region_p, + struct fd_scoped_permission_node *np, + struct fd_scoped_permission_arg *__user arg); +static void do_destroy_fd_scoped_permission( + struct vsoc_device_region *owner_region_p, + struct fd_scoped_permission *perm); +static long do_vsoc_describe_region(struct file *, + struct vsoc_device_region __user *); +static ssize_t vsoc_get_area(struct file *filp, __u32 *perm_off); + +/** + * Validate arguments on entry points to the driver. + */ +inline int vsoc_validate_inode(struct inode *inode) +{ + if (iminor(inode) >= vsoc_dev.layout->region_count) { + dev_err(&vsoc_dev.dev->dev, + "describe_region: invalid region %d\n", iminor(inode)); + return -ENODEV; + } + return 0; +} + +inline int vsoc_validate_filep(struct file *filp) +{ + int ret = vsoc_validate_inode(file_inode(filp)); + + if (ret) + return ret; + if (!filp->private_data) { + dev_err(&vsoc_dev.dev->dev, + "No private data on fd, region %d\n", + iminor(file_inode(filp))); + return -EBADFD; + } + return 0; +} + +/* Converts from shared memory offset to virtual address */ +static inline void *shm_off_to_virtual_addr(__u32 offset) +{ + return vsoc_dev.kernel_mapped_shm + offset; +} + +/* Converts from shared memory offset to physical address */ +static inline phys_addr_t shm_off_to_phys_addr(__u32 offset) +{ + return vsoc_dev.shm_phys_start + offset; +} + +/** + * Convenience functions to obtain the region from the inode or file. + * Dangerous to call before validating the inode/file. + */ +static inline struct vsoc_device_region *vsoc_region_from_inode( + struct inode *inode) +{ + return &vsoc_dev.regions[iminor(inode)]; +} + +static inline struct vsoc_device_region *vsoc_region_from_filep( + struct file *inode) +{ + return vsoc_region_from_inode(file_inode(inode)); +} + +static inline uint32_t vsoc_device_region_size(struct vsoc_device_region *r) +{ + return r->region_end_offset - r->region_begin_offset; +} + +static const struct file_operations vsoc_ops = { + .owner = THIS_MODULE, + .open = vsoc_open, + .mmap = vsoc_mmap, + .read = vsoc_read, + .unlocked_ioctl = vsoc_ioctl, + .compat_ioctl = vsoc_ioctl, + .write = vsoc_write, + .llseek = vsoc_lseek, + .release = vsoc_release, +}; + +static struct pci_device_id vsoc_id_table[] = { + {0x1af4, 0x1110, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {0}, +}; + +MODULE_DEVICE_TABLE(pci, vsoc_id_table); + +static void vsoc_remove_device(struct pci_dev *pdev); +static int vsoc_probe_device(struct pci_dev *pdev, + const struct pci_device_id *ent); + +static struct pci_driver vsoc_pci_driver = { + .name = "vsoc", + .id_table = vsoc_id_table, + .probe = vsoc_probe_device, + .remove = vsoc_remove_device, +}; + +static int do_create_fd_scoped_permission( + struct vsoc_device_region *region_p, + struct fd_scoped_permission_node *np, + struct fd_scoped_permission_arg *__user arg) +{ + struct file *managed_filp; + s32 managed_fd; + atomic_t *owner_ptr = NULL; + struct vsoc_device_region *managed_region_p; + + if (copy_from_user(&np->permission, &arg->perm, sizeof(*np)) || + copy_from_user(&managed_fd, + &arg->managed_region_fd, sizeof(managed_fd))) { + return -EFAULT; + } + managed_filp = fdget(managed_fd).file; + /* Check that it's a valid fd, */ + if (!managed_filp || vsoc_validate_filep(managed_filp)) + return -EPERM; + /* EEXIST if the given fd already has a permission. */ + if (((struct vsoc_private_data *)managed_filp->private_data)-> + fd_scoped_permission_node) + return -EEXIST; + managed_region_p = vsoc_region_from_filep(managed_filp); + /* Check that the provided region is managed by this one */ + if (&vsoc_dev.regions[managed_region_p->managed_by] != region_p) + return -EPERM; + /* The area must be well formed and have non-zero size */ + if (np->permission.begin_offset >= np->permission.end_offset) + return -EINVAL; + /* The area must fit in the memory window */ + if (np->permission.end_offset > + vsoc_device_region_size(managed_region_p)) + return -ERANGE; + /* The area must be in the region data section */ + if (np->permission.begin_offset < + managed_region_p->offset_of_region_data) + return -ERANGE; + /* The area must be page aligned */ + if (!PAGE_ALIGNED(np->permission.begin_offset) || + !PAGE_ALIGNED(np->permission.end_offset)) + return -EINVAL; + /* Owner offset must be naturally aligned in the window */ + if (np->permission.owner_offset & + (sizeof(np->permission.owner_offset) - 1)) + return -EINVAL; + /* The owner flag must reside in the owner memory */ + if (np->permission.owner_offset + sizeof(np->permission.owner_offset) > + vsoc_device_region_size(region_p)) + return -ERANGE; + /* The owner flag must reside in the data section */ + if (np->permission.owner_offset < region_p->offset_of_region_data) + return -EINVAL; + /* The owner value must change to claim the memory */ + if (np->permission.owned_value == VSOC_REGION_FREE) + return -EINVAL; + owner_ptr = + (atomic_t *)shm_off_to_virtual_addr(region_p->region_begin_offset + + np->permission.owner_offset); + /* We've already verified that this is in the shared memory window, so + * it should be safe to write to this address. + */ + if (atomic_cmpxchg(owner_ptr, + VSOC_REGION_FREE, + np->permission.owned_value) != VSOC_REGION_FREE) { + return -EBUSY; + } + ((struct vsoc_private_data *)managed_filp->private_data)-> + fd_scoped_permission_node = np; + /* The file offset needs to be adjusted if the calling + * process did any read/write operations on the fd + * before creating the permission. + */ + if (managed_filp->f_pos) { + if (managed_filp->f_pos > np->permission.end_offset) { + /* If the offset is beyond the permission end, set it + * to the end. + */ + managed_filp->f_pos = np->permission.end_offset; + } else { + /* If the offset is within the permission interval + * keep it there otherwise reset it to zero. + */ + if (managed_filp->f_pos < np->permission.begin_offset) { + managed_filp->f_pos = 0; + } else { + managed_filp->f_pos -= + np->permission.begin_offset; + } + } + } + return 0; +} + +static void do_destroy_fd_scoped_permission_node( + struct vsoc_device_region *owner_region_p, + struct fd_scoped_permission_node *node) +{ + if (node) { + do_destroy_fd_scoped_permission(owner_region_p, + &node->permission); + mutex_lock(&vsoc_dev.mtx); + list_del(&node->list); + mutex_unlock(&vsoc_dev.mtx); + kfree(node); + } +} + +static void do_destroy_fd_scoped_permission( + struct vsoc_device_region *owner_region_p, + struct fd_scoped_permission *perm) +{ + atomic_t *owner_ptr = NULL; + int prev = 0; + + if (!perm) + return; + owner_ptr = (atomic_t *)shm_off_to_virtual_addr( + owner_region_p->region_begin_offset + perm->owner_offset); + prev = atomic_xchg(owner_ptr, VSOC_REGION_FREE); + if (prev != perm->owned_value) + dev_err(&vsoc_dev.dev->dev, + "%x-%x: owner (%s) %x: expected to be %x was %x", + perm->begin_offset, perm->end_offset, + owner_region_p->device_name, perm->owner_offset, + perm->owned_value, prev); +} + +static long do_vsoc_describe_region(struct file *filp, + struct vsoc_device_region __user *dest) +{ + struct vsoc_device_region *region_p; + int retval = vsoc_validate_filep(filp); + + if (retval) + return retval; + region_p = vsoc_region_from_filep(filp); + if (copy_to_user(dest, region_p, sizeof(*region_p))) + return -EFAULT; + return 0; +} + +/** + * Implements the inner logic of cond_wait. Copies to and from userspace are + * done in the helper function below. + */ +static int handle_vsoc_cond_wait(struct file *filp, struct vsoc_cond_wait *arg) +{ + DEFINE_WAIT(wait); + u32 region_number = iminor(file_inode(filp)); + struct vsoc_region_data *data = vsoc_dev.regions_data + region_number; + struct hrtimer_sleeper timeout, *to = NULL; + int ret = 0; + struct vsoc_device_region *region_p = vsoc_region_from_filep(filp); + atomic_t *address = NULL; + struct timespec ts; + + /* Ensure that the offset is aligned */ + if (arg->offset & (sizeof(uint32_t) - 1)) + return -EADDRNOTAVAIL; + /* Ensure that the offset is within shared memory */ + if (((uint64_t)arg->offset) + region_p->region_begin_offset + + sizeof(uint32_t) > region_p->region_end_offset) + return -E2BIG; + address = shm_off_to_virtual_addr(region_p->region_begin_offset + + arg->offset); + + /* Ensure that the type of wait is valid */ + switch (arg->wait_type) { + case VSOC_WAIT_IF_EQUAL: + break; + case VSOC_WAIT_IF_EQUAL_TIMEOUT: + to = &timeout; + break; + default: + return -EINVAL; + } + + if (to) { + /* Copy the user-supplied timesec into the kernel structure. + * We do things this way to flatten differences between 32 bit + * and 64 bit timespecs. + */ + ts.tv_sec = arg->wake_time_sec; + ts.tv_nsec = arg->wake_time_nsec; + + if (!timespec_valid(&ts)) + return -EINVAL; + hrtimer_init_on_stack(&to->timer, CLOCK_MONOTONIC, + HRTIMER_MODE_ABS); + hrtimer_set_expires_range_ns(&to->timer, timespec_to_ktime(ts), + current->timer_slack_ns); + + hrtimer_init_sleeper(to, current); + } + + while (1) { + prepare_to_wait(&data->futex_wait_queue, &wait, + TASK_INTERRUPTIBLE); + /* + * Check the sentinel value after prepare_to_wait. If the value + * changes after this check the writer will call signal, + * changing the task state from INTERRUPTIBLE to RUNNING. That + * will ensure that schedule() will eventually schedule this + * task. + */ + if (atomic_read(address) != arg->value) { + ret = 0; + break; + } + if (to) { + hrtimer_start_expires(&to->timer, HRTIMER_MODE_ABS); + if (likely(to->task)) + freezable_schedule(); + hrtimer_cancel(&to->timer); + if (!to->task) { + ret = -ETIMEDOUT; + break; + } + } else { + freezable_schedule(); + } + /* Count the number of times that we woke up. This is useful + * for unit testing. + */ + ++arg->wakes; + if (signal_pending(current)) { + ret = -EINTR; + break; + } + } + finish_wait(&data->futex_wait_queue, &wait); + if (to) + destroy_hrtimer_on_stack(&to->timer); + return ret; +} + +/** + * Handles the details of copying from/to userspace to ensure that the copies + * happen on all of the return paths of cond_wait. + */ +static int do_vsoc_cond_wait(struct file *filp, + struct vsoc_cond_wait __user *untrusted_in) +{ + struct vsoc_cond_wait arg; + int rval = 0; + + if (copy_from_user(&arg, untrusted_in, sizeof(arg))) + return -EFAULT; + /* wakes is an out parameter. Initialize it to something sensible. */ + arg.wakes = 0; + rval = handle_vsoc_cond_wait(filp, &arg); + if (copy_to_user(untrusted_in, &arg, sizeof(arg))) + return -EFAULT; + return rval; +} + +static int do_vsoc_cond_wake(struct file *filp, uint32_t offset) +{ + struct vsoc_device_region *region_p = vsoc_region_from_filep(filp); + u32 region_number = iminor(file_inode(filp)); + struct vsoc_region_data *data = vsoc_dev.regions_data + region_number; + /* Ensure that the offset is aligned */ + if (offset & (sizeof(uint32_t) - 1)) + return -EADDRNOTAVAIL; + /* Ensure that the offset is within shared memory */ + if (((uint64_t)offset) + region_p->region_begin_offset + + sizeof(uint32_t) > region_p->region_end_offset) + return -E2BIG; + /* + * TODO(b/73664181): Use multiple futex wait queues. + * We need to wake every sleeper when the condition changes. Typically + * only a single thread will be waiting on the condition, but there + * are exceptions. The worst case is about 10 threads. + */ + wake_up_interruptible_all(&data->futex_wait_queue); + return 0; +} + +static long vsoc_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) +{ + int rv = 0; + struct vsoc_device_region *region_p; + u32 reg_num; + struct vsoc_region_data *reg_data; + int retval = vsoc_validate_filep(filp); + + if (retval) + return retval; + region_p = vsoc_region_from_filep(filp); + reg_num = iminor(file_inode(filp)); + reg_data = vsoc_dev.regions_data + reg_num; + switch (cmd) { + case VSOC_CREATE_FD_SCOPED_PERMISSION: + { + struct fd_scoped_permission_node *node = NULL; + + node = kzalloc(sizeof(*node), GFP_KERNEL); + /* We can't allocate memory for the permission */ + if (!node) + return -ENOMEM; + INIT_LIST_HEAD(&node->list); + rv = do_create_fd_scoped_permission( + region_p, + node, + (struct fd_scoped_permission_arg __user *)arg); + if (!rv) { + mutex_lock(&vsoc_dev.mtx); + list_add(&node->list, &vsoc_dev.permissions); + mutex_unlock(&vsoc_dev.mtx); + } else { + kfree(node); + return rv; + } + } + break; + + case VSOC_GET_FD_SCOPED_PERMISSION: + { + struct fd_scoped_permission_node *node = + ((struct vsoc_private_data *)filp->private_data)-> + fd_scoped_permission_node; + if (!node) + return -ENOENT; + if (copy_to_user + ((struct fd_scoped_permission __user *)arg, + &node->permission, sizeof(node->permission))) + return -EFAULT; + } + break; + + case VSOC_MAYBE_SEND_INTERRUPT_TO_HOST: + if (!atomic_xchg( + reg_data->outgoing_signalled, + 1)) { + writel(reg_num, vsoc_dev.regs + DOORBELL); + return 0; + } else { + return -EBUSY; + } + break; + + case VSOC_SEND_INTERRUPT_TO_HOST: + writel(reg_num, vsoc_dev.regs + DOORBELL); + return 0; + + case VSOC_WAIT_FOR_INCOMING_INTERRUPT: + wait_event_interruptible( + reg_data->interrupt_wait_queue, + (atomic_read(reg_data->incoming_signalled) != 0)); + break; + + case VSOC_DESCRIBE_REGION: + return do_vsoc_describe_region( + filp, + (struct vsoc_device_region __user *)arg); + + case VSOC_SELF_INTERRUPT: + atomic_set(reg_data->incoming_signalled, 1); + wake_up_interruptible(®_data->interrupt_wait_queue); + break; + + case VSOC_COND_WAIT: + return do_vsoc_cond_wait(filp, + (struct vsoc_cond_wait __user *)arg); + case VSOC_COND_WAKE: + return do_vsoc_cond_wake(filp, arg); + + default: + return -EINVAL; + } + return 0; +} + +static ssize_t vsoc_read(struct file *filp, char *buffer, size_t len, + loff_t *poffset) +{ + __u32 area_off; + void *area_p; + ssize_t area_len; + int retval = vsoc_validate_filep(filp); + + if (retval) + return retval; + area_len = vsoc_get_area(filp, &area_off); + area_p = shm_off_to_virtual_addr(area_off); + area_p += *poffset; + area_len -= *poffset; + if (area_len <= 0) + return 0; + if (area_len < len) + len = area_len; + if (copy_to_user(buffer, area_p, len)) + return -EFAULT; + *poffset += len; + return len; +} + +static loff_t vsoc_lseek(struct file *filp, loff_t offset, int origin) +{ + ssize_t area_len = 0; + int retval = vsoc_validate_filep(filp); + + if (retval) + return retval; + area_len = vsoc_get_area(filp, NULL); + switch (origin) { + case SEEK_SET: + break; + + case SEEK_CUR: + if (offset > 0 && offset + filp->f_pos < 0) + return -EOVERFLOW; + offset += filp->f_pos; + break; + + case SEEK_END: + if (offset > 0 && offset + area_len < 0) + return -EOVERFLOW; + offset += area_len; + break; + + case SEEK_DATA: + if (offset >= area_len) + return -EINVAL; + if (offset < 0) + offset = 0; + break; + + case SEEK_HOLE: + /* Next hole is always the end of the region, unless offset is + * beyond that + */ + if (offset < area_len) + offset = area_len; + break; + + default: + return -EINVAL; + } + + if (offset < 0 || offset > area_len) + return -EINVAL; + filp->f_pos = offset; + + return offset; +} + +static ssize_t vsoc_write(struct file *filp, const char *buffer, + size_t len, loff_t *poffset) +{ + __u32 area_off; + void *area_p; + ssize_t area_len; + int retval = vsoc_validate_filep(filp); + + if (retval) + return retval; + area_len = vsoc_get_area(filp, &area_off); + area_p = shm_off_to_virtual_addr(area_off); + area_p += *poffset; + area_len -= *poffset; + if (area_len <= 0) + return 0; + if (area_len < len) + len = area_len; + if (copy_from_user(area_p, buffer, len)) + return -EFAULT; + *poffset += len; + return len; +} + +static irqreturn_t vsoc_interrupt(int irq, void *region_data_v) +{ + struct vsoc_region_data *region_data = + (struct vsoc_region_data *)region_data_v; + int reg_num = region_data - vsoc_dev.regions_data; + + if (unlikely(!region_data)) + return IRQ_NONE; + + if (unlikely(reg_num < 0 || + reg_num >= vsoc_dev.layout->region_count)) { + dev_err(&vsoc_dev.dev->dev, + "invalid irq @%p reg_num=0x%04x\n", + region_data, reg_num); + return IRQ_NONE; + } + if (unlikely(vsoc_dev.regions_data + reg_num != region_data)) { + dev_err(&vsoc_dev.dev->dev, + "irq not aligned @%p reg_num=0x%04x\n", + region_data, reg_num); + return IRQ_NONE; + } + wake_up_interruptible(®ion_data->interrupt_wait_queue); + return IRQ_HANDLED; +} + +static int vsoc_probe_device(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + int result; + int i; + resource_size_t reg_size; + dev_t devt; + + vsoc_dev.dev = pdev; + result = pci_enable_device(pdev); + if (result) { + dev_err(&pdev->dev, + "pci_enable_device failed %s: error %d\n", + pci_name(pdev), result); + return result; + } + vsoc_dev.enabled_device = 1; + result = pci_request_regions(pdev, "vsoc"); + if (result < 0) { + dev_err(&pdev->dev, "pci_request_regions failed\n"); + vsoc_remove_device(pdev); + return -EBUSY; + } + vsoc_dev.requested_regions = 1; + /* Set up the control registers in BAR 0 */ + reg_size = pci_resource_len(pdev, REGISTER_BAR); + if (reg_size > MAX_REGISTER_BAR_LEN) + vsoc_dev.regs = + pci_iomap(pdev, REGISTER_BAR, MAX_REGISTER_BAR_LEN); + else + vsoc_dev.regs = pci_iomap(pdev, REGISTER_BAR, reg_size); + + if (!vsoc_dev.regs) { + dev_err(&pdev->dev, + "cannot ioremap registers of size %zu\n", + (size_t)reg_size); + vsoc_remove_device(pdev); + return -EBUSY; + } + + /* Map the shared memory in BAR 2 */ + vsoc_dev.shm_phys_start = pci_resource_start(pdev, SHARED_MEMORY_BAR); + vsoc_dev.shm_size = pci_resource_len(pdev, SHARED_MEMORY_BAR); + + dev_info(&pdev->dev, "shared memory @ DMA %p size=0x%zx\n", + (void *)vsoc_dev.shm_phys_start, vsoc_dev.shm_size); + /* TODO(ghartman): ioremap_wc should work here */ + vsoc_dev.kernel_mapped_shm = ioremap_nocache( + vsoc_dev.shm_phys_start, vsoc_dev.shm_size); + if (!vsoc_dev.kernel_mapped_shm) { + dev_err(&vsoc_dev.dev->dev, "cannot iomap region\n"); + vsoc_remove_device(pdev); + return -EBUSY; + } + + vsoc_dev.layout = + (struct vsoc_shm_layout_descriptor *)vsoc_dev.kernel_mapped_shm; + dev_info(&pdev->dev, "major_version: %d\n", + vsoc_dev.layout->major_version); + dev_info(&pdev->dev, "minor_version: %d\n", + vsoc_dev.layout->minor_version); + dev_info(&pdev->dev, "size: 0x%x\n", vsoc_dev.layout->size); + dev_info(&pdev->dev, "regions: %d\n", vsoc_dev.layout->region_count); + if (vsoc_dev.layout->major_version != + CURRENT_VSOC_LAYOUT_MAJOR_VERSION) { + dev_err(&vsoc_dev.dev->dev, + "driver supports only major_version %d\n", + CURRENT_VSOC_LAYOUT_MAJOR_VERSION); + vsoc_remove_device(pdev); + return -EBUSY; + } + result = alloc_chrdev_region(&devt, 0, vsoc_dev.layout->region_count, + VSOC_DEV_NAME); + if (result) { + dev_err(&vsoc_dev.dev->dev, "alloc_chrdev_region failed\n"); + vsoc_remove_device(pdev); + return -EBUSY; + } + vsoc_dev.major = MAJOR(devt); + cdev_init(&vsoc_dev.cdev, &vsoc_ops); + vsoc_dev.cdev.owner = THIS_MODULE; + result = cdev_add(&vsoc_dev.cdev, devt, vsoc_dev.layout->region_count); + if (result) { + dev_err(&vsoc_dev.dev->dev, "cdev_add error\n"); + vsoc_remove_device(pdev); + return -EBUSY; + } + vsoc_dev.cdev_added = 1; + vsoc_dev.class = class_create(THIS_MODULE, VSOC_DEV_NAME); + if (IS_ERR(vsoc_dev.class)) { + dev_err(&vsoc_dev.dev->dev, "class_create failed\n"); + vsoc_remove_device(pdev); + return PTR_ERR(vsoc_dev.class); + } + vsoc_dev.class_added = 1; + vsoc_dev.regions = (struct vsoc_device_region *) + (vsoc_dev.kernel_mapped_shm + + vsoc_dev.layout->vsoc_region_desc_offset); + vsoc_dev.msix_entries = kcalloc( + vsoc_dev.layout->region_count, + sizeof(vsoc_dev.msix_entries[0]), GFP_KERNEL); + if (!vsoc_dev.msix_entries) { + dev_err(&vsoc_dev.dev->dev, + "unable to allocate msix_entries\n"); + vsoc_remove_device(pdev); + return -ENOSPC; + } + vsoc_dev.regions_data = kcalloc( + vsoc_dev.layout->region_count, + sizeof(vsoc_dev.regions_data[0]), GFP_KERNEL); + if (!vsoc_dev.regions_data) { + dev_err(&vsoc_dev.dev->dev, + "unable to allocate regions' data\n"); + vsoc_remove_device(pdev); + return -ENOSPC; + } + for (i = 0; i < vsoc_dev.layout->region_count; ++i) + vsoc_dev.msix_entries[i].entry = i; + + result = pci_enable_msix_exact(vsoc_dev.dev, vsoc_dev.msix_entries, + vsoc_dev.layout->region_count); + if (result) { + dev_info(&pdev->dev, "pci_enable_msix failed: %d\n", result); + vsoc_remove_device(pdev); + return -ENOSPC; + } + /* Check that all regions are well formed */ + for (i = 0; i < vsoc_dev.layout->region_count; ++i) { + const struct vsoc_device_region *region = vsoc_dev.regions + i; + + if (!PAGE_ALIGNED(region->region_begin_offset) || + !PAGE_ALIGNED(region->region_end_offset)) { + dev_err(&vsoc_dev.dev->dev, + "region %d not aligned (%x:%x)", i, + region->region_begin_offset, + region->region_end_offset); + vsoc_remove_device(pdev); + return -EFAULT; + } + if (region->region_begin_offset >= region->region_end_offset || + region->region_end_offset > vsoc_dev.shm_size) { + dev_err(&vsoc_dev.dev->dev, + "region %d offsets are wrong: %x %x %zx", + i, region->region_begin_offset, + region->region_end_offset, vsoc_dev.shm_size); + vsoc_remove_device(pdev); + return -EFAULT; + } + if (region->managed_by >= vsoc_dev.layout->region_count) { + dev_err(&vsoc_dev.dev->dev, + "region %d has invalid owner: %u", + i, region->managed_by); + vsoc_remove_device(pdev); + return -EFAULT; + } + } + vsoc_dev.msix_enabled = 1; + for (i = 0; i < vsoc_dev.layout->region_count; ++i) { + const struct vsoc_device_region *region = vsoc_dev.regions + i; + size_t name_sz = sizeof(vsoc_dev.regions_data[i].name) - 1; + const struct vsoc_signal_table_layout *h_to_g_signal_table = + ®ion->host_to_guest_signal_table; + const struct vsoc_signal_table_layout *g_to_h_signal_table = + ®ion->guest_to_host_signal_table; + + vsoc_dev.regions_data[i].name[name_sz] = '\0'; + memcpy(vsoc_dev.regions_data[i].name, region->device_name, + name_sz); + dev_info(&pdev->dev, "region %d name=%s\n", + i, vsoc_dev.regions_data[i].name); + init_waitqueue_head( + &vsoc_dev.regions_data[i].interrupt_wait_queue); + init_waitqueue_head(&vsoc_dev.regions_data[i].futex_wait_queue); + vsoc_dev.regions_data[i].incoming_signalled = + vsoc_dev.kernel_mapped_shm + + region->region_begin_offset + + h_to_g_signal_table->interrupt_signalled_offset; + vsoc_dev.regions_data[i].outgoing_signalled = + vsoc_dev.kernel_mapped_shm + + region->region_begin_offset + + g_to_h_signal_table->interrupt_signalled_offset; + + result = request_irq( + vsoc_dev.msix_entries[i].vector, + vsoc_interrupt, 0, + vsoc_dev.regions_data[i].name, + vsoc_dev.regions_data + i); + if (result) { + dev_info(&pdev->dev, + "request_irq failed irq=%d vector=%d\n", + i, vsoc_dev.msix_entries[i].vector); + vsoc_remove_device(pdev); + return -ENOSPC; + } + vsoc_dev.regions_data[i].irq_requested = 1; + if (!device_create(vsoc_dev.class, NULL, + MKDEV(vsoc_dev.major, i), + NULL, vsoc_dev.regions_data[i].name)) { + dev_err(&vsoc_dev.dev->dev, "device_create failed\n"); + vsoc_remove_device(pdev); + return -EBUSY; + } + vsoc_dev.regions_data[i].device_created = 1; + } + return 0; +} + +/* + * This should undo all of the allocations in the probe function in reverse + * order. + * + * Notes: + * + * The device may have been partially initialized, so double check + * that the allocations happened. + * + * This function may be called multiple times, so mark resources as freed + * as they are deallocated. + */ +static void vsoc_remove_device(struct pci_dev *pdev) +{ + int i; + /* + * pdev is the first thing to be set on probe and the last thing + * to be cleared here. If it's NULL then there is no cleanup. + */ + if (!pdev || !vsoc_dev.dev) + return; + dev_info(&pdev->dev, "remove_device\n"); + if (vsoc_dev.regions_data) { + for (i = 0; i < vsoc_dev.layout->region_count; ++i) { + if (vsoc_dev.regions_data[i].device_created) { + device_destroy(vsoc_dev.class, + MKDEV(vsoc_dev.major, i)); + vsoc_dev.regions_data[i].device_created = 0; + } + if (vsoc_dev.regions_data[i].irq_requested) + free_irq(vsoc_dev.msix_entries[i].vector, NULL); + vsoc_dev.regions_data[i].irq_requested = 0; + } + kfree(vsoc_dev.regions_data); + vsoc_dev.regions_data = 0; + } + if (vsoc_dev.msix_enabled) { + pci_disable_msix(pdev); + vsoc_dev.msix_enabled = 0; + } + kfree(vsoc_dev.msix_entries); + vsoc_dev.msix_entries = 0; + vsoc_dev.regions = 0; + if (vsoc_dev.class_added) { + class_destroy(vsoc_dev.class); + vsoc_dev.class_added = 0; + } + if (vsoc_dev.cdev_added) { + cdev_del(&vsoc_dev.cdev); + vsoc_dev.cdev_added = 0; + } + if (vsoc_dev.major && vsoc_dev.layout) { + unregister_chrdev_region(MKDEV(vsoc_dev.major, 0), + vsoc_dev.layout->region_count); + vsoc_dev.major = 0; + } + vsoc_dev.layout = 0; + if (vsoc_dev.kernel_mapped_shm) { + pci_iounmap(pdev, vsoc_dev.kernel_mapped_shm); + vsoc_dev.kernel_mapped_shm = 0; + } + if (vsoc_dev.regs) { + pci_iounmap(pdev, vsoc_dev.regs); + vsoc_dev.regs = 0; + } + if (vsoc_dev.requested_regions) { + pci_release_regions(pdev); + vsoc_dev.requested_regions = 0; + } + if (vsoc_dev.enabled_device) { + pci_disable_device(pdev); + vsoc_dev.enabled_device = 0; + } + /* Do this last: it indicates that the device is not initialized. */ + vsoc_dev.dev = NULL; +} + +static void __exit vsoc_cleanup_module(void) +{ + vsoc_remove_device(vsoc_dev.dev); + pci_unregister_driver(&vsoc_pci_driver); +} + +static int __init vsoc_init_module(void) +{ + int err = -ENOMEM; + + INIT_LIST_HEAD(&vsoc_dev.permissions); + mutex_init(&vsoc_dev.mtx); + + err = pci_register_driver(&vsoc_pci_driver); + if (err < 0) + return err; + return 0; +} + +static int vsoc_open(struct inode *inode, struct file *filp) +{ + /* Can't use vsoc_validate_filep because filp is still incomplete */ + int ret = vsoc_validate_inode(inode); + + if (ret) + return ret; + filp->private_data = + kzalloc(sizeof(struct vsoc_private_data), GFP_KERNEL); + if (!filp->private_data) + return -ENOMEM; + return 0; +} + +static int vsoc_release(struct inode *inode, struct file *filp) +{ + struct vsoc_private_data *private_data = NULL; + struct fd_scoped_permission_node *node = NULL; + struct vsoc_device_region *owner_region_p = NULL; + int retval = vsoc_validate_filep(filp); + + if (retval) + return retval; + private_data = (struct vsoc_private_data *)filp->private_data; + if (!private_data) + return 0; + + node = private_data->fd_scoped_permission_node; + if (node) { + owner_region_p = vsoc_region_from_inode(inode); + if (owner_region_p->managed_by != VSOC_REGION_WHOLE) { + owner_region_p = + &vsoc_dev.regions[owner_region_p->managed_by]; + } + do_destroy_fd_scoped_permission_node(owner_region_p, node); + private_data->fd_scoped_permission_node = NULL; + } + kfree(private_data); + filp->private_data = NULL; + + return 0; +} + +/* + * Returns the device relative offset and length of the area specified by the + * fd scoped permission. If there is no fd scoped permission set, a default + * permission covering the entire region is assumed, unless the region is owned + * by another one, in which case the default is a permission with zero size. + */ +static ssize_t vsoc_get_area(struct file *filp, __u32 *area_offset) +{ + __u32 off = 0; + ssize_t length = 0; + struct vsoc_device_region *region_p; + struct fd_scoped_permission *perm; + + region_p = vsoc_region_from_filep(filp); + off = region_p->region_begin_offset; + perm = &((struct vsoc_private_data *)filp->private_data)-> + fd_scoped_permission_node->permission; + if (perm) { + off += perm->begin_offset; + length = perm->end_offset - perm->begin_offset; + } else if (region_p->managed_by == VSOC_REGION_WHOLE) { + /* No permission set and the regions is not owned by another, + * default to full region access. + */ + length = vsoc_device_region_size(region_p); + } else { + /* return zero length, access is denied. */ + length = 0; + } + if (area_offset) + *area_offset = off; + return length; +} + +static int vsoc_mmap(struct file *filp, struct vm_area_struct *vma) +{ + unsigned long len = vma->vm_end - vma->vm_start; + __u32 area_off; + phys_addr_t mem_off; + ssize_t area_len; + int retval = vsoc_validate_filep(filp); + + if (retval) + return retval; + area_len = vsoc_get_area(filp, &area_off); + /* Add the requested offset */ + area_off += (vma->vm_pgoff << PAGE_SHIFT); + area_len -= (vma->vm_pgoff << PAGE_SHIFT); + if (area_len < len) + return -EINVAL; + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); + mem_off = shm_off_to_phys_addr(area_off); + if (io_remap_pfn_range(vma, vma->vm_start, mem_off >> PAGE_SHIFT, + len, vma->vm_page_prot)) + return -EAGAIN; + return 0; +} + +module_init(vsoc_init_module); +module_exit(vsoc_cleanup_module); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Greg Hartman "); +MODULE_DESCRIPTION("VSoC interpretation of QEmu's ivshmem device"); +MODULE_VERSION("1.0"); -- GitLab From f16491f944e5a8c9c35fb7bf75cf1301fb413b9b Mon Sep 17 00:00:00 2001 From: Alistair Strachan Date: Thu, 5 Apr 2018 18:01:04 -0700 Subject: [PATCH 0400/1635] ANDROID: Add defconfig for cuttlefish. This file is based on x86_64_defconfig, merged with the base and recommended configs from configs.git, with the virtio drivers enabled and some spurious kernel features turned off. Change-Id: I61bde941e8cfef2dd83cb4ff040f7380922cc44e Signed-off-by: Alistair Strachan --- arch/x86/configs/x86_64_cuttlefish_defconfig | 444 +++++++++++++++++++ 1 file changed, 444 insertions(+) create mode 100644 arch/x86/configs/x86_64_cuttlefish_defconfig diff --git a/arch/x86/configs/x86_64_cuttlefish_defconfig b/arch/x86/configs/x86_64_cuttlefish_defconfig new file mode 100644 index 000000000000..1b9020912aae --- /dev/null +++ b/arch/x86/configs/x86_64_cuttlefish_defconfig @@ -0,0 +1,444 @@ +CONFIG_POSIX_MQUEUE=y +# CONFIG_FHANDLE is not set +# CONFIG_USELIB is not set +CONFIG_AUDIT=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_BSD_PROCESS_ACCT=y +CONFIG_TASKSTATS=y +CONFIG_TASK_DELAY_ACCT=y +CONFIG_TASK_XACCT=y +CONFIG_TASK_IO_ACCOUNTING=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_CGROUPS=y +CONFIG_MEMCG=y +CONFIG_MEMCG_SWAP=y +CONFIG_CGROUP_SCHED=y +CONFIG_RT_GROUP_SCHED=y +CONFIG_CGROUP_FREEZER=y +CONFIG_CGROUP_CPUACCT=y +CONFIG_CGROUP_BPF=y +CONFIG_NAMESPACES=y +CONFIG_BLK_DEV_INITRD=y +# CONFIG_RD_LZ4 is not set +CONFIG_KALLSYMS_ALL=y +# CONFIG_PCSPKR_PLATFORM is not set +CONFIG_BPF_SYSCALL=y +CONFIG_EMBEDDED=y +# CONFIG_COMPAT_BRK is not set +CONFIG_PROFILING=y +CONFIG_OPROFILE=y +CONFIG_KPROBES=y +CONFIG_JUMP_LABEL=y +CONFIG_CC_STACKPROTECTOR_STRONG=y +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +CONFIG_MODVERSIONS=y +CONFIG_PARTITION_ADVANCED=y +CONFIG_SMP=y +CONFIG_HYPERVISOR_GUEST=y +CONFIG_PARAVIRT=y +CONFIG_PARAVIRT_SPINLOCKS=y +CONFIG_MCORE2=y +CONFIG_PROCESSOR_SELECT=y +# CONFIG_CPU_SUP_CENTAUR is not set +CONFIG_NR_CPUS=8 +CONFIG_PREEMPT=y +# CONFIG_MICROCODE is not set +CONFIG_X86_MSR=y +CONFIG_X86_CPUID=y +CONFIG_KSM=y +CONFIG_DEFAULT_MMAP_MIN_ADDR=65536 +CONFIG_TRANSPARENT_HUGEPAGE=y +# CONFIG_MTRR is not set +CONFIG_HZ_100=y +CONFIG_KEXEC=y +CONFIG_CRASH_DUMP=y +CONFIG_PHYSICAL_START=0x200000 +CONFIG_PHYSICAL_ALIGN=0x1000000 +CONFIG_CMDLINE_BOOL=y +CONFIG_CMDLINE="console=ttyS0 reboot=p" +CONFIG_PM_WAKELOCKS=y +CONFIG_PM_WAKELOCKS_LIMIT=0 +# CONFIG_PM_WAKELOCKS_GC is not set +CONFIG_PM_DEBUG=y +CONFIG_ACPI_PROCFS_POWER=y +# CONFIG_ACPI_FAN is not set +# CONFIG_ACPI_THERMAL is not set +# CONFIG_X86_PM_TIMER is not set +CONFIG_CPU_FREQ_GOV_ONDEMAND=y +CONFIG_X86_ACPI_CPUFREQ=y +CONFIG_PCI_MMCONFIG=y +CONFIG_PCI_MSI=y +# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set +CONFIG_BINFMT_MISC=y +CONFIG_IA32_EMULATION=y +CONFIG_NET=y +CONFIG_PACKET=y +CONFIG_UNIX=y +CONFIG_XFRM_USER=y +CONFIG_NET_KEY=y +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_ADVANCED_ROUTER=y +CONFIG_IP_MULTIPLE_TABLES=y +CONFIG_IP_ROUTE_MULTIPATH=y +CONFIG_IP_ROUTE_VERBOSE=y +CONFIG_IP_MROUTE=y +CONFIG_IP_PIMSM_V1=y +CONFIG_IP_PIMSM_V2=y +CONFIG_SYN_COOKIES=y +CONFIG_INET_ESP=y +# CONFIG_INET_XFRM_MODE_TRANSPORT is not set +# CONFIG_INET_XFRM_MODE_BEET is not set +CONFIG_INET_DIAG_DESTROY=y +CONFIG_TCP_CONG_ADVANCED=y +# CONFIG_TCP_CONG_BIC is not set +# CONFIG_TCP_CONG_WESTWOOD is not set +# CONFIG_TCP_CONG_HTCP is not set +CONFIG_TCP_MD5SIG=y +CONFIG_IPV6_ROUTER_PREF=y +CONFIG_IPV6_ROUTE_INFO=y +CONFIG_IPV6_OPTIMISTIC_DAD=y +CONFIG_INET6_AH=y +CONFIG_INET6_ESP=y +CONFIG_INET6_IPCOMP=y +CONFIG_IPV6_MIP6=y +CONFIG_IPV6_MULTIPLE_TABLES=y +CONFIG_NETLABEL=y +CONFIG_NETFILTER=y +CONFIG_NF_CONNTRACK=y +CONFIG_NF_CONNTRACK_SECMARK=y +CONFIG_NF_CONNTRACK_EVENTS=y +CONFIG_NF_CONNTRACK_AMANDA=y +CONFIG_NF_CONNTRACK_FTP=y +CONFIG_NF_CONNTRACK_H323=y +CONFIG_NF_CONNTRACK_IRC=y +CONFIG_NF_CONNTRACK_NETBIOS_NS=y +CONFIG_NF_CONNTRACK_PPTP=y +CONFIG_NF_CONNTRACK_SANE=y +CONFIG_NF_CONNTRACK_TFTP=y +CONFIG_NF_CT_NETLINK=y +CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y +CONFIG_NETFILTER_XT_TARGET_CONNMARK=y +CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=y +CONFIG_NETFILTER_XT_TARGET_IDLETIMER=y +CONFIG_NETFILTER_XT_TARGET_MARK=y +CONFIG_NETFILTER_XT_TARGET_NFLOG=y +CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y +CONFIG_NETFILTER_XT_TARGET_TPROXY=y +CONFIG_NETFILTER_XT_TARGET_TRACE=y +CONFIG_NETFILTER_XT_TARGET_SECMARK=y +CONFIG_NETFILTER_XT_TARGET_TCPMSS=y +CONFIG_NETFILTER_XT_MATCH_COMMENT=y +CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y +CONFIG_NETFILTER_XT_MATCH_CONNMARK=y +CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y +CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y +CONFIG_NETFILTER_XT_MATCH_HELPER=y +CONFIG_NETFILTER_XT_MATCH_IPRANGE=y +CONFIG_NETFILTER_XT_MATCH_LENGTH=y +CONFIG_NETFILTER_XT_MATCH_LIMIT=y +CONFIG_NETFILTER_XT_MATCH_MAC=y +CONFIG_NETFILTER_XT_MATCH_MARK=y +CONFIG_NETFILTER_XT_MATCH_POLICY=y +CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y +CONFIG_NETFILTER_XT_MATCH_QUOTA=y +CONFIG_NETFILTER_XT_MATCH_QUOTA2=y +CONFIG_NETFILTER_XT_MATCH_STATE=y +CONFIG_NETFILTER_XT_MATCH_STATISTIC=y +CONFIG_NETFILTER_XT_MATCH_STRING=y +CONFIG_NETFILTER_XT_MATCH_TIME=y +CONFIG_NETFILTER_XT_MATCH_U32=y +CONFIG_NF_CONNTRACK_IPV4=y +CONFIG_IP_NF_IPTABLES=y +CONFIG_IP_NF_MATCH_AH=y +CONFIG_IP_NF_MATCH_ECN=y +CONFIG_IP_NF_MATCH_TTL=y +CONFIG_IP_NF_FILTER=y +CONFIG_IP_NF_TARGET_REJECT=y +CONFIG_IP_NF_NAT=y +CONFIG_IP_NF_TARGET_MASQUERADE=y +CONFIG_IP_NF_TARGET_NETMAP=y +CONFIG_IP_NF_TARGET_REDIRECT=y +CONFIG_IP_NF_MANGLE=y +CONFIG_IP_NF_RAW=y +CONFIG_IP_NF_SECURITY=y +CONFIG_IP_NF_ARPTABLES=y +CONFIG_IP_NF_ARPFILTER=y +CONFIG_IP_NF_ARP_MANGLE=y +CONFIG_NF_CONNTRACK_IPV6=y +CONFIG_IP6_NF_IPTABLES=y +CONFIG_IP6_NF_MATCH_IPV6HEADER=y +CONFIG_IP6_NF_MATCH_RPFILTER=y +CONFIG_IP6_NF_FILTER=y +CONFIG_IP6_NF_TARGET_REJECT=y +CONFIG_IP6_NF_MANGLE=y +CONFIG_IP6_NF_RAW=y +CONFIG_NET_SCHED=y +CONFIG_NET_SCH_HTB=y +CONFIG_NET_CLS_U32=y +CONFIG_NET_EMATCH=y +CONFIG_NET_EMATCH_U32=y +CONFIG_NET_CLS_ACT=y +CONFIG_CFG80211=y +CONFIG_MAC80211=y +CONFIG_RFKILL=y +CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" +CONFIG_DEVTMPFS=y +CONFIG_DEBUG_DEVRES=y +CONFIG_OF=y +CONFIG_OF_UNITTEST=y +# CONFIG_PNP_DEBUG_MESSAGES is not set +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=8192 +CONFIG_VIRTIO_BLK=y +CONFIG_UID_SYS_STATS=y +CONFIG_MEMORY_STATE_TIME=y +CONFIG_SCSI=y +CONFIG_BLK_DEV_SD=y +CONFIG_BLK_DEV_SR=y +CONFIG_BLK_DEV_SR_VENDOR=y +CONFIG_CHR_DEV_SG=y +CONFIG_SCSI_CONSTANTS=y +CONFIG_SCSI_SPI_ATTRS=y +CONFIG_SCSI_VIRTIO=y +CONFIG_MD=y +CONFIG_BLK_DEV_DM=y +CONFIG_DM_CRYPT=y +CONFIG_DM_MIRROR=y +CONFIG_DM_ZERO=y +CONFIG_DM_UEVENT=y +CONFIG_DM_VERITY=y +CONFIG_DM_VERITY_FEC=y +CONFIG_NETDEVICES=y +CONFIG_NETCONSOLE=y +CONFIG_NETCONSOLE_DYNAMIC=y +CONFIG_TUN=y +CONFIG_VIRTIO_NET=y +# CONFIG_ETHERNET is not set +CONFIG_PPP=y +CONFIG_PPP_BSDCOMP=y +CONFIG_PPP_DEFLATE=y +CONFIG_PPP_MPPE=y +CONFIG_USB_USBNET=y +# CONFIG_USB_NET_AX8817X is not set +# CONFIG_USB_NET_AX88179_178A is not set +# CONFIG_USB_NET_CDCETHER is not set +# CONFIG_USB_NET_CDC_NCM is not set +# CONFIG_USB_NET_NET1080 is not set +# CONFIG_USB_NET_CDC_SUBSET is not set +# CONFIG_USB_NET_ZAURUS is not set +# CONFIG_WLAN_VENDOR_ADMTEK is not set +# CONFIG_WLAN_VENDOR_ATH is not set +# CONFIG_WLAN_VENDOR_ATMEL is not set +# CONFIG_WLAN_VENDOR_BROADCOM is not set +# CONFIG_WLAN_VENDOR_CISCO is not set +# CONFIG_WLAN_VENDOR_INTEL is not set +# CONFIG_WLAN_VENDOR_INTERSIL is not set +# CONFIG_WLAN_VENDOR_MARVELL is not set +# CONFIG_WLAN_VENDOR_MEDIATEK is not set +# CONFIG_WLAN_VENDOR_RALINK is not set +# CONFIG_WLAN_VENDOR_REALTEK is not set +# CONFIG_WLAN_VENDOR_RSI is not set +# CONFIG_WLAN_VENDOR_ST is not set +# CONFIG_WLAN_VENDOR_TI is not set +# CONFIG_WLAN_VENDOR_ZYDAS is not set +# CONFIG_WLAN_VENDOR_QUANTENNA is not set +CONFIG_MAC80211_HWSIM=y +CONFIG_INPUT_EVDEV=y +CONFIG_INPUT_KEYRESET=y +# CONFIG_INPUT_KEYBOARD is not set +# CONFIG_INPUT_MOUSE is not set +CONFIG_INPUT_JOYSTICK=y +CONFIG_JOYSTICK_XPAD=y +CONFIG_JOYSTICK_XPAD_FF=y +CONFIG_JOYSTICK_XPAD_LEDS=y +CONFIG_INPUT_TABLET=y +CONFIG_TABLET_USB_ACECAD=y +CONFIG_TABLET_USB_AIPTEK=y +CONFIG_TABLET_USB_GTCO=y +CONFIG_TABLET_USB_HANWANG=y +CONFIG_TABLET_USB_KBTAB=y +CONFIG_INPUT_MISC=y +CONFIG_INPUT_KEYCHORD=y +CONFIG_INPUT_UINPUT=y +CONFIG_INPUT_GPIO=y +# CONFIG_SERIO_I8042 is not set +# CONFIG_VT is not set +# CONFIG_LEGACY_PTYS is not set +# CONFIG_DEVMEM is not set +CONFIG_SERIAL_8250=y +# CONFIG_SERIAL_8250_DEPRECATED_OPTIONS is not set +CONFIG_SERIAL_8250_CONSOLE=y +# CONFIG_SERIAL_8250_EXAR is not set +CONFIG_SERIAL_8250_NR_UARTS=48 +CONFIG_SERIAL_8250_EXTENDED=y +CONFIG_SERIAL_8250_MANY_PORTS=y +CONFIG_SERIAL_8250_SHARE_IRQ=y +CONFIG_VIRTIO_CONSOLE=y +CONFIG_HW_RANDOM=y +# CONFIG_HW_RANDOM_INTEL is not set +# CONFIG_HW_RANDOM_AMD is not set +# CONFIG_HW_RANDOM_VIA is not set +CONFIG_HW_RANDOM_VIRTIO=y +CONFIG_HPET=y +# CONFIG_HPET_MMAP_DEFAULT is not set +# CONFIG_DEVPORT is not set +# CONFIG_ACPI_I2C_OPREGION is not set +# CONFIG_I2C_COMPAT is not set +# CONFIG_I2C_HELPER_AUTO is not set +CONFIG_PTP_1588_CLOCK=y +# CONFIG_HWMON is not set +# CONFIG_X86_PKG_TEMP_THERMAL is not set +CONFIG_WATCHDOG=y +CONFIG_SOFT_WATCHDOG=y +CONFIG_MEDIA_SUPPORT=y +# CONFIG_VGA_ARB is not set +CONFIG_DRM=y +# CONFIG_DRM_FBDEV_EMULATION is not set +CONFIG_DRM_VIRTIO_GPU=y +CONFIG_SOUND=y +CONFIG_SND=y +CONFIG_HIDRAW=y +CONFIG_UHID=y +# CONFIG_HID_GENERIC is not set +CONFIG_HID_A4TECH=y +CONFIG_HID_ACRUX=y +CONFIG_HID_ACRUX_FF=y +CONFIG_HID_APPLE=y +CONFIG_HID_BELKIN=y +CONFIG_HID_CHERRY=y +CONFIG_HID_CHICONY=y +CONFIG_HID_PRODIKEYS=y +CONFIG_HID_CYPRESS=y +CONFIG_HID_DRAGONRISE=y +CONFIG_DRAGONRISE_FF=y +CONFIG_HID_EMS_FF=y +CONFIG_HID_ELECOM=y +CONFIG_HID_EZKEY=y +CONFIG_HID_HOLTEK=y +CONFIG_HID_KEYTOUCH=y +CONFIG_HID_KYE=y +CONFIG_HID_UCLOGIC=y +CONFIG_HID_WALTOP=y +CONFIG_HID_GYRATION=y +CONFIG_HID_TWINHAN=y +CONFIG_HID_KENSINGTON=y +CONFIG_HID_LCPOWER=y +CONFIG_HID_LOGITECH=y +CONFIG_HID_LOGITECH_DJ=y +CONFIG_LOGITECH_FF=y +CONFIG_LOGIRUMBLEPAD2_FF=y +CONFIG_LOGIG940_FF=y +CONFIG_HID_MAGICMOUSE=y +CONFIG_HID_MICROSOFT=y +CONFIG_HID_MONTEREY=y +CONFIG_HID_MULTITOUCH=y +CONFIG_HID_NTRIG=y +CONFIG_HID_ORTEK=y +CONFIG_HID_PANTHERLORD=y +CONFIG_PANTHERLORD_FF=y +CONFIG_HID_PETALYNX=y +CONFIG_HID_PICOLCD=y +CONFIG_HID_PRIMAX=y +CONFIG_HID_ROCCAT=y +CONFIG_HID_SAITEK=y +CONFIG_HID_SAMSUNG=y +CONFIG_HID_SONY=y +CONFIG_HID_SPEEDLINK=y +CONFIG_HID_SUNPLUS=y +CONFIG_HID_GREENASIA=y +CONFIG_GREENASIA_FF=y +CONFIG_HID_SMARTJOYPLUS=y +CONFIG_SMARTJOYPLUS_FF=y +CONFIG_HID_TIVO=y +CONFIG_HID_TOPSEED=y +CONFIG_HID_THRUSTMASTER=y +CONFIG_HID_WACOM=y +CONFIG_HID_WIIMOTE=y +CONFIG_HID_ZEROPLUS=y +CONFIG_HID_ZYDACRON=y +CONFIG_USB_HIDDEV=y +CONFIG_USB_ANNOUNCE_NEW_DEVICES=y +CONFIG_USB_EHCI_HCD=y +CONFIG_USB_GADGET=y +CONFIG_USB_DUMMY_HCD=y +CONFIG_USB_CONFIGFS=y +CONFIG_USB_CONFIGFS_F_FS=y +CONFIG_USB_CONFIGFS_F_ACC=y +CONFIG_USB_CONFIGFS_F_AUDIO_SRC=y +CONFIG_USB_CONFIGFS_UEVENT=y +CONFIG_USB_CONFIGFS_F_MIDI=y +CONFIG_RTC_CLASS=y +# CONFIG_RTC_HCTOSYS is not set +CONFIG_SW_SYNC=y +CONFIG_VIRTIO_PCI=y +CONFIG_VIRTIO_BALLOON=y +CONFIG_VIRTIO_MMIO=y +CONFIG_VIRTIO_MMIO_CMDLINE_DEVICES=y +CONFIG_STAGING=y +CONFIG_ASHMEM=y +CONFIG_ANDROID_VSOC=y +CONFIG_ION=y +# CONFIG_X86_PLATFORM_DEVICES is not set +# CONFIG_IOMMU_SUPPORT is not set +CONFIG_ANDROID=y +CONFIG_ANDROID_BINDER_IPC=y +# CONFIG_FIRMWARE_MEMMAP is not set +CONFIG_EXT4_FS=y +CONFIG_EXT4_FS_POSIX_ACL=y +CONFIG_EXT4_FS_SECURITY=y +CONFIG_EXT4_ENCRYPTION=y +CONFIG_QUOTA=y +CONFIG_QUOTA_NETLINK_INTERFACE=y +# CONFIG_PRINT_QUOTA_WARNING is not set +CONFIG_QFMT_V2=y +CONFIG_AUTOFS4_FS=y +CONFIG_MSDOS_FS=y +CONFIG_VFAT_FS=y +CONFIG_PROC_KCORE=y +CONFIG_TMPFS=y +CONFIG_TMPFS_POSIX_ACL=y +CONFIG_HUGETLBFS=y +CONFIG_SDCARD_FS=y +CONFIG_PSTORE=y +CONFIG_PSTORE_CONSOLE=y +CONFIG_PSTORE_RAM=y +CONFIG_NLS_DEFAULT="utf8" +CONFIG_NLS_CODEPAGE_437=y +CONFIG_NLS_ASCII=y +CONFIG_NLS_ISO8859_1=y +CONFIG_NLS_UTF8=y +CONFIG_PRINTK_TIME=y +CONFIG_DEBUG_INFO=y +# CONFIG_ENABLE_WARN_DEPRECATED is not set +# CONFIG_ENABLE_MUST_CHECK is not set +CONFIG_FRAME_WARN=1024 +# CONFIG_UNUSED_SYMBOLS is not set +CONFIG_MAGIC_SYSRQ=y +CONFIG_DEBUG_STACK_USAGE=y +CONFIG_DEBUG_MEMORY_INIT=y +CONFIG_DEBUG_STACKOVERFLOW=y +CONFIG_HARDLOCKUP_DETECTOR=y +CONFIG_PANIC_TIMEOUT=5 +# CONFIG_SCHED_DEBUG is not set +CONFIG_SCHEDSTATS=y +CONFIG_RCU_CPU_STALL_TIMEOUT=60 +CONFIG_ENABLE_DEFAULT_TRACERS=y +# CONFIG_KPROBE_EVENTS is not set +# CONFIG_UPROBE_EVENTS is not set +CONFIG_IO_DELAY_NONE=y +CONFIG_DEBUG_BOOT_PARAMS=y +CONFIG_OPTIMIZE_INLINING=y +CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y +CONFIG_SECURITY=y +CONFIG_SECURITY_NETWORK=y +CONFIG_SECURITY_PATH=y +CONFIG_HARDENED_USERCOPY=y +CONFIG_SECURITY_SELINUX=y +CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE=1 +# CONFIG_CRYPTO_MANAGER_DISABLE_TESTS is not set +CONFIG_CRYPTO_DEV_VIRTIO=y -- GitLab From a6bbdb917e442ef40c11533b404eb7b84b04f32e Mon Sep 17 00:00:00 2001 From: Alistair Strachan Date: Fri, 13 Apr 2018 15:36:37 -0700 Subject: [PATCH 0401/1635] ANDROID: Add build server config for cuttlefish. The build server config can be used with gcc or clang. Specify CC=clang to build with clang. Change-Id: Id346ab1489ecaaef8e9e66b084cc416dd0581f69 Signed-off-by: Alistair Strachan --- build.config.cuttlefish.x86_64 | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 build.config.cuttlefish.x86_64 diff --git a/build.config.cuttlefish.x86_64 b/build.config.cuttlefish.x86_64 new file mode 100644 index 000000000000..36c8a933f843 --- /dev/null +++ b/build.config.cuttlefish.x86_64 @@ -0,0 +1,15 @@ +ARCH=x86_64 +BRANCH=android-4.14 +CLANG_TRIPLE=x86_64-linux-gnu- +CROSS_COMPILE=x86_64-linux-androidkernel- +DEFCONFIG=x86_64_cuttlefish_defconfig +EXTRA_CMDS='' +KERNEL_DIR=common +POST_DEFCONFIG_CMDS="check_defconfig" +CLANG_PREBUILT_BIN=prebuilts/clang/host/linux-x86/clang-4630689/bin +LINUX_GCC_CROSS_COMPILE_PREBUILTS_BIN=prebuilts/gcc/linux-x86/x86/x86_64-linux-android-4.9/bin +FILES=" +arch/x86/boot/bzImage +vmlinux +System.map +" -- GitLab From 876fbb11d014e97a7637c49b162b5360c0d2cd09 Mon Sep 17 00:00:00 2001 From: Bruce Levy Date: Mon, 9 Apr 2018 19:04:52 -0700 Subject: [PATCH 0402/1635] ARM: dts: msm: Add vendor mount node for sdmshrike Add the node to enable early vendor mount for sdmshrike. Change-Id: I50e034bcccf52de186b3fd248939570f93daac19 Signed-off-by: Bruce Levy --- arch/arm64/boot/dts/qcom/sdmshrike.dtsi | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sdmshrike.dtsi b/arch/arm64/boot/dts/qcom/sdmshrike.dtsi index c759e4481014..6b6181ac4bfc 100644 --- a/arch/arm64/boot/dts/qcom/sdmshrike.dtsi +++ b/arch/arm64/boot/dts/qcom/sdmshrike.dtsi @@ -375,6 +375,23 @@ }; }; + firmware: firmware { + android { + compatible = "android,firmware"; + fstab { + compatible = "android,fstab"; + vendor { + compatible = "android,vendor"; + dev = "/dev/block/platform/soc/8804000.sdhci/by-name/vendor"; + type = "ext4"; + mnt_flags = "ro,barrier=1,discard"; + fsmgr_flags = "wait,slotselect"; + status = "ok"; + }; + }; + }; + }; + reserved-memory { #address-cells = <2>; #size-cells = <2>; -- GitLab From cb7be01e7d4a430be921b5fa2f44da376540b8f7 Mon Sep 17 00:00:00 2001 From: Jeevan Shriram Date: Fri, 13 Apr 2018 13:13:28 -0700 Subject: [PATCH 0403/1635] ARM: dts: msm: Add SLPI PIL node for sdmshrike target Add PIL node for SLPI for bringing out SLPI out of reset on sdmshrike target. Change-Id: Ie73b9097dc71a200d6548f58b69d93397164929f Signed-off-by: Jeevan Shriram --- arch/arm64/boot/dts/qcom/sdmshrike.dtsi | 41 +++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sdmshrike.dtsi b/arch/arm64/boot/dts/qcom/sdmshrike.dtsi index c759e4481014..a2d5376c1035 100644 --- a/arch/arm64/boot/dts/qcom/sdmshrike.dtsi +++ b/arch/arm64/boot/dts/qcom/sdmshrike.dtsi @@ -1117,6 +1117,47 @@ qcom,smem-state-names = "qcom,force-stop"; }; + qcom,ssc@5c00000 { + compatible = "qcom,pil-tz-generic"; + reg = <0x5c00000 0x4000>; + + vdd_cx-supply = <&L8E_LEVEL>; + vdd_mx-supply = <&L4E_LEVEL>; + + qcom,proxy-reg-names = "vdd_cx", "vdd_mx"; + qcom,keep-proxy-regs-on; + + clocks = <&clock_rpmh RPMH_CXO_CLK>; + clock-names = "xo"; + qcom,proxy-clock-names = "xo"; + + qcom,pas-id = <12>; + qcom,proxy-timeout-ms = <10000>; + qcom,smem-id = <424>; + qcom,sysmon-id = <3>; + qcom,ssctl-instance-id = <0x16>; + qcom,firmware-name = "slpi"; + status = "ok"; + memory-region = <&pil_slpi_mem>; + + /* Inputs from ssc */ + interrupts-extended = <&pdc 0 494 1>, + <&dsps_smp2p_in 0 0>, + <&dsps_smp2p_in 2 0>, + <&dsps_smp2p_in 1 0>, + <&dsps_smp2p_in 3 0>; + + interrupt-names = "qcom,wdog", + "qcom,err-fatal", + "qcom,proxy-unvote", + "qcom,err-ready", + "qcom,stop-ack"; + + /* Outputs to ssc */ + qcom,smem-states = <&dsps_smp2p_out 0>; + qcom,smem-state-names = "qcom,force-stop"; + }; + wdog: qcom,wdt@17c10000 { compatible = "qcom,msm-watchdog"; reg = <0x17c10000 0x1000>; -- GitLab From 25e4557483f363dfeafa7e3946bbdf9924fbfe85 Mon Sep 17 00:00:00 2001 From: Veera Sundaram Sankaran Date: Tue, 20 Mar 2018 18:25:59 -0700 Subject: [PATCH 0404/1635] drm/msm/sde: avoid disabling clks/bw when cont-splash is enabled Avoid disabling the core clocks and bandwidth vote during crtc disable when continuous splash screen is enabled as it might result in flicker or underrun during the transition from UEFI to kernel. Change-Id: I9299918ada63bb51f490c1d1aa9e94d6d9249db3 Signed-off-by: Veera Sundaram Sankaran --- drivers/gpu/drm/msm/sde/sde_crtc.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/msm/sde/sde_crtc.c b/drivers/gpu/drm/msm/sde/sde_crtc.c index a7c21c111c1c..eee6dfef14fd 100644 --- a/drivers/gpu/drm/msm/sde/sde_crtc.c +++ b/drivers/gpu/drm/msm/sde/sde_crtc.c @@ -4094,6 +4094,7 @@ static void sde_crtc_handle_power_event(u32 event_type, void *arg) static void sde_crtc_disable(struct drm_crtc *crtc) { + struct sde_kms *sde_kms; struct sde_crtc *sde_crtc; struct sde_crtc_state *cstate; struct drm_encoder *encoder; @@ -4109,6 +4110,12 @@ static void sde_crtc_disable(struct drm_crtc *crtc) return; } + sde_kms = _sde_crtc_get_kms(crtc); + if (!sde_kms) { + SDE_ERROR("invalid kms\n"); + return; + } + if (!sde_kms_power_resource_is_enabled(crtc->dev)) { SDE_ERROR("power resource is not enabled\n"); return; @@ -4174,7 +4181,9 @@ static void sde_crtc_disable(struct drm_crtc *crtc) } spin_unlock_irqrestore(&sde_crtc->spin_lock, flags); - sde_core_perf_crtc_update(crtc, 0, true); + /* avoid clk/bw downvote if cont-splash is enabled */ + if (!sde_kms->splash_data.cont_splash_en) + sde_core_perf_crtc_update(crtc, 0, true); drm_for_each_encoder(encoder, crtc->dev) { if (encoder->crtc != crtc) -- GitLab From 69ea22488010c485ecb3e5989144affa2132bc26 Mon Sep 17 00:00:00 2001 From: Veera Sundaram Sankaran Date: Tue, 20 Mar 2018 18:30:01 -0700 Subject: [PATCH 0405/1635] drm/msm/dsi-staging: avoid ctl soft reset when cont-splash is enabled Avoid resetting the dsi ctrl when continuous splash screen is enabled as it might cause flicker during the transition from UEFI to kernel. Change-Id: I0f9a28867fb83c26d39a2212916273cd686d7d23 Signed-off-by: Veera Sundaram Sankaran --- drivers/gpu/drm/msm/dsi-staging/dsi_display.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_display.c b/drivers/gpu/drm/msm/dsi-staging/dsi_display.c index 3c49b79af708..18fbfd925b6b 100644 --- a/drivers/gpu/drm/msm/dsi-staging/dsi_display.c +++ b/drivers/gpu/drm/msm/dsi-staging/dsi_display.c @@ -5033,18 +5033,19 @@ int dsi_display_prepare(struct dsi_display *display) goto error_host_engine_off; } - rc = dsi_display_soft_reset(display); - if (rc) { - pr_err("[%s] failed soft reset, rc=%d\n", display->name, rc); - goto error_ctrl_link_off; - } - if (!display->is_cont_splash_enabled) { /* - * For continuous splash usecase we skip panel - * prepare since the pnael is already in - * active state and panel on commands are not needed + * For continuous splash usecase, skip panel prepare and + * ctl reset since the pnael and ctrl is already in active + * state and panel on commands are not needed */ + rc = dsi_display_soft_reset(display); + if (rc) { + pr_err("[%s] failed soft reset, rc=%d\n", + display->name, rc); + goto error_ctrl_link_off; + } + rc = dsi_panel_prepare(display->panel); if (rc) { pr_err("[%s] panel prepare failed, rc=%d\n", -- GitLab From bef8f4172e1896ea1a3374d7af0008e9f026779f Mon Sep 17 00:00:00 2001 From: Veera Sundaram Sankaran Date: Mon, 5 Feb 2018 12:04:21 -0800 Subject: [PATCH 0406/1635] drm/msm/sde: remove invalid excl_rect validations Remove few excl_rect checks from crtcs atomic_check to avoid invalid failures. Change-Id: If6b787c373c7ea516346ab5ca1857d47d17550c3 Signed-off-by: Veera Sundaram Sankaran --- drivers/gpu/drm/msm/sde/sde_crtc.c | 55 ++++-------------------------- 1 file changed, 7 insertions(+), 48 deletions(-) diff --git a/drivers/gpu/drm/msm/sde/sde_crtc.c b/drivers/gpu/drm/msm/sde/sde_crtc.c index a7c21c111c1c..b0d4d75985d3 100644 --- a/drivers/gpu/drm/msm/sde/sde_crtc.c +++ b/drivers/gpu/drm/msm/sde/sde_crtc.c @@ -4329,46 +4329,6 @@ static int pstate_cmp(const void *a, const void *b) return rc; } -static int _sde_crtc_excl_rect_overlap_check(struct plane_state pstates[], - int cnt, int curr_cnt, struct sde_rect *excl_rect) -{ - struct sde_rect dst_rect, intersect; - int i, rc = -EINVAL; - const struct drm_plane_state *pstate; - - for (i = 0; i < cnt; i++) { - if (i == curr_cnt) - continue; - - pstate = pstates[i].drm_pstate; - POPULATE_RECT(&dst_rect, pstate->crtc_x, pstate->crtc_y, - pstate->crtc_w, pstate->crtc_h, false); - sde_kms_rect_intersect(&dst_rect, excl_rect, &intersect); - - /* complete intersection of excl_rect is required */ - if (intersect.w == excl_rect->w && intersect.h == excl_rect->h - /* intersecting rect should be in another z_order */ - && pstates[curr_cnt].stage != pstates[i].stage) { - rc = 0; - goto end; - } - } - - SDE_ERROR( - "no overlapping rect for [%d] z_pos:%d, excl_rect:{%d,%d,%d,%d}\n", - i, pstates[curr_cnt].stage, - excl_rect->x, excl_rect->y, excl_rect->w, excl_rect->h); - for (i = 0; i < cnt; i++) { - pstate = pstates[i].drm_pstate; - SDE_ERROR("[%d] p:%d, z_pos:%d, src:{%d,%d,%d,%d}\n", - i, pstate->plane->base.id, pstates[i].stage, - pstate->crtc_x, pstate->crtc_y, - pstate->crtc_w, pstate->crtc_h); - } -end: - return rc; -} - /* no input validation - caller API has all the checks */ static int _sde_crtc_excl_dim_layer_check(struct drm_crtc_state *state, struct plane_state pstates[], int cnt) @@ -4401,17 +4361,16 @@ static int _sde_crtc_excl_dim_layer_check(struct drm_crtc_state *state, } } - /* this is traversing on sorted z-order pstates */ + /* log all src and excl_rect, useful for debugging */ for (i = 0; i < cnt; i++) { pstate = pstates[i].drm_pstate; sde_pstate = to_sde_plane_state(pstate); - if (sde_pstate->excl_rect.w && sde_pstate->excl_rect.h) { - /* check overlap on any other z-order */ - rc = _sde_crtc_excl_rect_overlap_check(pstates, cnt, - i, &sde_pstate->excl_rect); - if (rc) - goto end; - } + SDE_DEBUG("p %d z %d src{%d,%d,%d,%d} excl_rect{%d,%d,%d,%d}\n", + pstate->plane->base.id, pstates[i].stage, + pstate->crtc_x, pstate->crtc_y, + pstate->crtc_w, pstate->crtc_h, + sde_pstate->excl_rect.x, sde_pstate->excl_rect.y, + sde_pstate->excl_rect.w, sde_pstate->excl_rect.h); } end: -- GitLab From 5d13333ba0f333014dfa8af50e11bf701d319029 Mon Sep 17 00:00:00 2001 From: Hemant Kumar Date: Thu, 2 Mar 2017 15:30:08 -0800 Subject: [PATCH 0407/1635] usb: gadget: f_qdss: Add support for mdm qdss channel Driver needs to pass qdss data received from mdm qdss bridge driver to host PC. This requires a software data path using IN endpoint. Bridge driver needs to open qdss_mdm channel and use exported write() API to pass the qdss data received from mdm. Driver calls the notify call back upon write completion. Change-Id: I4d8ceaed0bf9c85aa17d3f49503cd690917cc117 Signed-off-by: Hemant Kumar --- drivers/usb/gadget/function/f_qdss.c | 144 ++++++++++++++++++++++----- drivers/usb/gadget/function/f_qdss.h | 4 + include/linux/usb/usb_qdss.h | 3 + 3 files changed, 126 insertions(+), 25 deletions(-) diff --git a/drivers/usb/gadget/function/f_qdss.c b/drivers/usb/gadget/function/f_qdss.c index 63e127163d49..f00b301fb089 100644 --- a/drivers/usb/gadget/function/f_qdss.c +++ b/drivers/usb/gadget/function/f_qdss.c @@ -183,15 +183,28 @@ struct usb_qdss_opts *to_fi_usb_qdss_opts(struct usb_function_instance *fi) } /*----------------------------------------------------------------------*/ -static void qdss_ctrl_write_complete(struct usb_ep *ep, +static void qdss_write_complete(struct usb_ep *ep, struct usb_request *req) { struct f_qdss *qdss = ep->driver_data; struct qdss_request *d_req = req->context; + struct usb_ep *in; + struct list_head *list_pool; + enum qdss_state state; unsigned long flags; pr_debug("%s\n", __func__); + if (qdss->debug_inface_enabled) { + in = qdss->port.ctrl_in; + list_pool = &qdss->ctrl_write_pool; + state = USB_QDSS_CTRL_WRITE_DONE; + } else { + in = qdss->port.data; + list_pool = &qdss->data_write_pool; + state = USB_QDSS_DATA_WRITE_DONE; + } + if (!req->status) { /* send zlp */ if ((req->length >= ep->maxpacket) && @@ -199,13 +212,13 @@ static void qdss_ctrl_write_complete(struct usb_ep *ep, req->length = 0; d_req->actual = req->actual; d_req->status = req->status; - if (!usb_ep_queue(qdss->port.ctrl_in, req, GFP_ATOMIC)) + if (!usb_ep_queue(in, req, GFP_ATOMIC)) return; } } spin_lock_irqsave(&qdss->lock, flags); - list_add_tail(&req->list, &qdss->ctrl_write_pool); + list_add_tail(&req->list, list_pool); if (req->length != 0) { d_req->actual = req->actual; d_req->status = req->status; @@ -213,8 +226,7 @@ static void qdss_ctrl_write_complete(struct usb_ep *ep, spin_unlock_irqrestore(&qdss->lock, flags); if (qdss->ch.notify) - qdss->ch.notify(qdss->ch.priv, USB_QDSS_CTRL_WRITE_DONE, d_req, - NULL); + qdss->ch.notify(qdss->ch.priv, state, d_req, NULL); } static void qdss_ctrl_read_complete(struct usb_ep *ep, @@ -252,6 +264,12 @@ void usb_qdss_free_req(struct usb_qdss_ch *ch) return; } + list_for_each_safe(act, tmp, &qdss->data_write_pool) { + req = list_entry(act, struct usb_request, list); + list_del(&req->list); + usb_ep_free_request(qdss->port.data, req); + } + list_for_each_safe(act, tmp, &qdss->ctrl_write_pool) { req = list_entry(act, struct usb_request, list); list_del(&req->list); @@ -271,23 +289,41 @@ int usb_qdss_alloc_req(struct usb_qdss_ch *ch, int no_write_buf, { struct f_qdss *qdss = ch->priv_usb; struct usb_request *req; + struct usb_ep *in; + struct list_head *list_pool; int i; pr_debug("%s\n", __func__); - if (no_write_buf <= 0 || no_read_buf <= 0 || !qdss) { + if (!qdss) { + pr_err("%s: %s closed\n", __func__, ch->name); + return -ENODEV; + } + + if ((qdss->debug_inface_enabled && + (no_write_buf <= 0 || no_read_buf <= 0)) || + (!qdss->debug_inface_enabled && + (no_write_buf <= 0 || no_read_buf))) { pr_err("%s: missing params\n", __func__); return -ENODEV; } + if (qdss->debug_inface_enabled) { + in = qdss->port.ctrl_in; + list_pool = &qdss->ctrl_write_pool; + } else { + in = qdss->port.data; + list_pool = &qdss->data_write_pool; + } + for (i = 0; i < no_write_buf; i++) { - req = usb_ep_alloc_request(qdss->port.ctrl_in, GFP_ATOMIC); + req = usb_ep_alloc_request(in, GFP_ATOMIC); if (!req) { pr_err("%s: ctrl_in allocation err\n", __func__); goto fail; } - req->complete = qdss_ctrl_write_complete; - list_add_tail(&req->list, &qdss->ctrl_write_pool); + req->complete = qdss_write_complete; + list_add_tail(&req->list, list_pool); } for (i = 0; i < no_read_buf; i++) { @@ -378,6 +414,10 @@ static int qdss_bind(struct usb_configuration *c, struct usb_function *f) qdss_ctrl_intf_desc.iInterface = id; } + /* for non-accelerated path keep tx fifo size 1k */ + if (!strcmp(qdss->ch.name, USB_QDSS_CH_MDM)) + qdss_data_ep_comp_desc.bMaxBurst = 0; + ep = usb_ep_autoconfig_ss(gadget, &qdss_ss_data_desc, &qdss_data_ep_comp_desc); if (!ep) { @@ -491,21 +531,20 @@ static void usb_qdss_disconnect_work(struct work_struct *work) qdss = container_of(work, struct f_qdss, disconnect_w); pr_debug("%s\n", __func__); - /* - * Uninitialized init data i.e. ep specific operation. - * Notify qdss to cancel all active transfers. - */ - if (qdss->ch.app_conn) { + + /* Notify qdss to cancel all active transfers */ + if (qdss->ch.notify) + qdss->ch.notify(qdss->ch.priv, + USB_QDSS_DISCONNECT, + NULL, + NULL); + + /* Uninitialized init data i.e. ep specific operation */ + if (qdss->ch.app_conn && !strcmp(qdss->ch.name, USB_QDSS_CH_MSM)) { status = uninit_data(qdss->port.data); if (status) pr_err("%s: uninit_data error\n", __func__); - if (qdss->ch.notify) - qdss->ch.notify(qdss->ch.priv, - USB_QDSS_DISCONNECT, - NULL, - NULL); - status = set_qdss_data_connection(qdss, 0); if (status) pr_err("qdss_disconnect error"); @@ -562,15 +601,16 @@ static void usb_qdss_connect_work(struct work_struct *work) } pr_debug("%s\n", __func__); + + if (!strcmp(qdss->ch.name, USB_QDSS_CH_MDM)) + goto notify; + status = set_qdss_data_connection(qdss, 1); if (status) { pr_err("set_qdss_data_connection error(%d)", status); return; } - if (qdss->ch.notify) - qdss->ch.notify(qdss->ch.priv, USB_QDSS_CONNECT, - NULL, &qdss->ch); spin_lock_irqsave(&qdss->lock, flags); req = qdss->endless_req; spin_unlock_irqrestore(&qdss->lock, flags); @@ -578,8 +618,15 @@ static void usb_qdss_connect_work(struct work_struct *work) return; status = usb_ep_queue(qdss->port.data, req, GFP_ATOMIC); - if (status) + if (status) { pr_err("%s: usb_ep_queue error (%d)\n", __func__, status); + return; + } + +notify: + if (qdss->ch.notify) + qdss->ch.notify(qdss->ch.priv, USB_QDSS_CONNECT, + NULL, &qdss->ch); } static int qdss_set_alt(struct usb_function *f, unsigned int intf, @@ -722,6 +769,7 @@ static struct f_qdss *alloc_usb_qdss(char *channel_name) spin_lock_init(&qdss->lock); INIT_LIST_HEAD(&qdss->ctrl_read_pool); INIT_LIST_HEAD(&qdss->ctrl_write_pool); + INIT_LIST_HEAD(&qdss->data_write_pool); INIT_WORK(&qdss->connect_w, usb_qdss_connect_work); INIT_WORK(&qdss->disconnect_w, usb_qdss_disconnect_work); @@ -817,6 +865,50 @@ int usb_qdss_ctrl_write(struct usb_qdss_ch *ch, struct qdss_request *d_req) } EXPORT_SYMBOL(usb_qdss_ctrl_write); +int usb_qdss_write(struct usb_qdss_ch *ch, struct qdss_request *d_req) +{ + struct f_qdss *qdss = ch->priv_usb; + unsigned long flags; + struct usb_request *req = NULL; + + pr_debug("usb_qdss_ctrl_write\n"); + + if (!qdss) + return -ENODEV; + + spin_lock_irqsave(&qdss->lock, flags); + + if (qdss->usb_connected == 0) { + spin_unlock_irqrestore(&qdss->lock, flags); + return -EIO; + } + + if (list_empty(&qdss->data_write_pool)) { + pr_err("error: usb_qdss_data_write list is empty\n"); + spin_unlock_irqrestore(&qdss->lock, flags); + return -EAGAIN; + } + + req = list_first_entry(&qdss->data_write_pool, struct usb_request, + list); + list_del(&req->list); + spin_unlock_irqrestore(&qdss->lock, flags); + + req->buf = d_req->buf; + req->length = d_req->length; + req->context = d_req; + if (usb_ep_queue(qdss->port.data, req, GFP_ATOMIC)) { + spin_lock_irqsave(&qdss->lock, flags); + list_add_tail(&req->list, &qdss->data_write_pool); + spin_unlock_irqrestore(&qdss->lock, flags); + pr_err("qdss usb_ep_queue failed\n"); + return -EIO; + } + + return 0; +} +EXPORT_SYMBOL(usb_qdss_write); + struct usb_qdss_ch *usb_qdss_open(const char *name, void *priv, void (*notify)(void *priv, unsigned int event, struct qdss_request *d_req, struct usb_qdss_ch *)) @@ -874,7 +966,9 @@ void usb_qdss_close(struct usb_qdss_ch *ch) pr_debug("%s\n", __func__); spin_lock_irqsave(&qdss_lock, flags); - if (!qdss || !qdss->usb_connected) { + ch->priv_usb = NULL; + if (!qdss || !qdss->usb_connected || + !strcmp(qdss->ch.name, USB_QDSS_CH_MDM)) { ch->app_conn = 0; spin_unlock_irqrestore(&qdss_lock, flags); return; diff --git a/drivers/usb/gadget/function/f_qdss.h b/drivers/usb/gadget/function/f_qdss.h index 72edb9094eba..57c76f887618 100644 --- a/drivers/usb/gadget/function/f_qdss.h +++ b/drivers/usb/gadget/function/f_qdss.h @@ -59,6 +59,10 @@ struct f_qdss { struct usb_qdss_ch ch; struct list_head ctrl_read_pool; struct list_head ctrl_write_pool; + + /* for mdm channel SW path */ + struct list_head data_write_pool; + struct work_struct connect_w; struct work_struct disconnect_w; spinlock_t lock; diff --git a/include/linux/usb/usb_qdss.h b/include/linux/usb/usb_qdss.h index b58d8ee6d5aa..fe626c18b483 100644 --- a/include/linux/usb/usb_qdss.h +++ b/include/linux/usb/usb_qdss.h @@ -15,6 +15,9 @@ #include +#define USB_QDSS_CH_MDM "qdss_mdm" +#define USB_QDSS_CH_MSM "qdss" + struct qdss_request { char *buf; int length; -- GitLab From 195114a505c2477ff425905684af84b7a905edc8 Mon Sep 17 00:00:00 2001 From: Soheil Hassas Yeganeh Date: Sat, 14 Apr 2018 20:45:20 -0400 Subject: [PATCH 0408/1635] tcp: clear tp->packets_out when purging write queue Clear tp->packets_out when purging the write queue, otherwise tcp_rearm_rto() mistakenly assumes TCP write queue is not empty. This results in NULL pointer dereference. Also, remove the redundant `tp->packets_out = 0` from tcp_disconnect(), since tcp_disconnect() calls tcp_write_queue_purge(). CRs-Fixed: 2224545 Change-Id: I26f00abdd7fcfc6cdb30d89811ccf7be90f8186f Fixes: a27fd7a8ed38 (tcp: purge write queue upon RST) Reported-by: Subash Abhinov Kasiviswanathan Reported-by: Sami Farin Tested-by: Sami Farin Signed-off-by: Eric Dumazet Signed-off-by: Soheil Hassas Yeganeh Acked-by: Yuchung Cheng Acked-by: Neal Cardwell Patch-mainline: netdev @ April 15, 2018, 12:45 a.m. Signed-off-by: Subash Abhinov Kasiviswanathan --- include/net/tcp.h | 1 + net/ipv4/tcp.c | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/include/net/tcp.h b/include/net/tcp.h index f99d17c9540b..71082ba003d7 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -1617,6 +1617,7 @@ static inline void tcp_write_queue_purge(struct sock *sk) sk_mem_reclaim(sk); tcp_clear_all_retrans_hints(tcp_sk(sk)); tcp_init_send_head(sk); + tcp_sk(sk)->packets_out = 0; } static inline struct sk_buff *tcp_write_queue_head(const struct sock *sk) diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 38b9a6276a9d..4dda8d301802 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -2354,7 +2354,6 @@ int tcp_disconnect(struct sock *sk, int flags) icsk->icsk_backoff = 0; tp->snd_cwnd = 2; icsk->icsk_probes_out = 0; - tp->packets_out = 0; tp->snd_ssthresh = TCP_INFINITE_SSTHRESH; tp->snd_cwnd_cnt = 0; tp->window_clamp = 0; -- GitLab From 37faac857d58da1edf6e0d04d414ad2a79e342da Mon Sep 17 00:00:00 2001 From: Mulu He Date: Thu, 12 Apr 2018 17:23:07 +0800 Subject: [PATCH 0409/1635] ARM: dts: msm: Enable coresight prng tpdm for sm8150 Add tpdm_prng device node, it is new hw for sm8150.Fix issue in funnel_lpass_1,funnel_dl_mm1,funnel_turing_1 device config, *_1 node is duplicated funnel. Change-Id: If9f0a86462c7b5a1e841ab440e2db5a1d02acabc Signed-off-by: Mulu He --- .../arm64/boot/dts/qcom/sm8150-coresight.dtsi | 48 +++++++++++++++---- 1 file changed, 40 insertions(+), 8 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sm8150-coresight.dtsi b/arch/arm64/boot/dts/qcom/sm8150-coresight.dtsi index 9cee609dfe77..8247f89057c8 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-coresight.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-coresight.dtsi @@ -762,6 +762,15 @@ }; port@8 { + reg = <10>; + tpda_in_tpdm_prng: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_prng_out_tpda>; + }; + }; + + port@9 { reg = <13>; tpda_in_tpdm_pimem: endpoint { slave-mode; @@ -770,7 +779,7 @@ }; }; - port@9 { + port@10 { reg = <14>; tpda_in_tpdm_npu: endpoint { slave-mode; @@ -875,8 +884,9 @@ compatible = "arm,primecell"; arm,primecell-periphid = <0x0003b908>; - reg = <0x6846000 0x1000>; - reg-names = "funnel-base"; + reg = <0x6867020 0x10>, + <0x6846000 0x1000>; + reg-names = "funnel-base-dummy", "funnel-base-real"; coresight-name = "coresight-funnel-lpass-1"; @@ -1092,6 +1102,24 @@ }; }; + tpdm_prng: tpdm@684c000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + reg = <0x684c000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-prng"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + tpdm_prng_out_tpda: endpoint { + remote-endpoint = <&tpda_in_tpdm_prng>; + }; + }; + }; + funnel_spss: funnel@6883000 { compatible = "arm,primecell"; arm,primecell-periphid = <0x0003b908>; @@ -1398,18 +1426,21 @@ }; }; - funnel_dl_mm1: funnel@6c0b000 { + funnel_dl_mm1: funnel_1@6c0b000 { compatible = "arm,primecell"; arm,primecell-periphid = <0x0003b908>; - reg = <0x6c0b000 0x1000>; - reg-names = "funnel-base"; + reg = <0x6867000 0x10>, + <0x6c0b000 0x1000>; + reg-names = "funnel-base-dummy", "funnel-base-real"; coresight-name = "coresight-funnel-dl-mm1"; clocks = <&clock_aop QDSS_CLK>; clock-names = "apb_pclk"; + qcom,duplicate-funnel; + ports { #address-cells = <1>; #size-cells = <0>; @@ -1492,8 +1523,9 @@ compatible = "arm,primecell"; arm,primecell-periphid = <0x0003b908>; - reg = <0x6861000 0x1000>; - reg-names = "funnel-base"; + reg = <0x6867010 0x10>, + <0x6861000 0x1000>; + reg-names = "funnel-base-dummy", "funnel-base-real"; coresight-name = "coresight-funnel-turing-1"; -- GitLab From 89b7e992f78ea3a05e10ace36d84bb75519dfa50 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Mon, 8 Jan 2018 14:35:52 -0800 Subject: [PATCH 0410/1635] rcu: Create RCU-specific workqueues with rescuers RCU's expedited grace periods can participate in out-of-memory deadlocks due to all available system_wq kthreads being blocked and there not being memory available to create more. This commit prevents such deadlocks by allocating an RCU-specific workqueue_struct at early boot time, and providing it with a rescuer to ensure forward progress. This uses the shiny new init_rescuer() function provided by Tejun (but indirectly). This commit also causes SRCU to use this new RCU-specific workqueue_struct. Note that SRCU's use of workqueues never blocks them waiting for readers, so this should be safe from a forward-progress viewpoint. Note that this moves SRCU from system_power_efficient_wq to a normal workqueue. In the unlikely event that this results in measurable degradation, a separate power-efficient workqueue will be creates for SRCU. Change-Id: I2988819b553b769ccfdeabd62394c3aad63d6668 Reported-by: Prateek Sood Reported-by: Tejun Heo Signed-off-by: Paul E. McKenney Acked-by: Tejun Heo Git-commit: ad7c946b35ad455417fdd4bc0e17deda4011841b Git-Repo: git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git Signed-off-by: Prateek Sood --- kernel/rcu/rcu.h | 1 + kernel/rcu/srcutree.c | 8 +++----- kernel/rcu/tree.c | 6 ++++++ kernel/rcu/tree_exp.h | 2 +- 4 files changed, 11 insertions(+), 6 deletions(-) diff --git a/kernel/rcu/rcu.h b/kernel/rcu/rcu.h index e4b43fef89f5..a2bd180c7193 100644 --- a/kernel/rcu/rcu.h +++ b/kernel/rcu/rcu.h @@ -474,6 +474,7 @@ void show_rcu_gp_kthreads(void); void rcu_force_quiescent_state(void); void rcu_bh_force_quiescent_state(void); void rcu_sched_force_quiescent_state(void); +extern struct workqueue_struct *rcu_gp_wq; #endif /* #else #ifdef CONFIG_TINY_RCU */ #ifdef CONFIG_RCU_NOCB_CPU diff --git a/kernel/rcu/srcutree.c b/kernel/rcu/srcutree.c index 6d5880089ff6..3050ebd824e4 100644 --- a/kernel/rcu/srcutree.c +++ b/kernel/rcu/srcutree.c @@ -465,8 +465,7 @@ static bool srcu_queue_delayed_work_on(int cpu, struct workqueue_struct *wq, */ static void srcu_schedule_cbs_sdp(struct srcu_data *sdp, unsigned long delay) { - srcu_queue_delayed_work_on(sdp->cpu, system_power_efficient_wq, - &sdp->work, delay); + srcu_queue_delayed_work_on(sdp->cpu, rcu_gp_wq, &sdp->work, delay); } /* @@ -664,8 +663,7 @@ static void srcu_funnel_gp_start(struct srcu_struct *sp, struct srcu_data *sdp, rcu_seq_state(sp->srcu_gp_seq) == SRCU_STATE_IDLE) { WARN_ON_ONCE(ULONG_CMP_GE(sp->srcu_gp_seq, sp->srcu_gp_seq_needed)); srcu_gp_start(sp); - queue_delayed_work(system_power_efficient_wq, &sp->work, - srcu_get_delay(sp)); + queue_delayed_work(rcu_gp_wq, &sp->work, srcu_get_delay(sp)); } raw_spin_unlock_irqrestore_rcu_node(sp, flags); } @@ -1198,7 +1196,7 @@ static void srcu_reschedule(struct srcu_struct *sp, unsigned long delay) raw_spin_unlock_irq_rcu_node(sp); if (pushgp) - queue_delayed_work(system_power_efficient_wq, &sp->work, delay); + queue_delayed_work(rcu_gp_wq, &sp->work, delay); } /* diff --git a/kernel/rcu/tree.c b/kernel/rcu/tree.c index 40e261f82f40..2001ed6f6c5b 100644 --- a/kernel/rcu/tree.c +++ b/kernel/rcu/tree.c @@ -4176,6 +4176,8 @@ static void __init rcu_dump_rcu_node_tree(struct rcu_state *rsp) pr_cont("\n"); } +struct workqueue_struct *rcu_gp_wq; + void __init rcu_init(void) { int cpu; @@ -4203,6 +4205,10 @@ void __init rcu_init(void) if (IS_ENABLED(CONFIG_TREE_SRCU)) srcu_online_cpu(cpu); } + + /* Create workqueue for expedited GPs and for Tree SRCU. */ + rcu_gp_wq = alloc_workqueue("rcu_gp", WQ_MEM_RECLAIM, 0); + WARN_ON(!rcu_gp_wq); } #include "tree_exp.h" diff --git a/kernel/rcu/tree_exp.h b/kernel/rcu/tree_exp.h index 46d61b597731..a0ffc56bfc8a 100644 --- a/kernel/rcu/tree_exp.h +++ b/kernel/rcu/tree_exp.h @@ -606,7 +606,7 @@ static void _synchronize_rcu_expedited(struct rcu_state *rsp, rew.rew_rsp = rsp; rew.rew_s = s; INIT_WORK_ONSTACK(&rew.rew_work, wait_rcu_exp_gp); - schedule_work(&rew.rew_work); + queue_work(rcu_gp_wq, &rew.rew_work); } /* Wait for expedited grace period to complete. */ -- GitLab From eaf58ade21790b16e6b771bac42c2f2b6849c7e8 Mon Sep 17 00:00:00 2001 From: Prateek Sood Date: Sat, 14 Apr 2018 19:51:49 +0530 Subject: [PATCH 0411/1635] defconfig: sdm: Update defconfig for sdm640 Update defconfig for sdm640 to be in sync with sm8150. Change-Id: I17d4353a6cfdf80bd6407b23a93e101d093cb330 Signed-off-by: Prateek Sood --- arch/arm64/configs/sdmsteppe-perf_defconfig | 60 ++++++++++++++++-- arch/arm64/configs/sdmsteppe_defconfig | 68 ++++++++++++++++++--- 2 files changed, 115 insertions(+), 13 deletions(-) diff --git a/arch/arm64/configs/sdmsteppe-perf_defconfig b/arch/arm64/configs/sdmsteppe-perf_defconfig index 4e0728e8e4e2..43ddf66f2a0f 100644 --- a/arch/arm64/configs/sdmsteppe-perf_defconfig +++ b/arch/arm64/configs/sdmsteppe-perf_defconfig @@ -15,6 +15,8 @@ CONFIG_RCU_NOCB_CPU=y CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y CONFIG_LOG_CPU_MAX_BUF_SHIFT=17 +CONFIG_MEMCG=y +CONFIG_MEMCG_SWAP=y CONFIG_RT_GROUP_SCHED=y CONFIG_CGROUP_FREEZER=y CONFIG_CPUSETS=y @@ -64,6 +66,8 @@ CONFIG_SECCOMP=y # CONFIG_HARDEN_BRANCH_PREDICTOR is not set CONFIG_ARMV8_DEPRECATED=y CONFIG_SWP_EMULATION=y +CONFIG_CP15_BARRIER_EMULATION=y +CONFIG_SETEND_EMULATION=y # CONFIG_ARM64_VHE is not set CONFIG_RANDOMIZE_BASE=y # CONFIG_EFI is not set @@ -90,6 +94,7 @@ CONFIG_XFRM_USER=y CONFIG_XFRM_STATISTICS=y CONFIG_NET_KEY=y CONFIG_INET=y +CONFIG_IP_MULTICAST=y CONFIG_IP_ADVANCED_ROUTER=y CONFIG_IP_MULTIPLE_TABLES=y CONFIG_IP_ROUTE_VERBOSE=y @@ -125,6 +130,7 @@ CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y CONFIG_NETFILTER_XT_TARGET_CONNMARK=y CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=y CONFIG_NETFILTER_XT_TARGET_IDLETIMER=y +CONFIG_NETFILTER_XT_TARGET_HARDIDLETIMER=y CONFIG_NETFILTER_XT_TARGET_LOG=y CONFIG_NETFILTER_XT_TARGET_MARK=y CONFIG_NETFILTER_XT_TARGET_NFLOG=y @@ -154,12 +160,14 @@ CONFIG_NETFILTER_XT_MATCH_POLICY=y CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y CONFIG_NETFILTER_XT_MATCH_QUOTA=y CONFIG_NETFILTER_XT_MATCH_QUOTA2=y +CONFIG_NETFILTER_XT_MATCH_SOCKET=y CONFIG_NETFILTER_XT_MATCH_STATE=y CONFIG_NETFILTER_XT_MATCH_STATISTIC=y CONFIG_NETFILTER_XT_MATCH_STRING=y CONFIG_NETFILTER_XT_MATCH_TIME=y CONFIG_NETFILTER_XT_MATCH_U32=y CONFIG_NF_CONNTRACK_IPV4=y +CONFIG_NF_SOCKET_IPV4=y CONFIG_IP_NF_IPTABLES=y CONFIG_IP_NF_MATCH_AH=y CONFIG_IP_NF_MATCH_ECN=y @@ -178,6 +186,7 @@ CONFIG_IP_NF_ARPTABLES=y CONFIG_IP_NF_ARPFILTER=y CONFIG_IP_NF_ARP_MANGLE=y CONFIG_NF_CONNTRACK_IPV6=y +CONFIG_NF_SOCKET_IPV6=y CONFIG_IP6_NF_IPTABLES=y CONFIG_IP6_NF_MATCH_RPFILTER=y CONFIG_IP6_NF_FILTER=y @@ -215,11 +224,13 @@ CONFIG_QRTR_SMD=y CONFIG_RMNET_DATA=y CONFIG_RMNET_DATA_FC=y CONFIG_RMNET_DATA_DEBUG_PKT=y +CONFIG_SOCKEV_NLMCAST=y CONFIG_BT=y CONFIG_MSM_BT_POWER=y CONFIG_CFG80211=y CONFIG_CFG80211_INTERNAL_REGDB=y CONFIG_RFKILL=y +CONFIG_NFC_NQ=y CONFIG_FW_LOADER_USER_HELPER_FALLBACK=y CONFIG_REGMAP_ALLOW_WRITE_DEBUGFS=y CONFIG_DMA_CMA=y @@ -235,12 +246,10 @@ CONFIG_BLK_DEV_SD=y CONFIG_CHR_DEV_SG=y CONFIG_CHR_DEV_SCH=y CONFIG_SCSI_CONSTANTS=y -CONFIG_SCSI_LOGGING=y CONFIG_SCSI_SCAN_ASYNC=y CONFIG_SCSI_UFSHCD=y CONFIG_SCSI_UFSHCD_PLATFORM=y CONFIG_SCSI_UFS_QCOM=y -CONFIG_SCSI_UFSHCD_CMD_LOGGING=y CONFIG_MD=y CONFIG_BLK_DEV_DM=y CONFIG_DM_UEVENT=y @@ -274,6 +283,7 @@ CONFIG_KEYBOARD_GPIO=y # CONFIG_INPUT_MOUSE is not set CONFIG_INPUT_TOUCHSCREEN=y CONFIG_INPUT_MISC=y +CONFIG_INPUT_HBTP_INPUT=y CONFIG_INPUT_QPNP_POWER_ON=y CONFIG_INPUT_UINPUT=y # CONFIG_SERIO_SERPORT is not set @@ -282,6 +292,7 @@ CONFIG_INPUT_UINPUT=y # CONFIG_DEVMEM is not set CONFIG_SERIAL_MSM_GENI=y CONFIG_HW_RANDOM=y +CONFIG_HW_RANDOM_MSM_LEGACY=y CONFIG_DIAG_CHAR=y CONFIG_MSM_ADSPRPC=y CONFIG_I2C_CHARDEV=y @@ -302,6 +313,7 @@ CONFIG_POWER_RESET_QCOM=y CONFIG_QCOM_DLOAD_MODE=y CONFIG_POWER_RESET_XGENE=y CONFIG_POWER_RESET_SYSCON=y +CONFIG_QPNP_FG_GEN4=y CONFIG_QPNP_SMB5=y CONFIG_THERMAL=y CONFIG_THERMAL_WRITABLE_TRIPS=y @@ -314,7 +326,10 @@ CONFIG_THERMAL_TSENS=y CONFIG_QTI_THERMAL_LIMITS_DCVS=y CONFIG_QTI_VIRTUAL_SENSOR=y CONFIG_QTI_AOP_REG_COOLING_DEVICE=y +CONFIG_QTI_QMI_COOLING_DEVICE=y CONFIG_REGULATOR_COOLING_DEVICE=y +CONFIG_QTI_BCL_PMIC5=y +CONFIG_QTI_BCL_SOC_DRIVER=y CONFIG_MFD_SPMI_PMIC=y CONFIG_REGULATOR_FIXED_VOLTAGE=y CONFIG_REGULATOR_QPNP_LCDB=y @@ -336,8 +351,10 @@ CONFIG_MSM_SDE_ROTATOR_EVTLOG_DEBUG=y CONFIG_MSM_NPU=y CONFIG_DRM=y CONFIG_DRM_MSM_REGISTER_LOGGING=y +CONFIG_DRM_SDE_EVTLOG_DEBUG=y CONFIG_DRM_SDE_RSC=y CONFIG_FB_ARMCLCD=y +CONFIG_BACKLIGHT_QCOM_SPMI_WLED=y CONFIG_LOGO=y # CONFIG_LOGO_LINUX_MONO is not set # CONFIG_LOGO_LINUX_VGA16 is not set @@ -349,7 +366,11 @@ CONFIG_SND_USB_AUDIO_QMI=y CONFIG_SND_SOC=y CONFIG_UHID=y CONFIG_HID_APPLE=y +CONFIG_HID_ELECOM=y +CONFIG_HID_MAGICMOUSE=y CONFIG_HID_MICROSOFT=y +CONFIG_HID_MULTITOUCH=y +CONFIG_HID_PLANTRONICS=y CONFIG_USB=y CONFIG_USB_ANNOUNCE_NEW_DEVICES=y CONFIG_USB_XHCI_HCD=y @@ -359,6 +380,7 @@ CONFIG_USB_OHCI_HCD=y CONFIG_USB_OHCI_HCD_PLATFORM=y CONFIG_USB_STORAGE=y CONFIG_USB_DWC3=y +CONFIG_USB_DWC3_MSM=y CONFIG_USB_ISP1760=y CONFIG_USB_ISP1760_HOST_ROLE=y CONFIG_NOP_USB_XCEIV=y @@ -367,7 +389,7 @@ CONFIG_USB_MSM_SSPHY_QMP=y CONFIG_MSM_HSUSB_PHY=y CONFIG_DUAL_ROLE_USB_INTF=y CONFIG_USB_GADGET=y -CONFIG_USB_GADGET_VBUS_DRAW=500 +CONFIG_USB_GADGET_VBUS_DRAW=900 CONFIG_USB_CONFIGFS=y CONFIG_USB_CONFIGFS_NCM=y CONFIG_USB_CONFIGFS_MASS_STORAGE=y @@ -382,17 +404,26 @@ CONFIG_USB_CONFIGFS_F_HID=y CONFIG_USB_CONFIGFS_F_DIAG=y CONFIG_USB_CONFIGFS_F_CDEV=y CONFIG_USB_CONFIGFS_F_CCID=y +CONFIG_USB_CONFIGFS_F_GSI=y +CONFIG_USB_CONFIGFS_F_QDSS=y CONFIG_USB_PD_POLICY=y CONFIG_QPNP_USB_PDPHY=y CONFIG_MMC=y +CONFIG_MMC_PERF_PROFILING=y CONFIG_MMC_BLOCK_MINORS=32 +CONFIG_MMC_BLOCK_DEFERRED_RESUME=y CONFIG_MMC_TEST=y +CONFIG_MMC_PARANOID_SD_INIT=y +CONFIG_MMC_CLKGATE=y CONFIG_MMC_SDHCI=y CONFIG_MMC_SDHCI_PLTFM=y CONFIG_MMC_SDHCI_MSM=y CONFIG_NEW_LEDS=y CONFIG_LEDS_CLASS=y CONFIG_LEDS_QPNP_FLASH_V2=y +CONFIG_LEDS_QPNP_HAPTICS=y +CONFIG_LEDS_QTI_TRI_LED=y +CONFIG_LEDS_TRIGGER_TIMER=y CONFIG_EDAC=y CONFIG_EDAC_KRYO_ARM64=y CONFIG_EDAC_KRYO_ARM64_PANIC_ON_CE=y @@ -410,6 +441,7 @@ CONFIG_QCOM_GENI_SE=y CONFIG_QPNP_REVID=y CONFIG_SPS=y CONFIG_SPS_SUPPORT_NDP_BAM=y +CONFIG_USB_BAM=y CONFIG_IPA3=y CONFIG_IPA_WDI_UNIFIED_API=y CONFIG_RMNET_IPA3=y @@ -440,6 +472,8 @@ CONFIG_IOMMU_DEBUG_TRACKING=y CONFIG_IOMMU_TESTS=y CONFIG_RPMSG_CHAR=y CONFIG_RPMSG_QCOM_GLINK_SMEM=y +CONFIG_RPMSG_QCOM_GLINK_SPSS=y +CONFIG_QCOM_CPUSS_DUMP=y CONFIG_QCOM_RUN_QUEUE_STATS=y CONFIG_QCOM_LLCC=y CONFIG_QCOM_SDM640_LLCC=y @@ -455,9 +489,12 @@ CONFIG_MSM_SUBSYSTEM_RESTART=y CONFIG_MSM_PIL=y CONFIG_MSM_SYSMON_QMI_COMM=y CONFIG_MSM_PIL_SSR_GENERIC=y +CONFIG_MSM_BOOT_STATS=y CONFIG_QCOM_DCC_V2=y CONFIG_QCOM_SECURE_BUFFER=y CONFIG_ICNSS=y +CONFIG_ICNSS_QMI=y +CONFIG_QCOM_EUD=y CONFIG_QCOM_BUS_SCALING=y CONFIG_QCOM_BUS_CONFIG_RPMH=y CONFIG_QCOM_COMMAND_DB=y @@ -465,8 +502,12 @@ CONFIG_QCOM_EARLY_RANDOM=y CONFIG_QTI_RPMH_API=y CONFIG_QCOM_GLINK=y CONFIG_QCOM_GLINK_PKT=y +CONFIG_MSM_CDSP_LOADER=y CONFIG_MSM_EVENT_TIMER=y CONFIG_MSM_PM=y +CONFIG_QCOM_FSA4480_I2C=y +CONFIG_MSM_PERFORMANCE=y +CONFIG_QMP_DEBUGFS_CLIENT=y CONFIG_DEVFREQ_GOV_PASSIVE=y CONFIG_QCOM_BIMC_BWMON=y CONFIG_ARM_MEMLAT_MON=y @@ -477,20 +518,26 @@ CONFIG_DEVFREQ_GOV_QCOM_CACHE_HWMON=y CONFIG_DEVFREQ_GOV_MEMLAT=y CONFIG_DEVFREQ_SIMPLE_DEV=y CONFIG_QCOM_DEVFREQ_DEVBW=y +CONFIG_EXTCON_USB_GPIO=y CONFIG_IIO=y CONFIG_QCOM_SPMI_ADC5=y CONFIG_PWM=y +CONFIG_PWM_QTI_LPG=y +CONFIG_QCOM_KGSL=y CONFIG_ARM_GIC_V3_ACL=y CONFIG_QCOM_LLCC_PMU=y CONFIG_RAS=y CONFIG_ANDROID=y CONFIG_ANDROID_BINDER_IPC=y +CONFIG_NVMEM_SPMI_SDAM=y +CONFIG_SENSORS_SSC=y CONFIG_ESOC=y CONFIG_ESOC_DEV=y CONFIG_ESOC_CLIENT=y CONFIG_ESOC_MDM_4x=y CONFIG_ESOC_MDM_DRV=y CONFIG_ESOC_MDM_DBG_ENG=y +CONFIG_MSM_TZ_LOG=y CONFIG_EXT2_FS=y CONFIG_EXT2_FS_XATTR=y CONFIG_EXT3_FS=y @@ -503,6 +550,7 @@ CONFIG_VFAT_FS=y CONFIG_TMPFS_POSIX_ACL=y CONFIG_ECRYPT_FS=y CONFIG_ECRYPT_FS_MESSAGING=y +CONFIG_SDCARD_FS=y CONFIG_NLS_CODEPAGE_437=y CONFIG_NLS_ISO8859_1=y CONFIG_PRINTK_TIME=y @@ -523,6 +571,8 @@ CONFIG_CORESIGHT_TPDA=y CONFIG_CORESIGHT_TPDM=y CONFIG_CORESIGHT_HWEVENT=y CONFIG_CORESIGHT_DUMMY=y +CONFIG_CORESIGHT_REMOTE_ETM=y +CONFIG_CORESIGHT_REMOTE_ETM_DEFAULT_ENABLE=0 CONFIG_CORESIGHT_EVENT=y CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y CONFIG_SECURITY=y @@ -534,7 +584,9 @@ CONFIG_CRYPTO_XCBC=y CONFIG_CRYPTO_MD4=y CONFIG_CRYPTO_TWOFISH=y CONFIG_CRYPTO_ANSI_CPRNG=y -CONFIG_CRYPTO_DEV_QCE=y +CONFIG_CRYPTO_DEV_QCOM_MSM_QCE=y +CONFIG_CRYPTO_DEV_QCRYPTO=y +CONFIG_CRYPTO_DEV_QCEDEV=y CONFIG_ARM64_CRYPTO=y CONFIG_CRYPTO_SHA1_ARM64_CE=y CONFIG_CRYPTO_SHA2_ARM64_CE=y diff --git a/arch/arm64/configs/sdmsteppe_defconfig b/arch/arm64/configs/sdmsteppe_defconfig index 20e542df881a..b727134b2f70 100644 --- a/arch/arm64/configs/sdmsteppe_defconfig +++ b/arch/arm64/configs/sdmsteppe_defconfig @@ -14,6 +14,8 @@ CONFIG_RCU_NOCB_CPU=y CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y CONFIG_LOG_CPU_MAX_BUF_SHIFT=17 +CONFIG_MEMCG=y +CONFIG_MEMCG_SWAP=y CONFIG_RT_GROUP_SCHED=y CONFIG_CGROUP_FREEZER=y CONFIG_CPUSETS=y @@ -95,6 +97,7 @@ CONFIG_XFRM_USER=y CONFIG_XFRM_STATISTICS=y CONFIG_NET_KEY=y CONFIG_INET=y +CONFIG_IP_MULTICAST=y CONFIG_IP_ADVANCED_ROUTER=y CONFIG_IP_MULTIPLE_TABLES=y CONFIG_IP_ROUTE_VERBOSE=y @@ -130,6 +133,7 @@ CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y CONFIG_NETFILTER_XT_TARGET_CONNMARK=y CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=y CONFIG_NETFILTER_XT_TARGET_IDLETIMER=y +CONFIG_NETFILTER_XT_TARGET_HARDIDLETIMER=y CONFIG_NETFILTER_XT_TARGET_LOG=y CONFIG_NETFILTER_XT_TARGET_MARK=y CONFIG_NETFILTER_XT_TARGET_NFLOG=y @@ -159,12 +163,14 @@ CONFIG_NETFILTER_XT_MATCH_POLICY=y CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y CONFIG_NETFILTER_XT_MATCH_QUOTA=y CONFIG_NETFILTER_XT_MATCH_QUOTA2=y +CONFIG_NETFILTER_XT_MATCH_SOCKET=y CONFIG_NETFILTER_XT_MATCH_STATE=y CONFIG_NETFILTER_XT_MATCH_STATISTIC=y CONFIG_NETFILTER_XT_MATCH_STRING=y CONFIG_NETFILTER_XT_MATCH_TIME=y CONFIG_NETFILTER_XT_MATCH_U32=y CONFIG_NF_CONNTRACK_IPV4=y +CONFIG_NF_SOCKET_IPV4=y CONFIG_IP_NF_IPTABLES=y CONFIG_IP_NF_MATCH_AH=y CONFIG_IP_NF_MATCH_ECN=y @@ -183,6 +189,7 @@ CONFIG_IP_NF_ARPTABLES=y CONFIG_IP_NF_ARPFILTER=y CONFIG_IP_NF_ARP_MANGLE=y CONFIG_NF_CONNTRACK_IPV6=y +CONFIG_NF_SOCKET_IPV6=y CONFIG_IP6_NF_IPTABLES=y CONFIG_IP6_NF_MATCH_RPFILTER=y CONFIG_IP6_NF_FILTER=y @@ -222,12 +229,14 @@ CONFIG_QRTR_SMD=y CONFIG_RMNET_DATA=y CONFIG_RMNET_DATA_FC=y CONFIG_RMNET_DATA_DEBUG_PKT=y +CONFIG_SOCKEV_NLMCAST=y CONFIG_BT=y CONFIG_MSM_BT_POWER=y CONFIG_CFG80211=y CONFIG_CFG80211_INTERNAL_REGDB=y # CONFIG_CFG80211_CRDA_SUPPORT is not set CONFIG_RFKILL=y +CONFIG_NFC_NQ=y CONFIG_FW_LOADER_USER_HELPER_FALLBACK=y CONFIG_REGMAP_ALLOW_WRITE_DEBUGFS=y CONFIG_DMA_CMA=y @@ -272,6 +281,7 @@ CONFIG_PPPOLAC=y CONFIG_PPPOPNS=y CONFIG_PPP_ASYNC=y CONFIG_PPP_SYNC_TTY=y +CONFIG_WIL6210=m CONFIG_WCNSS_MEM_PRE_ALLOC=y CONFIG_CLD_LL_CORE=y CONFIG_INPUT_EVDEV=y @@ -280,6 +290,7 @@ CONFIG_KEYBOARD_GPIO=y CONFIG_INPUT_JOYSTICK=y CONFIG_INPUT_TOUCHSCREEN=y CONFIG_INPUT_MISC=y +CONFIG_INPUT_HBTP_INPUT=y CONFIG_INPUT_QPNP_POWER_ON=y CONFIG_INPUT_UINPUT=y # CONFIG_SERIO_SERPORT is not set @@ -290,6 +301,7 @@ CONFIG_SERIAL_MSM_GENI_CONSOLE=y CONFIG_SERIAL_DEV_BUS=y CONFIG_TTY_PRINTK=y CONFIG_HW_RANDOM=y +CONFIG_HW_RANDOM_MSM_LEGACY=y CONFIG_DIAG_CHAR=y CONFIG_MSM_ADSPRPC=y CONFIG_I2C_CHARDEV=y @@ -310,6 +322,7 @@ CONFIG_POWER_RESET_QCOM=y CONFIG_QCOM_DLOAD_MODE=y CONFIG_POWER_RESET_XGENE=y CONFIG_POWER_RESET_SYSCON=y +CONFIG_QPNP_FG_GEN4=y CONFIG_QPNP_SMB5=y CONFIG_THERMAL=y CONFIG_THERMAL_WRITABLE_TRIPS=y @@ -322,7 +335,10 @@ CONFIG_THERMAL_TSENS=y CONFIG_QTI_THERMAL_LIMITS_DCVS=y CONFIG_QTI_VIRTUAL_SENSOR=y CONFIG_QTI_AOP_REG_COOLING_DEVICE=y +CONFIG_QTI_QMI_COOLING_DEVICE=y CONFIG_REGULATOR_COOLING_DEVICE=y +CONFIG_QTI_BCL_PMIC5=y +CONFIG_QTI_BCL_SOC_DRIVER=y CONFIG_MFD_SPMI_PMIC=y CONFIG_REGULATOR_FIXED_VOLTAGE=y CONFIG_REGULATOR_QPNP_LCDB=y @@ -344,10 +360,12 @@ CONFIG_MSM_SDE_ROTATOR_EVTLOG_DEBUG=y CONFIG_MSM_NPU=y CONFIG_DRM=y CONFIG_DRM_MSM_REGISTER_LOGGING=y +CONFIG_DRM_SDE_EVTLOG_DEBUG=y CONFIG_DRM_SDE_RSC=y CONFIG_FB_VIRTUAL=y CONFIG_BACKLIGHT_LCD_SUPPORT=y CONFIG_BACKLIGHT_CLASS_DEVICE=y +CONFIG_BACKLIGHT_QCOM_SPMI_WLED=y CONFIG_LOGO=y # CONFIG_LOGO_LINUX_MONO is not set # CONFIG_LOGO_LINUX_VGA16 is not set @@ -359,7 +377,11 @@ CONFIG_SND_USB_AUDIO_QMI=y CONFIG_SND_SOC=y CONFIG_UHID=y CONFIG_HID_APPLE=y +CONFIG_HID_ELECOM=y +CONFIG_HID_MAGICMOUSE=y CONFIG_HID_MICROSOFT=y +CONFIG_HID_MULTITOUCH=y +CONFIG_HID_PLANTRONICS=y CONFIG_USB=y CONFIG_USB_ANNOUNCE_NEW_DEVICES=y CONFIG_USB_XHCI_HCD=y @@ -369,6 +391,7 @@ CONFIG_USB_OHCI_HCD=y CONFIG_USB_OHCI_HCD_PLATFORM=y CONFIG_USB_STORAGE=y CONFIG_USB_DWC3=y +CONFIG_USB_DWC3_MSM=y CONFIG_USB_ISP1760=y CONFIG_USB_ISP1760_HOST_ROLE=y CONFIG_NOP_USB_XCEIV=y @@ -377,7 +400,7 @@ CONFIG_USB_MSM_SSPHY_QMP=y CONFIG_MSM_HSUSB_PHY=y CONFIG_DUAL_ROLE_USB_INTF=y CONFIG_USB_GADGET=y -CONFIG_USB_GADGET_VBUS_DRAW=500 +CONFIG_USB_GADGET_VBUS_DRAW=900 CONFIG_USB_CONFIGFS=y CONFIG_USB_CONFIGFS_NCM=y CONFIG_USB_CONFIGFS_MASS_STORAGE=y @@ -392,17 +415,27 @@ CONFIG_USB_CONFIGFS_F_HID=y CONFIG_USB_CONFIGFS_F_DIAG=y CONFIG_USB_CONFIGFS_F_CDEV=y CONFIG_USB_CONFIGFS_F_CCID=y +CONFIG_USB_CONFIGFS_F_GSI=y +CONFIG_USB_CONFIGFS_F_QDSS=y CONFIG_USB_PD_POLICY=y CONFIG_QPNP_USB_PDPHY=y CONFIG_MMC=y +CONFIG_MMC_PERF_PROFILING=y CONFIG_MMC_BLOCK_MINORS=32 +CONFIG_MMC_BLOCK_DEFERRED_RESUME=y CONFIG_MMC_TEST=y +CONFIG_MMC_RING_BUFFER=y +CONFIG_MMC_PARANOID_SD_INIT=y +CONFIG_MMC_CLKGATE=y CONFIG_MMC_SDHCI=y CONFIG_MMC_SDHCI_PLTFM=y CONFIG_MMC_SDHCI_MSM=y CONFIG_NEW_LEDS=y CONFIG_LEDS_CLASS=y CONFIG_LEDS_QPNP_FLASH_V2=y +CONFIG_LEDS_QPNP_HAPTICS=y +CONFIG_LEDS_QTI_TRI_LED=y +CONFIG_LEDS_TRIGGER_TIMER=y CONFIG_EDAC=y CONFIG_EDAC_KRYO_ARM64=y CONFIG_EDAC_KRYO_ARM64_PANIC_ON_CE=y @@ -424,6 +457,7 @@ CONFIG_QCOM_GENI_SE=y CONFIG_QPNP_REVID=y CONFIG_SPS=y CONFIG_SPS_SUPPORT_NDP_BAM=y +CONFIG_USB_BAM=y CONFIG_IPA3=y CONFIG_IPA_WDI_UNIFIED_API=y CONFIG_RMNET_IPA3=y @@ -454,6 +488,8 @@ CONFIG_IOMMU_DEBUG_TRACKING=y CONFIG_IOMMU_TESTS=y CONFIG_RPMSG_CHAR=y CONFIG_RPMSG_QCOM_GLINK_SMEM=y +CONFIG_RPMSG_QCOM_GLINK_SPSS=y +CONFIG_QCOM_CPUSS_DUMP=y CONFIG_QCOM_RUN_QUEUE_STATS=y CONFIG_QCOM_LLCC=y CONFIG_QCOM_SDM640_LLCC=y @@ -465,28 +501,28 @@ CONFIG_QCOM_FORCE_WDOG_BITE_ON_PANIC=y CONFIG_QCOM_WDOG_IPI_ENABLE=y CONFIG_QCOM_SMP2P=y CONFIG_MSM_SERVICE_LOCATOR=y -CONFIG_MSM_SERVICE_NOTIFIER=y -CONFIG_MSM_SUBSYSTEM_RESTART=y -CONFIG_MSM_PIL=y -CONFIG_MSM_SYSMON_QMI_COMM=y -CONFIG_MSM_PIL_SSR_GENERIC=y +CONFIG_MSM_BOOT_STATS=y CONFIG_MSM_CORE_HANG_DETECT=y CONFIG_QCOM_DCC_V2=y CONFIG_MSM_GLADIATOR_HANG_DETECT=y CONFIG_QCOM_SECURE_BUFFER=y CONFIG_ICNSS=y CONFIG_ICNSS_DEBUG=y +CONFIG_ICNSS_QMI=y +CONFIG_QCOM_EUD=y CONFIG_QCOM_BUS_SCALING=y CONFIG_QCOM_BUS_CONFIG_RPMH=y CONFIG_QCOM_COMMAND_DB=y CONFIG_QCOM_EARLY_RANDOM=y -CONFIG_MSM_SPSS_UTILS=y CONFIG_QTI_RPMH_API=y CONFIG_QCOM_GLINK=y CONFIG_QCOM_GLINK_PKT=y +CONFIG_MSM_CDSP_LOADER=y CONFIG_MSM_EVENT_TIMER=y CONFIG_MSM_PM=y CONFIG_QCOM_FSA4480_I2C=y +CONFIG_MSM_PERFORMANCE=y +CONFIG_QMP_DEBUGFS_CLIENT=y CONFIG_DEVFREQ_GOV_PASSIVE=y CONFIG_QCOM_BIMC_BWMON=y CONFIG_ARM_MEMLAT_MON=y @@ -497,17 +533,20 @@ CONFIG_DEVFREQ_GOV_QCOM_CACHE_HWMON=y CONFIG_DEVFREQ_GOV_MEMLAT=y CONFIG_DEVFREQ_SIMPLE_DEV=y CONFIG_QCOM_DEVFREQ_DEVBW=y +CONFIG_EXTCON_USB_GPIO=y CONFIG_IIO=y CONFIG_QCOM_SPMI_ADC5=y CONFIG_PWM=y +CONFIG_PWM_QTI_LPG=y CONFIG_QCOM_KGSL=y CONFIG_ARM_GIC_V3_ACL=y -CONFIG_QTI_PDC_SM8150=y CONFIG_PHY_XGENE=y CONFIG_QCOM_LLCC_PMU=y CONFIG_RAS=y CONFIG_ANDROID=y CONFIG_ANDROID_BINDER_IPC=y +CONFIG_NVMEM_SPMI_SDAM=y +CONFIG_SENSORS_SSC=y CONFIG_ESOC=y CONFIG_ESOC_DEV=y CONFIG_ESOC_CLIENT=y @@ -515,6 +554,7 @@ CONFIG_ESOC_DEBUG=y CONFIG_ESOC_MDM_4x=y CONFIG_ESOC_MDM_DRV=y CONFIG_ESOC_MDM_DBG_ENG=y +CONFIG_MSM_TZ_LOG=y CONFIG_EXT2_FS=y CONFIG_EXT2_FS_XATTR=y CONFIG_EXT3_FS=y @@ -528,6 +568,7 @@ CONFIG_TMPFS_POSIX_ACL=y CONFIG_EFIVAR_FS=y CONFIG_ECRYPT_FS=y CONFIG_ECRYPT_FS_MESSAGING=y +CONFIG_SDCARD_FS=y # CONFIG_NETWORK_FILESYSTEMS is not set CONFIG_NLS_CODEPAGE_437=y CONFIG_NLS_ISO8859_1=y @@ -565,9 +606,11 @@ CONFIG_SCHED_STACK_END_CHECK=y CONFIG_DEBUG_SPINLOCK=y CONFIG_DEBUG_MUTEXES=y CONFIG_DEBUG_ATOMIC_SLEEP=y +CONFIG_LOCK_TORTURE_TEST=m CONFIG_DEBUG_SG=y CONFIG_DEBUG_NOTIFIERS=y CONFIG_DEBUG_CREDENTIALS=y +CONFIG_RCU_TORTURE_TEST=m CONFIG_FAULT_INJECTION=y CONFIG_FAIL_PAGE_ALLOC=y CONFIG_UFS_FAULT_INJECTION=y @@ -580,6 +623,9 @@ CONFIG_FUNCTION_TRACER=y CONFIG_IRQSOFF_TRACER=y CONFIG_PREEMPT_TRACER=y CONFIG_BLK_DEV_IO_TRACE=y +CONFIG_LKDTM=m +CONFIG_ATOMIC64_SELFTEST=m +CONFIG_TEST_USER_COPY=m CONFIG_MEMTEST=y CONFIG_BUG_ON_DATA_CORRUPTION=y CONFIG_PID_IN_CONTEXTIDR=y @@ -594,6 +640,8 @@ CONFIG_CORESIGHT_TPDA=y CONFIG_CORESIGHT_TPDM=y CONFIG_CORESIGHT_HWEVENT=y CONFIG_CORESIGHT_DUMMY=y +CONFIG_CORESIGHT_REMOTE_ETM=y +CONFIG_CORESIGHT_REMOTE_ETM_DEFAULT_ENABLE=0 CONFIG_CORESIGHT_TGU=y CONFIG_CORESIGHT_EVENT=y CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y @@ -607,7 +655,9 @@ CONFIG_CRYPTO_XCBC=y CONFIG_CRYPTO_MD4=y CONFIG_CRYPTO_TWOFISH=y CONFIG_CRYPTO_ANSI_CPRNG=y -CONFIG_CRYPTO_DEV_QCE=y +CONFIG_CRYPTO_DEV_QCOM_MSM_QCE=y +CONFIG_CRYPTO_DEV_QCRYPTO=y +CONFIG_CRYPTO_DEV_QCEDEV=y CONFIG_ARM64_CRYPTO=y CONFIG_CRYPTO_SHA1_ARM64_CE=y CONFIG_CRYPTO_SHA2_ARM64_CE=y -- GitLab From db7cd6ea70d44af3d479b7d4549046ac76acdaaf Mon Sep 17 00:00:00 2001 From: Shefali Jain Date: Thu, 12 Apr 2018 16:12:22 +0530 Subject: [PATCH 0412/1635] clk: qcom: alpha-pll: Add support to adjust postdiv factor in slew ops There could be a requirement where the PLL postdiv is being set by either HW or SW. In those cases the frequency of the PLL fout = fin/postdiv and the check for VCO range would result in a failure. Adjust the frequency with the post div value before the VCO range check. Change-Id: I5cd556b5af7eb7936b157521096658aae4d1ebf3 Signed-off-by: Shefali Jain --- drivers/clk/qcom/clk-alpha-pll.c | 33 +++++++++++++++++++++++++++----- 1 file changed, 28 insertions(+), 5 deletions(-) diff --git a/drivers/clk/qcom/clk-alpha-pll.c b/drivers/clk/qcom/clk-alpha-pll.c index ee80e6ee0021..b3c680049b99 100644 --- a/drivers/clk/qcom/clk-alpha-pll.c +++ b/drivers/clk/qcom/clk-alpha-pll.c @@ -1498,8 +1498,9 @@ static int clk_alpha_pll_slew_set_rate(struct clk_hw *hw, unsigned long rate, struct clk_alpha_pll *pll = to_clk_alpha_pll(hw); unsigned long freq_hz; const struct pll_vco *curr_vco, *vco; - u32 l; + u32 l, ctl; u64 a; + int i = 0; freq_hz = alpha_pll_round_rate(pll, rate, parent_rate, &l, &a); if (freq_hz != rate) { @@ -1507,7 +1508,18 @@ static int clk_alpha_pll_slew_set_rate(struct clk_hw *hw, unsigned long rate, return -EINVAL; } - curr_vco = alpha_pll_find_vco(pll, clk_hw_get_rate(hw)); + regmap_read(pll->clkr.regmap, pll->offset + PLL_USER_CTL, &ctl); + ctl >>= PLL_POST_DIV_SHIFT; + ctl &= PLL_POST_DIV_MASK; + + for (i = 0; i < ARRAY_SIZE(clk_alpha_div_table); i++) { + if (clk_alpha_div_table[i].val == ctl) + break; + } + + if (i < ARRAY_SIZE(clk_alpha_div_table)) + curr_vco = alpha_pll_find_vco(pll, clk_hw_get_rate(hw) * + clk_alpha_div_table[i].div); if (!curr_vco) { pr_err("alpha pll: not in a valid vco range\n"); return -EINVAL; @@ -1553,8 +1565,8 @@ static int clk_alpha_pll_calibrate(struct clk_hw *hw) struct clk_hw *parent; const struct pll_vco *vco; u64 a; - u32 l; - int rc; + u32 l, ctl; + int rc, i = 0; parent = clk_hw_get_parent(hw); if (!parent) { @@ -1562,7 +1574,18 @@ static int clk_alpha_pll_calibrate(struct clk_hw *hw) return -EINVAL; } - vco = alpha_pll_find_vco(pll, clk_hw_get_rate(hw)); + regmap_read(pll->clkr.regmap, pll->offset + PLL_USER_CTL, &ctl); + ctl >>= PLL_POST_DIV_SHIFT; + ctl &= PLL_POST_DIV_MASK; + + for (i = 0; i < ARRAY_SIZE(clk_alpha_div_table); i++) { + if (clk_alpha_div_table[i].val == ctl) + break; + } + + if (i < ARRAY_SIZE(clk_alpha_div_table)) + vco = alpha_pll_find_vco(pll, clk_hw_get_rate(hw) * + clk_alpha_div_table[i].div); if (!vco) { pr_err("alpha pll: not in a valid vco range\n"); return -EINVAL; -- GitLab From 8f5cb16ccb161e39f5001ecc795f2b29bd469924 Mon Sep 17 00:00:00 2001 From: Lina Iyer Date: Thu, 29 Mar 2018 16:46:47 -0600 Subject: [PATCH 0413/1635] drivers: cpuidle: lpm-levels: plug in cpu bias Fill in the function is_cpu_biased() with actual data from the scheduler. Change-Id: I5a9a9181b0e7e61d0bd7d3b0d87a93762c4c217d Signed-off-by: Lina Iyer --- drivers/cpuidle/lpm-levels.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/cpuidle/lpm-levels.c b/drivers/cpuidle/lpm-levels.c index 116b1a9e5eea..9d759c95b963 100644 --- a/drivers/cpuidle/lpm-levels.c +++ b/drivers/cpuidle/lpm-levels.c @@ -36,6 +36,7 @@ #include #include #include +#include #include #include #include @@ -581,7 +582,13 @@ static void update_history(struct cpuidle_device *dev, int idx); static inline bool is_cpu_biased(int cpu) { - return false; + u64 now = sched_clock(); + u64 last = sched_get_cpu_last_busy_time(cpu); + + if (!last) + return false; + + return (now - last) < BIAS_HYST; } static int cpu_power_select(struct cpuidle_device *dev, -- GitLab From a6ce1cc96d323f5c99631e77603c630abc5cc637 Mon Sep 17 00:00:00 2001 From: Carter Cooper Date: Tue, 10 Apr 2018 09:39:25 -0600 Subject: [PATCH 0414/1635] msm: kgsl: Remove extra performance vote This vote is no longer needed in the bootup sequence so remove it. Change-Id: I179090e51c1e9a05406018e01b3343d3154ccbe0 Signed-off-by: Carter Cooper --- drivers/gpu/msm/kgsl_hfi.c | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/drivers/gpu/msm/kgsl_hfi.c b/drivers/gpu/msm/kgsl_hfi.c index 83364bcc75ba..2af527d16b93 100644 --- a/drivers/gpu/msm/kgsl_hfi.c +++ b/drivers/gpu/msm/kgsl_hfi.c @@ -404,17 +404,6 @@ static int hfi_send_feature_ctrls(struct gmu_device *gmu) return 0; } -static int hfi_send_init_perf_vote(struct gmu_device *gmu) -{ - struct hfi_gx_bw_perf_vote_cmd req = { - .ack_type = DCVS_ACK_BLOCK, - .freq = 2, - .bw = 2, - }; - - return hfi_send_req(gmu, H2F_MSG_GX_BW_PERF_VOTE, &req); -} - static int hfi_send_dcvstbl(struct gmu_device *gmu) { struct hfi_dcvstable_cmd cmd = { @@ -647,11 +636,6 @@ int hfi_start(struct gmu_device *gmu, uint32_t boot_state) result = hfi_send_core_fw_start(gmu); if (result) return result; - - /* Force a vote with initial values */ - result = hfi_send_init_perf_vote(gmu); - if (result) - return result; } else { /* * Tell the GMU we are sending no more HFIs -- GitLab From 6a95433a4f8530bab7214e4f05cb6d5f052e173e Mon Sep 17 00:00:00 2001 From: Swathi Sridhar Date: Mon, 16 Apr 2018 10:52:33 -0700 Subject: [PATCH 0415/1635] ARM: dts: msm: Remove regulator votes in the compute_dsp TBUs in sdmshrike Remove the regulator votes in the compute_dsp TBUs in sdmshrike since votes necessary for the regulators are taken care by the bus drivers. Change-Id: I8fb4f24af9bb1b9ad53a08e5e27d6748f4634c2b Signed-off-by: Swathi Sridhar --- arch/arm64/boot/dts/qcom/msm-arm-smmu-sdmshrike.dtsi | 4 ---- 1 file changed, 4 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/msm-arm-smmu-sdmshrike.dtsi b/arch/arm64/boot/dts/qcom/msm-arm-smmu-sdmshrike.dtsi index 478012739507..5b773252cf2c 100644 --- a/arch/arm64/boot/dts/qcom/msm-arm-smmu-sdmshrike.dtsi +++ b/arch/arm64/boot/dts/qcom/msm-arm-smmu-sdmshrike.dtsi @@ -322,8 +322,6 @@ <0x15182220 0x8>; reg-names = "base", "status-reg"; qcom,stream-id-range = <0x1000 0x400>; - qcom,regulator-names = "vdd"; - vdd-supply = <&hlos1_vote_turing_mmu_tbu1_gdsc>; qcom,msm-bus,name = "apps_smmu"; qcom,msm-bus,num-cases = <2>; qcom,msm-bus,active-only; @@ -343,8 +341,6 @@ <0x15182228 0x8>; reg-names = "base", "status-reg"; qcom,stream-id-range = <0x1400 0x400>; - qcom,regulator-names = "vdd"; - vdd-supply = <&hlos1_vote_turing_mmu_tbu0_gdsc>; qcom,msm-bus,name = "apps_smmu"; qcom,msm-bus,num-cases = <2>; qcom,msm-bus,active-only; -- GitLab From 424013358b2afb8980ad9816bf1ffd7b6ac719a9 Mon Sep 17 00:00:00 2001 From: Ashay Jaiswal Date: Wed, 7 Mar 2018 18:25:43 +0530 Subject: [PATCH 0416/1635] power: smb5: update IRQ configuration Update IRQ handlers for all charger peripheral to ensure only required IRQ handlers are registered. While at it, configure few IRQs as wakeup capable. Change-Id: I04f6017a4940baa2539c007d6f17427b2b4db86f Signed-off-by: Ashay Jaiswal --- drivers/power/supply/qcom/qpnp-smb5.c | 40 ++++++--------------------- 1 file changed, 8 insertions(+), 32 deletions(-) diff --git a/drivers/power/supply/qcom/qpnp-smb5.c b/drivers/power/supply/qcom/qpnp-smb5.c index 1b0e1cbb4b6e..9d04b317d05a 100644 --- a/drivers/power/supply/qcom/qpnp-smb5.c +++ b/drivers/power/supply/qcom/qpnp-smb5.c @@ -1716,30 +1716,25 @@ static struct smb_irq_info smb5_irqs[] = { [CHG_STATE_CHANGE_IRQ] = { .name = "chg-state-change", .handler = chg_state_change_irq_handler, + .wake = true, }, [STEP_CHG_STATE_CHANGE_IRQ] = { .name = "step-chg-state-change", - .handler = default_irq_handler, }, [STEP_CHG_SOC_UPDATE_FAIL_IRQ] = { .name = "step-chg-soc-update-fail", - .handler = default_irq_handler, }, [STEP_CHG_SOC_UPDATE_REQ_IRQ] = { .name = "step-chg-soc-update-req", - .handler = default_irq_handler, }, [FG_FVCAL_QUALIFIED_IRQ] = { .name = "fg-fvcal-qualified", - .handler = default_irq_handler, }, [VPH_ALARM_IRQ] = { .name = "vph-alarm", - .handler = default_irq_handler, }, [VPH_DROP_PRECHG_IRQ] = { .name = "vph-drop-prechg", - .handler = default_irq_handler, }, /* DCDC IRQs */ [OTG_FAIL_IRQ] = { @@ -1748,19 +1743,17 @@ static struct smb_irq_info smb5_irqs[] = { }, [OTG_OC_DISABLE_SW_IRQ] = { .name = "otg-oc-disable-sw", - .handler = default_irq_handler, }, [OTG_OC_HICCUP_IRQ] = { .name = "otg-oc-hiccup", - .handler = default_irq_handler, }, [BSM_ACTIVE_IRQ] = { .name = "bsm-active", - .handler = default_irq_handler, }, [HIGH_DUTY_CYCLE_IRQ] = { .name = "high-duty-cycle", .handler = high_duty_cycle_irq_handler, + .wake = true, }, [INPUT_CURRENT_LIMITING_IRQ] = { .name = "input-current-limiting", @@ -1768,7 +1761,6 @@ static struct smb_irq_info smb5_irqs[] = { }, [CONCURRENT_MODE_DISABLE_IRQ] = { .name = "concurrent-mode-disable", - .handler = default_irq_handler, }, [SWITCHER_POWER_OK_IRQ] = { .name = "switcher-power-ok", @@ -1778,10 +1770,10 @@ static struct smb_irq_info smb5_irqs[] = { [BAT_TEMP_IRQ] = { .name = "bat-temp", .handler = batt_temp_changed_irq_handler, + .wake = true, }, [ALL_CHNL_CONV_DONE_IRQ] = { .name = "all-chnl-conv-done", - .handler = default_irq_handler, }, [BAT_OV_IRQ] = { .name = "bat-ov", @@ -1801,11 +1793,9 @@ static struct smb_irq_info smb5_irqs[] = { }, [BUCK_OC_IRQ] = { .name = "buck-oc", - .handler = default_irq_handler, }, [VPH_OV_IRQ] = { .name = "vph-ov", - .handler = default_irq_handler, }, /* USB INPUT IRQs */ [USBIN_COLLAPSE_IRQ] = { @@ -1827,23 +1817,24 @@ static struct smb_irq_info smb5_irqs[] = { [USBIN_PLUGIN_IRQ] = { .name = "usbin-plugin", .handler = usb_plugin_irq_handler, + .wake = true, }, [USBIN_REVI_CHANGE_IRQ] = { .name = "usbin-revi-change", - .handler = default_irq_handler, }, [USBIN_SRC_CHANGE_IRQ] = { .name = "usbin-src-change", .handler = usb_source_change_irq_handler, + .wake = true, }, [USBIN_ICL_CHANGE_IRQ] = { .name = "usbin-icl-change", .handler = icl_change_irq_handler, + .wake = true, }, /* DC INPUT IRQs */ [DCIN_VASHDN_IRQ] = { .name = "dcin-vashdn", - .handler = default_irq_handler, }, [DCIN_UV_IRQ] = { .name = "dcin-uv", @@ -1860,7 +1851,6 @@ static struct smb_irq_info smb5_irqs[] = { }, [DCIN_REVI_IRQ] = { .name = "dcin-revi", - .handler = default_irq_handler, }, [DCIN_PON_IRQ] = { .name = "dcin-pon", @@ -1874,14 +1864,15 @@ static struct smb_irq_info smb5_irqs[] = { [TYPEC_OR_RID_DETECTION_CHANGE_IRQ] = { .name = "typec-or-rid-detect-change", .handler = typec_or_rid_detection_change_irq_handler, + .wake = true, }, [TYPEC_VPD_DETECT_IRQ] = { .name = "typec-vpd-detect", - .handler = default_irq_handler, }, [TYPEC_CC_STATE_CHANGE_IRQ] = { .name = "typec-cc-state-change", .handler = typec_state_change_irq_handler, + .wake = true, }, [TYPEC_VCONN_OC_IRQ] = { .name = "typec-vconn-oc", @@ -1889,11 +1880,9 @@ static struct smb_irq_info smb5_irqs[] = { }, [TYPEC_VBUS_CHANGE_IRQ] = { .name = "typec-vbus-change", - .handler = default_irq_handler, }, [TYPEC_ATTACH_DETACH_IRQ] = { .name = "typec-attach-detach", - .handler = typec_attach_detach_irq_handler, }, [TYPEC_LEGACY_CABLE_DETECT_IRQ] = { .name = "typec-legacy-cable-detect", @@ -1901,12 +1890,10 @@ static struct smb_irq_info smb5_irqs[] = { }, [TYPEC_TRY_SNK_SRC_DETECT_IRQ] = { .name = "typec-try-snk-src-detect", - .handler = default_irq_handler, }, /* MISCELLANEOUS IRQs */ [WDOG_SNARL_IRQ] = { .name = "wdog-snarl", - .handler = NULL, }, [WDOG_BARK_IRQ] = { .name = "wdog-bark", @@ -1914,7 +1901,6 @@ static struct smb_irq_info smb5_irqs[] = { }, [AICL_FAIL_IRQ] = { .name = "aicl-fail", - .handler = default_irq_handler, }, [AICL_DONE_IRQ] = { .name = "aicl-done", @@ -1922,24 +1908,19 @@ static struct smb_irq_info smb5_irqs[] = { }, [SMB_EN_IRQ] = { .name = "smb-en", - .handler = default_irq_handler, }, [IMP_TRIGGER_IRQ] = { .name = "imp-trigger", - .handler = default_irq_handler, }, [TEMP_CHANGE_IRQ] = { .name = "temp-change", - .handler = default_irq_handler, }, [TEMP_CHANGE_SMB_IRQ] = { .name = "temp-change-smb", - .handler = default_irq_handler, }, /* FLASH */ [VREG_OK_IRQ] = { .name = "vreg-ok", - .handler = schgm_flash_default_irq_handler, }, [ILIM_S2_IRQ] = { .name = "ilim2-s2", @@ -1947,15 +1928,12 @@ static struct smb_irq_info smb5_irqs[] = { }, [ILIM_S1_IRQ] = { .name = "ilim1-s1", - .handler = schgm_flash_default_irq_handler, }, [VOUT_DOWN_IRQ] = { .name = "vout-down", - .handler = schgm_flash_default_irq_handler, }, [VOUT_UP_IRQ] = { .name = "vout-up", - .handler = schgm_flash_default_irq_handler, }, [FLASH_STATE_CHANGE_IRQ] = { .name = "flash-state-change", @@ -1963,11 +1941,9 @@ static struct smb_irq_info smb5_irqs[] = { }, [TORCH_REQ_IRQ] = { .name = "torch-req", - .handler = schgm_flash_default_irq_handler, }, [FLASH_EN_IRQ] = { .name = "flash-en", - .handler = schgm_flash_default_irq_handler, }, }; -- GitLab From a8de8a24fb5df90b58bcf2e01da9b09eb3b46b83 Mon Sep 17 00:00:00 2001 From: Guru Das Srinagesh Date: Wed, 11 Apr 2018 16:50:20 -0700 Subject: [PATCH 0417/1635] power: smb5: Make TYPEC_ATTACH_DETACH_IRQ wakeup capable Commit d92bfe55f8cc4dc1 ("power: smb5: update IRQ configuration") adds wakeup capabilities to several IRQs. Extend this to include TYPEC_ATTACH_DETACH_IRQ as well. And while we're at it, associate TYPEC_ATTACH_DETACH_IRQ with the right IRQ handler routine. CRs-Fixed: 2221052 Change-Id: I846e0bae574d2934b4498f1d2a55970347e181e4 Signed-off-by: Guru Das Srinagesh --- drivers/power/supply/qcom/qpnp-smb5.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/power/supply/qcom/qpnp-smb5.c b/drivers/power/supply/qcom/qpnp-smb5.c index 9d04b317d05a..6b40fb3b2a00 100644 --- a/drivers/power/supply/qcom/qpnp-smb5.c +++ b/drivers/power/supply/qcom/qpnp-smb5.c @@ -1883,6 +1883,8 @@ static struct smb_irq_info smb5_irqs[] = { }, [TYPEC_ATTACH_DETACH_IRQ] = { .name = "typec-attach-detach", + .handler = typec_attach_detach_irq_handler, + .wake = true, }, [TYPEC_LEGACY_CABLE_DETECT_IRQ] = { .name = "typec-legacy-cable-detect", -- GitLab From 2b96185ec4ee19c9926b9c3fb2becb5358cf8646 Mon Sep 17 00:00:00 2001 From: Shashank Babu Chinta Venkata Date: Wed, 4 Apr 2018 13:04:54 -0700 Subject: [PATCH 0418/1635] ARM: dts: msm: add pinctrl information of display for SDMSHRIKE Add te, reset and modeselect pincontrol information for SDMSHRIKE. Change-Id: I057d472bdf66e79a8fb6cc1db8e9d93b5c37ed3d Signed-off-by: Shashank Babu Chinta Venkata Signed-off-by: Ingrid Gallardo --- .../boot/dts/qcom/sdmshrike-pinctrl.dtsi | 55 +++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sdmshrike-pinctrl.dtsi b/arch/arm64/boot/dts/qcom/sdmshrike-pinctrl.dtsi index 99e988e5a69a..d013f24470e8 100644 --- a/arch/arm64/boot/dts/qcom/sdmshrike-pinctrl.dtsi +++ b/arch/arm64/boot/dts/qcom/sdmshrike-pinctrl.dtsi @@ -533,6 +533,61 @@ }; }; + pmx_sde: pmx_sde { + sde_dsi_active: sde_dsi_active { + mux { + pins = "gpio6", "gpio7"; + function = "gpio"; + }; + + config { + pins = "gpio6", "gpio7"; + drive-strength = <8>; /* 8 mA */ + bias-disable = <0>; /* no pull */ + }; + }; + sde_dsi_suspend: sde_dsi_suspend { + mux { + pins = "gpio6", "gpio7"; + function = "gpio"; + }; + + config { + pins = "gpio6", "gpio7"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + }; + }; + }; + + pmx_sde_te { + sde_te_active: sde_te_active { + mux { + pins = "gpio8"; + function = "mdp_vsync"; + }; + + config { + pins = "gpio8"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + }; + }; + + sde_te_suspend: sde_te_suspend { + mux { + pins = "gpio8"; + function = "mdp_vsync"; + }; + + config { + pins = "gpio8"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + }; + }; + }; + sec_tdm { sec_tdm_sleep: sec_tdm_sleep { mux { -- GitLab From 0a606fcdc481fa403bbed06a26bfc54422eeed9a Mon Sep 17 00:00:00 2001 From: Ingrid Gallardo Date: Tue, 3 Apr 2018 17:41:43 -0700 Subject: [PATCH 0419/1635] ARM: dts: msm: add display device tree file for sdmshrike This patch adds the sdmshrike display related device tree nodes required by the SDE DRM driver. Change-Id: Id43611c47b70097e0c266074c1f52233d20073b3 Signed-off-by: Ingrid Gallardo Signed-off-by: Shashank Babu Chinta Venkata --- arch/arm64/boot/dts/qcom/sdmshrike-sde.dtsi | 599 ++++++++++++++++++++ 1 file changed, 599 insertions(+) create mode 100644 arch/arm64/boot/dts/qcom/sdmshrike-sde.dtsi diff --git a/arch/arm64/boot/dts/qcom/sdmshrike-sde.dtsi b/arch/arm64/boot/dts/qcom/sdmshrike-sde.dtsi new file mode 100644 index 000000000000..067069d7fd29 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdmshrike-sde.dtsi @@ -0,0 +1,599 @@ +/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#include + +&soc { + mdss_mdp: qcom,mdss_mdp@ae00000 { + compatible = "qcom,sde-kms"; + reg = <0x0ae00000 0x84208>, + <0x0aeb0000 0x2008>, + <0x0aeac000 0x214>; + reg-names = "mdp_phys", + "vbif_phys", + "regdma_phys"; + + clocks = + <&clock_gcc GCC_DISP_AHB_CLK>, + <&clock_gcc GCC_DISP_HF_AXI_CLK>, + <&clock_dispcc DISP_CC_MDSS_AHB_CLK>, + <&clock_dispcc DISP_CC_MDSS_MDP_CLK>, + <&clock_dispcc DISP_CC_MDSS_VSYNC_CLK>; + clock-names = "gcc_iface", "gcc_bus", + "iface_clk", "core_clk", "vsync_clk"; + clock-rate = <0 0 0 300000000 19200000>; + clock-max-rate = <0 0 0 460000000 19200000>; + + sde-vdd-supply = <&mdss_core_gdsc>; + + /* interrupt config */ + interrupts = <0 83 0>; + interrupt-controller; + #interrupt-cells = <1>; + iommus = <&apps_smmu 0x800 0x20>, + <&apps_smmu 0xc00 0x20>; + + #address-cells = <1>; + #size-cells = <0>; + + /* hw blocks */ + qcom,sde-off = <0x1000>; + qcom,sde-len = <0x45c>; + + qcom,sde-ctl-off = <0x2000 0x2200 0x2400 + 0x2600 0x2800 0x2a00>; + qcom,sde-ctl-size = <0x1e0>; + qcom,sde-ctl-display-pref = "primary", "primary", "none", + "none", "none"; + + qcom,sde-mixer-off = <0x45000 0x46000 0x47000 + 0x48000 0x49000 0x4a000>; + qcom,sde-mixer-size = <0x320>; + qcom,sde-mixer-display-pref = "primary", "primary", "none", + "none", "none", "none"; + + qcom,sde-dspp-top-off = <0x1300>; + qcom,sde-dspp-top-size = <0x80>; + qcom,sde-dspp-off = <0x55000 0x57000 0x59000 0x5b000>; + qcom,sde-dspp-size = <0x1800>; + + qcom,sde-dest-scaler-top-off = <0x00061000>; + qcom,sde-dest-scaler-top-size = <0x1c>; + qcom,sde-dest-scaler-off = <0x800 0x1000>; + qcom,sde-dest-scaler-size = <0x800>; + + qcom,sde-wb-off = <0x66000>; + qcom,sde-wb-size = <0x2c8>; + qcom,sde-wb-xin-id = <6>; + qcom,sde-wb-id = <2>; + qcom,sde-wb-clk-ctrl = <0x3b8 24>; + + qcom,sde-intf-off = <0x6b000 0x6b800 + 0x6c000 0x6c800>; + qcom,sde-intf-size = <0x280>; + qcom,sde-intf-type = "dp", "dsi", "dsi", "dp"; + + qcom,sde-pp-off = <0x71000 0x71800 + 0x72000 0x72800 0x73000 0x73800>; + qcom,sde-pp-slave = <0x0 0x0 0x0 0x0 0x0 0x0>; + qcom,sde-pp-size = <0xd4>; + qcom,sde-pp-merge-3d-id = <0x0 0x0 0x1 0x1 0x2 0x2>; + + qcom,sde-merge-3d-off = <0x84000 0x84100 0x84200>; + qcom,sde-merge-3d-size = <0x100>; + + qcom,sde-te2-off = <0x2000 0x2000 0x0 0x0 0x0 0x0>; + + qcom,sde-cdm-off = <0x7a200>; + qcom,sde-cdm-size = <0x224>; + + qcom,sde-dsc-off = <0x81000 0x81400 0x81800 0x81c00>; + qcom,sde-dsc-size = <0x140>; + + qcom,sde-dither-off = <0x30e0 0x30e0 0x30e0 + 0x30e0 0x30e0 0x30e0>; + qcom,sde-dither-version = <0x00010000>; + qcom,sde-dither-size = <0x20>; + + qcom,sde-sspp-type = "vig", "vig", "vig", "vig", + "dma", "dma", "dma", "dma"; + + qcom,sde-sspp-off = <0x5000 0x7000 0x9000 0xb000 + 0x25000 0x27000 0x29000 0x2b000>; + qcom,sde-sspp-src-size = <0x1f0>; + + qcom,sde-sspp-xin-id = <0 4 8 12 + 1 5 9 13>; + qcom,sde-sspp-excl-rect = <1 1 1 1 + 1 1 1 1>; + qcom,sde-sspp-smart-dma-priority = <5 6 7 8 1 2 3 4>; + qcom,sde-smart-dma-rev = "smart_dma_v2p5"; + + qcom,sde-mixer-pair-mask = <2 1 4 3 6 5>; + + qcom,sde-mixer-blend-op-off = <0x20 0x38 0x50 0x68 0x80 0x98 + 0xb0 0xc8 0xe0 0xf8 0x110>; + + /* offsets are relative to "mdp_phys + qcom,sde-off */ + qcom,sde-sspp-clk-ctrl = + <0x2ac 0>, <0x2b4 0>, <0x2bc 0>, <0x2c4 0>, + <0x2ac 8>, <0x2b4 8>, <0x2bc 8>, <0x2c4 8>; + qcom,sde-sspp-csc-off = <0x1a00>; + qcom,sde-csc-type = "csc-10bit"; + qcom,sde-qseed-type = "qseedv3"; + qcom,sde-sspp-qseed-off = <0xa00>; + qcom,sde-mixer-linewidth = <2560>; + qcom,sde-sspp-linewidth = <4096>; + qcom,sde-wb-linewidth = <4096>; + qcom,sde-mixer-blendstages = <0xb>; + qcom,sde-highest-bank-bit = <0x2>; + qcom,sde-ubwc-version = <0x300>; + qcom,sde-ubwc-bw-calc-version = <0x1>; + qcom,sde-panic-per-pipe; + qcom,sde-has-cdp; + qcom,sde-has-src-split; + qcom,sde-pipe-order-version = <0x1>; + qcom,sde-has-dim-layer; + qcom,sde-has-idle-pc; + qcom,sde-has-dest-scaler; + qcom,sde-max-dest-scaler-input-linewidth = <2048>; + qcom,sde-max-dest-scaler-output-linewidth = <2560>; + qcom,sde-max-bw-low-kbps = <9600000>; + qcom,sde-max-bw-high-kbps = <9600000>; + qcom,sde-min-core-ib-kbps = <2400000>; + qcom,sde-min-llcc-ib-kbps = <800000>; + qcom,sde-min-dram-ib-kbps = <800000>; + qcom,sde-dram-channels = <2>; + qcom,sde-num-nrt-paths = <0>; + qcom,sde-dspp-ad-version = <0x00040000>; + qcom,sde-dspp-ad-off = <0x28000 0x27000>; + + qcom,sde-vbif-off = <0>; + qcom,sde-vbif-size = <0x1040>; + qcom,sde-vbif-id = <0>; + qcom,sde-vbif-memtype-0 = <3 3 3 3 3 3 3 3>; + qcom,sde-vbif-memtype-1 = <3 3 3 3 3 3>; + + qcom,sde-vbif-qos-rt-remap = <3 3 4 4 5 5 6 6>; + qcom,sde-vbif-qos-nrt-remap = <3 3 3 3 3 3 3 3>; + + qcom,sde-danger-lut = <0x0000000f 0x0000ffff 0x00000000 + 0x00000000>; + qcom,sde-safe-lut-linear = + <4 0xfff8>, + <0 0xfff0>; + qcom,sde-safe-lut-macrotile = + <10 0xfe00>, + <11 0xfc00>, + <12 0xf800>, + <0 0xf000>; + qcom,sde-safe-lut-nrt = + <0 0xffff>; + qcom,sde-safe-lut-cwb = + <0 0xffff>; + qcom,sde-qos-lut-linear = + <4 0x00000000 0x00000357>, + <5 0x00000000 0x00003357>, + <6 0x00000000 0x00023357>, + <7 0x00000000 0x00223357>, + <8 0x00000000 0x02223357>, + <9 0x00000000 0x22223357>, + <10 0x00000002 0x22223357>, + <11 0x00000022 0x22223357>, + <12 0x00000222 0x22223357>, + <13 0x00002222 0x22223357>, + <14 0x00012222 0x22223357>, + <0 0x00112222 0x22223357>; + qcom,sde-qos-lut-macrotile = + <10 0x00000003 0x44556677>, + <11 0x00000033 0x44556677>, + <12 0x00000233 0x44556677>, + <13 0x00002233 0x44556677>, + <14 0x00012233 0x44556677>, + <0 0x00112233 0x44556677>; + qcom,sde-qos-lut-nrt = + <0 0x00000000 0x00000000>; + qcom,sde-qos-lut-cwb = + <0 0x75300000 0x00000000>; + + qcom,sde-cdp-setting = <1 1>, <1 0>; + + qcom,sde-qos-cpu-mask = <0x3>; + qcom,sde-qos-cpu-dma-latency = <300>; + + qcom,sde-reg-dma-off = <0>; + qcom,sde-reg-dma-version = <0x00010001>; + qcom,sde-reg-dma-trigger-off = <0x119c>; + + qcom,sde-sspp-vig-blocks { + qcom,sde-vig-csc-off = <0x1a00>; + qcom,sde-vig-qseed-off = <0xa00>; + qcom,sde-vig-qseed-size = <0xa0>; + qcom,sde-vig-gamut = <0x1d00 0x00050000>; + qcom,sde-vig-igc = <0x1d00 0x00050000>; + qcom,sde-vig-inverse-pma; + }; + + qcom,sde-sspp-dma-blocks { + dgm@0 { + qcom,sde-dma-igc = <0x400 0x00050000>; + qcom,sde-dma-gc = <0x600 0x00050000>; + qcom,sde-dma-inverse-pma; + qcom,sde-dma-csc-off = <0x200>; + }; + dgm@1 { + qcom,sde-dma-igc = <0x1400 0x00050000>; + qcom,sde-dma-gc = <0x600 0x00050000>; + qcom,sde-dma-inverse-pma; + qcom,sde-dma-csc-off = <0x1200>; + }; + }; + + qcom,sde-dspp-blocks { + qcom,sde-dspp-igc = <0x0 0x00030001>; + qcom,sde-dspp-hsic = <0x800 0x00010007>; + qcom,sde-dspp-memcolor = <0x880 0x00010007>; + qcom,sde-dspp-hist = <0x800 0x00010007>; + qcom,sde-dspp-sixzone= <0x900 0x00010007>; + qcom,sde-dspp-vlut = <0xa00 0x00010008>; + qcom,sde-dspp-gamut = <0x1000 0x00040001>; + qcom,sde-dspp-pcc = <0x1700 0x00040000>; + qcom,sde-dspp-gc = <0x17c0 0x00010008>; + }; + + qcom,platform-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + + qcom,platform-supply-entry@0 { + reg = <0>; + qcom,supply-name = "sde-vdd"; + qcom,supply-min-voltage = <0>; + qcom,supply-max-voltage = <0>; + qcom,supply-enable-load = <0>; + qcom,supply-disable-load = <0>; + }; + }; + + smmu_sde_sec: qcom,smmu_sde_sec_cb { + compatible = "qcom,smmu_sde_sec"; + iommus = <&apps_smmu 0x801 0x20>, + <&apps_smmu 0xc01 0x20>; + }; + + /* data and reg bus scale settings */ + qcom,sde-data-bus { + qcom,msm-bus,name = "mdss_sde_mnoc"; + qcom,msm-bus,num-cases = <3>; + qcom,msm-bus,num-paths = <2>; + qcom,msm-bus,vectors-KBps = + <22 773 0 0>, <23 773 0 0>, + <22 773 0 6400000>, <23 773 0 6400000>, + <22 773 0 6400000>, <23 773 0 6400000>; + }; + + qcom,sde-llcc-bus { + qcom,msm-bus,name = "mdss_sde_llcc"; + qcom,msm-bus,num-cases = <3>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <132 770 0 0>, + <132 770 0 6400000>, + <132 770 0 6400000>; + }; + + qcom,sde-ebi-bus { + qcom,msm-bus,name = "mdss_sde_ebi"; + qcom,msm-bus,num-cases = <3>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <129 512 0 0>, + <129 512 0 6400000>, + <129 512 0 6400000>; + }; + + qcom,sde-reg-bus { + qcom,msm-bus,name = "mdss_reg"; + qcom,msm-bus,num-cases = <4>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,active-only; + qcom,msm-bus,vectors-KBps = + <1 590 0 0>, + <1 590 0 76800>, + <1 590 0 150000>, + <1 590 0 300000>; + }; + }; + + sde_rscc: qcom,sde_rscc@af20000 { + cell-index = <0>; + compatible = "qcom,sde-rsc"; + reg = <0xaf20000 0x1c44>, + <0xaf30000 0x3fd4>; + reg-names = "drv", "wrapper"; + qcom,sde-rsc-version = <2>; + status = "disabled"; + + vdd-supply = <&mdss_core_gdsc>; + clocks = <&clock_dispcc DISP_CC_MDSS_RSCC_VSYNC_CLK>, + <&clock_dispcc DISP_CC_MDSS_NON_GDSC_AHB_CLK>, + <&clock_dispcc DISP_CC_MDSS_RSCC_AHB_CLK>; + clock-names = "vsync_clk", "gdsc_clk", "iface_clk"; + clock-rate = <0 0 0>; + + qcom,sde-dram-channels = <2>; + + mboxes = <&disp_rsc 0>; + mbox-names = "disp_rsc"; + + /* data and reg bus scale settings */ + qcom,sde-data-bus { + qcom,msm-bus,name = "disp_rsc_mnoc"; + qcom,msm-bus,active-only; + qcom,msm-bus,num-cases = <3>; + qcom,msm-bus,num-paths = <2>; + qcom,msm-bus,vectors-KBps = + <20003 20515 0 0>, <20004 20515 0 0>, + <20003 20515 0 6400000>, <20004 20515 0 6400000>, + <20003 20515 0 6400000>, <20004 20515 0 6400000>; + }; + + qcom,sde-llcc-bus { + qcom,msm-bus,name = "disp_rsc_llcc"; + qcom,msm-bus,active-only; + qcom,msm-bus,num-cases = <3>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <20001 20513 0 0>, + <20001 20513 0 6400000>, + <20001 20513 0 6400000>; + }; + + qcom,sde-ebi-bus { + qcom,msm-bus,name = "disp_rsc_ebi"; + qcom,msm-bus,active-only; + qcom,msm-bus,num-cases = <3>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <20000 20512 0 0>, + <20000 20512 0 6400000>, + <20000 20512 0 6400000>; + }; + + qcom,platform-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + + qcom,platform-supply-entry@0 { + reg = <0>; + qcom,supply-name = "mmcx"; + qcom,supply-min-voltage = <0>; + qcom,supply-max-voltage = <0>; + qcom,supply-enable-load = <0>; + qcom,supply-disable-load = <0>; + }; + }; + }; + + mdss_rotator: qcom,mdss_rotator@ae00000 { + compatible = "qcom,sde_rotator"; + reg = <0x0ae00000 0xac000>, + <0x0aeb8000 0x3000>; + reg-names = "mdp_phys", + "rot_vbif_phys"; + + #list-cells = <1>; + + qcom,mdss-rot-mode = <1>; + qcom,mdss-highest-bank-bit = <0x2>; + + /* Bus Scale Settings */ + qcom,msm-bus,name = "mdss_rotator"; + qcom,msm-bus,num-cases = <3>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <25 512 0 0>, + <25 512 0 6400000>, + <25 512 0 6400000>; + + rot-vdd-supply = <&mdss_core_gdsc>; + qcom,supply-names = "rot-vdd"; + + clocks = + <&clock_gcc GCC_DISP_AHB_CLK>, + <&clock_gcc GCC_DISP_SF_AXI_CLK>, + <&clock_dispcc DISP_CC_MDSS_AHB_CLK>, + <&clock_dispcc DISP_CC_MDSS_ROT_CLK>; + clock-names = "gcc_iface", "gcc_bus", + "iface_clk", "rot_clk"; + + interrupt-parent = <&mdss_mdp>; + interrupts = <2 0>; + + power-domains = <&mdss_mdp>; + + /* Offline rotator QoS setting */ + qcom,mdss-rot-vbif-qos-setting = <3 3 3 3 3 3 3 3>; + qcom,mdss-rot-vbif-memtype = <3 3>; + qcom,mdss-rot-cdp-setting = <1 1>; + qcom,mdss-rot-qos-lut = <0x0 0x0 0x0 0x0>; + qcom,mdss-rot-danger-lut = <0x0 0x0>; + qcom,mdss-rot-safe-lut = <0x0000ffff 0x0000ffff>; + + /* Inline rotator QoS Setting */ + /* setting default register values for RD - qos/danger/safe */ + qcom,mdss-inline-rot-qos-lut = <0x44556677 0x00112233 + 0x44556677 0x00112233>; + qcom,mdss-inline-rot-danger-lut = <0x0055aaff 0x0000ffff>; + qcom,mdss-inline-rot-safe-lut = <0x0000f000 0x0000ff00>; + + qcom,mdss-default-ot-rd-limit = <32>; + qcom,mdss-default-ot-wr-limit = <32>; + + qcom,mdss-sbuf-headroom = <20>; + + cache-slice-names = "rotator"; + cache-slices = <&llcc 4>; + + /* reg bus scale settings */ + rot_reg: qcom,rot-reg-bus { + qcom,msm-bus,name = "mdss_rot_reg"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,active-only; + qcom,msm-bus,vectors-KBps = + <1 590 0 0>, + <1 590 0 76800>; + }; + + smmu_rot_unsec: qcom,smmu_rot_unsec_cb { + compatible = "qcom,smmu_sde_rot_unsec"; + iommus = <&apps_smmu 0x1040 0x0>; + }; + + smmu_rot_sec: qcom,smmu_rot_sec_cb { + compatible = "qcom,smmu_sde_rot_sec"; + iommus = <&apps_smmu 0x1041 0x0>; + }; + }; + + mdss_dsi0: qcom,mdss_dsi_ctrl0@ae94000 { + compatible = "qcom,dsi-ctrl-hw-v2.3"; + label = "dsi-ctrl-0"; + cell-index = <0>; + reg = <0xae94000 0x400>, + <0xaf08000 0x4>; + reg-names = "dsi_ctrl", "disp_cc_base"; + interrupt-parent = <&mdss_mdp>; + interrupts = <4 0>; + vdda-1p2-supply = <&pm855p_l3>; + clocks = <&clock_dispcc DISP_CC_MDSS_BYTE0_CLK>, + <&clock_dispcc DISP_CC_MDSS_BYTE0_CLK_SRC>, + <&clock_dispcc DISP_CC_MDSS_BYTE0_INTF_CLK>, + <&clock_dispcc DISP_CC_MDSS_PCLK0_CLK>, + <&clock_dispcc DISP_CC_MDSS_PCLK0_CLK_SRC>, + <&clock_dispcc DISP_CC_MDSS_ESC0_CLK>; + clock-names = "byte_clk", "byte_clk_rcg", "byte_intf_clk", + "pixel_clk", "pixel_clk_rcg", + "esc_clk"; + + qcom,ctrl-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + + qcom,ctrl-supply-entry@0 { + reg = <0>; + qcom,supply-name = "vdda-1p2"; + qcom,supply-min-voltage = <1200000>; + qcom,supply-max-voltage = <1200000>; + qcom,supply-enable-load = <21800>; + qcom,supply-disable-load = <4>; + }; + }; + }; + + mdss_dsi1: qcom,mdss_dsi_ctrl1@ae96000 { + compatible = "qcom,dsi-ctrl-hw-v2.3"; + label = "dsi-ctrl-1"; + cell-index = <1>; + reg = <0xae96000 0x400>, + <0xaf08000 0x4>; + reg-names = "dsi_ctrl", "disp_cc_base"; + interrupt-parent = <&mdss_mdp>; + interrupts = <5 0>; + vdda-1p2-supply = <&pm855p_l3>; + clocks = <&clock_dispcc DISP_CC_MDSS_BYTE1_CLK>, + <&clock_dispcc DISP_CC_MDSS_BYTE1_CLK_SRC>, + <&clock_dispcc DISP_CC_MDSS_BYTE1_INTF_CLK>, + <&clock_dispcc DISP_CC_MDSS_PCLK1_CLK>, + <&clock_dispcc DISP_CC_MDSS_PCLK1_CLK_SRC>, + <&clock_dispcc DISP_CC_MDSS_ESC1_CLK>; + clock-names = "byte_clk", "byte_clk_rcg", "byte_intf_clk", + "pixel_clk", "pixel_clk_rcg", "esc_clk"; + qcom,ctrl-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + + qcom,ctrl-supply-entry@0 { + reg = <0>; + qcom,supply-name = "vdda-1p2"; + qcom,supply-min-voltage = <1200000>; + qcom,supply-max-voltage = <1200000>; + qcom,supply-enable-load = <21800>; + qcom,supply-disable-load = <4>; + }; + }; + }; + + mdss_dsi_phy0: qcom,mdss_dsi_phy0@ae94400 { + compatible = "qcom,dsi-phy-v4.0"; + label = "dsi-phy-0"; + cell-index = <0>; + reg = <0xae94400 0x7c0>; + reg-names = "dsi_phy"; + vdda-0p9-supply = <&pm855_2_l5>; + qcom,platform-strength-ctrl = [55 03 + 55 03 + 55 03 + 55 03 + 55 00]; + qcom,platform-lane-config = [00 00 0a 0a + 00 00 0a 0a + 00 00 0a 0a + 00 00 0a 0a + 00 00 8a 8a]; + qcom,platform-regulator-settings = [1d 1d 1d 1d 1d]; + qcom,phy-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + qcom,phy-supply-entry@0 { + reg = <0>; + qcom,supply-name = "vdda-0p9"; + qcom,supply-min-voltage = <880000>; + qcom,supply-max-voltage = <880000>; + qcom,supply-enable-load = <36000>; + qcom,supply-disable-load = <32>; + }; + }; + }; + + mdss_dsi_phy1: qcom,mdss_dsi_phy0@ae96400 { + compatible = "qcom,dsi-phy-v4.0"; + label = "dsi-phy-1"; + cell-index = <1>; + reg = <0xae96400 0x7c0>; + reg-names = "dsi_phy"; + vdda-0p9-supply = <&pm855_2_l5>; + qcom,platform-strength-ctrl = [55 03 + 55 03 + 55 03 + 55 03 + 55 00]; + qcom,platform-regulator-settings = [1d 1d 1d 1d 1d]; + qcom,platform-lane-config = [00 00 0a 0a + 00 00 0a 0a + 00 00 0a 0a + 00 00 0a 0a + 00 00 8a 8a]; + qcom,phy-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + qcom,phy-supply-entry@0 { + reg = <0>; + qcom,supply-name = "vdda-0p9"; + qcom,supply-min-voltage = <880000>; + qcom,supply-max-voltage = <880000>; + qcom,supply-enable-load = <36000>; + qcom,supply-disable-load = <32>; + }; + }; + }; +}; -- GitLab From c3afde55abfe130d16343b966a609bd8e2f4725c Mon Sep 17 00:00:00 2001 From: Shashank Babu Chinta Venkata Date: Tue, 3 Apr 2018 15:40:40 -0700 Subject: [PATCH 0420/1635] ARM: dts: msm: add displays supported by sdm shrike Add various displays for sdmshrike and related panel configurations to support the same. Change-Id: If894f5339d402cdb52fbd6f5df0cc0aab6764c14 Signed-off-by: Shashank Babu Chinta Venkata Signed-off-by: Ingrid Gallardo --- .../boot/dts/qcom/sdmshrike-sde-display.dtsi | 757 ++++++++++++++++++ 1 file changed, 757 insertions(+) create mode 100644 arch/arm64/boot/dts/qcom/sdmshrike-sde-display.dtsi diff --git a/arch/arm64/boot/dts/qcom/sdmshrike-sde-display.dtsi b/arch/arm64/boot/dts/qcom/sdmshrike-sde-display.dtsi new file mode 100644 index 000000000000..3b0a83016880 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdmshrike-sde-display.dtsi @@ -0,0 +1,757 @@ +/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "dsi-panel-sim-video.dtsi" +#include "dsi-panel-sim-cmd.dtsi" +#include "dsi-panel-sim-dsc375-cmd.dtsi" +#include "dsi-panel-sim-dualmipi-video.dtsi" +#include "dsi-panel-sim-dualmipi-cmd.dtsi" +#include "dsi-panel-sim-dualmipi-dsc375-cmd.dtsi" +#include "dsi-panel-sharp-dsc-4k-video.dtsi" +#include "dsi-panel-sharp-dsc-4k-cmd.dtsi" +#include "dsi-panel-nt35597-truly-dualmipi-wqxga-video.dtsi" +#include "dsi-panel-nt35597-truly-dualmipi-wqxga-cmd.dtsi" +#include "dsi-panel-nt35597-truly-dsc-wqxga-cmd.dtsi" +#include "dsi-panel-nt35597-truly-dsc-wqxga-video.dtsi" +#include "dsi-panel-nt35695b-truly-fhd-video.dtsi" +#include "dsi-panel-nt35695b-truly-fhd-cmd.dtsi" +#include "dsi-panel-sharp-1080p-cmd.dtsi" +#include "dsi-panel-sharp-dualmipi-1080p-120hz.dtsi" +#include "dsi-panel-s6e3ha3-amoled-dualmipi-wqhd-cmd.dtsi" +#include "dsi-panel-sw43404-amoled-dsc-wqhd-cmd.dtsi" +#include + +&soc { + dsi_panel_pwr_supply: dsi_panel_pwr_supply { + #address-cells = <1>; + #size-cells = <0>; + + qcom,panel-supply-entry@0 { + reg = <0>; + qcom,supply-name = "vddio"; + qcom,supply-min-voltage = <1800000>; + qcom,supply-max-voltage = <1800000>; + qcom,supply-enable-load = <62000>; + qcom,supply-disable-load = <80>; + qcom,supply-post-on-sleep = <20>; + }; + + qcom,panel-supply-entry@1 { + reg = <1>; + qcom,supply-name = "lab"; + qcom,supply-min-voltage = <4600000>; + qcom,supply-max-voltage = <6000000>; + qcom,supply-enable-load = <100000>; + qcom,supply-disable-load = <100>; + }; + + qcom,panel-supply-entry@2 { + reg = <2>; + qcom,supply-name = "ibb"; + qcom,supply-min-voltage = <4600000>; + qcom,supply-max-voltage = <6000000>; + qcom,supply-enable-load = <100000>; + qcom,supply-disable-load = <100>; + qcom,supply-post-on-sleep = <20>; + }; + }; + + dsi_panel_pwr_supply_no_labibb: dsi_panel_pwr_supply_no_labibb { + #address-cells = <1>; + #size-cells = <0>; + + qcom,panel-supply-entry@0 { + reg = <0>; + qcom,supply-name = "vddio"; + qcom,supply-min-voltage = <1800000>; + qcom,supply-max-voltage = <1800000>; + qcom,supply-enable-load = <62000>; + qcom,supply-disable-load = <80>; + qcom,supply-post-on-sleep = <20>; + }; + }; + + dsi_panel_pwr_supply_vdd_no_labibb: dsi_panel_pwr_supply_vdd_no_labibb { + #address-cells = <1>; + #size-cells = <0>; + + qcom,panel-supply-entry@0 { + reg = <0>; + qcom,supply-name = "vddio"; + qcom,supply-min-voltage = <1800000>; + qcom,supply-max-voltage = <1800000>; + qcom,supply-enable-load = <62000>; + qcom,supply-disable-load = <80>; + qcom,supply-post-on-sleep = <20>; + }; + + qcom,panel-supply-entry@1 { + reg = <1>; + qcom,supply-name = "vdd"; + qcom,supply-min-voltage = <3000000>; + qcom,supply-max-voltage = <3000000>; + qcom,supply-enable-load = <857000>; + qcom,supply-disable-load = <0>; + qcom,supply-post-on-sleep = <0>; + }; + }; + + dsi_sharp_4k_dsc_video_display: qcom,dsi-display@0 { + compatible = "qcom,dsi-display"; + label = "dsi_sharp_4k_dsc_video_display"; + qcom,display-type = "primary"; + + qcom,dsi-ctrl = <&mdss_dsi0 &mdss_dsi1>; + qcom,dsi-phy = <&mdss_dsi_phy0 &mdss_dsi_phy1>; + clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>, + <&mdss_dsi0_pll PCLK_MUX_0_CLK>; + clock-names = "src_byte_clk", "src_pixel_clk"; + + pinctrl-names = "panel_active", "panel_suspend"; + pinctrl-0 = <&sde_dsi_active &sde_te_active>; + pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend>; + qcom,platform-te-gpio = <&tlmm 8 0>; + qcom,platform-reset-gpio = <&tlmm 7 0>; + qcom,panel-mode-gpio = <&tlmm 6 0>; + + qcom,dsi-panel = <&dsi_sharp_4k_dsc_video>; + + vddio-supply = <&pm855p_l1>; + lab-supply = <&lcdb_ldo_vreg>; + ibb-supply = <&lcdb_ncp_vreg>; + }; + + dsi_sharp_4k_dsc_cmd_display: qcom,dsi-display@1 { + compatible = "qcom,dsi-display"; + label = "dsi_sharp_4k_dsc_cmd_display"; + qcom,display-type = "primary"; + + qcom,dsi-ctrl = <&mdss_dsi0 &mdss_dsi1>; + qcom,dsi-phy = <&mdss_dsi_phy0 &mdss_dsi_phy1>; + clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>, + <&mdss_dsi0_pll PCLK_MUX_0_CLK>; + clock-names = "src_byte_clk", "src_pixel_clk"; + + pinctrl-names = "panel_active", "panel_suspend"; + pinctrl-0 = <&sde_dsi_active &sde_te_active>; + pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend>; + qcom,platform-te-gpio = <&tlmm 8 0>; + qcom,platform-reset-gpio = <&tlmm 7 0>; + qcom,panel-mode-gpio = <&tlmm 6 0>; + + qcom,dsi-panel = <&dsi_sharp_4k_dsc_cmd>; + vddio-supply = <&pm855p_l1>; + lab-supply = <&lcdb_ldo_vreg>; + ibb-supply = <&lcdb_ncp_vreg>; + }; + + dsi_sharp_1080_cmd_display: qcom,dsi-display@2 { + compatible = "qcom,dsi-display"; + label = "dsi_sharp_1080_cmd_display"; + qcom,display-type = "primary"; + + qcom,dsi-ctrl = <&mdss_dsi0>; + qcom,dsi-phy = <&mdss_dsi_phy0>; + clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>, + <&mdss_dsi0_pll PCLK_MUX_0_CLK>; + clock-names = "src_byte_clk", "src_pixel_clk"; + + pinctrl-names = "panel_active", "panel_suspend"; + pinctrl-0 = <&sde_dsi_active &sde_te_active>; + pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend>; + qcom,platform-te-gpio = <&tlmm 8 0>; + qcom,platform-reset-gpio = <&tlmm 7 0>; + qcom,panel-mode-gpio = <&tlmm 6 0>; + qcom,dsi-panel = <&dsi_sharp_1080_cmd>; + + vddio-supply = <&pm855p_l1>; + lab-supply = <&lcdb_ldo_vreg>; + ibb-supply = <&lcdb_ncp_vreg>; + }; + + dsi_dual_sharp_1080_120hz_cmd_display: qcom,dsi-display@3 { + compatible = "qcom,dsi-display"; + label = "dsi_dual_sharp_1080_120hz_cmd_display"; + qcom,display-type = "primary"; + + pinctrl-names = "panel_active", "panel_suspend"; + pinctrl-0 = <&sde_dsi_active &sde_te_active>; + pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend>; + qcom,dsi-ctrl = <&mdss_dsi0 &mdss_dsi1>; + qcom,dsi-phy = <&mdss_dsi_phy0 &mdss_dsi_phy1>; + clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>, + <&mdss_dsi0_pll PCLK_MUX_0_CLK>; + clock-names = "src_byte_clk", "src_pixel_clk"; + + qcom,platform-te-gpio = <&tlmm 8 0>; + qcom,platform-reset-gpio = <&tlmm 7 0>; + qcom,panel-mode-gpio = <&tlmm 6 0>; + qcom,dsi-panel = <&dsi_dual_sharp_1080_120hz_cmd>; + + vddio-supply = <&pm855p_l1>; + lab-supply = <&lcdb_ldo_vreg>; + ibb-supply = <&lcdb_ncp_vreg>; + }; + + dsi_dual_nt35597_truly_video_display: qcom,dsi-display@4 { + compatible = "qcom,dsi-display"; + label = "dsi_dual_nt35597_truly_video_display"; + qcom,display-type = "primary"; + + qcom,dsi-ctrl = <&mdss_dsi0 &mdss_dsi1>; + qcom,dsi-phy = <&mdss_dsi_phy0 &mdss_dsi_phy1>; + clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>, + <&mdss_dsi0_pll PCLK_MUX_0_CLK>; + clock-names = "src_byte_clk", "src_pixel_clk"; + + pinctrl-names = "panel_active", "panel_suspend"; + pinctrl-0 = <&sde_dsi_active &sde_te_active>; + pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend>; + qcom,platform-te-gpio = <&tlmm 8 0>; + qcom,platform-reset-gpio = <&tlmm 7 0>; + qcom,panel-mode-gpio = <&tlmm 6 0>; + qcom,dsi-panel = <&dsi_dual_nt35597_truly_video>; + + vddio-supply = <&pm855p_l1>; + lab-supply = <&lcdb_ldo_vreg>; + ibb-supply = <&lcdb_ncp_vreg>; + }; + + dsi_dual_nt35597_truly_cmd_display: qcom,dsi-display@5 { + compatible = "qcom,dsi-display"; + label = "dsi_dual_nt35597_truly_cmd_display"; + qcom,display-type = "primary"; + + qcom,dsi-ctrl = <&mdss_dsi0 &mdss_dsi1>; + qcom,dsi-phy = <&mdss_dsi_phy0 &mdss_dsi_phy1>; + clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>, + <&mdss_dsi0_pll PCLK_MUX_0_CLK>; + clock-names = "src_byte_clk", "src_pixel_clk"; + + pinctrl-names = "panel_active", "panel_suspend"; + pinctrl-0 = <&sde_dsi_active &sde_te_active>; + pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend>; + qcom,platform-te-gpio = <&tlmm 8 0>; + qcom,platform-reset-gpio = <&tlmm 7 0>; + qcom,panel-mode-gpio = <&tlmm 6 0>; + qcom,dsi-panel = <&dsi_dual_nt35597_truly_cmd>; + + vddio-supply = <&pm855p_l1>; + lab-supply = <&lcdb_ldo_vreg>; + ibb-supply = <&lcdb_ncp_vreg>; + }; + + dsi_nt35597_truly_dsc_cmd_display: qcom,dsi-display@6 { + compatible = "qcom,dsi-display"; + label = "dsi_nt35597_truly_dsc_cmd_display"; + qcom,display-type = "primary"; + + qcom,dsi-ctrl = <&mdss_dsi1>; + qcom,dsi-phy = <&mdss_dsi_phy1>; + clocks = <&mdss_dsi1_pll BYTECLK_MUX_1_CLK>, + <&mdss_dsi1_pll PCLK_MUX_1_CLK>; + clock-names = "src_byte_clk", "src_pixel_clk"; + + pinctrl-names = "panel_active", "panel_suspend"; + pinctrl-0 = <&sde_dsi_active &sde_te_active>; + pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend>; + qcom,platform-te-gpio = <&tlmm 8 0>; + qcom,platform-reset-gpio = <&tlmm 7 0>; + qcom,panel-mode-gpio = <&tlmm 6 0>; + qcom,dsi-panel = <&dsi_nt35597_truly_dsc_cmd>; + + vddio-supply = <&pm855p_l1>; + lab-supply = <&lcdb_ldo_vreg>; + ibb-supply = <&lcdb_ncp_vreg>; + }; + + dsi_nt35597_truly_dsc_video_display: qcom,dsi-display@7 { + compatible = "qcom,dsi-display"; + label = "dsi_nt35597_truly_dsc_video_display"; + qcom,display-type = "primary"; + + qcom,dsi-ctrl = <&mdss_dsi1>; + qcom,dsi-phy = <&mdss_dsi_phy1>; + clocks = <&mdss_dsi1_pll BYTECLK_MUX_1_CLK>, + <&mdss_dsi1_pll PCLK_MUX_1_CLK>; + clock-names = "src_byte_clk", "src_pixel_clk"; + + pinctrl-names = "panel_active", "panel_suspend"; + pinctrl-0 = <&sde_dsi_active &sde_te_active>; + pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend>; + qcom,platform-te-gpio = <&tlmm 8 0>; + qcom,platform-reset-gpio = <&tlmm 7 0>; + qcom,panel-mode-gpio = <&tlmm 6 0>; + qcom,dsi-panel = <&dsi_nt35597_truly_dsc_video>; + + vddio-supply = <&pm855p_l1>; + lab-supply = <&lcdb_ldo_vreg>; + ibb-supply = <&lcdb_ncp_vreg>; + }; + + dsi_sim_vid_display: qcom,dsi-display@8 { + compatible = "qcom,dsi-display"; + label = "dsi_sim_vid_display"; + qcom,display-type = "primary"; + + qcom,dsi-ctrl = <&mdss_dsi0>; + qcom,dsi-phy = <&mdss_dsi_phy0>; + clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>, + <&mdss_dsi0_pll PCLK_MUX_0_CLK>; + clock-names = "src_byte_clk", "src_pixel_clk"; + + pinctrl-names = "panel_active", "panel_suspend"; + pinctrl-0 = <&sde_dsi_active &sde_te_active>; + pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend>; + + qcom,dsi-panel = <&dsi_sim_vid>; + }; + + dsi_dual_sim_vid_display: qcom,dsi-display@9 { + compatible = "qcom,dsi-display"; + label = "dsi_dual_sim_vid_display"; + qcom,display-type = "primary"; + + qcom,dsi-ctrl = <&mdss_dsi0 &mdss_dsi1>; + qcom,dsi-phy = <&mdss_dsi_phy0 &mdss_dsi_phy1>; + clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>, + <&mdss_dsi0_pll PCLK_MUX_0_CLK>; + clock-names = "src_byte_clk", "src_pixel_clk"; + + pinctrl-names = "panel_active", "panel_suspend"; + pinctrl-0 = <&sde_dsi_active &sde_te_active>; + pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend>; + + qcom,dsi-panel = <&dsi_dual_sim_vid>; + }; + + dsi_sim_cmd_display: qcom,dsi-display@10 { + compatible = "qcom,dsi-display"; + label = "dsi_sim_cmd_display"; + qcom,display-type = "primary"; + + qcom,dsi-ctrl = <&mdss_dsi0>; + qcom,dsi-phy = <&mdss_dsi_phy0>; + clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>, + <&mdss_dsi0_pll PCLK_MUX_0_CLK>; + clock-names = "src_byte_clk", "src_pixel_clk"; + + pinctrl-names = "panel_active", "panel_suspend"; + pinctrl-0 = <&sde_dsi_active &sde_te_active>; + pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend>; + + qcom,dsi-panel = <&dsi_sim_cmd>; + }; + + dsi_dual_sim_cmd_display: qcom,dsi-display@11 { + compatible = "qcom,dsi-display"; + label = "dsi_dual_sim_cmd_display"; + qcom,display-type = "primary"; + + qcom,dsi-ctrl = <&mdss_dsi0 &mdss_dsi1>; + qcom,dsi-phy = <&mdss_dsi_phy0 &mdss_dsi_phy1>; + clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>, + <&mdss_dsi0_pll PCLK_MUX_0_CLK>; + clock-names = "src_byte_clk", "src_pixel_clk"; + + pinctrl-names = "panel_active", "panel_suspend"; + pinctrl-0 = <&sde_dsi_active &sde_te_active>; + pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend>; + + qcom,dsi-panel = <&dsi_dual_sim_cmd>; + }; + + dsi_sim_dsc_375_cmd_display: qcom,dsi-display@12 { + compatible = "qcom,dsi-display"; + label = "dsi_sim_dsc_375_cmd_display"; + qcom,display-type = "primary"; + + qcom,dsi-ctrl = <&mdss_dsi0>; + qcom,dsi-phy = <&mdss_dsi_phy0>; + clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>, + <&mdss_dsi0_pll PCLK_MUX_0_CLK>; + clock-names = "src_byte_clk", "src_pixel_clk"; + + pinctrl-names = "panel_active", "panel_suspend"; + pinctrl-0 = <&sde_dsi_active &sde_te_active>; + pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend>; + + qcom,dsi-panel = <&dsi_sim_dsc_375_cmd>; + }; + + dsi_dual_sim_dsc_375_cmd_display: qcom,dsi-display@13 { + compatible = "qcom,dsi-display"; + label = "dsi_dual_sim_dsc_375_cmd_display"; + qcom,display-type = "primary"; + + qcom,dsi-ctrl = <&mdss_dsi0 &mdss_dsi1>; + qcom,dsi-phy = <&mdss_dsi_phy0 &mdss_dsi_phy1>; + clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>, + <&mdss_dsi0_pll PCLK_MUX_0_CLK>; + clock-names = "src_byte_clk", "src_pixel_clk"; + + pinctrl-names = "panel_active", "panel_suspend"; + pinctrl-0 = <&sde_dsi_active &sde_te_active>; + pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend>; + + qcom,dsi-panel = <&dsi_dual_sim_dsc_375_cmd>; + }; + + dsi_sw43404_amoled_cmd_display: qcom,dsi-display@14 { + compatible = "qcom,dsi-display"; + label = "dsi_sw43404_amoled_cmd_display"; + qcom,display-type = "primary"; + + qcom,dsi-ctrl = <&mdss_dsi0>; + qcom,dsi-phy = <&mdss_dsi_phy0>; + clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>, + <&mdss_dsi0_pll PCLK_MUX_0_CLK>; + clock-names = "src_byte_clk", "src_pixel_clk"; + + pinctrl-names = "panel_active", "panel_suspend"; + pinctrl-0 = <&sde_dsi_active &sde_te_active>; + pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend>; + qcom,platform-te-gpio = <&tlmm 8 0>; + qcom,platform-reset-gpio = <&tlmm 7 0>; + qcom,panel-mode-gpio = <&tlmm 6 0>; + + qcom,dsi-panel = <&dsi_sw43404_amoled_cmd>; + vddio-supply = <&pm855p_l1>; + }; + + dsi_nt35695b_truly_fhd_cmd_display: qcom,dsi-display@15 { + compatible = "qcom,dsi-display"; + label = "dsi_nt35695b_truly_fhd_cmd_display"; + qcom,display-type = "primary"; + + qcom,dsi-ctrl = <&mdss_dsi0>; + qcom,dsi-phy = <&mdss_dsi_phy0>; + clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>, + <&mdss_dsi0_pll PCLK_MUX_0_CLK>; + clock-names = "src_byte_clk", "src_pixel_clk"; + + pinctrl-names = "panel_active", "panel_suspend"; + pinctrl-0 = <&sde_dsi_active &sde_te_active>; + pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend>; + qcom,platform-te-gpio = <&tlmm 8 0>; + qcom,platform-reset-gpio = <&tlmm 7 0>; + qcom,panel-mode-gpio = <&tlmm 6 0>; + + qcom,dsi-panel = <&dsi_nt35695b_truly_fhd_cmd>; + + vddio-supply = <&pm855p_l1>; + lab-supply = <&lcdb_ldo_vreg>; + ibb-supply = <&lcdb_ncp_vreg>; + }; + + dsi_nt35695b_truly_fhd_video_display: qcom,dsi-display@16 { + compatible = "qcom,dsi-display"; + label = "dsi_nt35695b_truly_fhd_video_display"; + qcom,display-type = "primary"; + + qcom,dsi-ctrl = <&mdss_dsi0>; + qcom,dsi-phy = <&mdss_dsi_phy0>; + clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>, + <&mdss_dsi0_pll PCLK_MUX_0_CLK>; + clock-names = "src_byte_clk", "src_pixel_clk"; + + pinctrl-names = "panel_active", "panel_suspend"; + pinctrl-0 = <&sde_dsi_active &sde_te_active>; + pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend>; + qcom,platform-te-gpio = <&tlmm 8 0>; + qcom,platform-reset-gpio = <&tlmm 7 0>; + qcom,panel-mode-gpio = <&tlmm 6 0>; + + qcom,dsi-panel = <&dsi_nt35695b_truly_fhd_video>; + + vddio-supply = <&pm855p_l1>; + lab-supply = <&lcdb_ldo_vreg>; + ibb-supply = <&lcdb_ncp_vreg>; + }; + + sde_wb: qcom,wb-display@0 { + compatible = "qcom,wb-display"; + cell-index = <0>; + label = "wb_display"; + }; + + ext_disp: qcom,msm-ext-disp { + compatible = "qcom,msm-ext-disp"; + + ext_disp_audio_codec: qcom,msm-ext-disp-audio-codec-rx { + compatible = "qcom,msm-ext-disp-audio-codec-rx"; + }; + }; +}; + +&mdss_mdp { + connectors = <&sde_wb>; +}; + +/* PHY TIMINGS REVISION P */ +&dsi_dual_nt35597_truly_video { + qcom,mdss-dsi-t-clk-post = <0x17>; + qcom,mdss-dsi-t-clk-pre = <0x18>; + qcom,mdss-dsi-display-timings { + timing@0{ + qcom,mdss-dsi-panel-phy-timings = [00 1c 08 07 23 22 07 + 07 05 03 04 00 18 17]; + qcom,display-topology = <2 0 2>, + <1 0 2>; + qcom,default-topology-index = <0>; + }; + }; +}; + +&dsi_dual_nt35597_truly_cmd { + qcom,mdss-dsi-t-clk-post = <0x17>; + qcom,mdss-dsi-t-clk-pre = <0x18>; + qcom,mdss-dsi-display-timings { + timing@0{ + qcom,mdss-dsi-panel-phy-timings = [00 1c 08 07 23 22 07 + 07 05 03 04 00 18 17]; + qcom,display-topology = <2 0 2>, + <1 0 2>; + qcom,default-topology-index = <0>; + }; + }; +}; + +&dsi_nt35597_truly_dsc_cmd { + qcom,mdss-dsi-t-clk-post = <0x15>; + qcom,mdss-dsi-t-clk-pre = <0x12>; + qcom,mdss-dsi-display-timings { + timing@0{ + qcom,mdss-dsi-panel-phy-timings = [00 15 05 05 20 1f 05 + 05 03 03 04 00 12 15]; + qcom,display-topology = <1 1 1>, + <2 2 1>, /* dsc merge */ + <2 1 1>; /* 3d mux */ + qcom,default-topology-index = <1>; + }; + }; +}; + +&dsi_nt35597_truly_dsc_video { + qcom,mdss-dsi-t-clk-post = <0x15>; + qcom,mdss-dsi-t-clk-pre = <0x12>; + qcom,mdss-dsi-display-timings { + timing@0{ + qcom,mdss-dsi-panel-phy-timings = [00 15 05 05 20 1f 05 + 05 03 03 04 00 12 15]; + qcom,display-topology = <1 1 1>, + <2 2 1>, /* dsc merge */ + <2 1 1>; /* 3d mux */ + qcom,default-topology-index = <1>; + }; + }; +}; + +&dsi_sharp_4k_dsc_video { + qcom,mdss-dsi-t-clk-post = <0x18>; + qcom,mdss-dsi-t-clk-pre = <0x19>; + qcom,mdss-dsi-display-timings { + timing@0{ + qcom,mdss-dsi-panel-phy-timings = [00 1e 08 07 24 22 08 + 08 05 03 04 00 19 18]; + qcom,display-topology = <2 2 2>; + qcom,default-topology-index = <0>; + }; + }; +}; + +&dsi_sharp_4k_dsc_cmd { + qcom,mdss-dsi-t-clk-post = <0x18>; + qcom,mdss-dsi-t-clk-pre = <0x19>; + qcom,mdss-dsi-display-timings { + timing@0{ + qcom,mdss-dsi-panel-phy-timings = [00 1e 08 07 24 22 08 + 08 05 03 04 00 19 18]; + qcom,display-topology = <2 2 2>; + qcom,default-topology-index = <0>; + }; + }; +}; + +&dsi_nt35695b_truly_fhd_video { + qcom,mdss-dsi-t-clk-post = <0x17>; + qcom,mdss-dsi-t-clk-pre = <0x19>; + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-phy-timings = [00 1e 08 07 24 22 + 08 08 05 03 04 00 19 17]; + qcom,display-topology = <1 0 1>; + qcom,default-topology-index = <0>; + }; + }; +}; + +&dsi_nt35695b_truly_fhd_cmd { + qcom,mdss-dsi-t-clk-post = <0x17>; + qcom,mdss-dsi-t-clk-pre = <0x19>; + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-phy-timings = [00 1e 08 07 24 22 + 08 08 05 03 04 00 19 17]; + qcom,display-topology = <1 0 1>; + qcom,default-topology-index = <0>; + }; + }; +}; + +&dsi_dual_sharp_1080_120hz_cmd { + qcom,mdss-dsi-t-clk-post = <0x0f>; + qcom,mdss-dsi-t-clk-pre = <0x36>; + qcom,mdss-dsi-display-timings { + timing@0{ + qcom,mdss-dsi-panel-phy-timings = [00 24 09 09 26 24 09 + 09 06 03 04 00]; + qcom,display-topology = <2 0 2>, + <1 0 2>; + qcom,default-topology-index = <0>; + }; + }; +}; + +&dsi_sharp_1080_cmd { + qcom,mdss-dsi-t-clk-post = <0x0c>; + qcom,mdss-dsi-t-clk-pre = <0x29>; + qcom,mdss-dsi-display-timings { + timing@0{ + qcom,mdss-dsi-panel-phy-timings = [00 1A 06 06 22 20 07 + 07 04 03 04 00]; + qcom,display-topology = <1 0 1>; + qcom,default-topology-index = <0>; + }; + }; +}; + +&dsi_sim_vid { + qcom,mdss-dsi-t-clk-post = <0x0d>; + qcom,mdss-dsi-t-clk-pre = <0x2d>; + qcom,mdss-dsi-display-timings { + timing@0{ + qcom,mdss-dsi-panel-phy-timings = [01 03 01 00 01 01 01 + 01 00 03 04 00 03 04]; + qcom,display-topology = <1 0 1>, + <2 0 1>; + qcom,default-topology-index = <0>; + }; + }; +}; + +&dsi_dual_sim_vid { + qcom,mdss-dsi-t-clk-post = <0x0d>; + qcom,mdss-dsi-t-clk-pre = <0x2d>; + qcom,mdss-dsi-display-timings { + timing@0{ + qcom,mdss-dsi-panel-phy-timings = [00 13 03 03 05 06 03 + 03 02 03 04 00 10 06]; + qcom,display-topology = <2 0 2>, + <1 0 2>; + qcom,default-topology-index = <0>; + }; + }; +}; + +&dsi_sim_cmd { + qcom,mdss-dsi-t-clk-post = <0x0d>; + qcom,mdss-dsi-t-clk-pre = <0x2d>; + qcom,mdss-dsi-display-timings { + timing@0{ + qcom,mdss-dsi-panel-phy-timings = [00 03 01 00 01 01 02 + 01 00 03 04 00 03 04]; + qcom,display-topology = <1 0 1>, + <2 0 1>; + qcom,default-topology-index = <0>; + }; + }; +}; + +&dsi_dual_sim_cmd { + qcom,mdss-dsi-t-clk-post = <0x0d>; + qcom,mdss-dsi-t-clk-pre = <0x2d>; + qcom,mdss-dsi-display-timings { + timing@0{ + qcom,mdss-dsi-panel-phy-timings = [00 13 03 03 05 06 03 + 03 02 03 04 00 10 06]; + qcom,display-topology = <2 0 2>; + qcom,default-topology-index = <0>; + }; + timing@1{ + qcom,mdss-dsi-panel-phy-timings = [00 13 03 03 05 06 03 + 03 02 03 04 00 10 06]; + qcom,display-topology = <2 0 2>, + <1 0 2>; + qcom,default-topology-index = <0>; + }; + timing@2{ + qcom,mdss-dsi-panel-phy-timings = [00 13 03 03 05 06 03 + 03 02 03 04 00 10 06]; + qcom,display-topology = <2 0 2>; + qcom,default-topology-index = <0>; + }; + }; +}; + +&dsi_sim_dsc_375_cmd { + qcom,mdss-dsi-t-clk-post = <0x0d>; + qcom,mdss-dsi-t-clk-pre = <0x2d>; + qcom,mdss-dsi-display-timings { + timing@0 { /* 1080p */ + qcom,mdss-dsi-panel-phy-timings = [00 12 03 04 07 07 04 + 04 03 03 04 00 13 07]; + qcom,display-topology = <1 1 1>; + qcom,default-topology-index = <0>; + }; + timing@1 { /* qhd */ + qcom,mdss-dsi-panel-phy-timings = [00 12 03 04 07 07 04 + 04 03 03 04 00 13 07]; + qcom,display-topology = <1 1 1>, + <2 2 1>, /* dsc merge */ + <2 1 1>; /* 3d mux */ + qcom,default-topology-index = <0>; + }; + }; +}; + +&dsi_dual_sim_dsc_375_cmd { + qcom,mdss-dsi-t-clk-post = <0x0d>; + qcom,mdss-dsi-t-clk-pre = <0x2d>; + qcom,mdss-dsi-display-timings { + timing@0 { /* qhd */ + qcom,mdss-dsi-panel-phy-timings = [00 13 03 03 05 06 03 + 03 02 03 04 00 10 06]; + qcom,display-topology = <2 2 2>; + qcom,default-topology-index = <0>; + }; + timing@1 { /* 4k */ + qcom,mdss-dsi-panel-phy-timings = [00 13 03 03 05 06 03 + 03 02 03 04 00 10 06]; + qcom,display-topology = <2 2 2>; + qcom,default-topology-index = <0>; + }; + }; +}; + +&dsi_sw43404_amoled_cmd { + qcom,mdss-dsi-t-clk-post = <0x16>; + qcom,mdss-dsi-t-clk-pre = <0x16>; + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-phy-timings = [00 1a 07 06 22 21 07 + 07 04 03 04 00 16 16]; + qcom,display-topology = <2 2 1>; + qcom,default-topology-index = <0>; + }; + }; +}; -- GitLab From b99b216b5c0875335ef2b5a9338c7512645730bf Mon Sep 17 00:00:00 2001 From: Shashank Babu Chinta Venkata Date: Tue, 3 Apr 2018 15:50:59 -0700 Subject: [PATCH 0421/1635] ARM: dts: msm: add 7nm DSI pll dtsi entries for sdm shrike Add DSI 7nm pll nodes for sdm shrike. Change-Id: I05004c1d545ba30edd667560c2e394eefb6a8905 Signed-off-by: Shashank Babu Chinta Venkata Signed-off-by: Ingrid Gallardo --- .../boot/dts/qcom/sdmshrike-sde-pll.dtsi | 68 +++++++++++++++++++ arch/arm64/boot/dts/qcom/sdmshrike.dtsi | 2 + 2 files changed, 70 insertions(+) create mode 100644 arch/arm64/boot/dts/qcom/sdmshrike-sde-pll.dtsi diff --git a/arch/arm64/boot/dts/qcom/sdmshrike-sde-pll.dtsi b/arch/arm64/boot/dts/qcom/sdmshrike-sde-pll.dtsi new file mode 100644 index 000000000000..6b350e54feb2 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdmshrike-sde-pll.dtsi @@ -0,0 +1,68 @@ +/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +&soc { + mdss_dsi0_pll: qcom,mdss_dsi_pll@ae94900 { + compatible = "qcom,mdss_dsi_pll_7nm"; + label = "MDSS DSI 0 PLL"; + cell-index = <0>; + #clock-cells = <1>; + reg = <0xae94900 0x260>, + <0xae94400 0x800>, + <0xaf03000 0x8>; + reg-names = "pll_base", "phy_base", "gdsc_base"; + clocks = <&clock_dispcc DISP_CC_MDSS_AHB_CLK>; + clock-names = "iface_clk"; + clock-rate = <0>; + gdsc-supply = <&mdss_core_gdsc>; + qcom,platform-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + qcom,platform-supply-entry@0 { + reg = <0>; + qcom,supply-name = "gdsc"; + qcom,supply-min-voltage = <0>; + qcom,supply-max-voltage = <0>; + qcom,supply-enable-load = <0>; + qcom,supply-disable-load = <0>; + }; + }; + }; + + mdss_dsi1_pll: qcom,mdss_dsi_pll@ae96900 { + compatible = "qcom,mdss_dsi_pll_7nm"; + label = "MDSS DSI 1 PLL"; + cell-index = <1>; + #clock-cells = <1>; + reg = <0xae96900 0x260>, + <0xae96400 0x800>, + <0xaf03000 0x8>; + reg-names = "pll_base", "phy_base", "gdsc_base"; + clocks = <&clock_dispcc DISP_CC_MDSS_AHB_CLK>; + clock-names = "iface_clk"; + clock-rate = <0>; + gdsc-supply = <&mdss_core_gdsc>; + qcom,platform-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + qcom,platform-supply-entry@0 { + reg = <0>; + qcom,supply-name = "gdsc"; + qcom,supply-min-voltage = <0>; + qcom,supply-max-voltage = <0>; + qcom,supply-enable-load = <0>; + qcom,supply-disable-load = <0>; + }; + }; + }; + +}; diff --git a/arch/arm64/boot/dts/qcom/sdmshrike.dtsi b/arch/arm64/boot/dts/qcom/sdmshrike.dtsi index 50d45696f779..85a4819dccb9 100644 --- a/arch/arm64/boot/dts/qcom/sdmshrike.dtsi +++ b/arch/arm64/boot/dts/qcom/sdmshrike.dtsi @@ -334,6 +334,8 @@ }; #include "sdmshrike-gdsc.dtsi" +#include "sdmshrike-sde-pll.dtsi" +#include "sdmshrike-sde.dtsi" &soc { #address-cells = <1>; -- GitLab From 58c732c4339efd5d2683aa41c8dafc8091c37286 Mon Sep 17 00:00:00 2001 From: Ingrid Gallardo Date: Wed, 11 Apr 2018 12:20:37 -0700 Subject: [PATCH 0422/1635] ARM: dts: msm: add default display for sdmshrike Add sharp 4k panel dual dsi command mode as default display to sdmshrike. Add panel reset gpio and mode select gpio for sharp 4k panel. Change-Id: I5ef14b70fa991830fcc18efed8eadfc14acde227 Signed-off-by: Ingrid Gallardo --- arch/arm64/boot/dts/qcom/sdmshrike-cdp.dtsi | 27 +++++++++++++++++++++ arch/arm64/boot/dts/qcom/sdmshrike-mtp.dtsi | 27 +++++++++++++++++++++ 2 files changed, 54 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sdmshrike-cdp.dtsi b/arch/arm64/boot/dts/qcom/sdmshrike-cdp.dtsi index ec52ab558887..4a58d7a9bcd8 100644 --- a/arch/arm64/boot/dts/qcom/sdmshrike-cdp.dtsi +++ b/arch/arm64/boot/dts/qcom/sdmshrike-cdp.dtsi @@ -12,6 +12,7 @@ #include #include +#include "sdmshrike-sde-display.dtsi" #include "sdmshrike-pmic-overlay.dtsi" @@ -51,6 +52,32 @@ status = "ok"; }; +&dsi_sharp_4k_dsc_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-dsi-mode-sel-gpio-state = "dual_port"; + qcom,panel-mode-gpio = <&tlmm 6 0>; + qcom,platform-te-gpio = <&tlmm 8 0>; + qcom,platform-reset-gpio = <&tlmm 7 0>; +}; + +&dsi_sharp_4k_dsc_video { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-dsi-mode-sel-gpio-state = "dual_port"; + qcom,panel-mode-gpio = <&tlmm 6 0>; + qcom,platform-te-gpio = <&tlmm 8 0>; + qcom,platform-reset-gpio = <&tlmm 7 0>; +}; + +&dsi_sharp_4k_dsc_cmd_display { + qcom,dsi-display-active; +}; + &pm855l_lcdb { status = "ok"; }; diff --git a/arch/arm64/boot/dts/qcom/sdmshrike-mtp.dtsi b/arch/arm64/boot/dts/qcom/sdmshrike-mtp.dtsi index ec52ab558887..4a58d7a9bcd8 100644 --- a/arch/arm64/boot/dts/qcom/sdmshrike-mtp.dtsi +++ b/arch/arm64/boot/dts/qcom/sdmshrike-mtp.dtsi @@ -12,6 +12,7 @@ #include #include +#include "sdmshrike-sde-display.dtsi" #include "sdmshrike-pmic-overlay.dtsi" @@ -51,6 +52,32 @@ status = "ok"; }; +&dsi_sharp_4k_dsc_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-dsi-mode-sel-gpio-state = "dual_port"; + qcom,panel-mode-gpio = <&tlmm 6 0>; + qcom,platform-te-gpio = <&tlmm 8 0>; + qcom,platform-reset-gpio = <&tlmm 7 0>; +}; + +&dsi_sharp_4k_dsc_video { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-dsi-mode-sel-gpio-state = "dual_port"; + qcom,panel-mode-gpio = <&tlmm 6 0>; + qcom,platform-te-gpio = <&tlmm 8 0>; + qcom,platform-reset-gpio = <&tlmm 7 0>; +}; + +&dsi_sharp_4k_dsc_cmd_display { + qcom,dsi-display-active; +}; + &pm855l_lcdb { status = "ok"; }; -- GitLab From 3d6b9df5b18ee7fba0c26b0366eef329021cb6ff Mon Sep 17 00:00:00 2001 From: Carter Cooper Date: Mon, 16 Apr 2018 11:30:20 -0600 Subject: [PATCH 0423/1635] msm: kgsl: Write a cookie into HFI write buffer remainder HFI commands can be any number of dwords in length. But commands are required to start at 4 dword alignemnt. Instead of skipping any remainder dwords at the end of a command (and possibly leaving junk in them), write a cookie into the unused dwords up to the next alignment. Change-Id: I12f3f1c37aa09fe57f08f6a1d0bd2cf122e93ee1 Signed-off-by: Carter Cooper --- drivers/gpu/msm/kgsl_hfi.c | 29 +++++++++++------------------ 1 file changed, 11 insertions(+), 18 deletions(-) diff --git a/drivers/gpu/msm/kgsl_hfi.c b/drivers/gpu/msm/kgsl_hfi.c index 83364bcc75ba..6751982b1588 100644 --- a/drivers/gpu/msm/kgsl_hfi.c +++ b/drivers/gpu/msm/kgsl_hfi.c @@ -45,22 +45,6 @@ (((minor) & 0x7FFFFF) << 5) | \ ((branch) & 0x1F)) -/* - * hfi_align_idx() - Update index based on HFI version - * @gmu: Pointer to a GMU device - * @idx: Integer that is either a read or write index - * @boundary: boundary of adjusted ptr value. Exceeding the boundary - * will reset ptr to 0 - */ -static int hfi_align_idx(struct gmu_device *gmu, int idx, int boundary) -{ - if (HFI_VER_MAJOR(&gmu->hfi) >= 2) { - idx = ALIGN(idx, SZ_4); - return (idx < boundary) ? idx : 0; - } - return idx; -} - /* Size in below functions are in unit of dwords */ static int hfi_queue_read(struct gmu_device *gmu, uint32_t queue_idx, unsigned int *output, unsigned int max_size) @@ -109,7 +93,10 @@ static int hfi_queue_read(struct gmu_device *gmu, uint32_t queue_idx, result = -ENODATA; } - hdr->read_index = hfi_align_idx(gmu, read, hdr->queue_size); + if (HFI_VER_MAJOR(&gmu->hfi) >= 2) + read = ALIGN(read, SZ_4) % hdr->queue_size; + + hdr->read_index = read; return result; } @@ -164,7 +151,13 @@ static int hfi_queue_write(struct gmu_device *gmu, uint32_t queue_idx, write = (write + 1) % hdr->queue_size; } - hdr->write_index = hfi_align_idx(gmu, write, hdr->queue_size); + /* Cookify any non used data at the end of the write buffer */ + if (HFI_VER_MAJOR(&gmu->hfi) >= 2) { + for (; write % 4; write = (write + 1) % hdr->queue_size) + queue[write] = 0xFAFAFAFA; + } + + hdr->write_index = write; mutex_unlock(&hfi->cmdq_mutex); -- GitLab From ce24eac1a9be77d96519e98fed1bbb45f93b36a5 Mon Sep 17 00:00:00 2001 From: Swathi Sridhar Date: Mon, 16 Apr 2018 11:39:14 -0700 Subject: [PATCH 0424/1635] defconfig: sdmshrike: Enable iommu debugfs interface on sdmshrike Enable iommu debugfs interface on sdmshrike Change-Id: I9d805122383b66c0362135d9b5d1b568c4896128 Signed-off-by: Swathi Sridhar --- arch/arm64/configs/sdmshrike-perf_defconfig | 3 +++ arch/arm64/configs/sdmshrike_defconfig | 3 +++ 2 files changed, 6 insertions(+) diff --git a/arch/arm64/configs/sdmshrike-perf_defconfig b/arch/arm64/configs/sdmshrike-perf_defconfig index ef70e9d78300..8da24fa8d733 100644 --- a/arch/arm64/configs/sdmshrike-perf_defconfig +++ b/arch/arm64/configs/sdmshrike-perf_defconfig @@ -362,6 +362,9 @@ CONFIG_QCOM_APCS_IPC=y CONFIG_MSM_QMP=y CONFIG_ARM_SMMU=y CONFIG_QCOM_LAZY_MAPPING=y +CONFIG_IOMMU_DEBUG=y +CONFIG_IOMMU_DEBUG_TRACKING=y +CONFIG_IOMMU_TESTS=y CONFIG_RPMSG_CHAR=y CONFIG_RPMSG_QCOM_GLINK_SMEM=y CONFIG_QCOM_LLCC=y diff --git a/arch/arm64/configs/sdmshrike_defconfig b/arch/arm64/configs/sdmshrike_defconfig index 6ffc799dd16e..f0983c783a5f 100644 --- a/arch/arm64/configs/sdmshrike_defconfig +++ b/arch/arm64/configs/sdmshrike_defconfig @@ -375,6 +375,9 @@ CONFIG_QCOM_APCS_IPC=y CONFIG_MSM_QMP=y CONFIG_ARM_SMMU=y CONFIG_QCOM_LAZY_MAPPING=y +CONFIG_IOMMU_DEBUG=y +CONFIG_IOMMU_DEBUG_TRACKING=y +CONFIG_IOMMU_TESTS=y CONFIG_RPMSG_CHAR=y CONFIG_RPMSG_QCOM_GLINK_SMEM=y CONFIG_QCOM_LLCC=y -- GitLab From fae333a5e89ae836924fb85d33086ded2e7b979a Mon Sep 17 00:00:00 2001 From: Kyle Yan Date: Fri, 13 Apr 2018 11:12:50 -0700 Subject: [PATCH 0425/1635] defconfig: sdmshrike: Enable various devfreq devices on sdmshrike Enable devfreq drivers for sdmshrike. Change-Id: I696e8cb12b9bbae752e331eb3bc2f3115605fd5e Signed-off-by: Kyle Yan --- arch/arm64/configs/sdmshrike-perf_defconfig | 9 +++++++++ arch/arm64/configs/sdmshrike_defconfig | 9 +++++++++ 2 files changed, 18 insertions(+) diff --git a/arch/arm64/configs/sdmshrike-perf_defconfig b/arch/arm64/configs/sdmshrike-perf_defconfig index ef70e9d78300..6eb2c8863dc2 100644 --- a/arch/arm64/configs/sdmshrike-perf_defconfig +++ b/arch/arm64/configs/sdmshrike-perf_defconfig @@ -383,6 +383,15 @@ CONFIG_QTI_RPMH_API=y CONFIG_QCOM_GLINK=y CONFIG_QCOM_GLINK_PKT=y CONFIG_QCOM_FSA4480_I2C=y +CONFIG_DEVFREQ_GOV_PASSIVE=y +CONFIG_QCOM_BIMC_BWMON=y +CONFIG_ARM_MEMLAT_MON=y +CONFIG_QCOMCCI_HWMON=y +CONFIG_QCOM_M4M_HWMON=y +CONFIG_DEVFREQ_GOV_QCOM_BW_HWMON=y +CONFIG_DEVFREQ_GOV_QCOM_CACHE_HWMON=y +CONFIG_DEVFREQ_GOV_MEMLAT=y +CONFIG_QCOM_DEVFREQ_DEVBW=y CONFIG_EXTCON_USB_GPIO=y CONFIG_IIO=y CONFIG_QCOM_SPMI_ADC5=y diff --git a/arch/arm64/configs/sdmshrike_defconfig b/arch/arm64/configs/sdmshrike_defconfig index 6ffc799dd16e..76224d2519f9 100644 --- a/arch/arm64/configs/sdmshrike_defconfig +++ b/arch/arm64/configs/sdmshrike_defconfig @@ -397,6 +397,15 @@ CONFIG_QTI_RPMH_API=y CONFIG_QCOM_GLINK=y CONFIG_QCOM_GLINK_PKT=y CONFIG_QCOM_FSA4480_I2C=y +CONFIG_DEVFREQ_GOV_PASSIVE=y +CONFIG_QCOM_BIMC_BWMON=y +CONFIG_ARM_MEMLAT_MON=y +CONFIG_QCOMCCI_HWMON=y +CONFIG_QCOM_M4M_HWMON=y +CONFIG_DEVFREQ_GOV_QCOM_BW_HWMON=y +CONFIG_DEVFREQ_GOV_QCOM_CACHE_HWMON=y +CONFIG_DEVFREQ_GOV_MEMLAT=y +CONFIG_QCOM_DEVFREQ_DEVBW=y CONFIG_EXTCON_USB_GPIO=y CONFIG_IIO=y CONFIG_QCOM_SPMI_ADC5=y -- GitLab From e4ec2969a5a59c4795a51f424a9bebab262cf640 Mon Sep 17 00:00:00 2001 From: Sujeev Dias Date: Fri, 13 Apr 2018 11:42:05 -0700 Subject: [PATCH 0426/1635] defconfig: sm8150: Enable MHI host driver stack MHI Host Interface is a communication protocol to be used by the host to control and communicate with modem over a high speed peripheral bus. Enabling this stack will allow host to communicate with external devices that support MHI protocol. CRs-Fixed: 2204910 Change-Id: I856b035d196885420797594e3c274390b5504237 Signed-off-by: Sujeev Dias --- arch/arm64/configs/sm8150-perf_defconfig | 4 ++++ arch/arm64/configs/sm8150_defconfig | 5 +++++ 2 files changed, 9 insertions(+) diff --git a/arch/arm64/configs/sm8150-perf_defconfig b/arch/arm64/configs/sm8150-perf_defconfig index cfec319adefc..7c9a5e1913e1 100644 --- a/arch/arm64/configs/sm8150-perf_defconfig +++ b/arch/arm64/configs/sm8150-perf_defconfig @@ -234,6 +234,10 @@ CONFIG_NFC_NQ=y CONFIG_FW_LOADER_USER_HELPER_FALLBACK=y CONFIG_REGMAP_ALLOW_WRITE_DEBUGFS=y CONFIG_DMA_CMA=y +CONFIG_MHI_BUS=y +CONFIG_MHI_QCOM=y +CONFIG_MHI_NETDEV=y +CONFIG_MHI_UCI=y CONFIG_ZRAM=y CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_RAM=y diff --git a/arch/arm64/configs/sm8150_defconfig b/arch/arm64/configs/sm8150_defconfig index 41bf474b81c5..59eb3638cb90 100644 --- a/arch/arm64/configs/sm8150_defconfig +++ b/arch/arm64/configs/sm8150_defconfig @@ -240,6 +240,11 @@ CONFIG_NFC_NQ=y CONFIG_FW_LOADER_USER_HELPER_FALLBACK=y CONFIG_REGMAP_ALLOW_WRITE_DEBUGFS=y CONFIG_DMA_CMA=y +CONFIG_MHI_BUS=y +CONFIG_MHI_DEBUG=y +CONFIG_MHI_QCOM=y +CONFIG_MHI_NETDEV=y +CONFIG_MHI_UCI=y CONFIG_ZRAM=y CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_RAM=y -- GitLab From 3fac46072c6ddedd1ec8859f31ec1d3f8813b1a9 Mon Sep 17 00:00:00 2001 From: Chinmay Sawarkar Date: Mon, 16 Apr 2018 15:25:43 -0700 Subject: [PATCH 0427/1635] msm: vidc: Remove inversion of video priority ctrl value Priority control value set by client match the values expected by firmware. Realtime Enable=1 for both, hence inversion is not required. CRs-Fixed: 2225514 Change-Id: I24aff5ea62af4339919655ff6417d1443b232764 Signed-off-by: Chinmay Sawarkar --- drivers/media/platform/msm/vidc/msm_vdec.c | 5 +---- drivers/media/platform/msm/vidc/msm_venc.c | 5 +---- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/drivers/media/platform/msm/vidc/msm_vdec.c b/drivers/media/platform/msm/vidc/msm_vdec.c index 498ade998dc8..033fc60d1536 100644 --- a/drivers/media/platform/msm/vidc/msm_vdec.c +++ b/drivers/media/platform/msm/vidc/msm_vdec.c @@ -1128,10 +1128,7 @@ int msm_vdec_s_ctrl(struct msm_vidc_inst *inst, struct v4l2_ctrl *ctrl) break; case V4L2_CID_MPEG_VIDC_VIDEO_PRIORITY: property_id = HAL_CONFIG_REALTIME; - /* firmware has inverted values for realtime and - * non-realtime priority - */ - hal_property.enable = !(ctrl->val); + hal_property.enable = ctrl->val; pdata = &hal_property; switch (ctrl->val) { case V4L2_MPEG_MSM_VIDC_DISABLE: diff --git a/drivers/media/platform/msm/vidc/msm_venc.c b/drivers/media/platform/msm/vidc/msm_venc.c index 892dcbcb839a..06fb23f94300 100644 --- a/drivers/media/platform/msm/vidc/msm_venc.c +++ b/drivers/media/platform/msm/vidc/msm_venc.c @@ -1828,10 +1828,7 @@ int msm_venc_s_ctrl(struct msm_vidc_inst *inst, struct v4l2_ctrl *ctrl) } case V4L2_CID_MPEG_VIDC_VIDEO_PRIORITY: property_id = HAL_CONFIG_REALTIME; - /* firmware has inverted values for realtime and - * non-realtime priority - */ - enable.enable = !(ctrl->val); + enable.enable = ctrl->val; pdata = &enable; switch (ctrl->val) { case V4L2_MPEG_MSM_VIDC_DISABLE: -- GitLab From b9428952cd2e6d6f28fc70fd4947027e8d77a4ac Mon Sep 17 00:00:00 2001 From: Sujeev Dias Date: Fri, 13 Apr 2018 17:40:05 -0700 Subject: [PATCH 0428/1635] ARM: dts: msm: Add MHI device tree nodes for sm8150 Add MHI host device tree node for MHI host driver. MHI bus allows host to control and communicate with external modem over high speed peripheral bus. CRs-Fixed: 2204910 Change-Id: Id0259ae53e876c3217eacd9727225da580aee2d8 Signed-off-by: Sujeev Dias --- arch/arm64/boot/dts/qcom/sm8150-cdp.dtsi | 5 ++ arch/arm64/boot/dts/qcom/sm8150-mtp.dtsi | 5 ++ arch/arm64/boot/dts/qcom/sm8150-sdx50m.dtsi | 13 ++++ arch/arm64/boot/dts/qcom/sm8150.dtsi | 71 +++++++++++++++++++++ 4 files changed, 94 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sm8150-cdp.dtsi b/arch/arm64/boot/dts/qcom/sm8150-cdp.dtsi index 98208f2a82c0..3a74720f6713 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-cdp.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-cdp.dtsi @@ -499,3 +499,8 @@ &wil6210 { status = "ok"; }; + +&mhi_0 { + mhi,fw-name = "debug.mbn"; + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/qcom/sm8150-mtp.dtsi b/arch/arm64/boot/dts/qcom/sm8150-mtp.dtsi index 8ae926fcfb4f..fb731aaa3db0 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-mtp.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-mtp.dtsi @@ -503,3 +503,8 @@ &wil6210 { status = "ok"; }; + +&mhi_0 { + mhi,fw-name = "debug.mbn"; + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/qcom/sm8150-sdx50m.dtsi b/arch/arm64/boot/dts/qcom/sm8150-sdx50m.dtsi index a47cac09c479..28eba3e155f2 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-sdx50m.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-sdx50m.dtsi @@ -38,3 +38,16 @@ }; }; }; + +&mhi_0 { + esoc-names = "mdm"; + esoc-0 = <&mdm3>; + qcom,smmu-cfg = <0x1d>; + qcom,addr-win = <0x0 0x20000000 0x0 0x3fffffff>; + mhi,fw-name = "sdx50m/sbl1.mbn"; + status = "okay"; +}; + +&pcie1 { + dma-coherent; +}; diff --git a/arch/arm64/boot/dts/qcom/sm8150.dtsi b/arch/arm64/boot/dts/qcom/sm8150.dtsi index 60c177c79204..8d526f5a19fa 100644 --- a/arch/arm64/boot/dts/qcom/sm8150.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150.dtsi @@ -40,6 +40,9 @@ sdhc2 = &sdhc_2; /* SDC2 SD card slot */ pci-domain0 = &pcie0; /* PCIe0 domain */ pci-domain1 = &pcie1; /* PCIe1 domain */ + mhi0 = &mhi_0; + mhi_netdev0 = &mhi_netdev_0; + mhi_netdev1 = &mhi_netdev_1; }; aliases { @@ -3179,6 +3182,74 @@ qcom,smmu-coherent; status = "disabled"; }; + + mhi_0: qcom,mhi@0 { + /* controller specific configuration */ + compatible = "qcom,mhi"; + qcom,pci-domain = <1>; + qcom,pci-bus = <1>; + qcom,pci-slot = <0>; + qcom,smmu-cfg = <0x3>; + qcom,msm-bus,name = "mhi"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <100 512 0 0>, + <100 512 1200000000 650000000>; + + /* mhi bus specific settings */ + mhi,max-channels = <106>; + mhi,chan-cfg = + <0 64 2 1 2 0 2 0 0>, <1 64 2 2 2 0 2 0 0>, + <2 128 1 1 2 0 1 0 0>, <3 128 1 2 2 0 1 0 0>, + <4 64 1 1 2 0 2 0 0>, <5 64 3 2 2 0 2 0 0x8>, + <8 64 1 1 2 0 2 0 0>, <9 64 1 2 2 0 2 0 0>, + <10 64 1 1 2 0 2 0 0>, <11 64 1 2 2 0 2 0 0>, + <14 64 1 1 2 0 2 0 0>, <15 64 2 2 2 0 2 0 0>, + <16 64 3 1 2 0 2 0 0>, <17 64 3 2 2 0 2 0 0>, + <18 64 1 1 2 0 2 0 0>, <19 64 1 2 2 0 2 0 0>, + <20 64 2 1 2 0 2 1 0>, <21 64 2 2 2 0 2 0 0x8>, + <22 64 2 1 2 0 2 0 0>, <23 64 2 2 2 0 2 0 0>, + <24 64 2 1 2 0 1 0 0>, <25 64 2 2 2 0 1 0 0>, + <26 64 3 1 2 0 2 0 0>, <27 64 3 2 2 0 2 0 0>, + <32 64 3 1 2 0 2 0 0>, <33 64 3 2 2 0 2 0 0>, + <100 512 4 1 3 1 2 1 0x4>, <101 512 5 2 3 1 2 1 0>; + mhi,chan-names = "LOOPBACK", "LOOPBACK", + "SAHARA", "SAHARA", + "DIAG", "DIAG", + "QDSS", "QDSS", + "EFS", "EFS", + "QMI0", "QMI0", + "QMI1", "QMI1", + "IP_CTRL", "IP_CTRL", + "IPCR", "IPCR", + "TF", "TF", + "BL", "BL", + "DCI", "DCI", + "DUN", "DUN", + "IP_HW0", "IP_HW0"; + mhi,ev-cfg = <32 0 1 0 1 2 0x8>, + <256 1 2 0 1 2 0>, + <256 1 3 0 1 2 0>, + <256 1 4 0 1 2 0>, + <1024 5 5 100 1 3 0x1>, + <1024 5 6 101 1 3 0x3>; + mhi,timeout = <2000>; + status = "disabled"; + + mhi_netdev_0: mhi_rmnet@0 { + mhi,chan = "IP_HW0"; + mhi,interface-name = "rmnet_mhi"; + mhi,mru = <0x4000>; + mhi,recycle-buf; + }; + + mhi_netdev_1: mhi_rmnet@1 { + mhi,chan = "IP_HW_ADPL"; + mhi,interface-name = "rmnet_mhi"; + mhi,mru = <0x4000>; + }; + }; }; &emac_gdsc { -- GitLab From d3badbe62b54b3ab2cb439a98a5949aa4831da85 Mon Sep 17 00:00:00 2001 From: "Isaac J. Manjarres" Date: Mon, 16 Apr 2018 16:11:44 -0700 Subject: [PATCH 0429/1635] Revert "ARM: dts: msm: Add a test thermal zone for SM8150" This reverts commit 2f994ded4e87a6ee0950fb5d78c6913d00d3e972. Change-Id: I9a1fcf9174a8cc327a74d539315ed32d937423f8 Signed-off-by: Isaac J. Manjarres --- arch/arm64/boot/dts/qcom/sm8150-thermal.dtsi | 47 -------------------- 1 file changed, 47 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sm8150-thermal.dtsi b/arch/arm64/boot/dts/qcom/sm8150-thermal.dtsi index f1f86faaa635..43cd31adfaaa 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-thermal.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-thermal.dtsi @@ -2197,51 +2197,4 @@ }; }; }; - - pop-mem-test { - polling-delay-passive = <10>; - polling-delay = <0>; - thermal-sensors = <&tsens1 3>; - thermal-governor = "step_wise"; - disable-thermal-zone; - trips { - pop_test_trip: pop-test-trip { - temperature = <95000>; - hysteresis = <0>; - type = "passive"; - }; - }; - cooling-maps { - pop_test_cdev0 { - trip = <&pop_test_trip>; - cooling-device = - <&modem_pa THERMAL_NO_LIMIT - THERMAL_NO_LIMIT>; - }; - pop_test_cdev1 { - trip = <&pop_test_trip>; - cooling-device = - <&modem_proc THERMAL_NO_LIMIT - THERMAL_NO_LIMIT>; - }; - pop_test_cdev2 { - trip = <&pop_test_trip>; - cooling-device = - <&modem_current THERMAL_NO_LIMIT - THERMAL_NO_LIMIT>; - }; - pop_test_cdev3 { - trip = <&pop_test_trip>; - cooling-device = - <&modem_skin THERMAL_NO_LIMIT - THERMAL_NO_LIMIT>; - }; - pop_test_cdev4 { - trip = <&pop_test_trip>; - cooling-device = - <&mdss_mdp THERMAL_NO_LIMIT - THERMAL_NO_LIMIT>; - }; - }; - }; }; -- GitLab From 15620de32e90b942df09d4487fcd9c755c407bee Mon Sep 17 00:00:00 2001 From: Tony Truong Date: Mon, 16 Apr 2018 17:54:47 -0700 Subject: [PATCH 0430/1635] ARM: dts: msm: update PCIe clock frequencies for SM8150 With the new addition of PCIe sleep clock in PCIe bus driver, update PCIe clock frequency tables for SM8150. Change-Id: I555f7cd3427a2897e99dd8d60480602fb225b1a7 Signed-off-by: Tony Truong --- arch/arm64/boot/dts/qcom/sm8150-pcie.dtsi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sm8150-pcie.dtsi b/arch/arm64/boot/dts/qcom/sm8150-pcie.dtsi index 10e13adfb850..e8a66b6551c6 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-pcie.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-pcie.dtsi @@ -262,7 +262,7 @@ "pcie_tbu_clk", "pcie_phy_refgen_clk", "pcie_phy_aux_clk"; - max-clock-frequency-hz = <0>, <0>, <19200000>, <0>, <0>, + max-clock-frequency-hz = <0>, <0>, <19200000>, <0>, <0>, <0>, <0>, <0>, <0>, <0>, <100000000>, <0>; resets = <&clock_gcc GCC_PCIE_0_BCR>, @@ -552,7 +552,7 @@ "pcie_tbu_clk", "pcie_phy_refgen_clk", "pcie_phy_aux_clk"; - max-clock-frequency-hz = <0>, <0>, <19200000>, <0>, <0>, + max-clock-frequency-hz = <0>, <0>, <19200000>, <0>, <0>, <0>, <0>, <0>, <0>, <0>, <100000000>, <0>; resets = <&clock_gcc GCC_PCIE_1_BCR>, -- GitLab From 4d2072f04eda28ae246e04c1cf061a2072e3095b Mon Sep 17 00:00:00 2001 From: Raghavendra Rao Ananta Date: Mon, 16 Apr 2018 19:14:44 -0700 Subject: [PATCH 0431/1635] AndroidKernel: Add configuration for the LLVM path Set LLVM path depending on the configuration done by the build system. Change-Id: Ib4ebf15c17c2febfee44404df0d2582625f11516 Signed-off-by: Raghavendra Rao Ananta --- AndroidKernel.mk | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/AndroidKernel.mk b/AndroidKernel.mk index c84f70958ba7..af4e1b404d9b 100644 --- a/AndroidKernel.mk +++ b/AndroidKernel.mk @@ -47,6 +47,20 @@ else KERNEL_CROSS_COMPILE := $(TARGET_KERNEL_CROSS_COMPILE_PREFIX) endif +ifeq ($(KERNEL_LLVM_SUPPORT), true) + ifeq ($(KERNEL_SD_LLVM_SUPPORT), true) #Using sd-llvm compiler + ifeq ($(shell echo $(SDCLANG_PATH_2) | head -c 1),/) + KERNEL_LLVM_BIN := $(SDCLANG_PATH_2)/clang + else + KERNEL_LLVM_BIN := $(ANDROID_BUILD_TOP)/$(SDCLANG_PATH_2)/clang + endif + $(warning "Using sdllvm" $(KERNEL_LLVM_BIN)) + else + KERNEL_LLVM_BIN := $(ANDROID_BUILD_TOP)/$(CLANG) #Using aosp-llvm compiler + $(warning "Using aosp-llvm" $(KERNEL_LLVM_BIN)) + endif +endif + ifeq ($(TARGET_PREBUILT_KERNEL),) KERNEL_GCC_NOANDROID_CHK := $(shell (echo "int main() {return 0;}" | $(KERNEL_CROSS_COMPILE)gcc -E -mno-android - > /dev/null 2>&1 ; echo $$?)) -- GitLab From b9cfffacf822a0ae111632645ff7b449980baafd Mon Sep 17 00:00:00 2001 From: Skylar Chang Date: Mon, 5 Feb 2018 15:44:34 -0800 Subject: [PATCH 0432/1635] msm: ipa3: support HW stats query for LTE Add support on IPA-driver to get HW stats for usb/wlan tethering under LTE backhaul. Change-Id: I0c87419f35431e5175d1050a446f7fc882369972 Signed-off-by: Skylar Chang --- drivers/platform/msm/ipa/ipa_v3/ipa.c | 4 +- .../platform/msm/ipa/ipa_v3/ipa_hw_stats.c | 185 +++++++++++++----- drivers/platform/msm/ipa/ipa_v3/ipa_i.h | 7 +- drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c | 159 ++++++++++++++- 4 files changed, 296 insertions(+), 59 deletions(-) diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa.c b/drivers/platform/msm/ipa/ipa_v3/ipa.c index 80edd9500fa2..082fdc53d9e4 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa.c @@ -4566,8 +4566,6 @@ static int ipa3_post_init(const struct ipa3_plat_drv_res *resource_p, IPADBG("teth_bridge initialized"); } - ipa3_debugfs_init(); - result = ipa3_uc_interface_init(); if (result) IPAERR(":ipa Uc interface init failed (%d)\n", -result); @@ -4605,6 +4603,8 @@ static int ipa3_post_init(const struct ipa3_plat_drv_res *resource_p, complete_all(&ipa3_ctx->init_completion_obj); pr_info("IPA driver initialization was successful.\n"); + ipa3_debugfs_init(); + return 0; fail_teth_bridge_driver_init: diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_hw_stats.c b/drivers/platform/msm/ipa/ipa_v3/ipa_hw_stats.c index 65fa40b2681b..79cec5ae5f4c 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_hw_stats.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_hw_stats.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -24,12 +24,63 @@ int ipa_hw_stats_init(void) { + int ret = 0, ep_index; + struct ipa_teth_stats_endpoints *teth_stats_init; + if (ipa3_ctx->ipa_hw_type < IPA_HW_v4_0) return 0; /* initialize stats here */ ipa3_ctx->hw_stats.enabled = true; - return 0; + + teth_stats_init = kzalloc(sizeof(*teth_stats_init), GFP_KERNEL); + if (!teth_stats_init) { + IPAERR("mem allocated failed!\n"); + return -ENOMEM; + } + /* enable prod mask */ + teth_stats_init->prod_mask = ( + IPA_CLIENT_BIT_32(IPA_CLIENT_Q6_WAN_PROD) | + IPA_CLIENT_BIT_32(IPA_CLIENT_USB_PROD) | + IPA_CLIENT_BIT_32(IPA_CLIENT_WLAN1_PROD)); + + if (IPA_CLIENT_BIT_32(IPA_CLIENT_Q6_WAN_PROD)) { + ep_index = ipa3_get_ep_mapping(IPA_CLIENT_Q6_WAN_PROD); + if (ep_index == -1) { + IPAERR("Invalid client.\n"); + kfree(teth_stats_init); + return -EINVAL; + } + teth_stats_init->dst_ep_mask[ep_index] = + (IPA_CLIENT_BIT_32(IPA_CLIENT_WLAN1_CONS) | + IPA_CLIENT_BIT_32(IPA_CLIENT_USB_CONS)); + } + + if (IPA_CLIENT_BIT_32(IPA_CLIENT_USB_PROD)) { + ep_index = ipa3_get_ep_mapping(IPA_CLIENT_USB_PROD); + if (ep_index == -1) { + IPAERR("Invalid client.\n"); + kfree(teth_stats_init); + return -EINVAL; + } + teth_stats_init->dst_ep_mask[ep_index] = + IPA_CLIENT_BIT_32(IPA_CLIENT_Q6_WAN_CONS); + } + + if (IPA_CLIENT_BIT_32(IPA_CLIENT_WLAN1_PROD)) { + ep_index = ipa3_get_ep_mapping(IPA_CLIENT_WLAN1_PROD); + if (ep_index == -1) { + IPAERR("Invalid client.\n"); + kfree(teth_stats_init); + return -EINVAL; + } + teth_stats_init->dst_ep_mask[ep_index] = + IPA_CLIENT_BIT_32(IPA_CLIENT_Q6_WAN_CONS); + } + + ret = ipa_init_teth_stats(teth_stats_init); + kfree(teth_stats_init); + return ret; } int ipa_init_quota_stats(u32 pipe_bitmask) @@ -347,9 +398,12 @@ int ipa_init_teth_stats(struct ipa_teth_stats_endpoints *in) /* reset driver's cache */ memset(&ipa3_ctx->hw_stats.teth.init, 0, sizeof(ipa3_ctx->hw_stats.teth.init)); - for (i = 0; i < IPA_CLIENT_MAX; i++) + for (i = 0; i < IPA_CLIENT_MAX; i++) { + memset(&ipa3_ctx->hw_stats.teth.prod_stats_sum[i], 0, + sizeof(ipa3_ctx->hw_stats.teth.prod_stats_sum[i])); memset(&ipa3_ctx->hw_stats.teth.prod_stats[i], 0, sizeof(ipa3_ctx->hw_stats.teth.prod_stats[i])); + } ipa3_ctx->hw_stats.teth.init.prod_bitmask = in->prod_mask; memcpy(ipa3_ctx->hw_stats.teth.init.cons_bitmask, in->dst_ep_mask, sizeof(ipa3_ctx->hw_stats.teth.init.cons_bitmask)); @@ -457,8 +511,7 @@ int ipa_init_teth_stats(struct ipa_teth_stats_endpoints *in) return ret; } -int ipa_get_teth_stats(enum ipa_client_type prod, - struct ipa_quota_stats_all *out) +int ipa_get_teth_stats(void) { int i, j; int ret; @@ -468,16 +521,17 @@ int ipa_get_teth_stats(enum ipa_client_type prod, struct ipahal_imm_cmd_pyld *cmd_pyld; struct ipa_mem_buffer mem; struct ipa3_desc desc = { 0 }; - struct ipahal_stats_tethering_all *stats; + struct ipahal_stats_tethering_all *stats_all; + struct ipa_hw_stats_teth *sw_stats = &ipa3_ctx->hw_stats.teth; + struct ipahal_stats_tethering *stats; + struct ipa_quota_stats *quota_stats; + struct ipahal_stats_init_tethering *init = + (struct ipahal_stats_init_tethering *) + &ipa3_ctx->hw_stats.teth.init; if (!ipa3_ctx->hw_stats.enabled) return 0; - if (!IPA_CLIENT_IS_PROD(prod) || ipa3_get_ep_mapping(prod) == -1) { - IPAERR("invalid prod %d\n", prod); - return -EINVAL; - } - get_offset.init = ipa3_ctx->hw_stats.teth.init; ret = ipahal_stats_get_offset(IPAHAL_HW_STATS_TETHERING, &get_offset, &offset); @@ -524,20 +578,26 @@ int ipa_get_teth_stats(enum ipa_client_type prod, goto destroy_imm; } - stats = kzalloc(sizeof(*stats), GFP_KERNEL); - if (!stats) { + stats_all = kzalloc(sizeof(*stats_all), GFP_KERNEL); + if (!stats_all) { IPADBG("failed to alloc memory\n"); ret = -ENOMEM; goto destroy_imm; } ret = ipahal_parse_stats(IPAHAL_HW_STATS_TETHERING, - &ipa3_ctx->hw_stats.teth.init, mem.base, stats); + &ipa3_ctx->hw_stats.teth.init, mem.base, stats_all); if (ret) { - IPAERR("failed to parse stats (error %d)\n", ret); + IPAERR("failed to parse stats_all (error %d)\n", ret); goto free_stats; } + /* reset prod_stats cache */ + for (i = 0; i < IPA_CLIENT_MAX; i++) { + memset(&ipa3_ctx->hw_stats.teth.prod_stats[i], 0, + sizeof(ipa3_ctx->hw_stats.teth.prod_stats[i])); + } + /* * update driver cache. * the stats were read from hardware with clear_after_read meaning @@ -545,8 +605,6 @@ int ipa_get_teth_stats(enum ipa_client_type prod, */ for (i = 0; i < IPA_CLIENT_MAX; i++) { for (j = 0; j < IPA_CLIENT_MAX; j++) { - struct ipa_hw_stats_teth *sw_stats = - &ipa3_ctx->hw_stats.teth; int prod_idx = ipa3_get_ep_mapping(i); int cons_idx = ipa3_get_ep_mapping(j); @@ -556,32 +614,53 @@ int ipa_get_teth_stats(enum ipa_client_type prod, if (cons_idx == -1 || cons_idx >= IPA3_MAX_NUM_PIPES) continue; - if (ipa3_ctx->ep[prod_idx].client != i || - ipa3_ctx->ep[cons_idx].client != j) - continue; - - sw_stats->prod_stats[i].client[j].num_ipv4_bytes += - stats->stats[prod_idx][cons_idx].num_ipv4_bytes; - sw_stats->prod_stats[i].client[j].num_ipv4_pkts += - stats->stats[prod_idx][cons_idx].num_ipv4_pkts; - sw_stats->prod_stats[i].client[j].num_ipv6_bytes += - stats->stats[prod_idx][cons_idx].num_ipv6_bytes; - sw_stats->prod_stats[i].client[j].num_ipv6_pkts += - stats->stats[prod_idx][cons_idx].num_ipv6_pkts; + /* save hw-query result */ + if ((init->prod_bitmask & (1 << prod_idx)) && + (init->cons_bitmask[prod_idx] + & (1 << cons_idx))) { + IPADBG_LOW("prod %d cons %d\n", + prod_idx, cons_idx); + stats = &stats_all->stats[prod_idx][cons_idx]; + IPADBG_LOW("num_ipv4_bytes %lld\n", + stats->num_ipv4_bytes); + IPADBG_LOW("num_ipv4_pkts %lld\n", + stats->num_ipv4_pkts); + IPADBG_LOW("num_ipv6_pkts %lld\n", + stats->num_ipv6_pkts); + IPADBG_LOW("num_ipv6_bytes %lld\n", + stats->num_ipv6_bytes); + + /* update stats*/ + quota_stats = + &sw_stats->prod_stats[i].client[j]; + quota_stats->num_ipv4_bytes = + stats->num_ipv4_bytes; + quota_stats->num_ipv4_pkts = + stats->num_ipv4_pkts; + quota_stats->num_ipv6_bytes = + stats->num_ipv6_bytes; + quota_stats->num_ipv6_pkts = + stats->num_ipv6_pkts; + + /* Accumulated stats */ + quota_stats = + &sw_stats->prod_stats_sum[i].client[j]; + quota_stats->num_ipv4_bytes += + stats->num_ipv4_bytes; + quota_stats->num_ipv4_pkts += + stats->num_ipv4_pkts; + quota_stats->num_ipv6_bytes += + stats->num_ipv6_bytes; + quota_stats->num_ipv6_pkts += + stats->num_ipv6_pkts; + } } } - if (!out) { - ret = 0; - goto free_stats; - } - - /* copy results to out parameter */ - *out = ipa3_ctx->hw_stats.teth.prod_stats[prod]; - ret = 0; free_stats: - kfree(stats); + kfree(stats_all); + stats = NULL; destroy_imm: ipahal_destroy_imm_cmd(cmd_pyld); free_dma_mem: @@ -590,6 +669,22 @@ int ipa_get_teth_stats(enum ipa_client_type prod, } +int ipa_query_teth_stats(enum ipa_client_type prod, + struct ipa_quota_stats_all *out, bool reset) +{ + if (!IPA_CLIENT_IS_PROD(prod) || ipa3_get_ep_mapping(prod) == -1) { + IPAERR("invalid prod %d\n", prod); + return -EINVAL; + } + + /* copy results to out parameter */ + if (reset) + *out = ipa3_ctx->hw_stats.teth.prod_stats[prod]; + else + *out = ipa3_ctx->hw_stats.teth.prod_stats_sum[prod]; + return 0; +} + int ipa_reset_teth_stats(enum ipa_client_type prod, enum ipa_client_type cons) { int ret; @@ -604,14 +699,14 @@ int ipa_reset_teth_stats(enum ipa_client_type prod, enum ipa_client_type cons) } /* reading stats will reset them in hardware */ - ret = ipa_get_teth_stats(prod, NULL); + ret = ipa_get_teth_stats(); if (ret) { IPAERR("ipa_get_teth_stats failed %d\n", ret); return ret; } /* reset driver's cache */ - stats = &ipa3_ctx->hw_stats.teth.prod_stats[prod].client[cons]; + stats = &ipa3_ctx->hw_stats.teth.prod_stats_sum[prod].client[cons]; memset(stats, 0, sizeof(*stats)); return 0; } @@ -631,7 +726,7 @@ int ipa_reset_all_cons_teth_stats(enum ipa_client_type prod) } /* reading stats will reset them in hardware */ - ret = ipa_get_teth_stats(prod, NULL); + ret = ipa_get_teth_stats(); if (ret) { IPAERR("ipa_get_teth_stats failed %d\n", ret); return ret; @@ -639,7 +734,7 @@ int ipa_reset_all_cons_teth_stats(enum ipa_client_type prod) /* reset driver's cache */ for (i = 0; i < IPA_CLIENT_MAX; i++) { - stats = &ipa3_ctx->hw_stats.teth.prod_stats[prod].client[i]; + stats = &ipa3_ctx->hw_stats.teth.prod_stats_sum[prod].client[i]; memset(stats, 0, sizeof(*stats)); } @@ -658,7 +753,7 @@ int ipa_reset_all_teth_stats(void) /* reading stats will reset them in hardware */ for (i = 0; i < IPA_CLIENT_MAX; i++) { if (IPA_CLIENT_IS_PROD(i) && ipa3_get_ep_mapping(i) != -1) { - ret = ipa_get_teth_stats(i, NULL); + ret = ipa_get_teth_stats(); if (ret) { IPAERR("ipa_get_teth_stats failed %d\n", ret); return ret; @@ -670,7 +765,7 @@ int ipa_reset_all_teth_stats(void) /* reset driver's cache */ for (i = 0; i < IPA_CLIENT_MAX; i++) { - stats = &ipa3_ctx->hw_stats.teth.prod_stats[i]; + stats = &ipa3_ctx->hw_stats.teth.prod_stats_sum[i]; memset(stats, 0, sizeof(*stats)); } @@ -1564,7 +1659,7 @@ static ssize_t ipa_debugfs_print_tethering_stats(struct file *file, (1 << ep_idx))) continue; - res = ipa_get_teth_stats(i, out); + res = ipa_get_teth_stats(); if (res) { mutex_unlock(&ipa3_ctx->lock); kfree(out); diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h index 615b701ac387..68999274fda8 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h @@ -1141,6 +1141,7 @@ struct ipa_hw_stats_quota { struct ipa_hw_stats_teth { struct ipahal_stats_init_tethering init; + struct ipa_quota_stats_all prod_stats_sum[IPA_CLIENT_MAX]; struct ipa_quota_stats_all prod_stats[IPA_CLIENT_MAX]; }; @@ -2276,8 +2277,10 @@ int ipa_reset_all_drop_stats(void); int ipa_init_teth_stats(struct ipa_teth_stats_endpoints *in); -int ipa_get_teth_stats(enum ipa_client_type prod, - struct ipa_quota_stats_all *out); +int ipa_get_teth_stats(void); + +int ipa_query_teth_stats(enum ipa_client_type prod, + struct ipa_quota_stats_all *out, bool reset); int ipa_reset_teth_stats(enum ipa_client_type prod, enum ipa_client_type cons); diff --git a/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c b/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c index f4bace874975..10406bb27111 100644 --- a/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c +++ b/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c @@ -3130,9 +3130,6 @@ static int rmnet_ipa3_query_tethering_stats_modem( req->reset_stats_valid = true; req->reset_stats = true; IPAWANDBG("reset the pipe stats\n"); - } else { - /* print tethered-client enum */ - IPAWANDBG("Tethered-client enum(%d)\n", data->ipa_client); } rc = ipa3_qmi_get_data_stats(req, resp); @@ -3203,8 +3200,8 @@ static int rmnet_ipa3_query_tethering_stats_modem( (unsigned long int) stat_ptr->num_ipv6_bytes); if (ipa_get_client_uplink( stat_ptr->pipe_index) == true) { - if (data->ipa_client == - stat_ptr->pipe_index) { + if (data->ipa_client == ipa_get_client( + stat_ptr->pipe_index)) { /* update the DL stats */ data->ipv4_tx_packets += stat_ptr->num_ipv4_packets; @@ -3228,6 +3225,133 @@ static int rmnet_ipa3_query_tethering_stats_modem( return 0; } +static int rmnet_ipa3_query_tethering_stats_hw( + struct wan_ioctl_query_tether_stats *data, bool reset) +{ + int rc = 0; + struct ipa_quota_stats_all *con_stats; + + if (reset) { + IPAWANERR("only reset the pipe stats without returning stats"); + rc = ipa_get_teth_stats(); + if (rc) { + IPAWANERR("ipa_get_teth_stats failed %d,\n", rc); + return rc; + } + return 0; + } + /* qet HW-stats */ + rc = ipa_get_teth_stats(); + if (rc) { + IPAWANDBG("ipa_get_teth_stats failed %d,\n", rc); + return rc; + } + + /* query DL stats */ + IPAWANDBG("reset the pipe stats? (%d)\n", reset); + con_stats = kzalloc(sizeof(*con_stats), GFP_KERNEL); + if (!con_stats) { + IPAWANERR("no memory\n"); + return -ENOMEM; + } + rc = ipa_query_teth_stats(IPA_CLIENT_Q6_WAN_PROD, con_stats, reset); + if (rc) { + IPAERR("IPA_CLIENT_Q6_WAN_PROD query failed %d,\n", rc); + kfree(con_stats); + return rc; + } + IPAWANDBG("wlan: v4_rx_p(%d) b(%lld) v6_rx_p(%d) b(%lld)\n", + con_stats->client[IPA_CLIENT_WLAN1_CONS].num_ipv4_pkts, + con_stats->client[IPA_CLIENT_WLAN1_CONS].num_ipv4_bytes, + con_stats->client[IPA_CLIENT_WLAN1_CONS].num_ipv6_pkts, + con_stats->client[IPA_CLIENT_WLAN1_CONS].num_ipv6_bytes); + + IPAWANDBG("usb: v4_rx_p(%d) b(%lld) v6_rx_p(%d) b(%lld)\n", + con_stats->client[IPA_CLIENT_USB_CONS].num_ipv4_pkts, + con_stats->client[IPA_CLIENT_USB_CONS].num_ipv4_bytes, + con_stats->client[IPA_CLIENT_USB_CONS].num_ipv6_pkts, + con_stats->client[IPA_CLIENT_USB_CONS].num_ipv6_bytes); + + /* update the DL stats */ + data->ipv4_rx_packets = + con_stats->client[IPA_CLIENT_WLAN1_CONS].num_ipv4_pkts + + con_stats->client[IPA_CLIENT_USB_CONS].num_ipv4_pkts; + data->ipv6_rx_packets = + con_stats->client[IPA_CLIENT_WLAN1_CONS].num_ipv6_pkts + + con_stats->client[IPA_CLIENT_USB_CONS].num_ipv6_pkts; + data->ipv4_rx_bytes = + con_stats->client[IPA_CLIENT_WLAN1_CONS].num_ipv4_bytes + + con_stats->client[IPA_CLIENT_USB_CONS].num_ipv4_bytes; + data->ipv6_rx_bytes = + con_stats->client[IPA_CLIENT_WLAN1_CONS].num_ipv6_bytes + + con_stats->client[IPA_CLIENT_USB_CONS].num_ipv6_bytes; + + IPAWANDBG("v4_rx_p(%lu) v6_rx_p(%lu) v4_rx_b(%lu) v6_rx_b(%lu)\n", + (unsigned long int) data->ipv4_rx_packets, + (unsigned long int) data->ipv6_rx_packets, + (unsigned long int) data->ipv4_rx_bytes, + (unsigned long int) data->ipv6_rx_bytes); + + /* query USB UL stats */ + memset(con_stats, 0, sizeof(struct ipa_quota_stats_all)); + rc = ipa_query_teth_stats(IPA_CLIENT_USB_PROD, con_stats, reset); + if (rc) { + IPAERR("IPA_CLIENT_USB_PROD query failed %d\n", rc); + kfree(con_stats); + return rc; + } + + IPAWANDBG("usb: v4_tx_p(%d) b(%lld) v6_tx_p(%d) b(%lld)\n", + con_stats->client[IPA_CLIENT_Q6_WAN_CONS].num_ipv4_pkts, + con_stats->client[IPA_CLIENT_Q6_WAN_CONS].num_ipv4_bytes, + con_stats->client[IPA_CLIENT_Q6_WAN_CONS].num_ipv6_pkts, + con_stats->client[IPA_CLIENT_Q6_WAN_CONS].num_ipv6_bytes); + + /* update the USB UL stats */ + data->ipv4_tx_packets = + con_stats->client[IPA_CLIENT_Q6_WAN_CONS].num_ipv4_pkts; + data->ipv6_tx_packets = + con_stats->client[IPA_CLIENT_Q6_WAN_CONS].num_ipv6_pkts; + data->ipv4_tx_bytes = + con_stats->client[IPA_CLIENT_Q6_WAN_CONS].num_ipv4_bytes; + data->ipv6_tx_bytes = + con_stats->client[IPA_CLIENT_Q6_WAN_CONS].num_ipv6_bytes; + + /* query WLAN UL stats */ + memset(con_stats, 0, sizeof(struct ipa_quota_stats_all)); + rc = ipa_query_teth_stats(IPA_CLIENT_WLAN1_PROD, con_stats, reset); + if (rc) { + IPAERR("IPA_CLIENT_WLAN1_PROD query failed %d\n", rc); + kfree(con_stats); + return rc; + } + + IPAWANDBG("wlan: v4_tx_p(%d) b(%lld) v6_tx_p(%d) b(%lld)\n", + con_stats->client[IPA_CLIENT_Q6_WAN_CONS].num_ipv4_pkts, + con_stats->client[IPA_CLIENT_Q6_WAN_CONS].num_ipv4_bytes, + con_stats->client[IPA_CLIENT_Q6_WAN_CONS].num_ipv6_pkts, + con_stats->client[IPA_CLIENT_Q6_WAN_CONS].num_ipv6_bytes); + + /* update the wlan UL stats */ + data->ipv4_tx_packets += + con_stats->client[IPA_CLIENT_Q6_WAN_CONS].num_ipv4_pkts; + data->ipv6_tx_packets += + con_stats->client[IPA_CLIENT_Q6_WAN_CONS].num_ipv6_pkts; + data->ipv4_tx_bytes += + con_stats->client[IPA_CLIENT_Q6_WAN_CONS].num_ipv4_bytes; + data->ipv6_tx_bytes += + con_stats->client[IPA_CLIENT_Q6_WAN_CONS].num_ipv6_bytes; + + IPAWANDBG("v4_tx_p(%lu) v6_tx_p(%lu) v4_tx_b(%lu) v6_tx_b(%lu)\n", + (unsigned long int) data->ipv4_tx_packets, + (unsigned long int) data->ipv6_tx_packets, + (unsigned long int) data->ipv4_tx_bytes, + (unsigned long int) data->ipv6_tx_bytes); + kfree(con_stats); + return rc; +} + + int rmnet_ipa3_query_tethering_stats(struct wan_ioctl_query_tether_stats *data, bool reset) { @@ -3297,11 +3421,26 @@ int rmnet_ipa3_query_tethering_stats_all( } else { IPAWANDBG_LOW(" query modem-backhaul stats\n"); tether_stats.ipa_client = data->ipa_client; - rc = rmnet_ipa3_query_tethering_stats_modem( - &tether_stats, data->reset_stats); - if (rc) { - IPAWANERR("modem WAN_IOC_QUERY_TETHER_STATS failed\n"); - return rc; + if (ipa3_ctx->ipa_hw_type < IPA_HW_v4_0 || + !ipa3_ctx->hw_stats.enabled) { + IPAWANDBG("hw version %d,hw_stats.enabled %d\n", + ipa3_ctx->ipa_hw_type, + ipa3_ctx->hw_stats.enabled); + /* get modem stats from QMI */ + rc = rmnet_ipa3_query_tethering_stats_modem( + &tether_stats, data->reset_stats); + if (rc) { + IPAWANERR("modem QUERY_TETHER_STATS failed\n"); + return rc; + } + } else { + /* get modem stats from IPA-HW counters */ + rc = rmnet_ipa3_query_tethering_stats_hw( + &tether_stats, data->reset_stats); + if (rc) { + IPAWANERR("modem QUERY_TETHER_STATS failed\n"); + return rc; + } } data->tx_bytes = tether_stats.ipv4_tx_bytes + tether_stats.ipv6_tx_bytes; -- GitLab From 9f4a8f9825d9c838799084845a25f2c910d8328f Mon Sep 17 00:00:00 2001 From: Swathi Sridhar Date: Mon, 16 Apr 2018 20:14:22 -0700 Subject: [PATCH 0433/1635] defconfig: sdmshrike: enable CONFIG_QCOM_SECURE_BUFFER Enable CONFIG_QCOM_SECURE_BUFFER for sdmshrike to enable secure ION allocations. Change-Id: I7711f2ecf80a69b06767ab1c94192ee25ecc0196 Signed-off-by: Swathi Sridhar --- arch/arm64/configs/sdmshrike-perf_defconfig | 1 + arch/arm64/configs/sdmshrike_defconfig | 1 + 2 files changed, 2 insertions(+) diff --git a/arch/arm64/configs/sdmshrike-perf_defconfig b/arch/arm64/configs/sdmshrike-perf_defconfig index ef70e9d78300..bc5c7a4de9f3 100644 --- a/arch/arm64/configs/sdmshrike-perf_defconfig +++ b/arch/arm64/configs/sdmshrike-perf_defconfig @@ -376,6 +376,7 @@ CONFIG_QCOM_SMSM=y CONFIG_MSM_SUBSYSTEM_RESTART=y CONFIG_MSM_PIL=y CONFIG_MSM_PIL_SSR_GENERIC=y +CONFIG_QCOM_SECURE_BUFFER=y CONFIG_QCOM_BUS_SCALING=y CONFIG_QCOM_BUS_CONFIG_RPMH=y CONFIG_QCOM_COMMAND_DB=y diff --git a/arch/arm64/configs/sdmshrike_defconfig b/arch/arm64/configs/sdmshrike_defconfig index 6ffc799dd16e..d28d577d6b46 100644 --- a/arch/arm64/configs/sdmshrike_defconfig +++ b/arch/arm64/configs/sdmshrike_defconfig @@ -390,6 +390,7 @@ CONFIG_QCOM_SMSM=y CONFIG_MSM_SUBSYSTEM_RESTART=y CONFIG_MSM_PIL=y CONFIG_MSM_PIL_SSR_GENERIC=y +CONFIG_QCOM_SECURE_BUFFER=y CONFIG_QCOM_BUS_SCALING=y CONFIG_QCOM_BUS_CONFIG_RPMH=y CONFIG_QCOM_COMMAND_DB=y -- GitLab From 10fd7410d72406a44d6b70059fad13b52d34e227 Mon Sep 17 00:00:00 2001 From: Tirupathi Reddy Date: Fri, 2 Mar 2018 14:08:39 +0530 Subject: [PATCH 0434/1635] misc: qpnp: add snapshot of qpnp-misc documentation qpnp-misc driver supports accessing MISC peripheral registers in certain PMICs. This is snapshot of the qpnp-misc device documentation as of msm-4.9 'commit 98cddae6cdce ("Merge "msm: camera: Fix media_entity assignment")'. Change-Id: Ic1e820e98dceb66195c56785e50590f1ba92f830 Signed-off-by: Tirupathi Reddy --- .../devicetree/bindings/misc/qpnp-misc.txt | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 Documentation/devicetree/bindings/misc/qpnp-misc.txt diff --git a/Documentation/devicetree/bindings/misc/qpnp-misc.txt b/Documentation/devicetree/bindings/misc/qpnp-misc.txt new file mode 100644 index 000000000000..a34cbde456e4 --- /dev/null +++ b/Documentation/devicetree/bindings/misc/qpnp-misc.txt @@ -0,0 +1,25 @@ +QPNP-MISC + +QPNP-MISC provides a way to read the PMIC part number and revision. + +Required properties: +- compatible : should be "qcom,qpnp-misc" +- reg : offset and length of the PMIC peripheral register map. + +Optional properties: +- qcom,pwm-sel: Select PWM source. Possible values: + 0: LOW + 1: PWM1_in + 2: PWM2_in + 3: PWM1_in & PWM2_in +- qcom,enable-gp-driver: Enable the GP driver. Should only be specified + if a non-zero PWM source is specified under + "qcom,pwm-sel" property. + +Example: + qcom,misc@900 { + compatible = "qcom,qpnp-misc"; + reg = <0x900 0x100>; + qcom,pwm-sel = <2>; + qcom,enable-gp-driver; + }; -- GitLab From e3c2d97b61a93def10ad70664b68d5c0cb0e65a0 Mon Sep 17 00:00:00 2001 From: Shefali Jain Date: Mon, 19 Mar 2018 10:19:45 +0530 Subject: [PATCH 0435/1635] ARM: dts: msm: Add GCC, CPU & RPM device node for QCS405 Add global clock controller, cpu controller and rpm clock device node to support the dummy clocks for clients to be able to request for the clocks. Change-Id: I7aa275f3ea5f8bf8059265f2533bdcab767a82e1 Signed-off-by: Shefali Jain --- arch/arm64/boot/dts/qcom/qcs405.dtsi | 31 ++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/qcs405.dtsi b/arch/arm64/boot/dts/qcom/qcs405.dtsi index 057ef01fd6c4..c9066a81296f 100644 --- a/arch/arm64/boot/dts/qcom/qcs405.dtsi +++ b/arch/arm64/boot/dts/qcom/qcs405.dtsi @@ -12,6 +12,9 @@ */ #include "skeleton64.dtsi" +#include +#include +#include / { model = "Qualcomm Technologies, Inc. QCS405"; @@ -133,6 +136,24 @@ clock-frequency = <32768>; }; + clock_rpmcc: qcom,rpmcc { + compatible = "qcom,dummycc"; + #clock-cells = <1>; + }; + + clock_gcc: qcom,gcc { + compatible = "qcom,dummycc"; + clock-output-names = "gcc_clocks"; + #clock-cells = <1>; + #reset-cells = <1>; + }; + + clock_cpu: qcom,cpu { + compatible = "qcom,dummycc"; + clock-output-names = "cpu_clocks"; + #clock-cells = <1>; + }; + cpu-pmu { compatible = "arm,armv8-pmuv3"; interrupts = <1 7 0xff00>; @@ -224,3 +245,13 @@ #thermal-sensor-cells = <1>; }; }; + +#include "qcs405-gdsc.dtsi" + +&gdsc_mdss { + status = "ok"; +}; + +&gdsc_oxili_gx { + status = "ok"; +}; -- GitLab From e92d48949650e3c87a2ca98b3cac582b11ce2d41 Mon Sep 17 00:00:00 2001 From: Shefali Jain Date: Fri, 6 Apr 2018 12:41:17 +0530 Subject: [PATCH 0436/1635] clk: qcom: gcc: Add global clock controller driver for QCS405 Add the clocks supported in global clock controller which clock the peripherals like BLSPs, SDCC, USB, MDSS etc. Register all the clocks to the clock framework for the clients to be able to request for them. Change-Id: I6e88109c8221023ddae7a0b17051b00d233f65c4 Signed-off-by: Shefali Jain --- .../devicetree/bindings/clock/qcom,gcc.txt | 2 + drivers/clk/qcom/Kconfig | 9 + drivers/clk/qcom/Makefile | 1 + drivers/clk/qcom/gcc-qcs405.c | 2847 +++++++++++++++++ drivers/clk/qcom/vdd-level-405.h | 43 + include/dt-bindings/clock/qcom,gcc-qcs405.h | 6 + 6 files changed, 2908 insertions(+) create mode 100644 drivers/clk/qcom/gcc-qcs405.c create mode 100644 drivers/clk/qcom/vdd-level-405.h diff --git a/Documentation/devicetree/bindings/clock/qcom,gcc.txt b/Documentation/devicetree/bindings/clock/qcom,gcc.txt index 3d99c632a420..4390120d11db 100644 --- a/Documentation/devicetree/bindings/clock/qcom,gcc.txt +++ b/Documentation/devicetree/bindings/clock/qcom,gcc.txt @@ -20,6 +20,8 @@ Required properties : "qcom,gcc-mdm9615" "qcom,gcc-sm8150" "qcom,gcc-sdmshrike" + "qcom,gcc-qcs405" + "qcom,gcc-mdss-qcs405" - reg : shall contain base register location and length - #clock-cells : shall contain 1 diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig index e7b664914068..e86ffd2c0cb3 100644 --- a/drivers/clk/qcom/Kconfig +++ b/drivers/clk/qcom/Kconfig @@ -315,3 +315,12 @@ config MSM_CAMCC_SDMSHRIKE SDMSHRIKE devices. Say Y if you want to support camera devices and functionality such as capturing pictures. + +config MDM_GCC_QCS405 + tristate "QCS405 Global Clock Controller" + depends on COMMON_CLK_QCOM + help + Support for the global clock controller on Qualcomm Technologies, Inc + QCS405 devices. + Say Y if you want to use peripheral devices such as UART, SPI, I2C, + USB, SD/eMMC, PCIe, etc. diff --git a/drivers/clk/qcom/Makefile b/drivers/clk/qcom/Makefile index 597663835aab..bdabc90ba6e9 100644 --- a/drivers/clk/qcom/Makefile +++ b/drivers/clk/qcom/Makefile @@ -25,6 +25,7 @@ obj-$(CONFIG_IPQ_GCC_806X) += gcc-ipq806x.o obj-$(CONFIG_IPQ_GCC_8074) += gcc-ipq8074.o obj-$(CONFIG_IPQ_LCC_806X) += lcc-ipq806x.o obj-$(CONFIG_MDM_GCC_9615) += gcc-mdm9615.o +obj-$(CONFIG_MDM_GCC_QCS405) += gcc-qcs405.o obj-$(CONFIG_MDM_LCC_9615) += lcc-mdm9615.o obj-$(CONFIG_MSM_CAMCC_SM8150) += camcc-sm8150.o obj-$(CONFIG_MSM_CAMCC_SDMSHRIKE) += camcc-sdmshrike.o diff --git a/drivers/clk/qcom/gcc-qcs405.c b/drivers/clk/qcom/gcc-qcs405.c new file mode 100644 index 000000000000..eb11ebeae5c8 --- /dev/null +++ b/drivers/clk/qcom/gcc-qcs405.c @@ -0,0 +1,2847 @@ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#define pr_fmt(fmt) "clk: %s: " fmt, __func__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "common.h" +#include "clk-regmap.h" +#include "clk-pll.h" +#include "clk-rcg.h" +#include "clk-branch.h" +#include "clk-voter.h" +#include "reset.h" +#include "clk-alpha-pll.h" +#include "vdd-level-405.h" + +#define F(f, s, h, m, n) { (f), (s), (2 * (h) - 1), (m), (n) } +#define F_SLEW(f, s, h, m, n, sf) { (f), (s), (2 * (h) - 1), (m), (n), (sf) } + +static DEFINE_VDD_REGULATORS(vdd_cx, VDD_NUM, 1, vdd_corner); + +enum { + P_CORE_BI_PLL_TEST_SE, + P_DSI0_PHY_PLL_OUT_BYTECLK, + P_DSI0_PHY_PLL_OUT_DSICLK, + P_GPLL0_OUT_AUX, + P_GPLL0_OUT_MAIN, + P_GPLL1_OUT_MAIN, + P_GPLL3_OUT_MAIN, + P_GPLL4_OUT_AUX, + P_GPLL4_OUT_MAIN, + P_GPLL6_OUT_AUX, + P_HDMI_PHY_PLL_CLK, + P_PCIE_0_PIPE_CLK, + P_SLEEP_CLK, + P_XO, +}; + +static const struct parent_map gcc_parent_map_0[] = { + { P_XO, 0 }, + { P_GPLL0_OUT_MAIN, 1 }, + { P_CORE_BI_PLL_TEST_SE, 7 }, +}; + +static const char * const gcc_parent_names_0[] = { + "cxo", + "gpll0_out_main", + "core_bi_pll_test_se", +}; + +static const char * const gcc_parent_names_ao_0[] = { + "cxo_a", + "gpll0_ao_out_main", + "core_bi_pll_test_se", +}; + +static const struct parent_map gcc_parent_map_1[] = { + { P_XO, 0 }, + { P_CORE_BI_PLL_TEST_SE, 7 }, +}; + +static const char * const gcc_parent_names_1[] = { + "cxo", + "core_bi_pll_test_se", +}; + +static const struct parent_map gcc_parent_map_2[] = { + { P_XO, 0 }, + { P_GPLL0_OUT_MAIN, 1 }, + { P_GPLL6_OUT_AUX, 2 }, + { P_SLEEP_CLK, 6 }, +}; + +static const char * const gcc_parent_names_2[] = { + "cxo", + "gpll0_out_main", + "gpll6_out_aux", + "sleep_clk", +}; + +static const struct parent_map gcc_parent_map_3[] = { + { P_XO, 0 }, + { P_GPLL0_OUT_MAIN, 1 }, + { P_GPLL6_OUT_AUX, 2 }, + { P_CORE_BI_PLL_TEST_SE, 7 }, +}; + +static const char * const gcc_parent_names_3[] = { + "cxo", + "gpll0_out_main", + "gpll6_out_aux", + "core_bi_pll_test_se", +}; + +static const struct parent_map gcc_parent_map_4[] = { + { P_XO, 0 }, + { P_GPLL1_OUT_MAIN, 1 }, + { P_CORE_BI_PLL_TEST_SE, 7 }, +}; + +static const char * const gcc_parent_names_4[] = { + "cxo", + "gpll1_out_main", + "core_bi_pll_test_se", +}; + +static const struct parent_map gcc_parent_map_5[] = { + { P_XO, 0 }, + { P_DSI0_PHY_PLL_OUT_BYTECLK, 1 }, + { P_GPLL0_OUT_AUX, 2 }, + { P_CORE_BI_PLL_TEST_SE, 7 }, +}; + +static const char * const gcc_parent_names_5[] = { + "cxo", + "dsi0_phy_pll_out_byteclk", + "gpll0_out_aux", + "core_bi_pll_test_se", +}; + +static const struct parent_map gcc_parent_map_6[] = { + { P_XO, 0 }, + { P_DSI0_PHY_PLL_OUT_BYTECLK, 2 }, + { P_GPLL0_OUT_AUX, 3 }, + { P_CORE_BI_PLL_TEST_SE, 7 }, +}; + +static const char * const gcc_parent_names_6[] = { + "cxo", + "dsi0_phy_pll_out_byteclk", + "gpll0_out_aux", + "core_bi_pll_test_se", +}; + +static const struct parent_map gcc_parent_map_7[] = { + { P_XO, 0 }, + { P_GPLL0_OUT_MAIN, 1 }, + { P_GPLL3_OUT_MAIN, 2 }, + { P_GPLL6_OUT_AUX, 3 }, + { P_GPLL4_OUT_AUX, 4 }, + { P_CORE_BI_PLL_TEST_SE, 7 }, +}; + +static const char * const gcc_parent_names_7[] = { + "cxo", + "gpll0_out_main", + "gpll3_out_main", + "gpll6_out_aux", + "gpll4_out_aux", + "core_bi_pll_test_se", +}; + +static const struct parent_map gcc_parent_map_8[] = { + { P_XO, 0 }, + { P_HDMI_PHY_PLL_CLK, 1 }, + { P_CORE_BI_PLL_TEST_SE, 7 }, +}; + +static const char * const gcc_parent_names_8[] = { + "cxo", + "hdmi_phy_pll_clk", + "core_bi_pll_test_se", +}; + +static const struct parent_map gcc_parent_map_9[] = { + { P_XO, 0 }, + { P_GPLL0_OUT_MAIN, 1 }, + { P_DSI0_PHY_PLL_OUT_DSICLK, 2 }, + { P_GPLL6_OUT_AUX, 3 }, + { P_CORE_BI_PLL_TEST_SE, 7 }, +}; + +static const char * const gcc_parent_names_9[] = { + "cxo", + "gpll0_out_main", + "dsi0_phy_pll_out_dsiclk", + "gpll6_out_aux", + "core_bi_pll_test_se", +}; + +static const struct parent_map gcc_parent_map_10[] = { + { P_XO, 0 }, + { P_SLEEP_CLK, 1 }, + { P_CORE_BI_PLL_TEST_SE, 7 }, +}; + +static const char * const gcc_parent_names_10[] = { + "cxo", + "sleep_clk", + "core_bi_pll_test_se", +}; + +static const struct parent_map gcc_parent_map_11[] = { + { P_XO, 0 }, + { P_PCIE_0_PIPE_CLK, 1 }, + { P_CORE_BI_PLL_TEST_SE, 7 }, +}; + +static const char * const gcc_parent_names_11[] = { + "cxo", + "pcie_0_pipe_clk", + "core_bi_pll_test_se", +}; + +static const struct parent_map gcc_parent_map_12[] = { + { P_XO, 0 }, + { P_DSI0_PHY_PLL_OUT_DSICLK, 1 }, + { P_GPLL0_OUT_AUX, 2 }, + { P_CORE_BI_PLL_TEST_SE, 7 }, +}; + +static const char * const gcc_parent_names_12[] = { + "cxo", + "dsi0_phy_pll_out_dsiclk", + "gpll0_out_aux", + "core_bi_pll_test_se", +}; + +static const struct parent_map gcc_parent_map_13[] = { + { P_XO, 0 }, + { P_GPLL0_OUT_MAIN, 1 }, + { P_GPLL4_OUT_MAIN, 2 }, + { P_GPLL6_OUT_AUX, 3 }, + { P_CORE_BI_PLL_TEST_SE, 7 }, +}; + +static const char * const gcc_parent_names_13[] = { + "cxo", + "gpll0_out_main", + "gpll4_out_main", + "gpll6_out_aux", + "core_bi_pll_test_se", +}; + +static const struct parent_map gcc_parent_map_14[] = { + { P_XO, 0 }, + { P_GPLL0_OUT_MAIN, 1 }, + { P_GPLL4_OUT_AUX, 2 }, + { P_CORE_BI_PLL_TEST_SE, 7 }, +}; + +static const char * const gcc_parent_names_14[] = { + "cxo", + "gpll0_out_main", + "gpll4_out_aux", + "core_bi_pll_test_se", +}; + +static const struct parent_map gcc_parent_map_15[] = { + { P_XO, 0 }, + { P_GPLL0_OUT_AUX, 2 }, + { P_CORE_BI_PLL_TEST_SE, 7 }, +}; + +static const char * const gcc_parent_names_15[] = { + "cxo", + "gpll0_out_aux", + "core_bi_pll_test_se", +}; + +static unsigned int soft_vote_gpll0; + +static struct clk_alpha_pll gpll0_sleep_clk_src = { + .offset = 0x21000, + .clkr = { + .enable_reg = 0x45008, + .enable_mask = BIT(23), + .enable_is_inverted = true, + .hw.init = &(struct clk_init_data){ + .name = "gpll0_sleep_clk_src", + .parent_names = (const char *[]){ "cxo" }, + .num_parents = 1, + .ops = &clk_pll_sleep_vote_ops, + }, + }, +}; + +static struct clk_alpha_pll gpll0_out_main = { + .offset = 0x21000, + .soft_vote = &soft_vote_gpll0, + .soft_vote_mask = PLL_SOFT_VOTE_PRIMARY, + .flags = SUPPORTS_FSM_MODE, + .clkr = { + .enable_reg = 0x45000, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gpll0_out_main", + .parent_names = (const char *[]) + { "gpll0_sleep_clk_src" }, + .num_parents = 1, + .ops = &clk_alpha_pll_ops, + }, + }, +}; + +static struct clk_alpha_pll gpll0_ao_out_main = { + .offset = 0x21000, + .soft_vote = &soft_vote_gpll0, + .soft_vote_mask = PLL_SOFT_VOTE_CPU, + .flags = SUPPORTS_FSM_MODE, + .clkr = { + .enable_reg = 0x45000, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gpll0_ao_out_main", + .parent_names = (const char *[]){ "cxo_a" }, + .num_parents = 1, + .ops = &clk_alpha_pll_ops, + }, + }, +}; + +static struct clk_alpha_pll gpll1_out_main = { + .offset = 0x20000, + .clkr = { + .enable_reg = 0x45000, + .enable_mask = BIT(1), + .hw.init = &(struct clk_init_data){ + .name = "gpll1_out_main", + .parent_names = (const char *[]){ "cxo" }, + .num_parents = 1, + .ops = &clk_alpha_pll_ops, + }, + }, +}; + +/* 930MHz configuration */ +static const struct alpha_pll_config gpll3_config = { + .l = 48, + .alpha = 0x0, + .alpha_u = 0x70, + .alpha_en_mask = BIT(24), + .post_div_mask = 0xf << 8, + .post_div_val = 0x1 << 8, + .vco_mask = 0x3 << 20, + .main_output_mask = 0x1, + .config_ctl_val = 0x4001055b, + .test_ctl_hi_val = 0x40000600, + .test_ctl_hi_mask = 0xffffffff, +}; + +static struct pll_vco gpll3_vco[] = { + { 700000000, 1400000000, 0 }, +}; + +static struct clk_alpha_pll gpll3_out_main = { + .offset = 0x22000, + .flags = SUPPORTS_SLEW, + .vco_table = gpll3_vco, + .num_vco = ARRAY_SIZE(gpll3_vco), + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "gpll3_out_main", + .parent_names = (const char *[]){ "cxo" }, + .num_parents = 1, + .ops = &clk_alpha_pll_slew_ops, + .vdd_class = &vdd_cx, + .num_rate_max = VDD_NUM, + .rate_max = (unsigned long[VDD_NUM]) { + [VDD_NOMINAL] = 1400000000}, + }, + }, +}; + +static struct clk_alpha_pll gpll4_out_main = { + .offset = 0x24000, + .clkr = { + .enable_reg = 0x45000, + .enable_mask = BIT(5), + .hw.init = &(struct clk_init_data){ + .name = "gpll4_out_main", + .parent_names = (const char *[]){ "cxo" }, + .num_parents = 1, + .ops = &clk_alpha_pll_ops, + }, + }, +}; + +static struct clk_pll gpll6 = { + .l_reg = 0x37004, + .m_reg = 0x37008, + .n_reg = 0x3700C, + .config_reg = 0x37014, + .mode_reg = 0x37000, + .status_reg = 0x3701C, + .status_bit = 17, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gpll6", + .parent_names = (const char *[]){ "cxo" }, + .num_parents = 1, + .ops = &clk_pll_ops, + }, +}; + + +static struct clk_regmap gpll6_out_aux = { + .enable_reg = 0x45000, + .enable_mask = BIT(7), + .hw.init = &(struct clk_init_data){ + .name = "gpll6_out_aux", + .parent_names = (const char *[]){ "gpll6" }, + .num_parents = 1, + .ops = &clk_pll_vote_ops, + }, +}; + +static const struct freq_tbl ftbl_apss_ahb_clk_src[] = { + F(19200000, P_XO, 1, 0, 0), + F(50000000, P_GPLL0_OUT_MAIN, 16, 0, 0), + F(100000000, P_GPLL0_OUT_MAIN, 8, 0, 0), + F(133333333, P_GPLL0_OUT_MAIN, 6, 0, 0), + { } +}; + +static struct clk_rcg2 apss_ahb_clk_src = { + .cmd_rcgr = 0x46000, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_apss_ahb_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "apss_ahb_clk_src", + .parent_names = gcc_parent_names_0, + .num_parents = 3, + .ops = &clk_rcg2_ops, + }, +}; + +static const struct freq_tbl ftbl_blsp1_qup0_i2c_apps_clk_src[] = { + F(19200000, P_XO, 1, 0, 0), + F(50000000, P_GPLL0_OUT_MAIN, 16, 0, 0), + { } +}; + +static struct clk_rcg2 blsp1_qup0_i2c_apps_clk_src = { + .cmd_rcgr = 0x602c, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_blsp1_qup0_i2c_apps_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "blsp1_qup0_i2c_apps_clk_src", + .parent_names = gcc_parent_names_0, + .num_parents = 3, + .ops = &clk_rcg2_ops, + .vdd_class = &vdd_cx, + .num_rate_max = VDD_NUM, + .rate_max = (unsigned long[VDD_NUM]) { + [VDD_LOW] = 50000000}, + }, +}; + +static const struct freq_tbl ftbl_blsp1_qup0_spi_apps_clk_src[] = { + F(960000, P_XO, 10, 1, 2), + F(4800000, P_XO, 4, 0, 0), + F(9600000, P_XO, 2, 0, 0), + F(16000000, P_GPLL0_OUT_MAIN, 10, 1, 5), + F(19200000, P_XO, 1, 0, 0), + F(25000000, P_GPLL0_OUT_MAIN, 16, 1, 2), + F(50000000, P_GPLL0_OUT_MAIN, 16, 0, 0), + { } +}; + +static struct clk_rcg2 blsp1_qup0_spi_apps_clk_src = { + .cmd_rcgr = 0x6034, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_blsp1_qup0_spi_apps_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "blsp1_qup0_spi_apps_clk_src", + .parent_names = gcc_parent_names_0, + .num_parents = 3, + .ops = &clk_rcg2_ops, + .vdd_class = &vdd_cx, + .num_rate_max = VDD_NUM, + .rate_max = (unsigned long[VDD_NUM]) { + [VDD_LOW] = 25000000, + [VDD_NOMINAL] = 50000000}, + }, +}; + +static struct clk_rcg2 blsp1_qup1_i2c_apps_clk_src = { + .cmd_rcgr = 0x200c, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_blsp1_qup0_i2c_apps_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "blsp1_qup1_i2c_apps_clk_src", + .parent_names = gcc_parent_names_0, + .num_parents = 3, + .ops = &clk_rcg2_ops, + .vdd_class = &vdd_cx, + .num_rate_max = VDD_NUM, + .rate_max = (unsigned long[VDD_NUM]) { + [VDD_LOW] = 50000000}, + }, +}; + +static struct clk_rcg2 blsp1_qup1_spi_apps_clk_src = { + .cmd_rcgr = 0x2024, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_blsp1_qup0_spi_apps_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "blsp1_qup1_spi_apps_clk_src", + .parent_names = gcc_parent_names_0, + .num_parents = 3, + .ops = &clk_rcg2_ops, + .vdd_class = &vdd_cx, + .num_rate_max = VDD_NUM, + .rate_max = (unsigned long[VDD_NUM]) { + [VDD_LOW] = 25000000, + [VDD_NOMINAL] = 50000000}, + }, +}; + +static struct clk_rcg2 blsp1_qup2_i2c_apps_clk_src = { + .cmd_rcgr = 0x3000, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_blsp1_qup0_i2c_apps_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "blsp1_qup2_i2c_apps_clk_src", + .parent_names = gcc_parent_names_0, + .num_parents = 3, + .ops = &clk_rcg2_ops, + .vdd_class = &vdd_cx, + .num_rate_max = VDD_NUM, + .rate_max = (unsigned long[VDD_NUM]) { + [VDD_LOW] = 50000000}, + }, +}; + +static struct clk_rcg2 blsp1_qup2_spi_apps_clk_src = { + .cmd_rcgr = 0x3014, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_blsp1_qup0_spi_apps_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "blsp1_qup2_spi_apps_clk_src", + .parent_names = gcc_parent_names_0, + .num_parents = 3, + .ops = &clk_rcg2_ops, + .vdd_class = &vdd_cx, + .num_rate_max = VDD_NUM, + .rate_max = (unsigned long[VDD_NUM]) { + [VDD_LOW] = 25000000, + [VDD_NOMINAL] = 50000000}, + }, +}; + +static struct clk_rcg2 blsp1_qup3_i2c_apps_clk_src = { + .cmd_rcgr = 0x4000, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_blsp1_qup0_i2c_apps_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "blsp1_qup3_i2c_apps_clk_src", + .parent_names = gcc_parent_names_0, + .num_parents = 3, + .ops = &clk_rcg2_ops, + .vdd_class = &vdd_cx, + .num_rate_max = VDD_NUM, + .rate_max = (unsigned long[VDD_NUM]) { + [VDD_LOW] = 50000000}, + }, +}; + +static struct clk_rcg2 blsp1_qup3_spi_apps_clk_src = { + .cmd_rcgr = 0x4024, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_blsp1_qup0_spi_apps_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "blsp1_qup3_spi_apps_clk_src", + .parent_names = gcc_parent_names_0, + .num_parents = 3, + .ops = &clk_rcg2_ops, + .vdd_class = &vdd_cx, + .num_rate_max = VDD_NUM, + .rate_max = (unsigned long[VDD_NUM]) { + [VDD_LOW] = 25000000, + [VDD_NOMINAL] = 50000000}, + }, +}; + +static struct clk_rcg2 blsp1_qup4_i2c_apps_clk_src = { + .cmd_rcgr = 0x5000, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_blsp1_qup0_i2c_apps_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "blsp1_qup4_i2c_apps_clk_src", + .parent_names = gcc_parent_names_0, + .num_parents = 3, + .ops = &clk_rcg2_ops, + .vdd_class = &vdd_cx, + .num_rate_max = VDD_NUM, + .rate_max = (unsigned long[VDD_NUM]) { + [VDD_LOW] = 50000000}, + }, +}; + +static struct clk_rcg2 blsp1_qup4_spi_apps_clk_src = { + .cmd_rcgr = 0x5024, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_blsp1_qup0_spi_apps_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "blsp1_qup4_spi_apps_clk_src", + .parent_names = gcc_parent_names_0, + .num_parents = 3, + .ops = &clk_rcg2_ops, + .vdd_class = &vdd_cx, + .num_rate_max = VDD_NUM, + .rate_max = (unsigned long[VDD_NUM]) { + [VDD_LOW] = 25000000, + [VDD_NOMINAL] = 50000000}, + }, +}; + +static const struct freq_tbl ftbl_blsp1_uart0_apps_clk_src[] = { + F(3686400, P_GPLL0_OUT_MAIN, 1, 72, 15625), + F(7372800, P_GPLL0_OUT_MAIN, 1, 144, 15625), + F(14745600, P_GPLL0_OUT_MAIN, 1, 288, 15625), + F(16000000, P_GPLL0_OUT_MAIN, 10, 1, 5), + F(19200000, P_XO, 1, 0, 0), + F(24000000, P_GPLL0_OUT_MAIN, 1, 3, 100), + F(25000000, P_GPLL0_OUT_MAIN, 16, 1, 2), + F(32000000, P_GPLL0_OUT_MAIN, 1, 1, 25), + F(40000000, P_GPLL0_OUT_MAIN, 1, 1, 20), + F(46400000, P_GPLL0_OUT_MAIN, 1, 29, 500), + F(48000000, P_GPLL0_OUT_MAIN, 1, 3, 50), + F(51200000, P_GPLL0_OUT_MAIN, 1, 8, 125), + F(56000000, P_GPLL0_OUT_MAIN, 1, 7, 100), + F(58982400, P_GPLL0_OUT_MAIN, 1, 1152, 15625), + F(60000000, P_GPLL0_OUT_MAIN, 1, 3, 40), + F(64000000, P_GPLL0_OUT_MAIN, 1, 2, 25), + { } +}; + +static struct clk_rcg2 blsp1_uart0_apps_clk_src = { + .cmd_rcgr = 0x600c, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_blsp1_uart0_apps_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "blsp1_uart0_apps_clk_src", + .parent_names = gcc_parent_names_0, + .num_parents = 3, + .ops = &clk_rcg2_ops, + .vdd_class = &vdd_cx, + .num_rate_max = VDD_NUM, + .rate_max = (unsigned long[VDD_NUM]) { + [VDD_LOW] = 32000000, + [VDD_NOMINAL] = 64000000}, + }, +}; + +static struct clk_rcg2 blsp1_uart1_apps_clk_src = { + .cmd_rcgr = 0x2044, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_blsp1_uart0_apps_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "blsp1_uart1_apps_clk_src", + .parent_names = gcc_parent_names_0, + .num_parents = 3, + .ops = &clk_rcg2_ops, + .vdd_class = &vdd_cx, + .num_rate_max = VDD_NUM, + .rate_max = (unsigned long[VDD_NUM]) { + [VDD_LOW] = 32000000, + [VDD_NOMINAL] = 64000000}, + }, +}; + +static struct clk_rcg2 blsp1_uart2_apps_clk_src = { + .cmd_rcgr = 0x3034, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_blsp1_uart0_apps_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "blsp1_uart2_apps_clk_src", + .parent_names = gcc_parent_names_0, + .num_parents = 3, + .ops = &clk_rcg2_ops, + .vdd_class = &vdd_cx, + .num_rate_max = VDD_NUM, + .rate_max = (unsigned long[VDD_NUM]) { + [VDD_LOW] = 32000000, + [VDD_NOMINAL] = 64000000}, + }, +}; + +static struct clk_rcg2 blsp1_uart3_apps_clk_src = { + .cmd_rcgr = 0x4014, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_blsp1_uart0_apps_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "blsp1_uart3_apps_clk_src", + .parent_names = gcc_parent_names_0, + .num_parents = 3, + .ops = &clk_rcg2_ops, + .vdd_class = &vdd_cx, + .num_rate_max = VDD_NUM, + .rate_max = (unsigned long[VDD_NUM]) { + [VDD_LOW] = 32000000, + [VDD_NOMINAL] = 64000000}, + }, +}; + +static struct clk_rcg2 blsp2_qup0_i2c_apps_clk_src = { + .cmd_rcgr = 0xc00c, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_blsp1_qup0_i2c_apps_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "blsp2_qup0_i2c_apps_clk_src", + .parent_names = gcc_parent_names_0, + .num_parents = 3, + .ops = &clk_rcg2_ops, + .vdd_class = &vdd_cx, + .num_rate_max = VDD_NUM, + .rate_max = (unsigned long[VDD_NUM]) { + [VDD_LOW] = 50000000}, + }, +}; + +static struct clk_rcg2 blsp2_qup0_spi_apps_clk_src = { + .cmd_rcgr = 0xc024, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_blsp1_qup0_spi_apps_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "blsp2_qup0_spi_apps_clk_src", + .parent_names = gcc_parent_names_0, + .num_parents = 3, + .ops = &clk_rcg2_ops, + .vdd_class = &vdd_cx, + .num_rate_max = VDD_NUM, + .rate_max = (unsigned long[VDD_NUM]) { + [VDD_LOW] = 25000000, + [VDD_NOMINAL] = 50000000}, + }, +}; + +static struct clk_rcg2 blsp2_uart0_apps_clk_src = { + .cmd_rcgr = 0xc044, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_blsp1_uart0_apps_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "blsp2_uart0_apps_clk_src", + .parent_names = gcc_parent_names_0, + .num_parents = 3, + .ops = &clk_rcg2_ops, + .vdd_class = &vdd_cx, + .num_rate_max = VDD_NUM, + .rate_max = (unsigned long[VDD_NUM]) { + [VDD_LOW] = 32000000, + [VDD_NOMINAL] = 64000000}, + }, +}; + +static struct clk_rcg2 byte0_clk_src = { + .cmd_rcgr = 0x4d044, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_5, + .clkr.hw.init = &(struct clk_init_data){ + .name = "byte0_clk_src", + .parent_names = gcc_parent_names_5, + .num_parents = 4, + .flags = CLK_GET_RATE_NOCACHE, + .ops = &clk_byte2_ops, + .vdd_class = &vdd_cx, + .num_rate_max = VDD_NUM, + .rate_max = (unsigned long[VDD_NUM]) { + [VDD_LOW] = 125000000, + [VDD_NOMINAL] = 187500000}, + }, +}; + +static const struct freq_tbl ftbl_emac_clk_src[] = { + F(125000000, P_GPLL1_OUT_MAIN, 4, 0, 0), + F(250000000, P_GPLL1_OUT_MAIN, 2, 0, 0), + { } +}; + +static struct clk_rcg2 emac_clk_src = { + .cmd_rcgr = 0x4e01c, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_parent_map_4, + .freq_tbl = ftbl_emac_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "emac_clk_src", + .parent_names = gcc_parent_names_4, + .num_parents = 3, + .ops = &clk_rcg2_ops, + .vdd_class = &vdd_cx, + .num_rate_max = VDD_NUM, + .rate_max = (unsigned long[VDD_NUM]) { + [VDD_LOW] = 125000000, + [VDD_NOMINAL] = 250000000}, + }, +}; + +static struct clk_rcg2 emac_ptp_clk_src = { + .cmd_rcgr = 0x4e014, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_4, + .freq_tbl = ftbl_emac_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "emac_ptp_clk_src", + .parent_names = gcc_parent_names_4, + .num_parents = 3, + .ops = &clk_rcg2_ops, + .vdd_class = &vdd_cx, + .num_rate_max = VDD_NUM, + .rate_max = (unsigned long[VDD_NUM]) { + [VDD_LOW] = 125000000, + [VDD_NOMINAL] = 250000000}, + }, +}; + +static const struct freq_tbl ftbl_esc0_clk_src[] = { + F(19200000, P_XO, 1, 0, 0), + { } +}; + +static struct clk_rcg2 esc0_clk_src = { + .cmd_rcgr = 0x4d05c, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_6, + .freq_tbl = ftbl_esc0_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "esc0_clk_src", + .parent_names = gcc_parent_names_6, + .num_parents = 4, + .ops = &clk_rcg2_ops, + .vdd_class = &vdd_cx, + .num_rate_max = VDD_NUM, + .rate_max = (unsigned long[VDD_NUM]) { + [VDD_LOW] = 19200000}, + }, +}; + +static const struct freq_tbl ftbl_gfx3d_clk_src[] = { + F_SLEW(19200000, P_XO, 1, 0, 0, FIXED_FREQ_SRC), + F_SLEW(50000000, P_GPLL0_OUT_MAIN, 16, 0, 0, FIXED_FREQ_SRC), + F_SLEW(80000000, P_GPLL0_OUT_MAIN, 10, 0, 0, FIXED_FREQ_SRC), + F_SLEW(100000000, P_GPLL0_OUT_MAIN, 8, 0, 0, FIXED_FREQ_SRC), + F_SLEW(160000000, P_GPLL0_OUT_MAIN, 5, 0, 0, FIXED_FREQ_SRC), + F_SLEW(200000000, P_GPLL0_OUT_MAIN, 4, 0, 0, FIXED_FREQ_SRC), + F_SLEW(228571429, P_GPLL0_OUT_MAIN, 3.5, 0, 0, FIXED_FREQ_SRC), + F_SLEW(240000000, P_GPLL6_OUT_AUX, 4.5, 0, 0, FIXED_FREQ_SRC), + F_SLEW(266666667, P_GPLL0_OUT_MAIN, 3, 0, 0, FIXED_FREQ_SRC), + F_SLEW(270000000, P_GPLL6_OUT_AUX, 4, 0, 0, FIXED_FREQ_SRC), + F_SLEW(320000000, P_GPLL0_OUT_MAIN, 2.5, 0, 0, FIXED_FREQ_SRC), + F_SLEW(400000000, P_GPLL0_OUT_MAIN, 2, 0, 0, FIXED_FREQ_SRC), + F_SLEW(484800000, P_GPLL3_OUT_MAIN, 1, 0, 0, 969600000), + F_SLEW(523200000, P_GPLL3_OUT_MAIN, 1, 0, 0, 1046400000), + F_SLEW(550000000, P_GPLL3_OUT_MAIN, 1, 0, 0, 1100000000), + F_SLEW(598000000, P_GPLL3_OUT_MAIN, 1, 0, 0, 1196000000), + { } +}; + +static struct clk_rcg2 gfx3d_clk_src = { + .cmd_rcgr = 0x59000, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_7, + .freq_tbl = ftbl_gfx3d_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gfx3d_clk_src", + .parent_names = gcc_parent_names_7, + .num_parents = 6, + .ops = &clk_rcg2_ops, + .vdd_class = &vdd_cx, + .num_rate_max = VDD_NUM, + .rate_max = (unsigned long[VDD_NUM]) { + [VDD_LOW] = 270000000, + [VDD_NOMINAL] = 484800000, + [VDD_HIGH] = 598000000}, + }, +}; + +static const struct freq_tbl ftbl_gp1_clk_src[] = { + F(19200000, P_XO, 1, 0, 0), + F(100000000, P_GPLL0_OUT_MAIN, 8, 0, 0), + F(200000000, P_GPLL0_OUT_MAIN, 4, 0, 0), + { } +}; + +static struct clk_rcg2 gp1_clk_src = { + .cmd_rcgr = 0x8004, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_parent_map_2, + .freq_tbl = ftbl_gp1_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gp1_clk_src", + .parent_names = gcc_parent_names_2, + .num_parents = 4, + .ops = &clk_rcg2_ops, + .vdd_class = &vdd_cx, + .num_rate_max = VDD_NUM, + .rate_max = (unsigned long[VDD_NUM]) { + [VDD_LOW] = 100000000, + [VDD_NOMINAL] = 200000000}, + }, +}; + +static struct clk_rcg2 gp2_clk_src = { + .cmd_rcgr = 0x9004, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_parent_map_2, + .freq_tbl = ftbl_gp1_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gp2_clk_src", + .parent_names = gcc_parent_names_2, + .num_parents = 4, + .ops = &clk_rcg2_ops, + .vdd_class = &vdd_cx, + .num_rate_max = VDD_NUM, + .rate_max = (unsigned long[VDD_NUM]) { + [VDD_LOW] = 100000000, + [VDD_NOMINAL] = 200000000}, + }, +}; + +static struct clk_rcg2 gp3_clk_src = { + .cmd_rcgr = 0xa004, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_parent_map_2, + .freq_tbl = ftbl_gp1_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gp3_clk_src", + .parent_names = gcc_parent_names_2, + .num_parents = 4, + .ops = &clk_rcg2_ops, + .vdd_class = &vdd_cx, + .num_rate_max = VDD_NUM, + .rate_max = (unsigned long[VDD_NUM]) { + [VDD_LOW] = 100000000, + [VDD_NOMINAL] = 200000000}, + }, +}; + +static struct clk_rcg2 hdmi_app_clk_src = { + .cmd_rcgr = 0x4d0e4, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_1, + .freq_tbl = ftbl_esc0_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "hdmi_app_clk_src", + .parent_names = gcc_parent_names_1, + .num_parents = 2, + .ops = &clk_rcg2_ops, + .vdd_class = &vdd_cx, + .num_rate_max = VDD_NUM, + .rate_max = (unsigned long[VDD_NUM]) { + [VDD_LOW] = 19200000}, + }, +}; + +static struct clk_rcg2 hdmi_pclk_clk_src = { + .cmd_rcgr = 0x4d0dc, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_8, + .freq_tbl = ftbl_esc0_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "hdmi_pclk_clk_src", + .parent_names = gcc_parent_names_8, + .num_parents = 3, + .ops = &clk_rcg2_ops, + .vdd_class = &vdd_cx, + .num_rate_max = VDD_NUM, + .rate_max = (unsigned long[VDD_NUM]) { + [VDD_LOW] = 75000000, + [VDD_NOMINAL] = 150000000}, + }, +}; + +static const struct freq_tbl ftbl_mdp_clk_src[] = { + F(50000000, P_GPLL0_OUT_MAIN, 16, 0, 0), + F(80000000, P_GPLL0_OUT_MAIN, 10, 0, 0), + F(100000000, P_GPLL0_OUT_MAIN, 8, 0, 0), + F(145454545, P_GPLL0_OUT_MAIN, 5.5, 0, 0), + F(160000000, P_GPLL0_OUT_MAIN, 5, 0, 0), + F(177777778, P_GPLL0_OUT_MAIN, 4.5, 0, 0), + F(200000000, P_GPLL0_OUT_MAIN, 4, 0, 0), + F(266666667, P_GPLL0_OUT_MAIN, 3, 0, 0), + F(320000000, P_GPLL0_OUT_MAIN, 2.5, 0, 0), + { } +}; + +static struct clk_rcg2 mdp_clk_src = { + .cmd_rcgr = 0x4d014, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_9, + .freq_tbl = ftbl_mdp_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "mdp_clk_src", + .parent_names = gcc_parent_names_9, + .num_parents = 5, + .ops = &clk_rcg2_ops, + .vdd_class = &vdd_cx, + .num_rate_max = VDD_NUM, + .rate_max = (unsigned long[VDD_NUM]) { + [VDD_LOW] = 160000000, + [VDD_NOMINAL] = 266666667, + [VDD_HIGH] = 320000000}, + }, +}; + +static const struct freq_tbl ftbl_pcie_0_aux_clk_src[] = { + F(1200000, P_XO, 16, 0, 0), + { } +}; + +static struct clk_rcg2 pcie_0_aux_clk_src = { + .cmd_rcgr = 0x3e024, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_10, + .freq_tbl = ftbl_pcie_0_aux_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "pcie_0_aux_clk_src", + .parent_names = gcc_parent_names_10, + .num_parents = 3, + .ops = &clk_rcg2_ops, + .vdd_class = &vdd_cx, + .num_rate_max = VDD_NUM, + .rate_max = (unsigned long[VDD_NUM]) { + [VDD_LOW] = 1200000}, + }, +}; + +static const struct freq_tbl ftbl_pcie_0_pipe_clk_src[] = { + F(19200000, P_XO, 1, 0, 0), + F(125000000, P_PCIE_0_PIPE_CLK, 2, 0, 0), + F(250000000, P_PCIE_0_PIPE_CLK, 1, 0, 0), + { } +}; + +static struct clk_rcg2 pcie_0_pipe_clk_src = { + .cmd_rcgr = 0x3e01c, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_11, + .freq_tbl = ftbl_pcie_0_pipe_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "pcie_0_pipe_clk_src", + .parent_names = gcc_parent_names_11, + .num_parents = 3, + .ops = &clk_rcg2_ops, + .vdd_class = &vdd_cx, + .num_rate_max = VDD_NUM, + .rate_max = (unsigned long[VDD_NUM]) { + [VDD_LOW] = 125000000, + [VDD_NOMINAL] = 250000000}, + }, +}; + +static struct clk_rcg2 pclk0_clk_src = { + .cmd_rcgr = 0x4d000, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_parent_map_12, + .clkr.hw.init = &(struct clk_init_data){ + .name = "pclk0_clk_src", + .parent_names = gcc_parent_names_12, + .num_parents = 4, + .flags = CLK_GET_RATE_NOCACHE, + .ops = &clk_pixel_ops, + .vdd_class = &vdd_cx, + .num_rate_max = VDD_NUM, + .rate_max = (unsigned long[VDD_NUM]) { + [VDD_LOW] = 166666667, + [VDD_NOMINAL] = 250000000}, + }, +}; + +static const struct freq_tbl ftbl_pdm2_clk_src[] = { + F(19200000, P_XO, 1, 0, 0), + F(64000000, P_GPLL0_OUT_MAIN, 12.5, 0, 0), + { } +}; + +static struct clk_rcg2 pdm2_clk_src = { + .cmd_rcgr = 0x44010, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_pdm2_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "pdm2_clk_src", + .parent_names = gcc_parent_names_0, + .num_parents = 3, + .ops = &clk_rcg2_ops, + .vdd_class = &vdd_cx, + .num_rate_max = VDD_NUM, + .rate_max = (unsigned long[VDD_NUM]) { + [VDD_LOW] = 64000000}, + }, +}; + +static const struct freq_tbl ftbl_sdcc1_apps_clk_src[] = { + F(144000, P_XO, 16, 3, 25), + F(400000, P_XO, 12, 1, 4), + F(20000000, P_GPLL0_OUT_MAIN, 10, 1, 4), + F(25000000, P_GPLL0_OUT_MAIN, 16, 1, 2), + F(50000000, P_GPLL0_OUT_MAIN, 16, 0, 0), + F(100000000, P_GPLL0_OUT_MAIN, 8, 0, 0), + F(177777778, P_GPLL0_OUT_MAIN, 4.5, 0, 0), + F(192000000, P_GPLL4_OUT_MAIN, 6, 0, 0), + F(200000000, P_GPLL0_OUT_MAIN, 4, 0, 0), + F(384000000, P_GPLL4_OUT_MAIN, 3, 0, 0), + { } +}; + +static struct clk_rcg2 sdcc1_apps_clk_src = { + .cmd_rcgr = 0x42004, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_parent_map_13, + .freq_tbl = ftbl_sdcc1_apps_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "sdcc1_apps_clk_src", + .parent_names = gcc_parent_names_13, + .num_parents = 5, + .ops = &clk_rcg2_ops, + .vdd_class = &vdd_cx, + .num_rate_max = VDD_NUM, + .rate_max = (unsigned long[VDD_NUM]) { + [VDD_LOW] = 200000000, + [VDD_NOMINAL] = 400000000}, + }, +}; + +static const struct freq_tbl ftbl_sdcc1_ice_core_clk_src[] = { + F(160000000, P_GPLL0_OUT_MAIN, 5, 0, 0), + F(266666667, P_GPLL0_OUT_MAIN, 3, 0, 0), + { } +}; + +static struct clk_rcg2 sdcc1_ice_core_clk_src = { + .cmd_rcgr = 0x5d000, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_parent_map_3, + .freq_tbl = ftbl_sdcc1_ice_core_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "sdcc1_ice_core_clk_src", + .parent_names = gcc_parent_names_3, + .num_parents = 4, + .ops = &clk_rcg2_ops, + .vdd_class = &vdd_cx, + .num_rate_max = VDD_NUM, + .rate_max = (unsigned long[VDD_NUM]) { + [VDD_LOW] = 160000000, + [VDD_NOMINAL] = 266666667}, + }, +}; + +static const struct freq_tbl ftbl_sdcc2_apps_clk_src[] = { + F(144000, P_XO, 16, 3, 25), + F(400000, P_XO, 12, 1, 4), + F(20000000, P_GPLL0_OUT_MAIN, 10, 1, 4), + F(25000000, P_GPLL0_OUT_MAIN, 16, 1, 2), + F(50000000, P_GPLL0_OUT_MAIN, 16, 0, 0), + F(100000000, P_GPLL0_OUT_MAIN, 8, 0, 0), + F(177777778, P_GPLL0_OUT_MAIN, 4.5, 0, 0), + F(200000000, P_GPLL0_OUT_MAIN, 4, 0, 0), + { } +}; + +static struct clk_rcg2 sdcc2_apps_clk_src = { + .cmd_rcgr = 0x43004, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_parent_map_14, + .freq_tbl = ftbl_sdcc2_apps_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "sdcc2_apps_clk_src", + .parent_names = gcc_parent_names_14, + .num_parents = 4, + .ops = &clk_rcg2_ops, + .vdd_class = &vdd_cx, + .num_rate_max = VDD_NUM, + .rate_max = (unsigned long[VDD_NUM]) { + [VDD_LOW] = 100000000, + [VDD_NOMINAL] = 200000000}, + }, +}; + +static struct clk_rcg2 usb20_mock_utmi_clk_src = { + .cmd_rcgr = 0x41048, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_1, + .freq_tbl = ftbl_esc0_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "usb20_mock_utmi_clk_src", + .parent_names = gcc_parent_names_1, + .num_parents = 2, + .ops = &clk_rcg2_ops, + .vdd_class = &vdd_cx, + .num_rate_max = VDD_NUM, + .rate_max = (unsigned long[VDD_NUM]) { + [VDD_LOW] = 19200000}, + }, +}; + +static const struct freq_tbl ftbl_usb30_master_clk_src[] = { + F(19200000, P_XO, 1, 0, 0), + F(100000000, P_GPLL0_OUT_MAIN, 8, 0, 0), + F(200000000, P_GPLL0_OUT_MAIN, 4, 0, 0), + F(266666667, P_GPLL0_OUT_MAIN, 3, 0, 0), + { } +}; + +static struct clk_rcg2 usb30_master_clk_src = { + .cmd_rcgr = 0x39028, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_usb30_master_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "usb30_master_clk_src", + .parent_names = gcc_parent_names_0, + .num_parents = 3, + .ops = &clk_rcg2_ops, + .vdd_class = &vdd_cx, + .num_rate_max = VDD_NUM, + .rate_max = (unsigned long[VDD_NUM]) { + [VDD_LOW] = 100000000, + [VDD_NOMINAL] = 200000000, + [VDD_HIGH] = 266666667}, + }, +}; + +static struct clk_rcg2 usb30_mock_utmi_clk_src = { + .cmd_rcgr = 0x3901c, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_1, + .freq_tbl = ftbl_esc0_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "usb30_mock_utmi_clk_src", + .parent_names = gcc_parent_names_1, + .num_parents = 2, + .ops = &clk_rcg2_ops, + .vdd_class = &vdd_cx, + .num_rate_max = VDD_NUM, + .rate_max = (unsigned long[VDD_NUM]) { + [VDD_LOW] = 19200000}, + }, +}; + +static struct clk_rcg2 usb3_phy_aux_clk_src = { + .cmd_rcgr = 0x3903c, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_1, + .freq_tbl = ftbl_pcie_0_aux_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "usb3_phy_aux_clk_src", + .parent_names = gcc_parent_names_1, + .num_parents = 2, + .ops = &clk_rcg2_ops, + .vdd_class = &vdd_cx, + .num_rate_max = VDD_NUM, + .rate_max = (unsigned long[VDD_NUM]) { + [VDD_LOW] = 1200000}, + }, +}; + +static const struct freq_tbl ftbl_usb_hs_system_clk_src[] = { + F(19200000, P_XO, 1, 0, 0), + F(80000000, P_GPLL0_OUT_MAIN, 10, 0, 0), + F(100000000, P_GPLL0_OUT_MAIN, 8, 0, 0), + F(133333333, P_GPLL0_OUT_MAIN, 6, 0, 0), + F(177777778, P_GPLL0_OUT_MAIN, 4.5, 0, 0), + { } +}; + +static struct clk_rcg2 usb_hs_system_clk_src = { + .cmd_rcgr = 0x41010, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_3, + .freq_tbl = ftbl_usb_hs_system_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "usb_hs_system_clk_src", + .parent_names = gcc_parent_names_3, + .num_parents = 4, + .ops = &clk_rcg2_ops, + .vdd_class = &vdd_cx, + .num_rate_max = VDD_NUM, + .rate_max = (unsigned long[VDD_NUM]) { + [VDD_LOW] = 80000000, + [VDD_NOMINAL] = 133333333, + [VDD_HIGH] = 177777778}, + }, +}; + +static struct clk_rcg2 vsync_clk_src = { + .cmd_rcgr = 0x4d02c, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_15, + .freq_tbl = ftbl_esc0_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "vsync_clk_src", + .parent_names = gcc_parent_names_15, + .num_parents = 3, + .ops = &clk_rcg2_ops, + .vdd_class = &vdd_cx, + .num_rate_max = VDD_NUM, + .rate_max = (unsigned long[VDD_NUM]) { + [VDD_LOW] = 19200000}, + }, +}; + +static struct clk_branch gcc_apss_ahb_clk = { + .halt_reg = 0x4601c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x45004, + .enable_mask = BIT(14), + .hw.init = &(struct clk_init_data){ + .name = "gcc_apss_ahb_clk", + .parent_names = (const char *[]){ + "apss_ahb_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_bimc_gfx_clk = { + .halt_reg = 0x59034, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x59034, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_bimc_gfx_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_bimc_mdss_clk = { + .halt_reg = 0x31038, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x31038, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_bimc_mdss_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_blsp1_ahb_clk = { + .halt_reg = 0x1008, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x45004, + .enable_mask = BIT(10), + .hw.init = &(struct clk_init_data){ + .name = "gcc_blsp1_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_blsp1_qup0_i2c_apps_clk = { + .halt_reg = 0x6028, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x6028, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_blsp1_qup0_i2c_apps_clk", + .parent_names = (const char *[]){ + "blsp1_qup0_i2c_apps_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_blsp1_qup0_spi_apps_clk = { + .halt_reg = 0x6024, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x6024, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_blsp1_qup0_spi_apps_clk", + .parent_names = (const char *[]){ + "blsp1_qup0_spi_apps_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_blsp1_qup1_i2c_apps_clk = { + .halt_reg = 0x2008, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x2008, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_blsp1_qup1_i2c_apps_clk", + .parent_names = (const char *[]){ + "blsp1_qup1_i2c_apps_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_blsp1_qup1_spi_apps_clk = { + .halt_reg = 0x2004, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x2004, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_blsp1_qup1_spi_apps_clk", + .parent_names = (const char *[]){ + "blsp1_qup1_spi_apps_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_blsp1_qup2_i2c_apps_clk = { + .halt_reg = 0x3010, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x3010, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_blsp1_qup2_i2c_apps_clk", + .parent_names = (const char *[]){ + "blsp1_qup2_i2c_apps_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_blsp1_qup2_spi_apps_clk = { + .halt_reg = 0x300c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x300c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_blsp1_qup2_spi_apps_clk", + .parent_names = (const char *[]){ + "blsp1_qup2_spi_apps_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_blsp1_qup3_i2c_apps_clk = { + .halt_reg = 0x4020, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x4020, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_blsp1_qup3_i2c_apps_clk", + .parent_names = (const char *[]){ + "blsp1_qup3_i2c_apps_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_blsp1_qup3_spi_apps_clk = { + .halt_reg = 0x401c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x401c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_blsp1_qup3_spi_apps_clk", + .parent_names = (const char *[]){ + "blsp1_qup3_spi_apps_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_blsp1_qup4_i2c_apps_clk = { + .halt_reg = 0x5020, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x5020, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_blsp1_qup4_i2c_apps_clk", + .parent_names = (const char *[]){ + "blsp1_qup4_i2c_apps_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_blsp1_qup4_spi_apps_clk = { + .halt_reg = 0x501c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x501c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_blsp1_qup4_spi_apps_clk", + .parent_names = (const char *[]){ + "blsp1_qup4_spi_apps_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_blsp1_uart0_apps_clk = { + .halt_reg = 0x6004, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x6004, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_blsp1_uart0_apps_clk", + .parent_names = (const char *[]){ + "blsp1_uart0_apps_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_blsp1_uart1_apps_clk = { + .halt_reg = 0x203c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x203c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_blsp1_uart1_apps_clk", + .parent_names = (const char *[]){ + "blsp1_uart1_apps_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_blsp1_uart2_apps_clk = { + .halt_reg = 0x302c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x302c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_blsp1_uart2_apps_clk", + .parent_names = (const char *[]){ + "blsp1_uart2_apps_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_blsp1_uart3_apps_clk = { + .halt_reg = 0x400c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x400c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_blsp1_uart3_apps_clk", + .parent_names = (const char *[]){ + "blsp1_uart3_apps_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_blsp2_ahb_clk = { + .halt_reg = 0xb008, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x45004, + .enable_mask = BIT(20), + .hw.init = &(struct clk_init_data){ + .name = "gcc_blsp2_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_blsp2_qup0_i2c_apps_clk = { + .halt_reg = 0xc008, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xc008, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_blsp2_qup0_i2c_apps_clk", + .parent_names = (const char *[]){ + "blsp2_qup0_i2c_apps_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_blsp2_qup0_spi_apps_clk = { + .halt_reg = 0xc004, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xc004, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_blsp2_qup0_spi_apps_clk", + .parent_names = (const char *[]){ + "blsp2_qup0_spi_apps_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_blsp2_uart0_apps_clk = { + .halt_reg = 0xc03c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xc03c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_blsp2_uart0_apps_clk", + .parent_names = (const char *[]){ + "blsp2_uart0_apps_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_boot_rom_ahb_clk = { + .halt_reg = 0x1300c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x45004, + .enable_mask = BIT(7), + .hw.init = &(struct clk_init_data){ + .name = "gcc_boot_rom_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_eth_axi_clk = { + .halt_reg = 0x4e010, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x4e010, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_eth_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_eth_ptp_clk = { + .halt_reg = 0x4e004, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x4e004, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_eth_ptp_clk", + .parent_names = (const char *[]){ + "emac_ptp_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_eth_rgmii_clk = { + .halt_reg = 0x4e008, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x4e008, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_eth_rgmii_clk", + .parent_names = (const char *[]){ + "emac_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_eth_slave_ahb_clk = { + .halt_reg = 0x4e00c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x4e00c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_eth_slave_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_geni_ir_s_clk = { + .halt_reg = 0xf008, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xf008, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_geni_ir_s_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_gp1_clk = { + .halt_reg = 0x8000, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x8000, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_gp1_clk", + .parent_names = (const char *[]){ + "gp1_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_gp2_clk = { + .halt_reg = 0x9000, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x9000, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_gp2_clk", + .parent_names = (const char *[]){ + "gp2_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_gp3_clk = { + .halt_reg = 0xa000, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xa000, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_gp3_clk", + .parent_names = (const char *[]){ + "gp3_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_mdss_ahb_clk = { + .halt_reg = 0x4d07c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x4d07c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_mdss_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_mdss_axi_clk = { + .halt_reg = 0x4d080, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x4d080, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_mdss_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_mdss_byte0_clk = { + .halt_reg = 0x4d094, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x4d094, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_mdss_byte0_clk", + .parent_names = (const char *[]){ + "byte0_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_mdss_esc0_clk = { + .halt_reg = 0x4d098, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x4d098, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_mdss_esc0_clk", + .parent_names = (const char *[]){ + "esc0_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_mdss_hdmi_app_clk = { + .halt_reg = 0x4d0d8, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x4d0d8, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_mdss_hdmi_app_clk", + .parent_names = (const char *[]){ + "hdmi_app_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_mdss_hdmi_pclk_clk = { + .halt_reg = 0x4d0d4, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x4d0d4, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_mdss_hdmi_pclk_clk", + .parent_names = (const char *[]){ + "hdmi_pclk_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_mdss_mdp_clk = { + .halt_reg = 0x4d088, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x4d088, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_mdss_mdp_clk", + .parent_names = (const char *[]){ + "mdp_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static DEFINE_CLK_VOTER(mdss_mdp_vote_clk, &gcc_mdss_mdp_clk.c, 0); +static DEFINE_CLK_VOTER(mdss_rotator_vote_clk, &gcc_mdss_mdp_clk.c, 0); + +static struct clk_branch gcc_mdss_pclk0_clk = { + .halt_reg = 0x4d084, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x4d084, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_mdss_pclk0_clk", + .parent_names = (const char *[]){ + "pclk0_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_mdss_vsync_clk = { + .halt_reg = 0x4d090, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x4d090, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_mdss_vsync_clk", + .parent_names = (const char *[]){ + "vsync_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_oxili_ahb_clk = { + .halt_reg = 0x59028, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x59028, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_oxili_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_oxili_gfx3d_clk = { + .halt_reg = 0x59020, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x59020, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_oxili_gfx3d_clk", + .parent_names = (const char *[]){ + "gfx3d_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_0_aux_clk = { + .halt_reg = 0x3e014, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x45004, + .enable_mask = BIT(27), + .hw.init = &(struct clk_init_data){ + .name = "gcc_pcie_0_aux_clk", + .parent_names = (const char *[]){ + "pcie_0_aux_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_0_cfg_ahb_clk = { + .halt_reg = 0x3e008, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x45004, + .enable_mask = BIT(11), + .hw.init = &(struct clk_init_data){ + .name = "gcc_pcie_0_cfg_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_0_mstr_axi_clk = { + .halt_reg = 0x3e018, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x45004, + .enable_mask = BIT(18), + .hw.init = &(struct clk_init_data){ + .name = "gcc_pcie_0_mstr_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_0_pipe_clk = { + .halt_reg = 0x3e00c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x45004, + .enable_mask = BIT(28), + .hw.init = &(struct clk_init_data){ + .name = "gcc_pcie_0_pipe_clk", + .parent_names = (const char *[]){ + "pcie_0_pipe_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_0_slv_axi_clk = { + .halt_reg = 0x3e010, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x45004, + .enable_mask = BIT(22), + .hw.init = &(struct clk_init_data){ + .name = "gcc_pcie_0_slv_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcnoc_usb2_clk = { + .halt_reg = 0x27008, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x27008, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_pcnoc_usb2_clk", + .parent_names = (const char *[]){ + "usb_hs_system_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcnoc_usb3_clk = { + .halt_reg = 0x2700c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x2700c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_pcnoc_usb3_clk", + .parent_names = (const char *[]){ + "usb30_master_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pdm2_clk = { + .halt_reg = 0x4400c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x4400c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_pdm2_clk", + .parent_names = (const char *[]){ + "pdm2_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pdm_ahb_clk = { + .halt_reg = 0x44004, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x44004, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_pdm_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_prng_ahb_clk = { + .halt_reg = 0x13004, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x45004, + .enable_mask = BIT(8), + .hw.init = &(struct clk_init_data){ + .name = "gcc_prng_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pwm0_xo512_clk = { + .halt_reg = 0x44018, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x44018, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_pwm0_xo512_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pwm1_xo512_clk = { + .halt_reg = 0x49004, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x49004, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_pwm1_xo512_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pwm2_xo512_clk = { + .halt_reg = 0x4a004, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x4a004, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_pwm2_xo512_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_sdcc1_ahb_clk = { + .halt_reg = 0x4201c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x4201c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_sdcc1_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_sdcc1_apps_clk = { + .halt_reg = 0x42018, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x42018, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_sdcc1_apps_clk", + .parent_names = (const char *[]){ + "sdcc1_apps_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_sdcc1_ice_core_clk = { + .halt_reg = 0x5d014, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x5d014, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_sdcc1_ice_core_clk", + .parent_names = (const char *[]){ + "sdcc1_ice_core_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_sdcc2_ahb_clk = { + .halt_reg = 0x4301c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x4301c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_sdcc2_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_sdcc2_apps_clk = { + .halt_reg = 0x43018, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x43018, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_sdcc2_apps_clk", + .parent_names = (const char *[]){ + "sdcc2_apps_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_sys_noc_usb3_clk = { + .halt_reg = 0x26014, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x26014, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_sys_noc_usb3_clk", + .parent_names = (const char *[]){ + "usb30_master_clk_src", + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb_hs_inactivity_timers_clk = { + .halt_reg = 0x4100C, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x4100C, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_usb_hs_inactivity_timers_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb20_mock_utmi_clk = { + .halt_reg = 0x41044, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x41044, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_usb20_mock_utmi_clk", + .parent_names = (const char *[]){ + "usb20_mock_utmi_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb2a_phy_sleep_clk = { + .halt_reg = 0x4102c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x4102c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_usb2a_phy_sleep_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb30_master_clk = { + .halt_reg = 0x3900c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x3900c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_usb30_master_clk", + .parent_names = (const char *[]){ + "usb30_master_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb30_mock_utmi_clk = { + .halt_reg = 0x39014, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x39014, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_usb30_mock_utmi_clk", + .parent_names = (const char *[]){ + "usb30_mock_utmi_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb30_sleep_clk = { + .halt_reg = 0x39010, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x39010, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_usb30_sleep_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb3_phy_aux_clk = { + .halt_reg = 0x39044, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x39044, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_usb3_phy_aux_clk", + .parent_names = (const char *[]){ + "usb3_phy_aux_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb3_phy_pipe_clk = { + .halt_reg = 0x39018, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x39018, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_usb3_phy_pipe_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb_hs_phy_cfg_ahb_clk = { + .halt_reg = 0x41030, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x41030, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_usb_hs_phy_cfg_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb_hs_system_clk = { + .halt_reg = 0x41004, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x41004, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_usb_hs_system_clk", + .parent_names = (const char *[]){ + "usb_hs_system_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_dummy wcnss_m_clk = { + .rrate = 1000, + .hw.init = &(struct clk_init_data){ + .name = "wcss_m_clk", + .ops = &clk_dummy_ops, + }, +}; + +static struct clk_regmap *gcc_qcs405_clocks[] = { + [APSS_AHB_CLK_SRC] = &apss_ahb_clk_src.clkr, + [BLSP1_QUP0_I2C_APPS_CLK_SRC] = &blsp1_qup0_i2c_apps_clk_src.clkr, + [BLSP1_QUP0_SPI_APPS_CLK_SRC] = &blsp1_qup0_spi_apps_clk_src.clkr, + [BLSP1_QUP1_I2C_APPS_CLK_SRC] = &blsp1_qup1_i2c_apps_clk_src.clkr, + [BLSP1_QUP1_SPI_APPS_CLK_SRC] = &blsp1_qup1_spi_apps_clk_src.clkr, + [BLSP1_QUP2_I2C_APPS_CLK_SRC] = &blsp1_qup2_i2c_apps_clk_src.clkr, + [BLSP1_QUP2_SPI_APPS_CLK_SRC] = &blsp1_qup2_spi_apps_clk_src.clkr, + [BLSP1_QUP3_I2C_APPS_CLK_SRC] = &blsp1_qup3_i2c_apps_clk_src.clkr, + [BLSP1_QUP3_SPI_APPS_CLK_SRC] = &blsp1_qup3_spi_apps_clk_src.clkr, + [BLSP1_QUP4_I2C_APPS_CLK_SRC] = &blsp1_qup4_i2c_apps_clk_src.clkr, + [BLSP1_QUP4_SPI_APPS_CLK_SRC] = &blsp1_qup4_spi_apps_clk_src.clkr, + [BLSP1_UART0_APPS_CLK_SRC] = &blsp1_uart0_apps_clk_src.clkr, + [BLSP1_UART1_APPS_CLK_SRC] = &blsp1_uart1_apps_clk_src.clkr, + [BLSP1_UART2_APPS_CLK_SRC] = &blsp1_uart2_apps_clk_src.clkr, + [BLSP1_UART3_APPS_CLK_SRC] = &blsp1_uart3_apps_clk_src.clkr, + [BLSP2_QUP0_I2C_APPS_CLK_SRC] = &blsp2_qup0_i2c_apps_clk_src.clkr, + [BLSP2_QUP0_SPI_APPS_CLK_SRC] = &blsp2_qup0_spi_apps_clk_src.clkr, + [BLSP2_UART0_APPS_CLK_SRC] = &blsp2_uart0_apps_clk_src.clkr, + [EMAC_CLK_SRC] = &emac_clk_src.clkr, + [EMAC_PTP_CLK_SRC] = &emac_ptp_clk_src.clkr, + [ESC0_CLK_SRC] = &esc0_clk_src.clkr, + [GCC_APSS_AHB_CLK] = &gcc_apss_ahb_clk.clkr, + [GCC_BIMC_GFX_CLK] = &gcc_bimc_gfx_clk.clkr, + [GCC_BIMC_MDSS_CLK] = &gcc_bimc_mdss_clk.clkr, + [GCC_BLSP1_AHB_CLK] = &gcc_blsp1_ahb_clk.clkr, + [GCC_BLSP1_QUP0_I2C_APPS_CLK] = &gcc_blsp1_qup0_i2c_apps_clk.clkr, + [GCC_BLSP1_QUP0_SPI_APPS_CLK] = &gcc_blsp1_qup0_spi_apps_clk.clkr, + [GCC_BLSP1_QUP1_I2C_APPS_CLK] = &gcc_blsp1_qup1_i2c_apps_clk.clkr, + [GCC_BLSP1_QUP1_SPI_APPS_CLK] = &gcc_blsp1_qup1_spi_apps_clk.clkr, + [GCC_BLSP1_QUP2_I2C_APPS_CLK] = &gcc_blsp1_qup2_i2c_apps_clk.clkr, + [GCC_BLSP1_QUP2_SPI_APPS_CLK] = &gcc_blsp1_qup2_spi_apps_clk.clkr, + [GCC_BLSP1_QUP3_I2C_APPS_CLK] = &gcc_blsp1_qup3_i2c_apps_clk.clkr, + [GCC_BLSP1_QUP3_SPI_APPS_CLK] = &gcc_blsp1_qup3_spi_apps_clk.clkr, + [GCC_BLSP1_QUP4_I2C_APPS_CLK] = &gcc_blsp1_qup4_i2c_apps_clk.clkr, + [GCC_BLSP1_QUP4_SPI_APPS_CLK] = &gcc_blsp1_qup4_spi_apps_clk.clkr, + [GCC_BLSP1_UART0_APPS_CLK] = &gcc_blsp1_uart0_apps_clk.clkr, + [GCC_BLSP1_UART1_APPS_CLK] = &gcc_blsp1_uart1_apps_clk.clkr, + [GCC_BLSP1_UART2_APPS_CLK] = &gcc_blsp1_uart2_apps_clk.clkr, + [GCC_BLSP1_UART3_APPS_CLK] = &gcc_blsp1_uart3_apps_clk.clkr, + [GCC_BLSP2_AHB_CLK] = &gcc_blsp2_ahb_clk.clkr, + [GCC_BLSP2_QUP0_I2C_APPS_CLK] = &gcc_blsp2_qup0_i2c_apps_clk.clkr, + [GCC_BLSP2_QUP0_SPI_APPS_CLK] = &gcc_blsp2_qup0_spi_apps_clk.clkr, + [GCC_BLSP2_UART0_APPS_CLK] = &gcc_blsp2_uart0_apps_clk.clkr, + [GCC_BOOT_ROM_AHB_CLK] = &gcc_boot_rom_ahb_clk.clkr, + [GCC_ETH_AXI_CLK] = &gcc_eth_axi_clk.clkr, + [GCC_ETH_PTP_CLK] = &gcc_eth_ptp_clk.clkr, + [GCC_ETH_RGMII_CLK] = &gcc_eth_rgmii_clk.clkr, + [GCC_ETH_SLAVE_AHB_CLK] = &gcc_eth_slave_ahb_clk.clkr, + [GCC_GENI_IR_S_CLK] = &gcc_geni_ir_s_clk.clkr, + [GCC_GP1_CLK] = &gcc_gp1_clk.clkr, + [GCC_GP2_CLK] = &gcc_gp2_clk.clkr, + [GCC_GP3_CLK] = &gcc_gp3_clk.clkr, + [GCC_MDSS_AHB_CLK] = &gcc_mdss_ahb_clk.clkr, + [GCC_MDSS_AXI_CLK] = &gcc_mdss_axi_clk.clkr, + [GCC_MDSS_ESC0_CLK] = &gcc_mdss_esc0_clk.clkr, + [GCC_MDSS_HDMI_APP_CLK] = &gcc_mdss_hdmi_app_clk.clkr, + [GCC_MDSS_HDMI_PCLK_CLK] = &gcc_mdss_hdmi_pclk_clk.clkr, + [GCC_MDSS_MDP_CLK] = &gcc_mdss_mdp_clk.clkr, + [GCC_MDSS_VSYNC_CLK] = &gcc_mdss_vsync_clk.clkr, + [GCC_OXILI_AHB_CLK] = &gcc_oxili_ahb_clk.clkr, + [GCC_OXILI_GFX3D_CLK] = &gcc_oxili_gfx3d_clk.clkr, + [GCC_PCIE_0_AUX_CLK] = &gcc_pcie_0_aux_clk.clkr, + [GCC_PCIE_0_CFG_AHB_CLK] = &gcc_pcie_0_cfg_ahb_clk.clkr, + [GCC_PCIE_0_MSTR_AXI_CLK] = &gcc_pcie_0_mstr_axi_clk.clkr, + [GCC_PCIE_0_PIPE_CLK] = &gcc_pcie_0_pipe_clk.clkr, + [GCC_PCIE_0_SLV_AXI_CLK] = &gcc_pcie_0_slv_axi_clk.clkr, + [GCC_PCNOC_USB2_CLK] = &gcc_pcnoc_usb2_clk.clkr, + [GCC_PCNOC_USB3_CLK] = &gcc_pcnoc_usb3_clk.clkr, + [GCC_PDM2_CLK] = &gcc_pdm2_clk.clkr, + [GCC_PDM_AHB_CLK] = &gcc_pdm_ahb_clk.clkr, + [GCC_PRNG_AHB_CLK] = &gcc_prng_ahb_clk.clkr, + [GCC_PWM0_XO512_CLK] = &gcc_pwm0_xo512_clk.clkr, + [GCC_PWM1_XO512_CLK] = &gcc_pwm1_xo512_clk.clkr, + [GCC_PWM2_XO512_CLK] = &gcc_pwm2_xo512_clk.clkr, + [GCC_SDCC1_AHB_CLK] = &gcc_sdcc1_ahb_clk.clkr, + [GCC_SDCC1_APPS_CLK] = &gcc_sdcc1_apps_clk.clkr, + [GCC_SDCC1_ICE_CORE_CLK] = &gcc_sdcc1_ice_core_clk.clkr, + [GCC_SDCC2_AHB_CLK] = &gcc_sdcc2_ahb_clk.clkr, + [GCC_SDCC2_APPS_CLK] = &gcc_sdcc2_apps_clk.clkr, + [GCC_SYS_NOC_USB3_CLK] = &gcc_sys_noc_usb3_clk.clkr, + [GCC_USB20_MOCK_UTMI_CLK] = &gcc_usb20_mock_utmi_clk.clkr, + [GCC_USB2A_PHY_SLEEP_CLK] = &gcc_usb2a_phy_sleep_clk.clkr, + [GCC_USB30_MASTER_CLK] = &gcc_usb30_master_clk.clkr, + [GCC_USB30_MOCK_UTMI_CLK] = &gcc_usb30_mock_utmi_clk.clkr, + [GCC_USB30_SLEEP_CLK] = &gcc_usb30_sleep_clk.clkr, + [GCC_USB3_PHY_AUX_CLK] = &gcc_usb3_phy_aux_clk.clkr, + [GCC_USB3_PHY_PIPE_CLK] = &gcc_usb3_phy_pipe_clk.clkr, + [GCC_USB_HS_PHY_CFG_AHB_CLK] = &gcc_usb_hs_phy_cfg_ahb_clk.clkr, + [GCC_USB_HS_SYSTEM_CLK] = &gcc_usb_hs_system_clk.clkr, + [GFX3D_CLK_SRC] = &gfx3d_clk_src.clkr, + [GP1_CLK_SRC] = &gp1_clk_src.clkr, + [GP2_CLK_SRC] = &gp2_clk_src.clkr, + [GP3_CLK_SRC] = &gp3_clk_src.clkr, + [GPLL0_OUT_MAIN] = &gpll0_out_main.clkr, + [GPLL0_AO_OUT_MAIN] = &gpll0_ao_out_main.clkr, + [GPLL0_SLEEP_CLK_SRC] = &gpll0_sleep_clk_src.clkr, + [GPLL1_OUT_MAIN] = &gpll1_out_main.clkr, + [GPLL3_OUT_MAIN] = &gpll3_out_main.clkr, + [GPLL4_OUT_MAIN] = &gpll4_out_main.clkr, + [GPLL6] = &gpll6.clkr, + [GPLL6_OUT_AUX] = &gpll6_out_aux, + [HDMI_APP_CLK_SRC] = &hdmi_app_clk_src.clkr, + [HDMI_PCLK_CLK_SRC] = &hdmi_pclk_clk_src.clkr, + [MDP_CLK_SRC] = &mdp_clk_src.clkr, + [PCIE_0_AUX_CLK_SRC] = &pcie_0_aux_clk_src.clkr, + [PCIE_0_PIPE_CLK_SRC] = &pcie_0_pipe_clk_src.clkr, + [PDM2_CLK_SRC] = &pdm2_clk_src.clkr, + [SDCC1_APPS_CLK_SRC] = &sdcc1_apps_clk_src.clkr, + [SDCC1_ICE_CORE_CLK_SRC] = &sdcc1_ice_core_clk_src.clkr, + [SDCC2_APPS_CLK_SRC] = &sdcc2_apps_clk_src.clkr, + [USB20_MOCK_UTMI_CLK_SRC] = &usb20_mock_utmi_clk_src.clkr, + [USB30_MASTER_CLK_SRC] = &usb30_master_clk_src.clkr, + [USB30_MOCK_UTMI_CLK_SRC] = &usb30_mock_utmi_clk_src.clkr, + [USB3_PHY_AUX_CLK_SRC] = &usb3_phy_aux_clk_src.clkr, + [USB_HS_SYSTEM_CLK_SRC] = &usb_hs_system_clk_src.clkr, + [VSYNC_CLK_SRC] = &vsync_clk_src.clkr, + [GCC_USB_HS_INACTIVITY_TIMERS_CLK] = + &gcc_usb_hs_inactivity_timers_clk.clkr, +}; + +static const struct qcom_reset_map gcc_qcs405_resets[] = { + [GCC_GENI_IR_BCR] = {0x0F000}, + [GCC_USB_HS_BCR] = {0x41000}, + [GCC_USB2_HS_PHY_ONLY_BCR] = {0x41034}, + [GCC_QUSB2_PHY_BCR] = {0x4103C}, + [GCC_USB_HS_PHY_CFG_AHB_BCR] = {0x41038}, + [GCC_USB2A_PHY_BCR] = {0x41028}, + [GCC_USB3_PHY_BCR] = {0x39004}, + [GCC_USB_30_BCR] = {0x39000}, + [GCC_USB3PHY_PHY_BCR] = {0x39008}, + [GCC_PCIE_0_BCR] = {0x3E000}, + [GCC_PCIE_0_PHY_BCR] = {0x3E004}, + [GCC_PCIE_0_LINK_DOWN_BCR] = {0x3E038}, + [GCC_PCIEPHY_0_PHY_BCR] = {0x3E03C}, + [GCC_EMAC_BCR] = {0x4E000}, +}; + +static const struct regmap_config gcc_qcs405_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = 0x7f000, + .fast_io = true, +}; + +static const struct qcom_cc_desc gcc_qcs405_desc = { + .config = &gcc_qcs405_regmap_config, + .clks = gcc_qcs405_clocks, + .num_clks = ARRAY_SIZE(gcc_qcs405_clocks), + .resets = gcc_qcs405_resets, + .num_resets = ARRAY_SIZE(gcc_qcs405_resets), +}; + +static const struct of_device_id gcc_qcs405_match_table[] = { + { .compatible = "qcom,gcc-qcs405" }, + { } +}; +MODULE_DEVICE_TABLE(of, gcc_qcs405_match_table); + +static int gcc_qcs405_probe(struct platform_device *pdev) +{ + struct clk *clk; + struct regmap *regmap; + int ret = 0; + + regmap = qcom_cc_map(pdev, &gcc_qcs405_desc); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + + clk = devm_clk_get(&pdev->dev, "cxo"); + if (IS_ERR(clk)) { + if (PTR_ERR(clk) != -EPROBE_DEFER) + dev_err(&pdev->dev, "Unable to get cxo clock\n"); + return PTR_ERR(clk); + } + + vdd_cx.regulator[0] = devm_regulator_get(&pdev->dev, "vdd_cx"); + if (IS_ERR(vdd_cx.regulator[0])) { + if (!(PTR_ERR(vdd_cx.regulator[0]) == -EPROBE_DEFER)) + dev_err(&pdev->dev, + "Unable to get vdd_cx regulator\n"); + return PTR_ERR(vdd_cx.regulator[0]); + } + + clk_alpha_pll_configure(&gpll3_out_main, regmap, &gpll3_config); + + clk = devm_clk_register(&pdev->dev, &wcnss_m_clk.hw); + if (IS_ERR(clk)) { + dev_err(&pdev->dev, "Unable to register wcnss_m_clk\n"); + return PTR_ERR(clk); + } + + ret = qcom_cc_really_probe(pdev, &gcc_qcs405_desc, regmap); + if (ret) { + dev_err(&pdev->dev, "Failed to register GCC clocks\n"); + return ret; + } + + clk_set_rate(apss_ahb_clk_src.clkr.hw.clk, 19200000); + clk_prepare_enable(apss_ahb_clk_src.clkr.hw.clk); + + dev_info(&pdev->dev, "Registered GCC clocks\n"); + + return ret; +} + +static struct platform_driver gcc_qcs405_driver = { + .probe = gcc_qcs405_probe, + .driver = { + .name = "gcc-qcs405", + .of_match_table = gcc_qcs405_match_table, + }, +}; + +static int __init gcc_qcs405_init(void) +{ + return platform_driver_register(&gcc_qcs405_driver); +} +subsys_initcall(gcc_qcs405_init); + +static void __exit gcc_qcs405_exit(void) +{ + platform_driver_unregister(&gcc_qcs405_driver); +} +module_exit(gcc_qcs405_exit); + +struct clk_hw *mdss_qcs405_hws[] = { + [MDSS_MDP_VOTE_CLK] = &mdss_mdp_vote_clk.hw, + [MDSS_ROTATOR_VOTE_CLK] = &mdss_rotator_vote_clk.hw, +}; + +static struct clk_regmap *mdss_qcs405_clocks[] = { + [GCC_MDSS_BYTE0_CLK] = &gcc_mdss_byte0_clk.clkr, + [GCC_MDSS_PCLK0_CLK] = &gcc_mdss_pclk0_clk.clkr, + [BYTE0_CLK_SRC] = &byte0_clk_src.clkr, + [PCLK0_CLK_SRC] = &pclk0_clk_src.clkr, +}; + +static const struct qcom_cc_desc mdss_qcs405_desc = { + .config = &gcc_qcs405_regmap_config, + .clks = mdss_qcs405_clocks, + .num_clks = ARRAY_SIZE(mdss_qcs405_clocks), +}; + +static const struct of_device_id mdss_qcs405_match_table[] = { + { .compatible = "qcom,gcc-mdss-qcs405" }, + {} +}; + +MODULE_DEVICE_TABLE(of, mdss_qcs405_match_table); + +static int mdss_qcs405_probe(struct platform_device *pdev) +{ + struct clk *clk; + int ret = 0, i; + + clk = devm_clk_get(&pdev->dev, "pclk0_src"); + if (IS_ERR(clk)) { + if (PTR_ERR(clk) != -EPROBE_DEFER) + dev_err(&pdev->dev, "Unable to get pclk0_src clock\n"); + return PTR_ERR(clk); + } + + clk = devm_clk_get(&pdev->dev, "byte0_src"); + if (IS_ERR(clk)) { + if (PTR_ERR(clk) != -EPROBE_DEFER) + dev_err(&pdev->dev, "Unable to get byte0_src clock\n"); + return PTR_ERR(clk); + } + + /* register hardware clocks */ + for (i = 0; i < ARRAY_SIZE(mdss_qcs405_hws); i++) { + clk = devm_clk_register(&pdev->dev, mdss_qcs405_hws[i]); + if (IS_ERR(clk)) { + dev_err(&pdev->dev, "Unable to register hardware clocks\n"); + return PTR_ERR(clk); + } + } + + ret = qcom_cc_probe(pdev, &mdss_qcs405_desc); + if (ret) { + dev_err(&pdev->dev, "Failed to register MDSS clocks\n"); + return ret; + } + + dev_info(&pdev->dev, "Registered MDSS clocks\n"); + + return ret; +} + +static struct platform_driver mdss_qcs405_driver = { + .probe = mdss_qcs405_probe, + .driver = { + .name = "gcc-mdss-qcs405", + .of_match_table = mdss_qcs405_match_table, + }, +}; + +static int __init mdss_qcs405_init(void) +{ + return platform_driver_register(&mdss_qcs405_driver); +} +subsys_initcall(mdss_qcs405_init); + +static void __exit mdss_qcs405_exit(void) +{ + platform_driver_unregister(&mdss_qcs405_driver); +} +module_exit(mdss_qcs405_exit); + +MODULE_DESCRIPTION("QTI GCC QCS405 Driver"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:gcc-qcs405"); diff --git a/drivers/clk/qcom/vdd-level-405.h b/drivers/clk/qcom/vdd-level-405.h new file mode 100644 index 000000000000..be0cf4eded86 --- /dev/null +++ b/drivers/clk/qcom/vdd-level-405.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __DRIVERS_CLK_QCOM_VDD_LEVEL_405_H +#define __DRIVERS_CLK_QCOM_VDD_LEVEL_405_H + +#include +#include + +enum vdd_dig_levels { + VDD_NONE, + VDD_MIN, /* MIN SVS */ + VDD_LOWER, /* SVS2 */ + VDD_LOW, /* SVS */ + VDD_LOW_L1, /* SVSL1 */ + VDD_NOMINAL, /* NOM */ + VDD_NOMINAL_L1, /* NOM */ + VDD_HIGH, /* TURBO */ + VDD_NUM, +}; + +static int vdd_corner[] = { + RPM_REGULATOR_LEVEL_NONE, /* VDD_NONE */ + RPM_REGULATOR_LEVEL_MIN_SVS, /* VDD_MIN */ + RPM_REGULATOR_LEVEL_LOW_SVS, /* VDD_LOWER */ + RPM_REGULATOR_LEVEL_SVS, /* VDD_LOW */ + RPM_REGULATOR_LEVEL_SVS_PLUS, /* VDD_LOW_L1 */ + RPM_REGULATOR_LEVEL_NOM, /* VDD_NOMINAL */ + RPM_REGULATOR_LEVEL_NOM_PLUS, /* VDD_NOMINAL */ + RPM_REGULATOR_LEVEL_TURBO, /* VDD_HIGH */ +}; + +#endif diff --git a/include/dt-bindings/clock/qcom,gcc-qcs405.h b/include/dt-bindings/clock/qcom,gcc-qcs405.h index 3b51e06d6f16..335c91724e02 100644 --- a/include/dt-bindings/clock/qcom,gcc-qcs405.h +++ b/include/dt-bindings/clock/qcom,gcc-qcs405.h @@ -137,6 +137,12 @@ #define GPLL0_AO_CLK_SRC 120 #define WCNSS_M_CLK 121 #define GCC_USB_HS_INACTIVITY_TIMERS_CLK 122 +#define GPLL0_AO_OUT_MAIN 123 +#define GPLL0_SLEEP_CLK_SRC 124 +#define GPLL6 125 +#define GPLL6_OUT_AUX 126 +#define MDSS_MDP_VOTE_CLK 127 +#define MDSS_ROTATOR_VOTE_CLK 128 #define GCC_GENI_IR_BCR 0 #define GCC_USB_HS_BCR 1 -- GitLab From 933eb9895ccde2986286c2ae57e89fed6622f5f6 Mon Sep 17 00:00:00 2001 From: Hareesh Gundu Date: Wed, 4 Apr 2018 18:20:34 +0530 Subject: [PATCH 0437/1635] msm: kgsl: Separate out A6xx GMU specific code A6xx GPU has different GMUs, which requires a different set of sequence programming. Move A6xx GMU specific code to separate file, so that it's easy and scalable to fit new kind of GMU in existing driver. Signed-off-by: Hareesh Gundu Change-Id: I7773b1626a8fa6036dda06753466d2c822960096 --- drivers/gpu/msm/Makefile | 1 + drivers/gpu/msm/adreno_a6xx.c | 1236 +---------------------------- drivers/gpu/msm/adreno_a6xx.h | 16 +- drivers/gpu/msm/adreno_a6xx_gmu.c | 1235 ++++++++++++++++++++++++++++ 4 files changed, 1264 insertions(+), 1224 deletions(-) create mode 100644 drivers/gpu/msm/adreno_a6xx_gmu.c diff --git a/drivers/gpu/msm/Makefile b/drivers/gpu/msm/Makefile index 005822672101..b7d636066354 100644 --- a/drivers/gpu/msm/Makefile +++ b/drivers/gpu/msm/Makefile @@ -39,6 +39,7 @@ msm_adreno-y += \ adreno_a4xx_preempt.o \ adreno_a5xx_preempt.o \ adreno_a6xx_preempt.o \ + adreno_a6xx_gmu.o \ adreno_sysfs.o \ adreno.o \ adreno_cp_parser.o \ diff --git a/drivers/gpu/msm/adreno_a6xx.c b/drivers/gpu/msm/adreno_a6xx.c index 78e1557ccfc4..9e56fe79cf80 100644 --- a/drivers/gpu/msm/adreno_a6xx.c +++ b/drivers/gpu/msm/adreno_a6xx.c @@ -44,9 +44,6 @@ #define A6XX_GPU_CX_REG_BASE 0x509E000 #define A6XX_GPU_CX_REG_SIZE 0x1000 -#define GPU_LIMIT_THRESHOLD_ENABLE BIT(31) - -static int _load_gmu_firmware(struct kgsl_device *device); static const struct adreno_vbif_data a630_vbif[] = { {A6XX_VBIF_GATE_OFF_WRREQ_EN, 0x00000009}, @@ -440,26 +437,6 @@ static void _update_always_on_regs(struct adreno_device *adreno_dev) A6XX_CP_ALWAYS_ON_COUNTER_HI; } -static uint64_t read_AO_counter(struct kgsl_device *device) -{ - unsigned int l, h, h1; - - kgsl_gmu_regread(device, A6XX_GMU_CX_GMU_ALWAYS_ON_COUNTER_H, &h); - kgsl_gmu_regread(device, A6XX_GMU_CX_GMU_ALWAYS_ON_COUNTER_L, &l); - kgsl_gmu_regread(device, A6XX_GMU_CX_GMU_ALWAYS_ON_COUNTER_H, &h1); - - /* - * If there's no change in COUNTER_H we have no overflow so return, - * otherwise read COUNTER_L again - */ - - if (h == h1) - return (uint64_t) l | ((uint64_t) h << 32); - - kgsl_gmu_regread(device, A6XX_GMU_CX_GMU_ALWAYS_ON_COUNTER_L, &l); - return (uint64_t) l | ((uint64_t) h1 << 32); -} - static void a6xx_pwrup_reglist_init(struct adreno_device *adreno_dev) { struct kgsl_device *device = KGSL_DEVICE(adreno_dev); @@ -657,22 +634,6 @@ static void a6xx_hwcg_set(struct adreno_device *adreno_dev, bool on) on ? __get_rbbm_clock_cntl_on(adreno_dev) : 0); } -#define LM_DEFAULT_LIMIT 6000 - -static uint32_t lm_limit(struct adreno_device *adreno_dev) -{ - struct kgsl_device *device = KGSL_DEVICE(adreno_dev); - - if (adreno_dev->lm_limit) - return adreno_dev->lm_limit; - - if (of_property_read_u32(device->pdev->dev.of_node, "qcom,lm-limit", - &adreno_dev->lm_limit)) - adreno_dev->lm_limit = LM_DEFAULT_LIMIT; - - return adreno_dev->lm_limit; -} - static void a6xx_patch_pwrup_reglist(struct adreno_device *adreno_dev) { uint32_t i; @@ -733,13 +694,6 @@ static void a6xx_patch_pwrup_reglist(struct adreno_device *adreno_dev) } } -#define LIMITS_CONFIG(t, s, c, i, a) ( \ - (t & 0xF) | \ - ((s & 0xF) << 4) | \ - ((c & 0xF) << 8) | \ - ((i & 0xF) << 12) | \ - ((a & 0xF) << 16)) - /* * a6xx_start() - Device start * @adreno_dev: Pointer to adreno device @@ -889,34 +843,8 @@ static void a6xx_start(struct adreno_device *adreno_dev) * At this point, we are guaranteed all. */ if (ADRENO_FEATURE(adreno_dev, ADRENO_LM) && - test_bit(ADRENO_LM_CTRL, &adreno_dev->pwrctrl_flag)) { - int result; - struct gmu_device *gmu = &device->gmu; - struct device *dev = &gmu->pdev->dev; - struct hfi_lmconfig_cmd cmd; - - kgsl_gmu_regwrite(device, A6XX_GPU_GMU_CX_GMU_PWR_THRESHOLD, - GPU_LIMIT_THRESHOLD_ENABLE | lm_limit(adreno_dev)); - kgsl_gmu_regwrite(device, A6XX_GMU_AO_SPARE_CNTL, 1); - kgsl_gmu_regwrite(device, A6XX_GPU_GMU_CX_GMU_ISENSE_CTRL, 0x1); - - gmu->lm_config = LIMITS_CONFIG(1, 1, 1, 0, 0); - gmu->bcl_config = 0; - gmu->lm_dcvs_level = 0; - - cmd.limit_conf = gmu->lm_config; - cmd.bcl_conf = gmu->bcl_config; - cmd.lm_enable_bitmask = 0; - - if (gmu->lm_dcvs_level <= MAX_GX_LEVELS) - cmd.lm_enable_bitmask = - (1 << (gmu->lm_dcvs_level + 1)) - 1; - - result = hfi_send_req(gmu, H2F_MSG_LM_CFG, &cmd); - if (result) - dev_err(dev, "Failure enabling limits management (%d)\n", - result); - } + test_bit(ADRENO_LM_CTRL, &adreno_dev->pwrctrl_flag)) + a6xx_gmu_enable_lm(device); } /* @@ -1253,361 +1181,6 @@ static int _load_firmware(struct kgsl_device *device, const char *fwfile, return ret; } -#define RSC_CMD_OFFSET 2 -#define PDC_CMD_OFFSET 4 - -static void _regwrite(void __iomem *regbase, - unsigned int offsetwords, unsigned int value) -{ - void __iomem *reg; - - reg = regbase + (offsetwords << 2); - __raw_writel(value, reg); -} - -/* - * _load_gmu_rpmh_ucode() - Load the ucode into the GPU PDC/RSC blocks - * PDC and RSC execute GPU power on/off RPMh sequence - * @device: Pointer to KGSL device - */ -static void _load_gmu_rpmh_ucode(struct kgsl_device *device) -{ - struct adreno_device *adreno_dev = ADRENO_DEVICE(device); - struct gmu_device *gmu = &device->gmu; - - /* Disable SDE clock gating */ - kgsl_gmu_regwrite(device, A6XX_GPU_RSCC_RSC_STATUS0_DRV0, BIT(24)); - - /* Setup RSC PDC handshake for sleep and wakeup */ - kgsl_gmu_regwrite(device, A6XX_RSCC_PDC_SLAVE_ID_DRV0, 1); - kgsl_gmu_regwrite(device, A6XX_RSCC_HIDDEN_TCS_CMD0_DATA, 0); - kgsl_gmu_regwrite(device, A6XX_RSCC_HIDDEN_TCS_CMD0_ADDR, 0); - kgsl_gmu_regwrite(device, - A6XX_RSCC_HIDDEN_TCS_CMD0_DATA + RSC_CMD_OFFSET, 0); - kgsl_gmu_regwrite(device, - A6XX_RSCC_HIDDEN_TCS_CMD0_ADDR + RSC_CMD_OFFSET, 0); - kgsl_gmu_regwrite(device, - A6XX_RSCC_HIDDEN_TCS_CMD0_DATA + RSC_CMD_OFFSET * 2, - 0x80000000); - kgsl_gmu_regwrite(device, - A6XX_RSCC_HIDDEN_TCS_CMD0_ADDR + RSC_CMD_OFFSET * 2, - 0); - kgsl_gmu_regwrite(device, A6XX_RSCC_OVERRIDE_START_ADDR, 0); - kgsl_gmu_regwrite(device, A6XX_RSCC_PDC_SEQ_START_ADDR, 0x4520); - kgsl_gmu_regwrite(device, A6XX_RSCC_PDC_MATCH_VALUE_LO, 0x4510); - kgsl_gmu_regwrite(device, A6XX_RSCC_PDC_MATCH_VALUE_HI, 0x4514); - - /* Enable timestamp event for v1 only */ - if (adreno_is_a630v1(adreno_dev)) - kgsl_gmu_regwrite(device, A6XX_RSCC_TIMESTAMP_UNIT1_EN_DRV0, 1); - - /* Load RSC sequencer uCode for sleep and wakeup */ - kgsl_gmu_regwrite(device, A6XX_RSCC_SEQ_MEM_0_DRV0, 0xA7A506A0); - kgsl_gmu_regwrite(device, A6XX_RSCC_SEQ_MEM_0_DRV0 + 1, 0xA1E6A6E7); - kgsl_gmu_regwrite(device, A6XX_RSCC_SEQ_MEM_0_DRV0 + 2, 0xA2E081E1); - kgsl_gmu_regwrite(device, A6XX_RSCC_SEQ_MEM_0_DRV0 + 3, 0xE9A982E2); - kgsl_gmu_regwrite(device, A6XX_RSCC_SEQ_MEM_0_DRV0 + 4, 0x0020E8A8); - - /* Load PDC sequencer uCode for power up and power down sequence */ - _regwrite(gmu->pdc_reg_virt, PDC_GPU_SEQ_MEM_0, 0xFEBEA1E1); - _regwrite(gmu->pdc_reg_virt, PDC_GPU_SEQ_MEM_0 + 1, 0xA5A4A3A2); - _regwrite(gmu->pdc_reg_virt, PDC_GPU_SEQ_MEM_0 + 2, 0x8382A6E0); - _regwrite(gmu->pdc_reg_virt, PDC_GPU_SEQ_MEM_0 + 3, 0xBCE3E284); - _regwrite(gmu->pdc_reg_virt, PDC_GPU_SEQ_MEM_0 + 4, 0x002081FC); - - /* Set TCS commands used by PDC sequence for low power modes */ - _regwrite(gmu->pdc_reg_virt, PDC_GPU_TCS1_CMD_ENABLE_BANK, 7); - _regwrite(gmu->pdc_reg_virt, PDC_GPU_TCS1_CMD_WAIT_FOR_CMPL_BANK, 0); - _regwrite(gmu->pdc_reg_virt, PDC_GPU_TCS1_CONTROL, 0); - _regwrite(gmu->pdc_reg_virt, PDC_GPU_TCS1_CMD0_MSGID, 0x10108); - _regwrite(gmu->pdc_reg_virt, PDC_GPU_TCS1_CMD0_ADDR, 0x30010); - _regwrite(gmu->pdc_reg_virt, PDC_GPU_TCS1_CMD0_DATA, 1); - _regwrite(gmu->pdc_reg_virt, - PDC_GPU_TCS1_CMD0_MSGID + PDC_CMD_OFFSET, 0x10108); - _regwrite(gmu->pdc_reg_virt, - PDC_GPU_TCS1_CMD0_ADDR + PDC_CMD_OFFSET, 0x30000); - _regwrite(gmu->pdc_reg_virt, - PDC_GPU_TCS1_CMD0_DATA + PDC_CMD_OFFSET, 0x0); - _regwrite(gmu->pdc_reg_virt, - PDC_GPU_TCS1_CMD0_MSGID + PDC_CMD_OFFSET * 2, 0x10108); - _regwrite(gmu->pdc_reg_virt, - PDC_GPU_TCS1_CMD0_ADDR + PDC_CMD_OFFSET * 2, 0x30080); - _regwrite(gmu->pdc_reg_virt, - PDC_GPU_TCS1_CMD0_DATA + PDC_CMD_OFFSET * 2, 0x0); - _regwrite(gmu->pdc_reg_virt, PDC_GPU_TCS3_CMD_ENABLE_BANK, 7); - _regwrite(gmu->pdc_reg_virt, PDC_GPU_TCS3_CMD_WAIT_FOR_CMPL_BANK, 0); - _regwrite(gmu->pdc_reg_virt, PDC_GPU_TCS3_CONTROL, 0); - _regwrite(gmu->pdc_reg_virt, PDC_GPU_TCS3_CMD0_MSGID, 0x10108); - _regwrite(gmu->pdc_reg_virt, PDC_GPU_TCS3_CMD0_ADDR, 0x30010); - _regwrite(gmu->pdc_reg_virt, PDC_GPU_TCS3_CMD0_DATA, 2); - _regwrite(gmu->pdc_reg_virt, - PDC_GPU_TCS3_CMD0_MSGID + PDC_CMD_OFFSET, 0x10108); - _regwrite(gmu->pdc_reg_virt, - PDC_GPU_TCS3_CMD0_ADDR + PDC_CMD_OFFSET, 0x30000); - _regwrite(gmu->pdc_reg_virt, - PDC_GPU_TCS3_CMD0_DATA + PDC_CMD_OFFSET, 0x3); - _regwrite(gmu->pdc_reg_virt, - PDC_GPU_TCS3_CMD0_MSGID + PDC_CMD_OFFSET * 2, 0x10108); - _regwrite(gmu->pdc_reg_virt, - PDC_GPU_TCS3_CMD0_ADDR + PDC_CMD_OFFSET * 2, 0x30080); - _regwrite(gmu->pdc_reg_virt, - PDC_GPU_TCS3_CMD0_DATA + PDC_CMD_OFFSET * 2, 0x3); - - /* Setup GPU PDC */ - _regwrite(gmu->pdc_reg_virt, PDC_GPU_SEQ_START_ADDR, 0); - _regwrite(gmu->pdc_reg_virt, PDC_GPU_ENABLE_PDC, 0x80000001); - - /* ensure no writes happen before the uCode is fully written */ - wmb(); -} - -#define GMU_START_TIMEOUT 100 /* ms */ -#define GPU_START_TIMEOUT 100 /* ms */ -#define GPU_RESET_TIMEOUT 1 /* ms */ -#define GPU_RESET_TIMEOUT_US 10 /* us */ - -/* - * timed_poll_check() - polling *gmu* register at given offset until - * its value changed to match expected value. The function times - * out and returns after given duration if register is not updated - * as expected. - * - * @device: Pointer to KGSL device - * @offset: Register offset - * @expected_ret: expected register value that stops polling - * @timout: number of jiffies to abort the polling - * @mask: bitmask to filter register value to match expected_ret - */ -static int timed_poll_check(struct kgsl_device *device, - unsigned int offset, unsigned int expected_ret, - unsigned int timeout, unsigned int mask) -{ - unsigned long t; - unsigned int value; - - t = jiffies + msecs_to_jiffies(timeout); - - do { - kgsl_gmu_regread(device, offset, &value); - if ((value & mask) == expected_ret) - return 0; - /* Wait 100us to reduce unnecessary AHB bus traffic */ - usleep_range(10, 100); - } while (!time_after(jiffies, t)); - - /* Double check one last time */ - kgsl_gmu_regread(device, offset, &value); - if ((value & mask) == expected_ret) - return 0; - - return -EINVAL; -} - -/* - * The lowest 16 bits of this value are the number of XO clock cycles - * for main hysteresis. This is the first hysteresis. Here we set it - * to 0x1680 cycles, or 300 us. The highest 16 bits of this value are - * the number of XO clock cycles for short hysteresis. This happens - * after main hysteresis. Here we set it to 0xA cycles, or 0.5 us. - */ -#define GMU_PWR_COL_HYST 0x000A1680 - -/* - * a6xx_gmu_power_config() - Configure and enable GMU's low power mode - * setting based on ADRENO feature flags. - * @device: Pointer to KGSL device - */ -static void a6xx_gmu_power_config(struct kgsl_device *device) -{ - struct adreno_device *adreno_dev = ADRENO_DEVICE(device); - struct gmu_device *gmu = &device->gmu; - - /* Configure registers for idle setting. The setting is cumulative */ - - /* Disable GMU WB/RB buffer and caches at boot */ - kgsl_gmu_regwrite(device, A6XX_GMU_SYS_BUS_CONFIG, 0x1); - kgsl_gmu_regwrite(device, A6XX_GMU_ICACHE_CONFIG, 0x1); - kgsl_gmu_regwrite(device, A6XX_GMU_DCACHE_CONFIG, 0x1); - - kgsl_gmu_regwrite(device, - A6XX_GMU_PWR_COL_INTER_FRAME_CTRL, 0x9C40400); - - switch (gmu->idle_level) { - case GPU_HW_MIN_VOLT: - kgsl_gmu_regrmw(device, A6XX_GMU_RPMH_CTRL, 0, - MIN_BW_ENABLE_MASK); - kgsl_gmu_regrmw(device, A6XX_GMU_RPMH_HYST_CTRL, 0, - MIN_BW_HYST); - /* fall through */ - case GPU_HW_NAP: - kgsl_gmu_regrmw(device, A6XX_GMU_GPU_NAP_CTRL, 0, - HW_NAP_ENABLE_MASK); - /* fall through */ - case GPU_HW_IFPC: - kgsl_gmu_regwrite(device, A6XX_GMU_PWR_COL_INTER_FRAME_HYST, - GMU_PWR_COL_HYST); - kgsl_gmu_regrmw(device, A6XX_GMU_PWR_COL_INTER_FRAME_CTRL, 0, - IFPC_ENABLE_MASK); - /* fall through */ - case GPU_HW_SPTP_PC: - kgsl_gmu_regwrite(device, A6XX_GMU_PWR_COL_SPTPRAC_HYST, - GMU_PWR_COL_HYST); - kgsl_gmu_regrmw(device, A6XX_GMU_PWR_COL_INTER_FRAME_CTRL, 0, - SPTP_ENABLE_MASK); - /* fall through */ - default: - break; - } - - /* ACD feature enablement */ - if (ADRENO_FEATURE(adreno_dev, ADRENO_LM) && - test_bit(ADRENO_LM_CTRL, &adreno_dev->pwrctrl_flag)) - kgsl_gmu_regrmw(device, A6XX_GMU_BOOT_KMD_LM_HANDSHAKE, 0, - BIT(10)); - - /* Enable RPMh GPU client */ - if (ADRENO_FEATURE(adreno_dev, ADRENO_RPMH)) - kgsl_gmu_regrmw(device, A6XX_GMU_RPMH_CTRL, 0, - RPMH_ENABLE_MASK); -} - -/* - * a6xx_gmu_start() - Start GMU and wait until FW boot up. - * @device: Pointer to KGSL device - */ -static int a6xx_gmu_start(struct kgsl_device *device) -{ - struct gmu_device *gmu = &device->gmu; - - kgsl_regwrite(device, A6XX_GMU_CX_GMU_WFI_CONFIG, 0x0); - /* Write 1 first to make sure the GMU is reset */ - kgsl_gmu_regwrite(device, A6XX_GMU_CM3_SYSRESET, 1); - - /* Make sure putting in reset doesn't happen after clearing */ - wmb(); - - /* Bring GMU out of reset */ - kgsl_gmu_regwrite(device, A6XX_GMU_CM3_SYSRESET, 0); - if (timed_poll_check(device, - A6XX_GMU_CM3_FW_INIT_RESULT, - 0xBABEFACE, - GMU_START_TIMEOUT, - 0xFFFFFFFF)) { - dev_err(&gmu->pdev->dev, "GMU doesn't boot\n"); - return -ETIMEDOUT; - } - - return 0; -} - -/* - * a6xx_gmu_hfi_start() - Write registers and start HFI. - * @device: Pointer to KGSL device - */ -static int a6xx_gmu_hfi_start(struct kgsl_device *device) -{ - struct gmu_device *gmu = &device->gmu; - - kgsl_gmu_regrmw(device, A6XX_GMU_GMU2HOST_INTR_MASK, - HFI_IRQ_MSGQ_MASK, 0); - kgsl_gmu_regwrite(device, A6XX_GMU_HFI_CTRL_INIT, 1); - - if (timed_poll_check(device, - A6XX_GMU_HFI_CTRL_STATUS, - BIT(0), - GMU_START_TIMEOUT, - BIT(0))) { - dev_err(&gmu->pdev->dev, "GMU HFI init failed\n"); - return -ETIMEDOUT; - } - - return 0; -} - -/* - * a6xx_oob_set() - Set OOB interrupt to GMU. - * @adreno_dev: Pointer to adreno device - * @req: Which of the OOB bits to request - */ -static int a6xx_oob_set(struct adreno_device *adreno_dev, - enum oob_request req) -{ - struct kgsl_device *device = KGSL_DEVICE(adreno_dev); - int ret = 0; - int set, check; - - if (!kgsl_gmu_isenabled(device)) - return 0; - - if (adreno_is_a640(adreno_dev)) { - set = BIT(30 - req * 2); - check = BIT(31 - req); - - if ((device->gmu.hfi.version & 0x1F) == 0) { - /* LEGACY for intermediate oobs */ - set = BIT(req + 16); - check = BIT(req + 16); - } - - if (req >= 6) { - dev_err(&device->gmu.pdev->dev, - "OOB_set(0x%x) invalid\n", set); - return -EINVAL; - } - } else { - set = BIT(req + 16); - check = BIT(req + 24); - } - - kgsl_gmu_regwrite(device, A6XX_GMU_HOST2GMU_INTR_SET, set); - - if (timed_poll_check(device, - A6XX_GMU_GMU2HOST_INTR_INFO, - check, - GPU_START_TIMEOUT, - check)) { - ret = -ETIMEDOUT; - dev_err(&device->gmu.pdev->dev, - "OOB_set(0x%x) timed out\n", set); - } - - kgsl_gmu_regwrite(device, A6XX_GMU_GMU2HOST_INTR_CLR, check); - - trace_kgsl_gmu_oob_set(set); - return ret; -} - -/* - * a6xx_oob_clear() - Clear a previously set OOB request. - * @adreno_dev: Pointer to the adreno device that has the GMU - * @req: Which of the OOB bits to clear - */ -static inline void a6xx_oob_clear(struct adreno_device *adreno_dev, - enum oob_request req) -{ - struct kgsl_device *device = KGSL_DEVICE(adreno_dev); - int clear; - - if (!kgsl_gmu_isenabled(device)) - return; - - if (adreno_is_a640(adreno_dev)) { - clear = BIT(31 - req * 2); - if (req >= 6) { - dev_err(&device->gmu.pdev->dev, - "OOB_clear(0x%x) invalid\n", clear); - return; - } - /* LEGACY for intermediate oobs */ - if ((device->gmu.hfi.version & 0x1F) == 0) - clear = BIT(req + 24); - } else - clear = BIT(req + 24); - - kgsl_gmu_regwrite(device, A6XX_GMU_HOST2GMU_INTR_SET, clear); - trace_kgsl_gmu_oob_clear(clear); -} - /* * a6xx_gpu_keepalive() - GMU reg write to request GPU stays on * @adreno_dev: Pointer to the adreno device that has the GMU @@ -1620,501 +1193,6 @@ static inline void a6xx_gpu_keepalive(struct adreno_device *adreno_dev, ADRENO_REG_GMU_PWR_COL_KEEPALIVE, state); } -#define SPTPRAC_POWERON_CTRL_MASK 0x00778000 -#define SPTPRAC_POWEROFF_CTRL_MASK 0x00778001 -#define SPTPRAC_POWEROFF_STATUS_MASK BIT(2) -#define SPTPRAC_POWERON_STATUS_MASK BIT(3) -#define SPTPRAC_CTRL_TIMEOUT 10 /* ms */ -#define A6XX_RETAIN_FF_ENABLE_ENABLE_MASK BIT(11) - -/* - * a6xx_sptprac_enable() - Power on SPTPRAC - * @adreno_dev: Pointer to Adreno device - */ -static int a6xx_sptprac_enable(struct adreno_device *adreno_dev) -{ - struct kgsl_device *device = KGSL_DEVICE(adreno_dev); - - if (!kgsl_gmu_gpmu_isenabled(device)) - return -EINVAL; - - if (!adreno_has_sptprac_gdsc(adreno_dev)) - return 0; - - kgsl_gmu_regwrite(device, A6XX_GMU_GX_SPTPRAC_POWER_CONTROL, - SPTPRAC_POWERON_CTRL_MASK); - - if (timed_poll_check(device, - A6XX_GMU_SPTPRAC_PWR_CLK_STATUS, - SPTPRAC_POWERON_STATUS_MASK, - SPTPRAC_CTRL_TIMEOUT, - SPTPRAC_POWERON_STATUS_MASK)) { - dev_err(&device->gmu.pdev->dev, "power on SPTPRAC fail\n"); - return -EINVAL; - } - - return 0; -} - -/* - * a6xx_sptprac_disable() - Power of SPTPRAC - * @adreno_dev: Pointer to Adreno device - */ -static void a6xx_sptprac_disable(struct adreno_device *adreno_dev) -{ - struct kgsl_device *device = KGSL_DEVICE(adreno_dev); - - if (!adreno_has_sptprac_gdsc(adreno_dev)) - return; - - if (!kgsl_gmu_gpmu_isenabled(device)) - return; - - /* Ensure that retention is on */ - kgsl_gmu_regrmw(device, A6XX_GPU_CC_GX_GDSCR, 0, - A6XX_RETAIN_FF_ENABLE_ENABLE_MASK); - - kgsl_gmu_regwrite(device, A6XX_GMU_GX_SPTPRAC_POWER_CONTROL, - SPTPRAC_POWEROFF_CTRL_MASK); - - if (timed_poll_check(device, - A6XX_GMU_SPTPRAC_PWR_CLK_STATUS, - SPTPRAC_POWEROFF_STATUS_MASK, - SPTPRAC_CTRL_TIMEOUT, - SPTPRAC_POWEROFF_STATUS_MASK)) - dev_err(&device->gmu.pdev->dev, "power off SPTPRAC fail\n"); -} - -#define SPTPRAC_POWER_OFF BIT(2) -#define SP_CLK_OFF BIT(4) -#define GX_GDSC_POWER_OFF BIT(6) -#define GX_CLK_OFF BIT(7) -#define is_on(val) (!(val & (GX_GDSC_POWER_OFF | GX_CLK_OFF))) -/* - * a6xx_gx_is_on() - Check if GX is on using pwr status register - * @adreno_dev - Pointer to adreno_device - * This check should only be performed if the keepalive bit is set or it - * can be guaranteed that the power state of the GPU will remain unchanged - */ -static bool a6xx_gx_is_on(struct adreno_device *adreno_dev) -{ - struct kgsl_device *device = KGSL_DEVICE(adreno_dev); - unsigned int val; - - if (!kgsl_gmu_isenabled(device)) - return true; - - kgsl_gmu_regread(device, A6XX_GMU_SPTPRAC_PWR_CLK_STATUS, &val); - return is_on(val); -} - -/* - * a6xx_sptprac_is_on() - Check if SPTP is on using pwr status register - * @adreno_dev - Pointer to adreno_device - * This check should only be performed if the keepalive bit is set or it - * can be guaranteed that the power state of the GPU will remain unchanged - */ -static bool a6xx_sptprac_is_on(struct adreno_device *adreno_dev) -{ - struct kgsl_device *device = KGSL_DEVICE(adreno_dev); - unsigned int val; - - if (!kgsl_gmu_isenabled(device) || !adreno_has_sptprac_gdsc(adreno_dev)) - return true; - - kgsl_gmu_regread(device, A6XX_GMU_SPTPRAC_PWR_CLK_STATUS, &val); - return !(val & (SPTPRAC_POWER_OFF | SP_CLK_OFF)); -} - -/* - * a6xx_gfx_rail_on() - request GMU to power GPU at given OPP. - * @device: Pointer to KGSL device - * - */ -static int a6xx_gfx_rail_on(struct kgsl_device *device) -{ - struct adreno_device *adreno_dev = ADRENO_DEVICE(device); - struct kgsl_pwrctrl *pwr = &device->pwrctrl; - struct gmu_device *gmu = &device->gmu; - unsigned int perf_idx = pwr->num_pwrlevels - pwr->default_pwrlevel - 1; - uint32_t default_opp = gmu->rpmh_votes.gx_votes[perf_idx]; - - kgsl_gmu_regwrite(device, A6XX_GMU_BOOT_SLUMBER_OPTION, - OOB_BOOT_OPTION); - kgsl_gmu_regwrite(device, A6XX_GMU_GX_VOTE_IDX, - ARC_VOTE_GET_PRI(default_opp)); - kgsl_gmu_regwrite(device, A6XX_GMU_MX_VOTE_IDX, - ARC_VOTE_GET_SEC(default_opp)); - - return a6xx_oob_set(adreno_dev, oob_boot_slumber); -} - -#define GMU_POWER_STATE_SLUMBER 15 - -/* - * a6xx_notify_slumber() - initiate request to GMU to prepare to slumber - * @device: Pointer to KGSL device - */ -static int a6xx_notify_slumber(struct kgsl_device *device) -{ - struct adreno_device *adreno_dev = ADRENO_DEVICE(device); - struct kgsl_pwrctrl *pwr = &device->pwrctrl; - struct gmu_device *gmu = &device->gmu; - int bus_level = pwr->pwrlevels[pwr->default_pwrlevel].bus_freq; - int perf_idx = gmu->num_gpupwrlevels - pwr->default_pwrlevel - 1; - int ret, state; - - /* Disable the power counter so that the GMU is not busy */ - kgsl_gmu_regwrite(device, A6XX_GMU_CX_GMU_POWER_COUNTER_ENABLE, 0); - - /* Turn off SPTPRAC if we own it */ - if (gmu->idle_level < GPU_HW_SPTP_PC) - a6xx_sptprac_disable(adreno_dev); - - if (!ADRENO_QUIRK(adreno_dev, ADRENO_QUIRK_HFI_USE_REG)) { - struct hfi_prep_slumber_cmd req = { - .freq = perf_idx, - .bw = bus_level, - }; - - ret = hfi_send_req(gmu, H2F_MSG_PREPARE_SLUMBER, &req); - goto out; - } - - kgsl_gmu_regwrite(device, A6XX_GMU_BOOT_SLUMBER_OPTION, - OOB_SLUMBER_OPTION); - kgsl_gmu_regwrite(device, A6XX_GMU_GX_VOTE_IDX, perf_idx); - kgsl_gmu_regwrite(device, A6XX_GMU_MX_VOTE_IDX, bus_level); - - ret = a6xx_oob_set(adreno_dev, oob_boot_slumber); - a6xx_oob_clear(adreno_dev, oob_boot_slumber); - - if (!ret) { - kgsl_gmu_regread(device, - A6XX_GPU_GMU_CX_GMU_RPMH_POWER_STATE, &state); - if (state != GPU_HW_SLUMBER) { - dev_err(&gmu->pdev->dev, - "Failed to prepare for slumber: 0x%x\n", - state); - ret = -EINVAL; - } - } - -out: - /* Make sure the fence is in ALLOW mode */ - kgsl_gmu_regwrite(device, A6XX_GMU_AO_AHB_FENCE_CTRL, 0); - return ret; -} - -static int a6xx_rpmh_power_on_gpu(struct kgsl_device *device) -{ - struct gmu_device *gmu = &device->gmu; - struct device *dev = &gmu->pdev->dev; - int val; - - kgsl_gmu_regread(device, A6XX_GPU_CC_GX_DOMAIN_MISC, &val); - if (!(val & 0x1)) - dev_err_ratelimited(&gmu->pdev->dev, - "GMEM CLAMP IO not set while GFX rail off\n"); - - /* RSC wake sequence */ - kgsl_gmu_regwrite(device, A6XX_GMU_RSCC_CONTROL_REQ, BIT(1)); - - /* Write request before polling */ - wmb(); - - if (timed_poll_check(device, - A6XX_GMU_RSCC_CONTROL_ACK, - BIT(1), - GPU_START_TIMEOUT, - BIT(1))) { - dev_err(dev, "Failed to do GPU RSC power on\n"); - return -EINVAL; - } - - if (timed_poll_check(device, - A6XX_RSCC_SEQ_BUSY_DRV0, - 0, - GPU_START_TIMEOUT, - 0xFFFFFFFF)) - goto error_rsc; - - kgsl_gmu_regwrite(device, A6XX_GMU_RSCC_CONTROL_REQ, 0); - - /* Enable the power counter because it was disabled before slumber */ - kgsl_gmu_regwrite(device, A6XX_GMU_CX_GMU_POWER_COUNTER_ENABLE, 1); - - return 0; -error_rsc: - dev_err(dev, "GPU RSC sequence stuck in waking up GPU\n"); - return -EINVAL; -} - -static int a6xx_rpmh_power_off_gpu(struct kgsl_device *device) -{ - struct gmu_device *gmu = &device->gmu; - struct adreno_device *adreno_dev = ADRENO_DEVICE(device); - int ret; - - /* RSC sleep sequence is different on v1 */ - if (adreno_is_a630v1(adreno_dev)) - kgsl_gmu_regwrite(device, A6XX_RSCC_TIMESTAMP_UNIT1_EN_DRV0, 1); - - kgsl_gmu_regwrite(device, A6XX_GMU_RSCC_CONTROL_REQ, 1); - /* Make sure the request completes before continuing */ - wmb(); - - if (adreno_is_a630v1(adreno_dev)) - ret = timed_poll_check(device, - A6XX_RSCC_TIMESTAMP_UNIT1_OUTPUT_DRV0, - BIT(0), - GPU_START_TIMEOUT, - BIT(0)); - else - ret = timed_poll_check(device, - A6XX_GPU_RSCC_RSC_STATUS0_DRV0, - BIT(16), - GPU_START_TIMEOUT, - BIT(16)); - - if (ret) { - dev_err(&gmu->pdev->dev, "GPU RSC power off fail\n"); - return -ETIMEDOUT; - } - - /* Read to clear the timestamp valid signal. Don't care what we read. */ - if (adreno_is_a630v1(adreno_dev)) { - kgsl_gmu_regread(device, - A6XX_RSCC_TIMESTAMP_UNIT0_TIMESTAMP_L_DRV0, - &ret); - kgsl_gmu_regread(device, - A6XX_RSCC_TIMESTAMP_UNIT0_TIMESTAMP_H_DRV0, - &ret); - } - - kgsl_gmu_regwrite(device, A6XX_GMU_RSCC_CONTROL_REQ, 0); - - if (ADRENO_FEATURE(adreno_dev, ADRENO_LM) && - test_bit(ADRENO_LM_CTRL, &adreno_dev->pwrctrl_flag)) - kgsl_gmu_regwrite(device, A6XX_GMU_AO_SPARE_CNTL, 0); - - return 0; -} - -/* - * Gmu FW header format: - * <32-bit start addr> <32-bit size> <32-bit pad0> <32-bit pad1> - */ -#define GMU_FW_HEADER_SIZE 4 - -#define GMU_ITCM_VA_START 0x0 -#define GMU_ITCM_VA_END (GMU_ITCM_VA_START + 0x4000) /* 16 KB */ - -#define GMU_DTCM_VA_START 0x40000 -#define GMU_DTCM_VA_END (GMU_DTCM_VA_START + 0x4000) /* 16 KB */ - -#define GMU_ICACHE_VA_START 0x4000 -#define GMU_ICACHE_VA_END (GMU_ICACHE_VA_START + 0x3C000) /* 240 KB */ - -static int load_gmu_fw(struct kgsl_device *device) -{ - struct gmu_device *gmu = &device->gmu; - uint32_t *fwptr = gmu->fw_image->hostptr; - int i, j, ret; - int start_addr, size_in_bytes, num_dwords, tcm_slot, num_records; - - /* Allocates & maps memory for GMU cached instructions range */ - ret = allocate_gmu_cached_fw(gmu); - if (ret) - return ret; - - /* - * Read first record. pad0 field of first record contains - * number of records in the image. - */ - num_records = fwptr[2]; - for (i = 0; i < num_records; i++) { - start_addr = fwptr[0]; - size_in_bytes = fwptr[1]; - num_dwords = size_in_bytes / sizeof(uint32_t); - fwptr += GMU_FW_HEADER_SIZE; - - if ((start_addr >= GMU_ITCM_VA_START) && - (start_addr < GMU_ITCM_VA_END)) { - tcm_slot = start_addr / sizeof(uint32_t); - - for (j = 0; j < num_dwords; j++) - kgsl_gmu_regwrite(device, - A6XX_GMU_CM3_ITCM_START + tcm_slot + j, - fwptr[j]); - } else if ((start_addr >= GMU_DTCM_VA_START) && - (start_addr < GMU_DTCM_VA_END)) { - tcm_slot = (start_addr - GMU_DTCM_VA_START) - / sizeof(uint32_t); - - for (j = 0; j < num_dwords; j++) - kgsl_gmu_regwrite(device, - A6XX_GMU_CM3_DTCM_START + tcm_slot + j, - fwptr[j]); - } else if ((start_addr >= GMU_ICACHE_VA_START) && - (start_addr < GMU_ICACHE_VA_END)) { - if (!is_cached_fw_size_valid(size_in_bytes)) { - dev_err(&gmu->pdev->dev, - "GMU firmware size too big\n"); - return -EINVAL; - - } - memcpy(gmu->cached_fw_image.hostptr, - fwptr, size_in_bytes); - } - - fwptr += num_dwords; - } - - /* Proceed only after the FW is written */ - wmb(); - return 0; -} - - -/* - * a6xx_gmu_fw_start() - set up GMU and start FW - * @device: Pointer to KGSL device - * @boot_state: State of the GMU being started - */ -static int a6xx_gmu_fw_start(struct kgsl_device *device, - unsigned int boot_state) -{ - struct adreno_device *adreno_dev = ADRENO_DEVICE(device); - struct gmu_device *gmu = &device->gmu; - struct gmu_memdesc *mem_addr = gmu->hfi_mem; - int ret; - unsigned int chipid = 0; - - switch (boot_state) { - case GMU_RESET: - /* fall through */ - case GMU_COLD_BOOT: - /* Turn on TCM retention */ - kgsl_gmu_regwrite(device, A6XX_GMU_GENERAL_7, 1); - - if (!test_and_set_bit(GMU_BOOT_INIT_DONE, &gmu->flags)) - _load_gmu_rpmh_ucode(device); - else if (boot_state != GMU_RESET) { - ret = a6xx_rpmh_power_on_gpu(device); - if (ret) - return ret; - } - - if (gmu->load_mode == TCM_BOOT) { - /* Load GMU image via AHB bus */ - ret = load_gmu_fw(device); - if (ret) - return ret; - } else { - dev_err(&gmu->pdev->dev, "Unsupported GMU load mode %d\n", - gmu->load_mode); - return -EINVAL; - } - break; - case GMU_WARM_BOOT: - ret = a6xx_rpmh_power_on_gpu(device); - if (ret) - return ret; - break; - default: - break; - } - - /* Clear init result to make sure we are getting fresh value */ - kgsl_gmu_regwrite(device, A6XX_GMU_CM3_FW_INIT_RESULT, 0); - kgsl_gmu_regwrite(device, A6XX_GMU_CM3_BOOT_CONFIG, gmu->load_mode); - - kgsl_gmu_regwrite(device, A6XX_GMU_HFI_QTBL_ADDR, - mem_addr->gmuaddr); - kgsl_gmu_regwrite(device, A6XX_GMU_HFI_QTBL_INFO, 1); - - kgsl_gmu_regwrite(device, A6XX_GMU_AHB_FENCE_RANGE_0, - FENCE_RANGE_MASK); - - /* Pass chipid to GMU FW, must happen before starting GMU */ - - /* Keep Core and Major bitfields unchanged */ - chipid = adreno_dev->chipid & 0xFFFF0000; - - /* - * Compress minor and patch version into 8 bits - * Bit 15-12: minor version - * Bit 11-8: patch version - */ - chipid = chipid | (ADRENO_CHIPID_MINOR(adreno_dev->chipid) << 12) - | (ADRENO_CHIPID_PATCH(adreno_dev->chipid) << 8); - - kgsl_gmu_regwrite(device, A6XX_GMU_HFI_SFR_ADDR, chipid); - init_gmu_log_base(device); - - /* Configure power control and bring the GMU out of reset */ - a6xx_gmu_power_config(device); - ret = a6xx_gmu_start(device); - if (ret) - return ret; - - if (ADRENO_QUIRK(adreno_dev, ADRENO_QUIRK_HFI_USE_REG)) { - ret = a6xx_gfx_rail_on(device); - if (ret) { - a6xx_oob_clear(adreno_dev, oob_boot_slumber); - return ret; - } - } - - if (gmu->idle_level < GPU_HW_SPTP_PC) { - ret = a6xx_sptprac_enable(adreno_dev); - if (ret) - return ret; - } - - ret = a6xx_gmu_hfi_start(device); - if (ret) - return ret; - - /* Make sure the write to start HFI happens before sending a message */ - wmb(); - return ret; -} - -#define FREQ_VOTE(idx, ack) (((idx) & 0xFF) | (((ack) & 0xF) << 28)) -#define BW_VOTE(idx) ((((idx) & 0xFFF) << 12) | ((idx) & 0xFFF)) - -/* - * a6xx_gmu_dcvs_nohfi() - request GMU to do DCVS without using HFI - * @device: Pointer to KGSL device - * @perf_idx: Index into GPU performance level table defined in - * HFI DCVS table message - * @bw_idx: Index into GPU b/w table defined in HFI b/w table message - * - */ -static int a6xx_gmu_dcvs_nohfi(struct kgsl_device *device, - unsigned int perf_idx, unsigned int bw_idx) -{ - struct adreno_device *adreno_dev = ADRENO_DEVICE(device); - int ret; - - kgsl_gmu_regwrite(device, A6XX_GMU_DCVS_ACK_OPTION, DCVS_ACK_NONBLOCK); - - kgsl_gmu_regwrite(device, A6XX_GMU_DCVS_PERF_SETTING, - FREQ_VOTE(perf_idx, CLKSET_OPTION_ATLEAST)); - - kgsl_gmu_regwrite(device, A6XX_GMU_DCVS_BW_SETTING, BW_VOTE(bw_idx)); - - ret = a6xx_oob_set(adreno_dev, oob_dcvs); - if (ret == 0) - kgsl_gmu_regread(device, A6XX_GMU_DCVS_RETURN, &ret); - - a6xx_oob_clear(adreno_dev, oob_dcvs); - - return ret; -} - static bool a6xx_hw_isidle(struct adreno_device *adreno_dev) { unsigned int reg; @@ -2126,132 +1204,6 @@ static bool a6xx_hw_isidle(struct adreno_device *adreno_dev) return true; } -static bool idle_trandition_complete(unsigned int idle_level, - unsigned int gmu_power_reg, - unsigned int sptprac_clk_reg) -{ - if (idle_level != gmu_power_reg) - return false; - - switch (idle_level) { - case GPU_HW_IFPC: - if (is_on(sptprac_clk_reg)) - return false; - break; - /* other GMU idle levels can be added here */ - case GPU_HW_ACTIVE: - default: - break; - } - return true; -} - -static int a6xx_wait_for_lowest_idle(struct adreno_device *adreno_dev) -{ - struct kgsl_device *device = KGSL_DEVICE(adreno_dev); - struct gmu_device *gmu = &device->gmu; - unsigned int reg, reg1; - unsigned long t; - uint64_t ts1, ts2, ts3; - - if (!kgsl_gmu_isenabled(device)) - return 0; - - ts1 = read_AO_counter(device); - - t = jiffies + msecs_to_jiffies(GMU_IDLE_TIMEOUT); - do { - kgsl_gmu_regread(device, - A6XX_GPU_GMU_CX_GMU_RPMH_POWER_STATE, ®); - kgsl_gmu_regread(device, - A6XX_GMU_SPTPRAC_PWR_CLK_STATUS, ®1); - - if (idle_trandition_complete(gmu->idle_level, reg, reg1)) - return 0; - /* Wait 100us to reduce unnecessary AHB bus traffic */ - usleep_range(10, 100); - } while (!time_after(jiffies, t)); - - ts2 = read_AO_counter(device); - /* Check one last time */ - - kgsl_gmu_regread(device, A6XX_GPU_GMU_CX_GMU_RPMH_POWER_STATE, ®); - kgsl_gmu_regread(device, A6XX_GMU_SPTPRAC_PWR_CLK_STATUS, ®1); - - if (idle_trandition_complete(gmu->idle_level, reg, reg1)) - return 0; - - ts3 = read_AO_counter(device); - WARN(1, "Timeout waiting for lowest idle: %08x %llx %llx %llx %x\n", - reg, ts1, ts2, ts3, reg1); - - return -ETIMEDOUT; -} - -static int a6xx_wait_for_gmu_idle(struct adreno_device *adreno_dev) -{ - struct kgsl_device *device = KGSL_DEVICE(adreno_dev); - struct gmu_device *gmu = &device->gmu; - unsigned int status2; - uint64_t ts1; - - ts1 = read_AO_counter(device); - if (timed_poll_check(device, A6XX_GPU_GMU_AO_GPU_CX_BUSY_STATUS, - 0, GMU_START_TIMEOUT, CXGXCPUBUSYIGNAHB)) { - kgsl_gmu_regread(device, - A6XX_GPU_GMU_AO_GPU_CX_BUSY_STATUS2, &status2); - dev_err(&gmu->pdev->dev, - "GMU not idling: status2=0x%x %llx %llx\n", - status2, ts1, read_AO_counter(device)); - return -ETIMEDOUT; - } - - return 0; -} - -/* - * _load_gmu_firmware() - Load the ucode into the GPMU RAM & PDC/RSC - * @device: Pointer to KGSL device - */ -static int _load_gmu_firmware(struct kgsl_device *device) -{ - const struct firmware *fw = NULL; - const struct adreno_device *adreno_dev = ADRENO_DEVICE(device); - struct gmu_device *gmu = &device->gmu; - const struct adreno_gpu_core *gpucore = adreno_dev->gpucore; - int image_size, ret = -EINVAL; - - /* there is no GMU */ - if (!kgsl_gmu_isenabled(device)) - return 0; - - /* GMU fw already saved and verified so do nothing new */ - if (gmu->fw_image) - return 0; - - if (gpucore->gpmufw_name == NULL) - return -EINVAL; - - ret = request_firmware(&fw, gpucore->gpmufw_name, device->dev); - if (ret || fw == NULL) { - KGSL_CORE_ERR("request_firmware (%s) failed: %d\n", - gpucore->gpmufw_name, ret); - return ret; - } - - image_size = PAGE_ALIGN(fw->size); - - ret = allocate_gmu_image(gmu, image_size); - - /* load into shared memory with GMU */ - if (!ret) - memcpy(gmu->fw_image->hostptr, fw->data, fw->size); - - release_firmware(fw); - - return ret; -} - /* * a6xx_microcode_read() - Read microcode * @adreno_dev: Pointer to adreno device @@ -2269,7 +1221,7 @@ static int a6xx_microcode_read(struct adreno_device *adreno_dev) return ret; } - return _load_gmu_firmware(device); + return a6xx_gmu_load_firmware(device); } static int a6xx_soft_reset(struct adreno_device *adreno_dev) @@ -2314,60 +1266,11 @@ static int a6xx_soft_reset(struct adreno_device *adreno_dev) /* Clear GBIF client halt and CX arbiter halt */ adreno_deassert_gbif_halt(adreno_dev); - a6xx_sptprac_enable(adreno_dev); - - return 0; -} - -#define A6XX_STATE_OF_CHILD (BIT(4) | BIT(5)) -#define A6XX_IDLE_FULL_LLM BIT(0) -#define A6XX_WAKEUP_ACK BIT(1) -#define A6XX_IDLE_FULL_ACK BIT(0) -#define A6XX_VBIF_XIN_HALT_CTRL1_ACKS (BIT(0) | BIT(1) | BIT(2) | BIT(3)) - -static void a6xx_isense_disable(struct kgsl_device *device) -{ - unsigned int val; - const struct adreno_device *adreno_dev = ADRENO_DEVICE(device); - - if (!ADRENO_FEATURE(adreno_dev, ADRENO_LM) || - !test_bit(ADRENO_LM_CTRL, &adreno_dev->pwrctrl_flag)) - return; - - kgsl_gmu_regread(device, A6XX_GPU_CS_ENABLE_REG, &val); - if (val) { - kgsl_gmu_regwrite(device, A6XX_GPU_CS_ENABLE_REG, 0); - kgsl_gmu_regwrite(device, A6XX_GMU_ISENSE_CTRL, 0); - } -} - -static int a6xx_llm_glm_handshake(struct kgsl_device *device) -{ - unsigned int val; - const struct adreno_device *adreno_dev = ADRENO_DEVICE(device); - struct gmu_device *gmu = &device->gmu; - - if (!ADRENO_FEATURE(adreno_dev, ADRENO_LM) || - !test_bit(ADRENO_LM_CTRL, &adreno_dev->pwrctrl_flag)) - return 0; - - kgsl_gmu_regread(device, A6XX_GMU_LLM_GLM_SLEEP_CTRL, &val); - if (!(val & A6XX_STATE_OF_CHILD)) { - kgsl_gmu_regrmw(device, A6XX_GMU_LLM_GLM_SLEEP_CTRL, 0, BIT(4)); - kgsl_gmu_regrmw(device, A6XX_GMU_LLM_GLM_SLEEP_CTRL, 0, - A6XX_IDLE_FULL_LLM); - if (timed_poll_check(device, A6XX_GMU_LLM_GLM_SLEEP_STATUS, - A6XX_IDLE_FULL_ACK, GPU_RESET_TIMEOUT, - A6XX_IDLE_FULL_ACK)) { - dev_err(&gmu->pdev->dev, "LLM-GLM handshake failed\n"); - return -EINVAL; - } - } + a6xx_gmu_sptprac_enable(adreno_dev); return 0; } - static void a6xx_count_throttles(struct adreno_device *adreno_dev, uint64_t adj) { @@ -2380,117 +1283,6 @@ static void a6xx_count_throttles(struct adreno_device *adreno_dev, &adreno_dev->lm_threshold_cross); } -static int a6xx_complete_rpmh_votes(struct kgsl_device *device) -{ - int ret = 0; - - if (!kgsl_gmu_isenabled(device)) - return ret; - - ret |= timed_poll_check(device, A6XX_RSCC_TCS0_DRV0_STATUS, BIT(0), - GPU_RESET_TIMEOUT, BIT(0)); - ret |= timed_poll_check(device, A6XX_RSCC_TCS1_DRV0_STATUS, BIT(0), - GPU_RESET_TIMEOUT, BIT(0)); - ret |= timed_poll_check(device, A6XX_RSCC_TCS2_DRV0_STATUS, BIT(0), - GPU_RESET_TIMEOUT, BIT(0)); - ret |= timed_poll_check(device, A6XX_RSCC_TCS3_DRV0_STATUS, BIT(0), - GPU_RESET_TIMEOUT, BIT(0)); - - return ret; -} - -static int a6xx_gmu_suspend(struct kgsl_device *device) -{ - /* Max GX clients on A6xx is 2: GMU and KMD */ - int ret = 0, max_client_num = 2; - struct gmu_device *gmu = &device->gmu; - struct adreno_device *adreno_dev = ADRENO_DEVICE(device); - - /* do it only if LM feature is enabled */ - /* Disable ISENSE if it's on */ - a6xx_isense_disable(device); - - /* LLM-GLM handshake sequence */ - a6xx_llm_glm_handshake(device); - - /* If SPTP_RAC is on, turn off SPTP_RAC HS */ - a6xx_sptprac_disable(adreno_dev); - - /* Disconnect GPU from BUS is not needed if CX GDSC goes off later */ - - /* Check no outstanding RPMh voting */ - a6xx_complete_rpmh_votes(device); - - if (gmu->gx_gdsc) { - if (regulator_is_enabled(gmu->gx_gdsc)) { - /* Switch gx gdsc control from GMU to CPU - * force non-zero reference count in clk driver - * so next disable call will turn - * off the GDSC - */ - ret = regulator_enable(gmu->gx_gdsc); - if (ret) - dev_err(&gmu->pdev->dev, - "suspend fail: gx enable\n"); - - while ((max_client_num)) { - ret = regulator_disable(gmu->gx_gdsc); - if (!regulator_is_enabled(gmu->gx_gdsc)) - break; - max_client_num -= 1; - } - - if (!max_client_num) - dev_err(&gmu->pdev->dev, - "suspend fail: cannot disable gx\n"); - } - } - - return ret; -} - -/* - * a6xx_rpmh_gpu_pwrctrl() - GPU power control via RPMh/GMU interface - * @adreno_dev: Pointer to adreno device - * @mode: requested power mode - * @arg1: first argument for mode control - * @arg2: second argument for mode control - */ -static int a6xx_rpmh_gpu_pwrctrl(struct adreno_device *adreno_dev, - unsigned int mode, unsigned int arg1, unsigned int arg2) -{ - struct kgsl_device *device = KGSL_DEVICE(adreno_dev); - struct gmu_device *gmu = &device->gmu; - int ret; - - switch (mode) { - case GMU_FW_START: - ret = a6xx_gmu_fw_start(device, arg1); - break; - case GMU_SUSPEND: - ret = a6xx_gmu_suspend(device); - break; - case GMU_FW_STOP: - if (ADRENO_QUIRK(adreno_dev, ADRENO_QUIRK_HFI_USE_REG)) - a6xx_oob_clear(adreno_dev, oob_boot_slumber); - ret = a6xx_rpmh_power_off_gpu(device); - break; - case GMU_DCVS_NOHFI: - ret = a6xx_gmu_dcvs_nohfi(device, arg1, arg2); - break; - case GMU_NOTIFY_SLUMBER: - ret = a6xx_notify_slumber(device); - break; - default: - dev_err(&gmu->pdev->dev, - "unsupported GMU power ctrl mode:%d\n", mode); - ret = -EINVAL; - break; - } - - return ret; -} - /** * a6xx_reset() - Helper function to reset the GPU * @device: Pointer to the KGSL device structure for the GPU @@ -3678,7 +2470,7 @@ static int a6xx_enable_pwr_counters(struct adreno_device *adreno_dev, if (counter == 0) return -EINVAL; - if (!device->gmu.pdev) + if (!kgsl_gmu_isenabled(device)) return -ENODEV; kgsl_regwrite(device, A6XX_GPU_GMU_AO_GPU_CX_BUSY_MASK, 0xFF000000); @@ -3987,8 +2779,8 @@ struct adreno_gpudev adreno_a6xx_gpudev = { .platform_setup = a6xx_platform_setup, .init = a6xx_init, .rb_start = a6xx_rb_start, - .regulator_enable = a6xx_sptprac_enable, - .regulator_disable = a6xx_sptprac_disable, + .regulator_enable = a6xx_gmu_sptprac_enable, + .regulator_disable = a6xx_gmu_sptprac_disable, .perfcounters = &a6xx_perfcounters, .enable_pwr_counters = a6xx_enable_pwr_counters, .count_throttles = a6xx_count_throttles, @@ -3997,13 +2789,13 @@ struct adreno_gpudev adreno_a6xx_gpudev = { .llc_configure_gpu_scid = a6xx_llc_configure_gpu_scid, .llc_configure_gpuhtw_scid = a6xx_llc_configure_gpuhtw_scid, .llc_enable_overrides = a6xx_llc_enable_overrides, - .oob_set = a6xx_oob_set, - .oob_clear = a6xx_oob_clear, + .oob_set = a6xx_gmu_oob_set, + .oob_clear = a6xx_gmu_oob_clear, .gpu_keepalive = a6xx_gpu_keepalive, - .rpmh_gpu_pwrctrl = a6xx_rpmh_gpu_pwrctrl, + .rpmh_gpu_pwrctrl = a6xx_gmu_rpmh_gpu_pwrctrl, .hw_isidle = a6xx_hw_isidle, /* Replaced by NULL if GMU is disabled */ - .wait_for_lowest_idle = a6xx_wait_for_lowest_idle, - .wait_for_gmu_idle = a6xx_wait_for_gmu_idle, + .wait_for_lowest_idle = a6xx_gmu_wait_for_lowest_idle, + .wait_for_gmu_idle = a6xx_gmu_wait_for_idle, .iommu_fault_block = a6xx_iommu_fault_block, .reset = a6xx_reset, .soft_reset = a6xx_soft_reset, @@ -4014,8 +2806,8 @@ struct adreno_gpudev adreno_a6xx_gpudev = { .set_marker = a6xx_set_marker, .preemption_context_init = a6xx_preemption_context_init, .preemption_context_destroy = a6xx_preemption_context_destroy, - .gx_is_on = a6xx_gx_is_on, - .sptprac_is_on = a6xx_sptprac_is_on, + .gx_is_on = a6xx_gmu_gx_is_on, + .sptprac_is_on = a6xx_gmu_sptprac_is_on, .ccu_invalidate = a6xx_ccu_invalidate, .perfcounter_update = a6xx_perfcounter_update, .coresight = {&a6xx_coresight, &a6xx_coresight_cx}, diff --git a/drivers/gpu/msm/adreno_a6xx.h b/drivers/gpu/msm/adreno_a6xx.h index bf1111c6204c..955de617b6ea 100644 --- a/drivers/gpu/msm/adreno_a6xx.h +++ b/drivers/gpu/msm/adreno_a6xx.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -131,6 +131,18 @@ void a6xx_snapshot(struct adreno_device *adreno_dev, struct kgsl_snapshot *snapshot); void a6xx_snapshot_gmu(struct adreno_device *adreno_dev, struct kgsl_snapshot *snapshot); - void a6xx_crashdump_init(struct adreno_device *adreno_dev); + +int a6xx_gmu_oob_set(struct adreno_device *adreno_dev, enum oob_request req); +void a6xx_gmu_oob_clear(struct adreno_device *adreno_dev, enum oob_request req); +void a6xx_gmu_enable_lm(struct kgsl_device *device); +int a6xx_gmu_load_firmware(struct kgsl_device *device); +int a6xx_gmu_rpmh_gpu_pwrctrl(struct adreno_device *adreno_dev, + unsigned int mode, unsigned int arg1, unsigned int arg2); +int a6xx_gmu_wait_for_lowest_idle(struct adreno_device *adreno_dev); +int a6xx_gmu_wait_for_idle(struct adreno_device *adreno_dev); +int a6xx_gmu_sptprac_enable(struct adreno_device *adreno_dev); +void a6xx_gmu_sptprac_disable(struct adreno_device *adreno_dev); +bool a6xx_gmu_gx_is_on(struct adreno_device *adreno_dev); +bool a6xx_gmu_sptprac_is_on(struct adreno_device *adreno_dev); #endif diff --git a/drivers/gpu/msm/adreno_a6xx_gmu.c b/drivers/gpu/msm/adreno_a6xx_gmu.c new file mode 100644 index 000000000000..e73da1e2db7d --- /dev/null +++ b/drivers/gpu/msm/adreno_a6xx_gmu.c @@ -0,0 +1,1235 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +#include +#include +#include +#include + +#include "adreno.h" +#include "a6xx_reg.h" +#include "adreno_a6xx.h" +#include "adreno_cp_parser.h" +#include "adreno_trace.h" +#include "kgsl_trace.h" + +#define RSC_CMD_OFFSET 2 +#define PDC_CMD_OFFSET 4 + +static void _regwrite(void __iomem *regbase, + unsigned int offsetwords, unsigned int value) +{ + void __iomem *reg; + + reg = regbase + (offsetwords << 2); + __raw_writel(value, reg); +} + +/* + * _load_gmu_rpmh_ucode() - Load the ucode into the GPU PDC/RSC blocks + * PDC and RSC execute GPU power on/off RPMh sequence + * @device: Pointer to KGSL device + */ +static void _load_gmu_rpmh_ucode(struct kgsl_device *device) +{ + struct adreno_device *adreno_dev = ADRENO_DEVICE(device); + struct gmu_device *gmu = &device->gmu; + + /* Disable SDE clock gating */ + kgsl_gmu_regwrite(device, A6XX_GPU_RSCC_RSC_STATUS0_DRV0, BIT(24)); + + /* Setup RSC PDC handshake for sleep and wakeup */ + kgsl_gmu_regwrite(device, A6XX_RSCC_PDC_SLAVE_ID_DRV0, 1); + kgsl_gmu_regwrite(device, A6XX_RSCC_HIDDEN_TCS_CMD0_DATA, 0); + kgsl_gmu_regwrite(device, A6XX_RSCC_HIDDEN_TCS_CMD0_ADDR, 0); + kgsl_gmu_regwrite(device, + A6XX_RSCC_HIDDEN_TCS_CMD0_DATA + RSC_CMD_OFFSET, 0); + kgsl_gmu_regwrite(device, + A6XX_RSCC_HIDDEN_TCS_CMD0_ADDR + RSC_CMD_OFFSET, 0); + kgsl_gmu_regwrite(device, + A6XX_RSCC_HIDDEN_TCS_CMD0_DATA + RSC_CMD_OFFSET * 2, + 0x80000000); + kgsl_gmu_regwrite(device, + A6XX_RSCC_HIDDEN_TCS_CMD0_ADDR + RSC_CMD_OFFSET * 2, + 0); + kgsl_gmu_regwrite(device, A6XX_RSCC_OVERRIDE_START_ADDR, 0); + kgsl_gmu_regwrite(device, A6XX_RSCC_PDC_SEQ_START_ADDR, 0x4520); + kgsl_gmu_regwrite(device, A6XX_RSCC_PDC_MATCH_VALUE_LO, 0x4510); + kgsl_gmu_regwrite(device, A6XX_RSCC_PDC_MATCH_VALUE_HI, 0x4514); + + /* Enable timestamp event for v1 only */ + if (adreno_is_a630v1(adreno_dev)) + kgsl_gmu_regwrite(device, A6XX_RSCC_TIMESTAMP_UNIT1_EN_DRV0, 1); + + /* Load RSC sequencer uCode for sleep and wakeup */ + kgsl_gmu_regwrite(device, A6XX_RSCC_SEQ_MEM_0_DRV0, 0xA7A506A0); + kgsl_gmu_regwrite(device, A6XX_RSCC_SEQ_MEM_0_DRV0 + 1, 0xA1E6A6E7); + kgsl_gmu_regwrite(device, A6XX_RSCC_SEQ_MEM_0_DRV0 + 2, 0xA2E081E1); + kgsl_gmu_regwrite(device, A6XX_RSCC_SEQ_MEM_0_DRV0 + 3, 0xE9A982E2); + kgsl_gmu_regwrite(device, A6XX_RSCC_SEQ_MEM_0_DRV0 + 4, 0x0020E8A8); + + /* Load PDC sequencer uCode for power up and power down sequence */ + _regwrite(gmu->pdc_reg_virt, PDC_GPU_SEQ_MEM_0, 0xFEBEA1E1); + _regwrite(gmu->pdc_reg_virt, PDC_GPU_SEQ_MEM_0 + 1, 0xA5A4A3A2); + _regwrite(gmu->pdc_reg_virt, PDC_GPU_SEQ_MEM_0 + 2, 0x8382A6E0); + _regwrite(gmu->pdc_reg_virt, PDC_GPU_SEQ_MEM_0 + 3, 0xBCE3E284); + _regwrite(gmu->pdc_reg_virt, PDC_GPU_SEQ_MEM_0 + 4, 0x002081FC); + + /* Set TCS commands used by PDC sequence for low power modes */ + _regwrite(gmu->pdc_reg_virt, PDC_GPU_TCS1_CMD_ENABLE_BANK, 7); + _regwrite(gmu->pdc_reg_virt, PDC_GPU_TCS1_CMD_WAIT_FOR_CMPL_BANK, 0); + _regwrite(gmu->pdc_reg_virt, PDC_GPU_TCS1_CONTROL, 0); + _regwrite(gmu->pdc_reg_virt, PDC_GPU_TCS1_CMD0_MSGID, 0x10108); + _regwrite(gmu->pdc_reg_virt, PDC_GPU_TCS1_CMD0_ADDR, 0x30010); + _regwrite(gmu->pdc_reg_virt, PDC_GPU_TCS1_CMD0_DATA, 1); + _regwrite(gmu->pdc_reg_virt, + PDC_GPU_TCS1_CMD0_MSGID + PDC_CMD_OFFSET, 0x10108); + _regwrite(gmu->pdc_reg_virt, + PDC_GPU_TCS1_CMD0_ADDR + PDC_CMD_OFFSET, 0x30000); + _regwrite(gmu->pdc_reg_virt, + PDC_GPU_TCS1_CMD0_DATA + PDC_CMD_OFFSET, 0x0); + _regwrite(gmu->pdc_reg_virt, + PDC_GPU_TCS1_CMD0_MSGID + PDC_CMD_OFFSET * 2, 0x10108); + _regwrite(gmu->pdc_reg_virt, + PDC_GPU_TCS1_CMD0_ADDR + PDC_CMD_OFFSET * 2, 0x30080); + _regwrite(gmu->pdc_reg_virt, + PDC_GPU_TCS1_CMD0_DATA + PDC_CMD_OFFSET * 2, 0x0); + _regwrite(gmu->pdc_reg_virt, PDC_GPU_TCS3_CMD_ENABLE_BANK, 7); + _regwrite(gmu->pdc_reg_virt, PDC_GPU_TCS3_CMD_WAIT_FOR_CMPL_BANK, 0); + _regwrite(gmu->pdc_reg_virt, PDC_GPU_TCS3_CONTROL, 0); + _regwrite(gmu->pdc_reg_virt, PDC_GPU_TCS3_CMD0_MSGID, 0x10108); + _regwrite(gmu->pdc_reg_virt, PDC_GPU_TCS3_CMD0_ADDR, 0x30010); + _regwrite(gmu->pdc_reg_virt, PDC_GPU_TCS3_CMD0_DATA, 2); + _regwrite(gmu->pdc_reg_virt, + PDC_GPU_TCS3_CMD0_MSGID + PDC_CMD_OFFSET, 0x10108); + _regwrite(gmu->pdc_reg_virt, + PDC_GPU_TCS3_CMD0_ADDR + PDC_CMD_OFFSET, 0x30000); + _regwrite(gmu->pdc_reg_virt, + PDC_GPU_TCS3_CMD0_DATA + PDC_CMD_OFFSET, 0x3); + _regwrite(gmu->pdc_reg_virt, + PDC_GPU_TCS3_CMD0_MSGID + PDC_CMD_OFFSET * 2, 0x10108); + _regwrite(gmu->pdc_reg_virt, + PDC_GPU_TCS3_CMD0_ADDR + PDC_CMD_OFFSET * 2, 0x30080); + _regwrite(gmu->pdc_reg_virt, + PDC_GPU_TCS3_CMD0_DATA + PDC_CMD_OFFSET * 2, 0x3); + + /* Setup GPU PDC */ + _regwrite(gmu->pdc_reg_virt, PDC_GPU_SEQ_START_ADDR, 0); + _regwrite(gmu->pdc_reg_virt, PDC_GPU_ENABLE_PDC, 0x80000001); + + /* ensure no writes happen before the uCode is fully written */ + wmb(); +} + +#define GMU_START_TIMEOUT 100 /* ms */ +#define GPU_START_TIMEOUT 100 /* ms */ +#define GPU_RESET_TIMEOUT 1 /* ms */ +#define GPU_RESET_TIMEOUT_US 10 /* us */ + +/* + * timed_poll_check() - polling *gmu* register at given offset until + * its value changed to match expected value. The function times + * out and returns after given duration if register is not updated + * as expected. + * + * @device: Pointer to KGSL device + * @offset: Register offset + * @expected_ret: expected register value that stops polling + * @timout: number of jiffies to abort the polling + * @mask: bitmask to filter register value to match expected_ret + */ +static int timed_poll_check(struct kgsl_device *device, + unsigned int offset, unsigned int expected_ret, + unsigned int timeout, unsigned int mask) +{ + unsigned long t; + unsigned int value; + + t = jiffies + msecs_to_jiffies(timeout); + + do { + kgsl_gmu_regread(device, offset, &value); + if ((value & mask) == expected_ret) + return 0; + /* Wait 100us to reduce unnecessary AHB bus traffic */ + usleep_range(10, 100); + } while (!time_after(jiffies, t)); + + /* Double check one last time */ + kgsl_gmu_regread(device, offset, &value); + if ((value & mask) == expected_ret) + return 0; + + return -EINVAL; +} + +/* + * The lowest 16 bits of this value are the number of XO clock cycles + * for main hysteresis. This is the first hysteresis. Here we set it + * to 0x1680 cycles, or 300 us. The highest 16 bits of this value are + * the number of XO clock cycles for short hysteresis. This happens + * after main hysteresis. Here we set it to 0xA cycles, or 0.5 us. + */ +#define GMU_PWR_COL_HYST 0x000A1680 + +/* + * a6xx_gmu_power_config() - Configure and enable GMU's low power mode + * setting based on ADRENO feature flags. + * @device: Pointer to KGSL device + */ +static void a6xx_gmu_power_config(struct kgsl_device *device) +{ + struct adreno_device *adreno_dev = ADRENO_DEVICE(device); + struct gmu_device *gmu = &device->gmu; + + /* Configure registers for idle setting. The setting is cumulative */ + + /* Disable GMU WB/RB buffer and caches at boot */ + kgsl_gmu_regwrite(device, A6XX_GMU_SYS_BUS_CONFIG, 0x1); + kgsl_gmu_regwrite(device, A6XX_GMU_ICACHE_CONFIG, 0x1); + kgsl_gmu_regwrite(device, A6XX_GMU_DCACHE_CONFIG, 0x1); + + kgsl_gmu_regwrite(device, + A6XX_GMU_PWR_COL_INTER_FRAME_CTRL, 0x9C40400); + + switch (gmu->idle_level) { + case GPU_HW_MIN_VOLT: + kgsl_gmu_regrmw(device, A6XX_GMU_RPMH_CTRL, 0, + MIN_BW_ENABLE_MASK); + kgsl_gmu_regrmw(device, A6XX_GMU_RPMH_HYST_CTRL, 0, + MIN_BW_HYST); + /* fall through */ + case GPU_HW_NAP: + kgsl_gmu_regrmw(device, A6XX_GMU_GPU_NAP_CTRL, 0, + HW_NAP_ENABLE_MASK); + /* fall through */ + case GPU_HW_IFPC: + kgsl_gmu_regwrite(device, A6XX_GMU_PWR_COL_INTER_FRAME_HYST, + GMU_PWR_COL_HYST); + kgsl_gmu_regrmw(device, A6XX_GMU_PWR_COL_INTER_FRAME_CTRL, 0, + IFPC_ENABLE_MASK); + /* fall through */ + case GPU_HW_SPTP_PC: + kgsl_gmu_regwrite(device, A6XX_GMU_PWR_COL_SPTPRAC_HYST, + GMU_PWR_COL_HYST); + kgsl_gmu_regrmw(device, A6XX_GMU_PWR_COL_INTER_FRAME_CTRL, 0, + SPTP_ENABLE_MASK); + /* fall through */ + default: + break; + } + + /* ACD feature enablement */ + if (ADRENO_FEATURE(adreno_dev, ADRENO_LM) && + test_bit(ADRENO_LM_CTRL, &adreno_dev->pwrctrl_flag)) + kgsl_gmu_regrmw(device, A6XX_GMU_BOOT_KMD_LM_HANDSHAKE, 0, + BIT(10)); + + /* Enable RPMh GPU client */ + if (ADRENO_FEATURE(adreno_dev, ADRENO_RPMH)) + kgsl_gmu_regrmw(device, A6XX_GMU_RPMH_CTRL, 0, + RPMH_ENABLE_MASK); +} + +/* + * a6xx_gmu_start() - Start GMU and wait until FW boot up. + * @device: Pointer to KGSL device + */ +static int a6xx_gmu_start(struct kgsl_device *device) +{ + struct gmu_device *gmu = &device->gmu; + + kgsl_regwrite(device, A6XX_GMU_CX_GMU_WFI_CONFIG, 0x0); + /* Write 1 first to make sure the GMU is reset */ + kgsl_gmu_regwrite(device, A6XX_GMU_CM3_SYSRESET, 1); + + /* Make sure putting in reset doesn't happen after clearing */ + wmb(); + + /* Bring GMU out of reset */ + kgsl_gmu_regwrite(device, A6XX_GMU_CM3_SYSRESET, 0); + if (timed_poll_check(device, + A6XX_GMU_CM3_FW_INIT_RESULT, + 0xBABEFACE, + GMU_START_TIMEOUT, + 0xFFFFFFFF)) { + dev_err(&gmu->pdev->dev, "GMU doesn't boot\n"); + return -ETIMEDOUT; + } + + return 0; +} + +/* + * a6xx_gmu_hfi_start() - Write registers and start HFI. + * @device: Pointer to KGSL device + */ +static int a6xx_gmu_hfi_start(struct kgsl_device *device) +{ + struct gmu_device *gmu = &device->gmu; + + kgsl_gmu_regrmw(device, A6XX_GMU_GMU2HOST_INTR_MASK, + HFI_IRQ_MSGQ_MASK, 0); + kgsl_gmu_regwrite(device, A6XX_GMU_HFI_CTRL_INIT, 1); + + if (timed_poll_check(device, + A6XX_GMU_HFI_CTRL_STATUS, + BIT(0), + GMU_START_TIMEOUT, + BIT(0))) { + dev_err(&gmu->pdev->dev, "GMU HFI init failed\n"); + return -ETIMEDOUT; + } + + return 0; +} + +static uint64_t read_AO_counter(struct kgsl_device *device) +{ + unsigned int l, h, h1; + + kgsl_gmu_regread(device, A6XX_GMU_CX_GMU_ALWAYS_ON_COUNTER_H, &h); + kgsl_gmu_regread(device, A6XX_GMU_CX_GMU_ALWAYS_ON_COUNTER_L, &l); + kgsl_gmu_regread(device, A6XX_GMU_CX_GMU_ALWAYS_ON_COUNTER_H, &h1); + + /* + * If there's no change in COUNTER_H we have no overflow so return, + * otherwise read COUNTER_L again + */ + + if (h == h1) + return (uint64_t) l | ((uint64_t) h << 32); + + kgsl_gmu_regread(device, A6XX_GMU_CX_GMU_ALWAYS_ON_COUNTER_L, &l); + return (uint64_t) l | ((uint64_t) h1 << 32); +} + +static int a6xx_rpmh_power_on_gpu(struct kgsl_device *device) +{ + struct gmu_device *gmu = &device->gmu; + struct device *dev = &gmu->pdev->dev; + int val; + + kgsl_gmu_regread(device, A6XX_GPU_CC_GX_DOMAIN_MISC, &val); + if (!(val & 0x1)) + dev_err_ratelimited(&gmu->pdev->dev, + "GMEM CLAMP IO not set while GFX rail off\n"); + + /* RSC wake sequence */ + kgsl_gmu_regwrite(device, A6XX_GMU_RSCC_CONTROL_REQ, BIT(1)); + + /* Write request before polling */ + wmb(); + + if (timed_poll_check(device, + A6XX_GMU_RSCC_CONTROL_ACK, + BIT(1), + GPU_START_TIMEOUT, + BIT(1))) { + dev_err(dev, "Failed to do GPU RSC power on\n"); + return -EINVAL; + } + + if (timed_poll_check(device, + A6XX_RSCC_SEQ_BUSY_DRV0, + 0, + GPU_START_TIMEOUT, + 0xFFFFFFFF)) + goto error_rsc; + + kgsl_gmu_regwrite(device, A6XX_GMU_RSCC_CONTROL_REQ, 0); + + /* Enable the power counter because it was disabled before slumber */ + kgsl_gmu_regwrite(device, A6XX_GMU_CX_GMU_POWER_COUNTER_ENABLE, 1); + + return 0; +error_rsc: + dev_err(dev, "GPU RSC sequence stuck in waking up GPU\n"); + return -EINVAL; +} + +static int a6xx_rpmh_power_off_gpu(struct kgsl_device *device) +{ + struct gmu_device *gmu = &device->gmu; + struct adreno_device *adreno_dev = ADRENO_DEVICE(device); + int ret; + + /* RSC sleep sequence is different on v1 */ + if (adreno_is_a630v1(adreno_dev)) + kgsl_gmu_regwrite(device, A6XX_RSCC_TIMESTAMP_UNIT1_EN_DRV0, 1); + + kgsl_gmu_regwrite(device, A6XX_GMU_RSCC_CONTROL_REQ, 1); + /* Make sure the request completes before continuing */ + wmb(); + + if (adreno_is_a630v1(adreno_dev)) + ret = timed_poll_check(device, + A6XX_RSCC_TIMESTAMP_UNIT1_OUTPUT_DRV0, + BIT(0), + GPU_START_TIMEOUT, + BIT(0)); + else + ret = timed_poll_check(device, + A6XX_GPU_RSCC_RSC_STATUS0_DRV0, + BIT(16), + GPU_START_TIMEOUT, + BIT(16)); + + if (ret) { + dev_err(&gmu->pdev->dev, "GPU RSC power off fail\n"); + return -ETIMEDOUT; + } + + /* Read to clear the timestamp valid signal. Don't care what we read. */ + if (adreno_is_a630v1(adreno_dev)) { + kgsl_gmu_regread(device, + A6XX_RSCC_TIMESTAMP_UNIT0_TIMESTAMP_L_DRV0, + &ret); + kgsl_gmu_regread(device, + A6XX_RSCC_TIMESTAMP_UNIT0_TIMESTAMP_H_DRV0, + &ret); + } + + kgsl_gmu_regwrite(device, A6XX_GMU_RSCC_CONTROL_REQ, 0); + + if (ADRENO_FEATURE(adreno_dev, ADRENO_LM) && + test_bit(ADRENO_LM_CTRL, &adreno_dev->pwrctrl_flag)) + kgsl_gmu_regwrite(device, A6XX_GMU_AO_SPARE_CNTL, 0); + + return 0; +} + +/* + * Gmu FW header format: + * <32-bit start addr> <32-bit size> <32-bit pad0> <32-bit pad1> + */ +#define GMU_FW_HEADER_SIZE 4 + +#define GMU_ITCM_VA_START 0x0 +#define GMU_ITCM_VA_END (GMU_ITCM_VA_START + 0x4000) /* 16 KB */ + +#define GMU_DTCM_VA_START 0x40000 +#define GMU_DTCM_VA_END (GMU_DTCM_VA_START + 0x4000) /* 16 KB */ + +#define GMU_ICACHE_VA_START 0x4000 +#define GMU_ICACHE_VA_END (GMU_ICACHE_VA_START + 0x3C000) /* 240 KB */ + +static int load_gmu_fw(struct kgsl_device *device) +{ + struct gmu_device *gmu = &device->gmu; + uint32_t *fwptr = gmu->fw_image->hostptr; + int i, j, ret; + int start_addr, size_in_bytes, num_dwords, tcm_slot, num_records; + + /* Allocates & maps memory for GMU cached instructions range */ + ret = allocate_gmu_cached_fw(gmu); + if (ret) + return ret; + + /* + * Read first record. pad0 field of first record contains + * number of records in the image. + */ + num_records = fwptr[2]; + for (i = 0; i < num_records; i++) { + start_addr = fwptr[0]; + size_in_bytes = fwptr[1]; + num_dwords = size_in_bytes / sizeof(uint32_t); + fwptr += GMU_FW_HEADER_SIZE; + + if ((start_addr >= GMU_ITCM_VA_START) && + (start_addr < GMU_ITCM_VA_END)) { + tcm_slot = start_addr / sizeof(uint32_t); + + for (j = 0; j < num_dwords; j++) + kgsl_gmu_regwrite(device, + A6XX_GMU_CM3_ITCM_START + tcm_slot + j, + fwptr[j]); + } else if ((start_addr >= GMU_DTCM_VA_START) && + (start_addr < GMU_DTCM_VA_END)) { + tcm_slot = (start_addr - GMU_DTCM_VA_START) + / sizeof(uint32_t); + + for (j = 0; j < num_dwords; j++) + kgsl_gmu_regwrite(device, + A6XX_GMU_CM3_DTCM_START + tcm_slot + j, + fwptr[j]); + } else if ((start_addr >= GMU_ICACHE_VA_START) && + (start_addr < GMU_ICACHE_VA_END)) { + if (!is_cached_fw_size_valid(size_in_bytes)) { + dev_err(&gmu->pdev->dev, + "GMU firmware size too big\n"); + return -EINVAL; + + } + memcpy(gmu->cached_fw_image.hostptr, + fwptr, size_in_bytes); + } + + fwptr += num_dwords; + } + + /* Proceed only after the FW is written */ + wmb(); + return 0; +} + +/* + * a6xx_gmu_oob_set() - Set OOB interrupt to GMU. + * @adreno_dev: Pointer to adreno device + * @req: Which of the OOB bits to request + */ +int a6xx_gmu_oob_set(struct adreno_device *adreno_dev, + enum oob_request req) +{ + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); + struct gmu_device *gmu = &device->gmu; + int ret = 0; + int set, check; + + if (!kgsl_gmu_isenabled(device)) + return 0; + + if (adreno_is_a640(adreno_dev)) { + set = BIT(30 - req * 2); + check = BIT(31 - req); + + if ((device->gmu.hfi.version & 0x1F) == 0) { + /* LEGACY for intermediate oobs */ + set = BIT(req + 16); + check = BIT(req + 16); + } + + if (req >= 6) { + dev_err(&gmu->pdev->dev, + "OOB_set(0x%x) invalid\n", set); + return -EINVAL; + } + } else { + set = BIT(req + 16); + check = BIT(req + 24); + } + + kgsl_gmu_regwrite(device, A6XX_GMU_HOST2GMU_INTR_SET, set); + + if (timed_poll_check(device, + A6XX_GMU_GMU2HOST_INTR_INFO, + check, + GPU_START_TIMEOUT, + check)) { + ret = -ETIMEDOUT; + dev_err(&gmu->pdev->dev, + "OOB_set(0x%x) timed out\n", set); + } + + kgsl_gmu_regwrite(device, A6XX_GMU_GMU2HOST_INTR_CLR, check); + + trace_kgsl_gmu_oob_set(set); + return ret; +} + +/* + * a6xx_gmu_oob_clear() - Clear a previously set OOB request. + * @adreno_dev: Pointer to the adreno device that has the GMU + * @req: Which of the OOB bits to clear + */ +void a6xx_gmu_oob_clear(struct adreno_device *adreno_dev, + enum oob_request req) +{ + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); + struct gmu_device *gmu = &device->gmu; + int clear; + + if (!kgsl_gmu_isenabled(device)) + return; + + if (adreno_is_a640(adreno_dev)) { + clear = BIT(31 - req * 2); + if (req >= 6) { + dev_err(&gmu->pdev->dev, + "OOB_clear(0x%x) invalid\n", clear); + return; + } + /* LEGACY for intermediate oobs */ + if ((device->gmu.hfi.version & 0x1F) == 0) + clear = BIT(req + 24); + } else + clear = BIT(req + 24); + + kgsl_gmu_regwrite(device, A6XX_GMU_HOST2GMU_INTR_SET, clear); + trace_kgsl_gmu_oob_clear(clear); +} + + + +#define FREQ_VOTE(idx, ack) (((idx) & 0xFF) | (((ack) & 0xF) << 28)) +#define BW_VOTE(idx) ((((idx) & 0xFFF) << 12) | ((idx) & 0xFFF)) + +/* + * a6xx_gmu_dcvs_nohfi() - request GMU to do DCVS without using HFI + * @device: Pointer to KGSL device + * @perf_idx: Index into GPU performance level table defined in + * HFI DCVS table message + * @bw_idx: Index into GPU b/w table defined in HFI b/w table message + * + */ +static int a6xx_gmu_dcvs_nohfi(struct kgsl_device *device, + unsigned int perf_idx, unsigned int bw_idx) +{ + struct adreno_device *adreno_dev = ADRENO_DEVICE(device); + int ret; + + kgsl_gmu_regwrite(device, A6XX_GMU_DCVS_ACK_OPTION, DCVS_ACK_NONBLOCK); + + kgsl_gmu_regwrite(device, A6XX_GMU_DCVS_PERF_SETTING, + FREQ_VOTE(perf_idx, CLKSET_OPTION_ATLEAST)); + + kgsl_gmu_regwrite(device, A6XX_GMU_DCVS_BW_SETTING, BW_VOTE(bw_idx)); + + ret = a6xx_gmu_oob_set(adreno_dev, oob_dcvs); + if (ret == 0) + kgsl_gmu_regread(device, A6XX_GMU_DCVS_RETURN, &ret); + + a6xx_gmu_oob_clear(adreno_dev, oob_dcvs); + + return ret; +} +static int a6xx_complete_rpmh_votes(struct kgsl_device *device) +{ + int ret = 0; + + if (!kgsl_gmu_isenabled(device)) + return ret; + + ret |= timed_poll_check(device, A6XX_RSCC_TCS0_DRV0_STATUS, BIT(0), + GPU_RESET_TIMEOUT, BIT(0)); + ret |= timed_poll_check(device, A6XX_RSCC_TCS1_DRV0_STATUS, BIT(0), + GPU_RESET_TIMEOUT, BIT(0)); + ret |= timed_poll_check(device, A6XX_RSCC_TCS2_DRV0_STATUS, BIT(0), + GPU_RESET_TIMEOUT, BIT(0)); + ret |= timed_poll_check(device, A6XX_RSCC_TCS3_DRV0_STATUS, BIT(0), + GPU_RESET_TIMEOUT, BIT(0)); + + return ret; +} + +#define SPTPRAC_POWERON_CTRL_MASK 0x00778000 +#define SPTPRAC_POWEROFF_CTRL_MASK 0x00778001 +#define SPTPRAC_POWEROFF_STATUS_MASK BIT(2) +#define SPTPRAC_POWERON_STATUS_MASK BIT(3) +#define SPTPRAC_CTRL_TIMEOUT 10 /* ms */ +#define A6XX_RETAIN_FF_ENABLE_ENABLE_MASK BIT(11) + +/* + * a6xx_gmu_sptprac_enable() - Power on SPTPRAC + * @adreno_dev: Pointer to Adreno device + */ +int a6xx_gmu_sptprac_enable(struct adreno_device *adreno_dev) +{ + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); + struct gmu_device *gmu = &device->gmu; + + if (!kgsl_gmu_gpmu_isenabled(device)) + return -EINVAL; + + if (!adreno_has_sptprac_gdsc(adreno_dev)) + return 0; + + kgsl_gmu_regwrite(device, A6XX_GMU_GX_SPTPRAC_POWER_CONTROL, + SPTPRAC_POWERON_CTRL_MASK); + + if (timed_poll_check(device, + A6XX_GMU_SPTPRAC_PWR_CLK_STATUS, + SPTPRAC_POWERON_STATUS_MASK, + SPTPRAC_CTRL_TIMEOUT, + SPTPRAC_POWERON_STATUS_MASK)) { + dev_err(&gmu->pdev->dev, "power on SPTPRAC fail\n"); + return -EINVAL; + } + + return 0; +} + +/* + * a6xx_gmu_sptprac_disable() - Power of SPTPRAC + * @adreno_dev: Pointer to Adreno device + */ +void a6xx_gmu_sptprac_disable(struct adreno_device *adreno_dev) +{ + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); + struct gmu_device *gmu = &device->gmu; + + if (!adreno_has_sptprac_gdsc(adreno_dev)) + return; + + if (!kgsl_gmu_gpmu_isenabled(device)) + return; + + /* Ensure that retention is on */ + kgsl_gmu_regrmw(device, A6XX_GPU_CC_GX_GDSCR, 0, + A6XX_RETAIN_FF_ENABLE_ENABLE_MASK); + + kgsl_gmu_regwrite(device, A6XX_GMU_GX_SPTPRAC_POWER_CONTROL, + SPTPRAC_POWEROFF_CTRL_MASK); + + if (timed_poll_check(device, + A6XX_GMU_SPTPRAC_PWR_CLK_STATUS, + SPTPRAC_POWEROFF_STATUS_MASK, + SPTPRAC_CTRL_TIMEOUT, + SPTPRAC_POWEROFF_STATUS_MASK)) + dev_err(&gmu->pdev->dev, "power off SPTPRAC fail\n"); +} + +#define SPTPRAC_POWER_OFF BIT(2) +#define SP_CLK_OFF BIT(4) +#define GX_GDSC_POWER_OFF BIT(6) +#define GX_CLK_OFF BIT(7) +#define is_on(val) (!(val & (GX_GDSC_POWER_OFF | GX_CLK_OFF))) +/* + * a6xx_gx_is_on() - Check if GX is on using pwr status register + * @adreno_dev - Pointer to adreno_device + * This check should only be performed if the keepalive bit is set or it + * can be guaranteed that the power state of the GPU will remain unchanged + */ +bool a6xx_gmu_gx_is_on(struct adreno_device *adreno_dev) +{ + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); + unsigned int val; + + if (!kgsl_gmu_isenabled(device)) + return true; + + kgsl_gmu_regread(device, A6XX_GMU_SPTPRAC_PWR_CLK_STATUS, &val); + return is_on(val); +} + +/* + * a6xx_gmu_sptprac_is_on() - Check if SPTP is on using pwr status register + * @adreno_dev - Pointer to adreno_device + * This check should only be performed if the keepalive bit is set or it + * can be guaranteed that the power state of the GPU will remain unchanged + */ +bool a6xx_gmu_sptprac_is_on(struct adreno_device *adreno_dev) +{ + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); + unsigned int val; + + if (!kgsl_gmu_isenabled(device) || !adreno_has_sptprac_gdsc(adreno_dev)) + return true; + + kgsl_gmu_regread(device, A6XX_GMU_SPTPRAC_PWR_CLK_STATUS, &val); + return !(val & (SPTPRAC_POWER_OFF | SP_CLK_OFF)); +} + +/* + * a6xx_gmu_gfx_rail_on() - request GMU to power GPU at given OPP. + * @device: Pointer to KGSL device + * + */ +static int a6xx_gmu_gfx_rail_on(struct kgsl_device *device) +{ + struct adreno_device *adreno_dev = ADRENO_DEVICE(device); + struct kgsl_pwrctrl *pwr = &device->pwrctrl; + struct gmu_device *gmu = &device->gmu; + unsigned int perf_idx = pwr->num_pwrlevels - pwr->default_pwrlevel - 1; + uint32_t default_opp = gmu->rpmh_votes.gx_votes[perf_idx]; + + kgsl_gmu_regwrite(device, A6XX_GMU_BOOT_SLUMBER_OPTION, + OOB_BOOT_OPTION); + kgsl_gmu_regwrite(device, A6XX_GMU_GX_VOTE_IDX, + ARC_VOTE_GET_PRI(default_opp)); + kgsl_gmu_regwrite(device, A6XX_GMU_MX_VOTE_IDX, + ARC_VOTE_GET_SEC(default_opp)); + + return a6xx_gmu_oob_set(adreno_dev, oob_boot_slumber); +} + +static bool idle_trandition_complete(unsigned int idle_level, + unsigned int gmu_power_reg, + unsigned int sptprac_clk_reg) +{ + if (idle_level != gmu_power_reg) + return false; + + switch (idle_level) { + case GPU_HW_IFPC: + if (is_on(sptprac_clk_reg)) + return false; + break; + /* other GMU idle levels can be added here */ + case GPU_HW_ACTIVE: + default: + break; + } + return true; +} + +int a6xx_gmu_wait_for_lowest_idle(struct adreno_device *adreno_dev) +{ + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); + struct gmu_device *gmu = &device->gmu; + unsigned int reg, reg1; + unsigned long t; + uint64_t ts1, ts2, ts3; + + if (!kgsl_gmu_isenabled(device)) + return 0; + + ts1 = read_AO_counter(device); + + t = jiffies + msecs_to_jiffies(GMU_IDLE_TIMEOUT); + do { + kgsl_gmu_regread(device, + A6XX_GPU_GMU_CX_GMU_RPMH_POWER_STATE, ®); + kgsl_gmu_regread(device, + A6XX_GMU_SPTPRAC_PWR_CLK_STATUS, ®1); + + if (idle_trandition_complete(gmu->idle_level, reg, reg1)) + return 0; + /* Wait 100us to reduce unnecessary AHB bus traffic */ + usleep_range(10, 100); + } while (!time_after(jiffies, t)); + + ts2 = read_AO_counter(device); + /* Check one last time */ + + kgsl_gmu_regread(device, A6XX_GPU_GMU_CX_GMU_RPMH_POWER_STATE, ®); + kgsl_gmu_regread(device, A6XX_GMU_SPTPRAC_PWR_CLK_STATUS, ®1); + + if (idle_trandition_complete(gmu->idle_level, reg, reg1)) + return 0; + + ts3 = read_AO_counter(device); + WARN(1, "Timeout waiting for lowest idle: %08x %llx %llx %llx %x\n", + reg, ts1, ts2, ts3, reg1); + + return -ETIMEDOUT; +} + +int a6xx_gmu_wait_for_idle(struct adreno_device *adreno_dev) +{ + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); + struct gmu_device *gmu = &device->gmu; + unsigned int status2; + uint64_t ts1; + + ts1 = read_AO_counter(device); + if (timed_poll_check(device, A6XX_GPU_GMU_AO_GPU_CX_BUSY_STATUS, + 0, GMU_START_TIMEOUT, CXGXCPUBUSYIGNAHB)) { + kgsl_gmu_regread(device, + A6XX_GPU_GMU_AO_GPU_CX_BUSY_STATUS2, &status2); + dev_err(&gmu->pdev->dev, + "GMU not idling: status2=0x%x %llx %llx\n", + status2, ts1, read_AO_counter(device)); + return -ETIMEDOUT; + } + + return 0; +} + +/* + * a6xx_gmu_fw_start() - set up GMU and start FW + * @device: Pointer to KGSL device + * @boot_state: State of the GMU being started + */ +static int a6xx_gmu_fw_start(struct kgsl_device *device, + unsigned int boot_state) +{ + struct adreno_device *adreno_dev = ADRENO_DEVICE(device); + struct gmu_device *gmu = &device->gmu; + struct gmu_memdesc *mem_addr = gmu->hfi_mem; + int ret; + unsigned int chipid = 0; + + switch (boot_state) { + case GMU_RESET: + /* fall through */ + case GMU_COLD_BOOT: + /* Turn on TCM retention */ + kgsl_gmu_regwrite(device, A6XX_GMU_GENERAL_7, 1); + + if (!test_and_set_bit(GMU_BOOT_INIT_DONE, &gmu->flags)) + _load_gmu_rpmh_ucode(device); + else if (boot_state != GMU_RESET) { + ret = a6xx_rpmh_power_on_gpu(device); + if (ret) + return ret; + } + + if (gmu->load_mode == TCM_BOOT) { + /* Load GMU image via AHB bus */ + ret = load_gmu_fw(device); + if (ret) + return ret; + } else { + dev_err(&gmu->pdev->dev, "Unsupported GMU load mode %d\n", + gmu->load_mode); + return -EINVAL; + } + break; + case GMU_WARM_BOOT: + ret = a6xx_rpmh_power_on_gpu(device); + if (ret) + return ret; + break; + default: + break; + } + + /* Clear init result to make sure we are getting fresh value */ + kgsl_gmu_regwrite(device, A6XX_GMU_CM3_FW_INIT_RESULT, 0); + kgsl_gmu_regwrite(device, A6XX_GMU_CM3_BOOT_CONFIG, gmu->load_mode); + + kgsl_gmu_regwrite(device, A6XX_GMU_HFI_QTBL_ADDR, + mem_addr->gmuaddr); + kgsl_gmu_regwrite(device, A6XX_GMU_HFI_QTBL_INFO, 1); + + kgsl_gmu_regwrite(device, A6XX_GMU_AHB_FENCE_RANGE_0, + FENCE_RANGE_MASK); + + /* Pass chipid to GMU FW, must happen before starting GMU */ + + /* Keep Core and Major bitfields unchanged */ + chipid = adreno_dev->chipid & 0xFFFF0000; + + /* + * Compress minor and patch version into 8 bits + * Bit 15-12: minor version + * Bit 11-8: patch version + */ + chipid = chipid | (ADRENO_CHIPID_MINOR(adreno_dev->chipid) << 12) + | (ADRENO_CHIPID_PATCH(adreno_dev->chipid) << 8); + + kgsl_gmu_regwrite(device, A6XX_GMU_HFI_SFR_ADDR, chipid); + init_gmu_log_base(device); + + /* Configure power control and bring the GMU out of reset */ + a6xx_gmu_power_config(device); + ret = a6xx_gmu_start(device); + if (ret) + return ret; + + if (ADRENO_QUIRK(adreno_dev, ADRENO_QUIRK_HFI_USE_REG)) { + ret = a6xx_gmu_gfx_rail_on(device); + if (ret) { + a6xx_gmu_oob_clear(adreno_dev, oob_boot_slumber); + return ret; + } + } + + if (gmu->idle_level < GPU_HW_SPTP_PC) { + ret = a6xx_gmu_sptprac_enable(adreno_dev); + if (ret) + return ret; + } + + ret = a6xx_gmu_hfi_start(device); + if (ret) + return ret; + + /* Make sure the write to start HFI happens before sending a message */ + wmb(); + return ret; +} + +/* + * a6xx_gmu_load_firmware() - Load the ucode into the GPMU RAM & PDC/RSC + * @device: Pointer to KGSL device + */ +int a6xx_gmu_load_firmware(struct kgsl_device *device) +{ + const struct firmware *fw = NULL; + const struct adreno_device *adreno_dev = ADRENO_DEVICE(device); + struct gmu_device *gmu = &device->gmu; + const struct adreno_gpu_core *gpucore = adreno_dev->gpucore; + int image_size, ret = -EINVAL; + + /* there is no GMU */ + if (!kgsl_gmu_isenabled(device)) + return 0; + + /* GMU fw already saved and verified so do nothing new */ + if (gmu->fw_image) + return 0; + + if (gpucore->gpmufw_name == NULL) + return -EINVAL; + + ret = request_firmware(&fw, gpucore->gpmufw_name, device->dev); + if (ret || fw == NULL) { + KGSL_CORE_ERR("request_firmware (%s) failed: %d\n", + gpucore->gpmufw_name, ret); + return ret; + } + + image_size = PAGE_ALIGN(fw->size); + + ret = allocate_gmu_image(gmu, image_size); + + /* load into shared memory with GMU */ + if (!ret) + memcpy(gmu->fw_image->hostptr, fw->data, fw->size); + + release_firmware(fw); + + return ret; +} + +#define A6XX_STATE_OF_CHILD (BIT(4) | BIT(5)) +#define A6XX_IDLE_FULL_LLM BIT(0) +#define A6XX_WAKEUP_ACK BIT(1) +#define A6XX_IDLE_FULL_ACK BIT(0) +#define A6XX_VBIF_XIN_HALT_CTRL1_ACKS (BIT(0) | BIT(1) | BIT(2) | BIT(3)) + +static int a6xx_llm_glm_handshake(struct kgsl_device *device) +{ + unsigned int val; + const struct adreno_device *adreno_dev = ADRENO_DEVICE(device); + struct gmu_device *gmu = &device->gmu; + + if (!ADRENO_FEATURE(adreno_dev, ADRENO_LM) || + !test_bit(ADRENO_LM_CTRL, &adreno_dev->pwrctrl_flag)) + return 0; + + kgsl_gmu_regread(device, A6XX_GMU_LLM_GLM_SLEEP_CTRL, &val); + if (!(val & A6XX_STATE_OF_CHILD)) { + kgsl_gmu_regrmw(device, A6XX_GMU_LLM_GLM_SLEEP_CTRL, 0, BIT(4)); + kgsl_gmu_regrmw(device, A6XX_GMU_LLM_GLM_SLEEP_CTRL, 0, + A6XX_IDLE_FULL_LLM); + if (timed_poll_check(device, A6XX_GMU_LLM_GLM_SLEEP_STATUS, + A6XX_IDLE_FULL_ACK, GPU_RESET_TIMEOUT, + A6XX_IDLE_FULL_ACK)) { + dev_err(&gmu->pdev->dev, "LLM-GLM handshake failed\n"); + return -EINVAL; + } + } + + return 0; +} + +static void a6xx_isense_disable(struct kgsl_device *device) +{ + unsigned int val; + const struct adreno_device *adreno_dev = ADRENO_DEVICE(device); + + if (!ADRENO_FEATURE(adreno_dev, ADRENO_LM) || + !test_bit(ADRENO_LM_CTRL, &adreno_dev->pwrctrl_flag)) + return; + + kgsl_gmu_regread(device, A6XX_GPU_CS_ENABLE_REG, &val); + if (val) { + kgsl_gmu_regwrite(device, A6XX_GPU_CS_ENABLE_REG, 0); + kgsl_gmu_regwrite(device, A6XX_GMU_ISENSE_CTRL, 0); + } +} + +static int a6xx_gmu_suspend(struct kgsl_device *device) +{ + /* Max GX clients on A6xx is 2: GMU and KMD */ + int ret = 0, max_client_num = 2; + struct gmu_device *gmu = &device->gmu; + struct adreno_device *adreno_dev = ADRENO_DEVICE(device); + + /* do it only if LM feature is enabled */ + /* Disable ISENSE if it's on */ + a6xx_isense_disable(device); + + /* LLM-GLM handshake sequence */ + a6xx_llm_glm_handshake(device); + + /* If SPTP_RAC is on, turn off SPTP_RAC HS */ + a6xx_gmu_sptprac_disable(adreno_dev); + + /* Disconnect GPU from BUS is not needed if CX GDSC goes off later */ + + /* Check no outstanding RPMh voting */ + a6xx_complete_rpmh_votes(device); + + if (gmu->gx_gdsc) { + if (regulator_is_enabled(gmu->gx_gdsc)) { + /* Switch gx gdsc control from GMU to CPU + * force non-zero reference count in clk driver + * so next disable call will turn + * off the GDSC + */ + ret = regulator_enable(gmu->gx_gdsc); + if (ret) + dev_err(&gmu->pdev->dev, + "suspend fail: gx enable\n"); + + while ((max_client_num)) { + ret = regulator_disable(gmu->gx_gdsc); + if (!regulator_is_enabled(gmu->gx_gdsc)) + break; + max_client_num -= 1; + } + + if (!max_client_num) + dev_err(&gmu->pdev->dev, + "suspend fail: cannot disable gx\n"); + } + } + + return ret; +} + +/* + * a6xx_gmu_notify_slumber() - initiate request to GMU to prepare to slumber + * @device: Pointer to KGSL device + */ +static int a6xx_gmu_notify_slumber(struct kgsl_device *device) +{ + struct adreno_device *adreno_dev = ADRENO_DEVICE(device); + struct kgsl_pwrctrl *pwr = &device->pwrctrl; + struct gmu_device *gmu = &device->gmu; + int bus_level = pwr->pwrlevels[pwr->default_pwrlevel].bus_freq; + int perf_idx = gmu->num_gpupwrlevels - pwr->default_pwrlevel - 1; + int ret, state; + + /* Disable the power counter so that the GMU is not busy */ + kgsl_gmu_regwrite(device, A6XX_GMU_CX_GMU_POWER_COUNTER_ENABLE, 0); + + /* Turn off SPTPRAC if we own it */ + if (gmu->idle_level < GPU_HW_SPTP_PC) + a6xx_gmu_sptprac_disable(adreno_dev); + + if (!ADRENO_QUIRK(adreno_dev, ADRENO_QUIRK_HFI_USE_REG)) { + struct hfi_prep_slumber_cmd req = { + .freq = perf_idx, + .bw = bus_level, + }; + + ret = hfi_send_req(gmu, H2F_MSG_PREPARE_SLUMBER, &req); + goto out; + } + + kgsl_gmu_regwrite(device, A6XX_GMU_BOOT_SLUMBER_OPTION, + OOB_SLUMBER_OPTION); + kgsl_gmu_regwrite(device, A6XX_GMU_GX_VOTE_IDX, perf_idx); + kgsl_gmu_regwrite(device, A6XX_GMU_MX_VOTE_IDX, bus_level); + + ret = a6xx_gmu_oob_set(adreno_dev, oob_boot_slumber); + a6xx_gmu_oob_clear(adreno_dev, oob_boot_slumber); + + if (!ret) { + kgsl_gmu_regread(device, + A6XX_GPU_GMU_CX_GMU_RPMH_POWER_STATE, &state); + if (state != GPU_HW_SLUMBER) { + dev_err(&gmu->pdev->dev, + "Failed to prepare for slumber: 0x%x\n", + state); + ret = -EINVAL; + } + } + +out: + /* Make sure the fence is in ALLOW mode */ + kgsl_gmu_regwrite(device, A6XX_GMU_AO_AHB_FENCE_CTRL, 0); + return ret; +} + +/* + * a6xx_rpmh_gpu_pwrctrl() - GPU power control via RPMh/GMU interface + * @adreno_dev: Pointer to adreno device + * @mode: requested power mode + * @arg1: first argument for mode control + * @arg2: second argument for mode control + */ +int a6xx_gmu_rpmh_gpu_pwrctrl(struct adreno_device *adreno_dev, + unsigned int mode, unsigned int arg1, unsigned int arg2) +{ + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); + struct gmu_device *gmu = &device->gmu; + int ret; + + switch (mode) { + case GMU_FW_START: + ret = a6xx_gmu_fw_start(device, arg1); + break; + case GMU_SUSPEND: + ret = a6xx_gmu_suspend(device); + break; + case GMU_FW_STOP: + if (ADRENO_QUIRK(adreno_dev, ADRENO_QUIRK_HFI_USE_REG)) + a6xx_gmu_oob_clear(adreno_dev, oob_boot_slumber); + ret = a6xx_rpmh_power_off_gpu(device); + break; + case GMU_DCVS_NOHFI: + ret = a6xx_gmu_dcvs_nohfi(device, arg1, arg2); + break; + case GMU_NOTIFY_SLUMBER: + ret = a6xx_gmu_notify_slumber(device); + break; + default: + dev_err(&gmu->pdev->dev, + "unsupported GMU power ctrl mode:%d\n", mode); + ret = -EINVAL; + break; + } + + return ret; +} + +#define LM_DEFAULT_LIMIT 6000 +#define GPU_LIMIT_THRESHOLD_ENABLE BIT(31) + +static uint32_t lm_limit(struct adreno_device *adreno_dev) +{ + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); + + if (adreno_dev->lm_limit) + return adreno_dev->lm_limit; + + if (of_property_read_u32(device->pdev->dev.of_node, "qcom,lm-limit", + &adreno_dev->lm_limit)) + adreno_dev->lm_limit = LM_DEFAULT_LIMIT; + + return adreno_dev->lm_limit; +} + +#define LIMITS_CONFIG(t, s, c, i, a) ( \ + (t & 0xF) | \ + ((s & 0xF) << 4) | \ + ((c & 0xF) << 8) | \ + ((i & 0xF) << 12) | \ + ((a & 0xF) << 16)) + +void a6xx_gmu_enable_lm(struct kgsl_device *device) +{ + int result; + struct gmu_device *gmu = &device->gmu; + struct adreno_device *adreno_dev = ADRENO_DEVICE(device); + struct device *dev = &gmu->pdev->dev; + struct hfi_lmconfig_cmd cmd; + + kgsl_gmu_regwrite(device, A6XX_GPU_GMU_CX_GMU_PWR_THRESHOLD, + GPU_LIMIT_THRESHOLD_ENABLE | lm_limit(adreno_dev)); + kgsl_gmu_regwrite(device, A6XX_GMU_AO_SPARE_CNTL, 1); + kgsl_gmu_regwrite(device, A6XX_GPU_GMU_CX_GMU_ISENSE_CTRL, 0x1); + + gmu->lm_config = LIMITS_CONFIG(1, 1, 1, 0, 0); + gmu->bcl_config = 0; + gmu->lm_dcvs_level = 0; + + cmd.limit_conf = gmu->lm_config; + cmd.bcl_conf = gmu->bcl_config; + cmd.lm_enable_bitmask = 0; + + if (gmu->lm_dcvs_level <= MAX_GX_LEVELS) + cmd.lm_enable_bitmask = + (1 << (gmu->lm_dcvs_level + 1)) - 1; + + result = hfi_send_req(gmu, H2F_MSG_LM_CFG, &cmd); + if (result) + dev_err(dev, "Failure enabling limits management:%d\n", result); + +} -- GitLab From 9e21b253cb848389bc66c73cd6e22c89efb4e367 Mon Sep 17 00:00:00 2001 From: Tharun Kumar Merugu Date: Tue, 17 Apr 2018 17:43:34 +0530 Subject: [PATCH 0438/1635] ARM: dts: msm: increase adsp heap size for sm8150 Increase adsp contig heap size from 12 MB to 16 MB Change-Id: I4c8cc579f3551475ee234a0440478bee5be9416b Acked-by: Thyagarajan Venkatanarayanan Signed-off-by: Tharun Kumar Merugu --- arch/arm64/boot/dts/qcom/sm8150.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/sm8150.dtsi b/arch/arm64/boot/dts/qcom/sm8150.dtsi index 3f7021ae3fb3..5ac770b58783 100644 --- a/arch/arm64/boot/dts/qcom/sm8150.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150.dtsi @@ -648,7 +648,7 @@ alloc-ranges = <0x0 0x00000000 0x0 0xffffffff>; reusable; alignment = <0x0 0x400000>; - size = <0x0 0xc00000>; + size = <0x0 0x1000000>; }; qseecom_ta_mem: qseecom_ta_region { -- GitLab From 48be0c6411d138f4d1d80b8fa0fa8006167736b2 Mon Sep 17 00:00:00 2001 From: Tharun Kumar Merugu Date: Tue, 17 Apr 2018 18:08:07 +0530 Subject: [PATCH 0439/1635] adsprpc: validate VMID before hyp_assign during unmap Validate VMID before doing hyp_assign_phys during unmap on DSP. Change-Id: I9c41416c9df12bd993bff59378ea66d31cda3686 Acked-by: Thyagarajan Venkatanarayanan Signed-off-by: Tharun Kumar Merugu --- drivers/char/adsprpc.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/char/adsprpc.c b/drivers/char/adsprpc.c index 10c29acecfca..4d1af266bf47 100644 --- a/drivers/char/adsprpc.c +++ b/drivers/char/adsprpc.c @@ -2041,12 +2041,15 @@ static int fastrpc_munmap_on_dsp_rh(struct fastrpc_file *fl, err = scm_call2(SCM_SIP_FNID(SCM_SVC_PIL, TZ_PIL_CLEAR_PROTECT_MEM_SUBSYS_ID), &desc); } else if (map->flags == ADSP_MMAP_REMOTE_HEAP_ADDR) { - VERIFY(err, !hyp_assign_phys(map->phys, (uint64_t)map->size, + if (me->channel[fl->cid].rhvm.vmid) { + VERIFY(err, !hyp_assign_phys(map->phys, + (uint64_t)map->size, me->channel[fl->cid].rhvm.vmid, me->channel[fl->cid].rhvm.vmcount, destVM, destVMperm, 1)); - if (err) - goto bail; + if (err) + goto bail; + } } bail: -- GitLab From 754a8023cd1673712be5958a9db1057c6cd78005 Mon Sep 17 00:00:00 2001 From: Konstantin Dorfman Date: Fri, 30 Mar 2018 16:17:01 +0300 Subject: [PATCH 0440/1635] soc: qcom: add secure processor communication (spcom) driver This driver supports communication with secure processor subsystem over rpmsg and ungerlying glink transport layer. The communication is based on using shared memory and interrupts. This driver exposes interface to user space. Migrate from using glink api to rpmsg api: - removed not used glink functionality - removed not used kernel api to spcom functionality - implemented rpmsg driver registration for each new spcom channel open/close/tx/rx/poll flows fixes: - rpmsg_abort flag introduced to synchronize close() of a channel with pending sending or receiving data from the channel - tx implemented as rpmsg_trysend() every 10ms (timeout_msec total) - poll imlemented link up/down events as first/last rpmsg device probed/removed - locking ION api replaced by dma-buf: ION api depricated. This change implements following functionality: Lock/unlock shared buffer by reference counting on underline dma-buf. Translation user allocated shared buffer virtual address to physical address (to enable SPU access to the buffer). Change-Id: I28d704b18a3b0de9711ff3235c3f5551e7302557 Signed-off-by: Konstantin Dorfman --- .../devicetree/bindings/arm/msm/spcom.txt | 11 + drivers/soc/qcom/Kconfig | 13 + drivers/soc/qcom/Makefile | 1 + drivers/soc/qcom/spcom.c | 2093 +++++++++++++++++ include/uapi/linux/spcom.h | 119 + 5 files changed, 2237 insertions(+) create mode 100644 Documentation/devicetree/bindings/arm/msm/spcom.txt create mode 100644 drivers/soc/qcom/spcom.c create mode 100644 include/uapi/linux/spcom.h diff --git a/Documentation/devicetree/bindings/arm/msm/spcom.txt b/Documentation/devicetree/bindings/arm/msm/spcom.txt new file mode 100644 index 000000000000..36a07ec686ad --- /dev/null +++ b/Documentation/devicetree/bindings/arm/msm/spcom.txt @@ -0,0 +1,11 @@ +Qualcomm Technologies, Inc. Secure Proccessor Communication (spcom) + +Required properties: +-compatible : should be "qcom,spcom" +-qcom,spcom-ch-names: predefined channels name string + +Example: + qcom,spcom { + compatible = "qcom,spcom"; + qcom,spcom-ch-names = "sp_kernel" , "sp_ssr"; + }; diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig index 72c57efb54e9..03592521b335 100644 --- a/drivers/soc/qcom/Kconfig +++ b/drivers/soc/qcom/Kconfig @@ -432,6 +432,19 @@ config MSM_SPSS_UTILS because the SPSS firmware size is too small to support multiple HW versions. +config MSM_SPCOM + depends on QCOM_GLINK + bool "Secure Processor Communication over GLINK" + help + spcom driver allows loading Secure Processor Applications and + sending messages to Secure Processor Applications. + spcom provides interface to both user space app and kernel driver. + It is using glink as the transport layer, which provides multiple + logical channels over single physical channel. + The physical layer is based on shared memory and interrupts. + spcom provides clients/server API, although currently only one client + or server is allowed per logical channel. + config QTI_RPMH_API bool "QTI RPMH (h/w accelerators) Communication API" select MAILBOX diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile index 67a8c9f81cb4..00e3dd6ba537 100644 --- a/drivers/soc/qcom/Makefile +++ b/drivers/soc/qcom/Makefile @@ -43,6 +43,7 @@ obj-$(CONFIG_MEM_SHARE_QMI_SERVICE) += memshare/ obj-$(CONFIG_MSM_PIL_SSR_GENERIC) += subsys-pil-tz.o obj-$(CONFIG_MSM_PIL) += peripheral-loader.o obj-$(CONFIG_QCOM_RUN_QUEUE_STATS) += rq_stats.o +obj-$(CONFIG_MSM_SPCOM) += spcom.o obj-$(CONFIG_QCOM_BUS_SCALING) += msm_bus/ obj-$(CONFIG_QCOM_COMMAND_DB) += cmd-db.o obj-$(CONFIG_QTI_RPMH_API) += rpmh.o diff --git a/drivers/soc/qcom/spcom.c b/drivers/soc/qcom/spcom.c new file mode 100644 index 000000000000..828d3f4a976b --- /dev/null +++ b/drivers/soc/qcom/spcom.c @@ -0,0 +1,2093 @@ +/* + * Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/* + * Secure-Processor-Communication (SPCOM). + * + * This driver provides communication to Secure Processor (SP) + * over RPMSG framework. + * + * It provides interface to userspace spcomlib. + * + * Userspace application shall use spcomlib for communication with SP. Userspace + * application can be either client or server. spcomlib shall use write() file + * operation to send data, and read() file operation to read data. + * + * This driver uses RPMSG with glink-spss as a transport layer. + * This driver exposes "/dev/" file node for each rpmsg logical + * channel. + * This driver exposes "/dev/spcom" file node for some debug/control command. + * The predefined channel "/dev/sp_kernel" is used for loading SP application + * from HLOS. + * This driver exposes "/dev/sp_ssr" file node to allow user space poll for SSR. + * After the remote SP App is loaded, this driver exposes a new file node + * "/dev/" for the matching HLOS App to use. + * The access to predefined file nodes and dynamically allocated file nodes is + * restricted by using unix group and SELinux. + * + * No message routing is used, but using the rpmsg/G-Link "multiplexing" feature + * to use a dedicated logical channel for HLOS and SP Application-Pair. + * + * Each HLOS/SP Application can be either Client or Server or both, + * Messaging is allways point-to-point between 2 HLOS<=>SP applications. + * Each channel exclusevly used by single Client or Server. + * + * User Space Request & Response are synchronous. + * read() & write() operations are blocking until completed or terminated. + */ +#define pr_fmt(fmt) KBUILD_MODNAME ": %s: " fmt, __func__ + +#include /* min() */ +#include /* MODULE_LICENSE */ +#include /* class_create() */ +#include /* kzalloc() */ +#include /* file_operations */ +#include /* cdev_add() */ +#include /* EINVAL, ETIMEDOUT */ +#include /* pr_err() */ +#include /* BIT(x) */ +#include /* wait_for_completion_timeout() */ +#include /* POLLOUT */ +#include +#include /* of_property_count_strings() */ +#include +#include /* msleep() */ +#include +#include +#include +#include +#include +#include + +/** + * Request buffer size. + * Any large data (multiply of 4KB) is provided by temp buffer in DDR. + * Request shall provide the temp buffer physical address (align to 4KB). + * Maximum request/response size of 268 is used to accommodate APDU size. + * From kernel spcom driver perspective a PAGE_SIZE of 4K + * is the actual maximum size for a single read/write file operation. + */ +#define SPCOM_MAX_RESPONSE_SIZE 268 + +/* SPCOM driver name */ +#define DEVICE_NAME "spcom" + +/* maximum ION buffers should be >= SPCOM_MAX_CHANNELS */ +#define SPCOM_MAX_ION_BUF_PER_CH (SPCOM_MAX_CHANNELS + 4) + +/* maximum ION buffer per send request/response command */ +#define SPCOM_MAX_ION_BUF_PER_CMD SPCOM_MAX_ION_BUF + +/* Maximum command size */ +#define SPCOM_MAX_COMMAND_SIZE (PAGE_SIZE) + +/* Maximum input size */ +#define SPCOM_MAX_READ_SIZE (PAGE_SIZE) + +/* Current Process ID */ +#define current_pid() ((u32)(current->pid)) + +/* + * After both sides get CONNECTED, + * there is a race between one side queueing rx buffer and the other side + * trying to call glink_tx() , this race is only on the 1st tx. + * Do tx retry with some delay to allow the other side to queue rx buffer. + */ +#define TX_RETRY_DELAY_MSEC 100 + +/* SPCOM_MAX_REQUEST_SIZE-or-SPCOM_MAX_RESPONSE_SIZE + header */ +#define SPCOM_RX_BUF_SIZE 300 + +/* + * Initial transaction id, use non-zero nonce for debug. + * Incremented by client on request, and copied back by server on response. + */ +#define INITIAL_TXN_ID 0x12345678 + +/** + * struct spcom_msg_hdr - Request/Response message header between HLOS and SP. + * + * This header is proceeding any request specific parameters. + * The transaction id is used to match request with response. + * Note: rpmsg API provides the rx/tx data size, so user payload size is + * calculated by reducing the header size. + */ +struct spcom_msg_hdr { + uint32_t reserved; /* for future use */ + uint32_t txn_id; /* transaction id */ + char buf[0]; /* Variable buffer size, must be last field */ +} __packed; + +/** + * struct spcom_client - Client handle + */ +struct spcom_client { + struct spcom_channel *ch; +}; + +/** + * struct spcom_server - Server handle + */ +struct spcom_server { + struct spcom_channel *ch; +}; + +/** + * struct spcom_channel - channel context + */ +struct spcom_channel { + char name[SPCOM_CHANNEL_NAME_SIZE]; + struct mutex lock; + uint32_t txn_id; /* incrementing nonce per client request */ + bool is_server; /* for txn_id and response_timeout_msec */ + uint32_t response_timeout_msec; /* for client only */ + + /* char dev */ + struct cdev *cdev; + struct device *dev; + struct device_attribute attr; + + /* rpmsg */ + struct rpmsg_driver *rpdrv; + struct rpmsg_device *rpdev; + + /* Events notification */ + struct completion rx_done; + struct completion connect; + + /* + * Only one client or server per channel. + * Only one rx/tx transaction at a time (request + response). + */ + bool is_busy; + + u32 pid; /* debug only to find user space application */ + + /* abort flags */ + bool rpmsg_abort; + + /* rx data info */ + size_t actual_rx_size; /* actual data size received */ + void *rpmsg_rx_buf; + + /* shared buffer lock/unlock support */ + int dmabuf_fd_table[SPCOM_MAX_ION_BUF_PER_CH]; + struct dma_buf *dmabuf_handle_table[SPCOM_MAX_ION_BUF_PER_CH]; +}; + +/** + * struct rx_buff_list - holds rx rpmsg data, before it will be consumed + * by spcom_signal_rx_done worker, item per rx packet + */ +struct rx_buff_list { + struct list_head list; + + void *rpmsg_rx_buf; + int rx_buf_size; + struct spcom_channel *ch; +}; + +/** + * struct spcom_device - device state structure. + */ +struct spcom_device { + char predefined_ch_name[SPCOM_MAX_CHANNELS][SPCOM_CHANNEL_NAME_SIZE]; + + /* char device info */ + struct cdev cdev; + dev_t device_no; + struct class *driver_class; + struct device *class_dev; + struct platform_device *pdev; + + /* rpmsg channels */ + struct spcom_channel channels[SPCOM_MAX_CHANNELS]; + atomic_t chdev_count; + + struct completion rpmsg_state_change; + atomic_t rpmsg_dev_count; + + /* rx data path */ + struct list_head rx_list_head; + spinlock_t rx_lock; +}; + +/* Device Driver State */ +static struct spcom_device *spcom_dev; + +/* static functions declaration */ +static int spcom_create_channel_chardev(const char *name); +static struct spcom_channel *spcom_find_channel_by_name(const char *name); +static int spcom_register_rpmsg_drv(struct spcom_channel *ch); +static int spcom_unregister_rpmsg_drv(struct spcom_channel *ch); + +/** + * spcom_is_channel_open() - channel is open on this side. + * + * Channel is fully connected, when rpmsg driver is registered and + * rpmsg device probed + */ +static inline bool spcom_is_channel_open(struct spcom_channel *ch) +{ + return ch->rpdrv != NULL; +} + +/** + * spcom_is_channel_connected() - channel is fully connected by both sides. + */ +static inline bool spcom_is_channel_connected(struct spcom_channel *ch) +{ + /* Channel must be open before it gets connected */ + if (!spcom_is_channel_open(ch)) + return false; + + return ch->rpdev != NULL; +} + +/** + * spcom_create_predefined_channels_chardev() - expose predefined channels to + * user space. + * + * Predefined channels list is provided by device tree. Typically, it is for + * known servers on remote side that are not loaded by the HLOS + */ +static int spcom_create_predefined_channels_chardev(void) +{ + int i; + int ret; + static bool is_predefined_created; + + if (is_predefined_created) + return 0; + + for (i = 0; i < SPCOM_MAX_CHANNELS; i++) { + const char *name = spcom_dev->predefined_ch_name[i]; + + if (name[0] == 0) + break; + ret = spcom_create_channel_chardev(name); + if (ret) { + pr_err("failed to create chardev [%s], ret [%d].\n", + name, ret); + return -EFAULT; + } + } + + is_predefined_created = true; + + return 0; +} + +/*======================================================================*/ +/* UTILITIES */ +/*======================================================================*/ + +/** + * spcom_init_channel() - initialize channel state. + * + * @ch: channel state struct pointer + * @name: channel name + */ +static int spcom_init_channel(struct spcom_channel *ch, const char *name) +{ + if (!ch || !name || !name[0]) { + pr_err("invalid parameters.\n"); + return -EINVAL; + } + + strlcpy(ch->name, name, SPCOM_CHANNEL_NAME_SIZE); + + init_completion(&ch->rx_done); + init_completion(&ch->connect); + + mutex_init(&ch->lock); + ch->rpdrv = NULL; + ch->rpdev = NULL; + ch->actual_rx_size = 0; + ch->is_busy = false; + ch->txn_id = INITIAL_TXN_ID; /* use non-zero nonce for debug */ + ch->pid = 0; + ch->rpmsg_abort = false; + ch->rpmsg_rx_buf = NULL; + + return 0; +} + +/** + * spcom_find_channel_by_name() - find a channel by name. + * + * @name: channel name + * + * Return: a channel state struct. + */ +static struct spcom_channel *spcom_find_channel_by_name(const char *name) +{ + int i; + + for (i = 0 ; i < ARRAY_SIZE(spcom_dev->channels); i++) { + struct spcom_channel *ch = &spcom_dev->channels[i]; + + if (strcmp(ch->name, name) == 0) + return ch; + } + + return NULL; +} + +/** + * spcom_rx() - wait for received data until timeout, unless pending rx data is + * already ready + * + * @ch: channel state struct pointer + * @buf: buffer pointer + * @size: buffer size + * + * Return: size in bytes on success, negative value on failure. + */ +static int spcom_rx(struct spcom_channel *ch, + void *buf, + uint32_t size, + uint32_t timeout_msec) +{ + unsigned long jiffies = msecs_to_jiffies(timeout_msec); + long timeleft = 1; + int ret; + + mutex_lock(&ch->lock); + + /* check for already pending data */ + if (!ch->actual_rx_size) { + reinit_completion(&ch->rx_done); + + mutex_unlock(&ch->lock); /* unlock while waiting */ + /* wait for rx response */ + pr_debug("wait for rx done, timeout_msec=%d\n", timeout_msec); + if (timeout_msec) + timeleft = wait_for_completion_timeout(&ch->rx_done, + jiffies); + else + wait_for_completion(&ch->rx_done); + + mutex_lock(&ch->lock); + if (timeout_msec && timeleft == 0) { + pr_err("rx_done timeout expired %d ms\n", timeout_msec); + ret = -ETIMEDOUT; + goto exit_err; + } else if (ch->rpmsg_abort) { + pr_warn("rpmsg channel is closing\n"); + ret = -ERESTART; + goto exit_err; + } else if (ch->actual_rx_size) { + pr_debug("actual_rx_size is [%zu]\n", + ch->actual_rx_size); + } else { + pr_err("actual_rx_size is zero.\n"); + ret = -EFAULT; + goto exit_err; + } + } else { + pr_debug("pending data size [%zu], requested size [%zu]\n", + ch->actual_rx_size, size); + } + if (!ch->rpmsg_rx_buf) { + pr_err("invalid rpmsg_rx_buf.\n"); + ret = -ENOMEM; + goto exit_err; + } + + size = min_t(size_t, ch->actual_rx_size, size); + memcpy(buf, ch->rpmsg_rx_buf, size); + + pr_debug("copy size [%d].\n", (int) size); + + memset(ch->rpmsg_rx_buf, 0, ch->actual_rx_size); + kfree((void *)ch->rpmsg_rx_buf); + ch->rpmsg_rx_buf = NULL; + ch->actual_rx_size = 0; + + mutex_unlock(&ch->lock); + + return size; +exit_err: + mutex_unlock(&ch->lock); + return ret; +} + +/** + * spcom_get_next_request_size() - get request size. + * already ready + * + * @ch: channel state struct pointer + * + * Server needs the size of the next request to allocate a request buffer. + * Initially used intent-request, however this complicated the remote side, + * so both sides are not using glink_tx() with INTENT_REQ anymore. + * + * Return: size in bytes on success, negative value on failure. + */ +static int spcom_get_next_request_size(struct spcom_channel *ch) +{ + int size = -1; + + /* NOTE: Remote clients might not be connected yet.*/ + mutex_lock(&ch->lock); + reinit_completion(&ch->rx_done); + + /* check if already got it via callback */ + if (ch->actual_rx_size) { + pr_debug("next-req-size already ready ch [%s] size [%zu]\n", + ch->name, ch->actual_rx_size); + goto exit_ready; + } + mutex_unlock(&ch->lock); /* unlock while waiting */ + + pr_debug("Wait for Rx Done, ch [%s].\n", ch->name); + wait_for_completion(&ch->rx_done); + + mutex_lock(&ch->lock); /* re-lock after waiting */ + + if (ch->actual_rx_size == 0) { + pr_err("invalid rx size [%zu] ch [%s]\n", + ch->actual_rx_size, ch->name); + goto exit_error; + } + +exit_ready: + /* actual_rx_size not exeeds SPCOM_RX_BUF_SIZE*/ + size = (int)ch->actual_rx_size; + if (size > sizeof(struct spcom_msg_hdr)) { + size -= sizeof(struct spcom_msg_hdr); + } else { + pr_err("rx size [%d] too small.\n", size); + goto exit_error; + } + + mutex_unlock(&ch->lock); + return size; + +exit_error: + mutex_unlock(&ch->lock); + return -EFAULT; + + +} + +/*======================================================================*/ +/* USER SPACE commands handling */ +/*======================================================================*/ + +/** + * spcom_handle_create_channel_command() - Handle Create Channel command from + * user space. + * + * @cmd_buf: command buffer. + * @cmd_size: command buffer size. + * + * Return: 0 on successful operation, negative value otherwise. + */ +static int spcom_handle_create_channel_command(void *cmd_buf, int cmd_size) +{ + int ret = 0; + struct spcom_user_create_channel_command *cmd = cmd_buf; + const char *ch_name; + const size_t maxlen = sizeof(cmd->ch_name); + + if (cmd_size != sizeof(*cmd)) { + pr_err("cmd_size [%d] , expected [%d].\n", + (int) cmd_size, (int) sizeof(*cmd)); + return -EINVAL; + } + + ch_name = cmd->ch_name; + if (strnlen(cmd->ch_name, maxlen) == maxlen) { + pr_err("channel name is not NULL terminated\n"); + return -EINVAL; + } + + pr_debug("ch_name [%s].\n", ch_name); + + ret = spcom_create_channel_chardev(ch_name); + + return ret; +} + +/** + * spcom_handle_send_command() - Handle send request/response from user space. + * + * @buf: command buffer. + * @buf_size: command buffer size. + * + * Return: 0 on successful operation, negative value otherwise. + */ +static int spcom_handle_send_command(struct spcom_channel *ch, + void *cmd_buf, int size) +{ + int ret = 0; + struct spcom_send_command *cmd = cmd_buf; + uint32_t buf_size; + void *buf; + struct spcom_msg_hdr *hdr; + void *tx_buf; + int tx_buf_size; + uint32_t timeout_msec; + int time_msec = 0; + + pr_debug("send req/resp ch [%s] size [%d] .\n", ch->name, size); + + /* + * check that cmd buf size is at least struct size, + * to allow access to struct fields. + */ + if (size < sizeof(*cmd)) { + pr_err("ch [%s] invalid cmd buf.\n", + ch->name); + return -EINVAL; + } + + /* Check if remote side connect */ + if (!spcom_is_channel_connected(ch)) { + pr_err("ch [%s] remote side not connect.\n", ch->name); + return -ENOTCONN; + } + + /* parse command buffer */ + buf = &cmd->buf; + buf_size = cmd->buf_size; + timeout_msec = cmd->timeout_msec; + + /* Check param validity */ + if (buf_size > SPCOM_MAX_RESPONSE_SIZE) { + pr_err("ch [%s] invalid buf size [%d].\n", + ch->name, buf_size); + return -EINVAL; + } + if (size != sizeof(*cmd) + buf_size) { + pr_err("ch [%s] invalid cmd size [%d].\n", + ch->name, size); + return -EINVAL; + } + + /* Allocate Buffers*/ + tx_buf_size = sizeof(*hdr) + buf_size; + tx_buf = kzalloc(tx_buf_size, GFP_KERNEL); + if (!tx_buf) + return -ENOMEM; + + /* Prepare Tx Buf */ + hdr = tx_buf; + + mutex_lock(&ch->lock); + /* Header */ + hdr->txn_id = ch->txn_id; + if (!ch->is_server) { + ch->txn_id++; /* client sets the request txn_id */ + ch->response_timeout_msec = timeout_msec; + } + + /* user buf */ + memcpy(hdr->buf, buf, buf_size); + + time_msec = 0; + do { + if (ch->rpmsg_abort) { + pr_err("ch [%s] aborted\n", ch->name); + ret = -ECANCELED; + break; + } + /* may fail when RX intent not queued by SP */ + ret = rpmsg_trysend(ch->rpdev->ept, tx_buf, tx_buf_size); + time_msec += TX_RETRY_DELAY_MSEC; + mutex_unlock(&ch->lock); + msleep(TX_RETRY_DELAY_MSEC); + mutex_lock(&ch->lock); + } while (ret == -EAGAIN && time_msec < timeout_msec); + mutex_unlock(&ch->lock); + + kfree(tx_buf); + return ret; +} + +/** + * modify_ion_addr() - replace the ION buffer virtual address with physical + * address in a request or response buffer. + * + * @buf: buffer to modify + * @buf_size: buffer size + * @ion_info: ION buffer info such as FD and offset in buffer. + * + * Return: 0 on successful operation, negative value otherwise. + */ +static int modify_ion_addr(void *buf, + uint32_t buf_size, + struct spcom_ion_info ion_info) +{ + struct dma_buf *dma_buf; + struct dma_buf_attachment *attach; + struct sg_table *sg = NULL; + dma_addr_t phy_addr = 0; + int fd, ret = 0; + uint32_t buf_offset; + char *ptr = (char *)buf; + + fd = ion_info.fd; + buf_offset = ion_info.buf_offset; + ptr += buf_offset; + + if (fd < 0) { + pr_err("invalid fd [%d].\n", fd); + return -ENODEV; + } + + if (buf_size < sizeof(uint64_t)) { + pr_err("buf size too small [%d].\n", buf_size); + return -ENODEV; + } + + if (buf_offset % sizeof(uint64_t)) + pr_debug("offset [%d] is NOT 64-bit aligned.\n", buf_offset); + else + pr_debug("offset [%d] is 64-bit aligned.\n", buf_offset); + + if (buf_offset > buf_size - sizeof(uint64_t)) { + pr_err("invalid buf_offset [%d].\n", buf_offset); + return -ENODEV; + } + + dma_buf = dma_buf_get(fd); + if (IS_ERR_OR_NULL(dma_buf)) { + pr_err("fail to get dma buf handle.\n"); + return -EINVAL; + } + pr_debug("dma_buf handle ok.\n"); + attach = dma_buf_attach(dma_buf, &spcom_dev->pdev->dev); + if (IS_ERR_OR_NULL(attach)) { + ret = PTR_ERR(attach); + pr_err("fail to attach dma buf %d\n", ret); + dma_buf_put(dma_buf); + goto mem_map_table_failed; + } + + sg = dma_buf_map_attachment(attach, DMA_BIDIRECTIONAL); + if (IS_ERR_OR_NULL(sg)) { + ret = PTR_ERR(sg); + pr_err("fail to get sg table of dma buf %d\n", ret); + goto mem_map_table_failed; + } + if (sg->sgl) { + phy_addr = sg->sgl->dma_address; + } else { + pr_err("sgl is NULL\n"); + ret = -ENOMEM; + goto mem_map_sg_failed; + } + + /* Set the physical address at the buffer offset */ + pr_debug("ion phys addr = [0x%lx].\n", (long int) phy_addr); + memcpy(ptr, &phy_addr, sizeof(phy_addr)); + +mem_map_sg_failed: + dma_buf_unmap_attachment(attach, sg, DMA_BIDIRECTIONAL); +mem_map_table_failed: + dma_buf_detach(dma_buf, attach); + dma_buf_put(dma_buf); + + return ret; +} + +/** + * spcom_handle_send_modified_command() - send a request/response with ION + * buffer address. Modify the request/response by replacing the ION buffer + * virtual address with the physical address. + * + * @ch: channel pointer + * @cmd_buf: User space command buffer + * @size: size of user command buffer + * + * Return: 0 on successful operation, negative value otherwise. + */ +static int spcom_handle_send_modified_command(struct spcom_channel *ch, + void *cmd_buf, int size) +{ + int ret = 0; + struct spcom_user_send_modified_command *cmd = cmd_buf; + uint32_t buf_size; + void *buf; + struct spcom_msg_hdr *hdr; + void *tx_buf; + int tx_buf_size; + struct spcom_ion_info ion_info[SPCOM_MAX_ION_BUF_PER_CMD]; + int i; + uint32_t timeout_msec; + int time_msec = 0; + + pr_debug("send req/resp ch [%s] size [%d] .\n", ch->name, size); + + /* + * check that cmd buf size is at least struct size, + * to allow access to struct fields. + */ + if (size < sizeof(*cmd)) { + pr_err("ch [%s] invalid cmd buf.\n", + ch->name); + return -EINVAL; + } + + /* Check if remote side connect */ + if (!spcom_is_channel_connected(ch)) { + pr_err("ch [%s] remote side not connect.\n", ch->name); + return -ENOTCONN; + } + + /* parse command buffer */ + buf = &cmd->buf; + buf_size = cmd->buf_size; + timeout_msec = cmd->timeout_msec; + memcpy(ion_info, cmd->ion_info, sizeof(ion_info)); + + /* Check param validity */ + if (buf_size > SPCOM_MAX_RESPONSE_SIZE) { + pr_err("ch [%s] invalid buf size [%d].\n", + ch->name, buf_size); + return -EINVAL; + } + if (size != sizeof(*cmd) + buf_size) { + pr_err("ch [%s] invalid cmd size [%d].\n", + ch->name, size); + return -EINVAL; + } + + /* Allocate Buffers*/ + tx_buf_size = sizeof(*hdr) + buf_size; + tx_buf = kzalloc(tx_buf_size, GFP_KERNEL); + if (!tx_buf) + return -ENOMEM; + + /* Prepare Tx Buf */ + hdr = tx_buf; + + mutex_lock(&ch->lock); + /* Header */ + hdr->txn_id = ch->txn_id; + if (!ch->is_server) { + ch->txn_id++; /* client sets the request txn_id */ + ch->response_timeout_msec = timeout_msec; + } + + /* user buf */ + memcpy(hdr->buf, buf, buf_size); + + for (i = 0 ; i < ARRAY_SIZE(ion_info) ; i++) { + if (ion_info[i].fd >= 0) { + ret = modify_ion_addr(hdr->buf, buf_size, ion_info[i]); + if (ret < 0) { + mutex_unlock(&ch->lock); + pr_err("modify_ion_addr() error [%d].\n", ret); + memset(tx_buf, 0, tx_buf_size); + kfree(tx_buf); + return -EFAULT; + } + } + } + + time_msec = 0; + do { + if (ch->rpmsg_abort) { + pr_err("ch [%s] aborted\n", ch->name); + ret = -ECANCELED; + break; + } + /* may fail when RX intent not queued by SP */ + ret = rpmsg_trysend(ch->rpdev->ept, tx_buf, tx_buf_size); + time_msec += TX_RETRY_DELAY_MSEC; + mutex_unlock(&ch->lock); + msleep(TX_RETRY_DELAY_MSEC); + mutex_lock(&ch->lock); + } while (ret == -EAGAIN && time_msec < timeout_msec); + mutex_unlock(&ch->lock); + memset(tx_buf, 0, tx_buf_size); + kfree(tx_buf); + return ret; +} + + +/** + * spcom_handle_lock_ion_buf_command() - Lock an shared buffer. + * + * Lock an shared buffer, prevent it from being free if the userspace App crash, + * while it is used by the remote subsystem. + */ +static int spcom_handle_lock_ion_buf_command(struct spcom_channel *ch, + void *cmd_buf, int size) +{ + struct spcom_user_command *cmd = cmd_buf; + int fd; + int i; + struct dma_buf *dma_buf; + + if (size != sizeof(*cmd)) { + pr_err("cmd size [%d] , expected [%d].\n", + (int) size, (int) sizeof(*cmd)); + return -EINVAL; + } + + if (cmd->arg > (unsigned int)INT_MAX) { + pr_err("int overflow [%ld]\n", cmd->arg); + return -EINVAL; + } + fd = cmd->arg; + + dma_buf = dma_buf_get(fd); + if (IS_ERR_OR_NULL(dma_buf)) { + pr_err("fail to get dma buf handle.\n"); + return -EINVAL; + } + pr_debug("dma_buf referenced ok.\n"); + + /* shared buf lock doesn't involve any rx/tx data to SP. */ + mutex_lock(&ch->lock); + + /* Check if this shared buffer is already locked */ + for (i = 0 ; i < ARRAY_SIZE(ch->dmabuf_handle_table) ; i++) { + if (ch->dmabuf_handle_table[i] == dma_buf) { + pr_err("fd [%d] shared buf is already locked.\n", fd); + /* decrement back the ref count */ + mutex_unlock(&ch->lock); + dma_buf_put(dma_buf); + return -EINVAL; + } + } + + /* Store the dma_buf handle */ + for (i = 0 ; i < ARRAY_SIZE(ch->dmabuf_handle_table) ; i++) { + if (ch->dmabuf_handle_table[i] == NULL) { + ch->dmabuf_handle_table[i] = dma_buf; + ch->dmabuf_fd_table[i] = fd; + pr_debug("ch [%s] locked ion buf #%d, fd [%d].\n", + ch->name, i, fd); + mutex_unlock(&ch->lock); + return 0; + } + } + + mutex_unlock(&ch->lock); + /* decrement back the ref count */ + dma_buf_put(dma_buf); + pr_err("no free entry to store ion handle of fd [%d].\n", fd); + + return -EFAULT; +} + +/** + * spcom_handle_unlock_ion_buf_command() - Unlock an ION buffer. + * + * Unlock an ION buffer, let it be free, when it is no longer being used by + * the remote subsystem. + */ +static int spcom_handle_unlock_ion_buf_command(struct spcom_channel *ch, + void *cmd_buf, int size) +{ + int i; + struct spcom_user_command *cmd = cmd_buf; + int fd; + bool found = false; + + if (size != sizeof(*cmd)) { + pr_err("cmd size [%d], expected [%d]\n", + (int)size, (int)sizeof(*cmd)); + return -EINVAL; + } + if (cmd->arg > (unsigned int)INT_MAX) { + pr_err("int overflow [%ld]\n", cmd->arg); + return -EINVAL; + } + fd = cmd->arg; + + pr_debug("Unlock ion buf ch [%s] fd [%d].\n", ch->name, fd); + /* shared buf unlock doesn't involve any rx/tx data to SP. */ + mutex_lock(&ch->lock); + if (fd == (int) SPCOM_ION_FD_UNLOCK_ALL) { + pr_debug("unlocked ALL ion buf ch [%s].\n", ch->name); + found = true; + /* unlock all buf */ + for (i = 0; i < ARRAY_SIZE(ch->dmabuf_handle_table); i++) { + if (ch->dmabuf_handle_table[i] != NULL) { + pr_debug("unlocked ion buf #%d fd [%d].\n", + i, ch->dmabuf_fd_table[i]); + dma_buf_put(ch->dmabuf_handle_table[i]); + ch->dmabuf_handle_table[i] = NULL; + ch->dmabuf_fd_table[i] = -1; + } + } + } else { + /* unlock specific buf */ + for (i = 0 ; i < ARRAY_SIZE(ch->dmabuf_handle_table) ; i++) { + if (!ch->dmabuf_handle_table[i]) + continue; + if (ch->dmabuf_fd_table[i] == fd) { + pr_debug("unlocked ion buf #%d fd [%d].\n", + i, ch->dmabuf_fd_table[i]); + dma_buf_put(ch->dmabuf_handle_table[i]); + ch->dmabuf_handle_table[i] = NULL; + ch->dmabuf_fd_table[i] = -1; + found = true; + break; + } + } + } + mutex_unlock(&ch->lock); + + if (!found) { + pr_err("ch [%s] fd [%d] was not found.\n", ch->name, fd); + return -ENODEV; + } + + return 0; +} + +/** + * spcom_handle_write() - Handle user space write commands. + * + * @buf: command buffer. + * @buf_size: command buffer size. + * + * Return: 0 on successful operation, negative value otherwise. + */ +static int spcom_handle_write(struct spcom_channel *ch, + void *buf, + int buf_size) +{ + int ret = 0; + struct spcom_user_command *cmd = NULL; + int cmd_id = 0; + + /* Minimal command should have command-id and argument */ + if (buf_size < sizeof(struct spcom_user_command)) { + pr_err("Command buffer size [%d] too small\n", buf_size); + return -EINVAL; + } + + cmd = (struct spcom_user_command *)buf; + cmd_id = (int) cmd->cmd_id; + + pr_debug("cmd_id [0x%x]\n", cmd_id); + + switch (cmd_id) { + case SPCOM_CMD_SEND: + ret = spcom_handle_send_command(ch, buf, buf_size); + break; + case SPCOM_CMD_SEND_MODIFIED: + ret = spcom_handle_send_modified_command(ch, buf, buf_size); + break; + case SPCOM_CMD_LOCK_ION_BUF: + ret = spcom_handle_lock_ion_buf_command(ch, buf, buf_size); + break; + case SPCOM_CMD_UNLOCK_ION_BUF: + ret = spcom_handle_unlock_ion_buf_command(ch, buf, buf_size); + break; + case SPCOM_CMD_CREATE_CHANNEL: + ret = spcom_handle_create_channel_command(buf, buf_size); + break; + default: + pr_err("Invalid Command Id [0x%x].\n", (int) cmd->cmd_id); + ret = -EINVAL; + } + + return ret; +} + +/** + * spcom_handle_get_req_size() - Handle user space get request size command + * + * @ch: channel handle + * @buf: command buffer. + * @size: command buffer size. + * + * Return: size in bytes on success, negative value on failure. + */ +static int spcom_handle_get_req_size(struct spcom_channel *ch, + void *buf, + uint32_t size) +{ + int ret = -1; + uint32_t next_req_size = 0; + + if (size < sizeof(next_req_size)) { + pr_err("buf size [%d] too small.\n", (int) size); + return -EINVAL; + } + + ret = spcom_get_next_request_size(ch); + if (ret < 0) + return ret; + next_req_size = (uint32_t) ret; + + memcpy(buf, &next_req_size, sizeof(next_req_size)); + pr_debug("next_req_size [%d].\n", next_req_size); + + return sizeof(next_req_size); /* can't exceed user buffer size */ +} + +/** + * spcom_handle_read_req_resp() - Handle user space get request/response command + * + * @ch: channel handle + * @buf: command buffer. + * @size: command buffer size. + * + * Return: size in bytes on success, negative value on failure. + */ +static int spcom_handle_read_req_resp(struct spcom_channel *ch, + void *buf, + uint32_t size) +{ + int ret; + struct spcom_msg_hdr *hdr; + void *rx_buf; + int rx_buf_size; + uint32_t timeout_msec = 0; /* client only */ + + /* Check if remote side connect */ + if (!spcom_is_channel_connected(ch)) { + pr_err("ch [%s] remote side not connect.\n", ch->name); + return -ENOTCONN; + } + + /* Check param validity */ + if (size > SPCOM_MAX_RESPONSE_SIZE) { + pr_err("ch [%s] invalid size [%d].\n", + ch->name, size); + return -EINVAL; + } + + /* Allocate Buffers*/ + rx_buf_size = sizeof(*hdr) + size; + rx_buf = kzalloc(rx_buf_size, GFP_KERNEL); + if (!rx_buf) + return -ENOMEM; + + /* + * client response timeout depends on the request + * handling time on the remote side . + */ + if (!ch->is_server) { + timeout_msec = ch->response_timeout_msec; + pr_debug("response_timeout_msec = %d.\n", (int) timeout_msec); + } + + ret = spcom_rx(ch, rx_buf, rx_buf_size, timeout_msec); + if (ret < 0) { + pr_err("rx error %d.\n", ret); + goto exit_err; + } else { + size = ret; /* actual_rx_size */ + } + + hdr = rx_buf; + + if (ch->is_server) { + ch->txn_id = hdr->txn_id; + pr_debug("request txn_id [0x%x].\n", ch->txn_id); + } + + /* copy data to user without the header */ + if (size > sizeof(*hdr)) { + size -= sizeof(*hdr); + memcpy(buf, hdr->buf, size); + } else { + pr_err("rx size [%d] too small.\n", size); + ret = -EFAULT; + goto exit_err; + } + + kfree(rx_buf); + return size; +exit_err: + kfree(rx_buf); + return ret; +} + +/** + * spcom_handle_read() - Handle user space read request/response or + * request-size command + * + * @ch: channel handle + * @buf: command buffer. + * @size: command buffer size. + * + * A special size SPCOM_GET_NEXT_REQUEST_SIZE, which is bigger than the max + * response/request tells the kernel that user space only need the size. + * + * Return: size in bytes on success, negative value on failure. + */ +static int spcom_handle_read(struct spcom_channel *ch, + void *buf, + uint32_t size) +{ + int ret = -1; + + if (size == SPCOM_GET_NEXT_REQUEST_SIZE) { + pr_debug("get next request size, ch [%s].\n", ch->name); + ch->is_server = true; + ret = spcom_handle_get_req_size(ch, buf, size); + } else { + pr_debug("get request/response, ch [%s].\n", ch->name); + ret = spcom_handle_read_req_resp(ch, buf, size); + } + + pr_debug("ch [%s] , size = %d.\n", ch->name, size); + + return ret; +} + +/*======================================================================*/ +/* CHAR DEVICE USER SPACE INTERFACE */ +/*======================================================================*/ + +/** + * file_to_filename() - get the filename from file pointer. + * + * @filp: file pointer + * + * it is used for debug prints. + * + * Return: filename string or "unknown". + */ +static char *file_to_filename(struct file *filp) +{ + struct dentry *dentry = NULL; + char *filename = NULL; + + if (!filp || !filp->f_path.dentry) + return "unknown"; + + dentry = filp->f_path.dentry; + filename = dentry->d_iname; + + return filename; +} + +/** + * spcom_device_open() - handle channel file open() from user space. + * + * @filp: file pointer + * + * The file name (without path) is the channel name. + * Register rpmsg driver matching with channel name. + * Store the channel context in the file private date pointer for future + * read/write/close operations. + */ +static int spcom_device_open(struct inode *inode, struct file *filp) +{ + struct spcom_channel *ch; + int ret; + const char *name = file_to_filename(filp); + u32 pid = current_pid(); + + pr_debug("open file [%s].\n", name); + + if (strcmp(name, "unknown") == 0) { + pr_err("name is unknown\n"); + return -EINVAL; + } + + if (strcmp(name, DEVICE_NAME) == 0) { + pr_debug("root dir skipped.\n"); + return 0; + } + + if (strcmp(name, "sp_ssr") == 0) { + pr_debug("sp_ssr dev node skipped.\n"); + return 0; + } + + ch = spcom_find_channel_by_name(name); + if (!ch) { + pr_err("channel %s doesn't exist, load App first.\n", name); + return -ENODEV; + } + + mutex_lock(&ch->lock); + if (!spcom_is_channel_open(ch)) { + reinit_completion(&ch->connect); + /* channel was closed need to register drv again */ + ret = spcom_register_rpmsg_drv(ch); + if (ret < 0) { + pr_err("register rpmsg driver failed %d\n", ret); + mutex_unlock(&ch->lock); + return ret; + } + } + /* only one client/server may use the channel */ + if (ch->is_busy) { + pr_err("channel [%s] is BUSY, already in use by pid [%d].\n", + name, ch->pid); + mutex_unlock(&ch->lock); + return -EBUSY; + } + + ch->is_busy = true; + ch->pid = pid; + ch->txn_id = INITIAL_TXN_ID; + mutex_unlock(&ch->lock); + + filp->private_data = ch; + return 0; +} + +/** + * spcom_device_release() - handle channel file close() from user space. + * + * @filp: file pointer + * + * The file name (without path) is the channel name. + * Open the relevant glink channel. + * Store the channel context in the file private + * date pointer for future read/write/close + * operations. + */ +static int spcom_device_release(struct inode *inode, struct file *filp) +{ + struct spcom_channel *ch; + const char *name = file_to_filename(filp); + int ret = 0; + + pr_err("close file [%s].\n", name); + + if (strcmp(name, "unknown") == 0) { + pr_err("name is unknown\n"); + return -EINVAL; + } + + if (strcmp(name, DEVICE_NAME) == 0) { + pr_debug("root dir skipped.\n"); + return 0; + } + + if (strcmp(name, "sp_ssr") == 0) { + pr_debug("sp_ssr dev node skipped.\n"); + return 0; + } + + ch = filp->private_data; + if (!ch) { + pr_debug("ch is NULL, file name %s.\n", file_to_filename(filp)); + return -ENODEV; + } + + mutex_lock(&ch->lock); + /* channel might be already closed or disconnected */ + if (!spcom_is_channel_open(ch)) { + pr_debug("ch [%s] already closed.\n", name); + mutex_unlock(&ch->lock); + return 0; + } + + ch->is_busy = false; + ch->pid = 0; + ch->txn_id = INITIAL_TXN_ID; /* use non-zero nonce for debug */ + + if (strcmp(name, "sp_kernel") != 0) { + ret = spcom_unregister_rpmsg_drv(ch); + if (ret != 0) + pr_err("can't unregister rpmsg drv\n", ret); + } + + mutex_unlock(&ch->lock); + filp->private_data = NULL; + + return ret; +} + +/** + * spcom_device_write() - handle channel file write() from user space. + * + * @filp: file pointer + * + * Return: On Success - same size as number of bytes to write. + * On Failure - negative value. + */ +static ssize_t spcom_device_write(struct file *filp, + const char __user *user_buff, + size_t size, loff_t *f_pos) +{ + int ret; + char *buf; + struct spcom_channel *ch; + const char *name = file_to_filename(filp); + int buf_size = 0; + + if (!user_buff || !f_pos || !filp) { + pr_err("invalid null parameters.\n"); + return -EINVAL; + } + + if (*f_pos != 0) { + pr_err("offset should be zero, no sparse buffer.\n"); + return -EINVAL; + } + + if (!name) { + pr_err("name is NULL\n"); + return -EINVAL; + } + pr_debug("write file [%s] size [%d] pos [%d].\n", + name, (int) size, (int) *f_pos); + + if (strcmp(name, "unknown") == 0) { + pr_err("name is unknown\n"); + return -EINVAL; + } + + ch = filp->private_data; + if (!ch) { + pr_err("invalid ch pointer, command not allowed.\n"); + return -EINVAL; + } + + /* Check if remote side connect */ + if (!spcom_is_channel_connected(ch)) { + pr_err("ch [%s] remote side not connected\n", ch->name); + return -ENOTCONN; + } + + if (size > SPCOM_MAX_COMMAND_SIZE) { + pr_err("size [%d] > max size [%d].\n", + (int) size, (int) SPCOM_MAX_COMMAND_SIZE); + return -EINVAL; + } + buf_size = size; /* explicit casting size_t to int */ + buf = kzalloc(size, GFP_KERNEL); + if (buf == NULL) + return -ENOMEM; + + ret = copy_from_user(buf, user_buff, size); + if (ret) { + pr_err("Unable to copy from user (err %d).\n", ret); + kfree(buf); + return -EFAULT; + } + + ret = spcom_handle_write(ch, buf, buf_size); + if (ret) { + pr_err("handle command error [%d].\n", ret); + kfree(buf); + return -EFAULT; + } + + kfree(buf); + + return size; +} + +/** + * spcom_device_read() - handle channel file read() from user space. + * + * @filp: file pointer + * + * Return: number of bytes to read on success, negative value on + * failure. + */ +static ssize_t spcom_device_read(struct file *filp, char __user *user_buff, + size_t size, loff_t *f_pos) +{ + int ret = 0; + int actual_size = 0; + char *buf; + struct spcom_channel *ch; + const char *name = file_to_filename(filp); + uint32_t buf_size = 0; + + pr_debug("read file [%s], size = %d bytes.\n", name, (int) size); + + if (strcmp(name, "unknown") == 0) { + pr_err("name is unknown\n"); + return -EINVAL; + } + + if (!user_buff || !f_pos || + (size == 0) || (size > SPCOM_MAX_READ_SIZE)) { + pr_err("invalid parameters.\n"); + return -EINVAL; + } + buf_size = size; /* explicit casting size_t to uint32_t */ + + ch = filp->private_data; + + if (ch == NULL) { + pr_err("invalid ch pointer, file [%s].\n", name); + return -EINVAL; + } + + if (!spcom_is_channel_open(ch)) { + pr_err("ch is not open, file [%s].\n", name); + return -EINVAL; + } + + buf = kzalloc(size, GFP_KERNEL); + if (buf == NULL) + return -ENOMEM; + + ret = spcom_handle_read(ch, buf, buf_size); + if (ret < 0) { + pr_err("read error [%d].\n", ret); + kfree(buf); + return ret; + } + actual_size = ret; + if ((actual_size == 0) || (actual_size > size)) { + pr_err("invalid actual_size [%d].\n", actual_size); + kfree(buf); + return -EFAULT; + } + + ret = copy_to_user(user_buff, buf, actual_size); + if (ret) { + pr_err("Unable to copy to user, err = %d.\n", ret); + kfree(buf); + return -EFAULT; + } + + kfree(buf); + pr_debug("ch [%s] ret [%d].\n", name, (int) actual_size); + + return actual_size; +} + +/** + * spcom_device_poll() - handle channel file poll() from user space. + * + * @filp: file pointer + * + * This allows user space to wait/check for channel connection, + * or wait for SSR event. + * + * Return: event bitmask on success, set POLLERR on failure. + */ +static unsigned int spcom_device_poll(struct file *filp, + struct poll_table_struct *poll_table) +{ + /* + * when user call with timeout -1 for blocking mode, + * any bit must be set in response + */ + unsigned int ret = SPCOM_POLL_READY_FLAG; + unsigned long mask; + struct spcom_channel *ch; + const char *name = file_to_filename(filp); + bool wait = false; + bool done = false; + /* Event types always implicitly polled for */ + unsigned long reserved = POLLERR | POLLHUP | POLLNVAL; + int ready = 0; + + if (strcmp(name, "unknown") == 0) { + pr_err("name is unknown\n"); + return -EINVAL; + } + + if (!poll_table) { + pr_err("invalid parameters.\n"); + return -EINVAL; + } + + ch = filp->private_data; + mask = poll_requested_events(poll_table); + + pr_debug("== ch [%s] mask [0x%x] ==.\n", name, (int) mask); + + /* user space API has poll use "short" and not "long" */ + mask &= 0x0000FFFF; + + wait = mask & SPCOM_POLL_WAIT_FLAG; + if (wait) + pr_debug("ch [%s] wait for event flag is ON.\n", name); + + // mask will be used in output, clean input bits + mask &= (unsigned long)~SPCOM_POLL_WAIT_FLAG; + mask &= (unsigned long)~SPCOM_POLL_READY_FLAG; + mask &= (unsigned long)~reserved; + + switch (mask) { + case SPCOM_POLL_LINK_STATE: + pr_debug("ch [%s] SPCOM_POLL_LINK_STATE.\n", name); + if (wait) { + reinit_completion(&spcom_dev->rpmsg_state_change); + ready = wait_for_completion_interruptible( + &spcom_dev->rpmsg_state_change); + pr_debug("ch [%s] poll LINK_STATE signaled.\n", name); + } + done = atomic_read(&spcom_dev->rpmsg_dev_count) > 0; + break; + case SPCOM_POLL_CH_CONNECT: + /* + * ch is not expected to be NULL since user must call open() + * to get FD before it can call poll(). + * open() will fail if no ch related to the char-device. + */ + if (ch == NULL) { + pr_err("invalid ch pointer, file [%s].\n", name); + return POLLERR; + } + pr_debug("ch [%s] SPCOM_POLL_CH_CONNECT.\n", name); + if (wait) { + reinit_completion(&ch->connect); + ready = wait_for_completion_interruptible(&ch->connect); + pr_debug("ch [%s] poll CH_CONNECT signaled.\n", name); + } + mutex_lock(&ch->lock); + done = completion_done(&ch->connect); + mutex_unlock(&ch->lock); + break; + default: + pr_err("ch [%s] poll, invalid mask [0x%x].\n", + name, (int) mask); + ret = POLLERR; + break; + } + + if (ready < 0) { /* wait was interrupted */ + pr_debug("ch [%s] poll interrupted, ret [%d].\n", name, ready); + ret = POLLERR | SPCOM_POLL_READY_FLAG | mask; + } + if (done) + ret |= mask; + + pr_debug("ch [%s] poll, mask = 0x%x, ret=0x%x.\n", + name, (int) mask, ret); + + return ret; +} + +/* file operation supported from user space */ +static const struct file_operations fops = { + .owner = THIS_MODULE, + .read = spcom_device_read, + .poll = spcom_device_poll, + .write = spcom_device_write, + .open = spcom_device_open, + .release = spcom_device_release, +}; + +/** + * spcom_create_channel_chardev() - Create a channel char-dev node file + * for user space interface + */ +static int spcom_create_channel_chardev(const char *name) +{ + int ret; + struct device *dev; + struct spcom_channel *ch; + dev_t devt; + struct class *cls = spcom_dev->driver_class; + struct device *parent = spcom_dev->class_dev; + void *priv; + struct cdev *cdev; + + pr_debug("Add channel [%s].\n", name); + + ch = spcom_find_channel_by_name(name); + if (ch) { + pr_err("channel [%s] already exist.\n", name); + return -EINVAL; + } + + ch = spcom_find_channel_by_name(""); /* find reserved channel */ + if (!ch) { + pr_err("no free channel.\n"); + return -ENODEV; + } + + ret = spcom_init_channel(ch, name); + if (ret < 0) { + pr_err("can't init channel %d\n", ret); + return ret; + } + + mutex_lock(&ch->lock); + ret = spcom_register_rpmsg_drv(ch); + if (ret < 0) { + pr_err("register rpmsg driver failed %d\n", ret); + goto exit_destroy_channel; + } + + cdev = kzalloc(sizeof(*cdev), GFP_KERNEL); + if (!cdev) { + ret = -ENOMEM; + goto exit_unregister_drv; + } + + devt = spcom_dev->device_no + atomic_read(&spcom_dev->chdev_count); + priv = ch; + dev = device_create(cls, parent, devt, priv, name); + if (IS_ERR(dev)) { + pr_err("device_create failed.\n"); + ret = -ENODEV; + goto exit_free_cdev; + } + + cdev_init(cdev, &fops); + cdev->owner = THIS_MODULE; + + ret = cdev_add(cdev, devt, 1); + if (ret < 0) { + pr_err("cdev_add failed %d\n", ret); + ret = -ENODEV; + goto exit_destroy_device; + } + atomic_inc(&spcom_dev->chdev_count); + ch->cdev = cdev; + ch->dev = dev; + mutex_unlock(&ch->lock); + + return 0; + +exit_destroy_device: + device_destroy(spcom_dev->driver_class, devt); +exit_free_cdev: + kfree(cdev); +exit_unregister_drv: + ret = spcom_unregister_rpmsg_drv(ch); + if (ret != 0) + pr_err("can't unregister rpmsg drv\n", ret); +exit_destroy_channel: + // empty channel leaves free slot for next time + memset(ch->name, 0, SPCOM_CHANNEL_NAME_SIZE); + mutex_unlock(&ch->lock); + return -EFAULT; +} + +static int __init spcom_register_chardev(void) +{ + int ret; + unsigned int baseminor = 0; + unsigned int count = 1; + void *priv = spcom_dev; + + ret = alloc_chrdev_region(&spcom_dev->device_no, baseminor, count, + DEVICE_NAME); + if (ret < 0) { + pr_err("alloc_chrdev_region failed %d\n", ret); + return ret; + } + + spcom_dev->driver_class = class_create(THIS_MODULE, DEVICE_NAME); + if (IS_ERR(spcom_dev->driver_class)) { + ret = -ENOMEM; + pr_err("class_create failed %d\n", ret); + goto exit_unreg_chrdev_region; + } + + spcom_dev->class_dev = device_create(spcom_dev->driver_class, NULL, + spcom_dev->device_no, priv, + DEVICE_NAME); + + if (IS_ERR(spcom_dev->class_dev)) { + pr_err("class_device_create failed %d\n", ret); + ret = -ENOMEM; + goto exit_destroy_class; + } + + cdev_init(&spcom_dev->cdev, &fops); + spcom_dev->cdev.owner = THIS_MODULE; + + ret = cdev_add(&spcom_dev->cdev, + MKDEV(MAJOR(spcom_dev->device_no), 0), + SPCOM_MAX_CHANNELS); + if (ret < 0) { + pr_err("cdev_add failed %d\n", ret); + goto exit_destroy_device; + } + + pr_debug("char device created.\n"); + + return 0; + +exit_destroy_device: + device_destroy(spcom_dev->driver_class, spcom_dev->device_no); +exit_destroy_class: + class_destroy(spcom_dev->driver_class); +exit_unreg_chrdev_region: + unregister_chrdev_region(spcom_dev->device_no, 1); + return ret; +} + +static void spcom_unregister_chrdev(void) +{ + cdev_del(&spcom_dev->cdev); + device_destroy(spcom_dev->driver_class, spcom_dev->device_no); + class_destroy(spcom_dev->driver_class); + unregister_chrdev_region(spcom_dev->device_no, + atomic_read(&spcom_dev->chdev_count)); + +} + +static int spcom_parse_dt(struct device_node *np) +{ + int ret; + const char *propname = "qcom,spcom-ch-names"; + int num_ch; + int i; + const char *name; + + num_ch = of_property_count_strings(np, propname); + if (num_ch < 0) { + pr_err("wrong format of predefined channels definition [%d].\n", + num_ch); + return num_ch; + } + if (num_ch > ARRAY_SIZE(spcom_dev->predefined_ch_name)) { + pr_err("too many predefined channels [%d].\n", num_ch); + return -EINVAL; + } + + pr_debug("num of predefined channels [%d].\n", num_ch); + for (i = 0; i < num_ch; i++) { + ret = of_property_read_string_index(np, propname, i, &name); + if (ret) { + pr_err("failed to read DT channel [%d] name .\n", i); + return -EFAULT; + } + strlcpy(spcom_dev->predefined_ch_name[i], + name, + sizeof(spcom_dev->predefined_ch_name[i])); + + pr_debug("found ch [%s].\n", name); + } + + return num_ch; +} + +/* + * the function is running on system workqueue context, + * processes delayed (by rpmsg rx callback) packets: + * each paket belong to its destination spcom channel ch + */ +static void spcom_signal_rx_done(struct work_struct *ignored) +{ + struct spcom_channel *ch; + struct rx_buff_list *rx_item; + unsigned long flags; + + spin_lock_irqsave(&spcom_dev->rx_lock, flags); + while (!list_empty(&spcom_dev->rx_list_head)) { + /* detach last entry */ + rx_item = list_last_entry(&spcom_dev->rx_list_head, + struct rx_buff_list, list); + list_del(&rx_item->list); + spin_unlock_irqrestore(&spcom_dev->rx_lock, flags); + + if (!rx_item) { + pr_err("empty entry in pending rx list\n"); + spin_lock_irqsave(&spcom_dev->rx_lock, flags); + continue; + } + ch = rx_item->ch; + mutex_lock(&ch->lock); + if (ch->rpmsg_abort) { + if (ch->rpmsg_rx_buf) { + pr_debug("ch [%s] rx aborted free %d bytes\n", + ch->actual_rx_size); + kfree(ch->rpmsg_rx_buf); + ch->actual_rx_size = 0; + } + goto rx_aborted; + } + if (ch->rpmsg_rx_buf) { + pr_err("ch [%s] previous buffer not consumed %d bytes\n", + ch->name, ch->actual_rx_size); + goto rx_aborted; + } + ch->rpmsg_rx_buf = rx_item->rpmsg_rx_buf; + ch->actual_rx_size = rx_item->rx_buf_size; + complete_all(&ch->rx_done); + mutex_unlock(&ch->lock); + + kfree(rx_item); + + /* lock for the next list entry */ + spin_lock_irqsave(&spcom_dev->rx_lock, flags); + } + spin_unlock_irqrestore(&spcom_dev->rx_lock, flags); + return; +rx_aborted: + mutex_unlock(&ch->lock); + kfree(rx_item->rpmsg_rx_buf); + kfree(rx_item); +} + +static int spcom_rpdev_cb(struct rpmsg_device *rpdev, + void *data, int len, void *priv, u32 src) +{ + struct spcom_channel *ch; + static DECLARE_WORK(rpmsg_rx_consumer, spcom_signal_rx_done); + struct rx_buff_list *rx_item; + unsigned long flags; + + if (!rpdev || !data) { + pr_err("rpdev or data is NULL\n"); + return -EINVAL; + } + pr_debug("incoming msg from %s\n", rpdev->id.name); + ch = dev_get_drvdata(&rpdev->dev); + if (!ch) { + pr_err("%s: invalid ch\n"); + return -EINVAL; + } + if (len > SPCOM_RX_BUF_SIZE || len <= 0) { + pr_err("got msg size %d, max allowed %d\n", + len, SPCOM_RX_BUF_SIZE); + return -EINVAL; + } + + rx_item = kzalloc(sizeof(*rx_item), GFP_ATOMIC); + if (!rx_item) + return -ENOMEM; + + rx_item->rpmsg_rx_buf = kzalloc(len, GFP_ATOMIC); + if (!rx_item->rpmsg_rx_buf) { + kfree(rx_item); + return -ENOMEM; + } + memcpy(rx_item->rpmsg_rx_buf, data, len); + rx_item->rx_buf_size = len; + rx_item->ch = ch; + + spin_lock_irqsave(&spcom_dev->rx_lock, flags); + list_add(&rx_item->list, &spcom_dev->rx_list_head); + spin_unlock_irqrestore(&spcom_dev->rx_lock, flags); + pr_err("signaling rx item for %s, received %d bytes\n", + rpdev->id.name, len); + + schedule_work(&rpmsg_rx_consumer); + return 0; +} + +static int spcom_rpdev_probe(struct rpmsg_device *rpdev) +{ + const char *name; + struct spcom_channel *ch; + + if (!rpdev) { + pr_err("rpdev is NULL\n"); + return -EINVAL; + } + name = rpdev->id.name; + pr_debug("new channel %s rpmsg_device arrived\n", name); + ch = spcom_find_channel_by_name(name); + if (!ch) { + pr_err("channel %s not found\n", name); + return -ENODEV; + } + mutex_lock(&ch->lock); + ch->rpdev = rpdev; + ch->rpmsg_abort = false; + complete_all(&ch->connect); + mutex_unlock(&ch->lock); + + dev_set_drvdata(&rpdev->dev, ch); + + /* used to evaluate underlying transport link up/down */ + atomic_inc(&spcom_dev->rpmsg_dev_count); + if (atomic_read(&spcom_dev->rpmsg_dev_count) == 1) + complete_all(&spcom_dev->rpmsg_state_change); + + return 0; +} + +static void spcom_rpdev_remove(struct rpmsg_device *rpdev) +{ + struct spcom_channel *ch; + + if (!rpdev) { + pr_err("rpdev is NULL\n"); + return; + } + + ch = dev_get_drvdata(&rpdev->dev); + if (!ch) { + pr_err("channel %s not found\n", rpdev->id.name); + return; + } + mutex_lock(&ch->lock); + ch->rpdev = NULL; + ch->rpmsg_abort = true; + complete_all(&ch->rx_done); + mutex_unlock(&ch->lock); + + /* used to evaluate underlying transport link up/down */ + if (atomic_dec_and_test(&spcom_dev->rpmsg_dev_count)) + complete_all(&spcom_dev->rpmsg_state_change); + + dev_info(&rpdev->dev, "rpmsg device %s removed\n", rpdev->id.name); +} + +/* + * register rpmsg driver to match with channel ch_name + * function shold be called under ch->lock + */ +static int spcom_register_rpmsg_drv(struct spcom_channel *ch) +{ + struct rpmsg_driver *rpdrv; + struct rpmsg_device_id *match; + char *drv_name; + int ret; + + if (ch->rpdrv) { + pr_err("ch:%s, rpmsg driver %s already registered\n", ch->name, + ch->rpdrv->id_table->name); + return -ENODEV; + } + + rpdrv = kzalloc(sizeof(*rpdrv), GFP_KERNEL); + if (!rpdrv) + return -ENOMEM; + + /* zalloc array of two to NULL terminate the match list */ + match = kzalloc(2 * sizeof(*match), GFP_KERNEL); + if (!match) { + kfree(rpdrv); + return -ENOMEM; + } + snprintf(match->name, RPMSG_NAME_SIZE, "%s", ch->name); + + drv_name = kasprintf(GFP_KERNEL, "%s_%s", "spcom_rpmsg_drv", ch->name); + if (!drv_name) { + pr_err("can't allocate drv_name for %s\n", ch->name); + kfree(rpdrv); + kfree(match); + return -ENOMEM; + } + + rpdrv->probe = spcom_rpdev_probe; + rpdrv->remove = spcom_rpdev_remove; + rpdrv->callback = spcom_rpdev_cb; + rpdrv->id_table = match; + rpdrv->drv.name = drv_name; + ret = register_rpmsg_driver(rpdrv); + if (ret) { + pr_err("can't register rpmsg_driver for %s\n", ch->name); + kfree(rpdrv); + kfree(match); + kfree(drv_name); + return ret; + } + // the function caller should mutex_lock(&ch->lock) + ch->rpdrv = rpdrv; + ch->rpmsg_abort = false; + + return 0; +} + +/* function shold be called under ch->lock */ +static int spcom_unregister_rpmsg_drv(struct spcom_channel *ch) +{ + if (!ch->rpdrv) + return -ENODEV; + unregister_rpmsg_driver(ch->rpdrv); + + kfree(ch->rpdrv->drv.name); + kfree((void *)ch->rpdrv->id_table); + kfree(ch->rpdrv); + ch->rpdrv = NULL; + ch->rpmsg_abort = true; /* will unblock spcom_rx() */ + return 0; +} + +static int spcom_probe(struct platform_device *pdev) +{ + int ret; + struct spcom_device *dev = NULL; + struct device_node *np; + + if (!pdev) { + pr_err("invalid pdev.\n"); + return -ENODEV; + } + + np = pdev->dev.of_node; + if (!np) { + pr_err("invalid DT node.\n"); + return -EINVAL; + } + + dev = kzalloc(sizeof(*dev), GFP_KERNEL); + if (dev == NULL) + return -ENOMEM; + + spcom_dev = dev; + spcom_dev->pdev = pdev; + /* start counting exposed channel char devices from 1 */ + atomic_set(&spcom_dev->chdev_count, 1); + init_completion(&spcom_dev->rpmsg_state_change); + atomic_set(&spcom_dev->rpmsg_dev_count, 0); + + INIT_LIST_HEAD(&spcom_dev->rx_list_head); + spin_lock_init(&spcom_dev->rx_lock); + + ret = spcom_register_chardev(); + if (ret) { + pr_err("create character device failed.\n"); + goto fail_reg_chardev; + } + + ret = spcom_parse_dt(np); + if (ret < 0) + goto fail_reg_chardev; + + ret = spcom_create_predefined_channels_chardev(); + if (ret < 0) { + pr_err("create character device failed.\n"); + goto fail_reg_chardev; + } + pr_debug("Driver Initialization ok.\n"); + return 0; + +fail_reg_chardev: + pr_err("failed to init driver\n"); + spcom_unregister_chrdev(); + kfree(dev); + spcom_dev = NULL; + + return -ENODEV; +} + +static const struct of_device_id spcom_match_table[] = { + { .compatible = "qcom,spcom", }, + { }, +}; + +static struct platform_driver spcom_driver = { + .probe = spcom_probe, + .driver = { + .name = DEVICE_NAME, + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(spcom_match_table), + }, +}; + +static int __init spcom_init(void) +{ + int ret; + + pr_debug("spcom driver version 2.0 4-Mar-2018\n"); + + ret = platform_driver_register(&spcom_driver); + if (ret) + pr_err("spcom_driver register failed %d\n", ret); + + return ret; +} +module_init(spcom_init); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("Secure Processor Communication"); diff --git a/include/uapi/linux/spcom.h b/include/uapi/linux/spcom.h new file mode 100644 index 000000000000..22c6e6224540 --- /dev/null +++ b/include/uapi/linux/spcom.h @@ -0,0 +1,119 @@ +/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _UAPI_SPCOM_H_ +#define _UAPI_SPCOM_H_ + +#include /* uint32_t, bool */ +#ifndef BIT + #define BIT(x) (1 << x) +#endif + +#ifndef PAGE_SIZE + #define PAGE_SIZE 4096 +#endif + +/** + * @brief - Secure Processor Communication interface to user space spcomlib. + * + * Sending data and control commands by write() file operation. + * Receiving data by read() file operation. + * Getting the next request size by read() file operation, + * with special size SPCOM_GET_NEXT_REQUEST_SIZE. + */ + +/* + * Maximum number of channel between Secure Processor and HLOS. + * including predefined channels, like "sp_kernel". + */ +#define SPCOM_MAX_CHANNELS 0x20 + +/* Maximum size (including null) for channel names */ +#define SPCOM_CHANNEL_NAME_SIZE 32 +/* + * file read(fd, buf, size) with this size, + * hints the kernel that user space wants to read the next-req-size. + * This size is bigger than both SPCOM_MAX_REQUEST_SIZE and + * SPCOM_MAX_RESPONSE_SIZE , so it is not a valid data size. + */ +#define SPCOM_GET_NEXT_REQUEST_SIZE (PAGE_SIZE-1) + +/* Command Id between spcomlib and spcom driver, on write() */ +enum spcom_cmd_id { + SPCOM_CMD_LOAD_APP = 0x4C4F4144, /* "LOAD" = 0x4C4F4144 */ + SPCOM_CMD_RESET_SP = 0x52455354, /* "REST" = 0x52455354 */ + SPCOM_CMD_SEND = 0x53454E44, /* "SEND" = 0x53454E44 */ + SPCOM_CMD_SEND_MODIFIED = 0x534E444D, /* "SNDM" = 0x534E444D */ + SPCOM_CMD_LOCK_ION_BUF = 0x4C4F434B, /* "LOCK" = 0x4C4F434B */ + SPCOM_CMD_UNLOCK_ION_BUF = 0x554C434B, /* "ULCK" = 0x4C4F434B */ + SPCOM_CMD_FSSR = 0x46535352, /* "FSSR" = 0x46535352 */ + SPCOM_CMD_CREATE_CHANNEL = 0x43524554, /* "CRET" = 0x43524554 */ +}; + +/* + * @note: Event types that are always implicitly polled: + * POLLERR=0x08 | POLLHUP=0x10 | POLLNVAL=0x20 + * so bits 3,4,5 can't be used + */ +enum spcom_poll_events { + SPCOM_POLL_LINK_STATE = BIT(1), + SPCOM_POLL_CH_CONNECT = BIT(2), + SPCOM_POLL_READY_FLAG = BIT(14), /* output */ + SPCOM_POLL_WAIT_FLAG = BIT(15), /* if set , wait for the event */ +}; + +/* Common Command structure between User Space and spcom driver, on write() */ +struct spcom_user_command { + enum spcom_cmd_id cmd_id; + uint32_t arg; +} __packed; + +/* Command structure between User Space and spcom driver, on write() */ +struct spcom_send_command { + enum spcom_cmd_id cmd_id; + uint32_t timeout_msec; + uint32_t buf_size; + char buf[0]; /* Variable buffer size - must be last field */ +} __packed; + +/* Command structure between userspace spcomlib and spcom driver, on write() */ +struct spcom_user_create_channel_command { + enum spcom_cmd_id cmd_id; + char ch_name[SPCOM_CHANNEL_NAME_SIZE]; +} __packed; + +/* maximum ION buf for send-modfied-command */ +#define SPCOM_MAX_ION_BUF 4 + +struct spcom_ion_info { + int32_t fd; /* ION buffer File Descriptor, set -1 for invalid fd */ + uint32_t buf_offset; /* virtual address offset in request/response */ +}; + +/* Pass this FD to unlock all ION buffer for the specific channel */ +#define SPCOM_ION_FD_UNLOCK_ALL 0xFFFF + +struct spcom_ion_handle { + int32_t fd; /* File Descriptor associated with the buffer */ +}; + +/* Command structure between User Space and spcom driver, on write() */ +struct spcom_user_send_modified_command { + enum spcom_cmd_id cmd_id; + struct spcom_ion_info ion_info[SPCOM_MAX_ION_BUF]; + uint32_t timeout_msec; + uint32_t buf_size; + char buf[0]; /* Variable buffer size - must be last field */ +} __packed; + + +#endif /* _UAPI_SPCOM_H_ */ -- GitLab From 890fc711e0b2284149a38c15d8518ee1df86afd2 Mon Sep 17 00:00:00 2001 From: Hemant Gupta Date: Sat, 7 Apr 2018 12:08:32 +0530 Subject: [PATCH 0441/1635] HID: uhid: remove custom locking from uhid_hid_open/close Now that HID core enforces serialization of transport driver open/close calls we can remove custom locking from uhid driver. CRs-Fixed: 2218607 Change-Id: I87e2077a5357744d8aa88b9d9c8103ba6acbedca Signed-off-by: Hemant Gupta --- drivers/hid/uhid.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/hid/uhid.c b/drivers/hid/uhid.c index a4e5ea19e997..d9ecdfefaaa8 100644 --- a/drivers/hid/uhid.c +++ b/drivers/hid/uhid.c @@ -144,13 +144,11 @@ static int uhid_hid_open(struct hid_device *hid) struct uhid_device *uhid = hid->driver_data; int retval = 0; - mutex_lock(&hid->ll_open_lock); if (!hid->ll_open_count++) { retval = uhid_queue_event(uhid, UHID_OPEN); if (retval) hid->ll_open_count--; } - mutex_unlock(&hid->ll_open_lock); return retval; } @@ -158,10 +156,8 @@ static void uhid_hid_close(struct hid_device *hid) { struct uhid_device *uhid = hid->driver_data; - mutex_lock(&hid->ll_open_lock); if (!--hid->ll_open_count) uhid_queue_event(uhid, UHID_CLOSE); - mutex_unlock(&hid->ll_open_lock); } static int uhid_hid_parse(struct hid_device *hid) -- GitLab From c96b88f9a1cf7e548bb0fd4949ed54c76004d8bb Mon Sep 17 00:00:00 2001 From: Tyler Wear Date: Wed, 4 Apr 2018 13:52:26 -0700 Subject: [PATCH 0442/1635] arch: arm64: defconfig: Enable QTAGUID for SM8150 Enable netfilter QTAGUID needed for sm8150. Change-Id: I21365c172feb3226a1b3abc6066a8643fa8401d9 CRs-fixed: 2218604 Signed-off-by: Tyler Wear --- arch/arm64/configs/sm8150-perf_defconfig | 1 + arch/arm64/configs/sm8150_defconfig | 1 + 2 files changed, 2 insertions(+) diff --git a/arch/arm64/configs/sm8150-perf_defconfig b/arch/arm64/configs/sm8150-perf_defconfig index 7c9a5e1913e1..b0fd13f12960 100644 --- a/arch/arm64/configs/sm8150-perf_defconfig +++ b/arch/arm64/configs/sm8150-perf_defconfig @@ -158,6 +158,7 @@ CONFIG_NETFILTER_XT_MATCH_MARK=y CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y CONFIG_NETFILTER_XT_MATCH_POLICY=y CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y +CONFIG_NETFILTER_XT_MATCH_QTAGUID=y CONFIG_NETFILTER_XT_MATCH_QUOTA=y CONFIG_NETFILTER_XT_MATCH_QUOTA2=y CONFIG_NETFILTER_XT_MATCH_SOCKET=y diff --git a/arch/arm64/configs/sm8150_defconfig b/arch/arm64/configs/sm8150_defconfig index a35eaa59a543..efef34b4b440 100644 --- a/arch/arm64/configs/sm8150_defconfig +++ b/arch/arm64/configs/sm8150_defconfig @@ -162,6 +162,7 @@ CONFIG_NETFILTER_XT_MATCH_MARK=y CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y CONFIG_NETFILTER_XT_MATCH_POLICY=y CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y +CONFIG_NETFILTER_XT_MATCH_QTAGUID=y CONFIG_NETFILTER_XT_MATCH_QUOTA=y CONFIG_NETFILTER_XT_MATCH_QUOTA2=y CONFIG_NETFILTER_XT_MATCH_SOCKET=y -- GitLab From 391a598903f931b2d6d0fd598ddef271b2d615da Mon Sep 17 00:00:00 2001 From: Lingutla Chandrasekhar Date: Mon, 25 Sep 2017 19:07:12 +0530 Subject: [PATCH 0443/1635] soc: qcom: Register default dump entries to minidump table Add below common dump entries to minidump table: All memory dump table entries, kernel data/bss sections, percpu static sections, rtb, logbuf, wdogdata, lpm_debug, stackpointer, and current task struct. Also add name for memory dump table entries to accommodate Minidump support. Change-Id: I45d121bc36b40332cfd0a0f5142572c6ce8f8a26 Signed-off-by: Lingutla Chandrasekhar [isaacm@codeaurora.org: Resolve trivial merge conflicts] Signed-off-by: Isaac J. Manjarres --- arch/arm64/kernel/smp.c | 2 + drivers/cpuidle/lpm-levels.c | 10 +++ drivers/soc/qcom/Makefile | 2 +- drivers/soc/qcom/cpuss_dump.c | 4 +- drivers/soc/qcom/memory_dump_v2.c | 35 ++++++++ drivers/soc/qcom/minidump_log.c | 144 ++++++++++++++++++++++++++++++ drivers/soc/qcom/watchdog_v2.c | 15 ++++ kernel/panic.c | 2 + kernel/trace/msm_rtb.c | 10 ++- 9 files changed, 221 insertions(+), 3 deletions(-) create mode 100644 drivers/soc/qcom/minidump_log.c diff --git a/arch/arm64/kernel/smp.c b/arch/arm64/kernel/smp.c index 0fdbecd8fd11..6fa2337b78b2 100644 --- a/arch/arm64/kernel/smp.c +++ b/arch/arm64/kernel/smp.c @@ -58,6 +58,7 @@ #include #include #include +#include #define CREATE_TRACE_POINTS #include @@ -857,6 +858,7 @@ static void ipi_cpu_stop(unsigned int cpu, struct pt_regs *regs) pr_crit("CPU%u: stopping\n", cpu); __show_regs(regs); dump_stack(); + dump_stack_minidump(regs->sp); raw_spin_unlock(&stop_lock); } diff --git a/drivers/cpuidle/lpm-levels.c b/drivers/cpuidle/lpm-levels.c index 116b1a9e5eea..de4a1f4811d6 100644 --- a/drivers/cpuidle/lpm-levels.c +++ b/drivers/cpuidle/lpm-levels.c @@ -40,6 +40,7 @@ #include #include #include +#include #include #include #include @@ -1621,6 +1622,7 @@ static int lpm_probe(struct platform_device *pdev) int ret; int size; struct kobject *module_kobj = NULL; + struct md_region md_entry; get_online_cpus(); lpm_root_node = lpm_of_parse_cluster(pdev); @@ -1677,6 +1679,14 @@ static int lpm_probe(struct platform_device *pdev) goto failed; } + /* Add lpm_debug to Minidump*/ + strlcpy(md_entry.name, "KLPMDEBUG", sizeof(md_entry.name)); + md_entry.virt_addr = (uintptr_t)lpm_debug; + md_entry.phys_addr = lpm_debug_phys; + md_entry.size = size; + if (msm_minidump_add_region(&md_entry)) + pr_info("Failed to add lpm_debug in Minidump\n"); + return 0; failed: free_cluster_node(lpm_root_node); diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile index 7b6a2d6bcec5..69cbd5b00a2c 100644 --- a/drivers/soc/qcom/Makefile +++ b/drivers/soc/qcom/Makefile @@ -28,7 +28,7 @@ obj-$(CONFIG_MSM_CORE_HANG_DETECT) += core_hang_detect.o obj-$(CONFIG_QCOM_DCC_V2) += dcc_v2.o obj-$(CONFIG_MSM_GLADIATOR_HANG_DETECT) += gladiator_hang_detect.o obj-$(CONFIG_MSM_GLADIATOR_ERP) += gladiator_erp.o -obj-$(CONFIG_QCOM_MINIDUMP) += msm_minidump.o +obj-$(CONFIG_QCOM_MINIDUMP) += msm_minidump.o minidump_log.o obj-$(CONFIG_QCOM_SECURE_BUFFER) += secure_buffer.o obj-$(CONFIG_QCOM_MEMORY_DUMP_V2) += memory_dump_v2.o obj-$(CONFIG_QCOM_WATCHDOG_V2) += watchdog_v2.o diff --git a/drivers/soc/qcom/cpuss_dump.c b/drivers/soc/qcom/cpuss_dump.c index 886a32fcf131..eba11283bea3 100644 --- a/drivers/soc/qcom/cpuss_dump.c +++ b/drivers/soc/qcom/cpuss_dump.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -74,6 +74,8 @@ static int cpuss_dump_probe(struct platform_device *pdev) dump_data->addr = dump_addr; dump_data->len = size; + scnprintf(dump_data->name, sizeof(dump_data->name), + "KCPUSS%X", id); dump_entry.id = id; dump_entry.addr = virt_to_phys(dump_data); ret = msm_dump_data_register(MSM_DUMP_TABLE_APPS, &dump_entry); diff --git a/drivers/soc/qcom/memory_dump_v2.c b/drivers/soc/qcom/memory_dump_v2.c index 5ed66bf02177..b0b9415d672c 100644 --- a/drivers/soc/qcom/memory_dump_v2.c +++ b/drivers/soc/qcom/memory_dump_v2.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -89,6 +90,33 @@ static struct msm_dump_table *msm_dump_get_table(enum msm_dump_table_ids id) return table; } +static int msm_dump_data_add_minidump(struct msm_dump_entry *entry) +{ + struct msm_dump_data *data; + struct md_region md_entry; + + data = (struct msm_dump_data *)(phys_to_virt(entry->addr)); + + if (!data->addr || !data->len) + return -EINVAL; + + if (!strcmp(data->name, "")) { + pr_debug("Entry name is NULL, Use ID %d for minidump\n", + entry->id); + snprintf(md_entry.name, sizeof(md_entry.name), "KMDT0x%X", + entry->id); + } else { + strlcpy(md_entry.name, data->name, sizeof(md_entry.name)); + } + + md_entry.phys_addr = data->addr; + md_entry.virt_addr = (uintptr_t)phys_to_virt(data->addr); + md_entry.size = data->len; + md_entry.id = entry->id; + + return msm_minidump_add_region(&md_entry); +} + int msm_dump_data_register(enum msm_dump_table_ids id, struct msm_dump_entry *entry) { @@ -109,6 +137,10 @@ int msm_dump_data_register(enum msm_dump_table_ids id, table->num_entries++; dmac_flush_range(table, (void *)table + sizeof(struct msm_dump_table)); + + if (msm_dump_data_add_minidump(entry)) + pr_err("Failed to add entry in Minidump table\n"); + return 0; } EXPORT_SYMBOL(msm_dump_data_register); @@ -245,6 +277,9 @@ static int mem_dump_probe(struct platform_device *pdev) dump_data->addr = dump_addr; dump_data->len = size; + strlcpy(dump_data->name, child_node->name, + strlen(child_node->name) + 1); + dump_entry.id = id; dump_entry.addr = virt_to_phys(dump_data); ret = msm_dump_data_register(MSM_DUMP_TABLE_APPS, &dump_entry); diff --git a/drivers/soc/qcom/minidump_log.c b/drivers/soc/qcom/minidump_log.c new file mode 100644 index 000000000000..7b177cc022de --- /dev/null +++ b/drivers/soc/qcom/minidump_log.c @@ -0,0 +1,144 @@ +/* Copyright (c) 2017, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static void __init register_log_buf(void) +{ + char **log_bufp; + uint32_t *log_buf_lenp; + struct md_region md_entry; + + log_bufp = (char **)kallsyms_lookup_name("log_buf"); + log_buf_lenp = (uint32_t *)kallsyms_lookup_name("log_buf_len"); + if (!log_bufp || !log_buf_lenp) { + pr_err("Unable to find log_buf by kallsyms!\n"); + return; + } + /*Register logbuf to minidump, first idx would be from bss section */ + strlcpy(md_entry.name, "KLOGBUF", sizeof(md_entry.name)); + md_entry.virt_addr = (uintptr_t) (*log_bufp); + md_entry.phys_addr = virt_to_phys(*log_bufp); + md_entry.size = *log_buf_lenp; + if (msm_minidump_add_region(&md_entry)) + pr_err("Failed to add logbuf in Minidump\n"); +} + +static void register_stack_entry(struct md_region *ksp_entry, u64 sp, u64 size, + u32 cpu) +{ + struct page *sp_page = vmalloc_to_page((const void *) sp); + struct vm_struct *stack_vm_area = task_stack_vm_area(current); + + ksp_entry->virt_addr = sp; + ksp_entry->size = size; + if (stack_vm_area) { + sp_page = vmalloc_to_page((const void *) sp); + ksp_entry->phys_addr = page_to_phys(sp_page); + } else { + ksp_entry->phys_addr = virt_to_phys((uintptr_t *)sp); + } + + if (msm_minidump_add_region(ksp_entry)) + pr_err("Failed to add stack of cpu %d in Minidump\n", cpu); +} + +static void __init register_kernel_sections(void) +{ + struct md_region ksec_entry; + char *data_name = "KDATABSS"; + const size_t static_size = __per_cpu_end - __per_cpu_start; + void __percpu *base = (void __percpu *)__per_cpu_start; + unsigned int cpu; + + strlcpy(ksec_entry.name, data_name, sizeof(ksec_entry.name)); + ksec_entry.virt_addr = (uintptr_t)_sdata; + ksec_entry.phys_addr = virt_to_phys(_sdata); + ksec_entry.size = roundup((__bss_stop - _sdata), 4); + if (msm_minidump_add_region(&ksec_entry)) + pr_err("Failed to add data section in Minidump\n"); + + /* Add percpu static sections */ + for_each_possible_cpu(cpu) { + void *start = per_cpu_ptr(base, cpu); + + memset(&ksec_entry, 0, sizeof(ksec_entry)); + scnprintf(ksec_entry.name, sizeof(ksec_entry.name), + "KSPERCPU%d", cpu); + ksec_entry.virt_addr = (uintptr_t)start; + ksec_entry.phys_addr = per_cpu_ptr_to_phys(start); + ksec_entry.size = static_size; + if (msm_minidump_add_region(&ksec_entry)) + pr_err("Failed to add percpu sections in Minidump\n"); + } +} + +void dump_stack_minidump(u64 sp) +{ + struct md_region ksp_entry, ktsk_entry; + u32 cpu = smp_processor_id(); + struct vm_struct *stack_vm_area; + unsigned int stack_pages, i, copy_pages; + u64 base_addr; + + /* + * Since stacks are now allocated with vmalloc, the translation to + * physical address is not a simple linear transformation like it is + * for kernel logical addresses, since vmalloc creates a virtual + * mapping. Thus, virt_to_phys() should not be used in this context; + * instead the page table must be walked to acquire the physical + * address of one page of the stack. + */ + stack_vm_area = task_stack_vm_area(current); + if (stack_vm_area) { + sp = PAGE_ALIGN(sp); + scnprintf(ksp_entry.name, sizeof(ksp_entry.name), "KSTACK%d", + cpu); + base_addr = (u64) stack_vm_area->addr; + stack_pages = get_vm_area_size(stack_vm_area) >> PAGE_SHIFT; + copy_pages = stack_pages - ((sp - base_addr) / PAGE_SIZE); + for (i = 0; i < copy_pages; i++) { + register_stack_entry(&ksp_entry, sp, PAGE_SIZE, cpu); + sp += PAGE_SIZE; + } + } else { + sp &= (THREAD_SIZE - 1); + scnprintf(ksp_entry.name, sizeof(ksp_entry.name), "KSTACK%d", + cpu); + register_stack_entry(&ksp_entry, sp, THREAD_SIZE, cpu); + } + + scnprintf(ktsk_entry.name, sizeof(ktsk_entry.name), "KTASK%d", cpu); + ktsk_entry.virt_addr = (u64)current; + ktsk_entry.phys_addr = virt_to_phys((uintptr_t *)current); + ktsk_entry.size = sizeof(struct task_struct); + if (msm_minidump_add_region(&ktsk_entry)) + pr_err("Failed to add current task %d in Minidump\n", cpu); +} + +static int __init msm_minidump_log_init(void) +{ + register_kernel_sections(); + register_log_buf(); + return 0; +} +late_initcall(msm_minidump_log_init); diff --git a/drivers/soc/qcom/watchdog_v2.c b/drivers/soc/qcom/watchdog_v2.c index cae57fb53128..01e99873ae3c 100644 --- a/drivers/soc/qcom/watchdog_v2.c +++ b/drivers/soc/qcom/watchdog_v2.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -556,6 +557,8 @@ static void configure_bark_dump(struct msm_watchdog_data *wdog_dd) cpu_data[cpu].addr = virt_to_phys(cpu_buf + cpu * MAX_CPU_CTX_SIZE); cpu_data[cpu].len = MAX_CPU_CTX_SIZE; + snprintf(cpu_data[cpu].name, sizeof(cpu_data[cpu].name), + "KCPU_CTX%d", cpu); dump_entry.id = MSM_DUMP_DATA_CPU_CTX + cpu; dump_entry.addr = virt_to_phys(&cpu_data[cpu]); ret = msm_dump_data_register(MSM_DUMP_TABLE_APPS, @@ -603,6 +606,8 @@ static void configure_scandump(struct msm_watchdog_data *wdog_dd) cpu_data->addr = dump_addr; cpu_data->len = MAX_CPU_SCANDUMP_SIZE; + snprintf(cpu_data->name, sizeof(cpu_data->name), + "KSCANDUMP%d", cpu); dump_entry.id = MSM_DUMP_DATA_SCANDUMP_PER_CPU + cpu; dump_entry.addr = virt_to_phys(cpu_data); ret = msm_dump_data_register(MSM_DUMP_TABLE_APPS, @@ -806,6 +811,7 @@ static int msm_watchdog_probe(struct platform_device *pdev) { int ret; struct msm_watchdog_data *wdog_dd; + struct md_region md_entry; if (!pdev->dev.of_node || !enable) return -ENODEV; @@ -827,6 +833,15 @@ static int msm_watchdog_probe(struct platform_device *pdev) goto err; } init_watchdog_data(wdog_dd); + + /* Add wdog info to minidump table */ + strlcpy(md_entry.name, "KWDOGDATA", sizeof(md_entry.name)); + md_entry.virt_addr = (uintptr_t)wdog_dd; + md_entry.phys_addr = virt_to_phys(wdog_dd); + md_entry.size = sizeof(*wdog_dd); + if (msm_minidump_add_region(&md_entry)) + pr_info("Failed to add Watchdog data in Minidump\n"); + return 0; err: kzfree(wdog_dd); diff --git a/kernel/panic.c b/kernel/panic.c index 91c7b0429929..2676c1f5c2b4 100644 --- a/kernel/panic.c +++ b/kernel/panic.c @@ -29,6 +29,7 @@ #include #define CREATE_TRACE_POINTS #include +#include #define PANIC_TIMER_STEP 100 #define PANIC_BLINK_SPD 18 @@ -176,6 +177,7 @@ void panic(const char *fmt, ...) va_start(args, fmt); vsnprintf(buf, sizeof(buf), fmt, args); va_end(args); + dump_stack_minidump(0); pr_emerg("Kernel panic - not syncing: %s\n", buf); #ifdef CONFIG_DEBUG_BUGVERBOSE /* diff --git a/kernel/trace/msm_rtb.c b/kernel/trace/msm_rtb.c index e5fafee0a154..abfa9c95d1de 100644 --- a/kernel/trace/msm_rtb.c +++ b/kernel/trace/msm_rtb.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2016, The Linux Foundation. All rights reserved. + * Copyright (c) 2013-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -28,6 +28,7 @@ #include #include #include +#include #define SENTINEL_BYTE_1 0xFF #define SENTINEL_BYTE_2 0xAA @@ -242,6 +243,7 @@ EXPORT_SYMBOL(uncached_logk); static int msm_rtb_probe(struct platform_device *pdev) { struct msm_rtb_platform_data *d = pdev->dev.platform_data; + struct md_region md_entry; #if defined(CONFIG_QCOM_RTB_SEPARATE_CPUS) unsigned int cpu; #endif @@ -293,6 +295,12 @@ static int msm_rtb_probe(struct platform_device *pdev) memset(msm_rtb.rtb, 0, msm_rtb.size); + strlcpy(md_entry.name, "KRTB_BUF", sizeof(md_entry.name)); + md_entry.virt_addr = (uintptr_t)msm_rtb.rtb; + md_entry.phys_addr = msm_rtb.phys; + md_entry.size = msm_rtb.size; + if (msm_minidump_add_region(&md_entry)) + pr_info("Failed to add RTB in Minidump\n"); #if defined(CONFIG_QCOM_RTB_SEPARATE_CPUS) for_each_possible_cpu(cpu) { -- GitLab From f42416dabbd67edb1d3a98dc0b5e25bba2c9a225 Mon Sep 17 00:00:00 2001 From: Lingutla Chandrasekhar Date: Tue, 3 Oct 2017 18:05:07 +0530 Subject: [PATCH 0444/1635] power: reset: Support Minidump select option in dump type On system crash, some targets are able to collect Minidump, so add option to collect fulldump as well as minidump or both dumps. This is snapshot of minidump driver support in msm-4.4, 'commit f4beb492260b ("power: reset: msm: add support to select both dumps")' Change-Id: I090653097ba12abb4fc0a1ff44bf155cc0d7a3ed Signed-off-by: Lingutla Chandrasekhar Signed-off-by: Isaac J. Manjarres --- drivers/power/reset/msm-poweroff.c | 62 ++++++++++++++++++++++++++++-- 1 file changed, 59 insertions(+), 3 deletions(-) diff --git a/drivers/power/reset/msm-poweroff.c b/drivers/power/reset/msm-poweroff.c index 54d88019c764..7e4b447009cc 100644 --- a/drivers/power/reset/msm-poweroff.c +++ b/drivers/power/reset/msm-poweroff.c @@ -33,6 +33,7 @@ #include #include #include +#include #define EMERGENCY_DLOAD_MAGIC1 0x322A4F99 #define EMERGENCY_DLOAD_MAGIC2 0xC67E4350 @@ -42,10 +43,11 @@ #define SCM_IO_DISABLE_PMIC_ARBITER 1 #define SCM_IO_DEASSERT_PS_HOLD 2 #define SCM_WDOG_DEBUG_BOOT_PART 0x9 -#define SCM_DLOAD_MODE 0X10 +#define SCM_DLOAD_FULLDUMP 0X10 #define SCM_EDLOAD_MODE 0X01 #define SCM_DLOAD_CMD 0x10 - +#define SCM_DLOAD_MINIDUMP 0X20 +#define SCM_DLOAD_BOTHDUMPS (SCM_DLOAD_MINIDUMP | SCM_DLOAD_FULLDUMP) static int restart_mode; static void *restart_reason, *dload_type_addr; @@ -72,6 +74,7 @@ static struct kobject dload_kobj; #endif static int in_panic; +static int dload_type = SCM_DLOAD_FULLDUMP; static void *dload_mode_addr; static bool dload_mode_enabled; static void *emergency_dload_mode_addr; @@ -140,7 +143,7 @@ static void set_dload_mode(int on) mb(); } - ret = scm_set_dload_mode(on ? SCM_DLOAD_MODE : 0, 0); + ret = scm_set_dload_mode(on ? dload_type : 0, 0); if (ret) pr_err("Failed to set secure DLOAD mode: %d\n", ret); @@ -438,6 +441,9 @@ static ssize_t show_emmc_dload(struct kobject *kobj, struct attribute *attr, { uint32_t read_val, show_val; + if (!dload_type_addr) + return -ENODEV; + read_val = __raw_readl(dload_type_addr); if (read_val == EMMC_DLOAD_TYPE) show_val = 1; @@ -453,6 +459,9 @@ static size_t store_emmc_dload(struct kobject *kobj, struct attribute *attr, uint32_t enabled; int ret; + if (!dload_type_addr) + return -ENODEV; + ret = kstrtouint(buf, 0, &enabled); if (ret < 0) return ret; @@ -467,10 +476,57 @@ static size_t store_emmc_dload(struct kobject *kobj, struct attribute *attr, return count; } + +#ifdef CONFIG_QCOM_MINIDUMP +static DEFINE_MUTEX(tcsr_lock); + +static ssize_t show_dload_mode(struct kobject *kobj, struct attribute *attr, + char *buf) +{ + return scnprintf(buf, PAGE_SIZE, "DLOAD dump type: %s\n", + (dload_type == SCM_DLOAD_BOTHDUMPS) ? "both" : + ((dload_type == SCM_DLOAD_MINIDUMP) ? "mini" : "full")); +} + +static size_t store_dload_mode(struct kobject *kobj, struct attribute *attr, + const char *buf, size_t count) +{ + if (sysfs_streq(buf, "full")) { + dload_type = SCM_DLOAD_FULLDUMP; + } else if (sysfs_streq(buf, "mini")) { + if (!msm_minidump_enabled()) { + pr_err("Minidump is not enabled\n"); + return -ENODEV; + } + dload_type = SCM_DLOAD_MINIDUMP; + } else if (sysfs_streq(buf, "both")) { + if (!msm_minidump_enabled()) { + pr_err("Minidump not enabled, setting fulldump only\n"); + dload_type = SCM_DLOAD_FULLDUMP; + return count; + } + dload_type = SCM_DLOAD_BOTHDUMPS; + } else{ + pr_err("Invalid Dump setup request..\n"); + pr_err("Supported dumps:'full', 'mini', or 'both'\n"); + return -EINVAL; + } + + mutex_lock(&tcsr_lock); + /*Overwrite TCSR reg*/ + set_dload_mode(dload_type); + mutex_unlock(&tcsr_lock); + return count; +} +RESET_ATTR(dload_mode, 0644, show_dload_mode, store_dload_mode); +#endif RESET_ATTR(emmc_dload, 0644, show_emmc_dload, store_emmc_dload); static struct attribute *reset_attrs[] = { &reset_attr_emmc_dload.attr, +#ifdef CONFIG_QCOM_MINIDUMP + &reset_attr_dload_mode.attr, +#endif NULL }; -- GitLab From 6559dea8205e700d4bedbe08a92dcc21f28101d8 Mon Sep 17 00:00:00 2001 From: Pavankumar Kondeti Date: Tue, 9 Jan 2018 11:02:30 +0530 Subject: [PATCH 0445/1635] sched: Add trace point to track preemption disable callers Add trace point to track preemption disable callers to isolate issues unrelated to scheduler and improve debug turn around time. Change-Id: If9303b7165167e8f79cd339929daf4afc31a61c4 Signed-off-by: Pavankumar Kondeti Signed-off-by: Satya Durga Srinivasu Prabhala --- include/linux/sched/sysctl.h | 6 ++++++ include/trace/events/sched.h | 32 ++++++++++++++++++++++++++++++ kernel/sched/core.c | 38 +++++++++++++++++++++++++++++++++++- kernel/sysctl.c | 10 ++++++++++ 4 files changed, 85 insertions(+), 1 deletion(-) diff --git a/include/linux/sched/sysctl.h b/include/linux/sched/sysctl.h index cce67e296de6..64adf47564b2 100644 --- a/include/linux/sched/sysctl.h +++ b/include/linux/sched/sysctl.h @@ -48,6 +48,12 @@ walt_proc_update_handler(struct ctl_table *table, int write, #endif +#if defined(CONFIG_DEBUG_PREEMPT) || defined(CONFIG_PREEMPT_TRACER) || \ + defined(CONFIG_PREEMPTIRQ_EVENTS) +extern unsigned int sysctl_preemptoff_tracing_threshold_ns; + +#endif + enum sched_tunable_scaling { SCHED_TUNABLESCALING_NONE, SCHED_TUNABLESCALING_LOG, diff --git a/include/trace/events/sched.h b/include/trace/events/sched.h index 344917831444..d3000b83b024 100644 --- a/include/trace/events/sched.h +++ b/include/trace/events/sched.h @@ -1298,6 +1298,38 @@ TRACE_EVENT(sched_isolate, __entry->time, __entry->isolate) ); +TRACE_EVENT(sched_preempt_disable, + + TP_PROTO(u64 delta, bool irqs_disabled, + unsigned long caddr0, unsigned long caddr1, + unsigned long caddr2, unsigned long caddr3), + + TP_ARGS(delta, irqs_disabled, caddr0, caddr1, caddr2, caddr3), + + TP_STRUCT__entry( + __field(u64, delta) + __field(bool, irqs_disabled) + __field(void*, caddr0) + __field(void*, caddr1) + __field(void*, caddr2) + __field(void*, caddr3) + ), + + TP_fast_assign( + __entry->delta = delta; + __entry->irqs_disabled = irqs_disabled; + __entry->caddr0 = (void *)caddr0; + __entry->caddr1 = (void *)caddr1; + __entry->caddr2 = (void *)caddr2; + __entry->caddr3 = (void *)caddr3; + ), + + TP_printk("delta=%llu(ns) irqs_d=%d Callers:(%pf<-%pf<-%pf<-%pf)", + __entry->delta, __entry->irqs_disabled, + __entry->caddr0, __entry->caddr1, + __entry->caddr2, __entry->caddr3) +); + #include "walt.h" #endif /* CONFIG_SMP */ diff --git a/kernel/sched/core.c b/kernel/sched/core.c index 6d6fa62fa206..aeb385453823 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -88,6 +88,12 @@ int sysctl_sched_rt_runtime = 950000; /* CPUs with isolated domains */ cpumask_var_t cpu_isolated_map; +/* + * preemptoff stack tracing threshold in ns. + * default: 1ms + */ +unsigned int sysctl_preemptoff_tracing_threshold_ns = 1000000UL; + /* * __task_rq_lock - lock the rq @p resides on. */ @@ -3191,17 +3197,34 @@ u64 scheduler_tick_max_deferment(void) #if defined(CONFIG_PREEMPT) && (defined(CONFIG_DEBUG_PREEMPT) || \ defined(CONFIG_PREEMPT_TRACER)) + +struct preempt_store { + u64 ts; + unsigned long caddr[4]; + bool irqs_disabled; +}; + +DEFINE_PER_CPU(struct preempt_store, the_ps); /* * If the value passed in is equal to the current preempt count * then we just disabled preemption. Start timing the latency. */ static inline void preempt_latency_start(int val) { + struct preempt_store *ps = &per_cpu(the_ps, raw_smp_processor_id()); + if (preempt_count() == val) { unsigned long ip = get_lock_parent_ip(); #ifdef CONFIG_DEBUG_PREEMPT current->preempt_disable_ip = ip; #endif + ps->ts = sched_clock(); + ps->caddr[0] = CALLER_ADDR0; + ps->caddr[1] = CALLER_ADDR1; + ps->caddr[2] = CALLER_ADDR2; + ps->caddr[3] = CALLER_ADDR3; + ps->irqs_disabled = irqs_disabled(); + trace_preempt_off(CALLER_ADDR0, ip); } } @@ -3234,8 +3257,21 @@ NOKPROBE_SYMBOL(preempt_count_add); */ static inline void preempt_latency_stop(int val) { - if (preempt_count() == val) + if (preempt_count() == val) { + struct preempt_store *ps = &per_cpu(the_ps, + raw_smp_processor_id()); + u64 delta = sched_clock() - ps->ts; + + /* + * Trace preempt disable stack if preemption + * is disabled for more than the threshold. + */ + if (delta > sysctl_preemptoff_tracing_threshold_ns) + trace_sched_preempt_disable(delta, ps->irqs_disabled, + ps->caddr[0], ps->caddr[1], + ps->caddr[2], ps->caddr[3]); trace_preempt_on(CALLER_ADDR0, get_lock_parent_ip()); + } } void preempt_count_sub(int val) diff --git a/kernel/sysctl.c b/kernel/sysctl.c index d983df404112..01b211c406d2 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -310,6 +310,16 @@ static struct ctl_table kern_table[] = { .mode = 0644, .proc_handler = proc_dointvec, }, +#if defined(CONFIG_DEBUG_PREEMPT) || defined(CONFIG_PREEMPT_TRACER) || \ + defined(CONFIG_PREEMPTIRQ_EVENTS) + { + .procname = "preemptoff_tracing_threshold_ns", + .data = &sysctl_preemptoff_tracing_threshold_ns, + .maxlen = sizeof(unsigned int), + .mode = 0644, + .proc_handler = proc_dointvec, + }, +#endif #ifdef CONFIG_SCHED_WALT { .procname = "sched_cpu_high_irqload", -- GitLab From 86a695fbed7556839c5938e6fd7a8d37baf0431a Mon Sep 17 00:00:00 2001 From: Pavankumar Kondeti Date: Mon, 26 Mar 2018 16:59:43 +0530 Subject: [PATCH 0446/1635] trace/irq: Add trace point to track IRQs disable callers Add trace point to track IRQs disable callers to isolate issues unrelated to scheduler and improve debug turn around time. Change-Id: Ib1ef45d8bed1fc0e128b5ab2051f0c30e8c50ee7 Signed-off-by: Pavankumar Kondeti Signed-off-by: Satya Durga Srinivasu Prabhala --- include/linux/sched/sysctl.h | 1 + include/trace/events/preemptirq.h | 28 ++++++++++++++++++++ kernel/sysctl.c | 7 +++++ kernel/trace/trace_irqsoff.c | 44 +++++++++++++++++++++++++++++++ 4 files changed, 80 insertions(+) diff --git a/include/linux/sched/sysctl.h b/include/linux/sched/sysctl.h index 64adf47564b2..de569df2bfa8 100644 --- a/include/linux/sched/sysctl.h +++ b/include/linux/sched/sysctl.h @@ -51,6 +51,7 @@ walt_proc_update_handler(struct ctl_table *table, int write, #if defined(CONFIG_DEBUG_PREEMPT) || defined(CONFIG_PREEMPT_TRACER) || \ defined(CONFIG_PREEMPTIRQ_EVENTS) extern unsigned int sysctl_preemptoff_tracing_threshold_ns; +extern unsigned int sysctl_irqsoff_tracing_threshold_ns; #endif diff --git a/include/trace/events/preemptirq.h b/include/trace/events/preemptirq.h index 9c4eb33c5a1d..3c5118011a2c 100644 --- a/include/trace/events/preemptirq.h +++ b/include/trace/events/preemptirq.h @@ -52,6 +52,34 @@ DEFINE_EVENT(preemptirq_template, preempt_enable, TP_ARGS(ip, parent_ip)); #endif +TRACE_EVENT(irqs_disable, + + TP_PROTO(u64 delta, unsigned long caddr0, unsigned long caddr1, + unsigned long caddr2, unsigned long caddr3), + + TP_ARGS(delta, caddr0, caddr1, caddr2, caddr3), + + TP_STRUCT__entry( + __field(u64, delta) + __field(void*, caddr0) + __field(void*, caddr1) + __field(void*, caddr2) + __field(void*, caddr3) + ), + + TP_fast_assign( + __entry->delta = delta; + __entry->caddr0 = (void *)caddr0; + __entry->caddr1 = (void *)caddr1; + __entry->caddr2 = (void *)caddr2; + __entry->caddr3 = (void *)caddr3; + ), + + TP_printk("delta=%llu(ns) Callers:(%pf<-%pf<-%pf<-%pf)", __entry->delta, + __entry->caddr0, __entry->caddr1, + __entry->caddr2, __entry->caddr3) +); + #endif /* _TRACE_PREEMPTIRQ_H */ #include diff --git a/kernel/sysctl.c b/kernel/sysctl.c index 01b211c406d2..b5704bf594e1 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -319,6 +319,13 @@ static struct ctl_table kern_table[] = { .mode = 0644, .proc_handler = proc_dointvec, }, + { + .procname = "irqsoff_tracing_threshold_ns", + .data = &sysctl_irqsoff_tracing_threshold_ns, + .maxlen = sizeof(unsigned int), + .mode = 0644, + .proc_handler = proc_dointvec, + }, #endif #ifdef CONFIG_SCHED_WALT { diff --git a/kernel/trace/trace_irqsoff.c b/kernel/trace/trace_irqsoff.c index 03ecb4465ee4..85b14eb4c0a6 100644 --- a/kernel/trace/trace_irqsoff.c +++ b/kernel/trace/trace_irqsoff.c @@ -13,6 +13,8 @@ #include #include #include +#include +#include #include "trace.h" @@ -39,6 +41,12 @@ static int save_flags; static void stop_irqsoff_tracer(struct trace_array *tr, int graph); static int start_irqsoff_tracer(struct trace_array *tr, int graph); +/* + * irqsoff stack tracing threshold in ns. + * default: 1ms + */ +unsigned int sysctl_irqsoff_tracing_threshold_ns = 1000000UL; + #ifdef CONFIG_PREEMPT_TRACER static inline int preempt_trace(void) @@ -466,17 +474,53 @@ void time_hardirqs_off(unsigned long a0, unsigned long a1) #else /* !CONFIG_PROVE_LOCKING */ +#ifdef CONFIG_PREEMPTIRQ_EVENTS +struct irqsoff_store { + u64 ts; + unsigned long caddr[4]; +}; + +DEFINE_PER_CPU(struct irqsoff_store, the_irqsoff); +#endif /* CONFIG_PREEMPTIRQ_EVENTS */ + /* * We are only interested in hardirq on/off events: */ static inline void tracer_hardirqs_on(void) { +#ifdef CONFIG_PREEMPTIRQ_EVENTS + struct irqsoff_store *is = &per_cpu(the_irqsoff, + raw_smp_processor_id()); + + if (!is->ts) { + is->ts = sched_clock(); + is->caddr[0] = CALLER_ADDR0; + is->caddr[1] = CALLER_ADDR1; + is->caddr[2] = CALLER_ADDR2; + is->caddr[3] = CALLER_ADDR3; + } +#endif /* CONFIG_PREEMPTIRQ_EVENTS */ + if (!preempt_trace() && irq_trace()) stop_critical_timing(CALLER_ADDR0, CALLER_ADDR1); } static inline void tracer_hardirqs_off(void) { +#ifdef CONFIG_PREEMPTIRQ_EVENTS + struct irqsoff_store *is = &per_cpu(the_irqsoff, + raw_smp_processor_id()); + u64 delta = 0; + + if (is->ts) { + delta = sched_clock() - is->ts; + is->ts = 0; + } + if (delta > sysctl_irqsoff_tracing_threshold_ns) + trace_irqs_disable(delta, is->caddr[0], is->caddr[1], + is->caddr[2], is->caddr[3]); +#endif /* CONFIG_PREEMPTIRQ_EVENTS */ + if (!preempt_trace() && irq_trace()) start_critical_timing(CALLER_ADDR0, CALLER_ADDR1); } -- GitLab From 589f164a93229c086d5e057dfb2be39567757069 Mon Sep 17 00:00:00 2001 From: Satya Durga Srinivasu Prabhala Date: Wed, 11 Apr 2018 13:04:16 -0700 Subject: [PATCH 0447/1635] defconfig: msm: enable PREEMPTIRQ_EVENTS for SM8150 To be able to debug performance issues related to scheduler, preempt and irq disable/enable trace events are needed. Change-Id: I87e72e60aef287f30b1008fdb145a72b3fc98c5c Signed-off-by: Satya Durga Srinivasu Prabhala --- arch/arm64/configs/sm8150_defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/configs/sm8150_defconfig b/arch/arm64/configs/sm8150_defconfig index a35eaa59a543..eb99e6c749d3 100644 --- a/arch/arm64/configs/sm8150_defconfig +++ b/arch/arm64/configs/sm8150_defconfig @@ -635,6 +635,7 @@ CONFIG_IPC_LOGGING=y CONFIG_QCOM_RTB=y CONFIG_QCOM_RTB_SEPARATE_CPUS=y CONFIG_FUNCTION_TRACER=y +CONFIG_PREEMPTIRQ_EVENTS=y CONFIG_IRQSOFF_TRACER=y CONFIG_PREEMPT_TRACER=y CONFIG_BLK_DEV_IO_TRACE=y -- GitLab From 9bc8b977936da7852b5ac3a86bdc783c538efbab Mon Sep 17 00:00:00 2001 From: Zhen Kong Date: Mon, 16 Apr 2018 14:21:38 -0700 Subject: [PATCH 0448/1635] drivers/soc/qcom: enable smcinvoke driver Make change to the kernel config and makefile in order to enable the smcinvoke driver. Change-Id: I591d4916cce9a1fdd162073b8c88db762c2843ff Signed-off-by: Zhen Kong --- drivers/soc/qcom/Kconfig | 8 ++++++++ drivers/soc/qcom/Makefile | 1 + 2 files changed, 9 insertions(+) diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig index 72c57efb54e9..75a8835792c0 100644 --- a/drivers/soc/qcom/Kconfig +++ b/drivers/soc/qcom/Kconfig @@ -517,6 +517,14 @@ config MSM_CDSP_LOADER for platforms that have compute DSP. Say M if you want to enable this module. +config QCOM_SMCINVOKE + bool "Secure QSEE Support" + help + Enable SMCInvoke driver which supports capability based secure + communication between QTI Secure Execution Environment (QSEE) + and high level operating system. It exposes APIs for both + userspace and kernel clients. + config MSM_EVENT_TIMER bool "Event timer" help diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile index 67a8c9f81cb4..71f64215fa24 100644 --- a/drivers/soc/qcom/Makefile +++ b/drivers/soc/qcom/Makefile @@ -50,6 +50,7 @@ obj-$(CONFIG_QTI_SYSTEM_PM) += system_pm.o obj-$(MSM_REMOTEQDSS) += remoteqdss.o obj-$(CONFIG_MSM_JTAGV8) += jtagv8.o jtagv8-etm.o obj-$(CONFIG_MSM_CDSP_LOADER) += qdsp6v2/ +obj-$(CONFIG_QCOM_SMCINVOKE) += smcinvoke.o ifdef CONFIG_MSM_SUBSYSTEM_RESTART obj-y += subsystem_notif.o -- GitLab From c7aec0e7042505a306cb84258e6336bf82f9dc24 Mon Sep 17 00:00:00 2001 From: Zhen Kong Date: Mon, 16 Apr 2018 14:22:03 -0700 Subject: [PATCH 0449/1635] defconfig: sm8150: enable the smcinvoke driver Changes to defconfig to enable the smc invoke driver used to communicate with TZ. Change-Id: Ib86172a16b4791b276d1a153e2410495f9204980 Signed-off-by: Zhen Kong --- arch/arm64/configs/sm8150-perf_defconfig | 1 + arch/arm64/configs/sm8150_defconfig | 1 + 2 files changed, 2 insertions(+) diff --git a/arch/arm64/configs/sm8150-perf_defconfig b/arch/arm64/configs/sm8150-perf_defconfig index 7c9a5e1913e1..c070097ae5f9 100644 --- a/arch/arm64/configs/sm8150-perf_defconfig +++ b/arch/arm64/configs/sm8150-perf_defconfig @@ -510,6 +510,7 @@ CONFIG_QCOM_GLINK=y CONFIG_QCOM_GLINK_PKT=y CONFIG_QTI_RPM_STATS_LOG=y CONFIG_MSM_CDSP_LOADER=y +CONFIG_QCOM_SMCINVOKE=y CONFIG_MSM_EVENT_TIMER=y CONFIG_MSM_PM=y CONFIG_QCOM_FSA4480_I2C=y diff --git a/arch/arm64/configs/sm8150_defconfig b/arch/arm64/configs/sm8150_defconfig index a35eaa59a543..7cf2e7b9d30d 100644 --- a/arch/arm64/configs/sm8150_defconfig +++ b/arch/arm64/configs/sm8150_defconfig @@ -533,6 +533,7 @@ CONFIG_QCOM_GLINK=y CONFIG_QCOM_GLINK_PKT=y CONFIG_QTI_RPM_STATS_LOG=y CONFIG_MSM_CDSP_LOADER=y +CONFIG_QCOM_SMCINVOKE=y CONFIG_MSM_EVENT_TIMER=y CONFIG_MSM_PM=y CONFIG_QCOM_FSA4480_I2C=y -- GitLab From 567f38265c98f7912c6131dcdb93ba41fd420dc4 Mon Sep 17 00:00:00 2001 From: "Isaac J. Manjarres" Date: Tue, 17 Apr 2018 10:26:50 -0700 Subject: [PATCH 0450/1635] drivers: edac: Allow IRQ line to be shared Other drivers in the kernel might want to use the same interrupt line that is used for llcc edac. Allow the interrupt line to be shared with other drivers by marking the line as shared at the time of request, and modify IRQ handler to identify if the interrupt is meant to be handled by edac or not. Change-Id: Ic06cf44540689d0f629607907bb9985fabe4cbaf Signed-off-by: Isaac J. Manjarres --- drivers/edac/qcom_llcc_edac.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/drivers/edac/qcom_llcc_edac.c b/drivers/edac/qcom_llcc_edac.c index 0b8f5369219d..ef40c2204316 100644 --- a/drivers/edac/qcom_llcc_edac.c +++ b/drivers/edac/qcom_llcc_edac.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -295,13 +295,14 @@ static void dump_syn_reg(struct edac_device_ctl_info *edev_ctl, errors[err_type].func(edev_ctl, 0, bank, errors[err_type].msg); } -static void qcom_llcc_check_cache_errors +static irqreturn_t qcom_llcc_check_cache_errors (struct edac_device_ctl_info *edev_ctl) { u32 drp_error; u32 trp_error; struct erp_drvdata *drv = edev_ctl->pvt_info; u32 i; + irqreturn_t irq_rc = IRQ_NONE; for (i = 0; i < drv->num_banks; i++) { /* Look for Data RAM errors */ @@ -312,10 +313,12 @@ static void qcom_llcc_check_cache_errors edac_printk(KERN_CRIT, EDAC_LLCC, "Single Bit Error detected in Data Ram\n"); dump_syn_reg(edev_ctl, LLCC_DRAM_CE, i); + irq_rc = IRQ_HANDLED; } else if (drp_error & DB_ECC_ERROR) { edac_printk(KERN_CRIT, EDAC_LLCC, "Double Bit Error detected in Data Ram\n"); dump_syn_reg(edev_ctl, LLCC_DRAM_UE, i); + irq_rc = IRQ_HANDLED; } /* Look for Tag RAM errors */ @@ -326,12 +329,16 @@ static void qcom_llcc_check_cache_errors edac_printk(KERN_CRIT, EDAC_LLCC, "Single Bit Error detected in Tag Ram\n"); dump_syn_reg(edev_ctl, LLCC_TRAM_CE, i); + irq_rc = IRQ_HANDLED; } else if (trp_error & DB_ECC_ERROR) { edac_printk(KERN_CRIT, EDAC_LLCC, "Double Bit Error detected in Tag Ram\n"); dump_syn_reg(edev_ctl, LLCC_TRAM_UE, i); + irq_rc = IRQ_HANDLED; } } + + return irq_rc; } #ifdef CONFIG_EDAC_LLCC_POLL @@ -344,8 +351,7 @@ static void qcom_llcc_poll_cache_errors(struct edac_device_ctl_info *edev_ctl) static irqreturn_t llcc_ecc_irq_handler (int irq, void *edev_ctl) { - qcom_llcc_check_cache_errors(edev_ctl); - return IRQ_HANDLED; + return qcom_llcc_check_cache_errors(edev_ctl); } static int qcom_llcc_erp_probe(struct platform_device *pdev) @@ -431,7 +437,8 @@ static int qcom_llcc_erp_probe(struct platform_device *pdev) } rc = devm_request_irq(dev, drv->ecc_irq, llcc_ecc_irq_handler, - IRQF_TRIGGER_HIGH, "llcc_ecc", edev_ctl); + IRQF_SHARED | IRQF_ONESHOT | IRQF_TRIGGER_HIGH, + "llcc_ecc", edev_ctl); if (rc) { dev_err(dev, "failed to request ecc irq\n"); goto out_dev; -- GitLab From 15ec1c42c06f589b51052f0f4ce48bf2e3ab69b5 Mon Sep 17 00:00:00 2001 From: Mayank Rana Date: Fri, 5 May 2017 16:21:29 -0700 Subject: [PATCH 0451/1635] Revert "usb: dwc3: gadget: skip Set/Clear Halt when invalid" This reverts commit 3ccf60e1ff5e ("usb: dwc3: gadget: skip Set/Clear Halt when invalid") as some of host side applications send CLEAR HALT request on opening of it without sending SET HALT which results into host and device side USB goes out of sync for SeqN (in SS) or Data Toggle (in HS). This result into host side application is not working. Fix this issue by honoring CLEAR HALT request although previously SET HALT request is not sent until host side applications are fixed. Change-Id: I896d6e264e84af06dba32ab336fe2269f417b785 Signed-off-by: Mayank Rana --- drivers/usb/dwc3/gadget.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 59710e1383b0..48f222314c46 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -1677,9 +1677,6 @@ int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value, int protocol) unsigned transfer_in_flight; unsigned started; - if (dep->flags & DWC3_EP_STALL) - return 0; - if (dep->number > 1) trb = dwc3_ep_prev_trb(dep, dep->trb_enqueue); else @@ -1701,8 +1698,6 @@ int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value, int protocol) else dep->flags |= DWC3_EP_STALL; } else { - if (!(dep->flags & DWC3_EP_STALL)) - return 0; ret = dwc3_send_clear_stall_ep_cmd(dep); if (ret) -- GitLab From c632135a3cd8846c361741c9f2e63f094485ce80 Mon Sep 17 00:00:00 2001 From: Mayank Rana Date: Tue, 3 Apr 2018 10:18:46 -0700 Subject: [PATCH 0452/1635] usb: gadget: Update functions for SSP descriptors This change updates USB function drivers to assign SSP descriptors using usb_assign_descriptors() API. USB SSP descriptors are needed to enumerate these functions as different composite device in super speed plus mode. Change-Id: Iea4d623afb2bf572358d1cc1d0673f20f2d7d5aa Signed-off-by: Mayank Rana --- drivers/usb/gadget/function/f_ccid.c | 2 +- drivers/usb/gadget/function/f_cdev.c | 4 +- drivers/usb/gadget/function/f_diag.c | 55 +++++-------------- drivers/usb/gadget/function/f_fs.c | 2 + drivers/usb/gadget/function/f_gsi.c | 79 +++++++++------------------- drivers/usb/gadget/function/f_mtp.c | 2 + drivers/usb/gadget/function/f_ncm.c | 2 +- drivers/usb/gadget/function/f_qdss.c | 44 ++++++---------- 8 files changed, 62 insertions(+), 128 deletions(-) diff --git a/drivers/usb/gadget/function/f_ccid.c b/drivers/usb/gadget/function/f_ccid.c index 08b24137f815..2e1d9beac545 100644 --- a/drivers/usb/gadget/function/f_ccid.c +++ b/drivers/usb/gadget/function/f_ccid.c @@ -638,7 +638,7 @@ static int ccid_function_bind(struct usb_configuration *c, ccid_fs_notify_desc.bEndpointAddress; ret = usb_assign_descriptors(f, ccid_fs_descs, ccid_hs_descs, - ccid_ss_descs, NULL); + ccid_ss_descs, ccid_ss_descs); if (ret) goto ep_auto_out_fail; diff --git a/drivers/usb/gadget/function/f_cdev.c b/drivers/usb/gadget/function/f_cdev.c index 18402cb548e4..fbd79142c8a2 100644 --- a/drivers/usb/gadget/function/f_cdev.c +++ b/drivers/usb/gadget/function/f_cdev.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2013-2017, The Linux Foundation. All rights reserved. + * Copyright (c) 2011, 2013-2018, The Linux Foundation. All rights reserved. * Linux Foundation chooses to take subject only to the GPLv2 license terms, * and distributes only under these terms. * @@ -793,7 +793,7 @@ static int usb_cser_bind(struct usb_configuration *c, struct usb_function *f) } status = usb_assign_descriptors(f, cser_fs_function, cser_hs_function, - cser_ss_function, NULL); + cser_ss_function, cser_ss_function); if (status) goto fail; diff --git a/drivers/usb/gadget/function/f_diag.c b/drivers/usb/gadget/function/f_diag.c index 78669fffbe49..a4217e3b5b6b 100644 --- a/drivers/usb/gadget/function/f_diag.c +++ b/drivers/usb/gadget/function/f_diag.c @@ -2,7 +2,7 @@ * Diag Function Device - Route ARM9 and ARM11 DIAG messages * between HOST and DEVICE. * Copyright (C) 2007 Google, Inc. - * Copyright (c) 2008-2017, The Linux Foundation. All rights reserved. + * Copyright (c) 2008-2018, The Linux Foundation. All rights reserved. * Author: Brian Swetland * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and @@ -728,12 +728,7 @@ static void diag_function_unbind(struct usb_configuration *c, struct diag_context *ctxt = func_to_diag(f); unsigned long flags; - if (gadget_is_superspeed(c->cdev->gadget)) - usb_free_descriptors(f->ss_descriptors); - if (gadget_is_dualspeed(c->cdev->gadget)) - usb_free_descriptors(f->hs_descriptors); - - usb_free_descriptors(f->fs_descriptors); + usb_free_all_descriptors(f); /* * Channel priv_usb may point to other diag function. @@ -773,36 +768,20 @@ static int diag_function_bind(struct usb_configuration *c, ctxt->out = ep; ep->driver_data = ctxt; - status = -ENOMEM; - /* copy descriptors, and track endpoint copies */ - f->fs_descriptors = usb_copy_descriptors(fs_diag_desc); - if (!f->fs_descriptors) + hs_bulk_in_desc.bEndpointAddress = + fs_bulk_in_desc.bEndpointAddress; + hs_bulk_out_desc.bEndpointAddress = + fs_bulk_out_desc.bEndpointAddress; + ss_bulk_in_desc.bEndpointAddress = + fs_bulk_in_desc.bEndpointAddress; + ss_bulk_out_desc.bEndpointAddress = + fs_bulk_out_desc.bEndpointAddress; + + status = usb_assign_descriptors(f, fs_diag_desc, hs_diag_desc, + ss_diag_desc, ss_diag_desc); + if (status) goto fail; - if (gadget_is_dualspeed(c->cdev->gadget)) { - hs_bulk_in_desc.bEndpointAddress = - fs_bulk_in_desc.bEndpointAddress; - hs_bulk_out_desc.bEndpointAddress = - fs_bulk_out_desc.bEndpointAddress; - - /* copy descriptors, and track endpoint copies */ - f->hs_descriptors = usb_copy_descriptors(hs_diag_desc); - if (!f->hs_descriptors) - goto fail; - } - - if (gadget_is_superspeed(c->cdev->gadget)) { - ss_bulk_in_desc.bEndpointAddress = - fs_bulk_in_desc.bEndpointAddress; - ss_bulk_out_desc.bEndpointAddress = - fs_bulk_out_desc.bEndpointAddress; - - /* copy descriptors, and track endpoint copies */ - f->ss_descriptors = usb_copy_descriptors(ss_diag_desc); - if (!f->ss_descriptors) - goto fail; - } - /* Allow only first diag channel to update pid and serial no */ if (ctxt == list_first_entry(&diag_dev_list, struct diag_context, list_item)) @@ -810,12 +789,6 @@ static int diag_function_bind(struct usb_configuration *c, return 0; fail: - if (f->ss_descriptors) - usb_free_descriptors(f->ss_descriptors); - if (f->hs_descriptors) - usb_free_descriptors(f->hs_descriptors); - if (f->fs_descriptors) - usb_free_descriptors(f->fs_descriptors); if (ctxt->out) ctxt->out->driver_data = NULL; if (ctxt->in) diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c index 0ecbbd446509..30650cacdee0 100644 --- a/drivers/usb/gadget/function/f_fs.c +++ b/drivers/usb/gadget/function/f_fs.c @@ -3331,6 +3331,7 @@ static int _ffs_func_bind(struct usb_configuration *c, ret = ss_len; goto error; } + func->function.ssp_descriptors = func->function.ss_descriptors; } else { ss_len = 0; } @@ -3791,6 +3792,7 @@ static void ffs_func_unbind(struct usb_configuration *c, func->function.fs_descriptors = NULL; func->function.hs_descriptors = NULL; func->function.ss_descriptors = NULL; + func->function.ssp_descriptors = NULL; func->interfaces_nums = NULL; ffs_event_add(ffs, FUNCTIONFS_UNBIND); diff --git a/drivers/usb/gadget/function/f_gsi.c b/drivers/usb/gadget/function/f_gsi.c index 3ef9018b0fb1..e8b96378a50d 100644 --- a/drivers/usb/gadget/function/f_gsi.c +++ b/drivers/usb/gadget/function/f_gsi.c @@ -2466,59 +2466,35 @@ static int gsi_update_function_bind_params(struct f_gsi *gsi, spin_lock_init(&gsi->d_port.evt_q.q_lock); gsi->d_port.evt_q.head = gsi->d_port.evt_q.tail = MAXQUEUELEN - 1; - /* copy descriptors, and track endpoint copies */ - f->fs_descriptors = usb_copy_descriptors(info->fs_desc_hdr); - if (!gsi->function.fs_descriptors) - goto fail; - - /* support all relevant hardware speeds... we expect that when - * hardware is dual speed, all bulk-capable endpoints work at - * both speeds - */ - if (gadget_is_dualspeed(cdev->gadget)) { - if (info->fs_in_desc) - info->hs_in_desc->bEndpointAddress = - info->fs_in_desc->bEndpointAddress; - if (info->fs_out_desc) - info->hs_out_desc->bEndpointAddress = - info->fs_out_desc->bEndpointAddress; - if (info->fs_notify_desc) - info->hs_notify_desc->bEndpointAddress = - info->fs_notify_desc->bEndpointAddress; - - /* copy descriptors, and track endpoint copies */ - f->hs_descriptors = usb_copy_descriptors(info->hs_desc_hdr); - if (!f->hs_descriptors) - goto fail; + if (info->fs_in_desc) { + info->hs_in_desc->bEndpointAddress = + info->fs_in_desc->bEndpointAddress; + info->ss_in_desc->bEndpointAddress = + info->fs_in_desc->bEndpointAddress; } - if (gadget_is_superspeed(cdev->gadget)) { - if (info->fs_in_desc) - info->ss_in_desc->bEndpointAddress = - info->fs_in_desc->bEndpointAddress; - - if (info->fs_out_desc) - info->ss_out_desc->bEndpointAddress = - info->fs_out_desc->bEndpointAddress; - if (info->fs_notify_desc) - info->ss_notify_desc->bEndpointAddress = - info->fs_notify_desc->bEndpointAddress; + if (info->fs_out_desc) { + info->hs_out_desc->bEndpointAddress = + info->fs_out_desc->bEndpointAddress; + info->ss_out_desc->bEndpointAddress = + info->fs_out_desc->bEndpointAddress; + } - /* copy descriptors, and track endpoint copies */ - f->ss_descriptors = usb_copy_descriptors(info->ss_desc_hdr); - if (!f->ss_descriptors) - goto fail; + if (info->fs_notify_desc) { + info->hs_notify_desc->bEndpointAddress = + info->fs_notify_desc->bEndpointAddress; + info->ss_notify_desc->bEndpointAddress = + info->fs_notify_desc->bEndpointAddress; } + status = usb_assign_descriptors(f, info->fs_desc_hdr, info->hs_desc_hdr, + info->ss_desc_hdr, info->ss_desc_hdr); + if (status) + goto fail; + return 0; fail: - if (gadget_is_superspeed(cdev->gadget) && f->ss_descriptors) - usb_free_descriptors(f->ss_descriptors); - if (gadget_is_dualspeed(cdev->gadget) && f->hs_descriptors) - usb_free_descriptors(f->hs_descriptors); - if (f->fs_descriptors) - usb_free_descriptors(f->fs_descriptors); if (gsi->c_port.notify_req) { kfree(gsi->c_port.notify_req->buf); usb_ep_free_request(gsi->c_port.notify, gsi->c_port.notify_req); @@ -2930,16 +2906,11 @@ static void gsi_unbind(struct usb_configuration *c, struct usb_function *f) if (gsi->prot_id == IPA_USB_MBIM) mbim_gsi_ext_config_desc.function.subCompatibleID[0] = 0; - if (gadget_is_superspeed(c->cdev->gadget)) { - usb_free_descriptors(f->ss_descriptors); - f->ss_descriptors = NULL; - } - if (gadget_is_dualspeed(c->cdev->gadget)) { - usb_free_descriptors(f->hs_descriptors); - f->hs_descriptors = NULL; - } - usb_free_descriptors(f->fs_descriptors); + usb_free_all_descriptors(f); + f->hs_descriptors = NULL; f->fs_descriptors = NULL; + f->ss_descriptors = NULL; + f->ssp_descriptors = NULL; if (gsi->c_port.notify) { kfree(gsi->c_port.notify_req->buf); diff --git a/drivers/usb/gadget/function/f_mtp.c b/drivers/usb/gadget/function/f_mtp.c index 892069269fa9..96af5de4ee78 100644 --- a/drivers/usb/gadget/function/f_mtp.c +++ b/drivers/usb/gadget/function/f_mtp.c @@ -1539,10 +1539,12 @@ struct usb_function *function_alloc_mtp_ptp(struct usb_function_instance *fi, dev->function.fs_descriptors = fs_mtp_descs; dev->function.hs_descriptors = hs_mtp_descs; dev->function.ss_descriptors = ss_mtp_descs; + dev->function.ssp_descriptors = ss_mtp_descs; } else { dev->function.fs_descriptors = fs_ptp_descs; dev->function.hs_descriptors = hs_ptp_descs; dev->function.ss_descriptors = ss_ptp_descs; + dev->function.ssp_descriptors = ss_ptp_descs; } dev->function.bind = mtp_function_bind; dev->function.unbind = mtp_function_unbind; diff --git a/drivers/usb/gadget/function/f_ncm.c b/drivers/usb/gadget/function/f_ncm.c index 45b334ceaf2e..dcf7bb50483f 100644 --- a/drivers/usb/gadget/function/f_ncm.c +++ b/drivers/usb/gadget/function/f_ncm.c @@ -1504,7 +1504,7 @@ static int ncm_bind(struct usb_configuration *c, struct usb_function *f) fs_ncm_notify_desc.bEndpointAddress; status = usb_assign_descriptors(f, ncm_fs_function, ncm_hs_function, - ncm_ss_function, NULL); + ncm_ss_function, ncm_ss_function); if (status) goto fail; diff --git a/drivers/usb/gadget/function/f_qdss.c b/drivers/usb/gadget/function/f_qdss.c index f00b301fb089..994ccd9e2f54 100644 --- a/drivers/usb/gadget/function/f_qdss.c +++ b/drivers/usb/gadget/function/f_qdss.c @@ -362,11 +362,7 @@ static void clear_desc(struct usb_gadget *gadget, struct usb_function *f) { pr_debug("%s\n", __func__); - if (gadget_is_superspeed(gadget) && f->ss_descriptors) - usb_free_descriptors(f->ss_descriptors); - - if (gadget_is_dualspeed(gadget) && f->hs_descriptors) - usb_free_descriptors(f->hs_descriptors); + usb_free_all_descriptors(f); } static int qdss_bind(struct usb_configuration *c, struct usb_function *f) @@ -374,7 +370,7 @@ static int qdss_bind(struct usb_configuration *c, struct usb_function *f) struct usb_gadget *gadget = c->cdev->gadget; struct f_qdss *qdss = func_to_qdss(f); struct usb_ep *ep; - int iface, id; + int iface, id, ret; pr_debug("%s\n", __func__); @@ -455,28 +451,18 @@ static int qdss_bind(struct usb_configuration *c, struct usb_function *f) qdss_ss_ctrl_in_desc.bEndpointAddress; qdss_hs_ctrl_out_desc.bEndpointAddress = qdss_ss_ctrl_out_desc.bEndpointAddress; - f->hs_descriptors = usb_copy_descriptors(qdss_hs_desc); - } else - f->hs_descriptors = usb_copy_descriptors( - qdss_hs_data_only_desc); - if (!f->hs_descriptors) { - pr_err("%s: usb_copy_descriptors error\n", __func__); - goto fail; } - /* update ss descriptors */ - if (gadget_is_superspeed(gadget)) { - if (qdss->debug_inface_enabled) - f->ss_descriptors = - usb_copy_descriptors(qdss_ss_desc); - else - f->ss_descriptors = - usb_copy_descriptors(qdss_ss_data_only_desc); - if (!f->ss_descriptors) { - pr_err("%s: usb_copy_descriptors error\n", __func__); - goto fail; - } - } + if (qdss->debug_inface_enabled) + ret = usb_assign_descriptors(f, qdss_hs_desc, qdss_hs_desc, + qdss_ss_desc, qdss_ss_desc); + else + ret = usb_assign_descriptors(f, qdss_hs_data_only_desc, + qdss_hs_data_only_desc, qdss_ss_data_only_desc, + qdss_ss_data_only_desc); + + if (ret) + goto fail; return 0; fail: @@ -643,9 +629,9 @@ static int qdss_set_alt(struct usb_function *f, unsigned int intf, if (alt != 0) goto fail1; - if (gadget->speed != USB_SPEED_SUPER && - gadget->speed != USB_SPEED_HIGH) { - pr_err("%s: qdss supportes HS or SS only\n", __func__); + if (gadget->speed < USB_SPEED_HIGH) { + pr_err("%s: qdss doesn't support USB full or low speed\n", + __func__); ret = -EINVAL; goto fail1; } -- GitLab From ced03aff569edc66e9dd9bdfa648881f4bcc3bf8 Mon Sep 17 00:00:00 2001 From: Veera Sundaram Sankaran Date: Tue, 17 Apr 2018 15:43:40 -0700 Subject: [PATCH 0453/1635] drm/msm/sde: fix kickoff ref count for single phys encoder usecase The pending_kickoff ref count is not updated properly for single physical encoder usecase resulting in frame-done triggered prematurely, causing various issues. Update the ref count during kickoff so that the frame-done and fences for the frame are handled properly. Change-Id: I6d62b047905c27cd5f039b83e9d490378b603714 Signed-off-by: Veera Sundaram Sankaran --- drivers/gpu/drm/msm/sde/sde_encoder.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/msm/sde/sde_encoder.c b/drivers/gpu/drm/msm/sde/sde_encoder.c index 65162c67d316..0a8ef2e1c1f5 100644 --- a/drivers/gpu/drm/msm/sde/sde_encoder.c +++ b/drivers/gpu/drm/msm/sde/sde_encoder.c @@ -3397,13 +3397,16 @@ static void _sde_encoder_kickoff_phys(struct sde_encoder_virt *sde_enc) set_bit(i, sde_enc->frame_busy_mask); if (!phys->ops.needs_single_flush || - !phys->ops.needs_single_flush(phys)) + !phys->ops.needs_single_flush(phys)) { + pending_kickoff_cnt = + sde_encoder_phys_inc_pending(phys); _sde_encoder_trigger_flush(&sde_enc->base, phys, 0x0); - else if (ctl->ops.get_pending_flush) { + SDE_EVT32(pending_kickoff_cnt, SDE_EVTLOG_FUNC_CASE1); + } else if (ctl->ops.get_pending_flush) { pending_kickoff_cnt = sde_encoder_phys_inc_pending(phys); ctl->ops.get_pending_flush(ctl, &pending_flush); - SDE_EVT32(pending_kickoff_cnt); + SDE_EVT32(pending_kickoff_cnt, SDE_EVTLOG_FUNC_CASE2); } } -- GitLab From cc455d4bab9dc060a3722d3d3b01f1b304adcb8f Mon Sep 17 00:00:00 2001 From: Raghavendra Rao Ananta Date: Tue, 17 Apr 2018 16:27:32 -0700 Subject: [PATCH 0454/1635] defconfig: sm8150: Enable the ARM DSU PMU Enable the ARM DynamIQ Shared Unit (DSU) PMU to gather various statistics at the cluster level. Change-Id: Ib9c9d9a541bb3309d9091913233d402ee0b81d5d Signed-off-by: Raghavendra Rao Ananta --- arch/arm64/configs/sm8150-perf_defconfig | 1 + arch/arm64/configs/sm8150_defconfig | 1 + 2 files changed, 2 insertions(+) diff --git a/arch/arm64/configs/sm8150-perf_defconfig b/arch/arm64/configs/sm8150-perf_defconfig index 7c9a5e1913e1..25cb78fefdbf 100644 --- a/arch/arm64/configs/sm8150-perf_defconfig +++ b/arch/arm64/configs/sm8150-perf_defconfig @@ -532,6 +532,7 @@ CONFIG_PWM=y CONFIG_PWM_QTI_LPG=y CONFIG_QCOM_KGSL=y CONFIG_ARM_GIC_V3_ACL=y +CONFIG_ARM_DSU_PMU=y CONFIG_QCOM_LLCC_PMU=y CONFIG_RAS=y CONFIG_ANDROID=y diff --git a/arch/arm64/configs/sm8150_defconfig b/arch/arm64/configs/sm8150_defconfig index a35eaa59a543..0a43879ff57b 100644 --- a/arch/arm64/configs/sm8150_defconfig +++ b/arch/arm64/configs/sm8150_defconfig @@ -556,6 +556,7 @@ CONFIG_PWM_QTI_LPG=y CONFIG_QCOM_KGSL=y CONFIG_ARM_GIC_V3_ACL=y CONFIG_PHY_XGENE=y +CONFIG_ARM_DSU_PMU=y CONFIG_QCOM_LLCC_PMU=y CONFIG_RAS=y CONFIG_ANDROID=y -- GitLab From 7c7447394e0df26c3d53682e01f1e73202f93a78 Mon Sep 17 00:00:00 2001 From: Raghavendra Rao Ananta Date: Tue, 17 Apr 2018 16:50:06 -0700 Subject: [PATCH 0455/1635] AndroidKernel: Update the LLVM path Update the LLVM path due to a change in the compiler version. Change-Id: I7c6c46047b4bb6f4a9e3d49eec1ae252c42fdbd8 Signed-off-by: Raghavendra Rao Ananta --- AndroidKernel.mk | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/AndroidKernel.mk b/AndroidKernel.mk index af4e1b404d9b..12ae066fcc21 100644 --- a/AndroidKernel.mk +++ b/AndroidKernel.mk @@ -49,10 +49,10 @@ endif ifeq ($(KERNEL_LLVM_SUPPORT), true) ifeq ($(KERNEL_SD_LLVM_SUPPORT), true) #Using sd-llvm compiler - ifeq ($(shell echo $(SDCLANG_PATH_2) | head -c 1),/) - KERNEL_LLVM_BIN := $(SDCLANG_PATH_2)/clang + ifeq ($(shell echo $(SDCLANG_PATH) | head -c 1),/) + KERNEL_LLVM_BIN := $(SDCLANG_PATH)/clang else - KERNEL_LLVM_BIN := $(ANDROID_BUILD_TOP)/$(SDCLANG_PATH_2)/clang + KERNEL_LLVM_BIN := $(ANDROID_BUILD_TOP)/$(SDCLANG_PATH)/clang endif $(warning "Using sdllvm" $(KERNEL_LLVM_BIN)) else -- GitLab From ed814b2e0e9dcd710bd55a1db1f594d5b06e7738 Mon Sep 17 00:00:00 2001 From: Steve Cohen Date: Wed, 11 Apr 2018 10:48:59 -0400 Subject: [PATCH 0456/1635] drm/msm/sde: clear dim-layer settings when setting default value Clear all dim-layers when the default value of 0 (NULL) is set for the dim layer property. This setting needs to be cleared when resetting the crtc custom properties during lastclose. Change-Id: Ib451f918d7448e4952d086827852516445f137c1 Signed-off-by: Steve Cohen --- drivers/gpu/drm/msm/sde/sde_crtc.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/drivers/gpu/drm/msm/sde/sde_crtc.c b/drivers/gpu/drm/msm/sde/sde_crtc.c index 7897f65acaa6..999a8baa1242 100644 --- a/drivers/gpu/drm/msm/sde/sde_crtc.c +++ b/drivers/gpu/drm/msm/sde/sde_crtc.c @@ -2453,6 +2453,23 @@ static void _sde_crtc_set_input_fence_timeout(struct sde_crtc_state *cstate) cstate->input_fence_timeout_ns *= NSEC_PER_MSEC; } +/** + * _sde_crtc_clear_dim_layers_v1 - clear all dim layer settings + * @cstate: Pointer to sde crtc state + */ +static void _sde_crtc_clear_dim_layers_v1(struct sde_crtc_state *cstate) +{ + u32 i; + + if (!cstate) + return; + + for (i = 0; i < cstate->num_dim_layers; i++) + memset(&cstate->dim_layer[i], 0, sizeof(cstate->dim_layer[i])); + + cstate->num_dim_layers = 0; +} + /** * _sde_crtc_set_dim_layer_v1 - copy dim layer settings from userspace * @cstate: Pointer to sde crtc state @@ -2473,6 +2490,8 @@ static void _sde_crtc_set_dim_layer_v1(struct sde_crtc_state *cstate, dim_layer = cstate->dim_layer; if (!usr_ptr) { + /* usr_ptr is null when setting the default property value */ + _sde_crtc_clear_dim_layers_v1(cstate); SDE_DEBUG("dim_layer data removed\n"); return; } -- GitLab From 036a2d159535360a9828ee15d0161bf346569c74 Mon Sep 17 00:00:00 2001 From: Steve Cohen Date: Thu, 12 Apr 2018 13:57:33 -0400 Subject: [PATCH 0457/1635] drm/msm/sde: clear exclusion rect settings on lastclose Clear the exclusion rect settings when the default value (NULL) is passed in as the property value instead of a valid user pointer. This occurs when the last DRM client closes the driver. Doing this ensures that any prior exclusion rect settings do not get re-applied the next time the driver is opened. Change-Id: Iefc994299eff526ead767e86b6794b761a2f336f Signed-off-by: Steve Cohen --- drivers/gpu/drm/msm/sde/sde_plane.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/msm/sde/sde_plane.c b/drivers/gpu/drm/msm/sde/sde_plane.c index 819c17f36a9d..e1da84267fc4 100644 --- a/drivers/gpu/drm/msm/sde/sde_plane.c +++ b/drivers/gpu/drm/msm/sde/sde_plane.c @@ -4621,13 +4621,14 @@ static void _sde_plane_set_excl_rect_v1(struct sde_plane *psde, { struct drm_clip_rect excl_rect_v1; - if (!psde) { - SDE_ERROR("invalid plane\n"); + if (!psde || !pstate) { + SDE_ERROR("invalid argument(s)\n"); return; } if (!usr_ptr) { - SDE_DEBUG_PLANE(psde, "invalid excl_rect user data\n"); + memset(&pstate->excl_rect, 0, sizeof(pstate->excl_rect)); + SDE_DEBUG_PLANE(psde, "excl_rect data cleared\n"); return; } -- GitLab From 649ae129311a25edcf940a5fb9a4f758648e579e Mon Sep 17 00:00:00 2001 From: Jack Pham Date: Wed, 7 Mar 2018 18:46:02 -0800 Subject: [PATCH 0458/1635] usb: dwc3-msm: Fix SuperSpeed when SuperSpeedPlus is supported On DWC 3.1 IP, maximum_speed may be USB_SPEED_SUPER_PLUS. There are several places where this value is using an equals comparison with USB_SPEED_SUPER, which will fail when speed is SSP, hence avoiding sequence needed to allow SuperSpeed operation. The comparisons should be changed from == to >=. Change-Id: Id43290379f1977ef181756ca77f43b3bb5d277d7 Signed-off-by: Jack Pham Signed-off-by: Mayank Rana --- drivers/usb/dwc3/core.c | 11 ++++------- drivers/usb/dwc3/dwc3-msm.c | 23 ++++++++++++----------- 2 files changed, 16 insertions(+), 18 deletions(-) diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index b17afab8e01c..9aba5be70c88 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -167,12 +167,8 @@ static int dwc3_core_soft_reset(struct dwc3 *dwc) int retries = 1000; int ret; - /* Reset PHYs */ + /* Reset and initialize PHYs */ usb_phy_reset(dwc->usb2_phy); - - if (dwc->maximum_speed == USB_SPEED_SUPER) - usb_phy_reset(dwc->usb3_phy); - ret = usb_phy_init(dwc->usb2_phy); if (ret) { pr_err("%s: usb_phy_init(dwc->usb2_phy) returned %d\n", @@ -180,9 +176,10 @@ static int dwc3_core_soft_reset(struct dwc3 *dwc) return ret; } - if (dwc->maximum_speed == USB_SPEED_HIGH) + if (dwc->maximum_speed <= USB_SPEED_HIGH) goto generic_phy_init; + usb_phy_reset(dwc->usb3_phy); ret = usb_phy_init(dwc->usb3_phy); if (ret == -EBUSY) { /* @@ -766,7 +763,7 @@ int dwc3_core_init(struct dwc3 *dwc) /* Handle USB2.0-only core configuration */ if (DWC3_GHWPARAMS3_SSPHY_IFC(dwc->hwparams.hwparams3) == DWC3_GHWPARAMS3_SSPHY_IFC_DIS) { - if (dwc->maximum_speed == USB_SPEED_SUPER) + if (dwc->maximum_speed >= USB_SPEED_SUPER) dwc->maximum_speed = USB_SPEED_HIGH; } diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c index 1626f46bd8ec..12fda55e4efc 100644 --- a/drivers/usb/dwc3/dwc3-msm.c +++ b/drivers/usb/dwc3/dwc3-msm.c @@ -275,9 +275,6 @@ struct dwc3_msm { #define USB_SSPHY_1P8_VOL_MAX 1800000 /* uV */ #define USB_SSPHY_1P8_HPM_LOAD 23000 /* uA */ -#define DSTS_CONNECTSPD_SS 0x4 - - static void dwc3_pwr_event_handler(struct dwc3_msm *mdwc); static int dwc3_msm_gadget_vbus_draw(struct dwc3_msm *mdwc, unsigned int mA); static void dwc3_msm_notify_event(struct dwc3 *dwc, unsigned int event); @@ -392,7 +389,7 @@ static bool dwc3_msm_is_ss_rhport_connected(struct dwc3_msm *mdwc) for (i = 0; i < num_ports; i++) { reg = dwc3_msm_read_reg(mdwc->base, USB3_PORTSC + i*0x10); - if ((reg & PORT_CONNECT) && DEV_SUPERSPEED(reg)) + if ((reg & PORT_CONNECT) && DEV_SUPERSPEED_ANY(reg)) return true; } @@ -409,7 +406,7 @@ static bool dwc3_msm_is_host_superspeed(struct dwc3_msm *mdwc) for (i = 0; i < num_ports; i++) { reg = dwc3_msm_read_reg(mdwc->base, USB3_PORTSC + i*0x10); - if ((reg & PORT_PE) && DEV_SUPERSPEED(reg)) + if ((reg & PORT_PE) && DEV_SUPERSPEED_ANY(reg)) return true; } @@ -421,7 +418,11 @@ static inline bool dwc3_msm_is_dev_superspeed(struct dwc3_msm *mdwc) u8 speed; speed = dwc3_msm_read_reg(mdwc->base, DWC3_DSTS) & DWC3_DSTS_CONNECTSPD; - return !!(speed & DSTS_CONNECTSPD_SS); + if ((speed & DWC3_DSTS_SUPERSPEED) || + (speed & DWC3_DSTS_SUPERSPEED_PLUS)) + return true; + + return false; } static inline bool dwc3_msm_is_superspeed(struct dwc3_msm *mdwc) @@ -1209,7 +1210,7 @@ static void gsi_configure_ep(struct usb_ep *ep, struct usb_gsi_request *request) | DWC3_DEPCFG_MAX_PACKET_SIZE(usb_endpoint_maxp(desc)); /* Burst size is only needed in SuperSpeed mode */ - if (dwc->gadget.speed == USB_SPEED_SUPER) { + if (dwc->gadget.speed >= USB_SPEED_SUPER) { u32 burst = dep->endpoint.maxburst - 1; params.param0 |= DWC3_DEPCFG_BURST_SIZE(burst); @@ -2194,7 +2195,7 @@ static int dwc3_msm_suspend(struct dwc3_msm *mdwc) usb_phy_set_suspend(mdwc->hs_phy, 1); /* Suspend SS PHY */ - if (dwc->maximum_speed == USB_SPEED_SUPER) { + if (dwc->maximum_speed >= USB_SPEED_SUPER) { /* indicate phy about SS mode */ if (dwc3_msm_is_superspeed(mdwc)) mdwc->ss_phy->flags |= DEVICE_IN_SS_MODE; @@ -2369,7 +2370,7 @@ static int dwc3_msm_resume(struct dwc3_msm *mdwc) clk_prepare_enable(mdwc->bus_aggr_clk); /* Resume SS PHY */ - if (dwc->maximum_speed == USB_SPEED_SUPER && + if (dwc->maximum_speed >= USB_SPEED_SUPER && mdwc->lpm_flags & MDWC3_SS_PHY_SUSPEND) { mdwc->ss_phy->flags &= ~(PHY_LANE_A | PHY_LANE_B); if (mdwc->typec_orientation == ORIENTATION_CC1) @@ -3637,7 +3638,7 @@ static int dwc3_otg_start_host(struct dwc3_msm *mdwc, int on) dev_dbg(mdwc->dev, "%s: turn on host\n", __func__); mdwc->hs_phy->flags |= PHY_HOST_MODE; - if (dwc->maximum_speed == USB_SPEED_SUPER) { + if (dwc->maximum_speed >= USB_SPEED_SUPER) { mdwc->ss_phy->flags |= PHY_HOST_MODE; usb_phy_notify_connect(mdwc->ss_phy, USB_SPEED_SUPER); @@ -3753,7 +3754,7 @@ static void dwc3_override_vbus_status(struct dwc3_msm *mdwc, bool vbus_present) vbus_present ? UTMI_OTG_VBUS_VALID | SW_SESSVLD_SEL : 0); /* Update only if Super Speed is supported */ - if (dwc->maximum_speed == USB_SPEED_SUPER) { + if (dwc->maximum_speed >= USB_SPEED_SUPER) { /* Update VBUS Valid from SSPHY to controller */ dwc3_msm_write_readback(mdwc->base, SS_PHY_CTRL_REG, LANE0_PWR_PRESENT, -- GitLab From 6fe2c698471a9c37d13478803604135c93fe182e Mon Sep 17 00:00:00 2001 From: Mayank Rana Date: Tue, 3 Apr 2018 09:39:40 -0700 Subject: [PATCH 0459/1635] dwc3-msm: Update maximum speed using extcon for high speed case only EXTCON_PROP_USB_SS property only supports boolean value (i.e 0 - high speed and 1 - super speed). Hence this property can't be used to select super speed plus as speed. Hence use hardware supported maximum speed always and use EXTCON_PROP_USB_SS property based value if it suggests as high speed. Change-Id: I157e63bfbb4cf8f756882a7e9573d8c99ea3a73d Signed-off-by: Mayank Rana --- drivers/usb/dwc3/dwc3-msm.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c index 12fda55e4efc..6fc3ff2d0755 100644 --- a/drivers/usb/dwc3/dwc3-msm.c +++ b/drivers/usb/dwc3/dwc3-msm.c @@ -2523,17 +2523,16 @@ static void dwc3_resume_work(struct work_struct *w) /* Check speed and Type-C polarity values in order to configure PHY */ if (edev && extcon_get_state(edev, extcon_id)) { - ret = extcon_get_property(edev, extcon_id, - EXTCON_PROP_USB_SS, &val); - /* Use default dwc->maximum_speed if speed isn't reported */ - if (!ret) - dwc->maximum_speed = (val.intval == 0) ? - USB_SPEED_HIGH : USB_SPEED_SUPER; - if (dwc->maximum_speed > dwc->max_hw_supp_speed) dwc->maximum_speed = dwc->max_hw_supp_speed; + ret = extcon_get_property(edev, extcon_id, + EXTCON_PROP_USB_SS, &val); + + if (!ret && val.intval == 0) + dwc->maximum_speed = USB_SPEED_HIGH; + if (mdwc->override_usb_speed) { dwc->maximum_speed = mdwc->override_usb_speed; dwc->gadget.max_speed = dwc->maximum_speed; -- GitLab From fd7c8ae4a92445f800335321319832fbbfc9f4b1 Mon Sep 17 00:00:00 2001 From: Abhijit Kulkarni Date: Tue, 17 Apr 2018 17:58:55 -0700 Subject: [PATCH 0460/1635] ARM: dts: msm: fix intf register size for sm8150 This change is required for sm8150 to dump the tear check registers which has now moved from pp block to intf block. Change-Id: Id8f23ac4aeac1e0469b4314cc4997ee0894aeb35 Signed-off-by: Abhijit Kulkarni --- arch/arm64/boot/dts/qcom/sm8150-sde.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/sm8150-sde.dtsi b/arch/arm64/boot/dts/qcom/sm8150-sde.dtsi index f217c1b50857..0f23687dbfed 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-sde.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-sde.dtsi @@ -79,7 +79,7 @@ qcom,sde-intf-off = <0x6b000 0x6b800 0x6c000 0x6c800>; - qcom,sde-intf-size = <0x280>; + qcom,sde-intf-size = <0x2b8>; qcom,sde-intf-type = "dp", "dsi", "dsi", "dp"; qcom,sde-pp-off = <0x71000 0x71800 -- GitLab From 43b2c2597d22886f11091642e3e2c3c9f79ea426 Mon Sep 17 00:00:00 2001 From: Abhijit Kulkarni Date: Mon, 16 Apr 2018 13:06:25 -0700 Subject: [PATCH 0461/1635] drm/msm/sde: set correct timeline at fence create This change adds the offset to the associated timeline when the retire and release fences are created. The DRM client queries the fences using the atomic commit instead of set_property ioctl. So the sync point should contain the updated timeline before sending the FDs to client. Change-Id: I1ac9507934223bd1091be6960805c63cb4aacfb1 Signed-off-by: Abhijit Kulkarni --- drivers/gpu/drm/msm/sde/sde_connector.c | 5 ++++- drivers/gpu/drm/msm/sde/sde_crtc.c | 7 +++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/msm/sde/sde_connector.c b/drivers/gpu/drm/msm/sde/sde_connector.c index 6ee35ca379b0..589f5097303c 100644 --- a/drivers/gpu/drm/msm/sde/sde_connector.c +++ b/drivers/gpu/drm/msm/sde/sde_connector.c @@ -1054,7 +1054,10 @@ static int sde_connector_atomic_set_property(struct drm_connector *connector, if (!val) goto end; - rc = sde_fence_create(&c_conn->retire_fence, &fence_fd, 0); + /* + * update the the offset to a timeline for commit completion + */ + rc = sde_fence_create(&c_conn->retire_fence, &fence_fd, 1); if (rc) { SDE_ERROR("fence create failed rc:%d\n", rc); goto end; diff --git a/drivers/gpu/drm/msm/sde/sde_crtc.c b/drivers/gpu/drm/msm/sde/sde_crtc.c index a7c21c111c1c..0a762ea019da 100644 --- a/drivers/gpu/drm/msm/sde/sde_crtc.c +++ b/drivers/gpu/drm/msm/sde/sde_crtc.c @@ -5209,6 +5209,13 @@ static int _sde_crtc_get_output_fence(struct drm_crtc *crtc, */ offset = is_cmd ? 0 : (offset + conn_offset); + /* + * Hwcomposer now queries the fences using the commit list in atomic + * commit ioctl. The offset should be set to next timeline + * which will be incremented during the prepare commit phase + */ + offset++; + return sde_fence_create(&sde_crtc->output_fence, val, offset); } -- GitLab From 38be6f7427c137899b59a4fb76b111b3b3e88510 Mon Sep 17 00:00:00 2001 From: Hardik Arya Date: Mon, 9 Apr 2018 14:49:40 +0530 Subject: [PATCH 0462/1635] diag: Add missing protection while accessing session's info Currently, mutex protection is missing while accessing md session's info via macro. The patch adds proper protection before accessing the same. Change-Id: I17b18183407279447229783fd0165337bd173423 Signed-off-by: Hardik Arya --- drivers/char/diag/diag_masks.c | 41 +++++++++++++++++++++------------- 1 file changed, 26 insertions(+), 15 deletions(-) diff --git a/drivers/char/diag/diag_masks.c b/drivers/char/diag/diag_masks.c index 25e6815e3723..f9da986229ea 100644 --- a/drivers/char/diag/diag_masks.c +++ b/drivers/char/diag/diag_masks.c @@ -27,9 +27,6 @@ #define DIAG_SET_FEATURE_MASK(x) (feature_bytes[(x)/8] |= (1 << (x & 0x7))) -#define diag_check_update(x) \ - (!info || (info && (info->peripheral_mask & MD_PERIPHERAL_MASK(x)))) \ - struct diag_mask_info msg_mask; struct diag_mask_info msg_bt_mask; struct diag_mask_info log_mask; @@ -64,6 +61,20 @@ static const struct diag_ssid_range_t msg_mask_tbl[] = { { .ssid_first = MSG_SSID_25, .ssid_last = MSG_SSID_25_LAST } }; +static int diag_check_update(int md_peripheral, int pid) +{ + int ret; + struct diag_md_session_t *info = NULL; + + mutex_lock(&driver->md_session_lock); + info = diag_md_session_get_pid(pid); + ret = (!info || (info && + (info->peripheral_mask & MD_PERIPHERAL_MASK(md_peripheral)))); + mutex_unlock(&driver->md_session_lock); + + return ret; +} + static int diag_apps_responds(void) { /* @@ -825,7 +836,7 @@ static int diag_cmd_set_msg_mask(unsigned char *src_buf, int src_len, mutex_unlock(&driver->msg_mask_lock); mutex_unlock(&mask_info->lock); mutex_unlock(&driver->md_session_lock); - if (diag_check_update(APPS_DATA)) + if (diag_check_update(APPS_DATA, pid)) diag_update_userspace_clients(MSG_MASKS_TYPE); /* @@ -849,7 +860,7 @@ static int diag_cmd_set_msg_mask(unsigned char *src_buf, int src_len, for (i = 0; i < NUM_MD_SESSIONS; i++) { if (i == APPS_DATA) continue; - if (!diag_check_update(i)) + if (!diag_check_update(i, pid)) continue; if (i > NUM_PERIPHERALS) peripheral = diag_search_peripheral_by_pd(i); @@ -919,7 +930,7 @@ static int diag_cmd_set_all_msg_mask(unsigned char *src_buf, int src_len, mutex_unlock(&driver->msg_mask_lock); mutex_unlock(&mask_info->lock); mutex_unlock(&driver->md_session_lock); - if (diag_check_update(APPS_DATA)) + if (diag_check_update(APPS_DATA, pid)) diag_update_userspace_clients(MSG_MASKS_TYPE); /* @@ -937,7 +948,7 @@ static int diag_cmd_set_all_msg_mask(unsigned char *src_buf, int src_len, for (i = 0; i < NUM_MD_SESSIONS; i++) { if (i == APPS_DATA) continue; - if (!diag_check_update(i)) + if (!diag_check_update(i, pid)) continue; if (i > NUM_PERIPHERALS) peripheral = diag_search_peripheral_by_pd(i); @@ -1027,7 +1038,7 @@ static int diag_cmd_update_event_mask(unsigned char *src_buf, int src_len, mask_info->status = DIAG_CTRL_MASK_VALID; mutex_unlock(&mask_info->lock); mutex_unlock(&driver->md_session_lock); - if (diag_check_update(APPS_DATA)) + if (diag_check_update(APPS_DATA, pid)) diag_update_userspace_clients(EVENT_MASKS_TYPE); /* @@ -1046,7 +1057,7 @@ static int diag_cmd_update_event_mask(unsigned char *src_buf, int src_len, for (i = 0; i < NUM_MD_SESSIONS; i++) { if (i == APPS_DATA) continue; - if (!diag_check_update(i)) + if (!diag_check_update(i, pid)) continue; if (i > NUM_PERIPHERALS) peripheral = diag_search_peripheral_by_pd(i); @@ -1098,7 +1109,7 @@ static int diag_cmd_toggle_events(unsigned char *src_buf, int src_len, } mutex_unlock(&mask_info->lock); mutex_unlock(&driver->md_session_lock); - if (diag_check_update(APPS_DATA)) + if (diag_check_update(APPS_DATA, pid)) diag_update_userspace_clients(EVENT_MASKS_TYPE); /* @@ -1110,7 +1121,7 @@ static int diag_cmd_toggle_events(unsigned char *src_buf, int src_len, for (i = 0; i < NUM_MD_SESSIONS; i++) { if (i == APPS_DATA) continue; - if (!diag_check_update(i)) + if (!diag_check_update(i, pid)) continue; if (i > NUM_PERIPHERALS) peripheral = diag_search_peripheral_by_pd(i); @@ -1373,7 +1384,7 @@ static int diag_cmd_set_log_mask(unsigned char *src_buf, int src_len, } mutex_unlock(&mask_info->lock); mutex_unlock(&driver->md_session_lock); - if (diag_check_update(APPS_DATA)) + if (diag_check_update(APPS_DATA, pid)) diag_update_userspace_clients(LOG_MASKS_TYPE); /* @@ -1404,7 +1415,7 @@ static int diag_cmd_set_log_mask(unsigned char *src_buf, int src_len, for (i = 0; i < NUM_MD_SESSIONS; i++) { if (i == APPS_DATA) continue; - if (!diag_check_update(i)) + if (!diag_check_update(i, pid)) continue; if (i > NUM_PERIPHERALS) peripheral = diag_search_peripheral_by_pd(i); @@ -1459,7 +1470,7 @@ static int diag_cmd_disable_log_mask(unsigned char *src_buf, int src_len, } mask_info->status = DIAG_CTRL_MASK_ALL_DISABLED; mutex_unlock(&driver->md_session_lock); - if (diag_check_update(APPS_DATA)) + if (diag_check_update(APPS_DATA, pid)) diag_update_userspace_clients(LOG_MASKS_TYPE); /* @@ -1477,7 +1488,7 @@ static int diag_cmd_disable_log_mask(unsigned char *src_buf, int src_len, for (i = 0; i < NUM_MD_SESSIONS; i++) { if (i == APPS_DATA) continue; - if (!diag_check_update(i)) + if (!diag_check_update(i, pid)) continue; if (i > NUM_PERIPHERALS) peripheral = diag_search_peripheral_by_pd(i); -- GitLab From 5eb409db94bbbdbda2a04f20f8448e594f03f9d6 Mon Sep 17 00:00:00 2001 From: Hardik Arya Date: Mon, 26 Mar 2018 10:42:25 +0530 Subject: [PATCH 0463/1635] diag: Clearing the mask before switching logging mode Currently there is a possibility of not clearing a mask when logging mode is switched via ioctl. The patch adds clearing of mask before switching logging mode from ioctl. CRs-Fixed: 2206931 Change-Id: Iaff41e67c963b2333be0cf5853ad657764a71cc1 Signed-off-by: Hardik Arya --- drivers/char/diag/diag_masks.c | 8 ----- drivers/char/diag/diagchar.h | 2 -- drivers/char/diag/diagchar_core.c | 56 ++++++++++++++++++++++++++----- 3 files changed, 48 insertions(+), 18 deletions(-) diff --git a/drivers/char/diag/diag_masks.c b/drivers/char/diag/diag_masks.c index 25e6815e3723..d1f426736ba9 100644 --- a/drivers/char/diag/diag_masks.c +++ b/drivers/char/diag/diag_masks.c @@ -2044,14 +2044,6 @@ int diag_copy_to_user_msg_mask(char __user *buf, size_t count, __func__, mask_info->ptr, mask_info->update_buf); return -EINVAL; } - mutex_lock(&driver->diag_maskclear_mutex); - if (driver->mask_clear) { - DIAG_LOG(DIAG_DEBUG_PERIPHERALS, - "diag:%s: count = %zu\n", __func__, count); - mutex_unlock(&driver->diag_maskclear_mutex); - return -EIO; - } - mutex_unlock(&driver->diag_maskclear_mutex); mutex_lock(&mask_info->lock); mutex_lock(&driver->msg_mask_lock); diff --git a/drivers/char/diag/diagchar.h b/drivers/char/diag/diagchar.h index a635c1c4bf01..4055608f88e2 100644 --- a/drivers/char/diag/diagchar.h +++ b/drivers/char/diag/diagchar.h @@ -538,8 +538,6 @@ struct diagchar_dev { struct class *diagchar_class; struct device *diag_dev; int ref_count; - int mask_clear; - struct mutex diag_maskclear_mutex; struct mutex diag_notifier_mutex; struct mutex diagchar_mutex; struct mutex diag_file_mutex; diff --git a/drivers/char/diag/diagchar_core.c b/drivers/char/diag/diagchar_core.c index abbcf94bbc06..c2f394fcf8c9 100644 --- a/drivers/char/diag/diagchar_core.c +++ b/drivers/char/diag/diagchar_core.c @@ -459,10 +459,6 @@ static void diag_close_logging_process(const int pid) if (diag_mask_clear_param) diag_clear_masks(pid); - mutex_lock(&driver->diag_maskclear_mutex); - driver->mask_clear = 1; - mutex_unlock(&driver->diag_maskclear_mutex); - mutex_lock(&driver->diagchar_mutex); p_mask = diag_translate_kernel_to_user_mask(session_mask); @@ -559,9 +555,7 @@ static int diagchar_close(struct inode *inode, struct file *file) DIAG_LOG(DIAG_DEBUG_USERSPACE, "diag: process exit %s\n", current->comm); ret = diag_remove_client_entry(file); - mutex_lock(&driver->diag_maskclear_mutex); - driver->mask_clear = 0; - mutex_unlock(&driver->diag_maskclear_mutex); + return ret; } @@ -1675,6 +1669,51 @@ static uint32_t diag_translate_mask(uint32_t peripheral_mask) return ret; } +static void diag_switch_logging_clear_mask( + struct diag_logging_mode_param_t *param, int pid) +{ + int new_mode; + struct diag_md_session_t *session_info = NULL; + + mutex_lock(&driver->md_session_lock); + session_info = diag_md_session_get_pid(pid); + if (!session_info) { + DIAG_LOG(DIAG_DEBUG_USERSPACE, "Invalid pid: %d\n", pid); + mutex_unlock(&driver->md_session_lock); + return; + } + mutex_unlock(&driver->md_session_lock); + + if (!param) + return; + + if (!param->peripheral_mask) { + DIAG_LOG(DIAG_DEBUG_USERSPACE, + "asking for mode switch with no peripheral mask set\n"); + return; + } + + switch (param->req_mode) { + case CALLBACK_MODE: + case UART_MODE: + case SOCKET_MODE: + case MEMORY_DEVICE_MODE: + new_mode = DIAG_MEMORY_DEVICE_MODE; + break; + case USB_MODE: + new_mode = DIAG_USB_MODE; + break; + default: + DIAG_LOG(DIAG_DEBUG_USERSPACE, + "Request to switch to invalid mode: %d\n", + param->req_mode); + return; + } + if ((new_mode == DIAG_USB_MODE) && diag_mask_clear_param) + diag_clear_masks(pid); + +} + static int diag_switch_logging(struct diag_logging_mode_param_t *param) { int new_mode, i = 0; @@ -2502,6 +2541,7 @@ long diagchar_compat_ioctl(struct file *filp, if (copy_from_user((void *)&mode_param, (void __user *)ioarg, sizeof(mode_param))) return -EFAULT; + diag_switch_logging_clear_mask(&mode_param, current->tgid); mutex_lock(&driver->diagchar_mutex); result = diag_switch_logging(&mode_param); mutex_unlock(&driver->diagchar_mutex); @@ -2633,6 +2673,7 @@ long diagchar_ioctl(struct file *filp, if (copy_from_user((void *)&mode_param, (void __user *)ioarg, sizeof(mode_param))) return -EFAULT; + diag_switch_logging_clear_mask(&mode_param, current->tgid); mutex_lock(&driver->diagchar_mutex); result = diag_switch_logging(&mode_param); mutex_unlock(&driver->diagchar_mutex); @@ -3906,7 +3947,6 @@ static int __init diagchar_init(void) non_hdlc_data.len = 0; mutex_init(&driver->hdlc_disable_mutex); mutex_init(&driver->diagchar_mutex); - mutex_init(&driver->diag_maskclear_mutex); mutex_init(&driver->diag_notifier_mutex); mutex_init(&driver->diag_file_mutex); mutex_init(&driver->delayed_rsp_mutex); -- GitLab From 12c7a6bbe31991f343cfcf9d1aac4c7d5f0531c4 Mon Sep 17 00:00:00 2001 From: Hardik Arya Date: Thu, 29 Mar 2018 13:58:19 +0530 Subject: [PATCH 0464/1635] diag: Add protection while accessing usb_info's buffer table Currently there a possibility of NULL pointer dereference while accessing usb_info's buffer table due to missing proper protection. The patch adds protection for the same. Change-Id: I974a70a48e7ac47b42bc237aac4db1b9e47be6be Signed-off-by: Hardik Arya --- drivers/char/diag/diag_usb.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/char/diag/diag_usb.c b/drivers/char/diag/diag_usb.c index 8f6cd5892201..588e60d07c49 100644 --- a/drivers/char/diag/diag_usb.c +++ b/drivers/char/diag/diag_usb.c @@ -308,23 +308,25 @@ static void diag_usb_write_done(struct diag_usb_info *ch, if (!ch || !req) return; + spin_lock_irqsave(&ch->write_lock, flags); ch->write_cnt++; entry = diag_usb_buf_tbl_get(ch, req->context); if (!entry) { pr_err_ratelimited("diag: In %s, unable to find entry %pK in the table\n", __func__, req->context); + spin_unlock_irqrestore(&ch->write_lock, flags); return; } if (atomic_read(&entry->ref_count) != 0) { DIAG_LOG(DIAG_DEBUG_MUX, "partial write_done ref %d\n", atomic_read(&entry->ref_count)); diag_ws_on_copy_complete(DIAG_WS_MUX); + spin_unlock_irqrestore(&ch->write_lock, flags); diagmem_free(driver, req, ch->mempool); return; } DIAG_LOG(DIAG_DEBUG_MUX, "full write_done, ctxt: %d\n", ctxt); - spin_lock_irqsave(&ch->write_lock, flags); list_del(&entry->track); ctxt = entry->ctxt; buf = entry->buf; -- GitLab From 5ab51b9761d85205711c3fdad81484bd3ecc8bf4 Mon Sep 17 00:00:00 2001 From: Konstantin Dorfman Date: Sun, 15 Apr 2018 09:03:01 +0300 Subject: [PATCH 0465/1635] ARM: dts: msm: add spcom to sm8150 Add Secure Processor Communication (spcom) device tree info. This spcom driver supports communication with secure processor subsystem over glink transport layer. Change-Id: I87146c36332581a7d86c468345aa5c4755c3c6bc Signed-off-by: Konstantin Dorfman --- arch/arm64/boot/dts/qcom/sm8150.dtsi | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sm8150.dtsi b/arch/arm64/boot/dts/qcom/sm8150.dtsi index d20bb095acb2..a49684328aa6 100644 --- a/arch/arm64/boot/dts/qcom/sm8150.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150.dtsi @@ -731,6 +731,14 @@ status = "ok"; }; + qcom,spcom { + compatible = "qcom,spcom"; + + /* predefined channels, remote side is server */ + qcom,spcom-ch-names = "sp_kernel", "sp_ssr"; + status = "ok"; + }; + jtag_mm0: jtagmm@7040000 { compatible = "qcom,jtagv8-mm"; reg = <0x7040000 0x1000>; -- GitLab From f711e77b5337f275cd4029404d9aabe02247325d Mon Sep 17 00:00:00 2001 From: Konstantin Dorfman Date: Sun, 15 Apr 2018 09:44:23 +0300 Subject: [PATCH 0466/1635] defconfig: sm8150: enable spcom driver Enable spcom driver required to support communication with Secure Processor (SP). Change-Id: I12455cb864d8f308c2f9ea2bb59ad28995f27ba3 Signed-off-by: Konstantin Dorfman --- arch/arm64/configs/sm8150-perf_defconfig | 1 + arch/arm64/configs/sm8150_defconfig | 1 + 2 files changed, 2 insertions(+) diff --git a/arch/arm64/configs/sm8150-perf_defconfig b/arch/arm64/configs/sm8150-perf_defconfig index 7c9a5e1913e1..84836801416a 100644 --- a/arch/arm64/configs/sm8150-perf_defconfig +++ b/arch/arm64/configs/sm8150-perf_defconfig @@ -504,6 +504,7 @@ CONFIG_QCOM_BUS_SCALING=y CONFIG_QCOM_BUS_CONFIG_RPMH=y CONFIG_QCOM_COMMAND_DB=y CONFIG_QCOM_EARLY_RANDOM=y +CONFIG_MSM_SPCOM=y CONFIG_QTI_RPMH_API=y CONFIG_QSEE_IPC_IRQ_BRIDGE=y CONFIG_QCOM_GLINK=y diff --git a/arch/arm64/configs/sm8150_defconfig b/arch/arm64/configs/sm8150_defconfig index a35eaa59a543..c17b7de9f062 100644 --- a/arch/arm64/configs/sm8150_defconfig +++ b/arch/arm64/configs/sm8150_defconfig @@ -527,6 +527,7 @@ CONFIG_QCOM_BUS_CONFIG_RPMH=y CONFIG_QCOM_COMMAND_DB=y CONFIG_QCOM_EARLY_RANDOM=y CONFIG_MSM_SPSS_UTILS=y +CONFIG_MSM_SPCOM=y CONFIG_QTI_RPMH_API=y CONFIG_QSEE_IPC_IRQ_BRIDGE=y CONFIG_QCOM_GLINK=y -- GitLab From c11598b5fa44889b11bdde2be290d83898899cbc Mon Sep 17 00:00:00 2001 From: Vijayanand Jitta Date: Wed, 14 Mar 2018 11:39:03 +0530 Subject: [PATCH 0467/1635] ARM: dts: msm: Add smmu device for sdm640 Describe the register address and settings for the graphics and apps smmu device for sdm640. Change-Id: I25d9c35d5ca7d2cb35439f5b11650101ffcb6e51 Signed-off-by: Vijayanand Jitta --- .../boot/dts/qcom/msm-arm-smmu-sdm640.dtsi | 214 ++++++++++++++++++ arch/arm64/boot/dts/qcom/sdm640.dtsi | 1 + 2 files changed, 215 insertions(+) create mode 100644 arch/arm64/boot/dts/qcom/msm-arm-smmu-sdm640.dtsi diff --git a/arch/arm64/boot/dts/qcom/msm-arm-smmu-sdm640.dtsi b/arch/arm64/boot/dts/qcom/msm-arm-smmu-sdm640.dtsi new file mode 100644 index 000000000000..d24312ad8bfc --- /dev/null +++ b/arch/arm64/boot/dts/qcom/msm-arm-smmu-sdm640.dtsi @@ -0,0 +1,214 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include + +&soc { + kgsl_smmu: kgsl-smmu@0x50a0000 { + compatible = "qcom,qsmmu-v500"; + reg = <0x50a0000 0x10000>, + <0x50c2000 0x20>; + reg-names = "base", "tcu-base"; + #iommu-cells = <1>; + qcom,skip-init; + qcom,use-3-lvl-tables; + #global-interrupts = <1>; + qcom,regulator-names = "vdd"; + vdd-supply = <&gpu_cx_gdsc>; + #size-cells = <1>; + #address-cells = <1>; + ranges; + interrupts = , + , + , + , + , + , + , + , + ; + + gfx_0_tbu: gfx_0_tbu@0x50c5000 { + compatible = "qcom,qsmmuv500-tbu"; + reg = <0x50c5000 0x1000>, + <0x50c2200 0x8>; + reg-names = "base", "status-reg"; + qcom,stream-id-range = <0x0 0x400>; + }; + + gfx_1_tbu: gfx_1_tbu@0x50c9000 { + compatible = "qcom,qsmmuv500-tbu"; + reg = <0x50c9000 0x1000>, + <0x50c2208 0x8>; + reg-names = "base", "status-reg"; + qcom,stream-id-range = <0x400 0x400>; + }; + }; + + apps_smmu: apps-smmu@0x15000000 { + compatible = "qcom,qsmmu-v500"; + reg = <0x15000000 0x80000>, + <0x150c2000 0x20>; + reg-names = "base", "tcu-base"; + #iommu-cells = <2>; + qcom,skip-init; + qcom,use-3-lvl-tables; + #global-interrupts = <1>; + #size-cells = <1>; + #address-cells = <1>; + ranges; + interrupts = , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + ; + + anoc_1_tbu: anoc_1_tbu@0x150c5000 { + compatible = "qcom,qsmmuv500-tbu"; + reg = <0x150c5000 0x1000>, + <0x150c2200 0x8>; + reg-names = "base", "status-reg"; + qcom,stream-id-range = <0x0 0x400>; + qcom,regulator-names = "vdd"; + vdd-supply = <&hlos1_vote_aggre_noc_mmu_tbu1_gdsc>; + }; + + anoc_2_tbu: anoc_2_tbu@0x150c9000 { + compatible = "qcom,qsmmuv500-tbu"; + reg = <0x150c9000 0x1000>, + <0x150c2208 0x8>; + reg-names = "base", "status-reg"; + qcom,stream-id-range = <0x400 0x400>; + qcom,regulator-names = "vdd"; + vdd-supply = <&hlos1_vote_aggre_noc_mmu_tbu2_gdsc>; + }; + + mnoc_hf_0_tbu: mnoc_hf_0_tbu@0x150cd000 { + compatible = "qcom,qsmmuv500-tbu"; + reg = <0x150cd000 0x1000>, + <0x150c2210 0x8>; + reg-names = "base", "status-reg"; + qcom,stream-id-range = <0x800 0x400>; + qcom,regulator-names = "vdd"; + vdd-supply = <&hlos1_vote_mmnoc_mmu_tbu_hf0_gdsc>; + }; + + mnoc_sf_0_tbu: mnoc_sf_0_tbu@0x150d1000 { + compatible = "qcom,qsmmuv500-tbu"; + reg = <0x150d1000 0x1000>, + <0x150c2218 0x8>; + reg-names = "base", "status-reg"; + qcom,stream-id-range = <0xc00 0x400>; + qcom,regulator-names = "vdd"; + vdd-supply = <&hlos1_vote_mmnoc_mmu_tbu_sf_gdsc>; + }; + + compute_dsp_tbu: compute_dsp_tbu@0x150d5000 { + compatible = "qcom,qsmmuv500-tbu"; + reg = <0x150d5000 0x1000>, + <0x150c2220 0x8>; + reg-names = "base", "status-reg"; + qcom,stream-id-range = <0x1000 0x400>; + /* No GDSC */ + }; + + adsp_tbu: adsp_tbu@0x150d9000 { + compatible = "qcom,qsmmuv500-tbu"; + reg = <0x150d9000 0x1000>, + <0x150c2228 0x8>; + reg-names = "base", "status-reg"; + qcom,stream-id-range = <0x1400 0x400>; + qcom,regulator-names = "vdd"; + vdd-supply = <&hlos1_vote_aggre_noc_mmu_audio_tbu_gdsc>; + }; + }; + + kgsl_iommu_test_device { + compatible = "iommu-debug-test"; + /* + * 0x7 isn't a valid sid, but should pass the sid sanity check. + * We just need _something_ here to get this node recognized by + * the SMMU driver. Our test uses ATOS, which doesn't use SIDs + * anyways, so using a dummy value is ok. + */ + iommus = <&kgsl_smmu 0x7>; + }; + + apps_iommu_test_device { + compatible = "iommu-debug-test"; + /* + * This SID belongs to TSIF. We can't use a fake SID for + * the apps_smmu device. + */ + iommus = <&apps_smmu 0x20 0>; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm640.dtsi b/arch/arm64/boot/dts/qcom/sdm640.dtsi index 83b097b3d624..74e81fc878dd 100644 --- a/arch/arm64/boot/dts/qcom/sdm640.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm640.dtsi @@ -986,3 +986,4 @@ }; #include "sdm640-ion.dtsi" +#include "msm-arm-smmu-sdm640.dtsi" -- GitLab From e795fce7db31ca11c1d95ac18d0a46dfff69fbe7 Mon Sep 17 00:00:00 2001 From: Jack Pham Date: Tue, 17 Apr 2018 23:45:13 -0700 Subject: [PATCH 0468/1635] power_supply: Add enums for POWER_SUPPLY_PROP_PD_ACTIVE Add enum definitions to use with POWER_SUPPLY_PROP_PD_ACTIVE to distinguish between whether a charger supports PD or not, and if PD, whether it also supports PPS. Change-Id: I4965292024cc48e13656f5bb30fa900af4174bc6 Signed-off-by: Jack Pham --- include/linux/power_supply.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h index f7179a1c462c..ea0d4f1544ef 100644 --- a/include/linux/power_supply.h +++ b/include/linux/power_supply.h @@ -125,6 +125,12 @@ enum { POWER_SUPPLY_PL_NON_STACKED_BATFET, }; +enum { + POWER_SUPPLY_PD_INACTIVE = 0, + POWER_SUPPLY_PD_ACTIVE, + POWER_SUPPLY_PD_PPS_ACTIVE, +}; + enum power_supply_property { /* Properties of type `int' */ POWER_SUPPLY_PROP_STATUS = 0, -- GitLab From 872e203c07b6e6a095c4f2ef35fbc195bcb79e2a Mon Sep 17 00:00:00 2001 From: Jack Pham Date: Tue, 3 Apr 2018 16:06:40 -0700 Subject: [PATCH 0469/1635] usb: pd: notify charger if source is PPS capable The charger driver may need to perform different charging behavior depending on whether the source is PPS capable or not. This can be determined when evaluating the source capabilities. If PPS capable, set PD_ACTIVE to 2. Use the new enum definitions POWER_SUPPLY_PD_ACTIVE, POWER_SUPPLY_PD_PPS_ACTIVE and POWER_SUPPLY_PD_INACTIVE for better readability. Change-Id: I2255fe404951e88a342095de21303358ae8ea50b Signed-off-by: Jack Pham --- drivers/usb/pd/policy_engine.c | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/drivers/usb/pd/policy_engine.c b/drivers/usb/pd/policy_engine.c index ad0c84629484..e07d067310b3 100644 --- a/drivers/usb/pd/policy_engine.c +++ b/drivers/usb/pd/policy_engine.c @@ -755,6 +755,7 @@ static int pd_eval_src_caps(struct usbpd *pd) { int i; union power_supply_propval val; + bool pps_found = false; u32 first_pdo = pd->received_pdos[0]; if (PD_SRC_PDO_TYPE(first_pdo) != PD_SRC_PDO_TYPE_FIXED) { @@ -774,10 +775,8 @@ static int pd_eval_src_caps(struct usbpd *pd) if (pd->peer_usb_comm && pd->current_dr == DR_UFP && !pd->pd_connected) start_usb_peripheral(pd); - if (pd->spec_rev == USBPD_REV_30 && !rev3_sink_only) { - bool pps_found = false; - - /* downgrade to 2.0 if no PPS */ + /* Check for PPS APDOs */ + if (pd->spec_rev == USBPD_REV_30) { for (i = 1; i < PD_MAX_DATA_OBJ; i++) { if ((PD_SRC_PDO_TYPE(pd->received_pdos[i]) == PD_SRC_PDO_TYPE_AUGMENTED) && @@ -786,10 +785,18 @@ static int pd_eval_src_caps(struct usbpd *pd) break; } } - if (!pps_found) + + /* downgrade to 2.0 if no PPS */ + if (!pps_found && !rev3_sink_only) pd->spec_rev = USBPD_REV_20; } + val.intval = pps_found ? + POWER_SUPPLY_PD_PPS_ACTIVE : + POWER_SUPPLY_PD_ACTIVE; + power_supply_set_property(pd->usb_psy, + POWER_SUPPLY_PROP_PD_ACTIVE, &val); + /* Select the first PDO (vSafe5V) immediately. */ pd_select_pdo(pd, 1, 0, 0); @@ -2125,7 +2132,7 @@ static void usbpd_sm(struct work_struct *w) usbpd_dbg(&pd->dev, "Src CapsCounter exceeded, disabling PD\n"); usbpd_set_state(pd, PE_SRC_DISABLED); - val.intval = 0; + val.intval = POWER_SUPPLY_PD_INACTIVE; power_supply_set_property(pd->usb_psy, POWER_SUPPLY_PROP_PD_ACTIVE, &val); @@ -2145,7 +2152,7 @@ static void usbpd_sm(struct work_struct *w) pd->current_state = PE_SRC_SEND_CAPABILITIES_WAIT; kick_sm(pd, SENDER_RESPONSE_TIME); - val.intval = 1; + val.intval = POWER_SUPPLY_PD_ACTIVE; power_supply_set_property(pd->usb_psy, POWER_SUPPLY_PROP_PD_ACTIVE, &val); break; @@ -2337,10 +2344,6 @@ static void usbpd_sm(struct work_struct *w) pd->src_cap_id++; usbpd_set_state(pd, PE_SNK_EVALUATE_CAPABILITY); - - val.intval = 1; - power_supply_set_property(pd->usb_psy, - POWER_SUPPLY_PROP_PD_ACTIVE, &val); } else if (pd->hard_reset_count < 3) { usbpd_set_state(pd, PE_SNK_HARD_RESET); } else { @@ -2351,7 +2354,7 @@ static void usbpd_sm(struct work_struct *w) POWER_SUPPLY_PROP_PD_IN_HARD_RESET, &val); - val.intval = 0; + val.intval = POWER_SUPPLY_PD_INACTIVE; power_supply_set_property(pd->usb_psy, POWER_SUPPLY_PROP_PD_ACTIVE, &val); } -- GitLab From 7b604a0dfa8d293cb9bdf6e6c3711d5f3abf923e Mon Sep 17 00:00:00 2001 From: Jack Pham Date: Wed, 4 Apr 2018 18:43:34 -0700 Subject: [PATCH 0470/1635] usb: pd: fix off-by-one in rdo_h_show When viewing rdo_h via sysfs, the request type is determined by looking up the type from the PDO list, however the obj_pos field is 1-based whereas the received_pdos is 0-based. This off-by-one error can result in misinterpretation of the request object, e.g. viewing a PPS request may show the fields for a Fixed request. Change-Id: If5f25cdadb7838b8f846ca90b16f8b17539d1e37 Signed-off-by: Jack Pham --- drivers/usb/pd/policy_engine.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/pd/policy_engine.c b/drivers/usb/pd/policy_engine.c index e07d067310b3..0f55135705cf 100644 --- a/drivers/usb/pd/policy_engine.c +++ b/drivers/usb/pd/policy_engine.c @@ -3575,7 +3575,7 @@ static ssize_t rdo_h_show(struct device *dev, struct device_attribute *attr, { struct usbpd *pd = dev_get_drvdata(dev); int pos = PD_RDO_OBJ_POS(pd->rdo); - int type = PD_SRC_PDO_TYPE(pd->received_pdos[pos]); + int type = PD_SRC_PDO_TYPE(pd->received_pdos[pos - 1]); int len; len = scnprintf(buf, PAGE_SIZE, "Request Data Object\n" -- GitLab From 947169fc3b9ba123d1ea623d37210b5991ce46be Mon Sep 17 00:00:00 2001 From: Jilai Wang Date: Tue, 10 Apr 2018 20:47:24 -0400 Subject: [PATCH 0471/1635] msm: npu: Update npu power level control Set npu to the power level based on use case information. Change-Id: Ie7e13431e45357a5ca2bf2a358b6b4b43f94fb43 Signed-off-by: Jilai Wang --- drivers/media/platform/msm/npu/npu_common.h | 17 ++- drivers/media/platform/msm/npu/npu_dev.c | 128 +++++++++++++------- drivers/media/platform/msm/npu/npu_mgr.c | 37 +++++- drivers/media/platform/msm/npu/npu_mgr.h | 2 + 4 files changed, 140 insertions(+), 44 deletions(-) diff --git a/drivers/media/platform/msm/npu/npu_common.h b/drivers/media/platform/msm/npu/npu_common.h index 26b96d7dcb53..4ef0506afd98 100644 --- a/drivers/media/platform/msm/npu/npu_common.h +++ b/drivers/media/platform/msm/npu/npu_common.h @@ -159,6 +159,19 @@ struct npu_pwrctrl { struct device *devbw; uint32_t bwmon_enabled; + uint32_t uc_pwrlevel; +}; + +/** + * struct npu_thermalctrl - Thermal control settings for a NPU device + * @max_state - maximum thermal mitigation state + * @current_state - current thermal mitigation state + * @pwr_level -power level that thermal control requested + */ +struct npu_thermalctrl { + unsigned long max_state; + unsigned long current_state; + uint32_t pwr_level; }; struct npu_device { @@ -195,6 +208,7 @@ struct npu_device { struct thermal_cooling_device *tcdev; struct npu_pwrctrl pwrctrl; + struct npu_thermalctrl thermalctrl; struct llcc_slice_desc *sys_cache; }; @@ -213,7 +227,8 @@ int npu_enable_post_pil_clocks(struct npu_device *npu_dev); irqreturn_t npu_intr_hdler(int irq, void *ptr); -int npu_set_power_level(struct npu_device *npu_dev, uint32_t pwr_level); +int npu_set_uc_power_level(struct npu_device *npu_dev, + uint32_t pwr_level); int fw_init(struct npu_device *npu_dev); void fw_deinit(struct npu_device *npu_dev); diff --git a/drivers/media/platform/msm/npu/npu_dev.c b/drivers/media/platform/msm/npu/npu_dev.c index f466b0c8b1bc..4abd72a66320 100644 --- a/drivers/media/platform/msm/npu/npu_dev.c +++ b/drivers/media/platform/msm/npu/npu_dev.c @@ -37,6 +37,8 @@ #define DDR_MAPPED_START_ADDR 0x80000000 #define DDR_MAPPED_SIZE 0x60000000 +#define PERF_MODE_DEFAULT 0 + #define POWER_LEVEL_MIN_SVS 0 #define POWER_LEVEL_LOW_SVS 1 #define POWER_LEVEL_NOMINAL 4 @@ -49,8 +51,7 @@ static int npu_enable_regulators(struct npu_device *npu_dev); static void npu_disable_regulators(struct npu_device *npu_dev); static int npu_enable_core_clocks(struct npu_device *npu_dev, bool post_pil); static void npu_disable_core_clocks(struct npu_device *npu_dev); -static int npu_calc_power_level(struct npu_device *npu_dev, - uint32_t perf_mode); +static uint32_t npu_calc_power_level(struct npu_device *npu_dev); static ssize_t npu_show_capabilities(struct device *dev, struct device_attribute *attr, char *buf); static ssize_t npu_show_pwr_state(struct device *dev, @@ -292,6 +293,11 @@ void npu_disable_core_power(struct npu_device *npu_dev) npu_disable_core_clocks(npu_dev); npu_disable_regulators(npu_dev); } + /* init the power levels back to default */ + pwr->active_pwrlevel = pwr->default_pwrlevel; + pwr->uc_pwrlevel = pwr->default_pwrlevel; + pr_debug("setting back to default power level=%d\n", + pwr->default_pwrlevel); } int npu_enable_post_pil_clocks(struct npu_device *npu_dev) @@ -299,26 +305,58 @@ int npu_enable_post_pil_clocks(struct npu_device *npu_dev) return npu_enable_core_clocks(npu_dev, true); } -int npu_set_power_level(struct npu_device *npu_dev, - uint32_t pwr_level) + +static uint32_t npu_calc_power_level(struct npu_device *npu_dev) +{ + uint32_t ret_level; + uint32_t therm_pwr_level = npu_dev->thermalctrl.pwr_level; + uint32_t active_pwr_level = npu_dev->pwrctrl.active_pwrlevel; + uint32_t uc_pwr_level = npu_dev->pwrctrl.uc_pwrlevel; + + /* if thermal power is higher than usecase power + * leave level at use case. Otherwise go down to + * thermal power level + */ + if (therm_pwr_level > uc_pwr_level) + ret_level = uc_pwr_level; + else + ret_level = therm_pwr_level; + + /* adjust the power level */ + /* force to lowsvs, minsvs not supported */ + if (ret_level == POWER_LEVEL_MIN_SVS) + ret_level = POWER_LEVEL_LOW_SVS; + + pr_debug("%s therm=%d active=%d uc=%d set level=%d\n", __func__, + therm_pwr_level, active_pwr_level, uc_pwr_level, ret_level); + + return ret_level; +} + +static int npu_set_power_level(struct npu_device *npu_dev) { struct npu_pwrctrl *pwr = &npu_dev->pwrctrl; struct npu_pwrlevel *pwrlevel; int i, ret = 0; long clk_rate = 0; + uint32_t pwr_level_to_set; if (!pwr->pwr_vote_num) { pr_err("power is not enabled during set request\n"); return -EINVAL; } - if (pwr_level == pwr->active_pwrlevel) + /* get power level to set */ + pwr_level_to_set = npu_calc_power_level(npu_dev); + + /* if the same as current, dont do anything */ + if (pwr_level_to_set == pwr->active_pwrlevel) return 0; - pr_debug("%s to [%d]\n", __func__, pwr_level); + pr_debug("setting power level to [%d]\n", pwr_level_to_set); - pwr->active_pwrlevel = pwr_level; - pwrlevel = &npu_dev->pwrctrl.pwrlevels[pwr_level]; + pwr->active_pwrlevel = pwr_level_to_set; + pwrlevel = &npu_dev->pwrctrl.pwrlevels[pwr->active_pwrlevel]; for (i = 0; i < npu_dev->core_clk_num; i++) { if (npu_is_exclude_rate_clock( @@ -338,6 +376,7 @@ int npu_set_power_level(struct npu_device *npu_dev, pwrlevel->clk_freq[i]); pr_debug("actual round clk rate [%ld]\n", clk_rate); + ret = clk_set_rate(npu_dev->core_clks[i].clk, clk_rate); if (ret) { pr_err("clk_set_rate %s to %ld failed with %d\n", @@ -350,20 +389,17 @@ int npu_set_power_level(struct npu_device *npu_dev, return ret; } -static int npu_calc_power_level(struct npu_device *npu_dev, +int npu_set_uc_power_level(struct npu_device *npu_dev, uint32_t perf_mode) { - int ret_level; + struct npu_pwrctrl *pwr = &npu_dev->pwrctrl; - if (perf_mode == 0) - ret_level = POWER_LEVEL_NOMINAL; - else if (perf_mode == POWER_LEVEL_MIN_SVS) - /* force to lowsvs, minsvs not supported */ - ret_level = POWER_LEVEL_LOW_SVS; + if (perf_mode == PERF_MODE_DEFAULT) + pwr->uc_pwrlevel = POWER_LEVEL_NOMINAL; else - ret_level = perf_mode-1; + pwr->uc_pwrlevel = perf_mode - 1; - return ret_level; + return npu_set_power_level(npu_dev); } /* ------------------------------------------------------------------------- @@ -513,11 +549,12 @@ static int npu_get_max_state(struct thermal_cooling_device *cdev, unsigned long *state) { struct npu_device *npu_dev = cdev->devdata; - struct npu_pwrctrl *pwr = &npu_dev->pwrctrl; + struct npu_thermalctrl *thermalctrl = &npu_dev->thermalctrl; - pr_debug("enter %s\n", __func__); + pr_debug("enter %s thermal max state=%lu\n", __func__, + thermalctrl->max_state); - *state = pwr->max_pwrlevel; + *state = thermalctrl->max_state; return 0; } @@ -526,11 +563,12 @@ static int npu_get_cur_state(struct thermal_cooling_device *cdev, unsigned long *state) { struct npu_device *npu_dev = cdev->devdata; - struct npu_pwrctrl *pwr = &npu_dev->pwrctrl; + struct npu_thermalctrl *thermal = &npu_dev->thermalctrl; - pr_debug("enter %s\n", __func__); + pr_debug("enter %s thermal current state=%lu\n", __func__, + thermal->current_state); - *state = pwr->max_pwrlevel - pwr->active_pwrlevel; + *state = thermal->current_state; return 0; } @@ -539,17 +577,17 @@ static int npu_set_cur_state(struct thermal_cooling_device *cdev, unsigned long state) { struct npu_device *npu_dev = cdev->devdata; + struct npu_thermalctrl *thermal = &npu_dev->thermalctrl; struct npu_pwrctrl *pwr = &npu_dev->pwrctrl; - uint32_t next_pwr_level; - - pr_debug("enter %s %lu\n", __func__, state); - if (state > pwr->max_pwrlevel) + pr_debug("enter %s request state=%lu\n", __func__, state); + if (state > thermal->max_state) return -EINVAL; - next_pwr_level = pwr->max_pwrlevel - state; + thermal->current_state = state; + thermal->pwr_level = pwr->max_pwrlevel - state; - return npu_set_power_level(npu_dev, next_pwr_level); + return npu_set_power_level(npu_dev); } /* ------------------------------------------------------------------------- @@ -786,7 +824,6 @@ static int npu_load_network(struct npu_device *npu_dev, unsigned long arg) struct msm_npu_load_network_ioctl req; void __user *argp = (void __user *)arg; int ret = 0; - uint32_t pwr_level_to_set; ret = copy_from_user(&req, argp, sizeof(req)); @@ -795,23 +832,14 @@ static int npu_load_network(struct npu_device *npu_dev, unsigned long arg) return -EFAULT; } - pr_debug("network load with perf request %d\n", req.flags); + pr_debug("network load with perf request %d\n", req.perf_mode); ret = npu_host_load_network(npu_dev, &req); if (ret) { - pr_err("npu_host_load_network failed\n"); - return ret; + pr_err("network load failed: %d\n", ret); + return -EFAULT; } - /* get the power level to set */ - pwr_level_to_set = npu_calc_power_level(npu_dev, req.flags); - - /* set the power level */ - ret = npu_set_power_level(npu_dev, pwr_level_to_set); - if (!ret) - pr_debug("network load pwr level set at %d\n", - pwr_level_to_set); - ret = copy_to_user(argp, &req, sizeof(req)); if (ret) { pr_err("fail to copy to user\n"); @@ -1071,6 +1099,7 @@ static int npu_of_parse_pwrlevels(struct npu_device *npu_dev, pr_debug("init power level %d\n", init_level); pwr->active_pwrlevel = init_level; pwr->default_pwrlevel = init_level; + pwr->uc_pwrlevel = init_level; pwr->min_pwrlevel = 0; pwr->max_pwrlevel = pwr->num_pwrlevels - 1; @@ -1121,6 +1150,17 @@ static int npu_pwrctrl_init(struct npu_device *npu_dev) return ret; } +static int npu_thermalctrl_init(struct npu_device *npu_dev) +{ + struct npu_pwrctrl *pwr = &npu_dev->pwrctrl; + struct npu_thermalctrl *thermalctrl = &npu_dev->thermalctrl; + int ret = 0; + + thermalctrl->max_state = pwr->max_pwrlevel; + thermalctrl->current_state = 0; + return ret; +} + /* ------------------------------------------------------------------------- * Probe/Remove * ------------------------------------------------------------------------- @@ -1161,6 +1201,10 @@ static int npu_probe(struct platform_device *pdev) if (rc) goto error_get_dev_num; + rc = npu_thermalctrl_init(npu_dev); + if (rc) + goto error_get_dev_num; + npu_dev->npu_base = devm_ioremap(&pdev->dev, res->start, npu_dev->reg_size); if (unlikely(!npu_dev->npu_base)) { diff --git a/drivers/media/platform/msm/npu/npu_mgr.c b/drivers/media/platform/msm/npu/npu_mgr.c index ecd742450090..e11e27978c03 100644 --- a/drivers/media/platform/msm/npu/npu_mgr.c +++ b/drivers/media/platform/msm/npu/npu_mgr.c @@ -454,6 +454,26 @@ void host_copy_patch_data(struct npu_patch_tuple *param, uint32_t value, layer_info->patch_info.variable_size_in_bits; } +static uint32_t find_networks_perf_mode(struct npu_host_ctx *host_ctx) +{ + struct npu_network *network; + uint32_t max_perf_mode = 0; + int i = 0; + + network = host_ctx->networks; + + /* find the max level among all the networks */ + for (i = 0; i < host_ctx->network_num; i++) { + if ((network->perf_mode != 0) && + (network->perf_mode > max_perf_mode)) + max_perf_mode = network->perf_mode; + network++; + } + pr_debug("max perf mode for networks: %d\n", max_perf_mode); + + return max_perf_mode; +} + int32_t npu_host_load_network(struct npu_device *npu_dev, struct msm_npu_load_network_ioctl *load_ioctl) { @@ -461,6 +481,7 @@ int32_t npu_host_load_network(struct npu_device *npu_dev, struct npu_network *network; struct ipc_cmd_load_pkt load_packet; struct npu_host_ctx *host_ctx = &npu_dev->host_ctx; + uint32_t networks_perf_mode = 0; ret = fw_init(npu_dev); if (ret) @@ -474,8 +495,18 @@ int32_t npu_host_load_network(struct npu_device *npu_dev, network->size = load_ioctl->buf_size; network->phy_add = load_ioctl->buf_phys_addr; network->first_block_size = load_ioctl->first_block_size; + network->priority = load_ioctl->priority; + network->perf_mode = load_ioctl->perf_mode; load_ioctl->network_hdl = network->id; + networks_perf_mode = find_networks_perf_mode(host_ctx); + + ret = npu_set_uc_power_level(npu_dev, networks_perf_mode); + if (ret) { + pr_err("network load failed due to power level set\n"); + goto error_free_network; + } + load_packet.header.cmd_type = NPU_IPC_CMD_LOAD; load_packet.header.size = sizeof(struct ipc_cmd_load_pkt); load_packet.header.trans_id = network->ipc_trans_id++; @@ -499,11 +530,15 @@ int32_t npu_host_load_network(struct npu_device *npu_dev, if (!wait_for_completion_interruptible_timeout( &host_ctx->load_done, NW_LOAD_TIMEOUT)) { pr_err_ratelimited("npu: NPU_IPC_CMD_LOAD time out\n"); - npu_dump_cal_state(npu_dev); ret = -ETIMEDOUT; + goto error_free_network; } return ret; + +error_free_network: + free_network(host_ctx, network->id); + return ret; } int32_t npu_host_unload_network(struct npu_device *npu_dev, diff --git a/drivers/media/platform/msm/npu/npu_mgr.h b/drivers/media/platform/msm/npu/npu_mgr.h index 035ac7c47f2d..a4ce88382cc8 100644 --- a/drivers/media/platform/msm/npu/npu_mgr.h +++ b/drivers/media/platform/msm/npu/npu_mgr.h @@ -48,6 +48,8 @@ struct npu_network { uint32_t first_block_size; uint32_t network_hdl; uint32_t ipc_trans_id; + uint32_t priority; + uint32_t perf_mode; }; struct npu_host_ctx { -- GitLab From a0783c8f08416647692fee6692057695a7f66474 Mon Sep 17 00:00:00 2001 From: Ajay Singh Parmar Date: Wed, 14 Mar 2018 19:34:46 -0700 Subject: [PATCH 0472/1635] drm/msm/dsi-staging: add parser sub-module Add the parser module to parse a given buffer of data into predefined data structures. Update the panel properties with the data parsed. CRs-Fixed: 2223812 Change-Id: I2212a55215d5ca1b128d552fd79b7b659d580ea7 Signed-off-by: Ajay Singh Parmar --- drivers/gpu/drm/msm/Makefile | 2 + drivers/gpu/drm/msm/dsi-staging/dsi_parser.c | 1247 ++++++++++++++++++ drivers/gpu/drm/msm/dsi-staging/dsi_parser.h | 244 ++++ 3 files changed, 1493 insertions(+) create mode 100644 drivers/gpu/drm/msm/dsi-staging/dsi_parser.c create mode 100644 drivers/gpu/drm/msm/dsi-staging/dsi_parser.h diff --git a/drivers/gpu/drm/msm/Makefile b/drivers/gpu/drm/msm/Makefile index ce105fb28270..98fdd007c875 100644 --- a/drivers/gpu/drm/msm/Makefile +++ b/drivers/gpu/drm/msm/Makefile @@ -150,6 +150,8 @@ msm_drm-$(CONFIG_DRM_MSM_DSI_STAGING) += dsi-staging/dsi_phy.o \ dsi-staging/dsi_clk_manager.o \ dsi-staging/dsi_display_test.o +msm_drm-$(CONFIG_DSI_PARSER) += dsi-staging/dsi_parser.o + msm_drm-$(CONFIG_DRM_MSM_DSI_PLL) += dsi/pll/dsi_pll.o \ dsi/pll/dsi_pll_28nm.o diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_parser.c b/drivers/gpu/drm/msm/dsi-staging/dsi_parser.c new file mode 100644 index 000000000000..1463bd491076 --- /dev/null +++ b/drivers/gpu/drm/msm/dsi-staging/dsi_parser.c @@ -0,0 +1,1247 @@ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#define pr_fmt(fmt) "[dsi-parser] %s: " fmt, __func__ + +#include +#include +#include +#include +#include +#include +#include + +#include "dsi_parser.h" + +#define DSI_PARSER_MAX_NODES 20 + +enum dsi_parser_prop_type { + DSI_PROP_TYPE_STR, + DSI_PROP_TYPE_STR_ARRAY, + DSI_PROP_TYPE_INT_SET, + DSI_PROP_TYPE_INT_SET_ARRAY, + DSI_PROP_TYPE_INT_ARRAY, +}; + +struct dsi_parser_prop { + char *name; + char *raw; + char *value; + char **items; + enum dsi_parser_prop_type type; + int len; +}; + +struct dsi_parser_node { + char *name; + char *data; + + struct dsi_parser_prop *prop; + int prop_count; + + struct dsi_parser_node *child[DSI_PARSER_MAX_NODES]; + int children_count; +}; + +struct dsi_parser { + const struct firmware *fw; + struct dsi_parser_node *head_node; + struct dsi_parser_node *current_node; + struct device *dev; + char *buf; + char file_name[SZ_32]; +}; + +static int dsi_parser_count(char *buf, int item) +{ + int count = 0; + + do { + buf = strnchr(buf, strlen(buf), item); + if (buf) + count++; + } while (buf++); + + return count; +} + +static char *dsi_parser_clear_tail(char *buf) +{ + int size = strlen(buf); + char *end; + + if (!size) + goto exit; + + end = buf + size - 1; + while (end >= buf && *end == '*') + end--; + + *(end + 1) = '\0'; +exit: + return buf; +} + +static char *dsi_parser_strim(char *buf) +{ + strreplace(buf, '*', ' '); + + return strim(buf); +} + +static char *dsi_parser_get_data(char *start, char *end, char *str) +{ + strsep(&str, start); + if (str) + return dsi_parser_clear_tail(strsep(&str, end)); + + return NULL; +} + +static bool dsi_parser_get_tuplets_data( + struct dsi_parser_prop *prop, char *str) +{ + bool middle_of_tx = false; + + while (str) { + char *out = strsep(&str, " "); + + if (str || middle_of_tx) { + middle_of_tx = true; + + prop->items[prop->len++] = dsi_parser_strim(out); + } + } + + return middle_of_tx; +} + +static bool dsi_parser_get_strings(struct device *dev, + struct dsi_parser_prop *prop, char *str) +{ + bool middle_of_tx = false; + int i = 0; + int count = 0; + + if (!dsi_parser_count(str, '"')) + goto end; + + count = dsi_parser_count(str, ','); + pr_debug("count=%d\n", count); + + if (!count) { + prop->value = dsi_parser_get_data("\"", "\"", str); + prop->type = DSI_PROP_TYPE_STR; + middle_of_tx = prop->value ? true : false; + + goto end; + } + + /* number of items are 1 more than separator */ + count++; + prop->items = devm_kzalloc(dev, count, GFP_KERNEL); + if (!prop->items) + goto end; + + prop->type = DSI_PROP_TYPE_STR_ARRAY; + + while (str) { + char *out = strsep(&str, ","); + + if ((str || middle_of_tx) && (i < count)) { + prop->items[i++] = + dsi_parser_get_data("\"", "\"", out); + prop->len++; + + middle_of_tx = true; + } + } +end: + return middle_of_tx; +} + +static bool dsi_parser_get_tuplets(struct device *dev, + struct dsi_parser_prop *prop, char *str) +{ + bool middle_of_tx = false; + char *data = NULL; + + while (str) { + char *out = strsep(&str, ","); + + if (str || middle_of_tx) { + data = dsi_parser_get_data("<", ">", out); + middle_of_tx = true; + + dsi_parser_get_tuplets_data(prop, data); + } + } + + return middle_of_tx; +} + +static void dsi_parser_get_int_value(struct dsi_parser_prop *prop, + int forced_base) +{ + int i; + + for (i = 0; i < prop->len; i++) { + int base, val; + + if (forced_base) { + base = forced_base; + } else { + char *to_int = strsep(&prop->items[i], "x"); + + if (!prop->items[i]) { + prop->items[i] = to_int; + base = 10; + } else { + base = 16; + } + } + + if (kstrtoint(prop->items[i], base, &val)) { + pr_err("error converting %s at %d\n", + prop->items[i], i); + + continue; + } + + prop->value[i] = val & 0xFF; + } +} + +static bool dsi_parser_parse_prop(struct device *dev, + struct dsi_parser_prop *prop, char *buf) +{ + bool found = false; + char *out = strsep(&buf, "="); + + if (!out || !buf) + goto end; + + prop->raw = devm_kzalloc(dev, strlen(buf) + 1, GFP_KERNEL); + if (!prop->raw) + goto end; + + strlcpy(prop->raw, buf, strlen(buf) + 1); + + found = true; + + prop->name = dsi_parser_strim(out); + pr_debug("RAW: %s: %s\n", prop->name, prop->raw); + + prop->len = 0; + + if (dsi_parser_get_strings(dev, prop, buf)) + goto end; + + prop->items = devm_kzalloc(dev, strlen(buf) * 2, GFP_KERNEL); + if (!prop->items) + goto end; + + if (dsi_parser_get_tuplets(dev, prop, buf)) { + prop->value = devm_kzalloc(dev, prop->len, GFP_KERNEL); + if (prop->value) { + prop->type = DSI_PROP_TYPE_INT_SET_ARRAY; + dsi_parser_get_int_value(prop, 0); + } + goto end; + } + + prop->value = dsi_parser_get_data("<", ">", buf); + if (prop->value) { + if (dsi_parser_get_tuplets_data(prop, prop->value)) { + prop->value = devm_kzalloc(dev, prop->len, GFP_KERNEL); + if (prop->value) { + prop->type = DSI_PROP_TYPE_INT_SET; + dsi_parser_get_int_value(prop, 0); + } + goto end; + } else { + prop->items[prop->len++] = prop->value; + } + + goto end; + } + + prop->value = dsi_parser_get_data("[", "]", buf); + if (prop->value) { + char *out5; + + if (!prop->items) + goto end; + + out5 = prop->value; + while (out5 && strlen(out5)) { + char *out6 = strsep(&out5, " "); + + out6 = dsi_parser_strim(out6); + if (out6 && strlen(out6)) + prop->items[prop->len++] = out6; + }; + + prop->value = devm_kzalloc(dev, prop->len, GFP_KERNEL); + if (prop->value) { + prop->type = DSI_PROP_TYPE_INT_ARRAY; + + dsi_parser_get_int_value(prop, 16); + } + } else { + found = false; + } +end: + return found; +} + +static char *dsi_parser_clean_name(char *name) +{ + char *clean_name = name; + + while (name) + clean_name = strsep(&name, ";"); + + return dsi_parser_strim(clean_name); +} + +static char *dsi_parser_get_blob(char **buf, bool *has_child) +{ + char *data = NULL; + char *start = *buf; + + data = strpbrk(*buf, "{}"); + if (!data) + goto end; + + if (*data == '{') + *has_child = true; + + if (*has_child) { + while (data != *buf) { + data--; + if (*data == ';') { + data++; + *data = '\0'; + *buf = data + 1; + break; + } + } + } else { + *data = '\0'; + *buf = data + 1; + } +end: + return start; +} + +static struct dsi_parser_node *dsi_parser_find_nodes(struct device *dev, + char **buf) +{ + struct dsi_parser_node *node = NULL, *cnode = NULL; + char *name, *data; + bool has_child = false; + + if (!buf) + goto end; + + data = strpbrk(*buf, "{}"); + if (!data) { + pr_debug("{} not found\n"); + goto end; + } + + if (*data == '}') { + *buf = data + 1; + goto end; + } + + name = strsep(buf, "{"); + + if (*buf && name) { + node = devm_kzalloc(dev, sizeof(*node), GFP_KERNEL); + if (!node) + goto end; + + node->name = dsi_parser_clean_name(name); + node->data = dsi_parser_get_blob(buf, &has_child); + + if (!has_child) + goto end; + + do { + cnode = dsi_parser_find_nodes(dev, buf); + if (cnode && + (node->children_count < DSI_PARSER_MAX_NODES)) + node->child[node->children_count++] = cnode; + } while (cnode); + } +end: + return node; +} + +static void dsi_parser_count_properties(struct dsi_parser_node *node) +{ + int count; + + if (node && strlen(node->data)) { + node->prop_count = dsi_parser_count(node->data, ';'); + + for (count = 0; count < node->children_count; count++) + dsi_parser_count_properties(node->child[count]); + } +} + +static void dsi_parser_get_properties(struct device *dev, + struct dsi_parser_node *node) +{ + int count; + + if (!node) + return; + + if (node->prop_count) { + int i = 0; + char *buf = node->data; + + node->prop = devm_kcalloc(dev, node->prop_count, + sizeof(struct dsi_parser_prop), + GFP_KERNEL); + if (!node->prop) + return; + + for (i = 0; i < node->prop_count; i++) { + char *out = strsep(&buf, ";"); + struct dsi_parser_prop *prop = &node->prop[i]; + + if (!out || !prop) + continue; + + if (!dsi_parser_parse_prop(dev, prop, out)) { + char *out1 = strsep(&out, "}"); + + if (!out1) + continue; + + out1 = dsi_parser_strim(out1); + + if (!out && strlen(out1)) { + prop->name = out1; + prop->value = "1"; + } + } + } + } + + for (count = 0; count < node->children_count; count++) + dsi_parser_get_properties(dev, node->child[count]); +} + +static struct dsi_parser_prop *dsi_parser_search_property( + struct dsi_parser_node *node, + const char *name) +{ + int i = 0; + struct dsi_parser_prop *prop = node->prop; + + for (i = 0; i < node->prop_count; i++) { + if (prop[i].name && !strcmp(prop[i].name, name)) + return &prop[i]; + } + + return NULL; +} + +/* APIs for the clients */ +struct property *dsi_parser_find_property(const struct device_node *np, + const char *name, + int *lenp) +{ + struct dsi_parser_node *node = (struct dsi_parser_node *)np; + struct dsi_parser_prop *prop = NULL; + + if (!node || !name || !lenp) + goto end; + + prop = dsi_parser_search_property(node, name); + if (!prop) { + pr_debug("%s not found\n", name); + goto end; + } else { + *lenp = strlen(prop->raw); + } + + pr_debug("%s: len=%d\n", name, *lenp); +end: + return (struct property *)prop; +} + +bool dsi_parser_read_bool(const struct device_node *np, + const char *propname) +{ + struct dsi_parser_node *node = (struct dsi_parser_node *)np; + bool prop_set; + + prop_set = dsi_parser_search_property(node, propname) ? true : false; + + pr_debug("%s=%s\n", propname, prop_set ? "set" : "not set"); + + return prop_set; +} + +int dsi_parser_read_string(const struct device_node *np, + const char *propname, const char **out_string) +{ + struct dsi_parser_node *node = (struct dsi_parser_node *)np; + struct dsi_parser_prop *prop; + char *property = NULL; + int rc = 0; + + prop = dsi_parser_search_property(node, propname); + if (!prop) { + pr_debug("%s not found\n", propname); + rc = -EINVAL; + } else { + property = prop->value; + } + + *out_string = property; + + pr_debug("%s=%s\n", propname, *out_string); + return rc; +} + +int dsi_parser_read_u64(const struct device_node *np, const char *propname, + u64 *out_value) +{ + return -EINVAL; +} + +int dsi_parser_read_u32(const struct device_node *np, + const char *propname, u32 *out_value) +{ + struct dsi_parser_node *node = (struct dsi_parser_node *)np; + struct dsi_parser_prop *prop; + char *property = NULL; + char *to_int; + int rc = 0, base; + + prop = dsi_parser_search_property(node, propname); + if (!prop) { + pr_debug("%s not found\n", propname); + rc = -EINVAL; + goto end; + } else { + property = prop->value; + } + + to_int = strsep(&property, "x"); + + if (!property) { + property = to_int; + base = 10; + } else { + base = 16; + } + + if (!property) + goto end; + + rc = kstrtoint(property, base, out_value); + if (rc) { + pr_err("error(%d) converting %s\n", rc, property); + goto end; + } + + pr_debug("%s=%d\n", propname, *out_value); +end: + return rc; +} + +int dsi_parser_read_u32_array(const struct device_node *np, + const char *propname, + u32 *out_values, size_t sz) +{ + int i, rc = 0; + struct dsi_parser_node *node = (struct dsi_parser_node *)np; + struct dsi_parser_prop *prop; + + prop = dsi_parser_search_property(node, propname); + if (!prop) { + pr_debug("%s not found\n", propname); + rc = -EINVAL; + goto end; + } + + for (i = 0; i < prop->len; i++) { + int base, val; + char *to_int = strsep(&prop->items[i], "x"); + + if (!prop->items[i]) { + prop->items[i] = to_int; + base = 10; + } else { + base = 16; + } + + if (!prop->items[i]) + continue; + + if (kstrtoint(prop->items[i], base, &val)) { + pr_err("error converting %s at %d\n", + prop->items[i], i); + + continue; + } + + *out_values++ = val; + + pr_debug("%s: [%d]=%d\n", propname, i, *(out_values - 1)); + } +end: + return rc; +} + +const void *dsi_parser_get_property(const struct device_node *np, + const char *name, int *lenp) +{ + struct dsi_parser_node *node = (struct dsi_parser_node *)np; + struct dsi_parser_prop *prop; + char *property = NULL; + + prop = dsi_parser_search_property(node, name); + if (!prop) { + pr_debug("%s not found\n", name); + goto end; + } + + property = prop->value; + + if (prop->type == DSI_PROP_TYPE_STR) + pr_debug("%s=%s\n", name, property); + + if (lenp) { + if (prop->type == DSI_PROP_TYPE_INT_ARRAY) + *lenp = prop->len; + else + *lenp = strlen(prop->raw) + 1; + + pr_debug("%s len=%d\n", name, *lenp); + } +end: + return property; +} + +struct device_node *dsi_parser_get_child_by_name(const struct device_node *np, + const char *name) +{ + int index = 0; + struct dsi_parser_node *node = (struct dsi_parser_node *)np; + struct dsi_parser_node *matched_node = NULL; + + if (!node || !node->children_count) + goto end; + + do { + struct dsi_parser_node *child_node = node->child[index++]; + + if (!child_node) + goto end; + + if (!strcmp(child_node->name, name)) { + matched_node = child_node; + break; + } + } while (index < node->children_count); +end: + pr_debug("%s: %s\n", name, matched_node ? "found" : "not found"); + + return (struct device_node *)matched_node; +} + +struct dsi_parser_node *dsi_parser_get_node_by_name( + struct dsi_parser_node *node, + char *name) +{ + int count = 0; + struct dsi_parser_node *matched_node = NULL; + + if (!node) { + pr_err("node is null\n"); + goto end; + } + + if (!strcmp(node->name, name)) { + matched_node = node; + goto end; + } + + for (count = 0; count < node->children_count; count++) { + matched_node = dsi_parser_get_node_by_name( + node->child[count], name); + if (matched_node) + break; + } +end: + pr_debug("%s: %s\n", name, matched_node ? "found" : "not found"); + + return matched_node; +} + +int dsi_parser_get_child_count(const struct device_node *np) +{ + struct dsi_parser_node *node = (struct dsi_parser_node *)np; + int count = 0; + + if (node) { + count = node->children_count; + pr_debug("node %s child count=%d\n", node->name, count); + } + + return count; +} + +struct device_node *dsi_parser_get_next_child(const struct device_node *np, + struct device_node *prev) +{ + int index = 0; + struct dsi_parser_node *parent = (struct dsi_parser_node *)np; + struct dsi_parser_node *prev_child = (struct dsi_parser_node *)prev; + struct dsi_parser_node *matched_node = NULL; + + if (!parent || !parent->children_count) + goto end; + + do { + struct dsi_parser_node *child_node = parent->child[index++]; + + if (!child_node) + goto end; + + if (!prev) { + matched_node = child_node; + goto end; + } + + if (!strcmp(child_node->name, prev_child->name)) { + if (index < parent->children_count) + matched_node = parent->child[index]; + break; + } + } while (index < parent->children_count); +end: + if (matched_node) + pr_debug("next child: %s\n", matched_node->name); + + return (struct device_node *)matched_node; +} + +int dsi_parser_count_u32_elems(const struct device_node *np, + const char *propname) +{ + int count = 0; + struct dsi_parser_node *node = (struct dsi_parser_node *)np; + struct dsi_parser_prop *prop; + + prop = dsi_parser_search_property(node, propname); + if (!prop) { + pr_debug("%s not found\n", propname); + goto end; + } + + count = prop->len; + + pr_debug("prop %s has %d items\n", prop->name, count); +end: + return count; +} + +int dsi_parser_count_strings(const struct device_node *np, + const char *propname) +{ + int count = 0; + struct dsi_parser_node *node = (struct dsi_parser_node *)np; + struct dsi_parser_prop *prop; + + prop = dsi_parser_search_property(node, propname); + if (!prop) { + pr_debug("%s not found\n", propname); + goto end; + } + + if (prop->type == DSI_PROP_TYPE_STR_ARRAY) + count = prop->len; + else if (prop->type == DSI_PROP_TYPE_STR) + count = 1; + + pr_debug("prop %s has %d items\n", prop->name, count); +end: + return count; +} + +int dsi_parser_read_string_index(const struct device_node *np, + const char *propname, + int index, const char **output) +{ + struct dsi_parser_node *node = (struct dsi_parser_node *)np; + struct dsi_parser_prop *prop; + + prop = dsi_parser_search_property(node, propname); + if (!prop) { + pr_debug("%s not found\n", propname); + goto end; + } + + if (prop->type != DSI_PROP_TYPE_STR_ARRAY) { + pr_err("not a string array property\n"); + goto end; + } + + if (index >= prop->len) { + pr_err("out of bond index %d\n", index); + goto end; + } + + *output = prop->items[index]; + + return 0; +end: + return -EINVAL; +} + +int dsi_parser_get_named_gpio(struct device_node *np, + const char *propname, int index) +{ + int gpio = -EINVAL; + + dsi_parser_read_u32(np, propname, &gpio); + + return gpio; +} + +void *dsi_parser_get_head_node(void *in, + const u8 *data, u32 size) +{ + struct dsi_parser *parser = in; + char *buf; + + if (!parser || !data || !size) { + pr_err("invalid input\n"); + goto err; + } + + parser->buf = devm_kzalloc(parser->dev, size, GFP_KERNEL); + if (!parser->buf) + goto err; + + buf = parser->buf; + + memcpy(buf, data, size); + + strreplace(buf, '\n', ' '); + strreplace(buf, '\t', '*'); + + parser->head_node = dsi_parser_find_nodes(parser->dev, &buf); + if (!parser->head_node) { + pr_err("could not get head node\n"); + devm_kfree(parser->dev, parser->buf); + goto err; + } + + dsi_parser_count_properties(parser->head_node); + dsi_parser_get_properties(parser->dev, parser->head_node); + + parser->current_node = parser->head_node; + + return parser->head_node; +err: + return NULL; +} + +static int dsi_parser_check_buffer_overflow(int rc, int *max_size, int *len) +{ + if (rc >= *max_size) { + pr_err("buffer overflow, rc=%d, max_size=%d\n", + rc, *max_size); + return -ENOMEM; + } + *len += rc; + *max_size = SZ_4K - *len; + + return 0; +} + +static int dsi_parser_read_file(struct dsi_parser *parser, + const u8 **buf, u32 *size) +{ + int rc = 0; + + release_firmware(parser->fw); + + rc = request_firmware(&parser->fw, parser->file_name, parser->dev); + if (rc || !parser->fw) { + pr_err("couldn't read firmware\n"); + goto end; + } + + *buf = parser->fw->data; + *size = parser->fw->size; + + pr_debug("file %s: size %zd\n", + parser->file_name, parser->fw->size); +end: + return rc; +} + +static void dsi_parser_free_mem(struct device *dev, + struct dsi_parser_node *node) +{ + int i = 0; + + if (!node) + return; + + pr_debug("node=%s, prop_count=%d\n", node->name, node->prop_count); + + for (i = 0; i < node->prop_count; i++) { + struct dsi_parser_prop *prop = &node->prop[i]; + + if (!prop) + continue; + + pr_debug("deleting prop=%s\n", prop->name); + + if (prop->items) + devm_kfree(dev, prop->items); + + if (prop->raw) + devm_kfree(dev, prop->raw); + + if ((prop->type == DSI_PROP_TYPE_INT_SET_ARRAY || + prop->type == DSI_PROP_TYPE_INT_SET || + prop->type == DSI_PROP_TYPE_INT_ARRAY) && prop->value) + devm_kfree(dev, prop->value); + } + + if (node->prop) + devm_kfree(dev, node->prop); + + for (i = 0; i < node->children_count; i++) + dsi_parser_free_mem(dev, node->child[i]); + + devm_kfree(dev, node); +} + +static ssize_t dsi_parser_write_init(struct file *file, + const char __user *user_buff, size_t count, loff_t *ppos) +{ + struct dsi_parser *parser = file->private_data; + const u8 *data = NULL; + u32 size = 0; + char buf[SZ_32]; + size_t len = 0; + + if (!parser) + return -ENODEV; + + if (*ppos) + return 0; + + /* Leave room for termination char */ + len = min_t(size_t, count, SZ_32 - 1); + if (copy_from_user(buf, user_buff, len)) + goto end; + + buf[len] = '\0'; + + if (sscanf(buf, "%31s", parser->file_name) != 1) { + pr_err("failed to get val\n"); + goto end; + } + + if (dsi_parser_read_file(parser, &data, &size)) { + pr_err("failed to read file\n"); + goto end; + } + + dsi_parser_free_mem(parser->dev, parser->head_node); + + if (parser->buf) { + devm_kfree(parser->dev, parser->buf); + parser->buf = NULL; + } + + parser->head_node = dsi_parser_get_head_node(parser, data, size); + if (!parser->head_node) { + pr_err("failed to parse data\n"); + goto end; + } +end: + return len; +} + +static ssize_t dsi_parser_read_node(struct file *file, + char __user *user_buff, size_t count, loff_t *ppos) +{ + char *buf = NULL; + int i, j, len = 0, rc = 0, max_size = SZ_4K; + struct dsi_parser *parser = file->private_data; + struct dsi_parser_node *node; + struct dsi_parser_prop *prop; + + if (!parser) { + len = -ENODEV; + goto error; + } + + if (*ppos) + goto error; + + buf = devm_kzalloc(parser->dev, SZ_4K, GFP_KERNEL); + if (!buf) { + len = -ENOMEM; + goto error; + } + + node = parser->current_node; + if (!node) { + len = -EINVAL; + goto error; + } + + prop = node->prop; + + rc = snprintf(buf + len, max_size, "node name=%s\n", node->name); + rc = dsi_parser_check_buffer_overflow(rc, &max_size, &len); + if (rc) + goto error; + + rc = snprintf(buf + len, max_size, "children count=%d\n", + node->children_count); + rc = dsi_parser_check_buffer_overflow(rc, &max_size, &len); + if (rc) + goto error; + + for (i = 0; i < node->children_count; i++) { + rc = snprintf(buf + len, max_size, "child[%d]=%s\n", + i, node->child[i]->name); + rc = dsi_parser_check_buffer_overflow(rc, &max_size, &len); + if (rc) + goto error; + } + + for (i = 0; i < node->prop_count; i++) { + if (!prop[i].name) + continue; + + rc = snprintf(buf + len, max_size, + "property=%s\n", prop[i].name); + rc = dsi_parser_check_buffer_overflow(rc, &max_size, &len); + if (rc) + goto error; + + if (prop[i].value) { + if (prop[i].type == DSI_PROP_TYPE_STR) { + rc = snprintf(buf + len, max_size, + "value=%s\n", prop[i].value); + rc = dsi_parser_check_buffer_overflow( + rc, &max_size, &len); + if (rc) + goto error; + } else { + for (j = 0; j < prop[i].len; j++) { + rc = snprintf(buf + len, max_size, + "%x", prop[i].value[j]); + rc = dsi_parser_check_buffer_overflow( + rc, &max_size, &len); + if (rc) + goto error; + } + + rc = snprintf(buf + len, max_size, "\n"); + rc = dsi_parser_check_buffer_overflow( + rc, &max_size, &len); + if (rc) + goto error; + + } + } + + if (prop[i].len) { + rc = snprintf(buf + len, max_size, "items:\n"); + rc = dsi_parser_check_buffer_overflow(rc, &max_size, + &len); + if (rc) + goto error; + } + + for (j = 0; j < prop[i].len; j++) { + char delim; + + if (j && !(j % 10)) + delim = '\n'; + else + delim = ' '; + + rc = snprintf(buf + len, max_size, "%s%c", + prop[i].items[j], delim); + rc = dsi_parser_check_buffer_overflow(rc, &max_size, + &len); + if (rc) + goto error; + } + + rc = snprintf(buf + len, max_size, "\n\n"); + rc = dsi_parser_check_buffer_overflow(rc, &max_size, &len); + if (rc) + goto error; + } +error: + if (copy_to_user(user_buff, buf, len)) { + len = -EFAULT; + goto error; + } + *ppos += len; + + if (buf) + devm_kfree(parser->dev, buf); + + return len; +} + +static ssize_t dsi_parser_write_node(struct file *file, + const char __user *user_buff, size_t count, loff_t *ppos) +{ + struct dsi_parser *parser = file->private_data; + char buf[SZ_512]; + size_t len = 0; + + if (!parser) + return -ENODEV; + + if (*ppos) + return 0; + + /* Leave room for termination char */ + len = min_t(size_t, count, SZ_512 - 1); + if (copy_from_user(buf, user_buff, len)) + goto end; + + buf[len] = '\0'; + + strreplace(buf, '\n', ' '); + + if (!strcmp(strim(buf), "head_node")) + parser->current_node = parser->head_node; + else + parser->current_node = dsi_parser_get_node_by_name( + parser->head_node, strim(buf)); +end: + return len; +} + +static const struct file_operations dsi_parser_init_fops = { + .open = simple_open, + .write = dsi_parser_write_init, +}; + +static const struct file_operations dsi_parser_node_fops = { + .open = simple_open, + .read = dsi_parser_read_node, + .write = dsi_parser_write_node, +}; + +int dsi_parser_dbg_init(void *parser, struct dentry *parent_dir) +{ + int rc = 0; + struct dentry *dir, *file; + + if (!parser || !parent_dir) { + pr_err("invalid input\n"); + goto end; + } + + dir = debugfs_create_dir("parser", parent_dir); + if (IS_ERR_OR_NULL(dir)) { + rc = PTR_ERR(dir); + + pr_err("failed to create parser debugfs\n"); + goto end; + } + + file = debugfs_create_file("init", 0644, dir, + parser, &dsi_parser_init_fops); + if (IS_ERR_OR_NULL(file)) { + rc = PTR_ERR(file); + + pr_err("failed to create init debugfs\n"); + goto dbg; + } + + file = debugfs_create_file("node", 0644, dir, + parser, &dsi_parser_node_fops); + if (IS_ERR_OR_NULL(file)) { + rc = PTR_ERR(file); + + pr_err("failed to create init debugfs\n"); + goto dbg; + } + + pr_debug("success\n"); + return 0; +dbg: + debugfs_remove_recursive(dir); +end: + return rc; +} + +void *dsi_parser_get(struct device *dev) +{ + int rc = 0; + struct dsi_parser *parser = NULL; + + if (!dev) { + pr_err("invalid data\n"); + rc = -EINVAL; + goto end; + } + + parser = devm_kzalloc(dev, sizeof(*parser), GFP_KERNEL); + if (!parser) { + rc = -ENOMEM; + goto end; + } + + parser->dev = dev; + + strlcpy(parser->file_name, "dsi_prop", sizeof(parser->file_name)); + + return parser; +end: + return ERR_PTR(rc); +} + +void dsi_parser_put(void *data) +{ + struct dsi_parser *parser = data; + + if (!parser) + return; + + dsi_parser_free_mem(parser->dev, parser->head_node); + + devm_kfree(parser->dev, parser->buf); + devm_kfree(parser->dev, parser); +} + diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_parser.h b/drivers/gpu/drm/msm/dsi-staging/dsi_parser.h new file mode 100644 index 000000000000..273a180a53da --- /dev/null +++ b/drivers/gpu/drm/msm/dsi-staging/dsi_parser.h @@ -0,0 +1,244 @@ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef _DSI_PARSER_H_ +#define _DSI_PARSER_H_ + +#include +#include + +#ifdef CONFIG_DSI_PARSER +void *dsi_parser_get(struct device *dev); +void dsi_parser_put(void *data); +int dsi_parser_dbg_init(void *parser, struct dentry *dir); +void *dsi_parser_get_head_node(void *parser, + const u8 *data, u32 size); + +const void *dsi_parser_get_property(const struct device_node *np, + const char *name, int *lenp); +bool dsi_parser_read_bool(const struct device_node *np, + const char *propname); +int dsi_parser_read_u64(const struct device_node *np, const char *propname, + u64 *out_value); +int dsi_parser_read_u32(const struct device_node *np, + const char *propname, u32 *out_value); +int dsi_parser_read_u32_array(const struct device_node *np, + const char *propname, + u32 *out_values, size_t sz); +int dsi_parser_read_string(const struct device_node *np, + const char *propname, const char **out_string); +struct device_node *dsi_parser_get_child_by_name(const struct device_node *node, + const char *name); +int dsi_parser_get_child_count(const struct device_node *np); +struct property *dsi_parser_find_property(const struct device_node *np, + const char *name, int *lenp); +struct device_node *dsi_parser_get_next_child(const struct device_node *np, + struct device_node *prev); +int dsi_parser_count_u32_elems(const struct device_node *np, + const char *propname); +int dsi_parser_count_strings(const struct device_node *np, + const char *propname); +int dsi_parser_read_string_index(const struct device_node *np, + const char *propname, + int index, const char **output); +int dsi_parser_get_named_gpio(struct device_node *np, + const char *propname, int index); +#else /* CONFIG_DSI_PARSER */ +static inline void *dsi_parser_get(struct device *dev) +{ + return NULL; +} + +static inline void dsi_parser_put(void *data) +{ +} + +static inline int dsi_parser_dbg_init(void *parser, struct dentry *dir) +{ + return -ENODEV; +} + +static inline void *dsi_parser_get_head_node(void *parser, + const u8 *data, u32 size) +{ + return NULL; +} + +static inline const void *dsi_parser_get_property(const struct device_node *np, + const char *name, int *lenp) +{ + return NULL; +} + +static inline bool dsi_parser_read_bool(const struct device_node *np, + const char *propname) +{ + return false; +} + +static inline int dsi_parser_read_u64(const struct device_node *np, + const char *propname, u64 *out_value) +{ + return -ENODEV; +} + +static inline int dsi_parser_read_u32(const struct device_node *np, + const char *propname, u32 *out_value) +{ + return -ENODEV; +} + +static inline int dsi_parser_read_u32_array(const struct device_node *np, + const char *propname, u32 *out_values, size_t sz) +{ + return -ENODEV; +} + +static inline int dsi_parser_read_string(const struct device_node *np, + const char *propname, const char **out_string) +{ + return -ENODEV; +} + +static inline struct device_node *dsi_parser_get_child_by_name( + const struct device_node *node, + const char *name) +{ + return NULL; +} + +static inline int dsi_parser_get_child_count(const struct device_node *np) +{ + return -ENODEV; +} + +static inline struct property *dsi_parser_find_property( + const struct device_node *np, + const char *name, int *lenp) +{ + return NULL; +} + +static inline struct device_node *dsi_parser_get_next_child( + const struct device_node *np, + struct device_node *prev) +{ + return NULL; +} + +static inline int dsi_parser_count_u32_elems(const struct device_node *np, + const char *propname) +{ + return -ENODEV; +} + +static inline int dsi_parser_count_strings(const struct device_node *np, + const char *propname) +{ + return -ENODEV; +} + +static inline int dsi_parser_read_string_index(const struct device_node *np, + const char *propname, + int index, const char **output) +{ + return -ENODEV; +} + +static inline int dsi_parser_get_named_gpio(struct device_node *np, + const char *propname, int index) +{ + return -ENODEV; +} + +#endif /* CONFIG_DSI_PARSER */ + +#define dsi_for_each_child_node(parent, child) \ + for (child = utils->get_next_child(parent, NULL); \ + child != NULL; \ + child = utils->get_next_child(parent, child)) + +struct dsi_parser_utils { + void *data; + struct device_node *node; + + const void *(*get_property)(const struct device_node *np, + const char *name, int *lenp); + int (*read_u64)(const struct device_node *np, + const char *propname, u64 *out_value); + int (*read_u32)(const struct device_node *np, + const char *propname, u32 *out_value); + bool (*read_bool)(const struct device_node *np, + const char *propname); + int (*read_u32_array)(const struct device_node *np, + const char *propname, u32 *out_values, size_t sz); + int (*read_string)(const struct device_node *np, const char *propname, + const char **out_string); + struct device_node *(*get_child_by_name)( + const struct device_node *node, + const char *name); + int (*get_child_count)(const struct device_node *np); + struct property *(*find_property)(const struct device_node *np, + const char *name, int *lenp); + struct device_node *(*get_next_child)(const struct device_node *np, + struct device_node *prev); + int (*count_u32_elems)(const struct device_node *np, + const char *propname); + int (*get_named_gpio)(struct device_node *np, + const char *propname, int index); + int (*get_available_child_count)(const struct device_node *np); +}; + +static inline struct dsi_parser_utils *dsi_parser_get_of_utils(void) +{ + static struct dsi_parser_utils of_utils = { + .get_property = of_get_property, + .read_bool = of_property_read_bool, + .read_u64 = of_property_read_u64, + .read_u32 = of_property_read_u32, + .read_u32_array = of_property_read_u32_array, + .read_string = of_property_read_string, + .get_child_by_name = of_get_child_by_name, + .get_child_count = of_get_child_count, + .get_available_child_count = of_get_available_child_count, + .find_property = of_find_property, + .get_next_child = of_get_next_child, + .count_u32_elems = of_property_count_u32_elems, + .get_named_gpio = of_get_named_gpio, + }; + + return &of_utils; +} + +static inline struct dsi_parser_utils *dsi_parser_get_parser_utils(void) +{ + static struct dsi_parser_utils parser_utils = { + .get_property = dsi_parser_get_property, + .read_bool = dsi_parser_read_bool, + .read_u64 = dsi_parser_read_u64, + .read_u32 = dsi_parser_read_u32, + .read_u32_array = dsi_parser_read_u32_array, + .read_string = dsi_parser_read_string, + .get_child_by_name = dsi_parser_get_child_by_name, + .get_child_count = dsi_parser_get_child_count, + .get_available_child_count = dsi_parser_get_child_count, + .find_property = dsi_parser_find_property, + .get_next_child = dsi_parser_get_next_child, + .count_u32_elems = dsi_parser_count_u32_elems, + .get_named_gpio = dsi_parser_get_named_gpio, + }; + + return &parser_utils; +} +#endif -- GitLab From 11b3bd37e78fc6b33ecebf4b2b0a9e283408d25f Mon Sep 17 00:00:00 2001 From: Ingrid Gallardo Date: Tue, 3 Apr 2018 18:30:39 -0700 Subject: [PATCH 0473/1635] drm/msm/sde: enable display mdp features for sdmshrike Enable mdp support for sdmshrike target. Change-Id: I1e3f78fcf4be1809d438cfabe108170a9afbc51f Signed-off-by: Ingrid Gallardo --- drivers/gpu/drm/msm/sde/sde_hw_catalog.c | 15 +++++++++++---- drivers/gpu/drm/msm/sde/sde_hw_catalog.h | 5 +++++ drivers/gpu/drm/msm/sde/sde_hw_lm.c | 3 ++- 3 files changed, 18 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/msm/sde/sde_hw_catalog.c b/drivers/gpu/drm/msm/sde/sde_hw_catalog.c index 5fcde3dae405..b1970be1ed43 100644 --- a/drivers/gpu/drm/msm/sde/sde_hw_catalog.c +++ b/drivers/gpu/drm/msm/sde/sde_hw_catalog.c @@ -1768,7 +1768,7 @@ static int sde_intf_parse_dt(struct device_node *np, if (IS_SDE_CTL_REV_100(sde_cfg->ctl_rev)) set_bit(SDE_INTF_INPUT_CTRL, &intf->features); - if (IS_SDE_MAJOR_MINOR_SAME((sde_cfg->hwversion), + if (IS_SDE_MAJOR_SAME((sde_cfg->hwversion), SDE_HW_VER_500)) set_bit(SDE_INTF_TE, &intf->features); } @@ -3430,7 +3430,7 @@ static int sde_hardware_format_caps(struct sde_mdss_cfg *sde_cfg, virt_vig_list_size += ARRAY_SIZE(rgb_10bit_formats); if (IS_SDE_MAJOR_MINOR_SAME((hw_rev), SDE_HW_VER_400) || (IS_SDE_MAJOR_MINOR_SAME((hw_rev), SDE_HW_VER_410)) || - (IS_SDE_MAJOR_MINOR_SAME((hw_rev), SDE_HW_VER_500))) + (IS_SDE_MAJOR_SAME((hw_rev), SDE_HW_VER_500))) vig_list_size += ARRAY_SIZE(p010_ubwc_formats); wb2_list_size += ARRAY_SIZE(rgb_10bit_formats) @@ -3468,7 +3468,7 @@ static int sde_hardware_format_caps(struct sde_mdss_cfg *sde_cfg, if (IS_SDE_MAJOR_MINOR_SAME((hw_rev), SDE_HW_VER_300) || IS_SDE_MAJOR_MINOR_SAME((hw_rev), SDE_HW_VER_400) || IS_SDE_MAJOR_MINOR_SAME((hw_rev), SDE_HW_VER_410) || - IS_SDE_MAJOR_MINOR_SAME((hw_rev), SDE_HW_VER_500)) + IS_SDE_MAJOR_SAME((hw_rev), SDE_HW_VER_500)) sde_cfg->has_hdr = true; index = sde_copy_formats(sde_cfg->dma_formats, dma_list_size, @@ -3486,7 +3486,7 @@ static int sde_hardware_format_caps(struct sde_mdss_cfg *sde_cfg, index, p010_formats, ARRAY_SIZE(p010_formats)); if (IS_SDE_MAJOR_MINOR_SAME((hw_rev), SDE_HW_VER_400) || (IS_SDE_MAJOR_MINOR_SAME((hw_rev), SDE_HW_VER_410)) || - (IS_SDE_MAJOR_MINOR_SAME((hw_rev), SDE_HW_VER_500))) + (IS_SDE_MAJOR_SAME((hw_rev), SDE_HW_VER_500))) index += sde_copy_formats(sde_cfg->vig_formats, vig_list_size, index, p010_ubwc_formats, ARRAY_SIZE(p010_ubwc_formats)); @@ -3544,6 +3544,13 @@ static int _sde_hardware_pre_caps(struct sde_mdss_cfg *sde_cfg, uint32_t hw_rev) sde_cfg->ctl_rev = SDE_CTL_CFG_VERSION_1_0_0; sde_cfg->delay_prg_fetch_start = true; sde_cfg->sui_ns_allowed = true; + } else if (IS_SDMSHRIKE_TARGET(hw_rev)) { + sde_cfg->has_wb_ubwc = true; + sde_cfg->perf.min_prefill_lines = 24; + sde_cfg->vbif_qos_nlvl = 8; + sde_cfg->ts_prefill_rev = 2; + sde_cfg->ctl_rev = SDE_CTL_CFG_VERSION_1_0_0; + sde_cfg->delay_prg_fetch_start = true; } else { SDE_ERROR("unsupported chipset id:%X\n", hw_rev); sde_cfg->perf.min_prefill_lines = 0xffff; diff --git a/drivers/gpu/drm/msm/sde/sde_hw_catalog.h b/drivers/gpu/drm/msm/sde/sde_hw_catalog.h index 57f0dd342d4d..4f40349927d6 100644 --- a/drivers/gpu/drm/msm/sde/sde_hw_catalog.h +++ b/drivers/gpu/drm/msm/sde/sde_hw_catalog.h @@ -36,6 +36,9 @@ #define SDE_HW_STEP(rev) ((rev) & 0xFFFF) #define SDE_HW_MAJOR_MINOR(rev) ((rev) >> 16) +#define IS_SDE_MAJOR_SAME(rev1, rev2) \ + (SDE_HW_MAJOR((rev1)) == SDE_HW_MAJOR((rev2))) + #define IS_SDE_MAJOR_MINOR_SAME(rev1, rev2) \ (SDE_HW_MAJOR_MINOR((rev1)) == SDE_HW_MAJOR_MINOR((rev2))) @@ -49,12 +52,14 @@ #define SDE_HW_VER_410 SDE_HW_VER(4, 1, 0) /* sdm670 v1.0 */ #define SDE_HW_VER_500 SDE_HW_VER(5, 0, 0) /* sm8150 v1.0 */ #define SDE_HW_VER_501 SDE_HW_VER(5, 0, 1) /* sm8150 v2.0 */ +#define SDE_HW_VER_510 SDE_HW_VER(5, 1, 0) /* sdmshrike v1.0 */ #define IS_MSM8996_TARGET(rev) IS_SDE_MAJOR_MINOR_SAME((rev), SDE_HW_VER_170) #define IS_MSM8998_TARGET(rev) IS_SDE_MAJOR_MINOR_SAME((rev), SDE_HW_VER_300) #define IS_SDM845_TARGET(rev) IS_SDE_MAJOR_MINOR_SAME((rev), SDE_HW_VER_400) #define IS_SDM670_TARGET(rev) IS_SDE_MAJOR_MINOR_SAME((rev), SDE_HW_VER_410) #define IS_SM8150_TARGET(rev) IS_SDE_MAJOR_MINOR_SAME((rev), SDE_HW_VER_500) +#define IS_SDMSHRIKE_TARGET(rev) IS_SDE_MAJOR_MINOR_SAME((rev), SDE_HW_VER_510) #define SDE_HW_BLK_NAME_LEN 16 diff --git a/drivers/gpu/drm/msm/sde/sde_hw_lm.c b/drivers/gpu/drm/msm/sde/sde_hw_lm.c index 2da2171364d5..cf77df035073 100644 --- a/drivers/gpu/drm/msm/sde/sde_hw_lm.c +++ b/drivers/gpu/drm/msm/sde/sde_hw_lm.c @@ -263,7 +263,8 @@ static void _setup_mixer_ops(struct sde_mdss_cfg *m, { ops->setup_mixer_out = sde_hw_lm_setup_out; if (IS_SDM845_TARGET(m->hwversion) || IS_SDM670_TARGET(m->hwversion) || - IS_SM8150_TARGET(m->hwversion)) + IS_SM8150_TARGET(m->hwversion) || + IS_SDMSHRIKE_TARGET(m->hwversion)) ops->setup_blend_config = sde_hw_lm_setup_blend_config_sdm845; else ops->setup_blend_config = sde_hw_lm_setup_blend_config; -- GitLab From 886a5c0c8e87aa88811728d1dee8a70d31cff187 Mon Sep 17 00:00:00 2001 From: Tatenda Chipeperekwa Date: Sat, 24 Mar 2018 19:12:19 -0700 Subject: [PATCH 0474/1635] drm/msm/dp: add orientation support for simulation mode Add support to specify the plug orientation during the connect event in simulation mode. For example: "echo 1 > /d/drm_dp/hpd" for normal plug orientation "echo 5 > /d/drm_dp/hpd" for flip plug orientation Furthermore, do not program the AUX switch device if we are in simulation mode as this might cause unexpected behaviour for USB functionality. Change-Id: I932b011aee97e584f3206c98115161b4041a4803 Signed-off-by: Tatenda Chipeperekwa --- drivers/gpu/drm/msm/dp/dp_debug.c | 12 +++++++++--- drivers/gpu/drm/msm/dp/dp_display.c | 5 +++++ drivers/gpu/drm/msm/dp/dp_usbpd.c | 7 ++++++- drivers/gpu/drm/msm/dp/dp_usbpd.h | 3 ++- 4 files changed, 22 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/msm/dp/dp_debug.c b/drivers/gpu/drm/msm/dp/dp_debug.c index 6dfa7763d6d5..c39051b8bd4a 100644 --- a/drivers/gpu/drm/msm/dp/dp_debug.c +++ b/drivers/gpu/drm/msm/dp/dp_debug.c @@ -262,7 +262,10 @@ static ssize_t dp_debug_write_hpd(struct file *file, struct dp_debug_private *debug = file->private_data; char buf[SZ_8]; size_t len = 0; - int hpd; + int const orientation_mask = 0x4; + int const hpd_data_mask = 0x7; + int hpd = 0; + int orientation = 0; if (!debug) return -ENODEV; @@ -280,11 +283,14 @@ static ssize_t dp_debug_write_hpd(struct file *file, if (kstrtoint(buf, 10, &hpd) != 0) goto end; - hpd &= 0x3; + hpd &= hpd_data_mask; + orientation = hpd & orientation_mask ? + ORIENTATION_CC2 : ORIENTATION_CC1; debug->dp_debug.psm_enabled = !!(hpd & BIT(1)); - debug->usbpd->simulate_connect(debug->usbpd, !!(hpd & BIT(0))); + debug->usbpd->simulate_connect(debug->usbpd, !!(hpd & BIT(0)), + orientation); end: return len; } diff --git a/drivers/gpu/drm/msm/dp/dp_display.c b/drivers/gpu/drm/msm/dp/dp_display.c index 0e7e6ec931f3..84dafc8a0cd1 100644 --- a/drivers/gpu/drm/msm/dp/dp_display.c +++ b/drivers/gpu/drm/msm/dp/dp_display.c @@ -658,6 +658,11 @@ static int dp_display_configure_aux_switch(struct dp_display_private *dp) int rc = 0; enum fsa_function event = FSA_EVENT_MAX; + if (dp->debug->sim_mode) { + pr_debug("simulation mode, skipping AUX switch programming\n"); + return 0; + } + if (!dp->aux_switch_node) { pr_debug("undefined fsa4480 handle\n"); goto end; diff --git a/drivers/gpu/drm/msm/dp/dp_usbpd.c b/drivers/gpu/drm/msm/dp/dp_usbpd.c index 42eb9b053e99..00ed5cf63325 100644 --- a/drivers/gpu/drm/msm/dp/dp_usbpd.c +++ b/drivers/gpu/drm/msm/dp/dp_usbpd.c @@ -401,7 +401,8 @@ static void dp_usbpd_response_cb(struct usbpd_svid_handler *hdlr, u8 cmd, } } -static int dp_usbpd_simulate_connect(struct dp_usbpd *dp_usbpd, bool hpd) +static int dp_usbpd_simulate_connect(struct dp_usbpd *dp_usbpd, bool hpd, + int orientation) { int rc = 0; struct dp_usbpd_private *pd; @@ -416,7 +417,11 @@ static int dp_usbpd_simulate_connect(struct dp_usbpd *dp_usbpd, bool hpd) dp_usbpd->hpd_high = hpd; pd->forced_disconnect = !hpd; + pd->dp_usbpd.orientation = orientation; + pr_debug("hpd_high=%d, forced_disconnect=%d, orientation=%d\n", + dp_usbpd->hpd_high, pd->forced_disconnect, + pd->dp_usbpd.orientation); if (hpd) pd->dp_cb->configure(pd->dev); else diff --git a/drivers/gpu/drm/msm/dp/dp_usbpd.h b/drivers/gpu/drm/msm/dp/dp_usbpd.h index 0a7efd957d84..5589af4417cf 100644 --- a/drivers/gpu/drm/msm/dp/dp_usbpd.h +++ b/drivers/gpu/drm/msm/dp/dp_usbpd.h @@ -65,7 +65,8 @@ struct dp_usbpd { bool alt_mode_cfg_done; bool debug_en; - int (*simulate_connect)(struct dp_usbpd *dp_usbpd, bool hpd); + int (*simulate_connect)(struct dp_usbpd *dp_usbpd, bool hpd, + int orientation); int (*simulate_attention)(struct dp_usbpd *dp_usbpd, int vdo); }; -- GitLab From 8ab02c344ae9f44340aeaa764dc7f9f8e712716d Mon Sep 17 00:00:00 2001 From: Tatenda Chipeperekwa Date: Wed, 18 Apr 2018 12:18:03 -0700 Subject: [PATCH 0475/1635] drivers: soc: qcom: terminate SBU lines when unused Terminate SBU lines with high impedance when they are unused, specifically at boot time and for non-DP use-cases. This is required so that USB compliance test cases can be passed. Change-Id: I42c6fedb784d0c2e113c5f4c69ac7ff100fc24e2 Signed-off-by: Tatenda Chipeperekwa --- drivers/soc/qcom/fsa4480-i2c.c | 10 +++++++--- include/linux/soc/qcom/fsa4480-i2c.h | 1 + 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/drivers/soc/qcom/fsa4480-i2c.c b/drivers/soc/qcom/fsa4480-i2c.c index 626e9832b557..ad4b233b2054 100644 --- a/drivers/soc/qcom/fsa4480-i2c.c +++ b/drivers/soc/qcom/fsa4480-i2c.c @@ -65,6 +65,7 @@ static const struct fsa4480_reg_val fsa_reg_i2c_defaults[] = { {FSA4480_DELAY_L_MIC, 0x00}, {FSA4480_DELAY_L_SENSE, 0x00}, {FSA4480_DELAY_L_AGND, 0x09}, + {FSA4480_SWITCH_SETTINGS, 0x98}, }; static void fsa4480_usbc_update_settings(struct fsa4480_priv *fsa_priv, @@ -193,7 +194,7 @@ int fsa4480_unreg_notifier(struct notifier_block *nb, if (!fsa_priv) return -EINVAL; - fsa4480_usbc_update_settings(fsa_priv, 0x18, 0xF8); + fsa4480_usbc_update_settings(fsa_priv, 0x18, 0x98); return blocking_notifier_chain_unregister (&fsa_priv->fsa4480_notifier, nb); } @@ -253,6 +254,9 @@ int fsa4480_switch_event(struct device_node *node, case FSA_USBC_ORIENTATION_CC2: fsa4480_usbc_update_settings(fsa_priv, 0x60, 0xE0); return fsa4480_validate_display_port_settings(fsa_priv); + case FSA_USBC_DISPLAYPORT_DISCONNECTED: + fsa4480_usbc_update_settings(fsa_priv, 0x18, 0x98); + break; default: break; } @@ -294,7 +298,7 @@ static int fsa4480_usbc_analog_setup_switches POWER_SUPPLY_TYPEC_NONE, NULL); /* deactivate switches */ - fsa4480_usbc_update_settings(fsa_priv, 0x18, 0xF8); + fsa4480_usbc_update_settings(fsa_priv, 0x18, 0x98); if (fsa_priv->usbc_force_pr_mode) { pval.intval = POWER_SUPPLY_TYPEC_PR_DUAL; @@ -405,7 +409,7 @@ static int fsa4480_remove(struct i2c_client *i2c) if (!fsa_priv) return -EINVAL; - fsa4480_usbc_update_settings(fsa_priv, 0x18, 0xF8); + fsa4480_usbc_update_settings(fsa_priv, 0x18, 0x98); /* deregister from PMI */ power_supply_unreg_notifier(&fsa_priv->psy_nb); diff --git a/include/linux/soc/qcom/fsa4480-i2c.h b/include/linux/soc/qcom/fsa4480-i2c.h index d84708657e58..83802f0b1e05 100644 --- a/include/linux/soc/qcom/fsa4480-i2c.h +++ b/include/linux/soc/qcom/fsa4480-i2c.h @@ -19,6 +19,7 @@ enum fsa_function { FSA_MIC_GND_SWAP, FSA_USBC_ORIENTATION_CC1, FSA_USBC_ORIENTATION_CC2, + FSA_USBC_DISPLAYPORT_DISCONNECTED, FSA_EVENT_MAX, }; -- GitLab From cf4733b035d49d77548da43964d46ef56463847b Mon Sep 17 00:00:00 2001 From: Tatenda Chipeperekwa Date: Wed, 18 Apr 2018 12:24:59 -0700 Subject: [PATCH 0476/1635] drm/msm/dp: configure AUX switch on connect/disconnect Configure the AUX switch to enable AUX transactions on cable connect, and to reset the switch once the cable is disconnected. Change-Id: I716364616f3dcf6076b6901eab487a25608ef046 Signed-off-by: Tatenda Chipeperekwa --- drivers/gpu/drm/msm/dp/dp_aux.c | 55 +++++++++++++++++++++++++++-- drivers/gpu/drm/msm/dp/dp_aux.h | 3 +- drivers/gpu/drm/msm/dp/dp_display.c | 50 ++++++-------------------- 3 files changed, 66 insertions(+), 42 deletions(-) diff --git a/drivers/gpu/drm/msm/dp/dp_aux.c b/drivers/gpu/drm/msm/dp/dp_aux.c index 796f55f90b08..840e44e8a5e1 100644 --- a/drivers/gpu/drm/msm/dp/dp_aux.c +++ b/drivers/gpu/drm/msm/dp/dp_aux.c @@ -14,6 +14,8 @@ #define pr_fmt(fmt) "[drm-dp] %s: " fmt, __func__ +#include +#include #include #include "dp_aux.h" @@ -29,6 +31,7 @@ struct dp_aux_private { struct dp_aux dp_aux; struct dp_catalog_aux *catalog; struct dp_aux_cfg *cfg; + struct device_node *aux_switch_node; struct mutex mutex; struct completion comp; struct drm_dp_aux drm_aux; @@ -703,14 +706,60 @@ static void dp_aux_set_sim_mode(struct dp_aux *dp_aux, bool en, aux->drm_aux.transfer = dp_aux_transfer; } +static int dp_aux_configure_aux_switch(struct dp_aux *dp_aux, + bool enable, int orientation) +{ + struct dp_aux_private *aux; + int rc = 0; + enum fsa_function event = FSA_USBC_DISPLAYPORT_DISCONNECTED; + + if (!dp_aux) { + pr_err("invalid input\n"); + rc = -EINVAL; + goto end; + } + + aux = container_of(dp_aux, struct dp_aux_private, dp_aux); + + if (!aux->aux_switch_node) { + pr_debug("undefined fsa4480 handle\n"); + rc = -EINVAL; + goto end; + } + + if (enable) { + switch (orientation) { + case ORIENTATION_CC1: + event = FSA_USBC_ORIENTATION_CC1; + break; + case ORIENTATION_CC2: + event = FSA_USBC_ORIENTATION_CC2; + break; + default: + pr_err("invalid orientation\n"); + rc = -EINVAL; + goto end; + } + } + + pr_debug("enable=%d, orientation=%d, event=%d\n", + enable, orientation, event); + + rc = fsa4480_switch_event(aux->aux_switch_node, event); + if (rc) + pr_err("failed to configure fsa4480 i2c device (%d)\n", rc); +end: + return rc; +} + struct dp_aux *dp_aux_get(struct device *dev, struct dp_catalog_aux *catalog, - struct dp_aux_cfg *aux_cfg) + struct dp_aux_cfg *aux_cfg, struct device_node *aux_switch) { int rc = 0; struct dp_aux_private *aux; struct dp_aux *dp_aux; - if (!catalog || !aux_cfg) { + if (!catalog || !aux_cfg || !aux_switch) { pr_err("invalid input\n"); rc = -ENODEV; goto error; @@ -729,6 +778,7 @@ struct dp_aux *dp_aux_get(struct device *dev, struct dp_catalog_aux *catalog, aux->dev = dev; aux->catalog = catalog; aux->cfg = aux_cfg; + aux->aux_switch_node = aux_switch; dp_aux = &aux->dp_aux; aux->retry_cnt = 0; aux->dp_aux.reg = 0xFFFF; @@ -742,6 +792,7 @@ struct dp_aux *dp_aux_get(struct device *dev, struct dp_catalog_aux *catalog, dp_aux->abort = dp_aux_abort_transaction; dp_aux->dpcd_updated = dp_aux_dpcd_updated; dp_aux->set_sim_mode = dp_aux_set_sim_mode; + dp_aux->aux_switch = dp_aux_configure_aux_switch; return dp_aux; error: diff --git a/drivers/gpu/drm/msm/dp/dp_aux.h b/drivers/gpu/drm/msm/dp/dp_aux.h index bf52d57d606b..dba1c5a64e59 100644 --- a/drivers/gpu/drm/msm/dp/dp_aux.h +++ b/drivers/gpu/drm/msm/dp/dp_aux.h @@ -55,10 +55,11 @@ struct dp_aux { void (*abort)(struct dp_aux *aux); void (*dpcd_updated)(struct dp_aux *aux); void (*set_sim_mode)(struct dp_aux *aux, bool en, u8 *edid, u8 *dpcd); + int (*aux_switch)(struct dp_aux *aux, bool enable, int orientation); }; struct dp_aux *dp_aux_get(struct device *dev, struct dp_catalog_aux *catalog, - struct dp_aux_cfg *aux_cfg); + struct dp_aux_cfg *aux_cfg, struct device_node *aux_switch); void dp_aux_put(struct dp_aux *aux); #endif /*__DP_AUX_H_*/ diff --git a/drivers/gpu/drm/msm/dp/dp_display.c b/drivers/gpu/drm/msm/dp/dp_display.c index 84dafc8a0cd1..19e4d5244f44 100644 --- a/drivers/gpu/drm/msm/dp/dp_display.c +++ b/drivers/gpu/drm/msm/dp/dp_display.c @@ -653,41 +653,6 @@ static int dp_display_process_hpd_low(struct dp_display_private *dp) return rc; } -static int dp_display_configure_aux_switch(struct dp_display_private *dp) -{ - int rc = 0; - enum fsa_function event = FSA_EVENT_MAX; - - if (dp->debug->sim_mode) { - pr_debug("simulation mode, skipping AUX switch programming\n"); - return 0; - } - - if (!dp->aux_switch_node) { - pr_debug("undefined fsa4480 handle\n"); - goto end; - } - - switch (dp->usbpd->orientation) { - case ORIENTATION_CC1: - event = FSA_USBC_ORIENTATION_CC1; - break; - case ORIENTATION_CC2: - event = FSA_USBC_ORIENTATION_CC2; - break; - default: - pr_err("invalid orientation\n"); - rc = -EINVAL; - goto end; - } - - rc = fsa4480_switch_event(dp->aux_switch_node, event); - if (rc) - pr_err("failed to configure fsa4480 i2c device (%d)\n", rc); -end: - return rc; -} - static int dp_display_usbpd_configure_cb(struct device *dev) { int rc = 0; @@ -706,9 +671,11 @@ static int dp_display_usbpd_configure_cb(struct device *dev) goto end; } - rc = dp_display_configure_aux_switch(dp); - if (rc) - goto end; + if (!dp->debug->sim_mode) { + rc = dp->aux->aux_switch(dp->aux, true, dp->usbpd->orientation); + if (rc) + goto end; + } dp_display_host_init(dp); @@ -797,6 +764,10 @@ static int dp_display_usbpd_disconnect_cb(struct device *dev) flush_workqueue(dp->wq); dp_display_handle_disconnect(dp); + + if (!dp->debug->sim_mode) + dp->aux->aux_switch(dp->aux, false, ORIENTATION_NONE); + atomic_set(&dp->aborted, 0); end: return rc; @@ -1033,7 +1004,8 @@ static int dp_init_sub_modules(struct dp_display_private *dp) goto error_aux; } - dp->aux = dp_aux_get(dev, &dp->catalog->aux, dp->parser->aux_cfg); + dp->aux = dp_aux_get(dev, &dp->catalog->aux, dp->parser->aux_cfg, + dp->aux_switch_node); if (IS_ERR(dp->aux)) { rc = PTR_ERR(dp->aux); pr_err("failed to initialize aux, rc = %d\n", rc); -- GitLab From cb30e68df75b410a837555c1639b53aa17824c1c Mon Sep 17 00:00:00 2001 From: Chris Lew Date: Sat, 31 Mar 2018 01:30:00 -0700 Subject: [PATCH 0477/1635] qrtr: Introduce MHI transport for qrtr MHI is used to communicate with external modems. Add MHI support for QRTR to support QMI traffic between an external modem and the local processor. Change-Id: I8d3ba9e9d48a7c37e21031c2ad1f27329dfdab6d Signed-off-by: Chris Lew --- net/qrtr/Kconfig | 7 +++ net/qrtr/Makefile | 3 + net/qrtr/mhi.c | 145 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 155 insertions(+) create mode 100644 net/qrtr/mhi.c diff --git a/net/qrtr/Kconfig b/net/qrtr/Kconfig index 326fd97444f5..61d66dd2290b 100644 --- a/net/qrtr/Kconfig +++ b/net/qrtr/Kconfig @@ -21,4 +21,11 @@ config QRTR_SMD Say Y here to support SMD based ipcrouter channels. SMD is the most common transport for IPC Router. +config QRTR_MHI + tristate "MHI IPC Router channels" + depends on MHI_BUS || (COMPILE_TEST && MHI_BUS=n) + ---help--- + Say Y here to support MHI based ipcrouter channels. MHI is the + transport used for external modem connections for IPC Router. + endif # QRTR diff --git a/net/qrtr/Makefile b/net/qrtr/Makefile index ab09e40f7c74..c31cf134f10f 100644 --- a/net/qrtr/Makefile +++ b/net/qrtr/Makefile @@ -2,3 +2,6 @@ obj-$(CONFIG_QRTR) := qrtr.o obj-$(CONFIG_QRTR_SMD) += qrtr-smd.o qrtr-smd-y := smd.o + +obj-$(CONFIG_QRTR_MHI) += qrtr-mhi.o +qrtr-mhi-y := mhi.o diff --git a/net/qrtr/mhi.c b/net/qrtr/mhi.c new file mode 100644 index 000000000000..f2c67b93e07e --- /dev/null +++ b/net/qrtr/mhi.c @@ -0,0 +1,145 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include + +#include "qrtr.h" + +struct qrtr_mhi_dev { + struct qrtr_endpoint ep; + struct mhi_device *mhi_dev; + struct device *dev; + struct completion ul_done; +}; + +/* from mhi to qrtr */ +static void qcom_mhi_qrtr_dl_callback(struct mhi_device *mhi_dev, + struct mhi_result *mhi_res) +{ + struct qrtr_mhi_dev *qdev = dev_get_drvdata(&mhi_dev->dev); + int rc; + + if (!qdev || mhi_res->transaction_status) + return; + + rc = qrtr_endpoint_post(&qdev->ep, mhi_res->buf_addr, + mhi_res->bytes_xferd); + if (rc == -EINVAL) + dev_err(qdev->dev, "invalid ipcrouter packet\n"); +} + +/* from mhi to qrtr */ +static void qcom_mhi_qrtr_ul_callback(struct mhi_device *mhi_dev, + struct mhi_result *mhi_res) +{ + struct qrtr_mhi_dev *qdev = dev_get_drvdata(&mhi_dev->dev); + struct sk_buff *skb = mhi_res->buf_addr; + + if (!mhi_res->transaction_status) { + complete(&qdev->ul_done); + consume_skb(skb); + } else { + kfree_skb(skb); + } +} + +/* from qrtr to mhi */ +static int qcom_mhi_qrtr_send(struct qrtr_endpoint *ep, struct sk_buff *skb) +{ + struct qrtr_mhi_dev *qdev = container_of(ep, struct qrtr_mhi_dev, ep); + int rc; + + rc = skb_linearize(skb); + if (rc) + goto out; + + reinit_completion(&qdev->ul_done); + rc = mhi_queue_transfer(qdev->mhi_dev, DMA_TO_DEVICE, skb, skb->len, + MHI_EOT); + if (rc) + goto out; + + rc = wait_for_completion_interruptible_timeout(&qdev->ul_done, HZ * 5); + if (rc > 0) + rc = 0; + else if (rc == 0) + rc = -ETIMEDOUT; + +out: + return rc; +} + +static int qcom_mhi_qrtr_probe(struct mhi_device *mhi_dev, + const struct mhi_device_id *id) +{ + struct qrtr_mhi_dev *qdev; + int rc; + + qdev = devm_kzalloc(&mhi_dev->dev, sizeof(*qdev), GFP_KERNEL); + if (!qdev) + return -ENOMEM; + + qdev->mhi_dev = mhi_dev; + qdev->dev = &mhi_dev->dev; + qdev->ep.xmit = qcom_mhi_qrtr_send; + + init_completion(&qdev->ul_done); + + rc = qrtr_endpoint_register(&qdev->ep, QRTR_EP_NID_AUTO); + if (rc) + return rc; + + dev_set_drvdata(&mhi_dev->dev, qdev); + + rc = mhi_prepare_for_transfer(mhi_dev); + if (rc) + return rc; + + dev_dbg(qdev->dev, "Qualcomm MHI QRTR driver probed\n"); + + return 0; +} + +static void qcom_mhi_qrtr_remove(struct mhi_device *mhi_dev) +{ + struct qrtr_mhi_dev *qdev = dev_get_drvdata(&mhi_dev->dev); + + qrtr_endpoint_unregister(&qdev->ep); + complete(&qdev->ul_done); + dev_set_drvdata(&mhi_dev->dev, NULL); +} + +static const struct mhi_device_id qcom_mhi_qrtr_mhi_match[] = { + { .chan = "IPCR" }, + {} +}; + +static struct mhi_driver qcom_mhi_qrtr_driver = { + .probe = qcom_mhi_qrtr_probe, + .remove = qcom_mhi_qrtr_remove, + .dl_xfer_cb = qcom_mhi_qrtr_dl_callback, + .ul_xfer_cb = qcom_mhi_qrtr_ul_callback, + .id_table = qcom_mhi_qrtr_mhi_match, + .driver = { + .name = "qcom_mhi_qrtr", + .owner = THIS_MODULE, + }, +}; + +module_driver(qcom_mhi_qrtr_driver, mhi_driver_register, + mhi_driver_unregister); + +MODULE_DESCRIPTION("Qualcomm IPC-Router MHI interface driver"); +MODULE_LICENSE("GPL v2"); -- GitLab From c5f4705b528597feaadeea184fcee7f516a3efdf Mon Sep 17 00:00:00 2001 From: Chris Lew Date: Tue, 17 Apr 2018 19:49:45 -0700 Subject: [PATCH 0478/1635] defconfig: sm8150: Enable MHI transport for qrtr The MHI transport for qrtr enables qrtr communication with external devices connected through the MHI Host Interface. Change-Id: I2d9c84cf70b105b665c6154d336bc670191d2eda Signed-off-by: Chris Lew --- arch/arm64/configs/sm8150-perf_defconfig | 1 + arch/arm64/configs/sm8150_defconfig | 1 + 2 files changed, 2 insertions(+) diff --git a/arch/arm64/configs/sm8150-perf_defconfig b/arch/arm64/configs/sm8150-perf_defconfig index 7c9a5e1913e1..3fd15d2913a8 100644 --- a/arch/arm64/configs/sm8150-perf_defconfig +++ b/arch/arm64/configs/sm8150-perf_defconfig @@ -221,6 +221,7 @@ CONFIG_NET_ACT_MIRRED=y CONFIG_NET_ACT_SKBEDIT=y CONFIG_QRTR=y CONFIG_QRTR_SMD=y +CONFIG_QRTR_MHI=y CONFIG_RMNET_DATA=y CONFIG_RMNET_DATA_FC=y CONFIG_RMNET_DATA_DEBUG_PKT=y diff --git a/arch/arm64/configs/sm8150_defconfig b/arch/arm64/configs/sm8150_defconfig index a35eaa59a543..206dd92770c4 100644 --- a/arch/arm64/configs/sm8150_defconfig +++ b/arch/arm64/configs/sm8150_defconfig @@ -227,6 +227,7 @@ CONFIG_NET_ACT_SKBEDIT=y CONFIG_DNS_RESOLVER=y CONFIG_QRTR=y CONFIG_QRTR_SMD=y +CONFIG_QRTR_MHI=y CONFIG_RMNET_DATA=y CONFIG_RMNET_DATA_FC=y CONFIG_RMNET_DATA_DEBUG_PKT=y -- GitLab From a3f8a97e4619a7cb90924781f0c5925967c35e88 Mon Sep 17 00:00:00 2001 From: Puja Gupta Date: Tue, 17 Apr 2018 11:44:32 -0700 Subject: [PATCH 0479/1635] sched/walt: Fix SCHED_CPUFREQ_CONTINUE for hotplug cases cluster->cpus might include hotplugged cores and as a result we would end up sending incorrect flag to cpufreq. Fix the bug by checking cpu_online_mask. Change-Id: I39fa9296aac72604c91470a8ffe0a5b9efbaac1f Signed-off-by: Puja Gupta --- kernel/sched/walt.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/kernel/sched/walt.c b/kernel/sched/walt.c index db90a4bd9313..746d3a2c1d83 100644 --- a/kernel/sched/walt.c +++ b/kernel/sched/walt.c @@ -3083,9 +3083,14 @@ void walt_irq_work(struct irq_work *irq_work) } for_each_sched_cluster(cluster) { - unsigned int num_cpus = cpumask_weight(&cluster->cpus), i = 1; + cpumask_t cluster_online_cpus; + unsigned int num_cpus, i = 1; - for_each_cpu(cpu, &cluster->cpus) { + cpumask_and(&cluster_online_cpus, &cluster->cpus, + cpu_online_mask); + num_cpus = cpumask_weight(&cluster_online_cpus); + + for_each_cpu(cpu, &cluster_online_cpus) { if (i == num_cpus) cpufreq_update_util(cpu_rq(cpu), flag); else -- GitLab From a0d504e92c5823885ef63bd3a7f144ffa283db9a Mon Sep 17 00:00:00 2001 From: Satya Durga Srinivasu Prabhala Date: Wed, 18 Apr 2018 13:42:31 -0700 Subject: [PATCH 0480/1635] sched/fair: use tunable value for capacity margin checks As user can change the migration thresholds, need to use the upmigration threshold for capcity margin checks instead of hard coded one to avoid undesired behavior. Change-Id: I83e68bbaeba814c720af5e6ae4c37b4162141c51 Signed-off-by: Satya Durga Srinivasu Prabhala --- kernel/sched/fair.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index 210977130d09..e6c6729c7da1 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -7366,7 +7366,7 @@ static int wake_cap(struct task_struct *p, int cpu, int prev_cpu) bool __cpu_overutilized(int cpu, int delta) { return (capacity_orig_of(cpu) * 1024) < - ((cpu_util(cpu) + delta) * capacity_margin); + ((cpu_util(cpu) + delta) * sched_capacity_margin_up[cpu]); } bool cpu_overutilized(int cpu) @@ -7579,7 +7579,8 @@ static int find_energy_efficient_cpu(struct sched_domain *sd, spare = capacity_spare_wake(cpu_iter, p); - if (spare * 1024 < capacity_margin * task_util(p)) + if (spare * 1024 < sched_capacity_margin_up[cpu_iter] * + task_util(p)) continue; /* Add CPU candidate */ @@ -9285,7 +9286,8 @@ group_is_overloaded(struct lb_env *env, struct sg_lb_stats *sgs) static inline bool group_smaller_cpu_capacity(struct sched_group *sg, struct sched_group *ref) { - return sg->sgc->min_capacity * capacity_margin < + return sg->sgc->min_capacity * + sched_capacity_margin_up[group_first_cpu(sg)] < ref->sgc->min_capacity * 1024; } @@ -9676,7 +9678,8 @@ static inline void update_sd_lb_stats(struct lb_env *env, struct sd_lb_stats *sd * needs to be done at the next sched domain level as well. */ if (lb_sd_parent(env->sd) && - sds->total_capacity * 1024 < sds->total_util * capacity_margin) + sds->total_capacity * 1024 < sds->total_util * + sched_capacity_margin_up[group_first_cpu(sds->local)]) set_sd_overutilized(env->sd->parent); } -- GitLab From 57244cc5b0207b13659d3a69baa7c75b9ea1a841 Mon Sep 17 00:00:00 2001 From: Steve Cohen Date: Wed, 11 Apr 2018 16:10:32 -0400 Subject: [PATCH 0481/1635] drm/msm/sde: restrict directly accessing data in user pointers Restrict directly dereferencing user pointers by casting with the proper attribute. Some properties accept a 64-bit value as a pointer to a user space structure. This data should only be accessed after copying to the kernel address space. Change-Id: I968dc92061263176f714d1fda5e75db3921dfc3e Signed-off-by: Steve Cohen --- drivers/gpu/drm/msm/sde/sde_connector.c | 9 +++++---- drivers/gpu/drm/msm/sde/sde_plane.c | 17 +++++++++-------- 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/msm/sde/sde_connector.c b/drivers/gpu/drm/msm/sde/sde_connector.c index 6ee35ca379b0..3b00e7b8d01a 100644 --- a/drivers/gpu/drm/msm/sde/sde_connector.c +++ b/drivers/gpu/drm/msm/sde/sde_connector.c @@ -889,7 +889,7 @@ int sde_connector_roi_v1_check_roi(struct drm_connector_state *conn_state) static int _sde_connector_set_roi_v1( struct sde_connector *c_conn, struct sde_connector_state *c_state, - void *usr_ptr) + void __user *usr_ptr) { struct sde_drm_roi_v1 roi_v1; int i; @@ -940,7 +940,7 @@ static int _sde_connector_set_roi_v1( static int _sde_connector_set_ext_hdr_info( struct sde_connector *c_conn, struct sde_connector_state *c_state, - void *usr_ptr) + void __user *usr_ptr) { int rc = 0; struct drm_connector *connector; @@ -1071,7 +1071,8 @@ static int sde_connector_atomic_set_property(struct drm_connector *connector, } break; case CONNECTOR_PROP_ROI_V1: - rc = _sde_connector_set_roi_v1(c_conn, c_state, (void *)val); + rc = _sde_connector_set_roi_v1(c_conn, + c_state, (void __user *)val); if (rc) SDE_ERROR_CONN(c_conn, "invalid roi_v1, rc: %d\n", rc); break; @@ -1094,7 +1095,7 @@ static int sde_connector_atomic_set_property(struct drm_connector *connector, if (idx == CONNECTOR_PROP_HDR_METADATA) { rc = _sde_connector_set_ext_hdr_info(c_conn, - c_state, (void *)val); + c_state, (void __user *)val); if (rc) SDE_ERROR_CONN(c_conn, "cannot set hdr info %d\n", rc); } diff --git a/drivers/gpu/drm/msm/sde/sde_plane.c b/drivers/gpu/drm/msm/sde/sde_plane.c index e1da84267fc4..c4ba4c44490d 100644 --- a/drivers/gpu/drm/msm/sde/sde_plane.c +++ b/drivers/gpu/drm/msm/sde/sde_plane.c @@ -4460,7 +4460,8 @@ static void _sde_plane_install_properties(struct drm_plane *plane, PLANE_PROP_FB_TRANSLATION_MODE); } -static inline void _sde_plane_set_csc_v1(struct sde_plane *psde, void *usr_ptr) +static inline void _sde_plane_set_csc_v1(struct sde_plane *psde, + void __user *usr_ptr) { struct sde_drm_csc_v1 csc_v1; int i; @@ -4496,7 +4497,7 @@ static inline void _sde_plane_set_csc_v1(struct sde_plane *psde, void *usr_ptr) } static inline void _sde_plane_set_scaler_v1(struct sde_plane *psde, - struct sde_plane_state *pstate, void *usr) + struct sde_plane_state *pstate, void __user *usr) { struct sde_drm_scaler_v1 scale_v1; struct sde_hw_pixel_ext *pe; @@ -4555,7 +4556,7 @@ static inline void _sde_plane_set_scaler_v1(struct sde_plane *psde, } static inline void _sde_plane_set_scaler_v2(struct sde_plane *psde, - struct sde_plane_state *pstate, void *usr) + struct sde_plane_state *pstate, void __user *usr) { struct sde_drm_scaler_v2 scale_v2; struct sde_hw_pixel_ext *pe; @@ -4617,7 +4618,7 @@ static inline void _sde_plane_set_scaler_v2(struct sde_plane *psde, } static void _sde_plane_set_excl_rect_v1(struct sde_plane *psde, - struct sde_plane_state *pstate, void *usr_ptr) + struct sde_plane_state *pstate, void __user *usr_ptr) { struct drm_clip_rect excl_rect_v1; @@ -4675,19 +4676,19 @@ static int sde_plane_atomic_set_property(struct drm_plane *plane, break; case PLANE_PROP_CSC_V1: case PLANE_PROP_CSC_DMA_V1: - _sde_plane_set_csc_v1(psde, (void *)val); + _sde_plane_set_csc_v1(psde, (void __user *)val); break; case PLANE_PROP_SCALER_V1: _sde_plane_set_scaler_v1(psde, pstate, - (void *)val); + (void __user *)val); break; case PLANE_PROP_SCALER_V2: _sde_plane_set_scaler_v2(psde, pstate, - (void *)val); + (void __user *)val); break; case PLANE_PROP_EXCL_RECT_V1: _sde_plane_set_excl_rect_v1(psde, pstate, - (void *)val); + (void __user *)val); break; default: /* nothing to do */ -- GitLab From 0b29e3750fce418c7adcd7c7c184c99dfdd39e6b Mon Sep 17 00:00:00 2001 From: Patrick Daly Date: Wed, 27 Sep 2017 15:10:29 -0700 Subject: [PATCH 0482/1635] iommu: arm-smmu: Fix QSMMUV500 system cache quirk Having page tables which are non coherent, but cached in a system cache requires SH=Non-Shareable. This applies to the qsmmuv500 model. For data buffers SH=Non-Shareable is not required. Change-Id: I51ff72be3e506df481628bdc7d3c069ff518ad0a Signed-off-by: Patrick Daly Signed-off-by: Sudarshan Rajagopalan --- drivers/iommu/arm-smmu.c | 3 +++ drivers/iommu/io-pgtable-arm.c | 8 +++++++- drivers/iommu/io-pgtable.h | 8 ++++++++ 3 files changed, 18 insertions(+), 1 deletion(-) diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c index 005a80301531..ae19a98b8325 100644 --- a/drivers/iommu/arm-smmu.c +++ b/drivers/iommu/arm-smmu.c @@ -1676,6 +1676,9 @@ static int arm_smmu_init_domain_context(struct iommu_domain *domain, quirks |= IO_PGTABLE_QUIRK_QCOM_USE_UPSTREAM_HINT; if (is_iommu_pt_coherent(smmu_domain)) quirks |= IO_PGTABLE_QUIRK_NO_DMA; + if ((quirks & IO_PGTABLE_QUIRK_QCOM_USE_UPSTREAM_HINT) && + (smmu->model == QCOM_SMMUV500)) + quirks |= IO_PGTABLE_QUIRK_QSMMUV500_NON_SHAREABLE; ret = arm_smmu_alloc_cb(domain, smmu, dev); if (ret < 0) diff --git a/drivers/iommu/io-pgtable-arm.c b/drivers/iommu/io-pgtable-arm.c index 3dcc65d8ef28..c95cddf5c06d 100644 --- a/drivers/iommu/io-pgtable-arm.c +++ b/drivers/iommu/io-pgtable-arm.c @@ -1116,7 +1116,8 @@ arm_64_lpae_alloc_pgtable_s1(struct io_pgtable_cfg *cfg, void *cookie) if (cfg->quirks & ~(IO_PGTABLE_QUIRK_ARM_NS | IO_PGTABLE_QUIRK_NO_DMA - | IO_PGTABLE_QUIRK_QCOM_USE_UPSTREAM_HINT)) + | IO_PGTABLE_QUIRK_QCOM_USE_UPSTREAM_HINT + | IO_PGTABLE_QUIRK_QSMMUV500_NON_SHAREABLE)) return NULL; data = arm_lpae_alloc_pgtable(cfg); @@ -1128,6 +1129,11 @@ arm_64_lpae_alloc_pgtable_s1(struct io_pgtable_cfg *cfg, void *cookie) reg = (ARM_LPAE_TCR_SH_OS << ARM_LPAE_TCR_SH0_SHIFT) | (ARM_LPAE_TCR_RGN_WBWA << ARM_LPAE_TCR_IRGN0_SHIFT) | (ARM_LPAE_TCR_RGN_WBWA << ARM_LPAE_TCR_ORGN0_SHIFT); + else if ((cfg->quirks & IO_PGTABLE_QUIRK_QCOM_USE_UPSTREAM_HINT) && + (cfg->quirks & IO_PGTABLE_QUIRK_QSMMUV500_NON_SHAREABLE)) + reg = (ARM_LPAE_TCR_SH_NS << ARM_LPAE_TCR_SH0_SHIFT) | + (ARM_LPAE_TCR_RGN_NC << ARM_LPAE_TCR_IRGN0_SHIFT) | + (ARM_LPAE_TCR_RGN_WBWA << ARM_LPAE_TCR_ORGN0_SHIFT); else if (cfg->quirks & IO_PGTABLE_QUIRK_QCOM_USE_UPSTREAM_HINT) reg = (ARM_LPAE_TCR_SH_OS << ARM_LPAE_TCR_SH0_SHIFT) | (ARM_LPAE_TCR_RGN_NC << ARM_LPAE_TCR_IRGN0_SHIFT) | diff --git a/drivers/iommu/io-pgtable.h b/drivers/iommu/io-pgtable.h index c8b112b8b280..d53c22339001 100644 --- a/drivers/iommu/io-pgtable.h +++ b/drivers/iommu/io-pgtable.h @@ -81,6 +81,13 @@ struct io_pgtable_cfg { * be accessed by a fully cache-coherent IOMMU or CPU (e.g. for a * software-emulated IOMMU), such that pagetable updates need not * be treated as explicit DMA data. + * + + * IO_PGTABLE_QUIRK_QSMMUV500_NON_SHAREABLE: + * Having page tables which are non coherent, but cached in a + * system cache requires SH=Non-Shareable. This applies to the + * qsmmuv500 model. For data buffers SH=Non-Shareable is not + * required. * IO_PGTABLE_QUIRK_QCOM_USE_UPSTREAM_HINT: Override the attributes * set in TCR for the page table walker. Use attributes specified @@ -92,6 +99,7 @@ struct io_pgtable_cfg { #define IO_PGTABLE_QUIRK_TLBI_ON_MAP BIT(2) #define IO_PGTABLE_QUIRK_ARM_MTK_4GB BIT(3) #define IO_PGTABLE_QUIRK_NO_DMA BIT(4) + #define IO_PGTABLE_QUIRK_QSMMUV500_NON_SHAREABLE BIT(5) #define IO_PGTABLE_QUIRK_QCOM_USE_UPSTREAM_HINT BIT(6) unsigned long quirks; unsigned long pgsize_bitmap; -- GitLab From c8f2b6103f31c49453aa763a24b2c61393d836e1 Mon Sep 17 00:00:00 2001 From: Patrick Daly Date: Fri, 6 Oct 2017 17:37:10 -0700 Subject: [PATCH 0483/1635] iommu: arm-smmu: Disable io-coherency in bypass mode The IC attribute from a client transaction is not connected to the MMU500. Instead, IC is set to OC at the MMU500 input. This can lead to an error scenario where: 1) Client sends OS=1 OC=1 IC=0 and expects io-coherency to be disabled. 2) Iommu is in bypass mode, and does not override any attributes. But per the above we get OS=1 IC=OC, which enables io-coherency. Prevent this by forcing incoming transactions to Non-Shareable when the iommu is in bypass mode. For non-bypass mode cases, the stage 1 page table entries will provide the cacheability and shareability attributes. Change-Id: I41a497aa2a92c8e1291de34a98cad407266f4f17 Signed-off-by: Patrick Daly Signed-off-by: Sudarshan Rajagopalan --- drivers/iommu/arm-smmu-regs.h | 9 +++++++++ drivers/iommu/arm-smmu.c | 10 +++++++++- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/drivers/iommu/arm-smmu-regs.h b/drivers/iommu/arm-smmu-regs.h index afac72cd8fd7..59fe3f49affd 100644 --- a/drivers/iommu/arm-smmu-regs.h +++ b/drivers/iommu/arm-smmu-regs.h @@ -37,6 +37,9 @@ #define sCR0_VMID16EN (1 << 31) #define sCR0_BSU_SHIFT 14 #define sCR0_BSU_MASK 0x3 +#define sCR0_SHCFG_SHIFT 22 +#define sCR0_SHCFG_MASK 0x3 +#define sCR0_SHCFG_NSH 3 /* Auxiliary Configuration register */ #define ARM_SMMU_GR0_sACR 0x10 @@ -114,6 +117,9 @@ #define S2CR_EXIDVALID (1 << 10) #define S2CR_TYPE_SHIFT 16 #define S2CR_TYPE_MASK 0x3 +#define S2CR_SHCFG_SHIFT 8 +#define S2CR_SHCFG_MASK 0x3 +#define S2CR_SHCFG_NSH 0x3 enum arm_smmu_s2cr_type { S2CR_TYPE_TRANS, S2CR_TYPE_BYPASS, @@ -184,6 +190,9 @@ enum arm_smmu_s2cr_privcfg { #define ARM_SMMU_CB_ATS1PR 0x800 #define ARM_SMMU_CB_ATSR 0x8f0 +#define SCTLR_SHCFG_SHIFT 22 +#define SCTLR_SHCFG_MASK 0x3 +#define SCTLR_SHCFG_NSH 0x3 #define SCTLR_S1_ASIDPNE (1 << 12) #define SCTLR_CFCFG (1 << 7) #define SCTLR_HUPCF (1 << 8) diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c index ae19a98b8325..d484b00e46f8 100644 --- a/drivers/iommu/arm-smmu.c +++ b/drivers/iommu/arm-smmu.c @@ -1480,6 +1480,9 @@ static void arm_smmu_write_context_bank(struct arm_smmu_device *smmu, int idx, /* SCTLR */ reg = SCTLR_CFCFG | SCTLR_CFIE | SCTLR_CFRE | SCTLR_AFE | SCTLR_TRE; + /* Ensure bypass transactions are Non-shareable */ + reg |= SCTLR_SHCFG_NSH << SCTLR_SHCFG_SHIFT; + if (attributes & (1 << DOMAIN_ATTR_CB_STALL_DISABLE)) { reg &= ~SCTLR_CFCFG; reg |= SCTLR_HUPCF; @@ -1894,7 +1897,8 @@ static void arm_smmu_write_s2cr(struct arm_smmu_device *smmu, int idx) struct arm_smmu_s2cr *s2cr = smmu->s2crs + idx; u32 reg = (s2cr->type & S2CR_TYPE_MASK) << S2CR_TYPE_SHIFT | (s2cr->cbndx & S2CR_CBNDX_MASK) << S2CR_CBNDX_SHIFT | - (s2cr->privcfg & S2CR_PRIVCFG_MASK) << S2CR_PRIVCFG_SHIFT; + (s2cr->privcfg & S2CR_PRIVCFG_MASK) << S2CR_PRIVCFG_SHIFT | + S2CR_SHCFG_NSH << S2CR_SHCFG_SHIFT; if (smmu->features & ARM_SMMU_FEAT_EXIDS && smmu->smrs && smmu->smrs[idx].valid) @@ -3501,6 +3505,10 @@ static void arm_smmu_device_reset(struct arm_smmu_device *smmu) if (smmu->features & ARM_SMMU_FEAT_EXIDS) reg |= sCR0_EXIDENABLE; + /* Force bypass transaction to be Non-Shareable & not io-coherent */ + reg &= ~(sCR0_SHCFG_MASK << sCR0_SHCFG_SHIFT); + reg |= sCR0_SHCFG_NSH << sCR0_SHCFG_SHIFT; + /* Push the button */ arm_smmu_tlb_sync_global(smmu); writel(reg, ARM_SMMU_GR0_NS(smmu) + ARM_SMMU_GR0_sCR0); -- GitLab From 0398322308d530a55341eb0dcd83f70555aae2cf Mon Sep 17 00:00:00 2001 From: Narendra Muppalla Date: Wed, 26 Jul 2017 15:17:54 -0700 Subject: [PATCH 0484/1635] ARM: dts: msm: add simulator panel support for sm8150 This change adds simulator panel support for command and video mode supporting multiple resolutions for MTP and CDP platform. Change-Id: Idd6107efafd09603d0ebea30207ad4f8c78c7271 Signed-off-by: Narendra Muppalla --- .../dts/qcom/dsi-panel-sim-dualmipi-cmd.dtsi | 77 ++++++++++++------- arch/arm64/boot/dts/qcom/sm8150-cdp.dtsi | 24 ++++++ arch/arm64/boot/dts/qcom/sm8150-mtp.dtsi | 24 ++++++ .../boot/dts/qcom/sm8150-sde-display.dtsi | 40 +++++----- 4 files changed, 119 insertions(+), 46 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-sim-dualmipi-cmd.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-sim-dualmipi-cmd.dtsi index a93deb55ff2f..870e2b3d8072 100644 --- a/arch/arm64/boot/dts/qcom/dsi-panel-sim-dualmipi-cmd.dtsi +++ b/arch/arm64/boot/dts/qcom/dsi-panel-sim-dualmipi-cmd.dtsi @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -46,6 +46,31 @@ qcom,mdss-dsi-display-timings { timing@0{ + qcom,mdss-dsi-panel-width = <540>; + qcom,mdss-dsi-panel-height = <1920>; + qcom,mdss-dsi-h-front-porch = <28>; + qcom,mdss-dsi-h-back-porch = <4>; + qcom,mdss-dsi-h-pulse-width = <4>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <12>; + qcom,mdss-dsi-v-front-porch = <12>; + qcom,mdss-dsi-v-pulse-width = <2>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-panel-framerate = <120>; + qcom,mdss-dsi-on-command = + [/* exit sleep mode, wait 0ms */ + 05 01 00 00 00 00 01 29]; + /* Set display on, wait 16ms */ + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command = + [05 01 00 00 00 00 02 28 00 + 05 01 00 00 00 00 02 10 00]; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + }; + timing@1{ qcom,mdss-dsi-panel-width = <1280>; qcom,mdss-dsi-panel-height = <1440>; qcom,mdss-dsi-h-front-porch = <120>; @@ -62,33 +87,33 @@ qcom,mdss-dsi-h-sync-pulse = <0>; qcom,mdss-dsi-panel-framerate = <60>; qcom,mdss-dsi-on-command = - [29 01 00 00 00 00 02 b0 03 - 05 01 00 00 0a 00 01 00 - /* Soft reset, wait 10ms */ - 15 01 00 00 0a 00 02 3a 77 - /* Set Pixel format (24 bpp) */ - 39 01 00 00 0a 00 05 2a 00 00 04 ff - /* Set Column address */ - 39 01 00 00 0a 00 05 2b 00 00 05 9f - /* Set page address */ - 15 01 00 00 0a 00 02 35 00 - /* Set tear on */ - 39 01 00 00 0a 00 03 44 00 00 - /* Set tear scan line */ - 15 01 00 00 0a 00 02 51 ff - /* write display brightness */ - 15 01 00 00 0a 00 02 53 24 - /* write control brightness */ - 15 01 00 00 0a 00 02 55 00 - /* CABC brightness */ - 05 01 00 00 78 00 01 11 - /* exit sleep mode, wait 120ms */ - 05 01 00 00 10 00 01 29]; - /* Set display on, wait 16ms */ + [/* exit sleep mode, wait 0ms */ + 05 01 00 00 00 00 01 29]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command = + [05 01 00 00 00 00 02 28 00 + 05 01 00 00 00 00 02 10 00]; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + }; + timing@2{ + qcom,mdss-dsi-panel-width = <1080>; + qcom,mdss-dsi-panel-height = <3840>; + qcom,mdss-dsi-h-front-porch = <30>; + qcom,mdss-dsi-h-back-porch = <100>; + qcom,mdss-dsi-h-pulse-width = <4>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <7>; + qcom,mdss-dsi-v-front-porch = <8>; + qcom,mdss-dsi-v-pulse-width = <1>; + qcom,mdss-dsi-h-sync-pulse = <0>; + qcom,mdss-dsi-panel-framerate = <40>; + qcom,mdss-dsi-on-command = + [/* exit sleep mode, wait 0ms */ + 05 01 00 00 00 00 01 29]; qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; qcom,mdss-dsi-off-command = - [05 01 00 00 32 00 02 28 00 - 05 01 00 00 78 00 02 10 00]; + [05 01 00 00 00 00 02 28 00 + 05 01 00 00 00 00 02 10 00]; qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; }; }; diff --git a/arch/arm64/boot/dts/qcom/sm8150-cdp.dtsi b/arch/arm64/boot/dts/qcom/sm8150-cdp.dtsi index 98208f2a82c0..1fe456466a23 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-cdp.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-cdp.dtsi @@ -114,6 +114,30 @@ qcom,platform-reset-gpio = <&tlmm 6 0>; }; +&dsi_sim_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,platform-reset-gpio = <&tlmm 6 0>; +}; + +&dsi_sim_vid { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,platform-reset-gpio = <&tlmm 6 0>; +}; + +&dsi_dual_sim_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,platform-reset-gpio = <&tlmm 6 0>; +}; + +&dsi_dual_sim_vid { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,platform-reset-gpio = <&tlmm 6 0>; +}; + &dsi_dual_nt35597_truly_video { qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; diff --git a/arch/arm64/boot/dts/qcom/sm8150-mtp.dtsi b/arch/arm64/boot/dts/qcom/sm8150-mtp.dtsi index 8ae926fcfb4f..7575e1c32c73 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-mtp.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-mtp.dtsi @@ -114,6 +114,30 @@ qcom,platform-reset-gpio = <&tlmm 6 0>; }; +&dsi_sim_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,platform-reset-gpio = <&tlmm 6 0>; +}; + +&dsi_sim_vid { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,platform-reset-gpio = <&tlmm 6 0>; +}; + +&dsi_dual_sim_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,platform-reset-gpio = <&tlmm 6 0>; +}; + +&dsi_dual_sim_vid { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,platform-reset-gpio = <&tlmm 6 0>; +}; + &dsi_dual_nt35597_truly_video { qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; diff --git a/arch/arm64/boot/dts/qcom/sm8150-sde-display.dtsi b/arch/arm64/boot/dts/qcom/sm8150-sde-display.dtsi index a86d4ff1fc54..b3ffea9ae99b 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-sde-display.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-sde-display.dtsi @@ -508,12 +508,12 @@ }; &dsi_sim_vid { - qcom,mdss-dsi-t-clk-post = <0x0d>; - qcom,mdss-dsi-t-clk-pre = <0x2d>; + qcom,mdss-dsi-t-clk-post = <0x15>; + qcom,mdss-dsi-t-clk-pre = <0x12>; qcom,mdss-dsi-display-timings { timing@0{ - qcom,mdss-dsi-panel-phy-timings = [01 03 01 00 01 01 01 - 01 00 03 04 00 03 04]; + qcom,mdss-dsi-panel-phy-timings = [00 1c 08 07 23 22 07 + 07 05 03 04 00 18 17]; qcom,display-topology = <1 0 1>, <2 0 1>; qcom,default-topology-index = <0>; @@ -522,12 +522,12 @@ }; &dsi_dual_sim_vid { - qcom,mdss-dsi-t-clk-post = <0x0d>; - qcom,mdss-dsi-t-clk-pre = <0x2d>; + qcom,mdss-dsi-t-clk-post = <0x15>; + qcom,mdss-dsi-t-clk-pre = <0x12>; qcom,mdss-dsi-display-timings { timing@0{ - qcom,mdss-dsi-panel-phy-timings = [00 13 03 03 05 06 03 - 03 02 03 04 00 10 06]; + qcom,mdss-dsi-panel-phy-timings = [00 1c 08 07 23 22 07 + 07 05 03 04 00 18 17]; qcom,display-topology = <2 0 2>, <1 0 2>; qcom,default-topology-index = <0>; @@ -536,12 +536,12 @@ }; &dsi_sim_cmd { - qcom,mdss-dsi-t-clk-post = <0x0d>; - qcom,mdss-dsi-t-clk-pre = <0x2d>; + qcom,mdss-dsi-t-clk-post = <0x15>; + qcom,mdss-dsi-t-clk-pre = <0x12>; qcom,mdss-dsi-display-timings { timing@0{ - qcom,mdss-dsi-panel-phy-timings = [00 03 01 00 01 01 02 - 01 00 03 04 00 03 04]; + qcom,mdss-dsi-panel-phy-timings = [00 1c 08 07 23 22 07 + 07 05 03 04 00 18 17]; qcom,display-topology = <1 0 1>, <2 0 1>; qcom,default-topology-index = <0>; @@ -550,25 +550,25 @@ }; &dsi_dual_sim_cmd { - qcom,mdss-dsi-t-clk-post = <0x0d>; - qcom,mdss-dsi-t-clk-pre = <0x2d>; + qcom,mdss-dsi-t-clk-post = <0x15>; + qcom,mdss-dsi-t-clk-pre = <0x12>; qcom,mdss-dsi-display-timings { timing@0{ - qcom,mdss-dsi-panel-phy-timings = [00 13 03 03 05 06 03 - 03 02 03 04 00 10 06]; + qcom,mdss-dsi-panel-phy-timings = [00 24 09 09 26 24 09 + 09 06 03 04 00]; qcom,display-topology = <2 0 2>; qcom,default-topology-index = <0>; }; timing@1{ - qcom,mdss-dsi-panel-phy-timings = [00 13 03 03 05 06 03 - 03 02 03 04 00 10 06]; + qcom,mdss-dsi-panel-phy-timings = [00 1c 08 07 23 22 07 + 07 05 03 04 00 18 17]; qcom,display-topology = <2 0 2>, <1 0 2>; qcom,default-topology-index = <0>; }; timing@2{ - qcom,mdss-dsi-panel-phy-timings = [00 13 03 03 05 06 03 - 03 02 03 04 00 10 06]; + qcom,mdss-dsi-panel-phy-timings = [00 1e 08 07 24 22 08 + 08 05 03 04 00 19 18]; qcom,display-topology = <2 0 2>; qcom,default-topology-index = <0>; }; -- GitLab From bafa59ad224ebdaab6d8edb5782d6c4b0419d303 Mon Sep 17 00:00:00 2001 From: Chris Lew Date: Wed, 11 Apr 2018 19:06:38 -0700 Subject: [PATCH 0485/1635] rpmsg: Guard against null endpoint ops in destroy In RPMSG GLINK, the chrdev device will allocate an ept as part of the rpdev creation. This device will not register endpoint ops even though it has an ept. Protect against the case where the device is being destroyed. Change-Id: If712d8a0a51404e97e246cc2c5085f6b0f6cf8f3 Signed-off-by: Chris Lew --- drivers/rpmsg/rpmsg_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/rpmsg/rpmsg_core.c b/drivers/rpmsg/rpmsg_core.c index 48913f2a2775..3799974b0b2f 100644 --- a/drivers/rpmsg/rpmsg_core.c +++ b/drivers/rpmsg/rpmsg_core.c @@ -89,7 +89,7 @@ EXPORT_SYMBOL(rpmsg_create_ept); */ void rpmsg_destroy_ept(struct rpmsg_endpoint *ept) { - if (ept) + if (ept && ept->ops) ept->ops->destroy_ept(ept); } EXPORT_SYMBOL(rpmsg_destroy_ept); -- GitLab From 653eb189246d7aec15b9ba860520fe4758ee18da Mon Sep 17 00:00:00 2001 From: Chris Lew Date: Tue, 17 Apr 2018 17:58:56 -0700 Subject: [PATCH 0486/1635] rpmsg: glink: spss: Unmap mailbox descriptors correctly The mailbox descriptors registers are mapped using the devm variant of ioremap. Switch the unmap function to the devm variant to prevent unmap warnings when the glink device is unregistered. Change-Id: Iafe0fcb673f215479ca13b1e0df0d96bdbc87fc8 Signed-off-by: Chris Lew --- drivers/rpmsg/qcom_glink_spss.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/rpmsg/qcom_glink_spss.c b/drivers/rpmsg/qcom_glink_spss.c index 1032f12372e6..832dd7446a81 100644 --- a/drivers/rpmsg/qcom_glink_spss.c +++ b/drivers/rpmsg/qcom_glink_spss.c @@ -210,8 +210,8 @@ static int glink_spss_advertise_cfg(struct device *dev, *spss_addr = cpu_to_le64(addr); *spss_size = cpu_to_le32(size); - iounmap(spss_addr); - iounmap(spss_size); + devm_iounmap(dev, spss_addr); + devm_iounmap(dev, spss_size); return 0; } -- GitLab From 1b4302372f48047d4d6164641ea37bea1f85e2b8 Mon Sep 17 00:00:00 2001 From: Chris Lew Date: Tue, 17 Apr 2018 18:05:22 -0700 Subject: [PATCH 0487/1635] rpmsg: glink: Add pipe reset functionality Some remote procs do not initialize the pipe when they are started and assume the data in the pipe descriptors is valid. Add an optional handler to clear the pipe descriptors and call this during removal of the glink device to ensure a clean restart of glink. Change-Id: I62871cc5d6fd052e234843645299fdc87a71185f Signed-off-by: Chris Lew --- drivers/rpmsg/qcom_glink_native.c | 11 +++++++++++ drivers/rpmsg/qcom_glink_native.h | 2 ++ 2 files changed, 13 insertions(+) diff --git a/drivers/rpmsg/qcom_glink_native.c b/drivers/rpmsg/qcom_glink_native.c index b9e24b030881..b54be731f7b9 100644 --- a/drivers/rpmsg/qcom_glink_native.c +++ b/drivers/rpmsg/qcom_glink_native.c @@ -317,6 +317,15 @@ static void qcom_glink_tx_write(struct qcom_glink *glink, glink->tx_pipe->write(glink->tx_pipe, hdr, hlen, data, dlen); } +static void qcom_glink_pipe_reset(struct qcom_glink *glink) +{ + if (glink->tx_pipe->reset) + glink->tx_pipe->reset(glink->tx_pipe); + + if (glink->rx_pipe->reset) + glink->rx_pipe->reset(glink->rx_pipe); +} + static int qcom_glink_tx(struct qcom_glink *glink, const void *hdr, size_t hlen, const void *data, size_t dlen, bool wait) @@ -1852,6 +1861,8 @@ void qcom_glink_native_remove(struct qcom_glink *glink) idr_destroy(&glink->lcids); idr_destroy(&glink->rcids); spin_unlock_irqrestore(&glink->idr_lock, flags); + + qcom_glink_pipe_reset(glink); mbox_free_channel(glink->mbox_chan); } EXPORT_SYMBOL_GPL(qcom_glink_native_remove); diff --git a/drivers/rpmsg/qcom_glink_native.h b/drivers/rpmsg/qcom_glink_native.h index 0cae8a8199f8..32f1b57868cc 100644 --- a/drivers/rpmsg/qcom_glink_native.h +++ b/drivers/rpmsg/qcom_glink_native.h @@ -30,6 +30,8 @@ struct qcom_glink_pipe { void (*write)(struct qcom_glink_pipe *glink_pipe, const void *hdr, size_t hlen, const void *data, size_t dlen); + + void (*reset)(struct qcom_glink_pipe *glink_pipe); }; struct qcom_glink; -- GitLab From 690467312a735e0df4e7c6343fe19386fe2c040d Mon Sep 17 00:00:00 2001 From: Chris Lew Date: Tue, 17 Apr 2018 18:09:40 -0700 Subject: [PATCH 0488/1635] rpmsg: glink: spss: Add pipe reset handlers SPSS assumes the data in the spss fifo descriptors is correct if the mailbox registers are initialized. Add handlers to reset the pipe for the SSR case. Change-Id: I4eb76018b8be934fc96857dcf2ee62e3c7b73e95 Signed-off-by: Chris Lew --- drivers/rpmsg/qcom_glink_spss.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/rpmsg/qcom_glink_spss.c b/drivers/rpmsg/qcom_glink_spss.c index 832dd7446a81..7ff798326d9e 100644 --- a/drivers/rpmsg/qcom_glink_spss.c +++ b/drivers/rpmsg/qcom_glink_spss.c @@ -53,6 +53,14 @@ struct glink_spss_pipe { #define to_spss_pipe(p) container_of(p, struct glink_spss_pipe, native) +static void glink_spss_reset(struct qcom_glink_pipe *np) +{ + struct glink_spss_pipe *pipe = to_spss_pipe(np); + + *pipe->head = cpu_to_le32(0); + *pipe->tail = cpu_to_le32(0); +} + static size_t glink_spss_rx_avail(struct qcom_glink_pipe *np) { struct glink_spss_pipe *pipe = to_spss_pipe(np); @@ -296,10 +304,12 @@ struct qcom_glink *qcom_glink_spss_register(struct device *parent, rx_pipe->native.avail = glink_spss_rx_avail; rx_pipe->native.peak = glink_spss_rx_peak; rx_pipe->native.advance = glink_spss_rx_advance; + rx_pipe->native.reset = glink_spss_reset; rx_pipe->remote_pid = remote_pid; tx_pipe->native.avail = glink_spss_tx_avail; tx_pipe->native.write = glink_spss_tx_write; + tx_pipe->native.reset = glink_spss_reset; tx_pipe->remote_pid = remote_pid; *rx_pipe->tail = 0; -- GitLab From cc17f70c430471338dfab0330660fad2d9347cc2 Mon Sep 17 00:00:00 2001 From: Chris Lew Date: Wed, 11 Apr 2018 19:59:45 -0700 Subject: [PATCH 0489/1635] soc: qcom: glink_probe: Add SSR support for GLINK RPMSG GLINK should be registered and unregisted as the remote processor comes up and down. During probe time, register a notifier block for each subsystem specified in device tree. The GLINK_SSR channel is part of the SSR handling for the GLINK RPMSG framework. Register as a rpmsg driver for the GLINK SSR driver and send the required SSR notifications to interested subsystems. The GLINK subsystem names differ from the PIL image names. Add a device tree property to keep track of the GLINK name and the PIL names. Change-Id: Ic6d5130a1f15776e51ba6698c7d09d561d9f967f Signed-off-by: Chris Lew --- .../bindings/soc/qcom/qcom,glink-probe.txt | 41 +- drivers/soc/qcom/glink_probe.c | 376 +++++++++++++++++- 2 files changed, 394 insertions(+), 23 deletions(-) diff --git a/Documentation/devicetree/bindings/soc/qcom/qcom,glink-probe.txt b/Documentation/devicetree/bindings/soc/qcom/qcom,glink-probe.txt index af7b3f9c1a15..badb9f9bcd53 100644 --- a/Documentation/devicetree/bindings/soc/qcom/qcom,glink-probe.txt +++ b/Documentation/devicetree/bindings/soc/qcom/qcom,glink-probe.txt @@ -13,26 +13,57 @@ The GLINK probe node must contain subnodes that describes the edge-pairs. See qcom,glink.txt for details on how to describe them. In addition to the properties in qcom,glink.txt, The GLINK Probe driver -requires the remote-pid and transport type to be specified in the subnodes. +requires the qcom,glink-label and transport type to be specified in the +subnodes. - transport : Usage: required Value type: Definition: must be "smem", "spss", or "spi" -- qcom,remote-pid : +- qcom,glink-label : Usage: required - Value type: + Value type: Definition: specifies the identifier of the remote proc of this edge. += GLINK_SSR +The GLINK probe driver also initializes the GLINK_SSR channel for the edges +that it brings up. The channel should be specified as a subnode to each edge. In +addition to the properties in qcom,glink.txt to specify a channel device node, +the qcom,notify-edges property must be defined. + +- qcom,notify-edges : + Usage: required + Value type: + Definition: list of phandles that specify the subsystems this glink edge + needs to receive ssr notifications about. + = EXAMPLE qcom,glink { compatible = "qcom,glink"; - modem { + glink_modem: modem { transport = "smem"; - qcom,remote-pid = <1>; + qcom,remote-pid = <0>; mboxes = <&apcs_glb 8>; mbox-names = "mpss_smem"; interrupts = ; + + qcom,modem_glink_ssr { + qcom,glink-channels = "glink_ssr"; + qcom,notify-edges = <&glink_adsp>; + }; + }; + + glink_adsp: adsp { + transport = "smem"; + qcom,remote-pid = <2>; + mboxes = <&apcs_glb 4>; + mbox-names = "adsp_smem"; + interrupts = ; + + qcom,modem_glink_ssr { + qcom,glink-channels = "glink_ssr"; + qcom,notify-edges = <&glink_modem>; + }; }; }; diff --git a/drivers/soc/qcom/glink_probe.c b/drivers/soc/qcom/glink_probe.c index 5d32a6b686e0..cc1b52387a0b 100644 --- a/drivers/soc/qcom/glink_probe.c +++ b/drivers/soc/qcom/glink_probe.c @@ -11,47 +11,384 @@ */ #include +#include +#include #include +#include #include +#include #include +#include +#include -#define NUM_SUBSYSTEMS 10 -static struct qcom_glink *edge_infos[NUM_SUBSYSTEMS]; +#define GLINK_PROBE_LOG_PAGE_CNT 4 +static void *glink_ilc; + +#define GLINK_INFO(x, ...) \ +do { \ + if (glink_ilc) \ + ipc_log_string(glink_ilc, "[%s]: "x, __func__, ##__VA_ARGS__); \ +} while (0) + +#define GLINK_ERR(dev, x, ...) \ +do { \ + dev_err(dev, "[%s]: "x, __func__, ##__VA_ARGS__); \ + if (glink_ilc) \ + ipc_log_string(glink_ilc, "[%s]: "x, __func__, ##__VA_ARGS__); \ +} while (0) + + +#define GLINK_SSR_DO_CLEANUP 0 +#define GLINK_SSR_CLEANUP_DONE 1 +#define GLINK_SSR_PRIORITY 1 +#define GLINK_SSR_REPLY_TIMEOUT HZ + +struct do_cleanup_msg { + __le32 version; + __le32 command; + __le32 seq_num; + __le32 name_len; + char name[32]; +}; + +struct cleanup_done_msg { + __le32 version; + __le32 response; + __le32 seq_num; +}; + +struct glink_ssr_nb { + struct list_head list; + struct glink_ssr *ssr; + void *ssr_register_handle; + + const char *glink_label; + const char *ssr_label; + + struct notifier_block nb; +}; + +struct glink_ssr { + struct device *dev; + struct rpmsg_endpoint *ept; + + struct list_head notify_list; + + u32 seq_num; + struct completion completion; +}; + +struct edge_info { + struct list_head list; + struct device *dev; + struct device_node *node; + + const char *glink_label; + const char *ssr_label; + void *glink; + + int (*register_fn)(struct edge_info *); + void (*unregister_fn)(struct edge_info *); + struct notifier_block nb; +}; +LIST_HEAD(edge_infos); + +static int glink_ssr_ssr_cb(struct notifier_block *this, + unsigned long code, void *data) +{ + struct glink_ssr_nb *nb = container_of(this, struct glink_ssr_nb, nb); + struct glink_ssr *ssr = nb->ssr; + struct device *dev = ssr->dev; + struct do_cleanup_msg msg; + int ret; + + if (code == SUBSYS_AFTER_SHUTDOWN) { + ssr->seq_num++; + reinit_completion(&ssr->completion); + + memset(&msg, 0, sizeof(msg)); + msg.command = cpu_to_le32(GLINK_SSR_DO_CLEANUP); + msg.seq_num = cpu_to_le32(ssr->seq_num); + msg.name_len = cpu_to_le32(strlen(nb->glink_label)); + strlcpy(msg.name, nb->glink_label, sizeof(msg.name)); + + GLINK_INFO("%s: notify of %s seq_num:%d\n", + dev->parent->of_node->name, nb->glink_label, + ssr->seq_num); + + ret = rpmsg_send(ssr->ept, &msg, sizeof(msg)); + if (ret) + GLINK_ERR(dev, "fail to send do cleanup to %s %d\n", + nb->ssr_label, ret); + + ret = wait_for_completion_timeout(&ssr->completion, HZ); + if (!ret) + GLINK_ERR(dev, "timeout waiting for cleanup resp\n"); + + } + return NOTIFY_DONE; +} + +static int glink_ssr_callback(struct rpmsg_device *rpdev, + void *data, int len, void *priv, u32 addr) +{ + struct cleanup_done_msg *msg = data; + struct glink_ssr *ssr = dev_get_drvdata(&rpdev->dev); + + if (len < sizeof(*msg)) { + GLINK_ERR(ssr->dev, "message too short\n"); + return -EINVAL; + } + + if (le32_to_cpu(msg->version) != 0) { + GLINK_ERR(ssr->dev, "invalid version\n"); + return -EINVAL; + } + + if (le32_to_cpu(msg->response) != GLINK_SSR_CLEANUP_DONE) + return 0; + + if (le32_to_cpu(msg->seq_num) != ssr->seq_num) { + GLINK_ERR(ssr->dev, "invalid response sequence number %d\n", + msg->seq_num); + return -EINVAL; + } + + complete(&ssr->completion); + + GLINK_INFO("%s: received seq_num:%d\n", ssr->dev->parent->of_node->name, + le32_to_cpu(msg->seq_num)); + + return 0; +} + +static void glink_ssr_init_notify(struct glink_ssr *ssr) +{ + struct device *dev = ssr->dev; + struct device_node *node; + struct glink_ssr_nb *nb; + void *handle; + int ret; + int i = 0; + + while (1) { + node = of_parse_phandle(dev->of_node, "qcom,notify-edges", i++); + if (!node) + break; + + nb = devm_kzalloc(dev, sizeof(*nb), GFP_KERNEL); + if (!nb) + return; + + ret = of_property_read_string(node, "label", &nb->ssr_label); + if (ret < 0) + nb->ssr_label = node->name; + + ret = of_property_read_string(node, "qcom,glink-label", + &nb->glink_label); + if (ret < 0) { + GLINK_ERR(dev, "no qcom,glink-label for %s\n", + nb->ssr_label); + continue; + } + + nb->nb.notifier_call = glink_ssr_ssr_cb; + nb->nb.priority = GLINK_SSR_PRIORITY; + + handle = subsys_notif_register_notifier(nb->ssr_label, &nb->nb); + if (IS_ERR_OR_NULL(handle)) { + GLINK_ERR(dev, "register fail for %s SSR notifier\n", + nb->ssr_label); + continue; + } + + nb->ssr = ssr; + nb->ssr_register_handle = handle; + list_add_tail(&nb->list, &ssr->notify_list); + } +} + +static int glink_ssr_probe(struct rpmsg_device *rpdev) +{ + struct glink_ssr *ssr; + + ssr = devm_kzalloc(&rpdev->dev, sizeof(*ssr), GFP_KERNEL); + if (!ssr) + return -ENOMEM; + + INIT_LIST_HEAD(&ssr->notify_list); + init_completion(&ssr->completion); + + ssr->dev = &rpdev->dev; + ssr->ept = rpdev->ept; + + glink_ssr_init_notify(ssr); + + dev_set_drvdata(&rpdev->dev, ssr); + + return 0; +} + +static void glink_ssr_remove(struct rpmsg_device *rpdev) +{ + struct glink_ssr *ssr = dev_get_drvdata(&rpdev->dev); + struct glink_ssr_nb *nb; + + list_for_each_entry(nb, &ssr->notify_list, list) { + subsys_notif_unregister_notifier(nb->ssr_register_handle, + &nb->nb); + } + + dev_set_drvdata(&rpdev->dev, NULL); +} + +static const struct rpmsg_device_id glink_ssr_match[] = { + { "glink_ssr" }, + {} +}; + +static struct rpmsg_driver glink_ssr_driver = { + .probe = glink_ssr_probe, + .remove = glink_ssr_remove, + .callback = glink_ssr_callback, + .id_table = glink_ssr_match, + .drv = { + .name = "glink_ssr", + }, +}; +module_rpmsg_driver(glink_ssr_driver); + +static int glink_probe_ssr_cb(struct notifier_block *this, + unsigned long code, void *data) +{ + struct edge_info *einfo = container_of(this, struct edge_info, nb); + + GLINK_INFO("received %d for %s", code, einfo->ssr_label); + + switch (code) { + case SUBSYS_AFTER_POWERUP: + einfo->register_fn(einfo); + break; + case SUBSYS_AFTER_SHUTDOWN: + einfo->unregister_fn(einfo); + break; + default: + break; + } + return NOTIFY_DONE; +} + +static int glink_probe_smem_reg(struct edge_info *einfo) +{ + struct device *dev = einfo->dev; + + einfo->glink = qcom_glink_smem_register(dev, einfo->node); + if (IS_ERR_OR_NULL(einfo->glink)) { + GLINK_ERR(dev, "register failed for %s\n", einfo->ssr_label); + einfo->glink = NULL; + } + GLINK_INFO("register successful for %s\n", einfo->ssr_label); + + return 0; +} + +static void glink_probe_smem_unreg(struct edge_info *einfo) +{ + if (einfo->glink) + qcom_glink_smem_unregister(einfo->glink); + + einfo->glink = NULL; + GLINK_INFO("unregister for %s\n", einfo->ssr_label); + +} + +static int glink_probe_spss_reg(struct edge_info *einfo) +{ + struct device *dev = einfo->dev; + + einfo->glink = qcom_glink_spss_register(dev, einfo->node); + if (IS_ERR_OR_NULL(einfo->glink)) { + GLINK_ERR(dev, "register failed for %s\n", einfo->ssr_label); + einfo->glink = NULL; + } + GLINK_INFO("register successful for %s\n", einfo->ssr_label); + + return 0; +} + +static void glink_probe_spss_unreg(struct edge_info *einfo) +{ + if (einfo->glink) + qcom_glink_spss_unregister(einfo->glink); + + einfo->glink = NULL; + GLINK_INFO("unregister for %s\n", einfo->ssr_label); +} static void probe_subsystem(struct device *dev, struct device_node *np) { - struct qcom_glink *glink = ERR_PTR(-EINVAL); + struct edge_info *einfo; const char *transport; - u32 pid; + void *handle; int ret; - ret = of_property_read_u32(np, "qcom,remote-pid", &pid); - if (ret || pid >= NUM_SUBSYSTEMS) { - dev_err(dev, "invalid pid:%d ret:%d\n", pid, ret); + einfo = devm_kzalloc(dev, sizeof(*einfo), GFP_KERNEL); + if (!einfo) return; + + ret = of_property_read_string(np, "label", &einfo->ssr_label); + if (ret < 0) + einfo->ssr_label = np->name; + + ret = of_property_read_string(np, "qcom,glink-label", + &einfo->glink_label); + if (ret < 0) { + GLINK_ERR(dev, "no qcom,glink-label for %s\n", + einfo->ssr_label); + goto free_einfo; } + einfo->dev = dev; + einfo->node = np; + ret = of_property_read_string(np, "transport", &transport); if (ret < 0) { - dev_err(dev, "missing transport pid:%d\n", pid); - return; + GLINK_ERR(dev, "%s missing transport\n", einfo->ssr_label); + goto free_einfo; } - if (!strcmp(transport, "smem")) - glink = qcom_glink_smem_register(dev, np); - else if (!strcmp(transport, "spss")) - glink = qcom_glink_spss_register(dev, np); - if (IS_ERR(glink)) { - dev_err(dev, "%s failed %d\n", np->name, PTR_ERR(glink)); - return; + if (!strcmp(transport, "smem")) { + einfo->register_fn = glink_probe_smem_reg; + einfo->unregister_fn = glink_probe_smem_unreg; + } else if (!strcmp(transport, "spss")) { + einfo->register_fn = glink_probe_spss_reg; + einfo->unregister_fn = glink_probe_spss_unreg; } - edge_infos[pid] = glink; + + einfo->nb.notifier_call = glink_probe_ssr_cb; + + handle = subsys_notif_register_notifier(einfo->ssr_label, &einfo->nb); + if (IS_ERR_OR_NULL(handle)) { + GLINK_ERR(dev, "could not register for SSR notifier for %s\n", + einfo->ssr_label); + goto free_einfo; + } + + list_add_tail(&einfo->list, &edge_infos); + GLINK_INFO("probe successful for %s\n", einfo->ssr_label); + + return; + +free_einfo: + devm_kfree(dev, einfo); + return; } static int glink_probe(struct platform_device *pdev) { - struct device_node *cn, *pn = pdev->dev.of_node; + struct device_node *pn = pdev->dev.of_node; + struct device_node *cn; for_each_available_child_of_node(pn, cn) { probe_subsystem(&pdev->dev, cn); @@ -77,6 +414,9 @@ static int __init glink_probe_init(void) { int ret; + glink_ilc = ipc_log_context_create(GLINK_PROBE_LOG_PAGE_CNT, + "glink_probe", 0); + ret = platform_driver_register(&glink_probe_driver); if (ret) { pr_err("%s: glink_probe register failed %d\n", -- GitLab From aa947bfb4aef861fdb5cf90f84383f1219f7d566 Mon Sep 17 00:00:00 2001 From: Chris Lew Date: Wed, 11 Apr 2018 20:07:13 -0700 Subject: [PATCH 0490/1635] ARM: dts: msm: Update glink nodes for sm8150 Update the GLINK device nodes to have the label and qcom,glink-label properties to support SSR handling. Add the glink_ssr channel and the required properties for modem, adsp, slpi, cdsp and slpi. Rename the glink channels to the format qcom,channel-name. Change-Id: Iefd3e36b6a367db204c78574ba4ac1607d89067c Signed-off-by: Chris Lew --- arch/arm64/boot/dts/qcom/sm8150.dtsi | 79 ++++++++++++++++++++++------ 1 file changed, 64 insertions(+), 15 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sm8150.dtsi b/arch/arm64/boot/dts/qcom/sm8150.dtsi index 7b591d8585a0..94dd9deb10c3 100644 --- a/arch/arm64/boot/dts/qcom/sm8150.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150.dtsi @@ -2307,14 +2307,17 @@ #size-cells = <1>; ranges; - modem { + glink_modem: modem { qcom,remote-pid = <1>; transport = "smem"; mboxes = <&apcs_glb 12>; mbox-names = "mpss_smem"; interrupts = ; - modem_qrtr { + label = "modem"; + qcom,glink-label = "mpss"; + + qcom,modem_qrtr { qcom,glink-channels = "IPCRTR"; qcom,intents = <0x800 5 0x2000 3 @@ -2327,27 +2330,38 @@ qcom,intents = <0x64 64>; }; - modem_ds { + qcom,modem_ds { qcom,glink-channels = "DS"; qcom,intents = <0x4000 0x2>; }; + + qcom,modem_glink_ssr { + qcom,glink-channels = "glink_ssr"; + qcom,notify-edges = <&glink_adsp>, + <&glink_slpi>, + <&glink_cdsp>, + <&glink_spss>; + }; }; - adsp { + glink_adsp: adsp { qcom,remote-pid = <2>; transport = "smem"; mboxes = <&apcs_glb 8>; mbox-names = "adsp_smem"; interrupts = ; - adsp_qrtr { + label = "adsp"; + qcom,glink-label = "lpass"; + + qcom,adsp_qrtr { qcom,glink-channels = "IPCRTR"; qcom,intents = <0x800 5 0x2000 3 0x4400 2>; }; - apr_tal_rpmsg { + qcom,apr_tal_rpmsg { qcom,glink-channels = "apr_audio_svc"; qcom,intents = <0x200 20>; }; @@ -2357,16 +2371,26 @@ qcom,glink-channels = "fastrpcglink-apps-dsp"; qcom,intents = <0x64 64>; }; + + qcom,adsp_glink_ssr { + qcom,glink-channels = "glink_ssr"; + qcom,notify-edges = <&glink_modem>, + <&glink_slpi>, + <&glink_cdsp>; + }; }; - dsps { + glink_slpi: dsps { qcom,remote-pid = <3>; transport = "smem"; mboxes = <&apcs_glb 24>; mbox-names = "dsps_smem"; interrupts = ; - dsps_qrtr { + label = "slpi"; + qcom,glink-label = "dsps"; + + qcom,slpi_qrtr { qcom,glink-channels = "IPCRTR"; qcom,intents = <0x800 5 0x2000 3 @@ -2378,16 +2402,26 @@ qcom,glink-channels = "fastrpcglink-apps-dsp"; qcom,intents = <0x64 64>; }; + + qcom,slpi_glink_ssr { + qcom,glink-channels = "glink_ssr"; + qcom,notify-edges = <&glink_modem>, + <&glink_adsp>, + <&glink_cdsp>; + }; }; - cdsp { + glink_cdsp: cdsp { qcom,remote-pid = <5>; transport = "smem"; mboxes = <&apcs_glb 4>; mbox-names = "cdsp_smem"; interrupts = ; - cdsp_qrtr { + label = "cdsp"; + qcom,glink-label = "cdsp"; + + qcom,cdsp_qrtr { qcom,glink-channels = "IPCRTR"; qcom,intents = <0x800 5 0x2000 3 @@ -2399,9 +2433,16 @@ qcom,glink-channels = "fastrpcglink-apps-dsp"; qcom,intents = <0x64 64>; }; + + qcom,cdsp_glink_ssr { + qcom,glink-channels = "glink_ssr"; + qcom,notify-edges = <&glink_modem>, + <&glink_adsp>, + <&glink_slpi>; + }; }; - spss { + glink_spss: spss { qcom,remote-pid = <8>; transport = "spss"; mboxes = <&sp_scsr 0>; @@ -2413,6 +2454,14 @@ <0x1885010 0x4>; reg-names = "qcom,spss-addr", "qcom,spss-size"; + + label = "spss"; + qcom,glink-label = "spss"; + + qcom,spss_glink_ssr { + qcom,glink-channels = "glink_ssr"; + qcom,notify-edges = <&glink_modem>; + }; }; glink_spi_xprt_wdsp: wdsp { @@ -2421,22 +2470,22 @@ tx-descriptors = <0x12000 0x12004>; rx-descriptors = <0x1200c 0x12010>; - wdsp_ctrl { + qcom,wdsp_ctrl { qcom,glink-channels = "g_glink_ctrl"; qcom,intents = <0x400 1>; }; - wdsp_ild { + qcom,wdsp_ild { qcom,glink-channels = "g_glink_persistent_data_ild"; }; - wdsp_nild { + qcom,wdsp_nild { qcom,glink-channels = "g_glink_persistent_data_nild"; }; - wdsp_data { + qcom,wdsp_data { qcom,glink-channels = "g_glink_audio_data"; qcom,intents = <0x1000 2>; }; -- GitLab From f950c534d22f4b1f3388d26a1714870b2bf5bf03 Mon Sep 17 00:00:00 2001 From: Jishnu Prakash Date: Fri, 13 Apr 2018 19:44:15 +0530 Subject: [PATCH 0491/1635] ARM: dts: msm: Add GPI DMA device tree nodes for sdm640 Add GPI device tree nodes for GPI DMA driver. The driver provides DMA capabilities for peripheral buses such as I2C, UART, and SPI. Change-Id: Id1c67bd0755d6d2659616463bf49aa2bdcd6a13a Signed-off-by: Jishnu Prakash --- arch/arm64/boot/dts/qcom/sdm640.dtsi | 32 ++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sdm640.dtsi b/arch/arm64/boot/dts/qcom/sdm640.dtsi index 74e81fc878dd..20a1e39dc3a9 100644 --- a/arch/arm64/boot/dts/qcom/sdm640.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm640.dtsi @@ -662,6 +662,38 @@ qcom,pipe-attr-ee; }; + gpi_dma0: qcom,gpi-dma@0x800000 { + #dma-cells = <5>; + compatible = "qcom,gpi-dma"; + reg = <0x800000 0x60000>; + reg-names = "gpi-top"; + interrupts = <0 244 0>, <0 245 0>, <0 246 0>, <0 247 0>, + <0 248 0>, <0 249 0>, <0 250 0>, <0 251 0>; + qcom,ev-factor = <2>; + qcom,max-num-gpii = <8>; + qcom,gpii-mask = <0x1f>; + iommus = <&apps_smmu 0x00d6 0x0>; + qcom,smmu-cfg = <0x1>; + qcom,iova-range = <0x0 0x100000 0x0 0x100000>; + status = "ok"; + }; + + gpi_dma1: qcom,gpi-dma@0xa00000 { + #dma-cells = <5>; + compatible = "qcom,gpi-dma"; + reg = <0xa00000 0x60000>; + reg-names = "gpi-top"; + interrupts = <0 279 0>, <0 280 0>, <0 281 0>, <0 282 0>, + <0 283 0>, <0 284 0>, <0 293 0>, <0 294 0>; + qcom,ev-factor = <2>; + qcom,max-num-gpii = <8>; + qcom,gpii-mask = <0x1f>; + qcom,smmu-cfg = <0x1>; + qcom,iova-range = <0x0 0x100000 0x0 0x100000>; + iommus = <&apps_smmu 0x0376 0x0>; + status = "ok"; + }; + qcom,msm-rtb { compatible = "qcom,msm-rtb"; qcom,rtb-size = <0x100000>; -- GitLab From 073e82701bc02c18ffb01579fa2b4971149d1976 Mon Sep 17 00:00:00 2001 From: Jozsef Kadlecsik Date: Sat, 6 Jan 2018 15:24:18 +0100 Subject: [PATCH 0492/1635] netfilter: ipset: Missing nfnl_lock()/nfnl_unlock() is added to ip_set_net_exit() commit f998b6b10144cd9809da6af02758615f789e8aa1 upstream. Patch "netfilter: ipset: use nfnl_mutex_is_locked" is added the real mutex locking check, which revealed the missing locking in ip_set_net_exit(). Signed-off-by: Jozsef Kadlecsik Reported-by: syzbot+36b06f219f2439fe62e1@syzkaller.appspotmail.com Signed-off-by: Pablo Neira Ayuso Signed-off-by: Greg Kroah-Hartman --- net/netfilter/ipset/ip_set_core.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/net/netfilter/ipset/ip_set_core.c b/net/netfilter/ipset/ip_set_core.c index cf84f7b37cd9..9d2ce1459cec 100644 --- a/net/netfilter/ipset/ip_set_core.c +++ b/net/netfilter/ipset/ip_set_core.c @@ -2055,6 +2055,7 @@ ip_set_net_exit(struct net *net) inst->is_deleted = true; /* flag for ip_set_nfnl_put */ + nfnl_lock(NFNL_SUBSYS_IPSET); for (i = 0; i < inst->ip_set_max; i++) { set = ip_set(inst, i); if (set) { @@ -2062,6 +2063,7 @@ ip_set_net_exit(struct net *net) ip_set_destroy_set(set); } } + nfnl_unlock(NFNL_SUBSYS_IPSET); kfree(rcu_dereference_protected(inst->ip_set_list, 1)); } -- GitLab From 856d5d075a92c5b3e41d366369dda1e5a5f7cc67 Mon Sep 17 00:00:00 2001 From: Bassem Boubaker Date: Wed, 11 Apr 2018 13:15:53 +0200 Subject: [PATCH 0493/1635] cdc_ether: flag the Cinterion AHS8 modem by gemalto as WWAN [ Upstream commit 53765341ee821c0a0f1dec41adc89c9096ad694c ] The Cinterion AHS8 is a 3G device with one embedded WWAN interface using cdc_ether as a driver. The modem is controlled via AT commands through the exposed TTYs. AT+CGDCONT write command can be used to activate or deactivate a WWAN connection for a PDP context defined with the same command. UE supports one WWAN adapter. Signed-off-by: Bassem Boubaker Acked-by: Oliver Neukum Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/usb/cdc_ether.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/net/usb/cdc_ether.c b/drivers/net/usb/cdc_ether.c index 05dca3e5c93d..178b956501a7 100644 --- a/drivers/net/usb/cdc_ether.c +++ b/drivers/net/usb/cdc_ether.c @@ -895,6 +895,12 @@ static const struct usb_device_id products[] = { USB_CDC_SUBCLASS_ETHERNET, USB_CDC_PROTO_NONE), .driver_info = (unsigned long)&wwan_info, +}, { + /* Cinterion AHS3 modem by GEMALTO */ + USB_DEVICE_AND_INTERFACE_INFO(0x1e2d, 0x0055, USB_CLASS_COMM, + USB_CDC_SUBCLASS_ETHERNET, + USB_CDC_PROTO_NONE), + .driver_info = (unsigned long)&wwan_info, }, { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ETHERNET, USB_CDC_PROTO_NONE), -- GitLab From 427b8a146973f10acd4aaa605d2377eb4cf43e55 Mon Sep 17 00:00:00 2001 From: Ka-Cheong Poon Date: Wed, 11 Apr 2018 00:57:25 -0700 Subject: [PATCH 0494/1635] rds: MP-RDS may use an invalid c_path [ Upstream commit a43cced9a348901f9015f4730b70b69e7c41a9c9 ] rds_sendmsg() calls rds_send_mprds_hash() to find a c_path to use to send a message. Suppose the RDS connection is not yet up. In rds_send_mprds_hash(), it does if (conn->c_npaths == 0) wait_event_interruptible(conn->c_hs_waitq, (conn->c_npaths != 0)); If it is interrupted before the connection is set up, rds_send_mprds_hash() will return a non-zero hash value. Hence rds_sendmsg() will use a non-zero c_path to send the message. But if the RDS connection ends up to be non-MP capable, the message will be lost as only the zero c_path can be used. Signed-off-by: Ka-Cheong Poon Acked-by: Santosh Shilimkar Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/rds/send.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/net/rds/send.c b/net/rds/send.c index f72466c63f0c..23f2d81e7967 100644 --- a/net/rds/send.c +++ b/net/rds/send.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006 Oracle. All rights reserved. + * Copyright (c) 2006, 2018 Oracle and/or its affiliates. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU @@ -986,10 +986,15 @@ static int rds_send_mprds_hash(struct rds_sock *rs, struct rds_connection *conn) if (conn->c_npaths == 0 && hash != 0) { rds_send_ping(conn, 0); - if (conn->c_npaths == 0) { - wait_event_interruptible(conn->c_hs_waitq, - (conn->c_npaths != 0)); - } + /* The underlying connection is not up yet. Need to wait + * until it is up to be sure that the non-zero c_path can be + * used. But if we are interrupted, we have to use the zero + * c_path in case the connection ends up being non-MP capable. + */ + if (conn->c_npaths == 0) + if (wait_event_interruptible(conn->c_hs_waitq, + conn->c_npaths != 0)) + hash = 0; if (conn->c_npaths == 1) hash = 0; } -- GitLab From 381ebff25898e62d3e12ac9b9bc2acbd64e543d6 Mon Sep 17 00:00:00 2001 From: Tejaswi Tanikella Date: Wed, 11 Apr 2018 16:34:47 +0530 Subject: [PATCH 0495/1635] slip: Check if rstate is initialized before uncompressing [ Upstream commit 3f01ddb962dc506916c243f9524e8bef97119b77 ] On receiving a packet the state index points to the rstate which must be used to fill up IP and TCP headers. But if the state index points to a rstate which is unitialized, i.e. filled with zeros, it gets stuck in an infinite loop inside ip_fast_csum trying to compute the ip checsum of a header with zero length. 89.666953: <2> [] slhc_uncompress+0x464/0x468 89.666965: <2> [] ppp_receive_nonmp_frame+0x3b4/0x65c 89.666978: <2> [] ppp_receive_frame+0x64/0x7e0 89.666991: <2> [] ppp_input+0x104/0x198 89.667005: <2> [] pppopns_recv_core+0x238/0x370 89.667027: <2> [] __sk_receive_skb+0xdc/0x250 89.667040: <2> [] pppopns_recv+0x44/0x60 89.667053: <2> [] __sock_queue_rcv_skb+0x16c/0x24c 89.667065: <2> [] sock_queue_rcv_skb+0x2c/0x38 89.667085: <2> [] raw_rcv+0x124/0x154 89.667098: <2> [] raw_local_deliver+0x1e0/0x22c 89.667117: <2> [] ip_local_deliver_finish+0x70/0x24c 89.667131: <2> [] ip_local_deliver+0x100/0x10c ./scripts/faddr2line vmlinux slhc_uncompress+0x464/0x468 output: ip_fast_csum at arch/arm64/include/asm/checksum.h:40 (inlined by) slhc_uncompress at drivers/net/slip/slhc.c:615 Adding a variable to indicate if the current rstate is initialized. If such a packet arrives, move to toss state. Signed-off-by: Tejaswi Tanikella Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/slip/slhc.c | 5 +++++ include/net/slhc_vj.h | 1 + 2 files changed, 6 insertions(+) diff --git a/drivers/net/slip/slhc.c b/drivers/net/slip/slhc.c index 5782733959f0..f4e93f5fc204 100644 --- a/drivers/net/slip/slhc.c +++ b/drivers/net/slip/slhc.c @@ -509,6 +509,10 @@ slhc_uncompress(struct slcompress *comp, unsigned char *icp, int isize) if(x < 0 || x > comp->rslot_limit) goto bad; + /* Check if the cstate is initialized */ + if (!comp->rstate[x].initialized) + goto bad; + comp->flags &=~ SLF_TOSS; comp->recv_current = x; } else { @@ -673,6 +677,7 @@ slhc_remember(struct slcompress *comp, unsigned char *icp, int isize) if (cs->cs_tcp.doff > 5) memcpy(cs->cs_tcpopt, icp + ihl*4 + sizeof(struct tcphdr), (cs->cs_tcp.doff - 5) * 4); cs->cs_hsize = ihl*2 + cs->cs_tcp.doff*2; + cs->initialized = true; /* Put headers back on packet * Neither header checksum is recalculated */ diff --git a/include/net/slhc_vj.h b/include/net/slhc_vj.h index 8716d5942b65..8fcf8908a694 100644 --- a/include/net/slhc_vj.h +++ b/include/net/slhc_vj.h @@ -127,6 +127,7 @@ typedef __u32 int32; */ struct cstate { byte_t cs_this; /* connection id number (xmit) */ + bool initialized; /* true if initialized */ struct cstate *next; /* next in ring (xmit) */ struct iphdr cs_ip; /* ip/tcp hdr from most recent packet */ struct tcphdr cs_tcp; -- GitLab From e240ffd5a3bea24906ae2cd375ec7a6f4810a77d Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Wed, 11 Apr 2018 10:35:40 +0800 Subject: [PATCH 0496/1635] vhost: fix vhost_vq_access_ok() log check [ Upstream commit d14d2b78090c7de0557362b26a4ca591aa6a9faa ] Commit d65026c6c62e7d9616c8ceb5a53b68bcdc050525 ("vhost: validate log when IOTLB is enabled") introduced a regression. The logic was originally: if (vq->iotlb) return 1; return A && B; After the patch the short-circuit logic for A was inverted: if (A || vq->iotlb) return A; return B; This patch fixes the regression by rewriting the checks in the obvious way, no longer returning A when vq->iotlb is non-NULL (which is hard to understand). Reported-by: syzbot+65a84dde0214b0387ccd@syzkaller.appspotmail.com Cc: Jason Wang Signed-off-by: Stefan Hajnoczi Acked-by: Michael S. Tsirkin Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/vhost/vhost.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c index c692e0b13242..40552a043c86 100644 --- a/drivers/vhost/vhost.c +++ b/drivers/vhost/vhost.c @@ -1252,10 +1252,12 @@ static int vq_log_access_ok(struct vhost_virtqueue *vq, /* Caller should have vq mutex and device mutex */ int vhost_vq_access_ok(struct vhost_virtqueue *vq) { - int ret = vq_log_access_ok(vq, vq->log_base); + if (!vq_log_access_ok(vq, vq->log_base)) + return 0; - if (ret || vq->iotlb) - return ret; + /* Access validation occurs at prefetch time with IOTLB */ + if (vq->iotlb) + return 1; return vq_access_ok(vq, vq->num, vq->desc, vq->avail, vq->used); } -- GitLab From 2ea541eb406468db42c25507c1df3a0d92fa0329 Mon Sep 17 00:00:00 2001 From: Eric Auger Date: Wed, 11 Apr 2018 15:30:38 +0200 Subject: [PATCH 0497/1635] vhost: Fix vhost_copy_to_user() [ Upstream commit 7ced6c98c7ab7a1f6743931e28671b833af79b1e ] vhost_copy_to_user is used to copy vring used elements to userspace. We should use VHOST_ADDR_USED instead of VHOST_ADDR_DESC. Fixes: f88949138058 ("vhost: introduce O(1) vq metadata cache") Signed-off-by: Eric Auger Acked-by: Jason Wang Acked-by: Michael S. Tsirkin Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/vhost/vhost.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c index 40552a043c86..8e3ca4400766 100644 --- a/drivers/vhost/vhost.c +++ b/drivers/vhost/vhost.c @@ -756,7 +756,7 @@ static int vhost_copy_to_user(struct vhost_virtqueue *vq, void __user *to, struct iov_iter t; void __user *uaddr = vhost_vq_meta_fetch(vq, (u64)(uintptr_t)to, size, - VHOST_ADDR_DESC); + VHOST_ADDR_USED); if (uaddr) return __copy_to_user(uaddr, from, size); -- GitLab From c0e0cd653e6a5584b245f0d3de477f073b7cb1c0 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Wed, 11 Apr 2018 10:59:17 +0100 Subject: [PATCH 0498/1635] lan78xx: Correctly indicate invalid OTP [ Upstream commit 4bfc33807a9a02764bdd1e42e794b3b401240f27 ] lan78xx_read_otp tries to return -EINVAL in the event of invalid OTP content, but the value gets overwritten before it is returned and the read goes ahead anyway. Make the read conditional as it should be and preserve the error code. Fixes: 55d7de9de6c3 ("Microchip's LAN7800 family USB 2/3 to 10/100/1000 Ethernet device driver") Signed-off-by: Phil Elwell Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/usb/lan78xx.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/usb/lan78xx.c b/drivers/net/usb/lan78xx.c index 89d82c4ee8df..1fb464837b3e 100644 --- a/drivers/net/usb/lan78xx.c +++ b/drivers/net/usb/lan78xx.c @@ -928,7 +928,8 @@ static int lan78xx_read_otp(struct lan78xx_net *dev, u32 offset, offset += 0x100; else ret = -EINVAL; - ret = lan78xx_read_raw_otp(dev, offset, length, data); + if (!ret) + ret = lan78xx_read_raw_otp(dev, offset, length, data); } return ret; -- GitLab From e7a4d7c2fe38147262dca2afeaf29a8f1a2adc7e Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 28 Mar 2018 13:59:22 -0400 Subject: [PATCH 0499/1635] media: v4l2-compat-ioctl32: don't oops on overlay commit 85ea29f19eab56ec16ec6b92bc67305998706afa upstream. At put_v4l2_window32(), it tries to access kp->clips. However, kp points to an userspace pointer. So, it should be obtained via get_user(), otherwise it can OOPS: vivid-000: ================== END STATUS ================== BUG: unable to handle kernel paging request at 00000000fffb18e0 IP: [] __put_v4l2_format32+0x169/0x220 [videodev] PGD 3f5776067 PUD 3f576f067 PMD 3f5769067 PTE 800000042548f067 Oops: 0001 [#1] SMP Modules linked in: vivid videobuf2_vmalloc videobuf2_memops v4l2_dv_timings videobuf2_core v4l2_common videodev media xt_CHECKSUM iptable_mangle ipt_MASQUERADE nf_nat_masquerade_ipv4 iptable_nat nf_nat_ipv4 nf_nat nf_conntrack_ipv4 nf_defrag_ipv4 xt_conntrack nf_conntrack tun bridge stp llc ebtable_filter ebtables ip6table_filter ip6_tables bluetooth rfkill binfmt_misc snd_hda_codec_hdmi i915 snd_hda_intel snd_hda_controller snd_hda_codec intel_rapl x86_pkg_temp_thermal snd_hwdep intel_powerclamp snd_pcm coretemp snd_seq_midi kvm_intel kvm snd_seq_midi_event snd_rawmidi i2c_algo_bit drm_kms_helper snd_seq drm crct10dif_pclmul e1000e snd_seq_device crc32_pclmul snd_timer ghash_clmulni_intel snd mei_me mei ptp pps_core soundcore lpc_ich video crc32c_intel [last unloaded: media] CPU: 2 PID: 28332 Comm: v4l2-compliance Not tainted 3.18.102+ #107 Hardware name: /NUC5i7RYB, BIOS RYBDWi35.86A.0364.2017.0511.0949 05/11/2017 task: ffff8804293f8000 ti: ffff8803f5640000 task.ti: ffff8803f5640000 RIP: 0010:[] [] __put_v4l2_format32+0x169/0x220 [videodev] RSP: 0018:ffff8803f5643e28 EFLAGS: 00010246 RAX: 0000000000000000 RBX: 0000000000000000 RCX: 00000000fffb1ab4 RDX: 00000000fffb1a68 RSI: 00000000fffb18d8 RDI: 00000000fffb1aa8 RBP: ffff8803f5643e48 R08: 0000000000000001 R09: ffff8803f54b0378 R10: 0000000000000000 R11: 0000000000000168 R12: 00000000fffb18c0 R13: 00000000fffb1a94 R14: 00000000fffb18c8 R15: 0000000000000000 FS: 0000000000000000(0000) GS:ffff880456d00000(0063) knlGS:00000000f7100980 CS: 0010 DS: 002b ES: 002b CR0: 0000000080050033 CR2: 00000000fffb18e0 CR3: 00000003f552b000 CR4: 00000000003407e0 Stack: 00000000fffb1a94 00000000c0cc5640 0000000000000056 ffff8804274f3600 ffff8803f5643ed0 ffffffffc0547e16 0000000000000003 ffff8803f5643eb0 ffffffff81301460 ffff88009db44b01 ffff880441942520 ffff8800c0d05640 Call Trace: [] v4l2_compat_ioctl32+0x12d6/0x1b1d [videodev] [] ? file_has_perm+0x70/0xc0 [] compat_SyS_ioctl+0xec/0x1200 [] sysenter_dispatch+0x7/0x21 Code: 00 00 48 8b 80 48 c0 ff ff 48 83 e8 38 49 39 c6 0f 87 2b ff ff ff 49 8d 45 1c e8 a3 ce e3 c0 85 c0 0f 85 1a ff ff ff 41 8d 40 ff <4d> 8b 64 24 20 41 89 d5 48 8d 44 40 03 4d 8d 34 c4 eb 15 0f 1f RIP [] __put_v4l2_format32+0x169/0x220 [videodev] RSP CR2: 00000000fffb18e0 Tested with vivid driver on Kernel v3.18.102. Same bug happens upstream too: BUG: KASAN: user-memory-access in __put_v4l2_format32+0x98/0x4d0 [videodev] Read of size 8 at addr 00000000ffe48400 by task v4l2-compliance/8713 CPU: 0 PID: 8713 Comm: v4l2-compliance Not tainted 4.16.0-rc4+ #108 Hardware name: /NUC5i7RYB, BIOS RYBDWi35.86A.0364.2017.0511.0949 05/11/2017 Call Trace: dump_stack+0x5c/0x7c kasan_report+0x164/0x380 ? __put_v4l2_format32+0x98/0x4d0 [videodev] __put_v4l2_format32+0x98/0x4d0 [videodev] v4l2_compat_ioctl32+0x1aec/0x27a0 [videodev] ? __fsnotify_inode_delete+0x20/0x20 ? __put_v4l2_format32+0x4d0/0x4d0 [videodev] compat_SyS_ioctl+0x646/0x14d0 ? do_ioctl+0x30/0x30 do_fast_syscall_32+0x191/0x3f4 entry_SYSENTER_compat+0x6b/0x7a ================================================================== Disabling lock debugging due to kernel taint BUG: unable to handle kernel paging request at 00000000ffe48400 IP: __put_v4l2_format32+0x98/0x4d0 [videodev] PGD 3a22fb067 P4D 3a22fb067 PUD 39b6f0067 PMD 39b6f1067 PTE 80000003256af067 Oops: 0001 [#1] SMP KASAN Modules linked in: vivid videobuf2_vmalloc videobuf2_dma_contig videobuf2_memops v4l2_tpg v4l2_dv_timings videobuf2_v4l2 videobuf2_common v4l2_common videodev xt_CHECKSUM iptable_mangle ipt_MASQUERADE nf_nat_masquerade_ipv4 iptable_nat nf_nat_ipv4 nf_nat nf_conntrack_ipv4 nf_defrag_ipv4 xt_conntrack nf_conntrack libcrc32c tun bridge stp llc ebtable_filter ebtables ip6table_filter ip6_tables bluetooth rfkill ecdh_generic binfmt_misc snd_hda_codec_hdmi intel_rapl x86_pkg_temp_thermal intel_powerclamp i915 coretemp snd_hda_intel snd_hda_codec kvm_intel snd_hwdep snd_hda_core kvm snd_pcm irqbypass crct10dif_pclmul crc32_pclmul snd_seq_midi ghash_clmulni_intel snd_seq_midi_event i2c_algo_bit intel_cstate snd_rawmidi intel_uncore snd_seq drm_kms_helper e1000e snd_seq_device snd_timer intel_rapl_perf drm ptp snd mei_me mei lpc_ich pps_core soundcore video crc32c_intel CPU: 0 PID: 8713 Comm: v4l2-compliance Tainted: G B 4.16.0-rc4+ #108 Hardware name: /NUC5i7RYB, BIOS RYBDWi35.86A.0364.2017.0511.0949 05/11/2017 RIP: 0010:__put_v4l2_format32+0x98/0x4d0 [videodev] RSP: 0018:ffff8803b9be7d30 EFLAGS: 00010282 RAX: 0000000000000000 RBX: ffff8803ac983e80 RCX: ffffffff8cd929f2 RDX: 1ffffffff1d0a149 RSI: 0000000000000297 RDI: 0000000000000297 RBP: 00000000ffe485c0 R08: fffffbfff1cf5123 R09: ffffffff8e7a8948 R10: 0000000000000001 R11: fffffbfff1cf5122 R12: 00000000ffe483e0 R13: 00000000ffe485c4 R14: ffff8803ac985918 R15: 00000000ffe483e8 FS: 0000000000000000(0000) GS:ffff880407400000(0063) knlGS:00000000f7a46980 CS: 0010 DS: 002b ES: 002b CR0: 0000000080050033 CR2: 00000000ffe48400 CR3: 00000003a83f2003 CR4: 00000000003606f0 Call Trace: v4l2_compat_ioctl32+0x1aec/0x27a0 [videodev] ? __fsnotify_inode_delete+0x20/0x20 ? __put_v4l2_format32+0x4d0/0x4d0 [videodev] compat_SyS_ioctl+0x646/0x14d0 ? do_ioctl+0x30/0x30 do_fast_syscall_32+0x191/0x3f4 entry_SYSENTER_compat+0x6b/0x7a Code: 4c 89 f7 4d 8d 7c 24 08 e8 e6 a4 69 cb 48 8b 83 98 1a 00 00 48 83 e8 10 49 39 c7 0f 87 9d 01 00 00 49 8d 7c 24 20 e8 c8 a4 69 cb <4d> 8b 74 24 20 4c 89 ef 4c 89 fe ba 10 00 00 00 e8 23 d9 08 cc RIP: __put_v4l2_format32+0x98/0x4d0 [videodev] RSP: ffff8803b9be7d30 CR2: 00000000ffe48400 cc: stable@vger.kernel.org Signed-off-by: Mauro Carvalho Chehab Reviewed-by: Sakari Ailus Reviewed-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Greg Kroah-Hartman --- drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c index cbeea8343a5c..6730fd08ef03 100644 --- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c +++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c @@ -101,7 +101,7 @@ static int get_v4l2_window32(struct v4l2_window __user *kp, static int put_v4l2_window32(struct v4l2_window __user *kp, struct v4l2_window32 __user *up) { - struct v4l2_clip __user *kclips = kp->clips; + struct v4l2_clip __user *kclips; struct v4l2_clip32 __user *uclips; compat_caddr_t p; u32 clipcount; @@ -116,6 +116,8 @@ static int put_v4l2_window32(struct v4l2_window __user *kp, if (!clipcount) return 0; + if (get_user(kclips, &kp->clips)) + return -EFAULT; if (get_user(p, &up->clips)) return -EFAULT; uclips = compat_ptr(p); -- GitLab From 4d167edf0f6ad8b3151bf247c6b43745ff7d0ed1 Mon Sep 17 00:00:00 2001 From: Kieran Bingham Date: Fri, 9 Feb 2018 09:50:34 -0500 Subject: [PATCH 0500/1635] media: v4l: vsp1: Fix header display list status check in continuous mode commit 613928e85317b945c863bb893f5737d2f22f5425 upstream. To allow dual pipelines utilising two WPF entities when available, the VSP was updated to support header-mode display list in continuous pipelines. A small bug in the status check of the command register causes the second pipeline to be directly afflicted by the running of the first; appearing as a perceived performance issue with stuttering display. Fix the vsp1_dl_list_hw_update_pending() call to ensure that the read comparison corresponds to the correct pipeline. Fixes: eaf4bfad6ad8 ("v4l: vsp1: Add support for header display lists in continuous mode") Cc: "Stable v4.14+" Signed-off-by: Kieran Bingham Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Greg Kroah-Hartman --- drivers/media/platform/vsp1/vsp1_dl.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/media/platform/vsp1/vsp1_dl.c b/drivers/media/platform/vsp1/vsp1_dl.c index 8b5cbb6b7a70..e5d8d99e124c 100644 --- a/drivers/media/platform/vsp1/vsp1_dl.c +++ b/drivers/media/platform/vsp1/vsp1_dl.c @@ -508,7 +508,8 @@ static bool vsp1_dl_list_hw_update_pending(struct vsp1_dl_manager *dlm) return !!(vsp1_read(vsp1, VI6_DL_BODY_SIZE) & VI6_DL_BODY_SIZE_UPD); else - return !!(vsp1_read(vsp1, VI6_CMD(dlm->index) & VI6_CMD_UPDHDR)); + return !!(vsp1_read(vsp1, VI6_CMD(dlm->index)) + & VI6_CMD_UPDHDR); } static void vsp1_dl_list_hw_enqueue(struct vsp1_dl_list *dl) -- GitLab From 08be2c1b6bb67a073e9722b11aaa6d529680f475 Mon Sep 17 00:00:00 2001 From: Helge Deller Date: Sun, 25 Mar 2018 23:53:22 +0200 Subject: [PATCH 0501/1635] parisc: Fix out of array access in match_pci_device() commit 615b2665fd20c327b631ff1e79426775de748094 upstream. As found by the ubsan checker, the value of the 'index' variable can be out of range for the bc[] array: UBSAN: Undefined behaviour in arch/parisc/kernel/drivers.c:655:21 index 6 is out of range for type 'char [6]' Backtrace: [<104fa850>] __ubsan_handle_out_of_bounds+0x68/0x80 [<1019d83c>] check_parent+0xc0/0x170 [<1019d91c>] descend_children+0x30/0x6c [<1059e164>] device_for_each_child+0x60/0x98 [<1019cd54>] parse_tree_node+0x40/0x54 [<1019d86c>] check_parent+0xf0/0x170 [<1019d91c>] descend_children+0x30/0x6c [<1059e164>] device_for_each_child+0x60/0x98 [<1019d938>] descend_children+0x4c/0x6c [<1059e164>] device_for_each_child+0x60/0x98 [<1019cd54>] parse_tree_node+0x40/0x54 [<1019cffc>] hwpath_to_device+0xa4/0xc4 Signed-off-by: Helge Deller Cc: stable@vger.kernel.org Signed-off-by: Greg Kroah-Hartman --- arch/parisc/kernel/drivers.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/parisc/kernel/drivers.c b/arch/parisc/kernel/drivers.c index d8f77358e2ba..513826a43efd 100644 --- a/arch/parisc/kernel/drivers.c +++ b/arch/parisc/kernel/drivers.c @@ -651,6 +651,10 @@ static int match_pci_device(struct device *dev, int index, (modpath->mod == PCI_FUNC(devfn))); } + /* index might be out of bounds for bc[] */ + if (index >= 6) + return 0; + id = PCI_SLOT(pdev->devfn) | (PCI_FUNC(pdev->devfn) << 5); return (modpath->bc[index] == id); } -- GitLab From abd9fd4a3b04fa6abb86f8bd3eb2974f1ffe4144 Mon Sep 17 00:00:00 2001 From: Helge Deller Date: Sat, 24 Mar 2018 21:18:25 +0100 Subject: [PATCH 0502/1635] parisc: Fix HPMC handler by increasing size to multiple of 16 bytes commit d5654e156bc4d68a87bbaa6d7e020baceddf6e68 upstream. Make sure that the HPMC (High Priority Machine Check) handler is 16-byte aligned and that it's length in the IVT is a multiple of 16 bytes. Otherwise PDC may decide not to call the HPMC crash handler. Signed-off-by: Helge Deller Cc: stable@vger.kernel.org Signed-off-by: Greg Kroah-Hartman --- arch/parisc/kernel/hpmc.S | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/arch/parisc/kernel/hpmc.S b/arch/parisc/kernel/hpmc.S index 8d072c44f300..781c3b9a3e46 100644 --- a/arch/parisc/kernel/hpmc.S +++ b/arch/parisc/kernel/hpmc.S @@ -84,6 +84,7 @@ END(hpmc_pim_data) .text .import intr_save, code + .align 16 ENTRY_CFI(os_hpmc) .os_hpmc: @@ -300,12 +301,15 @@ os_hpmc_6: b . nop + .align 16 /* make function length multiple of 16 bytes */ ENDPROC_CFI(os_hpmc) .os_hpmc_end: __INITRODATA +.globl os_hpmc_size .align 4 - .export os_hpmc_size + .type os_hpmc_size, @object + .size os_hpmc_size, 4 os_hpmc_size: .word .os_hpmc_end-.os_hpmc -- GitLab From a160105b550316fe01540735feaad550f834914d Mon Sep 17 00:00:00 2001 From: Dexuan Cui Date: Tue, 27 Mar 2018 15:01:02 -0700 Subject: [PATCH 0503/1635] Drivers: hv: vmbus: do not mark HV_PCIE as perf_device commit 238064f13d057390a8c5e1a6a80f4f0a0ec46499 upstream. The pci-hyperv driver's channel callback hv_pci_onchannelcallback() is not really a hot path, so we don't need to mark it as a perf_device, meaning with this patch all HV_PCIE channels' target_cpu will be CPU0. Signed-off-by: Dexuan Cui Cc: stable@vger.kernel.org Cc: Stephen Hemminger Signed-off-by: K. Y. Srinivasan Signed-off-by: Greg Kroah-Hartman Signed-off-by: Greg Kroah-Hartman --- drivers/hv/channel_mgmt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/hv/channel_mgmt.c b/drivers/hv/channel_mgmt.c index 65c6d6bdce4c..1939c0ca3741 100644 --- a/drivers/hv/channel_mgmt.c +++ b/drivers/hv/channel_mgmt.c @@ -71,7 +71,7 @@ static const struct vmbus_device vmbus_devs[] = { /* PCIE */ { .dev_type = HV_PCIE, HV_PCIE_GUID, - .perf_device = true, + .perf_device = false, }, /* Synthetic Frame Buffer */ -- GitLab From 5661d43b03c5b3dde9262a7bbd417991eba0723f Mon Sep 17 00:00:00 2001 From: Dexuan Cui Date: Thu, 15 Mar 2018 14:20:53 +0000 Subject: [PATCH 0504/1635] PCI: hv: Serialize the present and eject work items commit 021ad274d7dc31611d4f47f7dd4ac7a224526f30 upstream. When we hot-remove the device, we first receive a PCI_EJECT message and then receive a PCI_BUS_RELATIONS message with bus_rel->device_count == 0. The first message is offloaded to hv_eject_device_work(), and the second is offloaded to pci_devices_present_work(). Both the paths can be running list_del(&hpdev->list_entry), causing general protection fault, because system_wq can run them concurrently. The patch eliminates the race condition. Since access to present/eject work items is serialized, we do not need the hbus->enum_sem anymore, so remove it. Fixes: 4daace0d8ce8 ("PCI: hv: Add paravirtual PCI front-end for Microsoft Hyper-V VMs") Link: https://lkml.kernel.org/r/KL1P15301MB00064DA6B4D221123B5241CFBFD70@KL1P15301MB0006.APCP153.PROD.OUTLOOK.COM Tested-by: Adrian Suhov Tested-by: Chris Valean Signed-off-by: Dexuan Cui [lorenzo.pieralisi@arm.com: squashed semaphore removal patch] Signed-off-by: Lorenzo Pieralisi Reviewed-by: Michael Kelley Acked-by: Haiyang Zhang Cc: # v4.6+ Cc: Vitaly Kuznetsov Cc: Jack Morgenstein Cc: Stephen Hemminger Cc: K. Y. Srinivasan Signed-off-by: Greg Kroah-Hartman --- drivers/pci/host/pci-hyperv.c | 34 ++++++++++++++++------------------ 1 file changed, 16 insertions(+), 18 deletions(-) diff --git a/drivers/pci/host/pci-hyperv.c b/drivers/pci/host/pci-hyperv.c index 04dac6a42c9f..73b724143be0 100644 --- a/drivers/pci/host/pci-hyperv.c +++ b/drivers/pci/host/pci-hyperv.c @@ -457,7 +457,6 @@ struct hv_pcibus_device { spinlock_t device_list_lock; /* Protect lists below */ void __iomem *cfg_addr; - struct semaphore enum_sem; struct list_head resources_for_children; struct list_head children; @@ -471,6 +470,8 @@ struct hv_pcibus_device { struct retarget_msi_interrupt retarget_msi_interrupt_params; spinlock_t retarget_msi_interrupt_lock; + + struct workqueue_struct *wq; }; /* @@ -1604,12 +1605,8 @@ static struct hv_pci_dev *get_pcichild_wslot(struct hv_pcibus_device *hbus, * It must also treat the omission of a previously observed device as * notification that the device no longer exists. * - * Note that this function is a work item, and it may not be - * invoked in the order that it was queued. Back to back - * updates of the list of present devices may involve queuing - * multiple work items, and this one may run before ones that - * were sent later. As such, this function only does something - * if is the last one in the queue. + * Note that this function is serialized with hv_eject_device_work(), + * because both are pushed to the ordered workqueue hbus->wq. */ static void pci_devices_present_work(struct work_struct *work) { @@ -1630,11 +1627,6 @@ static void pci_devices_present_work(struct work_struct *work) INIT_LIST_HEAD(&removed); - if (down_interruptible(&hbus->enum_sem)) { - put_hvpcibus(hbus); - return; - } - /* Pull this off the queue and process it if it was the last one. */ spin_lock_irqsave(&hbus->device_list_lock, flags); while (!list_empty(&hbus->dr_list)) { @@ -1651,7 +1643,6 @@ static void pci_devices_present_work(struct work_struct *work) spin_unlock_irqrestore(&hbus->device_list_lock, flags); if (!dr) { - up(&hbus->enum_sem); put_hvpcibus(hbus); return; } @@ -1738,7 +1729,6 @@ static void pci_devices_present_work(struct work_struct *work) break; } - up(&hbus->enum_sem); put_hvpcibus(hbus); kfree(dr); } @@ -1784,7 +1774,7 @@ static void hv_pci_devices_present(struct hv_pcibus_device *hbus, spin_unlock_irqrestore(&hbus->device_list_lock, flags); get_hvpcibus(hbus); - schedule_work(&dr_wrk->wrk); + queue_work(hbus->wq, &dr_wrk->wrk); } /** @@ -1862,7 +1852,7 @@ static void hv_pci_eject_device(struct hv_pci_dev *hpdev) get_pcichild(hpdev, hv_pcidev_ref_pnp); INIT_WORK(&hpdev->wrk, hv_eject_device_work); get_hvpcibus(hpdev->hbus); - schedule_work(&hpdev->wrk); + queue_work(hpdev->hbus->wq, &hpdev->wrk); } /** @@ -2475,13 +2465,18 @@ static int hv_pci_probe(struct hv_device *hdev, spin_lock_init(&hbus->config_lock); spin_lock_init(&hbus->device_list_lock); spin_lock_init(&hbus->retarget_msi_interrupt_lock); - sema_init(&hbus->enum_sem, 1); init_completion(&hbus->remove_event); + hbus->wq = alloc_ordered_workqueue("hv_pci_%x", 0, + hbus->sysdata.domain); + if (!hbus->wq) { + ret = -ENOMEM; + goto free_bus; + } ret = vmbus_open(hdev->channel, pci_ring_size, pci_ring_size, NULL, 0, hv_pci_onchannelcallback, hbus); if (ret) - goto free_bus; + goto destroy_wq; hv_set_drvdata(hdev, hbus); @@ -2550,6 +2545,8 @@ static int hv_pci_probe(struct hv_device *hdev, hv_free_config_window(hbus); close: vmbus_close(hdev->channel); +destroy_wq: + destroy_workqueue(hbus->wq); free_bus: free_page((unsigned long)hbus); return ret; @@ -2629,6 +2626,7 @@ static int hv_pci_remove(struct hv_device *hdev) irq_domain_free_fwnode(hbus->sysdata.fwnode); put_hvpcibus(hbus); wait_for_completion(&hbus->remove_event); + destroy_workqueue(hbus->wq); free_page((unsigned long)hbus); return 0; } -- GitLab From 42b53a13ecac396d74c126c562b18ae8c6a99341 Mon Sep 17 00:00:00 2001 From: Nicholas Piggin Date: Fri, 6 Apr 2018 03:56:30 +1000 Subject: [PATCH 0505/1635] KVM: PPC: Book3S HV: trace_tlbie must not be called in realmode commit 19ce7909ed11c49f7eddf59e7f49cd3062bf83d5 upstream. This crashes with a "Bad real address for load" attempting to load from the vmalloc region in realmode (faulting address is in DAR). Oops: Bad interrupt in KVM entry/exit code, sig: 6 [#1] LE SMP NR_CPUS=2048 NUMA PowerNV CPU: 53 PID: 6582 Comm: qemu-system-ppc Not tainted 4.16.0-01530-g43d1859f0994 NIP: c0000000000155ac LR: c0000000000c2430 CTR: c000000000015580 REGS: c000000fff76dd80 TRAP: 0200 Not tainted (4.16.0-01530-g43d1859f0994) MSR: 9000000000201003 CR: 48082222 XER: 00000000 CFAR: 0000000102900ef0 DAR: d00017fffd941a28 DSISR: 00000040 SOFTE: 3 NIP [c0000000000155ac] perf_trace_tlbie+0x2c/0x1a0 LR [c0000000000c2430] do_tlbies+0x230/0x2f0 I suspect the reason is the per-cpu data is not in the linear chunk. This could be restored if that was able to be fixed, but for now, just remove the tracepoints. Fixes: 0428491cba92 ("powerpc/mm: Trace tlbie(l) instructions") Cc: stable@vger.kernel.org # v4.13+ Signed-off-by: Nicholas Piggin Signed-off-by: Michael Ellerman Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/kvm/book3s_hv_rm_mmu.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/arch/powerpc/kvm/book3s_hv_rm_mmu.c b/arch/powerpc/kvm/book3s_hv_rm_mmu.c index 4efe364f1188..4962d537c186 100644 --- a/arch/powerpc/kvm/book3s_hv_rm_mmu.c +++ b/arch/powerpc/kvm/book3s_hv_rm_mmu.c @@ -447,8 +447,6 @@ static void do_tlbies(struct kvm *kvm, unsigned long *rbvalues, for (i = 0; i < npages; ++i) { asm volatile(PPC_TLBIE_5(%0,%1,0,0,0) : : "r" (rbvalues[i]), "r" (kvm->arch.lpid)); - trace_tlbie(kvm->arch.lpid, 0, rbvalues[i], - kvm->arch.lpid, 0, 0, 0); } asm volatile("eieio; tlbsync; ptesync" : : : "memory"); kvm->arch.tlbie_lock = 0; @@ -458,8 +456,6 @@ static void do_tlbies(struct kvm *kvm, unsigned long *rbvalues, for (i = 0; i < npages; ++i) { asm volatile(PPC_TLBIEL(%0,%1,0,0,0) : : "r" (rbvalues[i]), "r" (0)); - trace_tlbie(kvm->arch.lpid, 1, rbvalues[i], - 0, 0, 0, 0); } asm volatile("ptesync" : : : "memory"); } -- GitLab From ff295906bd9b52c915dfe878753d27e92761e848 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Wed, 7 Mar 2018 16:02:21 +0200 Subject: [PATCH 0506/1635] perf intel-pt: Fix overlap detection to identify consecutive buffers correctly commit 117db4b27bf08dba412faf3924ba55fe970c57b8 upstream. Overlap detection was not not updating the buffer's 'consecutive' flag. Marking buffers consecutive has the advantage that decoding begins from the start of the buffer instead of the first PSB. Fix overlap detection to identify consecutive buffers correctly. Signed-off-by: Adrian Hunter Cc: Jiri Olsa Cc: stable@vger.kernel.org Link: http://lkml.kernel.org/r/1520431349-30689-2-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: Greg Kroah-Hartman --- .../util/intel-pt-decoder/intel-pt-decoder.c | 62 +++++++++---------- .../util/intel-pt-decoder/intel-pt-decoder.h | 2 +- tools/perf/util/intel-pt.c | 5 +- 3 files changed, 34 insertions(+), 35 deletions(-) diff --git a/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c b/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c index aa1593ce551d..00f25f4b5f48 100644 --- a/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c +++ b/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c @@ -2390,14 +2390,6 @@ const struct intel_pt_state *intel_pt_decode(struct intel_pt_decoder *decoder) return &decoder->state; } -static bool intel_pt_at_psb(unsigned char *buf, size_t len) -{ - if (len < INTEL_PT_PSB_LEN) - return false; - return memmem(buf, INTEL_PT_PSB_LEN, INTEL_PT_PSB_STR, - INTEL_PT_PSB_LEN); -} - /** * intel_pt_next_psb - move buffer pointer to the start of the next PSB packet. * @buf: pointer to buffer pointer @@ -2486,6 +2478,7 @@ static unsigned char *intel_pt_last_psb(unsigned char *buf, size_t len) * @buf: buffer * @len: size of buffer * @tsc: TSC value returned + * @rem: returns remaining size when TSC is found * * Find a TSC packet in @buf and return the TSC value. This function assumes * that @buf starts at a PSB and that PSB+ will contain TSC and so stops if a @@ -2493,7 +2486,8 @@ static unsigned char *intel_pt_last_psb(unsigned char *buf, size_t len) * * Return: %true if TSC is found, false otherwise. */ -static bool intel_pt_next_tsc(unsigned char *buf, size_t len, uint64_t *tsc) +static bool intel_pt_next_tsc(unsigned char *buf, size_t len, uint64_t *tsc, + size_t *rem) { struct intel_pt_pkt packet; int ret; @@ -2504,6 +2498,7 @@ static bool intel_pt_next_tsc(unsigned char *buf, size_t len, uint64_t *tsc) return false; if (packet.type == INTEL_PT_TSC) { *tsc = packet.payload; + *rem = len; return true; } if (packet.type == INTEL_PT_PSBEND) @@ -2554,6 +2549,8 @@ static int intel_pt_tsc_cmp(uint64_t tsc1, uint64_t tsc2) * @len_a: size of first buffer * @buf_b: second buffer * @len_b: size of second buffer + * @consecutive: returns true if there is data in buf_b that is consecutive + * to buf_a * * If the trace contains TSC we can look at the last TSC of @buf_a and the * first TSC of @buf_b in order to determine if the buffers overlap, and then @@ -2566,33 +2563,41 @@ static int intel_pt_tsc_cmp(uint64_t tsc1, uint64_t tsc2) static unsigned char *intel_pt_find_overlap_tsc(unsigned char *buf_a, size_t len_a, unsigned char *buf_b, - size_t len_b) + size_t len_b, bool *consecutive) { uint64_t tsc_a, tsc_b; unsigned char *p; - size_t len; + size_t len, rem_a, rem_b; p = intel_pt_last_psb(buf_a, len_a); if (!p) return buf_b; /* No PSB in buf_a => no overlap */ len = len_a - (p - buf_a); - if (!intel_pt_next_tsc(p, len, &tsc_a)) { + if (!intel_pt_next_tsc(p, len, &tsc_a, &rem_a)) { /* The last PSB+ in buf_a is incomplete, so go back one more */ len_a -= len; p = intel_pt_last_psb(buf_a, len_a); if (!p) return buf_b; /* No full PSB+ => assume no overlap */ len = len_a - (p - buf_a); - if (!intel_pt_next_tsc(p, len, &tsc_a)) + if (!intel_pt_next_tsc(p, len, &tsc_a, &rem_a)) return buf_b; /* No TSC in buf_a => assume no overlap */ } while (1) { /* Ignore PSB+ with no TSC */ - if (intel_pt_next_tsc(buf_b, len_b, &tsc_b) && - intel_pt_tsc_cmp(tsc_a, tsc_b) < 0) - return buf_b; /* tsc_a < tsc_b => no overlap */ + if (intel_pt_next_tsc(buf_b, len_b, &tsc_b, &rem_b)) { + int cmp = intel_pt_tsc_cmp(tsc_a, tsc_b); + + /* Same TSC, so buffers are consecutive */ + if (!cmp && rem_b >= rem_a) { + *consecutive = true; + return buf_b + len_b - (rem_b - rem_a); + } + if (cmp < 0) + return buf_b; /* tsc_a < tsc_b => no overlap */ + } if (!intel_pt_step_psb(&buf_b, &len_b)) return buf_b + len_b; /* No PSB in buf_b => no data */ @@ -2606,6 +2611,8 @@ static unsigned char *intel_pt_find_overlap_tsc(unsigned char *buf_a, * @buf_b: second buffer * @len_b: size of second buffer * @have_tsc: can use TSC packets to detect overlap + * @consecutive: returns true if there is data in buf_b that is consecutive + * to buf_a * * When trace samples or snapshots are recorded there is the possibility that * the data overlaps. Note that, for the purposes of decoding, data is only @@ -2616,7 +2623,7 @@ static unsigned char *intel_pt_find_overlap_tsc(unsigned char *buf_a, */ unsigned char *intel_pt_find_overlap(unsigned char *buf_a, size_t len_a, unsigned char *buf_b, size_t len_b, - bool have_tsc) + bool have_tsc, bool *consecutive) { unsigned char *found; @@ -2628,7 +2635,8 @@ unsigned char *intel_pt_find_overlap(unsigned char *buf_a, size_t len_a, return buf_b; /* No overlap */ if (have_tsc) { - found = intel_pt_find_overlap_tsc(buf_a, len_a, buf_b, len_b); + found = intel_pt_find_overlap_tsc(buf_a, len_a, buf_b, len_b, + consecutive); if (found) return found; } @@ -2643,28 +2651,16 @@ unsigned char *intel_pt_find_overlap(unsigned char *buf_a, size_t len_a, } /* Now len_b >= len_a */ - if (len_b > len_a) { - /* The leftover buffer 'b' must start at a PSB */ - while (!intel_pt_at_psb(buf_b + len_a, len_b - len_a)) { - if (!intel_pt_step_psb(&buf_a, &len_a)) - return buf_b; /* No overlap */ - } - } - while (1) { /* Potential overlap so check the bytes */ found = memmem(buf_a, len_a, buf_b, len_a); - if (found) + if (found) { + *consecutive = true; return buf_b + len_a; + } /* Try again at next PSB in buffer 'a' */ if (!intel_pt_step_psb(&buf_a, &len_a)) return buf_b; /* No overlap */ - - /* The leftover buffer 'b' must start at a PSB */ - while (!intel_pt_at_psb(buf_b + len_a, len_b - len_a)) { - if (!intel_pt_step_psb(&buf_a, &len_a)) - return buf_b; /* No overlap */ - } } } diff --git a/tools/perf/util/intel-pt-decoder/intel-pt-decoder.h b/tools/perf/util/intel-pt-decoder/intel-pt-decoder.h index 921b22e8ca0e..fc1752d50019 100644 --- a/tools/perf/util/intel-pt-decoder/intel-pt-decoder.h +++ b/tools/perf/util/intel-pt-decoder/intel-pt-decoder.h @@ -117,7 +117,7 @@ const struct intel_pt_state *intel_pt_decode(struct intel_pt_decoder *decoder); unsigned char *intel_pt_find_overlap(unsigned char *buf_a, size_t len_a, unsigned char *buf_b, size_t len_b, - bool have_tsc); + bool have_tsc, bool *consecutive); int intel_pt__strerror(int code, char *buf, size_t buflen); diff --git a/tools/perf/util/intel-pt.c b/tools/perf/util/intel-pt.c index b58f9fd1e2ee..6a1367e20062 100644 --- a/tools/perf/util/intel-pt.c +++ b/tools/perf/util/intel-pt.c @@ -209,14 +209,17 @@ static void intel_pt_dump_event(struct intel_pt *pt, unsigned char *buf, static int intel_pt_do_fix_overlap(struct intel_pt *pt, struct auxtrace_buffer *a, struct auxtrace_buffer *b) { + bool consecutive = false; void *start; start = intel_pt_find_overlap(a->data, a->size, b->data, b->size, - pt->have_tsc); + pt->have_tsc, &consecutive); if (!start) return -EINVAL; b->use_size = b->data + b->size - start; b->use_data = start; + if (b->use_size && consecutive) + b->consecutive = true; return 0; } -- GitLab From 0733facf3be9388f6f5c7eeba2754e57c22c138b Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Wed, 7 Mar 2018 16:02:22 +0200 Subject: [PATCH 0507/1635] perf intel-pt: Fix sync_switch commit 63d8e38f6ae6c36dd5b5ba0e8c112e8861532ea2 upstream. sync_switch is a facility to synchronize decoding more closely with the point in the kernel when the context actually switched. The flag when sync_switch is enabled was global to the decoding, whereas it is really specific to the CPU. The trace data for different CPUs is put on different queues, so add sync_switch to the intel_pt_queue structure and use that in preference to the global setting in the intel_pt structure. That fixes problems decoding one CPU's trace because sync_switch was disabled on a different CPU's queue. Signed-off-by: Adrian Hunter Cc: Jiri Olsa Cc: stable@vger.kernel.org Link: http://lkml.kernel.org/r/1520431349-30689-3-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: Greg Kroah-Hartman --- tools/perf/util/intel-pt.c | 32 +++++++++++++++++++++++++------- 1 file changed, 25 insertions(+), 7 deletions(-) diff --git a/tools/perf/util/intel-pt.c b/tools/perf/util/intel-pt.c index 6a1367e20062..d9573c1fa555 100644 --- a/tools/perf/util/intel-pt.c +++ b/tools/perf/util/intel-pt.c @@ -145,6 +145,7 @@ struct intel_pt_queue { bool stop; bool step_through_buffers; bool use_buffer_pid_tid; + bool sync_switch; pid_t pid, tid; int cpu; int switch_state; @@ -965,10 +966,12 @@ static int intel_pt_setup_queue(struct intel_pt *pt, if (pt->timeless_decoding || !pt->have_sched_switch) ptq->use_buffer_pid_tid = true; } + + ptq->sync_switch = pt->sync_switch; } if (!ptq->on_heap && - (!pt->sync_switch || + (!ptq->sync_switch || ptq->switch_state != INTEL_PT_SS_EXPECTING_SWITCH_EVENT)) { const struct intel_pt_state *state; int ret; @@ -1552,7 +1555,7 @@ static int intel_pt_sample(struct intel_pt_queue *ptq) if (pt->synth_opts.last_branch) intel_pt_update_last_branch_rb(ptq); - if (!pt->sync_switch) + if (!ptq->sync_switch) return 0; if (intel_pt_is_switch_ip(ptq, state->to_ip)) { @@ -1633,6 +1636,21 @@ static u64 intel_pt_switch_ip(struct intel_pt *pt, u64 *ptss_ip) return switch_ip; } +static void intel_pt_enable_sync_switch(struct intel_pt *pt) +{ + unsigned int i; + + pt->sync_switch = true; + + for (i = 0; i < pt->queues.nr_queues; i++) { + struct auxtrace_queue *queue = &pt->queues.queue_array[i]; + struct intel_pt_queue *ptq = queue->priv; + + if (ptq) + ptq->sync_switch = true; + } +} + static int intel_pt_run_decoder(struct intel_pt_queue *ptq, u64 *timestamp) { const struct intel_pt_state *state = ptq->state; @@ -1649,7 +1667,7 @@ static int intel_pt_run_decoder(struct intel_pt_queue *ptq, u64 *timestamp) if (pt->switch_ip) { intel_pt_log("switch_ip: %"PRIx64" ptss_ip: %"PRIx64"\n", pt->switch_ip, pt->ptss_ip); - pt->sync_switch = true; + intel_pt_enable_sync_switch(pt); } } } @@ -1665,9 +1683,9 @@ static int intel_pt_run_decoder(struct intel_pt_queue *ptq, u64 *timestamp) if (state->err) { if (state->err == INTEL_PT_ERR_NODATA) return 1; - if (pt->sync_switch && + if (ptq->sync_switch && state->from_ip >= pt->kernel_start) { - pt->sync_switch = false; + ptq->sync_switch = false; intel_pt_next_tid(pt, ptq); } if (pt->synth_opts.errors) { @@ -1693,7 +1711,7 @@ static int intel_pt_run_decoder(struct intel_pt_queue *ptq, u64 *timestamp) state->timestamp, state->est_timestamp); ptq->timestamp = state->est_timestamp; /* Use estimated TSC in unknown switch state */ - } else if (pt->sync_switch && + } else if (ptq->sync_switch && ptq->switch_state == INTEL_PT_SS_UNKNOWN && intel_pt_is_switch_ip(ptq, state->to_ip) && ptq->next_tid == -1) { @@ -1840,7 +1858,7 @@ static int intel_pt_sync_switch(struct intel_pt *pt, int cpu, pid_t tid, return 1; ptq = intel_pt_cpu_to_ptq(pt, cpu); - if (!ptq) + if (!ptq || !ptq->sync_switch) return 1; switch (ptq->switch_state) { -- GitLab From 4039579fca382fe2d02d2ed78c98f626ed5392f5 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Wed, 7 Mar 2018 16:02:23 +0200 Subject: [PATCH 0508/1635] perf intel-pt: Fix error recovery from missing TIP packet commit 1c196a6c771c47a2faa63d38d913e03284f73a16 upstream. When a TIP packet is expected but there is a different packet, it is an error. However the unexpected packet might be something important like a TSC packet, so after the error, it is necessary to continue from there, rather than the next packet. That is achieved by setting pkt_step to zero. Signed-off-by: Adrian Hunter Cc: Jiri Olsa Cc: stable@vger.kernel.org Link: http://lkml.kernel.org/r/1520431349-30689-4-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: Greg Kroah-Hartman --- tools/perf/util/intel-pt-decoder/intel-pt-decoder.c | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c b/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c index 00f25f4b5f48..5e4d0bbafc8b 100644 --- a/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c +++ b/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c @@ -1616,6 +1616,7 @@ static int intel_pt_walk_fup_tip(struct intel_pt_decoder *decoder) case INTEL_PT_PWRX: intel_pt_log("ERROR: Missing TIP after FUP\n"); decoder->pkt_state = INTEL_PT_STATE_ERR3; + decoder->pkt_step = 0; return -ENOENT; case INTEL_PT_OVF: -- GitLab From 674e18de7bde49129f7793728169e4ab8d6afcee Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Wed, 7 Mar 2018 16:02:24 +0200 Subject: [PATCH 0509/1635] perf intel-pt: Fix timestamp following overflow commit 91d29b288aed3406caf7c454bf2b898c96cfd177 upstream. timestamp_insn_cnt is used to estimate the timestamp based on the number of instructions since the last known timestamp. If the estimate is not accurate enough decoding might not be correctly synchronized with side-band events causing more trace errors. However there are always timestamps following an overflow, so the estimate is not needed and can indeed result in more errors. Suppress the estimate by setting timestamp_insn_cnt to zero. Signed-off-by: Adrian Hunter Cc: Jiri Olsa Cc: stable@vger.kernel.org Link: http://lkml.kernel.org/r/1520431349-30689-5-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: Greg Kroah-Hartman --- tools/perf/util/intel-pt-decoder/intel-pt-decoder.c | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c b/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c index 5e4d0bbafc8b..f9157aed1289 100644 --- a/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c +++ b/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c @@ -1378,6 +1378,7 @@ static int intel_pt_overflow(struct intel_pt_decoder *decoder) intel_pt_clear_tx_flags(decoder); decoder->have_tma = false; decoder->cbr = 0; + decoder->timestamp_insn_cnt = 0; decoder->pkt_state = INTEL_PT_STATE_ERR_RESYNC; decoder->overflow = true; return -EOVERFLOW; -- GitLab From 6f22be4ba787eb76abbf66aad14b4d60ec59e641 Mon Sep 17 00:00:00 2001 From: Prashant Bhole Date: Mon, 9 Apr 2018 19:03:46 +0900 Subject: [PATCH 0510/1635] perf/core: Fix use-after-free in uprobe_perf_close() commit 621b6d2ea297d0fb6030452c5bcd221f12165fcf upstream. A use-after-free bug was caught by KASAN while running usdt related code (BCC project. bcc/tests/python/test_usdt2.py): ================================================================== BUG: KASAN: use-after-free in uprobe_perf_close+0x222/0x3b0 Read of size 4 at addr ffff880384f9b4a4 by task test_usdt2.py/870 CPU: 4 PID: 870 Comm: test_usdt2.py Tainted: G W 4.16.0-next-20180409 #215 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Ubuntu-1.8.2-1ubuntu1 04/01/2014 Call Trace: dump_stack+0xc7/0x15b ? show_regs_print_info+0x5/0x5 ? printk+0x9c/0xc3 ? kmsg_dump_rewind_nolock+0x6e/0x6e ? uprobe_perf_close+0x222/0x3b0 print_address_description+0x83/0x3a0 ? uprobe_perf_close+0x222/0x3b0 kasan_report+0x1dd/0x460 ? uprobe_perf_close+0x222/0x3b0 uprobe_perf_close+0x222/0x3b0 ? probes_open+0x180/0x180 ? free_filters_list+0x290/0x290 trace_uprobe_register+0x1bb/0x500 ? perf_event_attach_bpf_prog+0x310/0x310 ? probe_event_disable+0x4e0/0x4e0 perf_uprobe_destroy+0x63/0xd0 _free_event+0x2bc/0xbd0 ? lockdep_rcu_suspicious+0x100/0x100 ? ring_buffer_attach+0x550/0x550 ? kvm_sched_clock_read+0x1a/0x30 ? perf_event_release_kernel+0x3e4/0xc00 ? __mutex_unlock_slowpath+0x12e/0x540 ? wait_for_completion+0x430/0x430 ? lock_downgrade+0x3c0/0x3c0 ? lock_release+0x980/0x980 ? do_raw_spin_trylock+0x118/0x150 ? do_raw_spin_unlock+0x121/0x210 ? do_raw_spin_trylock+0x150/0x150 perf_event_release_kernel+0x5d4/0xc00 ? put_event+0x30/0x30 ? fsnotify+0xd2d/0xea0 ? sched_clock_cpu+0x18/0x1a0 ? __fsnotify_update_child_dentry_flags.part.0+0x1b0/0x1b0 ? pvclock_clocksource_read+0x152/0x2b0 ? pvclock_read_flags+0x80/0x80 ? kvm_sched_clock_read+0x1a/0x30 ? sched_clock_cpu+0x18/0x1a0 ? pvclock_clocksource_read+0x152/0x2b0 ? locks_remove_file+0xec/0x470 ? pvclock_read_flags+0x80/0x80 ? fcntl_setlk+0x880/0x880 ? ima_file_free+0x8d/0x390 ? lockdep_rcu_suspicious+0x100/0x100 ? ima_file_check+0x110/0x110 ? fsnotify+0xea0/0xea0 ? kvm_sched_clock_read+0x1a/0x30 ? rcu_note_context_switch+0x600/0x600 perf_release+0x21/0x40 __fput+0x264/0x620 ? fput+0xf0/0xf0 ? do_raw_spin_unlock+0x121/0x210 ? do_raw_spin_trylock+0x150/0x150 ? SyS_fchdir+0x100/0x100 ? fsnotify+0xea0/0xea0 task_work_run+0x14b/0x1e0 ? task_work_cancel+0x1c0/0x1c0 ? copy_fd_bitmaps+0x150/0x150 ? vfs_read+0xe5/0x260 exit_to_usermode_loop+0x17b/0x1b0 ? trace_event_raw_event_sys_exit+0x1a0/0x1a0 do_syscall_64+0x3f6/0x490 ? syscall_return_slowpath+0x2c0/0x2c0 ? lockdep_sys_exit+0x1f/0xaa ? syscall_return_slowpath+0x1a3/0x2c0 ? lockdep_sys_exit+0x1f/0xaa ? prepare_exit_to_usermode+0x11c/0x1e0 ? enter_from_user_mode+0x30/0x30 random: crng init done ? __put_user_4+0x1c/0x30 entry_SYSCALL_64_after_hwframe+0x3d/0xa2 RIP: 0033:0x7f41d95f9340 RSP: 002b:00007fffe71e4268 EFLAGS: 00000246 ORIG_RAX: 0000000000000003 RAX: 0000000000000000 RBX: 000000000000000d RCX: 00007f41d95f9340 RDX: 0000000000000000 RSI: 0000000000002401 RDI: 000000000000000d RBP: 0000000000000000 R08: 00007f41ca8ff700 R09: 00007f41d996dd1f R10: 00007fffe71e41e0 R11: 0000000000000246 R12: 00007fffe71e4330 R13: 0000000000000000 R14: fffffffffffffffc R15: 00007fffe71e4290 Allocated by task 870: kasan_kmalloc+0xa0/0xd0 kmem_cache_alloc_node+0x11a/0x430 copy_process.part.19+0x11a0/0x41c0 _do_fork+0x1be/0xa20 do_syscall_64+0x198/0x490 entry_SYSCALL_64_after_hwframe+0x3d/0xa2 Freed by task 0: __kasan_slab_free+0x12e/0x180 kmem_cache_free+0x102/0x4d0 free_task+0xfe/0x160 __put_task_struct+0x189/0x290 delayed_put_task_struct+0x119/0x250 rcu_process_callbacks+0xa6c/0x1b60 __do_softirq+0x238/0x7ae The buggy address belongs to the object at ffff880384f9b480 which belongs to the cache task_struct of size 12928 It occurs because task_struct is freed before perf_event which refers to the task and task flags are checked while teardown of the event. perf_event_alloc() assigns task_struct to hw.target of perf_event, but there is no reference counting for it. As a fix we get_task_struct() in perf_event_alloc() at above mentioned assignment and put_task_struct() in _free_event(). Signed-off-by: Prashant Bhole Reviewed-by: Oleg Nesterov Acked-by: Peter Zijlstra (Intel) Cc: Cc: Alexander Shishkin Cc: Arnaldo Carvalho de Melo Cc: Jiri Olsa Cc: Linus Torvalds Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Thomas Gleixner Fixes: 63b6da39bb38e8f1a1ef3180d32a39d6 ("perf: Fix perf_event_exit_task() race") Link: http://lkml.kernel.org/r/20180409100346.6416-1-bhole_prashant_q7@lab.ntt.co.jp Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman --- kernel/events/core.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/kernel/events/core.c b/kernel/events/core.c index cecd72eb09b8..e9b0beca830f 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -4199,6 +4199,9 @@ static void _free_event(struct perf_event *event) if (event->ctx) put_ctx(event->ctx); + if (event->hw.target) + put_task_struct(event->hw.target); + exclusive_event_destroy(event); module_put(event->pmu->module); @@ -9508,6 +9511,7 @@ perf_event_alloc(struct perf_event_attr *attr, int cpu, * and we cannot use the ctx information because we need the * pmu before we get a ctx. */ + get_task_struct(task); event->hw.target = task; } @@ -9623,6 +9627,8 @@ perf_event_alloc(struct perf_event_attr *attr, int cpu, perf_detach_cgroup(event); if (event->ns) put_pid_ns(event->ns); + if (event->hw.target) + put_task_struct(event->hw.target); kfree(event); return ERR_PTR(err); -- GitLab From 8e52e2f41c43d53b35fcd053acf3101982da9b7c Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Fri, 16 Feb 2018 16:26:57 +0100 Subject: [PATCH 0511/1635] radeon: hide pointless #warning when compile testing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit c02216acf4177c4411d33735c81cad687790fa59 upstream. In randconfig testing, we sometimes get this warning: drivers/gpu/drm/radeon/radeon_object.c: In function 'radeon_bo_create': drivers/gpu/drm/radeon/radeon_object.c:242:2: error: #warning Please enable CONFIG_MTRR and CONFIG_X86_PAT for better performance thanks to write-combining [-Werror=cpp] #warning Please enable CONFIG_MTRR and CONFIG_X86_PAT for better performance \ This is rather annoying since almost all other code produces no build-time output unless we have found a real bug. We already fixed this in the amdgpu driver in commit 31bb90f1cd08 ("drm/amdgpu: shut up #warning for compile testing") by adding a CONFIG_COMPILE_TEST check last year and agreed to do the same here, but both Michel and I then forgot about it until I came across the issue again now. For stable kernels, as this is one of very few remaining randconfig warnings in 4.14. Cc: stable@vger.kernel.org Link: https://patchwork.kernel.org/patch/9550009/ Signed-off-by: Arnd Bergmann Signed-off-by: Michel Dänzer Signed-off-by: Alex Deucher Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/radeon/radeon_object.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/radeon/radeon_object.c b/drivers/gpu/drm/radeon/radeon_object.c index baadb706c276..b19a54dd18de 100644 --- a/drivers/gpu/drm/radeon/radeon_object.c +++ b/drivers/gpu/drm/radeon/radeon_object.c @@ -240,9 +240,10 @@ int radeon_bo_create(struct radeon_device *rdev, * may be slow * See https://bugs.freedesktop.org/show_bug.cgi?id=88758 */ - +#ifndef CONFIG_COMPILE_TEST #warning Please enable CONFIG_MTRR and CONFIG_X86_PAT for better performance \ thanks to write-combining +#endif if (bo->flags & RADEON_GEM_GTT_WC) DRM_INFO_ONCE("Please enable CONFIG_MTRR and CONFIG_X86_PAT for " -- GitLab From 0ed20e4b52afb4a213a51d9bf52b907bfa302f55 Mon Sep 17 00:00:00 2001 From: Yazen Ghannam Date: Mon, 18 Dec 2017 12:37:12 +0100 Subject: [PATCH 0512/1635] x86/MCE/AMD: Define a function to get SMCA bank type commit 11cf887728a3d1de77cc12ce247b64ef32608891 upstream. Scalable MCA systems have various types of banks. The bank's type can determine how we handle errors from it. For example, if a bank represents a UMC (Unified Memory Controller) then we will need to convert its address from a normalized address to a system physical address before handling the error. [ bp: Verify m->bank is within range and use bank pointer. ] Signed-off-by: Yazen Ghannam Signed-off-by: Borislav Petkov Signed-off-by: Thomas Gleixner Link: http://lkml.kernel.org/r/20171207203955.118171-1-Yazen.Ghannam@amd.com Signed-off-by: Greg Kroah-Hartman --- arch/x86/kernel/cpu/mcheck/mce_amd.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/arch/x86/kernel/cpu/mcheck/mce_amd.c b/arch/x86/kernel/cpu/mcheck/mce_amd.c index 486f640b02ef..bd0e1b77937c 100644 --- a/arch/x86/kernel/cpu/mcheck/mce_amd.c +++ b/arch/x86/kernel/cpu/mcheck/mce_amd.c @@ -110,6 +110,20 @@ const char *smca_get_long_name(enum smca_bank_types t) } EXPORT_SYMBOL_GPL(smca_get_long_name); +static enum smca_bank_types smca_get_bank_type(struct mce *m) +{ + struct smca_bank *b; + + if (m->bank >= N_SMCA_BANK_TYPES) + return N_SMCA_BANK_TYPES; + + b = &smca_banks[m->bank]; + if (!b->hwid) + return N_SMCA_BANK_TYPES; + + return b->hwid->bank_type; +} + static struct smca_hwid smca_hwid_mcatypes[] = { /* { bank_type, hwid_mcatype, xec_bitmap } */ -- GitLab From b18daa09fefe5c7a1b35419734012469287b9504 Mon Sep 17 00:00:00 2001 From: Bill Kuzeja Date: Fri, 23 Mar 2018 10:37:25 -0400 Subject: [PATCH 0513/1635] scsi: qla2xxx: Fix small memory leak in qla2x00_probe_one on probe failure commit 6d6340672ba3a99c4cf7af79c2edf7aa25595c84 upstream. The code that fixes the crashes in the following commit introduced a small memory leak: commit 6a2cf8d3663e ("scsi: qla2xxx: Fix crashes in qla2x00_probe_one on probe failure") Fixing this requires a bit of reworking, which I've explained. Also provide some code cleanup. There is a small window in qla2x00_probe_one where if qla2x00_alloc_queues fails, we end up never freeing req and rsp and leak 0xc0 and 0xc8 bytes respectively (the sizes of req and rsp). I originally put in checks to test for this condition which were based on the incorrect assumption that if ha->rsp_q_map and ha->req_q_map were allocated, then rsp and req were allocated as well. This is incorrect. There is a window between these allocations: ret = qla2x00_mem_alloc(ha, req_length, rsp_length, &req, &rsp); goto probe_hw_failed; [if successful, both rsp and req allocated] base_vha = qla2x00_create_host(sht, ha); goto probe_hw_failed; ret = qla2x00_request_irqs(ha, rsp); goto probe_failed; if (qla2x00_alloc_queues(ha, req, rsp)) { goto probe_failed; [if successful, now ha->rsp_q_map and ha->req_q_map allocated] To simplify this, we should just set req and rsp to NULL after we free them. Sounds simple enough? The problem is that req and rsp are pointers defined in the qla2x00_probe_one and they are not always passed by reference to the routines that free them. Here are paths which can free req and rsp: PATH 1: qla2x00_probe_one ret = qla2x00_mem_alloc(ha, req_length, rsp_length, &req, &rsp); [req and rsp are passed by reference, but if this fails, we currently do not NULL out req and rsp. Easily fixed] PATH 2: qla2x00_probe_one failing in qla2x00_request_irqs or qla2x00_alloc_queues probe_failed: qla2x00_free_device(base_vha); qla2x00_free_req_que(ha, req) qla2x00_free_rsp_que(ha, rsp) PATH 3: qla2x00_probe_one: failing in qla2x00_mem_alloc or qla2x00_create_host probe_hw_failed: qla2x00_free_req_que(ha, req) qla2x00_free_rsp_que(ha, rsp) PATH 1: This should currently work, but it doesn't because rsp and rsp are not set to NULL in qla2x00_mem_alloc. Easily remedied. PATH 2: req and rsp aren't passed in at all to qla2x00_free_device but are derived from ha->req_q_map[0] and ha->rsp_q_map[0]. These are only set up if qla2x00_alloc_queues succeeds. In qla2x00_free_queues, we are protected from crashing if these don't exist because req_qid_map and rsp_qid_map are only set on their allocation. We are guarded in this way: for (cnt = 0; cnt < ha->max_req_queues; cnt++) { if (!test_bit(cnt, ha->req_qid_map)) continue; PATH 3: This works. We haven't freed req or rsp yet (or they were never allocated if qla2x00_mem_alloc failed), so we'll attempt to free them here. To summarize, there are a few small changes to make this work correctly and (and for some cleanup): 1) (For PATH 1) Set *rsp and *req to NULL in case of failure in qla2x00_mem_alloc so these are correctly set to NULL back in qla2x00_probe_one 2) After jumping to probe_failed: and calling qla2x00_free_device, explicitly set rsp and req to NULL so further calls with these pointers do not crash, i.e. the free queue calls in the probe_hw_failed section we fall through to. 3) Fix return code check in the call to qla2x00_alloc_queues. We currently drop the return code on the floor. The probe fails but the caller of the probe doesn't have an error code, so it attaches to pci. This can result in a crash on module shutdown. 4) Remove unnecessary NULL checks in qla2x00_free_req_que, qla2x00_free_rsp_que, and the egregious NULL checks before kfrees and vfrees in qla2x00_mem_free. I tested this out running a scenario where the card breaks at various times during initialization. I made sure I forced every error exit path in qla2x00_probe_one. Cc: # v4.16 Fixes: 6a2cf8d3663e ("scsi: qla2xxx: Fix crashes in qla2x00_probe_one on probe failure") Signed-off-by: Bill Kuzeja Acked-by: Himanshu Madhani Signed-off-by: Martin K. Petersen Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/qla2xxx/qla_os.c | 44 +++++++++++++++++------------------ 1 file changed, 21 insertions(+), 23 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 1e17175692d3..8e7c0626f8b5 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -459,9 +459,6 @@ static int qla2x00_alloc_queues(struct qla_hw_data *ha, struct req_que *req, static void qla2x00_free_req_que(struct qla_hw_data *ha, struct req_que *req) { - if (!ha->req_q_map) - return; - if (IS_QLAFX00(ha)) { if (req && req->ring_fx00) dma_free_coherent(&ha->pdev->dev, @@ -472,17 +469,14 @@ static void qla2x00_free_req_que(struct qla_hw_data *ha, struct req_que *req) (req->length + 1) * sizeof(request_t), req->ring, req->dma); - if (req) { + if (req) kfree(req->outstanding_cmds); - kfree(req); - } + + kfree(req); } static void qla2x00_free_rsp_que(struct qla_hw_data *ha, struct rsp_que *rsp) { - if (!ha->rsp_q_map) - return; - if (IS_QLAFX00(ha)) { if (rsp && rsp->ring) dma_free_coherent(&ha->pdev->dev, @@ -493,8 +487,7 @@ static void qla2x00_free_rsp_que(struct qla_hw_data *ha, struct rsp_que *rsp) (rsp->length + 1) * sizeof(response_t), rsp->ring, rsp->dma); } - if (rsp) - kfree(rsp); + kfree(rsp); } static void qla2x00_free_queues(struct qla_hw_data *ha) @@ -3075,7 +3068,8 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) goto probe_failed; /* Alloc arrays of request and response ring ptrs */ - if (qla2x00_alloc_queues(ha, req, rsp)) { + ret = qla2x00_alloc_queues(ha, req, rsp); + if (ret) { ql_log(ql_log_fatal, base_vha, 0x003d, "Failed to allocate memory for queue pointers..." "aborting.\n"); @@ -3368,8 +3362,15 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) } qla2x00_free_device(base_vha); - scsi_host_put(base_vha->host); + /* + * Need to NULL out local req/rsp after + * qla2x00_free_device => qla2x00_free_queues frees + * what these are pointing to. Or else we'll + * fall over below in qla2x00_free_req/rsp_que. + */ + req = NULL; + rsp = NULL; probe_hw_failed: qla2x00_mem_free(ha); @@ -4062,6 +4063,7 @@ qla2x00_mem_alloc(struct qla_hw_data *ha, uint16_t req_len, uint16_t rsp_len, (*rsp)->dma = 0; fail_rsp_ring: kfree(*rsp); + *rsp = NULL; fail_rsp: dma_free_coherent(&ha->pdev->dev, ((*req)->length + 1) * sizeof(request_t), (*req)->ring, (*req)->dma); @@ -4069,6 +4071,7 @@ qla2x00_mem_alloc(struct qla_hw_data *ha, uint16_t req_len, uint16_t rsp_len, (*req)->dma = 0; fail_req_ring: kfree(*req); + *req = NULL; fail_req: dma_free_coherent(&ha->pdev->dev, sizeof(struct ct_sns_pkt), ha->ct_sns, ha->ct_sns_dma); @@ -4436,16 +4439,11 @@ qla2x00_mem_free(struct qla_hw_data *ha) dma_free_coherent(&ha->pdev->dev, ha->init_cb_size, ha->init_cb, ha->init_cb_dma); - if (ha->optrom_buffer) - vfree(ha->optrom_buffer); - if (ha->nvram) - kfree(ha->nvram); - if (ha->npiv_info) - kfree(ha->npiv_info); - if (ha->swl) - kfree(ha->swl); - if (ha->loop_id_map) - kfree(ha->loop_id_map); + vfree(ha->optrom_buffer); + kfree(ha->nvram); + kfree(ha->npiv_info); + kfree(ha->swl); + kfree(ha->loop_id_map); ha->srb_mempool = NULL; ha->ctx_mempool = NULL; -- GitLab From 1d0d8beb35cd5ae375c5192ba01794594688e248 Mon Sep 17 00:00:00 2001 From: John Johansen Date: Thu, 1 Feb 2018 11:24:10 +0100 Subject: [PATCH 0514/1635] apparmor: fix logging of the existence test for signals commit 98cf5bbff413eadf1b9cb195a7b80cc61c72a50e upstream. The existence test is not being properly logged as the signal mapping maps it to the last entry in the named signal table. This is done to help catch bugs by making the 0 mapped signal value invalid so that we can catch the signal value not being filled in. When fixing the off-by-one comparision logic the reporting of the existence test was broken, because the logic behind the mapped named table was hidden. Fix this by adding a define for the name lookup and using it. Cc: Stable Fixes: f7dc4c9a855a1 ("apparmor: fix off-by-one comparison on MAXMAPPED_SIG") Signed-off-by: John Johansen Signed-off-by: Greg Kroah-Hartman --- security/apparmor/include/sig_names.h | 4 +++- security/apparmor/ipc.c | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/security/apparmor/include/sig_names.h b/security/apparmor/include/sig_names.h index 92e62fe95292..5ca47c50dfa7 100644 --- a/security/apparmor/include/sig_names.h +++ b/security/apparmor/include/sig_names.h @@ -2,6 +2,8 @@ #define SIGUNKNOWN 0 #define MAXMAPPED_SIG 35 +#define MAXMAPPED_SIGNAME (MAXMAPPED_SIG + 1) + /* provide a mapping of arch signal to internal signal # for mediation * those that are always an alias SIGCLD for SIGCLHD and SIGPOLL for SIGIO * map to the same entry those that may/or may not get a separate entry @@ -56,7 +58,7 @@ static const int sig_map[MAXMAPPED_SIG] = { }; /* this table is ordered post sig_map[sig] mapping */ -static const char *const sig_names[MAXMAPPED_SIG + 1] = { +static const char *const sig_names[MAXMAPPED_SIGNAME] = { "unknown", "hup", "int", diff --git a/security/apparmor/ipc.c b/security/apparmor/ipc.c index b40678f3c1d5..586facd35f7c 100644 --- a/security/apparmor/ipc.c +++ b/security/apparmor/ipc.c @@ -174,7 +174,7 @@ static void audit_signal_cb(struct audit_buffer *ab, void *va) audit_signal_mask(ab, aad(sa)->denied); } } - if (aad(sa)->signal < MAXMAPPED_SIG) + if (aad(sa)->signal < MAXMAPPED_SIGNAME) audit_log_format(ab, " signal=%s", sig_names[aad(sa)->signal]); else audit_log_format(ab, " signal=rtmin+%d", -- GitLab From a0358f60528384789429dc149127a527eb2ae23c Mon Sep 17 00:00:00 2001 From: John Johansen Date: Tue, 23 Jan 2018 01:47:42 -0800 Subject: [PATCH 0515/1635] apparmor: fix display of .ns_name for containers commit 040d9e2bce0a5b321c402b79ee43a8e8d2fd3b06 upstream. The .ns_name should not be virtualized by the current ns view. It needs to report the ns base name as that is being used during startup as part of determining apparmor policy namespace support. BugLink: http://bugs.launchpad.net/bugs/1746463 Fixes: d9f02d9c237aa ("apparmor: fix display of ns name") Cc: Stable Reported-by: Serge Hallyn Tested-by: Serge Hallyn Signed-off-by: John Johansen Signed-off-by: Greg Kroah-Hartman --- security/apparmor/apparmorfs.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c index caaf51dda648..0e03377bb83e 100644 --- a/security/apparmor/apparmorfs.c +++ b/security/apparmor/apparmorfs.c @@ -1189,9 +1189,7 @@ static int seq_ns_level_show(struct seq_file *seq, void *v) static int seq_ns_name_show(struct seq_file *seq, void *v) { struct aa_label *label = begin_current_label_crit_section(); - - seq_printf(seq, "%s\n", aa_ns_name(labels_ns(label), - labels_ns(label), true)); + seq_printf(seq, "%s\n", labels_ns(label)->base.name); end_current_label_crit_section(label); return 0; -- GitLab From 54b990ede4c36c1dee566f24fac12973e30f6042 Mon Sep 17 00:00:00 2001 From: John Johansen Date: Fri, 9 Feb 2018 04:57:39 -0800 Subject: [PATCH 0516/1635] apparmor: fix resource audit messages when auditing peer commit b5beb07ad32ab533027aa988d96a44965ec116f7 upstream. Resource auditing is using the peer field which is not available when the rlim data struct is used, because it is a different element of the same union. Accessing peer during resource auditing could cause garbage log entries or even oops the kernel. Move the rlim data block into the same struct as the peer field so they can be used together. CC: Fixes: 86b92cb782b3 ("apparmor: move resource checks to using labels") Signed-off-by: John Johansen Signed-off-by: Greg Kroah-Hartman --- security/apparmor/include/audit.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/security/apparmor/include/audit.h b/security/apparmor/include/audit.h index 4ac095118717..2ebc00a579fd 100644 --- a/security/apparmor/include/audit.h +++ b/security/apparmor/include/audit.h @@ -126,6 +126,10 @@ struct apparmor_audit_data { const char *target; kuid_t ouid; } fs; + struct { + int rlim; + unsigned long max; + } rlim; int signal; }; }; @@ -134,10 +138,6 @@ struct apparmor_audit_data { const char *ns; long pos; } iface; - struct { - int rlim; - unsigned long max; - } rlim; struct { const char *src_name; const char *type; -- GitLab From 51a9580d67a2e0067262abbb06804b6b45f6aa45 Mon Sep 17 00:00:00 2001 From: Tetsuo Handa Date: Fri, 6 Apr 2018 10:03:17 +0900 Subject: [PATCH 0517/1635] block/loop: fix deadlock after loop_set_status commit 1e047eaab3bb5564f25b41e9cd3a053009f4e789 upstream. syzbot is reporting deadlocks at __blkdev_get() [1]. ---------------------------------------- [ 92.493919] systemd-udevd D12696 525 1 0x00000000 [ 92.495891] Call Trace: [ 92.501560] schedule+0x23/0x80 [ 92.502923] schedule_preempt_disabled+0x5/0x10 [ 92.504645] __mutex_lock+0x416/0x9e0 [ 92.510760] __blkdev_get+0x73/0x4f0 [ 92.512220] blkdev_get+0x12e/0x390 [ 92.518151] do_dentry_open+0x1c3/0x2f0 [ 92.519815] path_openat+0x5d9/0xdc0 [ 92.521437] do_filp_open+0x7d/0xf0 [ 92.527365] do_sys_open+0x1b8/0x250 [ 92.528831] do_syscall_64+0x6e/0x270 [ 92.530341] entry_SYSCALL_64_after_hwframe+0x42/0xb7 [ 92.931922] 1 lock held by systemd-udevd/525: [ 92.933642] #0: 00000000a2849e25 (&bdev->bd_mutex){+.+.}, at: __blkdev_get+0x73/0x4f0 ---------------------------------------- The reason of deadlock turned out that wait_event_interruptible() in blk_queue_enter() got stuck with bdev->bd_mutex held at __blkdev_put() due to q->mq_freeze_depth == 1. ---------------------------------------- [ 92.787172] a.out S12584 634 633 0x80000002 [ 92.789120] Call Trace: [ 92.796693] schedule+0x23/0x80 [ 92.797994] blk_queue_enter+0x3cb/0x540 [ 92.803272] generic_make_request+0xf0/0x3d0 [ 92.807970] submit_bio+0x67/0x130 [ 92.810928] submit_bh_wbc+0x15e/0x190 [ 92.812461] __block_write_full_page+0x218/0x460 [ 92.815792] __writepage+0x11/0x50 [ 92.817209] write_cache_pages+0x1ae/0x3d0 [ 92.825585] generic_writepages+0x5a/0x90 [ 92.831865] do_writepages+0x43/0xd0 [ 92.836972] __filemap_fdatawrite_range+0xc1/0x100 [ 92.838788] filemap_write_and_wait+0x24/0x70 [ 92.840491] __blkdev_put+0x69/0x1e0 [ 92.841949] blkdev_close+0x16/0x20 [ 92.843418] __fput+0xda/0x1f0 [ 92.844740] task_work_run+0x87/0xb0 [ 92.846215] do_exit+0x2f5/0xba0 [ 92.850528] do_group_exit+0x34/0xb0 [ 92.852018] SyS_exit_group+0xb/0x10 [ 92.853449] do_syscall_64+0x6e/0x270 [ 92.854944] entry_SYSCALL_64_after_hwframe+0x42/0xb7 [ 92.943530] 1 lock held by a.out/634: [ 92.945105] #0: 00000000a2849e25 (&bdev->bd_mutex){+.+.}, at: __blkdev_put+0x3c/0x1e0 ---------------------------------------- The reason of q->mq_freeze_depth == 1 turned out that loop_set_status() forgot to call blk_mq_unfreeze_queue() at error paths for info->lo_encrypt_type != NULL case. ---------------------------------------- [ 37.509497] CPU: 2 PID: 634 Comm: a.out Tainted: G W 4.16.0+ #457 [ 37.513608] Hardware name: VMware, Inc. VMware Virtual Platform/440BX Desktop Reference Platform, BIOS 6.00 05/19/2017 [ 37.518832] RIP: 0010:blk_freeze_queue_start+0x17/0x40 [ 37.521778] RSP: 0018:ffffb0c2013e7c60 EFLAGS: 00010246 [ 37.524078] RAX: 0000000000000000 RBX: ffff8b07b1519798 RCX: 0000000000000000 [ 37.527015] RDX: 0000000000000002 RSI: ffffb0c2013e7cc0 RDI: ffff8b07b1519798 [ 37.529934] RBP: ffffb0c2013e7cc0 R08: 0000000000000008 R09: 47a189966239b898 [ 37.532684] R10: dad78b99b278552f R11: 9332dca72259d5ef R12: ffff8b07acd73678 [ 37.535452] R13: 0000000000004c04 R14: 0000000000000000 R15: ffff8b07b841e940 [ 37.538186] FS: 00007fede33b9740(0000) GS:ffff8b07b8e80000(0000) knlGS:0000000000000000 [ 37.541168] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 37.543590] CR2: 00000000206fdf18 CR3: 0000000130b30006 CR4: 00000000000606e0 [ 37.546410] Call Trace: [ 37.547902] blk_freeze_queue+0x9/0x30 [ 37.549968] loop_set_status+0x67/0x3c0 [loop] [ 37.549975] loop_set_status64+0x3b/0x70 [loop] [ 37.549986] lo_ioctl+0x223/0x810 [loop] [ 37.549995] blkdev_ioctl+0x572/0x980 [ 37.550003] block_ioctl+0x34/0x40 [ 37.550006] do_vfs_ioctl+0xa7/0x6d0 [ 37.550017] ksys_ioctl+0x6b/0x80 [ 37.573076] SyS_ioctl+0x5/0x10 [ 37.574831] do_syscall_64+0x6e/0x270 [ 37.576769] entry_SYSCALL_64_after_hwframe+0x42/0xb7 ---------------------------------------- [1] https://syzkaller.appspot.com/bug?id=cd662bc3f6022c0979d01a262c318fab2ee9b56f Signed-off-by: Tetsuo Handa Reported-by: syzbot Fixes: ecdd09597a572513 ("block/loop: fix race between I/O and set_status") Cc: Ming Lei Cc: Dmitry Vyukov Cc: stable Cc: Jens Axboe Signed-off-by: Jens Axboe Signed-off-by: Greg Kroah-Hartman --- drivers/block/loop.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/drivers/block/loop.c b/drivers/block/loop.c index 19858a146f30..754852156622 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c @@ -1098,11 +1098,15 @@ loop_set_status(struct loop_device *lo, const struct loop_info64 *info) if (info->lo_encrypt_type) { unsigned int type = info->lo_encrypt_type; - if (type >= MAX_LO_CRYPT) - return -EINVAL; + if (type >= MAX_LO_CRYPT) { + err = -EINVAL; + goto exit; + } xfer = xfer_funcs[type]; - if (xfer == NULL) - return -EINVAL; + if (xfer == NULL) { + err = -EINVAL; + goto exit; + } } else xfer = NULL; -- GitLab From 3a6771e2fb321d0ea6004e0314b0aee847a2be7b Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Mon, 2 Apr 2018 16:49:30 -0700 Subject: [PATCH 0518/1635] nfit: fix region registration vs block-data-window ranges commit 8d0d8ed3356aa9ed43b819aaedd39b08ca453007 upstream. Commit 1cf03c00e7c1 "nfit: scrub and register regions in a workqueue" mistakenly attempts to register a region per BLK aperture. There is nothing to register for individual apertures as they belong as a set to a BLK aperture group that are registered with a corresponding DIMM-control-region. Filter them for registration to prevent some needless devm_kzalloc() allocations. Cc: Fixes: 1cf03c00e7c1 ("nfit: scrub and register regions in a workqueue") Reviewed-by: Dave Jiang Signed-off-by: Dan Williams Signed-off-by: Greg Kroah-Hartman --- drivers/acpi/nfit/core.c | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/drivers/acpi/nfit/core.c b/drivers/acpi/nfit/core.c index f14b4326e855..67a860790560 100644 --- a/drivers/acpi/nfit/core.c +++ b/drivers/acpi/nfit/core.c @@ -2748,15 +2748,21 @@ static void acpi_nfit_scrub(struct work_struct *work) static int acpi_nfit_register_regions(struct acpi_nfit_desc *acpi_desc) { struct nfit_spa *nfit_spa; - int rc; - list_for_each_entry(nfit_spa, &acpi_desc->spas, list) - if (nfit_spa_type(nfit_spa->spa) == NFIT_SPA_DCR) { - /* BLK regions don't need to wait for ars results */ - rc = acpi_nfit_register_region(acpi_desc, nfit_spa); - if (rc) - return rc; - } + list_for_each_entry(nfit_spa, &acpi_desc->spas, list) { + int rc, type = nfit_spa_type(nfit_spa->spa); + + /* PMEM and VMEM will be registered by the ARS workqueue */ + if (type == NFIT_SPA_PM || type == NFIT_SPA_VOLATILE) + continue; + /* BLK apertures belong to BLK region registration below */ + if (type == NFIT_SPA_BDW) + continue; + /* BLK regions don't need to wait for ARS results */ + rc = acpi_nfit_register_region(acpi_desc, nfit_spa); + if (rc) + return rc; + } acpi_desc->ars_start_flags = 0; if (!acpi_desc->cancel) -- GitLab From b6366b15a267427c95c4104fb719787562b007e7 Mon Sep 17 00:00:00 2001 From: Julian Wiedmann Date: Mon, 5 Mar 2018 09:39:38 +0100 Subject: [PATCH 0519/1635] s390/qdio: don't retry EQBS after CCQ 96 commit dae55b6fef58530c13df074bcc182c096609339e upstream. Immediate retry of EQBS after CCQ 96 means that we potentially misreport the state of buffers inspected during the first EQBS call. This occurs when 1. the first EQBS finds all inspected buffers still in the initial state set by the driver (ie INPUT EMPTY or OUTPUT PRIMED), 2. the EQBS terminates early with CCQ 96, and 3. by the time that the second EQBS comes around, the state of those previously inspected buffers has changed. If the state reported by the second EQBS is 'driver-owned', all we know is that the previous buffers are driver-owned now as well. But we can't tell if they all have the same state. So for instance - the second EQBS reports OUTPUT EMPTY, but any number of the previous buffers could be OUTPUT ERROR by now, - the second EQBS reports OUTPUT ERROR, but any number of the previous buffers could be OUTPUT EMPTY by now. Effectively, this can result in both over- and underreporting of errors. If the state reported by the second EQBS is 'HW-owned', that doesn't guarantee that the previous buffers have not been switched to driver-owned in the mean time. So for instance - the second EQBS reports INPUT EMPTY, but any number of the previous buffers could be INPUT PRIMED (or INPUT ERROR) by now. This would result in failure to process pending work on the queue. If it's the final check before yielding initiative, this can cause a (temporary) queue stall due to IRQ avoidance. Fixes: 25f269f17316 ("[S390] qdio: EQBS retry after CCQ 96") Cc: #v3.2+ Signed-off-by: Julian Wiedmann Reviewed-by: Benjamin Block Signed-off-by: Martin Schwidefsky Signed-off-by: Greg Kroah-Hartman --- drivers/s390/cio/qdio_main.c | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/drivers/s390/cio/qdio_main.c b/drivers/s390/cio/qdio_main.c index a4ad39ba3873..54ac82b82de3 100644 --- a/drivers/s390/cio/qdio_main.c +++ b/drivers/s390/cio/qdio_main.c @@ -126,7 +126,7 @@ static inline int qdio_check_ccq(struct qdio_q *q, unsigned int ccq) static int qdio_do_eqbs(struct qdio_q *q, unsigned char *state, int start, int count, int auto_ack) { - int rc, tmp_count = count, tmp_start = start, nr = q->nr, retried = 0; + int rc, tmp_count = count, tmp_start = start, nr = q->nr; unsigned int ccq = 0; qperf_inc(q, eqbs); @@ -149,14 +149,7 @@ static int qdio_do_eqbs(struct qdio_q *q, unsigned char *state, qperf_inc(q, eqbs_partial); DBF_DEV_EVENT(DBF_WARN, q->irq_ptr, "EQBS part:%02x", tmp_count); - /* - * Retry once, if that fails bail out and process the - * extracted buffers before trying again. - */ - if (!retried++) - goto again; - else - return count - tmp_count; + return count - tmp_count; } DBF_ERROR("%4x EQBS ERROR", SCH_NO(q)); -- GitLab From c6c8e42071dcaa11bb710b44471cb94f3ff78d19 Mon Sep 17 00:00:00 2001 From: Julian Wiedmann Date: Wed, 7 Mar 2018 14:01:01 +0100 Subject: [PATCH 0520/1635] s390/qdio: don't merge ERROR output buffers commit 0cf1e05157b9e5530dcc3ca9fec9bf617fc93375 upstream. On an Output queue, both EMPTY and PENDING buffer states imply that the buffer is ready for completion-processing by the upper-layer drivers. So for a non-QEBSM Output queue, get_buf_states() merges mixed batches of PENDING and EMPTY buffers into one large batch of EMPTY buffers. The upper-layer driver (ie. qeth) later distuingishes PENDING from EMPTY by inspecting the slsb_state for QDIO_OUTBUF_STATE_FLAG_PENDING. But the merge logic in get_buf_states() contains a bug that causes us to erronously also merge ERROR buffers into such a batch of EMPTY buffers (ERROR is 0xaf, EMPTY is 0xa1; so ERROR & EMPTY == EMPTY). Effectively, most outbound ERROR buffers are currently discarded silently and processed as if they had succeeded. Note that this affects _all_ non-QEBSM device types, not just IQD with CQ. Fix it by explicitly spelling out the exact conditions for merging. For extracting the "get initial state" part out of the loop, this relies on the fact that get_buf_states() is never called with a count of 0. The QEBSM path already strictly requires this, and the two callers with variable 'count' make sure of it. Fixes: 104ea556ee7f ("qdio: support asynchronous delivery of storage blocks") Cc: #v3.2+ Signed-off-by: Julian Wiedmann Reviewed-by: Ursula Braun Reviewed-by: Benjamin Block Signed-off-by: Martin Schwidefsky Signed-off-by: Greg Kroah-Hartman --- drivers/s390/cio/qdio_main.c | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/drivers/s390/cio/qdio_main.c b/drivers/s390/cio/qdio_main.c index 54ac82b82de3..8941e7caaf4d 100644 --- a/drivers/s390/cio/qdio_main.c +++ b/drivers/s390/cio/qdio_main.c @@ -205,7 +205,10 @@ static int qdio_do_sqbs(struct qdio_q *q, unsigned char state, int start, return 0; } -/* returns number of examined buffers and their common state in *state */ +/* + * Returns number of examined buffers and their common state in *state. + * Requested number of buffers-to-examine must be > 0. + */ static inline int get_buf_states(struct qdio_q *q, unsigned int bufnr, unsigned char *state, unsigned int count, int auto_ack, int merge_pending) @@ -216,17 +219,23 @@ static inline int get_buf_states(struct qdio_q *q, unsigned int bufnr, if (is_qebsm(q)) return qdio_do_eqbs(q, state, bufnr, count, auto_ack); - for (i = 0; i < count; i++) { - if (!__state) { - __state = q->slsb.val[bufnr]; - if (merge_pending && __state == SLSB_P_OUTPUT_PENDING) - __state = SLSB_P_OUTPUT_EMPTY; - } else if (merge_pending) { - if ((q->slsb.val[bufnr] & __state) != __state) - break; - } else if (q->slsb.val[bufnr] != __state) - break; + /* get initial state: */ + __state = q->slsb.val[bufnr]; + if (merge_pending && __state == SLSB_P_OUTPUT_PENDING) + __state = SLSB_P_OUTPUT_EMPTY; + + for (i = 1; i < count; i++) { bufnr = next_buf(bufnr); + + /* merge PENDING into EMPTY: */ + if (merge_pending && + q->slsb.val[bufnr] == SLSB_P_OUTPUT_PENDING && + __state == SLSB_P_OUTPUT_EMPTY) + continue; + + /* stop if next state differs from initial state: */ + if (q->slsb.val[bufnr] != __state) + break; } *state = __state; return i; -- GitLab From 3da5723b4f05c7931b51302aa15ccc382477f0d5 Mon Sep 17 00:00:00 2001 From: Vasily Gorbik Date: Tue, 3 Apr 2018 16:02:15 +0200 Subject: [PATCH 0521/1635] s390/ipl: ensure loadparm valid flag is set commit 15deb080a6087b73089139569558965750e69d67 upstream. When loadparm is set in reipl parm block, the kernel should also set DIAG308_FLAGS_LP_VALID flag. This fixes loadparm ignoring during z/VM fcp -> ccw reipl and kvm direct boot -> ccw reipl. Cc: Reviewed-by: Heiko Carstens Signed-off-by: Vasily Gorbik Signed-off-by: Martin Schwidefsky Signed-off-by: Greg Kroah-Hartman --- arch/s390/kernel/ipl.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/s390/kernel/ipl.c b/arch/s390/kernel/ipl.c index 8e622bb52f7a..d1a0e2c521d7 100644 --- a/arch/s390/kernel/ipl.c +++ b/arch/s390/kernel/ipl.c @@ -799,6 +799,7 @@ static ssize_t reipl_generic_loadparm_store(struct ipl_parameter_block *ipb, /* copy and convert to ebcdic */ memcpy(ipb->hdr.loadparm, buf, lp_len); ASCEBC(ipb->hdr.loadparm, LOADPARM_LEN); + ipb->hdr.flags |= DIAG308_FLAGS_LP_VALID; return len; } -- GitLab From adea72f0e570500f6f78343550950dcbb73e1a19 Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Fri, 13 Apr 2018 15:35:20 -0700 Subject: [PATCH 0522/1635] get_user_pages_fast(): return -EFAULT on access_ok failure commit c61611f70958d86f659bca25c02ae69413747a8d upstream. get_user_pages_fast is supposed to be a faster drop-in equivalent of get_user_pages. As such, callers expect it to return a negative return code when passed an invalid address, and never expect it to return 0 when passed a positive number of pages, since its documentation says: * Returns number of pages pinned. This may be fewer than the number * requested. If nr_pages is 0 or negative, returns 0. If no pages * were pinned, returns -errno. When get_user_pages_fast fall back on get_user_pages this is exactly what happens. Unfortunately the implementation is inconsistent: it returns 0 if passed a kernel address, confusing callers: for example, the following is pretty common but does not appear to do the right thing with a kernel address: ret = get_user_pages_fast(addr, 1, writeable, &page); if (ret < 0) return ret; Change get_user_pages_fast to return -EFAULT when supplied a kernel address to make it match expectations. All callers have been audited for consistency with the documented semantics. Link: http://lkml.kernel.org/r/1522962072-182137-4-git-send-email-mst@redhat.com Fixes: 5b65c4677a57 ("mm, x86/mm: Fix performance regression in get_user_pages_fast()") Signed-off-by: Michael S. Tsirkin Reported-by: syzbot+6304bf97ef436580fede@syzkaller.appspotmail.com Reviewed-by: Andrew Morton Cc: Kirill A. Shutemov Cc: Huang Ying Cc: Jonathan Corbet Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: Thorsten Leemhuis Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- mm/gup.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/mm/gup.c b/mm/gup.c index e0d82b6706d7..8fc23a60487d 100644 --- a/mm/gup.c +++ b/mm/gup.c @@ -1816,9 +1816,12 @@ int get_user_pages_fast(unsigned long start, int nr_pages, int write, len = (unsigned long) nr_pages << PAGE_SHIFT; end = start + len; + if (nr_pages <= 0) + return 0; + if (unlikely(!access_ok(write ? VERIFY_WRITE : VERIFY_READ, (void __user *)start, len))) - return 0; + return -EFAULT; if (gup_fast_permitted(start, nr_pages, write)) { local_irq_disable(); -- GitLab From c3efeaa3b15403eb17b693a66c6a297ac459a020 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 8 Apr 2018 11:57:10 -0400 Subject: [PATCH 0523/1635] getname_kernel() needs to make sure that ->name != ->iname in long case commit 30ce4d1903e1d8a7ccd110860a5eef3c638ed8be upstream. missed it in "kill struct filename.separate" several years ago. Cc: stable@vger.kernel.org Signed-off-by: Al Viro Signed-off-by: Greg Kroah-Hartman --- fs/namei.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fs/namei.c b/fs/namei.c index f839b0750ca3..0b46b858cd42 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -222,9 +222,10 @@ getname_kernel(const char * filename) if (len <= EMBEDDED_NAME_MAX) { result->name = (char *)result->iname; } else if (len <= PATH_MAX) { + const size_t size = offsetof(struct filename, iname[1]); struct filename *tmp; - tmp = kmalloc(sizeof(*tmp), GFP_KERNEL); + tmp = kmalloc(size, GFP_KERNEL); if (unlikely(!tmp)) { __putname(result); return ERR_PTR(-ENOMEM); -- GitLab From f58ef38ef1a881cc178b7ae537be29dc65766e18 Mon Sep 17 00:00:00 2001 From: Szymon Janc Date: Tue, 3 Apr 2018 13:40:06 +0200 Subject: [PATCH 0524/1635] Bluetooth: Fix connection if directed advertising and privacy is used commit 082f2300cfa1a3d9d5221c38c5eba85d4ab98bd8 upstream. Local random address needs to be updated before creating connection if RPA from LE Direct Advertising Report was resolved in host. Otherwise remote device might ignore connection request due to address mismatch. This was affecting following qualification test cases: GAP/CONN/SCEP/BV-03-C, GAP/CONN/GCEP/BV-05-C, GAP/CONN/DCEP/BV-05-C Before patch: < HCI Command: LE Set Random Address (0x08|0x0005) plen 6 #11350 [hci0] 84680.231216 Address: 56:BC:E8:24:11:68 (Resolvable) Identity type: Random (0x01) Identity: F2:F1:06:3D:9C:42 (Static) > HCI Event: Command Complete (0x0e) plen 4 #11351 [hci0] 84680.246022 LE Set Random Address (0x08|0x0005) ncmd 1 Status: Success (0x00) < HCI Command: LE Set Scan Parameters (0x08|0x000b) plen 7 #11352 [hci0] 84680.246417 Type: Passive (0x00) Interval: 60.000 msec (0x0060) Window: 30.000 msec (0x0030) Own address type: Random (0x01) Filter policy: Accept all advertisement, inc. directed unresolved RPA (0x02) > HCI Event: Command Complete (0x0e) plen 4 #11353 [hci0] 84680.248854 LE Set Scan Parameters (0x08|0x000b) ncmd 1 Status: Success (0x00) < HCI Command: LE Set Scan Enable (0x08|0x000c) plen 2 #11354 [hci0] 84680.249466 Scanning: Enabled (0x01) Filter duplicates: Enabled (0x01) > HCI Event: Command Complete (0x0e) plen 4 #11355 [hci0] 84680.253222 LE Set Scan Enable (0x08|0x000c) ncmd 1 Status: Success (0x00) > HCI Event: LE Meta Event (0x3e) plen 18 #11356 [hci0] 84680.458387 LE Direct Advertising Report (0x0b) Num reports: 1 Event type: Connectable directed - ADV_DIRECT_IND (0x01) Address type: Random (0x01) Address: 53:38:DA:46:8C:45 (Resolvable) Identity type: Public (0x00) Identity: 11:22:33:44:55:66 (OUI 11-22-33) Direct address type: Random (0x01) Direct address: 7C:D6:76:8C:DF:82 (Resolvable) Identity type: Random (0x01) Identity: F2:F1:06:3D:9C:42 (Static) RSSI: -74 dBm (0xb6) < HCI Command: LE Set Scan Enable (0x08|0x000c) plen 2 #11357 [hci0] 84680.458737 Scanning: Disabled (0x00) Filter duplicates: Disabled (0x00) > HCI Event: Command Complete (0x0e) plen 4 #11358 [hci0] 84680.469982 LE Set Scan Enable (0x08|0x000c) ncmd 1 Status: Success (0x00) < HCI Command: LE Create Connection (0x08|0x000d) plen 25 #11359 [hci0] 84680.470444 Scan interval: 60.000 msec (0x0060) Scan window: 60.000 msec (0x0060) Filter policy: White list is not used (0x00) Peer address type: Random (0x01) Peer address: 53:38:DA:46:8C:45 (Resolvable) Identity type: Public (0x00) Identity: 11:22:33:44:55:66 (OUI 11-22-33) Own address type: Random (0x01) Min connection interval: 30.00 msec (0x0018) Max connection interval: 50.00 msec (0x0028) Connection latency: 0 (0x0000) Supervision timeout: 420 msec (0x002a) Min connection length: 0.000 msec (0x0000) Max connection length: 0.000 msec (0x0000) > HCI Event: Command Status (0x0f) plen 4 #11360 [hci0] 84680.474971 LE Create Connection (0x08|0x000d) ncmd 1 Status: Success (0x00) < HCI Command: LE Create Connection Cancel (0x08|0x000e) plen 0 #11361 [hci0] 84682.545385 > HCI Event: Command Complete (0x0e) plen 4 #11362 [hci0] 84682.551014 LE Create Connection Cancel (0x08|0x000e) ncmd 1 Status: Success (0x00) > HCI Event: LE Meta Event (0x3e) plen 19 #11363 [hci0] 84682.551074 LE Connection Complete (0x01) Status: Unknown Connection Identifier (0x02) Handle: 0 Role: Master (0x00) Peer address type: Public (0x00) Peer address: 00:00:00:00:00:00 (OUI 00-00-00) Connection interval: 0.00 msec (0x0000) Connection latency: 0 (0x0000) Supervision timeout: 0 msec (0x0000) Master clock accuracy: 0x00 After patch: < HCI Command: LE Set Scan Parameters (0x08|0x000b) plen 7 #210 [hci0] 667.152459 Type: Passive (0x00) Interval: 60.000 msec (0x0060) Window: 30.000 msec (0x0030) Own address type: Random (0x01) Filter policy: Accept all advertisement, inc. directed unresolved RPA (0x02) > HCI Event: Command Complete (0x0e) plen 4 #211 [hci0] 667.153613 LE Set Scan Parameters (0x08|0x000b) ncmd 1 Status: Success (0x00) < HCI Command: LE Set Scan Enable (0x08|0x000c) plen 2 #212 [hci0] 667.153704 Scanning: Enabled (0x01) Filter duplicates: Enabled (0x01) > HCI Event: Command Complete (0x0e) plen 4 #213 [hci0] 667.154584 LE Set Scan Enable (0x08|0x000c) ncmd 1 Status: Success (0x00) > HCI Event: LE Meta Event (0x3e) plen 18 #214 [hci0] 667.182619 LE Direct Advertising Report (0x0b) Num reports: 1 Event type: Connectable directed - ADV_DIRECT_IND (0x01) Address type: Random (0x01) Address: 50:52:D9:A6:48:A0 (Resolvable) Identity type: Public (0x00) Identity: 11:22:33:44:55:66 (OUI 11-22-33) Direct address type: Random (0x01) Direct address: 7C:C1:57:A5:B7:A8 (Resolvable) Identity type: Random (0x01) Identity: F4:28:73:5D:38:B0 (Static) RSSI: -70 dBm (0xba) < HCI Command: LE Set Scan Enable (0x08|0x000c) plen 2 #215 [hci0] 667.182704 Scanning: Disabled (0x00) Filter duplicates: Disabled (0x00) > HCI Event: Command Complete (0x0e) plen 4 #216 [hci0] 667.183599 LE Set Scan Enable (0x08|0x000c) ncmd 1 Status: Success (0x00) < HCI Command: LE Set Random Address (0x08|0x0005) plen 6 #217 [hci0] 667.183645 Address: 7C:C1:57:A5:B7:A8 (Resolvable) Identity type: Random (0x01) Identity: F4:28:73:5D:38:B0 (Static) > HCI Event: Command Complete (0x0e) plen 4 #218 [hci0] 667.184590 LE Set Random Address (0x08|0x0005) ncmd 1 Status: Success (0x00) < HCI Command: LE Create Connection (0x08|0x000d) plen 25 #219 [hci0] 667.184613 Scan interval: 60.000 msec (0x0060) Scan window: 60.000 msec (0x0060) Filter policy: White list is not used (0x00) Peer address type: Random (0x01) Peer address: 50:52:D9:A6:48:A0 (Resolvable) Identity type: Public (0x00) Identity: 11:22:33:44:55:66 (OUI 11-22-33) Own address type: Random (0x01) Min connection interval: 30.00 msec (0x0018) Max connection interval: 50.00 msec (0x0028) Connection latency: 0 (0x0000) Supervision timeout: 420 msec (0x002a) Min connection length: 0.000 msec (0x0000) Max connection length: 0.000 msec (0x0000) > HCI Event: Command Status (0x0f) plen 4 #220 [hci0] 667.186558 LE Create Connection (0x08|0x000d) ncmd 1 Status: Success (0x00) > HCI Event: LE Meta Event (0x3e) plen 19 #221 [hci0] 667.485824 LE Connection Complete (0x01) Status: Success (0x00) Handle: 0 Role: Master (0x00) Peer address type: Random (0x01) Peer address: 50:52:D9:A6:48:A0 (Resolvable) Identity type: Public (0x00) Identity: 11:22:33:44:55:66 (OUI 11-22-33) Connection interval: 50.00 msec (0x0028) Connection latency: 0 (0x0000) Supervision timeout: 420 msec (0x002a) Master clock accuracy: 0x07 @ MGMT Event: Device Connected (0x000b) plen 13 {0x0002} [hci0] 667.485996 LE Address: 11:22:33:44:55:66 (OUI 11-22-33) Flags: 0x00000000 Data length: 0 Signed-off-by: Szymon Janc Signed-off-by: Marcel Holtmann Cc: stable@vger.kernel.org Signed-off-by: Greg Kroah-Hartman --- include/net/bluetooth/hci_core.h | 2 +- net/bluetooth/hci_conn.c | 29 +++++++++++++++++++++-------- net/bluetooth/hci_event.c | 15 +++++++++++---- net/bluetooth/l2cap_core.c | 2 +- 4 files changed, 34 insertions(+), 14 deletions(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 95ccc1eef558..b619a190ff12 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -895,7 +895,7 @@ struct hci_conn *hci_connect_le_scan(struct hci_dev *hdev, bdaddr_t *dst, u16 conn_timeout); struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst, u8 dst_type, u8 sec_level, u16 conn_timeout, - u8 role); + u8 role, bdaddr_t *direct_rpa); struct hci_conn *hci_connect_acl(struct hci_dev *hdev, bdaddr_t *dst, u8 sec_level, u8 auth_type); struct hci_conn *hci_connect_sco(struct hci_dev *hdev, int type, bdaddr_t *dst, diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index dc59eae54717..cc061495f653 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -749,18 +749,31 @@ static bool conn_use_rpa(struct hci_conn *conn) } static void hci_req_add_le_create_conn(struct hci_request *req, - struct hci_conn *conn) + struct hci_conn *conn, + bdaddr_t *direct_rpa) { struct hci_cp_le_create_conn cp; struct hci_dev *hdev = conn->hdev; u8 own_addr_type; - /* Update random address, but set require_privacy to false so - * that we never connect with an non-resolvable address. + /* If direct address was provided we use it instead of current + * address. */ - if (hci_update_random_address(req, false, conn_use_rpa(conn), - &own_addr_type)) - return; + if (direct_rpa) { + if (bacmp(&req->hdev->random_addr, direct_rpa)) + hci_req_add(req, HCI_OP_LE_SET_RANDOM_ADDR, 6, + direct_rpa); + + /* direct address is always RPA */ + own_addr_type = ADDR_LE_DEV_RANDOM; + } else { + /* Update random address, but set require_privacy to false so + * that we never connect with an non-resolvable address. + */ + if (hci_update_random_address(req, false, conn_use_rpa(conn), + &own_addr_type)) + return; + } memset(&cp, 0, sizeof(cp)); @@ -825,7 +838,7 @@ static void hci_req_directed_advertising(struct hci_request *req, struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst, u8 dst_type, u8 sec_level, u16 conn_timeout, - u8 role) + u8 role, bdaddr_t *direct_rpa) { struct hci_conn_params *params; struct hci_conn *conn; @@ -940,7 +953,7 @@ struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst, hci_dev_set_flag(hdev, HCI_LE_SCAN_INTERRUPTED); } - hci_req_add_le_create_conn(&req, conn); + hci_req_add_le_create_conn(&req, conn, direct_rpa); create_conn: err = hci_req_run(&req, create_le_conn_complete); diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 0b4dba08a14e..01f211e31f47 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -4646,7 +4646,8 @@ static void hci_le_conn_update_complete_evt(struct hci_dev *hdev, /* This function requires the caller holds hdev->lock */ static struct hci_conn *check_pending_le_conn(struct hci_dev *hdev, bdaddr_t *addr, - u8 addr_type, u8 adv_type) + u8 addr_type, u8 adv_type, + bdaddr_t *direct_rpa) { struct hci_conn *conn; struct hci_conn_params *params; @@ -4697,7 +4698,8 @@ static struct hci_conn *check_pending_le_conn(struct hci_dev *hdev, } conn = hci_connect_le(hdev, addr, addr_type, BT_SECURITY_LOW, - HCI_LE_AUTOCONN_TIMEOUT, HCI_ROLE_MASTER); + HCI_LE_AUTOCONN_TIMEOUT, HCI_ROLE_MASTER, + direct_rpa); if (!IS_ERR(conn)) { /* If HCI_AUTO_CONN_EXPLICIT is set, conn is already owned * by higher layer that tried to connect, if no then @@ -4807,8 +4809,13 @@ static void process_adv_report(struct hci_dev *hdev, u8 type, bdaddr_t *bdaddr, bdaddr_type = irk->addr_type; } - /* Check if we have been requested to connect to this device */ - conn = check_pending_le_conn(hdev, bdaddr, bdaddr_type, type); + /* Check if we have been requested to connect to this device. + * + * direct_addr is set only for directed advertising reports (it is NULL + * for advertising reports) and is already verified to be RPA above. + */ + conn = check_pending_le_conn(hdev, bdaddr, bdaddr_type, type, + direct_addr); if (conn && type == LE_ADV_IND) { /* Store report for later inclusion by * mgmt_device_connected diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index fc6615d59165..9b7907ebfa01 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -7156,7 +7156,7 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, hcon = hci_connect_le(hdev, dst, dst_type, chan->sec_level, HCI_LE_CONN_TIMEOUT, - HCI_ROLE_SLAVE); + HCI_ROLE_SLAVE, NULL); else hcon = hci_connect_le_scan(hdev, dst, dst_type, chan->sec_level, -- GitLab From 9e483bc229f54ecfdd87f630d9b265c3223e3671 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 16 Mar 2018 21:28:08 +0100 Subject: [PATCH 0525/1635] Bluetooth: hci_bcm: Treat Interrupt ACPI resources as always being active-low commit bb5208b314c5127b716b2ee4f55803a8bb73b750 upstream. Older devices with a serdev attached bcm bt hci, use an Interrupt ACPI resource to describe the IRQ (rather then a GpioInt resource). These device seem to all claim the IRQ is active-high and seem to all need a DMI quirk to treat it as active-low. Instead simply always assume that Interrupt resource specified IRQs are always active-low. This fixes the bt device not being able to wake the host from runtime- suspend on the: Asus T100TAM, Asus T200TA, Lenovo Yoga2 and the Toshiba Encore, without the need to add 4 new DMI quirks for these models. This also allows us to remove 2 DMI quirks for the Asus T100TA and Asus T100CHI series. Likely the 2 remaining quirks can also be removed but I could not find a DSDT of these devices to verify this. Cc: stable@vger.kernel.org Buglink: https://bugzilla.kernel.org/show_bug.cgi?id=198953 Buglink: https://bugzilla.redhat.com/show_bug.cgi?id=1554835 Signed-off-by: Hans de Goede Signed-off-by: Marcel Holtmann Signed-off-by: Greg Kroah-Hartman --- drivers/bluetooth/hci_bcm.c | 20 +++----------------- 1 file changed, 3 insertions(+), 17 deletions(-) diff --git a/drivers/bluetooth/hci_bcm.c b/drivers/bluetooth/hci_bcm.c index 73d2d88ddc03..32527bdf4b50 100644 --- a/drivers/bluetooth/hci_bcm.c +++ b/drivers/bluetooth/hci_bcm.c @@ -694,22 +694,6 @@ static const struct acpi_gpio_mapping acpi_bcm_int_first_gpios[] = { #ifdef CONFIG_ACPI /* IRQ polarity of some chipsets are not defined correctly in ACPI table. */ static const struct dmi_system_id bcm_active_low_irq_dmi_table[] = { - { - .ident = "Asus T100TA", - .matches = { - DMI_EXACT_MATCH(DMI_SYS_VENDOR, - "ASUSTeK COMPUTER INC."), - DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "T100TA"), - }, - }, - { - .ident = "Asus T100CHI", - .matches = { - DMI_EXACT_MATCH(DMI_SYS_VENDOR, - "ASUSTeK COMPUTER INC."), - DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "T100CHI"), - }, - }, { /* Handle ThinkPad 8 tablets with BCM2E55 chipset ACPI ID */ .ident = "Lenovo ThinkPad 8", .matches = { @@ -730,7 +714,9 @@ static int bcm_resource(struct acpi_resource *ares, void *data) switch (ares->type) { case ACPI_RESOURCE_TYPE_EXTENDED_IRQ: irq = &ares->data.extended_irq; - dev->irq_active_low = irq->polarity == ACPI_ACTIVE_LOW; + if (irq->polarity != ACPI_ACTIVE_LOW) + dev_info(&dev->pdev->dev, "ACPI Interrupt resource is active-high, this is usually wrong, treating the IRQ as active-low\n"); + dev->irq_active_low = true; break; case ACPI_RESOURCE_TYPE_GPIO: -- GitLab From a2813b4cfe3b836422a883857c68e2981c47a4ba Mon Sep 17 00:00:00 2001 From: Sudhir Sreedharan Date: Thu, 15 Feb 2018 12:52:45 +0530 Subject: [PATCH 0526/1635] rtl8187: Fix NULL pointer dereference in priv->conf_mutex commit 7972326a26b5bf8dc2adac575c4e03ee7e9d193a upstream. This can be reproduced by bind/unbind the driver multiple times in AM3517 board. Analysis revealed that rtl8187_start() was invoked before probe finishes(ie. before the mutex is initialized). INFO: trying to register non-static key. the code is fine but needs lockdep annotation. turning off the locking correctness validator. CPU: 0 PID: 821 Comm: wpa_supplicant Not tainted 4.9.80-dirty #250 Hardware name: Generic AM3517 (Flattened Device Tree) [] (unwind_backtrace) from [] (show_stack+0x10/0x14) [] (show_stack) from [] (register_lock_class+0x4f4/0x55c) [] (register_lock_class) from [] (__lock_acquire+0x74/0x1938) [] (__lock_acquire) from [] (lock_acquire+0xfc/0x23c) [] (lock_acquire) from [] (mutex_lock_nested+0x50/0x3b0) [] (mutex_lock_nested) from [] (rtl8187_start+0x2c/0xd54) [] (rtl8187_start) from [] (drv_start+0xa8/0x320) [] (drv_start) from [] (ieee80211_do_open+0x2bc/0x8e4) [] (ieee80211_do_open) from [] (__dev_open+0xb8/0x120) [] (__dev_open) from [] (__dev_change_flags+0x88/0x14c) [] (__dev_change_flags) from [] (dev_change_flags+0x18/0x48) [] (dev_change_flags) from [] (devinet_ioctl+0x738/0x840) [] (devinet_ioctl) from [] (sock_ioctl+0x164/0x2f4) [] (sock_ioctl) from [] (do_vfs_ioctl+0x8c/0x9d0) [] (do_vfs_ioctl) from [] (SyS_ioctl+0x6c/0x7c) [] (SyS_ioctl) from [] (ret_fast_syscall+0x0/0x1c) Unable to handle kernel NULL pointer dereference at virtual address 00000000 pgd = cd1ec000 [00000000] *pgd=8d1de831, *pte=00000000, *ppte=00000000 Internal error: Oops: 817 [#1] PREEMPT ARM Modules linked in: CPU: 0 PID: 821 Comm: wpa_supplicant Not tainted 4.9.80-dirty #250 Hardware name: Generic AM3517 (Flattened Device Tree) task: ce73eec0 task.stack: cd1ea000 PC is at mutex_lock_nested+0xe8/0x3b0 LR is at mutex_lock_nested+0xd0/0x3b0 Cc: stable@vger.kernel.org Signed-off-by: Sudhir Sreedharan Signed-off-by: Kalle Valo Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c b/drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c index 121b94f09714..9a1d15b3ce45 100644 --- a/drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c +++ b/drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c @@ -1450,6 +1450,7 @@ static int rtl8187_probe(struct usb_interface *intf, goto err_free_dev; } mutex_init(&priv->io_mutex); + mutex_init(&priv->conf_mutex); SET_IEEE80211_DEV(dev, &intf->dev); usb_set_intfdata(intf, dev); @@ -1625,7 +1626,6 @@ static int rtl8187_probe(struct usb_interface *intf, printk(KERN_ERR "rtl8187: Cannot register device\n"); goto err_free_dmabuf; } - mutex_init(&priv->conf_mutex); skb_queue_head_init(&priv->b_tx_status.queue); wiphy_info(dev->wiphy, "hwaddr %pM, %s V%d + %s, rfkill mask %d\n", -- GitLab From 99971efd7d9a82940dd410013f234816b7a82bcf Mon Sep 17 00:00:00 2001 From: Yazen Ghannam Date: Mon, 18 Dec 2017 12:37:13 +0100 Subject: [PATCH 0527/1635] x86/MCE: Report only DRAM ECC as memory errors on AMD systems commit c6708d50f166bea2d763c96485d31fdbc50204f1 upstream. The MCA_STATUS[ErrorCodeExt] field is very bank type specific. We currently check if the ErrorCodeExt value is 0x0 or 0x8 in mce_is_memory_error(), but we don't check the bank number. This means that we could flag non-memory errors as memory errors. We know that we want to flag DRAM ECC errors as memory errors, so let's do those cases first. We can add more cases later when needed. Define a wrapper function in mce_amd.c so we can use SMCA enums. [ bp: Remove brackets around return statements. ] Signed-off-by: Yazen Ghannam Signed-off-by: Borislav Petkov Signed-off-by: Thomas Gleixner Link: http://lkml.kernel.org/r/20171207203955.118171-2-Yazen.Ghannam@amd.com Signed-off-by: Greg Kroah-Hartman --- arch/x86/include/asm/mce.h | 2 ++ arch/x86/kernel/cpu/mcheck/mce.c | 4 +--- arch/x86/kernel/cpu/mcheck/mce_amd.c | 11 +++++++++++ 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/arch/x86/include/asm/mce.h b/arch/x86/include/asm/mce.h index b1e8d8db921f..96ea4b5ba658 100644 --- a/arch/x86/include/asm/mce.h +++ b/arch/x86/include/asm/mce.h @@ -376,6 +376,7 @@ struct smca_bank { extern struct smca_bank smca_banks[MAX_NR_BANKS]; extern const char *smca_get_long_name(enum smca_bank_types t); +extern bool amd_mce_is_memory_error(struct mce *m); extern int mce_threshold_create_device(unsigned int cpu); extern int mce_threshold_remove_device(unsigned int cpu); @@ -384,6 +385,7 @@ extern int mce_threshold_remove_device(unsigned int cpu); static inline int mce_threshold_create_device(unsigned int cpu) { return 0; }; static inline int mce_threshold_remove_device(unsigned int cpu) { return 0; }; +static inline bool amd_mce_is_memory_error(struct mce *m) { return false; }; #endif diff --git a/arch/x86/kernel/cpu/mcheck/mce.c b/arch/x86/kernel/cpu/mcheck/mce.c index e13d652fc30a..28d27de08545 100644 --- a/arch/x86/kernel/cpu/mcheck/mce.c +++ b/arch/x86/kernel/cpu/mcheck/mce.c @@ -512,10 +512,8 @@ static int mce_usable_address(struct mce *m) bool mce_is_memory_error(struct mce *m) { if (m->cpuvendor == X86_VENDOR_AMD) { - /* ErrCodeExt[20:16] */ - u8 xec = (m->status >> 16) & 0x1f; + return amd_mce_is_memory_error(m); - return (xec == 0x0 || xec == 0x8); } else if (m->cpuvendor == X86_VENDOR_INTEL) { /* * Intel SDM Volume 3B - 15.9.2 Compound Error Codes diff --git a/arch/x86/kernel/cpu/mcheck/mce_amd.c b/arch/x86/kernel/cpu/mcheck/mce_amd.c index bd0e1b77937c..2c5e2251a874 100644 --- a/arch/x86/kernel/cpu/mcheck/mce_amd.c +++ b/arch/x86/kernel/cpu/mcheck/mce_amd.c @@ -752,6 +752,17 @@ int umc_normaddr_to_sysaddr(u64 norm_addr, u16 nid, u8 umc, u64 *sys_addr) } EXPORT_SYMBOL_GPL(umc_normaddr_to_sysaddr); +bool amd_mce_is_memory_error(struct mce *m) +{ + /* ErrCodeExt[20:16] */ + u8 xec = (m->status >> 16) & 0x1f; + + if (mce_flags.smca) + return smca_get_bank_type(m) == SMCA_UMC && xec == 0x0; + + return m->bank == 4 && xec == 0x8; +} + static void __log_error(unsigned int bank, u64 status, u64 addr, u64 misc) { struct mce m; -- GitLab From 0ee4f31673af1d8423c46eb121513c17774cca28 Mon Sep 17 00:00:00 2001 From: Yazen Ghannam Date: Wed, 21 Feb 2018 11:18:57 +0100 Subject: [PATCH 0528/1635] x86/mce/AMD: Pass the bank number to smca_get_bank_type() commit e5d6a126d4c473499f354254a15ca0c2d8c84ca3 upstream. Pass the bank number to smca_get_bank_type() since that's all we need. Also, we should compare the bank number to MAX_NR_BANKS (size of the smca_banks array) not the number of bank types. Bank types are reused for multiple banks, so the number of types can be different from the number of banks in a system and thus we could return an invalid bank type. Signed-off-by: Yazen Ghannam Signed-off-by: Borislav Petkov Cc: # 4.14.x Cc: # 4.14.x: 11cf887728a3 x86/MCE/AMD: Define a function to get SMCA bank type Cc: # 4.14.x: c6708d50f166 x86/MCE: Report only DRAM ECC as memory errors on AMD systems Cc: Borislav Petkov Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: Tony Luck Cc: linux-edac Link: http://lkml.kernel.org/r/20180221101900.10326-6-bp@alien8.de Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman --- arch/x86/kernel/cpu/mcheck/mce_amd.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/arch/x86/kernel/cpu/mcheck/mce_amd.c b/arch/x86/kernel/cpu/mcheck/mce_amd.c index 2c5e2251a874..63747c772234 100644 --- a/arch/x86/kernel/cpu/mcheck/mce_amd.c +++ b/arch/x86/kernel/cpu/mcheck/mce_amd.c @@ -110,14 +110,14 @@ const char *smca_get_long_name(enum smca_bank_types t) } EXPORT_SYMBOL_GPL(smca_get_long_name); -static enum smca_bank_types smca_get_bank_type(struct mce *m) +static enum smca_bank_types smca_get_bank_type(unsigned int bank) { struct smca_bank *b; - if (m->bank >= N_SMCA_BANK_TYPES) + if (bank >= MAX_NR_BANKS) return N_SMCA_BANK_TYPES; - b = &smca_banks[m->bank]; + b = &smca_banks[bank]; if (!b->hwid) return N_SMCA_BANK_TYPES; @@ -758,7 +758,7 @@ bool amd_mce_is_memory_error(struct mce *m) u8 xec = (m->status >> 16) & 0x1f; if (mce_flags.smca) - return smca_get_bank_type(m) == SMCA_UMC && xec == 0x0; + return smca_get_bank_type(m->bank) == SMCA_UMC && xec == 0x0; return m->bank == 4 && xec == 0x8; } @@ -1061,7 +1061,7 @@ static struct kobj_type threshold_ktype = { static const char *get_name(unsigned int bank, struct threshold_block *b) { - unsigned int bank_type; + enum smca_bank_types bank_type; if (!mce_flags.smca) { if (b && bank == 4) @@ -1070,11 +1070,10 @@ static const char *get_name(unsigned int bank, struct threshold_block *b) return th_names[bank]; } - if (!smca_banks[bank].hwid) + bank_type = smca_get_bank_type(bank); + if (bank_type >= N_SMCA_BANK_TYPES) return NULL; - bank_type = smca_banks[bank].hwid->bank_type; - if (b && bank_type == SMCA_UMC) { if (b->block < ARRAY_SIZE(smca_umc_block_names)) return smca_umc_block_names[b->block]; -- GitLab From c81968e93acaa2d59b048b27de46f61f27eeafc3 Mon Sep 17 00:00:00 2001 From: Yazen Ghannam Date: Wed, 21 Feb 2018 11:18:58 +0100 Subject: [PATCH 0529/1635] x86/mce/AMD, EDAC/mce_amd: Enumerate Reserved SMCA bank type commit 68627a697c195937672ce07683094c72b1174786 upstream. Currently, bank 4 is reserved on Fam17h, so we chose not to initialize bank 4 in the smca_banks array. This means that when we check if a bank is initialized, like during boot or resume, we will see that bank 4 is not initialized and try to initialize it. This will cause a call trace, when resuming from suspend, due to rdmsr_*on_cpu() calls in the init path. The rdmsr_*on_cpu() calls issue an IPI but we're running with interrupts disabled. This triggers: WARNING: CPU: 0 PID: 11523 at kernel/smp.c:291 smp_call_function_single+0xdc/0xe0 ... Reserved banks will be read-as-zero, so their MCA_IPID register will be zero. So, like the smca_banks array, the threshold_banks array will not have an entry for a reserved bank since all its MCA_MISC* registers will be zero. Enumerate a "Reserved" bank type that matches on a HWID_MCATYPE of 0,0. Use the "Reserved" type when checking if a bank is reserved. It's possible that other bank numbers may be reserved on future systems. Don't try to find the block address on reserved banks. Signed-off-by: Yazen Ghannam Signed-off-by: Borislav Petkov Cc: # 4.14.x Cc: Borislav Petkov Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: Tony Luck Cc: linux-edac Link: http://lkml.kernel.org/r/20180221101900.10326-7-bp@alien8.de Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman --- arch/x86/include/asm/mce.h | 1 + arch/x86/kernel/cpu/mcheck/mce_amd.c | 7 +++++++ drivers/edac/mce_amd.c | 11 +++++++---- 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/arch/x86/include/asm/mce.h b/arch/x86/include/asm/mce.h index 96ea4b5ba658..340070415c2c 100644 --- a/arch/x86/include/asm/mce.h +++ b/arch/x86/include/asm/mce.h @@ -346,6 +346,7 @@ enum smca_bank_types { SMCA_IF, /* Instruction Fetch */ SMCA_L2_CACHE, /* L2 Cache */ SMCA_DE, /* Decoder Unit */ + SMCA_RESERVED, /* Reserved */ SMCA_EX, /* Execution Unit */ SMCA_FP, /* Floating Point */ SMCA_L3_CACHE, /* L3 Cache */ diff --git a/arch/x86/kernel/cpu/mcheck/mce_amd.c b/arch/x86/kernel/cpu/mcheck/mce_amd.c index 63747c772234..0e78ff5a7365 100644 --- a/arch/x86/kernel/cpu/mcheck/mce_amd.c +++ b/arch/x86/kernel/cpu/mcheck/mce_amd.c @@ -82,6 +82,7 @@ static struct smca_bank_name smca_names[] = { [SMCA_IF] = { "insn_fetch", "Instruction Fetch Unit" }, [SMCA_L2_CACHE] = { "l2_cache", "L2 Cache" }, [SMCA_DE] = { "decode_unit", "Decode Unit" }, + [SMCA_RESERVED] = { "reserved", "Reserved" }, [SMCA_EX] = { "execution_unit", "Execution Unit" }, [SMCA_FP] = { "floating_point", "Floating Point Unit" }, [SMCA_L3_CACHE] = { "l3_cache", "L3 Cache" }, @@ -127,6 +128,9 @@ static enum smca_bank_types smca_get_bank_type(unsigned int bank) static struct smca_hwid smca_hwid_mcatypes[] = { /* { bank_type, hwid_mcatype, xec_bitmap } */ + /* Reserved type */ + { SMCA_RESERVED, HWID_MCATYPE(0x00, 0x0), 0x0 }, + /* ZN Core (HWID=0xB0) MCA types */ { SMCA_LS, HWID_MCATYPE(0xB0, 0x0), 0x1FFFEF }, { SMCA_IF, HWID_MCATYPE(0xB0, 0x1), 0x3FFF }, @@ -431,6 +435,9 @@ static u32 get_block_address(unsigned int cpu, u32 current_addr, u32 low, u32 hi u32 addr = 0, offset = 0; if (mce_flags.smca) { + if (smca_get_bank_type(bank) == SMCA_RESERVED) + return addr; + if (!block) { addr = MSR_AMD64_SMCA_MCx_MISC(bank); } else { diff --git a/drivers/edac/mce_amd.c b/drivers/edac/mce_amd.c index a11a671c7a38..2ab4d61ee47e 100644 --- a/drivers/edac/mce_amd.c +++ b/drivers/edac/mce_amd.c @@ -854,21 +854,24 @@ static void decode_mc6_mce(struct mce *m) static void decode_smca_error(struct mce *m) { struct smca_hwid *hwid; - unsigned int bank_type; + enum smca_bank_types bank_type; const char *ip_name; u8 xec = XEC(m->status, xec_mask); if (m->bank >= ARRAY_SIZE(smca_banks)) return; - if (x86_family(m->cpuid) >= 0x17 && m->bank == 4) - pr_emerg(HW_ERR "Bank 4 is reserved on Fam17h.\n"); - hwid = smca_banks[m->bank].hwid; if (!hwid) return; bank_type = hwid->bank_type; + + if (bank_type == SMCA_RESERVED) { + pr_emerg(HW_ERR "Bank %d is reserved.\n", m->bank); + return; + } + ip_name = smca_get_long_name(bank_type); pr_emerg(HW_ERR "%s Extended Error Code: %d\n", ip_name, xec); -- GitLab From 360ecf51864ef1da2e74c7e5b7957508414f17ac Mon Sep 17 00:00:00 2001 From: Yazen Ghannam Date: Wed, 21 Feb 2018 11:18:59 +0100 Subject: [PATCH 0530/1635] x86/mce/AMD: Get address from already initialized block commit 27bd59502702fe51d9eb00450a75b727ec6bfcb4 upstream. The block address is saved after the block is initialized when threshold_init_device() is called. Use the saved block address, if available, rather than trying to rediscover it. This will avoid a call trace, when resuming from suspend, due to the rdmsr_safe_on_cpu() call in get_block_address(). The rdmsr_safe_on_cpu() call issues an IPI but we're running with interrupts disabled. This triggers: WARNING: CPU: 0 PID: 11523 at kernel/smp.c:291 smp_call_function_single+0xdc/0xe0 Signed-off-by: Yazen Ghannam Signed-off-by: Borislav Petkov Cc: # 4.14.x Cc: Borislav Petkov Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: Tony Luck Cc: linux-edac Link: http://lkml.kernel.org/r/20180221101900.10326-8-bp@alien8.de Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman --- arch/x86/kernel/cpu/mcheck/mce_amd.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/arch/x86/kernel/cpu/mcheck/mce_amd.c b/arch/x86/kernel/cpu/mcheck/mce_amd.c index 0e78ff5a7365..259c75d7a2a0 100644 --- a/arch/x86/kernel/cpu/mcheck/mce_amd.c +++ b/arch/x86/kernel/cpu/mcheck/mce_amd.c @@ -434,6 +434,21 @@ static u32 get_block_address(unsigned int cpu, u32 current_addr, u32 low, u32 hi { u32 addr = 0, offset = 0; + if ((bank >= mca_cfg.banks) || (block >= NR_BLOCKS)) + return addr; + + /* Get address from already initialized block. */ + if (per_cpu(threshold_banks, cpu)) { + struct threshold_bank *bankp = per_cpu(threshold_banks, cpu)[bank]; + + if (bankp && bankp->blocks) { + struct threshold_block *blockp = &bankp->blocks[block]; + + if (blockp) + return blockp->address; + } + } + if (mce_flags.smca) { if (smca_get_bank_type(bank) == SMCA_RESERVED) return addr; -- GitLab From aa3bfa29fcd5a6af2959152be406245a8f48d481 Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Mon, 15 Jan 2018 14:58:21 +0100 Subject: [PATCH 0531/1635] hwmon: (ina2xx) Fix access to uninitialized mutex commit 0c4c5860e9983eb3da7a3d73ca987643c3ed034b upstream. Initialize data->config_lock mutex before it is used by the driver code. This fixes following warning on Odroid XU3 boards: INFO: trying to register non-static key. the code is fine but needs lockdep annotation. turning off the locking correctness validator. CPU: 5 PID: 1 Comm: swapper/0 Not tainted 4.15.0-rc7-next-20180115-00001-gb75575dee3f2 #107 Hardware name: SAMSUNG EXYNOS (Flattened Device Tree) [] (unwind_backtrace) from [] (show_stack+0x10/0x14) [] (show_stack) from [] (dump_stack+0x90/0xc8) [] (dump_stack) from [] (register_lock_class+0x1c0/0x59c) [] (register_lock_class) from [] (__lock_acquire+0x78/0x1850) [] (__lock_acquire) from [] (lock_acquire+0xc8/0x2b8) [] (lock_acquire) from [] (__mutex_lock+0x60/0xa0c) [] (__mutex_lock) from [] (mutex_lock_nested+0x1c/0x24) [] (mutex_lock_nested) from [] (ina2xx_set_shunt+0x70/0xb0) [] (ina2xx_set_shunt) from [] (ina2xx_probe+0x88/0x1b0) [] (ina2xx_probe) from [] (i2c_device_probe+0x1e0/0x2d0) [] (i2c_device_probe) from [] (driver_probe_device+0x2b8/0x4a0) [] (driver_probe_device) from [] (__driver_attach+0xfc/0x120) [] (__driver_attach) from [] (bus_for_each_dev+0x58/0x7c) [] (bus_for_each_dev) from [] (bus_add_driver+0x174/0x250) [] (bus_add_driver) from [] (driver_register+0x78/0xf4) [] (driver_register) from [] (i2c_register_driver+0x38/0xa8) [] (i2c_register_driver) from [] (do_one_initcall+0x48/0x18c) [] (do_one_initcall) from [] (kernel_init_freeable+0x110/0x1d4) [] (kernel_init_freeable) from [] (kernel_init+0x8/0x114) [] (kernel_init) from [] (ret_from_fork+0x14/0x20) Fixes: 5d389b125186 ("hwmon: (ina2xx) Make calibration register value fixed") Signed-off-by: Marek Szyprowski Signed-off-by: Guenter Roeck Signed-off-by: Greg Kroah-Hartman --- drivers/hwmon/ina2xx.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/hwmon/ina2xx.c b/drivers/hwmon/ina2xx.c index e362a932fe8c..e9e6aeabbf84 100644 --- a/drivers/hwmon/ina2xx.c +++ b/drivers/hwmon/ina2xx.c @@ -454,6 +454,7 @@ static int ina2xx_probe(struct i2c_client *client, /* set the device type */ data->config = &ina2xx_config[chip]; + mutex_init(&data->config_lock); if (of_property_read_u32(dev->of_node, "shunt-resistor", &val) < 0) { struct ina2xx_platform_data *pdata = dev_get_platdata(dev); @@ -480,8 +481,6 @@ static int ina2xx_probe(struct i2c_client *client, return -ENODEV; } - mutex_init(&data->config_lock); - data->groups[group++] = &ina2xx_group; if (id->driver_data == ina226) data->groups[group++] = &ina226_group; -- GitLab From 3d06535693a3d4e9eed1a2c0a86c32ad9d5f5d4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Toke=20H=C3=B8iland-J=C3=B8rgensen?= Date: Tue, 27 Feb 2018 19:09:44 +0200 Subject: [PATCH 0532/1635] ath9k: Protect queue draining by rcu_read_lock() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 182b1917109892ab9f26d66bfdcbc4ba6f0a0a65 upstream. When ath9k was switched over to use the mac80211 intermediate queues, node cleanup now drains the mac80211 queues. However, this call path is not protected by rcu_read_lock() as it was previously entirely internal to the driver which uses its own locking. This leads to a possible rcu_dereference() without holding rcu_read_lock(); but only if a station is cleaned up while having packets queued on the TXQ. Fix this by adding the rcu_read_lock() to the caller in ath9k. Fixes: 50f08edf9809 ("ath9k: Switch to using mac80211 intermediate software queues.") Cc: stable@vger.kernel.org Reported-by: Ben Greear Signed-off-by: Toke Høiland-Jørgensen Signed-off-by: Kalle Valo Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/ath/ath9k/xmit.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 396bf05c6bf6..d8b041f48ca8 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -2892,6 +2892,8 @@ void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an) struct ath_txq *txq; int tidno; + rcu_read_lock(); + for (tidno = 0; tidno < IEEE80211_NUM_TIDS; tidno++) { tid = ath_node_to_tid(an, tidno); txq = tid->txq; @@ -2909,6 +2911,8 @@ void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an) if (!an->sta) break; /* just one multicast ath_atx_tid */ } + + rcu_read_unlock(); } #ifdef CONFIG_ATH9K_TX99 -- GitLab From e4fa275b8fddea4fa24872207aa64b8f2cdb8335 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Wed, 28 Mar 2018 10:57:22 -0700 Subject: [PATCH 0533/1635] sunrpc: remove incorrect HMAC request initialization commit f3aefb6a7066e24bfea7fcf1b07907576de69d63 upstream. make_checksum_hmac_md5() is allocating an HMAC transform and doing crypto API calls in the following order: crypto_ahash_init() crypto_ahash_setkey() crypto_ahash_digest() This is wrong because it makes no sense to init() the request before a key has been set, given that the initial state depends on the key. And digest() is short for init() + update() + final(), so in this case there's no need to explicitly call init() at all. Before commit 9fa68f620041 ("crypto: hash - prevent using keyed hashes without setting key") the extra init() had no real effect, at least for the software HMAC implementation. (There are also hardware drivers that implement HMAC-MD5, and it's not immediately obvious how gracefully they handle init() before setkey().) But now the crypto API detects this incorrect initialization and returns -ENOKEY. This is breaking NFS mounts in some cases. Fix it by removing the incorrect call to crypto_ahash_init(). Reported-by: Michael Young Fixes: 9fa68f620041 ("crypto: hash - prevent using keyed hashes without setting key") Fixes: fffdaef2eb4a ("gss_krb5: Add support for rc4-hmac encryption") Cc: stable@vger.kernel.org Signed-off-by: Eric Biggers Signed-off-by: J. Bruce Fields Signed-off-by: Greg Kroah-Hartman --- net/sunrpc/auth_gss/gss_krb5_crypto.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/net/sunrpc/auth_gss/gss_krb5_crypto.c b/net/sunrpc/auth_gss/gss_krb5_crypto.c index 12649c9fedab..8654494b4d0a 100644 --- a/net/sunrpc/auth_gss/gss_krb5_crypto.c +++ b/net/sunrpc/auth_gss/gss_krb5_crypto.c @@ -237,9 +237,6 @@ make_checksum_hmac_md5(struct krb5_ctx *kctx, char *header, int hdrlen, ahash_request_set_callback(req, CRYPTO_TFM_REQ_MAY_SLEEP, NULL, NULL); - err = crypto_ahash_init(req); - if (err) - goto out; err = crypto_ahash_setkey(hmac_md5, cksumkey, kctx->gk5e->keylength); if (err) goto out; -- GitLab From f9e66750d4bd0ea7b0fc3782387cb8373e7685eb Mon Sep 17 00:00:00 2001 From: Yunlong Song Date: Mon, 29 Jan 2018 11:37:45 +0800 Subject: [PATCH 0534/1635] f2fs: fix heap mode to reset it back commit b94929d975c8423defc9aededb0f499ff936b509 upstream. Commit 7a20b8a61eff81bdb7097a578752a74860e9d142 ("f2fs: allocate node and hot data in the beginning of partition") introduces another mount option, heap, to reset it back. But it does not do anything for heap mode, so fix it. Cc: stable@vger.kernel.org Signed-off-by: Yunlong Song Reviewed-by: Chao Yu Signed-off-by: Jaegeuk Kim Signed-off-by: Greg Kroah-Hartman --- fs/f2fs/gc.c | 5 +++-- fs/f2fs/segment.c | 3 ++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/fs/f2fs/gc.c b/fs/f2fs/gc.c index bfe6a8ccc3a0..d5021ba69e7a 100644 --- a/fs/f2fs/gc.c +++ b/fs/f2fs/gc.c @@ -191,8 +191,9 @@ static void select_policy(struct f2fs_sb_info *sbi, int gc_type, if (gc_type != FG_GC && p->max_search > sbi->max_victim_search) p->max_search = sbi->max_victim_search; - /* let's select beginning hot/small space first */ - if (type == CURSEG_HOT_DATA || IS_NODESEG(type)) + /* let's select beginning hot/small space first in no_heap mode*/ + if (test_opt(sbi, NOHEAP) && + (type == CURSEG_HOT_DATA || IS_NODESEG(type))) p->offset = 0; else p->offset = SIT_I(sbi)->last_victim[p->gc_mode]; diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c index c695ff462ee6..271516db8939 100644 --- a/fs/f2fs/segment.c +++ b/fs/f2fs/segment.c @@ -1992,7 +1992,8 @@ static unsigned int __get_next_segno(struct f2fs_sb_info *sbi, int type) if (sbi->segs_per_sec != 1) return CURSEG_I(sbi, type)->segno; - if (type == CURSEG_HOT_DATA || IS_NODESEG(type)) + if (test_opt(sbi, NOHEAP) && + (type == CURSEG_HOT_DATA || IS_NODESEG(type))) return 0; if (SIT_I(sbi)->last_victim[ALLOC_NEXT]) -- GitLab From a333a284fff29db8e68acf14f39432be9c63eb1b Mon Sep 17 00:00:00 2001 From: Yury Norov Date: Thu, 5 Apr 2018 16:18:25 -0700 Subject: [PATCH 0535/1635] lib: fix stall in __bitmap_parselist() commit 8351760ff5b2042039554b4948ddabaac644a976 upstream. syzbot is catching stalls at __bitmap_parselist() (https://syzkaller.appspot.com/bug?id=ad7e0351fbc90535558514a71cd3edc11681997a). The trigger is unsigned long v = 0; bitmap_parselist("7:,", &v, BITS_PER_LONG); which results in hitting infinite loop at while (a <= b) { off = min(b - a + 1, used_size); bitmap_set(maskp, a, off); a += group_size; } due to used_size == group_size == 0. Link: http://lkml.kernel.org/r/20180404162647.15763-1-ynorov@caviumnetworks.com Fixes: 0a5ce0831d04382a ("lib/bitmap.c: make bitmap_parselist() thread-safe and much faster") Signed-off-by: Yury Norov Reported-by: Tetsuo Handa Reported-by: syzbot Cc: Noam Camus Cc: Rasmus Villemoes Cc: Matthew Wilcox Cc: Mauro Carvalho Chehab Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- lib/bitmap.c | 2 +- lib/test_bitmap.c | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/bitmap.c b/lib/bitmap.c index c82c61b66e16..2a9373ef4054 100644 --- a/lib/bitmap.c +++ b/lib/bitmap.c @@ -605,7 +605,7 @@ static int __bitmap_parselist(const char *buf, unsigned int buflen, /* if no digit is after '-', it's wrong*/ if (at_start && in_range) return -EINVAL; - if (!(a <= b) || !(used_size <= group_size)) + if (!(a <= b) || group_size == 0 || !(used_size <= group_size)) return -EINVAL; if (b >= nmaskbits) return -ERANGE; diff --git a/lib/test_bitmap.c b/lib/test_bitmap.c index aa1f2669bdd5..0ddf293cfac3 100644 --- a/lib/test_bitmap.c +++ b/lib/test_bitmap.c @@ -218,6 +218,10 @@ static const struct test_bitmap_parselist parselist_tests[] __initconst = { {-EINVAL, "-1", NULL, 8, 0}, {-EINVAL, "-0", NULL, 8, 0}, {-EINVAL, "10-1", NULL, 8, 0}, + {-EINVAL, "0-31:", NULL, 8, 0}, + {-EINVAL, "0-31:0", NULL, 8, 0}, + {-EINVAL, "0-31:0/0", NULL, 8, 0}, + {-EINVAL, "0-31:1/0", NULL, 8, 0}, {-EINVAL, "0-31:10/1", NULL, 8, 0}, }; -- GitLab From 5ee935daaaebc6e25e4ea7396b57adcd012af858 Mon Sep 17 00:00:00 2001 From: Ming Lei Date: Sun, 8 Apr 2018 17:48:08 +0800 Subject: [PATCH 0536/1635] blk-mq: don't keep offline CPUs mapped to hctx 0 commit bffa9909a6b48d8ca3398dec601bc9162a4020c4 upstream. From commit 4b855ad37194 ("blk-mq: Create hctx for each present CPU), blk-mq doesn't remap queue after CPU topo is changed, that said when some of these offline CPUs become online, they are still mapped to hctx 0, then hctx 0 may become the bottleneck of IO dispatch and completion. This patch sets up the mapping from the beginning, and aligns to queue mapping for PCI device (blk_mq_pci_map_queues()). Cc: Stefan Haberland Cc: Keith Busch Cc: stable@vger.kernel.org Fixes: 4b855ad37194 ("blk-mq: Create hctx for each present CPU) Tested-by: Christian Borntraeger Reviewed-by: Christoph Hellwig Reviewed-by: Sagi Grimberg Signed-off-by: Ming Lei Signed-off-by: Jens Axboe Signed-off-by: Greg Kroah-Hartman --- block/blk-mq-cpumap.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/block/blk-mq-cpumap.c b/block/blk-mq-cpumap.c index 9f8cffc8a701..3eb169f15842 100644 --- a/block/blk-mq-cpumap.c +++ b/block/blk-mq-cpumap.c @@ -16,11 +16,6 @@ static int cpu_to_queue_index(unsigned int nr_queues, const int cpu) { - /* - * Non present CPU will be mapped to queue index 0. - */ - if (!cpu_present(cpu)) - return 0; return cpu % nr_queues; } -- GitLab From 80f509d4919d5517b4b16c272df5d1cd39a8ea18 Mon Sep 17 00:00:00 2001 From: Amir Goldstein Date: Mon, 12 Mar 2018 10:30:41 -0400 Subject: [PATCH 0537/1635] ovl: fix lookup with middle layer opaque dir and absolute path redirects commit 3ec9b3fafcaf441cc4d46b9742cd6ec0c79f8df0 upstream. As of now if we encounter an opaque dir while looking for a dentry, we set d->last=true. This means that there is no need to look further in any of the lower layers. This works fine as long as there are no redirets or relative redircts. But what if there is an absolute redirect on the children dentry of opaque directory. We still need to continue to look into next lower layer. This patch fixes it. Here is an example to demonstrate the issue. Say you have following setup. upper: /redirect (redirect=/a/b/c) lower1: /a/[b]/c ([b] is opaque) (c has absolute redirect=/a/b/d/) lower0: /a/b/d/foo Now "redirect" dir should merge with lower1:/a/b/c/ and lower0:/a/b/d. Note, despite the fact lower1:/a/[b] is opaque, we need to continue to look into lower0 because children c has an absolute redirect. Following is a reproducer. Watch me make foo disappear: $ mkdir lower middle upper work work2 merged $ mkdir lower/origin $ touch lower/origin/foo $ mount -t overlay none merged/ \ -olowerdir=lower,upperdir=middle,workdir=work2 $ mkdir merged/pure $ mv merged/origin merged/pure/redirect $ umount merged $ mount -t overlay none merged/ \ -olowerdir=middle:lower,upperdir=upper,workdir=work $ mv merged/pure/redirect merged/redirect Now you see foo inside a twice redirected merged dir: $ ls merged/redirect foo $ umount merged $ mount -t overlay none merged/ \ -olowerdir=middle:lower,upperdir=upper,workdir=work After mount cycle you don't see foo inside the same dir: $ ls merged/redirect During middle layer lookup, the opaqueness of middle/pure is left in the lookup state and then middle/pure/redirect is wrongly treated as opaque. Fixes: 02b69b284cd7 ("ovl: lookup redirects") Cc: #v4.10 Signed-off-by: Amir Goldstein Signed-off-by: Vivek Goyal Signed-off-by: Miklos Szeredi Signed-off-by: Greg Kroah-Hartman --- fs/overlayfs/namei.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/fs/overlayfs/namei.c b/fs/overlayfs/namei.c index 4bb7e4f53ea6..8a10506db993 100644 --- a/fs/overlayfs/namei.c +++ b/fs/overlayfs/namei.c @@ -56,6 +56,15 @@ static int ovl_check_redirect(struct dentry *dentry, struct ovl_lookup_data *d, if (s == next) goto invalid; } + /* + * One of the ancestor path elements in an absolute path + * lookup in ovl_lookup_layer() could have been opaque and + * that will stop further lookup in lower layers (d->stop=true) + * But we have found an absolute redirect in decendant path + * element and that should force continue lookup in lower + * layers (reset d->stop). + */ + d->stop = false; } else { if (strchr(buf, '/') != NULL) goto invalid; -- GitLab From 0319ce67b793e7fed0d828587e3edd8c6a80cc56 Mon Sep 17 00:00:00 2001 From: Simon Gaiser Date: Thu, 15 Mar 2018 03:43:20 +0100 Subject: [PATCH 0538/1635] xen: xenbus_dev_frontend: Fix XS_TRANSACTION_END handling commit 2a22ee6c3ab1d761bc9c04f1e4117edd55b82f09 upstream. Commit fd8aa9095a95 ("xen: optimize xenbus driver for multiple concurrent xenstore accesses") made a subtle change to the semantic of xenbus_dev_request_and_reply() and xenbus_transaction_end(). Before on an error response to XS_TRANSACTION_END xenbus_dev_request_and_reply() would not decrement the active transaction counter. But xenbus_transaction_end() has always counted the transaction as finished regardless of the response. The new behavior is that xenbus_dev_request_and_reply() and xenbus_transaction_end() will always count the transaction as finished regardless the response code (handled in xs_request_exit()). But xenbus_dev_frontend tries to end a transaction on closing of the device if the XS_TRANSACTION_END failed before. Trying to close the transaction twice corrupts the reference count. So fix this by also considering a transaction closed if we have sent XS_TRANSACTION_END once regardless of the return code. Cc: # 4.11 Fixes: fd8aa9095a95 ("xen: optimize xenbus driver for multiple concurrent xenstore accesses") Signed-off-by: Simon Gaiser Reviewed-by: Juergen Gross Signed-off-by: Boris Ostrovsky Signed-off-by: Greg Kroah-Hartman --- drivers/xen/xenbus/xenbus_dev_frontend.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/xen/xenbus/xenbus_dev_frontend.c b/drivers/xen/xenbus/xenbus_dev_frontend.c index f3b089b7c0b6..d2edbc79384a 100644 --- a/drivers/xen/xenbus/xenbus_dev_frontend.c +++ b/drivers/xen/xenbus/xenbus_dev_frontend.c @@ -365,7 +365,7 @@ void xenbus_dev_queue_reply(struct xb_req_data *req) if (WARN_ON(rc)) goto out; } - } else if (req->msg.type == XS_TRANSACTION_END) { + } else if (req->type == XS_TRANSACTION_END) { trans = xenbus_get_transaction(u, req->msg.tx_id); if (WARN_ON(!trans)) goto out; -- GitLab From 61534984904eaf3604626170dc718556210642a2 Mon Sep 17 00:00:00 2001 From: Mike Kravetz Date: Thu, 5 Apr 2018 16:18:21 -0700 Subject: [PATCH 0539/1635] hugetlbfs: fix bug in pgoff overflow checking commit 5df63c2a149ae65a9ec239e7c2af44efa6f79beb upstream. This is a fix for a regression in 32 bit kernels caused by an invalid check for pgoff overflow in hugetlbfs mmap setup. The check incorrectly specified that the size of a loff_t was the same as the size of a long. The regression prevents mapping hugetlbfs files at offsets greater than 4GB on 32 bit kernels. On 32 bit kernels conversion from a page based unsigned long can not overflow a loff_t byte offset. Therefore, skip this check if sizeof(unsigned long) != sizeof(loff_t). Link: http://lkml.kernel.org/r/20180330145402.5053-1-mike.kravetz@oracle.com Fixes: 63489f8e8211 ("hugetlbfs: check for pgoff value overflow") Reported-by: Dan Rue Signed-off-by: Mike Kravetz Tested-by: Anders Roxell Cc: Michal Hocko Cc: Yisheng Xie Cc: "Kirill A . Shutemov" Cc: Nic Losby Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- fs/hugetlbfs/inode.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c index 3b293d0d1785..2a6ed036d207 100644 --- a/fs/hugetlbfs/inode.c +++ b/fs/hugetlbfs/inode.c @@ -148,10 +148,14 @@ static int hugetlbfs_file_mmap(struct file *file, struct vm_area_struct *vma) /* * page based offset in vm_pgoff could be sufficiently large to - * overflow a (l)off_t when converted to byte offset. + * overflow a loff_t when converted to byte offset. This can + * only happen on architectures where sizeof(loff_t) == + * sizeof(unsigned long). So, only check in those instances. */ - if (vma->vm_pgoff & PGOFF_LOFFT_MAX) - return -EINVAL; + if (sizeof(unsigned long) == sizeof(loff_t)) { + if (vma->vm_pgoff & PGOFF_LOFFT_MAX) + return -EINVAL; + } /* must be huge page aligned */ if (vma->vm_pgoff & (~huge_page_mask(h) >> PAGE_SHIFT)) -- GitLab From 9a0a509839f31dc17f2ea788dc362c93589e077a Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Wed, 21 Mar 2018 17:19:02 -0400 Subject: [PATCH 0540/1635] nfsd: fix incorrect umasks commit 880a3a5325489a143269a8e172e7563ebf9897bc upstream. We're neglecting to clear the umask after it's set, which can cause a later unrelated rpc to (incorrectly) use the same umask if it happens to be processed by the same thread. There's a more subtle problem here too: An NFSv4 compound request is decoded all in one pass before any operations are executed. Currently we're setting current->fs->umask at the time we decode the compound. In theory a single compound could contain multiple creates each setting a umask. In that case we'd end up using whichever umask was passed in the *last* operation as the umask for all the creates, whether that was correct or not. So, we should just be saving the umask at decode time and waiting to set it until we actually process the corresponding operation. In practice it's unlikely any client would do multiple creates in a single compound. And even if it did they'd likely be from the same process (hence carry the same umask). So this is a little academic, but we should get it right anyway. Fixes: 47057abde515 (nfsd: add support for the umask attribute) Cc: stable@vger.kernel.org Reported-by: Lucash Stach Signed-off-by: J. Bruce Fields Signed-off-by: Greg Kroah-Hartman --- fs/nfsd/nfs4proc.c | 12 ++++++++++-- fs/nfsd/nfs4xdr.c | 8 +++----- fs/nfsd/xdr4.h | 2 ++ 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index 8ce60986fb75..5b6ff168d11a 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c @@ -32,6 +32,7 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#include #include #include #include @@ -252,11 +253,13 @@ do_open_lookup(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, stru * Note: create modes (UNCHECKED,GUARDED...) are the same * in NFSv4 as in v3 except EXCLUSIVE4_1. */ + current->fs->umask = open->op_umask; status = do_nfsd_create(rqstp, current_fh, open->op_fname.data, open->op_fname.len, &open->op_iattr, *resfh, open->op_createmode, (u32 *)open->op_verf.data, &open->op_truncate, &open->op_created); + current->fs->umask = 0; if (!status && open->op_label.len) nfsd4_security_inode_setsecctx(*resfh, &open->op_label, open->op_bmval); @@ -608,6 +611,7 @@ nfsd4_create(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, if (status) return status; + current->fs->umask = create->cr_umask; switch (create->cr_type) { case NF4LNK: status = nfsd_symlink(rqstp, &cstate->current_fh, @@ -616,20 +620,22 @@ nfsd4_create(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, break; case NF4BLK: + status = nfserr_inval; rdev = MKDEV(create->cr_specdata1, create->cr_specdata2); if (MAJOR(rdev) != create->cr_specdata1 || MINOR(rdev) != create->cr_specdata2) - return nfserr_inval; + goto out_umask; status = nfsd_create(rqstp, &cstate->current_fh, create->cr_name, create->cr_namelen, &create->cr_iattr, S_IFBLK, rdev, &resfh); break; case NF4CHR: + status = nfserr_inval; rdev = MKDEV(create->cr_specdata1, create->cr_specdata2); if (MAJOR(rdev) != create->cr_specdata1 || MINOR(rdev) != create->cr_specdata2) - return nfserr_inval; + goto out_umask; status = nfsd_create(rqstp, &cstate->current_fh, create->cr_name, create->cr_namelen, &create->cr_iattr,S_IFCHR, rdev, &resfh); @@ -673,6 +679,8 @@ nfsd4_create(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, fh_dup2(&cstate->current_fh, &resfh); out: fh_put(&resfh); +out_umask: + current->fs->umask = 0; return status; } diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 2c61c6b8ae09..df2b8849a63b 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -33,7 +33,6 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include #include #include #include @@ -683,7 +682,7 @@ nfsd4_decode_create(struct nfsd4_compoundargs *argp, struct nfsd4_create *create status = nfsd4_decode_fattr(argp, create->cr_bmval, &create->cr_iattr, &create->cr_acl, &create->cr_label, - ¤t->fs->umask); + &create->cr_umask); if (status) goto out; @@ -928,7 +927,6 @@ nfsd4_decode_open(struct nfsd4_compoundargs *argp, struct nfsd4_open *open) case NFS4_OPEN_NOCREATE: break; case NFS4_OPEN_CREATE: - current->fs->umask = 0; READ_BUF(4); open->op_createmode = be32_to_cpup(p++); switch (open->op_createmode) { @@ -936,7 +934,7 @@ nfsd4_decode_open(struct nfsd4_compoundargs *argp, struct nfsd4_open *open) case NFS4_CREATE_GUARDED: status = nfsd4_decode_fattr(argp, open->op_bmval, &open->op_iattr, &open->op_acl, &open->op_label, - ¤t->fs->umask); + &open->op_umask); if (status) goto out; break; @@ -951,7 +949,7 @@ nfsd4_decode_open(struct nfsd4_compoundargs *argp, struct nfsd4_open *open) COPYMEM(open->op_verf.data, NFS4_VERIFIER_SIZE); status = nfsd4_decode_fattr(argp, open->op_bmval, &open->op_iattr, &open->op_acl, &open->op_label, - ¤t->fs->umask); + &open->op_umask); if (status) goto out; break; diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h index 1e4edbf70052..aa4375eac475 100644 --- a/fs/nfsd/xdr4.h +++ b/fs/nfsd/xdr4.h @@ -118,6 +118,7 @@ struct nfsd4_create { } u; u32 cr_bmval[3]; /* request */ struct iattr cr_iattr; /* request */ + int cr_umask; /* request */ struct nfsd4_change_info cr_cinfo; /* response */ struct nfs4_acl *cr_acl; struct xdr_netobj cr_label; @@ -228,6 +229,7 @@ struct nfsd4_open { u32 op_why_no_deleg; /* response - DELEG_NONE_EXT only */ u32 op_create; /* request */ u32 op_createmode; /* request */ + int op_umask; /* request */ u32 op_bmval[3]; /* request */ struct iattr op_iattr; /* UNCHECKED4, GUARDED4, EXCLUSIVE4_1 */ nfs4_verifier op_verf __attribute__((aligned(32))); -- GitLab From 672f07d8274ba5978be693710efd55f230777193 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 19 Apr 2018 08:56:21 +0200 Subject: [PATCH 0541/1635] Linux 4.14.35 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index a6906dfb112e..995666d5e57b 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 VERSION = 4 PATCHLEVEL = 14 -SUBLEVEL = 34 +SUBLEVEL = 35 EXTRAVERSION = NAME = Petit Gorille -- GitLab From 687d4ad9f657a89a442b37412b137be0aae734cd Mon Sep 17 00:00:00 2001 From: Lina Iyer Date: Tue, 28 Nov 2017 10:13:12 -0700 Subject: [PATCH 0542/1635] drivers: cpuidle: lpm-levels: Do not set affinity level for 0 mode id A PSCI ID of zero doesn't require any setting from the firmware. In this case, incrementing the affinity level would be incorrect, especially for a single core system where the CPU and Cluster states are linearized. The Sleep driver in the kernel needs to different between CPU/Cluster states to send System votes through before sleep. Do not increment affinity level when PSCI ID is zero. Change-Id: I4739ee1ac893d30e5ab5f24b1c388ef58acda06a Signed-off-by: Mahesh Sivasubramanian Signed-off-by: Lina Iyer --- drivers/cpuidle/lpm-levels.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/cpuidle/lpm-levels.c b/drivers/cpuidle/lpm-levels.c index 054d99c741ef..cbda188a8149 100644 --- a/drivers/cpuidle/lpm-levels.c +++ b/drivers/cpuidle/lpm-levels.c @@ -1244,7 +1244,6 @@ int get_cluster_id(struct lpm_cluster *cluster, int *aff_lvl) state_id |= (level->psci_id & cluster->psci_mode_mask) << cluster->psci_mode_shift; - (*aff_lvl)++; /* * We may have updated the broadcast timers, update @@ -1252,6 +1251,8 @@ int get_cluster_id(struct lpm_cluster *cluster, int *aff_lvl) */ if (level->notify_rpm) system_sleep_update_wakeup(); + if (level->psci_id) + (*aff_lvl)++; } unlock_and_return: spin_unlock(&cluster->sync_lock); -- GitLab From 8b6b8fd39aa0ddb78abc4d9aebe7200ea7cd1e8a Mon Sep 17 00:00:00 2001 From: "Raju P.L.S.S.S.N" Date: Thu, 7 Dec 2017 00:09:01 +0530 Subject: [PATCH 0543/1635] cpuidle: lpm-levels: Add system_pm ops for system level LPMs Add system_pm ops that are used by LPM driver to configure sleep and wake votes as well as next wake up time. LPM driver uses them during system level LPMs. Change-Id: I72b89aeb3408b89a73d1f0c821649f4f998ab85c Signed-off-by: Raju P.L.S.S.S.N --- drivers/cpuidle/lpm-levels.c | 107 +++++++++++++++++++--------------- drivers/cpuidle/lpm-levels.h | 2 - drivers/soc/qcom/system_pm.c | 28 +++++---- include/soc/qcom/lpm_levels.h | 30 ++++++++++ include/soc/qcom/system_pm.h | 39 ------------- 5 files changed, 104 insertions(+), 102 deletions(-) create mode 100644 include/soc/qcom/lpm_levels.h delete mode 100644 include/soc/qcom/system_pm.h diff --git a/drivers/cpuidle/lpm-levels.c b/drivers/cpuidle/lpm-levels.c index cbda188a8149..30a78e6cf1fb 100644 --- a/drivers/cpuidle/lpm-levels.c +++ b/drivers/cpuidle/lpm-levels.c @@ -39,8 +39,8 @@ #include #include #include +#include #include -#include #include #include #include @@ -79,6 +79,9 @@ struct lpm_debug { uint32_t arg4; }; +static struct system_pm_ops *sys_pm_ops; + + struct lpm_cluster *lpm_root_node; #define MAXSAMPLES 5 @@ -123,11 +126,6 @@ static void cluster_prepare(struct lpm_cluster *cluster, const struct cpumask *cpu, int child_idx, bool from_idle, int64_t time); -static int msm_pm_sleep_time_override; -module_param_named(sleep_time_override, - msm_pm_sleep_time_override, int, 0664); -static uint64_t suspend_wake_time; - static bool print_parsed_dt; module_param_named(print_parsed_dt, print_parsed_dt, bool, 0664); @@ -145,20 +143,15 @@ s32 msm_cpuidle_get_deep_idle_latency(void) } EXPORT_SYMBOL(msm_cpuidle_get_deep_idle_latency); -void lpm_suspend_wake_time(uint64_t wakeup_time) +uint32_t register_system_pm_ops(struct system_pm_ops *pm_ops) { - if (wakeup_time <= 0) { - suspend_wake_time = msm_pm_sleep_time_override; - return; - } + if (sys_pm_ops) + return -EUSERS; - if (msm_pm_sleep_time_override && - (msm_pm_sleep_time_override < wakeup_time)) - suspend_wake_time = msm_pm_sleep_time_override; - else - suspend_wake_time = wakeup_time; + sys_pm_ops = pm_ops; + + return 0; } -EXPORT_SYMBOL(lpm_suspend_wake_time); static uint32_t least_cluster_latency(struct lpm_cluster *cluster, struct latency_level *lat_level) @@ -703,28 +696,40 @@ static int cpu_power_select(struct cpuidle_device *dev, return best_level; } +static unsigned int get_next_online_cpu(bool from_idle) +{ + unsigned int cpu; + ktime_t next_event; + unsigned int next_cpu = raw_smp_processor_id(); + + if (!from_idle) + return next_cpu; + next_event = KTIME_MAX; + for_each_online_cpu(cpu) { + ktime_t *next_event_c; + + next_event_c = get_next_event_cpu(cpu); + if (*next_event_c < next_event) { + next_event = *next_event_c; + next_cpu = cpu; + } + } + return next_cpu; +} + static uint64_t get_cluster_sleep_time(struct lpm_cluster *cluster, - struct cpumask *mask, bool from_idle, uint32_t *pred_time) + bool from_idle, uint32_t *pred_time) { int cpu; - int next_cpu = raw_smp_processor_id(); ktime_t next_event; struct cpumask online_cpus_in_cluster; struct lpm_history *history; int64_t prediction = LONG_MAX; - next_event = KTIME_MAX; - if (!suspend_wake_time) - suspend_wake_time = msm_pm_sleep_time_override; - if (!from_idle) { - if (mask) - cpumask_copy(mask, cpumask_of(raw_smp_processor_id())); - if (!suspend_wake_time) - return ~0ULL; - else - return USEC_PER_SEC * suspend_wake_time; - } + if (!from_idle) + return ~0ULL; + next_event = KTIME_MAX; cpumask_and(&online_cpus_in_cluster, &cluster->num_children_in_sync, cpu_online_mask); @@ -732,10 +737,8 @@ static uint64_t get_cluster_sleep_time(struct lpm_cluster *cluster, ktime_t *next_event_c; next_event_c = get_next_event_cpu(cpu); - if (*next_event_c < next_event) { + if (*next_event_c < next_event) next_event = *next_event_c; - next_cpu = cpu; - } if (from_idle && lpm_prediction) { history = &per_cpu(hist, cpu); @@ -744,9 +747,6 @@ static uint64_t get_cluster_sleep_time(struct lpm_cluster *cluster, } } - if (mask) - cpumask_copy(mask, cpumask_of(next_cpu)); - if (from_idle && lpm_prediction) { if (prediction > ktime_to_us(ktime_get())) *pred_time = prediction - ktime_to_us(ktime_get()); @@ -929,7 +929,7 @@ static int cluster_select(struct lpm_cluster *cluster, bool from_idle, if (!cluster) return -EINVAL; - sleep_us = (uint32_t)get_cluster_sleep_time(cluster, NULL, + sleep_us = (uint32_t)get_cluster_sleep_time(cluster, from_idle, &cpupred_us); if (from_idle) { @@ -980,8 +980,12 @@ static int cluster_select(struct lpm_cluster *cluster, bool from_idle, if (suspend_in_progress && from_idle && level->notify_rpm) continue; - if (level->notify_rpm && !system_sleep_allowed()) - continue; + if (level->notify_rpm) { + if (!(sys_pm_ops && sys_pm_ops->sleep_allowed)) + continue; + if (!sys_pm_ops->sleep_allowed()) + continue; + } best_level = i; @@ -1015,6 +1019,11 @@ static int cluster_configure(struct lpm_cluster *cluster, int idx, bool from_idle, int predicted) { struct lpm_cluster_level *level = &cluster->levels[idx]; + struct cpumask online_cpus, cpumask; + unsigned int cpu; + + cpumask_and(&online_cpus, &cluster->num_children_in_sync, + cpu_online_mask); if (!cpumask_equal(&cluster->num_children_in_sync, &cluster->child_cpus) || is_IPI_pending(&cluster->num_children_in_sync)) { @@ -1036,10 +1045,13 @@ static int cluster_configure(struct lpm_cluster *cluster, int idx, } if (level->notify_rpm) { + cpu = get_next_online_cpu(from_idle); + cpumask_copy(&cpumask, cpumask_of(cpu)); clear_predict_history(); clear_cl_predict_history(); - if (system_sleep_enter()) - return -EBUSY; + if (sys_pm_ops && sys_pm_ops->enter) + if ((sys_pm_ops->enter(&cpumask))) + return -EBUSY; } /* Notify cluster enter event after successfully config completion */ cluster_notify(cluster, level, true); @@ -1170,7 +1182,8 @@ static void cluster_unprepare(struct lpm_cluster *cluster, level = &cluster->levels[cluster->last_level]; if (level->notify_rpm) - system_sleep_exit(); + if (sys_pm_ops && sys_pm_ops->exit) + sys_pm_ops->exit(); update_debug_pc_event(CLUSTER_EXIT, cluster->last_level, cluster->num_children_in_sync.bits[0], @@ -1223,7 +1236,8 @@ static inline void cpu_unprepare(struct lpm_cpu *cpu, int cpu_index, cpu_pm_exit(); } -int get_cluster_id(struct lpm_cluster *cluster, int *aff_lvl) +static int get_cluster_id(struct lpm_cluster *cluster, int *aff_lvl, + bool from_idle) { int state_id = 0; @@ -1236,7 +1250,7 @@ int get_cluster_id(struct lpm_cluster *cluster, int *aff_lvl) &cluster->child_cpus)) goto unlock_and_return; - state_id |= get_cluster_id(cluster->parent, aff_lvl); + state_id |= get_cluster_id(cluster->parent, aff_lvl, from_idle); if (cluster->last_level != cluster->default_level) { struct lpm_cluster_level *level @@ -1250,7 +1264,8 @@ int get_cluster_id(struct lpm_cluster *cluster, int *aff_lvl) * the wakeup value by reading the bc timer directly. */ if (level->notify_rpm) - system_sleep_update_wakeup(); + if (sys_pm_ops && sys_pm_ops->update_wakeup) + sys_pm_ops->update_wakeup(from_idle); if (level->psci_id) (*aff_lvl)++; } @@ -1279,7 +1294,7 @@ static bool psci_enter_sleep(struct lpm_cpu *cpu, int idx, bool from_idle) return success; } - state_id = get_cluster_id(cpu->parent, &affinity_level); + state_id = get_cluster_id(cpu->parent, &affinity_level, from_idle); power_state = PSCI_POWER_STATE(cpu->levels[idx].is_reset); affinity_level = PSCI_AFFINITY_LEVEL(affinity_level); state_id |= power_state | affinity_level | cpu->levels[idx].psci_id; diff --git a/drivers/cpuidle/lpm-levels.h b/drivers/cpuidle/lpm-levels.h index 67aaa91db1d7..8c66bd73402c 100644 --- a/drivers/cpuidle/lpm-levels.h +++ b/drivers/cpuidle/lpm-levels.h @@ -108,8 +108,6 @@ struct lpm_cluster { struct hrtimer histtimer; }; -void lpm_suspend_wake_time(uint64_t wakeup_time); - struct lpm_cluster *lpm_of_parse_cluster(struct platform_device *pdev); void free_cluster_node(struct lpm_cluster *cluster); void cluster_dt_walkthrough(struct lpm_cluster *cluster); diff --git a/drivers/soc/qcom/system_pm.c b/drivers/soc/qcom/system_pm.c index 6164b445f1f4..0921f18f2f39 100644 --- a/drivers/soc/qcom/system_pm.c +++ b/drivers/soc/qcom/system_pm.c @@ -13,11 +13,9 @@ #include #include - #include -#include - #include +#include #define PDC_TIME_VALID_SHIFT 31 #define PDC_TIME_UPPER_MASK 0xFFFFFF @@ -35,7 +33,7 @@ static int setup_wakeup(uint32_t lo, uint32_t hi) return rpmh_write_control(rpmh_client, cmd, ARRAY_SIZE(cmd)); } -int system_sleep_update_wakeup(void) +static int system_sleep_update_wakeup(bool from_idle) { uint32_t lo = ~0U, hi = ~0U; @@ -44,16 +42,14 @@ int system_sleep_update_wakeup(void) return setup_wakeup(lo, hi); } -EXPORT_SYMBOL(system_sleep_update_wakeup); /** * system_sleep_allowed() - Returns if its okay to enter system low power modes */ -bool system_sleep_allowed(void) +static bool system_sleep_allowed(void) { return (rpmh_ctrlr_idle(rpmh_client) == 0); } -EXPORT_SYMBOL(system_sleep_allowed); /** * system_sleep_enter() - Activties done when entering system low power modes @@ -61,22 +57,24 @@ EXPORT_SYMBOL(system_sleep_allowed); * Returns 0 for success or error values from writing the sleep/wake values to * the hardware block. */ -int system_sleep_enter(void) +static int system_sleep_enter(struct cpumask *mask) { - if (IS_ERR_OR_NULL(rpmh_client)) - return -EFAULT; - return rpmh_flush(rpmh_client); } -EXPORT_SYMBOL(system_sleep_enter); /** * system_sleep_exit() - Activities done when exiting system low power modes */ -void system_sleep_exit(void) +static void system_sleep_exit(void) { } -EXPORT_SYMBOL(system_sleep_exit); + +static struct system_pm_ops pm_ops = { + .enter = system_sleep_enter, + .exit = system_sleep_exit, + .update_wakeup = system_sleep_update_wakeup, + .sleep_allowed = system_sleep_allowed, +}; static int sys_pm_probe(struct platform_device *pdev) { @@ -84,7 +82,7 @@ static int sys_pm_probe(struct platform_device *pdev) if (IS_ERR_OR_NULL(rpmh_client)) return PTR_ERR(rpmh_client); - return 0; + return register_system_pm_ops(&pm_ops); } static const struct of_device_id sys_pm_drv_match[] = { diff --git a/include/soc/qcom/lpm_levels.h b/include/soc/qcom/lpm_levels.h new file mode 100644 index 000000000000..f838665d2fdc --- /dev/null +++ b/include/soc/qcom/lpm_levels.h @@ -0,0 +1,30 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +#ifndef __SOC_QCOM_LPM_LEVEL_H__ +#define __SOC_QCOM_LPM_LEVEL_H__ + +struct system_pm_ops { + int (*enter)(struct cpumask *mask); + void (*exit)(void); + int (*update_wakeup)(bool); + bool (*sleep_allowed)(void); +}; + +#ifdef CONFIG_MSM_PM +uint32_t register_system_pm_ops(struct system_pm_ops *pm_ops); +#else +static inline uint32_t register_system_pm_ops(struct system_pm_ops *pm_ops) +{ return -ENODEV; } +#endif + +#endif diff --git a/include/soc/qcom/system_pm.h b/include/soc/qcom/system_pm.h deleted file mode 100644 index 028c729718f4..000000000000 --- a/include/soc/qcom/system_pm.h +++ /dev/null @@ -1,39 +0,0 @@ -/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ -#ifndef __SOC_QCOM_SYS_PM_H__ -#define __SOC_QCOM_SYS_PM_H__ - -#ifdef CONFIG_QTI_SYSTEM_PM -int system_sleep_enter(void); - -void system_sleep_exit(void); - -bool system_sleep_allowed(void); - -int system_sleep_update_wakeup(void); -#else -static inline int system_sleep_enter(void) -{ return -ENODEV; } - -static inline void system_sleep_exit(void) -{ } - -static inline bool system_sleep_allowed(void) -{ return false; } - -static inline int system_sleep_update_wakeup(void) -{ return -ENODEV; } - -#endif /* CONFIG_QTI_SYSTEM_PM */ - -#endif /* __SOC_QCOM_SYS_PM_H__ */ -- GitLab From 2a97a3e2530196431c640a2cde77eb6b1b59c0c9 Mon Sep 17 00:00:00 2001 From: Maulik Shah Date: Fri, 2 Mar 2018 17:17:01 +0530 Subject: [PATCH 0544/1635] cpuidle: lpm-levels: Correctly init 32bit ops for SMP systems SMP systems needs to pass each cpu number to init cpuidle ops. Correctly pass cpu number to init function. Change-Id: I0aac47abe155cbd9f25c8c020d641aea4f2c122c Signed-off-by: Maulik Shah --- drivers/cpuidle/lpm-levels.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/cpuidle/lpm-levels.c b/drivers/cpuidle/lpm-levels.c index 30a78e6cf1fb..4a3b8c986462 100644 --- a/drivers/cpuidle/lpm-levels.c +++ b/drivers/cpuidle/lpm-levels.c @@ -1739,7 +1739,7 @@ static int __init lpm_levels_module_init(void) int cpu; for_each_possible_cpu(cpu) { - rc = arm_cpuidle_init(smp_processor_id()); + rc = arm_cpuidle_init(cpu); if (rc) { pr_err("CPU%d ARM CPUidle init failed (%d)\n", cpu, rc); return rc; -- GitLab From 0cc9c4148ec2ec3d1705fe9156a5343d9f1b4eae Mon Sep 17 00:00:00 2001 From: Vijayavardhan Vennapusa Date: Mon, 19 Mar 2018 18:43:50 +0530 Subject: [PATCH 0545/1635] dwc3-msm: Add check before calling stop host in restart callback Display driver calls usb_pd_release_ss_lanes() callback to use SS lines for higher bandwidth use cases. This results in USB PD driver notify dwc3_msm driver to stop host mode and restart it in highspeed mode. If DP adaptor is disconnected while usb_pd_release_ss_lanes() in progress, then there is a chance that stop host mode gets called again after disconnect handling and results in Use after free scenario. Hence fix it by checking whether host mode is active before calling stop host mode. Change-Id: I2337f451b2f74ebb5178d40078ef6b2166e8f64c Signed-off-by: Vijayavardhan Vennapusa --- drivers/usb/dwc3/dwc3-msm.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c index 6fc3ff2d0755..e3c6fcdea8c5 100644 --- a/drivers/usb/dwc3/dwc3-msm.c +++ b/drivers/usb/dwc3/dwc3-msm.c @@ -3847,6 +3847,10 @@ static int dwc3_restart_usb_host_mode(struct notifier_block *nb, dbg_event(0xFF, "fw_restarthost", 0); flush_delayed_work(&mdwc->sm_work); + + if (!mdwc->in_host_mode) + goto err; + dbg_event(0xFF, "stop_host_mode", dwc->maximum_speed); ret = dwc3_otg_start_host(mdwc, 0); if (ret) -- GitLab From 80832034f422f1ead6ee841934364d37aa91561c Mon Sep 17 00:00:00 2001 From: Kyle Piefer Date: Fri, 6 Apr 2018 16:50:31 -0700 Subject: [PATCH 0546/1635] ARM: dts: msm: Remove GMU OPP table for SM8150 The clock driver will register the OPP table for the GPU device. Remove it from our DTSI to avoid duplicates. Change-Id: I6ce0aef1e63803bdfc34f7bfa2b142b791d5aa84 Signed-off-by: Kyle Piefer --- arch/arm64/boot/dts/qcom/sm8150-gpu.dtsi | 22 ---------------------- 1 file changed, 22 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sm8150-gpu.dtsi b/arch/arm64/boot/dts/qcom/sm8150-gpu.dtsi index 20c76ba6c8fb..e72892ad78fe 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-gpu.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-gpu.dtsi @@ -289,20 +289,6 @@ }; }; - gmu_opp_table: gmu-opp-table { - compatible = "operating-points-v2"; - - opp-200000000 { - opp-hz = /bits/ 64 <200000000>; - opp-microvolt = ; - }; - - opp-500000000 { - opp-hz = /bits/ 64 <500000000>; - opp-microvolt = ; - }; - }; - gmu: qcom,gmu@0x2C6A000 { label = "kgsl-gmu"; compatible = "qcom,gpu-gmu"; @@ -324,9 +310,6 @@ vddcx-supply = <&gpu_cx_gdsc>; vdd-supply = <&gpu_gx_gdsc>; - /* GMU OPP data */ - operating-points-v2 = <&gmu_opp_table>; - clocks = <&clock_gpucc GPU_CC_CX_GMU_CLK>, <&clock_gpucc GPU_CC_CXO_CLK>, <&clock_gcc GCC_DDRSS_GPU_AXI_CLK>, @@ -352,11 +335,6 @@ reg = <1>; qcom,gmu-freq = <200000000>; }; - - qcom,gmu-pwrlevel@2 { - reg = <2>; - qcom,gmu-freq = <500000000>; - }; }; gmu_user: gmu_user { -- GitLab From 986dc35b2aa278504ba330f49166906f51dac8f2 Mon Sep 17 00:00:00 2001 From: Liam Mark Date: Wed, 4 Apr 2018 11:29:45 -0700 Subject: [PATCH 0547/1635] staging: android: ion: Track total memory allocations per heap Add support to track the total amount of memory allocated by each ION heap. This information makes it easier to identify if an ION client is responsible for a memory leak. Change-Id: I44638316b6462d28ec182f58b3b3e5cc99716f33 Signed-off-by: Liam Mark --- drivers/staging/android/ion/ion.c | 2 ++ drivers/staging/android/ion/ion.h | 1 + 2 files changed, 3 insertions(+) diff --git a/drivers/staging/android/ion/ion.c b/drivers/staging/android/ion/ion.c index 04645dfebcab..f71d430d169e 100644 --- a/drivers/staging/android/ion/ion.c +++ b/drivers/staging/android/ion/ion.c @@ -168,6 +168,7 @@ static struct ion_buffer *ion_buffer_create(struct ion_heap *heap, mutex_lock(&dev->buffer_lock); ion_buffer_add(dev, buffer); mutex_unlock(&dev->buffer_lock); + atomic_long_add(len, &heap->total_allocated); return buffer; err1: @@ -196,6 +197,7 @@ static void _ion_buffer_destroy(struct ion_buffer *buffer) rb_erase(&buffer->node, &dev->buffers); mutex_unlock(&dev->buffer_lock); + atomic_long_sub(buffer->size, &buffer->heap->total_allocated); if (heap->flags & ION_HEAP_FLAG_DEFER_FREE) ion_heap_freelist_add(heap, buffer); else diff --git a/drivers/staging/android/ion/ion.h b/drivers/staging/android/ion/ion.h index aa099fdcaa25..c8f84887bb6b 100644 --- a/drivers/staging/android/ion/ion.h +++ b/drivers/staging/android/ion/ion.h @@ -240,6 +240,7 @@ struct ion_heap { spinlock_t free_lock; wait_queue_head_t waitqueue; struct task_struct *task; + atomic_long_t total_allocated; int (*debug_show)(struct ion_heap *heap, struct seq_file *, void *); }; -- GitLab From ec0b11a3cb7184b8691d7c7d6cb398d8f484200f Mon Sep 17 00:00:00 2001 From: Steve Cohen Date: Tue, 3 Apr 2018 13:14:04 -0700 Subject: [PATCH 0548/1635] drm/msm/sde: make sure all locks are acquired during lastclose Ensure that we actually acquired all locks before proceeding to disable modes and revert custom properties back to their default values. This patch adds the typical grab locks and backoff dance to avoid lock contention. Change-Id: Iaaea9fd75a79be8978d048f93d61ea0f7d4f8a4d Signed-off-by: Steve Cohen --- drivers/gpu/drm/msm/msm_drv.c | 34 +++++++++++++++++++++++++--------- 1 file changed, 25 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c index ec0e0c36cea6..9aef53dc65ea 100644 --- a/drivers/gpu/drm/msm/msm_drv.c +++ b/drivers/gpu/drm/msm/msm_drv.c @@ -990,7 +990,7 @@ static void msm_lastclose(struct drm_device *dev) struct msm_drm_private *priv = dev->dev_private; struct msm_kms *kms = priv->kms; struct drm_modeset_acquire_ctx ctx; - int i; + int i, rc; /* * clean up vblank disable immediately as this is the last close. @@ -1008,15 +1008,31 @@ static void msm_lastclose(struct drm_device *dev) if (priv->fbdev) { drm_fb_helper_restore_fbdev_mode_unlocked(priv->fbdev); - } else { - drm_modeset_acquire_init(&ctx, 0); - drm_modeset_lock_all_ctx(dev, &ctx); - msm_disable_all_modes(dev, &ctx); - if (kms && kms->funcs && kms->funcs->lastclose) - kms->funcs->lastclose(kms, &ctx); - drm_modeset_drop_locks(&ctx); - drm_modeset_acquire_fini(&ctx); + return; + } + + drm_modeset_acquire_init(&ctx, 0); +retry: + rc = drm_modeset_lock_all_ctx(dev, &ctx); + if (rc) + goto fail; + + rc = msm_disable_all_modes(dev, &ctx); + if (rc) + goto fail; + + if (kms && kms->funcs && kms->funcs->lastclose) + kms->funcs->lastclose(kms, &ctx); + +fail: + if (rc == -EDEADLK) { + drm_modeset_backoff(&ctx); + goto retry; + } else if (rc) { + pr_err("last close failed: %d\n", rc); } + drm_modeset_drop_locks(&ctx); + drm_modeset_acquire_fini(&ctx); } static irqreturn_t msm_irq(int irq, void *arg) -- GitLab From 91f591cf84728260393fb10e7e578d0de602d291 Mon Sep 17 00:00:00 2001 From: Zhen Kong Date: Thu, 19 Apr 2018 11:58:09 -0700 Subject: [PATCH 0549/1635] defconfig: sm8150: Enable EXT4 encryption Enable ext4 encryption in order to support ext4 encryption for enabling software FBE. Change-Id: I83e4038a1e12a7979cacae1b586d30371cbe5322 Signed-off-by: Zhen Kong --- arch/arm64/configs/sm8150-perf_defconfig | 1 + arch/arm64/configs/sm8150_defconfig | 1 + 2 files changed, 2 insertions(+) diff --git a/arch/arm64/configs/sm8150-perf_defconfig b/arch/arm64/configs/sm8150-perf_defconfig index c7646559c8d1..261d58f7a969 100644 --- a/arch/arm64/configs/sm8150-perf_defconfig +++ b/arch/arm64/configs/sm8150-perf_defconfig @@ -553,6 +553,7 @@ CONFIG_EXT2_FS=y CONFIG_EXT2_FS_XATTR=y CONFIG_EXT3_FS=y CONFIG_EXT4_FS_SECURITY=y +CONFIG_EXT4_ENCRYPTION=y CONFIG_QUOTA=y CONFIG_QUOTA_NETLINK_INTERFACE=y CONFIG_FUSE_FS=y diff --git a/arch/arm64/configs/sm8150_defconfig b/arch/arm64/configs/sm8150_defconfig index 1c28159b7668..f46b7489e406 100644 --- a/arch/arm64/configs/sm8150_defconfig +++ b/arch/arm64/configs/sm8150_defconfig @@ -578,6 +578,7 @@ CONFIG_EXT2_FS=y CONFIG_EXT2_FS_XATTR=y CONFIG_EXT3_FS=y CONFIG_EXT4_FS_SECURITY=y +CONFIG_EXT4_ENCRYPTION=y CONFIG_QUOTA=y CONFIG_QUOTA_NETLINK_INTERFACE=y CONFIG_FUSE_FS=y -- GitLab From f789bf2cc81a4ae9d2481fbe13f90e6cffa2426d Mon Sep 17 00:00:00 2001 From: Subash Abhinov Kasiviswanathan Date: Tue, 17 Apr 2018 15:50:50 -0600 Subject: [PATCH 0550/1635] net: qualcomm: rmnet: Fix warning seen with fill_info When the last rmnet device attached to a real device is removed, the real device is unregistered from rmnet. As a result, the real device lookup fails resulting in a warning when the fill_info handler is called as part of the rmnet device unregistration. Fix this by returning the rmnet flags as 0 when no real device is present. WARNING: CPU: 0 PID: 1779 at net/core/rtnetlink.c:3254 rtmsg_ifinfo_build_skb+0xca/0x10d Modules linked in: CPU: 0 PID: 1779 Comm: ip Not tainted 4.16.0-11872-g7ce2367 #1 Stack: 7fe655f0 60371ea3 00000000 00000000 60282bc6 6006b116 7fe65600 60371ee8 7fe65660 6003a68c 00000000 900000000 Call Trace: [<6006b116>] ? printk+0x0/0x94 [<6001f375>] show_stack+0xfe/0x158 [<60371ea3>] ? dump_stack_print_info+0xe8/0xf1 [<60282bc6>] ? rtmsg_ifinfo_build_skb+0xca/0x10d [<6006b116>] ? printk+0x0/0x94 [<60371ee8>] dump_stack+0x2a/0x2c [<6003a68c>] __warn+0x10e/0x13e [<6003a82c>] warn_slowpath_null+0x48/0x4f [<60282bc6>] rtmsg_ifinfo_build_skb+0xca/0x10d [<60282c4d>] rtmsg_ifinfo_event.part.37+0x1e/0x43 [<60282c2f>] ? rtmsg_ifinfo_event.part.37+0x0/0x43 [<60282d03>] rtmsg_ifinfo+0x24/0x28 [<60264e86>] dev_close_many+0xba/0x119 [<60282cdf>] ? rtmsg_ifinfo+0x0/0x28 [<6027c225>] ? rtnl_is_locked+0x0/0x1c [<6026ca67>] rollback_registered_many+0x1ae/0x4ae [<600314be>] ? unblock_signals+0x0/0xae [<6026cdc0>] ? unregister_netdevice_queue+0x19/0xec [<6026ceec>] unregister_netdevice_many+0x21/0xa1 [<6027c765>] rtnl_delete_link+0x3e/0x4e [<60280ecb>] rtnl_dellink+0x262/0x29c [<6027c241>] ? rtnl_get_link+0x0/0x3e [<6027f867>] rtnetlink_rcv_msg+0x235/0x274 CRs-Fixed: 2156182 Change-Id: I47a3f313902f8d0ce34fb52d1dc1de52beb172ea Fixes: be81a85f5f87 ("net: qualcomm: rmnet: Implement fill_info") Signed-off-by: Subash Abhinov Kasiviswanathan --- drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c b/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c index 7c120b0e5126..1573e0b45a68 100644 --- a/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c +++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c @@ -348,15 +348,16 @@ static int rmnet_fill_info(struct sk_buff *skb, const struct net_device *dev) real_dev = priv->real_dev; - if (!rmnet_is_real_dev_registered(real_dev)) - return -ENODEV; - if (nla_put_u16(skb, IFLA_RMNET_MUX_ID, priv->mux_id)) goto nla_put_failure; - port = rmnet_get_port_rtnl(real_dev); + if (rmnet_is_real_dev_registered(real_dev)) { + port = rmnet_get_port_rtnl(real_dev); + f.flags = port->data_format; + } else { + f.flags = 0; + } - f.flags = port->data_format; f.mask = ~0; if (nla_put(skb, IFLA_RMNET_FLAGS, sizeof(f), &f)) -- GitLab From e8ebd9424b00a77bc29245fd910970affd0cd2ee Mon Sep 17 00:00:00 2001 From: Ajay Singh Parmar Date: Thu, 19 Apr 2018 12:19:21 -0700 Subject: [PATCH 0551/1635] platform: msm: Export register_codec ops API for audio Merge back Ic4010c204a12155437f6eb44dbbd66d56774fdba as this is needed for audio DLKM. CRs-Fixed: 2206904 Change-Id: Icbae30abf66d3893e0a74494f1a39e4603de0782 Signed-off-by: Ajay Singh Parmar --- drivers/platform/msm/msm_ext_display.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/platform/msm/msm_ext_display.c b/drivers/platform/msm/msm_ext_display.c index 077e3a65cda3..ad2b83991877 100644 --- a/drivers/platform/msm/msm_ext_display.c +++ b/drivers/platform/msm/msm_ext_display.c @@ -404,6 +404,7 @@ int msm_ext_disp_register_audio_codec(struct platform_device *pdev, return ret; } +EXPORT_SYMBOL(msm_ext_disp_register_audio_codec); int msm_ext_disp_select_audio_codec(struct platform_device *pdev, struct msm_ext_disp_codec_id *codec) -- GitLab From 3e306598f6c23a9fd337d5d3bbb5c7045f0b484a Mon Sep 17 00:00:00 2001 From: Subbaraman Narayanamurthy Date: Thu, 29 Mar 2018 13:33:53 -0700 Subject: [PATCH 0552/1635] power: qpnp-fg-gen4: add support for capacity learning and cycle counter Capacity learning and cycle counter algorithms are supported through fg-alg.c. Add the necessary initialization and callback functions to GEN4 FG driver to support those algorithms. Change-Id: If071bf02cc6ddcedbc7361c8a02f23bd1ca95b5c Signed-off-by: Subbaraman Narayanamurthy --- .../power/supply/qcom/qpnp-fg-gen4.txt | 49 +++ drivers/power/supply/qcom/Makefile | 2 +- drivers/power/supply/qcom/qpnp-fg-gen4.c | 335 +++++++++++++++++- 3 files changed, 378 insertions(+), 8 deletions(-) diff --git a/Documentation/devicetree/bindings/power/supply/qcom/qpnp-fg-gen4.txt b/Documentation/devicetree/bindings/power/supply/qcom/qpnp-fg-gen4.txt index 975d0ecb85c9..18568d3863eb 100644 --- a/Documentation/devicetree/bindings/power/supply/qcom/qpnp-fg-gen4.txt +++ b/Documentation/devicetree/bindings/power/supply/qcom/qpnp-fg-gen4.txt @@ -158,6 +158,55 @@ First Level Node - FG Gen4 device loaded earlier by bootloader doesn't match with the profile available in the device tree. +- qcom,cl-start-capacity + Usage: optional + Value type: + Definition: Battery SOC threshold to start the capacity learning. + If this is not specified, then the default value used + will be 15. Unit is in percentage. + +- qcom,cl-min-temp + Usage: optional + Value type: + Definition: Lower limit of battery temperature to start the capacity + learning. If this is not specified, then the default value + used will be 150 (15 C). Unit is in decidegC. + +- qcom,cl-max-temp + Usage: optional + Value type: + Definition: Upper limit of battery temperature to start the capacity + learning. If this is not specified, then the default value + used will be 500 (50 C). Unit is in decidegC. + +- qcom,cl-max-increment + Usage: optional + Value type: + Definition: Maximum capacity increment allowed per capacity learning + cycle. If this is not specified, then the default value + used will be 5 (0.5%). Unit is in decipercentage. + +- qcom,cl-max-decrement + Usage: optional + Value type: + Definition: Maximum capacity decrement allowed per capacity learning + cycle. If this is not specified, then the default value + used will be 100 (10%). Unit is in decipercentage. + +- qcom,cl-min-limit + Usage: optional + Value type: + Definition: Minimum limit that the capacity cannot go below in a + capacity learning cycle. If this is not specified, then + the default value is 0. Unit is in decipercentage. + +- qcom,cl-max-limit + Usage: optional + Value type: + Definition: Maximum limit that the capacity cannot go above in a + capacity learning cycle. If this is not specified, then + the default value is 0. Unit is in decipercentage. + - qcom,hold-soc-while-full Usage: optional Value type: diff --git a/drivers/power/supply/qcom/Makefile b/drivers/power/supply/qcom/Makefile index 911a77a7966c..3281b14af4d1 100644 --- a/drivers/power/supply/qcom/Makefile +++ b/drivers/power/supply/qcom/Makefile @@ -1,5 +1,5 @@ obj-$(CONFIG_QPNP_FG_GEN3) += qpnp-fg-gen3.o fg-memif.o fg-util.o -obj-$(CONFIG_QPNP_FG_GEN4) += qpnp-fg-gen4.o fg-memif.o fg-util.o pmic-voter.o +obj-$(CONFIG_QPNP_FG_GEN4) += qpnp-fg-gen4.o fg-memif.o fg-util.o fg-alg.o pmic-voter.o obj-$(CONFIG_SMB1355_SLAVE_CHARGER) += smb1355-charger.o pmic-voter.o obj-$(CONFIG_QPNP_SMB2) += step-chg-jeita.o battery.o qpnp-smb2.o smb-lib.o pmic-voter.o storm-watch.o obj-$(CONFIG_SMB138X_CHARGER) += step-chg-jeita.o smb138x-charger.o smb-lib.o pmic-voter.o storm-watch.o battery.o diff --git a/drivers/power/supply/qcom/qpnp-fg-gen4.c b/drivers/power/supply/qcom/qpnp-fg-gen4.c index 36573f04cf66..97bf0c51ee62 100644 --- a/drivers/power/supply/qcom/qpnp-fg-gen4.c +++ b/drivers/power/supply/qcom/qpnp-fg-gen4.c @@ -20,6 +20,7 @@ #include #include "fg-core.h" #include "fg-reg.h" +#include "fg-alg.h" #define FG_GEN4_DEV_NAME "qcom,fg-gen4" @@ -142,9 +143,12 @@ struct fg_dt_props { struct fg_gen4_chip { struct fg_dev fg; struct fg_dt_props dt; + struct cycle_counter *counter; + struct cap_learning *cl; struct ttf ttf; struct delayed_work ttf_work; char batt_profile[PROFILE_LEN]; + char counter_buf[BUCKET_COUNT * 8]; bool ki_coeff_dischg_en; bool slope_limit_en; }; @@ -321,7 +325,7 @@ static int fg_gen4_get_learned_capacity(void *data, int64_t *learned_cap_uah) int rc, act_cap_mah; if (!chip) - return -ENODATA; + return -ENODEV; fg = &chip->fg; rc = fg_get_sram_prop(fg, FG_SRAM_ACT_BATT_CAP, &act_cap_mah); @@ -542,6 +546,128 @@ static inline void get_esr_meas_current(int curr_ma, u8 *val) *val <<= ESR_PULL_DOWN_IVAL_SHIFT; } +/* ALG callback functions below */ + +static int fg_gen4_store_learned_capacity(void *data, int64_t learned_cap_uah) +{ + struct fg_gen4_chip *chip = data; + struct fg_dev *fg; + int16_t cc_mah; + int rc; + + if (!chip) + return -ENODEV; + + fg = &chip->fg; + if (fg->battery_missing || !learned_cap_uah) + return -EPERM; + + cc_mah = div64_s64(learned_cap_uah, 1000); + rc = fg_sram_write(fg, fg->sp[FG_SRAM_ACT_BATT_CAP].addr_word, + fg->sp[FG_SRAM_ACT_BATT_CAP].addr_byte, (u8 *)&cc_mah, + fg->sp[FG_SRAM_ACT_BATT_CAP].len, FG_IMA_DEFAULT); + if (rc < 0) { + pr_err("Error in writing act_batt_cap_bkup, rc=%d\n", rc); + return rc; + } + + fg_dbg(fg, FG_CAP_LEARN, "learned capacity %llduah/%dmah stored\n", + chip->cl->learned_cap_uah, cc_mah); + return 0; +} + +static int fg_gen4_prime_cc_soc_sw(void *data, u32 batt_soc) +{ + struct fg_gen4_chip *chip = data; + struct fg_dev *fg; + int rc, cc_soc_sw; + + if (!chip) + return -ENODEV; + + fg = &chip->fg; + if (batt_soc == CC_SOC_30BIT) + cc_soc_sw = batt_soc; + else + cc_soc_sw = div64_s64((int64_t)batt_soc * CC_SOC_30BIT, + BATT_SOC_32BIT); + + rc = fg_sram_write(fg, fg->sp[FG_SRAM_CC_SOC_SW].addr_word, + fg->sp[FG_SRAM_CC_SOC_SW].addr_byte, (u8 *)&cc_soc_sw, + fg->sp[FG_SRAM_CC_SOC_SW].len, FG_IMA_ATOMIC); + if (rc < 0) + pr_err("Error in writing cc_soc_sw, rc=%d\n", rc); + else + fg_dbg(fg, FG_STATUS, "cc_soc_sw: %x\n", cc_soc_sw); + + return rc; +} + +static int fg_gen4_get_cc_soc_sw(void *data, int *cc_soc_sw) +{ + struct fg_gen4_chip *chip = data; + struct fg_dev *fg; + int rc, temp; + + if (!chip) + return -ENODEV; + + fg = &chip->fg; + rc = fg_get_sram_prop(fg, FG_SRAM_CC_SOC_SW, &temp); + if (rc < 0) { + pr_err("Error in getting CC_SOC_SW, rc=%d\n", rc); + return rc; + } + + *cc_soc_sw = temp; + return rc; +} + +static int fg_gen4_restore_count(void *data, u16 *buf, int length) +{ + struct fg_gen4_chip *chip = data; + int id, rc = 0; + u8 tmp[2]; + + if (!chip) + return -ENODEV; + + if (!buf || length > BUCKET_COUNT) + return -EINVAL; + + for (id = 0; id < length; id++) { + rc = fg_sram_read(&chip->fg, CYCLE_COUNT_WORD + id, + CYCLE_COUNT_OFFSET, (u8 *)tmp, 2, + FG_IMA_DEFAULT); + if (rc < 0) + pr_err("failed to read bucket %d rc=%d\n", id, rc); + else + *buf++ = tmp[0] | tmp[1] << 8; + } + + return rc; +} + +static int fg_gen4_store_count(void *data, u16 *buf, int id, int length) +{ + struct fg_gen4_chip *chip = data; + int rc; + + if (!chip) + return -ENODEV; + + if (!buf || length > BUCKET_COUNT * 2 || id < 0 || + id > BUCKET_COUNT - 1 || ((id * 2) + length) > BUCKET_COUNT * 2) + return -EINVAL; + + rc = fg_sram_write(&chip->fg, CYCLE_COUNT_WORD + id, CYCLE_COUNT_OFFSET, + (u8 *)buf, length, FG_IMA_DEFAULT); + if (rc < 0) + pr_err("failed to write bucket %d rc=%d\n", rc); + + return rc; +} + /* All worker and helper functions below */ #define KI_COEFF_MED_DISCHG_DEFAULT 245 @@ -828,6 +954,7 @@ static void profile_load_work(struct work_struct *work) profile_load_work.work); struct fg_gen4_chip *chip = container_of(fg, struct fg_gen4_chip, fg); + int64_t nom_cap_uah; u8 val; int rc; @@ -853,6 +980,8 @@ static void profile_load_work(struct work_struct *work) if (!is_profile_load_required(chip)) goto done; + clear_cycle_count(chip->counter); + fg_dbg(fg, FG_STATUS, "profile loading started\n"); rc = fg_masked_write(fg, BATT_SOC_RESTART(fg), RESTART_GO_BIT, 0); if (rc < 0) { @@ -892,6 +1021,14 @@ static void profile_load_work(struct work_struct *work) pr_err("Error in configuring battery profile params, rc:%d\n", rc); + rc = fg_gen4_get_nominal_capacity(chip, &nom_cap_uah); + if (!rc) { + rc = cap_learning_post_profile_init(chip->cl, nom_cap_uah); + if (rc < 0) + pr_err("Error in cap_learning_post_profile_init rc=%d\n", + rc); + } + batt_psy_initialized(fg); fg_notify_charger(fg); @@ -1233,7 +1370,9 @@ static irqreturn_t fg_delta_bsoc_irq_handler(int irq, void *data) static irqreturn_t fg_delta_msoc_irq_handler(int irq, void *data) { struct fg_dev *fg = data; + struct fg_gen4_chip *chip = container_of(fg, struct fg_gen4_chip, fg); int rc, batt_soc, batt_temp; + bool input_present = is_input_present(fg); fg_dbg(fg, FG_IRQ, "irq %d triggered\n", irq); @@ -1242,10 +1381,17 @@ static irqreturn_t fg_delta_msoc_irq_handler(int irq, void *data) rc = fg_get_sram_prop(fg, FG_SRAM_BATT_SOC, &batt_soc); if (rc < 0) pr_err("Failed to read battery soc rc: %d\n", rc); + else + cycle_count_update(chip->counter, (u32)batt_soc >> 24, + fg->charge_status, fg->charge_done, input_present); rc = fg_gen4_get_battery_temp(fg, &batt_temp); if (rc < 0) pr_err("Failed to read battery temp rc: %d\n", rc); + else if (chip->cl->active) + cap_learning_update(chip->cl, batt_temp, batt_soc, + fg->charge_status, fg->charge_done, input_present, + is_qnovo_en(fg)); rc = fg_gen4_charge_full_update(fg); if (rc < 0) @@ -1485,7 +1631,9 @@ static void status_change_work(struct work_struct *work) { struct fg_dev *fg = container_of(work, struct fg_dev, status_change_work); + struct fg_gen4_chip *chip = container_of(fg, struct fg_gen4_chip, fg); int rc, batt_soc, batt_temp; + bool input_present, qnovo_en; if (!batt_psy_initialized(fg)) { fg_dbg(fg, FG_STATUS, "Charger not available?!\n"); @@ -1511,6 +1659,16 @@ static void status_change_work(struct work_struct *work) goto out; } + input_present = is_input_present(fg); + qnovo_en = is_qnovo_en(fg); + cycle_count_update(chip->counter, (u32)batt_soc >> 24, + fg->charge_status, fg->charge_done, input_present); + + if (fg->charge_status != fg->prev_charge_status) + cap_learning_update(chip->cl, batt_temp, batt_soc, + fg->charge_status, fg->charge_done, input_present, + qnovo_en); + rc = fg_gen4_charge_full_update(fg); if (rc < 0) pr_err("Error in charge_full_update, rc=%d\n", rc); @@ -1879,6 +2037,32 @@ static int fg_get_time_to_empty(struct fg_dev *fg, int *val) return 0; } +static const char *fg_gen4_get_cycle_counts(struct fg_gen4_chip *chip) +{ + int i, rc, len = 0; + char *buf; + + buf = chip->counter_buf; + for (i = 1; i <= BUCKET_COUNT; i++) { + chip->counter->id = i; + rc = get_cycle_count(chip->counter); + if (rc < 0) { + pr_err("Couldn't get cycle count rc=%d\n", rc); + return NULL; + } + + if (sizeof(chip->counter_buf) - len < 8) { + pr_err("Invalid length %d\n", len); + return NULL; + } + + len += snprintf(buf+len, 8, "%d ", rc); + } + + buf[len] = '\0'; + return buf; +} + static void sram_dump_work(struct work_struct *work) { struct fg_dev *fg = container_of(work, struct fg_dev, @@ -2056,6 +2240,9 @@ static int fg_psy_get_property(struct power_supply *psy, case POWER_SUPPLY_PROP_CHARGE_COUNTER_SHADOW: rc = fg_gen4_get_charge_counter_shadow(chip, &pval->intval); break; + case POWER_SUPPLY_PROP_CYCLE_COUNTS: + pval->strval = fg_gen4_get_cycle_counts(chip); + break; case POWER_SUPPLY_PROP_SOC_REPORTING_READY: pval->intval = fg->soc_reporting_ready; break; @@ -2087,9 +2274,25 @@ static int fg_psy_set_property(struct power_supply *psy, enum power_supply_property psp, const union power_supply_propval *pval) { + struct fg_gen4_chip *chip = power_supply_get_drvdata(psy); int rc = 0; switch (psp) { + case POWER_SUPPLY_PROP_CHARGE_FULL: + if (chip->cl->active) { + pr_warn("Capacity learning active!\n"); + return 0; + } + if (pval->intval <= 0 || pval->intval > chip->cl->nom_cap_uah) { + pr_err("charge_full is out of bounds\n"); + return -EINVAL; + } + mutex_lock(&chip->cl->lock); + rc = fg_gen4_store_learned_capacity(chip, pval->intval); + if (!rc) + chip->cl->learned_cap_uah = pval->intval; + mutex_unlock(&chip->cl->lock); + break; default: break; } @@ -2101,6 +2304,8 @@ static int fg_property_is_writeable(struct power_supply *psy, enum power_supply_property psp) { switch (psp) { + case POWER_SUPPLY_PROP_CHARGE_FULL: + return 1; default: break; } @@ -2124,6 +2329,7 @@ static enum power_supply_property fg_psy_props[] = { POWER_SUPPLY_PROP_CHARGE_FULL, POWER_SUPPLY_PROP_CHARGE_COUNTER, POWER_SUPPLY_PROP_CHARGE_COUNTER_SHADOW, + POWER_SUPPLY_PROP_CYCLE_COUNTS, POWER_SUPPLY_PROP_SOC_REPORTING_READY, POWER_SUPPLY_PROP_DEBUG_BATTERY, POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE, @@ -2204,6 +2410,59 @@ static int fg_delta_bsoc_irq_en_cb(struct votable *votable, void *data, /* All init functions below this */ +static int fg_alg_init(struct fg_gen4_chip *chip) +{ + struct fg_dev *fg = &chip->fg; + struct cycle_counter *counter; + struct cap_learning *cl; + int rc; + + counter = devm_kzalloc(fg->dev, sizeof(*counter), GFP_KERNEL); + if (!counter) + return -ENOMEM; + + counter->restore_count = fg_gen4_restore_count; + counter->store_count = fg_gen4_store_count; + counter->data = chip; + + rc = cycle_count_init(counter); + if (rc < 0) { + dev_err(fg->dev, "Error in initializing cycle counter, rc:%d\n", + rc); + counter->data = NULL; + devm_kfree(fg->dev, counter); + return rc; + } + + chip->counter = counter; + + cl = devm_kzalloc(fg->dev, sizeof(*cl), GFP_KERNEL); + if (!cl) + return -ENOMEM; + + cl->cc_soc_max = CC_SOC_30BIT; + cl->get_cc_soc = fg_gen4_get_cc_soc_sw; + cl->prime_cc_soc = fg_gen4_prime_cc_soc_sw; + cl->get_learned_capacity = fg_gen4_get_learned_capacity; + cl->store_learned_capacity = fg_gen4_store_learned_capacity; + cl->data = chip; + + rc = cap_learning_init(cl); + if (rc < 0) { + dev_err(fg->dev, "Error in initializing capacity learning, rc:%d\n", + rc); + counter->data = NULL; + cl->data = NULL; + devm_kfree(fg->dev, counter); + devm_kfree(fg->dev, cl); + return rc; + } + + chip->cl = cl; + + return 0; +} + #define BATT_TEMP_HYST_MASK GENMASK(3, 0) #define BATT_TEMP_DELTA_MASK GENMASK(7, 4) #define BATT_TEMP_DELTA_SHIFT 4 @@ -2419,6 +2678,12 @@ static int fg_gen4_hw_init(struct fg_gen4_chip *chip) } } + rc = restore_cycle_count(chip->counter); + if (rc < 0) { + pr_err("Error in restoring cycle_count, rc=%d\n", rc); + return rc; + } + return 0; } @@ -2695,6 +2960,48 @@ static int fg_gen4_parse_dt(struct fg_gen4_chip *chip) chip->dt.force_load_profile = of_property_read_bool(node, "qcom,fg-force-load-profile"); + rc = of_property_read_u32(node, "qcom,cl-start-capacity", &temp); + if (rc < 0) + chip->cl->dt.start_soc = DEFAULT_CL_START_SOC; + else + chip->cl->dt.start_soc = temp; + + rc = of_property_read_u32(node, "qcom,cl-min-temp", &temp); + if (rc < 0) + chip->cl->dt.min_temp = DEFAULT_CL_MIN_TEMP_DECIDEGC; + else + chip->cl->dt.min_temp = temp; + + rc = of_property_read_u32(node, "qcom,cl-max-temp", &temp); + if (rc < 0) + chip->cl->dt.max_temp = DEFAULT_CL_MAX_TEMP_DECIDEGC; + else + chip->cl->dt.max_temp = temp; + + rc = of_property_read_u32(node, "qcom,cl-max-increment", &temp); + if (rc < 0) + chip->cl->dt.max_cap_inc = DEFAULT_CL_MAX_INC_DECIPERC; + else + chip->cl->dt.max_cap_inc = temp; + + rc = of_property_read_u32(node, "qcom,cl-max-decrement", &temp); + if (rc < 0) + chip->cl->dt.max_cap_dec = DEFAULT_CL_MAX_DEC_DECIPERC; + else + chip->cl->dt.max_cap_dec = temp; + + rc = of_property_read_u32(node, "qcom,cl-min-limit", &temp); + if (rc < 0) + chip->cl->dt.min_cap_limit = DEFAULT_CL_MIN_LIM_DECIPERC; + else + chip->cl->dt.min_cap_limit = temp; + + rc = of_property_read_u32(node, "qcom,cl-max-limit", &temp); + if (rc < 0) + chip->cl->dt.max_cap_limit = DEFAULT_CL_MAX_LIM_DECIPERC; + else + chip->cl->dt.max_cap_limit = temp; + rc = of_property_read_u32(node, "qcom,fg-batt-temp-hot", &temp); if (rc < 0) chip->dt.batt_temp_hot_thresh = -EINVAL; @@ -2819,6 +3126,13 @@ static int fg_gen4_probe(struct platform_device *pdev) goto exit; } + rc = fg_alg_init(chip); + if (rc < 0) { + dev_err(fg->dev, "Error in alg_init, rc:%d\n", + rc); + goto exit; + } + rc = fg_gen4_parse_dt(chip); if (rc < 0) { dev_err(fg->dev, "Error in reading DT parameters, rc:%d\n", @@ -2930,13 +3244,13 @@ static void fg_gen4_shutdown(struct platform_device *pdev) struct fg_dev *fg = &chip->fg; int rc, bsoc; - if (fg->charge_full) { - rc = fg_get_sram_prop(fg, FG_SRAM_BATT_SOC, &bsoc); - if (rc < 0) { - pr_err("Error in getting BATT_SOC, rc=%d\n", rc); - return; - } + rc = fg_get_sram_prop(fg, FG_SRAM_BATT_SOC, &bsoc); + if (rc < 0) { + pr_err("Error in getting BATT_SOC, rc=%d\n", rc); + return; + } + if (fg->charge_full) { /* We need 2 most significant bytes here */ bsoc = (u32)bsoc >> 16; @@ -2946,6 +3260,13 @@ static void fg_gen4_shutdown(struct platform_device *pdev) return; } } + + /* + * Charging status doesn't matter when the device shuts down and we + * have to treat this as charge done. Hence pass charge_done as true. + */ + cycle_count_update(chip->counter, (u32)bsoc >> 24, + POWER_SUPPLY_STATUS_NOT_CHARGING, true, is_input_present(fg)); } static int fg_gen4_suspend(struct device *dev) -- GitLab From d854d188b8ec8e793a2ddc2eacbaf791fd765613 Mon Sep 17 00:00:00 2001 From: Zhen Kong Date: Thu, 19 Apr 2018 14:07:52 -0700 Subject: [PATCH 0553/1635] qseecom: check dmabuf api return value correctly make change to check dmabuf api return error or NULL to avoid misjudgement on return value. Change-Id: I8aa8498533a606e828ce769c02b762c56407f2e8 Signed-off-by: Zhen Kong --- drivers/misc/qseecom.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c index 48a68e97367e..78aa561fb7b0 100644 --- a/drivers/misc/qseecom.c +++ b/drivers/misc/qseecom.c @@ -1160,21 +1160,21 @@ static int qseecom_dmabuf_map(int ion_fd, struct sg_table **sgt, int ret = 0; new_dma_buf = dma_buf_get(ion_fd); - if (new_dma_buf == NULL) { + if (IS_ERR_OR_NULL(new_dma_buf)) { pr_err("dma_buf_get() for ion_fd %d failed\n", ion_fd); ret = -ENOMEM; goto err; } new_attach = dma_buf_attach(new_dma_buf, qseecom.dev); - if (IS_ERR(new_attach)) { + if (IS_ERR_OR_NULL(new_attach)) { pr_err("dma_buf_attach() for ion_fd %d failed\n", ion_fd); ret = -ENOMEM; goto err_put; } new_sgt = dma_buf_map_attachment(new_attach, DMA_BIDIRECTIONAL); - if (IS_ERR(new_sgt)) { + if (IS_ERR_OR_NULL(new_sgt)) { ret = PTR_ERR(new_sgt); pr_err("dma_buf_map_attachment for ion_fd %d failed ret = %d\n", ion_fd, ret); @@ -1227,7 +1227,7 @@ static int qseecom_vaddr_map(int ion_fd, dma_buf_begin_cpu_access(new_dma_buf, DMA_BIDIRECTIONAL); new_va = dma_buf_kmap(new_dma_buf, 0); - if (!new_va) { + if (IS_ERR_OR_NULL(new_va)) { pr_err("dma_buf_kmap failed\n"); ret = -ENOMEM; goto err_unmap; -- GitLab From 66bf3c6b679f84481102c9f8bfa0ce7b2bdf91bc Mon Sep 17 00:00:00 2001 From: David Collins Date: Thu, 19 Apr 2018 14:11:30 -0700 Subject: [PATCH 0554/1635] clk: qcom: gcc-sdmshrike: update usb mock utmi supported frequencies Add 19.2 MHz support for the gcc_usb30_mp_mock_utmi_clk_src, gcc_usb30_prim_mock_utmi_clk_src, and gcc_usb30_sec_mock_utmi_clk_src RCGs. Change-Id: Id4b0277ca2f7660cd005539a0df80fdac61a48e7 Signed-off-by: David Collins --- drivers/clk/qcom/gcc-sdmshrike.c | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/drivers/clk/qcom/gcc-sdmshrike.c b/drivers/clk/qcom/gcc-sdmshrike.c index 378fcf4628a5..481b557d51ee 100644 --- a/drivers/clk/qcom/gcc-sdmshrike.c +++ b/drivers/clk/qcom/gcc-sdmshrike.c @@ -1661,6 +1661,8 @@ static struct clk_rcg2 gcc_usb30_mp_master_clk_src = { }; static const struct freq_tbl ftbl_gcc_usb30_mp_mock_utmi_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + F(20000000, P_GPLL0_OUT_EVEN, 15, 0, 0), F(40000000, P_GPLL0_OUT_EVEN, 7.5, 0, 0), F(60000000, P_GPLL0_OUT_MAIN, 10, 0, 0), { } @@ -1709,19 +1711,12 @@ static struct clk_rcg2 gcc_usb30_prim_master_clk_src = { }, }; -static const struct freq_tbl ftbl_gcc_usb30_prim_mock_utmi_clk_src[] = { - F(20000000, P_GPLL0_OUT_EVEN, 15, 0, 0), - F(40000000, P_GPLL0_OUT_EVEN, 7.5, 0, 0), - F(60000000, P_GPLL0_OUT_MAIN, 10, 0, 0), - { } -}; - static struct clk_rcg2 gcc_usb30_prim_mock_utmi_clk_src = { .cmd_rcgr = 0xf034, .mnd_width = 0, .hid_width = 5, .parent_map = gcc_parent_map_0, - .freq_tbl = ftbl_gcc_usb30_prim_mock_utmi_clk_src, + .freq_tbl = ftbl_gcc_usb30_mp_mock_utmi_clk_src, .clkr.hw.init = &(struct clk_init_data){ .name = "gcc_usb30_prim_mock_utmi_clk_src", .parent_names = gcc_parent_names_0, @@ -1764,7 +1759,7 @@ static struct clk_rcg2 gcc_usb30_sec_mock_utmi_clk_src = { .mnd_width = 0, .hid_width = 5, .parent_map = gcc_parent_map_0, - .freq_tbl = ftbl_gcc_usb30_prim_mock_utmi_clk_src, + .freq_tbl = ftbl_gcc_usb30_mp_mock_utmi_clk_src, .clkr.hw.init = &(struct clk_init_data){ .name = "gcc_usb30_sec_mock_utmi_clk_src", .parent_names = gcc_parent_names_0, -- GitLab From 7ef5063992c912946e7e05e14292126d3f90733b Mon Sep 17 00:00:00 2001 From: David Collins Date: Thu, 19 Apr 2018 12:23:11 -0700 Subject: [PATCH 0555/1635] clk: qcom: gcc-sm8150: update usb mock utmi supported frequencies Add 19.2 MHz support for the gcc_usb30_prim_mock_utmi_clk_src and gcc_usb30_sec_mock_utmi_clk_src RCGs. Change-Id: I4934562f3adf75a2b089cecf182da20eceb770d9 Signed-off-by: David Collins --- drivers/clk/qcom/gcc-sm8150.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/clk/qcom/gcc-sm8150.c b/drivers/clk/qcom/gcc-sm8150.c index 7ac2b7df1e64..e084b3a66a2a 100644 --- a/drivers/clk/qcom/gcc-sm8150.c +++ b/drivers/clk/qcom/gcc-sm8150.c @@ -1515,6 +1515,7 @@ static struct clk_rcg2 gcc_usb30_prim_master_clk_src = { }; static const struct freq_tbl ftbl_gcc_usb30_prim_mock_utmi_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), F(20000000, P_GPLL0_OUT_EVEN, 15, 0, 0), F(60000000, P_GPLL0_OUT_EVEN, 5, 0, 0), { } -- GitLab From 079a9e54429f8ff53af6cf13e21774b9b0deb8f9 Mon Sep 17 00:00:00 2001 From: Vijayavardhan Vennapusa Date: Thu, 5 Apr 2018 14:25:39 +0530 Subject: [PATCH 0556/1635] policy_engine: Clear ss_lane_svid in reset_vdm_state() During insertion of DP adaptor, our target might start in SINK mode as well. In that case, DP adaptor sends DR_SWAP to change data role from UFP to DFP. While starting host mode, driver is not clearing ss_lane_svid variable due to which usb_pd_release_ss_lanes() will return -EBUSY even though DP client is requesting. Fix the issue by clearing ss_lane_svid in reset_vdm_state() unconditionally. Change-Id: I62e775623295d795ad3e203590634f669cbf7537 Signed-off-by: Vijayavardhan Vennapusa --- drivers/usb/pd/policy_engine.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/usb/pd/policy_engine.c b/drivers/usb/pd/policy_engine.c index bcb4e4aa3ce6..a79712a1d571 100644 --- a/drivers/usb/pd/policy_engine.c +++ b/drivers/usb/pd/policy_engine.c @@ -1832,6 +1832,7 @@ static void reset_vdm_state(struct usbpd *pd) pd->num_svids = 0; kfree(pd->vdm_tx); pd->vdm_tx = NULL; + pd->ss_lane_svid = 0x0; } static void dr_swap(struct usbpd *pd) -- GitLab From 5adf17c184155be590cd20407039cc597474f35e Mon Sep 17 00:00:00 2001 From: Vijayavardhan Vennapusa Date: Wed, 18 Apr 2018 16:09:20 +0530 Subject: [PATCH 0557/1635] dwc3-msm: Return zero if max speed requested is already active USB PD driver calls restart_usb_host_mode callback to start host mode in high speed to release SS lanes. If current maximum speed is same as requested maximum speed i.e HIGH speed, then return zero instead of ERROR to notify as success. Change-Id: I45f3aaf4a8ecb85f0551e67fdc36263f6da50ed6 Signed-off-by: Vijayavardhan Vennapusa --- drivers/usb/dwc3/dwc3-msm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c index 6fc3ff2d0755..2714f386f858 100644 --- a/drivers/usb/dwc3/dwc3-msm.c +++ b/drivers/usb/dwc3/dwc3-msm.c @@ -3843,7 +3843,7 @@ static int dwc3_restart_usb_host_mode(struct notifier_block *nb, usb_speed = (event == 0 ? USB_SPEED_HIGH : USB_SPEED_SUPER); if (dwc->maximum_speed == usb_speed) - goto err; + return 0; dbg_event(0xFF, "fw_restarthost", 0); flush_delayed_work(&mdwc->sm_work); -- GitLab From 1c955dd27a97699d74c6a3863db932e1d1912ed5 Mon Sep 17 00:00:00 2001 From: Mayank Rana Date: Wed, 28 Mar 2018 14:19:57 -0700 Subject: [PATCH 0558/1635] ARM: dts: msm: Update USB QMP DP PHY initialization sequence on SM8150 Update USB QMP DP PHY initialization sequence (version 2.4) for USB SSP functionality on SM8150. Change-Id: Ic3c30e11b652abbaf77021e2cd7f18b2c1f2c6e5 Signed-off-by: Mayank Rana --- arch/arm64/boot/dts/qcom/sm8150-usb.dtsi | 72 ++++++++++++------------ 1 file changed, 36 insertions(+), 36 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sm8150-usb.dtsi b/arch/arm64/boot/dts/qcom/sm8150-usb.dtsi index 49aebbd9e3c4..6fe2d8d07b9d 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-usb.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-usb.dtsi @@ -152,7 +152,6 @@ USB3_DP_QSERDES_COM_SSC_STEP_SIZE1_MODE1 0xde 0 USB3_DP_QSERDES_COM_SSC_STEP_SIZE2_MODE1 0x07 0 USB3_DP_QSERDES_COM_SYSCLK_BUF_ENABLE 0x0a 0 - USB3_DP_QSERDES_COM_CMN_IPTRIM 0x14 0 USB3_DP_QSERDES_COM_CP_CTRL_MODE0 0x06 0 USB3_DP_QSERDES_COM_CP_CTRL_MODE1 0x06 0 USB3_DP_QSERDES_COM_PLL_RCTRL_MODE0 0x16 0 @@ -173,22 +172,23 @@ USB3_DP_QSERDES_COM_DIV_FRAC_START1_MODE1 0xab 0 USB3_DP_QSERDES_COM_DIV_FRAC_START2_MODE1 0xea 0 USB3_DP_QSERDES_COM_DIV_FRAC_START3_MODE1 0x02 0 - USB3_DP_QSERDES_COM_VCO_TUNE_CTRL 0x00 0 - USB3_DP_QSERDES_COM_VCO_TUNE_MAP 0x02 0 USB3_DP_QSERDES_COM_VCO_TUNE1_MODE0 0x24 0 USB3_DP_QSERDES_COM_VCO_TUNE1_MODE1 0x24 0 USB3_DP_QSERDES_COM_VCO_TUNE2_MODE1 0x02 0 USB3_DP_QSERDES_COM_HSCLK_SEL 0x01 0 USB3_DP_QSERDES_COM_CORECLK_DIV_MODE1 0x08 0 + USB3_DP_QSERDES_COM_SVS_MODE_CLK_SEL 0x5 0 USB3_DP_QSERDES_COM_BIN_VCOCAL_CMP_CODE1_MODE0 0xca 0 USB3_DP_QSERDES_COM_BIN_VCOCAL_CMP_CODE2_MODE0 0x1e 0 USB3_DP_QSERDES_COM_BIN_VCOCAL_CMP_CODE1_MODE1 0xca 0 USB3_DP_QSERDES_COM_BIN_VCOCAL_CMP_CODE2_MODE1 0x1e 0 USB3_DP_QSERDES_COM_BIN_VCOCAL_HSCLK_SEL 0x11 0 - USB3_DP_QSERDES_TXA_RES_CODE_LANE_TX 0xd4 0 - USB3_DP_QSERDES_TXA_RES_CODE_LANE_RX 0xd0 0 + USB3_DP_QSERDES_COM_VCO_TUNE_MAP 0x02 0 + USB3_DP_QSERDES_COM_CMN_IPTRIM 0x20 0 USB3_DP_QSERDES_TXA_LANE_MODE_1 0x05 0 USB3_DP_QSERDES_TXA_RCV_DETECT_LVL_2 0x12 0 + USB3_DP_QSERDES_TXA_RES_CODE_LANE_TX 0xe4 0 + USB3_DP_QSERDES_TXA_RES_CODE_LANE_RX 0xd0 0 USB3_DP_QSERDES_RXA_UCDR_SO_GAIN 0x04 0 USB3_DP_QSERDES_RXA_UCDR_FASTLOCK_FO_GAIN 0x2f 0 USB3_DP_QSERDES_RXA_UCDR_SO_SATURATION_AND_ENABLE 0x7f 0 @@ -199,32 +199,34 @@ USB3_DP_QSERDES_RXA_UCDR_SB2_THRESH2 0x08 0 USB3_DP_QSERDES_RXA_UCDR_SB2_GAIN1 0x05 0 USB3_DP_QSERDES_RXA_UCDR_SB2_GAIN2 0x05 0 - USB3_DP_QSERDES_RXA_VGA_CAL_CNTRL2 0x0f 0 + USB3_DP_QSERDES_RXA_VGA_CAL_CNTRL1 0x54 0 + USB3_DP_QSERDES_RXA_VGA_CAL_CNTRL2 0x08 0 + USB3_DP_QSERDES_RXA_GM_CAL 0x1f 0 USB3_DP_QSERDES_RXA_RX_EQU_ADAPTOR_CNTRL2 0x0f 0 USB3_DP_QSERDES_RXA_RX_EQU_ADAPTOR_CNTRL3 0x4a 0 - USB3_DP_QSERDES_RXA_RX_EQU_ADAPTOR_CNTRL4 0x08 0 + USB3_DP_QSERDES_RXA_RX_EQU_ADAPTOR_CNTRL4 0x0a 0 USB3_DP_QSERDES_RXA_RX_IDAC_TSETTLE_LOW 0xc0 0 USB3_DP_QSERDES_RXA_RX_IDAC_TSETTLE_HIGH 0x00 0 USB3_DP_QSERDES_RXA_RX_EQ_OFFSET_ADAPTOR_CNTRL1 0x77 0 USB3_DP_QSERDES_RXA_RX_OFFSET_ADAPTOR_CNTRL2 0x80 0 USB3_DP_QSERDES_RXA_SIGDET_CNTRL 0x04 0 USB3_DP_QSERDES_RXA_SIGDET_DEGLITCH_CNTRL 0x0e 0 - USB3_DP_QSERDES_RXA_RX_MODE_00_LOW 0x36 0 - USB3_DP_QSERDES_RXA_RX_MODE_00_HIGH 0x36 0 - USB3_DP_QSERDES_RXA_RX_MODE_00_HIGH2 0xb6 0 - USB3_DP_QSERDES_RXA_RX_MODE_00_HIGH3 0x17 0 - USB3_DP_QSERDES_RXA_RX_MODE_00_HIGH4 0x7c 0 - USB3_DP_QSERDES_RXA_RX_MODE_01_LOW 0xfc 0 - USB3_DP_QSERDES_RXA_RX_MODE_01_HIGH 0xfc 0 - USB3_DP_QSERDES_RXA_RX_MODE_01_HIGH2 0xff 0 - USB3_DP_QSERDES_RXA_RX_MODE_01_HIGH3 0x23 0 - USB3_DP_QSERDES_RXA_RX_MODE_01_HIGH4 0x34 0 + USB3_DP_QSERDES_RXA_RX_MODE_00_LOW 0x3f 0 + USB3_DP_QSERDES_RXA_RX_MODE_00_HIGH 0xbf 0 + USB3_DP_QSERDES_RXA_RX_MODE_00_HIGH2 0x3f 0 + USB3_DP_QSERDES_RXA_RX_MODE_00_HIGH3 0x3f 0 + USB3_DP_QSERDES_RXA_RX_MODE_00_HIGH4 0x8a 0 + USB3_DP_QSERDES_RXA_RX_MODE_01_LOW 0xdc 0 + USB3_DP_QSERDES_RXA_RX_MODE_01_HIGH 0xdc 0 + USB3_DP_QSERDES_RXA_RX_MODE_01_HIGH2 0x5c 0 + USB3_DP_QSERDES_RXA_RX_MODE_01_HIGH3 0x0b 0 + USB3_DP_QSERDES_RXA_RX_MODE_01_HIGH4 0xb3 0 USB3_DP_QSERDES_RXA_DFE_EN_TIMER 0x04 0 USB3_DP_QSERDES_RXA_DFE_CTLE_POST_CAL_OFFSET 0x30 0 - USB3_DP_QSERDES_TXB_RES_CODE_LANE_TX 0xd4 0 - USB3_DP_QSERDES_TXB_RES_CODE_LANE_RX 0xd0 0 USB3_DP_QSERDES_TXB_LANE_MODE_1 0x05 0 USB3_DP_QSERDES_TXB_RCV_DETECT_LVL_2 0x12 0 + USB3_DP_QSERDES_TXB_RES_CODE_LANE_TX 0xe4 0 + USB3_DP_QSERDES_TXB_RES_CODE_LANE_RX 0xd0 0 USB3_DP_QSERDES_RXB_UCDR_SO_GAIN 0x04 0 USB3_DP_QSERDES_RXB_UCDR_FASTLOCK_FO_GAIN 0x2f 0 USB3_DP_QSERDES_RXB_UCDR_SO_SATURATION_AND_ENABLE 0x7f 0 @@ -235,26 +237,28 @@ USB3_DP_QSERDES_RXB_UCDR_SB2_THRESH2 0x08 0 USB3_DP_QSERDES_RXB_UCDR_SB2_GAIN1 0x05 0 USB3_DP_QSERDES_RXB_UCDR_SB2_GAIN2 0x05 0 - USB3_DP_QSERDES_RXB_VGA_CAL_CNTRL2 0x0f 0 + USB3_DP_QSERDES_RXB_VGA_CAL_CNTRL1 0x54 0 + USB3_DP_QSERDES_RXB_VGA_CAL_CNTRL2 0x08 0 + USB3_DP_QSERDES_RXB_GM_CAL 0x1f 0 USB3_DP_QSERDES_RXB_RX_EQU_ADAPTOR_CNTRL2 0x0f 0 USB3_DP_QSERDES_RXB_RX_EQU_ADAPTOR_CNTRL3 0x4a 0 - USB3_DP_QSERDES_RXB_RX_EQU_ADAPTOR_CNTRL4 0x08 0 + USB3_DP_QSERDES_RXB_RX_EQU_ADAPTOR_CNTRL4 0x0a 0 USB3_DP_QSERDES_RXB_RX_IDAC_TSETTLE_LOW 0xc0 0 USB3_DP_QSERDES_RXB_RX_IDAC_TSETTLE_HIGH 0x00 0 USB3_DP_QSERDES_RXB_RX_EQ_OFFSET_ADAPTOR_CNTRL1 0x77 0 USB3_DP_QSERDES_RXB_RX_OFFSET_ADAPTOR_CNTRL2 0x80 0 USB3_DP_QSERDES_RXB_SIGDET_CNTRL 0x04 0 USB3_DP_QSERDES_RXB_SIGDET_DEGLITCH_CNTRL 0x0e 0 - USB3_DP_QSERDES_RXB_RX_MODE_00_LOW 0x36 0 - USB3_DP_QSERDES_RXB_RX_MODE_00_HIGH 0x36 0 - USB3_DP_QSERDES_RXB_RX_MODE_00_HIGH2 0xb6 0 - USB3_DP_QSERDES_RXB_RX_MODE_00_HIGH3 0x17 0 - USB3_DP_QSERDES_RXB_RX_MODE_00_HIGH4 0x7c 0 - USB3_DP_QSERDES_RXB_RX_MODE_01_LOW 0xfc 0 - USB3_DP_QSERDES_RXB_RX_MODE_01_HIGH 0xfc 0 - USB3_DP_QSERDES_RXB_RX_MODE_01_HIGH2 0xff 0 - USB3_DP_QSERDES_RXB_RX_MODE_01_HIGH3 0x23 0 - USB3_DP_QSERDES_RXB_RX_MODE_01_HIGH4 0x34 0 + USB3_DP_QSERDES_RXB_RX_MODE_00_LOW 0x3f 0 + USB3_DP_QSERDES_RXB_RX_MODE_00_HIGH 0xbf 0 + USB3_DP_QSERDES_RXB_RX_MODE_00_HIGH2 0x3f 0 + USB3_DP_QSERDES_RXB_RX_MODE_00_HIGH3 0x3f 0 + USB3_DP_QSERDES_RXB_RX_MODE_00_HIGH4 0x8a 0 + USB3_DP_QSERDES_RXB_RX_MODE_01_LOW 0xdc 0 + USB3_DP_QSERDES_RXB_RX_MODE_01_HIGH 0xdc 0 + USB3_DP_QSERDES_RXB_RX_MODE_01_HIGH2 0x5c 0 + USB3_DP_QSERDES_RXB_RX_MODE_01_HIGH3 0x0b 0 + USB3_DP_QSERDES_RXB_RX_MODE_01_HIGH4 0xb3 0 USB3_DP_QSERDES_RXB_DFE_EN_TIMER 0x04 0 USB3_DP_QSERDES_RXB_DFE_CTLE_POST_CAL_OFFSET 0x30 0 USB3_DP_PCS_LOCK_DETECT_CONFIG1 0xd0 0 @@ -265,11 +269,7 @@ USB3_DP_PCS_ALIGN_DETECT_CONFIG2 0x13 0 USB3_DP_PCS_EQ_CONFIG1 0x0d 0 USB3_DP_PCS_USB3_LFPS_DET_HIGH_COUNT_VAL 0xf8 0 - USB3_DP_PCS_USB3_RXEQTRAINING_LOCK_TIME 0x55 0 - USB3_DP_PCS_USB3_RXEQTRAINING_WAIT_TIME 0x30 0 - USB3_DP_PCS_USB3_RXEQTRAINING_CTLE_TIME 0x05 0 - USB3_DP_PCS_USB3_RXEQTRAINING_WAIT_TIME_S2 0x15 0 - USB3_DP_PCS_USB3_RXEQTRAINING_DFE_TIME_S2 0x04 0 + USB3_DP_PCS_USB3_RXEQTRAINING_DFE_TIME_S2 0x07 0 0xffffffff 0xffffffff 0x00>; qcom,qmp-phy-reg-offset = -- GitLab From 51f8475a0af79c36d2aee6555f5e20181c877662 Mon Sep 17 00:00:00 2001 From: Mayank Rana Date: Tue, 3 Apr 2018 10:06:04 -0700 Subject: [PATCH 0559/1635] usb: configfs: Set USB gadget speed as super speed plus This change sets maximum allowed USB speed as super speed plus with configfs based gadget to support USB SSP functionality. Change-Id: Idc76b817d962207e471354812933da4bfeda0530 Signed-off-by: Mayank Rana --- drivers/usb/gadget/configfs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/gadget/configfs.c b/drivers/usb/gadget/configfs.c index bf2d0ce80c99..1ef8187ceb5b 100644 --- a/drivers/usb/gadget/configfs.c +++ b/drivers/usb/gadget/configfs.c @@ -1563,7 +1563,7 @@ static const struct usb_gadget_driver configfs_driver_template = { .suspend = composite_suspend, .resume = composite_resume, - .max_speed = USB_SPEED_SUPER, + .max_speed = USB_SPEED_SUPER_PLUS, .driver = { .owner = THIS_MODULE, .name = "configfs-gadget", -- GitLab From fbcf003ddf9dd451c8e1658d38ab6a514465e4fb Mon Sep 17 00:00:00 2001 From: Maulik Shah Date: Wed, 6 Dec 2017 16:34:06 +0530 Subject: [PATCH 0560/1635] cpuidle: lpm-levels: Remove sched_set_cpu_cstate calls Scheduler no more need to know current c-state of cpu. Remove unused calls to set c-state. Change-Id: I2ddb3676527a20e00c0dfc192751a86e14eb0965 Signed-off-by: Maulik Shah --- drivers/cpuidle/lpm-levels.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/cpuidle/lpm-levels.c b/drivers/cpuidle/lpm-levels.c index 4a3b8c986462..b172a6f31626 100644 --- a/drivers/cpuidle/lpm-levels.c +++ b/drivers/cpuidle/lpm-levels.c @@ -1367,9 +1367,6 @@ static int lpm_cpuidle_enter(struct cpuidle_device *dev, const struct cpumask *cpumask = get_cpu_mask(dev->cpu); ktime_t start = ktime_get(); uint64_t start_time = ktime_to_ns(start), end_time; - struct power_params *pwr_params; - - pwr_params = &cpu->levels[idx].pwr; cpu_prepare(cpu, idx, true); cluster_prepare(cpu->parent, cpumask, idx, true, start_time); -- GitLab From a211388121119a6e85ef7a467dbafa4e97d3b2b6 Mon Sep 17 00:00:00 2001 From: Raghavendra Kakarla Date: Fri, 23 Mar 2018 23:35:37 +0530 Subject: [PATCH 0561/1635] cpuidle: lpm-levels: Add premature count to module parameter Add premature count prediction parameter as module parameter. Change-Id: I6f356e63f12ab9a0701d01aca2b968798d7e5dcc Signed-off-by: Raghavendra Kakarla --- drivers/cpuidle/lpm-levels.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/cpuidle/lpm-levels.c b/drivers/cpuidle/lpm-levels.c index b172a6f31626..b9ab79165369 100644 --- a/drivers/cpuidle/lpm-levels.c +++ b/drivers/cpuidle/lpm-levels.c @@ -96,6 +96,8 @@ static uint32_t tmr_add = 1000; module_param_named(tmr_add, tmr_add, uint, 0664); static uint32_t ref_premature_cnt = 1; +module_param_named(ref_premature_cnt, ref_premature_cnt, uint, 0664); + static uint32_t bias_hyst; module_param_named(bias_hyst, bias_hyst, uint, 0664); -- GitLab From f3ca18a7fcd4c8cb4419e9bb1ecbf3a89485b63f Mon Sep 17 00:00:00 2001 From: Chris Lew Date: Thu, 19 Apr 2018 16:59:58 -0700 Subject: [PATCH 0562/1635] qrtr: Reset address of to sockaddr for local enqueue The broadcast node id should only be sent with the control port id. Ensure that broadcasts are only to the control port and set the to sockaddr for local enqueues to the address . Change-Id: I31de1220f99f6e7c8544c6d42072cb8daf4bbd85 Signed-off-by: Chris Lew --- net/qrtr/qrtr.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/net/qrtr/qrtr.c b/net/qrtr/qrtr.c index 8cc7c4f67991..8273f44b27af 100644 --- a/net/qrtr/qrtr.c +++ b/net/qrtr/qrtr.c @@ -714,6 +714,8 @@ static int qrtr_bcast_enqueue(struct qrtr_node *node, struct sk_buff *skb, } mutex_unlock(&qrtr_node_lock); + to->sq_node = QRTR_NODE_BCAST; + to->sq_port = QRTR_PORT_CTRL; qrtr_local_enqueue(node, skb, type, from, to); return 0; @@ -766,6 +768,10 @@ static int qrtr_sendmsg(struct socket *sock, struct msghdr *msg, size_t len) node = NULL; if (addr->sq_node == QRTR_NODE_BCAST) { enqueue_fn = qrtr_bcast_enqueue; + if (addr->sq_port != QRTR_PORT_CTRL) { + release_sock(sk); + return -EINVAL; + } } else if (addr->sq_node == ipc->us.sq_node) { enqueue_fn = qrtr_local_enqueue; } else { -- GitLab From 95e8846aaa5a0b35504282c2beda89da35c5866a Mon Sep 17 00:00:00 2001 From: Chris Lew Date: Fri, 13 Apr 2018 20:25:16 -0700 Subject: [PATCH 0563/1635] msm: ipa3: Add QMI server exit handling The QMI net reset callback is called when the name server is restarted. This does not cover the SSR case, where the del_server callback will be called. Add a handler to reset the server sock addrs when a del_server notification is given. Change-Id: I35f6577d37370ac293fbfe8731c9ee1410f8766e Signed-off-by: Chris Lew --- .../platform/msm/ipa/ipa_v3/ipa_qmi_service.c | 20 +++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.c b/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.c index b2063d25b0c7..09b34c1d91c9 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.c @@ -1053,6 +1053,10 @@ static void ipa3_q6_clnt_svc_exit(struct work_struct *work) static int ipa3_q6_clnt_svc_event_notify_svc_new(struct qmi_handle *qmi, struct qmi_service *service) { + IPAWANDBG("QMI svc:%d vers:%d ins:%d node:%d port:%d\n", + service->service, service->version, service->instance, + service->node, service->port); + ipa3_qmi_ctx->ipa_q6_client_params.sq.sq_family = AF_QIPCRTR; ipa3_qmi_ctx->ipa_q6_client_params.sq.sq_node = service->node; ipa3_qmi_ctx->ipa_q6_client_params.sq.sq_port = service->port; @@ -1064,8 +1068,19 @@ static int ipa3_q6_clnt_svc_event_notify_svc_new(struct qmi_handle *qmi, return 0; } -static void ipa3_q6_clnt_svc_event_notify_svc_exit(struct qmi_handle *qmi) +static void ipa3_q6_clnt_svc_event_notify_net_reset(struct qmi_handle *qmi) +{ + if (!workqueues_stopped) + queue_delayed_work(ipa_clnt_req_workqueue, + &ipa3_work_svc_exit, 0); +} + +static void ipa3_q6_clnt_svc_event_notify_svc_exit(struct qmi_handle *qmi, + struct qmi_service *svc) { + IPAWANDBG("QMI svc:%d vers:%d ins:%d node:%d port:%d\n", svc->service, + svc->version, svc->instance, svc->node, svc->port); + if (!workqueues_stopped) queue_delayed_work(ipa_clnt_req_workqueue, &ipa3_work_svc_exit, 0); @@ -1077,7 +1092,8 @@ static struct qmi_ops server_ops = { static struct qmi_ops client_ops = { .new_server = ipa3_q6_clnt_svc_event_notify_svc_new, - .net_reset = ipa3_q6_clnt_svc_event_notify_svc_exit, + .del_server = ipa3_q6_clnt_svc_event_notify_svc_exit, + .net_reset = ipa3_q6_clnt_svc_event_notify_net_reset, }; static struct qmi_msg_handler server_handlers[] = { -- GitLab From d326f95c8aa6a542860c8fcb81072230056e1bff Mon Sep 17 00:00:00 2001 From: Sudheer Papothi Date: Wed, 11 Apr 2018 11:00:56 -0700 Subject: [PATCH 0564/1635] ARM: dts: msm: Add audio device tree properties on sdmshrike Add audio device tree properties to enable audio support on sdmshrike. Change-Id: I38f616b727657199d5c6ba0e610956c8e865b780 Signed-off-by: Sudheer Papothi --- .../dts/qcom/sdmshrike-audio-overlay.dtsi | 4 ++++ arch/arm64/boot/dts/qcom/sdmshrike-cdp.dtsi | 5 +++++ arch/arm64/boot/dts/qcom/sdmshrike-mtp.dtsi | 1 + .../boot/dts/qcom/sdmshrike-pinctrl.dtsi | 20 ++++++++++--------- arch/arm64/boot/dts/qcom/sdmshrike.dtsi | 1 + 5 files changed, 22 insertions(+), 9 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sdmshrike-audio-overlay.dtsi b/arch/arm64/boot/dts/qcom/sdmshrike-audio-overlay.dtsi index b9ffea089e09..118b3097b78e 100644 --- a/arch/arm64/boot/dts/qcom/sdmshrike-audio-overlay.dtsi +++ b/arch/arm64/boot/dts/qcom/sdmshrike-audio-overlay.dtsi @@ -47,6 +47,10 @@ qcom,pahu-ext-clk-freq = <19200000>; + asoc-codec = <&stub_codec>, <&ext_disp_audio_codec>; + asoc-codec-names = "msm-stub-codec.1", + "msm-ext-disp-audio-codec-rx"; + qcom,wsa-max-devs = <2>; qcom,wsa-devs = <&wsa881x_0211>, <&wsa881x_0212>, <&wsa881x_0213>, <&wsa881x_0214>; diff --git a/arch/arm64/boot/dts/qcom/sdmshrike-cdp.dtsi b/arch/arm64/boot/dts/qcom/sdmshrike-cdp.dtsi index 4a58d7a9bcd8..c4590ddd3199 100644 --- a/arch/arm64/boot/dts/qcom/sdmshrike-cdp.dtsi +++ b/arch/arm64/boot/dts/qcom/sdmshrike-cdp.dtsi @@ -15,6 +15,7 @@ #include "sdmshrike-sde-display.dtsi" #include "sdmshrike-pmic-overlay.dtsi" +#include "sdmshrike-audio-overlay.dtsi" &soc { gpio_keys { @@ -45,6 +46,10 @@ linux,can-disable; }; }; + + sound-tavil { + qcom,us-euro-gpios = <&tavil_us_euro_switch>; + }; }; &pm855l_wled { diff --git a/arch/arm64/boot/dts/qcom/sdmshrike-mtp.dtsi b/arch/arm64/boot/dts/qcom/sdmshrike-mtp.dtsi index 4a58d7a9bcd8..c1c08a7afb7b 100644 --- a/arch/arm64/boot/dts/qcom/sdmshrike-mtp.dtsi +++ b/arch/arm64/boot/dts/qcom/sdmshrike-mtp.dtsi @@ -15,6 +15,7 @@ #include "sdmshrike-sde-display.dtsi" #include "sdmshrike-pmic-overlay.dtsi" +#include "sdmshrike-audio-overlay.dtsi" &soc { gpio_keys { diff --git a/arch/arm64/boot/dts/qcom/sdmshrike-pinctrl.dtsi b/arch/arm64/boot/dts/qcom/sdmshrike-pinctrl.dtsi index d013f24470e8..04766c9aa5d3 100644 --- a/arch/arm64/boot/dts/qcom/sdmshrike-pinctrl.dtsi +++ b/arch/arm64/boot/dts/qcom/sdmshrike-pinctrl.dtsi @@ -1730,16 +1730,18 @@ }; fsa_usbc_ana_en_n@100 { - mux { - pins = "gpio100"; - function = "gpio"; - }; + fsa_usbc_ana_en: fsa_usbc_ana_en { + mux { + pins = "gpio100"; + function = "gpio"; + }; - config { - pins = "gpio100"; - drive-strength = <2>; - bias-disable; - output-low; + config { + pins = "gpio100"; + drive-strength = <2>; + bias-disable; + output-low; + }; }; }; diff --git a/arch/arm64/boot/dts/qcom/sdmshrike.dtsi b/arch/arm64/boot/dts/qcom/sdmshrike.dtsi index 9fa44eb49eb6..68ce712bec88 100644 --- a/arch/arm64/boot/dts/qcom/sdmshrike.dtsi +++ b/arch/arm64/boot/dts/qcom/sdmshrike.dtsi @@ -1423,3 +1423,4 @@ #include "msm-arm-smmu-sdmshrike.dtsi" #include "sdmshrike-usb.dtsi" #include "sdmshrike-qupv3.dtsi" +#include "sm8150-audio.dtsi" -- GitLab From 8f72619e04d92887f116d94cffdf0559dabc17c7 Mon Sep 17 00:00:00 2001 From: Ingrid Gallardo Date: Thu, 22 Mar 2018 16:34:41 -0700 Subject: [PATCH 0565/1635] ARM: dts: msm: add proxy vote for DSI supplies for sm8150 For continuous splash screen feature, the display needs to be kept alive during the kernel boot up. Add proxy vote for all the regulator supplies needed to keep the display alive. Change-Id: Ia6229bffcd185ab2b6f9f9bdd6c42080187d5ccb Signed-off-by: Ingrid Gallardo --- arch/arm64/boot/dts/qcom/sm8150-gdsc.dtsi | 4 +++- arch/arm64/boot/dts/qcom/sm8150-regulator.dtsi | 9 +++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/sm8150-gdsc.dtsi b/arch/arm64/boot/dts/qcom/sm8150-gdsc.dtsi index b86390bfd574..f83eb2a10064 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-gdsc.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-gdsc.dtsi @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -193,6 +193,8 @@ reg = <0xaf03000 0x4>; qcom,support-hw-trigger; status = "disabled"; + proxy-supply = <&mdss_core_gdsc>; + qcom,proxy-consumer-enable; }; /* GDSCs in Graphics CC */ diff --git a/arch/arm64/boot/dts/qcom/sm8150-regulator.dtsi b/arch/arm64/boot/dts/qcom/sm8150-regulator.dtsi index 7d8768c343a3..9eead4264774 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-regulator.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-regulator.dtsi @@ -195,11 +195,14 @@ ; qcom,mode-threshold-currents = <0 1>; + proxy-supply = <&pm855_l5>; L5A: pm855_l5: regulator-pm855-l5 { regulator-name = "pm855_l5"; qcom,set = ; regulator-min-microvolt = <880000>; regulator-max-microvolt = <880000>; + qcom,proxy-consumer-enable; + qcom,proxy-consumer-current = <23800>; qcom,init-voltage = <880000>; qcom,init-mode = ; }; @@ -402,11 +405,14 @@ ; qcom,mode-threshold-currents = <0 10000>; + proxy-supply = <&pm855_l14>; L14A: pm855_l14: regulator-pm855-l14 { regulator-name = "pm855_l14"; qcom,set = ; regulator-min-microvolt = <1800000>; regulator-max-microvolt = <1880000>; + qcom,proxy-consumer-enable; + qcom,proxy-consumer-current = <115000>; qcom,init-voltage = <1800000>; qcom,init-mode = ; }; @@ -683,11 +689,14 @@ ; qcom,mode-threshold-currents = <0 1>; + proxy-supply = <&pm855l_l3>; L3C: pm855l_l3: regulator-pm855l-l3 { regulator-name = "pm855l_l3"; qcom,set = ; regulator-min-microvolt = <1200000>; regulator-max-microvolt = <1200000>; + qcom,proxy-consumer-enable; + qcom,proxy-consumer-current = <51800>; qcom,init-voltage = <1200000>; qcom,init-mode = ; }; -- GitLab From e8c41655ccd38d16fc938a450e925c908ceadd44 Mon Sep 17 00:00:00 2001 From: Ingrid Gallardo Date: Fri, 23 Mar 2018 11:34:35 -0700 Subject: [PATCH 0566/1635] ARM: dts: msm: reserve memory for continuous splash for sm8150 Reserve memory for continuous splash feature on sm8150 target. This memory buffer would be configured by the bootloader and needs to be retained until the first frame update in the kernel. Change-Id: Ibec432396f1da1780375b621bee39994152e8032 Signed-off-by: Ingrid Gallardo --- arch/arm64/boot/dts/qcom/sm8150.dtsi | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sm8150.dtsi b/arch/arm64/boot/dts/qcom/sm8150.dtsi index d20bb095acb2..8027843c339f 100644 --- a/arch/arm64/boot/dts/qcom/sm8150.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150.dtsi @@ -646,6 +646,11 @@ reg = <0 0x9e400000 0 0x1400000>; }; + cont_splash_memory: cont_splash_region@9c000000 { + reg = <0x0 0x9c000000 0x0 0x02400000>; + label = "cont_splash_region"; + }; + adsp_mem: adsp_region { compatible = "shared-dma-pool"; alloc-ranges = <0x0 0x00000000 0x0 0xffffffff>; -- GitLab From 7d914bdcbc83377cb2bfb139c11e145c6d6c5713 Mon Sep 17 00:00:00 2001 From: Ingrid Gallardo Date: Thu, 22 Mar 2018 17:12:53 -0700 Subject: [PATCH 0567/1635] defconfig: sm8150: enable proxy consumer driver for regulators Enable proxy consumer driver for regulators of sm8150 so that supply regulator initialization constraints can be enforced. Change-Id: Iac68091198e5604499b4d44ac1d0a9cc0cda9668 Signed-off-by: Ingrid Gallardo --- arch/arm64/configs/sm8150-perf_defconfig | 1 + arch/arm64/configs/sm8150_defconfig | 1 + 2 files changed, 2 insertions(+) diff --git a/arch/arm64/configs/sm8150-perf_defconfig b/arch/arm64/configs/sm8150-perf_defconfig index 7c9a5e1913e1..24537273acc7 100644 --- a/arch/arm64/configs/sm8150-perf_defconfig +++ b/arch/arm64/configs/sm8150-perf_defconfig @@ -337,6 +337,7 @@ CONFIG_QTI_BCL_PMIC5=y CONFIG_QTI_BCL_SOC_DRIVER=y CONFIG_MFD_SPMI_PMIC=y CONFIG_REGULATOR_FIXED_VOLTAGE=y +CONFIG_REGULATOR_PROXY_CONSUMER=y CONFIG_REGULATOR_QPNP_LCDB=y CONFIG_REGULATOR_REFGEN=y CONFIG_REGULATOR_RPMH=y diff --git a/arch/arm64/configs/sm8150_defconfig b/arch/arm64/configs/sm8150_defconfig index a35eaa59a543..c442d51ccfc6 100644 --- a/arch/arm64/configs/sm8150_defconfig +++ b/arch/arm64/configs/sm8150_defconfig @@ -348,6 +348,7 @@ CONFIG_QTI_BCL_PMIC5=y CONFIG_QTI_BCL_SOC_DRIVER=y CONFIG_MFD_SPMI_PMIC=y CONFIG_REGULATOR_FIXED_VOLTAGE=y +CONFIG_REGULATOR_PROXY_CONSUMER=y CONFIG_REGULATOR_QPNP_LCDB=y CONFIG_REGULATOR_REFGEN=y CONFIG_REGULATOR_RPMH=y -- GitLab From cf315933b2654a2ee8f753e07963b189a3944951 Mon Sep 17 00:00:00 2001 From: Sudarshan Rajagopalan Date: Wed, 18 Apr 2018 14:27:28 -0700 Subject: [PATCH 0568/1635] ARM: dts: msm: Update SID entries for iommu test devices for sm8150 Update the sid entries as per the new smmu configuration settings for ksgl and apps test devices. Change-Id: I7cac8ea4aac5aa3d01330061dfc1d8f11395189a Signed-off-by: Sudarshan Rajagopalan --- .../boot/dts/qcom/msm-arm-smmu-sm8150.dtsi | 24 ++++++++++--------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/msm-arm-smmu-sm8150.dtsi b/arch/arm64/boot/dts/qcom/msm-arm-smmu-sm8150.dtsi index 1af74823cc0b..c89f2a3569ce 100644 --- a/arch/arm64/boot/dts/qcom/msm-arm-smmu-sm8150.dtsi +++ b/arch/arm64/boot/dts/qcom/msm-arm-smmu-sm8150.dtsi @@ -361,22 +361,24 @@ kgsl_iommu_test_device { compatible = "iommu-debug-test"; - /* - * 0x7 isn't a valid sid, but should pass the sid sanity check. - * We just need _something_ here to get this node recognized by - * the SMMU driver. Our test uses ATOS, which doesn't use SIDs - * anyways, so using a dummy value is ok. - */ iommus = <&kgsl_smmu 0x7 0>; }; + kgsl_iommu_coherent_test_device { + compatible = "iommu-debug-test"; + iommus = <&kgsl_smmu 0x9 0>; + dma-coherent; + }; + apps_iommu_test_device { compatible = "iommu-debug-test"; - /* - * This SID belongs to TSIF. We can't use a fake SID for - * the apps_smmu device. - */ - iommus = <&apps_smmu 0x20 0>; + iommus = <&apps_smmu 0x21 0>; + }; + + apps_iommu_coherent_test_device { + compatible = "iommu-debug-test"; + iommus = <&apps_smmu 0x23 0>; + dma-coherent; }; }; -- GitLab From 2614f5cf5dcde27e8ab76733cebe50fde710d222 Mon Sep 17 00:00:00 2001 From: Fenglin Wu Date: Fri, 20 Apr 2018 10:43:30 +0800 Subject: [PATCH 0569/1635] ARM: dts: msm: Add mlp466076 3250mAh battery profile to SM8150 QRD Add mlp466076 3250mAh battery profile for GEN4 FG to SM8150 QRD where mlp466076 battery will be used. Change-Id: I638e195ae42f8dec5fde66773a4dadf3e49cfa2c Signed-off-by: Fenglin Wu --- arch/arm64/boot/dts/qcom/sm8150-qrd.dtsi | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sm8150-qrd.dtsi b/arch/arm64/boot/dts/qcom/sm8150-qrd.dtsi index cf63ff6565ec..f3d988ae3a7b 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-qrd.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-qrd.dtsi @@ -34,6 +34,15 @@ qca,bt-vdd-pa-current-level = <0>; /* LPM/PFM */ qca,bt-vdd-ldo-current-level = <0>; /* LPM/PFM */ }; + + qrd_batterydata: qcom,battery-data { + qcom,batt-id-range-pct = <15>; + #include "fg-gen4-batterydata-mlp466076-3250mah.dtsi" + }; +}; + +&pm855b_fg { + qcom,battery-data = <&qrd_batterydata>; }; &soc { -- GitLab From 5ec63ad20032d4f64cbd903d1684473b8abea775 Mon Sep 17 00:00:00 2001 From: Jishnu Prakash Date: Tue, 17 Apr 2018 19:12:16 +0530 Subject: [PATCH 0570/1635] ARM: dts: msm: Add thermal zone configuration for QCS405 Add usr thermal zone configurations for all TSENS in QCS405. Change-Id: I7d17720247ef8b2d96f53266b847dc7a0c8ca15e Signed-off-by: Jishnu Prakash --- arch/arm64/boot/dts/qcom/qcs405-thermal.dtsi | 155 +++++++++++++++++++ arch/arm64/boot/dts/qcom/qcs405.dtsi | 3 + 2 files changed, 158 insertions(+) create mode 100644 arch/arm64/boot/dts/qcom/qcs405-thermal.dtsi diff --git a/arch/arm64/boot/dts/qcom/qcs405-thermal.dtsi b/arch/arm64/boot/dts/qcom/qcs405-thermal.dtsi new file mode 100644 index 000000000000..63a49cd149ec --- /dev/null +++ b/arch/arm64/boot/dts/qcom/qcs405-thermal.dtsi @@ -0,0 +1,155 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include + +&thermal_zones { + aoss-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&tsens0 0>; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + cpuss-0-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&tsens0 1>; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + cpuss-1-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&tsens0 2>; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + cpuss-2-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&tsens0 3>; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + cpuss-3-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens0 4>; + thermal-governor = "user_space"; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + mhm-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens0 5>; + thermal-governor = "user_space"; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + gpu-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens0 6>; + thermal-governor = "user_space"; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + q6-hvx-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens0 7>; + thermal-governor = "user_space"; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + lpass-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens0 8>; + thermal-governor = "user_space"; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + wlan-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens0 9>; + thermal-governor = "user_space"; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/qcs405.dtsi b/arch/arm64/boot/dts/qcom/qcs405.dtsi index c9066a81296f..174f84a32ca8 100644 --- a/arch/arm64/boot/dts/qcom/qcs405.dtsi +++ b/arch/arm64/boot/dts/qcom/qcs405.dtsi @@ -244,9 +244,12 @@ interrupt-names = "tsens-upper-lower"; #thermal-sensor-cells = <1>; }; + + thermal_zones: thermal-zones {}; }; #include "qcs405-gdsc.dtsi" +#include "qcs405-thermal.dtsi" &gdsc_mdss { status = "ok"; -- GitLab From 4438d0403a49eacf2b3db49d5557b9d9df813ed9 Mon Sep 17 00:00:00 2001 From: Naresh Maradana Date: Mon, 19 Mar 2018 15:05:08 +0530 Subject: [PATCH 0571/1635] seemp: port instrumentation and logging service MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Port seemp related instrumentation and logging service to from msm-4.9 to msm-4.14. This change serves two purposes: - Enable logging service for API events âogged events are read by userspace components. - Log relevant kernel events. Change-Id: I6eeadc0cb0033d167dde49703269946c77f2acda Signed-off-by: Yida Wang Signed-off-by: Naresh Maradana --- drivers/platform/msm/Kconfig | 8 + drivers/platform/msm/Makefile | 1 + drivers/platform/msm/seemp_core/Makefile | 3 + .../msm/seemp_core/seemp_event_encoder.c | 180 +++++ .../msm/seemp_core/seemp_event_encoder.h | 21 + drivers/platform/msm/seemp_core/seemp_logk.c | 687 ++++++++++++++++++ drivers/platform/msm/seemp_core/seemp_logk.h | 161 ++++ .../platform/msm/seemp_core/seemp_ringbuf.c | 161 ++++ .../platform/msm/seemp_core/seemp_ringbuf.h | 29 + include/linux/seemp_instrumentation.h | 156 ++++ include/uapi/linux/Kbuild | 2 + include/uapi/linux/seemp_api.h | 395 ++++++++++ include/uapi/linux/seemp_param_id.h | 90 +++ net/socket.c | 4 + 14 files changed, 1898 insertions(+) create mode 100644 drivers/platform/msm/seemp_core/Makefile create mode 100644 drivers/platform/msm/seemp_core/seemp_event_encoder.c create mode 100644 drivers/platform/msm/seemp_core/seemp_event_encoder.h create mode 100644 drivers/platform/msm/seemp_core/seemp_logk.c create mode 100644 drivers/platform/msm/seemp_core/seemp_logk.h create mode 100644 drivers/platform/msm/seemp_core/seemp_ringbuf.c create mode 100644 drivers/platform/msm/seemp_core/seemp_ringbuf.h create mode 100644 include/linux/seemp_instrumentation.h create mode 100644 include/uapi/linux/seemp_api.h create mode 100644 include/uapi/linux/seemp_param_id.h diff --git a/drivers/platform/msm/Kconfig b/drivers/platform/msm/Kconfig index dc01db3fa2b7..9a7e6980f990 100644 --- a/drivers/platform/msm/Kconfig +++ b/drivers/platform/msm/Kconfig @@ -169,4 +169,12 @@ config MSM_11AD If you choose to build it as a module, it will be called msm_11ad_proxy. +config SEEMP_CORE + tristate "SEEMP Core" + help + This option enables QTI Snapdragron Smart Protection to detect + anomalies in various activities. It records task activities in + a log and rates the actions according to whether a typical user would + use the tools. + endmenu diff --git a/drivers/platform/msm/Makefile b/drivers/platform/msm/Makefile index 6e36268a7502..12149fde88fe 100644 --- a/drivers/platform/msm/Makefile +++ b/drivers/platform/msm/Makefile @@ -10,3 +10,4 @@ obj-$(CONFIG_GSI) += gsi/ obj-$(CONFIG_IPA) += ipa/ obj-$(CONFIG_IPA3) += ipa/ obj-$(CONFIG_MSM_11AD) += msm_11ad/ +obj-$(CONFIG_SEEMP_CORE) += seemp_core/ diff --git a/drivers/platform/msm/seemp_core/Makefile b/drivers/platform/msm/seemp_core/Makefile new file mode 100644 index 000000000000..a26db430718d --- /dev/null +++ b/drivers/platform/msm/seemp_core/Makefile @@ -0,0 +1,3 @@ +ccflags-y += -Iinclude/linux +obj-$(CONFIG_SEEMP_CORE) += seemp_core.o +seemp_core-objs:= seemp_logk.o seemp_ringbuf.o seemp_event_encoder.o \ No newline at end of file diff --git a/drivers/platform/msm/seemp_core/seemp_event_encoder.c b/drivers/platform/msm/seemp_core/seemp_event_encoder.c new file mode 100644 index 000000000000..e73b69c11e3c --- /dev/null +++ b/drivers/platform/msm/seemp_core/seemp_event_encoder.c @@ -0,0 +1,180 @@ +/* + * Copyright (c) 2015, 2017-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include "seemp_logk.h" +#include "seemp_event_encoder.h" + +static char *scan_id(char *s); +static void encode_seemp_section(char *section_start, char *section_eq, + char *section_end, bool param, bool numeric, + int id, __s32 numeric_value); + +static void check_param_range(char *section_eq, bool param, + bool *numeric, int val_len, __s32 *numeric_value) +{ + long long_value = 0; + + if (param && *numeric) { + /*check if 2 bytes & in[-99999,999999]*/ + *numeric = (val_len >= 2) && (val_len <= 6); + if (*numeric) { + if (kstrtol(section_eq + 1, 10, &long_value) + != 0) { + *numeric = false; + } else { + *numeric_value = (__s32)long_value; + /* We are checking whether the value + * lies within 16bits + */ + *numeric = (long_value >= -32768) && + (long_value <= 32767); + } + } + } +} + +void encode_seemp_params(struct seemp_logk_blk *blk) +{ + struct seemp_logk_blk tmp; + char *s = 0; + char *msg_section_start = 0; + char *msg_section_eq = 0; + char *msg_s = 0; + + memcpy(tmp.payload.msg, blk->payload.msg, BLK_MAX_MSG_SZ); + s = tmp.payload.msg + 1; + tmp.payload.msg[BLK_MAX_MSG_SZ - 1] = 0; /* zero-terminate */ + + while (true) { + char *section_start = s; + char *section_eq = scan_id(s); + bool param = (section_eq - section_start >= 2) && + (*section_eq == '=') && (section_eq[1] != ' '); + bool numeric = false; + int id = -1; + __s32 numeric_value = 0; + int id_len; + int val_len; + char ch; + + if (param) { + id = param_id_index(section_start, section_eq); + + if (id < 0) + param = false; + } + + if (!param) { + s = section_eq; + while ((*s != 0) && (*s != ',')) + s++; + } else { + s = section_eq + 1; /* equal sign */ + numeric = (*s == '-') || ((*s >= '0') && (*s <= '9')); + + if (numeric) + s++; /* first char of number */ + + while ((*s != 0) && (*s != ',')) { + if (*s == '=') + param = false; + else if (!((*s >= '0') && (*s <= '9'))) + numeric = false; + + s++; + } + + if (param) { + id_len = section_eq - section_start; + val_len = s - (section_eq + 1); + param = (id_len >= 2) && (id_len <= 31) + && (val_len <= 31); + ch = *s; + *s = 0; + + check_param_range(section_eq, param, + &numeric, val_len, &numeric_value); + *s = ch; + } + } + + msg_section_start = blk->payload.msg + (section_start - + tmp.payload.msg); + msg_section_eq = blk->payload.msg + (section_eq - + tmp.payload.msg); + msg_s = blk->payload.msg + (s - tmp.payload.msg); + encode_seemp_section(msg_section_start, msg_section_eq, + msg_s, param, numeric, id, numeric_value); + + if (*s == 0) + break; + + s++; + } + + blk->len = s - blk->payload.msg; +} + +static char *scan_id(char *s) +{ + while ((*s == '_') || + ((*s >= 'A') && (*s <= 'Z')) || + ((*s >= 'a') && (*s <= 'z'))) { + s++; + } + + return s; +} + +static void encode_seemp_section(char *section_start, char *section_eq, + char *section_end, bool param, bool numeric, + int id, __s32 numeric_value) +{ + param = param && (section_eq + 1 < section_end); + + if (!param) { + /* Encode skip section */ + int skip_len = section_end - section_start; + char skip_len_hi = skip_len & 0xE0; + char skip_len_lo = skip_len & 0x1F; + + if (skip_len < 32) { + section_start[-1] = 0xC0 | skip_len_lo; + /* [1:1:0:0 0000] */ + } else { + section_start[-1] = 0xE0 | skip_len_lo; + /* [1:1:1:0 0000] */ + + if (skip_len_hi & 0x20) + section_start[0] |= 0x80; + + if (skip_len_hi & 0x40) + section_start[1] |= 0x80; + + if (skip_len_hi & 0x80) + section_start[2] |= 0x80; + } + } else { + /* Encode ID=VALUE section */ + char id_len = section_eq - section_start; + char value_len = section_end - (section_eq + 1); + + section_start[-1] = 0x00 | id_len; + *(__s16 *)section_start = id; + section_eq[0] = (!numeric ? 0x80 : 0x00) | value_len; + + if (numeric) + *(__s16 *)(section_eq + 1) = numeric_value; + } +} diff --git a/drivers/platform/msm/seemp_core/seemp_event_encoder.h b/drivers/platform/msm/seemp_core/seemp_event_encoder.h new file mode 100644 index 000000000000..a64b18b806cc --- /dev/null +++ b/drivers/platform/msm/seemp_core/seemp_event_encoder.h @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2015, 2017-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __SEEMP_EVENT_ENCODER_H__ +#define __SEEMP_EVENT_ENCODER_H__ + +#include "seemp_logk.h" + +void encode_seemp_params(struct seemp_logk_blk *blk); + +#endif /* __SEEMP_EVENT_ENCODER_H__ */ diff --git a/drivers/platform/msm/seemp_core/seemp_logk.c b/drivers/platform/msm/seemp_core/seemp_logk.c new file mode 100644 index 000000000000..ca77f925c06b --- /dev/null +++ b/drivers/platform/msm/seemp_core/seemp_logk.c @@ -0,0 +1,687 @@ +/* + * Copyright (c) 2014-2015, 2017-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#define pr_fmt(fmt) "seemp: %s: " fmt, __func__ + +#include "seemp_logk.h" +#include "seemp_ringbuf.h" + +#ifndef VM_RESERVED +#define VM_RESERVED (VM_DONTEXPAND | VM_DONTDUMP) +#endif + +#define MASK_BUFFER_SIZE 256 +#define FOUR_MB 4 +#define YEAR_BASE 1900 + +static struct seemp_logk_dev *slogk_dev; + +static unsigned int ring_sz = FOUR_MB; + +/* + * default is besteffort, apps do not get blocked + */ +static unsigned int block_apps; + + +/* + * When this flag is turned on, + * kmalloc should be used for ring buf allocation + * otherwise it is vmalloc. + * default is to use vmalloc + * kmalloc has a limit of 4MB + */ +unsigned int kmalloc_flag; + +static struct class *cl; + +static rwlock_t filter_lock; +static struct seemp_source_mask *pmask; +static unsigned int num_sources; + +static long seemp_logk_reserve_rdblks( + struct seemp_logk_dev *sdev, unsigned long arg); +static long seemp_logk_set_mask(unsigned long arg); +static long seemp_logk_set_mapping(unsigned long arg); +static long seemp_logk_check_filter(unsigned long arg); + +void* (*seemp_logk_kernel_begin)(char **buf); + +void (*seemp_logk_kernel_end)(void *blck); + +/* + * the last param is the permission bits * + * kernel logging is done in three steps: + * (1) fetch a block, fill everything except payload. + * (2) return payload pointer to the caller. + * (3) caller fills its data directly into the payload area. + * (4) caller invoked finish_record(), to finish writing. + */ +void *seemp_logk_kernel_start_record(char **buf) +{ + struct seemp_logk_blk *blk; + struct timespec now; + struct tm ts; + int idx; + int ret; + + DEFINE_WAIT(write_wait); + + ret = 0; + idx = 0; + now = current_kernel_time(); + blk = ringbuf_fetch_wr_block(slogk_dev); + if (!blk) { + /* + * there is no blk to write + * if block_apps == 0; quietly return + */ + if (!block_apps) { + *buf = NULL; + return NULL; + } + /*else wait for the blks to be available*/ + while (1) { + mutex_lock(&slogk_dev->lock); + prepare_to_wait(&slogk_dev->writers_wq, + &write_wait, TASK_INTERRUPTIBLE); + ret = (slogk_dev->num_write_avail_blks <= 0); + if (!ret) { + /* don't have to wait*/ + break; + } + mutex_unlock(&slogk_dev->lock); + if (signal_pending(current)) { + ret = -EINTR; + break; + } + schedule(); + } + + finish_wait(&slogk_dev->writers_wq, &write_wait); + if (ret) + return NULL; + + idx = slogk_dev->write_idx; + slogk_dev->write_idx = + (slogk_dev->write_idx + 1) % slogk_dev->num_tot_blks; + slogk_dev->num_write_avail_blks--; + slogk_dev->num_write_in_prog_blks++; + slogk_dev->num_writers++; + + blk = &slogk_dev->ring[idx]; + /*mark block invalid*/ + blk->status = 0x0; + mutex_unlock(&slogk_dev->lock); + } + + blk->version = OBSERVER_VERSION; + blk->pid = current->tgid; + blk->tid = current->pid; + blk->uid = (current_uid()).val; + blk->sec = now.tv_sec; + blk->nsec = now.tv_nsec; + strlcpy(blk->appname, current->comm, TASK_COMM_LEN); + time_to_tm(now.tv_sec, 0, &ts); + ts.tm_year += YEAR_BASE; + ts.tm_mon += 1; + + snprintf(blk->ts, TS_SIZE, "%04ld-%02d-%02d %02d:%02d:%02d", + ts.tm_year, ts.tm_mon, ts.tm_mday, + ts.tm_hour, ts.tm_min, ts.tm_sec); + + *buf = blk->payload.msg; + + return blk; +} + +void seemp_logk_kernel_end_record(void *blck) +{ + struct seemp_logk_blk *blk = (struct seemp_logk_blk *)blck; + + if (blk) { + /*update status at the very end*/ + blk->status |= 0x1; + blk->uid = (current_uid()).val; + + ringbuf_finish_writer(slogk_dev, blk); + } +} + +static int seemp_logk_usr_record(const char __user *buf, size_t count) +{ + struct seemp_logk_blk *blk; + struct seemp_logk_blk usr_blk; + struct seemp_logk_blk *local_blk; + struct timespec now; + struct tm ts; + int idx, ret; + + DEFINE_WAIT(write_wait); + + if (buf) { + local_blk = (struct seemp_logk_blk *)buf; + if (copy_from_user(&usr_blk.pid, &local_blk->pid, + sizeof(usr_blk.pid)) != 0) + return -EFAULT; + if (copy_from_user(&usr_blk.tid, &local_blk->tid, + sizeof(usr_blk.tid)) != 0) + return -EFAULT; + if (copy_from_user(&usr_blk.uid, &local_blk->uid, + sizeof(usr_blk.uid)) != 0) + return -EFAULT; + if (copy_from_user(&usr_blk.len, &local_blk->len, + sizeof(usr_blk.len)) != 0) + return -EFAULT; + if (copy_from_user(&usr_blk.payload, &local_blk->payload, + sizeof(struct blk_payload)) != 0) + return -EFAULT; + } else { + return -EFAULT; + } + idx = ret = 0; + now = current_kernel_time(); + blk = ringbuf_fetch_wr_block(slogk_dev); + if (!blk) { + if (!block_apps) + return 0; + while (1) { + mutex_lock(&slogk_dev->lock); + prepare_to_wait(&slogk_dev->writers_wq, + &write_wait, + TASK_INTERRUPTIBLE); + ret = (slogk_dev->num_write_avail_blks <= 0); + if (!ret) + break; + mutex_unlock(&slogk_dev->lock); + if (signal_pending(current)) { + ret = -EINTR; + break; + } + schedule(); + } + finish_wait(&slogk_dev->writers_wq, &write_wait); + if (ret) + return -EINTR; + + idx = slogk_dev->write_idx; + slogk_dev->write_idx = + (slogk_dev->write_idx + 1) % slogk_dev->num_tot_blks; + slogk_dev->num_write_avail_blks--; + slogk_dev->num_write_in_prog_blks++; + slogk_dev->num_writers++; + blk = &slogk_dev->ring[idx]; + /*mark block invalid*/ + blk->status = 0x0; + mutex_unlock(&slogk_dev->lock); + } + if (usr_blk.len > sizeof(struct blk_payload)-1) + usr_blk.len = sizeof(struct blk_payload)-1; + + memcpy(&blk->payload, &usr_blk.payload, sizeof(struct blk_payload)); + blk->pid = usr_blk.pid; + blk->uid = usr_blk.uid; + blk->tid = usr_blk.tid; + blk->sec = now.tv_sec; + blk->nsec = now.tv_nsec; + time_to_tm(now.tv_sec, 0, &ts); + ts.tm_year += YEAR_BASE; + ts.tm_mon += 1; + snprintf(blk->ts, TS_SIZE, "%02ld-%02d-%02d %02d:%02d:%02d", + ts.tm_year, ts.tm_mon, ts.tm_mday, + ts.tm_hour, ts.tm_min, ts.tm_sec); + strlcpy(blk->appname, current->comm, TASK_COMM_LEN); + blk->status |= 0x1; + ringbuf_finish_writer(slogk_dev, blk); + return ret; +} + +static void seemp_logk_attach(void) +{ + seemp_logk_kernel_end = seemp_logk_kernel_end_record; + seemp_logk_kernel_begin = seemp_logk_kernel_start_record; +} + +static void seemp_logk_detach(void) +{ + seemp_logk_kernel_begin = NULL; + seemp_logk_kernel_end = NULL; +} + +static ssize_t +seemp_logk_write(struct file *file, const char __user *buf, size_t count, + loff_t *ppos) +{ + return seemp_logk_usr_record(buf, count); +} + +static int +seemp_logk_open(struct inode *inode, struct file *filp) +{ + int ret; + + /*disallow seeks on this file*/ + ret = nonseekable_open(inode, filp); + if (ret) { + pr_err("ret= %d\n", ret); + return ret; + } + + slogk_dev->minor = iminor(inode); + filp->private_data = slogk_dev; + + return 0; +} + +static bool seemp_logk_get_bit_from_vector(__u8 *pVec, __u32 index) +{ + unsigned int byte_num = index/8; + unsigned int bit_num = index%8; + unsigned char byte; + + if (DIV_ROUND_UP(index, 8) > MASK_BUFFER_SIZE) + return false; + + byte = pVec[byte_num]; + + return !(byte & (1 << bit_num)); +} + +static long seemp_logk_ioctl(struct file *filp, unsigned int cmd, + unsigned long arg) +{ + struct seemp_logk_dev *sdev; + int ret; + + sdev = (struct seemp_logk_dev *) filp->private_data; + + if (cmd == SEEMP_CMD_RESERVE_RDBLKS) { + return seemp_logk_reserve_rdblks(sdev, arg); + } else if (cmd == SEEMP_CMD_RELEASE_RDBLKS) { + mutex_lock(&sdev->lock); + sdev->read_idx = (sdev->read_idx + sdev->num_read_in_prog_blks) + % sdev->num_tot_blks; + sdev->num_write_avail_blks += sdev->num_read_in_prog_blks; + ret = sdev->num_read_in_prog_blks; + sdev->num_read_in_prog_blks = 0; + /*wake up any waiting writers*/ + mutex_unlock(&sdev->lock); + if (ret && block_apps) + wake_up_interruptible(&sdev->writers_wq); + } else if (cmd == SEEMP_CMD_GET_RINGSZ) { + if (copy_to_user((unsigned int *)arg, &sdev->ring_sz, + sizeof(unsigned int))) + return -EFAULT; + } else if (cmd == SEEMP_CMD_GET_BLKSZ) { + if (copy_to_user((unsigned int *)arg, &sdev->blk_sz, + sizeof(unsigned int))) + return -EFAULT; + } else if (cmd == SEEMP_CMD_SET_MASK) { + return seemp_logk_set_mask(arg); + } else if (cmd == SEEMP_CMD_SET_MAPPING) { + return seemp_logk_set_mapping(arg); + } else if (cmd == SEEMP_CMD_CHECK_FILTER) { + return seemp_logk_check_filter(arg); + } + pr_err("Invalid Request %X\n", cmd); + return -ENOIOCTLCMD; +} + +static long seemp_logk_reserve_rdblks( + struct seemp_logk_dev *sdev, unsigned long arg) +{ + int ret; + struct read_range rrange; + + DEFINE_WAIT(read_wait); + + mutex_lock(&sdev->lock); + if (sdev->num_writers > 0 || sdev->num_read_avail_blks <= 0) { + ret = -EPERM; + pr_debug("(reserve): blocking, cannot read.\n"); + pr_debug("num_writers=%d num_read_avail_blks=%d\n", + sdev->num_writers, + sdev->num_read_avail_blks); + mutex_unlock(&sdev->lock); + /* + * unlock the device + * wait on a wait queue + * after wait, grab the dev lock again + */ + while (1) { + mutex_lock(&sdev->lock); + prepare_to_wait(&sdev->readers_wq, &read_wait, + TASK_INTERRUPTIBLE); + ret = (sdev->num_writers > 0 || + sdev->num_read_avail_blks <= 0); + if (!ret) { + /*don't have to wait*/ + break; + } + mutex_unlock(&sdev->lock); + if (signal_pending(current)) { + ret = -EINTR; + break; + } + schedule(); + } + + finish_wait(&sdev->readers_wq, &read_wait); + if (ret) + return -EINTR; + } + + /*sdev->lock is held at this point*/ + sdev->num_read_in_prog_blks = sdev->num_read_avail_blks; + sdev->num_read_avail_blks = 0; + rrange.start_idx = sdev->read_idx; + rrange.num = sdev->num_read_in_prog_blks; + mutex_unlock(&sdev->lock); + + if (copy_to_user((unsigned int *)arg, &rrange, + sizeof(struct read_range))) + return -EFAULT; + + return 0; +} + +static long seemp_logk_set_mask(unsigned long arg) +{ + __u8 buffer[256]; + int i; + unsigned int num_elements; + + if (copy_from_user(&num_elements, + (unsigned int __user *) arg, sizeof(unsigned int))) + return -EFAULT; + + read_lock(&filter_lock); + if (num_sources == 0) { + read_unlock(&filter_lock); + return -EINVAL; + } + + if (num_elements == 0 || + DIV_ROUND_UP(num_sources, 8) > MASK_BUFFER_SIZE) { + read_unlock(&filter_lock); + return -EINVAL; + } + + if (copy_from_user(buffer, + (__u8 *)arg, DIV_ROUND_UP(num_sources, 8))) { + read_unlock(&filter_lock); + return -EFAULT; + } + + read_unlock(&filter_lock); + write_lock(&filter_lock); + if (num_elements != num_sources) { + write_unlock(&filter_lock); + return -EPERM; + } + + for (i = 0; i < num_sources; i++) { + pmask[i].isOn = + seemp_logk_get_bit_from_vector( + (__u8 *)buffer, i); + } + write_unlock(&filter_lock); + return 0; +} + +static long seemp_logk_set_mapping(unsigned long arg) +{ + __u32 num_elements; + __u32 *pbuffer; + int i; + struct seemp_source_mask *pnewmask; + + if (copy_from_user(&num_elements, + (__u32 __user *)arg, sizeof(__u32))) + return -EFAULT; + + if ((num_elements == 0) || (num_elements > + (UINT_MAX / sizeof(struct seemp_source_mask)))) + return -EFAULT; + + write_lock(&filter_lock); + if (pmask != NULL) { + /* + * Mask is getting set again. + * seemp_core was probably restarted. + */ + struct seemp_source_mask *ptempmask; + + num_sources = 0; + ptempmask = pmask; + pmask = NULL; + kfree(ptempmask); + } + write_unlock(&filter_lock); + pbuffer = kmalloc_array(num_elements, + sizeof(struct seemp_source_mask), GFP_KERNEL); + if (pbuffer == NULL) + return -ENOMEM; + + /* + * Use our new table as scratch space for now. + * We copy an ordered list of hash values into our buffer. + */ + if (copy_from_user(pbuffer, &((__u32 __user *)arg)[1], + num_elements*sizeof(unsigned int))) { + kfree(pbuffer); + return -EFAULT; + } + /* + * We arrange the user data into a more usable form. + * This is done in-place. + */ + pnewmask = (struct seemp_source_mask *) pbuffer; + for (i = num_elements - 1; i >= 0; i--) { + pnewmask[i].hash = pbuffer[i]; + /* Observer is off by default*/ + pnewmask[i].isOn = 0; + } + write_lock(&filter_lock); + pmask = pnewmask; + num_sources = num_elements; + write_unlock(&filter_lock); + return 0; +} + +static long seemp_logk_check_filter(unsigned long arg) +{ + int i; + unsigned int hash = (unsigned int) arg; + + /* + * This lock may be a bit long. + * If it is a problem, it can be fixed. + */ + read_lock(&filter_lock); + for (i = 0; i < num_sources; i++) { + if (hash == pmask[i].hash) { + int result = pmask[i].isOn; + + read_unlock(&filter_lock); + return result; + } + } + read_unlock(&filter_lock); + return 0; +} + +static int seemp_logk_mmap(struct file *filp, + struct vm_area_struct *vma) +{ + int ret; + char *vptr; + unsigned long length, pfn; + unsigned long start = vma->vm_start; + + length = vma->vm_end - vma->vm_start; + + if (length > (unsigned long) slogk_dev->ring_sz) { + pr_err("len check failed\n"); + return -EIO; + } + + vma->vm_flags |= VM_RESERVED | VM_SHARED; + vptr = (char *) slogk_dev->ring; + ret = 0; + + if (kmalloc_flag) { + ret = remap_pfn_range(vma, + start, + virt_to_phys((void *) + ((unsigned long)slogk_dev->ring)) >> PAGE_SHIFT, + length, + vma->vm_page_prot); + if (ret != 0) { + pr_err("remap_pfn_range() fails with ret = %d\n", + ret); + return -EAGAIN; + } + } else { + while (length > 0) { + pfn = vmalloc_to_pfn(vptr); + + ret = remap_pfn_range(vma, start, pfn, PAGE_SIZE, + vma->vm_page_prot); + if (ret < 0) { + pr_err("remap_pfn_range() fails with ret = %d\n", + ret); + return ret; + } + start += PAGE_SIZE; + vptr += PAGE_SIZE; + length -= PAGE_SIZE; + } + } + + return 0; +} + +static const struct file_operations seemp_logk_fops = { + .write = seemp_logk_write, + .open = seemp_logk_open, + .unlocked_ioctl = seemp_logk_ioctl, + .compat_ioctl = seemp_logk_ioctl, + .mmap = seemp_logk_mmap, +}; + +__init int seemp_logk_init(void) +{ + int ret; + int devno = 0; + + num_sources = 0; + kmalloc_flag = 0; + block_apps = 0; + pmask = NULL; + + if (kmalloc_flag && ring_sz > FOUR_MB) { + pr_err("kmalloc cannot allocate > 4MB\n"); + return -ENOMEM; + } + + ring_sz = ring_sz * SZ_1M; + if (ring_sz <= 0) { + pr_err("Too small a ring_sz=%d\n", ring_sz); + return -EINVAL; + } + + slogk_dev = kmalloc(sizeof(*slogk_dev), GFP_KERNEL); + if (slogk_dev == NULL) + return -ENOMEM; + + slogk_dev->ring_sz = ring_sz; + slogk_dev->blk_sz = sizeof(struct seemp_logk_blk); + /*initialize ping-pong buffers*/ + ret = ringbuf_init(slogk_dev); + if (ret < 0) { + pr_err("Init Failed, ret = %d\n", ret); + goto pingpong_fail; + } + + ret = alloc_chrdev_region(&devno, 0, seemp_LOGK_NUM_DEVS, + seemp_LOGK_DEV_NAME); + if (ret < 0) { + pr_err("alloc_chrdev_region failed with ret = %d\n", + ret); + goto register_fail; + } + + slogk_dev->major = MAJOR(devno); + + pr_debug("logk: major# = %d\n", slogk_dev->major); + + cl = class_create(THIS_MODULE, seemp_LOGK_DEV_NAME); + if (cl == NULL) { + pr_err("class create failed"); + goto cdev_fail; + } + if (device_create(cl, NULL, devno, NULL, + seemp_LOGK_DEV_NAME) == NULL) { + pr_err("device create failed"); + goto class_destroy_fail; + } + cdev_init(&(slogk_dev->cdev), &seemp_logk_fops); + + slogk_dev->cdev.owner = THIS_MODULE; + ret = cdev_add(&(slogk_dev->cdev), MKDEV(slogk_dev->major, 0), 1); + if (ret) { + pr_err("cdev_add failed with ret = %d", ret); + goto class_destroy_fail; + } + + seemp_logk_attach(); + mutex_init(&slogk_dev->lock); + init_waitqueue_head(&slogk_dev->readers_wq); + init_waitqueue_head(&slogk_dev->writers_wq); + rwlock_init(&filter_lock); + return 0; +class_destroy_fail: + class_destroy(cl); +cdev_fail: + unregister_chrdev_region(devno, seemp_LOGK_NUM_DEVS); +register_fail: + ringbuf_cleanup(slogk_dev); +pingpong_fail: + kfree(slogk_dev); + return -EPERM; +} + +__exit void seemp_logk_cleanup(void) +{ + dev_t devno = MKDEV(slogk_dev->major, slogk_dev->minor); + + seemp_logk_detach(); + + cdev_del(&slogk_dev->cdev); + + unregister_chrdev_region(devno, seemp_LOGK_NUM_DEVS); + ringbuf_cleanup(slogk_dev); + kfree(slogk_dev); + + if (pmask != NULL) { + kfree(pmask); + pmask = NULL; + } +} + +module_init(seemp_logk_init); +module_exit(seemp_logk_cleanup); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("seemp Observer"); diff --git a/drivers/platform/msm/seemp_core/seemp_logk.h b/drivers/platform/msm/seemp_core/seemp_logk.h new file mode 100644 index 000000000000..acef9fa59558 --- /dev/null +++ b/drivers/platform/msm/seemp_core/seemp_logk.h @@ -0,0 +1,161 @@ +/* + * Copyright (c) 2014-2015, 2017-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __SEEMP_LOGK_H__ +#define __SEEMP_LOGK_H__ + +#define OBSERVER_VERSION 0x01 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define seemp_LOGK_NUM_DEVS 1 +#define seemp_LOGK_DEV_NAME "seemplog" + +/* + * The logcat driver on Android uses four 256k ring buffers + * here, we use two ring buffers of the same size. + * we think this is reasonable + */ +#define FULL_BUF_SIZE (64 * 1024 * 1024) +#define HALF_BUF_SIZE (32 * 1024 * 1024) +#define FULL_BLOCKS (8 * 1024) +#define HALF_BLOCKS (4 * 1024) + +#define READER_NOT_READY 0 +#define READER_READY 1 + +#define MAGIC 'z' + +#define SEEMP_CMD_RESERVE_RDBLKS _IOR(MAGIC, 1, int) +#define SEEMP_CMD_RELEASE_RDBLKS _IO(MAGIC, 2) +#define SEEMP_CMD_GET_RINGSZ _IOR(MAGIC, 3, int) +#define SEEMP_CMD_GET_BLKSZ _IOR(MAGIC, 4, int) +#define SEEMP_CMD_SET_MASK _IO(MAGIC, 5) +#define SEEMP_CMD_SET_MAPPING _IO(MAGIC, 6) +#define SEEMP_CMD_CHECK_FILTER _IOR(MAGIC, 7, int) + +struct read_range { + int start_idx; + int num; +}; + +struct seemp_logk_dev { + unsigned int major; + unsigned int minor; + + struct cdev cdev; + struct class *cls; + /*the full buffer*/ + struct seemp_logk_blk *ring; + /*an array of blks*/ + unsigned int ring_sz; + unsigned int blk_sz; + + int num_tot_blks; + + int num_write_avail_blks; + int num_write_in_prog_blks; + + int num_read_avail_blks; + int num_read_in_prog_blks; + + int num_writers; + + /* + * there is always one reader + * which is the observer daemon + * therefore there is no necessity + * for num_readers variable + */ + + /* + * read_idx and write_idx loop through from zero to ring_sz, + * and then back to zero in a circle, as they advance + * based on the reader's and writers' accesses + */ + int read_idx; + + int write_idx; + + /* + * wait queues + * readers_wq: implement wait for readers + * writers_wq: implement wait for writers + * + * whether writers are blocked or not is driven by the policy: + * case 1: (best_effort_logging == 1) + * writers are not blocked, and + * when there is no mem in the ring to store logs, + * the logs are simply dropped. + * case 2: (best_effort_logging == 0) + * when there is no mem in the ring to store logs, + * the process gets blocked until there is space. + */ + wait_queue_head_t readers_wq; + wait_queue_head_t writers_wq; + + /* + * protects everything in the device + * including ring buffer and all the num_ variables + * spinlock_t lock; + */ + struct mutex lock; +}; + +#define BLK_SIZE 256 +#define BLK_HDR_SIZE 64 +#define TS_SIZE 20 +#define BLK_MAX_MSG_SZ (BLK_SIZE - BLK_HDR_SIZE) + +struct blk_payload { + __u32 api_id; /* event API id */ + char msg[BLK_MAX_MSG_SZ]; /* event parameters */ +} __packed; + +struct seemp_logk_blk { + __u8 status; /* bits: 0->valid/invalid; 1-7: unused as of now! */ + __u16 len; /* length of the payload */ + __u8 version; /* version number */ + __s32 pid; /* generating process's pid */ + __s32 uid; /* generating process's uid - app specific */ + __s32 tid; /* generating process's tid */ + __s32 sec; /* seconds since Epoch */ + __s32 nsec; /* nanoseconds */ + char ts[TS_SIZE]; /* Time Stamp */ + char appname[TASK_COMM_LEN]; + struct blk_payload payload; +} __packed; + + +extern unsigned int kmalloc_flag; + +struct seemp_source_mask { + __u32 hash; + bool isOn; +}; +#endif diff --git a/drivers/platform/msm/seemp_core/seemp_ringbuf.c b/drivers/platform/msm/seemp_core/seemp_ringbuf.c new file mode 100644 index 000000000000..6438032e743e --- /dev/null +++ b/drivers/platform/msm/seemp_core/seemp_ringbuf.c @@ -0,0 +1,161 @@ +/* + * Copyright (c) 2014-2015, 2017-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#define pr_fmt(fmt) "seemp: %s: " fmt, __func__ + +#include "seemp_logk.h" +#include "seemp_ringbuf.h" +#include "seemp_event_encoder.h" + +/*initial function no need to hold ring_lock*/ +int ringbuf_init(struct seemp_logk_dev *sdev) +{ + char *buf; + unsigned long virt_addr; + + if (kmalloc_flag) { + sdev->ring = kmalloc(sdev->ring_sz, GFP_KERNEL); + if (sdev->ring == NULL) + return -ENOMEM; + + buf = (char *)sdev->ring; + + /*reserve kmalloc memory as pages to make them remapable*/ + for (virt_addr = (unsigned long)buf; + virt_addr < (unsigned long)buf + sdev->ring_sz; + virt_addr += PAGE_SIZE) { + SetPageReserved(virt_to_page((virt_addr))); + } + } else { + sdev->ring = vmalloc(sdev->ring_sz); + if (sdev->ring == NULL) + return -ENOMEM; + + buf = (char *)sdev->ring; + + /*reserve vmalloc memory as pages to make them remapable*/ + for (virt_addr = (unsigned long)buf; + virt_addr < (unsigned long)buf + sdev->ring_sz; + virt_addr += PAGE_SIZE) { + SetPageReserved(vmalloc_to_page( + (unsigned long *) virt_addr)); + } + } + + memset(sdev->ring, 0, sdev->ring_sz); + + sdev->num_tot_blks = (sdev->ring_sz / BLK_SIZE); + sdev->num_writers = 0; + sdev->write_idx = 0; + sdev->read_idx = 0; + + sdev->num_write_avail_blks = sdev->num_tot_blks; + /*no. of blocks available for write*/ + sdev->num_write_in_prog_blks = 0; + /*no. of blocks held by writers to perform writes*/ + + sdev->num_read_avail_blks = 0; + /*no. of blocks ready for read*/ + sdev->num_read_in_prog_blks = 0; + /*no. of blocks held by the reader to perform read*/ + + return 0; +} + +void ringbuf_cleanup(struct seemp_logk_dev *sdev) +{ + unsigned long virt_addr; + + if (kmalloc_flag) { + for (virt_addr = (unsigned long)sdev->ring; + virt_addr < (unsigned long)sdev->ring + sdev->ring_sz; + virt_addr += PAGE_SIZE) { + /*clear all pages*/ + ClearPageReserved(virt_to_page((unsigned long *) + virt_addr)); + } + kfree(sdev->ring); + } else { + for (virt_addr = (unsigned long)sdev->ring; + virt_addr < (unsigned long)sdev->ring + sdev->ring_sz; + virt_addr += PAGE_SIZE) { + /*clear all pages*/ + ClearPageReserved(vmalloc_to_page((unsigned long *) + virt_addr)); + } + vfree(sdev->ring); + } +} + +struct seemp_logk_blk *ringbuf_fetch_wr_block + (struct seemp_logk_dev *sdev) +{ + struct seemp_logk_blk *blk = NULL; + int idx; + + mutex_lock(&sdev->lock); + if (sdev->num_write_avail_blks == 0) { + idx = -1; + mutex_unlock(&sdev->lock); + return blk; + } + + idx = sdev->write_idx; + sdev->write_idx = (sdev->write_idx + 1) % sdev->num_tot_blks; + sdev->num_write_avail_blks--; + sdev->num_write_in_prog_blks++; + sdev->num_writers++; + + blk = &sdev->ring[idx]; + blk->status = 0x0; + + mutex_unlock(&sdev->lock); + return blk; +} + +void ringbuf_finish_writer(struct seemp_logk_dev *sdev, + struct seemp_logk_blk *blk) +{ + /* Encode seemp parameters in multi-threaded mode (before mutex lock) */ + encode_seemp_params(blk); + + /* + * finish writing... + * the calling process will no longer access this block. + */ + mutex_lock(&sdev->lock); + + sdev->num_writers--; + sdev->num_write_in_prog_blks--; + sdev->num_read_avail_blks++; + + /*wake up any readers*/ + if (sdev->num_writers == 0) + wake_up_interruptible(&sdev->readers_wq); + + mutex_unlock(&sdev->lock); +} + +int ringbuf_count_marked(struct seemp_logk_dev *sdev) +{ + int i; + unsigned int marked; + + mutex_lock(&sdev->lock); + for (marked = 0, i = 0; i < sdev->num_tot_blks; i++) + if (sdev->ring[i].status & 0x1) + marked++; + mutex_unlock(&sdev->lock); + + return marked; +} diff --git a/drivers/platform/msm/seemp_core/seemp_ringbuf.h b/drivers/platform/msm/seemp_core/seemp_ringbuf.h new file mode 100644 index 000000000000..944ef7774b76 --- /dev/null +++ b/drivers/platform/msm/seemp_core/seemp_ringbuf.h @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2014-2015, 2017-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __SEEMP_RINGBUF_H__ +#define __SEEMP_RINGBUF_H__ + +/* + * This header exports pingpong's API + */ + +int ringbuf_init(struct seemp_logk_dev *sdev); +struct seemp_logk_blk *ringbuf_fetch_wr_block +(struct seemp_logk_dev *sdev); +void ringbuf_finish_writer(struct seemp_logk_dev *sdev, + struct seemp_logk_blk *blk); +void ringbuf_cleanup(struct seemp_logk_dev *sdev); +int ringbuf_count_marked(struct seemp_logk_dev *sdev); + +#endif diff --git a/include/linux/seemp_instrumentation.h b/include/linux/seemp_instrumentation.h new file mode 100644 index 000000000000..d6923bae5d96 --- /dev/null +++ b/include/linux/seemp_instrumentation.h @@ -0,0 +1,156 @@ +/* + * Copyright (c) 2015, 2017-2018 The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#ifndef __SEEMP_LOGK_STUB__ +#define __SEEMP_LOGK_STUB__ + +#ifdef CONFIG_SEEMP_CORE +#include + +#define MAX_BUF_SIZE 188 + +#define SEEMP_LOGK_API_SIZE sizeof(int) + +/* Write: api_id + skip encoding byte + params */ +#define SEEMP_LOGK_RECORD(api_id, format, ...) do { \ + *((int *)(buf - SEEMP_LOGK_API_SIZE)) = api_id; \ + snprintf(buf + 1, MAX_BUF_SIZE - 1, format, ##__VA_ARGS__); \ +} while (0) + +extern void *(*seemp_logk_kernel_begin)(char **buf); +extern void (*seemp_logk_kernel_end)(void *blck); + +static inline void *seemp_setup_buf(char **buf) +{ + void *blck; + + if (seemp_logk_kernel_begin && seemp_logk_kernel_end) { + blck = seemp_logk_kernel_begin(buf); + if (!*buf) { + seemp_logk_kernel_end(blck); + return NULL; + } + } else { + return NULL; + } + return blck; +} +/* + * NOTE: only sendto is going to be instrumented + * since send sys call internally calls sendto + * with 2 extra parameters + */ +static inline void seemp_logk_sendto(int fd, void __user *buff, size_t len, + unsigned int flags, struct sockaddr __user *addr, int addr_len) +{ + char *buf = NULL; + void *blck = NULL; + + /*sets up buf and blck correctly*/ + blck = seemp_setup_buf(&buf); + if (!blck) + return; + + /*fill the buf*/ + SEEMP_LOGK_RECORD(SEEMP_API_kernel__sendto, "len=%u,fd=%d", + (unsigned int)len, fd); + + seemp_logk_kernel_end(blck); +} + +/* + * NOTE: only recvfrom is going to be instrumented + * since recv sys call internally calls recvfrom + * with 2 extra parameters + */ +static inline void seemp_logk_recvfrom(int fd, void __user *ubuf, + size_t size, unsigned int flags, struct sockaddr __user *addr, + int __user *addr_len) +{ + char *buf = NULL; + void *blck = NULL; + + /*sets up buf and blck correctly*/ + blck = seemp_setup_buf(&buf); + if (!blck) + return; + + /*fill the buf*/ + SEEMP_LOGK_RECORD(SEEMP_API_kernel__recvfrom, "size=%u,fd=%d", + (unsigned int)size, fd); + + seemp_logk_kernel_end(blck); +} + +static inline void seemp_logk_oom_adjust_write(pid_t pid, + kuid_t uid, int oom_adj) +{ + char *buf = NULL; + void *blck = NULL; + + /*sets up buf and blck correctly*/ + blck = seemp_setup_buf(&buf); + if (!blck) + return; + + /*fill the buf*/ + SEEMP_LOGK_RECORD(SEEMP_API_kernel__oom_adjust_write, + "app_uid=%d,app_pid=%d,oom_adj=%d", + uid.val, pid, oom_adj); + + seemp_logk_kernel_end(blck); +} + +static inline void seemp_logk_oom_score_adj_write(pid_t pid, kuid_t uid, + int oom_adj_score) +{ + char *buf = NULL; + void *blck = NULL; + + /*sets up buf and blck correctly*/ + blck = seemp_setup_buf(&buf); + if (!blck) + return; + + /*fill the buf*/ + snprintf(buf, MAX_BUF_SIZE, + "-1|kernel|oom_score_adj_write|app_uid=%d,app_pid=%d,oom_adj=%d|--end", + uid.val, pid, oom_adj_score); + + seemp_logk_kernel_end(blck); +} + +#else +static inline void seemp_logk_sendto(int fd, void __user *buff, + size_t len, unsigned int flags, struct sockaddr __user *addr, + int addr_len) +{ +} + +static inline void seemp_logk_recvfrom + (int fd, void __user *ubuf, size_t size, + unsigned int flags, struct sockaddr __user *addr, + int __user *addr_len) +{ +} + +static inline void seemp_logk_oom_adjust_write + (pid_t pid, kuid_t uid, int oom_adj) +{ +} + +static inline void seemp_logk_oom_score_adj_write + (pid_t pid, kuid_t uid, int oom_adj_score) +{ +} +#endif +#endif diff --git a/include/uapi/linux/Kbuild b/include/uapi/linux/Kbuild index 983370997ced..ec7e998689d3 100644 --- a/include/uapi/linux/Kbuild +++ b/include/uapi/linux/Kbuild @@ -16,3 +16,5 @@ endif header-y += sockev.h header-y += nfc/ +header-y += seemp_api.h +header-y += seemp_param_id.h diff --git a/include/uapi/linux/seemp_api.h b/include/uapi/linux/seemp_api.h new file mode 100644 index 000000000000..4dfc257ea326 --- /dev/null +++ b/include/uapi/linux/seemp_api.h @@ -0,0 +1,395 @@ +#ifndef _SEEMP_API_H_ +#define _SEEMP_API_H_ + +#define SEEMP_API_kernel__oom_adjust_write 0 +#define SEEMP_API_kernel__sendto 1 +#define SEEMP_API_kernel__recvfrom 2 +#define SEEMP_API_View__onTouchEvent 3 +#define SEEMP_API_View__onKeyDown 4 +#define SEEMP_API_View__onKeyUp 5 +#define SEEMP_API_View__onTrackBallEvent 6 +#define SEEMP_API_android_provider_Settings__get_ANDROID_ID_ 7 +#define SEEMP_API_TelephonyManager__getDeviceId 8 +#define SEEMP_API_TelephonyManager__getLine1Number 9 +#define SEEMP_API_Telephony__query 10 +#define SEEMP_API_CallerInfo__getCallerId 11 +#define SEEMP_API_CallerInfo__getCallerInfo 12 +#define SEEMP_API_ContentResolver__query 13 +#define SEEMP_API_AccountManagerService__getPassword 14 +#define SEEMP_API_AccountManagerService__getUserData 15 +#define SEEMP_API_AccountManagerService__addAccount 16 +#define SEEMP_API_AccountManagerService__removeAccount 17 +#define SEEMP_API_AccountManagerService__setPassword 18 +#define SEEMP_API_AccountManagerService__clearPassword 19 +#define SEEMP_API_AccountManagerService__setUserData 20 +#define SEEMP_API_AccountManagerService__editProperties 21 +#define SEEMP_API_AccountManager__getPassword 22 +#define SEEMP_API_AccountManager__getUserData 23 +#define SEEMP_API_AccountManager__addAccountExplicitly 24 +#define SEEMP_API_AccountManager__removeAccount 25 +#define SEEMP_API_AccountManager__setPassword 26 +#define SEEMP_API_AccountManager__clearPassword 27 +#define SEEMP_API_AccountManager__setUserData 28 +#define SEEMP_API_AccountManager__addAccount 29 +#define SEEMP_API_AccountManager__editProperties 30 +#define SEEMP_API_AccountManager__doWork 31 +#define SEEMP_API_Browser__getAllBookmarks 32 +#define SEEMP_API_Browser__getAllVisitedUrls 33 +#define SEEMP_API_Browser__getVisitedLike 34 +#define SEEMP_API_Browser__getVisitedHistory 35 +#define SEEMP_API_Browser__requestAllIcons 36 +#define SEEMP_API_ContentResolver__insert 37 +#define SEEMP_API_CalendarContract__insert 38 +#define SEEMP_API_CalendarContract__alarmExists 39 +#define SEEMP_API_CalendarContract__findNextAlarmTime 40 +#define SEEMP_API_CalendarContract__query 41 +#define SEEMP_API_LocationManager___requestLocationUpdates 42 +#define SEEMP_API_LocationManager__addGpsStatusListener 43 +#define SEEMP_API_LocationManager__addNmeaListener 44 +#define SEEMP_API_LocationManager__addProximityAlert 45 +#define SEEMP_API_LocationManager__getLastKnownLocation 46 +#define SEEMP_API_LocationManager__requestLocationUpdates 47 +#define SEEMP_API_LocationManager__sendExtraCommand 48 +#define SEEMP_API_TelephonyManager__getCellLocation 49 +#define SEEMP_API_TelephonyManager__getNeighboringCellInfo 50 +#define SEEMP_API_GeolocationService__registerForLocationUpdates 51 +#define SEEMP_API_GeolocationService__setEnableGps 52 +#define SEEMP_API_GeolocationService__start 53 +#define SEEMP_API_WebChromeClient__onGeolocationPermissionsShowPrompt 54 +#define SEEMP_API_WifiManager__getScanResults 55 +#define SEEMP_API_adB__enable 56 +#define SEEMP_API_adB__disable 57 +#define SEEMP_API_adB__startDiscovery 58 +#define SEEMP_API_adB__listenUsingInsecureRfcommWithServiceRecord 59 +#define SEEMP_API_adB__listenUsingSecureRfcommWithServiceRecord 60 +#define SEEMP_API_adB__getBondedDevices 61 +#define SEEMP_API_adB__getRemoteDevice 62 +#define SEEMP_API_adB__getState 63 +#define SEEMP_API_adB__getProfileConnectionState 64 +#define SEEMP_API_Camera__takePicture 65 +#define SEEMP_API_Camera__setPreviewCallback 66 +#define SEEMP_API_Camera__setPreviewCallbackWithBuffer 67 +#define SEEMP_API_Camera__setOneShotPreviewCallback 68 +#define SEEMP_API_android_media_MediaRecorder__start 69 +#define SEEMP_API_AudioRecord__startRecording 70 +#define SEEMP_API_AudioRecord__start 71 +#define SEEMP_API_SpeechRecognizer__startListening 72 +#define SEEMP_API_at_SmsManager__sendDataMessage 73 +#define SEEMP_API_at_SmsManager__sendMultipartTextMessage 74 +#define SEEMP_API_at_SmsManager__sendTextMessage 75 +#define SEEMP_API_at_gsm_SmsManager__sendDataMessage 76 +#define SEEMP_API_at_gsm_SmsManager__sendMultipartTextMessage 77 +#define SEEMP_API_at_gsm_SmsManager__sendTextMessage 78 +#define SEEMP_API_at_SmsManager__copyMessageToIcc 79 +#define SEEMP_API_at_SmsManager__deleteMessageFromIcc 80 +#define SEEMP_API_at_SmsManager__updateMessageOnIcc 81 +#define SEEMP_API_at_gsm_SmsManager__copyMessageToSim 82 +#define SEEMP_API_at_gsm_SmsManager__deleteMessageFromSim 83 +#define SEEMP_API_at_gsm_SmsManager__updateMessageOnSim 84 +#define SEEMP_API_at_gsm_SmsManager__getAllMessagesFromSim 85 +#define SEEMP_API_ContactsContract__getLookupUri 86 +#define SEEMP_API_ContactsContract__lookupContact 87 +#define SEEMP_API_ContactsContract__openContactPhotoInputStream 88 +#define SEEMP_API_ContactsContract__getContactLookupUri 89 +#define SEEMP_API_PackageManagerService__installPackage 90 +#define SEEMP_API_URL__openConnection 91 +#define SEEMP_API_URI__URI 92 +#define SEEMP_API_HttpGet__HttpGet 93 +#define SEEMP_API_HttpPut__HttpPut 94 +#define SEEMP_API_HttpPost__HttpPost 95 +#define SEEMP_API_apS__get_ACCELEROMETER_ROTATION_ 96 +#define SEEMP_API_apS__get_USER_ROTATION_ 97 +#define SEEMP_API_apS__get_ADB_ENABLED_ 98 +#define SEEMP_API_apS__get_DEBUG_APP_ 99 +#define SEEMP_API_apS__get_WAIT_FOR_DEBUGGER_ 100 +#define SEEMP_API_apS__get_AIRPLANE_MODE_ON_ 101 +#define SEEMP_API_apS__get_AIRPLANE_MODE_RADIOS_ 102 +#define SEEMP_API_apS__get_ALARM_ALERT_ 103 +#define SEEMP_API_apS__get_NEXT_ALARM_FORMATTED_ 104 +#define SEEMP_API_apS__get_ALWAYS_FINISH_ACTIVITIES_ 105 +#define SEEMP_API_apS__get_LOGGING_ID_ 106 +#define SEEMP_API_apS__get_ANIMATOR_DURATION_SCALE_ 107 +#define SEEMP_API_apS__get_WINDOW_ANIMATION_SCALE_ 108 +#define SEEMP_API_apS__get_FONT_SCALE_ 109 +#define SEEMP_API_apS__get_SCREEN_BRIGHTNESS_ 110 +#define SEEMP_API_apS__get_SCREEN_BRIGHTNESS_MODE_ 111 +#define SEEMP_API_apS__get_SCREEN_BRIGHTNESS_MODE_AUTOMATIC_ 112 +#define SEEMP_API_apS__get_SCREEN_BRIGHTNESS_MODE_MANUAL_ 113 +#define SEEMP_API_apS__get_SCREEN_OFF_TIMEOUT_ 114 +#define SEEMP_API_apS__get_DIM_SCREEN_ 115 +#define SEEMP_API_apS__get_TRANSITION_ANIMATION_SCALE_ 116 +#define SEEMP_API_apS__get_STAY_ON_WHILE_PLUGGED_IN_ 117 +#define SEEMP_API_apS__get_WALLPAPER_ACTIVITY_ 118 +#define SEEMP_API_apS__get_SHOW_PROCESSES_ 119 +#define SEEMP_API_apS__get_SHOW_WEB_SUGGESTIONS_ 120 +#define SEEMP_API_apS__get_SHOW_GTALK_SERVICE_STATUS_ 121 +#define SEEMP_API_apS__get_USE_GOOGLE_MAIL_ 122 +#define SEEMP_API_apS__get_AUTO_TIME_ 123 +#define SEEMP_API_apS__get_AUTO_TIME_ZONE_ 124 +#define SEEMP_API_apS__get_DATE_FORMAT_ 125 +#define SEEMP_API_apS__get_TIME_12_24_ 126 +#define SEEMP_API_apS__get_BLUETOOTH_DISCOVERABILITY_ 127 +#define SEEMP_API_apS__get_BLUETOOTH_DISCOVERABILITY_TIMEOUT_ 128 +#define SEEMP_API_apS__get_BLUETOOTH_ON_ 129 +#define SEEMP_API_apS__get_DEVICE_PROVISIONED_ 130 +#define SEEMP_API_apS__get_SETUP_WIZARD_HAS_RUN_ 131 +#define SEEMP_API_apS__get_DTMF_TONE_WHEN_DIALING_ 132 +#define SEEMP_API_apS__get_END_BUTTON_BEHAVIOR_ 133 +#define SEEMP_API_apS__get_RINGTONE_ 134 +#define SEEMP_API_apS__get_MODE_RINGER_ 135 +#define SEEMP_API_apS__get_INSTALL_NON_MARKET_APPS_ 136 +#define SEEMP_API_apS__get_LOCATION_PROVIDERS_ALLOWED_ 137 +#define SEEMP_API_apS__get_LOCK_PATTERN_ENABLED_ 138 +#define SEEMP_API_apS__get_LOCK_PATTERN_TACTILE_FEEDBACK_ENABLED_ 139 +#define SEEMP_API_apS__get_LOCK_PATTERN_VISIBLE_ 140 +#define SEEMP_API_apS__get_NETWORK_PREFERENCE_ 141 +#define SEEMP_API_apS__get_DATA_ROAMING_ 142 +#define SEEMP_API_apS__get_HTTP_PROXY_ 143 +#define SEEMP_API_apS__get_PARENTAL_CONTROL_ENABLED_ 144 +#define SEEMP_API_apS__get_PARENTAL_CONTROL_LAST_UPDATE_ 145 +#define SEEMP_API_apS__get_PARENTAL_CONTROL_REDIRECT_URL_ 146 +#define SEEMP_API_apS__get_RADIO_BLUETOOTH_ 147 +#define SEEMP_API_apS__get_RADIO_CELL_ 148 +#define SEEMP_API_apS__get_RADIO_NFC_ 149 +#define SEEMP_API_apS__get_RADIO_WIFI_ 150 +#define SEEMP_API_apS__get_SYS_PROP_SETTING_VERSION_ 151 +#define SEEMP_API_apS__get_SETTINGS_CLASSNAME_ 152 +#define SEEMP_API_apS__get_TEXT_AUTO_CAPS_ 153 +#define SEEMP_API_apS__get_TEXT_AUTO_PUNCTUATE_ 154 +#define SEEMP_API_apS__get_TEXT_AUTO_REPLACE_ 155 +#define SEEMP_API_apS__get_TEXT_SHOW_PASSWORD_ 156 +#define SEEMP_API_apS__get_USB_MASS_STORAGE_ENABLED_ 157 +#define SEEMP_API_apS__get_VIBRATE_ON_ 158 +#define SEEMP_API_apS__get_HAPTIC_FEEDBACK_ENABLED_ 159 +#define SEEMP_API_apS__get_VOLUME_ALARM_ 160 +#define SEEMP_API_apS__get_VOLUME_BLUETOOTH_SCO_ 161 +#define SEEMP_API_apS__get_VOLUME_MUSIC_ 162 +#define SEEMP_API_apS__get_VOLUME_NOTIFICATION_ 163 +#define SEEMP_API_apS__get_VOLUME_RING_ 164 +#define SEEMP_API_apS__get_VOLUME_SYSTEM_ 165 +#define SEEMP_API_apS__get_VOLUME_VOICE_ 166 +#define SEEMP_API_apS__get_SOUND_EFFECTS_ENABLED_ 167 +#define SEEMP_API_apS__get_MODE_RINGER_STREAMS_AFFECTED_ 168 +#define SEEMP_API_apS__get_MUTE_STREAMS_AFFECTED_ 169 +#define SEEMP_API_apS__get_NOTIFICATION_SOUND_ 170 +#define SEEMP_API_apS__get_APPEND_FOR_LAST_AUDIBLE_ 171 +#define SEEMP_API_apS__get_WIFI_MAX_DHCP_RETRY_COUNT_ 172 +#define SEEMP_API_apS__get_WIFI_MOBILE_DATA_TRANSITION_WAKELOCK_TIMEOUT_MS_ 173 +#define SEEMP_API_apS__get_WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON_ 174 +#define SEEMP_API_apS__get_WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY_ 175 +#define SEEMP_API_apS__get_WIFI_NUM_OPEN_NETWORKS_KEPT_ 176 +#define SEEMP_API_apS__get_WIFI_ON_ 177 +#define SEEMP_API_apS__get_WIFI_SLEEP_POLICY_ 178 +#define SEEMP_API_apS__get_WIFI_SLEEP_POLICY_DEFAULT_ 179 +#define SEEMP_API_apS__get_WIFI_SLEEP_POLICY_NEVER_ 180 +#define SEEMP_API_apS__get_WIFI_SLEEP_POLICY_NEVER_WHILE_PLUGGED_ 181 +#define SEEMP_API_apS__get_WIFI_STATIC_DNS1_ 182 +#define SEEMP_API_apS__get_WIFI_STATIC_DNS2_ 183 +#define SEEMP_API_apS__get_WIFI_STATIC_GATEWAY_ 184 +#define SEEMP_API_apS__get_WIFI_STATIC_IP_ 185 +#define SEEMP_API_apS__get_WIFI_STATIC_NETMASK_ 186 +#define SEEMP_API_apS__get_WIFI_USE_STATIC_IP_ 187 +#define SEEMP_API_apS__get_WIFI_WATCHDOG_ACCEPTABLE_PACKET_LOSS_PERCENTAGE_ 188 +#define SEEMP_API_apS__get_WIFI_WATCHDOG_AP_COUNT_ 189 +#define SEEMP_API_apS__get_WIFI_WATCHDOG_BACKGROUND_CHECK_DELAY_MS_ 190 +#define SEEMP_API_apS__get_WIFI_WATCHDOG_BACKGROUND_CHECK_ENABLED_ 191 +#define SEEMP_API_apS__get_WIFI_WATCHDOG_BACKGROUND_CHECK_TIMEOUT_MS_ 192 +#define SEEMP_API_apS__get_WIFI_WATCHDOG_INITIAL_IGNORED_PING_COUNT_ 193 +#define SEEMP_API_apS__get_WIFI_WATCHDOG_MAX_AP_CHECKS_ 194 +#define SEEMP_API_apS__get_WIFI_WATCHDOG_ON_ 195 +#define SEEMP_API_apS__get_WIFI_WATCHDOG_PING_COUNT_ 196 +#define SEEMP_API_apS__get_WIFI_WATCHDOG_PING_DELAY_MS_ 197 +#define SEEMP_API_apS__get_WIFI_WATCHDOG_PING_TIMEOUT_MS_ 198 +#define SEEMP_API_apS__put_ACCELEROMETER_ROTATION_ 199 +#define SEEMP_API_apS__put_USER_ROTATION_ 200 +#define SEEMP_API_apS__put_ADB_ENABLED_ 201 +#define SEEMP_API_apS__put_DEBUG_APP_ 202 +#define SEEMP_API_apS__put_WAIT_FOR_DEBUGGER_ 203 +#define SEEMP_API_apS__put_AIRPLANE_MODE_ON_ 204 +#define SEEMP_API_apS__put_AIRPLANE_MODE_RADIOS_ 205 +#define SEEMP_API_apS__put_ALARM_ALERT_ 206 +#define SEEMP_API_apS__put_NEXT_ALARM_FORMATTED_ 207 +#define SEEMP_API_apS__put_ALWAYS_FINISH_ACTIVITIES_ 208 +#define SEEMP_API_apS__put_ANDROID_ID_ 209 +#define SEEMP_API_apS__put_LOGGING_ID_ 210 +#define SEEMP_API_apS__put_ANIMATOR_DURATION_SCALE_ 211 +#define SEEMP_API_apS__put_WINDOW_ANIMATION_SCALE_ 212 +#define SEEMP_API_apS__put_FONT_SCALE_ 213 +#define SEEMP_API_apS__put_SCREEN_BRIGHTNESS_ 214 +#define SEEMP_API_apS__put_SCREEN_BRIGHTNESS_MODE_ 215 +#define SEEMP_API_apS__put_SCREEN_BRIGHTNESS_MODE_AUTOMATIC_ 216 +#define SEEMP_API_apS__put_SCREEN_BRIGHTNESS_MODE_MANUAL_ 217 +#define SEEMP_API_apS__put_SCREEN_OFF_TIMEOUT_ 218 +#define SEEMP_API_apS__put_DIM_SCREEN_ 219 +#define SEEMP_API_apS__put_TRANSITION_ANIMATION_SCALE_ 220 +#define SEEMP_API_apS__put_STAY_ON_WHILE_PLUGGED_IN_ 221 +#define SEEMP_API_apS__put_WALLPAPER_ACTIVITY_ 222 +#define SEEMP_API_apS__put_SHOW_PROCESSES_ 223 +#define SEEMP_API_apS__put_SHOW_WEB_SUGGESTIONS_ 224 +#define SEEMP_API_apS__put_SHOW_GTALK_SERVICE_STATUS_ 225 +#define SEEMP_API_apS__put_USE_GOOGLE_MAIL_ 226 +#define SEEMP_API_apS__put_AUTO_TIME_ 227 +#define SEEMP_API_apS__put_AUTO_TIME_ZONE_ 228 +#define SEEMP_API_apS__put_DATE_FORMAT_ 229 +#define SEEMP_API_apS__put_TIME_12_24_ 230 +#define SEEMP_API_apS__put_BLUETOOTH_DISCOVERABILITY_ 231 +#define SEEMP_API_apS__put_BLUETOOTH_DISCOVERABILITY_TIMEOUT_ 232 +#define SEEMP_API_apS__put_BLUETOOTH_ON_ 233 +#define SEEMP_API_apS__put_DEVICE_PROVISIONED_ 234 +#define SEEMP_API_apS__put_SETUP_WIZARD_HAS_RUN_ 235 +#define SEEMP_API_apS__put_DTMF_TONE_WHEN_DIALING_ 236 +#define SEEMP_API_apS__put_END_BUTTON_BEHAVIOR_ 237 +#define SEEMP_API_apS__put_RINGTONE_ 238 +#define SEEMP_API_apS__put_MODE_RINGER_ 239 +#define SEEMP_API_apS__put_INSTALL_NON_MARKET_APPS_ 240 +#define SEEMP_API_apS__put_LOCATION_PROVIDERS_ALLOWED_ 241 +#define SEEMP_API_apS__put_LOCK_PATTERN_ENABLED_ 242 +#define SEEMP_API_apS__put_LOCK_PATTERN_TACTILE_FEEDBACK_ENABLED_ 243 +#define SEEMP_API_apS__put_LOCK_PATTERN_VISIBLE_ 244 +#define SEEMP_API_apS__put_NETWORK_PREFERENCE_ 245 +#define SEEMP_API_apS__put_DATA_ROAMING_ 246 +#define SEEMP_API_apS__put_HTTP_PROXY_ 247 +#define SEEMP_API_apS__put_PARENTAL_CONTROL_ENABLED_ 248 +#define SEEMP_API_apS__put_PARENTAL_CONTROL_LAST_UPDATE_ 249 +#define SEEMP_API_apS__put_PARENTAL_CONTROL_REDIRECT_URL_ 250 +#define SEEMP_API_apS__put_RADIO_BLUETOOTH_ 251 +#define SEEMP_API_apS__put_RADIO_CELL_ 252 +#define SEEMP_API_apS__put_RADIO_NFC_ 253 +#define SEEMP_API_apS__put_RADIO_WIFI_ 254 +#define SEEMP_API_apS__put_SYS_PROP_SETTING_VERSION_ 255 +#define SEEMP_API_apS__put_SETTINGS_CLASSNAME_ 256 +#define SEEMP_API_apS__put_TEXT_AUTO_CAPS_ 257 +#define SEEMP_API_apS__put_TEXT_AUTO_PUNCTUATE_ 258 +#define SEEMP_API_apS__put_TEXT_AUTO_REPLACE_ 259 +#define SEEMP_API_apS__put_TEXT_SHOW_PASSWORD_ 260 +#define SEEMP_API_apS__put_USB_MASS_STORAGE_ENABLED_ 261 +#define SEEMP_API_apS__put_VIBRATE_ON_ 262 +#define SEEMP_API_apS__put_HAPTIC_FEEDBACK_ENABLED_ 263 +#define SEEMP_API_apS__put_VOLUME_ALARM_ 264 +#define SEEMP_API_apS__put_VOLUME_BLUETOOTH_SCO_ 265 +#define SEEMP_API_apS__put_VOLUME_MUSIC_ 266 +#define SEEMP_API_apS__put_VOLUME_NOTIFICATION_ 267 +#define SEEMP_API_apS__put_VOLUME_RING_ 268 +#define SEEMP_API_apS__put_VOLUME_SYSTEM_ 269 +#define SEEMP_API_apS__put_VOLUME_VOICE_ 270 +#define SEEMP_API_apS__put_SOUND_EFFECTS_ENABLED_ 271 +#define SEEMP_API_apS__put_MODE_RINGER_STREAMS_AFFECTED_ 272 +#define SEEMP_API_apS__put_MUTE_STREAMS_AFFECTED_ 273 +#define SEEMP_API_apS__put_NOTIFICATION_SOUND_ 274 +#define SEEMP_API_apS__put_APPEND_FOR_LAST_AUDIBLE_ 275 +#define SEEMP_API_apS__put_WIFI_MAX_DHCP_RETRY_COUNT_ 276 +#define SEEMP_API_apS__put_WIFI_MOBILE_DATA_TRANSITION_WAKELOCK_TIMEOUT_MS_ 277 +#define SEEMP_API_apS__put_WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON_ 278 +#define SEEMP_API_apS__put_WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY_ 279 +#define SEEMP_API_apS__put_WIFI_NUM_OPEN_NETWORKS_KEPT_ 280 +#define SEEMP_API_apS__put_WIFI_ON_ 281 +#define SEEMP_API_apS__put_WIFI_SLEEP_POLICY_ 282 +#define SEEMP_API_apS__put_WIFI_SLEEP_POLICY_DEFAULT_ 283 +#define SEEMP_API_apS__put_WIFI_SLEEP_POLICY_NEVER_ 284 +#define SEEMP_API_apS__put_WIFI_SLEEP_POLICY_NEVER_WHILE_PLUGGED_ 285 +#define SEEMP_API_apS__put_WIFI_STATIC_DNS1_ 286 +#define SEEMP_API_apS__put_WIFI_STATIC_DNS2_ 287 +#define SEEMP_API_apS__put_WIFI_STATIC_GATEWAY_ 288 +#define SEEMP_API_apS__put_WIFI_STATIC_IP_ 289 +#define SEEMP_API_apS__put_WIFI_STATIC_NETMASK_ 290 +#define SEEMP_API_apS__put_WIFI_USE_STATIC_IP_ 291 +#define SEEMP_API_apS__put_WIFI_WATCHDOG_ACCEPTABLE_PACKET_LOSS_PERCENTAGE_ 292 +#define SEEMP_API_apS__put_WIFI_WATCHDOG_AP_COUNT_ 293 +#define SEEMP_API_apS__put_WIFI_WATCHDOG_BACKGROUND_CHECK_DELAY_MS_ 294 +#define SEEMP_API_apS__put_WIFI_WATCHDOG_BACKGROUND_CHECK_ENABLED_ 295 +#define SEEMP_API_apS__put_WIFI_WATCHDOG_BACKGROUND_CHECK_TIMEOUT_MS_ 296 +#define SEEMP_API_apS__put_WIFI_WATCHDOG_INITIAL_IGNORED_PING_COUNT_ 297 +#define SEEMP_API_apS__put_WIFI_WATCHDOG_MAX_AP_CHECKS_ 298 +#define SEEMP_API_apS__put_WIFI_WATCHDOG_ON_ 299 +#define SEEMP_API_apS__put_WIFI_WATCHDOG_PING_COUNT_ 300 +#define SEEMP_API_apS__put_WIFI_WATCHDOG_PING_DELAY_MS_ 301 +#define SEEMP_API_apS__put_WIFI_WATCHDOG_PING_TIMEOUT_MS_ 302 +#define SEEMP_API_Poll__setCumulativeWifiRxMBytes 303 +#define SEEMP_API_Poll__setInstantaneousWifiRxMBytes 304 +#define SEEMP_API_Poll__setCumulativeWifiRxPackets 305 +#define SEEMP_API_Poll__setInstantaneousWifiRxPackets 306 +#define SEEMP_API_Poll__setCumulativeWifiTxMBytes 307 +#define SEEMP_API_Poll__setInstantaneousWifiTxMBytes 308 +#define SEEMP_API_Poll__setCumulativeWifiTxPackets 309 +#define SEEMP_API_Poll__setInstantaneousWifiTxPackets 310 +#define SEEMP_API_Poll__setCumulativeWifiRxTcpMBytes 311 +#define SEEMP_API_Poll__setInstantaneousWifiRxTcpMBytes 312 +#define SEEMP_API_Poll__setCumulativeWifiRxTcpPackets 313 +#define SEEMP_API_Poll__setInstantaneousWifiRxTcpPackets 314 +#define SEEMP_API_Poll__setCumulativeWifiRxUdpMBytes 315 +#define SEEMP_API_Poll__setInstantaneousWifiRxUdpMBytes 316 +#define SEEMP_API_Poll__setCumulativeWifiRxUdpPackets 317 +#define SEEMP_API_Poll__setInstantaneousWifiRxUdpPackets 318 +#define SEEMP_API_Poll__setCumulativeWifiRxOtherMBytes 319 +#define SEEMP_API_Poll__setInstantaneousWifiRxOtherMBytes 320 +#define SEEMP_API_Poll__setCumulativeWifiRxOtherPackets 321 +#define SEEMP_API_Poll__setInstantaneousWifiRxOtherPackets 322 +#define SEEMP_API_Poll__setCumulativeWifiTxTcpMBytes 323 +#define SEEMP_API_Poll__setInstantaneousWifiTxTcpMBytes 324 +#define SEEMP_API_Poll__setCumulativeWifiTxTcpPackets 325 +#define SEEMP_API_Poll__setInstantaneousWifiTxTcpPackets 326 +#define SEEMP_API_Poll__setCumulativeWifiTxUdpMBytes 327 +#define SEEMP_API_Poll__setInstantaneousWifiTxUdpMBytes 328 +#define SEEMP_API_Poll__setCumulativeWifiTxUdpPackets 329 +#define SEEMP_API_Poll__setInstantaneousWifiTxUdpPackets 330 +#define SEEMP_API_Poll__setCumulativeWifiTxOtherMBytes 331 +#define SEEMP_API_Poll__setInstantaneousWifiTxOtherMBytes 332 +#define SEEMP_API_Poll__setCumulativeWifiTxOtherPackets 333 +#define SEEMP_API_Poll__setInstantaneousWifiTxOtherPackets 334 +#define SEEMP_API_Poll__setCumulativeMobileRxMBytes 335 +#define SEEMP_API_Poll__setInstantaneousMobileRxMBytes 336 +#define SEEMP_API_Poll__setCumulativeMobileRxPackets 337 +#define SEEMP_API_Poll__setInstantaneousMobileRxPackets 338 +#define SEEMP_API_Poll__setCumulativeMobileTxMBytes 339 +#define SEEMP_API_Poll__setInstantaneousMobileTxMBytes 340 +#define SEEMP_API_Poll__setCumulativeMobileTxPackets 341 +#define SEEMP_API_Poll__setInstantaneousMobileTxPackets 342 +#define SEEMP_API_Poll__setCumulativeMobileRxTcpMBytes 343 +#define SEEMP_API_Poll__setInstantaneousMobileRxTcpMBytes 344 +#define SEEMP_API_Poll__setCumulativeMobileRxTcpPackets 345 +#define SEEMP_API_Poll__setInstantaneousMobileRxTcpPackets 346 +#define SEEMP_API_Poll__setCumulativeMobileRxUdpMBytes 347 +#define SEEMP_API_Poll__setInstantaneousMobileRxUdpMBytes 348 +#define SEEMP_API_Poll__setCumulativeMobileRxUdpPackets 349 +#define SEEMP_API_Poll__setInstantaneousMobileRxUdpPackets 350 +#define SEEMP_API_Poll__setCumulativeMobileRxOtherMBytes 351 +#define SEEMP_API_Poll__setInstantaneousMobileRxOtherMBytes 352 +#define SEEMP_API_Poll__setCumulativeMobileRxOtherPackets 353 +#define SEEMP_API_Poll__setInstantaneousMobileRxOtherPackets 354 +#define SEEMP_API_Poll__setCumulativeMobileTxTcpMBytes 355 +#define SEEMP_API_Poll__setInstantaneousMobileTxTcpMBytes 356 +#define SEEMP_API_Poll__setCumulativeMobileTxTcpPackets 357 +#define SEEMP_API_Poll__setInstantaneousMobileTxTcpPackets 358 +#define SEEMP_API_Poll__setCumulativeMobileTxUdpMBytes 359 +#define SEEMP_API_Poll__setInstantaneousMobileTxUdpMBytes 360 +#define SEEMP_API_Poll__setCumulativeMobileTxUdpPackets 361 +#define SEEMP_API_Poll__setInstantaneousMobileTxUdpPackets 362 +#define SEEMP_API_Poll__setCumulativeMobileTxOtherMBytes 363 +#define SEEMP_API_Poll__setInstantaneousMobileTxOtherMBytes 364 +#define SEEMP_API_Poll__setCumulativeMobileTxOtherPackets 365 +#define SEEMP_API_Poll__setInstantaneousMobileTxOtherPackets 366 +#define SEEMP_API_Poll__setNumSockets 367 +#define SEEMP_API_Poll__setNumTcpStateListen 368 +#define SEEMP_API_Poll__setNumTcpStateEstablished 369 +#define SEEMP_API_Poll__setNumLocalIp 370 +#define SEEMP_API_Poll__setNumLocalPort 371 +#define SEEMP_API_Poll__setNumRemoteIp 372 +#define SEEMP_API_Poll__setNumRemotePort 373 +#define SEEMP_API_Poll__setNumRemoteTuple 374 +#define SEEMP_API_Poll__setNumInode 375 +#define SEEMP_API_Instrumentation__startActivitySync 376 +#define SEEMP_API_Instrumentation__execStartActivity 377 +#define SEEMP_API_Instrumentation__execStartActivitiesAsUser 378 +#define SEEMP_API_Instrumentation__execStartActivityAsCaller 379 +#define SEEMP_API_Instrumentation__execStartActivityFromAppTask 380 +#define SEEMP_API_ah_SystemSensorManager__registerListenerImpl 381 +#define SEEMP_API_ah_SystemSensorManager__unregisterListenerImpl 382 +#define SEEMP_API_WindowManagerImpl__addView 383 +#define SEEMP_API_WindowManagerImpl__updateViewLayout 384 +#define SEEMP_API_ActivityManagerService__applyOomAdjLocked 385 +#define SEEMP_API_ProcessRecord__makeActive 386 +#define SEEMP_API_ProcessRecord__makeInactive 387 +#define SEEMP_API_TelephonyManager__getSimSerialNumber 388 +#define SEEMP_API_TelephonyManager__getSubscriberId 389 + +#endif /* _SEEMP_API_H_*/ diff --git a/include/uapi/linux/seemp_param_id.h b/include/uapi/linux/seemp_param_id.h new file mode 100644 index 000000000000..8f1f05fdc923 --- /dev/null +++ b/include/uapi/linux/seemp_param_id.h @@ -0,0 +1,90 @@ +#ifndef _PARAM_ID_H_ +#define _PARAM_ID_H_ + +#define PARAM_ID_LEN 0 +#define PARAM_ID_OOM_ADJ 1 +#define PARAM_ID_APP_UID 2 +#define PARAM_ID_APP_PID 3 +#define PARAM_ID_VALUE 4 +#define PARAM_ID_SIZE 5 +#define PARAM_ID_FD 6 +#define PARAM_ID_RATE 7 +#define PARAM_ID_SENSOR 8 +#define PARAM_ID_WINDOW_TYPE 9 +#define PARAM_ID_WINDOW_FLAG 10 +#define NUM_PARAM_IDS 11 + +static inline int param_id_index(const char *param, const char *end) +{ + int id = -1; + int len = ((end != NULL) ? (end - param) : (int)strlen(param)); + + if ((len == 3) && !memcmp(param, "len", 3)) + id = 0; + else if ((len == 7) && !memcmp(param, "oom_adj", 7)) + id = 1; + else if ((len == 7) && !memcmp(param, "app_uid", 7)) + id = 2; + else if ((len == 7) && !memcmp(param, "app_pid", 7)) + id = 3; + else if ((len == 5) && !memcmp(param, "value", 5)) + id = 4; + else if ((len == 4) && !memcmp(param, "size", 4)) + id = 5; + else if ((len == 2) && !memcmp(param, "fd", 2)) + id = 6; + else if ((len == 4) && !memcmp(param, "rate", 4)) + id = 7; + else if ((len == 6) && !memcmp(param, "sensor", 6)) + id = 8; + else if ((len == 11) && !memcmp(param, "window_type", 11)) + id = 9; + else if ((len == 11) && !memcmp(param, "window_flag", 11)) + id = 10; + + return id; +} + +static inline const char *get_param_id_name(int id) +{ + const char *name = "?"; + + switch (id) { + case 0: + name = "len"; + break; + case 1: + name = "oom_adj"; + break; + case 2: + name = "app_uid"; + break; + case 3: + name = "app_pid"; + break; + case 4: + name = "value"; + break; + case 5: + name = "size"; + break; + case 6: + name = "fd"; + break; + case 7: + name = "rate"; + break; + case 8: + name = "sensor"; + break; + case 9: + name = "window_type"; + break; + case 10: + name = "window_flag"; + break; + } + return name; +} + +#endif /* _PARAM_ID_H_ */ diff --git a/net/socket.c b/net/socket.c index 1700a6ba1472..690d308de7c9 100644 --- a/net/socket.c +++ b/net/socket.c @@ -89,6 +89,8 @@ #include #include #include +#include +#include #include #include @@ -1745,6 +1747,8 @@ SYSCALL_DEFINE6(sendto, int, fd, void __user *, buff, size_t, len, struct iovec iov; int fput_needed; + seemp_logk_sendto(fd, buff, len, flags, addr, addr_len); + err = import_single_range(WRITE, buff, len, &iov, &msg.msg_iter); if (unlikely(err)) return err; -- GitLab From 8dd980c0a150aeafd71d82bfbe8f82ad5dcd132d Mon Sep 17 00:00:00 2001 From: Lynus Vaz Date: Wed, 11 Apr 2018 19:29:16 +0530 Subject: [PATCH 0572/1635] msm: kgsl: Keep the IRQ pending count accurate If the IRQ pending count is incremented, make sure it is decremented even in case of errors. Change-Id: I63443d4430b24ff82eb58d729e42f7115607ff25 Signed-off-by: Lynus Vaz --- drivers/gpu/msm/adreno.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c index 4bc57003ebd5..065bacfd8c77 100644 --- a/drivers/gpu/msm/adreno.c +++ b/drivers/gpu/msm/adreno.c @@ -643,7 +643,7 @@ static irqreturn_t adreno_irq_handler(struct kgsl_device *device) if (fence_retries == FENCE_RETRY_MAX) { KGSL_DRV_CRIT_RATELIMIT(device, "AHB fence stuck in ISR\n"); - return ret; + goto done; } fence_retries++; } while (fence != 0); @@ -687,6 +687,7 @@ static irqreturn_t adreno_irq_handler(struct kgsl_device *device) adreno_writereg(adreno_dev, ADRENO_REG_RBBM_INT_CLEAR_CMD, int_bit); +done: /* Turn off the KEEPALIVE vote from earlier unless hard fault set */ if (gpudev->gpu_keepalive) { /* If hard fault, then let snapshot turn off the keepalive */ -- GitLab From 7f9a3caadceab0d6771a2600ff56970435607547 Mon Sep 17 00:00:00 2001 From: Mukesh Kumar Savaliya Date: Wed, 7 Mar 2018 19:04:19 +0530 Subject: [PATCH 0573/1635] ARM: dts: msm: Add support for I2C, SPI, UART and Slimbus on QCS405 Initial support for all BLSP I2C, SPI, UART and Slimbus instances with default configuration and disabled state such that clients can overwrite and enable respective instance as per need. Change-Id: Ideb28e7af6ffd80d040182c2b7bf2167afa3fb67 Signed-off-by: Mukesh Kumar Savaliya Signed-off-by: Shrey Vijay --- arch/arm64/boot/dts/qcom/qcs405-blsp.dtsi | 526 ++++++++++++++++ arch/arm64/boot/dts/qcom/qcs405-pinctrl.dtsi | 595 +++++++++++++++++++ arch/arm64/boot/dts/qcom/qcs405.dtsi | 25 + 3 files changed, 1146 insertions(+) create mode 100644 arch/arm64/boot/dts/qcom/qcs405-blsp.dtsi diff --git a/arch/arm64/boot/dts/qcom/qcs405-blsp.dtsi b/arch/arm64/boot/dts/qcom/qcs405-blsp.dtsi new file mode 100644 index 000000000000..a65e323ccfdd --- /dev/null +++ b/arch/arm64/boot/dts/qcom/qcs405-blsp.dtsi @@ -0,0 +1,526 @@ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#include "qcs405-pinctrl.dtsi" + +/ { + aliases { + spi1 = &spi_1; + spi2 = &spi_2; + spi3 = &spi_3; + spi4 = &spi_4; + spi5 = &spi_5; + spi6 = &spi_6; + i2c1 = &i2c_1; + i2c2 = &i2c_2; + i2c3 = &i2c_3; + i2c4 = &i2c_4; + i2c5 = &i2c_5; + i2c6 = &i2c_6; + }; +}; + + +&soc { + + dma_blsp1: qcom,sps-dma@7884000{ /* BLSP1 */ + #dma-cells = <4>; + compatible = "qcom,sps-dma"; + reg = <0x7884000 0x25000>; + interrupts = <0 238 0>; + qcom,summing-threshold = <0x10>; + }; + + dma_blsp2: qcom,sps-dma@7ac4000{ /* BLSP2 */ + #dma-cells = <4>; + compatible = "qcom,sps-dma"; + reg = <0x7ac4000 0x17000>; + interrupts = <0 239 0>; + qcom,summing-threshold = <0x10>; + }; + + i2c_1: i2c@78b5000 { /* BLSP1 QUP1 */ + compatible = "qcom,i2c-msm-v2"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x78b5000 0x600>; + reg-names = "qup_phys_addr"; + interrupt-names = "qup_irq"; + interrupts = <0 95 0>; + dmas = <&dma_blsp1 8 64 0x20000020 0x20>, + <&dma_blsp1 9 32 0x20000020 0x20>; + dma-names = "tx", "rx"; + qcom,master-id = <86>; + qcom,clk-freq-out = <400000>; + qcom,clk-freq-in = <19200000>; + clock-names = "iface_clk", "core_clk"; + clocks = <&clock_gcc GCC_BLSP1_AHB_CLK>, + <&clock_gcc GCC_BLSP1_QUP0_I2C_APPS_CLK>; + pinctrl-names = "i2c_active", "i2c_sleep"; + pinctrl-0 = <&i2c_1_active>; + pinctrl-1 = <&i2c_1_sleep>; + status = "disabled"; + }; + + i2c_2: i2c@78b6000 { /* BLSP1 QUP2 */ + compatible = "qcom,i2c-msm-v2"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x78b6000 0x600>; + reg-names = "qup_phys_addr"; + interrupt-names = "qup_irq"; + interrupts = <0 96 0>; + dmas = <&dma_blsp1 10 64 0x20000020 0x20>, + <&dma_blsp1 11 32 0x20000020 0x20>; + dma-names = "tx", "rx"; + qcom,master-id = <86>; + qcom,clk-freq-out = <400000>; + qcom,clk-freq-in = <19200000>; + clock-names = "iface_clk", "core_clk"; + clocks = <&clock_gcc GCC_BLSP1_AHB_CLK>, + <&clock_gcc GCC_BLSP1_QUP1_I2C_APPS_CLK>; + pinctrl-names = "i2c_active", "i2c_sleep"; + pinctrl-0 = <&i2c_2_active>; + pinctrl-1 = <&i2c_2_sleep>; + status = "disabled"; + }; + + i2c_3: i2c@78b7000 { /* BLSP1 QUP3 */ + compatible = "qcom,i2c-msm-v2"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x78b7000 0x600>; + reg-names = "qup_phys_addr"; + interrupt-names = "qup_irq"; + interrupts = <0 97 0>; + dmas = <&dma_blsp1 12 64 0x20000020 0x20>, + <&dma_blsp1 13 32 0x20000020 0x20>; + dma-names = "tx", "rx"; + qcom,master-id = <86>; + qcom,clk-freq-out = <400000>; + qcom,clk-freq-in = <19200000>; + clock-names = "iface_clk", "core_clk"; + clocks = <&clock_gcc GCC_BLSP1_AHB_CLK>, + <&clock_gcc GCC_BLSP1_QUP2_I2C_APPS_CLK>; + pinctrl-names = "i2c_active", "i2c_sleep"; + pinctrl-0 = <&i2c_3_sda_active>, <&i2c_3_scl_active>; + pinctrl-1 = <&i2c_3_sleep>; + status = "disabled"; + }; + + i2c_4: i2c@78b8000 { /* BLSP1 QUP4 */ + compatible = "qcom,i2c-msm-v2"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x78b8000 0x600>; + reg-names = "qup_phys_addr"; + interrupt-names = "qup_irq"; + interrupts = <0 98 0>; + dmas = <&dma_blsp1 14 64 0x20000020 0x20>, + <&dma_blsp1 15 32 0x20000020 0x20>; + dma-names = "tx", "rx"; + qcom,master-id = <86>; + qcom,clk-freq-out = <400000>; + qcom,clk-freq-in = <19200000>; + clock-names = "iface_clk", "core_clk"; + clocks = <&clock_gcc GCC_BLSP1_AHB_CLK>, + <&clock_gcc GCC_BLSP1_QUP3_I2C_APPS_CLK>; + pinctrl-names = "i2c_active", "i2c_sleep"; + pinctrl-0 = <&i2c_4_active>; + pinctrl-1 = <&i2c_4_sleep>; + status = "disabled"; + }; + + i2c_5: i2c@78b9000 { /* BLSP2 QUP1 */ + compatible = "qcom,i2c-msm-v2"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x78b9000 0x600>; + reg-names = "qup_phys_addr"; + interrupt-names = "qup_irq"; + interrupts = <0 99 0>; + dmas = <&dma_blsp1 16 64 0x20000020 0x20>, + <&dma_blsp1 17 32 0x20000020 0x20>; + dma-names = "tx", "rx"; + qcom,master-id = <86>; + qcom,clk-freq-out = <400000>; + qcom,clk-freq-in = <19200000>; + clock-names = "iface_clk", "core_clk"; + clocks = <&clock_gcc GCC_BLSP1_AHB_CLK>, + <&clock_gcc GCC_BLSP1_QUP4_I2C_APPS_CLK>; + pinctrl-names = "i2c_active", "i2c_sleep"; + pinctrl-0 = <&i2c_5_active>; + pinctrl-1 = <&i2c_5_sleep>; + status = "disabled"; + }; + + i2c_6: i2c@7af5000 { /* BLSP2 QUP1 */ + compatible = "qcom,i2c-msm-v2"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x7af5000 0x600>; + reg-names = "qup_phys_addr"; + interrupt-names = "qup_irq"; + interrupts = <0 299 0>; + dmas = <&dma_blsp2 2 64 0x20000020 0x20>, + <&dma_blsp2 3 32 0x20000020 0x20>; + dma-names = "tx", "rx"; + qcom,master-id = <84>; + qcom,clk-freq-out = <400000>; + qcom,clk-freq-in = <19200000>; + clock-names = "iface_clk", "core_clk"; + clocks = <&clock_gcc GCC_BLSP2_AHB_CLK>, + <&clock_gcc GCC_BLSP2_QUP0_I2C_APPS_CLK>; + pinctrl-names = "i2c_active", "i2c_sleep"; + pinctrl-0 = <&i2c_6_active>; + pinctrl-1 = <&i2c_6_sleep>; + status = "disabled"; + }; + + spi_1: spi@78b5000 { /* BLSP1 QUP1 */ + compatible = "qcom,spi-qup-v2"; + #address-cells = <1>; + #size-cells = <0>; + reg-names = "spi_physical", "spi_bam_physical"; + reg = <0x78b5000 0x600>, + <0x7884000 0x25000>; + interrupt-names = "spi_irq", "spi_bam_irq"; + interrupts = <0 95 0>, <0 238 0>; + spi-max-frequency = <50000000>; + qcom,use-bam; + qcom,ver-reg-exists; + qcom,bam-consumer-pipe-index = <8>; + qcom,bam-producer-pipe-index = <9>; + qcom,master-id = <86>; + qcom,use-pinctrl; + pinctrl-names = "spi_default", "spi_sleep"; + pinctrl-0 = <&spi_1_active>; + pinctrl-1 = <&spi_1_sleep>; + clock-names = "iface_clk", "core_clk"; + clocks = <&clock_gcc GCC_BLSP1_AHB_CLK>, + <&clock_gcc GCC_BLSP1_QUP0_SPI_APPS_CLK>; + status = "disabled"; + }; + + spi_2: spi@78b6000 { /* BLSP1 QUP2 */ + compatible = "qcom,spi-qup-v2"; + #address-cells = <1>; + #size-cells = <0>; + reg-names = "spi_physical", "spi_bam_physical"; + reg = <0x78b6000 0x600>, + <0x7884000 0x25000>; + interrupt-names = "spi_irq", "spi_bam_irq"; + interrupts = <0 96 0>, <0 238 0>; + spi-max-frequency = <50000000>; + qcom,use-bam; + qcom,ver-reg-exists; + qcom,bam-consumer-pipe-index = <10>; + qcom,bam-producer-pipe-index = <11>; + qcom,master-id = <86>; + qcom,use-pinctrl; + pinctrl-names = "spi_default", "spi_sleep"; + pinctrl-0 = <&spi_2_active>; + pinctrl-1 = <&spi_2_sleep>; + clock-names = "iface_clk", "core_clk"; + clocks = <&clock_gcc GCC_BLSP1_AHB_CLK>, + <&clock_gcc GCC_BLSP1_QUP1_SPI_APPS_CLK>; + status = "disabled"; + }; + + spi_3: spi@78b7000 { /* BLSP1 QUP3 */ + compatible = "qcom,spi-qup-v2"; + #address-cells = <1>; + #size-cells = <0>; + reg-names = "spi_physical", "spi_bam_physical"; + reg = <0x78b7000 0x600>, + <0x7884000 0x25000>; + interrupt-names = "spi_irq", "spi_bam_irq"; + interrupts = <0 97 0>, <0 238 0>; + spi-max-frequency = <50000000>; + qcom,use-bam; + qcom,ver-reg-exists; + qcom,bam-consumer-pipe-index = <12>; + qcom,bam-producer-pipe-index = <13>; + qcom,master-id = <86>; + qcom,use-pinctrl; + pinctrl-names = "spi_default", "spi_sleep"; + pinctrl-0 = <&spi_3_active>; + pinctrl-1 = <&spi_3_sleep>; + clock-names = "iface_clk", "core_clk"; + clocks = <&clock_gcc GCC_BLSP1_AHB_CLK>, + <&clock_gcc GCC_BLSP1_QUP2_SPI_APPS_CLK>; + status = "disabled"; + }; + + spi_4: spi@78b8000 { /* BLSP1 QUP4 */ + compatible = "qcom,spi-qup-v2"; + #address-cells = <1>; + #size-cells = <0>; + reg-names = "spi_physical", "spi_bam_physical"; + reg = <0x78b8000 0x600>, + <0x7884000 0x25000>; + interrupt-names = "spi_irq", "spi_bam_irq"; + interrupts = <0 98 0>, <0 238 0>; + spi-max-frequency = <50000000>; + qcom,use-bam; + qcom,ver-reg-exists; + qcom,bam-consumer-pipe-index = <14>; + qcom,bam-producer-pipe-index = <15>; + qcom,master-id = <86>; + qcom,use-pinctrl; + pinctrl-names = "spi_default", "spi_sleep"; + pinctrl-0 = <&spi_4_active>; + pinctrl-1 = <&spi_4_sleep>; + clock-names = "iface_clk", "core_clk"; + clocks = <&clock_gcc GCC_BLSP1_AHB_CLK>, + <&clock_gcc GCC_BLSP1_QUP3_SPI_APPS_CLK>; + status = "disabled"; + }; + + spi_5: spi@78b9000 { /* BLSP1 QUP2 */ + compatible = "qcom,spi-qup-v2"; + #address-cells = <1>; + #size-cells = <0>; + reg-names = "spi_physical", "spi_bam_physical"; + reg = <0x78b9000 0x600>, + <0x7884000 0x25000>; + interrupt-names = "spi_irq", "spi_bam_irq"; + interrupts = <0 99 0>, <0 238 0>; + spi-max-frequency = <50000000>; + qcom,use-bam; + qcom,ver-reg-exists; + qcom,bam-consumer-pipe-index = <16>; + qcom,bam-producer-pipe-index = <17>; + qcom,master-id = <86>; + qcom,use-pinctrl; + pinctrl-names = "spi_default", "spi_sleep"; + pinctrl-0 = <&spi_5_active>; + pinctrl-1 = <&spi_5_sleep>; + clock-names = "iface_clk", "core_clk"; + clocks = <&clock_gcc GCC_BLSP1_AHB_CLK>, + <&clock_gcc GCC_BLSP1_QUP4_SPI_APPS_CLK>; + status = "disabled"; + }; + + spi_6: spi@7af5000 { /* BLSP2 QUP1 */ + compatible = "qcom,spi-qup-v2"; + #address-cells = <1>; + #size-cells = <0>; + reg-names = "spi_physical", "spi_bam_physical"; + reg = <0x7af5000 0x600>, + <0x7ac4000 0x17000>; + interrupt-names = "spi_irq", "spi_bam_irq"; + interrupts = <0 299 0>, <0 239 0>; + spi-max-frequency = <50000000>; + qcom,use-bam; + qcom,ver-reg-exists; + qcom,bam-consumer-pipe-index = <2>; + qcom,bam-producer-pipe-index = <3>; + qcom,master-id = <84>; + qcom,use-pinctrl; + pinctrl-names = "spi_default", "spi_sleep"; + pinctrl-0 = <&spi_6_active>; + pinctrl-1 = <&spi_6_sleep>; + clock-names = "iface_clk", "core_clk"; + clocks = <&clock_gcc GCC_BLSP2_AHB_CLK>, + <&clock_gcc GCC_BLSP2_QUP0_SPI_APPS_CLK>; + status = "disabled"; + }; + + + blsp1_uart1_hs: uart@78af000 { /* BLSP1 UART1 */ + compatible = "qcom,msm-hsuart-v14"; + reg = <0x78af000 0x200>, + <0x7884000 0x25000>; + reg-names = "core_mem", "bam_mem"; + interrupt-names = "core_irq", "bam_irq", "wakeup_irq"; + #address-cells = <0>; + interrupt-parent = <&blsp1_uart1_hs>; + interrupts = <0 1 2>; + #interrupt-cells = <1>; + interrupt-map-mask = <0xffffffff>; + interrupt-map = <0 &intc 0 0 107 0 + 1 &intc 0 0 238 0 + 2 &tlmm 31 0>; + + qcom,inject-rx-on-wakeup; + qcom,rx-char-to-inject = <0xfd>; + + qcom,bam-tx-ep-pipe-index = <0>; + qcom,bam-rx-ep-pipe-index = <1>; + qcom,master-id = <86>; + clock-names = "core_clk", "iface_clk"; + clocks = <&clock_gcc GCC_BLSP1_UART0_APPS_CLK>, + <&clock_gcc GCC_BLSP1_AHB_CLK>; + pinctrl-names = "sleep", "default"; + pinctrl-0 = <&blsp1_uart1_sleep>; + pinctrl-1 = <&blsp1_uart1_active>; + + qcom,msm-bus,name = "buart1"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <86 512 0 0>, + <86 512 500 800>; + status = "disabled"; + }; + + blsp1_uart2_hs: uart@78b0000{ /* BLSP1 UART2 */ + compatible = "qcom,msm-hsuart-v14"; + reg = <0x78b0000 0x200>, + <0x7884000 0x25000>; + reg-names = "core_mem", "bam_mem"; + interrupt-names = "core_irq", "bam_irq", "wakeup_irq"; + #address-cells = <0>; + interrupt-parent = <&blsp1_uart2_hs>; + interrupts = <0 1 2>; + #interrupt-cells = <1>; + interrupt-map-mask = <0xffffffff>; + interrupt-map = <0 &intc 0 0 108 0 + 1 &intc 0 0 238 0 + 2 &tlmm 23 0>; + + qcom,inject-rx-on-wakeup; + qcom,rx-char-to-inject = <0xfd>; + + qcom,bam-tx-ep-pipe-index = <2>; + qcom,bam-rx-ep-pipe-index = <3>; + qcom,master-id = <86>; + clock-names = "core_clk", "iface_clk"; + clocks = <&clock_gcc GCC_BLSP1_UART1_APPS_CLK>, + <&clock_gcc GCC_BLSP1_AHB_CLK>; + pinctrl-names = "sleep", "default"; + pinctrl-0 = <&blsp1_uart2_sleep>; + pinctrl-1 = <&blsp1_uart2_active>; + + qcom,msm-bus,name = "buart2"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <86 512 0 0>, + <86 512 500 800>; + status = "disabled"; + }; + + blsp1_uart3_hs: uart@78b1000 { /* BLSP1 UART3 */ + compatible = "qcom,msm-hsuart-v14"; + reg = <0x78b1000 0x200>, + <0x7884000 0x25000>; + reg-names = "core_mem", "bam_mem"; + interrupt-names = "core_irq", "bam_irq", "wakeup_irq"; + #address-cells = <0>; + interrupt-parent = <&blsp1_uart3_hs>; + interrupts = <0 1 2>; + #interrupt-cells = <1>; + interrupt-map-mask = <0xffffffff>; + interrupt-map = <0 &intc 0 0 118 0 + 1 &intc 0 0 238 0 + 2 &tlmm 18 0>; + + qcom,inject-rx-on-wakeup; + qcom,rx-char-to-inject = <0xfd>; + + qcom,bam-tx-ep-pipe-index = <4>; + qcom,bam-rx-ep-pipe-index = <5>; + qcom,master-id = <86>; + clock-names = "core_clk", "iface_clk"; + clocks = <&clock_gcc GCC_BLSP1_UART2_APPS_CLK>, + <&clock_gcc GCC_BLSP1_AHB_CLK>; + pinctrl-names = "sleep", "default"; + pinctrl-0 = <&blsp1_uart3_sleep>; + pinctrl-1 = <&blsp1_uart3_active>; + + qcom,msm-bus,name = "buart3"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <86 512 0 0>, + <86 512 500 800>; + status = "disabled"; + }; + + blsp1_uart4_hs: uart@78b2000 { /* BLSP1 UART4 */ + compatible = "qcom,msm-hsuart-v14"; + reg = <0x78b2000 0x200>, + <0x7884000 0x25000>; + reg-names = "core_mem", "bam_mem"; + interrupt-names = "core_irq", "bam_irq", "wakeup_irq"; + #address-cells = <0>; + interrupt-parent = <&blsp1_uart4_hs>; + interrupts = <0 1 2>; + #interrupt-cells = <1>; + interrupt-map-mask = <0xffffffff>; + interrupt-map = <0 &intc 0 0 119 0 + 1 &intc 0 0 238 0 + 2 &tlmm 83 0>; + + qcom,inject-rx-on-wakeup; + qcom,rx-char-to-inject = <0xfd>; + + qcom,bam-tx-ep-pipe-index = <6>; + qcom,bam-rx-ep-pipe-index = <7>; + qcom,master-id = <86>; + clock-names = "core_clk", "iface_clk"; + clocks = <&clock_gcc GCC_BLSP1_UART3_APPS_CLK>, + <&clock_gcc GCC_BLSP1_AHB_CLK>; + pinctrl-names = "sleep", "default"; + pinctrl-0 = <&blsp1_uart4_tx_sleep>, + <&blsp1_uart4_rxcts_sleep>, <&blsp1_uart4_rfr_sleep>; + pinctrl-1 = <&blsp1_uart4_tx_active>, + <&blsp1_uart4_rxcts_active>, <&blsp1_uart4_rfr_active>; + + qcom,msm-bus,name = "buart4"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <86 512 0 0>, + <86 512 500 800>; + status = "disabled"; + }; + + blsp2_uart1_hs: uart@7aef000 { /* BLSP1 UART4 */ + compatible = "qcom,msm-hsuart-v14"; + reg = <0x7aef000 0x200>, + <0x7ac4000 0x17000>; + reg-names = "core_mem", "bam_mem"; + interrupt-names = "core_irq", "bam_irq", "wakeup_irq"; + #address-cells = <0>; + interrupt-parent = <&blsp2_uart1_hs>; + interrupts = <0 1 2>; + #interrupt-cells = <1>; + interrupt-map-mask = <0xffffffff>; + interrupt-map = <0 &intc 0 0 297 0 + 1 &intc 0 0 239 0 + 2 &tlmm 27 0>; + + qcom,inject-rx-on-wakeup; + qcom,rx-char-to-inject = <0xfd>; + + qcom,bam-tx-ep-pipe-index = <0>; + qcom,bam-rx-ep-pipe-index = <1>; + qcom,master-id = <84>; + clock-names = "core_clk", "iface_clk"; + clocks = <&clock_gcc GCC_BLSP2_UART0_APPS_CLK>, + <&clock_gcc GCC_BLSP2_AHB_CLK>; + pinctrl-names = "sleep", "default"; + pinctrl-0 = <&blsp2_uart1_sleep>; + pinctrl-1 = <&blsp2_uart1_active>; + + qcom,msm-bus,name = "buart5"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <84 512 0 0>, + <84 512 500 800>; + status = "disabled"; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/qcs405-pinctrl.dtsi b/arch/arm64/boot/dts/qcom/qcs405-pinctrl.dtsi index ce806af6f4e9..470b0322f829 100644 --- a/arch/arm64/boot/dts/qcom/qcs405-pinctrl.dtsi +++ b/arch/arm64/boot/dts/qcom/qcs405-pinctrl.dtsi @@ -48,5 +48,600 @@ }; }; }; + + blsp1_uart1 { + blsp1_uart1_active: blsp1_uart1_active { + mux { + pins = "gpio30", "gpio31", + "gpio32", "gpio33"; + function = "blsp_uart0"; + }; + + config { + pins = "gpio30", "gpio31", + "gpio32", "gpio33"; + drive-strength = <2>; + bias-disable; + }; + }; + + blsp1_uart1_sleep: blsp1_uart1_sleep { + mux { + pins = "gpio30", "gpio31", + "gpio32", "gpio33"; + function = "gpio"; + }; + + config { + pins = "gpio30", "gpio31", + "gpio32", "gpio33"; + drive-strength = <2>; + bias-disable; + }; + }; + }; + + blsp1_uart2 { + blsp1_uart2_active: blsp1_uart2_active { + mux { + pins = "gpio22", "gpio23", + "gpio24", "gpio25"; + function = "blsp_uart1"; + }; + + config { + pins = "gpio22", "gpio23", + "gpio24", "gpio25"; + drive-strength = <2>; + bias-disable; + }; + }; + + blsp1_uart2_sleep: blsp1_uart2_sleep { + mux { + pins = "gpio22", "gpio23", + "gpio24", "gpio25"; + function = "gpio"; + }; + + config { + pins = "gpio22", "gpio23", + "gpio24", "gpio25"; + drive-strength = <2>; + bias-disable; + }; + }; + }; + + blsp1_uart3 { + blsp1_uart3_active: blsp1_uart3_active { + mux { + pins = "gpio17", "gpio18", + "gpio19", "gpio20"; + function = "blsp_uart2"; + }; + + config { + pins = "gpio17", "gpio18", + "gpio19", "gpio20"; + drive-strength = <2>; + bias-disable; + }; + }; + + blsp1_uart3_sleep: blsp1_uart3_sleep { + mux { + pins = "gpio17", "gpio18", + "gpio19", "gpio20"; + function = "gpio"; + }; + + config { + pins = "gpio17", "gpio18", + "gpio19", "gpio20"; + drive-strength = <2>; + bias-disable; + }; + }; + }; + + blsp1_uart4: blsp1_uart4 { + blsp1_uart4_tx_active: blsp1_uart4_tx_active { + mux { + pins = "gpio82"; + function = "blsp_uart3"; + }; + + config { + pins = "gpio82"; + drive-strength = <2>; + bias-disable; + }; + }; + + blsp1_uart4_tx_sleep: blsp1_uart4_tx_sleep { + mux { + pins = "gpio82"; + function = "gpio"; + }; + + config { + pins = "gpio82"; + drive-strength = <2>; + bias-pull-up; + }; + }; + + blsp1_uart4_rxcts_active: blsp1_uart4_rxcts_active { + mux { + pins = "gpio83", "gpio84"; + function = "blsp_uart3"; + }; + + config { + pins = "gpio83", "gpio84"; + drive-strength = <2>; + bias-disable; + }; + }; + + blsp1_uart4_rxcts_sleep: blsp1_uart4_rxcts_sleep { + mux { + pins = "gpio83", "gpio84"; + function = "gpio"; + }; + + config { + pins = "gpio83", "gpio84"; + drive-strength = <2>; + bias-no-pull; + }; + }; + + blsp1_uart4_rfr_active: blsp1_uart4_rfr_active { + mux { + pins = "gpio85"; + function = "blsp_uart3"; + }; + + config { + pins = "gpio85"; + drive-strength = <2>; + bias-disable; + }; + }; + + blsp1_uart4_rfr_sleep: blsp1_uart4_rfr_sleep { + mux { + pins = "gpio85"; + function = "gpio"; + }; + + config { + pins = "gpio85"; + drive-strength = <2>; + bias-no-pull; + }; + }; + }; + + blsp2_uart1 { + blsp2_uart1_active: blsp2_uart1_active { + mux { + pins = "gpio26", "gpio27", + "gpio28", "gpio29"; + function = "blsp_uart5"; + }; + + config { + pins = "gpio26", "gpio27", + "gpio28", "gpio29"; + drive-strength = <2>; + bias-disable; + }; + }; + + blsp2_uart1_sleep: blsp2_uart1_sleep { + mux { + pins = "gpio26", "gpio27", + "gpio28", "gpio29"; + function = "gpio"; + }; + + config { + pins = "gpio26", "gpio27", + "gpio28", "gpio29"; + drive-strength = <2>; + bias-disable; + }; + }; + }; + + /* SPI CONFIGURATION */ + spi_1 { + spi_1_active: spi_1_active { + mux { + pins = "gpio30", "gpio31", + "gpio32", "gpio33"; + function = "blsp_spi0"; + }; + + config { + pins = "gpio30", "gpio31", + "gpio32", "gpio33"; + drive-strength = <6>; + bias-disable; + }; + }; + + spi_1_sleep: spi_1_sleep { + mux { + pins = "gpio30", "gpio31", + "gpio32", "gpio33"; + function = "blsp_spi0"; + }; + + config { + pins = "gpio30", "gpio31", + "gpio32", "gpio33"; + drive-strength = <6>; + bias-disable; + }; + }; + }; + + spi_2 { + spi_2_active: spi_2_active { + mux { + pins = "gpio22", "gpio23", + "gpio24", "gpio25"; + function = "blsp_spi1"; + }; + + config { + pins = "gpio22", "gpio23", + "gpio24", "gpio25"; + drive-strength = <6>; + bias-disable; + }; + }; + + spi_2_sleep: spi_2_sleep { + mux { + pins = "gpio22", "gpio23", + "gpio24", "gpio25"; + function = "blsp_spi1"; + }; + + config { + pins = "gpio22", "gpio23", + "gpio24", "gpio25"; + drive-strength = <6>; + bias-disable; + }; + }; + }; + + spi_3 { + spi_3_active: spi_3_active { + mux { + pins = "gpio17", "gpio18", + "gpio19", "gpio20"; + function = "blsp_spi2"; + }; + + config { + pins = "gpio17", "gpio18", + "gpio19", "gpio20"; + drive-strength = <6>; + bias-disable; + }; + }; + + spi_3_sleep: spi_3_sleep { + mux { + pins = "gpio17", "gpio18", + "gpio19", "gpio20"; + function = "blsp_spi2"; + }; + + config { + pins = "gpio17", "gpio18", + "gpio19", "gpio20"; + drive-strength = <6>; + bias-disable; + }; + }; + }; + + spi_4 { + spi_4_active: spi_4_active { + mux { + pins = "gpio82", "gpio83", + "gpio84", "gpio85"; + function = "blsp_spi3"; + }; + + config { + pins = "gpio82", "gpio83", + "gpio84", "gpio85"; + drive-strength = <6>; + bias-disable; + }; + }; + + spi_4_sleep: spi_4_sleep { + mux { + pins = "gpio82", "gpio83", + "gpio84", "gpio85"; + function = "blsp_spi3"; + }; + + config { + pins = "gpio82", "gpio83", + "gpio84", "gpio85"; + drive-strength = <6>; + bias-disable; + }; + }; + }; + + spi_5 { + spi_5_active: spi_5_active { + mux { + pins = "gpio37", "gpio38", + "gpio117", "gpio118"; + function = "blsp_spi4"; + }; + + config { + pins = "gpio37", "gpio38", + "gpio117", "gpio118"; + drive-strength = <6>; + bias-disable; + }; + }; + + spi_5_sleep: spi_5_sleep { + mux { + pins = "gpio37", "gpio38", + "gpio117", "gpio118"; + function = "blsp_spi4"; + }; + + config { + pins = "gpio37", "gpio38", + "gpio117", "gpio118"; + drive-strength = <6>; + bias-disable; + }; + }; + }; + + spi_6 { + spi_6_active: spi_6_active { + mux { + pins = "gpio26", "gpio27", + "gpio28", "gpio29"; + function = "blsp_spi5"; + }; + + config { + pins = "gpio26", "gpio27", + "gpio28", "gpio29"; + drive-strength = <6>; + bias-disable; + }; + }; + + spi_6_sleep: spi_6_sleep { + mux { + pins = "gpio26", "gpio27", + "gpio28", "gpio29"; + function = "blsp_spi5"; + }; + + config { + pins = "gpio26", "gpio27", + "gpio28", "gpio29"; + drive-strength = <6>; + bias-disable; + }; + }; + }; + + i2c_1 { + i2c_1_active: i2c_1_active { + /* active state */ + mux { + pins = "gpio32", "gpio33"; + function = "blsp_i2c0"; + }; + + config { + pins = "gpio32", "gpio33"; + drive-strength = <2>; + bias-disable; + }; + }; + + i2c_1_sleep: i2c_1_sleep { + /* suspended state */ + mux { + pins = "gpio32", "gpio33"; + function = "gpio"; + }; + + config { + pins = "gpio32", "gpio33"; + drive-strength = <2>; + bias-disable; + }; + }; + }; + + i2c_2 { + i2c_2_active: i2c_2_active { + /* active state */ + mux { + pins = "gpio24", "gpio25"; + function = "blsp_i2c1"; + }; + + config { + pins = "gpio24", "gpio25"; + drive-strength = <2>; + bias-disable; + }; + }; + + i2c_2_sleep: i2c_2_sleep { + /* suspended state */ + mux { + pins = "gpio24", "gpio25"; + function = "gpio"; + }; + + config { + pins = "gpio24", "gpio25"; + drive-strength = <2>; + bias-disable; + }; + }; + }; + + i2c_3 { + i2c_3_sda_active: i2c_3_sda_active { + /* active state */ + mux { + pins = "gpio19"; + function = "blsp_i2c_sda_a2"; + }; + + config { + pins = "gpio19"; + drive-strength = <2>; + bias-disable; + }; + }; + + i2c_3_scl_active: i2c_3_scl_active { + /* active state */ + mux { + pins = "gpio20"; + function = "blsp_i2c_scl_a2"; + }; + + config { + pins = "gpio20"; + drive-strength = <2>; + bias-disable; + }; + }; + + i2c_3_sleep: i2c_3_sleep { + /* suspended state */ + mux { + pins = "gpio19", "gpio20"; + function = "gpio"; + }; + + config { + pins = "gpio19", "gpio20"; + drive-strength = <2>; + bias-disable; + }; + }; + }; + + i2c_4 { + i2c_4_active: i2c_4_active { + /* active state */ + mux { + pins = "gpio84", "gpio85"; + function = "blsp_i2c3"; + }; + + config { + pins = "gpio84", "gpio85"; + drive-strength = <2>; + bias-disable; + }; + }; + + i2c_4_sleep: i2c_4_sleep { + /* suspended state */ + mux { + pins = "gpio84", "gpio85"; + function = "gpio"; + }; + + config { + pins = "gpio84", "gpio85"; + drive-strength = <2>; + bias-disable; + }; + }; + }; + + i2c_5 { + i2c_5_active: i2c_5_active { + /* active state */ + mux { + pins = "gpio117", "gpio118"; + function = "blsp_i2c4"; + }; + + config { + pins = "gpio117", "gpio118"; + drive-strength = <2>; + bias-disable; + }; + }; + + i2c_5_sleep: i2c_5_sleep { + /* suspended state */ + mux { + pins = "gpio117", "gpio118"; + function = "gpio"; + }; + + config { + pins = "gpio117", "gpio118"; + drive-strength = <2>; + bias-disable; + }; + }; + }; + + i2c_6 { + i2c_6_active: i2c_6_active { + /* active state */ + mux { + pins = "gpio28", "gpio29"; + function = "blsp_i2c5"; + }; + + config { + pins = "gpio28", "gpio29"; + drive-strength = <2>; + bias-disable; + }; + }; + + i2c_6_sleep: i2c_6_sleep { + /* suspended state */ + mux { + pins = "gpio28", "gpio29"; + function = "gpio"; + }; + + config { + pins = "gpio28", "gpio29"; + drive-strength = <2>; + bias-disable; + }; + }; + }; }; }; diff --git a/arch/arm64/boot/dts/qcom/qcs405.dtsi b/arch/arm64/boot/dts/qcom/qcs405.dtsi index c9066a81296f..9e0189cf11ed 100644 --- a/arch/arm64/boot/dts/qcom/qcs405.dtsi +++ b/arch/arm64/boot/dts/qcom/qcs405.dtsi @@ -39,6 +39,7 @@ }; #include "qcs405-pinctrl.dtsi" +#include "qcs405-blsp.dtsi" #include "qcs405-cpu.dtsi" &soc { @@ -164,6 +165,30 @@ qcom,pipe-attr-ee; }; + slim_aud: slim@c1c0000 { + cell-index = <1>; + compatible = "qcom,slim-ngd"; + reg = <0xc1c0000 0x2c000>, + <0xc184000 0x2a000>; + reg-names = "slimbus_physical", "slimbus_bam_physical"; + interrupts = <0 163 0>, <0 180 0>; + interrupt-names = "slimbus_irq", "slimbus_bam_irq"; + qcom,apps-ch-pipes = <0x7c0000>; + qcom,ea-pc = <0x2e0>; + status = "disabled"; + }; + + slim_qca: slim@c240000 { + cell-index = <3>; + compatible = "qcom,slim-ngd"; + reg = <0xc240000 0x2c000>, + <0xc204000 0x20000>; + reg-names = "slimbus_physical", "slimbus_bam_physical"; + interrupts = <0 191 0>, <0 63 0>; + interrupt-names = "slimbus_irq", "slimbus_bam_irq"; + status = "disabled"; + }; + blsp1_uart2: serial@78b0000 { compatible = "qcom,msm-uartdm", "qcom,msm-uartdm-v1.4"; reg = <0x78b0000 0x200>; -- GitLab From 10e335baa9d9c0e318b248453716292f94d3b2da Mon Sep 17 00:00:00 2001 From: Shefali Jain Date: Mon, 16 Apr 2018 14:06:57 +0530 Subject: [PATCH 0574/1635] clk: qcom: clk-debug: Add support for enable mask for debug clk The enable bit position could vary across targets. Add the en_mask where the enable bit position could be supplied for debug clock branch. Change-Id: I9e910f53e4a13f701a3a37b640c4f72da164f6af Signed-off-by: Shefali Jain --- drivers/clk/qcom/clk-debug.c | 12 ++++++++---- drivers/clk/qcom/clk-debug.h | 5 ++++- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/drivers/clk/qcom/clk-debug.c b/drivers/clk/qcom/clk-debug.c index ec2a318cebbe..b9d3d717ebef 100644 --- a/drivers/clk/qcom/clk-debug.c +++ b/drivers/clk/qcom/clk-debug.c @@ -209,17 +209,19 @@ static void enable_debug_clks(struct clk_debug_mux *meas, u8 index) { int dbg_cc = meas->parent[index].dbg_cc; + meas->en_mask = meas->en_mask ? meas->en_mask : CBCR_ENA; + if (dbg_cc != GCC) { /* Not all recursive muxes have a DEBUG clock. */ if (meas->parent[index].cbcr_offset != U32_MAX) regmap_update_bits(meas->regmap[dbg_cc], meas->parent[index].cbcr_offset, - CBCR_ENA, CBCR_ENA); + meas->en_mask, meas->en_mask); } /* Turn on the GCC_DEBUG_CBCR */ regmap_update_bits(meas->regmap[GCC], meas->cbcr_offset, - CBCR_ENA, CBCR_ENA); + meas->en_mask, meas->en_mask); } @@ -227,15 +229,17 @@ static void disable_debug_clks(struct clk_debug_mux *meas, u8 index) { int dbg_cc = meas->parent[index].dbg_cc; + meas->en_mask = meas->en_mask ? meas->en_mask : CBCR_ENA; + /* Turn off the GCC_DEBUG_CBCR */ regmap_update_bits(meas->regmap[GCC], meas->cbcr_offset, - CBCR_ENA, 0); + meas->en_mask, 0); if (dbg_cc != GCC) { if (meas->parent[index].cbcr_offset != U32_MAX) regmap_update_bits(meas->regmap[dbg_cc], meas->parent[index].cbcr_offset, - CBCR_ENA, 0); + meas->en_mask, 0); } } diff --git a/drivers/clk/qcom/clk-debug.h b/drivers/clk/qcom/clk-debug.h index 3aea9cde97ac..742c295e43f0 100644 --- a/drivers/clk/qcom/clk-debug.h +++ b/drivers/clk/qcom/clk-debug.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -98,6 +98,8 @@ struct clk_src { * @num_parents: number of parents * @regmap: regmaps of debug mux * @priv: private measure_clk_data to be used by debug mux + * @en_mask: indicates the enable bit mask at global clock + * controller debug mux. * @debug_offset: debug mux offset. * @post_div_offset: register with post-divider settings for the debug mux. * @cbcr_offset: branch register to turn on debug mux. @@ -116,6 +118,7 @@ struct clk_debug_mux { int num_parents; struct regmap **regmap; void *priv; + u32 en_mask; u32 debug_offset; u32 post_div_offset; u32 cbcr_offset; -- GitLab From 2ff2021ba9301a2088ebd4512066113b81369d37 Mon Sep 17 00:00:00 2001 From: Vijay Viswanath Date: Wed, 11 Apr 2018 14:38:21 +0530 Subject: [PATCH 0575/1635] ARM: dts: msm: Add sdhc1 and sdhc2 for sdm640-rumi Add entried for sdhc1(eMMC) and sdhc2(sdcard). But enable only sdhc1 for now. Enabling SD card without cd-gpio will result in continuous polling. Change-Id: I5fd71e1d5d177083600e67d46243d5bfa9171b49 Signed-off-by: Vijay Viswanath --- arch/arm64/boot/dts/qcom/sdm640-pinctrl.dtsi | 112 +++++++++++++++++++ arch/arm64/boot/dts/qcom/sdm640-rumi.dtsi | 44 ++++++++ arch/arm64/boot/dts/qcom/sdm640.dtsi | 52 +++++++++ 3 files changed, 208 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sdm640-pinctrl.dtsi b/arch/arm64/boot/dts/qcom/sdm640-pinctrl.dtsi index 819e551963f6..e5771c6f8ff0 100644 --- a/arch/arm64/boot/dts/qcom/sdm640-pinctrl.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm640-pinctrl.dtsi @@ -47,5 +47,117 @@ }; }; }; + + /* SDC pin type */ + sdc1_clk_on: sdc1_clk_on { + config { + pins = "sdc1_clk"; + bias-disable; /* NO pull */ + drive-strength = <16>; /* 16 MA */ + }; + }; + + sdc1_clk_off: sdc1_clk_off { + config { + pins = "sdc1_clk"; + bias-disable; /* NO pull */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + sdc1_cmd_on: sdc1_cmd_on { + config { + pins = "sdc1_cmd"; + bias-pull-up; /* pull up */ + drive-strength = <10>; /* 10 MA */ + }; + }; + + sdc1_cmd_off: sdc1_cmd_off { + config { + pins = "sdc1_cmd"; + num-grp-pins = <1>; + bias-pull-up; /* pull up */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + sdc1_data_on: sdc1_data_on { + config { + pins = "sdc1_data"; + bias-pull-up; /* pull up */ + drive-strength = <10>; /* 10 MA */ + }; + }; + + sdc1_data_off: sdc1_data_off { + config { + pins = "sdc1_data"; + bias-pull-up; /* pull up */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + sdc1_rclk_on: sdc1_rclk_on { + config { + pins = "sdc1_rclk"; + bias-pull-down; /* pull down */ + }; + }; + + sdc1_rclk_off: sdc1_rclk_off { + config { + pins = "sdc1_rclk"; + bias-pull-down; /* pull down */ + }; + }; + + sdc2_clk_on: sdc2_clk_on { + config { + pins = "sdc2_clk"; + bias-disable; /* NO pull */ + drive-strength = <16>; /* 16 MA */ + }; + }; + + sdc2_clk_off: sdc2_clk_off { + config { + pins = "sdc2_clk"; + bias-disable; /* NO pull */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + sdc2_cmd_on: sdc2_cmd_on { + config { + pins = "sdc2_cmd"; + bias-pull-up; /* pull up */ + drive-strength = <10>; /* 10 MA */ + }; + }; + + sdc2_cmd_off: sdc2_cmd_off { + config { + pins = "sdc2_cmd"; + bias-pull-up; /* pull up */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + sdc2_data_on: sdc2_data_on { + config { + pins = "sdc2_data"; + bias-pull-up; /* pull up */ + drive-strength = <10>; /* 10 MA */ + }; + }; + + sdc2_data_off: sdc2_data_off { + config { + pins = "sdc2_data"; + bias-pull-up; /* pull up */ + drive-strength = <2>; /* 2 MA */ + }; + }; }; }; diff --git a/arch/arm64/boot/dts/qcom/sdm640-rumi.dtsi b/arch/arm64/boot/dts/qcom/sdm640-rumi.dtsi index e2b2d1dcfb5a..1fd5029c0d78 100644 --- a/arch/arm64/boot/dts/qcom/sdm640-rumi.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm640-rumi.dtsi @@ -27,3 +27,47 @@ &qupv3_se0_2uart { status = "ok"; }; + +&sdhc_1 { + vdd-supply = <&pm640l_l11>; + qcom,vdd-voltage-level = <2960000 2960000>; + qcom,vdd-current-level = <200 570000>; + + vdd-io-supply = <&pm640_l12>; + qcom,vdd-io-always-on; + qcom,vdd-io-lpm-sup; + qcom,vdd-io-voltage-level = <1800000 1800000>; + qcom,vdd-io-current-level = <200 325000>; + + pinctrl-names = "active", "sleep"; + pinctrl-0 = <&sdc1_clk_on &sdc1_cmd_on &sdc1_data_on>; + pinctrl-1 = <&sdc1_clk_off &sdc1_cmd_off &sdc1_data_off>; + + qcom,clk-rates = <400000 20000000 25000000 50000000>; + qcom,bus-speed-mode = "HS200_1p8v", "DDR_1p8v"; + + /delete-property/qcom,devfreq,freq-table; + + status = "ok"; +}; + +&sdhc_2 { + vdd-supply = <&pm640l_l9>; + qcom,vdd-voltage-level = <2960000 2960000>; + qcom,vdd-current-level = <200 800000>; + + vdd-io-supply = <&pm640l_l6>; + qcom,vdd-io-voltage-level = <1800000 2950000>; + qcom,vdd-io-current-level = <200 22000>; + + pinctrl-names = "active", "sleep"; + pinctrl-0 = <&sdc2_clk_on &sdc2_cmd_on &sdc2_data_on>; + pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off>; + + qcom,clk-rates = <400000 20000000 25000000 50000000>; + qcom,bus-speed-mode = "SDR12", "SDR25", "SDR50"; + + /delete-property/qcom,devfreq,freq-table; + + status = "disabled"; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm640.dtsi b/arch/arm64/boot/dts/qcom/sdm640.dtsi index 83b097b3d624..4c13cd7d547c 100644 --- a/arch/arm64/boot/dts/qcom/sdm640.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm640.dtsi @@ -30,6 +30,8 @@ aliases { serial0 = &qupv3_se0_2uart; + sdhc1 = &sdhc_1; /* SDC1 eMMC slot */ + sdhc2 = &sdhc_2; /* SDC2 SD Card slot */ }; cpus { @@ -881,6 +883,56 @@ compatible = "qcom,llcc-amon"; }; }; + + sdhc_1: sdhci@7c4000 { + compatible = "qcom,sdhci-msm-v5"; + reg = <0x7c4000 0x1000>, <0x7c5000 0x1000>; + reg-names = "hc_mem", "cmdq_mem"; + + interrupts = <0 641 0>, <0 644 0>; + interrupt-names = "hc_irq", "pwr_irq"; + + qcom,bus-width = <8>; + qcom,large-address-bus; + + qcom,clk-rates = <400000 20000000 25000000 50000000 100000000 + 192000000 384000000>; + qcom,bus-speed-mode = "HS400_1p8v", "HS200_1p8v", "DDR_1p8v"; + + qcom,devfreq,freq-table = <50000000 200000000>; + + clocks = <&clock_gcc GCC_SDCC1_AHB_CLK>, + <&clock_gcc GCC_SDCC1_APPS_CLK>; + clock-names = "iface_clk", "core_clk"; + + qcom,nonremovable; + status = "disabled"; + }; + + sdhc_2: sdhci@8804000 { + compatible = "qcom,sdhci-msm-v5"; + reg = <0x8804000 0x1000>; + reg-names = "hc_mem"; + + interrupts = <0 204 0>, <0 222 0>; + interrupt-names = "hc_irq", "pwr_irq"; + + qcom,bus-width = <4>; + qcom,large-address-bus; + + qcom,clk-rates = <400000 20000000 25000000 + 50000000 100000000 201500000>; + qcom,bus-speed-mode = "SDR12", "SDR25", "SDR50", "DDR50", + "SDR104"; + + qcom,devfreq,freq-table = <50000000 201500000>; + + clocks = <&clock_gcc GCC_SDCC2_AHB_CLK>, + <&clock_gcc GCC_SDCC2_APPS_CLK>; + clock-names = "iface_clk", "core_clk"; + + status = "disabled"; + }; }; #include "sdm640-pinctrl.dtsi" -- GitLab From 3bbd0dbf4babd2ba0020bb37e3f0e2ecbea05da3 Mon Sep 17 00:00:00 2001 From: Vijay Viswanath Date: Mon, 16 Apr 2018 10:53:58 +0530 Subject: [PATCH 0576/1635] ARM: config: Enable different CONFIG_MMC flags for sdm640 Enable various features such as clock gating, deferred resume, paranoid_sd_init, perf profiling and ring buffer for sdm640. The ring buffer config should only be enabled for debug builds because of perf impact. Change-Id: Iba5831cce301988260eee70a1c423085d321f657 Signed-off-by: Vijay Viswanath --- arch/arm64/configs/sdmsteppe-perf_defconfig | 4 ++++ arch/arm64/configs/sdmsteppe_defconfig | 5 +++++ 2 files changed, 9 insertions(+) diff --git a/arch/arm64/configs/sdmsteppe-perf_defconfig b/arch/arm64/configs/sdmsteppe-perf_defconfig index 4e0728e8e4e2..5012aa60c7b0 100644 --- a/arch/arm64/configs/sdmsteppe-perf_defconfig +++ b/arch/arm64/configs/sdmsteppe-perf_defconfig @@ -385,8 +385,12 @@ CONFIG_USB_CONFIGFS_F_CCID=y CONFIG_USB_PD_POLICY=y CONFIG_QPNP_USB_PDPHY=y CONFIG_MMC=y +CONFIG_MMC_PERF_PROFILING=y CONFIG_MMC_BLOCK_MINORS=32 +CONFIG_MMC_BLOCK_DEFERRED_RESUME=y CONFIG_MMC_TEST=y +CONFIG_MMC_PARANOID_SD_INIT=y +CONFIG_MMC_CLKGATE=y CONFIG_MMC_SDHCI=y CONFIG_MMC_SDHCI_PLTFM=y CONFIG_MMC_SDHCI_MSM=y diff --git a/arch/arm64/configs/sdmsteppe_defconfig b/arch/arm64/configs/sdmsteppe_defconfig index 20e542df881a..2da4caa1709a 100644 --- a/arch/arm64/configs/sdmsteppe_defconfig +++ b/arch/arm64/configs/sdmsteppe_defconfig @@ -395,8 +395,13 @@ CONFIG_USB_CONFIGFS_F_CCID=y CONFIG_USB_PD_POLICY=y CONFIG_QPNP_USB_PDPHY=y CONFIG_MMC=y +CONFIG_MMC_PERF_PROFILING=y CONFIG_MMC_BLOCK_MINORS=32 +CONFIG_MMC_BLOCK_DEFERRED_RESUME=y CONFIG_MMC_TEST=y +CONFIG_MMC_RING_BUFFER=y +CONFIG_MMC_PARANOID_SD_INIT=y +CONFIG_MMC_CLKGATE=y CONFIG_MMC_SDHCI=y CONFIG_MMC_SDHCI_PLTFM=y CONFIG_MMC_SDHCI_MSM=y -- GitLab From 84d618eb55d7e111ae6ebfddbe8141745c45147e Mon Sep 17 00:00:00 2001 From: Hardik Arya Date: Thu, 8 Mar 2018 11:50:49 +0530 Subject: [PATCH 0577/1635] diag: Allocate DCI memory using vzalloc instead of kzalloc Currently there is a possibility of kmalloc failing when system is running low on memory condition. The patch changes the dci memory allocation from kzalloc to vzalloc. CRs-Fixed: 2195818 Change-Id: I92b20d8e77ce5b2a96212f9d0757fbbff2703891 Signed-off-by: Hardik Arya --- drivers/char/diag/diag_dci.c | 41 ++++++++++++++++++------------------ 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/drivers/char/diag/diag_dci.c b/drivers/char/diag/diag_dci.c index 7075b20695e1..c98d12f76568 100644 --- a/drivers/char/diag/diag_dci.c +++ b/drivers/char/diag/diag_dci.c @@ -27,6 +27,7 @@ #include #include #include +#include #ifdef CONFIG_DIAG_OVER_USB #include #endif @@ -261,7 +262,7 @@ static int diag_dci_init_buffer(struct diag_dci_buffer_t *buffer, int type) switch (type) { case DCI_BUF_PRIMARY: buffer->capacity = IN_BUF_SIZE; - buffer->data = kzalloc(buffer->capacity, GFP_KERNEL); + buffer->data = vzalloc(buffer->capacity); if (!buffer->data) return -ENOMEM; break; @@ -271,7 +272,7 @@ static int diag_dci_init_buffer(struct diag_dci_buffer_t *buffer, int type) break; case DCI_BUF_CMD: buffer->capacity = DIAG_MAX_REQ_SIZE + DCI_BUF_SIZE; - buffer->data = kzalloc(buffer->capacity, GFP_KERNEL); + buffer->data = vzalloc(buffer->capacity); if (!buffer->data) return -ENOMEM; break; @@ -2728,7 +2729,7 @@ static int diag_dci_init_remote(void) create_dci_event_mask_tbl(temp->event_mask_composite); } - partial_pkt.data = kzalloc(MAX_DCI_PACKET_SZ, GFP_KERNEL); + partial_pkt.data = vzalloc(MAX_DCI_PACKET_SZ); if (!partial_pkt.data) return -ENOMEM; @@ -2782,7 +2783,7 @@ int diag_dci_init(void) goto err; if (driver->apps_dci_buf == NULL) { - driver->apps_dci_buf = kzalloc(DCI_BUF_SIZE, GFP_KERNEL); + driver->apps_dci_buf = vzalloc(DCI_BUF_SIZE); if (driver->apps_dci_buf == NULL) goto err; } @@ -2799,12 +2800,12 @@ int diag_dci_init(void) return DIAG_DCI_NO_ERROR; err: pr_err("diag: Could not initialize diag DCI buffers"); - kfree(driver->apps_dci_buf); + vfree(driver->apps_dci_buf); driver->apps_dci_buf = NULL; if (driver->diag_dci_wq) destroy_workqueue(driver->diag_dci_wq); - kfree(partial_pkt.data); + vfree(partial_pkt.data); partial_pkt.data = NULL; mutex_destroy(&driver->dci_mutex); mutex_destroy(&dci_log_mask_mutex); @@ -2824,9 +2825,9 @@ void diag_dci_channel_init(void) void diag_dci_exit(void) { - kfree(partial_pkt.data); + vfree(partial_pkt.data); partial_pkt.data = NULL; - kfree(driver->apps_dci_buf); + vfree(driver->apps_dci_buf); driver->apps_dci_buf = NULL; mutex_destroy(&driver->dci_mutex); mutex_destroy(&dci_log_mask_mutex); @@ -2964,7 +2965,7 @@ int diag_dci_register_client(struct diag_dci_reg_tbl_t *reg_entry) new_entry->in_service = 0; INIT_LIST_HEAD(&new_entry->list_write_buf); mutex_init(&new_entry->write_buf_mutex); - new_entry->dci_log_mask = kzalloc(DCI_LOG_MASK_SIZE, GFP_KERNEL); + new_entry->dci_log_mask = vzalloc(DCI_LOG_MASK_SIZE); if (!new_entry->dci_log_mask) { pr_err("diag: Unable to create log mask for client, %d", driver->dci_client_id); @@ -2972,14 +2973,14 @@ int diag_dci_register_client(struct diag_dci_reg_tbl_t *reg_entry) } create_dci_log_mask_tbl(new_entry->dci_log_mask, DCI_LOG_MASK_CLEAN); - new_entry->dci_event_mask = kzalloc(DCI_EVENT_MASK_SIZE, GFP_KERNEL); + new_entry->dci_event_mask = vzalloc(DCI_EVENT_MASK_SIZE); if (!new_entry->dci_event_mask) goto fail_alloc; create_dci_event_mask_tbl(new_entry->dci_event_mask); new_entry->buffers = kcalloc(new_entry->num_buffers, sizeof(struct diag_dci_buf_peripheral_t), - GFP_KERNEL); + GFP_KERNEL); if (!new_entry->buffers) { pr_err("diag: Unable to allocate buffers for peripherals in %s\n", __func__); @@ -3003,7 +3004,7 @@ int diag_dci_register_client(struct diag_dci_reg_tbl_t *reg_entry) if (!proc_buf->buf_primary) goto fail_alloc; proc_buf->buf_cmd = kzalloc(sizeof(struct diag_dci_buffer_t), - GFP_KERNEL); + GFP_KERNEL); if (!proc_buf->buf_cmd) goto fail_alloc; err = diag_dci_init_buffer(proc_buf->buf_primary, @@ -3036,7 +3037,7 @@ int diag_dci_register_client(struct diag_dci_reg_tbl_t *reg_entry) if (proc_buf) { mutex_destroy(&proc_buf->health_mutex); if (proc_buf->buf_primary) { - kfree(proc_buf->buf_primary->data); + vfree(proc_buf->buf_primary->data); proc_buf->buf_primary->data = NULL; mutex_destroy( &proc_buf->buf_primary->data_mutex); @@ -3044,7 +3045,7 @@ int diag_dci_register_client(struct diag_dci_reg_tbl_t *reg_entry) kfree(proc_buf->buf_primary); proc_buf->buf_primary = NULL; if (proc_buf->buf_cmd) { - kfree(proc_buf->buf_cmd->data); + vfree(proc_buf->buf_cmd->data); proc_buf->buf_cmd->data = NULL; mutex_destroy( &proc_buf->buf_cmd->data_mutex); @@ -3053,9 +3054,9 @@ int diag_dci_register_client(struct diag_dci_reg_tbl_t *reg_entry) proc_buf->buf_cmd = NULL; } } - kfree(new_entry->dci_event_mask); + vfree(new_entry->dci_event_mask); new_entry->dci_event_mask = NULL; - kfree(new_entry->dci_log_mask); + vfree(new_entry->dci_log_mask); new_entry->dci_log_mask = NULL; kfree(new_entry->buffers); new_entry->buffers = NULL; @@ -3090,7 +3091,7 @@ int diag_dci_deinit_client(struct diag_dci_client_tbl *entry) * Clear the client's log and event masks, update the cumulative * masks and send the masks to peripherals */ - kfree(entry->dci_log_mask); + vfree(entry->dci_log_mask); entry->dci_log_mask = NULL; diag_dci_invalidate_cumulative_log_mask(token); if (token == DCI_LOCAL_PROC) @@ -3098,7 +3099,7 @@ int diag_dci_deinit_client(struct diag_dci_client_tbl *entry) ret = dci_ops_tbl[token].send_log_mask(token); if (ret != DIAG_DCI_NO_ERROR) return ret; - kfree(entry->dci_event_mask); + vfree(entry->dci_event_mask); entry->dci_event_mask = NULL; diag_dci_invalidate_cumulative_event_mask(token); if (token == DCI_LOCAL_PROC) @@ -3161,12 +3162,12 @@ int diag_dci_deinit_client(struct diag_dci_client_tbl *entry) } mutex_lock(&proc_buf->buf_primary->data_mutex); - kfree(proc_buf->buf_primary->data); + vfree(proc_buf->buf_primary->data); proc_buf->buf_primary->data = NULL; mutex_unlock(&proc_buf->buf_primary->data_mutex); mutex_lock(&proc_buf->buf_cmd->data_mutex); - kfree(proc_buf->buf_cmd->data); + vfree(proc_buf->buf_cmd->data); proc_buf->buf_cmd->data = NULL; mutex_unlock(&proc_buf->buf_cmd->data_mutex); -- GitLab From b1316c12441fe6b5074a853d6c9c845c549ac945 Mon Sep 17 00:00:00 2001 From: Mayank Rana Date: Thu, 19 Apr 2018 11:49:24 -0700 Subject: [PATCH 0578/1635] ARM: dts: msm: Set maximum speed as super speed plus on SM8150 SM8150 USB primary port supports USB super speed plus functionality. Hence set maximum speed as super speed plus. Change-Id: I11b7f4b2a903def8e90d36b77897710aecdfe980 Signed-off-by: Mayank Rana --- arch/arm64/boot/dts/qcom/sm8150-usb.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/sm8150-usb.dtsi b/arch/arm64/boot/dts/qcom/sm8150-usb.dtsi index 6fe2d8d07b9d..3b8a17867a98 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-usb.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-usb.dtsi @@ -79,7 +79,7 @@ snps,ssp-u3-u0-quirk; usb-core-id = <0>; tx-fifo-resize; - maximum-speed = "super-speed"; + maximum-speed = "super-speed-plus"; dr_mode = "otg"; }; -- GitLab From 6b72d6ea278d271952d6a8ec16a74bbee98103a1 Mon Sep 17 00:00:00 2001 From: Lingutla Chandrasekhar Date: Mon, 11 Dec 2017 14:40:16 +0530 Subject: [PATCH 0579/1635] soc: qcom: update ss structure for alignment support minidump Some sub systems operates in 32 bit mode, which could lead to alignment issues with sub system toc structures. So update ss toc to use variable instead of pointer. Change-Id: I4904410f9a86e9c947a377ddd28303204f04bc34 Signed-off-by: Lingutla Chandrasekhar Signed-off-by: Isaac J. Manjarres --- drivers/soc/qcom/minidump_private.h | 2 +- drivers/soc/qcom/msm_minidump.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/soc/qcom/minidump_private.h b/drivers/soc/qcom/minidump_private.h index 81ebb1c4ee54..1e61dd7ec92f 100644 --- a/drivers/soc/qcom/minidump_private.h +++ b/drivers/soc/qcom/minidump_private.h @@ -65,7 +65,7 @@ struct md_ss_toc { u32 encryption_status; u32 encryption_required; u32 ss_region_count; - struct md_ss_region *md_ss_smem_regions_baseptr; + u64 md_ss_smem_regions_baseptr; }; /** diff --git a/drivers/soc/qcom/msm_minidump.c b/drivers/soc/qcom/msm_minidump.c index e5a1204ec09d..38843f760c2e 100644 --- a/drivers/soc/qcom/msm_minidump.c +++ b/drivers/soc/qcom/msm_minidump.c @@ -355,7 +355,7 @@ static int __init msm_minidump_init(void) return -ENOMEM; md_ss_toc->md_ss_smem_regions_baseptr = - (void *)virt_to_phys(minidump_table.md_regions); + virt_to_phys(minidump_table.md_regions); /* First entry would be ELF header */ md_ss_toc->ss_region_count = 1; -- GitLab From 7fae8e7576ded87306a44260cc6fa5ffa95c41d2 Mon Sep 17 00:00:00 2001 From: Lingutla Chandrasekhar Date: Wed, 27 Dec 2017 18:12:23 +0530 Subject: [PATCH 0580/1635] qcom: minidump: don't register idle task's stack in minidump Idle task stacks are not much useful for debug in minidump. Remove idle task and its stack registration to optimize minidump size and collection time. Change-Id: Ifa9e3ba54a6a0c912aa022707496c8f2e48dee02 Signed-off-by: Lingutla Chandrasekhar Signed-off-by: Isaac J. Manjarres --- drivers/soc/qcom/minidump_log.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/soc/qcom/minidump_log.c b/drivers/soc/qcom/minidump_log.c index 7b177cc022de..d85c506fb796 100644 --- a/drivers/soc/qcom/minidump_log.c +++ b/drivers/soc/qcom/minidump_log.c @@ -100,6 +100,9 @@ void dump_stack_minidump(u64 sp) unsigned int stack_pages, i, copy_pages; u64 base_addr; + if (is_idle_task(current)) + return; + /* * Since stacks are now allocated with vmalloc, the translation to * physical address is not a simple linear transformation like it is -- GitLab From 75cc47bfa5f8ffb8ee43d6597ac2e8c74093cd91 Mon Sep 17 00:00:00 2001 From: Ingrid Gallardo Date: Tue, 3 Apr 2018 14:07:08 -0700 Subject: [PATCH 0581/1635] drm/msm/sde: fix to set the interfaces for cont splash Current driver is not updating the correct interfaces during the continuous splash case. Update the continuous splash softwar to be able to read the interfaces enabled for each controller. Change-Id: I9318ee4434f1c59897aaaca499274287f8043f09 Signed-off-by: Ingrid Gallardo --- drivers/gpu/drm/msm/sde/sde_encoder.c | 12 +++++- .../gpu/drm/msm/sde/sde_encoder_phys_cmd.c | 10 ++++- drivers/gpu/drm/msm/sde/sde_hw_ctl.c | 38 +++++++++++++++++++ drivers/gpu/drm/msm/sde/sde_hw_ctl.h | 7 ++++ drivers/gpu/drm/msm/sde/sde_hw_mdss.h | 8 ---- drivers/gpu/drm/msm/sde/sde_rm.c | 14 ++----- 6 files changed, 69 insertions(+), 20 deletions(-) diff --git a/drivers/gpu/drm/msm/sde/sde_encoder.c b/drivers/gpu/drm/msm/sde/sde_encoder.c index 65162c67d316..be1e0fbc5f77 100644 --- a/drivers/gpu/drm/msm/sde/sde_encoder.c +++ b/drivers/gpu/drm/msm/sde/sde_encoder.c @@ -4828,7 +4828,7 @@ int sde_encoder_update_caps_for_cont_splash(struct drm_encoder *encoder) struct sde_connector *sde_conn = NULL; struct sde_connector_state *sde_conn_state = NULL; struct drm_display_mode *drm_mode = NULL; - struct sde_rm_hw_iter dsc_iter, pp_iter, ctl_iter; + struct sde_rm_hw_iter dsc_iter, pp_iter, ctl_iter, intf_iter; int ret = 0, i; if (!encoder) { @@ -4965,6 +4965,16 @@ int sde_encoder_update_caps_for_cont_splash(struct drm_encoder *encoder) phys->hw_ctl = (struct sde_hw_ctl *) ctl_iter.hw; } + sde_rm_init_hw_iter(&intf_iter, encoder->base.id, SDE_HW_BLK_INTF); + for (i = 0; i < sde_enc->num_phys_encs; i++) { + struct sde_encoder_phys *phys = sde_enc->phys_encs[i]; + + phys->hw_intf = NULL; + if (!sde_rm_get_hw(&sde_kms->rm, &intf_iter)) + break; + phys->hw_intf = (struct sde_hw_intf *) intf_iter.hw; + } + for (i = 0; i < sde_enc->num_phys_encs; i++) { struct sde_encoder_phys *phys = sde_enc->phys_encs[i]; diff --git a/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c b/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c index 248d54ddcb92..5bf6b401caf2 100644 --- a/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c +++ b/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c @@ -376,8 +376,16 @@ static void _sde_encoder_phys_cmd_setup_irq_hw_idx( { struct sde_encoder_irq *irq; - if (!phys_enc || !phys_enc->hw_pp || !phys_enc->hw_intf) + if (!phys_enc || !phys_enc->hw_pp || !phys_enc->hw_ctl) { + SDE_ERROR("invalid args %d %d\n", !phys_enc, + phys_enc ? !phys_enc->hw_pp : 0); return; + } + + if (phys_enc->has_intf_te && !phys_enc->hw_intf) { + SDE_ERROR("invalid intf configuration\n"); + return; + } irq = &phys_enc->irq[INTR_IDX_CTL_START]; irq->hw_idx = phys_enc->hw_ctl->idx; diff --git a/drivers/gpu/drm/msm/sde/sde_hw_ctl.c b/drivers/gpu/drm/msm/sde/sde_hw_ctl.c index 43890964e810..4ab6941697a3 100644 --- a/drivers/gpu/drm/msm/sde/sde_hw_ctl.c +++ b/drivers/gpu/drm/msm/sde/sde_hw_ctl.c @@ -576,6 +576,42 @@ static inline int sde_hw_ctl_trigger_flush_v1(struct sde_hw_ctl *ctx) return 0; } +static inline u32 sde_hw_ctl_get_intf_v1(struct sde_hw_ctl *ctx) +{ + struct sde_hw_blk_reg_map *c; + u32 intf_active; + + if (!ctx) { + pr_err("Invalid input argument\n"); + return 0; + } + + c = &ctx->hw; + intf_active = SDE_REG_READ(c, CTL_INTF_ACTIVE); + + return intf_active; +} + +static inline u32 sde_hw_ctl_get_intf(struct sde_hw_ctl *ctx) +{ + struct sde_hw_blk_reg_map *c; + u32 ctl_top; + u32 intf_active = 0; + + if (!ctx) { + pr_err("Invalid input argument\n"); + return 0; + } + + c = &ctx->hw; + ctl_top = SDE_REG_READ(c, CTL_TOP); + + intf_active = (ctl_top > 0) ? + BIT(ctl_top - 1) : 0; + + return intf_active; +} + static u32 sde_hw_ctl_poll_reset_status(struct sde_hw_ctl *ctx, u32 timeout_us) { struct sde_hw_blk_reg_map *c; @@ -1011,6 +1047,7 @@ static void _setup_ctl_ops(struct sde_hw_ctl_ops *ops, ops->update_bitmask_merge3d = sde_hw_ctl_update_bitmask_merge3d_v1; ops->update_bitmask_cwb = sde_hw_ctl_update_bitmask_cwb_v1; + ops->get_ctl_intf = sde_hw_ctl_get_intf_v1; } else { ops->update_pending_flush = sde_hw_ctl_update_pending_flush; ops->trigger_flush = sde_hw_ctl_trigger_flush; @@ -1020,6 +1057,7 @@ static void _setup_ctl_ops(struct sde_hw_ctl_ops *ops, ops->update_bitmask_cdm = sde_hw_ctl_update_bitmask_cdm; ops->update_bitmask_wb = sde_hw_ctl_update_bitmask_wb; ops->update_bitmask_intf = sde_hw_ctl_update_bitmask_intf; + ops->get_ctl_intf = sde_hw_ctl_get_intf; } ops->clear_pending_flush = sde_hw_ctl_clear_pending_flush; ops->get_pending_flush = sde_hw_ctl_get_pending_flush; diff --git a/drivers/gpu/drm/msm/sde/sde_hw_ctl.h b/drivers/gpu/drm/msm/sde/sde_hw_ctl.h index a2db1a8eb534..08167a400953 100644 --- a/drivers/gpu/drm/msm/sde/sde_hw_ctl.h +++ b/drivers/gpu/drm/msm/sde/sde_hw_ctl.h @@ -380,6 +380,13 @@ struct sde_hw_ctl_ops { */ u32 (*read_ctl_top)(struct sde_hw_ctl *ctx); + /** + * get interfaces for the active CTL . + * @ctx : ctl path ctx pointer + * @return : bit mask with the active interfaces for the CTL + */ + u32 (*get_ctl_intf)(struct sde_hw_ctl *ctx); + /** * read CTL layers register value and return * the data. diff --git a/drivers/gpu/drm/msm/sde/sde_hw_mdss.h b/drivers/gpu/drm/msm/sde/sde_hw_mdss.h index 852c20693077..6f547f6bc622 100644 --- a/drivers/gpu/drm/msm/sde/sde_hw_mdss.h +++ b/drivers/gpu/drm/msm/sde/sde_hw_mdss.h @@ -561,19 +561,11 @@ struct sde_splash_lm_hw { /** * struct ctl_top - Struct contains CTL block properties - * @value: Store the CTL block register value - * @mode_sel: stores the mode selected in the CTL block - * @dspp_sel: stores the dspp selected in the CTL block - * @pp_sel: stores the pp selected in the CTL block * @intf_sel: stores the intf selected in the CTL block * @lm: Pointer to store the list of LMs in the CTL block * @ctl_lm_cnt: stores the active number of MDSS "LM" blocks in the CTL block */ struct ctl_top { - u32 value; - u8 mode_sel; - u8 dspp_sel; - u8 pp_sel; u8 intf_sel; struct sde_splash_lm_hw lm[LM_MAX - LM_0]; u8 ctl_lm_cnt; diff --git a/drivers/gpu/drm/msm/sde/sde_rm.c b/drivers/gpu/drm/msm/sde/sde_rm.c index 33990b33c5df..880592585091 100644 --- a/drivers/gpu/drm/msm/sde/sde_rm.c +++ b/drivers/gpu/drm/msm/sde/sde_rm.c @@ -1412,20 +1412,14 @@ static void _sde_rm_get_ctl_top_for_cont_splash(struct sde_hw_ctl *ctl, return; } - if (!ctl->ops.read_ctl_top) { - SDE_ERROR("read_ctl_top not initialized\n"); + if (!ctl->ops.get_ctl_intf) { + SDE_ERROR("get_ctl_intf not initialized\n"); return; } - top->value = ctl->ops.read_ctl_top(ctl); - top->intf_sel = (top->value >> 4) & 0xf; - top->pp_sel = (top->value >> 8) & 0x7; - top->dspp_sel = (top->value >> 11) & 0x3; - top->mode_sel = (top->value >> 17) & 0x1; + top->intf_sel = ctl->ops.get_ctl_intf(ctl); - SDE_DEBUG("id=%d,top->0x%x,pp_sel=0x%x,dspp_sel=0x%x,intf_sel=%d\n", - ctl->idx, top->value, top->pp_sel, - top->dspp_sel, top->intf_sel); + SDE_DEBUG("id=%d intf_sel=%d\n", ctl->idx, top->intf_sel); } int sde_rm_cont_splash_res_init(struct msm_drm_private *priv, -- GitLab From 4fb6aa3092225a303925bf2d9914be41ecf83816 Mon Sep 17 00:00:00 2001 From: Ingrid Gallardo Date: Tue, 3 Apr 2018 14:48:07 -0700 Subject: [PATCH 0582/1635] drm/msm/sde: fix to update controller in all phys encoders In some cases (i.e. dual-dsi scenarios) driver can have two physical interfaces with one single controller. For those cases, make sure that driver populates both physical encoders with the pointer to the controller hardware for the continuous splash case. Change-Id: I0edea2048b6790221f9015da786eaa3d0573d0e8 Signed-off-by: Ingrid Gallardo --- drivers/gpu/drm/msm/sde/sde_encoder.c | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/msm/sde/sde_encoder.c b/drivers/gpu/drm/msm/sde/sde_encoder.c index be1e0fbc5f77..9804d2d09ba6 100644 --- a/drivers/gpu/drm/msm/sde/sde_encoder.c +++ b/drivers/gpu/drm/msm/sde/sde_encoder.c @@ -4829,7 +4829,8 @@ int sde_encoder_update_caps_for_cont_splash(struct drm_encoder *encoder) struct sde_connector_state *sde_conn_state = NULL; struct drm_display_mode *drm_mode = NULL; struct sde_rm_hw_iter dsc_iter, pp_iter, ctl_iter, intf_iter; - int ret = 0, i; + struct sde_encoder_phys *phys_enc; + int ret = 0, i, idx; if (!encoder) { SDE_ERROR("invalid drm enc\n"); @@ -4955,14 +4956,24 @@ int sde_encoder_update_caps_for_cont_splash(struct drm_encoder *encoder) sde_enc->hw_dsc[i] = (struct sde_hw_dsc *) dsc_iter.hw; } - sde_rm_init_hw_iter(&ctl_iter, encoder->base.id, SDE_HW_BLK_CTL); - for (i = 0; i < sde_enc->num_phys_encs; i++) { - struct sde_encoder_phys *phys = sde_enc->phys_encs[i]; + /* + * If we have multiple phys encoders with one controller, make + * sure to populate the controller pointer in both phys encoders. + */ + for (idx = 0; idx < sde_enc->num_phys_encs; idx++) { + phys_enc = sde_enc->phys_encs[idx]; + phys_enc->hw_ctl = NULL; - phys->hw_ctl = NULL; - if (!sde_rm_get_hw(&sde_kms->rm, &ctl_iter)) - break; - phys->hw_ctl = (struct sde_hw_ctl *) ctl_iter.hw; + sde_rm_init_hw_iter(&ctl_iter, encoder->base.id, + SDE_HW_BLK_CTL); + for (i = 0; i < sde_enc->num_phys_encs; i++) { + if (sde_rm_get_hw(&sde_kms->rm, &ctl_iter)) { + phys_enc->hw_ctl = + (struct sde_hw_ctl *) ctl_iter.hw; + pr_debug("HW CTL intf_idx:%d hw_ctl:[0x%pK]\n", + phys_enc->intf_idx, phys_enc->hw_ctl); + } + } } sde_rm_init_hw_iter(&intf_iter, encoder->base.id, SDE_HW_BLK_INTF); -- GitLab From becb0856245f0f4d79509e4f5b4a01d3ba963d88 Mon Sep 17 00:00:00 2001 From: Ingrid Gallardo Date: Tue, 3 Apr 2018 15:10:18 -0700 Subject: [PATCH 0583/1635] drm/msm/sde: avoid intf regs access in cont. splash For continuous splash, driver needs to make sure not to access some of the non-double buffered registers during the first commit after continuous splash. Enforce this by adding the necessary checks. Change-Id: Iae8e1660374a0a9534a1840ffa200a6cb5e90144 Signed-off-by: Ingrid Gallardo --- drivers/gpu/drm/msm/sde/sde_encoder.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/msm/sde/sde_encoder.c b/drivers/gpu/drm/msm/sde/sde_encoder.c index 9804d2d09ba6..d29e9b524bb5 100644 --- a/drivers/gpu/drm/msm/sde/sde_encoder.c +++ b/drivers/gpu/drm/msm/sde/sde_encoder.c @@ -2688,7 +2688,8 @@ static void _sde_encoder_virt_enable_helper(struct drm_encoder *drm_enc) sde_kms->catalog); if (sde_enc->cur_master->hw_ctl && - sde_enc->cur_master->hw_ctl->ops.setup_intf_cfg_v1) + sde_enc->cur_master->hw_ctl->ops.setup_intf_cfg_v1 && + !sde_kms->splash_data.cont_splash_en) sde_enc->cur_master->hw_ctl->ops.setup_intf_cfg_v1( sde_enc->cur_master->hw_ctl, &sde_enc->cur_master->intf_cfg_v1); -- GitLab From 38fc2a8e8d2d09f960ee167633f309cb5eb6e580 Mon Sep 17 00:00:00 2001 From: Ingrid Gallardo Date: Wed, 28 Feb 2018 15:26:37 -0800 Subject: [PATCH 0584/1635] drm/msm/sde: fix pp-split boot up with continuous splash enabled Current driver does not boot up properly when device boots with continuous splash enabled and pp-split configuration. Fix this problem by adding the correct checks that were causing a null pointer dereference and a wrong configuration. Change-Id: I2b6b499a38305e5bd98a52e8ff606bd843dd0199 Signed-off-by: Ingrid Gallardo Signed-off-by: Jayant Shekhar --- drivers/gpu/drm/msm/sde/sde_encoder.c | 15 +++++++++++---- drivers/gpu/drm/msm/sde/sde_encoder_phys.h | 10 ++++++++-- drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c | 7 +++++++ drivers/gpu/drm/msm/sde/sde_hw_mdss.h | 2 ++ drivers/gpu/drm/msm/sde/sde_hw_top.c | 13 +++++++++++++ drivers/gpu/drm/msm/sde/sde_hw_top.h | 8 +++++++- drivers/gpu/drm/msm/sde/sde_rm.c | 12 ++++++++++-- 7 files changed, 58 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/msm/sde/sde_encoder.c b/drivers/gpu/drm/msm/sde/sde_encoder.c index d29e9b524bb5..d8bc30b25157 100644 --- a/drivers/gpu/drm/msm/sde/sde_encoder.c +++ b/drivers/gpu/drm/msm/sde/sde_encoder.c @@ -2902,8 +2902,11 @@ static void sde_encoder_virt_disable(struct drm_encoder *drm_enc) sde_encoder_resource_control(drm_enc, SDE_ENC_RC_EVENT_STOP); for (i = 0; i < sde_enc->num_phys_encs; i++) { - if (sde_enc->phys_encs[i]) + if (sde_enc->phys_encs[i]) { + sde_enc->phys_encs[i]->cont_splash_settings = false; + sde_enc->phys_encs[i]->cont_splash_single_flush = 0; sde_enc->phys_encs[i]->connector = NULL; + } } sde_enc->cur_master = NULL; @@ -4996,14 +4999,18 @@ int sde_encoder_update_caps_for_cont_splash(struct drm_encoder *encoder) return -EINVAL; } + /* update connector for master and slave phys encoders */ + phys->connector = conn; + phys->cont_splash_single_flush = + sde_kms->splash_data.single_flush_en; + phys->cont_splash_settings = true; + phys->hw_pp = sde_enc->hw_pp[i]; if (phys->ops.cont_splash_mode_set) phys->ops.cont_splash_mode_set(phys, drm_mode); - if (phys->ops.is_master && phys->ops.is_master(phys)) { - phys->connector = conn; + if (phys->ops.is_master && phys->ops.is_master(phys)) sde_enc->cur_master = phys; - } } return ret; diff --git a/drivers/gpu/drm/msm/sde/sde_encoder_phys.h b/drivers/gpu/drm/msm/sde/sde_encoder_phys.h index 3b13289a1829..488a36fe7899 100644 --- a/drivers/gpu/drm/msm/sde/sde_encoder_phys.h +++ b/drivers/gpu/drm/msm/sde/sde_encoder_phys.h @@ -269,6 +269,8 @@ struct sde_encoder_irq { * @pending_kickoff_wq: Wait queue for blocking until kickoff completes * @irq: IRQ tracking structures * @has_intf_te: Interface TE configuration support + * @cont_splash_single_flush Variable to check if single flush is enabled. + * @cont_splash_settings Variable to store continuous splash settings. */ struct sde_encoder_phys { struct drm_encoder *parent; @@ -300,6 +302,8 @@ struct sde_encoder_phys { wait_queue_head_t pending_kickoff_wq; struct sde_encoder_irq irq[INTR_IDX_MAX]; bool has_intf_te; + u32 cont_splash_single_flush; + bool cont_splash_settings; }; static inline int sde_encoder_phys_inc_pending(struct sde_encoder_phys *phys) @@ -665,7 +669,9 @@ static inline bool sde_encoder_phys_needs_single_flush( if (!phys_enc) return false; - return phys_enc && (_sde_encoder_phys_is_ppsplit(phys_enc) || - _sde_encoder_phys_is_dual_ctl(phys_enc)); + return phys_enc->cont_splash_settings ? + phys_enc->cont_splash_single_flush : + (_sde_encoder_phys_is_ppsplit(phys_enc) || + _sde_encoder_phys_is_dual_ctl(phys_enc)); } #endif /* __sde_encoder_phys_H__ */ diff --git a/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c b/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c index 5bf6b401caf2..e9fc4f0cb389 100644 --- a/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c +++ b/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c @@ -426,6 +426,13 @@ static void sde_encoder_phys_cmd_cont_splash_mode_set( phys_enc->cached_mode = *adj_mode; phys_enc->enable_state = SDE_ENC_ENABLED; + if (!phys_enc->hw_ctl || !phys_enc->hw_pp) { + SDE_DEBUG("invalid ctl:%d pp:%d\n", + (phys_enc->hw_ctl == NULL), + (phys_enc->hw_pp == NULL)); + return; + } + _sde_encoder_phys_cmd_setup_irq_hw_idx(phys_enc); } diff --git a/drivers/gpu/drm/msm/sde/sde_hw_mdss.h b/drivers/gpu/drm/msm/sde/sde_hw_mdss.h index 6f547f6bc622..b30c3f0e6f24 100644 --- a/drivers/gpu/drm/msm/sde/sde_hw_mdss.h +++ b/drivers/gpu/drm/msm/sde/sde_hw_mdss.h @@ -587,6 +587,7 @@ struct ctl_top { * @lm_cnt: stores the active number of MDSS "LM" blks for the current mode * @dsc_cnt: stores the active number of MDSS "dsc" blks for the current mode * @cont_splash_en: Stores the cont_splash status (enabled/disabled) + * @single_flush_en: Stores if the single flush is enabled. */ struct sde_splash_data { bool resource_handoff_pending; @@ -600,6 +601,7 @@ struct sde_splash_data { u8 lm_cnt; u8 dsc_cnt; bool cont_splash_en; + bool single_flush_en; }; /** diff --git a/drivers/gpu/drm/msm/sde/sde_hw_top.c b/drivers/gpu/drm/msm/sde/sde_hw_top.c index 0302a3e55194..82840e64d12f 100644 --- a/drivers/gpu/drm/msm/sde/sde_hw_top.c +++ b/drivers/gpu/drm/msm/sde/sde_hw_top.c @@ -107,6 +107,18 @@ static void sde_hw_setup_split_pipe(struct sde_hw_mdp *mdp, SDE_REG_WRITE(c, SPLIT_DISPLAY_EN, cfg->en & 0x1); } +static u32 sde_hw_get_split_flush(struct sde_hw_mdp *mdp) +{ + struct sde_hw_blk_reg_map *c; + + if (!mdp) + return 0; + + c = &mdp->hw; + + return (SDE_REG_READ(c, SSPP_SPARE) & 0x1); +} + static void sde_hw_setup_pp_split(struct sde_hw_mdp *mdp, struct split_pipe_cfg *cfg) { @@ -411,6 +423,7 @@ static void _setup_mdp_ops(struct sde_hw_mdp_ops *ops, ops->get_danger_status = sde_hw_get_danger_status; ops->setup_vsync_source = sde_hw_setup_vsync_source; ops->get_safe_status = sde_hw_get_safe_status; + ops->get_split_flush_status = sde_hw_get_split_flush; ops->setup_dce = sde_hw_setup_dce; ops->reset_ubwc = sde_hw_reset_ubwc; ops->intf_audio_select = sde_hw_intf_audio_select; diff --git a/drivers/gpu/drm/msm/sde/sde_hw_top.h b/drivers/gpu/drm/msm/sde/sde_hw_top.h index 0ca5af9359ba..950a62cee8ef 100644 --- a/drivers/gpu/drm/msm/sde/sde_hw_top.h +++ b/drivers/gpu/drm/msm/sde/sde_hw_top.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -176,6 +176,12 @@ struct sde_hw_mdp_ops { void (*get_safe_status)(struct sde_hw_mdp *mdp, struct sde_danger_safe_status *status); + /** + * get_split_flush_status - get split flush status + * @mdp: mdp top context driver + */ + u32 (*get_split_flush_status)(struct sde_hw_mdp *mdp); + /** * reset_ubwc - reset top level UBWC configuration * @mdp: mdp top context driver diff --git a/drivers/gpu/drm/msm/sde/sde_rm.c b/drivers/gpu/drm/msm/sde/sde_rm.c index 880592585091..b195e00d00fe 100644 --- a/drivers/gpu/drm/msm/sde/sde_rm.c +++ b/drivers/gpu/drm/msm/sde/sde_rm.c @@ -1430,6 +1430,7 @@ int sde_rm_cont_splash_res_init(struct msm_drm_private *priv, struct sde_rm_hw_iter iter_c; int index = 0, ctl_top_cnt; struct sde_kms *sde_kms = NULL; + struct sde_hw_mdp *hw_mdp; if (!priv || !rm || !cat || !splash_data) { SDE_ERROR("invalid input parameters\n"); @@ -1485,9 +1486,16 @@ int sde_rm_cont_splash_res_init(struct msm_drm_private *priv, sde_kms, cat->dsc_count, splash_data->dsc_ids); - SDE_DEBUG("splash_data: ctl_top_cnt=%d, lm_cnt=%d, dsc_cnt=%d\n", + + hw_mdp = sde_rm_get_mdp(rm); + if (hw_mdp && hw_mdp->ops.get_split_flush_status) { + splash_data->single_flush_en = + hw_mdp->ops.get_split_flush_status(hw_mdp); + } + + SDE_DEBUG("splash_data: ctl_top_cnt=%d, lm_cnt=%d, dsc_cnt=%d sf=%d\n", splash_data->ctl_top_cnt, splash_data->lm_cnt, - splash_data->dsc_cnt); + splash_data->dsc_cnt, splash_data->single_flush_en); return 0; } -- GitLab From 17834dcf111f612df65919d1fda75ebf1565e15a Mon Sep 17 00:00:00 2001 From: Ingrid Gallardo Date: Fri, 6 Apr 2018 17:52:06 -0700 Subject: [PATCH 0585/1635] drm/msm/sde: fix to disable autorefresh from cont splash With latest hw, autorefresh feature needs to be disabled in the hw interface. This change makes sure that during the continuous splash use case, the interface api's get called to disable auto-refresh when required. Change-Id: If4864443498efbba5b3c53478ec5a152672457a4 Signed-off-by: Ingrid Gallardo --- .../gpu/drm/msm/sde/sde_encoder_phys_cmd.c | 4 +- drivers/gpu/drm/msm/sde/sde_rm.c | 158 ++++++++++++++---- 2 files changed, 133 insertions(+), 29 deletions(-) diff --git a/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c b/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c index e9fc4f0cb389..5c4d9f25c935 100644 --- a/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c +++ b/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c @@ -254,7 +254,9 @@ static void sde_encoder_phys_cmd_autorefresh_done_irq(void *arg, int irq_idx) spin_unlock_irqrestore(phys_enc->enc_spinlock, lock_flags); SDE_EVT32_IRQ(DRMID(phys_enc->parent), - phys_enc->hw_pp->idx - PINGPONG_0, new_cnt); + phys_enc->hw_pp->idx - PINGPONG_0, + phys_enc->hw_intf->idx - INTF_0, + new_cnt); /* Signal any waiting atomic commit thread */ wake_up_all(&cmd_enc->autorefresh.kickoff_wq); diff --git a/drivers/gpu/drm/msm/sde/sde_rm.c b/drivers/gpu/drm/msm/sde/sde_rm.c index b195e00d00fe..fe2e5511c4fa 100644 --- a/drivers/gpu/drm/msm/sde/sde_rm.c +++ b/drivers/gpu/drm/msm/sde/sde_rm.c @@ -1215,47 +1215,132 @@ static u32 _sde_rm_poll_intr_status_for_cont_splash(struct sde_hw_intr *intr, return -ETIMEDOUT; } +static inline bool _sde_rm_autorefresh_validate(struct sde_hw_pingpong *pp, + struct sde_hw_intf *intf, + bool hw_intf_te) +{ + + if ((hw_intf_te && !intf) || + (!hw_intf_te && !pp)) { + SDE_ERROR("autorefresh wrong params!\n"); + return true; + } + + if (hw_intf_te) { + if (!intf->ops.get_autorefresh || + !intf->ops.setup_autorefresh || + !intf->ops.connect_external_te || + !intf->ops.get_vsync_info) { + SDE_ERROR("intf autorefresh apis not supported\n"); + return true; + } + } else { + if (!pp->ops.get_autorefresh || + !pp->ops.setup_autorefresh || + !pp->ops.connect_external_te || + !pp->ops.get_vsync_info) { + SDE_ERROR("pp autorefresh apis not supported\n"); + return true; + } + } + + return false; +} + +static inline void _sde_rm_autorefresh_get_cfg( + struct sde_hw_pingpong *pp, + struct sde_hw_intf *intf, + struct sde_hw_autorefresh *cfg, + bool hw_intf_te) +{ + if (hw_intf_te) + intf->ops.get_autorefresh(intf, cfg); + else + pp->ops.get_autorefresh(pp, cfg); +} + +static inline void _sde_rm_autorefresh_connect_external_te( + struct sde_hw_pingpong *pp, + struct sde_hw_intf *intf, + bool hw_intf_te, + bool enable) +{ + if (hw_intf_te) + intf->ops.connect_external_te(intf, enable); + else + pp->ops.connect_external_te(pp, enable); +} + +static inline void _sde_rm_autorefresh_setup(struct sde_hw_pingpong *pp, + struct sde_hw_intf *intf, + struct sde_hw_autorefresh *cfg, + bool hw_intf_te) +{ + if (hw_intf_te) + intf->ops.setup_autorefresh(intf, cfg); + else + pp->ops.setup_autorefresh(pp, cfg); +} + +static inline void _sde_rm_autorefresh_get_vsync_info( + struct sde_hw_pingpong *pp, + struct sde_hw_intf *intf, + struct sde_hw_pp_vsync_info *info, + bool hw_intf_te) +{ + if (hw_intf_te) + intf->ops.get_vsync_info(intf, info); + else + pp->ops.get_vsync_info(pp, info); +} + static int _sde_rm_autorefresh_disable(struct sde_hw_pingpong *pp, - struct sde_hw_intr *hw_intr) + struct sde_hw_intf *intf, + struct sde_hw_intr *hw_intr, + bool hw_intf_te) { u32 const timeout_ms = 35; /* Max two vsyncs delay */ int rc = 0, i, loop = 3; struct sde_hw_pp_vsync_info info; int irq_idx_pp_done = -1, irq_idx_autorefresh = -1; struct sde_hw_autorefresh cfg = {0}; + int dbg_idx; + int te_irq_idx; - if (!pp->ops.get_autorefresh || !pp->ops.setup_autorefresh || - !pp->ops.connect_external_te || !pp->ops.get_vsync_info) { - SDE_ERROR("autorefresh update api not supported\n"); + if (_sde_rm_autorefresh_validate(pp, intf, hw_intf_te)) return 0; - } + + dbg_idx = hw_intf_te ? intf->idx - INTF_0 : pp->idx - PINGPONG_0; + te_irq_idx = hw_intf_te ? intf->idx : pp->idx; /* read default autorefresh configuration */ - pp->ops.get_autorefresh(pp, &cfg); + _sde_rm_autorefresh_get_cfg(pp, intf, &cfg, hw_intf_te); + if (!cfg.enable) { - SDE_DEBUG("autorefresh already disabled\n"); - SDE_EVT32(pp->idx - PINGPONG_0, SDE_EVTLOG_FUNC_CASE1); + SDE_DEBUG("autorefresh already disabled idx:%d\n", + dbg_idx); + SDE_EVT32(dbg_idx, SDE_EVTLOG_FUNC_CASE1); return 0; } /* disable external TE first */ - pp->ops.connect_external_te(pp, false); + _sde_rm_autorefresh_connect_external_te(pp, intf, hw_intf_te, false); /* get all IRQ indexes */ if (hw_intr->ops.irq_idx_lookup) { irq_idx_pp_done = hw_intr->ops.irq_idx_lookup( - SDE_IRQ_TYPE_PING_PONG_COMP, pp->idx); + SDE_IRQ_TYPE_PING_PONG_COMP, te_irq_idx); irq_idx_autorefresh = hw_intr->ops.irq_idx_lookup( - SDE_IRQ_TYPE_PING_PONG_AUTO_REF, pp->idx); - SDE_DEBUG("pp_done itr_idx = %d autorefresh irq_idx:%d\n", + SDE_IRQ_TYPE_PING_PONG_AUTO_REF, te_irq_idx); + SDE_DEBUG("pp_done irq_idx = %d autorefresh irq_idx:%d\n", irq_idx_pp_done, irq_idx_autorefresh); } /* disable autorefresh */ cfg.enable = false; - pp->ops.setup_autorefresh(pp, &cfg); + _sde_rm_autorefresh_setup(pp, intf, &cfg, hw_intf_te); - SDE_EVT32(pp->idx - PINGPONG_0, irq_idx_pp_done, irq_idx_autorefresh); + SDE_EVT32(dbg_idx, irq_idx_pp_done, irq_idx_autorefresh); _sde_rm_clear_irq_status(hw_intr, irq_idx_pp_done, irq_idx_autorefresh); /* @@ -1267,9 +1352,9 @@ static int _sde_rm_autorefresh_disable(struct sde_hw_pingpong *pp, for (i = 0; i < loop; i++) { info.wr_ptr_line_count = 0; info.rd_ptr_init_val = 0; - pp->ops.get_vsync_info(pp, &info); + _sde_rm_autorefresh_get_vsync_info(pp, intf, &info, hw_intf_te); - SDE_EVT32(pp->idx - PINGPONG_0, info.wr_ptr_line_count, + SDE_EVT32(dbg_idx, info.wr_ptr_line_count, info.rd_ptr_init_val, SDE_EVTLOG_FUNC_CASE1); /* wait for read ptr intr */ @@ -1278,10 +1363,11 @@ static int _sde_rm_autorefresh_disable(struct sde_hw_pingpong *pp, info.wr_ptr_line_count = 0; info.rd_ptr_init_val = 0; - pp->ops.get_vsync_info(pp, &info); - SDE_DEBUG("i=%d, line count=%d\n", i, info.wr_ptr_line_count); - SDE_EVT32(pp->idx - PINGPONG_0, info.wr_ptr_line_count, + _sde_rm_autorefresh_get_vsync_info(pp, intf, &info, hw_intf_te); + + SDE_DEBUG("i=%d, line count=%d\n", i, info.wr_ptr_line_count); + SDE_EVT32(dbg_idx, info.wr_ptr_line_count, info.rd_ptr_init_val, SDE_EVTLOG_FUNC_CASE2); /* log line count and return */ @@ -1295,7 +1381,7 @@ static int _sde_rm_autorefresh_disable(struct sde_hw_pingpong *pp, usleep_range(3000, 4000); } - pp->ops.connect_external_te(pp, true); + _sde_rm_autorefresh_connect_external_te(pp, intf, hw_intf_te, true); return rc; } @@ -1315,29 +1401,33 @@ static int _sde_rm_get_pp_dsc_for_cont_splash(struct sde_rm *rm, { int index = 0; int value, dsc_cnt = 0; - struct sde_rm_hw_iter iter_pp; + struct sde_rm_hw_iter iter_pp, intf_iter; + bool hw_intf_te_supported; + struct sde_hw_intr *hw_intr = NULL; if (!rm || !sde_kms || !dsc_ids) { SDE_ERROR("invalid input parameters\n"); return 0; } + hw_intf_te_supported = sde_hw_intf_te_supported(sde_kms->catalog); + hw_intr = sde_kms->hw_intr; + if (!hw_intr) { + SDE_ERROR("hw_intr handler not initialized\n"); + return 0; + } + SDE_DEBUG("max_dsc_cnt = %d\n", max_dsc_cnt); sde_rm_init_hw_iter(&iter_pp, 0, SDE_HW_BLK_PINGPONG); while (_sde_rm_get_hw_locked(rm, &iter_pp)) { struct sde_hw_pingpong *pp = to_sde_hw_pingpong(iter_pp.blk->hw); - struct sde_hw_intr *hw_intr = NULL; if (!pp->ops.get_dsc_status) { SDE_ERROR("get_dsc_status ops not initialized\n"); return 0; } - hw_intr = sde_kms->hw_intr; - if (!hw_intr) { - SDE_ERROR("hw_intr handler not initialized\n"); - return 0; - } + value = pp->ops.get_dsc_status(pp); SDE_DEBUG("DSC[%d]=0x%x, dsc_cnt = %d\n", index, value, dsc_cnt); @@ -1347,7 +1437,19 @@ static int _sde_rm_get_pp_dsc_for_cont_splash(struct sde_rm *rm, } index++; - _sde_rm_autorefresh_disable(pp, hw_intr); + if (!hw_intf_te_supported) + _sde_rm_autorefresh_disable(pp, NULL, hw_intr, + hw_intf_te_supported); + } + + sde_rm_init_hw_iter(&intf_iter, 0, SDE_HW_BLK_INTF); + while (_sde_rm_get_hw_locked(rm, &intf_iter)) { + struct sde_hw_intf *intf = + to_sde_hw_intf(intf_iter.blk->hw); + + if (hw_intf_te_supported) + _sde_rm_autorefresh_disable(NULL, intf, hw_intr, + hw_intf_te_supported); } return dsc_cnt; -- GitLab From 1e9871d06e9587d914510865c49bd49d1d73947c Mon Sep 17 00:00:00 2001 From: Sami Tolvanen Date: Mon, 13 Nov 2017 08:19:17 -0800 Subject: [PATCH 0586/1635] FROMLIST: arm64: kvm: use -fno-jump-tables with clang Starting with LLVM r308050, clang generates a jump table with EL1 virtual addresses in __init_stage2_translation, which results in a kernel panic when booting at EL2: Kernel panic - not syncing: HYP panic: PS:800003c9 PC:ffff0000089e6fd8 ESR:86000004 FAR:ffff0000089e6fd8 HPFAR:0000000009825000 PAR:0000000000000000 VCPU:000804fc20001221 CPU: 0 PID: 0 Comm: swapper/0 Not tainted 4.14.0-rc7-dirty #3 Hardware name: ARM Juno development board (r1) (DT) Call trace: [] dump_backtrace+0x0/0x34c [] show_stack+0x18/0x20 [] dump_stack+0xc4/0xfc [] panic+0x138/0x2b4 [] panic+0x0/0x2b4 SMP: stopping secondary CPUs SMP: failed to stop secondary CPUs 0-3,5 Kernel Offset: disabled CPU features: 0x002086 Memory Limit: none ---[ end Kernel panic - not syncing: HYP panic: PS:800003c9 PC:ffff0000089e6fd8 ESR:86000004 FAR:ffff0000089e6fd8 HPFAR:0000000009825000 PAR:0000000000000000 VCPU:000804fc20001221 This change adds -fno-jump-tables to arm64/hyp to work around the bug. Bug: 62093296 Bug: 67506682 Change-Id: I1257be1febdcbfcc886fe6183c698b7a98d2a153 (am from https://patchwork.kernel.org/patch/10060301/) Suggested-by: AKASHI Takahiro Signed-off-by: Sami Tolvanen --- arch/arm64/kvm/hyp/Makefile | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/arm64/kvm/hyp/Makefile b/arch/arm64/kvm/hyp/Makefile index f04400d494b7..19fa1c6b6b69 100644 --- a/arch/arm64/kvm/hyp/Makefile +++ b/arch/arm64/kvm/hyp/Makefile @@ -5,6 +5,10 @@ ccflags-y += -fno-stack-protector -DDISABLE_BRANCH_PROFILING +ifeq ($(cc-name),clang) +ccflags-y += -fno-jump-tables +endif + KVM=../../../../virt/kvm obj-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/hyp/vgic-v2-sr.o -- GitLab From edfbe043a13c3b7b1ef90b99d5dba41489be7728 Mon Sep 17 00:00:00 2001 From: Jeevan Shriram Date: Thu, 19 Apr 2018 14:18:03 -0700 Subject: [PATCH 0587/1635] ARM: dts: msm: Add support for cdsp PIL for sdmshrike Add PIL node for cdsp for bringing firmware out of reset on sdmshrike target. Change-Id: Iea66e2c453e9d7e04c28a5a4eadc4e4b79b4b09d Signed-off-by: Jeevan Shriram --- arch/arm64/boot/dts/qcom/sdmshrike.dtsi | 44 +++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sdmshrike.dtsi b/arch/arm64/boot/dts/qcom/sdmshrike.dtsi index 68ce712bec88..131b18132741 100644 --- a/arch/arm64/boot/dts/qcom/sdmshrike.dtsi +++ b/arch/arm64/boot/dts/qcom/sdmshrike.dtsi @@ -1160,6 +1160,50 @@ qcom,smem-state-names = "qcom,force-stop"; }; + qcom,turing@8300000 { + compatible = "qcom,pil-tz-generic"; + reg = <0x8300000 0x100000>; + + vdd_cx-supply = <&VDD_CX_LEVEL>; + qcom,proxy-reg-names = "vdd_cx"; + + clocks = <&clock_rpmh RPMH_CXO_CLK>; + clock-names = "xo"; + qcom,proxy-clock-names = "xo"; + + qcom,pas-id = <18>; + qcom,proxy-timeout-ms = <10000>; + qcom,smem-id = <601>; + qcom,sysmon-id = <7>; + qcom,ssctl-instance-id = <0x17>; + qcom,firmware-name = "cdsp"; + memory-region = <&pil_cdsp_mem>; + + qcom,msm-bus,name = "pil-cdsp"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <154 10070 0 0>, + <154 10070 0 1>; + + /* Inputs from turing */ + interrupts-extended = <&pdc 0 578 1>, + <&cdsp_smp2p_in 0 0>, + <&cdsp_smp2p_in 2 0>, + <&cdsp_smp2p_in 1 0>, + <&cdsp_smp2p_in 3 0>; + + interrupt-names = "qcom,wdog", + "qcom,err-fatal", + "qcom,proxy-unvote", + "qcom,err-ready", + "qcom,stop-ack"; + + /* Outputs to turing */ + qcom,smem-states = <&cdsp_smp2p_out 0>; + qcom,smem-state-names = "qcom,force-stop"; + }; + wdog: qcom,wdt@17c10000 { compatible = "qcom,msm-watchdog"; reg = <0x17c10000 0x1000>; -- GitLab From 81cc4011b93b94b834ac68b70972fc886539ff13 Mon Sep 17 00:00:00 2001 From: Chris Lew Date: Wed, 11 Apr 2018 19:12:50 -0700 Subject: [PATCH 0588/1635] diag: diagfwd_socket: Fix DEL_CLIENT notification The QMI handle used to register server lookups will never receive DEL_CLIENT notifications because itself is a client. Only servers will receive the DEL_CLIENT notification. Remove the DEL_CLIENT handler from the QMI handle. The sockets that act as servers should parse control packets to see if the client they are connected to ever disconnects. Add handling for the bye and del_client control packets. Since the SSR Framework is no longer used to receive side channel state notifications, the socket that acts as the server should always remain open. During client disconnect cleanup, close the channel in the diag layers but keep the socket open so new data packets can reopen the diag channel. Change-Id: I64d1793a1335ee4b50ad264f78d91a43ccd5279a Signed-off-by: Chris Lew --- drivers/char/diag/diagfwd_socket.c | 92 +++++++++++++++++------------- 1 file changed, 52 insertions(+), 40 deletions(-) diff --git a/drivers/char/diag/diagfwd_socket.c b/drivers/char/diag/diagfwd_socket.c index 7c5f207a02a5..13be6d6cdf69 100644 --- a/drivers/char/diag/diagfwd_socket.c +++ b/drivers/char/diag/diagfwd_socket.c @@ -500,6 +500,9 @@ static void __socket_close_channel(struct diag_socket_info *info) diagfwd_channel_close(info->fwd_ctxt); atomic_set(&info->opened, 0); + /* Don't close the server. Server should always remain open */ + if (info->port_type == PORT_TYPE_SERVER) + return; write_lock_bh(&info->hdl->sk->sk_callback_lock); info->hdl->sk->sk_user_data = NULL; @@ -509,13 +512,13 @@ static void __socket_close_channel(struct diag_socket_info *info) sock_release(info->hdl); info->hdl = NULL; + cancel_work(&info->read_work); + wake_up_interruptible(&info->read_wait_q); + spin_lock_irqsave(&info->lock, flags); info->data_ready = 0; spin_unlock_irqrestore(&info->lock, flags); - cancel_work(&info->read_work); - wake_up_interruptible(&info->read_wait_q); - DIAG_LOG(DIAG_DEBUG_PERIPHERALS, "%s exiting\n", info->name); } @@ -593,6 +596,44 @@ static void diag_socket_queue_read(void *ctxt) queue_work(info->wq, &(info->read_work)); } +static void handle_ctrl_pkt(struct diag_socket_info *info, void *buf, int len) +{ + const struct qrtr_ctrl_pkt *pkt = buf; + u32 node; + u32 port; + + if (len < sizeof(struct qrtr_ctrl_pkt)) + return; + + switch (le32_to_cpu(pkt->cmd)) { + case QRTR_TYPE_BYE: + node = le32_to_cpu(pkt->client.node); + if (info->remote_addr.sq_node == node) { + DIAG_LOG(DIAG_DEBUG_PERIPHERALS, "%s rcvd bye\n", + info->name); + + mutex_lock(&driver->diag_notifier_mutex); + socket_close_channel(info); + mutex_unlock(&driver->diag_notifier_mutex); + } + break; + case QRTR_TYPE_DEL_CLIENT: + node = le32_to_cpu(pkt->client.node); + port = le32_to_cpu(pkt->client.port); + + if (info->remote_addr.sq_node == node && + info->remote_addr.sq_port == port) { + DIAG_LOG(DIAG_DEBUG_PERIPHERALS, "%s rcvd del client\n", + info->name); + + mutex_lock(&driver->diag_notifier_mutex); + socket_close_channel(info); + mutex_unlock(&driver->diag_notifier_mutex); + } + break; + } +} + static int diag_socket_read(void *ctxt, unsigned char *buf, int buf_len) { int err = 0; @@ -683,8 +724,10 @@ static int diag_socket_read(void *ctxt, unsigned char *buf, int buf_len) } else if (read_len <= 0) goto fail; - if (src_addr.sq_port == QRTR_PORT_CTRL) + if (src_addr.sq_port == QRTR_PORT_CTRL) { + handle_ctrl_pkt(info, temp, read_len); continue; + } if (!atomic_read(&info->opened) && info->port_type == PORT_TYPE_SERVER) { @@ -694,6 +737,11 @@ static int diag_socket_read(void *ctxt, unsigned char *buf, int buf_len) * channel open for communication. */ memcpy(&info->remote_addr, &src_addr, sizeof(src_addr)); + DIAG_LOG(DIAG_DEBUG_PERIPHERALS, + "%s first client [0x%x:0x%x]\n", + info->name, src_addr.sq_node, + src_addr.sq_port); + if (info->ins_id == INST_ID_DCI) atomic_set(&info->opened, 1); else @@ -917,45 +965,9 @@ static void diag_del_server(struct qmi_handle *qmi, struct qmi_service *svc) socket_close_channel(info); } -static void diag_del_client(struct qmi_handle *qmi, unsigned int node_id, - unsigned int port_id) -{ - - struct diag_socket_info *info = NULL; - int i; - - for (i = 0; i < NUM_PERIPHERALS; i++) { - if ((socket_data[i].remote_addr.sq_node == node_id) && - (socket_data[i].remote_addr.sq_port == port_id)) { - info = &socket_data[i]; - break; - } - - if ((socket_cntl[i].remote_addr.sq_node == node_id) && - (socket_cntl[i].remote_addr.sq_port == port_id)) { - info = &socket_cntl[i]; - break; - } - - if ((socket_dci[i].remote_addr.sq_node == node_id) && - (socket_dci[i].remote_addr.sq_port == port_id)) { - info = &socket_dci[i]; - break; - } - } - if (!info) - return; - - DIAG_LOG(DIAG_DEBUG_PERIPHERALS, "%s rcvd del client\n", info->name); - mutex_lock(&driver->diag_notifier_mutex); - socket_close_channel(info); - mutex_unlock(&driver->diag_notifier_mutex); -} - static struct qmi_ops diag_qmi_cntl_ops = { .new_server = diag_new_server, .del_server = diag_del_server, - .del_client = diag_del_client, }; int diag_socket_init(void) -- GitLab From e70c3b46abe1a440f1bf4c452efa1c0f3adab6f9 Mon Sep 17 00:00:00 2001 From: Shivendra Kakrania Date: Tue, 10 Apr 2018 12:47:26 -0700 Subject: [PATCH 0589/1635] msm: vidc: Adding debugfs support to vote video core clocks Voting video core clocks to a specific value for debugging purpose. CRs-Fixed: 2223586 Change-Id: If80ab0d20ce161e1998f114fb82d43f467d0cfb0 Signed-off-by: Shivendra Kakrania --- .../media/platform/msm/vidc/msm_vidc_clocks.c | 16 ++++++++++++---- drivers/media/platform/msm/vidc/msm_vidc_debug.c | 6 +++--- drivers/media/platform/msm/vidc/msm_vidc_debug.h | 2 +- 3 files changed, 16 insertions(+), 8 deletions(-) diff --git a/drivers/media/platform/msm/vidc/msm_vidc_clocks.c b/drivers/media/platform/msm/vidc/msm_vidc_clocks.c index 3576437f2e1a..728932c6a939 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc_clocks.c +++ b/drivers/media/platform/msm/vidc/msm_vidc_clocks.c @@ -270,7 +270,7 @@ int msm_comm_vote_bus(struct msm_vidc_core *core) vote_data[i].fps = inst->prop.fps; vote_data[i].power_mode = 0; - if (!msm_vidc_clock_scaling || is_turbo || + if (msm_vidc_clock_voting || is_turbo || inst->clk_data.buffer_counter < DCVS_FTB_WINDOW) vote_data[i].power_mode = VIDC_POWER_TURBO; @@ -686,6 +686,14 @@ int msm_vidc_set_clocks(struct msm_vidc_core *core) freq_core_max = max_t(unsigned long, freq_core_1, freq_core_2); + if (msm_vidc_clock_voting) { + dprintk(VIDC_PROF, + "msm_vidc_clock_voting %d\n", + msm_vidc_clock_voting); + freq_core_max = msm_vidc_clock_voting; + break; + } + if (temp->clk_data.turbo_mode) { dprintk(VIDC_PROF, "Found an instance with Turbo request\n"); @@ -758,7 +766,7 @@ int msm_vidc_validate_operating_rate(struct msm_vidc_inst *inst, operating_rate = operating_rate >> 16; if ((curr_operating_rate * (1 + ops_left)) >= operating_rate || - !msm_vidc_clock_scaling || + msm_vidc_clock_voting || inst->clk_data.buffer_counter < DCVS_FTB_WINDOW) { dprintk(VIDC_DBG, "Requestd operating rate is valid %u\n", @@ -820,7 +828,7 @@ int msm_comm_scale_clocks(struct msm_vidc_inst *inst) inst->clk_data.min_freq = freq; if (inst->clk_data.buffer_counter < DCVS_FTB_WINDOW || - !msm_vidc_clock_scaling) + msm_vidc_clock_voting) inst->clk_data.min_freq = msm_vidc_max_freq(inst->core); else inst->clk_data.min_freq = freq; @@ -861,7 +869,7 @@ int msm_dcvs_try_enable(struct msm_vidc_inst *inst) return -EINVAL; } - if (!msm_vidc_clock_scaling || + if (msm_vidc_clock_voting || inst->flags & VIDC_THUMBNAIL || inst->clk_data.low_latency_mode) { dprintk(VIDC_PROF, diff --git a/drivers/media/platform/msm/vidc/msm_vidc_debug.c b/drivers/media/platform/msm/vidc/msm_vidc_debug.c index 2b4930f95367..03af199ebb7c 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc_debug.c +++ b/drivers/media/platform/msm/vidc/msm_vidc_debug.c @@ -27,7 +27,7 @@ int msm_vidc_fw_debug_mode = 1; int msm_vidc_fw_low_power_mode = 1; bool msm_vidc_fw_coverage = !true; bool msm_vidc_thermal_mitigation_disabled = !true; -bool msm_vidc_clock_scaling = true; +int msm_vidc_clock_voting = !1; bool msm_vidc_syscache_disable = !true; #define MAX_DBG_BUF_SIZE 4096 @@ -200,8 +200,8 @@ struct dentry *msm_vidc_debugfs_init_drv(void) __debugfs_create(u32, "debug_output", &msm_vidc_debug_out) && __debugfs_create(bool, "disable_thermal_mitigation", &msm_vidc_thermal_mitigation_disabled) && - __debugfs_create(bool, "clock_scaling", - &msm_vidc_clock_scaling) && + __debugfs_create(u32, "core_clock_voting", + &msm_vidc_clock_voting) && __debugfs_create(bool, "disable_video_syscache", &msm_vidc_syscache_disable); diff --git a/drivers/media/platform/msm/vidc/msm_vidc_debug.h b/drivers/media/platform/msm/vidc/msm_vidc_debug.h index d6cfda575b3c..0b2b8bfcf86d 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc_debug.h +++ b/drivers/media/platform/msm/vidc/msm_vidc_debug.h @@ -58,7 +58,7 @@ extern int msm_vidc_fw_debug_mode; extern int msm_vidc_fw_low_power_mode; extern bool msm_vidc_fw_coverage; extern bool msm_vidc_thermal_mitigation_disabled; -extern bool msm_vidc_clock_scaling; +extern int msm_vidc_clock_voting; extern bool msm_vidc_syscache_disable; #define dprintk(__level, __fmt, arg...) \ -- GitLab From d037a293efec2a2cbe188a441acb2231bdc21398 Mon Sep 17 00:00:00 2001 From: Shivendra Kakrania Date: Thu, 12 Apr 2018 13:50:46 -0700 Subject: [PATCH 0590/1635] msm: vidc: Enable 4K@120fps Video Playback Fixed load calculation to enable 4K@120fps video playback. CRs-Fixed: 2223586 Change-Id: I3bc06e0b60409b659224d7933510f4500a41eec4 Signed-off-by: Shivendra Kakrania --- drivers/media/platform/msm/vidc/msm_vidc_clocks.c | 8 ++++---- drivers/media/platform/msm/vidc/msm_vidc_platform.c | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/media/platform/msm/vidc/msm_vidc_clocks.c b/drivers/media/platform/msm/vidc/msm_vidc_clocks.c index 3576437f2e1a..5b2ec9403307 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc_clocks.c +++ b/drivers/media/platform/msm/vidc/msm_vidc_clocks.c @@ -1308,11 +1308,11 @@ int msm_vidc_decide_core_and_power_mode(struct msm_vidc_inst *inst) min_lp_load = core0_lp_load; } - current_inst_load = msm_comm_get_inst_load(inst, LOAD_CALC_NO_QUIRKS) * - inst->clk_data.entry->vpp_cycles; + current_inst_load = (msm_comm_get_inst_load(inst, LOAD_CALC_NO_QUIRKS) * + inst->clk_data.entry->vpp_cycles)/inst->clk_data.work_route; - current_inst_lp_load = msm_comm_get_inst_load(inst, - LOAD_CALC_NO_QUIRKS) * lp_cycles; + current_inst_lp_load = (msm_comm_get_inst_load(inst, + LOAD_CALC_NO_QUIRKS) * lp_cycles)/inst->clk_data.work_route; dprintk(VIDC_DBG, "Core 0 RT Load = %d Core 1 RT Load = %d\n", core0_load, core1_load); diff --git a/drivers/media/platform/msm/vidc/msm_vidc_platform.c b/drivers/media/platform/msm/vidc/msm_vidc_platform.c index a801da7de80a..3a0ff07d32b7 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc_platform.c +++ b/drivers/media/platform/msm/vidc/msm_vidc_platform.c @@ -133,7 +133,7 @@ static struct msm_vidc_common_data sm8150_common_data[] = { }, { .key = "qcom,max-hw-load", - .value = 3110400, /* 4096x2160@90 */ + .value = 4147200, /* 4096x2160/256 MBs@120fps */ }, { .key = "qcom,max-hq-mbs-per-frame", -- GitLab From be47bf1c90d7528ab18211a8a6a488ed82dbd3ff Mon Sep 17 00:00:00 2001 From: Maheshwar Ajja Date: Fri, 13 Apr 2018 18:07:51 -0700 Subject: [PATCH 0591/1635] [media] v4l: Add TME color format Update v4l_fill_fmtdesc() with TME color format. Change-Id: Icf753f1be19f61b914461930036f7c7f12a1c4f3 Signed-off-by: Maheshwar Ajja --- drivers/media/v4l2-core/v4l2-ioctl.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c index c286fba04d38..a27dde03e59f 100644 --- a/drivers/media/v4l2-core/v4l2-ioctl.c +++ b/drivers/media/v4l2-core/v4l2-ioctl.c @@ -1367,6 +1367,8 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt) case V4L2_PIX_FMT_SE401: descr = "GSPCA SE401"; break; case V4L2_PIX_FMT_S5C_UYVY_JPG: descr = "S5C73MX interleaved UYVY/JPEG"; break; case V4L2_PIX_FMT_MT21C: descr = "Mediatek Compressed Format"; break; + case V4L2_PIX_FMT_TME: + descr = "TME"; break; default: WARN(1, "Unknown pixelformat 0x%08x\n", fmt->pixelformat); if (fmt->description[0]) -- GitLab From 6117d079ad3241525042842bc5c3e419fdd6e5d7 Mon Sep 17 00:00:00 2001 From: Ajay Singh Parmar Date: Thu, 19 Apr 2018 23:55:05 -0700 Subject: [PATCH 0592/1635] drm/dsi-staging: do not update the stored values in parser While retrieving the data from the DSI parser, do not update the stored values. APIs to retrieve the stored data can be called multiple times. Updating the stored values may result in wrong data to be returned in subsequent calls. CRs-Fixed: 2223812 Change-Id: I189639a1451a067e70452e3f06a85f488a40e7e0 Signed-off-by: Ajay Singh Parmar --- drivers/gpu/drm/msm/dsi-staging/dsi_parser.c | 73 +++++++++++++------- 1 file changed, 47 insertions(+), 26 deletions(-) diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_parser.c b/drivers/gpu/drm/msm/dsi-staging/dsi_parser.c index 1463bd491076..e5ca15156bbc 100644 --- a/drivers/gpu/drm/msm/dsi-staging/dsi_parser.c +++ b/drivers/gpu/drm/msm/dsi-staging/dsi_parser.c @@ -198,23 +198,29 @@ static void dsi_parser_get_int_value(struct dsi_parser_prop *prop, for (i = 0; i < prop->len; i++) { int base, val; + char *to_int, *tmp; + char item[SZ_128]; + + strlcpy(item, prop->items[i], SZ_128); + + tmp = item; if (forced_base) { base = forced_base; } else { - char *to_int = strsep(&prop->items[i], "x"); + to_int = strsep(&tmp, "x"); - if (!prop->items[i]) { - prop->items[i] = to_int; + if (!tmp) { + tmp = to_int; base = 10; } else { base = 16; } } - if (kstrtoint(prop->items[i], base, &val)) { + if (kstrtoint(tmp, base, &val)) { pr_err("error converting %s at %d\n", - prop->items[i], i); + tmp, i); continue; } @@ -478,11 +484,19 @@ struct property *dsi_parser_find_property(const struct device_node *np, if (!prop) { pr_debug("%s not found\n", name); goto end; - } else { - *lenp = strlen(prop->raw); } - pr_debug("%s: len=%d\n", name, *lenp); + if (lenp) { + if (prop->type == DSI_PROP_TYPE_INT_ARRAY) + *lenp = prop->len; + else if (prop->type == DSI_PROP_TYPE_INT_SET_ARRAY || + prop->type == DSI_PROP_TYPE_INT_SET) + *lenp = prop->len * sizeof(u32); + else + *lenp = strlen(prop->raw) + 1; + + pr_debug("%s len=%d\n", name, *lenp); + } end: return (struct property *)prop; } @@ -533,8 +547,7 @@ int dsi_parser_read_u32(const struct device_node *np, { struct dsi_parser_node *node = (struct dsi_parser_node *)np; struct dsi_parser_prop *prop; - char *property = NULL; - char *to_int; + char *property, *to_int, item[SZ_128]; int rc = 0, base; prop = dsi_parser_search_property(node, propname); @@ -542,10 +555,13 @@ int dsi_parser_read_u32(const struct device_node *np, pr_debug("%s not found\n", propname); rc = -EINVAL; goto end; - } else { - property = prop->value; } + if (!prop->value) + goto end; + + strlcpy(item, prop->value, SZ_128); + property = item; to_int = strsep(&property, "x"); if (!property) { @@ -555,12 +571,10 @@ int dsi_parser_read_u32(const struct device_node *np, base = 16; } - if (!property) - goto end; - rc = kstrtoint(property, base, out_value); if (rc) { - pr_err("error(%d) converting %s\n", rc, property); + pr_err("prop=%s error(%d) converting %s, base=%d\n", + propname, rc, property, base); goto end; } @@ -586,22 +600,26 @@ int dsi_parser_read_u32_array(const struct device_node *np, for (i = 0; i < prop->len; i++) { int base, val; - char *to_int = strsep(&prop->items[i], "x"); + char item[SZ_128]; + char *to_int, *tmp; + + strlcpy(item, prop->items[i], SZ_128); - if (!prop->items[i]) { - prop->items[i] = to_int; + tmp = item; + + to_int = strsep(&tmp, "x"); + + if (!tmp) { + tmp = to_int; base = 10; } else { base = 16; } - if (!prop->items[i]) - continue; - - if (kstrtoint(prop->items[i], base, &val)) { - pr_err("error converting %s at %d\n", - prop->items[i], i); - + rc = kstrtoint(tmp, base, &val); + if (rc) { + pr_err("prop=%s error(%d) converting %s(%d), base=%d\n", + propname, rc, tmp, i, base); continue; } @@ -634,6 +652,9 @@ const void *dsi_parser_get_property(const struct device_node *np, if (lenp) { if (prop->type == DSI_PROP_TYPE_INT_ARRAY) *lenp = prop->len; + else if (prop->type == DSI_PROP_TYPE_INT_SET_ARRAY || + prop->type == DSI_PROP_TYPE_INT_SET) + *lenp = prop->len * sizeof(u32); else *lenp = strlen(prop->raw) + 1; -- GitLab From bab04e16d780476b25cbcca7247d30d8293b3318 Mon Sep 17 00:00:00 2001 From: Liam Mark Date: Fri, 20 Apr 2018 16:13:56 -0700 Subject: [PATCH 0593/1635] iommu: arm-smmu: Initialize value of phys Ensure that phys is initialized so that on error cases a consistent value is returned. Change-Id: I758acb659435a777e5abae4ef766d249736277d4 Signed-off-by: Liam Mark --- drivers/iommu/arm-smmu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c index d484b00e46f8..6fb07c709f26 100644 --- a/drivers/iommu/arm-smmu.c +++ b/drivers/iommu/arm-smmu.c @@ -4659,7 +4659,7 @@ static phys_addr_t qsmmuv500_iova_to_phys( struct arm_smmu_cfg *cfg = &smmu_domain->cfg; struct qsmmuv500_tbu_device *tbu; int ret; - phys_addr_t phys; + phys_addr_t phys = 0; u64 val, fsr; unsigned long flags; void __iomem *cb_base; -- GitLab From 79a70847ca6c436a8c9770c9eb6378cea72c25cb Mon Sep 17 00:00:00 2001 From: Liam Mark Date: Fri, 20 Apr 2018 16:08:01 -0700 Subject: [PATCH 0594/1635] iommu: msm: Fix __msm_dma_map_sg sg_tmp sanity check Fix the sanity check in __msm_dma_map_sg to ensure that sg_tmp is always valid. Change-Id: Idfb242afa42ce07727458d9319aaa374ab3cb3ec Signed-off-by: Liam Mark --- drivers/iommu/msm_dma_iommu_mapping.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/iommu/msm_dma_iommu_mapping.c b/drivers/iommu/msm_dma_iommu_mapping.c index 84e0330dbbdb..bd31fedb26d6 100644 --- a/drivers/iommu/msm_dma_iommu_mapping.c +++ b/drivers/iommu/msm_dma_iommu_mapping.c @@ -247,7 +247,7 @@ static inline int __msm_dma_map_sg(struct device *dev, struct scatterlist *sg, break; sg_tmp = sg_next(sg_tmp); - if (sg == NULL) + if (sg_tmp == NULL) break; } -- GitLab From 5b27f0762c87c8c18bdd0fb51b3efd409ee6c131 Mon Sep 17 00:00:00 2001 From: Siddartha Mohanadoss Date: Wed, 11 Apr 2018 11:27:06 -0700 Subject: [PATCH 0595/1635] thermal: adc-tm: Add ADC_TM driver ADC_TM driver is used by clients to set temperature thresholds on channels supported by VADC peripheral. Clients can receive notification once set thresholds are crossed. ADC_TM driver is used by thermal driver and registers with of_thermal to let thermal core set trip thresholds and read temperature for thermistors. Change-Id: I49f57e3c6108b7976ad36a51f2c2f7a8e9eb5f2e Signed-off-by: Siddartha Mohanadoss --- .../bindings/thermal/qcom-adc-tm.txt | 145 +++++ drivers/thermal/qcom/Kconfig | 10 + drivers/thermal/qcom/Makefile | 1 + drivers/thermal/qcom/adc-tm-common.c | 133 ++++ drivers/thermal/qcom/adc-tm.c | 334 ++++++++++ drivers/thermal/qcom/adc-tm.h | 218 +++++++ drivers/thermal/qcom/adc-tm5.c | 573 ++++++++++++++++++ 7 files changed, 1414 insertions(+) create mode 100644 Documentation/devicetree/bindings/thermal/qcom-adc-tm.txt create mode 100644 drivers/thermal/qcom/adc-tm-common.c create mode 100644 drivers/thermal/qcom/adc-tm.c create mode 100644 drivers/thermal/qcom/adc-tm.h create mode 100644 drivers/thermal/qcom/adc-tm5.c diff --git a/Documentation/devicetree/bindings/thermal/qcom-adc-tm.txt b/Documentation/devicetree/bindings/thermal/qcom-adc-tm.txt new file mode 100644 index 000000000000..05cdd98d9e39 --- /dev/null +++ b/Documentation/devicetree/bindings/thermal/qcom-adc-tm.txt @@ -0,0 +1,145 @@ +Qualcomm Technologies, Inc. PMIC thermal monitor ADC driver (ADC_TM) + +PMIC thermal monitoring (TM) provides interface to thermal clients +to set temperature thresholds and receive notification when the thresholds +are crossed. A 15 bit ADC is used for measurements. The driver is part +of the sysfs thermal framework that provides support to read the trip +points, set threshold for the trip points and enable the trip points. + +ADC_TM node + +- compatible: + Usage: required + Value type: + Definition: Should contain "qcom,adc-tm5" for PMIC5 ADC TM driver. + +- reg: + Usage: required + Value type: + Definition: ADC_TM base address and length in the SPMI PMIC register map. + +- #address-cells: + Usage: required + Value type: + Definition: Must be one. Child node 'reg' property should define ADC + channel number. + +- #size-cells: + Usage: required + Value type: + Definition: Must be zero. + +- interrupts: + Usage: required + Value type: + Definition: End of conversion interrupt. + +- interrupt-names: + Usage: required + Value type: + Definition: Should contain "thr-int-en" for PMIC5 ADC TM driver. + +- qcom,decimation: + Usage: optional + Value type: + Definition: This parameter is used to decrease ADC sampling rate. + Quicker measurements can be made by reducing decimation ratio. + For PMIC5 ADC, combined two step decimation values are 250, 420 and 840. + If property is not found, default value of 840 will be used. + +- qcom,avg-samples: + Usage: optional + Value type: + Definition: Number of samples to be used for measurement. + Averaging provides the option to obtain a single measurement + from the ADC that is an average of multiple samples. The value + selected is 2^(value). + Valid values are: 1, 2, 4, 8, 16 + If property is not found, 1 sample will be used. + +- #thermal-sensor-cells: + Usage: optional + Value type: + Definition: Should be 1. See thermal.txt for a description. + +- io-channels: + Usage: Required + Value type: + Definition: The phandle of the iio provider. + +Channel node properties: + +- reg: + Usage: required + Value type: + Definition: ADC channel number. + See include/dt-bindings/iio/qcom,spmi-vadc.h + +- qcom,pre-scaling: + Usage: optional + Value type: + Definition: Used for scaling the channel input signal before the signal is + fed to VADC. The configuration for this node is to know the + pre-determined ratio and use it for post scaling. Select one from + the following options. + <1 1>, <1 3>, <1 4>, <1 6>, <1 20>, <1 8>, <10 81>, <1 10> + If property is not found default value depending on chip will be used. + +- qcom,ratiometric: + Usage: optional + Value type: + Definition: Channel calibration type. If this property is specified + VADC will use the VDD reference (1.875V) and GND for channel + calibration. If property is not found, channel will be + calibrated with 0V and 1.25V reference channels, also + known as absolute calibration. + +- qcom,hw-settle-time: + Usage: optional + Value type: + Definition: Time between AMUX getting configured and the ADC starting + conversion. + For PMIC5, delay = 15us for value 0, + 100us * (value) for values 0 < value < 11, and + 2ms * (value - 10) otherwise. + Valid values are: 15, 100, 200, 300, 400, 500, 600, 700, 1, + 2, 4, 8, 16, 32, 64, 128 ms + If property is not found, channel will use 15us. + +Example: + + /* ADC_TM node */ + pmic_adc_tm: adc_tm@3500 { + compatible = "qcom,adc-tm5"; + reg = <0x3500 0x100>; + interrupts = <0x0 0x35 0x0 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "thr-int-en"; + #address-cells = <1>; + #size-cells = <0>; + #thermal-sensor-cells = <1>; + io-channels = <&pmic_vadc ADC_AMUX_THM2_PU2>; + + /* Channel node */ + skin_msm_therm { + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + }; + }; + + /* Adding thermal zone to register with of_thermal */ + &thermal_zones { + wp-therm { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&pmic_adc_tm ADC_AMUX_THM2_PU2>; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + }; diff --git a/drivers/thermal/qcom/Kconfig b/drivers/thermal/qcom/Kconfig index 5dd8869180ba..f0385436f105 100644 --- a/drivers/thermal/qcom/Kconfig +++ b/drivers/thermal/qcom/Kconfig @@ -93,3 +93,13 @@ config QTI_BCL_SOC_DRIVER threshold and notify the thermal framework. If you want this support, you should say Y here. + +config QTI_ADC_TM + tristate "Qualcomm Technologies Inc. Thermal Monitor ADC Driver" + depends on SPMI && THERMAL + depends on QCOM_SPMI_ADC5 + help + This enables the thermal Sysfs driver for the ADC thermal monitoring + device. It shows up in Sysfs as a thermal zone with multiple trip points. + Thermal client sets threshold temperature for both warm and cool + and gets updated when a threshold is reached. diff --git a/drivers/thermal/qcom/Makefile b/drivers/thermal/qcom/Makefile index aa6535bb0cda..e7e88d95d2b2 100644 --- a/drivers/thermal/qcom/Makefile +++ b/drivers/thermal/qcom/Makefile @@ -8,3 +8,4 @@ obj-$(CONFIG_QTI_QMI_COOLING_DEVICE) += thermal_mitigation_device_service_v01.o obj-$(CONFIG_MSM_BCL_PERIPHERAL_CTL) += bcl_peripheral.o obj-$(CONFIG_QTI_BCL_PMIC5) += bcl_pmic5.o obj-$(CONFIG_QTI_BCL_SOC_DRIVER) += bcl_soc.o +obj-$(CONFIG_QTI_ADC_TM) += adc-tm.o adc-tm-common.o adc-tm5.o diff --git a/drivers/thermal/qcom/adc-tm-common.c b/drivers/thermal/qcom/adc-tm-common.c new file mode 100644 index 000000000000..583bd4ec0e0e --- /dev/null +++ b/drivers/thermal/qcom/adc-tm-common.c @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include "adc-tm.h" + +/* + * Voltage to temperature table for NTCG104EF104 thermistor with + * 1.875V reference and 100k pull-up. + */ +static const struct adc_tm_map_pt adcmap_100k_104ef_104fb_1875_vref[] = { + { 1831, -40000 }, + { 1814, -35000 }, + { 1791, -30000 }, + { 1761, -25000 }, + { 1723, -20000 }, + { 1675, -15000 }, + { 1616, -10000 }, + { 1545, -5000 }, + { 1463, 0 }, + { 1370, 5000 }, + { 1268, 10000 }, + { 1160, 15000 }, + { 1049, 20000 }, + { 937, 25000 }, + { 828, 30000 }, + { 726, 35000 }, + { 630, 40000 }, + { 544, 45000 }, + { 467, 50000 }, + { 399, 55000 }, + { 340, 60000 }, + { 290, 65000 }, + { 247, 70000 }, + { 209, 75000 }, + { 179, 80000 }, + { 153, 85000 }, + { 130, 90000 }, + { 112, 95000 }, + { 96, 100000 }, + { 82, 105000 }, + { 71, 110000 }, + { 62, 115000 }, + { 53, 120000 }, + { 46, 125000 }, +}; + +static void adc_tm_map_temp_voltage(const struct adc_tm_map_pt *pts, + size_t tablesize, int input, int64_t *output) +{ + bool descending = true; + unsigned int i = 0; + + /* Check if table is descending or ascending */ + if (tablesize > 1) { + if (pts[0].y < pts[1].y) + descending = 0; + } + + while (i < tablesize) { + if (descending && (pts[i].y < input)) { + /* + * Table entry is less than measured value. + * Table is descending, stop. + */ + break; + } else if (!descending && (pts[i].y > input)) { + /* + * Table entry is greater than measured value. + * Table is ascending, stop. + */ + break; + } + i++; + } + + if (i == 0) { + *output = pts[0].x; + } else if (i == tablesize) { + *output = pts[tablesize-1].x; + } else { + /* + * Result is between search_index and search_index-1. + * Interpolate linearly. + */ + *output = (((int32_t) ((pts[i].x - pts[i-1].x) * + (input - pts[i-1].y)) / + (pts[i].y - pts[i-1].y)) + + pts[i-1].x); + } +} + +void adc_tm_scale_therm_voltage_100k(struct adc_tm_config *param, + const struct adc_tm_data *data) +{ + uint32_t adc_hc_vdd_ref_mv = 1875; + + /* High temperature maps to lower threshold voltage */ + adc_tm_map_temp_voltage( + adcmap_100k_104ef_104fb_1875_vref, + ARRAY_SIZE(adcmap_100k_104ef_104fb_1875_vref), + param->high_thr_temp, ¶m->low_thr_voltage); + + param->low_thr_voltage *= data->full_scale_code_volt; + param->low_thr_voltage = div64_s64(param->low_thr_voltage, + adc_hc_vdd_ref_mv); + + /* Low temperature maps to higher threshold voltage */ + adc_tm_map_temp_voltage( + adcmap_100k_104ef_104fb_1875_vref, + ARRAY_SIZE(adcmap_100k_104ef_104fb_1875_vref), + param->low_thr_temp, ¶m->high_thr_voltage); + + param->high_thr_voltage *= data->full_scale_code_volt; + param->high_thr_voltage = div64_s64(param->high_thr_voltage, + adc_hc_vdd_ref_mv); + +} +EXPORT_SYMBOL(adc_tm_scale_therm_voltage_100k); + +MODULE_DESCRIPTION("Qualcomm Technologies Inc. PMIC ADC_TM common driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/thermal/qcom/adc-tm.c b/drivers/thermal/qcom/adc-tm.c new file mode 100644 index 000000000000..f2a800ba20b8 --- /dev/null +++ b/drivers/thermal/qcom/adc-tm.c @@ -0,0 +1,334 @@ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "adc-tm.h" + +LIST_HEAD(adc_tm_device_list); + +static int adc_tm_get_temp(void *data, int *temp) +{ + struct adc_tm_sensor *s = data; + struct adc_tm_chip *adc_tm = s->chip; + + return adc_tm->ops->get_temp(s, temp); +} + +static int adc_tm_set_trip_temp(void *data, int low_temp, int high_temp) +{ + struct adc_tm_sensor *s = data; + struct adc_tm_chip *adc_tm = s->chip; + + if (adc_tm->ops->set_trips) + return adc_tm->ops->set_trips(s, low_temp, high_temp); + + return 0; +} + +static int adc_tm_register_interrupts(struct adc_tm_chip *adc_tm) +{ + if (adc_tm->ops->interrupts_reg) + return adc_tm->ops->interrupts_reg(adc_tm); + + return 0; +} + +static int adc_tm_init(struct adc_tm_chip *adc_tm, uint32_t dt_chans) +{ + if (adc_tm->ops->init) + return adc_tm->ops->init(adc_tm, dt_chans); + + return 0; +} + +static struct thermal_zone_of_device_ops adc_tm_ops = { + .get_temp = adc_tm_get_temp, + .set_trips = adc_tm_set_trip_temp, +}; + +static int adc_tm_register_tzd(struct adc_tm_chip *adc_tm, int dt_chan_num) +{ + unsigned int i; + struct thermal_zone_device *tzd; + + for (i = 0; i < dt_chan_num; i++) { + adc_tm->sensor[i].chip = adc_tm; + tzd = devm_thermal_zone_of_sensor_register(adc_tm->dev, + adc_tm->sensor[i].adc_ch, + &adc_tm->sensor[i], + &adc_tm_ops); + if (IS_ERR(tzd)) { + pr_err("Error registering TZ zone:%d for dt_ch:%d\n", + PTR_ERR(tzd), adc_tm->sensor[i].adc_ch); + continue; + } + adc_tm->sensor[i].tzd = tzd; + } + + return 0; +} + +static int adc_tm_avg_samples_from_dt(u32 value) +{ + if (!is_power_of_2(value) || value > ADC_TM_AVG_SAMPLES_MAX) + return -EINVAL; + + return __ffs64(value); +} + +static int adc_tm_hw_settle_time_from_dt(u32 value, + const unsigned int *hw_settle) +{ + unsigned int i; + + for (i = 0; i < ADC_TM_HW_SETTLE_SAMPLES_MAX; i++) { + if (value == hw_settle[i]) + return i; + } + + return -EINVAL; +} + +static int adc_tm_decimation_from_dt(u32 value, const unsigned int *decimation) +{ + unsigned int i; + + for (i = 0; i < ADC_TM_DECIMATION_SAMPLES_MAX; i++) { + if (value == decimation[i]) + return i; + } + + return -EINVAL; +} + +static const struct of_device_id adc_tm_match_table[] = { + { + .compatible = "qcom,adc-tm5", + .data = &data_adc_tm5, + }, + {} +}; + +static int adc_tm_get_dt_data(struct platform_device *pdev, + struct adc_tm_chip *adc_tm, + struct iio_channel *chan, + uint32_t dt_chan_num) +{ + struct device_node *child, *node = pdev->dev.of_node; + struct device *dev = &pdev->dev; + const struct of_device_id *id; + const struct adc_tm_data *data; + int ret, idx = 0; + + if (!node) + return -EINVAL; + + id = of_match_node(adc_tm_match_table, node); + if (id) + data = id->data; + else + data = &data_adc_tm5; + adc_tm->data = data; + adc_tm->ops = data->ops; + + ret = of_property_read_u32(node, "qcom,decimation", + &adc_tm->prop.decimation); + if (!ret) { + ret = adc_tm_decimation_from_dt(adc_tm->prop.decimation, + data->decimation); + if (ret < 0) { + dev_err(dev, "Invalid decimation value\n"); + return ret; + } + adc_tm->prop.decimation = ret; + } else { + adc_tm->prop.decimation = ADC_TM_DECIMATION_DEFAULT; + } + + ret = of_property_read_u32(node, "qcom,avg-samples", + &adc_tm->prop.fast_avg_samples); + if (!ret) { + ret = adc_tm_avg_samples_from_dt(adc_tm->prop.fast_avg_samples); + if (ret < 0) { + dev_err(dev, "Invalid fast average with%d\n", ret); + return -EINVAL; + } + } else { + adc_tm->prop.fast_avg_samples = ADC_TM_DEF_AVG_SAMPLES; + } + + adc_tm->prop.timer1 = ADC_TM_TIMER1; + adc_tm->prop.timer2 = ADC_TM_TIMER2; + adc_tm->prop.timer3 = ADC_TM_TIMER3; + + for_each_child_of_node(node, child) { + int channel_num, i = 0; + int calib_type = 0, ret, hw_settle_time = 0; + struct iio_channel *chan_adc; + + ret = of_property_read_u32(child, "reg", &channel_num); + if (ret) { + dev_err(dev, "Invalid channel num\n"); + return -EINVAL; + } + + ret = of_property_read_u32(child, "qcom,hw-settle-time", + &hw_settle_time); + if (!ret) { + ret = adc_tm_hw_settle_time_from_dt(hw_settle_time, + data->hw_settle); + if (ret < 0) { + pr_err("Invalid channel hw settle time property\n"); + return ret; + } + hw_settle_time = ret; + } else { + hw_settle_time = ADC_TM_DEF_HW_SETTLE_TIME; + } + + if (of_property_read_bool(child, "qcom,ratiometric")) + calib_type = ADC_RATIO_CAL; + else + calib_type = ADC_ABS_CAL; + + /* Individual channel properties */ + adc_tm->sensor[idx].adc_ch = channel_num; + adc_tm->sensor[idx].cal_sel = calib_type; + /* Default to 1 second timer select */ + adc_tm->sensor[idx].timer_select = ADC_TIMER_SEL_2; + adc_tm->sensor[idx].hw_settle_time = hw_settle_time; + while (i < dt_chan_num) { + chan_adc = &chan[i]; + if (chan_adc->channel->channel == channel_num) + adc_tm->sensor[idx].adc = chan_adc; + i++; + } + idx++; + } + + return 0; +} + +static int adc_tm_probe(struct platform_device *pdev) +{ + struct device_node *child, *node = pdev->dev.of_node; + struct device *dev = &pdev->dev; + struct adc_tm_chip *adc_tm; + struct regmap *regmap; + struct iio_channel *channels; + int ret, dt_chan_num = 0, indio_chan_count = 0; + u32 reg; + + if (!node) + return -EINVAL; + + for_each_child_of_node(node, child) + dt_chan_num++; + + if (!dt_chan_num) { + dev_err(dev, "No channel listing\n"); + return -EINVAL; + } + + channels = iio_channel_get_all(dev); + if (IS_ERR(channels)) + return PTR_ERR(channels); + + while (channels[indio_chan_count].indio_dev) + indio_chan_count++; + + if (indio_chan_count != dt_chan_num) { + dev_err(dev, "VADC IIO channel missing in main node\n"); + return -EINVAL; + } + + regmap = dev_get_regmap(dev->parent, NULL); + if (!regmap) + return -ENODEV; + + ret = of_property_read_u32(node, "reg", ®); + if (ret < 0) + return ret; + + adc_tm = devm_kzalloc(&pdev->dev, + sizeof(struct adc_tm_chip) + (dt_chan_num * + (sizeof(struct adc_tm_sensor))), GFP_KERNEL); + if (!adc_tm) + return -ENOMEM; + + adc_tm->regmap = regmap; + adc_tm->dev = dev; + adc_tm->base = reg; + adc_tm->dt_channels = dt_chan_num; + + ret = adc_tm_get_dt_data(pdev, adc_tm, channels, dt_chan_num); + if (ret) { + dev_err(dev, "adc-tm get dt data failed\n"); + return ret; + } + + ret = adc_tm_init(adc_tm, dt_chan_num); + if (ret) { + dev_err(dev, "adc-tm init failed\n"); + return ret; + } + + ret = adc_tm_register_tzd(adc_tm, dt_chan_num); + if (ret) { + dev_err(dev, "adc-tm failed to register with of thermal\n"); + return ret; + } + + ret = adc_tm_register_interrupts(adc_tm); + if (ret) { + pr_err("adc-tm register interrupts failed:%d\n", ret); + return ret; + } + + list_add_tail(&adc_tm->list, &adc_tm_device_list); + platform_set_drvdata(pdev, adc_tm); + + return 0; +} + +static int adc_tm_remove(struct platform_device *pdev) +{ + struct adc_tm_chip *adc_tm = platform_get_drvdata(pdev); + + if (adc_tm->ops->shutdown) + adc_tm->ops->shutdown(adc_tm); + + return 0; +} + +static struct platform_driver adc_tm_driver = { + .driver = { + .name = "qcom,adc-tm", + .of_match_table = adc_tm_match_table, + }, + .probe = adc_tm_probe, + .remove = adc_tm_remove, +}; +module_platform_driver(adc_tm_driver); + +MODULE_DESCRIPTION("Qualcomm Technologies Inc. PMIC ADC_TM driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/thermal/qcom/adc-tm.h b/drivers/thermal/qcom/adc-tm.h new file mode 100644 index 000000000000..5ab40e9a26f6 --- /dev/null +++ b/drivers/thermal/qcom/adc-tm.h @@ -0,0 +1,218 @@ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#ifndef __QCOM_ADC_TM_H__ +#define __QCOM_ADC_TM_H__ + +#include +#include +#include +#include +#include +#include + +struct adc_tm_chip; + +#define ADC_TM_DECIMATION_DEFAULT 840 +#define ADC_TM_DECIMATION_SAMPLES_MAX 3 +#define ADC_TM_DEF_AVG_SAMPLES 0 /* 1 sample */ +#define ADC_TM_DEF_HW_SETTLE_TIME 0 /* 15 us */ +#define ADC_TM_HW_SETTLE_SAMPLES_MAX 16 +#define ADC_TM_AVG_SAMPLES_MAX 16 +#define ADC_TM_TIMER1 3 /* 3.9ms */ +#define ADC_TM_TIMER2 10 /* 1 second */ +#define ADC_TM_TIMER3 4 /* 4 second */ + +enum adc_cal_method { + ADC_NO_CAL = 0, + ADC_RATIO_CAL = 1, + ADC_ABS_CAL = 2, + ADC_CAL_SEL_NONE, +}; + +enum adc_cal_val { + ADC_TIMER_CAL = 0, + ADC_NEW_CAL, + ADC_CAL_VAL_NONE, +}; + +enum adc_timer_select { + ADC_TIMER_SEL_1 = 0, + ADC_TIMER_SEL_2, + ADC_TIMER_SEL_3, + ADC_TIMER_SEL_NONE, +}; + +struct adc_tm_sensor { + struct adc_tm_chip *chip; + struct thermal_zone_device *tzd; + enum adc_cal_val cal_val; + enum adc_cal_method cal_sel; + unsigned int hw_settle_time; + unsigned int adc_ch; + unsigned int btm_ch; + unsigned int prescaling; + unsigned int timer_select; + struct iio_channel *adc; +}; + +struct adc_tm_cmn_prop { + unsigned int decimation; + unsigned int fast_avg_samples; + unsigned int timer1; + unsigned int timer2; + unsigned int timer3; +}; + +struct adc_tm_ops { + int (*get_temp)(struct adc_tm_sensor *, int *); + int (*init)(struct adc_tm_chip *, uint32_t); + int (*set_trips)(struct adc_tm_sensor *, int, int); + int (*interrupts_reg)(struct adc_tm_chip *); + int (*shutdown)(struct adc_tm_chip *); +}; + +struct adc_tm_chip { + struct device *dev; + struct list_head list; + struct regmap *regmap; + u16 base; + struct adc_tm_cmn_prop prop; + spinlock_t adc_tm_lock; + const struct adc_tm_ops *ops; + const struct adc_tm_data *data; + unsigned int dt_channels; + struct adc_tm_sensor sensor[0]; +}; + +struct adc_tm_data { + const struct adc_tm_ops *ops; + const u32 full_scale_code_volt; + unsigned int *decimation; + unsigned int *hw_settle; +}; + +extern const struct adc_tm_data data_adc_tm5; +/** + * Channel index for the corresponding index to adc_tm_channel_select + */ +enum adc_tm_channel_num { + ADC_TM_CHAN0 = 0, + ADC_TM_CHAN1, + ADC_TM_CHAN2, + ADC_TM_CHAN3, + ADC_TM_CHAN4, + ADC_TM_CHAN5, + ADC_TM_CHAN6, + ADC_TM_CHAN7, + ADC_TM_CHAN_NONE +}; + +/** + * Channel selection registers for each of the configurable measurements + * Channels allotment is set at device config for a channel. + */ +enum adc_tm_channel_sel { + ADC_TM_M0_ADC_CH_SEL_CTL = 0x60, + ADC_TM_M1_ADC_CH_SEL_CTL = 0x68, + ADC_TM_M2_ADC_CH_SEL_CTL = 0x70, + ADC_TM_M3_ADC_CH_SEL_CTL = 0x78, + ADC_TM_M4_ADC_CH_SEL_CTL = 0x80, + ADC_TM_M5_ADC_CH_SEL_CTL = 0x88, + ADC_TM_M6_ADC_CH_SEL_CTL = 0x90, + ADC_TM_M7_ADC_CH_SEL_CTL = 0x98, + ADC_TM_CH_SELECT_NONE +}; + +/** + * enum adc_tm_fast_avg_ctl - Provides ability to obtain single result + * from the ADC that is an average of multiple measurement + * samples. Select number of samples for use in fast + * average mode (i.e. 2 ^ value). + * %ADC_FAST_AVG_SAMPLE_1: 0x0 = 1 + * %ADC_FAST_AVG_SAMPLE_2: 0x1 = 2 + * %ADC_FAST_AVG_SAMPLE_4: 0x2 = 4 + * %ADC_FAST_AVG_SAMPLE_8: 0x3 = 8 + * %ADC_FAST_AVG_SAMPLE_16: 0x4 = 16 + */ +enum qpnp_adc_fast_avg_ctl { + ADC_FAST_AVG_SAMPLE_1 = 0, + ADC_FAST_AVG_SAMPLE_2, + ADC_FAST_AVG_SAMPLE_4, + ADC_FAST_AVG_SAMPLE_8, + ADC_FAST_AVG_SAMPLE_16, + ADC_FAST_AVG_SAMPLE_NONE, +}; + +struct adc_tm_trip_reg_type { + enum adc_tm_channel_sel btm_amux_ch; + uint16_t low_thr_lsb_addr; + uint16_t low_thr_msb_addr; + uint16_t high_thr_lsb_addr; + uint16_t high_thr_msb_addr; + u8 multi_meas_en; + u8 low_thr_int_chan_en; + u8 high_thr_int_chan_en; + u8 meas_interval_ctl; +}; + +/** + * struct adc_tm_config - Represent ADC Thermal Monitor configuration. + * @channel: ADC channel for which thermal monitoring is requested. + * @adc_code: The pre-calibrated digital output of a given ADC releative to the + * ADC reference. + * @high_thr_temp: Temperature at which high threshold notification is required. + * @low_thr_temp: Temperature at which low threshold notification is required. + * @low_thr_voltage : Low threshold voltage ADC code used for reverse + * calibration. + * @high_thr_voltage: High threshold voltage ADC code used for reverse + * calibration. + */ +struct adc_tm_config { + int channel; + int adc_code; + int high_thr_temp; + int low_thr_temp; + int64_t high_thr_voltage; + int64_t low_thr_voltage; +}; + +/** + * struct adc_map_pt - Map the graph representation for ADC channel + * @x: Represent the ADC digitized code. + * @y: Represent the physical data which can be temperature, voltage, + * resistance. + */ +struct adc_tm_map_pt { + int32_t x; + int32_t y; +}; + +/** + * struct adc_linear_graph - Represent ADC characteristics. + * @dy: numerator slope to calculate the gain. + * @dx: denominator slope to calculate the gain. + * @gnd: A/D word of the ground reference used for the channel. + * + * Each ADC device has different offset and gain parameters which are + * computed to calibrate the device. + */ +struct adc_tm_linear_graph { + s32 dy; + s32 dx; + s32 gnd; +}; + +void adc_tm_scale_therm_voltage_100k(struct adc_tm_config *param, + const struct adc_tm_data *data); + +#endif /* __QCOM_ADC_TM_H__ */ diff --git a/drivers/thermal/qcom/adc-tm5.c b/drivers/thermal/qcom/adc-tm5.c new file mode 100644 index 000000000000..6c22366eaf3e --- /dev/null +++ b/drivers/thermal/qcom/adc-tm5.c @@ -0,0 +1,573 @@ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "adc-tm.h" +#include "../thermal_core.h" + +#define ADC_TM_STATUS2 0x09 +#define ADC_TM_STATUS_LOW 0x0a +#define ADC_TM_STATUS_HIGH 0x0b +#define ADC_TM_NUM_BTM 0x0f + +#define ADC_TM_ADC_DIG_PARAM 0x42 +#define ADC_TM_FAST_AVG_CTL 0x43 +#define ADC_TM_FAST_AVG_EN BIT(7) + +#define ADC_TM_MEAS_INTERVAL_CTL 0x44 +#define ADC_TM_MEAS_INTERVAL_CTL2 0x45 + +#define ADC_TM_MEAS_INTERVAL_CTL2_SHIFT 0x4 +#define ADC_TM_MEAS_INTERVAL_CTL2_MASK 0xf0 +#define ADC_TM_MEAS_INTERVAL_CTL3_MASK 0xf + +#define ADC_TM_EN_CTL1 0x46 +#define ADC_TM_EN BIT(7) +#define ADC_TM_CONV_REQ 0x47 +#define ADC_TM_CONV_REQ_EN BIT(7) + +#define ADC_TM_Mn_ADC_CH_SEL_CTL(n) ((n * 8) + 0x60) +#define ADC_TM_Mn_LOW_THR0(n) ((n * 8) + 0x61) +#define ADC_TM_Mn_LOW_THR1(n) ((n * 8) + 0x62) +#define ADC_TM_Mn_HIGH_THR0(n) ((n * 8) + 0x63) +#define ADC_TM_Mn_HIGH_THR1(n) ((n * 8) + 0x64) +#define ADC_TM_Mn_MEAS_INTERVAL_CTL(n) ((n * 8) + 0x65) +#define ADC_TM_Mn_CTL(n) ((n * 8) + 0x66) +#define ADC_TM_CTL_HW_SETTLE_DELAY_MASK 0xf +#define ADC_TM_CTL_CAL_SEL 0x30 +#define ADC_TM_CTL_CAL_SEL_MASK_SHIFT 4 +#define ADC_TM_CTL_CAL_VAL 0x40 + +#define ADC_TM_Mn_EN(n) ((n * 8) + 0x67) +#define ADC_TM_Mn_MEAS_EN BIT(7) +#define ADC_TM_Mn_HIGH_THR_INT_EN BIT(1) +#define ADC_TM_Mn_LOW_THR_INT_EN BIT(0) +#define ADC_TM_LOWER_MASK(n) ((n) & 0x000000ff) +#define ADC_TM_UPPER_MASK(n) (((n) & 0xffffff00) >> 8) + +static struct adc_tm_trip_reg_type adc_tm_ch_data[] = { + [ADC_TM_CHAN0] = {ADC_TM_M0_ADC_CH_SEL_CTL}, + [ADC_TM_CHAN1] = {ADC_TM_M1_ADC_CH_SEL_CTL}, + [ADC_TM_CHAN2] = {ADC_TM_M2_ADC_CH_SEL_CTL}, + [ADC_TM_CHAN3] = {ADC_TM_M3_ADC_CH_SEL_CTL}, + [ADC_TM_CHAN4] = {ADC_TM_M4_ADC_CH_SEL_CTL}, + [ADC_TM_CHAN5] = {ADC_TM_M5_ADC_CH_SEL_CTL}, + [ADC_TM_CHAN6] = {ADC_TM_M6_ADC_CH_SEL_CTL}, + [ADC_TM_CHAN7] = {ADC_TM_M7_ADC_CH_SEL_CTL}, +}; + +static int adc_tm5_get_temp(struct adc_tm_sensor *sensor, int *temp) +{ + int ret, milli_celsius; + + if (!sensor || !sensor->adc) + return -EINVAL; + + ret = iio_read_channel_processed(sensor->adc, &milli_celsius); + if (ret < 0) + return ret; + + *temp = milli_celsius; + + return 0; +} + +static int32_t adc_tm5_read_reg(struct adc_tm_chip *chip, + int16_t reg, u8 *data, int len) +{ + int ret; + + ret = regmap_bulk_read(chip->regmap, (chip->base + reg), data, len); + if (ret < 0) + pr_err("adc-tm read reg %d failed with %d\n", reg, ret); + + return ret; +} + +static int32_t adc_tm5_write_reg(struct adc_tm_chip *chip, + int16_t reg, u8 *data, int len) +{ + int ret; + + ret = regmap_bulk_write(chip->regmap, (chip->base + reg), data, len); + if (ret < 0) + pr_err("adc-tm write reg %d failed with %d\n", reg, ret); + + return ret; +} + +static int32_t adc_tm5_reg_update(struct adc_tm_chip *chip, + uint16_t addr, u8 mask, bool state) +{ + u8 reg_value = 0; + int ret; + + ret = adc_tm5_read_reg(chip, addr, ®_value, 1); + if (ret < 0) { + pr_err("read failed for addr:0x%x\n", addr); + return ret; + } + + reg_value = reg_value & ~mask; + if (state) + reg_value |= mask; + + pr_debug("state:%d, reg:0x%x with bits:0x%x and mask:0x%x\n", + state, addr, reg_value, ~mask); + ret = adc_tm5_write_reg(chip, addr, ®_value, 1); + if (ret < 0) { + pr_err("write failed for addr:%x\n", addr); + return ret; + } + + return ret; +} + +static int32_t adc_tm5_get_btm_idx(struct adc_tm_chip *chip, + uint32_t btm_chan, uint32_t *btm_chan_idx) +{ + int i; + + for (i = 0; i < ADC_TM_CHAN_NONE; i++) { + if (adc_tm_ch_data[i].btm_amux_ch == btm_chan) { + *btm_chan_idx = i; + return 0; + } + } + + return -EINVAL; +} + +static int32_t adc_tm5_enable(struct adc_tm_chip *chip) +{ + int rc = 0; + u8 data = 0; + + data = ADC_TM_EN; + rc = adc_tm5_write_reg(chip, ADC_TM_EN_CTL1, &data, 1); + if (rc < 0) { + pr_err("adc-tm enable failed\n"); + return rc; + } + + data = ADC_TM_CONV_REQ_EN; + rc = adc_tm5_write_reg(chip, ADC_TM_CONV_REQ, &data, 1); + if (rc < 0) { + pr_err("adc-tm request conversion failed\n"); + return rc; + } + + return rc; +} + +static int adc_tm5_configure(struct adc_tm_sensor *sensor, + uint32_t btm_chan_idx) +{ + struct adc_tm_chip *chip = sensor->chip; + u8 buf[8], cal_sel; + int ret = 0; + + ret = adc_tm5_read_reg(chip, + ADC_TM_Mn_ADC_CH_SEL_CTL(btm_chan_idx), buf, 8); + if (ret < 0) { + pr_err("adc-tm block read failed with %d\n", ret); + return ret; + } + + /* Update ADC channel select */ + buf[0] = sensor->adc_ch; + + /* Update timer select */ + buf[5] = sensor->timer_select; + + /* Set calibration select, hw_settle delay */ + cal_sel |= (u8) (sensor->cal_sel << ADC_TM_CTL_CAL_SEL_MASK_SHIFT); + buf[6] &= (u8) ~ADC_TM_CTL_HW_SETTLE_DELAY_MASK; + buf[6] |= (u8) sensor->hw_settle_time; + buf[6] &= (u8) ~ADC_TM_CTL_CAL_SEL; + buf[6] |= (u8) cal_sel; + + buf[7] |= ADC_TM_Mn_MEAS_EN; + + ret = adc_tm5_write_reg(chip, + ADC_TM_Mn_ADC_CH_SEL_CTL(btm_chan_idx), buf, 8); + if (ret < 0) { + pr_err("adc-tm block write failed with %d\n", ret); + return ret; + } + + return 0; +} + +static int adc_tm5_set_mode(struct adc_tm_sensor *sensor, + enum thermal_device_mode mode) +{ + struct adc_tm_chip *chip = sensor->chip; + int ret = 0; + uint32_t btm_chan_idx = 0; + + ret = adc_tm5_get_btm_idx(chip, sensor->btm_ch, &btm_chan_idx); + if (ret < 0) { + pr_err("Invalid btm channel idx with %d\n", ret); + return ret; + } + + if (mode == THERMAL_DEVICE_ENABLED) { + ret = adc_tm5_configure(sensor, btm_chan_idx); + if (ret < 0) { + pr_err("Error during adc-tm configure:%d\n", ret); + return ret; + } + + ret = adc_tm5_enable(chip); + if (ret < 0) + pr_err("Error enabling adc-tm with %d\n", ret); + + } else if (mode == THERMAL_DEVICE_DISABLED) { + ret = adc_tm5_reg_update(chip, + ADC_TM_Mn_EN(btm_chan_idx), + ADC_TM_Mn_MEAS_EN, false); + if (ret < 0) + pr_err("Disable failed for ch:%d\n", btm_chan_idx); + } + + return ret; +} + +static int adc_tm5_activate_trip_type(struct adc_tm_sensor *adc_tm, + int trip, enum thermal_device_mode mode) +{ + struct adc_tm_chip *chip = adc_tm->chip; + int ret = 0; + bool state = false; + uint32_t btm_chan_idx = 0, btm_chan = 0; + + if (mode == THERMAL_DEVICE_ENABLED) + state = true; + + btm_chan = adc_tm->btm_ch; + ret = adc_tm5_get_btm_idx(chip, btm_chan, &btm_chan_idx); + if (ret < 0) { + pr_err("Invalid btm channel idx\n"); + return ret; + } + + switch (trip) { + case THERMAL_TRIP_CONFIGURABLE_HI: + /* low_thr (lower voltage) for higher temp */ + ret = adc_tm5_reg_update(chip, + ADC_TM_Mn_EN(btm_chan_idx), + ADC_TM_Mn_LOW_THR_INT_EN, state); + if (ret) + pr_err("channel:%x failed\n", btm_chan); + break; + case THERMAL_TRIP_CONFIGURABLE_LOW: + /* high_thr (higher voltage) for cooler temp */ + ret = adc_tm5_reg_update(chip, + ADC_TM_Mn_EN(btm_chan_idx), + ADC_TM_Mn_HIGH_THR_INT_EN, state); + if (ret) + pr_err("channel:%x failed\n", btm_chan); + break; + default: + return -EINVAL; + } + + return ret; +} + +static int adc_tm5_set_trip_temp(struct adc_tm_sensor *sensor, + int low_temp, int high_temp) +{ + struct adc_tm_chip *chip = sensor->chip; + struct adc_tm_config tm_config; + u8 trip_low_thr[2], trip_high_thr[2]; + uint16_t reg_low_thr_lsb, reg_high_thr_lsb; + int ret; + uint32_t btm_chan = 0, btm_chan_idx = 0, mask = 0; + unsigned long flags; + + if (!sensor) + return -EINVAL; + + pr_debug("%s:low_temp(mdegC):%d, high_temp(mdegC):%d\n", __func__, + low_temp, high_temp); + + tm_config.channel = sensor->adc_ch; + tm_config.high_thr_temp = tm_config.low_thr_temp = 0; + if (high_temp != INT_MAX) + tm_config.high_thr_temp = high_temp; + if (low_temp != INT_MIN) + tm_config.low_thr_temp = low_temp; + + if ((high_temp == INT_MAX) && (low_temp == INT_MIN)) { + pr_err("No trips to set\n"); + return -EINVAL; + } + + pr_debug("requested a low temp- %d and high temp- %d\n", + tm_config.low_thr_temp, tm_config.high_thr_temp); + adc_tm_scale_therm_voltage_100k(&tm_config, chip->data); + + /* Cool temperature corresponds to high voltage threshold */ + mask = lower_32_bits(tm_config.high_thr_voltage); + trip_high_thr[0] = ADC_TM_LOWER_MASK(mask); + trip_high_thr[1] = ADC_TM_UPPER_MASK(mask); + /* Warm temperature corresponds to low voltage threshold */ + mask = lower_32_bits(tm_config.low_thr_voltage); + trip_low_thr[0] = ADC_TM_LOWER_MASK(mask); + trip_low_thr[1] = ADC_TM_UPPER_MASK(mask); + + pr_debug("high_thr:0x%llx, low_thr:0x%llx\n", + tm_config.high_thr_voltage, tm_config.low_thr_voltage); + + btm_chan = sensor->btm_ch; + ret = adc_tm5_get_btm_idx(chip, btm_chan, &btm_chan_idx); + if (ret < 0) { + pr_err("Invalid btm channel idx\n"); + return ret; + } + + spin_lock_irqsave(&chip->adc_tm_lock, flags); + + reg_low_thr_lsb = ADC_TM_Mn_LOW_THR0(btm_chan_idx); + reg_high_thr_lsb = ADC_TM_Mn_HIGH_THR0(btm_chan_idx); + + if (high_temp != INT_MAX) { + ret = adc_tm5_write_reg(chip, reg_low_thr_lsb, + trip_low_thr, 2); + if (ret) { + pr_err("Warm set threshold err\n"); + goto fail; + } + + ret = adc_tm5_activate_trip_type(sensor, + THERMAL_TRIP_CONFIGURABLE_HI, + THERMAL_DEVICE_ENABLED); + if (ret) { + pr_err("adc-tm warm activation failed\n"); + goto fail; + } + } else { + ret = adc_tm5_activate_trip_type(sensor, + THERMAL_TRIP_CONFIGURABLE_HI, + THERMAL_DEVICE_DISABLED); + if (ret) { + pr_err("adc-tm warm deactivation failed\n"); + goto fail; + } + } + + if (low_temp != INT_MIN) { + ret = adc_tm5_write_reg(chip, reg_high_thr_lsb, + trip_high_thr, 2); + if (ret) { + pr_err("adc-tm cool temp set threshold err\n"); + goto fail; + } + + ret = adc_tm5_activate_trip_type(sensor, + THERMAL_TRIP_CONFIGURABLE_LOW, + THERMAL_DEVICE_ENABLED); + if (ret) { + pr_err("adc-tm cool activation failed\n"); + goto fail; + } + } else { + ret = adc_tm5_activate_trip_type(sensor, + THERMAL_TRIP_CONFIGURABLE_LOW, + THERMAL_DEVICE_DISABLED); + if (ret) { + pr_err("adc-tm cool deactivation failed\n"); + goto fail; + } + } + + if ((high_temp != INT_MAX) || (low_temp != INT_MIN)) { + ret = adc_tm5_set_mode(sensor, THERMAL_DEVICE_ENABLED); + if (ret) + pr_err("sensor enabled failed\n"); + } else { + ret = adc_tm5_set_mode(sensor, THERMAL_DEVICE_DISABLED); + if (ret) + pr_err("sensor disable failed\n"); + } + +fail: + spin_unlock_irqrestore(&chip->adc_tm_lock, flags); + + return ret; +} + +static irqreturn_t adc_tm5_handler(int irq, void *data) +{ + struct adc_tm_chip *chip = data; + u8 status_low, status_high, ctl; + int ret, i = 0; + unsigned long flags; + + ret = adc_tm5_read_reg(chip, ADC_TM_STATUS_LOW, &status_low, 1); + if (ret < 0) { + pr_err("adc-tm-tm read status low failed with %d\n", ret); + return IRQ_HANDLED; + } + + ret = adc_tm5_read_reg(chip, ADC_TM_STATUS_HIGH, &status_high, 1); + if (ret < 0) { + pr_err("adc-tm-tm read status high failed with %d\n", ret); + return IRQ_HANDLED; + } + + while (i < chip->dt_channels) { + bool upper_set = false, lower_set = false; + int temp; + + if (IS_ERR(chip->sensor[i].tzd)) + continue; + + ret = adc_tm5_get_temp(&chip->sensor[i], &temp); + if (ret < 0) + continue; + + spin_lock_irqsave(&chip->adc_tm_lock, flags); + + ret = adc_tm5_read_reg(chip, ADC_TM_Mn_EN(i), &ctl, 1); + if (ret) { + pr_err("ctl read failed with %d\n", ret); + goto fail; + } + + if ((status_low & 0x1) && (ctl & ADC_TM_Mn_MEAS_EN) + && (ctl & ADC_TM_Mn_LOW_THR_INT_EN)) + lower_set = true; + + if ((status_high & 0x1) && (ctl & ADC_TM_Mn_MEAS_EN) && + (ctl & ADC_TM_Mn_HIGH_THR_INT_EN)) + upper_set = true; +fail: + status_low >>= 1; + status_high >>= 1; + spin_unlock_irqrestore(&chip->adc_tm_lock, flags); + if (upper_set || lower_set) { + /* + * Expected behavior is while notifying of_thermal, + * thermal core will call set_trips with new thresholds + * and activate/disable the appropriate trips. + */ + pr_debug("notifying of_thermal\n"); + of_thermal_handle_trip(chip->sensor[i].tzd); + } + i++; + } + return IRQ_HANDLED; +} + +static int adc_tm5_register_interrupts(struct adc_tm_chip *chip) +{ + struct platform_device *pdev; + int ret, irq; + + if (!chip) + return -EINVAL; + + pdev = to_platform_device(chip->dev); + + irq = platform_get_irq_byname(pdev, "thr-int-en"); + if (irq < 0) { + dev_err(&pdev->dev, "failed to get irq %s\n", + "thr-int-en"); + return irq; + } + + ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, + adc_tm5_handler, + IRQF_TRIGGER_RISING | IRQF_ONESHOT, + "thr-int-en", chip); + if (ret) { + dev_err(&pdev->dev, "failed to get irq %s\n", + "thr-int-en"); + return ret; + } + + enable_irq_wake(irq); + + return ret; +} + +static int adc_tm5_init(struct adc_tm_chip *chip, uint32_t dt_chans) +{ + u8 buf[4], channels_available; + int ret, i; + + ret = adc_tm5_read_reg(chip, ADC_TM_NUM_BTM, &channels_available, 1); + if (ret < 0) { + pr_err("read failed for BTM channels\n"); + return ret; + } + + if (dt_chans > channels_available) { + pr_err("Number of nodes greater than channels supported:%d\n", + channels_available); + return -EINVAL; + } + + /* Select decimation */ + buf[0] = chip->prop.decimation; + + /* Select number of samples in fast average mode */ + buf[1] |= chip->prop.fast_avg_samples | ADC_TM_FAST_AVG_EN; + + /* Select timer1 */ + buf[2] = chip->prop.timer1; + + /* Select timer2 and timer2 */ + buf[3] |= chip->prop.timer2 << ADC_TM_MEAS_INTERVAL_CTL2_SHIFT; + buf[3] |= chip->prop.timer3; + + ret = adc_tm5_write_reg(chip, + ADC_TM_ADC_DIG_PARAM, buf, 4); + if (ret < 0) + pr_err("adc-tm block write failed with %d\n", ret); + + spin_lock_init(&chip->adc_tm_lock); + + for (i = 0; i < dt_chans; i++) + chip->sensor[i].btm_ch = adc_tm_ch_data[i].btm_amux_ch; + + return ret; +} + +static const struct adc_tm_ops ops_adc_tm5 = { + .init = adc_tm5_init, + .set_trips = adc_tm5_set_trip_temp, + .interrupts_reg = adc_tm5_register_interrupts, + .get_temp = adc_tm5_get_temp, +}; + +const struct adc_tm_data data_adc_tm5 = { + .ops = &ops_adc_tm5, + .full_scale_code_volt = 0x70e4, + .decimation = (unsigned int []) {250, 420, 840}, + .hw_settle = (unsigned int []) {15, 100, 200, 300, 400, 500, 600, 700, + 1, 2, 4, 8, 16, 32, 64, 128}, +}; -- GitLab From 99f0a4864bf102e4921f7cd0769c9d2ecfd47b7a Mon Sep 17 00:00:00 2001 From: Siddartha Mohanadoss Date: Tue, 17 Apr 2018 11:41:54 -0700 Subject: [PATCH 0596/1635] ARM: dts: msm: Add ADC_TM nodes for PM855, PM855B and PM855l ADC_TM peripheral supports clients to set temperature thresholds and receive notification. Add ADC_TM channels as thermal zones that are registered with of_thermal for thermal clients to set trip thresholds and read temperature. Change-Id: I8932c44bf3b5178d09d7431b435c153b30ce959e Signed-off-by: Siddartha Mohanadoss --- arch/arm64/boot/dts/qcom/pm855.dtsi | 11 +++ arch/arm64/boot/dts/qcom/pm855b.dtsi | 25 ++++++ arch/arm64/boot/dts/qcom/pm855l.dtsi | 13 +++ arch/arm64/boot/dts/qcom/sm8150-cdp.dtsi | 108 +++++++++++++++++++++++ arch/arm64/boot/dts/qcom/sm8150-mtp.dtsi | 108 +++++++++++++++++++++++ arch/arm64/boot/dts/qcom/sm8150-qrd.dtsi | 108 +++++++++++++++++++++++ 6 files changed, 373 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/pm855.dtsi b/arch/arm64/boot/dts/qcom/pm855.dtsi index 1dda03621edd..dba9da14b9ac 100644 --- a/arch/arm64/boot/dts/qcom/pm855.dtsi +++ b/arch/arm64/boot/dts/qcom/pm855.dtsi @@ -134,6 +134,17 @@ qcom,pre-scaling = <1 1>; }; }; + + pm855_adc_tm: adc_tm@3500 { + compatible = "qcom,adc-tm5"; + reg = <0x3500 0x100>; + interrupts = <0x0 0x35 0x0 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "thr-int-en"; + #address-cells = <1>; + #size-cells = <0>; + #thermal-sensor-cells = <1>; + io-channels = <&pm855_vadc ADC_XO_THERM_PU2>; + }; }; qcom,pm855@1 { diff --git a/arch/arm64/boot/dts/qcom/pm855b.dtsi b/arch/arm64/boot/dts/qcom/pm855b.dtsi index 10a2f3d53a59..f7e27363bf8a 100644 --- a/arch/arm64/boot/dts/qcom/pm855b.dtsi +++ b/arch/arm64/boot/dts/qcom/pm855b.dtsi @@ -142,6 +142,17 @@ }; }; + pm855b_adc_tm: adc_tm@3500 { + compatible = "qcom,adc-tm5"; + reg = <0x3500 0x100>; + interrupts = <0x2 0x35 0x0 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "thr-int-en"; + #address-cells = <1>; + #size-cells = <0>; + #thermal-sensor-cells = <1>; + io-channels = <&pm855b_vadc ADC_AMUX_THM2_PU2>; + }; + pm855b_charger: qcom,qpnp-smb5 { compatible = "qcom,qpnp-smb5"; #address-cells = <1>; @@ -472,6 +483,20 @@ }; &thermal_zones { + pm855b-wp-therm { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&pm855b_adc_tm ADC_AMUX_THM2_PU2>; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + pm855b_temp_alarm: pm855b_tz { polling-delay-passive = <0>; polling-delay = <0>; diff --git a/arch/arm64/boot/dts/qcom/pm855l.dtsi b/arch/arm64/boot/dts/qcom/pm855l.dtsi index fc1359503514..5edc237769d2 100644 --- a/arch/arm64/boot/dts/qcom/pm855l.dtsi +++ b/arch/arm64/boot/dts/qcom/pm855l.dtsi @@ -117,6 +117,19 @@ "bcl-vbat-lvl2"; #thermal-sensor-cells = <1>; }; + + pm855l_adc_tm: adc_tm@3500 { + compatible = "qcom,adc-tm5"; + reg = <0x3500 0x100>; + interrupts = <0x4 0x35 0x0 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "thr-int-en"; + #address-cells = <1>; + #size-cells = <0>; + #thermal-sensor-cells = <1>; + io-channels = <&pm855l_vadc ADC_AMUX_THM1_PU2>, + <&pm855l_vadc ADC_AMUX_THM2_PU2>, + <&pm855l_vadc ADC_AMUX_THM3_PU2>; + }; }; qcom,pm855l@5 { diff --git a/arch/arm64/boot/dts/qcom/sm8150-cdp.dtsi b/arch/arm64/boot/dts/qcom/sm8150-cdp.dtsi index 570f3a6d8137..24f3796dda68 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-cdp.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-cdp.dtsi @@ -410,3 +410,111 @@ mhi,fw-name = "debug.mbn"; status = "okay"; }; + +&pm855b_adc_tm { + wp_therm { + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + }; +}; + +&pm855_adc_tm { + xo_therm { + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + }; +}; + +&pm855l_adc_tm { + camera_flash_therm { + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + }; + + skin_msm_therm { + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + }; + + pa_therm2 { + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + }; +}; + +&thermal_zones { + wp-therm { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&pm855b_adc_tm ADC_AMUX_THM2_PU2>; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + xo-therm { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&pm855_adc_tm ADC_XO_THERM_PU2>; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + camera-flash-therm { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&pm855l_adc_tm ADC_AMUX_THM1_PU2>; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + skin-msm-therm { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&pm855l_adc_tm ADC_AMUX_THM2_PU2>; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + pa-therm2 { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&pm855l_adc_tm ADC_AMUX_THM3_PU2>; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/sm8150-mtp.dtsi b/arch/arm64/boot/dts/qcom/sm8150-mtp.dtsi index 3607f5a38a32..c76fa288c127 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-mtp.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-mtp.dtsi @@ -414,3 +414,111 @@ mhi,fw-name = "debug.mbn"; status = "okay"; }; + +&pm855b_adc_tm { + wp_therm { + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + }; +}; + +&pm855_adc_tm { + xo_therm { + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + }; +}; + +&pm855l_adc_tm { + camera_flash_therm { + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + }; + + skin_msm_therm { + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + }; + + pa_therm2 { + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + }; +}; + +&thermal_zones { + wp-therm { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&pm855b_adc_tm ADC_AMUX_THM2_PU2>; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + xo-therm { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&pm855_adc_tm ADC_XO_THERM_PU2>; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + camera-flash-therm { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&pm855l_adc_tm ADC_AMUX_THM1_PU2>; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + skin-msm-therm { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&pm855l_adc_tm ADC_AMUX_THM2_PU2>; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + pa-therm2 { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&pm855l_adc_tm ADC_AMUX_THM3_PU2>; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/sm8150-qrd.dtsi b/arch/arm64/boot/dts/qcom/sm8150-qrd.dtsi index cf63ff6565ec..74a8e7aca49a 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-qrd.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-qrd.dtsi @@ -388,3 +388,111 @@ &wil6210 { status = "ok"; }; + +&pm855b_adc_tm { + wp_therm { + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + }; +}; + +&pm855_adc_tm { + xo_therm { + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + }; +}; + +&pm855l_adc_tm { + camera_flash_therm { + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + }; + + skin_msm_therm { + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + }; + + pa_therm2 { + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + }; +}; + +&thermal_zones { + wp-therm { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&pm855b_adc_tm ADC_AMUX_THM2_PU2>; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + xo-therm { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&pm855_adc_tm ADC_XO_THERM_PU2>; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + camera-flash-therm { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&pm855l_adc_tm ADC_AMUX_THM1_PU2>; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + skin-msm-therm { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&pm855l_adc_tm ADC_AMUX_THM2_PU2>; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + pa-therm2 { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&pm855l_adc_tm ADC_AMUX_THM3_PU2>; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; +}; -- GitLab From 9befaff58bc16c468d1074fe311570b871114c41 Mon Sep 17 00:00:00 2001 From: Ping Li Date: Fri, 20 Apr 2018 15:34:06 -0700 Subject: [PATCH 0597/1635] drm/msm/sde: Update CSC matrix coefficient programming Currently VIG CSC and DMA CSC share the same CSC matrix program function. However, the input CSC matrix data for VIG and DMA pipes are in different formats. This change adds an additional parameter for VIG and DMA pipes to specify the format change. Change-Id: I7edb18a1e91f6caabcbf79e895aa0076890e217c Signed-off-by: Ping Li --- drivers/gpu/drm/msm/sde/sde_hw_sspp.c | 3 ++- drivers/gpu/drm/msm/sde/sde_hw_util.c | 25 +++++++++++++------------ drivers/gpu/drm/msm/sde/sde_hw_util.h | 3 ++- 3 files changed, 17 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/msm/sde/sde_hw_sspp.c b/drivers/gpu/drm/msm/sde/sde_hw_sspp.c index 12b05e628c6f..4533a1a825f3 100644 --- a/drivers/gpu/drm/msm/sde/sde_hw_sspp.c +++ b/drivers/gpu/drm/msm/sde/sde_hw_sspp.c @@ -150,6 +150,7 @@ #define VIG_CSC_10_SRC_DATAFMT BIT(1) #define VIG_CSC_10_EN BIT(0) #define CSC_10BIT_OFFSET 4 +#define DGM_CSC_MATRIX_SHIFT 0 /* traffic shaper clock in Hz */ #define TS_CLK 19200000 @@ -1053,7 +1054,7 @@ static void sde_hw_sspp_setup_dgm_csc(struct sde_hw_pipe *ctx, if (data) { op_mode |= BIT(0); sde_hw_csc_matrix_coeff_setup(&ctx->hw, - offset + CSC_10BIT_OFFSET, data); + offset + CSC_10BIT_OFFSET, data, DGM_CSC_MATRIX_SHIFT); } SDE_REG_WRITE(&ctx->hw, offset, op_mode); diff --git a/drivers/gpu/drm/msm/sde/sde_hw_util.c b/drivers/gpu/drm/msm/sde/sde_hw_util.c index 84ce6df21883..fab9e349b28a 100644 --- a/drivers/gpu/drm/msm/sde/sde_hw_util.c +++ b/drivers/gpu/drm/msm/sde/sde_hw_util.c @@ -373,27 +373,27 @@ u32 sde_hw_get_scaler3_ver(struct sde_hw_blk_reg_map *c, } void sde_hw_csc_matrix_coeff_setup(struct sde_hw_blk_reg_map *c, - u32 csc_reg_off, struct sde_csc_cfg *data) + u32 csc_reg_off, struct sde_csc_cfg *data, + u32 shift_bit) { u32 val; if (!c || !data) return; - /* matrix coeff - convert S15.16 to S4.9 */ - val = ((data->csc_mv[0] >> CSC_MATRIX_SHIFT) & 0x1FFF) | - (((data->csc_mv[1] >> CSC_MATRIX_SHIFT) & 0x1FFF) << 16); + val = ((data->csc_mv[0] >> shift_bit) & 0x1FFF) | + (((data->csc_mv[1] >> shift_bit) & 0x1FFF) << 16); SDE_REG_WRITE(c, csc_reg_off, val); - val = ((data->csc_mv[2] >> CSC_MATRIX_SHIFT) & 0x1FFF) | - (((data->csc_mv[3] >> CSC_MATRIX_SHIFT) & 0x1FFF) << 16); + val = ((data->csc_mv[2] >> shift_bit) & 0x1FFF) | + (((data->csc_mv[3] >> shift_bit) & 0x1FFF) << 16); SDE_REG_WRITE(c, csc_reg_off + 0x4, val); - val = ((data->csc_mv[4] >> CSC_MATRIX_SHIFT) & 0x1FFF) | - (((data->csc_mv[5] >> CSC_MATRIX_SHIFT) & 0x1FFF) << 16); + val = ((data->csc_mv[4] >> shift_bit) & 0x1FFF) | + (((data->csc_mv[5] >> shift_bit) & 0x1FFF) << 16); SDE_REG_WRITE(c, csc_reg_off + 0x8, val); - val = ((data->csc_mv[6] >> CSC_MATRIX_SHIFT) & 0x1FFF) | - (((data->csc_mv[7] >> CSC_MATRIX_SHIFT) & 0x1FFF) << 16); + val = ((data->csc_mv[6] >> shift_bit) & 0x1FFF) | + (((data->csc_mv[7] >> shift_bit) & 0x1FFF) << 16); SDE_REG_WRITE(c, csc_reg_off + 0xc, val); - val = (data->csc_mv[8] >> CSC_MATRIX_SHIFT) & 0x1FFF; + val = (data->csc_mv[8] >> shift_bit) & 0x1FFF; SDE_REG_WRITE(c, csc_reg_off + 0x10, val); } @@ -407,7 +407,8 @@ void sde_hw_csc_setup(struct sde_hw_blk_reg_map *c, if (!c || !data) return; - sde_hw_csc_matrix_coeff_setup(c, csc_reg_off, data); + /* matrix coeff - convert S15.16 to S4.9 */ + sde_hw_csc_matrix_coeff_setup(c, csc_reg_off, data, CSC_MATRIX_SHIFT); /* Pre clamp */ val = (data->csc_pre_lv[0] << clamp_shift) | data->csc_pre_lv[1]; diff --git a/drivers/gpu/drm/msm/sde/sde_hw_util.h b/drivers/gpu/drm/msm/sde/sde_hw_util.h index bdcc25307ad8..d07a15b5e30b 100644 --- a/drivers/gpu/drm/msm/sde/sde_hw_util.h +++ b/drivers/gpu/drm/msm/sde/sde_hw_util.h @@ -189,7 +189,8 @@ u32 sde_hw_get_scaler3_ver(struct sde_hw_blk_reg_map *c, u32 scaler_offset); void sde_hw_csc_matrix_coeff_setup(struct sde_hw_blk_reg_map *c, - u32 csc_reg_off, struct sde_csc_cfg *data); + u32 csc_reg_off, struct sde_csc_cfg *data, + u32 shift_bit); void sde_hw_csc_setup(struct sde_hw_blk_reg_map *c, u32 csc_reg_off, -- GitLab From 5444d7a43275697d9c68099073dfc7b6af562176 Mon Sep 17 00:00:00 2001 From: Ping Li Date: Thu, 12 Apr 2018 14:06:46 -0700 Subject: [PATCH 0598/1635] drm/msm/sde: remove SSPP feature bits from SDE_PLANE_DIRTY_ALL Currently SDE_PLANE_DIRTY_ALL covers SSPP feature bits and it gets set in multiple cases in which we don't want SSPP features to be affected. This change removes SSPP feature bits from the SDE_PLANE_DIRTY_ALL. Change-Id: Ic56ea8d49bae9a1a18d5f40800c4c13f76a22103 Signed-off-by: Ping Li --- drivers/gpu/drm/msm/sde/sde_plane.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/msm/sde/sde_plane.h b/drivers/gpu/drm/msm/sde/sde_plane.h index acd7770524a2..5810cc44ef33 100644 --- a/drivers/gpu/drm/msm/sde/sde_plane.h +++ b/drivers/gpu/drm/msm/sde/sde_plane.h @@ -97,7 +97,10 @@ struct sde_plane_rot_state { #define SDE_PLANE_DIRTY_VIG_IGC 0x40 #define SDE_PLANE_DIRTY_DMA_IGC 0x80 #define SDE_PLANE_DIRTY_DMA_GC 0x100 -#define SDE_PLANE_DIRTY_ALL 0xFFFFFFFF +#define SDE_PLANE_DIRTY_CP (SDE_PLANE_DIRTY_VIG_GAMUT |\ + SDE_PLANE_DIRTY_VIG_IGC | SDE_PLANE_DIRTY_DMA_IGC |\ + SDE_PLANE_DIRTY_DMA_GC) +#define SDE_PLANE_DIRTY_ALL (0xFFFFFFFF & ~(SDE_PLANE_DIRTY_CP)) /** * enum sde_plane_sclcheck_state - User scaler data status -- GitLab From 5428ebbaca68d877034dc86a4b151127d36efc83 Mon Sep 17 00:00:00 2001 From: Ping Li Date: Thu, 7 Dec 2017 12:22:23 -0800 Subject: [PATCH 0599/1635] ARM: dts: msm: Add HDR support for dsi 4K panels Add chromaticity, peak brightness and blackness level information for 4K dsi panel for HDR support. Change-Id: I5a70e4754f49dc02db1284c7941ffa3a4f989fca Signed-off-by: Ping Li --- arch/arm64/boot/dts/qcom/dsi-panel-sharp-dsc-4k-cmd.dtsi | 5 +++++ arch/arm64/boot/dts/qcom/dsi-panel-sharp-dsc-4k-video.dtsi | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-sharp-dsc-4k-cmd.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-sharp-dsc-4k-cmd.dtsi index ce849c62e6cd..92897aee929e 100644 --- a/arch/arm64/boot/dts/qcom/dsi-panel-sharp-dsc-4k-cmd.dtsi +++ b/arch/arm64/boot/dts/qcom/dsi-panel-sharp-dsc-4k-cmd.dtsi @@ -39,6 +39,11 @@ qcom,dcs-cmd-by-left; qcom,mdss-dsi-tx-eot-append; qcom,adjust-timer-wakeup-ms = <1>; + qcom,mdss-dsi-panel-hdr-enabled; + qcom,mdss-dsi-panel-hdr-color-primaries = <14500 15500 32000 + 17000 15500 30000 8000 3000>; + qcom,mdss-dsi-panel-peak-brightness = <4200000>; + qcom,mdss-dsi-panel-blackness-level = <3230>; qcom,mdss-dsi-display-timings { timing@0{ diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-sharp-dsc-4k-video.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-sharp-dsc-4k-video.dtsi index d3411c8ac65c..9995fb3e79bc 100644 --- a/arch/arm64/boot/dts/qcom/dsi-panel-sharp-dsc-4k-video.dtsi +++ b/arch/arm64/boot/dts/qcom/dsi-panel-sharp-dsc-4k-video.dtsi @@ -33,6 +33,11 @@ qcom,mdss-dsi-tx-eot-append; qcom,adjust-timer-wakeup-ms = <1>; + qcom,mdss-dsi-panel-hdr-enabled; + qcom,mdss-dsi-panel-hdr-color-primaries = <14500 15500 32000 + 17000 15500 30000 8000 3000>; + qcom,mdss-dsi-panel-peak-brightness = <4200000>; + qcom,mdss-dsi-panel-blackness-level = <3230>; qcom,mdss-dsi-display-timings { timing@0{ -- GitLab From f0de11333f22c198f93b075c76ae0c7ce6eeb9b3 Mon Sep 17 00:00:00 2001 From: Karthikeyan Periasamy Date: Fri, 20 Apr 2018 15:05:50 -0700 Subject: [PATCH 0600/1635] msm: vidc: Debug message format to improve readability - Removed unwanted debug messages - Print FW message in one line CRs-Fixed: 2228683 Change-Id: Id87caca15eb7661ee6075ccbfcc017cc211f94fd Signed-off-by: Karthikeyan Periasamy --- drivers/media/platform/msm/vidc/msm_vidc_debug.h | 4 ++-- drivers/media/platform/msm/vidc/venus_hfi.c | 9 ++++++++- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/drivers/media/platform/msm/vidc/msm_vidc_debug.h b/drivers/media/platform/msm/vidc/msm_vidc_debug.h index d6cfda575b3c..2c0cce21f830 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc_debug.h +++ b/drivers/media/platform/msm/vidc/msm_vidc_debug.h @@ -73,8 +73,8 @@ extern bool msm_vidc_syscache_disable; } while (0) #define MSM_VIDC_ERROR(value) \ - do { \ - dprintk(VIDC_DBG, "BugOn"); \ + do { if (value) \ + dprintk(VIDC_DBG, "BugOn"); \ BUG_ON(value); \ } while (0) diff --git a/drivers/media/platform/msm/vidc/venus_hfi.c b/drivers/media/platform/msm/vidc/venus_hfi.c index 862328c065d5..3c6176a3ded3 100644 --- a/drivers/media/platform/msm/vidc/venus_hfi.c +++ b/drivers/media/platform/msm/vidc/venus_hfi.c @@ -3162,7 +3162,14 @@ static void __flush_debug_queue(struct venus_hfi_device *device, u8 *packet) } else { struct hfi_msg_sys_debug_packet *pkt = (struct hfi_msg_sys_debug_packet *) packet; - dprintk(log_level, "%s", pkt->rg_msg_data); + /* + * All fw messages starts with new line character. This + * causes dprintk to print this message in two lines + * in the kernel log. Ignoring the first character + * from the message fixes this to print it in a single + * line. + */ + dprintk(log_level, "%s", &pkt->rg_msg_data[1]); } } -- GitLab From a2201034951c5642c3e71f9199e3d39b06710c3b Mon Sep 17 00:00:00 2001 From: Puja Gupta Date: Fri, 20 Apr 2018 17:24:43 -0700 Subject: [PATCH 0601/1635] sched: Fix incorrect usage of SCHED_CPUFREQ_INTERCLUSTER_MIG flag Mark the source/destination CPUs correctly for inter cluster migration. Change-Id: I771b9357d20cb0270465abd594fb94bb3669c936 Signed-off-by: Pavankumar Kondeti Signed-off-by: Puja Gupta --- include/linux/sched/cpufreq.h | 3 ++- kernel/sched/sched.h | 4 +++- kernel/sched/walt.c | 25 ++++++++++++++++++++----- 3 files changed, 25 insertions(+), 7 deletions(-) diff --git a/include/linux/sched/cpufreq.h b/include/linux/sched/cpufreq.h index cd304cb07983..e0234142b2f2 100644 --- a/include/linux/sched/cpufreq.h +++ b/include/linux/sched/cpufreq.h @@ -15,7 +15,8 @@ #define SCHED_CPUFREQ_WALT (1U << 4) #define SCHED_CPUFREQ_PL (1U << 5) #define SCHED_CPUFREQ_EARLY_DET (1U << 6) -#define SCHED_CPUFREQ_CONTINUE (1U << 7) +#define SCHED_CPUFREQ_FORCE_UPDATE (1U << 7) +#define SCHED_CPUFREQ_CONTINUE (1U << 8) #define SCHED_CPUFREQ_RT_DL (SCHED_CPUFREQ_RT | SCHED_CPUFREQ_DL) diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h index 60ed50da5220..c3661044a33c 100644 --- a/kernel/sched/sched.h +++ b/kernel/sched/sched.h @@ -876,6 +876,7 @@ struct rq { u8 curr_table; int prev_top; int curr_top; + bool notif_pending; #endif /* CONFIG_SCHED_WALT */ #ifdef CONFIG_IRQ_TIME_ACCOUNTING @@ -2451,7 +2452,8 @@ static inline void cpufreq_update_util(struct rq *rq, unsigned int flags) #ifdef CONFIG_SCHED_WALT unsigned int exception_flags = SCHED_CPUFREQ_INTERCLUSTER_MIG | - SCHED_CPUFREQ_PL | SCHED_CPUFREQ_EARLY_DET; + SCHED_CPUFREQ_PL | SCHED_CPUFREQ_EARLY_DET | + SCHED_CPUFREQ_FORCE_UPDATE; /* * Skip if we've already reported, but not if this is an inter-cluster diff --git a/kernel/sched/walt.c b/kernel/sched/walt.c index 746d3a2c1d83..7c016b598e82 100644 --- a/kernel/sched/walt.c +++ b/kernel/sched/walt.c @@ -812,8 +812,11 @@ void fixup_busy_time(struct task_struct *p, int new_cpu) migrate_top_tasks(p, src_rq, dest_rq); - if (!same_freq_domain(new_cpu, task_cpu(p))) + if (!same_freq_domain(new_cpu, task_cpu(p))) { + src_rq->notif_pending = true; + dest_rq->notif_pending = true; irq_work_queue(&walt_migration_irq_work); + } if (p == src_rq->ed_task) { src_rq->ed_task = NULL; @@ -3051,11 +3054,11 @@ void walt_irq_work(struct irq_work *irq_work) struct rq *rq; int cpu; u64 wc; - int flag = SCHED_CPUFREQ_WALT; + bool is_migration = false; /* Am I the window rollover work or the migration work? */ if (irq_work == &walt_migration_irq_work) - flag |= SCHED_CPUFREQ_INTERCLUSTER_MIG; + is_migration = true; for_each_cpu(cpu, cpu_possible_mask) raw_spin_lock(&cpu_rq(cpu)->lock); @@ -3089,8 +3092,19 @@ void walt_irq_work(struct irq_work *irq_work) cpumask_and(&cluster_online_cpus, &cluster->cpus, cpu_online_mask); num_cpus = cpumask_weight(&cluster_online_cpus); - for_each_cpu(cpu, &cluster_online_cpus) { + int flag = SCHED_CPUFREQ_WALT; + + rq = cpu_rq(cpu); + + if (is_migration) { + if (rq->notif_pending) { + flag |= SCHED_CPUFREQ_INTERCLUSTER_MIG; + rq->notif_pending = false; + } else + flag |= SCHED_CPUFREQ_FORCE_UPDATE; + } + if (i == num_cpus) cpufreq_update_util(cpu_rq(cpu), flag); else @@ -3103,7 +3117,7 @@ void walt_irq_work(struct irq_work *irq_work) for_each_cpu(cpu, cpu_possible_mask) raw_spin_unlock(&cpu_rq(cpu)->lock); - if (irq_work != &walt_migration_irq_work) + if (!is_migration) core_ctl_check(this_rq()->window_start); } @@ -3199,6 +3213,7 @@ void walt_sched_init(struct rq *rq) clear_top_tasks_bitmap(rq->top_tasks_bitmap[j]); } rq->cum_window_demand = 0; + rq->notif_pending = false; walt_cpu_util_freq_divisor = (sched_ravg_window >> SCHED_CAPACITY_SHIFT) * 100; -- GitLab From 61760b0be333584661bb029f0d071dc9baa1d84a Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Wed, 18 Apr 2018 11:09:47 -0700 Subject: [PATCH 0602/1635] fscrypt: allow synchronous bio decryption Cherry-pick from origin/upstream-f2fs-stable-linux-4.14.y: fac0e4a8acde ("fscrypt: allow synchronous bio decryption") Currently, fscrypt provides fscrypt_decrypt_bio_pages() which decrypts a bio's pages asynchronously, then unlocks them afterwards. But, this assumes that decryption is the last "postprocessing step" for the bio, so it's incompatible with additional postprocessing steps such as authenticity verification after decryption. Therefore, rename the existing fscrypt_decrypt_bio_pages() to fscrypt_enqueue_decrypt_bio(). Then, add fscrypt_decrypt_bio() which decrypts the pages in the bio synchronously without unlocking the pages, nor setting them Uptodate; and add fscrypt_enqueue_decrypt_work(), which enqueues work on the fscrypt_read_workqueue. The new functions will be used by filesystems that support both fscrypt and fs-verity. Change-Id: I87514f59bcf1d2cec858bb44f6e27652ba0e93eb Signed-off-by: Eric Biggers Signed-off-by: Jaegeuk Kim --- fs/crypto/bio.c | 35 +++++++++++++++++++++------------ fs/crypto/crypto.c | 8 +++++++- fs/crypto/fscrypt_private.h | 1 - fs/ext4/readpage.c | 2 +- fs/f2fs/data.c | 2 +- include/linux/fscrypt_notsupp.h | 13 +++++++++--- include/linux/fscrypt_supp.h | 5 ++++- 7 files changed, 45 insertions(+), 21 deletions(-) diff --git a/fs/crypto/bio.c b/fs/crypto/bio.c index 0d5e6a569d58..0959044c5cee 100644 --- a/fs/crypto/bio.c +++ b/fs/crypto/bio.c @@ -26,15 +26,8 @@ #include #include "fscrypt_private.h" -/* - * Call fscrypt_decrypt_page on every single page, reusing the encryption - * context. - */ -static void completion_pages(struct work_struct *work) +static void __fscrypt_decrypt_bio(struct bio *bio, bool done) { - struct fscrypt_ctx *ctx = - container_of(work, struct fscrypt_ctx, r.work); - struct bio *bio = ctx->r.bio; struct bio_vec *bv; int i; @@ -46,22 +39,38 @@ static void completion_pages(struct work_struct *work) if (ret) { WARN_ON_ONCE(1); SetPageError(page); - } else { + } else if (done) { SetPageUptodate(page); } - unlock_page(page); + if (done) + unlock_page(page); } +} + +void fscrypt_decrypt_bio(struct bio *bio) +{ + __fscrypt_decrypt_bio(bio, false); +} +EXPORT_SYMBOL(fscrypt_decrypt_bio); + +static void completion_pages(struct work_struct *work) +{ + struct fscrypt_ctx *ctx = + container_of(work, struct fscrypt_ctx, r.work); + struct bio *bio = ctx->r.bio; + + __fscrypt_decrypt_bio(bio, true); fscrypt_release_ctx(ctx); bio_put(bio); } -void fscrypt_decrypt_bio_pages(struct fscrypt_ctx *ctx, struct bio *bio) +void fscrypt_enqueue_decrypt_bio(struct fscrypt_ctx *ctx, struct bio *bio) { INIT_WORK(&ctx->r.work, completion_pages); ctx->r.bio = bio; - queue_work(fscrypt_read_workqueue, &ctx->r.work); + fscrypt_enqueue_decrypt_work(&ctx->r.work); } -EXPORT_SYMBOL(fscrypt_decrypt_bio_pages); +EXPORT_SYMBOL(fscrypt_enqueue_decrypt_bio); void fscrypt_pullback_bio_page(struct page **page, bool restore) { diff --git a/fs/crypto/crypto.c b/fs/crypto/crypto.c index ce654526c0fb..0758d32ad01b 100644 --- a/fs/crypto/crypto.c +++ b/fs/crypto/crypto.c @@ -45,12 +45,18 @@ static mempool_t *fscrypt_bounce_page_pool = NULL; static LIST_HEAD(fscrypt_free_ctxs); static DEFINE_SPINLOCK(fscrypt_ctx_lock); -struct workqueue_struct *fscrypt_read_workqueue; +static struct workqueue_struct *fscrypt_read_workqueue; static DEFINE_MUTEX(fscrypt_init_mutex); static struct kmem_cache *fscrypt_ctx_cachep; struct kmem_cache *fscrypt_info_cachep; +void fscrypt_enqueue_decrypt_work(struct work_struct *work) +{ + queue_work(fscrypt_read_workqueue, work); +} +EXPORT_SYMBOL(fscrypt_enqueue_decrypt_work); + /** * fscrypt_release_ctx() - Releases an encryption context * @ctx: The encryption context to release. diff --git a/fs/crypto/fscrypt_private.h b/fs/crypto/fscrypt_private.h index ad6722bae8b7..4012558f6115 100644 --- a/fs/crypto/fscrypt_private.h +++ b/fs/crypto/fscrypt_private.h @@ -97,7 +97,6 @@ static inline bool fscrypt_valid_enc_modes(u32 contents_mode, /* crypto.c */ extern struct kmem_cache *fscrypt_info_cachep; extern int fscrypt_initialize(unsigned int cop_flags); -extern struct workqueue_struct *fscrypt_read_workqueue; extern int fscrypt_do_page_crypto(const struct inode *inode, fscrypt_direction_t rw, u64 lblk_num, struct page *src_page, diff --git a/fs/ext4/readpage.c b/fs/ext4/readpage.c index df22fcb3c41c..039aa698159a 100644 --- a/fs/ext4/readpage.c +++ b/fs/ext4/readpage.c @@ -92,7 +92,7 @@ static void mpage_end_io(struct bio *bio) if (bio->bi_status) { fscrypt_release_ctx(bio->bi_private); } else { - fscrypt_decrypt_bio_pages(bio->bi_private, bio); + fscrypt_enqueue_decrypt_bio(bio->bi_private, bio); return; } } diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c index b42e8d3539e8..2a7b8dcd07d1 100644 --- a/fs/f2fs/data.c +++ b/fs/f2fs/data.c @@ -67,7 +67,7 @@ static void f2fs_read_end_io(struct bio *bio) if (bio->bi_status) { fscrypt_release_ctx(bio->bi_private); } else { - fscrypt_decrypt_bio_pages(bio->bi_private, bio); + fscrypt_enqueue_decrypt_bio(bio->bi_private, bio); return; } } diff --git a/include/linux/fscrypt_notsupp.h b/include/linux/fscrypt_notsupp.h index 44b50c04bae9..9770be37c9d4 100644 --- a/include/linux/fscrypt_notsupp.h +++ b/include/linux/fscrypt_notsupp.h @@ -25,6 +25,10 @@ static inline bool fscrypt_dummy_context_enabled(struct inode *inode) } /* crypto.c */ +static inline void fscrypt_enqueue_decrypt_work(struct work_struct *work) +{ +} + static inline struct fscrypt_ctx *fscrypt_get_ctx(const struct inode *inode, gfp_t gfp_flags) { @@ -160,10 +164,13 @@ static inline bool fscrypt_match_name(const struct fscrypt_name *fname, } /* bio.c */ -static inline void fscrypt_decrypt_bio_pages(struct fscrypt_ctx *ctx, - struct bio *bio) +static inline void fscrypt_decrypt_bio(struct bio *bio) +{ +} + +static inline void fscrypt_enqueue_decrypt_bio(struct fscrypt_ctx *ctx, + struct bio *bio) { - return; } static inline void fscrypt_pullback_bio_page(struct page **page, bool restore) diff --git a/include/linux/fscrypt_supp.h b/include/linux/fscrypt_supp.h index 477a7a6504d2..2c9a86ac5e83 100644 --- a/include/linux/fscrypt_supp.h +++ b/include/linux/fscrypt_supp.h @@ -59,6 +59,7 @@ static inline bool fscrypt_dummy_context_enabled(struct inode *inode) } /* crypto.c */ +extern void fscrypt_enqueue_decrypt_work(struct work_struct *); extern struct fscrypt_ctx *fscrypt_get_ctx(const struct inode *, gfp_t); extern void fscrypt_release_ctx(struct fscrypt_ctx *); extern struct page *fscrypt_encrypt_page(const struct inode *, struct page *, @@ -188,7 +189,9 @@ static inline bool fscrypt_match_name(const struct fscrypt_name *fname, } /* bio.c */ -extern void fscrypt_decrypt_bio_pages(struct fscrypt_ctx *, struct bio *); +extern void fscrypt_decrypt_bio(struct bio *); +extern void fscrypt_enqueue_decrypt_bio(struct fscrypt_ctx *ctx, + struct bio *bio); extern void fscrypt_pullback_bio_page(struct page **, bool); extern int fscrypt_zeroout_range(const struct inode *, pgoff_t, sector_t, unsigned int); -- GitLab From c6e638ae452cc27fca4894022c2a3e53772cee2d Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Wed, 18 Apr 2018 11:09:48 -0700 Subject: [PATCH 0603/1635] f2fs: refactor read path to allow multiple postprocessing steps Cherry-pick from origin/upstream-f2fs-stable-linux-4.14.y: e1f299357c3e ("f2fs: refactor read path to allow multiple postprocessing steps") Currently f2fs's ->readpage() and ->readpages() assume that either the data undergoes no postprocessing, or decryption only. But with fs-verity, there will be an additional authenticity verification step, and it may be needed either by itself, or combined with decryption. To support this, store a 'struct bio_post_read_ctx' in ->bi_private which contains a work struct, a bitmask of postprocessing steps that are enabled, and an indicator of the current step. The bio completion routine, if there was no I/O error, enqueues the first postprocessing step. When that completes, it continues to the next step. Pages that fail any postprocessing step have PageError set. Once all steps have completed, pages without PageError set are set Uptodate, and all pages are unlocked. Also replace f2fs_encrypted_file() with a new function f2fs_post_read_required() in places like direct I/O and garbage collection that really should be testing whether the file needs special I/O processing, not whether it is encrypted specifically. This may also be useful for other future f2fs features such as compression. Change-Id: I8178e0fa7ae0171e5894b32a692cc8b1fb45a149 Signed-off-by: Eric Biggers Signed-off-by: Jaegeuk Kim --- fs/f2fs/data.c | 166 +++++++++++++++++++++++++++++++++++------------ fs/f2fs/f2fs.h | 12 +++- fs/f2fs/file.c | 4 +- fs/f2fs/gc.c | 6 +- fs/f2fs/inline.c | 2 +- fs/f2fs/super.c | 6 ++ 6 files changed, 147 insertions(+), 49 deletions(-) diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c index 2a7b8dcd07d1..072a1cf1ee13 100644 --- a/fs/f2fs/data.c +++ b/fs/f2fs/data.c @@ -31,6 +31,11 @@ #include #include +#define NUM_PREALLOC_POST_READ_CTXS 128 + +static struct kmem_cache *bio_post_read_ctx_cache; +static mempool_t *bio_post_read_ctx_pool; + static bool __is_cp_guaranteed(struct page *page) { struct address_space *mapping = page->mapping; @@ -51,11 +56,77 @@ static bool __is_cp_guaranteed(struct page *page) return false; } -static void f2fs_read_end_io(struct bio *bio) +/* postprocessing steps for read bios */ +enum bio_post_read_step { + STEP_INITIAL = 0, + STEP_DECRYPT, +}; + +struct bio_post_read_ctx { + struct bio *bio; + struct work_struct work; + unsigned int cur_step; + unsigned int enabled_steps; +}; + +static void __read_end_io(struct bio *bio) { - struct bio_vec *bvec; + struct page *page; + struct bio_vec *bv; int i; + bio_for_each_segment_all(bv, bio, i) { + page = bv->bv_page; + + /* PG_error was set if any post_read step failed */ + if (bio->bi_status || PageError(page)) { + ClearPageUptodate(page); + SetPageError(page); + } else { + SetPageUptodate(page); + } + unlock_page(page); + } + if (bio->bi_private) + mempool_free(bio->bi_private, bio_post_read_ctx_pool); + bio_put(bio); +} + +static void bio_post_read_processing(struct bio_post_read_ctx *ctx); + +static void decrypt_work(struct work_struct *work) +{ + struct bio_post_read_ctx *ctx = + container_of(work, struct bio_post_read_ctx, work); + + fscrypt_decrypt_bio(ctx->bio); + + bio_post_read_processing(ctx); +} + +static void bio_post_read_processing(struct bio_post_read_ctx *ctx) +{ + switch (++ctx->cur_step) { + case STEP_DECRYPT: + if (ctx->enabled_steps & (1 << STEP_DECRYPT)) { + INIT_WORK(&ctx->work, decrypt_work); + fscrypt_enqueue_decrypt_work(&ctx->work); + return; + } + ctx->cur_step++; + /* fall-through */ + default: + __read_end_io(ctx->bio); + } +} + +static bool f2fs_bio_post_read_required(struct bio *bio) +{ + return bio->bi_private && !bio->bi_status; +} + +static void f2fs_read_end_io(struct bio *bio) +{ #ifdef CONFIG_F2FS_FAULT_INJECTION if (time_to_inject(F2FS_P_SB(bio->bi_io_vec->bv_page), FAULT_IO)) { f2fs_show_injection_info(FAULT_IO); @@ -63,28 +134,15 @@ static void f2fs_read_end_io(struct bio *bio) } #endif - if (f2fs_bio_encrypted(bio)) { - if (bio->bi_status) { - fscrypt_release_ctx(bio->bi_private); - } else { - fscrypt_enqueue_decrypt_bio(bio->bi_private, bio); - return; - } - } - - bio_for_each_segment_all(bvec, bio, i) { - struct page *page = bvec->bv_page; + if (f2fs_bio_post_read_required(bio)) { + struct bio_post_read_ctx *ctx = bio->bi_private; - if (!bio->bi_status) { - if (!PageUptodate(page)) - SetPageUptodate(page); - } else { - ClearPageUptodate(page); - SetPageError(page); - } - unlock_page(page); + ctx->cur_step = STEP_INITIAL; + bio_post_read_processing(ctx); + return; } - bio_put(bio); + + __read_end_io(bio); } static void f2fs_write_end_io(struct bio *bio) @@ -482,29 +540,33 @@ static struct bio *f2fs_grab_read_bio(struct inode *inode, block_t blkaddr, unsigned nr_pages) { struct f2fs_sb_info *sbi = F2FS_I_SB(inode); - struct fscrypt_ctx *ctx = NULL; struct bio *bio; - - if (f2fs_encrypted_file(inode)) { - ctx = fscrypt_get_ctx(inode, GFP_NOFS); - if (IS_ERR(ctx)) - return ERR_CAST(ctx); - - /* wait the page to be moved by cleaning */ - f2fs_wait_on_block_writeback(sbi, blkaddr); - } + struct bio_post_read_ctx *ctx; + unsigned int post_read_steps = 0; bio = f2fs_bio_alloc(sbi, min_t(int, nr_pages, BIO_MAX_PAGES), false); - if (!bio) { - if (ctx) - fscrypt_release_ctx(ctx); + if (!bio) return ERR_PTR(-ENOMEM); - } f2fs_target_device(sbi, blkaddr, bio); bio->bi_end_io = f2fs_read_end_io; - bio->bi_private = ctx; bio_set_op_attrs(bio, REQ_OP_READ, 0); + if (f2fs_encrypted_file(inode)) + post_read_steps |= 1 << STEP_DECRYPT; + if (post_read_steps) { + ctx = mempool_alloc(bio_post_read_ctx_pool, GFP_NOFS); + if (!ctx) { + bio_put(bio); + return ERR_PTR(-ENOMEM); + } + ctx->bio = bio; + ctx->enabled_steps = post_read_steps; + bio->bi_private = ctx; + + /* wait the page to be moved by cleaning */ + f2fs_wait_on_block_writeback(sbi, blkaddr); + } + return bio; } @@ -1526,7 +1588,7 @@ static int encrypt_one_page(struct f2fs_io_info *fio) if (!f2fs_encrypted_file(inode)) return 0; - /* wait for GCed encrypted page writeback */ + /* wait for GCed page writeback via META_MAPPING */ f2fs_wait_on_block_writeback(fio->sbi, fio->old_blkaddr); retry_encrypt: @@ -2238,8 +2300,8 @@ static int f2fs_write_begin(struct file *file, struct address_space *mapping, f2fs_wait_on_page_writeback(page, DATA, false); - /* wait for GCed encrypted page writeback */ - if (f2fs_encrypted_file(inode)) + /* wait for GCed page writeback via META_MAPPING */ + if (f2fs_post_read_required(inode)) f2fs_wait_on_block_writeback(sbi, blkaddr); if (len == PAGE_SIZE || PageUptodate(page)) @@ -2600,3 +2662,27 @@ const struct address_space_operations f2fs_dblock_aops = { .migratepage = f2fs_migrate_page, #endif }; + +int __init f2fs_init_post_read_processing(void) +{ + bio_post_read_ctx_cache = KMEM_CACHE(bio_post_read_ctx, 0); + if (!bio_post_read_ctx_cache) + goto fail; + bio_post_read_ctx_pool = + mempool_create_slab_pool(NUM_PREALLOC_POST_READ_CTXS, + bio_post_read_ctx_cache); + if (!bio_post_read_ctx_pool) + goto fail_free_cache; + return 0; + +fail_free_cache: + kmem_cache_destroy(bio_post_read_ctx_cache); +fail: + return -ENOMEM; +} + +void __exit f2fs_destroy_post_read_processing(void) +{ + mempool_destroy(bio_post_read_ctx_pool); + kmem_cache_destroy(bio_post_read_ctx_cache); +} diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index 1df7f10476d6..ea92c18db624 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -2858,6 +2858,8 @@ void destroy_checkpoint_caches(void); /* * data.c */ +int f2fs_init_post_read_processing(void); +void f2fs_destroy_post_read_processing(void); void f2fs_submit_merged_write(struct f2fs_sb_info *sbi, enum page_type type); void f2fs_submit_merged_write_cond(struct f2fs_sb_info *sbi, struct inode *inode, nid_t ino, pgoff_t idx, @@ -3218,9 +3220,13 @@ static inline void f2fs_set_encrypted_inode(struct inode *inode) #endif } -static inline bool f2fs_bio_encrypted(struct bio *bio) +/* + * Returns true if the reads of the inode's data need to undergo some + * postprocessing step, like decryption or authenticity verification. + */ +static inline bool f2fs_post_read_required(struct inode *inode) { - return bio->bi_private != NULL; + return f2fs_encrypted_file(inode); } #define F2FS_FEATURE_FUNCS(name, flagname) \ @@ -3288,7 +3294,7 @@ static inline bool f2fs_may_encrypt(struct inode *inode) static inline bool f2fs_force_buffered_io(struct inode *inode, int rw) { - return (f2fs_encrypted_file(inode) || + return (f2fs_post_read_required(inode) || (rw == WRITE && test_opt(F2FS_I_SB(inode), LFS)) || F2FS_I_SB(inode)->s_ndevs); } diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c index cc88981fbe28..cb231b004e61 100644 --- a/fs/f2fs/file.c +++ b/fs/f2fs/file.c @@ -110,8 +110,8 @@ static int f2fs_vm_page_mkwrite(struct vm_fault *vmf) /* fill the page */ f2fs_wait_on_page_writeback(page, DATA, false); - /* wait for GCed encrypted page writeback */ - if (f2fs_encrypted_file(inode)) + /* wait for GCed page writeback via META_MAPPING */ + if (f2fs_post_read_required(inode)) f2fs_wait_on_block_writeback(sbi, dn.data_blkaddr); out_sem: diff --git a/fs/f2fs/gc.c b/fs/f2fs/gc.c index 0ad8b3a7a74d..604d3fcb8957 100644 --- a/fs/f2fs/gc.c +++ b/fs/f2fs/gc.c @@ -850,8 +850,8 @@ static void gc_data_segment(struct f2fs_sb_info *sbi, struct f2fs_summary *sum, if (IS_ERR(inode) || is_bad_inode(inode)) continue; - /* if encrypted inode, let's go phase 3 */ - if (f2fs_encrypted_file(inode)) { + /* if inode uses special I/O path, let's go phase 3 */ + if (f2fs_post_read_required(inode)) { add_gc_inode(gc_list, inode); continue; } @@ -899,7 +899,7 @@ static void gc_data_segment(struct f2fs_sb_info *sbi, struct f2fs_summary *sum, start_bidx = start_bidx_of_node(nofs, inode) + ofs_in_node; - if (f2fs_encrypted_file(inode)) + if (f2fs_post_read_required(inode)) move_data_block(inode, start_bidx, segno, off); else move_data_page(inode, start_bidx, gc_type, diff --git a/fs/f2fs/inline.c b/fs/f2fs/inline.c index 1925814ac675..26832e778233 100644 --- a/fs/f2fs/inline.c +++ b/fs/f2fs/inline.c @@ -26,7 +26,7 @@ bool f2fs_may_inline_data(struct inode *inode) if (i_size_read(inode) > MAX_INLINE_DATA(inode)) return false; - if (f2fs_encrypted_file(inode)) + if (f2fs_post_read_required(inode)) return false; return true; diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c index 2717c9c5fdf4..7cbddecdf41f 100644 --- a/fs/f2fs/super.c +++ b/fs/f2fs/super.c @@ -3092,8 +3092,13 @@ static int __init init_f2fs_fs(void) err = f2fs_create_root_stats(); if (err) goto free_filesystem; + err = f2fs_init_post_read_processing(); + if (err) + goto free_root_stats; return 0; +free_root_stats: + f2fs_destroy_root_stats(); free_filesystem: unregister_filesystem(&f2fs_fs_type); free_shrinker: @@ -3116,6 +3121,7 @@ static int __init init_f2fs_fs(void) static void __exit exit_f2fs_fs(void) { + f2fs_destroy_post_read_processing(); f2fs_destroy_root_stats(); unregister_filesystem(&f2fs_fs_type); unregister_shrinker(&f2fs_shrinker_info); -- GitLab From b84f60104105155e456a2341ce19337021c12c5e Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Wed, 18 Apr 2018 15:48:42 -0700 Subject: [PATCH 0604/1635] f2fs: call unlock_new_inode() before d_instantiate() Cherry-pick from origin/upstream-f2fs-stable-linux-4.14.y: b9a28b16e93d ("f2fs: call unlock_new_inode() before d_instantiate()") xfstest generic/429 sometimes hangs on f2fs, caused by a thread being unable to take a directory's i_rwsem for write in vfs_rmdir(). In the test, one thread repeatedly creates and removes a directory, and other threads repeatedly look up a file in the directory. The bug is that f2fs_mkdir() calls d_instantiate() before unlock_new_inode(), resulting in the directory inode being exposed to lookups before it has been fully initialized. And with CONFIG_DEBUG_LOCK_ALLOC, unlock_new_inode() reinitializes ->i_rwsem, corrupting its state when it is already held. Fix it by calling unlock_new_inode() before d_instantiate(). This matches what other filesystems do. Fixes: 57397d86c62d ("f2fs: add inode operations for special inodes") Change-Id: I908ef971703907f9903e75071694595a8742601d Signed-off-by: Eric Biggers Signed-off-by: Jaegeuk Kim --- fs/f2fs/namei.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/fs/f2fs/namei.c b/fs/f2fs/namei.c index d5098efe577c..3a7ed962d2f7 100644 --- a/fs/f2fs/namei.c +++ b/fs/f2fs/namei.c @@ -294,8 +294,8 @@ static int f2fs_create(struct inode *dir, struct dentry *dentry, umode_t mode, alloc_nid_done(sbi, ino); - d_instantiate(dentry, inode); unlock_new_inode(inode); + d_instantiate(dentry, inode); if (IS_DIRSYNC(dir)) f2fs_sync_fs(sbi->sb, 1); @@ -597,8 +597,8 @@ static int f2fs_symlink(struct inode *dir, struct dentry *dentry, err = page_symlink(inode, disk_link.name, disk_link.len); err_out: - d_instantiate(dentry, inode); unlock_new_inode(inode); + d_instantiate(dentry, inode); /* * Let's flush symlink data in order to avoid broken symlink as much as @@ -661,8 +661,8 @@ static int f2fs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) alloc_nid_done(sbi, inode->i_ino); - d_instantiate(dentry, inode); unlock_new_inode(inode); + d_instantiate(dentry, inode); if (IS_DIRSYNC(dir)) f2fs_sync_fs(sbi->sb, 1); @@ -713,8 +713,8 @@ static int f2fs_mknod(struct inode *dir, struct dentry *dentry, alloc_nid_done(sbi, inode->i_ino); - d_instantiate(dentry, inode); unlock_new_inode(inode); + d_instantiate(dentry, inode); if (IS_DIRSYNC(dir)) f2fs_sync_fs(sbi->sb, 1); -- GitLab From 51d5b4b87d69dcbca05b45e29c93cc14eab776b0 Mon Sep 17 00:00:00 2001 From: Fenglin Wu Date: Mon, 4 Dec 2017 09:56:51 +0800 Subject: [PATCH 0605/1635] pwm: Add different PWM output types support Normally, PWM channel has fixed output until software request to change its settings. There are some PWM devices which their outputs could be changed autonomously according to a predefined pattern programmed in hardware. Add pwm_output_type enum type to identify these two different PWM types and add relevant helper functions to set and get PWM output types and pattern. Change-Id: Ia1f914a45ab4f4dd7be037a395eeb89d0e65a80e Signed-off-by: Fenglin Wu --- drivers/pwm/core.c | 26 +++++++++++++++++ drivers/pwm/sysfs.c | 50 ++++++++++++++++++++++++++++++++ include/linux/pwm.h | 70 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 146 insertions(+) diff --git a/drivers/pwm/core.c b/drivers/pwm/core.c index 1581f6ab1b1f..89ff9991cc1e 100644 --- a/drivers/pwm/core.c +++ b/drivers/pwm/core.c @@ -294,6 +294,7 @@ int pwmchip_add_with_polarity(struct pwm_chip *chip, pwm->pwm = chip->base + i; pwm->hwpwm = i; pwm->state.polarity = polarity; + pwm->state.output_type = PWM_OUTPUT_FIXED; if (chip->ops->get_state) chip->ops->get_state(chip, pwm, &pwm->state); @@ -507,6 +508,31 @@ int pwm_apply_state(struct pwm_device *pwm, struct pwm_state *state) pwm->state.polarity = state->polarity; } + if (state->output_type != pwm->state.output_type) { + if (!pwm->chip->ops->set_output_type) + return -ENOTSUPP; + + err = pwm->chip->ops->set_output_type(pwm->chip, pwm, + state->output_type); + if (err) + return err; + + pwm->state.output_type = state->output_type; + } + + if (state->output_pattern != pwm->state.output_pattern && + state->output_pattern != NULL) { + if (!pwm->chip->ops->set_output_pattern) + return -ENOTSUPP; + + err = pwm->chip->ops->set_output_pattern(pwm->chip, + pwm, state->output_pattern); + if (err) + return err; + + pwm->state.output_pattern = state->output_pattern; + } + if (state->period != pwm->state.period || state->duty_cycle != pwm->state.duty_cycle) { err = pwm->chip->ops->config(pwm->chip, pwm, diff --git a/drivers/pwm/sysfs.c b/drivers/pwm/sysfs.c index a813239300c3..ea2b53d17199 100644 --- a/drivers/pwm/sysfs.c +++ b/drivers/pwm/sysfs.c @@ -223,11 +223,60 @@ static ssize_t capture_show(struct device *child, return sprintf(buf, "%u %u\n", result.period, result.duty_cycle); } +static ssize_t output_type_show(struct device *child, + struct device_attribute *attr, + char *buf) +{ + const struct pwm_device *pwm = child_to_pwm_device(child); + const char *output_type = "unknown"; + struct pwm_state state; + + pwm_get_state(pwm, &state); + switch (state.output_type) { + case PWM_OUTPUT_FIXED: + output_type = "fixed"; + break; + case PWM_OUTPUT_MODULATED: + output_type = "modulated"; + break; + default: + break; + } + + return snprintf(buf, PAGE_SIZE, "%s\n", output_type); +} + +static ssize_t output_type_store(struct device *child, + struct device_attribute *attr, + const char *buf, size_t size) +{ + struct pwm_export *export = child_to_pwm_export(child); + struct pwm_device *pwm = export->pwm; + struct pwm_state state; + int ret = -EINVAL; + + mutex_lock(&export->lock); + pwm_get_state(pwm, &state); + if (sysfs_streq(buf, "fixed")) + state.output_type = PWM_OUTPUT_FIXED; + else if (sysfs_streq(buf, "modulated")) + state.output_type = PWM_OUTPUT_MODULATED; + else + goto unlock; + + ret = pwm_apply_state(pwm, &state); +unlock: + mutex_unlock(&export->lock); + + return ret ? : size; +} + static DEVICE_ATTR_RW(period); static DEVICE_ATTR_RW(duty_cycle); static DEVICE_ATTR_RW(enable); static DEVICE_ATTR_RW(polarity); static DEVICE_ATTR_RO(capture); +static DEVICE_ATTR_RW(output_type); static struct attribute *pwm_attrs[] = { &dev_attr_period.attr, @@ -235,6 +284,7 @@ static struct attribute *pwm_attrs[] = { &dev_attr_enable.attr, &dev_attr_polarity.attr, &dev_attr_capture.attr, + &dev_attr_output_type.attr, NULL }; ATTRIBUTE_GROUPS(pwm); diff --git a/include/linux/pwm.h b/include/linux/pwm.h index 56518adc31dd..e0e5bf8a33df 100644 --- a/include/linux/pwm.h +++ b/include/linux/pwm.h @@ -48,6 +48,29 @@ enum { PWMF_EXPORTED = 1 << 1, }; +/** + * enum pwm_output_type - output type of the PWM signal + * @PWM_OUTPUT_FIXED: PWM output is fixed until a change request + * @PWM_OUTPUT_MODULATED: PWM output is modulated in hardware + * autonomously with a predefined pattern + */ +enum pwm_output_type { + PWM_OUTPUT_FIXED = 1 << 0, + PWM_OUTPUT_MODULATED = 1 << 1, +}; + +/** + * struct pwm_output_pattern - PWM duty pattern for MODULATED duty type + * @duty_pattern: PWM duty cycles in the pattern for duty modulation + * @num_entries: number of entries in the pattern + * @cycles_per_duty: number of PWM period cycles an entry stays at + */ +struct pwm_output_pattern { + unsigned int *duty_pattern; + unsigned int num_entries; + unsigned int cycles_per_duty; +}; + /* * struct pwm_state - state of a PWM channel * @period: PWM period (in nanoseconds) @@ -59,6 +82,8 @@ struct pwm_state { unsigned int period; unsigned int duty_cycle; enum pwm_polarity polarity; + enum pwm_output_type output_type; + struct pwm_output_pattern *output_pattern; bool enabled; }; @@ -144,6 +169,26 @@ static inline enum pwm_polarity pwm_get_polarity(const struct pwm_device *pwm) return state.polarity; } +static inline enum pwm_output_type pwm_get_output_type( + const struct pwm_device *pwm) +{ + struct pwm_state state; + + pwm_get_state(pwm, &state); + + return state.output_type; +} + +static inline struct pwm_output_pattern *pwm_get_output_pattern( + struct pwm_device *pwm) +{ + struct pwm_state state; + + pwm_get_state(pwm, &state); + + return pwm->state.output_pattern ?: NULL; +} + static inline void pwm_get_args(const struct pwm_device *pwm, struct pwm_args *args) { @@ -247,6 +292,9 @@ pwm_set_relative_duty_cycle(struct pwm_state *state, unsigned int duty_cycle, * @capture: capture and report PWM signal * @enable: enable PWM output toggling * @disable: disable PWM output toggling + * @get_output_type_supported: get the supported output type + * @set_output_type: set PWM output type + * @set_output_pattern: set the pattern for the modulated output * @apply: atomically apply a new PWM config. The state argument * should be adjusted with the real hardware config (if the * approximate the period or duty_cycle value, state should @@ -268,6 +316,13 @@ struct pwm_ops { struct pwm_capture *result, unsigned long timeout); int (*enable)(struct pwm_chip *chip, struct pwm_device *pwm); void (*disable)(struct pwm_chip *chip, struct pwm_device *pwm); + int (*get_output_type_supported)(struct pwm_chip *chip, + struct pwm_device *pwm); + int (*set_output_type)(struct pwm_chip *chip, struct pwm_device *pwm, + enum pwm_output_type output_type); + int (*set_output_pattern)(struct pwm_chip *chip, + struct pwm_device *pwm, + struct pwm_output_pattern *output_pattern); int (*apply)(struct pwm_chip *chip, struct pwm_device *pwm, struct pwm_state *state); void (*get_state)(struct pwm_chip *chip, struct pwm_device *pwm, @@ -320,6 +375,21 @@ void pwm_free(struct pwm_device *pwm); int pwm_apply_state(struct pwm_device *pwm, struct pwm_state *state); int pwm_adjust_config(struct pwm_device *pwm); +/** + * pwm_output_type_support() + * @pwm: PWM device + * + * Returns: output types supported by the PWM device + */ +static inline int pwm_get_output_type_supported(struct pwm_device *pwm) +{ + if (pwm->chip->ops->get_output_type_supported != NULL) + return pwm->chip->ops-> + get_output_type_supported(pwm->chip, pwm); + else + return PWM_OUTPUT_FIXED; +} + /** * pwm_config() - change a PWM device configuration * @pwm: PWM device -- GitLab From f1006f325117bfe66f6fcdf9857b36560d7837cc Mon Sep 17 00:00:00 2001 From: Fenglin Wu Date: Tue, 3 Apr 2018 08:51:39 +0800 Subject: [PATCH 0606/1635] pwm: pwm-qti-lpg: Add LUT mode to support modulated PWM output LPG module supports outputting the pattern programmed in Look-up table (LUT) in addition to supporting PWM output. Add support for configuring LPG to operate in LUT mode and configure LUT patterns per LPG channel. Change-Id: I6352af136c4916f8b6bc17f1b8374ce1d421c10b Signed-off-by: Fenglin Wu --- .../devicetree/bindings/pwm/pwm-qti-lpg.txt | 125 +++- drivers/pwm/pwm-qti-lpg.c | 646 +++++++++++++++++- 2 files changed, 734 insertions(+), 37 deletions(-) diff --git a/Documentation/devicetree/bindings/pwm/pwm-qti-lpg.txt b/Documentation/devicetree/bindings/pwm/pwm-qti-lpg.txt index 3174ccb0fd2d..ddd90e134a16 100644 --- a/Documentation/devicetree/bindings/pwm/pwm-qti-lpg.txt +++ b/Documentation/devicetree/bindings/pwm/pwm-qti-lpg.txt @@ -11,26 +11,137 @@ device module in Qualcomm Technologies, Inc. PMIC chips. - reg: Usage: required Value type: - Definition: Register base and length for LPG modules. The length - varies based on the number of channels available in - the PMIC chips. + Definition: Register base and length for LPG and LUT modules. LPG size + or length available per channel varies depending on the + number of channels in PMIC. - reg-names: Usage: required Value type: Definition: The name of the register defined in the reg property. - It must be "lpg-base". + It must have "lpg-base", "lut-base" is optional but + it's required if any LPG channels support LUT mode. - #pwm-cells: Usage: required Value type: - Definition: See Documentation/devicetree/bindings/pwm/pwm.txt; + Definition: The number of cells in "pwms" property specified in + PWM user nodes. It should be 2. The first cell is + the PWM channel ID indexed from 0, and the second + cell is the PWM default period in nanoseconds. +- qcom,lut-patterns: + Usage: optional + Value type: + Definition: Duty ratios in percentages for LPG working at LUT mode. + These duty ratios will be translated into PWM values + and stored in LUT module. The LUT module has resource + to store 47 PWM values at max and shared for all LPG + channels. This property is required if any LPG channels + support LUT mode. + +Subnode is optional if LUT mode is not required, it's required if any LPG +channels expected to be supported in LUT mode. + +Subnode properties: +Subnodes for each LPG channel (lpg@X) can be defined if any of the following +parameters needs to be configured for that channel. + +- qcom,lpg-chan-id: + Usage: required + Value type: + Definition: The LPG channel's hardware ID indexed from 1. Allowed + range is 1 - 8. Maximum value depends on the number of + channels supported on PMIC. + +- qcom,ramp-step-ms: + Usage: required + Value type: + Definition: The step duration in milliseconds for LPG staying at each + duty specified in the LUT pattern. Allowed range is + 1 - 511. + +- qcom,ramp-high-index: + Usage: required + Value type: + Definition: The high index of the LUT pattern where LPG ends up + ramping to. Allowed range is 1 - 47. + +- qcom,ramp-low-index: + Usage: required + Value type: + Definition: The low index of the LUT pattern from where LPG begins + ramping from. Allowed range is 0 - 46. + +- qcom,ramp-from-low-to-high: + Usage: optional + Value type: + Definition: The flag to specify the LPG ramping direction. The ramping + direction is from low index to high index of the LUT + pattern if it's specified. + +- qcom,ramp-pattern-repeat: + Usage: optional + Value type: + Definition: The flag to specify if LPG would be ramping with the LUT + pattern repeatedly. + +- qcom,ramp-toggle: + Usage: optional + Value type: + Definition: The flag to specify if LPG would toggle the LUT pattern + in ramping. If toggling enabled, LPG would return to the + low index when high index is reached, or return to the high + index when low index is reached. + +- qcom,ramp-pause-hi-count: + Usage: optional + Value type: + Definition: The step count that LPG stop the output when it ramped up + to the high index of the LUT. + +- qcom,ramp-pause-lo-count: + Usage: optional + Value type: + Definition: The step count that LPG stop the output when it ramped up + to the low index of the LUT. Example: pmi8998_lpg: lpg@b100 { compatible = "qcom,pwm-lpg"; - reg = <0xb100 0x600>; - reg-names = "lpg-base"; + reg = <0xb100 0x600>, <0xb000 0x100>; + reg-names = "lpg-base", "lut-base"; #pwm-cells = <2>; + qcom,lut-patterns = <0 14 28 42 56 70 84 100 + 100 84 70 56 42 28 14 0>; + lpg@3 { + qcom,lpg-chan-id = <3>; + qcom,ramp-step-ms = <200>; + qcom,ramp-pause-hi-count = <10>; + qcom,ramp-pause-lo-count = <10>; + qcom,ramp-low-index = <0>; + qcom,ramp-high-index = <15>; + qcom,ramp-from-low-to-high; + qcom,ramp-pattern-repeat; + }; + lpg@4 { + qcom,lpg-chan-id = <4>; + qcom,ramp-step-ms = <200>; + qcom,ramp-pause-hi-count = <10>; + qcom,ramp-pause-lo-count = <10>; + qcom,ramp-low-index = <0>; + qcom,ramp-high-index = <15>; + qcom,ramp-from-low-to-high; + qcom,ramp-pattern-repeat; + }; + lpg@5 { + qcom,lpg-chan-id = <5>; + qcom,ramp-step-ms = <200>; + qcom,ramp-pause-hi-count = <10>; + qcom,ramp-pause-lo-count = <10>; + qcom,ramp-low-index = <0>; + qcom,ramp-high-index = <15>; + qcom,ramp-from-low-to-high; + qcom,ramp-pattern-repeat; + }; }; diff --git a/drivers/pwm/pwm-qti-lpg.c b/drivers/pwm/pwm-qti-lpg.c index d31a18d8142b..aca41a8d5b9c 100644 --- a/drivers/pwm/pwm-qti-lpg.c +++ b/drivers/pwm/pwm-qti-lpg.c @@ -24,11 +24,16 @@ #include #include #include +#include #include #define REG_SIZE_PER_LPG 0x100 +#define LPG_BASE "lpg-base" +#define LUT_BASE "lut-base" +/* LPG module registers */ #define REG_LPG_PERPH_SUBTYPE 0x05 +#define REG_LPG_PATTERN_CONFIG 0x40 #define REG_LPG_PWM_SIZE_CLK 0x41 #define REG_LPG_PWM_FREQ_PREDIV_CLK 0x42 #define REG_LPG_PWM_TYPE_CONFIG 0x43 @@ -36,16 +41,29 @@ #define REG_LPG_PWM_VALUE_MSB 0x45 #define REG_LPG_ENABLE_CONTROL 0x46 #define REG_LPG_PWM_SYNC 0x47 +#define REG_LPG_RAMP_STEP_DURATION_LSB 0x50 +#define REG_LPG_RAMP_STEP_DURATION_MSB 0x51 +#define REG_LPG_PAUSE_HI_MULTIPLIER 0x52 +#define REG_LPG_PAUSE_LO_MULTIPLIER 0x54 +#define REG_LPG_HI_INDEX 0x56 +#define REG_LPG_LO_INDEX 0x57 + +/* REG_LPG_PATTERN_CONFIG */ +#define LPG_PATTERN_EN_PAUSE_LO BIT(0) +#define LPG_PATTERN_EN_PAUSE_HI BIT(1) +#define LPG_PATTERN_RAMP_TOGGLE BIT(2) +#define LPG_PATTERN_REPEAT BIT(3) +#define LPG_PATTERN_RAMP_LO_TO_HI BIT(4) /* REG_LPG_PERPH_SUBTYPE */ #define SUBTYPE_PWM 0x0b #define SUBTYPE_LPG_LITE 0x11 /* REG_LPG_PWM_SIZE_CLK */ -#define LPG_PWM_SIZE_MASK_LPG BIT(4) -#define LPG_PWM_SIZE_MASK_PWM BIT(2) -#define LPG_PWM_SIZE_SHIFT_LPG 4 -#define LPG_PWM_SIZE_SHIFT_PWM 2 +#define LPG_PWM_SIZE_LPG_MASK BIT(4) +#define LPG_PWM_SIZE_PWM_MASK BIT(2) +#define LPG_PWM_SIZE_LPG_SHIFT 4 +#define LPG_PWM_SIZE_PWM_SHIFT 2 #define LPG_PWM_CLK_FREQ_SEL_MASK GENMASK(1, 0) /* REG_LPG_PWM_FREQ_PREDIV_CLK */ @@ -64,6 +82,7 @@ /* REG_LPG_ENABLE_CONTROL */ #define LPG_EN_LPG_OUT_BIT BIT(7) +#define LPG_EN_LPG_OUT_SHIFT 7 #define LPG_PWM_SRC_SELECT_MASK BIT(2) #define LPG_PWM_SRC_SELECT_SHIFT 2 #define LPG_EN_RAMP_GEN_MASK BIT(1) @@ -77,9 +96,18 @@ #define NUM_CLK_PREDIV 4 #define NUM_PWM_EXP 8 -enum { +#define LPG_HI_LO_IDX_MASK GENMASK(5, 0) + +/* LUT module registers */ +#define REG_LPG_LUT_1_LSB 0x42 +#define REG_LPG_LUT_RAMP_CONTROL 0xc8 + +#define LPG_LUT_VALUE_MSB_MASK BIT(0) +#define LPG_LUT_COUNT_MAX 47 + +enum lpg_src { LUT_PATTERN = 0, - PWM_OUTPUT, + PWM_VALUE, }; static const int pwm_size[NUM_PWM_SIZE] = {6, 9}; @@ -87,6 +115,19 @@ static const int clk_freq_hz[NUM_PWM_CLK] = {1024, 32768, 19200000}; static const int clk_prediv[NUM_CLK_PREDIV] = {1, 3, 5, 6}; static const int pwm_exponent[NUM_PWM_EXP] = {0, 1, 2, 3, 4, 5, 6, 7}; +struct lpg_ramp_config { + u16 step_ms; + u8 pause_hi_count; + u8 pause_lo_count; + u8 hi_idx; + u8 lo_idx; + bool ramp_dir_low_to_hi; + bool pattern_repeat; + bool toggle; + u32 *pattern; + u32 pattern_length; +}; + struct lpg_pwm_config { u32 pwm_size; u32 pwm_clk; @@ -96,13 +137,23 @@ struct lpg_pwm_config { u32 best_period_ns; }; +struct qpnp_lpg_lut { + struct qpnp_lpg_chip *chip; + struct mutex lock; + u32 reg_base; + u32 *pattern; /* patterns in percentage */ +}; + struct qpnp_lpg_channel { struct qpnp_lpg_chip *chip; struct lpg_pwm_config pwm_config; + struct lpg_ramp_config ramp_config; u32 lpg_idx; u32 reg_base; + u32 max_pattern_length; u8 src_sel; u8 subtype; + bool lut_written; int current_period_ns; int current_duty_ns; }; @@ -112,6 +163,7 @@ struct qpnp_lpg_chip { struct regmap *regmap; struct device *dev; struct qpnp_lpg_channel *lpgs; + struct qpnp_lpg_lut *lut; struct mutex bus_lock; u32 num_lpgs; }; @@ -163,6 +215,36 @@ static int qpnp_lpg_masked_write(struct qpnp_lpg_channel *lpg, return rc; } +static int qpnp_lut_write(struct qpnp_lpg_lut *lut, u16 addr, u8 val) +{ + int rc; + + mutex_lock(&lut->chip->bus_lock); + rc = regmap_write(lut->chip->regmap, lut->reg_base + addr, val); + if (rc < 0) + dev_err(lut->chip->dev, "Write addr 0x%x with value %d failed, rc=%d\n", + lut->reg_base + addr, val, rc); + mutex_unlock(&lut->chip->bus_lock); + + return rc; +} + +static int qpnp_lut_masked_write(struct qpnp_lpg_lut *lut, + u16 addr, u8 mask, u8 val) +{ + int rc; + + mutex_lock(&lut->chip->bus_lock); + rc = regmap_update_bits(lut->chip->regmap, lut->reg_base + addr, + mask, val); + if (rc < 0) + dev_err(lut->chip->dev, "Update addr 0x%x to val 0x%x with mask 0x%x failed, rc=%d\n", + lut->reg_base + addr, val, mask, rc); + mutex_unlock(&lut->chip->bus_lock); + + return rc; +} + static struct qpnp_lpg_channel *pwm_dev_to_qpnp_lpg(struct pwm_chip *pwm_chip, struct pwm_device *pwm) { @@ -228,11 +310,11 @@ static int qpnp_lpg_set_pwm_config(struct qpnp_lpg_channel *lpg) /* pwm_clk_idx is 1 bit lower than the register value */ pwm_clk_idx += 1; if (lpg->subtype == SUBTYPE_PWM) { - shift = LPG_PWM_SIZE_SHIFT_PWM; - mask = LPG_PWM_SIZE_MASK_PWM; + shift = LPG_PWM_SIZE_PWM_SHIFT; + mask = LPG_PWM_SIZE_PWM_MASK; } else { - shift = LPG_PWM_SIZE_SHIFT_LPG; - mask = LPG_PWM_SIZE_MASK_LPG; + shift = LPG_PWM_SIZE_LPG_SHIFT; + mask = LPG_PWM_SIZE_LPG_MASK; } val = pwm_size_idx << shift | pwm_clk_idx; @@ -253,6 +335,9 @@ static int qpnp_lpg_set_pwm_config(struct qpnp_lpg_channel *lpg) return rc; } + if (lpg->src_sel == LUT_PATTERN) + return 0; + val = lpg->pwm_config.pwm_value & LPG_PWM_VALUE_LSB_MASK; rc = qpnp_lpg_write(lpg, REG_LPG_PWM_VALUE_LSB, val); if (rc < 0) { @@ -281,6 +366,145 @@ static int qpnp_lpg_set_pwm_config(struct qpnp_lpg_channel *lpg) return rc; } +static int qpnp_lpg_set_lut_pattern(struct qpnp_lpg_channel *lpg, + unsigned int *pattern, unsigned int length) +{ + struct qpnp_lpg_lut *lut = lpg->chip->lut; + int i, rc = 0; + u16 full_duty_value, pwm_values[LPG_LUT_COUNT_MAX + 1] = {0}; + u8 lsb, msb, addr; + + if (length > lpg->max_pattern_length) { + dev_err(lpg->chip->dev, "new pattern length (%d) larger than predefined (%d)\n", + length, lpg->max_pattern_length); + return -EINVAL; + } + + /* Program LUT pattern */ + mutex_lock(&lut->lock); + addr = REG_LPG_LUT_1_LSB + lpg->ramp_config.lo_idx * 2; + for (i = 0; i < length; i++) { + full_duty_value = 1 << lpg->pwm_config.pwm_size; + pwm_values[i] = pattern[i] * full_duty_value / 100; + + if (unlikely(pwm_values[i] > full_duty_value)) { + dev_err(lpg->chip->dev, "PWM value %d exceed the max %d\n", + pwm_values[i], full_duty_value); + rc = -EINVAL; + goto unlock; + } + + if (pwm_values[i] == full_duty_value) + pwm_values[i] = full_duty_value - 1; + + lsb = pwm_values[i] & 0xff; + msb = pwm_values[i] >> 8; + rc = qpnp_lut_write(lut, addr++, lsb); + if (rc < 0) { + dev_err(lpg->chip->dev, "Write NO.%d LUT pattern LSB (%d) failed, rc=%d", + i, lsb, rc); + goto unlock; + } + + rc = qpnp_lut_masked_write(lut, addr++, + LPG_LUT_VALUE_MSB_MASK, msb); + if (rc < 0) { + dev_err(lpg->chip->dev, "Write NO.%d LUT pattern MSB (%d) failed, rc=%d", + i, msb, rc); + goto unlock; + } + } + lpg->ramp_config.pattern_length = length; +unlock: + mutex_unlock(&lut->lock); + + return rc; +} + +static int qpnp_lpg_set_ramp_config(struct qpnp_lpg_channel *lpg) +{ + struct lpg_ramp_config *ramp = &lpg->ramp_config; + u8 lsb, msb, addr, mask, val; + int rc = 0; + + /* Set ramp step duration */ + lsb = ramp->step_ms & 0xff; + msb = ramp->step_ms >> 8; + addr = REG_LPG_RAMP_STEP_DURATION_LSB; + rc = qpnp_lpg_write(lpg, addr, lsb); + if (rc < 0) { + dev_err(lpg->chip->dev, "Write RAMP_STEP_DURATION_LSB failed, rc=%d\n", + rc); + return rc; + } + rc = qpnp_lpg_write(lpg, addr + 1, msb); + if (rc < 0) { + dev_err(lpg->chip->dev, "Write RAMP_STEP_DURATION_MSB failed, rc=%d\n", + rc); + return rc; + } + + /* Set hi_idx and lo_idx */ + rc = qpnp_lpg_masked_write(lpg, REG_LPG_HI_INDEX, + LPG_HI_LO_IDX_MASK, ramp->hi_idx); + if (rc < 0) { + dev_err(lpg->chip->dev, "Write LPG_HI_IDX failed, rc=%d\n", + rc); + return rc; + } + + rc = qpnp_lpg_masked_write(lpg, REG_LPG_LO_INDEX, + LPG_HI_LO_IDX_MASK, ramp->lo_idx); + if (rc < 0) { + dev_err(lpg->chip->dev, "Write LPG_LO_IDX failed, rc=%d\n", + rc); + return rc; + } + + /* Set pause_hi/lo_count */ + rc = qpnp_lpg_write(lpg, REG_LPG_PAUSE_HI_MULTIPLIER, + ramp->pause_hi_count); + if (rc < 0) { + dev_err(lpg->chip->dev, "Write LPG_PAUSE_HI_MULTIPLIER failed, rc=%d\n", + rc); + return rc; + } + + rc = qpnp_lpg_write(lpg, REG_LPG_PAUSE_LO_MULTIPLIER, + ramp->pause_lo_count); + if (rc < 0) { + dev_err(lpg->chip->dev, "Write LPG_PAUSE_LO_MULTIPLIER failed, rc=%d\n", + rc); + return rc; + } + + /* Set LPG_PATTERN_CONFIG */ + addr = REG_LPG_PATTERN_CONFIG; + mask = LPG_PATTERN_EN_PAUSE_LO | LPG_PATTERN_EN_PAUSE_HI + | LPG_PATTERN_RAMP_TOGGLE | LPG_PATTERN_REPEAT + | LPG_PATTERN_RAMP_LO_TO_HI; + val = 0; + if (ramp->pause_lo_count != 0) + val |= LPG_PATTERN_EN_PAUSE_LO; + if (ramp->pause_hi_count != 0) + val |= LPG_PATTERN_EN_PAUSE_HI; + if (ramp->ramp_dir_low_to_hi) + val |= LPG_PATTERN_RAMP_LO_TO_HI; + if (ramp->pattern_repeat) + val |= LPG_PATTERN_REPEAT; + if (ramp->toggle) + val |= LPG_PATTERN_RAMP_TOGGLE; + + rc = qpnp_lpg_masked_write(lpg, addr, mask, val); + if (rc < 0) { + dev_err(lpg->chip->dev, "Write LPG_PATTERN_CONFIG failed, rc=%d\n", + rc); + return rc; + } + + return rc; +} + static void __qpnp_lpg_calc_pwm_period(int period_ns, struct lpg_pwm_config *pwm_config) { @@ -397,17 +621,202 @@ static int qpnp_lpg_pwm_config(struct pwm_chip *pwm_chip, return -EINVAL; } - if (period_ns != lpg->current_period_ns) + if (period_ns != lpg->current_period_ns) { __qpnp_lpg_calc_pwm_period(period_ns, &lpg->pwm_config); + /* program LUT if PWM period is changed */ + if (lpg->src_sel == LUT_PATTERN) { + rc = qpnp_lpg_set_lut_pattern(lpg, + lpg->ramp_config.pattern, + lpg->ramp_config.pattern_length); + if (rc < 0) { + dev_err(pwm_chip->dev, "set LUT pattern failed for LPG%d, rc=%d\n", + lpg->lpg_idx, rc); + return rc; + } + lpg->lut_written = true; + } + } + if (period_ns != lpg->current_period_ns || duty_ns != lpg->current_duty_ns) __qpnp_lpg_calc_pwm_duty(period_ns, duty_ns, &lpg->pwm_config); rc = qpnp_lpg_set_pwm_config(lpg); - if (rc < 0) + if (rc < 0) { dev_err(pwm_chip->dev, "Config PWM failed for channel %d, rc=%d\n", lpg->lpg_idx, rc); + return rc; + } + + lpg->current_period_ns = period_ns; + lpg->current_duty_ns = duty_ns; + + return rc; +} + +static int qpnp_lpg_pwm_src_enable(struct qpnp_lpg_channel *lpg, bool en) +{ + struct qpnp_lpg_chip *chip = lpg->chip; + struct qpnp_lpg_lut *lut = chip->lut; + u8 mask, val; + int rc; + + mask = LPG_PWM_SRC_SELECT_MASK | LPG_EN_LPG_OUT_BIT | + LPG_EN_RAMP_GEN_MASK; + val = lpg->src_sel << LPG_PWM_SRC_SELECT_SHIFT; + + if (lpg->src_sel == LUT_PATTERN) + val |= 1 << LPG_EN_RAMP_GEN_SHIFT; + + if (en) + val |= 1 << LPG_EN_LPG_OUT_SHIFT; + + rc = qpnp_lpg_masked_write(lpg, REG_LPG_ENABLE_CONTROL, mask, val); + if (rc < 0) { + dev_err(chip->dev, "Write LPG_ENABLE_CONTROL failed, rc=%d\n", + rc); + return rc; + } + + if (lpg->src_sel == LUT_PATTERN && en) { + mutex_lock(&lut->lock); + val = 1 << lpg->lpg_idx; + rc = qpnp_lut_write(lut, REG_LPG_LUT_RAMP_CONTROL, val); + if (rc < 0) + dev_err(chip->dev, "Write LPG_LUT_RAMP_CONTROL failed, rc=%d\n", + rc); + mutex_unlock(&lut->lock); + } + + return rc; +} + +static int qpnp_lpg_pwm_set_output_type(struct pwm_chip *pwm_chip, + struct pwm_device *pwm, enum pwm_output_type output_type) +{ + struct qpnp_lpg_channel *lpg; + enum lpg_src src_sel; + int rc; + + lpg = pwm_dev_to_qpnp_lpg(pwm_chip, pwm); + if (lpg == NULL) { + dev_err(pwm_chip->dev, "lpg not found\n"); + return -ENODEV; + } + + if (lpg->chip->lut == NULL) { + pr_debug("lpg%d only support PWM mode\n", lpg->lpg_idx); + return 0; + } + + src_sel = (output_type == PWM_OUTPUT_MODULATED) ? + LUT_PATTERN : PWM_VALUE; + if (src_sel == lpg->src_sel) + return 0; + + if (src_sel == LUT_PATTERN) { + /* program LUT if it's never been programmed */ + if (!lpg->lut_written) { + rc = qpnp_lpg_set_lut_pattern(lpg, + lpg->ramp_config.pattern, + lpg->ramp_config.pattern_length); + if (rc < 0) { + dev_err(pwm_chip->dev, "set LUT pattern failed for LPG%d, rc=%d\n", + lpg->lpg_idx, rc); + return rc; + } + lpg->lut_written = true; + } + + rc = qpnp_lpg_set_ramp_config(lpg); + if (rc < 0) { + dev_err(pwm_chip->dev, "Config LPG%d ramping failed, rc=%d\n", + lpg->lpg_idx, rc); + return rc; + } + } + + lpg->src_sel = src_sel; + + if (pwm_is_enabled(pwm)) { + rc = qpnp_lpg_pwm_src_enable(lpg, true); + if (rc < 0) { + dev_err(pwm_chip->dev, "Enable PWM output failed for channel %d, rc=%d\n", + lpg->lpg_idx, rc); + return rc; + } + } + + return 0; +} + +static int qpnp_lpg_pwm_set_output_pattern(struct pwm_chip *pwm_chip, + struct pwm_device *pwm, struct pwm_output_pattern *output_pattern) +{ + struct qpnp_lpg_channel *lpg; + int rc = 0, i, period_ns, duty_ns; + u32 *percentages; + + lpg = pwm_dev_to_qpnp_lpg(pwm_chip, pwm); + if (lpg == NULL) { + dev_err(pwm_chip->dev, "lpg not found\n"); + return -ENODEV; + } + + if (output_pattern->num_entries > lpg->max_pattern_length) { + dev_err(lpg->chip->dev, "pattern length %d shouldn't exceed %d\n", + output_pattern->num_entries, + lpg->max_pattern_length); + return -EINVAL; + } + + percentages = kcalloc(output_pattern->num_entries, + sizeof(u32), GFP_KERNEL); + if (!percentages) + return -ENOMEM; + + period_ns = pwm_get_period(pwm); + for (i = 0; i < output_pattern->num_entries; i++) { + duty_ns = output_pattern->duty_pattern[i]; + if (duty_ns > period_ns) { + dev_err(lpg->chip->dev, "duty %dns is larger than period %dns\n", + duty_ns, period_ns); + goto err; + } + /* Translate the pattern in duty_ns to percentage */ + if ((INT_MAX / duty_ns) < 100) + percentages[i] = duty_ns / (period_ns / 100); + else + percentages[i] = (duty_ns * 100) / period_ns; + } + + rc = qpnp_lpg_set_lut_pattern(lpg, percentages, + output_pattern->num_entries); + if (rc < 0) { + dev_err(lpg->chip->dev, "Set LUT pattern failed for LPG%d, rc=%d\n", + lpg->lpg_idx, rc); + goto err; + } + + lpg->lut_written = true; + memcpy(lpg->ramp_config.pattern, percentages, + output_pattern->num_entries); + lpg->ramp_config.hi_idx = lpg->ramp_config.lo_idx + + output_pattern->num_entries - 1; + if ((INT_MAX / period_ns) > output_pattern->cycles_per_duty) + lpg->ramp_config.step_ms = output_pattern->cycles_per_duty * + period_ns / NSEC_PER_MSEC; + else + lpg->ramp_config.step_ms = (period_ns / NSEC_PER_MSEC) * + output_pattern->cycles_per_duty; + + rc = qpnp_lpg_set_ramp_config(lpg); + if (rc < 0) + dev_err(pwm_chip->dev, "Config LPG%d ramping failed, rc=%d\n", + lpg->lpg_idx, rc); +err: + kfree(percentages); return rc; } @@ -417,7 +826,6 @@ static int qpnp_lpg_pwm_enable(struct pwm_chip *pwm_chip, { struct qpnp_lpg_channel *lpg; int rc = 0; - u8 mask, val; lpg = pwm_dev_to_qpnp_lpg(pwm_chip, pwm); if (lpg == NULL) { @@ -432,10 +840,7 @@ static int qpnp_lpg_pwm_enable(struct pwm_chip *pwm_chip, return rc; } - mask = LPG_PWM_SRC_SELECT_MASK | LPG_EN_LPG_OUT_BIT; - val = lpg->src_sel << LPG_PWM_SRC_SELECT_SHIFT | LPG_EN_LPG_OUT_BIT; - - rc = qpnp_lpg_masked_write(lpg, REG_LPG_ENABLE_CONTROL, mask, val); + rc = qpnp_lpg_pwm_src_enable(lpg, true); if (rc < 0) dev_err(pwm_chip->dev, "Enable PWM output failed for channel %d, rc=%d\n", lpg->lpg_idx, rc); @@ -448,7 +853,6 @@ static void qpnp_lpg_pwm_disable(struct pwm_chip *pwm_chip, { struct qpnp_lpg_channel *lpg; int rc; - u8 mask, val; lpg = pwm_dev_to_qpnp_lpg(pwm_chip, pwm); if (lpg == NULL) { @@ -456,10 +860,7 @@ static void qpnp_lpg_pwm_disable(struct pwm_chip *pwm_chip, return; } - mask = LPG_PWM_SRC_SELECT_MASK | LPG_EN_LPG_OUT_BIT; - val = lpg->src_sel << LPG_PWM_SRC_SELECT_SHIFT; - - rc = qpnp_lpg_masked_write(lpg, REG_LPG_ENABLE_CONTROL, mask, val); + rc = qpnp_lpg_pwm_src_enable(lpg, false); if (rc < 0) { dev_err(pwm_chip->dev, "Disable PWM output failed for channel %d, rc=%d\n", lpg->lpg_idx, rc); @@ -472,13 +873,32 @@ static void qpnp_lpg_pwm_disable(struct pwm_chip *pwm_chip, rc); } +static int qpnp_lpg_pwm_output_types_supported(struct pwm_chip *pwm_chip, + struct pwm_device *pwm) +{ + enum pwm_output_type type = PWM_OUTPUT_FIXED; + struct qpnp_lpg_channel *lpg; + + lpg = pwm_dev_to_qpnp_lpg(pwm_chip, pwm); + if (lpg == NULL) { + dev_err(pwm_chip->dev, "lpg not found\n"); + return type; + } + + if (lpg->chip->lut != NULL) + type |= PWM_OUTPUT_MODULATED; + + return type; +} + #ifdef CONFIG_DEBUG_FS static void qpnp_lpg_pwm_dbg_show(struct pwm_chip *pwm_chip, struct seq_file *s) { struct qpnp_lpg_channel *lpg; struct lpg_pwm_config *cfg; + struct lpg_ramp_config *ramp; struct pwm_device *pwm; - int i; + int i, j; for (i = 0; i < pwm_chip->npwm; i++) { pwm = &pwm_chip->pwms[i]; @@ -513,12 +933,39 @@ static void qpnp_lpg_pwm_dbg_show(struct pwm_chip *pwm_chip, struct seq_file *s) seq_printf(s, " pwm_value = %d\n", cfg->pwm_value); seq_printf(s, " Requested period: %dns, best period = %dns\n", pwm_get_period(pwm), cfg->best_period_ns); + + ramp = &lpg->ramp_config; + if (pwm_get_output_type(pwm) == PWM_OUTPUT_MODULATED) { + seq_puts(s, " ramping duty percentages:"); + for (j = 0; j < ramp->pattern_length; j++) + seq_printf(s, " %d", ramp->pattern[j]); + seq_puts(s, "\n"); + seq_printf(s, " ramping time per step: %dms\n", + ramp->step_ms); + seq_printf(s, " ramping low index: %d\n", + ramp->lo_idx); + seq_printf(s, " ramping high index: %d\n", + ramp->hi_idx); + seq_printf(s, " ramping from low to high: %d\n", + ramp->ramp_dir_low_to_hi); + seq_printf(s, " ramping pattern repeat: %d\n", + ramp->pattern_repeat); + seq_printf(s, " ramping toggle: %d\n", + ramp->toggle); + seq_printf(s, " ramping pause count at low index: %d\n", + ramp->pause_lo_count); + seq_printf(s, " ramping pause count at high index: %d\n", + ramp->pause_hi_count); + } } } #endif static const struct pwm_ops qpnp_lpg_pwm_ops = { .config = qpnp_lpg_pwm_config, + .get_output_type_supported = qpnp_lpg_pwm_output_types_supported, + .set_output_type = qpnp_lpg_pwm_set_output_type, + .set_output_pattern = qpnp_lpg_pwm_set_output_pattern, .enable = qpnp_lpg_pwm_enable, .disable = qpnp_lpg_pwm_disable, #ifdef CONFIG_DEBUG_FS @@ -529,15 +976,19 @@ static const struct pwm_ops qpnp_lpg_pwm_ops = { static int qpnp_lpg_parse_dt(struct qpnp_lpg_chip *chip) { + struct device_node *child; + struct qpnp_lpg_channel *lpg; + struct lpg_ramp_config *ramp; int rc = 0, i; - u64 base, length; + u32 base, length, lpg_chan_id, tmp; const __be32 *addr; addr = of_get_address(chip->dev->of_node, 0, NULL, NULL); if (!addr) { - dev_err(chip->dev, "Getting address failed\n"); + dev_err(chip->dev, "Get %s address failed\n", LPG_BASE); return -EINVAL; } + base = be32_to_cpu(addr[0]); length = be32_to_cpu(addr[1]); @@ -551,7 +1002,7 @@ static int qpnp_lpg_parse_dt(struct qpnp_lpg_chip *chip) chip->lpgs[i].chip = chip; chip->lpgs[i].lpg_idx = i; chip->lpgs[i].reg_base = base + i * REG_SIZE_PER_LPG; - chip->lpgs[i].src_sel = PWM_OUTPUT; + chip->lpgs[i].src_sel = PWM_VALUE; rc = qpnp_lpg_read(&chip->lpgs[i], REG_LPG_PERPH_SUBTYPE, &chip->lpgs[i].subtype); if (rc < 0) { @@ -560,7 +1011,142 @@ static int qpnp_lpg_parse_dt(struct qpnp_lpg_chip *chip) } } - return rc; + addr = of_get_address(chip->dev->of_node, 1, NULL, NULL); + if (!addr) { + pr_debug("NO LUT address assigned\n"); + return 0; + } + + chip->lut = devm_kmalloc(chip->dev, sizeof(*chip->lut), GFP_KERNEL); + if (!chip->lut) + return -ENOMEM; + + chip->lut->chip = chip; + chip->lut->reg_base = be32_to_cpu(*addr); + mutex_init(&chip->lut->lock); + + rc = of_property_count_elems_of_size(chip->dev->of_node, + "qcom,lut-patterns", sizeof(u32)); + if (rc < 0) { + dev_err(chip->dev, "Read qcom,lut-patterns failed, rc=%d\n", + rc); + return rc; + } + + length = rc; + if (length > LPG_LUT_COUNT_MAX) { + dev_err(chip->dev, "qcom,lut-patterns length %d exceed max %d\n", + length, LPG_LUT_COUNT_MAX); + return -EINVAL; + } + + chip->lut->pattern = devm_kcalloc(chip->dev, LPG_LUT_COUNT_MAX, + sizeof(*chip->lut->pattern), GFP_KERNEL); + if (!chip->lut->pattern) + return -ENOMEM; + + rc = of_property_read_u32_array(chip->dev->of_node, "qcom,lut-patterns", + chip->lut->pattern, length); + if (rc < 0) { + dev_err(chip->dev, "Get qcom,lut-patterns failed, rc=%d\n", + rc); + return rc; + } + + if (of_get_available_child_count(chip->dev->of_node) == 0) { + dev_err(chip->dev, "No ramp configuration for any LPG\n"); + return -EINVAL; + } + + for_each_available_child_of_node(chip->dev->of_node, child) { + rc = of_property_read_u32(child, "qcom,lpg-chan-id", + &lpg_chan_id); + if (rc < 0) { + dev_err(chip->dev, "Get qcom,lpg-chan-id failed for node %s, rc=%d\n", + child->name, rc); + return rc; + } + + if (lpg_chan_id > chip->num_lpgs) { + dev_err(chip->dev, "lpg-chann-id %d is out of range 1~%d\n", + lpg_chan_id, chip->num_lpgs); + return -EINVAL; + } + + /* lpg channel id is indexed from 1 in hardware */ + lpg = &chip->lpgs[lpg_chan_id - 1]; + ramp = &lpg->ramp_config; + + rc = of_property_read_u32(child, "qcom,ramp-step-ms", &tmp); + if (rc < 0) { + dev_err(chip->dev, "get qcom,ramp-step-ms failed for lpg%d, rc=%d\n", + lpg_chan_id, rc); + return rc; + } + ramp->step_ms = (u16)tmp; + + rc = of_property_read_u32(child, "qcom,ramp-low-index", &tmp); + if (rc < 0) { + dev_err(chip->dev, "get qcom,ramp-low-index failed for lpg%d, rc=%d\n", + lpg_chan_id, rc); + return rc; + } + ramp->lo_idx = (u8)tmp; + if (ramp->lo_idx >= LPG_LUT_COUNT_MAX) { + dev_err(chip->dev, "qcom,ramp-low-index should less than max %d\n", + LPG_LUT_COUNT_MAX); + return -EINVAL; + } + + rc = of_property_read_u32(child, "qcom,ramp-high-index", &tmp); + if (rc < 0) { + dev_err(chip->dev, "get qcom,ramp-high-index failed for lpg%d, rc=%d\n", + lpg_chan_id, rc); + return rc; + } + ramp->hi_idx = (u8)tmp; + + if (ramp->hi_idx > LPG_LUT_COUNT_MAX) { + dev_err(chip->dev, "qcom,ramp-high-index shouldn't exceed max %d\n", + LPG_LUT_COUNT_MAX); + return -EINVAL; + } + + if (ramp->hi_idx <= ramp->lo_idx) { + dev_err(chip->dev, "high-index(%d) should be larger than low-index(%d)\n", + ramp->hi_idx, ramp->lo_idx); + return -EINVAL; + } + + ramp->pattern_length = ramp->hi_idx - ramp->lo_idx + 1; + ramp->pattern = &chip->lut->pattern[ramp->lo_idx]; + lpg->max_pattern_length = ramp->pattern_length; + + rc = of_property_read_u32(child, + "qcom,ramp-pause-hi-count", &tmp); + if (rc < 0) + ramp->pause_hi_count = 0; + else + ramp->pause_hi_count = (u8)tmp; + + rc = of_property_read_u32(child, + "qcom,ramp-pause-lo-count", &tmp); + if (rc < 0) + ramp->pause_lo_count = 0; + else + ramp->pause_lo_count = (u8)tmp; + + ramp->ramp_dir_low_to_hi = of_property_read_bool(child, + "qcom,ramp-from-low-to-high"); + + ramp->pattern_repeat = of_property_read_bool(child, + "qcom,ramp-pattern-repeat"); + + ramp->toggle = of_property_read_bool(child, + "qcom,ramp-toggle"); + } + + return 0; } static int qpnp_lpg_probe(struct platform_device *pdev) @@ -584,7 +1170,7 @@ static int qpnp_lpg_probe(struct platform_device *pdev) if (rc < 0) { dev_err(chip->dev, "Devicetree properties parsing failed, rc=%d\n", rc); - goto destroy; + goto err_out; } dev_set_drvdata(chip->dev, chip); @@ -596,11 +1182,11 @@ static int qpnp_lpg_probe(struct platform_device *pdev) rc = pwmchip_add(&chip->pwm_chip); if (rc < 0) { dev_err(chip->dev, "Add pwmchip failed, rc=%d\n", rc); - goto destroy; + goto err_out; } return 0; -destroy: +err_out: mutex_destroy(&chip->bus_lock); return rc; } -- GitLab From d184f7564d885b6ee5651dff8cbd7d1620e73767 Mon Sep 17 00:00:00 2001 From: Fenglin Wu Date: Sun, 28 Jan 2018 13:57:43 +0800 Subject: [PATCH 0607/1635] leds: qti-tri-led: Add breath feature for tri-led Some PWM devices could output modulated waveforms with a predefined pattern which can be used for controlling LED breathing behavior. Add a sysfs parameter to make the LED device can output breathing pattern. Change-Id: I1e2c60ea3c61bf14d382991b40536d0cdb39006c Signed-off-by: Fenglin Wu --- drivers/leds/leds-qti-tri-led.c | 95 ++++++++++++++++++++++++++++++--- 1 file changed, 88 insertions(+), 7 deletions(-) diff --git a/drivers/leds/leds-qti-tri-led.c b/drivers/leds/leds-qti-tri-led.c index 09485d53fccb..4798689f73cb 100644 --- a/drivers/leds/leds-qti-tri-led.c +++ b/drivers/leds/leds-qti-tri-led.c @@ -54,6 +54,7 @@ struct led_setting { u32 off_ms; enum led_brightness brightness; bool blink; + bool breath; }; struct qpnp_led_dev { @@ -67,6 +68,7 @@ struct qpnp_led_dev { const char *default_trigger; u8 id; bool blinking; + bool breathing; }; struct qpnp_tri_led_chip { @@ -122,6 +124,10 @@ static int __tri_led_config_pwm(struct qpnp_led_dev *led, pstate.enabled = !!(pwm->duty_ns != 0); pstate.period = pwm->period_ns; pstate.duty_cycle = pwm->duty_ns; + pstate.output_type = led->led_setting.breath ? + PWM_OUTPUT_MODULATED : PWM_OUTPUT_FIXED; + /* Use default pattern in PWM device */ + pstate.output_pattern = NULL; rc = pwm_apply_state(led->pwm_dev, &pstate); if (rc < 0) @@ -237,7 +243,9 @@ static int qpnp_tri_led_set(struct qpnp_led_dev *led) /* Use initial period if no blinking is required */ period_ns = led->pwm_setting.pre_period_ns; - if (period_ns > INT_MAX / brightness) + if (brightness == LED_OFF) + duty_ns = 0; + else if (period_ns > INT_MAX / brightness) duty_ns = (period_ns / LED_FULL) * brightness; else duty_ns = (period_ns * brightness) / LED_FULL; @@ -261,9 +269,15 @@ static int qpnp_tri_led_set(struct qpnp_led_dev *led) if (led->led_setting.blink) { led->cdev.brightness = LED_FULL; led->blinking = true; + led->breathing = false; + } else if (led->led_setting.breath) { + led->cdev.brightness = LED_FULL; + led->blinking = false; + led->breathing = true; } else { led->cdev.brightness = led->led_setting.brightness; led->blinking = false; + led->breathing = false; } return rc; @@ -281,7 +295,7 @@ static int qpnp_tri_led_set_brightness(struct led_classdev *led_cdev, brightness = LED_FULL; if (brightness == led->led_setting.brightness && - !led->blinking) { + !led->blinking && !led->breathing) { mutex_unlock(&led->lock); return 0; } @@ -292,6 +306,7 @@ static int qpnp_tri_led_set_brightness(struct led_classdev *led_cdev, else led->led_setting.on_ms = 0; led->led_setting.blink = false; + led->led_setting.breath = false; rc = qpnp_tri_led_set(led); if (rc) @@ -327,14 +342,17 @@ static int qpnp_tri_led_set_blink(struct led_classdev *led_cdev, if (*on_ms == 0) { led->led_setting.blink = false; + led->led_setting.breath = false; led->led_setting.brightness = LED_OFF; } else if (*off_ms == 0) { led->led_setting.blink = false; + led->led_setting.breath = false; led->led_setting.brightness = led->cdev.brightness; } else { led->led_setting.on_ms = *on_ms; led->led_setting.off_ms = *off_ms; led->led_setting.blink = true; + led->led_setting.breath = false; } rc = qpnp_tri_led_set(led); @@ -346,6 +364,52 @@ static int qpnp_tri_led_set_blink(struct led_classdev *led_cdev, return rc; } +static ssize_t breath_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct led_classdev *led_cdev = dev_get_drvdata(dev); + struct qpnp_led_dev *led = + container_of(led_cdev, struct qpnp_led_dev, cdev); + + return snprintf(buf, PAGE_SIZE, "%d\n", led->led_setting.breath); +} + +static ssize_t breath_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + int rc; + bool breath; + struct led_classdev *led_cdev = dev_get_drvdata(dev); + struct qpnp_led_dev *led = + container_of(led_cdev, struct qpnp_led_dev, cdev); + + rc = kstrtobool(buf, &breath); + if (rc < 0) + return rc; + + mutex_lock(&led->lock); + if (led->breathing == breath) + goto unlock; + + led->led_setting.blink = false; + led->led_setting.breath = breath; + led->led_setting.brightness = breath ? LED_FULL : LED_OFF; + rc = qpnp_tri_led_set(led); + if (rc < 0) + dev_err(led->chip->dev, "Set led failed for %s, rc=%d\n", + led->label, rc); + +unlock: + mutex_unlock(&led->lock); + return (rc < 0) ? rc : count; +} + +static DEVICE_ATTR(breath, 0644, breath_show, breath_store); +static const struct attribute *breath_attrs[] = { + &dev_attr_breath.attr, + NULL +}; + static int qpnp_tri_led_register(struct qpnp_tri_led_chip *chip) { struct qpnp_led_dev *led; @@ -367,15 +431,30 @@ static int qpnp_tri_led_register(struct qpnp_tri_led_chip *chip) if (rc < 0) { dev_err(chip->dev, "%s led class device registering failed, rc=%d\n", led->label, rc); - goto destroy; + goto err_out; + } + + if (pwm_get_output_type_supported(led->pwm_dev) + & PWM_OUTPUT_MODULATED) { + rc = sysfs_create_files(&led->cdev.dev->kobj, + breath_attrs); + if (rc < 0) { + dev_err(chip->dev, "Create breath file for %s led failed, rc=%d\n", + led->label, rc); + goto err_out; + } } } return 0; -destroy: - for (j = 0; j <= i; j++) - mutex_destroy(&chip->leds[i].lock); +err_out: + for (j = 0; j <= i; j++) { + if (j < i) + sysfs_remove_files(&chip->leds[j].cdev.dev->kobj, + breath_attrs); + mutex_destroy(&chip->leds[j].lock); + } return rc; } @@ -551,8 +630,10 @@ static int qpnp_tri_led_remove(struct platform_device *pdev) struct qpnp_tri_led_chip *chip = dev_get_drvdata(&pdev->dev); mutex_destroy(&chip->bus_lock); - for (i = 0; i < chip->num_leds; i++) + for (i = 0; i < chip->num_leds; i++) { + sysfs_remove_files(&chip->leds[i].cdev.dev->kobj, breath_attrs); mutex_destroy(&chip->leds[i].lock); + } dev_set_drvdata(chip->dev, NULL); return 0; } -- GitLab From 340bb1039c87b504600dc67e50064d609ddbdb67 Mon Sep 17 00:00:00 2001 From: Mohit Aggarwal Date: Thu, 28 Dec 2017 16:21:12 +0530 Subject: [PATCH 0608/1635] rtc-pm8xxx: Fix issue in RTC write path In order to set time in rtc, need to disable rtc hw before writing into rtc registers. Also fixes disabling of alarm while setting rtc time. Change-Id: I0ffad7b6dcba5fea510d5acfad82ed328cffcf84 Signed-off-by: Mohit Aggarwal --- drivers/rtc/rtc-pm8xxx.c | 49 +++++++++++++++++++++++++++++++--------- 1 file changed, 38 insertions(+), 11 deletions(-) diff --git a/drivers/rtc/rtc-pm8xxx.c b/drivers/rtc/rtc-pm8xxx.c index fac835530671..5309edcee7b7 100644 --- a/drivers/rtc/rtc-pm8xxx.c +++ b/drivers/rtc/rtc-pm8xxx.c @@ -74,16 +74,18 @@ struct pm8xxx_rtc { /* * Steps to write the RTC registers. * 1. Disable alarm if enabled. - * 2. Write 0x00 to LSB. - * 3. Write Byte[1], Byte[2], Byte[3] then Byte[0]. - * 4. Enable alarm if disabled in step 1. + * 2. Disable rtc if enabled. + * 3. Write 0x00 to LSB. + * 4. Write Byte[1], Byte[2], Byte[3] then Byte[0]. + * 5. Enable rtc if disabled in step 2. + * 6. Enable alarm if disabled in step 1. */ static int pm8xxx_rtc_set_time(struct device *dev, struct rtc_time *tm) { int rc, i; unsigned long secs, irq_flags; - u8 value[NUM_8_BIT_RTC_REGS], alarm_enabled = 0; - unsigned int ctrl_reg; + u8 value[NUM_8_BIT_RTC_REGS], alarm_enabled = 0, rtc_disabled = 0; + unsigned int ctrl_reg, rtc_ctrl_reg; struct pm8xxx_rtc *rtc_dd = dev_get_drvdata(dev); const struct pm8xxx_rtc_regs *regs = rtc_dd->regs; @@ -92,23 +94,38 @@ static int pm8xxx_rtc_set_time(struct device *dev, struct rtc_time *tm) rtc_tm_to_time(tm, &secs); + dev_dbg(dev, "Seconds value to be written to RTC = %lu\n", secs); + for (i = 0; i < NUM_8_BIT_RTC_REGS; i++) { value[i] = secs & 0xFF; secs >>= 8; } - dev_dbg(dev, "Seconds value to be written to RTC = %lu\n", secs); - spin_lock_irqsave(&rtc_dd->ctrl_reg_lock, irq_flags); - rc = regmap_read(rtc_dd->regmap, regs->ctrl, &ctrl_reg); + rc = regmap_read(rtc_dd->regmap, regs->alarm_ctrl, &ctrl_reg); if (rc) goto rtc_rw_fail; if (ctrl_reg & regs->alarm_en) { alarm_enabled = 1; ctrl_reg &= ~regs->alarm_en; - rc = regmap_write(rtc_dd->regmap, regs->ctrl, ctrl_reg); + rc = regmap_write(rtc_dd->regmap, regs->alarm_ctrl, ctrl_reg); + if (rc) { + dev_err(dev, "Write to RTC Alarm control register failed\n"); + goto rtc_rw_fail; + } + } + + /* Disable RTC H/w before writing on RTC register */ + rc = regmap_read(rtc_dd->regmap, regs->ctrl, &rtc_ctrl_reg); + if (rc) + goto rtc_rw_fail; + + if (rtc_ctrl_reg & PM8xxx_RTC_ENABLE) { + rtc_disabled = 1; + rtc_ctrl_reg &= ~PM8xxx_RTC_ENABLE; + rc = regmap_write(rtc_dd->regmap, regs->ctrl, rtc_ctrl_reg); if (rc) { dev_err(dev, "Write to RTC control register failed\n"); goto rtc_rw_fail; @@ -137,11 +154,21 @@ static int pm8xxx_rtc_set_time(struct device *dev, struct rtc_time *tm) goto rtc_rw_fail; } + /* Enable RTC H/w after writing on RTC register */ + if (rtc_disabled) { + rtc_ctrl_reg |= PM8xxx_RTC_ENABLE; + rc = regmap_write(rtc_dd->regmap, regs->ctrl, rtc_ctrl_reg); + if (rc) { + dev_err(dev, "Write to RTC control register failed\n"); + goto rtc_rw_fail; + } + } + if (alarm_enabled) { ctrl_reg |= regs->alarm_en; - rc = regmap_write(rtc_dd->regmap, regs->ctrl, ctrl_reg); + rc = regmap_write(rtc_dd->regmap, regs->alarm_ctrl, ctrl_reg); if (rc) { - dev_err(dev, "Write to RTC control register failed\n"); + dev_err(dev, "Write to RTC Alarm control register failed\n"); goto rtc_rw_fail; } } -- GitLab From 8908375794d4c81f713f39f05dca6f6ca68bf7c9 Mon Sep 17 00:00:00 2001 From: Maulik Shah Date: Fri, 15 Dec 2017 17:37:47 +0530 Subject: [PATCH 0609/1635] drivers: soc: qcom: Add support to display RPMH master stats Individual subsystem maintains stats on system sleep like sleep counts, sleep last entered at, sleep last exited at, and accumulated sleep duration. Provide support to display it through sysfs. Below command will display stats for each master available. cat /sys/power/rpmh_stats/master_stats Sample output on SDM670. MPSS Version:0x1 Sleep Count:0x0 Sleep Last Entered At:0x0 Sleep Last Exited At:0x0 Sleep Accumulated Duration:0x0 CDSP Version:0x1 Sleep Count:0x2e Sleep Last Entered At:0x4aee0370 Sleep Last Exited At:0x4aed513b Sleep Accumulated Duration:0x251c7019 Change-Id: I5224feed252e105c045ee028e4f56cbd244a101b Signed-off-by: Maulik Shah --- .../bindings/arm/msm/rpmh-master-stat.txt | 18 ++ drivers/soc/qcom/Makefile | 3 + drivers/soc/qcom/rpmh_master_stat.c | 220 ++++++++++++++++++ 3 files changed, 241 insertions(+) create mode 100644 Documentation/devicetree/bindings/arm/msm/rpmh-master-stat.txt create mode 100644 drivers/soc/qcom/rpmh_master_stat.c diff --git a/Documentation/devicetree/bindings/arm/msm/rpmh-master-stat.txt b/Documentation/devicetree/bindings/arm/msm/rpmh-master-stat.txt new file mode 100644 index 000000000000..36e1a69c564f --- /dev/null +++ b/Documentation/devicetree/bindings/arm/msm/rpmh-master-stat.txt @@ -0,0 +1,18 @@ +* RPMH Master Stats + +Differet Subsystems maintains master data in SMEM. +It tells about the individual masters information at any given +time like "system sleep counts", "system sleep last entered at" +and "system sleep accumulated duration" etc. These stats can be +show to the user using the debugfs interface of the kernel. +To achieve this, device tree node has been added. + +The required properties for rpmh-master-stats are: + +- compatible: "qcom,rpmh-master-stats". + +Example: + +qcom,rpmh-master-stats { + compatible = "qcom,rpmh-master-stats"; +}; diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile index fcd312c2bb51..d5bdf2b12065 100644 --- a/drivers/soc/qcom/Makefile +++ b/drivers/soc/qcom/Makefile @@ -70,5 +70,8 @@ obj-$(CONFIG_MSM_EVENT_TIMER) += event_timer.o obj-$(CONFIG_MSM_IDLE_STATS) += lpm-stats.o obj-$(CONFIG_QTI_RPM_STATS_LOG) += rpm_stats.o obj-$(CONFIG_QCOM_FSA4480_I2C) += fsa4480-i2c.o +ifdef CONFIG_QTI_RPMH_API + obj-$(CONFIG_QTI_RPM_STATS_LOG) += rpmh_master_stat.o +endif obj-$(CONFIG_QMP_DEBUGFS_CLIENT) += qmp-debugfs-client.o obj-$(CONFIG_MSM_PERFORMANCE) += msm_performance.o diff --git a/drivers/soc/qcom/rpmh_master_stat.c b/drivers/soc/qcom/rpmh_master_stat.c new file mode 100644 index 000000000000..f2f708823ca4 --- /dev/null +++ b/drivers/soc/qcom/rpmh_master_stat.c @@ -0,0 +1,220 @@ +/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#define pr_fmt(fmt) "%s: " fmt, KBUILD_MODNAME + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +enum master_smem_id { + MPSS = 605, + ADSP, + CDSP, + SLPI, + GPU, + DISPLAY, +}; + +enum master_pid { + PID_APSS = 0, + PID_MPSS = 1, + PID_ADSP = 2, + PID_SLPI = 3, + PID_CDSP = 5, + PID_GPU = PID_APSS, + PID_DISPLAY = PID_APSS, +}; + +struct msm_rpmh_master_data { + char *master_name; + enum master_smem_id smem_id; + enum master_pid pid; +}; + +static const struct msm_rpmh_master_data rpmh_masters[] = { + {"MPSS", MPSS, PID_MPSS}, + {"ADSP", ADSP, PID_ADSP}, + {"CDSP", CDSP, PID_CDSP}, + {"SLPI", SLPI, PID_SLPI}, + {"GPU", GPU, PID_GPU}, + {"DISPLAY", DISPLAY, PID_DISPLAY}, +}; + +struct msm_rpmh_master_stats { + uint32_t version_id; + uint32_t counts; + uint64_t last_entered_at; + uint64_t last_exited_at; + uint64_t accumulated_duration; +}; + +struct rpmh_master_stats_prv_data { + struct kobj_attribute ka; + struct kobject *kobj; +}; + +static DEFINE_MUTEX(rpmh_stats_mutex); + +static ssize_t msm_rpmh_master_stats_print_data(char *prvbuf, ssize_t length, + struct msm_rpmh_master_stats *record, + const char *name) +{ + return snprintf(prvbuf, length, "%s\n\tVersion:0x%x\n" + "\tSleep Count:0x%x\n" + "\tSleep Last Entered At:0x%llx\n" + "\tSleep Last Exited At:0x%llx\n" + "\tSleep Accumulated Duration:0x%llx\n\n", + name, record->version_id, record->counts, + record->last_entered_at, record->last_exited_at, + record->accumulated_duration); +} + +static ssize_t msm_rpmh_master_stats_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + ssize_t length; + int i = 0; + size_t size = 0; + struct msm_rpmh_master_stats *record = NULL; + + /* + * Read SMEM data written by masters + */ + + mutex_lock(&rpmh_stats_mutex); + + for (i = 0, length = 0; i < ARRAY_SIZE(rpmh_masters); i++) { + record = (struct msm_rpmh_master_stats *) qcom_smem_get( + rpmh_masters[i].pid, + rpmh_masters[i].smem_id, &size); + if (!IS_ERR_OR_NULL(record) && (PAGE_SIZE - length > 0)) + length += msm_rpmh_master_stats_print_data( + buf + length, PAGE_SIZE - length, + record, + rpmh_masters[i].master_name); + } + + mutex_unlock(&rpmh_stats_mutex); + + return length; +} + +static int msm_rpmh_master_stats_probe(struct platform_device *pdev) +{ + struct rpmh_master_stats_prv_data *prvdata = NULL; + struct kobject *rpmh_master_stats_kobj = NULL; + int ret = 0; + + if (!pdev) + return -EINVAL; + + prvdata = kzalloc(sizeof(struct rpmh_master_stats_prv_data), + GFP_KERNEL); + if (!prvdata) { + ret = -ENOMEM; + goto fail; + } + + rpmh_master_stats_kobj = kobject_create_and_add( + "rpmh_stats", + power_kobj); + if (!rpmh_master_stats_kobj) { + ret = -ENOMEM; + kfree(prvdata); + goto fail; + } + + prvdata->kobj = rpmh_master_stats_kobj; + + sysfs_attr_init(&prvdata->ka.attr); + prvdata->ka.attr.mode = 0444; + prvdata->ka.attr.name = "master_stats"; + prvdata->ka.show = msm_rpmh_master_stats_show; + prvdata->ka.store = NULL; + + ret = sysfs_create_file(prvdata->kobj, &prvdata->ka.attr); + if (ret) { + pr_err("sysfs_create_file failed\n"); + kobject_put(prvdata->kobj); + kfree(prvdata); + goto fail; + } + + platform_set_drvdata(pdev, prvdata); + +fail: + return ret; +} + +static int msm_rpmh_master_stats_remove(struct platform_device *pdev) +{ + struct rpmh_master_stats_prv_data *prvdata; + + if (!pdev) + return -EINVAL; + + prvdata = (struct rpmh_master_stats_prv_data *) + platform_get_drvdata(pdev); + + sysfs_remove_file(prvdata->kobj, &prvdata->ka.attr); + kobject_put(prvdata->kobj); + kfree(prvdata); + platform_set_drvdata(pdev, NULL); + + return 0; +} + +static const struct of_device_id rpmh_master_table[] = { + {.compatible = "qcom,rpmh-master-stats"}, + {}, +}; + +static struct platform_driver msm_rpmh_master_stats_driver = { + .probe = msm_rpmh_master_stats_probe, + .remove = msm_rpmh_master_stats_remove, + .driver = { + .name = "msm_rpmh_master_stats", + .owner = THIS_MODULE, + .of_match_table = rpmh_master_table, + }, +}; + +static int __init msm_rpmh_master_stats_init(void) +{ + return platform_driver_register(&msm_rpmh_master_stats_driver); +} + +static void __exit msm_rpmh_master_stats_exit(void) +{ + platform_driver_unregister(&msm_rpmh_master_stats_driver); +} + +module_init(msm_rpmh_master_stats_init); +module_exit(msm_rpmh_master_stats_exit); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("MSM RPMH Master Statistics driver"); +MODULE_ALIAS("platform:msm_rpmh_master_stat_log"); -- GitLab From 5b4032108545cebc0890491a907ea6d14ee3d6fa Mon Sep 17 00:00:00 2001 From: Maulik Shah Date: Thu, 1 Feb 2018 14:39:50 +0530 Subject: [PATCH 0610/1635] rpmh_master_stat: Add support for application processor master stats Add support to read application processor's PDC profiling data and display it as part of master stats. Below command displays application processor stats along with other master's stats. cat /sys/power/rpmh_stats/master_stats APSS Version:0x1 Sleep Count:0x13 Sleep Last Entered At:0x14721eadb Sleep Last Exited At:0x14724a427 Sleep Accumulated Duration:0x3a76b0 Change-Id: I2a9fa26a2418e58d185b8285e0b46549a41b4709 Signed-off-by: Maulik Shah --- .../bindings/arm/msm/rpmh-master-stat.txt | 17 ++- drivers/soc/qcom/rpmh_master_stat.c | 144 ++++++++++++------ drivers/soc/qcom/rpmh_master_stat.h | 23 +++ drivers/soc/qcom/system_pm.c | 4 +- 4 files changed, 141 insertions(+), 47 deletions(-) create mode 100644 drivers/soc/qcom/rpmh_master_stat.h diff --git a/Documentation/devicetree/bindings/arm/msm/rpmh-master-stat.txt b/Documentation/devicetree/bindings/arm/msm/rpmh-master-stat.txt index 36e1a69c564f..a53eba57f89d 100644 --- a/Documentation/devicetree/bindings/arm/msm/rpmh-master-stat.txt +++ b/Documentation/devicetree/bindings/arm/msm/rpmh-master-stat.txt @@ -4,15 +4,28 @@ Differet Subsystems maintains master data in SMEM. It tells about the individual masters information at any given time like "system sleep counts", "system sleep last entered at" and "system sleep accumulated duration" etc. These stats can be -show to the user using the debugfs interface of the kernel. +displayed using the sysfs interface. To achieve this, device tree node has been added. +Additionally, RPMH master stats also maintains application processor's +master stats. It uses profiling units to calculate power down and power +up stats. + The required properties for rpmh-master-stats are: -- compatible: "qcom,rpmh-master-stats". +- compatible: + Usage: required + Value type: + Definition: Should be "qcom,rpmh-master-stats-v1". + +- reg: + Usage: required + Value type: + Definition: Specifies physical address of start of profiling unit. Example: qcom,rpmh-master-stats { compatible = "qcom,rpmh-master-stats"; + reg = <0xb221200 0x60>; }; diff --git a/drivers/soc/qcom/rpmh_master_stat.c b/drivers/soc/qcom/rpmh_master_stat.c index f2f708823ca4..615464fd260f 100644 --- a/drivers/soc/qcom/rpmh_master_stat.c +++ b/drivers/soc/qcom/rpmh_master_stat.c @@ -13,21 +13,25 @@ #define pr_fmt(fmt) "%s: " fmt, KBUILD_MODNAME -#include -#include #include #include -#include #include #include #include -#include -#include #include #include #include +#include #include #include +#include "rpmh_master_stat.h" + +#define UNIT_DIST 0x14 +#define REG_VALID 0x0 +#define REG_DATA_LO 0x4 +#define REG_DATA_HI 0x8 + +#define GET_ADDR(REG, UNIT_NO) (REG + (UNIT_DIST * UNIT_NO)) enum master_smem_id { MPSS = 605, @@ -48,6 +52,14 @@ enum master_pid { PID_DISPLAY = PID_APSS, }; +enum profile_data { + POWER_DOWN_START, + POWER_UP_END, + POWER_DOWN_END, + POWER_UP_START, + NUM_UNIT, +}; + struct msm_rpmh_master_data { char *master_name; enum master_smem_id smem_id; @@ -66,16 +78,24 @@ static const struct msm_rpmh_master_data rpmh_masters[] = { struct msm_rpmh_master_stats { uint32_t version_id; uint32_t counts; - uint64_t last_entered_at; - uint64_t last_exited_at; + uint64_t last_entered; + uint64_t last_exited; uint64_t accumulated_duration; }; +struct msm_rpmh_profile_unit { + uint64_t value; + uint64_t valid; +}; + struct rpmh_master_stats_prv_data { struct kobj_attribute ka; struct kobject *kobj; }; +static struct msm_rpmh_master_stats apss_master_stats; +static void __iomem *rpmh_unit_base; + static DEFINE_MUTEX(rpmh_stats_mutex); static ssize_t msm_rpmh_master_stats_print_data(char *prvbuf, ssize_t length, @@ -88,7 +108,7 @@ static ssize_t msm_rpmh_master_stats_print_data(char *prvbuf, ssize_t length, "\tSleep Last Exited At:0x%llx\n" "\tSleep Accumulated Duration:0x%llx\n\n", name, record->version_id, record->counts, - record->last_entered_at, record->last_exited_at, + record->last_entered, record->last_exited, record->accumulated_duration); } @@ -100,12 +120,15 @@ static ssize_t msm_rpmh_master_stats_show(struct kobject *kobj, size_t size = 0; struct msm_rpmh_master_stats *record = NULL; - /* - * Read SMEM data written by masters - */ - mutex_lock(&rpmh_stats_mutex); + /* First Read APSS master stats */ + + length = msm_rpmh_master_stats_print_data(buf, PAGE_SIZE, + &apss_master_stats, "APSS"); + + /* Read SMEM data written by other masters */ + for (i = 0, length = 0; i < ARRAY_SIZE(rpmh_masters); i++) { record = (struct msm_rpmh_master_stats *) qcom_smem_get( rpmh_masters[i].pid, @@ -122,30 +145,66 @@ static ssize_t msm_rpmh_master_stats_show(struct kobject *kobj, return length; } +static inline void msm_rpmh_apss_master_stats_update( + struct msm_rpmh_profile_unit *profile_unit) +{ + apss_master_stats.counts++; + apss_master_stats.last_entered = profile_unit[POWER_DOWN_END].value; + apss_master_stats.last_exited = profile_unit[POWER_UP_START].value; + apss_master_stats.accumulated_duration += + (apss_master_stats.last_exited + - apss_master_stats.last_entered); +} + +void msm_rpmh_master_stats_update(void) +{ + int i; + struct msm_rpmh_profile_unit profile_unit[NUM_UNIT]; + + if (!rpmh_unit_base) + return; + + for (i = POWER_DOWN_END; i < NUM_UNIT; i++) { + profile_unit[i].valid = readl_relaxed(rpmh_unit_base + + GET_ADDR(REG_VALID, i)); + + /* + * Do not update APSS stats if valid bit is not set. + * It means APSS did not execute cx-off sequence. + * This can be due to fall through at some point. + */ + + if (!(profile_unit[i].valid & BIT(REG_VALID))) + return; + + profile_unit[i].value = readl_relaxed(rpmh_unit_base + + GET_ADDR(REG_DATA_LO, i)); + profile_unit[i].value |= ((uint64_t) + readl_relaxed(rpmh_unit_base + + GET_ADDR(REG_DATA_HI, i)) << 32); + } + msm_rpmh_apss_master_stats_update(profile_unit); +} +EXPORT_SYMBOL(msm_rpmh_master_stats_update); + static int msm_rpmh_master_stats_probe(struct platform_device *pdev) { struct rpmh_master_stats_prv_data *prvdata = NULL; struct kobject *rpmh_master_stats_kobj = NULL; - int ret = 0; + int ret = -ENOMEM; if (!pdev) return -EINVAL; - prvdata = kzalloc(sizeof(struct rpmh_master_stats_prv_data), - GFP_KERNEL); - if (!prvdata) { - ret = -ENOMEM; - goto fail; - } + prvdata = devm_kzalloc(&pdev->dev, sizeof(*prvdata), GFP_KERNEL); + if (!prvdata) + return ret; rpmh_master_stats_kobj = kobject_create_and_add( "rpmh_stats", power_kobj); - if (!rpmh_master_stats_kobj) { - ret = -ENOMEM; - kfree(prvdata); - goto fail; - } + if (!rpmh_master_stats_kobj) + return ret; prvdata->kobj = rpmh_master_stats_kobj; @@ -158,14 +217,24 @@ static int msm_rpmh_master_stats_probe(struct platform_device *pdev) ret = sysfs_create_file(prvdata->kobj, &prvdata->ka.attr); if (ret) { pr_err("sysfs_create_file failed\n"); - kobject_put(prvdata->kobj); - kfree(prvdata); - goto fail; + goto fail_sysfs; } + rpmh_unit_base = of_iomap(pdev->dev.of_node, 0); + if (!rpmh_unit_base) { + pr_err("Failed to get rpmh_unit_base\n"); + ret = -ENOMEM; + goto fail_iomap; + } + + apss_master_stats.version_id = 0x1; platform_set_drvdata(pdev, prvdata); + return ret; -fail: +fail_iomap: + sysfs_remove_file(prvdata->kobj, &prvdata->ka.attr); +fail_sysfs: + kobject_put(prvdata->kobj); return ret; } @@ -181,14 +250,14 @@ static int msm_rpmh_master_stats_remove(struct platform_device *pdev) sysfs_remove_file(prvdata->kobj, &prvdata->ka.attr); kobject_put(prvdata->kobj); - kfree(prvdata); platform_set_drvdata(pdev, NULL); + iounmap(rpmh_unit_base); return 0; } static const struct of_device_id rpmh_master_table[] = { - {.compatible = "qcom,rpmh-master-stats"}, + {.compatible = "qcom,rpmh-master-stats-v1"}, {}, }; @@ -197,24 +266,11 @@ static struct platform_driver msm_rpmh_master_stats_driver = { .remove = msm_rpmh_master_stats_remove, .driver = { .name = "msm_rpmh_master_stats", - .owner = THIS_MODULE, .of_match_table = rpmh_master_table, }, }; -static int __init msm_rpmh_master_stats_init(void) -{ - return platform_driver_register(&msm_rpmh_master_stats_driver); -} - -static void __exit msm_rpmh_master_stats_exit(void) -{ - platform_driver_unregister(&msm_rpmh_master_stats_driver); -} - -module_init(msm_rpmh_master_stats_init); -module_exit(msm_rpmh_master_stats_exit); - +module_platform_driver(msm_rpmh_master_stats_driver); MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("MSM RPMH Master Statistics driver"); MODULE_ALIAS("platform:msm_rpmh_master_stat_log"); diff --git a/drivers/soc/qcom/rpmh_master_stat.h b/drivers/soc/qcom/rpmh_master_stat.h new file mode 100644 index 000000000000..c3fe7dcff97d --- /dev/null +++ b/drivers/soc/qcom/rpmh_master_stat.h @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2018 The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#if defined(CONFIG_QTI_RPMH_API) && defined(CONFIG_QTI_RPM_STATS_LOG) + +void msm_rpmh_master_stats_update(void); + +#else + +static inline void msm_rpmh_master_stats_update(void) {} + +#endif diff --git a/drivers/soc/qcom/system_pm.c b/drivers/soc/qcom/system_pm.c index 0921f18f2f39..f2ca7c823c4a 100644 --- a/drivers/soc/qcom/system_pm.c +++ b/drivers/soc/qcom/system_pm.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -16,6 +16,7 @@ #include #include #include +#include "rpmh_master_stat.h" #define PDC_TIME_VALID_SHIFT 31 #define PDC_TIME_UPPER_MASK 0xFFFFFF @@ -67,6 +68,7 @@ static int system_sleep_enter(struct cpumask *mask) */ static void system_sleep_exit(void) { + msm_rpmh_master_stats_update(); } static struct system_pm_ops pm_ops = { -- GitLab From e89d1352bc53be45ea91d54d1805c8f796d7a1a4 Mon Sep 17 00:00:00 2001 From: Lingutla Chandrasekhar Date: Mon, 23 Apr 2018 12:37:39 +0530 Subject: [PATCH 0611/1635] trace/sched: use proper specifier to avoid compilation errors WALT utilization is u32 type. But the sched_load_se trace point incorrectly uses %lu as its specifier, this results in a compilation failure. Fix it by using %u specifier. Change-Id: I2369c6bb79e09468301961a837875e7472148a83 Signed-off-by: Lingutla Chandrasekhar --- include/trace/events/sched.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/trace/events/sched.h b/include/trace/events/sched.h index d3000b83b024..43ce05186bba 100644 --- a/include/trace/events/sched.h +++ b/include/trace/events/sched.h @@ -880,7 +880,7 @@ TRACE_EVENT(sched_load_se, #endif ), - TP_printk("cpu=%d path=%s comm=%s pid=%d load=%lu util=%lu util_pelt=%lu util_walt=%lu", + TP_printk("cpu=%d path=%s comm=%s pid=%d load=%lu util=%lu util_pelt=%lu util_walt=%u", __entry->cpu, __get_str(path), __entry->comm, __entry->pid, __entry->load, __entry->util, __entry->util_pelt, __entry->util_walt) -- GitLab From b133ccf7e2388d40ea3809925a51079b3af8a494 Mon Sep 17 00:00:00 2001 From: Chong Gu Date: Wed, 18 Apr 2018 13:19:16 +0800 Subject: [PATCH 0612/1635] input: touchscreen: Disable fts_fw_update_auto disable FW auto update and DEBUG, so that print less log at boot stage. Change-Id: Icc58db38753231049ef5a963e9a10b9c30cae367 Signed-off-by: Chong Gu --- drivers/input/touchscreen/st/fts.c | 250 +----------------- .../touchscreen/st/fts_lib/ftsCrossCompile.h | 2 +- 2 files changed, 11 insertions(+), 241 deletions(-) diff --git a/drivers/input/touchscreen/st/fts.c b/drivers/input/touchscreen/st/fts.c index eaa804f5a722..99aa77338399 100644 --- a/drivers/input/touchscreen/st/fts.c +++ b/drivers/input/touchscreen/st/fts.c @@ -134,8 +134,6 @@ static int fts_mode_handler(struct fts_ts_info *info, int force); static int fts_command(struct fts_ts_info *info, unsigned char cmd); -static int fts_chip_initialization(struct fts_ts_info *info); - void touch_callback(unsigned int status) { /* Empty */ @@ -3271,240 +3269,6 @@ static void fts_event_handler(struct work_struct *work) fts_interrupt_enable(info); } -static int cx_crc_check(void) -{ - unsigned char regAdd1[3] = {FTS_CMD_HW_REG_R, ADDR_CRC_BYTE0, - ADDR_CRC_BYTE1}; - unsigned char val[2]; - unsigned char crc_status; - int res; -#ifndef FTM3_CHIP - u8 cmd[4] = { FTS_CMD_HW_REG_W, 0x00, 0x00, SYSTEM_RESET_VALUE }; - int event_to_search[2] = {(int)EVENTID_ERROR_EVENT, - (int)EVENT_TYPE_CHECKSUM_ERROR}; - u8 readData[FIFO_EVENT_SIZE]; -#endif - /*read 2 bytes because the first one is a dummy byte!*/ - res = fts_readCmd(regAdd1, sizeof(regAdd1), val, 2); - if (res < OK) { - logError(1, "%s %s Cannot read crc status ERROR %08X\n", - tag, __func__, res); - return res; - } - - crc_status = val[1] & CRC_MASK; - if (crc_status != OK) { - logError(1, "%s %s CRC ERROR = %X\n", - tag, __func__, crc_status); - return crc_status; - } - -#ifndef FTM3_CHIP - logError(1, "%s %s: Verifying if Config CRC Error...\n", tag, __func__); - u16ToU8_be(SYSTEM_RESET_ADDRESS, &cmd[1]); - res = fts_writeCmd(cmd, 4); - if (res < OK) { - logError(1, "%s %s Cannot send system resest command:%08X\n", - tag, __func__, res); - return res; - } - setSystemResettedDown(1); - setSystemResettedUp(1); - res = pollForEvent(event_to_search, 2, readData, GENERAL_TIMEOUT); - if (res < OK) { - logError(1, "%s %s: No Config CRC Found!\n", tag, __func__); - } else { - if (readData[2] == CRC_CONFIG_SIGNATURE || - readData[2] == CRC_CONFIG) { - logError(1, "%s:%s: CRC Error for config found! %02X\n", - tag, __func__, readData[2]); - return readData[2]; - } - } -#endif - /*return OK if no CRC error, or a number >OK if crc error*/ - return OK; -} - -static void fts_fw_update_auto(struct work_struct *work) -{ -#ifndef FTM3_CHIP - u8 cmd[4] = { FTS_CMD_HW_REG_W, 0x00, 0x00, SYSTEM_RESET_VALUE }; - int event_to_search[2] = {(int)EVENTID_ERROR_EVENT, - (int)EVENT_TYPE_CHECKSUM_ERROR}; - u8 readData[FIFO_EVENT_SIZE]; - int flag_init = 0; -#endif - int retval = 0; - int retval1 = 0; - int ret; - struct fts_ts_info *info; - struct delayed_work *fwu_work = container_of(work, - struct delayed_work, work); - int crc_status = 0; - int error = 0; - - info = container_of(fwu_work, struct fts_ts_info, fwu_work); - logError(1, "%s Fw Auto Update is starting...\n", tag); - - /* check CRC status */ - ret = cx_crc_check(); - if (ret > OK && ftsInfo.u16_fwVer == 0x0000) { - logError(1, "%s %s: CRC Error or NO FW!\n", tag, __func__); - crc_status = 1; - } else { - crc_status = 0; - logError(1, - "%s %s:NO Error or Impossible to read CRC register!\n", - tag, __func__); - } -#ifdef FTM3_CHIP - retval = flashProcedure(PATH_FILE_FW, crc_status, !crc_status); -#else - retval = flashProcedure(PATH_FILE_FW, crc_status, 1); -#endif - if ((retval & 0xFF000000) == ERROR_FLASH_PROCEDURE) { - logError(1, - "%s %s:firmware update failed and retry! ERROR %08X\n", - tag, __func__, retval); - fts_chip_powercycle(info); /* power reset */ -#ifdef FTM3_CHIP - retval1 = flashProcedure(PATH_FILE_FW, crc_status, !crc_status); -#else - retval1 = flashProcedure(PATH_FILE_FW, crc_status, 1); -#endif - if ((retval1 & 0xFF000000) == ERROR_FLASH_PROCEDURE) { - logError(1, - "%s %s: firmware update failed again! %08X\n", - tag, __func__, retval1); - logError(1, "%s Fw Auto Update Failed!\n", tag); - /* return; */ - } - } -#ifndef FTM3_CHIP - logError(1, "%s %s: Verifying if CX CRC Error...\n", - tag, __func__, ret); - u16ToU8_be(SYSTEM_RESET_ADDRESS, &cmd[1]); - ret = fts_writeCmd(cmd, 4); - if (ret < OK) { - logError(1, - "%s %s Cannot send system reset command ERROR %08X\n", - tag, __func__, ret); - } else { - setSystemResettedDown(1); - setSystemResettedUp(1); - ret = pollForEvent(event_to_search, 2, readData, - GENERAL_TIMEOUT); - if (ret < OK) { - logError(1, "%s %s: No CX CRC Found!\n", tag, __func__); - } else { - if (readData[2] == CRC_CX_MEMORY) { - logError(1, "%s %s: CRC Error for CX found! ", - tag, __func__); - logError(1, "ERROR:%02X\n\n", readData[2]); - flag_init = 1; - } - } - } -#endif - - if (ftsInfo.u8_msScrConfigTuneVer != ftsInfo.u8_msScrCxmemTuneVer || - ftsInfo.u8_ssTchConfigTuneVer != ftsInfo.u8_ssTchCxmemTuneVer) - ret = ERROR_GET_INIT_STATUS; - else if (((ftsInfo.u32_mpPassFlag != INIT_MP) - && (ftsInfo.u32_mpPassFlag != INIT_FIELD)) -#ifndef FTM3_CHIP - || flag_init == 1 -#endif - ) - ret = ERROR_GET_INIT_STATUS; - else - ret = OK; - /** - * initialization status not correct or - * after FW complete update, do initialization. - */ - if (ret == ERROR_GET_INIT_STATUS) { - error = fts_chip_initialization(info); - if (error < OK) { - logError(1, - "%s %s Cannot initialize the chip ERROR %08X\n", - tag, __func__, error); - } - } - - error = fts_init_afterProbe(info); - if (error < OK) { - logError(1, - "%s Cannot initialize the hardware device ERROR %08X\n", - tag, error); - } - logError(1, "%s Fw Auto Update Finished!\n", tag); -} - -static int fts_chip_initialization(struct fts_ts_info *info) -{ - int ret2 = 0; - int retry; - int initretrycnt = 0; - struct TestToDo todoDefault; - - todoDefault.MutualRaw = 1; - todoDefault.MutualRawGap = 1; - todoDefault.MutualCx1 = 0; - todoDefault.MutualCx2 = 1; - todoDefault.MutualCx2Adj = 1; - todoDefault.MutualCxTotal = 0; - todoDefault.MutualCxTotalAdj = 0; - - todoDefault.MutualKeyRaw = 0; - todoDefault.MutualKeyCx1 = 0; - todoDefault.MutualKeyCx2 = 0; - todoDefault.MutualKeyCxTotal = 0; - - todoDefault.SelfForceRaw = 1; - todoDefault.SelfForceRawGap = 0; - todoDefault.SelfForceIx1 = 0; - todoDefault.SelfForceIx2 = 0; - todoDefault.SelfForceIx2Adj = 0; - todoDefault.SelfForceIxTotal = 1; - todoDefault.SelfForceIxTotalAdj = 0; - todoDefault.SelfForceCx1 = 0; - todoDefault.SelfForceCx2 = 0; - todoDefault.SelfForceCx2Adj = 0; - todoDefault.SelfForceCxTotal = 0; - todoDefault.SelfForceCxTotalAdj = 0; - - todoDefault.SelfSenseRaw = 1; - todoDefault.SelfSenseRawGap = 0; - todoDefault.SelfSenseIx1 = 0; - todoDefault.SelfSenseIx2 = 0; - todoDefault.SelfSenseIx2Adj = 0; - todoDefault.SelfSenseIxTotal = 1; - todoDefault.SelfSenseIxTotalAdj = 0; - todoDefault.SelfSenseCx1 = 0; - todoDefault.SelfSenseCx2 = 0; - todoDefault.SelfSenseCx2Adj = 0; - todoDefault.SelfSenseCxTotal = 0; - todoDefault.SelfSenseCxTotalAdj = 0; - - /*initialization error, retry initialization */ - for (retry = 0; retry <= INIT_FLAG_CNT; retry++) { - ret2 = production_test_main(LIMITS_FILE, 1, 1, &todoDefault, - INIT_FIELD); - if (ret2 == OK) - break; - initretrycnt++; - logError(1, - "%s initialization cycle count = %04d - ERROR %08X\n", - tag, initretrycnt, ret2); - fts_chip_powercycle(info); - } - /* initialization error */ - if (ret2 < OK) - logError(1, "%s fts initialization failed 3 times\n", tag); - return ret2; -} #ifdef FTS_USE_POLLING_MODE @@ -4483,7 +4247,7 @@ static int fts_probe(struct i2c_client *client, } info->client->irq = gpio_to_irq(info->bdata->irq_gpio); - logError(1, "%s SET Auto Fw Update:\n", tag); + logError(0, "%s SET Auto Fw Update:\n", tag); /*info->fwu_workqueue =*/ /*create_singlethread_workqueue("fts-fwu-queue");*/ info->fwu_workqueue = alloc_workqueue("fts-fwu-queue", @@ -4492,7 +4256,14 @@ static int fts_probe(struct i2c_client *client, logError(1, "%s ERROR: Cannot create fwu work thread\n", tag); goto ProbeErrorExit_3; } - INIT_DELAYED_WORK(&info->fwu_work, fts_fw_update_auto); + + error = fts_init_afterProbe(info); + if (error < OK) { + logError(1, + "%s Cannot initialize the hardware device ERROR %08X\n", + tag, error); + goto ProbeErrorExit_3; + } logError(1, "%s SET Event Handler:\n", tag); /*wake_lock_init(&info->wakelock, WAKE_LOCK_SUSPEND, "fts_tp");*/ @@ -4700,8 +4471,7 @@ static int fts_probe(struct i2c_client *client, goto ProbeErrorExit_11; } #endif - queue_delayed_work(info->fwu_workqueue, &info->fwu_work, - msecs_to_jiffies(EXP_FN_WORK_DELAY_MS)); + logError(1, "%s Probe Finished!\n", tag); return OK; diff --git a/drivers/input/touchscreen/st/fts_lib/ftsCrossCompile.h b/drivers/input/touchscreen/st/fts_lib/ftsCrossCompile.h index 90420fdc0e69..400d59c25a65 100644 --- a/drivers/input/touchscreen/st/fts_lib/ftsCrossCompile.h +++ b/drivers/input/touchscreen/st/fts_lib/ftsCrossCompile.h @@ -37,7 +37,7 @@ #define __FTS_CROSS_COMPILE_H //#define NDK -#define DEBUG +//#define DEBUG #include #include -- GitLab From 055e4854f4b479835238b673b1f02a7128527bc1 Mon Sep 17 00:00:00 2001 From: Anirudh Ghayal Date: Thu, 22 Feb 2018 23:55:53 +0530 Subject: [PATCH 0613/1635] power: smb5-lib: Disable charging on detecting a debug battery Disable battery charging on detecting a debug board to avoid damaging it. Change-Id: I160c62e69cbc987131d57099c94698de1d684c2c Signed-off-by: Anirudh Ghayal --- drivers/power/supply/qcom/smb5-lib.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/drivers/power/supply/qcom/smb5-lib.c b/drivers/power/supply/qcom/smb5-lib.c index fff32eccde99..95c49c4eea0c 100644 --- a/drivers/power/supply/qcom/smb5-lib.c +++ b/drivers/power/supply/qcom/smb5-lib.c @@ -707,20 +707,21 @@ void smblib_suspend_on_debug_battery(struct smb_charger *chg) int rc; union power_supply_propval val; - if (!chg->suspend_input_on_debug_batt) - return; - rc = power_supply_get_property(chg->bms_psy, POWER_SUPPLY_PROP_DEBUG_BATTERY, &val); if (rc < 0) { smblib_err(chg, "Couldn't get debug battery prop rc=%d\n", rc); return; } - - vote(chg->usb_icl_votable, DEBUG_BOARD_VOTER, val.intval, 0); - vote(chg->dc_suspend_votable, DEBUG_BOARD_VOTER, val.intval, 0); - if (val.intval) - pr_info("Input suspended: Fake battery\n"); + if (chg->suspend_input_on_debug_batt) { + vote(chg->usb_icl_votable, DEBUG_BOARD_VOTER, val.intval, 0); + vote(chg->dc_suspend_votable, DEBUG_BOARD_VOTER, val.intval, 0); + if (val.intval) + pr_info("Input suspended: Fake battery\n"); + } else { + vote(chg->chg_disable_votable, DEBUG_BOARD_VOTER, + val.intval, 0); + } } int smblib_rerun_apsd_if_required(struct smb_charger *chg) -- GitLab From c8b50d264c3bc48d04ec1918ae9f87a604d57ce1 Mon Sep 17 00:00:00 2001 From: Raghavendra Kakarla Date: Fri, 9 Mar 2018 18:27:33 +0530 Subject: [PATCH 0614/1635] cpuidle: lpm-levels: Add support to parse LPM parameters Add support for providing LPM prediction parameters in device tree and parsing them. Change-Id: I60fd7e8d32505e212100b886df29b72a9999ca6d Signed-off-by: Raghavendra Kakarla --- .../bindings/arm/msm/lpm-levels.txt | 26 +++++++++- drivers/cpuidle/lpm-levels-of.c | 48 +++++++++++++++++-- drivers/cpuidle/lpm-levels.c | 46 ++++++++---------- drivers/cpuidle/lpm-levels.h | 14 ++++++ 4 files changed, 102 insertions(+), 32 deletions(-) diff --git a/Documentation/devicetree/bindings/arm/msm/lpm-levels.txt b/Documentation/devicetree/bindings/arm/msm/lpm-levels.txt index 55d06b25b2de..1a357b10418d 100644 --- a/Documentation/devicetree/bindings/arm/msm/lpm-levels.txt +++ b/Documentation/devicetree/bindings/arm/msm/lpm-levels.txt @@ -28,6 +28,14 @@ Required properties: mask of the cluster mode in the composite state ID used to define cluster low power modes in PSCI. +Optional properties: + - qcom,disable-prediction: This property is used to indicate the LPM + governor will not use LPM prediction for this cluster. + - qcom,clstr-tmr-add: This property is used as correction timer for + wrong prediction by lpm prediction algorithm for cluster predictions. + This value should be between 100 to 1500. Higher values would mean + longer time staying in shallower state before waking up to select a + deeper state in case of wrong prediction. qcom,pm-cluster contains qcom,pm-cluster-level nodes which identify the various low power modes that the cluster can enter. The qcom,pm-cluster node should also include another cluster node or a cpu @@ -77,8 +85,22 @@ that share the parameters.It contains the following properties. - qcom,pm-cpu-levels: The different low power modes that a CPU could enter. The following section explains the required properties of this node. - -qcom,use-prediction: This optional property is used to indicate the - the LPM governor is to apply sleep prediction to this cluster. + +Optional properties: + - qcom,disable-prediction: This property is used to indicate the + LPM governor is to disable sleep prediction to this cpu. + - qcom,ref-stddev: This property is used as reference standard deviation + in lpm prediction algorithm. This value should be between 100 to 1000. + Higher value would result in more predictions and thereby resulting in + shallower low power modes. + - qcom,tmr-add: This property is used as correction timer for wrong + prediction by lpm prediction algorithm. This value should be between + 100 to 1500. Higher values would mean longer time staying in shallower + state before waking up to select a deeper state in case of wrong prediction. + - qcom,ref-premature-cnt: This property is used as reference premature + count to predict next sleep state by the prediction algorithm. This value + should be between 1 to 5. Higher value for this parameter would result in + less predictions to disallow deeper low power modes. [Node bindings for qcom,pm-cpu-levels] Required properties: diff --git a/drivers/cpuidle/lpm-levels-of.c b/drivers/cpuidle/lpm-levels-of.c index 030aacb7cba8..80d89e9d2083 100644 --- a/drivers/cpuidle/lpm-levels-of.c +++ b/drivers/cpuidle/lpm-levels-of.c @@ -178,8 +178,8 @@ static ssize_t lpm_latency_show(struct kobject *kobj, struct kernel_param kp; struct lpm_level_avail *avail = get_avail_ptr(kobj, attr); - if (!avail) - pr_info("Error\n"); + if (WARN_ON(!avail)) + return -EINVAL; kp.arg = &avail->latency_us; @@ -197,8 +197,15 @@ ssize_t lpm_enable_show(struct kobject *kobj, struct kobj_attribute *attr, { int ret = 0; struct kernel_param kp; + struct lpm_level_avail *avail = get_avail_ptr(kobj, attr); + + if (WARN_ON(!avail)) + return -EINVAL; + + kp.arg = get_enabled_ptr(attr, avail); + if (WARN_ON(!kp.arg)) + return -EINVAL; - kp.arg = get_enabled_ptr(attr, get_avail_ptr(kobj, attr)); ret = param_get_bool(buf, &kp); if (ret > 0) { strlcat(buf, "\n", PAGE_SIZE); @@ -450,6 +457,17 @@ static int parse_cluster_params(struct device_node *node, if (ret) goto fail; + key = "qcom,disable-prediction"; + c->lpm_prediction = !(of_property_read_bool(node, key)); + + if (c->lpm_prediction) { + key = "qcom,clstr-tmr-add"; + ret = of_property_read_u32(node, key, &c->tmr_add); + if (ret || c->tmr_add < TIMER_ADD_LOW || + c->tmr_add > TIMER_ADD_HIGH) + c->tmr_add = DEFAULT_TIMER_ADD; + } + /* Set default_level to 0 as default */ c->default_level = 0; @@ -711,8 +729,28 @@ static int parse_cpu_levels(struct device_node *node, struct lpm_cluster *c) if (ret) goto failed_parse_params; - key = "qcom,use-prediction"; - cpu->lpm_prediction = of_property_read_bool(node, key); + key = "qcom,disable-prediction"; + cpu->lpm_prediction = !(of_property_read_bool(node, key)); + + if (cpu->lpm_prediction) { + key = "qcom,ref-stddev"; + ret = of_property_read_u32(node, key, &cpu->ref_stddev); + if (ret || cpu->ref_stddev < STDDEV_LOW || + cpu->ref_stddev > STDDEV_HIGH) + cpu->ref_stddev = DEFAULT_STDDEV; + + key = "qcom,tmr-add"; + ret = of_property_read_u32(node, key, &cpu->tmr_add); + if (ret || cpu->tmr_add < TIMER_ADD_LOW || + cpu->tmr_add > TIMER_ADD_HIGH) + cpu->tmr_add = DEFAULT_TIMER_ADD; + + key = "qcom,ref-premature-cnt"; + ret = of_property_read_u32(node, key, &cpu->ref_premature_cnt); + if (ret || cpu->ref_premature_cnt < PREMATURE_CNT_LOW || + cpu->ref_premature_cnt > PREMATURE_CNT_HIGH) + cpu->ref_premature_cnt = DEFAULT_PREMATURE_CNT; + } key = "parse_cpu"; ret = parse_cpu(node, cpu); diff --git a/drivers/cpuidle/lpm-levels.c b/drivers/cpuidle/lpm-levels.c index b9ab79165369..bb4dd7891138 100644 --- a/drivers/cpuidle/lpm-levels.c +++ b/drivers/cpuidle/lpm-levels.c @@ -89,15 +89,6 @@ struct lpm_cluster *lpm_root_node; static bool lpm_prediction = true; module_param_named(lpm_prediction, lpm_prediction, bool, 0664); -static uint32_t ref_stddev = 500; -module_param_named(ref_stddev, ref_stddev, uint, 0664); - -static uint32_t tmr_add = 1000; -module_param_named(tmr_add, tmr_add, uint, 0664); - -static uint32_t ref_premature_cnt = 1; -module_param_named(ref_premature_cnt, ref_premature_cnt, uint, 0664); - static uint32_t bias_hyst; module_param_named(bias_hyst, bias_hyst, uint, 0664); @@ -493,7 +484,7 @@ static uint64_t lpm_cpuidle_predict(struct cpuidle_device *dev, * ignore one maximum sample and retry */ if (((avg > stddev * 6) && (divisor >= (MAXSAMPLES - 1))) - || stddev <= ref_stddev) { + || stddev <= cpu->ref_stddev) { history->stime = ktime_to_us(ktime_get()) + avg; return avg; } else if (divisor > (MAXSAMPLES - 1)) { @@ -518,7 +509,7 @@ static uint64_t lpm_cpuidle_predict(struct cpuidle_device *dev, total += history->resi[i]; } } - if (failed >= ref_premature_cnt) { + if (failed >= cpu->ref_premature_cnt) { *idx_restrict = j; do_div(total, failed); for (i = 0; i < j; i++) { @@ -542,8 +533,9 @@ static uint64_t lpm_cpuidle_predict(struct cpuidle_device *dev, static inline void invalidate_predict_history(struct cpuidle_device *dev) { struct lpm_history *history = &per_cpu(hist, dev->cpu); + struct lpm_cpu *lpm_cpu = per_cpu(cpu_lpm, dev->cpu); - if (!lpm_prediction) + if (!lpm_prediction || !lpm_cpu->lpm_prediction) return; if (history->hinvalid) { @@ -558,8 +550,9 @@ static void clear_predict_history(void) struct lpm_history *history; int i; unsigned int cpu; + struct lpm_cpu *lpm_cpu = per_cpu(cpu_lpm, raw_smp_processor_id()); - if (!lpm_prediction) + if (!lpm_prediction || !lpm_cpu->lpm_prediction) return; for_each_possible_cpu(cpu) { @@ -678,8 +671,8 @@ static int cpu_power_select(struct cpuidle_device *dev, if ((predicted || (idx_restrict != (cpu->nlevels + 1))) && ((best_level >= 0) && (best_level < (cpu->nlevels-1)))) { - htime = predicted + tmr_add; - if (htime == tmr_add) + htime = predicted + cpu->tmr_add; + if (htime == cpu->tmr_add) htime = idx_restrict_time; else if (htime > max_residency[best_level]) htime = max_residency[best_level]; @@ -742,14 +735,14 @@ static uint64_t get_cluster_sleep_time(struct lpm_cluster *cluster, if (*next_event_c < next_event) next_event = *next_event_c; - if (from_idle && lpm_prediction) { + if (from_idle && lpm_prediction && cluster->lpm_prediction) { history = &per_cpu(hist, cpu); if (history->stime && (history->stime < prediction)) prediction = history->stime; } } - if (from_idle && lpm_prediction) { + if (from_idle && lpm_prediction && cluster->lpm_prediction) { if (prediction > ktime_to_us(ktime_get())) *pred_time = prediction - ktime_to_us(ktime_get()); } @@ -768,7 +761,7 @@ static int cluster_predict(struct lpm_cluster *cluster, struct cluster_history *history = &cluster->history; int64_t cur_time = ktime_to_us(ktime_get()); - if (!lpm_prediction) + if (!lpm_prediction || !cluster->lpm_prediction) return 0; if (history->hinvalid) { @@ -843,7 +836,7 @@ static void update_cluster_history(struct cluster_history *history, int idx) struct lpm_cluster *cluster = container_of(history, struct lpm_cluster, history); - if (!lpm_prediction) + if (!lpm_prediction || !cluster->lpm_prediction) return; if ((history->entry_idx == -1) || (history->entry_idx == idx)) { @@ -904,7 +897,7 @@ static void clear_cl_predict_history(void) struct lpm_cluster *cluster = lpm_root_node; struct list_head *list; - if (!lpm_prediction) + if (!lpm_prediction || !cluster->lpm_prediction) return; clear_cl_history_each(&cluster->history); @@ -1041,7 +1034,7 @@ static int cluster_configure(struct lpm_cluster *cluster, int idx, cluster->child_cpus.bits[0], from_idle); lpm_stats_cluster_enter(cluster->stats, idx); - if (from_idle && lpm_prediction) + if (from_idle && lpm_prediction && cluster->lpm_prediction) update_cluster_history_time(&cluster->history, idx, ktime_to_us(ktime_get())); } @@ -1063,7 +1056,8 @@ static int cluster_configure(struct lpm_cluster *cluster, int idx, if (predicted && (idx < (cluster->nlevels - 1))) { struct power_params *pwr_params = &cluster->levels[idx].pwr; - clusttimer_start(cluster, pwr_params->max_residency + tmr_add); + clusttimer_start(cluster, pwr_params->max_residency + + cluster->tmr_add); } return 0; @@ -1117,7 +1111,8 @@ static void cluster_prepare(struct lpm_cluster *cluster, &cluster->levels[0].pwr; clusttimer_start(cluster, - pwr_params->max_residency + tmr_add); + pwr_params->max_residency + + cluster->tmr_add); goto failed; } @@ -1332,8 +1327,9 @@ static void update_history(struct cpuidle_device *dev, int idx) { struct lpm_history *history = &per_cpu(hist, dev->cpu); uint32_t tmr = 0; + struct lpm_cpu *lpm_cpu = per_cpu(cpu_lpm, dev->cpu); - if (!lpm_prediction) + if (!lpm_prediction || !lpm_cpu->lpm_prediction) return; if (history->htmr_wkup) { @@ -1391,7 +1387,7 @@ static int lpm_cpuidle_enter(struct cpuidle_device *dev, update_history(dev, idx); trace_cpu_idle_exit(idx, success); local_irq_enable(); - if (lpm_prediction) { + if (lpm_prediction && cpu->lpm_prediction) { histtimer_cancel(); clusttimer_cancel(); } diff --git a/drivers/cpuidle/lpm-levels.h b/drivers/cpuidle/lpm-levels.h index 8c66bd73402c..a6c7c5b5986c 100644 --- a/drivers/cpuidle/lpm-levels.h +++ b/drivers/cpuidle/lpm-levels.h @@ -15,6 +15,15 @@ #define NR_LPM_LEVELS 8 #define MAXSAMPLES 5 #define CLUST_SMPL_INVLD_TIME 40000 +#define DEFAULT_PREMATURE_CNT 3 +#define DEFAULT_STDDEV 100 +#define DEFAULT_TIMER_ADD 100 +#define TIMER_ADD_LOW 100 +#define TIMER_ADD_HIGH 1500 +#define STDDEV_LOW 100 +#define STDDEV_HIGH 1000 +#define PREMATURE_CNT_LOW 1 +#define PREMATURE_CNT_HIGH 5 struct power_params { uint32_t latency_us; /* Enter + Exit latency */ @@ -42,6 +51,9 @@ struct lpm_cpu { int nlevels; unsigned int psci_mode_shift; unsigned int psci_mode_mask; + uint32_t ref_stddev; + uint32_t ref_premature_cnt; + uint32_t tmr_add; bool lpm_prediction; struct cpuidle_driver *drv; struct lpm_cluster *parent; @@ -96,6 +108,8 @@ struct lpm_cluster { int min_child_level; int default_level; int last_level; + uint32_t tmr_add; + bool lpm_prediction; struct list_head cpu; spinlock_t sync_lock; struct cpumask child_cpus; -- GitLab From a73c9bca682673630cd95a7fa55190f53bab73cf Mon Sep 17 00:00:00 2001 From: Patrik Torstensson Date: Thu, 22 Mar 2018 18:18:04 -0700 Subject: [PATCH 0615/1635] BACKPORT: dm verity: add 'check_at_most_once' option to only validate hashes once This allows platforms that are CPU/memory contrained to verify data blocks only the first time they are read from the data device, rather than every time. As such, it provides a reduced level of security because only offline tampering of the data device's content will be detected, not online tampering. Hash blocks are still verified each time they are read from the hash device, since verification of hash blocks is less performance critical than data blocks, and a hash block will not be verified any more after all the data blocks it covers have been verified anyway. This option introduces a bitset that is used to check if a block has been validated before or not. A block can be validated more than once as there is no thread protection for the bitset. These changes were developed and tested on entry-level Android Go devices. Bug: 72664474 Change-Id: Ie5f1ffda93c7f48e95b90ca80fe3f896c11f7baf Signed-off-by: Mike Snitzer (cherry picked from commit 843f38d382b1ca2f6f4ae2ef7c35933e6319ffbb) Signed-off-by: Patrik Torstensson --- Documentation/device-mapper/verity.txt | 11 +++++ drivers/md/dm-verity-target.c | 64 ++++++++++++++++++++++++-- drivers/md/dm-verity.h | 1 + 3 files changed, 71 insertions(+), 5 deletions(-) diff --git a/Documentation/device-mapper/verity.txt b/Documentation/device-mapper/verity.txt index 89fd8f9a259f..b3d2e4a42255 100644 --- a/Documentation/device-mapper/verity.txt +++ b/Documentation/device-mapper/verity.txt @@ -109,6 +109,17 @@ fec_start This is the offset, in blocks, from the start of the FEC device to the beginning of the encoding data. +check_at_most_once + Verify data blocks only the first time they are read from the data device, + rather than every time. This reduces the overhead of dm-verity so that it + can be used on systems that are memory and/or CPU constrained. However, it + provides a reduced level of security because only offline tampering of the + data device's content will be detected, not online tampering. + + Hash blocks are still verified each time they are read from the hash device, + since verification of hash blocks is less performance critical than data + blocks, and a hash block will not be verified any more after all the data + blocks it covers have been verified anyway. Theory of operation =================== diff --git a/drivers/md/dm-verity-target.c b/drivers/md/dm-verity-target.c index 5c6d441a8a8a..751855c24d5a 100644 --- a/drivers/md/dm-verity-target.c +++ b/drivers/md/dm-verity-target.c @@ -32,6 +32,7 @@ #define DM_VERITY_OPT_LOGGING "ignore_corruption" #define DM_VERITY_OPT_RESTART "restart_on_corruption" #define DM_VERITY_OPT_IGN_ZEROES "ignore_zero_blocks" +#define DM_VERITY_OPT_AT_MOST_ONCE "check_at_most_once" #define DM_VERITY_OPTS_MAX (2 + DM_VERITY_OPTS_FEC) @@ -473,6 +474,18 @@ static int verity_bv_zero(struct dm_verity *v, struct dm_verity_io *io, return 0; } +/* + * Moves the bio iter one data block forward. + */ +static inline void verity_bv_skip_block(struct dm_verity *v, + struct dm_verity_io *io, + struct bvec_iter *iter) +{ + struct bio *bio = dm_bio_from_per_bio_data(io, v->ti->per_io_data_size); + + bio_advance_iter(bio, iter, 1 << v->data_dev_block_bits); +} + /* * Verify one "dm_verity_io" structure. */ @@ -486,9 +499,16 @@ static int verity_verify_io(struct dm_verity_io *io) for (b = 0; b < io->n_blocks; b++) { int r; + sector_t cur_block = io->block + b; struct ahash_request *req = verity_io_hash_req(v, io); - r = verity_hash_for_block(v, io, io->block + b, + if (v->validated_blocks && + likely(test_bit(cur_block, v->validated_blocks))) { + verity_bv_skip_block(v, io, &io->iter); + continue; + } + + r = verity_hash_for_block(v, io, cur_block, verity_io_want_digest(v, io), &is_zero); if (unlikely(r < 0)) @@ -522,13 +542,16 @@ static int verity_verify_io(struct dm_verity_io *io) return r; if (likely(memcmp(verity_io_real_digest(v, io), - verity_io_want_digest(v, io), v->digest_size) == 0)) + verity_io_want_digest(v, io), v->digest_size) == 0)) { + if (v->validated_blocks) + set_bit(cur_block, v->validated_blocks); continue; + } else if (verity_fec_decode(v, io, DM_VERITY_BLOCK_TYPE_DATA, - io->block + b, NULL, &start) == 0) + cur_block, NULL, &start) == 0) continue; else if (verity_handle_err(v, DM_VERITY_BLOCK_TYPE_DATA, - io->block + b)) + cur_block)) return -EIO; } @@ -721,6 +744,8 @@ void verity_status(struct dm_target *ti, status_type_t type, args += DM_VERITY_OPTS_FEC; if (v->zero_digest) args++; + if (v->validated_blocks) + args++; if (!args) return; DMEMIT(" %u", args); @@ -739,6 +764,8 @@ void verity_status(struct dm_target *ti, status_type_t type, } if (v->zero_digest) DMEMIT(" " DM_VERITY_OPT_IGN_ZEROES); + if (v->validated_blocks) + DMEMIT(" " DM_VERITY_OPT_AT_MOST_ONCE); sz = verity_fec_status_table(v, sz, result, maxlen); break; } @@ -788,6 +815,7 @@ void verity_dtr(struct dm_target *ti) if (v->bufio) dm_bufio_client_destroy(v->bufio); + kvfree(v->validated_blocks); kfree(v->salt); kfree(v->root_digest); kfree(v->zero_digest); @@ -808,6 +836,26 @@ void verity_dtr(struct dm_target *ti) kfree(v); } +static int verity_alloc_most_once(struct dm_verity *v) +{ + struct dm_target *ti = v->ti; + + /* the bitset can only handle INT_MAX blocks */ + if (v->data_blocks > INT_MAX) { + ti->error = "device too large to use check_at_most_once"; + return -E2BIG; + } + + v->validated_blocks = kvzalloc(BITS_TO_LONGS(v->data_blocks) * + sizeof(unsigned long), GFP_KERNEL); + if (!v->validated_blocks) { + ti->error = "failed to allocate bitset for check_at_most_once"; + return -ENOMEM; + } + + return 0; +} + static int verity_alloc_zero_digest(struct dm_verity *v) { int r = -ENOMEM; @@ -877,6 +925,12 @@ static int verity_parse_opt_args(struct dm_arg_set *as, struct dm_verity *v) } continue; + } else if (!strcasecmp(arg_name, DM_VERITY_OPT_AT_MOST_ONCE)) { + r = verity_alloc_most_once(v); + if (r) + return r; + continue; + } else if (verity_is_fec_opt_arg(arg_name)) { r = verity_fec_parse_opt_args(as, v, &argc, arg_name); if (r) @@ -1144,7 +1198,7 @@ int verity_ctr(struct dm_target *ti, unsigned argc, char **argv) static struct target_type verity_target = { .name = "verity", - .version = {1, 3, 0}, + .version = {1, 4, 0}, .module = THIS_MODULE, .ctr = verity_ctr, .dtr = verity_dtr, diff --git a/drivers/md/dm-verity.h b/drivers/md/dm-verity.h index 29831d66d9c2..e80e06aa5ec6 100644 --- a/drivers/md/dm-verity.h +++ b/drivers/md/dm-verity.h @@ -63,6 +63,7 @@ struct dm_verity { sector_t hash_level_block[DM_VERITY_MAX_LEVELS]; struct dm_verity_fec *fec; /* forward error correction */ + unsigned long *validated_blocks; /* bitset blocks validated */ }; struct dm_verity_io { -- GitLab From 303d90c82cd3dccf41423b265d853f25ed161783 Mon Sep 17 00:00:00 2001 From: Oleg Perelet Date: Tue, 17 Apr 2018 17:41:17 -0700 Subject: [PATCH 0616/1635] msm: kgsl: Enable CPU vote for GPU bus DCVS Enable CPU side devfreq governor and CPU side vote for bus GPU DCVS. Change-Id: I4160cc9b54edcce1d14f46e8e92b8b4b724373b4 Signed-off-by: Oleg Perelet --- drivers/gpu/msm/kgsl_pwrctrl.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/gpu/msm/kgsl_pwrctrl.c b/drivers/gpu/msm/kgsl_pwrctrl.c index c77bb17e68bd..1ad0a6e3b637 100644 --- a/drivers/gpu/msm/kgsl_pwrctrl.c +++ b/drivers/gpu/msm/kgsl_pwrctrl.c @@ -1811,9 +1811,6 @@ static void kgsl_pwrctrl_axi(struct kgsl_device *device, int state) { struct kgsl_pwrctrl *pwr = &device->pwrctrl; - if (kgsl_gmu_gpmu_isenabled(device)) - return; - if (test_bit(KGSL_PWRFLAGS_AXI_ON, &pwr->ctrl_flags)) return; -- GitLab From d2c5084df58cfb70d7b0b95b00dd0dc6cab5854e Mon Sep 17 00:00:00 2001 From: Subash Abhinov Kasiviswanathan Date: Tue, 6 Mar 2018 15:20:09 -0700 Subject: [PATCH 0617/1635] net: qualcomm: rmnet: Add support for UL aggregation This patch brings in the implementation for the UL aggregation for packets sent from rmnet. The delay argument in schedule_delayed_work(struct delayed_work *dwork, unsigned long delay) API is jiffies. The system tick for seems to be 100Hz, so the minimum time resolution for the work to be scheduled is 10ms. Switch to hrtimer to achieve 3 ms granularity with a current timer of 1ms for the flush thread. A workqueue is immediately scheduled in the same context after this timer expiry to do the tx work. CRs-Fixed: 2156182 Change-Id: I6beb47d86b133b1db85d9a352eae8870e554eebb Signed-off-by: Subash Abhinov Kasiviswanathan --- .../ethernet/qualcomm/rmnet/rmnet_config.c | 8 +- .../ethernet/qualcomm/rmnet/rmnet_config.h | 13 ++ .../ethernet/qualcomm/rmnet/rmnet_handlers.c | 20 +- .../net/ethernet/qualcomm/rmnet/rmnet_map.h | 4 + .../ethernet/qualcomm/rmnet/rmnet_map_data.c | 193 ++++++++++++++++++ .../ethernet/qualcomm/rmnet/rmnet_private.h | 3 + 6 files changed, 239 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c b/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c index 1573e0b45a68..43fd9ec80825 100644 --- a/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c +++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c @@ -21,6 +21,7 @@ #include "rmnet_handlers.h" #include "rmnet_vnd.h" #include "rmnet_private.h" +#include "rmnet_map.h" /* Locking scheme - * The shared resource which needs to be protected is realdev->rx_handler_data. @@ -66,6 +67,8 @@ static int rmnet_unregister_real_device(struct net_device *real_dev, if (port->nr_rmnet_devs) return -EINVAL; + rmnet_map_tx_aggregate_exit(port); + kfree(port); netdev_rx_handler_unregister(real_dev); @@ -104,6 +107,8 @@ static int rmnet_register_real_device(struct net_device *real_dev) for (entry = 0; entry < RMNET_MAX_LOGICAL_EP; entry++) INIT_HLIST_HEAD(&port->muxed_ep[entry]); + rmnet_map_tx_aggregate_init(port); + netdev_dbg(real_dev, "registered with rmnet\n"); return 0; } @@ -136,7 +141,8 @@ static int rmnet_newlink(struct net *src_net, struct net_device *dev, struct nlattr *tb[], struct nlattr *data[], struct netlink_ext_ack *extack) { - u32 data_format = RMNET_FLAGS_INGRESS_DEAGGREGATION; + u32 data_format = RMNET_FLAGS_INGRESS_DEAGGREGATION | + RMNET_EGRESS_FORMAT_AGGREGATION; struct net_device *real_dev; int mode = RMNET_EPMODE_VND; struct rmnet_endpoint *ep; diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.h b/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.h index af2d2dea1162..d792d831c2ed 100644 --- a/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.h +++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.h @@ -37,6 +37,19 @@ struct rmnet_port { u8 rmnet_mode; struct hlist_head muxed_ep[RMNET_MAX_LOGICAL_EP]; struct net_device *bridge_ep; + + u16 egress_agg_size; + u16 egress_agg_count; + + /* Protect aggregation related elements */ + spinlock_t agg_lock; + + struct sk_buff *agg_skb; + int agg_state; + u8 agg_count; + struct timespec agg_time; + struct timespec agg_last; + struct hrtimer hrtimer; }; extern struct rtnl_link_ops rmnet_link_ops; diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_handlers.c b/drivers/net/ethernet/qualcomm/rmnet/rmnet_handlers.c index 253b0acc9c83..1b4555263a55 100644 --- a/drivers/net/ethernet/qualcomm/rmnet/rmnet_handlers.c +++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_handlers.c @@ -191,8 +191,26 @@ static int rmnet_map_egress_handler(struct sk_buff *skb, map_header->mux_id = mux_id; - skb->protocol = htons(ETH_P_MAP); + if (port->data_format & RMNET_EGRESS_FORMAT_AGGREGATION) { + int non_linear_skb; + + if (rmnet_map_tx_agg_skip(skb, required_headroom)) + goto done; + + non_linear_skb = (orig_dev->features & NETIF_F_GSO) && + skb_is_nonlinear(skb); + + if (non_linear_skb) { + if (unlikely(__skb_linearize(skb))) + goto done; + } + rmnet_map_tx_aggregate(skb, port); + return -EINPROGRESS; + } + +done: + skb->protocol = htons(ETH_P_MAP); return 0; fail: diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_map.h b/drivers/net/ethernet/qualcomm/rmnet/rmnet_map.h index 884f1f52dcc2..13d5e1af7742 100644 --- a/drivers/net/ethernet/qualcomm/rmnet/rmnet_map.h +++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_map.h @@ -91,5 +91,9 @@ void rmnet_map_command(struct sk_buff *skb, struct rmnet_port *port); int rmnet_map_checksum_downlink_packet(struct sk_buff *skb, u16 len); void rmnet_map_checksum_uplink_packet(struct sk_buff *skb, struct net_device *orig_dev); +int rmnet_map_tx_agg_skip(struct sk_buff *skb, int offset); +void rmnet_map_tx_aggregate(struct sk_buff *skb, struct rmnet_port *port); +void rmnet_map_tx_aggregate_init(struct rmnet_port *port); +void rmnet_map_tx_aggregate_exit(struct rmnet_port *port); #endif /* _RMNET_MAP_H_ */ diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_map_data.c b/drivers/net/ethernet/qualcomm/rmnet/rmnet_map_data.c index a6ea09416f8d..49373da7fab9 100644 --- a/drivers/net/ethernet/qualcomm/rmnet/rmnet_map_data.c +++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_map_data.c @@ -400,3 +400,196 @@ void rmnet_map_checksum_uplink_packet(struct sk_buff *skb, ul_header->csum_enabled = 0; ul_header->udp_ip4_ind = 0; } + +struct rmnet_agg_work { + struct work_struct work; + struct rmnet_port *port; +}; + +long rmnet_agg_time_limit __read_mostly = 1000000L; +long rmnet_agg_bypass_time __read_mostly = 10000000L; + +int rmnet_map_tx_agg_skip(struct sk_buff *skb, int offset) +{ + u8 *packet_start = skb->data + offset; + int is_icmp = 0; + + if (skb->protocol == htons(ETH_P_IP)) { + struct iphdr *ip4h = (struct iphdr *)(packet_start); + + if (ip4h->protocol == IPPROTO_ICMP) + is_icmp = 1; + } else if (skb->protocol == htons(ETH_P_IPV6)) { + struct ipv6hdr *ip6h = (struct ipv6hdr *)(packet_start); + + if (ip6h->nexthdr == IPPROTO_ICMPV6) { + is_icmp = 1; + } else if (ip6h->nexthdr == NEXTHDR_FRAGMENT) { + struct frag_hdr *frag; + + frag = (struct frag_hdr *)(packet_start + + sizeof(struct ipv6hdr)); + if (frag->nexthdr == IPPROTO_ICMPV6) + is_icmp = 1; + } + } + + return is_icmp; +} + +static void rmnet_map_flush_tx_packet_work(struct work_struct *work) +{ + struct rmnet_agg_work *real_work; + struct rmnet_port *port; + unsigned long flags; + struct sk_buff *skb; + int agg_count = 0; + + real_work = (struct rmnet_agg_work *)work; + port = real_work->port; + skb = NULL; + + spin_lock_irqsave(&port->agg_lock, flags); + if (likely(port->agg_state == -EINPROGRESS)) { + /* Buffer may have already been shipped out */ + if (likely(port->agg_skb)) { + skb = port->agg_skb; + agg_count = port->agg_count; + port->agg_skb = NULL; + port->agg_count = 0; + memset(&port->agg_time, 0, sizeof(struct timespec)); + } + port->agg_state = 0; + } + + spin_unlock_irqrestore(&port->agg_lock, flags); + if (skb) { + skb->protocol = htons(ETH_P_MAP); + dev_queue_xmit(skb); + } + + kfree(work); +} + +enum hrtimer_restart rmnet_map_flush_tx_packet_queue(struct hrtimer *t) +{ + struct rmnet_agg_work *work; + struct rmnet_port *port; + + port = container_of(t, struct rmnet_port, hrtimer); + + work = kmalloc(sizeof(*work), GFP_ATOMIC); + if (!work) { + port->agg_state = 0; + + return HRTIMER_NORESTART; + } + + INIT_WORK(&work->work, rmnet_map_flush_tx_packet_work); + work->port = port; + schedule_work((struct work_struct *)work); + return HRTIMER_NORESTART; +} + +void rmnet_map_tx_aggregate(struct sk_buff *skb, struct rmnet_port *port) +{ + struct timespec diff, last; + int size, agg_count = 0; + struct sk_buff *agg_skb; + unsigned long flags; + u8 *dest_buff; + +new_packet: + spin_lock_irqsave(&port->agg_lock, flags); + memcpy(&last, &port->agg_last, sizeof(struct timespec)); + getnstimeofday(&port->agg_last); + + if (!port->agg_skb) { + /* Check to see if we should agg first. If the traffic is very + * sparse, don't aggregate. We will need to tune this later + */ + diff = timespec_sub(port->agg_last, last); + + if (diff.tv_sec > 0 || diff.tv_nsec > rmnet_agg_bypass_time) { + spin_unlock_irqrestore(&port->agg_lock, flags); + skb->protocol = htons(ETH_P_MAP); + dev_queue_xmit(skb); + return; + } + + size = port->egress_agg_size - skb->len; + port->agg_skb = skb_copy_expand(skb, 0, size, GFP_ATOMIC); + if (!port->agg_skb) { + port->agg_skb = 0; + port->agg_count = 0; + memset(&port->agg_time, 0, sizeof(struct timespec)); + spin_unlock_irqrestore(&port->agg_lock, flags); + skb->protocol = htons(ETH_P_MAP); + dev_queue_xmit(skb); + return; + } + port->agg_count = 1; + getnstimeofday(&port->agg_time); + dev_kfree_skb_any(skb); + goto schedule; + } + diff = timespec_sub(port->agg_last, port->agg_time); + + if (skb->len > (port->egress_agg_size - port->agg_skb->len) || + port->agg_count >= port->egress_agg_count || + diff.tv_sec > 0 || diff.tv_nsec > rmnet_agg_time_limit) { + agg_skb = port->agg_skb; + agg_count = port->agg_count; + port->agg_skb = 0; + port->agg_count = 0; + memset(&port->agg_time, 0, sizeof(struct timespec)); + port->agg_state = 0; + spin_unlock_irqrestore(&port->agg_lock, flags); + hrtimer_cancel(&port->hrtimer); + agg_skb->protocol = htons(ETH_P_MAP); + dev_queue_xmit(agg_skb); + goto new_packet; + } + + dest_buff = skb_put(port->agg_skb, skb->len); + memcpy(dest_buff, skb->data, skb->len); + port->agg_count++; + dev_kfree_skb_any(skb); + +schedule: + if (port->agg_state != -EINPROGRESS) { + port->agg_state = -EINPROGRESS; + hrtimer_start(&port->hrtimer, ns_to_ktime(3000000), + HRTIMER_MODE_REL); + } + spin_unlock_irqrestore(&port->agg_lock, flags); +} + +void rmnet_map_tx_aggregate_init(struct rmnet_port *port) +{ + hrtimer_init(&port->hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + port->hrtimer.function = rmnet_map_flush_tx_packet_queue; + port->egress_agg_size = 8192; + port->egress_agg_count = 20; + spin_lock_init(&port->agg_lock); +} + +void rmnet_map_tx_aggregate_exit(struct rmnet_port *port) +{ + unsigned long flags; + + hrtimer_cancel(&port->hrtimer); + spin_lock_irqsave(&port->agg_lock, flags); + if (port->agg_state == -EINPROGRESS) { + if (port->agg_skb) { + kfree_skb(port->agg_skb); + port->agg_skb = NULL; + port->agg_count = 0; + memset(&port->agg_time, 0, sizeof(struct timespec)); + } + + port->agg_state = 0; + } + + spin_unlock_irqrestore(&port->agg_lock, flags); +} diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_private.h b/drivers/net/ethernet/qualcomm/rmnet/rmnet_private.h index b9cc4f85f229..c30100ced465 100644 --- a/drivers/net/ethernet/qualcomm/rmnet/rmnet_private.h +++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_private.h @@ -18,6 +18,9 @@ #define RMNET_NEEDED_HEADROOM 16 #define RMNET_TX_QUEUE_LEN 1000 +/* Constants */ +#define RMNET_EGRESS_FORMAT_AGGREGATION BIT(31) + /* Replace skb->dev to a virtual rmnet device and pass up the stack */ #define RMNET_EPMODE_VND (1) /* Pass the frame directly to another device with dev_queue_xmit() */ -- GitLab From 50a9fa1e743bf960874be5899cc8cfa445ecaea7 Mon Sep 17 00:00:00 2001 From: Runmin Wang Date: Fri, 6 Apr 2018 13:54:56 -0700 Subject: [PATCH 0618/1635] sched: boost: Add support for nesting and priority Multiple clients could vote for different levels of boost. Use a bucket to count the voting of different levels and take the one with the highest priority. It is expected that client needs to remove their vote when finished. Change-Id: I947c01a0e0f5e79a70fb393e61d43aa06fef7444 Signed-off-by: Runmin Wang --- kernel/sched/boost.c | 102 +++++++++++++++++++++++++++++++------------ kernel/sched/sched.h | 9 ++++ kernel/sysctl.c | 3 +- 3 files changed, 84 insertions(+), 30 deletions(-) diff --git a/kernel/sched/boost.c b/kernel/sched/boost.c index 4c08b3b90c2f..76a139770245 100644 --- a/kernel/sched/boost.c +++ b/kernel/sched/boost.c @@ -27,6 +27,7 @@ static enum sched_boost_policy boost_policy; static enum sched_boost_policy boost_policy_dt = SCHED_BOOST_NONE; static DEFINE_MUTEX(boost_mutex); static unsigned int freq_aggr_threshold_backup; +static int boost_refcount[MAX_NUM_BOOST_TYPE]; static inline void boost_kick(int cpu) { @@ -103,49 +104,98 @@ enum sched_boost_policy sched_boost_policy(void) return boost_policy; } -static bool verify_boost_params(int old_val, int new_val) +static bool verify_boost_params(int type) { - /* - * Boost can only be turned on or off. There is no possiblity of - * switching from one boost type to another or to set the same - * kind of boost several times. - */ - return !(!!old_val == !!new_val); + return type >= RESTRAINED_BOOST_DISABLE && type <= RESTRAINED_BOOST; } -static void _sched_set_boost(int old_val, int type) +static void _sched_set_boost(int type) { switch (type) { - case NO_BOOST: - if (old_val == FULL_THROTTLE_BOOST) + case NO_BOOST: /* All boost clear */ + if (boost_refcount[FULL_THROTTLE_BOOST] > 0) { core_ctl_set_boost(false); - else if (old_val == CONSERVATIVE_BOOST) + boost_refcount[FULL_THROTTLE_BOOST] = 0; + } + if (boost_refcount[CONSERVATIVE_BOOST] > 0) { restore_cgroup_boost_settings(); - else + boost_refcount[CONSERVATIVE_BOOST] = 0; + } + if (boost_refcount[RESTRAINED_BOOST] > 0) { update_freq_aggregate_threshold( freq_aggr_threshold_backup); + boost_refcount[RESTRAINED_BOOST] = 0; + } break; case FULL_THROTTLE_BOOST: - core_ctl_set_boost(true); - boost_kick_cpus(); + boost_refcount[FULL_THROTTLE_BOOST]++; + if (boost_refcount[FULL_THROTTLE_BOOST] == 1) { + core_ctl_set_boost(true); + restore_cgroup_boost_settings(); + boost_kick_cpus(); + } break; case CONSERVATIVE_BOOST: - update_cgroup_boost_settings(); - boost_kick_cpus(); + boost_refcount[CONSERVATIVE_BOOST]++; + if ((boost_refcount[CONSERVATIVE_BOOST] == 1) && + !boost_refcount[FULL_THROTTLE_BOOST]) { + update_cgroup_boost_settings(); + boost_kick_cpus(); + } break; case RESTRAINED_BOOST: - freq_aggr_threshold_backup = - update_freq_aggregate_threshold(1); + boost_refcount[RESTRAINED_BOOST]++; + if (boost_refcount[RESTRAINED_BOOST] == 1) { + freq_aggr_threshold_backup = + update_freq_aggregate_threshold(1); + } + break; + + case FULL_THROTTLE_BOOST_DISABLE: + if (boost_refcount[FULL_THROTTLE_BOOST] >= 1) { + boost_refcount[FULL_THROTTLE_BOOST]--; + if (!boost_refcount[FULL_THROTTLE_BOOST]) { + core_ctl_set_boost(false); + if (boost_refcount[CONSERVATIVE_BOOST] >= 1) + update_cgroup_boost_settings(); + } + } break; + case CONSERVATIVE_BOOST_DISABLE: + if (boost_refcount[CONSERVATIVE_BOOST] >= 1) { + boost_refcount[CONSERVATIVE_BOOST]--; + if (!boost_refcount[CONSERVATIVE_BOOST]) + restore_cgroup_boost_settings(); + } + break; + + case RESTRAINED_BOOST_DISABLE: + if (boost_refcount[RESTRAINED_BOOST] >= 1) { + boost_refcount[RESTRAINED_BOOST]--; + if (!boost_refcount[RESTRAINED_BOOST]) + update_freq_aggregate_threshold( + freq_aggr_threshold_backup); + } + default: WARN_ON(1); return; } + /* Aggregate final boost type */ + if (boost_refcount[FULL_THROTTLE_BOOST] >= 1) + type = FULL_THROTTLE_BOOST; + else if (boost_refcount[CONSERVATIVE_BOOST] >= 1) + type = CONSERVATIVE_BOOST; + else if (boost_refcount[RESTRAINED_BOOST] >= 1) + type = RESTRAINED_BOOST; + else + type = NO_BOOST; + set_boost_policy(type); sysctl_sched_boost = type; trace_sched_set_boost(type); @@ -173,12 +223,10 @@ int sched_set_boost(int type) int ret = 0; mutex_lock(&boost_mutex); - - if (verify_boost_params(sysctl_sched_boost, type)) - _sched_set_boost(sysctl_sched_boost, type); + if (verify_boost_params(type)) + _sched_set_boost(type); else ret = -EINVAL; - mutex_unlock(&boost_mutex); return ret; } @@ -189,22 +237,18 @@ int sched_boost_handler(struct ctl_table *table, int write, { int ret; unsigned int *data = (unsigned int *)table->data; - unsigned int old_val; mutex_lock(&boost_mutex); - old_val = *data; ret = proc_dointvec_minmax(table, write, buffer, lenp, ppos); if (ret || !write) goto done; - if (verify_boost_params(old_val, *data)) { - _sched_set_boost(old_val, *data); - } else { - *data = old_val; + if (verify_boost_params(*data)) + _sched_set_boost(*data); + else ret = -EINVAL; - } done: mutex_unlock(&boost_mutex); diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h index 60ed50da5220..f59e2b19be19 100644 --- a/kernel/sched/sched.h +++ b/kernel/sched/sched.h @@ -2582,6 +2582,15 @@ extern void set_preferred_cluster(struct related_thread_group *grp); extern void add_new_task_to_grp(struct task_struct *new); extern unsigned int update_freq_aggregate_threshold(unsigned int threshold); +#define NO_BOOST 0 +#define FULL_THROTTLE_BOOST 1 +#define CONSERVATIVE_BOOST 2 +#define RESTRAINED_BOOST 3 +#define FULL_THROTTLE_BOOST_DISABLE -1 +#define CONSERVATIVE_BOOST_DISABLE -2 +#define RESTRAINED_BOOST_DISABLE -3 +#define MAX_NUM_BOOST_TYPE (RESTRAINED_BOOST+1) + static inline int cpu_capacity(int cpu) { return cpu_rq(cpu)->cluster->capacity; diff --git a/kernel/sysctl.c b/kernel/sysctl.c index b5704bf594e1..33569050db31 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -119,6 +119,7 @@ static int sixty = 60; #endif static int __maybe_unused neg_one = -1; +static int __maybe_unused neg_three = -3; static int zero; static int __maybe_unused one = 1; @@ -358,7 +359,7 @@ static struct ctl_table kern_table[] = { .maxlen = sizeof(unsigned int), .mode = 0644, .proc_handler = sched_boost_handler, - .extra1 = &zero, + .extra1 = &neg_three, .extra2 = &three, }, { -- GitLab From ad8f3020522f456c3811e67d0107cabd005dda4a Mon Sep 17 00:00:00 2001 From: Narendra Muppalla Date: Mon, 23 Apr 2018 15:31:21 -0700 Subject: [PATCH 0619/1635] drm/msm/sde: add software te support for phy cmd mode panels This change adds software te watchdog support for all physical cmd mode panels. Change-Id: I4c838b1f89d56ed8d63be0d7bf188f5b884fae8b Signed-off-by: Narendra Muppalla --- drivers/gpu/drm/msm/dsi-staging/dsi_display.c | 8 +++++++- drivers/gpu/drm/msm/dsi-staging/dsi_display.h | 2 ++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_display.c b/drivers/gpu/drm/msm/dsi-staging/dsi_display.c index 18fbfd925b6b..53ba61ccbb10 100644 --- a/drivers/gpu/drm/msm/dsi-staging/dsi_display.c +++ b/drivers/gpu/drm/msm/dsi-staging/dsi_display.c @@ -1595,6 +1595,7 @@ static void dsi_display_parse_cmdline_topology(struct dsi_display *display, { char *boot_str = NULL; char *str = NULL; + char *sw_te = NULL; unsigned long value; if (display_type >= MAX_DSI_ACTIVE_DISPLAY) { @@ -1607,6 +1608,10 @@ static void dsi_display_parse_cmdline_topology(struct dsi_display *display, else boot_str = dsi_display_secondary; + sw_te = strnstr(boot_str, ":swte", strlen(boot_str)); + if (sw_te) + display->sw_te_using_wd = true; + str = strnstr(boot_str, ":config", strlen(boot_str)); if (!str) return; @@ -4202,7 +4207,8 @@ int dsi_display_get_info(struct drm_connector *connector, case DSI_OP_CMD_MODE: info->capabilities |= MSM_DISPLAY_CAP_CMD_MODE; info->is_te_using_watchdog_timer = - display->panel->te_using_watchdog_timer; + display->panel->te_using_watchdog_timer | + display->sw_te_using_wd; break; default: pr_err("unknwown dsi panel mode %d\n", diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_display.h b/drivers/gpu/drm/msm/dsi-staging/dsi_display.h index 10e6ae551b1e..149b1fc89a5f 100644 --- a/drivers/gpu/drm/msm/dsi-staging/dsi_display.h +++ b/drivers/gpu/drm/msm/dsi-staging/dsi_display.h @@ -132,6 +132,7 @@ struct dsi_display_clk_info { * @list: List pointer. * @is_active: Is display active. * @is_cont_splash_enabled: Is continuous splash enabled + * @sw_te_using_wd: Is software te enabled * @display_lock: Mutex for dsi_display interface. * @ctrl_count: Number of DSI interfaces required by panel. * @ctrl: Controller information for DSI display. @@ -172,6 +173,7 @@ struct dsi_display { const char *display_type; struct list_head list; bool is_cont_splash_enabled; + bool sw_te_using_wd; struct mutex display_lock; u32 ctrl_count; -- GitLab From fca2f7b380a8b802cda4d08785c2bb116efd9731 Mon Sep 17 00:00:00 2001 From: Maheshwar Ajja Date: Mon, 23 Apr 2018 13:13:56 -0700 Subject: [PATCH 0620/1635] msm: vidc: Fix CDSP interface queue release issue CDSP interface queue release function is failing due to the usage of incorrect pointer. Resolve the issue by properly assigning the correct pointer. Change-Id: I5f3bb17fbcc4f54d3c3a2ee32dd00de171e1d52e Signed-off-by: Maheshwar Ajja --- drivers/media/platform/msm/vidc/venus_hfi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/platform/msm/vidc/venus_hfi.c b/drivers/media/platform/msm/vidc/venus_hfi.c index 862328c065d5..d00c0efaf566 100644 --- a/drivers/media/platform/msm/vidc/venus_hfi.c +++ b/drivers/media/platform/msm/vidc/venus_hfi.c @@ -1385,7 +1385,7 @@ static void __set_queue_hdr_defaults(struct hfi_queue_header *q_hdr) static void __interface_dsp_queues_release(struct venus_hfi_device *device) { int i; - struct msm_smem *mem_data = &device->iface_q_table.mem_data; + struct msm_smem *mem_data = &device->dsp_iface_q_table.mem_data; struct context_bank_info *cb = mem_data->mapping_info.cb_info; if (!device->dsp_iface_q_table.align_virtual_addr) { @@ -1393,7 +1393,7 @@ static void __interface_dsp_queues_release(struct venus_hfi_device *device) return; } - dma_unmap_single_attrs(cb->dev, mem_data->dma_handle, + dma_unmap_single_attrs(cb->dev, mem_data->device_addr, mem_data->size, DMA_BIDIRECTIONAL, 0); dma_free_coherent(device->res->mem_adsp.dev, mem_data->size, mem_data->kvaddr, mem_data->dma_handle); -- GitLab From 9feeb3a87afdc17332bdfd0f0d2fee44e4980ae5 Mon Sep 17 00:00:00 2001 From: Chris Lew Date: Mon, 23 Apr 2018 18:09:11 -0700 Subject: [PATCH 0621/1635] rpmsg: glink: Use strlcpy Replace strcpy and strncpy for the safer variant strlcpy. Change-Id: Ic4fea469596b3115b59096be53de3eb2f5f8cb4f Signed-off-by: Chris Lew --- drivers/rpmsg/qcom_glink_native.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/rpmsg/qcom_glink_native.c b/drivers/rpmsg/qcom_glink_native.c index b54be731f7b9..725d6d007464 100644 --- a/drivers/rpmsg/qcom_glink_native.c +++ b/drivers/rpmsg/qcom_glink_native.c @@ -459,7 +459,7 @@ static int qcom_glink_send_open_req(struct qcom_glink *glink, req.msg.cmd = cpu_to_le16(RPM_CMD_OPEN); req.msg.param1 = cpu_to_le16(channel->lcid); req.msg.param2 = cpu_to_le32(name_len); - strcpy(req.name, channel->name); + strlcpy(req.name, channel->name, GLINK_NAME_SIZE); ret = qcom_glink_tx(glink, &req, req_len, NULL, 0, true); if (ret) @@ -1558,7 +1558,7 @@ static int qcom_glink_rx_open(struct qcom_glink *glink, unsigned int rcid, } rpdev->ept = &channel->ept; - strncpy(rpdev->id.name, name, RPMSG_NAME_SIZE); + strlcpy(rpdev->id.name, name, RPMSG_NAME_SIZE); rpdev->src = RPMSG_ADDR_ANY; rpdev->dst = RPMSG_ADDR_ANY; rpdev->ops = &glink_device_ops; @@ -1613,7 +1613,7 @@ static void qcom_glink_rx_close(struct qcom_glink *glink, unsigned int rcid) cancel_work_sync(&channel->intent_work); if (channel->rpdev) { - strncpy(chinfo.name, channel->name, sizeof(chinfo.name)); + strlcpy(chinfo.name, channel->name, sizeof(chinfo.name)); chinfo.src = RPMSG_ADDR_ANY; chinfo.dst = RPMSG_ADDR_ANY; -- GitLab From f1e039cce73fa435911f7b8abb0fc371a8040a06 Mon Sep 17 00:00:00 2001 From: Ping Li Date: Tue, 17 Apr 2018 11:55:20 -0700 Subject: [PATCH 0622/1635] drm/msm/sde: Expand sspp lut_dma buf for multi-rect use cases Currently lut_dma allocates one buffer for each SSPP feature per pipe. This change expands the sspp_buf storage for each SSPP feature per rect instead of per pipe. Change-Id: Id9a6b90c996c516ab0e8c6eb16f1ff1231b9c900 Signed-off-by: Ping Li --- .../msm/sde/sde_hw_reg_dma_v1_color_proc.c | 154 ++++++++++-------- drivers/gpu/drm/msm/sde/sde_hw_sspp.h | 2 + 2 files changed, 91 insertions(+), 65 deletions(-) diff --git a/drivers/gpu/drm/msm/sde/sde_hw_reg_dma_v1_color_proc.c b/drivers/gpu/drm/msm/sde/sde_hw_reg_dma_v1_color_proc.c index 2b8295d03427..35b93011703c 100644 --- a/drivers/gpu/drm/msm/sde/sde_hw_reg_dma_v1_color_proc.c +++ b/drivers/gpu/drm/msm/sde/sde_hw_reg_dma_v1_color_proc.c @@ -92,7 +92,8 @@ #define QSEED3_COEF_LUT_CTRL_OFF 0x4C static struct sde_reg_dma_buffer *dspp_buf[REG_DMA_FEATURES_MAX][DSPP_MAX]; -static struct sde_reg_dma_buffer *sspp_buf[REG_DMA_FEATURES_MAX][SSPP_MAX]; +static struct sde_reg_dma_buffer + *sspp_buf[SDE_SSPP_RECT_MAX][REG_DMA_FEATURES_MAX][SSPP_MAX]; static u32 feature_map[SDE_DSPP_MAX] = { [SDE_DSPP_VLUT] = VLUT, @@ -189,7 +190,8 @@ static int reg_dma_buf_init(struct sde_reg_dma_buffer **buf, u32 sz); static int reg_dma_dspp_check(struct sde_hw_dspp *ctx, void *cfg, enum sde_reg_dma_features feature); static int reg_dma_sspp_check(struct sde_hw_pipe *ctx, void *cfg, - enum sde_reg_dma_features feature); + enum sde_reg_dma_features feature, + enum sde_sspp_multirect_index idx); static int reg_dma_buf_init(struct sde_reg_dma_buffer **buf, u32 size) { @@ -1576,7 +1578,7 @@ int reg_dmav1_init_sspp_op_v4(int feature, enum sde_sspp idx) int rc = -ENOTSUPP; struct sde_hw_reg_dma_ops *dma_ops; bool is_supported = false; - u32 blk; + u32 blk, i = 0; if (feature >= SDE_SSPP_MAX || idx >= SSPP_MAX) { DRM_ERROR("invalid feature %x max %x sspp idx %x max %xd\n", @@ -1600,15 +1602,25 @@ int reg_dmav1_init_sspp_op_v4(int feature, enum sde_sspp idx) if (!rc) rc = (is_supported) ? 0 : -ENOTSUPP; - if (!rc) - rc = reg_dma_buf_init(&sspp_buf[sspp_feature_map[feature]][idx], + if (!rc) { + for (i = SDE_SSPP_RECT_0; i < SDE_SSPP_RECT_MAX; i++) { + rc = reg_dma_buf_init( + &sspp_buf[i][sspp_feature_map[feature]][idx], sspp_feature_reg_dma_sz[feature]); + if (rc) { + DRM_ERROR("rect %d buf init failed\n", i); + break; + } + } + + } return rc; } static int reg_dma_sspp_check(struct sde_hw_pipe *ctx, void *cfg, - enum sde_reg_dma_features feature) + enum sde_reg_dma_features feature, + enum sde_sspp_multirect_index idx) { struct sde_hw_reg_dma_ops *dma_ops; struct sde_hw_cp_cfg *hw_cfg = cfg; @@ -1618,6 +1630,11 @@ static int reg_dma_sspp_check(struct sde_hw_pipe *ctx, void *cfg, return -EINVAL; } + if (idx >= SDE_SSPP_RECT_MAX) { + DRM_ERROR("invalid multirect idx %d\n", idx); + return -EINVAL; + } + dma_ops = sde_reg_dma_get_ops(); if (IS_ERR_OR_NULL(dma_ops)) return -EINVAL; @@ -1629,8 +1646,9 @@ static int reg_dma_sspp_check(struct sde_hw_pipe *ctx, void *cfg, return -EINVAL; } - if (!sspp_buf[feature][ctx->idx]) { - DRM_ERROR("invalid dma_buf for sspp idx %d\n", ctx->idx); + if (!sspp_buf[idx][feature][ctx->idx]) { + DRM_ERROR("invalid dma_buf for rect idx %d sspp idx %d\n", idx, + ctx->idx); return -EINVAL; } @@ -1646,12 +1664,13 @@ static void vig_gamutv5_off(struct sde_hw_pipe *ctx, void *cfg) struct sde_reg_dma_setup_ops_cfg dma_write_cfg; struct sde_reg_dma_kickoff_cfg kick_off; u32 gamut_base = ctx->cap->sblk->gamut_blk.base - REG_DMA_VIG_SWI_DIFF; + enum sde_sspp_multirect_index idx = SDE_SSPP_RECT_0; dma_ops = sde_reg_dma_get_ops(); - dma_ops->reset_reg_dma_buf(sspp_buf[GAMUT][ctx->idx]); + dma_ops->reset_reg_dma_buf(sspp_buf[idx][GAMUT][ctx->idx]); REG_DMA_INIT_OPS(dma_write_cfg, sspp_mapping[ctx->idx], GAMUT, - sspp_buf[GAMUT][ctx->idx]); + sspp_buf[idx][GAMUT][ctx->idx]); REG_DMA_SETUP_OPS(dma_write_cfg, 0, NULL, 0, HW_BLK_SELECT, 0, 0, 0); rc = dma_ops->setup_payload(&dma_write_cfg); @@ -1669,8 +1688,9 @@ static void vig_gamutv5_off(struct sde_hw_pipe *ctx, void *cfg) return; } - REG_DMA_SETUP_KICKOFF(kick_off, hw_cfg->ctl, sspp_buf[GAMUT][ctx->idx], - REG_DMA_WRITE, DMA_CTL_QUEUE0, WRITE_IMMEDIATE); + REG_DMA_SETUP_KICKOFF(kick_off, hw_cfg->ctl, + sspp_buf[idx][GAMUT][ctx->idx], REG_DMA_WRITE, + DMA_CTL_QUEUE0, WRITE_IMMEDIATE); rc = dma_ops->kick_off(&kick_off); if (rc) DRM_ERROR("failed to kick off ret %d\n", rc); @@ -1688,8 +1708,9 @@ void reg_dmav1_setup_vig_gamutv5(struct sde_hw_pipe *ctx, void *cfg) struct sde_reg_dma_kickoff_cfg kick_off; u32 gamut_base = ctx->cap->sblk->gamut_blk.base - REG_DMA_VIG_SWI_DIFF; bool use_2nd_memory = false; + enum sde_sspp_multirect_index idx = SDE_SSPP_RECT_0; - rc = reg_dma_sspp_check(ctx, cfg, GAMUT); + rc = reg_dma_sspp_check(ctx, cfg, GAMUT, idx); if (rc) return; @@ -1714,10 +1735,10 @@ void reg_dmav1_setup_vig_gamutv5(struct sde_hw_pipe *ctx, void *cfg) } dma_ops = sde_reg_dma_get_ops(); - dma_ops->reset_reg_dma_buf(sspp_buf[GAMUT][ctx->idx]); + dma_ops->reset_reg_dma_buf(sspp_buf[idx][GAMUT][ctx->idx]); REG_DMA_INIT_OPS(dma_write_cfg, sspp_mapping[ctx->idx], GAMUT, - sspp_buf[GAMUT][ctx->idx]); + sspp_buf[idx][GAMUT][ctx->idx]); REG_DMA_SETUP_OPS(dma_write_cfg, 0, NULL, 0, HW_BLK_SELECT, 0, 0, 0); rc = dma_ops->setup_payload(&dma_write_cfg); @@ -1778,8 +1799,9 @@ void reg_dmav1_setup_vig_gamutv5(struct sde_hw_pipe *ctx, void *cfg) return; } - REG_DMA_SETUP_KICKOFF(kick_off, hw_cfg->ctl, sspp_buf[GAMUT][ctx->idx], - REG_DMA_WRITE, DMA_CTL_QUEUE0, WRITE_IMMEDIATE); + REG_DMA_SETUP_KICKOFF(kick_off, hw_cfg->ctl, + sspp_buf[idx][GAMUT][ctx->idx], REG_DMA_WRITE, + DMA_CTL_QUEUE0, WRITE_IMMEDIATE); rc = dma_ops->kick_off(&kick_off); if (rc) DRM_ERROR("failed to kick off ret %d\n", rc); @@ -1794,12 +1816,13 @@ static void vig_igcv5_off(struct sde_hw_pipe *ctx, void *cfg) struct sde_reg_dma_setup_ops_cfg dma_write_cfg; struct sde_reg_dma_kickoff_cfg kick_off; u32 igc_base = ctx->cap->sblk->igc_blk[0].base - REG_DMA_VIG_SWI_DIFF; + enum sde_sspp_multirect_index idx = SDE_SSPP_RECT_0; dma_ops = sde_reg_dma_get_ops(); - dma_ops->reset_reg_dma_buf(sspp_buf[IGC][ctx->idx]); + dma_ops->reset_reg_dma_buf(sspp_buf[idx][IGC][ctx->idx]); REG_DMA_INIT_OPS(dma_write_cfg, sspp_mapping[ctx->idx], IGC, - sspp_buf[IGC][ctx->idx]); + sspp_buf[idx][IGC][ctx->idx]); REG_DMA_SETUP_OPS(dma_write_cfg, 0, NULL, 0, HW_BLK_SELECT, 0, 0, 0); rc = dma_ops->setup_payload(&dma_write_cfg); @@ -1816,8 +1839,9 @@ static void vig_igcv5_off(struct sde_hw_pipe *ctx, void *cfg) return; } - REG_DMA_SETUP_KICKOFF(kick_off, hw_cfg->ctl, sspp_buf[IGC][ctx->idx], - REG_DMA_WRITE, DMA_CTL_QUEUE0, WRITE_IMMEDIATE); + REG_DMA_SETUP_KICKOFF(kick_off, hw_cfg->ctl, + sspp_buf[idx][IGC][ctx->idx], REG_DMA_WRITE, + DMA_CTL_QUEUE0, WRITE_IMMEDIATE); rc = dma_ops->kick_off(&kick_off); if (rc) DRM_ERROR("failed to kick off ret %d\n", rc); @@ -1836,8 +1860,9 @@ void reg_dmav1_setup_vig_igcv5(struct sde_hw_pipe *ctx, void *cfg) struct sde_reg_dma_setup_ops_cfg dma_write_cfg; struct sde_reg_dma_kickoff_cfg kick_off; u32 igc_base = ctx->cap->sblk->igc_blk[0].base - REG_DMA_VIG_SWI_DIFF; + enum sde_sspp_multirect_index idx = SDE_SSPP_RECT_0; - rc = reg_dma_sspp_check(ctx, cfg, IGC); + rc = reg_dma_sspp_check(ctx, cfg, IGC, idx); if (rc) return; @@ -1855,10 +1880,10 @@ void reg_dmav1_setup_vig_igcv5(struct sde_hw_pipe *ctx, void *cfg) } dma_ops = sde_reg_dma_get_ops(); - dma_ops->reset_reg_dma_buf(sspp_buf[IGC][ctx->idx]); + dma_ops->reset_reg_dma_buf(sspp_buf[idx][IGC][ctx->idx]); REG_DMA_INIT_OPS(dma_write_cfg, sspp_mapping[ctx->idx], IGC, - sspp_buf[IGC][ctx->idx]); + sspp_buf[idx][IGC][ctx->idx]); REG_DMA_SETUP_OPS(dma_write_cfg, 0, NULL, 0, HW_BLK_SELECT, 0, 0, 0); rc = dma_ops->setup_payload(&dma_write_cfg); @@ -1927,8 +1952,9 @@ void reg_dmav1_setup_vig_igcv5(struct sde_hw_pipe *ctx, void *cfg) goto exit; } - REG_DMA_SETUP_KICKOFF(kick_off, hw_cfg->ctl, sspp_buf[IGC][ctx->idx], - REG_DMA_WRITE, DMA_CTL_QUEUE0, WRITE_IMMEDIATE); + REG_DMA_SETUP_KICKOFF(kick_off, hw_cfg->ctl, + sspp_buf[idx][IGC][ctx->idx], REG_DMA_WRITE, + DMA_CTL_QUEUE0, WRITE_IMMEDIATE); rc = dma_ops->kick_off(&kick_off); if (rc) DRM_ERROR("failed to kick off ret %d\n", rc); @@ -1948,10 +1974,10 @@ static void dma_igcv5_off(struct sde_hw_pipe *ctx, void *cfg, u32 igc_opmode_off; dma_ops = sde_reg_dma_get_ops(); - dma_ops->reset_reg_dma_buf(sspp_buf[IGC][ctx->idx]); + dma_ops->reset_reg_dma_buf(sspp_buf[idx][IGC][ctx->idx]); REG_DMA_INIT_OPS(dma_write_cfg, sspp_mapping[ctx->idx], IGC, - sspp_buf[IGC][ctx->idx]); + sspp_buf[idx][IGC][ctx->idx]); REG_DMA_SETUP_OPS(dma_write_cfg, 0, NULL, 0, HW_BLK_SELECT, 0, 0, 0); rc = dma_ops->setup_payload(&dma_write_cfg); @@ -1974,8 +2000,9 @@ static void dma_igcv5_off(struct sde_hw_pipe *ctx, void *cfg, return; } - REG_DMA_SETUP_KICKOFF(kick_off, hw_cfg->ctl, sspp_buf[IGC][ctx->idx], - REG_DMA_WRITE, DMA_CTL_QUEUE0, WRITE_IMMEDIATE); + REG_DMA_SETUP_KICKOFF(kick_off, hw_cfg->ctl, + sspp_buf[idx][IGC][ctx->idx], REG_DMA_WRITE, + DMA_CTL_QUEUE0, WRITE_IMMEDIATE); rc = dma_ops->kick_off(&kick_off); if (rc) DRM_ERROR("failed to kick off ret %d\n", rc); @@ -1994,15 +2021,10 @@ void reg_dmav1_setup_dma_igcv5(struct sde_hw_pipe *ctx, void *cfg, struct sde_reg_dma_kickoff_cfg kick_off; u32 igc_base, igc_dither_off, igc_opmode_off; - rc = reg_dma_sspp_check(ctx, cfg, IGC); + rc = reg_dma_sspp_check(ctx, cfg, IGC, idx); if (rc) return; - if (idx > SDE_SSPP_RECT_1) { - DRM_ERROR("invalid multirect idx %d\n", idx); - return; - } - igc_lut = hw_cfg->payload; if (!igc_lut) { DRM_DEBUG_DRIVER("disable igc feature\n"); @@ -2017,10 +2039,10 @@ void reg_dmav1_setup_dma_igcv5(struct sde_hw_pipe *ctx, void *cfg, } dma_ops = sde_reg_dma_get_ops(); - dma_ops->reset_reg_dma_buf(sspp_buf[IGC][ctx->idx]); + dma_ops->reset_reg_dma_buf(sspp_buf[idx][IGC][ctx->idx]); REG_DMA_INIT_OPS(dma_write_cfg, sspp_mapping[ctx->idx], IGC, - sspp_buf[IGC][ctx->idx]); + sspp_buf[idx][IGC][ctx->idx]); REG_DMA_SETUP_OPS(dma_write_cfg, 0, NULL, 0, HW_BLK_SELECT, 0, 0, 0); rc = dma_ops->setup_payload(&dma_write_cfg); @@ -2082,8 +2104,9 @@ void reg_dmav1_setup_dma_igcv5(struct sde_hw_pipe *ctx, void *cfg, goto igc_exit; } - REG_DMA_SETUP_KICKOFF(kick_off, hw_cfg->ctl, sspp_buf[IGC][ctx->idx], - REG_DMA_WRITE, DMA_CTL_QUEUE0, WRITE_IMMEDIATE); + REG_DMA_SETUP_KICKOFF(kick_off, hw_cfg->ctl, + sspp_buf[idx][IGC][ctx->idx], REG_DMA_WRITE, + DMA_CTL_QUEUE0, WRITE_IMMEDIATE); rc = dma_ops->kick_off(&kick_off); if (rc) DRM_ERROR("failed to kick off ret %d\n", rc); @@ -2103,10 +2126,10 @@ static void dma_gcv5_off(struct sde_hw_pipe *ctx, void *cfg, u32 gc_opmode_off; dma_ops = sde_reg_dma_get_ops(); - dma_ops->reset_reg_dma_buf(sspp_buf[GC][ctx->idx]); + dma_ops->reset_reg_dma_buf(sspp_buf[idx][GC][ctx->idx]); REG_DMA_INIT_OPS(dma_write_cfg, sspp_mapping[ctx->idx], GC, - sspp_buf[GC][ctx->idx]); + sspp_buf[idx][GC][ctx->idx]); REG_DMA_SETUP_OPS(dma_write_cfg, 0, NULL, 0, HW_BLK_SELECT, 0, 0, 0); rc = dma_ops->setup_payload(&dma_write_cfg); @@ -2129,8 +2152,9 @@ static void dma_gcv5_off(struct sde_hw_pipe *ctx, void *cfg, return; } - REG_DMA_SETUP_KICKOFF(kick_off, hw_cfg->ctl, sspp_buf[GC][ctx->idx], - REG_DMA_WRITE, DMA_CTL_QUEUE0, WRITE_IMMEDIATE); + REG_DMA_SETUP_KICKOFF(kick_off, hw_cfg->ctl, + sspp_buf[idx][GC][ctx->idx], REG_DMA_WRITE, + DMA_CTL_QUEUE0, WRITE_IMMEDIATE); rc = dma_ops->kick_off(&kick_off); if (rc) DRM_ERROR("failed to kick off ret %d\n", rc); @@ -2149,15 +2173,10 @@ void reg_dmav1_setup_dma_gcv5(struct sde_hw_pipe *ctx, void *cfg, struct sde_reg_dma_kickoff_cfg kick_off; u32 gc_base, gc_opmode_off; - rc = reg_dma_sspp_check(ctx, cfg, GC); + rc = reg_dma_sspp_check(ctx, cfg, GC, idx); if (rc) return; - if (idx > SDE_SSPP_RECT_1) { - DRM_ERROR("invalid multirect idx %d\n", idx); - return; - } - gc_lut = hw_cfg->payload; if (!gc_lut) { DRM_DEBUG_DRIVER("disable gc feature\n"); @@ -2172,10 +2191,10 @@ void reg_dmav1_setup_dma_gcv5(struct sde_hw_pipe *ctx, void *cfg, } dma_ops = sde_reg_dma_get_ops(); - dma_ops->reset_reg_dma_buf(sspp_buf[GC][ctx->idx]); + dma_ops->reset_reg_dma_buf(sspp_buf[idx][GC][ctx->idx]); REG_DMA_INIT_OPS(dma_write_cfg, sspp_mapping[ctx->idx], GC, - sspp_buf[GC][ctx->idx]); + sspp_buf[idx][GC][ctx->idx]); REG_DMA_SETUP_OPS(dma_write_cfg, 0, NULL, 0, HW_BLK_SELECT, 0, 0, 0); rc = dma_ops->setup_payload(&dma_write_cfg); @@ -2219,8 +2238,9 @@ void reg_dmav1_setup_dma_gcv5(struct sde_hw_pipe *ctx, void *cfg, goto gc_exit; } - REG_DMA_SETUP_KICKOFF(kick_off, hw_cfg->ctl, sspp_buf[GC][ctx->idx], - REG_DMA_WRITE, DMA_CTL_QUEUE0, WRITE_IMMEDIATE); + REG_DMA_SETUP_KICKOFF(kick_off, hw_cfg->ctl, + sspp_buf[idx][GC][ctx->idx], REG_DMA_WRITE, + DMA_CTL_QUEUE0, WRITE_IMMEDIATE); rc = dma_ops->kick_off(&kick_off); if (rc) DRM_ERROR("failed to kick off ret %d\n", rc); @@ -2230,7 +2250,7 @@ void reg_dmav1_setup_dma_gcv5(struct sde_hw_pipe *ctx, void *cfg, int reg_dmav1_deinit_sspp_ops(enum sde_sspp idx) { - int i; + u32 i, j; struct sde_hw_reg_dma_ops *dma_ops; dma_ops = sde_reg_dma_get_ops(); @@ -2242,11 +2262,13 @@ int reg_dmav1_deinit_sspp_ops(enum sde_sspp idx) return -EINVAL; } - for (i = 0; i < REG_DMA_FEATURES_MAX; i++) { - if (!sspp_buf[i][idx]) - continue; - dma_ops->dealloc_reg_dma(sspp_buf[i][idx]); - sspp_buf[i][idx] = NULL; + for (i = SDE_SSPP_RECT_0; i < SDE_SSPP_RECT_MAX; i++) { + for (j = 0; j < REG_DMA_FEATURES_MAX; j++) { + if (!sspp_buf[i][j][idx]) + continue; + dma_ops->dealloc_reg_dma(sspp_buf[i][j][idx]); + sspp_buf[i][j][idx] = NULL; + } } return 0; } @@ -2392,6 +2414,7 @@ void reg_dmav1_setup_vig_qseed3(struct sde_hw_pipe *ctx, u32 op_mode = 0, offset; u32 preload, src_y_rgb, src_uv, dst; u32 cache[4]; + enum sde_sspp_multirect_index idx = SDE_SSPP_RECT_0; if (!ctx || !pe || !scaler_cfg) { DRM_ERROR("invalid params ctx %pK pe %pK scaler_cfg %pK", @@ -2402,7 +2425,7 @@ void reg_dmav1_setup_vig_qseed3(struct sde_hw_pipe *ctx, hw_cfg.ctl = ctx->ctl; hw_cfg.payload = scaler_cfg; hw_cfg.len = sizeof(*scaler3_cfg); - rc = reg_dma_sspp_check(ctx, &hw_cfg, QSEED); + rc = reg_dma_sspp_check(ctx, &hw_cfg, QSEED, idx); if (rc || !sspp) { DRM_ERROR("invalid params rc %d sspp %pK\n", rc, sspp); return; @@ -2410,10 +2433,10 @@ void reg_dmav1_setup_vig_qseed3(struct sde_hw_pipe *ctx, offset = ctx->cap->sblk->scaler_blk.base - REG_DMA_VIG_SWI_DIFF; dma_ops = sde_reg_dma_get_ops(); - dma_ops->reset_reg_dma_buf(sspp_buf[QSEED][ctx->idx]); + dma_ops->reset_reg_dma_buf(sspp_buf[idx][QSEED][ctx->idx]); REG_DMA_INIT_OPS(dma_write_cfg, sspp_mapping[ctx->idx], QSEED, - sspp_buf[QSEED][ctx->idx]); + sspp_buf[idx][QSEED][ctx->idx]); REG_DMA_SETUP_OPS(dma_write_cfg, 0, NULL, 0, HW_BLK_SELECT, 0, 0, 0); rc = dma_ops->setup_payload(&dma_write_cfg); @@ -2529,8 +2552,9 @@ void reg_dmav1_setup_vig_qseed3(struct sde_hw_pipe *ctx, return; } - REG_DMA_SETUP_KICKOFF(kick_off, hw_cfg.ctl, sspp_buf[QSEED][ctx->idx], - REG_DMA_WRITE, DMA_CTL_QUEUE0, WRITE_IMMEDIATE); + REG_DMA_SETUP_KICKOFF(kick_off, hw_cfg.ctl, + sspp_buf[idx][QSEED][ctx->idx], REG_DMA_WRITE, + DMA_CTL_QUEUE0, WRITE_IMMEDIATE); rc = dma_ops->kick_off(&kick_off); if (rc) DRM_ERROR("failed to kick off ret %d\n", rc); diff --git a/drivers/gpu/drm/msm/sde/sde_hw_sspp.h b/drivers/gpu/drm/msm/sde/sde_hw_sspp.h index 51595036ce50..e493bb77ca53 100644 --- a/drivers/gpu/drm/msm/sde/sde_hw_sspp.h +++ b/drivers/gpu/drm/msm/sde/sde_hw_sspp.h @@ -56,6 +56,7 @@ enum { * SDE_SSPP_RECT_SOLO - multirect disabled * SDE_SSPP_RECT_0 - rect0 of a multirect pipe * SDE_SSPP_RECT_1 - rect1 of a multirect pipe + * SDE_SSPP_RECT_MAX - max enum of multirect pipe * * Note: HW supports multirect with either RECT0 or * RECT1. Considering no benefit of such configs over @@ -66,6 +67,7 @@ enum sde_sspp_multirect_index { SDE_SSPP_RECT_SOLO = 0, SDE_SSPP_RECT_0, SDE_SSPP_RECT_1, + SDE_SSPP_RECT_MAX, }; enum sde_sspp_multirect_mode { -- GitLab From 67bf3675a0d3bb7cbd2a883e22cff963e1d9775b Mon Sep 17 00:00:00 2001 From: Ping Li Date: Wed, 18 Apr 2018 10:20:26 -0700 Subject: [PATCH 0623/1635] drm/msm/sde: Update DMA 1D LUT IGC and GC programming When user space passes 1D LUT IGC and GC data to driver, it uses color channel 2 instead of color channel 0. Color algorithm manager also packs the even & odd value of DMA GC LUT in register format. This change Updates the driver code to accommodate this changes. Change-Id: Ie1be9a3d5d6fc0b336dcc6d99b6fd2156a0dc95f Signed-off-by: Ping Li --- .../msm/sde/sde_hw_reg_dma_v1_color_proc.c | 28 +++++++------------ 1 file changed, 10 insertions(+), 18 deletions(-) diff --git a/drivers/gpu/drm/msm/sde/sde_hw_reg_dma_v1_color_proc.c b/drivers/gpu/drm/msm/sde/sde_hw_reg_dma_v1_color_proc.c index 35b93011703c..b03fc9ea1360 100644 --- a/drivers/gpu/drm/msm/sde/sde_hw_reg_dma_v1_color_proc.c +++ b/drivers/gpu/drm/msm/sde/sde_hw_reg_dma_v1_color_proc.c @@ -2057,9 +2057,10 @@ void reg_dmav1_setup_dma_igcv5(struct sde_hw_pipe *ctx, void *cfg, return; } + /* client packs the 1D LUT data in c2 instead of c0 */ for (i = 0; i < DMA_1D_LUT_IGC_LEN; i++) - data[i] = (igc_lut->c0[2 * i] & IGC_DATA_MASK) | - ((igc_lut->c0[2 * i + 1] & IGC_DATA_MASK) << 16); + data[i] = (igc_lut->c2[2 * i] & IGC_DATA_MASK) | + ((igc_lut->c2[2 * i + 1] & IGC_DATA_MASK) << 16); if (idx == SDE_SSPP_RECT_SOLO || idx == SDE_SSPP_RECT_0) { igc_base = ctx->cap->sblk->igc_blk[0].base - @@ -2164,8 +2165,7 @@ void reg_dmav1_setup_dma_gcv5(struct sde_hw_pipe *ctx, void *cfg, enum sde_sspp_multirect_index idx) { int rc; - u32 i = 0, reg = 0; - u32 *data = NULL; + u32 reg = 0; struct drm_msm_pgc_lut *gc_lut; struct sde_hw_cp_cfg *hw_cfg = cfg; struct sde_hw_reg_dma_ops *dma_ops; @@ -2203,15 +2203,6 @@ void reg_dmav1_setup_dma_gcv5(struct sde_hw_pipe *ctx, void *cfg, return; } - data = kzalloc(DMA_1D_LUT_GC_LEN * sizeof(u32), GFP_KERNEL); - if (!data) { - DRM_ERROR("failed to allocate memory for igc\n"); - return; - } - - for (i = 0; i < DMA_1D_LUT_GC_LEN; i++) - data[i] = gc_lut->c0[2 * i] | (gc_lut->c0[2 * i + 1] << 16); - if (idx == SDE_SSPP_RECT_SOLO || idx == SDE_SSPP_RECT_0) { gc_base = ctx->cap->sblk->gc_blk[0].base - REG_DMA_DMA_SWI_DIFF; gc_opmode_off = DMA_DGM_0_OP_MODE_OFF; @@ -2220,13 +2211,16 @@ void reg_dmav1_setup_dma_gcv5(struct sde_hw_pipe *ctx, void *cfg, gc_opmode_off = DMA_DGM_1_OP_MODE_OFF; } - REG_DMA_SETUP_OPS(dma_write_cfg, gc_base, data, + /* client packs the 1D LUT data in c2 instead of c0, + * and even & odd values are already stacked in register foramt + */ + REG_DMA_SETUP_OPS(dma_write_cfg, gc_base, gc_lut->c2, DMA_1D_LUT_GC_LEN * sizeof(u32), REG_BLK_WRITE_SINGLE, 0, 0, 0); rc = dma_ops->setup_payload(&dma_write_cfg); if (rc) { DRM_ERROR("lut write failed ret %d\n", rc); - goto gc_exit; + return; } reg = BIT(2); REG_DMA_SETUP_OPS(dma_write_cfg, gc_opmode_off, ®, @@ -2235,7 +2229,7 @@ void reg_dmav1_setup_dma_gcv5(struct sde_hw_pipe *ctx, void *cfg, rc = dma_ops->setup_payload(&dma_write_cfg); if (rc) { DRM_ERROR("setting opcode failed ret %d\n", rc); - goto gc_exit; + return; } REG_DMA_SETUP_KICKOFF(kick_off, hw_cfg->ctl, @@ -2244,8 +2238,6 @@ void reg_dmav1_setup_dma_gcv5(struct sde_hw_pipe *ctx, void *cfg, rc = dma_ops->kick_off(&kick_off); if (rc) DRM_ERROR("failed to kick off ret %d\n", rc); -gc_exit: - kfree(data); } int reg_dmav1_deinit_sspp_ops(enum sde_sspp idx) -- GitLab From 20017f33839a2e8e52980ba07fd14f63f2193250 Mon Sep 17 00:00:00 2001 From: Runmin Wang Date: Thu, 19 Apr 2018 18:04:32 -0700 Subject: [PATCH 0624/1635] sched/fair: Only kick nohz balance when runqueue has more than 1 task Misfit task will go through active migration path so there is no need to check in the nohz balance case. Change-Id: Ic05035d8c745797c4a5cbe52b7cdbd98edb352f3 Signed-off-by: Runmin Wang --- kernel/sched/fair.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index e6c6729c7da1..23c9e8be90f1 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -11209,13 +11209,16 @@ static inline bool nohz_kick_needed(struct rq *rq, bool only_update) if (time_before(now, nohz.next_balance)) return false; + /* + * If energy aware is enabled, do idle load balance if runqueue has + * at least 2 tasks and cpu is overutilized + */ if (rq->nr_running >= 2 && (!energy_aware() || cpu_overutilized(cpu))) return true; - /* Do idle load balance if there have misfit task */ if (energy_aware()) - return rq_has_misfit(rq); + return false; rcu_read_lock(); sds = rcu_dereference(per_cpu(sd_llc_shared, cpu)); -- GitLab From 44dab19e00f10cb20a8b7ef694686103307f6ec7 Mon Sep 17 00:00:00 2001 From: Mahesh Sivasubramanian Date: Tue, 28 Nov 2017 10:06:17 -0700 Subject: [PATCH 0625/1635] drivers: cpuidle: lpm-levels: Fix untrusted pointer dereference. The list_for_each macro was not used correctly, where the intermediate variable would be LIST_POISON, resulting in a untrusted pointer dereference. Switch to using list_for_each_entry_safe to for safe removal of a list entry. Change-Id: I0e0fd5dd9f251b5093d6e9d6335387512ec59249 Signed-off-by: Mahesh Sivasubramanian --- drivers/cpuidle/lpm-levels-of.c | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/drivers/cpuidle/lpm-levels-of.c b/drivers/cpuidle/lpm-levels-of.c index 030aacb7cba8..4139c4316f00 100644 --- a/drivers/cpuidle/lpm-levels-of.c +++ b/drivers/cpuidle/lpm-levels-of.c @@ -737,26 +737,22 @@ static int parse_cpu_levels(struct device_node *node, struct lpm_cluster *c) void free_cluster_node(struct lpm_cluster *cluster) { - struct list_head *list; struct lpm_cpu *cpu, *n; - int i; - - list_for_each(list, &cluster->child) { - struct lpm_cluster *n; + struct lpm_cluster *cl, *m; - n = list_entry(list, typeof(*n), list); - list_del(list); - free_cluster_node(n); + list_for_each_entry_safe(cl, m, &cluster->child, list) { + list_del(&cl->list); + free_cluster_node(cl); }; list_for_each_entry_safe(cpu, n, &cluster->cpu, list) { - struct lpm_cpu *cpu = list_entry(list, typeof(*cpu), list); + int i; + list_del(&cpu->list); for (i = 0; i < cpu->nlevels; i++) { kfree(cpu->levels[i].name); cpu->levels[i].name = NULL; } - list_del(list); } } -- GitLab From 35e30b35b4e76bfa30c77c1ba5ec620de8263a1d Mon Sep 17 00:00:00 2001 From: Raghavendra Kakarla Date: Thu, 26 Oct 2017 22:00:13 +0530 Subject: [PATCH 0626/1635] drivers: cpuidle: lpm-levels: Update CPU prediction timer Use per cpu timer to wake up cpu when LPM prediction fails. Change-Id: I42e56a54decb1b98651a85f0087fd37542b68425 Signed-off-by: Raghavendra Kakarla --- drivers/cpuidle/lpm-levels.c | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/drivers/cpuidle/lpm-levels.c b/drivers/cpuidle/lpm-levels.c index b9ab79165369..7bcbd731e33e 100644 --- a/drivers/cpuidle/lpm-levels.c +++ b/drivers/cpuidle/lpm-levels.c @@ -116,7 +116,7 @@ static DEFINE_PER_CPU(struct lpm_history, hist); static DEFINE_PER_CPU(struct lpm_cpu*, cpu_lpm); static bool suspend_in_progress; static struct hrtimer lpm_hrtimer; -static struct hrtimer histtimer; +static DEFINE_PER_CPU(struct hrtimer, histtimer); static struct lpm_debug *lpm_debug; static phys_addr_t lpm_debug_phys; static const int num_dbg_elements = 0x100; @@ -345,7 +345,10 @@ static enum hrtimer_restart lpm_hrtimer_cb(struct hrtimer *h) static void histtimer_cancel(void) { - hrtimer_try_to_cancel(&histtimer); + unsigned int cpu = raw_smp_processor_id(); + struct hrtimer *cpu_histtimer = &per_cpu(histtimer, cpu); + + hrtimer_try_to_cancel(cpu_histtimer); } static enum hrtimer_restart histtimer_fn(struct hrtimer *h) @@ -361,9 +364,11 @@ static void histtimer_start(uint32_t time_us) { uint64_t time_ns = time_us * NSEC_PER_USEC; ktime_t hist_ktime = ns_to_ktime(time_ns); + unsigned int cpu = raw_smp_processor_id(); + struct hrtimer *cpu_histtimer = &per_cpu(histtimer, cpu); - histtimer.function = histtimer_fn; - hrtimer_start(&histtimer, hist_ktime, HRTIMER_MODE_REL_PINNED); + cpu_histtimer->function = histtimer_fn; + hrtimer_start(cpu_histtimer, hist_ktime, HRTIMER_MODE_REL_PINNED); } static void cluster_timer_init(struct lpm_cluster *cluster) @@ -1643,6 +1648,8 @@ static int lpm_probe(struct platform_device *pdev) { int ret; int size; + unsigned int cpu; + struct hrtimer *cpu_histtimer; struct kobject *module_kobj = NULL; struct md_region md_entry; @@ -1666,7 +1673,11 @@ static int lpm_probe(struct platform_device *pdev) */ suspend_set_ops(&lpm_suspend_ops); hrtimer_init(&lpm_hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); - hrtimer_init(&histtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + for_each_possible_cpu(cpu) { + cpu_histtimer = &per_cpu(histtimer, cpu); + hrtimer_init(cpu_histtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + } + cluster_timer_init(lpm_root_node); size = num_dbg_elements * sizeof(struct lpm_debug); -- GitLab From f8385a150801a3aaf9592e310c5bf9f21ecbea0c Mon Sep 17 00:00:00 2001 From: Jaegeuk Kim Date: Wed, 11 Apr 2018 23:09:04 -0700 Subject: [PATCH 0627/1635] f2fs: clear PageError on writepage Cherry-pick from origin/upstream-f2fs-stable-linux-4.14.y: commit 0d05d5b2391a ("f2fs: clear PageError on writepage") This patch clears PageError in some pages tagged by read path, but when we write the pages with valid contents, writepage should clear the bit likewise ext4. Change-Id: I2b089495a565e6ae78e16fec4b81eb2306fcf3c7 Reviewed-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/data.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c index 072a1cf1ee13..96ebf8da4a22 100644 --- a/fs/f2fs/data.c +++ b/fs/f2fs/data.c @@ -1738,6 +1738,7 @@ int do_write_data_page(struct f2fs_io_info *fio) goto out_writepage; set_page_writeback(page); + ClearPageError(page); f2fs_put_dnode(&dn); if (fio->need_lock == LOCK_REQ) f2fs_unlock_op(fio->sbi); @@ -1760,6 +1761,7 @@ int do_write_data_page(struct f2fs_io_info *fio) goto out_writepage; set_page_writeback(page); + ClearPageError(page); /* LFS mode write path */ write_data_page(&dn, fio); -- GitLab From 3eb22bff65592ff7666a2cbd11262d6751e94441 Mon Sep 17 00:00:00 2001 From: Jaegeuk Kim Date: Fri, 20 Apr 2018 19:29:52 -0700 Subject: [PATCH 0628/1635] Revert "f2fs: introduce f2fs_set_page_dirty_nobuffer" Cherry-pick from origin/upstream-f2fs-stable-linux-4.14.y: commit 4c3540173ab2 ("Revert "f2fs: introduce f2fs_set_page_dirty_nobuffer"") This patch reverts copied f2fs_set_page_dirty_nobuffer to use generic function for stability. This reverts commit fe76b796fc5194cc3d57265002e3a748566d073f. Change-Id: Ie3636c90336986cfe3a0ee79d32d8669a82efcc2 Reviewed-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/checkpoint.c | 2 +- fs/f2fs/data.c | 33 +-------------------------------- fs/f2fs/f2fs.h | 1 - fs/f2fs/node.c | 2 +- 4 files changed, 3 insertions(+), 35 deletions(-) diff --git a/fs/f2fs/checkpoint.c b/fs/f2fs/checkpoint.c index 6c7b0547a307..91b2d0056470 100644 --- a/fs/f2fs/checkpoint.c +++ b/fs/f2fs/checkpoint.c @@ -385,7 +385,7 @@ static int f2fs_set_meta_page_dirty(struct page *page) if (!PageUptodate(page)) SetPageUptodate(page); if (!PageDirty(page)) { - f2fs_set_page_dirty_nobuffers(page); + __set_page_dirty_nobuffers(page); inc_page_count(F2FS_P_SB(page), F2FS_DIRTY_META); SetPagePrivate(page); f2fs_trace_pid(page); diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c index 96ebf8da4a22..1afce941a9df 100644 --- a/fs/f2fs/data.c +++ b/fs/f2fs/data.c @@ -19,8 +19,6 @@ #include #include #include -#include -#include #include #include @@ -2516,35 +2514,6 @@ int f2fs_release_page(struct page *page, gfp_t wait) return 1; } -/* - * This was copied from __set_page_dirty_buffers which gives higher performance - * in very high speed storages. (e.g., pmem) - */ -void f2fs_set_page_dirty_nobuffers(struct page *page) -{ - struct address_space *mapping = page->mapping; - unsigned long flags; - - if (unlikely(!mapping)) - return; - - spin_lock(&mapping->private_lock); - lock_page_memcg(page); - SetPageDirty(page); - spin_unlock(&mapping->private_lock); - - spin_lock_irqsave(&mapping->tree_lock, flags); - WARN_ON_ONCE(!PageUptodate(page)); - account_page_dirtied(page, mapping); - radix_tree_tag_set(&mapping->page_tree, - page_index(page), PAGECACHE_TAG_DIRTY); - spin_unlock_irqrestore(&mapping->tree_lock, flags); - unlock_page_memcg(page); - - __mark_inode_dirty(mapping->host, I_DIRTY_PAGES); - return; -} - static int f2fs_set_data_page_dirty(struct page *page) { struct address_space *mapping = page->mapping; @@ -2568,7 +2537,7 @@ static int f2fs_set_data_page_dirty(struct page *page) } if (!PageDirty(page)) { - f2fs_set_page_dirty_nobuffers(page); + __set_page_dirty_nobuffers(page); update_dirty_page(inode, page); return 1; } diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index ea92c18db624..d4678174baa8 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -2891,7 +2891,6 @@ int f2fs_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, u64 start, u64 len); bool should_update_inplace(struct inode *inode, struct f2fs_io_info *fio); bool should_update_outplace(struct inode *inode, struct f2fs_io_info *fio); -void f2fs_set_page_dirty_nobuffers(struct page *page); int __f2fs_write_data_pages(struct address_space *mapping, struct writeback_control *wbc, enum iostat_type io_type); diff --git a/fs/f2fs/node.c b/fs/f2fs/node.c index 199170e2e221..ccf410af9192 100644 --- a/fs/f2fs/node.c +++ b/fs/f2fs/node.c @@ -1772,7 +1772,7 @@ static int f2fs_set_node_page_dirty(struct page *page) if (!PageUptodate(page)) SetPageUptodate(page); if (!PageDirty(page)) { - f2fs_set_page_dirty_nobuffers(page); + __set_page_dirty_nobuffers(page); inc_page_count(F2FS_P_SB(page), F2FS_DIRTY_NODES); SetPagePrivate(page); f2fs_trace_pid(page); -- GitLab From b374bf0f3097e464fcf4f8c891816a1437de1182 Mon Sep 17 00:00:00 2001 From: Jaegeuk Kim Date: Fri, 20 Apr 2018 23:44:59 -0700 Subject: [PATCH 0629/1635] f2fs: check cap_resource only for data blocks Cherry-pick from origin/upstream-f2fs-stable-linux-4.14.y: commit ca17de437834 ("f2fs: check cap_resource only for data blocks") This patch changes the rule to check cap_resource for data blocks, not inode or node blocks in order to avoid selinux denial. Change-Id: Icf0ce297701d20d288f3f08cd94f3b7c9348f79c Reviewed-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/f2fs.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index d4678174baa8..f32a0c79702f 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -1614,7 +1614,7 @@ static inline bool f2fs_has_xattr_block(unsigned int ofs) } static inline bool __allow_reserved_blocks(struct f2fs_sb_info *sbi, - struct inode *inode) + struct inode *inode, bool cap) { if (!inode) return true; @@ -1627,7 +1627,7 @@ static inline bool __allow_reserved_blocks(struct f2fs_sb_info *sbi, if (!gid_eq(F2FS_OPTION(sbi).s_resgid, GLOBAL_ROOT_GID) && in_group_p(F2FS_OPTION(sbi).s_resgid)) return true; - if (capable(CAP_SYS_RESOURCE)) + if (cap && capable(CAP_SYS_RESOURCE)) return true; return false; } @@ -1662,7 +1662,7 @@ static inline int inc_valid_block_count(struct f2fs_sb_info *sbi, avail_user_block_count = sbi->user_block_count - sbi->current_reserved_blocks; - if (!__allow_reserved_blocks(sbi, inode)) + if (!__allow_reserved_blocks(sbi, inode, true)) avail_user_block_count -= F2FS_OPTION(sbi).root_reserved_blocks; if (unlikely(sbi->total_valid_block_count > avail_user_block_count)) { @@ -1869,7 +1869,7 @@ static inline int inc_valid_node_count(struct f2fs_sb_info *sbi, valid_block_count = sbi->total_valid_block_count + sbi->current_reserved_blocks + 1; - if (!__allow_reserved_blocks(sbi, inode)) + if (!__allow_reserved_blocks(sbi, inode, false)) valid_block_count += F2FS_OPTION(sbi).root_reserved_blocks; if (unlikely(valid_block_count > sbi->user_block_count)) { -- GitLab From 5a68fc4588112631c6f9a8805f7d5722d827ebfd Mon Sep 17 00:00:00 2001 From: Kiran Gunda Date: Tue, 10 Apr 2018 17:17:20 +0530 Subject: [PATCH 0630/1635] ARM: dts: msm: add SPMI PMIC arbiter device for sdm640 Add SPMI PMIC arbiter device so that it is possible to communicate with PMICs attached to the SPMI bus. Change-Id: Ia014109a801d2884fefed11c5a2b61bd8ca5f938 Signed-off-by: Kiran Gunda --- arch/arm64/boot/dts/qcom/sdm640.dtsi | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sdm640.dtsi b/arch/arm64/boot/dts/qcom/sdm640.dtsi index 7d991a9d4f47..aaf7786cd472 100644 --- a/arch/arm64/boot/dts/qcom/sdm640.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm640.dtsi @@ -21,6 +21,7 @@ #include #include #include +#include / { model = "Qualcomm Technologies, Inc. SDM640"; @@ -933,6 +934,25 @@ status = "disabled"; }; + + spmi_bus: qcom,spmi@c440000 { + compatible = "qcom,spmi-pmic-arb"; + reg = <0xc440000 0x2300>, + <0xc600000 0x2000000>, + <0xe600000 0x100000>, + <0xe700000 0xa0000>, + <0xc40a000 0x26000>; + reg-names = "core", "chnls", "obsrvr", "intr", "cnfg"; + interrupt-names = "periph_irq"; + interrupts = ; + qcom,ee = <0>; + qcom,channel = <0>; + #address-cells = <2>; + #size-cells = <0>; + interrupt-controller; + #interrupt-cells = <4>; + cell-index = <0>; + }; }; #include "sdm640-pinctrl.dtsi" -- GitLab From ae18847c1bdc00dd3dd909b2320c5c523d478162 Mon Sep 17 00:00:00 2001 From: Kiran Gunda Date: Thu, 12 Apr 2018 16:53:19 +0530 Subject: [PATCH 0631/1635] qcom: spmi-wled: Add compatible string for pm640l Add compatible string "qcom,pm640l-spmi-wled" to select pm640l configuration. Also, add the missing compatible string for pm855l. Change-Id: I7550337ed363924c38c5f70c3d02ceef09b4ec79 Signed-off-by: Kiran Gunda --- .../devicetree/bindings/leds/backlight/qcom-spmi-wled.txt | 5 ++++- drivers/video/backlight/qcom-spmi-wled.c | 1 + 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/leds/backlight/qcom-spmi-wled.txt b/Documentation/devicetree/bindings/leds/backlight/qcom-spmi-wled.txt index 87d313462a89..a877264aa6c5 100644 --- a/Documentation/devicetree/bindings/leds/backlight/qcom-spmi-wled.txt +++ b/Documentation/devicetree/bindings/leds/backlight/qcom-spmi-wled.txt @@ -7,7 +7,10 @@ platforms. The PMIC is connected to the host processor via SPMI bus. - compatible Usage: required Value type: - Definition: should be "qcom,pmi8998-spmi-wled". + Definition: should be one of the below. + "qcom,pmi8998-spmi-wled", + "qcom,pm855l-spmi-wled", + "qcom,pm640l-spmi-wled" - reg Usage: required diff --git a/drivers/video/backlight/qcom-spmi-wled.c b/drivers/video/backlight/qcom-spmi-wled.c index 77944f62a230..2ceb797c02c8 100644 --- a/drivers/video/backlight/qcom-spmi-wled.c +++ b/drivers/video/backlight/qcom-spmi-wled.c @@ -1514,6 +1514,7 @@ static int wled_probe(struct platform_device *pdev) static const struct of_device_id wled_match_table[] = { { .compatible = "qcom,pmi8998-spmi-wled", .data = &version_table[0] }, { .compatible = "qcom,pm855l-spmi-wled", .data = &version_table[2] }, + { .compatible = "qcom,pm640l-spmi-wled", .data = &version_table[2] }, { }, }; -- GitLab From 49441bad9d8bb714feb6306dd072d64f80096e38 Mon Sep 17 00:00:00 2001 From: Tirupathi Reddy Date: Tue, 28 Nov 2017 12:41:59 +0530 Subject: [PATCH 0632/1635] leds: qpnp: add driver file for configuring vibrator LDO Add a platform driver for configuring QPNP vibrator LDO HW module. The driver registers to leds framework and exposes device attributes such as state, duration, activate and vmax_uv. CRs-Fixed: 2165526 Change-Id: Ib18fb4bdb6e412e7ef8b094501e0e0f8c89a2077 Signed-off-by: Tirupathi Reddy --- .../bindings/leds/leds-qpnp-vibrator-ldo.txt | 50 ++ drivers/leds/Kconfig | 8 + drivers/leds/Makefile | 1 + drivers/leds/leds-qpnp-vibrator-ldo.c | 550 ++++++++++++++++++ 4 files changed, 609 insertions(+) create mode 100644 Documentation/devicetree/bindings/leds/leds-qpnp-vibrator-ldo.txt create mode 100644 drivers/leds/leds-qpnp-vibrator-ldo.c diff --git a/Documentation/devicetree/bindings/leds/leds-qpnp-vibrator-ldo.txt b/Documentation/devicetree/bindings/leds/leds-qpnp-vibrator-ldo.txt new file mode 100644 index 000000000000..2865019b3fcc --- /dev/null +++ b/Documentation/devicetree/bindings/leds/leds-qpnp-vibrator-ldo.txt @@ -0,0 +1,50 @@ +Qualcomm Technologies, Inc. Vibrator-LDO + +QPNP (Qualcomm Technologies, Inc. Plug N Play) Vibrator-LDO is a peripheral +on some QTI PMICs. It can be interfaced with the host processor via SPMI. + +Vibrator-LDO peripheral supports Eccentric Rotation Mass (ERM) vibrator. + +Properties: + +- compatible + Usage: required + Value type: + Definition: "qcom,qpnp-vibrator-ldo". + +- reg + Usage: required + Value type: + Definition: Base address of vibrator-ldo peripheral. + +- qcom,vib-ldo-volt-uv + Usage: required + Value type: + Definition: The optimal voltage requirement of the vibrator motor for + a normal vibration. Value is specified in microvolts. + +- qcom,disable-overdrive + Usage: optional + Value type: + Definition: Do not apply overdrive voltage. + +- qcom,vib-overdrive-volt-uv + Usage: optional and not required if qcom,disable-overdrive present + Value type: + Definition: The voltage in microvolts used as overdrive factor for + improving motor reactivity at the start of vibration. + If this property not specified, a default value of + 2 times the value specified in qcom,vib-ldo-volt-uv + property is used. + +======= +Example +======= + +pmi632_vib: qcom,vibrator@5700 { + compatible = "qcom,qpnp-vibrator-ldo"; + reg = <0x5700 0x100>; + qcom,vib-ldo-volt-uv = <1504000>; + qcom,disable-overdrive; + qcom,vib-overdrive-volt-uv = <3544000>; +}; diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig index 8fa42fe33fa9..da8b46f9ec7f 100644 --- a/drivers/leds/Kconfig +++ b/drivers/leds/Kconfig @@ -726,6 +726,14 @@ config LEDS_NIC78BX To compile this driver as a module, choose M here: the module will be called leds-nic78bx. +config LEDS_QPNP_VIBRATOR_LDO + tristate "Vibrator-LDO support for QPNP PMIC" + depends on LEDS_CLASS && MFD_SPMI_PMIC + help + This option enables device driver support for the vibrator-ldo + peripheral found on Qualcomm Technologies, Inc. QPNP PMICs. + The vibrator-ldo peripheral is capable of driving ERM vibrators. + comment "LED Triggers" source "drivers/leds/trigger/Kconfig" diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile index dc92a3f209b9..e8e7a2ec587c 100644 --- a/drivers/leds/Makefile +++ b/drivers/leds/Makefile @@ -76,6 +76,7 @@ obj-$(CONFIG_LEDS_PM8058) += leds-pm8058.o obj-$(CONFIG_LEDS_MLXCPLD) += leds-mlxcpld.o obj-$(CONFIG_LEDS_NIC78BX) += leds-nic78bx.o obj-$(CONFIG_LEDS_MT6323) += leds-mt6323.o +obj-$(CONFIG_LEDS_QPNP_VIBRATOR_LDO) += leds-qpnp-vibrator-ldo.o # LED SPI Drivers obj-$(CONFIG_LEDS_DAC124S085) += leds-dac124s085.o diff --git a/drivers/leds/leds-qpnp-vibrator-ldo.c b/drivers/leds/leds-qpnp-vibrator-ldo.c new file mode 100644 index 000000000000..6a143247cd9b --- /dev/null +++ b/drivers/leds/leds-qpnp-vibrator-ldo.c @@ -0,0 +1,550 @@ +/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#define pr_fmt(fmt) "%s: " fmt, __func__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Vibrator-LDO register definitions */ +#define QPNP_VIB_LDO_REG_STATUS1 0x08 +#define QPNP_VIB_LDO_VREG_READY BIT(7) + +#define QPNP_VIB_LDO_REG_VSET_LB 0x40 + +#define QPNP_VIB_LDO_REG_EN_CTL 0x46 +#define QPNP_VIB_LDO_EN BIT(7) + +/* Vibrator-LDO voltage settings */ +#define QPNP_VIB_LDO_VMIN_UV 1504000 +#define QPNP_VIB_LDO_VMAX_UV 3544000 +#define QPNP_VIB_LDO_VOLT_STEP_UV 8000 + +/* + * Define vibration periods: default(5sec), min(50ms), max(15sec) and + * overdrive(30ms). + */ +#define QPNP_VIB_MIN_PLAY_MS 50 +#define QPNP_VIB_PLAY_MS 5000 +#define QPNP_VIB_MAX_PLAY_MS 15000 +#define QPNP_VIB_OVERDRIVE_PLAY_MS 30 + +struct vib_ldo_chip { + struct led_classdev cdev; + struct regmap *regmap; + struct mutex lock; + struct hrtimer stop_timer; + struct hrtimer overdrive_timer; + struct work_struct vib_work; + struct work_struct overdrive_work; + + u16 base; + int vmax_uV; + int overdrive_volt_uV; + int ldo_uV; + int state; + u64 vib_play_ms; + bool vib_enabled; + bool disable_overdrive; +}; + +static int qpnp_vib_ldo_set_voltage(struct vib_ldo_chip *chip, int new_uV) +{ + unsigned int val; + u32 vlevel; + u8 reg[2]; + int ret; + + if (chip->ldo_uV == new_uV) + return 0; + + vlevel = roundup(new_uV, QPNP_VIB_LDO_VOLT_STEP_UV) / 1000; + reg[0] = vlevel & 0xff; + reg[1] = (vlevel & 0xff00) >> 8; + ret = regmap_bulk_write(chip->regmap, + chip->base + QPNP_VIB_LDO_REG_VSET_LB, reg, 2); + if (ret < 0) { + pr_err("regmap write failed, ret=%d\n", ret); + return ret; + } + + if (chip->vib_enabled) { + ret = regmap_read_poll_timeout(chip->regmap, + chip->base + QPNP_VIB_LDO_REG_STATUS1, + val, val & QPNP_VIB_LDO_VREG_READY, + 100, 1000); + if (ret < 0) { + pr_err("Vibrator LDO vreg_ready timeout, status=0x%02x, ret=%d\n", + val, ret); + return ret; + } + } + + chip->ldo_uV = new_uV; + return ret; +} + +static inline int qpnp_vib_ldo_enable(struct vib_ldo_chip *chip, bool enable) +{ + unsigned int val; + int ret; + + if (chip->vib_enabled == enable) + return 0; + + ret = regmap_update_bits(chip->regmap, + chip->base + QPNP_VIB_LDO_REG_EN_CTL, + QPNP_VIB_LDO_EN, + enable ? QPNP_VIB_LDO_EN : 0); + if (ret < 0) { + pr_err("Program Vibrator LDO %s is failed, ret=%d\n", + enable ? "enable" : "disable", ret); + return ret; + } + + if (enable) { + ret = regmap_read_poll_timeout(chip->regmap, + chip->base + QPNP_VIB_LDO_REG_STATUS1, + val, val & QPNP_VIB_LDO_VREG_READY, + 100, 1000); + if (ret < 0) { + pr_err("Vibrator LDO vreg_ready timeout, status=0x%02x, ret=%d\n", + val, ret); + return ret; + } + } + + chip->vib_enabled = enable; + + return ret; +} + +static int qpnp_vibrator_play_on(struct vib_ldo_chip *chip) +{ + int volt_uV; + int ret; + + volt_uV = chip->vmax_uV; + if (!chip->disable_overdrive) + volt_uV = chip->overdrive_volt_uV ? chip->overdrive_volt_uV + : min(chip->vmax_uV * 2, QPNP_VIB_LDO_VMAX_UV); + + ret = qpnp_vib_ldo_set_voltage(chip, volt_uV); + if (ret < 0) { + pr_err("set voltage = %duV failed, ret=%d\n", volt_uV, ret); + return ret; + } + pr_debug("voltage set to %d uV\n", volt_uV); + + ret = qpnp_vib_ldo_enable(chip, true); + if (ret < 0) { + pr_err("vibration enable failed, ret=%d\n", ret); + return ret; + } + + if (!chip->disable_overdrive) + hrtimer_start(&chip->overdrive_timer, + ms_to_ktime(QPNP_VIB_OVERDRIVE_PLAY_MS), + HRTIMER_MODE_REL); + + return ret; +} + +static void qpnp_vib_work(struct work_struct *work) +{ + struct vib_ldo_chip *chip = container_of(work, struct vib_ldo_chip, + vib_work); + int ret = 0; + + if (chip->state) { + if (!chip->vib_enabled) + ret = qpnp_vibrator_play_on(chip); + + if (ret == 0) + hrtimer_start(&chip->stop_timer, + ms_to_ktime(chip->vib_play_ms), + HRTIMER_MODE_REL); + } else { + if (!chip->disable_overdrive) { + hrtimer_cancel(&chip->overdrive_timer); + cancel_work_sync(&chip->overdrive_work); + } + qpnp_vib_ldo_enable(chip, false); + } +} + +static enum hrtimer_restart vib_stop_timer(struct hrtimer *timer) +{ + struct vib_ldo_chip *chip = container_of(timer, struct vib_ldo_chip, + stop_timer); + + chip->state = 0; + schedule_work(&chip->vib_work); + return HRTIMER_NORESTART; +} + +static void qpnp_vib_overdrive_work(struct work_struct *work) +{ + struct vib_ldo_chip *chip = container_of(work, struct vib_ldo_chip, + overdrive_work); + int ret; + + mutex_lock(&chip->lock); + + /* LDO voltage update not required if Vibration disabled */ + if (!chip->vib_enabled) + goto unlock; + + ret = qpnp_vib_ldo_set_voltage(chip, chip->vmax_uV); + if (ret < 0) { + pr_err("set vibration voltage = %duV failed, ret=%d\n", + chip->vmax_uV, ret); + qpnp_vib_ldo_enable(chip, false); + goto unlock; + } + pr_debug("voltage set to %d\n", chip->vmax_uV); + +unlock: + mutex_unlock(&chip->lock); +} + +static enum hrtimer_restart vib_overdrive_timer(struct hrtimer *timer) +{ + struct vib_ldo_chip *chip = container_of(timer, struct vib_ldo_chip, + overdrive_timer); + schedule_work(&chip->overdrive_work); + pr_debug("overdrive timer expired\n"); + return HRTIMER_NORESTART; +} + +static ssize_t qpnp_vib_show_state(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct led_classdev *cdev = dev_get_drvdata(dev); + struct vib_ldo_chip *chip = container_of(cdev, struct vib_ldo_chip, + cdev); + + return snprintf(buf, PAGE_SIZE, "%d\n", chip->vib_enabled); +} + +static ssize_t qpnp_vib_store_state(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + /* At present, nothing to do with setting state */ + return count; +} + +static ssize_t qpnp_vib_show_duration(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct led_classdev *cdev = dev_get_drvdata(dev); + struct vib_ldo_chip *chip = container_of(cdev, struct vib_ldo_chip, + cdev); + ktime_t time_rem; + s64 time_ms = 0; + + if (hrtimer_active(&chip->stop_timer)) { + time_rem = hrtimer_get_remaining(&chip->stop_timer); + time_ms = ktime_to_ms(time_rem); + } + + return snprintf(buf, PAGE_SIZE, "%lld\n", time_ms); +} + +static ssize_t qpnp_vib_store_duration(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct led_classdev *cdev = dev_get_drvdata(dev); + struct vib_ldo_chip *chip = container_of(cdev, struct vib_ldo_chip, + cdev); + u32 val; + int ret; + + ret = kstrtouint(buf, 0, &val); + if (ret < 0) + return ret; + + /* setting 0 on duration is NOP for now */ + if (val <= 0) + return count; + + if (val < QPNP_VIB_MIN_PLAY_MS) + val = QPNP_VIB_MIN_PLAY_MS; + + if (val > QPNP_VIB_MAX_PLAY_MS) + val = QPNP_VIB_MAX_PLAY_MS; + + mutex_lock(&chip->lock); + chip->vib_play_ms = val; + mutex_unlock(&chip->lock); + + return count; +} + +static ssize_t qpnp_vib_show_activate(struct device *dev, + struct device_attribute *attr, char *buf) +{ + /* For now nothing to show */ + return snprintf(buf, PAGE_SIZE, "%d\n", 0); +} + +static ssize_t qpnp_vib_store_activate(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct led_classdev *cdev = dev_get_drvdata(dev); + struct vib_ldo_chip *chip = container_of(cdev, struct vib_ldo_chip, + cdev); + u32 val; + int ret; + + ret = kstrtouint(buf, 0, &val); + if (ret < 0) + return ret; + + if (val != 0 && val != 1) + return count; + + mutex_lock(&chip->lock); + hrtimer_cancel(&chip->stop_timer); + chip->state = val; + pr_debug("state = %d, time = %llums\n", chip->state, chip->vib_play_ms); + mutex_unlock(&chip->lock); + schedule_work(&chip->vib_work); + + return count; +} + +static ssize_t qpnp_vib_show_vmax(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct led_classdev *cdev = dev_get_drvdata(dev); + struct vib_ldo_chip *chip = container_of(cdev, struct vib_ldo_chip, + cdev); + + return snprintf(buf, PAGE_SIZE, "%d\n", chip->vmax_uV / 1000); +} + +static ssize_t qpnp_vib_store_vmax(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct led_classdev *cdev = dev_get_drvdata(dev); + struct vib_ldo_chip *chip = container_of(cdev, struct vib_ldo_chip, + cdev); + int data, ret; + + ret = kstrtoint(buf, 10, &data); + if (ret < 0) + return ret; + + data = data * 1000; /* Convert to microvolts */ + + /* check against vibrator ldo min/max voltage limits */ + data = min(data, QPNP_VIB_LDO_VMAX_UV); + data = max(data, QPNP_VIB_LDO_VMIN_UV); + + mutex_lock(&chip->lock); + chip->vmax_uV = data; + mutex_unlock(&chip->lock); + return ret; +} + +static struct device_attribute qpnp_vib_attrs[] = { + __ATTR(state, 0664, qpnp_vib_show_state, qpnp_vib_store_state), + __ATTR(duration, 0664, qpnp_vib_show_duration, qpnp_vib_store_duration), + __ATTR(activate, 0664, qpnp_vib_show_activate, qpnp_vib_store_activate), + __ATTR(vmax_mv, 0664, qpnp_vib_show_vmax, qpnp_vib_store_vmax), +}; + +static int qpnp_vib_parse_dt(struct device *dev, struct vib_ldo_chip *chip) +{ + int ret; + + ret = of_property_read_u32(dev->of_node, "qcom,vib-ldo-volt-uv", + &chip->vmax_uV); + if (ret < 0) { + pr_err("qcom,vib-ldo-volt-uv property read failed, ret=%d\n", + ret); + return ret; + } + + chip->disable_overdrive = of_property_read_bool(dev->of_node, + "qcom,disable-overdrive"); + + if (of_find_property(dev->of_node, "qcom,vib-overdrive-volt-uv", + NULL)) { + ret = of_property_read_u32(dev->of_node, + "qcom,vib-overdrive-volt-uv", + &chip->overdrive_volt_uV); + if (ret < 0) { + pr_err("qcom,vib-overdrive-volt-uv property read failed, ret=%d\n", + ret); + return ret; + } + + /* check against vibrator ldo min/max voltage limits */ + chip->overdrive_volt_uV = min(chip->overdrive_volt_uV, + QPNP_VIB_LDO_VMAX_UV); + chip->overdrive_volt_uV = max(chip->overdrive_volt_uV, + QPNP_VIB_LDO_VMIN_UV); + } + + return ret; +} + +/* Dummy functions for brightness */ +static enum led_brightness qpnp_vib_brightness_get(struct led_classdev *cdev) +{ + return 0; +} + +static void qpnp_vib_brightness_set(struct led_classdev *cdev, + enum led_brightness level) +{ +} + +static int qpnp_vibrator_ldo_suspend(struct device *dev) +{ + struct vib_ldo_chip *chip = dev_get_drvdata(dev); + + mutex_lock(&chip->lock); + if (!chip->disable_overdrive) { + hrtimer_cancel(&chip->overdrive_timer); + cancel_work_sync(&chip->overdrive_work); + } + hrtimer_cancel(&chip->stop_timer); + cancel_work_sync(&chip->vib_work); + mutex_unlock(&chip->lock); + + return 0; +} +static SIMPLE_DEV_PM_OPS(qpnp_vibrator_ldo_pm_ops, qpnp_vibrator_ldo_suspend, + NULL); + +static int qpnp_vibrator_ldo_probe(struct platform_device *pdev) +{ + struct device_node *of_node = pdev->dev.of_node; + struct vib_ldo_chip *chip; + int i, ret; + u32 base; + + ret = of_property_read_u32(of_node, "reg", &base); + if (ret < 0) { + pr_err("reg property reading failed, ret=%d\n", ret); + return ret; + } + + chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL); + if (!chip) + return -ENOMEM; + + chip->regmap = dev_get_regmap(pdev->dev.parent, NULL); + if (!chip->regmap) { + pr_err("couldn't get parent's regmap\n"); + return -EINVAL; + } + + ret = qpnp_vib_parse_dt(&pdev->dev, chip); + if (ret < 0) { + pr_err("couldn't parse device tree, ret=%d\n", ret); + return ret; + } + + chip->base = (uint16_t)base; + chip->vib_play_ms = QPNP_VIB_PLAY_MS; + mutex_init(&chip->lock); + INIT_WORK(&chip->vib_work, qpnp_vib_work); + INIT_WORK(&chip->overdrive_work, qpnp_vib_overdrive_work); + + hrtimer_init(&chip->stop_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + chip->stop_timer.function = vib_stop_timer; + hrtimer_init(&chip->overdrive_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + chip->overdrive_timer.function = vib_overdrive_timer; + dev_set_drvdata(&pdev->dev, chip); + + chip->cdev.name = "vibrator"; + chip->cdev.brightness_get = qpnp_vib_brightness_get; + chip->cdev.brightness_set = qpnp_vib_brightness_set; + chip->cdev.max_brightness = 100; + ret = devm_led_classdev_register(&pdev->dev, &chip->cdev); + if (ret < 0) { + pr_err("Error in registering led class device, ret=%d\n", ret); + goto fail; + } + + for (i = 0; i < ARRAY_SIZE(qpnp_vib_attrs); i++) { + ret = sysfs_create_file(&chip->cdev.dev->kobj, + &qpnp_vib_attrs[i].attr); + if (ret < 0) { + dev_err(&pdev->dev, "Error in creating sysfs file, ret=%d\n", + ret); + goto sysfs_fail; + } + } + + pr_info("Vibrator LDO successfully registered: uV = %d, overdrive = %s\n", + chip->vmax_uV, + chip->disable_overdrive ? "disabled" : "enabled"); + return 0; + +sysfs_fail: + for (--i; i >= 0; i--) + sysfs_remove_file(&chip->cdev.dev->kobj, + &qpnp_vib_attrs[i].attr); +fail: + mutex_destroy(&chip->lock); + dev_set_drvdata(&pdev->dev, NULL); + return ret; +} + +static int qpnp_vibrator_ldo_remove(struct platform_device *pdev) +{ + struct vib_ldo_chip *chip = dev_get_drvdata(&pdev->dev); + + if (!chip->disable_overdrive) { + hrtimer_cancel(&chip->overdrive_timer); + cancel_work_sync(&chip->overdrive_work); + } + hrtimer_cancel(&chip->stop_timer); + cancel_work_sync(&chip->vib_work); + mutex_destroy(&chip->lock); + dev_set_drvdata(&pdev->dev, NULL); + + return 0; +} + +static const struct of_device_id vibrator_ldo_match_table[] = { + { .compatible = "qcom,qpnp-vibrator-ldo" }, + { /* sentinel */ }, +}; +MODULE_DEVICE_TABLE(of, vibrator_ldo_match_table); + +static struct platform_driver qpnp_vibrator_ldo_driver = { + .driver = { + .name = "qcom,qpnp-vibrator-ldo", + .of_match_table = vibrator_ldo_match_table, + .pm = &qpnp_vibrator_ldo_pm_ops, + }, + .probe = qpnp_vibrator_ldo_probe, + .remove = qpnp_vibrator_ldo_remove, +}; +module_platform_driver(qpnp_vibrator_ldo_driver); + +MODULE_DESCRIPTION("QCOM QPNP Vibrator-LDO driver"); +MODULE_LICENSE("GPL v2"); -- GitLab From 9427a4aecf2330ba70dd59f194416de3e49042e2 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Tue, 13 Feb 2018 07:38:08 -0800 Subject: [PATCH 0633/1635] tty: make n_tty_read() always abort if hangup is in progress commit 28b0f8a6962a24ed21737578f3b1b07424635c9e upstream. A tty is hung up by __tty_hangup() setting file->f_op to hung_up_tty_fops, which is skipped on ttys whose write operation isn't tty_write(). This means that, for example, /dev/console whose write op is redirected_tty_write() is never actually marked hung up. Because n_tty_read() uses the hung up status to decide whether to abort the waiting readers, the lack of hung-up marking can lead to the following scenario. 1. A session contains two processes. The leader and its child. The child ignores SIGHUP. 2. The leader exits and starts disassociating from the controlling terminal (/dev/console). 3. __tty_hangup() skips setting f_op to hung_up_tty_fops. 4. SIGHUP is delivered and ignored. 5. tty_ldisc_hangup() is invoked. It wakes up the waits which should clear the read lockers of tty->ldisc_sem. 6. The reader wakes up but because tty_hung_up_p() is false, it doesn't abort and goes back to sleep while read-holding tty->ldisc_sem. 7. The leader progresses to tty_ldisc_lock() in tty_ldisc_hangup() and is now stuck in D sleep indefinitely waiting for tty->ldisc_sem. The following is Alan's explanation on why some ttys aren't hung up. http://lkml.kernel.org/r/20171101170908.6ad08580@alans-desktop 1. It broke the serial consoles because they would hang up and close down the hardware. With tty_port that *should* be fixable properly for any cases remaining. 2. The console layer was (and still is) completely broken and doens't refcount properly. So if you turn on console hangups it breaks (as indeed does freeing consoles and half a dozen other things). As neither can be fixed quickly, this patch works around the problem by introducing a new flag, TTY_HUPPING, which is used solely to tell n_tty_read() that hang-up is in progress for the console and the readers should be aborted regardless of the hung-up status of the device. The following is a sample hung task warning caused by this issue. INFO: task agetty:2662 blocked for more than 120 seconds. Not tainted 4.11.3-dbg-tty-lockup-02478-gfd6c7ee-dirty #28 "echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message. 0 2662 1 0x00000086 Call Trace: __schedule+0x267/0x890 schedule+0x36/0x80 schedule_timeout+0x23c/0x2e0 ldsem_down_write+0xce/0x1f6 tty_ldisc_lock+0x16/0x30 tty_ldisc_hangup+0xb3/0x1b0 __tty_hangup+0x300/0x410 disassociate_ctty+0x6c/0x290 do_exit+0x7ef/0xb00 do_group_exit+0x3f/0xa0 get_signal+0x1b3/0x5d0 do_signal+0x28/0x660 exit_to_usermode_loop+0x46/0x86 do_syscall_64+0x9c/0xb0 entry_SYSCALL64_slow_path+0x25/0x25 The following is the repro. Run "$PROG /dev/console". The parent process hangs in D state. #include #include #include #include #include #include #include #include #include #include #include #include int main(int argc, char **argv) { struct sigaction sact = { .sa_handler = SIG_IGN }; struct timespec ts1s = { .tv_sec = 1 }; pid_t pid; int fd; if (argc < 2) { fprintf(stderr, "test-hung-tty /dev/$TTY\n"); return 1; } /* fork a child to ensure that it isn't already the session leader */ pid = fork(); if (pid < 0) { perror("fork"); return 1; } if (pid > 0) { /* top parent, wait for everyone */ while (waitpid(-1, NULL, 0) >= 0) ; if (errno != ECHILD) perror("waitpid"); return 0; } /* new session, start a new session and set the controlling tty */ if (setsid() < 0) { perror("setsid"); return 1; } fd = open(argv[1], O_RDWR); if (fd < 0) { perror("open"); return 1; } if (ioctl(fd, TIOCSCTTY, 1) < 0) { perror("ioctl"); return 1; } /* fork a child, sleep a bit and exit */ pid = fork(); if (pid < 0) { perror("fork"); return 1; } if (pid > 0) { nanosleep(&ts1s, NULL); printf("Session leader exiting\n"); exit(0); } /* * The child ignores SIGHUP and keeps reading from the controlling * tty. Because SIGHUP is ignored, the child doesn't get killed on * parent exit and the bug in n_tty makes the read(2) block the * parent's control terminal hangup attempt. The parent ends up in * D sleep until the child is explicitly killed. */ sigaction(SIGHUP, &sact, NULL); printf("Child reading tty\n"); while (1) { char buf[1024]; if (read(fd, buf, sizeof(buf)) < 0) { perror("read"); return 1; } } return 0; } Signed-off-by: Tejun Heo Cc: Alan Cox Cc: stable@vger.kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/n_tty.c | 6 ++++++ drivers/tty/tty_io.c | 9 +++++++++ include/linux/tty.h | 1 + 3 files changed, 16 insertions(+) diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c index faf50df81622..1c70541a1467 100644 --- a/drivers/tty/n_tty.c +++ b/drivers/tty/n_tty.c @@ -2182,6 +2182,12 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file, } if (tty_hung_up_p(file)) break; + /* + * Abort readers for ttys which never actually + * get hung up. See __tty_hangup(). + */ + if (test_bit(TTY_HUPPING, &tty->flags)) + break; if (!timeout) break; if (file->f_flags & O_NONBLOCK) { diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c index 7e77bd2118ad..52627478ab61 100644 --- a/drivers/tty/tty_io.c +++ b/drivers/tty/tty_io.c @@ -585,6 +585,14 @@ static void __tty_hangup(struct tty_struct *tty, int exit_session) return; } + /* + * Some console devices aren't actually hung up for technical and + * historical reasons, which can lead to indefinite interruptible + * sleep in n_tty_read(). The following explicitly tells + * n_tty_read() to abort readers. + */ + set_bit(TTY_HUPPING, &tty->flags); + /* inuse_filps is protected by the single tty lock, this really needs to change if we want to flush the workqueue with the lock held */ @@ -639,6 +647,7 @@ static void __tty_hangup(struct tty_struct *tty, int exit_session) * from the ldisc side, which is now guaranteed. */ set_bit(TTY_HUPPED, &tty->flags); + clear_bit(TTY_HUPPING, &tty->flags); tty_unlock(tty); if (f) diff --git a/include/linux/tty.h b/include/linux/tty.h index 0a6c71e0ad01..47f8af22f216 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h @@ -364,6 +364,7 @@ struct tty_file_private { #define TTY_PTY_LOCK 16 /* pty private */ #define TTY_NO_WRITE_SPLIT 17 /* Preserve write boundaries to driver */ #define TTY_HUPPED 18 /* Post driver->hangup() */ +#define TTY_HUPPING 19 /* Hangup in progress */ #define TTY_LDISC_HALTED 22 /* Line discipline is halted */ /* Values for tty->flow_change */ -- GitLab From f1e90bf95e5503fcedaf59ac52cbdc013068eeb4 Mon Sep 17 00:00:00 2001 From: George Cherian Date: Fri, 23 Mar 2018 03:30:31 -0700 Subject: [PATCH 0634/1635] cpufreq: CPPC: Use transition_delay_us depending transition_latency commit 3d41386d556db9f720e00de3e11e45f39cb5071c upstream. With commit e948bc8fbee0 (cpufreq: Cap the default transition delay value to 10 ms) the cpufreq was not honouring the delay passed via ACPI (PCCT). Due to which on ARM based platforms using CPPC the cpufreq governor tries to change the frequency of CPUs faster than expected. This leads to continuous error messages like the following. " ACPI CPPC: PCC check channel failed. Status=0 " Earlier (without above commit) the default transition delay was taken form the value passed from PCCT. Use the same value provided by PCCT to set the transition_delay_us. Fixes: e948bc8fbee0 (cpufreq: Cap the default transition delay value to 10 ms) Signed-off-by: George Cherian Cc: 4.14+ # 4.14+ Signed-off-by: Rafael J. Wysocki Signed-off-by: Greg Kroah-Hartman --- drivers/cpufreq/cppc_cpufreq.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/cpufreq/cppc_cpufreq.c b/drivers/cpufreq/cppc_cpufreq.c index a1c3025f9df7..dcb1cb9a4572 100644 --- a/drivers/cpufreq/cppc_cpufreq.c +++ b/drivers/cpufreq/cppc_cpufreq.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -162,6 +163,8 @@ static int cppc_cpufreq_cpu_init(struct cpufreq_policy *policy) policy->cpuinfo.max_freq = cppc_dmi_max_khz; policy->cpuinfo.transition_latency = cppc_get_transition_latency(cpu_num); + policy->transition_delay_us = cppc_get_transition_latency(cpu_num) / + NSEC_PER_USEC; policy->shared_type = cpu->shared_type; if (policy->shared_type == CPUFREQ_SHARED_TYPE_ANY) -- GitLab From 09844df060879db7d7fbec2c22c7f3c92f6b6b57 Mon Sep 17 00:00:00 2001 From: Richard Weinberger Date: Wed, 17 Jan 2018 19:12:42 +0100 Subject: [PATCH 0635/1635] ubifs: Check ubifs_wbuf_sync() return code commit aac17948a7ce01fb60b9ee6cf902967a47b3ce26 upstream. If ubifs_wbuf_sync() fails we must not write a master node with the dirty marker cleared. Otherwise it is possible that in case of an IO error while syncing we mark the filesystem as clean and UBIFS refuses to recover upon next mount. Cc: Fixes: 1e51764a3c2a ("UBIFS: add new flash file system") Signed-off-by: Richard Weinberger Signed-off-by: Greg Kroah-Hartman --- fs/ubifs/super.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/fs/ubifs/super.c b/fs/ubifs/super.c index 5496b17b959c..e1cd3dcf5a03 100644 --- a/fs/ubifs/super.c +++ b/fs/ubifs/super.c @@ -1739,8 +1739,11 @@ static void ubifs_remount_ro(struct ubifs_info *c) dbg_save_space_info(c); - for (i = 0; i < c->jhead_cnt; i++) - ubifs_wbuf_sync(&c->jheads[i].wbuf); + for (i = 0; i < c->jhead_cnt; i++) { + err = ubifs_wbuf_sync(&c->jheads[i].wbuf); + if (err) + ubifs_ro_mode(c, err); + } c->mst_node->flags &= ~cpu_to_le32(UBIFS_MST_DIRTY); c->mst_node->flags |= cpu_to_le32(UBIFS_MST_NO_ORPHS); @@ -1806,8 +1809,11 @@ static void ubifs_put_super(struct super_block *sb) int err; /* Synchronize write-buffers */ - for (i = 0; i < c->jhead_cnt; i++) - ubifs_wbuf_sync(&c->jheads[i].wbuf); + for (i = 0; i < c->jhead_cnt; i++) { + err = ubifs_wbuf_sync(&c->jheads[i].wbuf); + if (err) + ubifs_ro_mode(c, err); + } /* * We are being cleanly unmounted which means the -- GitLab From bf3fbf54a9aec60eac770b2e69b4762c09082bd1 Mon Sep 17 00:00:00 2001 From: Richard Weinberger Date: Wed, 17 Jan 2018 23:15:57 +0100 Subject: [PATCH 0636/1635] ubi: fastmap: Don't flush fastmap work on detach commit 29b7a6fa1ec07e8480b0d9caf635a4498a438bf4 upstream. At this point UBI volumes have already been free()'ed and fastmap can no longer access these data structures. Reported-by: Martin Townsend Fixes: 74cdaf24004a ("UBI: Fastmap: Fix memory leaks while closing the WL sub-system") Cc: stable@vger.kernel.org Signed-off-by: Richard Weinberger Signed-off-by: Greg Kroah-Hartman --- drivers/mtd/ubi/fastmap-wl.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/mtd/ubi/fastmap-wl.c b/drivers/mtd/ubi/fastmap-wl.c index 4f0bd6b4422a..69dd21679a30 100644 --- a/drivers/mtd/ubi/fastmap-wl.c +++ b/drivers/mtd/ubi/fastmap-wl.c @@ -362,7 +362,6 @@ static void ubi_fastmap_close(struct ubi_device *ubi) { int i; - flush_work(&ubi->fm_work); return_unused_pool_pebs(ubi, &ubi->fm_pool); return_unused_pool_pebs(ubi, &ubi->fm_wl_pool); -- GitLab From 7ade852714ded6f3ede2708e036e13ed4c63335d Mon Sep 17 00:00:00 2001 From: Romain Izard Date: Mon, 29 Jan 2018 11:18:20 +0100 Subject: [PATCH 0637/1635] ubi: Fix error for write access commit 78a8dfbabbece22bee58ac4cb26cab10e7a19c5d upstream. When opening a device with write access, ubiblock_open returns an error code. Currently, this error code is -EPERM, but this is not the right value. The open function for other block devices returns -EROFS when opening read-only devices with FMODE_WRITE set. When used with dm-verity, the veritysetup userspace tool is expecting EROFS, and refuses to use the ubiblock device. Use -EROFS for ubiblock as well. As a result, veritysetup accepts the ubiblock device as valid. Cc: stable@vger.kernel.org Fixes: 9d54c8a33eec (UBI: R/O block driver on top of UBI volumes) Signed-off-by: Romain Izard Signed-off-by: Richard Weinberger Signed-off-by: Greg Kroah-Hartman --- drivers/mtd/ubi/block.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mtd/ubi/block.c b/drivers/mtd/ubi/block.c index b1fc28f63882..d0b63bbf46a7 100644 --- a/drivers/mtd/ubi/block.c +++ b/drivers/mtd/ubi/block.c @@ -244,7 +244,7 @@ static int ubiblock_open(struct block_device *bdev, fmode_t mode) * in any case. */ if (mode & FMODE_WRITE) { - ret = -EPERM; + ret = -EROFS; goto out_unlock; } -- GitLab From 577b4eb23811dfc8e38924dc476dbc866be74253 Mon Sep 17 00:00:00 2001 From: Richard Weinberger Date: Sat, 3 Mar 2018 11:45:54 +0100 Subject: [PATCH 0638/1635] ubi: Reject MLC NAND commit b5094b7f135be34630e3ea8a98fa215715d0f29d upstream. While UBI and UBIFS seem to work at first sight with MLC NAND, you will most likely lose all your data upon a power-cut or due to read/write disturb. In order to protect users from bad surprises, refuse to attach to MLC NAND. Cc: stable@vger.kernel.org Signed-off-by: Richard Weinberger Acked-by: Boris Brezillon Acked-by: Artem Bityutskiy Signed-off-by: Greg Kroah-Hartman --- drivers/mtd/ubi/build.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c index 842550b5712a..defb1cd8d2e1 100644 --- a/drivers/mtd/ubi/build.c +++ b/drivers/mtd/ubi/build.c @@ -845,6 +845,17 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, return -EINVAL; } + /* + * Both UBI and UBIFS have been designed for SLC NAND and NOR flashes. + * MLC NAND is different and needs special care, otherwise UBI or UBIFS + * will die soon and you will lose all your data. + */ + if (mtd->type == MTD_MLCNANDFLASH) { + pr_err("ubi: refuse attaching mtd%d - MLC NAND is not supported\n", + mtd->index); + return -EINVAL; + } + if (ubi_num == UBI_DEV_NUM_AUTO) { /* Search for an empty slot in the @ubi_devices array */ for (ubi_num = 0; ubi_num < UBI_MAX_DEVICES; ubi_num++) -- GitLab From e84e6914ccb464ce5cbb99fd832a4673bb119adc Mon Sep 17 00:00:00 2001 From: Claudio Imbrenda Date: Tue, 10 Apr 2018 16:29:41 -0700 Subject: [PATCH 0639/1635] mm/ksm.c: fix inconsistent accounting of zero pages commit a38c015f3156895b07e71d4e4414289f8a3b2745 upstream. When using KSM with use_zero_pages, we replace anonymous pages containing only zeroes with actual zero pages, which are not anonymous. We need to do proper accounting of the mm counters, otherwise we will get wrong values in /proc and a BUG message in dmesg when tearing down the mm. Link: http://lkml.kernel.org/r/1522931274-15552-1-git-send-email-imbrenda@linux.vnet.ibm.com Fixes: e86c59b1b1 ("mm/ksm: improve deduplication of zero pages with colouring") Signed-off-by: Claudio Imbrenda Reviewed-by: Andrew Morton Cc: Andrea Arcangeli Cc: Minchan Kim Cc: Kirill A. Shutemov Cc: Hugh Dickins Cc: Christian Borntraeger Cc: Gerald Schaefer Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- mm/ksm.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/mm/ksm.c b/mm/ksm.c index 6cb60f46cce5..5b6be9eeb095 100644 --- a/mm/ksm.c +++ b/mm/ksm.c @@ -1133,6 +1133,13 @@ static int replace_page(struct vm_area_struct *vma, struct page *page, } else { newpte = pte_mkspecial(pfn_pte(page_to_pfn(kpage), vma->vm_page_prot)); + /* + * We're replacing an anonymous page with a zero page, which is + * not anonymous. We need to do proper accounting otherwise we + * will get wrong values in /proc, and a BUG message in dmesg + * when tearing down the mm. + */ + dec_mm_counter(mm, MM_ANONPAGES); } flush_cache_page(vma, addr, pte_pfn(*ptep)); -- GitLab From 963722d031e506600b66b91738e2007bf55ac3d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Glisse?= Date: Tue, 10 Apr 2018 16:28:15 -0700 Subject: [PATCH 0640/1635] mm/hmm: fix header file if/else/endif maze MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit b28b08de436a638c82d0cf3dcdbdbad055baf1fc upstream. The #if/#else/#endif for IS_ENABLED(CONFIG_HMM) were wrong. Because of this after multiple include there was multiple definition of both hmm_mm_init() and hmm_mm_destroy() leading to build failure if HMM was enabled (CONFIG_HMM set). Link: http://lkml.kernel.org/r/20180323005527.758-3-jglisse@redhat.com Signed-off-by: Jérôme Glisse Acked-by: Balbir Singh Cc: Andrew Morton Cc: Ralph Campbell Cc: John Hubbard Cc: Evgeny Baskakov Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- include/linux/hmm.h | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/include/linux/hmm.h b/include/linux/hmm.h index 96e69979f84d..8198faf16ed6 100644 --- a/include/linux/hmm.h +++ b/include/linux/hmm.h @@ -498,23 +498,16 @@ struct hmm_device { struct hmm_device *hmm_device_new(void *drvdata); void hmm_device_put(struct hmm_device *hmm_device); #endif /* CONFIG_DEVICE_PRIVATE || CONFIG_DEVICE_PUBLIC */ -#endif /* IS_ENABLED(CONFIG_HMM) */ /* Below are for HMM internal use only! Not to be used by device driver! */ -#if IS_ENABLED(CONFIG_HMM_MIRROR) void hmm_mm_destroy(struct mm_struct *mm); static inline void hmm_mm_init(struct mm_struct *mm) { mm->hmm = NULL; } -#else /* IS_ENABLED(CONFIG_HMM_MIRROR) */ -static inline void hmm_mm_destroy(struct mm_struct *mm) {} -static inline void hmm_mm_init(struct mm_struct *mm) {} -#endif /* IS_ENABLED(CONFIG_HMM_MIRROR) */ - - #else /* IS_ENABLED(CONFIG_HMM) */ static inline void hmm_mm_destroy(struct mm_struct *mm) {} static inline void hmm_mm_init(struct mm_struct *mm) {} +#endif /* IS_ENABLED(CONFIG_HMM) */ #endif /* LINUX_HMM_H */ -- GitLab From 28cb085f1598956b5b29edb7f220ce9e0d827762 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Glisse?= Date: Tue, 10 Apr 2018 16:28:27 -0700 Subject: [PATCH 0641/1635] mm/hmm: hmm_pfns_bad() was accessing wrong struct MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit c719547f032d4610c7a20900baacae26d0b1ff3e upstream. The private field of mm_walk struct point to an hmm_vma_walk struct and not to the hmm_range struct desired. Fix to get proper struct pointer. Link: http://lkml.kernel.org/r/20180323005527.758-6-jglisse@redhat.com Signed-off-by: Jérôme Glisse Cc: Evgeny Baskakov Cc: Ralph Campbell Cc: Mark Hairgrove Cc: John Hubbard Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- mm/hmm.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mm/hmm.c b/mm/hmm.c index a88a847bccba..81ff1dbbf8a8 100644 --- a/mm/hmm.c +++ b/mm/hmm.c @@ -277,7 +277,8 @@ static int hmm_pfns_bad(unsigned long addr, unsigned long end, struct mm_walk *walk) { - struct hmm_range *range = walk->private; + struct hmm_vma_walk *hmm_vma_walk = walk->private; + struct hmm_range *range = hmm_vma_walk->range; hmm_pfn_t *pfns = range->pfns; unsigned long i; -- GitLab From 6337067b2ab66c91b18b895c2399139b28f13fb7 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Tue, 10 Apr 2018 16:32:44 -0700 Subject: [PATCH 0642/1635] task_struct: only use anon struct under randstruct plugin commit 2cfe0d3009418a132b93d78642a8059a38fe5944 upstream. The original intent for always adding the anonymous struct in task_struct was to make sure we had compiler coverage. However, this caused pathological padding of 40 bytes at the start of task_struct. Instead, move the anonymous struct to being only used when struct layout randomization is enabled. Link: http://lkml.kernel.org/r/20180327213609.GA2964@beast Fixes: 29e48ce87f1e ("task_struct: Allow randomized") Signed-off-by: Kees Cook Reported-by: Peter Zijlstra Cc: Peter Zijlstra Cc: Ingo Molnar Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- include/linux/compiler-clang.h | 3 --- include/linux/compiler-gcc.h | 12 +++--------- 2 files changed, 3 insertions(+), 12 deletions(-) diff --git a/include/linux/compiler-clang.h b/include/linux/compiler-clang.h index be3aef6839f6..070f85d92c15 100644 --- a/include/linux/compiler-clang.h +++ b/include/linux/compiler-clang.h @@ -17,9 +17,6 @@ */ #define __UNIQUE_ID(prefix) __PASTE(__PASTE(__UNIQUE_ID_, prefix), __COUNTER__) -#define randomized_struct_fields_start struct { -#define randomized_struct_fields_end }; - /* Clang doesn't have a way to turn it off per-function, yet. */ #ifdef __noretpoline #undef __noretpoline diff --git a/include/linux/compiler-gcc.h b/include/linux/compiler-gcc.h index a1ffbf25873f..b78b31af36f8 100644 --- a/include/linux/compiler-gcc.h +++ b/include/linux/compiler-gcc.h @@ -229,6 +229,9 @@ #ifdef RANDSTRUCT_PLUGIN #define __randomize_layout __attribute__((randomize_layout)) #define __no_randomize_layout __attribute__((no_randomize_layout)) +/* This anon struct can add padding, so only enable it under randstruct. */ +#define randomized_struct_fields_start struct { +#define randomized_struct_fields_end } __randomize_layout; #endif #endif /* GCC_VERSION >= 40500 */ @@ -243,15 +246,6 @@ */ #define __visible __attribute__((externally_visible)) -/* - * RANDSTRUCT_PLUGIN wants to use an anonymous struct, but it is only - * possible since GCC 4.6. To provide as much build testing coverage - * as possible, this is used for all GCC 4.6+ builds, and not just on - * RANDSTRUCT_PLUGIN builds. - */ -#define randomized_struct_fields_start struct { -#define randomized_struct_fields_end } __randomize_layout; - #endif /* GCC_VERSION >= 40600 */ -- GitLab From f659e7e79f52657b88ea0f9ed473fe0958d31996 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Tue, 10 Apr 2018 16:34:41 -0700 Subject: [PATCH 0643/1635] fs/reiserfs/journal.c: add missing resierfs_warning() arg commit 9ad553abe66f8be3f4755e9fa0a6ba137ce76341 upstream. One use of the reiserfs_warning() macro in journal_init_dev() is missing a parameter, causing the following warning: REISERFS warning (device loop0): journal_init_dev: Cannot open '%s': %i journal_init_dev: This also causes a WARN_ONCE() warning in the vsprintf code, and then a panic if panic_on_warn is set. Please remove unsupported %/ in format string WARNING: CPU: 1 PID: 4480 at lib/vsprintf.c:2138 format_decode+0x77f/0x830 lib/vsprintf.c:2138 Kernel panic - not syncing: panic_on_warn set ... Just add another string argument to the macro invocation. Addresses https://syzkaller.appspot.com/bug?id=0627d4551fdc39bf1ef5d82cd9eef587047f7718 Link: http://lkml.kernel.org/r/d678ebe1-6f54-8090-df4c-b9affad62293@infradead.org Signed-off-by: Randy Dunlap Reported-by: Tested-by: Randy Dunlap Acked-by: Jeff Mahoney Cc: Alexander Viro Cc: Jan Kara Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- fs/reiserfs/journal.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/reiserfs/journal.c b/fs/reiserfs/journal.c index 69ff280bdfe8..2be907231375 100644 --- a/fs/reiserfs/journal.c +++ b/fs/reiserfs/journal.c @@ -2643,7 +2643,7 @@ static int journal_init_dev(struct super_block *super, if (IS_ERR(journal->j_dev_bd)) { result = PTR_ERR(journal->j_dev_bd); journal->j_dev_bd = NULL; - reiserfs_warning(super, + reiserfs_warning(super, "sh-457", "journal_init_dev: Cannot open '%s': %i", jdev_name, result); return result; -- GitLab From c25ef6220facd0ec7df7f3af0a5f5f24ab9659e8 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 13 Apr 2018 15:35:13 -0700 Subject: [PATCH 0644/1635] resource: fix integer overflow at reallocation commit 60bb83b81169820c691fbfa33a6a4aef32aa4b0b upstream. We've got a bug report indicating a kernel panic at booting on an x86-32 system, and it turned out to be the invalid PCI resource assigned after reallocation. __find_resource() first aligns the resource start address and resets the end address with start+size-1 accordingly, then checks whether it's contained. Here the end address may overflow the integer, although resource_contains() still returns true because the function validates only start and end address. So this ends up with returning an invalid resource (start > end). There was already an attempt to cover such a problem in the commit 47ea91b4052d ("Resource: fix wrong resource window calculation"), but this case is an overseen one. This patch adds the validity check of the newly calculated resource for avoiding the integer overflow problem. Bugzilla: http://bugzilla.opensuse.org/show_bug.cgi?id=1086739 Link: http://lkml.kernel.org/r/s5hpo37d5l8.wl-tiwai@suse.de Fixes: 23c570a67448 ("resource: ability to resize an allocated resource") Signed-off-by: Takashi Iwai Reported-by: Michael Henders Tested-by: Michael Henders Reviewed-by: Andrew Morton Cc: Ram Pai Cc: Bjorn Helgaas Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- kernel/resource.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/kernel/resource.c b/kernel/resource.c index 9b5f04404152..7ee3dd1ad2af 100644 --- a/kernel/resource.c +++ b/kernel/resource.c @@ -633,7 +633,8 @@ static int __find_resource(struct resource *root, struct resource *old, alloc.start = constraint->alignf(constraint->alignf_data, &avail, size, constraint->align); alloc.end = alloc.start + size - 1; - if (resource_contains(&avail, &alloc)) { + if (alloc.start <= alloc.end && + resource_contains(&avail, &alloc)) { new->start = alloc.start; new->end = alloc.end; return 0; -- GitLab From 703eee654360679660c813a591176c7bf4016254 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Fri, 13 Apr 2018 15:35:30 -0700 Subject: [PATCH 0645/1635] ipc/shm: fix use-after-free of shm file via remap_file_pages() commit 3f05317d9889ab75c7190dcd39491d2a97921984 upstream. syzbot reported a use-after-free of shm_file_data(file)->file->f_op in shm_get_unmapped_area(), called via sys_remap_file_pages(). Unfortunately it couldn't generate a reproducer, but I found a bug which I think caused it. When remap_file_pages() is passed a full System V shared memory segment, the memory is first unmapped, then a new map is created using the ->vm_file. Between these steps, the shm ID can be removed and reused for a new shm segment. But, shm_mmap() only checks whether the ID is currently valid before calling the underlying file's ->mmap(); it doesn't check whether it was reused. Thus it can use the wrong underlying file, one that was already freed. Fix this by making the "outer" shm file (the one that gets put in ->vm_file) hold a reference to the real shm file, and by making __shm_open() require that the file associated with the shm ID matches the one associated with the "outer" file. Taking the reference to the real shm file is needed to fully solve the problem, since otherwise sfd->file could point to a freed file, which then could be reallocated for the reused shm ID, causing the wrong shm segment to be mapped (and without the required permission checks). Commit 1ac0b6dec656 ("ipc/shm: handle removed segments gracefully in shm_mmap()") almost fixed this bug, but it didn't go far enough because it didn't consider the case where the shm ID is reused. The following program usually reproduces this bug: #include #include #include #include int main() { int is_parent = (fork() != 0); srand(getpid()); for (;;) { int id = shmget(0xF00F, 4096, IPC_CREAT|0700); if (is_parent) { void *addr = shmat(id, NULL, 0); usleep(rand() % 50); while (!syscall(__NR_remap_file_pages, addr, 4096, 0, 0, 0)); } else { usleep(rand() % 50); shmctl(id, IPC_RMID, NULL); } } } It causes the following NULL pointer dereference due to a 'struct file' being used while it's being freed. (I couldn't actually get a KASAN use-after-free splat like in the syzbot report. But I think it's possible with this bug; it would just take a more extraordinary race...) BUG: unable to handle kernel NULL pointer dereference at 0000000000000058 PGD 0 P4D 0 Oops: 0000 [#1] SMP NOPTI CPU: 9 PID: 258 Comm: syz_ipc Not tainted 4.16.0-05140-gf8cf2f16a7c95 #189 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.11.0-20171110_100015-anatol 04/01/2014 RIP: 0010:d_inode include/linux/dcache.h:519 [inline] RIP: 0010:touch_atime+0x25/0xd0 fs/inode.c:1724 [...] Call Trace: file_accessed include/linux/fs.h:2063 [inline] shmem_mmap+0x25/0x40 mm/shmem.c:2149 call_mmap include/linux/fs.h:1789 [inline] shm_mmap+0x34/0x80 ipc/shm.c:465 call_mmap include/linux/fs.h:1789 [inline] mmap_region+0x309/0x5b0 mm/mmap.c:1712 do_mmap+0x294/0x4a0 mm/mmap.c:1483 do_mmap_pgoff include/linux/mm.h:2235 [inline] SYSC_remap_file_pages mm/mmap.c:2853 [inline] SyS_remap_file_pages+0x232/0x310 mm/mmap.c:2769 do_syscall_64+0x64/0x1a0 arch/x86/entry/common.c:287 entry_SYSCALL_64_after_hwframe+0x42/0xb7 [ebiggers@google.com: add comment] Link: http://lkml.kernel.org/r/20180410192850.235835-1-ebiggers3@gmail.com Link: http://lkml.kernel.org/r/20180409043039.28915-1-ebiggers3@gmail.com Reported-by: syzbot+d11f321e7f1923157eac80aa990b446596f46439@syzkaller.appspotmail.com Fixes: c8d78c1823f4 ("mm: replace remap_file_pages() syscall with emulation") Signed-off-by: Eric Biggers Acked-by: Kirill A. Shutemov Acked-by: Davidlohr Bueso Cc: Manfred Spraul Cc: "Eric W . Biederman" Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- ipc/shm.c | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/ipc/shm.c b/ipc/shm.c index b469e910f887..a9cce632ed48 100644 --- a/ipc/shm.c +++ b/ipc/shm.c @@ -203,6 +203,12 @@ static int __shm_open(struct vm_area_struct *vma) if (IS_ERR(shp)) return PTR_ERR(shp); + if (shp->shm_file != sfd->file) { + /* ID was reused */ + shm_unlock(shp); + return -EINVAL; + } + shp->shm_atim = ktime_get_real_seconds(); shp->shm_lprid = task_tgid_vnr(current); shp->shm_nattch++; @@ -431,8 +437,9 @@ static int shm_mmap(struct file *file, struct vm_area_struct *vma) int ret; /* - * In case of remap_file_pages() emulation, the file can represent - * removed IPC ID: propogate shm_lock() error to caller. + * In case of remap_file_pages() emulation, the file can represent an + * IPC ID that was removed, and possibly even reused by another shm + * segment already. Propagate this case as an error to caller. */ ret = __shm_open(vma); if (ret) @@ -456,6 +463,7 @@ static int shm_release(struct inode *ino, struct file *file) struct shm_file_data *sfd = shm_file_data(file); put_ipc_ns(sfd->ns); + fput(sfd->file); shm_file_data(file) = NULL; kfree(sfd); return 0; @@ -1391,7 +1399,16 @@ long do_shmat(int shmid, char __user *shmaddr, int shmflg, file->f_mapping = shp->shm_file->f_mapping; sfd->id = shp->shm_perm.id; sfd->ns = get_ipc_ns(ns); - sfd->file = shp->shm_file; + /* + * We need to take a reference to the real shm file to prevent the + * pointer from becoming stale in cases where the lifetime of the outer + * file extends beyond that of the shm segment. It's not usually + * possible, but it can happen during remap_file_pages() emulation as + * that unmaps the memory, then does ->mmap() via file reference only. + * We'll deny the ->mmap() if the shm segment was since removed, but to + * detect shm ID reuse we need to compare the file pointers. + */ + sfd->file = get_file(shp->shm_file); sfd->vm_ops = NULL; err = security_mmap_file(file, prot, flags); -- GitLab From 20eaa393fcd32fe48f2e13ce649e90a48a446fe6 Mon Sep 17 00:00:00 2001 From: Vlastimil Babka Date: Fri, 13 Apr 2018 15:35:38 -0700 Subject: [PATCH 0646/1635] mm, slab: reschedule cache_reap() on the same CPU commit a9f2a846f0503e7d729f552e3ccfe2279010fe94 upstream. cache_reap() is initially scheduled in start_cpu_timer() via schedule_delayed_work_on(). But then the next iterations are scheduled via schedule_delayed_work(), i.e. using WORK_CPU_UNBOUND. Thus since commit ef557180447f ("workqueue: schedule WORK_CPU_UNBOUND work on wq_unbound_cpumask CPUs") there is no guarantee the future iterations will run on the originally intended cpu, although it's still preferred. I was able to demonstrate this with /sys/module/workqueue/parameters/debug_force_rr_cpu. IIUC, it may also happen due to migrating timers in nohz context. As a result, some cpu's would be calling cache_reap() more frequently and others never. This patch uses schedule_delayed_work_on() with the current cpu when scheduling the next iteration. Link: http://lkml.kernel.org/r/20180411070007.32225-1-vbabka@suse.cz Fixes: ef557180447f ("workqueue: schedule WORK_CPU_UNBOUND work on wq_unbound_cpumask CPUs") Signed-off-by: Vlastimil Babka Acked-by: Pekka Enberg Acked-by: Christoph Lameter Cc: Joonsoo Kim Cc: David Rientjes Cc: Tejun Heo Cc: Lai Jiangshan Cc: John Stultz Cc: Thomas Gleixner Cc: Stephen Boyd Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- mm/slab.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mm/slab.c b/mm/slab.c index 966839a1ac2c..1bfc3d847a0a 100644 --- a/mm/slab.c +++ b/mm/slab.c @@ -4080,7 +4080,8 @@ static void cache_reap(struct work_struct *w) next_reap_node(); out: /* Set up the next iteration */ - schedule_delayed_work(work, round_jiffies_relative(REAPTIMEOUT_AC)); + schedule_delayed_work_on(smp_processor_id(), work, + round_jiffies_relative(REAPTIMEOUT_AC)); } #ifdef CONFIG_SLABINFO -- GitLab From 334d8f201ef5f9c32ab26fbc868952ffb86dc175 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Thu, 29 Mar 2018 10:48:28 -0500 Subject: [PATCH 0647/1635] usb: musb: gadget: misplaced out of bounds check commit af6f8529098aeb0e56a68671b450cf74e7a64fcd upstream. musb->endpoints[] has array size MUSB_C_NUM_EPS. We must check array bounds before accessing the array and not afterwards. Signed-off-by: Heinrich Schuchardt Signed-off-by: Bin Liu Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/usb/musb/musb_gadget_ep0.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/drivers/usb/musb/musb_gadget_ep0.c b/drivers/usb/musb/musb_gadget_ep0.c index 844a309fe895..e85b9c2a4910 100644 --- a/drivers/usb/musb/musb_gadget_ep0.c +++ b/drivers/usb/musb/musb_gadget_ep0.c @@ -114,15 +114,19 @@ static int service_tx_status_request( } is_in = epnum & USB_DIR_IN; - if (is_in) { - epnum &= 0x0f; + epnum &= 0x0f; + if (epnum >= MUSB_C_NUM_EPS) { + handled = -EINVAL; + break; + } + + if (is_in) ep = &musb->endpoints[epnum].ep_in; - } else { + else ep = &musb->endpoints[epnum].ep_out; - } regs = musb->endpoints[epnum].regs; - if (epnum >= MUSB_C_NUM_EPS || !ep->desc) { + if (!ep->desc) { handled = -EINVAL; break; } -- GitLab From aea6c0b4aee80367bd091ebd2132b6db533c1ed1 Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Fri, 19 Jan 2018 17:25:41 +0800 Subject: [PATCH 0648/1635] phy: allwinner: sun4i-usb: poll vbus changes on A23/A33 when driving VBUS commit d7119224bfe6e8efbf821a52db7da9530d790f07 upstream. The AXP223 PMIC, like the AXP221, does not generate VBUS change interrupts when N_VBUSEN is used to drive VBUS for the OTG port on the board. This was not noticed until recently, as most A23/A33 boards use a GPIO pin that does not support interrupts for OTG ID detection. This forces the driver to use polling. However the A33-OlinuXino uses a pin that does support interrupts, so the driver uses them. However the VBUS interrupt never fires, and the driver never gets to update the VBUS status. This results in musb timing out waiting for VBUS to rise. This was worked around for the AXP221 by resorting to polling changes in commit 91d96f06a760 ("phy-sun4i-usb: Add workaround for missing Vbus det interrupts on A31"). This patch adds the A23 and A33 to the list of SoCs that need the workaround. Fixes: fc1f45ed3043 ("phy-sun4i-usb: Add support for the usb-phys on the sun8i-a33 SoC") Fixes: 123dfdbcfaf5 ("phy-sun4i-usb: Add support for the usb-phys on the sun8i-a23 SoC") Cc: # 4.3.x: 68dbc2ce77bb phy-sun4i-usb: Use of_match_node to get model specific config data Cc: # 4.3.x: 5cf700ac9d50 phy: phy-sun4i-usb: Fix optional gpios failing probe Cc: # 4.3.x: 04e59a0211ff phy-sun4i-usb: Fix irq free conditions to match request conditions Cc: # 4.3.x: 91d96f06a760 phy-sun4i-usb: Add workaround for missing Vbus det interrupts on A31 Cc: # 4.3.x Signed-off-by: Chen-Yu Tsai Acked-by: Maxime Ripard Signed-off-by: Kishon Vijay Abraham I Signed-off-by: Greg Kroah-Hartman Signed-off-by: Kishon Vijay Abraham I --- drivers/phy/allwinner/phy-sun4i-usb.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/phy/allwinner/phy-sun4i-usb.c b/drivers/phy/allwinner/phy-sun4i-usb.c index 1161e11fb3cf..afedb8cd1990 100644 --- a/drivers/phy/allwinner/phy-sun4i-usb.c +++ b/drivers/phy/allwinner/phy-sun4i-usb.c @@ -410,11 +410,13 @@ static bool sun4i_usb_phy0_poll(struct sun4i_usb_phy_data *data) return true; /* - * The A31 companion pmic (axp221) does not generate vbus change - * interrupts when the board is driving vbus, so we must poll + * The A31/A23/A33 companion pmics (AXP221/AXP223) do not + * generate vbus change interrupts when the board is driving + * vbus using the N_VBUSEN pin on the pmic, so we must poll * when using the pmic for vbus-det _and_ we're driving vbus. */ - if (data->cfg->type == sun6i_a31_phy && + if ((data->cfg->type == sun6i_a31_phy || + data->cfg->type == sun8i_a33_phy) && data->vbus_power_supply && data->phys[0].regulator_on) return true; @@ -885,7 +887,7 @@ static const struct sun4i_usb_phy_cfg sun7i_a20_cfg = { static const struct sun4i_usb_phy_cfg sun8i_a23_cfg = { .num_phys = 2, - .type = sun4i_a10_phy, + .type = sun6i_a31_phy, .disc_thresh = 3, .phyctl_offset = REG_PHYCTL_A10, .dedicated_clocks = true, -- GitLab From 7732495c599c0b98ff17097637f239e1ef108e69 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Mon, 26 Mar 2018 13:14:46 +0300 Subject: [PATCH 0649/1635] usb: gadget: udc: core: update usb_ep_queue() documentation commit eaa358c7790338d83bb6a31258bdc077de120414 upstream. Mention that ->complete() should never be called from within usb_ep_queue(). Signed-off-by: Felipe Balbi Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/udc/core.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/usb/gadget/udc/core.c b/drivers/usb/gadget/udc/core.c index 794bb4958383..5bab09294a8a 100644 --- a/drivers/usb/gadget/udc/core.c +++ b/drivers/usb/gadget/udc/core.c @@ -249,6 +249,9 @@ EXPORT_SYMBOL_GPL(usb_ep_free_request); * arranges to poll once per interval, and the gadget driver usually will * have queued some data to transfer at that time. * + * Note that @req's ->complete() callback must never be called from + * within usb_ep_queue() as that can create deadlock situations. + * * Returns zero, or a negative error code. Endpoints that are not enabled * report errors; errors will also be * reported when the usb peripheral is disconnected. -- GitLab From 8fdbba69cb3424b8ff470da40980d4edfec19769 Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Fri, 2 Mar 2018 14:44:36 +0100 Subject: [PATCH 0650/1635] ARM64: dts: meson: reduce odroid-c2 eMMC maximum rate commit c04ffa71ff491220cac28f55237c9aad379a8656 upstream. Different modules maybe installed by the user on the eMMC connector of the odroid-c2. While the red modules are working without an issue, it seems some black modules (apparently Samsung based) are having issue at 200MHz While the tuning algorithm introduced in v4.14 enables high speed modes on every other tested designs, it seems a problem remains for this particular combination of board and eMMC module. Lowering the maximum frequency of the eMMC on this board until we can figure out a better solution. Fixes: d341ca88eead ("mmc: meson-gx: rework tuning function") Suggested-by: Ellie Reeves Signed-off-by: Jerome Brunet Cc: stable@vger.kernel.org Signed-off-by: Kevin Hilman Signed-off-by: Greg Kroah-Hartman --- arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts b/arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts index 08b7bb7f5b74..c3c65b06ba76 100644 --- a/arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts +++ b/arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts @@ -276,7 +276,7 @@ pinctrl-names = "default", "clk-gate"; bus-width = <8>; - max-frequency = <200000000>; + max-frequency = <100000000>; non-removable; disable-wp; cap-mmc-highspeed; -- GitLab From 8f1a2803e4c2163c013816f7b41c85b91c9124c9 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Fri, 23 Mar 2018 14:57:09 +0000 Subject: [PATCH 0651/1635] KVM: arm/arm64: vgic-its: Fix potential overrun in vgic_copy_lpi_list commit 7d8b44c54e0c7c8f688e3a07f17e6083f849f01f upstream. vgic_copy_lpi_list() parses the LPI list and picks LPIs targeting a given vcpu. We allocate the array containing the intids before taking the lpi_list_lock, which means we can have an array size that is not equal to the number of LPIs. This is particularly obvious when looking at the path coming from vgic_enable_lpis, which is not a command, and thus can run in parallel with commands: vcpu 0: vcpu 1: vgic_enable_lpis its_sync_lpi_pending_table vgic_copy_lpi_list intids = kmalloc_array(irq_count) MAPI(lpi targeting vcpu 0) list_for_each_entry(lpi_list_head) intids[i++] = irq->intid; At that stage, we will happily overrun the intids array. Boo. An easy fix is is to break once the array is full. The MAPI command will update the config anyway, and we won't miss a thing. We also make sure that lpi_list_count is read exactly once, so that further updates of that value will not affect the array bound check. Cc: stable@vger.kernel.org Fixes: ccb1d791ab9e ("KVM: arm64: vgic-its: Fix pending table sync") Reviewed-by: Andre Przywara Reviewed-by: Eric Auger Signed-off-by: Marc Zyngier Signed-off-by: Greg Kroah-Hartman --- virt/kvm/arm/vgic/vgic-its.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/virt/kvm/arm/vgic/vgic-its.c b/virt/kvm/arm/vgic/vgic-its.c index 59ce2fb49821..5a11f4d3972c 100644 --- a/virt/kvm/arm/vgic/vgic-its.c +++ b/virt/kvm/arm/vgic/vgic-its.c @@ -309,21 +309,24 @@ static int vgic_copy_lpi_list(struct kvm_vcpu *vcpu, u32 **intid_ptr) struct vgic_dist *dist = &vcpu->kvm->arch.vgic; struct vgic_irq *irq; u32 *intids; - int irq_count = dist->lpi_list_count, i = 0; + int irq_count, i = 0; /* - * We use the current value of the list length, which may change - * after the kmalloc. We don't care, because the guest shouldn't - * change anything while the command handling is still running, - * and in the worst case we would miss a new IRQ, which one wouldn't - * expect to be covered by this command anyway. + * There is an obvious race between allocating the array and LPIs + * being mapped/unmapped. If we ended up here as a result of a + * command, we're safe (locks are held, preventing another + * command). If coming from another path (such as enabling LPIs), + * we must be careful not to overrun the array. */ + irq_count = READ_ONCE(dist->lpi_list_count); intids = kmalloc_array(irq_count, sizeof(intids[0]), GFP_KERNEL); if (!intids) return -ENOMEM; spin_lock(&dist->lpi_list_lock); list_for_each_entry(irq, &dist->lpi_list_head, lpi_list) { + if (i == irq_count) + break; /* We don't need to "get" the IRQ, as we hold the list lock. */ if (irq->target_vcpu != vcpu) continue; -- GitLab From 326e61ce9761d71098c7001e51dafec067f50424 Mon Sep 17 00:00:00 2001 From: David Lechner Date: Sun, 3 Dec 2017 16:04:53 -0600 Subject: [PATCH 0652/1635] ARM: dts: da850-lego-ev3: Fix battery voltage gpio commit c5a88cd2e1c508868922bafa0a5c3365986b98e5 upstream. This fixes the battery voltage monitoring gpio-hog settings. When the gpio is low, it turns off the battery voltage to the ADC chip. However, this needs to be on all of the time so that we can monitor battery voltage. Also, there was a typo that prevented pinmuxing from working correctly. Signed-off-by: David Lechner Signed-off-by: Sekhar Nori Signed-off-by: Greg Kroah-Hartman --- arch/arm/boot/dts/da850-lego-ev3.dts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/boot/dts/da850-lego-ev3.dts b/arch/arm/boot/dts/da850-lego-ev3.dts index 413dbd5d9f64..81942ae83e1f 100644 --- a/arch/arm/boot/dts/da850-lego-ev3.dts +++ b/arch/arm/boot/dts/da850-lego-ev3.dts @@ -178,7 +178,7 @@ */ battery { pinctrl-names = "default"; - pintctrl-0 = <&battery_pins>; + pinctrl-0 = <&battery_pins>; compatible = "lego,ev3-battery"; io-channels = <&adc 4>, <&adc 3>; io-channel-names = "voltage", "current"; @@ -392,7 +392,7 @@ batt_volt_en { gpio-hog; gpios = <6 GPIO_ACTIVE_HIGH>; - output-low; + output-high; }; }; -- GitLab From 2106cd34635e5aa95d759e414e38d5fd216ce8ec Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Wed, 21 Mar 2018 10:45:05 +0100 Subject: [PATCH 0653/1635] ARM: EXYNOS: Fix coupled CPU idle freeze on Exynos4210 commit a7480dbcf983c31d8111f864c848e8a75116a87d upstream. Since commit 04c8b0f82c7d ("irqchip/gic: Make locking a BL_SWITCHER only feature") coupled CPU idle freezes from time to time on Exynos4210. Later commit 313c8c16ee62 ("PM / CPU: replace raw_notifier with atomic_notifier") changed the context in which the CPU idle code is executed, what results in fully reproducible freeze all the time. However, almost the same coupled CPU idle code works fine on Exynos3250 regardless of the changes made in the mentioned commits. It turned out that the IPI call used on Exynos4210 is conflicting with the change done in the first mentioned commit in GIC. Fix this by using the same code path as for Exynos3250, instead of the IPI call for synchronization with second CPU core, call dsb_sev() directly. Tested on Exynos4210-based Trats and Origen boards. Signed-off-by: Marek Szyprowski CC: # v4.13+ Acked-by: Marc Zyngier Acked-by: Bartlomiej Zolnierkiewicz Signed-off-by: Krzysztof Kozlowski Signed-off-by: Greg Kroah-Hartman --- arch/arm/mach-exynos/pm.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/arch/arm/mach-exynos/pm.c b/arch/arm/mach-exynos/pm.c index 1a7e5b5d08d8..3dbbf1fffead 100644 --- a/arch/arm/mach-exynos/pm.c +++ b/arch/arm/mach-exynos/pm.c @@ -276,11 +276,7 @@ static int exynos_cpu0_enter_aftr(void) goto fail; call_firmware_op(cpu_boot, 1); - - if (soc_is_exynos3250()) - dsb_sev(); - else - arch_send_wakeup_ipi_mask(cpumask_of(1)); + dsb_sev(); } } fail: -- GitLab From 958d6e41888f8659db70418a8203c16d021833cc Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Fri, 23 Feb 2018 18:16:26 +0800 Subject: [PATCH 0654/1635] arm: dts: mt7623: fix USB initialization fails on bananapi-r2 commit 0629a01920c0f8a3f825361b24863d760610884a upstream. Fix that USB initialization fails as below runtime log is present during booting on bananapi-r2 board by adding missing regulators the USB device requires. Current regulators USB device uses are being updated with the correct ones to reflect real configurations which are all from fixed regulators rather than MT6323 one's output. xhci-mtk 1a1c0000.usb: 1a1c0000.usb supply vbus not found, using dummy regulator xhci-mtk 1a240000.usb: 1a240000.usb supply vbus not found, using dummy regulator Cc: stable@vger.kernel.org Fixes: f4ff257cd160 ("arm: dts: mt7623: add support for Bananapi R2 (BPI-R2) board") Signed-off-by: Sean Wang [mb: update kernel log in commit message] Signed-off-by: Matthias Brugger Signed-off-by: Greg Kroah-Hartman --- arch/arm/boot/dts/mt7623n-bananapi-bpi-r2.dts | 24 +++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/arch/arm/boot/dts/mt7623n-bananapi-bpi-r2.dts b/arch/arm/boot/dts/mt7623n-bananapi-bpi-r2.dts index 7bf5aa2237c9..7de704575aee 100644 --- a/arch/arm/boot/dts/mt7623n-bananapi-bpi-r2.dts +++ b/arch/arm/boot/dts/mt7623n-bananapi-bpi-r2.dts @@ -39,6 +39,24 @@ }; }; + reg_3p3v: regulator-3p3v { + compatible = "regulator-fixed"; + regulator-name = "fixed-3.3V"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-boot-on; + regulator-always-on; + }; + + reg_5v: regulator-5v { + compatible = "regulator-fixed"; + regulator-name = "fixed-5V"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + regulator-boot-on; + regulator-always-on; + }; + gpio_keys { compatible = "gpio-keys"; pinctrl-names = "default"; @@ -468,12 +486,14 @@ }; &usb1 { - vusb33-supply = <&mt6323_vusb_reg>; + vusb33-supply = <®_3p3v>; + vbus-supply = <®_5v>; status = "okay"; }; &usb2 { - vusb33-supply = <&mt6323_vusb_reg>; + vusb33-supply = <®_3p3v>; + vbus-supply = <®_5v>; status = "okay"; }; -- GitLab From 838ea3802e9dbe96ac1c3faa03a93a399d09f8ff Mon Sep 17 00:00:00 2001 From: Nicolas Ferre Date: Tue, 13 Mar 2018 16:20:05 +0100 Subject: [PATCH 0655/1635] ARM: dts: at91: at91sam9g25: fix mux-mask pinctrl property commit e8fd0adf105e132fd84545997bbef3d5edc2c9c1 upstream. There are only 19 PIOB pins having primary names PB0-PB18. Not all of them have a 'C' function. So the pinctrl property mask ends up being the same as the other SoC of the at91sam9x5 series. Reported-by: Marek Sieranski Signed-off-by: Nicolas Ferre Cc: # v3.8+ Signed-off-by: Alexandre Belloni Signed-off-by: Greg Kroah-Hartman --- arch/arm/boot/dts/at91sam9g25.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/at91sam9g25.dtsi b/arch/arm/boot/dts/at91sam9g25.dtsi index a7da0dd0c98f..0898213f3bb2 100644 --- a/arch/arm/boot/dts/at91sam9g25.dtsi +++ b/arch/arm/boot/dts/at91sam9g25.dtsi @@ -21,7 +21,7 @@ atmel,mux-mask = < /* A B C */ 0xffffffff 0xffe0399f 0xc000001c /* pioA */ - 0x0007ffff 0x8000fe3f 0x00000000 /* pioB */ + 0x0007ffff 0x00047e3f 0x00000000 /* pioB */ 0x80000000 0x07c0ffff 0xb83fffff /* pioC */ 0x003fffff 0x003f8000 0x00000000 /* pioD */ >; -- GitLab From c57b7e1a150e840004b628d2eae3c3d3385fd25a Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Fri, 2 Mar 2018 17:07:42 +0100 Subject: [PATCH 0656/1635] ARM: dts: exynos: Fix IOMMU support for GScaler devices on Exynos5250 commit 6f4870753f29edf7dc39444246f9e39987b8b158 upstream. The proper name for the property, which assign given device to IOMMU is 'iommus', not 'iommu'. Fix incorrect name and let all GScaler devices to be properly handled when IOMMU support is enabled. Reported-by: Andrzej Hajda Signed-off-by: Marek Szyprowski Fixes: 6cbfdd73a94f ("ARM: dts: add sysmmu nodes for exynos5250") Cc: # v4.8+ Signed-off-by: Krzysztof Kozlowski Signed-off-by: Greg Kroah-Hartman --- arch/arm/boot/dts/exynos5250.dtsi | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/arm/boot/dts/exynos5250.dtsi b/arch/arm/boot/dts/exynos5250.dtsi index 8dbeb873e99c..35b1949a3e3c 100644 --- a/arch/arm/boot/dts/exynos5250.dtsi +++ b/arch/arm/boot/dts/exynos5250.dtsi @@ -643,7 +643,7 @@ power-domains = <&pd_gsc>; clocks = <&clock CLK_GSCL0>; clock-names = "gscl"; - iommu = <&sysmmu_gsc0>; + iommus = <&sysmmu_gsc0>; }; gsc_1: gsc@13e10000 { @@ -653,7 +653,7 @@ power-domains = <&pd_gsc>; clocks = <&clock CLK_GSCL1>; clock-names = "gscl"; - iommu = <&sysmmu_gsc1>; + iommus = <&sysmmu_gsc1>; }; gsc_2: gsc@13e20000 { @@ -663,7 +663,7 @@ power-domains = <&pd_gsc>; clocks = <&clock CLK_GSCL2>; clock-names = "gscl"; - iommu = <&sysmmu_gsc2>; + iommus = <&sysmmu_gsc2>; }; gsc_3: gsc@13e30000 { @@ -673,7 +673,7 @@ power-domains = <&pd_gsc>; clocks = <&clock CLK_GSCL3>; clock-names = "gscl"; - iommu = <&sysmmu_gsc3>; + iommus = <&sysmmu_gsc3>; }; hdmi: hdmi@14530000 { -- GitLab From 38866e866121454b5c6e2fc7eefe82fec97e810e Mon Sep 17 00:00:00 2001 From: Santiago Esteban Date: Thu, 18 Jan 2018 15:38:47 +0100 Subject: [PATCH 0657/1635] ARM: dts: at91: sama5d4: fix pinctrl compatible string commit 9a06757dcc8509c162ac00488c8c82fc98e04227 upstream. The compatible string is incorrect. Add atmel,sama5d3-pinctrl since it's the appropriate compatible string. Remove the atmel,at91rm9200-pinctrl compatible string, this fallback is useless, there are too many changes. Signed-off-by: Santiago Esteban Signed-off-by: Ludovic Desroches Cc: stable@vger.kernel.org #v3.18 Signed-off-by: Alexandre Belloni Signed-off-by: Greg Kroah-Hartman --- arch/arm/boot/dts/sama5d4.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/sama5d4.dtsi b/arch/arm/boot/dts/sama5d4.dtsi index 2fa36c525957..81b526085097 100644 --- a/arch/arm/boot/dts/sama5d4.dtsi +++ b/arch/arm/boot/dts/sama5d4.dtsi @@ -1365,7 +1365,7 @@ pinctrl@fc06a000 { #address-cells = <1>; #size-cells = <1>; - compatible = "atmel,at91sam9x5-pinctrl", "atmel,at91rm9200-pinctrl", "simple-bus"; + compatible = "atmel,sama5d3-pinctrl", "atmel,at91sam9x5-pinctrl", "simple-bus"; ranges = <0xfc068000 0xfc068000 0x100 0xfc06a000 0xfc06a000 0x4000>; /* WARNING: revisit as pin spec has changed */ -- GitLab From faddb17685f9f0507dcd28a3a4af3c63d5765407 Mon Sep 17 00:00:00 2001 From: Eugen Hristev Date: Tue, 27 Feb 2018 12:25:07 +0200 Subject: [PATCH 0658/1635] spi: atmel: init FIFOs before spi enable commit 9581329eff9db72ab4fbb46a594fd7fdda3c51b0 upstream. The datasheet recommends initializing FIFOs before SPI enable. If we do not do it like this, there may be a strange behavior. We noticed that DMA does not work properly with FIFOs if we do not clear them beforehand or enable them before SPIEN. Signed-off-by: Eugen Hristev Acked-by: Nicolas Ferre Signed-off-by: Mark Brown Cc: stable@vger.kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/spi/spi-atmel.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/spi/spi-atmel.c b/drivers/spi/spi-atmel.c index 669470971023..047875861df1 100644 --- a/drivers/spi/spi-atmel.c +++ b/drivers/spi/spi-atmel.c @@ -1489,6 +1489,11 @@ static void atmel_spi_init(struct atmel_spi *as) { spi_writel(as, CR, SPI_BIT(SWRST)); spi_writel(as, CR, SPI_BIT(SWRST)); /* AT91SAM9263 Rev B workaround */ + + /* It is recommended to enable FIFOs first thing after reset */ + if (as->fifo_size) + spi_writel(as, CR, SPI_BIT(FIFOEN)); + if (as->caps.has_wdrbt) { spi_writel(as, MR, SPI_BIT(WDRBT) | SPI_BIT(MODFDIS) | SPI_BIT(MSTR)); @@ -1499,9 +1504,6 @@ static void atmel_spi_init(struct atmel_spi *as) if (as->use_pdc) spi_writel(as, PTCR, SPI_BIT(RXTDIS) | SPI_BIT(TXTDIS)); spi_writel(as, CR, SPI_BIT(SPIEN)); - - if (as->fifo_size) - spi_writel(as, CR, SPI_BIT(FIFOEN)); } static int atmel_spi_probe(struct platform_device *pdev) -- GitLab From e4ff723039dcacff20d834f6fb710ec18074b677 Mon Sep 17 00:00:00 2001 From: Maxime Chevallier Date: Fri, 2 Mar 2018 15:55:09 +0100 Subject: [PATCH 0659/1635] spi: Fix scatterlist elements size in spi_map_buf commit ce99319a182fe766be67f96338386f3ec73e321c upstream. When SPI transfers can be offloaded using DMA, the SPI core need to build a scatterlist to make sure that the buffer to be transferred is dma-able. This patch fixes the scatterlist entry size computation in the case where the maximum acceptable scatterlist entry supported by the DMA controller is less than PAGE_SIZE, when the buffer is vmalloced. For each entry, the actual size is given by the minimum between the desc_len (which is the max buffer size supported by the DMA controller) and the remaining buffer length until we cross a page boundary. Fixes: 65598c13fd66 ("spi: Fix per-page mapping of unaligned vmalloc-ed buffer") Signed-off-by: Maxime Chevallier Signed-off-by: Mark Brown Cc: stable@vger.kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/spi/spi.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 3ff0ee88c467..adcbb5ae8558 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -779,8 +779,14 @@ static int spi_map_buf(struct spi_controller *ctlr, struct device *dev, for (i = 0; i < sgs; i++) { if (vmalloced_buf || kmap_buf) { - min = min_t(size_t, - len, desc_len - offset_in_page(buf)); + /* + * Next scatterlist entry size is the minimum between + * the desc_len and the remaining buffer length that + * fits in a page. + */ + min = min_t(size_t, desc_len, + min_t(size_t, len, + PAGE_SIZE - offset_in_page(buf))); if (vmalloced_buf) vm_page = vmalloc_to_page(buf); else -- GitLab From 9629964f032ca5289a371da9f1288ad2655fb6b7 Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Tue, 20 Mar 2018 10:27:50 +0200 Subject: [PATCH 0660/1635] spi: Fix unregistration of controller with fixed SPI bus number commit 613bd1ea387bb48b7c9a71a0bb451ac15cfbbc01 upstream. Commit 9b61e302210e (spi: Pick spi bus number from Linux idr or spi alias) ceased to unregister SPI buses with fixed bus numbers. Moreover this is visible only if CONFIG_SPI_DEBUG=y is set or when trying to re-register the same SPI controller. rmmod spi_pxa2xx_platform (with CONFIG_SPI_DEBUG=y): [ 26.788362] spi_master spi1: attempting to delete unregistered controller [spi1] modprobe spi_pxa2xx_platform: [ 37.883137] sysfs: cannot create duplicate filename '/devices/pci0000:00/0000:00:19.0/pxa2xx-spi.12/spi_master/spi1' [ 37.894984] CPU: 1 PID: 1467 Comm: modprobe Not tainted 4.16.0-rc4+ #21 [ 37.902384] Call Trace: ... [ 38.122680] kobject_add_internal failed for spi1 with -EEXIST, don't try to register things with the same name in the same directory. [ 38.136154] WARNING: CPU: 1 PID: 1467 at lib/kobject.c:238 kobject_add_internal+0x2a5/0x2f0 ... [ 38.513817] pxa2xx-spi pxa2xx-spi.12: problem registering spi master [ 38.521036] pxa2xx-spi: probe of pxa2xx-spi.12 failed with error -17 Fix this by not returning immediately from spi_unregister_controller() if idr_find() doesn't find controller with given ID/bus number. It finds only those controllers that were registered with dynamic SPI bus numbers. Only conditional cleanup between dynamic and fixed bus numbers is to remove allocated IDR. Fixes: 9b61e302210e (spi: Pick spi bus number from Linux idr or spi alias) Cc: stable@vger.kernel.org Signed-off-by: Jarkko Nikula Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman --- drivers/spi/spi.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index adcbb5ae8558..84dfef4bd6ae 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -2258,12 +2258,6 @@ void spi_unregister_controller(struct spi_controller *ctlr) mutex_lock(&board_lock); found = idr_find(&spi_master_idr, id); mutex_unlock(&board_lock); - if (found != ctlr) { - dev_dbg(&ctlr->dev, - "attempting to delete unregistered controller [%s]\n", - dev_name(&ctlr->dev)); - return; - } if (ctlr->queued) { if (spi_destroy_queue(ctlr)) dev_err(&ctlr->dev, "queue remove failed\n"); @@ -2276,7 +2270,8 @@ void spi_unregister_controller(struct spi_controller *ctlr) device_unregister(&ctlr->dev); /* free bus id */ mutex_lock(&board_lock); - idr_remove(&spi_master_idr, id); + if (found == ctlr) + idr_remove(&spi_master_idr, id); mutex_unlock(&board_lock); } EXPORT_SYMBOL_GPL(spi_unregister_controller); -- GitLab From 9864a1ef86791897b0f6c215001deae472c05635 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 25 Feb 2018 06:55:32 -0500 Subject: [PATCH 0661/1635] media: atomisp_fops.c: disable atomisp_compat_ioctl32 commit 57e6b6f2303e596a6493078b53be14b789e7b79f upstream. The atomisp_compat_ioctl32() code has problems. This patch disables the compat_ioctl32 support until those issues have been fixed. Contact Sakari or me for more details. Signed-off-by: Hans Verkuil Cc: # for v4.12 and up Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Greg Kroah-Hartman --- drivers/staging/media/atomisp/pci/atomisp2/atomisp_fops.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/staging/media/atomisp/pci/atomisp2/atomisp_fops.c b/drivers/staging/media/atomisp/pci/atomisp2/atomisp_fops.c index d8cfed358d55..f1d8cc5a2730 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/atomisp_fops.c +++ b/drivers/staging/media/atomisp/pci/atomisp2/atomisp_fops.c @@ -1285,7 +1285,10 @@ const struct v4l2_file_operations atomisp_fops = { .mmap = atomisp_mmap, .unlocked_ioctl = video_ioctl2, #ifdef CONFIG_COMPAT + /* + * There are problems with this code. Disable this for now. .compat_ioctl32 = atomisp_compat_ioctl32, + */ #endif .poll = atomisp_poll, }; @@ -1297,7 +1300,10 @@ const struct v4l2_file_operations atomisp_file_fops = { .mmap = atomisp_file_mmap, .unlocked_ioctl = video_ioctl2, #ifdef CONFIG_COMPAT + /* + * There are problems with this code. Disable this for now. .compat_ioctl32 = atomisp_compat_ioctl32, + */ #endif .poll = atomisp_poll, }; -- GitLab From 2fb28b075f80136b17c8aebb2c006a3502c628db Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 12 Feb 2018 06:45:32 -0500 Subject: [PATCH 0662/1635] media: vivid: check if the cec_adapter is valid commit ed356f110403f6acc64dcbbbfdc38662ab9b06c2 upstream. If CEC is not enabled for the vivid driver, then the adap pointer is NULL and 'adap->phys_addr' will fail. Cc: # for v4.12 and up Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Greg Kroah-Hartman --- drivers/media/platform/vivid/vivid-vid-common.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/media/platform/vivid/vivid-vid-common.c b/drivers/media/platform/vivid/vivid-vid-common.c index f0f423c7ca41..6f6d4df1e8a8 100644 --- a/drivers/media/platform/vivid/vivid-vid-common.c +++ b/drivers/media/platform/vivid/vivid-vid-common.c @@ -858,7 +858,8 @@ int vidioc_g_edid(struct file *file, void *_fh, return -EINVAL; if (edid->start_block + edid->blocks > dev->edid_blocks) edid->blocks = dev->edid_blocks - edid->start_block; - cec_set_edid_phys_addr(dev->edid, dev->edid_blocks * 128, adap->phys_addr); + if (adap) + cec_set_edid_phys_addr(dev->edid, dev->edid_blocks * 128, adap->phys_addr); memcpy(edid->edid, dev->edid + edid->start_block * 128, edid->blocks * 128); return 0; } -- GitLab From fcd054c733cf702f192e01fa7e78596cc07df771 Mon Sep 17 00:00:00 2001 From: Kieran Bingham Date: Mon, 26 Mar 2018 09:29:17 -0400 Subject: [PATCH 0663/1635] media: vsp1: Fix BRx conditional path in WPF commit 639fa43d59e5a41ca8c55592cd5c1021fea2ab83 upstream. When a BRx is provided by a pipeline, the WPF must determine the master layer. Currently the condition to check this identifies pipe->bru || pipe->num_inputs > 1. The code then moves on to dereference pipe->bru, thus the check fails static analysers on the possibility that pipe->num_inputs could be greater than 1 without pipe->bru being set. The reality is that the pipeline must have a BRx to support more than one input, thus this could never cause a fault - however it also identifies that the num_inputs > 1 check is redundant. Remove the redundant check - and always configure the master layer appropriately when we have a BRx configured in our pipeline. Fixes: 6134148f6098 ("v4l: vsp1: Add support for the BRS entity") Cc: stable@vger.kernel.org Suggested-by: Mauro Carvalho Chehab Signed-off-by: Kieran Bingham Reviewed-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Greg Kroah-Hartman --- drivers/media/platform/vsp1/vsp1_wpf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/platform/vsp1/vsp1_wpf.c b/drivers/media/platform/vsp1/vsp1_wpf.c index f7f3b4b2c2de..8bd6b2f1af15 100644 --- a/drivers/media/platform/vsp1/vsp1_wpf.c +++ b/drivers/media/platform/vsp1/vsp1_wpf.c @@ -452,7 +452,7 @@ static void wpf_configure(struct vsp1_entity *entity, : VI6_WPF_SRCRPF_RPF_ACT_SUB(input->entity.index); } - if (pipe->bru || pipe->num_inputs > 1) + if (pipe->bru) srcrpf |= pipe->bru->type == VSP1_ENTITY_BRU ? VI6_WPF_SRCRPF_VIRACT_MST : VI6_WPF_SRCRPF_VIRACT2_MST; -- GitLab From e7b00dc28275a1883749d319081484e3306dc265 Mon Sep 17 00:00:00 2001 From: Jason Andryuk Date: Mon, 19 Mar 2018 12:58:04 -0400 Subject: [PATCH 0664/1635] x86/xen: Delay get_cpu_cap until stack canary is established commit 36104cb9012a82e73c32a3b709257766b16bcd1d upstream. Commit 2cc42bac1c79 ("x86-64/Xen: eliminate W+X mappings") introduced a call to get_cpu_cap, which is fstack-protected. This is works on x86-64 as commit 4f277295e54c ("x86/xen: init %gs very early to avoid page faults with stack protector") ensures the stack protector is configured, but it it did not cover x86-32. Delay calling get_cpu_cap until after xen_setup_gdt has initialized the stack canary. Without this, a 32bit PV machine crashes early in boot. (XEN) Domain 0 (vcpu#0) crashed on cpu#0: (XEN) ----[ Xen-4.6.6-xc x86_64 debug=n Tainted: C ]---- (XEN) CPU: 0 (XEN) RIP: e019:[<00000000c10362f8>] And the PV kernel IP corresponds to init_scattered_cpuid_features 0xc10362f8 <+24>: mov %gs:0x14,%eax Fixes 2cc42bac1c79 ("x86-64/Xen: eliminate W+X mappings") Signed-off-by: Jason Andryuk Reviewed-by: Boris Ostrovsky Signed-off-by: Boris Ostrovsky Signed-off-by: Greg Kroah-Hartman --- arch/x86/xen/enlighten_pv.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/x86/xen/enlighten_pv.c b/arch/x86/xen/enlighten_pv.c index f896c2975545..fcd8789470d1 100644 --- a/arch/x86/xen/enlighten_pv.c +++ b/arch/x86/xen/enlighten_pv.c @@ -1258,10 +1258,6 @@ asmlinkage __visible void __init xen_start_kernel(void) */ __userpte_alloc_gfp &= ~__GFP_HIGHMEM; - /* Work out if we support NX */ - get_cpu_cap(&boot_cpu_data); - x86_configure_nx(); - /* Get mfn list */ xen_build_dynamic_phys_to_machine(); @@ -1271,6 +1267,10 @@ asmlinkage __visible void __init xen_start_kernel(void) */ xen_setup_gdt(0); + /* Work out if we support NX */ + get_cpu_cap(&boot_cpu_data); + x86_configure_nx(); + xen_init_irq_ops(); /* Let's presume PV guests always boot on vCPU with id 0. */ -- GitLab From 666d1084c13d919c1ace5cbcd594eb355e8c4686 Mon Sep 17 00:00:00 2001 From: Jason Andryuk Date: Wed, 28 Feb 2018 07:23:23 -0500 Subject: [PATCH 0665/1635] xen-netfront: Fix hang on device removal commit c2d2e6738a209f0f9dffa2dc8e7292fc45360d61 upstream. A toolstack may delete the vif frontend and backend xenstore entries while xen-netfront is in the removal code path. In that case, the checks for xenbus_read_driver_state would return XenbusStateUnknown, and xennet_remove would hang indefinitely. This hang prevents system shutdown. xennet_remove must be able to handle XenbusStateUnknown, and netback_changed must also wake up the wake_queue for that state as well. Fixes: 5b5971df3bc2 ("xen-netfront: remove warning when unloading module") Signed-off-by: Jason Andryuk Cc: Eduardo Otubo Reviewed-by: Boris Ostrovsky Signed-off-by: Juergen Gross Signed-off-by: Greg Kroah-Hartman --- drivers/net/xen-netfront.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c index c980cdbd6e53..a9ba9fe263ca 100644 --- a/drivers/net/xen-netfront.c +++ b/drivers/net/xen-netfront.c @@ -2008,7 +2008,10 @@ static void netback_changed(struct xenbus_device *dev, case XenbusStateInitialised: case XenbusStateReconfiguring: case XenbusStateReconfigured: + break; + case XenbusStateUnknown: + wake_up_all(&module_unload_q); break; case XenbusStateInitWait: @@ -2139,7 +2142,9 @@ static int xennet_remove(struct xenbus_device *dev) xenbus_switch_state(dev, XenbusStateClosing); wait_event(module_unload_q, xenbus_read_driver_state(dev->otherend) == - XenbusStateClosing); + XenbusStateClosing || + xenbus_read_driver_state(dev->otherend) == + XenbusStateUnknown); xenbus_switch_state(dev, XenbusStateClosed); wait_event(module_unload_q, -- GitLab From 3dac1fe2719d6aa894768848fecf6a2837356534 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 8 Feb 2018 10:23:44 +0300 Subject: [PATCH 0666/1635] regmap: Fix reversed bounds check in regmap_raw_write() commit f00e71091ab92eba52122332586c6ecaa9cd1a56 upstream. We're supposed to be checking that "val_len" is not too large but instead we check if it is smaller than the max. The only function affected would be regmap_i2c_smbus_i2c_write() in drivers/base/regmap/regmap-i2c.c. Strangely that function has its own limit check which returns an error if (count >= I2C_SMBUS_BLOCK_MAX) so it doesn't look like it has ever been able to do anything except return an error. Fixes: c335931ed9d2 ("regmap: Add raw_write/read checks for max_raw_write/read sizes") Signed-off-by: Dan Carpenter Signed-off-by: Mark Brown Cc: stable@vger.kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/base/regmap/regmap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c index b9a779a4a739..efdadd153abe 100644 --- a/drivers/base/regmap/regmap.c +++ b/drivers/base/regmap/regmap.c @@ -1739,7 +1739,7 @@ int regmap_raw_write(struct regmap *map, unsigned int reg, return -EINVAL; if (val_len % map->format.val_bytes) return -EINVAL; - if (map->max_raw_write && map->max_raw_write > val_len) + if (map->max_raw_write && map->max_raw_write < val_len) return -E2BIG; map->lock(map->lock_arg); -- GitLab From d6e98387b2e994e68d3b7a6abd5c6ceef62ad5e3 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Mon, 19 Mar 2018 18:01:45 +0100 Subject: [PATCH 0667/1635] ACPI / video: Add quirk to force acpi-video backlight on Samsung 670Z5E commit bbf038618a24d72e2efc19146ef421bb1e1eda1a upstream. Just like many other Samsung models, the 670Z5E needs to use the acpi-video backlight interface rather then the native one for backlight control to work, add a quirk for this. Buglink: https://bugzilla.redhat.com/show_bug.cgi?id=1557060 Cc: All applicable Signed-off-by: Hans de Goede Signed-off-by: Rafael J. Wysocki Signed-off-by: Greg Kroah-Hartman --- drivers/acpi/video_detect.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/acpi/video_detect.c b/drivers/acpi/video_detect.c index 601e5d372887..43587ac680e4 100644 --- a/drivers/acpi/video_detect.c +++ b/drivers/acpi/video_detect.c @@ -219,6 +219,15 @@ static const struct dmi_system_id video_detect_dmi_table[] = { "3570R/370R/470R/450R/510R/4450RV"), }, }, + { + /* https://bugzilla.redhat.com/show_bug.cgi?id=1557060 */ + .callback = video_detect_force_video, + .ident = "SAMSUNG 670Z5E", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."), + DMI_MATCH(DMI_PRODUCT_NAME, "670Z5E"), + }, + }, { /* https://bugzilla.redhat.com/show_bug.cgi?id=1094948 */ .callback = video_detect_force_video, -- GitLab From a2b540651d8c1938e07493e18e781e3fc609728c Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Mon, 12 Feb 2018 13:55:23 +0300 Subject: [PATCH 0668/1635] ACPI / hotplug / PCI: Check presence of slot itself in get_slot_status() commit 13d3047c81505cc0fb9bdae7810676e70523c8bf upstream. Mike Lothian reported that plugging in a USB-C device does not work properly in his Dell Alienware system. This system has an Intel Alpine Ridge Thunderbolt controller providing USB-C functionality. In these systems the USB controller (xHCI) is hotplugged whenever a device is connected to the port using ACPI-based hotplug. The ACPI description of the root port in question is as follows: Device (RP01) { Name (_ADR, 0x001C0000) Device (PXSX) { Name (_ADR, 0x02) Method (_RMV, 0, NotSerialized) { // ... } } Here _ADR 0x02 means device 0, function 2 on the bus under root port (RP01) but that seems to be incorrect because device 0 is the upstream port of the Alpine Ridge PCIe switch and it has no functions other than 0 (the bridge itself). When we get ACPI Notify() to the root port resulting from connecting a USB-C device, Linux tries to read PCI_VENDOR_ID from device 0, function 2 which of course always returns 0xffffffff because there is no such function and we never find the device. In Windows this works fine. Now, since we get ACPI Notify() to the root port and not to the PXSX device we should actually start our scan from there as well and not from the non-existent PXSX device. Fix this by checking presence of the slot itself (function 0) if we fail to do that otherwise. While there use pci_bus_read_dev_vendor_id() in get_slot_status(), which is the recommended way to read Device and Vendor IDs of devices on PCI buses. Link: https://bugzilla.kernel.org/show_bug.cgi?id=198557 Reported-by: Mike Lothian Signed-off-by: Mika Westerberg Signed-off-by: Bjorn Helgaas Reviewed-by: Rafael J. Wysocki Cc: Greg Kroah-Hartman Cc: stable@vger.kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/pci/hotplug/acpiphp_glue.c | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index 5ed2dcaa8e27..711875afdd70 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c @@ -558,6 +558,7 @@ static unsigned int get_slot_status(struct acpiphp_slot *slot) { unsigned long long sta = 0; struct acpiphp_func *func; + u32 dvid; list_for_each_entry(func, &slot->funcs, sibling) { if (func->flags & FUNC_HAS_STA) { @@ -568,19 +569,27 @@ static unsigned int get_slot_status(struct acpiphp_slot *slot) if (ACPI_SUCCESS(status) && sta) break; } else { - u32 dvid; - - pci_bus_read_config_dword(slot->bus, - PCI_DEVFN(slot->device, - func->function), - PCI_VENDOR_ID, &dvid); - if (dvid != 0xffffffff) { + if (pci_bus_read_dev_vendor_id(slot->bus, + PCI_DEVFN(slot->device, func->function), + &dvid, 0)) { sta = ACPI_STA_ALL; break; } } } + if (!sta) { + /* + * Check for the slot itself since it may be that the + * ACPI slot is a device below PCIe upstream port so in + * that case it may not even be reachable yet. + */ + if (pci_bus_read_dev_vendor_id(slot->bus, + PCI_DEVFN(slot->device, 0), &dvid, 0)) { + sta = ACPI_STA_ALL; + } + } + return (unsigned int)sta; } -- GitLab From 96dc465173a1f790e805246206aee3d18770f614 Mon Sep 17 00:00:00 2001 From: "Yavuz, Tuba" Date: Fri, 23 Mar 2018 17:00:38 +0000 Subject: [PATCH 0669/1635] USB: gadget: f_midi: fixing a possible double-free in f_midi commit 7fafcfdf6377b18b2a726ea554d6e593ba44349f upstream. It looks like there is a possibility of a double-free vulnerability on an error path of the f_midi_set_alt function in the f_midi driver. If the path is feasible then free_ep_req gets called twice: req->complete = f_midi_complete; err = usb_ep_queue(midi->out_ep, req, GFP_ATOMIC); => ... usb_gadget_giveback_request => f_midi_complete (CALLBACK) (inside f_midi_complete, for various cases of status) free_ep_req(ep, req); // first kfree if (err) { ERROR(midi, "%s: couldn't enqueue request: %d\n", midi->out_ep->name, err); free_ep_req(midi->out_ep, req); // second kfree return err; } The double-free possibility was introduced with commit ad0d1a058eac ("usb: gadget: f_midi: fix leak on failed to enqueue out requests"). Found by MOXCAFE tool. Signed-off-by: Tuba Yavuz Fixes: ad0d1a058eac ("usb: gadget: f_midi: fix leak on failed to enqueue out requests") Acked-by: Felipe Balbi Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/function/f_midi.c | 3 ++- drivers/usb/gadget/u_f.h | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/usb/gadget/function/f_midi.c b/drivers/usb/gadget/function/f_midi.c index 5d3d7941d2c2..71cf552b8828 100644 --- a/drivers/usb/gadget/function/f_midi.c +++ b/drivers/usb/gadget/function/f_midi.c @@ -405,7 +405,8 @@ static int f_midi_set_alt(struct usb_function *f, unsigned intf, unsigned alt) if (err) { ERROR(midi, "%s: couldn't enqueue request: %d\n", midi->out_ep->name, err); - free_ep_req(midi->out_ep, req); + if (req->buf != NULL) + free_ep_req(midi->out_ep, req); return err; } } diff --git a/drivers/usb/gadget/u_f.h b/drivers/usb/gadget/u_f.h index 7d53a4773d1a..2f03334c6874 100644 --- a/drivers/usb/gadget/u_f.h +++ b/drivers/usb/gadget/u_f.h @@ -64,7 +64,9 @@ struct usb_request *alloc_ep_req(struct usb_ep *ep, size_t len); /* Frees a usb_request previously allocated by alloc_ep_req() */ static inline void free_ep_req(struct usb_ep *ep, struct usb_request *req) { + WARN_ON(req->buf == NULL); kfree(req->buf); + req->buf = NULL; usb_ep_free_request(ep, req); } -- GitLab From f7f9187a110e58c0b9988db972a0631d06c7633f Mon Sep 17 00:00:00 2001 From: Zhengjun Xing Date: Wed, 21 Mar 2018 13:29:42 +0800 Subject: [PATCH 0670/1635] USB:fix USB3 devices behind USB3 hubs not resuming at hibernate thaw MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 64627388b50158fd24d6ad88132525b95a5ef573 upstream. USB3 hubs don't support global suspend. USB3 specification 10.10, Enhanced SuperSpeed hubs only support selective suspend and resume, they do not support global suspend/resume where the hub downstream facing ports states are not affected. When system enters hibernation it first enters freeze process where only the root hub enters suspend, usb_port_suspend() is not called for other devices, and suspend status flags are not set for them. Other devices are expected to suspend globally. Some external USB3 hubs will suspend the downstream facing port at global suspend. These devices won't be resumed at thaw as the suspend status flag is not set. A USB3 removable hard disk connected through a USB3 hub that won't resume at thaw will fail to synchronize SCSI cache, return “cmd cmplt err -71” error, and needs a 60 seconds timeout which causing system hang for 60s before the USB host reset the port for the USB3 removable hard disk to recover. Fix this by always calling usb_port_suspend() during freeze for USB3 devices. Signed-off-by: Zhengjun Xing Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/generic.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/usb/core/generic.c b/drivers/usb/core/generic.c index bd3e0c5a6db2..212289c55b6f 100644 --- a/drivers/usb/core/generic.c +++ b/drivers/usb/core/generic.c @@ -210,8 +210,13 @@ static int generic_suspend(struct usb_device *udev, pm_message_t msg) if (!udev->parent) rc = hcd_bus_suspend(udev, msg); - /* Non-root devices don't need to do anything for FREEZE or PRETHAW */ - else if (msg.event == PM_EVENT_FREEZE || msg.event == PM_EVENT_PRETHAW) + /* + * Non-root USB2 devices don't need to do anything for FREEZE + * or PRETHAW. USB3 devices don't support global suspend and + * needs to be selectively suspended. + */ + else if ((msg.event == PM_EVENT_FREEZE || msg.event == PM_EVENT_PRETHAW) + && (udev->speed < USB_SPEED_SUPER)) rc = 0; else rc = usb_port_suspend(udev, msg); -- GitLab From 30e9a1cddc4d4ef881515ff128c2c707ef81573d Mon Sep 17 00:00:00 2001 From: Roger Quadros Date: Tue, 27 Feb 2018 12:54:37 +0200 Subject: [PATCH 0671/1635] usb: dwc3: prevent setting PRTCAP to OTG from debugfs commit daaecc6541d014dca073473ec8a4120c0babbeb4 upstream. We don't support PRTCAP == OTG yet, so prevent user from setting it via debugfs. Fixes: 41ce1456e1db ("usb: dwc3: core: make dwc3_set_mode() work properly") Cc: # v4.12+ Signed-off-by: Roger Quadros Signed-off-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman --- drivers/usb/dwc3/core.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index 3219d8157f5b..c3f3f1a89b0f 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -128,6 +128,9 @@ static void __dwc3_set_mode(struct work_struct *work) if (dwc->dr_mode != USB_DR_MODE_OTG) return; + if (dwc->desired_dr_role == DWC3_GCTL_PRTCAP_OTG) + return; + switch (dwc->current_dr_role) { case DWC3_GCTL_PRTCAP_HOST: dwc3_host_exit(dwc); -- GitLab From 093dcb929c8e8344ce148ba11e0313ad1890553d Mon Sep 17 00:00:00 2001 From: Thinh Nguyen Date: Mon, 19 Mar 2018 13:07:35 -0700 Subject: [PATCH 0672/1635] usb: dwc3: pci: Properly cleanup resource commit cabdf83dadfb3d83eec31e0f0638a92dbd716435 upstream. Platform device is allocated before adding resources. Make sure to properly cleanup on error case. Cc: Fixes: f1c7e7108109 ("usb: dwc3: convert to pcim_enable_device()") Signed-off-by: Thinh Nguyen Signed-off-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman --- drivers/usb/dwc3/dwc3-pci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/dwc3/dwc3-pci.c b/drivers/usb/dwc3/dwc3-pci.c index 54343fbd85ee..bc5e91d4fac8 100644 --- a/drivers/usb/dwc3/dwc3-pci.c +++ b/drivers/usb/dwc3/dwc3-pci.c @@ -212,7 +212,7 @@ static int dwc3_pci_probe(struct pci_dev *pci, ret = platform_device_add_resources(dwc->dwc3, res, ARRAY_SIZE(res)); if (ret) { dev_err(dev, "couldn't add resources to dwc3 device\n"); - return ret; + goto err; } dwc->pci = pci; -- GitLab From 59d3a952e4f3d505f9444e86db069081323351c7 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Mon, 26 Mar 2018 13:14:47 +0300 Subject: [PATCH 0673/1635] usb: dwc3: gadget: never call ->complete() from ->ep_queue() commit c91815b596245fd7da349ecc43c8def670d2269e upstream. This is a requirement which has always existed but, somehow, wasn't reflected in the documentation and problems weren't found until now when Tuba Yavuz found a possible deadlock happening between dwc3 and f_hid. She described the situation as follows: spin_lock_irqsave(&hidg->write_spinlock, flags); // first acquire /* we our function has been disabled by host */ if (!hidg->req) { free_ep_req(hidg->in_ep, hidg->req); goto try_again; } [...] status = usb_ep_queue(hidg->in_ep, hidg->req, GFP_ATOMIC); => [...] => usb_gadget_giveback_request => f_hidg_req_complete => spin_lock_irqsave(&hidg->write_spinlock, flags); // second acquire Note that this happens because dwc3 would call ->complete() on a failed usb_ep_queue() due to failed Start Transfer command. This is, anyway, a theoretical situation because dwc3 currently uses "No Response Update Transfer" command for Bulk and Interrupt endpoints. It's still good to make this case impossible to happen even if the "No Reponse Update Transfer" command is changed. Reported-by: Tuba Yavuz Signed-off-by: Felipe Balbi Cc: stable Signed-off-by: Greg Kroah-Hartman Signed-off-by: Greg Kroah-Hartman --- drivers/usb/dwc3/gadget.c | 43 +++++++++++++++++++++++---------------- 1 file changed, 25 insertions(+), 18 deletions(-) diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 0ebdb313bb00..fe75e969f5ac 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -174,18 +174,8 @@ static void dwc3_ep_inc_deq(struct dwc3_ep *dep) dwc3_ep_inc_trb(&dep->trb_dequeue); } -/** - * dwc3_gadget_giveback - call struct usb_request's ->complete callback - * @dep: The endpoint to whom the request belongs to - * @req: The request we're giving back - * @status: completion code for the request - * - * Must be called with controller's lock held and interrupts disabled. This - * function will unmap @req and call its ->complete() callback to notify upper - * layers that it has completed. - */ -void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req, - int status) +void dwc3_gadget_del_and_unmap_request(struct dwc3_ep *dep, + struct dwc3_request *req, int status) { struct dwc3 *dwc = dep->dwc; @@ -198,18 +188,35 @@ void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req, if (req->trb) usb_gadget_unmap_request_by_dev(dwc->sysdev, - &req->request, req->direction); + &req->request, req->direction); req->trb = NULL; - trace_dwc3_gadget_giveback(req); + if (dep->number > 1) + pm_runtime_put(dwc->dev); +} + +/** + * dwc3_gadget_giveback - call struct usb_request's ->complete callback + * @dep: The endpoint to whom the request belongs to + * @req: The request we're giving back + * @status: completion code for the request + * + * Must be called with controller's lock held and interrupts disabled. This + * function will unmap @req and call its ->complete() callback to notify upper + * layers that it has completed. + */ +void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req, + int status) +{ + struct dwc3 *dwc = dep->dwc; + + dwc3_gadget_del_and_unmap_request(dep, req, status); + spin_unlock(&dwc->lock); usb_gadget_giveback_request(&dep->endpoint, &req->request); spin_lock(&dwc->lock); - - if (dep->number > 1) - pm_runtime_put(dwc->dev); } /** @@ -1233,7 +1240,7 @@ static int __dwc3_gadget_kick_transfer(struct dwc3_ep *dep, u16 cmd_param) if (req->trb) memset(req->trb, 0, sizeof(struct dwc3_trb)); dep->queued_requests--; - dwc3_gadget_giveback(dep, req, ret); + dwc3_gadget_del_and_unmap_request(dep, req, ret); return ret; } -- GitLab From fdbd795405203c22c063690f00cf79a23389f1df Mon Sep 17 00:00:00 2001 From: Ronnie Sahlberg Date: Tue, 13 Feb 2018 15:42:30 +1100 Subject: [PATCH 0674/1635] cifs: fix memory leak in SMB2_open() commit b7a73c84eb96dabd6bb8e9d7c56f796d83efee8e upstream. Signed-off-by: Ronnie Sahlberg Signed-off-by: Steve French CC: Stable Signed-off-by: Greg Kroah-Hartman --- fs/cifs/smb2pdu.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c index 66af1f8a13cc..49779d952cd5 100644 --- a/fs/cifs/smb2pdu.c +++ b/fs/cifs/smb2pdu.c @@ -1773,8 +1773,10 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path, rc = alloc_path_with_tree_prefix(©_path, ©_size, &name_len, tcon->treeName, path); - if (rc) + if (rc) { + cifs_small_buf_release(req); return rc; + } req->NameLength = cpu_to_le16(name_len * 2); uni_path_len = copy_size; path = copy_path; @@ -1785,8 +1787,10 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path, if (uni_path_len % 8 != 0) { copy_size = roundup(uni_path_len, 8); copy_path = kzalloc(copy_size, GFP_KERNEL); - if (!copy_path) + if (!copy_path) { + cifs_small_buf_release(req); return -ENOMEM; + } memcpy((char *)copy_path, (const char *)path, uni_path_len); uni_path_len = copy_size; -- GitLab From bf895b2a637dc4bbe818cabf1fa2c91a2f346dfd Mon Sep 17 00:00:00 2001 From: Ronnie Sahlberg Date: Tue, 20 Feb 2018 12:45:21 +1100 Subject: [PATCH 0675/1635] fix smb3-encryption breakage when CONFIG_DEBUG_SG=y commit 262916bc69faf90104aa784d55e10760a4199594 upstream. We can not use the standard sg_set_buf() fucntion since when CONFIG_DEBUG_SG=y this adds a check that will BUG_ON for cifs.ko when we pass it an object from the stack. Create a new wrapper smb2_sg_set_buf() which avoids doing that particular check and use it for smb3 encryption instead. Signed-off-by: Ronnie Sahlberg Signed-off-by: Steve French CC: Stable Signed-off-by: Greg Kroah-Hartman --- fs/cifs/smb2ops.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c index bdb963d0ba32..eef875da7c0b 100644 --- a/fs/cifs/smb2ops.c +++ b/fs/cifs/smb2ops.c @@ -2060,6 +2060,15 @@ fill_transform_hdr(struct smb2_transform_hdr *tr_hdr, struct smb_rqst *old_rq) inc_rfc1001_len(tr_hdr, orig_len); } +/* We can not use the normal sg_set_buf() as we will sometimes pass a + * stack object as buf. + */ +static inline void smb2_sg_set_buf(struct scatterlist *sg, const void *buf, + unsigned int buflen) +{ + sg_set_page(sg, virt_to_page(buf), buflen, offset_in_page(buf)); +} + static struct scatterlist * init_sg(struct smb_rqst *rqst, u8 *sign) { @@ -2074,16 +2083,16 @@ init_sg(struct smb_rqst *rqst, u8 *sign) return NULL; sg_init_table(sg, sg_len); - sg_set_buf(&sg[0], rqst->rq_iov[0].iov_base + 24, assoc_data_len); + smb2_sg_set_buf(&sg[0], rqst->rq_iov[0].iov_base + 24, assoc_data_len); for (i = 1; i < rqst->rq_nvec; i++) - sg_set_buf(&sg[i], rqst->rq_iov[i].iov_base, + smb2_sg_set_buf(&sg[i], rqst->rq_iov[i].iov_base, rqst->rq_iov[i].iov_len); for (j = 0; i < sg_len - 1; i++, j++) { unsigned int len = (j < rqst->rq_npages - 1) ? rqst->rq_pagesz : rqst->rq_tailsz; sg_set_page(&sg[i], rqst->rq_pages[j], len, 0); } - sg_set_buf(&sg[sg_len - 1], sign, SMB2_SIGNATURE_SIZE); + smb2_sg_set_buf(&sg[sg_len - 1], sign, SMB2_SIGNATURE_SIZE); return sg; } -- GitLab From 70dbed63a96d1f5ebc779c87f00340d352b3b0c5 Mon Sep 17 00:00:00 2001 From: Steve French Date: Sat, 31 Mar 2018 18:13:38 -0500 Subject: [PATCH 0676/1635] smb3: Fix root directory when server returns inode number of zero commit 7ea884c77e5c97f1e0a1a422d961d27f78ca2745 upstream. Some servers return inode number zero for the root directory, which causes ls to display incorrect data (missing "." and ".."). If the server returns zero for the inode number of the root directory, fake an inode number for it. Signed-off-by: Steve French Reviewed-by: Pavel Shilovsky CC: Stable Signed-off-by: Greg Kroah-Hartman --- fs/cifs/cifsglob.h | 1 + fs/cifs/inode.c | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index e185b2853eab..6b6496820a21 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -1449,6 +1449,7 @@ struct dfs_info3_param { #define CIFS_FATTR_NEED_REVAL 0x4 #define CIFS_FATTR_INO_COLLISION 0x8 #define CIFS_FATTR_UNKNOWN_NLINK 0x10 +#define CIFS_FATTR_FAKE_ROOT_INO 0x20 struct cifs_fattr { u32 cf_flags; diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index 7c732cb44164..0c7b7e2a0919 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c @@ -707,6 +707,18 @@ cifs_get_file_info(struct file *filp) return rc; } +/* Simple function to return a 64 bit hash of string. Rarely called */ +static __u64 simple_hashstr(const char *str) +{ + const __u64 hash_mult = 1125899906842597L; /* a big enough prime */ + __u64 hash = 0; + + while (*str) + hash = (hash + (__u64) *str++) * hash_mult; + + return hash; +} + int cifs_get_inode_info(struct inode **inode, const char *full_path, FILE_ALL_INFO *data, struct super_block *sb, int xid, @@ -816,6 +828,14 @@ cifs_get_inode_info(struct inode **inode, const char *full_path, tmprc); fattr.cf_uniqueid = iunique(sb, ROOT_I); cifs_autodisable_serverino(cifs_sb); + } else if ((fattr.cf_uniqueid == 0) && + strlen(full_path) == 0) { + /* some servers ret bad root ino ie 0 */ + cifs_dbg(FYI, "Invalid (0) inodenum\n"); + fattr.cf_flags |= + CIFS_FATTR_FAKE_ROOT_INO; + fattr.cf_uniqueid = + simple_hashstr(tcon->treeName); } } } else @@ -832,6 +852,16 @@ cifs_get_inode_info(struct inode **inode, const char *full_path, &fattr.cf_uniqueid, data); if (tmprc) fattr.cf_uniqueid = CIFS_I(*inode)->uniqueid; + else if ((fattr.cf_uniqueid == 0) && + strlen(full_path) == 0) { + /* + * Reuse existing root inode num since + * inum zero for root causes ls of . and .. to + * not be returned + */ + cifs_dbg(FYI, "Srv ret 0 inode num for root\n"); + fattr.cf_uniqueid = CIFS_I(*inode)->uniqueid; + } } else fattr.cf_uniqueid = CIFS_I(*inode)->uniqueid; } @@ -893,6 +923,9 @@ cifs_get_inode_info(struct inode **inode, const char *full_path, } cgii_exit: + if ((*inode) && ((*inode)->i_ino == 0)) + cifs_dbg(FYI, "inode number of zero returned\n"); + kfree(buf); cifs_put_tlink(tlink); return rc; -- GitLab From d6b3a5c87d45ba6af5597879c98024de1ff0f327 Mon Sep 17 00:00:00 2001 From: Aaron Ma Date: Mon, 8 Jan 2018 10:41:40 +0800 Subject: [PATCH 0677/1635] HID: i2c-hid: fix size check and type usage commit ac75a041048b8c1f7418e27621ca5efda8571043 upstream. When convert char array with signed int, if the inbuf[x] is negative then upper bits will be set to 1. Fix this by using u8 instead of char. ret_size has to be at least 3, hid_input_report use it after minus 2 bytes. Cc: stable@vger.kernel.org Signed-off-by: Aaron Ma Signed-off-by: Jiri Kosina Signed-off-by: Greg Kroah-Hartman --- drivers/hid/i2c-hid/i2c-hid.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/drivers/hid/i2c-hid/i2c-hid.c b/drivers/hid/i2c-hid/i2c-hid.c index 9145c2129a96..3535073a9a7d 100644 --- a/drivers/hid/i2c-hid/i2c-hid.c +++ b/drivers/hid/i2c-hid/i2c-hid.c @@ -143,10 +143,10 @@ struct i2c_hid { * register of the HID * descriptor. */ unsigned int bufsize; /* i2c buffer size */ - char *inbuf; /* Input buffer */ - char *rawbuf; /* Raw Input buffer */ - char *cmdbuf; /* Command buffer */ - char *argsbuf; /* Command arguments buffer */ + u8 *inbuf; /* Input buffer */ + u8 *rawbuf; /* Raw Input buffer */ + u8 *cmdbuf; /* Command buffer */ + u8 *argsbuf; /* Command arguments buffer */ unsigned long flags; /* device flags */ unsigned long quirks; /* Various quirks */ @@ -450,7 +450,8 @@ static int i2c_hid_hwreset(struct i2c_client *client) static void i2c_hid_get_input(struct i2c_hid *ihid) { - int ret, ret_size; + int ret; + u32 ret_size; int size = le16_to_cpu(ihid->hdesc.wMaxInputLength); if (size > ihid->bufsize) @@ -475,7 +476,7 @@ static void i2c_hid_get_input(struct i2c_hid *ihid) return; } - if (ret_size > size) { + if ((ret_size > size) || (ret_size <= 2)) { dev_err(&ihid->client->dev, "%s: incomplete report (%d/%d)\n", __func__, size, ret_size); return; -- GitLab From 44ff2389a840c76434c943544f24909783366d90 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Wed, 11 Apr 2018 18:03:31 +0200 Subject: [PATCH 0678/1635] i2c: i801: Save register SMBSLVCMD value only once commit a086bb8317303dd74725dca933b9b29575159382 upstream. Saving the original value of register SMBSLVCMD in i801_enable_host_notify() doesn't work, because this function is called not only at probe time but also at resume time. Do it in i801_probe() instead, so that the saved value is not overwritten at resume time. Signed-off-by: Jean Delvare Fixes: 22e94bd6779e ("i2c: i801: store and restore the SLVCMD register at load and unload") Reviewed-by: Benjamin Tissoires Tested-by: Jason Andryuk Signed-off-by: Wolfram Sang Cc: stable@vger.kernel.org # v4.10+ Signed-off-by: Greg Kroah-Hartman --- drivers/i2c/busses/i2c-i801.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index 8eac00efadc1..fd167f78051a 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -965,8 +965,6 @@ static void i801_enable_host_notify(struct i2c_adapter *adapter) if (!(priv->features & FEATURE_HOST_NOTIFY)) return; - priv->original_slvcmd = inb_p(SMBSLVCMD(priv)); - if (!(SMBSLVCMD_HST_NTFY_INTREN & priv->original_slvcmd)) outb_p(SMBSLVCMD_HST_NTFY_INTREN | priv->original_slvcmd, SMBSLVCMD(priv)); @@ -1614,6 +1612,10 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id) outb_p(inb_p(SMBAUXCTL(priv)) & ~(SMBAUXCTL_CRC | SMBAUXCTL_E32B), SMBAUXCTL(priv)); + /* Remember original Host Notify setting */ + if (priv->features & FEATURE_HOST_NOTIFY) + priv->original_slvcmd = inb_p(SMBSLVCMD(priv)); + /* Default timeout in interrupt mode: 200 ms */ priv->adapter.timeout = HZ / 5; -- GitLab From fd5cc02cbef93b2391d295d81f16706fdc01bcea Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Wed, 11 Apr 2018 18:05:34 +0200 Subject: [PATCH 0679/1635] i2c: i801: Restore configuration at shutdown commit f7f6d915a10f7f2bce17e3b1b7d3376562395a28 upstream. On some systems, the BIOS expects certain SMBus register values to match the hardware defaults. Restore these configuration registers at shutdown time to avoid confusing the BIOS. This avoids hard-locking such systems upon reboot. Signed-off-by: Jean Delvare Tested-by: Jason Andryuk Signed-off-by: Wolfram Sang Cc: stable@vger.kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/i2c/busses/i2c-i801.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index fd167f78051a..ba8df2fde1b2 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -1700,6 +1700,15 @@ static void i801_remove(struct pci_dev *dev) */ } +static void i801_shutdown(struct pci_dev *dev) +{ + struct i801_priv *priv = pci_get_drvdata(dev); + + /* Restore config registers to avoid hard hang on some systems */ + i801_disable_host_notify(priv); + pci_write_config_byte(dev, SMBHSTCFG, priv->original_hstcfg); +} + #ifdef CONFIG_PM static int i801_suspend(struct device *dev) { @@ -1729,6 +1738,7 @@ static struct pci_driver i801_driver = { .id_table = i801_ids, .probe = i801_probe, .remove = i801_remove, + .shutdown = i801_shutdown, .driver = { .pm = &i801_pm_ops, }, -- GitLab From 0910e2804f2ecb081bd87c26cdb8f4ff502c39f2 Mon Sep 17 00:00:00 2001 From: Aurelien Aptel Date: Fri, 16 Feb 2018 19:19:27 +0100 Subject: [PATCH 0680/1635] CIFS: refactor crypto shash/sdesc allocation&free commit 82fb82be05585426405667dd5f0510aa953ba439 upstream. shash and sdesc and always allocated and freed together. * abstract this in new functions cifs_alloc_hash() and cifs_free_hash(). * make smb2/3 crypto allocation independent from each other. Signed-off-by: Aurelien Aptel Signed-off-by: Steve French Reviewed-by: Ronnie Sahlberg CC: Stable Signed-off-by: Greg Kroah-Hartman --- fs/cifs/cifsencrypt.c | 78 ++++------------------------------------- fs/cifs/cifsproto.h | 5 +++ fs/cifs/link.c | 27 ++++---------- fs/cifs/misc.c | 54 ++++++++++++++++++++++++++++ fs/cifs/smb2transport.c | 75 ++++++++------------------------------- fs/cifs/smbencrypt.c | 27 ++++---------- 6 files changed, 93 insertions(+), 173 deletions(-) diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c index f2b0a7f124da..478a145aa4d0 100644 --- a/fs/cifs/cifsencrypt.c +++ b/fs/cifs/cifsencrypt.c @@ -36,37 +36,6 @@ #include #include -static int -cifs_crypto_shash_md5_allocate(struct TCP_Server_Info *server) -{ - int rc; - unsigned int size; - - if (server->secmech.sdescmd5 != NULL) - return 0; /* already allocated */ - - server->secmech.md5 = crypto_alloc_shash("md5", 0, 0); - if (IS_ERR(server->secmech.md5)) { - cifs_dbg(VFS, "could not allocate crypto md5\n"); - rc = PTR_ERR(server->secmech.md5); - server->secmech.md5 = NULL; - return rc; - } - - size = sizeof(struct shash_desc) + - crypto_shash_descsize(server->secmech.md5); - server->secmech.sdescmd5 = kmalloc(size, GFP_KERNEL); - if (!server->secmech.sdescmd5) { - crypto_free_shash(server->secmech.md5); - server->secmech.md5 = NULL; - return -ENOMEM; - } - server->secmech.sdescmd5->shash.tfm = server->secmech.md5; - server->secmech.sdescmd5->shash.flags = 0x0; - - return 0; -} - int __cifs_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server, char *signature, struct shash_desc *shash) @@ -132,13 +101,10 @@ static int cifs_calc_signature(struct smb_rqst *rqst, if (!rqst->rq_iov || !signature || !server) return -EINVAL; - if (!server->secmech.sdescmd5) { - rc = cifs_crypto_shash_md5_allocate(server); - if (rc) { - cifs_dbg(VFS, "%s: Can't alloc md5 crypto\n", __func__); - return -1; - } - } + rc = cifs_alloc_hash("md5", &server->secmech.md5, + &server->secmech.sdescmd5); + if (rc) + return -1; rc = crypto_shash_init(&server->secmech.sdescmd5->shash); if (rc) { @@ -663,37 +629,6 @@ CalcNTLMv2_response(const struct cifs_ses *ses, char *ntlmv2_hash) return rc; } -static int crypto_hmacmd5_alloc(struct TCP_Server_Info *server) -{ - int rc; - unsigned int size; - - /* check if already allocated */ - if (server->secmech.sdeschmacmd5) - return 0; - - server->secmech.hmacmd5 = crypto_alloc_shash("hmac(md5)", 0, 0); - if (IS_ERR(server->secmech.hmacmd5)) { - cifs_dbg(VFS, "could not allocate crypto hmacmd5\n"); - rc = PTR_ERR(server->secmech.hmacmd5); - server->secmech.hmacmd5 = NULL; - return rc; - } - - size = sizeof(struct shash_desc) + - crypto_shash_descsize(server->secmech.hmacmd5); - server->secmech.sdeschmacmd5 = kmalloc(size, GFP_KERNEL); - if (!server->secmech.sdeschmacmd5) { - crypto_free_shash(server->secmech.hmacmd5); - server->secmech.hmacmd5 = NULL; - return -ENOMEM; - } - server->secmech.sdeschmacmd5->shash.tfm = server->secmech.hmacmd5; - server->secmech.sdeschmacmd5->shash.flags = 0x0; - - return 0; -} - int setup_ntlmv2_rsp(struct cifs_ses *ses, const struct nls_table *nls_cp) { @@ -757,9 +692,10 @@ setup_ntlmv2_rsp(struct cifs_ses *ses, const struct nls_table *nls_cp) mutex_lock(&ses->server->srv_mutex); - rc = crypto_hmacmd5_alloc(ses->server); + rc = cifs_alloc_hash("hmac(md5)", + &ses->server->secmech.hmacmd5, + &ses->server->secmech.sdeschmacmd5); if (rc) { - cifs_dbg(VFS, "could not crypto alloc hmacmd5 rc %d\n", rc); goto unlock; } diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index 4143c9dec463..762d513a5087 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -538,4 +538,9 @@ enum securityEnum cifs_select_sectype(struct TCP_Server_Info *, struct cifs_aio_ctx *cifs_aio_ctx_alloc(void); void cifs_aio_ctx_release(struct kref *refcount); int setup_aio_ctx_iter(struct cifs_aio_ctx *ctx, struct iov_iter *iter, int rw); + +int cifs_alloc_hash(const char *name, struct crypto_shash **shash, + struct sdesc **sdesc); +void cifs_free_hash(struct crypto_shash **shash, struct sdesc **sdesc); + #endif /* _CIFSPROTO_H */ diff --git a/fs/cifs/link.c b/fs/cifs/link.c index 60b5a11ee11b..889a840172eb 100644 --- a/fs/cifs/link.c +++ b/fs/cifs/link.c @@ -50,25 +50,12 @@ static int symlink_hash(unsigned int link_len, const char *link_str, u8 *md5_hash) { int rc; - unsigned int size; - struct crypto_shash *md5; - struct sdesc *sdescmd5; - - md5 = crypto_alloc_shash("md5", 0, 0); - if (IS_ERR(md5)) { - rc = PTR_ERR(md5); - cifs_dbg(VFS, "%s: Crypto md5 allocation error %d\n", - __func__, rc); - return rc; - } - size = sizeof(struct shash_desc) + crypto_shash_descsize(md5); - sdescmd5 = kmalloc(size, GFP_KERNEL); - if (!sdescmd5) { - rc = -ENOMEM; + struct crypto_shash *md5 = NULL; + struct sdesc *sdescmd5 = NULL; + + rc = cifs_alloc_hash("md5", &md5, &sdescmd5); + if (rc) goto symlink_hash_err; - } - sdescmd5->shash.tfm = md5; - sdescmd5->shash.flags = 0x0; rc = crypto_shash_init(&sdescmd5->shash); if (rc) { @@ -85,9 +72,7 @@ symlink_hash(unsigned int link_len, const char *link_str, u8 *md5_hash) cifs_dbg(VFS, "%s: Could not generate md5 hash\n", __func__); symlink_hash_err: - crypto_free_shash(md5); - kfree(sdescmd5); - + cifs_free_hash(&md5, &sdescmd5); return rc; } diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c index a0dbced4a45c..460084a8eac5 100644 --- a/fs/cifs/misc.c +++ b/fs/cifs/misc.c @@ -848,3 +848,57 @@ setup_aio_ctx_iter(struct cifs_aio_ctx *ctx, struct iov_iter *iter, int rw) iov_iter_bvec(&ctx->iter, ITER_BVEC | rw, ctx->bv, npages, ctx->len); return 0; } + +/** + * cifs_alloc_hash - allocate hash and hash context together + * + * The caller has to make sure @sdesc is initialized to either NULL or + * a valid context. Both can be freed via cifs_free_hash(). + */ +int +cifs_alloc_hash(const char *name, + struct crypto_shash **shash, struct sdesc **sdesc) +{ + int rc = 0; + size_t size; + + if (*sdesc != NULL) + return 0; + + *shash = crypto_alloc_shash(name, 0, 0); + if (IS_ERR(*shash)) { + cifs_dbg(VFS, "could not allocate crypto %s\n", name); + rc = PTR_ERR(*shash); + *shash = NULL; + *sdesc = NULL; + return rc; + } + + size = sizeof(struct shash_desc) + crypto_shash_descsize(*shash); + *sdesc = kmalloc(size, GFP_KERNEL); + if (*sdesc == NULL) { + cifs_dbg(VFS, "no memory left to allocate crypto %s\n", name); + crypto_free_shash(*shash); + *shash = NULL; + return -ENOMEM; + } + + (*sdesc)->shash.tfm = *shash; + (*sdesc)->shash.flags = 0x0; + return 0; +} + +/** + * cifs_free_hash - free hash and hash context together + * + * Freeing a NULL hash or context is safe. + */ +void +cifs_free_hash(struct crypto_shash **shash, struct sdesc **sdesc) +{ + kfree(*sdesc); + *sdesc = NULL; + if (*shash) + crypto_free_shash(*shash); + *shash = NULL; +} diff --git a/fs/cifs/smb2transport.c b/fs/cifs/smb2transport.c index 99493946e2f9..c3c271f557a0 100644 --- a/fs/cifs/smb2transport.c +++ b/fs/cifs/smb2transport.c @@ -43,76 +43,31 @@ static int smb2_crypto_shash_allocate(struct TCP_Server_Info *server) { - int rc; - unsigned int size; - - if (server->secmech.sdeschmacsha256 != NULL) - return 0; /* already allocated */ - - server->secmech.hmacsha256 = crypto_alloc_shash("hmac(sha256)", 0, 0); - if (IS_ERR(server->secmech.hmacsha256)) { - cifs_dbg(VFS, "could not allocate crypto hmacsha256\n"); - rc = PTR_ERR(server->secmech.hmacsha256); - server->secmech.hmacsha256 = NULL; - return rc; - } - - size = sizeof(struct shash_desc) + - crypto_shash_descsize(server->secmech.hmacsha256); - server->secmech.sdeschmacsha256 = kmalloc(size, GFP_KERNEL); - if (!server->secmech.sdeschmacsha256) { - crypto_free_shash(server->secmech.hmacsha256); - server->secmech.hmacsha256 = NULL; - return -ENOMEM; - } - server->secmech.sdeschmacsha256->shash.tfm = server->secmech.hmacsha256; - server->secmech.sdeschmacsha256->shash.flags = 0x0; - - return 0; + return cifs_alloc_hash("hmac(sha256)", + &server->secmech.hmacsha256, + &server->secmech.sdeschmacsha256); } static int smb3_crypto_shash_allocate(struct TCP_Server_Info *server) { - unsigned int size; + struct cifs_secmech *p = &server->secmech; int rc; - if (server->secmech.sdesccmacaes != NULL) - return 0; /* already allocated */ - - rc = smb2_crypto_shash_allocate(server); + rc = cifs_alloc_hash("hmac(sha256)", + &p->hmacsha256, + &p->sdeschmacsha256); if (rc) - return rc; - - server->secmech.cmacaes = crypto_alloc_shash("cmac(aes)", 0, 0); - if (IS_ERR(server->secmech.cmacaes)) { - cifs_dbg(VFS, "could not allocate crypto cmac-aes"); - kfree(server->secmech.sdeschmacsha256); - server->secmech.sdeschmacsha256 = NULL; - crypto_free_shash(server->secmech.hmacsha256); - server->secmech.hmacsha256 = NULL; - rc = PTR_ERR(server->secmech.cmacaes); - server->secmech.cmacaes = NULL; - return rc; - } + goto err; - size = sizeof(struct shash_desc) + - crypto_shash_descsize(server->secmech.cmacaes); - server->secmech.sdesccmacaes = kmalloc(size, GFP_KERNEL); - if (!server->secmech.sdesccmacaes) { - cifs_dbg(VFS, "%s: Can't alloc cmacaes\n", __func__); - kfree(server->secmech.sdeschmacsha256); - server->secmech.sdeschmacsha256 = NULL; - crypto_free_shash(server->secmech.hmacsha256); - crypto_free_shash(server->secmech.cmacaes); - server->secmech.hmacsha256 = NULL; - server->secmech.cmacaes = NULL; - return -ENOMEM; - } - server->secmech.sdesccmacaes->shash.tfm = server->secmech.cmacaes; - server->secmech.sdesccmacaes->shash.flags = 0x0; + rc = cifs_alloc_hash("cmac(aes)", &p->cmacaes, &p->sdesccmacaes); + if (rc) + goto err; return 0; +err: + cifs_free_hash(&p->hmacsha256, &p->sdeschmacsha256); + return rc; } static struct cifs_ses * @@ -457,7 +412,7 @@ smb3_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server) cifs_dbg(VFS, "%s: Could not init cmac aes\n", __func__); return rc; } - + rc = __cifs_calc_signature(rqst, server, sigptr, &server->secmech.sdesccmacaes->shash); diff --git a/fs/cifs/smbencrypt.c b/fs/cifs/smbencrypt.c index c12bffefa3c9..a0b80ac651a6 100644 --- a/fs/cifs/smbencrypt.c +++ b/fs/cifs/smbencrypt.c @@ -121,25 +121,12 @@ int mdfour(unsigned char *md4_hash, unsigned char *link_str, int link_len) { int rc; - unsigned int size; - struct crypto_shash *md4; - struct sdesc *sdescmd4; - - md4 = crypto_alloc_shash("md4", 0, 0); - if (IS_ERR(md4)) { - rc = PTR_ERR(md4); - cifs_dbg(VFS, "%s: Crypto md4 allocation error %d\n", - __func__, rc); - return rc; - } - size = sizeof(struct shash_desc) + crypto_shash_descsize(md4); - sdescmd4 = kmalloc(size, GFP_KERNEL); - if (!sdescmd4) { - rc = -ENOMEM; + struct crypto_shash *md4 = NULL; + struct sdesc *sdescmd4 = NULL; + + rc = cifs_alloc_hash("md4", &md4, &sdescmd4); + if (rc) goto mdfour_err; - } - sdescmd4->shash.tfm = md4; - sdescmd4->shash.flags = 0x0; rc = crypto_shash_init(&sdescmd4->shash); if (rc) { @@ -156,9 +143,7 @@ mdfour(unsigned char *md4_hash, unsigned char *link_str, int link_len) cifs_dbg(VFS, "%s: Could not generate md4 hash\n", __func__); mdfour_err: - crypto_free_shash(md4); - kfree(sdescmd4); - + cifs_free_hash(&md4, &sdescmd4); return rc; } -- GitLab From 7a55d160b730da05a7ea82c6c78b8e8d012a74cc Mon Sep 17 00:00:00 2001 From: Aurelien Aptel Date: Fri, 16 Feb 2018 19:19:28 +0100 Subject: [PATCH 0681/1635] CIFS: add sha512 secmech commit 5fcd7f3f966f37f3f9a215af4cc1597fe338d0d5 upstream. * prepare for SMB3.11 pre-auth integrity * enable sha512 when SMB311 is enabled in Kconfig * add sha512 as a soft dependency Signed-off-by: Aurelien Aptel Signed-off-by: Steve French CC: Stable Reviewed-by: Ronnie Sahlberg Signed-off-by: Greg Kroah-Hartman --- fs/cifs/Kconfig | 1 + fs/cifs/cifsencrypt.c | 7 +++++++ fs/cifs/cifsfs.c | 1 + fs/cifs/cifsglob.h | 2 ++ fs/cifs/smb2proto.h | 3 +++ fs/cifs/smb2transport.c | 30 ++++++++++++++++++++++++++++++ 6 files changed, 44 insertions(+) diff --git a/fs/cifs/Kconfig b/fs/cifs/Kconfig index d5b2e12b5d02..cb0f1fbe836d 100644 --- a/fs/cifs/Kconfig +++ b/fs/cifs/Kconfig @@ -190,6 +190,7 @@ config CIFS_NFSD_EXPORT config CIFS_SMB311 bool "SMB3.1.1 network file system support (Experimental)" depends on CIFS + select CRYPTO_SHA512 help This enables experimental support for the newest, SMB3.1.1, dialect. diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c index 478a145aa4d0..6fa6d459678e 100644 --- a/fs/cifs/cifsencrypt.c +++ b/fs/cifs/cifsencrypt.c @@ -829,6 +829,11 @@ cifs_crypto_secmech_release(struct TCP_Server_Info *server) server->secmech.md5 = NULL; } + if (server->secmech.md5) { + crypto_free_shash(server->secmech.sha512); + server->secmech.sha512 = NULL; + } + if (server->secmech.hmacmd5) { crypto_free_shash(server->secmech.hmacmd5); server->secmech.hmacmd5 = NULL; @@ -852,4 +857,6 @@ cifs_crypto_secmech_release(struct TCP_Server_Info *server) server->secmech.sdeschmacmd5 = NULL; kfree(server->secmech.sdescmd5); server->secmech.sdescmd5 = NULL; + kfree(server->secmech.sdescsha512); + server->secmech.sdescsha512 = NULL; } diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 8c8b75d33f31..dbcd2e066066 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -1476,6 +1476,7 @@ MODULE_SOFTDEP("pre: nls"); MODULE_SOFTDEP("pre: aes"); MODULE_SOFTDEP("pre: cmac"); MODULE_SOFTDEP("pre: sha256"); +MODULE_SOFTDEP("pre: sha512"); MODULE_SOFTDEP("pre: aead2"); MODULE_SOFTDEP("pre: ccm"); module_init(init_cifs) diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 6b6496820a21..33d6eb58ce34 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -130,10 +130,12 @@ struct cifs_secmech { struct crypto_shash *md5; /* md5 hash function */ struct crypto_shash *hmacsha256; /* hmac-sha256 hash function */ struct crypto_shash *cmacaes; /* block-cipher based MAC function */ + struct crypto_shash *sha512; /* sha512 hash function */ struct sdesc *sdeschmacmd5; /* ctxt to generate ntlmv2 hash, CR1 */ struct sdesc *sdescmd5; /* ctxt to generate cifs/smb signature */ struct sdesc *sdeschmacsha256; /* ctxt to generate smb2 signature */ struct sdesc *sdesccmacaes; /* ctxt to generate smb3 signature */ + struct sdesc *sdescsha512; /* ctxt to generate smb3.11 signing key */ struct crypto_aead *ccmaesencrypt; /* smb3 encryption aead */ struct crypto_aead *ccmaesdecrypt; /* smb3 decryption aead */ }; diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h index e9ab5227e7a8..6fe4898f6975 100644 --- a/fs/cifs/smb2proto.h +++ b/fs/cifs/smb2proto.h @@ -203,4 +203,7 @@ extern int smb3_validate_negotiate(const unsigned int, struct cifs_tcon *); extern enum securityEnum smb2_select_sectype(struct TCP_Server_Info *, enum securityEnum); +#ifdef CONFIG_CIFS_SMB311 +extern int smb311_crypto_shash_allocate(struct TCP_Server_Info *server); +#endif #endif /* _SMB2PROTO_H */ diff --git a/fs/cifs/smb2transport.c b/fs/cifs/smb2transport.c index c3c271f557a0..bf49cb73b9e6 100644 --- a/fs/cifs/smb2transport.c +++ b/fs/cifs/smb2transport.c @@ -70,6 +70,36 @@ smb3_crypto_shash_allocate(struct TCP_Server_Info *server) return rc; } +#ifdef CONFIG_CIFS_SMB311 +int +smb311_crypto_shash_allocate(struct TCP_Server_Info *server) +{ + struct cifs_secmech *p = &server->secmech; + int rc = 0; + + rc = cifs_alloc_hash("hmac(sha256)", + &p->hmacsha256, + &p->sdeschmacsha256); + if (rc) + return rc; + + rc = cifs_alloc_hash("cmac(aes)", &p->cmacaes, &p->sdesccmacaes); + if (rc) + goto err; + + rc = cifs_alloc_hash("sha512", &p->sha512, &p->sdescsha512); + if (rc) + goto err; + + return 0; + +err: + cifs_free_hash(&p->cmacaes, &p->sdesccmacaes); + cifs_free_hash(&p->hmacsha256, &p->sdeschmacsha256); + return rc; +} +#endif + static struct cifs_ses * smb2_find_smb_ses_unlocked(struct TCP_Server_Info *server, __u64 ses_id) { -- GitLab From 693b03f9b185f14dded38a934c744a60e99363c3 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Mon, 19 Feb 2018 11:11:13 -0600 Subject: [PATCH 0682/1635] CIFS: fix sha512 check in cifs_crypto_secmech_release commit 70e80655f58e17a2e38e577e1b4fa7a8c99619a0 upstream. It seems this is a copy-paste error and that the proper variable to use in this particular case is _sha512_ instead of _md5_. Addresses-Coverity-ID: 1465358 ("Copy-paste error") Fixes: 1c6614d229e7 ("CIFS: add sha512 secmech") Signed-off-by: Gustavo A. R. Silva Reviewed-by: Aurelien Aptel CC: Stable Signed-off-by: Steve French Signed-off-by: Greg Kroah-Hartman --- fs/cifs/cifsencrypt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c index 6fa6d459678e..a6ef088e057b 100644 --- a/fs/cifs/cifsencrypt.c +++ b/fs/cifs/cifsencrypt.c @@ -829,7 +829,7 @@ cifs_crypto_secmech_release(struct TCP_Server_Info *server) server->secmech.md5 = NULL; } - if (server->secmech.md5) { + if (server->secmech.sha512) { crypto_free_shash(server->secmech.sha512); server->secmech.sha512 = NULL; } -- GitLab From c3baeca67d85e698201fca324368c3a704667e80 Mon Sep 17 00:00:00 2001 From: Nicholas Piggin Date: Tue, 27 Mar 2018 01:02:33 +1000 Subject: [PATCH 0683/1635] powerpc/powernv: Handle unknown OPAL errors in opal_nvram_write() commit 741de617661794246f84a21a02fc5e327bffc9ad upstream. opal_nvram_write currently just assumes success if it encounters an error other than OPAL_BUSY or OPAL_BUSY_EVENT. Have it return -EIO on other errors instead. Fixes: 628daa8d5abf ("powerpc/powernv: Add RTC and NVRAM support plus RTAS fallbacks") Cc: stable@vger.kernel.org # v3.2+ Signed-off-by: Nicholas Piggin Reviewed-by: Vasant Hegde Acked-by: Stewart Smith Signed-off-by: Michael Ellerman Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/platforms/powernv/opal-nvram.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/powerpc/platforms/powernv/opal-nvram.c b/arch/powerpc/platforms/powernv/opal-nvram.c index 9db4398ded5d..ba2ff06a2c98 100644 --- a/arch/powerpc/platforms/powernv/opal-nvram.c +++ b/arch/powerpc/platforms/powernv/opal-nvram.c @@ -59,6 +59,10 @@ static ssize_t opal_nvram_write(char *buf, size_t count, loff_t *index) if (rc == OPAL_BUSY_EVENT) opal_poll_events(NULL); } + + if (rc) + return -EIO; + *index += count; return count; } -- GitLab From f4eff13a278079ab219a182a354e8571e0bdc468 Mon Sep 17 00:00:00 2001 From: Nicholas Piggin Date: Thu, 5 Apr 2018 15:50:49 +1000 Subject: [PATCH 0684/1635] powerpc/64s: Fix dt_cpu_ftrs to have restore_cpu clear unwanted LPCR bits commit a57ac411832384eb93df4bfed2bf644c4089720e upstream. Presently the dt_cpu_ftrs restore_cpu will only add bits to the LPCR for secondaries, but some bits must be removed (e.g., UPRT for HPT). Not clearing these bits on secondaries causes checkstops when booting with disable_radix. restore_cpu can not just set LPCR, because it is also called by the idle wakeup code which relies on opal_slw_set_reg to restore the value of LPCR, at least on P8 which does not save LPCR to stack in the idle code. Fix this by including a mask of bits to clear from LPCR as well, which is used by restore_cpu. This is a little messy now, but it's a minimal fix that can be backported. Longer term, the idle SPR save/restore code can be reworked to completely avoid calls to restore_cpu, then restore_cpu would be able to unconditionally set LPCR to match boot processor environment. Fixes: 5a61ef74f269f ("powerpc/64s: Support new device tree binding for discovering CPU features") Cc: stable@vger.kernel.org # v4.12+ Signed-off-by: Nicholas Piggin Signed-off-by: Michael Ellerman Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/kernel/dt_cpu_ftrs.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/arch/powerpc/kernel/dt_cpu_ftrs.c b/arch/powerpc/kernel/dt_cpu_ftrs.c index 7275fed271af..f047ae1b6271 100644 --- a/arch/powerpc/kernel/dt_cpu_ftrs.c +++ b/arch/powerpc/kernel/dt_cpu_ftrs.c @@ -86,6 +86,7 @@ static int hv_mode; static struct { u64 lpcr; + u64 lpcr_clear; u64 hfscr; u64 fscr; } system_registers; @@ -115,6 +116,8 @@ static void cpufeatures_flush_tlb(void) static void __restore_cpu_cpufeatures(void) { + u64 lpcr; + /* * LPCR is restored by the power on engine already. It can be changed * after early init e.g., by radix enable, and we have no unified API @@ -127,8 +130,10 @@ static void __restore_cpu_cpufeatures(void) * The best we can do to accommodate secondary boot and idle restore * for now is "or" LPCR with existing. */ - - mtspr(SPRN_LPCR, system_registers.lpcr | mfspr(SPRN_LPCR)); + lpcr = mfspr(SPRN_LPCR); + lpcr |= system_registers.lpcr; + lpcr &= ~system_registers.lpcr_clear; + mtspr(SPRN_LPCR, lpcr); if (hv_mode) { mtspr(SPRN_LPID, 0); mtspr(SPRN_HFSCR, system_registers.hfscr); @@ -351,8 +356,9 @@ static int __init feat_enable_mmu_hash_v3(struct dt_cpu_feature *f) { u64 lpcr; + system_registers.lpcr_clear |= (LPCR_ISL | LPCR_UPRT | LPCR_HR); lpcr = mfspr(SPRN_LPCR); - lpcr &= ~LPCR_ISL; + lpcr &= ~(LPCR_ISL | LPCR_UPRT | LPCR_HR); mtspr(SPRN_LPCR, lpcr); cur_cpu_spec->mmu_features |= MMU_FTRS_HASH_BASE; -- GitLab From 1699bd03742d89732f2d15eb8e4a544cfe4da1fa Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Thu, 16 Feb 2017 16:03:39 +1100 Subject: [PATCH 0685/1635] powerpc/64: Call H_REGISTER_PROC_TBL when running as a HPT guest on POWER9 commit dbfcf3cb9c681aa0c5d0bb46068f98d5b1823dd3 upstream. On POWER9, since commit cc3d2940133d ("powerpc/64: Enable use of radix MMU under hypervisor on POWER9", 2017-01-30), we set both the radix and HPT bits in the client-architecture-support (CAS) vector, which tells the hypervisor that we can do either radix or HPT. According to PAPR, if we use this combination we are promising to do a H_REGISTER_PROC_TBL hcall later on to let the hypervisor know whether we are doing radix or HPT. We currently do this call if we are doing radix but not if we are doing HPT. If the hypervisor is able to support both radix and HPT guests, it would be entitled to defer allocation of the HPT until the H_REGISTER_PROC_TBL call, and to fail any attempts to create HPTEs until the H_REGISTER_PROC_TBL call. Thus we need to do a H_REGISTER_PROC_TBL call when we are doing HPT; otherwise we may crash at boot time. This adds the code to call H_REGISTER_PROC_TBL in this case, before we attempt to create any HPT entries using H_ENTER. Fixes: cc3d2940133d ("powerpc/64: Enable use of radix MMU under hypervisor on POWER9") Cc: stable@vger.kernel.org # v4.11+ Signed-off-by: Paul Mackerras Reviewed-by: Suraj Jitindar Singh Signed-off-by: Michael Ellerman Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/mm/hash_utils_64.c | 6 ++++++ arch/powerpc/platforms/pseries/lpar.c | 8 ++++++-- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/arch/powerpc/mm/hash_utils_64.c b/arch/powerpc/mm/hash_utils_64.c index 67ec2e927253..87687e46b48b 100644 --- a/arch/powerpc/mm/hash_utils_64.c +++ b/arch/powerpc/mm/hash_utils_64.c @@ -872,6 +872,12 @@ static void __init htab_initialize(void) /* Using a hypervisor which owns the htab */ htab_address = NULL; _SDR1 = 0; + /* + * On POWER9, we need to do a H_REGISTER_PROC_TBL hcall + * to inform the hypervisor that we wish to use the HPT. + */ + if (cpu_has_feature(CPU_FTR_ARCH_300)) + register_process_table(0, 0, 0); #ifdef CONFIG_FA_DUMP /* * If firmware assisted dump is active firmware preserves diff --git a/arch/powerpc/platforms/pseries/lpar.c b/arch/powerpc/platforms/pseries/lpar.c index 495ba4e7336d..55e97565ed2d 100644 --- a/arch/powerpc/platforms/pseries/lpar.c +++ b/arch/powerpc/platforms/pseries/lpar.c @@ -726,15 +726,18 @@ static int pseries_lpar_resize_hpt(unsigned long shift) return 0; } -/* Actually only used for radix, so far */ static int pseries_lpar_register_process_table(unsigned long base, unsigned long page_size, unsigned long table_size) { long rc; - unsigned long flags = PROC_TABLE_NEW; + unsigned long flags = 0; + if (table_size) + flags |= PROC_TABLE_NEW; if (radix_enabled()) flags |= PROC_TABLE_RADIX | PROC_TABLE_GTSE; + else + flags |= PROC_TABLE_HPT_SLB; for (;;) { rc = plpar_hcall_norets(H_REGISTER_PROC_TBL, flags, base, page_size, table_size); @@ -760,6 +763,7 @@ void __init hpte_init_pseries(void) mmu_hash_ops.flush_hash_range = pSeries_lpar_flush_hash_range; mmu_hash_ops.hpte_clear_all = pseries_hpte_clear_all; mmu_hash_ops.hugepage_invalidate = pSeries_lpar_hugepage_invalidate; + register_process_table = pseries_lpar_register_process_table; if (firmware_has_feature(FW_FEATURE_HPT_RESIZE)) mmu_hash_ops.resize_hpt = pseries_lpar_resize_hpt; -- GitLab From 3df05fcf89114e9011b899dcb7437a50a978bac1 Mon Sep 17 00:00:00 2001 From: Nicholas Piggin Date: Thu, 22 Mar 2018 20:41:46 +1000 Subject: [PATCH 0686/1635] powerpc/64: Fix smp_wmb barrier definition use use lwsync consistently commit 0bfdf598900fd62869659f360d3387ed80eb71cf upstream. asm/barrier.h is not always included after asm/synch.h, which meant it was missing __SUBARCH_HAS_LWSYNC, so in some files smp_wmb() would be eieio when it should be lwsync. kernel/time/hrtimer.c is one case. __SUBARCH_HAS_LWSYNC is only used in one place, so just fold it in to where it's used. Previously with my small simulator config, 377 instances of eieio in the tree. After this patch there are 55. Fixes: 46d075be585e ("powerpc: Optimise smp_wmb") Cc: stable@vger.kernel.org # v2.6.29+ Signed-off-by: Nicholas Piggin Signed-off-by: Michael Ellerman Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/include/asm/barrier.h | 3 ++- arch/powerpc/include/asm/synch.h | 4 ---- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/arch/powerpc/include/asm/barrier.h b/arch/powerpc/include/asm/barrier.h index 10daa1d56e0a..c7c63959ba91 100644 --- a/arch/powerpc/include/asm/barrier.h +++ b/arch/powerpc/include/asm/barrier.h @@ -35,7 +35,8 @@ #define rmb() __asm__ __volatile__ ("sync" : : : "memory") #define wmb() __asm__ __volatile__ ("sync" : : : "memory") -#ifdef __SUBARCH_HAS_LWSYNC +/* The sub-arch has lwsync */ +#if defined(__powerpc64__) || defined(CONFIG_PPC_E500MC) # define SMPWMB LWSYNC #else # define SMPWMB eieio diff --git a/arch/powerpc/include/asm/synch.h b/arch/powerpc/include/asm/synch.h index 63e7f5a1f105..6ec546090ba1 100644 --- a/arch/powerpc/include/asm/synch.h +++ b/arch/powerpc/include/asm/synch.h @@ -6,10 +6,6 @@ #include #include -#if defined(__powerpc64__) || defined(CONFIG_PPC_E500MC) -#define __SUBARCH_HAS_LWSYNC -#endif - #ifndef __ASSEMBLY__ extern unsigned int __start___lwsync_fixup, __stop___lwsync_fixup; extern void do_lwsync_fixups(unsigned long value, void *fixup_start, -- GitLab From fa99a3470e917a7a83b0648b53d2e1a5d71f3b29 Mon Sep 17 00:00:00 2001 From: "Naveen N. Rao" Date: Wed, 17 Jan 2018 17:52:24 +0530 Subject: [PATCH 0687/1635] powerpc/kprobes: Fix call trace due to incorrect preempt count commit e6e133c47e6bd4d5dac05b35d06634a8e5648615 upstream. Michael Ellerman reported the following call trace when running ftracetest: BUG: using __this_cpu_write() in preemptible [00000000] code: ftracetest/6178 caller is opt_pre_handler+0xc4/0x110 CPU: 1 PID: 6178 Comm: ftracetest Not tainted 4.15.0-rc7-gcc6x-gb2cd1df #1 Call Trace: [c0000000f9ec39c0] [c000000000ac4304] dump_stack+0xb4/0x100 (unreliable) [c0000000f9ec3a00] [c00000000061159c] check_preemption_disabled+0x15c/0x170 [c0000000f9ec3a90] [c000000000217e84] opt_pre_handler+0xc4/0x110 [c0000000f9ec3af0] [c00000000004cf68] optimized_callback+0x148/0x170 [c0000000f9ec3b40] [c00000000004d954] optinsn_slot+0xec/0x10000 [c0000000f9ec3e30] [c00000000004bae0] kretprobe_trampoline+0x0/0x10 This is showing up since OPTPROBES is now enabled with CONFIG_PREEMPT. trampoline_probe_handler() considers itself to be a special kprobe handler for kretprobes. In doing so, it expects to be called from kprobe_handler() on a trap, and re-enables preemption before returning a non-zero return value so as to suppress any subsequent processing of the trap by the kprobe_handler(). However, with optprobes, we don't deal with special handlers (we ignore the return code) and just try to re-enable preemption causing the above trace. To address this, modify trampoline_probe_handler() to not be special. The only additional processing done in kprobe_handler() is to emulate the instruction (in this case, a 'nop'). We adjust the value of regs->nip for the purpose and delegate the job of re-enabling preemption and resetting current kprobe to the probe handlers (kprobe_handler() or optimized_callback()). Fixes: 8a2d71a3f273 ("powerpc/kprobes: Disable preemption before invoking probe handler for optprobes") Cc: stable@vger.kernel.org # v4.15+ Reported-by: Michael Ellerman Signed-off-by: Naveen N. Rao Acked-by: Ananth N Mavinakayanahalli Signed-off-by: Michael Ellerman Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/kernel/kprobes.c | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/arch/powerpc/kernel/kprobes.c b/arch/powerpc/kernel/kprobes.c index bebc3007a793..10b46b35c059 100644 --- a/arch/powerpc/kernel/kprobes.c +++ b/arch/powerpc/kernel/kprobes.c @@ -457,29 +457,33 @@ static int trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs) } kretprobe_assert(ri, orig_ret_address, trampoline_address); - regs->nip = orig_ret_address; + /* - * Make LR point to the orig_ret_address. - * When the 'nop' inside the kretprobe_trampoline - * is optimized, we can do a 'blr' after executing the - * detour buffer code. + * We get here through one of two paths: + * 1. by taking a trap -> kprobe_handler() -> here + * 2. by optprobe branch -> optimized_callback() -> opt_pre_handler() -> here + * + * When going back through (1), we need regs->nip to be setup properly + * as it is used to determine the return address from the trap. + * For (2), since nip is not honoured with optprobes, we instead setup + * the link register properly so that the subsequent 'blr' in + * kretprobe_trampoline jumps back to the right instruction. + * + * For nip, we should set the address to the previous instruction since + * we end up emulating it in kprobe_handler(), which increments the nip + * again. */ + regs->nip = orig_ret_address - 4; regs->link = orig_ret_address; - reset_current_kprobe(); kretprobe_hash_unlock(current, &flags); - preempt_enable_no_resched(); hlist_for_each_entry_safe(ri, tmp, &empty_rp, hlist) { hlist_del(&ri->hlist); kfree(ri); } - /* - * By returning a non-zero value, we are telling - * kprobe_handler() that we don't want the post_handler - * to run (and have re-enabled preemption) - */ - return 1; + + return 0; } NOKPROBE_SYMBOL(trampoline_probe_handler); -- GitLab From a55d2c9d42f9212740911f4c8d4c3de12154ef42 Mon Sep 17 00:00:00 2001 From: Thiago Jung Bauermann Date: Thu, 29 Mar 2018 16:05:43 -0300 Subject: [PATCH 0688/1635] powerpc/kexec_file: Fix error code when trying to load kdump kernel commit bf8a1abc3ddbd6e9a8312ea7d96e5dd89c140f18 upstream. kexec_file_load() on powerpc doesn't support kdump kernels yet, so it returns -ENOTSUPP in that case. I've recently learned that this errno is internal to the kernel and isn't supposed to be exposed to userspace. Therefore, change to -EOPNOTSUPP which is defined in an uapi header. This does indeed make kexec-tools happier. Before the patch, on ppc64le: # ~bauermann/src/kexec-tools/build/sbin/kexec -s -p /boot/vmlinuz kexec_file_load failed: Unknown error 524 After the patch: # ~bauermann/src/kexec-tools/build/sbin/kexec -s -p /boot/vmlinuz kexec_file_load failed: Operation not supported Fixes: a0458284f062 ("powerpc: Add support code for kexec_file_load()") Cc: stable@vger.kernel.org # v4.10+ Reported-by: Dave Young Signed-off-by: Thiago Jung Bauermann Reviewed-by: Simon Horman Reviewed-by: Dave Young Signed-off-by: Michael Ellerman Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/kernel/machine_kexec_file_64.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/powerpc/kernel/machine_kexec_file_64.c b/arch/powerpc/kernel/machine_kexec_file_64.c index 992c0d258e5d..c66132b145eb 100644 --- a/arch/powerpc/kernel/machine_kexec_file_64.c +++ b/arch/powerpc/kernel/machine_kexec_file_64.c @@ -43,7 +43,7 @@ int arch_kexec_kernel_image_probe(struct kimage *image, void *buf, /* We don't support crash kernels yet. */ if (image->type == KEXEC_TYPE_CRASH) - return -ENOTSUPP; + return -EOPNOTSUPP; for (i = 0; i < ARRAY_SIZE(kexec_file_loaders); i++) { fops = kexec_file_loaders[i]; -- GitLab From 7c854f2e1ff08edd35988acd733c6b1ad0e95e8b Mon Sep 17 00:00:00 2001 From: Nicholas Piggin Date: Tue, 10 Apr 2018 21:49:31 +1000 Subject: [PATCH 0689/1635] powerpc/powernv: define a standard delay for OPAL_BUSY type retry loops commit 34dd25de9fe3f60bfdb31b473bf04b28262d0896 upstream. This is the start of an effort to tidy up and standardise all the delays. Existing loops have a range of delay/sleep periods from 1ms to 20ms, and some have no delay. They all loop forever except rtc, which times out after 10 retries, and that uses 10ms delays. So use 10ms as our standard delay. The OPAL maintainer agrees 10ms is a reasonable starting point. The idea is to use the same recipe everywhere, once this is proven to work then it will be documented as an OPAL API standard. Then both firmware and OS can agree, and if a particular call needs something else, then that can be documented with reasoning. This is not the end-all of this effort, it's just a relatively easy change that fixes some existing high latency delays. There should be provision for standardising timeouts and/or interruptible loops where possible, so non-fatal firmware errors don't cause hangs. Signed-off-by: Nicholas Piggin Signed-off-by: Michael Ellerman Cc: Nathan Chancellor Cc: Guenter Roeck Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/include/asm/opal.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/powerpc/include/asm/opal.h b/arch/powerpc/include/asm/opal.h index 726c23304a57..8eb3ebca02df 100644 --- a/arch/powerpc/include/asm/opal.h +++ b/arch/powerpc/include/asm/opal.h @@ -21,6 +21,9 @@ /* We calculate number of sg entries based on PAGE_SIZE */ #define SG_ENTRIES_PER_NODE ((PAGE_SIZE - 16) / sizeof(struct opal_sg_entry)) +/* Default time to sleep or delay between OPAL_BUSY/OPAL_BUSY_EVENT loops */ +#define OPAL_BUSY_DELAY_MS 10 + /* /sys/firmware/opal */ extern struct kobject *opal_kobj; -- GitLab From 25b6ee378dc43fff21e778f1a21cb7e6dffa6e1a Mon Sep 17 00:00:00 2001 From: Nicholas Piggin Date: Tue, 10 Apr 2018 21:49:33 +1000 Subject: [PATCH 0690/1635] powerpc/powernv: Fix OPAL NVRAM driver OPAL_BUSY loops commit 3b8070335f751aac9f1526ae2e012e6f5b8b0f21 upstream. The OPAL NVRAM driver does not sleep in case it gets OPAL_BUSY or OPAL_BUSY_EVENT from firmware, which causes large scheduling latencies, and various lockup errors to trigger (again, BMC reboot can cause it). Fix this by converting it to the standard form OPAL_BUSY loop that sleeps. Fixes: 628daa8d5abf ("powerpc/powernv: Add RTC and NVRAM support plus RTAS fallbacks") Depends-on: 34dd25de9fe3 ("powerpc/powernv: define a standard delay for OPAL_BUSY type retry loops") Cc: stable@vger.kernel.org # v3.2+ Signed-off-by: Nicholas Piggin Signed-off-by: Michael Ellerman Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/platforms/powernv/opal-nvram.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/arch/powerpc/platforms/powernv/opal-nvram.c b/arch/powerpc/platforms/powernv/opal-nvram.c index ba2ff06a2c98..1bceb95f422d 100644 --- a/arch/powerpc/platforms/powernv/opal-nvram.c +++ b/arch/powerpc/platforms/powernv/opal-nvram.c @@ -11,6 +11,7 @@ #define DEBUG +#include #include #include #include @@ -56,8 +57,12 @@ static ssize_t opal_nvram_write(char *buf, size_t count, loff_t *index) while (rc == OPAL_BUSY || rc == OPAL_BUSY_EVENT) { rc = opal_write_nvram(__pa(buf), count, off); - if (rc == OPAL_BUSY_EVENT) + if (rc == OPAL_BUSY_EVENT) { + msleep(OPAL_BUSY_DELAY_MS); opal_poll_events(NULL); + } else if (rc == OPAL_BUSY) { + msleep(OPAL_BUSY_DELAY_MS); + } } if (rc) -- GitLab From f671ac7a5317edddcc8d4593bae3ea1dde5334ed Mon Sep 17 00:00:00 2001 From: Aaron Ma Date: Sat, 3 Feb 2018 23:57:15 +0800 Subject: [PATCH 0691/1635] HID: Fix hid_report_len usage commit 3064a03b94e60388f0955fcc29f3e8a978d28f75 upstream. Follow the change of return type u32 of hid_report_len, fix all the types of variables those get the return value of hid_report_len to u32, and all other code already uses u32. Cc: stable@vger.kernel.org Signed-off-by: Aaron Ma Signed-off-by: Jiri Kosina Signed-off-by: Greg Kroah-Hartman --- drivers/hid/hid-input.c | 3 ++- drivers/hid/hid-multitouch.c | 5 +++-- drivers/hid/hid-rmi.c | 4 ++-- drivers/hid/wacom_sys.c | 4 ++-- 4 files changed, 9 insertions(+), 7 deletions(-) diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c index 199f6a01fc62..44f20aac018d 100644 --- a/drivers/hid/hid-input.c +++ b/drivers/hid/hid-input.c @@ -1359,7 +1359,8 @@ static void hidinput_led_worker(struct work_struct *work) led_work); struct hid_field *field; struct hid_report *report; - int len, ret; + int ret; + u32 len; __u8 *buf; field = hidinput_get_led_field(hid); diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c index 6598501c1ad0..c3b9bd5dba75 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c @@ -354,7 +354,8 @@ static const struct attribute_group mt_attribute_group = { static void mt_get_feature(struct hid_device *hdev, struct hid_report *report) { struct mt_device *td = hid_get_drvdata(hdev); - int ret, size = hid_report_len(report); + int ret; + u32 size = hid_report_len(report); u8 *buf; /* @@ -1049,7 +1050,7 @@ static void mt_set_input_mode(struct hid_device *hdev) struct hid_report_enum *re; struct mt_class *cls = &td->mtclass; char *buf; - int report_len; + u32 report_len; if (td->inputmode < 0) return; diff --git a/drivers/hid/hid-rmi.c b/drivers/hid/hid-rmi.c index ef241d66562e..cf5812188c37 100644 --- a/drivers/hid/hid-rmi.c +++ b/drivers/hid/hid-rmi.c @@ -89,8 +89,8 @@ struct rmi_data { u8 *writeReport; u8 *readReport; - int input_report_size; - int output_report_size; + u32 input_report_size; + u32 output_report_size; unsigned long flags; diff --git a/drivers/hid/wacom_sys.c b/drivers/hid/wacom_sys.c index 65f1cfbbe7fe..4c337585479e 100644 --- a/drivers/hid/wacom_sys.c +++ b/drivers/hid/wacom_sys.c @@ -115,7 +115,7 @@ static void wacom_feature_mapping(struct hid_device *hdev, unsigned int equivalent_usage = wacom_equivalent_usage(usage->hid); u8 *data; int ret; - int n; + u32 n; switch (equivalent_usage) { case HID_DG_CONTACTMAX: @@ -408,7 +408,7 @@ static int wacom_set_device_mode(struct hid_device *hdev, u8 *rep_data; struct hid_report *r; struct hid_report_enum *re; - int length; + u32 length; int error = -ENOMEM, limit = 0; if (wacom_wac->mode_report < 0) -- GitLab From 3f306336cdee80f830c46a768c08daf90a31e972 Mon Sep 17 00:00:00 2001 From: Aaron Ma Date: Mon, 8 Jan 2018 10:41:41 +0800 Subject: [PATCH 0692/1635] HID: core: Fix size as type u32 commit 6de0b13cc0b4ba10e98a9263d7a83b940720b77a upstream. When size is negative, calling memset will make segment fault. Declare the size as type u32 to keep memset safe. size in struct hid_report is unsigned, fix return type of hid_report_len to u32. Cc: stable@vger.kernel.org Signed-off-by: Aaron Ma Signed-off-by: Jiri Kosina Signed-off-by: Greg Kroah-Hartman --- drivers/hid/hid-core.c | 10 +++++----- include/linux/hid.h | 6 +++--- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index ca2fbe56635a..672b0be41d44 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1390,7 +1390,7 @@ u8 *hid_alloc_report_buf(struct hid_report *report, gfp_t flags) * of implement() working on 8 byte chunks */ - int len = hid_report_len(report) + 7; + u32 len = hid_report_len(report) + 7; return kmalloc(len, flags); } @@ -1455,7 +1455,7 @@ void __hid_request(struct hid_device *hid, struct hid_report *report, { char *buf; int ret; - int len; + u32 len; buf = hid_alloc_report_buf(report, GFP_KERNEL); if (!buf) @@ -1481,14 +1481,14 @@ void __hid_request(struct hid_device *hid, struct hid_report *report, } EXPORT_SYMBOL_GPL(__hid_request); -int hid_report_raw_event(struct hid_device *hid, int type, u8 *data, int size, +int hid_report_raw_event(struct hid_device *hid, int type, u8 *data, u32 size, int interrupt) { struct hid_report_enum *report_enum = hid->report_enum + type; struct hid_report *report; struct hid_driver *hdrv; unsigned int a; - int rsize, csize = size; + u32 rsize, csize = size; u8 *cdata = data; int ret = 0; @@ -1546,7 +1546,7 @@ EXPORT_SYMBOL_GPL(hid_report_raw_event); * * This is data entry for lower layers. */ -int hid_input_report(struct hid_device *hid, int type, u8 *data, int size, int interrupt) +int hid_input_report(struct hid_device *hid, int type, u8 *data, u32 size, int interrupt) { struct hid_report_enum *report_enum; struct hid_driver *hdrv; diff --git a/include/linux/hid.h b/include/linux/hid.h index ab05a86269dc..7f7c72d405ba 100644 --- a/include/linux/hid.h +++ b/include/linux/hid.h @@ -839,7 +839,7 @@ extern int hidinput_connect(struct hid_device *hid, unsigned int force); extern void hidinput_disconnect(struct hid_device *); int hid_set_field(struct hid_field *, unsigned, __s32); -int hid_input_report(struct hid_device *, int type, u8 *, int, int); +int hid_input_report(struct hid_device *, int type, u8 *, u32, int); int hidinput_find_field(struct hid_device *hid, unsigned int type, unsigned int code, struct hid_field **field); struct hid_field *hidinput_get_led_field(struct hid_device *hid); unsigned int hidinput_count_leds(struct hid_device *hid); @@ -1086,13 +1086,13 @@ static inline void hid_hw_wait(struct hid_device *hdev) * * @report: the report we want to know the length */ -static inline int hid_report_len(struct hid_report *report) +static inline u32 hid_report_len(struct hid_report *report) { /* equivalent to DIV_ROUND_UP(report->size, 8) + !!(report->id > 0) */ return ((report->size - 1) >> 3) + 1 + (report->id > 0); } -int hid_report_raw_event(struct hid_device *hid, int type, u8 *data, int size, +int hid_report_raw_event(struct hid_device *hid, int type, u8 *data, u32 size, int interrupt); /* HID quirks API */ -- GitLab From 1b3d2e7a34095edb8ff104961bdc403f8d36e405 Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Fri, 9 Feb 2018 02:07:59 +0800 Subject: [PATCH 0693/1635] soc: mediatek: fix the mistaken pointer accessed when subdomains are added commit 73ce2ce129783813e1ebc37d2c757fe5e0fab1ef upstream. Fix the pointer to struct scp_subdomian not being moved forward when each sub-domain is expected to be iteratively added through pm_genpd_add_subdomain call. Cc: stable@vger.kernel.org Fixes: 53fddb1a66dd ("soc: mediatek: reduce code duplication of scpsys_probe across all SoCs") Reported-by: Weiyi Lu Signed-off-by: Sean Wang Signed-off-by: Matthias Brugger Signed-off-by: Greg Kroah-Hartman --- drivers/soc/mediatek/mtk-scpsys.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/soc/mediatek/mtk-scpsys.c b/drivers/soc/mediatek/mtk-scpsys.c index e1ce8b1b5090..fb2a8b1e7979 100644 --- a/drivers/soc/mediatek/mtk-scpsys.c +++ b/drivers/soc/mediatek/mtk-scpsys.c @@ -892,7 +892,7 @@ static int scpsys_probe(struct platform_device *pdev) pd_data = &scp->pd_data; - for (i = 0, sd = soc->subdomains ; i < soc->num_subdomains ; i++) { + for (i = 0, sd = soc->subdomains; i < soc->num_subdomains; i++, sd++) { ret = pm_genpd_add_subdomain(pd_data->domains[sd->origin], pd_data->domains[sd->subdomain]); if (ret && IS_ENABLED(CONFIG_PM)) -- GitLab From 7e23ef535073ef8e1684f7b6e967b55dab055bd0 Mon Sep 17 00:00:00 2001 From: James Kelly Date: Mon, 19 Mar 2018 21:29:50 +1100 Subject: [PATCH 0694/1635] ASoC: ssm2602: Replace reg_default_raw with reg_default commit a01df75ce737951ad13a08d101306e88c3f57cb2 upstream. SSM2602 driver is broken on recent kernels (at least since 4.9). User space applications such as amixer or alsamixer get EIO when attempting to access codec controls via the relevant IOCTLs. Root cause of these failures is the regcache_hw_init function in drivers/base/regmap/regcache.c, which prevents regmap cache initalization from the reg_defaults_raw element of the regmap_config structure when registers are write only. It also disables the regmap cache entirely when all registers are write only or volatile as is the case for the SSM2602 driver. Using the reg_defaults element of the regmap_config structure rather than the reg_defaults_raw element to initalize the regmap cache avoids the logic in the regcache_hw_init function entirely. It also makes this driver consistent with other ASoC codec drivers, as this driver was the ONLY codec driver that used the reg_defaults_raw element to initalize the cache. Tested on Digilent Zybo Z7 development board which has a SSM2603 codec chip connected to a Xilinx Zynq SoC. Signed-off-by: James Kelly Signed-off-by: Mark Brown Cc: stable@vger.kernel.org Signed-off-by: Greg Kroah-Hartman --- sound/soc/codecs/ssm2602.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/sound/soc/codecs/ssm2602.c b/sound/soc/codecs/ssm2602.c index 9b341c23f62b..5e80867d09ef 100644 --- a/sound/soc/codecs/ssm2602.c +++ b/sound/soc/codecs/ssm2602.c @@ -54,10 +54,17 @@ struct ssm2602_priv { * using 2 wire for device control, so we cache them instead. * There is no point in caching the reset register */ -static const u16 ssm2602_reg[SSM2602_CACHEREGNUM] = { - 0x0097, 0x0097, 0x0079, 0x0079, - 0x000a, 0x0008, 0x009f, 0x000a, - 0x0000, 0x0000 +static const struct reg_default ssm2602_reg[SSM2602_CACHEREGNUM] = { + { .reg = 0x00, .def = 0x0097 }, + { .reg = 0x01, .def = 0x0097 }, + { .reg = 0x02, .def = 0x0079 }, + { .reg = 0x03, .def = 0x0079 }, + { .reg = 0x04, .def = 0x000a }, + { .reg = 0x05, .def = 0x0008 }, + { .reg = 0x06, .def = 0x009f }, + { .reg = 0x07, .def = 0x000a }, + { .reg = 0x08, .def = 0x0000 }, + { .reg = 0x09, .def = 0x0000 } }; @@ -620,8 +627,8 @@ const struct regmap_config ssm2602_regmap_config = { .volatile_reg = ssm2602_register_volatile, .cache_type = REGCACHE_RBTREE, - .reg_defaults_raw = ssm2602_reg, - .num_reg_defaults_raw = ARRAY_SIZE(ssm2602_reg), + .reg_defaults = ssm2602_reg, + .num_reg_defaults = ARRAY_SIZE(ssm2602_reg), }; EXPORT_SYMBOL_GPL(ssm2602_regmap_config); -- GitLab From 73b969f6a92062a5c1547541a2608d1755a7954b Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Tue, 27 Mar 2018 12:04:04 +0100 Subject: [PATCH 0695/1635] ASoC: topology: Fix kcontrol name string handling commit 267e2c6fd7ca3d4076d20f9d52d49dc91addfe9d upstream. Fix the topology kcontrol string handling so that string pointer references are strdup()ed instead of being copied. This fixes issues with kcontrol templates on the stack or ones that are freed. Remember and free the strings too when topology is unloaded. Signed-off-by: Liam Girdwood Signed-off-by: Mark Brown Cc: stable@vger.kernel.org Signed-off-by: Greg Kroah-Hartman --- sound/soc/soc-topology.c | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index 01a50413c66f..782c580b7aa3 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -523,6 +523,7 @@ static void remove_widget(struct snd_soc_component *comp, kfree(se->dobj.control.dtexts[j]); kfree(se); + kfree(w->kcontrol_news[i].name); } kfree(w->kcontrol_news); } else { @@ -540,6 +541,7 @@ static void remove_widget(struct snd_soc_component *comp, */ kfree((void *)kcontrol->private_value); snd_ctl_remove(card, kcontrol); + kfree(w->kcontrol_news[i].name); } kfree(w->kcontrol_news); } @@ -1233,7 +1235,9 @@ static struct snd_kcontrol_new *soc_tplg_dapm_widget_dmixer_create( dev_dbg(tplg->dev, " adding DAPM widget mixer control %s at %d\n", mc->hdr.name, i); - kc[i].name = mc->hdr.name; + kc[i].name = kstrdup(mc->hdr.name, GFP_KERNEL); + if (kc[i].name == NULL) + goto err_str; kc[i].private_value = (long)sm; kc[i].iface = SNDRV_CTL_ELEM_IFACE_MIXER; kc[i].access = mc->hdr.access; @@ -1278,8 +1282,10 @@ static struct snd_kcontrol_new *soc_tplg_dapm_widget_dmixer_create( err_str: kfree(sm); err: - for (--i; i >= 0; i--) + for (--i; i >= 0; i--) { kfree((void *)kc[i].private_value); + kfree(kc[i].name); + } kfree(kc); return NULL; } @@ -1310,7 +1316,9 @@ static struct snd_kcontrol_new *soc_tplg_dapm_widget_denum_create( dev_dbg(tplg->dev, " adding DAPM widget enum control %s\n", ec->hdr.name); - kc[i].name = ec->hdr.name; + kc[i].name = kstrdup(ec->hdr.name, GFP_KERNEL); + if (kc[i].name == NULL) + goto err_se; kc[i].private_value = (long)se; kc[i].iface = SNDRV_CTL_ELEM_IFACE_MIXER; kc[i].access = ec->hdr.access; @@ -1386,6 +1394,7 @@ static struct snd_kcontrol_new *soc_tplg_dapm_widget_denum_create( kfree(se->dobj.control.dtexts[j]); kfree(se); + kfree(kc[i].name); } err: kfree(kc); @@ -1424,7 +1433,9 @@ static struct snd_kcontrol_new *soc_tplg_dapm_widget_dbytes_create( "ASoC: adding bytes kcontrol %s with access 0x%x\n", be->hdr.name, be->hdr.access); - kc[i].name = be->hdr.name; + kc[i].name = kstrdup(be->hdr.name, GFP_KERNEL); + if (kc[i].name == NULL) + goto err; kc[i].private_value = (long)sbe; kc[i].iface = SNDRV_CTL_ELEM_IFACE_MIXER; kc[i].access = be->hdr.access; @@ -1454,8 +1465,10 @@ static struct snd_kcontrol_new *soc_tplg_dapm_widget_dbytes_create( return kc; err: - for (--i; i >= 0; i--) + for (--i; i >= 0; i--) { kfree((void *)kc[i].private_value); + kfree(kc[i].name); + } kfree(kc); return NULL; -- GitLab From 6f40f6ee22b91c913b2891c26943eb37bfceb50a Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Fri, 24 Nov 2017 17:51:12 +0300 Subject: [PATCH 0696/1635] thunderbolt: Wait a bit longer for ICM to authenticate the active NVM commit e4be8c9b6a512e274cb6bbac4ac869d73880a8b3 upstream. Sometimes during cold boot ICM has not yet authenticated the active NVM image leading to timeout and failing the driver probe. Allow ICM to take some more time and increase the timeout to 3 seconds before we give up. While there fix icm_firmware_init() to return the real error code without overwriting it with -ENODEV. Fixes: f67cf491175a ("thunderbolt: Add support for Internal Connection Manager (ICM)") Signed-off-by: Mika Westerberg Reviewed-by: Andy Shevchenko Cc: stable@vger.kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/thunderbolt/icm.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/thunderbolt/icm.c b/drivers/thunderbolt/icm.c index 53250fc057e1..7533984381a9 100644 --- a/drivers/thunderbolt/icm.c +++ b/drivers/thunderbolt/icm.c @@ -539,14 +539,14 @@ static bool icm_ar_is_supported(struct tb *tb) static int icm_ar_get_mode(struct tb *tb) { struct tb_nhi *nhi = tb->nhi; - int retries = 5; + int retries = 60; u32 val; do { val = ioread32(nhi->iobase + REG_FW_STS); if (val & REG_FW_STS_NVM_AUTH_DONE) break; - msleep(30); + msleep(50); } while (--retries); if (!retries) { @@ -859,6 +859,9 @@ static int icm_firmware_init(struct tb *tb) break; default: + if (ret < 0) + return ret; + tb_err(tb, "ICM firmware is in wrong mode: %u\n", ret); return -ENODEV; } -- GitLab From 7a4a66c504fbfae4428ac7a3784ee5017ae28682 Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Thu, 18 Jan 2018 20:27:47 +0300 Subject: [PATCH 0697/1635] thunderbolt: Serialize PCIe tunnel creation with PCI rescan commit a03e828915c00ed0ea5aa40647c81472cfa7a984 upstream. We need to make sure a new PCIe tunnel is not created in a middle of previous PCI rescan because otherwise the rescan code might find too much and fail to reconfigure devices properly. This is important when native PCIe hotplug is used. In BIOS assisted hotplug there should be no such issue. Fixes: f67cf491175a ("thunderbolt: Add support for Internal Connection Manager (ICM)") Signed-off-by: Mika Westerberg Reviewed-by: Andy Shevchenko Cc: Bjorn Helgaas Cc: stable@vger.kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/thunderbolt/switch.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/thunderbolt/switch.c b/drivers/thunderbolt/switch.c index 3953d17202a8..8bd137109980 100644 --- a/drivers/thunderbolt/switch.c +++ b/drivers/thunderbolt/switch.c @@ -716,6 +716,13 @@ static int tb_switch_set_authorized(struct tb_switch *sw, unsigned int val) if (sw->authorized) goto unlock; + /* + * Make sure there is no PCIe rescan ongoing when a new PCIe + * tunnel is created. Otherwise the PCIe rescan code might find + * the new tunnel too early. + */ + pci_lock_rescan_remove(); + switch (val) { /* Approve switch */ case 1: @@ -735,6 +742,8 @@ static int tb_switch_set_authorized(struct tb_switch *sw, unsigned int val) break; } + pci_unlock_rescan_remove(); + if (!ret) { sw->authorized = val; /* Notify status change to the userspace */ -- GitLab From 5ae695df59e1c3519b36d31671ac01697b606240 Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Tue, 19 Dec 2017 12:44:56 +0300 Subject: [PATCH 0698/1635] thunderbolt: Resume control channel after hibernation image is created commit f2a659f7d8d5da803836583aa16df06bdf324252 upstream. The driver misses implementation of PM hook that undoes what ->freeze_noirq() does after the hibernation image is created. This means the control channel is not resumed properly and the Thunderbolt bus becomes useless in later stages of hibernation (when the image is stored or if the operation fails). Fix this by pointing ->thaw_noirq to driver nhi_resume_noirq(). This makes sure the control channel is resumed properly. Fixes: 23dd5bb49d98 ("thunderbolt: Add suspend/hibernate support") Signed-off-by: Mika Westerberg Reviewed-by: Andy Shevchenko Cc: stable@vger.kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/thunderbolt/nhi.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/thunderbolt/nhi.c b/drivers/thunderbolt/nhi.c index 05af126a2435..16c607075ede 100644 --- a/drivers/thunderbolt/nhi.c +++ b/drivers/thunderbolt/nhi.c @@ -846,6 +846,7 @@ static const struct dev_pm_ops nhi_pm_ops = { * we just disable hotplug, the * pci-tunnels stay alive. */ + .thaw_noirq = nhi_resume_noirq, .restore_noirq = nhi_resume_noirq, .suspend = nhi_suspend, .freeze = nhi_suspend, -- GitLab From 2836377857633db5a7d93106fad90a642e296eec Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Fri, 9 Mar 2018 13:17:01 +0300 Subject: [PATCH 0699/1635] thunderbolt: Prevent crash when ICM firmware is not running commit ea9d7bb798900096f26c585957d6ad9c532417e6 upstream. On Lenovo ThinkPad Yoga 370 (and possibly some other Lenovo models as well) the Thunderbolt host controller sometimes comes up in such way that the ICM firmware is not running properly. This is most likely an issue in BIOS/firmware but as side-effect driver crashes the kernel due to NULL pointer dereference: BUG: unable to handle kernel NULL pointer dereference at 0000000000000980 IP: pci_write_config_dword+0x5/0x20 Call Trace: pcie2cio_write+0x3b/0x70 [thunderbolt] icm_driver_ready+0x168/0x260 [thunderbolt] ? tb_ctl_start+0x50/0x70 [thunderbolt] tb_domain_add+0x73/0xf0 [thunderbolt] nhi_probe+0x182/0x300 [thunderbolt] local_pci_probe+0x42/0xa0 ? pci_match_device+0xd9/0x100 pci_device_probe+0x146/0x1b0 driver_probe_device+0x315/0x480 ... Instead of crashing update the driver to bail out gracefully if we encounter such situation. Fixes: f67cf491175a ("thunderbolt: Add support for Internal Connection Manager (ICM)") Reported-by: Jordan Glover Signed-off-by: Mika Westerberg Acked-by: Yehezkel Bernat Cc: stable@vger.kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/thunderbolt/icm.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/thunderbolt/icm.c b/drivers/thunderbolt/icm.c index 7533984381a9..91830b1bdcaf 100644 --- a/drivers/thunderbolt/icm.c +++ b/drivers/thunderbolt/icm.c @@ -720,6 +720,9 @@ static int icm_firmware_reset(struct tb *tb, struct tb_nhi *nhi) struct icm *icm = tb_priv(tb); u32 val; + if (!icm->upstream_port) + return -ENODEV; + /* Put ARC to wait for CIO reset event to happen */ val = ioread32(nhi->iobase + REG_FW_STS); val |= REG_FW_STS_CIO_RESET_REQ; -- GitLab From 439e8b2dcab1963d077af193ebdabb586b8e14be Mon Sep 17 00:00:00 2001 From: Aniruddha Banerjee Date: Wed, 28 Mar 2018 19:12:00 +0530 Subject: [PATCH 0700/1635] irqchip/gic: Take lock when updating irq type commit aa08192a254d362a4d5317647a81de6996961aef upstream. Most MMIO GIC register accesses use a 1-hot bit scheme that avoids requiring any form of locking. This isn't true for the GICD_ICFGRn registers, which require a RMW sequence. Unfortunately, we seem to be missing a lock for these particular accesses, which could result in a race condition if changing the trigger type on any two interrupts within the same set of 16 interrupts (and thus controlled by the same CFGR register). Introduce a private lock in the GIC common comde for this particular case, making it cover both GIC implementations in one go. Cc: stable@vger.kernel.org Signed-off-by: Aniruddha Banerjee [maz: updated changelog] Signed-off-by: Marc Zyngier Signed-off-by: Greg Kroah-Hartman --- drivers/irqchip/irq-gic-common.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/irqchip/irq-gic-common.c b/drivers/irqchip/irq-gic-common.c index 9ae71804b5dd..1c2ca8d51a70 100644 --- a/drivers/irqchip/irq-gic-common.c +++ b/drivers/irqchip/irq-gic-common.c @@ -21,6 +21,8 @@ #include "irq-gic-common.h" +static DEFINE_RAW_SPINLOCK(irq_controller_lock); + static const struct gic_kvm_info *gic_kvm_info; const struct gic_kvm_info *gic_get_kvm_info(void) @@ -52,11 +54,13 @@ int gic_configure_irq(unsigned int irq, unsigned int type, u32 confoff = (irq / 16) * 4; u32 val, oldval; int ret = 0; + unsigned long flags; /* * Read current configuration register, and insert the config * for "irq", depending on "type". */ + raw_spin_lock_irqsave(&irq_controller_lock, flags); val = oldval = readl_relaxed(base + GIC_DIST_CONFIG + confoff); if (type & IRQ_TYPE_LEVEL_MASK) val &= ~confmask; @@ -64,8 +68,10 @@ int gic_configure_irq(unsigned int irq, unsigned int type, val |= confmask; /* If the current configuration is the same, then we are done */ - if (val == oldval) + if (val == oldval) { + raw_spin_unlock_irqrestore(&irq_controller_lock, flags); return 0; + } /* * Write back the new configuration, and possibly re-enable @@ -83,6 +89,7 @@ int gic_configure_irq(unsigned int irq, unsigned int type, pr_warn("GIC: PPI%d is secure or misconfigured\n", irq - 16); } + raw_spin_unlock_irqrestore(&irq_controller_lock, flags); if (sync_access) sync_access(); -- GitLab From b0afd9d1cb5aeb116edaaf967321444b588849cf Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Sat, 25 Feb 2017 18:21:33 -0400 Subject: [PATCH 0701/1635] random: use a tighter cap in credit_entropy_bits_safe() commit 9f886f4d1d292442b2f22a0a33321eae821bde40 upstream. This fixes a harmless UBSAN where root could potentially end up causing an overflow while bumping the entropy_total field (which is ignored once the entropy pool has been initialized, and this generally is completed during the boot sequence). This is marginal for the stable kernel series, but it's a really trivial patch, and it fixes UBSAN warning that might cause security folks to get overly excited for no reason. Signed-off-by: Theodore Ts'o Reported-by: Chen Feng Cc: stable@vger.kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/char/random.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/char/random.c b/drivers/char/random.c index ea0115cf5fc0..e88a5c61eaa1 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -732,7 +732,7 @@ static void credit_entropy_bits(struct entropy_store *r, int nbits) static int credit_entropy_bits_safe(struct entropy_store *r, int nbits) { - const int nbits_max = (int)(~0U >> (ENTROPY_SHIFT + 1)); + const int nbits_max = r->poolinfo->poolwords * 32; if (nbits < 0) return -EINVAL; -- GitLab From 7044bf9ef6c87cb49c71a9aa1f219e6a1cce5148 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Mon, 19 Feb 2018 14:20:46 +0100 Subject: [PATCH 0702/1635] extcon: intel-cht-wc: Set direction and drv flags for V5 boost GPIO commit ad49aee401dd1997ec71360df6e51a91ad3cf516 upstream. Sometimes (firmware bug?) the V5 boost GPIO is not configured as output by the BIOS, leading to the 5V boost convertor being permanently on, Explicitly set the direction and drv flags rather then inheriting them from the firmware to fix this. Fixes: 585cb239f4de ("extcon: intel-cht-wc: Disable external 5v boost ...") Cc: stable@vger.kernel.org Reviewed-by: Andy Shevchenko Signed-off-by: Hans de Goede Signed-off-by: Chanwoo Choi Signed-off-by: Greg Kroah-Hartman --- drivers/extcon/extcon-intel-cht-wc.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/extcon/extcon-intel-cht-wc.c b/drivers/extcon/extcon-intel-cht-wc.c index 91a0023074af..60baaf693103 100644 --- a/drivers/extcon/extcon-intel-cht-wc.c +++ b/drivers/extcon/extcon-intel-cht-wc.c @@ -66,6 +66,8 @@ #define CHT_WC_VBUS_GPIO_CTLO 0x6e2d #define CHT_WC_VBUS_GPIO_CTLO_OUTPUT BIT(0) +#define CHT_WC_VBUS_GPIO_CTLO_DRV_OD BIT(4) +#define CHT_WC_VBUS_GPIO_CTLO_DIR_OUT BIT(5) enum cht_wc_usb_id { USB_ID_OTG, @@ -183,14 +185,15 @@ static void cht_wc_extcon_set_5v_boost(struct cht_wc_extcon_data *ext, { int ret, val; - val = enable ? CHT_WC_VBUS_GPIO_CTLO_OUTPUT : 0; - /* * The 5V boost converter is enabled through a gpio on the PMIC, since * there currently is no gpio driver we access the gpio reg directly. */ - ret = regmap_update_bits(ext->regmap, CHT_WC_VBUS_GPIO_CTLO, - CHT_WC_VBUS_GPIO_CTLO_OUTPUT, val); + val = CHT_WC_VBUS_GPIO_CTLO_DRV_OD | CHT_WC_VBUS_GPIO_CTLO_DIR_OUT; + if (enable) + val |= CHT_WC_VBUS_GPIO_CTLO_OUTPUT; + + ret = regmap_write(ext->regmap, CHT_WC_VBUS_GPIO_CTLO, val); if (ret) dev_err(ext->dev, "Error writing Vbus GPIO CTLO: %d\n", ret); } -- GitLab From 6151a5a45fc42271493c8805b533d8349954b130 Mon Sep 17 00:00:00 2001 From: Mikulas Patocka Date: Wed, 21 Mar 2018 12:42:25 -0400 Subject: [PATCH 0703/1635] block: use 32-bit blk_status_t on Alpha commit 6e2fb22103b99c26ae30a46512abe75526d8e4c9 upstream. Early alpha processors cannot write a single byte or word; they read 8 bytes, modify the value in registers and write back 8 bytes. The type blk_status_t is defined as one byte, it is often written asynchronously by I/O completion routines, this asynchronous modification can corrupt content of nearby bytes if these nearby bytes can be written simultaneously by another CPU. - one example of such corruption is the structure dm_io where "blk_status_t status" is written by an asynchronous completion routine and "atomic_t io_count" is modified synchronously - another example is the structure dm_buffer where "unsigned hold_count" is modified synchronously from process context and "blk_status_t write_error" is modified asynchronously from bio completion routine This patch fixes the bug by changing the type blk_status_t to 32 bits if we are on Alpha and if we are compiling for a processor that doesn't have the byte-word-extension. Signed-off-by: Mikulas Patocka Cc: stable@vger.kernel.org # 4.13+ Signed-off-by: Jens Axboe Signed-off-by: Greg Kroah-Hartman --- include/linux/blk_types.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/include/linux/blk_types.h b/include/linux/blk_types.h index 1c8a8a2aedf7..91072b68dc38 100644 --- a/include/linux/blk_types.h +++ b/include/linux/blk_types.h @@ -20,8 +20,13 @@ typedef void (bio_end_io_t) (struct bio *); /* * Block error status values. See block/blk-core:blk_errors for the details. + * Alpha cannot write a byte atomically, so we need to use 32-bit value. */ +#if defined(CONFIG_ALPHA) && !defined(__alpha_bwx__) +typedef u32 __bitwise blk_status_t; +#else typedef u8 __bitwise blk_status_t; +#endif #define BLK_STS_OK 0 #define BLK_STS_NOTSUPP ((__force blk_status_t)1) #define BLK_STS_TIMEOUT ((__force blk_status_t)2) -- GitLab From 867175f944857448b83cad1370e532a1ffda9e47 Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Mon, 19 Feb 2018 12:22:53 -0500 Subject: [PATCH 0704/1635] jbd2: if the journal is aborted then don't allow update of the log tail commit 85e0c4e89c1b864e763c4e3bb15d0b6d501ad5d9 upstream. This updates the jbd2 superblock unnecessarily, and on an abort we shouldn't truncate the log. Signed-off-by: Theodore Ts'o Cc: stable@vger.kernel.org Signed-off-by: Greg Kroah-Hartman --- fs/jbd2/journal.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/fs/jbd2/journal.c b/fs/jbd2/journal.c index 7d5ef3bf3f3e..aeaa993d4849 100644 --- a/fs/jbd2/journal.c +++ b/fs/jbd2/journal.c @@ -961,7 +961,7 @@ int __jbd2_update_log_tail(journal_t *journal, tid_t tid, unsigned long block) } /* - * This is a variaon of __jbd2_update_log_tail which checks for validity of + * This is a variation of __jbd2_update_log_tail which checks for validity of * provided log tail and locks j_checkpoint_mutex. So it is safe against races * with other threads updating log tail. */ @@ -1404,6 +1404,9 @@ int jbd2_journal_update_sb_log_tail(journal_t *journal, tid_t tail_tid, journal_superblock_t *sb = journal->j_superblock; int ret; + if (is_journal_aborted(journal)) + return -EIO; + BUG_ON(!mutex_is_locked(&journal->j_checkpoint_mutex)); jbd_debug(1, "JBD2: updating superblock (start %lu, seq %u)\n", tail_block, tail_tid); -- GitLab From 7ebcea25968219b4ed9b27e5708e2b96c1718d86 Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Sun, 18 Feb 2018 22:07:36 -0500 Subject: [PATCH 0705/1635] ext4: shutdown should not prevent get_write_access commit 576d18ed60f5465110087c5e0eb1010de13e374d upstream. The ext4 forced shutdown flag needs to prevent new handles from being started, but it needs to allow existing handles to complete. So the forced shutdown flag should not force ext4_journal_get_write_access to fail. Signed-off-by: Theodore Ts'o Cc: stable@vger.kernel.org Signed-off-by: Greg Kroah-Hartman --- fs/ext4/ext4_jbd2.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/fs/ext4/ext4_jbd2.c b/fs/ext4/ext4_jbd2.c index 2d593201cf7a..7c70b08d104c 100644 --- a/fs/ext4/ext4_jbd2.c +++ b/fs/ext4/ext4_jbd2.c @@ -166,13 +166,6 @@ int __ext4_journal_get_write_access(const char *where, unsigned int line, might_sleep(); if (ext4_handle_valid(handle)) { - struct super_block *sb; - - sb = handle->h_transaction->t_journal->j_private; - if (unlikely(ext4_forced_shutdown(EXT4_SB(sb)))) { - jbd2_journal_abort_handle(handle); - return -EIO; - } err = jbd2_journal_get_write_access(handle, bh); if (err) ext4_journal_abort_handle(where, line, __func__, bh, -- GitLab From 09439481998aefbe1bd6ae067079e738ba4a7a3f Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Sun, 18 Feb 2018 23:16:28 -0500 Subject: [PATCH 0706/1635] ext4: eliminate sleep from shutdown ioctl commit a6d9946bb925293fda9f5ed6d33d8580b001f006 upstream. The msleep() when processing EXT4_GOING_FLAGS_NOLOGFLUSH was a hack to avoid some races (that are now fixed), but in fact it introduced its own race. Signed-off-by: Theodore Ts'o Cc: stable@vger.kernel.org Signed-off-by: Greg Kroah-Hartman --- fs/ext4/ioctl.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/fs/ext4/ioctl.c b/fs/ext4/ioctl.c index d97f40396765..7f889b1e4db0 100644 --- a/fs/ext4/ioctl.c +++ b/fs/ext4/ioctl.c @@ -498,10 +498,8 @@ static int ext4_shutdown(struct super_block *sb, unsigned long arg) break; case EXT4_GOING_FLAGS_NOLOGFLUSH: set_bit(EXT4_FLAGS_SHUTDOWN, &sbi->s_ext4_flags); - if (sbi->s_journal && !is_journal_aborted(sbi->s_journal)) { - msleep(100); + if (sbi->s_journal && !is_journal_aborted(sbi->s_journal)) jbd2_journal_abort(sbi->s_journal, 0); - } break; default: return -EINVAL; -- GitLab From 73297f13a003b97e37a5648bbbecd45323cc0e24 Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Sun, 18 Feb 2018 23:45:18 -0500 Subject: [PATCH 0707/1635] ext4: pass -ESHUTDOWN code to jbd2 layer commit fb7c02445c497943e7296cd3deee04422b63acb8 upstream. Previously the jbd2 layer assumed that a file system check would be required after a journal abort. In the case of the deliberate file system shutdown, this should not be necessary. Allow the jbd2 layer to distinguish between these two cases by using the ESHUTDOWN errno. Also add proper locking to __journal_abort_soft(). Signed-off-by: Theodore Ts'o Cc: stable@vger.kernel.org Signed-off-by: Greg Kroah-Hartman --- fs/ext4/ioctl.c | 4 ++-- fs/jbd2/journal.c | 25 +++++++++++++++++++------ 2 files changed, 21 insertions(+), 8 deletions(-) diff --git a/fs/ext4/ioctl.c b/fs/ext4/ioctl.c index 7f889b1e4db0..1eb68e626931 100644 --- a/fs/ext4/ioctl.c +++ b/fs/ext4/ioctl.c @@ -493,13 +493,13 @@ static int ext4_shutdown(struct super_block *sb, unsigned long arg) set_bit(EXT4_FLAGS_SHUTDOWN, &sbi->s_ext4_flags); if (sbi->s_journal && !is_journal_aborted(sbi->s_journal)) { (void) ext4_force_commit(sb); - jbd2_journal_abort(sbi->s_journal, 0); + jbd2_journal_abort(sbi->s_journal, -ESHUTDOWN); } break; case EXT4_GOING_FLAGS_NOLOGFLUSH: set_bit(EXT4_FLAGS_SHUTDOWN, &sbi->s_ext4_flags); if (sbi->s_journal && !is_journal_aborted(sbi->s_journal)) - jbd2_journal_abort(sbi->s_journal, 0); + jbd2_journal_abort(sbi->s_journal, -ESHUTDOWN); break; default: return -EINVAL; diff --git a/fs/jbd2/journal.c b/fs/jbd2/journal.c index aeaa993d4849..61d48f0c41a1 100644 --- a/fs/jbd2/journal.c +++ b/fs/jbd2/journal.c @@ -1473,12 +1473,15 @@ static void jbd2_mark_journal_empty(journal_t *journal, int write_op) void jbd2_journal_update_sb_errno(journal_t *journal) { journal_superblock_t *sb = journal->j_superblock; + int errcode; read_lock(&journal->j_state_lock); - jbd_debug(1, "JBD2: updating superblock error (errno %d)\n", - journal->j_errno); - sb->s_errno = cpu_to_be32(journal->j_errno); + errcode = journal->j_errno; read_unlock(&journal->j_state_lock); + if (errcode == -ESHUTDOWN) + errcode = 0; + jbd_debug(1, "JBD2: updating superblock error (errno %d)\n", errcode); + sb->s_errno = cpu_to_be32(errcode); jbd2_write_superblock(journal, REQ_SYNC | REQ_FUA); } @@ -2095,12 +2098,22 @@ void __jbd2_journal_abort_hard(journal_t *journal) * but don't do any other IO. */ static void __journal_abort_soft (journal_t *journal, int errno) { - if (journal->j_flags & JBD2_ABORT) - return; + int old_errno; - if (!journal->j_errno) + write_lock(&journal->j_state_lock); + old_errno = journal->j_errno; + if (!journal->j_errno || errno == -ESHUTDOWN) journal->j_errno = errno; + if (journal->j_flags & JBD2_ABORT) { + write_unlock(&journal->j_state_lock); + if (!old_errno && old_errno != -ESHUTDOWN && + errno == -ESHUTDOWN) + jbd2_journal_update_sb_errno(journal); + return; + } + write_unlock(&journal->j_state_lock); + __jbd2_journal_abort_hard(journal); if (errno) { -- GitLab From bd499f55384969d53c825fa7c3a0ae21c972c945 Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Mon, 19 Feb 2018 14:16:47 -0500 Subject: [PATCH 0708/1635] ext4: don't update checksum of new initialized bitmaps commit 044e6e3d74a3d7103a0c8a9305dfd94d64000660 upstream. When reading the inode or block allocation bitmap, if the bitmap needs to be initialized, do not update the checksum in the block group descriptor. That's because we're not set up to journal those changes. Instead, just set the verified bit on the bitmap block, so that it's not necessary to validate the checksum. When a block or inode allocation actually happens, at that point the checksum will be calculated, and update of the bg descriptor block will be properly journalled. Signed-off-by: Theodore Ts'o Cc: stable@vger.kernel.org Signed-off-by: Greg Kroah-Hartman --- fs/ext4/balloc.c | 3 +-- fs/ext4/ialloc.c | 47 +++-------------------------------------------- 2 files changed, 4 insertions(+), 46 deletions(-) diff --git a/fs/ext4/balloc.c b/fs/ext4/balloc.c index d5ddfb96c83c..db5be5e2e6f2 100644 --- a/fs/ext4/balloc.c +++ b/fs/ext4/balloc.c @@ -243,8 +243,6 @@ static int ext4_init_block_bitmap(struct super_block *sb, */ ext4_mark_bitmap_end(num_clusters_in_group(sb, block_group), sb->s_blocksize * 8, bh->b_data); - ext4_block_bitmap_csum_set(sb, block_group, gdp, bh); - ext4_group_desc_csum_set(sb, block_group, gdp); return 0; } @@ -448,6 +446,7 @@ ext4_read_block_bitmap_nowait(struct super_block *sb, ext4_group_t block_group) err = ext4_init_block_bitmap(sb, bh, block_group, desc); set_bitmap_uptodate(bh); set_buffer_uptodate(bh); + set_buffer_verified(bh); ext4_unlock_group(sb, block_group); unlock_buffer(bh); if (err) { diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c index 207588dc803e..7ec55dd8db56 100644 --- a/fs/ext4/ialloc.c +++ b/fs/ext4/ialloc.c @@ -66,44 +66,6 @@ void ext4_mark_bitmap_end(int start_bit, int end_bit, char *bitmap) memset(bitmap + (i >> 3), 0xff, (end_bit - i) >> 3); } -/* Initializes an uninitialized inode bitmap */ -static int ext4_init_inode_bitmap(struct super_block *sb, - struct buffer_head *bh, - ext4_group_t block_group, - struct ext4_group_desc *gdp) -{ - struct ext4_group_info *grp; - struct ext4_sb_info *sbi = EXT4_SB(sb); - J_ASSERT_BH(bh, buffer_locked(bh)); - - /* If checksum is bad mark all blocks and inodes use to prevent - * allocation, essentially implementing a per-group read-only flag. */ - if (!ext4_group_desc_csum_verify(sb, block_group, gdp)) { - grp = ext4_get_group_info(sb, block_group); - if (!EXT4_MB_GRP_BBITMAP_CORRUPT(grp)) - percpu_counter_sub(&sbi->s_freeclusters_counter, - grp->bb_free); - set_bit(EXT4_GROUP_INFO_BBITMAP_CORRUPT_BIT, &grp->bb_state); - if (!EXT4_MB_GRP_IBITMAP_CORRUPT(grp)) { - int count; - count = ext4_free_inodes_count(sb, gdp); - percpu_counter_sub(&sbi->s_freeinodes_counter, - count); - } - set_bit(EXT4_GROUP_INFO_IBITMAP_CORRUPT_BIT, &grp->bb_state); - return -EFSBADCRC; - } - - memset(bh->b_data, 0, (EXT4_INODES_PER_GROUP(sb) + 7) / 8); - ext4_mark_bitmap_end(EXT4_INODES_PER_GROUP(sb), sb->s_blocksize * 8, - bh->b_data); - ext4_inode_bitmap_csum_set(sb, block_group, gdp, bh, - EXT4_INODES_PER_GROUP(sb) / 8); - ext4_group_desc_csum_set(sb, block_group, gdp); - - return 0; -} - void ext4_end_bitmap_read(struct buffer_head *bh, int uptodate) { if (uptodate) { @@ -187,17 +149,14 @@ ext4_read_inode_bitmap(struct super_block *sb, ext4_group_t block_group) ext4_lock_group(sb, block_group); if (desc->bg_flags & cpu_to_le16(EXT4_BG_INODE_UNINIT)) { - err = ext4_init_inode_bitmap(sb, bh, block_group, desc); + memset(bh->b_data, 0, (EXT4_INODES_PER_GROUP(sb) + 7) / 8); + ext4_mark_bitmap_end(EXT4_INODES_PER_GROUP(sb), + sb->s_blocksize * 8, bh->b_data); set_bitmap_uptodate(bh); set_buffer_uptodate(bh); set_buffer_verified(bh); ext4_unlock_group(sb, block_group); unlock_buffer(bh); - if (err) { - ext4_error(sb, "Failed to init inode bitmap for group " - "%u: %d", block_group, err); - goto out; - } return bh; } ext4_unlock_group(sb, block_group); -- GitLab From 5058b70d2118ee0304a2f3124946c4089b06abde Mon Sep 17 00:00:00 2001 From: Eryu Guan Date: Thu, 22 Mar 2018 11:41:25 -0400 Subject: [PATCH 0709/1635] ext4: protect i_disksize update by i_data_sem in direct write path commit 73fdad00b208b139cf43f3163fbc0f67e4c6047c upstream. i_disksize update should be protected by i_data_sem, by either taking the lock explicitly or by using ext4_update_i_disksize() helper. But the i_disksize updates in ext4_direct_IO_write() are not protected at all, which may be racing with i_disksize updates in writeback path in delalloc buffer write path. This is found by code inspection, and I didn't hit any i_disksize corruption due to this bug. Thanks to Jan Kara for catching this bug and suggesting the fix! Reported-by: Jan Kara Suggested-by: Jan Kara Signed-off-by: Eryu Guan Signed-off-by: Theodore Ts'o Cc: stable@vger.kernel.org Signed-off-by: Greg Kroah-Hartman --- fs/ext4/inode.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index 0b9f3f284799..69f017e88e89 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -3614,7 +3614,6 @@ static ssize_t ext4_direct_IO_write(struct kiocb *iocb, struct iov_iter *iter) { struct file *file = iocb->ki_filp; struct inode *inode = file->f_mapping->host; - struct ext4_inode_info *ei = EXT4_I(inode); ssize_t ret; loff_t offset = iocb->ki_pos; size_t count = iov_iter_count(iter); @@ -3638,7 +3637,7 @@ static ssize_t ext4_direct_IO_write(struct kiocb *iocb, struct iov_iter *iter) goto out; } orphan = 1; - ei->i_disksize = inode->i_size; + ext4_update_i_disksize(inode, inode->i_size); ext4_journal_stop(handle); } @@ -3746,7 +3745,7 @@ static ssize_t ext4_direct_IO_write(struct kiocb *iocb, struct iov_iter *iter) if (ret > 0) { loff_t end = offset + ret; if (end > inode->i_size) { - ei->i_disksize = end; + ext4_update_i_disksize(inode, end); i_size_write(inode, end); /* * We're going to return a positive `ret' -- GitLab From a57eb14b740e6175aff8b8941bec628403992dfa Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Thu, 29 Mar 2018 14:31:42 -0400 Subject: [PATCH 0710/1635] ext4: limit xattr size to INT_MAX commit ce3fd194fcc6fbdc00ce095a852f22df97baa401 upstream. ext4 isn't validating the sizes of xattrs where the value of the xattr is stored in an external inode. This is problematic because ->e_value_size is a u32, but ext4_xattr_get() returns an int. A very large size is misinterpreted as an error code, which ext4_get_acl() translates into a bogus ERR_PTR() for which IS_ERR() returns false, causing a crash. Fix this by validating that all xattrs are <= INT_MAX bytes. This issue has been assigned CVE-2018-1095. https://bugzilla.kernel.org/show_bug.cgi?id=199185 https://bugzilla.redhat.com/show_bug.cgi?id=1560793 Reported-by: Wen Xu Signed-off-by: Eric Biggers Signed-off-by: Theodore Ts'o Cc: stable@vger.kernel.org Fixes: e50e5129f384 ("ext4: xattr-in-inode support") Signed-off-by: Greg Kroah-Hartman --- fs/ext4/xattr.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/fs/ext4/xattr.c b/fs/ext4/xattr.c index 218a7ba57819..5d0f5ba5c6f5 100644 --- a/fs/ext4/xattr.c +++ b/fs/ext4/xattr.c @@ -194,10 +194,13 @@ ext4_xattr_check_entries(struct ext4_xattr_entry *entry, void *end, /* Check the values */ while (!IS_LAST_ENTRY(entry)) { - if (entry->e_value_size != 0 && - entry->e_value_inum == 0) { + u32 size = le32_to_cpu(entry->e_value_size); + + if (size > INT_MAX) + return -EFSCORRUPTED; + + if (size != 0 && entry->e_value_inum == 0) { u16 offs = le16_to_cpu(entry->e_value_offs); - u32 size = le32_to_cpu(entry->e_value_size); void *value; /* -- GitLab From 8e0e94683f8449f4e83b4b563b80eb9c76b9e18f Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Thu, 29 Mar 2018 21:56:09 -0400 Subject: [PATCH 0711/1635] ext4: fail ext4_iget for root directory if unallocated commit 8e4b5eae5decd9dfe5a4ee369c22028f90ab4c44 upstream. If the root directory has an i_links_count of zero, then when the file system is mounted, then when ext4_fill_super() notices the problem and tries to call iput() the root directory in the error return path, ext4_evict_inode() will try to free the inode on disk, before all of the file system structures are set up, and this will result in an OOPS caused by a NULL pointer dereference. This issue has been assigned CVE-2018-1092. https://bugzilla.kernel.org/show_bug.cgi?id=199179 https://bugzilla.redhat.com/show_bug.cgi?id=1560777 Reported-by: Wen Xu Signed-off-by: Theodore Ts'o Cc: stable@vger.kernel.org Signed-off-by: Greg Kroah-Hartman --- fs/ext4/inode.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index 69f017e88e89..09014c3c4207 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -4685,6 +4685,12 @@ struct inode *ext4_iget(struct super_block *sb, unsigned long ino) goto bad_inode; raw_inode = ext4_raw_inode(&iloc); + if ((ino == EXT4_ROOT_INO) && (raw_inode->i_links_count == 0)) { + EXT4_ERROR_INODE(inode, "root inode unallocated"); + ret = -EFSCORRUPTED; + goto bad_inode; + } + if (EXT4_INODE_SIZE(inode->i_sb) > EXT4_GOOD_OLD_INODE_SIZE) { ei->i_extra_isize = le16_to_cpu(raw_inode->i_extra_isize); if (EXT4_GOOD_OLD_INODE_SIZE + ei->i_extra_isize > -- GitLab From 26dbb30c58ffb85bc015bd5e58831483d50f7d18 Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Thu, 29 Mar 2018 22:10:31 -0400 Subject: [PATCH 0712/1635] ext4: always initialize the crc32c checksum driver commit a45403b51582a87872927a3e0fc0a389c26867f1 upstream. The extended attribute code now uses the crc32c checksum for hashing purposes, so we should just always always initialize it. We also want to prevent NULL pointer dereferences if one of the metadata checksum features is enabled after the file sytsem is originally mounted. This issue has been assigned CVE-2018-1094. https://bugzilla.kernel.org/show_bug.cgi?id=199183 https://bugzilla.redhat.com/show_bug.cgi?id=1560788 Signed-off-by: Theodore Ts'o Cc: stable@vger.kernel.org Signed-off-by: Greg Kroah-Hartman --- fs/ext4/super.c | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 16d247f056e2..1339a79eb314 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -3490,15 +3490,12 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) } /* Load the checksum driver */ - if (ext4_has_feature_metadata_csum(sb) || - ext4_has_feature_ea_inode(sb)) { - sbi->s_chksum_driver = crypto_alloc_shash("crc32c", 0, 0); - if (IS_ERR(sbi->s_chksum_driver)) { - ext4_msg(sb, KERN_ERR, "Cannot load crc32c driver."); - ret = PTR_ERR(sbi->s_chksum_driver); - sbi->s_chksum_driver = NULL; - goto failed_mount; - } + sbi->s_chksum_driver = crypto_alloc_shash("crc32c", 0, 0); + if (IS_ERR(sbi->s_chksum_driver)) { + ext4_msg(sb, KERN_ERR, "Cannot load crc32c driver."); + ret = PTR_ERR(sbi->s_chksum_driver); + sbi->s_chksum_driver = NULL; + goto failed_mount; } /* Check superblock checksum */ -- GitLab From b2623d8166563a19bee0cc8292e4ec951a42a6da Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Thu, 29 Mar 2018 22:10:35 -0400 Subject: [PATCH 0713/1635] ext4: don't allow r/w mounts if metadata blocks overlap the superblock commit 18db4b4e6fc31eda838dd1c1296d67dbcb3dc957 upstream. If some metadata block, such as an allocation bitmap, overlaps the superblock, it's very likely that if the file system is mounted read/write, the results will not be pretty. So disallow r/w mounts for file systems corrupted in this particular way. Signed-off-by: Theodore Ts'o Cc: stable@vger.kernel.org Signed-off-by: Greg Kroah-Hartman --- fs/ext4/super.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 1339a79eb314..3a605c672649 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -2330,6 +2330,8 @@ static int ext4_check_descriptors(struct super_block *sb, ext4_msg(sb, KERN_ERR, "ext4_check_descriptors: " "Block bitmap for group %u overlaps " "superblock", i); + if (!sb_rdonly(sb)) + return 0; } if (block_bitmap < first_block || block_bitmap > last_block) { ext4_msg(sb, KERN_ERR, "ext4_check_descriptors: " @@ -2342,6 +2344,8 @@ static int ext4_check_descriptors(struct super_block *sb, ext4_msg(sb, KERN_ERR, "ext4_check_descriptors: " "Inode bitmap for group %u overlaps " "superblock", i); + if (!sb_rdonly(sb)) + return 0; } if (inode_bitmap < first_block || inode_bitmap > last_block) { ext4_msg(sb, KERN_ERR, "ext4_check_descriptors: " @@ -2354,6 +2358,8 @@ static int ext4_check_descriptors(struct super_block *sb, ext4_msg(sb, KERN_ERR, "ext4_check_descriptors: " "Inode table for group %u overlaps " "superblock", i); + if (!sb_rdonly(sb)) + return 0; } if (inode_table < first_block || inode_table + sbi->s_itb_per_group - 1 > last_block) { -- GitLab From 598e04ae2fc402c364d3f0ee76599783149f573f Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Fri, 30 Mar 2018 15:42:25 -0400 Subject: [PATCH 0714/1635] ext4: move call to ext4_error() into ext4_xattr_check_block() commit de05ca8526796c7e9f7c7282b7f89a818af19818 upstream. Refactor the call to EXT4_ERROR_INODE() into ext4_xattr_check_block(). This simplifies the code, and fixes a problem where not all callers of ext4_xattr_check_block() were not resulting in ext4_error() getting called when the xattr block is corrupted. Signed-off-by: Theodore Ts'o Cc: stable@vger.kernel.org Signed-off-by: Greg Kroah-Hartman --- fs/ext4/xattr.c | 60 ++++++++++++++++++++++--------------------------- 1 file changed, 27 insertions(+), 33 deletions(-) diff --git a/fs/ext4/xattr.c b/fs/ext4/xattr.c index 5d0f5ba5c6f5..4bc3217fa038 100644 --- a/fs/ext4/xattr.c +++ b/fs/ext4/xattr.c @@ -224,25 +224,36 @@ ext4_xattr_check_entries(struct ext4_xattr_entry *entry, void *end, } static inline int -ext4_xattr_check_block(struct inode *inode, struct buffer_head *bh) +__ext4_xattr_check_block(struct inode *inode, struct buffer_head *bh, + const char *function, unsigned int line) { - int error; + int error = -EFSCORRUPTED; if (buffer_verified(bh)) return 0; if (BHDR(bh)->h_magic != cpu_to_le32(EXT4_XATTR_MAGIC) || BHDR(bh)->h_blocks != cpu_to_le32(1)) - return -EFSCORRUPTED; + goto errout; + error = -EFSBADCRC; if (!ext4_xattr_block_csum_verify(inode, bh)) - return -EFSBADCRC; + goto errout; error = ext4_xattr_check_entries(BFIRST(bh), bh->b_data + bh->b_size, bh->b_data); - if (!error) +errout: + if (error) + __ext4_error_inode(inode, function, line, 0, + "corrupted xattr block %llu", + (unsigned long long) bh->b_blocknr); + else set_buffer_verified(bh); return error; } +#define ext4_xattr_check_block(inode, bh) \ + __ext4_xattr_check_block((inode), (bh), __func__, __LINE__) + + static int __xattr_check_inode(struct inode *inode, struct ext4_xattr_ibody_header *header, void *end, const char *function, unsigned int line) @@ -513,12 +524,9 @@ ext4_xattr_block_get(struct inode *inode, int name_index, const char *name, goto cleanup; ea_bdebug(bh, "b_count=%d, refcount=%d", atomic_read(&(bh->b_count)), le32_to_cpu(BHDR(bh)->h_refcount)); - if (ext4_xattr_check_block(inode, bh)) { - EXT4_ERROR_INODE(inode, "bad block %llu", - EXT4_I(inode)->i_file_acl); - error = -EFSCORRUPTED; + error = ext4_xattr_check_block(inode, bh); + if (error) goto cleanup; - } ext4_xattr_block_cache_insert(ea_block_cache, bh); entry = BFIRST(bh); error = ext4_xattr_find_entry(&entry, name_index, name, 1); @@ -678,12 +686,9 @@ ext4_xattr_block_list(struct dentry *dentry, char *buffer, size_t buffer_size) goto cleanup; ea_bdebug(bh, "b_count=%d, refcount=%d", atomic_read(&(bh->b_count)), le32_to_cpu(BHDR(bh)->h_refcount)); - if (ext4_xattr_check_block(inode, bh)) { - EXT4_ERROR_INODE(inode, "bad block %llu", - EXT4_I(inode)->i_file_acl); - error = -EFSCORRUPTED; + error = ext4_xattr_check_block(inode, bh); + if (error) goto cleanup; - } ext4_xattr_block_cache_insert(EA_BLOCK_CACHE(inode), bh); error = ext4_xattr_list_entries(dentry, BFIRST(bh), buffer, buffer_size); @@ -810,10 +815,9 @@ int ext4_get_inode_usage(struct inode *inode, qsize_t *usage) goto out; } - if (ext4_xattr_check_block(inode, bh)) { - ret = -EFSCORRUPTED; + ret = ext4_xattr_check_block(inode, bh); + if (ret) goto out; - } for (entry = BFIRST(bh); !IS_LAST_ENTRY(entry); entry = EXT4_XATTR_NEXT(entry)) @@ -1795,12 +1799,9 @@ ext4_xattr_block_find(struct inode *inode, struct ext4_xattr_info *i, ea_bdebug(bs->bh, "b_count=%d, refcount=%d", atomic_read(&(bs->bh->b_count)), le32_to_cpu(BHDR(bs->bh)->h_refcount)); - if (ext4_xattr_check_block(inode, bs->bh)) { - EXT4_ERROR_INODE(inode, "bad block %llu", - EXT4_I(inode)->i_file_acl); - error = -EFSCORRUPTED; + error = ext4_xattr_check_block(inode, bs->bh); + if (error) goto cleanup; - } /* Find the named attribute. */ bs->s.base = BHDR(bs->bh); bs->s.first = BFIRST(bs->bh); @@ -2723,13 +2724,9 @@ int ext4_expand_extra_isize_ea(struct inode *inode, int new_extra_isize, error = -EIO; if (!bh) goto cleanup; - if (ext4_xattr_check_block(inode, bh)) { - EXT4_ERROR_INODE(inode, "bad block %llu", - EXT4_I(inode)->i_file_acl); - error = -EFSCORRUPTED; - brelse(bh); + error = ext4_xattr_check_block(inode, bh); + if (error) goto cleanup; - } base = BHDR(bh); end = bh->b_data + bh->b_size; min_offs = end - base; @@ -2886,11 +2883,8 @@ int ext4_xattr_delete_inode(handle_t *handle, struct inode *inode, goto cleanup; } error = ext4_xattr_check_block(inode, bh); - if (error) { - EXT4_ERROR_INODE(inode, "bad block %llu (error %d)", - EXT4_I(inode)->i_file_acl, error); + if (error) goto cleanup; - } if (ext4_has_feature_ea_inode(inode->i_sb)) { for (entry = BFIRST(bh); !IS_LAST_ENTRY(entry); -- GitLab From 9703952178f1412b7a74e170298d58e96c53152f Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Fri, 30 Mar 2018 20:00:56 -0400 Subject: [PATCH 0715/1635] ext4: add bounds checking to ext4_xattr_find_entry() commit 9496005d6ca4cf8f5ee8f828165a8956872dc59d upstream. Add some paranoia checks to make sure we don't stray beyond the end of the valid memory region containing ext4 xattr entries while we are scanning for a match. Also rename the function to xattr_find_entry() since it is static and thus only used in fs/ext4/xattr.c Signed-off-by: Theodore Ts'o Cc: stable@kernel.org Signed-off-by: Greg Kroah-Hartman --- fs/ext4/xattr.c | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/fs/ext4/xattr.c b/fs/ext4/xattr.c index 4bc3217fa038..88544d6f2cb3 100644 --- a/fs/ext4/xattr.c +++ b/fs/ext4/xattr.c @@ -275,18 +275,22 @@ __xattr_check_inode(struct inode *inode, struct ext4_xattr_ibody_header *header, __xattr_check_inode((inode), (header), (end), __func__, __LINE__) static int -ext4_xattr_find_entry(struct ext4_xattr_entry **pentry, int name_index, - const char *name, int sorted) +xattr_find_entry(struct inode *inode, struct ext4_xattr_entry **pentry, + void *end, int name_index, const char *name, int sorted) { - struct ext4_xattr_entry *entry; + struct ext4_xattr_entry *entry, *next; size_t name_len; int cmp = 1; if (name == NULL) return -EINVAL; name_len = strlen(name); - entry = *pentry; - for (; !IS_LAST_ENTRY(entry); entry = EXT4_XATTR_NEXT(entry)) { + for (entry = *pentry; !IS_LAST_ENTRY(entry); entry = next) { + next = EXT4_XATTR_NEXT(entry); + if ((void *) next >= end) { + EXT4_ERROR_INODE(inode, "corrupted xattr entries"); + return -EFSCORRUPTED; + } cmp = name_index - entry->e_name_index; if (!cmp) cmp = name_len - entry->e_name_len; @@ -508,6 +512,7 @@ ext4_xattr_block_get(struct inode *inode, int name_index, const char *name, struct buffer_head *bh = NULL; struct ext4_xattr_entry *entry; size_t size; + void *end; int error; struct mb_cache *ea_block_cache = EA_BLOCK_CACHE(inode); @@ -529,7 +534,8 @@ ext4_xattr_block_get(struct inode *inode, int name_index, const char *name, goto cleanup; ext4_xattr_block_cache_insert(ea_block_cache, bh); entry = BFIRST(bh); - error = ext4_xattr_find_entry(&entry, name_index, name, 1); + end = bh->b_data + bh->b_size; + error = xattr_find_entry(inode, &entry, end, name_index, name, 1); if (error) goto cleanup; size = le32_to_cpu(entry->e_value_size); @@ -578,7 +584,7 @@ ext4_xattr_ibody_get(struct inode *inode, int name_index, const char *name, if (error) goto cleanup; entry = IFIRST(header); - error = ext4_xattr_find_entry(&entry, name_index, name, 0); + error = xattr_find_entry(inode, &entry, end, name_index, name, 0); if (error) goto cleanup; size = le32_to_cpu(entry->e_value_size); @@ -1807,8 +1813,8 @@ ext4_xattr_block_find(struct inode *inode, struct ext4_xattr_info *i, bs->s.first = BFIRST(bs->bh); bs->s.end = bs->bh->b_data + bs->bh->b_size; bs->s.here = bs->s.first; - error = ext4_xattr_find_entry(&bs->s.here, i->name_index, - i->name, 1); + error = xattr_find_entry(inode, &bs->s.here, bs->s.end, + i->name_index, i->name, 1); if (error && error != -ENODATA) goto cleanup; bs->s.not_found = error; @@ -2167,8 +2173,8 @@ int ext4_xattr_ibody_find(struct inode *inode, struct ext4_xattr_info *i, if (error) return error; /* Find the named attribute. */ - error = ext4_xattr_find_entry(&is->s.here, i->name_index, - i->name, 0); + error = xattr_find_entry(inode, &is->s.here, is->s.end, + i->name_index, i->name, 0); if (error && error != -ENODATA) return error; is->s.not_found = error; -- GitLab From e7793f2a2ac85f912690a69f7964907e31731ae7 Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Fri, 30 Mar 2018 20:04:11 -0400 Subject: [PATCH 0716/1635] ext4: add extra checks to ext4_xattr_block_get() commit 54dd0e0a1b255f115f8647fc6fb93273251b01b9 upstream. Add explicit checks in ext4_xattr_block_get() just in case the e_value_offs and e_value_size fields in the the xattr block are corrupted in memory after the buffer_verified bit is set on the xattr block. Signed-off-by: Theodore Ts'o Cc: stable@kernel.org Signed-off-by: Greg Kroah-Hartman --- fs/ext4/xattr.c | 26 +++++++++++++++++++------- fs/ext4/xattr.h | 11 +++++++++++ 2 files changed, 30 insertions(+), 7 deletions(-) diff --git a/fs/ext4/xattr.c b/fs/ext4/xattr.c index 88544d6f2cb3..1718354e6322 100644 --- a/fs/ext4/xattr.c +++ b/fs/ext4/xattr.c @@ -196,7 +196,7 @@ ext4_xattr_check_entries(struct ext4_xattr_entry *entry, void *end, while (!IS_LAST_ENTRY(entry)) { u32 size = le32_to_cpu(entry->e_value_size); - if (size > INT_MAX) + if (size > EXT4_XATTR_SIZE_MAX) return -EFSCORRUPTED; if (size != 0 && entry->e_value_inum == 0) { @@ -539,8 +539,10 @@ ext4_xattr_block_get(struct inode *inode, int name_index, const char *name, if (error) goto cleanup; size = le32_to_cpu(entry->e_value_size); + error = -ERANGE; + if (unlikely(size > EXT4_XATTR_SIZE_MAX)) + goto cleanup; if (buffer) { - error = -ERANGE; if (size > buffer_size) goto cleanup; if (entry->e_value_inum) { @@ -549,8 +551,12 @@ ext4_xattr_block_get(struct inode *inode, int name_index, const char *name, if (error) goto cleanup; } else { - memcpy(buffer, bh->b_data + - le16_to_cpu(entry->e_value_offs), size); + u16 offset = le16_to_cpu(entry->e_value_offs); + void *p = bh->b_data + offset; + + if (unlikely(p + size > end)) + goto cleanup; + memcpy(buffer, p, size); } } error = size; @@ -588,8 +594,10 @@ ext4_xattr_ibody_get(struct inode *inode, int name_index, const char *name, if (error) goto cleanup; size = le32_to_cpu(entry->e_value_size); + error = -ERANGE; + if (unlikely(size > EXT4_XATTR_SIZE_MAX)) + goto cleanup; if (buffer) { - error = -ERANGE; if (size > buffer_size) goto cleanup; if (entry->e_value_inum) { @@ -598,8 +606,12 @@ ext4_xattr_ibody_get(struct inode *inode, int name_index, const char *name, if (error) goto cleanup; } else { - memcpy(buffer, (void *)IFIRST(header) + - le16_to_cpu(entry->e_value_offs), size); + u16 offset = le16_to_cpu(entry->e_value_offs); + void *p = (void *)IFIRST(header) + offset; + + if (unlikely(p + size > end)) + goto cleanup; + memcpy(buffer, p, size); } } error = size; diff --git a/fs/ext4/xattr.h b/fs/ext4/xattr.h index f8cc07588ac9..262b9314119f 100644 --- a/fs/ext4/xattr.h +++ b/fs/ext4/xattr.h @@ -70,6 +70,17 @@ struct ext4_xattr_entry { EXT4_I(inode)->i_extra_isize)) #define IFIRST(hdr) ((struct ext4_xattr_entry *)((hdr)+1)) +/* + * XATTR_SIZE_MAX is currently 64k, but for the purposes of checking + * for file system consistency errors, we use a somewhat bigger value. + * This allows XATTR_SIZE_MAX to grow in the future, but by using this + * instead of INT_MAX for certain consistency checks, we don't need to + * worry about arithmetic overflows. (Actually XATTR_SIZE_MAX is + * defined in include/uapi/linux/limits.h, so changing it is going + * not going to be trivial....) + */ +#define EXT4_XATTR_SIZE_MAX (1 << 24) + /* * The minimum size of EA value when you start storing it in an external inode * size of block - size of header - size of 1 entry - 4 null bytes -- GitLab From 79fbd052ea63e26ee739dbdd32b45bf124eb7923 Mon Sep 17 00:00:00 2001 From: Mikulas Patocka Date: Sun, 13 Aug 2017 22:45:08 -0400 Subject: [PATCH 0717/1635] dm crypt: limit the number of allocated pages commit 5059353df86e2573ccd9d43fd9d9396dcec47ca2 upstream. dm-crypt consumes an excessive amount memory when the user attempts to zero a dm-crypt device with "blkdiscard -z". The command "blkdiscard -z" calls the BLKZEROOUT ioctl, it goes to the function __blkdev_issue_zeroout, __blkdev_issue_zeroout sends a large amount of write bios that contain the zero page as their payload. For each incoming page, dm-crypt allocates another page that holds the encrypted data, so when processing "blkdiscard -z", dm-crypt tries to allocate the amount of memory that is equal to the size of the device. This can trigger OOM killer or cause system crash. Fix this by limiting the amount of memory that dm-crypt allocates to 2% of total system memory. This limit is system-wide and is divided by the number of active dm-crypt devices and each device receives an equal share. Cc: stable@vger.kernel.org Signed-off-by: Mikulas Patocka Signed-off-by: Mike Snitzer Signed-off-by: Greg Kroah-Hartman --- drivers/md/dm-crypt.c | 66 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 65 insertions(+), 1 deletion(-) diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c index 554d60394c06..f575110454b6 100644 --- a/drivers/md/dm-crypt.c +++ b/drivers/md/dm-crypt.c @@ -148,6 +148,8 @@ struct crypt_config { mempool_t *tag_pool; unsigned tag_pool_max_sectors; + struct percpu_counter n_allocated_pages; + struct bio_set *bs; struct mutex bio_alloc_lock; @@ -219,6 +221,12 @@ struct crypt_config { #define MAX_TAG_SIZE 480 #define POOL_ENTRY_SIZE 512 +static DEFINE_SPINLOCK(dm_crypt_clients_lock); +static unsigned dm_crypt_clients_n = 0; +static volatile unsigned long dm_crypt_pages_per_client; +#define DM_CRYPT_MEMORY_PERCENT 2 +#define DM_CRYPT_MIN_PAGES_PER_CLIENT (BIO_MAX_PAGES * 16) + static void clone_init(struct dm_crypt_io *, struct bio *); static void kcryptd_queue_crypt(struct dm_crypt_io *io); static struct scatterlist *crypt_get_sg_data(struct crypt_config *cc, @@ -2156,6 +2164,43 @@ static int crypt_wipe_key(struct crypt_config *cc) return r; } +static void crypt_calculate_pages_per_client(void) +{ + unsigned long pages = (totalram_pages - totalhigh_pages) * DM_CRYPT_MEMORY_PERCENT / 100; + + if (!dm_crypt_clients_n) + return; + + pages /= dm_crypt_clients_n; + if (pages < DM_CRYPT_MIN_PAGES_PER_CLIENT) + pages = DM_CRYPT_MIN_PAGES_PER_CLIENT; + dm_crypt_pages_per_client = pages; +} + +static void *crypt_page_alloc(gfp_t gfp_mask, void *pool_data) +{ + struct crypt_config *cc = pool_data; + struct page *page; + + if (unlikely(percpu_counter_compare(&cc->n_allocated_pages, dm_crypt_pages_per_client) >= 0) && + likely(gfp_mask & __GFP_NORETRY)) + return NULL; + + page = alloc_page(gfp_mask); + if (likely(page != NULL)) + percpu_counter_add(&cc->n_allocated_pages, 1); + + return page; +} + +static void crypt_page_free(void *page, void *pool_data) +{ + struct crypt_config *cc = pool_data; + + __free_page(page); + percpu_counter_sub(&cc->n_allocated_pages, 1); +} + static void crypt_dtr(struct dm_target *ti) { struct crypt_config *cc = ti->private; @@ -2182,6 +2227,10 @@ static void crypt_dtr(struct dm_target *ti) mempool_destroy(cc->req_pool); mempool_destroy(cc->tag_pool); + if (cc->page_pool) + WARN_ON(percpu_counter_sum(&cc->n_allocated_pages) != 0); + percpu_counter_destroy(&cc->n_allocated_pages); + if (cc->iv_gen_ops && cc->iv_gen_ops->dtr) cc->iv_gen_ops->dtr(cc); @@ -2196,6 +2245,12 @@ static void crypt_dtr(struct dm_target *ti) /* Must zero key material before freeing */ kzfree(cc); + + spin_lock(&dm_crypt_clients_lock); + WARN_ON(!dm_crypt_clients_n); + dm_crypt_clients_n--; + crypt_calculate_pages_per_client(); + spin_unlock(&dm_crypt_clients_lock); } static int crypt_ctr_ivmode(struct dm_target *ti, const char *ivmode) @@ -2643,6 +2698,15 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv) ti->private = cc; + spin_lock(&dm_crypt_clients_lock); + dm_crypt_clients_n++; + crypt_calculate_pages_per_client(); + spin_unlock(&dm_crypt_clients_lock); + + ret = percpu_counter_init(&cc->n_allocated_pages, 0, GFP_KERNEL); + if (ret < 0) + goto bad; + /* Optional parameters need to be read before cipher constructor */ if (argc > 5) { ret = crypt_ctr_optional(ti, argc - 5, &argv[5]); @@ -2697,7 +2761,7 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv) ALIGN(sizeof(struct dm_crypt_io) + cc->dmreq_start + additional_req_size, ARCH_KMALLOC_MINALIGN); - cc->page_pool = mempool_create_page_pool(BIO_MAX_PAGES, 0); + cc->page_pool = mempool_create(BIO_MAX_PAGES, crypt_page_alloc, crypt_page_free, cc); if (!cc->page_pool) { ti->error = "Cannot allocate page mempool"; goto bad; -- GitLab From b140d94688707e42b75cad3b020563a706101abe Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Tue, 3 Apr 2018 15:33:01 -0700 Subject: [PATCH 0718/1635] RDMA/ucma: Don't allow setting RDMA_OPTION_IB_PATH without an RDMA device commit 8435168d50e66fa5eae01852769d20a36f9e5e83 upstream. Check to make sure that ctx->cm_id->device is set before we use it. Otherwise userspace can trigger a NULL dereference by doing RDMA_USER_CM_CMD_SET_OPTION on an ID that is not bound to a device. Cc: Reported-by: Signed-off-by: Roland Dreier Signed-off-by: Jason Gunthorpe Signed-off-by: Greg Kroah-Hartman --- drivers/infiniband/core/ucma.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/infiniband/core/ucma.c b/drivers/infiniband/core/ucma.c index d6fa38f8604f..0698d92e2656 100644 --- a/drivers/infiniband/core/ucma.c +++ b/drivers/infiniband/core/ucma.c @@ -1241,6 +1241,9 @@ static int ucma_set_ib_path(struct ucma_context *ctx, if (!optlen) return -EINVAL; + if (!ctx->cm_id->device) + return -EINVAL; + memset(&sa_path, 0, sizeof(sa_path)); sa_path.rec_type = SA_PATH_REC_TYPE_IB; -- GitLab From 28ce82e3c8b116f09ea539e15bbb9f0f09f5fa32 Mon Sep 17 00:00:00 2001 From: Leon Romanovsky Date: Tue, 13 Mar 2018 15:29:24 +0200 Subject: [PATCH 0719/1635] RDMA/mlx5: Protect from NULL pointer derefence commit 4289861d88d6c7b5e4c8cc7fe2ad6cdf0cdfc366 upstream. The mlx5_ib_alloc_implicit_mr() can fail to acquire pages and the returned mr pointer won't be valid. Ensure that it is not error prior to access. Cc: # 4.10 Fixes: 81713d3788d2 ("IB/mlx5: Add implicit MR support") Reported-by: Noa Osherovich Signed-off-by: Leon Romanovsky Signed-off-by: Doug Ledford Signed-off-by: Greg Kroah-Hartman --- drivers/infiniband/hw/mlx5/mr.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/infiniband/hw/mlx5/mr.c b/drivers/infiniband/hw/mlx5/mr.c index 6d48d8a93b62..538f1784863a 100644 --- a/drivers/infiniband/hw/mlx5/mr.c +++ b/drivers/infiniband/hw/mlx5/mr.c @@ -1220,6 +1220,8 @@ struct ib_mr *mlx5_ib_reg_user_mr(struct ib_pd *pd, u64 start, u64 length, return ERR_PTR(-EINVAL); mr = mlx5_ib_alloc_implicit_mr(to_mpd(pd), access_flags); + if (IS_ERR(mr)) + return ERR_CAST(mr); return &mr->ibmr; } #endif -- GitLab From d3b14a66e14bb6b248dcab04c294aceacff68c0b Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Thu, 1 Mar 2018 14:00:29 -0800 Subject: [PATCH 0720/1635] RDMA/rxe: Fix an out-of-bounds read commit a6544a624c3ff92a64e4aca3931fa064607bd3da upstream. This patch avoids that KASAN reports the following when the SRP initiator calls srp_post_send(): ================================================================== BUG: KASAN: stack-out-of-bounds in rxe_post_send+0x5c4/0x980 [rdma_rxe] Read of size 8 at addr ffff880066606e30 by task 02-mq/1074 CPU: 2 PID: 1074 Comm: 02-mq Not tainted 4.16.0-rc3-dbg+ #1 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.0.0-prebuilt.qemu-project.org 04/01/2014 Call Trace: dump_stack+0x85/0xc7 print_address_description+0x65/0x270 kasan_report+0x231/0x350 rxe_post_send+0x5c4/0x980 [rdma_rxe] srp_post_send.isra.16+0x149/0x190 [ib_srp] srp_queuecommand+0x94d/0x1670 [ib_srp] scsi_dispatch_cmd+0x1c2/0x550 [scsi_mod] scsi_queue_rq+0x843/0xa70 [scsi_mod] blk_mq_dispatch_rq_list+0x143/0xac0 blk_mq_do_dispatch_ctx+0x1c5/0x260 blk_mq_sched_dispatch_requests+0x2bf/0x2f0 __blk_mq_run_hw_queue+0xdb/0x160 __blk_mq_delay_run_hw_queue+0xba/0x100 blk_mq_run_hw_queue+0xf2/0x190 blk_mq_sched_insert_request+0x163/0x2f0 blk_execute_rq+0xb0/0x130 scsi_execute+0x14e/0x260 [scsi_mod] scsi_probe_and_add_lun+0x366/0x13d0 [scsi_mod] __scsi_scan_target+0x18a/0x810 [scsi_mod] scsi_scan_target+0x11e/0x130 [scsi_mod] srp_create_target+0x1522/0x19e0 [ib_srp] kernfs_fop_write+0x180/0x210 __vfs_write+0xb1/0x2e0 vfs_write+0xf6/0x250 SyS_write+0x99/0x110 do_syscall_64+0xee/0x2b0 entry_SYSCALL_64_after_hwframe+0x42/0xb7 The buggy address belongs to the page: page:ffffea0001998180 count:0 mapcount:0 mapping:0000000000000000 index:0x0 flags: 0x4000000000000000() raw: 4000000000000000 0000000000000000 0000000000000000 00000000ffffffff raw: dead000000000100 dead000000000200 0000000000000000 0000000000000000 page dumped because: kasan: bad access detected Memory state around the buggy address: ffff880066606d00: 00 00 00 00 00 00 00 00 00 00 00 00 00 f1 f1 f1 ffff880066606d80: f1 00 f2 f2 f2 f2 f2 f2 f2 00 00 f2 f2 f2 f2 f2 >ffff880066606e00: f2 00 00 00 00 00 f2 f2 f2 f3 f3 f3 f3 00 00 00 ^ ffff880066606e80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ffff880066606f00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ================================================================== Fixes: 8700e3e7c485 ("Soft RoCE driver") Signed-off-by: Bart Van Assche Cc: Moni Shoua Cc: stable@vger.kernel.org Signed-off-by: Jason Gunthorpe Signed-off-by: Greg Kroah-Hartman --- drivers/infiniband/sw/rxe/rxe_verbs.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/infiniband/sw/rxe/rxe_verbs.c b/drivers/infiniband/sw/rxe/rxe_verbs.c index afbf701dc9a7..906bacf365d4 100644 --- a/drivers/infiniband/sw/rxe/rxe_verbs.c +++ b/drivers/infiniband/sw/rxe/rxe_verbs.c @@ -712,9 +712,8 @@ static int init_send_wqe(struct rxe_qp *qp, struct ib_send_wr *ibwr, memcpy(wqe->dma.sge, ibwr->sg_list, num_sge * sizeof(struct ib_sge)); - wqe->iova = (mask & WR_ATOMIC_MASK) ? - atomic_wr(ibwr)->remote_addr : - rdma_wr(ibwr)->remote_addr; + wqe->iova = mask & WR_ATOMIC_MASK ? atomic_wr(ibwr)->remote_addr : + mask & WR_READ_OR_WRITE_MASK ? rdma_wr(ibwr)->remote_addr : 0; wqe->mask = mask; wqe->dma.length = length; wqe->dma.resid = length; -- GitLab From 0bb5579128e65d8c4334f90ca47cfe49e90187f7 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 2 Apr 2018 22:41:43 +0200 Subject: [PATCH 0721/1635] ALSA: pcm: Fix UAF at PCM release via PCM timer access commit a820ccbe21e8ce8e86c39cd1d3bc8c7d1cbb949b upstream. The PCM runtime object is created and freed dynamically at PCM stream open / close time. This is tracked via substream->runtime, and it's cleared at snd_pcm_detach_substream(). The runtime object assignment is protected by PCM open_mutex, so for all PCM operations, it's safely handled. However, each PCM substream provides also an ALSA timer interface, and user-space can access to this while closing a PCM substream. This may eventually lead to a UAF, as snd_pcm_timer_resolution() tries to access the runtime while clearing it in other side. Fortunately, it's the only concurrent access from the PCM timer, and it merely reads runtime->timer_resolution field. So, we can avoid the race by reordering kfree() and wrapping the substream->runtime clearance with the corresponding timer lock. Reported-by: syzbot+8e62ff4e07aa2ce87826@syzkaller.appspotmail.com Cc: Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/core/pcm.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/sound/core/pcm.c b/sound/core/pcm.c index 7fea724d093a..e8dc1a5afe66 100644 --- a/sound/core/pcm.c +++ b/sound/core/pcm.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -1050,8 +1051,13 @@ void snd_pcm_detach_substream(struct snd_pcm_substream *substream) snd_free_pages((void*)runtime->control, PAGE_ALIGN(sizeof(struct snd_pcm_mmap_control))); kfree(runtime->hw_constraints.rules); - kfree(runtime); + /* Avoid concurrent access to runtime via PCM timer interface */ + if (substream->timer) + spin_lock_irq(&substream->timer->lock); substream->runtime = NULL; + if (substream->timer) + spin_unlock_irq(&substream->timer->lock); + kfree(runtime); put_pid(substream->pid); substream->pid = NULL; substream->pstr->substream_opened--; -- GitLab From fe71b03e698325f5361d187fc7534b202f2a8404 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Fri, 23 Feb 2018 14:09:24 -0800 Subject: [PATCH 0722/1635] IB/srp: Fix srp_abort() commit e68088e78d82920632eba112b968e49d588d02a2 upstream. Before commit e494f6a72839 ("[SCSI] improved eh timeout handler") it did not really matter whether or not abort handlers like srp_abort() called .scsi_done() when returning another value than SUCCESS. Since that commit however this matters. Hence only call .scsi_done() when returning SUCCESS. Signed-off-by: Bart Van Assche Cc: stable@vger.kernel.org Signed-off-by: Jason Gunthorpe Signed-off-by: Greg Kroah-Hartman --- drivers/infiniband/ulp/srp/ib_srp.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c index 60d7b493ed2d..02a3169b2fd6 100644 --- a/drivers/infiniband/ulp/srp/ib_srp.c +++ b/drivers/infiniband/ulp/srp/ib_srp.c @@ -2656,9 +2656,11 @@ static int srp_abort(struct scsi_cmnd *scmnd) ret = FAST_IO_FAIL; else ret = FAILED; - srp_free_req(ch, req, scmnd, 0); - scmnd->result = DID_ABORT << 16; - scmnd->scsi_done(scmnd); + if (ret == SUCCESS) { + srp_free_req(ch, req, scmnd, 0); + scmnd->result = DID_ABORT << 16; + scmnd->scsi_done(scmnd); + } return ret; } -- GitLab From e99ca1ee070dea0fcda75c127cab1b8b85189224 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Mon, 12 Feb 2018 09:50:25 -0800 Subject: [PATCH 0723/1635] IB/srp: Fix completion vector assignment algorithm commit 3a148896b24adf8688dc0c59af54531931677a40 upstream. Ensure that cv_end is equal to ibdev->num_comp_vectors for the NUMA node with the highest index. This patch improves spreading of RDMA channels over completion vectors and thereby improves performance, especially on systems with only a single NUMA node. This patch drops support for the comp_vector login parameter by ignoring the value of that parameter since I have not found a good way to combine support for that parameter and automatic spreading of RDMA channels over completion vectors. Fixes: d92c0da71a35 ("IB/srp: Add multichannel support") Reported-by: Alexander Schmid Signed-off-by: Bart Van Assche Cc: Alexander Schmid Cc: stable@vger.kernel.org Signed-off-by: Jason Gunthorpe Signed-off-by: Greg Kroah-Hartman --- drivers/infiniband/ulp/srp/ib_srp.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c index 02a3169b2fd6..299a97b7e17f 100644 --- a/drivers/infiniband/ulp/srp/ib_srp.c +++ b/drivers/infiniband/ulp/srp/ib_srp.c @@ -3430,12 +3430,10 @@ static ssize_t srp_create_target(struct device *dev, num_online_nodes()); const int ch_end = ((node_idx + 1) * target->ch_count / num_online_nodes()); - const int cv_start = (node_idx * ibdev->num_comp_vectors / - num_online_nodes() + target->comp_vector) - % ibdev->num_comp_vectors; - const int cv_end = ((node_idx + 1) * ibdev->num_comp_vectors / - num_online_nodes() + target->comp_vector) - % ibdev->num_comp_vectors; + const int cv_start = node_idx * ibdev->num_comp_vectors / + num_online_nodes(); + const int cv_end = (node_idx + 1) * ibdev->num_comp_vectors / + num_online_nodes(); int cpu_idx = 0; for_each_online_cpu(cpu) { -- GitLab From 156b45ed22073e7b8aa753abb8ff4462e1cbe47f Mon Sep 17 00:00:00 2001 From: Maxime Jayat Date: Thu, 22 Feb 2018 12:39:55 +0100 Subject: [PATCH 0724/1635] dmaengine: at_xdmac: fix rare residue corruption commit c5637476bbf9bb86c7f0413b8f4822a73d8d2d07 upstream. Despite the efforts made to correctly read the NDA and CUBC registers, the order in which the registers are read could sometimes lead to an inconsistent state. Re-using the timeline from the comments, this following timing of registers reads could lead to reading NDA with value "@desc2" and CUBC with value "MAX desc1": INITD -------- ------------ |____________________| _______________________ _______________ NDA @desc2 \/ @desc3 _______________________/\_______________ __________ ___________ _______________ CUBC 0 \/ MAX desc1 \/ MAX desc2 __________/\___________/\_______________ | | | | Events:(1)(2) (3)(4) (1) check_nda = @desc2 (2) initd = 1 (3) cur_ubc = MAX desc1 (4) cur_nda = @desc2 This is allowed by the condition ((check_nda == cur_nda) && initd), despite cur_ubc and cur_nda being in the precise state we don't want. This error leads to incorrect residue computation. Fix it by inversing the order in which CUBC and INITD are read. This makes sure that NDA and CUBC are always read together either _before_ INITD goes to 0 or _after_ it is back at 1. The case where NDA is read before INITD is at 0 and CUBC is read after INITD is back at 1 will be rejected by check_nda and cur_nda being different. Fixes: 53398f488821 ("dmaengine: at_xdmac: fix residue corruption") Cc: stable@vger.kernel.org Signed-off-by: Maxime Jayat Acked-by: Ludovic Desroches Signed-off-by: Vinod Koul Signed-off-by: Greg Kroah-Hartman --- drivers/dma/at_xdmac.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/dma/at_xdmac.c b/drivers/dma/at_xdmac.c index c00e3923d7d8..94236ec9d410 100644 --- a/drivers/dma/at_xdmac.c +++ b/drivers/dma/at_xdmac.c @@ -1471,10 +1471,10 @@ at_xdmac_tx_status(struct dma_chan *chan, dma_cookie_t cookie, for (retry = 0; retry < AT_XDMAC_RESIDUE_MAX_RETRIES; retry++) { check_nda = at_xdmac_chan_read(atchan, AT_XDMAC_CNDA) & 0xfffffffc; rmb(); - initd = !!(at_xdmac_chan_read(atchan, AT_XDMAC_CC) & AT_XDMAC_CC_INITD); - rmb(); cur_ubc = at_xdmac_chan_read(atchan, AT_XDMAC_CUBC); rmb(); + initd = !!(at_xdmac_chan_read(atchan, AT_XDMAC_CC) & AT_XDMAC_CC_INITD); + rmb(); cur_nda = at_xdmac_chan_read(atchan, AT_XDMAC_CNDA) & 0xfffffffc; rmb(); -- GitLab From c1edd3b19f302c85ed6fe11e753eda674c100524 Mon Sep 17 00:00:00 2001 From: Frederic Barrat Date: Tue, 3 Apr 2018 15:54:02 +0200 Subject: [PATCH 0725/1635] cxl: Fix possible deadlock when processing page faults from cxllib commit ad7b4e8022b9864c075fe71e1328b1d25cad82f6 upstream. cxllib_handle_fault() is called by an external driver when it needs to have the host resolve page faults for a buffer. The buffer can cover several pages and VMAs. The function iterates over all the pages used by the buffer, based on the page size of the VMA. To ensure some stability while processing the faults, the thread T1 grabs the mm->mmap_sem semaphore with read access (R1). However, when processing a page fault for a single page, one of the underlying functions, copro_handle_mm_fault(), also grabs the same semaphore with read access (R2). So the thread T1 takes the semaphore twice. If another thread T2 tries to access the semaphore in write mode W1 (say, because it wants to allocate memory and calls 'brk'), then that thread T2 will have to wait because there's a reader (R1). If the thread T1 is processing a new page at that time, it won't get an automatic grant at R2, because there's now a writer thread waiting (T2). And we have a deadlock. The timeline is: 1. thread T1 owns the semaphore with read access R1 2. thread T2 requests write access W1 and waits 3. thread T1 requests read access R2 and waits The fix is for the thread T1 to release the semaphore R1 once it got the information it needs from the current VMA. The address space/VMAs could evolve while T1 iterates over the full buffer, but in the unlikely case where T1 misses a page, the external driver will raise a new page fault when retrying the memory access. Fixes: 3ced8d730063 ("cxl: Export library to support IBM XSL") Cc: stable@vger.kernel.org # 4.13+ Signed-off-by: Frederic Barrat Signed-off-by: Michael Ellerman Signed-off-by: Greg Kroah-Hartman --- drivers/misc/cxl/cxllib.c | 85 +++++++++++++++++++++++++-------------- 1 file changed, 55 insertions(+), 30 deletions(-) diff --git a/drivers/misc/cxl/cxllib.c b/drivers/misc/cxl/cxllib.c index dc9bc1807fdf..562a6803d690 100644 --- a/drivers/misc/cxl/cxllib.c +++ b/drivers/misc/cxl/cxllib.c @@ -207,49 +207,74 @@ int cxllib_get_PE_attributes(struct task_struct *task, } EXPORT_SYMBOL_GPL(cxllib_get_PE_attributes); -int cxllib_handle_fault(struct mm_struct *mm, u64 addr, u64 size, u64 flags) +static int get_vma_info(struct mm_struct *mm, u64 addr, + u64 *vma_start, u64 *vma_end, + unsigned long *page_size) { - int rc; - u64 dar; struct vm_area_struct *vma = NULL; - unsigned long page_size; - - if (mm == NULL) - return -EFAULT; + int rc = 0; down_read(&mm->mmap_sem); vma = find_vma(mm, addr); if (!vma) { - pr_err("Can't find vma for addr %016llx\n", addr); rc = -EFAULT; goto out; } - /* get the size of the pages allocated */ - page_size = vma_kernel_pagesize(vma); - - for (dar = (addr & ~(page_size - 1)); dar < (addr + size); dar += page_size) { - if (dar < vma->vm_start || dar >= vma->vm_end) { - vma = find_vma(mm, addr); - if (!vma) { - pr_err("Can't find vma for addr %016llx\n", addr); - rc = -EFAULT; - goto out; - } - /* get the size of the pages allocated */ - page_size = vma_kernel_pagesize(vma); + *page_size = vma_kernel_pagesize(vma); + *vma_start = vma->vm_start; + *vma_end = vma->vm_end; +out: + up_read(&mm->mmap_sem); + return rc; +} + +int cxllib_handle_fault(struct mm_struct *mm, u64 addr, u64 size, u64 flags) +{ + int rc; + u64 dar, vma_start, vma_end; + unsigned long page_size; + + if (mm == NULL) + return -EFAULT; + + /* + * The buffer we have to process can extend over several pages + * and may also cover several VMAs. + * We iterate over all the pages. The page size could vary + * between VMAs. + */ + rc = get_vma_info(mm, addr, &vma_start, &vma_end, &page_size); + if (rc) + return rc; + + for (dar = (addr & ~(page_size - 1)); dar < (addr + size); + dar += page_size) { + if (dar < vma_start || dar >= vma_end) { + /* + * We don't hold the mm->mmap_sem semaphore + * while iterating, since the semaphore is + * required by one of the lower-level page + * fault processing functions and it could + * create a deadlock. + * + * It means the VMAs can be altered between 2 + * loop iterations and we could theoretically + * miss a page (however unlikely). But that's + * not really a problem, as the driver will + * retry access, get another page fault on the + * missing page and call us again. + */ + rc = get_vma_info(mm, dar, &vma_start, &vma_end, + &page_size); + if (rc) + return rc; } rc = cxl_handle_mm_fault(mm, flags, dar); - if (rc) { - pr_err("cxl_handle_mm_fault failed %d", rc); - rc = -EFAULT; - goto out; - } + if (rc) + return -EFAULT; } - rc = 0; -out: - up_read(&mm->mmap_sem); - return rc; + return 0; } EXPORT_SYMBOL_GPL(cxllib_handle_fault); -- GitLab From a43d8e0ee79d748ad98129254a7969abf88f11b6 Mon Sep 17 00:00:00 2001 From: Chris Chiu Date: Tue, 20 Mar 2018 15:36:40 +0800 Subject: [PATCH 0726/1635] tpm: self test failure should not cause suspend to fail commit 0803d7befa15cab5717d667a97a66214d2a4c083 upstream. The Acer Acer Veriton X4110G has a TPM device detected as: tpm_tis 00:0b: 1.2 TPM (device-id 0xFE, rev-id 71) After the first S3 suspend, the following error appears during resume: tpm tpm0: A TPM error(38) occurred continue selftest Any following S3 suspend attempts will now fail with this error: tpm tpm0: Error (38) sending savestate before suspend PM: Device 00:0b failed to suspend: error 38 Error 38 is TPM_ERR_INVALID_POSTINIT which means the TPM is not in the correct state. This indicates that the platform BIOS is not sending the usual TPM_Startup command during S3 resume. >From this point onwards, all TPM commands will fail. The same issue was previously reported on Foxconn 6150BK8MC and Sony Vaio TX3. The platform behaviour seems broken here, but we should not break suspend/resume because of this. When the unexpected TPM state is encountered, set a flag to skip the affected TPM_SaveState command on later suspends. Cc: stable@vger.kernel.org Signed-off-by: Chris Chiu Signed-off-by: Daniel Drake Link: http://lkml.kernel.org/r/CAB4CAwfSCvj1cudi+MWaB5g2Z67d9DwY1o475YOZD64ma23UiQ@mail.gmail.com Link: https://lkml.org/lkml/2011/3/28/192 Link: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=591031 Reviewed-by: Jarkko Sakkinen Signed-off-by: Jarkko Sakkinen Signed-off-by: Greg Kroah-Hartman --- drivers/char/tpm/tpm-interface.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c index 0f1dc35e7078..1d01a8f77db1 100644 --- a/drivers/char/tpm/tpm-interface.c +++ b/drivers/char/tpm/tpm-interface.c @@ -971,6 +971,10 @@ int tpm_do_selftest(struct tpm_chip *chip) loops = jiffies_to_msecs(duration) / delay_msec; rc = tpm_continue_selftest(chip); + if (rc == TPM_ERR_INVALID_POSTINIT) { + chip->flags |= TPM_CHIP_FLAG_ALWAYS_POWERED; + dev_info(&chip->dev, "TPM not ready (%d)\n", rc); + } /* This may fail if there was no TPM driver during a suspend/resume * cycle; some may return 10 (BAD_ORDINAL), others 28 (FAILEDSELFTEST) */ -- GitLab From 45980ba59916718a8d8e9a4c1a27a4ac187e515c Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Fri, 6 Apr 2018 11:25:38 -0700 Subject: [PATCH 0727/1635] libnvdimm, dimm: fix dpa reservation vs uninitialized label area commit c31898c8c711f2bbbcaebe802a55827e288d875a upstream. At initialization time the 'dimm' driver caches a copy of the memory device's label area and reserves address space for each of the namespaces defined. However, as can be seen below, the reservation occurs even when the index blocks are invalid: nvdimm nmem0: nvdimm_init_config_data: len: 131072 rc: 0 nvdimm nmem0: config data size: 131072 nvdimm nmem0: __nd_label_validate: nsindex0 labelsize 1 invalid nvdimm nmem0: __nd_label_validate: nsindex1 labelsize 1 invalid nvdimm nmem0: : pmem-6025e505: 0x1000000000 @ 0xf50000000 reserve <-- bad Gate dpa reservation on the presence of valid index blocks. Cc: Fixes: 4a826c83db4e ("libnvdimm: namespace indices: read and validate") Reported-by: Krzysztof Rusocki Signed-off-by: Dan Williams Signed-off-by: Greg Kroah-Hartman --- drivers/nvdimm/dimm.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/nvdimm/dimm.c b/drivers/nvdimm/dimm.c index 98466d762c8f..0939f064054d 100644 --- a/drivers/nvdimm/dimm.c +++ b/drivers/nvdimm/dimm.c @@ -65,9 +65,11 @@ static int nvdimm_probe(struct device *dev) ndd->ns_next = nd_label_next_nsindex(ndd->ns_current); nd_label_copy(ndd, to_next_namespace_index(ndd), to_current_namespace_index(ndd)); - rc = nd_label_reserve_dpa(ndd); - if (ndd->ns_current >= 0) - nvdimm_set_aliasing(dev); + if (ndd->ns_current >= 0) { + rc = nd_label_reserve_dpa(ndd); + if (rc == 0) + nvdimm_set_aliasing(dev); + } nvdimm_clear_locked(dev); nvdimm_bus_unlock(dev); -- GitLab From b68b77c935dd1574873aac827c17fc76bb036a0f Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Fri, 6 Apr 2018 16:37:21 -0700 Subject: [PATCH 0728/1635] libnvdimm, namespace: use a safe lookup for dimm device name commit 4f8672201b7e7ed4f5f6c3cf6dcd080648580582 upstream. The following NULL dereference results from incorrectly assuming that ndd is valid in this print: struct nvdimm_drvdata *ndd = to_ndd(&nd_region->mapping[i]); /* * Give up if we don't find an instance of a uuid at each * position (from 0 to nd_region->ndr_mappings - 1), or if we * find a dimm with two instances of the same uuid. */ dev_err(&nd_region->dev, "%s missing label for %pUb\n", dev_name(ndd->dev), nd_label->uuid); BUG: unable to handle kernel NULL pointer dereference at 0000000000000000 IP: nd_region_register_namespaces+0xd67/0x13c0 [libnvdimm] PGD 0 P4D 0 Oops: 0000 [#1] SMP PTI CPU: 43 PID: 673 Comm: kworker/u609:10 Not tainted 4.16.0-rc4+ #1 [..] RIP: 0010:nd_region_register_namespaces+0xd67/0x13c0 [libnvdimm] [..] Call Trace: ? devres_add+0x2f/0x40 ? devm_kmalloc+0x52/0x60 ? nd_region_activate+0x9c/0x320 [libnvdimm] nd_region_probe+0x94/0x260 [libnvdimm] ? kernfs_add_one+0xe4/0x130 nvdimm_bus_probe+0x63/0x100 [libnvdimm] Switch to using the nvdimm device directly. Fixes: 0e3b0d123c8f ("libnvdimm, namespace: allow multiple pmem...") Cc: Reported-by: Dave Jiang Signed-off-by: Dan Williams Signed-off-by: Greg Kroah-Hartman --- drivers/nvdimm/namespace_devs.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/nvdimm/namespace_devs.c b/drivers/nvdimm/namespace_devs.c index 0af988739a06..228bafa4d322 100644 --- a/drivers/nvdimm/namespace_devs.c +++ b/drivers/nvdimm/namespace_devs.c @@ -1926,7 +1926,7 @@ struct device *create_namespace_pmem(struct nd_region *nd_region, } if (i < nd_region->ndr_mappings) { - struct nvdimm_drvdata *ndd = to_ndd(&nd_region->mapping[i]); + struct nvdimm *nvdimm = nd_region->mapping[i].nvdimm; /* * Give up if we don't find an instance of a uuid at each @@ -1934,7 +1934,7 @@ struct device *create_namespace_pmem(struct nd_region *nd_region, * find a dimm with two instances of the same uuid. */ dev_err(&nd_region->dev, "%s missing label for %pUb\n", - dev_name(ndd->dev), nd_label->uuid); + nvdimm_name(nvdimm), nd_label->uuid); rc = -EINVAL; goto err; } -- GitLab From 5520091356b09abbaa2205babc5312a78d741a75 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Mon, 2 Apr 2018 16:40:04 -0700 Subject: [PATCH 0729/1635] nfit, address-range-scrub: fix scrub in-progress reporting commit 78727137fdf49edf9f731bde79d7189067b4047a upstream. There is a small window whereby ARS scan requests can schedule work that userspace will miss when polling scrub_show. Hold the init_mutex lock over calls to report the status to close this potential escape. Also, make sure that requests to cancel the ARS workqueue are treated as an idle event. Cc: Cc: Vishal Verma Fixes: 37b137ff8c83 ("nfit, libnvdimm: allow an ARS scrub...") Reviewed-by: Dave Jiang Signed-off-by: Dan Williams Signed-off-by: Greg Kroah-Hartman --- drivers/acpi/nfit/core.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/acpi/nfit/core.c b/drivers/acpi/nfit/core.c index 67a860790560..fd72b316b961 100644 --- a/drivers/acpi/nfit/core.c +++ b/drivers/acpi/nfit/core.c @@ -1022,8 +1022,11 @@ static ssize_t scrub_show(struct device *dev, if (nd_desc) { struct acpi_nfit_desc *acpi_desc = to_acpi_desc(nd_desc); + mutex_lock(&acpi_desc->init_mutex); rc = sprintf(buf, "%d%s", acpi_desc->scrub_count, - (work_busy(&acpi_desc->work)) ? "+\n" : "\n"); + work_busy(&acpi_desc->work) + && !acpi_desc->cancel ? "+\n" : "\n"); + mutex_unlock(&acpi_desc->init_mutex); } device_unlock(dev); return rc; -- GitLab From 4171ea2471a1c383e5df0a4cb6a193fc13436b9b Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Wed, 21 Mar 2018 21:22:34 -0700 Subject: [PATCH 0730/1635] nfit: skip region registration for incomplete control regions commit 0731de476a37c33485af82d64041c9d193208df8 upstream. Per the ACPI specification the only functional purpose for a DIMM Control Region to be mapped into the system physical address space, from an OSPM perspective, is to support block-apertures. However, there are some BIOSen that publish DIMM Control Region SPA entries for pre-boot environment consumption. Undo the kernel policy of generating disabled 'ndblk' regions when this configuration is detected. Cc: Fixes: 1f7df6f88b92 ("libnvdimm, nfit: regions (block-data-window...)") Reviewed-by: Toshi Kani Signed-off-by: Dan Williams Signed-off-by: Greg Kroah-Hartman --- drivers/acpi/nfit/core.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/drivers/acpi/nfit/core.c b/drivers/acpi/nfit/core.c index fd72b316b961..d56822f58ab1 100644 --- a/drivers/acpi/nfit/core.c +++ b/drivers/acpi/nfit/core.c @@ -2316,7 +2316,7 @@ static int acpi_nfit_init_mapping(struct acpi_nfit_desc *acpi_desc, struct acpi_nfit_system_address *spa = nfit_spa->spa; struct nd_blk_region_desc *ndbr_desc; struct nfit_mem *nfit_mem; - int blk_valid = 0, rc; + int rc; if (!nvdimm) { dev_err(acpi_desc->dev, "spa%d dimm: %#x not found\n", @@ -2336,15 +2336,14 @@ static int acpi_nfit_init_mapping(struct acpi_nfit_desc *acpi_desc, if (!nfit_mem || !nfit_mem->bdw) { dev_dbg(acpi_desc->dev, "spa%d %s missing bdw\n", spa->range_index, nvdimm_name(nvdimm)); - } else { - mapping->size = nfit_mem->bdw->capacity; - mapping->start = nfit_mem->bdw->start_address; - ndr_desc->num_lanes = nfit_mem->bdw->windows; - blk_valid = 1; + break; } + mapping->size = nfit_mem->bdw->capacity; + mapping->start = nfit_mem->bdw->start_address; + ndr_desc->num_lanes = nfit_mem->bdw->windows; ndr_desc->mapping = mapping; - ndr_desc->num_mappings = blk_valid; + ndr_desc->num_mappings = 1; ndbr_desc = to_blk_region_desc(ndr_desc); ndbr_desc->enable = acpi_nfit_blk_region_enable; ndbr_desc->do_io = acpi_desc->blk_do_io; -- GitLab From dc0f003274525862bd671bf438398bf46fc62b0f Mon Sep 17 00:00:00 2001 From: "Steven Rostedt (VMware)" Date: Mon, 2 Apr 2018 10:33:56 -0400 Subject: [PATCH 0731/1635] ring-buffer: Check if memory is available before allocation commit 2a872fa4e9c8adc79c830e4009e1cc0c013a9d8a upstream. The ring buffer is made up of a link list of pages. When making the ring buffer bigger, it will allocate all the pages it needs before adding to the ring buffer, and if it fails, it frees them and returns an error. This makes increasing the ring buffer size an all or nothing action. When this was first created, the pages were allocated with "NORETRY". This was to not cause any Out-Of-Memory (OOM) actions from allocating the ring buffer. But NORETRY was too strict, as the ring buffer would fail to expand even when there's memory available, but was taken up in the page cache. Commit 848618857d253 ("tracing/ring_buffer: Try harder to allocate") changed the allocating from NORETRY to RETRY_MAYFAIL. The RETRY_MAYFAIL would allocate from the page cache, but if there was no memory available, it would simple fail the allocation and not trigger an OOM. This worked fine, but had one problem. As the ring buffer would allocate one page at a time, it could take up all memory in the system before it failed to allocate and free that memory. If the allocation is happening and the ring buffer allocates all memory and then tries to take more than available, its allocation will not trigger an OOM, but if there's any allocation that happens someplace else, that could trigger an OOM, even though once the ring buffer's allocation fails, it would free up all the previous memory it tried to allocate, and allow other memory allocations to succeed. Commit d02bd27bd33dd ("mm/page_alloc.c: calculate 'available' memory in a separate function") separated out si_mem_availble() as a separate function that could be used to see how much memory is available in the system. Using this function to make sure that the ring buffer could be allocated before it tries to allocate pages we can avoid allocating all memory in the system and making it vulnerable to OOMs if other allocations are taking place. Link: http://lkml.kernel.org/r/1522320104-6573-1-git-send-email-zhaoyang.huang@spreadtrum.com CC: stable@vger.kernel.org Cc: linux-mm@kvack.org Fixes: 848618857d253 ("tracing/ring_buffer: Try harder to allocate") Requires: d02bd27bd33dd ("mm/page_alloc.c: calculate 'available' memory in a separate function") Reported-by: Zhaoyang Huang Tested-by: Joel Fernandes Signed-off-by: Steven Rostedt (VMware) Signed-off-by: Greg Kroah-Hartman --- kernel/trace/ring_buffer.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c index 39c221454186..36f018b15392 100644 --- a/kernel/trace/ring_buffer.c +++ b/kernel/trace/ring_buffer.c @@ -1136,6 +1136,11 @@ static int __rb_allocate_pages(long nr_pages, struct list_head *pages, int cpu) struct buffer_page *bpage, *tmp; long i; + /* Check if the available memory is there first */ + i = si_mem_available(); + if (i < nr_pages) + return -ENOMEM; + for (i = 0; i < nr_pages; i++) { struct page *page; /* -- GitLab From f57f3f346d0516fcfcb9bee1df2a2a9f361c4396 Mon Sep 17 00:00:00 2001 From: "Jason A. Donenfeld" Date: Thu, 14 Dec 2017 03:23:37 +0100 Subject: [PATCH 0732/1635] um: Compile with modern headers commit 530ba6c7cb3c22435a4d26de47037bb6f86a5329 upstream. Recent libcs have gotten a bit more strict, so we actually need to include the right headers and use the right types. This enables UML to compile again. Signed-off-by: Jason A. Donenfeld Cc: stable@vger.kernel.org Signed-off-by: Richard Weinberger Signed-off-by: Greg Kroah-Hartman --- arch/um/os-Linux/file.c | 1 + arch/um/os-Linux/signal.c | 1 + arch/x86/um/stub_segv.c | 1 + 3 files changed, 3 insertions(+) diff --git a/arch/um/os-Linux/file.c b/arch/um/os-Linux/file.c index 2db18cbbb0ea..c0197097c86e 100644 --- a/arch/um/os-Linux/file.c +++ b/arch/um/os-Linux/file.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include diff --git a/arch/um/os-Linux/signal.c b/arch/um/os-Linux/signal.c index a86d7cc2c2d8..fa29e92a16d1 100644 --- a/arch/um/os-Linux/signal.c +++ b/arch/um/os-Linux/signal.c @@ -16,6 +16,7 @@ #include #include #include +#include void (*sig_info[NSIG])(int, struct siginfo *, struct uml_pt_regs *) = { [SIGTRAP] = relay_signal, diff --git a/arch/x86/um/stub_segv.c b/arch/x86/um/stub_segv.c index 1518d2805ae8..41780110252e 100644 --- a/arch/x86/um/stub_segv.c +++ b/arch/x86/um/stub_segv.c @@ -6,6 +6,7 @@ #include #include #include +#include void __attribute__ ((__section__ (".__syscall_stub"))) stub_segv_handler(int sig, siginfo_t *info, void *p) -- GitLab From 5a999c2bef6880909901b5c56c81b920f89ed72f Mon Sep 17 00:00:00 2001 From: Krzysztof Mazur Date: Wed, 15 Nov 2017 11:12:39 +0100 Subject: [PATCH 0733/1635] um: Use POSIX ucontext_t instead of struct ucontext commit 4d1a535b8ec5e74b42dfd9dc809142653b2597f6 upstream. glibc 2.26 removed the 'struct ucontext' to "improve" POSIX compliance and break programs, including User Mode Linux. Fix User Mode Linux by using POSIX ucontext_t. This fixes: arch/um/os-Linux/signal.c: In function 'hard_handler': arch/um/os-Linux/signal.c:163:22: error: dereferencing pointer to incomplete type 'struct ucontext' mcontext_t *mc = &uc->uc_mcontext; arch/x86/um/stub_segv.c: In function 'stub_segv_handler': arch/x86/um/stub_segv.c:16:13: error: dereferencing pointer to incomplete type 'struct ucontext' &uc->uc_mcontext); Cc: stable@vger.kernel.org Signed-off-by: Krzysztof Mazur Signed-off-by: Richard Weinberger Signed-off-by: Greg Kroah-Hartman --- arch/um/os-Linux/signal.c | 2 +- arch/x86/um/stub_segv.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/um/os-Linux/signal.c b/arch/um/os-Linux/signal.c index fa29e92a16d1..bf0acb8aad8b 100644 --- a/arch/um/os-Linux/signal.c +++ b/arch/um/os-Linux/signal.c @@ -160,7 +160,7 @@ static void (*handlers[_NSIG])(int sig, struct siginfo *si, mcontext_t *mc) = { static void hard_handler(int sig, siginfo_t *si, void *p) { - struct ucontext *uc = p; + ucontext_t *uc = p; mcontext_t *mc = &uc->uc_mcontext; unsigned long pending = 1UL << sig; diff --git a/arch/x86/um/stub_segv.c b/arch/x86/um/stub_segv.c index 41780110252e..27361cbb7ca9 100644 --- a/arch/x86/um/stub_segv.c +++ b/arch/x86/um/stub_segv.c @@ -11,7 +11,7 @@ void __attribute__ ((__section__ (".__syscall_stub"))) stub_segv_handler(int sig, siginfo_t *info, void *p) { - struct ucontext *uc = p; + ucontext_t *uc = p; GET_FAULTINFO_FROM_MC(*((struct faultinfo *) STUB_DATA), &uc->uc_mcontext); -- GitLab From 180d28f824ce68022a4600300e3b5bc98c3c0661 Mon Sep 17 00:00:00 2001 From: Lu Baolu Date: Sat, 24 Feb 2018 13:42:27 +0800 Subject: [PATCH 0734/1635] iommu/vt-d: Fix a potential memory leak commit bbe4b3af9d9e3172fb9aa1f8dcdfaedcb381fc64 upstream. A memory block was allocated in intel_svm_bind_mm() but never freed in a failure path. This patch fixes this by free it to avoid memory leakage. Cc: Ashok Raj Cc: Jacob Pan Cc: # v4.4+ Signed-off-by: Lu Baolu Fixes: 2f26e0a9c9860 ('iommu/vt-d: Add basic SVM PASID support') Signed-off-by: Joerg Roedel Signed-off-by: Greg Kroah-Hartman --- drivers/iommu/intel-svm.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/iommu/intel-svm.c b/drivers/iommu/intel-svm.c index 003b4a4d4b78..d7def26ccf79 100644 --- a/drivers/iommu/intel-svm.c +++ b/drivers/iommu/intel-svm.c @@ -382,6 +382,7 @@ int intel_svm_bind_mm(struct device *dev, int *pasid, int flags, struct svm_dev_ pasid_max - 1, GFP_KERNEL); if (ret < 0) { kfree(svm); + kfree(sdev); goto out; } svm->pasid = ret; -- GitLab From e5e2841e20ff7d6bc5c886a0aa46c8623a0afe63 Mon Sep 17 00:00:00 2001 From: Alex Smith Date: Wed, 28 Mar 2018 18:00:43 -0300 Subject: [PATCH 0735/1635] mmc: jz4740: Fix race condition in IRQ mask update commit a04f0017c22453613d5f423326b190c61e3b4f98 upstream. A spinlock is held while updating the internal copy of the IRQ mask, but not while writing it to the actual IMASK register. After the lock is released, an IRQ can occur before the IMASK register is written. If handling this IRQ causes the mask to be changed, when the handler returns back to the middle of the first mask update, a stale value will be written to the mask register. If this causes an IRQ to become unmasked that cannot have its status cleared by writing a 1 to it in the IREG register, e.g. the SDIO IRQ, then we can end up stuck with the same IRQ repeatedly being fired but not handled. Normally the MMC IRQ handler attempts to clear any unexpected IRQs by writing IREG, but for those that cannot be cleared in this way then the IRQ will just repeatedly fire. This was resulting in lockups after a while of using Wi-Fi on the CI20 (GitHub issue #19). Resolve by holding the spinlock until after the IMASK register has been updated. Cc: stable@vger.kernel.org Link: https://github.com/MIPS/CI20_linux/issues/19 Fixes: 61bfbdb85687 ("MMC: Add support for the controller on JZ4740 SoCs.") Tested-by: Mathieu Malaterre Signed-off-by: Alex Smith Signed-off-by: Ulf Hansson Signed-off-by: Greg Kroah-Hartman --- drivers/mmc/host/jz4740_mmc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mmc/host/jz4740_mmc.c b/drivers/mmc/host/jz4740_mmc.c index 7db8c7a8d38d..48b67f552afe 100644 --- a/drivers/mmc/host/jz4740_mmc.c +++ b/drivers/mmc/host/jz4740_mmc.c @@ -362,9 +362,9 @@ static void jz4740_mmc_set_irq_enabled(struct jz4740_mmc_host *host, host->irq_mask &= ~irq; else host->irq_mask |= irq; - spin_unlock_irqrestore(&host->lock, flags); writew(host->irq_mask, host->base + JZ_REG_MMC_IMASK); + spin_unlock_irqrestore(&host->lock, flags); } static void jz4740_mmc_clock_enable(struct jz4740_mmc_host *host, -- GitLab From 4b684fbbc58ed048a2da5e21e94eec8c98c3c914 Mon Sep 17 00:00:00 2001 From: Masaharu Hayakawa Date: Tue, 3 Apr 2018 23:57:03 +0200 Subject: [PATCH 0736/1635] mmc: tmio: Fix error handling when issuing CMD23 commit fc167daff581c01ebce8695e9618231cae3561a1 upstream. If an error was detected when CMD23 was issued, command sequence should be terminated with errors and CMD23 should be issued after retuning. Fixes: 8b22c3c18be5 ("mmc: tmio: add CMD23 support") Signed-off-by: Masaharu Hayakawa Signed-off-by: Wolfram Sang Cc: # 4.13+ Signed-off-by: Ulf Hansson Signed-off-by: Greg Kroah-Hartman --- drivers/mmc/host/tmio_mmc_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mmc/host/tmio_mmc_core.c b/drivers/mmc/host/tmio_mmc_core.c index 3a6d49f07e22..de1562f27fdb 100644 --- a/drivers/mmc/host/tmio_mmc_core.c +++ b/drivers/mmc/host/tmio_mmc_core.c @@ -911,7 +911,7 @@ static void tmio_mmc_finish_request(struct tmio_mmc_host *host) host->check_scc_error(host); /* If SET_BLOCK_COUNT, continue with main command */ - if (host->mrq) { + if (host->mrq && !mrq->cmd->error) { tmio_process_mrq(host, mrq); return; } -- GitLab From f13b4a61989fb29e16adba2ed2e073ffed301f40 Mon Sep 17 00:00:00 2001 From: Sinan Kaya Date: Tue, 10 Apr 2018 14:44:21 -0500 Subject: [PATCH 0737/1635] PCI: Mark Broadcom HT1100 and HT2000 Root Port Extended Tags as broken commit 1b30dfd376e28e7f37eda5e2033f6823cdda222b upstream. Per PCIe r3.1, sec 2.2.6.2 and 7.8.4, a Requester may not use 8-bit Tags unless its Extended Tag Field Enable is set, but all Receivers/Completers must handle 8-bit Tags correctly regardless of their Extended Tag Field Enable. Some devices do not handle 8-bit Tags as Completers, so add a quirk for them. If we find such a device, we disable Extended Tags for the entire hierarchy to make peer-to-peer DMA possible. The Broadcom HT1100/HT2000/HT2100 seems to have issues with handling 8-bit tags. Mark it as broken. This fixes Xorg hangs and unresponsive keyboards with errors like this: radeon 0000:06:00.0: GPU lockup (current fence id 0x000000000000000e last fence id 0x0000000000000 [drm:r600_ring_test [radeon]] *ERROR* radeon: ring 0 test failed (scratch(0x8504)=0xCAFEDEAD) [drm:r600_resume [radeon]] *ERROR* r600 startup failed on resume Fixes: 60db3a4d8cc9 ("PCI: Enable PCIe Extended Tags if supported") Link: https://bugzilla.kernel.org/show_bug.cgi?id=196197 Signed-off-by: Sinan Kaya Signed-off-by: Bjorn Helgaas CC: stable@vger.kernel.org # v4.11: 62ce94a7a5a5 PCI: Mark Broadcom HT2100 Root Port Extended Tags as broken CC: stable@vger.kernel.org # v4.11 Signed-off-by: Greg Kroah-Hartman --- drivers/pci/quirks.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 05fadcc4f9d2..5c5a8af66829 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -4806,9 +4806,13 @@ static void quirk_no_ext_tags(struct pci_dev *pdev) pci_walk_bus(bridge->bus, pci_configure_extended_tags, NULL); } +DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SERVERWORKS, 0x0132, quirk_no_ext_tags); DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SERVERWORKS, 0x0140, quirk_no_ext_tags); +DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SERVERWORKS, 0x0141, quirk_no_ext_tags); DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SERVERWORKS, 0x0142, quirk_no_ext_tags); DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SERVERWORKS, 0x0144, quirk_no_ext_tags); +DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SERVERWORKS, 0x0420, quirk_no_ext_tags); +DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SERVERWORKS, 0x0422, quirk_no_ext_tags); #ifdef CONFIG_PCI_ATS /* -- GitLab From 37d8947c0b073a27198ae477d8a8a8b6cda61abf Mon Sep 17 00:00:00 2001 From: Richard Genoud Date: Tue, 13 Mar 2018 16:27:02 +0100 Subject: [PATCH 0738/1635] clk: mvebu: armada-38x: add support for missing clocks commit 6a4a4595804548e173f0763a0e7274a3521c59a9 upstream. Clearfog boards can come with a CPU clocked at 1600MHz (commercial) or 1333MHz (industrial). They have also some dip-switches to select a different clock (666, 800, 1066, 1200). The funny thing is that the recovery button is on the MPP34 fq selector. So, when booting an industrial board with this button down, the frequency 666MHz is selected (and the kernel didn't boot). This patch add all the missing clocks. The only mode I didn't test is 2GHz (uboot found 4294MHz instead :/ ). Fixes: 0e85aeced4d6 ("clk: mvebu: add clock support for Armada 380/385") Cc: # 3.16.x: 9593f4f56cf5: clk: mvebu: armada-38x: add support for 1866MHz variants Cc: # 3.16.x Signed-off-by: Richard Genoud Acked-by: Gregory CLEMENT Signed-off-by: Stephen Boyd Signed-off-by: Greg Kroah-Hartman --- drivers/clk/mvebu/armada-38x.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/clk/mvebu/armada-38x.c b/drivers/clk/mvebu/armada-38x.c index 394aa6f03f01..9ff4ea63932d 100644 --- a/drivers/clk/mvebu/armada-38x.c +++ b/drivers/clk/mvebu/armada-38x.c @@ -46,11 +46,11 @@ static u32 __init armada_38x_get_tclk_freq(void __iomem *sar) } static const u32 armada_38x_cpu_frequencies[] __initconst = { - 0, 0, 0, 0, - 1066 * 1000 * 1000, 0, 0, 0, + 666 * 1000 * 1000, 0, 800 * 1000 * 1000, 0, + 1066 * 1000 * 1000, 0, 1200 * 1000 * 1000, 0, 1332 * 1000 * 1000, 0, 0, 0, 1600 * 1000 * 1000, 0, 0, 0, - 1866 * 1000 * 1000, + 1866 * 1000 * 1000, 0, 0, 2000 * 1000 * 1000, }; static u32 __init armada_38x_get_cpu_freq(void __iomem *sar) @@ -76,11 +76,11 @@ static const struct coreclk_ratio armada_38x_coreclk_ratios[] __initconst = { }; static const int armada_38x_cpu_l2_ratios[32][2] __initconst = { - {0, 1}, {0, 1}, {0, 1}, {0, 1}, - {1, 2}, {0, 1}, {0, 1}, {0, 1}, - {1, 2}, {0, 1}, {0, 1}, {0, 1}, + {1, 2}, {0, 1}, {1, 2}, {0, 1}, + {1, 2}, {0, 1}, {1, 2}, {0, 1}, {1, 2}, {0, 1}, {0, 1}, {0, 1}, {1, 2}, {0, 1}, {0, 1}, {0, 1}, + {1, 2}, {0, 1}, {0, 1}, {1, 2}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, @@ -91,7 +91,7 @@ static const int armada_38x_cpu_ddr_ratios[32][2] __initconst = { {1, 2}, {0, 1}, {0, 1}, {0, 1}, {1, 2}, {0, 1}, {0, 1}, {0, 1}, {1, 2}, {0, 1}, {0, 1}, {0, 1}, - {1, 2}, {0, 1}, {0, 1}, {0, 1}, + {1, 2}, {0, 1}, {0, 1}, {7, 15}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, -- GitLab From d8b6fdbe513d2f68d93dd07af4df1b65254408e1 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Fri, 16 Feb 2018 16:27:47 +0100 Subject: [PATCH 0739/1635] clk: fix false-positive Wmaybe-uninitialized warning commit ce33f284935e08229046b30635e6aadcbab02b53 upstream. When we build this driver with on x86-32, gcc produces a false-positive warning: drivers/clk/renesas/clk-sh73a0.c: In function 'sh73a0_cpg_clocks_init': drivers/clk/renesas/clk-sh73a0.c:155:10: error: 'parent_name' may be used uninitialized in this function [-Werror=maybe-uninitialized] return clk_register_fixed_factor(NULL, name, parent_name, 0, We can work around that warning by adding a fake initialization, I tried and failed to come up with any better workaround. This is currently one of few remaining warnings for a 4.14.y randconfig build, so it would be good to also have it backported at least to that version. Older versions have more randconfig warnings, so we might not care. I had not noticed this earlier, because one patch in my randconfig test tree removes the '-ffreestanding' option on x86-32, and that avoids the warning. The -ffreestanding flag was originally global but moved into arch/i386 by Andi Kleen in commit 6edfba1b33c7 ("[PATCH] x86_64: Don't define string functions to builtin") as a 'temporary workaround'. Like many temporary hacks, this turned out to be rather long-lived, from all I can tell we still need a simple fix to asm/string_32.h before it can be removed, but I'm not sure about how to best do that. Cc: stable@vger.kernel.org Cc: Andi Kleen Signed-off-by: Arnd Bergmann Acked-by: Geert Uytterhoeven Signed-off-by: Stephen Boyd Signed-off-by: Greg Kroah-Hartman --- drivers/clk/renesas/clk-sh73a0.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/clk/renesas/clk-sh73a0.c b/drivers/clk/renesas/clk-sh73a0.c index eea38f6ea77e..3892346c4fcc 100644 --- a/drivers/clk/renesas/clk-sh73a0.c +++ b/drivers/clk/renesas/clk-sh73a0.c @@ -46,7 +46,7 @@ struct div4_clk { unsigned int shift; }; -static struct div4_clk div4_clks[] = { +static const struct div4_clk div4_clks[] = { { "zg", "pll0", CPG_FRQCRA, 16 }, { "m3", "pll1", CPG_FRQCRA, 12 }, { "b", "pll1", CPG_FRQCRA, 8 }, @@ -79,7 +79,7 @@ sh73a0_cpg_register_clock(struct device_node *np, struct sh73a0_cpg *cpg, { const struct clk_div_table *table = NULL; unsigned int shift, reg, width; - const char *parent_name; + const char *parent_name = NULL; unsigned int mult = 1; unsigned int div = 1; @@ -135,7 +135,7 @@ sh73a0_cpg_register_clock(struct device_node *np, struct sh73a0_cpg *cpg, shift = 24; width = 5; } else { - struct div4_clk *c; + const struct div4_clk *c; for (c = div4_clks; c->name; c++) { if (!strcmp(name, c->name)) { -- GitLab From dc7a428ae26f7711be24c484b9b793853734b44a Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Thu, 1 Mar 2018 11:27:51 +0800 Subject: [PATCH 0740/1635] clk: mediatek: fix PWM clock source by adding a fixed-factor clock commit 89cd7aec21af26fd0c117bfc4bfc781724f201de upstream. The clock for which all PWM devices on MT7623 or MT2701 actually depending on has to be divided by four from its parent clock axi_sel in the clock path prior to PWM devices. Consequently, adding a fixed-factor clock axisel_d4 as one-fourth of clock axi_sel allows that PWM devices can have the correct resolution calculation. Cc: stable@vger.kernel.org Fixes: e9862118272a ("clk: mediatek: Add MT2701 clock support") Signed-off-by: Sean Wang Signed-off-by: Stephen Boyd Signed-off-by: Greg Kroah-Hartman --- drivers/clk/mediatek/clk-mt2701.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/drivers/clk/mediatek/clk-mt2701.c b/drivers/clk/mediatek/clk-mt2701.c index 9598889f972b..ccfe5d30fe10 100644 --- a/drivers/clk/mediatek/clk-mt2701.c +++ b/drivers/clk/mediatek/clk-mt2701.c @@ -148,6 +148,7 @@ static const struct mtk_fixed_factor top_fixed_divs[] = { FACTOR(CLK_TOP_CLK26M_D8, "clk26m_d8", "clk26m", 1, 8), FACTOR(CLK_TOP_32K_INTERNAL, "32k_internal", "clk26m", 1, 793), FACTOR(CLK_TOP_32K_EXTERNAL, "32k_external", "rtc32k", 1, 1), + FACTOR(CLK_TOP_AXISEL_D4, "axisel_d4", "axi_sel", 1, 4), }; static const char * const axi_parents[] = { @@ -857,13 +858,13 @@ static const struct mtk_gate peri_clks[] = { GATE_PERI0(CLK_PERI_USB1, "usb1_ck", "usb20_sel", 11), GATE_PERI0(CLK_PERI_USB0, "usb0_ck", "usb20_sel", 10), GATE_PERI0(CLK_PERI_PWM, "pwm_ck", "axi_sel", 9), - GATE_PERI0(CLK_PERI_PWM7, "pwm7_ck", "axi_sel", 8), - GATE_PERI0(CLK_PERI_PWM6, "pwm6_ck", "axi_sel", 7), - GATE_PERI0(CLK_PERI_PWM5, "pwm5_ck", "axi_sel", 6), - GATE_PERI0(CLK_PERI_PWM4, "pwm4_ck", "axi_sel", 5), - GATE_PERI0(CLK_PERI_PWM3, "pwm3_ck", "axi_sel", 4), - GATE_PERI0(CLK_PERI_PWM2, "pwm2_ck", "axi_sel", 3), - GATE_PERI0(CLK_PERI_PWM1, "pwm1_ck", "axi_sel", 2), + GATE_PERI0(CLK_PERI_PWM7, "pwm7_ck", "axisel_d4", 8), + GATE_PERI0(CLK_PERI_PWM6, "pwm6_ck", "axisel_d4", 7), + GATE_PERI0(CLK_PERI_PWM5, "pwm5_ck", "axisel_d4", 6), + GATE_PERI0(CLK_PERI_PWM4, "pwm4_ck", "axisel_d4", 5), + GATE_PERI0(CLK_PERI_PWM3, "pwm3_ck", "axisel_d4", 4), + GATE_PERI0(CLK_PERI_PWM2, "pwm2_ck", "axisel_d4", 3), + GATE_PERI0(CLK_PERI_PWM1, "pwm1_ck", "axisel_d4", 2), GATE_PERI0(CLK_PERI_THERM, "therm_ck", "axi_sel", 1), GATE_PERI0(CLK_PERI_NFI, "nfi_ck", "nfi2x_sel", 0), -- GitLab From ff18ffb1f81db091e916bb3afc4a264219f840ea Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Thu, 22 Mar 2018 10:11:30 +0100 Subject: [PATCH 0741/1635] clk: bcm2835: De-assert/assert PLL reset signal when appropriate commit 753872373b599384ac7df809aa61ea12d1c4d5d1 upstream. In order to enable a PLL, not only the PLL has to be powered up and locked, but you also have to de-assert the reset signal. The last part was missing. Add it so PLLs that were not enabled by the FW/bootloader can be enabled from Linux. Fixes: 41691b8862e2 ("clk: bcm2835: Add support for programming the audio domain clocks") Cc: Signed-off-by: Boris Brezillon Reviewed-by: Eric Anholt Signed-off-by: Stephen Boyd Signed-off-by: Greg Kroah-Hartman --- drivers/clk/bcm/clk-bcm2835.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/clk/bcm/clk-bcm2835.c b/drivers/clk/bcm/clk-bcm2835.c index eec52734d6ac..5f8082d89131 100644 --- a/drivers/clk/bcm/clk-bcm2835.c +++ b/drivers/clk/bcm/clk-bcm2835.c @@ -632,9 +632,7 @@ static void bcm2835_pll_off(struct clk_hw *hw) const struct bcm2835_pll_data *data = pll->data; spin_lock(&cprman->regs_lock); - cprman_write(cprman, data->cm_ctrl_reg, - cprman_read(cprman, data->cm_ctrl_reg) | - CM_PLL_ANARST); + cprman_write(cprman, data->cm_ctrl_reg, CM_PLL_ANARST); cprman_write(cprman, data->a2w_ctrl_reg, cprman_read(cprman, data->a2w_ctrl_reg) | A2W_PLL_CTRL_PWRDN); @@ -670,6 +668,10 @@ static int bcm2835_pll_on(struct clk_hw *hw) cpu_relax(); } + cprman_write(cprman, data->a2w_ctrl_reg, + cprman_read(cprman, data->a2w_ctrl_reg) | + A2W_PLL_CTRL_PRST_DISABLE); + return 0; } -- GitLab From c9b200ce2be5da7613e73daf356bd0ae63c0a48d Mon Sep 17 00:00:00 2001 From: Ryo Kodama Date: Fri, 9 Mar 2018 20:24:21 +0900 Subject: [PATCH 0742/1635] pwm: rcar: Fix a condition to prevent mismatch value setting to duty commit 6225f9c64b40bc8a22503e9cda70f55d7a9dd3c6 upstream. This patch fixes an issue that is possible to set mismatch value to duty for R-Car PWM if we input the following commands: # cd /sys/class/pwm// # echo 0 > export # cd pwm0 # echo 30 > period # echo 30 > duty_cycle # echo 0 > duty_cycle # cat duty_cycle 0 # echo 1 > enable --> Then, the actual duty_cycle is 30, not 0. So, this patch adds a condition into rcar_pwm_config() to fix this issue. Signed-off-by: Ryo Kodama [shimoda: revise the commit log and add Fixes and Cc tags] Fixes: ed6c1476bf7f ("pwm: Add support for R-Car PWM Timer") Cc: Cc: # v4.4+ Signed-off-by: Yoshihiro Shimoda Signed-off-by: Thierry Reding Signed-off-by: Greg Kroah-Hartman --- drivers/pwm/pwm-rcar.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/pwm/pwm-rcar.c b/drivers/pwm/pwm-rcar.c index 1c85ecc9e7ac..0fcf94ffad32 100644 --- a/drivers/pwm/pwm-rcar.c +++ b/drivers/pwm/pwm-rcar.c @@ -156,8 +156,12 @@ static int rcar_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, if (div < 0) return div; - /* Let the core driver set pwm->period if disabled and duty_ns == 0 */ - if (!pwm_is_enabled(pwm) && !duty_ns) + /* + * Let the core driver set pwm->period if disabled and duty_ns == 0. + * But, this driver should prevent to set the new duty_ns if current + * duty_cycle is not set + */ + if (!pwm_is_enabled(pwm) && !duty_ns && !pwm->state.duty_cycle) return 0; rcar_pwm_update(rp, RCAR_PWMCR_SYNC, RCAR_PWMCR_SYNC, RCAR_PWMCR); -- GitLab From ecb67e92d42e1fbbb710c9c86259ba4ef0839304 Mon Sep 17 00:00:00 2001 From: Mikhail Lappo Date: Fri, 2 Feb 2018 16:17:46 -0200 Subject: [PATCH 0743/1635] thermal: imx: Fix race condition in imx_thermal_probe() commit cf1ba1d73a33944d8c1a75370a35434bf146b8a7 upstream. When device boots with T > T_trip_1 and requests interrupt, the race condition takes place. The interrupt comes before THERMAL_DEVICE_ENABLED is set. This leads to an attempt to reading sensor value from irq and disabling the sensor, based on the data->mode field, which expected to be THERMAL_DEVICE_ENABLED, but still stays as THERMAL_DEVICE_DISABLED. Afher this issue sensor is never re-enabled, as the driver state is wrong. Fix this problem by setting the 'data' members prior to requesting the interrupts. Fixes: 37713a1e8e4c ("thermal: imx: implement thermal alarm interrupt handling") Cc: Signed-off-by: Mikhail Lappo Signed-off-by: Fabio Estevam Reviewed-by: Philipp Zabel Acked-by: Dong Aisheng Signed-off-by: Zhang Rui Signed-off-by: Greg Kroah-Hartman --- drivers/thermal/imx_thermal.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/thermal/imx_thermal.c b/drivers/thermal/imx_thermal.c index 4798b4b1fd77..41c6154ae856 100644 --- a/drivers/thermal/imx_thermal.c +++ b/drivers/thermal/imx_thermal.c @@ -601,6 +601,9 @@ static int imx_thermal_probe(struct platform_device *pdev) regmap_write(map, TEMPSENSE0 + REG_CLR, TEMPSENSE0_POWER_DOWN); regmap_write(map, TEMPSENSE0 + REG_SET, TEMPSENSE0_MEASURE_TEMP); + data->irq_enabled = true; + data->mode = THERMAL_DEVICE_ENABLED; + ret = devm_request_threaded_irq(&pdev->dev, data->irq, imx_thermal_alarm_irq, imx_thermal_alarm_irq_thread, 0, "imx_thermal", data); @@ -613,9 +616,6 @@ static int imx_thermal_probe(struct platform_device *pdev) return ret; } - data->irq_enabled = true; - data->mode = THERMAL_DEVICE_ENABLED; - return 0; } -- GitLab From 28fe0fba29f20d1301ae2183d424bcf6a46c0ca8 Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Thu, 1 Mar 2018 11:27:50 +0800 Subject: [PATCH 0744/1635] dt-bindings: clock: mediatek: add binding for fixed-factor clock axisel_d4 commit 55a5fcafe3a94e8a0777bb993d09107d362258d2 upstream. Just add binding for a fixed-factor clock axisel_d4, which would be referenced by PWM devices on MT7623 or MT2701 SoC. Cc: stable@vger.kernel.org Fixes: 1de9b21633d6 ("clk: mediatek: Add dt-bindings for MT2701 clocks") Signed-off-by: Sean Wang Reviewed-by: Rob Herring Cc: Mark Rutland Cc: devicetree@vger.kernel.org Signed-off-by: Stephen Boyd Signed-off-by: Greg Kroah-Hartman --- include/dt-bindings/clock/mt2701-clk.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/dt-bindings/clock/mt2701-clk.h b/include/dt-bindings/clock/mt2701-clk.h index 551f7600ab58..24e93dfcee9f 100644 --- a/include/dt-bindings/clock/mt2701-clk.h +++ b/include/dt-bindings/clock/mt2701-clk.h @@ -176,7 +176,8 @@ #define CLK_TOP_AUD_EXT1 156 #define CLK_TOP_AUD_EXT2 157 #define CLK_TOP_NFI1X_PAD 158 -#define CLK_TOP_NR 159 +#define CLK_TOP_AXISEL_D4 159 +#define CLK_TOP_NR 160 /* APMIXEDSYS */ -- GitLab From 23a63d96e015d56fc69f527a012625c5b8f346e5 Mon Sep 17 00:00:00 2001 From: Igor Pylypiv Date: Tue, 6 Mar 2018 23:47:25 -0800 Subject: [PATCH 0745/1635] watchdog: f71808e_wdt: Fix WD_EN register read commit 977f6f68331f94bb72ad84ee96b7b87ce737d89d upstream. F71808FG_FLAG_WD_EN defines bit position, not a bitmask Signed-off-by: Igor Pylypiv Reviewed-by: Guenter Roeck Signed-off-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/watchdog/f71808e_wdt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/watchdog/f71808e_wdt.c b/drivers/watchdog/f71808e_wdt.c index 8658dba21768..e682bf046e50 100644 --- a/drivers/watchdog/f71808e_wdt.c +++ b/drivers/watchdog/f71808e_wdt.c @@ -496,7 +496,7 @@ static bool watchdog_is_running(void) is_running = (superio_inb(watchdog.sioaddr, SIO_REG_ENABLE) & BIT(0)) && (superio_inb(watchdog.sioaddr, F71808FG_REG_WDT_CONF) - & F71808FG_FLAG_WD_EN); + & BIT(F71808FG_FLAG_WD_EN)); superio_exit(watchdog.sioaddr); -- GitLab From 2ccdea040e81553aaaa9f380f0ff745f71d27eff Mon Sep 17 00:00:00 2001 From: Alex Williamson Date: Mon, 2 Oct 2017 12:39:10 -0600 Subject: [PATCH 0746/1635] vfio/pci: Virtualize Maximum Read Request Size commit cf0d53ba4947aad6e471491d5b20a567cbe92e56 upstream. MRRS defines the maximum read request size a device is allowed to make. Drivers will often increase this to allow more data transfer with a single request. Completions to this request are bound by the MPS setting for the bus. Aside from device quirks (none known), it doesn't seem to make sense to set an MRRS value less than MPS, yet this is a likely scenario given that user drivers do not have a system-wide view of the PCI topology. Virtualize MRRS such that the user can set MRRS >= MPS, but use MPS as the floor value that we'll write to hardware. Signed-off-by: Alex Williamson Signed-off-by: Greg Kroah-Hartman --- drivers/vfio/pci/vfio_pci_config.c | 29 ++++++++++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/drivers/vfio/pci/vfio_pci_config.c b/drivers/vfio/pci/vfio_pci_config.c index 91335e6de88a..115a36f6f403 100644 --- a/drivers/vfio/pci/vfio_pci_config.c +++ b/drivers/vfio/pci/vfio_pci_config.c @@ -808,6 +808,7 @@ static int vfio_exp_config_write(struct vfio_pci_device *vdev, int pos, { __le16 *ctrl = (__le16 *)(vdev->vconfig + pos - offset + PCI_EXP_DEVCTL); + int readrq = le16_to_cpu(*ctrl) & PCI_EXP_DEVCTL_READRQ; count = vfio_default_config_write(vdev, pos, count, perm, offset, val); if (count < 0) @@ -833,6 +834,27 @@ static int vfio_exp_config_write(struct vfio_pci_device *vdev, int pos, pci_try_reset_function(vdev->pdev); } + /* + * MPS is virtualized to the user, writes do not change the physical + * register since determining a proper MPS value requires a system wide + * device view. The MRRS is largely independent of MPS, but since the + * user does not have that system-wide view, they might set a safe, but + * inefficiently low value. Here we allow writes through to hardware, + * but we set the floor to the physical device MPS setting, so that + * we can at least use full TLPs, as defined by the MPS value. + * + * NB, if any devices actually depend on an artificially low MRRS + * setting, this will need to be revisited, perhaps with a quirk + * though pcie_set_readrq(). + */ + if (readrq != (le16_to_cpu(*ctrl) & PCI_EXP_DEVCTL_READRQ)) { + readrq = 128 << + ((le16_to_cpu(*ctrl) & PCI_EXP_DEVCTL_READRQ) >> 12); + readrq = max(readrq, pcie_get_mps(vdev->pdev)); + + pcie_set_readrq(vdev->pdev, readrq); + } + return count; } @@ -851,11 +873,12 @@ static int __init init_pci_cap_exp_perm(struct perm_bits *perm) * Allow writes to device control fields, except devctl_phantom, * which could confuse IOMMU, MPS, which can break communication * with other physical devices, and the ARI bit in devctl2, which - * is set at probe time. FLR gets virtualized via our writefn. + * is set at probe time. FLR and MRRS get virtualized via our + * writefn. */ p_setw(perm, PCI_EXP_DEVCTL, - PCI_EXP_DEVCTL_BCR_FLR | PCI_EXP_DEVCTL_PAYLOAD, - ~PCI_EXP_DEVCTL_PHANTOM); + PCI_EXP_DEVCTL_BCR_FLR | PCI_EXP_DEVCTL_PAYLOAD | + PCI_EXP_DEVCTL_READRQ, ~PCI_EXP_DEVCTL_PHANTOM); p_setw(perm, PCI_EXP_DEVCTL2, NO_VIRT, ~PCI_EXP_DEVCTL2_ARI); return 0; } -- GitLab From 4d2ea307ffa16644127ba09de30cfb31f3f40c4a Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 9 Jan 2018 08:51:02 +0100 Subject: [PATCH 0747/1635] ALSA: pcm: Use ERESTARTSYS instead of EINTR in OSS emulation commit c64ed5dd9feba193c76eb460b451225ac2a0d87b upstream. Fix the last standing EINTR in the whole subsystem. Use more correct ERESTARTSYS for pending signals. Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/core/oss/pcm_oss.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c index d6e9a18fd821..1bee2404edbc 100644 --- a/sound/core/oss/pcm_oss.c +++ b/sound/core/oss/pcm_oss.c @@ -842,7 +842,7 @@ static int snd_pcm_oss_change_params(struct snd_pcm_substream *substream, if (!(mutex_trylock(&runtime->oss.params_lock))) return -EAGAIN; } else if (mutex_lock_interruptible(&runtime->oss.params_lock)) - return -EINTR; + return -ERESTARTSYS; sw_params = kzalloc(sizeof(*sw_params), GFP_KERNEL); params = kmalloc(sizeof(*params), GFP_KERNEL); sparams = kmalloc(sizeof(*sparams), GFP_KERNEL); -- GitLab From bd889a82fb01365ca0c364166d4defad3253248c Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 22 Mar 2018 18:10:14 +0100 Subject: [PATCH 0748/1635] ALSA: pcm: Avoid potential races between OSS ioctls and read/write commit 02a5d6925cd34c3b774bdb8eefb057c40a30e870 upstream. Although we apply the params_lock mutex to the whole read and write operations as well as snd_pcm_oss_change_params(), we may still face some races. First off, the params_lock is taken inside the read and write loop. This is intentional for avoiding the too long locking, but it allows the in-between parameter change, which might lead to invalid pointers. We check the readiness of the stream and set up via snd_pcm_oss_make_ready() at the beginning of read and write, but it's called only once, by assuming that it remains ready in the rest. Second, many ioctls that may change the actual parameters (i.e. setting runtime->oss.params=1) aren't protected, hence they can be processed in a half-baked state. This patch is an attempt to plug these holes. The stream readiness check is moved inside the read/write inner loop, so that the stream is always set up in a proper state before further processing. Also, each ioctl that may change the parameter is wrapped with the params_lock for avoiding the races. The issues were triggered by syzkaller in a few different scenarios, particularly the one below appearing as GPF in loopback_pos_update. Reported-by: syzbot+c4227aec125487ec3efa@syzkaller.appspotmail.com Cc: Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/core/oss/pcm_oss.c | 134 +++++++++++++++++++++++++++++++-------- 1 file changed, 106 insertions(+), 28 deletions(-) diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c index 1bee2404edbc..c526cef424bd 100644 --- a/sound/core/oss/pcm_oss.c +++ b/sound/core/oss/pcm_oss.c @@ -823,8 +823,8 @@ static int choose_rate(struct snd_pcm_substream *substream, return snd_pcm_hw_param_near(substream, params, SNDRV_PCM_HW_PARAM_RATE, best_rate, NULL); } -static int snd_pcm_oss_change_params(struct snd_pcm_substream *substream, - bool trylock) +/* call with params_lock held */ +static int snd_pcm_oss_change_params_locked(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; struct snd_pcm_hw_params *params, *sparams; @@ -838,11 +838,8 @@ static int snd_pcm_oss_change_params(struct snd_pcm_substream *substream, const struct snd_mask *sformat_mask; struct snd_mask mask; - if (trylock) { - if (!(mutex_trylock(&runtime->oss.params_lock))) - return -EAGAIN; - } else if (mutex_lock_interruptible(&runtime->oss.params_lock)) - return -ERESTARTSYS; + if (!runtime->oss.params) + return 0; sw_params = kzalloc(sizeof(*sw_params), GFP_KERNEL); params = kmalloc(sizeof(*params), GFP_KERNEL); sparams = kmalloc(sizeof(*sparams), GFP_KERNEL); @@ -1068,6 +1065,23 @@ static int snd_pcm_oss_change_params(struct snd_pcm_substream *substream, kfree(sw_params); kfree(params); kfree(sparams); + return err; +} + +/* this one takes the lock by itself */ +static int snd_pcm_oss_change_params(struct snd_pcm_substream *substream, + bool trylock) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + int err; + + if (trylock) { + if (!(mutex_trylock(&runtime->oss.params_lock))) + return -EAGAIN; + } else if (mutex_lock_interruptible(&runtime->oss.params_lock)) + return -ERESTARTSYS; + + err = snd_pcm_oss_change_params_locked(substream); mutex_unlock(&runtime->oss.params_lock); return err; } @@ -1096,11 +1110,14 @@ static int snd_pcm_oss_get_active_substream(struct snd_pcm_oss_file *pcm_oss_fil return 0; } +/* call with params_lock held */ static int snd_pcm_oss_prepare(struct snd_pcm_substream *substream) { int err; struct snd_pcm_runtime *runtime = substream->runtime; + if (!runtime->oss.prepare) + return 0; err = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_PREPARE, NULL); if (err < 0) { pcm_dbg(substream->pcm, @@ -1120,14 +1137,35 @@ static int snd_pcm_oss_make_ready(struct snd_pcm_substream *substream) struct snd_pcm_runtime *runtime; int err; - if (substream == NULL) - return 0; runtime = substream->runtime; if (runtime->oss.params) { err = snd_pcm_oss_change_params(substream, false); if (err < 0) return err; } + if (runtime->oss.prepare) { + if (mutex_lock_interruptible(&runtime->oss.params_lock)) + return -ERESTARTSYS; + err = snd_pcm_oss_prepare(substream); + mutex_unlock(&runtime->oss.params_lock); + if (err < 0) + return err; + } + return 0; +} + +/* call with params_lock held */ +static int snd_pcm_oss_make_ready_locked(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime; + int err; + + runtime = substream->runtime; + if (runtime->oss.params) { + err = snd_pcm_oss_change_params_locked(substream); + if (err < 0) + return err; + } if (runtime->oss.prepare) { err = snd_pcm_oss_prepare(substream); if (err < 0) @@ -1332,13 +1370,14 @@ static ssize_t snd_pcm_oss_write1(struct snd_pcm_substream *substream, const cha if (atomic_read(&substream->mmap_count)) return -ENXIO; - if ((tmp = snd_pcm_oss_make_ready(substream)) < 0) - return tmp; while (bytes > 0) { if (mutex_lock_interruptible(&runtime->oss.params_lock)) { tmp = -ERESTARTSYS; break; } + tmp = snd_pcm_oss_make_ready_locked(substream); + if (tmp < 0) + goto err; if (bytes < runtime->oss.period_bytes || runtime->oss.buffer_used > 0) { tmp = bytes; if (tmp + runtime->oss.buffer_used > runtime->oss.period_bytes) @@ -1439,13 +1478,14 @@ static ssize_t snd_pcm_oss_read1(struct snd_pcm_substream *substream, char __use if (atomic_read(&substream->mmap_count)) return -ENXIO; - if ((tmp = snd_pcm_oss_make_ready(substream)) < 0) - return tmp; while (bytes > 0) { if (mutex_lock_interruptible(&runtime->oss.params_lock)) { tmp = -ERESTARTSYS; break; } + tmp = snd_pcm_oss_make_ready_locked(substream); + if (tmp < 0) + goto err; if (bytes < runtime->oss.period_bytes || runtime->oss.buffer_used > 0) { if (runtime->oss.buffer_used == 0) { tmp = snd_pcm_oss_read2(substream, runtime->oss.buffer, runtime->oss.period_bytes, 1); @@ -1501,10 +1541,12 @@ static int snd_pcm_oss_reset(struct snd_pcm_oss_file *pcm_oss_file) continue; runtime = substream->runtime; snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DROP, NULL); + mutex_lock(&runtime->oss.params_lock); runtime->oss.prepare = 1; runtime->oss.buffer_used = 0; runtime->oss.prev_hw_ptr_period = 0; runtime->oss.period_ptr = 0; + mutex_unlock(&runtime->oss.params_lock); } return 0; } @@ -1590,9 +1632,10 @@ static int snd_pcm_oss_sync(struct snd_pcm_oss_file *pcm_oss_file) goto __direct; if ((err = snd_pcm_oss_make_ready(substream)) < 0) return err; + if (mutex_lock_interruptible(&runtime->oss.params_lock)) + return -ERESTARTSYS; format = snd_pcm_oss_format_from(runtime->oss.format); width = snd_pcm_format_physical_width(format); - mutex_lock(&runtime->oss.params_lock); if (runtime->oss.buffer_used > 0) { #ifdef OSS_DEBUG pcm_dbg(substream->pcm, "sync: buffer_used\n"); @@ -1643,7 +1686,9 @@ static int snd_pcm_oss_sync(struct snd_pcm_oss_file *pcm_oss_file) substream->f_flags = saved_f_flags; if (err < 0) return err; + mutex_lock(&runtime->oss.params_lock); runtime->oss.prepare = 1; + mutex_unlock(&runtime->oss.params_lock); } substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_CAPTURE]; @@ -1654,8 +1699,10 @@ static int snd_pcm_oss_sync(struct snd_pcm_oss_file *pcm_oss_file) err = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DROP, NULL); if (err < 0) return err; + mutex_lock(&runtime->oss.params_lock); runtime->oss.buffer_used = 0; runtime->oss.prepare = 1; + mutex_unlock(&runtime->oss.params_lock); } return 0; } @@ -1674,10 +1721,13 @@ static int snd_pcm_oss_set_rate(struct snd_pcm_oss_file *pcm_oss_file, int rate) rate = 1000; else if (rate > 192000) rate = 192000; + if (mutex_lock_interruptible(&runtime->oss.params_lock)) + return -ERESTARTSYS; if (runtime->oss.rate != rate) { runtime->oss.params = 1; runtime->oss.rate = rate; } + mutex_unlock(&runtime->oss.params_lock); } return snd_pcm_oss_get_rate(pcm_oss_file); } @@ -1705,10 +1755,13 @@ static int snd_pcm_oss_set_channels(struct snd_pcm_oss_file *pcm_oss_file, unsig if (substream == NULL) continue; runtime = substream->runtime; + if (mutex_lock_interruptible(&runtime->oss.params_lock)) + return -ERESTARTSYS; if (runtime->oss.channels != channels) { runtime->oss.params = 1; runtime->oss.channels = channels; } + mutex_unlock(&runtime->oss.params_lock); } return snd_pcm_oss_get_channels(pcm_oss_file); } @@ -1794,10 +1847,13 @@ static int snd_pcm_oss_set_format(struct snd_pcm_oss_file *pcm_oss_file, int for if (substream == NULL) continue; runtime = substream->runtime; + if (mutex_lock_interruptible(&runtime->oss.params_lock)) + return -ERESTARTSYS; if (runtime->oss.format != format) { runtime->oss.params = 1; runtime->oss.format = format; } + mutex_unlock(&runtime->oss.params_lock); } } return snd_pcm_oss_get_format(pcm_oss_file); @@ -1817,8 +1873,6 @@ static int snd_pcm_oss_set_subdivide1(struct snd_pcm_substream *substream, int s { struct snd_pcm_runtime *runtime; - if (substream == NULL) - return 0; runtime = substream->runtime; if (subdivide == 0) { subdivide = runtime->oss.subdivision; @@ -1842,9 +1896,16 @@ static int snd_pcm_oss_set_subdivide(struct snd_pcm_oss_file *pcm_oss_file, int for (idx = 1; idx >= 0; --idx) { struct snd_pcm_substream *substream = pcm_oss_file->streams[idx]; + struct snd_pcm_runtime *runtime; + if (substream == NULL) continue; - if ((err = snd_pcm_oss_set_subdivide1(substream, subdivide)) < 0) + runtime = substream->runtime; + if (mutex_lock_interruptible(&runtime->oss.params_lock)) + return -ERESTARTSYS; + err = snd_pcm_oss_set_subdivide1(substream, subdivide); + mutex_unlock(&runtime->oss.params_lock); + if (err < 0) return err; } return err; @@ -1854,8 +1915,6 @@ static int snd_pcm_oss_set_fragment1(struct snd_pcm_substream *substream, unsign { struct snd_pcm_runtime *runtime; - if (substream == NULL) - return 0; runtime = substream->runtime; if (runtime->oss.subdivision || runtime->oss.fragshift) return -EINVAL; @@ -1875,9 +1934,16 @@ static int snd_pcm_oss_set_fragment(struct snd_pcm_oss_file *pcm_oss_file, unsig for (idx = 1; idx >= 0; --idx) { struct snd_pcm_substream *substream = pcm_oss_file->streams[idx]; + struct snd_pcm_runtime *runtime; + if (substream == NULL) continue; - if ((err = snd_pcm_oss_set_fragment1(substream, val)) < 0) + runtime = substream->runtime; + if (mutex_lock_interruptible(&runtime->oss.params_lock)) + return -ERESTARTSYS; + err = snd_pcm_oss_set_fragment1(substream, val); + mutex_unlock(&runtime->oss.params_lock); + if (err < 0) return err; } return err; @@ -1961,6 +2027,9 @@ static int snd_pcm_oss_set_trigger(struct snd_pcm_oss_file *pcm_oss_file, int tr } if (psubstream) { runtime = psubstream->runtime; + cmd = 0; + if (mutex_lock_interruptible(&runtime->oss.params_lock)) + return -ERESTARTSYS; if (trigger & PCM_ENABLE_OUTPUT) { if (runtime->oss.trigger) goto _skip1; @@ -1978,13 +2047,19 @@ static int snd_pcm_oss_set_trigger(struct snd_pcm_oss_file *pcm_oss_file, int tr cmd = SNDRV_PCM_IOCTL_DROP; runtime->oss.prepare = 1; } - err = snd_pcm_kernel_ioctl(psubstream, cmd, NULL); - if (err < 0) - return err; - } _skip1: + mutex_unlock(&runtime->oss.params_lock); + if (cmd) { + err = snd_pcm_kernel_ioctl(psubstream, cmd, NULL); + if (err < 0) + return err; + } + } if (csubstream) { runtime = csubstream->runtime; + cmd = 0; + if (mutex_lock_interruptible(&runtime->oss.params_lock)) + return -ERESTARTSYS; if (trigger & PCM_ENABLE_INPUT) { if (runtime->oss.trigger) goto _skip2; @@ -1999,11 +2074,14 @@ static int snd_pcm_oss_set_trigger(struct snd_pcm_oss_file *pcm_oss_file, int tr cmd = SNDRV_PCM_IOCTL_DROP; runtime->oss.prepare = 1; } - err = snd_pcm_kernel_ioctl(csubstream, cmd, NULL); - if (err < 0) - return err; - } _skip2: + mutex_unlock(&runtime->oss.params_lock); + if (cmd) { + err = snd_pcm_kernel_ioctl(csubstream, cmd, NULL); + if (err < 0) + return err; + } + } return 0; } -- GitLab From 048747b04842cbe81386386ecd15b74db93029cf Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 23 Mar 2018 08:03:26 +0100 Subject: [PATCH 0749/1635] ALSA: pcm: Return -EBUSY for OSS ioctls changing busy streams commit 40cab6e88cb0b6c56d3f30b7491a20e803f948f6 upstream. OSS PCM stream management isn't modal but it allows ioctls issued at any time for changing the parameters. In the previous hardening patch ("ALSA: pcm: Avoid potential races between OSS ioctls and read/write"), we covered these races and prevent the corruption by protecting the concurrent accesses via params_lock mutex. However, this means that some ioctls that try to change the stream parameter (e.g. channels or format) would be blocked until the read/write finishes, and it may take really long. Basically changing the parameter while reading/writing is an invalid operation, hence it's even more user-friendly from the API POV if it returns -EBUSY in such a situation. This patch adds such checks in the relevant ioctls with the addition of read/write access refcount. Cc: Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- include/sound/pcm_oss.h | 1 + sound/core/oss/pcm_oss.c | 36 +++++++++++++++++++++++++++--------- 2 files changed, 28 insertions(+), 9 deletions(-) diff --git a/include/sound/pcm_oss.h b/include/sound/pcm_oss.h index 760c969d885d..12bbf8c81112 100644 --- a/include/sound/pcm_oss.h +++ b/include/sound/pcm_oss.h @@ -57,6 +57,7 @@ struct snd_pcm_oss_runtime { char *buffer; /* vmallocated period */ size_t buffer_used; /* used length from period buffer */ struct mutex params_lock; + atomic_t rw_ref; /* concurrent read/write accesses */ #ifdef CONFIG_SND_PCM_OSS_PLUGINS struct snd_pcm_plugin *plugin_first; struct snd_pcm_plugin *plugin_last; diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c index c526cef424bd..07bb3afa18b0 100644 --- a/sound/core/oss/pcm_oss.c +++ b/sound/core/oss/pcm_oss.c @@ -1370,6 +1370,7 @@ static ssize_t snd_pcm_oss_write1(struct snd_pcm_substream *substream, const cha if (atomic_read(&substream->mmap_count)) return -ENXIO; + atomic_inc(&runtime->oss.rw_ref); while (bytes > 0) { if (mutex_lock_interruptible(&runtime->oss.params_lock)) { tmp = -ERESTARTSYS; @@ -1433,6 +1434,7 @@ static ssize_t snd_pcm_oss_write1(struct snd_pcm_substream *substream, const cha } tmp = 0; } + atomic_dec(&runtime->oss.rw_ref); return xfer > 0 ? (snd_pcm_sframes_t)xfer : tmp; } @@ -1478,6 +1480,7 @@ static ssize_t snd_pcm_oss_read1(struct snd_pcm_substream *substream, char __use if (atomic_read(&substream->mmap_count)) return -ENXIO; + atomic_inc(&runtime->oss.rw_ref); while (bytes > 0) { if (mutex_lock_interruptible(&runtime->oss.params_lock)) { tmp = -ERESTARTSYS; @@ -1526,6 +1529,7 @@ static ssize_t snd_pcm_oss_read1(struct snd_pcm_substream *substream, char __use } tmp = 0; } + atomic_dec(&runtime->oss.rw_ref); return xfer > 0 ? (snd_pcm_sframes_t)xfer : tmp; } @@ -1632,8 +1636,11 @@ static int snd_pcm_oss_sync(struct snd_pcm_oss_file *pcm_oss_file) goto __direct; if ((err = snd_pcm_oss_make_ready(substream)) < 0) return err; - if (mutex_lock_interruptible(&runtime->oss.params_lock)) + atomic_inc(&runtime->oss.rw_ref); + if (mutex_lock_interruptible(&runtime->oss.params_lock)) { + atomic_dec(&runtime->oss.rw_ref); return -ERESTARTSYS; + } format = snd_pcm_oss_format_from(runtime->oss.format); width = snd_pcm_format_physical_width(format); if (runtime->oss.buffer_used > 0) { @@ -1645,10 +1652,8 @@ static int snd_pcm_oss_sync(struct snd_pcm_oss_file *pcm_oss_file) runtime->oss.buffer + runtime->oss.buffer_used, size); err = snd_pcm_oss_sync1(substream, runtime->oss.period_bytes); - if (err < 0) { - mutex_unlock(&runtime->oss.params_lock); - return err; - } + if (err < 0) + goto unlock; } else if (runtime->oss.period_ptr > 0) { #ifdef OSS_DEBUG pcm_dbg(substream->pcm, "sync: period_ptr\n"); @@ -1658,10 +1663,8 @@ static int snd_pcm_oss_sync(struct snd_pcm_oss_file *pcm_oss_file) runtime->oss.buffer, size * 8 / width); err = snd_pcm_oss_sync1(substream, size); - if (err < 0) { - mutex_unlock(&runtime->oss.params_lock); - return err; - } + if (err < 0) + goto unlock; } /* * The ALSA's period might be a bit large than OSS one. @@ -1675,7 +1678,11 @@ static int snd_pcm_oss_sync(struct snd_pcm_oss_file *pcm_oss_file) else if (runtime->access == SNDRV_PCM_ACCESS_RW_NONINTERLEAVED) snd_pcm_lib_writev(substream, NULL, size); } +unlock: mutex_unlock(&runtime->oss.params_lock); + atomic_dec(&runtime->oss.rw_ref); + if (err < 0) + return err; /* * finish sync: drain the buffer */ @@ -1723,6 +1730,8 @@ static int snd_pcm_oss_set_rate(struct snd_pcm_oss_file *pcm_oss_file, int rate) rate = 192000; if (mutex_lock_interruptible(&runtime->oss.params_lock)) return -ERESTARTSYS; + if (atomic_read(&runtime->oss.rw_ref)) + return -EBUSY; if (runtime->oss.rate != rate) { runtime->oss.params = 1; runtime->oss.rate = rate; @@ -1757,6 +1766,8 @@ static int snd_pcm_oss_set_channels(struct snd_pcm_oss_file *pcm_oss_file, unsig runtime = substream->runtime; if (mutex_lock_interruptible(&runtime->oss.params_lock)) return -ERESTARTSYS; + if (atomic_read(&runtime->oss.rw_ref)) + return -EBUSY; if (runtime->oss.channels != channels) { runtime->oss.params = 1; runtime->oss.channels = channels; @@ -1847,6 +1858,8 @@ static int snd_pcm_oss_set_format(struct snd_pcm_oss_file *pcm_oss_file, int for if (substream == NULL) continue; runtime = substream->runtime; + if (atomic_read(&runtime->oss.rw_ref)) + return -EBUSY; if (mutex_lock_interruptible(&runtime->oss.params_lock)) return -ERESTARTSYS; if (runtime->oss.format != format) { @@ -1901,6 +1914,8 @@ static int snd_pcm_oss_set_subdivide(struct snd_pcm_oss_file *pcm_oss_file, int if (substream == NULL) continue; runtime = substream->runtime; + if (atomic_read(&runtime->oss.rw_ref)) + return -EBUSY; if (mutex_lock_interruptible(&runtime->oss.params_lock)) return -ERESTARTSYS; err = snd_pcm_oss_set_subdivide1(substream, subdivide); @@ -1939,6 +1954,8 @@ static int snd_pcm_oss_set_fragment(struct snd_pcm_oss_file *pcm_oss_file, unsig if (substream == NULL) continue; runtime = substream->runtime; + if (atomic_read(&runtime->oss.rw_ref)) + return -EBUSY; if (mutex_lock_interruptible(&runtime->oss.params_lock)) return -ERESTARTSYS; err = snd_pcm_oss_set_fragment1(substream, val); @@ -2333,6 +2350,7 @@ static void snd_pcm_oss_init_substream(struct snd_pcm_substream *substream, runtime->oss.maxfrags = 0; runtime->oss.subdivision = 0; substream->pcm_release = snd_pcm_oss_release_substream; + atomic_set(&runtime->oss.rw_ref, 0); } static int snd_pcm_oss_release_file(struct snd_pcm_oss_file *pcm_oss_file) -- GitLab From 157113cb7c89829b1cd2e2792a1f38932f31c965 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 27 Mar 2018 14:32:23 +0200 Subject: [PATCH 0750/1635] ALSA: pcm: Fix mutex unbalance in OSS emulation ioctls commit f6d297df4dd47ef949540e4a201230d0c5308325 upstream. The previous fix 40cab6e88cb0 ("ALSA: pcm: Return -EBUSY for OSS ioctls changing busy streams") introduced some mutex unbalance; the check of runtime->oss.rw_ref was inserted in a wrong place after the mutex lock. This patch fixes the inconsistency by rewriting with the helper functions to lock/unlock parameters with the stream check. Fixes: 40cab6e88cb0 ("ALSA: pcm: Return -EBUSY for OSS ioctls changing busy streams") Reported-by: Dan Carpenter Cc: Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/core/oss/pcm_oss.c | 67 +++++++++++++++++++++++++--------------- 1 file changed, 42 insertions(+), 25 deletions(-) diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c index 07bb3afa18b0..3835f179e509 100644 --- a/sound/core/oss/pcm_oss.c +++ b/sound/core/oss/pcm_oss.c @@ -823,6 +823,23 @@ static int choose_rate(struct snd_pcm_substream *substream, return snd_pcm_hw_param_near(substream, params, SNDRV_PCM_HW_PARAM_RATE, best_rate, NULL); } +/* parameter locking: returns immediately if tried during streaming */ +static int lock_params(struct snd_pcm_runtime *runtime) +{ + if (mutex_lock_interruptible(&runtime->oss.params_lock)) + return -ERESTARTSYS; + if (atomic_read(&runtime->oss.rw_ref)) { + mutex_unlock(&runtime->oss.params_lock); + return -EBUSY; + } + return 0; +} + +static void unlock_params(struct snd_pcm_runtime *runtime) +{ + mutex_unlock(&runtime->oss.params_lock); +} + /* call with params_lock held */ static int snd_pcm_oss_change_params_locked(struct snd_pcm_substream *substream) { @@ -1721,6 +1738,8 @@ static int snd_pcm_oss_set_rate(struct snd_pcm_oss_file *pcm_oss_file, int rate) for (idx = 1; idx >= 0; --idx) { struct snd_pcm_substream *substream = pcm_oss_file->streams[idx]; struct snd_pcm_runtime *runtime; + int err; + if (substream == NULL) continue; runtime = substream->runtime; @@ -1728,15 +1747,14 @@ static int snd_pcm_oss_set_rate(struct snd_pcm_oss_file *pcm_oss_file, int rate) rate = 1000; else if (rate > 192000) rate = 192000; - if (mutex_lock_interruptible(&runtime->oss.params_lock)) - return -ERESTARTSYS; - if (atomic_read(&runtime->oss.rw_ref)) - return -EBUSY; + err = lock_params(runtime); + if (err < 0) + return err; if (runtime->oss.rate != rate) { runtime->oss.params = 1; runtime->oss.rate = rate; } - mutex_unlock(&runtime->oss.params_lock); + unlock_params(runtime); } return snd_pcm_oss_get_rate(pcm_oss_file); } @@ -1761,18 +1779,19 @@ static int snd_pcm_oss_set_channels(struct snd_pcm_oss_file *pcm_oss_file, unsig for (idx = 1; idx >= 0; --idx) { struct snd_pcm_substream *substream = pcm_oss_file->streams[idx]; struct snd_pcm_runtime *runtime; + int err; + if (substream == NULL) continue; runtime = substream->runtime; - if (mutex_lock_interruptible(&runtime->oss.params_lock)) - return -ERESTARTSYS; - if (atomic_read(&runtime->oss.rw_ref)) - return -EBUSY; + err = lock_params(runtime); + if (err < 0) + return err; if (runtime->oss.channels != channels) { runtime->oss.params = 1; runtime->oss.channels = channels; } - mutex_unlock(&runtime->oss.params_lock); + unlock_params(runtime); } return snd_pcm_oss_get_channels(pcm_oss_file); } @@ -1845,6 +1864,7 @@ static int snd_pcm_oss_get_formats(struct snd_pcm_oss_file *pcm_oss_file) static int snd_pcm_oss_set_format(struct snd_pcm_oss_file *pcm_oss_file, int format) { int formats, idx; + int err; if (format != AFMT_QUERY) { formats = snd_pcm_oss_get_formats(pcm_oss_file); @@ -1858,15 +1878,14 @@ static int snd_pcm_oss_set_format(struct snd_pcm_oss_file *pcm_oss_file, int for if (substream == NULL) continue; runtime = substream->runtime; - if (atomic_read(&runtime->oss.rw_ref)) - return -EBUSY; - if (mutex_lock_interruptible(&runtime->oss.params_lock)) - return -ERESTARTSYS; + err = lock_params(runtime); + if (err < 0) + return err; if (runtime->oss.format != format) { runtime->oss.params = 1; runtime->oss.format = format; } - mutex_unlock(&runtime->oss.params_lock); + unlock_params(runtime); } } return snd_pcm_oss_get_format(pcm_oss_file); @@ -1914,12 +1933,11 @@ static int snd_pcm_oss_set_subdivide(struct snd_pcm_oss_file *pcm_oss_file, int if (substream == NULL) continue; runtime = substream->runtime; - if (atomic_read(&runtime->oss.rw_ref)) - return -EBUSY; - if (mutex_lock_interruptible(&runtime->oss.params_lock)) - return -ERESTARTSYS; + err = lock_params(runtime); + if (err < 0) + return err; err = snd_pcm_oss_set_subdivide1(substream, subdivide); - mutex_unlock(&runtime->oss.params_lock); + unlock_params(runtime); if (err < 0) return err; } @@ -1954,12 +1972,11 @@ static int snd_pcm_oss_set_fragment(struct snd_pcm_oss_file *pcm_oss_file, unsig if (substream == NULL) continue; runtime = substream->runtime; - if (atomic_read(&runtime->oss.rw_ref)) - return -EBUSY; - if (mutex_lock_interruptible(&runtime->oss.params_lock)) - return -ERESTARTSYS; + err = lock_params(runtime); + if (err < 0) + return err; err = snd_pcm_oss_set_fragment1(substream, val); - mutex_unlock(&runtime->oss.params_lock); + unlock_params(runtime); if (err < 0) return err; } -- GitLab From 312d02879f9f0ae9c6b011d0ead6a143115e9f93 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sat, 7 Apr 2018 11:48:58 +0200 Subject: [PATCH 0751/1635] ALSA: pcm: Fix endless loop for XRUN recovery in OSS emulation commit e15dc99dbb9cf99f6432e8e3c0b3a8f7a3403a86 upstream. The commit 02a5d6925cd3 ("ALSA: pcm: Avoid potential races between OSS ioctls and read/write") split the PCM preparation code to a locked version, and it added a sanity check of runtime->oss.prepare flag along with the change. This leaded to an endless loop when the stream gets XRUN: namely, snd_pcm_oss_write3() and co call snd_pcm_oss_prepare() without setting runtime->oss.prepare flag and the loop continues until the PCM state reaches to another one. As the function is supposed to execute the preparation unconditionally, drop the invalid state check there. The bug was triggered by syzkaller. Fixes: 02a5d6925cd3 ("ALSA: pcm: Avoid potential races between OSS ioctls and read/write") Reported-by: syzbot+150189c103427d31a053@syzkaller.appspotmail.com Reported-by: syzbot+7e3f31a52646f939c052@syzkaller.appspotmail.com Reported-by: syzbot+4f2016cf5185da7759dc@syzkaller.appspotmail.com Cc: Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/core/oss/pcm_oss.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c index 3835f179e509..b4f954e6d2db 100644 --- a/sound/core/oss/pcm_oss.c +++ b/sound/core/oss/pcm_oss.c @@ -1128,13 +1128,14 @@ static int snd_pcm_oss_get_active_substream(struct snd_pcm_oss_file *pcm_oss_fil } /* call with params_lock held */ +/* NOTE: this always call PREPARE unconditionally no matter whether + * runtime->oss.prepare is set or not + */ static int snd_pcm_oss_prepare(struct snd_pcm_substream *substream) { int err; struct snd_pcm_runtime *runtime = substream->runtime; - if (!runtime->oss.prepare) - return 0; err = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_PREPARE, NULL); if (err < 0) { pcm_dbg(substream->pcm, -- GitLab From 674b6963cec22d45d0ff9565554bf5ee2628630e Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Wed, 21 Mar 2018 21:05:46 -0500 Subject: [PATCH 0752/1635] drm/amdgpu: Add an ATPX quirk for hybrid laptop commit 13b40935cf64f59b93cf1c716a2033488e5a228c upstream. _PR3 doesn't seem to work properly, use ATPX instead. Bug: https://bugs.freedesktop.org/show_bug.cgi?id=104064 Reviewed-by: Huang Rui Signed-off-by: Alex Deucher Cc: stable@vger.kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/amd/amdgpu/amdgpu_atpx_handler.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_atpx_handler.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_atpx_handler.c index c53095b3b0fb..1ae5ae8c45a4 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_atpx_handler.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_atpx_handler.c @@ -569,6 +569,7 @@ static const struct amdgpu_px_quirk amdgpu_px_quirk_list[] = { { 0x1002, 0x6900, 0x1002, 0x0124, AMDGPU_PX_QUIRK_FORCE_ATPX }, { 0x1002, 0x6900, 0x1028, 0x0812, AMDGPU_PX_QUIRK_FORCE_ATPX }, { 0x1002, 0x6900, 0x1028, 0x0813, AMDGPU_PX_QUIRK_FORCE_ATPX }, + { 0x1002, 0x67DF, 0x1028, 0x0774, AMDGPU_PX_QUIRK_FORCE_ATPX }, { 0, 0, 0, 0, 0 }, }; -- GitLab From c73d9e350085a479d787d6d6dff3599fa6952491 Mon Sep 17 00:00:00 2001 From: Bas Nieuwenhuizen Date: Wed, 31 Jan 2018 13:58:55 +0100 Subject: [PATCH 0753/1635] drm/amdgpu: Fix always_valid bos multiple LRU insertions. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit a20ee0b1f8b42e2568f3a4408003d22b2dfcc706 upstream. If these bos are evicted and are in the validated list things blow up, so do not put them in there. Notably, that tries to add the bo to the LRU twice, which results in a BUG_ON in ttm_bo.c. While for the bo_list an alternative would be to not allow always valid bos in there, that does not work for the user fence. v2: Fixed whitespace issue pointed out by checkpatch.pl Signed-off-by: Bas Nieuwenhuizen Reviewed-by: Christian König Signed-off-by: Alex Deucher Cc: stable@vger.kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c | 6 ++++-- drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c index 59089e027f4d..92be7f6de197 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c @@ -233,8 +233,10 @@ void amdgpu_bo_list_get_list(struct amdgpu_bo_list *list, for (i = 0; i < list->num_entries; i++) { unsigned priority = list->array[i].priority; - list_add_tail(&list->array[i].tv.head, - &bucket[priority]); + if (!list->array[i].robj->parent) + list_add_tail(&list->array[i].tv.head, + &bucket[priority]); + list->array[i].user_pages = NULL; } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c index b5aa8e6f8e0b..5f892ad6476e 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c @@ -522,7 +522,7 @@ static int amdgpu_cs_parser_bos(struct amdgpu_cs_parser *p, INIT_LIST_HEAD(&duplicates); amdgpu_vm_get_pd_bo(&fpriv->vm, &p->validated, &p->vm_pd); - if (p->uf_entry.robj) + if (p->uf_entry.robj && !p->uf_entry.robj->parent) list_add(&p->uf_entry.tv.head, &p->validated); if (need_mmap_lock) -- GitLab From 57e56826611a158234ce75a1684d0de92af73c8e Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 27 Mar 2018 15:53:52 -0500 Subject: [PATCH 0754/1635] drm/amdgpu/sdma: fix mask in emit_pipeline_sync MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 4a8e06f7aad797e92413a3042d09d3b385fa1fda upstream. Needs to be a 32 bit mask. Acked-by: Huang Rui Reviewed-by: Christian König Signed-off-by: Alex Deucher Cc: stable@vger.kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/amd/amdgpu/cik_sdma.c | 2 +- drivers/gpu/drm/amd/amdgpu/sdma_v2_4.c | 2 +- drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c | 2 +- drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/cik_sdma.c b/drivers/gpu/drm/amd/amdgpu/cik_sdma.c index f508f4d01e4a..11beef7c595f 100644 --- a/drivers/gpu/drm/amd/amdgpu/cik_sdma.c +++ b/drivers/gpu/drm/amd/amdgpu/cik_sdma.c @@ -866,7 +866,7 @@ static void cik_sdma_ring_emit_pipeline_sync(struct amdgpu_ring *ring) amdgpu_ring_write(ring, addr & 0xfffffffc); amdgpu_ring_write(ring, upper_32_bits(addr) & 0xffffffff); amdgpu_ring_write(ring, seq); /* reference */ - amdgpu_ring_write(ring, 0xfffffff); /* mask */ + amdgpu_ring_write(ring, 0xffffffff); /* mask */ amdgpu_ring_write(ring, (0xfff << 16) | 4); /* retry count, poll interval */ } diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v2_4.c b/drivers/gpu/drm/amd/amdgpu/sdma_v2_4.c index f2d0710258cb..9928473234a6 100644 --- a/drivers/gpu/drm/amd/amdgpu/sdma_v2_4.c +++ b/drivers/gpu/drm/amd/amdgpu/sdma_v2_4.c @@ -856,7 +856,7 @@ static void sdma_v2_4_ring_emit_pipeline_sync(struct amdgpu_ring *ring) amdgpu_ring_write(ring, addr & 0xfffffffc); amdgpu_ring_write(ring, upper_32_bits(addr) & 0xffffffff); amdgpu_ring_write(ring, seq); /* reference */ - amdgpu_ring_write(ring, 0xfffffff); /* mask */ + amdgpu_ring_write(ring, 0xffffffff); /* mask */ amdgpu_ring_write(ring, SDMA_PKT_POLL_REGMEM_DW5_RETRY_COUNT(0xfff) | SDMA_PKT_POLL_REGMEM_DW5_INTERVAL(4)); /* retry count, poll interval */ } diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c b/drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c index b1de44f22824..f5db1fad3f05 100644 --- a/drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c +++ b/drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c @@ -1099,7 +1099,7 @@ static void sdma_v3_0_ring_emit_pipeline_sync(struct amdgpu_ring *ring) amdgpu_ring_write(ring, addr & 0xfffffffc); amdgpu_ring_write(ring, upper_32_bits(addr) & 0xffffffff); amdgpu_ring_write(ring, seq); /* reference */ - amdgpu_ring_write(ring, 0xfffffff); /* mask */ + amdgpu_ring_write(ring, 0xffffffff); /* mask */ amdgpu_ring_write(ring, SDMA_PKT_POLL_REGMEM_DW5_RETRY_COUNT(0xfff) | SDMA_PKT_POLL_REGMEM_DW5_INTERVAL(4)); /* retry count, poll interval */ } diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c b/drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c index fd7c72aaafa6..4e5fed7c66bf 100644 --- a/drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c +++ b/drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c @@ -1136,7 +1136,7 @@ static void sdma_v4_0_ring_emit_pipeline_sync(struct amdgpu_ring *ring) amdgpu_ring_write(ring, addr & 0xfffffffc); amdgpu_ring_write(ring, upper_32_bits(addr) & 0xffffffff); amdgpu_ring_write(ring, seq); /* reference */ - amdgpu_ring_write(ring, 0xfffffff); /* mask */ + amdgpu_ring_write(ring, 0xffffffff); /* mask */ amdgpu_ring_write(ring, SDMA_PKT_POLL_REGMEM_DW5_RETRY_COUNT(0xfff) | SDMA_PKT_POLL_REGMEM_DW5_INTERVAL(4)); /* retry count, poll interval */ } -- GitLab From f056e3339741cf34908d93d428c2fbe5fd6a3a3e Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Mon, 2 Apr 2018 12:29:26 -0500 Subject: [PATCH 0755/1635] drm/amdgpu: Fix PCIe lane width calculation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 41212e2fe72b26ded7ed78224d9eab720c2891e2 upstream. The calculation of the lane widths via ATOM_PPLIB_PCIE_LINK_WIDTH_MASK and ATOM_PPLIB_PCIE_LINK_WIDTH_SHIFT macros did not increment the resulting value, per the comment in pptable.h ("lanes - 1"), and per usage elsewhere. Port of the radeon fix to amdgpu. Acked-by: Christian König Acked-by: Chunming Zhou Bug: https://bugs.freedesktop.org/show_bug.cgi?id=102553 Signed-off-by: Alex Deucher Cc: stable@vger.kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/amd/amdgpu/si_dpm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/si_dpm.c b/drivers/gpu/drm/amd/amdgpu/si_dpm.c index abb0a2341a41..6f1dea157a77 100644 --- a/drivers/gpu/drm/amd/amdgpu/si_dpm.c +++ b/drivers/gpu/drm/amd/amdgpu/si_dpm.c @@ -6374,9 +6374,9 @@ static void si_set_pcie_lane_width_in_smc(struct amdgpu_device *adev, { u32 lane_width; u32 new_lane_width = - (amdgpu_new_state->caps & ATOM_PPLIB_PCIE_LINK_WIDTH_MASK) >> ATOM_PPLIB_PCIE_LINK_WIDTH_SHIFT; + ((amdgpu_new_state->caps & ATOM_PPLIB_PCIE_LINK_WIDTH_MASK) >> ATOM_PPLIB_PCIE_LINK_WIDTH_SHIFT) + 1; u32 current_lane_width = - (amdgpu_current_state->caps & ATOM_PPLIB_PCIE_LINK_WIDTH_MASK) >> ATOM_PPLIB_PCIE_LINK_WIDTH_SHIFT; + ((amdgpu_current_state->caps & ATOM_PPLIB_PCIE_LINK_WIDTH_MASK) >> ATOM_PPLIB_PCIE_LINK_WIDTH_SHIFT) + 1; if (new_lane_width != current_lane_width) { amdgpu_set_pcie_lanes(adev, new_lane_width); -- GitLab From f188464e3d54c2d651fa710f74c8aed68aa87813 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 3 Apr 2018 12:54:33 -0500 Subject: [PATCH 0756/1635] drm/amdgpu/si: implement get/set pcie_lanes asic callback MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 20ca25e86c56f5490bdc80318f4fc06466e4c21b upstream. Required for dpm setup on some asics. Fixes a NULL dereference on asics that require it. Acked-by: Christian König Bug: https://bugs.freedesktop.org/show_bug.cgi?id=102553 Tested-by: Abel Garcia Dorta Signed-off-by: Alex Deucher Cc: stable@vger.kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/amd/amdgpu/si.c | 67 +++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/si.c b/drivers/gpu/drm/amd/amdgpu/si.c index 4c178feeb4bd..40520a968eac 100644 --- a/drivers/gpu/drm/amd/amdgpu/si.c +++ b/drivers/gpu/drm/amd/amdgpu/si.c @@ -1231,6 +1231,71 @@ static void si_detect_hw_virtualization(struct amdgpu_device *adev) adev->virt.caps |= AMDGPU_PASSTHROUGH_MODE; } +static int si_get_pcie_lanes(struct amdgpu_device *adev) +{ + u32 link_width_cntl; + + if (adev->flags & AMD_IS_APU) + return 0; + + link_width_cntl = RREG32_PCIE_PORT(PCIE_LC_LINK_WIDTH_CNTL); + + switch ((link_width_cntl & LC_LINK_WIDTH_RD_MASK) >> LC_LINK_WIDTH_RD_SHIFT) { + case LC_LINK_WIDTH_X1: + return 1; + case LC_LINK_WIDTH_X2: + return 2; + case LC_LINK_WIDTH_X4: + return 4; + case LC_LINK_WIDTH_X8: + return 8; + case LC_LINK_WIDTH_X0: + case LC_LINK_WIDTH_X16: + default: + return 16; + } +} + +static void si_set_pcie_lanes(struct amdgpu_device *adev, int lanes) +{ + u32 link_width_cntl, mask; + + if (adev->flags & AMD_IS_APU) + return; + + switch (lanes) { + case 0: + mask = LC_LINK_WIDTH_X0; + break; + case 1: + mask = LC_LINK_WIDTH_X1; + break; + case 2: + mask = LC_LINK_WIDTH_X2; + break; + case 4: + mask = LC_LINK_WIDTH_X4; + break; + case 8: + mask = LC_LINK_WIDTH_X8; + break; + case 16: + mask = LC_LINK_WIDTH_X16; + break; + default: + DRM_ERROR("invalid pcie lane request: %d\n", lanes); + return; + } + + link_width_cntl = RREG32_PCIE_PORT(PCIE_LC_LINK_WIDTH_CNTL); + link_width_cntl &= ~LC_LINK_WIDTH_MASK; + link_width_cntl |= mask << LC_LINK_WIDTH_SHIFT; + link_width_cntl |= (LC_RECONFIG_NOW | + LC_RECONFIG_ARC_MISSING_ESCAPE); + + WREG32_PCIE_PORT(PCIE_LC_LINK_WIDTH_CNTL, link_width_cntl); +} + static const struct amdgpu_asic_funcs si_asic_funcs = { .read_disabled_bios = &si_read_disabled_bios, @@ -1241,6 +1306,8 @@ static const struct amdgpu_asic_funcs si_asic_funcs = .get_xclk = &si_get_xclk, .set_uvd_clocks = &si_set_uvd_clocks, .set_vce_clocks = NULL, + .get_pcie_lanes = &si_get_pcie_lanes, + .set_pcie_lanes = &si_set_pcie_lanes, .get_config_memsize = &si_get_config_memsize, }; -- GitLab From 791469d6b882c7366a7710539dc7267c5b57fed6 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Tue, 20 Feb 2018 13:01:18 +0000 Subject: [PATCH 0757/1635] drm/rockchip: Clear all interrupts before requesting the IRQ commit 5f9e93fed4d45e9a8f84728aff1a8f2ab8922902 upstream. Calling request_irq() followed by disable_irq() is usually a bad idea, specially if the interrupt can be pending, and you're not yet in a position to handle it. This is exactly what happens on my kevin system when rebooting in a second kernel using kexec: Some interrupt is left pending from the previous kernel, and we take it too early, before disable_irq() could do anything. Let's clear the pending interrupts as we initialize the HW, and move the interrupt request after that point. This ensures that we're in a sane state when the interrupt is requested. Cc: stable@vger.kernel.org Signed-off-by: Marc Zyngier [adapted to recent rockchip-drm changes] Signed-off-by: Heiko Stuebner Link: https://patchwork.freedesktop.org/patch/msgid/20180220130120.5254-2-marc.zyngier@arm.com Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 23 +++++++++++---------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c index bf9ed0e63973..f1fa8d5c9b52 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c @@ -1413,6 +1413,9 @@ static int vop_initial(struct vop *vop) usleep_range(10, 20); reset_control_deassert(ahb_rst); + VOP_INTR_SET_TYPE(vop, clear, INTR_MASK, 1); + VOP_INTR_SET_TYPE(vop, enable, INTR_MASK, 0); + memcpy(vop->regsbak, vop->regs, vop->len); VOP_REG_SET(vop, misc, global_regdone_en, 1); @@ -1568,17 +1571,9 @@ static int vop_bind(struct device *dev, struct device *master, void *data) mutex_init(&vop->vsync_mutex); - ret = devm_request_irq(dev, vop->irq, vop_isr, - IRQF_SHARED, dev_name(dev), vop); - if (ret) - return ret; - - /* IRQ is initially disabled; it gets enabled in power_on */ - disable_irq(vop->irq); - ret = vop_create_crtc(vop); if (ret) - goto err_enable_irq; + return ret; pm_runtime_enable(&pdev->dev); @@ -1588,13 +1583,19 @@ static int vop_bind(struct device *dev, struct device *master, void *data) goto err_disable_pm_runtime; } + ret = devm_request_irq(dev, vop->irq, vop_isr, + IRQF_SHARED, dev_name(dev), vop); + if (ret) + goto err_disable_pm_runtime; + + /* IRQ is initially disabled; it gets enabled in power_on */ + disable_irq(vop->irq); + return 0; err_disable_pm_runtime: pm_runtime_disable(&pdev->dev); vop_destroy_crtc(vop); -err_enable_irq: - enable_irq(vop->irq); /* To balance out the disable_irq above */ return ret; } -- GitLab From 110b72d9351ff9662fd27d1225301d10293cf5a8 Mon Sep 17 00:00:00 2001 From: Nico Sneck Date: Sat, 7 Apr 2018 15:13:04 +0000 Subject: [PATCH 0758/1635] drm/radeon: add PX quirk for Asus K73TK commit b1550359d1eb392ee54f7cf47cffcfe0a602f6a7 upstream. With this the dGPU turns on correctly. Signed-off-by: Nico Sneck Signed-off-by: Alex Deucher Cc: stable@vger.kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/radeon/radeon_device.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c index 32b577c776b9..58488eac8462 100644 --- a/drivers/gpu/drm/radeon/radeon_device.c +++ b/drivers/gpu/drm/radeon/radeon_device.c @@ -139,6 +139,10 @@ static struct radeon_px_quirk radeon_px_quirk_list[] = { * https://bugs.freedesktop.org/show_bug.cgi?id=101491 */ { PCI_VENDOR_ID_ATI, 0x6741, 0x1043, 0x2122, RADEON_PX_QUIRK_DISABLE_PX }, + /* Asus K73TK laptop with AMD A6-3420M APU and Radeon 7670m GPU + * https://bugzilla.kernel.org/show_bug.cgi?id=51381#c52 + */ + { PCI_VENDOR_ID_ATI, 0x6840, 0x1043, 0x2123, RADEON_PX_QUIRK_DISABLE_PX }, { 0, 0, 0, 0, 0 }, }; -- GitLab From bdc6f4c3db08c7b947b5c4200e600136993fe01b Mon Sep 17 00:00:00 2001 From: Paul Parsons Date: Sat, 2 Apr 2016 12:32:30 +0100 Subject: [PATCH 0759/1635] drm/radeon: Fix PCIe lane width calculation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 85e290d92b4b794d0c758c53007eb4248d385386 upstream. Two years ago I tried an AMD Radeon E8860 embedded GPU with the drm driver. The dmesg output included driver warnings about an invalid PCIe lane width. Tracking the problem back led to si_set_pcie_lane_width_in_smc(). The calculation of the lane widths via ATOM_PPLIB_PCIE_LINK_WIDTH_MASK and ATOM_PPLIB_PCIE_LINK_WIDTH_SHIFT macros did not increment the resulting value, per the comment in pptable.h ("lanes - 1"), and per usage elsewhere. Applying the increment silenced the warnings. The code has not changed since, so either my analysis was incorrect or the bug has gone unnoticed. Hence submitting this as an RFC. Acked-by: Christian König Acked-by: Chunming Zhou Signed-off-by: Paul Parsons Signed-off-by: Alex Deucher Cc: stable@vger.kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/radeon/si_dpm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/radeon/si_dpm.c b/drivers/gpu/drm/radeon/si_dpm.c index 97a0a639dad9..90d5b41007bf 100644 --- a/drivers/gpu/drm/radeon/si_dpm.c +++ b/drivers/gpu/drm/radeon/si_dpm.c @@ -5912,9 +5912,9 @@ static void si_set_pcie_lane_width_in_smc(struct radeon_device *rdev, { u32 lane_width; u32 new_lane_width = - (radeon_new_state->caps & ATOM_PPLIB_PCIE_LINK_WIDTH_MASK) >> ATOM_PPLIB_PCIE_LINK_WIDTH_SHIFT; + ((radeon_new_state->caps & ATOM_PPLIB_PCIE_LINK_WIDTH_MASK) >> ATOM_PPLIB_PCIE_LINK_WIDTH_SHIFT) + 1; u32 current_lane_width = - (radeon_current_state->caps & ATOM_PPLIB_PCIE_LINK_WIDTH_MASK) >> ATOM_PPLIB_PCIE_LINK_WIDTH_SHIFT; + ((radeon_current_state->caps & ATOM_PPLIB_PCIE_LINK_WIDTH_MASK) >> ATOM_PPLIB_PCIE_LINK_WIDTH_SHIFT) + 1; if (new_lane_width != current_lane_width) { radeon_set_pcie_lanes(rdev, new_lane_width); -- GitLab From 43b3e7915edd6c20be27444bd70d967fcb07394d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fabi=C3=A1n=20Inostroza?= Date: Thu, 12 Apr 2018 00:37:35 -0300 Subject: [PATCH 0760/1635] ALSA: line6: Use correct endpoint type for midi output MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 7ecb46e9ee9af18e304eb9e7d6804c59a408e846 upstream. Sending MIDI messages to a PODxt through the USB connection shows "usb_submit_urb failed" in dmesg and the message is not received by the POD. The error is caused because in the funcion send_midi_async() in midi.c there is a call to usb_sndbulkpipe() for endpoint 3 OUT, but the PODxt USB descriptor shows that this endpoint it's an interrupt endpoint. Patch tested with PODxt only. [ The bug has been present from the very beginning in the staging driver time, but Fixes below points to the commit moving to sound/ directory so that the fix can be cleanly applied -- tiwai ] Fixes: 61864d844c29 ("ALSA: move line6 usb driver into sound/usb") Signed-off-by: Fabián Inostroza Cc: Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/usb/line6/midi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/usb/line6/midi.c b/sound/usb/line6/midi.c index 1d3a23b02d68..b5d62b5f59ba 100644 --- a/sound/usb/line6/midi.c +++ b/sound/usb/line6/midi.c @@ -125,7 +125,7 @@ static int send_midi_async(struct usb_line6 *line6, unsigned char *data, } usb_fill_int_urb(urb, line6->usbdev, - usb_sndbulkpipe(line6->usbdev, + usb_sndintpipe(line6->usbdev, line6->properties->ep_ctrl_w), transfer_buffer, length, midi_sent, line6, line6->interval); -- GitLab From fcf38cf55e286f7da4a1210d8496696b855934be Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 19 Apr 2018 18:16:15 +0200 Subject: [PATCH 0761/1635] ALSA: rawmidi: Fix missing input substream checks in compat ioctls commit 8a56ef4f3ffba9ebf4967b61ef600b0a7ba10f11 upstream. Some rawmidi compat ioctls lack of the input substream checks (although they do check only for rfile->output). This many eventually lead to an Oops as NULL substream is passed to the rawmidi core functions. Fix it by adding the proper checks before each function call. The bug was spotted by syzkaller. Reported-by: syzbot+f7a0348affc3b67bc617@syzkaller.appspotmail.com Cc: Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/core/rawmidi_compat.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/sound/core/rawmidi_compat.c b/sound/core/rawmidi_compat.c index f69764d7cdd7..e30e30ba6e39 100644 --- a/sound/core/rawmidi_compat.c +++ b/sound/core/rawmidi_compat.c @@ -36,8 +36,6 @@ static int snd_rawmidi_ioctl_params_compat(struct snd_rawmidi_file *rfile, struct snd_rawmidi_params params; unsigned int val; - if (rfile->output == NULL) - return -EINVAL; if (get_user(params.stream, &src->stream) || get_user(params.buffer_size, &src->buffer_size) || get_user(params.avail_min, &src->avail_min) || @@ -46,8 +44,12 @@ static int snd_rawmidi_ioctl_params_compat(struct snd_rawmidi_file *rfile, params.no_active_sensing = val; switch (params.stream) { case SNDRV_RAWMIDI_STREAM_OUTPUT: + if (!rfile->output) + return -EINVAL; return snd_rawmidi_output_params(rfile->output, ¶ms); case SNDRV_RAWMIDI_STREAM_INPUT: + if (!rfile->input) + return -EINVAL; return snd_rawmidi_input_params(rfile->input, ¶ms); } return -EINVAL; @@ -67,16 +69,18 @@ static int snd_rawmidi_ioctl_status_compat(struct snd_rawmidi_file *rfile, int err; struct snd_rawmidi_status status; - if (rfile->output == NULL) - return -EINVAL; if (get_user(status.stream, &src->stream)) return -EFAULT; switch (status.stream) { case SNDRV_RAWMIDI_STREAM_OUTPUT: + if (!rfile->output) + return -EINVAL; err = snd_rawmidi_output_status(rfile->output, &status); break; case SNDRV_RAWMIDI_STREAM_INPUT: + if (!rfile->input) + return -EINVAL; err = snd_rawmidi_input_status(rfile->input, &status); break; default: @@ -112,16 +116,18 @@ static int snd_rawmidi_ioctl_status_x32(struct snd_rawmidi_file *rfile, int err; struct snd_rawmidi_status status; - if (rfile->output == NULL) - return -EINVAL; if (get_user(status.stream, &src->stream)) return -EFAULT; switch (status.stream) { case SNDRV_RAWMIDI_STREAM_OUTPUT: + if (!rfile->output) + return -EINVAL; err = snd_rawmidi_output_status(rfile->output, &status); break; case SNDRV_RAWMIDI_STREAM_INPUT: + if (!rfile->input) + return -EINVAL; err = snd_rawmidi_input_status(rfile->input, &status); break; default: -- GitLab From 11e9bed2b97199ee940226be54aed5d19c50d0e4 Mon Sep 17 00:00:00 2001 From: David Wang Date: Mon, 16 Apr 2018 17:48:09 +0800 Subject: [PATCH 0762/1635] ALSA: hda - New VIA controller suppor no-snoop path commit af52f9982e410edac21ca4b49563053ffc9da1eb upstream. This patch is used to tell kernel that new VIA HDAC controller also support no-snoop path. [ minor coding style fix by tiwai ] Signed-off-by: David Wang Cc: Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/pci/hda/hda_intel.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index c507c69029e3..738e1fe90312 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -1645,7 +1645,8 @@ static void azx_check_snoop_available(struct azx *chip) */ u8 val; pci_read_config_byte(chip->pci, 0x42, &val); - if (!(val & 0x80) && chip->pci->revision == 0x30) + if (!(val & 0x80) && (chip->pci->revision == 0x30 || + chip->pci->revision == 0x20)) snoop = false; } -- GitLab From adc02ac60919116f61ebcfbb4e5cfd0b6c3cb2f3 Mon Sep 17 00:00:00 2001 From: Hui Wang Date: Thu, 19 Apr 2018 13:29:04 +0800 Subject: [PATCH 0763/1635] ALSA: hda/realtek - set PINCFG_HEADSET_MIC to parse_flags commit 3ce0d5aa265bcc0a4b281cb0cabf92491276101b upstream. Otherwise, the pin will be regarded as microphone, and the jack name is "Mic Phantom", it is always on in the pulseaudio even nothing is plugged into the jack. So the UI is confusing to users since the microphone always shows up in the UI even there is no microphone plugged. After adding this flag, the jack name is "Headset Mic Phantom", then the pulseaudio can handle its detection correctly. Fixes: f0ba9d699e5c ("ALSA: hda/realtek - Fix Dell headset Mic can't record") Cc: Signed-off-by: Hui Wang Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/pci/hda/patch_realtek.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index e44a9758f2eb..a4f24c453b8d 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -6225,6 +6225,8 @@ static const struct hda_fixup alc269_fixups[] = { { 0x19, 0x01a1913c }, /* use as headset mic, without its own jack detect */ { } }, + .chained = true, + .chain_id = ALC269_FIXUP_HEADSET_MIC }, }; -- GitLab From 8036cdaa1b13144428bbf95bc9679ea7a592d7dd Mon Sep 17 00:00:00 2001 From: Hui Wang Date: Thu, 19 Apr 2018 13:29:05 +0800 Subject: [PATCH 0764/1635] ALSA: hda/realtek - adjust the location of one mic commit a3dafb2200bf3c13905a088e82ae11f1eb275a83 upstream. There are two front mics on this machine, if we don't adjust the location for one of them, they will have the same mixer name, pulseaudio can't handle this situation. After applying this FIXUP, they will have different mixer name, then pulseaudio can handle them correctly. Cc: Signed-off-by: Hui Wang Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/pci/hda/patch_realtek.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index a4f24c453b8d..b1b28c6928a7 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -6430,6 +6430,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x17aa, 0x30bb, "ThinkCentre AIO", ALC233_FIXUP_LENOVO_LINE2_MIC_HOTKEY), SND_PCI_QUIRK(0x17aa, 0x30e2, "ThinkCentre AIO", ALC233_FIXUP_LENOVO_LINE2_MIC_HOTKEY), SND_PCI_QUIRK(0x17aa, 0x310c, "ThinkCentre Station", ALC294_FIXUP_LENOVO_MIC_LOCATION), + SND_PCI_QUIRK(0x17aa, 0x3138, "ThinkCentre Station", ALC294_FIXUP_LENOVO_MIC_LOCATION), SND_PCI_QUIRK(0x17aa, 0x313c, "ThinkCentre Station", ALC294_FIXUP_LENOVO_MIC_LOCATION), SND_PCI_QUIRK(0x17aa, 0x3112, "ThinkCentre AIO", ALC233_FIXUP_LENOVO_LINE2_MIC_HOTKEY), SND_PCI_QUIRK(0x17aa, 0x3902, "Lenovo E50-80", ALC269_FIXUP_DMIC_THINKPAD_ACPI), -- GitLab From 6e513bc20ca63f594632eca4e1968791240b8f18 Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Wed, 11 Apr 2018 13:27:52 -0400 Subject: [PATCH 0765/1635] random: fix crng_ready() test commit 43838a23a05fbd13e47d750d3dfd77001536dd33 upstream. The crng_init variable has three states: 0: The CRNG is not initialized at all 1: The CRNG has a small amount of entropy, hopefully good enough for early-boot, non-cryptographical use cases 2: The CRNG is fully initialized and we are sure it is safe for cryptographic use cases. The crng_ready() function should only return true once we are in the last state. This addresses CVE-2018-1108. Reported-by: Jann Horn Fixes: e192be9d9a30 ("random: replace non-blocking pool...") Cc: stable@kernel.org # 4.8+ Signed-off-by: Theodore Ts'o Reviewed-by: Jann Horn Signed-off-by: Greg Kroah-Hartman --- drivers/char/random.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/char/random.c b/drivers/char/random.c index e88a5c61eaa1..d7dc9727bcf0 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -427,7 +427,7 @@ struct crng_state primary_crng = { * its value (from 0->1->2). */ static int crng_init = 0; -#define crng_ready() (likely(crng_init > 0)) +#define crng_ready() (likely(crng_init > 1)) static int crng_init_cnt = 0; #define CRNG_INIT_CNT_THRESH (2*CHACHA20_KEY_SIZE) static void _extract_crng(struct crng_state *crng, @@ -793,7 +793,7 @@ static int crng_fast_load(const char *cp, size_t len) if (!spin_trylock_irqsave(&primary_crng.lock, flags)) return 0; - if (crng_ready()) { + if (crng_init != 0) { spin_unlock_irqrestore(&primary_crng.lock, flags); return 0; } @@ -855,7 +855,7 @@ static void _extract_crng(struct crng_state *crng, { unsigned long v, flags; - if (crng_init > 1 && + if (crng_ready() && time_after(jiffies, crng->init_time + CRNG_RESEED_INTERVAL)) crng_reseed(crng, crng == &primary_crng ? &input_pool : NULL); spin_lock_irqsave(&crng->lock, flags); @@ -1141,7 +1141,7 @@ void add_interrupt_randomness(int irq, int irq_flags) fast_mix(fast_pool); add_interrupt_bench(cycles); - if (!crng_ready()) { + if (unlikely(crng_init == 0)) { if ((fast_pool->count >= 64) && crng_fast_load((char *) fast_pool->pool, sizeof(fast_pool->pool))) { @@ -2214,7 +2214,7 @@ void add_hwgenerator_randomness(const char *buffer, size_t count, { struct entropy_store *poolp = &input_pool; - if (!crng_ready()) { + if (unlikely(crng_init == 0)) { crng_fast_load(buffer, count); return; } -- GitLab From 7b6b1f3a192372937164d1293b432c640ffc7c8f Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Wed, 11 Apr 2018 14:58:27 -0400 Subject: [PATCH 0766/1635] random: use a different mixing algorithm for add_device_randomness() commit dc12baacb95f205948f64dc936a47d89ee110117 upstream. add_device_randomness() use of crng_fast_load() was highly problematic. Some callers of add_device_randomness() can pass in a large amount of static information. This would immediately promote the crng_init state from 0 to 1, without really doing much to initialize the primary_crng's internal state with something even vaguely unpredictable. Since we don't have the speed constraints of add_interrupt_randomness(), we can do a better job mixing in the what unpredictability a device driver or architecture maintainer might see fit to give us, and do it in a way which does not bump the crng_init_cnt variable. Also, since add_device_randomness() doesn't bump any entropy accounting in crng_init state 0, mix the device randomness into the input_pool entropy pool as well. This is related to CVE-2018-1108. Reported-by: Jann Horn Fixes: ee7998c50c26 ("random: do not ignore early device randomness") Cc: stable@kernel.org # 4.13+ Signed-off-by: Theodore Ts'o Signed-off-by: Greg Kroah-Hartman --- drivers/char/random.c | 55 +++++++++++++++++++++++++++++++++++++++---- 1 file changed, 51 insertions(+), 4 deletions(-) diff --git a/drivers/char/random.c b/drivers/char/random.c index d7dc9727bcf0..d64aebe7ecf3 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -786,6 +786,10 @@ static void crng_initialize(struct crng_state *crng) crng->init_time = jiffies - CRNG_RESEED_INTERVAL - 1; } +/* + * crng_fast_load() can be called by code in the interrupt service + * path. So we can't afford to dilly-dally. + */ static int crng_fast_load(const char *cp, size_t len) { unsigned long flags; @@ -812,6 +816,51 @@ static int crng_fast_load(const char *cp, size_t len) return 1; } +/* + * crng_slow_load() is called by add_device_randomness, which has two + * attributes. (1) We can't trust the buffer passed to it is + * guaranteed to be unpredictable (so it might not have any entropy at + * all), and (2) it doesn't have the performance constraints of + * crng_fast_load(). + * + * So we do something more comprehensive which is guaranteed to touch + * all of the primary_crng's state, and which uses a LFSR with a + * period of 255 as part of the mixing algorithm. Finally, we do + * *not* advance crng_init_cnt since buffer we may get may be something + * like a fixed DMI table (for example), which might very well be + * unique to the machine, but is otherwise unvarying. + */ +static int crng_slow_load(const char *cp, size_t len) +{ + unsigned long flags; + static unsigned char lfsr = 1; + unsigned char tmp; + unsigned i, max = CHACHA20_KEY_SIZE; + const char * src_buf = cp; + char * dest_buf = (char *) &primary_crng.state[4]; + + if (!spin_trylock_irqsave(&primary_crng.lock, flags)) + return 0; + if (crng_init != 0) { + spin_unlock_irqrestore(&primary_crng.lock, flags); + return 0; + } + if (len > max) + max = len; + + for (i = 0; i < max ; i++) { + tmp = lfsr; + lfsr >>= 1; + if (tmp & 1) + lfsr ^= 0xE1; + tmp = dest_buf[i % CHACHA20_KEY_SIZE]; + dest_buf[i % CHACHA20_KEY_SIZE] ^= src_buf[i % len] ^ lfsr; + lfsr += (tmp << 3) | (tmp >> 5); + } + spin_unlock_irqrestore(&primary_crng.lock, flags); + return 1; +} + static void crng_reseed(struct crng_state *crng, struct entropy_store *r) { unsigned long flags; @@ -981,10 +1030,8 @@ void add_device_randomness(const void *buf, unsigned int size) unsigned long time = random_get_entropy() ^ jiffies; unsigned long flags; - if (!crng_ready()) { - crng_fast_load(buf, size); - return; - } + if (!crng_ready() && size) + crng_slow_load(buf, size); trace_add_device_randomness(size, _RET_IP_); spin_lock_irqsave(&input_pool.lock, flags); -- GitLab From d152fcc173149a99d6f707a5b8a80d83d906755b Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Thu, 12 Apr 2018 00:50:45 -0400 Subject: [PATCH 0767/1635] random: crng_reseed() should lock the crng instance that it is modifying commit 0bb29a849a6433b72e249eea7695477b02056e94 upstream. Reported-by: Jann Horn Fixes: 1e7f583af67b ("random: make /dev/urandom scalable for silly...") Cc: stable@kernel.org # 4.8+ Signed-off-by: Theodore Ts'o Reviewed-by: Jann Horn Signed-off-by: Greg Kroah-Hartman --- drivers/char/random.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/char/random.c b/drivers/char/random.c index d64aebe7ecf3..c621f8443281 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -879,7 +879,7 @@ static void crng_reseed(struct crng_state *crng, struct entropy_store *r) _crng_backtrack_protect(&primary_crng, buf.block, CHACHA20_KEY_SIZE); } - spin_lock_irqsave(&primary_crng.lock, flags); + spin_lock_irqsave(&crng->lock, flags); for (i = 0; i < 8; i++) { unsigned long rv; if (!arch_get_random_seed_long(&rv) && @@ -889,7 +889,7 @@ static void crng_reseed(struct crng_state *crng, struct entropy_store *r) } memzero_explicit(&buf, sizeof(buf)); crng->init_time = jiffies; - spin_unlock_irqrestore(&primary_crng.lock, flags); + spin_unlock_irqrestore(&crng->lock, flags); if (crng == &primary_crng && crng_init < 2) { invalidate_batched_entropy(); crng_init = 2; -- GitLab From 90936d903c2f34663cffe68d9845debdeb85174c Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Wed, 11 Apr 2018 16:32:17 -0400 Subject: [PATCH 0768/1635] random: add new ioctl RNDRESEEDCRNG commit d848e5f8e1ebdb227d045db55fe4f825e82965fa upstream. Add a new ioctl which forces the the crng to be reseeded. Signed-off-by: Theodore Ts'o Cc: stable@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/char/random.c | 13 ++++++++++++- include/uapi/linux/random.h | 3 +++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/drivers/char/random.c b/drivers/char/random.c index c621f8443281..58a2ff7df392 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -429,6 +429,7 @@ struct crng_state primary_crng = { static int crng_init = 0; #define crng_ready() (likely(crng_init > 1)) static int crng_init_cnt = 0; +static unsigned long crng_global_init_time = 0; #define CRNG_INIT_CNT_THRESH (2*CHACHA20_KEY_SIZE) static void _extract_crng(struct crng_state *crng, __u8 out[CHACHA20_BLOCK_SIZE]); @@ -905,7 +906,8 @@ static void _extract_crng(struct crng_state *crng, unsigned long v, flags; if (crng_ready() && - time_after(jiffies, crng->init_time + CRNG_RESEED_INTERVAL)) + (time_after(crng_global_init_time, crng->init_time) || + time_after(jiffies, crng->init_time + CRNG_RESEED_INTERVAL))) crng_reseed(crng, crng == &primary_crng ? &input_pool : NULL); spin_lock_irqsave(&crng->lock, flags); if (arch_get_random_long(&v)) @@ -1738,6 +1740,7 @@ static int rand_initialize(void) init_std_data(&input_pool); init_std_data(&blocking_pool); crng_initialize(&primary_crng); + crng_global_init_time = jiffies; #ifdef CONFIG_NUMA pool = kcalloc(nr_node_ids, sizeof(*pool), GFP_KERNEL|__GFP_NOFAIL); @@ -1924,6 +1927,14 @@ static long random_ioctl(struct file *f, unsigned int cmd, unsigned long arg) input_pool.entropy_count = 0; blocking_pool.entropy_count = 0; return 0; + case RNDRESEEDCRNG: + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + if (crng_init < 2) + return -ENODATA; + crng_reseed(&primary_crng, NULL); + crng_global_init_time = jiffies - 1; + return 0; default: return -EINVAL; } diff --git a/include/uapi/linux/random.h b/include/uapi/linux/random.h index c34f4490d025..26ee91300e3e 100644 --- a/include/uapi/linux/random.h +++ b/include/uapi/linux/random.h @@ -35,6 +35,9 @@ /* Clear the entropy pool and associated counters. (Superuser only.) */ #define RNDCLEARPOOL _IO( 'R', 0x06 ) +/* Reseed CRNG. (Superuser only.) */ +#define RNDRESEEDCRNG _IO( 'R', 0x07 ) + struct rand_pool_info { int entropy_count; int buf_size; -- GitLab From 27840bc4ebb2b4bf106c3cf7cb931c277f997a24 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Tue, 3 Apr 2018 10:52:20 -0700 Subject: [PATCH 0769/1635] HID: input: fix battery level reporting on BT mice commit 2e210bbb7429cdcf1a1a3ad00c1bf98bd9bf2452 upstream. The commit 581c4484769e ("HID: input: map digitizer battery usage") assumed that devices having input (qas opposed to feature) report for battery strength would report the data on their own, without the need to be polled by the kernel; unfortunately it is not so. Many wireless mice do not send unsolicited reports with battery strength data and have to be polled explicitly. As a complication, stylus devices on digitizers are not normally connected to the base and thus can not be polled - the base can only determine battery strength in the stylus when it is in proximity. To solve this issue, we add a special flag that tells the kernel to avoid polling the device (and expect unsolicited reports) and set it when report field with physical usage of digitizer stylus (HID_DG_STYLUS). Unless this flag is set, and we have not seen the unsolicited reports, the kernel will attempt to poll the device when userspace attempts to read "capacity" and "state" attributes of power_supply object corresponding to the devices battery. Fixes: 581c4484769e ("HID: input: map digitizer battery usage") Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=198095 Cc: stable@vger.kernel.org Reported-and-tested-by: Martin van Es Signed-off-by: Dmitry Torokhov Signed-off-by: Jiri Kosina Signed-off-by: Greg Kroah-Hartman --- drivers/hid/hid-input.c | 24 +++++++++++++++++------- include/linux/hid.h | 9 ++++++++- 2 files changed, 25 insertions(+), 8 deletions(-) diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c index 44f20aac018d..bb984cc9753b 100644 --- a/drivers/hid/hid-input.c +++ b/drivers/hid/hid-input.c @@ -387,7 +387,8 @@ static int hidinput_get_battery_property(struct power_supply *psy, break; case POWER_SUPPLY_PROP_CAPACITY: - if (dev->battery_report_type == HID_FEATURE_REPORT) { + if (dev->battery_status != HID_BATTERY_REPORTED && + !dev->battery_avoid_query) { value = hidinput_query_battery_capacity(dev); if (value < 0) return value; @@ -403,17 +404,17 @@ static int hidinput_get_battery_property(struct power_supply *psy, break; case POWER_SUPPLY_PROP_STATUS: - if (!dev->battery_reported && - dev->battery_report_type == HID_FEATURE_REPORT) { + if (dev->battery_status != HID_BATTERY_REPORTED && + !dev->battery_avoid_query) { value = hidinput_query_battery_capacity(dev); if (value < 0) return value; dev->battery_capacity = value; - dev->battery_reported = true; + dev->battery_status = HID_BATTERY_QUERIED; } - if (!dev->battery_reported) + if (dev->battery_status == HID_BATTERY_UNKNOWN) val->intval = POWER_SUPPLY_STATUS_UNKNOWN; else if (dev->battery_capacity == 100) val->intval = POWER_SUPPLY_STATUS_FULL; @@ -486,6 +487,14 @@ static int hidinput_setup_battery(struct hid_device *dev, unsigned report_type, dev->battery_report_type = report_type; dev->battery_report_id = field->report->id; + /* + * Stylus is normally not connected to the device and thus we + * can't query the device and get meaningful battery strength. + * We have to wait for the device to report it on its own. + */ + dev->battery_avoid_query = report_type == HID_INPUT_REPORT && + field->physical == HID_DG_STYLUS; + dev->battery = power_supply_register(&dev->dev, psy_desc, &psy_cfg); if (IS_ERR(dev->battery)) { error = PTR_ERR(dev->battery); @@ -530,9 +539,10 @@ static void hidinput_update_battery(struct hid_device *dev, int value) capacity = hidinput_scale_battery_capacity(dev, value); - if (!dev->battery_reported || capacity != dev->battery_capacity) { + if (dev->battery_status != HID_BATTERY_REPORTED || + capacity != dev->battery_capacity) { dev->battery_capacity = capacity; - dev->battery_reported = true; + dev->battery_status = HID_BATTERY_REPORTED; power_supply_changed(dev->battery); } } diff --git a/include/linux/hid.h b/include/linux/hid.h index 7f7c72d405ba..06e6e04e6c11 100644 --- a/include/linux/hid.h +++ b/include/linux/hid.h @@ -512,6 +512,12 @@ enum hid_type { HID_TYPE_USBNONE }; +enum hid_battery_status { + HID_BATTERY_UNKNOWN = 0, + HID_BATTERY_QUERIED, /* Kernel explicitly queried battery strength */ + HID_BATTERY_REPORTED, /* Device sent unsolicited battery strength report */ +}; + struct hid_driver; struct hid_ll_driver; @@ -554,7 +560,8 @@ struct hid_device { /* device report descriptor */ __s32 battery_max; __s32 battery_report_type; __s32 battery_report_id; - bool battery_reported; + enum hid_battery_status battery_status; + bool battery_avoid_query; #endif unsigned int status; /* see STAT flags above */ -- GitLab From 0e159a9e1823469c46bf3355d87a79a2cc7f8890 Mon Sep 17 00:00:00 2001 From: Rodrigo Rivas Costa Date: Fri, 6 Apr 2018 01:09:36 +0200 Subject: [PATCH 0770/1635] HID: hidraw: Fix crash on HIDIOCGFEATURE with a destroyed device commit a955358d54695e4ad9f7d6489a7ac4d69a8fc711 upstream. Doing `ioctl(HIDIOCGFEATURE)` in a tight loop on a hidraw device and then disconnecting the device, or unloading the driver, can cause a NULL pointer dereference. When a hidraw device is destroyed it sets 0 to `dev->exist`. Most functions check 'dev->exist' before doing its work, but `hidraw_get_report()` was missing that check. Cc: stable@vger.kernel.org Signed-off-by: Rodrigo Rivas Costa Signed-off-by: Jiri Kosina Signed-off-by: Greg Kroah-Hartman --- drivers/hid/hidraw.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/hid/hidraw.c b/drivers/hid/hidraw.c index 5fbe0f81ab2e..01b5a9f01814 100644 --- a/drivers/hid/hidraw.c +++ b/drivers/hid/hidraw.c @@ -192,6 +192,11 @@ static ssize_t hidraw_get_report(struct file *file, char __user *buffer, size_t int ret = 0, len; unsigned char report_number; + if (!hidraw_table[minor] || !hidraw_table[minor]->exist) { + ret = -ENODEV; + goto out; + } + dev = hidraw_table[minor]->hid; if (!dev->ll_driver->raw_request) { -- GitLab From 1da964d421dae559422561ef407c2557d8d0348a Mon Sep 17 00:00:00 2001 From: Aaron Armstrong Skomra Date: Wed, 4 Apr 2018 14:24:11 -0700 Subject: [PATCH 0771/1635] HID: wacom: bluetooth: send exit report for recent Bluetooth devices commit 619d3a2922ce623ca2eca443cc936810d328317c upstream. The code path for recent Bluetooth devices omits an exit report which resets all the values of the device. Fixes: 4922cd26f0 ("HID: wacom: Support 2nd-gen Intuos Pro's Bluetooth classic interface") Cc: # 4.11 Signed-off-by: Aaron Armstrong Skomra Reviewed-by: Ping Cheng Signed-off-by: Jiri Kosina Signed-off-by: Greg Kroah-Hartman --- drivers/hid/wacom_wac.c | 76 +++++++++++++++++++++++++---------------- 1 file changed, 46 insertions(+), 30 deletions(-) diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c index 70cbe1e5a3d2..c401b5b63f4c 100644 --- a/drivers/hid/wacom_wac.c +++ b/drivers/hid/wacom_wac.c @@ -689,6 +689,45 @@ static int wacom_intuos_get_tool_type(int tool_id) return tool_type; } +static void wacom_exit_report(struct wacom_wac *wacom) +{ + struct input_dev *input = wacom->pen_input; + struct wacom_features *features = &wacom->features; + unsigned char *data = wacom->data; + int idx = (features->type == INTUOS) ? (data[1] & 0x01) : 0; + + /* + * Reset all states otherwise we lose the initial states + * when in-prox next time + */ + input_report_abs(input, ABS_X, 0); + input_report_abs(input, ABS_Y, 0); + input_report_abs(input, ABS_DISTANCE, 0); + input_report_abs(input, ABS_TILT_X, 0); + input_report_abs(input, ABS_TILT_Y, 0); + if (wacom->tool[idx] >= BTN_TOOL_MOUSE) { + input_report_key(input, BTN_LEFT, 0); + input_report_key(input, BTN_MIDDLE, 0); + input_report_key(input, BTN_RIGHT, 0); + input_report_key(input, BTN_SIDE, 0); + input_report_key(input, BTN_EXTRA, 0); + input_report_abs(input, ABS_THROTTLE, 0); + input_report_abs(input, ABS_RZ, 0); + } else { + input_report_abs(input, ABS_PRESSURE, 0); + input_report_key(input, BTN_STYLUS, 0); + input_report_key(input, BTN_STYLUS2, 0); + input_report_key(input, BTN_TOUCH, 0); + input_report_abs(input, ABS_WHEEL, 0); + if (features->type >= INTUOS3S) + input_report_abs(input, ABS_Z, 0); + } + input_report_key(input, wacom->tool[idx], 0); + input_report_abs(input, ABS_MISC, 0); /* reset tool id */ + input_event(input, EV_MSC, MSC_SERIAL, wacom->serial[idx]); + wacom->id[idx] = 0; +} + static int wacom_intuos_inout(struct wacom_wac *wacom) { struct wacom_features *features = &wacom->features; @@ -741,36 +780,7 @@ static int wacom_intuos_inout(struct wacom_wac *wacom) if (!wacom->id[idx]) return 1; - /* - * Reset all states otherwise we lose the initial states - * when in-prox next time - */ - input_report_abs(input, ABS_X, 0); - input_report_abs(input, ABS_Y, 0); - input_report_abs(input, ABS_DISTANCE, 0); - input_report_abs(input, ABS_TILT_X, 0); - input_report_abs(input, ABS_TILT_Y, 0); - if (wacom->tool[idx] >= BTN_TOOL_MOUSE) { - input_report_key(input, BTN_LEFT, 0); - input_report_key(input, BTN_MIDDLE, 0); - input_report_key(input, BTN_RIGHT, 0); - input_report_key(input, BTN_SIDE, 0); - input_report_key(input, BTN_EXTRA, 0); - input_report_abs(input, ABS_THROTTLE, 0); - input_report_abs(input, ABS_RZ, 0); - } else { - input_report_abs(input, ABS_PRESSURE, 0); - input_report_key(input, BTN_STYLUS, 0); - input_report_key(input, BTN_STYLUS2, 0); - input_report_key(input, BTN_TOUCH, 0); - input_report_abs(input, ABS_WHEEL, 0); - if (features->type >= INTUOS3S) - input_report_abs(input, ABS_Z, 0); - } - input_report_key(input, wacom->tool[idx], 0); - input_report_abs(input, ABS_MISC, 0); /* reset tool id */ - input_event(input, EV_MSC, MSC_SERIAL, wacom->serial[idx]); - wacom->id[idx] = 0; + wacom_exit_report(wacom); return 2; } @@ -1226,6 +1236,12 @@ static void wacom_intuos_pro2_bt_pen(struct wacom_wac *wacom) if (!valid) continue; + if (!prox) { + wacom->shared->stylus_in_proximity = false; + wacom_exit_report(wacom); + input_sync(pen_input); + return; + } if (range) { /* Fix rotation alignment: userspace expects zero at left */ int16_t rotation = (int16_t)get_unaligned_le16(&frame[9]); -- GitLab From 23f5562852b9f999d6c36606e40bcd81c64f4765 Mon Sep 17 00:00:00 2001 From: Matt Redfearn Date: Tue, 17 Apr 2018 16:40:01 +0100 Subject: [PATCH 0772/1635] MIPS: uaccess: Add micromips clobbers to bzero invocation commit b3d7e55c3f886493235bfee08e1e5a4a27cbcce8 upstream. The micromips implementation of bzero additionally clobbers registers t7 & t8. Specify this in the clobbers list when invoking bzero. Fixes: 26c5e07d1478 ("MIPS: microMIPS: Optimise 'memset' core library function.") Reported-by: James Hogan Signed-off-by: Matt Redfearn Cc: Ralf Baechle Cc: linux-mips@linux-mips.org Cc: # 3.10+ Patchwork: https://patchwork.linux-mips.org/patch/19110/ Signed-off-by: James Hogan Signed-off-by: Greg Kroah-Hartman --- arch/mips/include/asm/uaccess.h | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/arch/mips/include/asm/uaccess.h b/arch/mips/include/asm/uaccess.h index b71306947290..06629011a434 100644 --- a/arch/mips/include/asm/uaccess.h +++ b/arch/mips/include/asm/uaccess.h @@ -654,6 +654,13 @@ __clear_user(void __user *addr, __kernel_size_t size) { __kernel_size_t res; +#ifdef CONFIG_CPU_MICROMIPS +/* micromips memset / bzero also clobbers t7 & t8 */ +#define bzero_clobbers "$4", "$5", "$6", __UA_t0, __UA_t1, "$15", "$24", "$31" +#else +#define bzero_clobbers "$4", "$5", "$6", __UA_t0, __UA_t1, "$31" +#endif /* CONFIG_CPU_MICROMIPS */ + if (eva_kernel_access()) { __asm__ __volatile__( "move\t$4, %1\n\t" @@ -663,7 +670,7 @@ __clear_user(void __user *addr, __kernel_size_t size) "move\t%0, $6" : "=r" (res) : "r" (addr), "r" (size) - : "$4", "$5", "$6", __UA_t0, __UA_t1, "$31"); + : bzero_clobbers); } else { might_fault(); __asm__ __volatile__( @@ -674,7 +681,7 @@ __clear_user(void __user *addr, __kernel_size_t size) "move\t%0, $6" : "=r" (res) : "r" (addr), "r" (size) - : "$4", "$5", "$6", __UA_t0, __UA_t1, "$31"); + : bzero_clobbers); } return res; -- GitLab From 7b34760dc682d58f77dfab1810d4af2841828f6b Mon Sep 17 00:00:00 2001 From: Matt Redfearn Date: Thu, 29 Mar 2018 10:28:23 +0100 Subject: [PATCH 0773/1635] MIPS: memset.S: EVA & fault support for small_memset commit 8a8158c85e1e774a44fbe81106fa41138580dfd1 upstream. The MIPS kernel memset / bzero implementation includes a small_memset branch which is used when the region to be set is smaller than a long (4 bytes on 32bit, 8 bytes on 64bit). The current small_memset implementation uses a simple store byte loop to write the destination. There are 2 issues with this implementation: 1. When EVA mode is active, user and kernel address spaces may overlap. Currently the use of the sb instruction means kernel mode addressing is always used and an intended write to userspace may actually overwrite some critical kernel data. 2. If the write triggers a page fault, for example by calling __clear_user(NULL, 2), instead of gracefully handling the fault, an OOPS is triggered. Fix these issues by replacing the sb instruction with the EX() macro, which will emit EVA compatible instuctions as required. Additionally implement a fault fixup for small_memset which sets a2 to the number of bytes that could not be cleared (as defined by __clear_user). Reported-by: Chuanhua Lei Signed-off-by: Matt Redfearn Cc: Ralf Baechle Cc: linux-mips@linux-mips.org Cc: stable@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/18975/ Signed-off-by: James Hogan Signed-off-by: Greg Kroah-Hartman --- arch/mips/lib/memset.S | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/arch/mips/lib/memset.S b/arch/mips/lib/memset.S index a1456664d6c2..90bcdf1224ee 100644 --- a/arch/mips/lib/memset.S +++ b/arch/mips/lib/memset.S @@ -219,7 +219,7 @@ 1: PTR_ADDIU a0, 1 /* fill bytewise */ R10KCBARRIER(0(ra)) bne t1, a0, 1b - sb a1, -1(a0) + EX(sb, a1, -1(a0), .Lsmall_fixup\@) 2: jr ra /* done */ move a2, zero @@ -260,6 +260,11 @@ jr ra andi v1, a2, STORMASK +.Lsmall_fixup\@: + PTR_SUBU a2, t1, a0 + jr ra + PTR_ADDIU a2, 1 + .endm /* -- GitLab From 6da34ca1ca3e7a42b46e1265d04e827d3a6970d3 Mon Sep 17 00:00:00 2001 From: Matt Redfearn Date: Tue, 17 Apr 2018 15:52:21 +0100 Subject: [PATCH 0774/1635] MIPS: memset.S: Fix return of __clear_user from Lpartial_fixup commit daf70d89f80c6e1772233da9e020114b1254e7e0 upstream. The __clear_user function is defined to return the number of bytes that could not be cleared. From the underlying memset / bzero implementation this means setting register a2 to that number on return. Currently if a page fault is triggered within the memset_partial block, the value loaded into a2 on return is meaningless. The label .Lpartial_fixup\@ is jumped to on page fault. In order to work out how many bytes failed to copy, the exception handler should find how many bytes left in the partial block (andi a2, STORMASK), add that to the partial block end address (a2), and subtract the faulting address to get the remainder. Currently it incorrectly subtracts the partial block start address (t1), which has additionally been clobbered to generate a jump target in memset_partial. Fix this by adding the block end address instead. This issue was found with the following test code: int j, k; for (j = 0; j < 512; j++) { if ((k = clear_user(NULL, j)) != j) { pr_err("clear_user (NULL %d) returned %d\n", j, k); } } Which now passes on Creator Ci40 (MIPS32) and Cavium Octeon II (MIPS64). Suggested-by: James Hogan Signed-off-by: Matt Redfearn Cc: Ralf Baechle Cc: linux-mips@linux-mips.org Cc: stable@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/19108/ Signed-off-by: James Hogan Signed-off-by: Greg Kroah-Hartman --- arch/mips/lib/memset.S | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/mips/lib/memset.S b/arch/mips/lib/memset.S index 90bcdf1224ee..184819c1d5c8 100644 --- a/arch/mips/lib/memset.S +++ b/arch/mips/lib/memset.S @@ -252,7 +252,7 @@ PTR_L t0, TI_TASK($28) andi a2, STORMASK LONG_L t0, THREAD_BUADDR(t0) - LONG_ADDU a2, t1 + LONG_ADDU a2, a0 jr ra LONG_SUBU a2, t0 -- GitLab From a5f6e787b9b061624f525eff944fc73e08974567 Mon Sep 17 00:00:00 2001 From: Matt Redfearn Date: Tue, 17 Apr 2018 16:40:00 +0100 Subject: [PATCH 0775/1635] MIPS: memset.S: Fix clobber of v1 in last_fixup commit c96eebf07692e53bf4dd5987510d8b550e793598 upstream. The label .Llast_fixup\@ is jumped to on page fault within the final byte set loop of memset (on < MIPSR6 architectures). For some reason, in this fault handler, the v1 register is randomly set to a2 & STORMASK. This clobbers v1 for the calling function. This can be observed with the following test code: static int __init __attribute__((optimize("O0"))) test_clear_user(void) { register int t asm("v1"); char *test; int j, k; pr_info("\n\n\nTesting clear_user\n"); test = vmalloc(PAGE_SIZE); for (j = 256; j < 512; j++) { t = 0xa5a5a5a5; if ((k = clear_user(test + PAGE_SIZE - 256, j)) != j - 256) { pr_err("clear_user (%px %d) returned %d\n", test + PAGE_SIZE - 256, j, k); } if (t != 0xa5a5a5a5) { pr_err("v1 was clobbered to 0x%x!\n", t); } } return 0; } late_initcall(test_clear_user); Which demonstrates that v1 is indeed clobbered (MIPS64): Testing clear_user v1 was clobbered to 0x1! v1 was clobbered to 0x2! v1 was clobbered to 0x3! v1 was clobbered to 0x4! v1 was clobbered to 0x5! v1 was clobbered to 0x6! v1 was clobbered to 0x7! Since the number of bytes that could not be set is already contained in a2, the andi placing a value in v1 is not necessary and actively harmful in clobbering v1. Reported-by: James Hogan Signed-off-by: Matt Redfearn Cc: Ralf Baechle Cc: linux-mips@linux-mips.org Cc: stable@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/19109/ Signed-off-by: James Hogan Signed-off-by: Greg Kroah-Hartman --- arch/mips/lib/memset.S | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/mips/lib/memset.S b/arch/mips/lib/memset.S index 184819c1d5c8..f7327979a8f8 100644 --- a/arch/mips/lib/memset.S +++ b/arch/mips/lib/memset.S @@ -258,7 +258,7 @@ .Llast_fixup\@: jr ra - andi v1, a2, STORMASK + nop .Lsmall_fixup\@: PTR_SUBU a2, t1, a0 -- GitLab From 49a52f7d9274da3f32d7c3b51843fa44fffd2e55 Mon Sep 17 00:00:00 2001 From: Michael Neuling Date: Wed, 11 Apr 2018 13:37:58 +1000 Subject: [PATCH 0776/1635] powerpc/eeh: Fix enabling bridge MMIO windows commit 13a83eac373c49c0a081cbcd137e79210fe78acd upstream. On boot we save the configuration space of PCIe bridges. We do this so when we get an EEH event and everything gets reset that we can restore them. Unfortunately we save this state before we've enabled the MMIO space on the bridges. Hence if we have to reset the bridge when we come back MMIO is not enabled and we end up taking an PE freeze when the driver starts accessing again. This patch forces the memory/MMIO and bus mastering on when restoring bridges on EEH. Ideally we'd do this correctly by saving the configuration space writes later, but that will have to come later in a larger EEH rewrite. For now we have this simple fix. The original bug can be triggered on a boston machine by doing: echo 0x8000000000000000 > /sys/kernel/debug/powerpc/PCI0001/err_injct_outbound On boston, this PHB has a PCIe switch on it. Without this patch, you'll see two EEH events, 1 expected and 1 the failure we are fixing here. The second EEH event causes the anything under the PHB to disappear (i.e. the i40e eth). With this patch, only 1 EEH event occurs and devices properly recover. Fixes: 652defed4875 ("powerpc/eeh: Check PCIe link after reset") Cc: stable@vger.kernel.org # v3.11+ Reported-by: Pridhiviraj Paidipeddi Signed-off-by: Michael Neuling Acked-by: Russell Currey Signed-off-by: Michael Ellerman Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/kernel/eeh_pe.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/powerpc/kernel/eeh_pe.c b/arch/powerpc/kernel/eeh_pe.c index 2e8d1b2b5af4..8545a9523b9b 100644 --- a/arch/powerpc/kernel/eeh_pe.c +++ b/arch/powerpc/kernel/eeh_pe.c @@ -807,7 +807,8 @@ static void eeh_restore_bridge_bars(struct eeh_dev *edev) eeh_ops->write_config(pdn, 15*4, 4, edev->config_space[15]); /* PCI Command: 0x4 */ - eeh_ops->write_config(pdn, PCI_COMMAND, 4, edev->config_space[1]); + eeh_ops->write_config(pdn, PCI_COMMAND, 4, edev->config_space[1] | + PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER); /* Check the PCIe link is ready */ eeh_bridge_check_link(edev); -- GitLab From ce3b0b0589a8b7e0241c0d1b1049a715108b78fb Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Wed, 11 Apr 2018 15:17:59 +1000 Subject: [PATCH 0777/1635] powerpc/xive: Fix trying to "push" an already active pool VP commit b32e56e5a87a1f9243db92bc7a5df0ffb4627cfb upstream. When setting up a CPU, we "push" (activate) a pool VP for it. However it's an error to do so if it already has an active pool VP. This happens when doing soft CPU hotplug on powernv since we don't tear down the CPU on unplug. The HW flags the error which gets captured by the diagnostics. Fix this by making sure to "pull" out any already active pool first. Fixes: 243e25112d06 ("powerpc/xive: Native exploitation of the XIVE interrupt controller") Cc: stable@vger.kernel.org # v4.12+ Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Michael Ellerman Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/sysdev/xive/native.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/powerpc/sysdev/xive/native.c b/arch/powerpc/sysdev/xive/native.c index ebc244b08d67..0f89ee557b04 100644 --- a/arch/powerpc/sysdev/xive/native.c +++ b/arch/powerpc/sysdev/xive/native.c @@ -388,6 +388,10 @@ static void xive_native_setup_cpu(unsigned int cpu, struct xive_cpu *xc) if (xive_pool_vps == XIVE_INVALID_VP) return; + /* Check if pool VP already active, if it is, pull it */ + if (in_be32(xive_tima + TM_QW2_HV_POOL + TM_WORD2) & TM_QW2W2_VP) + in_be64(xive_tima + TM_SPC_PULL_POOL_CTX); + /* Enable the pool VP */ vp = xive_pool_vps + cpu; pr_debug("CPU %d setting up pool VP 0x%x\n", cpu, vp); -- GitLab From f86815184c471dae61f3c764b7589872a91e930a Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Mon, 16 Apr 2018 23:25:19 +1000 Subject: [PATCH 0778/1635] powerpc/lib: Fix off-by-one in alternate feature patching commit b8858581febb050688e276b956796bc4a78299ed upstream. When we patch an alternate feature section, we have to adjust any relative branches that branch out of the alternate section. But currently we have a bug if we have a branch that points to past the last instruction of the alternate section, eg: FTR_SECTION_ELSE 1: b 2f or 6,6,6 2: ALT_FTR_SECTION_END(...) nop This will result in a relative branch at 1 with a target that equals the end of the alternate section. That branch does not need adjusting when it's moved to the non-else location. Currently we do adjust it, resulting in a branch that goes off into the link-time location of the else section, which is junk. The fix is to not patch branches that have a target == end of the alternate section. Fixes: d20fe50a7b3c ("KVM: PPC: Book3S HV: Branch inside feature section") Fixes: 9b1a735de64c ("powerpc: Add logic to patch alternative feature sections") Cc: stable@vger.kernel.org # v2.6.27+ Signed-off-by: Michael Ellerman Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/lib/feature-fixups.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/powerpc/lib/feature-fixups.c b/arch/powerpc/lib/feature-fixups.c index a95ea007d654..d0c0b8443dcf 100644 --- a/arch/powerpc/lib/feature-fixups.c +++ b/arch/powerpc/lib/feature-fixups.c @@ -55,7 +55,7 @@ static int patch_alt_instruction(unsigned int *src, unsigned int *dest, unsigned int *target = (unsigned int *)branch_target(src); /* Branch within the section doesn't need translating */ - if (target < alt_start || target >= alt_end) { + if (target < alt_start || target > alt_end) { instr = translate_branch(dest, src); if (!instr) return 1; -- GitLab From a2a9d0190f9964dd734348085c22582e519c145a Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Thu, 12 Apr 2018 17:22:23 +0200 Subject: [PATCH 0779/1635] udf: Fix leak of UTF-16 surrogates into encoded strings commit 44f06ba8297c7e9dfd0e49b40cbe119113cca094 upstream. OSTA UDF specification does not mention whether the CS0 charset in case of two bytes per character encoding should be treated in UTF-16 or UCS-2. The sample code in the standard does not treat UTF-16 surrogates in any special way but on systems such as Windows which work in UTF-16 internally, filenames would be treated as being in UTF-16 effectively. In Linux it is more difficult to handle characters outside of Base Multilingual plane (beyond 0xffff) as NLS framework works with 2-byte characters only. Just make sure we don't leak UTF-16 surrogates into the resulting string when loading names from the filesystem for now. CC: stable@vger.kernel.org # >= v4.6 Reported-by: Mingye Wang Signed-off-by: Jan Kara Signed-off-by: Greg Kroah-Hartman --- fs/udf/unicode.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/fs/udf/unicode.c b/fs/udf/unicode.c index 695389a4fc23..3a3be23689b3 100644 --- a/fs/udf/unicode.c +++ b/fs/udf/unicode.c @@ -28,6 +28,9 @@ #include "udf_sb.h" +#define SURROGATE_MASK 0xfffff800 +#define SURROGATE_PAIR 0x0000d800 + static int udf_uni2char_utf8(wchar_t uni, unsigned char *out, int boundlen) @@ -37,6 +40,9 @@ static int udf_uni2char_utf8(wchar_t uni, if (boundlen <= 0) return -ENAMETOOLONG; + if ((uni & SURROGATE_MASK) == SURROGATE_PAIR) + return -EINVAL; + if (uni < 0x80) { out[u_len++] = (unsigned char)uni; } else if (uni < 0x800) { -- GitLab From 28f46dee49d3eac6dbeac3e4c9ecf1b861d2594b Mon Sep 17 00:00:00 2001 From: Amir Goldstein Date: Wed, 4 Apr 2018 23:42:18 +0300 Subject: [PATCH 0780/1635] fanotify: fix logic of events on child commit 54a307ba8d3cd00a3902337ffaae28f436eeb1a4 upstream. When event on child inodes are sent to the parent inode mark and parent inode mark was not marked with FAN_EVENT_ON_CHILD, the event will not be delivered to the listener process. However, if the same process also has a mount mark, the event to the parent inode will be delivered regadless of the mount mark mask. This behavior is incorrect in the case where the mount mark mask does not contain the specific event type. For example, the process adds a mark on a directory with mask FAN_MODIFY (without FAN_EVENT_ON_CHILD) and a mount mark with mask FAN_CLOSE_NOWRITE (without FAN_ONDIR). A modify event on a file inside that directory (and inside that mount) should not create a FAN_MODIFY event, because neither of the marks requested to get that event on the file. Fixes: 1968f5eed54c ("fanotify: use both marks when possible") Cc: stable Signed-off-by: Amir Goldstein Signed-off-by: Jan Kara Signed-off-by: Greg Kroah-Hartman --- fs/notify/fanotify/fanotify.c | 34 +++++++++++++++------------------- 1 file changed, 15 insertions(+), 19 deletions(-) diff --git a/fs/notify/fanotify/fanotify.c b/fs/notify/fanotify/fanotify.c index 3c7053207297..bd520450c37a 100644 --- a/fs/notify/fanotify/fanotify.c +++ b/fs/notify/fanotify/fanotify.c @@ -90,7 +90,7 @@ static bool fanotify_should_send_event(struct fsnotify_mark *inode_mark, u32 event_mask, const void *data, int data_type) { - __u32 marks_mask, marks_ignored_mask; + __u32 marks_mask = 0, marks_ignored_mask = 0; const struct path *path = data; pr_debug("%s: inode_mark=%p vfsmnt_mark=%p mask=%x data=%p" @@ -106,24 +106,20 @@ static bool fanotify_should_send_event(struct fsnotify_mark *inode_mark, !d_can_lookup(path->dentry)) return false; - if (inode_mark && vfsmnt_mark) { - marks_mask = (vfsmnt_mark->mask | inode_mark->mask); - marks_ignored_mask = (vfsmnt_mark->ignored_mask | inode_mark->ignored_mask); - } else if (inode_mark) { - /* - * if the event is for a child and this inode doesn't care about - * events on the child, don't send it! - */ - if ((event_mask & FS_EVENT_ON_CHILD) && - !(inode_mark->mask & FS_EVENT_ON_CHILD)) - return false; - marks_mask = inode_mark->mask; - marks_ignored_mask = inode_mark->ignored_mask; - } else if (vfsmnt_mark) { - marks_mask = vfsmnt_mark->mask; - marks_ignored_mask = vfsmnt_mark->ignored_mask; - } else { - BUG(); + /* + * if the event is for a child and this inode doesn't care about + * events on the child, don't send it! + */ + if (inode_mark && + (!(event_mask & FS_EVENT_ON_CHILD) || + (inode_mark->mask & FS_EVENT_ON_CHILD))) { + marks_mask |= inode_mark->mask; + marks_ignored_mask |= inode_mark->ignored_mask; + } + + if (vfsmnt_mark) { + marks_mask |= vfsmnt_mark->mask; + marks_ignored_mask |= vfsmnt_mark->ignored_mask; } if (d_is_dir(path->dentry) && -- GitLab From 4bddb1209a6df483487b241b586f9ef12c88ab8c Mon Sep 17 00:00:00 2001 From: Daniel Kurtz Date: Fri, 6 Apr 2018 16:07:59 -0600 Subject: [PATCH 0781/1635] mmc: sdhci-pci: Only do AMD tuning for HS200 commit 300ad8992913025b4294d4fc37b6bfff4a8b7ad1 upstream. Commit c31165d7400b ("mmc: sdhci-pci: Add support for HS200 tuning mode on AMD, eMMC-4.5.1") added a HS200 tuning method for use with AMD SDHCI controllers. As described in the commit subject, this tuning is specific for HS200. However, as implemented, this method is used for all host timings, because platform_execute_tuning, if it exists, is called unconditionally by sdhci_execute_tuning(). This breaks tuning when using the AMD controller with, for example, a DDR50 SD card. Instead, we can implement an amd execute_tuning wrapper callback, and then conditionally do the HS200 specific tuning for HS200, and otherwise call back to the standard sdhci_execute_tuning(). Signed-off-by: Daniel Kurtz Acked-by: Shyam Sundar S K Acked-by: Adrian Hunter Fixes: c31165d7400b ("mmc: sdhci-pci: Add support for HS200 tuning mode on AMD, eMMC-4.5.1") Cc: stable@vger.kernel.org # v4.11+ Signed-off-by: Ulf Hansson Signed-off-by: Greg Kroah-Hartman --- drivers/mmc/host/sdhci-pci-core.c | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/host/sdhci-pci-core.c b/drivers/mmc/host/sdhci-pci-core.c index 5bedf4b7f0f7..44da037b13ba 100644 --- a/drivers/mmc/host/sdhci-pci-core.c +++ b/drivers/mmc/host/sdhci-pci-core.c @@ -1192,7 +1192,7 @@ static void amd_enable_manual_tuning(struct pci_dev *pdev) pci_write_config_dword(pdev, AMD_SD_MISC_CONTROL, val); } -static int amd_execute_tuning(struct sdhci_host *host, u32 opcode) +static int amd_execute_tuning_hs200(struct sdhci_host *host, u32 opcode) { struct sdhci_pci_slot *slot = sdhci_priv(host); struct pci_dev *pdev = slot->chip->pdev; @@ -1231,6 +1231,27 @@ static int amd_execute_tuning(struct sdhci_host *host, u32 opcode) return 0; } +static int amd_execute_tuning(struct mmc_host *mmc, u32 opcode) +{ + struct sdhci_host *host = mmc_priv(mmc); + + /* AMD requires custom HS200 tuning */ + if (host->timing == MMC_TIMING_MMC_HS200) + return amd_execute_tuning_hs200(host, opcode); + + /* Otherwise perform standard SDHCI tuning */ + return sdhci_execute_tuning(mmc, opcode); +} + +static int amd_probe_slot(struct sdhci_pci_slot *slot) +{ + struct mmc_host_ops *ops = &slot->host->mmc_host_ops; + + ops->execute_tuning = amd_execute_tuning; + + return 0; +} + static int amd_probe(struct sdhci_pci_chip *chip) { struct pci_dev *smbus_dev; @@ -1265,12 +1286,12 @@ static const struct sdhci_ops amd_sdhci_pci_ops = { .set_bus_width = sdhci_set_bus_width, .reset = sdhci_reset, .set_uhs_signaling = sdhci_set_uhs_signaling, - .platform_execute_tuning = amd_execute_tuning, }; static const struct sdhci_pci_fixes sdhci_amd = { .probe = amd_probe, .ops = &amd_sdhci_pci_ops, + .probe_slot = amd_probe_slot, }; static const struct pci_device_id pci_ids[] = { -- GitLab From 22ec5ee71086284911b21339eaf4d2c2ec1df351 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 14 Feb 2018 21:23:23 +0200 Subject: [PATCH 0782/1635] drm/i915: Correctly handle limited range YCbCr data on VLV/CHV MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 5deae9191130db6b617c94fb261804597cf9b508 upstream. Turns out the VLV/CHV fixed function sprite CSC expects full range data as input. We've been feeding it limited range data to it all along. To expand the data out to full range we'll use the color correction registers (brightness, contrast, and saturation). On CHV pipe B we were actually doing the right thing already because we progammed the custom CSC matrix to do expect limited range input. Now that well pre-expand the data out with the color correction unit, we need to change the CSC matrix to operate with full range input instead. This should make the sprite output of the other pipes match the sprite output of pipe B reasonably well. Looking at the resulting pipe CRCs, there can be a slight difference in the output, but as I don't know the formula used by the fixed function CSC of the other pipes, I don't think it's worth the effort to try to match the output exactly. It might not even be possible due to difference in internal precision etc. One slight caveat here is that the color correction registers are single bufferred, so we should really be updating them during vblank, but we still don't have a mechanism for that, so just toss in another FIXME. v2: Rebase v3: s/bri/brightness/ s/con/contrast/ (Shashank) v4: Clarify the constants and math (Shashank) Cc: Harry Wentland Cc: Daniel Vetter Cc: Daniel Stone Cc: Russell King - ARM Linux Cc: Ilia Mirkin Cc: Hans Verkuil Cc: Shashank Sharma Cc: Uma Shankar Cc: Jyri Sarha Cc: "Tang, Jun" Reported-by: "Tang, Jun" Cc: stable@vger.kernel.org Fixes: 7f1f3851feb0 ("drm/i915: sprite support for ValleyView v4") Reviewed-by: Shashank Sharma Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20180214192327.3250-5-ville.syrjala@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/i915/i915_reg.h | 10 ++++ drivers/gpu/drm/i915/intel_sprite.c | 81 ++++++++++++++++++++++------- 2 files changed, 73 insertions(+), 18 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 920c8914cec1..cc70e2470272 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -6159,6 +6159,12 @@ enum { #define _SPATILEOFF (VLV_DISPLAY_BASE + 0x721a4) #define _SPACONSTALPHA (VLV_DISPLAY_BASE + 0x721a8) #define SP_CONST_ALPHA_ENABLE (1<<31) +#define _SPACLRC0 (VLV_DISPLAY_BASE + 0x721d0) +#define SP_CONTRAST(x) ((x) << 18) /* u3.6 */ +#define SP_BRIGHTNESS(x) ((x) & 0xff) /* s8 */ +#define _SPACLRC1 (VLV_DISPLAY_BASE + 0x721d4) +#define SP_SH_SIN(x) (((x) & 0x7ff) << 16) /* s4.7 */ +#define SP_SH_COS(x) (x) /* u3.7 */ #define _SPAGAMC (VLV_DISPLAY_BASE + 0x721f4) #define _SPBCNTR (VLV_DISPLAY_BASE + 0x72280) @@ -6172,6 +6178,8 @@ enum { #define _SPBKEYMAXVAL (VLV_DISPLAY_BASE + 0x722a0) #define _SPBTILEOFF (VLV_DISPLAY_BASE + 0x722a4) #define _SPBCONSTALPHA (VLV_DISPLAY_BASE + 0x722a8) +#define _SPBCLRC0 (VLV_DISPLAY_BASE + 0x722d0) +#define _SPBCLRC1 (VLV_DISPLAY_BASE + 0x722d4) #define _SPBGAMC (VLV_DISPLAY_BASE + 0x722f4) #define _MMIO_VLV_SPR(pipe, plane_id, reg_a, reg_b) \ @@ -6188,6 +6196,8 @@ enum { #define SPKEYMAXVAL(pipe, plane_id) _MMIO_VLV_SPR((pipe), (plane_id), _SPAKEYMAXVAL, _SPBKEYMAXVAL) #define SPTILEOFF(pipe, plane_id) _MMIO_VLV_SPR((pipe), (plane_id), _SPATILEOFF, _SPBTILEOFF) #define SPCONSTALPHA(pipe, plane_id) _MMIO_VLV_SPR((pipe), (plane_id), _SPACONSTALPHA, _SPBCONSTALPHA) +#define SPCLRC0(pipe, plane_id) _MMIO_VLV_SPR((pipe), (plane_id), _SPACLRC0, _SPBCLRC0) +#define SPCLRC1(pipe, plane_id) _MMIO_VLV_SPR((pipe), (plane_id), _SPACLRC1, _SPBCLRC1) #define SPGAMC(pipe, plane_id) _MMIO_VLV_SPR((pipe), (plane_id), _SPAGAMC, _SPBGAMC) /* diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c index f8ebeb5ffb96..41e31a454604 100644 --- a/drivers/gpu/drm/i915/intel_sprite.c +++ b/drivers/gpu/drm/i915/intel_sprite.c @@ -345,44 +345,87 @@ skl_plane_get_hw_state(struct intel_plane *plane) } static void -chv_update_csc(struct intel_plane *plane, uint32_t format) +chv_update_csc(const struct intel_plane_state *plane_state) { + struct intel_plane *plane = to_intel_plane(plane_state->base.plane); struct drm_i915_private *dev_priv = to_i915(plane->base.dev); + const struct drm_framebuffer *fb = plane_state->base.fb; enum plane_id plane_id = plane->id; /* Seems RGB data bypasses the CSC always */ - if (!format_is_yuv(format)) + if (!format_is_yuv(fb->format->format)) return; /* - * BT.601 limited range YCbCr -> full range RGB + * BT.601 full range YCbCr -> full range RGB * - * |r| | 6537 4769 0| |cr | - * |g| = |-3330 4769 -1605| x |y-64| - * |b| | 0 4769 8263| |cb | + * |r| | 5743 4096 0| |cr| + * |g| = |-2925 4096 -1410| x |y | + * |b| | 0 4096 7258| |cb| * - * Cb and Cr apparently come in as signed already, so no - * need for any offset. For Y we need to remove the offset. + * Cb and Cr apparently come in as signed already, + * and we get full range data in on account of CLRC0/1 */ - I915_WRITE_FW(SPCSCYGOFF(plane_id), SPCSC_OOFF(0) | SPCSC_IOFF(-64)); + I915_WRITE_FW(SPCSCYGOFF(plane_id), SPCSC_OOFF(0) | SPCSC_IOFF(0)); I915_WRITE_FW(SPCSCCBOFF(plane_id), SPCSC_OOFF(0) | SPCSC_IOFF(0)); I915_WRITE_FW(SPCSCCROFF(plane_id), SPCSC_OOFF(0) | SPCSC_IOFF(0)); - I915_WRITE_FW(SPCSCC01(plane_id), SPCSC_C1(4769) | SPCSC_C0(6537)); - I915_WRITE_FW(SPCSCC23(plane_id), SPCSC_C1(-3330) | SPCSC_C0(0)); - I915_WRITE_FW(SPCSCC45(plane_id), SPCSC_C1(-1605) | SPCSC_C0(4769)); - I915_WRITE_FW(SPCSCC67(plane_id), SPCSC_C1(4769) | SPCSC_C0(0)); - I915_WRITE_FW(SPCSCC8(plane_id), SPCSC_C0(8263)); + I915_WRITE_FW(SPCSCC01(plane_id), SPCSC_C1(4096) | SPCSC_C0(5743)); + I915_WRITE_FW(SPCSCC23(plane_id), SPCSC_C1(-2925) | SPCSC_C0(0)); + I915_WRITE_FW(SPCSCC45(plane_id), SPCSC_C1(-1410) | SPCSC_C0(4096)); + I915_WRITE_FW(SPCSCC67(plane_id), SPCSC_C1(4096) | SPCSC_C0(0)); + I915_WRITE_FW(SPCSCC8(plane_id), SPCSC_C0(7258)); - I915_WRITE_FW(SPCSCYGICLAMP(plane_id), SPCSC_IMAX(940) | SPCSC_IMIN(64)); - I915_WRITE_FW(SPCSCCBICLAMP(plane_id), SPCSC_IMAX(448) | SPCSC_IMIN(-448)); - I915_WRITE_FW(SPCSCCRICLAMP(plane_id), SPCSC_IMAX(448) | SPCSC_IMIN(-448)); + I915_WRITE_FW(SPCSCYGICLAMP(plane_id), SPCSC_IMAX(1023) | SPCSC_IMIN(0)); + I915_WRITE_FW(SPCSCCBICLAMP(plane_id), SPCSC_IMAX(512) | SPCSC_IMIN(-512)); + I915_WRITE_FW(SPCSCCRICLAMP(plane_id), SPCSC_IMAX(512) | SPCSC_IMIN(-512)); I915_WRITE_FW(SPCSCYGOCLAMP(plane_id), SPCSC_OMAX(1023) | SPCSC_OMIN(0)); I915_WRITE_FW(SPCSCCBOCLAMP(plane_id), SPCSC_OMAX(1023) | SPCSC_OMIN(0)); I915_WRITE_FW(SPCSCCROCLAMP(plane_id), SPCSC_OMAX(1023) | SPCSC_OMIN(0)); } +#define SIN_0 0 +#define COS_0 1 + +static void +vlv_update_clrc(const struct intel_plane_state *plane_state) +{ + struct intel_plane *plane = to_intel_plane(plane_state->base.plane); + struct drm_i915_private *dev_priv = to_i915(plane->base.dev); + const struct drm_framebuffer *fb = plane_state->base.fb; + enum pipe pipe = plane->pipe; + enum plane_id plane_id = plane->id; + int contrast, brightness, sh_scale, sh_sin, sh_cos; + + if (format_is_yuv(fb->format->format)) { + /* + * Expand limited range to full range: + * Contrast is applied first and is used to expand Y range. + * Brightness is applied second and is used to remove the + * offset from Y. Saturation/hue is used to expand CbCr range. + */ + contrast = DIV_ROUND_CLOSEST(255 << 6, 235 - 16); + brightness = -DIV_ROUND_CLOSEST(16 * 255, 235 - 16); + sh_scale = DIV_ROUND_CLOSEST(128 << 7, 240 - 128); + sh_sin = SIN_0 * sh_scale; + sh_cos = COS_0 * sh_scale; + } else { + /* Pass-through everything. */ + contrast = 1 << 6; + brightness = 0; + sh_scale = 1 << 7; + sh_sin = SIN_0 * sh_scale; + sh_cos = COS_0 * sh_scale; + } + + /* FIXME these register are single buffered :( */ + I915_WRITE_FW(SPCLRC0(pipe, plane_id), + SP_CONTRAST(contrast) | SP_BRIGHTNESS(brightness)); + I915_WRITE_FW(SPCLRC1(pipe, plane_id), + SP_SH_SIN(sh_sin) | SP_SH_COS(sh_cos)); +} + static u32 vlv_sprite_ctl(const struct intel_crtc_state *crtc_state, const struct intel_plane_state *plane_state) { @@ -476,8 +519,10 @@ vlv_update_plane(struct intel_plane *plane, spin_lock_irqsave(&dev_priv->uncore.lock, irqflags); + vlv_update_clrc(plane_state); + if (IS_CHERRYVIEW(dev_priv) && pipe == PIPE_B) - chv_update_csc(plane, fb->format->format); + chv_update_csc(plane_state); if (key->flags) { I915_WRITE_FW(SPKEYMINVAL(pipe, plane_id), key->min_value); -- GitLab From c780ac96e120081a1d2e892f47ce34245ef1cfb2 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 2 Apr 2018 23:56:44 -0400 Subject: [PATCH 0783/1635] jffs2_kill_sb(): deal with failed allocations commit c66b23c2840446a82c389e4cb1a12eb2a71fa2e4 upstream. jffs2_fill_super() might fail to allocate jffs2_sb_info; jffs2_kill_sb() must survive that. Cc: stable@kernel.org Signed-off-by: Al Viro Signed-off-by: Greg Kroah-Hartman --- fs/jffs2/super.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/jffs2/super.c b/fs/jffs2/super.c index 153f1c6eb169..33e01de576d2 100644 --- a/fs/jffs2/super.c +++ b/fs/jffs2/super.c @@ -342,7 +342,7 @@ static void jffs2_put_super (struct super_block *sb) static void jffs2_kill_sb(struct super_block *sb) { struct jffs2_sb_info *c = JFFS2_SB_INFO(sb); - if (!sb_rdonly(sb)) + if (c && !sb_rdonly(sb)) jffs2_stop_garbage_collect_thread(c); kill_mtd_super(sb); kfree(c); -- GitLab From bb5def77d0a1e41b53f7049fdb0f640408194068 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 2 Apr 2018 23:50:31 -0400 Subject: [PATCH 0784/1635] hypfs_kill_super(): deal with failed allocations commit a24cd490739586a7d2da3549a1844e1d7c4f4fc4 upstream. hypfs_fill_super() might fail to allocate sbi; hypfs_kill_super() should not oops on that. Cc: stable@vger.kernel.org Signed-off-by: Al Viro Signed-off-by: Greg Kroah-Hartman --- arch/s390/hypfs/inode.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/s390/hypfs/inode.c b/arch/s390/hypfs/inode.c index cf8a2d92467f..45eb5999110b 100644 --- a/arch/s390/hypfs/inode.c +++ b/arch/s390/hypfs/inode.c @@ -320,7 +320,7 @@ static void hypfs_kill_super(struct super_block *sb) if (sb->s_root) hypfs_delete_tree(sb->s_root); - if (sb_info->update_file) + if (sb_info && sb_info->update_file) hypfs_remove(sb_info->update_file); kfree(sb->s_fs_info); sb->s_fs_info = NULL; -- GitLab From 0bb4a6f2ff1a9081a35b07760fa40f9880d16bc6 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 3 Apr 2018 00:13:17 -0400 Subject: [PATCH 0785/1635] orangefs_kill_sb(): deal with allocation failures commit 659038428cb43a66e3eff71e2c845c9de3611a98 upstream. orangefs_fill_sb() might've failed to allocate ORANGEFS_SB(s); don't oops in that case. Cc: stable@kernel.org Signed-off-by: Al Viro Signed-off-by: Greg Kroah-Hartman --- fs/orangefs/super.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/fs/orangefs/super.c b/fs/orangefs/super.c index 47ebd9bfd1a1..1997ce49ab46 100644 --- a/fs/orangefs/super.c +++ b/fs/orangefs/super.c @@ -594,6 +594,11 @@ void orangefs_kill_sb(struct super_block *sb) /* provided sb cleanup */ kill_anon_super(sb); + if (!ORANGEFS_SB(sb)) { + mutex_lock(&orangefs_request_mutex); + mutex_unlock(&orangefs_request_mutex); + return; + } /* * issue the unmount to userspace to tell it to remove the * dynamic mount info it has for this superblock -- GitLab From 085125572a453938bf4b0f483ccb0d76c40f1d1c Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 3 Apr 2018 01:15:46 -0400 Subject: [PATCH 0786/1635] rpc_pipefs: fix double-dput() commit 4a3877c4cedd95543f8726b0a98743ed8db0c0fb upstream. if we ever hit rpc_gssd_dummy_depopulate() dentry passed to it has refcount equal to 1. __rpc_rmpipe() drops it and dput() done after that hits an already freed dentry. Cc: stable@kernel.org Signed-off-by: Al Viro Signed-off-by: Greg Kroah-Hartman --- net/sunrpc/rpc_pipe.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c index 61a504fb1ae2..34f94052c519 100644 --- a/net/sunrpc/rpc_pipe.c +++ b/net/sunrpc/rpc_pipe.c @@ -1375,6 +1375,7 @@ rpc_gssd_dummy_depopulate(struct dentry *pipe_dentry) struct dentry *clnt_dir = pipe_dentry->d_parent; struct dentry *gssd_dir = clnt_dir->d_parent; + dget(pipe_dentry); __rpc_rmpipe(d_inode(clnt_dir), pipe_dentry); __rpc_depopulate(clnt_dir, gssd_dummy_info_file, 0, 1); __rpc_depopulate(gssd_dir, gssd_dummy_clnt_dir, 0, 1); -- GitLab From d4d49cb1c20a13f03cf1740f5ae690cb1dd1f43d Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 19 Apr 2018 22:03:08 -0400 Subject: [PATCH 0787/1635] Don't leak MNT_INTERNAL away from internal mounts commit 16a34adb9392b2fe4195267475ab5b472e55292c upstream. We want it only for the stuff created by SB_KERNMOUNT mounts, *not* for their copies. As it is, creating a deep stack of bindings of /proc/*/ns/* somewhere in a new namespace and exiting yields a stack overflow. Cc: stable@kernel.org Reported-by: Alexander Aring Bisected-by: Kirill Tkhai Tested-by: Kirill Tkhai Tested-by: Alexander Aring Signed-off-by: Al Viro Signed-off-by: Greg Kroah-Hartman --- fs/namespace.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fs/namespace.c b/fs/namespace.c index adae9ffce91d..62b17aff1908 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -1089,7 +1089,8 @@ static struct mount *clone_mnt(struct mount *old, struct dentry *root, goto out_free; } - mnt->mnt.mnt_flags = old->mnt.mnt_flags & ~(MNT_WRITE_HOLD|MNT_MARKED); + mnt->mnt.mnt_flags = old->mnt.mnt_flags; + mnt->mnt.mnt_flags &= ~(MNT_WRITE_HOLD|MNT_MARKED|MNT_INTERNAL); /* Don't allow unprivileged users to change mount flags */ if (flag & CL_UNPRIVILEGED) { mnt->mnt.mnt_flags |= MNT_LOCK_ATIME; -- GitLab From 5e7575c6690a2871a1db5d5fe86c8fe8aef00cd8 Mon Sep 17 00:00:00 2001 From: Ian Kent Date: Fri, 20 Apr 2018 14:55:59 -0700 Subject: [PATCH 0788/1635] autofs: mount point create should honour passed in mode commit 1e6306652ba18723015d1b4967fe9de55f042499 upstream. The autofs file system mkdir inode operation blindly sets the created directory mode to S_IFDIR | 0555, ingoring the passed in mode, which can cause selinux dac_override denials. But the function also checks if the caller is the daemon (as no-one else should be able to do anything here) so there's no point in not honouring the passed in mode, allowing the daemon to set appropriate mode when required. Link: http://lkml.kernel.org/r/152361593601.8051.14014139124905996173.stgit@pluto.themaw.net Signed-off-by: Ian Kent Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- fs/autofs4/root.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/autofs4/root.c b/fs/autofs4/root.c index 82e8f6edfb48..b12e37f27530 100644 --- a/fs/autofs4/root.c +++ b/fs/autofs4/root.c @@ -749,7 +749,7 @@ static int autofs4_dir_mkdir(struct inode *dir, autofs4_del_active(dentry); - inode = autofs4_get_inode(dir->i_sb, S_IFDIR | 0555); + inode = autofs4_get_inode(dir->i_sb, S_IFDIR | mode); if (!inode) return -ENOMEM; d_add(dentry, inode); -- GitLab From 90a32d1f0ec9844b7984f52f07fe7bcb0abfb6a7 Mon Sep 17 00:00:00 2001 From: Matthew Wilcox Date: Fri, 20 Apr 2018 14:56:20 -0700 Subject: [PATCH 0789/1635] mm/filemap.c: fix NULL pointer in page_cache_tree_insert() commit abc1be13fd113ddef5e2d807a466286b864caed3 upstream. f2fs specifies the __GFP_ZERO flag for allocating some of its pages. Unfortunately, the page cache also uses the mapping's GFP flags for allocating radix tree nodes. It always masked off the __GFP_HIGHMEM flag, and masks off __GFP_ZERO in some paths, but not all. That causes radix tree nodes to be allocated with a NULL list_head, which causes backtraces like: __list_del_entry+0x30/0xd0 list_lru_del+0xac/0x1ac page_cache_tree_insert+0xd8/0x110 The __GFP_DMA and __GFP_DMA32 flags would also be able to sneak through if they are ever used. Fix them all by using GFP_RECLAIM_MASK at the innermost location, and remove it from earlier in the callchain. Link: http://lkml.kernel.org/r/20180411060320.14458-2-willy@infradead.org Fixes: 449dd6984d0e ("mm: keep page cache radix tree nodes in check") Signed-off-by: Matthew Wilcox Reported-by: Chris Fries Debugged-by: Minchan Kim Acked-by: Johannes Weiner Acked-by: Michal Hocko Reviewed-by: Jan Kara Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- mm/filemap.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/mm/filemap.c b/mm/filemap.c index 594d73fef8b4..e2e738cc08b1 100644 --- a/mm/filemap.c +++ b/mm/filemap.c @@ -688,7 +688,7 @@ int replace_page_cache_page(struct page *old, struct page *new, gfp_t gfp_mask) VM_BUG_ON_PAGE(!PageLocked(new), new); VM_BUG_ON_PAGE(new->mapping, new); - error = radix_tree_preload(gfp_mask & ~__GFP_HIGHMEM); + error = radix_tree_preload(gfp_mask & GFP_RECLAIM_MASK); if (!error) { struct address_space *mapping = old->mapping; void (*freepage)(struct page *); @@ -744,7 +744,7 @@ static int __add_to_page_cache_locked(struct page *page, return error; } - error = radix_tree_maybe_preload(gfp_mask & ~__GFP_HIGHMEM); + error = radix_tree_maybe_preload(gfp_mask & GFP_RECLAIM_MASK); if (error) { if (!huge) mem_cgroup_cancel_charge(page, memcg, false); @@ -1486,8 +1486,7 @@ struct page *pagecache_get_page(struct address_space *mapping, pgoff_t offset, if (fgp_flags & FGP_ACCESSED) __SetPageReferenced(page); - err = add_to_page_cache_lru(page, mapping, offset, - gfp_mask & GFP_RECLAIM_MASK); + err = add_to_page_cache_lru(page, mapping, offset, gfp_mask); if (unlikely(err)) { put_page(page); page = NULL; @@ -2275,7 +2274,7 @@ static int page_cache_read(struct file *file, pgoff_t offset, gfp_t gfp_mask) if (!page) return -ENOMEM; - ret = add_to_page_cache_lru(page, mapping, offset, gfp_mask & GFP_KERNEL); + ret = add_to_page_cache_lru(page, mapping, offset, gfp_mask); if (ret == 0) ret = mapping->a_ops->readpage(file, page); else if (ret == -EEXIST) -- GitLab From 30593709f80ddf23a3e8b41f3a7edfc68c4786be Mon Sep 17 00:00:00 2001 From: Andrew Lunn Date: Sat, 7 Apr 2018 20:37:40 +0200 Subject: [PATCH 0790/1635] net: dsa: Discard frames from unused ports commit fc5f33768cca7144f8d793205b229d46740d183b upstream. The Marvell switches under some conditions will pass a frame to the host with the port being the CPU port. Such frames are invalid, and should be dropped. Not dropping them can result in a crash when incrementing the receive statistics for an invalid port. This has been reworked for 4.14, which does not have the central dsa_master_find_slave() function, so each tag driver needs to check. Reported-by: Chris Healy Fixes: 91da11f870f0 ("net: Distributed Switch Architecture protocol support") Signed-off-by: Andrew Lunn Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/dsa/tag_brcm.c | 3 +++ net/dsa/tag_dsa.c | 3 +++ net/dsa/tag_edsa.c | 3 +++ net/dsa/tag_ksz.c | 3 +++ net/dsa/tag_lan9303.c | 3 +++ net/dsa/tag_mtk.c | 3 +++ net/dsa/tag_qca.c | 3 +++ net/dsa/tag_trailer.c | 3 +++ 8 files changed, 24 insertions(+) diff --git a/net/dsa/tag_brcm.c b/net/dsa/tag_brcm.c index dbb016434ace..de92fc1fc3be 100644 --- a/net/dsa/tag_brcm.c +++ b/net/dsa/tag_brcm.c @@ -121,6 +121,9 @@ static struct sk_buff *brcm_tag_rcv(struct sk_buff *skb, struct net_device *dev, if (source_port >= ds->num_ports || !ds->ports[source_port].netdev) return NULL; + if (unlikely(ds->cpu_port_mask & BIT(source_port))) + return NULL; + /* Remove Broadcom tag and update checksum */ skb_pull_rcsum(skb, BRCM_TAG_LEN); diff --git a/net/dsa/tag_dsa.c b/net/dsa/tag_dsa.c index fbf9ca954773..b3008a9bacf3 100644 --- a/net/dsa/tag_dsa.c +++ b/net/dsa/tag_dsa.c @@ -107,6 +107,9 @@ static struct sk_buff *dsa_rcv(struct sk_buff *skb, struct net_device *dev, if (source_port >= ds->num_ports || !ds->ports[source_port].netdev) return NULL; + if (unlikely(ds->cpu_port_mask & BIT(source_port))) + return NULL; + /* * Convert the DSA header to an 802.1q header if the 'tagged' * bit in the DSA header is set. If the 'tagged' bit is clear, diff --git a/net/dsa/tag_edsa.c b/net/dsa/tag_edsa.c index 76367ba1b2e2..c86b6d90576d 100644 --- a/net/dsa/tag_edsa.c +++ b/net/dsa/tag_edsa.c @@ -120,6 +120,9 @@ static struct sk_buff *edsa_rcv(struct sk_buff *skb, struct net_device *dev, if (source_port >= ds->num_ports || !ds->ports[source_port].netdev) return NULL; + if (unlikely(ds->cpu_port_mask & BIT(source_port))) + return NULL; + /* * If the 'tagged' bit is set, convert the DSA tag to a 802.1q * tag and delete the ethertype part. If the 'tagged' bit is diff --git a/net/dsa/tag_ksz.c b/net/dsa/tag_ksz.c index 010ca0a336c4..6c894692b9cd 100644 --- a/net/dsa/tag_ksz.c +++ b/net/dsa/tag_ksz.c @@ -92,6 +92,9 @@ static struct sk_buff *ksz_rcv(struct sk_buff *skb, struct net_device *dev, if (source_port >= ds->num_ports || !ds->ports[source_port].netdev) return NULL; + if (unlikely(ds->cpu_port_mask & BIT(source_port))) + return NULL; + pskb_trim_rcsum(skb, skb->len - KSZ_EGRESS_TAG_LEN); skb->dev = ds->ports[source_port].netdev; diff --git a/net/dsa/tag_lan9303.c b/net/dsa/tag_lan9303.c index 0b9826105e42..2d1603009e16 100644 --- a/net/dsa/tag_lan9303.c +++ b/net/dsa/tag_lan9303.c @@ -108,6 +108,9 @@ static struct sk_buff *lan9303_rcv(struct sk_buff *skb, struct net_device *dev, return NULL; } + if (unlikely(ds->cpu_port_mask & BIT(source_port))) + return NULL; + if (!ds->ports[source_port].netdev) { dev_warn_ratelimited(&dev->dev, "Dropping packet due to invalid netdev or device\n"); return NULL; diff --git a/net/dsa/tag_mtk.c b/net/dsa/tag_mtk.c index ec8ee5f43255..5c471854412d 100644 --- a/net/dsa/tag_mtk.c +++ b/net/dsa/tag_mtk.c @@ -81,6 +81,9 @@ static struct sk_buff *mtk_tag_rcv(struct sk_buff *skb, struct net_device *dev, if (!ds->ports[port].netdev) return NULL; + if (unlikely(ds->cpu_port_mask & BIT(port))) + return NULL; + skb->dev = ds->ports[port].netdev; return skb; diff --git a/net/dsa/tag_qca.c b/net/dsa/tag_qca.c index 1d4c70711c0f..b8c05f1cf47d 100644 --- a/net/dsa/tag_qca.c +++ b/net/dsa/tag_qca.c @@ -104,6 +104,9 @@ static struct sk_buff *qca_tag_rcv(struct sk_buff *skb, struct net_device *dev, if (!ds->ports[port].netdev) return NULL; + if (unlikely(ds->cpu_port_mask & BIT(port))) + return NULL; + /* Update skb & forward the frame accordingly */ skb->dev = ds->ports[port].netdev; diff --git a/net/dsa/tag_trailer.c b/net/dsa/tag_trailer.c index d2fd4923aa3e..fcc9aa72877d 100644 --- a/net/dsa/tag_trailer.c +++ b/net/dsa/tag_trailer.c @@ -76,6 +76,9 @@ static struct sk_buff *trailer_rcv(struct sk_buff *skb, struct net_device *dev, if (source_port >= ds->num_ports || !ds->ports[source_port].netdev) return NULL; + if (unlikely(ds->cpu_port_mask & BIT(source_port))) + return NULL; + pskb_trim_rcsum(skb, skb->len - 4); skb->dev = ds->ports[source_port].netdev; -- GitLab From 0c61952c3d199c8179cb8d2d400ef33c5511c3a3 Mon Sep 17 00:00:00 2001 From: Luca Coelho Date: Wed, 21 Feb 2018 22:18:59 +0200 Subject: [PATCH 0791/1635] iwlwifi: add shared clock PHY config flag for some devices commit 86a2b2043af79deff5cf000c5a08847faa4f2ee0 upstream. Some devices use a shared clock which is very sensitive to variations and cause trouble in some situations. We need to set a bit in the phy configuration to indicate that to the FW. To make this generic, add a extra_phy_config_flags element to the device configuration and OR it into the phy_cfg before sending it to the firmware. And also create a set of configurations for devices that use shared clocks and need this extra bit to be set. Fixes: c62446d2b028 ("iwlwifi: add new 9460 series PCI IDs") Signed-off-by: Luca Coelho Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/intel/iwlwifi/cfg/9000.c | 62 +++++++++++++++++++ drivers/net/wireless/intel/iwlwifi/fw/file.h | 1 + .../net/wireless/intel/iwlwifi/iwl-config.h | 5 ++ drivers/net/wireless/intel/iwlwifi/mvm/fw.c | 4 ++ drivers/net/wireless/intel/iwlwifi/pcie/drv.c | 38 ++++++------ 5 files changed, 91 insertions(+), 19 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/9000.c b/drivers/net/wireless/intel/iwlwifi/cfg/9000.c index c8e7b54a538a..73da5e63a609 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/9000.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/9000.c @@ -53,6 +53,7 @@ #include #include "iwl-config.h" #include "iwl-agn-hw.h" +#include "fw/file.h" /* Highest firmware API version supported */ #define IWL9000_UCODE_API_MAX 34 @@ -264,6 +265,67 @@ const struct iwl_cfg iwl9560_2ac_cfg_soc = { .integrated = true, .soc_latency = 5000, }; + +const struct iwl_cfg iwl9460_2ac_cfg_shared_clk = { + .name = "Intel(R) Dual Band Wireless AC 9460", + .fw_name_pre = IWL9000A_FW_PRE, + .fw_name_pre_b_or_c_step = IWL9000B_FW_PRE, + .fw_name_pre_rf_next_step = IWL9000RFB_FW_PRE, + IWL_DEVICE_9000, + .ht_params = &iwl9000_ht_params, + .nvm_ver = IWL9000_NVM_VERSION, + .nvm_calib_ver = IWL9000_TX_POWER_VERSION, + .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K, + .integrated = true, + .soc_latency = 5000, + .extra_phy_cfg_flags = FW_PHY_CFG_SHARED_CLK +}; + +const struct iwl_cfg iwl9461_2ac_cfg_shared_clk = { + .name = "Intel(R) Dual Band Wireless AC 9461", + .fw_name_pre = IWL9000A_FW_PRE, + .fw_name_pre_b_or_c_step = IWL9000B_FW_PRE, + .fw_name_pre_rf_next_step = IWL9000RFB_FW_PRE, + IWL_DEVICE_9000, + .ht_params = &iwl9000_ht_params, + .nvm_ver = IWL9000_NVM_VERSION, + .nvm_calib_ver = IWL9000_TX_POWER_VERSION, + .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K, + .integrated = true, + .soc_latency = 5000, + .extra_phy_cfg_flags = FW_PHY_CFG_SHARED_CLK +}; + +const struct iwl_cfg iwl9462_2ac_cfg_shared_clk = { + .name = "Intel(R) Dual Band Wireless AC 9462", + .fw_name_pre = IWL9000A_FW_PRE, + .fw_name_pre_b_or_c_step = IWL9000B_FW_PRE, + .fw_name_pre_rf_next_step = IWL9000RFB_FW_PRE, + IWL_DEVICE_9000, + .ht_params = &iwl9000_ht_params, + .nvm_ver = IWL9000_NVM_VERSION, + .nvm_calib_ver = IWL9000_TX_POWER_VERSION, + .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K, + .integrated = true, + .soc_latency = 5000, + .extra_phy_cfg_flags = FW_PHY_CFG_SHARED_CLK +}; + +const struct iwl_cfg iwl9560_2ac_cfg_shared_clk = { + .name = "Intel(R) Dual Band Wireless AC 9560", + .fw_name_pre = IWL9000A_FW_PRE, + .fw_name_pre_b_or_c_step = IWL9000B_FW_PRE, + .fw_name_pre_rf_next_step = IWL9000RFB_FW_PRE, + IWL_DEVICE_9000, + .ht_params = &iwl9000_ht_params, + .nvm_ver = IWL9000_NVM_VERSION, + .nvm_calib_ver = IWL9000_TX_POWER_VERSION, + .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K, + .integrated = true, + .soc_latency = 5000, + .extra_phy_cfg_flags = FW_PHY_CFG_SHARED_CLK +}; + MODULE_FIRMWARE(IWL9000A_MODULE_FIRMWARE(IWL9000_UCODE_API_MAX)); MODULE_FIRMWARE(IWL9000B_MODULE_FIRMWARE(IWL9000_UCODE_API_MAX)); MODULE_FIRMWARE(IWL9000RFB_MODULE_FIRMWARE(IWL9000_UCODE_API_MAX)); diff --git a/drivers/net/wireless/intel/iwlwifi/fw/file.h b/drivers/net/wireless/intel/iwlwifi/fw/file.h index e988e4c371c4..1b3ad8ef0c79 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/file.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/file.h @@ -434,6 +434,7 @@ enum iwl_fw_phy_cfg { FW_PHY_CFG_TX_CHAIN = 0xf << FW_PHY_CFG_TX_CHAIN_POS, FW_PHY_CFG_RX_CHAIN_POS = 20, FW_PHY_CFG_RX_CHAIN = 0xf << FW_PHY_CFG_RX_CHAIN_POS, + FW_PHY_CFG_SHARED_CLK = BIT(31), }; #define IWL_UCODE_MAX_CS 1 diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-config.h b/drivers/net/wireless/intel/iwlwifi/iwl-config.h index e226179c32fa..85fe1a928adc 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-config.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-config.h @@ -394,6 +394,7 @@ struct iwl_cfg { u8 max_vht_ampdu_exponent; u8 ucode_api_max; u8 ucode_api_min; + u32 extra_phy_cfg_flags; }; /* @@ -476,6 +477,10 @@ extern const struct iwl_cfg iwl9460_2ac_cfg_soc; extern const struct iwl_cfg iwl9461_2ac_cfg_soc; extern const struct iwl_cfg iwl9462_2ac_cfg_soc; extern const struct iwl_cfg iwl9560_2ac_cfg_soc; +extern const struct iwl_cfg iwl9460_2ac_cfg_shared_clk; +extern const struct iwl_cfg iwl9461_2ac_cfg_shared_clk; +extern const struct iwl_cfg iwl9462_2ac_cfg_shared_clk; +extern const struct iwl_cfg iwl9560_2ac_cfg_shared_clk; extern const struct iwl_cfg iwla000_2ac_cfg_hr; extern const struct iwl_cfg iwla000_2ac_cfg_hr_cdb; extern const struct iwl_cfg iwla000_2ac_cfg_jf; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c index 83485493a79a..b71a9d11a50f 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c @@ -435,6 +435,10 @@ static int iwl_send_phy_cfg_cmd(struct iwl_mvm *mvm) /* Set parameters */ phy_cfg_cmd.phy_cfg = cpu_to_le32(iwl_mvm_get_phy_config(mvm)); + + /* set flags extra PHY configuration flags from the device's cfg */ + phy_cfg_cmd.phy_cfg |= cpu_to_le32(mvm->cfg->extra_phy_cfg_flags); + phy_cfg_cmd.calib_control.event_trigger = mvm->fw->default_calib[ucode_type].event_trigger; phy_cfg_cmd.calib_control.flow_trigger = diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c index 0f7bd37bf172..95024477bfe7 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c @@ -577,25 +577,25 @@ static const struct pci_device_id iwl_hw_card_ids[] = { {IWL_PCI_DEVICE(0x30DC, 0x0264, iwl9461_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x30DC, 0x02A0, iwl9462_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x30DC, 0x02A4, iwl9462_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0x31DC, 0x0030, iwl9560_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0x31DC, 0x0034, iwl9560_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0x31DC, 0x0038, iwl9560_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0x31DC, 0x003C, iwl9560_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0x31DC, 0x0060, iwl9460_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0x31DC, 0x0064, iwl9461_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0x31DC, 0x00A0, iwl9462_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0x31DC, 0x00A4, iwl9462_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0x31DC, 0x0230, iwl9560_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0x31DC, 0x0234, iwl9560_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0x31DC, 0x0238, iwl9560_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0x31DC, 0x023C, iwl9560_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0x31DC, 0x0260, iwl9461_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0x31DC, 0x0264, iwl9461_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0x31DC, 0x02A0, iwl9462_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0x31DC, 0x02A4, iwl9462_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0x31DC, 0x4030, iwl9560_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0x31DC, 0x4034, iwl9560_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0x31DC, 0x40A4, iwl9462_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x31DC, 0x0030, iwl9560_2ac_cfg_shared_clk)}, + {IWL_PCI_DEVICE(0x31DC, 0x0034, iwl9560_2ac_cfg_shared_clk)}, + {IWL_PCI_DEVICE(0x31DC, 0x0038, iwl9560_2ac_cfg_shared_clk)}, + {IWL_PCI_DEVICE(0x31DC, 0x003C, iwl9560_2ac_cfg_shared_clk)}, + {IWL_PCI_DEVICE(0x31DC, 0x0060, iwl9460_2ac_cfg_shared_clk)}, + {IWL_PCI_DEVICE(0x31DC, 0x0064, iwl9461_2ac_cfg_shared_clk)}, + {IWL_PCI_DEVICE(0x31DC, 0x00A0, iwl9462_2ac_cfg_shared_clk)}, + {IWL_PCI_DEVICE(0x31DC, 0x00A4, iwl9462_2ac_cfg_shared_clk)}, + {IWL_PCI_DEVICE(0x31DC, 0x0230, iwl9560_2ac_cfg_shared_clk)}, + {IWL_PCI_DEVICE(0x31DC, 0x0234, iwl9560_2ac_cfg_shared_clk)}, + {IWL_PCI_DEVICE(0x31DC, 0x0238, iwl9560_2ac_cfg_shared_clk)}, + {IWL_PCI_DEVICE(0x31DC, 0x023C, iwl9560_2ac_cfg_shared_clk)}, + {IWL_PCI_DEVICE(0x31DC, 0x0260, iwl9461_2ac_cfg_shared_clk)}, + {IWL_PCI_DEVICE(0x31DC, 0x0264, iwl9461_2ac_cfg_shared_clk)}, + {IWL_PCI_DEVICE(0x31DC, 0x02A0, iwl9462_2ac_cfg_shared_clk)}, + {IWL_PCI_DEVICE(0x31DC, 0x02A4, iwl9462_2ac_cfg_shared_clk)}, + {IWL_PCI_DEVICE(0x31DC, 0x4030, iwl9560_2ac_cfg_shared_clk)}, + {IWL_PCI_DEVICE(0x31DC, 0x4034, iwl9560_2ac_cfg_shared_clk)}, + {IWL_PCI_DEVICE(0x31DC, 0x40A4, iwl9462_2ac_cfg_shared_clk)}, {IWL_PCI_DEVICE(0x34F0, 0x0030, iwl9560_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x34F0, 0x0034, iwl9560_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x34F0, 0x02A4, iwl9462_2ac_cfg_soc)}, -- GitLab From 8caa4c5fde76315b964b77c4a7dade6833be4cb1 Mon Sep 17 00:00:00 2001 From: Luca Coelho Date: Wed, 28 Mar 2018 11:15:09 +0300 Subject: [PATCH 0792/1635] iwlwifi: add a bunch of new 9000 PCI IDs commit 9e5053ad9d590e095829a8bb07adbbdbd893f0f9 upstream. A lot of new PCI IDs were added for the 9000 series. Add them to the list of supported PCI IDs. Cc: stable@vger.kernel.org # 4.13+ Signed-off-by: Luca Coelho Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/intel/iwlwifi/pcie/drv.c | 157 +++++++++++++++++- 1 file changed, 155 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c index 95024477bfe7..9a8605abb00a 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c @@ -8,6 +8,7 @@ * Copyright(c) 2007 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2016-2017 Intel Deutschland GmbH + * Copyright(c) 2018 Intel Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -36,6 +37,7 @@ * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * All rights reserved. * Copyright(c) 2017 Intel Deutschland GmbH + * Copyright(c) 2018 Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -515,9 +517,9 @@ static const struct pci_device_id iwl_hw_card_ids[] = { {IWL_PCI_DEVICE(0x24FD, 0x9074, iwl8265_2ac_cfg)}, /* 9000 Series */ - {IWL_PCI_DEVICE(0x2526, 0x0000, iwl9260_2ac_cfg)}, {IWL_PCI_DEVICE(0x2526, 0x0010, iwl9260_2ac_cfg)}, {IWL_PCI_DEVICE(0x2526, 0x0014, iwl9260_2ac_cfg)}, + {IWL_PCI_DEVICE(0x2526, 0x0018, iwl9260_2ac_cfg)}, {IWL_PCI_DEVICE(0x2526, 0x0030, iwl9560_2ac_cfg)}, {IWL_PCI_DEVICE(0x2526, 0x0034, iwl9560_2ac_cfg)}, {IWL_PCI_DEVICE(0x2526, 0x0038, iwl9560_2ac_cfg)}, @@ -542,11 +544,15 @@ static const struct pci_device_id iwl_hw_card_ids[] = { {IWL_PCI_DEVICE(0x2526, 0x1410, iwl9270_2ac_cfg)}, {IWL_PCI_DEVICE(0x2526, 0x1420, iwl9460_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x2526, 0x1610, iwl9270_2ac_cfg)}, + {IWL_PCI_DEVICE(0x2526, 0x2030, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x2526, 0x2034, iwl9560_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x2526, 0x4010, iwl9260_2ac_cfg)}, {IWL_PCI_DEVICE(0x2526, 0x4030, iwl9560_2ac_cfg)}, + {IWL_PCI_DEVICE(0x2526, 0x4034, iwl9560_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x2526, 0x40A4, iwl9460_2ac_cfg)}, - {IWL_PCI_DEVICE(0x2526, 0xA014, iwl9260_2ac_cfg)}, + {IWL_PCI_DEVICE(0x2526, 0x4234, iwl9560_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x2526, 0x42A4, iwl9462_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x2526, 0xA014, iwl9260_2ac_cfg)}, {IWL_PCI_DEVICE(0x271B, 0x0010, iwl9160_2ac_cfg)}, {IWL_PCI_DEVICE(0x271B, 0x0014, iwl9160_2ac_cfg)}, {IWL_PCI_DEVICE(0x271B, 0x0210, iwl9160_2ac_cfg)}, @@ -567,16 +573,42 @@ static const struct pci_device_id iwl_hw_card_ids[] = { {IWL_PCI_DEVICE(0x2720, 0x0264, iwl9461_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x2720, 0x02A0, iwl9462_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x2720, 0x02A4, iwl9462_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x2720, 0x1010, iwl9260_2ac_cfg)}, + {IWL_PCI_DEVICE(0x2720, 0x1030, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x2720, 0x1210, iwl9260_2ac_cfg)}, + {IWL_PCI_DEVICE(0x2720, 0x2030, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x2720, 0x2034, iwl9560_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x2720, 0x4030, iwl9560_2ac_cfg)}, + {IWL_PCI_DEVICE(0x2720, 0x4034, iwl9560_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x2720, 0x40A4, iwl9462_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x2720, 0x4234, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x2720, 0x42A4, iwl9462_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x30DC, 0x0030, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x30DC, 0x0034, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x30DC, 0x0038, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x30DC, 0x003C, iwl9560_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x30DC, 0x0060, iwl9460_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x30DC, 0x0064, iwl9461_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x30DC, 0x00A0, iwl9462_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x30DC, 0x00A4, iwl9462_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x30DC, 0x0230, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x30DC, 0x0234, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x30DC, 0x0238, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x30DC, 0x023C, iwl9560_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x30DC, 0x0260, iwl9461_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x30DC, 0x0264, iwl9461_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x30DC, 0x02A0, iwl9462_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x30DC, 0x02A4, iwl9462_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x30DC, 0x1010, iwl9260_2ac_cfg)}, + {IWL_PCI_DEVICE(0x30DC, 0x1030, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x30DC, 0x1210, iwl9260_2ac_cfg)}, + {IWL_PCI_DEVICE(0x30DC, 0x2030, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x30DC, 0x2034, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x30DC, 0x4030, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x30DC, 0x4034, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x30DC, 0x40A4, iwl9462_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x30DC, 0x4234, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x30DC, 0x42A4, iwl9462_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x31DC, 0x0030, iwl9560_2ac_cfg_shared_clk)}, {IWL_PCI_DEVICE(0x31DC, 0x0034, iwl9560_2ac_cfg_shared_clk)}, {IWL_PCI_DEVICE(0x31DC, 0x0038, iwl9560_2ac_cfg_shared_clk)}, @@ -593,12 +625,94 @@ static const struct pci_device_id iwl_hw_card_ids[] = { {IWL_PCI_DEVICE(0x31DC, 0x0264, iwl9461_2ac_cfg_shared_clk)}, {IWL_PCI_DEVICE(0x31DC, 0x02A0, iwl9462_2ac_cfg_shared_clk)}, {IWL_PCI_DEVICE(0x31DC, 0x02A4, iwl9462_2ac_cfg_shared_clk)}, + {IWL_PCI_DEVICE(0x31DC, 0x1010, iwl9260_2ac_cfg)}, + {IWL_PCI_DEVICE(0x31DC, 0x1030, iwl9560_2ac_cfg_shared_clk)}, + {IWL_PCI_DEVICE(0x31DC, 0x1210, iwl9260_2ac_cfg)}, + {IWL_PCI_DEVICE(0x31DC, 0x2030, iwl9560_2ac_cfg_shared_clk)}, + {IWL_PCI_DEVICE(0x31DC, 0x2034, iwl9560_2ac_cfg_shared_clk)}, {IWL_PCI_DEVICE(0x31DC, 0x4030, iwl9560_2ac_cfg_shared_clk)}, {IWL_PCI_DEVICE(0x31DC, 0x4034, iwl9560_2ac_cfg_shared_clk)}, {IWL_PCI_DEVICE(0x31DC, 0x40A4, iwl9462_2ac_cfg_shared_clk)}, + {IWL_PCI_DEVICE(0x31DC, 0x4234, iwl9560_2ac_cfg_shared_clk)}, + {IWL_PCI_DEVICE(0x31DC, 0x42A4, iwl9462_2ac_cfg_shared_clk)}, {IWL_PCI_DEVICE(0x34F0, 0x0030, iwl9560_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x34F0, 0x0034, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x34F0, 0x0038, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x34F0, 0x003C, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x34F0, 0x0060, iwl9461_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x34F0, 0x0064, iwl9461_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x34F0, 0x00A0, iwl9462_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x34F0, 0x00A4, iwl9462_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x34F0, 0x0230, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x34F0, 0x0234, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x34F0, 0x0238, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x34F0, 0x023C, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x34F0, 0x0260, iwl9461_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x34F0, 0x0264, iwl9461_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x34F0, 0x02A0, iwl9462_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x34F0, 0x02A4, iwl9462_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x34F0, 0x1010, iwl9260_2ac_cfg)}, + {IWL_PCI_DEVICE(0x34F0, 0x1030, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x34F0, 0x1210, iwl9260_2ac_cfg)}, + {IWL_PCI_DEVICE(0x34F0, 0x2030, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x34F0, 0x2034, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x34F0, 0x4030, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x34F0, 0x4034, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x34F0, 0x40A4, iwl9462_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x34F0, 0x4234, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x34F0, 0x42A4, iwl9462_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x3DF0, 0x0030, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x3DF0, 0x0034, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x3DF0, 0x0038, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x3DF0, 0x003C, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x3DF0, 0x0060, iwl9461_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x3DF0, 0x0064, iwl9461_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x3DF0, 0x00A0, iwl9462_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x3DF0, 0x00A4, iwl9462_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x3DF0, 0x0230, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x3DF0, 0x0234, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x3DF0, 0x0238, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x3DF0, 0x023C, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x3DF0, 0x0260, iwl9461_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x3DF0, 0x0264, iwl9461_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x3DF0, 0x02A0, iwl9462_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x3DF0, 0x02A4, iwl9462_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x3DF0, 0x1010, iwl9260_2ac_cfg)}, + {IWL_PCI_DEVICE(0x3DF0, 0x1030, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x3DF0, 0x1210, iwl9260_2ac_cfg)}, + {IWL_PCI_DEVICE(0x3DF0, 0x2030, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x3DF0, 0x2034, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x3DF0, 0x4030, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x3DF0, 0x4034, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x3DF0, 0x40A4, iwl9462_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x3DF0, 0x4234, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x3DF0, 0x42A4, iwl9462_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x43F0, 0x0030, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x43F0, 0x0034, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x43F0, 0x0038, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x43F0, 0x003C, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x43F0, 0x0060, iwl9461_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x43F0, 0x0064, iwl9461_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x43F0, 0x00A0, iwl9462_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x43F0, 0x00A4, iwl9462_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x43F0, 0x0230, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x43F0, 0x0234, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x43F0, 0x0238, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x43F0, 0x023C, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x43F0, 0x0260, iwl9461_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x43F0, 0x0264, iwl9461_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x43F0, 0x02A0, iwl9462_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x43F0, 0x02A4, iwl9462_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x43F0, 0x1010, iwl9260_2ac_cfg)}, + {IWL_PCI_DEVICE(0x43F0, 0x1030, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x43F0, 0x1210, iwl9260_2ac_cfg)}, + {IWL_PCI_DEVICE(0x43F0, 0x2030, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x43F0, 0x2034, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x43F0, 0x4030, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x43F0, 0x4034, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x43F0, 0x40A4, iwl9462_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x43F0, 0x4234, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x43F0, 0x42A4, iwl9462_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x9DF0, 0x0000, iwl9460_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x9DF0, 0x0010, iwl9460_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x9DF0, 0x0030, iwl9560_2ac_cfg_soc)}, @@ -624,11 +738,44 @@ static const struct pci_device_id iwl_hw_card_ids[] = { {IWL_PCI_DEVICE(0x9DF0, 0x0610, iwl9460_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x9DF0, 0x0710, iwl9460_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x9DF0, 0x0A10, iwl9460_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x9DF0, 0x1010, iwl9260_2ac_cfg)}, + {IWL_PCI_DEVICE(0x9DF0, 0x1030, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x9DF0, 0x1210, iwl9260_2ac_cfg)}, {IWL_PCI_DEVICE(0x9DF0, 0x2010, iwl9460_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x9DF0, 0x2030, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x9DF0, 0x2034, iwl9560_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x9DF0, 0x2A10, iwl9460_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x9DF0, 0x4030, iwl9560_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x9DF0, 0x4034, iwl9560_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x9DF0, 0x40A4, iwl9462_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x9DF0, 0x4234, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x9DF0, 0x42A4, iwl9462_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0xA0F0, 0x0030, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0xA0F0, 0x0034, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0xA0F0, 0x0038, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0xA0F0, 0x003C, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0xA0F0, 0x0060, iwl9461_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0xA0F0, 0x0064, iwl9461_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0xA0F0, 0x00A0, iwl9462_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0xA0F0, 0x00A4, iwl9462_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0xA0F0, 0x0230, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0xA0F0, 0x0234, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0xA0F0, 0x0238, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0xA0F0, 0x023C, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0xA0F0, 0x0260, iwl9461_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0xA0F0, 0x0264, iwl9461_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0xA0F0, 0x02A0, iwl9462_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0xA0F0, 0x02A4, iwl9462_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0xA0F0, 0x1010, iwl9260_2ac_cfg)}, + {IWL_PCI_DEVICE(0xA0F0, 0x1030, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0xA0F0, 0x1210, iwl9260_2ac_cfg)}, + {IWL_PCI_DEVICE(0xA0F0, 0x2030, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0xA0F0, 0x2034, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0xA0F0, 0x4030, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0xA0F0, 0x4034, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0xA0F0, 0x40A4, iwl9462_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0xA0F0, 0x4234, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0xA0F0, 0x42A4, iwl9462_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0xA370, 0x0030, iwl9560_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0xA370, 0x0034, iwl9560_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0xA370, 0x0038, iwl9560_2ac_cfg_soc)}, @@ -645,10 +792,16 @@ static const struct pci_device_id iwl_hw_card_ids[] = { {IWL_PCI_DEVICE(0xA370, 0x0264, iwl9461_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0xA370, 0x02A0, iwl9462_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0xA370, 0x02A4, iwl9462_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0xA370, 0x1010, iwl9260_2ac_cfg)}, {IWL_PCI_DEVICE(0xA370, 0x1030, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0xA370, 0x1210, iwl9260_2ac_cfg)}, + {IWL_PCI_DEVICE(0xA370, 0x2030, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0xA370, 0x2034, iwl9560_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0xA370, 0x4030, iwl9560_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0xA370, 0x4034, iwl9560_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0xA370, 0x40A4, iwl9462_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0xA370, 0x4234, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0xA370, 0x42A4, iwl9462_2ac_cfg_soc)}, /* a000 Series */ {IWL_PCI_DEVICE(0x2720, 0x0A10, iwla000_2ac_cfg_hr_cdb)}, -- GitLab From e7a08ffb2d897f4cfbd7b2931339c4643ad04f64 Mon Sep 17 00:00:00 2001 From: Sean Young Date: Sun, 15 Apr 2018 10:51:50 +0100 Subject: [PATCH 0793/1635] Revert "media: lirc_zilog: driver only sends LIRCCODE" [not upstream as the driver is deleted in 4.16 - gregkh] The lirc config documented here https://www.blushingpenguin.com/mark/blog/?p=24 uses raw_codes for sending IR. Each key only has one pulse, which in fact is an index into the haup-ir-blaster.bin file. Changing the driver to LIRCCODE (although more accurate) breaks this configuration. This code has been replaced completely in kernel v4.16 by a new driver, see commit acaa34bf06e9 ("media: rc: implement zilog transmitter"), and commit f95367a7b758 ("media: staging: remove lirc_zilog driver"). This reverts commit 89d8a2cc51d1f29ea24a0b44dde13253141190a0. Fixes: 615cd3fe6ccc ("[media] media: lirc_dev: make better use of file->private_data") Cc: stable@vger.kernel.org # v4.14-v4.15 Reported-by: Warren Sturm Tested-by: Warren Sturm Signed-off-by: Sean Young Signed-off-by: Greg Kroah-Hartman --- drivers/staging/media/lirc/lirc_zilog.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/staging/media/lirc/lirc_zilog.c b/drivers/staging/media/lirc/lirc_zilog.c index 71af13bd0ebd..26dd32d5b5b2 100644 --- a/drivers/staging/media/lirc/lirc_zilog.c +++ b/drivers/staging/media/lirc/lirc_zilog.c @@ -288,7 +288,7 @@ static void release_ir_tx(struct kref *ref) struct IR_tx *tx = container_of(ref, struct IR_tx, ref); struct IR *ir = tx->ir; - ir->l.features &= ~LIRC_CAN_SEND_LIRCCODE; + ir->l.features &= ~LIRC_CAN_SEND_PULSE; /* Don't put_ir_device(tx->ir) here, so our lock doesn't get freed */ ir->tx = NULL; kfree(tx); @@ -1267,14 +1267,14 @@ static long ioctl(struct file *filep, unsigned int cmd, unsigned long arg) if (!(features & LIRC_CAN_SEND_MASK)) return -ENOTTY; - result = put_user(LIRC_MODE_LIRCCODE, uptr); + result = put_user(LIRC_MODE_PULSE, uptr); break; case LIRC_SET_SEND_MODE: if (!(features & LIRC_CAN_SEND_MASK)) return -ENOTTY; result = get_user(mode, uptr); - if (!result && mode != LIRC_MODE_LIRCCODE) + if (!result && mode != LIRC_MODE_PULSE) return -EINVAL; break; default: @@ -1512,7 +1512,7 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id) kref_init(&tx->ref); ir->tx = tx; - ir->l.features |= LIRC_CAN_SEND_LIRCCODE; + ir->l.features |= LIRC_CAN_SEND_PULSE; mutex_init(&tx->client_lock); tx->c = client; tx->need_boot = 1; -- GitLab From 071ff203d962478368bbc84c3c8f9ba40e9fe2b6 Mon Sep 17 00:00:00 2001 From: Sean Young Date: Sun, 15 Apr 2018 10:51:51 +0100 Subject: [PATCH 0794/1635] media: staging: lirc_zilog: incorrect reference counting [not upstream as the driver is deleted in 4.16 - gregkh] Whenever poll is called, the reference count is increased but never decreased. This means that on rmmod, the lirc_thread is not stopped, and will trample over freed memory. Zilog/Hauppauge IR driver unloaded BUG: unable to handle kernel paging request at ffffffffc17ba640 Oops: 0010 [#1] SMP CPU: 1 PID: 667 Comm: zilog-rx-i2c-1 Tainted: P C OE 4.13.16-302.fc27.x86_64 #1 Hardware name: Gigabyte Technology Co., Ltd. GA-MA790FXT-UD5P/GA-MA790FXT-UD5P, BIOS F6 08/06/2009 task: ffff964eb452ca00 task.stack: ffffb254414dc000 RIP: 0010:0xffffffffc17ba640 RSP: 0018:ffffb254414dfe78 EFLAGS: 00010286 RAX: 0000000000000000 RBX: ffff964ec1b35890 RCX: 0000000000000000 RDX: 0000000000000000 RSI: 0000000000000246 RDI: 0000000000000246 RBP: ffffb254414dff00 R08: 000000000000036e R09: ffff964ecfc8dfd0 R10: ffffb254414dfe78 R11: 00000000000f4240 R12: ffff964ec2bf28a0 R13: ffff964ec1b358a8 R14: ffff964ec1b358d0 R15: ffff964ec1b35800 FS: 0000000000000000(0000) GS:ffff964ecfc80000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: ffffffffc17ba640 CR3: 000000023058c000 CR4: 00000000000006e0 Call Trace: kthread+0x125/0x140 ? kthread_park+0x60/0x60 ? do_syscall_64+0x67/0x140 ret_from_fork+0x25/0x30 Code: Bad RIP value. RIP: 0xffffffffc17ba640 RSP: ffffb254414dfe78 CR2: ffffffffc17ba640 Note that zilog-rx-i2c-1 should have exited by now, but hasn't due to the missing put in poll(). This code has been replaced completely in kernel v4.16 by a new driver, see commit acaa34bf06e9 ("media: rc: implement zilog transmitter"), and commit f95367a7b758 ("media: staging: remove lirc_zilog driver"). Cc: stable@vger.kernel.org # v4.15- (all up to and including v4.15) Reported-by: Warren Sturm Tested-by: Warren Sturm Signed-off-by: Sean Young Signed-off-by: Greg Kroah-Hartman --- drivers/staging/media/lirc/lirc_zilog.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/staging/media/lirc/lirc_zilog.c b/drivers/staging/media/lirc/lirc_zilog.c index 26dd32d5b5b2..e35e1b2160e3 100644 --- a/drivers/staging/media/lirc/lirc_zilog.c +++ b/drivers/staging/media/lirc/lirc_zilog.c @@ -1228,6 +1228,7 @@ static unsigned int poll(struct file *filep, poll_table *wait) dev_dbg(ir->l.dev, "%s result = %s\n", __func__, ret ? "POLLIN|POLLRDNORM" : "none"); + put_ir_rx(rx, false); return ret; } -- GitLab From 7c9b87a78a17017abe5def1ab53e3b261be6853f Mon Sep 17 00:00:00 2001 From: Greg Thelen Date: Fri, 20 Apr 2018 14:55:42 -0700 Subject: [PATCH 0795/1635] writeback: safer lock nesting commit 2e898e4c0a3897ccd434adac5abb8330194f527b upstream. lock_page_memcg()/unlock_page_memcg() use spin_lock_irqsave/restore() if the page's memcg is undergoing move accounting, which occurs when a process leaves its memcg for a new one that has memory.move_charge_at_immigrate set. unlocked_inode_to_wb_begin,end() use spin_lock_irq/spin_unlock_irq() if the given inode is switching writeback domains. Switches occur when enough writes are issued from a new domain. This existing pattern is thus suspicious: lock_page_memcg(page); unlocked_inode_to_wb_begin(inode, &locked); ... unlocked_inode_to_wb_end(inode, locked); unlock_page_memcg(page); If both inode switch and process memcg migration are both in-flight then unlocked_inode_to_wb_end() will unconditionally enable interrupts while still holding the lock_page_memcg() irq spinlock. This suggests the possibility of deadlock if an interrupt occurs before unlock_page_memcg(). truncate __cancel_dirty_page lock_page_memcg unlocked_inode_to_wb_begin unlocked_inode_to_wb_end end_page_writeback test_clear_page_writeback lock_page_memcg unlock_page_memcg Due to configuration limitations this deadlock is not currently possible because we don't mix cgroup writeback (a cgroupv2 feature) and memory.move_charge_at_immigrate (a cgroupv1 feature). If the kernel is hacked to always claim inode switching and memcg moving_account, then this script triggers lockup in less than a minute: cd /mnt/cgroup/memory mkdir a b echo 1 > a/memory.move_charge_at_immigrate echo 1 > b/memory.move_charge_at_immigrate ( echo $BASHPID > a/cgroup.procs while true; do dd if=/dev/zero of=/mnt/big bs=1M count=256 done ) & while true; do sync done & sleep 1h & SLEEP=$! while true; do echo $SLEEP > a/cgroup.procs echo $SLEEP > b/cgroup.procs done The deadlock does not seem possible, so it's debatable if there's any reason to modify the kernel. I suggest we should to prevent future surprises. And Wang Long said "this deadlock occurs three times in our environment", so there's more reason to apply this, even to stable. Stable 4.4 has minor conflicts applying this patch. For a clean 4.4 patch see "[PATCH for-4.4] writeback: safer lock nesting" https://lkml.org/lkml/2018/4/11/146 Wang Long said "this deadlock occurs three times in our environment" [gthelen@google.com: v4] Link: http://lkml.kernel.org/r/20180411084653.254724-1-gthelen@google.com [akpm@linux-foundation.org: comment tweaks, struct initialization simplification] Change-Id: Ibb773e8045852978f6207074491d262f1b3fb613 Link: http://lkml.kernel.org/r/20180410005908.167976-1-gthelen@google.com Fixes: 682aa8e1a6a1 ("writeback: implement unlocked_inode_to_wb transaction and use it for stat updates") Signed-off-by: Greg Thelen Reported-by: Wang Long Acked-by: Wang Long Acked-by: Michal Hocko Reviewed-by: Andrew Morton Cc: Johannes Weiner Cc: Tejun Heo Cc: Nicholas Piggin Cc: [v4.2+] Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds [natechancellor: Adjust context due to lack of b93b016313b3b] Signed-off-by: Nathan Chancellor Signed-off-by: Greg Kroah-Hartman --- fs/fs-writeback.c | 7 ++++--- include/linux/backing-dev-defs.h | 5 +++++ include/linux/backing-dev.h | 30 ++++++++++++++++-------------- mm/page-writeback.c | 18 +++++++++--------- 4 files changed, 34 insertions(+), 26 deletions(-) diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c index 245c430a2e41..8a7ef9378bf6 100644 --- a/fs/fs-writeback.c +++ b/fs/fs-writeback.c @@ -745,11 +745,12 @@ int inode_congested(struct inode *inode, int cong_bits) */ if (inode && inode_to_wb_is_valid(inode)) { struct bdi_writeback *wb; - bool locked, congested; + struct wb_lock_cookie lock_cookie = {}; + bool congested; - wb = unlocked_inode_to_wb_begin(inode, &locked); + wb = unlocked_inode_to_wb_begin(inode, &lock_cookie); congested = wb_congested(wb, cong_bits); - unlocked_inode_to_wb_end(inode, locked); + unlocked_inode_to_wb_end(inode, &lock_cookie); return congested; } diff --git a/include/linux/backing-dev-defs.h b/include/linux/backing-dev-defs.h index fff4cfa0c21d..eac387a3bfef 100644 --- a/include/linux/backing-dev-defs.h +++ b/include/linux/backing-dev-defs.h @@ -199,6 +199,11 @@ static inline void set_bdi_congested(struct backing_dev_info *bdi, int sync) set_wb_congested(bdi->wb.congested, sync); } +struct wb_lock_cookie { + bool locked; + unsigned long flags; +}; + #ifdef CONFIG_CGROUP_WRITEBACK /** diff --git a/include/linux/backing-dev.h b/include/linux/backing-dev.h index 16621579a3db..012adec97543 100644 --- a/include/linux/backing-dev.h +++ b/include/linux/backing-dev.h @@ -342,7 +342,7 @@ static inline struct bdi_writeback *inode_to_wb(struct inode *inode) /** * unlocked_inode_to_wb_begin - begin unlocked inode wb access transaction * @inode: target inode - * @lockedp: temp bool output param, to be passed to the end function + * @cookie: output param, to be passed to the end function * * The caller wants to access the wb associated with @inode but isn't * holding inode->i_lock, mapping->tree_lock or wb->list_lock. This @@ -350,12 +350,12 @@ static inline struct bdi_writeback *inode_to_wb(struct inode *inode) * association doesn't change until the transaction is finished with * unlocked_inode_to_wb_end(). * - * The caller must call unlocked_inode_to_wb_end() with *@lockdep - * afterwards and can't sleep during transaction. IRQ may or may not be - * disabled on return. + * The caller must call unlocked_inode_to_wb_end() with *@cookie afterwards and + * can't sleep during the transaction. IRQs may or may not be disabled on + * return. */ static inline struct bdi_writeback * -unlocked_inode_to_wb_begin(struct inode *inode, bool *lockedp) +unlocked_inode_to_wb_begin(struct inode *inode, struct wb_lock_cookie *cookie) { rcu_read_lock(); @@ -363,10 +363,10 @@ unlocked_inode_to_wb_begin(struct inode *inode, bool *lockedp) * Paired with store_release in inode_switch_wb_work_fn() and * ensures that we see the new wb if we see cleared I_WB_SWITCH. */ - *lockedp = smp_load_acquire(&inode->i_state) & I_WB_SWITCH; + cookie->locked = smp_load_acquire(&inode->i_state) & I_WB_SWITCH; - if (unlikely(*lockedp)) - spin_lock_irq(&inode->i_mapping->tree_lock); + if (unlikely(cookie->locked)) + spin_lock_irqsave(&inode->i_mapping->tree_lock, cookie->flags); /* * Protected by either !I_WB_SWITCH + rcu_read_lock() or tree_lock. @@ -378,12 +378,13 @@ unlocked_inode_to_wb_begin(struct inode *inode, bool *lockedp) /** * unlocked_inode_to_wb_end - end inode wb access transaction * @inode: target inode - * @locked: *@lockedp from unlocked_inode_to_wb_begin() + * @cookie: @cookie from unlocked_inode_to_wb_begin() */ -static inline void unlocked_inode_to_wb_end(struct inode *inode, bool locked) +static inline void unlocked_inode_to_wb_end(struct inode *inode, + struct wb_lock_cookie *cookie) { - if (unlikely(locked)) - spin_unlock_irq(&inode->i_mapping->tree_lock); + if (unlikely(cookie->locked)) + spin_unlock_irqrestore(&inode->i_mapping->tree_lock, cookie->flags); rcu_read_unlock(); } @@ -430,12 +431,13 @@ static inline struct bdi_writeback *inode_to_wb(struct inode *inode) } static inline struct bdi_writeback * -unlocked_inode_to_wb_begin(struct inode *inode, bool *lockedp) +unlocked_inode_to_wb_begin(struct inode *inode, struct wb_lock_cookie *cookie) { return inode_to_wb(inode); } -static inline void unlocked_inode_to_wb_end(struct inode *inode, bool locked) +static inline void unlocked_inode_to_wb_end(struct inode *inode, + struct wb_lock_cookie *cookie) { } diff --git a/mm/page-writeback.c b/mm/page-writeback.c index 0b9c5cbe8eba..3175ac850a53 100644 --- a/mm/page-writeback.c +++ b/mm/page-writeback.c @@ -2518,13 +2518,13 @@ void account_page_redirty(struct page *page) if (mapping && mapping_cap_account_dirty(mapping)) { struct inode *inode = mapping->host; struct bdi_writeback *wb; - bool locked; + struct wb_lock_cookie cookie = {}; - wb = unlocked_inode_to_wb_begin(inode, &locked); + wb = unlocked_inode_to_wb_begin(inode, &cookie); current->nr_dirtied--; dec_node_page_state(page, NR_DIRTIED); dec_wb_stat(wb, WB_DIRTIED); - unlocked_inode_to_wb_end(inode, locked); + unlocked_inode_to_wb_end(inode, &cookie); } } EXPORT_SYMBOL(account_page_redirty); @@ -2630,15 +2630,15 @@ void cancel_dirty_page(struct page *page) if (mapping_cap_account_dirty(mapping)) { struct inode *inode = mapping->host; struct bdi_writeback *wb; - bool locked; + struct wb_lock_cookie cookie = {}; lock_page_memcg(page); - wb = unlocked_inode_to_wb_begin(inode, &locked); + wb = unlocked_inode_to_wb_begin(inode, &cookie); if (TestClearPageDirty(page)) account_page_cleaned(page, mapping, wb); - unlocked_inode_to_wb_end(inode, locked); + unlocked_inode_to_wb_end(inode, &cookie); unlock_page_memcg(page); } else { ClearPageDirty(page); @@ -2670,7 +2670,7 @@ int clear_page_dirty_for_io(struct page *page) if (mapping && mapping_cap_account_dirty(mapping)) { struct inode *inode = mapping->host; struct bdi_writeback *wb; - bool locked; + struct wb_lock_cookie cookie = {}; /* * Yes, Virginia, this is indeed insane. @@ -2707,14 +2707,14 @@ int clear_page_dirty_for_io(struct page *page) * always locked coming in here, so we get the desired * exclusion. */ - wb = unlocked_inode_to_wb_begin(inode, &locked); + wb = unlocked_inode_to_wb_begin(inode, &cookie); if (TestClearPageDirty(page)) { dec_lruvec_page_state(page, NR_FILE_DIRTY); dec_zone_page_state(page, NR_ZONE_WRITE_PENDING); dec_wb_stat(wb, WB_RECLAIMABLE); ret = 1; } - unlocked_inode_to_wb_end(inode, locked); + unlocked_inode_to_wb_end(inode, &cookie); return ret; } return TestClearPageDirty(page); -- GitLab From d6949f48093c2d862d9bc39a7a89f2825c55edc4 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Tue, 24 Apr 2018 09:36:40 +0200 Subject: [PATCH 0796/1635] Linux 4.14.36 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 995666d5e57b..0a1f941899f4 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 VERSION = 4 PATCHLEVEL = 14 -SUBLEVEL = 35 +SUBLEVEL = 36 EXTRAVERSION = NAME = Petit Gorille -- GitLab From 96fef188b8a40e971bdc73585ce91e4e1274693a Mon Sep 17 00:00:00 2001 From: Meng Wang Date: Mon, 23 Apr 2018 16:06:37 +0800 Subject: [PATCH 0797/1635] ARM: dts: msm: add headset mic for SM8150 QRD device Add AMIC2, Mic Bias2 and Headset Mic routing for SM8150 QRD device. Change-Id: I0184e15f76503266918dba3aa35417d02c7bf5c0 Signed-off-by: Meng Wang --- arch/arm64/boot/dts/qcom/sm8150-qrd.dtsi | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sm8150-qrd.dtsi b/arch/arm64/boot/dts/qcom/sm8150-qrd.dtsi index 5306c05a561a..758feb54689c 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-qrd.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-qrd.dtsi @@ -120,6 +120,8 @@ "AIF4 VI", "MCLK", "RX_BIAS", "MCLK", "MADINPUT", "MCLK", + "AMIC2", "MIC BIAS2", + "MIC BIAS2", "Headset Mic", "DMIC0", "MIC BIAS1", "MIC BIAS1", "Digital Mic0", "DMIC2", "MIC BIAS3", -- GitLab From 308116e05c7213bd656ee13d78478bbd43ab2e9d Mon Sep 17 00:00:00 2001 From: Lina Iyer Date: Wed, 1 Nov 2017 22:52:33 +0000 Subject: [PATCH 0798/1635] drivers: qcom: lpm-stats: reset CPU stats from that CPU Currently when the LPM stats are reset, they are saved stats are reset without synchronizing with the idle state of the CPU. As a result, CPUs that are currently idle when the stats are reset may throw a wrench into the accounting by adding the sleep time from before the point of reset. Fix this by waking up each CPU and resetting the CPU's stats from that CPU when the stats are reset. This behavior is only supported when the stats are reset from the overall stats. echo reset > /sys/kernel/debug/lpm_stats/stats Change-Id: I2751bf0fb8d9ce9cb79c2429b5b59dd7b9681adb Signed-off-by: Lina Iyer --- drivers/soc/qcom/lpm-stats.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/drivers/soc/qcom/lpm-stats.c b/drivers/soc/qcom/lpm-stats.c index 09bb4269aea9..267588af0e27 100644 --- a/drivers/soc/qcom/lpm-stats.c +++ b/drivers/soc/qcom/lpm-stats.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -254,6 +255,15 @@ static ssize_t level_stats_file_write(struct file *file, return count; } +static void reset_cpu_stats(void *info) +{ + struct lpm_stats *stats = &(*this_cpu_ptr(&(cpu_stats))); + int i; + + for (i = 0; i < stats->num_levels; i++) + level_stats_reset(&stats->time_stats[i]); +} + static ssize_t lpm_stats_file_write(struct file *file, const char __user *buffer, size_t count, loff_t *off) { @@ -275,6 +285,12 @@ static ssize_t lpm_stats_file_write(struct file *file, return -EINVAL; level_stats_reset_all(stats); + /* + * Wake up each CPU and reset the stats from that CPU, + * for that CPU, so we could have better timestamp for + * accounting. + */ + on_each_cpu(reset_cpu_stats, NULL, 1); return count; } -- GitLab From baecc503d66635f96b45e09f61993bed4c503006 Mon Sep 17 00:00:00 2001 From: Tejaswi Tanikella Date: Mon, 23 Apr 2018 13:21:02 +0530 Subject: [PATCH 0799/1635] net: Add noinline to reduce dev_ethtool stack size Maximum stack size for arm32 devices is (configured by FRAME_WARN) 1024. dev_ethtool()'s stacksize (=1208) exceeds this limit. Adding noinline attribute to reduce stack size. Change-Id: I00dbd3cad029ca99694d7cee611d4ee32016f889 Signed-off-by: Tejaswi Tanikella --- net/core/ethtool.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/net/core/ethtool.c b/net/core/ethtool.c index d374a904f1b1..373f7ebd1629 100644 --- a/net/core/ethtool.c +++ b/net/core/ethtool.c @@ -2319,9 +2319,10 @@ static int ethtool_set_tunable(struct net_device *dev, void __user *useraddr) return ret; } -static int ethtool_get_per_queue_coalesce(struct net_device *dev, - void __user *useraddr, - struct ethtool_per_queue_op *per_queue_opt) +static noinline_for_stack +int ethtool_get_per_queue_coalesce(struct net_device *dev, + void __user *useraddr, + struct ethtool_per_queue_op *per_queue_opt) { u32 bit; int ret; @@ -2351,9 +2352,10 @@ static int ethtool_get_per_queue_coalesce(struct net_device *dev, return 0; } -static int ethtool_set_per_queue_coalesce(struct net_device *dev, - void __user *useraddr, - struct ethtool_per_queue_op *per_queue_opt) +static noinline_for_stack +int ethtool_set_per_queue_coalesce(struct net_device *dev, + void __user *useraddr, + struct ethtool_per_queue_op *per_queue_opt) { u32 bit; int i, ret = 0; -- GitLab From 5704525974fc1f3cb3f14d922d4987f35f2dc278 Mon Sep 17 00:00:00 2001 From: sssanjee Date: Wed, 4 Apr 2018 11:38:47 +0530 Subject: [PATCH 0800/1635] msm: fastcvpd: add fastcvp driver Add fastcvp driver, which exposes APIs to video driver to share HFI command queue address to CDSP and handle errors to exit gracefully in case video and cdsp subsystems restart. Change-Id: Ie9502371e0e112f11e8fd5cf7b69a9e52599ee98 Acked-by: Abhikrant Sharma Signed-off-by: Suman Voora --- drivers/char/Kconfig | 8 ++ drivers/char/Makefile | 1 + drivers/char/fastcvpd.c | 197 +++++++++++++++++++++++++++++++++++++++ include/linux/fastcvpd.h | 89 ++++++++++++++++++ 4 files changed, 295 insertions(+) create mode 100644 drivers/char/fastcvpd.c create mode 100644 include/linux/fastcvpd.h diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig index 647e74a3b9e3..d96a3842a400 100644 --- a/drivers/char/Kconfig +++ b/drivers/char/Kconfig @@ -589,6 +589,14 @@ config TILE_SROM source "drivers/char/xillybus/Kconfig" source "drivers/char/diag/Kconfig" +config MSM_FASTCVPD + bool "QTI FASTCVP driver" + depends on QCOM_GLINK + help + This driver exposes APIs to video driver to share + HFI command queue address to CDSP and handle errors + to exit gracefully in case video and cdsp subsystems crash. + config MSM_ADSPRPC tristate "QTI ADSP RPC driver" depends on QCOM_GLINK diff --git a/drivers/char/Makefile b/drivers/char/Makefile index 8127b328b88f..96ecee7cebc0 100644 --- a/drivers/char/Makefile +++ b/drivers/char/Makefile @@ -65,3 +65,4 @@ obj-$(CONFIG_MSM_ADSPRPC) += adsprpc.o ifdef CONFIG_COMPAT obj-$(CONFIG_MSM_ADSPRPC) += adsprpc_compat.o endif +obj-$(CONFIG_MSM_FASTCVPD) += fastcvpd.o \ No newline at end of file diff --git a/drivers/char/fastcvpd.c b/drivers/char/fastcvpd.c new file mode 100644 index 000000000000..ef043bc85273 --- /dev/null +++ b/drivers/char/fastcvpd.c @@ -0,0 +1,197 @@ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +#include +#include +#include +#include "linux/fastcvpd.h" + +#define FASTCVPD_VIDEO_SEND_HFI_CMD_QUEUE 0 +#define FASTCVPD_VIDEO_SUSPEND 1 +#define FASTCVPD_VIDEO_RESUME 2 +#define FASTCVPD_VIDEO_SHUTDOWN 3 + +struct fastcvpd_cmd_msg { + uint32_t cmd_msg_type; + int ret_val; + uint64_t msg_ptr; + uint32_t msg_ptr_len; +}; + +struct fastcvpd_apps { + struct rpmsg_device *chan; + struct mutex smd_mutex; + int rpmsg_register; +}; + +static struct fastcvpd_apps gfa_cv; + +static int fastcvpd_send_cmd(void *msg, uint32_t len) +{ + struct fastcvpd_apps *me = &gfa_cv; + int err; + + if (IS_ERR_OR_NULL(me->chan)) { + err = -EINVAL; + goto bail; + } + err = rpmsg_send(me->chan->ept, msg, len); + +bail: + return err; +} + +static int fastcvpd_rpmsg_probe(struct rpmsg_device *rpdev) +{ + int err = 0; + struct fastcvpd_apps *me = &gfa_cv; + + if (strcmp(rpdev->dev.parent->of_node->name, "cdsp")) { + pr_err("%s: Failed to probe rpmsg device.Node name:%s\n", + __func__, rpdev->dev.parent->of_node->name); + err = -EINVAL; + goto bail; + } + mutex_lock(&me->smd_mutex); + me->chan = rpdev; + mutex_unlock(&me->smd_mutex); + pr_debug("%s: Successfully probed\n", __func__); +bail: + return err; +} + +static void fastcvpd_rpmsg_remove(struct rpmsg_device *rpdev) +{ + struct fastcvpd_apps *me = &gfa_cv; + + mutex_lock(&me->smd_mutex); + me->chan = NULL; + mutex_unlock(&me->smd_mutex); +} + +static int fastcvpd_rpmsg_callback(struct rpmsg_device *rpdev, + void *data, int len, void *priv, u32 addr) +{ + return 0; +} + +int fastcvpd_video_send_cmd_hfi_queue(phys_addr_t *phys_addr, + uint32_t size_in_bytes) +{ + int err; + struct fastcvpd_cmd_msg cmd_msg; + + cmd_msg.cmd_msg_type = FASTCVPD_VIDEO_SEND_HFI_CMD_QUEUE; + cmd_msg.msg_ptr = (uint64_t)phys_addr; + cmd_msg.msg_ptr_len = size_in_bytes; + + err = fastcvpd_send_cmd + (&cmd_msg, sizeof(struct fastcvpd_cmd_msg)); + if (err != 0) + pr_err("%s: fastcvpd_send_cmd failed with err=%d\n", + __func__, err); + return err; +} +EXPORT_SYMBOL(fastcvpd_video_send_cmd_hfi_queue); + +int fastcvpd_video_suspend(uint32_t session_flag) +{ + int err = 0; + struct fastcvpd_cmd_msg cmd_msg; + + cmd_msg.cmd_msg_type = FASTCVPD_VIDEO_SUSPEND; + err = fastcvpd_send_cmd + (&cmd_msg, sizeof(struct fastcvpd_cmd_msg)); + if (err != 0) + pr_err("%s: fastcvpd_send_cmd failed with err=%d\n", + __func__, err); + return err; +} +EXPORT_SYMBOL(fastcvpd_video_suspend); + +int fastcvpd_video_resume(uint32_t session_flag) +{ + int err; + struct fastcvpd_cmd_msg cmd_msg; + + cmd_msg.cmd_msg_type = FASTCVPD_VIDEO_RESUME; + err = fastcvpd_send_cmd + (&cmd_msg, sizeof(struct fastcvpd_cmd_msg)); + if (err != 0) + pr_err("%s: fastcvpd_send_cmd failed with err=%d\n", + __func__, err); + return err; +} +EXPORT_SYMBOL(fastcvpd_video_resume); + +int fastcvpd_video_shutdown(uint32_t session_flag) +{ + int err; + struct fastcvpd_cmd_msg cmd_msg; + + cmd_msg.cmd_msg_type = FASTCVPD_VIDEO_SHUTDOWN; + err = fastcvpd_send_cmd + (&cmd_msg, sizeof(struct fastcvpd_cmd_msg)); + if (err != 0) + pr_err("%s: fastcvpd_send_cmd failed with err=%d\n", + __func__, err); + return err; +} +EXPORT_SYMBOL(fastcvpd_video_shutdown); + +static const struct rpmsg_device_id fastcvpd_rpmsg_match[] = { + { FASTCVPD_GLINK_GUID }, + { }, +}; + +static struct rpmsg_driver fastcvpd_rpmsg_client = { + .id_table = fastcvpd_rpmsg_match, + .probe = fastcvpd_rpmsg_probe, + .remove = fastcvpd_rpmsg_remove, + .callback = fastcvpd_rpmsg_callback, + .drv = { + .name = "qcom,msm_fastcvpd_rpmsg", + }, +}; + +static int __init fastcvpd_device_init(void) +{ + struct fastcvpd_apps *me = &gfa_cv; + int err; + + mutex_init(&me->smd_mutex); + err = register_rpmsg_driver(&fastcvpd_rpmsg_client); + if (err) { + pr_err("%s : register_rpmsg_driver failed with err %d\n", + __func__, err); + goto register_bail; + } + me->rpmsg_register = 1; + return 0; + +register_bail: + return err; +} + +static void __exit fastcvpd_device_exit(void) +{ + struct fastcvpd_apps *me = &gfa_cv; + + if (me->rpmsg_register == 1) + unregister_rpmsg_driver(&fastcvpd_rpmsg_client); +} + +late_initcall(fastcvpd_device_init); +module_exit(fastcvpd_device_exit); + +MODULE_LICENSE("GPL v2"); diff --git a/include/linux/fastcvpd.h b/include/linux/fastcvpd.h new file mode 100644 index 000000000000..6c7fc529ca20 --- /dev/null +++ b/include/linux/fastcvpd.h @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +#ifndef FASTCVPD_H +#define FASTCVPD_H + +#include + +#define FASTCVPD_GLINK_GUID "fastcvpd-glink-apps-dsp" +#define FASTCVPD_SMD_GUID "fastcvpd-smd-apps-dsp" +#define FASTCVPD_DEVICE_NAME "fastcvpd-smd" + +#ifdef CONFIG_MSM_FASTCVPD +/* + * API for Video driver to send physical address to FastCVP driver + * @param phys_addr + * Physical address of command message queue + * that needs to be mapped to CDSP. + * It should be allocated from CMA adsp_mem region. + * + * @param size_in_bytes + * Size in bytes of command message queue + */ +int fastcvpd_video_send_cmd_hfi_queue(phys_addr_t *phys_addr, + uint32_t size_in_bytes); + +/* + * API for Video driver to suspend CVP session during + * power collapse + * + * @param session_flag + * Flag to share details of session. + */ +int fastcvpd_video_suspend(uint32_t session_flag); + +/* + * API for Video driver to resume CVP session during + * power collapse + * + * @param session_flag + * Flag to share details of session. + */ +int fastcvpd_video_resume(uint32_t session_flag); + +/* + * API for Video driver to shutdown CVP session during + * video subsystem error. + * + * @param session_flag + * Flag to share details of session. + */ +int fastcvpd_video_shutdown(uint32_t session_flag); + +#else + +static inline int fastcvpd_video_send_cmd_hfi_queue( + phys_addr_t *phys_addr, + uint32_t size_in_bytes) +{ + return -ENODEV; +} + +static inline int fastcvpd_video_suspend(uint32_t session_flag) +{ + return -ENODEV; +} + +static inline int fastcvpd_video_suspend(uint32_t session_flag) +{ + return -ENODEV; +} + +static inline int fastcvpd_video_resume(uint32_t session_flag) +{ + return -ENODEV; +} + +#endif // CONFIG_FASTCVPD +#endif // FASTCVPD_H -- GitLab From d0a5ebbaf41f6a4e38cb8d27ad60aef20a86a92f Mon Sep 17 00:00:00 2001 From: Siddartha Mohanadoss Date: Mon, 23 Apr 2018 12:56:30 -0700 Subject: [PATCH 0801/1635] thermal: adc-tm5: Fix pointer dereference error Fix pointer dereference and uninitialized element errors during driver initialization and when client sets temperature thresholds. Change-Id: Ia1b1eb263f8468c096210a0ccbe2098b4a70f547 Signed-off-by: Siddartha Mohanadoss --- drivers/thermal/qcom/adc-tm5.c | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/drivers/thermal/qcom/adc-tm5.c b/drivers/thermal/qcom/adc-tm5.c index 6c22366eaf3e..3f44d8188beb 100644 --- a/drivers/thermal/qcom/adc-tm5.c +++ b/drivers/thermal/qcom/adc-tm5.c @@ -201,7 +201,7 @@ static int adc_tm5_configure(struct adc_tm_sensor *sensor, buf[5] = sensor->timer_select; /* Set calibration select, hw_settle delay */ - cal_sel |= (u8) (sensor->cal_sel << ADC_TM_CTL_CAL_SEL_MASK_SHIFT); + cal_sel = (u8) (sensor->cal_sel << ADC_TM_CTL_CAL_SEL_MASK_SHIFT); buf[6] &= (u8) ~ADC_TM_CTL_HW_SETTLE_DELAY_MASK; buf[6] |= (u8) sensor->hw_settle_time; buf[6] &= (u8) ~ADC_TM_CTL_CAL_SEL; @@ -299,7 +299,7 @@ static int adc_tm5_activate_trip_type(struct adc_tm_sensor *adc_tm, static int adc_tm5_set_trip_temp(struct adc_tm_sensor *sensor, int low_temp, int high_temp) { - struct adc_tm_chip *chip = sensor->chip; + struct adc_tm_chip *chip; struct adc_tm_config tm_config; u8 trip_low_thr[2], trip_high_thr[2]; uint16_t reg_low_thr_lsb, reg_high_thr_lsb; @@ -313,6 +313,7 @@ static int adc_tm5_set_trip_temp(struct adc_tm_sensor *sensor, pr_debug("%s:low_temp(mdegC):%d, high_temp(mdegC):%d\n", __func__, low_temp, high_temp); + chip = sensor->chip; tm_config.channel = sensor->adc_ch; tm_config.high_thr_temp = tm_config.low_thr_temp = 0; if (high_temp != INT_MAX) @@ -516,7 +517,7 @@ static int adc_tm5_register_interrupts(struct adc_tm_chip *chip) static int adc_tm5_init(struct adc_tm_chip *chip, uint32_t dt_chans) { - u8 buf[4], channels_available; + u8 buf[4], channels_available, meas_int_timer_2_3 = 0; int ret, i; ret = adc_tm5_read_reg(chip, ADC_TM_NUM_BTM, &channels_available, 1); @@ -531,18 +532,27 @@ static int adc_tm5_init(struct adc_tm_chip *chip, uint32_t dt_chans) return -EINVAL; } + ret = adc_tm5_read_reg(chip, + ADC_TM_ADC_DIG_PARAM, buf, 4); + if (ret < 0) { + pr_err("adc-tm block read failed with %d\n", ret); + return ret; + } + /* Select decimation */ buf[0] = chip->prop.decimation; /* Select number of samples in fast average mode */ - buf[1] |= chip->prop.fast_avg_samples | ADC_TM_FAST_AVG_EN; + buf[1] = chip->prop.fast_avg_samples | ADC_TM_FAST_AVG_EN; /* Select timer1 */ buf[2] = chip->prop.timer1; - /* Select timer2 and timer2 */ - buf[3] |= chip->prop.timer2 << ADC_TM_MEAS_INTERVAL_CTL2_SHIFT; - buf[3] |= chip->prop.timer3; + /* Select timer2 and timer3 */ + meas_int_timer_2_3 |= chip->prop.timer2 << + ADC_TM_MEAS_INTERVAL_CTL2_SHIFT; + meas_int_timer_2_3 |= chip->prop.timer3; + buf[3] = meas_int_timer_2_3; ret = adc_tm5_write_reg(chip, ADC_TM_ADC_DIG_PARAM, buf, 4); -- GitLab From f2478a7ad09cbffb660a9cec6fda9eeec3bdb157 Mon Sep 17 00:00:00 2001 From: Siddartha Mohanadoss Date: Thu, 19 Apr 2018 14:55:43 -0700 Subject: [PATCH 0802/1635] defconfig: msm: Enable ADC_TM driver for sm8150 ADC_TM PMIC peripheral is used by clients to configure and set thresholds for notification. Thermal clients can read temperature from on board system thermistors through thermal zones and set temperature thresholds. Change-Id: I39a0ac4e99b9e60941c68186336db384dbb8fff6 Signed-off-by: Siddartha Mohanadoss --- arch/arm64/configs/sm8150-perf_defconfig | 1 + arch/arm64/configs/sm8150_defconfig | 1 + 2 files changed, 2 insertions(+) diff --git a/arch/arm64/configs/sm8150-perf_defconfig b/arch/arm64/configs/sm8150-perf_defconfig index 64a922f9348f..b1a37b0a7991 100644 --- a/arch/arm64/configs/sm8150-perf_defconfig +++ b/arch/arm64/configs/sm8150-perf_defconfig @@ -337,6 +337,7 @@ CONFIG_QTI_QMI_COOLING_DEVICE=y CONFIG_REGULATOR_COOLING_DEVICE=y CONFIG_QTI_BCL_PMIC5=y CONFIG_QTI_BCL_SOC_DRIVER=y +CONFIG_QTI_ADC_TM=y CONFIG_MFD_SPMI_PMIC=y CONFIG_REGULATOR_FIXED_VOLTAGE=y CONFIG_REGULATOR_PROXY_CONSUMER=y diff --git a/arch/arm64/configs/sm8150_defconfig b/arch/arm64/configs/sm8150_defconfig index af8f88e260f1..3cb4ed96a3e1 100644 --- a/arch/arm64/configs/sm8150_defconfig +++ b/arch/arm64/configs/sm8150_defconfig @@ -348,6 +348,7 @@ CONFIG_QTI_QMI_COOLING_DEVICE=y CONFIG_REGULATOR_COOLING_DEVICE=y CONFIG_QTI_BCL_PMIC5=y CONFIG_QTI_BCL_SOC_DRIVER=y +CONFIG_QTI_ADC_TM=y CONFIG_MFD_SPMI_PMIC=y CONFIG_REGULATOR_FIXED_VOLTAGE=y CONFIG_REGULATOR_PROXY_CONSUMER=y -- GitLab From 3a63e37c1d9577385f96850ac1e5149f2a0320c8 Mon Sep 17 00:00:00 2001 From: Chris Lew Date: Wed, 4 Apr 2018 11:30:59 -0700 Subject: [PATCH 0803/1635] rpmsg: Introduce GLINK SPI driver Add support for the GLINK SPI driver to communicate to the codec processor. This driver uses the wdsp spi interface to send and receive messages on a SPI bus. Change-Id: I50c0f0023d26e547afa9baf64d0715002ced7347 Signed-off-by: Chris Lew --- drivers/rpmsg/Kconfig | 9 + drivers/rpmsg/Makefile | 1 + drivers/rpmsg/qcom_glink_spi.c | 2473 ++++++++++++++++++++++++++++++ include/linux/rpmsg/qcom_glink.h | 21 + 4 files changed, 2504 insertions(+) create mode 100644 drivers/rpmsg/qcom_glink_spi.c diff --git a/drivers/rpmsg/Kconfig b/drivers/rpmsg/Kconfig index cb27c4ef6a33..a3b621d37ff5 100644 --- a/drivers/rpmsg/Kconfig +++ b/drivers/rpmsg/Kconfig @@ -50,6 +50,15 @@ config RPMSG_QCOM_GLINK_SPSS region with the remote proc by writing the smem descriptor location and size into shared registers. +config RPMSG_QCOM_GLINK_SPI + tristate "Qualcomm SPI Glink driver" + help + Say y here to enable support for the GLINK SPI communication driver, + which provides support for using the GLINK communication protocol + over SPI. This transport performs marshaling of GLINK commands and + data to the appropriate SPI bus wire format and allows for GLINK + communication with remote subsystems that are external to the SoC. + config RPMSG_QCOM_SMD tristate "Qualcomm Shared Memory Driver (SMD)" depends on QCOM_SMEM diff --git a/drivers/rpmsg/Makefile b/drivers/rpmsg/Makefile index 58a46fd77a22..1680763bb8b5 100644 --- a/drivers/rpmsg/Makefile +++ b/drivers/rpmsg/Makefile @@ -5,5 +5,6 @@ obj-$(CONFIG_RPMSG_QCOM_GLINK_RPM) += qcom_glink_rpm.o obj-$(CONFIG_RPMSG_QCOM_GLINK_NATIVE) += qcom_glink_native.o obj-$(CONFIG_RPMSG_QCOM_GLINK_SMEM) += qcom_glink_smem.o obj-$(CONFIG_RPMSG_QCOM_GLINK_SPSS) += qcom_glink_spss.o +obj-$(CONFIG_RPMSG_QCOM_GLINK_SPI) += qcom_glink_spi.o obj-$(CONFIG_RPMSG_QCOM_SMD) += qcom_smd.o obj-$(CONFIG_RPMSG_VIRTIO) += virtio_rpmsg_bus.o diff --git a/drivers/rpmsg/qcom_glink_spi.c b/drivers/rpmsg/qcom_glink_spi.c new file mode 100644 index 000000000000..a3ef2642ff11 --- /dev/null +++ b/drivers/rpmsg/qcom_glink_spi.c @@ -0,0 +1,2473 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "rpmsg_internal.h" +#include "qcom_glink_native.h" + +#define GLINK_LOG_PAGE_CNT 2 +#define GLINK_INFO(ctxt, x, ...) \ +do { \ + if (ctxt->ilc) \ + ipc_log_string(ctxt->ilc, "[%s]: "x, __func__, ##__VA_ARGS__); \ +} while (0) + +#define CH_INFO(ch, x, ...) \ +do { \ + if (ch->glink && ch->glink->ilc) \ + ipc_log_string(ch->glink->ilc, "%s[%d:%d] %s: "x, ch->name, \ + ch->lcid, ch->rcid, __func__, ##__VA_ARGS__); \ +} while (0) + + +#define GLINK_ERR(ctxt, x, ...) \ +do { \ + pr_err_ratelimited("[%s]: "x, __func__, ##__VA_ARGS__); \ + if (ctxt->ilc) \ + ipc_log_string(ctxt->ilc, "[%s]: "x, __func__, ##__VA_ARGS__); \ +} while (0) + +#define SPI_ALIGNMENT 16 +#define FIFO_FULL_RESERVE 8 +#define TX_BLOCKED_CMD_RESERVE 16 +#define DEFAULT_FIFO_SIZE 1024 +#define SHORT_PKT_SIZE 16 +#define XPRT_ALIGNMENT 4 + +#define MAX_INACTIVE_CYCLES 50 +#define POLL_INTERVAL_US 500 + +#define ACTIVE_TX BIT(0) +#define ACTIVE_RX BIT(1) + +#define ID_MASK 0xFFFFFF + +#define GLINK_NAME_SIZE 32 +#define GLINK_VERSION_1 1 + +#define SPI_GLINK_CID_MIN 1 +#define SPI_GLINK_CID_MAX 65536 + +struct glink_msg { + __le16 cmd; + __le16 param1; + __le32 param2; + __le32 param3; + __le32 param4; + u8 data[]; +} __packed; + +/** + * struct glink_defer_cmd - deferred incoming control message + * @node: list node + * @msg: message header + * data: payload of the message + * + * Copy of a received control message, to be added to @rx_queue and processed + * by @rx_work of @glink_spi. + */ +struct glink_defer_cmd { + struct list_head node; + + struct glink_msg msg; + u8 data[]; +}; + +/** + * struct glink_core_rx_intent - RX intent + * RX intent + * + * @data: pointer to the data (may be NULL for zero-copy) + * @id: remote or local intent ID + * @size: size of the original intent (do not modify) + * @addr: addr to read/write the data from + * @reuse: To mark if the intent can be reused after first use + * @in_use: To mark if intent is already in use for the channel + * @offset: next write offset (initially 0) + */ +struct glink_core_rx_intent { + void *data; + u32 id; + size_t size; + u32 addr; + bool reuse; + bool in_use; + u32 offset; + + struct list_head node; +}; + +/** + * @fifo_base: Base Address of the RX FIFO. + * @length: End Address of the RX FIFO. + * @tail_addr: Address of the TX FIFO Read Index Register. + * @head_addr: Address of the TX FIFO Write Index Register. + * @local_addr: Address of the RX FIFO Read Index Register. + */ +struct glink_spi_pipe { + u32 fifo_base; + u32 length; + + u32 tail_addr; + u32 head_addr; + + u32 local_addr; +}; + +/** + * struct glink_cmpnt - Component to cache spi component and its operations + * @master_dev: Device structure corresponding to spi device. + * @master_ops: Operations supported by the spi device. + */ +struct glink_cmpnt { + struct device *master_dev; + struct wdsp_mgr_ops *master_ops; +}; + +/** + * struct glink_spi - driver context, relates to one remote subsystem + * @dev: reference to the associated struct device + * @name: name of this edge + * @rx_pipe: pipe object for receive FIFO + * @tx_pipe: pipe object for transmit FIFO + * @rx_work: worker for handling received control messages + * @rx_worker: worker struct for handling received control messages + * @rx_task: task that runs the rx_worker + * @rx_lock: protects the @rx_queue + * @rx_queue: queue of received control messages to be processed in @rx_work + * @tx_lock: synchronizes operations on the tx fifo + * @idr_lock: synchronizes @lcids and @rcids modifications + * @lcids: idr of all channels with a known local channel id + * @rcids: idr of all channels with a known remote channel id + * @spi_ops: spi ops for sending data to the remote + * @cmpnt: component to be registered with the wdsp component manager + * @in_reset indicates that remote processor is in reset + * @ilc: ipc logging context reference + */ +struct glink_spi { + struct device dev; + + const char *name; + + struct glink_spi_pipe rx_pipe; + struct glink_spi_pipe tx_pipe; + + struct kthread_work rx_work; + struct kthread_worker rx_worker; + struct task_struct *rx_task; + + spinlock_t rx_lock; + struct list_head rx_queue; + struct work_struct rx_defer_work; + + struct mutex tx_lock; + + spinlock_t idr_lock; + struct idr lcids; + struct idr rcids; + u32 features; + + bool intentless; + + struct wcd_spi_ops spi_ops; + struct glink_cmpnt cmpnt; + u32 activity_flag; + spinlock_t activity_lock; + bool in_reset; + + void *ilc; +}; + +enum { + GLINK_STATE_CLOSED, + GLINK_STATE_OPENING, + GLINK_STATE_OPEN, + GLINK_STATE_CLOSING, +}; + +/** + * struct glink_channel - internal representation of a channel + * @rpdev: rpdev reference, only used for primary endpoints + * @ept: rpmsg endpoint this channel is associated with + * @glink: glink_spi context handle + * @refcount: refcount for the channel object + * @recv_lock: guard for @ept.cb + * @name: unique channel name/identifier + * @lcid: channel id, in local space + * @rcid: channel id, in remote space + * @intent_lock: lock for protection of @liids, @riids + * @liids: idr of all local intents + * @riids: idr of all remote intents + * @intent_work: worker responsible for transmitting rx_done packets + * @done_intents: list of intents that needs to be announced rx_done + * @buf: receive buffer, for gathering fragments + * @buf_offset: write offset in @buf + * @buf_size: size of current @buf + * @open_ack: completed once remote has acked the open-request + * @open_req: completed once open-request has been received + * @intent_req_lock: Synchronises multiple intent requests + * @intent_req_result: Result of intent request + * @intent_req_comp: Completion for intent_req signalling + */ +struct glink_channel { + struct rpmsg_endpoint ept; + + struct rpmsg_device *rpdev; + struct glink_spi *glink; + + struct kref refcount; + + spinlock_t recv_lock; + + char *name; + unsigned int lcid; + unsigned int rcid; + + spinlock_t intent_lock; + struct idr liids; + struct idr riids; + struct work_struct intent_work; + struct list_head done_intents; + + struct glink_core_rx_intent *buf; + int buf_offset; + int buf_size; + + unsigned int lsigs; + unsigned int rsigs; + + struct completion open_ack; + struct completion open_req; + + struct mutex intent_req_lock; + bool intent_req_result; + struct completion intent_req_comp; +}; + +#define to_glink_channel(_ept) container_of(_ept, struct glink_channel, ept) + +static const struct rpmsg_endpoint_ops glink_endpoint_ops; + +#define SPI_CMD_VERSION 0 +#define SPI_CMD_VERSION_ACK 1 +#define SPI_CMD_OPEN 2 +#define SPI_CMD_CLOSE 3 +#define SPI_CMD_OPEN_ACK 4 +#define SPI_CMD_CLOSE_ACK 5 +#define SPI_CMD_INTENT 6 +#define SPI_CMD_RX_DONE 7 +#define SPI_CMD_RX_DONE_W_REUSE 8 +#define SPI_CMD_RX_INTENT_REQ 9 +#define SPI_CMD_RX_INTENT_REQ_ACK 10 +#define SPI_CMD_TX_DATA 11 +#define SPI_CMD_TX_DATA_CONT 12 +#define SPI_CMD_READ_NOTIF 13 +#define SPI_CMD_SIGNALS 14 +#define SPI_CMD_TX_SHORT_DATA 17 + +static void glink_spi_rx_done_work(struct work_struct *work); +static void glink_spi_remove(struct glink_spi *glink); + +/** + * spi_suspend() - Vote for the spi device suspend + * @cmpnt: Component to identify the spi device. + * + * Return: 0 on success, standard Linux error codes on failure. + */ +static int spi_suspend(struct glink_cmpnt *cmpnt) +{ + if (!cmpnt || !cmpnt->master_dev || !cmpnt->master_ops || + !cmpnt->master_ops->suspend) + return 0; + + return cmpnt->master_ops->suspend(cmpnt->master_dev); +} + +/** + * spi_resume() - Vote for the spi device resume + * @cmpnt: Component to identify the spi device. + * + * Return: 0 on success, standard Linux error codes on failure. + */ +static int spi_resume(struct glink_cmpnt *cmpnt) +{ + if (!cmpnt || !cmpnt->master_dev || !cmpnt->master_ops || + !cmpnt->master_ops->resume) + return 0; + + return cmpnt->master_ops->resume(cmpnt->master_dev); +} + +/** + * glink_spi_xprt_set_poll_mode() - Set the transport to polling mode + * @glink: Edge information corresponding to the transport. + * + * This helper function indicates the start of RX polling. This will + * prevent the system from suspending and keeps polling for RX for a + * pre-defined duration. + */ +static void glink_spi_xprt_set_poll_mode(struct glink_spi *glink) +{ + unsigned long flags; + + spin_lock_irqsave(&glink->activity_lock, flags); + glink->activity_flag |= ACTIVE_RX; + spin_unlock_irqrestore(&glink->activity_lock, flags); + + spi_resume(&glink->cmpnt); +} + +/** + * glink_spi_xprt_set_irq_mode() - Set the transport to IRQ mode + * @glink: Edge information corresponding to the transport. + * + * This helper indicates the end of RX polling. This will allow the + * system to suspend and new RX data can be handled only through an IRQ. + */ +static void glink_spi_xprt_set_irq_mode(struct glink_spi *glink) +{ + unsigned long flags; + + spin_lock_irqsave(&glink->activity_lock, flags); + glink->activity_flag &= ~ACTIVE_RX; + spin_unlock_irqrestore(&glink->activity_lock, flags); + + spi_suspend(&glink->cmpnt); +} + +static struct glink_channel *glink_spi_alloc_channel(struct glink_spi *glink, + const char *name) +{ + struct glink_channel *channel; + + channel = kzalloc(sizeof(*channel), GFP_KERNEL); + if (!channel) + return ERR_PTR(-ENOMEM); + + /* Setup glink internal glink_channel data */ + spin_lock_init(&channel->recv_lock); + spin_lock_init(&channel->intent_lock); + mutex_init(&channel->intent_req_lock); + + channel->glink = glink; + channel->name = kstrdup(name, GFP_KERNEL); + + init_completion(&channel->open_req); + init_completion(&channel->open_ack); + init_completion(&channel->intent_req_comp); + + INIT_LIST_HEAD(&channel->done_intents); + INIT_WORK(&channel->intent_work, glink_spi_rx_done_work); + + idr_init(&channel->liids); + idr_init(&channel->riids); + kref_init(&channel->refcount); + + return channel; +} + +static void glink_spi_channel_release(struct kref *ref) +{ + struct glink_channel *channel = container_of(ref, struct glink_channel, + refcount); + unsigned long flags; + + CH_INFO(channel, "\n"); + spin_lock_irqsave(&channel->intent_lock, flags); + idr_destroy(&channel->liids); + idr_destroy(&channel->riids); + spin_unlock_irqrestore(&channel->intent_lock, flags); + + kfree(channel->name); + kfree(channel); +} + +/** + * glink_spi_read() - Receive data over SPI bus + * @glink: Edge from which the data has to be received. + * @src: Source Address of the RX data. + * @dst: Address of the destination RX buffer. + * @size: Size of the RX data. + * + * This function is used to receive data or command as a byte stream from + * the remote subsystem over the SPI bus. + * + * Return: 0 on success, standard Linux error codes on failure. + */ +static int glink_spi_read(struct glink_spi *glink, u32 src, void *dst, + size_t size) +{ + struct wcd_spi_msg spi_msg = { 0 }; + + if (unlikely(!glink->spi_ops.read_dev)) + return -EINVAL; + + spi_msg.data = dst; + spi_msg.remote_addr = src; + spi_msg.len = size; + return glink->spi_ops.read_dev(glink->spi_ops.spi_dev, &spi_msg); +} + +/** + * glink_spi_write() - Transmit data over SPI bus + * @glink: Edge from which the data has to be received. + * @src: Address of the TX buffer. + * @dst: Destination Address of the TX Data. + * @size: Size of the TX data. + * + * This function is used to transmit data or command as a byte stream to + * the remote subsystem over the SPI bus. + * + * Return: 0 on success, standard Linux error codes on failure. + */ +static int glink_spi_write(struct glink_spi *glink, void *src, u32 dst, + size_t size) +{ + struct wcd_spi_msg spi_msg = { 0 }; + + if (unlikely(!glink->spi_ops.write_dev)) + return -EINVAL; + + spi_msg.data = src; + spi_msg.remote_addr = dst; + spi_msg.len = size; + return glink->spi_ops.write_dev(glink->spi_ops.spi_dev, &spi_msg); +} + +/** + * glink_spi_reg_read() - Read the TX/RX FIFO Read/Write Index registers + * @glink: Edge from which the registers have to be read. + * @reg_addr: Address of the register to be read. + * @data: Buffer into which the register data has to be read. + * + * Return: 0 on success, standard Linux error codes on failure. + */ +static int glink_spi_reg_read(struct glink_spi *glink, u32 reg_addr, u32 *data) +{ + int ret; + + ret = glink_spi_read(glink, reg_addr, data, sizeof(*data)); + if (ret) + return ret; + + /* SPI register reads need to be masked */ + *data = *data & ID_MASK; + return 0; +} + +/** + * glink_spi_reg_write() - Write the TX/RX FIFO Read/Write Index registers + * @glink: Edge to which the registers have to be written. + * @reg_addr: Address of the registers to be written. + * @data: Data to be written to the registers. + * + * Return: 0 on success, standard Linux error codes on failure. + */ +static int glink_spi_reg_write(struct glink_spi *glink, u32 reg_addr, u32 data) +{ + return glink_spi_write(glink, &data, reg_addr, sizeof(data)); +} + +static size_t glink_spi_rx_avail(struct glink_spi *glink) +{ + struct glink_spi_pipe *pipe = &glink->rx_pipe; + u32 head; + u32 tail; + int ret; + + if (unlikely(glink->in_reset)) + return 0; + + if (unlikely(!pipe->fifo_base)) { + ret = glink_spi_reg_read(glink, pipe->tail_addr, + &pipe->local_addr); + if (ret < 0) { + GLINK_ERR(glink, "Error %d reading rx tail\n", ret); + return 0; + } + pipe->fifo_base = pipe->local_addr; + } + + tail = pipe->local_addr; + ret = glink_spi_reg_read(glink, pipe->head_addr, &head); + if (ret < 0) { + GLINK_ERR(glink, "Error %d reading rx head\n", ret); + return 0; + } + + if (head < tail) + return pipe->length - (tail - head); + else + return head - tail; +} + +static void glink_spi_rx_peak(struct glink_spi *glink, + void *data, unsigned int offset, size_t count) +{ + struct glink_spi_pipe *pipe = &glink->rx_pipe; + u32 fifo_end; + size_t len; + u32 tail; + + fifo_end = pipe->fifo_base + pipe->length; + tail = pipe->local_addr; + tail += offset; + if (tail >= fifo_end) + tail -= pipe->length; + + len = min_t(size_t, count, fifo_end - tail); + if (len) + glink_spi_read(glink, tail, data, len); + + if (len != count) + glink_spi_read(glink, pipe->fifo_base, data + len, count - len); +} + +static void glink_spi_rx_advance(struct glink_spi *glink, size_t count) +{ + struct glink_spi_pipe *pipe = &glink->rx_pipe; + u32 tail; + int ret; + + tail = pipe->local_addr; + tail += count; + + if (tail > pipe->fifo_base + pipe->length) + tail -= pipe->length; + + pipe->local_addr = tail; + ret = glink_spi_reg_write(glink, pipe->tail_addr, tail); + if (ret) + GLINK_ERR(glink, "Error writing rx tail\n", ret); +} + +static size_t glink_spi_tx_avail(struct glink_spi *glink) +{ + struct glink_spi_pipe *pipe = &glink->tx_pipe; + u32 avail; + u32 head; + u32 tail; + int ret; + + if (unlikely(glink->in_reset)) + return 0; + + if (unlikely(!pipe->fifo_base)) { + ret = glink_spi_reg_read(glink, pipe->head_addr, + &pipe->local_addr); + if (ret < 0) { + GLINK_ERR(glink, "Error %d reading tx head\n", ret); + return 0; + } + pipe->fifo_base = pipe->local_addr; + } + + head = pipe->local_addr; + ret = glink_spi_reg_read(glink, pipe->tail_addr, &tail); + if (ret < 0) { + GLINK_ERR(glink, "Error %d reading tx tail\n", ret); + return 0; + } + + if (tail <= head) + avail = pipe->fifo_base + pipe->length - head + tail; + else + avail = tail - head; + + if (avail < (FIFO_FULL_RESERVE + TX_BLOCKED_CMD_RESERVE)) + avail = 0; + else + avail -= FIFO_FULL_RESERVE + TX_BLOCKED_CMD_RESERVE; + + return avail; +} + +static unsigned int glink_spi_tx_write_one(struct glink_spi *glink, u32 head, + void *data, size_t count) +{ + struct glink_spi_pipe *pipe = &glink->tx_pipe; + size_t len; + int ret; + + len = min_t(size_t, count, pipe->fifo_base + pipe->length - head); + if (len) { + ret = glink_spi_write(glink, data, head, len); + if (ret) + GLINK_ERR(glink, "Error %d writing tx data\n", ret); + } + + if (len != count) { + ret = glink_spi_write(glink, data + len, pipe->fifo_base, + count - len); + if (ret) + GLINK_ERR(glink, "Error %d writing tx data\n", ret); + } + + head += count; + if (head >= pipe->fifo_base + pipe->length) + head -= pipe->length; + + return head; +} + +static void glink_spi_tx_write(struct glink_spi *glink, void *hdr, size_t hlen, + void *data, size_t dlen) +{ + struct glink_spi_pipe *pipe = &glink->tx_pipe; + u32 head; + int ret; + + head = pipe->local_addr; + + if (hlen) + head = glink_spi_tx_write_one(glink, head, hdr, hlen); + if (dlen) + head = glink_spi_tx_write_one(glink, head, data, dlen); + + /* Ensure head is always aligned to 8 bytes */ + head = ALIGN(head, SPI_ALIGNMENT); + if (head >= pipe->fifo_base + pipe->length) + head -= pipe->length; + + pipe->local_addr = head; + ret = glink_spi_reg_write(glink, pipe->head_addr, head); + if (ret) + GLINK_ERR(glink, "Error %d writing tx head\n", ret); + +} + +static int glink_spi_tx(struct glink_spi *glink, void *hdr, size_t hlen, + void *data, size_t dlen, bool wait) +{ + unsigned int tlen = hlen + dlen; + int ret = 0; + + if (tlen >= glink->tx_pipe.length) + return -EINVAL; + + mutex_lock(&glink->tx_lock); + + while (glink_spi_tx_avail(glink) < tlen) { + if (!wait) { + ret = -EAGAIN; + goto out; + } + + if (unlikely(glink->in_reset)) { + ret = -ENXIO; + goto out; + } + + /* Wait without holding the tx_lock */ + mutex_unlock(&glink->tx_lock); + + usleep_range(10000, 15000); + + mutex_lock(&glink->tx_lock); + } + + glink_spi_tx_write(glink, hdr, hlen, data, dlen); + +out: + mutex_unlock(&glink->tx_lock); + + + return ret; +} + +static int glink_spi_send_version(struct glink_spi *glink) +{ + struct glink_msg msg = { 0 }; + + msg.cmd = cpu_to_le16(SPI_CMD_VERSION); + msg.param1 = cpu_to_le16(GLINK_VERSION_1); + msg.param2 = cpu_to_le32(glink->features); + + GLINK_INFO(glink, "vers:%d features:%d\n", msg.param1, msg.param2); + return glink_spi_tx(glink, &msg, sizeof(msg), NULL, 0, true); +} + +static void glink_spi_send_version_ack(struct glink_spi *glink) +{ + struct glink_msg msg = { 0 }; + + msg.cmd = cpu_to_le16(SPI_CMD_VERSION_ACK); + msg.param1 = cpu_to_le16(GLINK_VERSION_1); + msg.param2 = cpu_to_le32(glink->features); + + GLINK_INFO(glink, "vers:%d features:%d\n", msg.param1, msg.param2); + glink_spi_tx(glink, &msg, sizeof(msg), NULL, 0, true); +} + +/** + * glink_spi_receive_version() - receive version/features from remote system + * + * @glink: pointer to transport interface + * @r_version: remote version + * @r_features: remote features + * + * This function is called in response to a remote-initiated version/feature + * negotiation sequence. + */ +static void glink_spi_receive_version(struct glink_spi *glink, + u32 version, + u32 features) +{ + GLINK_INFO(glink, "vers:%d features:%d\n", version, features); + + switch (version) { + case 0: + break; + case GLINK_VERSION_1: + glink->features &= features; + /* FALLTHROUGH */ + default: + glink_spi_send_version_ack(glink); + break; + } +} + +/** + * glink_spi_receive_version_ack() - receive negotiation ack from remote system + * + * @glink: pointer to transport interface + * @r_version: remote version response + * @r_features: remote features response + * + * This function is called in response to a local-initiated version/feature + * negotiation sequence and is the counter-offer from the remote side based + * upon the initial version and feature set requested. + */ +static void glink_spi_receive_version_ack(struct glink_spi *glink, + u32 version, + u32 features) +{ + GLINK_INFO(glink, "vers:%d features:%d\n", version, features); + + switch (version) { + case 0: + /* Version negotiation failed */ + break; + case GLINK_VERSION_1: + if (features == glink->features) + break; + + glink->features &= features; + /* FALLTHROUGH */ + default: + glink_spi_send_version(glink); + break; + } +} + +/** + * glink_spi_send_open_req() - send a SPI_CMD_OPEN request to the remote + * @glink: Ptr to the glink edge + * @channel: Ptr to the channel that the open req is sent + * + * Allocates a local channel id and sends a SPI_CMD_OPEN message to the remote. + * Will return with refcount held, regardless of outcome. + * + * Returns 0 on success, negative errno otherwise. + */ +static int glink_spi_send_open_req(struct glink_spi *glink, + struct glink_channel *channel) +{ + + struct cmd_msg { + __le16 cmd; + __le16 lcid; + __le16 length; + __le16 req_xprt; + __le64 reserved; + }; + struct { + struct cmd_msg msg; + u8 name[GLINK_NAME_SIZE]; + } __packed req; + int name_len = strlen(channel->name) + 1; + int req_len = ALIGN(sizeof(req.msg) + name_len, SPI_ALIGNMENT); + int ret; + unsigned long flags; + + kref_get(&channel->refcount); + + spin_lock_irqsave(&glink->idr_lock, flags); + ret = idr_alloc_cyclic(&glink->lcids, channel, + SPI_GLINK_CID_MIN, SPI_GLINK_CID_MAX, + GFP_ATOMIC); + spin_unlock_irqrestore(&glink->idr_lock, flags); + if (ret < 0) + return ret; + + channel->lcid = ret; + CH_INFO(channel, "\n"); + + memset(&req, 0, sizeof(req)); + req.msg.cmd = cpu_to_le16(SPI_CMD_OPEN); + req.msg.lcid = cpu_to_le16(channel->lcid); + req.msg.length = cpu_to_le16(name_len); + strlcpy(req.name, channel->name, GLINK_NAME_SIZE); + + ret = glink_spi_tx(glink, &req, req_len, NULL, 0, true); + if (ret) + goto remove_idr; + + return 0; + +remove_idr: + CH_INFO(channel, "remove_idr\n"); + + spin_lock_irqsave(&glink->idr_lock, flags); + idr_remove(&glink->lcids, channel->lcid); + channel->lcid = 0; + spin_unlock_irqrestore(&glink->idr_lock, flags); + + return ret; +} + +static void glink_spi_send_open_ack(struct glink_spi *glink, + struct glink_channel *channel) +{ + struct glink_msg msg = { 0 }; + + msg.cmd = cpu_to_le16(SPI_CMD_OPEN_ACK); + msg.param1 = cpu_to_le16(channel->rcid); + + CH_INFO(channel, "\n"); + glink_spi_tx(glink, &msg, sizeof(msg), NULL, 0, true); +} + +static int glink_spi_rx_open_ack(struct glink_spi *glink, unsigned int lcid) +{ + struct glink_channel *channel; + + spin_lock(&glink->idr_lock); + channel = idr_find(&glink->lcids, lcid); + spin_unlock(&glink->idr_lock); + if (!channel) { + GLINK_ERR(glink, "Invalid open ack packet %d\n", lcid); + return -EINVAL; + } + + CH_INFO(channel, "\n"); + complete_all(&channel->open_ack); + + return 0; +} + +static void glink_spi_send_close_req(struct glink_spi *glink, + struct glink_channel *channel) +{ + struct glink_msg req = { 0 }; + + req.cmd = cpu_to_le16(SPI_CMD_CLOSE); + req.param1 = cpu_to_le16(channel->lcid); + + CH_INFO(channel, "\n"); + glink_spi_tx(glink, &req, sizeof(req), NULL, 0, true); +} + +static void glink_spi_send_close_ack(struct glink_spi *glink, + unsigned int rcid) +{ + struct glink_msg req = { 0 }; + + req.cmd = cpu_to_le16(SPI_CMD_CLOSE_ACK); + req.param1 = cpu_to_le16(rcid); + + GLINK_INFO(glink, "rcid:%d\n", rcid); + glink_spi_tx(glink, &req, sizeof(req), NULL, 0, true); +} + +static int glink_spi_request_intent(struct glink_spi *glink, + struct glink_channel *channel, + size_t size) +{ + struct glink_msg req = { 0 }; + int ret; + + mutex_lock(&channel->intent_req_lock); + + reinit_completion(&channel->intent_req_comp); + + req.cmd = cpu_to_le16(SPI_CMD_RX_INTENT_REQ); + req.param1 = cpu_to_le16(channel->lcid); + req.param2 = cpu_to_le32(size); + + CH_INFO(channel, "size:%d\n", size); + + ret = glink_spi_tx(glink, &req, sizeof(req), NULL, 0, true); + if (ret) + goto unlock; + + ret = wait_for_completion_timeout(&channel->intent_req_comp, 10 * HZ); + if (!ret) { + dev_err(&glink->dev, "intent request timed out\n"); + ret = -ETIMEDOUT; + } else { + ret = channel->intent_req_result ? 0 : -ECANCELED; + } + +unlock: + mutex_unlock(&channel->intent_req_lock); + return ret; +} + +static int glink_spi_handle_intent(struct glink_spi *glink, + unsigned int cid, + unsigned int count, + void *rx_data, + size_t avail) +{ + struct glink_core_rx_intent *intent; + struct glink_channel *channel; + struct intent_pair { + __le32 size; + __le32 iid; + __le64 addr; + }; + struct intent_pair *intents; + const size_t msglen = sizeof(struct intent_pair) * count; + int ret; + int i; + unsigned long flags; + + if (avail < msglen) { + dev_err(&glink->dev, "Not enough data in buf\n"); + return avail; + } + + spin_lock_irqsave(&glink->idr_lock, flags); + channel = idr_find(&glink->rcids, cid); + spin_unlock_irqrestore(&glink->idr_lock, flags); + if (!channel) { + dev_err(&glink->dev, "intents for non-existing channel\n"); + return msglen; + } + + intents = (struct intent_pair *)rx_data; + for (i = 0; i < count; ++i) { + intent = kzalloc(sizeof(*intent), GFP_ATOMIC); + if (!intent) + break; + + intent->id = le32_to_cpu(intents[i].iid); + intent->size = le32_to_cpu(intents[i].size); + intent->addr = (u32)le64_to_cpu(intents[i].addr); + + CH_INFO(channel, "riid:%d size:%d\n", intent->id, intent->size); + + spin_lock_irqsave(&channel->intent_lock, flags); + ret = idr_alloc(&channel->riids, intent, + intent->id, intent->id + 1, GFP_ATOMIC); + spin_unlock_irqrestore(&channel->intent_lock, flags); + + if (ret < 0) + dev_err(&glink->dev, "failed to store remote intent\n"); + } + + return msglen; +} + +static void glink_spi_handle_intent_req_ack(struct glink_spi *glink, + unsigned int cid, bool granted) +{ + struct glink_channel *channel; + unsigned long flags; + + spin_lock_irqsave(&glink->idr_lock, flags); + channel = idr_find(&glink->rcids, cid); + spin_unlock_irqrestore(&glink->idr_lock, flags); + if (!channel) { + dev_err(&glink->dev, "unable to find channel\n"); + return; + } + + channel->intent_req_result = granted; + complete(&channel->intent_req_comp); + CH_INFO(channel, "\n"); +} + +/** + * glink_spi_send_intent_req_ack() - convert an rx intent request ack cmd to + wire format and transmit + * @glink: The transport to transmit on. + * @channel: The glink channel + * @granted: The request response to encode. + * + * Return: 0 on success or standard Linux error code. + */ +static int glink_spi_send_intent_req_ack(struct glink_spi *glink, + struct glink_channel *channel, + bool granted) +{ + struct glink_msg msg = { 0 }; + + msg.cmd = cpu_to_le16(SPI_CMD_RX_INTENT_REQ_ACK); + msg.param1 = cpu_to_le16(channel->lcid); + msg.param2 = cpu_to_le32(granted); + + CH_INFO(channel, "\n"); + glink_spi_tx(glink, &msg, sizeof(msg), NULL, 0, true); + + return 0; +} + +static struct glink_core_rx_intent * +glink_spi_alloc_intent(struct glink_spi *glink, + struct glink_channel *channel, + size_t size, + bool reuseable) +{ + struct glink_core_rx_intent *intent; + int ret; + unsigned long flags; + + intent = kzalloc(sizeof(*intent), GFP_KERNEL); + if (!intent) + return NULL; + + intent->data = kzalloc(size, GFP_KERNEL); + if (!intent->data) + goto free_intent; + + spin_lock_irqsave(&channel->intent_lock, flags); + ret = idr_alloc_cyclic(&channel->liids, intent, 1, -1, GFP_ATOMIC); + if (ret < 0) { + spin_unlock_irqrestore(&channel->intent_lock, flags); + goto free_data; + } + spin_unlock_irqrestore(&channel->intent_lock, flags); + + intent->id = ret; + intent->size = size; + intent->reuse = reuseable; + + return intent; + +free_data: + kfree(intent->data); +free_intent: + kfree(intent); + return NULL; +} + +/** + * glink_spi_advertise_intent - convert an rx intent cmd to wire format and + * transmit + * @glink: The transport to transmit on. + * @channel: The local channel + * @size: The intent to pass on to remote. + * + * Return: 0 on success or standard Linux error code. + */ +static int glink_spi_advertise_intent(struct glink_spi *glink, + struct glink_channel *channel, + struct glink_core_rx_intent *intent) +{ + struct command { + struct glink_msg msg; + __le32 size; + __le32 liid; + __le64 addr; + } __packed; + struct command cmd; + + memset(&cmd, 0, sizeof(cmd)); + cmd.msg.cmd = cpu_to_le16(SPI_CMD_INTENT); + cmd.msg.param1 = cpu_to_le16(channel->lcid); + cmd.msg.param2 = cpu_to_le32(1); + cmd.size = cpu_to_le32(intent->size); + cmd.liid = cpu_to_le32(intent->id); + + CH_INFO(channel, "count:%d size:%d liid:%d\n", 1, + intent->size, intent->id); + + glink_spi_tx(glink, &cmd, sizeof(cmd), NULL, 0, true); + + return 0; +} + +/** + * glink_spi_handle_intent_req() - Receive a request for rx_intent + * from remote side + * if_ptr: Pointer to the transport interface + * rcid: Remote channel ID + * size: size of the intent + * + * The function searches for the local channel to which the request for + * rx_intent has arrived and allocates and notifies the remote back + */ +static void glink_spi_handle_intent_req(struct glink_spi *glink, + u32 cid, size_t size) +{ + struct glink_core_rx_intent *intent; + struct glink_channel *channel; + unsigned long flags; + + spin_lock_irqsave(&glink->idr_lock, flags); + channel = idr_find(&glink->rcids, cid); + spin_unlock_irqrestore(&glink->idr_lock, flags); + + if (!channel) { + pr_err("%s channel not found for cid %d\n", __func__, cid); + return; + } + + intent = glink_spi_alloc_intent(glink, channel, size, false); + if (intent) + glink_spi_advertise_intent(glink, channel, intent); + + glink_spi_send_intent_req_ack(glink, channel, !!intent); +} + +static int glink_spi_send_short(struct glink_channel *channel, + void *data, int len, + struct glink_core_rx_intent *intent, bool wait) +{ + struct glink_spi *glink = channel->glink; + struct { + struct glink_msg msg; + u8 data[SHORT_PKT_SIZE]; + } __packed req; + int ret = 0; + + req.msg.cmd = cpu_to_le16(SPI_CMD_TX_SHORT_DATA); + req.msg.param1 = cpu_to_le16(channel->lcid); + req.msg.param2 = cpu_to_le32(intent->id); + req.msg.param3 = cpu_to_le32(len); + req.msg.param4 = cpu_to_be32(0); + memcpy(req.data, data, len); + + mutex_lock(&glink->tx_lock); + while (glink_spi_tx_avail(glink) < sizeof(req)) { + if (!wait) { + ret = -EAGAIN; + goto out; + } + + if (unlikely(glink->in_reset)) { + ret = -ENXIO; + goto out; + } + + /* Wait without holding the tx_lock */ + mutex_unlock(&glink->tx_lock); + + usleep_range(10000, 15000); + + mutex_lock(&glink->tx_lock); + } + glink_spi_tx_write(glink, &req, sizeof(req), NULL, 0); + +out: + mutex_unlock(&glink->tx_lock); + return ret; +} + +static int __glink_spi_send(struct glink_channel *channel, + void *data, int len, bool wait) +{ + struct glink_spi *glink = channel->glink; + struct glink_core_rx_intent *intent = NULL; + struct glink_core_rx_intent *tmp; + int iid = 0; + struct { + struct glink_msg msg; + __le32 chunk_size; + __le32 left_size; + } __packed req; + int ret = 0; + unsigned long flags; + + CH_INFO(channel, "size:%d, wait:%d\n", len, wait); + + spin_lock_irqsave(&glink->activity_lock, flags); + glink->activity_flag |= ACTIVE_TX; + spin_unlock_irqrestore(&glink->activity_lock, flags); + + while (!intent) { + spin_lock_irqsave(&channel->intent_lock, flags); + idr_for_each_entry(&channel->riids, tmp, iid) { + if (tmp->size >= len && !tmp->in_use) { + if (!intent) + intent = tmp; + else if (intent->size > tmp->size) + intent = tmp; + if (intent->size == len) + break; + } + } + if (intent) + intent->in_use = true; + spin_unlock_irqrestore(&channel->intent_lock, flags); + + /* We found an available intent */ + if (intent) + break; + + if (!wait) { + ret = -EBUSY; + goto tx_exit; + } + + ret = glink_spi_request_intent(glink, channel, len); + if (ret < 0) + goto tx_exit; + } + + memset(&req, 0, sizeof(req)); + iid = intent->id; + + if (len <= SHORT_PKT_SIZE) { + ret = glink_spi_send_short(channel, data, len, intent, wait); + goto tx_exit; + } + + if (intent->offset) + req.msg.cmd = cpu_to_le16(SPI_CMD_TX_DATA_CONT); + else + req.msg.cmd = cpu_to_le16(SPI_CMD_TX_DATA); + + req.msg.param1 = cpu_to_le16(channel->lcid); + req.msg.param2 = cpu_to_le32(iid); + req.chunk_size = cpu_to_le32(len); + req.left_size = cpu_to_le32(0); + + mutex_lock(&glink->tx_lock); + while (glink_spi_tx_avail(glink) < sizeof(req)) { + if (!wait) { + ret = -EAGAIN; + mutex_unlock(&glink->tx_lock); + goto tx_exit; + } + + if (unlikely(glink->in_reset)) { + ret = -EINVAL; + mutex_unlock(&glink->tx_lock); + goto tx_exit; + } + + /* Wait without holding the tx_lock */ + mutex_unlock(&glink->tx_lock); + + usleep_range(10000, 15000); + + mutex_lock(&glink->tx_lock); + } + + glink_spi_write(glink, data, intent->addr, len); + glink_spi_tx_write(glink, &req, sizeof(req), NULL, 0); + mutex_unlock(&glink->tx_lock); + +tx_exit: + /* Mark intent available if we failed */ + if (ret && intent) + intent->in_use = false; + + spin_lock_irqsave(&glink->activity_lock, flags); + glink->activity_flag &= ~ACTIVE_TX; + spin_unlock_irqrestore(&glink->activity_lock, flags); + + return ret; +} + +static void glink_spi_handle_rx_done(struct glink_spi *glink, + u32 cid, uint32_t iid, + bool reuse) +{ + struct glink_core_rx_intent *intent; + struct glink_channel *channel; + unsigned long flags; + + spin_lock_irqsave(&glink->idr_lock, flags); + channel = idr_find(&glink->rcids, cid); + spin_unlock_irqrestore(&glink->idr_lock, flags); + if (!channel) { + dev_err(&glink->dev, "invalid channel id received\n"); + return; + } + + spin_lock_irqsave(&channel->intent_lock, flags); + intent = idr_find(&channel->riids, iid); + + if (!intent) { + spin_unlock_irqrestore(&channel->intent_lock, flags); + dev_err(&glink->dev, "invalid intent id received\n"); + return; + } + + intent->in_use = false; + CH_INFO(channel, "reuse:%d iid:%d\n", reuse, intent->id); + + if (!reuse) { + idr_remove(&channel->riids, intent->id); + kfree(intent); + } + spin_unlock_irqrestore(&channel->intent_lock, flags); +} + +static void glink_spi_rx_done(struct glink_spi *glink, + struct glink_channel *channel, + struct glink_core_rx_intent *intent) +{ + /* We don't send RX_DONE to intentless systems */ + if (glink->intentless) { + kfree(intent->data); + kfree(intent); + return; + } + + /* Take it off the tree of receive intents */ + if (!intent->reuse) { + spin_lock(&channel->intent_lock); + idr_remove(&channel->liids, intent->id); + spin_unlock(&channel->intent_lock); + } + + /* Schedule the sending of a rx_done indication */ + spin_lock(&channel->intent_lock); + list_add_tail(&intent->node, &channel->done_intents); + spin_unlock(&channel->intent_lock); + + schedule_work(&channel->intent_work); +} + +static void glink_spi_rx_done_work(struct work_struct *work) +{ + struct glink_channel *channel = container_of(work, struct glink_channel, + intent_work); + struct glink_spi *glink = channel->glink; + struct glink_core_rx_intent *intent, *tmp; + struct { + u16 id; + u16 lcid; + u32 liid; + u64 reserved; + } __packed cmd; + + unsigned int lcid = channel->lcid; + unsigned int iid; + bool reuse; + unsigned long flags; + + spin_lock_irqsave(&channel->intent_lock, flags); + list_for_each_entry_safe(intent, tmp, &channel->done_intents, node) { + list_del(&intent->node); + spin_unlock_irqrestore(&channel->intent_lock, flags); + iid = intent->id; + reuse = intent->reuse; + + cmd.id = reuse ? SPI_CMD_RX_DONE_W_REUSE : SPI_CMD_RX_DONE; + cmd.lcid = lcid; + cmd.liid = iid; + + CH_INFO(channel, "reuse:%d liid:%d", reuse, iid); + glink_spi_tx(glink, &cmd, sizeof(cmd), NULL, 0, true); + if (!reuse) { + kfree(intent->data); + kfree(intent); + } + spin_lock_irqsave(&channel->intent_lock, flags); + } + spin_unlock_irqrestore(&channel->intent_lock, flags); +} + +/* Locally initiated rpmsg_create_ept */ +static struct glink_channel *glink_spi_create_local(struct glink_spi *glink, + const char *name) +{ + struct glink_channel *channel; + int ret; + unsigned long flags; + + channel = glink_spi_alloc_channel(glink, name); + if (IS_ERR(channel)) + return ERR_CAST(channel); + + CH_INFO(channel, "\n"); + ret = glink_spi_send_open_req(glink, channel); + if (ret) + goto release_channel; + + ret = wait_for_completion_timeout(&channel->open_ack, 5 * HZ); + if (!ret) + goto err_timeout; + + ret = wait_for_completion_timeout(&channel->open_req, 5 * HZ); + if (!ret) + goto err_timeout; + + glink_spi_send_open_ack(glink, channel); + + return channel; + +err_timeout: + CH_INFO(channel, "err_timeout\n"); + + /* glink_spi_send_open_req() did register the channel in lcids*/ + spin_lock_irqsave(&glink->idr_lock, flags); + idr_remove(&glink->lcids, channel->lcid); + spin_unlock_irqrestore(&glink->idr_lock, flags); + +release_channel: + CH_INFO(channel, "release_channel\n"); + /* Release glink_spi_send_open_req() reference */ + kref_put(&channel->refcount, glink_spi_channel_release); + /* Release glink_spi_alloc_channel() reference */ + kref_put(&channel->refcount, glink_spi_channel_release); + + return ERR_PTR(-ETIMEDOUT); +} + +/* Remote initiated rpmsg_create_ept */ +static int glink_spi_create_remote(struct glink_spi *glink, + struct glink_channel *channel) +{ + int ret; + + CH_INFO(channel, "\n"); + + glink_spi_send_open_ack(glink, channel); + + ret = glink_spi_send_open_req(glink, channel); + if (ret) + goto close_link; + + ret = wait_for_completion_timeout(&channel->open_ack, 5 * HZ); + if (!ret) { + ret = -ETIMEDOUT; + goto close_link; + } + + return 0; + +close_link: + CH_INFO(channel, "close_link %d\n", ret); + + /* + * Send a close request to "undo" our open-ack. The close-ack will + * release the last reference. + */ + glink_spi_send_close_req(glink, channel); + + /* Release glink_spi_send_open_req() reference */ + kref_put(&channel->refcount, glink_spi_channel_release); + + return ret; +} + +static struct rpmsg_endpoint *glink_spi_create_ept(struct rpmsg_device *rpdev, + rpmsg_rx_cb_t cb, + void *priv, + struct rpmsg_channel_info + chinfo) +{ + struct glink_channel *parent = to_glink_channel(rpdev->ept); + struct glink_channel *channel; + struct glink_spi *glink = parent->glink; + struct rpmsg_endpoint *ept; + const char *name = chinfo.name; + int cid; + int ret; + unsigned long flags; + + spin_lock_irqsave(&glink->idr_lock, flags); + idr_for_each_entry(&glink->rcids, channel, cid) { + if (!strcmp(channel->name, name)) + break; + } + spin_unlock_irqrestore(&glink->idr_lock, flags); + + if (!channel) { + channel = glink_spi_create_local(glink, name); + if (IS_ERR(channel)) + return NULL; + } else { + ret = glink_spi_create_remote(glink, channel); + if (ret) + return NULL; + } + + ept = &channel->ept; + ept->rpdev = rpdev; + ept->cb = cb; + ept->priv = priv; + ept->ops = &glink_endpoint_ops; + + return ept; +} + +static int glink_spi_announce_create(struct rpmsg_device *rpdev) +{ + struct glink_channel *channel = to_glink_channel(rpdev->ept); + struct device_node *np = rpdev->dev.of_node; + struct glink_spi *glink = channel->glink; + struct glink_core_rx_intent *intent; + const struct property *prop = NULL; + __be32 defaults[] = { cpu_to_be32(SZ_1K), cpu_to_be32(5) }; + int num_intents; + int num_groups = 1; + __be32 *val = defaults; + int size; + + if (glink->intentless || !completion_done(&channel->open_ack)) + return 0; + + prop = of_find_property(np, "qcom,intents", NULL); + if (prop) { + val = prop->value; + num_groups = prop->length / sizeof(u32) / 2; + } + + /* Channel is now open, advertise base set of intents */ + while (num_groups--) { + size = be32_to_cpup(val++); + num_intents = be32_to_cpup(val++); + while (num_intents--) { + intent = glink_spi_alloc_intent(glink, channel, size, + true); + if (!intent) + break; + + glink_spi_advertise_intent(glink, channel, intent); + } + } + return 0; +} + +static void glink_spi_destroy_ept(struct rpmsg_endpoint *ept) +{ + struct glink_channel *channel = to_glink_channel(ept); + struct glink_spi *glink = channel->glink; + unsigned long flags; + + spin_lock_irqsave(&channel->recv_lock, flags); + channel->ept.cb = NULL; + spin_unlock_irqrestore(&channel->recv_lock, flags); + + /* Decouple the potential rpdev from the channel */ + channel->rpdev = NULL; + + glink_spi_send_close_req(glink, channel); +} + +static void glink_spi_rx_close(struct glink_spi *glink, unsigned int rcid) +{ + struct rpmsg_channel_info chinfo; + struct glink_channel *channel; + unsigned long flags; + + spin_lock_irqsave(&glink->idr_lock, flags); + channel = idr_find(&glink->rcids, rcid); + spin_unlock_irqrestore(&glink->idr_lock, flags); + if (WARN(!channel, "close request on unknown channel\n")) + return; + CH_INFO(channel, "\n"); + + /* cancel pending rx_done work */ + cancel_work_sync(&channel->intent_work); + + if (channel->rpdev) { + strlcpy(chinfo.name, channel->name, sizeof(chinfo.name)); + chinfo.src = RPMSG_ADDR_ANY; + chinfo.dst = RPMSG_ADDR_ANY; + + rpmsg_unregister_device(&glink->dev, &chinfo); + } + + glink_spi_send_close_ack(glink, channel->rcid); + + spin_lock_irqsave(&glink->idr_lock, flags); + idr_remove(&glink->rcids, channel->rcid); + channel->rcid = 0; + spin_unlock_irqrestore(&glink->idr_lock, flags); + + kref_put(&channel->refcount, glink_spi_channel_release); +} + +static void glink_spi_rx_close_ack(struct glink_spi *glink, unsigned int lcid) +{ + struct glink_channel *channel; + unsigned long flags; + + spin_lock_irqsave(&glink->idr_lock, flags); + channel = idr_find(&glink->lcids, lcid); + if (WARN(!channel, "close ack on unknown channel\n")) { + spin_unlock_irqrestore(&glink->idr_lock, flags); + return; + } + CH_INFO(channel, "\n"); + + idr_remove(&glink->lcids, channel->lcid); + channel->lcid = 0; + spin_unlock_irqrestore(&glink->idr_lock, flags); + + kref_put(&channel->refcount, glink_spi_channel_release); +} + +static int glink_spi_send(struct rpmsg_endpoint *ept, void *data, int len) +{ + struct glink_channel *channel = to_glink_channel(ept); + + return __glink_spi_send(channel, data, len, true); +} + +static int glink_spi_trysend(struct rpmsg_endpoint *ept, void *data, int len) +{ + struct glink_channel *channel = to_glink_channel(ept); + + return __glink_spi_send(channel, data, len, false); +} + +/** + * glink_spi_send_signals() - convert a signal cmd to wire format and transmit + * @glink: The transport to transmit on. + * @channel: The glink channel + * @sigs: The signals to encode. + * + * Return: 0 on success or standard Linux error code. + */ +static int glink_spi_send_signals(struct glink_spi *glink, + struct glink_channel *channel, + u32 sigs) +{ + struct glink_msg msg; + + msg.cmd = cpu_to_le16(SPI_CMD_SIGNALS); + msg.param1 = cpu_to_le16(channel->lcid); + msg.param2 = cpu_to_le32(sigs); + + GLINK_INFO(glink, "sigs:%d\n", sigs); + return glink_spi_tx(glink, &msg, sizeof(msg), NULL, 0, true); +} + +static int glink_spi_handle_signals(struct glink_spi *glink, + unsigned int rcid, unsigned int signals) +{ + struct glink_channel *channel; + unsigned long flags; + u32 old; + + spin_lock_irqsave(&glink->idr_lock, flags); + channel = idr_find(&glink->rcids, rcid); + spin_unlock_irqrestore(&glink->idr_lock, flags); + if (!channel) { + dev_err(&glink->dev, "signal for non-existing channel\n"); + return -EINVAL; + } + + old = channel->rsigs; + channel->rsigs = signals; + + if (channel->ept.sig_cb) + channel->ept.sig_cb(channel->ept.rpdev, old, channel->rsigs); + + CH_INFO(channel, "old:%d new:%d\n", old, channel->rsigs); + + return 0; +} + +static int glink_spi_get_sigs(struct rpmsg_endpoint *ept, + u32 *lsigs, u32 *rsigs) +{ + struct glink_channel *channel = to_glink_channel(ept); + + *lsigs = channel->lsigs; + *rsigs = channel->rsigs; + + return 0; +} + +static int glink_spi_set_sigs(struct rpmsg_endpoint *ept, u32 sigs) +{ + struct glink_channel *channel = to_glink_channel(ept); + struct glink_spi *glink = channel->glink; + + channel->lsigs = sigs; + + return glink_spi_send_signals(glink, channel, sigs); +} + +/* + * Finds the device_node for the glink child interested in this channel. + */ +static struct device_node *glink_spi_match_channel(struct device_node *node, + const char *channel) +{ + struct device_node *child; + const char *name; + const char *key; + int ret; + + for_each_available_child_of_node(node, child) { + key = "qcom,glink-channels"; + ret = of_property_read_string(child, key, &name); + if (ret) + continue; + + if (strcmp(name, channel) == 0) + return child; + } + + return NULL; +} + +static const struct rpmsg_device_ops glink_device_ops = { + .create_ept = glink_spi_create_ept, + .announce_create = glink_spi_announce_create, +}; + +static const struct rpmsg_endpoint_ops glink_endpoint_ops = { + .destroy_ept = glink_spi_destroy_ept, + .send = glink_spi_send, + .trysend = glink_spi_trysend, + .get_sigs = glink_spi_get_sigs, + .set_sigs = glink_spi_set_sigs, +}; + +static void glink_spi_rpdev_release(struct device *dev) +{ + struct rpmsg_device *rpdev = to_rpmsg_device(dev); + struct glink_channel *channel = to_glink_channel(rpdev->ept); + + channel->rpdev = NULL; + kfree(rpdev); +} + +static int glink_spi_rx_open(struct glink_spi *glink, unsigned int rcid, + char *name) +{ + struct glink_channel *channel; + struct rpmsg_device *rpdev; + bool create_device = false; + struct device_node *node; + int lcid; + int ret; + unsigned long flags; + + spin_lock_irqsave(&glink->idr_lock, flags); + idr_for_each_entry(&glink->lcids, channel, lcid) { + if (!strcmp(channel->name, name)) + break; + } + spin_unlock_irqrestore(&glink->idr_lock, flags); + + if (!channel) { + channel = glink_spi_alloc_channel(glink, name); + if (IS_ERR(channel)) + return PTR_ERR(channel); + + /* The opening dance was initiated by the remote */ + create_device = true; + } + + spin_lock_irqsave(&glink->idr_lock, flags); + ret = idr_alloc(&glink->rcids, channel, rcid, rcid + 1, GFP_ATOMIC); + if (ret < 0) { + dev_err(&glink->dev, "Unable to insert channel into rcid list\n"); + spin_unlock_irqrestore(&glink->idr_lock, flags); + goto free_channel; + } + channel->rcid = ret; + spin_unlock_irqrestore(&glink->idr_lock, flags); + + complete_all(&channel->open_req); + + if (create_device) { + rpdev = kzalloc(sizeof(*rpdev), GFP_KERNEL); + if (!rpdev) { + ret = -ENOMEM; + goto rcid_remove; + } + + rpdev->ept = &channel->ept; + strlcpy(rpdev->id.name, name, RPMSG_NAME_SIZE); + rpdev->src = RPMSG_ADDR_ANY; + rpdev->dst = RPMSG_ADDR_ANY; + rpdev->ops = &glink_device_ops; + + node = glink_spi_match_channel(glink->dev.of_node, name); + rpdev->dev.of_node = node; + rpdev->dev.parent = &glink->dev; + rpdev->dev.release = glink_spi_rpdev_release; + + ret = rpmsg_register_device(rpdev); + if (ret) + goto free_rpdev; + + channel->rpdev = rpdev; + } + CH_INFO(channel, "\n"); + + return 0; + +free_rpdev: + CH_INFO(channel, "free_rpdev\n"); + kfree(rpdev); +rcid_remove: + CH_INFO(channel, "rcid_remove\n"); + spin_lock_irqsave(&glink->idr_lock, flags); + idr_remove(&glink->rcids, channel->rcid); + channel->rcid = 0; + spin_unlock_irqrestore(&glink->idr_lock, flags); +free_channel: + CH_INFO(channel, "free_channel\n"); + /* Release the reference, iff we took it */ + if (create_device) + kref_put(&channel->refcount, glink_spi_channel_release); + + return ret; +} + +static int glink_spi_rx_data(struct glink_spi *glink, + unsigned int rcid, unsigned int liid, + void *rx_data, size_t avail) +{ + struct glink_core_rx_intent *intent; + struct glink_channel *channel; + struct data_desc { + __le32 chunk_size; + __le32 left_size; + __le64 addr; + }; + struct data_desc *hdr; + unsigned int chunk_size; + unsigned int left_size; + u32 addr; + size_t msglen; + unsigned long flags; + + msglen = sizeof(*hdr); + if (avail < msglen) { + dev_dbg(&glink->dev, "Not enough data in fifo\n"); + return avail; + } + hdr = (struct data_desc *)rx_data; + + chunk_size = le32_to_cpu(hdr->chunk_size); + left_size = le32_to_cpu(hdr->left_size); + addr = (u32)le64_to_cpu(hdr->addr); + + spin_lock_irqsave(&glink->idr_lock, flags); + channel = idr_find(&glink->rcids, rcid); + spin_unlock_irqrestore(&glink->idr_lock, flags); + if (!channel) { + dev_dbg(&glink->dev, "Data on non-existing channel\n"); + return msglen; + } + CH_INFO(channel, "chunk_size:%d left_size:%d\n", chunk_size, left_size); + + spin_lock_irqsave(&channel->intent_lock, flags); + intent = idr_find(&channel->liids, liid); + spin_unlock_irqrestore(&channel->intent_lock, flags); + + if (!intent) { + dev_err(&glink->dev, + "no intent found for channel %s intent %d", + channel->name, liid); + return msglen; + } + + if (intent->size - intent->offset < chunk_size) { + dev_err(&glink->dev, "Insufficient space in intent\n"); + + /* The packet header lied, drop payload */ + return msglen; + } + + /* Read message from addr sent by WDSP */ + glink_spi_read(glink, addr, intent->data + intent->offset, chunk_size); + intent->offset += chunk_size; + + /* Handle message when no fragments remain to be received */ + if (!left_size) { + spin_lock(&channel->recv_lock); + if (channel->ept.cb) { + channel->ept.cb(channel->ept.rpdev, + intent->data, + intent->offset, + channel->ept.priv, + RPMSG_ADDR_ANY); + } + spin_unlock(&channel->recv_lock); + + intent->offset = 0; + channel->buf = NULL; + + glink_spi_rx_done(glink, channel, intent); + } + return msglen; +} + +static int glink_spi_rx_short_data(struct glink_spi *glink, + unsigned int rcid, unsigned int liid, + unsigned int chunk_size, + unsigned int left_size, + void *src, size_t avail) +{ + struct glink_core_rx_intent *intent; + struct glink_channel *channel; + size_t msglen = SHORT_PKT_SIZE; + unsigned long flags; + + if (avail < msglen) { + dev_dbg(&glink->dev, "Not enough data in fifo\n"); + return avail; + } + spin_lock_irqsave(&glink->idr_lock, flags); + channel = idr_find(&glink->rcids, rcid); + spin_unlock_irqrestore(&glink->idr_lock, flags); + if (!channel) { + dev_dbg(&glink->dev, "Data on non-existing channel\n"); + return msglen; + } + CH_INFO(channel, "chunk_size:%d left_size:%d\n", chunk_size, left_size); + + spin_lock_irqsave(&channel->intent_lock, flags); + intent = idr_find(&channel->liids, liid); + spin_unlock_irqrestore(&channel->intent_lock, flags); + + if (!intent) { + dev_err(&glink->dev, + "no intent found for channel %s intent %d", + channel->name, liid); + return msglen; + } + + if (intent->size - intent->offset < chunk_size) { + dev_err(&glink->dev, "Insufficient space in intent\n"); + + /* The packet header lied, drop payload */ + return msglen; + } + + /* Read message from addr sent by WDSP */ + memcpy(intent->data + intent->offset, src, chunk_size); + intent->offset += chunk_size; + + /* Handle message when no fragments remain to be received */ + if (!left_size) { + spin_lock(&channel->recv_lock); + if (channel->ept.cb) { + channel->ept.cb(channel->ept.rpdev, + intent->data, + intent->offset, + channel->ept.priv, + RPMSG_ADDR_ANY); + } + spin_unlock(&channel->recv_lock); + + intent->offset = 0; + channel->buf = NULL; + + glink_spi_rx_done(glink, channel, intent); + } + return msglen; +} + +static void glink_spi_defer_work(struct work_struct *work) +{ + struct glink_spi *glink = container_of(work, struct glink_spi, + rx_defer_work); + + struct glink_defer_cmd *dcmd; + struct glink_msg *msg; + unsigned long flags; + unsigned int param1; + unsigned int param2; + unsigned int param3; + unsigned int param4; + unsigned int cmd; + + for (;;) { + spin_lock_irqsave(&glink->rx_lock, flags); + if (list_empty(&glink->rx_queue)) { + spin_unlock_irqrestore(&glink->rx_lock, flags); + break; + } + dcmd = list_first_entry(&glink->rx_queue, + struct glink_defer_cmd, node); + list_del(&dcmd->node); + spin_unlock_irqrestore(&glink->rx_lock, flags); + + msg = &dcmd->msg; + cmd = le16_to_cpu(msg->cmd); + param1 = le16_to_cpu(msg->param1); + param2 = le32_to_cpu(msg->param2); + param3 = le32_to_cpu(msg->param3); + param4 = le32_to_cpu(msg->param4); + + switch (cmd) { + case SPI_CMD_OPEN: + glink_spi_rx_open(glink, param1, msg->data); + break; + case SPI_CMD_CLOSE: + glink_spi_rx_close(glink, param1); + break; + case SPI_CMD_CLOSE_ACK: + glink_spi_rx_close_ack(glink, param1); + break; + default: + WARN(1, "Unknown defer object %d\n", cmd); + break; + } + + kfree(dcmd); + } +} + +static int glink_spi_rx_defer(struct glink_spi *glink, + void *rx_data, u32 rx_avail, size_t extra) +{ + struct glink_defer_cmd *dcmd; + + extra = ALIGN(extra, SPI_ALIGNMENT); + + if (rx_avail < sizeof(struct glink_msg) + extra) { + dev_dbg(&glink->dev, "Insufficient data in rx fifo"); + return -ENXIO; + } + + dcmd = kzalloc(sizeof(*dcmd) + extra, GFP_KERNEL); + if (!dcmd) + return -ENOMEM; + + INIT_LIST_HEAD(&dcmd->node); + + memcpy(&dcmd->msg, rx_data, sizeof(dcmd->msg) + extra); + + spin_lock(&glink->rx_lock); + list_add_tail(&dcmd->node, &glink->rx_queue); + spin_unlock(&glink->rx_lock); + + schedule_work(&glink->rx_defer_work); + + return 0; +} + +static void glink_spi_process_cmd(struct glink_spi *glink, void *rx_data, + u32 rx_size) +{ + struct glink_msg *msg; + unsigned int param1; + unsigned int param2; + unsigned int param3; + unsigned int param4; + unsigned int cmd; + int offset = 0; + int ret; + u16 name_len; + char *name; + + while (offset < rx_size) { + msg = (struct glink_msg *)(rx_data + offset); + offset += sizeof(*msg); + + cmd = le16_to_cpu(msg->cmd); + param1 = le16_to_cpu(msg->param1); + param2 = le32_to_cpu(msg->param2); + param3 = le32_to_cpu(msg->param3); + param4 = le32_to_cpu(msg->param4); + + switch (cmd) { + case SPI_CMD_VERSION: + if (param3) { + glink->rx_pipe.length = param3; + glink->tx_pipe.length = param3; + } + glink_spi_receive_version(glink, param1, param2); + break; + case SPI_CMD_VERSION_ACK: + glink_spi_receive_version_ack(glink, param1, param2); + break; + case SPI_CMD_CLOSE: + case SPI_CMD_CLOSE_ACK: + glink_spi_rx_defer(glink, + rx_data + offset - sizeof(*msg), + rx_size + offset - sizeof(*msg), 0); + break; + case SPI_CMD_RX_INTENT_REQ: + glink_spi_handle_intent_req(glink, param1, param2); + break; + case SPI_CMD_OPEN_ACK: + ret = glink_spi_rx_open_ack(glink, param1); + break; + case SPI_CMD_OPEN: + name_len = (u16)(param2 & 0xFFFF); + name = rx_data + offset; + glink_spi_rx_defer(glink, + rx_data + offset - sizeof(*msg), + rx_size + offset - sizeof(*msg), + ALIGN(name_len, SPI_ALIGNMENT)); + + offset += ALIGN(name_len, SPI_ALIGNMENT); + break; + case SPI_CMD_TX_DATA: + case SPI_CMD_TX_DATA_CONT: + ret = glink_spi_rx_data(glink, param1, param2, + rx_data + offset, + rx_size - offset); + offset += ALIGN(ret, SPI_ALIGNMENT); + break; + case SPI_CMD_TX_SHORT_DATA: + ret = glink_spi_rx_short_data(glink, + param1, param2, + param3, param4, + rx_data + offset, + rx_size - offset); + offset += ALIGN(ret, SPI_ALIGNMENT); + break; + case SPI_CMD_READ_NOTIF: + break; + case SPI_CMD_INTENT: + ret = glink_spi_handle_intent(glink, + param1, param2, + rx_data + offset, + rx_size - offset); + offset += ALIGN(ret, SPI_ALIGNMENT); + break; + case SPI_CMD_RX_DONE: + glink_spi_handle_rx_done(glink, param1, param2, false); + break; + case SPI_CMD_RX_DONE_W_REUSE: + glink_spi_handle_rx_done(glink, param1, param2, true); + break; + case SPI_CMD_RX_INTENT_REQ_ACK: + glink_spi_handle_intent_req_ack(glink, param1, param2); + break; + case SPI_CMD_SIGNALS: + glink_spi_handle_signals(glink, param1, param2); + break; + default: + dev_err(&glink->dev, "unhandled rx cmd: %d\n", cmd); + break; + } + } +} + +static void glink_spi_work(struct kthread_work *work) +{ + struct glink_spi *glink = container_of(work, struct glink_spi, + rx_work); + u32 inactive_cycles = 0; + u32 rx_avail; + void *rx_data; + + glink_spi_xprt_set_poll_mode(glink); + do { + rx_avail = glink_spi_rx_avail(glink); + if (!rx_avail) { + usleep_range(POLL_INTERVAL_US, POLL_INTERVAL_US + 50); + inactive_cycles++; + continue; + } + inactive_cycles = 0; + + rx_data = kzalloc(rx_avail, GFP_KERNEL); + if (!rx_data) + break; + + glink_spi_rx_peak(glink, rx_data, 0, rx_avail); + glink_spi_process_cmd(glink, rx_data, rx_avail); + kfree(rx_data); + glink_spi_rx_advance(glink, rx_avail); + + } while (inactive_cycles < MAX_INACTIVE_CYCLES && !glink->in_reset); + glink_spi_xprt_set_irq_mode(glink); +} + +static int glink_spi_cmpnt_init(struct device *dev, void *priv) +{ + return 0; +} + +static int glink_spi_cmpnt_deinit(struct device *dev, void *priv) +{ + return 0; +} + +static int glink_spi_cmpnt_event_handler(struct device *dev, void *priv, + enum wdsp_event_type event, + void *data) +{ + struct glink_spi *glink = dev_get_drvdata(dev); + struct glink_cmpnt *cmpnt = &glink->cmpnt; + int ret; + + switch (event) { + case WDSP_EVENT_PRE_BOOTUP: + if (!cmpnt || !cmpnt->master_dev || !cmpnt->master_ops || + !cmpnt->master_ops->get_devops_for_cmpnt) + break; + + ret = cmpnt->master_ops->get_devops_for_cmpnt(cmpnt->master_dev, + WDSP_CMPNT_TRANSPORT, &glink->spi_ops); + if (ret) + GLINK_ERR(glink, "Failed to get transport device\n"); + break; + case WDSP_EVENT_POST_BOOTUP: + glink->in_reset = false; + ret = glink_spi_send_version(glink); + if (ret) + GLINK_ERR(glink, "failed to send version %d\n", ret); + + /* FALLTHROUGH */ + case WDSP_EVENT_IPC1_INTR: + kthread_queue_work(&glink->rx_worker, &glink->rx_work); + break; + case WDSP_EVENT_PRE_SHUTDOWN: + glink_spi_remove(glink); + break; + case WDSP_EVENT_RESUME: + break; + case WDSP_EVENT_SUSPEND: + break; + default: + GLINK_INFO(glink, "unhandled event %d", event); + break; + } + + return 0; +} + +/* glink_spi_cmpnt_ops - Callback operations registered wtih wdsp framework */ +static struct wdsp_cmpnt_ops glink_spi_cmpnt_ops = { + .init = glink_spi_cmpnt_init, + .deinit = glink_spi_cmpnt_deinit, + .event_handler = glink_spi_cmpnt_event_handler, +}; + +static int glink_component_bind(struct device *dev, struct device *master, + void *data) +{ + struct glink_spi *glink = dev_get_drvdata(dev); + struct glink_cmpnt *cmpnt = &glink->cmpnt; + int ret = 0; + + cmpnt->master_dev = master; + cmpnt->master_ops = data; + + if (cmpnt->master_ops && cmpnt->master_ops->register_cmpnt_ops) + ret = cmpnt->master_ops->register_cmpnt_ops(master, dev, glink, + &glink_spi_cmpnt_ops); + else + ret = -EINVAL; + + if (ret) + dev_err(dev, "%s: register_cmpnt_ops failed, err = %d\n", + __func__, ret); + return ret; +} + +static void glink_component_unbind(struct device *dev, struct device *master, + void *data) +{ + struct glink_spi *glink = dev_get_drvdata(dev); + struct glink_cmpnt *cmpnt = &glink->cmpnt; + + cmpnt->master_dev = NULL; + cmpnt->master_ops = NULL; +} + +static const struct component_ops glink_component_ops = { + .bind = glink_component_bind, + .unbind = glink_component_unbind, +}; + +static int glink_spi_init_pipe(const char *key, struct device_node *node, + struct glink_spi_pipe *pipe) +{ + const struct property *prop = NULL; + __be32 *addrs; + + prop = of_find_property(node, key, NULL); + if (!prop) { + pr_err("%s failed to find prop %s", __func__, key); + return -ENODEV; + } + + if ((prop->length / sizeof(u32)) != 2) { + pr_err("%s %s wrong length %d", __func__, key, prop->length); + return -EINVAL; + } + addrs = prop->value; + + pipe->tail_addr = be32_to_cpup(addrs++); + pipe->head_addr = be32_to_cpup(addrs++); + pipe->length = DEFAULT_FIFO_SIZE; + + return 0; +} + +static void glink_spi_release(struct device *dev) +{ + struct glink_spi *glink = container_of(dev, struct glink_spi, dev); + + kfree(glink); +} + +struct glink_spi *qcom_glink_spi_register(struct device *parent, + struct device_node *node) +{ + struct glink_spi *glink; + struct device *dev; + int ret; + + glink = kzalloc(sizeof(*glink), GFP_KERNEL); + if (!glink) + return ERR_PTR(-ENOMEM); + + dev = &glink->dev; + dev->parent = parent; + dev->of_node = node; + dev->release = glink_spi_release; + dev_set_name(dev, "%s:%s", node->parent->name, node->name); + ret = device_register(dev); + if (ret) { + pr_err("failed to register glink edge\n"); + return ERR_PTR(ret); + } + dev_set_drvdata(dev, glink); + + ret = of_property_read_string(dev->of_node, "label", &glink->name); + if (ret < 0) + glink->name = dev->of_node->name; + + glink->features = GLINK_FEATURE_INTENT_REUSE; + glink->intentless = false; + + mutex_init(&glink->tx_lock); + spin_lock_init(&glink->rx_lock); + INIT_LIST_HEAD(&glink->rx_queue); + INIT_WORK(&glink->rx_defer_work, glink_spi_defer_work); + + kthread_init_work(&glink->rx_work, glink_spi_work); + kthread_init_worker(&glink->rx_worker); + + spin_lock_init(&glink->idr_lock); + idr_init(&glink->lcids); + idr_init(&glink->rcids); + + glink->in_reset = true; + glink->activity_flag = 0; + spin_lock_init(&glink->activity_lock); + + ret = glink_spi_init_pipe("tx-descriptors", node, &glink->tx_pipe); + if (ret) + goto err_put_dev; + + ret = glink_spi_init_pipe("rx-descriptors", node, &glink->rx_pipe); + if (ret) + goto err_put_dev; + + ret = component_add(dev, &glink_component_ops); + if (ret) { + dev_err(dev, "component_add failed, err = %d\n", ret); + goto err_put_dev; + } + + glink->ilc = ipc_log_context_create(GLINK_LOG_PAGE_CNT, glink->name, 0); + + glink->rx_task = kthread_run(kthread_worker_fn, &glink->rx_worker, + "spi_%s", glink->name); + if (IS_ERR(glink->rx_task)) { + ret = PTR_ERR(glink->rx_task); + dev_err(dev, "kthread run failed %d\n", ret); + goto err_put_dev; + } + + return glink; + +err_put_dev: + dev_set_drvdata(dev, NULL); + put_device(dev); + + return ERR_PTR(ret); +} +EXPORT_SYMBOL(qcom_glink_spi_register); + +static int glink_spi_remove_device(struct device *dev, void *data) +{ + device_unregister(dev); + + return 0; +} + +static void glink_spi_remove(struct glink_spi *glink) +{ + struct glink_spi_pipe *rx_pipe = &glink->rx_pipe; + struct glink_spi_pipe *tx_pipe = &glink->tx_pipe; + struct glink_channel *channel; + int cid; + int ret; + unsigned long flags; + + GLINK_INFO(glink, "\n"); + + glink->in_reset = true; + + ret = device_for_each_child(&glink->dev, NULL, glink_spi_remove_device); + if (ret) + dev_warn(&glink->dev, "Can't remove GLINK devices: %d\n", ret); + + spin_lock_irqsave(&glink->idr_lock, flags); + /* Release any defunct local channels, waiting for close-ack */ + idr_for_each_entry(&glink->lcids, channel, cid) + kref_put(&channel->refcount, glink_spi_channel_release); + + /* Release any defunct local channels, waiting for close-req */ + idr_for_each_entry(&glink->lcids, channel, cid) + kref_put(&channel->refcount, glink_spi_channel_release); + + idr_destroy(&glink->lcids); + idr_destroy(&glink->rcids); + spin_unlock_irqrestore(&glink->idr_lock, flags); + + tx_pipe->fifo_base = 0; + tx_pipe->local_addr = 0; + tx_pipe->length = DEFAULT_FIFO_SIZE; + + rx_pipe->fifo_base = 0; + rx_pipe->local_addr = 0; + rx_pipe->length = DEFAULT_FIFO_SIZE; +} + +void qcom_glink_spi_unregister(struct glink_spi *glink) +{ + device_unregister(&glink->dev); +} +EXPORT_SYMBOL(qcom_glink_spi_unregister); + +MODULE_DESCRIPTION("QTI GLINK SPI Transport"); +MODULE_LICENSE("GPL v2"); diff --git a/include/linux/rpmsg/qcom_glink.h b/include/linux/rpmsg/qcom_glink.h index 8c0b65908877..7de68ce767d6 100644 --- a/include/linux/rpmsg/qcom_glink.h +++ b/include/linux/rpmsg/qcom_glink.h @@ -4,6 +4,7 @@ #include struct qcom_glink; +struct glink_spi; #if IS_ENABLED(CONFIG_RPMSG_QCOM_GLINK_SMEM) @@ -44,4 +45,24 @@ static inline void qcom_glink_spss_unregister(struct qcom_glink *glink) {} #endif + +#if IS_ENABLED(CONFIG_RPMSG_QCOM_GLINK_SPI) + +struct glink_spi *qcom_glink_spi_register(struct device *parent, + struct device_node *node); +void qcom_glink_spi_unregister(struct glink_spi *glink); + +#else + +static inline struct glink_spi * +qcom_glink_spi_register(struct device *parent, struct device_node *node) +{ + return NULL; +} + +static inline void qcom_glink_spi_unregister(struct glink_spi *glink) {} + +#endif + + #endif -- GitLab From 308ef5aa3c9e98581fb78daaa7d1d4b04583cd88 Mon Sep 17 00:00:00 2001 From: Pavankumar Kondeti Date: Fri, 23 Mar 2018 08:10:20 +0530 Subject: [PATCH 0804/1635] sched/fair: Consider an idle CPU outside c-state as an active CPU The find_best_target() selects an active CPU and an idle CPU as two candidate CPUs. Whichever CPUs saves the most energy compared to the previous CPU is selected finally. An idle CPU i.e no runnable tasks but also outside c-state is a good candidate to run the waking task since the task can run immediately and there is no idle exit latency. Hence consider such CPU as an active CPU which helps both power and performance. Change-Id: I34f40c2dbca70995a8e6b4a8d5876f802bc000bc Signed-off-by: Pavankumar Kondeti [satyap@codeaurora.org: Bring in is_packing_eligible functionality from msm-4.9 to check whether packing can be done or not as part of dependency] Signed-off-by: Satya Durga Srinivasu Prabhala --- kernel/sched/core.c | 2 ++ kernel/sched/fair.c | 44 +++++++++++++++++++++++++++++++++++++++----- 2 files changed, 41 insertions(+), 5 deletions(-) diff --git a/kernel/sched/core.c b/kernel/sched/core.c index abaf2bfa483c..76414c203238 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -3118,6 +3118,8 @@ unsigned long long task_sched_runtime(struct task_struct *p) return ns; } +unsigned int capacity_margin_freq = 1280; /* ~20% margin */ + /* * This function gets called by the timer code, with HZ frequency. * We call it with interrupts disabled. diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index 210977130d09..1de8802adb4f 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -7003,6 +7003,38 @@ struct find_best_target_env { bool need_idle; }; +static bool is_packing_eligible(struct task_struct *p, int target_cpu, + struct find_best_target_env *fbt_env, + unsigned int target_cpus_count, + int best_idle_cstate) +{ + unsigned long tutil, estimated_capacity; + + if (fbt_env->placement_boost || fbt_env->need_idle) + return false; + + if (best_idle_cstate == -1) + return false; + + if (target_cpus_count != 1) + return true; + + if (task_in_cum_window_demand(cpu_rq(target_cpu), p)) + tutil = 0; + else + tutil = task_util(p); + + estimated_capacity = cpu_util_cum(target_cpu, tutil); + estimated_capacity = add_capacity_margin(estimated_capacity, + target_cpu); + + /* + * If there is only one active CPU and it is already above its current + * capacity, avoid placing additional task on the CPU. + */ + return (estimated_capacity <= capacity_curr_of(target_cpu)); +} + static inline bool skip_sg(struct task_struct *p, struct sched_group *sg, struct cpumask *rtg_target) { @@ -7047,6 +7079,7 @@ static inline int find_best_target(struct task_struct *p, int *backup_cpu, int target_cpu = -1; int cpu, i; unsigned long spare_cap; + unsigned int active_cpus_count = 0; *backup_cpu = -1; @@ -7270,6 +7303,8 @@ static inline int find_best_target(struct task_struct *p, int *backup_cpu, * capacity. */ + active_cpus_count++; + /* Favor CPUs with maximum spare capacity */ if ((capacity_orig - new_util) < target_max_spare_cap) continue; @@ -7290,11 +7325,10 @@ static inline int find_best_target(struct task_struct *p, int *backup_cpu, } while (sg = sg->next, sg != sd->groups); - if (fbt_env->need_idle || fbt_env->placement_boost) { - if (best_idle_cpu != -1) { - target_cpu = best_idle_cpu; - best_idle_cpu = -1; - } + if (best_idle_cpu != -1 && !is_packing_eligible(p, target_cpu, fbt_env, + active_cpus_count, best_idle_cstate)) { + target_cpu = best_idle_cpu; + best_idle_cpu = -1; } /* -- GitLab From b1fe44b6f43cbd8f6c430c6cd38c42c3a75dc6ed Mon Sep 17 00:00:00 2001 From: Sreelakshmi Gownipalli Date: Mon, 23 Apr 2018 13:41:14 -0700 Subject: [PATCH 0805/1635] diag: Add new Diag IDs Update to latest diag IDs Change-Id: I57a25f570484f2cd8255275015ca2c70294a78fb Signed-off-by: Sreelakshmi Gownipalli --- include/linux/diagchar.h | 52 ++++++++++++++++++++++------------------ 1 file changed, 29 insertions(+), 23 deletions(-) diff --git a/include/linux/diagchar.h b/include/linux/diagchar.h index 95fe2397315f..3c7ec2264935 100644 --- a/include/linux/diagchar.h +++ b/include/linux/diagchar.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2008-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -146,10 +146,10 @@ * a new RANGE of SSIDs to the msg_mask_tbl. */ #define MSG_MASK_TBL_CNT 26 -#define APPS_EVENT_LAST_ID 0x0B3F +#define APPS_EVENT_LAST_ID 0x0C5A #define MSG_SSID_0 0 -#define MSG_SSID_0_LAST 121 +#define MSG_SSID_0_LAST 125 #define MSG_SSID_1 500 #define MSG_SSID_1_LAST 506 #define MSG_SSID_2 1000 @@ -161,11 +161,11 @@ #define MSG_SSID_5 4000 #define MSG_SSID_5_LAST 4010 #define MSG_SSID_6 4500 -#define MSG_SSID_6_LAST 4583 +#define MSG_SSID_6_LAST 4584 #define MSG_SSID_7 4600 -#define MSG_SSID_7_LAST 4615 +#define MSG_SSID_7_LAST 4616 #define MSG_SSID_8 5000 -#define MSG_SSID_8_LAST 5033 +#define MSG_SSID_8_LAST 5034 #define MSG_SSID_9 5500 #define MSG_SSID_9_LAST 5516 #define MSG_SSID_10 6000 @@ -265,7 +265,7 @@ static const uint32_t msg_bld_masks_0[] = { MSG_MASK_9 | MSG_MASK_10, MSG_LVL_MED, MSG_LVL_LOW, - MSG_LVL_LOW, + MSG_LVL_MED, MSG_LVL_MED, MSG_LVL_LOW, MSG_LVL_LOW, @@ -319,7 +319,7 @@ static const uint32_t msg_bld_masks_0[] = { MSG_LVL_FATAL, MSG_LVL_MED, MSG_LVL_HIGH, - MSG_LVL_LOW, + MSG_LVL_MED, MSG_LVL_HIGH, MSG_LVL_LOW | MSG_LVL_MED | MSG_LVL_HIGH | MSG_LVL_ERROR | MSG_LVL_FATAL, @@ -497,6 +497,7 @@ static const uint32_t msg_bld_masks_6[] = { MSG_LVL_LOW, MSG_LVL_LOW, MSG_LVL_LOW, + MSG_LVL_LOW, MSG_LVL_LOW }; @@ -516,7 +517,9 @@ static const uint32_t msg_bld_masks_7[] = { MSG_LVL_LOW, MSG_LVL_LOW, MSG_LVL_LOW, - MSG_LVL_LOW | MSG_LVL_MED | MSG_LVL_HIGH | MSG_LVL_ERROR | MSG_LVL_FATAL + MSG_LVL_LOW | MSG_LVL_MED | MSG_LVL_HIGH | MSG_LVL_ERROR | + MSG_LVL_FATAL, + MSG_LVL_LOW }; static const uint32_t msg_bld_masks_8[] = { @@ -536,9 +539,6 @@ static const uint32_t msg_bld_masks_8[] = { MSG_LVL_MED, MSG_LVL_MED, MSG_LVL_MED, - MSG_LVL_LOW, - MSG_LVL_LOW, - MSG_LVL_LOW, MSG_LVL_MED, MSG_LVL_MED, MSG_LVL_MED, @@ -553,6 +553,10 @@ static const uint32_t msg_bld_masks_8[] = { MSG_LVL_MED, MSG_LVL_MED, MSG_LVL_MED, + MSG_LVL_MED, + MSG_LVL_MED, + MSG_LVL_MED, + MSG_LVL_HIGH, MSG_LVL_HIGH }; @@ -655,14 +659,14 @@ static const uint32_t msg_bld_masks_10[] = { MSG_LVL_MED, MSG_LVL_MED, MSG_LVL_LOW, - MSG_LVL_LOW, - MSG_LVL_LOW, - MSG_LVL_LOW, - MSG_LVL_LOW, - MSG_LVL_LOW, - MSG_LVL_LOW, - MSG_LVL_LOW, - MSG_LVL_LOW, + MSG_LVL_MED, + MSG_LVL_MED, + MSG_LVL_MED, + MSG_LVL_MED, + MSG_LVL_MED, + MSG_LVL_MED, + MSG_LVL_MED, + MSG_LVL_MED, MSG_LVL_MED }; @@ -812,7 +816,9 @@ static const uint32_t msg_bld_masks_19[] = { }; static const uint32_t msg_bld_masks_20[] = { - MSG_LVL_LOW, + MSG_LVL_LOW | MSG_MASK_5 | MSG_MASK_6 | MSG_MASK_7 | + MSG_MASK_8 | MSG_MASK_9 | MSG_MASK_10 | MSG_MASK_11 | + MSG_MASK_12, MSG_LVL_LOW, MSG_LVL_LOW, MSG_LVL_LOW, @@ -890,7 +896,7 @@ static const uint32_t msg_bld_masks_25[] = { /* LOG CODES */ static const uint32_t log_code_last_tbl[] = { 0x0, /* EQUIP ID 0 */ - 0x1A11, /* EQUIP ID 1 */ + 0x1C68, /* EQUIP ID 1 */ 0x0, /* EQUIP ID 2 */ 0x0, /* EQUIP ID 3 */ 0x4910, /* EQUIP ID 4 */ @@ -900,7 +906,7 @@ static const uint32_t log_code_last_tbl[] = { 0x0, /* EQUIP ID 8 */ 0x0, /* EQUIP ID 9 */ 0xA38A, /* EQUIP ID 10 */ - 0xB201, /* EQUIP ID 11 */ + 0xB9FF, /* EQUIP ID 11 */ 0x0, /* EQUIP ID 12 */ 0xD1FF, /* EQUIP ID 13 */ 0x0, /* EQUIP ID 14 */ -- GitLab From eac9d4d393534408b96428cdee19fff49a5abbb2 Mon Sep 17 00:00:00 2001 From: Vikram Mulukutla Date: Tue, 30 May 2017 14:38:55 -0700 Subject: [PATCH 0806/1635] sched: walt: Optimize cycle counter reads The cycle counter read is a bit of an expensive operation and requires locking across all CPUs in a frequency domain. Optimize this by returning the same value if the delta between two reads is zero i.e two reads are done in the same sched context for the same CPU. Change-Id: I99da5a704d3652f53c8564ba7532783d3288f227 Signed-off-by: Vikram Mulukutla [pkondeti@codeaurora.org: limit the optimization to the same CPU for the sched context] Signed-off-by: Pavankumar Kondeti Signed-off-by: Satya Durga Srinivasu Prabhala --- kernel/sched/sched.h | 2 ++ kernel/sched/walt.c | 33 ++++++++++++++++++++++++++------- 2 files changed, 28 insertions(+), 7 deletions(-) diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h index c3661044a33c..3d19b937d0f1 100644 --- a/kernel/sched/sched.h +++ b/kernel/sched/sched.h @@ -877,6 +877,8 @@ struct rq { int prev_top; int curr_top; bool notif_pending; + u64 last_cc_update; + u64 cycles; #endif /* CONFIG_SCHED_WALT */ #ifdef CONFIG_IRQ_TIME_ACCOUNTING diff --git a/kernel/sched/walt.c b/kernel/sched/walt.c index 7c016b598e82..bec6aef86664 100644 --- a/kernel/sched/walt.c +++ b/kernel/sched/walt.c @@ -291,10 +291,27 @@ update_window_start(struct rq *rq, u64 wallclock, int event) return old_window_start; } -static void update_task_cpu_cycles(struct task_struct *p, int cpu) +/* + * Assumes rq_lock is held and wallclock was recorded in the same critical + * section as this function's invocation. + */ +static inline u64 read_cycle_counter(int cpu, u64 wallclock) +{ + struct rq *rq = cpu_rq(cpu); + + if (rq->last_cc_update != wallclock) { + rq->cycles = cpu_cycle_counter_cb.get_cpu_cycle_counter(cpu); + rq->last_cc_update = wallclock; + } + + return rq->cycles; +} + +static void update_task_cpu_cycles(struct task_struct *p, int cpu, + u64 wallclock) { if (use_cycle_counter) - p->cpu_cycles = cpu_cycle_counter_cb.get_cpu_cycle_counter(cpu); + p->cpu_cycles = read_cycle_counter(cpu, wallclock); } void clear_ed_task(struct task_struct *p, struct rq *rq) @@ -338,7 +355,7 @@ void sched_account_irqstart(int cpu, struct task_struct *curr, u64 wallclock) if (is_idle_task(curr)) { /* We're here without rq->lock held, IRQ disabled */ raw_spin_lock(&rq->lock); - update_task_cpu_cycles(curr, cpu); + update_task_cpu_cycles(curr, cpu, ktime_get_ns()); raw_spin_unlock(&rq->lock); } } @@ -747,7 +764,7 @@ void fixup_busy_time(struct task_struct *p, int new_cpu) update_task_ravg(p, task_rq(p), TASK_MIGRATE, wallclock, 0); - update_task_cpu_cycles(p, new_cpu); + update_task_cpu_cycles(p, new_cpu, wallclock); /* * When a task is migrating during the wakeup, adjust @@ -1831,7 +1848,7 @@ update_task_rq_cpu_cycles(struct task_struct *p, struct rq *rq, int event, return; } - cur_cycles = cpu_cycle_counter_cb.get_cpu_cycle_counter(cpu); + cur_cycles = read_cycle_counter(cpu, wallclock); /* * If current task is idle task and irqtime == 0 CPU was @@ -1896,7 +1913,7 @@ void update_task_ravg(struct task_struct *p, struct rq *rq, int event, old_window_start = update_window_start(rq, wallclock, event); if (!p->ravg.mark_start) { - update_task_cpu_cycles(p, cpu_of(rq)); + update_task_cpu_cycles(p, cpu_of(rq), wallclock); goto done; } @@ -2019,7 +2036,7 @@ void mark_task_starting(struct task_struct *p) p->ravg.mark_start = p->last_wake_ts = wallclock; p->last_enqueued_ts = wallclock; p->last_switch_out_ts = 0; - update_task_cpu_cycles(p, cpu_of(rq)); + update_task_cpu_cycles(p, cpu_of(rq), wallclock); } static cpumask_t all_cluster_cpus = CPU_MASK_NONE; @@ -3203,6 +3220,8 @@ void walt_sched_init(struct rq *rq) rq->curr_table = 0; rq->prev_top = 0; rq->curr_top = 0; + rq->last_cc_update = 0; + rq->cycles = 0; for (j = 0; j < NUM_TRACKED_WINDOWS; j++) { memset(&rq->load_subs[j], 0, sizeof(struct load_subtractions)); -- GitLab From d660893f951541059d238b8ec734dd972514b645 Mon Sep 17 00:00:00 2001 From: Pavankumar Kondeti Date: Fri, 23 Mar 2018 11:15:21 +0530 Subject: [PATCH 0807/1635] sched/fair: Add bias towards previous CPU for high wakeup rate tasks Skip the CPU selection algorithm for high wakeup rate tasks and select the previous CPU if it is idle. Change-Id: I99493c8c37e091c79723ee22a5230fbb6f4e33b9 Signed-off-by: Pavankumar Kondeti Signed-off-by: Satya Durga Srinivasu Prabhala --- include/linux/sched.h | 1 + kernel/sched/core.c | 2 ++ kernel/sched/fair.c | 36 ++++++++++++++++++++++++++++++++++++ 3 files changed, 39 insertions(+) diff --git a/include/linux/sched.h b/include/linux/sched.h index cf124ba4a03c..15fc9e3c0691 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -705,6 +705,7 @@ struct task_struct { struct sched_entity se; struct sched_rt_entity rt; u64 last_sleep_ts; + u64 last_cpu_selected_ts; #ifdef CONFIG_SCHED_WALT struct ravg ravg; /* diff --git a/kernel/sched/core.c b/kernel/sched/core.c index 76414c203238..a4ac7249c842 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -2276,6 +2276,8 @@ static void __sched_fork(unsigned long clone_flags, struct task_struct *p) p->se.nr_migrations = 0; p->se.vruntime = 0; p->last_sleep_ts = 0; + p->last_cpu_selected_ts = 0; + INIT_LIST_HEAD(&p->se.group_node); #ifdef CONFIG_FAIR_GROUP_SCHED diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index 1de8802adb4f..7059ad8fdd7a 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -7537,6 +7537,39 @@ static inline int wake_to_idle(struct task_struct *p) (p->flags & PF_WAKE_UP_IDLE); } +#define SCHED_SELECT_PREV_CPU_NSEC 2000000 +#define SCHED_FORCE_CPU_SELECTION_NSEC 20000000 + +static inline bool +bias_to_prev_cpu(struct task_struct *p, struct cpumask *rtg_target) +{ + int prev_cpu = task_cpu(p); +#ifdef CONFIG_SCHED_WALT + u64 ms = p->ravg.mark_start; +#else + u64 ms = sched_clock(); +#endif + + if (cpu_isolated(prev_cpu) || !idle_cpu(prev_cpu)) + return false; + + if (!ms) + return false; + + if (ms - p->last_cpu_selected_ts >= SCHED_SELECT_PREV_CPU_NSEC) { + p->last_cpu_selected_ts = ms; + return false; + } + + if (ms - p->last_sleep_ts >= SCHED_SELECT_PREV_CPU_NSEC) + return false; + + if (rtg_target && !cpumask_test_cpu(prev_cpu, rtg_target)) + return false; + + return true; +} + #ifdef CONFIG_SCHED_WALT static inline struct cpumask *find_rtg_target(struct task_struct *p) { @@ -7636,6 +7669,9 @@ static int find_energy_efficient_cpu(struct sched_domain *sd, prefer_idle = sched_feat(EAS_PREFER_IDLE) ? (schedtune_prefer_idle(p) > 0) : 0; + if (bias_to_prev_cpu(p, rtg_target)) + return prev_cpu; + eenv->max_cpu_count = EAS_CPU_BKP + 1; fbt_env.rtg_target = rtg_target; -- GitLab From 7fd5ffd1a6ed1d170fcd801c2edfac34d12915cb Mon Sep 17 00:00:00 2001 From: Narendra Muppalla Date: Fri, 14 Jul 2017 16:41:01 -0400 Subject: [PATCH 0808/1635] ARM: dts: msm: add dsc sim panels on sm8150 target This change adds single and dual dsi simulator command mode panels with 3.75:1 DSC configuration for various resolutions on sm8150 target. Change-Id: I02a2ed8a2229966baa99e7230ee489b2d704637d Signed-off-by: Narendra Muppalla --- arch/arm64/boot/dts/qcom/sm8150-cdp.dtsi | 12 ++++++++++++ arch/arm64/boot/dts/qcom/sm8150-mtp.dtsi | 12 ++++++++++++ arch/arm64/boot/dts/qcom/sm8150-sde-display.dtsi | 16 ++++++++-------- 3 files changed, 32 insertions(+), 8 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sm8150-cdp.dtsi b/arch/arm64/boot/dts/qcom/sm8150-cdp.dtsi index 570f3a6d8137..1ae284226bbc 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-cdp.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-cdp.dtsi @@ -156,6 +156,18 @@ qcom,platform-reset-gpio = <&tlmm 6 0>; }; +&dsi_sim_dsc_375_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,platform-reset-gpio = <&tlmm 6 0>; +}; + +&dsi_dual_sim_dsc_375_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,platform-reset-gpio = <&tlmm 6 0>; +}; + &dsi_nt35597_truly_dsc_cmd { qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; diff --git a/arch/arm64/boot/dts/qcom/sm8150-mtp.dtsi b/arch/arm64/boot/dts/qcom/sm8150-mtp.dtsi index 3607f5a38a32..81807fd15354 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-mtp.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-mtp.dtsi @@ -160,6 +160,18 @@ qcom,platform-reset-gpio = <&tlmm 6 0>; }; +&dsi_sim_dsc_375_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,platform-reset-gpio = <&tlmm 6 0>; +}; + +&dsi_dual_sim_dsc_375_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,platform-reset-gpio = <&tlmm 6 0>; +}; + &dsi_nt35597_truly_dsc_cmd { qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; diff --git a/arch/arm64/boot/dts/qcom/sm8150-sde-display.dtsi b/arch/arm64/boot/dts/qcom/sm8150-sde-display.dtsi index b3ffea9ae99b..b4f963e21562 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-sde-display.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-sde-display.dtsi @@ -580,14 +580,14 @@ qcom,mdss-dsi-t-clk-pre = <0x2d>; qcom,mdss-dsi-display-timings { timing@0 { /* 1080p */ - qcom,mdss-dsi-panel-phy-timings = [00 12 03 04 07 07 04 - 04 03 03 04 00 13 07]; + qcom,mdss-dsi-panel-phy-timings = [00 1A 06 06 22 20 07 + 07 04 03 04 00]; qcom,display-topology = <1 1 1>; qcom,default-topology-index = <0>; }; timing@1 { /* qhd */ - qcom,mdss-dsi-panel-phy-timings = [00 12 03 04 07 07 04 - 04 03 03 04 00 13 07]; + qcom,mdss-dsi-panel-phy-timings = [00 1A 06 06 22 20 07 + 07 04 03 04 00]; qcom,display-topology = <1 1 1>, <2 2 1>, /* dsc merge */ <2 1 1>; /* 3d mux */ @@ -601,14 +601,14 @@ qcom,mdss-dsi-t-clk-pre = <0x2d>; qcom,mdss-dsi-display-timings { timing@0 { /* qhd */ - qcom,mdss-dsi-panel-phy-timings = [00 13 03 03 05 06 03 - 03 02 03 04 00 10 06]; + qcom,mdss-dsi-panel-phy-timings = [00 1c 08 07 23 22 07 + 07 05 03 04 00 18 17]; qcom,display-topology = <2 2 2>; qcom,default-topology-index = <0>; }; timing@1 { /* 4k */ - qcom,mdss-dsi-panel-phy-timings = [00 13 03 03 05 06 03 - 03 02 03 04 00 10 06]; + qcom,mdss-dsi-panel-phy-timings = [00 1e 08 07 24 22 08 + 08 05 03 04 00 19 18]; qcom,display-topology = <2 2 2>; qcom,default-topology-index = <0>; }; -- GitLab From 35af866949e31deb659d420bfcf7c33a71bf1fc7 Mon Sep 17 00:00:00 2001 From: Tapas Kumar Kundu Date: Fri, 20 Apr 2018 16:42:11 -0700 Subject: [PATCH 0809/1635] msm: vidc: use declarations from upi header file Driver should directly use declarations from upi header file rather it duplicates into an internal file. Change-Id: If7b54df89300ffd7edc93c8a406483dd37a317c5 Signed-off-by: Tapas Kumar Kundu --- .../platform/msm/vidc/hfi_response_handler.c | 4 +- drivers/media/platform/msm/vidc/msm_venc.c | 8 +- drivers/media/platform/msm/vidc/msm_vidc.h | 375 +----------------- .../platform/msm/vidc/msm_vidc_internal.h | 2 +- .../media/platform/msm/vidc/vidc_hfi_api.h | 2 +- 5 files changed, 9 insertions(+), 382 deletions(-) diff --git a/drivers/media/platform/msm/vidc/hfi_response_handler.c b/drivers/media/platform/msm/vidc/hfi_response_handler.c index cc29a8f9704d..98b0de785294 100644 --- a/drivers/media/platform/msm/vidc/hfi_response_handler.c +++ b/drivers/media/platform/msm/vidc/hfi_response_handler.c @@ -93,7 +93,7 @@ static enum vidc_status hfi_map_err_status(u32 hfi_err) return vidc_err; } -static enum msm_vidc_pixel_depth get_hal_pixel_depth(u32 hfi_bit_depth) +static int get_hal_pixel_depth(u32 hfi_bit_depth) { switch (hfi_bit_depth) { case HFI_BITDEPTH_8: return MSM_VIDC_BIT_DEPTH_8; @@ -119,7 +119,7 @@ static int hfi_process_sess_evt_seq_changed(u32 device_id, u32 entropy_mode = 0; u8 *data_ptr; int prop_id; - enum msm_vidc_pixel_depth luma_bit_depth, chroma_bit_depth; + int luma_bit_depth, chroma_bit_depth; struct hfi_colour_space *colour_info; if (sizeof(struct hfi_msg_event_notify_packet) > pkt->size) { diff --git a/drivers/media/platform/msm/vidc/msm_venc.c b/drivers/media/platform/msm/vidc/msm_venc.c index 892dcbcb839a..188f4d8acc5f 100644 --- a/drivers/media/platform/msm/vidc/msm_venc.c +++ b/drivers/media/platform/msm/vidc/msm_venc.c @@ -2286,12 +2286,12 @@ int msm_venc_s_ext_ctrl(struct msm_vidc_inst *inst, control[i].value; break; case V4L2_CID_MPEG_VIDC_VENC_MAX_DISP_LUM: - mdisp_sei->nMaxDispMasteringLum = - control[i].value; + mdisp_sei->nMaxDisplayMasteringLuminance + = control[i].value; break; case V4L2_CID_MPEG_VIDC_VENC_MIN_DISP_LUM: - mdisp_sei->nMinDispMasteringLum = - control[i].value; + mdisp_sei->nMinDisplayMasteringLuminance + = control[i].value; break; case V4L2_CID_MPEG_VIDC_VENC_MAX_CLL: cll_sei->nMaxContentLight = diff --git a/drivers/media/platform/msm/vidc/msm_vidc.h b/drivers/media/platform/msm/vidc/msm_vidc.h index 913b5f9f29d9..776c74357cd2 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc.h +++ b/drivers/media/platform/msm/vidc/msm_vidc.h @@ -19,6 +19,7 @@ #include #include #include +#include #define HAL_BUFFER_MAX 0xd @@ -101,380 +102,6 @@ union msm_v4l2_cmd { struct v4l2_encoder_cmd enc; }; -#define MSM_VIDC_HAL_INTERLACE_COLOR_FORMAT_NV12 0x2 -#define MSM_VIDC_HAL_INTERLACE_COLOR_FORMAT_NV12_UBWC 0x8002 -#define MSM_VIDC_EXTRADATA_FRAME_QP_ADV 0x1 - -struct msm_vidc_extradata_header { - unsigned int size; - unsigned int:32; /** Keeping binary compatibility */ - unsigned int:32; /* with firmware and OpenMAX IL **/ - unsigned int type; /* msm_vidc_extradata_type */ - unsigned int data_size; - unsigned char data[1]; -}; - -struct msm_vidc_interlace_payload { - unsigned int format; - unsigned int color_format; -}; - -struct msm_vidc_framerate_payload { - unsigned int frame_rate; -}; - -struct msm_vidc_ts_payload { - unsigned int timestamp_lo; - unsigned int timestamp_hi; -}; - -struct msm_vidc_concealmb_payload { - unsigned int num_mbs; -}; - -struct msm_vidc_recoverysei_payload { - unsigned int flags; -}; - -struct msm_vidc_aspect_ratio_payload { - unsigned int size; - unsigned int version; - unsigned int port_index; - unsigned int aspect_width; - unsigned int aspect_height; -}; - -struct msm_vidc_mpeg2_seqdisp_payload { - unsigned int video_format; - unsigned int color_descp; - unsigned int color_primaries; - unsigned int transfer_char; - unsigned int matrix_coeffs; - unsigned int disp_width; - unsigned int disp_height; -}; - -struct msm_vidc_vc1_seqdisp_payload { - unsigned int prog_seg_format; - unsigned int uv_sampl_fmt; - unsigned int color_format; - unsigned int color_primaries; - unsigned int transfer_char; - unsigned int matrix_coeffs; - unsigned int aspect_ratio; - unsigned int aspect_horiz; - unsigned int aspect_vert; -}; - -struct msm_vidc_input_crop_payload { - unsigned int size; - unsigned int version; - unsigned int port_index; - unsigned int left; - unsigned int top; - unsigned int width; - unsigned int height; -}; - -struct msm_vidc_extradata_index { - unsigned int type; - union { - struct msm_vidc_input_crop_payload input_crop; - struct msm_vidc_aspect_ratio_payload aspect_ratio; - }; -}; - -struct msm_vidc_panscan_window { - unsigned int panscan_height_offset; - unsigned int panscan_width_offset; - unsigned int panscan_window_width; - unsigned int panscan_window_height; -}; - -struct msm_vidc_panscan_window_payload { - unsigned int num_panscan_windows; - struct msm_vidc_panscan_window wnd[1]; -}; - -struct msm_vidc_stream_userdata_payload { - unsigned int type; - unsigned int data[1]; -}; - -struct msm_vidc_frame_qp_payload { - unsigned int frame_qp; - unsigned int qp_sum; - unsigned int skip_qp_sum; - unsigned int skip_num_blocks; - unsigned int total_num_blocks; -}; - -struct msm_vidc_frame_bits_info_payload { - unsigned int frame_bits; - unsigned int header_bits; -}; - -struct msm_vidc_s3d_frame_packing_payload { - unsigned int fpa_id; - unsigned int cancel_flag; - unsigned int fpa_type; - unsigned int quin_cunx_flag; - unsigned int content_interprtation_type; - unsigned int spatial_flipping_flag; - unsigned int frame0_flipped_flag; - unsigned int field_views_flag; - unsigned int current_frame_is_frame0_flag; - unsigned int frame0_self_contained_flag; - unsigned int frame1_self_contained_flag; - unsigned int frame0_graid_pos_x; - unsigned int frame0_graid_pos_y; - unsigned int frame1_graid_pos_x; - unsigned int frame1_graid_pos_y; - unsigned int fpa_reserved_byte; - unsigned int fpa_repetition_period; - unsigned int fpa_extension_flag; -}; - -struct msm_vidc_ubwc_cr_stats_info { - unsigned int stats_tile_32; - unsigned int stats_tile_64; - unsigned int stats_tile_96; - unsigned int stats_tile_128; - unsigned int stats_tile_160; - unsigned int stats_tile_192; - unsigned int stats_tile_256; -}; - -struct msm_vidc_yuv_stats_payload { - unsigned int frame_qp; - unsigned int texture; - unsigned int luma_in_q16; - unsigned int frame_difference; -}; - -struct msm_vidc_vpx_colorspace_payload { - unsigned int color_space; - unsigned int yuv_range_flag; - unsigned int sumsampling_x; - unsigned int sumsampling_y; -}; - -struct msm_vidc_roi_qp_payload { - int upper_qp_offset; - int lower_qp_offset; - unsigned int b_roi_info; - int mbi_info_size; - unsigned int data[1]; -}; - -struct msm_vidc_mastering_display_colour_sei_payload { - unsigned int nDisplayPrimariesX[3]; - unsigned int nDisplayPrimariesY[3]; - unsigned int nWhitePointX; - unsigned int nWhitePointY; - unsigned int nMaxDispMasteringLum; - unsigned int nMinDispMasteringLum; -}; - -struct msm_vidc_content_light_level_sei_payload { - unsigned int nMaxContentLight; - unsigned int nMaxPicAverageLight; -}; - -struct msm_vidc_vui_display_info_payload { - unsigned int video_signal_present_flag; - unsigned int video_format; - unsigned int bit_depth_y; - unsigned int bit_depth_c; - unsigned int video_full_range_flag; - unsigned int color_description_present_flag; - unsigned int color_primaries; - unsigned int transfer_characteristics; - unsigned int matrix_coefficients; - unsigned int chroma_location_info_present_flag; - unsigned int chroma_format_idc; - unsigned int separate_color_plane_flag; - unsigned int chroma_sample_loc_type_top_field; - unsigned int chroma_sample_loc_type_bottom_field; -}; - -enum msm_vidc_extradata_type { - MSM_VIDC_EXTRADATA_NONE = 0x00000000, - MSM_VIDC_EXTRADATA_MB_QUANTIZATION = 0x00000001, - MSM_VIDC_EXTRADATA_INTERLACE_VIDEO = 0x00000002, - MSM_VIDC_EXTRADATA_TIMESTAMP = 0x00000005, - MSM_VIDC_EXTRADATA_S3D_FRAME_PACKING = 0x00000006, - MSM_VIDC_EXTRADATA_FRAME_RATE = 0x00000007, - MSM_VIDC_EXTRADATA_PANSCAN_WINDOW = 0x00000008, - MSM_VIDC_EXTRADATA_RECOVERY_POINT_SEI = 0x00000009, - MSM_VIDC_EXTRADATA_MPEG2_SEQDISP = 0x0000000D, - MSM_VIDC_EXTRADATA_STREAM_USERDATA = 0x0000000E, - MSM_VIDC_EXTRADATA_FRAME_QP = 0x0000000F, - MSM_VIDC_EXTRADATA_FRAME_BITS_INFO = 0x00000010, - MSM_VIDC_EXTRADATA_VQZIP_SEI = 0x00000011, - MSM_VIDC_EXTRADATA_ROI_QP = 0x00000013, -#define MSM_VIDC_EXTRADATA_VPX_COLORSPACE_INFO \ - MSM_VIDC_EXTRADATA_VPX_COLORSPACE_INFO - MSM_VIDC_EXTRADATA_VPX_COLORSPACE_INFO = 0x00000014, -#define MSM_VIDC_EXTRADATA_MASTERING_DISPLAY_COLOUR_SEI \ - MSM_VIDC_EXTRADATA_MASTERING_DISPLAY_COLOUR_SEI - MSM_VIDC_EXTRADATA_MASTERING_DISPLAY_COLOUR_SEI = 0x00000015, -#define MSM_VIDC_EXTRADATA_CONTENT_LIGHT_LEVEL_SEI \ - MSM_VIDC_EXTRADATA_CONTENT_LIGHT_LEVEL_SEI - MSM_VIDC_EXTRADATA_CONTENT_LIGHT_LEVEL_SEI = 0x00000016, -#define MSM_VIDC_EXTRADATA_PQ_INFO \ - MSM_VIDC_EXTRADATA_PQ_INFO - MSM_VIDC_EXTRADATA_PQ_INFO = 0x00000017, -#define MSM_VIDC_EXTRADATA_COLOUR_REMAPPING_INFO_SEI \ - MSM_VIDC_EXTRADATA_COLOUR_REMAPPING_INFO_SEI - MSM_VIDC_EXTRADATA_COLOUR_REMAPPING_INFO_SEI = 0x00000018, -#define MSM_VIDC_EXTRADATA_UBWC_CR_STAT_INFO \ - MSM_VIDC_EXTRADATA_UBWC_CR_STAT_INFO - MSM_VIDC_EXTRADATA_UBWC_CR_STAT_INFO = 0x00000019, - MSM_VIDC_EXTRADATA_INPUT_CROP = 0x0700000E, -#define MSM_VIDC_EXTRADATA_OUTPUT_CROP \ - MSM_VIDC_EXTRADATA_OUTPUT_CROP - MSM_VIDC_EXTRADATA_OUTPUT_CROP = 0x0700000F, - MSM_VIDC_EXTRADATA_DIGITAL_ZOOM = 0x07000010, - MSM_VIDC_EXTRADATA_MULTISLICE_INFO = 0x7F100000, - MSM_VIDC_EXTRADATA_NUM_CONCEALED_MB = 0x7F100001, - MSM_VIDC_EXTRADATA_INDEX = 0x7F100002, - MSM_VIDC_EXTRADATA_ASPECT_RATIO = 0x7F100003, - MSM_VIDC_EXTRADATA_METADATA_LTR = 0x7F100004, - MSM_VIDC_EXTRADATA_METADATA_FILLER = 0x7FE00002, - MSM_VIDC_EXTRADATA_METADATA_MBI = 0x7F100005, -#define MSM_VIDC_EXTRADATA_VUI_DISPLAY_INFO \ - MSM_VIDC_EXTRADATA_VUI_DISPLAY_INFO - MSM_VIDC_EXTRADATA_VUI_DISPLAY_INFO = 0x7F100006, - MSM_VIDC_EXTRADATA_YUVSTATS_INFO = 0x7F100007, -}; -enum msm_vidc_interlace_type { - MSM_VIDC_INTERLACE_FRAME_PROGRESSIVE = 0x01, - MSM_VIDC_INTERLACE_INTERLEAVE_FRAME_TOPFIELDFIRST = 0x02, - MSM_VIDC_INTERLACE_INTERLEAVE_FRAME_BOTTOMFIELDFIRST = 0x04, - MSM_VIDC_INTERLACE_FRAME_TOPFIELDFIRST = 0x08, - MSM_VIDC_INTERLACE_FRAME_BOTTOMFIELDFIRST = 0x10, -}; - -/* enum msm_vidc_framepack_type */ -#define MSM_VIDC_FRAMEPACK_CHECKERBOARD 0x00 -#define MSM_VIDC_FRAMEPACK_COLUMN_INTERLEAVE 0x01 -#define MSM_VIDC_FRAMEPACK_ROW_INTERLEAVE 0x02 -#define MSM_VIDC_FRAMEPACK_SIDE_BY_SIDE 0x03 -#define MSM_VIDC_FRAMEPACK_TOP_BOTTOM 0x04 -#define MSM_VIDC_FRAMEPACK_TEMPORAL_INTERLEAVE 0x05 - -enum msm_vidc_recovery_sei { - MSM_VIDC_FRAME_RECONSTRUCTION_INCORRECT = 0x0, - MSM_VIDC_FRAME_RECONSTRUCTION_CORRECT = 0x01, - MSM_VIDC_FRAME_RECONSTRUCTION_APPROXIMATELY_CORRECT = 0x02, -}; -enum msm_vidc_userdata_type { - MSM_VIDC_USERDATA_TYPE_FRAME = 0x1, - MSM_VIDC_USERDATA_TYPE_TOP_FIELD = 0x2, - MSM_VIDC_USERDATA_TYPE_BOTTOM_FIELD = 0x3, -}; - -/* See colour_primaries of ISO/IEC 14496 for significance */ -enum msm_vidc_h264_color_primaries_values { - MSM_VIDC_RESERVED_1 = 0, - MSM_VIDC_BT709_5 = 1, - MSM_VIDC_UNSPECIFIED = 2, - MSM_VIDC_RESERVED_2 = 3, - MSM_VIDC_BT470_6_M = 4, - MSM_VIDC_BT601_6_625 = 5, - MSM_VIDC_BT470_6_BG = MSM_VIDC_BT601_6_625, - MSM_VIDC_BT601_6_525 = 6, - MSM_VIDC_SMPTE_240M = 7, - MSM_VIDC_GENERIC_FILM = 8, - MSM_VIDC_BT2020 = 9, -}; - -enum msm_vidc_vp9_color_primaries_values { - MSM_VIDC_CS_UNKNOWN, - MSM_VIDC_CS_BT_601, - MSM_VIDC_CS_BT_709, - MSM_VIDC_CS_SMPTE_170, - MSM_VIDC_CS_SMPTE_240, - MSM_VIDC_CS_BT_2020, - MSM_VIDC_CS_RESERVED, - MSM_VIDC_CS_RGB, -}; - -enum msm_vidc_h264_matrix_coeff_values { - MSM_VIDC_MATRIX_RGB = 0, - MSM_VIDC_MATRIX_BT_709_5 = 1, - MSM_VIDC_MATRIX_UNSPECIFIED = 2, - MSM_VIDC_MATRIX_RESERVED = 3, - MSM_VIDC_MATRIX_FCC_47 = 4, - MSM_VIDC_MATRIX_601_6_625 = 5, - MSM_VIDC_MATRIX_BT470_BG = MSM_VIDC_MATRIX_601_6_625, - MSM_VIDC_MATRIX_601_6_525 = 6, - MSM_VIDC_MATRIX_SMPTE_170M = MSM_VIDC_MATRIX_601_6_525, - MSM_VIDC_MATRIX_SMPTE_240M = 7, - MSM_VIDC_MATRIX_Y_CG_CO = 8, - MSM_VIDC_MATRIX_BT_2020 = 9, - MSM_VIDC_MATRIX_BT_2020_CONST = 10, -}; - -enum msm_vidc_h264_transfer_chars_values { - MSM_VIDC_TRANSFER_RESERVED_1 = 0, - MSM_VIDC_TRANSFER_BT709_5 = 1, - MSM_VIDC_TRANSFER_UNSPECIFIED = 2, - MSM_VIDC_TRANSFER_RESERVED_2 = 3, - MSM_VIDC_TRANSFER_BT_470_6_M = 4, - MSM_VIDC_TRANSFER_BT_470_6_BG = 5, - MSM_VIDC_TRANSFER_601_6_625 = 6, - MSM_VIDC_TRANSFER_601_6_525 = MSM_VIDC_TRANSFER_601_6_625, - MSM_VIDC_TRANSFER_SMPTE_240M = 7, - MSM_VIDC_TRANSFER_LINEAR = 8, - MSM_VIDC_TRANSFER_LOG_100_1 = 9, - MSM_VIDC_TRANSFER_LOG_100_SQRT10_1 = 10, - MSM_VIDC_TRANSFER_IEC_61966 = 11, - MSM_VIDC_TRANSFER_BT_1361 = 12, - MSM_VIDC_TRANSFER_SRGB = 13, - MSM_VIDC_TRANSFER_BT_2020_10 = 14, - MSM_VIDC_TRANSFER_BT_2020_12 = 15, -#define MSM_VIDC_TRANSFER_SMPTE_ST2084 \ - MSM_VIDC_TRANSFER_SMPTE_ST2084 - MSM_VIDC_TRANSFER_SMPTE_ST2084 = 16, -#define MSM_VIDC_TRANSFER_SMPTE_ST428_1 \ - MSM_VIDC_TRANSFER_SMPTE_ST428_1 - MSM_VIDC_TRANSFER_SMPTE_ST428_1 = 17, -#define MSM_VIDC_TRANSFER_HLG \ - MSM_VIDC_TRANSFER_HLG - MSM_VIDC_TRANSFER_HLG = 18, -}; - -enum msm_vidc_pixel_depth { - MSM_VIDC_BIT_DEPTH_8, - MSM_VIDC_BIT_DEPTH_10, - MSM_VIDC_BIT_DEPTH_UNSUPPORTED = 0XFFFFFFFF, -}; - -enum msm_vidc_video_format { - MSM_VIDC_COMPONENT, - MSM_VIDC_PAL, - MSM_VIDC_NTSC, - MSM_VIDC_SECAM, - MSM_VIDC_MAC, - MSM_VIDC_UNSPECIFIED_FORMAT, - MSM_VIDC_RESERVED_1_FORMAT, - MSM_VIDC_RESERVED_2_FORMAT, -}; - -enum msm_vidc_color_desc_flag { - MSM_VIDC_COLOR_DESC_NOT_PRESENT, - MSM_VIDC_COLOR_DESC_PRESENT, -}; - -/*enum msm_vidc_pic_struct */ -#define MSM_VIDC_PIC_STRUCT_MAYBE_INTERLACED 0x0 -#define MSM_VIDC_PIC_STRUCT_PROGRESSIVE 0x1 - -/*default when layer ID isn't specified*/ -#define MSM_VIDC_ALL_LAYER_ID 0xFF - void *msm_vidc_open(int core_id, int session_type); int msm_vidc_close(void *instance); int msm_vidc_suspend(int core_id); diff --git a/drivers/media/platform/msm/vidc/msm_vidc_internal.h b/drivers/media/platform/msm/vidc/msm_vidc_internal.h index f63056384d74..8d4090e259c1 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc_internal.h +++ b/drivers/media/platform/msm/vidc/msm_vidc_internal.h @@ -407,7 +407,7 @@ struct msm_vidc_inst { u32 buffer_size_limit; enum buffer_mode_type buffer_mode_set[MAX_PORT_NUM]; struct v4l2_ctrl **ctrls; - enum msm_vidc_pixel_depth bit_depth; + int bit_depth; struct kref kref; bool in_flush; u32 pic_struct; diff --git a/drivers/media/platform/msm/vidc/vidc_hfi_api.h b/drivers/media/platform/msm/vidc/vidc_hfi_api.h index 736ebdcdea1a..5fd1c9092f25 100644 --- a/drivers/media/platform/msm/vidc/vidc_hfi_api.h +++ b/drivers/media/platform/msm/vidc/vidc_hfi_api.h @@ -1284,7 +1284,7 @@ struct msm_vidc_cb_event { enum vidc_status status; u32 height; u32 width; - enum msm_vidc_pixel_depth bit_depth; + int bit_depth; u32 hal_event_type; u32 packet_buffer; u32 extra_data_buffer; -- GitLab From 0c9e8e0f04bffbbe998077f0237d949eea08b736 Mon Sep 17 00:00:00 2001 From: Prasad Sodagudi Date: Mon, 23 Apr 2018 19:38:13 -0700 Subject: [PATCH 0810/1635] sched/core: Disable irq before calling irq_migrate_all_off_this_cpu irq_migrate_all_off_this_cpu is not disabling the irq when when irqs are migrated. commit 0dd945ff4647 ("genirq/cpuhotplug: Remove irq disabling logic") removed the irq disable, thinking that every caller of irq_migrate_all_off_this_cpu would disable irqs. So disable irqs during the core isolation before calling irq_migrate_all_off_this_cpu. Change-Id: I07b42e4ab6ce488e41f181ecf3033de20da8f831 Signed-off-by: Prasad Sodagudi --- kernel/sched/core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kernel/sched/core.c b/kernel/sched/core.c index abaf2bfa483c..1f6e0753ba96 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -5789,10 +5789,10 @@ int do_isolation_work_cpu_stop(void *data) watchdog_disable(cpu); - irq_migrate_all_off_this_cpu(); - local_irq_disable(); + irq_migrate_all_off_this_cpu(); + sched_ttwu_pending(); /* Update our root-domain */ -- GitLab From 17c53d66c736fd8e5cf6c8ff87b11e638e1b87dc Mon Sep 17 00:00:00 2001 From: Ajay Singh Parmar Date: Mon, 16 Apr 2018 15:04:24 -0700 Subject: [PATCH 0811/1635] drm/msm/dp: retry usb lane release if busy Retry to release USB super speed lanes in case the USB PHY is busy. This is needed to avoid USB programming the PHY while DP setting up a new connection. CRs-Fixed: 2219588 Change-Id: Ib53236319809b35bb4a7bf0bb37e0f114ce68337 Signed-off-by: Ajay Singh Parmar --- drivers/gpu/drm/msm/dp/dp_usbpd.c | 50 ++++++++++++++++++++++++------- 1 file changed, 39 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/msm/dp/dp_usbpd.c b/drivers/gpu/drm/msm/dp/dp_usbpd.c index 42eb9b053e99..3a14f7c96803 100644 --- a/drivers/gpu/drm/msm/dp/dp_usbpd.c +++ b/drivers/gpu/drm/msm/dp/dp_usbpd.c @@ -16,6 +16,7 @@ #include #include +#include #include "dp_usbpd.h" @@ -314,11 +315,44 @@ static int dp_usbpd_validate_callback(u8 cmd, return ret; } + +static int dp_usbpd_get_ss_lanes(struct dp_usbpd_private *pd) +{ + int rc = 0; + int timeout = 250; + + /* + * By default, USB reserves two lanes for Super Speed. + * Which means DP has remaining two lanes to operate on. + * If multi-function is not supported, request USB to + * release the Super Speed lanes so that DP can use + * all four lanes in case DPCD indicates support for + * four lanes. + */ + if (!pd->dp_usbpd.multi_func) { + while (timeout) { + rc = pd->svid_handler.request_usb_ss_lane( + pd->pd, &pd->svid_handler); + if (rc != -EBUSY) + break; + + pr_warn("USB busy, retry\n"); + + /* wait for hw recommended delay for usb */ + msleep(20); + timeout--; + } + } + + return rc; +} + static void dp_usbpd_response_cb(struct usbpd_svid_handler *hdlr, u8 cmd, enum usbpd_svdm_cmd_type cmd_type, const u32 *vdos, int num_vdos) { struct dp_usbpd_private *pd; + int rc = 0; pd = container_of(hdlr, struct dp_usbpd_private, svid_handler); @@ -380,17 +414,11 @@ static void dp_usbpd_response_cb(struct usbpd_svid_handler *hdlr, u8 cmd, pd->dp_usbpd.orientation = usbpd_get_plug_orientation(pd->pd); - /* - * By default, USB reserves two lanes for Super Speed. - * Which means DP has remaining two lanes to operate on. - * If multi-function is not supported, request USB to - * release the Super Speed lanes so that DP can use - * all four lanes in case DPCD indicates support for - * four lanes. - */ - if (!pd->dp_usbpd.multi_func) - pd->svid_handler.request_usb_ss_lane(pd->pd, - &pd->svid_handler); + rc = dp_usbpd_get_ss_lanes(pd); + if (rc) { + pr_err("failed to get SuperSpeed lanes\n"); + break; + } if (pd->dp_cb && pd->dp_cb->configure) pd->dp_cb->configure(pd->dev); -- GitLab From d0f24f3fef3f79a324b1ff4e17b7e68631bcae4d Mon Sep 17 00:00:00 2001 From: Harry Yang Date: Sat, 24 Mar 2018 00:51:46 -0700 Subject: [PATCH 0812/1635] power: smb5: Add support to read USBIN_I, USBIN_V, and charger temperature Add driver support for reading USB input voltage and current, and charger temperature for PM855B, which are obtained from VADC channels. Also update the documentation to correct an error, add descriptions for io-channels properties, and update the example device tree with required properties. CRs-Fixed: 2228622 Change-Id: Iaa230050b2c8c02a5dfbe0ed1de49c6b374074ed Signed-off-by: Harry Yang Signed-off-by: Guru Das Srinagesh --- .../bindings/power/supply/qcom/qpnp-smb5.txt | 18 ++++- drivers/power/supply/qcom/qpnp-smb5.c | 64 ++++++++++++++++ drivers/power/supply/qcom/smb5-lib.c | 73 +++++++++++++++++++ drivers/power/supply/qcom/smb5-lib.h | 10 ++- 4 files changed, 160 insertions(+), 5 deletions(-) diff --git a/Documentation/devicetree/bindings/power/supply/qcom/qpnp-smb5.txt b/Documentation/devicetree/bindings/power/supply/qcom/qpnp-smb5.txt index b7e6a31bf6c3..954e729fa205 100644 --- a/Documentation/devicetree/bindings/power/supply/qcom/qpnp-smb5.txt +++ b/Documentation/devicetree/bindings/power/supply/qcom/qpnp-smb5.txt @@ -27,6 +27,13 @@ Charger specific properties: Definition: Should specify the phandle of PMI's revid module. This is used to identify the PMI subtype. +- io-channels +- io-channel-names + Usage: optional + Value type: + Definition: For details about IIO bindings see: + Documentation/devicetree/bindings/iio/iio-bindings.txt + - qcom,batteryless-platform Usage: optional Value type: @@ -223,13 +230,22 @@ Peripheral specific properties: Example ======= -pmi8998_charger: qcom,qpnp-smb5 { +pm855b_charger: qcom,qpnp-smb5 { compatible = "qcom,qpnp-smb5"; #address-cells = <1>; #size-cells = <1>; + qcom,pmic-revid = <&pm855b_revid>; + dpdm-supply = <&qusb_phy0>; + io-channels = <&pm855b_vadc ADC_USB_IN_V_16>, + <&pm855b_vadc ADC_USB_IN_I>, + <&pm855b_vadc ADC_CHG_TEMP>; + io-channel-names = "usb_in_voltage", + "usb_in_current", + "chg_temp"; + qcom,chgr@1000 { reg = <0x1000 0x100>; interrupts = <0x2 0x10 0x0 IRQ_TYPE_NONE>, diff --git a/drivers/power/supply/qcom/qpnp-smb5.c b/drivers/power/supply/qcom/qpnp-smb5.c index 6b40fb3b2a00..a9034bc4dfe7 100644 --- a/drivers/power/supply/qcom/qpnp-smb5.c +++ b/drivers/power/supply/qcom/qpnp-smb5.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include "smb5-reg.h" #include "smb5-lib.h" @@ -363,6 +364,50 @@ static int smb5_parse_dt(struct smb5 *chip) if (rc < 0) chg->otg_delay_ms = OTG_DEFAULT_DEGLITCH_TIME_MS; + rc = of_property_match_string(node, "io-channel-names", + "usb_in_voltage"); + if (rc >= 0) { + chg->iio.usbin_v_chan = iio_channel_get(chg->dev, + "usb_in_voltage"); + if (IS_ERR(chg->iio.usbin_v_chan)) { + rc = PTR_ERR(chg->iio.usbin_v_chan); + if (rc != -EPROBE_DEFER) + dev_err(chg->dev, "USBIN_V channel unavailable, %ld\n", + rc); + chg->iio.usbin_v_chan = NULL; + return rc; + } + } + + rc = of_property_match_string(node, "io-channel-names", + "chg_temp"); + if (rc >= 0) { + chg->iio.temp_chan = iio_channel_get(chg->dev, "chg_temp"); + if (IS_ERR(chg->iio.temp_chan)) { + rc = PTR_ERR(chg->iio.temp_chan); + if (rc != -EPROBE_DEFER) + dev_err(chg->dev, "CHG_TEMP channel unavailable, %ld\n", + rc); + chg->iio.temp_chan = NULL; + return rc; + } + } + + rc = of_property_match_string(node, "io-channel-names", + "usb_in_current"); + if (rc >= 0) { + chg->iio.usbin_i_chan = iio_channel_get(chg->dev, + "usb_in_current"); + if (IS_ERR(chg->iio.usbin_i_chan)) { + rc = PTR_ERR(chg->iio.usbin_i_chan); + if (rc != -EPROBE_DEFER) + dev_err(chg->dev, "USBIN_I channel unavailable, %ld\n", + rc); + chg->iio.usbin_i_chan = NULL; + return rc; + } + } + return 0; } @@ -372,6 +417,7 @@ static int smb5_parse_dt(struct smb5 *chip) static enum power_supply_property smb5_usb_props[] = { POWER_SUPPLY_PROP_PRESENT, POWER_SUPPLY_PROP_ONLINE, + POWER_SUPPLY_PROP_VOLTAGE_NOW, POWER_SUPPLY_PROP_PD_CURRENT_MAX, POWER_SUPPLY_PROP_CURRENT_MAX, POWER_SUPPLY_PROP_TYPE, @@ -426,6 +472,9 @@ static int smb5_usb_get_prop(struct power_supply *psy, case POWER_SUPPLY_PROP_VOLTAGE_MAX: rc = smblib_get_prop_usb_voltage_max(chg, val); break; + case POWER_SUPPLY_PROP_VOLTAGE_NOW: + rc = smblib_get_prop_usb_voltage_now(chg, val); + break; case POWER_SUPPLY_PROP_PD_CURRENT_MAX: val->intval = get_client_vote(chg->usb_icl_votable, PD_VOTER); break; @@ -462,6 +511,9 @@ static int smb5_usb_get_prop(struct power_supply *psy, case POWER_SUPPLY_PROP_INPUT_CURRENT_SETTLED: rc = smblib_get_prop_input_current_settled(chg, val); break; + case POWER_SUPPLY_PROP_INPUT_CURRENT_NOW: + rc = smblib_get_prop_usb_current_now(chg, val); + break; case POWER_SUPPLY_PROP_BOOST_CURRENT: val->intval = chg->boost_current_ua; break; @@ -947,6 +999,7 @@ static enum power_supply_property smb5_batt_props[] = { POWER_SUPPLY_PROP_PRESENT, POWER_SUPPLY_PROP_CHARGE_TYPE, POWER_SUPPLY_PROP_CAPACITY, + POWER_SUPPLY_PROP_CHARGER_TEMP, POWER_SUPPLY_PROP_INPUT_CURRENT_LIMITED, POWER_SUPPLY_PROP_VOLTAGE_NOW, POWER_SUPPLY_PROP_VOLTAGE_MAX, @@ -973,6 +1026,8 @@ static int smb5_batt_get_prop(struct power_supply *psy, union power_supply_propval *val) { struct smb_charger *chg = power_supply_get_drvdata(psy); + union power_supply_propval pval = {0, }; + int rc = 0; switch (psp) { @@ -1000,6 +1055,15 @@ static int smb5_batt_get_prop(struct power_supply *psy, case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT_MAX: rc = smblib_get_prop_system_temp_level_max(chg, val); break; + case POWER_SUPPLY_PROP_CHARGER_TEMP: + rc = smblib_get_prop_usb_present(chg, &pval); + if (rc < 0) { + pr_err("Couldn't get usb present rc=%d\n", rc); + break; + } + if (pval.intval) + rc = smblib_get_prop_charger_temp(chg, val); + break; case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMITED: rc = smblib_get_prop_input_current_limited(chg, val); break; diff --git a/drivers/power/supply/qcom/smb5-lib.c b/drivers/power/supply/qcom/smb5-lib.c index fff32eccde99..98505a755c13 100644 --- a/drivers/power/supply/qcom/smb5-lib.c +++ b/drivers/power/supply/qcom/smb5-lib.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include "smb5-lib.h" #include "smb5-reg.h" @@ -1788,6 +1789,36 @@ int smblib_get_prop_usb_voltage_max(struct smb_charger *chg, return 0; } +int smblib_get_prop_usb_voltage_now(struct smb_charger *chg, + union power_supply_propval *val) +{ + if (chg->iio.usbin_v_chan) + return iio_read_channel_processed(chg->iio.usbin_v_chan, + &val->intval); + else + return -ENODATA; +} + +int smblib_get_prop_charger_temp(struct smb_charger *chg, + union power_supply_propval *val) +{ + int rc; + + if (chg->iio.temp_chan) { + rc = iio_read_channel_processed(chg->iio.temp_chan, + &val->intval); + if (rc < 0) { + pr_err("Error in reading temp channel, rc=%d", rc); + return rc; + } + val->intval /= 100; + } else { + return -ENODATA; + } + + return rc; +} + int smblib_get_prop_typec_cc_orientation(struct smb_charger *chg, union power_supply_propval *val) { @@ -1936,6 +1967,36 @@ int smblib_get_prop_typec_power_role(struct smb_charger *chg, return rc; } +int smblib_get_prop_usb_current_now(struct smb_charger *chg, + union power_supply_propval *val) +{ + int rc = 0; + + if (chg->iio.usbin_i_chan) { + rc = iio_read_channel_processed(chg->iio.usbin_i_chan, + &val->intval); + + /* + * For PM855B, scaling factor = reciprocal of + * 0.2V/A in Buck mode, 0.4V/A in Boost mode. + */ + if (smblib_get_prop_ufp_mode(chg) != POWER_SUPPLY_TYPEC_NONE) { + val->intval *= 5; + return rc; + } + + if (smblib_get_prop_dfp_mode(chg) != POWER_SUPPLY_TYPEC_NONE) { + val->intval = DIV_ROUND_CLOSEST(val->intval * 100, 40); + return rc; + } + } else { + rc = -ENODATA; + } + + val->intval = 0; + return rc; +} + int smblib_get_prop_input_current_settled(struct smb_charger *chg, union power_supply_propval *val) { @@ -3531,6 +3592,16 @@ static void smblib_destroy_votables(struct smb_charger *chg) destroy_votable(chg->chg_disable_votable); } +static void smblib_iio_deinit(struct smb_charger *chg) +{ + if (!IS_ERR_OR_NULL(chg->iio.usbin_v_chan)) + iio_channel_release(chg->iio.usbin_v_chan); + if (!IS_ERR_OR_NULL(chg->iio.usbin_i_chan)) + iio_channel_release(chg->iio.usbin_i_chan); + if (!IS_ERR_OR_NULL(chg->iio.temp_chan)) + iio_channel_release(chg->iio.temp_chan); +} + int smblib_init(struct smb_charger *chg) { int rc = 0; @@ -3622,5 +3693,7 @@ int smblib_deinit(struct smb_charger *chg) return -EINVAL; } + smblib_iio_deinit(chg); + return 0; } diff --git a/drivers/power/supply/qcom/smb5-lib.h b/drivers/power/supply/qcom/smb5-lib.h index 3a4c4cf2ee3f..7533ad2bfce4 100644 --- a/drivers/power/supply/qcom/smb5-lib.h +++ b/drivers/power/supply/qcom/smb5-lib.h @@ -245,14 +245,10 @@ struct parallel_params { struct smb_iio { struct iio_channel *temp_chan; - struct iio_channel *temp_max_chan; struct iio_channel *usbin_i_chan; struct iio_channel *usbin_v_chan; struct iio_channel *batt_i_chan; struct iio_channel *connector_temp_chan; - struct iio_channel *connector_temp_thr1_chan; - struct iio_channel *connector_temp_thr2_chan; - struct iio_channel *connector_temp_thr3_chan; }; struct smb_charger { @@ -485,6 +481,10 @@ int smblib_get_prop_usb_suspend(struct smb_charger *chg, union power_supply_propval *val); int smblib_get_prop_usb_voltage_max(struct smb_charger *chg, union power_supply_propval *val); +int smblib_get_prop_usb_voltage_now(struct smb_charger *chg, + union power_supply_propval *val); +int smblib_get_prop_usb_current_now(struct smb_charger *chg, + union power_supply_propval *val); int smblib_get_prop_typec_cc_orientation(struct smb_charger *chg, union power_supply_propval *val); int smblib_get_prop_typec_power_role(struct smb_charger *chg, @@ -497,6 +497,8 @@ int smblib_get_prop_pd_in_hard_reset(struct smb_charger *chg, union power_supply_propval *val); int smblib_get_pe_start(struct smb_charger *chg, union power_supply_propval *val); +int smblib_get_prop_charger_temp(struct smb_charger *chg, + union power_supply_propval *val); int smblib_get_prop_die_health(struct smb_charger *chg, union power_supply_propval *val); int smblib_set_prop_pd_current_max(struct smb_charger *chg, -- GitLab From 0f9dcc70ffb9c51bfcc1a55809eb6589aec888fc Mon Sep 17 00:00:00 2001 From: Skylar Chang Date: Tue, 24 Apr 2018 14:43:03 -0700 Subject: [PATCH 0813/1635] msm: ipa: disable prefetch for MHI MHI might be configured to MBIM aggregation. For this to work TX prefetch needs to be disabled. Change-Id: I52510f3a7fbe90d5a472703363136e6e909d301c Acked-by: Ady Abraham Signed-off-by: Skylar Chang --- drivers/platform/msm/ipa/ipa_v3/ipa.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa.c b/drivers/platform/msm/ipa/ipa_v3/ipa.c index 77c89435f98e..2d8c90121b8c 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa.c @@ -4526,13 +4526,18 @@ static int ipa3_post_init(const struct ipa3_plat_drv_res *resource_p, /* * IPAv3.5 and above requires to disable prefetch for USB in order - * to allow MBIM to work, currently MBIM is not needed in MHI mode. + * to allow MBIM to work. */ if ((ipa3_ctx->ipa_hw_type >= IPA_HW_v3_5 && ipa3_ctx->ipa_hw_type < IPA_HW_v4_0) && (!ipa3_ctx->ipa_config_is_mhi)) ipa3_disable_prefetch(IPA_CLIENT_USB_CONS); + if ((ipa3_ctx->ipa_hw_type >= IPA_HW_v3_5 + && ipa3_ctx->ipa_hw_type < IPA_HW_v4_0) && + (ipa3_ctx->ipa_config_is_mhi)) + ipa3_disable_prefetch(IPA_CLIENT_MHI_CONS); + memset(&gsi_props, 0, sizeof(gsi_props)); gsi_props.ver = ipa3_get_gsi_ver(resource_p->ipa_hw_type); gsi_props.ee = resource_p->ee; -- GitLab From bfa8766a597145941c5b2d3d875df64b2d08c50c Mon Sep 17 00:00:00 2001 From: Tony Truong Date: Tue, 17 Apr 2018 14:13:03 -0700 Subject: [PATCH 0814/1635] ARM: dts: msm: update PCIe gen3x1 and gen3x2 PHY sequence for SM8150 Update Gen3x1 and Gen3x2 PCIe node on SM8150 with new PHY sequence based on the hardware recommendation. Change-Id: Icc1419bb6e12cd1fcc3f255c0cf3288d09eff840 Signed-off-by: Tony Truong --- arch/arm64/boot/dts/qcom/sm8150-pcie.dtsi | 236 +++++++++++++--------- 1 file changed, 139 insertions(+), 97 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sm8150-pcie.dtsi b/arch/arm64/boot/dts/qcom/sm8150-pcie.dtsi index e8a66b6551c6..88168634e9f2 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-pcie.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-pcie.dtsi @@ -90,8 +90,7 @@ "msi_24", "msi_25", "msi_26", "msi_27", "msi_28", "msi_29", "msi_30", "msi_31"; - qcom,phy-sequence = <0x02b4 0x03 0x0 - 0x0840 0x03 0x0 + qcom,phy-sequence = <0x0840 0x03 0x0 0x0094 0x08 0x0 0x0154 0x32 0x0 0x016c 0x08 0x0 @@ -155,12 +154,12 @@ 0x0588 0xe4 0x0 0x058c 0xec 0x0 0x0590 0x39 0x0 - 0x0594 0x36 0x0 - 0x0570 0xbd 0x0 - 0x0574 0xbd 0x0 - 0x0578 0x7f 0x0 - 0x057c 0xfb 0x0 - 0x0580 0x53 0x0 + 0x0594 0x37 0x0 + 0x0570 0x7f 0x0 + 0x0574 0xff 0x0 + 0x0578 0xff 0x0 + 0x057c 0xdb 0x0 + 0x0580 0x76 0x0 0x04fc 0x00 0x0 0x04f8 0xc0 0x0 0x0414 0x04 0x0 @@ -174,6 +173,19 @@ 0x0988 0x66 0x0 0x0998 0x08 0x0 0x08dc 0x0d 0x0 + 0x04f0 0x6a 0x0 + 0x04f4 0x07 0x0 + 0x04b4 0x02 0x0 + 0x04b8 0x02 0x0 + 0x04bc 0xaa 0x0 + 0x04d4 0x54 0x0 + 0x04d8 0x37 0x0 + 0x0460 0xa0 0x0 + 0x05c4 0x0c 0x0 + 0x0464 0xc0 0x0 + 0x04c0 0x0f 0x0 + 0x0284 0x05 0x0 + 0x05c0 0x14 0x0 0x0800 0x00 0x0 0x0844 0x03 0x0>; @@ -349,121 +361,151 @@ "msi_28", "msi_29", "msi_30", "msi_31"; qcom,phy-sequence = <0x0a40 0x03 0x0 - 0x0094 0x08 0x0 - 0x0154 0x32 0x0 - 0x016c 0x08 0x0 + 0x0010 0x00 0x0 + 0x001c 0x31 0x0 + 0x0020 0x01 0x0 + 0x0024 0xde 0x0 + 0x0028 0x07 0x0 + 0x0030 0x4c 0x0 + 0x0034 0x06 0x0 + 0x0048 0x90 0x0 + 0x0050 0x07 0x0 0x0058 0x0f 0x0 + 0x0074 0x06 0x0 + 0x0078 0x06 0x0 + 0x007c 0x16 0x0 + 0x0080 0x16 0x0 + 0x0084 0x36 0x0 + 0x0088 0x36 0x0 + 0x0094 0x08 0x0 0x00a4 0x42 0x0 - 0x0110 0x24 0x0 - 0x011c 0x03 0x0 - 0x0118 0xb4 0x0 - 0x010c 0x02 0x0 - 0x01bc 0x11 0x0 - 0x00bc 0x82 0x0 - 0x00d4 0x03 0x0 - 0x00d0 0x55 0x0 - 0x00cc 0x55 0x0 - 0x00b0 0x1a 0x0 0x00ac 0x0a 0x0 + 0x00b0 0x1a 0x0 + 0x00b4 0x14 0x0 + 0x00b8 0x34 0x0 + 0x00bc 0x82 0x0 0x00c4 0x68 0x0 - 0x00e0 0x02 0x0 - 0x00dc 0xaa 0x0 + 0x00cc 0x55 0x0 + 0x00d0 0x55 0x0 + 0x00d4 0x03 0x0 0x00d8 0xab 0x0 - 0x00b8 0x34 0x0 - 0x00b4 0x14 0x0 - 0x01bc 0x01 0x0 + 0x00dc 0xaa 0x0 + 0x00e0 0x02 0x0 + 0x010c 0x02 0x0 + 0x0110 0x24 0x0 + 0x0118 0xb4 0x0 + 0x011c 0x03 0x0 + 0x0154 0x32 0x0 0x0158 0x01 0x0 - 0x0074 0x06 0x0 - 0x007c 0x16 0x0 - 0x0084 0x36 0x0 - 0x0078 0x06 0x0 - 0x0080 0x16 0x0 - 0x0088 0x36 0x0 - 0x01b0 0x1e 0x0 + 0x016c 0x08 0x0 0x01ac 0xb9 0x0 - 0x01b8 0x18 0x0 + 0x01b0 0x1e 0x0 0x01b4 0x94 0x0 - 0x0050 0x07 0x0 - 0x0010 0x00 0x0 - 0x001c 0x31 0x0 - 0x0020 0x01 0x0 - 0x0024 0xde 0x0 - 0x0028 0x07 0x0 - 0x0030 0x4c 0x0 - 0x0034 0x06 0x0 - 0x069c 0x12 0x0 - 0x029c 0x12 0x0 + 0x01b8 0x18 0x0 + 0x01bc 0x01 0x0 0x0284 0x05 0x0 - 0x0684 0x05 0x0 - 0x0e38 0x03 0x0 - 0x051c 0x03 0x0 - 0x091c 0x03 0x0 - 0x0518 0x1c 0x0 - 0x0918 0x1c 0x0 - 0x0524 0x14 0x0 - 0x0924 0x14 0x0 - 0x08ec 0x0e 0x0 + 0x029c 0x12 0x0 + 0x0414 0x04 0x0 + 0x0434 0x7f 0x0 + 0x0444 0x70 0x0 + 0x04d8 0x01 0x0 0x04ec 0x0e 0x0 - 0x08f0 0x4a 0x0 0x04f0 0x4a 0x0 - 0x08f4 0x0f 0x0 0x04f4 0x0f 0x0 - 0x05b4 0x04 0x0 - 0x09b4 0x04 0x0 - 0x0834 0x7f 0x0 - 0x0434 0x7f 0x0 - 0x0844 0x70 0x0 - 0x0444 0x70 0x0 + 0x04f8 0xc0 0x0 + 0x04fc 0x00 0x0 0x0510 0x17 0x0 - 0x0910 0x17 0x0 - 0x08d8 0x01 0x0 - 0x04d8 0x01 0x0 - 0x0998 0xd4 0x0 + 0x0518 0x1c 0x0 + 0x051c 0x03 0x0 + 0x0524 0x14 0x0 + 0x0570 0x7f 0x0 + 0x0574 0xff 0x0 + 0x0578 0xff 0x0 + 0x057c 0xdb 0x0 + 0x0580 0x76 0x0 + 0x0584 0x24 0x0 + 0x0588 0xe4 0x0 + 0x058c 0xec 0x0 + 0x0590 0x39 0x0 + 0x0594 0x07 0x0 0x0598 0xd4 0x0 - 0x099c 0x54 0x0 0x059c 0x54 0x0 0x05a0 0xdb 0x0 - 0x09a0 0xdb 0x0 0x05a4 0x39 0x0 - 0x09a4 0x39 0x0 0x05a8 0x31 0x0 - 0x09a8 0x31 0x0 - 0x0584 0x24 0x0 + 0x05b4 0x04 0x0 + 0x0684 0x05 0x0 + 0x069c 0x12 0x0 + 0x0814 0x04 0x0 + 0x0834 0x7f 0x0 + 0x0844 0x70 0x0 + 0x08d8 0x01 0x0 + 0x08ec 0x0e 0x0 + 0x08f0 0x4a 0x0 + 0x08f4 0x0f 0x0 + 0x08f8 0xc0 0x0 + 0x08fc 0x00 0x0 + 0x0910 0x17 0x0 + 0x0918 0x1c 0x0 + 0x091c 0x03 0x0 + 0x0924 0x14 0x0 + 0x0970 0x7f 0x0 + 0x0974 0xff 0x0 + 0x0978 0xff 0x0 + 0x097c 0xdb 0x0 + 0x0980 0x76 0x0 0x0984 0x24 0x0 0x0988 0xe4 0x0 - 0x0588 0xe4 0x0 0x098c 0xec 0x0 - 0x058c 0xec 0x0 0x0990 0x39 0x0 - 0x0590 0x39 0x0 - 0x0994 0x36 0x0 - 0x0594 0x36 0x0 - 0x0570 0xbd 0x0 - 0x0970 0xbd 0x0 - 0x0974 0xbd 0x0 - 0x0574 0xbd 0x0 - 0x0578 0x7f 0x0 - 0x0978 0x7f 0x0 - 0x097c 0xfb 0x0 - 0x057c 0xfb 0x0 - 0x0980 0x53 0x0 - 0x0580 0x53 0x0 - 0x08fc 0x00 0x0 - 0x04fc 0x00 0x0 - 0x08f8 0xc0 0x0 - 0x04f8 0xc0 0x0 - 0x0414 0x04 0x0 - 0x0814 0x04 0x0 + 0x0994 0x07 0x0 + 0x0998 0xd4 0x0 + 0x099c 0x54 0x0 + 0x09a0 0xdb 0x0 + 0x09a4 0x39 0x0 + 0x09a8 0x31 0x0 + 0x09b4 0x04 0x0 + 0x0a98 0x01 0x0 + 0x0abc 0x56 0x0 + 0x0adc 0x0d 0x0 + 0x0b88 0x66 0x0 0x0ba4 0x01 0x0 - 0x0e90 0x00 0x0 + 0x0b98 0x08 0x0 + 0x0e14 0x07 0x0 + 0x0e1c 0xc1 0x0 0x0e40 0x01 0x0 0x0e48 0x01 0x0 + 0x0e78 0x50 0x0 + 0x0e90 0x00 0x0 + 0x0ea0 0x11 0x0 + 0x0e38 0x03 0x0 0x0e50 0x00 0x0 - 0x0048 0x90 0x0 - 0x0e1c 0xc1 0x0 - 0x0b88 0x66 0x0 - 0x0b98 0x08 0x0 - 0x0adc 0x0d 0x0 + 0x04f0 0x6a 0x0 + 0x04f4 0x07 0x0 + 0x04b4 0x02 0x0 + 0x04b8 0x02 0x0 + 0x04bc 0xaa 0x0 + 0x04d4 0x54 0x0 + 0x04d8 0x37 0x0 + 0x0460 0xa0 0x0 + 0x05c4 0x0c 0x0 + 0x0464 0xc0 0x0 + 0x04c0 0x0f 0x0 + 0x0284 0x05 0x0 + 0x05c0 0x14 0x0 + 0x08f0 0x6a 0x0 + 0x08f4 0x07 0x0 + 0x08b4 0x02 0x0 + 0x08b8 0x02 0x0 + 0x08bc 0xaa 0x0 + 0x08d4 0x54 0x0 + 0x08d8 0x37 0x0 + 0x0860 0xa0 0x0 + 0x09c4 0x0c 0x0 + 0x0864 0xc0 0x0 + 0x08c0 0x0f 0x0 + 0x0684 0x05 0x0 + 0x09c0 0x14 0x0 0x0a00 0x00 0x0 0x0a44 0x03 0x0>; -- GitLab From 59dbcd7dcb6bc53f40a6a99b962d6bedf37bbe7f Mon Sep 17 00:00:00 2001 From: Tony Truong Date: Mon, 16 Apr 2018 18:15:29 -0700 Subject: [PATCH 0815/1635] msm: pcie: update PCIe gen3 settings Update PCIe gen3 core settings based on hardware recommendation. Improves overall stability. Change-Id: Ia7e8c3ff4c327b157c470507923b6295106ac36f Signed-off-by: Tony Truong --- drivers/pci/host/pci-msm.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/drivers/pci/host/pci-msm.c b/drivers/pci/host/pci-msm.c index 1201f208d2c2..5cdac364a0fc 100644 --- a/drivers/pci/host/pci-msm.c +++ b/drivers/pci/host/pci-msm.c @@ -3748,23 +3748,22 @@ static void msm_pcie_setup_gen3(struct msm_pcie_dev_t *dev) { PCIE_DBG(dev, "PCIe: RC%d: Setting up Gen3\n", dev->rc_idx); - msm_pcie_write_reg(dev->dm_core, - PCIE_GEN3_EQ_FB_MODE_DIR_CHANGE, - (0x05 << 14) | (0x05 << 10) | (0x0d << 5)); + msm_pcie_write_reg_field(dev->dm_core, + PCIE_GEN3_GEN2_CTRL, 0x1f00, 1); - msm_pcie_write_mask(dev->dm_core + - PCIE_GEN3_EQ_CONTROL, BIT(4), 0); + msm_pcie_write_mask(dev->dm_core, + PCIE_GEN3_EQ_CONTROL, 0x20); msm_pcie_write_mask(dev->dm_core + PCIE_GEN3_RELATED, BIT(0), 0); /* configure PCIe preset */ - msm_pcie_write_reg(dev->dm_core, - PCIE_GEN3_MISC_CONTROL, 1); + msm_pcie_write_reg_field(dev->dm_core, + PCIE_GEN3_MISC_CONTROL, BIT(0), 1); msm_pcie_write_reg(dev->dm_core, PCIE_GEN3_SPCIE_CAP, 0x77777777); - msm_pcie_write_reg(dev->dm_core, - PCIE_GEN3_MISC_CONTROL, 1); + msm_pcie_write_reg_field(dev->dm_core, + PCIE_GEN3_MISC_CONTROL, BIT(0), 0); } static int msm_pcie_enable(struct msm_pcie_dev_t *dev, u32 options) -- GitLab From 20a440cc869ea33a4353b0b2e70ab97ac637c114 Mon Sep 17 00:00:00 2001 From: Tony Truong Date: Mon, 16 Apr 2018 13:14:25 -0700 Subject: [PATCH 0816/1635] ARM: dts: msm: disable L1/L1ss for PCIe on SM8150 Disable L1 and L1ss for each PCIe core on SM8150 since the link is not yet stable with it. Change-Id: Ib27084f1cb5507a5fc73d94111f63edc009c45cd Signed-off-by: Tony Truong --- arch/arm64/boot/dts/qcom/sm8150-pcie.dtsi | 8 -------- 1 file changed, 8 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sm8150-pcie.dtsi b/arch/arm64/boot/dts/qcom/sm8150-pcie.dtsi index e8a66b6551c6..13e662762a74 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-pcie.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-pcie.dtsi @@ -195,10 +195,6 @@ qcom,vreg-cx-voltage-level = ; - qcom,l1-supported; - qcom,l1ss-supported; - qcom,aux-clk-sync; - qcom,max-link-speed = <0x3>; qcom,ep-latency = <10>; @@ -485,10 +481,6 @@ qcom,vreg-cx-voltage-level = ; - qcom,l1-supported; - qcom,l1ss-supported; - qcom,aux-clk-sync; - qcom,max-link-speed = <0x3>; qcom,ep-latency = <10>; -- GitLab From 818c29116583afe0c10283c9f292a10ca12634e4 Mon Sep 17 00:00:00 2001 From: Michael Adisumarta Date: Tue, 24 Apr 2018 16:04:20 -0700 Subject: [PATCH 0817/1635] msm: ipa4: Dump IPA registers during panic handling Print out IPA registers to DMESG and IPC_logs so their values can be seen without the need of modem dumps. Change-Id: I175a71b242bfe7821f6c6fde976c8c818eb435a2 CRs-fixed: 2220253 Signed-off-by: Michael Adisumarta --- drivers/platform/msm/ipa/ipa_v3/ipa.c | 5 +- drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c | 14 + drivers/platform/msm/ipa/ipa_v3/ipa_i.h | 1 + .../platform/msm/ipa/ipa_v3/ipahal/ipahal_i.h | 9 + .../msm/ipa/ipa_v3/ipahal/ipahal_reg.c | 448 +++++++++++++----- .../msm/ipa/ipa_v3/ipahal/ipahal_reg.h | 29 ++ 6 files changed, 387 insertions(+), 119 deletions(-) diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa.c b/drivers/platform/msm/ipa/ipa_v3/ipa.c index 77c89435f98e..72b0b16db7cb 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa.c @@ -374,7 +374,7 @@ static int ipa3_active_clients_panic_notifier(struct notifier_block *this, { ipa3_active_clients_log_print_table(active_clients_table_buf, IPA3_ACTIVE_CLIENTS_TABLE_BUF_SIZE); - IPAERR("%s", active_clients_table_buf); + IPAERR("%s\n", active_clients_table_buf); return NOTIFY_DONE; } @@ -4273,6 +4273,9 @@ static int ipa3_panic_notifier(struct notifier_block *this, if (res) IPAERR("uC panic handler failed %d\n", res); + if (atomic_read(&ipa3_ctx->ipa3_active_clients.cnt) != 0) + ipahal_print_all_regs(); + return NOTIFY_DONE; } diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c b/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c index ba1af38cbbe5..00b812f6f2e0 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c @@ -1889,6 +1889,16 @@ static ssize_t ipa3_pm_ex_read_stats(struct file *file, char __user *ubuf, return simple_read_from_buffer(ubuf, count, ppos, dbg_buff, cnt); } +static ssize_t ipa3_read_ipahal_regs(struct file *file, char __user *ubuf, + size_t count, loff_t *ppos) +{ + IPA_ACTIVE_CLIENTS_INC_SIMPLE(); + ipahal_print_all_regs(); + IPA_ACTIVE_CLIENTS_DEC_SIMPLE(); + + return 0; +} + static void ipa_dump_status(struct ipahal_pkt_status *status) { IPA_DUMP_STATUS_FIELD(status_opcode); @@ -2155,6 +2165,10 @@ static const struct ipa3_debugfs_file debugfs_files[] = { "enable_low_prio_print", IPA_WRITE_ONLY_MODE, NULL, { .write = ipa3_enable_ipc_low, } + }, { + "ipa_dump_regs", IPA_READ_ONLY_MODE, NULL, { + .read = ipa3_read_ipahal_regs, + } } }; diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h index 68999274fda8..c492c37912e1 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h @@ -2133,6 +2133,7 @@ int __ipa3_release_hdr(u32 hdr_hdl); int __ipa3_release_hdr_proc_ctx(u32 proc_ctx_hdl); int _ipa_read_ep_reg_v3_0(char *buf, int max_len, int pipe); int _ipa_read_ep_reg_v4_0(char *buf, int max_len, int pipe); +int _ipa_read_ipahal_regs(void); void _ipa_enable_clks_v3_0(void); void _ipa_disable_clks_v3_0(void); struct device *ipa3_get_dma_dev(void); diff --git a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_i.h b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_i.h index bf00ce7180a6..26b7f0fc005e 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_i.h +++ b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_i.h @@ -46,6 +46,15 @@ IPAHAL_DRV_NAME " %s:%d " fmt, ## args); \ } while (0) +#define IPAHAL_DBG_REG(fmt, args...) \ + do { \ + pr_err(fmt, ## args); \ + IPA_IPC_LOGGING(ipa_get_ipc_logbuf(), \ + " %s:%d " fmt, ## args); \ + IPA_IPC_LOGGING(ipa_get_ipc_logbuf_low(), \ + " %s:%d " fmt, ## args); \ + } while (0) + #define IPAHAL_ERR_RL(fmt, args...) \ do { \ pr_err_ratelimited_ipa(IPAHAL_DRV_NAME " %s:%d " fmt, \ diff --git a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg.c b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg.c index 1b3f5f15a46c..48f6e7db24c3 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg.c @@ -18,6 +18,8 @@ #include "ipahal_reg.h" #include "ipahal_reg_i.h" +#define IPA_MAX_MSG_LEN 4096 + static const char *ipareg_name_to_str[IPA_REG_MAX] = { __stringify(IPA_ROUTE), __stringify(IPA_IRQ_STTS_EE_n), @@ -26,6 +28,9 @@ static const char *ipareg_name_to_str[IPA_REG_MAX] = { __stringify(IPA_IRQ_SUSPEND_INFO_EE_n), __stringify(IPA_SUSPEND_IRQ_EN_EE_n), __stringify(IPA_SUSPEND_IRQ_CLR_EE_n), + __stringify(IPA_HOLB_DROP_IRQ_INFO_EE_n), + __stringify(IPA_HOLB_DROP_IRQ_EN_EE_n), + __stringify(IPA_HOLB_DROP_IRQ_CLR_EE_n), __stringify(IPA_BCR), __stringify(IPA_ENABLED_PIPES), __stringify(IPA_COMP_SW_RESET), @@ -35,8 +40,21 @@ static const char *ipareg_name_to_str[IPA_REG_MAX] = { __stringify(IPA_SPARE_REG_1), __stringify(IPA_SPARE_REG_2), __stringify(IPA_COMP_CFG), + __stringify(IPA_STATE_TX_WRAPPER), + __stringify(IPA_STATE_TX1), + __stringify(IPA_STATE_FETCHER), + __stringify(IPA_STATE_FETCHER_MASK), + __stringify(IPA_STATE_DFETCHER), + __stringify(IPA_STATE_ACL), + __stringify(IPA_STATE), + __stringify(IPA_STATE_RX_ACTIVE), + __stringify(IPA_STATE_TX0), __stringify(IPA_STATE_AGGR_ACTIVE), __stringify(IPA_COUNTER_CFG), + __stringify(IPA_STATE_GSI_TLV), + __stringify(IPA_STATE_GSI_AOS), + __stringify(IPA_STATE_GSI_IF), + __stringify(IPA_STATE_GSI_SKIP), __stringify(IPA_ENDP_INIT_HDR_n), __stringify(IPA_ENDP_INIT_HDR_EXT_n), __stringify(IPA_ENDP_INIT_AGGR_n), @@ -47,6 +65,7 @@ static const char *ipareg_name_to_str[IPA_REG_MAX] = { __stringify(IPA_ENDP_INIT_CONN_TRACK_n), __stringify(IPA_ENDP_INIT_CTRL_n), __stringify(IPA_ENDP_INIT_CTRL_SCND_n), + __stringify(IPA_ENDP_INIT_CTRL_STATUS_n), __stringify(IPA_ENDP_INIT_HOL_BLOCK_EN_n), __stringify(IPA_ENDP_INIT_HOL_BLOCK_TIMER_n), __stringify(IPA_ENDP_INIT_DEAGGR_n), @@ -56,6 +75,7 @@ static const char *ipareg_name_to_str[IPA_REG_MAX] = { __stringify(IPA_IRQ_EE_UC_n), __stringify(IPA_ENDP_INIT_HDR_METADATA_MASK_n), __stringify(IPA_ENDP_INIT_HDR_METADATA_n), + __stringify(IPA_ENDP_INIT_PROD_CFG_n), __stringify(IPA_ENDP_INIT_RSRC_GRP_n), __stringify(IPA_SHARED_MEM_SIZE), __stringify(IPA_SRAM_DIRECT_ACCESS_n), @@ -67,6 +87,8 @@ static const char *ipareg_name_to_str[IPA_REG_MAX] = { __stringify(IPA_SYS_PKT_PROC_CNTXT_BASE), __stringify(IPA_LOCAL_PKT_PROC_CNTXT_BASE), __stringify(IPA_ENDP_STATUS_n), + __stringify(IPA_ENDP_WEIGHTS_n), + __stringify(IPA_ENDP_YELLOW_RED_MARKER), __stringify(IPA_ENDP_FILTER_ROUTER_HSH_CFG_n), __stringify(IPA_SRC_RSRC_GRP_01_RSRC_TYPE_n), __stringify(IPA_SRC_RSRC_GRP_23_RSRC_TYPE_n), @@ -106,6 +128,12 @@ static const char *ipareg_name_to_str[IPA_REG_MAX] = { __stringify(IPA_STAT_ROUTER_IPV6_END_ID), __stringify(IPA_STAT_DROP_CNT_BASE_n), __stringify(IPA_STAT_DROP_CNT_MASK_n), + __stringify(IPA_SNOC_FEC_EE_n), + __stringify(IPA_FEC_ADDR_EE_n), + __stringify(IPA_FEC_ADDR_MSB_EE_n), + __stringify(IPA_FEC_ATTR_EE_n), + __stringify(IPA_MBIM_DEAGGR_FEC_ATTR_EE_n), + __stringify(IPA_GEN_DEAGGR_FEC_ATTR_EE_n), }; static void ipareg_construct_dummy(enum ipahal_reg_name reg, @@ -1689,6 +1717,9 @@ static void ipareg_parse_counter_cfg( * @parse - CB to parse register value to abstracted structure * @offset - register offset relative to base address * @n_ofst - N parameterized register sub-offset + * @n_start - starting n for n_registers + * @n_end - ending n for n_registers + * @en_print - enable this register to be printed when the device crashes */ struct ipahal_reg_obj { void (*construct)(enum ipahal_reg_name reg, const void *fields, @@ -1697,6 +1728,9 @@ struct ipahal_reg_obj { u32 val); u32 offset; u32 n_ofst; + int n_start; + int n_end; + bool en_print; }; /* @@ -1714,368 +1748,546 @@ static struct ipahal_reg_obj ipahal_reg_objs[IPA_HW_MAX][IPA_REG_MAX] = { /* IPAv3 */ [IPA_HW_v3_0][IPA_ROUTE] = { ipareg_construct_route, ipareg_parse_dummy, - 0x00000048, 0}, + 0x00000048, 0, 0, 0, 0}, [IPA_HW_v3_0][IPA_IRQ_STTS_EE_n] = { ipareg_construct_dummy, ipareg_parse_dummy, - 0x00003008, 0x1000}, + 0x00003008, 0x1000, 0, 0, 0}, [IPA_HW_v3_0][IPA_IRQ_EN_EE_n] = { ipareg_construct_dummy, ipareg_parse_dummy, - 0x0000300c, 0x1000}, + 0x0000300c, 0x1000, 0, 0, 0}, [IPA_HW_v3_0][IPA_IRQ_CLR_EE_n] = { ipareg_construct_dummy, ipareg_parse_dummy, - 0x00003010, 0x1000}, + 0x00003010, 0x1000, 0, 0, 0}, [IPA_HW_v3_0][IPA_IRQ_SUSPEND_INFO_EE_n] = { ipareg_construct_dummy, ipareg_parse_dummy, - 0x00003098, 0x1000}, + 0x00003098, 0x1000, 0, 0, 0}, [IPA_HW_v3_0][IPA_BCR] = { ipareg_construct_dummy, ipareg_parse_dummy, - 0x000001D0, 0}, + 0x000001D0, 0, 0, 0, 0}, [IPA_HW_v3_0][IPA_ENABLED_PIPES] = { ipareg_construct_dummy, ipareg_parse_dummy, - 0x00000038, 0}, + 0x00000038, 0, 0, 0, 0}, [IPA_HW_v3_0][IPA_COMP_SW_RESET] = { ipareg_construct_dummy, ipareg_parse_dummy, - 0x00000040, 0}, + 0x00000040, 0, 0, 0, 0}, [IPA_HW_v3_0][IPA_VERSION] = { ipareg_construct_dummy, ipareg_parse_dummy, - 0x00000034, 0}, + 0x00000034, 0, 0, 0, 0}, [IPA_HW_v3_0][IPA_TAG_TIMER] = { ipareg_construct_dummy, ipareg_parse_dummy, - 0x00000060, 0 }, + 0x00000060, 0, 0, 0, 0}, [IPA_HW_v3_0][IPA_COMP_HW_VERSION] = { ipareg_construct_dummy, ipareg_parse_dummy, - 0x00000030, 0}, + 0x00000030, 0, 0, 0, 0}, [IPA_HW_v3_0][IPA_SPARE_REG_1] = { ipareg_construct_dummy, ipareg_parse_dummy, - 0x00005090, 0}, + 0x00005090, 0, 0, 0, 0}, [IPA_HW_v3_0][IPA_SPARE_REG_2] = { ipareg_construct_dummy, ipareg_parse_dummy, - 0x00005094, 0}, + 0x00005094, 0, 0, 0, 0}, [IPA_HW_v3_0][IPA_COMP_CFG] = { ipareg_construct_comp_cfg, ipareg_parse_comp_cfg, - 0x0000003C, 0}, + 0x0000003C, 0, 0, 0, 0}, [IPA_HW_v3_0][IPA_STATE_AGGR_ACTIVE] = { ipareg_construct_dummy, ipareg_parse_dummy, - 0x0000010C, 0}, + 0x0000010C, 0, 0, 0, 0}, [IPA_HW_v3_0][IPA_ENDP_INIT_HDR_n] = { ipareg_construct_endp_init_hdr_n, ipareg_parse_dummy, - 0x00000810, 0x70}, + 0x00000810, 0x70, 0, 0, 0}, [IPA_HW_v3_0][IPA_ENDP_INIT_HDR_EXT_n] = { ipareg_construct_endp_init_hdr_ext_n, ipareg_parse_dummy, - 0x00000814, 0x70}, + 0x00000814, 0x70, 0, 0, 0}, [IPA_HW_v3_0][IPA_ENDP_INIT_AGGR_n] = { ipareg_construct_endp_init_aggr_n, ipareg_parse_endp_init_aggr_n, - 0x00000824, 0x70}, + 0x00000824, 0x70, 0, 0, 0}, [IPA_HW_v3_0][IPA_AGGR_FORCE_CLOSE] = { ipareg_construct_dummy, ipareg_parse_dummy, - 0x000001EC, 0}, + 0x000001EC, 0, 0, 0, 0}, [IPA_HW_v3_0][IPA_ENDP_INIT_ROUTE_n] = { ipareg_construct_endp_init_route_n, ipareg_parse_dummy, - 0x00000828, 0x70}, + 0x00000828, 0x70, 0, 0, 0}, [IPA_HW_v3_0][IPA_ENDP_INIT_MODE_n] = { ipareg_construct_endp_init_mode_n, ipareg_parse_dummy, - 0x00000820, 0x70}, + 0x00000820, 0x70, 0, 0, 0}, [IPA_HW_v3_0][IPA_ENDP_INIT_NAT_n] = { ipareg_construct_endp_init_nat_n, ipareg_parse_dummy, - 0x0000080C, 0x70}, + 0x0000080C, 0x70, 0, 0, 0}, [IPA_HW_v3_0][IPA_ENDP_INIT_CTRL_n] = { ipareg_construct_endp_init_ctrl_n, ipareg_parse_endp_init_ctrl_n, - 0x00000800, 0x70}, + 0x00000800, 0x70, 0, 0, 0}, [IPA_HW_v3_0][IPA_ENDP_INIT_CTRL_SCND_n] = { ipareg_construct_endp_init_ctrl_scnd_n, ipareg_parse_dummy, - 0x00000804, 0x70 }, + 0x00000804, 0x70, 0, 0, 0}, [IPA_HW_v3_0][IPA_ENDP_INIT_HOL_BLOCK_EN_n] = { ipareg_construct_endp_init_hol_block_en_n, ipareg_parse_dummy, - 0x0000082c, 0x70}, + 0x0000082c, 0x70, 0, 0, 0}, [IPA_HW_v3_0][IPA_ENDP_INIT_HOL_BLOCK_TIMER_n] = { ipareg_construct_endp_init_hol_block_timer_n, ipareg_parse_dummy, - 0x00000830, 0x70}, + 0x00000830, 0x70, 0, 0, 0}, [IPA_HW_v3_0][IPA_ENDP_INIT_DEAGGR_n] = { ipareg_construct_endp_init_deaggr_n, ipareg_parse_dummy, - 0x00000834, 0x70}, + 0x00000834, 0x70, 0, 0, 0}, [IPA_HW_v3_0][IPA_ENDP_INIT_SEQ_n] = { ipareg_construct_dummy, ipareg_parse_dummy, - 0x0000083C, 0x70}, + 0x0000083C, 0x70, 0, 0, 0}, [IPA_HW_v3_0][IPA_DEBUG_CNT_REG_n] = { ipareg_construct_dummy, ipareg_parse_dummy, - 0x00000600, 0x4}, + 0x00000600, 0x4, 0, 0, 0}, [IPA_HW_v3_0][IPA_ENDP_INIT_CFG_n] = { ipareg_construct_endp_init_cfg_n, ipareg_parse_dummy, - 0x00000808, 0x70}, + 0x00000808, 0x70, 0, 0, 0}, [IPA_HW_v3_0][IPA_IRQ_EE_UC_n] = { ipareg_construct_dummy, ipareg_parse_dummy, - 0x0000301c, 0x1000}, + 0x0000301c, 0x1000, 0, 0, 0}, [IPA_HW_v3_0][IPA_ENDP_INIT_HDR_METADATA_MASK_n] = { ipareg_construct_endp_init_hdr_metadata_mask_n, ipareg_parse_dummy, - 0x00000818, 0x70}, + 0x00000818, 0x70, 0, 0, 0}, [IPA_HW_v3_0][IPA_ENDP_INIT_HDR_METADATA_n] = { ipareg_construct_endp_init_hdr_metadata_n, ipareg_parse_dummy, - 0x0000081c, 0x70}, + 0x0000081c, 0x70, 0, 0, 0}, [IPA_HW_v3_0][IPA_ENDP_INIT_RSRC_GRP_n] = { ipareg_construct_endp_init_rsrc_grp_n, ipareg_parse_dummy, - 0x00000838, 0x70}, + 0x00000838, 0x70, 0, 0, 0}, [IPA_HW_v3_0][IPA_SHARED_MEM_SIZE] = { ipareg_construct_dummy, ipareg_parse_shared_mem_size, - 0x00000054, 0}, + 0x00000054, 0, 0, 0, 0}, [IPA_HW_v3_0][IPA_SRAM_DIRECT_ACCESS_n] = { ipareg_construct_dummy, ipareg_parse_dummy, - 0x00007000, 0x4}, + 0x00007000, 0x4, 0, 0, 0}, [IPA_HW_v3_0][IPA_DEBUG_CNT_CTRL_n] = { ipareg_construct_debug_cnt_ctrl_n, ipareg_parse_dummy, - 0x00000640, 0x4}, + 0x00000640, 0x4, 0, 0, 0}, [IPA_HW_v3_0][IPA_UC_MAILBOX_m_n] = { ipareg_construct_dummy, ipareg_parse_dummy, - 0x00032000, 0x4}, + 0x00032000, 0x4, 0, 0, 0}, [IPA_HW_v3_0][IPA_FILT_ROUT_HASH_FLUSH] = { ipareg_construct_dummy, ipareg_parse_dummy, - 0x00000090, 0}, + 0x00000090, 0, 0, 0, 0}, [IPA_HW_v3_0][IPA_SINGLE_NDP_MODE] = { ipareg_construct_single_ndp_mode, ipareg_parse_single_ndp_mode, - 0x00000068, 0}, + 0x00000068, 0, 0, 0, 0}, [IPA_HW_v3_0][IPA_QCNCM] = { ipareg_construct_qcncm, ipareg_parse_qcncm, - 0x00000064, 0}, + 0x00000064, 0, 0, 0, 0}, [IPA_HW_v3_0][IPA_SYS_PKT_PROC_CNTXT_BASE] = { ipareg_construct_dummy, ipareg_parse_dummy, - 0x000001e0, 0}, + 0x000001e0, 0, 0, 0, 0}, [IPA_HW_v3_0][IPA_LOCAL_PKT_PROC_CNTXT_BASE] = { ipareg_construct_dummy, ipareg_parse_dummy, - 0x000001e8, 0}, + 0x000001e8, 0, 0, 0, 0}, [IPA_HW_v3_0][IPA_ENDP_STATUS_n] = { ipareg_construct_endp_status_n, ipareg_parse_dummy, - 0x00000840, 0x70}, + 0x00000840, 0x70, 0, 0, 0}, [IPA_HW_v3_0][IPA_ENDP_FILTER_ROUTER_HSH_CFG_n] = { ipareg_construct_hash_cfg_n, ipareg_parse_hash_cfg_n, - 0x0000085C, 0x70}, + 0x0000085C, 0x70, 0, 0, 0}, [IPA_HW_v3_0][IPA_SRC_RSRC_GRP_01_RSRC_TYPE_n] = { ipareg_construct_rsrg_grp_xy, ipareg_parse_dummy, - 0x00000400, 0x20}, + 0x00000400, 0x20, 0, 0, 0}, [IPA_HW_v3_0][IPA_SRC_RSRC_GRP_23_RSRC_TYPE_n] = { ipareg_construct_rsrg_grp_xy, ipareg_parse_dummy, - 0x00000404, 0x20}, + 0x00000404, 0x20, 0, 0, 0}, [IPA_HW_v3_0][IPA_SRC_RSRC_GRP_45_RSRC_TYPE_n] = { ipareg_construct_rsrg_grp_xy, ipareg_parse_dummy, - 0x00000408, 0x20}, + 0x00000408, 0x20, 0, 0, 0}, [IPA_HW_v3_0][IPA_SRC_RSRC_GRP_67_RSRC_TYPE_n] = { ipareg_construct_rsrg_grp_xy, ipareg_parse_dummy, - 0x0000040C, 0x20}, + 0x0000040C, 0x20, 0, 0, 0}, [IPA_HW_v3_0][IPA_DST_RSRC_GRP_01_RSRC_TYPE_n] = { ipareg_construct_rsrg_grp_xy, ipareg_parse_dummy, - 0x00000500, 0x20}, + 0x00000500, 0x20, 0, 0, 0}, [IPA_HW_v3_0][IPA_DST_RSRC_GRP_23_RSRC_TYPE_n] = { ipareg_construct_rsrg_grp_xy, ipareg_parse_dummy, - 0x00000504, 0x20}, + 0x00000504, 0x20, 0, 0, 0}, [IPA_HW_v3_0][IPA_DST_RSRC_GRP_45_RSRC_TYPE_n] = { ipareg_construct_rsrg_grp_xy, ipareg_parse_dummy, - 0x00000508, 0x20}, + 0x00000508, 0x20, 0, 0, 0}, [IPA_HW_v3_0][IPA_DST_RSRC_GRP_67_RSRC_TYPE_n] = { ipareg_construct_rsrg_grp_xy, ipareg_parse_dummy, - 0x0000050c, 0x20}, + 0x0000050c, 0x20, 0, 0, 0}, [IPA_HW_v3_0][IPA_RX_HPS_CLIENTS_MIN_DEPTH_0] = { ipareg_construct_rx_hps_clients_depth0, ipareg_parse_dummy, - 0x000023C4, 0}, + 0x000023C4, 0, 0, 0, 0}, [IPA_HW_v3_0][IPA_RX_HPS_CLIENTS_MIN_DEPTH_1] = { ipareg_construct_rx_hps_clients_depth1, ipareg_parse_dummy, - 0x000023C8, 0}, + 0x000023C8, 0, 0, 0, 0}, [IPA_HW_v3_0][IPA_RX_HPS_CLIENTS_MAX_DEPTH_0] = { ipareg_construct_rx_hps_clients_depth0, ipareg_parse_dummy, - 0x000023CC, 0}, + 0x000023CC, 0, 0, 0, 0}, [IPA_HW_v3_0][IPA_RX_HPS_CLIENTS_MAX_DEPTH_1] = { ipareg_construct_rx_hps_clients_depth1, ipareg_parse_dummy, - 0x000023D0, 0}, + 0x000023D0, 0, 0, 0, 0}, [IPA_HW_v3_0][IPA_QSB_MAX_WRITES] = { ipareg_construct_qsb_max_writes, ipareg_parse_dummy, - 0x00000074, 0}, + 0x00000074, 0, 0, 0, 0}, [IPA_HW_v3_0][IPA_QSB_MAX_READS] = { ipareg_construct_qsb_max_reads, ipareg_parse_dummy, - 0x00000078, 0}, + 0x00000078, 0, 0, 0, 0}, [IPA_HW_v3_0][IPA_DPS_SEQUENCER_FIRST] = { ipareg_construct_dummy, ipareg_parse_dummy, - 0x0001e000, 0}, + 0x0001e000, 0, 0, 0, 0}, [IPA_HW_v3_0][IPA_HPS_SEQUENCER_FIRST] = { ipareg_construct_dummy, ipareg_parse_dummy, - 0x0001e080, 0}, + 0x0001e080, 0, 0, 0, 0}, /* IPAv3.1 */ [IPA_HW_v3_1][IPA_IRQ_SUSPEND_INFO_EE_n] = { ipareg_construct_dummy, ipareg_parse_dummy, - 0x00003030, 0x1000}, + 0x00003030, 0x1000, 0, 0, 0}, [IPA_HW_v3_1][IPA_SUSPEND_IRQ_EN_EE_n] = { ipareg_construct_dummy, ipareg_parse_dummy, - 0x00003034, 0x1000}, + 0x00003034, 0x1000, 0, 0, 0}, [IPA_HW_v3_1][IPA_SUSPEND_IRQ_CLR_EE_n] = { ipareg_construct_dummy, ipareg_parse_dummy, - 0x00003038, 0x1000}, + 0x00003038, 0x1000, 0, 0, 0}, /* IPAv3.5 */ [IPA_HW_v3_5][IPA_TX_CFG] = { ipareg_construct_tx_cfg, ipareg_parse_tx_cfg, - 0x000001FC, 0}, + 0x000001FC, 0, 0, 0, 0}, [IPA_HW_v3_5][IPA_SRC_RSRC_GRP_01_RSRC_TYPE_n] = { ipareg_construct_rsrg_grp_xy_v3_5, ipareg_parse_dummy, - 0x00000400, 0x20}, + 0x00000400, 0x20, 0, 0, 0}, [IPA_HW_v3_5][IPA_SRC_RSRC_GRP_23_RSRC_TYPE_n] = { ipareg_construct_rsrg_grp_xy_v3_5, ipareg_parse_dummy, - 0x00000404, 0x20}, + 0x00000404, 0x20, 0, 0, 0}, [IPA_HW_v3_5][IPA_SRC_RSRC_GRP_45_RSRC_TYPE_n] = { ipareg_construct_dummy, ipareg_parse_dummy, - -1, 0}, + -1, 0, 0, 0, 0}, [IPA_HW_v3_5][IPA_SRC_RSRC_GRP_67_RSRC_TYPE_n] = { ipareg_construct_dummy, ipareg_parse_dummy, - -1, 0}, + -1, 0, 0, 0, 0}, [IPA_HW_v3_5][IPA_DST_RSRC_GRP_01_RSRC_TYPE_n] = { ipareg_construct_rsrg_grp_xy_v3_5, ipareg_parse_dummy, - 0x00000500, 0x20}, + 0x00000500, 0x20, 0, 0, 0}, [IPA_HW_v3_5][IPA_DST_RSRC_GRP_23_RSRC_TYPE_n] = { ipareg_construct_rsrg_grp_xy_v3_5, ipareg_parse_dummy, - 0x00000504, 0x20}, + 0x00000504, 0x20, 0, 0, 0}, [IPA_HW_v3_5][IPA_DST_RSRC_GRP_45_RSRC_TYPE_n] = { ipareg_construct_dummy, ipareg_parse_dummy, - -1, 0}, + -1, 0, 0, 0, 0}, [IPA_HW_v3_5][IPA_DST_RSRC_GRP_67_RSRC_TYPE_n] = { ipareg_construct_dummy, ipareg_parse_dummy, - -1, 0}, + -1, 0, 0, 0, 0}, [IPA_HW_v3_5][IPA_ENDP_INIT_RSRC_GRP_n] = { ipareg_construct_endp_init_rsrc_grp_n_v3_5, ipareg_parse_dummy, - 0x00000838, 0x70}, + 0x00000838, 0x70, 0, 0, 0}, [IPA_HW_v3_5][IPA_RX_HPS_CLIENTS_MIN_DEPTH_0] = { ipareg_construct_rx_hps_clients_depth0_v3_5, ipareg_parse_dummy, - 0x000023C4, 0}, + 0x000023C4, 0, 0, 0, 0}, [IPA_HW_v3_5][IPA_RX_HPS_CLIENTS_MIN_DEPTH_1] = { ipareg_construct_dummy, ipareg_parse_dummy, - -1, 0}, + -1, 0, 0, 0, 0}, [IPA_HW_v3_5][IPA_RX_HPS_CLIENTS_MAX_DEPTH_0] = { ipareg_construct_rx_hps_clients_depth0_v3_5, ipareg_parse_dummy, - 0x000023CC, 0}, + 0x000023CC, 0, 0, 0, 0}, [IPA_HW_v3_5][IPA_RX_HPS_CLIENTS_MAX_DEPTH_1] = { ipareg_construct_dummy, ipareg_parse_dummy, - -1, 0}, + -1, 0, 0, 0, 0}, [IPA_HW_v3_5][IPA_SPARE_REG_1] = { ipareg_construct_dummy, ipareg_parse_dummy, - 0x00002780, 0}, + 0x00002780, 0, 0, 0, 0}, [IPA_HW_v3_5][IPA_SPARE_REG_2] = { ipareg_construct_dummy, ipareg_parse_dummy, - 0x00002784, 0}, + 0x00002784, 0, 0, 0, 0}, [IPA_HW_v3_5][IPA_IDLE_INDICATION_CFG] = { ipareg_construct_idle_indication_cfg, ipareg_parse_dummy, - 0x00000220, 0}, + 0x00000220, 0, 0, 0, 0}, [IPA_HW_v3_5][IPA_HPS_FTCH_ARB_QUEUE_WEIGHT] = { ipareg_construct_hps_queue_weights, - ipareg_parse_hps_queue_weights, 0x000005a4, 0}, + ipareg_parse_hps_queue_weights, 0x000005a4, 0, 0, 0, 0}, [IPA_HW_v3_5][IPA_COUNTER_CFG] = { ipareg_construct_counter_cfg, ipareg_parse_counter_cfg, - 0x000001F0, 0 }, + 0x000001F0, 0, 0, 0, 0}, /* IPAv4.0 */ + [IPA_HW_v4_0][IPA_IRQ_SUSPEND_INFO_EE_n] = { + ipareg_construct_dummy, ipareg_parse_dummy, + 0x00003030, 0x1000, 0, 1, 1}, + [IPA_HW_v4_0][IPA_SUSPEND_IRQ_EN_EE_n] = { + ipareg_construct_dummy, ipareg_parse_dummy, + 0x00003034, 0x1000, 0, 1, 1}, + [IPA_HW_v4_0][IPA_SUSPEND_IRQ_CLR_EE_n] = { + ipareg_construct_dummy, ipareg_parse_dummy, + 0x00003038, 0x1000, 0, 1, 1}, + [IPA_HW_v4_0][IPA_IRQ_EN_EE_n] = { + ipareg_construct_dummy, ipareg_parse_dummy, + 0x0000300c, 0x1000, 0, 1, 1}, + [IPA_HW_v4_0][IPA_TAG_TIMER] = { + ipareg_construct_dummy, ipareg_parse_dummy, + 0x00000060, 0, 0, 0, 1}, [IPA_HW_v4_0][IPA_ENDP_INIT_CTRL_n] = { ipareg_construct_endp_init_ctrl_n_v4_0, ipareg_parse_dummy, - 0x00000800, 0x70 }, + 0x00000800, 0x70, 0, 23, 1}, + [IPA_HW_v4_0][IPA_ENDP_INIT_HDR_EXT_n] = { + ipareg_construct_endp_init_hdr_ext_n, ipareg_parse_dummy, + 0x00000814, 0x70, 0, 23, 1}, + [IPA_HW_v4_0][IPA_ENDP_INIT_AGGR_n] = { + ipareg_construct_endp_init_aggr_n, + ipareg_parse_endp_init_aggr_n, + 0x00000824, 0x70, 0, 23, 1}, [IPA_HW_v4_0][IPA_TX_CFG] = { ipareg_construct_tx_cfg_v4_0, ipareg_parse_tx_cfg_v4_0, - 0x000001FC, 0}, + 0x000001FC, 0, 0, 0, 0}, [IPA_HW_v4_0][IPA_DEBUG_CNT_REG_n] = { ipareg_construct_dummy, ipareg_parse_dummy, - -1, 0}, + -1, 0, 0, 0, 0}, [IPA_HW_v4_0][IPA_DEBUG_CNT_CTRL_n] = { ipareg_construct_debug_cnt_ctrl_n, ipareg_parse_dummy, - -1, 0}, + -1, 0, 0, 0, 0}, [IPA_HW_v4_0][IPA_QCNCM] = { ipareg_construct_qcncm, ipareg_parse_qcncm, - -1, 0}, + -1, 0, 0, 0, 0}, [IPA_HW_v4_0][IPA_SINGLE_NDP_MODE] = { ipareg_construct_single_ndp_mode, ipareg_parse_single_ndp_mode, - -1, 0}, + -1, 0, 0, 0, 0}, [IPA_HW_v4_0][IPA_QSB_MAX_READS] = { ipareg_construct_qsb_max_reads_v4_0, ipareg_parse_dummy, - 0x00000078, 0}, + 0x00000078, 0, 0, 0, 0}, [IPA_HW_v4_0][IPA_FILT_ROUT_HASH_FLUSH] = { ipareg_construct_dummy, ipareg_parse_dummy, - 0x0000014c, 0}, - [IPA_HW_v4_0][IPA_STATE_AGGR_ACTIVE] = { - ipareg_construct_dummy, ipareg_parse_dummy, - 0x000000b4, 0}, + 0x0000014c, 0, 0, 0, 0}, + [IPA_HW_v4_0][IPA_ENDP_INIT_HDR_n] = { + ipareg_construct_endp_init_hdr_n, ipareg_parse_dummy, + 0x00000810, 0x70, 0, 23, 1}, [IPA_HW_v4_0][IPA_ENDP_INIT_ROUTE_n] = { ipareg_construct_endp_init_route_n, ipareg_parse_dummy, - -1, 0}, + -1, 0, 0, 0, 0}, + [IPA_HW_v4_0][IPA_ENDP_INIT_MODE_n] = { + ipareg_construct_endp_init_mode_n, ipareg_parse_dummy, + 0x00000820, 0x70, 0, 10, 1}, + [IPA_HW_v4_0][IPA_ENDP_INIT_NAT_n] = { + ipareg_construct_endp_init_nat_n, ipareg_parse_dummy, + 0x0000080C, 0x70, 0, 10, 1}, [IPA_HW_v4_0][IPA_ENDP_STATUS_n] = { ipareg_construct_endp_status_n_v4_0, ipareg_parse_dummy, - 0x00000840, 0x70}, - [IPA_HW_v4_0][IPA_CLKON_CFG] = { - ipareg_construct_clkon_cfg, ipareg_parse_clkon_cfg, - 0x00000044, 0}, + 0x00000840, 0x70, 0, 23, 1}, + [IPA_HW_v4_0][IPA_ENDP_FILTER_ROUTER_HSH_CFG_n] = { + ipareg_construct_hash_cfg_n, ipareg_parse_hash_cfg_n, + 0x0000085C, 0x70, 0, 32, 1}, [IPA_HW_v4_0][IPA_ENDP_INIT_CONN_TRACK_n] = { ipareg_construct_endp_init_conn_track_n, ipareg_parse_dummy, - 0x00000850, 0x70}, + 0x00000850, 0x70, 0, 10, 1}, + [IPA_HW_v4_0][IPA_ENDP_INIT_CTRL_SCND_n] = { + ipareg_construct_endp_init_ctrl_scnd_n, ipareg_parse_dummy, + 0x00000804, 0x70, 0, 23, 1}, + [IPA_HW_v4_0][IPA_ENDP_INIT_HOL_BLOCK_EN_n] = { + ipareg_construct_endp_init_hol_block_en_n, + ipareg_parse_dummy, + 0x0000082c, 0x70, 10, 23, 1}, + [IPA_HW_v4_0][IPA_ENDP_INIT_HOL_BLOCK_TIMER_n] = { + ipareg_construct_endp_init_hol_block_timer_n, + ipareg_parse_dummy, + 0x00000830, 0x70, 10, 23, 1}, + [IPA_HW_v4_0][IPA_ENDP_INIT_DEAGGR_n] = { + ipareg_construct_endp_init_deaggr_n, + ipareg_parse_dummy, + 0x00000834, 0x70, 0, 10, 1}, + [IPA_HW_v4_0][IPA_ENDP_INIT_SEQ_n] = { + ipareg_construct_dummy, ipareg_parse_dummy, + 0x0000083C, 0x70, 0, 10, 1}, + [IPA_HW_v4_0][IPA_ENDP_INIT_CFG_n] = { + ipareg_construct_endp_init_cfg_n, ipareg_parse_dummy, + 0x00000808, 0x70, 0, 23, 1}, + [IPA_HW_v4_0][IPA_IRQ_EE_UC_n] = { + ipareg_construct_dummy, ipareg_parse_dummy, + 0x0000301c, 0x1000, 0, 0, 1}, + [IPA_HW_v4_0][IPA_ENDP_INIT_HDR_METADATA_MASK_n] = { + ipareg_construct_endp_init_hdr_metadata_mask_n, + ipareg_parse_dummy, + 0x00000818, 0x70, 10, 23, 1}, + [IPA_HW_v4_0][IPA_ENDP_INIT_HDR_METADATA_n] = { + ipareg_construct_endp_init_hdr_metadata_n, + ipareg_parse_dummy, + 0x0000081c, 0x70, 0, 10, 1}, + [IPA_HW_v4_0][IPA_CLKON_CFG] = { + ipareg_construct_clkon_cfg, ipareg_parse_clkon_cfg, + 0x00000044, 0, 0, 0, 0}, [IPA_HW_v4_0][IPA_STAT_QUOTA_BASE_n] = { ipareg_construct_dummy, ipareg_parse_dummy, - 0x00000700, 0x4 }, + 0x00000700, 0x4, 0, 0, 0}, [IPA_HW_v4_0][IPA_STAT_QUOTA_MASK_n] = { ipareg_construct_dummy, ipareg_parse_dummy, - 0x00000708, 0x4 }, + 0x00000708, 0x4, 0, 0, 0}, [IPA_HW_v4_0][IPA_STAT_TETHERING_BASE_n] = { ipareg_construct_dummy, ipareg_parse_dummy, - 0x00000710, 0x4 }, + 0x00000710, 0x4, 0, 0, 0}, [IPA_HW_v4_0][IPA_STAT_TETHERING_MASK_n] = { ipareg_construct_dummy, ipareg_parse_dummy, - 0x00000718, 0x4 }, + 0x00000718, 0x4, 0, 0, 0}, [IPA_HW_v4_0][IPA_STAT_FILTER_IPV4_BASE] = { ipareg_construct_dummy, ipareg_parse_dummy, - 0x00000720, 0x0 }, + 0x00000720, 0, 0, 0, 0}, [IPA_HW_v4_0][IPA_STAT_FILTER_IPV6_BASE] = { ipareg_construct_dummy, ipareg_parse_dummy, - 0x00000724, 0x0 }, + 0x00000724, 0, 0, 0, 0}, [IPA_HW_v4_0][IPA_STAT_ROUTER_IPV4_BASE] = { ipareg_construct_dummy, ipareg_parse_dummy, - 0x00000728, 0x0 }, + 0x00000728, 0, 0, 0, 0}, [IPA_HW_v4_0][IPA_STAT_ROUTER_IPV6_BASE] = { ipareg_construct_dummy, ipareg_parse_dummy, - 0x0000072C, 0x0 }, + 0x0000072C, 0, 0, 0, 0}, [IPA_HW_v4_0][IPA_STAT_FILTER_IPV4_START_ID] = { ipareg_construct_dummy, ipareg_parse_dummy, - 0x00000730, 0x0 }, + 0x00000730, 0, 0, 0, 0}, [IPA_HW_v4_0][IPA_STAT_FILTER_IPV6_START_ID] = { ipareg_construct_dummy, ipareg_parse_dummy, - 0x00000734, 0x0 }, + 0x00000734, 0, 0, 0, 0}, [IPA_HW_v4_0][IPA_STAT_ROUTER_IPV4_START_ID] = { ipareg_construct_dummy, ipareg_parse_dummy, - 0x00000738, 0x0 }, + 0x00000738, 0, 0, 0, 0}, [IPA_HW_v4_0][IPA_STAT_ROUTER_IPV6_START_ID] = { ipareg_construct_dummy, ipareg_parse_dummy, - 0x0000073C, 0x0 }, + 0x0000073C, 0, 0, 0, 0}, [IPA_HW_v4_0][IPA_STAT_FILTER_IPV4_END_ID] = { ipareg_construct_dummy, ipareg_parse_dummy, - 0x00000740, 0x0 }, + 0x00000740, 0, 0, 0, 0}, [IPA_HW_v4_0][IPA_STAT_FILTER_IPV6_END_ID] = { ipareg_construct_dummy, ipareg_parse_dummy, - 0x00000744, 0x0 }, + 0x00000744, 0, 0, 0, 0}, [IPA_HW_v4_0][IPA_STAT_ROUTER_IPV4_END_ID] = { ipareg_construct_dummy, ipareg_parse_dummy, - 0x00000748, 0x0 }, + 0x00000748, 0, 0, 0, 0}, [IPA_HW_v4_0][IPA_STAT_ROUTER_IPV6_END_ID] = { ipareg_construct_dummy, ipareg_parse_dummy, - 0x0000074C, 0x0 }, + 0x0000074C, 0, 0, 0, 0}, [IPA_HW_v4_0][IPA_STAT_DROP_CNT_BASE_n] = { ipareg_construct_dummy, ipareg_parse_dummy, - 0x00000750, 0x4 }, + 0x00000750, 0x4, 3, 1}, [IPA_HW_v4_0][IPA_STAT_DROP_CNT_MASK_n] = { ipareg_construct_dummy, ipareg_parse_dummy, - 0x00000758, 0x4 }, + 0x00000758, 0x4, 0, 0, 1}, + [IPA_HW_v4_0][IPA_STATE_TX_WRAPPER] = { + ipareg_construct_dummy, ipareg_parse_dummy, + 0x00000090, 0, 0, 0, 1}, + [IPA_HW_v4_0][IPA_STATE_TX1] = { + ipareg_construct_dummy, ipareg_parse_dummy, + 0x00000094, 0, 0, 0, 1}, + [IPA_HW_v4_0][IPA_STATE_FETCHER] = { + ipareg_construct_dummy, ipareg_parse_dummy, + 0x00000098, 0, 0, 0, 1}, + [IPA_HW_v4_0][IPA_STATE_FETCHER_MASK] = { + ipareg_construct_dummy, ipareg_parse_dummy, + 0x0000009C, 0, 0, 0, 1}, + [IPA_HW_v4_0][IPA_STATE_DFETCHER] = { + ipareg_construct_dummy, ipareg_parse_dummy, + 0x000000A0, 0, 0, 0, 1}, + [IPA_HW_v4_0][IPA_STATE_ACL] = { + ipareg_construct_dummy, ipareg_parse_dummy, + 0x000000A4, 0, 0, 0, 1}, + [IPA_HW_v4_0][IPA_STATE] = { + ipareg_construct_dummy, ipareg_parse_dummy, + 0x000000A8, 0, 0, 0, 1}, + [IPA_HW_v4_0][IPA_STATE_RX_ACTIVE] = { + ipareg_construct_dummy, ipareg_parse_dummy, + 0x000000AC, 0, 0, 0, 1}, + [IPA_HW_v4_0][IPA_STATE_TX0] = { + ipareg_construct_dummy, ipareg_parse_dummy, + 0x000000B0, 0, 0, 0, 1}, + [IPA_HW_v4_0][IPA_STATE_AGGR_ACTIVE] = { + ipareg_construct_dummy, ipareg_parse_dummy, + 0x000000B4, 0, 0, 0, 1}, + [IPA_HW_v4_0][IPA_STATE_GSI_TLV] = { + ipareg_construct_dummy, ipareg_parse_dummy, + 0x000000B8, 0, 0, 0, 1}, + [IPA_HW_v4_0][IPA_STATE_GSI_AOS] = { + ipareg_construct_dummy, ipareg_parse_dummy, + 0x000000B8, 0, 0, 0, 1}, + [IPA_HW_v4_0][IPA_STATE_GSI_IF] = { + ipareg_construct_dummy, ipareg_parse_dummy, + 0x000000C0, 0, 0, 0, 1}, + [IPA_HW_v4_0][IPA_STATE_GSI_SKIP] = { + ipareg_construct_dummy, ipareg_parse_dummy, + 0x000000C4, 0, 0, 0, 1}, + [IPA_HW_v4_0][IPA_SNOC_FEC_EE_n] = { + ipareg_construct_dummy, ipareg_parse_dummy, + 0x00003018, 0x1000, 0, 0, 1}, + [IPA_HW_v4_0][IPA_FEC_ADDR_EE_n] = { + ipareg_construct_dummy, ipareg_parse_dummy, + 0x00003020, 0x1000, 0, 0, 1}, + [IPA_HW_v4_0][IPA_FEC_ADDR_MSB_EE_n] = { + ipareg_construct_dummy, ipareg_parse_dummy, + 0x00003024, 0x1000, 0, 0, 1}, + [IPA_HW_v4_0][IPA_FEC_ATTR_EE_n] = { + ipareg_construct_dummy, ipareg_parse_dummy, + 0x00003028, 0x1000, 0, 0, 1}, + [IPA_HW_v4_0][IPA_MBIM_DEAGGR_FEC_ATTR_EE_n] = { + ipareg_construct_dummy, ipareg_parse_dummy, + 0x00003028, 0x1000, 0, 0, 1}, + [IPA_HW_v4_0][IPA_GEN_DEAGGR_FEC_ATTR_EE_n] = { + ipareg_construct_dummy, ipareg_parse_dummy, + 0x00003028, 0x1000, 0, 0, 1}, + [IPA_HW_v4_0][IPA_HOLB_DROP_IRQ_INFO_EE_n] = { + ipareg_construct_dummy, ipareg_parse_dummy, + 0x0000303C, 0x1000, 0, 0, 1}, + [IPA_HW_v4_0][IPA_HOLB_DROP_IRQ_EN_EE_n] = { + ipareg_construct_dummy, ipareg_parse_dummy, + 0x00003040, 0x1000, 0, 0, 1}, + [IPA_HW_v4_0][IPA_HOLB_DROP_IRQ_CLR_EE_n] = { + ipareg_construct_dummy, ipareg_parse_dummy, + 0x00003044, 0x1000, 0, 0, 1}, + [IPA_HW_v4_0][IPA_ENDP_INIT_CTRL_STATUS_n] = { + ipareg_construct_dummy, ipareg_parse_dummy, + 0x00000864, 0x70, 0, 23, 1}, + [IPA_HW_v4_0][IPA_ENDP_INIT_PROD_CFG_n] = { + ipareg_construct_dummy, ipareg_parse_dummy, + 0x00000CC8, 0x70, 10, 23, 1}, + [IPA_HW_v4_0][IPA_ENDP_INIT_RSRC_GRP_n] = { + ipareg_construct_endp_init_rsrc_grp_n_v3_5, + ipareg_parse_dummy, + 0x00000838, 0x70, 0, 23, 1}, + [IPA_HW_v4_0][IPA_ENDP_WEIGHTS_n] = { + ipareg_construct_dummy, ipareg_parse_dummy, + 0x00000CA4, 0x70, 10, 23, 1}, + [IPA_HW_v4_0][IPA_ENDP_YELLOW_RED_MARKER] = { + ipareg_construct_dummy, ipareg_parse_dummy, + 0x00000CC0, 0x70, 10, 23, 1}, }; +int ipahal_print_all_regs(void) +{ + int i, j; + + IPAHAL_DBG("Printing all registers for ipa_hw_type %d\n", + ipahal_ctx->hw_type); + + if ((ipahal_ctx->hw_type < IPA_HW_v4_0) || + (ipahal_ctx->hw_type >= IPA_HW_MAX)) { + IPAHAL_ERR("invalid IPA HW type (%d)\n", ipahal_ctx->hw_type); + return -EINVAL; + } + + for (i = 0; i < IPA_REG_MAX ; i++) { + if (!ipahal_reg_objs[IPA_HW_v4_0][i].en_print) + continue; + + j = ipahal_reg_objs[ipahal_ctx->hw_type][i].n_start; + + if (j == ipahal_reg_objs[ipahal_ctx->hw_type][i].n_end) + IPAHAL_DBG_REG("%s=0x%x\n", ipahal_reg_name_str(i), + ipahal_read_reg_n(i, j)); + + for (; j < ipahal_reg_objs[ipahal_ctx->hw_type][i].n_end; j++) + IPAHAL_DBG_REG("%s_%u=0x%x\n", ipahal_reg_name_str(i), + j, ipahal_read_reg_n(i, j)); + } + return 0; +} + /* * ipahal_reg_init() - Build the registers information table * See ipahal_reg_objs[][] comments diff --git a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg.h b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg.h index f0aa207a9a3a..0bece888a50c 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg.h +++ b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg.h @@ -29,6 +29,9 @@ enum ipahal_reg_name { IPA_IRQ_SUSPEND_INFO_EE_n, IPA_SUSPEND_IRQ_EN_EE_n, IPA_SUSPEND_IRQ_CLR_EE_n, + IPA_HOLB_DROP_IRQ_INFO_EE_n, + IPA_HOLB_DROP_IRQ_EN_EE_n, + IPA_HOLB_DROP_IRQ_CLR_EE_n, IPA_BCR, IPA_ENABLED_PIPES, IPA_COMP_SW_RESET, @@ -38,8 +41,21 @@ enum ipahal_reg_name { IPA_SPARE_REG_1, IPA_SPARE_REG_2, IPA_COMP_CFG, + IPA_STATE_TX_WRAPPER, + IPA_STATE_TX1, + IPA_STATE_FETCHER, + IPA_STATE_FETCHER_MASK, + IPA_STATE_DFETCHER, + IPA_STATE_ACL, + IPA_STATE, + IPA_STATE_RX_ACTIVE, + IPA_STATE_TX0, IPA_STATE_AGGR_ACTIVE, IPA_COUNTER_CFG, + IPA_STATE_GSI_TLV, + IPA_STATE_GSI_AOS, + IPA_STATE_GSI_IF, + IPA_STATE_GSI_SKIP, IPA_ENDP_INIT_HDR_n, IPA_ENDP_INIT_HDR_EXT_n, IPA_ENDP_INIT_AGGR_n, @@ -50,6 +66,7 @@ enum ipahal_reg_name { IPA_ENDP_INIT_CONN_TRACK_n, IPA_ENDP_INIT_CTRL_n, IPA_ENDP_INIT_CTRL_SCND_n, + IPA_ENDP_INIT_CTRL_STATUS_n, IPA_ENDP_INIT_HOL_BLOCK_EN_n, IPA_ENDP_INIT_HOL_BLOCK_TIMER_n, IPA_ENDP_INIT_DEAGGR_n, @@ -59,6 +76,7 @@ enum ipahal_reg_name { IPA_IRQ_EE_UC_n, IPA_ENDP_INIT_HDR_METADATA_MASK_n, IPA_ENDP_INIT_HDR_METADATA_n, + IPA_ENDP_INIT_PROD_CFG_n, IPA_ENDP_INIT_RSRC_GRP_n, IPA_SHARED_MEM_SIZE, IPA_SRAM_DIRECT_ACCESS_n, @@ -70,6 +88,8 @@ enum ipahal_reg_name { IPA_SYS_PKT_PROC_CNTXT_BASE, IPA_LOCAL_PKT_PROC_CNTXT_BASE, IPA_ENDP_STATUS_n, + IPA_ENDP_WEIGHTS_n, + IPA_ENDP_YELLOW_RED_MARKER, IPA_ENDP_FILTER_ROUTER_HSH_CFG_n, IPA_SRC_RSRC_GRP_01_RSRC_TYPE_n, IPA_SRC_RSRC_GRP_23_RSRC_TYPE_n, @@ -109,6 +129,12 @@ enum ipahal_reg_name { IPA_STAT_ROUTER_IPV6_END_ID, IPA_STAT_DROP_CNT_BASE_n, IPA_STAT_DROP_CNT_MASK_n, + IPA_SNOC_FEC_EE_n, + IPA_FEC_ADDR_EE_n, + IPA_FEC_ADDR_MSB_EE_n, + IPA_FEC_ATTR_EE_n, + IPA_MBIM_DEAGGR_FEC_ATTR_EE_n, + IPA_GEN_DEAGGR_FEC_ATTR_EE_n, IPA_REG_MAX, }; @@ -508,6 +534,9 @@ struct ipahal_ep_cfg_ctrl_scnd { bool endp_delay; }; + +int ipahal_print_all_regs(void); + /* * ipahal_reg_name_str() - returns string that represent the register * @reg_name: [in] register name -- GitLab From 756c453a48fba885e299b4aa074a95455a65e3eb Mon Sep 17 00:00:00 2001 From: Ajay Singh Parmar Date: Tue, 17 Apr 2018 22:15:57 -0700 Subject: [PATCH 0818/1635] drm/msm/dsi-staging: use parser APIs for custom panel data In case custom panel data is used instead of device tree, parse the data using parser sub-module and use its APIs instead of device tree. CRs-Fixed: 2223812 Change-Id: Id7d69d2ed35526e0c0e8e92739c85b9e22f4ab32 Signed-off-by: Ajay Singh Parmar --- drivers/gpu/drm/msm/dsi-staging/dsi_display.c | 124 ++++- drivers/gpu/drm/msm/dsi-staging/dsi_display.h | 6 + drivers/gpu/drm/msm/dsi-staging/dsi_panel.c | 483 ++++++++++-------- drivers/gpu/drm/msm/dsi-staging/dsi_panel.h | 9 +- drivers/gpu/drm/msm/dsi-staging/dsi_pwr.c | 51 +- drivers/gpu/drm/msm/dsi-staging/dsi_pwr.h | 6 +- 6 files changed, 419 insertions(+), 260 deletions(-) diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_display.c b/drivers/gpu/drm/msm/dsi-staging/dsi_display.c index 18fbfd925b6b..957ebc4974f4 100644 --- a/drivers/gpu/drm/msm/dsi-staging/dsi_display.c +++ b/drivers/gpu/drm/msm/dsi-staging/dsi_display.c @@ -29,6 +29,7 @@ #include "dsi_clk.h" #include "dsi_pwr.h" #include "sde_dbg.h" +#include "dsi_parser.h" #define to_dsi_display(x) container_of(x, struct dsi_display, host) #define INT_BASE_10 10 @@ -1143,6 +1144,8 @@ static int dsi_display_debugfs_init(struct dsi_display *display) } display->root = dir; + dsi_parser_dbg_init(display->parser, dir); + return rc; error_remove_dir: debugfs_remove(dir); @@ -2452,6 +2455,27 @@ static bool dsi_display_check_prefix(const char *clk_prefix, return !!strnstr(clk_name, clk_prefix, strlen(clk_name)); } +static int dsi_display_get_clocks_count(struct dsi_display *display) +{ + if (display->fw) + return dsi_parser_count_strings(display->parser_node, + "qcom,dsi-select-clocks"); + else + return of_property_count_strings(display->disp_node, + "qcom,dsi-select-clocks"); +} + +static void dsi_display_get_clock_name(struct dsi_display *display, + int index, const char **clk_name) +{ + if (display->fw) + dsi_parser_read_string_index(display->parser_node, + "qcom,dsi-select-clocks", index, clk_name); + else + of_property_read_string_index(display->disp_node, + "qcom,dsi-select-clocks", index, clk_name); +} + static int dsi_display_clocks_init(struct dsi_display *display) { int i, rc = 0, num_clk = 0; @@ -2464,12 +2488,12 @@ static int dsi_display_clocks_init(struct dsi_display *display) struct dsi_clk_link_set *mux = &display->clock_info.mux_clks; struct dsi_clk_link_set *shadow = &display->clock_info.shadow_clks; - num_clk = of_property_count_strings(display->disp_node, - "qcom,dsi-select-clocks"); + num_clk = dsi_display_get_clocks_count(display); + + pr_debug("clk count=%d\n", num_clk); for (i = 0; i < num_clk; i++) { - of_property_read_string_index(display->disp_node, - "qcom,dsi-select-clocks", i, &clk_name); + dsi_display_get_clock_name(display, i, &clk_name); pr_debug("clock name:%s\n", clk_name); @@ -2912,7 +2936,12 @@ static int dsi_display_get_phandle_index( if (index >= count) goto end; - rc = of_property_read_u32_array(disp_node, propname, val, count); + if (display->fw) + rc = dsi_parser_read_u32_array(display->parser_node, + propname, val, count); + else + rc = of_property_read_u32_array(disp_node, propname, + val, count); if (rc) goto end; @@ -2924,18 +2953,31 @@ static int dsi_display_get_phandle_index( return rc; } +static int dsi_display_get_phandle_count(struct dsi_display *display, + const char *propname) +{ + if (display->fw) + return dsi_parser_count_u32_elems(display->parser_node, + propname); + else + return of_property_count_u32_elems(display->disp_node, + propname); +} + static int dsi_display_parse_dt(struct dsi_display *display) { - int rc = 0; - int i; + int i, rc = 0; u32 phy_count = 0; struct device_node *of_node = display->pdev->dev.of_node; struct device_node *disp_node = display->disp_node; - display->ctrl_count = of_property_count_u32_elems(disp_node, + display->ctrl_count = dsi_display_get_phandle_count(display, + "qcom,dsi-ctrl-num"); + phy_count = dsi_display_get_phandle_count(display, "qcom,dsi-ctrl-num"); - phy_count = of_property_count_u32_elems(disp_node, - "qcom,dsi-phy-num"); + + pr_debug("ctrl count=%d, phy count=%d\n", + display->ctrl_count, phy_count); if (!phy_count || !display->ctrl_count) { pr_err("no ctrl/phys found\n"); @@ -2972,6 +3014,8 @@ static int dsi_display_parse_dt(struct dsi_display *display) rc = -ENODEV; goto error; } + + pr_debug("success\n"); error: return rc; } @@ -3002,8 +3046,11 @@ static int dsi_display_res_init(struct dsi_display *display) } } - display->panel = dsi_panel_get(&display->pdev->dev, display->panel_of, - display->cmdline_topology); + display->panel = dsi_panel_get(&display->pdev->dev, + display->panel_of, + display->parser_node, + display->root, + display->cmdline_topology); if (IS_ERR_OR_NULL(display->panel)) { rc = PTR_ERR(display->panel); pr_err("failed to get panel, rc=%d\n", rc); @@ -3489,6 +3536,12 @@ static int _dsi_display_dev_init(struct dsi_display *display) mutex_lock(&display->display_lock); + display->parser = dsi_parser_get(&display->pdev->dev); + if (display->fw && display->parser) + display->parser_node = dsi_parser_get_head_node( + display->parser, display->fw->data, + display->fw->size); + rc = dsi_display_parse_dt(display); if (rc) { pr_err("[%s] failed to parse dt, rc=%d\n", display->name, rc); @@ -3968,6 +4021,28 @@ static int dsi_display_init(struct dsi_display *display, return rc; } +static void dsi_display_firmware_display(const struct firmware *fw, + void *context) +{ + struct dsi_display *display = context; + struct platform_device *pdev = display->pdev; + + if (fw) { + pr_debug("reading data from firmware, size=%zd\n", + fw->size); + + display->fw = fw; + display->name = "dsi_firmware_display"; + } + + dsi_display_setup(display); + + if (dsi_display_init(display, pdev)) + return; + + pr_debug("success\n"); +} + int dsi_display_dev_probe(struct platform_device *pdev) { struct dsi_display *display = NULL; @@ -3976,6 +4051,7 @@ int dsi_display_dev_probe(struct platform_device *pdev) const char *disp_list = "qcom,dsi-display-list"; const char *disp_active = "qcom,dsi-display-active"; int i, count, rc = 0; + bool firm_req = false; if (!pdev || !pdev->dev.of_node) { pr_err("pdev not found\n"); @@ -3984,8 +4060,10 @@ int dsi_display_dev_probe(struct platform_device *pdev) } display = devm_kzalloc(&pdev->dev, sizeof(*display), GFP_KERNEL); - if (!display) - return -ENOMEM; + if (!display) { + rc = -ENOMEM; + goto end; + } if (boot_displays[DSI_PRIMARY].boot_disp_en) display_from_cmdline = true; @@ -4007,6 +4085,12 @@ int dsi_display_dev_probe(struct platform_device *pdev) } else { if (of_property_read_bool(np, disp_active)) { disp_node = np; + + if (IS_ENABLED(CONFIG_DSI_PARSER)) + firm_req = !request_firmware_nowait( + THIS_MODULE, 1, "dsi_prop", + &pdev->dev, GFP_KERNEL, display, + dsi_display_firmware_display); break; } } @@ -4030,10 +4114,14 @@ int dsi_display_dev_probe(struct platform_device *pdev) platform_set_drvdata(pdev, display); default_display = display; - dsi_display_setup(display); - rc = dsi_display_init(display, pdev); - if (rc) - goto end; + /* initialize display in firmware callback */ + if (!firm_req) { + dsi_display_setup(display); + + rc = dsi_display_init(display, pdev); + if (rc) + goto end; + } return 0; end: diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_display.h b/drivers/gpu/drm/msm/dsi-staging/dsi_display.h index 10e6ae551b1e..13d06cf82aec 100644 --- a/drivers/gpu/drm/msm/dsi-staging/dsi_display.h +++ b/drivers/gpu/drm/msm/dsi-staging/dsi_display.h @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -181,6 +182,7 @@ struct dsi_display { struct dsi_panel *panel; struct device_node *disp_node; struct device_node *panel_of; + struct device_node *parser_node; struct dsi_display_mode *modes; @@ -226,6 +228,10 @@ struct dsi_display { struct work_struct fifo_underflow_work; struct work_struct fifo_overflow_work; struct work_struct lp_rx_timeout_work; + + /* firmware panel data */ + const struct firmware *fw; + void *parser; }; int dsi_display_dev_probe(struct platform_device *pdev); diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c b/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c index 4021b8be0e12..4705d7d96830 100644 --- a/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c +++ b/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c @@ -21,6 +21,7 @@ #include "dsi_panel.h" #include "dsi_ctrl_hw.h" +#include "dsi_parser.h" /** * topology is currently defined by a set of following 3 values: @@ -680,42 +681,45 @@ static int dsi_panel_bl_unregister(struct dsi_panel *panel) error: return rc; } + static int dsi_panel_parse_timing(struct dsi_mode_info *mode, - struct device_node *of_node) + struct dsi_parser_utils *utils) { int rc = 0; - u64 tmp64; + u64 tmp64 = 0; struct dsi_display_mode *display_mode; display_mode = container_of(mode, struct dsi_display_mode, timing); - rc = of_property_read_u64(of_node, + rc = utils->read_u64(utils->data, "qcom,mdss-dsi-panel-clockrate", &tmp64); if (rc == -EOVERFLOW) { tmp64 = 0; - rc = of_property_read_u32(of_node, + rc = utils->read_u32(utils->data, "qcom,mdss-dsi-panel-clockrate", (u32 *)&tmp64); } mode->clk_rate_hz = !rc ? tmp64 : 0; display_mode->priv_info->clk_rate_hz = mode->clk_rate_hz; - rc = of_property_read_u32(of_node, "qcom,mdss-dsi-panel-framerate", - &mode->refresh_rate); + rc = utils->read_u32(utils->data, + "qcom,mdss-dsi-panel-framerate", + &mode->refresh_rate); if (rc) { pr_err("failed to read qcom,mdss-dsi-panel-framerate, rc=%d\n", rc); goto error; } - rc = of_property_read_u32(of_node, "qcom,mdss-dsi-panel-width", + rc = utils->read_u32(utils->data, "qcom,mdss-dsi-panel-width", &mode->h_active); if (rc) { pr_err("failed to read qcom,mdss-dsi-panel-width, rc=%d\n", rc); goto error; } - rc = of_property_read_u32(of_node, "qcom,mdss-dsi-h-front-porch", + rc = utils->read_u32(utils->data, + "qcom,mdss-dsi-h-front-porch", &mode->h_front_porch); if (rc) { pr_err("failed to read qcom,mdss-dsi-h-front-porch, rc=%d\n", @@ -723,7 +727,8 @@ static int dsi_panel_parse_timing(struct dsi_mode_info *mode, goto error; } - rc = of_property_read_u32(of_node, "qcom,mdss-dsi-h-back-porch", + rc = utils->read_u32(utils->data, + "qcom,mdss-dsi-h-back-porch", &mode->h_back_porch); if (rc) { pr_err("failed to read qcom,mdss-dsi-h-back-porch, rc=%d\n", @@ -731,7 +736,8 @@ static int dsi_panel_parse_timing(struct dsi_mode_info *mode, goto error; } - rc = of_property_read_u32(of_node, "qcom,mdss-dsi-h-pulse-width", + rc = utils->read_u32(utils->data, + "qcom,mdss-dsi-h-pulse-width", &mode->h_sync_width); if (rc) { pr_err("failed to read qcom,mdss-dsi-h-pulse-width, rc=%d\n", @@ -739,7 +745,7 @@ static int dsi_panel_parse_timing(struct dsi_mode_info *mode, goto error; } - rc = of_property_read_u32(of_node, "qcom,mdss-dsi-h-sync-skew", + rc = utils->read_u32(utils->data, "qcom,mdss-dsi-h-sync-skew", &mode->h_skew); if (rc) pr_err("qcom,mdss-dsi-h-sync-skew is not defined, rc=%d\n", rc); @@ -748,7 +754,7 @@ static int dsi_panel_parse_timing(struct dsi_mode_info *mode, mode->h_active, mode->h_front_porch, mode->h_back_porch, mode->h_sync_width); - rc = of_property_read_u32(of_node, "qcom,mdss-dsi-panel-height", + rc = utils->read_u32(utils->data, "qcom,mdss-dsi-panel-height", &mode->v_active); if (rc) { pr_err("failed to read qcom,mdss-dsi-panel-height, rc=%d\n", @@ -756,7 +762,7 @@ static int dsi_panel_parse_timing(struct dsi_mode_info *mode, goto error; } - rc = of_property_read_u32(of_node, "qcom,mdss-dsi-v-back-porch", + rc = utils->read_u32(utils->data, "qcom,mdss-dsi-v-back-porch", &mode->v_back_porch); if (rc) { pr_err("failed to read qcom,mdss-dsi-v-back-porch, rc=%d\n", @@ -764,7 +770,7 @@ static int dsi_panel_parse_timing(struct dsi_mode_info *mode, goto error; } - rc = of_property_read_u32(of_node, "qcom,mdss-dsi-v-front-porch", + rc = utils->read_u32(utils->data, "qcom,mdss-dsi-v-front-porch", &mode->v_front_porch); if (rc) { pr_err("failed to read qcom,mdss-dsi-v-back-porch, rc=%d\n", @@ -772,7 +778,7 @@ static int dsi_panel_parse_timing(struct dsi_mode_info *mode, goto error; } - rc = of_property_read_u32(of_node, "qcom,mdss-dsi-v-pulse-width", + rc = utils->read_u32(utils->data, "qcom,mdss-dsi-v-pulse-width", &mode->v_sync_width); if (rc) { pr_err("failed to read qcom,mdss-dsi-v-pulse-width, rc=%d\n", @@ -788,7 +794,7 @@ static int dsi_panel_parse_timing(struct dsi_mode_info *mode, } static int dsi_panel_parse_pixel_format(struct dsi_host_common_cfg *host, - struct device_node *of_node, + struct dsi_parser_utils *utils, const char *name) { int rc = 0; @@ -796,7 +802,7 @@ static int dsi_panel_parse_pixel_format(struct dsi_host_common_cfg *host, enum dsi_pixel_format fmt; const char *packing; - rc = of_property_read_u32(of_node, "qcom,mdss-dsi-bpp", &bpp); + rc = utils->read_u32(utils->data, "qcom,mdss-dsi-bpp", &bpp); if (rc) { pr_err("[%s] failed to read qcom,mdss-dsi-bpp, rc=%d\n", name, rc); @@ -826,7 +832,7 @@ static int dsi_panel_parse_pixel_format(struct dsi_host_common_cfg *host, } if (fmt == DSI_PIXEL_FORMAT_RGB666) { - packing = of_get_property(of_node, + packing = utils->get_property(utils->data, "qcom,mdss-dsi-pixel-packing", NULL); if (packing && !strcmp(packing, "loose")) @@ -838,25 +844,25 @@ static int dsi_panel_parse_pixel_format(struct dsi_host_common_cfg *host, } static int dsi_panel_parse_lane_states(struct dsi_host_common_cfg *host, - struct device_node *of_node, + struct dsi_parser_utils *utils, const char *name) { int rc = 0; bool lane_enabled; - lane_enabled = of_property_read_bool(of_node, + lane_enabled = utils->read_bool(utils->data, "qcom,mdss-dsi-lane-0-state"); host->data_lanes |= (lane_enabled ? DSI_DATA_LANE_0 : 0); - lane_enabled = of_property_read_bool(of_node, + lane_enabled = utils->read_bool(utils->data, "qcom,mdss-dsi-lane-1-state"); host->data_lanes |= (lane_enabled ? DSI_DATA_LANE_1 : 0); - lane_enabled = of_property_read_bool(of_node, + lane_enabled = utils->read_bool(utils->data, "qcom,mdss-dsi-lane-2-state"); host->data_lanes |= (lane_enabled ? DSI_DATA_LANE_2 : 0); - lane_enabled = of_property_read_bool(of_node, + lane_enabled = utils->read_bool(utils->data, "qcom,mdss-dsi-lane-3-state"); host->data_lanes |= (lane_enabled ? DSI_DATA_LANE_3 : 0); @@ -869,13 +875,14 @@ static int dsi_panel_parse_lane_states(struct dsi_host_common_cfg *host, } static int dsi_panel_parse_color_swap(struct dsi_host_common_cfg *host, - struct device_node *of_node, + struct dsi_parser_utils *utils, const char *name) { int rc = 0; const char *swap_mode; - swap_mode = of_get_property(of_node, "qcom,mdss-dsi-color-order", NULL); + swap_mode = utils->get_property(utils->data, + "qcom,mdss-dsi-color-order", NULL); if (swap_mode) { if (!strcmp(swap_mode, "rgb_swap_rgb")) { host->swap_mode = DSI_COLOR_SWAP_RGB; @@ -905,13 +912,14 @@ static int dsi_panel_parse_color_swap(struct dsi_host_common_cfg *host, } static int dsi_panel_parse_triggers(struct dsi_host_common_cfg *host, - struct device_node *of_node, + struct dsi_parser_utils *utils, const char *name) { const char *trig; int rc = 0; - trig = of_get_property(of_node, "qcom,mdss-dsi-mdp-trigger", NULL); + trig = utils->get_property(utils->data, + "qcom,mdss-dsi-mdp-trigger", NULL); if (trig) { if (!strcmp(trig, "none")) { host->mdp_cmd_trigger = DSI_TRIGGER_NONE; @@ -933,7 +941,8 @@ static int dsi_panel_parse_triggers(struct dsi_host_common_cfg *host, host->mdp_cmd_trigger = DSI_TRIGGER_SW; } - trig = of_get_property(of_node, "qcom,mdss-dsi-dma-trigger", NULL); + trig = utils->get_property(utils->data, + "qcom,mdss-dsi-dma-trigger", NULL); if (trig) { if (!strcmp(trig, "none")) { host->dma_cmd_trigger = DSI_TRIGGER_NONE; @@ -956,7 +965,7 @@ static int dsi_panel_parse_triggers(struct dsi_host_common_cfg *host, host->dma_cmd_trigger = DSI_TRIGGER_SW; } - rc = of_property_read_u32(of_node, "qcom,mdss-dsi-te-pin-select", + rc = utils->read_u32(utils->data, "qcom,mdss-dsi-te-pin-select", &host->te_mode); if (rc) { pr_warn("[%s] fallback to default te-pin-select\n", name); @@ -968,13 +977,13 @@ static int dsi_panel_parse_triggers(struct dsi_host_common_cfg *host, } static int dsi_panel_parse_misc_host_config(struct dsi_host_common_cfg *host, - struct device_node *of_node, + struct dsi_parser_utils *utils, const char *name) { u32 val = 0; int rc = 0; - rc = of_property_read_u32(of_node, "qcom,mdss-dsi-t-clk-post", &val); + rc = utils->read_u32(utils->data, "qcom,mdss-dsi-t-clk-post", &val); if (rc) { pr_debug("[%s] Fallback to default t_clk_post value\n", name); host->t_clk_post = 0x03; @@ -984,7 +993,7 @@ static int dsi_panel_parse_misc_host_config(struct dsi_host_common_cfg *host, } val = 0; - rc = of_property_read_u32(of_node, "qcom,mdss-dsi-t-clk-pre", &val); + rc = utils->read_u32(utils->data, "qcom,mdss-dsi-t-clk-pre", &val); if (rc) { pr_debug("[%s] Fallback to default t_clk_pre value\n", name); host->t_clk_pre = 0x24; @@ -993,21 +1002,21 @@ static int dsi_panel_parse_misc_host_config(struct dsi_host_common_cfg *host, pr_debug("[%s] t_clk_pre = %d\n", name, val); } - host->ignore_rx_eot = of_property_read_bool(of_node, + host->ignore_rx_eot = utils->read_bool(utils->data, "qcom,mdss-dsi-rx-eot-ignore"); - host->append_tx_eot = of_property_read_bool(of_node, + host->append_tx_eot = utils->read_bool(utils->data, "qcom,mdss-dsi-tx-eot-append"); return 0; } -static int dsi_panel_parse_host_config(struct dsi_panel *panel, - struct device_node *of_node) +static int dsi_panel_parse_host_config(struct dsi_panel *panel) { int rc = 0; + struct dsi_parser_utils *utils = &panel->utils; - rc = dsi_panel_parse_pixel_format(&panel->host_config, of_node, + rc = dsi_panel_parse_pixel_format(&panel->host_config, utils, panel->name); if (rc) { pr_err("[%s] failed to get pixel format, rc=%d\n", @@ -1015,7 +1024,7 @@ static int dsi_panel_parse_host_config(struct dsi_panel *panel, goto error; } - rc = dsi_panel_parse_lane_states(&panel->host_config, of_node, + rc = dsi_panel_parse_lane_states(&panel->host_config, utils, panel->name); if (rc) { pr_err("[%s] failed to parse lane states, rc=%d\n", @@ -1023,7 +1032,7 @@ static int dsi_panel_parse_host_config(struct dsi_panel *panel, goto error; } - rc = dsi_panel_parse_color_swap(&panel->host_config, of_node, + rc = dsi_panel_parse_color_swap(&panel->host_config, utils, panel->name); if (rc) { pr_err("[%s] failed to parse color swap config, rc=%d\n", @@ -1031,7 +1040,7 @@ static int dsi_panel_parse_host_config(struct dsi_panel *panel, goto error; } - rc = dsi_panel_parse_triggers(&panel->host_config, of_node, + rc = dsi_panel_parse_triggers(&panel->host_config, utils, panel->name); if (rc) { pr_err("[%s] failed to parse triggers, rc=%d\n", @@ -1039,7 +1048,7 @@ static int dsi_panel_parse_host_config(struct dsi_panel *panel, goto error; } - rc = dsi_panel_parse_misc_host_config(&panel->host_config, of_node, + rc = dsi_panel_parse_misc_host_config(&panel->host_config, utils, panel->name); if (rc) { pr_err("[%s] failed to parse misc host config, rc=%d\n", @@ -1051,24 +1060,25 @@ static int dsi_panel_parse_host_config(struct dsi_panel *panel, return rc; } -static int dsi_panel_parse_dfps_caps(struct dsi_dfps_capabilities *dfps_caps, - struct device_node *of_node, - const char *name) +static int dsi_panel_parse_dfps_caps(struct dsi_panel *panel) { int rc = 0; bool supported = false; + struct dsi_dfps_capabilities *dfps_caps = &panel->dfps_caps; + struct dsi_parser_utils *utils = &panel->utils; + const char *name = panel->name; const char *type; u32 val = 0; - supported = of_property_read_bool(of_node, - "qcom,mdss-dsi-pan-enable-dynamic-fps"); + supported = utils->read_bool(utils->data, + "qcom,mdss-dsi-pan-enable-dynamic-fps"); if (!supported) { pr_debug("[%s] DFPS is not supported\n", name); dfps_caps->dfps_support = false; } else { - type = of_get_property(of_node, + type = utils->get_property(utils->data, "qcom,mdss-dsi-pan-fps-update", NULL); if (!type) { @@ -1089,7 +1099,7 @@ static int dsi_panel_parse_dfps_caps(struct dsi_dfps_capabilities *dfps_caps, goto error; } - rc = of_property_read_u32(of_node, + rc = utils->read_u32(utils->data, "qcom,mdss-dsi-min-refresh-rate", &val); if (rc) { @@ -1099,12 +1109,12 @@ static int dsi_panel_parse_dfps_caps(struct dsi_dfps_capabilities *dfps_caps, } dfps_caps->min_refresh_rate = val; - rc = of_property_read_u32(of_node, + rc = utils->read_u32(utils->data, "qcom,mdss-dsi-max-refresh-rate", &val); if (rc) { pr_debug("[%s] Using default refresh rate\n", name); - rc = of_property_read_u32(of_node, + rc = utils->read_u32(utils->data, "qcom,mdss-dsi-panel-framerate", &val); if (rc) { @@ -1133,7 +1143,7 @@ static int dsi_panel_parse_dfps_caps(struct dsi_dfps_capabilities *dfps_caps, } static int dsi_panel_parse_video_host_config(struct dsi_video_engine_cfg *cfg, - struct device_node *of_node, + struct dsi_parser_utils *utils, const char *name) { int rc = 0; @@ -1141,7 +1151,7 @@ static int dsi_panel_parse_video_host_config(struct dsi_video_engine_cfg *cfg, u32 vc_id = 0; u32 val = 0; - rc = of_property_read_u32(of_node, "qcom,mdss-dsi-h-sync-pulse", &val); + rc = utils->read_u32(utils->data, "qcom,mdss-dsi-h-sync-pulse", &val); if (rc) { pr_debug("[%s] fallback to default h-sync-pulse\n", name); cfg->pulse_mode_hsa_he = false; @@ -1156,25 +1166,25 @@ static int dsi_panel_parse_video_host_config(struct dsi_video_engine_cfg *cfg, goto error; } - cfg->hfp_lp11_en = of_property_read_bool(of_node, + cfg->hfp_lp11_en = utils->read_bool(utils->data, "qcom,mdss-dsi-hfp-power-mode"); - cfg->hbp_lp11_en = of_property_read_bool(of_node, + cfg->hbp_lp11_en = utils->read_bool(utils->data, "qcom,mdss-dsi-hbp-power-mode"); - cfg->hsa_lp11_en = of_property_read_bool(of_node, + cfg->hsa_lp11_en = utils->read_bool(utils->data, "qcom,mdss-dsi-hsa-power-mode"); - cfg->last_line_interleave_en = of_property_read_bool(of_node, + cfg->last_line_interleave_en = utils->read_bool(utils->data, "qcom,mdss-dsi-last-line-interleave"); - cfg->eof_bllp_lp11_en = of_property_read_bool(of_node, + cfg->eof_bllp_lp11_en = utils->read_bool(utils->data, "qcom,mdss-dsi-bllp-eof-power-mode"); - cfg->bllp_lp11_en = of_property_read_bool(of_node, + cfg->bllp_lp11_en = utils->read_bool(utils->data, "qcom,mdss-dsi-bllp-power-mode"); - traffic_mode = of_get_property(of_node, + traffic_mode = utils->get_property(utils->data, "qcom,mdss-dsi-traffic-mode", NULL); if (!traffic_mode) { @@ -1193,7 +1203,7 @@ static int dsi_panel_parse_video_host_config(struct dsi_video_engine_cfg *cfg, goto error; } - rc = of_property_read_u32(of_node, "qcom,mdss-dsi-virtual-channel-id", + rc = utils->read_u32(utils->data, "qcom,mdss-dsi-virtual-channel-id", &vc_id); if (rc) { pr_debug("[%s] Fallback to default vc id\n", name); @@ -1207,13 +1217,13 @@ static int dsi_panel_parse_video_host_config(struct dsi_video_engine_cfg *cfg, } static int dsi_panel_parse_cmd_host_config(struct dsi_cmd_engine_cfg *cfg, - struct device_node *of_node, + struct dsi_parser_utils *utils, const char *name) { u32 val = 0; int rc = 0; - rc = of_property_read_u32(of_node, "qcom,mdss-dsi-wr-mem-start", &val); + rc = utils->read_u32(utils->data, "qcom,mdss-dsi-wr-mem-start", &val); if (rc) { pr_debug("[%s] Fallback to default wr-mem-start\n", name); cfg->wr_mem_start = 0x2C; @@ -1222,7 +1232,7 @@ static int dsi_panel_parse_cmd_host_config(struct dsi_cmd_engine_cfg *cfg, } val = 0; - rc = of_property_read_u32(of_node, "qcom,mdss-dsi-wr-mem-continue", + rc = utils->read_u32(utils->data, "qcom,mdss-dsi-wr-mem-continue", &val); if (rc) { pr_debug("[%s] Fallback to default wr-mem-continue\n", name); @@ -1235,7 +1245,7 @@ static int dsi_panel_parse_cmd_host_config(struct dsi_cmd_engine_cfg *cfg, cfg->max_cmd_packets_interleave = 0; val = 0; - rc = of_property_read_u32(of_node, "qcom,mdss-dsi-te-dcs-command", + rc = utils->read_u32(utils->data, "qcom,mdss-dsi-te-dcs-command", &val); if (rc) { pr_debug("[%s] fallback to default te-dcs-cmd\n", name); @@ -1251,7 +1261,7 @@ static int dsi_panel_parse_cmd_host_config(struct dsi_cmd_engine_cfg *cfg, goto error; } - if (of_property_read_u32(of_node, "qcom,mdss-mdp-transfer-time-us", + if (utils->read_u32(utils->data, "qcom,mdss-mdp-transfer-time-us", &val)) { pr_debug("[%s] Fallback to default transfer-time-us\n", name); cfg->mdp_transfer_time_us = DEFAULT_MDP_TRANSFER_TIME; @@ -1263,14 +1273,15 @@ static int dsi_panel_parse_cmd_host_config(struct dsi_cmd_engine_cfg *cfg, return rc; } -static int dsi_panel_parse_panel_mode(struct dsi_panel *panel, - struct device_node *of_node) +static int dsi_panel_parse_panel_mode(struct dsi_panel *panel) { int rc = 0; + struct dsi_parser_utils *utils = &panel->utils; enum dsi_op_mode panel_mode; const char *mode; - mode = of_get_property(of_node, "qcom,mdss-dsi-panel-type", NULL); + mode = utils->get_property(utils->data, + "qcom,mdss-dsi-panel-type", NULL); if (!mode) { pr_debug("[%s] Fallback to default panel mode\n", panel->name); panel_mode = DSI_OP_VIDEO_MODE; @@ -1286,7 +1297,7 @@ static int dsi_panel_parse_panel_mode(struct dsi_panel *panel, if (panel_mode == DSI_OP_VIDEO_MODE) { rc = dsi_panel_parse_video_host_config(&panel->video_config, - of_node, + utils, panel->name); if (rc) { pr_err("[%s] Failed to parse video host cfg, rc=%d\n", @@ -1297,7 +1308,7 @@ static int dsi_panel_parse_panel_mode(struct dsi_panel *panel, if (panel_mode == DSI_OP_CMD_MODE) { rc = dsi_panel_parse_cmd_host_config(&panel->cmd_config, - of_node, + utils, panel->name); if (rc) { pr_err("[%s] Failed to parse cmd host config, rc=%d\n", @@ -1311,17 +1322,17 @@ static int dsi_panel_parse_panel_mode(struct dsi_panel *panel, return rc; } -static int dsi_panel_parse_phy_props(struct dsi_panel_phy_props *props, - struct device_node *of_node, - const char *name) +static int dsi_panel_parse_phy_props(struct dsi_panel *panel) { int rc = 0; u32 val = 0; const char *str; + struct dsi_panel_phy_props *props = &panel->phy_props; + struct dsi_parser_utils *utils = &panel->utils; + const char *name = panel->name; - rc = of_property_read_u32(of_node, - "qcom,mdss-pan-physical-width-dimension", - &val); + rc = utils->read_u32(utils->data, + "qcom,mdss-pan-physical-width-dimension", &val); if (rc) { pr_debug("[%s] Physical panel width is not defined\n", name); props->panel_width_mm = 0; @@ -1330,7 +1341,7 @@ static int dsi_panel_parse_phy_props(struct dsi_panel_phy_props *props, props->panel_width_mm = val; } - rc = of_property_read_u32(of_node, + rc = utils->read_u32(utils->data, "qcom,mdss-pan-physical-height-dimension", &val); if (rc) { @@ -1341,7 +1352,8 @@ static int dsi_panel_parse_phy_props(struct dsi_panel_phy_props *props, props->panel_height_mm = val; } - str = of_get_property(of_node, "qcom,mdss-dsi-panel-orientation", NULL); + str = utils->get_property(utils->data, + "qcom,mdss-dsi-panel-orientation", NULL); if (!str) { props->rotation = DSI_PANEL_ROTATE_NONE; } else if (!strcmp(str, "180")) { @@ -1504,7 +1516,7 @@ static int dsi_panel_alloc_cmd_packets(struct dsi_panel_cmd_set *cmd, static int dsi_panel_parse_cmd_sets_sub(struct dsi_panel_cmd_set *cmd, enum dsi_cmd_set_type type, - struct device_node *of_node) + struct dsi_parser_utils *utils) { int rc = 0; u32 length = 0; @@ -1512,13 +1524,20 @@ static int dsi_panel_parse_cmd_sets_sub(struct dsi_panel_cmd_set *cmd, const char *state; u32 packet_count = 0; - data = of_get_property(of_node, cmd_set_prop_map[type], &length); + data = utils->get_property(utils->data, cmd_set_prop_map[type], + &length); if (!data) { pr_debug("%s commands not defined\n", cmd_set_prop_map[type]); rc = -ENOTSUPP; goto error; } + pr_debug("type=%d, name=%s, length=%d\n", type, + cmd_set_prop_map[type], length); + + print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_NONE, + 8, 1, data, length, false); + rc = dsi_panel_get_cmd_pkt_count(data, length, &packet_count); if (rc) { pr_err("commands failed, rc=%d\n", rc); @@ -1540,7 +1559,7 @@ static int dsi_panel_parse_cmd_sets_sub(struct dsi_panel_cmd_set *cmd, goto error_free_mem; } - state = of_get_property(of_node, cmd_set_state_map[type], NULL); + state = utils->get_property(utils->data, cmd_set_state_map[type], NULL); if (!state || !strcmp(state, "dsi_lp_mode")) { cmd->state = DSI_CMD_SET_STATE_LP; } else if (!strcmp(state, "dsi_hs_mode")) { @@ -1562,7 +1581,7 @@ static int dsi_panel_parse_cmd_sets_sub(struct dsi_panel_cmd_set *cmd, static int dsi_panel_parse_cmd_sets( struct dsi_display_mode_priv_info *priv_info, - struct device_node *of_node) + struct dsi_parser_utils *utils) { int rc = 0; struct dsi_panel_cmd_set *set; @@ -1585,7 +1604,7 @@ static int dsi_panel_parse_cmd_sets( i, rc); set->state = DSI_CMD_SET_STATE_LP; } else { - rc = dsi_panel_parse_cmd_sets_sub(set, i, of_node); + rc = dsi_panel_parse_cmd_sets_sub(set, i, utils); if (rc) pr_debug("failed to parse set %d\n", i); } @@ -1595,8 +1614,7 @@ static int dsi_panel_parse_cmd_sets( return rc; } -static int dsi_panel_parse_reset_sequence(struct dsi_panel *panel, - struct device_node *of_node) +static int dsi_panel_parse_reset_sequence(struct dsi_panel *panel) { int rc = 0; int i; @@ -1605,9 +1623,11 @@ static int dsi_panel_parse_reset_sequence(struct dsi_panel *panel, u32 size = 0; u32 *arr_32 = NULL; const u32 *arr; + struct dsi_parser_utils *utils = &panel->utils; struct dsi_reset_seq *seq; - arr = of_get_property(of_node, "qcom,mdss-dsi-reset-sequence", &length); + arr = utils->get_property(utils->data, + "qcom,mdss-dsi-reset-sequence", &length); if (!arr) { pr_err("[%s] dsi-reset-sequence not found\n", panel->name); rc = -EINVAL; @@ -1631,7 +1651,7 @@ static int dsi_panel_parse_reset_sequence(struct dsi_panel *panel, goto error; } - rc = of_property_read_u32_array(of_node, "qcom,mdss-dsi-reset-sequence", + rc = utils->read_u32_array(utils->data, "qcom,mdss-dsi-reset-sequence", arr_32, length); if (rc) { pr_err("[%s] cannot read dso-reset-seqience\n", panel->name); @@ -1662,32 +1682,33 @@ static int dsi_panel_parse_reset_sequence(struct dsi_panel *panel, return rc; } -static int dsi_panel_parse_misc_features(struct dsi_panel *panel, - struct device_node *of_node) +static int dsi_panel_parse_misc_features(struct dsi_panel *panel) { + struct dsi_parser_utils *utils = &panel->utils; + panel->ulps_enabled = - of_property_read_bool(of_node, "qcom,ulps-enabled"); + utils->read_bool(utils->data, "qcom,ulps-enabled"); pr_info("%s: ulps feature %s\n", __func__, (panel->ulps_enabled ? "enabled" : "disabled")); panel->ulps_suspend_enabled = - of_property_read_bool(of_node, "qcom,suspend-ulps-enabled"); + utils->read_bool(utils->data, "qcom,suspend-ulps-enabled"); pr_info("%s: ulps during suspend feature %s", __func__, (panel->ulps_suspend_enabled ? "enabled" : "disabled")); - panel->te_using_watchdog_timer = of_property_read_bool(of_node, + panel->te_using_watchdog_timer = utils->read_bool(utils->data, "qcom,mdss-dsi-te-using-wd"); - panel->sync_broadcast_en = of_property_read_bool(of_node, + panel->sync_broadcast_en = utils->read_bool(utils->data, "qcom,cmd-sync-wait-broadcast"); return 0; } static int dsi_panel_parse_jitter_config( struct dsi_display_mode *mode, - struct device_node *of_node) + struct dsi_parser_utils *utils) { int rc; struct dsi_display_mode_priv_info *priv_info; @@ -1696,7 +1717,7 @@ static int dsi_panel_parse_jitter_config( priv_info = mode->priv_info; - rc = of_property_read_u32_array(of_node, "qcom,mdss-dsi-panel-jitter", + rc = utils->read_u32_array(utils->data, "qcom,mdss-dsi-panel-jitter", jitter, DEFAULT_PANEL_JITTER_ARRAY_SIZE); if (rc) { pr_debug("panel jitter not defined rc=%d\n", rc); @@ -1714,7 +1735,7 @@ static int dsi_panel_parse_jitter_config( priv_info->panel_jitter_denom = jitter[1]; } - rc = of_property_read_u32(of_node, "qcom,mdss-dsi-panel-prefill-lines", + rc = utils->read_u32(utils->data, "qcom,mdss-dsi-panel-prefill-lines", &priv_info->panel_prefill_lines); if (rc) { pr_debug("panel prefill lines are not defined rc=%d\n", rc); @@ -1730,15 +1751,13 @@ static int dsi_panel_parse_jitter_config( return 0; } -static int dsi_panel_parse_power_cfg(struct device *parent, - struct dsi_panel *panel, - struct device_node *of_node) +static int dsi_panel_parse_power_cfg(struct dsi_panel *panel) { int rc = 0; - rc = dsi_pwr_of_get_vreg_data(of_node, - &panel->power_info, - "qcom,panel-supply-entries"); + rc = dsi_pwr_of_get_vreg_data(&panel->utils, + &panel->power_info, + "qcom,panel-supply-entries"); if (rc) { pr_err("[%s] failed to parse vregs\n", panel->name); goto error; @@ -1748,42 +1767,43 @@ static int dsi_panel_parse_power_cfg(struct device *parent, return rc; } -static int dsi_panel_parse_gpios(struct dsi_panel *panel, - struct device_node *of_node) +static int dsi_panel_parse_gpios(struct dsi_panel *panel) { int rc = 0; const char *data; + struct dsi_parser_utils *utils = &panel->utils; - panel->reset_config.reset_gpio = of_get_named_gpio(of_node, - "qcom,platform-reset-gpio", - 0); + panel->reset_config.reset_gpio = utils->get_named_gpio(utils->data, + "qcom,platform-reset-gpio", 0); if (!gpio_is_valid(panel->reset_config.reset_gpio)) { pr_err("[%s] failed get reset gpio, rc=%d\n", panel->name, rc); rc = -EINVAL; goto error; } - panel->reset_config.disp_en_gpio = of_get_named_gpio(of_node, + panel->reset_config.disp_en_gpio = utils->get_named_gpio(utils->data, "qcom,5v-boost-gpio", 0); if (!gpio_is_valid(panel->reset_config.disp_en_gpio)) { pr_debug("[%s] 5v-boot-gpio is not set, rc=%d\n", panel->name, rc); - panel->reset_config.disp_en_gpio = of_get_named_gpio(of_node, - "qcom,platform-en-gpio", - 0); + panel->reset_config.disp_en_gpio = + utils->get_named_gpio(utils->data, + "qcom,platform-en-gpio", 0); if (!gpio_is_valid(panel->reset_config.disp_en_gpio)) { pr_debug("[%s] platform-en-gpio is not set, rc=%d\n", panel->name, rc); } } - panel->reset_config.lcd_mode_sel_gpio = of_get_named_gpio(of_node, - "qcom,panel-mode-gpio", 0); + panel->reset_config.lcd_mode_sel_gpio = utils->get_named_gpio( + utils->data, "qcom,panel-mode-gpio", 0); if (!gpio_is_valid(panel->reset_config.lcd_mode_sel_gpio)) pr_debug("%s:%d mode gpio not specified\n", __func__, __LINE__); - data = of_get_property(of_node, + pr_err("mode gpio=%d\n", panel->reset_config.lcd_mode_sel_gpio); + + data = utils->get_property(utils->data, "qcom,mdss-dsi-mode-sel-gpio-state", NULL); if (data) { if (!strcmp(data, "single_port")) @@ -1804,7 +1824,7 @@ static int dsi_panel_parse_gpios(struct dsi_panel *panel, } /* TODO: release memory */ - rc = dsi_panel_parse_reset_sequence(panel, of_node); + rc = dsi_panel_parse_reset_sequence(panel); if (rc) { pr_err("[%s] failed to parse reset sequence, rc=%d\n", panel->name, rc); @@ -1815,13 +1835,14 @@ static int dsi_panel_parse_gpios(struct dsi_panel *panel, return rc; } -static int dsi_panel_parse_bl_pwm_config(struct dsi_backlight_config *config, - struct device_node *of_node) +static int dsi_panel_parse_bl_pwm_config(struct dsi_panel *panel) { int rc = 0; u32 val; + struct dsi_backlight_config *config = &panel->bl_config; + struct dsi_parser_utils *utils = &panel->utils; - rc = of_property_read_u32(of_node, "qcom,dsi-bl-pmic-bank-select", + rc = utils->read_u32(utils->data, "qcom,dsi-bl-pmic-bank-select", &val); if (rc) { pr_err("bl-pmic-bank-select is not defined, rc=%d\n", rc); @@ -1829,7 +1850,7 @@ static int dsi_panel_parse_bl_pwm_config(struct dsi_backlight_config *config, } config->pwm_pmic_bank = val; - rc = of_property_read_u32(of_node, "qcom,dsi-bl-pmic-pwm-frequency", + rc = utils->read_u32(utils->data, "qcom,dsi-bl-pmic-pwm-frequency", &val); if (rc) { pr_err("bl-pmic-bank-select is not defined, rc=%d\n", rc); @@ -1837,10 +1858,10 @@ static int dsi_panel_parse_bl_pwm_config(struct dsi_backlight_config *config, } config->pwm_period_usecs = val; - config->pwm_pmi_control = of_property_read_bool(of_node, + config->pwm_pmi_control = utils->read_bool(utils->data, "qcom,mdss-dsi-bl-pwm-pmi"); - config->pwm_gpio = of_get_named_gpio(of_node, + config->pwm_gpio = utils->get_named_gpio(utils->data, "qcom,mdss-dsi-pwm-gpio", 0); if (!gpio_is_valid(config->pwm_gpio)) { @@ -1853,14 +1874,14 @@ static int dsi_panel_parse_bl_pwm_config(struct dsi_backlight_config *config, return rc; } -static int dsi_panel_parse_bl_config(struct dsi_panel *panel, - struct device_node *of_node) +static int dsi_panel_parse_bl_config(struct dsi_panel *panel) { int rc = 0; - const char *bl_type; u32 val = 0; + const char *bl_type; + struct dsi_parser_utils *utils = &panel->utils; - bl_type = of_get_property(of_node, + bl_type = utils->get_property(utils->data, "qcom,mdss-dsi-bl-pmic-control-type", NULL); if (!bl_type) { @@ -1880,7 +1901,7 @@ static int dsi_panel_parse_bl_config(struct dsi_panel *panel, panel->bl_config.bl_scale = MAX_BL_SCALE_LEVEL; panel->bl_config.bl_scale_ad = MAX_AD_BL_SCALE_LEVEL; - rc = of_property_read_u32(of_node, "qcom,mdss-dsi-bl-min-level", &val); + rc = utils->read_u32(utils->data, "qcom,mdss-dsi-bl-min-level", &val); if (rc) { pr_debug("[%s] bl-min-level unspecified, defaulting to zero\n", panel->name); @@ -1889,7 +1910,7 @@ static int dsi_panel_parse_bl_config(struct dsi_panel *panel, panel->bl_config.bl_min_level = val; } - rc = of_property_read_u32(of_node, "qcom,mdss-dsi-bl-max-level", &val); + rc = utils->read_u32(utils->data, "qcom,mdss-dsi-bl-max-level", &val); if (rc) { pr_debug("[%s] bl-max-level unspecified, defaulting to max level\n", panel->name); @@ -1898,7 +1919,7 @@ static int dsi_panel_parse_bl_config(struct dsi_panel *panel, panel->bl_config.bl_max_level = val; } - rc = of_property_read_u32(of_node, "qcom,mdss-brightness-max-level", + rc = utils->read_u32(utils->data, "qcom,mdss-brightness-max-level", &val); if (rc) { pr_debug("[%s] brigheness-max-level unspecified, defaulting to 255\n", @@ -1909,7 +1930,7 @@ static int dsi_panel_parse_bl_config(struct dsi_panel *panel, } if (panel->bl_config.type == DSI_BACKLIGHT_PWM) { - rc = dsi_panel_parse_bl_pwm_config(&panel->bl_config, of_node); + rc = dsi_panel_parse_bl_pwm_config(panel); if (rc) { pr_err("[%s] failed to parse pwm config, rc=%d\n", panel->name, rc); @@ -1917,7 +1938,7 @@ static int dsi_panel_parse_bl_config(struct dsi_panel *panel, } } - panel->bl_config.en_gpio = of_get_named_gpio(of_node, + panel->bl_config.en_gpio = utils->get_named_gpio(utils->data, "qcom,platform-bklight-en-gpio", 0); if (!gpio_is_valid(panel->bl_config.en_gpio)) { @@ -2116,7 +2137,7 @@ int dsi_dsc_populate_static_param(struct msm_display_dsc_info *dsc) static int dsi_panel_parse_phy_timing(struct dsi_display_mode *mode, - struct device_node *of_node) + struct dsi_parser_utils *utils) { const char *data; u32 len, i; @@ -2125,7 +2146,7 @@ static int dsi_panel_parse_phy_timing(struct dsi_display_mode *mode, priv_info = mode->priv_info; - data = of_get_property(of_node, + data = utils->get_property(utils->data, "qcom,mdss-dsi-panel-phy-timings", &len); if (!data) { pr_debug("Unable to read Phy timing settings"); @@ -2148,7 +2169,7 @@ static int dsi_panel_parse_phy_timing(struct dsi_display_mode *mode, } static int dsi_panel_parse_dsc_params(struct dsi_display_mode *mode, - struct device_node *of_node) + struct dsi_parser_utils *utils) { u32 data; int rc = -EINVAL; @@ -2162,7 +2183,8 @@ static int dsi_panel_parse_dsc_params(struct dsi_display_mode *mode, priv_info = mode->priv_info; priv_info->dsc_enabled = false; - compression = of_get_property(of_node, "qcom,compression-mode", NULL); + compression = utils->get_property(utils->data, + "qcom,compression-mode", NULL); if (compression && !strcmp(compression, "dsc")) priv_info->dsc_enabled = true; @@ -2171,14 +2193,14 @@ static int dsi_panel_parse_dsc_params(struct dsi_display_mode *mode, return 0; } - rc = of_property_read_u32(of_node, "qcom,mdss-dsc-slice-height", &data); + rc = utils->read_u32(utils->data, "qcom,mdss-dsc-slice-height", &data); if (rc) { pr_err("failed to parse qcom,mdss-dsc-slice-height\n"); goto error; } priv_info->dsc.slice_height = data; - rc = of_property_read_u32(of_node, "qcom,mdss-dsc-slice-width", &data); + rc = utils->read_u32(utils->data, "qcom,mdss-dsc-slice-width", &data); if (rc) { pr_err("failed to parse qcom,mdss-dsc-slice-width\n"); goto error; @@ -2196,7 +2218,7 @@ static int dsi_panel_parse_dsc_params(struct dsi_display_mode *mode, priv_info->dsc.pic_width = mode->timing.h_active; priv_info->dsc.pic_height = mode->timing.v_active; - rc = of_property_read_u32(of_node, "qcom,mdss-dsc-slice-per-pkt", + rc = utils->read_u32(utils->data, "qcom,mdss-dsc-slice-per-pkt", &data); if (rc) { pr_err("failed to parse qcom,mdss-dsc-slice-per-pkt\n"); @@ -2204,7 +2226,7 @@ static int dsi_panel_parse_dsc_params(struct dsi_display_mode *mode, } priv_info->dsc.slice_per_pkt = data; - rc = of_property_read_u32(of_node, "qcom,mdss-dsc-bit-per-component", + rc = utils->read_u32(utils->data, "qcom,mdss-dsc-bit-per-component", &data); if (rc) { pr_err("failed to parse qcom,mdss-dsc-bit-per-component\n"); @@ -2212,7 +2234,7 @@ static int dsi_panel_parse_dsc_params(struct dsi_display_mode *mode, } priv_info->dsc.bpc = data; - rc = of_property_read_u32(of_node, "qcom,mdss-dsc-bit-per-pixel", + rc = utils->read_u32(utils->data, "qcom,mdss-dsc-bit-per-pixel", &data); if (rc) { pr_err("failed to parse qcom,mdss-dsc-bit-per-pixel\n"); @@ -2220,7 +2242,7 @@ static int dsi_panel_parse_dsc_params(struct dsi_display_mode *mode, } priv_info->dsc.bpp = data; - priv_info->dsc.block_pred_enable = of_property_read_bool(of_node, + priv_info->dsc.block_pred_enable = utils->read_bool(utils->data, "qcom,mdss-dsc-block-prediction-enable"); priv_info->dsc.full_frame_slices = DIV_ROUND_UP(intf_width, @@ -2233,19 +2255,18 @@ static int dsi_panel_parse_dsc_params(struct dsi_display_mode *mode, return rc; } -static int dsi_panel_parse_hdr_config(struct dsi_panel *panel, - struct device_node *of_node) +static int dsi_panel_parse_hdr_config(struct dsi_panel *panel) { - int rc = 0; struct drm_panel_hdr_properties *hdr_prop; + struct dsi_parser_utils *utils = &panel->utils; hdr_prop = &panel->hdr_props; - hdr_prop->hdr_enabled = of_property_read_bool(of_node, + hdr_prop->hdr_enabled = utils->read_bool(utils->data, "qcom,mdss-dsi-panel-hdr-enabled"); if (hdr_prop->hdr_enabled) { - rc = of_property_read_u32_array(of_node, + rc = utils->read_u32_array(utils->data, "qcom,mdss-dsi-panel-hdr-color-primaries", hdr_prop->display_primaries, DISPLAY_PRIMARIES_MAX); @@ -2256,7 +2277,7 @@ static int dsi_panel_parse_hdr_config(struct dsi_panel *panel, return rc; } - rc = of_property_read_u32(of_node, + rc = utils->read_u32(utils->data, "qcom,mdss-dsi-panel-peak-brightness", &(hdr_prop->peak_brightness)); if (rc) { @@ -2266,7 +2287,7 @@ static int dsi_panel_parse_hdr_config(struct dsi_panel *panel, return rc; } - rc = of_property_read_u32(of_node, + rc = utils->read_u32(utils->data, "qcom,mdss-dsi-panel-blackness-level", &(hdr_prop->blackness_level)); if (rc) { @@ -2281,14 +2302,15 @@ static int dsi_panel_parse_hdr_config(struct dsi_panel *panel, static int dsi_panel_parse_topology( struct dsi_display_mode_priv_info *priv_info, - struct device_node *of_node, int topology_override) + struct dsi_parser_utils *utils, + int topology_override) { struct msm_display_topology *topology; u32 top_count, top_sel, *array = NULL; int i, len = 0; int rc = -EINVAL; - len = of_property_count_u32_elems(of_node, "qcom,display-topology"); + len = utils->count_u32_elems(utils->data, "qcom,display-topology"); if (len <= 0 || len % TOPOLOGY_SET_LEN || len > (TOPOLOGY_SET_LEN * MAX_TOPOLOGY)) { pr_err("invalid topology list for the panel, rc = %d\n", rc); @@ -2301,7 +2323,7 @@ static int dsi_panel_parse_topology( if (!array) return -ENOMEM; - rc = of_property_read_u32_array(of_node, + rc = utils->read_u32_array(utils->data, "qcom,display-topology", array, len); if (rc) { pr_err("unable to read the display topologies, rc = %d\n", rc); @@ -2332,7 +2354,7 @@ static int dsi_panel_parse_topology( goto parse_done; } - rc = of_property_read_u32(of_node, + rc = utils->read_u32(utils->data, "qcom,default-topology-index", &top_sel); if (rc) { pr_err("no default topology selected, rc = %d\n", rc); @@ -2362,19 +2384,20 @@ static int dsi_panel_parse_topology( return rc; } -static int dsi_panel_parse_roi_alignment(struct device_node *of_node, +static int dsi_panel_parse_roi_alignment(struct dsi_parser_utils *utils, struct msm_roi_alignment *align) { int len = 0, rc = 0; u32 value[6]; struct property *data; - if (!align || !of_node) + if (!align) return -EINVAL; memset(align, 0, sizeof(*align)); - data = of_find_property(of_node, "qcom,panel-roi-alignment", &len); + data = utils->find_property(utils->data, + "qcom,panel-roi-alignment", &len); len /= sizeof(u32); if (!data) { pr_err("panel roi alignment not found\n"); @@ -2383,7 +2406,7 @@ static int dsi_panel_parse_roi_alignment(struct device_node *of_node, pr_err("incorrect roi alignment len %d\n", len); rc = -EINVAL; } else { - rc = of_property_read_u32_array(of_node, + rc = utils->read_u32_array(utils->data, "qcom,panel-roi-alignment", value, len); if (rc) pr_debug("error reading panel roi alignment values\n"); @@ -2409,7 +2432,7 @@ static int dsi_panel_parse_roi_alignment(struct device_node *of_node, } static int dsi_panel_parse_partial_update_caps(struct dsi_display_mode *mode, - struct device_node *of_node) + struct dsi_parser_utils *utils) { struct msm_roi_caps *roi_caps = NULL; const char *data; @@ -2424,7 +2447,8 @@ static int dsi_panel_parse_partial_update_caps(struct dsi_display_mode *mode, memset(roi_caps, 0, sizeof(*roi_caps)); - data = of_get_property(of_node, "qcom,partial-update-enabled", NULL); + data = utils->get_property(utils->data, + "qcom,partial-update-enabled", NULL); if (data) { if (!strcmp(data, "dual_roi")) roi_caps->num_roi = 2; @@ -2441,7 +2465,7 @@ static int dsi_panel_parse_partial_update_caps(struct dsi_display_mode *mode, return 0; } - roi_caps->merge_rois = of_property_read_bool(of_node, + roi_caps->merge_rois = utils->read_bool(utils->data, "qcom,partial-update-roi-merge"); roi_caps->enabled = roi_caps->num_roi > 0; @@ -2450,7 +2474,7 @@ static int dsi_panel_parse_partial_update_caps(struct dsi_display_mode *mode, roi_caps->enabled); if (roi_caps->enabled) - rc = dsi_panel_parse_roi_alignment(of_node, + rc = dsi_panel_parse_roi_alignment(utils, &roi_caps->align); if (rc) @@ -2459,24 +2483,20 @@ static int dsi_panel_parse_partial_update_caps(struct dsi_display_mode *mode, return rc; } -static int dsi_panel_parse_dms_info(struct dsi_panel *panel, - struct device_node *of_node) +static int dsi_panel_parse_dms_info(struct dsi_panel *panel) { int dms_enabled; const char *data; - - if (!of_node || !panel) { - pr_err("invalid params\n"); - return -EINVAL; - } + struct dsi_parser_utils *utils = &panel->utils; panel->dms_mode = DSI_DMS_MODE_DISABLED; - dms_enabled = of_property_read_bool(of_node, + dms_enabled = utils->read_bool(utils->data, "qcom,dynamic-mode-switch-enabled"); if (!dms_enabled) return 0; - data = of_get_property(of_node, "qcom,dynamic-mode-switch-type", NULL); + data = utils->get_property(utils->data, + "qcom,dynamic-mode-switch-type", NULL); if (data && !strcmp(data, "dynamic-resolution-switch-immediate")) { panel->dms_mode = DSI_DMS_MODE_RES_SWITCH_IMMEDIATE; } else { @@ -2509,12 +2529,12 @@ dsi_panel_parse_esd_check_valid_params(struct dsi_panel *panel, u32 count) return true; } -static bool dsi_panel_parse_esd_status_len(struct device_node *np, +static bool dsi_panel_parse_esd_status_len(struct dsi_parser_utils *utils, char *prop_key, u32 **target, u32 cmd_cnt) { int tmp; - if (!of_find_property(np, prop_key, &tmp)) + if (!utils->find_property(utils->data, prop_key, &tmp)) return false; tmp /= sizeof(u32); @@ -2530,7 +2550,7 @@ static bool dsi_panel_parse_esd_status_len(struct device_node *np, return false; } - if (of_property_read_u32_array(np, prop_key, *target, tmp)) { + if (utils->read_u32_array(utils->data, prop_key, *target, tmp)) { pr_err("cannot get values from dts\n"); kfree(*target); *target = NULL; @@ -2550,8 +2570,7 @@ static void dsi_panel_esd_config_deinit(struct drm_panel_esd_config *esd_config) kfree(esd_config->status_cmd.cmds); } -static int dsi_panel_parse_esd_config(struct dsi_panel *panel, - struct device_node *of_node) +static int dsi_panel_parse_esd_config(struct dsi_panel *panel) { int rc = 0; u32 tmp; @@ -2559,17 +2578,18 @@ static int dsi_panel_parse_esd_config(struct dsi_panel *panel, struct property *data; const char *string; struct drm_panel_esd_config *esd_config; + struct dsi_parser_utils *utils = &panel->utils; u8 *esd_mode = NULL; esd_config = &panel->esd_config; esd_config->status_mode = ESD_MODE_MAX; - esd_config->esd_enabled = of_property_read_bool(of_node, - "qcom,esd-check-enabled"); + esd_config->esd_enabled = utils->read_bool(utils->data, + "qcom,esd-check-enabled"); if (!esd_config->esd_enabled) return 0; - rc = of_property_read_string(of_node, + rc = utils->read_string(utils->data, "qcom,mdss-dsi-panel-status-check-mode", &string); if (!rc) { if (!strcmp(string, "bta_check")) { @@ -2600,14 +2620,14 @@ static int dsi_panel_parse_esd_config(struct dsi_panel *panel, return 0; dsi_panel_parse_cmd_sets_sub(&esd_config->status_cmd, - DSI_CMD_SET_PANEL_STATUS, of_node); + DSI_CMD_SET_PANEL_STATUS, utils); if (!esd_config->status_cmd.count) { pr_err("panel status command parsing failed\n"); rc = -EINVAL; goto error; } - if (!dsi_panel_parse_esd_status_len(of_node, + if (!dsi_panel_parse_esd_status_len(utils, "qcom,mdss-dsi-panel-status-read-length", &panel->esd_config.status_cmds_rlen, esd_config->status_cmd.count)) { @@ -2616,7 +2636,7 @@ static int dsi_panel_parse_esd_config(struct dsi_panel *panel, goto error1; } - if (dsi_panel_parse_esd_status_len(of_node, + if (dsi_panel_parse_esd_status_len(utils, "qcom,mdss-dsi-panel-status-valid-params", &panel->esd_config.status_valid_params, esd_config->status_cmd.count)) { @@ -2645,7 +2665,7 @@ static int dsi_panel_parse_esd_config(struct dsi_panel *panel, * commands are there then, there should be corresponding * status check values for each read command. */ - data = of_find_property(of_node, + data = utils->find_property(utils->data, "qcom,mdss-dsi-panel-status-value", &tmp); tmp /= sizeof(u32); if (!IS_ERR_OR_NULL(data) && tmp != 0 && (tmp % status_len) == 0) { @@ -2675,7 +2695,7 @@ static int dsi_panel_parse_esd_config(struct dsi_panel *panel, if (!esd_config->status_buf) goto error4; - rc = of_property_read_u32_array(of_node, + rc = utils->read_u32_array(utils->data, "qcom,mdss-dsi-panel-status-value", esd_config->status_value, esd_config->groups * status_len); if (rc) { @@ -2709,83 +2729,112 @@ static int dsi_panel_parse_esd_config(struct dsi_panel *panel, return rc; } +static void dsi_panel_update_util(struct dsi_panel *panel, + struct device_node *parser_node) +{ + struct dsi_parser_utils *utils = &panel->utils; + + if (parser_node) { + *utils = *dsi_parser_get_parser_utils(); + utils->data = parser_node; + + pr_debug("switching to parser APIs\n"); + + goto end; + } + + *utils = *dsi_parser_get_of_utils(); + utils->data = panel->panel_of_node; +end: + utils->node = panel->panel_of_node; +} + struct dsi_panel *dsi_panel_get(struct device *parent, struct device_node *of_node, + struct device_node *parser_node, + struct dentry *root, int topology_override) { struct dsi_panel *panel; + struct dsi_parser_utils *utils; int rc = 0; panel = kzalloc(sizeof(*panel), GFP_KERNEL); if (!panel) return ERR_PTR(-ENOMEM); - panel->name = of_get_property(of_node, "qcom,mdss-dsi-panel-name", - NULL); + panel->panel_of_node = of_node; + panel->parent = parent; + panel->root = root; + + dsi_panel_update_util(panel, parser_node); + utils = &panel->utils; + + panel->name = utils->get_property(utils->data, + "qcom,mdss-dsi-panel-name", NULL); if (!panel->name) panel->name = DSI_PANEL_DEFAULT_LABEL; - rc = dsi_panel_parse_host_config(panel, of_node); + rc = dsi_panel_parse_host_config(panel); if (rc) { pr_err("failed to parse host configuration, rc=%d\n", rc); goto error; } - rc = dsi_panel_parse_panel_mode(panel, of_node); + rc = dsi_panel_parse_panel_mode(panel); if (rc) { pr_err("failed to parse panel mode configuration, rc=%d\n", rc); goto error; } - rc = dsi_panel_parse_dfps_caps(&panel->dfps_caps, of_node, panel->name); + rc = dsi_panel_parse_dfps_caps(panel); if (rc) pr_err("failed to parse dfps configuration, rc=%d\n", rc); - rc = dsi_panel_parse_phy_props(&panel->phy_props, of_node, panel->name); + rc = dsi_panel_parse_phy_props(panel); if (rc) { pr_err("failed to parse panel physical dimension, rc=%d\n", rc); goto error; } - rc = dsi_panel_parse_power_cfg(parent, panel, of_node); + rc = dsi_panel_parse_power_cfg(panel); if (rc) pr_err("failed to parse power config, rc=%d\n", rc); - rc = dsi_panel_parse_gpios(panel, of_node); + rc = dsi_panel_parse_gpios(panel); if (rc) pr_err("failed to parse panel gpios, rc=%d\n", rc); - rc = dsi_panel_parse_bl_config(panel, of_node); + rc = dsi_panel_parse_bl_config(panel); if (rc) pr_err("failed to parse backlight config, rc=%d\n", rc); - rc = dsi_panel_parse_misc_features(panel, of_node); + rc = dsi_panel_parse_misc_features(panel); if (rc) pr_err("failed to parse misc features, rc=%d\n", rc); - rc = dsi_panel_parse_hdr_config(panel, of_node); + rc = dsi_panel_parse_hdr_config(panel); if (rc) pr_err("failed to parse hdr config, rc=%d\n", rc); - rc = dsi_panel_get_mode_count(panel, of_node); + rc = dsi_panel_get_mode_count(panel); if (rc) { pr_err("failed to get mode count, rc=%d\n", rc); goto error; } - rc = dsi_panel_parse_dms_info(panel, of_node); + rc = dsi_panel_parse_dms_info(panel); if (rc) pr_debug("failed to get dms info, rc=%d\n", rc); - rc = dsi_panel_parse_esd_config(panel, of_node); + rc = dsi_panel_parse_esd_config(panel); if (rc) pr_debug("failed to parse esd config, rc=%d\n", rc); - panel->panel_of_node = of_node; drm_panel_init(&panel->drm_panel); mutex_init(&panel->panel_lock); - panel->parent = parent; + return panel; error: kfree(panel); @@ -2909,21 +2958,23 @@ int dsi_panel_validate_mode(struct dsi_panel *panel, return 0; } -int dsi_panel_get_mode_count(struct dsi_panel *panel, - struct device_node *of_node) +int dsi_panel_get_mode_count(struct dsi_panel *panel) { const u32 SINGLE_MODE_SUPPORT = 1; + struct dsi_parser_utils *utils; struct device_node *timings_np; int count, rc = 0; - if (!of_node || !panel) { + if (!panel) { pr_err("invalid params\n"); return -EINVAL; } + utils = &panel->utils; + panel->num_timing_nodes = 0; - timings_np = of_get_child_by_name(of_node, + timings_np = utils->get_child_by_name(utils->data, "qcom,mdss-dsi-display-timings"); if (!timings_np) { pr_err("no display timing nodes defined\n"); @@ -2931,7 +2982,7 @@ int dsi_panel_get_mode_count(struct dsi_panel *panel, goto error; } - count = of_get_child_count(timings_np); + count = utils->get_child_count(timings_np); if (!count || count > DSI_MODE_MAX) { pr_err("invalid count of timing nodes: %d\n", count); rc = -EINVAL; @@ -3002,9 +3053,11 @@ int dsi_panel_get_mode(struct dsi_panel *panel, int topology_override) { struct device_node *timings_np, *child_np; + struct dsi_parser_utils *utils; struct dsi_display_mode_priv_info *prv_info; u32 child_idx = 0; int rc = 0, num_timings; + void *utils_data = NULL; if (!panel || !mode) { pr_err("invalid params\n"); @@ -3012,6 +3065,7 @@ int dsi_panel_get_mode(struct dsi_panel *panel, } mutex_lock(&panel->panel_lock); + utils = &panel->utils; mode->priv_info = kzalloc(sizeof(*mode->priv_info), GFP_KERNEL); if (!mode->priv_info) { @@ -3021,7 +3075,7 @@ int dsi_panel_get_mode(struct dsi_panel *panel, prv_info = mode->priv_info; - timings_np = of_get_child_by_name(panel->panel_of_node, + timings_np = utils->get_child_by_name(utils->data, "qcom,mdss-dsi-display-timings"); if (!timings_np) { pr_err("no display timing nodes defined\n"); @@ -3029,55 +3083,59 @@ int dsi_panel_get_mode(struct dsi_panel *panel, goto parse_fail; } - num_timings = of_get_child_count(timings_np); + num_timings = utils->get_child_count(timings_np); if (!num_timings || num_timings > DSI_MODE_MAX) { pr_err("invalid count of timing nodes: %d\n", num_timings); rc = -EINVAL; goto parse_fail; } - for_each_child_of_node(timings_np, child_np) { + utils_data = utils->data; + + dsi_for_each_child_node(timings_np, child_np) { if (index != child_idx++) continue; - rc = dsi_panel_parse_timing(&mode->timing, child_np); + utils->data = child_np; + + rc = dsi_panel_parse_timing(&mode->timing, utils); if (rc) { pr_err("failed to parse panel timing, rc=%d\n", rc); goto parse_fail; } - rc = dsi_panel_parse_dsc_params(mode, child_np); + rc = dsi_panel_parse_dsc_params(mode, utils); if (rc) { pr_err("failed to parse dsc params, rc=%d\n", rc); goto parse_fail; } - rc = dsi_panel_parse_topology(prv_info, child_np, + rc = dsi_panel_parse_topology(prv_info, utils, topology_override); if (rc) { pr_err("failed to parse panel topology, rc=%d\n", rc); goto parse_fail; } - rc = dsi_panel_parse_cmd_sets(prv_info, child_np); + rc = dsi_panel_parse_cmd_sets(prv_info, utils); if (rc) { pr_err("failed to parse command sets, rc=%d\n", rc); goto parse_fail; } - rc = dsi_panel_parse_jitter_config(mode, child_np); + rc = dsi_panel_parse_jitter_config(mode, utils); if (rc) pr_err( "failed to parse panel jitter config, rc=%d\n", rc); - rc = dsi_panel_parse_phy_timing(mode, child_np); + rc = dsi_panel_parse_phy_timing(mode, utils); if (rc) { pr_err( "failed to parse panel phy timings, rc=%d\n", rc); goto parse_fail; } - rc = dsi_panel_parse_partial_update_caps(mode, child_np); + rc = dsi_panel_parse_partial_update_caps(mode, utils); if (rc) pr_err("failed to partial update caps, rc=%d\n", rc); } @@ -3087,6 +3145,7 @@ int dsi_panel_get_mode(struct dsi_panel *panel, kfree(mode->priv_info); mode->priv_info = NULL; done: + utils->data = utils_data; mutex_unlock(&panel->panel_lock); return rc; } diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_panel.h b/drivers/gpu/drm/msm/dsi-staging/dsi_panel.h index c6b09531aa68..4d3d23e7fddc 100644 --- a/drivers/gpu/drm/msm/dsi-staging/dsi_panel.h +++ b/drivers/gpu/drm/msm/dsi-staging/dsi_panel.h @@ -27,6 +27,7 @@ #include "dsi_ctrl_hw.h" #include "dsi_clk.h" #include "dsi_pwr.h" +#include "dsi_parser.h" #include "msm_drv.h" #define MAX_BL_LEVEL 4096 @@ -149,6 +150,7 @@ struct dsi_panel { struct drm_panel drm_panel; struct mipi_dsi_host *host; struct device *parent; + struct dentry *root; struct dsi_host_common_cfg host_config; struct dsi_video_engine_cfg video_config; @@ -168,6 +170,8 @@ struct dsi_panel { struct drm_panel_hdr_properties hdr_props; struct drm_panel_esd_config esd_config; + struct dsi_parser_utils utils; + bool lp11_init; bool ulps_enabled; bool ulps_suspend_enabled; @@ -204,6 +208,8 @@ static inline void dsi_panel_release_panel_lock(struct dsi_panel *panel) struct dsi_panel *dsi_panel_get(struct device *parent, struct device_node *of_node, + struct device_node *parser_node, + struct dentry *root, int topology_override); int dsi_panel_trigger_esd_attack(struct dsi_panel *panel); @@ -214,8 +220,7 @@ int dsi_panel_drv_init(struct dsi_panel *panel, struct mipi_dsi_host *host); int dsi_panel_drv_deinit(struct dsi_panel *panel); -int dsi_panel_get_mode_count(struct dsi_panel *panel, - struct device_node *of_node); +int dsi_panel_get_mode_count(struct dsi_panel *panel); void dsi_panel_put_mode(struct dsi_display_mode *mode); diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_pwr.c b/drivers/gpu/drm/msm/dsi-staging/dsi_pwr.c index 60deeeee3fe3..3ba54ccc8212 100644 --- a/drivers/gpu/drm/msm/dsi-staging/dsi_pwr.c +++ b/drivers/gpu/drm/msm/dsi-staging/dsi_pwr.c @@ -17,11 +17,13 @@ #include #include "dsi_pwr.h" +#include "dsi_parser.h" /* * dsi_pwr_parse_supply_node() - parse power supply node from root device node */ -static int dsi_pwr_parse_supply_node(struct device_node *root, +static int dsi_pwr_parse_supply_node(struct dsi_parser_utils *utils, + struct device_node *root, struct dsi_regulator_info *regs) { int rc = 0; @@ -29,10 +31,10 @@ static int dsi_pwr_parse_supply_node(struct device_node *root, u32 tmp = 0; struct device_node *node = NULL; - for_each_child_of_node(root, node) { + dsi_for_each_child_node(root, node) { const char *st = NULL; - rc = of_property_read_string(node, "qcom,supply-name", &st); + rc = utils->read_string(node, "qcom,supply-name", &st); if (rc) { pr_err("failed to read name, rc = %d\n", rc); goto error; @@ -42,32 +44,28 @@ static int dsi_pwr_parse_supply_node(struct device_node *root, ARRAY_SIZE(regs->vregs[i].vreg_name), "%s", st); - rc = of_property_read_u32(node, "qcom,supply-min-voltage", - &tmp); + rc = utils->read_u32(node, "qcom,supply-min-voltage", &tmp); if (rc) { pr_err("failed to read min voltage, rc = %d\n", rc); goto error; } regs->vregs[i].min_voltage = tmp; - rc = of_property_read_u32(node, "qcom,supply-max-voltage", - &tmp); + rc = utils->read_u32(node, "qcom,supply-max-voltage", &tmp); if (rc) { pr_err("failed to read max voltage, rc = %d\n", rc); goto error; } regs->vregs[i].max_voltage = tmp; - rc = of_property_read_u32(node, "qcom,supply-enable-load", - &tmp); + rc = utils->read_u32(node, "qcom,supply-enable-load", &tmp); if (rc) { pr_err("failed to read enable load, rc = %d\n", rc); goto error; } regs->vregs[i].enable_load = tmp; - rc = of_property_read_u32(node, "qcom,supply-disable-load", - &tmp); + rc = utils->read_u32(node, "qcom,supply-disable-load", &tmp); if (rc) { pr_err("failed to read disable load, rc = %d\n", rc); goto error; @@ -75,8 +73,7 @@ static int dsi_pwr_parse_supply_node(struct device_node *root, regs->vregs[i].disable_load = tmp; /* Optional values */ - rc = of_property_read_u32(node, "qcom,supply-pre-on-sleep", - &tmp); + rc = utils->read_u32(node, "qcom,supply-pre-on-sleep", &tmp); if (rc) { pr_debug("pre-on-sleep not specified\n"); rc = 0; @@ -84,8 +81,7 @@ static int dsi_pwr_parse_supply_node(struct device_node *root, regs->vregs[i].pre_on_sleep = tmp; } - rc = of_property_read_u32(node, "qcom,supply-pre-off-sleep", - &tmp); + rc = utils->read_u32(node, "qcom,supply-pre-off-sleep", &tmp); if (rc) { pr_debug("pre-off-sleep not specified\n"); rc = 0; @@ -93,8 +89,7 @@ static int dsi_pwr_parse_supply_node(struct device_node *root, regs->vregs[i].pre_off_sleep = tmp; } - rc = of_property_read_u32(node, "qcom,supply-post-on-sleep", - &tmp); + rc = utils->read_u32(node, "qcom,supply-post-on-sleep", &tmp); if (rc) { pr_debug("post-on-sleep not specified\n"); rc = 0; @@ -102,8 +97,7 @@ static int dsi_pwr_parse_supply_node(struct device_node *root, regs->vregs[i].post_on_sleep = tmp; } - rc = of_property_read_u32(node, "qcom,supply-post-off-sleep", - &tmp); + rc = utils->read_u32(node, "qcom,supply-post-off-sleep", &tmp); if (rc) { pr_debug("post-off-sleep not specified\n"); rc = 0; @@ -221,22 +215,23 @@ static int dsi_pwr_enable_vregs(struct dsi_regulator_info *regs, bool enable) * * return: error code in case of failure or 0 for success. */ -int dsi_pwr_of_get_vreg_data(struct device_node *of_node, +int dsi_pwr_of_get_vreg_data(struct dsi_parser_utils *utils, struct dsi_regulator_info *regs, char *supply_name) { int rc = 0; struct device_node *supply_root_node = NULL; - if (!of_node || !regs) { + if (!utils || !regs) { pr_err("Bad params\n"); return -EINVAL; } regs->count = 0; - supply_root_node = of_get_child_by_name(of_node, supply_name); + supply_root_node = utils->get_child_by_name(utils->data, supply_name); if (!supply_root_node) { - supply_root_node = of_parse_phandle(of_node, supply_name, 0); + supply_root_node = of_parse_phandle(utils->node, + supply_name, 0); if (!supply_root_node) { pr_debug("No supply entry present for %s\n", supply_name); @@ -244,7 +239,7 @@ int dsi_pwr_of_get_vreg_data(struct device_node *of_node, } } - regs->count = of_get_available_child_count(supply_root_node); + regs->count = utils->get_available_child_count(supply_root_node); if (regs->count == 0) { pr_err("No vregs defined for %s\n", supply_name); return -EINVAL; @@ -256,7 +251,7 @@ int dsi_pwr_of_get_vreg_data(struct device_node *of_node, return -ENOMEM; } - rc = dsi_pwr_parse_supply_node(supply_root_node, regs); + rc = dsi_pwr_parse_supply_node(utils, supply_root_node, regs); if (rc) { pr_err("failed to parse supply node for %s, rc = %d\n", supply_name, rc); @@ -285,6 +280,7 @@ int dsi_pwr_get_dt_vreg_data(struct device *dev, struct device_node *of_node = NULL; struct device_node *supply_node = NULL; struct device_node *supply_root_node = NULL; + struct dsi_parser_utils utils = *dsi_parser_get_of_utils(); if (!dev || !regs) { pr_err("Bad params\n"); @@ -318,7 +314,10 @@ int dsi_pwr_get_dt_vreg_data(struct device *dev, return -ENOMEM; } - rc = dsi_pwr_parse_supply_node(supply_root_node, regs); + utils.data = of_node; + utils.node = of_node; + + rc = dsi_pwr_parse_supply_node(&utils, supply_root_node, regs); if (rc) { pr_err("failed to parse supply node for %s, rc = %d\n", supply_name, rc); diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_pwr.h b/drivers/gpu/drm/msm/dsi-staging/dsi_pwr.h index 4d85244fc5cc..35b0601d1823 100644 --- a/drivers/gpu/drm/msm/dsi-staging/dsi_pwr.h +++ b/drivers/gpu/drm/msm/dsi-staging/dsi_pwr.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -20,6 +20,8 @@ #include #include +struct dsi_parser_utils; + /** * struct dsi_vreg - regulator information for DSI regulators * @vreg: Handle to the regulator. @@ -66,7 +68,7 @@ struct dsi_regulator_info { * * return: error code in case of failure or 0 for success. */ -int dsi_pwr_of_get_vreg_data(struct device_node *of_node, +int dsi_pwr_of_get_vreg_data(struct dsi_parser_utils *utils, struct dsi_regulator_info *regs, char *supply_name); -- GitLab From 30900a8bf22fa65df1842c171e44fe1b5adb77d4 Mon Sep 17 00:00:00 2001 From: Satya Durga Srinivasu Prabhala Date: Tue, 24 Apr 2018 18:00:23 -0700 Subject: [PATCH 0819/1635] sched/fair: fix cpu util for waking tasks While computing cpu utilization for the waking task, subtracting task utilization isn't needed. Just return cpu_util. Also, use cpu_util for calculating utilization. Change-Id: I214a39dbeff209125727360bb15fffcaf10bb9ac Signed-off-by: Satya Durga Srinivasu Prabhala --- kernel/sched/fair.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index c78063f79868..7791b0d31482 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -6951,7 +6951,8 @@ static int cpu_util_wake(int cpu, struct task_struct *p) * utilization from cpu utilization. Instead just use * cpu_util for this case. */ - if (!walt_disabled && sysctl_sched_use_walt_cpu_util) + if (!walt_disabled && sysctl_sched_use_walt_cpu_util && + p->state == TASK_WAKING) return cpu_util(cpu); #endif /* Task has no contribution or is new */ @@ -6959,7 +6960,7 @@ static int cpu_util_wake(int cpu, struct task_struct *p) return cpu_util(cpu); capacity = capacity_orig_of(cpu); - util = max_t(long, cpu_rq(cpu)->cfs.avg.util_avg - task_util(p), 0); + util = max_t(long, cpu_util(cpu) - task_util(p), 0); return (util >= capacity) ? capacity : util; } -- GitLab From 0038b390b3277e61868af50cd126c1290b56a786 Mon Sep 17 00:00:00 2001 From: Srinivas Rao L Date: Fri, 13 Oct 2017 23:41:58 +0530 Subject: [PATCH 0820/1635] lpm_levels: Return true for CPU WFI mode allow check As it's a general understanding across all architectures to have a WFI (or equalivalent) mode always present and never disabled for cpuidle, return true for CPU WFI mode allow check. Change-Id: Ic55571488f845e4aaf997faaac3b2e0f22368d4e Signed-off-by: Srinivas Rao L --- drivers/cpuidle/lpm-levels-of.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/cpuidle/lpm-levels-of.c b/drivers/cpuidle/lpm-levels-of.c index 4139c4316f00..25e3b7311cea 100644 --- a/drivers/cpuidle/lpm-levels-of.c +++ b/drivers/cpuidle/lpm-levels-of.c @@ -410,6 +410,9 @@ bool lpm_cpu_mode_allow(unsigned int cpu, { struct lpm_level_avail *avail = cpu_level_available[cpu]; + if (lpm_pdev && !index) + return 1; + if (!lpm_pdev || !avail) return !from_idle; -- GitLab From 073517a0db0add9ce3a72507f11d18f80b057beb Mon Sep 17 00:00:00 2001 From: Deepak Kumar Date: Tue, 17 Apr 2018 15:59:42 +0530 Subject: [PATCH 0821/1635] msm: kgsl: Use only compat VA range for compat tasks Set KGSL_MEMFLAGS_FORCE_32BIT for compat tasks in IOCTL_KGSL_GPUOBJ_ALLOC and IOCTL_KGSL_GPUOBJ_IMPORT to make sure compat VA range is used. This is required to avoid allocating a 64bit GPU VA for a 32bit application running on a 64bit kernel. Change-Id: I5cc526efd513e099fc7cda747e85e5fd6a8f1a32 Signed-off-by: Deepak Kumar --- drivers/gpu/msm/adreno_a6xx_preempt.c | 3 +++ drivers/gpu/msm/kgsl.c | 19 +++++++++++++++---- drivers/gpu/msm/kgsl.h | 6 ++++++ drivers/gpu/msm/kgsl_iommu.c | 2 +- 4 files changed, 25 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/msm/adreno_a6xx_preempt.c b/drivers/gpu/msm/adreno_a6xx_preempt.c index 8d57da1a80ec..38db00bc03b0 100644 --- a/drivers/gpu/msm/adreno_a6xx_preempt.c +++ b/drivers/gpu/msm/adreno_a6xx_preempt.c @@ -745,6 +745,9 @@ int a6xx_preemption_context_init(struct kgsl_context *context) if (context->flags & KGSL_CONTEXT_SECURE) flags |= KGSL_MEMFLAGS_SECURE; + if (kgsl_is_compat_task()) + flags |= KGSL_MEMFLAGS_FORCE_32BIT; + /* * gpumem_alloc_entry takes an extra refcount. Put it only when * destroying the context to keep the context record valid diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c index f5971c9efbcd..075d21bdf9f4 100644 --- a/drivers/gpu/msm/kgsl.c +++ b/drivers/gpu/msm/kgsl.c @@ -2412,6 +2412,9 @@ long kgsl_ioctl_gpuobj_import(struct kgsl_device_private *dev_priv, if (!MMU_FEATURE(mmu, KGSL_MMU_IO_COHERENT)) param->flags &= ~((uint64_t)KGSL_MEMFLAGS_IOCOHERENT); + if (kgsl_is_compat_task()) + param->flags |= KGSL_MEMFLAGS_FORCE_32BIT; + entry->memdesc.flags = param->flags; if (MMU_FEATURE(mmu, KGSL_MMU_NEED_GUARD_PAGE)) @@ -2702,8 +2705,10 @@ long kgsl_ioctl_map_user_mem(struct kgsl_device_private *dev_priv, if (!MMU_FEATURE(mmu, KGSL_MMU_IO_COHERENT)) param->flags &= ~((uint64_t)KGSL_MEMFLAGS_IOCOHERENT); - entry->memdesc.flags = ((uint64_t) param->flags) - | KGSL_MEMFLAGS_FORCE_32BIT; + entry->memdesc.flags = (uint64_t) param->flags; + + if (kgsl_is_compat_task()) + entry->memdesc.flags |= KGSL_MEMFLAGS_FORCE_32BIT; if (!kgsl_mmu_use_cpu_map(mmu)) entry->memdesc.flags &= ~((uint64_t) KGSL_MEMFLAGS_USE_CPU_MAP); @@ -3207,6 +3212,9 @@ long kgsl_ioctl_gpuobj_alloc(struct kgsl_device_private *dev_priv, struct kgsl_gpuobj_alloc *param = data; struct kgsl_mem_entry *entry; + if (kgsl_is_compat_task()) + param->flags |= KGSL_MEMFLAGS_FORCE_32BIT; + entry = gpumem_alloc_entry(dev_priv, param->size, param->flags); if (IS_ERR(entry)) @@ -3234,7 +3242,9 @@ long kgsl_ioctl_gpumem_alloc(struct kgsl_device_private *dev_priv, /* Legacy functions doesn't support these advanced features */ flags &= ~((uint64_t) KGSL_MEMFLAGS_USE_CPU_MAP); - flags |= KGSL_MEMFLAGS_FORCE_32BIT; + + if (kgsl_is_compat_task()) + flags |= KGSL_MEMFLAGS_FORCE_32BIT; entry = gpumem_alloc_entry(dev_priv, (uint64_t) param->size, flags); @@ -3258,7 +3268,8 @@ long kgsl_ioctl_gpumem_alloc_id(struct kgsl_device_private *dev_priv, struct kgsl_mem_entry *entry; uint64_t flags = param->flags; - flags |= KGSL_MEMFLAGS_FORCE_32BIT; + if (kgsl_is_compat_task()) + flags |= KGSL_MEMFLAGS_FORCE_32BIT; entry = gpumem_alloc_entry(dev_priv, (uint64_t) param->size, flags); diff --git a/drivers/gpu/msm/kgsl.h b/drivers/gpu/msm/kgsl.h index 60aa76a3639c..be81d646a566 100644 --- a/drivers/gpu/msm/kgsl.h +++ b/drivers/gpu/msm/kgsl.h @@ -27,6 +27,7 @@ #include #include #include +#include /* * --- kgsl drawobj flags --- @@ -630,4 +631,9 @@ static inline void kgsl_gpu_sysfs_add_link(struct kobject *dst, kernfs_create_link(dst->sd, dst_name, old); } + +static inline bool kgsl_is_compat_task(void) +{ + return (BITS_PER_LONG == 32) || is_compat_task(); +} #endif /* __KGSL_H */ diff --git a/drivers/gpu/msm/kgsl_iommu.c b/drivers/gpu/msm/kgsl_iommu.c index ded7dde1a5a3..1bbbeb497532 100644 --- a/drivers/gpu/msm/kgsl_iommu.c +++ b/drivers/gpu/msm/kgsl_iommu.c @@ -1052,7 +1052,7 @@ static void setup_64bit_pagetable(struct kgsl_mmu *mmu, if (pagetable->name != KGSL_MMU_GLOBAL_PT && pagetable->name != KGSL_MMU_SECURE_PT) { - if ((BITS_PER_LONG == 32) || is_compat_task()) { + if (kgsl_is_compat_task()) { pt->svm_start = KGSL_IOMMU_SVM_BASE32; pt->svm_end = KGSL_IOMMU_SECURE_BASE(mmu); } else { -- GitLab From 9d6cae31104a9a23fe4577e2bb18aa9f075c93df Mon Sep 17 00:00:00 2001 From: Deepak Kumar Date: Wed, 7 Mar 2018 20:06:58 +0530 Subject: [PATCH 0822/1635] msm: kgsl: Specify context aware target power level for each speed bin Some platforms support multiple GPU clock plans based on the speed bin in the efuse. Specify context aware DCVS target power level for each speed bin to make sure context aware jump happens at correct level for each GPU clock plan. Change-Id: I4837423815c94d5d0966d4f7ea7a4427d65d0d50 Signed-off-by: Deepak Kumar --- .../bindings/gpu/adreno-pwrlevels.txt | 4 ++ .../devicetree/bindings/gpu/adreno.txt | 19 +++++++ drivers/gpu/msm/adreno.c | 55 +++++++++++++++++++ drivers/gpu/msm/kgsl_pwrscale.c | 24 ++------ drivers/gpu/msm/kgsl_pwrscale.h | 8 +++ 5 files changed, 92 insertions(+), 18 deletions(-) diff --git a/Documentation/devicetree/bindings/gpu/adreno-pwrlevels.txt b/Documentation/devicetree/bindings/gpu/adreno-pwrlevels.txt index aece6ac44b78..747e0b601da2 100644 --- a/Documentation/devicetree/bindings/gpu/adreno-pwrlevels.txt +++ b/Documentation/devicetree/bindings/gpu/adreno-pwrlevels.txt @@ -17,6 +17,10 @@ Properties: - qcom,gpu-pwrlevel: A single powerlevel +- qcom,ca-target-pwrlevel: + This value indicates which qcom,gpu-pwrlevel + to jump on in case of context aware power level + jump. Properties: - reg: Index of the powerlevel (0 = highest perf) - qcom,gpu-freq GPU frequency for the powerlevel (in Hz) diff --git a/Documentation/devicetree/bindings/gpu/adreno.txt b/Documentation/devicetree/bindings/gpu/adreno.txt index 375e929ab367..7976a8728b15 100644 --- a/Documentation/devicetree/bindings/gpu/adreno.txt +++ b/Documentation/devicetree/bindings/gpu/adreno.txt @@ -167,6 +167,15 @@ Optional Properties: Specify the size of snapshot in bytes. This will override snapshot size defined in the driver code. +- qcom,enable-ca-jump: + Boolean. Enables use of context aware DCVS +- qcom,ca-busy-penalty: + This property represents the time in microseconds required to + initiate context aware power level jump. +- qcom,ca-target-pwrlevel: + This value indicates which qcom,gpu-pwrlevel to jump on in case + of context aware power level jump. + - qcom,gpu-qdss-stm: baseAddr - base address of the gpu channels in the qdss stm memory region @@ -323,6 +332,15 @@ Example of A330 GPU in MSM8916: coresight-child-list = <&funnel_in0>; coresight-child-ports = <5>; + /* Enable context aware freq. scaling */ + qcom,enable-ca-jump; + + /* Context aware jump busy penalty in us */ + qcom,ca-busy-penalty = <12000>; + + /* Context aware jump target power level */ + qcom,ca-target-pwrlevel = <1>; + qcom,soc-hw-revisions { #address-cells = <1>; #size-cells = <0>; @@ -389,6 +407,7 @@ Example of A330 GPU in MSM8916: #size-cells = <0>; qcom,speed-bin = <0>; + qcom,ca-target-pwrlevel = <1>; qcom,gpu-pwrlevel@0 { reg = <0>; diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c index 065bacfd8c77..0137001b8fc3 100644 --- a/drivers/gpu/msm/adreno.c +++ b/drivers/gpu/msm/adreno.c @@ -849,6 +849,58 @@ static const struct of_device_id adreno_match_table[] = { {} }; +static void adreno_of_get_ca_target_pwrlevel(struct adreno_device *adreno_dev, + struct device_node *node) +{ + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); + unsigned int ca_target_pwrlevel = 1; + + of_property_read_u32(node, "qcom,ca-target-pwrlevel", + &ca_target_pwrlevel); + + if (ca_target_pwrlevel > device->pwrctrl.num_pwrlevels - 2) + ca_target_pwrlevel = 1; + + device->pwrscale.ctxt_aware_target_pwrlevel = ca_target_pwrlevel; +} + +static void adreno_of_get_ca_aware_properties(struct adreno_device *adreno_dev, + struct device_node *parent) +{ + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); + struct kgsl_pwrscale *pwrscale = &device->pwrscale; + struct device_node *node, *child; + unsigned int bin = 0; + + pwrscale->ctxt_aware_enable = + of_property_read_bool(parent, "qcom,enable-ca-jump"); + + if (pwrscale->ctxt_aware_enable) { + if (of_property_read_u32(parent, "qcom,ca-busy-penalty", + &pwrscale->ctxt_aware_busy_penalty)) + pwrscale->ctxt_aware_busy_penalty = 12000; + + node = of_find_node_by_name(parent, "qcom,gpu-pwrlevel-bins"); + if (node == NULL) { + adreno_of_get_ca_target_pwrlevel(adreno_dev, parent); + return; + } + + for_each_child_of_node(node, child) { + if (of_property_read_u32(child, "qcom,speed-bin", &bin)) + continue; + + if (bin == adreno_dev->speed_bin) { + adreno_of_get_ca_target_pwrlevel(adreno_dev, + child); + return; + } + } + + pwrscale->ctxt_aware_target_pwrlevel = 1; + } +} + static int adreno_of_parse_pwrlevels(struct adreno_device *adreno_dev, struct device_node *node) { @@ -1018,6 +1070,9 @@ static int adreno_of_get_power(struct adreno_device *adreno_dev, if (adreno_of_get_pwrlevels(adreno_dev, node)) return -EINVAL; + /* Get context aware DCVS properties */ + adreno_of_get_ca_aware_properties(adreno_dev, node); + /* get pm-qos-active-latency, set it to default if not found */ if (of_property_read_u32(node, "qcom,pm-qos-active-latency", &device->pwrctrl.pm_qos_active_latency)) diff --git a/drivers/gpu/msm/kgsl_pwrscale.c b/drivers/gpu/msm/kgsl_pwrscale.c index b5249b366db9..e207a073c78a 100644 --- a/drivers/gpu/msm/kgsl_pwrscale.c +++ b/drivers/gpu/msm/kgsl_pwrscale.c @@ -985,24 +985,12 @@ int kgsl_pwrscale_init(struct device *dev, const char *governor) data->disable_busy_time_burst = of_property_read_bool( device->pdev->dev.of_node, "qcom,disable-busy-time-burst"); - data->ctxt_aware_enable = - of_property_read_bool(device->pdev->dev.of_node, - "qcom,enable-ca-jump"); - - if (data->ctxt_aware_enable) { - if (of_property_read_u32(device->pdev->dev.of_node, - "qcom,ca-target-pwrlevel", - &data->bin.ctxt_aware_target_pwrlevel)) - data->bin.ctxt_aware_target_pwrlevel = 1; - - if ((data->bin.ctxt_aware_target_pwrlevel > - pwr->num_pwrlevels)) - data->bin.ctxt_aware_target_pwrlevel = 1; - - if (of_property_read_u32(device->pdev->dev.of_node, - "qcom,ca-busy-penalty", - &data->bin.ctxt_aware_busy_penalty)) - data->bin.ctxt_aware_busy_penalty = 12000; + if (pwrscale->ctxt_aware_enable) { + data->ctxt_aware_enable = pwrscale->ctxt_aware_enable; + data->bin.ctxt_aware_target_pwrlevel = + pwrscale->ctxt_aware_target_pwrlevel; + data->bin.ctxt_aware_busy_penalty = + pwrscale->ctxt_aware_busy_penalty; } if (of_property_read_bool(device->pdev->dev.of_node, diff --git a/drivers/gpu/msm/kgsl_pwrscale.h b/drivers/gpu/msm/kgsl_pwrscale.h index f74f7315bac6..9e28b6594b8d 100644 --- a/drivers/gpu/msm/kgsl_pwrscale.h +++ b/drivers/gpu/msm/kgsl_pwrscale.h @@ -91,6 +91,11 @@ struct kgsl_pwr_history { * @popp_level - Current level of POPP mitigation * @popp_state - Control state for POPP, on/off, recently pushed, etc * @cooling_dev - Thermal cooling device handle + * @ctxt_aware_enable - Whether or not ctxt aware DCVS feature is enabled + * @ctxt_aware_busy_penalty - The time in microseconds required to trigger + * ctxt aware power level jump + * @ctxt_aware_target_pwrlevel - pwrlevel to jump on in case of ctxt aware + * power level jump */ struct kgsl_pwrscale { struct devfreq *devfreqptr; @@ -113,6 +118,9 @@ struct kgsl_pwrscale { int popp_level; unsigned long popp_state; struct thermal_cooling_device *cooling_dev; + bool ctxt_aware_enable; + unsigned int ctxt_aware_target_pwrlevel; + unsigned int ctxt_aware_busy_penalty; }; int kgsl_pwrscale_init(struct device *dev, const char *governor); -- GitLab From a6e44af5614b9d619b9a07e114122f2f32e06c77 Mon Sep 17 00:00:00 2001 From: Deepak Kumar Date: Wed, 28 Feb 2018 11:06:38 +0530 Subject: [PATCH 0823/1635] msm: kgsl: Keep dispatcher halted during SUSPEND state Increment GPU halt variable after successful transition to SUSPEND state to halt dispatcher. This is necessary to make sure that any pending dispatcher threads don't go ahead and try to wake up GPU in SUSPEND state. Change-Id: I806884306549afbef0dfa92ea14903cc7a47d347 Signed-off-by: Deepak Kumar --- drivers/gpu/msm/adreno.c | 2 ++ drivers/gpu/msm/adreno_dispatch.c | 17 +++++++++++++++++ drivers/gpu/msm/adreno_dispatch.h | 4 +++- drivers/gpu/msm/kgsl.c | 3 +++ drivers/gpu/msm/kgsl_device.h | 2 ++ 5 files changed, 27 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c index 065bacfd8c77..fb1bb4ac5200 100644 --- a/drivers/gpu/msm/adreno.c +++ b/drivers/gpu/msm/adreno.c @@ -3549,6 +3549,8 @@ static const struct kgsl_functable adreno_functable = { .clk_set_options = adreno_clk_set_options, .gpu_model = adreno_gpu_model, .stop_fault_timer = adreno_dispatcher_stop_fault_timer, + .dispatcher_halt = adreno_dispatcher_halt, + .dispatcher_unhalt = adreno_dispatcher_unhalt, }; static struct platform_driver adreno_platform_driver = { diff --git a/drivers/gpu/msm/adreno_dispatch.c b/drivers/gpu/msm/adreno_dispatch.c index 0f372114fcf1..85e814ad8ee5 100644 --- a/drivers/gpu/msm/adreno_dispatch.c +++ b/drivers/gpu/msm/adreno_dispatch.c @@ -2857,6 +2857,16 @@ int adreno_dispatcher_init(struct adreno_device *adreno_dev) return ret; } +void adreno_dispatcher_halt(struct kgsl_device *device) +{ + adreno_get_gpu_halt(ADRENO_DEVICE(device)); +} + +void adreno_dispatcher_unhalt(struct kgsl_device *device) +{ + adreno_put_gpu_halt(ADRENO_DEVICE(device)); +} + /* * adreno_dispatcher_idle() - Wait for dispatcher to idle * @adreno_dev: Adreno device whose dispatcher needs to idle @@ -2887,6 +2897,13 @@ int adreno_dispatcher_idle(struct adreno_device *adreno_dev) mutex_unlock(&device->mutex); + /* + * Flush the worker to make sure all executing + * or pending dispatcher works on worker are + * finished + */ + kthread_flush_worker(&kgsl_driver.worker); + ret = wait_for_completion_timeout(&dispatcher->idle_gate, msecs_to_jiffies(ADRENO_IDLE_TIMEOUT)); if (ret == 0) { diff --git a/drivers/gpu/msm/adreno_dispatch.h b/drivers/gpu/msm/adreno_dispatch.h index 48f0cdc546ff..61bd06f4d373 100644 --- a/drivers/gpu/msm/adreno_dispatch.h +++ b/drivers/gpu/msm/adreno_dispatch.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2008-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -103,6 +103,8 @@ enum adreno_dispatcher_flags { }; void adreno_dispatcher_start(struct kgsl_device *device); +void adreno_dispatcher_halt(struct kgsl_device *device); +void adreno_dispatcher_unhalt(struct kgsl_device *device); int adreno_dispatcher_init(struct adreno_device *adreno_dev); void adreno_dispatcher_close(struct adreno_device *adreno_dev); int adreno_dispatcher_idle(struct adreno_device *adreno_dev); diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c index f5971c9efbcd..cea742fa74c5 100644 --- a/drivers/gpu/msm/kgsl.c +++ b/drivers/gpu/msm/kgsl.c @@ -754,6 +754,8 @@ static int kgsl_suspend_device(struct kgsl_device *device, pm_message_t state) mutex_lock(&device->mutex); status = kgsl_pwrctrl_change_state(device, KGSL_STATE_SUSPEND); + if (status == 0) + device->ftbl->dispatcher_halt(device); mutex_unlock(&device->mutex); KGSL_PWR_WARN(device, "suspend end\n"); @@ -768,6 +770,7 @@ static int kgsl_resume_device(struct kgsl_device *device) KGSL_PWR_WARN(device, "resume start\n"); mutex_lock(&device->mutex); if (device->state == KGSL_STATE_SUSPEND) { + device->ftbl->dispatcher_unhalt(device); kgsl_pwrctrl_change_state(device, KGSL_STATE_SLUMBER); } else if (device->state != KGSL_STATE_INIT) { /* diff --git a/drivers/gpu/msm/kgsl_device.h b/drivers/gpu/msm/kgsl_device.h index 6767c7125772..15f13a1d0488 100644 --- a/drivers/gpu/msm/kgsl_device.h +++ b/drivers/gpu/msm/kgsl_device.h @@ -190,6 +190,8 @@ struct kgsl_functable { void (*gpu_model)(struct kgsl_device *device, char *str, size_t bufsz); void (*stop_fault_timer)(struct kgsl_device *device); + void (*dispatcher_halt)(struct kgsl_device *device); + void (*dispatcher_unhalt)(struct kgsl_device *device); }; struct kgsl_ioctl { -- GitLab From b210e6e05e60779a602520de3eb8f1d3ea63bce0 Mon Sep 17 00:00:00 2001 From: Deepak Kumar Date: Mon, 5 Mar 2018 16:51:25 +0530 Subject: [PATCH 0824/1635] msm: kgsl: Correctly limit max number of contexts per process Read and increment context count atomic variable under a lock to avoid race condition between read and increment. This is necessary to make sure no process goes beyond the specified context limit. Change-Id: I483e2ac169beaff49e19b8ef1b46541f6eb740b0 Signed-off-by: Deepak Kumar --- drivers/gpu/msm/kgsl.c | 8 ++++++++ drivers/gpu/msm/kgsl_device.h | 2 ++ 2 files changed, 10 insertions(+) diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c index f5971c9efbcd..39ed08f40f98 100644 --- a/drivers/gpu/msm/kgsl.c +++ b/drivers/gpu/msm/kgsl.c @@ -532,14 +532,21 @@ int kgsl_context_init(struct kgsl_device_private *dev_priv, int ret = 0, id; struct kgsl_process_private *proc_priv = dev_priv->process_priv; + /* + * Read and increment the context count under lock to make sure + * no process goes beyond the specified context limit. + */ + spin_lock(&proc_priv->ctxt_count_lock); if (atomic_read(&proc_priv->ctxt_count) > KGSL_MAX_CONTEXTS_PER_PROC) { KGSL_DRV_ERR(device, "Per process context limit reached for pid %u", dev_priv->process_priv->pid); + spin_unlock(&proc_priv->ctxt_count_lock); return -ENOSPC; } atomic_inc(&proc_priv->ctxt_count); + spin_unlock(&proc_priv->ctxt_count_lock); id = _kgsl_get_context_id(device); if (id == -ENOSPC) { @@ -919,6 +926,7 @@ static struct kgsl_process_private *kgsl_process_private_new( spin_lock_init(&private->mem_lock); spin_lock_init(&private->syncsource_lock); + spin_lock_init(&private->ctxt_count_lock); idr_init(&private->mem_idr); idr_init(&private->syncsource_idr); diff --git a/drivers/gpu/msm/kgsl_device.h b/drivers/gpu/msm/kgsl_device.h index 6767c7125772..05b127a5933a 100644 --- a/drivers/gpu/msm/kgsl_device.h +++ b/drivers/gpu/msm/kgsl_device.h @@ -443,6 +443,7 @@ struct kgsl_context { * @syncsource_lock: Spinlock to protect the syncsource idr * @fd_count: Counter for the number of FDs for this process * @ctxt_count: Count for the number of contexts for this process + * @ctxt_count_lock: Spinlock to protect ctxt_count */ struct kgsl_process_private { unsigned long priv; @@ -463,6 +464,7 @@ struct kgsl_process_private { spinlock_t syncsource_lock; int fd_count; atomic_t ctxt_count; + spinlock_t ctxt_count_lock; }; /** -- GitLab From a33c77c0cf4babc8e985c1367f2eb2639268121c Mon Sep 17 00:00:00 2001 From: Deepak Kumar Date: Fri, 23 Feb 2018 16:31:46 +0530 Subject: [PATCH 0825/1635] msm: kgsl: Correct memory type update in IOCTL_KGSL_GPUOBJ_SET_INFO A bad user can pass memory type parameter value greater than 255. Limit the memory type value to valid range before updating memory descriptor flags to avoid incorrect flag update. Change-Id: I23ce69584d1e2c9969583461ee942c5046e7cdbc Signed-off-by: Deepak Kumar --- drivers/gpu/msm/kgsl.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c index f5971c9efbcd..71d0dbdf6af7 100644 --- a/drivers/gpu/msm/kgsl.c +++ b/drivers/gpu/msm/kgsl.c @@ -4044,6 +4044,7 @@ long kgsl_ioctl_gpuobj_set_info(struct kgsl_device_private *dev_priv, struct kgsl_process_private *private = dev_priv->process_priv; struct kgsl_gpuobj_set_info *param = data; struct kgsl_mem_entry *entry; + int ret = 0; if (param->id == 0) return -EINVAL; @@ -4056,13 +4057,16 @@ long kgsl_ioctl_gpuobj_set_info(struct kgsl_device_private *dev_priv, copy_metadata(entry, param->metadata, param->metadata_len); if (param->flags & KGSL_GPUOBJ_SET_INFO_TYPE) { - entry->memdesc.flags &= ~((uint64_t) KGSL_MEMTYPE_MASK); - entry->memdesc.flags |= (uint64_t)(param->type << - KGSL_MEMTYPE_SHIFT); + if (param->type <= (KGSL_MEMTYPE_MASK >> KGSL_MEMTYPE_SHIFT)) { + entry->memdesc.flags &= ~((uint64_t) KGSL_MEMTYPE_MASK); + entry->memdesc.flags |= (uint64_t)((param->type << + KGSL_MEMTYPE_SHIFT) & KGSL_MEMTYPE_MASK); + } else + ret = -EINVAL; } kgsl_mem_entry_put(entry); - return 0; + return ret; } /** -- GitLab From 3ee9a1e384088265f00834cc21449f9908b03aa6 Mon Sep 17 00:00:00 2001 From: Shefali Jain Date: Wed, 25 Apr 2018 12:55:05 +0530 Subject: [PATCH 0826/1635] defconfig: Enable GCC clock driver for QCS405 Enable global clock controller driver support. Change-Id: I9ba1553c0933d54c011f9dd216392a8bc8801e87 Signed-off-by: Shefali Jain --- arch/arm/configs/qcs405-perf_defconfig | 1 + arch/arm/configs/qcs405_defconfig | 1 + arch/arm64/configs/qcs405-perf_defconfig | 1 + arch/arm64/configs/qcs405_defconfig | 1 + 4 files changed, 4 insertions(+) diff --git a/arch/arm/configs/qcs405-perf_defconfig b/arch/arm/configs/qcs405-perf_defconfig index 88ccdd905d46..88a6e0ff8915 100644 --- a/arch/arm/configs/qcs405-perf_defconfig +++ b/arch/arm/configs/qcs405-perf_defconfig @@ -311,6 +311,7 @@ CONFIG_STAGING=y CONFIG_ASHMEM=y CONFIG_ION=y CONFIG_COMMON_CLK_QCOM=y +CONFIG_MDM_GCC_QCS405=y CONFIG_HWSPINLOCK=y CONFIG_MAILBOX=y CONFIG_QCOM_SMEM=y diff --git a/arch/arm/configs/qcs405_defconfig b/arch/arm/configs/qcs405_defconfig index f865ec11eb54..ec19bc8580af 100644 --- a/arch/arm/configs/qcs405_defconfig +++ b/arch/arm/configs/qcs405_defconfig @@ -321,6 +321,7 @@ CONFIG_STAGING=y CONFIG_ASHMEM=y CONFIG_ION=y CONFIG_COMMON_CLK_QCOM=y +CONFIG_MDM_GCC_QCS405=y CONFIG_HWSPINLOCK=y CONFIG_MAILBOX=y CONFIG_QCOM_LAZY_MAPPING=y diff --git a/arch/arm64/configs/qcs405-perf_defconfig b/arch/arm64/configs/qcs405-perf_defconfig index 716ca01882b6..c1bd23430490 100644 --- a/arch/arm64/configs/qcs405-perf_defconfig +++ b/arch/arm64/configs/qcs405-perf_defconfig @@ -312,6 +312,7 @@ CONFIG_UIO=y CONFIG_STAGING=y CONFIG_ASHMEM=y CONFIG_ION=y +CONFIG_MDM_GCC_QCS405=y CONFIG_HWSPINLOCK=y CONFIG_MAILBOX=y CONFIG_IOMMU_IO_PGTABLE_LPAE=y diff --git a/arch/arm64/configs/qcs405_defconfig b/arch/arm64/configs/qcs405_defconfig index acd1918ca2cf..64f939a877af 100644 --- a/arch/arm64/configs/qcs405_defconfig +++ b/arch/arm64/configs/qcs405_defconfig @@ -324,6 +324,7 @@ CONFIG_UIO=y CONFIG_STAGING=y CONFIG_ASHMEM=y CONFIG_ION=y +CONFIG_MDM_GCC_QCS405=y CONFIG_HWSPINLOCK=y CONFIG_MAILBOX=y CONFIG_IOMMU_IO_PGTABLE_LPAE=y -- GitLab From 25bda03e965362da6f3f4be7728200cf1b439eed Mon Sep 17 00:00:00 2001 From: Yujun Zhang Date: Wed, 31 Jan 2018 17:42:07 +0800 Subject: [PATCH 0827/1635] drm/msm/dsi-staging: implement dynamic DSI clock Dynamic DSI clock setting is implemented by re-calculating DSI link clocks from DSI bitrate in sysfs interface and re-enaling the clock with new bitrate while there is no DSI data transferring. Currently, the feature is only supported in DSI command mode. CRs-Fixed: 2177917 Change-Id: I1192e1980726ad632b619e0fe13034f79c169afa Signed-off-by: Yujun Zhang --- drivers/gpu/drm/msm/dsi-staging/dsi_catalog.c | 2 + drivers/gpu/drm/msm/dsi-staging/dsi_catalog.h | 1 + drivers/gpu/drm/msm/dsi-staging/dsi_clk.h | 11 +- .../gpu/drm/msm/dsi-staging/dsi_clk_manager.c | 72 ++++- drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c | 21 ++ drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.h | 7 + drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw.h | 7 + .../gpu/drm/msm/dsi-staging/dsi_ctrl_hw_cmn.c | 17 +- drivers/gpu/drm/msm/dsi-staging/dsi_display.c | 297 ++++++++++++++++++ drivers/gpu/drm/msm/dsi-staging/dsi_display.h | 6 + 10 files changed, 438 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.c b/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.c index 2074db0d7691..06b3e48f0962 100644 --- a/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.c +++ b/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.c @@ -67,6 +67,8 @@ static void dsi_catalog_cmn_init(struct dsi_ctrl_hw *ctrl, ctrl->ops.error_intr_ctrl = dsi_ctrl_hw_cmn_error_intr_ctrl; ctrl->ops.get_error_mask = dsi_ctrl_hw_cmn_get_error_mask; ctrl->ops.get_hw_version = dsi_ctrl_hw_cmn_get_hw_version; + ctrl->ops.wait_for_cmd_mode_mdp_idle = + dsi_ctrl_hw_cmn_wait_for_cmd_mode_mdp_idle; switch (version) { case DSI_CTRL_VERSION_1_4: diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.h b/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.h index 8fd07375144e..03cb251dbe3f 100644 --- a/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.h +++ b/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.h @@ -202,6 +202,7 @@ void dsi_ctrl_hw_cmn_mask_error_intr(struct dsi_ctrl_hw *ctrl, u32 idx, void dsi_ctrl_hw_cmn_error_intr_ctrl(struct dsi_ctrl_hw *ctrl, bool en); u32 dsi_ctrl_hw_cmn_get_error_mask(struct dsi_ctrl_hw *ctrl); u32 dsi_ctrl_hw_cmn_get_hw_version(struct dsi_ctrl_hw *ctrl); +int dsi_ctrl_hw_cmn_wait_for_cmd_mode_mdp_idle(struct dsi_ctrl_hw *ctrl); /* Definitions specific to 1.4 DSI controller hardware */ int dsi_ctrl_hw_14_wait_for_lane_idle(struct dsi_ctrl_hw *ctrl, u32 lanes); diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_clk.h b/drivers/gpu/drm/msm/dsi-staging/dsi_clk.h index 1fd10d990c03..d2000f6c0977 100644 --- a/drivers/gpu/drm/msm/dsi-staging/dsi_clk.h +++ b/drivers/gpu/drm/msm/dsi-staging/dsi_clk.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -231,6 +231,15 @@ void *dsi_register_clk_handle(void *clk_mngr, char *client); */ int dsi_deregister_clk_handle(void *client); +/** + * dsi_display_link_clk_force_update_ctrl() - force to set link clks + * @handle: Handle of desired DSI clock client. + * + * return: error code in case of failure or 0 for success. + */ + +int dsi_display_link_clk_force_update_ctrl(void *handle); + /** * dsi_display_clk_ctrl() - set frequencies for link clks * @handle: Handle of desired DSI clock client. diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_clk_manager.c b/drivers/gpu/drm/msm/dsi-staging/dsi_clk_manager.c index 38eba8de48dd..ae71dad5dd98 100644 --- a/drivers/gpu/drm/msm/dsi-staging/dsi_clk_manager.c +++ b/drivers/gpu/drm/msm/dsi-staging/dsi_clk_manager.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -1071,6 +1071,76 @@ int dsi_clk_req_state(void *client, enum dsi_clk_type clk, DEFINE_MUTEX(dsi_mngr_clk_mutex); +static int dsi_display_link_clk_force_update(void *client) +{ + int rc = 0; + struct dsi_clk_client_info *c = client; + struct dsi_clk_mngr *mngr; + struct dsi_link_clks *l_clks; + + if (!client) { + pr_err("%s: Invalid arg\n", __func__); + return -EINVAL; + } + mngr = c->mngr; + + mutex_lock(&mngr->clk_mutex); + + l_clks = mngr->link_clks; + + /* + * When link_clk_state is DSI_CLK_OFF, don't change DSI clock rate + * since it is possible to be overwritten, and return -EAGAIN to + * dynamic DSI writing interface to defer the reenabling to the next + * drm commit. + */ + if (mngr->link_clk_state == DSI_CLK_OFF) { + rc = -EAGAIN; + goto error; + } + + rc = dsi_display_link_clk_disable(l_clks, + mngr->dsi_ctrl_count, mngr->master_ndx); + if (rc) { + pr_err("%s, failed to stop link clk, rc = %d\n", + __func__, rc); + goto error; + } + + rc = dsi_display_link_clk_enable(l_clks, + mngr->dsi_ctrl_count, mngr->master_ndx); + if (rc) { + pr_err("%s, failed to start link clk rc= %d\n", + __func__, rc); + goto error; + } + +error: + mutex_unlock(&mngr->clk_mutex); + return rc; + +} + +int dsi_display_link_clk_force_update_ctrl(void *handle) +{ + int rc = 0; + + if (!handle) { + pr_err("%s: Invalid arg\n", __func__); + return -EINVAL; + } + + mutex_lock(&dsi_mngr_clk_mutex); + + rc = dsi_display_link_clk_force_update(handle); + if (rc && (rc != -EAGAIN)) + pr_err("%s: failed set clk state, rc = %d\n", __func__, rc); + + mutex_unlock(&dsi_mngr_clk_mutex); + + return rc; +} + int dsi_display_clk_ctrl(void *handle, enum dsi_clk_type clk_type, enum dsi_clk_state clk_state) { diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c index fb2f4b95c3b1..2587a6efd79f 100644 --- a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c +++ b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c @@ -921,6 +921,27 @@ static int dsi_ctrl_copy_and_pad_cmd(struct dsi_ctrl *dsi_ctrl, return rc; } +int dsi_ctrl_wait_for_cmd_mode_mdp_idle(struct dsi_ctrl *dsi_ctrl) +{ + int rc = 0; + + if (!dsi_ctrl) { + pr_err("Invalid params\n"); + return -EINVAL; + } + + if (dsi_ctrl->host_config.panel_mode != DSI_OP_CMD_MODE) + return -EINVAL; + + mutex_lock(&dsi_ctrl->ctrl_lock); + + rc = dsi_ctrl->hw.ops.wait_for_cmd_mode_mdp_idle(&dsi_ctrl->hw); + + mutex_unlock(&dsi_ctrl->ctrl_lock); + + return rc; +} + static void dsi_ctrl_wait_for_video_done(struct dsi_ctrl *dsi_ctrl) { u32 v_total = 0, v_blank = 0, sleep_ms = 0, fps = 0, ret; diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.h b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.h index 451ada370bbc..6ea34689bc3c 100644 --- a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.h +++ b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.h @@ -741,4 +741,11 @@ void dsi_ctrl_irq_update(struct dsi_ctrl *dsi_ctrl, bool enable); int dsi_ctrl_get_host_engine_init_state(struct dsi_ctrl *dsi_ctrl, bool *state); +/** + * dsi_ctrl_wait_for_cmd_mode_mdp_idle() - Wait for command mode engine not to + * be busy sending data from display engine. + * @dsi_ctrl: DSI controller handle. + */ +int dsi_ctrl_wait_for_cmd_mode_mdp_idle(struct dsi_ctrl *dsi_ctrl); + #endif /* _DSI_CTRL_H_ */ diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw.h b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw.h index 86eed096dd3b..230772f1bcd1 100644 --- a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw.h +++ b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw.h @@ -801,6 +801,13 @@ struct dsi_ctrl_hw_ops { * @ctrl: Pointer to the controller host hardware. */ u32 (*get_hw_version)(struct dsi_ctrl_hw *ctrl); + + /** + * wait_for_cmd_mode_mdp_idle() - wait for command mode engine not to + * be busy sending data from display engine + * @ctrl: Pointer to the controller host hardware. + */ + int (*wait_for_cmd_mode_mdp_idle)(struct dsi_ctrl_hw *ctrl); }; /* diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw_cmn.c b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw_cmn.c index 0600d1aa3815..28195d83c9cc 100644 --- a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw_cmn.c +++ b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw_cmn.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. + * Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -1476,3 +1476,18 @@ u32 dsi_ctrl_hw_cmn_get_hw_version(struct dsi_ctrl_hw *ctrl) return reg; } + +int dsi_ctrl_hw_cmn_wait_for_cmd_mode_mdp_idle(struct dsi_ctrl_hw *ctrl) +{ + int rc = 0, val = 0; + u32 cmd_mode_mdp_busy_mask = BIT(2); + u32 const sleep_us = 2 * 1000; + u32 const timeout_us = 200 * 1000; + + rc = readl_poll_timeout(ctrl->base + DSI_STATUS, val, + !(val & cmd_mode_mdp_busy_mask), sleep_us, timeout_us); + if (rc) + pr_err("%s: waiting failed, ret=%d\n", __func__, rc); + + return rc; +} diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_display.c b/drivers/gpu/drm/msm/dsi-staging/dsi_display.c index 53ba61ccbb10..e8d1719ad7c3 100644 --- a/drivers/gpu/drm/msm/dsi-staging/dsi_display.c +++ b/drivers/gpu/drm/msm/dsi-staging/dsi_display.c @@ -38,6 +38,8 @@ #define MAX_NAME_SIZE 64 +#define DSI_CLOCK_BITRATE_RADIX 10 + static char dsi_display_primary[MAX_CMDLINE_PARAM_LEN]; static char dsi_display_secondary[MAX_CMDLINE_PARAM_LEN]; static struct dsi_display_boot_param boot_displays[MAX_DSI_ACTIVE_DISPLAY]; @@ -3642,6 +3644,245 @@ int dsi_display_splash_res_cleanup(struct dsi_display *display) return rc; } +static int dsi_display_force_update_dsi_clk(struct dsi_display *display) +{ + int rc = 0; + + if (!display || !display->panel) { + pr_err("Invalid params\n"); + return -EINVAL; + } + + rc = dsi_display_link_clk_force_update_ctrl(display->dsi_clk_handle); + + if (!rc) { + pr_info("dsi bit clk has been configured to %d\n", + display->cached_clk_rate); + + atomic_set(&display->clkrate_change_pending, 0); + } else if (rc == -EAGAIN) { + pr_info("Clock is disabled, update it next time\n"); + } else { + pr_err("Failed to configure dsi bit clock '%d'. rc = %d\n", + display->cached_clk_rate, rc); + } + + return rc; +} + +static int dsi_display_request_update_dsi_bitrate(struct dsi_display *display, + u32 bit_clk_rate) +{ + int rc = 0; + int i; + + pr_debug("%s:bit rate:%d\n", __func__, bit_clk_rate); + if (!display || !display->panel) { + pr_err("Invalid params\n"); + return -EINVAL; + } + + if (bit_clk_rate == 0) { + pr_err("Invalid bit clock rate\n"); + return -EINVAL; + } + + display->config.bit_clk_rate_hz = bit_clk_rate; + + for (i = 0; i < display->ctrl_count; i++) { + struct dsi_display_ctrl *dsi_disp_ctrl = &display->ctrl[i]; + struct dsi_ctrl *ctrl = dsi_disp_ctrl->ctrl; + u32 num_of_lanes = 0; + u32 bpp = 3; + u64 bit_rate, pclk_rate, bit_rate_per_lane, byte_clk_rate; + struct dsi_host_common_cfg *host_cfg; + + mutex_lock(&ctrl->ctrl_lock); + + host_cfg = &display->panel->host_config; + if (host_cfg->data_lanes & DSI_DATA_LANE_0) + num_of_lanes++; + if (host_cfg->data_lanes & DSI_DATA_LANE_1) + num_of_lanes++; + if (host_cfg->data_lanes & DSI_DATA_LANE_2) + num_of_lanes++; + if (host_cfg->data_lanes & DSI_DATA_LANE_3) + num_of_lanes++; + + if (num_of_lanes == 0) { + pr_err("Invalid lane count\n"); + rc = -EINVAL; + goto error; + } + + bit_rate = display->config.bit_clk_rate_hz * num_of_lanes; + bit_rate_per_lane = bit_rate; + do_div(bit_rate_per_lane, num_of_lanes); + pclk_rate = bit_rate; + do_div(pclk_rate, (8 * bpp)); + byte_clk_rate = bit_rate_per_lane; + do_div(byte_clk_rate, 8); + pr_debug("bit_clk_rate = %llu, bit_clk_rate_per_lane = %llu\n", + bit_rate, bit_rate_per_lane); + pr_debug("byte_clk_rate = %llu, pclk_rate = %llu\n", + byte_clk_rate, pclk_rate); + + ctrl->clk_freq.byte_clk_rate = byte_clk_rate; + ctrl->clk_freq.pix_clk_rate = pclk_rate; + rc = dsi_clk_set_link_frequencies(display->dsi_clk_handle, + ctrl->clk_freq, ctrl->cell_index); + if (rc) { + pr_err("Failed to update link frequencies\n"); + goto error; + } + + ctrl->host_config.bit_clk_rate_hz = bit_clk_rate; +error: + mutex_unlock(&ctrl->ctrl_lock); + + /* TODO: recover ctrl->clk_freq in case of failure */ + if (rc) + return rc; + } + + return 0; +} + +static ssize_t sysfs_dynamic_dsi_clk_read(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int rc = 0; + struct dsi_display *display; + struct dsi_display_ctrl *m_ctrl; + struct dsi_ctrl *ctrl; + + if (!dev) { + pr_err("Invalid device\n"); + return -EINVAL; + } + + display = dev_get_drvdata(dev); + if (!display) { + pr_err("Invalid display\n"); + return -EINVAL; + } + + mutex_lock(&display->display_lock); + + m_ctrl = &display->ctrl[display->cmd_master_idx]; + ctrl = m_ctrl->ctrl; + if (ctrl) + display->cached_clk_rate = ctrl->clk_freq.byte_clk_rate + * 8; + + rc = snprintf(buf, PAGE_SIZE, "%d\n", display->cached_clk_rate); + pr_info("%s: read dsi clk rate %d\n", __func__, + display->cached_clk_rate); + + mutex_unlock(&display->display_lock); + + return rc; +} + +static ssize_t sysfs_dynamic_dsi_clk_write(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int rc = 0; + int clk_rate; + struct dsi_display *display; + + if (!dev) { + pr_err("Invalid device\n"); + return -EINVAL; + } + + display = dev_get_drvdata(dev); + if (!display) { + pr_err("Invalid display\n"); + return -EINVAL; + } + + rc = kstrtoint(buf, DSI_CLOCK_BITRATE_RADIX, &clk_rate); + if (rc) { + pr_err("%s: kstrtoint failed. rc=%d\n", __func__, rc); + return rc; + } + + if (clk_rate <= 0) { + pr_err("%s: bitrate should be greater than 0\n", __func__); + return -EINVAL; + } + + if (clk_rate == display->cached_clk_rate) { + pr_info("%s: ignore duplicated DSI clk setting\n", __func__); + return count; + } + + pr_info("%s: bitrate param value: '%d'\n", __func__, clk_rate); + + mutex_lock(&display->display_lock); + + display->cached_clk_rate = clk_rate; + rc = dsi_display_request_update_dsi_bitrate(display, clk_rate); + if (!rc) { + pr_info("%s: bit clk is ready to be configured to '%d'\n", + __func__, clk_rate); + } else { + pr_err("%s: Failed to prepare to configure '%d'. rc = %d\n", + __func__, clk_rate, rc); + /*Caching clock failed, so don't go on doing so.*/ + atomic_set(&display->clkrate_change_pending, 0); + display->cached_clk_rate = 0; + + mutex_unlock(&display->display_lock); + + return rc; + } + atomic_set(&display->clkrate_change_pending, 1); + + mutex_unlock(&display->display_lock); + + return count; + +} + +static DEVICE_ATTR(dynamic_dsi_clock, 0644, + sysfs_dynamic_dsi_clk_read, + sysfs_dynamic_dsi_clk_write); + +static struct attribute *dynamic_dsi_clock_fs_attrs[] = { + &dev_attr_dynamic_dsi_clock.attr, + NULL, +}; +static struct attribute_group dynamic_dsi_clock_fs_attrs_group = { + .attrs = dynamic_dsi_clock_fs_attrs, +}; + +static int dsi_display_sysfs_init(struct dsi_display *display) +{ + int rc = 0; + struct device *dev = &display->pdev->dev; + + if (display->panel->panel_mode == DSI_OP_CMD_MODE) + rc = sysfs_create_group(&dev->kobj, + &dynamic_dsi_clock_fs_attrs_group); + + return rc; + +} + +static int dsi_display_sysfs_deinit(struct dsi_display *display) +{ + struct device *dev = &display->pdev->dev; + + if (display->panel->panel_mode == DSI_OP_CMD_MODE) + sysfs_remove_group(&dev->kobj, + &dynamic_dsi_clock_fs_attrs_group); + + return 0; + +} + /** * dsi_display_bind - bind dsi device with controlling device * @dev: Pointer to base of platform device @@ -3689,6 +3930,15 @@ static int dsi_display_bind(struct device *dev, goto error; } + atomic_set(&display->clkrate_change_pending, 0); + display->cached_clk_rate = 0; + + rc = dsi_display_sysfs_init(display); + if (rc) { + pr_err("[%s] sysfs init failed, rc=%d\n", display->name, rc); + goto error; + } + memset(&info, 0x0, sizeof(info)); for (i = 0; i < display->ctrl_count; i++) { @@ -3840,6 +4090,7 @@ static int dsi_display_bind(struct device *dev, (void)dsi_phy_drv_deinit(display_ctrl->phy); (void)dsi_ctrl_drv_deinit(display_ctrl->ctrl); } + (void)dsi_display_sysfs_deinit(display); (void)dsi_display_debugfs_deinit(display); error: mutex_unlock(&display->display_lock); @@ -3897,6 +4148,9 @@ static void dsi_display_unbind(struct device *dev, pr_err("[%s] failed to deinit ctrl%d driver, rc=%d\n", display->name, i, rc); } + + atomic_set(&display->clkrate_change_pending, 0); + (void)dsi_display_sysfs_deinit(display); (void)dsi_display_debugfs_deinit(display); mutex_unlock(&display->display_lock); @@ -4603,6 +4857,10 @@ int dsi_display_set_mode(struct dsi_display *display, adj_mode = *mode; adjust_timing_by_ctrl_count(display, &adj_mode); + /*For dynamic DSI setting, use specified clock rate */ + if (display->cached_clk_rate > 0) + adj_mode.priv_info->clk_rate_hz = display->cached_clk_rate; + rc = dsi_display_validate_mode_set(display, &adj_mode, flags); if (rc) { pr_err("[%s] mode cannot be set\n", display->name); @@ -5195,6 +5453,7 @@ int dsi_display_pre_kickoff(struct drm_connector *connector, struct msm_display_kickoff_params *params) { int rc = 0; + int i; /* check and setup MISR */ if (display->misr_enable) @@ -5202,6 +5461,44 @@ int dsi_display_pre_kickoff(struct drm_connector *connector, rc = dsi_display_set_roi(display, params->rois); + /* dynamic DSI clock setting */ + if (atomic_read(&display->clkrate_change_pending)) { + mutex_lock(&display->display_lock); + /* + * acquire panel_lock to make sure no commands are in progress + */ + dsi_panel_acquire_panel_lock(display->panel); + + /* + * Wait for DSI command engine not to be busy sending data + * from display engine. + * If waiting fails, return "rc" instead of below "ret" so as + * not to impact DRM commit. The clock updating would be + * deferred to the next DRM commit. + */ + for (i = 0; i < display->ctrl_count; i++) { + struct dsi_ctrl *ctrl = display->ctrl[i].ctrl; + int ret = 0; + + ret = dsi_ctrl_wait_for_cmd_mode_mdp_idle(ctrl); + if (ret) { + pr_info("Failed to wait for cmd engine not to be busy sending data from MDP, rc: %d\n", + ret); + goto wait_failure; + } + } + + /* + * Don't check the return value so as not to impact DRM commit + * when error occurs. + */ + (void)dsi_display_force_update_dsi_clk(display); +wait_failure: + /* release panel_lock */ + dsi_panel_release_panel_lock(display->panel); + mutex_unlock(&display->display_lock); + } + return rc; } diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_display.h b/drivers/gpu/drm/msm/dsi-staging/dsi_display.h index 149b1fc89a5f..7b3bc976fc44 100644 --- a/drivers/gpu/drm/msm/dsi-staging/dsi_display.h +++ b/drivers/gpu/drm/msm/dsi-staging/dsi_display.h @@ -144,6 +144,8 @@ struct dsi_display_clk_info { * index into the ctrl[MAX_DSI_CTRLS_PER_DISPLAY] array. * @cmd_master_idx: The master controller for sending DSI commands to panel. * @video_master_idx: The master controller for enabling video engine. + * @cached_clk_rate: The cached DSI clock rate set dynamically by sysfs. + * @clkrate_change_pending: Flag indicating the pending DSI clock re-enabling. * @clock_info: Clock sourcing for DSI display. * @config: DSI host configuration information. * @lane_map: Lane mapping between DSI host and Panel. @@ -191,6 +193,10 @@ struct dsi_display { u32 cmd_master_idx; u32 video_master_idx; + /* dynamic DSI clock info*/ + u32 cached_clk_rate; + atomic_t clkrate_change_pending; + struct dsi_display_clk_info clock_info; struct dsi_host_config config; struct dsi_lane_map lane_map; -- GitLab From 7fe881f3ae6a94ee70f3be25bde749c2bf31be03 Mon Sep 17 00:00:00 2001 From: Yujun Zhang Date: Mon, 26 Mar 2018 15:48:59 +0800 Subject: [PATCH 0828/1635] drm/msm/dsi-staging: remove unnecessary check for dynamic DSI clock For dynamic DSI clock, remove unnecessary return status check, update log output with more meaningful description and simplify related log output to make code and log brief. CRs-Fixed: 2212653 Change-Id: Ie2cfa565f3358217dbc407abfdf25563dfa55eec Signed-off-by: Yujun Zhang --- .../gpu/drm/msm/dsi-staging/dsi_clk_manager.c | 7 ----- .../gpu/drm/msm/dsi-staging/dsi_ctrl_hw_cmn.c | 2 +- drivers/gpu/drm/msm/dsi-staging/dsi_display.c | 26 +++---------------- 3 files changed, 4 insertions(+), 31 deletions(-) diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_clk_manager.c b/drivers/gpu/drm/msm/dsi-staging/dsi_clk_manager.c index ae71dad5dd98..858769682740 100644 --- a/drivers/gpu/drm/msm/dsi-staging/dsi_clk_manager.c +++ b/drivers/gpu/drm/msm/dsi-staging/dsi_clk_manager.c @@ -1078,12 +1078,7 @@ static int dsi_display_link_clk_force_update(void *client) struct dsi_clk_mngr *mngr; struct dsi_link_clks *l_clks; - if (!client) { - pr_err("%s: Invalid arg\n", __func__); - return -EINVAL; - } mngr = c->mngr; - mutex_lock(&mngr->clk_mutex); l_clks = mngr->link_clks; @@ -1133,8 +1128,6 @@ int dsi_display_link_clk_force_update_ctrl(void *handle) mutex_lock(&dsi_mngr_clk_mutex); rc = dsi_display_link_clk_force_update(handle); - if (rc && (rc != -EAGAIN)) - pr_err("%s: failed set clk state, rc = %d\n", __func__, rc); mutex_unlock(&dsi_mngr_clk_mutex); diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw_cmn.c b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw_cmn.c index 28195d83c9cc..53717a50ccc8 100644 --- a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw_cmn.c +++ b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw_cmn.c @@ -1487,7 +1487,7 @@ int dsi_ctrl_hw_cmn_wait_for_cmd_mode_mdp_idle(struct dsi_ctrl_hw *ctrl) rc = readl_poll_timeout(ctrl->base + DSI_STATUS, val, !(val & cmd_mode_mdp_busy_mask), sleep_us, timeout_us); if (rc) - pr_err("%s: waiting failed, ret=%d\n", __func__, rc); + pr_err("%s: timed out waiting for idle\n", __func__); return rc; } diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_display.c b/drivers/gpu/drm/msm/dsi-staging/dsi_display.c index e8d1719ad7c3..d074df0256c8 100644 --- a/drivers/gpu/drm/msm/dsi-staging/dsi_display.c +++ b/drivers/gpu/drm/msm/dsi-staging/dsi_display.c @@ -3648,11 +3648,6 @@ static int dsi_display_force_update_dsi_clk(struct dsi_display *display) { int rc = 0; - if (!display || !display->panel) { - pr_err("Invalid params\n"); - return -EINVAL; - } - rc = dsi_display_link_clk_force_update_ctrl(display->dsi_clk_handle); if (!rc) { @@ -3660,8 +3655,6 @@ static int dsi_display_force_update_dsi_clk(struct dsi_display *display) display->cached_clk_rate); atomic_set(&display->clkrate_change_pending, 0); - } else if (rc == -EAGAIN) { - pr_info("Clock is disabled, update it next time\n"); } else { pr_err("Failed to configure dsi bit clock '%d'. rc = %d\n", display->cached_clk_rate, rc); @@ -3677,7 +3670,7 @@ static int dsi_display_request_update_dsi_bitrate(struct dsi_display *display, int i; pr_debug("%s:bit rate:%d\n", __func__, bit_clk_rate); - if (!display || !display->panel) { + if (!display->panel) { pr_err("Invalid params\n"); return -EINVAL; } @@ -3756,11 +3749,6 @@ static ssize_t sysfs_dynamic_dsi_clk_read(struct device *dev, struct dsi_display_ctrl *m_ctrl; struct dsi_ctrl *ctrl; - if (!dev) { - pr_err("Invalid device\n"); - return -EINVAL; - } - display = dev_get_drvdata(dev); if (!display) { pr_err("Invalid display\n"); @@ -3776,7 +3764,7 @@ static ssize_t sysfs_dynamic_dsi_clk_read(struct device *dev, * 8; rc = snprintf(buf, PAGE_SIZE, "%d\n", display->cached_clk_rate); - pr_info("%s: read dsi clk rate %d\n", __func__, + pr_debug("%s: read dsi clk rate %d\n", __func__, display->cached_clk_rate); mutex_unlock(&display->display_lock); @@ -3791,11 +3779,6 @@ static ssize_t sysfs_dynamic_dsi_clk_write(struct device *dev, int clk_rate; struct dsi_display *display; - if (!dev) { - pr_err("Invalid device\n"); - return -EINVAL; - } - display = dev_get_drvdata(dev); if (!display) { pr_err("Invalid display\n"); @@ -5481,11 +5464,8 @@ int dsi_display_pre_kickoff(struct drm_connector *connector, int ret = 0; ret = dsi_ctrl_wait_for_cmd_mode_mdp_idle(ctrl); - if (ret) { - pr_info("Failed to wait for cmd engine not to be busy sending data from MDP, rc: %d\n", - ret); + if (ret) goto wait_failure; - } } /* -- GitLab From b1732400c316bbca8534095ebb936fe7e98bc109 Mon Sep 17 00:00:00 2001 From: Alexei Avshalom Lazar Date: Wed, 25 Apr 2018 12:05:26 +0300 Subject: [PATCH 0829/1635] msm_11ad: Add support for triple MSI Current code assumes single interrupt for 11ad device. Extend support for triple MSI which may be supported by the device. Change-Id: I81c5bc428a070344f3dab0ecbeead8794e717967 Signed-off-by: Alexei Avshalom Lazar --- .../net/wireless/ath/wil6210/wil_platform.h | 1 + drivers/platform/msm/msm_11ad/msm_11ad.c | 59 +++++++++++++------ 2 files changed, 43 insertions(+), 17 deletions(-) diff --git a/drivers/net/wireless/ath/wil6210/wil_platform.h b/drivers/net/wireless/ath/wil6210/wil_platform.h index 177026e5323b..bca090611477 100644 --- a/drivers/net/wireless/ath/wil6210/wil_platform.h +++ b/drivers/net/wireless/ath/wil6210/wil_platform.h @@ -29,6 +29,7 @@ enum wil_platform_event { enum wil_platform_features { WIL_PLATFORM_FEATURE_FW_EXT_CLK_CONTROL = 0, + WIL_PLATFORM_FEATURE_TRIPLE_MSI = 1, WIL_PLATFORM_FEATURE_MAX, }; diff --git a/drivers/platform/msm/msm_11ad/msm_11ad.c b/drivers/platform/msm/msm_11ad/msm_11ad.c index fb8f91643f62..3eb263722887 100644 --- a/drivers/platform/msm/msm_11ad/msm_11ad.c +++ b/drivers/platform/msm/msm_11ad/msm_11ad.c @@ -131,7 +131,8 @@ struct msm11ad_ctx { /* cpu boost support */ bool use_cpu_boost; bool is_cpu_boosted; - struct cpumask boost_cpu; + struct cpumask boost_cpu_0; + struct cpumask boost_cpu_1; bool keep_radio_on_during_sleep; int features; @@ -964,13 +965,22 @@ static void msm_11ad_init_cpu_boost(struct msm11ad_ctx *ctx) if (minfreq != maxfreq) { /* - * use first big core for boost, to be compatible with WLAN + * use first 2 big cores for boost, to be compatible with WLAN * which assigns big cores from the last index */ ctx->use_cpu_boost = true; - cpumask_clear(&ctx->boost_cpu); - cpumask_set_cpu(boost_cpu, &ctx->boost_cpu); - dev_info(ctx->dev, "CPU boost: will use core %d\n", boost_cpu); + cpumask_clear(&ctx->boost_cpu_0); + cpumask_clear(&ctx->boost_cpu_1); + cpumask_set_cpu(boost_cpu, &ctx->boost_cpu_0); + if (boost_cpu < (nr_cpu_ids - 1)) { + cpumask_set_cpu(boost_cpu + 1, &ctx->boost_cpu_1); + dev_info(ctx->dev, "CPU boost: will use cores %d - %d\n", + boost_cpu, boost_cpu + 1); + } else { + cpumask_set_cpu(boost_cpu, &ctx->boost_cpu_1); + dev_info(ctx->dev, "CPU boost: will use core %d\n", + boost_cpu); + } } else { ctx->use_cpu_boost = false; dev_info(ctx->dev, "CPU boost disabled, uniform topology\n"); @@ -1253,7 +1263,8 @@ static struct platform_driver msm_11ad_driver = { }; module_platform_driver(msm_11ad_driver); -static void msm_11ad_set_boost_affinity(struct msm11ad_ctx *ctx) +static void msm_11ad_set_affinity_hint(struct msm11ad_ctx *ctx, uint irq, + struct cpumask *boost_cpu) { /* * There is a very small window where user space can change the @@ -1264,15 +1275,14 @@ static void msm_11ad_set_boost_affinity(struct msm11ad_ctx *ctx) struct irq_desc *desc; while (retries > 0) { - irq_modify_status(ctx->pcidev->irq, IRQ_NO_BALANCING, 0); - rc = irq_set_affinity_hint(ctx->pcidev->irq, &ctx->boost_cpu); + irq_modify_status(irq, IRQ_NO_BALANCING, 0); + rc = irq_set_affinity_hint(irq, boost_cpu); if (rc) dev_warn(ctx->dev, "Failed set affinity, rc=%d\n", rc); - irq_modify_status(ctx->pcidev->irq, 0, IRQ_NO_BALANCING); - desc = irq_to_desc(ctx->pcidev->irq); - if (cpumask_equal(desc->irq_common_data.affinity, - &ctx->boost_cpu)) + irq_modify_status(irq, 0, IRQ_NO_BALANCING); + desc = irq_to_desc(irq); + if (cpumask_equal(desc->irq_common_data.affinity, boost_cpu)) break; retries--; } @@ -1281,15 +1291,30 @@ static void msm_11ad_set_boost_affinity(struct msm11ad_ctx *ctx) dev_warn(ctx->dev, "failed to set CPU boost affinity\n"); } -static void msm_11ad_clear_boost_affinity(struct msm11ad_ctx *ctx) +static void msm_11ad_set_boost_affinity(struct msm11ad_ctx *ctx) +{ + msm_11ad_set_affinity_hint(ctx, ctx->pcidev->irq, &ctx->boost_cpu_0); + /* boost rx and tx interrupts */ + if (ctx->features & BIT(WIL_PLATFORM_FEATURE_TRIPLE_MSI)) + msm_11ad_set_affinity_hint(ctx, ctx->pcidev->irq + 1, + &ctx->boost_cpu_1); +} + +static void msm_11ad_clear_affinity_hint(struct msm11ad_ctx *ctx, uint irq) { int rc; - irq_modify_status(ctx->pcidev->irq, IRQ_NO_BALANCING, 0); - rc = irq_set_affinity_hint(ctx->pcidev->irq, NULL); + irq_modify_status(irq, IRQ_NO_BALANCING, 0); + rc = irq_set_affinity_hint(irq, NULL); if (rc) - dev_warn(ctx->dev, - "Failed clear affinity, rc=%d\n", rc); + dev_warn(ctx->dev, "Failed clear affinity, rc=%d\n", rc); +} + +static void msm_11ad_clear_boost_affinity(struct msm11ad_ctx *ctx) +{ + msm_11ad_clear_affinity_hint(ctx, ctx->pcidev->irq); + if (ctx->features & BIT(WIL_PLATFORM_FEATURE_TRIPLE_MSI)) + msm_11ad_clear_affinity_hint(ctx, ctx->pcidev->irq + 1); } /* hooks for the wil6210 driver */ -- GitLab From 76119ca2d089b51e03c5b30e7053c13de24b3139 Mon Sep 17 00:00:00 2001 From: Yuan Zhao Date: Wed, 25 Apr 2018 12:17:11 +0800 Subject: [PATCH 0830/1635] ARM: dts: msm: Disable ESD check for QRD SM8150 panel Disable the ESD check on SM8150 QRD platform, add the panel power control to match the new configuration. Change-Id: I081d21f2115bd460e6fcae4284a3fb0b6131ef19 Signed-off-by: Yuan Zhao --- arch/arm64/boot/dts/qcom/sm8150-qrd.dtsi | 3 +++ arch/arm64/boot/dts/qcom/sm8150-sde-display.dtsi | 7 ------- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sm8150-qrd.dtsi b/arch/arm64/boot/dts/qcom/sm8150-qrd.dtsi index 758feb54689c..3e444d236b2d 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-qrd.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-qrd.dtsi @@ -213,6 +213,9 @@ &dsi_sw43404_amoled_cmd_display { qcom,dsi-display-active; +}; + +&sde_dsi { vdd-supply = <&display_panel_avdd_eldo>; }; diff --git a/arch/arm64/boot/dts/qcom/sm8150-sde-display.dtsi b/arch/arm64/boot/dts/qcom/sm8150-sde-display.dtsi index b3ffea9ae99b..bb48488ce26e 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-sde-display.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-sde-display.dtsi @@ -618,13 +618,6 @@ &dsi_sw43404_amoled_cmd { qcom,mdss-dsi-t-clk-post = <0x16>; qcom,mdss-dsi-t-clk-pre = <0x16>; - qcom,esd-check-enabled; - qcom,mdss-dsi-panel-status-check-mode = "reg_read"; - qcom,mdss-dsi-panel-status-command = [06 01 00 01 00 00 01 0a]; - qcom,mdss-dsi-panel-status-command-state = "dsi_lp_mode"; - qcom,mdss-dsi-panel-status-value = <0x9c>; - qcom,mdss-dsi-panel-on-check-value = <0x9c>; - qcom,mdss-dsi-panel-status-read-length = <1>; qcom,mdss-dsi-display-timings { timing@0 { qcom,mdss-dsi-panel-phy-timings = [00 1a 07 06 22 21 07 -- GitLab From f1f59ece22bdd1ec2690cc869d1cd7d2241bdd8f Mon Sep 17 00:00:00 2001 From: Vinayak Menon Date: Fri, 26 Dec 2014 19:29:41 +0530 Subject: [PATCH 0831/1635] mm: vmscan: fix the page state calculation in too_many_isolated It is observed that sometimes multiple tasks get blocked in the congestion_wait loop below, in shrink_inactive_list. (__schedule) from [] (schedule_timeout) from [] (io_schedule_timeout) from [] (congestion_wait) from [] (shrink_inactive_list) from [] (shrink_zone) from [] (try_to_free_pages) from [] (__alloc_pages_nodemask) from [] (new_slab) from [] (__slab_alloc) from [] In one such instance, zone_page_state(zone, NR_ISOLATED_FILE) had returned 14, zone_page_state(zone, NR_INACTIVE_FILE) returned 92, and the gfp_flag was GFP_KERNEL which resulted in too_many_isolated to return true. But one of the CPU pageset vmstat diff had NR_ISOLATED_FILE as -14. As there weren't any more update to per cpu pageset, the threshold wasn't met, and the tasks were blocked in the congestion wait. This patch uses zone_page_state_snapshot instead, but restricts its usage to avoid performance penalty. Change-Id: Iec767a548e524729c7ed79a92fe4718cdd08ce69 Signed-off-by: Vinayak Menon Signed-off-by: Charan Teja Reddy --- mm/vmscan.c | 65 +++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 46 insertions(+), 19 deletions(-) diff --git a/mm/vmscan.c b/mm/vmscan.c index a8a3729bfaa9..293fe9d3bd5a 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -1637,6 +1637,44 @@ int isolate_lru_page(struct page *page) return ret; } +static int __too_many_isolated(struct pglist_data *pgdat, int file, + struct scan_control *sc, bool stalled) +{ + unsigned long inactive, isolated; + + if (file) { + if (stalled) { + inactive = node_page_state_snapshot(pgdat, + NR_INACTIVE_FILE); + isolated = node_page_state_snapshot(pgdat, + NR_ISOLATED_FILE); + } else { + inactive = node_page_state(pgdat, NR_INACTIVE_FILE); + isolated = node_page_state(pgdat, NR_ISOLATED_FILE); + } + } else { + if (stalled) { + inactive = node_page_state_snapshot(pgdat, + NR_INACTIVE_ANON); + isolated = node_page_state_snapshot(pgdat, + NR_ISOLATED_ANON); + } else { + inactive = node_page_state(pgdat, NR_INACTIVE_ANON); + isolated = node_page_state(pgdat, NR_ISOLATED_ANON); + } + } + + /* + * GFP_NOIO/GFP_NOFS callers are allowed to isolate more pages, so they + * won't get blocked by normal direct-reclaimers, forming a circular + * deadlock. + */ + if ((sc->gfp_mask & (__GFP_IO | __GFP_FS)) == (__GFP_IO | __GFP_FS)) + inactive >>= 3; + + return isolated > inactive; +} + /* * A direct reclaimer may isolate SWAP_CLUSTER_MAX pages from the LRU list and * then get resheduled. When there are massive number of tasks doing page @@ -1645,33 +1683,22 @@ int isolate_lru_page(struct page *page) * unnecessary swapping, thrashing and OOM. */ static int too_many_isolated(struct pglist_data *pgdat, int file, - struct scan_control *sc) + struct scan_control *sc, bool stalled) { - unsigned long inactive, isolated; - if (current_is_kswapd()) return 0; if (!sane_reclaim(sc)) return 0; - if (file) { - inactive = node_page_state(pgdat, NR_INACTIVE_FILE); - isolated = node_page_state(pgdat, NR_ISOLATED_FILE); - } else { - inactive = node_page_state(pgdat, NR_INACTIVE_ANON); - isolated = node_page_state(pgdat, NR_ISOLATED_ANON); + if (unlikely(__too_many_isolated(pgdat, file, sc, false))) { + if (stalled) + return __too_many_isolated(pgdat, file, sc, stalled); + else + return 1; } - /* - * GFP_NOIO/GFP_NOFS callers are allowed to isolate more pages, so they - * won't get blocked by normal direct-reclaimers, forming a circular - * deadlock. - */ - if ((sc->gfp_mask & (__GFP_IO | __GFP_FS)) == (__GFP_IO | __GFP_FS)) - inactive >>= 3; - - return isolated > inactive; + return 0; } static noinline_for_stack void @@ -1761,7 +1788,7 @@ shrink_inactive_list(unsigned long nr_to_scan, struct lruvec *lruvec, struct zone_reclaim_stat *reclaim_stat = &lruvec->reclaim_stat; bool stalled = false; - while (unlikely(too_many_isolated(pgdat, file, sc))) { + while (unlikely(too_many_isolated(pgdat, file, sc, stalled))) { if (stalled) return 0; -- GitLab From 5d3323ae0461ac364883892965a5fdf4cbe6da79 Mon Sep 17 00:00:00 2001 From: Vinayak Menon Date: Wed, 5 Apr 2017 10:49:14 +0530 Subject: [PATCH 0832/1635] mm: allow page poisoning to be enabled by default. Add a config option to enable page poisoning by default. The kernel command line option "page_poison" can be used to change the behaviour during boot. Change-Id: Ie70763841191a722b1c6125dfad119a29ed0f605 Signed-off-by: Vinayak Menon Signed-off-by: Charan Teja Reddy --- mm/Kconfig.debug | 10 ++++++++++ mm/page_poison.c | 3 ++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/mm/Kconfig.debug b/mm/Kconfig.debug index 3959c10009b6..02f01adc2eef 100644 --- a/mm/Kconfig.debug +++ b/mm/Kconfig.debug @@ -63,6 +63,16 @@ config PAGE_POISONING If unsure, say N +config PAGE_POISONING_ENABLE_DEFAULT + bool "Enable page poisoning by default?" + default n + depends on PAGE_POISONING + ---help--- + Enable page poisoning of free pages by default? This value + can be overridden by page_poison=off|on. This can be used + to avoid passing the kernel parameter and let page poisoning + feature enabled by default. + config PAGE_POISONING_NO_SANITY depends on PAGE_POISONING bool "Only poison, don't sanity check" diff --git a/mm/page_poison.c b/mm/page_poison.c index e83fd44867de..2885f89917ad 100644 --- a/mm/page_poison.c +++ b/mm/page_poison.c @@ -7,7 +7,8 @@ #include #include -static bool want_page_poisoning __read_mostly; +static bool want_page_poisoning __read_mostly + = IS_ENABLED(CONFIG_PAGE_POISONING_ENABLE_DEFAULT); static int early_page_poison_param(char *buf) { -- GitLab From 5e3f16b0cde8d82a1cb8d27cb3c7467de80ca296 Mon Sep 17 00:00:00 2001 From: Shefali Jain Date: Wed, 25 Apr 2018 15:24:57 +0530 Subject: [PATCH 0833/1635] ARM: dts: msm: Update GDSC device nodes for QCS405 Currently the device nodes of GDSC uses the fixed regulators, update them to register with gdsc regulator. Change-Id: Ibf226b1c05ea1badade6b67d582baa9551b38b9e Signed-off-by: Shefali Jain --- arch/arm64/boot/dts/qcom/qcs405-gdsc.dtsi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/qcs405-gdsc.dtsi b/arch/arm64/boot/dts/qcom/qcs405-gdsc.dtsi index 7dac7132fd17..52d3ffb8a78a 100644 --- a/arch/arm64/boot/dts/qcom/qcs405-gdsc.dtsi +++ b/arch/arm64/boot/dts/qcom/qcs405-gdsc.dtsi @@ -14,14 +14,14 @@ &soc { /* GDSCs in Global CC */ gdsc_mdss: qcom,gdsc@184d078 { - compatible = "regulator-fixed"; + compatible = "qcom,gdsc"; regulator-name = "gdsc_mdss"; reg = <0x184d078 0x4>; status = "disabled"; }; gdsc_oxili_gx: qcom,gdsc@185901c { - compatible = "regulator-fixed"; + compatible = "qcom,gdsc"; regulator-name = "gdsc_oxili_gx"; reg = <0x185901c 0x4>; status = "disabled"; -- GitLab From f010656d0f008bf9faf5461d72be0034d978bb99 Mon Sep 17 00:00:00 2001 From: Prateek Sood Date: Tue, 24 Apr 2018 12:31:47 +0530 Subject: [PATCH 0834/1635] ARM: dts: msm: Add support for core hang detection Add support for core hang detection feature for sdm640. Change-Id: I15ffb16f89bf8fe920e961e73dc07dd56d86c937 Signed-off-by: Prateek Sood --- arch/arm64/boot/dts/qcom/sdm640.dtsi | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sdm640.dtsi b/arch/arm64/boot/dts/qcom/sdm640.dtsi index aaf7786cd472..7ec6f9cc7732 100644 --- a/arch/arm64/boot/dts/qcom/sdm640.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm640.dtsi @@ -681,6 +681,24 @@ qcom,wakeup-enable; }; + qcom,chd_sliver { + compatible = "qcom,core-hang-detect"; + label = "silver"; + qcom,threshold-arr = <0x18000058 0x18010058 + 0x18020058 0x18030058 + 0x18040058 0x18050058>; + qcom,config-arr = <0x18000060 0x18010060 + 0x18020060 0x18030060 + 0x18040060 0x18050060>; + }; + + qcom,chd_gold { + compatible = "qcom,core-hang-detect"; + label = "gold"; + qcom,threshold-arr = <0x18060058 0x18070058>; + qcom,config-arr = <0x18060060 0x18070060>; + }; + kryo-erp { compatible = "arm,arm64-kryo-cpu-erp"; interrupts = <1 6 4>, -- GitLab From dc5b08a6d173f202b67f58767dc704b03f14b129 Mon Sep 17 00:00:00 2001 From: Prateek Sood Date: Tue, 24 Apr 2018 12:41:25 +0530 Subject: [PATCH 0835/1635] ARM: dts: msm: Remove errirq interrupts EDAC feature uses the fault irq for identification of L1/L2/L3 errors. Remove unused errirq interrupts. Change-Id: I29134660ffd25f682fbe7011c4cce4a44b45f1e5 Signed-off-by: Prateek Sood --- arch/arm64/boot/dts/qcom/sdm640.dtsi | 4 ---- 1 file changed, 4 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sdm640.dtsi b/arch/arm64/boot/dts/qcom/sdm640.dtsi index 7ec6f9cc7732..fa5ba6492bba 100644 --- a/arch/arm64/boot/dts/qcom/sdm640.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm640.dtsi @@ -702,13 +702,9 @@ kryo-erp { compatible = "arm,arm64-kryo-cpu-erp"; interrupts = <1 6 4>, - <1 7 4>, - <0 34 4>, <0 35 4>; interrupt-names = "l1-l2-faultirq", - "l1-l2-errirq", - "l3-scu-errirq", "l3-scu-faultirq"; }; -- GitLab From 2e71828dc8f55931cee96276da0873bdef728ae9 Mon Sep 17 00:00:00 2001 From: Shefali Jain Date: Wed, 25 Apr 2018 14:25:00 +0530 Subject: [PATCH 0836/1635] ARM: dts: msm: Update the GCC clock node for QCS405 Update the global clock controller node to use the gcc clock driver. Add the clocks and regulator handles for the same. Change-Id: Ib21ecac70e0e433c7abf8dbd5f05c86aef7dff99 Signed-off-by: Shefali Jain --- arch/arm64/boot/dts/qcom/qcs405.dtsi | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/qcs405.dtsi b/arch/arm64/boot/dts/qcom/qcs405.dtsi index 91eee94a1ebb..ddec57236062 100644 --- a/arch/arm64/boot/dts/qcom/qcs405.dtsi +++ b/arch/arm64/boot/dts/qcom/qcs405.dtsi @@ -143,8 +143,12 @@ }; clock_gcc: qcom,gcc { - compatible = "qcom,dummycc"; - clock-output-names = "gcc_clocks"; + compatible = "qcom,gcc-qcs405", "syscon"; + reg = <0x1800000 0x80000>; + reg-names = "cc_base"; + vdd_cx-supply = <&pmd9655_s1_level>; + clocks = <&clock_rpmcc RPM_SMD_XO_CLK_SRC>; + clock-names = "cxo"; #clock-cells = <1>; #reset-cells = <1>; }; -- GitLab From 5265e232d2718fa13c4aeb705824b1d7e8a1970c Mon Sep 17 00:00:00 2001 From: Steve Cohen Date: Mon, 23 Apr 2018 10:30:59 -0400 Subject: [PATCH 0837/1635] msm: sde: apply mask for sw timestamps Apply the sw-timestamp mask for high priority and low priority timestamps when reading or writing these values. This is to prevent status bits from affecting the timestamp functionality. Change-Id: I78b99b0978fbde707addae8e2cad568c2c963192 Signed-off-by: Steve Cohen --- .../platform/msm/sde/rotator/sde_rotator_r3.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c b/drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c index 2ff3432033ae..d9f3fdc012cd 100644 --- a/drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c +++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c @@ -2297,8 +2297,10 @@ void sde_hw_rotator_pre_pmevent(struct sde_rot_mgr *mgr, bool pmon) */ if (!pmon && mgr && mgr->hw_data) { rot = mgr->hw_data; - h_ts = atomic_read(&rot->timestamp[ROT_QUEUE_HIGH_PRIORITY]); - l_ts = atomic_read(&rot->timestamp[ROT_QUEUE_LOW_PRIORITY]); + h_ts = atomic_read(&rot->timestamp[ROT_QUEUE_HIGH_PRIORITY]) & + SDE_REGDMA_SWTS_MASK; + l_ts = atomic_read(&rot->timestamp[ROT_QUEUE_LOW_PRIORITY]) & + SDE_REGDMA_SWTS_MASK; /* Need to turn on clock to access rotator register */ sde_rotator_clk_ctrl(mgr, true); @@ -2373,8 +2375,10 @@ void sde_hw_rotator_post_pmevent(struct sde_rot_mgr *mgr, bool pmon) SDEROT_DBG("h_ts:0x%x, l_ts;0x%x\n", h_ts, l_ts); SDEROT_EVTLOG(h_ts, l_ts); rot->reset_hw_ts = true; - rot->last_hwts[ROT_QUEUE_LOW_PRIORITY] = l_ts; - rot->last_hwts[ROT_QUEUE_HIGH_PRIORITY] = h_ts; + rot->last_hwts[ROT_QUEUE_LOW_PRIORITY] = + l_ts & SDE_REGDMA_SWTS_MASK; + rot->last_hwts[ROT_QUEUE_HIGH_PRIORITY] = + h_ts & SDE_REGDMA_SWTS_MASK; } } @@ -2678,10 +2682,13 @@ static int sde_hw_rotator_config(struct sde_rot_hw_resource *hw, l_ts = atomic_read(&rot->timestamp[ROT_QUEUE_LOW_PRIORITY]); SDEROT_EVTLOG(0xbad0, rststs, l_hwts, h_hwts, l_ts, h_ts); - if (ctx->q_id == ROT_QUEUE_HIGH_PRIORITY) + if (ctx->q_id == ROT_QUEUE_HIGH_PRIORITY) { h_ts = (h_ts - 1) & SDE_REGDMA_SWTS_MASK; - else + l_ts &= SDE_REGDMA_SWTS_MASK; + } else { l_ts = (l_ts - 1) & SDE_REGDMA_SWTS_MASK; + h_ts &= SDE_REGDMA_SWTS_MASK; + } SDEROT_DBG("h_ts:0x%x, l_ts;0x%x\n", h_ts, l_ts); SDEROT_EVTLOG(0x900d, h_ts, l_ts); -- GitLab From bf3742df7592f19a9c8e92f9a0075c6688163ed3 Mon Sep 17 00:00:00 2001 From: "Isaac J. Manjarres" Date: Thu, 12 Apr 2018 13:55:59 -0700 Subject: [PATCH 0838/1635] ARM: dts: msm: Add support for L1 TLB dumping Enable dumping of instruction and data L1 TLBs on the sm8150's gold cluster. Change-Id: Idd41840bcba8e8403be396777ad7635baad28738 Signed-off-by: Isaac J. Manjarres --- arch/arm64/boot/dts/qcom/sm8150.dtsi | 72 ++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sm8150.dtsi b/arch/arm64/boot/dts/qcom/sm8150.dtsi index dd28cfca9eaa..c4a997206f5a 100644 --- a/arch/arm64/boot/dts/qcom/sm8150.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150.dtsi @@ -222,6 +222,14 @@ qcom,dump-size = <0x12000>; }; + L1_ITLB_400: l1-itlb { + qcom,dump-size = <0x300>; + }; + + L1_DTLB_400: l1-dtlb { + qcom,dump-size = <0x480>; + }; + L2_TLB_400: l2-tlb { qcom,dump-size = <0x7800>; }; @@ -255,6 +263,14 @@ qcom,dump-size = <0x12000>; }; + L1_ITLB_500: l1-itlb { + qcom,dump-size = <0x300>; + }; + + L1_DTLB_500: l1-dtlb { + qcom,dump-size = <0x480>; + }; + L2_TLB_500: l2-tlb { qcom,dump-size = <0x7800>; }; @@ -288,6 +304,14 @@ qcom,dump-size = <0x12000>; }; + L1_ITLB_600: l1-itlb { + qcom,dump-size = <0x300>; + }; + + L1_DTLB_600: l1-dtlb { + qcom,dump-size = <0x480>; + }; + L2_TLB_600: l2-tlb { qcom,dump-size = <0x7800>; }; @@ -321,6 +345,14 @@ qcom,dump-size = <0x12000>; }; + L1_ITLB_700: l1-itlb { + qcom,dump-size = <0x300>; + }; + + L1_DTLB_700: l1-dtlb { + qcom,dump-size = <0x480>; + }; + L2_TLB_700: l2-tlb { qcom,dump-size = <0x7800>; }; @@ -1880,6 +1912,46 @@ qcom,dump-id = <0x87>; }; + qcom,l1_i_tlb_dump400 { + qcom,dump-node = <&L1_ITLB_400>; + qcom,dump-id = <0x24>; + }; + + qcom,l1_i_tlb_dump500 { + qcom,dump-node = <&L1_ITLB_500>; + qcom,dump-id = <0x25>; + }; + + qcom,l1_i_tlb_dump600 { + qcom,dump-node = <&L1_ITLB_600>; + qcom,dump-id = <0x26>; + }; + + qcom,l1_i_tlb_dump700 { + qcom,dump-node = <&L1_ITLB_700>; + qcom,dump-id = <0x27>; + }; + + qcom,l1_d_tlb_dump400 { + qcom,dump-node = <&L1_DTLB_400>; + qcom,dump-id = <0x44>; + }; + + qcom,l1_d_tlb_dump500 { + qcom,dump-node = <&L1_DTLB_500>; + qcom,dump-id = <0x45>; + }; + + qcom,l1_d_tlb_dump600 { + qcom,dump-node = <&L1_DTLB_600>; + qcom,dump-id = <0x46>; + }; + + qcom,l1_d_tlb_dump700 { + qcom,dump-node = <&L1_DTLB_700>; + qcom,dump-id = <0x47>; + }; + qcom,l2_tlb_dump0 { qcom,dump-node = <&L2_TLB_0>; qcom,dump-id = <0x120>; -- GitLab From 272f3dabfe0f59c1d2412497ecbd13f814766039 Mon Sep 17 00:00:00 2001 From: "Isaac J. Manjarres" Date: Wed, 25 Apr 2018 10:04:31 -0700 Subject: [PATCH 0839/1635] ARM: dts: msm: Add support for L2 Cache dumping Enable dumping of L2 cache on the sm8150's gold cluster. Change-Id: I8e5892951ac45ef287a3d86f0e778d133dd3e9b4 Signed-off-by: Isaac J. Manjarres --- arch/arm64/boot/dts/qcom/sm8150.dtsi | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sm8150.dtsi b/arch/arm64/boot/dts/qcom/sm8150.dtsi index c4a997206f5a..eb7e9b4c7fd4 100644 --- a/arch/arm64/boot/dts/qcom/sm8150.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150.dtsi @@ -210,6 +210,7 @@ cache-size = <0x40000>; cache-level = <2>; next-level-cache = <&L3_0>; + qcom,dump-size = <0x88000>; }; L1_I_400: l1-icache { @@ -251,6 +252,7 @@ cache-size = <0x40000>; cache-level = <2>; next-level-cache = <&L3_0>; + qcom,dump-size = <0x88000>; }; L1_I_500: l1-icache { @@ -292,6 +294,7 @@ cache-size = <0x40000>; cache-level = <2>; next-level-cache = <&L3_0>; + qcom,dump-size = <0x88000>; }; L1_I_600: l1-icache { @@ -333,6 +336,7 @@ cache-size = <0x80000>; cache-level = <2>; next-level-cache = <&L3_0>; + qcom,dump-size = <0x110000>; }; L1_I_700: l1-icache { @@ -1952,6 +1956,26 @@ qcom,dump-id = <0x47>; }; + qcom,l2_cache_dump400 { + qcom,dump-node = <&L2_4>; + qcom,dump-id = <0xc4>; + }; + + qcom,l2_cache_dump500 { + qcom,dump-node = <&L2_5>; + qcom,dump-id = <0xc5>; + }; + + qcom,l2_cache_dump600 { + qcom,dump-node = <&L2_6>; + qcom,dump-id = <0xc6>; + }; + + qcom,l2_cache_dump700 { + qcom,dump-node = <&L2_7>; + qcom,dump-id = <0xc7>; + }; + qcom,l2_tlb_dump0 { qcom,dump-node = <&L2_TLB_0>; qcom,dump-id = <0x120>; -- GitLab From f6604c4321392d1a812cda86b0bb41f10c4c0056 Mon Sep 17 00:00:00 2001 From: Carter Cooper Date: Mon, 16 Apr 2018 10:11:16 -0600 Subject: [PATCH 0840/1635] msm: kgsl: Don't allocate GMU dump memory if not used Older targets used this scratch memory for debug purposes. Newer targets don't use this memory so don't allocate it. Change-Id: I4bfae0fc10eedb289c6765a15d95045f46ffb96e Signed-off-by: Carter Cooper --- drivers/gpu/msm/kgsl_gmu.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/msm/kgsl_gmu.c b/drivers/gpu/msm/kgsl_gmu.c index b2dafe820e50..ea10b84c93f1 100644 --- a/drivers/gpu/msm/kgsl_gmu.c +++ b/drivers/gpu/msm/kgsl_gmu.c @@ -555,6 +555,8 @@ static void gmu_memory_close(struct gmu_device *gmu) */ static int gmu_memory_probe(struct gmu_device *gmu, struct device_node *node) { + struct kgsl_device *device = container_of(gmu, struct kgsl_device, gmu); + struct adreno_device *adreno_dev = ADRENO_DEVICE(device); int ret; ret = gmu_iommu_init(gmu, node); @@ -582,11 +584,13 @@ static int gmu_memory_probe(struct gmu_device *gmu, struct device_node *node) } /* Allocates & maps GMU crash dump memory */ - gmu->dump_mem = allocate_gmu_kmem(gmu, GMU_NONCACHED_KERNEL, - DUMPMEM_SIZE, (IOMMU_READ | IOMMU_WRITE)); - if (IS_ERR(gmu->dump_mem)) { - ret = PTR_ERR(gmu->dump_mem); - goto err_ret; + if (adreno_is_a630(adreno_dev)) { + gmu->dump_mem = allocate_gmu_kmem(gmu, GMU_NONCACHED_KERNEL, + DUMPMEM_SIZE, (IOMMU_READ | IOMMU_WRITE)); + if (IS_ERR(gmu->dump_mem)) { + ret = PTR_ERR(gmu->dump_mem); + goto err_ret; + } } /* GMU master log */ -- GitLab From c4193b3645809a152acbbdc40bcd4c848f4d1748 Mon Sep 17 00:00:00 2001 From: Nathan Chancellor Date: Wed, 25 Apr 2018 11:30:54 -0700 Subject: [PATCH 0841/1635] ANDROID: sched: Remove duplicate const specifier MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes the following warning while building with GCC 7.3.0: ../kernel/sched/sched.h:1127:34: warning: duplicate ‘const’ declaration specifier [-Wduplicate-decl-specifier] const struct sched_group_energy const *sge; ^~~~~ Change-Id: I779a2c042caa6e140cbcfe009070db57c9652970 Signed-off-by: Nathan Chancellor --- kernel/sched/sched.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h index 453ce4530dd9..3e0fef71f7a4 100644 --- a/kernel/sched/sched.h +++ b/kernel/sched/sched.h @@ -1124,7 +1124,7 @@ struct sched_group { unsigned int group_weight; struct sched_group_capacity *sgc; int asym_prefer_cpu; /* cpu of highest priority in group */ - const struct sched_group_energy const *sge; + const struct sched_group_energy *sge; /* * The CPUs this group covers. -- GitLab From 9bfda4c84044fee52794421f16faed212cd1a6c6 Mon Sep 17 00:00:00 2001 From: Harry Yang Date: Tue, 13 Mar 2018 22:37:53 -0700 Subject: [PATCH 0842/1635] power: smb5: Rearrange USB ICL SW configuration SW configures USB ICL by updating ICL_MAX to override APSD results. As APSD/PD flow has been re-organized by running APSD after PD, SW ICL configuration process has to be updated accordingly. Following is the order of power source precedence along with ICL_MAX set by SW. 1. USB PD: set by USB PD driver 2. HVDCP (Quick Charge 2.0/3.0): 3A 3. USB Type-C Rp-high: 3A; Rp-medium: 1.5A 4. USB Legacy/Type-C Rp-std: follow USB BC 1.2 CRs-Fixed: 2215965 Change-Id: Ibd1cd3d531c3132f3cfadad68f6bb10453c702f2 Signed-off-by: Harry Yang --- drivers/power/supply/qcom/qpnp-smb5.c | 20 +++- drivers/power/supply/qcom/smb5-lib.c | 128 +++++++++++++++++--------- drivers/power/supply/qcom/smb5-lib.h | 3 +- drivers/power/supply/qcom/smb5-reg.h | 2 + 4 files changed, 107 insertions(+), 46 deletions(-) diff --git a/drivers/power/supply/qcom/qpnp-smb5.c b/drivers/power/supply/qcom/qpnp-smb5.c index 6b40fb3b2a00..5a093cfaa9f4 100644 --- a/drivers/power/supply/qcom/qpnp-smb5.c +++ b/drivers/power/supply/qcom/qpnp-smb5.c @@ -51,6 +51,13 @@ static struct smb_params smb5_pmi632_params = { .max_u = 3000000, .step_u = 50000, }, + .icl_max_stat = { + .name = "dcdc icl max status", + .reg = ICL_MAX_STATUS_REG, + .min_u = 0, + .max_u = 3000000, + .step_u = 50000, + }, .icl_stat = { .name = "input current limit status", .reg = AICL_ICL_STATUS_REG, @@ -89,7 +96,7 @@ static struct smb_params smb5_pmi632_params = { }, }; -static struct smb_params smb5_pmi855_params = { +static struct smb_params smb5_pm855b_params = { .fcc = { .name = "fast charge current", .reg = CHGR_FAST_CHARGE_CURRENT_CFG_REG, @@ -111,8 +118,15 @@ static struct smb_params smb5_pmi855_params = { .max_u = 5000000, .step_u = 50000, }, + .icl_max_stat = { + .name = "dcdc icl max status", + .reg = ICL_MAX_STATUS_REG, + .min_u = 0, + .max_u = 5000000, + .step_u = 50000, + }, .icl_stat = { - .name = "input current limit status", + .name = "aicl icl status", .reg = AICL_ICL_STATUS_REG, .min_u = 0, .max_u = 5000000, @@ -215,7 +229,7 @@ static int smb5_chg_config_init(struct smb5 *chip) switch (pmic_rev_id->pmic_subtype) { case PM855B_SUBTYPE: chip->chg.smb_version = PM855B_SUBTYPE; - chg->param = smb5_pmi855_params; + chg->param = smb5_pm855b_params; chg->name = "pm855b_charger"; break; case PMI632_SUBTYPE: diff --git a/drivers/power/supply/qcom/smb5-lib.c b/drivers/power/supply/qcom/smb5-lib.c index fff32eccde99..db0844a060c0 100644 --- a/drivers/power/supply/qcom/smb5-lib.c +++ b/drivers/power/supply/qcom/smb5-lib.c @@ -38,6 +38,10 @@ __func__, ##__VA_ARGS__); \ } while (0) +#define typec_rp_med_high(chg, typec_mode) \ + ((typec_mode == POWER_SUPPLY_TYPEC_SOURCE_MEDIUM \ + || typec_mode == POWER_SUPPLY_TYPEC_SOURCE_HIGH) \ + && !chg->typec_legacy) int smblib_read(struct smb_charger *chg, u16 addr, u8 *val) { @@ -651,6 +655,7 @@ int smblib_mapping_cc_delta_from_field_value(struct smb_chg_param *param, return 0; } +#define SDP_100_MA 100000 static void smblib_uusb_removal(struct smb_charger *chg) { int rc; @@ -675,6 +680,7 @@ static void smblib_uusb_removal(struct smb_charger *chg) /* reset both usbin current and voltage votes */ vote(chg->pl_enable_votable_indirect, USBIN_I_VOTER, false, 0); vote(chg->pl_enable_votable_indirect, USBIN_V_VOTER, false, 0); + vote(chg->usb_icl_votable, SW_ICL_MAX_VOTER, true, SDP_100_MA); vote(chg->usb_icl_votable, SW_QC3_VOTER, false, 0); /* reconfigure allowed voltage for HVDCP */ @@ -868,6 +874,10 @@ int smblib_set_icl_current(struct smb_charger *chg, int icl_ua) set_mode: rc = smblib_masked_write(chg, USBIN_ICL_OPTIONS_REG, USBIN_MODE_CHG_BIT, hc_mode ? USBIN_MODE_CHG_BIT : 0); + if (rc < 0) { + smblib_err(chg, "Couldn't set USBIN_ICL_OPTIONS rc=%d\n", rc); + goto out; + } /* unsuspend after configuring current and override */ rc = smblib_set_usb_suspend(chg, false); @@ -905,7 +915,8 @@ int smblib_get_icl_current(struct smb_charger *chg, int *icl_ua) return INT_MAX; /* override is set */ - rc = smblib_get_charge_param(chg, &chg->param.usb_icl, icl_ua); + rc = smblib_get_charge_param(chg, &chg->param.icl_max_stat, + icl_ua); if (rc < 0) { smblib_err(chg, "Couldn't get HC ICL rc=%d\n", rc); return rc; @@ -2072,7 +2083,7 @@ static int smblib_handle_usb_current(struct smb_charger *chg, */ typec_mode = smblib_get_prop_typec_mode(chg); rp_ua = get_rp_based_dcp_current(chg, typec_mode); - rc = vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, + rc = vote(chg->usb_icl_votable, SW_ICL_MAX_VOTER, true, rp_ua); if (rc < 0) return rc; @@ -2087,7 +2098,7 @@ static int smblib_handle_usb_current(struct smb_charger *chg, true, usb_current); if (rc < 0) return rc; - rc = vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, + rc = vote(chg->usb_icl_votable, SW_ICL_MAX_VOTER, false, 0); if (rc < 0) return rc; @@ -2230,7 +2241,9 @@ int smblib_set_prop_pd_active(struct smb_charger *chg, * pd_current_max */ vote(chg->usb_icl_votable, PD_VOTER, true, USBIN_500MA); + vote(chg->usb_icl_votable, SW_ICL_MAX_VOTER, false, 0); } else { + vote(chg->usb_icl_votable, SW_ICL_MAX_VOTER, true, SDP_100_MA); vote(chg->usb_icl_votable, PD_VOTER, false, 0); vote(chg->usb_irq_enable_votable, PD_VOTER, false, 0); @@ -2773,17 +2786,16 @@ static void smblib_handle_hvdcp_check_timeout(struct smb_charger *chg, { if (rising) { - /* enable HDC and ICL irq for QC2/3 charger */ - if (qc_charger) + if (qc_charger) { + /* enable HDC and ICL irq for QC2/3 charger */ vote(chg->usb_irq_enable_votable, QC_VOTER, true, 0); - else - /* - * HVDCP detection timeout done - * If adapter is not QC2.0/QC3.0 - it is a plain old DCP. - * enforce DCP ICL if specified - */ + vote(chg->usb_icl_votable, SW_ICL_MAX_VOTER, true, + HVDCP_CURRENT_UA); + } else { + /* A plain DCP, enforce DCP ICL if specified */ vote(chg->usb_icl_votable, DCP_VOTER, chg->dcp_icl_ua != -EINVAL, chg->dcp_icl_ua); + } } smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s %s\n", __func__, @@ -2798,6 +2810,65 @@ static void smblib_handle_hvdcp_detect_done(struct smb_charger *chg, rising ? "rising" : "falling"); } +static void update_sw_icl_max(struct smb_charger *chg, int pst) +{ + int typec_mode; + int rp_ua; + + /* while PD is active it should have complete ICL control */ + if (chg->pd_active) + return; + + /* HVDCP 2/3, handled separately */ + if (pst == POWER_SUPPLY_TYPE_USB_HVDCP + || pst == POWER_SUPPLY_TYPE_USB_HVDCP_3) + return; + + /* TypeC rp med or high, use rp value */ + typec_mode = smblib_get_prop_typec_mode(chg); + if (typec_rp_med_high(chg, typec_mode)) { + rp_ua = get_rp_based_dcp_current(chg, typec_mode); + vote(chg->usb_icl_votable, SW_ICL_MAX_VOTER, true, rp_ua); + return; + } + + /* rp-std or legacy, USB BC 1.2 */ + switch (pst) { + case POWER_SUPPLY_TYPE_USB: + /* + * USB_PSY will vote to increase the current to 500/900mA once + * enumeration is done. + */ + if (!is_client_vote_enabled(chg->usb_icl_votable, + USB_PSY_VOTER)) + vote(chg->usb_icl_votable, USB_PSY_VOTER, true, + SDP_100_MA); + vote(chg->usb_icl_votable, SW_ICL_MAX_VOTER, false, 0); + break; + case POWER_SUPPLY_TYPE_USB_CDP: + vote(chg->usb_icl_votable, SW_ICL_MAX_VOTER, true, + CDP_CURRENT_UA); + break; + case POWER_SUPPLY_TYPE_USB_DCP: + vote(chg->usb_icl_votable, SW_ICL_MAX_VOTER, true, + DCP_CURRENT_UA); + break; + case POWER_SUPPLY_TYPE_USB_FLOAT: + /* + * limit ICL to 100mA, the USB driver will enumerate to check + * if this is a SDP and appropriately set the current + */ + vote(chg->usb_icl_votable, SW_ICL_MAX_VOTER, true, + SDP_100_MA); + break; + default: + smblib_err(chg, "Unknown APSD %d; forcing 500mA\n", pst); + vote(chg->usb_icl_votable, SW_ICL_MAX_VOTER, true, + SDP_CURRENT_UA); + break; + } +} + static void smblib_handle_apsd_done(struct smb_charger *chg, bool rising) { const struct apsd_result *apsd_result; @@ -2807,6 +2878,8 @@ static void smblib_handle_apsd_done(struct smb_charger *chg, bool rising) apsd_result = smblib_update_usb_type(chg); + update_sw_icl_max(chg, apsd_result->pst); + switch (apsd_result->bit) { case SDP_CHARGER_BIT: case CDP_CHARGER_BIT: @@ -2972,7 +3045,7 @@ static void typec_src_removal(struct smb_charger *chg) cancel_delayed_work_sync(&chg->pl_enable_work); /* reset input current limit voters */ - vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, true, 100000); + vote(chg->usb_icl_votable, SW_ICL_MAX_VOTER, true, SDP_100_MA); vote(chg->usb_icl_votable, PD_VOTER, false, 0); vote(chg->usb_icl_votable, USB_PSY_VOTER, false, 0); vote(chg->usb_icl_votable, DCP_VOTER, false, 0); @@ -3023,41 +3096,12 @@ static void typec_src_removal(struct smb_charger *chg) static void smblib_handle_rp_change(struct smb_charger *chg, int typec_mode) { - int rp_ua; const struct apsd_result *apsd = smblib_get_apsd_result(chg); - if ((apsd->pst != POWER_SUPPLY_TYPE_USB_DCP) - && (apsd->pst != POWER_SUPPLY_TYPE_USB_FLOAT)) - return; - - /* - * if APSD indicates FLOAT and the USB stack had detected SDP, - * do not respond to Rp changes as we do not confirm that its - * a legacy cable - */ - if (chg->real_charger_type == POWER_SUPPLY_TYPE_USB) - return; - /* - * We want the ICL vote @ 100mA for a FLOAT charger - * until the detection by the USB stack is complete. - * Ignore the Rp changes unless there is a - * pre-existing valid vote. - */ - if (apsd->pst == POWER_SUPPLY_TYPE_USB_FLOAT && - get_client_vote(chg->usb_icl_votable, - LEGACY_UNKNOWN_VOTER) <= 100000) - return; + update_sw_icl_max(chg, apsd->pst); - /* - * handle Rp change for DCP/FLOAT/OCP. - * Update the current only if the Rp is different from - * the last Rp value. - */ smblib_dbg(chg, PR_MISC, "CC change old_mode=%d new_mode=%d\n", chg->typec_mode, typec_mode); - - rp_ua = get_rp_based_dcp_current(chg, typec_mode); - vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, true, rp_ua); } irqreturn_t typec_or_rid_detection_change_irq_handler(int irq, void *data) diff --git a/drivers/power/supply/qcom/smb5-lib.h b/drivers/power/supply/qcom/smb5-lib.h index 3a4c4cf2ee3f..7f5f33a1bc60 100644 --- a/drivers/power/supply/qcom/smb5-lib.h +++ b/drivers/power/supply/qcom/smb5-lib.h @@ -56,7 +56,7 @@ enum print_reason { #define CTM_VOTER "CTM_VOTER" #define SW_QC3_VOTER "SW_QC3_VOTER" #define AICL_RERUN_VOTER "AICL_RERUN_VOTER" -#define LEGACY_UNKNOWN_VOTER "LEGACY_UNKNOWN_VOTER" +#define SW_ICL_MAX_VOTER "SW_ICL_MAX_VOTER" #define QNOVO_VOTER "QNOVO_VOTER" #define BATT_PROFILE_VOTER "BATT_PROFILE_VOTER" #define OTG_DELAY_VOTER "OTG_DELAY_VOTER" @@ -232,6 +232,7 @@ struct smb_params { struct smb_chg_param fcc; struct smb_chg_param fv; struct smb_chg_param usb_icl; + struct smb_chg_param icl_max_stat; struct smb_chg_param icl_stat; struct smb_chg_param otg_cl; struct smb_chg_param jeita_cc_comp_hot; diff --git a/drivers/power/supply/qcom/smb5-reg.h b/drivers/power/supply/qcom/smb5-reg.h index 92a52b2cf801..83cef8aa0bfc 100644 --- a/drivers/power/supply/qcom/smb5-reg.h +++ b/drivers/power/supply/qcom/smb5-reg.h @@ -104,6 +104,8 @@ enum { /******************************** * DCDC Peripheral Registers * ********************************/ +#define ICL_MAX_STATUS_REG (DCDC_BASE + 0x06) + #define AICL_ICL_STATUS_REG (DCDC_BASE + 0x08) #define AICL_STATUS_REG (DCDC_BASE + 0x0A) -- GitLab From 9d57d42d4ed99649aded636977a46735d2393575 Mon Sep 17 00:00:00 2001 From: Kyle Piefer Date: Wed, 25 Apr 2018 11:41:27 -0700 Subject: [PATCH 0843/1635] msm: kgsl: Prevent dual ownership of GMU counters The last two XO clock-based GMU power counters are owned by the GMU firmware. Mark them as broken to prevent KGSL from using them and causing dual ownership problems. Change-Id: I481f850153cbbce7ccf149e032c68e37cc112dac Signed-off-by: Kyle Piefer --- drivers/gpu/msm/adreno_a6xx.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/msm/adreno_a6xx.c b/drivers/gpu/msm/adreno_a6xx.c index 6c5dac651254..a365bab25eb2 100644 --- a/drivers/gpu/msm/adreno_a6xx.c +++ b/drivers/gpu/msm/adreno_a6xx.c @@ -2400,11 +2400,17 @@ static struct adreno_perfcount_register a6xx_pwrcounters_gpmu[] = { A6XX_GMU_CX_GMU_POWER_COUNTER_XOCLK_3_L, A6XX_GMU_CX_GMU_POWER_COUNTER_XOCLK_3_H, -1, A6XX_GMU_CX_GMU_POWER_COUNTER_SELECT_0, }, - { KGSL_PERFCOUNTER_NOT_USED, 0, 0, + /* + * Both A6XX_GMU_CX_GMU_POWER_COUNTER_XOCLK_4 and + * A6XX_GMU_CX_GMU_POWER_COUNTER_XOCLK_5 are owned + * by the GMU. Mark them as broken so there is no + * dual ownership. + */ + { KGSL_PERFCOUNTER_BROKEN, 0, 0, A6XX_GMU_CX_GMU_POWER_COUNTER_XOCLK_4_L, A6XX_GMU_CX_GMU_POWER_COUNTER_XOCLK_4_H, -1, A6XX_GMU_CX_GMU_POWER_COUNTER_SELECT_1, }, - { KGSL_PERFCOUNTER_NOT_USED, 0, 0, + { KGSL_PERFCOUNTER_BROKEN, 0, 0, A6XX_GMU_CX_GMU_POWER_COUNTER_XOCLK_5_L, A6XX_GMU_CX_GMU_POWER_COUNTER_XOCLK_5_H, -1, A6XX_GMU_CX_GMU_POWER_COUNTER_SELECT_1, }, -- GitLab From 88a0dc6f9e56100af3ef352025229a47856e1cfb Mon Sep 17 00:00:00 2001 From: Ajay Singh Parmar Date: Fri, 20 Apr 2018 16:37:13 -0700 Subject: [PATCH 0844/1635] ARM: dts: msm: move common nodes to sde display for SM8150 Move the device tree nodes which are common for all variants of SM8150 to main sde display device tree so that they can be used for any hardware variant. CRs-Fixed: 2223812 Change-Id: I6e860fa4f9463645466fa086812f966b1c34a257 Signed-off-by: Ajay Singh Parmar --- arch/arm64/boot/dts/qcom/sm8150-qrd.dtsi | 29 ------------------- .../boot/dts/qcom/sm8150-sde-display.dtsi | 28 ++++++++++++++++++ 2 files changed, 28 insertions(+), 29 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sm8150-qrd.dtsi b/arch/arm64/boot/dts/qcom/sm8150-qrd.dtsi index 758feb54689c..c31998e7b857 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-qrd.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-qrd.dtsi @@ -164,35 +164,6 @@ }; }; -&tlmm { - display_panel_avdd_eldo_default: display_panel_avdd_eldo_default { - mux { - pins = "gpio130"; - function = "gpio"; - }; - config { - pins = "gpio130"; - drive-strength = <8>; - bias-disable = <0>; - output-low; - }; - }; -}; - -&soc { - display_panel_avdd_eldo: display-gpio-regulator@0 { - compatible = "regulator-fixed"; - regulator-name = "display_panel_avdd_eldo"; - regulator-min-microvolt = <1800000>; - regulator-max-microvolt = <1800000>; - regulator-enable-ramp-delay = <233>; - gpio = <&tlmm 130 0>; - enable-active-high; - pinctrl-names = "default"; - pintctrl-0 = <&display_panel_avdd_eldo_default>; - }; -}; - &dsi_panel_pwr_supply_vdd_no_labibb { qcom,panel-supply-entry@1 { qcom,supply-min-voltage = <1800000>; diff --git a/arch/arm64/boot/dts/qcom/sm8150-sde-display.dtsi b/arch/arm64/boot/dts/qcom/sm8150-sde-display.dtsi index b3ffea9ae99b..73ebd8f991da 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-sde-display.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-sde-display.dtsi @@ -30,6 +30,21 @@ #include "dsi-panel-sw43404-amoled-dsc-wqhd-cmd.dtsi" #include +&tlmm { + display_panel_avdd_eldo_default: display_panel_avdd_eldo_default { + mux { + pins = "gpio130"; + function = "gpio"; + }; + config { + pins = "gpio130"; + drive-strength = <8>; + bias-disable = <0>; + output-low; + }; + }; +}; + &soc { dsi_panel_pwr_supply: dsi_panel_pwr_supply { #address-cells = <1>; @@ -105,6 +120,18 @@ }; }; + display_panel_avdd_eldo: display-gpio-regulator@0 { + compatible = "regulator-fixed"; + regulator-name = "display_panel_avdd_eldo"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-enable-ramp-delay = <233>; + gpio = <&tlmm 130 0>; + enable-active-high; + pinctrl-names = "default"; + pintctrl-0 = <&display_panel_avdd_eldo_default>; + }; + dsi_sharp_4k_dsc_video_display: qcom,dsi-display@0 { label = "dsi_sharp_4k_dsc_video_display"; qcom,display-type = "primary"; @@ -315,6 +342,7 @@ vddio-supply = <&pm855_l14>; lab-supply = <&lcdb_ldo_vreg>; ibb-supply = <&lcdb_ncp_vreg>; + vdd-supply = <&display_panel_avdd_eldo>; qcom,dsi-display-list = <&dsi_sharp_4k_dsc_video_display -- GitLab From 608391f449abc210566d0181ba6f4db411c5da16 Mon Sep 17 00:00:00 2001 From: Daniel Rosenberg Date: Wed, 11 Apr 2018 16:19:10 -0700 Subject: [PATCH 0845/1635] ANDROID: sdcardfs: Check for private data earlier When an sdcardfs dentry is destroyed, it may not yet have its fsdata initialized. It must be checked before we try to access the paths in its private data. Additionally, when cleaning up the superblock after a failure, we don't have our sb private data, so check for that case. Bug: 77923821 Change-Id: I89caf6e121ed86480b42024664453fe0031bbcf3 Signed-off-by: Daniel Rosenberg --- fs/sdcardfs/dentry.c | 2 ++ fs/sdcardfs/lookup.c | 2 -- fs/sdcardfs/main.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/fs/sdcardfs/dentry.c b/fs/sdcardfs/dentry.c index e9426a61d04a..166f14b2400b 100644 --- a/fs/sdcardfs/dentry.c +++ b/fs/sdcardfs/dentry.c @@ -131,6 +131,8 @@ static int sdcardfs_d_revalidate(struct dentry *dentry, unsigned int flags) static void sdcardfs_d_release(struct dentry *dentry) { + if (!dentry || !dentry->d_fsdata) + return; /* release and reset the lower paths */ if (has_graft_path(dentry)) sdcardfs_put_reset_orig_path(dentry); diff --git a/fs/sdcardfs/lookup.c b/fs/sdcardfs/lookup.c index 7dab5f76896b..2ff305161882 100644 --- a/fs/sdcardfs/lookup.c +++ b/fs/sdcardfs/lookup.c @@ -41,8 +41,6 @@ void sdcardfs_destroy_dentry_cache(void) void free_dentry_private_data(struct dentry *dentry) { - if (!dentry || !dentry->d_fsdata) - return; kmem_cache_free(sdcardfs_dentry_cachep, dentry->d_fsdata); dentry->d_fsdata = NULL; } diff --git a/fs/sdcardfs/main.c b/fs/sdcardfs/main.c index e4fd3fbb05e6..c3120108f627 100644 --- a/fs/sdcardfs/main.c +++ b/fs/sdcardfs/main.c @@ -422,7 +422,7 @@ void sdcardfs_kill_sb(struct super_block *sb) { struct sdcardfs_sb_info *sbi; - if (sb->s_magic == SDCARDFS_SUPER_MAGIC) { + if (sb->s_magic == SDCARDFS_SUPER_MAGIC && sb->s_fs_info) { sbi = SDCARDFS_SB(sb); mutex_lock(&sdcardfs_super_list_lock); list_del(&sbi->list); -- GitLab From b556f4e38f2bbde3d1b6206e922acd3bcdb4fd79 Mon Sep 17 00:00:00 2001 From: Daniel Rosenberg Date: Wed, 11 Apr 2018 16:24:51 -0700 Subject: [PATCH 0846/1635] ANDROID: sdcardfs: d_make_root calls iput d_make_root will call iput on failure, so we shouldn't try to do that ourselves. Signed-off-by: Daniel Rosenberg Bug: 77923821 Change-Id: I1abb4afb0f894ab917b7c6be8c833676f436beb7 --- fs/sdcardfs/main.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/fs/sdcardfs/main.c b/fs/sdcardfs/main.c index c3120108f627..1a977493f88d 100644 --- a/fs/sdcardfs/main.c +++ b/fs/sdcardfs/main.c @@ -316,7 +316,7 @@ static int sdcardfs_read_super(struct vfsmount *mnt, struct super_block *sb, sb->s_root = d_make_root(inode); if (!sb->s_root) { err = -ENOMEM; - goto out_iput; + goto out_sput; } d_set_d_op(sb->s_root, &sdcardfs_ci_dops); @@ -361,8 +361,6 @@ static int sdcardfs_read_super(struct vfsmount *mnt, struct super_block *sb, /* no longer needed: free_dentry_private_data(sb->s_root); */ out_freeroot: dput(sb->s_root); -out_iput: - iput(inode); out_sput: /* drop refs we took earlier */ atomic_dec(&lower_sb->s_active); -- GitLab From 4da009f6cde226f60697e0aca1b285065332847d Mon Sep 17 00:00:00 2001 From: Daniel Rosenberg Date: Wed, 11 Apr 2018 18:39:43 -0700 Subject: [PATCH 0847/1635] ANDROID: sdcardfs: Set s_root to NULL after putting Signed-off-by: Daniel Rosenberg Bug: 77923821 Change-Id: I1705bfd146009561d2d1da5f0e6a342ec6932a1c --- fs/sdcardfs/main.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/sdcardfs/main.c b/fs/sdcardfs/main.c index 1a977493f88d..30e0c431a1ea 100644 --- a/fs/sdcardfs/main.c +++ b/fs/sdcardfs/main.c @@ -361,6 +361,7 @@ static int sdcardfs_read_super(struct vfsmount *mnt, struct super_block *sb, /* no longer needed: free_dentry_private_data(sb->s_root); */ out_freeroot: dput(sb->s_root); + sb->s_root = NULL; out_sput: /* drop refs we took earlier */ atomic_dec(&lower_sb->s_active); -- GitLab From 489da2db487312fdaf9441056745490031b59f55 Mon Sep 17 00:00:00 2001 From: Guru Das Srinagesh Date: Wed, 25 Apr 2018 12:29:17 -0700 Subject: [PATCH 0848/1635] ARM: dts: msm: Change VDD_MMCX's min. voltage to LOW_SVS for SDMSHRIKE Change the minimum and initial voltage levels for the VDD_MMCX regulator supply to LOW_SVS. This corresponds to the minimum operation level of hardware blocks powered by VDD_MMCX. CRs-Fixed: 2231304 Change-Id: I23a7ce0599f5d2928737266044b914cb122fa152 Signed-off-by: Guru Das Srinagesh --- arch/arm64/boot/dts/qcom/sdmshrike-regulators.dtsi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sdmshrike-regulators.dtsi b/arch/arm64/boot/dts/qcom/sdmshrike-regulators.dtsi index f022cc1b2d79..249e37677aca 100644 --- a/arch/arm64/boot/dts/qcom/sdmshrike-regulators.dtsi +++ b/arch/arm64/boot/dts/qcom/sdmshrike-regulators.dtsi @@ -569,11 +569,11 @@ regulator-name = "pm855p_s1_level"; qcom,set = ; regulator-min-microvolt - = ; + = ; regulator-max-microvolt = ; qcom,init-voltage-level - = ; + = ; }; }; -- GitLab From ea86e2d210a54f8c62158856fa509dd452b77c24 Mon Sep 17 00:00:00 2001 From: Deepak Katragadda Date: Wed, 25 Apr 2018 14:50:33 -0700 Subject: [PATCH 0849/1635] clk: qcom: gcc-sm8150: Pull in changes to the GCC clock frequency plan There have been updates to the frequency plan for peripheral clocks. Pull these into the clock driver. Change-Id: Ifb206477913aebddbc09f380631d5b83af3530dd Signed-off-by: Deepak Katragadda --- drivers/clk/qcom/gcc-sm8150.c | 141 +-------- include/dt-bindings/clock/qcom,gcc-sm8150.h | 317 ++++++++++---------- 2 files changed, 172 insertions(+), 286 deletions(-) diff --git a/drivers/clk/qcom/gcc-sm8150.c b/drivers/clk/qcom/gcc-sm8150.c index e084b3a66a2a..5dc6771a05b6 100644 --- a/drivers/clk/qcom/gcc-sm8150.c +++ b/drivers/clk/qcom/gcc-sm8150.c @@ -51,10 +51,7 @@ enum { P_CORE_BI_PLL_TEST_SE, P_GPLL0_OUT_EVEN, P_GPLL0_OUT_MAIN, - P_GPLL1_OUT_MAIN, - P_GPLL2_OUT_MAIN, P_GPLL4_OUT_MAIN, - P_GPLL5_OUT_MAIN, P_GPLL7_OUT_MAIN, P_GPLL9_OUT_MAIN, P_SLEEP_CLK, @@ -131,28 +128,6 @@ static const char * const gcc_parent_names_4[] = { }; static const struct parent_map gcc_parent_map_5[] = { - { P_BI_TCXO, 0 }, - { P_GPLL0_OUT_MAIN, 1 }, - { P_GPLL2_OUT_MAIN, 2 }, - { P_GPLL5_OUT_MAIN, 3 }, - { P_GPLL1_OUT_MAIN, 4 }, - { P_GPLL4_OUT_MAIN, 5 }, - { P_GPLL0_OUT_EVEN, 6 }, - { P_CORE_BI_PLL_TEST_SE, 7 }, -}; - -static const char * const gcc_parent_names_5[] = { - "bi_tcxo", - "gpll0", - "gpll2", - "gpll5", - "gpll1", - "gpll4", - "gpll0_out_even", - "core_bi_pll_test_se", -}; - -static const struct parent_map gcc_parent_map_6[] = { { P_BI_TCXO, 0 }, { P_GPLL0_OUT_MAIN, 1 }, { P_GPLL7_OUT_MAIN, 3 }, @@ -160,7 +135,7 @@ static const struct parent_map gcc_parent_map_6[] = { { P_CORE_BI_PLL_TEST_SE, 7 }, }; -static const char * const gcc_parent_names_6[] = { +static const char * const gcc_parent_names_5[] = { "bi_tcxo", "gpll0", "gpll7", @@ -168,7 +143,7 @@ static const char * const gcc_parent_names_6[] = { "core_bi_pll_test_se", }; -static const struct parent_map gcc_parent_map_7[] = { +static const struct parent_map gcc_parent_map_6[] = { { P_BI_TCXO, 0 }, { P_GPLL0_OUT_MAIN, 1 }, { P_GPLL9_OUT_MAIN, 2 }, @@ -177,7 +152,7 @@ static const struct parent_map gcc_parent_map_7[] = { { P_CORE_BI_PLL_TEST_SE, 7 }, }; -static const char * const gcc_parent_names_7[] = { +static const char * const gcc_parent_names_6[] = { "bi_tcxo", "gpll0", "gpll9", @@ -186,7 +161,7 @@ static const char * const gcc_parent_names_7[] = { "core_bi_pll_test_se", }; -static const struct parent_map gcc_parent_map_8[] = { +static const struct parent_map gcc_parent_map_7[] = { { P_BI_TCXO, 0 }, { P_GPLL0_OUT_MAIN, 1 }, { P_AUD_REF_CLK, 2 }, @@ -194,7 +169,7 @@ static const struct parent_map gcc_parent_map_8[] = { { P_CORE_BI_PLL_TEST_SE, 7 }, }; -static const char * const gcc_parent_names_8[] = { +static const char * const gcc_parent_names_7[] = { "bi_tcxo", "gpll0", "aud_ref_clk", @@ -294,54 +269,6 @@ static struct clk_alpha_pll_postdiv gpll0_out_even = { }, }; -static struct clk_alpha_pll gpll1 = { - .offset = 0x1000, - .vco_table = trion_vco, - .num_vco = ARRAY_SIZE(trion_vco), - .type = TRION_PLL, - .clkr = { - .enable_reg = 0x52000, - .enable_mask = BIT(1), - .hw.init = &(struct clk_init_data){ - .name = "gpll1", - .parent_names = (const char *[]){ "bi_tcxo" }, - .num_parents = 1, - .ops = &clk_trion_fixed_pll_ops, - .vdd_class = &vdd_cx, - .num_rate_max = VDD_NUM, - .rate_max = (unsigned long[VDD_NUM]) { - [VDD_MIN] = 615000000, - [VDD_LOW] = 1066000000, - [VDD_LOW_L1] = 1600000000, - [VDD_NOMINAL] = 2000000000}, - }, - }, -}; - -static struct clk_alpha_pll gpll4 = { - .offset = 0x76000, - .vco_table = trion_vco, - .num_vco = ARRAY_SIZE(trion_vco), - .type = TRION_PLL, - .clkr = { - .enable_reg = 0x52000, - .enable_mask = BIT(4), - .hw.init = &(struct clk_init_data){ - .name = "gpll4", - .parent_names = (const char *[]){ "bi_tcxo" }, - .num_parents = 1, - .ops = &clk_trion_fixed_pll_ops, - .vdd_class = &vdd_cx, - .num_rate_max = VDD_NUM, - .rate_max = (unsigned long[VDD_NUM]) { - [VDD_MIN] = 615000000, - [VDD_LOW] = 1066000000, - [VDD_LOW_L1] = 1600000000, - [VDD_NOMINAL] = 2000000000}, - }, - }, -}; - static struct clk_alpha_pll gpll7 = { .offset = 0x1a000, .vco_table = trion_vco, @@ -430,11 +357,11 @@ static struct clk_rcg2 gcc_emac_ptp_clk_src = { .cmd_rcgr = 0x6038, .mnd_width = 0, .hid_width = 5, - .parent_map = gcc_parent_map_6, + .parent_map = gcc_parent_map_5, .freq_tbl = ftbl_gcc_emac_ptp_clk_src, .clkr.hw.init = &(struct clk_init_data){ .name = "gcc_emac_ptp_clk_src", - .parent_names = gcc_parent_names_6, + .parent_names = gcc_parent_names_5, .num_parents = 5, .flags = CLK_SET_RATE_PARENT, .ops = &clk_rcg2_ops, @@ -463,11 +390,11 @@ static struct clk_rcg2 gcc_emac_rgmii_clk_src = { .cmd_rcgr = 0x601c, .mnd_width = 8, .hid_width = 5, - .parent_map = gcc_parent_map_6, + .parent_map = gcc_parent_map_5, .freq_tbl = ftbl_gcc_emac_rgmii_clk_src, .clkr.hw.init = &(struct clk_init_data){ .name = "gcc_emac_rgmii_clk_src", - .parent_names = gcc_parent_names_6, + .parent_names = gcc_parent_names_5, .num_parents = 5, .flags = CLK_SET_RATE_PARENT, .ops = &clk_rcg2_ops, @@ -556,41 +483,6 @@ static struct clk_rcg2 gcc_gp3_clk_src = { }, }; -static const struct freq_tbl ftbl_gcc_npu_axi_clk_src[] = { - F(19200000, P_BI_TCXO, 1, 0, 0), - F(60000000, P_GPLL0_OUT_EVEN, 5, 0, 0), - F(150000000, P_GPLL0_OUT_EVEN, 2, 0, 0), - F(200000000, P_GPLL0_OUT_MAIN, 3, 0, 0), - F(300000000, P_GPLL0_OUT_MAIN, 2, 0, 0), - F(403000000, P_GPLL4_OUT_MAIN, 2, 0, 0), - F(533000000, P_GPLL1_OUT_MAIN, 2, 0, 0), - { } -}; - -static struct clk_rcg2 gcc_npu_axi_clk_src = { - .cmd_rcgr = 0x4d014, - .mnd_width = 0, - .hid_width = 5, - .parent_map = gcc_parent_map_5, - .freq_tbl = ftbl_gcc_npu_axi_clk_src, - .clkr.hw.init = &(struct clk_init_data){ - .name = "gcc_npu_axi_clk_src", - .parent_names = gcc_parent_names_5, - .num_parents = 8, - .flags = CLK_SET_RATE_PARENT, - .ops = &clk_rcg2_ops, - .vdd_class = &vdd_cx, - .num_rate_max = VDD_NUM, - .rate_max = (unsigned long[VDD_NUM]) { - [VDD_MIN] = 60000000, - [VDD_LOWER] = 150000000, - [VDD_LOW] = 200000000, - [VDD_LOW_L1] = 300000000, - [VDD_NOMINAL] = 403000000, - [VDD_HIGH] = 533000000}, - }, -}; - static const struct freq_tbl ftbl_gcc_pcie_0_aux_clk_src[] = { F(9600000, P_BI_TCXO, 2, 0, 0), F(19200000, P_BI_TCXO, 1, 0, 0), @@ -1187,7 +1079,7 @@ static const struct freq_tbl ftbl_gcc_sdcc2_apps_clk_src[] = { F(25000000, P_GPLL0_OUT_MAIN, 12, 1, 2), F(50000000, P_GPLL0_OUT_MAIN, 12, 0, 0), F(100000000, P_GPLL0_OUT_MAIN, 6, 0, 0), - F(201600000, P_GPLL9_OUT_MAIN, 4, 0, 0), + F(202000000, P_GPLL9_OUT_MAIN, 4, 0, 0), { } }; @@ -1195,11 +1087,11 @@ static struct clk_rcg2 gcc_sdcc2_apps_clk_src = { .cmd_rcgr = 0x1400c, .mnd_width = 8, .hid_width = 5, - .parent_map = gcc_parent_map_7, + .parent_map = gcc_parent_map_6, .freq_tbl = ftbl_gcc_sdcc2_apps_clk_src, .clkr.hw.init = &(struct clk_init_data){ .name = "gcc_sdcc2_apps_clk_src", - .parent_names = gcc_parent_names_7, + .parent_names = gcc_parent_names_6, .num_parents = 6, .flags = CLK_SET_RATE_PARENT, .ops = &clk_rcg2_ops, @@ -1208,7 +1100,7 @@ static struct clk_rcg2 gcc_sdcc2_apps_clk_src = { .rate_max = (unsigned long[VDD_NUM]) { [VDD_MIN] = 19200000, [VDD_LOW] = 100000000, - [VDD_LOW_L1] = 201600000}, + [VDD_LOW_L1] = 202000000}, }, }; @@ -1252,11 +1144,11 @@ static struct clk_rcg2 gcc_tsif_ref_clk_src = { .cmd_rcgr = 0x36010, .mnd_width = 8, .hid_width = 5, - .parent_map = gcc_parent_map_8, + .parent_map = gcc_parent_map_7, .freq_tbl = ftbl_gcc_tsif_ref_clk_src, .clkr.hw.init = &(struct clk_init_data){ .name = "gcc_tsif_ref_clk_src", - .parent_names = gcc_parent_names_8, + .parent_names = gcc_parent_names_7, .num_parents = 5, .flags = CLK_SET_RATE_PARENT, .ops = &clk_rcg2_ops, @@ -4066,7 +3958,6 @@ static struct clk_regmap *gcc_sm8150_clocks[] = { [GCC_GPU_SNOC_DVM_GFX_CLK] = &gcc_gpu_snoc_dvm_gfx_clk.clkr, [GCC_NPU_AT_CLK] = &gcc_npu_at_clk.clkr, [GCC_NPU_AXI_CLK] = &gcc_npu_axi_clk.clkr, - [GCC_NPU_AXI_CLK_SRC] = &gcc_npu_axi_clk_src.clkr, [GCC_NPU_CFG_AHB_CLK] = &gcc_npu_cfg_ahb_clk.clkr, [GCC_NPU_GPLL0_CLK_SRC] = &gcc_npu_gpll0_clk_src.clkr, [GCC_NPU_GPLL0_DIV_CLK_SRC] = &gcc_npu_gpll0_div_clk_src.clkr, @@ -4231,8 +4122,6 @@ static struct clk_regmap *gcc_sm8150_clocks[] = { [GCC_VIDEO_XO_CLK] = &gcc_video_xo_clk.clkr, [GPLL0] = &gpll0.clkr, [GPLL0_OUT_EVEN] = &gpll0_out_even.clkr, - [GPLL1] = &gpll1.clkr, - [GPLL4] = &gpll4.clkr, [GPLL7] = &gpll7.clkr, [GPLL9] = &gpll9.clkr, }; diff --git a/include/dt-bindings/clock/qcom,gcc-sm8150.h b/include/dt-bindings/clock/qcom,gcc-sm8150.h index 87c1e42f16bc..6a0a0ab5c70e 100644 --- a/include/dt-bindings/clock/qcom,gcc-sm8150.h +++ b/include/dt-bindings/clock/qcom,gcc-sm8150.h @@ -59,166 +59,163 @@ #define GCC_GPU_SNOC_DVM_GFX_CLK 41 #define GCC_NPU_AT_CLK 42 #define GCC_NPU_AXI_CLK 43 -#define GCC_NPU_AXI_CLK_SRC 44 -#define GCC_NPU_CFG_AHB_CLK 45 -#define GCC_NPU_GPLL0_CLK_SRC 46 -#define GCC_NPU_GPLL0_DIV_CLK_SRC 47 -#define GCC_NPU_TRIG_CLK 48 -#define GCC_PCIE0_PHY_REFGEN_CLK 49 -#define GCC_PCIE1_PHY_REFGEN_CLK 50 -#define GCC_PCIE_0_AUX_CLK 51 -#define GCC_PCIE_0_AUX_CLK_SRC 52 -#define GCC_PCIE_0_CFG_AHB_CLK 53 -#define GCC_PCIE_0_CLKREF_CLK 54 -#define GCC_PCIE_0_MSTR_AXI_CLK 55 -#define GCC_PCIE_0_PIPE_CLK 56 -#define GCC_PCIE_0_SLV_AXI_CLK 57 -#define GCC_PCIE_0_SLV_Q2A_AXI_CLK 58 -#define GCC_PCIE_1_AUX_CLK 59 -#define GCC_PCIE_1_AUX_CLK_SRC 60 -#define GCC_PCIE_1_CFG_AHB_CLK 61 -#define GCC_PCIE_1_CLKREF_CLK 62 -#define GCC_PCIE_1_MSTR_AXI_CLK 63 -#define GCC_PCIE_1_PIPE_CLK 64 -#define GCC_PCIE_1_SLV_AXI_CLK 65 -#define GCC_PCIE_1_SLV_Q2A_AXI_CLK 66 -#define GCC_PCIE_PHY_AUX_CLK 67 -#define GCC_PCIE_PHY_REFGEN_CLK_SRC 68 -#define GCC_PDM2_CLK 69 -#define GCC_PDM2_CLK_SRC 70 -#define GCC_PDM_AHB_CLK 71 -#define GCC_PDM_XO4_CLK 72 -#define GCC_PRNG_AHB_CLK 73 -#define GCC_QMIP_CAMERA_NRT_AHB_CLK 74 -#define GCC_QMIP_CAMERA_RT_AHB_CLK 75 -#define GCC_QMIP_DISP_AHB_CLK 76 -#define GCC_QMIP_VIDEO_CVP_AHB_CLK 77 -#define GCC_QMIP_VIDEO_VCODEC_AHB_CLK 78 -#define GCC_QSPI_CNOC_PERIPH_AHB_CLK 79 -#define GCC_QSPI_CORE_CLK 80 -#define GCC_QSPI_CORE_CLK_SRC 81 -#define GCC_QUPV3_WRAP0_S0_CLK 82 -#define GCC_QUPV3_WRAP0_S0_CLK_SRC 83 -#define GCC_QUPV3_WRAP0_S1_CLK 84 -#define GCC_QUPV3_WRAP0_S1_CLK_SRC 85 -#define GCC_QUPV3_WRAP0_S2_CLK 86 -#define GCC_QUPV3_WRAP0_S2_CLK_SRC 87 -#define GCC_QUPV3_WRAP0_S3_CLK 88 -#define GCC_QUPV3_WRAP0_S3_CLK_SRC 89 -#define GCC_QUPV3_WRAP0_S4_CLK 90 -#define GCC_QUPV3_WRAP0_S4_CLK_SRC 91 -#define GCC_QUPV3_WRAP0_S5_CLK 92 -#define GCC_QUPV3_WRAP0_S5_CLK_SRC 93 -#define GCC_QUPV3_WRAP0_S6_CLK 94 -#define GCC_QUPV3_WRAP0_S6_CLK_SRC 95 -#define GCC_QUPV3_WRAP0_S7_CLK 96 -#define GCC_QUPV3_WRAP0_S7_CLK_SRC 97 -#define GCC_QUPV3_WRAP1_S0_CLK 98 -#define GCC_QUPV3_WRAP1_S0_CLK_SRC 99 -#define GCC_QUPV3_WRAP1_S1_CLK 100 -#define GCC_QUPV3_WRAP1_S1_CLK_SRC 101 -#define GCC_QUPV3_WRAP1_S2_CLK 102 -#define GCC_QUPV3_WRAP1_S2_CLK_SRC 103 -#define GCC_QUPV3_WRAP1_S3_CLK 104 -#define GCC_QUPV3_WRAP1_S3_CLK_SRC 105 -#define GCC_QUPV3_WRAP1_S4_CLK 106 -#define GCC_QUPV3_WRAP1_S4_CLK_SRC 107 -#define GCC_QUPV3_WRAP1_S5_CLK 108 -#define GCC_QUPV3_WRAP1_S5_CLK_SRC 109 -#define GCC_QUPV3_WRAP2_S0_CLK 110 -#define GCC_QUPV3_WRAP2_S0_CLK_SRC 111 -#define GCC_QUPV3_WRAP2_S1_CLK 112 -#define GCC_QUPV3_WRAP2_S1_CLK_SRC 113 -#define GCC_QUPV3_WRAP2_S2_CLK 114 -#define GCC_QUPV3_WRAP2_S2_CLK_SRC 115 -#define GCC_QUPV3_WRAP2_S3_CLK 116 -#define GCC_QUPV3_WRAP2_S3_CLK_SRC 117 -#define GCC_QUPV3_WRAP2_S4_CLK 118 -#define GCC_QUPV3_WRAP2_S4_CLK_SRC 119 -#define GCC_QUPV3_WRAP2_S5_CLK 120 -#define GCC_QUPV3_WRAP2_S5_CLK_SRC 121 -#define GCC_QUPV3_WRAP_0_M_AHB_CLK 122 -#define GCC_QUPV3_WRAP_0_S_AHB_CLK 123 -#define GCC_QUPV3_WRAP_1_M_AHB_CLK 124 -#define GCC_QUPV3_WRAP_1_S_AHB_CLK 125 -#define GCC_QUPV3_WRAP_2_M_AHB_CLK 126 -#define GCC_QUPV3_WRAP_2_S_AHB_CLK 127 -#define GCC_SDCC2_AHB_CLK 128 -#define GCC_SDCC2_APPS_CLK 129 -#define GCC_SDCC2_APPS_CLK_SRC 130 -#define GCC_SDCC4_AHB_CLK 131 -#define GCC_SDCC4_APPS_CLK 132 -#define GCC_SDCC4_APPS_CLK_SRC 133 -#define GCC_SYS_NOC_CPUSS_AHB_CLK 134 -#define GCC_TSIF_AHB_CLK 135 -#define GCC_TSIF_INACTIVITY_TIMERS_CLK 136 -#define GCC_TSIF_REF_CLK 137 -#define GCC_TSIF_REF_CLK_SRC 138 -#define GCC_UFS_CARD_AHB_CLK 139 -#define GCC_UFS_CARD_AXI_CLK 140 -#define GCC_UFS_CARD_AXI_CLK_SRC 141 -#define GCC_UFS_CARD_AXI_HW_CTL_CLK 142 -#define GCC_UFS_CARD_CLKREF_CLK 143 -#define GCC_UFS_CARD_ICE_CORE_CLK 144 -#define GCC_UFS_CARD_ICE_CORE_CLK_SRC 145 -#define GCC_UFS_CARD_ICE_CORE_HW_CTL_CLK 146 -#define GCC_UFS_CARD_PHY_AUX_CLK 147 -#define GCC_UFS_CARD_PHY_AUX_CLK_SRC 148 -#define GCC_UFS_CARD_PHY_AUX_HW_CTL_CLK 149 -#define GCC_UFS_CARD_RX_SYMBOL_0_CLK 150 -#define GCC_UFS_CARD_RX_SYMBOL_1_CLK 151 -#define GCC_UFS_CARD_TX_SYMBOL_0_CLK 152 -#define GCC_UFS_CARD_UNIPRO_CORE_CLK 153 -#define GCC_UFS_CARD_UNIPRO_CORE_CLK_SRC 154 -#define GCC_UFS_CARD_UNIPRO_CORE_HW_CTL_CLK 155 -#define GCC_UFS_MEM_CLKREF_CLK 156 -#define GCC_UFS_PHY_AHB_CLK 157 -#define GCC_UFS_PHY_AXI_CLK 158 -#define GCC_UFS_PHY_AXI_CLK_SRC 159 -#define GCC_UFS_PHY_AXI_HW_CTL_CLK 160 -#define GCC_UFS_PHY_ICE_CORE_CLK 161 -#define GCC_UFS_PHY_ICE_CORE_CLK_SRC 162 -#define GCC_UFS_PHY_ICE_CORE_HW_CTL_CLK 163 -#define GCC_UFS_PHY_PHY_AUX_CLK 164 -#define GCC_UFS_PHY_PHY_AUX_CLK_SRC 165 -#define GCC_UFS_PHY_PHY_AUX_HW_CTL_CLK 166 -#define GCC_UFS_PHY_RX_SYMBOL_0_CLK 167 -#define GCC_UFS_PHY_RX_SYMBOL_1_CLK 168 -#define GCC_UFS_PHY_TX_SYMBOL_0_CLK 169 -#define GCC_UFS_PHY_UNIPRO_CORE_CLK 170 -#define GCC_UFS_PHY_UNIPRO_CORE_CLK_SRC 171 -#define GCC_UFS_PHY_UNIPRO_CORE_HW_CTL_CLK 172 -#define GCC_USB30_PRIM_MASTER_CLK 173 -#define GCC_USB30_PRIM_MASTER_CLK_SRC 174 -#define GCC_USB30_PRIM_MOCK_UTMI_CLK 175 -#define GCC_USB30_PRIM_MOCK_UTMI_CLK_SRC 176 -#define GCC_USB30_PRIM_SLEEP_CLK 177 -#define GCC_USB30_SEC_MASTER_CLK 178 -#define GCC_USB30_SEC_MASTER_CLK_SRC 179 -#define GCC_USB30_SEC_MOCK_UTMI_CLK 180 -#define GCC_USB30_SEC_MOCK_UTMI_CLK_SRC 181 -#define GCC_USB30_SEC_SLEEP_CLK 182 -#define GCC_USB3_PRIM_CLKREF_CLK 183 -#define GCC_USB3_PRIM_PHY_AUX_CLK 184 -#define GCC_USB3_PRIM_PHY_AUX_CLK_SRC 185 -#define GCC_USB3_PRIM_PHY_COM_AUX_CLK 186 -#define GCC_USB3_PRIM_PHY_PIPE_CLK 187 -#define GCC_USB3_SEC_CLKREF_CLK 188 -#define GCC_USB3_SEC_PHY_AUX_CLK 189 -#define GCC_USB3_SEC_PHY_AUX_CLK_SRC 190 -#define GCC_USB3_SEC_PHY_COM_AUX_CLK 191 -#define GCC_USB3_SEC_PHY_PIPE_CLK 192 -#define GCC_VIDEO_AHB_CLK 193 -#define GCC_VIDEO_AXI0_CLK 194 -#define GCC_VIDEO_AXI1_CLK 195 -#define GCC_VIDEO_AXIC_CLK 196 -#define GCC_VIDEO_XO_CLK 197 -#define GPLL0 198 -#define GPLL0_OUT_EVEN 199 -#define GPLL1 200 -#define GPLL4 201 -#define GPLL7 202 -#define GPLL9 203 +#define GCC_NPU_CFG_AHB_CLK 44 +#define GCC_NPU_GPLL0_CLK_SRC 45 +#define GCC_NPU_GPLL0_DIV_CLK_SRC 46 +#define GCC_NPU_TRIG_CLK 47 +#define GCC_PCIE0_PHY_REFGEN_CLK 48 +#define GCC_PCIE1_PHY_REFGEN_CLK 49 +#define GCC_PCIE_0_AUX_CLK 50 +#define GCC_PCIE_0_AUX_CLK_SRC 51 +#define GCC_PCIE_0_CFG_AHB_CLK 52 +#define GCC_PCIE_0_CLKREF_CLK 53 +#define GCC_PCIE_0_MSTR_AXI_CLK 54 +#define GCC_PCIE_0_PIPE_CLK 55 +#define GCC_PCIE_0_SLV_AXI_CLK 56 +#define GCC_PCIE_0_SLV_Q2A_AXI_CLK 57 +#define GCC_PCIE_1_AUX_CLK 58 +#define GCC_PCIE_1_AUX_CLK_SRC 59 +#define GCC_PCIE_1_CFG_AHB_CLK 60 +#define GCC_PCIE_1_CLKREF_CLK 61 +#define GCC_PCIE_1_MSTR_AXI_CLK 62 +#define GCC_PCIE_1_PIPE_CLK 63 +#define GCC_PCIE_1_SLV_AXI_CLK 64 +#define GCC_PCIE_1_SLV_Q2A_AXI_CLK 65 +#define GCC_PCIE_PHY_AUX_CLK 66 +#define GCC_PCIE_PHY_REFGEN_CLK_SRC 67 +#define GCC_PDM2_CLK 68 +#define GCC_PDM2_CLK_SRC 69 +#define GCC_PDM_AHB_CLK 70 +#define GCC_PDM_XO4_CLK 71 +#define GCC_PRNG_AHB_CLK 72 +#define GCC_QMIP_CAMERA_NRT_AHB_CLK 73 +#define GCC_QMIP_CAMERA_RT_AHB_CLK 74 +#define GCC_QMIP_DISP_AHB_CLK 75 +#define GCC_QMIP_VIDEO_CVP_AHB_CLK 76 +#define GCC_QMIP_VIDEO_VCODEC_AHB_CLK 77 +#define GCC_QSPI_CNOC_PERIPH_AHB_CLK 78 +#define GCC_QSPI_CORE_CLK 79 +#define GCC_QSPI_CORE_CLK_SRC 80 +#define GCC_QUPV3_WRAP0_S0_CLK 81 +#define GCC_QUPV3_WRAP0_S0_CLK_SRC 82 +#define GCC_QUPV3_WRAP0_S1_CLK 83 +#define GCC_QUPV3_WRAP0_S1_CLK_SRC 84 +#define GCC_QUPV3_WRAP0_S2_CLK 85 +#define GCC_QUPV3_WRAP0_S2_CLK_SRC 86 +#define GCC_QUPV3_WRAP0_S3_CLK 87 +#define GCC_QUPV3_WRAP0_S3_CLK_SRC 88 +#define GCC_QUPV3_WRAP0_S4_CLK 89 +#define GCC_QUPV3_WRAP0_S4_CLK_SRC 90 +#define GCC_QUPV3_WRAP0_S5_CLK 91 +#define GCC_QUPV3_WRAP0_S5_CLK_SRC 92 +#define GCC_QUPV3_WRAP0_S6_CLK 93 +#define GCC_QUPV3_WRAP0_S6_CLK_SRC 94 +#define GCC_QUPV3_WRAP0_S7_CLK 95 +#define GCC_QUPV3_WRAP0_S7_CLK_SRC 96 +#define GCC_QUPV3_WRAP1_S0_CLK 97 +#define GCC_QUPV3_WRAP1_S0_CLK_SRC 98 +#define GCC_QUPV3_WRAP1_S1_CLK 99 +#define GCC_QUPV3_WRAP1_S1_CLK_SRC 100 +#define GCC_QUPV3_WRAP1_S2_CLK 101 +#define GCC_QUPV3_WRAP1_S2_CLK_SRC 102 +#define GCC_QUPV3_WRAP1_S3_CLK 103 +#define GCC_QUPV3_WRAP1_S3_CLK_SRC 104 +#define GCC_QUPV3_WRAP1_S4_CLK 105 +#define GCC_QUPV3_WRAP1_S4_CLK_SRC 106 +#define GCC_QUPV3_WRAP1_S5_CLK 107 +#define GCC_QUPV3_WRAP1_S5_CLK_SRC 108 +#define GCC_QUPV3_WRAP2_S0_CLK 109 +#define GCC_QUPV3_WRAP2_S0_CLK_SRC 110 +#define GCC_QUPV3_WRAP2_S1_CLK 111 +#define GCC_QUPV3_WRAP2_S1_CLK_SRC 112 +#define GCC_QUPV3_WRAP2_S2_CLK 113 +#define GCC_QUPV3_WRAP2_S2_CLK_SRC 114 +#define GCC_QUPV3_WRAP2_S3_CLK 115 +#define GCC_QUPV3_WRAP2_S3_CLK_SRC 116 +#define GCC_QUPV3_WRAP2_S4_CLK 117 +#define GCC_QUPV3_WRAP2_S4_CLK_SRC 118 +#define GCC_QUPV3_WRAP2_S5_CLK 119 +#define GCC_QUPV3_WRAP2_S5_CLK_SRC 120 +#define GCC_QUPV3_WRAP_0_M_AHB_CLK 121 +#define GCC_QUPV3_WRAP_0_S_AHB_CLK 122 +#define GCC_QUPV3_WRAP_1_M_AHB_CLK 123 +#define GCC_QUPV3_WRAP_1_S_AHB_CLK 124 +#define GCC_QUPV3_WRAP_2_M_AHB_CLK 125 +#define GCC_QUPV3_WRAP_2_S_AHB_CLK 126 +#define GCC_SDCC2_AHB_CLK 127 +#define GCC_SDCC2_APPS_CLK 128 +#define GCC_SDCC2_APPS_CLK_SRC 129 +#define GCC_SDCC4_AHB_CLK 130 +#define GCC_SDCC4_APPS_CLK 131 +#define GCC_SDCC4_APPS_CLK_SRC 132 +#define GCC_SYS_NOC_CPUSS_AHB_CLK 133 +#define GCC_TSIF_AHB_CLK 134 +#define GCC_TSIF_INACTIVITY_TIMERS_CLK 135 +#define GCC_TSIF_REF_CLK 136 +#define GCC_TSIF_REF_CLK_SRC 137 +#define GCC_UFS_CARD_AHB_CLK 138 +#define GCC_UFS_CARD_AXI_CLK 139 +#define GCC_UFS_CARD_AXI_CLK_SRC 140 +#define GCC_UFS_CARD_AXI_HW_CTL_CLK 141 +#define GCC_UFS_CARD_CLKREF_CLK 142 +#define GCC_UFS_CARD_ICE_CORE_CLK 143 +#define GCC_UFS_CARD_ICE_CORE_CLK_SRC 144 +#define GCC_UFS_CARD_ICE_CORE_HW_CTL_CLK 145 +#define GCC_UFS_CARD_PHY_AUX_CLK 146 +#define GCC_UFS_CARD_PHY_AUX_CLK_SRC 147 +#define GCC_UFS_CARD_PHY_AUX_HW_CTL_CLK 148 +#define GCC_UFS_CARD_RX_SYMBOL_0_CLK 149 +#define GCC_UFS_CARD_RX_SYMBOL_1_CLK 150 +#define GCC_UFS_CARD_TX_SYMBOL_0_CLK 151 +#define GCC_UFS_CARD_UNIPRO_CORE_CLK 152 +#define GCC_UFS_CARD_UNIPRO_CORE_CLK_SRC 153 +#define GCC_UFS_CARD_UNIPRO_CORE_HW_CTL_CLK 154 +#define GCC_UFS_MEM_CLKREF_CLK 155 +#define GCC_UFS_PHY_AHB_CLK 156 +#define GCC_UFS_PHY_AXI_CLK 157 +#define GCC_UFS_PHY_AXI_CLK_SRC 158 +#define GCC_UFS_PHY_AXI_HW_CTL_CLK 159 +#define GCC_UFS_PHY_ICE_CORE_CLK 160 +#define GCC_UFS_PHY_ICE_CORE_CLK_SRC 161 +#define GCC_UFS_PHY_ICE_CORE_HW_CTL_CLK 162 +#define GCC_UFS_PHY_PHY_AUX_CLK 163 +#define GCC_UFS_PHY_PHY_AUX_CLK_SRC 164 +#define GCC_UFS_PHY_PHY_AUX_HW_CTL_CLK 165 +#define GCC_UFS_PHY_RX_SYMBOL_0_CLK 166 +#define GCC_UFS_PHY_RX_SYMBOL_1_CLK 167 +#define GCC_UFS_PHY_TX_SYMBOL_0_CLK 168 +#define GCC_UFS_PHY_UNIPRO_CORE_CLK 169 +#define GCC_UFS_PHY_UNIPRO_CORE_CLK_SRC 170 +#define GCC_UFS_PHY_UNIPRO_CORE_HW_CTL_CLK 171 +#define GCC_USB30_PRIM_MASTER_CLK 172 +#define GCC_USB30_PRIM_MASTER_CLK_SRC 173 +#define GCC_USB30_PRIM_MOCK_UTMI_CLK 174 +#define GCC_USB30_PRIM_MOCK_UTMI_CLK_SRC 175 +#define GCC_USB30_PRIM_SLEEP_CLK 176 +#define GCC_USB30_SEC_MASTER_CLK 177 +#define GCC_USB30_SEC_MASTER_CLK_SRC 178 +#define GCC_USB30_SEC_MOCK_UTMI_CLK 179 +#define GCC_USB30_SEC_MOCK_UTMI_CLK_SRC 180 +#define GCC_USB30_SEC_SLEEP_CLK 181 +#define GCC_USB3_PRIM_CLKREF_CLK 182 +#define GCC_USB3_PRIM_PHY_AUX_CLK 183 +#define GCC_USB3_PRIM_PHY_AUX_CLK_SRC 184 +#define GCC_USB3_PRIM_PHY_COM_AUX_CLK 185 +#define GCC_USB3_PRIM_PHY_PIPE_CLK 186 +#define GCC_USB3_SEC_CLKREF_CLK 187 +#define GCC_USB3_SEC_PHY_AUX_CLK 188 +#define GCC_USB3_SEC_PHY_AUX_CLK_SRC 189 +#define GCC_USB3_SEC_PHY_COM_AUX_CLK 190 +#define GCC_USB3_SEC_PHY_PIPE_CLK 191 +#define GCC_VIDEO_AHB_CLK 192 +#define GCC_VIDEO_AXI0_CLK 193 +#define GCC_VIDEO_AXI1_CLK 194 +#define GCC_VIDEO_AXIC_CLK 195 +#define GCC_VIDEO_XO_CLK 196 +#define GPLL0 197 +#define GPLL0_OUT_EVEN 198 +#define GPLL7 199 +#define GPLL9 200 /* Reset clocks */ #define GCC_EMAC_BCR 0 -- GitLab From 974a2dce6ac2ff70f6426e54326bb9c3e83a5fa4 Mon Sep 17 00:00:00 2001 From: Runmin Wang Date: Wed, 25 Apr 2018 14:54:11 -0700 Subject: [PATCH 0850/1635] sched/fair: load balance if a group is overloaded Doing more aggressive balance if a sched_group is overloaded. Change-Id: I00950c23c67a40b3431b68ac7ce2a1e470e563ed Signed-off-by: Runmin Wang --- kernel/sched/fair.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index c78063f79868..8f38795cf6c4 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -9903,6 +9903,11 @@ static inline void calculate_imbalance(struct lb_env *env, struct sd_lb_stats *s (busiest->avg_load <= sds->avg_load || local->avg_load >= sds->avg_load)) { env->imbalance = 0; + if (busiest->group_type == group_overloaded && + local->group_type <= group_misfit_task) { + env->imbalance = busiest->load_per_task; + return; + } return fix_small_imbalance(env, sds); } -- GitLab From 9cbb63ce0b6983c444d1cef721714e78d863b3ec Mon Sep 17 00:00:00 2001 From: Runmin Wang Date: Wed, 25 Apr 2018 15:01:55 -0700 Subject: [PATCH 0851/1635] sched/fair: do not pull single task if a dst_cpu is not idle Misfit task will get migrated in the tick path so there is no need to do active pulling of the single task. Change-Id: I372b23c038f4e34af4608859ba7a7d9ec9ca4283 Signed-off-by: Runmin Wang --- kernel/sched/fair.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index c78063f79868..7441eaf7acba 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -10203,7 +10203,8 @@ static int need_active_balance(struct lb_env *env) return 1; } - if ((capacity_of(env->src_cpu) < capacity_of(env->dst_cpu)) && + if ((env->idle != CPU_NOT_IDLE) && + (capacity_of(env->src_cpu) < capacity_of(env->dst_cpu)) && ((capacity_orig_of(env->src_cpu) < capacity_orig_of(env->dst_cpu))) && env->src_rq->cfs.h_nr_running == 1 && cpu_overutilized(env->src_cpu) && -- GitLab From 25ed8eed265a07f08c1a81653cfe4c4b0ef5f9c4 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Mon, 26 Feb 2018 16:04:18 -0800 Subject: [PATCH 0852/1635] UPSTREAM: console: SisUSB2VGA: Drop dummy con_font_get() As done in commit: 724ba8b30b04 ("console/dummy: leave .con_font_get set to NULL") This drops the dummy .con_font_get(), as it could leave arguments uninitialized. Cc: Thomas Winischhofer Signed-off-by: Kees Cook Signed-off-by: Greg Kroah-Hartman Change-Id: I71d98ce1245f204c324c730a524c6e9a3ec26ef9 (cherry picked from commit ea92110bc048848967bd2a046675a006005c4f06) Signed-off-by: Sami Tolvanen --- drivers/usb/misc/sisusbvga/sisusb_con.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/usb/misc/sisusbvga/sisusb_con.c b/drivers/usb/misc/sisusbvga/sisusb_con.c index f019d80ca9e4..78112f97d8c7 100644 --- a/drivers/usb/misc/sisusbvga/sisusb_con.c +++ b/drivers/usb/misc/sisusbvga/sisusb_con.c @@ -1357,7 +1357,6 @@ static const struct consw sisusb_dummy_con = { .con_switch = SISUSBCONDUMMY, .con_blank = SISUSBCONDUMMY, .con_font_set = SISUSBCONDUMMY, - .con_font_get = SISUSBCONDUMMY, .con_font_default = SISUSBCONDUMMY, .con_font_copy = SISUSBCONDUMMY, }; -- GitLab From d354d0d06129444ecf8e6b47e9551581c9565ba8 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Mon, 26 Feb 2018 16:04:20 -0800 Subject: [PATCH 0853/1635] UPSTREAM: console: Expand dummy functions for CFI This expands the no-op dummy functions into full prototypes to avoid indirect call mismatches when running under Control Flow Integrity checking, like with Clang's -fsanitize=cfi. Co-Developed-by: Sami Tolvanen Signed-off-by: Sami Tolvanen Signed-off-by: Kees Cook Signed-off-by: Greg Kroah-Hartman Change-Id: If63cf04ad86b55afb1442ef4037b5f575457ea06 (cherry picked from commit c396a5bf457fb60159dcedbd4f48d53a62be030a) Signed-off-by: Sami Tolvanen --- drivers/usb/misc/sisusbvga/sisusb_con.c | 67 ++++++++++++++++++------ drivers/video/console/dummycon.c | 69 +++++++++++++++++++------ drivers/video/console/newport_con.c | 10 ++-- drivers/video/console/vgacon.c | 20 +++---- drivers/video/fbdev/core/fbcon.c | 3 +- 5 files changed, 121 insertions(+), 48 deletions(-) diff --git a/drivers/usb/misc/sisusbvga/sisusb_con.c b/drivers/usb/misc/sisusbvga/sisusb_con.c index 78112f97d8c7..dc45cfc8eb10 100644 --- a/drivers/usb/misc/sisusbvga/sisusb_con.c +++ b/drivers/usb/misc/sisusbvga/sisusb_con.c @@ -1216,7 +1216,7 @@ sisusbcon_do_font_op(struct sisusb_usb_data *sisusb, int set, int slot, /* Interface routine */ static int sisusbcon_font_set(struct vc_data *c, struct console_font *font, - unsigned flags) + unsigned int flags) { struct sisusb_usb_data *sisusb; unsigned charcount = font->charcount; @@ -1337,28 +1337,65 @@ static void sisusbdummycon_init(struct vc_data *vc, int init) vc_resize(vc, 80, 25); } -static int sisusbdummycon_dummy(void) +static void sisusbdummycon_deinit(struct vc_data *vc) { } +static void sisusbdummycon_clear(struct vc_data *vc, int sy, int sx, + int height, int width) { } +static void sisusbdummycon_putc(struct vc_data *vc, int c, int ypos, + int xpos) { } +static void sisusbdummycon_putcs(struct vc_data *vc, const unsigned short *s, + int count, int ypos, int xpos) { } +static void sisusbdummycon_cursor(struct vc_data *vc, int mode) { } + +static bool sisusbdummycon_scroll(struct vc_data *vc, unsigned int top, + unsigned int bottom, enum con_scroll dir, + unsigned int lines) { - return 0; + return false; } -#define SISUSBCONDUMMY (void *)sisusbdummycon_dummy +static int sisusbdummycon_switch(struct vc_data *vc) +{ + return 0; +} + +static int sisusbdummycon_blank(struct vc_data *vc, int blank, int mode_switch) +{ + return 0; +} + +static int sisusbdummycon_font_set(struct vc_data *vc, + struct console_font *font, + unsigned int flags) +{ + return 0; +} + +static int sisusbdummycon_font_default(struct vc_data *vc, + struct console_font *font, char *name) +{ + return 0; +} + +static int sisusbdummycon_font_copy(struct vc_data *vc, int con) +{ + return 0; +} static const struct consw sisusb_dummy_con = { .owner = THIS_MODULE, .con_startup = sisusbdummycon_startup, .con_init = sisusbdummycon_init, - .con_deinit = SISUSBCONDUMMY, - .con_clear = SISUSBCONDUMMY, - .con_putc = SISUSBCONDUMMY, - .con_putcs = SISUSBCONDUMMY, - .con_cursor = SISUSBCONDUMMY, - .con_scroll = SISUSBCONDUMMY, - .con_switch = SISUSBCONDUMMY, - .con_blank = SISUSBCONDUMMY, - .con_font_set = SISUSBCONDUMMY, - .con_font_default = SISUSBCONDUMMY, - .con_font_copy = SISUSBCONDUMMY, + .con_deinit = sisusbdummycon_deinit, + .con_clear = sisusbdummycon_clear, + .con_putc = sisusbdummycon_putc, + .con_putcs = sisusbdummycon_putcs, + .con_cursor = sisusbdummycon_cursor, + .con_scroll = sisusbdummycon_scroll, + .con_switch = sisusbdummycon_switch, + .con_blank = sisusbdummycon_blank, + .con_font_set = sisusbdummycon_font_set, + .con_font_default = sisusbdummycon_font_default, + .con_font_copy = sisusbdummycon_font_copy, }; int diff --git a/drivers/video/console/dummycon.c b/drivers/video/console/dummycon.c index b90ef96e43d6..f2eafe2ed980 100644 --- a/drivers/video/console/dummycon.c +++ b/drivers/video/console/dummycon.c @@ -41,12 +41,47 @@ static void dummycon_init(struct vc_data *vc, int init) vc_resize(vc, DUMMY_COLUMNS, DUMMY_ROWS); } -static int dummycon_dummy(void) +static void dummycon_deinit(struct vc_data *vc) { } +static void dummycon_clear(struct vc_data *vc, int sy, int sx, int height, + int width) { } +static void dummycon_putc(struct vc_data *vc, int c, int ypos, int xpos) { } +static void dummycon_putcs(struct vc_data *vc, const unsigned short *s, + int count, int ypos, int xpos) { } +static void dummycon_cursor(struct vc_data *vc, int mode) { } + +static bool dummycon_scroll(struct vc_data *vc, unsigned int top, + unsigned int bottom, enum con_scroll dir, + unsigned int lines) +{ + return false; +} + +static int dummycon_switch(struct vc_data *vc) { - return 0; + return 0; } -#define DUMMY (void *)dummycon_dummy +static int dummycon_blank(struct vc_data *vc, int blank, int mode_switch) +{ + return 0; +} + +static int dummycon_font_set(struct vc_data *vc, struct console_font *font, + unsigned int flags) +{ + return 0; +} + +static int dummycon_font_default(struct vc_data *vc, + struct console_font *font, char *name) +{ + return 0; +} + +static int dummycon_font_copy(struct vc_data *vc, int con) +{ + return 0; +} /* * The console `switch' structure for the dummy console @@ -55,19 +90,19 @@ static int dummycon_dummy(void) */ const struct consw dummy_con = { - .owner = THIS_MODULE, - .con_startup = dummycon_startup, - .con_init = dummycon_init, - .con_deinit = DUMMY, - .con_clear = DUMMY, - .con_putc = DUMMY, - .con_putcs = DUMMY, - .con_cursor = DUMMY, - .con_scroll = DUMMY, - .con_switch = DUMMY, - .con_blank = DUMMY, - .con_font_set = DUMMY, - .con_font_default = DUMMY, - .con_font_copy = DUMMY, + .owner = THIS_MODULE, + .con_startup = dummycon_startup, + .con_init = dummycon_init, + .con_deinit = dummycon_deinit, + .con_clear = dummycon_clear, + .con_putc = dummycon_putc, + .con_putcs = dummycon_putcs, + .con_cursor = dummycon_cursor, + .con_scroll = dummycon_scroll, + .con_switch = dummycon_switch, + .con_blank = dummycon_blank, + .con_font_set = dummycon_font_set, + .con_font_default = dummycon_font_default, + .con_font_copy = dummycon_font_copy, }; EXPORT_SYMBOL_GPL(dummy_con); diff --git a/drivers/video/console/newport_con.c b/drivers/video/console/newport_con.c index 42d02a206059..6897bd0fc00e 100644 --- a/drivers/video/console/newport_con.c +++ b/drivers/video/console/newport_con.c @@ -673,14 +673,14 @@ static bool newport_scroll(struct vc_data *vc, unsigned int t, unsigned int b, return true; } -static int newport_dummy(struct vc_data *c) +static int newport_set_origin(struct vc_data *vc) { return 0; } -#define DUMMY (void *) newport_dummy +static void newport_save_screen(struct vc_data *vc) { } -const struct consw newport_con = { +static const struct consw newport_con = { .owner = THIS_MODULE, .con_startup = newport_startup, .con_init = newport_init, @@ -694,8 +694,8 @@ const struct consw newport_con = { .con_blank = newport_blank, .con_font_set = newport_font_set, .con_font_default = newport_font_default, - .con_set_origin = DUMMY, - .con_save_screen = DUMMY + .con_set_origin = newport_set_origin, + .con_save_screen = newport_save_screen }; static int newport_probe(struct gio_device *dev, diff --git a/drivers/video/console/vgacon.c b/drivers/video/console/vgacon.c index a17ba1465815..f09e17b60e45 100644 --- a/drivers/video/console/vgacon.c +++ b/drivers/video/console/vgacon.c @@ -1272,7 +1272,8 @@ static int vgacon_adjust_height(struct vc_data *vc, unsigned fontheight) return 0; } -static int vgacon_font_set(struct vc_data *c, struct console_font *font, unsigned flags) +static int vgacon_font_set(struct vc_data *c, struct console_font *font, + unsigned int flags) { unsigned charcount = font->charcount; int rc; @@ -1407,21 +1408,20 @@ static bool vgacon_scroll(struct vc_data *c, unsigned int t, unsigned int b, * The console `switch' structure for the VGA based console */ -static int vgacon_dummy(struct vc_data *c) -{ - return 0; -} - -#define DUMMY (void *) vgacon_dummy +static void vgacon_clear(struct vc_data *vc, int sy, int sx, int height, + int width) { } +static void vgacon_putc(struct vc_data *vc, int c, int ypos, int xpos) { } +static void vgacon_putcs(struct vc_data *vc, const unsigned short *s, + int count, int ypos, int xpos) { } const struct consw vga_con = { .owner = THIS_MODULE, .con_startup = vgacon_startup, .con_init = vgacon_init, .con_deinit = vgacon_deinit, - .con_clear = DUMMY, - .con_putc = DUMMY, - .con_putcs = DUMMY, + .con_clear = vgacon_clear, + .con_putc = vgacon_putc, + .con_putcs = vgacon_putcs, .con_cursor = vgacon_cursor, .con_scroll = vgacon_scroll, .con_switch = vgacon_switch, diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c index 04612f938bab..235d549d5958 100644 --- a/drivers/video/fbdev/core/fbcon.c +++ b/drivers/video/fbdev/core/fbcon.c @@ -2588,7 +2588,8 @@ static int fbcon_copy_font(struct vc_data *vc, int con) * is ever implemented. */ -static int fbcon_set_font(struct vc_data *vc, struct console_font *font, unsigned flags) +static int fbcon_set_font(struct vc_data *vc, struct console_font *font, + unsigned int flags) { struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; unsigned charcount = font->charcount; -- GitLab From 550306ee8a755569c1d0b6ae8f7df560f3559ea6 Mon Sep 17 00:00:00 2001 From: Sami Tolvanen Date: Thu, 30 Nov 2017 15:38:26 -0800 Subject: [PATCH 0854/1635] UPSTREAM: kbuild: add clang-version.sh Based on gcc-version.sh, clang-version.sh prints out the correct version of clang. Signed-off-by: Sami Tolvanen Tested-by: Nick Desaulniers Signed-off-by: Masahiro Yamada Change-Id: I71ccd673392841ea99fbb76a0b41040625ebd307 (cherry picked from commit ae0c553c24c009596c3a3e903433824fe050c547) Signed-off-by: Sami Tolvanen --- scripts/clang-version.sh | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100755 scripts/clang-version.sh diff --git a/scripts/clang-version.sh b/scripts/clang-version.sh new file mode 100755 index 000000000000..9780efa56980 --- /dev/null +++ b/scripts/clang-version.sh @@ -0,0 +1,33 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0 +# +# clang-version [-p] clang-command +# +# Prints the compiler version of `clang-command' in a canonical 4-digit form +# such as `0500' for clang-5.0 etc. +# +# With the -p option, prints the patchlevel as well, for example `050001' for +# clang-5.0.1 etc. +# + +if [ "$1" = "-p" ] ; then + with_patchlevel=1; + shift; +fi + +compiler="$*" + +if [ ${#compiler} -eq 0 ]; then + echo "Error: No compiler specified." + printf "Usage:\n\t$0 \n" + exit 1 +fi + +MAJOR=$(echo __clang_major__ | $compiler -E -x c - | tail -n 1) +MINOR=$(echo __clang_minor__ | $compiler -E -x c - | tail -n 1) +if [ "x$with_patchlevel" != "x" ] ; then + PATCHLEVEL=$(echo __clang_patchlevel__ | $compiler -E -x c - | tail -n 1) + printf "%02d%02d%02d\\n" $MAJOR $MINOR $PATCHLEVEL +else + printf "%02d%02d\\n" $MAJOR $MINOR +fi -- GitLab From 5b37dfe508f9d710946524faa1bcfab228e8c100 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Tue, 17 Oct 2017 19:04:41 -0700 Subject: [PATCH 0855/1635] UPSTREAM: module: Prepare to convert all module_param_call() prototypes After actually converting all module_param_call() function prototypes, we no longer need to do a tricky sizeof(func(thing)) type-check. Remove it. Signed-off-by: Kees Cook Signed-off-by: Jessica Yu Bug: 67506682 Change-Id: Ie20dbd09634c7cbef499c81bf2dbfd762ad0058a (cherry picked from commit b2f270e8747387335d80428c576118e7d87f69cc) Signed-off-by: Sami Tolvanen --- include/linux/moduleparam.h | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/include/linux/moduleparam.h b/include/linux/moduleparam.h index 1d7140fef154..d94e5bef4a12 100644 --- a/include/linux/moduleparam.h +++ b/include/linux/moduleparam.h @@ -229,18 +229,10 @@ struct kparam_array /* Obsolete - use module_param_cb() */ #define module_param_call(name, set, get, arg, perm) \ - static const struct kernel_param_ops __param_ops_##name = \ + static const struct kernel_param_ops __param_ops_##name = \ { .flags = 0, (void *)set, (void *)get }; \ __module_param_call(MODULE_PARAM_PREFIX, \ - name, &__param_ops_##name, arg, \ - (perm) + sizeof(__check_old_set_param(set))*0, -1, 0) - -/* We don't get oldget: it's often a new-style param_get_uint, etc. */ -static inline int -__check_old_set_param(int (*oldset)(const char *, struct kernel_param *)) -{ - return 0; -} + name, &__param_ops_##name, arg, perm, -1, 0) #ifdef CONFIG_SYSFS extern void kernel_param_lock(struct module *mod); -- GitLab From 549b203743145b290c31f1d349f06e43e7cf06ee Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Tue, 17 Oct 2017 19:04:42 -0700 Subject: [PATCH 0856/1635] UPSTREAM: treewide: Fix function prototypes for module_param_call() Several function prototypes for the set/get functions defined by module_param_call() have a slightly wrong argument types. This fixes those in an effort to clean up the calls when running under type-enforced compiler instrumentation for CFI. This is the result of running the following semantic patch: @match_module_param_call_function@ declarer name module_param_call; identifier _name, _set_func, _get_func; expression _arg, _mode; @@ module_param_call(_name, _set_func, _get_func, _arg, _mode); @fix_set_prototype depends on match_module_param_call_function@ identifier match_module_param_call_function._set_func; identifier _val, _param; type _val_type, _param_type; @@ int _set_func( -_val_type _val +const char * _val , -_param_type _param +const struct kernel_param * _param ) { ... } @fix_get_prototype depends on match_module_param_call_function@ identifier match_module_param_call_function._get_func; identifier _val, _param; type _val_type, _param_type; @@ int _get_func( -_val_type _val +char * _val , -_param_type _param +const struct kernel_param * _param ) { ... } Two additional by-hand changes are included for places where the above Coccinelle script didn't notice them: drivers/platform/x86/thinkpad_acpi.c fs/lockd/svc.c Signed-off-by: Kees Cook Signed-off-by: Jessica Yu Bug: 67506682 Change-Id: I2c9c0ee8ed28065e63270a52c155e5e7d2791295 (cherry picked from commit e4dca7b7aa08b22893c45485d222b5807c1375ae) Signed-off-by: Sami Tolvanen --- arch/powerpc/platforms/pseries/cmm.c | 2 +- arch/x86/oprofile/nmi_int.c | 2 +- drivers/acpi/button.c | 6 ++++-- drivers/acpi/ec.c | 6 ++++-- drivers/acpi/sysfs.c | 8 +++++--- drivers/android/binder.c | 2 +- drivers/char/ipmi/ipmi_poweroff.c | 2 +- drivers/char/ipmi/ipmi_si_intf.c | 4 ++-- drivers/edac/edac_mc_sysfs.c | 2 +- drivers/edac/edac_module.c | 3 ++- drivers/hid/hid-magicmouse.c | 3 ++- drivers/ide/ide.c | 4 ++-- drivers/infiniband/hw/qib/qib_iba7322.c | 4 ++-- drivers/infiniband/ulp/srpt/ib_srpt.c | 2 +- drivers/isdn/hardware/mISDN/avmfritz.c | 2 +- drivers/isdn/hardware/mISDN/mISDNinfineon.c | 2 +- drivers/isdn/hardware/mISDN/netjet.c | 2 +- drivers/isdn/hardware/mISDN/speedfax.c | 2 +- drivers/isdn/hardware/mISDN/w6692.c | 2 +- drivers/md/md.c | 6 +++--- drivers/media/pci/tw686x/tw686x-core.c | 4 ++-- drivers/media/usb/uvc/uvc_driver.c | 4 ++-- drivers/message/fusion/mptbase.c | 4 ++-- drivers/misc/kgdbts.c | 3 ++- drivers/mtd/devices/block2mtd.c | 2 +- drivers/mtd/devices/phram.c | 2 +- drivers/mtd/ubi/build.c | 2 +- drivers/pci/pcie/aspm.c | 5 +++-- drivers/platform/x86/thinkpad_acpi.c | 2 +- drivers/scsi/fcoe/fcoe_transport.c | 20 ++++++++++++-------- drivers/scsi/mpt3sas/mpt3sas_base.c | 2 +- drivers/scsi/mpt3sas/mpt3sas_scsih.c | 2 +- drivers/tty/serial/kgdboc.c | 3 ++- fs/fuse/inode.c | 4 ++-- fs/lockd/svc.c | 2 +- fs/ocfs2/dlmfs/dlmfs.c | 4 ++-- include/net/netfilter/nf_conntrack.h | 2 +- net/netfilter/nf_conntrack_core.c | 2 +- net/netfilter/nf_nat_ftp.c | 2 +- net/netfilter/nf_nat_irc.c | 2 +- net/sunrpc/svc.c | 4 ++-- security/apparmor/lsm.c | 16 ++++++++-------- 42 files changed, 87 insertions(+), 72 deletions(-) diff --git a/arch/powerpc/platforms/pseries/cmm.c b/arch/powerpc/platforms/pseries/cmm.c index 4ac419c7eb4c..560aefde06c0 100644 --- a/arch/powerpc/platforms/pseries/cmm.c +++ b/arch/powerpc/platforms/pseries/cmm.c @@ -742,7 +742,7 @@ static void cmm_exit(void) * Return value: * 0 on success / other on failure **/ -static int cmm_set_disable(const char *val, struct kernel_param *kp) +static int cmm_set_disable(const char *val, const struct kernel_param *kp) { int disable = simple_strtoul(val, NULL, 10); diff --git a/arch/x86/oprofile/nmi_int.c b/arch/x86/oprofile/nmi_int.c index abff76bda9e6..a7a7677265b6 100644 --- a/arch/x86/oprofile/nmi_int.c +++ b/arch/x86/oprofile/nmi_int.c @@ -592,7 +592,7 @@ enum __force_cpu_type { static int force_cpu_type; -static int set_cpu_type(const char *str, struct kernel_param *kp) +static int set_cpu_type(const char *str, const struct kernel_param *kp) { if (!strcmp(str, "timer")) { force_cpu_type = timer; diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c index ef1856b15488..891b0921a307 100644 --- a/drivers/acpi/button.c +++ b/drivers/acpi/button.c @@ -557,7 +557,8 @@ static int acpi_button_remove(struct acpi_device *device) return 0; } -static int param_set_lid_init_state(const char *val, struct kernel_param *kp) +static int param_set_lid_init_state(const char *val, + const struct kernel_param *kp) { int result = 0; @@ -575,7 +576,8 @@ static int param_set_lid_init_state(const char *val, struct kernel_param *kp) return result; } -static int param_get_lid_init_state(char *buffer, struct kernel_param *kp) +static int param_get_lid_init_state(char *buffer, + const struct kernel_param *kp) { switch (lid_init_state) { case ACPI_BUTTON_LID_INIT_OPEN: diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index 6adcda057b36..d9f38c645e4a 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -1956,7 +1956,8 @@ static const struct dev_pm_ops acpi_ec_pm = { SET_SYSTEM_SLEEP_PM_OPS(acpi_ec_suspend, acpi_ec_resume) }; -static int param_set_event_clearing(const char *val, struct kernel_param *kp) +static int param_set_event_clearing(const char *val, + const struct kernel_param *kp) { int result = 0; @@ -1974,7 +1975,8 @@ static int param_set_event_clearing(const char *val, struct kernel_param *kp) return result; } -static int param_get_event_clearing(char *buffer, struct kernel_param *kp) +static int param_get_event_clearing(char *buffer, + const struct kernel_param *kp) { switch (ec_event_clearing) { case ACPI_EC_EVT_TIMING_STATUS: diff --git a/drivers/acpi/sysfs.c b/drivers/acpi/sysfs.c index 0fd57bf33524..9e728a1494f6 100644 --- a/drivers/acpi/sysfs.c +++ b/drivers/acpi/sysfs.c @@ -230,7 +230,8 @@ module_param_cb(trace_method_name, ¶m_ops_trace_method, &trace_method_name, module_param_cb(trace_debug_layer, ¶m_ops_trace_attrib, &acpi_gbl_trace_dbg_layer, 0644); module_param_cb(trace_debug_level, ¶m_ops_trace_attrib, &acpi_gbl_trace_dbg_level, 0644); -static int param_set_trace_state(const char *val, struct kernel_param *kp) +static int param_set_trace_state(const char *val, + const struct kernel_param *kp) { acpi_status status; const char *method = trace_method_name; @@ -266,7 +267,7 @@ static int param_set_trace_state(const char *val, struct kernel_param *kp) return 0; } -static int param_get_trace_state(char *buffer, struct kernel_param *kp) +static int param_get_trace_state(char *buffer, const struct kernel_param *kp) { if (!(acpi_gbl_trace_flags & ACPI_TRACE_ENABLED)) return sprintf(buffer, "disable"); @@ -295,7 +296,8 @@ MODULE_PARM_DESC(aml_debug_output, "To enable/disable the ACPI Debug Object output."); /* /sys/module/acpi/parameters/acpica_version */ -static int param_get_acpica_version(char *buffer, struct kernel_param *kp) +static int param_get_acpica_version(char *buffer, + const struct kernel_param *kp) { int result; diff --git a/drivers/android/binder.c b/drivers/android/binder.c index ac976864b3d1..e84d6ce7a60a 100644 --- a/drivers/android/binder.c +++ b/drivers/android/binder.c @@ -151,7 +151,7 @@ static DECLARE_WAIT_QUEUE_HEAD(binder_user_error_wait); static int binder_stop_on_user_error; static int binder_set_stop_on_user_error(const char *val, - struct kernel_param *kp) + const struct kernel_param *kp) { int ret; diff --git a/drivers/char/ipmi/ipmi_poweroff.c b/drivers/char/ipmi/ipmi_poweroff.c index 9f2e3be2c5b8..676c910e990f 100644 --- a/drivers/char/ipmi/ipmi_poweroff.c +++ b/drivers/char/ipmi/ipmi_poweroff.c @@ -66,7 +66,7 @@ static void (*specific_poweroff_func)(ipmi_user_t user); /* Holds the old poweroff function so we can restore it on removal. */ static void (*old_poweroff_func)(void); -static int set_param_ifnum(const char *val, struct kernel_param *kp) +static int set_param_ifnum(const char *val, const struct kernel_param *kp) { int rv = param_set_int(val, kp); if (rv) diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index c04aa11f0e21..9abc067f5799 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c @@ -1345,7 +1345,7 @@ static unsigned int num_slave_addrs; #define IPMI_MEM_ADDR_SPACE 1 static const char * const addr_space_to_str[] = { "i/o", "mem" }; -static int hotmod_handler(const char *val, struct kernel_param *kp); +static int hotmod_handler(const char *val, const struct kernel_param *kp); module_param_call(hotmod, hotmod_handler, NULL, NULL, 0200); MODULE_PARM_DESC(hotmod, "Add and remove interfaces. See" @@ -1811,7 +1811,7 @@ static struct smi_info *smi_info_alloc(void) return info; } -static int hotmod_handler(const char *val, struct kernel_param *kp) +static int hotmod_handler(const char *val, const struct kernel_param *kp) { char *str = kstrdup(val, GFP_KERNEL); int rv; diff --git a/drivers/edac/edac_mc_sysfs.c b/drivers/edac/edac_mc_sysfs.c index e4fcfa84fbd3..c70ea82c815c 100644 --- a/drivers/edac/edac_mc_sysfs.c +++ b/drivers/edac/edac_mc_sysfs.c @@ -50,7 +50,7 @@ int edac_mc_get_poll_msec(void) return edac_mc_poll_msec; } -static int edac_set_poll_msec(const char *val, struct kernel_param *kp) +static int edac_set_poll_msec(const char *val, const struct kernel_param *kp) { unsigned long l; int ret; diff --git a/drivers/edac/edac_module.c b/drivers/edac/edac_module.c index 172598a27d7d..32a931d0cb71 100644 --- a/drivers/edac/edac_module.c +++ b/drivers/edac/edac_module.c @@ -19,7 +19,8 @@ #ifdef CONFIG_EDAC_DEBUG -static int edac_set_debug_level(const char *buf, struct kernel_param *kp) +static int edac_set_debug_level(const char *buf, + const struct kernel_param *kp) { unsigned long val; int ret; diff --git a/drivers/hid/hid-magicmouse.c b/drivers/hid/hid-magicmouse.c index 20b40ad26325..42ed887ba0be 100644 --- a/drivers/hid/hid-magicmouse.c +++ b/drivers/hid/hid-magicmouse.c @@ -34,7 +34,8 @@ module_param(emulate_scroll_wheel, bool, 0644); MODULE_PARM_DESC(emulate_scroll_wheel, "Emulate a scroll wheel"); static unsigned int scroll_speed = 32; -static int param_set_scroll_speed(const char *val, struct kernel_param *kp) { +static int param_set_scroll_speed(const char *val, + const struct kernel_param *kp) { unsigned long speed; if (!val || kstrtoul(val, 0, &speed) || speed > 63) return -EINVAL; diff --git a/drivers/ide/ide.c b/drivers/ide/ide.c index d127ace6aa57..6ee866fcc5dd 100644 --- a/drivers/ide/ide.c +++ b/drivers/ide/ide.c @@ -244,7 +244,7 @@ struct chs_geom { static unsigned int ide_disks; static struct chs_geom ide_disks_chs[MAX_HWIFS * MAX_DRIVES]; -static int ide_set_disk_chs(const char *str, struct kernel_param *kp) +static int ide_set_disk_chs(const char *str, const struct kernel_param *kp) { unsigned int a, b, c = 0, h = 0, s = 0, i, j = 1; @@ -328,7 +328,7 @@ static void ide_dev_apply_params(ide_drive_t *drive, u8 unit) static unsigned int ide_ignore_cable; -static int ide_set_ignore_cable(const char *s, struct kernel_param *kp) +static int ide_set_ignore_cable(const char *s, const struct kernel_param *kp) { int i, j = 1; diff --git a/drivers/infiniband/hw/qib/qib_iba7322.c b/drivers/infiniband/hw/qib/qib_iba7322.c index 14cadf6d6214..a45e46098914 100644 --- a/drivers/infiniband/hw/qib/qib_iba7322.c +++ b/drivers/infiniband/hw/qib/qib_iba7322.c @@ -150,7 +150,7 @@ static struct kparam_string kp_txselect = { .string = txselect_list, .maxlen = MAX_ATTEN_LEN }; -static int setup_txselect(const char *, struct kernel_param *); +static int setup_txselect(const char *, const struct kernel_param *); module_param_call(txselect, setup_txselect, param_get_string, &kp_txselect, S_IWUSR | S_IRUGO); MODULE_PARM_DESC(txselect, @@ -6169,7 +6169,7 @@ static void set_no_qsfp_atten(struct qib_devdata *dd, int change) } /* handle the txselect parameter changing */ -static int setup_txselect(const char *str, struct kernel_param *kp) +static int setup_txselect(const char *str, const struct kernel_param *kp) { struct qib_devdata *dd; unsigned long val; diff --git a/drivers/infiniband/ulp/srpt/ib_srpt.c b/drivers/infiniband/ulp/srpt/ib_srpt.c index ee578fa713c2..7b1d7e58671e 100644 --- a/drivers/infiniband/ulp/srpt/ib_srpt.c +++ b/drivers/infiniband/ulp/srpt/ib_srpt.c @@ -80,7 +80,7 @@ module_param(srpt_srq_size, int, 0444); MODULE_PARM_DESC(srpt_srq_size, "Shared receive queue (SRQ) size."); -static int srpt_get_u64_x(char *buffer, struct kernel_param *kp) +static int srpt_get_u64_x(char *buffer, const struct kernel_param *kp) { return sprintf(buffer, "0x%016llx", *(u64 *)kp->arg); } diff --git a/drivers/isdn/hardware/mISDN/avmfritz.c b/drivers/isdn/hardware/mISDN/avmfritz.c index dce6632daae1..ae2b2669af1b 100644 --- a/drivers/isdn/hardware/mISDN/avmfritz.c +++ b/drivers/isdn/hardware/mISDN/avmfritz.c @@ -156,7 +156,7 @@ _set_debug(struct fritzcard *card) } static int -set_debug(const char *val, struct kernel_param *kp) +set_debug(const char *val, const struct kernel_param *kp) { int ret; struct fritzcard *card; diff --git a/drivers/isdn/hardware/mISDN/mISDNinfineon.c b/drivers/isdn/hardware/mISDN/mISDNinfineon.c index d5bdbaf93a1a..1fc290659e94 100644 --- a/drivers/isdn/hardware/mISDN/mISDNinfineon.c +++ b/drivers/isdn/hardware/mISDN/mISDNinfineon.c @@ -244,7 +244,7 @@ _set_debug(struct inf_hw *card) } static int -set_debug(const char *val, struct kernel_param *kp) +set_debug(const char *val, const struct kernel_param *kp) { int ret; struct inf_hw *card; diff --git a/drivers/isdn/hardware/mISDN/netjet.c b/drivers/isdn/hardware/mISDN/netjet.c index 6a6d848bd18e..89d9ba8ed535 100644 --- a/drivers/isdn/hardware/mISDN/netjet.c +++ b/drivers/isdn/hardware/mISDN/netjet.c @@ -111,7 +111,7 @@ _set_debug(struct tiger_hw *card) } static int -set_debug(const char *val, struct kernel_param *kp) +set_debug(const char *val, const struct kernel_param *kp) { int ret; struct tiger_hw *card; diff --git a/drivers/isdn/hardware/mISDN/speedfax.c b/drivers/isdn/hardware/mISDN/speedfax.c index 9815bb4eec9c..1f1446ed8d5f 100644 --- a/drivers/isdn/hardware/mISDN/speedfax.c +++ b/drivers/isdn/hardware/mISDN/speedfax.c @@ -94,7 +94,7 @@ _set_debug(struct sfax_hw *card) } static int -set_debug(const char *val, struct kernel_param *kp) +set_debug(const char *val, const struct kernel_param *kp) { int ret; struct sfax_hw *card; diff --git a/drivers/isdn/hardware/mISDN/w6692.c b/drivers/isdn/hardware/mISDN/w6692.c index d80072fef434..209036a4af3a 100644 --- a/drivers/isdn/hardware/mISDN/w6692.c +++ b/drivers/isdn/hardware/mISDN/w6692.c @@ -101,7 +101,7 @@ _set_debug(struct w6692_hw *card) } static int -set_debug(const char *val, struct kernel_param *kp) +set_debug(const char *val, const struct kernel_param *kp) { int ret; struct w6692_hw *card; diff --git a/drivers/md/md.c b/drivers/md/md.c index e058c209bbcf..7671b1475607 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -5357,7 +5357,7 @@ static struct kobject *md_probe(dev_t dev, int *part, void *data) return NULL; } -static int add_named_array(const char *val, struct kernel_param *kp) +static int add_named_array(const char *val, const struct kernel_param *kp) { /* * val must be "md_*" or "mdNNN". @@ -9278,11 +9278,11 @@ static __exit void md_exit(void) subsys_initcall(md_init); module_exit(md_exit) -static int get_ro(char *buffer, struct kernel_param *kp) +static int get_ro(char *buffer, const struct kernel_param *kp) { return sprintf(buffer, "%d", start_readonly); } -static int set_ro(const char *val, struct kernel_param *kp) +static int set_ro(const char *val, const struct kernel_param *kp) { return kstrtouint(val, 10, (unsigned int *)&start_readonly); } diff --git a/drivers/media/pci/tw686x/tw686x-core.c b/drivers/media/pci/tw686x/tw686x-core.c index 336e2f9bc1b6..b762e5f0ba1d 100644 --- a/drivers/media/pci/tw686x/tw686x-core.c +++ b/drivers/media/pci/tw686x/tw686x-core.c @@ -72,12 +72,12 @@ static const char *dma_mode_name(unsigned int mode) } } -static int tw686x_dma_mode_get(char *buffer, struct kernel_param *kp) +static int tw686x_dma_mode_get(char *buffer, const struct kernel_param *kp) { return sprintf(buffer, "%s", dma_mode_name(dma_mode)); } -static int tw686x_dma_mode_set(const char *val, struct kernel_param *kp) +static int tw686x_dma_mode_set(const char *val, const struct kernel_param *kp) { if (!strcasecmp(val, dma_mode_name(TW686X_DMA_MODE_MEMCPY))) dma_mode = TW686X_DMA_MODE_MEMCPY; diff --git a/drivers/media/usb/uvc/uvc_driver.c b/drivers/media/usb/uvc/uvc_driver.c index 6d22b22cb35b..28b91b7d756f 100644 --- a/drivers/media/usb/uvc/uvc_driver.c +++ b/drivers/media/usb/uvc/uvc_driver.c @@ -2230,7 +2230,7 @@ static int uvc_reset_resume(struct usb_interface *intf) * Module parameters */ -static int uvc_clock_param_get(char *buffer, struct kernel_param *kp) +static int uvc_clock_param_get(char *buffer, const struct kernel_param *kp) { if (uvc_clock_param == CLOCK_MONOTONIC) return sprintf(buffer, "CLOCK_MONOTONIC"); @@ -2238,7 +2238,7 @@ static int uvc_clock_param_get(char *buffer, struct kernel_param *kp) return sprintf(buffer, "CLOCK_REALTIME"); } -static int uvc_clock_param_set(const char *val, struct kernel_param *kp) +static int uvc_clock_param_set(const char *val, const struct kernel_param *kp) { if (strncasecmp(val, "clock_", strlen("clock_")) == 0) val += strlen("clock_"); diff --git a/drivers/message/fusion/mptbase.c b/drivers/message/fusion/mptbase.c index 84eab28665f3..7a93400eea2a 100644 --- a/drivers/message/fusion/mptbase.c +++ b/drivers/message/fusion/mptbase.c @@ -99,7 +99,7 @@ module_param(mpt_channel_mapping, int, 0); MODULE_PARM_DESC(mpt_channel_mapping, " Mapping id's to channels (default=0)"); static int mpt_debug_level; -static int mpt_set_debug_level(const char *val, struct kernel_param *kp); +static int mpt_set_debug_level(const char *val, const struct kernel_param *kp); module_param_call(mpt_debug_level, mpt_set_debug_level, param_get_int, &mpt_debug_level, 0600); MODULE_PARM_DESC(mpt_debug_level, @@ -242,7 +242,7 @@ pci_enable_io_access(struct pci_dev *pdev) pci_write_config_word(pdev, PCI_COMMAND, command_reg); } -static int mpt_set_debug_level(const char *val, struct kernel_param *kp) +static int mpt_set_debug_level(const char *val, const struct kernel_param *kp) { int ret = param_set_int(val, kp); MPT_ADAPTER *ioc; diff --git a/drivers/misc/kgdbts.c b/drivers/misc/kgdbts.c index fc7efedbc4be..24108bfad889 100644 --- a/drivers/misc/kgdbts.c +++ b/drivers/misc/kgdbts.c @@ -1132,7 +1132,8 @@ static void kgdbts_put_char(u8 chr) ts.run_test(0, chr); } -static int param_set_kgdbts_var(const char *kmessage, struct kernel_param *kp) +static int param_set_kgdbts_var(const char *kmessage, + const struct kernel_param *kp) { int len = strlen(kmessage); diff --git a/drivers/mtd/devices/block2mtd.c b/drivers/mtd/devices/block2mtd.c index 7c887f111a7d..62fd6905c648 100644 --- a/drivers/mtd/devices/block2mtd.c +++ b/drivers/mtd/devices/block2mtd.c @@ -431,7 +431,7 @@ static int block2mtd_setup2(const char *val) } -static int block2mtd_setup(const char *val, struct kernel_param *kp) +static int block2mtd_setup(const char *val, const struct kernel_param *kp) { #ifdef MODULE return block2mtd_setup2(val); diff --git a/drivers/mtd/devices/phram.c b/drivers/mtd/devices/phram.c index 8b66e52ca3cc..7287696a21f9 100644 --- a/drivers/mtd/devices/phram.c +++ b/drivers/mtd/devices/phram.c @@ -266,7 +266,7 @@ static int phram_setup(const char *val) return ret; } -static int phram_param_call(const char *val, struct kernel_param *kp) +static int phram_param_call(const char *val, const struct kernel_param *kp) { #ifdef MODULE return phram_setup(val); diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c index defb1cd8d2e1..68d6f4158868 100644 --- a/drivers/mtd/ubi/build.c +++ b/drivers/mtd/ubi/build.c @@ -1345,7 +1345,7 @@ static int bytes_str_to_int(const char *str) * This function returns zero in case of success and a negative error code in * case of error. */ -static int ubi_mtd_param_parse(const char *val, struct kernel_param *kp) +static int ubi_mtd_param_parse(const char *val, const struct kernel_param *kp) { int i, len; struct mtd_dev_param *p; diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c index 633e55c57b13..bcb96af284a1 100644 --- a/drivers/pci/pcie/aspm.c +++ b/drivers/pci/pcie/aspm.c @@ -1065,7 +1065,8 @@ void pci_disable_link_state(struct pci_dev *pdev, int state) } EXPORT_SYMBOL(pci_disable_link_state); -static int pcie_aspm_set_policy(const char *val, struct kernel_param *kp) +static int pcie_aspm_set_policy(const char *val, + const struct kernel_param *kp) { int i; struct pcie_link_state *link; @@ -1092,7 +1093,7 @@ static int pcie_aspm_set_policy(const char *val, struct kernel_param *kp) return 0; } -static int pcie_aspm_get_policy(char *buffer, struct kernel_param *kp) +static int pcie_aspm_get_policy(char *buffer, const struct kernel_param *kp) { int i, cnt = 0; for (i = 0; i < ARRAY_SIZE(policy_str); i++) diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index 2242d6035d9e..3887dfeafc96 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -9543,7 +9543,7 @@ static struct ibm_init_struct ibms_init[] __initdata = { }, }; -static int __init set_ibm_param(const char *val, struct kernel_param *kp) +static int __init set_ibm_param(const char *val, const struct kernel_param *kp) { unsigned int i; struct ibm_struct *ibm; diff --git a/drivers/scsi/fcoe/fcoe_transport.c b/drivers/scsi/fcoe/fcoe_transport.c index 375c536cbc68..c5eb0c468f0b 100644 --- a/drivers/scsi/fcoe/fcoe_transport.c +++ b/drivers/scsi/fcoe/fcoe_transport.c @@ -32,13 +32,13 @@ MODULE_AUTHOR("Open-FCoE.org"); MODULE_DESCRIPTION("FIP discovery protocol and FCoE transport for FCoE HBAs"); MODULE_LICENSE("GPL v2"); -static int fcoe_transport_create(const char *, struct kernel_param *); -static int fcoe_transport_destroy(const char *, struct kernel_param *); +static int fcoe_transport_create(const char *, const struct kernel_param *); +static int fcoe_transport_destroy(const char *, const struct kernel_param *); static int fcoe_transport_show(char *buffer, const struct kernel_param *kp); static struct fcoe_transport *fcoe_transport_lookup(struct net_device *device); static struct fcoe_transport *fcoe_netdev_map_lookup(struct net_device *device); -static int fcoe_transport_enable(const char *, struct kernel_param *); -static int fcoe_transport_disable(const char *, struct kernel_param *); +static int fcoe_transport_enable(const char *, const struct kernel_param *); +static int fcoe_transport_disable(const char *, const struct kernel_param *); static int libfcoe_device_notification(struct notifier_block *notifier, ulong event, void *ptr); @@ -865,7 +865,8 @@ EXPORT_SYMBOL(fcoe_ctlr_destroy_store); * * Returns: 0 for success */ -static int fcoe_transport_create(const char *buffer, struct kernel_param *kp) +static int fcoe_transport_create(const char *buffer, + const struct kernel_param *kp) { int rc = -ENODEV; struct net_device *netdev = NULL; @@ -930,7 +931,8 @@ static int fcoe_transport_create(const char *buffer, struct kernel_param *kp) * * Returns: 0 for success */ -static int fcoe_transport_destroy(const char *buffer, struct kernel_param *kp) +static int fcoe_transport_destroy(const char *buffer, + const struct kernel_param *kp) { int rc = -ENODEV; struct net_device *netdev = NULL; @@ -974,7 +976,8 @@ static int fcoe_transport_destroy(const char *buffer, struct kernel_param *kp) * * Returns: 0 for success */ -static int fcoe_transport_disable(const char *buffer, struct kernel_param *kp) +static int fcoe_transport_disable(const char *buffer, + const struct kernel_param *kp) { int rc = -ENODEV; struct net_device *netdev = NULL; @@ -1008,7 +1011,8 @@ static int fcoe_transport_disable(const char *buffer, struct kernel_param *kp) * * Returns: 0 for success */ -static int fcoe_transport_enable(const char *buffer, struct kernel_param *kp) +static int fcoe_transport_enable(const char *buffer, + const struct kernel_param *kp) { int rc = -ENODEV; struct net_device *netdev = NULL; diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.c b/drivers/scsi/mpt3sas/mpt3sas_base.c index 6efa739a1912..508ae4bc5ab5 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_base.c +++ b/drivers/scsi/mpt3sas/mpt3sas_base.c @@ -105,7 +105,7 @@ _base_get_ioc_facts(struct MPT3SAS_ADAPTER *ioc); * */ static int -_scsih_set_fwfault_debug(const char *val, struct kernel_param *kp) +_scsih_set_fwfault_debug(const char *val, const struct kernel_param *kp) { int ret = param_set_int(val, kp); struct MPT3SAS_ADAPTER *ioc; diff --git a/drivers/scsi/mpt3sas/mpt3sas_scsih.c b/drivers/scsi/mpt3sas/mpt3sas_scsih.c index 139219c994e9..a1a7c45497f5 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_scsih.c +++ b/drivers/scsi/mpt3sas/mpt3sas_scsih.c @@ -281,7 +281,7 @@ struct _scsi_io_transfer { * Note: The logging levels are defined in mpt3sas_debug.h. */ static int -_scsih_set_debug_level(const char *val, struct kernel_param *kp) +_scsih_set_debug_level(const char *val, const struct kernel_param *kp) { int ret = param_set_int(val, kp); struct MPT3SAS_ADAPTER *ioc; diff --git a/drivers/tty/serial/kgdboc.c b/drivers/tty/serial/kgdboc.c index a260cde743e2..5532c440bf61 100644 --- a/drivers/tty/serial/kgdboc.c +++ b/drivers/tty/serial/kgdboc.c @@ -245,7 +245,8 @@ static void kgdboc_put_char(u8 chr) kgdb_tty_line, chr); } -static int param_set_kgdboc_var(const char *kmessage, struct kernel_param *kp) +static int param_set_kgdboc_var(const char *kmessage, + const struct kernel_param *kp) { int len = strlen(kmessage); diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c index 94a745acaef8..a79e320349cd 100644 --- a/fs/fuse/inode.c +++ b/fs/fuse/inode.c @@ -31,7 +31,7 @@ static struct kmem_cache *fuse_inode_cachep; struct list_head fuse_conn_list; DEFINE_MUTEX(fuse_mutex); -static int set_global_limit(const char *val, struct kernel_param *kp); +static int set_global_limit(const char *val, const struct kernel_param *kp); unsigned max_user_bgreq; module_param_call(max_user_bgreq, set_global_limit, param_get_uint, @@ -823,7 +823,7 @@ static void sanitize_global_limit(unsigned *limit) *limit = (1 << 16) - 1; } -static int set_global_limit(const char *val, struct kernel_param *kp) +static int set_global_limit(const char *val, const struct kernel_param *kp) { int rv; diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c index 809cbccbad28..da2825a45ce8 100644 --- a/fs/lockd/svc.c +++ b/fs/lockd/svc.c @@ -614,7 +614,7 @@ static struct ctl_table nlm_sysctl_root[] = { */ #define param_set_min_max(name, type, which_strtol, min, max) \ -static int param_set_##name(const char *val, struct kernel_param *kp) \ +static int param_set_##name(const char *val, const struct kernel_param *kp) \ { \ char *endp; \ __typeof__(type) num = which_strtol(val, &endp, 0); \ diff --git a/fs/ocfs2/dlmfs/dlmfs.c b/fs/ocfs2/dlmfs/dlmfs.c index 9ab9e1892b5f..988137de08f5 100644 --- a/fs/ocfs2/dlmfs/dlmfs.c +++ b/fs/ocfs2/dlmfs/dlmfs.c @@ -88,13 +88,13 @@ struct workqueue_struct *user_dlm_worker; */ #define DLMFS_CAPABILITIES "bast stackglue" static int param_set_dlmfs_capabilities(const char *val, - struct kernel_param *kp) + const struct kernel_param *kp) { printk(KERN_ERR "%s: readonly parameter\n", kp->name); return -EINVAL; } static int param_get_dlmfs_capabilities(char *buffer, - struct kernel_param *kp) + const struct kernel_param *kp) { return strlcpy(buffer, DLMFS_CAPABILITIES, strlen(DLMFS_CAPABILITIES) + 1); diff --git a/include/net/netfilter/nf_conntrack.h b/include/net/netfilter/nf_conntrack.h index 792c3f6d30ce..f5223bf2c420 100644 --- a/include/net/netfilter/nf_conntrack.h +++ b/include/net/netfilter/nf_conntrack.h @@ -285,7 +285,7 @@ static inline bool nf_ct_should_gc(const struct nf_conn *ct) struct kernel_param; -int nf_conntrack_set_hashsize(const char *val, struct kernel_param *kp); +int nf_conntrack_set_hashsize(const char *val, const struct kernel_param *kp); int nf_conntrack_hash_resize(unsigned int hashsize); extern struct hlist_nulls_head *nf_conntrack_hash; diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c index 01130392b7c0..5e50c54e1318 100644 --- a/net/netfilter/nf_conntrack_core.c +++ b/net/netfilter/nf_conntrack_core.c @@ -1940,7 +1940,7 @@ int nf_conntrack_hash_resize(unsigned int hashsize) return 0; } -int nf_conntrack_set_hashsize(const char *val, struct kernel_param *kp) +int nf_conntrack_set_hashsize(const char *val, const struct kernel_param *kp) { unsigned int hashsize; int rc; diff --git a/net/netfilter/nf_nat_ftp.c b/net/netfilter/nf_nat_ftp.c index e84a578dbe35..d76afafdc699 100644 --- a/net/netfilter/nf_nat_ftp.c +++ b/net/netfilter/nf_nat_ftp.c @@ -134,7 +134,7 @@ static int __init nf_nat_ftp_init(void) } /* Prior to 2.6.11, we had a ports param. No longer, but don't break users. */ -static int warn_set(const char *val, struct kernel_param *kp) +static int warn_set(const char *val, const struct kernel_param *kp) { printk(KERN_INFO KBUILD_MODNAME ": kernel >= 2.6.10 only uses 'ports' for conntrack modules\n"); diff --git a/net/netfilter/nf_nat_irc.c b/net/netfilter/nf_nat_irc.c index 0648cb096bd8..dcb5f6375d9d 100644 --- a/net/netfilter/nf_nat_irc.c +++ b/net/netfilter/nf_nat_irc.c @@ -106,7 +106,7 @@ static int __init nf_nat_irc_init(void) } /* Prior to 2.6.11, we had a ports param. No longer, but don't break users. */ -static int warn_set(const char *val, struct kernel_param *kp) +static int warn_set(const char *val, const struct kernel_param *kp) { printk(KERN_INFO KBUILD_MODNAME ": kernel >= 2.6.10 only uses 'ports' for conntrack modules\n"); diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c index aa04666f929d..e5e4e18699c8 100644 --- a/net/sunrpc/svc.c +++ b/net/sunrpc/svc.c @@ -50,7 +50,7 @@ EXPORT_SYMBOL_GPL(svc_pool_map); static DEFINE_MUTEX(svc_pool_map_mutex);/* protects svc_pool_map.count only */ static int -param_set_pool_mode(const char *val, struct kernel_param *kp) +param_set_pool_mode(const char *val, const struct kernel_param *kp) { int *ip = (int *)kp->arg; struct svc_pool_map *m = &svc_pool_map; @@ -80,7 +80,7 @@ param_set_pool_mode(const char *val, struct kernel_param *kp) } static int -param_get_pool_mode(char *buf, struct kernel_param *kp) +param_get_pool_mode(char *buf, const struct kernel_param *kp) { int *ip = (int *)kp->arg; diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c index 1346ee5be04f..17893fde4487 100644 --- a/security/apparmor/lsm.c +++ b/security/apparmor/lsm.c @@ -813,11 +813,11 @@ static const struct kernel_param_ops param_ops_aalockpolicy = { .get = param_get_aalockpolicy }; -static int param_set_audit(const char *val, struct kernel_param *kp); -static int param_get_audit(char *buffer, struct kernel_param *kp); +static int param_set_audit(const char *val, const struct kernel_param *kp); +static int param_get_audit(char *buffer, const struct kernel_param *kp); -static int param_set_mode(const char *val, struct kernel_param *kp); -static int param_get_mode(char *buffer, struct kernel_param *kp); +static int param_set_mode(const char *val, const struct kernel_param *kp); +static int param_get_mode(char *buffer, const struct kernel_param *kp); /* Flag values, also controllable via /sys/module/apparmor/parameters * We define special types as we want to do additional mediation. @@ -951,7 +951,7 @@ static int param_get_aauint(char *buffer, const struct kernel_param *kp) return param_get_uint(buffer, kp); } -static int param_get_audit(char *buffer, struct kernel_param *kp) +static int param_get_audit(char *buffer, const struct kernel_param *kp) { if (!apparmor_enabled) return -EINVAL; @@ -960,7 +960,7 @@ static int param_get_audit(char *buffer, struct kernel_param *kp) return sprintf(buffer, "%s", audit_mode_names[aa_g_audit]); } -static int param_set_audit(const char *val, struct kernel_param *kp) +static int param_set_audit(const char *val, const struct kernel_param *kp) { int i; @@ -981,7 +981,7 @@ static int param_set_audit(const char *val, struct kernel_param *kp) return -EINVAL; } -static int param_get_mode(char *buffer, struct kernel_param *kp) +static int param_get_mode(char *buffer, const struct kernel_param *kp) { if (!apparmor_enabled) return -EINVAL; @@ -991,7 +991,7 @@ static int param_get_mode(char *buffer, struct kernel_param *kp) return sprintf(buffer, "%s", aa_profile_mode_names[aa_g_profile_mode]); } -static int param_set_mode(const char *val, struct kernel_param *kp) +static int param_set_mode(const char *val, const struct kernel_param *kp) { int i; -- GitLab From 57dad96bfcbf65ae893504c137693a98874bdaa8 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Tue, 17 Oct 2017 19:04:43 -0700 Subject: [PATCH 0857/1635] UPSTREAM: module: Do not paper over type mismatches in module_param_call() The module_param_call() macro was explicitly casting the .set and .get function prototypes away. This can lead to hard-to-find type mismatches. Now that all the function prototypes have been fixed tree-wide, we can drop these casts, and use named initializers too. Signed-off-by: Kees Cook Signed-off-by: Jessica Yu Bug: 67506682 Change-Id: I439c8b4b9f0108ac357267bbc396a63baec2b242 (cherry picked from commit ece1996a21eeb344b49200e627c6660111009c10) Signed-off-by: Sami Tolvanen --- include/linux/moduleparam.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/linux/moduleparam.h b/include/linux/moduleparam.h index d94e5bef4a12..ba36506db4fb 100644 --- a/include/linux/moduleparam.h +++ b/include/linux/moduleparam.h @@ -228,9 +228,9 @@ struct kparam_array VERIFY_OCTAL_PERMISSIONS(perm), level, flags, { arg } } /* Obsolete - use module_param_cb() */ -#define module_param_call(name, set, get, arg, perm) \ +#define module_param_call(name, _set, _get, arg, perm) \ static const struct kernel_param_ops __param_ops_##name = \ - { .flags = 0, (void *)set, (void *)get }; \ + { .flags = 0, .set = _set, .get = _get }; \ __module_param_call(MODULE_PARAM_PREFIX, \ name, &__param_ops_##name, arg, perm, -1, 0) -- GitLab From dc34cc805b63de069871c5fe4d54ea57b2e32898 Mon Sep 17 00:00:00 2001 From: "Bao D. Nguyen" Date: Wed, 25 Apr 2018 15:46:51 -0700 Subject: [PATCH 0858/1635] scsi: ufs: Fix UFS's NOC error, command tracing Fix UFS unclocked access error due to the function ufshcd_release_all() being called erroneously. As a result, the UFS clock gating code may turn off the UFS clocks by mistake while the device is still active. Also, fixed the UFS command tracing being disabled by mistake. Change-Id: I5c8ff317d53d1e162b9275c81fe7e2e622cc69b5 Signed-off-by: Bao D. Nguyen --- drivers/scsi/ufs/ufshcd.c | 4 ---- drivers/scsi/ufs/ufshcd.h | 4 ++-- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index b1f6a91e860e..8566809a47c5 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -753,9 +753,6 @@ static inline void ufshcd_cond_add_cmd_trace(struct ufs_hba *hba, sector_t lba = 0; int transfer_len = 0; - if (!trace_ufshcd_command_enabled()) - return; - lrbp = &hba->lrb[tag]; if (lrbp->cmd) { /* data phase exists */ @@ -3703,7 +3700,6 @@ static int ufshcd_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd) if (err) { err = SCSI_MLQUEUE_HOST_BUSY; clear_bit_unlock(tag, &hba->lrb_in_use); - ufshcd_release_all(hba); goto out; } if (ufshcd_is_clkgating_allowed(hba)) diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h index 4e96e3994756..388f3d46c9c4 100644 --- a/drivers/scsi/ufs/ufshcd.h +++ b/drivers/scsi/ufs/ufshcd.h @@ -892,10 +892,10 @@ struct ufs_hba { #define UFSHCD_BROKEN_LCC_PROCESSING_ON_HOST UFS_BIT(13) - #define UFSHCD_QUIRK_DME_PEER_GET_FAST_MODE UFS_BIT(8) + #define UFSHCD_QUIRK_DME_PEER_GET_FAST_MODE UFS_BIT(14) /* Auto hibern8 support is broken */ - #define UFSHCD_QUIRK_BROKEN_AUTO_HIBERN8 UFS_BIT(9) + #define UFSHCD_QUIRK_BROKEN_AUTO_HIBERN8 UFS_BIT(15) unsigned int quirks; /* Deviations from standard UFSHCI spec. */ -- GitLab From 5603fd4488c31e9edcbb39b813d188526dec76eb Mon Sep 17 00:00:00 2001 From: sssanjee Date: Tue, 24 Apr 2018 15:14:40 +0530 Subject: [PATCH 0859/1635] defconfig: enable FastCVP driver for sm8150 Enable FastCVP driver, which exposes APIs to video driver to share HFI command queue address to CDSP and handle errors to exit gracefully in case video and cdsp subsystems restart. Change-Id: Iff2a0cf7f1906f7bf73c08a3ccebd6f35cd67363 Acked-by: Abhikrant Sharma Signed-off-by: Suman Voora --- arch/arm64/configs/sm8150-perf_defconfig | 1 + arch/arm64/configs/sm8150_defconfig | 1 + 2 files changed, 2 insertions(+) diff --git a/arch/arm64/configs/sm8150-perf_defconfig b/arch/arm64/configs/sm8150-perf_defconfig index b1a37b0a7991..16eeebf21664 100644 --- a/arch/arm64/configs/sm8150-perf_defconfig +++ b/arch/arm64/configs/sm8150-perf_defconfig @@ -301,6 +301,7 @@ CONFIG_SERIAL_MSM_GENI=y CONFIG_HW_RANDOM=y CONFIG_HW_RANDOM_MSM_LEGACY=y CONFIG_DIAG_CHAR=y +CONFIG_MSM_FASTCVPD=y CONFIG_MSM_ADSPRPC=y CONFIG_I2C_CHARDEV=y CONFIG_I2C_QCOM_GENI=y diff --git a/arch/arm64/configs/sm8150_defconfig b/arch/arm64/configs/sm8150_defconfig index 3cb4ed96a3e1..5bf92e55b3dc 100644 --- a/arch/arm64/configs/sm8150_defconfig +++ b/arch/arm64/configs/sm8150_defconfig @@ -312,6 +312,7 @@ CONFIG_TTY_PRINTK=y CONFIG_HW_RANDOM=y CONFIG_HW_RANDOM_MSM_LEGACY=y CONFIG_DIAG_CHAR=y +CONFIG_MSM_FASTCVPD=y CONFIG_MSM_ADSPRPC=y CONFIG_I2C_CHARDEV=y CONFIG_I2C_QCOM_GENI=y -- GitLab From b26cd5c63e4691a88c4ac8a2e34ad57b684f1205 Mon Sep 17 00:00:00 2001 From: Raghavendra Rao Ananta Date: Wed, 25 Apr 2018 17:45:09 -0700 Subject: [PATCH 0860/1635] ARM: dts: msm: Update the link information for sm8150+sdx50 Update the PCIe link information for the sm8150+sdx50 platform with the correct value. Change-Id: I6a81f80b59e19216cde099a6e1174ebcb9d567d9 Signed-off-by: Raghavendra Rao Ananta --- arch/arm64/boot/dts/qcom/sm8150-sdx50m.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/sm8150-sdx50m.dtsi b/arch/arm64/boot/dts/qcom/sm8150-sdx50m.dtsi index 28eba3e155f2..a228f982b151 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-sdx50m.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-sdx50m.dtsi @@ -22,7 +22,7 @@ qcom,mdm2ap-status-gpio = <&tlmm 142 0x00>; qcom,ap2mdm-status-gpio = <&tlmm 135 0x00>; qcom,ap2mdm-soft-reset-gpio = <&pm855l_gpios 9 0>; - qcom,mdm-link-info = "0304_00.01.00"; + qcom,mdm-link-info = "0305_01.01.00"; qcom,esoc-skip-restart-for-mdm-crash; status = "ok"; }; -- GitLab From 867889444eda1134a8488fe746377c883b300601 Mon Sep 17 00:00:00 2001 From: Ziqi Chen Date: Tue, 26 Sep 2017 18:48:28 +0800 Subject: [PATCH 0861/1635] usb: gadget: Send dedicate uevent for ML client connection According to mirror link spec, once mirror link client connected, client will set mirror link command with bRequestType 0x40 and bRequest 0xF0. In this scenario, USB driver send dedicate uevent to notify userspace that USB host is a mirror link client. Change-Id: Ic52f4f7d4e58e879877517fe5775b2f89091fe2a Signed-off-by: Ziqi Chen --- drivers/usb/gadget/configfs.c | 17 +++++++++ drivers/usb/gadget/function/f_ncm.c | 55 +++++++++++++++++++++++++++++ drivers/usb/gadget/function/u_ncm.h | 4 +++ 3 files changed, 76 insertions(+) diff --git a/drivers/usb/gadget/configfs.c b/drivers/usb/gadget/configfs.c index 1ef8187ceb5b..085f6f4f3552 100644 --- a/drivers/usb/gadget/configfs.c +++ b/drivers/usb/gadget/configfs.c @@ -14,11 +14,16 @@ #include #include +#ifdef CONFIG_USB_F_NCM +#include +#endif + #ifdef CONFIG_USB_CONFIGFS_F_ACC extern int acc_ctrlrequest(struct usb_composite_dev *cdev, const struct usb_ctrlrequest *ctrl); void acc_disconnect(void); #endif + static struct class *android_class; static struct device *android_device; static int index; @@ -1499,6 +1504,18 @@ static int android_setup(struct usb_gadget *gadget, } } +#ifdef CONFIG_USB_F_NCM + if (value < 0) + value = ncm_ctrlrequest(cdev, c); + + /* + * for mirror link command case, if it already been handled, + * do not pass to composite_setup + */ + if (value == 0) + return value; +#endif + #ifdef CONFIG_USB_CONFIGFS_F_ACC if (value < 0) value = acc_ctrlrequest(cdev, c); diff --git a/drivers/usb/gadget/function/f_ncm.c b/drivers/usb/gadget/function/f_ncm.c index dcf7bb50483f..239e211c5271 100644 --- a/drivers/usb/gadget/function/f_ncm.c +++ b/drivers/usb/gadget/function/f_ncm.c @@ -1574,10 +1574,57 @@ static struct config_item_type ncm_func_type = { .ct_owner = THIS_MODULE, }; +#ifdef CONFIG_USB_CONFIGFS_UEVENT + +struct ncm_setup_desc { + struct work_struct work; + struct device *device; + uint8_t major; // Mirror Link major version + uint8_t minor; // Mirror Link minor version +}; + +static struct ncm_setup_desc *_ncm_setup_desc; + +#define MIRROR_LINK_STRING_LENGTH_MAX 32 +static void ncm_setup_work(struct work_struct *data) +{ + char mirror_link_string[MIRROR_LINK_STRING_LENGTH_MAX]; + char *envp[2] = { mirror_link_string, NULL }; + + snprintf(mirror_link_string, MIRROR_LINK_STRING_LENGTH_MAX, + "MirrorLink=V%d.%d", + _ncm_setup_desc->major, _ncm_setup_desc->minor); + kobject_uevent_env(&_ncm_setup_desc->device->kobj, KOBJ_CHANGE, envp); +} + +int ncm_ctrlrequest(struct usb_composite_dev *cdev, + const struct usb_ctrlrequest *ctrl) +{ + int value = -EOPNOTSUPP; + + if (ctrl->bRequestType == 0x40 && ctrl->bRequest == 0xF0) { + _ncm_setup_desc->minor = (uint8_t)(ctrl->wValue >> 8); + _ncm_setup_desc->major = (uint8_t)(ctrl->wValue & 0xFF); + schedule_work(&_ncm_setup_desc->work); + value = 0; + } + + return value; +} +#endif + static void ncm_free_inst(struct usb_function_instance *f) { struct f_ncm_opts *opts; +#ifdef CONFIG_USB_CONFIGFS_UEVENT + /* release _ncm_setup_desc related resource */ + device_destroy(_ncm_setup_desc->device->class, + _ncm_setup_desc->device->devt); + cancel_work(&_ncm_setup_desc->work); + kfree(_ncm_setup_desc); +#endif + opts = container_of(f, struct f_ncm_opts, func_inst); if (opts->bound) gether_cleanup(netdev_priv(opts->net)); @@ -1604,6 +1651,14 @@ static struct usb_function_instance *ncm_alloc_inst(void) config_group_init_type_name(&opts->func_inst.group, "", &ncm_func_type); +#ifdef CONFIG_USB_CONFIGFS_UEVENT + _ncm_setup_desc = kzalloc(sizeof(*_ncm_setup_desc), GFP_KERNEL); + if (!_ncm_setup_desc) + return ERR_PTR(-ENOMEM); + INIT_WORK(&_ncm_setup_desc->work, ncm_setup_work); + _ncm_setup_desc->device = create_function_device("f_ncm"); +#endif + return &opts->func_inst; } diff --git a/drivers/usb/gadget/function/u_ncm.h b/drivers/usb/gadget/function/u_ncm.h index ce0f3a78ca13..b4541e200963 100644 --- a/drivers/usb/gadget/function/u_ncm.h +++ b/drivers/usb/gadget/function/u_ncm.h @@ -33,4 +33,8 @@ struct f_ncm_opts { int refcnt; }; +extern struct device *create_function_device(char *name); +int ncm_ctrlrequest(struct usb_composite_dev *cdev, + const struct usb_ctrlrequest *ctrl); + #endif /* U_NCM_H */ -- GitLab From 906a67a03a7cf96d94a36751910497bdb8d01e81 Mon Sep 17 00:00:00 2001 From: Harry Yang Date: Sat, 24 Mar 2018 00:53:04 -0700 Subject: [PATCH 0862/1635] ARM: dts: msm: Specify ADC channels for PM855B charger on SM8150 Specify VADC channels for PM855B charger device so that USB input voltage, current and charger temperature can be read for SM8150 platforms. CRs-Fixed: 2228622 Change-Id: I2e7291ea8cfce7cfc38a032aa92e70b07994906f Signed-off-by: Harry Yang Signed-off-by: Guru Das Srinagesh --- arch/arm64/boot/dts/qcom/sm8150-cdp.dtsi | 6 ++++++ arch/arm64/boot/dts/qcom/sm8150-mtp.dtsi | 9 +++++++++ arch/arm64/boot/dts/qcom/sm8150-qrd.dtsi | 9 +++++++++ 3 files changed, 24 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sm8150-cdp.dtsi b/arch/arm64/boot/dts/qcom/sm8150-cdp.dtsi index 24f3796dda68..a743b227b414 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-cdp.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-cdp.dtsi @@ -276,6 +276,12 @@ &pm855b_charger { qcom,batteryless-platform; + io-channels = <&pm855b_vadc ADC_USB_IN_V_16>, + <&pm855b_vadc ADC_USB_IN_I>, + <&pm855b_vadc ADC_CHG_TEMP>; + io-channel-names = "usb_in_voltage", + "usb_in_current", + "chg_temp"; }; &pm855b_vadc { diff --git a/arch/arm64/boot/dts/qcom/sm8150-mtp.dtsi b/arch/arm64/boot/dts/qcom/sm8150-mtp.dtsi index c76fa288c127..4f981e3a4049 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-mtp.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-mtp.dtsi @@ -522,3 +522,12 @@ }; }; }; + +&pm855b_charger { + io-channels = <&pm855b_vadc ADC_USB_IN_V_16>, + <&pm855b_vadc ADC_USB_IN_I>, + <&pm855b_vadc ADC_CHG_TEMP>; + io-channel-names = "usb_in_voltage", + "usb_in_current", + "chg_temp"; +}; diff --git a/arch/arm64/boot/dts/qcom/sm8150-qrd.dtsi b/arch/arm64/boot/dts/qcom/sm8150-qrd.dtsi index 758feb54689c..70c13b6c170b 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-qrd.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-qrd.dtsi @@ -507,3 +507,12 @@ }; }; }; + +&pm855b_charger { + io-channels = <&pm855b_vadc ADC_USB_IN_V_16>, + <&pm855b_vadc ADC_USB_IN_I>, + <&pm855b_vadc ADC_CHG_TEMP>; + io-channel-names = "usb_in_voltage", + "usb_in_current", + "chg_temp"; +}; -- GitLab From d676a7c0c7667cbb542739c21d5d8dc5a0b74646 Mon Sep 17 00:00:00 2001 From: Saranya Chidura Date: Thu, 26 Apr 2018 13:39:27 +0530 Subject: [PATCH 0863/1635] coresight: Kconfig: remove dependency on arch for ETM4X The coresight ETMV4 has both arm32 bit and arm64 bit support. Remove the dependency of architecture in Kconfig. Change-Id: I5615cfd5fbe572e98096c5b96a1ec5d359ab219f Signed-off-by: Saranya Chidura --- drivers/hwtracing/coresight/Kconfig | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/hwtracing/coresight/Kconfig b/drivers/hwtracing/coresight/Kconfig index 1a4b6ec08bcf..7cb22ed8c99a 100644 --- a/drivers/hwtracing/coresight/Kconfig +++ b/drivers/hwtracing/coresight/Kconfig @@ -63,7 +63,6 @@ config CORESIGHT_SOURCE_ETM3X config CORESIGHT_SOURCE_ETM4X bool "CoreSight Embedded Trace Macrocell 4.x driver" - depends on ARM64 select CORESIGHT_LINKS_AND_SINKS help This driver provides support for the ETM4.x tracer module, tracing the -- GitLab From 054c435f0b725fb274f0b3ca0934abe27a619643 Mon Sep 17 00:00:00 2001 From: Saranya Chidura Date: Thu, 8 Mar 2018 20:23:23 +0530 Subject: [PATCH 0864/1635] defconfig: add QDSS config options of qcs405 QDSS sink, replicator, ETM config support on arm architecture is added on qcs405. Change-Id: Ic30f2ea90791d00b33ee9b0bc1daf75dbef0d63e Signed-off-by: Saranya Chidura --- arch/arm/configs/qcs405_defconfig | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/arch/arm/configs/qcs405_defconfig b/arch/arm/configs/qcs405_defconfig index f865ec11eb54..f07ab6470bb0 100644 --- a/arch/arm/configs/qcs405_defconfig +++ b/arch/arm/configs/qcs405_defconfig @@ -174,6 +174,7 @@ CONFIG_NET_EMATCH_U32=y CONFIG_NET_EMATCH_META=y CONFIG_NET_EMATCH_TEXT=y CONFIG_NET_CLS_ACT=y +CONFIG_QRTR=y CONFIG_RMNET_DATA=y CONFIG_RMNET_DATA_FC=y CONFIG_RMNET_DATA_DEBUG_PKT=y @@ -326,12 +327,14 @@ CONFIG_MAILBOX=y CONFIG_QCOM_LAZY_MAPPING=y CONFIG_IOMMU_DEBUG=y CONFIG_QCOM_IOMMU=y +CONFIG_QCOM_QMI_HELPERS=y CONFIG_QCOM_SMEM=y CONFIG_QCOM_SCM=y CONFIG_MSM_SUBSYSTEM_RESTART=y CONFIG_MSM_PIL=y CONFIG_MSM_BOOT_STATS=y CONFIG_MSM_CORE_HANG_DETECT=y +# CONFIG_MSM_JTAGV8 is not set CONFIG_PWM=y CONFIG_ANDROID=y CONFIG_ANDROID_BINDER_IPC=y @@ -383,11 +386,15 @@ CONFIG_IPC_LOGGING=y CONFIG_BLK_DEV_IO_TRACE=y CONFIG_LKDTM=y CONFIG_CORESIGHT=y +CONFIG_CORESIGHT_LINK_AND_SINK_TMC=y +CONFIG_CORESIGHT_SOURCE_ETM4X=y +CONFIG_CORESIGHT_DYNAMIC_REPLICATOR=y CONFIG_CORESIGHT_STM=y CONFIG_CORESIGHT_CTI=y CONFIG_CORESIGHT_TPDA=y CONFIG_CORESIGHT_TPDM=y CONFIG_CORESIGHT_HWEVENT=y +CONFIG_CORESIGHT_REMOTE_ETM=y CONFIG_CORESIGHT_EVENT=y CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y CONFIG_SECURITY=y -- GitLab From 1974ed8f771348b1f361519310132b5345a802d4 Mon Sep 17 00:00:00 2001 From: Pavankumar Kondeti Date: Thu, 25 Jan 2018 01:12:08 +0530 Subject: [PATCH 0865/1635] sched/walt: improve the scheduler This change is for general scheduler improvement. Change-Id: I03c9e0c333c139ef848c4c2143606c6fe0335a7d Signed-off-by: Pavankumar Kondeti --- kernel/sched/walt.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/kernel/sched/walt.c b/kernel/sched/walt.c index 746d3a2c1d83..7d02721328b7 100644 --- a/kernel/sched/walt.c +++ b/kernel/sched/walt.c @@ -817,8 +817,7 @@ void fixup_busy_time(struct task_struct *p, int new_cpu) if (p == src_rq->ed_task) { src_rq->ed_task = NULL; - if (!dest_rq->ed_task) - dest_rq->ed_task = p; + dest_rq->ed_task = p; } done: -- GitLab From 240a528684852cc3231b276b59c3e4bf1b533de5 Mon Sep 17 00:00:00 2001 From: Steve French Date: Fri, 20 Apr 2018 12:19:07 -0500 Subject: [PATCH 0866/1635] cifs: do not allow creating sockets except with SMB1 posix exensions commit 1d0cffa674cfa7d185a302c8c6850fc50b893bed upstream. RHBZ: 1453123 Since at least the 3.10 kernel and likely a lot earlier we have not been able to create unix domain sockets in a cifs share when mounted using the SFU mount option (except when mounted with the cifs unix extensions to Samba e.g.) Trying to create a socket, for example using the af_unix command from xfstests will cause : BUG: unable to handle kernel NULL pointer dereference at 00000000 00000040 Since no one uses or depends on being able to create unix domains sockets on a cifs share the easiest fix to stop this vulnerability is to simply not allow creation of any other special files than char or block devices when sfu is used. Added update to Ronnie's patch to handle a tcon link leak, and to address a buf leak noticed by Gustavo and Colin. Acked-by: Gustavo A. R. Silva CC: Colin Ian King Reviewed-by: Pavel Shilovsky Reported-by: Eryu Guan Signed-off-by: Ronnie Sahlberg Signed-off-by: Steve French Cc: stable@vger.kernel.org Signed-off-by: Greg Kroah-Hartman --- fs/cifs/dir.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c index 81ba6e0d88d8..925844343038 100644 --- a/fs/cifs/dir.c +++ b/fs/cifs/dir.c @@ -684,6 +684,9 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, umode_t mode, goto mknod_out; } + if (!S_ISCHR(mode) && !S_ISBLK(mode)) + goto mknod_out; + if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL)) goto mknod_out; @@ -692,10 +695,8 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, umode_t mode, buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL); if (buf == NULL) { - kfree(full_path); rc = -ENOMEM; - free_xid(xid); - return rc; + goto mknod_out; } if (backup_cred(cifs_sb)) @@ -742,7 +743,7 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, umode_t mode, pdev->minor = cpu_to_le64(MINOR(device_number)); rc = tcon->ses->server->ops->sync_write(xid, &fid, &io_parms, &bytes_written, iov, 1); - } /* else if (S_ISFIFO) */ + } tcon->ses->server->ops->close(xid, tcon, &fid); d_drop(direntry); -- GitLab From f6edc45e21c35f9e0124f7ac8b2d8eb7f551cc3b Mon Sep 17 00:00:00 2001 From: David Sterba Date: Mon, 16 Apr 2018 21:10:14 +0200 Subject: [PATCH 0867/1635] btrfs: fix unaligned access in readdir MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 92d32170847bfff2dd08af2c016085779f2fd2a1 upstream. The last update to readdir introduced a temporary buffer to store the emitted readdir data, but as there are file names of variable length, there's a lot of unaligned access. This was observed on a sparc64 machine: Kernel unaligned access at TPC[102f3080] btrfs_real_readdir+0x51c/0x718 [btrfs] Fixes: 23b5ec74943 ("btrfs: fix readdir deadlock with pagefault") CC: stable@vger.kernel.org # 4.14+ Reported-and-tested-by: René Rebe Reviewed-by: Liu Bo Signed-off-by: David Sterba Signed-off-by: Greg Kroah-Hartman --- fs/btrfs/inode.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index dfa360d18ae2..768661aa885c 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -42,6 +42,7 @@ #include #include #include +#include #include "ctree.h" #include "disk-io.h" #include "transaction.h" @@ -5980,11 +5981,13 @@ static int btrfs_filldir(void *addr, int entries, struct dir_context *ctx) struct dir_entry *entry = addr; char *name = (char *)(entry + 1); - ctx->pos = entry->offset; - if (!dir_emit(ctx, name, entry->name_len, entry->ino, - entry->type)) + ctx->pos = get_unaligned(&entry->offset); + if (!dir_emit(ctx, name, get_unaligned(&entry->name_len), + get_unaligned(&entry->ino), + get_unaligned(&entry->type))) return 1; - addr += sizeof(struct dir_entry) + entry->name_len; + addr += sizeof(struct dir_entry) + + get_unaligned(&entry->name_len); ctx->pos++; } return 0; @@ -6078,14 +6081,15 @@ static int btrfs_real_readdir(struct file *file, struct dir_context *ctx) } entry = addr; - entry->name_len = name_len; + put_unaligned(name_len, &entry->name_len); name_ptr = (char *)(entry + 1); read_extent_buffer(leaf, name_ptr, (unsigned long)(di + 1), name_len); - entry->type = btrfs_filetype_table[btrfs_dir_type(leaf, di)]; + put_unaligned(btrfs_filetype_table[btrfs_dir_type(leaf, di)], + &entry->type); btrfs_dir_item_key_to_cpu(leaf, di, &location); - entry->ino = location.objectid; - entry->offset = found_key.offset; + put_unaligned(location.objectid, &entry->ino); + put_unaligned(found_key.offset, &entry->offset); entries++; addr += sizeof(struct dir_entry) + name_len; total_len += sizeof(struct dir_entry) + name_len; -- GitLab From b8d4055372b58aad4a51b67e176eabdcc238fde3 Mon Sep 17 00:00:00 2001 From: Dou Liyang Date: Thu, 12 Apr 2018 09:40:52 +0800 Subject: [PATCH 0868/1635] x86/acpi: Prevent X2APIC id 0xffffffff from being accounted MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 10daf10ab154e31237a8c07242be3063fb6a9bf4 upstream. RongQing reported that there are some X2APIC id 0xffffffff in his machine's ACPI MADT table, which makes the number of possible CPU inaccurate. The reason is that the ACPI X2APIC parser has no sanity check for APIC ID 0xffffffff, which is an invalid id in all APIC types. See "Intel® 64 Architecture x2APIC Specification", Chapter 2.4.1. Add a sanity check to acpi_parse_x2apic() which ignores the invalid id. Reported-by: Li RongQing Signed-off-by: Dou Liyang Signed-off-by: Thomas Gleixner Cc: stable@vger.kernel.org Cc: len.brown@intel.com Cc: rjw@rjwysocki.net Cc: hpa@zytor.com Link: https://lkml.kernel.org/r/20180412014052.25186-1-douly.fnst@cn.fujitsu.com Signed-off-by: Greg Kroah-Hartman --- arch/x86/kernel/acpi/boot.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c index 9c2a002d9297..6dda3595acf8 100644 --- a/arch/x86/kernel/acpi/boot.c +++ b/arch/x86/kernel/acpi/boot.c @@ -215,6 +215,10 @@ acpi_parse_x2apic(struct acpi_subtable_header *header, const unsigned long end) apic_id = processor->local_apic_id; enabled = processor->lapic_flags & ACPI_MADT_ENABLED; + /* Ignore invalid ID */ + if (apic_id == 0xffffffff) + return 0; + /* * We need to register disabled CPU as well to permit * counting disabled CPUs. This allows us to size -- GitLab From c6aaaaa4d62ad885a8ca0a255d4af975f843ee98 Mon Sep 17 00:00:00 2001 From: Anson Huang Date: Thu, 19 Apr 2018 14:04:43 +0800 Subject: [PATCH 0869/1635] clocksource/imx-tpm: Correct -ETIME return condition check commit 7407188489c62a7b5694bc75a6db2b82af94c9a5 upstream. The additional brakects added to tpm_set_next_event's return value computation causes (int) forced type conversion NOT taking effect, and the incorrect value return will cause various system timer issue, like RCU stall etc.. Remove the additional brackets to make sure tpm_set_next_event always returns correct value. Fixes: 059ab7b82eec ("clocksource/drivers/imx-tpm: Add imx tpm timer support") Signed-off-by: Anson Huang Signed-off-by: Thomas Gleixner Acked-by: Dong Aisheng Cc: stable@vger.kernel.org Cc: daniel.lezcano@linaro.org Cc: Linux-imx@nxp.com Link: https://lkml.kernel.org/r/1524117883-2484-1-git-send-email-Anson.Huang@nxp.com Signed-off-by: Greg Kroah-Hartman --- drivers/clocksource/timer-imx-tpm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clocksource/timer-imx-tpm.c b/drivers/clocksource/timer-imx-tpm.c index 21bffdcb2f20..557ed25b42e3 100644 --- a/drivers/clocksource/timer-imx-tpm.c +++ b/drivers/clocksource/timer-imx-tpm.c @@ -105,7 +105,7 @@ static int tpm_set_next_event(unsigned long delta, * of writing CNT registers which may cause the min_delta event got * missed, so we need add a ETIME check here in case it happened. */ - return (int)((next - now) <= 0) ? -ETIME : 0; + return (int)(next - now) <= 0 ? -ETIME : 0; } static int tpm_set_state_oneshot(struct clock_event_device *evt) -- GitLab From 08641a24d4e70607f767b066def49d3b3a3f9c98 Mon Sep 17 00:00:00 2001 From: Xiaoming Gao Date: Fri, 13 Apr 2018 17:48:08 +0800 Subject: [PATCH 0870/1635] x86/tsc: Prevent 32bit truncation in calc_hpet_ref() commit d3878e164dcd3925a237a20e879432400e369172 upstream. The TSC calibration code uses HPET as reference. The conversion normalizes the delta of two HPET timestamps: hpetref = ((tshpet1 - tshpet2) * HPET_PERIOD) / 1e6 and then divides the normalized delta of the corresponding TSC timestamps by the result to calulate the TSC frequency. tscfreq = ((tstsc1 - tstsc2 ) * 1e6) / hpetref This uses do_div() which takes an u32 as the divisor, which worked so far because the HPET frequency was low enough that 'hpetref' never exceeded 32bit. On Skylake machines the HPET frequency increased so 'hpetref' can exceed 32bit. do_div() truncates the divisor, which causes the calibration to fail. Use div64_u64() to avoid the problem. [ tglx: Fixes whitespace mangled patch and rewrote changelog ] Signed-off-by: Xiaoming Gao Signed-off-by: Thomas Gleixner Cc: stable@vger.kernel.org Cc: peterz@infradead.org Cc: hpa@zytor.com Link: https://lkml.kernel.org/r/38894564-4fc9-b8ec-353f-de702839e44e@gmail.com Signed-off-by: Greg Kroah-Hartman --- arch/x86/kernel/tsc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/kernel/tsc.c b/arch/x86/kernel/tsc.c index 47506567435e..183a3a142309 100644 --- a/arch/x86/kernel/tsc.c +++ b/arch/x86/kernel/tsc.c @@ -316,7 +316,7 @@ static unsigned long calc_hpet_ref(u64 deltatsc, u64 hpet1, u64 hpet2) hpet2 -= hpet1; tmp = ((u64)hpet2 * hpet_readl(HPET_PERIOD)); do_div(tmp, 1000000); - do_div(deltatsc, tmp); + deltatsc = div64_u64(deltatsc, tmp); return (unsigned long) deltatsc; } -- GitLab From 325abf3db041d7ca130a5f84024da2ffffa35f0e Mon Sep 17 00:00:00 2001 From: Daniel J Blueman Date: Mon, 2 Apr 2018 15:10:35 +0800 Subject: [PATCH 0871/1635] drm/vc4: Fix memory leak during BO teardown commit c0db1b677e1d584fab5d7ac76a32e1c0157542e0 upstream. During BO teardown, an indirect list 'uniform_addr_offsets' wasn't being freed leading to leaking many 128B allocations. Fix the memory leak by releasing it at teardown time. Cc: stable@vger.kernel.org Fixes: 6d45c81d229d ("drm/vc4: Add support for branching in shader validation.") Signed-off-by: Daniel J Blueman Signed-off-by: Eric Anholt Reviewed-by: Eric Anholt Link: https://patchwork.freedesktop.org/patch/msgid/20180402071035.25356-1-daniel@quora.org Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/vc4/vc4_bo.c | 2 ++ drivers/gpu/drm/vc4/vc4_validate_shaders.c | 1 + 2 files changed, 3 insertions(+) diff --git a/drivers/gpu/drm/vc4/vc4_bo.c b/drivers/gpu/drm/vc4/vc4_bo.c index 3afdbf4bc10b..eff0a8ece8bc 100644 --- a/drivers/gpu/drm/vc4/vc4_bo.c +++ b/drivers/gpu/drm/vc4/vc4_bo.c @@ -173,6 +173,7 @@ static void vc4_bo_destroy(struct vc4_bo *bo) vc4_bo_set_label(obj, -1); if (bo->validated_shader) { + kfree(bo->validated_shader->uniform_addr_offsets); kfree(bo->validated_shader->texture_samples); kfree(bo->validated_shader); bo->validated_shader = NULL; @@ -432,6 +433,7 @@ void vc4_free_object(struct drm_gem_object *gem_bo) } if (bo->validated_shader) { + kfree(bo->validated_shader->uniform_addr_offsets); kfree(bo->validated_shader->texture_samples); kfree(bo->validated_shader); bo->validated_shader = NULL; diff --git a/drivers/gpu/drm/vc4/vc4_validate_shaders.c b/drivers/gpu/drm/vc4/vc4_validate_shaders.c index d3f15bf60900..7cf82b071de2 100644 --- a/drivers/gpu/drm/vc4/vc4_validate_shaders.c +++ b/drivers/gpu/drm/vc4/vc4_validate_shaders.c @@ -942,6 +942,7 @@ vc4_validate_shader(struct drm_gem_cma_object *shader_obj) fail: kfree(validation_state.branch_targets); if (validated_shader) { + kfree(validated_shader->uniform_addr_offsets); kfree(validated_shader->texture_samples); kfree(validated_shader); } -- GitLab From c53f225fd792970c75ce0cb4042a11d04ef06d09 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Wed, 21 Mar 2018 15:08:47 +0100 Subject: [PATCH 0872/1635] drm/i915/gvt: throw error on unhandled vfio ioctls commit 9f591ae60e1be026901398ef99eede91237aa3a1 upstream. On unknown/unhandled ioctls the driver should return an error, so userspace knows it tried to use something unsupported. Cc: stable@vger.kernel.org Signed-off-by: Gerd Hoffmann Reviewed-by: Alex Williamson Signed-off-by: Zhenyu Wang Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/i915/gvt/kvmgt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/gvt/kvmgt.c b/drivers/gpu/drm/i915/gvt/kvmgt.c index 83e88c70272a..9bf4045cd679 100644 --- a/drivers/gpu/drm/i915/gvt/kvmgt.c +++ b/drivers/gpu/drm/i915/gvt/kvmgt.c @@ -1153,7 +1153,7 @@ static long intel_vgpu_ioctl(struct mdev_device *mdev, unsigned int cmd, return 0; } - return 0; + return -ENOTTY; } static ssize_t -- GitLab From 8e0489cf4d098ab4fe1c30941390362fb2843b7c Mon Sep 17 00:00:00 2001 From: Gaurav K Singh Date: Tue, 17 Apr 2018 23:52:18 +0530 Subject: [PATCH 0873/1635] drm/i915/audio: Fix audio detection issue on GLK commit b4615730530be85fc45ab4631c2ad6d8e2d0b97d upstream. On Geminilake, sometimes audio card is not getting detected after reboot. This is a spurious issue happening on Geminilake. HW codec and HD audio controller link was going out of sync for which there was a fix in i915 driver but was not getting invoked for GLK. Extending this fix to GLK as well. Tested by Du,Wenkai on GLK board. Bspec: 21829 v2: Instead of checking GEN9_BC, BXT and GLK macros, use IS_GEN9 macro (Jani N) Cc: # b651bd2a3ae3 ("drm/i915/audio: Fix audio enumeration issue on BXT") Cc: Signed-off-by: Gaurav K Singh Reviewed-by: Abhay Kumar Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/1523989338-29677-1-git-send-email-gaurav.k.singh@intel.com (cherry picked from commit 8221229046e862977ae93ec9d34aa583fbd10397) Signed-off-by: Joonas Lahtinen Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/i915/intel_audio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_audio.c b/drivers/gpu/drm/i915/intel_audio.c index 27743be5b768..9240fa79de7c 100644 --- a/drivers/gpu/drm/i915/intel_audio.c +++ b/drivers/gpu/drm/i915/intel_audio.c @@ -704,7 +704,7 @@ static void i915_audio_component_codec_wake_override(struct device *kdev, struct drm_i915_private *dev_priv = kdev_to_i915(kdev); u32 tmp; - if (!IS_GEN9_BC(dev_priv)) + if (!IS_GEN9(dev_priv)) return; i915_audio_component_get_power(kdev); -- GitLab From 6312eff3c70ed43bc0d4a86a042772e4921d649d Mon Sep 17 00:00:00 2001 From: Xidong Wang Date: Wed, 4 Apr 2018 10:38:24 +0100 Subject: [PATCH 0874/1635] drm/i915: Do no use kfree() to free a kmem_cache_alloc() return value commit fcf1fadf4c65eea6c519c773d2d9901e8ad94f5f upstream. Along the eb_lookup_vmas() error path, the return value from kmem_cache_alloc() was freed using kfree(). Fix it to use the proper kmem_cache_free() instead. Fixes: d1b48c1e7184 ("drm/i915: Replace execbuf vma ht with an idr") Signed-off-by: Xidong Wang Cc: Chris Wilson Cc: Tvrtko Ursulin Cc: # v4.14+ Reviewed-by: Chris Wilson Signed-off-by: Chris Wilson Link: https://patchwork.freedesktop.org/patch/msgid/20180404093824.9313-1-chris@chris-wilson.co.uk (cherry picked from commit 6be1187dbffa0027ea379c53f7ca0c782515c610) Signed-off-by: Joonas Lahtinen Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/i915/i915_gem_execbuffer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index de8ca5f1dd2e..4cc9ce4b5b16 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -722,7 +722,7 @@ static int eb_lookup_vmas(struct i915_execbuffer *eb) err = radix_tree_insert(handles_vma, handle, vma); if (unlikely(err)) { - kfree(lut); + kmem_cache_free(eb->i915->luts, lut); goto err_obj; } -- GitLab From 5c825627d4e5dd1989b44b7c27feba8061084096 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Mon, 16 Apr 2018 18:53:09 +0300 Subject: [PATCH 0875/1635] drm/i915: Fix LSPCON TMDS output buffer enabling from low-power state MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 7eb2c4dd54ff841f2fe509a84973eb25fa20bda2 upstream. LSPCON adapters in low-power state may ignore the first I2C write during TMDS output buffer enabling, resulting in a blank screen even with an otherwise enabled pipe. Fix this by reading back and validating the written value a few times. The problem was noticed on GLK machines with an onboard LSPCON adapter after entering/exiting DC5 power state. Doing an I2C read of the adapter ID as the first transaction - instead of the I2C write to enable the TMDS buffers - returns the correct value. Based on this we assume that the transaction itself is sent properly, it's only the adapter that is not ready for some reason to accept this first write after waking from low-power state. In my case the second I2C write attempt always succeeded. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=105854 Cc: Clinton Taylor Cc: Ville Syrjälä Cc: stable@vger.kernel.org Signed-off-by: Imre Deak Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/20180416155309.11100-1-imre.deak@intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/drm_dp_dual_mode_helper.c | 39 +++++++++++++++++++---- 1 file changed, 32 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/drm_dp_dual_mode_helper.c b/drivers/gpu/drm/drm_dp_dual_mode_helper.c index 02a50929af67..e7f4fe2848a5 100644 --- a/drivers/gpu/drm/drm_dp_dual_mode_helper.c +++ b/drivers/gpu/drm/drm_dp_dual_mode_helper.c @@ -350,19 +350,44 @@ int drm_dp_dual_mode_set_tmds_output(enum drm_dp_dual_mode_type type, { uint8_t tmds_oen = enable ? 0 : DP_DUAL_MODE_TMDS_DISABLE; ssize_t ret; + int retry; if (type < DRM_DP_DUAL_MODE_TYPE2_DVI) return 0; - ret = drm_dp_dual_mode_write(adapter, DP_DUAL_MODE_TMDS_OEN, - &tmds_oen, sizeof(tmds_oen)); - if (ret) { - DRM_DEBUG_KMS("Failed to %s TMDS output buffers\n", - enable ? "enable" : "disable"); - return ret; + /* + * LSPCON adapters in low-power state may ignore the first write, so + * read back and verify the written value a few times. + */ + for (retry = 0; retry < 3; retry++) { + uint8_t tmp; + + ret = drm_dp_dual_mode_write(adapter, DP_DUAL_MODE_TMDS_OEN, + &tmds_oen, sizeof(tmds_oen)); + if (ret) { + DRM_DEBUG_KMS("Failed to %s TMDS output buffers (%d attempts)\n", + enable ? "enable" : "disable", + retry + 1); + return ret; + } + + ret = drm_dp_dual_mode_read(adapter, DP_DUAL_MODE_TMDS_OEN, + &tmp, sizeof(tmp)); + if (ret) { + DRM_DEBUG_KMS("I2C read failed during TMDS output buffer %s (%d attempts)\n", + enable ? "enabling" : "disabling", + retry + 1); + return ret; + } + + if (tmp == tmds_oen) + return 0; } - return 0; + DRM_DEBUG_KMS("I2C write value mismatch during TMDS output buffer %s\n", + enable ? "enabling" : "disabling"); + + return -EIO; } EXPORT_SYMBOL(drm_dp_dual_mode_set_tmds_output); -- GitLab From 829239740c129fe9aaf276843fd546bdd45f114e Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Tue, 30 Jan 2018 16:29:38 +0200 Subject: [PATCH 0876/1635] drm/i915/bxt, glk: Increase PCODE timeouts during CDCLK freq changing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 5e1df40f40ee45a97bb1066c3d71f0ae920a9672 upstream. Currently we see sporadic timeouts during CDCLK changing both on BXT and GLK as reported by the Bugzilla: ticket. It's easy to reproduce this by changing the frequency in a tight loop after blanking the display. The upper bound for the completion time is 800us based on my tests, so increase it from the current 500us to 2ms; with that I couldn't trigger the problem either on BXT or GLK. Note that timeouts happened during both the change notification and the voltage level setting PCODE request. (For the latter one BSpec doesn't require us to wait for completion before further HW programming.) This issue is similar to commit 2c7d0602c815 ("drm/i915/gen9: Fix PCODE polling during CDCLK change notification") but there the PCODE request does complete (as shown by the mbox busy flag), only the reply we get from PCODE indicates a failure. So there we keep resending the request until a success reply, here we just have to increase the timeout for the one PCODE request we send. v2: - s/snb_pcode_request/sandybridge_pcode_write_timeout/ (Ville) Cc: Chris Wilson Cc: Ville Syrjälä Cc: # v4.4+ Acked-by: Chris Wilson (v1) Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=103326 Reviewed-by: Ville Syrjälä Signed-off-by: Imre Deak Link: https://patchwork.freedesktop.org/patch/msgid/20180130142939.17983-1-imre.deak@intel.com (cherry picked from commit e76019a81921e87a4d9e7b3d86102bc708a6c227) Signed-off-by: Rodrigo Vivi (Rebased for v4.14 stable tree due to upstream cdclk_state and pcu_lock change) Signed-off-by: Imre Deak Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/i915/i915_drv.h | 6 +++++- drivers/gpu/drm/i915/intel_cdclk.c | 22 +++++++++++++++++----- drivers/gpu/drm/i915/intel_pm.c | 6 +++--- 3 files changed, 25 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 3f818412765c..51411894d2cd 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -3995,7 +3995,11 @@ extern void intel_display_print_error_state(struct drm_i915_error_state_buf *e, struct intel_display_error_state *error); int sandybridge_pcode_read(struct drm_i915_private *dev_priv, u32 mbox, u32 *val); -int sandybridge_pcode_write(struct drm_i915_private *dev_priv, u32 mbox, u32 val); +int sandybridge_pcode_write_timeout(struct drm_i915_private *dev_priv, u32 mbox, + u32 val, int timeout_us); +#define sandybridge_pcode_write(dev_priv, mbox, val) \ + sandybridge_pcode_write_timeout(dev_priv, mbox, val, 500) + int skl_pcode_request(struct drm_i915_private *dev_priv, u32 mbox, u32 request, u32 reply_mask, u32 reply, int timeout_base_ms); diff --git a/drivers/gpu/drm/i915/intel_cdclk.c b/drivers/gpu/drm/i915/intel_cdclk.c index 26a8dcd2c549..47ad24229c78 100644 --- a/drivers/gpu/drm/i915/intel_cdclk.c +++ b/drivers/gpu/drm/i915/intel_cdclk.c @@ -1289,10 +1289,15 @@ static void bxt_set_cdclk(struct drm_i915_private *dev_priv, break; } - /* Inform power controller of upcoming frequency change */ mutex_lock(&dev_priv->rps.hw_lock); - ret = sandybridge_pcode_write(dev_priv, HSW_PCODE_DE_WRITE_FREQ_REQ, - 0x80000000); + /* + * Inform power controller of upcoming frequency change. BSpec + * requires us to wait up to 150usec, but that leads to timeouts; + * the 2ms used here is based on experiment. + */ + ret = sandybridge_pcode_write_timeout(dev_priv, + HSW_PCODE_DE_WRITE_FREQ_REQ, + 0x80000000, 2000); mutex_unlock(&dev_priv->rps.hw_lock); if (ret) { @@ -1323,8 +1328,15 @@ static void bxt_set_cdclk(struct drm_i915_private *dev_priv, I915_WRITE(CDCLK_CTL, val); mutex_lock(&dev_priv->rps.hw_lock); - ret = sandybridge_pcode_write(dev_priv, HSW_PCODE_DE_WRITE_FREQ_REQ, - DIV_ROUND_UP(cdclk, 25000)); + /* + * The timeout isn't specified, the 2ms used here is based on + * experiment. + * FIXME: Waiting for the request completion could be delayed until + * the next PCODE request based on BSpec. + */ + ret = sandybridge_pcode_write_timeout(dev_priv, + HSW_PCODE_DE_WRITE_FREQ_REQ, + DIV_ROUND_UP(cdclk, 25000), 2000); mutex_unlock(&dev_priv->rps.hw_lock); if (ret) { diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 014e5c08571a..87cccb5f8c5d 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -8941,8 +8941,8 @@ int sandybridge_pcode_read(struct drm_i915_private *dev_priv, u32 mbox, u32 *val return 0; } -int sandybridge_pcode_write(struct drm_i915_private *dev_priv, - u32 mbox, u32 val) +int sandybridge_pcode_write_timeout(struct drm_i915_private *dev_priv, + u32 mbox, u32 val, int timeout_us) { int status; @@ -8965,7 +8965,7 @@ int sandybridge_pcode_write(struct drm_i915_private *dev_priv, if (__intel_wait_for_register_fw(dev_priv, GEN6_PCODE_MAILBOX, GEN6_PCODE_READY, 0, - 500, 0, NULL)) { + timeout_us, 0, NULL)) { DRM_ERROR("timeout waiting for pcode write of 0x%08x to mbox %x to finish for %ps\n", val, mbox, __builtin_return_address(0)); return -ETIMEDOUT; -- GitLab From 43de32cdf0f4f73519e2df12fb93adc24f9746cb Mon Sep 17 00:00:00 2001 From: Andreas Kemnade Date: Tue, 20 Feb 2018 07:30:10 -0600 Subject: [PATCH 0877/1635] usb: musb: fix enumeration after resume commit 17539f2f4f0b7fa906b508765c8ada07a1e45f52 upstream. On dm3730 there are enumeration problems after resume. Investigation led to the cause that the MUSB_POWER_SOFTCONN bit is not set. If it was set before suspend (because it was enabled via musb_pullup()), it is set in musb_restore_context() so the pullup is enabled. But then musb_start() is called which overwrites MUSB_POWER and therefore disables MUSB_POWER_SOFTCONN, so no pullup is enabled and the device is not enumerated. So let's do a subset of what musb_start() does in the same way as musb_suspend() does it. Platform-specific stuff it still called as there might be some phy-related stuff which needs to be enabled. Also interrupts are enabled, as it was the original idea of calling musb_start() in musb_resume() according to Commit 6fc6f4b87cb3 ("usb: musb: Disable interrupts on suspend, enable them on resume") Signed-off-by: Andreas Kemnade Tested-by: Tony Lindgren Signed-off-by: Bin Liu Signed-off-by: Greg Kroah-Hartman --- drivers/usb/musb/musb_core.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c index ff5a1a8989d5..4f0d937bf0e5 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c @@ -2733,7 +2733,8 @@ static int musb_resume(struct device *dev) if ((devctl & mask) != (musb->context.devctl & mask)) musb->port1_status = 0; - musb_start(musb); + musb_enable_interrupts(musb); + musb_platform_enable(musb); spin_lock_irqsave(&musb->lock, flags); error = musb_run_resume_work(musb); -- GitLab From de4c4914cce296b8dd9f5381f5d5dad70a065ba0 Mon Sep 17 00:00:00 2001 From: Merlijn Wajer Date: Mon, 5 Mar 2018 11:35:10 -0600 Subject: [PATCH 0878/1635] usb: musb: call pm_runtime_{get,put}_sync before reading vbus registers commit df6b074dbe248d8c43a82131e8fd429e401841a5 upstream. Without pm_runtime_{get,put}_sync calls in place, reading vbus status via /sys causes the following error: Unhandled fault: external abort on non-linefetch (0x1028) at 0xfa0ab060 pgd = b333e822 [fa0ab060] *pgd=48011452(bad) [] (musb_default_readb) from [] (musb_vbus_show+0x58/0xe4) [] (musb_vbus_show) from [] (dev_attr_show+0x20/0x44) [] (dev_attr_show) from [] (sysfs_kf_seq_show+0x80/0xdc) [] (sysfs_kf_seq_show) from [] (seq_read+0x250/0x448) [] (seq_read) from [] (__vfs_read+0x1c/0x118) [] (__vfs_read) from [] (vfs_read+0x90/0x144) [] (vfs_read) from [] (SyS_read+0x3c/0x74) [] (SyS_read) from [] (ret_fast_syscall+0x0/0x54) Solution was suggested by Tony Lindgren . Signed-off-by: Merlijn Wajer Acked-by: Tony Lindgren Signed-off-by: Bin Liu Signed-off-by: Greg Kroah-Hartman --- drivers/usb/musb/musb_core.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c index 4f0d937bf0e5..7af7cdf1c812 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c @@ -1780,6 +1780,7 @@ musb_vbus_show(struct device *dev, struct device_attribute *attr, char *buf) int vbus; u8 devctl; + pm_runtime_get_sync(dev); spin_lock_irqsave(&musb->lock, flags); val = musb->a_wait_bcon; vbus = musb_platform_get_vbus_status(musb); @@ -1793,6 +1794,7 @@ musb_vbus_show(struct device *dev, struct device_attribute *attr, char *buf) vbus = 0; } spin_unlock_irqrestore(&musb->lock, flags); + pm_runtime_put_sync(dev); return sprintf(buf, "Vbus %s, timeout %lu msec\n", vbus ? "on" : "off", val); -- GitLab From 1f52b0c642157bafda295c16a4650b4f0c26f4d1 Mon Sep 17 00:00:00 2001 From: Merlijn Wajer Date: Tue, 13 Mar 2018 09:48:40 -0500 Subject: [PATCH 0879/1635] usb: musb: Fix external abort in musb_remove on omap2430 commit 94e46a4f2d5eb14059e42f313c098d4854847376 upstream. This fixes an oops on unbind / module unload (on the musb omap2430 platform). musb_remove function now calls musb_platform_exit before disabling runtime pm. Signed-off-by: Merlijn Wajer Signed-off-by: Bin Liu Signed-off-by: Greg Kroah-Hartman --- drivers/usb/musb/musb_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c index 7af7cdf1c812..ff17e94ef465 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c @@ -2498,11 +2498,11 @@ static int musb_remove(struct platform_device *pdev) musb_disable_interrupts(musb); musb_writeb(musb->mregs, MUSB_DEVCTL, 0); spin_unlock_irqrestore(&musb->lock, flags); + musb_platform_exit(musb); pm_runtime_dont_use_autosuspend(musb->controller); pm_runtime_put_sync(musb->controller); pm_runtime_disable(musb->controller); - musb_platform_exit(musb); musb_phy_callback = NULL; if (musb->dma_controller) musb_dma_controller_destroy(musb->dma_controller); -- GitLab From 4a5d70332d57bd473ffe76d8777a2e9f847c7863 Mon Sep 17 00:00:00 2001 From: Hector Martin Date: Fri, 3 Nov 2017 20:28:57 +0900 Subject: [PATCH 0880/1635] firewire-ohci: work around oversized DMA reads on JMicron controllers [ Upstream commit 188775181bc05f29372b305ef96485840e351fde ] At least some JMicron controllers issue buggy oversized DMA reads when fetching context descriptors, always fetching 0x20 bytes at once for descriptors which are only 0x10 bytes long. This is often harmless, but can cause page faults on modern systems with IOMMUs: DMAR: [DMA Read] Request device [05:00.0] fault addr fff56000 [fault reason 06] PTE Read access is not set firewire_ohci 0000:05:00.0: DMA context IT0 has stopped, error code: evt_descriptor_read This works around the problem by always leaving 0x10 padding bytes at the end of descriptor buffer pages, which should be harmless to do unconditionally for controllers in case others have the same behavior. Signed-off-by: Hector Martin Reviewed-by: Clemens Ladisch Signed-off-by: Stefan Richter Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/firewire/ohci.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c index 8bf89267dc25..d731b413cb2c 100644 --- a/drivers/firewire/ohci.c +++ b/drivers/firewire/ohci.c @@ -1130,7 +1130,13 @@ static int context_add_buffer(struct context *ctx) return -ENOMEM; offset = (void *)&desc->buffer - (void *)desc; - desc->buffer_size = PAGE_SIZE - offset; + /* + * Some controllers, like JMicron ones, always issue 0x20-byte DMA reads + * for descriptors, even 0x10-byte ones. This can cause page faults when + * an IOMMU is in use and the oversized read crosses a page boundary. + * Work around this by always leaving at least 0x10 bytes of padding. + */ + desc->buffer_size = PAGE_SIZE - offset - 0x10; desc->buffer_bus = bus_addr + offset; desc->used = 0; -- GitLab From 239c948e3266adba944da4ea257362e773f39823 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Fri, 22 Dec 2017 10:20:11 +0100 Subject: [PATCH 0881/1635] x86/tsc: Allow TSC calibration without PIT [ Upstream commit 30c7e5b123673d5e570e238dbada2fb68a87212c ] Zhang Rui reported that a Surface Pro 4 will fail to boot with lapic=notscdeadline. Part of the problem is that that machine doesn't have a PIT. If, for some reason, the TSC init has to fall back to TSC calibration, it relies on the PIT to be present. Allow TSC calibration to reliably fall back to HPET. The below results in an accurate TSC measurement when forced on a IVB: tsc: Unable to calibrate against PIT tsc: No reference (HPET/PMTIMER) available tsc: Unable to calibrate against PIT tsc: using HPET reference calibration tsc: Detected 2792.451 MHz processor Signed-off-by: Peter Zijlstra (Intel) Signed-off-by: Thomas Gleixner Cc: len.brown@intel.com Cc: rui.zhang@intel.com Link: https://lkml.kernel.org/r/20171222092243.333145937@infradead.org Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/x86/include/asm/i8259.h | 5 +++++ arch/x86/kernel/tsc.c | 18 ++++++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/arch/x86/include/asm/i8259.h b/arch/x86/include/asm/i8259.h index c8376b40e882..5cdcdbd4d892 100644 --- a/arch/x86/include/asm/i8259.h +++ b/arch/x86/include/asm/i8259.h @@ -69,6 +69,11 @@ struct legacy_pic { extern struct legacy_pic *legacy_pic; extern struct legacy_pic null_legacy_pic; +static inline bool has_legacy_pic(void) +{ + return legacy_pic != &null_legacy_pic; +} + static inline int nr_legacy_irqs(void) { return legacy_pic->nr_legacy_irqs; diff --git a/arch/x86/kernel/tsc.c b/arch/x86/kernel/tsc.c index 183a3a142309..0bf06fa3027e 100644 --- a/arch/x86/kernel/tsc.c +++ b/arch/x86/kernel/tsc.c @@ -25,6 +25,7 @@ #include #include #include +#include unsigned int __read_mostly cpu_khz; /* TSC clocks / usec, not used here */ EXPORT_SYMBOL(cpu_khz); @@ -363,6 +364,20 @@ static unsigned long pit_calibrate_tsc(u32 latch, unsigned long ms, int loopmin) unsigned long tscmin, tscmax; int pitcnt; + if (!has_legacy_pic()) { + /* + * Relies on tsc_early_delay_calibrate() to have given us semi + * usable udelay(), wait for the same 50ms we would have with + * the PIT loop below. + */ + udelay(10 * USEC_PER_MSEC); + udelay(10 * USEC_PER_MSEC); + udelay(10 * USEC_PER_MSEC); + udelay(10 * USEC_PER_MSEC); + udelay(10 * USEC_PER_MSEC); + return ULONG_MAX; + } + /* Set the Gate high, disable speaker */ outb((inb(0x61) & ~0x02) | 0x01, 0x61); @@ -487,6 +502,9 @@ static unsigned long quick_pit_calibrate(void) u64 tsc, delta; unsigned long d1, d2; + if (!has_legacy_pic()) + return 0; + /* Set the Gate high, disable speaker */ outb((inb(0x61) & ~0x02) | 0x01, 0x61); -- GitLab From 7a420b5d95a5428887dbcbd338ddb36fdbdc9233 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Wed, 13 Dec 2017 09:57:09 +1100 Subject: [PATCH 0882/1635] NFSv4: always set NFS_LOCK_LOST when a lock is lost. [ Upstream commit dce2630c7da73b0634686bca557cc8945cc450c8 ] There are 2 comments in the NFSv4 code which suggest that SIGLOST should possibly be sent to a process. In these cases a lock has been lost. The current practice is to set NFS_LOCK_LOST so that read/write returns EIO when a lock is lost. So change these comments to code when sets NFS_LOCK_LOST. One case is when lock recovery after apparent server restart fails with NFS4ERR_DENIED, NFS4ERR_RECLAIM_BAD, or NFS4ERRO_RECLAIM_CONFLICT. The other case is when a lock attempt as part of lease recovery fails with NFS4ERR_DENIED. In an ideal world, these should not happen. However I have a packet trace showing an NFSv4.1 session getting NFS4ERR_BADSESSION after an extended network parition. The NFSv4.1 client treats this like server reboot until/unless it get NFS4ERR_NO_GRACE, in which case it switches over to "nograce" recovery mode. In this network trace, the client attempts to recover a lock and the server (incorrectly) reports NFS4ERR_DENIED rather than NFS4ERR_NO_GRACE. This leads to the ineffective comment and the client then continues to write using the OPEN stateid. Signed-off-by: NeilBrown Signed-off-by: Trond Myklebust Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- fs/nfs/nfs4proc.c | 12 ++++++++---- fs/nfs/nfs4state.c | 5 ++++- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 2241d52710f7..ae8f43d270d6 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -1885,7 +1885,7 @@ static int nfs4_open_reclaim(struct nfs4_state_owner *sp, struct nfs4_state *sta return ret; } -static int nfs4_handle_delegation_recall_error(struct nfs_server *server, struct nfs4_state *state, const nfs4_stateid *stateid, int err) +static int nfs4_handle_delegation_recall_error(struct nfs_server *server, struct nfs4_state *state, const nfs4_stateid *stateid, struct file_lock *fl, int err) { switch (err) { default: @@ -1932,7 +1932,11 @@ static int nfs4_handle_delegation_recall_error(struct nfs_server *server, struct return -EAGAIN; case -ENOMEM: case -NFS4ERR_DENIED: - /* kill_proc(fl->fl_pid, SIGLOST, 1); */ + if (fl) { + struct nfs4_lock_state *lsp = fl->fl_u.nfs4_fl.owner; + if (lsp) + set_bit(NFS_LOCK_LOST, &lsp->ls_flags); + } return 0; } return err; @@ -1968,7 +1972,7 @@ int nfs4_open_delegation_recall(struct nfs_open_context *ctx, err = nfs4_open_recover_helper(opendata, FMODE_READ); } nfs4_opendata_put(opendata); - return nfs4_handle_delegation_recall_error(server, state, stateid, err); + return nfs4_handle_delegation_recall_error(server, state, stateid, NULL, err); } static void nfs4_open_confirm_prepare(struct rpc_task *task, void *calldata) @@ -6595,7 +6599,7 @@ int nfs4_lock_delegation_recall(struct file_lock *fl, struct nfs4_state *state, if (err != 0) return err; err = _nfs4_do_setlk(state, F_SETLK, fl, NFS_LOCK_NEW); - return nfs4_handle_delegation_recall_error(server, state, stateid, err); + return nfs4_handle_delegation_recall_error(server, state, stateid, fl, err); } struct nfs_release_lockowner_data { diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index 0378e2257ca7..45873ed92057 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c @@ -1447,6 +1447,7 @@ static int nfs4_reclaim_locks(struct nfs4_state *state, const struct nfs4_state_ struct inode *inode = state->inode; struct nfs_inode *nfsi = NFS_I(inode); struct file_lock *fl; + struct nfs4_lock_state *lsp; int status = 0; struct file_lock_context *flctx = inode->i_flctx; struct list_head *list; @@ -1487,7 +1488,9 @@ static int nfs4_reclaim_locks(struct nfs4_state *state, const struct nfs4_state_ case -NFS4ERR_DENIED: case -NFS4ERR_RECLAIM_BAD: case -NFS4ERR_RECLAIM_CONFLICT: - /* kill_proc(fl->fl_pid, SIGLOST, 1); */ + lsp = fl->fl_u.nfs4_fl.owner; + if (lsp) + set_bit(NFS_LOCK_LOST, &lsp->ls_flags); status = 0; } spin_lock(&flctx->flc_lock); -- GitLab From 4e7284b34c78a11f04452621b3eb41e1bdb83bff Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 14 Jan 2018 21:01:48 +0100 Subject: [PATCH 0883/1635] ACPI / LPSS: Do not instiate platform_dev for devs without MMIO resources [ Upstream commit e1681599345b8466786b6e54a2db2a00a068a3f3 ] acpi_lpss_create_device() skips handling LPSS devices which do not have a mmio resources in their resource list (typically these devices are disabled by the firmware). But since the LPSS code does not bind to the device, acpi_bus_attach() ends up still creating a platform device for it and the regular platform_driver for the ACPI HID still tries to bind to it. This happens e.g. on some boards which do not use the pwm-controller and have an empty or invalid resource-table for it. Currently this causes these error messages to get logged: [ 3.281966] pwm-lpss 80862288:00: invalid resource [ 3.287098] pwm-lpss: probe of 80862288:00 failed with error -22 This commit stops the undesirable creation of a platform_device for disabled LPSS devices by setting pnp.type.platform_id to 0. Note that acpi_scan_attach_handler() also sets pnp.type.platform_id to 0 when there is a matching handler for the device and that handler has no attach callback, so we simply behave as a handler without an attach function in this case. Signed-off-by: Hans de Goede Acked-by: Mika Westerberg Reviewed-by: Andy Shevchenko Signed-off-by: Rafael J. Wysocki Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/acpi/acpi_lpss.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/acpi/acpi_lpss.c b/drivers/acpi/acpi_lpss.c index 032ae44710e5..a2be3fd2c72b 100644 --- a/drivers/acpi/acpi_lpss.c +++ b/drivers/acpi/acpi_lpss.c @@ -465,6 +465,8 @@ static int acpi_lpss_create_device(struct acpi_device *adev, acpi_dev_free_resource_list(&resource_list); if (!pdata->mmio_base) { + /* Avoid acpi_bus_attach() instantiating a pdev for this dev. */ + adev->pnp.type.platform_id = 0; /* Skip the device, but continue the namespace scan. */ ret = 0; goto err_out; -- GitLab From d3222cfc0b58f022a17f5f936b5c5d2df8a3f868 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 15 Jan 2018 10:44:35 +0100 Subject: [PATCH 0884/1635] ALSA: hda - Use IS_REACHABLE() for dependency on input [ Upstream commit c469652bb5e8fb715db7d152f46d33b3740c9b87 ] The commit ffcd28d88e4f ("ALSA: hda - Select INPUT for Realtek HD-audio codec") introduced the reverse-selection of CONFIG_INPUT for Realtek codec in order to avoid the mess with dependency between built-in and modules. Later on, we obtained IS_REACHABLE() macro exactly for this kind of problems, and now we can remove th INPUT selection in Kconfig and put IS_REACHABLE(INPUT) to the appropriate places in the code, so that the driver doesn't need to select other subsystem forcibly. Fixes: ffcd28d88e4f ("ALSA: hda - Select INPUT for Realtek HD-audio codec") Reported-by: Randy Dunlap Acked-by: Randy Dunlap # and build-tested Signed-off-by: Takashi Iwai Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- sound/pci/hda/Kconfig | 1 - sound/pci/hda/patch_realtek.c | 5 +++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/sound/pci/hda/Kconfig b/sound/pci/hda/Kconfig index 7f3b5ed81995..f7a492c382d9 100644 --- a/sound/pci/hda/Kconfig +++ b/sound/pci/hda/Kconfig @@ -88,7 +88,6 @@ config SND_HDA_PATCH_LOADER config SND_HDA_CODEC_REALTEK tristate "Build Realtek HD-audio codec support" select SND_HDA_GENERIC - select INPUT help Say Y or M here to include Realtek HD-audio codec support in snd-hda-intel driver, such as ALC880. diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index b1b28c6928a7..590887d9b7a1 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -3721,6 +3721,7 @@ static void alc280_fixup_hp_gpio4(struct hda_codec *codec, } } +#if IS_REACHABLE(INPUT) static void gpio2_mic_hotkey_event(struct hda_codec *codec, struct hda_jack_callback *event) { @@ -3853,6 +3854,10 @@ static void alc233_fixup_lenovo_line2_mic_hotkey(struct hda_codec *codec, spec->kb_dev = NULL; } } +#else /* INPUT */ +#define alc280_fixup_hp_gpio2_mic_hotkey NULL +#define alc233_fixup_lenovo_line2_mic_hotkey NULL +#endif /* INPUT */ static void alc269_fixup_hp_line1_mic1_led(struct hda_codec *codec, const struct hda_fixup *fix, int action) -- GitLab From 3f3017fa1540cf5eb6bd6af1f76f76a831c99652 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Mon, 15 Jan 2018 11:08:38 +0300 Subject: [PATCH 0885/1635] ASoC: au1x: Fix timeout tests in au1xac97c_ac97_read() [ Upstream commit 123af9043e93cb6f235207d260d50f832cdb5439 ] The loop timeout doesn't work because it's a post op and ends with "tmo" set to -1. I changed it from a post-op to a pre-op and I changed the initial the starting value from 5 to 6 so we still iterate 5 times. I left the other as it was because it's a large number. Fixes: b3c70c9ea62a ("ASoC: Alchemy AC97C/I2SC audio support") Signed-off-by: Dan Carpenter Signed-off-by: Mark Brown Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- sound/soc/au1x/ac97c.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/soc/au1x/ac97c.c b/sound/soc/au1x/ac97c.c index 29a97d52e8ad..66d6c52e7761 100644 --- a/sound/soc/au1x/ac97c.c +++ b/sound/soc/au1x/ac97c.c @@ -91,8 +91,8 @@ static unsigned short au1xac97c_ac97_read(struct snd_ac97 *ac97, do { mutex_lock(&ctx->lock); - tmo = 5; - while ((RD(ctx, AC97_STATUS) & STAT_CP) && tmo--) + tmo = 6; + while ((RD(ctx, AC97_STATUS) & STAT_CP) && --tmo) udelay(21); /* wait an ac97 frame time */ if (!tmo) { pr_debug("ac97rd timeout #1\n"); @@ -105,7 +105,7 @@ static unsigned short au1xac97c_ac97_read(struct snd_ac97 *ac97, * poll, Forrest, poll... */ tmo = 0x10000; - while ((RD(ctx, AC97_STATUS) & STAT_CP) && tmo--) + while ((RD(ctx, AC97_STATUS) & STAT_CP) && --tmo) asm volatile ("nop"); data = RD(ctx, AC97_CMDRESP); -- GitLab From 8e40eae185f85426d9d6d667f2e55aa721b84e0d Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 26 Oct 2017 15:45:47 +0200 Subject: [PATCH 0886/1635] kvm: x86: fix KVM_XEN_HVM_CONFIG ioctl MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit 51776043afa415435c7e4636204fbe4f7edc4501 ] This ioctl is obsolete (it was used by Xenner as far as I know) but still let's not break it gratuitously... Its handler is copying directly into struct kvm. Go through a bounce buffer instead, with the added benefit that we can actually do something useful with the flags argument---the previous code was exiting with -EINVAL but still doing the copy. This technically is a userspace ABI breakage, but since no one should be using the ioctl, it's a good occasion to see if someone actually complains. Cc: kernel-hardening@lists.openwall.com Cc: Kees Cook Cc: Radim Krčmář Signed-off-by: Paolo Bonzini Signed-off-by: Kees Cook Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/x86/kvm/x86.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index b9afb4784d12..d7728bcd9a3c 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -4225,13 +4225,14 @@ long kvm_arch_vm_ioctl(struct file *filp, mutex_unlock(&kvm->lock); break; case KVM_XEN_HVM_CONFIG: { + struct kvm_xen_hvm_config xhc; r = -EFAULT; - if (copy_from_user(&kvm->arch.xen_hvm_config, argp, - sizeof(struct kvm_xen_hvm_config))) + if (copy_from_user(&xhc, argp, sizeof(xhc))) goto out; r = -EINVAL; - if (kvm->arch.xen_hvm_config.flags) + if (xhc.flags) goto out; + memcpy(&kvm->arch.xen_hvm_config, &xhc, sizeof(xhc)); r = 0; break; } -- GitLab From b7b27e19e374e12b8bb3d12627242e6c5d69d706 Mon Sep 17 00:00:00 2001 From: Parav Pandit Date: Fri, 12 Jan 2018 07:58:42 +0200 Subject: [PATCH 0887/1635] RDMA/core: Clarify rdma_ah_find_type [ Upstream commit a6532e7139660c103dda181aa5b2c734aa26ed6c ] iWARP does not use rdma_ah_attr_type, and for this reason we do not have a RDMA_AH_ATTR_TYPE_IWARP. rdma_ah_find_type should not even be called on iwarp ports and for clarity it shouldn't have a special test for iWarp. This changes the result from RDMA_AH_ATTR_TYPE_ROCE to RDMA_AH_ATTR_TYPE_IB when wrongly called on an iWarp port. Fixes: 44c58487d51a ("IB/core: Define 'ib' and 'roce' rdma_ah_attr types") Signed-off-by: Parav Pandit Signed-off-by: Leon Romanovsky Signed-off-by: Jason Gunthorpe Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- include/rdma/ib_verbs.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/include/rdma/ib_verbs.h b/include/rdma/ib_verbs.h index 6533aa64f009..a9fae49a1883 100644 --- a/include/rdma/ib_verbs.h +++ b/include/rdma/ib_verbs.h @@ -3766,8 +3766,7 @@ static inline void rdma_ah_set_grh(struct rdma_ah_attr *attr, static inline enum rdma_ah_attr_type rdma_ah_find_type(struct ib_device *dev, u32 port_num) { - if ((rdma_protocol_roce(dev, port_num)) || - (rdma_protocol_iwarp(dev, port_num))) + if (rdma_protocol_roce(dev, port_num)) return RDMA_AH_ATTR_TYPE_ROCE; else if ((rdma_protocol_ib(dev, port_num)) && (rdma_cap_opa_ah(dev, port_num))) -- GitLab From ddf09f2a0896bb29f1574d0ef983f42eb8592346 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Fri, 12 Jan 2018 20:55:20 +1100 Subject: [PATCH 0888/1635] KVM: PPC: Book3S HV: Enable migration of decrementer register [ Upstream commit 5855564c8ab2d9cefca7b2933bd19818eb795e40 ] This adds a register identifier for use with the one_reg interface to allow the decrementer expiry time to be read and written by userspace. The decrementer expiry time is in guest timebase units and is equal to the sum of the decrementer and the guest timebase. (The expiry time is used rather than the decrementer value itself because the expiry time is not constantly changing, though the decrementer value is, while the guest vcpu is not running.) Without this, a guest vcpu migrated to a new host will see its decrementer set to some random value. On POWER8 and earlier, the decrementer is 32 bits wide and counts down at 512MHz, so the guest vcpu will potentially see no decrementer interrupts for up to about 4 seconds, which will lead to a stall. With POWER9, the decrementer is now 56 bits side, so the stall can be much longer (up to 2.23 years) and more noticeable. To help work around the problem in cases where userspace has not been updated to migrate the decrementer expiry time, we now set the default decrementer expiry at vcpu creation time to the current time rather than the maximum possible value. This should mean an immediate decrementer interrupt when a migrated vcpu starts running. In cases where the decrementer is 32 bits wide and more than 4 seconds elapse between the creation of the vcpu and when it first runs, the decrementer would have wrapped around to positive values and there may still be a stall - but this is no worse than the current situation. In the large-decrementer case, we are sure to get an immediate decrementer interrupt (assuming the time from vcpu creation to first run is less than 2.23 years) and we thus avoid a very long stall. Signed-off-by: Paul Mackerras Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- Documentation/virtual/kvm/api.txt | 1 + arch/powerpc/include/uapi/asm/kvm.h | 2 ++ arch/powerpc/kvm/book3s_hv.c | 8 ++++++++ arch/powerpc/kvm/powerpc.c | 2 +- 4 files changed, 12 insertions(+), 1 deletion(-) diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt index e63a35fafef0..0f9089416b4c 100644 --- a/Documentation/virtual/kvm/api.txt +++ b/Documentation/virtual/kvm/api.txt @@ -1837,6 +1837,7 @@ registers, find a list below: PPC | KVM_REG_PPC_DBSR | 32 PPC | KVM_REG_PPC_TIDR | 64 PPC | KVM_REG_PPC_PSSCR | 64 + PPC | KVM_REG_PPC_DEC_EXPIRY | 64 PPC | KVM_REG_PPC_TM_GPR0 | 64 ... PPC | KVM_REG_PPC_TM_GPR31 | 64 diff --git a/arch/powerpc/include/uapi/asm/kvm.h b/arch/powerpc/include/uapi/asm/kvm.h index 61d6049f4c1e..8aaec831053a 100644 --- a/arch/powerpc/include/uapi/asm/kvm.h +++ b/arch/powerpc/include/uapi/asm/kvm.h @@ -607,6 +607,8 @@ struct kvm_ppc_rmmu_info { #define KVM_REG_PPC_TIDR (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xbc) #define KVM_REG_PPC_PSSCR (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xbd) +#define KVM_REG_PPC_DEC_EXPIRY (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xbe) + /* Transactional Memory checkpointed state: * This is all GPRs, all VSX regs and a subset of SPRs */ diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c index f48e3379a18a..e094dc90ff1b 100644 --- a/arch/powerpc/kvm/book3s_hv.c +++ b/arch/powerpc/kvm/book3s_hv.c @@ -1497,6 +1497,10 @@ static int kvmppc_get_one_reg_hv(struct kvm_vcpu *vcpu, u64 id, case KVM_REG_PPC_ARCH_COMPAT: *val = get_reg_val(id, vcpu->arch.vcore->arch_compat); break; + case KVM_REG_PPC_DEC_EXPIRY: + *val = get_reg_val(id, vcpu->arch.dec_expires + + vcpu->arch.vcore->tb_offset); + break; default: r = -EINVAL; break; @@ -1724,6 +1728,10 @@ static int kvmppc_set_one_reg_hv(struct kvm_vcpu *vcpu, u64 id, case KVM_REG_PPC_ARCH_COMPAT: r = kvmppc_set_arch_compat(vcpu, set_reg_val(id, *val)); break; + case KVM_REG_PPC_DEC_EXPIRY: + vcpu->arch.dec_expires = set_reg_val(id, *val) - + vcpu->arch.vcore->tb_offset; + break; default: r = -EINVAL; break; diff --git a/arch/powerpc/kvm/powerpc.c b/arch/powerpc/kvm/powerpc.c index 2b02d51d14d8..ecb45361095b 100644 --- a/arch/powerpc/kvm/powerpc.c +++ b/arch/powerpc/kvm/powerpc.c @@ -758,7 +758,7 @@ int kvm_arch_vcpu_init(struct kvm_vcpu *vcpu) hrtimer_init(&vcpu->arch.dec_timer, CLOCK_REALTIME, HRTIMER_MODE_ABS); vcpu->arch.dec_timer.function = kvmppc_decrementer_wakeup; - vcpu->arch.dec_expires = ~(u64)0; + vcpu->arch.dec_expires = get_tb(); #ifdef CONFIG_KVM_EXIT_TIMING mutex_init(&vcpu->arch.exit_timing_lock); -- GitLab From e0a1cec3db0a2fcf002fc101a15fcede7551c699 Mon Sep 17 00:00:00 2001 From: Subash Abhinov Kasiviswanathan Date: Fri, 12 Jan 2018 17:36:27 -0700 Subject: [PATCH 0889/1635] netfilter: ipv6: nf_defrag: Pass on packets to stack per RFC2460 [ Upstream commit 83f1999caeb14e15df205e80d210699951733287 ] ipv6_defrag pulls network headers before fragment header. In case of an error, the netfilter layer is currently dropping these packets. This results in failure of some IPv6 standards tests which passed on older kernels due to the netfilter framework using cloning. The test case run here is a check for ICMPv6 error message replies when some invalid IPv6 fragments are sent. This specific test case is listed in https://www.ipv6ready.org/docs/Core_Conformance_Latest.pdf in the Extension Header Processing Order section. A packet with unrecognized option Type 11 is sent and the test expects an ICMP error in line with RFC2460 section 4.2 - 11 - discard the packet and, only if the packet's Destination Address was not a multicast address, send an ICMP Parameter Problem, Code 2, message to the packet's Source Address, pointing to the unrecognized Option Type. Since netfilter layer now drops all invalid IPv6 frag packets, we no longer see the ICMP error message and fail the test case. To fix this, save the transport header. If defrag is unable to process the packet due to RFC2460, restore the transport header and allow packet to be processed by stack. There is no change for other packet processing paths. Tested by confirming that stack sends an ICMP error when it receives these packets. Also tested that fragmented ICMP pings succeed. v1->v2: Instead of cloning always, save the transport_header and restore it in case of this specific error. Update the title and commit message accordingly. Signed-off-by: Subash Abhinov Kasiviswanathan Signed-off-by: Pablo Neira Ayuso Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- net/ipv6/netfilter/nf_conntrack_reasm.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/net/ipv6/netfilter/nf_conntrack_reasm.c b/net/ipv6/netfilter/nf_conntrack_reasm.c index b263bf3a19f7..5edfe66a3d7a 100644 --- a/net/ipv6/netfilter/nf_conntrack_reasm.c +++ b/net/ipv6/netfilter/nf_conntrack_reasm.c @@ -230,7 +230,7 @@ static int nf_ct_frag6_queue(struct frag_queue *fq, struct sk_buff *skb, if ((unsigned int)end > IPV6_MAXPLEN) { pr_debug("offset is too large.\n"); - return -1; + return -EINVAL; } ecn = ip6_frag_ecn(ipv6_hdr(skb)); @@ -263,7 +263,7 @@ static int nf_ct_frag6_queue(struct frag_queue *fq, struct sk_buff *skb, * this case. -DaveM */ pr_debug("end of fragment not rounded to 8 bytes.\n"); - return -1; + return -EPROTO; } if (end > fq->q.len) { /* Some bits beyond end -> corruption. */ @@ -357,7 +357,7 @@ static int nf_ct_frag6_queue(struct frag_queue *fq, struct sk_buff *skb, discard_fq: inet_frag_kill(&fq->q, &nf_frags); err: - return -1; + return -EINVAL; } /* @@ -566,6 +566,7 @@ find_prev_fhdr(struct sk_buff *skb, u8 *prevhdrp, int *prevhoff, int *fhoff) int nf_ct_frag6_gather(struct net *net, struct sk_buff *skb, u32 user) { + u16 savethdr = skb->transport_header; struct net_device *dev = skb->dev; int fhoff, nhoff, ret; struct frag_hdr *fhdr; @@ -599,8 +600,12 @@ int nf_ct_frag6_gather(struct net *net, struct sk_buff *skb, u32 user) spin_lock_bh(&fq->q.lock); - if (nf_ct_frag6_queue(fq, skb, fhdr, nhoff) < 0) { - ret = -EINVAL; + ret = nf_ct_frag6_queue(fq, skb, fhdr, nhoff); + if (ret < 0) { + if (ret == -EPROTO) { + skb->transport_header = savethdr; + ret = 0; + } goto out_unlock; } -- GitLab From a5a8ca753c0c4659287416ce282ba357c30098a8 Mon Sep 17 00:00:00 2001 From: Anna-Maria Gleixner Date: Thu, 21 Dec 2017 11:41:37 +0100 Subject: [PATCH 0890/1635] tracing/hrtimer: Fix tracing bugs by taking all clock bases and modes into account [ Upstream commit 91633eed73a3ac37aaece5c8c1f93a18bae616a9 ] So far only CLOCK_MONOTONIC and CLOCK_REALTIME were taken into account as well as HRTIMER_MODE_ABS/REL in the hrtimer_init tracepoint. The query for detecting the ABS or REL timer modes is not valid anymore, it got broken by the introduction of HRTIMER_MODE_PINNED. HRTIMER_MODE_PINNED is not evaluated in the hrtimer_init() call, but for the sake of completeness print all given modes. Signed-off-by: Anna-Maria Gleixner Cc: Christoph Hellwig Cc: John Stultz Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: keescook@chromium.org Link: http://lkml.kernel.org/r/20171221104205.7269-9-anna-maria@linutronix.de Signed-off-by: Ingo Molnar Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- include/trace/events/timer.h | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/include/trace/events/timer.h b/include/trace/events/timer.h index 16e305e69f34..c6f728037c53 100644 --- a/include/trace/events/timer.h +++ b/include/trace/events/timer.h @@ -136,6 +136,20 @@ DEFINE_EVENT(timer_class, timer_cancel, TP_ARGS(timer) ); +#define decode_clockid(type) \ + __print_symbolic(type, \ + { CLOCK_REALTIME, "CLOCK_REALTIME" }, \ + { CLOCK_MONOTONIC, "CLOCK_MONOTONIC" }, \ + { CLOCK_BOOTTIME, "CLOCK_BOOTTIME" }, \ + { CLOCK_TAI, "CLOCK_TAI" }) + +#define decode_hrtimer_mode(mode) \ + __print_symbolic(mode, \ + { HRTIMER_MODE_ABS, "ABS" }, \ + { HRTIMER_MODE_REL, "REL" }, \ + { HRTIMER_MODE_ABS_PINNED, "ABS|PINNED" }, \ + { HRTIMER_MODE_REL_PINNED, "REL|PINNED" }) + /** * hrtimer_init - called when the hrtimer is initialized * @hrtimer: pointer to struct hrtimer @@ -162,10 +176,8 @@ TRACE_EVENT(hrtimer_init, ), TP_printk("hrtimer=%p clockid=%s mode=%s", __entry->hrtimer, - __entry->clockid == CLOCK_REALTIME ? - "CLOCK_REALTIME" : "CLOCK_MONOTONIC", - __entry->mode == HRTIMER_MODE_ABS ? - "HRTIMER_MODE_ABS" : "HRTIMER_MODE_REL") + decode_clockid(__entry->clockid), + decode_hrtimer_mode(__entry->mode)) ); /** -- GitLab From 80bd91ab9ad853d2f4f769b732fb8a501c90ec9d Mon Sep 17 00:00:00 2001 From: Christian Borntraeger Date: Thu, 16 Nov 2017 15:12:52 +0100 Subject: [PATCH 0891/1635] KVM: s390: use created_vcpus in more places [ Upstream commit 241e3ec0faf5ab1a0d9b1f6c43eefa919fb9c112 ] commit a03825bbd0c3 ("KVM: s390: use kvm->created_vcpus") introduced kvm->created_vcpus to avoid races with the existing kvm->online_vcpus scheme. One place was "forgotten" and one new place was "added". Let's fix those. Reported-by: Halil Pasic Signed-off-by: Christian Borntraeger Reviewed-by: Halil Pasic Reviewed-by: Cornelia Huck Reviewed-by: David Hildenbrand Fixes: 4e0b1ab72b8a ("KVM: s390: gs support for kvm guests") Fixes: a03825bbd0c3 ("KVM: s390: use kvm->created_vcpus") Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/s390/kvm/kvm-s390.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c index 0fa3a788dd20..0bce918db11a 100644 --- a/arch/s390/kvm/kvm-s390.c +++ b/arch/s390/kvm/kvm-s390.c @@ -601,7 +601,7 @@ static int kvm_vm_ioctl_enable_cap(struct kvm *kvm, struct kvm_enable_cap *cap) case KVM_CAP_S390_GS: r = -EINVAL; mutex_lock(&kvm->lock); - if (atomic_read(&kvm->online_vcpus)) { + if (kvm->created_vcpus) { r = -EBUSY; } else if (test_facility(133)) { set_kvm_facility(kvm->arch.model.fac_mask, 133); @@ -1121,7 +1121,7 @@ static int kvm_s390_set_processor_feat(struct kvm *kvm, return -EINVAL; mutex_lock(&kvm->lock); - if (!atomic_read(&kvm->online_vcpus)) { + if (!kvm->created_vcpus) { bitmap_copy(kvm->arch.cpu_feat, (unsigned long *) data.feat, KVM_S390_VM_CPU_FEAT_NR_BITS); ret = 0; -- GitLab From 79f2ced39657f6eb539f70664c355183cf21aa79 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Thu, 11 Jan 2018 15:14:39 +0100 Subject: [PATCH 0892/1635] platform/x86: dell-laptop: Filter out spurious keyboard backlight change events MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit 4d6bde512a86c32df3a1f289d2b4cd04b17758d1 ] On some Dell XPS models WMI events of type 0x0000 reporting a keycode of 0xe00c get reported when the brightness of the LCD panel changes. This leads to us reporting false-positive kbd_led change events to userspace which in turn leads to the kbd backlight OSD showing when it should not. We already read the current keyboard backlight brightness value when reporting events because the led_classdev_notify_brightness_hw_changed API requires this. Compare this value to the last known value and filter out duplicate events, fixing this. Note the fixed issue is esp. a problem on XPS models with an ambient light sensor and automatic brightness adjustments turned on, this causes the kbd backlight OSD to show all the time there. BugLink: https://bugzilla.redhat.com/show_bug.cgi?id=1514969 Fixes: 9c656b0799 ("platform/x86: dell-*: Call new led hw_changed API ...") Acked-by: Pali Rohár Signed-off-by: Hans de Goede Signed-off-by: Andy Shevchenko Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/platform/x86/dell-laptop.c | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/drivers/platform/x86/dell-laptop.c b/drivers/platform/x86/dell-laptop.c index 7424e53157b0..dd5043a6a114 100644 --- a/drivers/platform/x86/dell-laptop.c +++ b/drivers/platform/x86/dell-laptop.c @@ -1177,6 +1177,7 @@ static u8 kbd_previous_mode_bit; static bool kbd_led_present; static DEFINE_MUTEX(kbd_led_mutex); +static enum led_brightness kbd_led_level; /* * NOTE: there are three ways to set the keyboard backlight level. @@ -2020,6 +2021,7 @@ static enum led_brightness kbd_led_level_get(struct led_classdev *led_cdev) static int kbd_led_level_set(struct led_classdev *led_cdev, enum led_brightness value) { + enum led_brightness new_value = value; struct kbd_state state; struct kbd_state new_state; u16 num; @@ -2049,6 +2051,9 @@ static int kbd_led_level_set(struct led_classdev *led_cdev, } out: + if (ret == 0) + kbd_led_level = new_value; + mutex_unlock(&kbd_led_mutex); return ret; } @@ -2076,6 +2081,9 @@ static int __init kbd_led_init(struct device *dev) if (kbd_led.max_brightness) kbd_led.max_brightness--; } + + kbd_led_level = kbd_led_level_get(NULL); + ret = led_classdev_register(dev, &kbd_led); if (ret) kbd_led_present = false; @@ -2100,13 +2108,25 @@ static void kbd_led_exit(void) static int dell_laptop_notifier_call(struct notifier_block *nb, unsigned long action, void *data) { + bool changed = false; + enum led_brightness new_kbd_led_level; + switch (action) { case DELL_LAPTOP_KBD_BACKLIGHT_BRIGHTNESS_CHANGED: if (!kbd_led_present) break; - led_classdev_notify_brightness_hw_changed(&kbd_led, - kbd_led_level_get(&kbd_led)); + mutex_lock(&kbd_led_mutex); + new_kbd_led_level = kbd_led_level_get(&kbd_led); + if (kbd_led_level != new_kbd_led_level) { + kbd_led_level = new_kbd_led_level; + changed = true; + } + mutex_unlock(&kbd_led_mutex); + + if (changed) + led_classdev_notify_brightness_hw_changed(&kbd_led, + kbd_led_level); break; } -- GitLab From 342d9092a50184b4b6d1c3f1f6bed06321afa88d Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Thu, 14 Dec 2017 20:56:09 -0500 Subject: [PATCH 0893/1635] xprtrdma: Fix backchannel allocation of extra rpcrdma_reps [ Upstream commit d698c4a02ee02053bbebe051322ff427a2dad56a ] The backchannel code uses rpcrdma_recv_buffer_put to add new reps to the free rep list. This also decrements rb_recv_count, which spoofs the receive overrun logic in rpcrdma_buffer_get_rep. Commit 9b06688bc3b9 ("xprtrdma: Fix additional uses of spin_lock_irqsave(rb_lock)") replaced the original open-coded list_add with a call to rpcrdma_recv_buffer_put(), but then a year later, commit 05c974669ece ("xprtrdma: Fix receive buffer accounting") added rep accounting to rpcrdma_recv_buffer_put. It was an oversight to let the backchannel continue to use this function. The fix this, let's combine the "add to free list" logic with rpcrdma_create_rep. Also, do not allocate RPCRDMA_MAX_BC_REQUESTS rpcrdma_reps in rpcrdma_buffer_create and then allocate additional rpcrdma_reps in rpcrdma_bc_setup_reps. Allocating the extra reps during backchannel set-up is sufficient. Fixes: 05c974669ece ("xprtrdma: Fix receive buffer accounting") Signed-off-by: Chuck Lever Signed-off-by: Anna Schumaker Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- net/sunrpc/xprtrdma/backchannel.c | 12 ++---------- net/sunrpc/xprtrdma/verbs.c | 32 ++++++++++++++++++------------- net/sunrpc/xprtrdma/xprt_rdma.h | 2 +- 3 files changed, 22 insertions(+), 24 deletions(-) diff --git a/net/sunrpc/xprtrdma/backchannel.c b/net/sunrpc/xprtrdma/backchannel.c index 823a781ec89c..25e3602aa41f 100644 --- a/net/sunrpc/xprtrdma/backchannel.c +++ b/net/sunrpc/xprtrdma/backchannel.c @@ -74,21 +74,13 @@ static int rpcrdma_bc_setup_rqst(struct rpcrdma_xprt *r_xprt, static int rpcrdma_bc_setup_reps(struct rpcrdma_xprt *r_xprt, unsigned int count) { - struct rpcrdma_rep *rep; int rc = 0; while (count--) { - rep = rpcrdma_create_rep(r_xprt); - if (IS_ERR(rep)) { - pr_err("RPC: %s: reply buffer alloc failed\n", - __func__); - rc = PTR_ERR(rep); + rc = rpcrdma_create_rep(r_xprt); + if (rc) break; - } - - rpcrdma_recv_buffer_put(rep); } - return rc; } diff --git a/net/sunrpc/xprtrdma/verbs.c b/net/sunrpc/xprtrdma/verbs.c index 9e8e1de19b2e..97b9d4f671ac 100644 --- a/net/sunrpc/xprtrdma/verbs.c +++ b/net/sunrpc/xprtrdma/verbs.c @@ -951,10 +951,17 @@ rpcrdma_create_req(struct rpcrdma_xprt *r_xprt) return req; } -struct rpcrdma_rep * +/** + * rpcrdma_create_rep - Allocate an rpcrdma_rep object + * @r_xprt: controlling transport + * + * Returns 0 on success or a negative errno on failure. + */ +int rpcrdma_create_rep(struct rpcrdma_xprt *r_xprt) { struct rpcrdma_create_data_internal *cdata = &r_xprt->rx_data; + struct rpcrdma_buffer *buf = &r_xprt->rx_buf; struct rpcrdma_rep *rep; int rc; @@ -979,12 +986,18 @@ rpcrdma_create_rep(struct rpcrdma_xprt *r_xprt) rep->rr_recv_wr.wr_cqe = &rep->rr_cqe; rep->rr_recv_wr.sg_list = &rep->rr_rdmabuf->rg_iov; rep->rr_recv_wr.num_sge = 1; - return rep; + + spin_lock(&buf->rb_lock); + list_add(&rep->rr_list, &buf->rb_recv_bufs); + spin_unlock(&buf->rb_lock); + return 0; out_free: kfree(rep); out: - return ERR_PTR(rc); + dprintk("RPC: %s: reply buffer %d alloc failed\n", + __func__, rc); + return rc; } int @@ -1027,17 +1040,10 @@ rpcrdma_buffer_create(struct rpcrdma_xprt *r_xprt) } INIT_LIST_HEAD(&buf->rb_recv_bufs); - for (i = 0; i < buf->rb_max_requests + RPCRDMA_MAX_BC_REQUESTS; i++) { - struct rpcrdma_rep *rep; - - rep = rpcrdma_create_rep(r_xprt); - if (IS_ERR(rep)) { - dprintk("RPC: %s: reply buffer %d alloc failed\n", - __func__, i); - rc = PTR_ERR(rep); + for (i = 0; i <= buf->rb_max_requests; i++) { + rc = rpcrdma_create_rep(r_xprt); + if (rc) goto out; - } - list_add(&rep->rr_list, &buf->rb_recv_bufs); } return 0; diff --git a/net/sunrpc/xprtrdma/xprt_rdma.h b/net/sunrpc/xprtrdma/xprt_rdma.h index e26a97d2f922..fcb0b3227ee1 100644 --- a/net/sunrpc/xprtrdma/xprt_rdma.h +++ b/net/sunrpc/xprtrdma/xprt_rdma.h @@ -550,8 +550,8 @@ int rpcrdma_ep_post_recv(struct rpcrdma_ia *, struct rpcrdma_rep *); * Buffer calls - xprtrdma/verbs.c */ struct rpcrdma_req *rpcrdma_create_req(struct rpcrdma_xprt *); -struct rpcrdma_rep *rpcrdma_create_rep(struct rpcrdma_xprt *); void rpcrdma_destroy_req(struct rpcrdma_req *); +int rpcrdma_create_rep(struct rpcrdma_xprt *r_xprt); int rpcrdma_buffer_create(struct rpcrdma_xprt *); void rpcrdma_buffer_destroy(struct rpcrdma_buffer *); -- GitLab From c45ab4fb384cb3fc05e0949ca3a6ca4d6f7613fb Mon Sep 17 00:00:00 2001 From: Masami Hiramatsu Date: Sun, 14 Jan 2018 22:50:07 +0900 Subject: [PATCH 0894/1635] selftest: ftrace: Fix to pick text symbols for kprobes [ Upstream commit 5e46664703b364434a2cbda3e6988fc24ae0ced5 ] Fix to pick text symbols for multiple kprobe testcase. kallsyms shows text symbols with " t " or " T " but current testcase picks all symbols including "t", so it picks data symbols if it includes 't' (e.g. "str"). This fixes it to find symbol lines with " t " or " T " (including spaces). Signed-off-by: Masami Hiramatsu Reported-by: Russell King Acked-by: Steven Rostedt (VMware) Signed-off-by: Shuah Khan Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- .../selftests/ftrace/test.d/kprobe/multiple_kprobes.tc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/testing/selftests/ftrace/test.d/kprobe/multiple_kprobes.tc b/tools/testing/selftests/ftrace/test.d/kprobe/multiple_kprobes.tc index bb16cf91f1b5..e297bd7a2e79 100644 --- a/tools/testing/selftests/ftrace/test.d/kprobe/multiple_kprobes.tc +++ b/tools/testing/selftests/ftrace/test.d/kprobe/multiple_kprobes.tc @@ -12,8 +12,8 @@ case `uname -m` in *) OFFS=0;; esac -echo "Setup up to 256 kprobes" -grep t /proc/kallsyms | cut -f3 -d" " | grep -v .*\\..* | \ +echo "Setup up kprobes on first 256 text symbols" +grep -i " t " /proc/kallsyms | cut -f3 -d" " | grep -v .*\\..* | \ head -n 256 | while read i; do echo p ${i}+${OFFS} ; done > kprobe_events ||: echo 1 > events/kprobes/enable -- GitLab From 03fdc4ef7a67217506d48e1fcd2a03ab9c1f74bb Mon Sep 17 00:00:00 2001 From: Alex Williamson Date: Tue, 16 Jan 2018 10:05:26 -0700 Subject: [PATCH 0895/1635] PCI: Add function 1 DMA alias quirk for Marvell 9128 [ Upstream commit aa008206634363ef800fbd5f0262016c9ff81dea ] The Marvell 9128 is the original device generating bug 42679, from which many other Marvell DMA alias quirks have been sourced, but we didn't have positive confirmation of the fix on 9128 until now. Link: https://bugzilla.kernel.org/show_bug.cgi?id=42679 Link: https://www.spinics.net/lists/kvm/msg161459.html Reported-by: Binarus Tested-by: Binarus Signed-off-by: Alex Williamson Signed-off-by: Bjorn Helgaas Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/pci/quirks.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 5c5a8af66829..116127a0accb 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -3879,6 +3879,8 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_MARVELL_EXT, 0x9120, quirk_dma_func1_alias); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_MARVELL_EXT, 0x9123, quirk_dma_func1_alias); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_MARVELL_EXT, 0x9128, + quirk_dma_func1_alias); /* https://bugzilla.kernel.org/show_bug.cgi?id=42679#c14 */ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_MARVELL_EXT, 0x9130, quirk_dma_func1_alias); -- GitLab From d925c308742284e508c984bc820b47a3d5c88397 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Tue, 9 Jan 2018 13:44:46 -0800 Subject: [PATCH 0896/1635] Input: psmouse - fix Synaptics detection when protocol is disabled [ Upstream commit 2bc4298f59d2f15175bb568e2d356b5912d0cdd9 ] When Synaptics protocol is disabled, we still need to try and detect the hardware, so we can switch to SMBus device if SMbus is detected, or we know that it is Synaptics device and reset it properly for the bare PS/2 protocol. Fixes: c378b5119eb0 ("Input: psmouse - factor out common protocol probing code") Reported-by: Matteo Croce Tested-by: Matteo Croce Signed-off-by: Dmitry Torokhov Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/input/mouse/psmouse-base.c | 34 ++++++++++++++++++------------ 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c index 6a5649e52eed..8ac9e03c05b4 100644 --- a/drivers/input/mouse/psmouse-base.c +++ b/drivers/input/mouse/psmouse-base.c @@ -975,6 +975,21 @@ static void psmouse_apply_defaults(struct psmouse *psmouse) psmouse->pt_deactivate = NULL; } +static bool psmouse_do_detect(int (*detect)(struct psmouse *, bool), + struct psmouse *psmouse, bool allow_passthrough, + bool set_properties) +{ + if (psmouse->ps2dev.serio->id.type == SERIO_PS_PSTHRU && + !allow_passthrough) { + return false; + } + + if (set_properties) + psmouse_apply_defaults(psmouse); + + return detect(psmouse, set_properties) == 0; +} + static bool psmouse_try_protocol(struct psmouse *psmouse, enum psmouse_type type, unsigned int *max_proto, @@ -986,15 +1001,8 @@ static bool psmouse_try_protocol(struct psmouse *psmouse, if (!proto) return false; - if (psmouse->ps2dev.serio->id.type == SERIO_PS_PSTHRU && - !proto->try_passthru) { - return false; - } - - if (set_properties) - psmouse_apply_defaults(psmouse); - - if (proto->detect(psmouse, set_properties) != 0) + if (!psmouse_do_detect(proto->detect, psmouse, proto->try_passthru, + set_properties)) return false; if (set_properties && proto->init && init_allowed) { @@ -1027,8 +1035,8 @@ static int psmouse_extensions(struct psmouse *psmouse, * Always check for focaltech, this is safe as it uses pnp-id * matching. */ - if (psmouse_try_protocol(psmouse, PSMOUSE_FOCALTECH, - &max_proto, set_properties, false)) { + if (psmouse_do_detect(focaltech_detect, + psmouse, false, set_properties)) { if (max_proto > PSMOUSE_IMEX && IS_ENABLED(CONFIG_MOUSE_PS2_FOCALTECH) && (!set_properties || focaltech_init(psmouse) == 0)) { @@ -1074,8 +1082,8 @@ static int psmouse_extensions(struct psmouse *psmouse, * probing for IntelliMouse. */ if (max_proto > PSMOUSE_PS2 && - psmouse_try_protocol(psmouse, PSMOUSE_SYNAPTICS, &max_proto, - set_properties, false)) { + psmouse_do_detect(synaptics_detect, + psmouse, false, set_properties)) { synaptics_hardware = true; if (max_proto > PSMOUSE_IMEX) { -- GitLab From 0d9a46ae3204b0d07ec6a4de00573cf12b0b1822 Mon Sep 17 00:00:00 2001 From: Jesper Dangaard Brouer Date: Wed, 17 Jan 2018 00:20:40 +0100 Subject: [PATCH 0897/1635] libbpf: Makefile set specified permission mode [ Upstream commit 7110d80d53f472956420cd05a6297f49b558b674 ] The third parameter to do_install was not used by $(INSTALL) command. Fix this by only setting the -m option when the third parameter is supplied. The use of a third parameter was introduced in commit eb54e522a000 ("bpf: install libbpf headers on 'make install'"). Without this change, the header files are install as executables files (755). Fixes: eb54e522a000 ("bpf: install libbpf headers on 'make install'") Signed-off-by: Jesper Dangaard Brouer Signed-off-by: Daniel Borkmann Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- tools/lib/bpf/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/lib/bpf/Makefile b/tools/lib/bpf/Makefile index 4555304dc18e..f02448e86d38 100644 --- a/tools/lib/bpf/Makefile +++ b/tools/lib/bpf/Makefile @@ -183,7 +183,7 @@ define do_install if [ ! -d '$(DESTDIR_SQ)$2' ]; then \ $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$2'; \ fi; \ - $(INSTALL) $1 '$(DESTDIR_SQ)$2' + $(INSTALL) $1 $(if $3,-m $3,) '$(DESTDIR_SQ)$2' endef install_lib: all_cmd -- GitLab From 0d5ef8956c84a4d6667d41085755b09ac54266c6 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Tue, 16 Jan 2018 15:20:58 -0800 Subject: [PATCH 0898/1635] Input: synaptics - reset the ABS_X/Y fuzz after initializing MT axes [ Upstream commit 19eb4ed1141bd1096b9bc84ba9c4d03d5830c143 ] input_mt_init_slots() resets the ABS_X/Y fuzz to 0 and expects the driver to call input_mt_report_pointer_emulation(). That is based on the MT position bits which are already defuzzed - hence a fuzz of 0. In the case of synaptics semi-mt devices, we report the ABS_X/Y axes manually. This results in the MT position being defuzzed but the single-touch emulation missing that defuzzing. Work around this by re-initializing the ABS_X/Y axes after the MT axis to get the same fuzz value back. https://bugs.freedesktop.org/show_bug.cgi?id=104533 Signed-off-by: Peter Hutterer Signed-off-by: Dmitry Torokhov Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/input/mouse/synaptics.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c index ee5466a374bf..a246fc686bb7 100644 --- a/drivers/input/mouse/synaptics.c +++ b/drivers/input/mouse/synaptics.c @@ -1280,6 +1280,16 @@ static void set_input_params(struct psmouse *psmouse, INPUT_MT_POINTER | (cr48_profile_sensor ? INPUT_MT_TRACK : INPUT_MT_SEMI_MT)); + + /* + * For semi-mt devices we send ABS_X/Y ourselves instead of + * input_mt_report_pointer_emulation. But + * input_mt_init_slots() resets the fuzz to 0, leading to a + * filtered ABS_MT_POSITION_X but an unfiltered ABS_X + * position. Let's re-initialize ABS_X/Y here. + */ + if (!cr48_profile_sensor) + set_abs_position_params(dev, &priv->info, ABS_X, ABS_Y); } if (SYN_CAP_PALMDETECT(info->capabilities)) -- GitLab From b3b2ca24d9f7c5c34a073553a983c099a2862119 Mon Sep 17 00:00:00 2001 From: Mustafa Ismail Date: Thu, 11 Jan 2018 18:10:54 -0600 Subject: [PATCH 0899/1635] i40iw: Free IEQ resources [ Upstream commit f20d429511affab6a2a9129f46042f43e6ffe396 ] The iWARP Exception Queue (IEQ) resources are not freed when a QP is destroyed. Fix this by freeing IEQ resources when freeing QP resources. Fixes: d37498417947 ("i40iw: add files for iwarp interface") Signed-off-by: Mustafa Ismail Signed-off-by: Shiraz Saleem Signed-off-by: Jason Gunthorpe Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/infiniband/hw/i40iw/i40iw_puda.c | 3 +-- drivers/infiniband/hw/i40iw/i40iw_puda.h | 1 + drivers/infiniband/hw/i40iw/i40iw_verbs.c | 1 + 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/infiniband/hw/i40iw/i40iw_puda.c b/drivers/infiniband/hw/i40iw/i40iw_puda.c index 14d38d733cb4..27a2d782f6d9 100644 --- a/drivers/infiniband/hw/i40iw/i40iw_puda.c +++ b/drivers/infiniband/hw/i40iw/i40iw_puda.c @@ -48,7 +48,6 @@ static void i40iw_ieq_tx_compl(struct i40iw_sc_vsi *vsi, void *sqwrid); static void i40iw_ilq_putback_rcvbuf(struct i40iw_sc_qp *qp, u32 wqe_idx); static enum i40iw_status_code i40iw_puda_replenish_rq(struct i40iw_puda_rsrc *rsrc, bool initial); -static void i40iw_ieq_cleanup_qp(struct i40iw_puda_rsrc *ieq, struct i40iw_sc_qp *qp); /** * i40iw_puda_get_listbuf - get buffer from puda list * @list: list to use for buffers (ILQ or IEQ) @@ -1480,7 +1479,7 @@ static void i40iw_ieq_tx_compl(struct i40iw_sc_vsi *vsi, void *sqwrid) * @ieq: ieq resource * @qp: all pending fpdu buffers */ -static void i40iw_ieq_cleanup_qp(struct i40iw_puda_rsrc *ieq, struct i40iw_sc_qp *qp) +void i40iw_ieq_cleanup_qp(struct i40iw_puda_rsrc *ieq, struct i40iw_sc_qp *qp) { struct i40iw_puda_buf *buf; struct i40iw_pfpdu *pfpdu = &qp->pfpdu; diff --git a/drivers/infiniband/hw/i40iw/i40iw_puda.h b/drivers/infiniband/hw/i40iw/i40iw_puda.h index dba05ce7d392..ebe37f157d90 100644 --- a/drivers/infiniband/hw/i40iw/i40iw_puda.h +++ b/drivers/infiniband/hw/i40iw/i40iw_puda.h @@ -186,4 +186,5 @@ enum i40iw_status_code i40iw_cqp_qp_create_cmd(struct i40iw_sc_dev *dev, struct enum i40iw_status_code i40iw_cqp_cq_create_cmd(struct i40iw_sc_dev *dev, struct i40iw_sc_cq *cq); void i40iw_cqp_qp_destroy_cmd(struct i40iw_sc_dev *dev, struct i40iw_sc_qp *qp); void i40iw_cqp_cq_destroy_cmd(struct i40iw_sc_dev *dev, struct i40iw_sc_cq *cq); +void i40iw_ieq_cleanup_qp(struct i40iw_puda_rsrc *ieq, struct i40iw_sc_qp *qp); #endif diff --git a/drivers/infiniband/hw/i40iw/i40iw_verbs.c b/drivers/infiniband/hw/i40iw/i40iw_verbs.c index 62be0a41ad0b..9e7ae7161d2f 100644 --- a/drivers/infiniband/hw/i40iw/i40iw_verbs.c +++ b/drivers/infiniband/hw/i40iw/i40iw_verbs.c @@ -428,6 +428,7 @@ void i40iw_free_qp_resources(struct i40iw_device *iwdev, { struct i40iw_pbl *iwpbl = &iwqp->iwpbl; + i40iw_ieq_cleanup_qp(iwdev->vsi.ieq, &iwqp->sc_qp); i40iw_dealloc_push_page(iwdev, &iwqp->sc_qp); if (qp_num) i40iw_free_resource(iwdev, iwdev->allocated_qps, qp_num); -- GitLab From f3ce194cae63c2d1749dbfe4c92e1ce7b56e0648 Mon Sep 17 00:00:00 2001 From: Shiraz Saleem Date: Thu, 11 Jan 2018 18:10:51 -0600 Subject: [PATCH 0900/1635] i40iw: Zero-out consumer key on allocate stag for FMR [ Upstream commit 6376e926af1a8661dd1b2e6d0896e07f84a35844 ] If the application invalidates the MR before the FMR WR, HW parses the consumer key portion of the stag and returns an invalid stag key Asynchronous Event (AE) that tears down the QP. Fix this by zeroing-out the consumer key portion of the allocated stag returned to application for FMR. Fixes: ee855d3b93f3 ("RDMA/i40iw: Add base memory management extensions") Signed-off-by: Shiraz Saleem Signed-off-by: Jason Gunthorpe Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/infiniband/hw/i40iw/i40iw_verbs.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/infiniband/hw/i40iw/i40iw_verbs.c b/drivers/infiniband/hw/i40iw/i40iw_verbs.c index 9e7ae7161d2f..b7961f21b555 100644 --- a/drivers/infiniband/hw/i40iw/i40iw_verbs.c +++ b/drivers/infiniband/hw/i40iw/i40iw_verbs.c @@ -1656,6 +1656,7 @@ static struct ib_mr *i40iw_alloc_mr(struct ib_pd *pd, err_code = -EOVERFLOW; goto err; } + stag &= ~I40IW_CQPSQ_STAG_KEY_MASK; iwmr->stag = stag; iwmr->ibmr.rkey = stag; iwmr->ibmr.lkey = stag; -- GitLab From f3a7d11834f30d04a67c68dd572493953c088834 Mon Sep 17 00:00:00 2001 From: "himanshu.madhani@cavium.com" Date: Mon, 15 Jan 2018 20:46:48 -0800 Subject: [PATCH 0901/1635] scsi: qla2xxx: Fix warning in qla2x00_async_iocb_timeout() [ Upstream commit 7ac0c332f96bb9688560726f5e80c097ed8de59a ] This patch fixes following Smatch warning: drivers/scsi/qla2xxx/qla_init.c:130 qla2x00_async_iocb_timeout() error: we previously assumed 'fcport' could be null (see line 107) Fixes: 5c25d451163c ("scsi: qla2xxx: Fix NULL pointer access for fcport structure") Reported by: Dan Carpenter Signed-off-by: Quinn Tran Signed-off-by: Himanshu Madhani Signed-off-by: Martin K. Petersen Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/qla2xxx/qla_init.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index 2300c02ab5e6..e24f57946a17 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -115,6 +115,8 @@ qla2x00_async_iocb_timeout(void *data) switch (sp->type) { case SRB_LOGIN_CMD: + if (!fcport) + break; /* Retry as needed. */ lio->u.logio.data[0] = MBS_COMMAND_ERROR; lio->u.logio.data[1] = lio->u.logio.flags & SRB_LOGIN_RETRIED ? @@ -128,6 +130,8 @@ qla2x00_async_iocb_timeout(void *data) qla24xx_handle_plogi_done_event(fcport->vha, &ea); break; case SRB_LOGOUT_CMD: + if (!fcport) + break; qlt_logo_completion_handler(fcport, QLA_FUNCTION_TIMEOUT); break; case SRB_CT_PTHRU_CMD: -- GitLab From 0eda4d03ef4c4c707a3f40c5afe634238775ff8a Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Mon, 15 Jan 2018 16:48:46 -0300 Subject: [PATCH 0902/1635] perf unwind: Do not look just at the global callchain_param.record_mode [ Upstream commit eabad8c6856f185f876b54c426c2cc69fe0f0a7d ] When setting up DWARF callchains on specific events, without using 'record' or 'trace' --call-graph, but instead doing it like: perf trace -e cycles/call-graph=dwarf/ The unwind__prepare_access() call in thread__insert_map() when we process PERF_RECORD_MMAP(2) metadata events were not being performed, precluding us from using per-event DWARF callchains, handling them just when we asked for all events to be DWARF, using "--call-graph dwarf". We do it in the PERF_RECORD_MMAP because we have to look at one of the executable maps to figure out the executable type (64-bit, 32-bit) of the DSO laid out in that mmap. Also to look at the architecture where the perf.data file was recorded. All this probably should be deferred to when we process a sample for some thread that has callchains, so that we do this processing only for the threads with samples, not for all of them. For now, fix using DWARF on specific events. Before: # perf trace --no-syscalls -e probe_libc:inet_pton/call-graph=dwarf/ ping -6 -c 1 ::1 PING ::1(::1) 56 data bytes 64 bytes from ::1: icmp_seq=1 ttl=64 time=0.048 ms --- ::1 ping statistics --- 1 packets transmitted, 1 received, 0% packet loss, time 0ms rtt min/avg/max/mdev = 0.048/0.048/0.048/0.000 ms 0.000 probe_libc:inet_pton:(7fe9597bb350)) Problem processing probe_libc:inet_pton callchain, skipping... # After: # perf trace --no-syscalls -e probe_libc:inet_pton/call-graph=dwarf/ ping -6 -c 1 ::1 PING ::1(::1) 56 data bytes 64 bytes from ::1: icmp_seq=1 ttl=64 time=0.060 ms --- ::1 ping statistics --- 1 packets transmitted, 1 received, 0% packet loss, time 0ms rtt min/avg/max/mdev = 0.060/0.060/0.060/0.000 ms 0.000 probe_libc:inet_pton:(7fd4aa930350)) __inet_pton (inlined) gaih_inet.constprop.7 (/usr/lib64/libc-2.26.so) __GI_getaddrinfo (inlined) [0xffffaa804e51af3f] (/usr/bin/ping) __libc_start_main (/usr/lib64/libc-2.26.so) [0xffffaa804e51b379] (/usr/bin/ping) # # perf trace --call-graph=dwarf --no-syscalls -e probe_libc:inet_pton/call-graph=dwarf/ ping -6 -c 1 ::1 PING ::1(::1) 56 data bytes 64 bytes from ::1: icmp_seq=1 ttl=64 time=0.057 ms --- ::1 ping statistics --- 1 packets transmitted, 1 received, 0% packet loss, time 0ms rtt min/avg/max/mdev = 0.057/0.057/0.057/0.000 ms 0.000 probe_libc:inet_pton:(7f9363b9e350)) __inet_pton (inlined) gaih_inet.constprop.7 (/usr/lib64/libc-2.26.so) __GI_getaddrinfo (inlined) [0xffffa9e8a14e0f3f] (/usr/bin/ping) __libc_start_main (/usr/lib64/libc-2.26.so) [0xffffa9e8a14e1379] (/usr/bin/ping) # # perf trace --call-graph=fp --no-syscalls -e probe_libc:inet_pton/call-graph=dwarf/ ping -6 -c 1 ::1 PING ::1(::1) 56 data bytes 64 bytes from ::1: icmp_seq=1 ttl=64 time=0.077 ms --- ::1 ping statistics --- 1 packets transmitted, 1 received, 0% packet loss, time 0ms rtt min/avg/max/mdev = 0.077/0.077/0.077/0.000 ms 0.000 probe_libc:inet_pton:(7f4947e1c350)) __inet_pton (inlined) gaih_inet.constprop.7 (/usr/lib64/libc-2.26.so) __GI_getaddrinfo (inlined) [0xffffaa716d88ef3f] (/usr/bin/ping) __libc_start_main (/usr/lib64/libc-2.26.so) [0xffffaa716d88f379] (/usr/bin/ping) # # perf trace --no-syscalls -e probe_libc:inet_pton/call-graph=fp/ ping -6 -c 1 ::1 PING ::1(::1) 56 data bytes 64 bytes from ::1: icmp_seq=1 ttl=64 time=0.078 ms --- ::1 ping statistics --- 1 packets transmitted, 1 received, 0% packet loss, time 0ms rtt min/avg/max/mdev = 0.078/0.078/0.078/0.000 ms 0.000 probe_libc:inet_pton:(7fa157696350)) __GI___inet_pton (/usr/lib64/libc-2.26.so) getaddrinfo (/usr/lib64/libc-2.26.so) [0xffffa9ba39c74f40] (/usr/bin/ping) # Acked-by: Namhyung Kim Cc: Adrian Hunter Cc: David Ahern Cc: Hendrick Brueckner Cc: Jiri Olsa Cc: Thomas Richter Cc: Wang Nan Link: https://lkml.kernel.org/r/20180116182650.GE16107@kernel.org Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- tools/perf/builtin-c2c.c | 5 +++-- tools/perf/builtin-report.c | 5 +++-- tools/perf/builtin-script.c | 5 +++-- tools/perf/tests/dwarf-unwind.c | 1 + tools/perf/util/callchain.c | 10 ++++++++++ tools/perf/util/callchain.h | 2 ++ tools/perf/util/unwind-libunwind-local.c | 9 +++------ 7 files changed, 25 insertions(+), 12 deletions(-) diff --git a/tools/perf/builtin-c2c.c b/tools/perf/builtin-c2c.c index d00aac51130d..3479a1bc7caa 100644 --- a/tools/perf/builtin-c2c.c +++ b/tools/perf/builtin-c2c.c @@ -2393,9 +2393,10 @@ static int setup_callchain(struct perf_evlist *evlist) enum perf_call_graph_mode mode = CALLCHAIN_NONE; if ((sample_type & PERF_SAMPLE_REGS_USER) && - (sample_type & PERF_SAMPLE_STACK_USER)) + (sample_type & PERF_SAMPLE_STACK_USER)) { mode = CALLCHAIN_DWARF; - else if (sample_type & PERF_SAMPLE_BRANCH_STACK) + dwarf_callchain_users = true; + } else if (sample_type & PERF_SAMPLE_BRANCH_STACK) mode = CALLCHAIN_LBR; else if (sample_type & PERF_SAMPLE_CALLCHAIN) mode = CALLCHAIN_FP; diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 183c3ed56e08..4ddb0726eebc 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -328,9 +328,10 @@ static int report__setup_sample_type(struct report *rep) if (symbol_conf.use_callchain || symbol_conf.cumulate_callchain) { if ((sample_type & PERF_SAMPLE_REGS_USER) && - (sample_type & PERF_SAMPLE_STACK_USER)) + (sample_type & PERF_SAMPLE_STACK_USER)) { callchain_param.record_mode = CALLCHAIN_DWARF; - else if (sample_type & PERF_SAMPLE_BRANCH_STACK) + dwarf_callchain_users = true; + } else if (sample_type & PERF_SAMPLE_BRANCH_STACK) callchain_param.record_mode = CALLCHAIN_LBR; else callchain_param.record_mode = CALLCHAIN_FP; diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index 0fe02758de7d..615fdc63452e 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c @@ -2574,9 +2574,10 @@ static void script__setup_sample_type(struct perf_script *script) if (symbol_conf.use_callchain || symbol_conf.cumulate_callchain) { if ((sample_type & PERF_SAMPLE_REGS_USER) && - (sample_type & PERF_SAMPLE_STACK_USER)) + (sample_type & PERF_SAMPLE_STACK_USER)) { callchain_param.record_mode = CALLCHAIN_DWARF; - else if (sample_type & PERF_SAMPLE_BRANCH_STACK) + dwarf_callchain_users = true; + } else if (sample_type & PERF_SAMPLE_BRANCH_STACK) callchain_param.record_mode = CALLCHAIN_LBR; else callchain_param.record_mode = CALLCHAIN_FP; diff --git a/tools/perf/tests/dwarf-unwind.c b/tools/perf/tests/dwarf-unwind.c index ac40e05bcab4..260418969120 100644 --- a/tools/perf/tests/dwarf-unwind.c +++ b/tools/perf/tests/dwarf-unwind.c @@ -173,6 +173,7 @@ int test__dwarf_unwind(struct test *test __maybe_unused, int subtest __maybe_unu } callchain_param.record_mode = CALLCHAIN_DWARF; + dwarf_callchain_users = true; if (init_live_machine(machine)) { pr_err("Could not init machine\n"); diff --git a/tools/perf/util/callchain.c b/tools/perf/util/callchain.c index 6031933d811c..146683b1c28d 100644 --- a/tools/perf/util/callchain.c +++ b/tools/perf/util/callchain.c @@ -37,6 +37,15 @@ struct callchain_param callchain_param = { CALLCHAIN_PARAM_DEFAULT }; +/* + * Are there any events usind DWARF callchains? + * + * I.e. + * + * -e cycles/call-graph=dwarf/ + */ +bool dwarf_callchain_users; + struct callchain_param callchain_param_default = { CALLCHAIN_PARAM_DEFAULT }; @@ -265,6 +274,7 @@ int parse_callchain_record(const char *arg, struct callchain_param *param) ret = 0; param->record_mode = CALLCHAIN_DWARF; param->dump_size = default_stack_dump_size; + dwarf_callchain_users = true; tok = strtok_r(NULL, ",", &saveptr); if (tok) { diff --git a/tools/perf/util/callchain.h b/tools/perf/util/callchain.h index f967aa47d0a1..9ba5903c8d3e 100644 --- a/tools/perf/util/callchain.h +++ b/tools/perf/util/callchain.h @@ -89,6 +89,8 @@ enum chain_value { CCVAL_COUNT, }; +extern bool dwarf_callchain_users; + struct callchain_param { bool enabled; enum perf_call_graph_mode record_mode; diff --git a/tools/perf/util/unwind-libunwind-local.c b/tools/perf/util/unwind-libunwind-local.c index 7a42f703e858..af873044d33a 100644 --- a/tools/perf/util/unwind-libunwind-local.c +++ b/tools/perf/util/unwind-libunwind-local.c @@ -631,9 +631,8 @@ static unw_accessors_t accessors = { static int _unwind__prepare_access(struct thread *thread) { - if (callchain_param.record_mode != CALLCHAIN_DWARF) + if (!dwarf_callchain_users) return 0; - thread->addr_space = unw_create_addr_space(&accessors, 0); if (!thread->addr_space) { pr_err("unwind: Can't create unwind address space.\n"); @@ -646,17 +645,15 @@ static int _unwind__prepare_access(struct thread *thread) static void _unwind__flush_access(struct thread *thread) { - if (callchain_param.record_mode != CALLCHAIN_DWARF) + if (!dwarf_callchain_users) return; - unw_flush_cache(thread->addr_space, 0, 0); } static void _unwind__finish_access(struct thread *thread) { - if (callchain_param.record_mode != CALLCHAIN_DWARF) + if (!dwarf_callchain_users) return; - unw_destroy_addr_space(thread->addr_space); } -- GitLab From 448bcd67b4c51bd7e4ac3a6d4a1b49e880c5bb5a Mon Sep 17 00:00:00 2001 From: "Steven Rostedt (VMware)" Date: Thu, 11 Jan 2018 19:47:45 -0500 Subject: [PATCH 0903/1635] tools lib traceevent: Simplify pointer print logic and fix %pF [ Upstream commit 38d70b7ca1769f26c0b79f3c08ff2cc949712b59 ] When processing %pX in pretty_print(), simplify the logic slightly by incrementing the ptr to the format string if isalnum(ptr[1]) is true. This follows the logic a bit more closely to what is in the kernel. Also, this fixes a small bug where %pF was not giving the offset of the function. Signed-off-by: Steven Rostedt Acked-by: Namhyung Kim Cc: Andrew Morton Link: http://lkml.kernel.org/r/20180112004822.260262257@goodmis.org Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- tools/lib/traceevent/event-parse.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/tools/lib/traceevent/event-parse.c b/tools/lib/traceevent/event-parse.c index 7ce724fc0544..9a17bc27296e 100644 --- a/tools/lib/traceevent/event-parse.c +++ b/tools/lib/traceevent/event-parse.c @@ -4949,21 +4949,22 @@ static void pretty_print(struct trace_seq *s, void *data, int size, struct event else ls = 2; - if (*(ptr+1) == 'F' || *(ptr+1) == 'f' || - *(ptr+1) == 'S' || *(ptr+1) == 's') { + if (isalnum(ptr[1])) ptr++; + + if (*ptr == 'F' || *ptr == 'f' || + *ptr == 'S' || *ptr == 's') { show_func = *ptr; - } else if (*(ptr+1) == 'M' || *(ptr+1) == 'm') { - print_mac_arg(s, *(ptr+1), data, size, event, arg); - ptr++; + } else if (*ptr == 'M' || *ptr == 'm') { + print_mac_arg(s, *ptr, data, size, event, arg); arg = arg->next; break; - } else if (*(ptr+1) == 'I' || *(ptr+1) == 'i') { + } else if (*ptr == 'I' || *ptr == 'i') { int n; - n = print_ip_arg(s, ptr+1, data, size, event, arg); + n = print_ip_arg(s, ptr, data, size, event, arg); if (n > 0) { - ptr += n; + ptr += n - 1; arg = arg->next; break; } -- GitLab From 4e63115b6b9d040c153a9d4b53cd783e0ce9ae76 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Mon, 15 Jan 2018 11:07:58 -0300 Subject: [PATCH 0904/1635] perf callchain: Fix attr.sample_max_stack setting [ Upstream commit 249d98e567e25dd03e015e2d31e1b7b9648f34df ] When setting the "dwarf" unwinder for a specific event and not specifying the max-stack, the attr.sample_max_stack ended up using an uninitialized callchain_param.max_stack, fix it by using designated initializers for that callchain_param variable, zeroing all non explicitely initialized struct members. Here is what happened: # perf trace -vv --no-syscalls --max-stack 4 -e probe_libc:inet_pton/call-graph=dwarf/ ping -6 -c 1 ::1 callchain: type DWARF callchain: stack dump size 8192 perf_event_attr: type 2 size 112 config 0x730 { sample_period, sample_freq } 1 sample_type IP|TID|TIME|ADDR|CALLCHAIN|CPU|PERIOD|RAW|REGS_USER|STACK_USER|DATA_SRC exclude_callchain_user 1 { wakeup_events, wakeup_watermark } 1 sample_regs_user 0xff0fff sample_stack_user 8192 sample_max_stack 50656 sys_perf_event_open failed, error -75 Value too large for defined data type # perf trace -vv --no-syscalls --max-stack 4 -e probe_libc:inet_pton/call-graph=dwarf/ ping -6 -c 1 ::1 callchain: type DWARF callchain: stack dump size 8192 perf_event_attr: type 2 size 112 config 0x730 sample_type IP|TID|TIME|ADDR|CALLCHAIN|CPU|PERIOD|RAW|REGS_USER|STACK_USER|DATA_SRC exclude_callchain_user 1 sample_regs_user 0xff0fff sample_stack_user 8192 sample_max_stack 30448 sys_perf_event_open failed, error -75 Value too large for defined data type # Now the attr.sample_max_stack is set to zero and the above works as expected: # perf trace --no-syscalls --max-stack 4 -e probe_libc:inet_pton/call-graph=dwarf/ ping -6 -c 1 ::1 PING ::1(::1) 56 data bytes 64 bytes from ::1: icmp_seq=1 ttl=64 time=0.072 ms --- ::1 ping statistics --- 1 packets transmitted, 1 received, 0% packet loss, time 0ms rtt min/avg/max/mdev = 0.072/0.072/0.072/0.000 ms 0.000 probe_libc:inet_pton:(7feb7a998350)) __inet_pton (inlined) gaih_inet.constprop.7 (/usr/lib64/libc-2.26.so) __GI_getaddrinfo (inlined) [0xffffaa39b6108f3f] (/usr/bin/ping) # Cc: Adrian Hunter Cc: David Ahern Cc: Hendrick Brueckner Cc: Jiri Olsa Cc: Namhyung Kim Cc: Thomas Richter Cc: Wang Nan Link: https://lkml.kernel.org/n/tip-is9tramondqa9jlxxsgcm9iz@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- tools/perf/util/evsel.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index ac19130c14d8..2ffac0a477e5 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c @@ -722,14 +722,14 @@ static void apply_config_terms(struct perf_evsel *evsel, struct perf_evsel_config_term *term; struct list_head *config_terms = &evsel->config_terms; struct perf_event_attr *attr = &evsel->attr; - struct callchain_param param; + /* callgraph default */ + struct callchain_param param = { + .record_mode = callchain_param.record_mode, + }; u32 dump_size = 0; int max_stack = 0; const char *callgraph_buf = NULL; - /* callgraph default */ - param.record_mode = callchain_param.record_mode; - list_for_each_entry(term, config_terms, list) { switch (term->type) { case PERF_EVSEL__CONFIG_TERM_PERIOD: -- GitLab From 1fe5e88c389a2f7bda893ed57aa0f3fff52b82b0 Mon Sep 17 00:00:00 2001 From: "Steven Rostedt (VMware)" Date: Thu, 11 Jan 2018 19:47:51 -0500 Subject: [PATCH 0905/1635] tools lib traceevent: Fix get_field_str() for dynamic strings [ Upstream commit d777f8de99b05d399c0e4e51cdce016f26bd971b ] If a field is a dynamic string, get_field_str() returned just the offset/size value and not the string. Have it parse the offset/size correctly to return the actual string. Otherwise filtering fails when trying to filter fields that are dynamic strings. Reported-by: Gopanapalli Pradeep Signed-off-by: Steven Rostedt Acked-by: Namhyung Kim Cc: Andrew Morton Link: http://lkml.kernel.org/r/20180112004823.146333275@goodmis.org Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- tools/lib/traceevent/parse-filter.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/tools/lib/traceevent/parse-filter.c b/tools/lib/traceevent/parse-filter.c index 7c214ceb9386..5e10ba796a6f 100644 --- a/tools/lib/traceevent/parse-filter.c +++ b/tools/lib/traceevent/parse-filter.c @@ -1879,17 +1879,25 @@ static const char *get_field_str(struct filter_arg *arg, struct pevent_record *r struct pevent *pevent; unsigned long long addr; const char *val = NULL; + unsigned int size; char hex[64]; /* If the field is not a string convert it */ if (arg->str.field->flags & FIELD_IS_STRING) { val = record->data + arg->str.field->offset; + size = arg->str.field->size; + + if (arg->str.field->flags & FIELD_IS_DYNAMIC) { + addr = *(unsigned int *)val; + val = record->data + (addr & 0xffff); + size = addr >> 16; + } /* * We need to copy the data since we can't be sure the field * is null terminated. */ - if (*(val + arg->str.field->size - 1)) { + if (*(val + size - 1)) { /* copy it */ memcpy(arg->str.buffer, val, arg->str.field->size); /* the buffer is already NULL terminated */ -- GitLab From 77d17d0e8934b65864051d74b099f04420066689 Mon Sep 17 00:00:00 2001 From: Thomas Richter Date: Wed, 17 Jan 2018 14:16:11 +0100 Subject: [PATCH 0906/1635] perf record: Fix failed memory allocation for get_cpuid_str [ Upstream commit 81fccd6ca507d3b2012eaf1edeb9b1dbf4bd22db ] In x86 architecture dependend part function get_cpuid_str() mallocs a 128 byte buffer, but does not check if the memory allocation succeeded or not. When the memory allocation fails, function __get_cpuid() is called with first parameter being a NULL pointer. However this function references its first parameter and operates on a NULL pointer which might cause core dumps. Signed-off-by: Thomas Richter Cc: Heiko Carstens Cc: Hendrik Brueckner Cc: Martin Schwidefsky Link: http://lkml.kernel.org/r/20180117131611.34319-1-tmricht@linux.vnet.ibm.com Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- tools/perf/arch/x86/util/header.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/perf/arch/x86/util/header.c b/tools/perf/arch/x86/util/header.c index 33027c5e6f92..c6b5204e0280 100644 --- a/tools/perf/arch/x86/util/header.c +++ b/tools/perf/arch/x86/util/header.c @@ -70,7 +70,7 @@ get_cpuid_str(void) { char *buf = malloc(128); - if (__get_cpuid(buf, 128, "%s-%u-%X$") < 0) { + if (buf && __get_cpuid(buf, 128, "%s-%u-%X$") < 0) { free(buf); return NULL; } -- GitLab From bc5fddf315f8a1664754bac4ef3752f4bc553e44 Mon Sep 17 00:00:00 2001 From: Robin Murphy Date: Tue, 9 Jan 2018 15:34:07 +0000 Subject: [PATCH 0907/1635] iommu/exynos: Don't unconditionally steal bus ops [ Upstream commit dc98b8480d8a68c2ce9aa28b9f0d714fd258bc0b ] Removing the early device registration hook overlooked the fact that it only ran conditionally on a compatible device being present in the DT. With exynos_iommu_init() now running as an unconditional initcall, problems arise on non-Exynos systems when other IOMMU drivers find themselves unable to install their ops on the platform bus, or at worst the Exynos ops get called with someone else's domain and all hell breaks loose. The global ops/cache setup could probably all now be triggered from the first IOMMU probe, as with dma_dev assigment, but for the time being the simplest fix is to resurrect the logic from commit a7b67cd5d9af ("iommu/exynos: Play nice in multi-platform builds") to explicitly check the DT for the presence of an Exynos IOMMU before trying anything. Fixes: 928055a01b3f ("iommu/exynos: Remove custom platform device registration code") Signed-off-by: Robin Murphy Acked-by: Marek Szyprowski Signed-off-by: Joerg Roedel Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/iommu/exynos-iommu.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/iommu/exynos-iommu.c b/drivers/iommu/exynos-iommu.c index 25c2c75f5332..13485a40dd46 100644 --- a/drivers/iommu/exynos-iommu.c +++ b/drivers/iommu/exynos-iommu.c @@ -1344,8 +1344,15 @@ static const struct iommu_ops exynos_iommu_ops = { static int __init exynos_iommu_init(void) { + struct device_node *np; int ret; + np = of_find_matching_node(NULL, sysmmu_of_match); + if (!np) + return 0; + + of_node_put(np); + lv2table_kmem_cache = kmem_cache_create("exynos-iommu-lv2table", LV2TABLE_SIZE, LV2TABLE_SIZE, 0, NULL); if (!lv2table_kmem_cache) { -- GitLab From 6ec6bd8ec2e363f7955a992d97038b7fbed4974b Mon Sep 17 00:00:00 2001 From: Nicholas Piggin Date: Sun, 24 Dec 2017 02:49:22 +1000 Subject: [PATCH 0908/1635] powerpc: System reset avoid interleaving oops using die synchronisation [ Upstream commit 4552d128c26e0f0f27a5bd2fadc24092b8f6c1d7 ] The die() oops path contains a serializing lock to prevent oops messages from being interleaved. In the case of a system reset initiated oops (e.g., qemu nmi command), __die was being called which lacks that synchronisation and oops reports could be interleaved across CPUs. A recent patch 4388c9b3a6ee7 ("powerpc: Do not send system reset request through the oops path") changed this to __die to avoid the debugger() call, but there is no real harm to calling it twice if the first time fell through. So go back to using die() here. This was observed to fix the problem. Fixes: 4388c9b3a6ee7 ("powerpc: Do not send system reset request through the oops path") Signed-off-by: Nicholas Piggin Reviewed-by: David Gibson Signed-off-by: Michael Ellerman Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/kernel/traps.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c index 13c9dcdcba69..d17007451f62 100644 --- a/arch/powerpc/kernel/traps.c +++ b/arch/powerpc/kernel/traps.c @@ -336,7 +336,7 @@ void system_reset_exception(struct pt_regs *regs) * No debugger or crash dump registered, print logs then * panic. */ - __die("System Reset", regs, SIGABRT); + die("System Reset", regs, SIGABRT); mdelay(2*MSEC_PER_SEC); /* Wait a little while for others to print */ add_taint(TAINT_DIE, LOCKDEP_NOW_UNRELIABLE); -- GitLab From e9c8a5fa078ca85b4a78dfbe837fadfef780608d Mon Sep 17 00:00:00 2001 From: Peter Xu Date: Wed, 10 Jan 2018 13:51:37 +0800 Subject: [PATCH 0909/1635] iommu/vt-d: Use domain instead of cache fetching [ Upstream commit 9d2e6505f6d6934e681aed502f566198cb25c74a ] after commit a1ddcbe93010 ("iommu/vt-d: Pass dmar_domain directly into iommu_flush_iotlb_psi", 2015-08-12), we have domain pointer as parameter to iommu_flush_iotlb_psi(), so no need to fetch it from cache again. More importantly, a NULL reference pointer bug is reported on RHEL7 (and it can be reproduced on some old upstream kernels too, e.g., v4.13) by unplugging an 40g nic from a VM (hard to test unplug on real host, but it should be the same): https://bugzilla.redhat.com/show_bug.cgi?id=1531367 [ 24.391863] pciehp 0000:00:03.0:pcie004: Slot(0): Attention button pressed [ 24.393442] pciehp 0000:00:03.0:pcie004: Slot(0): Powering off due to button press [ 29.721068] i40evf 0000:01:00.0: Unable to send opcode 2 to PF, err I40E_ERR_QUEUE_EMPTY, aq_err OK [ 29.783557] iommu: Removing device 0000:01:00.0 from group 3 [ 29.784662] BUG: unable to handle kernel NULL pointer dereference at 0000000000000304 [ 29.785817] IP: iommu_flush_iotlb_psi+0xcf/0x120 [ 29.786486] PGD 0 [ 29.786487] P4D 0 [ 29.786812] [ 29.787390] Oops: 0000 [#1] SMP [ 29.787876] Modules linked in: ip6t_rpfilter ip6t_REJECT nf_reject_ipv6 xt_conntrack ip_set nfnetlink ebtable_nat ebtable_broute bridge stp llc ip6table_ng [ 29.795371] CPU: 0 PID: 156 Comm: kworker/0:2 Not tainted 4.13.0 #14 [ 29.796366] Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.11.0-1.el7 04/01/2014 [ 29.797593] Workqueue: pciehp-0 pciehp_power_thread [ 29.798328] task: ffff94f5745b4a00 task.stack: ffffb326805ac000 [ 29.799178] RIP: 0010:iommu_flush_iotlb_psi+0xcf/0x120 [ 29.799919] RSP: 0018:ffffb326805afbd0 EFLAGS: 00010086 [ 29.800666] RAX: ffff94f5bc56e800 RBX: 0000000000000000 RCX: 0000000200000025 [ 29.801667] RDX: ffff94f5bc56e000 RSI: 0000000000000082 RDI: 0000000000000000 [ 29.802755] RBP: ffffb326805afbf8 R08: 0000000000000000 R09: ffff94f5bc86bbf0 [ 29.803772] R10: ffffb326805afba8 R11: 00000000000ffdc4 R12: ffff94f5bc86a400 [ 29.804789] R13: 0000000000000000 R14: 00000000ffdc4000 R15: 0000000000000000 [ 29.805792] FS: 0000000000000000(0000) GS:ffff94f5bfc00000(0000) knlGS:0000000000000000 [ 29.806923] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 29.807736] CR2: 0000000000000304 CR3: 000000003499d000 CR4: 00000000000006f0 [ 29.808747] Call Trace: [ 29.809156] flush_unmaps_timeout+0x126/0x1c0 [ 29.809800] domain_exit+0xd6/0x100 [ 29.810322] device_notifier+0x6b/0x70 [ 29.810902] notifier_call_chain+0x4a/0x70 [ 29.812822] __blocking_notifier_call_chain+0x47/0x60 [ 29.814499] blocking_notifier_call_chain+0x16/0x20 [ 29.816137] device_del+0x233/0x320 [ 29.817588] pci_remove_bus_device+0x6f/0x110 [ 29.819133] pci_stop_and_remove_bus_device+0x1a/0x20 [ 29.820817] pciehp_unconfigure_device+0x7a/0x1d0 [ 29.822434] pciehp_disable_slot+0x52/0xe0 [ 29.823931] pciehp_power_thread+0x8a/0xa0 [ 29.825411] process_one_work+0x18c/0x3a0 [ 29.826875] worker_thread+0x4e/0x3b0 [ 29.828263] kthread+0x109/0x140 [ 29.829564] ? process_one_work+0x3a0/0x3a0 [ 29.831081] ? kthread_park+0x60/0x60 [ 29.832464] ret_from_fork+0x25/0x30 [ 29.833794] Code: 85 ed 74 0b 5b 41 5c 41 5d 41 5e 41 5f 5d c3 49 8b 54 24 60 44 89 f8 0f b6 c4 48 8b 04 c2 48 85 c0 74 49 45 0f b6 ff 4a 8b 3c f8 <80> bf [ 29.838514] RIP: iommu_flush_iotlb_psi+0xcf/0x120 RSP: ffffb326805afbd0 [ 29.840362] CR2: 0000000000000304 [ 29.841716] ---[ end trace b10ec0d6900868d3 ]--- This patch fixes that problem if applied to v4.13 kernel. The bug does not exist on latest upstream kernel since it's fixed as a side effect of commit 13cf01744608 ("iommu/vt-d: Make use of iova deferred flushing", 2017-08-15). But IMHO it's still good to have this patch upstream. CC: Alex Williamson Signed-off-by: Peter Xu Fixes: a1ddcbe93010 ("iommu/vt-d: Pass dmar_domain directly into iommu_flush_iotlb_psi") Reviewed-by: Alex Williamson Signed-off-by: Joerg Roedel Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/iommu/intel-iommu.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c index 83f3d4831f94..e8414bcf8390 100644 --- a/drivers/iommu/intel-iommu.c +++ b/drivers/iommu/intel-iommu.c @@ -1603,8 +1603,7 @@ static void iommu_flush_iotlb_psi(struct intel_iommu *iommu, * flush. However, device IOTLB doesn't need to be flushed in this case. */ if (!cap_caching_mode(iommu->cap) || !map) - iommu_flush_dev_iotlb(get_iommu_domain(iommu, did), - addr, mask); + iommu_flush_dev_iotlb(domain, addr, mask); } static void iommu_flush_iova(struct iova_domain *iovad) -- GitLab From 223ed638e937c53fdb49c6a55aa3c9de2c728b0f Mon Sep 17 00:00:00 2001 From: mulhern Date: Mon, 27 Nov 2017 10:02:39 -0500 Subject: [PATCH 0910/1635] dm thin: fix documentation relative to low water mark threshold [ Upstream commit 9b28a1102efc75d81298198166ead87d643a29ce ] Fixes: 1. The use of "exceeds" when the opposite of exceeds, falls below, was meant. 2. Properly speaking, a table can not exceed a threshold. It emphasizes the important point, which is that it is the userspace daemon's responsibility to check for low free space when a device is resumed, since it won't get a special event indicating low free space in that situation. Signed-off-by: mulhern Signed-off-by: Mike Snitzer Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- Documentation/device-mapper/thin-provisioning.txt | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/Documentation/device-mapper/thin-provisioning.txt b/Documentation/device-mapper/thin-provisioning.txt index 1699a55b7b70..ef639960b272 100644 --- a/Documentation/device-mapper/thin-provisioning.txt +++ b/Documentation/device-mapper/thin-provisioning.txt @@ -112,9 +112,11 @@ $low_water_mark is expressed in blocks of size $data_block_size. If free space on the data device drops below this level then a dm event will be triggered which a userspace daemon should catch allowing it to extend the pool device. Only one such event will be sent. -Resuming a device with a new table itself triggers an event so the -userspace daemon can use this to detect a situation where a new table -already exceeds the threshold. + +No special event is triggered if a just resumed device's free space is below +the low water mark. However, resuming a device always triggers an +event; a userspace daemon should verify that free space exceeds the low +water mark when handling this event. A low water mark for the metadata device is maintained in the kernel and will trigger a dm event if free space on the metadata device drops below -- GitLab From 2e102fe86ede237ca875da9336648caa5e2fcac6 Mon Sep 17 00:00:00 2001 From: Ming Lei Date: Thu, 11 Jan 2018 14:01:56 +0800 Subject: [PATCH 0911/1635] dm mpath: return DM_MAPIO_REQUEUE on blk-mq rq allocation failure [ Upstream commit 050af08ffb1b62af69196d61c22a0755f9a3cdbd ] blk-mq will rerun queue via RESTART or dispatch wake after one request is completed, so not necessary to wait random time for requeuing, we should trust blk-mq to do it. More importantly, we need to return BLK_STS_RESOURCE to blk-mq so that dequeuing from the I/O scheduler can be stopped, this results in improved I/O merging. Signed-off-by: Ming Lei Signed-off-by: Mike Snitzer Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/md/dm-mpath.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/drivers/md/dm-mpath.c b/drivers/md/dm-mpath.c index 2704a55f8b6e..8b7328666eaa 100644 --- a/drivers/md/dm-mpath.c +++ b/drivers/md/dm-mpath.c @@ -502,8 +502,20 @@ static int multipath_clone_and_map(struct dm_target *ti, struct request *rq, if (queue_dying) { atomic_inc(&m->pg_init_in_progress); activate_or_offline_path(pgpath); + return DM_MAPIO_DELAY_REQUEUE; } - return DM_MAPIO_DELAY_REQUEUE; + + /* + * blk-mq's SCHED_RESTART can cover this requeue, so we + * needn't deal with it by DELAY_REQUEUE. More importantly, + * we have to return DM_MAPIO_REQUEUE so that blk-mq can + * get the queue busy feedback (via BLK_STS_RESOURCE), + * otherwise I/O merging can suffer. + */ + if (q->mq_ops) + return DM_MAPIO_REQUEUE; + else + return DM_MAPIO_DELAY_REQUEUE; } clone->bio = clone->biotail = NULL; clone->rq_disk = bdev->bd_disk; -- GitLab From a1dfcb01e374729f6920c3c07867914c5e848fb4 Mon Sep 17 00:00:00 2001 From: Ming Lei Date: Thu, 18 Jan 2018 00:41:52 +0800 Subject: [PATCH 0912/1635] blk-mq: turn WARN_ON in __blk_mq_run_hw_queue into printk [ Upstream commit 7df938fbc4ee641e70e05002ac67c24b19e86e74 ] We know this WARN_ON is harmless and in reality it may be trigged, so convert it to printk() and dump_stack() to avoid to confusing people. Also add comment about two releated races here. Cc: Christian Borntraeger Cc: Stefan Haberland Cc: Christoph Hellwig Cc: Thomas Gleixner Cc: "jianchao.wang" Signed-off-by: Ming Lei Signed-off-by: Jens Axboe Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- block/blk-mq.c | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/block/blk-mq.c b/block/blk-mq.c index 6f899669cbdd..007f96611364 100644 --- a/block/blk-mq.c +++ b/block/blk-mq.c @@ -1143,9 +1143,27 @@ static void __blk_mq_run_hw_queue(struct blk_mq_hw_ctx *hctx) /* * We should be running this queue from one of the CPUs that * are mapped to it. + * + * There are at least two related races now between setting + * hctx->next_cpu from blk_mq_hctx_next_cpu() and running + * __blk_mq_run_hw_queue(): + * + * - hctx->next_cpu is found offline in blk_mq_hctx_next_cpu(), + * but later it becomes online, then this warning is harmless + * at all + * + * - hctx->next_cpu is found online in blk_mq_hctx_next_cpu(), + * but later it becomes offline, then the warning can't be + * triggered, and we depend on blk-mq timeout handler to + * handle dispatched requests to this hctx */ - WARN_ON(!cpumask_test_cpu(raw_smp_processor_id(), hctx->cpumask) && - cpu_online(hctx->next_cpu)); + if (!cpumask_test_cpu(raw_smp_processor_id(), hctx->cpumask) && + cpu_online(hctx->next_cpu)) { + printk(KERN_WARNING "run queue from wrong CPU %d, hctx %s\n", + raw_smp_processor_id(), + cpumask_empty(hctx->cpumask) ? "inactive": "active"); + dump_stack(); + } /* * We can't run the queue inline with ints disabled. Ensure that -- GitLab From 2a71a742f09b390a200110dd3d8ff9f6f51f9443 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Sun, 17 Sep 2017 10:32:20 +0200 Subject: [PATCH 0913/1635] ubifs: Fix uninitialized variable in search_dh_cookie() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit c877154d307f4a91e0b5b85b75535713dab945ae ] fs/ubifs/tnc.c: In function ‘search_dh_cookie’: fs/ubifs/tnc.c:1893: warning: ‘err’ is used uninitialized in this function Indeed, err is always used uninitialized. According to an original review comment from Hyunchul, acknowledged by Richard, err should be initialized to -ENOENT to avoid the first call to tnc_next(). But we can achieve the same by reordering the code. Fixes: 781f675e2d7e ("ubifs: Fix unlink code wrt. double hash lookups") Reported-by: Hyunchul Lee Signed-off-by: Geert Uytterhoeven Signed-off-by: Richard Weinberger Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- fs/ubifs/tnc.c | 21 +++++++-------------- 1 file changed, 7 insertions(+), 14 deletions(-) diff --git a/fs/ubifs/tnc.c b/fs/ubifs/tnc.c index 0a213dcba2a1..ba3d0e0f8615 100644 --- a/fs/ubifs/tnc.c +++ b/fs/ubifs/tnc.c @@ -1890,35 +1890,28 @@ static int search_dh_cookie(struct ubifs_info *c, const union ubifs_key *key, union ubifs_key *dkey; for (;;) { - if (!err) { - err = tnc_next(c, &znode, n); - if (err) - goto out; - } - zbr = &znode->zbranch[*n]; dkey = &zbr->key; if (key_inum(c, dkey) != key_inum(c, key) || key_type(c, dkey) != key_type(c, key)) { - err = -ENOENT; - goto out; + return -ENOENT; } err = tnc_read_hashed_node(c, zbr, dent); if (err) - goto out; + return err; if (key_hash(c, key) == key_hash(c, dkey) && le32_to_cpu(dent->cookie) == cookie) { *zn = znode; - goto out; + return 0; } - } - -out: - return err; + err = tnc_next(c, &znode, n); + if (err) + return err; + } } static int do_lookup_dh(struct ubifs_info *c, const union ubifs_key *key, -- GitLab From 5bfa11c9619283d77cf8193152fba8ae18819557 Mon Sep 17 00:00:00 2001 From: Martin Blumenstingl Date: Mon, 15 Jan 2018 18:10:14 +0100 Subject: [PATCH 0914/1635] net: stmmac: dwmac-meson8b: fix setting the RGMII TX clock on Meson8b [ Upstream commit 433c6cab9d298687c097f6ee82e49157044dc7c6 ] Meson8b only supports MPLL2 as clock input. The rate of the MPLL2 clock set by Odroid-C1's u-boot is close to (but not exactly) 500MHz. The exact rate is 500002394Hz, which is calculated in drivers/clk/meson/clk-mpll.c using the following formula: DIV_ROUND_UP_ULL((u64)parent_rate * SDM_DEN, (SDM_DEN * n2) + sdm) Odroid-C1's u-boot configures MPLL2 with the following values: - SDM_DEN = 16384 - SDM = 1638 - N2 = 5 The 250MHz clock (m250_div) inside dwmac-meson8b driver is derived from the MPLL2 clock. Due to MPLL2 running slightly faster than 500MHz the common clock framework chooses a divider which is too big to generate the 250MHz clock (a divider of 2 would be needed, but this is rounded up to a divider of 3). This breaks the RTL8211F RGMII PHY on Odroid-C1 because it requires a (close to) 125MHz RGMII TX clock (on Gbit speeds, the IP block internally divides that down to 25MHz on 100Mbit/s connections and 2.5MHz on 10Mbit/s connections - we don't need any special configuration for that). Round the divider to the closest value to prevent this issue on Meson8b. This means we'll now end up with a clock rate for the RGMII TX clock of 125001197Hz (= 125MHz plus 1197Hz), which is close-enough to 125MHz. This has no effect on the Meson GX SoCs since there fclk_div2 is used as input clock, which has a rate of 1000MHz (and thus is divisible cleanly to 250MHz and 125MHz). Fixes: 566e8251625304 ("net: stmmac: add a glue driver for the Amlogic Meson 8b / GXBB DWMAC") Reported-by: Emiliano Ingrassia Signed-off-by: Martin Blumenstingl Reviewed-by: Jerome Brunet Tested-by: Jerome Brunet Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/stmicro/stmmac/dwmac-meson8b.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-meson8b.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-meson8b.c index 4404650b32c5..157e12e15f28 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-meson8b.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-meson8b.c @@ -144,7 +144,9 @@ static int meson8b_init_clk(struct meson8b_dwmac *dwmac) dwmac->m250_div.shift = PRG_ETH0_CLK_M250_DIV_SHIFT; dwmac->m250_div.width = PRG_ETH0_CLK_M250_DIV_WIDTH; dwmac->m250_div.hw.init = &init; - dwmac->m250_div.flags = CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO; + dwmac->m250_div.flags = CLK_DIVIDER_ONE_BASED | + CLK_DIVIDER_ALLOW_ZERO | + CLK_DIVIDER_ROUND_CLOSEST; dwmac->m250_div_clk = devm_clk_register(dev, &dwmac->m250_div.hw); if (WARN_ON(IS_ERR(dwmac->m250_div_clk))) -- GitLab From 5bb5b9c68192b81e16eef1b7f9d4d526fe6afefe Mon Sep 17 00:00:00 2001 From: Martin Blumenstingl Date: Mon, 15 Jan 2018 18:10:15 +0100 Subject: [PATCH 0915/1635] net: stmmac: dwmac-meson8b: propagate rate changes to the parent clock [ Upstream commit fb7d38a70e1d8ffd54f7a7464dcc4889d7e490ad ] On Meson8b the only valid input clock is MPLL2. The bootloader configures that to run at 500002394Hz which cannot be divided evenly down to 125MHz using the m250_div clock. Currently the common clock framework chooses a m250_div of 2 - with the internal fixed "divide by 10" this results in a RGMII TX clock of 125001197Hz (120Hz above the requested 125MHz). Letting the common clock framework propagate the rate changes up to the parent of m250_mux allows us to get the best possible clock rate. With this patch the common clock framework calculates a rate of very-close-to-250MHz (249999701Hz to be exact) for the MPLL2 clock (which is the mux input). Dividing that by 2 (which is an internal, fixed divider for the RGMII TX clock) gives us an RGMII TX clock of 124999850Hz (which is only 150Hz off the requested 125MHz, compared to 1197Hz based on the MPLL2 rate set by u-boot and the Amlogic GPL kernel sources). SoCs from the Meson GX series are not affected by this change because the input clock is FCLK_DIV2 whose rate cannot be changed (which is fine since it's running at 1GHz, so it's already a multiple of 250MHz and 125MHz). Fixes: 566e8251625304 ("net: stmmac: add a glue driver for the Amlogic Meson 8b / GXBB DWMAC") Suggested-by: Jerome Brunet Signed-off-by: Martin Blumenstingl Reviewed-by: Jerome Brunet Tested-by: Jerome Brunet Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/stmicro/stmmac/dwmac-meson8b.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-meson8b.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-meson8b.c index 157e12e15f28..8be4b32544ef 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-meson8b.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-meson8b.c @@ -116,7 +116,7 @@ static int meson8b_init_clk(struct meson8b_dwmac *dwmac) snprintf(clk_name, sizeof(clk_name), "%s#m250_sel", dev_name(dev)); init.name = clk_name; init.ops = &clk_mux_ops; - init.flags = 0; + init.flags = CLK_SET_RATE_PARENT; init.parent_names = mux_parent_names; init.num_parents = MUX_CLK_NUM_PARENTS; -- GitLab From 58bc0fd8434d510c5e86f6739c9856b695730504 Mon Sep 17 00:00:00 2001 From: Maxime Chevallier Date: Wed, 17 Jan 2018 17:15:25 +0100 Subject: [PATCH 0916/1635] spi: a3700: Clear DATA_OUT when performing a read [ Upstream commit 44a5f423e70374e5b42cecd85e78f2d79334e0f2 ] When performing a read using FIFO mode, the spi controller shifts out the last 2 bytes that were written in a previous transfer on MOSI. This undocumented behaviour can cause devices to misinterpret the transfer, so we explicitly clear the WFIFO before each read. This behaviour was noticed on EspressoBin. Signed-off-by: Maxime Chevallier Signed-off-by: Mark Brown Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/spi/spi-armada-3700.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/spi/spi-armada-3700.c b/drivers/spi/spi-armada-3700.c index fe3fa1e8517a..4903f15177cf 100644 --- a/drivers/spi/spi-armada-3700.c +++ b/drivers/spi/spi-armada-3700.c @@ -624,6 +624,11 @@ static int a3700_spi_transfer_one(struct spi_master *master, a3700_spi_header_set(a3700_spi); if (xfer->rx_buf) { + /* Clear WFIFO, since it's last 2 bytes are shifted out during + * a read operation + */ + spireg_write(a3700_spi, A3700_SPI_DATA_OUT_REG, 0); + /* Set read data length */ spireg_write(a3700_spi, A3700_SPI_IF_DIN_CNT_REG, a3700_spi->buf_len); -- GitLab From 35ceddc59cd4f70343072247fd5b9995d8fceb87 Mon Sep 17 00:00:00 2001 From: Sagi Grimberg Date: Sun, 14 Jan 2018 17:07:50 +0200 Subject: [PATCH 0917/1635] IB/cq: Don't force IB_POLL_DIRECT poll context for ib_process_cq_direct [ Upstream commit 246d8b184c100e8eb6b4e8c88f232c2ed2a4e672 ] polling the completion queue directly does not interfere with the existing polling logic, hence drop the requirement. Be aware that running ib_process_cq_direct with non IB_POLL_DIRECT CQ may trigger concurrent CQ processing. This can be used for polling mode ULPs. Cc: Bart Van Assche Reported-by: Steve Wise Signed-off-by: Sagi Grimberg [maxg: added wcs array argument to __ib_process_cq] Signed-off-by: Max Gurtovoy Signed-off-by: Doug Ledford Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/infiniband/core/cq.c | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/drivers/infiniband/core/cq.c b/drivers/infiniband/core/cq.c index f2ae75fa3128..c8c5a5a7f433 100644 --- a/drivers/infiniband/core/cq.c +++ b/drivers/infiniband/core/cq.c @@ -25,9 +25,10 @@ #define IB_POLL_FLAGS \ (IB_CQ_NEXT_COMP | IB_CQ_REPORT_MISSED_EVENTS) -static int __ib_process_cq(struct ib_cq *cq, int budget) +static int __ib_process_cq(struct ib_cq *cq, int budget, struct ib_wc *poll_wc) { int i, n, completed = 0; + struct ib_wc *wcs = poll_wc ? : cq->wc; /* * budget might be (-1) if the caller does not @@ -35,9 +36,9 @@ static int __ib_process_cq(struct ib_cq *cq, int budget) * minimum here. */ while ((n = ib_poll_cq(cq, min_t(u32, IB_POLL_BATCH, - budget - completed), cq->wc)) > 0) { + budget - completed), wcs)) > 0) { for (i = 0; i < n; i++) { - struct ib_wc *wc = &cq->wc[i]; + struct ib_wc *wc = &wcs[i]; if (wc->wr_cqe) wc->wr_cqe->done(cq, wc); @@ -60,18 +61,20 @@ static int __ib_process_cq(struct ib_cq *cq, int budget) * @cq: CQ to process * @budget: number of CQEs to poll for * - * This function is used to process all outstanding CQ entries on a - * %IB_POLL_DIRECT CQ. It does not offload CQ processing to a different - * context and does not ask for completion interrupts from the HCA. + * This function is used to process all outstanding CQ entries. + * It does not offload CQ processing to a different context and does + * not ask for completion interrupts from the HCA. + * Using direct processing on CQ with non IB_POLL_DIRECT type may trigger + * concurrent processing. * * Note: do not pass -1 as %budget unless it is guaranteed that the number * of completions that will be processed is small. */ int ib_process_cq_direct(struct ib_cq *cq, int budget) { - WARN_ON_ONCE(cq->poll_ctx != IB_POLL_DIRECT); + struct ib_wc wcs[IB_POLL_BATCH]; - return __ib_process_cq(cq, budget); + return __ib_process_cq(cq, budget, wcs); } EXPORT_SYMBOL(ib_process_cq_direct); @@ -85,7 +88,7 @@ static int ib_poll_handler(struct irq_poll *iop, int budget) struct ib_cq *cq = container_of(iop, struct ib_cq, iop); int completed; - completed = __ib_process_cq(cq, budget); + completed = __ib_process_cq(cq, budget, NULL); if (completed < budget) { irq_poll_complete(&cq->iop); if (ib_req_notify_cq(cq, IB_POLL_FLAGS) > 0) @@ -105,7 +108,7 @@ static void ib_cq_poll_work(struct work_struct *work) struct ib_cq *cq = container_of(work, struct ib_cq, work); int completed; - completed = __ib_process_cq(cq, IB_POLL_BUDGET_WORKQUEUE); + completed = __ib_process_cq(cq, IB_POLL_BUDGET_WORKQUEUE, NULL); if (completed >= IB_POLL_BUDGET_WORKQUEUE || ib_req_notify_cq(cq, IB_POLL_FLAGS) > 0) queue_work(ib_comp_wq, &cq->work); -- GitLab From 81fbb7e26ea1068d6c7777f5c1f8d4f9b4ec68a9 Mon Sep 17 00:00:00 2001 From: Jan Chochol Date: Fri, 5 Jan 2018 08:39:12 +0100 Subject: [PATCH 0918/1635] nfs: Do not convert nfs_idmap_cache_timeout to jiffies [ Upstream commit cbebc6ef4fc830f4040d4140bf53484812d5d5d9 ] Since commit 57e62324e469 ("NFS: Store the legacy idmapper result in the keyring") nfs_idmap_cache_timeout changed units from jiffies to seconds. Unfortunately sysctl interface was not updated accordingly. As a effect updating /proc/sys/fs/nfs/idmap_cache_timeout with some value will incorrectly multiply this value by HZ. Also reading /proc/sys/fs/nfs/idmap_cache_timeout will show real value divided by HZ. Fixes: 57e62324e469 ("NFS: Store the legacy idmapper result in the keyring") Signed-off-by: Jan Chochol Signed-off-by: Trond Myklebust Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- fs/nfs/nfs4sysctl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/nfs/nfs4sysctl.c b/fs/nfs/nfs4sysctl.c index 0d91d84e5822..c394e4447100 100644 --- a/fs/nfs/nfs4sysctl.c +++ b/fs/nfs/nfs4sysctl.c @@ -32,7 +32,7 @@ static struct ctl_table nfs4_cb_sysctls[] = { .data = &nfs_idmap_cache_timeout, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = proc_dointvec_jiffies, + .proc_handler = proc_dointvec, }, { } }; -- GitLab From c212c855a09d826b95eb18d5adf04f4c65ecb8ca Mon Sep 17 00:00:00 2001 From: James Hogan Date: Tue, 16 Jan 2018 21:38:24 +0000 Subject: [PATCH 0919/1635] MIPS: Fix clean of vmlinuz.{32,ecoff,bin,srec} [ Upstream commit 5f2483eb2423152445b39f2db59d372f523e664e ] Make doesn't expand shell style "vmlinuz.{32,ecoff,bin,srec}" to the 4 separate files, so none of these files get cleaned up by make clean. List the files separately instead. Fixes: ec3352925b74 ("MIPS: Remove all generated vmlinuz* files on "make clean"") Signed-off-by: James Hogan Cc: Ralf Baechle Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/18491/ Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/mips/boot/compressed/Makefile | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/arch/mips/boot/compressed/Makefile b/arch/mips/boot/compressed/Makefile index c675eece389a..adce180f3ee4 100644 --- a/arch/mips/boot/compressed/Makefile +++ b/arch/mips/boot/compressed/Makefile @@ -133,4 +133,8 @@ vmlinuz.srec: vmlinuz uzImage.bin: vmlinuz.bin FORCE $(call if_changed,uimage,none) -clean-files := $(objtree)/vmlinuz $(objtree)/vmlinuz.{32,ecoff,bin,srec} +clean-files += $(objtree)/vmlinuz +clean-files += $(objtree)/vmlinuz.32 +clean-files += $(objtree)/vmlinuz.ecoff +clean-files += $(objtree)/vmlinuz.bin +clean-files += $(objtree)/vmlinuz.srec -- GitLab From ebf5ffca1bf2be571544befa56e37723e8b8356f Mon Sep 17 00:00:00 2001 From: Niklas Cassel Date: Fri, 19 Jan 2018 10:39:06 +0100 Subject: [PATCH 0920/1635] PCI: Add dummy pci_irqd_intx_xlate() for CONFIG_PCI=n build [ Upstream commit 80db6f08b7af93eddc9487535e6150b220262637 ] Some hardware can operate in either "host" or "endpoint" mode, which means there can be both a host bridge driver and an endpoint driver for the same device. Those drivers share a lot of code, so sometimes they live in the same source file. The host bridge driver requires CONFIG_PCI=y because it enumerates PCI devices below the bridge using the PCI core. The endpoint driver does not require CONFIG_PCI=y because it runs in an embedded kernel on the other side of the device, e.g., on an adapter card. pci-dra7xx.c contains both host and endpoint drivers. If we select only the endpoint driver (CONFIG_PCI=n and CONFIG_PCI_DRA7XX_EP=y), the unneeded host driver is still compiled. It references pci_irqd_intx_xlate(), which is not present when CONFIG_PCI=n, which causes this error: drivers/pci/dwc/pci-dra7xx.c:229:11: error: 'pci_irqd_intx_xlate' undeclared here (not in a function) Add a dummy pci_irqd_intx_xlate() for the CONFIG_PCI=n case. [bhelgaas: changelog] Signed-off-by: Niklas Cassel Signed-off-by: Bjorn Helgaas Acked-by: Arnd Bergmann Acked-by: Lorenzo Pieralisi Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- include/linux/pci.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/include/linux/pci.h b/include/linux/pci.h index d16a7c037ec0..727e309baa5e 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -1688,6 +1688,13 @@ static inline int pci_get_new_domain_nr(void) { return -ENOSYS; } #define dev_is_pf(d) (false) static inline bool pci_acs_enabled(struct pci_dev *pdev, u16 acs_flags) { return false; } +static inline int pci_irqd_intx_xlate(struct irq_domain *d, + struct device_node *node, + const u32 *intspec, + unsigned int intsize, + unsigned long *out_hwirq, + unsigned int *out_type) +{ return -EINVAL; } #endif /* CONFIG_PCI */ /* Include architecture-dependent settings and functions */ -- GitLab From 9f2df99f9eb020a1fa4fceb460d9a494c3b33341 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Sun, 24 Dec 2017 13:04:07 -0800 Subject: [PATCH 0921/1635] watchdog: sp5100_tco: Fix watchdog disable bit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit f541c09ebfc61697b586b38c9ebaf4b70defb278 ] According to all published information, the watchdog disable bit for SB800 compatible controllers is bit 1 of PM register 0x48, not bit 2. For the most part that doesn't matter in practice, since the bit has to be cleared to enable watchdog address decoding, which is the default setting, but it still needs to be fixed. Cc: Zoltán Böszörményi Signed-off-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/watchdog/sp5100_tco.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/watchdog/sp5100_tco.h b/drivers/watchdog/sp5100_tco.h index 1af4dee71337..0e242d1110ce 100644 --- a/drivers/watchdog/sp5100_tco.h +++ b/drivers/watchdog/sp5100_tco.h @@ -55,7 +55,7 @@ #define SB800_PM_WATCHDOG_CONFIG 0x4C #define SB800_PCI_WATCHDOG_DECODE_EN (1 << 0) -#define SB800_PM_WATCHDOG_DISABLE (1 << 2) +#define SB800_PM_WATCHDOG_DISABLE (1 << 1) #define SB800_PM_WATCHDOG_SECOND_RES (3 << 0) #define SB800_ACPI_MMIO_DECODE_EN (1 << 0) #define SB800_ACPI_MMIO_SEL (1 << 1) -- GitLab From 8bf116b258c286137635542a752ec68ffebd809b Mon Sep 17 00:00:00 2001 From: Ulf Magnusson Date: Sun, 8 Oct 2017 19:11:21 +0200 Subject: [PATCH 0922/1635] kconfig: Don't leak main menus during parsing [ Upstream commit 0724a7c32a54e3e50d28e19e30c59014f61d4e2c ] If a 'mainmenu' entry appeared in the Kconfig files, two things would leak: - The 'struct property' allocated for the default "Linux Kernel Configuration" prompt. - The string for the T_WORD/T_WORD_QUOTE prompt after the T_MAINMENU token, allocated on the heap in zconf.l. To fix it, introduce a new 'no_mainmenu_stmt' nonterminal that matches if there's no 'mainmenu' and adds the default prompt. That means the prompt only gets allocated once regardless of whether there's a 'mainmenu' statement or not, and managing it becomes simple. Summary from Valgrind on 'menuconfig' (ARCH=x86) before the fix: LEAK SUMMARY: definitely lost: 344,568 bytes in 14,352 blocks ... Summary after the fix: LEAK SUMMARY: definitely lost: 344,440 bytes in 14,350 blocks ... Signed-off-by: Ulf Magnusson Signed-off-by: Masahiro Yamada Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- scripts/kconfig/zconf.y | 33 ++++++++++++++++++++++++--------- 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/scripts/kconfig/zconf.y b/scripts/kconfig/zconf.y index c8f396c3b190..20d9caa4be99 100644 --- a/scripts/kconfig/zconf.y +++ b/scripts/kconfig/zconf.y @@ -108,7 +108,27 @@ static struct menu *current_menu, *current_entry; %% input: nl start | start; -start: mainmenu_stmt stmt_list | stmt_list; +start: mainmenu_stmt stmt_list | no_mainmenu_stmt stmt_list; + +/* mainmenu entry */ + +mainmenu_stmt: T_MAINMENU prompt nl +{ + menu_add_prompt(P_MENU, $2, NULL); +}; + +/* Default main menu, if there's no mainmenu entry */ + +no_mainmenu_stmt: /* empty */ +{ + /* + * Hack: Keep the main menu title on the heap so we can safely free it + * later regardless of whether it comes from the 'prompt' in + * mainmenu_stmt or here + */ + menu_add_prompt(P_MENU, strdup("Linux Kernel Configuration"), NULL); +}; + stmt_list: /* empty */ @@ -351,13 +371,6 @@ if_block: | if_block choice_stmt ; -/* mainmenu entry */ - -mainmenu_stmt: T_MAINMENU prompt nl -{ - menu_add_prompt(P_MENU, $2, NULL); -}; - /* menu entry */ menu: T_MENU prompt T_EOL @@ -502,6 +515,7 @@ word_opt: /* empty */ { $$ = NULL; } void conf_parse(const char *name) { + const char *tmp; struct symbol *sym; int i; @@ -509,7 +523,6 @@ void conf_parse(const char *name) sym_init(); _menu_init(); - rootmenu.prompt = menu_add_prompt(P_MENU, "Linux Kernel Configuration", NULL); if (getenv("ZCONF_DEBUG")) zconfdebug = 1; @@ -519,8 +532,10 @@ void conf_parse(const char *name) if (!modules_sym) modules_sym = sym_find( "n" ); + tmp = rootmenu.prompt->text; rootmenu.prompt->text = _(rootmenu.prompt->text); rootmenu.prompt->text = sym_expand_string_value(rootmenu.prompt->text); + free((char*)tmp); menu_finalize(&rootmenu); for_all_symbols(i, sym) { -- GitLab From 0f511f3dda8c6fb2c799eab22acfb39056047a49 Mon Sep 17 00:00:00 2001 From: Ulf Magnusson Date: Sun, 8 Oct 2017 19:35:44 +0200 Subject: [PATCH 0923/1635] kconfig: Fix automatic menu creation mem leak [ Upstream commit ae7440ef0c8013d68c00dad6900e7cce5311bb1c ] expr_trans_compare() always allocates and returns a new expression, giving the following leak outline: ... *Allocate* basedep = expr_trans_compare(basedep, E_UNEQUAL, &symbol_no); ... for (menu = parent->next; menu; menu = menu->next) { ... *Copy* dep2 = expr_copy(basedep); ... *Free copy* expr_free(dep2); } *basedep lost!* Fix by freeing 'basedep' after the loop. Summary from Valgrind on 'menuconfig' (ARCH=x86) before the fix: LEAK SUMMARY: definitely lost: 344,376 bytes in 14,349 blocks ... Summary after the fix: LEAK SUMMARY: definitely lost: 44,448 bytes in 1,852 blocks ... Signed-off-by: Ulf Magnusson Signed-off-by: Masahiro Yamada Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- scripts/kconfig/menu.c | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/kconfig/menu.c b/scripts/kconfig/menu.c index e9357931b47d..749c2bd5fc51 100644 --- a/scripts/kconfig/menu.c +++ b/scripts/kconfig/menu.c @@ -372,6 +372,7 @@ void menu_finalize(struct menu *parent) menu->parent = parent; last_menu = menu; } + expr_free(basedep); if (last_menu) { parent->list = parent->next; parent->next = last_menu->next; -- GitLab From 18004e6f26ec406ee762fd3f8cceaf4ab5acde41 Mon Sep 17 00:00:00 2001 From: Ulf Magnusson Date: Sun, 8 Oct 2017 19:35:45 +0200 Subject: [PATCH 0924/1635] kconfig: Fix expr_free() E_NOT leak [ Upstream commit 5b1374b3b3c2fc4f63a398adfa446fb8eff791a4 ] Only the E_NOT operand and not the E_NOT node itself was freed, due to accidentally returning too early in expr_free(). Outline of leak: switch (e->type) { ... case E_NOT: expr_free(e->left.expr); return; ... } *Never reached, 'e' leaked* free(e); Fix by changing the 'return' to a 'break'. Summary from Valgrind on 'menuconfig' (ARCH=x86) before the fix: LEAK SUMMARY: definitely lost: 44,448 bytes in 1,852 blocks ... Summary after the fix: LEAK SUMMARY: definitely lost: 1,608 bytes in 67 blocks ... Signed-off-by: Ulf Magnusson Signed-off-by: Masahiro Yamada Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- scripts/kconfig/expr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/kconfig/expr.c b/scripts/kconfig/expr.c index cbf4996dd9c1..ed29bad1f03a 100644 --- a/scripts/kconfig/expr.c +++ b/scripts/kconfig/expr.c @@ -113,7 +113,7 @@ void expr_free(struct expr *e) break; case E_NOT: expr_free(e->left.expr); - return; + break; case E_EQUAL: case E_GEQ: case E_GTH: -- GitLab From afadc440a1cc08895f451b4a9db551a45f2a1a21 Mon Sep 17 00:00:00 2001 From: "weiyongjun (A)" Date: Thu, 18 Jan 2018 02:23:34 +0000 Subject: [PATCH 0925/1635] mac80211_hwsim: fix possible memory leak in hwsim_new_radio_nl() [ Upstream commit 0ddcff49b672239dda94d70d0fcf50317a9f4b51 ] 'hwname' is malloced in hwsim_new_radio_nl() and should be freed before leaving from the error handling cases, otherwise it will cause memory leak. Fixes: ff4dd73dd2b4 ("mac80211_hwsim: check HWSIM_ATTR_RADIO_NAME length") Signed-off-by: Wei Yongjun Reviewed-by: Ben Hutchings Signed-off-by: Johannes Berg Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/mac80211_hwsim.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index d148dbf3beeb..977fd7aa2082 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -3153,8 +3153,10 @@ static int hwsim_new_radio_nl(struct sk_buff *msg, struct genl_info *info) if (info->attrs[HWSIM_ATTR_REG_CUSTOM_REG]) { u32 idx = nla_get_u32(info->attrs[HWSIM_ATTR_REG_CUSTOM_REG]); - if (idx >= ARRAY_SIZE(hwsim_world_regdom_custom)) + if (idx >= ARRAY_SIZE(hwsim_world_regdom_custom)) { + kfree(hwname); return -EINVAL; + } param.regd = hwsim_world_regdom_custom[idx]; } -- GitLab From fb5d97a19fc39d9fd5238af989a45cc56b4c2b9a Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Thu, 18 Jan 2018 01:43:19 +0000 Subject: [PATCH 0926/1635] ipmi/powernv: Fix error return code in ipmi_powernv_probe() [ Upstream commit e749d328b0b450aa78d562fa26a0cd8872325dd9 ] Fix to return a negative error code from the request_irq() error handling case instead of 0, as done elsewhere in this function. Fixes: dce143c3381c ("ipmi/powernv: Convert to irq event interface") Signed-off-by: Wei Yongjun Reviewed-by: Alexey Kardashevskiy Signed-off-by: Corey Minyard Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/char/ipmi/ipmi_powernv.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/char/ipmi/ipmi_powernv.c b/drivers/char/ipmi/ipmi_powernv.c index b338a4becbf8..845efa0f724f 100644 --- a/drivers/char/ipmi/ipmi_powernv.c +++ b/drivers/char/ipmi/ipmi_powernv.c @@ -251,8 +251,9 @@ static int ipmi_powernv_probe(struct platform_device *pdev) ipmi->irq = opal_event_request(prop); } - if (request_irq(ipmi->irq, ipmi_opal_event, IRQ_TYPE_LEVEL_HIGH, - "opal-ipmi", ipmi)) { + rc = request_irq(ipmi->irq, ipmi_opal_event, IRQ_TYPE_LEVEL_HIGH, + "opal-ipmi", ipmi); + if (rc) { dev_warn(dev, "Unable to request irq\n"); goto err_dispose; } -- GitLab From a4909c8518f79875e06d4903d249f2524126c2cd Mon Sep 17 00:00:00 2001 From: Liu Bo Date: Wed, 15 Nov 2017 16:10:28 -0700 Subject: [PATCH 0927/1635] Btrfs: set plug for fsync [ Upstream commit 343e4fc1c60971b0734de26dbbd475d433950982 ] Setting plug can merge adjacent IOs before dispatching IOs to the disk driver. Without plug, it'd not be a problem for single disk usecases, but for multiple disks using raid profile, a large IO can be split to several IOs of stripe length, and plug can be helpful to bring them together for each disk so that we can save several disk access. Moreover, fsync issues synchronous writes, so plug can really take effect. Signed-off-by: Liu Bo Reviewed-by: David Sterba Signed-off-by: David Sterba Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- fs/btrfs/file.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c index d564a7049d7f..5690feded0de 100644 --- a/fs/btrfs/file.c +++ b/fs/btrfs/file.c @@ -2018,10 +2018,19 @@ int btrfs_release_file(struct inode *inode, struct file *filp) static int start_ordered_ops(struct inode *inode, loff_t start, loff_t end) { int ret; + struct blk_plug plug; + /* + * This is only called in fsync, which would do synchronous writes, so + * a plug can merge adjacent IOs as much as possible. Esp. in case of + * multiple disks using raid profile, a large IO can be split to + * several segments of stripe length (currently 64K). + */ + blk_start_plug(&plug); atomic_inc(&BTRFS_I(inode)->sync_writers); ret = btrfs_fdatawrite_range(inode, start, end); atomic_dec(&BTRFS_I(inode)->sync_writers); + blk_finish_plug(&plug); return ret; } -- GitLab From db6d651eccded6fe512f0ed02347e0638dd95296 Mon Sep 17 00:00:00 2001 From: Nikolay Borisov Date: Tue, 12 Dec 2017 11:14:49 +0200 Subject: [PATCH 0928/1635] btrfs: Fix out of bounds access in btrfs_search_slot [ Upstream commit 9ea2c7c9da13c9073e371c046cbbc45481ecb459 ] When modifying a tree where the root is at BTRFS_MAX_LEVEL - 1 then the level variable is going to be 7 (this is the max height of the tree). On the other hand btrfs_cow_block is always called with "level + 1" as an index into the nodes and slots arrays. This leads to an out of bounds access. Admittdely this will be benign since an OOB access of the nodes array will likely read the 0th element from the slots array, which in this case is going to be 0 (since we start CoW at the top of the tree). The OOB access into the slots array in turn will read the 0th and 1st values of the locks array, which would both be 0 at the time. However, this benign behavior relies on the fact that the path being passed hasn't been initialised, if it has already been used to query a btree then it could potentially have populated the nodes/slots arrays. Fix it by explicitly checking if we are at level 7 (the maximum allowed index in nodes/slots arrays) and explicitly call the CoW routine with NULL for parent's node/slot. Signed-off-by: Nikolay Borisov Fixes-coverity-id: 711515 Reviewed-by: David Sterba Signed-off-by: David Sterba Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- fs/btrfs/ctree.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c index e2bb2a065741..21cc27509993 100644 --- a/fs/btrfs/ctree.c +++ b/fs/btrfs/ctree.c @@ -2774,6 +2774,8 @@ int btrfs_search_slot(struct btrfs_trans_handle *trans, struct btrfs_root *root, * contention with the cow code */ if (cow) { + bool last_level = (level == (BTRFS_MAX_LEVEL - 1)); + /* * if we don't really need to cow this block * then we don't want to set the path blocking, @@ -2798,9 +2800,13 @@ int btrfs_search_slot(struct btrfs_trans_handle *trans, struct btrfs_root *root, } btrfs_set_path_blocking(p); - err = btrfs_cow_block(trans, root, b, - p->nodes[level + 1], - p->slots[level + 1], &b); + if (last_level) + err = btrfs_cow_block(trans, root, b, NULL, 0, + &b); + else + err = btrfs_cow_block(trans, root, b, + p->nodes[level + 1], + p->slots[level + 1], &b); if (err) { ret = err; goto done; -- GitLab From d91bb7c6988bd6450284c762b33f2e1ea3fe7c97 Mon Sep 17 00:00:00 2001 From: Liu Bo Date: Tue, 2 Jan 2018 13:36:41 -0700 Subject: [PATCH 0929/1635] Btrfs: fix scrub to repair raid6 corruption [ Upstream commit 762221f095e3932669093466aaf4b85ed9ad2ac1 ] The raid6 corruption is that, suppose that all disks can be read without problems and if the content that was read out doesn't match its checksum, currently for raid6 btrfs at most retries twice, - the 1st retry is to rebuild with all other stripes, it'll eventually be a raid5 xor rebuild, - if the 1st fails, the 2nd retry will deliberately fail parity p so that it will do raid6 style rebuild, however, the chances are that another non-parity stripe content also has something corrupted, so that the above retries are not able to return correct content. We've fixed normal reads to rebuild raid6 correctly with more retries in Patch "Btrfs: make raid6 rebuild retry more"[1], this is to fix scrub to do the exactly same rebuild process. [1]: https://patchwork.kernel.org/patch/10091755/ Signed-off-by: Liu Bo Signed-off-by: David Sterba Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- fs/btrfs/raid56.c | 18 ++++++++++++++---- fs/btrfs/volumes.c | 9 ++++++++- 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/fs/btrfs/raid56.c b/fs/btrfs/raid56.c index 32b186c5694c..dcab41157899 100644 --- a/fs/btrfs/raid56.c +++ b/fs/btrfs/raid56.c @@ -2159,11 +2159,21 @@ int raid56_parity_recover(struct btrfs_fs_info *fs_info, struct bio *bio, } /* - * reconstruct from the q stripe if they are - * asking for mirror 3 + * Loop retry: + * for 'mirror == 2', reconstruct from all other stripes. + * for 'mirror_num > 2', select a stripe to fail on every retry. */ - if (mirror_num == 3) - rbio->failb = rbio->real_stripes - 2; + if (mirror_num > 2) { + /* + * 'mirror == 3' is to fail the p stripe and + * reconstruct from the q stripe. 'mirror > 3' is to + * fail a data stripe and reconstruct from p+q stripe. + */ + rbio->failb = rbio->real_stripes - (mirror_num - 1); + ASSERT(rbio->failb > 0); + if (rbio->failb <= rbio->faila) + rbio->failb--; + } ret = lock_stripe_add(rbio); diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index 71b3cd634436..b983e7fb200b 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -5101,7 +5101,14 @@ int btrfs_num_copies(struct btrfs_fs_info *fs_info, u64 logical, u64 len) else if (map->type & BTRFS_BLOCK_GROUP_RAID5) ret = 2; else if (map->type & BTRFS_BLOCK_GROUP_RAID6) - ret = 3; + /* + * There could be two corrupted data stripes, we need + * to loop retry in order to rebuild the correct data. + * + * Fail a stripe at a time on every retry except the + * stripe under reconstruction. + */ + ret = map->num_stripes; else ret = 1; free_extent_map(em); -- GitLab From c231cec825a9d72642b712b6b62bb9c99b7407fd Mon Sep 17 00:00:00 2001 From: Anand Jain Date: Tue, 9 Jan 2018 09:05:43 +0800 Subject: [PATCH 0930/1635] btrfs: fail mount when sb flag is not in BTRFS_SUPER_FLAG_SUPP [ Upstream commit 6f794e3c5c8f8fdd3b5bb20d9ded894e685b5bbe ] It appears from the original commit [1] that there isn't any design specific reason not to fail the mount instead of just warning. This patch will change it to fail. [1] commit 319e4d0661e5323c9f9945f0f8fb5905e5fe74c3 btrfs: Enhance super validation check Fixes: 319e4d0661e5323 ("btrfs: Enhance super validation check") Signed-off-by: Anand Jain Reviewed-by: Qu Wenruo Reviewed-by: David Sterba Signed-off-by: David Sterba Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- fs/btrfs/disk-io.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index 167ce43cabe8..79f0f282a0ef 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -4063,9 +4063,11 @@ static int btrfs_check_super_valid(struct btrfs_fs_info *fs_info) btrfs_err(fs_info, "no valid FS found"); ret = -EINVAL; } - if (btrfs_super_flags(sb) & ~BTRFS_SUPER_FLAG_SUPP) - btrfs_warn(fs_info, "unrecognized super flag: %llu", + if (btrfs_super_flags(sb) & ~BTRFS_SUPER_FLAG_SUPP) { + btrfs_err(fs_info, "unrecognized or unsupported super flag: %llu", btrfs_super_flags(sb) & ~BTRFS_SUPER_FLAG_SUPP); + ret = -EINVAL; + } if (btrfs_super_root_level(sb) >= BTRFS_MAX_LEVEL) { btrfs_err(fs_info, "tree_root level too big: %d >= %d", btrfs_super_root_level(sb), BTRFS_MAX_LEVEL); -- GitLab From ebe064401f078ae68f2532833ad8f212b6ee2be2 Mon Sep 17 00:00:00 2001 From: Liu Bo Date: Fri, 5 Jan 2018 12:51:09 -0700 Subject: [PATCH 0931/1635] Btrfs: fix unexpected EEXIST from btrfs_get_extent [ Upstream commit 18e83ac75bfe67009c4ddcdd581bba8eb16f4030 ] This fixes a corner case that is caused by a race of dio write vs dio read/write. Here is how the race could happen. Suppose that no extent map has been loaded into memory yet. There is a file extent [0, 32K), two jobs are running concurrently against it, t1 is doing dio write to [8K, 32K) and t2 is doing dio read from [0, 4K) or [4K, 8K). t1 goes ahead of t2 and splits em [0, 32K) to em [0K, 8K) and [8K 32K). ------------------------------------------------------ t1 t2 btrfs_get_blocks_direct() btrfs_get_blocks_direct() -> btrfs_get_extent() -> btrfs_get_extent() -> lookup_extent_mapping() -> add_extent_mapping() -> lookup_extent_mapping() # load [0, 32K) -> btrfs_new_extent_direct() -> btrfs_drop_extent_cache() # split [0, 32K) and # drop [8K, 32K) -> add_extent_mapping() # add [8K, 32K) -> add_extent_mapping() # handle -EEXIST when adding # [0, 32K) ------------------------------------------------------ About how t2(dio read/write) runs into -EEXIST: a) add_extent_mapping() gets -EEXIST for adding em [0, 32k), b) search_extent_mapping() then returns [0, 8k) as the existing em, even though start == existing->start, em is [0, 32k) so that extent_map_end(em) > extent_map_end(existing), i.e. 32k > 8k, c) then it goes thru merge_extent_mapping() which tries to add a [8k, 8k) (with a length 0) and returns -EEXIST as [8k, 32k) is already in tree, d) so btrfs_get_extent() ends up returning -EEXIST to dio read/write, which is confusing applications. Here I conclude all the possible situations, 1) start < existing->start +-----------+em+-----------+ +--prev---+ | +-------------+ | | | | | | | +---------+ + +---+existing++ ++ + | + start 2) start == existing->start +------------em------------+ | +-------------+ | | | | | + +----existing-+ + | | + start 3) start > existing->start && start < (existing->start + existing->len) +------------em------------+ | +-------------+ | | | | | + +----existing-+ + | | + start 4) start >= (existing->start + existing->len) +-----------+em+-----------+ | +-------------+ | +--next---+ | | | | | | + +---+existing++ + +---------+ + | + start As we can see, it turns out that if start is within existing em (front inclusive), then the existing em should be returned as is, otherwise, we try our best to merge candidate em with sibling ems to form a larger em (in order to reduce the total number of em). Reported-by: David Vallender Signed-off-by: Liu Bo Reviewed-by: Josef Bacik Signed-off-by: David Sterba Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- fs/btrfs/inode.c | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 768661aa885c..9f21c29d0259 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -7265,19 +7265,12 @@ struct extent_map *btrfs_get_extent(struct btrfs_inode *inode, * existing will always be non-NULL, since there must be * extent causing the -EEXIST. */ - if (existing->start == em->start && - extent_map_end(existing) >= extent_map_end(em) && - em->block_start == existing->block_start) { - /* - * The existing extent map already encompasses the - * entire extent map we tried to add. - */ + if (start >= existing->start && + start < extent_map_end(existing)) { free_extent_map(em); em = existing; err = 0; - - } else if (start >= extent_map_end(existing) || - start <= existing->start) { + } else { /* * The existing extent map is the one nearest to * the [start, start + len) range which overlaps @@ -7289,10 +7282,6 @@ struct extent_map *btrfs_get_extent(struct btrfs_inode *inode, free_extent_map(em); em = NULL; } - } else { - free_extent_map(em); - em = existing; - err = 0; } } write_unlock(&em_tree->lock); -- GitLab From 48b8839d91a49cde35ddab422a99ef908391aeee Mon Sep 17 00:00:00 2001 From: Liu Bo Date: Tue, 9 Jan 2018 18:36:25 -0700 Subject: [PATCH 0932/1635] Btrfs: raid56: fix race between merge_bio and rbio_orig_end_io MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit 7583d8d088ff2c323b1d4f15b191ca2c23d32558 ] Before rbio_orig_end_io() goes to free rbio, rbio may get merged with more bios from other rbios and rbio->bio_list becomes non-empty, in that case, these newly merged bios don't end properly. Once unlock_stripe() is done, rbio->bio_list will not be updated any more and we can call bio_endio() on all queued bios. It should only happen in error-out cases, the normal path of recover and full stripe write have already set RBIO_RMW_LOCKED_BIT to disable merge before doing IO, so rbio_orig_end_io() called by them doesn't have the above issue. Reported-by: Jérôme Carretero Signed-off-by: Liu Bo Signed-off-by: David Sterba Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- fs/btrfs/raid56.c | 37 +++++++++++++++++++++++++------------ 1 file changed, 25 insertions(+), 12 deletions(-) diff --git a/fs/btrfs/raid56.c b/fs/btrfs/raid56.c index dcab41157899..2e995e565633 100644 --- a/fs/btrfs/raid56.c +++ b/fs/btrfs/raid56.c @@ -858,10 +858,17 @@ static void __free_raid_bio(struct btrfs_raid_bio *rbio) kfree(rbio); } -static void free_raid_bio(struct btrfs_raid_bio *rbio) +static void rbio_endio_bio_list(struct bio *cur, blk_status_t err) { - unlock_stripe(rbio); - __free_raid_bio(rbio); + struct bio *next; + + while (cur) { + next = cur->bi_next; + cur->bi_next = NULL; + cur->bi_status = err; + bio_endio(cur); + cur = next; + } } /* @@ -871,20 +878,26 @@ static void free_raid_bio(struct btrfs_raid_bio *rbio) static void rbio_orig_end_io(struct btrfs_raid_bio *rbio, blk_status_t err) { struct bio *cur = bio_list_get(&rbio->bio_list); - struct bio *next; + struct bio *extra; if (rbio->generic_bio_cnt) btrfs_bio_counter_sub(rbio->fs_info, rbio->generic_bio_cnt); - free_raid_bio(rbio); + /* + * At this moment, rbio->bio_list is empty, however since rbio does not + * always have RBIO_RMW_LOCKED_BIT set and rbio is still linked on the + * hash list, rbio may be merged with others so that rbio->bio_list + * becomes non-empty. + * Once unlock_stripe() is done, rbio->bio_list will not be updated any + * more and we can call bio_endio() on all queued bios. + */ + unlock_stripe(rbio); + extra = bio_list_get(&rbio->bio_list); + __free_raid_bio(rbio); - while (cur) { - next = cur->bi_next; - cur->bi_next = NULL; - cur->bi_status = err; - bio_endio(cur); - cur = next; - } + rbio_endio_bio_list(cur, err); + if (extra) + rbio_endio_bio_list(extra, err); } /* -- GitLab From 889177d172d3a1879742cdd17debbbeb300ca1b5 Mon Sep 17 00:00:00 2001 From: Parav Pandit Date: Tue, 9 Jan 2018 15:58:54 +0200 Subject: [PATCH 0933/1635] RDMA/cma: Check existence of netdevice during port validation [ Upstream commit 00db63c128dd3daf38f481371976c24d32678142 ] If valid netdevice is not found for RoCE, GID table should not be searched with NULL netdevice. Doing so causes the search routines to ignore the netdev argument and may match the wrong GID table entry if the netdev is deleted. Fixes: abae1b71dd37 ("IB/cma: cma_validate_port should verify the port and netdevice") Signed-off-by: Parav Pandit Reviewed-by: Mark Bloch Signed-off-by: Leon Romanovsky Signed-off-by: Jason Gunthorpe Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/infiniband/core/cma.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c index 25de7cc9f49f..6c725c435f5d 100644 --- a/drivers/infiniband/core/cma.c +++ b/drivers/infiniband/core/cma.c @@ -624,11 +624,13 @@ static inline int cma_validate_port(struct ib_device *device, u8 port, if ((dev_type != ARPHRD_INFINIBAND) && rdma_protocol_ib(device, port)) return ret; - if (dev_type == ARPHRD_ETHER && rdma_protocol_roce(device, port)) + if (dev_type == ARPHRD_ETHER && rdma_protocol_roce(device, port)) { ndev = dev_get_by_index(&init_net, bound_if_index); - else + if (!ndev) + return ret; + } else { gid_type = IB_GID_TYPE_IB; - + } ret = ib_find_cached_gid_by_port(device, gid, gid_type, port, ndev, NULL); -- GitLab From a09881cfb7135787375a3975cbd05bc94e07a0d0 Mon Sep 17 00:00:00 2001 From: Sheng Yong Date: Wed, 17 Jan 2018 12:11:31 +0800 Subject: [PATCH 0934/1635] f2fs: avoid hungtask when GC encrypted block if io_bits is set [ Upstream commit a9d572c7550044d5b217b5287d99a2e6d34b97b0 ] When io_bits is set, GCing encrypted block may hit the following hungtask. Since io_bits requires aligned block address, f2fs_submit_page_write may return -EAGAIN if new_blkaddr does not satisify io_bits alignment. As a result, the encrypted page will never be writtenback. This patch makes move_data_block aware the EAGAIN error and cancel the writeback. [ 246.751371] INFO: task kworker/u4:4:797 blocked for more than 90 seconds. [ 246.752423] Not tainted 4.15.0-rc4+ #11 [ 246.754176] "echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message. [ 246.755336] kworker/u4:4 D25448 797 2 0x80000000 [ 246.755597] Workqueue: writeback wb_workfn (flush-7:0) [ 246.755616] Call Trace: [ 246.755695] ? __schedule+0x322/0xa90 [ 246.755761] ? blk_init_request_from_bio+0x120/0x120 [ 246.755773] ? pci_mmcfg_check_reserved+0xb0/0xb0 [ 246.755801] ? __radix_tree_create+0x19e/0x200 [ 246.755813] ? delete_node+0x136/0x370 [ 246.755838] schedule+0x43/0xc0 [ 246.755904] io_schedule+0x17/0x40 [ 246.755939] wait_on_page_bit_common+0x17b/0x240 [ 246.755950] ? wake_page_function+0xa0/0xa0 [ 246.755961] ? add_to_page_cache_lru+0x160/0x160 [ 246.755972] ? page_cache_tree_insert+0x170/0x170 [ 246.755983] ? __lru_cache_add+0x96/0xb0 [ 246.756086] __filemap_fdatawait_range+0x14f/0x1c0 [ 246.756097] ? wait_on_page_bit_common+0x240/0x240 [ 246.756120] ? __wake_up_locked_key_bookmark+0x20/0x20 [ 246.756167] ? wait_on_all_pages_writeback+0xc9/0x100 [ 246.756179] ? __remove_ino_entry+0x120/0x120 [ 246.756192] ? wait_woken+0x100/0x100 [ 246.756204] filemap_fdatawait_range+0x9/0x20 [ 246.756216] write_checkpoint+0x18a1/0x1f00 [ 246.756254] ? blk_get_request+0x10/0x10 [ 246.756265] ? cpumask_next_and+0x43/0x60 [ 246.756279] ? f2fs_sync_inode_meta+0x160/0x160 [ 246.756289] ? remove_element.isra.4+0xa0/0xa0 [ 246.756300] ? __put_compound_page+0x40/0x40 [ 246.756310] ? f2fs_sync_fs+0xec/0x1c0 [ 246.756320] ? f2fs_sync_fs+0x120/0x1c0 [ 246.756329] f2fs_sync_fs+0x120/0x1c0 [ 246.756357] ? trace_event_raw_event_f2fs__page+0x260/0x260 [ 246.756393] ? ata_build_rw_tf+0x173/0x410 [ 246.756397] f2fs_balance_fs_bg+0x198/0x390 [ 246.756405] ? drop_inmem_page+0x230/0x230 [ 246.756415] ? ahci_qc_prep+0x1bb/0x2e0 [ 246.756418] ? ahci_qc_issue+0x1df/0x290 [ 246.756422] ? __accumulate_pelt_segments+0x42/0xd0 [ 246.756426] ? f2fs_write_node_pages+0xd1/0x380 [ 246.756429] f2fs_write_node_pages+0xd1/0x380 [ 246.756437] ? sync_node_pages+0x8f0/0x8f0 [ 246.756440] ? update_curr+0x53/0x220 [ 246.756444] ? __accumulate_pelt_segments+0xa2/0xd0 [ 246.756448] ? __update_load_avg_se.isra.39+0x349/0x360 [ 246.756452] ? do_writepages+0x2a/0xa0 [ 246.756456] do_writepages+0x2a/0xa0 [ 246.756460] __writeback_single_inode+0x70/0x490 [ 246.756463] ? check_preempt_wakeup+0x199/0x310 [ 246.756467] writeback_sb_inodes+0x2a2/0x660 [ 246.756471] ? is_empty_dir_inode+0x40/0x40 [ 246.756474] ? __writeback_single_inode+0x490/0x490 [ 246.756477] ? string+0xbf/0xf0 [ 246.756480] ? down_read_trylock+0x35/0x60 [ 246.756484] __writeback_inodes_wb+0x9f/0xf0 [ 246.756488] wb_writeback+0x41d/0x4b0 [ 246.756492] ? writeback_inodes_wb.constprop.55+0x150/0x150 [ 246.756498] ? set_worker_desc+0xf7/0x130 [ 246.756502] ? current_is_workqueue_rescuer+0x60/0x60 [ 246.756511] ? _find_next_bit+0x2c/0xa0 [ 246.756514] ? wb_workfn+0x400/0x5d0 [ 246.756518] wb_workfn+0x400/0x5d0 [ 246.756521] ? finish_task_switch+0xdf/0x2a0 [ 246.756525] ? inode_wait_for_writeback+0x30/0x30 [ 246.756529] process_one_work+0x3a7/0x6f0 [ 246.756533] worker_thread+0x82/0x750 [ 246.756537] kthread+0x16f/0x1c0 [ 246.756541] ? trace_event_raw_event_workqueue_work+0x110/0x110 [ 246.756544] ? kthread_create_worker_on_cpu+0xb0/0xb0 [ 246.756548] ret_from_fork+0x1f/0x30 Signed-off-by: Sheng Yong Reviewed-by: Chao Yu Signed-off-by: Jaegeuk Kim Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- fs/f2fs/gc.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/fs/f2fs/gc.c b/fs/f2fs/gc.c index d5021ba69e7a..e5673a9b2619 100644 --- a/fs/f2fs/gc.c +++ b/fs/f2fs/gc.c @@ -696,7 +696,12 @@ static void move_data_block(struct inode *inode, block_t bidx, fio.op = REQ_OP_WRITE; fio.op_flags = REQ_SYNC; fio.new_blkaddr = newaddr; - f2fs_submit_page_write(&fio); + err = f2fs_submit_page_write(&fio); + if (err) { + if (PageWriteback(fio.encrypted_page)) + end_page_writeback(fio.encrypted_page); + goto put_page_out; + } f2fs_update_iostat(fio.sbi, FS_GC_DATA_IO, F2FS_BLKSIZE); -- GitLab From 800fda575b119312b429fe488680e990b32e2de6 Mon Sep 17 00:00:00 2001 From: Xose Vazquez Perez Date: Mon, 15 Jan 2018 17:47:23 +0100 Subject: [PATCH 0935/1635] scsi: devinfo: fix format of the device list [ Upstream commit 3f884a0a8bdf28cfd1e9987d54d83350096cdd46 ] Replace "" with NULL for product revision level, and merge TEXEL duplicate entries. Cc: Hannes Reinecke Cc: Martin K. Petersen Cc: James E.J. Bottomley Cc: SCSI ML Signed-off-by: Xose Vazquez Perez Signed-off-by: Martin K. Petersen Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/scsi_devinfo.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/scsi_devinfo.c b/drivers/scsi/scsi_devinfo.c index cfc095f45e26..ea947a7c2596 100644 --- a/drivers/scsi/scsi_devinfo.c +++ b/drivers/scsi/scsi_devinfo.c @@ -109,8 +109,8 @@ static struct { * seagate controller, which causes SCSI code to reset bus. */ {"HP", "C1750A", "3226", BLIST_NOLUN}, /* scanjet iic */ - {"HP", "C1790A", "", BLIST_NOLUN}, /* scanjet iip */ - {"HP", "C2500A", "", BLIST_NOLUN}, /* scanjet iicx */ + {"HP", "C1790A", NULL, BLIST_NOLUN}, /* scanjet iip */ + {"HP", "C2500A", NULL, BLIST_NOLUN}, /* scanjet iicx */ {"MEDIAVIS", "CDR-H93MV", "1.31", BLIST_NOLUN}, /* locks up */ {"MICROTEK", "ScanMaker II", "5.61", BLIST_NOLUN}, /* responds to all lun */ {"MITSUMI", "CD-R CR-2201CS", "6119", BLIST_NOLUN}, /* locks up */ @@ -120,7 +120,7 @@ static struct { {"QUANTUM", "FIREBALL ST4.3S", "0F0C", BLIST_NOLUN}, /* locks up */ {"RELISYS", "Scorpio", NULL, BLIST_NOLUN}, /* responds to all lun */ {"SANKYO", "CP525", "6.64", BLIST_NOLUN}, /* causes failed REQ SENSE, extra reset */ - {"TEXEL", "CD-ROM", "1.06", BLIST_NOLUN}, + {"TEXEL", "CD-ROM", "1.06", BLIST_NOLUN | BLIST_BORKEN}, {"transtec", "T5008", "0001", BLIST_NOREPORTLUN }, {"YAMAHA", "CDR100", "1.00", BLIST_NOLUN}, /* locks up */ {"YAMAHA", "CDR102", "1.00", BLIST_NOLUN}, /* locks up */ @@ -255,7 +255,6 @@ static struct { {"ST650211", "CF", NULL, BLIST_RETRY_HWERROR}, {"SUN", "T300", "*", BLIST_SPARSELUN}, {"SUN", "T4", "*", BLIST_SPARSELUN}, - {"TEXEL", "CD-ROM", "1.06", BLIST_BORKEN}, {"Tornado-", "F4", "*", BLIST_NOREPORTLUN}, {"TOSHIBA", "CDROM", NULL, BLIST_ISROM}, {"TOSHIBA", "CD-ROM", NULL, BLIST_ISROM}, -- GitLab From 8afed2798e50f3f9b84a6b0c9eb9810119a0fc3f Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 18 Jan 2018 14:16:38 +0100 Subject: [PATCH 0936/1635] scsi: fas216: fix sense buffer initialization [ Upstream commit 96d5eaa9bb74d299508d811d865c2c41b38b0301 ] While testing with the ARM specific memset() macro removed, I ran into a compiler warning that shows an old bug: drivers/scsi/arm/fas216.c: In function 'fas216_rq_sns_done': drivers/scsi/arm/fas216.c:2014:40: error: argument to 'sizeof' in 'memset' call is the same expression as the destination; did you mean to provide an explicit length? [-Werror=sizeof-pointer-memaccess] It turns out that the definition of the scsi_cmd structure changed back in linux-2.6.25, so now we clear only four bytes (sizeof(pointer)) instead of 96 (SCSI_SENSE_BUFFERSIZE). I did not check whether we actually need to initialize the buffer here, but it's clear that if we do it, we should use the correct size. Fixes: de25deb18016 ("[SCSI] use dynamically allocated sense buffer") Signed-off-by: Arnd Bergmann Signed-off-by: Martin K. Petersen Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/arm/fas216.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/arm/fas216.c b/drivers/scsi/arm/fas216.c index 24388795ee9a..936e8c735656 100644 --- a/drivers/scsi/arm/fas216.c +++ b/drivers/scsi/arm/fas216.c @@ -2011,7 +2011,7 @@ static void fas216_rq_sns_done(FAS216_Info *info, struct scsi_cmnd *SCpnt, * have valid data in the sense buffer that could * confuse the higher levels. */ - memset(SCpnt->sense_buffer, 0, sizeof(SCpnt->sense_buffer)); + memset(SCpnt->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE); //printk("scsi%d.%c: sense buffer: ", info->host->host_no, '0' + SCpnt->device->id); //{ int i; for (i = 0; i < 32; i++) printk("%02x ", SCpnt->sense_buffer[i]); printk("\n"); } /* -- GitLab From 6a5505da41faa98555526ba50ca9865a2bd0ef99 Mon Sep 17 00:00:00 2001 From: Andi Shyti Date: Mon, 22 Jan 2018 17:32:46 -0800 Subject: [PATCH 0937/1635] Input: stmfts - set IRQ_NOAUTOEN to the irq flag [ Upstream commit cba04cdf437d745fac85220d1d692a9ae23d7004 ] The interrupt is requested before the device is powered on and it's value in some cases cannot be reliable. It happens on some devices that an interrupt is generated as soon as requested before having the chance to disable the irq. Set the irq flag as IRQ_NOAUTOEN before requesting it. This patch mutes the error: stmfts 2-0049: failed to read events: -11 received sometimes during boot time. Signed-off-by: Andi Shyti Signed-off-by: Dmitry Torokhov Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/input/touchscreen/stmfts.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/drivers/input/touchscreen/stmfts.c b/drivers/input/touchscreen/stmfts.c index 8c6c6178ec12..025bae3853cc 100644 --- a/drivers/input/touchscreen/stmfts.c +++ b/drivers/input/touchscreen/stmfts.c @@ -687,6 +687,14 @@ static int stmfts_probe(struct i2c_client *client, input_set_drvdata(sdata->input, sdata); + /* + * stmfts_power_on expects interrupt to be disabled, but + * at this point the device is still off and I do not trust + * the status of the irq line that can generate some spurious + * interrupts. To be on the safe side it's better to not enable + * the interrupts during their request. + */ + irq_set_status_flags(client->irq, IRQ_NOAUTOEN); err = devm_request_threaded_irq(&client->dev, client->irq, NULL, stmfts_irq_handler, IRQF_ONESHOT, @@ -694,9 +702,6 @@ static int stmfts_probe(struct i2c_client *client, if (err) return err; - /* stmfts_power_on expects interrupt to be disabled */ - disable_irq(client->irq); - dev_dbg(&client->dev, "initializing ST-Microelectronics FTS...\n"); err = stmfts_power_on(sdata); -- GitLab From 8591958413bfeacbe294dbb846e53c7bbd82e685 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 10 Jan 2018 12:39:03 +0300 Subject: [PATCH 0938/1635] HID: roccat: prevent an out of bounds read in kovaplus_profile_activated() [ Upstream commit 7ad81482cad67cbe1ec808490d1ddfc420c42008 ] We get the "new_profile_index" value from the mouse device when we're handling raw events. Smatch taints it as untrusted data and complains that we need a bounds check. This seems like a reasonable warning otherwise there is a small read beyond the end of the array. Fixes: 0e70f97f257e ("HID: roccat: Add support for Kova[+] mouse") Signed-off-by: Dan Carpenter Acked-by: Silvan Jegen Signed-off-by: Jiri Kosina Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/hid/hid-roccat-kovaplus.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/hid/hid-roccat-kovaplus.c b/drivers/hid/hid-roccat-kovaplus.c index 43617fb28b87..317c9c2c0a7c 100644 --- a/drivers/hid/hid-roccat-kovaplus.c +++ b/drivers/hid/hid-roccat-kovaplus.c @@ -37,6 +37,8 @@ static uint kovaplus_convert_event_cpi(uint value) static void kovaplus_profile_activated(struct kovaplus_device *kovaplus, uint new_profile_index) { + if (new_profile_index >= ARRAY_SIZE(kovaplus->profile_settings)) + return; kovaplus->actual_profile = new_profile_index; kovaplus->actual_cpi = kovaplus->profile_settings[new_profile_index].cpi_startup_level; kovaplus->actual_x_sensitivity = kovaplus->profile_settings[new_profile_index].sensitivity_x; -- GitLab From f2e73df302f31b588086b6eb5a4151b196faf427 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Tue, 23 Jan 2018 02:10:27 +0000 Subject: [PATCH 0939/1635] nfp: fix error return code in nfp_pci_probe() [ Upstream commit e58decc9c51eb61697aba35ba8eda33f4b80552d ] Fix to return error code -EINVAL instead of 0 when num_vfs above limit_vfs, as done elsewhere in this function. Fixes: 0dc786219186 ("nfp: handle SR-IOV already enabled when driver is probing") Signed-off-by: Wei Yongjun Acked-by: Jakub Kicinski Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/netronome/nfp/nfp_main.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/ethernet/netronome/nfp/nfp_main.c b/drivers/net/ethernet/netronome/nfp/nfp_main.c index f8fa63b66739..a1a15e0c2245 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_main.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_main.c @@ -492,6 +492,7 @@ static int nfp_pci_probe(struct pci_dev *pdev, dev_err(&pdev->dev, "Error: %d VFs already enabled, but loaded FW can only support %d\n", pf->num_vfs, pf->limit_vfs); + err = -EINVAL; goto err_fw_unload; } -- GitLab From c6c6e38aeff2b4131de2718a993d07995844dcc8 Mon Sep 17 00:00:00 2001 From: Goldwyn Rodrigues Date: Tue, 23 Jan 2018 09:10:19 -0700 Subject: [PATCH 0940/1635] block: Set BIO_TRACE_COMPLETION on new bio during split [ Upstream commit 20d59023c5ec4426284af492808bcea1f39787ef ] We inadvertently set it again on the source bio, but we need to set it on the new split bio instead. Fixes: fbbaf700e7b1 ("block: trace completion of all bios.") Signed-off-by: Goldwyn Rodrigues Signed-off-by: Jens Axboe Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- block/bio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/block/bio.c b/block/bio.c index dbaa82c967f4..90f19d7df66c 100644 --- a/block/bio.c +++ b/block/bio.c @@ -1893,7 +1893,7 @@ struct bio *bio_split(struct bio *bio, int sectors, bio_advance(bio, split->bi_iter.bi_size); if (bio_flagged(bio, BIO_TRACE_COMPLETION)) - bio_set_flag(bio, BIO_TRACE_COMPLETION); + bio_set_flag(split, BIO_TRACE_COMPLETION); return split; } -- GitLab From 7c7ae4ed2fcd5a10bdac40b82deaa7f940f001ed Mon Sep 17 00:00:00 2001 From: Prashant Bhole Date: Tue, 23 Jan 2018 13:30:44 +0900 Subject: [PATCH 0941/1635] bpf: test_maps: cleanup sockmaps when test ends [ Upstream commit 783687810e986a15ffbf86c516a1a48ff37f38f7 ] Bug: BPF programs and maps related to sockmaps test exist in memory even after test_maps ends. This patch fixes it as a short term workaround (sockmap kernel side needs real fixing) by empyting sockmaps when test ends. Fixes: 6f6d33f3b3d0f ("bpf: selftests add sockmap tests") Signed-off-by: Prashant Bhole [ daniel: Note on workaround. ] Signed-off-by: Daniel Borkmann Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- tools/testing/selftests/bpf/test_maps.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/tools/testing/selftests/bpf/test_maps.c b/tools/testing/selftests/bpf/test_maps.c index 50ce52d2013d..8b9470b5af6d 100644 --- a/tools/testing/selftests/bpf/test_maps.c +++ b/tools/testing/selftests/bpf/test_maps.c @@ -463,7 +463,7 @@ static void test_devmap(int task, void *data) #define SOCKMAP_VERDICT_PROG "./sockmap_verdict_prog.o" static void test_sockmap(int tasks, void *data) { - int one = 1, map_fd_rx, map_fd_tx, map_fd_break, s, sc, rc; + int one = 1, map_fd_rx = 0, map_fd_tx = 0, map_fd_break, s, sc, rc; struct bpf_map *bpf_map_rx, *bpf_map_tx, *bpf_map_break; int ports[] = {50200, 50201, 50202, 50204}; int err, i, fd, udp, sfd[6] = {0xdeadbeef}; @@ -868,9 +868,12 @@ static void test_sockmap(int tasks, void *data) goto out_sockmap; } - /* Test map close sockets */ - for (i = 0; i < 6; i++) + /* Test map close sockets and empty maps */ + for (i = 0; i < 6; i++) { + bpf_map_delete_elem(map_fd_tx, &i); + bpf_map_delete_elem(map_fd_rx, &i); close(sfd[i]); + } close(fd); close(map_fd_rx); bpf_object__close(obj); @@ -881,8 +884,13 @@ static void test_sockmap(int tasks, void *data) printf("Failed to create sockmap '%i:%s'!\n", i, strerror(errno)); exit(1); out_sockmap: - for (i = 0; i < 6; i++) + for (i = 0; i < 6; i++) { + if (map_fd_tx) + bpf_map_delete_elem(map_fd_tx, &i); + if (map_fd_rx) + bpf_map_delete_elem(map_fd_rx, &i); close(sfd[i]); + } close(fd); exit(1); } -- GitLab From 09f6d65db13b0a58af216d11a8e3f23069dc0f47 Mon Sep 17 00:00:00 2001 From: Avinash Dayanand Date: Mon, 18 Dec 2017 05:16:43 -0500 Subject: [PATCH 0942/1635] i40evf: Don't schedule reset_task when device is being removed [ Upstream commit 06aa040f039404a0039a5158cd12f41187487a1f ] When a host disables and enables a PF device, all the associated VFs are removed and added back in. It also generates a PFR which in turn resets all the connected VFs. This behaviour is different from that of Linux guest on Linux host. Hence we end up in a situation where there's a PFR and device removal at the same time. And watchdog doesn't have a clue about this and schedules a reset_task. This patch adds code to send signal to reset_task that the device is currently being removed. Signed-off-by: Avinash Dayanand Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/intel/i40evf/i40evf.h | 1 + drivers/net/ethernet/intel/i40evf/i40evf_main.c | 9 ++++++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/intel/i40evf/i40evf.h b/drivers/net/ethernet/intel/i40evf/i40evf.h index 82f69031e5cd..2ef32ab1dfae 100644 --- a/drivers/net/ethernet/intel/i40evf/i40evf.h +++ b/drivers/net/ethernet/intel/i40evf/i40evf.h @@ -186,6 +186,7 @@ enum i40evf_state_t { enum i40evf_critical_section_t { __I40EVF_IN_CRITICAL_TASK, /* cannot be interrupted */ __I40EVF_IN_CLIENT_TASK, + __I40EVF_IN_REMOVE_TASK, /* device being removed */ }; /* board specific private data structure */ diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_main.c b/drivers/net/ethernet/intel/i40evf/i40evf_main.c index 4eb6ff60e8fc..1b5d204c57c1 100644 --- a/drivers/net/ethernet/intel/i40evf/i40evf_main.c +++ b/drivers/net/ethernet/intel/i40evf/i40evf_main.c @@ -1839,6 +1839,12 @@ static void i40evf_reset_task(struct work_struct *work) int i = 0, err; bool running; + /* When device is being removed it doesn't make sense to run the reset + * task, just return in such a case. + */ + if (test_bit(__I40EVF_IN_REMOVE_TASK, &adapter->crit_section)) + return; + while (test_and_set_bit(__I40EVF_IN_CLIENT_TASK, &adapter->crit_section)) usleep_range(500, 1000); @@ -3022,7 +3028,8 @@ static void i40evf_remove(struct pci_dev *pdev) struct i40evf_mac_filter *f, *ftmp; struct i40e_hw *hw = &adapter->hw; int err; - + /* Indicate we are in remove and not to run reset_task */ + set_bit(__I40EVF_IN_REMOVE_TASK, &adapter->crit_section); cancel_delayed_work_sync(&adapter->init_task); cancel_work_sync(&adapter->reset_task); cancel_delayed_work_sync(&adapter->client_task); -- GitLab From b9d78055c6aea80faa783b105520efa05b443075 Mon Sep 17 00:00:00 2001 From: Alan Brady Date: Fri, 5 Jan 2018 04:55:21 -0500 Subject: [PATCH 0943/1635] i40evf: ignore link up if not running [ Upstream commit e0346f9fcb6c636d2f870e6666de8781413f34ea ] If we receive the link status message from PF with link up before queues are actually enabled, it will trigger a TX hang. This fixes the issue by ignoring a link up message if the VF state is not yet in RUNNING state. Signed-off-by: Alan Brady Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- .../ethernet/intel/i40evf/i40evf_virtchnl.c | 35 ++++++++++++------- 1 file changed, 23 insertions(+), 12 deletions(-) diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c b/drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c index 85876f4fb1fb..46bf11afba08 100644 --- a/drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c +++ b/drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c @@ -937,23 +937,34 @@ void i40evf_virtchnl_completion(struct i40evf_adapter *adapter, if (v_opcode == VIRTCHNL_OP_EVENT) { struct virtchnl_pf_event *vpe = (struct virtchnl_pf_event *)msg; + bool link_up = vpe->event_data.link_event.link_status; switch (vpe->event) { case VIRTCHNL_EVENT_LINK_CHANGE: adapter->link_speed = vpe->event_data.link_event.link_speed; - if (adapter->link_up != - vpe->event_data.link_event.link_status) { - adapter->link_up = - vpe->event_data.link_event.link_status; - if (adapter->link_up) { - netif_tx_start_all_queues(netdev); - netif_carrier_on(netdev); - } else { - netif_tx_stop_all_queues(netdev); - netif_carrier_off(netdev); - } - i40evf_print_link_message(adapter); + + /* we've already got the right link status, bail */ + if (adapter->link_up == link_up) + break; + + /* If we get link up message and start queues before + * our queues are configured it will trigger a TX hang. + * In that case, just ignore the link status message, + * we'll get another one after we enable queues and + * actually prepared to send traffic. + */ + if (link_up && adapter->state != __I40EVF_RUNNING) + break; + + adapter->link_up = link_up; + if (link_up) { + netif_tx_start_all_queues(netdev); + netif_carrier_on(netdev); + } else { + netif_tx_stop_all_queues(netdev); + netif_carrier_off(netdev); } + i40evf_print_link_message(adapter); break; case VIRTCHNL_EVENT_RESET_IMPENDING: dev_info(&adapter->pdev->dev, "PF reset warning received\n"); -- GitLab From 48d441324a58460e201f15309edf2e082392170d Mon Sep 17 00:00:00 2001 From: David Herrmann Date: Fri, 12 Jan 2018 12:04:45 +0100 Subject: [PATCH 0944/1635] platform/x86: thinkpad_acpi: suppress warning about palm detection [ Upstream commit 587d8628fb71c3bfae29fb2bbe84c1478c59bac8 ] This patch prevents the thinkpad_acpi driver from warning about 2 event codes returned for keyboard palm-detection. No behavioral changes, other than suppressing the warning in the kernel log. The events are still forwarded via acpi-netlink channels. We could, optionally, decide to forward the event through a input-switch on the tpacpi input device. However, so far no suitable input-code exists, and no similar drivers report such events. Hence, leave it an acpi event for now. Note that the event-codes are named based on empirical studies. On the ThinkPad X1 5th Gen the sensor can be found underneath the arrow key. Cc: Matthew Thode Signed-off-by: David Herrmann Acked-by: Henrique de Moraes Holschuh Signed-off-by: Andy Shevchenko Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/platform/x86/thinkpad_acpi.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index 2242d6035d9e..c407d52ef7cf 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -214,6 +214,10 @@ enum tpacpi_hkey_event_t { /* AC-related events */ TP_HKEY_EV_AC_CHANGED = 0x6040, /* AC status changed */ + /* Further user-interface events */ + TP_HKEY_EV_PALM_DETECTED = 0x60b0, /* palm hoveres keyboard */ + TP_HKEY_EV_PALM_UNDETECTED = 0x60b1, /* palm removed */ + /* Misc */ TP_HKEY_EV_RFKILL_CHANGED = 0x7000, /* rfkill switch changed */ }; @@ -3973,6 +3977,12 @@ static bool hotkey_notify_6xxx(const u32 hkey, *send_acpi_ev = false; break; + case TP_HKEY_EV_PALM_DETECTED: + case TP_HKEY_EV_PALM_UNDETECTED: + /* palm detected hovering the keyboard, forward to user-space + * via netlink for consumption */ + return true; + default: pr_warn("unknown possible thermal alarm or keyboard event received\n"); known = false; -- GitLab From a42ebbdae0a58e62906a47fc36b89822c82f627a Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Tue, 16 Jan 2018 18:15:25 +0100 Subject: [PATCH 0945/1635] KVM: s390: vsie: use READ_ONCE to access some SCB fields [ Upstream commit b3ecd4aa8632a86428605ab73393d14779019d82 ] Another VCPU might try to modify the SCB while we are creating the shadow SCB. In general this is no problem - unless the compiler decides to not load values once, but e.g. twice. For us, this is only relevant when checking/working with such values. E.g. the prefix value, the mso, state of transactional execution and addresses of satellite blocks. E.g. if we blindly forward values (e.g. general purpose registers or execution controls after masking), we don't care. Leaving unpin_blocks() untouched for now, will handle it separately. The worst thing right now that I can see would be a missed prefix un/remap (mso, prefix, tx) or using wrong guest addresses. Nothing critical, but let's try to avoid unpredictable behavior. Signed-off-by: David Hildenbrand Message-Id: <20180116171526.12343-2-david@redhat.com> Reviewed-by: Christian Borntraeger Acked-by: Cornelia Huck Signed-off-by: Christian Borntraeger Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/s390/kvm/vsie.c | 50 +++++++++++++++++++++++++++----------------- 1 file changed, 31 insertions(+), 19 deletions(-) diff --git a/arch/s390/kvm/vsie.c b/arch/s390/kvm/vsie.c index b18b5652e5c5..a74204db759b 100644 --- a/arch/s390/kvm/vsie.c +++ b/arch/s390/kvm/vsie.c @@ -31,7 +31,11 @@ struct vsie_page { * the same offset as that in struct sie_page! */ struct mcck_volatile_info mcck_info; /* 0x0200 */ - /* the pinned originial scb */ + /* + * The pinned original scb. Be aware that other VCPUs can modify + * it while we read from it. Values that are used for conditions or + * are reused conditionally, should be accessed via READ_ONCE. + */ struct kvm_s390_sie_block *scb_o; /* 0x0218 */ /* the shadow gmap in use by the vsie_page */ struct gmap *gmap; /* 0x0220 */ @@ -143,12 +147,13 @@ static int shadow_crycb(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page) { struct kvm_s390_sie_block *scb_s = &vsie_page->scb_s; struct kvm_s390_sie_block *scb_o = vsie_page->scb_o; - u32 crycb_addr = scb_o->crycbd & 0x7ffffff8U; + const uint32_t crycbd_o = READ_ONCE(scb_o->crycbd); + const u32 crycb_addr = crycbd_o & 0x7ffffff8U; unsigned long *b1, *b2; u8 ecb3_flags; scb_s->crycbd = 0; - if (!(scb_o->crycbd & vcpu->arch.sie_block->crycbd & CRYCB_FORMAT1)) + if (!(crycbd_o & vcpu->arch.sie_block->crycbd & CRYCB_FORMAT1)) return 0; /* format-1 is supported with message-security-assist extension 3 */ if (!test_kvm_facility(vcpu->kvm, 76)) @@ -186,12 +191,15 @@ static void prepare_ibc(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page) { struct kvm_s390_sie_block *scb_s = &vsie_page->scb_s; struct kvm_s390_sie_block *scb_o = vsie_page->scb_o; + /* READ_ONCE does not work on bitfields - use a temporary variable */ + const uint32_t __new_ibc = scb_o->ibc; + const uint32_t new_ibc = READ_ONCE(__new_ibc) & 0x0fffU; __u64 min_ibc = (sclp.ibc >> 16) & 0x0fffU; scb_s->ibc = 0; /* ibc installed in g2 and requested for g3 */ - if (vcpu->kvm->arch.model.ibc && (scb_o->ibc & 0x0fffU)) { - scb_s->ibc = scb_o->ibc & 0x0fffU; + if (vcpu->kvm->arch.model.ibc && new_ibc) { + scb_s->ibc = new_ibc; /* takte care of the minimum ibc level of the machine */ if (scb_s->ibc < min_ibc) scb_s->ibc = min_ibc; @@ -256,6 +264,10 @@ static int shadow_scb(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page) { struct kvm_s390_sie_block *scb_o = vsie_page->scb_o; struct kvm_s390_sie_block *scb_s = &vsie_page->scb_s; + /* READ_ONCE does not work on bitfields - use a temporary variable */ + const uint32_t __new_prefix = scb_o->prefix; + const uint32_t new_prefix = READ_ONCE(__new_prefix); + const bool wants_tx = READ_ONCE(scb_o->ecb) & ECB_TE; bool had_tx = scb_s->ecb & ECB_TE; unsigned long new_mso = 0; int rc; @@ -302,14 +314,14 @@ static int shadow_scb(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page) scb_s->icpua = scb_o->icpua; if (!(atomic_read(&scb_s->cpuflags) & CPUSTAT_SM)) - new_mso = scb_o->mso & 0xfffffffffff00000UL; + new_mso = READ_ONCE(scb_o->mso) & 0xfffffffffff00000UL; /* if the hva of the prefix changes, we have to remap the prefix */ - if (scb_s->mso != new_mso || scb_s->prefix != scb_o->prefix) + if (scb_s->mso != new_mso || scb_s->prefix != new_prefix) prefix_unmapped(vsie_page); /* SIE will do mso/msl validity and exception checks for us */ scb_s->msl = scb_o->msl & 0xfffffffffff00000UL; scb_s->mso = new_mso; - scb_s->prefix = scb_o->prefix; + scb_s->prefix = new_prefix; /* We have to definetly flush the tlb if this scb never ran */ if (scb_s->ihcpu != 0xffffU) @@ -321,11 +333,11 @@ static int shadow_scb(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page) if (test_kvm_cpu_feat(vcpu->kvm, KVM_S390_VM_CPU_FEAT_ESOP)) scb_s->ecb |= scb_o->ecb & ECB_HOSTPROTINT; /* transactional execution */ - if (test_kvm_facility(vcpu->kvm, 73)) { + if (test_kvm_facility(vcpu->kvm, 73) && wants_tx) { /* remap the prefix is tx is toggled on */ - if ((scb_o->ecb & ECB_TE) && !had_tx) + if (!had_tx) prefix_unmapped(vsie_page); - scb_s->ecb |= scb_o->ecb & ECB_TE; + scb_s->ecb |= ECB_TE; } /* SIMD */ if (test_kvm_facility(vcpu->kvm, 129)) { @@ -544,9 +556,9 @@ static int pin_blocks(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page) gpa_t gpa; int rc = 0; - gpa = scb_o->scaol & ~0xfUL; + gpa = READ_ONCE(scb_o->scaol) & ~0xfUL; if (test_kvm_cpu_feat(vcpu->kvm, KVM_S390_VM_CPU_FEAT_64BSCAO)) - gpa |= (u64) scb_o->scaoh << 32; + gpa |= (u64) READ_ONCE(scb_o->scaoh) << 32; if (gpa) { if (!(gpa & ~0x1fffUL)) rc = set_validity_icpt(scb_s, 0x0038U); @@ -566,7 +578,7 @@ static int pin_blocks(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page) scb_s->scaol = (u32)(u64)hpa; } - gpa = scb_o->itdba & ~0xffUL; + gpa = READ_ONCE(scb_o->itdba) & ~0xffUL; if (gpa && (scb_s->ecb & ECB_TE)) { if (!(gpa & ~0x1fffU)) { rc = set_validity_icpt(scb_s, 0x0080U); @@ -581,7 +593,7 @@ static int pin_blocks(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page) scb_s->itdba = hpa; } - gpa = scb_o->gvrd & ~0x1ffUL; + gpa = READ_ONCE(scb_o->gvrd) & ~0x1ffUL; if (gpa && (scb_s->eca & ECA_VX) && !(scb_s->ecd & ECD_HOSTREGMGMT)) { if (!(gpa & ~0x1fffUL)) { rc = set_validity_icpt(scb_s, 0x1310U); @@ -599,7 +611,7 @@ static int pin_blocks(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page) scb_s->gvrd = hpa; } - gpa = scb_o->riccbd & ~0x3fUL; + gpa = READ_ONCE(scb_o->riccbd) & ~0x3fUL; if (gpa && (scb_s->ecb3 & ECB3_RI)) { if (!(gpa & ~0x1fffUL)) { rc = set_validity_icpt(scb_s, 0x0043U); @@ -617,8 +629,8 @@ static int pin_blocks(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page) if ((scb_s->ecb & ECB_GS) && !(scb_s->ecd & ECD_HOSTREGMGMT)) { unsigned long sdnxc; - gpa = scb_o->sdnxo & ~0xfUL; - sdnxc = scb_o->sdnxo & 0xfUL; + gpa = READ_ONCE(scb_o->sdnxo) & ~0xfUL; + sdnxc = READ_ONCE(scb_o->sdnxo) & 0xfUL; if (!gpa || !(gpa & ~0x1fffUL)) { rc = set_validity_icpt(scb_s, 0x10b0U); goto unpin; @@ -785,7 +797,7 @@ static void retry_vsie_icpt(struct vsie_page *vsie_page) static int handle_stfle(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page) { struct kvm_s390_sie_block *scb_s = &vsie_page->scb_s; - __u32 fac = vsie_page->scb_o->fac & 0x7ffffff8U; + __u32 fac = READ_ONCE(vsie_page->scb_o->fac) & 0x7ffffff8U; if (fac && test_kvm_facility(vcpu->kvm, 7)) { retry_vsie_icpt(vsie_page); -- GitLab From f25ba4f6be4aa368a4ce22d225d4c09257b3667a Mon Sep 17 00:00:00 2001 From: Eryu Guan Date: Wed, 24 Jan 2018 01:20:00 +0800 Subject: [PATCH 0946/1635] blk-mq-debugfs: don't allow write on attributes with seq_operations set [ Upstream commit 6b136a24b05c81a24e0b648a4bd938bcd0c4f69e ] Attributes that only implement .seq_ops are read-only, any write to them should be rejected. But currently kernel would crash when writing to such debugfs entries, e.g. chmod +w /sys/kernel/debug/block//requeue_list echo 0 > /sys/kernel/debug/block//requeue_list chmod -w /sys/kernel/debug/block//requeue_list Fix it by returning -EPERM in blk_mq_debugfs_write() when writing to such attributes. Cc: Ming Lei Signed-off-by: Eryu Guan Signed-off-by: Jens Axboe Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- block/blk-mq-debugfs.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/block/blk-mq-debugfs.c b/block/blk-mq-debugfs.c index de294d775acf..d95439154556 100644 --- a/block/blk-mq-debugfs.c +++ b/block/blk-mq-debugfs.c @@ -704,7 +704,11 @@ static ssize_t blk_mq_debugfs_write(struct file *file, const char __user *buf, const struct blk_mq_debugfs_attr *attr = m->private; void *data = d_inode(file->f_path.dentry->d_parent)->i_private; - if (!attr->write) + /* + * Attributes that only implement .seq_ops are read-only and 'attr' is + * the same with 'data' in this case. + */ + if (attr == data || !attr->write) return -EPERM; return attr->write(data, buf, count, ppos); -- GitLab From 048af64fd48f639bb97773c33e87ee6cf250ac99 Mon Sep 17 00:00:00 2001 From: Jeffy Chen Date: Tue, 21 Nov 2017 16:25:17 +0800 Subject: [PATCH 0947/1635] ASoC: rockchip: Use dummy_dai for rt5514 dsp dailink [ Upstream commit fde7f9dbc71365230eeb8c8ea97ce9b552c8e5bd ] The rt5514 dsp captures pcm data through spi directly, so we should not use rockchip-i2s as it's cpu dai like other codecs. Use dummy_dai for rt5514 dsp dailink to make voice wakeup work again. Reported-by: Jimmy Cheng-Yi Chiang Fixes: (72cfb0f20c75 ASoC: rockchip: Use codec of_node and dai_name for rt5514 dsp) Signed-off-by: Jeffy Chen Tested-by: Brian Norris Signed-off-by: Mark Brown Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- sound/soc/rockchip/rk3399_gru_sound.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/sound/soc/rockchip/rk3399_gru_sound.c b/sound/soc/rockchip/rk3399_gru_sound.c index 0513fe480353..21ac8d6cce3a 100644 --- a/sound/soc/rockchip/rk3399_gru_sound.c +++ b/sound/soc/rockchip/rk3399_gru_sound.c @@ -387,7 +387,8 @@ static const struct snd_soc_dai_link rockchip_dais[] = { [DAILINK_RT5514_DSP] = { .name = "RT5514 DSP", .stream_name = "Wake on Voice", - .codec_dai_name = "rt5514-dsp-cpu-dai", + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", }, }; @@ -432,7 +433,18 @@ static int rockchip_sound_of_parse_dais(struct device *dev, if (index < 0) continue; - np_cpu = (index == DAILINK_CDNDP) ? np_cpu1 : np_cpu0; + switch (index) { + case DAILINK_CDNDP: + np_cpu = np_cpu1; + break; + case DAILINK_RT5514_DSP: + np_cpu = np_codec; + break; + default: + np_cpu = np_cpu0; + break; + } + if (!np_cpu) { dev_err(dev, "Missing 'rockchip,cpu' for %s\n", rockchip_dais[index].name); @@ -442,7 +454,8 @@ static int rockchip_sound_of_parse_dais(struct device *dev, dai = &card->dai_link[card->num_links++]; *dai = rockchip_dais[index]; - dai->codec_of_node = np_codec; + if (!dai->codec_name) + dai->codec_of_node = np_codec; dai->platform_of_node = np_cpu; dai->cpu_of_node = np_cpu; } -- GitLab From 187bf28199d85d12c68c836e1ba3fe903ba7fec3 Mon Sep 17 00:00:00 2001 From: Corinna Vinschen Date: Mon, 10 Apr 2017 10:58:14 +0200 Subject: [PATCH 0948/1635] igb: Allow to remove administratively set MAC on VFs [ Upstream commit 177132df5e45b134c147f419f567a3b56aafaf2b ] Before libvirt modifies the MAC address and vlan tag for an SRIOV VF for use by a virtual machine (either using vfio device assignment or macvtap passthru mode), it saves the current MAC address and vlan tag so that it can reset them to their original value when the guest is done. Libvirt can't leave the VF MAC set to the value used by the now-defunct guest since it may be started again later using a different VF, but it certainly shouldn't just pick any random value, either. So it saves the state of everything prior to using the VF, and resets it to that. The igb driver initializes the MAC addresses of all VFs to 00:00:00:00:00:00, and reports that when asked (via an RTM_GETLINK netlink message, also visible in the list of VFs in the output of "ip link show"). But when libvirt attempts to restore the MAC address back to 00:00:00:00:00:00 (using an RTM_SETLINK netlink message) the kernel responds with "Invalid argument". Forbidding a reset back to the original value leaves the VF MAC at the value set for the now-defunct virtual machine. Especially on a system with NetworkManager enabled, this has very bad consequences, since NetworkManager forces all interfacess to be IFF_UP all the time - if the same virtual machine is restarted using a different VF (or even on a different host), there will be multiple interfaces watching for traffic with the same MAC address. To allow libvirt to revert to the original state, we need a way to remove the administrative set MAC on a VF, to allow normal host operation again, and to reset/overwrite the VF MAC via VF netdev. This patch implements the outlined scenario by allowing to set the VF MAC to 00:00:00:00:00:00 via RTM_SETLINK on the PF. igb_ndo_set_vf_mac resets the IGB_VF_FLAG_PF_SET_MAC flag to 0, so it's possible to reset the VF MAC back to the original value via the VF netdev. Note: Recent patches to libvirt allow for a workaround if the NIC isn't capable of resetting the administrative MAC back to all 0, but in theory the NIC should allow resetting the MAC in the first place. Signed-off-by: Corinna Vinschen Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/intel/igb/igb_main.c | 42 +++++++++++++++++------ 1 file changed, 31 insertions(+), 11 deletions(-) diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c index d1a44a84c97e..6ca580cdfd84 100644 --- a/drivers/net/ethernet/intel/igb/igb_main.c +++ b/drivers/net/ethernet/intel/igb/igb_main.c @@ -8373,7 +8373,8 @@ static void igb_rar_set_index(struct igb_adapter *adapter, u32 index) /* Indicate to hardware the Address is Valid. */ if (adapter->mac_table[index].state & IGB_MAC_STATE_IN_USE) { - rar_high |= E1000_RAH_AV; + if (is_valid_ether_addr(addr)) + rar_high |= E1000_RAH_AV; if (hw->mac.type == e1000_82575) rar_high |= E1000_RAH_POOL_1 * @@ -8411,17 +8412,36 @@ static int igb_set_vf_mac(struct igb_adapter *adapter, static int igb_ndo_set_vf_mac(struct net_device *netdev, int vf, u8 *mac) { struct igb_adapter *adapter = netdev_priv(netdev); - if (!is_valid_ether_addr(mac) || (vf >= adapter->vfs_allocated_count)) + + if (vf >= adapter->vfs_allocated_count) + return -EINVAL; + + /* Setting the VF MAC to 0 reverts the IGB_VF_FLAG_PF_SET_MAC + * flag and allows to overwrite the MAC via VF netdev. This + * is necessary to allow libvirt a way to restore the original + * MAC after unbinding vfio-pci and reloading igbvf after shutting + * down a VM. + */ + if (is_zero_ether_addr(mac)) { + adapter->vf_data[vf].flags &= ~IGB_VF_FLAG_PF_SET_MAC; + dev_info(&adapter->pdev->dev, + "remove administratively set MAC on VF %d\n", + vf); + } else if (is_valid_ether_addr(mac)) { + adapter->vf_data[vf].flags |= IGB_VF_FLAG_PF_SET_MAC; + dev_info(&adapter->pdev->dev, "setting MAC %pM on VF %d\n", + mac, vf); + dev_info(&adapter->pdev->dev, + "Reload the VF driver to make this change effective."); + /* Generate additional warning if PF is down */ + if (test_bit(__IGB_DOWN, &adapter->state)) { + dev_warn(&adapter->pdev->dev, + "The VF MAC address has been set, but the PF device is not up.\n"); + dev_warn(&adapter->pdev->dev, + "Bring the PF device up before attempting to use the VF device.\n"); + } + } else { return -EINVAL; - adapter->vf_data[vf].flags |= IGB_VF_FLAG_PF_SET_MAC; - dev_info(&adapter->pdev->dev, "setting MAC %pM on VF %d\n", mac, vf); - dev_info(&adapter->pdev->dev, - "Reload the VF driver to make this change effective."); - if (test_bit(__IGB_DOWN, &adapter->state)) { - dev_warn(&adapter->pdev->dev, - "The VF MAC address has been set, but the PF device is not up.\n"); - dev_warn(&adapter->pdev->dev, - "Bring the PF device up before attempting to use the VF device.\n"); } return igb_set_vf_mac(adapter, vf, mac); } -- GitLab From 0e7a0c139cbf09d602eabb935ad5a080c99cdd46 Mon Sep 17 00:00:00 2001 From: Daniel Hua Date: Tue, 2 Jan 2018 08:33:18 +0800 Subject: [PATCH 0949/1635] igb: Clear TXSTMP when ptp_tx_work() is timeout [ Upstream commit 3a53285228165225a7f76c7d5ff1ddc0213ce0e4 ] Problem description: After ethernet cable connect and disconnect for several iterations on a device with i210, tx timestamp will stop being put into the socket. Steps to reproduce: 1. Setup a device with i210 and wire it to a 802.1AS capable switch ( Extreme Networks Summit x440 is used in our case) 2. Have the gptp daemon running on the device and make sure it is synced with the switch 3. Have the switch disable and enable the port, wait for the device gets resynced with the switch 4. Iterates step 3 until the device is not albe to get resynced 5. Review the log in dmesg and you will see warning message "igb : clearing Tx timestamp hang" Root cause: If ptp_tx_work() gets scheduled just before the port gets disabled, a LINK DOWN event will be processed before ptp_tx_work(), which may cause timeout in ptp_tx_work(). In the timeout logic, the TSYNCTXCTL's TXTT bit (Transmit timestamp valid bit) is not cleared, causing no new timestamp loaded to TXSTMP register. Consequently therefore, no new interrupt is triggerred by TSICR.TXTS bit and no more Tx timestamp send to the socket. Signed-off-by: Daniel Hua Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/intel/igb/igb_ptp.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/net/ethernet/intel/igb/igb_ptp.c b/drivers/net/ethernet/intel/igb/igb_ptp.c index 841c2a083349..0746b19ec6d3 100644 --- a/drivers/net/ethernet/intel/igb/igb_ptp.c +++ b/drivers/net/ethernet/intel/igb/igb_ptp.c @@ -643,6 +643,10 @@ static void igb_ptp_tx_work(struct work_struct *work) adapter->ptp_tx_skb = NULL; clear_bit_unlock(__IGB_PTP_TX_IN_PROGRESS, &adapter->state); adapter->tx_hwtstamp_timeouts++; + /* Clear the tx valid bit in TSYNCTXCTL register to enable + * interrupt + */ + rd32(E1000_TXSTMPH); dev_warn(&adapter->pdev->dev, "clearing Tx timestamp hang\n"); return; } @@ -717,6 +721,7 @@ void igb_ptp_rx_hang(struct igb_adapter *adapter) */ void igb_ptp_tx_hang(struct igb_adapter *adapter) { + struct e1000_hw *hw = &adapter->hw; bool timeout = time_is_before_jiffies(adapter->ptp_tx_start + IGB_PTP_TX_TIMEOUT); @@ -736,6 +741,10 @@ void igb_ptp_tx_hang(struct igb_adapter *adapter) adapter->ptp_tx_skb = NULL; clear_bit_unlock(__IGB_PTP_TX_IN_PROGRESS, &adapter->state); adapter->tx_hwtstamp_timeouts++; + /* Clear the tx valid bit in TSYNCTXCTL register to enable + * interrupt + */ + rd32(E1000_TXSTMPH); dev_warn(&adapter->pdev->dev, "clearing Tx timestamp hang\n"); } } -- GitLab From 9a1dda252663c930822c933232736cd05a8cb800 Mon Sep 17 00:00:00 2001 From: Ngai-Mint Kwan Date: Wed, 24 Jan 2018 14:18:22 -0800 Subject: [PATCH 0950/1635] fm10k: fix "failed to kill vid" message for VF [ Upstream commit cf315ea596ec26d7aa542a9ce354990875a920c0 ] When a VF is under PF VLAN assignment: ip link set vf <#> vlan This will remove all previous entries in the VLAN table including those generated by VLAN interfaces created on the VF. The issue arises when the VF is under PF VLAN assignment and one or more of these VLAN interfaces of the VF are deleted. When deleting these VLAN interfaces, the following message will be generated in "dmesg": failed to kill vid 0081/ for device This is due to the fact that "ndo_vlan_rx_kill_vid" exits with an error. The handler for this ndo is "fm10k_update_vid". Any calls to this function while under PF VLAN management will exit prematurely and, thus, it will generate the failure message. Additionally, since "fm10k_update_vid" exits prematurely, none of the VLAN update is performed. So, even though the actual VLAN interfaces of the VF will be deleted, the active_vlans bitmask is not cleared. When the VF is no longer under PF VLAN assignment, the driver mistakenly restores the previous entries of the VLAN table based on an unsynchronized list of active VLANs. The solution to this issue involves checking the VLAN update action type before exiting "fm10k_update_vid". If the VLAN update action type is to "add", this action will not be permitted while the VF is under PF VLAN assignment and the VLAN update is abandoned like before. However, if the VLAN update action type is to "kill", then we need to also clear the active_vlans bitmask. However, we don't need to actually queue any messages to the PF, because the MAC and VLAN tables have already been cleared, and the PF would silently ignore these requests anyways. Signed-off-by: Ngai-Mint Kwan Signed-off-by: Jacob Keller Tested-by: Krishneil Singh Signed-off-by: Jeff Kirsher Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/intel/fm10k/fm10k_netdev.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/intel/fm10k/fm10k_netdev.c b/drivers/net/ethernet/intel/fm10k/fm10k_netdev.c index e69d49d91d67..914258310ddd 100644 --- a/drivers/net/ethernet/intel/fm10k/fm10k_netdev.c +++ b/drivers/net/ethernet/intel/fm10k/fm10k_netdev.c @@ -815,8 +815,12 @@ static int fm10k_update_vid(struct net_device *netdev, u16 vid, bool set) if (vid >= VLAN_N_VID) return -EINVAL; - /* Verify we have permission to add VLANs */ - if (hw->mac.vlan_override) + /* Verify that we have permission to add VLANs. If this is a request + * to remove a VLAN, we still want to allow the user to remove the + * VLAN device. In that case, we need to clear the bit in the + * active_vlans bitmask. + */ + if (set && hw->mac.vlan_override) return -EACCES; /* update active_vlans bitmask */ @@ -835,6 +839,12 @@ static int fm10k_update_vid(struct net_device *netdev, u16 vid, bool set) rx_ring->vid &= ~FM10K_VLAN_CLEAR; } + /* If our VLAN has been overridden, there is no reason to send VLAN + * removal requests as they will be silently ignored. + */ + if (hw->mac.vlan_override) + return 0; + /* Do not remove default VLAN ID related entries from VLAN and MAC * tables */ -- GitLab From 519a7119527c26984e6804abc422808681d1a117 Mon Sep 17 00:00:00 2001 From: Vitaly Kuznetsov Date: Wed, 24 Jan 2018 11:36:29 +0100 Subject: [PATCH 0951/1635] x86/hyperv: Stop suppressing X86_FEATURE_PCID [ Upstream commit 617ab45c9a8900e64a78b43696c02598b8cad68b ] When hypercall-based TLB flush was enabled for Hyper-V guests PCID feature was deliberately suppressed as a precaution: back then PCID was never exposed to Hyper-V guests and it wasn't clear what will happen if some day it becomes available. The day came and PCID/INVPCID features are already exposed on certain Hyper-V hosts. >From TLFS (as of 5.0b) it is unclear how TLB flush hypercalls combine with PCID. In particular the usage of PCID is per-cpu based: the same mm gets different CR3 values on different CPUs. If the hypercall does exact matching this will fail. However, this is not the case. David Zhang explains: "In practice, the AddressSpace argument is ignored on any VM that supports PCIDs. Architecturally, the AddressSpace argument must match the CR3 with PCID bits stripped out (i.e., the low 12 bits of AddressSpace should be 0 in long mode). The flush hypercalls flush all PCIDs for the specified AddressSpace." With this, PCID can be enabled. Signed-off-by: Vitaly Kuznetsov Signed-off-by: Thomas Gleixner Cc: David Zhang Cc: Stephen Hemminger Cc: Haiyang Zhang Cc: "Michael Kelley (EOSG)" Cc: Andy Lutomirski Cc: devel@linuxdriverproject.org Cc: "K. Y. Srinivasan" Cc: Aditya Bhandari Link: https://lkml.kernel.org/r/20180124103629.29980-1-vkuznets@redhat.com Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/x86/hyperv/mmu.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/arch/x86/hyperv/mmu.c b/arch/x86/hyperv/mmu.c index 9cc9e1c1e2db..56c9ebac946f 100644 --- a/arch/x86/hyperv/mmu.c +++ b/arch/x86/hyperv/mmu.c @@ -137,7 +137,12 @@ static void hyperv_flush_tlb_others(const struct cpumask *cpus, } if (info->mm) { + /* + * AddressSpace argument must match the CR3 with PCID bits + * stripped out. + */ flush->address_space = virt_to_phys(info->mm->pgd); + flush->address_space &= CR3_ADDR_MASK; flush->flags = 0; } else { flush->address_space = 0; @@ -219,7 +224,12 @@ static void hyperv_flush_tlb_others_ex(const struct cpumask *cpus, } if (info->mm) { + /* + * AddressSpace argument must match the CR3 with PCID bits + * stripped out. + */ flush->address_space = virt_to_phys(info->mm->pgd); + flush->address_space &= CR3_ADDR_MASK; flush->flags = 0; } else { flush->address_space = 0; @@ -278,8 +288,6 @@ void hyperv_setup_mmu_ops(void) if (!(ms_hyperv.hints & HV_X64_REMOTE_TLB_FLUSH_RECOMMENDED)) return; - setup_clear_cpu_cap(X86_FEATURE_PCID); - if (!(ms_hyperv.hints & HV_X64_EX_PROCESSOR_MASKS_RECOMMENDED)) { pr_info("Using hypercall for remote TLB flush\n"); pv_mmu_ops.flush_tlb_others = hyperv_flush_tlb_others; -- GitLab From c5fda2b8610b96f0035210952fb1dedcd73bf2ee Mon Sep 17 00:00:00 2001 From: Aaron Sierra Date: Wed, 24 Jan 2018 18:19:23 -0600 Subject: [PATCH 0952/1635] tty: serial: exar: Relocate sleep wake-up handling [ Upstream commit c7e1b4059075c9e8eed101d7cc5da43e95eb5e18 ] Exar sleep wake-up handling has been done on a per-channel basis by virtue of INT0 being accessible from each channel's address space. I believe this was initially done out of necessity, but now that Exar devices have their own driver, we can do things more efficiently by registering a dedicated INT0 handler at the PCI device level. I see this change providing the following benefits: 1. If more than one port is active, eliminates the redundant bus cycles for reading INT0 on every interrupt. 2. This note associated with hooking in the per-channel handler in 8250_port.c is resolved: /* Fixme: probably not the best place for this */ Cc: Matt Schulte Signed-off-by: Aaron Sierra Signed-off-by: Greg Kroah-Hartman Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_exar.c | 34 +++++++++++++++++++++++++---- drivers/tty/serial/8250/8250_port.c | 26 ---------------------- 2 files changed, 30 insertions(+), 30 deletions(-) diff --git a/drivers/tty/serial/8250/8250_exar.c b/drivers/tty/serial/8250/8250_exar.c index c55624703fdf..e0aa5f03004c 100644 --- a/drivers/tty/serial/8250/8250_exar.c +++ b/drivers/tty/serial/8250/8250_exar.c @@ -37,6 +37,7 @@ #define PCI_DEVICE_ID_EXAR_XR17V4358 0x4358 #define PCI_DEVICE_ID_EXAR_XR17V8358 0x8358 +#define UART_EXAR_INT0 0x80 #define UART_EXAR_8XMODE 0x88 /* 8X sampling rate select */ #define UART_EXAR_FCTR 0x08 /* Feature Control Register */ @@ -124,6 +125,7 @@ struct exar8250_board { struct exar8250 { unsigned int nr; struct exar8250_board *board; + void __iomem *virt; int line[0]; }; @@ -134,12 +136,9 @@ static int default_setup(struct exar8250 *priv, struct pci_dev *pcidev, const struct exar8250_board *board = priv->board; unsigned int bar = 0; - if (!pcim_iomap_table(pcidev)[bar] && !pcim_iomap(pcidev, bar, 0)) - return -ENOMEM; - port->port.iotype = UPIO_MEM; port->port.mapbase = pci_resource_start(pcidev, bar) + offset; - port->port.membase = pcim_iomap_table(pcidev)[bar] + offset; + port->port.membase = priv->virt + offset; port->port.regshift = board->reg_shift; return 0; @@ -423,6 +422,25 @@ static void pci_xr17v35x_exit(struct pci_dev *pcidev) port->port.private_data = NULL; } +/* + * These Exar UARTs have an extra interrupt indicator that could fire for a + * few interrupts that are not presented/cleared through IIR. One of which is + * a wakeup interrupt when coming out of sleep. These interrupts are only + * cleared by reading global INT0 or INT1 registers as interrupts are + * associated with channel 0. The INT[3:0] registers _are_ accessible from each + * channel's address space, but for the sake of bus efficiency we register a + * dedicated handler at the PCI device level to handle them. + */ +static irqreturn_t exar_misc_handler(int irq, void *data) +{ + struct exar8250 *priv = data; + + /* Clear all PCI interrupts by reading INT0. No effect on IIR */ + ioread8(priv->virt + UART_EXAR_INT0); + + return IRQ_HANDLED; +} + static int exar_pci_probe(struct pci_dev *pcidev, const struct pci_device_id *ent) { @@ -451,6 +469,9 @@ exar_pci_probe(struct pci_dev *pcidev, const struct pci_device_id *ent) return -ENOMEM; priv->board = board; + priv->virt = pcim_iomap(pcidev, bar, 0); + if (!priv->virt) + return -ENOMEM; pci_set_master(pcidev); @@ -464,6 +485,11 @@ exar_pci_probe(struct pci_dev *pcidev, const struct pci_device_id *ent) uart.port.irq = pci_irq_vector(pcidev, 0); uart.port.dev = &pcidev->dev; + rc = devm_request_irq(&pcidev->dev, uart.port.irq, exar_misc_handler, + IRQF_SHARED, "exar_uart", priv); + if (rc) + return rc; + for (i = 0; i < nr_ports && i < maxnr; i++) { rc = board->setup(priv, pcidev, &uart, i); if (rc) { diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c index fde34c84e707..e32c51d549c3 100644 --- a/drivers/tty/serial/8250/8250_port.c +++ b/drivers/tty/serial/8250/8250_port.c @@ -458,7 +458,6 @@ static void io_serial_out(struct uart_port *p, int offset, int value) } static int serial8250_default_handle_irq(struct uart_port *port); -static int exar_handle_irq(struct uart_port *port); static void set_io_from_upio(struct uart_port *p) { @@ -1903,26 +1902,6 @@ static int serial8250_default_handle_irq(struct uart_port *port) return ret; } -/* - * These Exar UARTs have an extra interrupt indicator that could - * fire for a few unimplemented interrupts. One of which is a - * wakeup event when coming out of sleep. Put this here just - * to be on the safe side that these interrupts don't go unhandled. - */ -static int exar_handle_irq(struct uart_port *port) -{ - unsigned int iir = serial_port_in(port, UART_IIR); - int ret = 0; - - if (((port->type == PORT_XR17V35X) || (port->type == PORT_XR17D15X)) && - serial_port_in(port, UART_EXAR_INT0) != 0) - ret = 1; - - ret |= serial8250_handle_irq(port, iir); - - return ret; -} - /* * Newer 16550 compatible parts such as the SC16C650 & Altera 16550 Soft IP * have a programmable TX threshold that triggers the THRE interrupt in @@ -3107,11 +3086,6 @@ static void serial8250_config_port(struct uart_port *port, int flags) if (port->type == PORT_UNKNOWN) serial8250_release_std_resource(up); - /* Fixme: probably not the best place for this */ - if ((port->type == PORT_XR17V35X) || - (port->type == PORT_XR17D15X)) - port->handle_irq = exar_handle_irq; - register_dev_spec_attr_grp(up); up->fcr = uart_config[up->port.type].fcr; } -- GitLab From 592ea370bf1ce685bdb5bdf71eaf7e65190c551f Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 22 Jan 2018 18:01:42 +0200 Subject: [PATCH 0953/1635] device property: Define type of PROPERTY_ENRTY_*() macros [ Upstream commit c505cbd45f6e9c539d57dd171d95ec7e5e9f9cd0 ] Some of the drivers may use the macro at runtime flow, like struct property_entry p[10]; ... p[index++] = PROPERTY_ENTRY_U8("u8 property", u8_data); In that case and absence of the data type compiler fails the build: drivers/char/ipmi/ipmi_dmi.c:79:29: error: Expected ; at end of statement drivers/char/ipmi/ipmi_dmi.c:79:29: error: got { Acked-by: Corey Minyard Cc: Corey Minyard Signed-off-by: Andy Shevchenko Signed-off-by: Greg Kroah-Hartman Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- include/linux/property.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/include/linux/property.h b/include/linux/property.h index 6bebee13c5e0..89d94b349912 100644 --- a/include/linux/property.h +++ b/include/linux/property.h @@ -206,7 +206,7 @@ struct property_entry { */ #define PROPERTY_ENTRY_INTEGER_ARRAY(_name_, _type_, _val_) \ -{ \ +(struct property_entry) { \ .name = _name_, \ .length = ARRAY_SIZE(_val_) * sizeof(_type_), \ .is_array = true, \ @@ -224,7 +224,7 @@ struct property_entry { PROPERTY_ENTRY_INTEGER_ARRAY(_name_, u64, _val_) #define PROPERTY_ENTRY_STRING_ARRAY(_name_, _val_) \ -{ \ +(struct property_entry) { \ .name = _name_, \ .length = ARRAY_SIZE(_val_) * sizeof(const char *), \ .is_array = true, \ @@ -233,7 +233,7 @@ struct property_entry { } #define PROPERTY_ENTRY_INTEGER(_name_, _type_, _val_) \ -{ \ +(struct property_entry) { \ .name = _name_, \ .length = sizeof(_type_), \ .is_string = false, \ @@ -250,7 +250,7 @@ struct property_entry { PROPERTY_ENTRY_INTEGER(_name_, u64, _val_) #define PROPERTY_ENTRY_STRING(_name_, _val_) \ -{ \ +(struct property_entry) { \ .name = _name_, \ .length = sizeof(_val_), \ .is_string = true, \ @@ -258,7 +258,7 @@ struct property_entry { } #define PROPERTY_ENTRY_BOOL(_name_) \ -{ \ +(struct property_entry) { \ .name = _name_, \ } -- GitLab From 827aab45cb16862083415abdb3e56313d59c347e Mon Sep 17 00:00:00 2001 From: Corentin LABBE Date: Wed, 17 Jan 2018 19:50:56 +0100 Subject: [PATCH 0954/1635] crypto: artpec6 - remove select on non-existing CRYPTO_SHA384 [ Upstream commit 980b4c95e78e4113cb7b9f430f121dab1c814b6c ] Since CRYPTO_SHA384 does not exists, Kconfig should not select it. Anyway, all SHA384 stuff is in CRYPTO_SHA512 which is already selected. Fixes: a21eb94fc4d3i ("crypto: axis - add ARTPEC-6/7 crypto accelerator driver") Signed-off-by: Corentin Labbe Signed-off-by: Herbert Xu Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/crypto/Kconfig | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig index fe33c199fc1a..143f8bc403b9 100644 --- a/drivers/crypto/Kconfig +++ b/drivers/crypto/Kconfig @@ -721,7 +721,6 @@ config CRYPTO_DEV_ARTPEC6 select CRYPTO_HASH select CRYPTO_SHA1 select CRYPTO_SHA256 - select CRYPTO_SHA384 select CRYPTO_SHA512 help Enables the driver for the on-chip crypto accelerator -- GitLab From 19b3638ce46065936c2092c983227ae7f2161220 Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe Date: Wed, 24 Jan 2018 19:58:34 -0700 Subject: [PATCH 0955/1635] RDMA/uverbs: Use an unambiguous errno for method not supported [ Upstream commit 3624a8f02568f08aef299d3b117f2226f621177d ] Returning EOPNOTSUPP is problematic because it can also be returned by the method function, and we use it in quite a few places in drivers these days. Instead, dedicate EPROTONOSUPPORT to indicate that the ioctl framework is enabled but the requested object and method are not supported by the kernel. No other case will return this code, and it lets userspace know to fall back to write(). grep says we do not use it today in drivers/infiniband subsystem. Signed-off-by: Jason Gunthorpe Reviewed-by: Matan Barak Signed-off-by: Doug Ledford Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/infiniband/core/uverbs_ioctl.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/drivers/infiniband/core/uverbs_ioctl.c b/drivers/infiniband/core/uverbs_ioctl.c index 5286ad57d903..8f2dc79ad4ec 100644 --- a/drivers/infiniband/core/uverbs_ioctl.c +++ b/drivers/infiniband/core/uverbs_ioctl.c @@ -245,16 +245,13 @@ static long ib_uverbs_cmd_verbs(struct ib_device *ib_dev, uintptr_t data[UVERBS_OPTIMIZE_USING_STACK_SZ / sizeof(uintptr_t)]; #endif - if (hdr->reserved) - return -EINVAL; - object_spec = uverbs_get_object(ib_dev, hdr->object_id); if (!object_spec) - return -EOPNOTSUPP; + return -EPROTONOSUPPORT; method_spec = uverbs_get_method(object_spec, hdr->method_id); if (!method_spec) - return -EOPNOTSUPP; + return -EPROTONOSUPPORT; if ((method_spec->flags & UVERBS_ACTION_FLAG_CREATE_ROOT) ^ !file->ucontext) return -EINVAL; @@ -310,6 +307,16 @@ static long ib_uverbs_cmd_verbs(struct ib_device *ib_dev, err = uverbs_handle_method(buf, ctx->uattrs, hdr->num_attrs, ib_dev, file, method_spec, ctx->uverbs_attr_bundle); + + /* + * EPROTONOSUPPORT is ONLY to be returned if the ioctl framework can + * not invoke the method because the request is not supported. No + * other cases should return this code. + */ + if (unlikely(err == -EPROTONOSUPPORT)) { + WARN_ON_ONCE(err == -EPROTONOSUPPORT); + err = -EINVAL; + } out: #ifdef UVERBS_OPTIMIZE_USING_STACK_SZ if (ctx_size > UVERBS_OPTIMIZE_USING_STACK_SZ) @@ -348,7 +355,7 @@ long ib_uverbs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) } if (hdr.reserved) { - err = -EOPNOTSUPP; + err = -EPROTONOSUPPORT; goto out; } -- GitLab From 27eb641f236843b34819ed05d6288dd54053827b Mon Sep 17 00:00:00 2001 From: Jake Daryll Obina Date: Fri, 22 Sep 2017 00:00:14 +0800 Subject: [PATCH 0956/1635] jffs2: Fix use-after-free bug in jffs2_iget()'s error handling path [ Upstream commit 5bdd0c6f89fba430e18d636493398389dadc3b17 ] If jffs2_iget() fails for a newly-allocated inode, jffs2_do_clear_inode() can get called twice in the error handling path, the first call in jffs2_iget() itself and the second through iget_failed(). This can result to a use-after-free error in the second jffs2_do_clear_inode() call, such as shown by the oops below wherein the second jffs2_do_clear_inode() call was trying to free node fragments that were already freed in the first jffs2_do_clear_inode() call. [ 78.178860] jffs2: error: (1904) jffs2_do_read_inode_internal: CRC failed for read_inode of inode 24 at physical location 0x1fc00c [ 78.178914] Unable to handle kernel paging request at virtual address 6b6b6b6b6b6b6b7b [ 78.185871] pgd = ffffffc03a567000 [ 78.188794] [6b6b6b6b6b6b6b7b] *pgd=0000000000000000, *pud=0000000000000000 [ 78.194968] Internal error: Oops: 96000004 [#1] PREEMPT SMP ... [ 78.513147] PC is at rb_first_postorder+0xc/0x28 [ 78.516503] LR is at jffs2_kill_fragtree+0x28/0x90 [jffs2] [ 78.520672] pc : [] lr : [] pstate: 60000105 [ 78.526757] sp : ffffff800cea38f0 [ 78.528753] x29: ffffff800cea38f0 x28: ffffffc01f3f8e80 [ 78.532754] x27: 0000000000000000 x26: ffffff800cea3c70 [ 78.536756] x25: 00000000dc67c8ae x24: ffffffc033d6945d [ 78.540759] x23: ffffffc036811740 x22: ffffff800891a5b8 [ 78.544760] x21: 0000000000000000 x20: 0000000000000000 [ 78.548762] x19: ffffffc037d48910 x18: ffffff800891a588 [ 78.552764] x17: 0000000000000800 x16: 0000000000000c00 [ 78.556766] x15: 0000000000000010 x14: 6f2065646f6e695f [ 78.560767] x13: 6461657220726f66 x12: 2064656c69616620 [ 78.564769] x11: 435243203a6c616e x10: 7265746e695f6564 [ 78.568771] x9 : 6f6e695f64616572 x8 : ffffffc037974038 [ 78.572774] x7 : bbbbbbbbbbbbbbbb x6 : 0000000000000008 [ 78.576775] x5 : 002f91d85bd44a2f x4 : 0000000000000000 [ 78.580777] x3 : 0000000000000000 x2 : 000000403755e000 [ 78.584779] x1 : 6b6b6b6b6b6b6b6b x0 : 6b6b6b6b6b6b6b6b ... [ 79.038551] [] rb_first_postorder+0xc/0x28 [ 79.042962] [] jffs2_do_clear_inode+0x88/0x100 [jffs2] [ 79.048395] [] jffs2_evict_inode+0x3c/0x48 [jffs2] [ 79.053443] [] evict+0xb0/0x168 [ 79.056835] [] iput+0x1c0/0x200 [ 79.060228] [] iget_failed+0x30/0x3c [ 79.064097] [] jffs2_iget+0x2d8/0x360 [jffs2] [ 79.068740] [] jffs2_lookup+0xe8/0x130 [jffs2] [ 79.073434] [] lookup_slow+0x118/0x190 [ 79.077435] [] walk_component+0xfc/0x28c [ 79.081610] [] path_lookupat+0x84/0x108 [ 79.085699] [] filename_lookup+0x88/0x100 [ 79.089960] [] user_path_at_empty+0x58/0x6c [ 79.094396] [] vfs_statx+0xa4/0x114 [ 79.098138] [] SyS_newfstatat+0x58/0x98 [ 79.102227] [] __sys_trace_return+0x0/0x4 [ 79.106489] Code: d65f03c0 f9400001 b40000e1 aa0103e0 (f9400821) The jffs2_do_clear_inode() call in jffs2_iget() is unnecessary since iget_failed() will eventually call jffs2_do_clear_inode() if needed, so just remove it. Fixes: 5451f79f5f81 ("iget: stop JFFS2 from using iget() and read_inode()") Reviewed-by: Richard Weinberger Signed-off-by: Jake Daryll Obina Signed-off-by: Al Viro Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- fs/jffs2/fs.c | 1 - 1 file changed, 1 deletion(-) diff --git a/fs/jffs2/fs.c b/fs/jffs2/fs.c index e96c6b05e43e..3c96f4bdc549 100644 --- a/fs/jffs2/fs.c +++ b/fs/jffs2/fs.c @@ -362,7 +362,6 @@ struct inode *jffs2_iget(struct super_block *sb, unsigned long ino) ret = -EIO; error: mutex_unlock(&f->sem); - jffs2_do_clear_inode(c, f); iget_failed(inode); return ERR_PTR(ret); } -- GitLab From 7addb3e4ad3db6a95a953c59884921b5883dcdec Mon Sep 17 00:00:00 2001 From: Emil Tantilov Date: Fri, 12 Jan 2018 14:02:56 -0800 Subject: [PATCH 0957/1635] ixgbe: don't set RXDCTL.RLPML for 82599 [ Upstream commit 2bafa8fac19a31ca72ae1a3e48df35f73661dbed ] commit 2de6aa3a666e ("ixgbe: Add support for padding packet") Uses RXDCTL.RLPML to limit the maximum frame size on Rx when using build_skb. Unfortunately that register does not work on 82599. Added an explicit check to avoid setting this register on 82599 MAC. Extended the comment related to the setting of RXDCTL.RLPML to better explain its purpose. Signed-off-by: Emil Tantilov Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c index 29f600fd6977..9e30cfeac04b 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c @@ -3987,11 +3987,15 @@ void ixgbe_configure_rx_ring(struct ixgbe_adapter *adapter, rxdctl &= ~0x3FFFFF; rxdctl |= 0x080420; #if (PAGE_SIZE < 8192) - } else { + /* RXDCTL.RLPML does not work on 82599 */ + } else if (hw->mac.type != ixgbe_mac_82599EB) { rxdctl &= ~(IXGBE_RXDCTL_RLPMLMASK | IXGBE_RXDCTL_RLPML_EN); - /* Limit the maximum frame size so we don't overrun the skb */ + /* Limit the maximum frame size so we don't overrun the skb. + * This can happen in SRIOV mode when the MTU of the VF is + * higher than the MTU of the PF. + */ if (ring_uses_build_skb(ring) && !test_bit(__IXGBE_RX_3K_BUFFER, &ring->state)) rxdctl |= IXGBE_MAX_2K_FRAME_BUILD_SKB | -- GitLab From 1ec85fe4e259a25e69c7d73fa5efe47074fcff46 Mon Sep 17 00:00:00 2001 From: Jacob Keller Date: Wed, 27 Dec 2017 08:24:12 -0500 Subject: [PATCH 0958/1635] i40e: program fragmented IPv4 filter input set [ Upstream commit 02b4016bfe43d2d5ed043be7ffa56cda6a4d1100 ] When implementing support for IP_USER_FLOW filters, we correctly programmed a filter for both the non fragmented IPv4/Other filter, as well as the fragmented IPv4 filters. However, we did not properly program the input set for fragmented IPv4 PCTYPE. This meant that the filters would almost certainly not match, unless the user specified all of the flow types. Add support to program the fragmented IPv4 filter input set. Since we always program these filters together, we'll assume that the two input sets must match, and will thus always program the input sets to the same value. Signed-off-by: Jacob Keller Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/intel/i40e/i40e_ethtool.c | 10 ++++++++++ drivers/net/ethernet/intel/i40e/i40e_main.c | 3 +++ 2 files changed, 13 insertions(+) diff --git a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c index 05e89864f781..fc27ba5caa55 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c +++ b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c @@ -3648,6 +3648,16 @@ static int i40e_check_fdir_input_set(struct i40e_vsi *vsi, i40e_write_fd_input_set(pf, index, new_mask); + /* IP_USER_FLOW filters match both IPv4/Other and IPv4/Fragmented + * frames. If we're programming the input set for IPv4/Other, we also + * need to program the IPv4/Fragmented input set. Since we don't have + * separate support, we'll always assume and enforce that the two flow + * types must have matching input sets. + */ + if (index == I40E_FILTER_PCTYPE_NONF_IPV4_OTHER) + i40e_write_fd_input_set(pf, I40E_FILTER_PCTYPE_FRAG_IPV4, + new_mask); + /* Add the new offset and update table, if necessary */ if (new_flex_offset) { err = i40e_add_flex_offset(&pf->l4_flex_pit_list, src_offset, diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index b1cde1b051a4..d36b799116e4 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -5828,6 +5828,9 @@ static void i40e_fdir_filter_exit(struct i40e_pf *pf) /* Reprogram the default input set for Other/IPv4 */ i40e_write_fd_input_set(pf, I40E_FILTER_PCTYPE_NONF_IPV4_OTHER, I40E_L3_SRC_MASK | I40E_L3_DST_MASK); + + i40e_write_fd_input_set(pf, I40E_FILTER_PCTYPE_FRAG_IPV4, + I40E_L3_SRC_MASK | I40E_L3_DST_MASK); } /** -- GitLab From 64e5e46cdd8b3fcfed016dc89f057087346ad742 Mon Sep 17 00:00:00 2001 From: Jacob Keller Date: Wed, 27 Dec 2017 08:26:33 -0500 Subject: [PATCH 0959/1635] i40e: fix reported mask for ntuple filters [ Upstream commit 40339af33c703bacb336493157d43c86a8bf2fed ] In commit 36777d9fa24c ("i40e: check current configured input set when adding ntuple filters") some code was added to report the input set mask for a given filter when reporting it to the user. This code is necessary so that the reported filter correctly displays that it is or is not masking certain fields. Unfortunately the code was incorrect. Development error accidentally swapped the mask values for the IPv4 addresses with the L4 port numbers. The port numbers are only 16bits wide while IPv4 addresses are 32 bits. Unfortunately we assigned only 16 bits to the IPv4 address masks. Additionally we assigned 32bit value 0xFFFFFFF to the TCP port numbers. This second part does not matter as the value would be truncated to 16bits regardless, but it is unnecessary. Fix the reported masks to properly report that the entire field is masked. Fixes: 36777d9fa24c ("i40e: check current configured input set when adding ntuple filters") Signed-off-by: Jacob Keller Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/intel/i40e/i40e_ethtool.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c index fc27ba5caa55..ef22793d6a03 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c +++ b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c @@ -2588,16 +2588,16 @@ static int i40e_get_ethtool_fdir_entry(struct i40e_pf *pf, no_input_set: if (input_set & I40E_L3_SRC_MASK) - fsp->m_u.tcp_ip4_spec.ip4src = htonl(0xFFFF); + fsp->m_u.tcp_ip4_spec.ip4src = htonl(0xFFFFFFFF); if (input_set & I40E_L3_DST_MASK) - fsp->m_u.tcp_ip4_spec.ip4dst = htonl(0xFFFF); + fsp->m_u.tcp_ip4_spec.ip4dst = htonl(0xFFFFFFFF); if (input_set & I40E_L4_SRC_MASK) - fsp->m_u.tcp_ip4_spec.psrc = htons(0xFFFFFFFF); + fsp->m_u.tcp_ip4_spec.psrc = htons(0xFFFF); if (input_set & I40E_L4_DST_MASK) - fsp->m_u.tcp_ip4_spec.pdst = htons(0xFFFFFFFF); + fsp->m_u.tcp_ip4_spec.pdst = htons(0xFFFF); if (rule->dest_ctl == I40E_FILTER_PROGRAM_DESC_DEST_DROP_PACKET) fsp->ring_cookie = RX_CLS_FLOW_DISC; -- GitLab From b086dd2d79d911abbc6001ef2d59dc6a042ae5d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Sala=C3=BCn?= Date: Fri, 26 Jan 2018 01:39:30 +0100 Subject: [PATCH 0960/1635] samples/bpf: Partially fixes the bpf.o build MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit c25ef6a5e62fa212d298ce24995ce239f29b5f96 ] Do not build lib/bpf/bpf.o with this Makefile but use the one from the library directory. This avoid making a buggy bpf.o file (e.g. missing symbols). This patch is useful if some code (e.g. Landlock tests) needs both the bpf.o (from tools/lib/bpf) and the bpf_load.o (from samples/bpf). Signed-off-by: Mickaël Salaün Cc: Alexei Starovoitov Cc: Daniel Borkmann Signed-off-by: Daniel Borkmann Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- samples/bpf/Makefile | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/samples/bpf/Makefile b/samples/bpf/Makefile index 9b4a66e3363e..c1dc632d4ea4 100644 --- a/samples/bpf/Makefile +++ b/samples/bpf/Makefile @@ -179,13 +179,16 @@ LLC ?= llc CLANG ?= clang # Trick to allow make to be run from this directory -all: +all: $(LIBBPF) $(MAKE) -C ../../ $(CURDIR)/ clean: $(MAKE) -C ../../ M=$(CURDIR) clean @rm -f *~ +$(LIBBPF): FORCE + $(MAKE) -C $(dir $@) $(notdir $@) + $(obj)/syscall_nrs.s: $(src)/syscall_nrs.c $(call if_changed_dep,cc_s_c) -- GitLab From 0caebc3810328467cc67dadee612603d24087a9f Mon Sep 17 00:00:00 2001 From: Michael Bringmann Date: Tue, 28 Nov 2017 16:58:36 -0600 Subject: [PATCH 0961/1635] powerpc/numa: Use ibm,max-associativity-domains to discover possible nodes [ Upstream commit a346137e9142b039fd13af2e59696e3d40c487ef ] On powerpc systems which allow 'hot-add' of CPU or memory resources, it may occur that the new resources are to be inserted into nodes that were not used for these resources at bootup. In the kernel, any node that is used must be defined and initialized. These empty nodes may occur when, * Dedicated vs. shared resources. Shared resources require information such as the VPHN hcall for CPU assignment to nodes. Associativity decisions made based on dedicated resource rules, such as associativity properties in the device tree, may vary from decisions made using the values returned by the VPHN hcall. * memoryless nodes at boot. Nodes need to be defined as 'possible' at boot for operation with other code modules. Previously, the powerpc code would limit the set of possible nodes to those which have memory assigned at boot, and were thus online. Subsequent add/remove of CPUs or memory would only work with this subset of possible nodes. * memoryless nodes with CPUs at boot. Due to the previous restriction on nodes, nodes that had CPUs but no memory were being collapsed into other nodes that did have memory at boot. In practice this meant that the node assignment presented by the runtime kernel differed from the affinity and associativity attributes presented by the device tree or VPHN hcalls. Nodes that might be known to the pHyp were not 'possible' in the runtime kernel because they did not have memory at boot. This patch ensures that sufficient nodes are defined to support configuration requirements after boot, as well as at boot. This patch set fixes a couple of problems. * Nodes known to powerpc to be memoryless at boot, but to have CPUs in them are allowed to be 'possible' and 'online'. Memory allocations for those nodes are taken from another node that does have memory until and if memory is hot-added to the node. * Nodes which have no resources assigned at boot, but which may still be referenced subsequently by affinity or associativity attributes, are kept in the list of 'possible' nodes for powerpc. Hot-add of memory or CPUs to the system can reference these nodes and bring them online instead of redirecting to one of the set of nodes that were known to have memory at boot. This patch extracts the value of the lowest domain level (number of allocable resources) from the device tree property "ibm,max-associativity-domains" to use as the maximum number of nodes to setup as possibly available in the system. This new setting will override the instruction: nodes_and(node_possible_map, node_possible_map, node_online_map); presently seen in the function arch/powerpc/mm/numa.c:initmem_init(). If the "ibm,max-associativity-domains" property is not present at boot, no operation will be performed to define or enable additional nodes, or enable the above 'nodes_and()'. Signed-off-by: Michael Bringmann Reviewed-by: Nathan Fontenot Signed-off-by: Michael Ellerman Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/mm/numa.c | 37 ++++++++++++++++++++++++++++++++++--- 1 file changed, 34 insertions(+), 3 deletions(-) diff --git a/arch/powerpc/mm/numa.c b/arch/powerpc/mm/numa.c index a81279249bfb..0356c6cceff7 100644 --- a/arch/powerpc/mm/numa.c +++ b/arch/powerpc/mm/numa.c @@ -887,6 +887,34 @@ static void __init setup_node_data(int nid, u64 start_pfn, u64 end_pfn) NODE_DATA(nid)->node_spanned_pages = spanned_pages; } +static void __init find_possible_nodes(void) +{ + struct device_node *rtas; + u32 numnodes, i; + + if (min_common_depth <= 0) + return; + + rtas = of_find_node_by_path("/rtas"); + if (!rtas) + return; + + if (of_property_read_u32_index(rtas, + "ibm,max-associativity-domains", + min_common_depth, &numnodes)) + goto out; + + for (i = 0; i < numnodes; i++) { + if (!node_possible(i)) { + setup_node_data(i, 0, 0); + node_set(i, node_possible_map); + } + } + +out: + of_node_put(rtas); +} + void __init initmem_init(void) { int nid, cpu; @@ -900,12 +928,15 @@ void __init initmem_init(void) memblock_dump_all(); /* - * Reduce the possible NUMA nodes to the online NUMA nodes, - * since we do not support node hotplug. This ensures that we - * lower the maximum NUMA node ID to what is actually present. + * Modify the set of possible NUMA nodes to reflect information + * available about the set of online nodes, and the set of nodes + * that we expect to make use of for this platform's affinity + * calculations. */ nodes_and(node_possible_map, node_possible_map, node_online_map); + find_possible_nodes(); + for_each_online_node(nid) { unsigned long start_pfn, end_pfn; -- GitLab From 0bddd43ac2001d87471117ff29e789aa3bcfd18b Mon Sep 17 00:00:00 2001 From: Michael Bringmann Date: Tue, 28 Nov 2017 16:58:40 -0600 Subject: [PATCH 0962/1635] powerpc/numa: Ensure nodes initialized for hotplug [ Upstream commit ea05ba7c559c8e5a5946c3a94a2a266e9a6680a6 ] This patch fixes some problems encountered at runtime with configurations that support memory-less nodes, or that hot-add CPUs into nodes that are memoryless during system execution after boot. The problems of interest include: * Nodes known to powerpc to be memoryless at boot, but to have CPUs in them are allowed to be 'possible' and 'online'. Memory allocations for those nodes are taken from another node that does have memory until and if memory is hot-added to the node. * Nodes which have no resources assigned at boot, but which may still be referenced subsequently by affinity or associativity attributes, are kept in the list of 'possible' nodes for powerpc. Hot-add of memory or CPUs to the system can reference these nodes and bring them online instead of redirecting the references to one of the set of nodes known to have memory at boot. Note that this software operates under the context of CPU hotplug. We are not doing memory hotplug in this code, but rather updating the kernel's CPU topology (i.e. arch_update_cpu_topology / numa_update_cpu_topology). We are initializing a node that may be used by CPUs or memory before it can be referenced as invalid by a CPU hotplug operation. CPU hotplug operations are protected by a range of APIs including cpu_maps_update_begin/cpu_maps_update_done, cpus_read/write_lock / cpus_read/write_unlock, device locks, and more. Memory hotplug operations, including try_online_node, are protected by mem_hotplug_begin/mem_hotplug_done, device locks, and more. In the case of CPUs being hot-added to a previously memoryless node, the try_online_node operation occurs wholly within the CPU locks with no overlap. Using HMC hot-add/hot-remove operations, we have been able to add and remove CPUs to any possible node without failures. HMC operations involve a degree self-serialization, though. Signed-off-by: Michael Bringmann Reviewed-by: Nathan Fontenot Signed-off-by: Michael Ellerman Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/mm/numa.c | 47 +++++++++++++++++++++++++++++++++--------- 1 file changed, 37 insertions(+), 10 deletions(-) diff --git a/arch/powerpc/mm/numa.c b/arch/powerpc/mm/numa.c index 0356c6cceff7..9fead0796364 100644 --- a/arch/powerpc/mm/numa.c +++ b/arch/powerpc/mm/numa.c @@ -546,7 +546,7 @@ static int numa_setup_cpu(unsigned long lcpu) nid = of_node_to_nid_single(cpu); out_present: - if (nid < 0 || !node_online(nid)) + if (nid < 0 || !node_possible(nid)) nid = first_online_node; map_cpu_to_node(lcpu, nid); @@ -905,10 +905,8 @@ static void __init find_possible_nodes(void) goto out; for (i = 0; i < numnodes; i++) { - if (!node_possible(i)) { - setup_node_data(i, 0, 0); + if (!node_possible(i)) node_set(i, node_possible_map); - } } out: @@ -1277,6 +1275,40 @@ static long vphn_get_associativity(unsigned long cpu, return rc; } +static inline int find_and_online_cpu_nid(int cpu) +{ + __be32 associativity[VPHN_ASSOC_BUFSIZE] = {0}; + int new_nid; + + /* Use associativity from first thread for all siblings */ + vphn_get_associativity(cpu, associativity); + new_nid = associativity_to_nid(associativity); + if (new_nid < 0 || !node_possible(new_nid)) + new_nid = first_online_node; + + if (NODE_DATA(new_nid) == NULL) { +#ifdef CONFIG_MEMORY_HOTPLUG + /* + * Need to ensure that NODE_DATA is initialized for a node from + * available memory (see memblock_alloc_try_nid). If unable to + * init the node, then default to nearest node that has memory + * installed. + */ + if (try_online_node(new_nid)) + new_nid = first_online_node; +#else + /* + * Default to using the nearest node that has memory installed. + * Otherwise, it would be necessary to patch the kernel MM code + * to deal with more memoryless-node error conditions. + */ + new_nid = first_online_node; +#endif + } + + return new_nid; +} + /* * Update the CPU maps and sysfs entries for a single CPU when its NUMA * characteristics change. This function doesn't perform any locking and is @@ -1344,7 +1376,6 @@ int numa_update_cpu_topology(bool cpus_locked) { unsigned int cpu, sibling, changed = 0; struct topology_update_data *updates, *ud; - __be32 associativity[VPHN_ASSOC_BUFSIZE] = {0}; cpumask_t updated_cpus; struct device *dev; int weight, new_nid, i = 0; @@ -1379,11 +1410,7 @@ int numa_update_cpu_topology(bool cpus_locked) continue; } - /* Use associativity from first thread for all siblings */ - vphn_get_associativity(cpu, associativity); - new_nid = associativity_to_nid(associativity); - if (new_nid < 0 || !node_online(new_nid)) - new_nid = first_online_node; + new_nid = find_and_online_cpu_nid(cpu); if (new_nid == numa_cpu_lookup_table[cpu]) { cpumask_andnot(&cpu_associativity_changes_mask, -- GitLab From d810c548157f9f2533864bfb220787eaa9e36e3e Mon Sep 17 00:00:00 2001 From: Leon Romanovsky Date: Sun, 28 Jan 2018 11:25:30 +0200 Subject: [PATCH 0963/1635] RDMA/mlx5: Avoid memory leak in case of XRCD dealloc failure [ Upstream commit b081808a66345ba725b77ecd8d759bee874cd937 ] Failure in XRCD FW deallocation command leaves memory leaked and returns error to the user which he can't do anything about it. This patch changes behavior to always free memory and always return success to the user. Fixes: e126ba97dba9 ("mlx5: Add driver for Mellanox Connect-IB adapters") Reviewed-by: Majd Dibbiny Signed-off-by: Leon Romanovsky Reviewed-by: Yuval Shaia Signed-off-by: Jason Gunthorpe Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/infiniband/hw/mlx5/qp.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/infiniband/hw/mlx5/qp.c b/drivers/infiniband/hw/mlx5/qp.c index c4d8cc1c2b1d..e1978d91a2f7 100644 --- a/drivers/infiniband/hw/mlx5/qp.c +++ b/drivers/infiniband/hw/mlx5/qp.c @@ -4636,13 +4636,10 @@ int mlx5_ib_dealloc_xrcd(struct ib_xrcd *xrcd) int err; err = mlx5_core_xrcd_dealloc(dev->mdev, xrcdn); - if (err) { + if (err) mlx5_ib_warn(dev, "failed to dealloc xrcdn 0x%x\n", xrcdn); - return err; - } kfree(xrcd); - return 0; } -- GitLab From 67fa8bfff771973a6867ca4be8b6c29e6e2e312f Mon Sep 17 00:00:00 2001 From: Logan Gunthorpe Date: Mon, 18 Dec 2017 11:25:05 -0700 Subject: [PATCH 0964/1635] ntb_transport: Fix bug with max_mw_size parameter [ Upstream commit cbd27448faff4843ac4b66cc71445a10623ff48d ] When using the max_mw_size parameter of ntb_transport to limit the size of the Memory windows, communication cannot be established and the queues freeze. This is because the mw_size that's reported to the peer is correctly limited but the size used locally is not. So the MW is initialized with a buffer smaller than the window but the TX side is using the full window. This means the TX side will be writing to a region of the window that points nowhere. This is easily fixed by applying the same limit to tx_size in ntb_transport_init_queue(). Fixes: e26a5843f7f5 ("NTB: Split ntb_hw_intel and ntb_transport drivers") Signed-off-by: Logan Gunthorpe Acked-by: Allen Hubbe Cc: Dave Jiang Signed-off-by: Jon Mason Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/ntb/ntb_transport.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/ntb/ntb_transport.c b/drivers/ntb/ntb_transport.c index f58d8e305323..18339b7e88a4 100644 --- a/drivers/ntb/ntb_transport.c +++ b/drivers/ntb/ntb_transport.c @@ -998,6 +998,9 @@ static int ntb_transport_init_queue(struct ntb_transport_ctx *nt, mw_base = nt->mw_vec[mw_num].phys_addr; mw_size = nt->mw_vec[mw_num].phys_size; + if (max_mw_size && mw_size > max_mw_size) + mw_size = max_mw_size; + tx_size = (unsigned int)mw_size / num_qps_mw; qp_offset = tx_size * (qp_num / mw_count); -- GitLab From cdf635a66c5ba80fa03275265d6191fb3adf33c8 Mon Sep 17 00:00:00 2001 From: Andy Spencer Date: Thu, 25 Jan 2018 19:37:50 -0800 Subject: [PATCH 0965/1635] gianfar: prevent integer wrapping in the rx handler [ Upstream commit 202a0a70e445caee1d0ec7aae814e64b1189fa4d ] When the frame check sequence (FCS) is split across the last two frames of a fragmented packet, part of the FCS gets counted twice, once when subtracting the FCS, and again when subtracting the previously received data. For example, if 1602 bytes are received, and the first fragment contains the first 1600 bytes (including the first two bytes of the FCS), and the second fragment contains the last two bytes of the FCS: 'skb->len == 1600' from the first fragment size = lstatus & BD_LENGTH_MASK; # 1602 size -= ETH_FCS_LEN; # 1598 size -= skb->len; # -2 Since the size is unsigned, it wraps around and causes a BUG later in the packet handling, as shown below: kernel BUG at ./include/linux/skbuff.h:2068! Oops: Exception in kernel mode, sig: 5 [#1] ... NIP [c021ec60] skb_pull+0x24/0x44 LR [c01e2fbc] gfar_clean_rx_ring+0x498/0x690 Call Trace: [df7edeb0] [c01e2c1c] gfar_clean_rx_ring+0xf8/0x690 (unreliable) [df7edf20] [c01e33a8] gfar_poll_rx_sq+0x3c/0x9c [df7edf40] [c023352c] net_rx_action+0x21c/0x274 [df7edf90] [c0329000] __do_softirq+0xd8/0x240 [df7edff0] [c000c108] call_do_irq+0x24/0x3c [c0597e90] [c00041dc] do_IRQ+0x64/0xc4 [c0597eb0] [c000d920] ret_from_except+0x0/0x18 --- interrupt: 501 at arch_cpu_idle+0x24/0x5c Change the size to a signed integer and then trim off any part of the FCS that was received prior to the last fragment. Fixes: 6c389fc931bc ("gianfar: fix size of scatter-gathered frames") Signed-off-by: Andy Spencer Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/freescale/gianfar.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/freescale/gianfar.c b/drivers/net/ethernet/freescale/gianfar.c index 7f837006bb6a..3bdeb295514b 100644 --- a/drivers/net/ethernet/freescale/gianfar.c +++ b/drivers/net/ethernet/freescale/gianfar.c @@ -2932,7 +2932,7 @@ static irqreturn_t gfar_transmit(int irq, void *grp_id) static bool gfar_add_rx_frag(struct gfar_rx_buff *rxb, u32 lstatus, struct sk_buff *skb, bool first) { - unsigned int size = lstatus & BD_LENGTH_MASK; + int size = lstatus & BD_LENGTH_MASK; struct page *page = rxb->page; bool last = !!(lstatus & BD_LFLAG(RXBD_LAST)); @@ -2947,11 +2947,16 @@ static bool gfar_add_rx_frag(struct gfar_rx_buff *rxb, u32 lstatus, if (last) size -= skb->len; - /* in case the last fragment consisted only of the FCS */ + /* Add the last fragment if it contains something other than + * the FCS, otherwise drop it and trim off any part of the FCS + * that was already received. + */ if (size > 0) skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags, page, rxb->page_offset + RXBUF_ALIGNMENT, size, GFAR_RXB_TRUESIZE); + else if (size < 0) + pskb_trim(skb, skb->len + size); } /* try reuse page */ -- GitLab From 2b7cc93682acf720f6b2e1a690ccdae71129e6fc Mon Sep 17 00:00:00 2001 From: Vitaly Kuznetsov Date: Wed, 24 Jan 2018 14:23:31 +0100 Subject: [PATCH 0966/1635] x86/hyperv: Check for required priviliges in hyperv_init() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit 89a8f6d4904c8cf3ff8fee9fdaff392a6bbb8bf6 ] In hyperv_init() its presumed that it always has access to VP index and hypercall MSRs while according to the specification it should be checked if it's allowed to access the corresponding MSRs before accessing them. Signed-off-by: Vitaly Kuznetsov Signed-off-by: Thomas Gleixner Reviewed-by: Thomas Gleixner Cc: Stephen Hemminger Cc: kvm@vger.kernel.org Cc: Radim Krčmář Cc: Haiyang Zhang Cc: "Michael Kelley (EOSG)" Cc: Roman Kagan Cc: Andy Lutomirski Cc: devel@linuxdriverproject.org Cc: Paolo Bonzini Cc: "K. Y. Srinivasan" Cc: Cathy Avery Cc: Mohammed Gamal Link: https://lkml.kernel.org/r/20180124132337.30138-2-vkuznets@redhat.com Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/x86/hyperv/hv_init.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/arch/x86/hyperv/hv_init.c b/arch/x86/hyperv/hv_init.c index a0b86cf486e0..2e9d58cc371e 100644 --- a/arch/x86/hyperv/hv_init.c +++ b/arch/x86/hyperv/hv_init.c @@ -110,12 +110,19 @@ static int hv_cpu_init(unsigned int cpu) */ void hyperv_init(void) { - u64 guest_id; + u64 guest_id, required_msrs; union hv_x64_msr_hypercall_contents hypercall_msr; if (x86_hyper_type != X86_HYPER_MS_HYPERV) return; + /* Absolutely required MSRs */ + required_msrs = HV_X64_MSR_HYPERCALL_AVAILABLE | + HV_X64_MSR_VP_INDEX_AVAILABLE; + + if ((ms_hyperv.features & required_msrs) != required_msrs) + return; + /* Allocate percpu VP index */ hv_vp_index = kmalloc_array(num_possible_cpus(), sizeof(*hv_vp_index), GFP_KERNEL); -- GitLab From ad10785a706e63ff155fc97860cdcc5e3bc5992d Mon Sep 17 00:00:00 2001 From: Dmitry Vyukov Date: Mon, 29 Jan 2018 13:21:20 +0100 Subject: [PATCH 0967/1635] netfilter: x_tables: fix pointer leaks to userspace [ Upstream commit 1e98ffea5a8935ec040ab72299e349cb44b8defd ] Several netfilter matches and targets put kernel pointers into info objects, but don't set usersize in descriptors. This leads to kernel pointer leaks if a match/target is set and then read back to userspace. Properly set usersize for these matches/targets. Found with manual code inspection. Fixes: ec2318904965 ("xtables: extend matches and targets with .usersize") Signed-off-by: Dmitry Vyukov Signed-off-by: Pablo Neira Ayuso Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- net/netfilter/xt_IDLETIMER.c | 1 + net/netfilter/xt_LED.c | 1 + net/netfilter/xt_limit.c | 3 +-- net/netfilter/xt_nfacct.c | 1 + net/netfilter/xt_statistic.c | 1 + 5 files changed, 5 insertions(+), 2 deletions(-) diff --git a/net/netfilter/xt_IDLETIMER.c b/net/netfilter/xt_IDLETIMER.c index bb5d6a058fb7..1141f08810b6 100644 --- a/net/netfilter/xt_IDLETIMER.c +++ b/net/netfilter/xt_IDLETIMER.c @@ -256,6 +256,7 @@ static struct xt_target idletimer_tg __read_mostly = { .family = NFPROTO_UNSPEC, .target = idletimer_tg_target, .targetsize = sizeof(struct idletimer_tg_info), + .usersize = offsetof(struct idletimer_tg_info, timer), .checkentry = idletimer_tg_checkentry, .destroy = idletimer_tg_destroy, .me = THIS_MODULE, diff --git a/net/netfilter/xt_LED.c b/net/netfilter/xt_LED.c index 0858fe17e14a..2d1c5c169a26 100644 --- a/net/netfilter/xt_LED.c +++ b/net/netfilter/xt_LED.c @@ -198,6 +198,7 @@ static struct xt_target led_tg_reg __read_mostly = { .family = NFPROTO_UNSPEC, .target = led_tg, .targetsize = sizeof(struct xt_led_info), + .usersize = offsetof(struct xt_led_info, internal_data), .checkentry = led_tg_check, .destroy = led_tg_destroy, .me = THIS_MODULE, diff --git a/net/netfilter/xt_limit.c b/net/netfilter/xt_limit.c index d27b5f1ea619..61403b77361c 100644 --- a/net/netfilter/xt_limit.c +++ b/net/netfilter/xt_limit.c @@ -193,9 +193,8 @@ static struct xt_match limit_mt_reg __read_mostly = { .compatsize = sizeof(struct compat_xt_rateinfo), .compat_from_user = limit_mt_compat_from_user, .compat_to_user = limit_mt_compat_to_user, -#else - .usersize = offsetof(struct xt_rateinfo, prev), #endif + .usersize = offsetof(struct xt_rateinfo, prev), .me = THIS_MODULE, }; diff --git a/net/netfilter/xt_nfacct.c b/net/netfilter/xt_nfacct.c index cc0518fe598e..6f92d25590a8 100644 --- a/net/netfilter/xt_nfacct.c +++ b/net/netfilter/xt_nfacct.c @@ -62,6 +62,7 @@ static struct xt_match nfacct_mt_reg __read_mostly = { .match = nfacct_mt, .destroy = nfacct_mt_destroy, .matchsize = sizeof(struct xt_nfacct_match_info), + .usersize = offsetof(struct xt_nfacct_match_info, nfacct), .me = THIS_MODULE, }; diff --git a/net/netfilter/xt_statistic.c b/net/netfilter/xt_statistic.c index 11de55e7a868..8710fdba2ae2 100644 --- a/net/netfilter/xt_statistic.c +++ b/net/netfilter/xt_statistic.c @@ -84,6 +84,7 @@ static struct xt_match xt_statistic_mt_reg __read_mostly = { .checkentry = statistic_mt_check, .destroy = statistic_mt_destroy, .matchsize = sizeof(struct xt_statistic_info), + .usersize = offsetof(struct xt_statistic_info, master), .me = THIS_MODULE, }; -- GitLab From a6a25002e6d83c4b66297a0fd192927c8fa0988d Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Tue, 30 Jan 2018 22:21:48 -0600 Subject: [PATCH 0968/1635] tcp_nv: fix potential integer overflow in tcpnv_acked [ Upstream commit e4823fbd229bfbba368b40cdadb8f4eeb20604cc ] Add suffix ULL to constant 80000 in order to avoid a potential integer overflow and give the compiler complete information about the proper arithmetic to use. Notice that this constant is used in a context that expects an expression of type u64. The current cast to u64 effectively applies to the whole expression as an argument of type u64 to be passed to div64_u64, but it does not prevent it from being evaluated using 32-bit arithmetic instead of 64-bit arithmetic. Also, once the expression is properly evaluated using 64-bit arithmentic, there is no need for the parentheses and the external cast to u64. Addresses-Coverity-ID: 1357588 ("Unintentional integer overflow") Signed-off-by: Gustavo A. R. Silva Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- net/ipv4/tcp_nv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/ipv4/tcp_nv.c b/net/ipv4/tcp_nv.c index 125fc1450b01..09f8773fd769 100644 --- a/net/ipv4/tcp_nv.c +++ b/net/ipv4/tcp_nv.c @@ -327,7 +327,7 @@ static void tcpnv_acked(struct sock *sk, const struct ack_sample *sample) */ cwnd_by_slope = (u32) div64_u64(((u64)ca->nv_rtt_max_rate) * ca->nv_min_rtt, - (u64)(80000 * tp->mss_cache)); + 80000ULL * tp->mss_cache); max_win = cwnd_by_slope + nv_pad; /* If cwnd > max_win, decrease cwnd -- GitLab From d757c3a9cf4a8af26d085054731ebd9b5bc9983c Mon Sep 17 00:00:00 2001 From: KarimAllah Ahmed Date: Wed, 17 Jan 2018 19:18:56 +0100 Subject: [PATCH 0969/1635] kvm: Map PFN-type memory regions as writable (if possible) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit a340b3e229b24a56f1c7f5826b15a3af0f4b13e5 ] For EPT-violations that are triggered by a read, the pages are also mapped with write permissions (if their memory region is also writable). That would avoid getting yet another fault on the same page when a write occurs. This optimization only happens when you have a "struct page" backing the memory region. So also enable it for memory regions that do not have a "struct page". Cc: Paolo Bonzini Cc: Radim Krčmář Cc: kvm@vger.kernel.org Cc: linux-kernel@vger.kernel.org Signed-off-by: KarimAllah Ahmed Reviewed-by: Paolo Bonzini Signed-off-by: Radim Krčmář Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- virt/kvm/kvm_main.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index d81af263f50b..4f35f0dfe681 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c @@ -1434,7 +1434,8 @@ static bool vma_is_valid(struct vm_area_struct *vma, bool write_fault) static int hva_to_pfn_remapped(struct vm_area_struct *vma, unsigned long addr, bool *async, - bool write_fault, kvm_pfn_t *p_pfn) + bool write_fault, bool *writable, + kvm_pfn_t *p_pfn) { unsigned long pfn; int r; @@ -1460,6 +1461,8 @@ static int hva_to_pfn_remapped(struct vm_area_struct *vma, } + if (writable) + *writable = true; /* * Get a reference here because callers of *hva_to_pfn* and @@ -1525,7 +1528,7 @@ static kvm_pfn_t hva_to_pfn(unsigned long addr, bool atomic, bool *async, if (vma == NULL) pfn = KVM_PFN_ERR_FAULT; else if (vma->vm_flags & (VM_IO | VM_PFNMAP)) { - r = hva_to_pfn_remapped(vma, addr, async, write_fault, &pfn); + r = hva_to_pfn_remapped(vma, addr, async, write_fault, writable, &pfn); if (r == -EAGAIN) goto retry; if (r < 0) -- GitLab From cc0600dae30fe2ca2f3783599420a1b9bb88715d Mon Sep 17 00:00:00 2001 From: Vitaly Kuznetsov Date: Thu, 25 Jan 2018 16:37:07 +0100 Subject: [PATCH 0970/1635] x86/kvm/vmx: do not use vm-exit instruction length for fast MMIO when running nested MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit d391f1207067268261add0485f0f34503539c5b0 ] I was investigating an issue with seabios >= 1.10 which stopped working for nested KVM on Hyper-V. The problem appears to be in handle_ept_violation() function: when we do fast mmio we need to skip the instruction so we do kvm_skip_emulated_instruction(). This, however, depends on VM_EXIT_INSTRUCTION_LEN field being set correctly in VMCS. However, this is not the case. Intel's manual doesn't mandate VM_EXIT_INSTRUCTION_LEN to be set when EPT MISCONFIG occurs. While on real hardware it was observed to be set, some hypervisors follow the spec and don't set it; we end up advancing IP with some random value. I checked with Microsoft and they confirmed they don't fill VM_EXIT_INSTRUCTION_LEN on EPT MISCONFIG. Fix the issue by doing instruction skip through emulator when running nested. Fixes: 68c3b4d1676d870f0453c31d5a52e7e65c7448ae Suggested-by: Radim Krčmář Suggested-by: Paolo Bonzini Signed-off-by: Vitaly Kuznetsov Acked-by: Michael S. Tsirkin Signed-off-by: Radim Krčmář Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/x86/kvm/vmx.c | 16 +++++++++++++++- arch/x86/kvm/x86.c | 3 ++- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index ae4803b213d0..bdd84ce4491e 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c @@ -6765,7 +6765,21 @@ static int handle_ept_misconfig(struct kvm_vcpu *vcpu) if (!is_guest_mode(vcpu) && !kvm_io_bus_write(vcpu, KVM_FAST_MMIO_BUS, gpa, 0, NULL)) { trace_kvm_fast_mmio(gpa); - return kvm_skip_emulated_instruction(vcpu); + /* + * Doing kvm_skip_emulated_instruction() depends on undefined + * behavior: Intel's manual doesn't mandate + * VM_EXIT_INSTRUCTION_LEN to be set in VMCS when EPT MISCONFIG + * occurs and while on real hardware it was observed to be set, + * other hypervisors (namely Hyper-V) don't set it, we end up + * advancing IP with some random value. Disable fast mmio when + * running nested and keep it for real hardware in hope that + * VM_EXIT_INSTRUCTION_LEN will always be set correctly. + */ + if (!static_cpu_has(X86_FEATURE_HYPERVISOR)) + return kvm_skip_emulated_instruction(vcpu); + else + return x86_emulate_instruction(vcpu, gpa, EMULTYPE_SKIP, + NULL, 0) == EMULATE_DONE; } ret = kvm_mmu_page_fault(vcpu, gpa, PFERR_RSVD_MASK, NULL, 0); diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index d7728bcd9a3c..3b2c3aa2cd07 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -5699,7 +5699,8 @@ int x86_emulate_instruction(struct kvm_vcpu *vcpu, * handle watchpoints yet, those would be handled in * the emulate_ops. */ - if (kvm_vcpu_check_breakpoint(vcpu, &r)) + if (!(emulation_type & EMULTYPE_SKIP) && + kvm_vcpu_check_breakpoint(vcpu, &r)) return r; ctxt->interruptibility = 0; -- GitLab From 710b5124aac67c4a48d29e32c2d9525278db405b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20H=2E=20Sch=C3=B6nherr?= Date: Wed, 31 Jan 2018 16:14:04 -0800 Subject: [PATCH 0971/1635] fs/dax.c: release PMD lock even when there is no PMD support in DAX MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit ee190ca6516bc8257e3d36187ca6f0f71a9ec477 ] follow_pte_pmd() can theoretically return after having acquired a PMD lock, even when DAX was not compiled with CONFIG_FS_DAX_PMD. Release the PMD lock unconditionally. Link: http://lkml.kernel.org/r/20180118133839.20587-1-jschoenh@amazon.de Fixes: f729c8c9b24f ("dax: wrprotect pmd_t in dax_mapping_entry_mkclean") Signed-off-by: Jan H. Schönherr Reviewed-by: Ross Zwisler Reviewed-by: Andrew Morton Cc: Matthew Wilcox Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- fs/dax.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/dax.c b/fs/dax.c index 191306cd8b6b..ddb4981ae32e 100644 --- a/fs/dax.c +++ b/fs/dax.c @@ -630,8 +630,8 @@ static void dax_mapping_entry_mkclean(struct address_space *mapping, set_pmd_at(vma->vm_mm, address, pmdp, pmd); mmu_notifier_invalidate_range(vma->vm_mm, start, end); unlock_pmd: - spin_unlock(ptl); #endif + spin_unlock(ptl); } else { if (pfn != pte_pfn(*ptep)) goto unlock_pte; -- GitLab From 66aaeed2796ef50af8775cad209e62c173463d05 Mon Sep 17 00:00:00 2001 From: piaojun Date: Wed, 31 Jan 2018 16:14:44 -0800 Subject: [PATCH 0972/1635] ocfs2: return -EROFS to mount.ocfs2 if inode block is invalid [ Upstream commit 025bcbde3634b2c9b316f227fed13ad6ad6817fb ] If metadata is corrupted such as 'invalid inode block', we will get failed by calling 'mount()' and then set filesystem readonly as below: ocfs2_mount ocfs2_initialize_super ocfs2_init_global_system_inodes ocfs2_iget ocfs2_read_locked_inode ocfs2_validate_inode_block ocfs2_error ocfs2_handle_error ocfs2_set_ro_flag(osb, 0); // set readonly In this situation we need return -EROFS to 'mount.ocfs2', so that user can fix it by fsck. And then mount again. In addition, 'mount.ocfs2' should be updated correspondingly as it only return 1 for all errno. And I will post a patch for 'mount.ocfs2' too. Link: http://lkml.kernel.org/r/5A4302FA.2010606@huawei.com Signed-off-by: Jun Piao Reviewed-by: Alex Chen Reviewed-by: Joseph Qi Reviewed-by: Changwei Ge Reviewed-by: Gang He Cc: Mark Fasheh Cc: Joel Becker Cc: Junxiao Bi Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- fs/ocfs2/super.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/fs/ocfs2/super.c b/fs/ocfs2/super.c index 80733496b22a..24ab735d91dd 100644 --- a/fs/ocfs2/super.c +++ b/fs/ocfs2/super.c @@ -474,9 +474,8 @@ static int ocfs2_init_global_system_inodes(struct ocfs2_super *osb) new = ocfs2_get_system_file_inode(osb, i, osb->slot_num); if (!new) { ocfs2_release_system_inodes(osb); - status = -EINVAL; + status = ocfs2_is_soft_readonly(osb) ? -EROFS : -EINVAL; mlog_errno(status); - /* FIXME: Should ERROR_RO_FS */ mlog(ML_ERROR, "Unable to load system inode %d, " "possibly corrupt fs?", i); goto bail; @@ -505,7 +504,7 @@ static int ocfs2_init_local_system_inodes(struct ocfs2_super *osb) new = ocfs2_get_system_file_inode(osb, i, osb->slot_num); if (!new) { ocfs2_release_system_inodes(osb); - status = -EINVAL; + status = ocfs2_is_soft_readonly(osb) ? -EROFS : -EINVAL; mlog(ML_ERROR, "status=%d, sysfile=%d, slot=%d\n", status, i, osb->slot_num); goto bail; -- GitLab From a66174eb4a149b7919d174d9a7ce6ad9909c5ee2 Mon Sep 17 00:00:00 2001 From: piaojun Date: Wed, 31 Jan 2018 16:14:59 -0800 Subject: [PATCH 0973/1635] ocfs2/acl: use 'ip_xattr_sem' to protect getting extended attribute [ Upstream commit 16c8d569f5704a84164f30ff01b29879f3438065 ] The race between *set_acl and *get_acl will cause getting incomplete xattr data as below: processA processB ocfs2_set_acl ocfs2_xattr_set __ocfs2_xattr_set_handle ocfs2_get_acl_nolock ocfs2_xattr_get_nolock: processB may get incomplete xattr data if processA hasn't set_acl done. So we should use 'ip_xattr_sem' to protect getting extended attribute in ocfs2_get_acl_nolock(), as other processes could be changing it concurrently. Link: http://lkml.kernel.org/r/5A5DDCFF.7030001@huawei.com Signed-off-by: Jun Piao Reviewed-by: Alex Chen Cc: Mark Fasheh Cc: Joel Becker Cc: Junxiao Bi Cc: Joseph Qi Cc: Changwei Ge Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- fs/ocfs2/acl.c | 6 ++++++ fs/ocfs2/xattr.c | 2 ++ 2 files changed, 8 insertions(+) diff --git a/fs/ocfs2/acl.c b/fs/ocfs2/acl.c index 40b5cc97f7b0..917fadca8a7b 100644 --- a/fs/ocfs2/acl.c +++ b/fs/ocfs2/acl.c @@ -311,7 +311,9 @@ struct posix_acl *ocfs2_iop_get_acl(struct inode *inode, int type) if (had_lock < 0) return ERR_PTR(had_lock); + down_read(&OCFS2_I(inode)->ip_xattr_sem); acl = ocfs2_get_acl_nolock(inode, type, di_bh); + up_read(&OCFS2_I(inode)->ip_xattr_sem); ocfs2_inode_unlock_tracker(inode, 0, &oh, had_lock); brelse(di_bh); @@ -330,7 +332,9 @@ int ocfs2_acl_chmod(struct inode *inode, struct buffer_head *bh) if (!(osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL)) return 0; + down_read(&OCFS2_I(inode)->ip_xattr_sem); acl = ocfs2_get_acl_nolock(inode, ACL_TYPE_ACCESS, bh); + up_read(&OCFS2_I(inode)->ip_xattr_sem); if (IS_ERR(acl) || !acl) return PTR_ERR(acl); ret = __posix_acl_chmod(&acl, GFP_KERNEL, inode->i_mode); @@ -361,8 +365,10 @@ int ocfs2_init_acl(handle_t *handle, if (!S_ISLNK(inode->i_mode)) { if (osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL) { + down_read(&OCFS2_I(dir)->ip_xattr_sem); acl = ocfs2_get_acl_nolock(dir, ACL_TYPE_DEFAULT, dir_bh); + up_read(&OCFS2_I(dir)->ip_xattr_sem); if (IS_ERR(acl)) return PTR_ERR(acl); } diff --git a/fs/ocfs2/xattr.c b/fs/ocfs2/xattr.c index 5fdf269ba82e..fb0a4eec310c 100644 --- a/fs/ocfs2/xattr.c +++ b/fs/ocfs2/xattr.c @@ -638,9 +638,11 @@ int ocfs2_calc_xattr_init(struct inode *dir, si->value_len); if (osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL) { + down_read(&OCFS2_I(dir)->ip_xattr_sem); acl_len = ocfs2_xattr_get_nolock(dir, dir_bh, OCFS2_XATTR_INDEX_POSIX_ACL_DEFAULT, "", NULL, 0); + up_read(&OCFS2_I(dir)->ip_xattr_sem); if (acl_len > 0) { a_size = ocfs2_xattr_entry_real_size(0, acl_len); if (S_ISDIR(mode)) -- GitLab From a7fbc7f3134ab4848898383a0852a8e768311498 Mon Sep 17 00:00:00 2001 From: piaojun Date: Wed, 31 Jan 2018 16:15:32 -0800 Subject: [PATCH 0974/1635] ocfs2: return error when we attempt to access a dirty bh in jbd2 [ Upstream commit d984187e3a1ad7d12447a7ab2c43ce3717a2b5b3 ] We should not reuse the dirty bh in jbd2 directly due to the following situation: 1. When removing extent rec, we will dirty the bhs of extent rec and truncate log at the same time, and hand them over to jbd2. 2. The bhs are submitted to jbd2 area successfully. 3. The write-back thread of device help flush the bhs to disk but encounter write error due to abnormal storage link. 4. After a while the storage link become normal. Truncate log flush worker triggered by the next space reclaiming found the dirty bh of truncate log and clear its 'BH_Write_EIO' and then set it uptodate in __ocfs2_journal_access(): ocfs2_truncate_log_worker ocfs2_flush_truncate_log __ocfs2_flush_truncate_log ocfs2_replay_truncate_records ocfs2_journal_access_di __ocfs2_journal_access // here we clear io_error and set 'tl_bh' uptodata. 5. Then jbd2 will flush the bh of truncate log to disk, but the bh of extent rec is still in error state, and unfortunately nobody will take care of it. 6. At last the space of extent rec was not reduced, but truncate log flush worker have given it back to globalalloc. That will cause duplicate cluster problem which could be identified by fsck.ocfs2. Sadly we can hardly revert this but set fs read-only in case of ruining atomicity and consistency of space reclaim. Link: http://lkml.kernel.org/r/5A6E8092.8090701@huawei.com Fixes: acf8fdbe6afb ("ocfs2: do not BUG if buffer not uptodate in __ocfs2_journal_access") Signed-off-by: Jun Piao Reviewed-by: Yiwen Jiang Reviewed-by: Changwei Ge Cc: Mark Fasheh Cc: Joel Becker Cc: Junxiao Bi Cc: Joseph Qi Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- fs/ocfs2/journal.c | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/fs/ocfs2/journal.c b/fs/ocfs2/journal.c index 36304434eacf..e5dcea6cee5f 100644 --- a/fs/ocfs2/journal.c +++ b/fs/ocfs2/journal.c @@ -666,23 +666,24 @@ static int __ocfs2_journal_access(handle_t *handle, /* we can safely remove this assertion after testing. */ if (!buffer_uptodate(bh)) { mlog(ML_ERROR, "giving me a buffer that's not uptodate!\n"); - mlog(ML_ERROR, "b_blocknr=%llu\n", - (unsigned long long)bh->b_blocknr); + mlog(ML_ERROR, "b_blocknr=%llu, b_state=0x%lx\n", + (unsigned long long)bh->b_blocknr, bh->b_state); lock_buffer(bh); /* - * A previous attempt to write this buffer head failed. - * Nothing we can do but to retry the write and hope for - * the best. + * A previous transaction with a couple of buffer heads fail + * to checkpoint, so all the bhs are marked as BH_Write_EIO. + * For current transaction, the bh is just among those error + * bhs which previous transaction handle. We can't just clear + * its BH_Write_EIO and reuse directly, since other bhs are + * not written to disk yet and that will cause metadata + * inconsistency. So we should set fs read-only to avoid + * further damage. */ if (buffer_write_io_error(bh) && !buffer_uptodate(bh)) { - clear_buffer_write_io_error(bh); - set_buffer_uptodate(bh); - } - - if (!buffer_uptodate(bh)) { unlock_buffer(bh); - return -EIO; + return ocfs2_error(osb->sb, "A previous attempt to " + "write this buffer head failed\n"); } unlock_buffer(bh); } -- GitLab From 6cab60ac6a0a978ac58e27f79012122f90e75a1d Mon Sep 17 00:00:00 2001 From: Yisheng Xie Date: Wed, 31 Jan 2018 16:16:11 -0800 Subject: [PATCH 0975/1635] mm/mempolicy: fix the check of nodemask from user [ Upstream commit 56521e7a02b7b84a5e72691a1fb15570e6055545 ] As Xiaojun reported the ltp of migrate_pages01 will fail on arm64 system which has 4 nodes[0...3], all have memory and CONFIG_NODES_SHIFT=2: migrate_pages01 0 TINFO : test_invalid_nodes migrate_pages01 14 TFAIL : migrate_pages_common.c:45: unexpected failure - returned value = 0, expected: -1 migrate_pages01 15 TFAIL : migrate_pages_common.c:55: call succeeded unexpectedly In this case the test_invalid_nodes of migrate_pages01 will call: SYSC_migrate_pages as: migrate_pages(0, , {0x0000000000000001}, 64, , {0x0000000000000010}, 64) = 0 The new nodes specifies one or more node IDs that are greater than the maximum supported node ID, however, the errno is not set to EINVAL as expected. As man pages of set_mempolicy[1], mbind[2], and migrate_pages[3] mentioned, when nodemask specifies one or more node IDs that are greater than the maximum supported node ID, the errno should set to EINVAL. However, get_nodes only check whether the part of bits [BITS_PER_LONG*BITS_TO_LONGS(MAX_NUMNODES), maxnode) is zero or not, and remain [MAX_NUMNODES, BITS_PER_LONG*BITS_TO_LONGS(MAX_NUMNODES) unchecked. This patch is to check the bits of [MAX_NUMNODES, maxnode) in get_nodes to let migrate_pages set the errno to EINVAL when nodemask specifies one or more node IDs that are greater than the maximum supported node ID, which follows the manpage's guide. [1] http://man7.org/linux/man-pages/man2/set_mempolicy.2.html [2] http://man7.org/linux/man-pages/man2/mbind.2.html [3] http://man7.org/linux/man-pages/man2/migrate_pages.2.html Link: http://lkml.kernel.org/r/1510882624-44342-3-git-send-email-xieyisheng1@huawei.com Signed-off-by: Yisheng Xie Reported-by: Tan Xiaojun Acked-by: Vlastimil Babka Cc: Andi Kleen Cc: Chris Salls Cc: Christopher Lameter Cc: David Rientjes Cc: Ingo Molnar Cc: Naoya Horiguchi Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- mm/mempolicy.c | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/mm/mempolicy.c b/mm/mempolicy.c index a2af6d58a68f..80b67805b51d 100644 --- a/mm/mempolicy.c +++ b/mm/mempolicy.c @@ -1262,6 +1262,7 @@ static int get_nodes(nodemask_t *nodes, const unsigned long __user *nmask, unsigned long maxnode) { unsigned long k; + unsigned long t; unsigned long nlongs; unsigned long endmask; @@ -1278,13 +1279,19 @@ static int get_nodes(nodemask_t *nodes, const unsigned long __user *nmask, else endmask = (1UL << (maxnode % BITS_PER_LONG)) - 1; - /* When the user specified more nodes than supported just check - if the non supported part is all zero. */ + /* + * When the user specified more nodes than supported just check + * if the non supported part is all zero. + * + * If maxnode have more longs than MAX_NUMNODES, check + * the bits in that area first. And then go through to + * check the rest bits which equal or bigger than MAX_NUMNODES. + * Otherwise, just check bits [MAX_NUMNODES, maxnode). + */ if (nlongs > BITS_TO_LONGS(MAX_NUMNODES)) { if (nlongs > PAGE_SIZE/sizeof(long)) return -EINVAL; for (k = BITS_TO_LONGS(MAX_NUMNODES); k < nlongs; k++) { - unsigned long t; if (get_user(t, nmask + k)) return -EFAULT; if (k == nlongs - 1) { @@ -1297,6 +1304,16 @@ static int get_nodes(nodemask_t *nodes, const unsigned long __user *nmask, endmask = ~0UL; } + if (maxnode > MAX_NUMNODES && MAX_NUMNODES % BITS_PER_LONG != 0) { + unsigned long valid_mask = endmask; + + valid_mask &= ~((1UL << (MAX_NUMNODES % BITS_PER_LONG)) - 1); + if (get_user(t, nmask + nlongs - 1)) + return -EFAULT; + if (t & valid_mask) + return -EINVAL; + } + if (copy_from_user(nodes_addr(*nodes), nmask, nlongs*sizeof(unsigned long))) return -EFAULT; nodes_addr(*nodes)[nlongs-1] &= endmask; -- GitLab From 305e56756da71e0ef7cc8d91b8e66fafbb6e5d5a Mon Sep 17 00:00:00 2001 From: Yisheng Xie Date: Wed, 31 Jan 2018 16:16:15 -0800 Subject: [PATCH 0976/1635] mm/mempolicy: add nodes_empty check in SYSC_migrate_pages [ Upstream commit 0486a38bcc4749808edbc848f1bcf232042770fc ] As in manpage of migrate_pages, the errno should be set to EINVAL when none of the node IDs specified by new_nodes are on-line and allowed by the process's current cpuset context, or none of the specified nodes contain memory. However, when test by following case: new_nodes = 0; old_nodes = 0xf; ret = migrate_pages(pid, old_nodes, new_nodes, MAX); The ret will be 0 and no errno is set. As the new_nodes is empty, we should expect EINVAL as documented. To fix the case like above, this patch check whether target nodes AND current task_nodes is empty, and then check whether AND node_states[N_MEMORY] is empty. Link: http://lkml.kernel.org/r/1510882624-44342-4-git-send-email-xieyisheng1@huawei.com Signed-off-by: Yisheng Xie Acked-by: Vlastimil Babka Cc: Andi Kleen Cc: Chris Salls Cc: Christopher Lameter Cc: David Rientjes Cc: Ingo Molnar Cc: Naoya Horiguchi Cc: Tan Xiaojun Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- mm/mempolicy.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/mm/mempolicy.c b/mm/mempolicy.c index 80b67805b51d..2d3077ce50cd 100644 --- a/mm/mempolicy.c +++ b/mm/mempolicy.c @@ -1440,10 +1440,14 @@ SYSCALL_DEFINE4(migrate_pages, pid_t, pid, unsigned long, maxnode, goto out_put; } - if (!nodes_subset(*new, node_states[N_MEMORY])) { - err = -EINVAL; + task_nodes = cpuset_mems_allowed(current); + nodes_and(*new, *new, task_nodes); + if (nodes_empty(*new)) + goto out_put; + + nodes_and(*new, *new, node_states[N_MEMORY]); + if (nodes_empty(*new)) goto out_put; - } err = security_task_movememory(task); if (err) -- GitLab From 78185a93d42ddb9595df13b3394312d07a34e832 Mon Sep 17 00:00:00 2001 From: "Kirill A. Shutemov" Date: Wed, 31 Jan 2018 16:17:43 -0800 Subject: [PATCH 0977/1635] asm-generic: provide generic_pmdp_establish() [ Upstream commit c58f0bb77ed8bf93dfdde762b01cb67eebbdfc29 ] Patch series "Do not lose dirty bit on THP pages", v4. Vlastimil noted that pmdp_invalidate() is not atomic and we can lose dirty and access bits if CPU sets them after pmdp dereference, but before set_pmd_at(). The bug can lead to data loss, but the race window is tiny and I haven't seen any reports that suggested that it happens in reality. So I don't think it worth sending it to stable. Unfortunately, there's no way to address the issue in a generic way. We need to fix all architectures that support THP one-by-one. All architectures that have THP supported have to provide atomic pmdp_invalidate() that returns previous value. If generic implementation of pmdp_invalidate() is used, architecture needs to provide atomic pmdp_estabish(). pmdp_estabish() is not used out-side generic implementation of pmdp_invalidate() so far, but I think this can change in the future. This patch (of 12): This is an implementation of pmdp_establish() that is only suitable for an architecture that doesn't have hardware dirty/accessed bits. In this case we can't race with CPU which sets these bits and non-atomic approach is fine. Link: http://lkml.kernel.org/r/20171213105756.69879-2-kirill.shutemov@linux.intel.com Signed-off-by: Kirill A. Shutemov Cc: Vlastimil Babka Cc: Andrea Arcangeli Cc: Michal Hocko Cc: Aneesh Kumar K.V Cc: Catalin Marinas Cc: David Daney Cc: David Miller Cc: H. Peter Anvin Cc: Hugh Dickins Cc: Ingo Molnar Cc: Martin Schwidefsky Cc: Nitin Gupta Cc: Ralf Baechle Cc: Thomas Gleixner Cc: Vineet Gupta Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- include/asm-generic/pgtable.h | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/include/asm-generic/pgtable.h b/include/asm-generic/pgtable.h index 77b891a8f191..2142bceaeb75 100644 --- a/include/asm-generic/pgtable.h +++ b/include/asm-generic/pgtable.h @@ -309,6 +309,21 @@ extern void pgtable_trans_huge_deposit(struct mm_struct *mm, pmd_t *pmdp, extern pgtable_t pgtable_trans_huge_withdraw(struct mm_struct *mm, pmd_t *pmdp); #endif +#ifdef CONFIG_TRANSPARENT_HUGEPAGE +/* + * This is an implementation of pmdp_establish() that is only suitable for an + * architecture that doesn't have hardware dirty/accessed bits. In this case we + * can't race with CPU which sets these bits and non-atomic aproach is fine. + */ +static inline pmd_t generic_pmdp_establish(struct vm_area_struct *vma, + unsigned long address, pmd_t *pmdp, pmd_t pmd) +{ + pmd_t old_pmd = *pmdp; + set_pmd_at(vma->vm_mm, address, pmdp, pmd); + return old_pmd; +} +#endif + #ifndef __HAVE_ARCH_PMDP_INVALIDATE extern void pmdp_invalidate(struct vm_area_struct *vma, unsigned long address, pmd_t *pmdp); -- GitLab From 6acb8818eff43638b691acadb048bce32d0c89a3 Mon Sep 17 00:00:00 2001 From: Nitin Gupta Date: Wed, 31 Jan 2018 16:18:09 -0800 Subject: [PATCH 0978/1635] sparc64: update pmdp_invalidate() to return old pmd value [ Upstream commit a8e654f01cb725d0bfd741ebca1bf4c9337969cc ] It's required to avoid losing dirty and accessed bits. [akpm@linux-foundation.org: add a `do' to the do-while loop] Link: http://lkml.kernel.org/r/20171213105756.69879-9-kirill.shutemov@linux.intel.com Signed-off-by: Nitin Gupta Signed-off-by: Kirill A. Shutemov Cc: David Miller Cc: Vlastimil Babka Cc: Andrea Arcangeli Cc: Michal Hocko Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/sparc/include/asm/pgtable_64.h | 2 +- arch/sparc/mm/tlb.c | 23 ++++++++++++++++++----- 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/arch/sparc/include/asm/pgtable_64.h b/arch/sparc/include/asm/pgtable_64.h index fd9d9bac7cfa..79c3bdaaa0b4 100644 --- a/arch/sparc/include/asm/pgtable_64.h +++ b/arch/sparc/include/asm/pgtable_64.h @@ -980,7 +980,7 @@ void update_mmu_cache_pmd(struct vm_area_struct *vma, unsigned long addr, pmd_t *pmd); #define __HAVE_ARCH_PMDP_INVALIDATE -extern void pmdp_invalidate(struct vm_area_struct *vma, unsigned long address, +extern pmd_t pmdp_invalidate(struct vm_area_struct *vma, unsigned long address, pmd_t *pmdp); #define __HAVE_ARCH_PGTABLE_DEPOSIT diff --git a/arch/sparc/mm/tlb.c b/arch/sparc/mm/tlb.c index 4ae86bc0d35c..847ddffbf38a 100644 --- a/arch/sparc/mm/tlb.c +++ b/arch/sparc/mm/tlb.c @@ -219,17 +219,28 @@ void set_pmd_at(struct mm_struct *mm, unsigned long addr, } } +static inline pmd_t pmdp_establish(struct vm_area_struct *vma, + unsigned long address, pmd_t *pmdp, pmd_t pmd) +{ + pmd_t old; + + do { + old = *pmdp; + } while (cmpxchg64(&pmdp->pmd, old.pmd, pmd.pmd) != old.pmd); + + return old; +} + /* * This routine is only called when splitting a THP */ -void pmdp_invalidate(struct vm_area_struct *vma, unsigned long address, +pmd_t pmdp_invalidate(struct vm_area_struct *vma, unsigned long address, pmd_t *pmdp) { - pmd_t entry = *pmdp; - - pmd_val(entry) &= ~_PAGE_VALID; + pmd_t old, entry; - set_pmd_at(vma->vm_mm, address, pmdp, entry); + entry = __pmd(pmd_val(*pmdp) & ~_PAGE_VALID); + old = pmdp_establish(vma, address, pmdp, entry); flush_tlb_range(vma, address, address + HPAGE_PMD_SIZE); /* @@ -240,6 +251,8 @@ void pmdp_invalidate(struct vm_area_struct *vma, unsigned long address, if ((pmd_val(entry) & _PAGE_PMD_HUGE) && !is_huge_zero_page(pmd_page(entry))) (vma->vm_mm)->context.thp_pte_count--; + + return old; } void pgtable_trans_huge_deposit(struct mm_struct *mm, pmd_t *pmdp, -- GitLab From 8054b87fccd4fe9c67bfc164462d81b38ea56af4 Mon Sep 17 00:00:00 2001 From: Yang Shi Date: Wed, 31 Jan 2018 16:18:28 -0800 Subject: [PATCH 0979/1635] mm: thp: use down_read_trylock() in khugepaged to avoid long block MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit 3b454ad35043dfbd3b5d2bb92b0991d6342afb44 ] In the current design, khugepaged needs to acquire mmap_sem before scanning an mm. But in some corner cases, khugepaged may scan a process which is modifying its memory mapping, so khugepaged blocks in uninterruptible state. But the process might hold the mmap_sem for a long time when modifying a huge memory space and it may trigger the below khugepaged hung issue: INFO: task khugepaged:270 blocked for more than 120 seconds. Tainted: G E 4.9.65-006.ali3000.alios7.x86_64 #1 "echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message. khugepaged D 0 270 2 0x00000000  ffff883f3deae4c0 0000000000000000 ffff883f610596c0 ffff883f7d359440 ffff883f63818000 ffffc90019adfc78 ffffffff817079a5 d67e5aa8c1860a64 0000000000000246 ffff883f7d359440 ffffc90019adfc88 ffff883f610596c0 Call Trace: schedule+0x36/0x80 rwsem_down_read_failed+0xf0/0x150 call_rwsem_down_read_failed+0x18/0x30 down_read+0x20/0x40 khugepaged+0x476/0x11d0 kthread+0xe6/0x100 ret_from_fork+0x25/0x30 So it sounds pointless to just block khugepaged waiting for the semaphore so replace down_read() with down_read_trylock() to move to scan the next mm quickly instead of just blocking on the semaphore so that other processes can get more chances to install THP. Then khugepaged can come back to scan the skipped mm when it has finished the current round full_scan. And it appears that the change can improve khugepaged efficiency a little bit. Below is the test result when running LTP on a 24 cores 4GB memory 2 nodes NUMA VM: pristine w/ trylock full_scan 197 187 pages_collapsed 21 26 thp_fault_alloc 40818 44466 thp_fault_fallback 18413 16679 thp_collapse_alloc 21 150 thp_collapse_alloc_failed 14 16 thp_file_alloc 369 369 [akpm@linux-foundation.org: coding-style fixes] [akpm@linux-foundation.org: tweak comment] [arnd@arndb.de: avoid uninitialized variable use] Link: http://lkml.kernel.org/r/20171215125129.2948634-1-arnd@arndb.de Link: http://lkml.kernel.org/r/1513281203-54878-1-git-send-email-yang.s@alibaba-inc.com Signed-off-by: Yang Shi Acked-by: Kirill A. Shutemov Acked-by: Michal Hocko Cc: Hugh Dickins Cc: Andrea Arcangeli Signed-off-by: Arnd Bergmann Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- mm/khugepaged.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/mm/khugepaged.c b/mm/khugepaged.c index 2fe26634e1a2..29221602d802 100644 --- a/mm/khugepaged.c +++ b/mm/khugepaged.c @@ -1679,10 +1679,14 @@ static unsigned int khugepaged_scan_mm_slot(unsigned int pages, spin_unlock(&khugepaged_mm_lock); mm = mm_slot->mm; - down_read(&mm->mmap_sem); - if (unlikely(khugepaged_test_exit(mm))) - vma = NULL; - else + /* + * Don't wait for semaphore (to avoid long wait times). Just move to + * the next mm on the list. + */ + vma = NULL; + if (unlikely(!down_read_trylock(&mm->mmap_sem))) + goto breakouterloop_mmap_sem; + if (likely(!khugepaged_test_exit(mm))) vma = find_vma(mm, khugepaged_scan.address); progress++; -- GitLab From 1f9c87e251583942991c482d99c1797f1454be2a Mon Sep 17 00:00:00 2001 From: Mel Gorman Date: Wed, 31 Jan 2018 16:19:52 -0800 Subject: [PATCH 0980/1635] mm: pin address_space before dereferencing it while isolating an LRU page [ Upstream commit 69d763fc6d3aee787a3e8c8c35092b4f4960fa5d ] Minchan Kim asked the following question -- what locks protects address_space destroying when race happens between inode trauncation and __isolate_lru_page? Jan Kara clarified by describing the race as follows CPU1 CPU2 truncate(inode) __isolate_lru_page() ... truncate_inode_page(mapping, page); delete_from_page_cache(page) spin_lock_irqsave(&mapping->tree_lock, flags); __delete_from_page_cache(page, NULL) page_cache_tree_delete(..) ... mapping = page_mapping(page); page->mapping = NULL; ... spin_unlock_irqrestore(&mapping->tree_lock, flags); page_cache_free_page(mapping, page) put_page(page) if (put_page_testzero(page)) -> false - inode now has no pages and can be freed including embedded address_space if (mapping && !mapping->a_ops->migratepage) - we've dereferenced mapping which is potentially already free. The race is theoretically possible but unlikely. Before the delete_from_page_cache, truncate_cleanup_page is called so the page is likely to be !PageDirty or PageWriteback which gets skipped by the only caller that checks the mappping in __isolate_lru_page. Even if the race occurs, a substantial amount of work has to happen during a tiny window with no preemption but it could potentially be done using a virtual machine to artifically slow one CPU or halt it during the critical window. This patch should eliminate the race with truncation by try-locking the page before derefencing mapping and aborting if the lock was not acquired. There was a suggestion from Huang Ying to use RCU as a side-effect to prevent mapping being freed. However, I do not like the solution as it's an unconventional means of preserving a mapping and it's not a context where rcu_read_lock is obviously protecting rcu data. Link: http://lkml.kernel.org/r/20180104102512.2qos3h5vqzeisrek@techsingularity.net Fixes: c82449352854 ("mm: compaction: make isolate_lru_page() filter-aware again") Signed-off-by: Mel Gorman Acked-by: Minchan Kim Cc: "Huang, Ying" Cc: Jan Kara Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- mm/vmscan.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/mm/vmscan.c b/mm/vmscan.c index a8a3729bfaa9..b3f5e337b64a 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -1436,14 +1436,24 @@ int __isolate_lru_page(struct page *page, isolate_mode_t mode) if (PageDirty(page)) { struct address_space *mapping; + bool migrate_dirty; /* * Only pages without mappings or that have a * ->migratepage callback are possible to migrate - * without blocking + * without blocking. However, we can be racing with + * truncation so it's necessary to lock the page + * to stabilise the mapping as truncation holds + * the page lock until after the page is removed + * from the page cache. */ + if (!trylock_page(page)) + return ret; + mapping = page_mapping(page); - if (mapping && !mapping->a_ops->migratepage) + migrate_dirty = mapping && mapping->a_ops->migratepage; + unlock_page(page); + if (!migrate_dirty) return ret; } } -- GitLab From 3b1d9626fc58c133ae434368495a3b33c1b18ccd Mon Sep 17 00:00:00 2001 From: "shidao.ytt" Date: Wed, 31 Jan 2018 16:19:55 -0800 Subject: [PATCH 0981/1635] mm/fadvise: discard partial page if endbyte is also EOF [ Upstream commit a7ab400d6fe73d0119fdc234e9982a6f80faea9f ] During our recent testing with fadvise(FADV_DONTNEED), we find that if given offset/length is not page-aligned, the last page will not be discarded. The tool we use is vmtouch (https://hoytech.com/vmtouch/), we map a 10KB-sized file into memory and then try to run this tool to evict the whole file mapping, but the last single page always remains staying in the memory: $./vmtouch -e test_10K Files: 1 Directories: 0 Evicted Pages: 3 (12K) Elapsed: 2.1e-05 seconds $./vmtouch test_10K Files: 1 Directories: 0 Resident Pages: 1/3 4K/12K 33.3% Elapsed: 5.5e-05 seconds However when we test with an older kernel, say 3.10, this problem is gone. So we wonder if this is a regression: $./vmtouch -e test_10K Files: 1 Directories: 0 Evicted Pages: 3 (12K) Elapsed: 8.2e-05 seconds $./vmtouch test_10K Files: 1 Directories: 0 Resident Pages: 0/3 0/12K 0% <-- partial page also discarded Elapsed: 5e-05 seconds After digging a little bit into this problem, we find it seems not a regression. Not discarding partial page is likely to be on purpose according to commit 441c228f817f ("mm: fadvise: document the fadvise(FADV_DONTNEED) behaviour for partial pages") written by Mel Gorman. He explained why partial pages should be preserved instead of being discarded when using fadvise(FADV_DONTNEED). However, the interesting part is that the actual code did NOT work as the same as it was described, the partial page was still discarded anyway, due to a calculation mistake of `end_index' passed to invalidate_mapping_pages(). This mistake has not been fixed until recently, that's why we fail to reproduce our problem in old kernels. The fix is done in commit 18aba41cbf ("mm/fadvise.c: do not discard partial pages with POSIX_FADV_DONTNEED") by Oleg Drokin. Back to the original testing, our problem becomes that there is a special case that, if the page-unaligned `endbyte' is also the end of file, it is not necessary at all to preserve the last partial page, as we all know no one else will use the rest of it. It should be safe enough if we just discard the whole page. So we add an EOF check in this patch. We also find a poosbile real world issue in mainline kernel. Assume such scenario: A userspace backup application want to backup a huge amount of small files (<4k) at once, the developer might (I guess) want to use fadvise(FADV_DONTNEED) to save memory. However, FADV_DONTNEED won't really happen since the only page mapped is a partial page, and kernel will preserve it. Our patch also fixes this problem, since we know the endbyte is EOF, so we discard it. Here is a simple reproducer to reproduce and verify each scenario we described above: test_fadvise.c ============================== #include #include #include #include #include #include #include int main(int argc, char **argv) { int i, fd, ret, len; struct stat buf; void *addr; unsigned char *vec; char *strbuf; ssize_t pagesize = getpagesize(); ssize_t filesize; fd = open(argv[1], O_RDWR|O_CREAT, S_IRUSR|S_IWUSR); if (fd < 0) return -1; filesize = strtoul(argv[2], NULL, 10); strbuf = malloc(filesize); memset(strbuf, 42, filesize); write(fd, strbuf, filesize); free(strbuf); fsync(fd); len = (filesize + pagesize - 1) / pagesize; printf("length of pages: %d\n", len); addr = mmap(NULL, filesize, PROT_READ, MAP_SHARED, fd, 0); if (addr == MAP_FAILED) return -1; ret = posix_fadvise(fd, 0, filesize, POSIX_FADV_DONTNEED); if (ret < 0) return -1; vec = malloc(len); ret = mincore(addr, filesize, (void *)vec); if (ret < 0) return -1; for (i = 0; i < len; i++) printf("pages[%d]: %x\n", i, vec[i] & 0x1); free(vec); close(fd); return 0; } ============================== Test 1: running on kernel with commit 18aba41cbf reverted: [root@caspar ~]# uname -r 4.15.0-rc6.revert+ [root@caspar ~]# ./test_fadvise file1 1024 length of pages: 1 pages[0]: 0 # <-- partial page discarded [root@caspar ~]# ./test_fadvise file2 8192 length of pages: 2 pages[0]: 0 pages[1]: 0 [root@caspar ~]# ./test_fadvise file3 10240 length of pages: 3 pages[0]: 0 pages[1]: 0 pages[2]: 0 # <-- partial page discarded Test 2: running on mainline kernel: [root@caspar ~]# uname -r 4.15.0-rc6+ [root@caspar ~]# ./test_fadvise test1 1024 length of pages: 1 pages[0]: 1 # <-- partial and the only page not discarded [root@caspar ~]# ./test_fadvise test2 8192 length of pages: 2 pages[0]: 0 pages[1]: 0 [root@caspar ~]# ./test_fadvise test3 10240 length of pages: 3 pages[0]: 0 pages[1]: 0 pages[2]: 1 # <-- partial page not discarded Test 3: running on kernel with this patch: [root@caspar ~]# uname -r 4.15.0-rc6.patched+ [root@caspar ~]# ./test_fadvise test1 1024 length of pages: 1 pages[0]: 0 # <-- partial page and EOF, discarded [root@caspar ~]# ./test_fadvise test2 8192 length of pages: 2 pages[0]: 0 pages[1]: 0 [root@caspar ~]# ./test_fadvise test3 10240 length of pages: 3 pages[0]: 0 pages[1]: 0 pages[2]: 0 # <-- partial page and EOF, discarded [akpm@linux-foundation.org: tweak code comment] Link: http://lkml.kernel.org/r/5222da9ee20e1695eaabb69f631f200d6e6b8876.1515132470.git.jinli.zjl@alibaba-inc.com Signed-off-by: shidao.ytt Signed-off-by: Caspar Zhang Reviewed-by: Oliver Yang Cc: Mel Gorman Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- mm/fadvise.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/mm/fadvise.c b/mm/fadvise.c index ec70d6e4b86d..767887f5f3bf 100644 --- a/mm/fadvise.c +++ b/mm/fadvise.c @@ -127,7 +127,15 @@ SYSCALL_DEFINE4(fadvise64_64, int, fd, loff_t, offset, loff_t, len, int, advice) */ start_index = (offset+(PAGE_SIZE-1)) >> PAGE_SHIFT; end_index = (endbyte >> PAGE_SHIFT); - if ((endbyte & ~PAGE_MASK) != ~PAGE_MASK) { + /* + * The page at end_index will be inclusively discarded according + * by invalidate_mapping_pages(), so subtracting 1 from + * end_index means we will skip the last page. But if endbyte + * is page aligned or is at the end of file, we should not skip + * that page - discarding the last page is safe enough. + */ + if ((endbyte & ~PAGE_MASK) != ~PAGE_MASK && + endbyte != inode->i_size - 1) { /* First page is tricky as 0 - 1 = -1, but pgoff_t * is unsigned, so the end_index >= start_index * check below would be true and we'll discard the whole -- GitLab From 6eddea4ba5ccd00875d6f07ea042f16335a854ba Mon Sep 17 00:00:00 2001 From: Ed Swierk Date: Wed, 31 Jan 2018 18:48:02 -0800 Subject: [PATCH 0982/1635] openvswitch: Remove padding from packet before L3+ conntrack processing [ Upstream commit 9382fe71c0058465e942a633869629929102843d ] IPv4 and IPv6 packets may arrive with lower-layer padding that is not included in the L3 length. For example, a short IPv4 packet may have up to 6 bytes of padding following the IP payload when received on an Ethernet device with a minimum packet length of 64 bytes. Higher-layer processing functions in netfilter (e.g. nf_ip_checksum(), and help() in nf_conntrack_ftp) assume skb->len reflects the length of the L3 header and payload, rather than referring back to ip_hdr->tot_len or ipv6_hdr->payload_len, and get confused by lower-layer padding. In the normal IPv4 receive path, ip_rcv() trims the packet to ip_hdr->tot_len before invoking netfilter hooks. In the IPv6 receive path, ip6_rcv() does the same using ipv6_hdr->payload_len. Similarly in the br_netfilter receive path, br_validate_ipv4() and br_validate_ipv6() trim the packet to the L3 length before invoking netfilter hooks. Currently in the OVS conntrack receive path, ovs_ct_execute() pulls the skb to the L3 header but does not trim it to the L3 length before calling nf_conntrack_in(NF_INET_PRE_ROUTING). When nf_conntrack_proto_tcp encounters a packet with lower-layer padding, nf_ip_checksum() fails causing a "nf_ct_tcp: bad TCP checksum" log message. While extra zero bytes don't affect the checksum, the length in the IP pseudoheader does. That length is based on skb->len, and without trimming, it doesn't match the length the sender used when computing the checksum. In ovs_ct_execute(), trim the skb to the L3 length before higher-layer processing. Signed-off-by: Ed Swierk Acked-by: Pravin B Shelar Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- net/openvswitch/conntrack.c | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/net/openvswitch/conntrack.c b/net/openvswitch/conntrack.c index d558e882ca0c..285f8797c26a 100644 --- a/net/openvswitch/conntrack.c +++ b/net/openvswitch/conntrack.c @@ -1097,6 +1097,36 @@ static int ovs_ct_commit(struct net *net, struct sw_flow_key *key, return 0; } +/* Trim the skb to the length specified by the IP/IPv6 header, + * removing any trailing lower-layer padding. This prepares the skb + * for higher-layer processing that assumes skb->len excludes padding + * (such as nf_ip_checksum). The caller needs to pull the skb to the + * network header, and ensure ip_hdr/ipv6_hdr points to valid data. + */ +static int ovs_skb_network_trim(struct sk_buff *skb) +{ + unsigned int len; + int err; + + switch (skb->protocol) { + case htons(ETH_P_IP): + len = ntohs(ip_hdr(skb)->tot_len); + break; + case htons(ETH_P_IPV6): + len = sizeof(struct ipv6hdr) + + ntohs(ipv6_hdr(skb)->payload_len); + break; + default: + len = skb->len; + } + + err = pskb_trim_rcsum(skb, len); + if (err) + kfree_skb(skb); + + return err; +} + /* Returns 0 on success, -EINPROGRESS if 'skb' is stolen, or other nonzero * value if 'skb' is freed. */ @@ -1111,6 +1141,10 @@ int ovs_ct_execute(struct net *net, struct sk_buff *skb, nh_ofs = skb_network_offset(skb); skb_pull_rcsum(skb, nh_ofs); + err = ovs_skb_network_trim(skb); + if (err) + return err; + if (key->ip.frag != OVS_FRAG_TYPE_NONE) { err = handle_fragments(net, key, info->zone.id, skb); if (err) -- GitLab From 73027d80d67e151787603e65bf62bdbc4125877c Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Thu, 1 Feb 2018 14:01:02 -0700 Subject: [PATCH 0983/1635] blk-mq: fix discard merge with scheduler attached [ Upstream commit 445251d0f4d329aa061f323546cd6388a3bb7ab5 ] I ran into an issue on my laptop that triggered a bug on the discard path: WARNING: CPU: 2 PID: 207 at drivers/nvme/host/core.c:527 nvme_setup_cmd+0x3d3/0x430 Modules linked in: rfcomm fuse ctr ccm bnep arc4 binfmt_misc snd_hda_codec_hdmi nls_iso8859_1 nls_cp437 vfat snd_hda_codec_conexant fat snd_hda_codec_generic iwlmvm snd_hda_intel snd_hda_codec snd_hwdep mac80211 snd_hda_core snd_pcm snd_seq_midi snd_seq_midi_event snd_rawmidi snd_seq x86_pkg_temp_thermal intel_powerclamp kvm_intel uvcvideo iwlwifi btusb snd_seq_device videobuf2_vmalloc btintel videobuf2_memops kvm snd_timer videobuf2_v4l2 bluetooth irqbypass videobuf2_core aesni_intel aes_x86_64 crypto_simd cryptd snd glue_helper videodev cfg80211 ecdh_generic soundcore hid_generic usbhid hid i915 psmouse e1000e ptp pps_core xhci_pci xhci_hcd intel_gtt CPU: 2 PID: 207 Comm: jbd2/nvme0n1p7- Tainted: G U 4.15.0+ #176 Hardware name: LENOVO 20FBCTO1WW/20FBCTO1WW, BIOS N1FET59W (1.33 ) 12/19/2017 RIP: 0010:nvme_setup_cmd+0x3d3/0x430 RSP: 0018:ffff880423e9f838 EFLAGS: 00010217 RAX: 0000000000000000 RBX: ffff880423e9f8c8 RCX: 0000000000010000 RDX: ffff88022b200010 RSI: 0000000000000002 RDI: 00000000327f0000 RBP: ffff880421251400 R08: ffff88022b200000 R09: 0000000000000009 R10: 0000000000000000 R11: 0000000000000000 R12: 000000000000ffff R13: ffff88042341e280 R14: 000000000000ffff R15: ffff880421251440 FS: 0000000000000000(0000) GS:ffff880441500000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 000055b684795030 CR3: 0000000002e09006 CR4: 00000000001606e0 DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 Call Trace: nvme_queue_rq+0x40/0xa00 ? __sbitmap_queue_get+0x24/0x90 ? blk_mq_get_tag+0xa3/0x250 ? wait_woken+0x80/0x80 ? blk_mq_get_driver_tag+0x97/0xf0 blk_mq_dispatch_rq_list+0x7b/0x4a0 ? deadline_remove_request+0x49/0xb0 blk_mq_do_dispatch_sched+0x4f/0xc0 blk_mq_sched_dispatch_requests+0x106/0x170 __blk_mq_run_hw_queue+0x53/0xa0 __blk_mq_delay_run_hw_queue+0x83/0xa0 blk_mq_run_hw_queue+0x6c/0xd0 blk_mq_sched_insert_request+0x96/0x140 __blk_mq_try_issue_directly+0x3d/0x190 blk_mq_try_issue_directly+0x30/0x70 blk_mq_make_request+0x1a4/0x6a0 generic_make_request+0xfd/0x2f0 ? submit_bio+0x5c/0x110 submit_bio+0x5c/0x110 ? __blkdev_issue_discard+0x152/0x200 submit_bio_wait+0x43/0x60 ext4_process_freed_data+0x1cd/0x440 ? account_page_dirtied+0xe2/0x1a0 ext4_journal_commit_callback+0x4a/0xc0 jbd2_journal_commit_transaction+0x17e2/0x19e0 ? kjournald2+0xb0/0x250 kjournald2+0xb0/0x250 ? wait_woken+0x80/0x80 ? commit_timeout+0x10/0x10 kthread+0x111/0x130 ? kthread_create_worker_on_cpu+0x50/0x50 ? do_group_exit+0x3a/0xa0 ret_from_fork+0x1f/0x30 Code: 73 89 c1 83 ce 10 c1 e1 10 09 ca 83 f8 04 0f 87 0f ff ff ff 8b 4d 20 48 8b 7d 00 c1 e9 09 48 01 8c c7 00 08 00 00 e9 f8 fe ff ff <0f> ff 4c 89 c7 41 bc 0a 00 00 00 e8 0d 78 d6 ff e9 a1 fc ff ff ---[ end trace 50d361cc444506c8 ]--- print_req_error: I/O error, dev nvme0n1, sector 847167488 Decoding the assembly, the request claims to have 0xffff segments, while nvme counts two. This turns out to be because we don't check for a data carrying request on the mq scheduler path, and since blk_phys_contig_segment() returns true for a non-data request, we decrement the initial segment count of 0 and end up with 0xffff in the unsigned short. There are a few issues here: 1) We should initialize the segment count for a discard to 1. 2) The discard merging is currently using the data limits for segments and sectors. Fix this up by having attempt_merge() correctly identify the request, and by initializing the segment count correctly for discards. This can only be triggered with mq-deadline on discard capable devices right now, which isn't a common configuration. Signed-off-by: Jens Axboe Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- block/blk-core.c | 2 ++ block/blk-merge.c | 29 ++++++++++++++++++++++++++--- 2 files changed, 28 insertions(+), 3 deletions(-) diff --git a/block/blk-core.c b/block/blk-core.c index c01f4907dbbc..1feeb1a8aad9 100644 --- a/block/blk-core.c +++ b/block/blk-core.c @@ -3065,6 +3065,8 @@ void blk_rq_bio_prep(struct request_queue *q, struct request *rq, { if (bio_has_data(bio)) rq->nr_phys_segments = bio_phys_segments(q, bio); + else if (bio_op(bio) == REQ_OP_DISCARD) + rq->nr_phys_segments = 1; rq->__data_len = bio->bi_iter.bi_size; rq->bio = rq->biotail = bio; diff --git a/block/blk-merge.c b/block/blk-merge.c index f5dedd57dff6..8d60a5bbcef9 100644 --- a/block/blk-merge.c +++ b/block/blk-merge.c @@ -551,6 +551,24 @@ static bool req_no_special_merge(struct request *req) return !q->mq_ops && req->special; } +static bool req_attempt_discard_merge(struct request_queue *q, struct request *req, + struct request *next) +{ + unsigned short segments = blk_rq_nr_discard_segments(req); + + if (segments >= queue_max_discard_segments(q)) + goto no_merge; + if (blk_rq_sectors(req) + bio_sectors(next->bio) > + blk_rq_get_max_sectors(req, blk_rq_pos(req))) + goto no_merge; + + req->nr_phys_segments = segments + blk_rq_nr_discard_segments(next); + return true; +no_merge: + req_set_nomerge(q, req); + return false; +} + static int ll_merge_requests_fn(struct request_queue *q, struct request *req, struct request *next) { @@ -684,9 +702,13 @@ static struct request *attempt_merge(struct request_queue *q, * If we are allowed to merge, then append bio list * from next to rq and release next. merge_requests_fn * will have updated segment counts, update sector - * counts here. + * counts here. Handle DISCARDs separately, as they + * have separate settings. */ - if (!ll_merge_requests_fn(q, req, next)) + if (req_op(req) == REQ_OP_DISCARD) { + if (!req_attempt_discard_merge(q, req, next)) + return NULL; + } else if (!ll_merge_requests_fn(q, req, next)) return NULL; /* @@ -716,7 +738,8 @@ static struct request *attempt_merge(struct request_queue *q, req->__data_len += blk_rq_bytes(next); - elv_merge_requests(q, req, next); + if (req_op(req) != REQ_OP_DISCARD) + elv_merge_requests(q, req, next); /* * 'next' is going away, so update stats accordingly -- GitLab From 5ceae7690f0d0575c730663ffd67493c9fa4e992 Mon Sep 17 00:00:00 2001 From: "Michael J. Ruhl" Date: Thu, 1 Feb 2018 10:43:42 -0800 Subject: [PATCH 0984/1635] IB/hfi1: Re-order IRQ cleanup to address driver cleanup race [ Upstream commit 82a979265638c505e12fbe7ba40980dc0901436d ] The pci_request_irq() interfaces always adds the IRQF_SHARED bit to all IRQ requests. When the kernel is built with CONFIG_DEBUG_SHIRQ config flag, if the IRQF_SHARED bit is set, a call to the IRQ handler is made from the __free_irq() function. This is testing a race condition between the IRQ cleanup and an IRQ racing the cleanup. The HFI driver should be able to handle this race, but does not. This race can cause traces that start with this footprint: BUG: unable to handle kernel NULL pointer dereference at (null) Call Trace: ... __free_irq+0x1b3/0x2d0 free_irq+0x35/0x70 pci_free_irq+0x1c/0x30 clean_up_interrupts+0x53/0xf0 [hfi1] hfi1_start_cleanup+0x122/0x190 [hfi1] postinit_cleanup+0x1d/0x280 [hfi1] remove_one+0x233/0x250 [hfi1] pci_device_remove+0x39/0xc0 Export IRQ cleanup function so it can be called from other modules. Using the exported cleanup function: Re-order the driver cleanup code to clean up IRQ resources before other resources, eliminating the race. Re-order error path for init so that the race does not occur. Reduce severity on spurious error message for SDMA IRQs to info. Reviewed-by: Alex Estrin Reviewed-by: Patel Jay P Reviewed-by: Mike Marciniszyn Signed-off-by: Michael J. Ruhl Signed-off-by: Dennis Dalessandro Signed-off-by: Jason Gunthorpe Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/infiniband/hw/hfi1/chip.c | 18 ++++++++++++------ drivers/infiniband/hw/hfi1/hfi.h | 1 + drivers/infiniband/hw/hfi1/init.c | 4 +++- 3 files changed, 16 insertions(+), 7 deletions(-) diff --git a/drivers/infiniband/hw/hfi1/chip.c b/drivers/infiniband/hw/hfi1/chip.c index 0e17d03ef1cb..82114ba86041 100644 --- a/drivers/infiniband/hw/hfi1/chip.c +++ b/drivers/infiniband/hw/hfi1/chip.c @@ -8294,8 +8294,8 @@ static irqreturn_t sdma_interrupt(int irq, void *data) /* handle the interrupt(s) */ sdma_engine_interrupt(sde, status); } else { - dd_dev_err_ratelimited(dd, "SDMA engine %u interrupt, but no status bits set\n", - sde->this_idx); + dd_dev_info_ratelimited(dd, "SDMA engine %u interrupt, but no status bits set\n", + sde->this_idx); } return IRQ_HANDLED; } @@ -12967,7 +12967,14 @@ static void disable_intx(struct pci_dev *pdev) pci_intx(pdev, 0); } -static void clean_up_interrupts(struct hfi1_devdata *dd) +/** + * hfi1_clean_up_interrupts() - Free all IRQ resources + * @dd: valid device data data structure + * + * Free the MSI or INTx IRQs and assoicated PCI resources, + * if they have been allocated. + */ +void hfi1_clean_up_interrupts(struct hfi1_devdata *dd) { int i; @@ -13344,7 +13351,7 @@ static int set_up_interrupts(struct hfi1_devdata *dd) return 0; fail: - clean_up_interrupts(dd); + hfi1_clean_up_interrupts(dd); return ret; } @@ -14770,7 +14777,6 @@ void hfi1_start_cleanup(struct hfi1_devdata *dd) aspm_exit(dd); free_cntrs(dd); free_rcverr(dd); - clean_up_interrupts(dd); finish_chip_resources(dd); } @@ -15229,7 +15235,7 @@ struct hfi1_devdata *hfi1_init_dd(struct pci_dev *pdev, bail_free_cntrs: free_cntrs(dd); bail_clear_intr: - clean_up_interrupts(dd); + hfi1_clean_up_interrupts(dd); bail_cleanup: hfi1_pcie_ddcleanup(dd); bail_free: diff --git a/drivers/infiniband/hw/hfi1/hfi.h b/drivers/infiniband/hw/hfi1/hfi.h index 3409eee16092..dc9c951ef946 100644 --- a/drivers/infiniband/hw/hfi1/hfi.h +++ b/drivers/infiniband/hw/hfi1/hfi.h @@ -1954,6 +1954,7 @@ void hfi1_verbs_unregister_sysfs(struct hfi1_devdata *dd); int qsfp_dump(struct hfi1_pportdata *ppd, char *buf, int len); int hfi1_pcie_init(struct pci_dev *pdev, const struct pci_device_id *ent); +void hfi1_clean_up_interrupts(struct hfi1_devdata *dd); void hfi1_pcie_cleanup(struct pci_dev *pdev); int hfi1_pcie_ddinit(struct hfi1_devdata *dd, struct pci_dev *pdev); void hfi1_pcie_ddcleanup(struct hfi1_devdata *); diff --git a/drivers/infiniband/hw/hfi1/init.c b/drivers/infiniband/hw/hfi1/init.c index fba77001c3a7..d4fc8795cdf6 100644 --- a/drivers/infiniband/hw/hfi1/init.c +++ b/drivers/infiniband/hw/hfi1/init.c @@ -1039,8 +1039,9 @@ static void shutdown_device(struct hfi1_devdata *dd) } dd->flags &= ~HFI1_INITTED; - /* mask interrupts, but not errors */ + /* mask and clean up interrupts, but not errors */ set_intr_state(dd, 0); + hfi1_clean_up_interrupts(dd); for (pidx = 0; pidx < dd->num_pports; ++pidx) { ppd = dd->pport + pidx; @@ -1696,6 +1697,7 @@ static int init_one(struct pci_dev *pdev, const struct pci_device_id *ent) dd_dev_err(dd, "Failed to create /dev devices: %d\n", -j); if (initfail || ret) { + hfi1_clean_up_interrupts(dd); stop_timers(dd); flush_workqueue(ib_wq); for (pidx = 0; pidx < dd->num_pports; ++pidx) { -- GitLab From 8f96d408a9547e2a814562796c6f7fac3e839332 Mon Sep 17 00:00:00 2001 From: Alex Estrin Date: Thu, 1 Feb 2018 10:43:58 -0800 Subject: [PATCH 0985/1635] IB/hfi1: Fix for potential refcount leak in hfi1_open_file() [ Upstream commit 2b1e7fe16124e86ee9242aeeee859c79a843e3a2 ] The dd refcount is speculatively incremented prior to allocating the fd memory with kzalloc(). If that kzalloc() failed the dd refcount leaks. Increment refcount on kzalloc success. Fixes: e11ffbd57520 ("IB/hfi1: Do not free hfi1 cdev parent structure early") Reviewed-by: Michael J Ruhl Signed-off-by: Alex Estrin Signed-off-by: Jason Gunthorpe Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/infiniband/hw/hfi1/file_ops.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/infiniband/hw/hfi1/file_ops.c b/drivers/infiniband/hw/hfi1/file_ops.c index fd28f09b4445..ee2253d06984 100644 --- a/drivers/infiniband/hw/hfi1/file_ops.c +++ b/drivers/infiniband/hw/hfi1/file_ops.c @@ -191,9 +191,6 @@ static int hfi1_file_open(struct inode *inode, struct file *fp) if (!atomic_inc_not_zero(&dd->user_refcount)) return -ENXIO; - /* Just take a ref now. Not all opens result in a context assign */ - kobject_get(&dd->kobj); - /* The real work is performed later in assign_ctxt() */ fd = kzalloc(sizeof(*fd), GFP_KERNEL); @@ -203,6 +200,7 @@ static int hfi1_file_open(struct inode *inode, struct file *fp) fd->mm = current->mm; mmgrab(fd->mm); fd->dd = dd; + kobject_get(&fd->dd->kobj); fp->private_data = fd; } else { fp->private_data = NULL; -- GitLab From f63bb02694f08e94a50ae334d16b9908426655f7 Mon Sep 17 00:00:00 2001 From: Alex Estrin Date: Thu, 1 Feb 2018 10:55:41 -0800 Subject: [PATCH 0986/1635] IB/ipoib: Fix for potential no-carrier state [ Upstream commit 1029361084d18cc270f64dfd39529fafa10cfe01 ] On reboot SM can program port pkey table before ipoib registered its event handler, which could result in missing pkey event and leave root interface with initial pkey value from index 0. Since OPA port starts with invalid pkey in index 0, root interface will fail to initialize and stay down with no-carrier flag. For IB ipoib interface may end up with pkey different from value opensm put in pkey table idx 0, resulting in connectivity issues (different mcast groups, for example). Close the window by calling event handler after registration to make sure ipoib pkey is in sync with port pkey table. Reviewed-by: Mike Marciniszyn Reviewed-by: Ira Weiny Signed-off-by: Alex Estrin Signed-off-by: Dennis Dalessandro Signed-off-by: Jason Gunthorpe Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/infiniband/ulp/ipoib/ipoib_main.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c index a009e943362a..6bc9a768f721 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_main.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c @@ -2273,6 +2273,9 @@ static struct net_device *ipoib_add_port(const char *format, priv->ca, ipoib_event); ib_register_event_handler(&priv->event_handler); + /* call event handler to ensure pkey in sync */ + queue_work(ipoib_workqueue, &priv->flush_heavy); + result = register_netdev(priv->dev); if (result) { printk(KERN_WARNING "%s: couldn't register ipoib port %d; error %d\n", -- GitLab From fd370b8e65e3364a8a4411656506ccfaf13b4599 Mon Sep 17 00:00:00 2001 From: Don Hiatt Date: Thu, 1 Feb 2018 10:57:03 -0800 Subject: [PATCH 0987/1635] IB/core: Map iWarp AH type to undefined in rdma_ah_find_type [ Upstream commit 87daac68f77a3e21a1113f816e6a7be0b38bdde8 ] iWarp devices do not support the creation of address handles so return AH_ATTR_TYPE_UNDEFINED for all iWarp devices. While we are here reduce the size of port_num to u8 and add a comment. Fixes: 44c58487d51a ("IB/core: Define 'ib' and 'roce' rdma_ah_attr types") Reported-by: Parav Pandit CC: Sean Hefty Reviewed-by: Ira Weiny Reviewed-by: Shiraz Saleem Signed-off-by: Don Hiatt Signed-off-by: Dennis Dalessandro Signed-off-by: Jason Gunthorpe Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- include/rdma/ib_verbs.h | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/include/rdma/ib_verbs.h b/include/rdma/ib_verbs.h index a9fae49a1883..08f3d8699a27 100644 --- a/include/rdma/ib_verbs.h +++ b/include/rdma/ib_verbs.h @@ -866,6 +866,7 @@ struct ib_mr_status { __attribute_const__ enum ib_rate mult_to_ib_rate(int mult); enum rdma_ah_attr_type { + RDMA_AH_ATTR_TYPE_UNDEFINED, RDMA_AH_ATTR_TYPE_IB, RDMA_AH_ATTR_TYPE_ROCE, RDMA_AH_ATTR_TYPE_OPA, @@ -3762,17 +3763,24 @@ static inline void rdma_ah_set_grh(struct rdma_ah_attr *attr, grh->traffic_class = traffic_class; } -/*Get AH type */ +/** + * rdma_ah_find_type - Return address handle type. + * + * @dev: Device to be checked + * @port_num: Port number + */ static inline enum rdma_ah_attr_type rdma_ah_find_type(struct ib_device *dev, - u32 port_num) + u8 port_num) { if (rdma_protocol_roce(dev, port_num)) return RDMA_AH_ATTR_TYPE_ROCE; - else if ((rdma_protocol_ib(dev, port_num)) && - (rdma_cap_opa_ah(dev, port_num))) - return RDMA_AH_ATTR_TYPE_OPA; - else + if (rdma_protocol_ib(dev, port_num)) { + if (rdma_cap_opa_ah(dev, port_num)) + return RDMA_AH_ATTR_TYPE_OPA; return RDMA_AH_ATTR_TYPE_IB; + } + + return RDMA_AH_ATTR_TYPE_UNDEFINED; } /** -- GitLab From eb41efa1386582c00865a3dec5758cfbda6dbda8 Mon Sep 17 00:00:00 2001 From: Karol Herbst Date: Mon, 6 Nov 2017 16:32:41 +0100 Subject: [PATCH 0988/1635] drm/nouveau/pmu/fuc: don't use movw directly anymore [ Upstream commit fe9748b7b41cee11f8db57fb8b20bc540a33102a ] Fixes failure to compile with recent envyas as a result of the 'movw' alias being removed for v5. A bit of history: v3 only has a 16-bit sign-extended immediate mov op. In order to set the high bits, there's a separate 'sethi' op. envyas validates that the value passed to mov(imm) is between -0x8000 and 0x7fff. In order to simplify macros that load both the low and high word, a 'movw' alias was added which takes an unsigned 16-bit immediate. However the actual hardware op still sign extends. v5 has a full 32-bit immediate mov op. The v3 16-bit immediate mov op is gone (loads 0 into the dst reg). However due to a bug in envyas, the movw alias still existed, and selected the no-longer-present v3 16-bit immediate mov op. As a result usage of movw on v5 is the same as mov with a 0x0 argument. The proper fix throughout is to only ever use the 'movw' alias in combination with 'sethi'. Anything else should get the sign-extended validation to ensure that the intended value ends up in the destination register. Changes in fuc3 binaries is the result of a different encoding being selected for a mov with an 8-bit value. v2: added commit message written by Ilia, thanks for that! v3: messed up rebasing, now it should apply Signed-off-by: Karol Herbst Signed-off-by: Ben Skeggs Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- .../nouveau/nvkm/subdev/pmu/fuc/gf100.fuc3.h | 746 ++++++------ .../nouveau/nvkm/subdev/pmu/fuc/gk208.fuc5.h | 802 ++++++------- .../nouveau/nvkm/subdev/pmu/fuc/gt215.fuc3.h | 1006 ++++++++--------- .../drm/nouveau/nvkm/subdev/pmu/fuc/memx.fuc | 30 +- 4 files changed, 1292 insertions(+), 1292 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/gf100.fuc3.h b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/gf100.fuc3.h index 53d01fb00a8b..1dbe593e5960 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/gf100.fuc3.h +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/gf100.fuc3.h @@ -47,8 +47,8 @@ static uint32_t gf100_pmu_data[] = { 0x00000000, 0x00000000, 0x584d454d, - 0x00000756, - 0x00000748, + 0x00000754, + 0x00000746, 0x00000000, 0x00000000, 0x00000000, @@ -69,8 +69,8 @@ static uint32_t gf100_pmu_data[] = { 0x00000000, 0x00000000, 0x46524550, - 0x0000075a, 0x00000758, + 0x00000756, 0x00000000, 0x00000000, 0x00000000, @@ -91,8 +91,8 @@ static uint32_t gf100_pmu_data[] = { 0x00000000, 0x00000000, 0x5f433249, - 0x00000b8a, - 0x00000a2d, + 0x00000b88, + 0x00000a2b, 0x00000000, 0x00000000, 0x00000000, @@ -113,8 +113,8 @@ static uint32_t gf100_pmu_data[] = { 0x00000000, 0x00000000, 0x54534554, - 0x00000bb3, - 0x00000b8c, + 0x00000bb1, + 0x00000b8a, 0x00000000, 0x00000000, 0x00000000, @@ -135,8 +135,8 @@ static uint32_t gf100_pmu_data[] = { 0x00000000, 0x00000000, 0x454c4449, - 0x00000bbf, 0x00000bbd, + 0x00000bbb, 0x00000000, 0x00000000, 0x00000000, @@ -237,19 +237,19 @@ static uint32_t gf100_pmu_data[] = { 0x000005d3, 0x00000003, 0x00000002, - 0x0000069d, + 0x0000069b, 0x00040004, 0x00000000, - 0x000006b9, + 0x000006b7, 0x00010005, 0x00000000, - 0x000006d6, + 0x000006d4, 0x00010006, 0x00000000, 0x0000065b, 0x00000007, 0x00000000, - 0x000006e1, + 0x000006df, /* 0x03c4: memx_func_tail */ /* 0x03c4: memx_ts_start */ 0x00000000, @@ -1373,432 +1373,432 @@ static uint32_t gf100_pmu_code[] = { /* 0x065b: memx_func_wait_vblank */ 0x9800f840, 0x66b00016, - 0x130bf400, + 0x120bf400, 0xf40166b0, 0x0ef4060b, /* 0x066d: memx_func_wait_vblank_head1 */ - 0x2077f12e, - 0x070ef400, -/* 0x0674: memx_func_wait_vblank_head0 */ - 0x000877f1, -/* 0x0678: memx_func_wait_vblank_0 */ - 0x07c467f1, - 0xcf0664b6, - 0x67fd0066, - 0xf31bf404, -/* 0x0688: memx_func_wait_vblank_1 */ - 0x07c467f1, - 0xcf0664b6, - 0x67fd0066, - 0xf30bf404, -/* 0x0698: memx_func_wait_vblank_fini */ - 0xf80410b6, -/* 0x069d: memx_func_wr32 */ - 0x00169800, - 0xb6011598, - 0x60f90810, - 0xd0fc50f9, - 0x21f4e0fc, - 0x0242b640, - 0xf8e91bf4, -/* 0x06b9: memx_func_wait */ - 0x2c87f000, - 0xcf0684b6, - 0x1e980088, - 0x011d9800, - 0x98021c98, - 0x10b6031b, - 0xa321f410, -/* 0x06d6: memx_func_delay */ - 0x1e9800f8, - 0x0410b600, - 0xf87e21f4, -/* 0x06e1: memx_func_train */ -/* 0x06e3: memx_exec */ - 0xf900f800, - 0xb9d0f9e0, - 0xb2b902c1, -/* 0x06ed: memx_exec_next */ - 0x00139802, - 0xe70410b6, - 0xe701f034, - 0xb601e033, - 0x30f00132, - 0xde35980c, - 0x12b855f9, - 0xe41ef406, - 0x98f10b98, - 0xcbbbf20c, - 0xc4b7f102, - 0x06b4b607, - 0xfc00bbcf, - 0xf5e0fcd0, - 0xf8033621, -/* 0x0729: memx_info */ - 0x01c67000, -/* 0x072f: memx_info_data */ - 0xf10e0bf4, - 0xf103ccc7, - 0xf40800b7, -/* 0x073a: memx_info_train */ - 0xc7f10b0e, - 0xb7f10bcc, -/* 0x0742: memx_info_send */ - 0x21f50100, - 0x00f80336, -/* 0x0748: memx_recv */ - 0xf401d6b0, - 0xd6b0980b, - 0xd80bf400, -/* 0x0756: memx_init */ - 0x00f800f8, -/* 0x0758: perf_recv */ -/* 0x075a: perf_init */ + 0x2077f02c, +/* 0x0673: memx_func_wait_vblank_head0 */ + 0xf0060ef4, +/* 0x0676: memx_func_wait_vblank_0 */ + 0x67f10877, + 0x64b607c4, + 0x0066cf06, + 0xf40467fd, +/* 0x0686: memx_func_wait_vblank_1 */ + 0x67f1f31b, + 0x64b607c4, + 0x0066cf06, + 0xf40467fd, +/* 0x0696: memx_func_wait_vblank_fini */ + 0x10b6f30b, +/* 0x069b: memx_func_wr32 */ + 0x9800f804, + 0x15980016, + 0x0810b601, + 0x50f960f9, + 0xe0fcd0fc, + 0xb64021f4, + 0x1bf40242, +/* 0x06b7: memx_func_wait */ + 0xf000f8e9, + 0x84b62c87, + 0x0088cf06, + 0x98001e98, + 0x1c98011d, + 0x031b9802, + 0xf41010b6, + 0x00f8a321, +/* 0x06d4: memx_func_delay */ + 0xb6001e98, + 0x21f40410, +/* 0x06df: memx_func_train */ + 0xf800f87e, +/* 0x06e1: memx_exec */ + 0xf9e0f900, + 0x02c1b9d0, +/* 0x06eb: memx_exec_next */ + 0x9802b2b9, + 0x10b60013, + 0xf034e704, + 0xe033e701, + 0x0132b601, + 0x980c30f0, + 0x55f9de35, + 0xf40612b8, + 0x0b98e41e, + 0xf20c98f1, + 0xf102cbbb, + 0xb607c4b7, + 0xbbcf06b4, + 0xfcd0fc00, + 0x3621f5e0, +/* 0x0727: memx_info */ + 0x7000f803, + 0x0bf401c6, +/* 0x072d: memx_info_data */ + 0xccc7f10e, + 0x00b7f103, + 0x0b0ef408, +/* 0x0738: memx_info_train */ + 0x0bccc7f1, + 0x0100b7f1, +/* 0x0740: memx_info_send */ + 0x033621f5, +/* 0x0746: memx_recv */ + 0xd6b000f8, + 0x980bf401, + 0xf400d6b0, + 0x00f8d80b, +/* 0x0754: memx_init */ +/* 0x0756: perf_recv */ 0x00f800f8, -/* 0x075c: i2c_drive_scl */ - 0xf40036b0, - 0x07f1110b, - 0x04b607e0, - 0x0001d006, - 0x00f804bd, -/* 0x0770: i2c_drive_scl_lo */ - 0x07e407f1, - 0xd00604b6, - 0x04bd0001, -/* 0x077e: i2c_drive_sda */ +/* 0x0758: perf_init */ +/* 0x075a: i2c_drive_scl */ 0x36b000f8, 0x110bf400, 0x07e007f1, 0xd00604b6, - 0x04bd0002, -/* 0x0792: i2c_drive_sda_lo */ + 0x04bd0001, +/* 0x076e: i2c_drive_scl_lo */ 0x07f100f8, 0x04b607e4, + 0x0001d006, + 0x00f804bd, +/* 0x077c: i2c_drive_sda */ + 0xf40036b0, + 0x07f1110b, + 0x04b607e0, 0x0002d006, 0x00f804bd, -/* 0x07a0: i2c_sense_scl */ - 0xf10132f4, - 0xb607c437, - 0x33cf0634, - 0x0431fd00, - 0xf4060bf4, -/* 0x07b6: i2c_sense_scl_done */ - 0x00f80131, -/* 0x07b8: i2c_sense_sda */ - 0xf10132f4, - 0xb607c437, - 0x33cf0634, - 0x0432fd00, - 0xf4060bf4, -/* 0x07ce: i2c_sense_sda_done */ - 0x00f80131, -/* 0x07d0: i2c_raise_scl */ - 0x47f140f9, - 0x37f00898, - 0x5c21f501, -/* 0x07dd: i2c_raise_scl_wait */ - 0xe8e7f107, - 0x7e21f403, - 0x07a021f5, - 0xb60901f4, - 0x1bf40142, -/* 0x07f1: i2c_raise_scl_done */ - 0xf840fcef, -/* 0x07f5: i2c_start */ - 0xa021f500, - 0x0d11f407, - 0x07b821f5, - 0xf40611f4, -/* 0x0806: i2c_start_rep */ - 0x37f0300e, - 0x5c21f500, - 0x0137f007, - 0x077e21f5, - 0xb60076bb, - 0x50f90465, - 0xbb046594, - 0x50bd0256, - 0xfc0475fd, - 0xd021f550, - 0x0464b607, -/* 0x0833: i2c_start_send */ - 0xf01f11f4, +/* 0x0790: i2c_drive_sda_lo */ + 0x07e407f1, + 0xd00604b6, + 0x04bd0002, +/* 0x079e: i2c_sense_scl */ + 0x32f400f8, + 0xc437f101, + 0x0634b607, + 0xfd0033cf, + 0x0bf40431, + 0x0131f406, +/* 0x07b4: i2c_sense_scl_done */ +/* 0x07b6: i2c_sense_sda */ + 0x32f400f8, + 0xc437f101, + 0x0634b607, + 0xfd0033cf, + 0x0bf40432, + 0x0131f406, +/* 0x07cc: i2c_sense_sda_done */ +/* 0x07ce: i2c_raise_scl */ + 0x40f900f8, + 0x089847f1, + 0xf50137f0, +/* 0x07db: i2c_raise_scl_wait */ + 0xf1075a21, + 0xf403e8e7, + 0x21f57e21, + 0x01f4079e, + 0x0142b609, +/* 0x07ef: i2c_raise_scl_done */ + 0xfcef1bf4, +/* 0x07f3: i2c_start */ + 0xf500f840, + 0xf4079e21, + 0x21f50d11, + 0x11f407b6, + 0x300ef406, +/* 0x0804: i2c_start_rep */ + 0xf50037f0, + 0xf0075a21, + 0x21f50137, + 0x76bb077c, + 0x0465b600, + 0x659450f9, + 0x0256bb04, + 0x75fd50bd, + 0xf550fc04, + 0xb607ce21, + 0x11f40464, +/* 0x0831: i2c_start_send */ + 0x0037f01f, + 0x077c21f5, + 0x1388e7f1, + 0xf07e21f4, 0x21f50037, - 0xe7f1077e, + 0xe7f1075a, 0x21f41388, - 0x0037f07e, - 0x075c21f5, - 0x1388e7f1, -/* 0x084f: i2c_start_out */ - 0xf87e21f4, -/* 0x0851: i2c_stop */ - 0x0037f000, - 0x075c21f5, - 0xf50037f0, - 0xf1077e21, - 0xf403e8e7, - 0x37f07e21, - 0x5c21f501, - 0x88e7f107, - 0x7e21f413, +/* 0x084d: i2c_start_out */ +/* 0x084f: i2c_stop */ + 0xf000f87e, + 0x21f50037, + 0x37f0075a, + 0x7c21f500, + 0xe8e7f107, + 0x7e21f403, 0xf50137f0, - 0xf1077e21, + 0xf1075a21, 0xf41388e7, - 0x00f87e21, -/* 0x0884: i2c_bitw */ - 0x077e21f5, - 0x03e8e7f1, - 0xbb7e21f4, - 0x65b60076, - 0x9450f904, - 0x56bb0465, - 0xfd50bd02, - 0x50fc0475, - 0x07d021f5, - 0xf40464b6, - 0xe7f11811, - 0x21f41388, - 0x0037f07e, - 0x075c21f5, - 0x1388e7f1, -/* 0x08c3: i2c_bitw_out */ - 0xf87e21f4, -/* 0x08c5: i2c_bitr */ - 0x0137f000, - 0x077e21f5, - 0x03e8e7f1, - 0xbb7e21f4, - 0x65b60076, - 0x9450f904, - 0x56bb0465, - 0xfd50bd02, - 0x50fc0475, - 0x07d021f5, - 0xf40464b6, - 0x21f51b11, - 0x37f007b8, - 0x5c21f500, + 0x37f07e21, + 0x7c21f501, 0x88e7f107, 0x7e21f413, - 0xf4013cf0, -/* 0x090a: i2c_bitr_done */ - 0x00f80131, -/* 0x090c: i2c_get_byte */ - 0xf00057f0, -/* 0x0912: i2c_get_byte_next */ - 0x54b60847, - 0x0076bb01, +/* 0x0882: i2c_bitw */ + 0x21f500f8, + 0xe7f1077c, + 0x21f403e8, + 0x0076bb7e, 0xf90465b6, 0x04659450, 0xbd0256bb, 0x0475fd50, 0x21f550fc, - 0x64b608c5, - 0x2b11f404, - 0xb60553fd, - 0x1bf40142, - 0x0137f0d8, - 0xb60076bb, - 0x50f90465, - 0xbb046594, - 0x50bd0256, - 0xfc0475fd, - 0x8421f550, - 0x0464b608, -/* 0x095c: i2c_get_byte_done */ -/* 0x095e: i2c_put_byte */ - 0x47f000f8, -/* 0x0961: i2c_put_byte_next */ - 0x0142b608, - 0xbb3854ff, + 0x64b607ce, + 0x1811f404, + 0x1388e7f1, + 0xf07e21f4, + 0x21f50037, + 0xe7f1075a, + 0x21f41388, +/* 0x08c1: i2c_bitw_out */ +/* 0x08c3: i2c_bitr */ + 0xf000f87e, + 0x21f50137, + 0xe7f1077c, + 0x21f403e8, + 0x0076bb7e, + 0xf90465b6, + 0x04659450, + 0xbd0256bb, + 0x0475fd50, + 0x21f550fc, + 0x64b607ce, + 0x1b11f404, + 0x07b621f5, + 0xf50037f0, + 0xf1075a21, + 0xf41388e7, + 0x3cf07e21, + 0x0131f401, +/* 0x0908: i2c_bitr_done */ +/* 0x090a: i2c_get_byte */ + 0x57f000f8, + 0x0847f000, +/* 0x0910: i2c_get_byte_next */ + 0xbb0154b6, 0x65b60076, 0x9450f904, 0x56bb0465, 0xfd50bd02, 0x50fc0475, - 0x088421f5, + 0x08c321f5, 0xf40464b6, - 0x46b03411, - 0xd81bf400, - 0xb60076bb, - 0x50f90465, - 0xbb046594, - 0x50bd0256, - 0xfc0475fd, - 0xc521f550, - 0x0464b608, - 0xbb0f11f4, - 0x36b00076, - 0x061bf401, -/* 0x09b7: i2c_put_byte_done */ - 0xf80132f4, -/* 0x09b9: i2c_addr */ - 0x0076bb00, + 0x53fd2b11, + 0x0142b605, + 0xf0d81bf4, + 0x76bb0137, + 0x0465b600, + 0x659450f9, + 0x0256bb04, + 0x75fd50bd, + 0xf550fc04, + 0xb6088221, +/* 0x095a: i2c_get_byte_done */ + 0x00f80464, +/* 0x095c: i2c_put_byte */ +/* 0x095f: i2c_put_byte_next */ + 0xb60847f0, + 0x54ff0142, + 0x0076bb38, 0xf90465b6, 0x04659450, 0xbd0256bb, 0x0475fd50, 0x21f550fc, - 0x64b607f5, - 0x2911f404, - 0x012ec3e7, - 0xfd0134b6, - 0x76bb0553, + 0x64b60882, + 0x3411f404, + 0xf40046b0, + 0x76bbd81b, 0x0465b600, 0x659450f9, 0x0256bb04, 0x75fd50bd, 0xf550fc04, - 0xb6095e21, -/* 0x09fe: i2c_addr_done */ - 0x00f80464, -/* 0x0a00: i2c_acquire_addr */ - 0xb6f8cec7, - 0xe0b702e4, - 0xee980d1c, -/* 0x0a0f: i2c_acquire */ - 0xf500f800, - 0xf40a0021, - 0xd9f00421, - 0x4021f403, -/* 0x0a1e: i2c_release */ - 0x21f500f8, - 0x21f40a00, - 0x03daf004, - 0xf84021f4, -/* 0x0a2d: i2c_recv */ - 0x0132f400, - 0xb6f8c1c7, - 0x16b00214, - 0x3a1ff528, - 0xf413a001, - 0x0032980c, - 0x0ccc13a0, - 0xf4003198, - 0xd0f90231, - 0xd0f9e0f9, - 0x000067f1, - 0x100063f1, - 0xbb016792, + 0xb608c321, + 0x11f40464, + 0x0076bb0f, + 0xf40136b0, + 0x32f4061b, +/* 0x09b5: i2c_put_byte_done */ +/* 0x09b7: i2c_addr */ + 0xbb00f801, 0x65b60076, 0x9450f904, 0x56bb0465, 0xfd50bd02, 0x50fc0475, - 0x0a0f21f5, - 0xfc0464b6, - 0x00d6b0d0, - 0x00b31bf5, - 0xbb0057f0, - 0x65b60076, - 0x9450f904, - 0x56bb0465, - 0xfd50bd02, - 0x50fc0475, - 0x09b921f5, - 0xf50464b6, - 0xc700d011, - 0x76bbe0c5, - 0x0465b600, - 0x659450f9, - 0x0256bb04, - 0x75fd50bd, - 0xf550fc04, - 0xb6095e21, - 0x11f50464, - 0x57f000ad, + 0x07f321f5, + 0xf40464b6, + 0xc3e72911, + 0x34b6012e, + 0x0553fd01, + 0xb60076bb, + 0x50f90465, + 0xbb046594, + 0x50bd0256, + 0xfc0475fd, + 0x5c21f550, + 0x0464b609, +/* 0x09fc: i2c_addr_done */ +/* 0x09fe: i2c_acquire_addr */ + 0xcec700f8, + 0x02e4b6f8, + 0x0d1ce0b7, + 0xf800ee98, +/* 0x0a0d: i2c_acquire */ + 0xfe21f500, + 0x0421f409, + 0xf403d9f0, + 0x00f84021, +/* 0x0a1c: i2c_release */ + 0x09fe21f5, + 0xf00421f4, + 0x21f403da, +/* 0x0a2b: i2c_recv */ + 0xf400f840, + 0xc1c70132, + 0x0214b6f8, + 0xf52816b0, + 0xa0013a1f, + 0x980cf413, + 0x13a00032, + 0x31980ccc, + 0x0231f400, + 0xe0f9d0f9, + 0x67f1d0f9, + 0x63f10000, + 0x67921000, 0x0076bb01, 0xf90465b6, 0x04659450, 0xbd0256bb, 0x0475fd50, 0x21f550fc, - 0x64b609b9, - 0x8a11f504, + 0x64b60a0d, + 0xb0d0fc04, + 0x1bf500d6, + 0x57f000b3, 0x0076bb00, 0xf90465b6, 0x04659450, 0xbd0256bb, 0x0475fd50, 0x21f550fc, - 0x64b6090c, - 0x6a11f404, - 0xbbe05bcb, + 0x64b609b7, + 0xd011f504, + 0xe0c5c700, + 0xb60076bb, + 0x50f90465, + 0xbb046594, + 0x50bd0256, + 0xfc0475fd, + 0x5c21f550, + 0x0464b609, + 0x00ad11f5, + 0xbb0157f0, 0x65b60076, 0x9450f904, 0x56bb0465, 0xfd50bd02, 0x50fc0475, - 0x085121f5, - 0xb90464b6, - 0x74bd025b, -/* 0x0b33: i2c_recv_not_rd08 */ - 0xb0430ef4, - 0x1bf401d6, - 0x0057f03d, - 0x09b921f5, - 0xc73311f4, - 0x21f5e0c5, - 0x11f4095e, - 0x0057f029, - 0x09b921f5, - 0xc71f11f4, - 0x21f5e0b5, - 0x11f4095e, - 0x5121f515, - 0xc774bd08, - 0x1bf408c5, - 0x0232f409, -/* 0x0b73: i2c_recv_not_wr08 */ -/* 0x0b73: i2c_recv_done */ - 0xc7030ef4, - 0x21f5f8ce, - 0xe0fc0a1e, - 0x12f4d0fc, - 0x027cb90a, - 0x033621f5, -/* 0x0b88: i2c_recv_exit */ -/* 0x0b8a: i2c_init */ - 0x00f800f8, -/* 0x0b8c: test_recv */ - 0x05d817f1, + 0x09b721f5, + 0xf50464b6, + 0xbb008a11, + 0x65b60076, + 0x9450f904, + 0x56bb0465, + 0xfd50bd02, + 0x50fc0475, + 0x090a21f5, + 0xf40464b6, + 0x5bcb6a11, + 0x0076bbe0, + 0xf90465b6, + 0x04659450, + 0xbd0256bb, + 0x0475fd50, + 0x21f550fc, + 0x64b6084f, + 0x025bb904, + 0x0ef474bd, +/* 0x0b31: i2c_recv_not_rd08 */ + 0x01d6b043, + 0xf03d1bf4, + 0x21f50057, + 0x11f409b7, + 0xe0c5c733, + 0x095c21f5, + 0xf02911f4, + 0x21f50057, + 0x11f409b7, + 0xe0b5c71f, + 0x095c21f5, + 0xf51511f4, + 0xbd084f21, + 0x08c5c774, + 0xf4091bf4, + 0x0ef40232, +/* 0x0b71: i2c_recv_not_wr08 */ +/* 0x0b71: i2c_recv_done */ + 0xf8cec703, + 0x0a1c21f5, + 0xd0fce0fc, + 0xb90a12f4, + 0x21f5027c, +/* 0x0b86: i2c_recv_exit */ + 0x00f80336, +/* 0x0b88: i2c_init */ +/* 0x0b8a: test_recv */ + 0x17f100f8, + 0x14b605d8, + 0x0011cf06, + 0xf10110b6, + 0xb605d807, + 0x01d00604, + 0xf104bd00, + 0xf1d900e7, + 0xf5134fe3, + 0xf8025621, +/* 0x0bb1: test_init */ + 0x00e7f100, + 0x5621f508, +/* 0x0bbb: idle_recv */ + 0xf800f802, +/* 0x0bbd: idle */ + 0x0031f400, + 0x05d417f1, 0xcf0614b6, 0x10b60011, - 0xd807f101, + 0xd407f101, 0x0604b605, 0xbd0001d0, - 0x00e7f104, - 0x4fe3f1d9, - 0x5621f513, -/* 0x0bb3: test_init */ - 0xf100f802, - 0xf50800e7, - 0xf8025621, -/* 0x0bbd: idle_recv */ -/* 0x0bbf: idle */ - 0xf400f800, - 0x17f10031, - 0x14b605d4, - 0x0011cf06, - 0xf10110b6, - 0xb605d407, - 0x01d00604, -/* 0x0bdb: idle_loop */ - 0xf004bd00, - 0x32f45817, -/* 0x0be1: idle_proc */ -/* 0x0be1: idle_proc_exec */ - 0xb910f902, - 0x21f5021e, - 0x10fc033f, - 0xf40911f4, - 0x0ef40231, -/* 0x0bf5: idle_proc_next */ - 0x5810b6ef, - 0xf4061fb8, - 0x02f4e61b, - 0x0028f4dd, - 0x00bb0ef4, +/* 0x0bd9: idle_loop */ + 0x5817f004, +/* 0x0bdf: idle_proc */ +/* 0x0bdf: idle_proc_exec */ + 0xf90232f4, + 0x021eb910, + 0x033f21f5, + 0x11f410fc, + 0x0231f409, +/* 0x0bf3: idle_proc_next */ + 0xb6ef0ef4, + 0x1fb85810, + 0xe61bf406, + 0xf4dd02f4, + 0x0ef40028, + 0x000000bb, 0x00000000, 0x00000000, 0x00000000, diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/gk208.fuc5.h b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/gk208.fuc5.h index c4edbc79e41a..e0222cb832fb 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/gk208.fuc5.h +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/gk208.fuc5.h @@ -47,8 +47,8 @@ static uint32_t gk208_pmu_data[] = { 0x00000000, 0x00000000, 0x584d454d, - 0x000005f3, - 0x000005e5, + 0x000005ee, + 0x000005e0, 0x00000000, 0x00000000, 0x00000000, @@ -69,8 +69,8 @@ static uint32_t gk208_pmu_data[] = { 0x00000000, 0x00000000, 0x46524550, - 0x000005f7, - 0x000005f5, + 0x000005f2, + 0x000005f0, 0x00000000, 0x00000000, 0x00000000, @@ -91,8 +91,8 @@ static uint32_t gk208_pmu_data[] = { 0x00000000, 0x00000000, 0x5f433249, - 0x000009f8, - 0x000008a2, + 0x000009f3, + 0x0000089d, 0x00000000, 0x00000000, 0x00000000, @@ -113,8 +113,8 @@ static uint32_t gk208_pmu_data[] = { 0x00000000, 0x00000000, 0x54534554, - 0x00000a16, - 0x000009fa, + 0x00000a11, + 0x000009f5, 0x00000000, 0x00000000, 0x00000000, @@ -135,8 +135,8 @@ static uint32_t gk208_pmu_data[] = { 0x00000000, 0x00000000, 0x454c4449, - 0x00000a21, - 0x00000a1f, + 0x00000a1c, + 0x00000a1a, 0x00000000, 0x00000000, 0x00000000, @@ -234,22 +234,22 @@ static uint32_t gk208_pmu_data[] = { /* 0x037c: memx_func_next */ 0x00000002, 0x00000000, - 0x000004cf, + 0x000004cc, 0x00000003, 0x00000002, - 0x00000546, + 0x00000541, 0x00040004, 0x00000000, - 0x00000563, + 0x0000055e, 0x00010005, 0x00000000, - 0x0000057d, + 0x00000578, 0x00010006, 0x00000000, - 0x00000541, + 0x0000053c, 0x00000007, 0x00000000, - 0x00000589, + 0x00000584, /* 0x03c4: memx_func_tail */ /* 0x03c4: memx_ts_start */ 0x00000000, @@ -1239,454 +1239,454 @@ static uint32_t gk208_pmu_code[] = { 0x0001f604, 0x00f804bd, /* 0x045c: memx_func_enter */ - 0x162067f1, - 0xf55d77f1, - 0x047e6eb2, - 0xd8b20000, - 0xf90487fd, - 0xfc80f960, - 0x7ee0fcd0, - 0x0700002d, - 0x7e6eb2fe, + 0x47162046, + 0x6eb2f55d, + 0x0000047e, + 0x87fdd8b2, + 0xf960f904, + 0xfcd0fc80, + 0x002d7ee0, + 0xb2fe0700, + 0x00047e6e, + 0xfdd8b200, + 0x60f90487, + 0xd0fc80f9, + 0x2d7ee0fc, + 0xf0460000, + 0x7e6eb226, 0xb2000004, 0x0487fdd8, 0x80f960f9, 0xe0fcd0fc, 0x00002d7e, - 0x26f067f1, - 0x047e6eb2, - 0xd8b20000, - 0xf90487fd, - 0xfc80f960, - 0x7ee0fcd0, - 0x0600002d, - 0x07e04004, - 0xbd0006f6, -/* 0x04b9: memx_func_enter_wait */ - 0x07c04604, - 0xf00066cf, - 0x0bf40464, - 0xcf2c06f7, - 0x06b50066, -/* 0x04cf: memx_func_leave */ - 0x0600f8f1, - 0x0066cf2c, - 0x06f206b5, - 0x07e44004, - 0xbd0006f6, -/* 0x04e1: memx_func_leave_wait */ - 0x07c04604, - 0xf00066cf, - 0x1bf40464, - 0xf067f1f7, + 0xe0400406, + 0x0006f607, +/* 0x04b6: memx_func_enter_wait */ + 0xc04604bd, + 0x0066cf07, + 0xf40464f0, + 0x2c06f70b, + 0xb50066cf, + 0x00f8f106, +/* 0x04cc: memx_func_leave */ + 0x66cf2c06, + 0xf206b500, + 0xe4400406, + 0x0006f607, +/* 0x04de: memx_func_leave_wait */ + 0xc04604bd, + 0x0066cf07, + 0xf40464f0, + 0xf046f71b, 0xb2010726, 0x00047e6e, 0xfdd8b200, 0x60f90587, 0xd0fc80f9, 0x2d7ee0fc, - 0x67f10000, - 0x6eb21620, - 0x0000047e, - 0x87fdd8b2, - 0xf960f905, - 0xfcd0fc80, - 0x002d7ee0, - 0x0aa24700, - 0x047e6eb2, - 0xd8b20000, - 0xf90587fd, - 0xfc80f960, - 0x7ee0fcd0, - 0xf800002d, -/* 0x0541: memx_func_wait_vblank */ + 0x20460000, + 0x7e6eb216, + 0xb2000004, + 0x0587fdd8, + 0x80f960f9, + 0xe0fcd0fc, + 0x00002d7e, + 0xb20aa247, + 0x00047e6e, + 0xfdd8b200, + 0x60f90587, + 0xd0fc80f9, + 0x2d7ee0fc, + 0x00f80000, +/* 0x053c: memx_func_wait_vblank */ + 0xf80410b6, +/* 0x0541: memx_func_wr32 */ + 0x00169800, + 0xb6011598, + 0x60f90810, + 0xd0fc50f9, + 0x2d7ee0fc, + 0x42b60000, + 0xe81bf402, +/* 0x055e: memx_func_wait */ + 0x2c0800f8, + 0x980088cf, + 0x1d98001e, + 0x021c9801, + 0xb6031b98, + 0x747e1010, + 0x00f80000, +/* 0x0578: memx_func_delay */ + 0xb6001e98, + 0x587e0410, + 0x00f80000, +/* 0x0584: memx_func_train */ +/* 0x0586: memx_exec */ + 0xe0f900f8, + 0xc1b2d0f9, +/* 0x058e: memx_exec_next */ + 0x1398b2b2, 0x0410b600, -/* 0x0546: memx_func_wr32 */ - 0x169800f8, - 0x01159800, - 0xf90810b6, - 0xfc50f960, + 0x01f034e7, + 0x01e033e7, + 0xf00132b6, + 0x35980c30, + 0xa655f9de, + 0xe51ef412, + 0x98f10b98, + 0xcbbbf20c, + 0x07c44b02, + 0xfc00bbcf, 0x7ee0fcd0, - 0xb600002d, - 0x1bf40242, -/* 0x0563: memx_func_wait */ - 0x0800f8e8, - 0x0088cf2c, - 0x98001e98, - 0x1c98011d, - 0x031b9802, - 0x7e1010b6, - 0xf8000074, -/* 0x057d: memx_func_delay */ - 0x001e9800, - 0x7e0410b6, - 0xf8000058, -/* 0x0589: memx_func_train */ -/* 0x058b: memx_exec */ - 0xf900f800, - 0xb2d0f9e0, -/* 0x0593: memx_exec_next */ - 0x98b2b2c1, - 0x10b60013, - 0xf034e704, - 0xe033e701, - 0x0132b601, - 0x980c30f0, - 0x55f9de35, - 0x1ef412a6, - 0xf10b98e5, - 0xbbf20c98, - 0xc44b02cb, - 0x00bbcf07, - 0xe0fcd0fc, - 0x00029f7e, -/* 0x05ca: memx_info */ - 0xc67000f8, - 0x0c0bf401, -/* 0x05d0: memx_info_data */ - 0x4b03cc4c, - 0x0ef40800, -/* 0x05d9: memx_info_train */ - 0x0bcc4c09, -/* 0x05df: memx_info_send */ - 0x7e01004b, 0xf800029f, -/* 0x05e5: memx_recv */ - 0x01d6b000, - 0xb0a30bf4, - 0x0bf400d6, -/* 0x05f3: memx_init */ - 0xf800f8dc, -/* 0x05f5: perf_recv */ -/* 0x05f7: perf_init */ - 0xf800f800, -/* 0x05f9: i2c_drive_scl */ - 0x0036b000, - 0x400d0bf4, - 0x01f607e0, - 0xf804bd00, -/* 0x0609: i2c_drive_scl_lo */ - 0x07e44000, - 0xbd0001f6, -/* 0x0613: i2c_drive_sda */ - 0xb000f804, - 0x0bf40036, - 0x07e0400d, - 0xbd0002f6, -/* 0x0623: i2c_drive_sda_lo */ - 0x4000f804, - 0x02f607e4, - 0xf804bd00, -/* 0x062d: i2c_sense_scl */ - 0x0132f400, - 0xcf07c443, - 0x31fd0033, - 0x060bf404, -/* 0x063f: i2c_sense_scl_done */ - 0xf80131f4, -/* 0x0641: i2c_sense_sda */ - 0x0132f400, - 0xcf07c443, - 0x32fd0033, - 0x060bf404, -/* 0x0653: i2c_sense_sda_done */ - 0xf80131f4, -/* 0x0655: i2c_raise_scl */ - 0x4440f900, - 0x01030898, - 0x0005f97e, -/* 0x0660: i2c_raise_scl_wait */ - 0x7e03e84e, - 0x7e000058, - 0xf400062d, - 0x42b60901, - 0xef1bf401, -/* 0x0674: i2c_raise_scl_done */ - 0x00f840fc, -/* 0x0678: i2c_start */ - 0x00062d7e, - 0x7e0d11f4, - 0xf4000641, - 0x0ef40611, -/* 0x0689: i2c_start_rep */ - 0x7e00032e, - 0x030005f9, - 0x06137e01, +/* 0x05c5: memx_info */ + 0x01c67000, +/* 0x05cb: memx_info_data */ + 0x4c0c0bf4, + 0x004b03cc, + 0x090ef408, +/* 0x05d4: memx_info_train */ + 0x4b0bcc4c, +/* 0x05da: memx_info_send */ + 0x9f7e0100, + 0x00f80002, +/* 0x05e0: memx_recv */ + 0xf401d6b0, + 0xd6b0a30b, + 0xdc0bf400, +/* 0x05ee: memx_init */ + 0x00f800f8, +/* 0x05f0: perf_recv */ +/* 0x05f2: perf_init */ + 0x00f800f8, +/* 0x05f4: i2c_drive_scl */ + 0xf40036b0, + 0xe0400d0b, + 0x0001f607, + 0x00f804bd, +/* 0x0604: i2c_drive_scl_lo */ + 0xf607e440, + 0x04bd0001, +/* 0x060e: i2c_drive_sda */ + 0x36b000f8, + 0x0d0bf400, + 0xf607e040, + 0x04bd0002, +/* 0x061e: i2c_drive_sda_lo */ + 0xe44000f8, + 0x0002f607, + 0x00f804bd, +/* 0x0628: i2c_sense_scl */ + 0x430132f4, + 0x33cf07c4, + 0x0431fd00, + 0xf4060bf4, +/* 0x063a: i2c_sense_scl_done */ + 0x00f80131, +/* 0x063c: i2c_sense_sda */ + 0x430132f4, + 0x33cf07c4, + 0x0432fd00, + 0xf4060bf4, +/* 0x064e: i2c_sense_sda_done */ + 0x00f80131, +/* 0x0650: i2c_raise_scl */ + 0x984440f9, + 0x7e010308, +/* 0x065b: i2c_raise_scl_wait */ + 0x4e0005f4, + 0x587e03e8, + 0x287e0000, + 0x01f40006, + 0x0142b609, +/* 0x066f: i2c_raise_scl_done */ + 0xfcef1bf4, +/* 0x0673: i2c_start */ + 0x7e00f840, + 0xf4000628, + 0x3c7e0d11, + 0x11f40006, + 0x2e0ef406, +/* 0x0684: i2c_start_rep */ + 0xf47e0003, + 0x01030005, + 0x00060e7e, + 0xb60076bb, + 0x50f90465, + 0xbb046594, + 0x50bd0256, + 0xfc0475fd, + 0x06507e50, + 0x0464b600, +/* 0x06af: i2c_start_send */ + 0x031d11f4, + 0x060e7e00, + 0x13884e00, + 0x0000587e, + 0xf47e0003, + 0x884e0005, + 0x00587e13, +/* 0x06c9: i2c_start_out */ +/* 0x06cb: i2c_stop */ + 0x0300f800, + 0x05f47e00, + 0x7e000300, + 0x4e00060e, + 0x587e03e8, + 0x01030000, + 0x0005f47e, + 0x7e13884e, + 0x03000058, + 0x060e7e01, + 0x13884e00, + 0x0000587e, +/* 0x06fa: i2c_bitw */ + 0x0e7e00f8, + 0xe84e0006, + 0x00587e03, 0x0076bb00, 0xf90465b6, 0x04659450, 0xbd0256bb, 0x0475fd50, - 0x557e50fc, + 0x507e50fc, 0x64b60006, - 0x1d11f404, -/* 0x06b4: i2c_start_send */ - 0x137e0003, - 0x884e0006, - 0x00587e13, - 0x7e000300, - 0x4e0005f9, - 0x587e1388, -/* 0x06ce: i2c_start_out */ - 0x00f80000, -/* 0x06d0: i2c_stop */ - 0xf97e0003, - 0x00030005, - 0x0006137e, - 0x7e03e84e, + 0x1711f404, + 0x7e13884e, 0x03000058, - 0x05f97e01, + 0x05f47e00, 0x13884e00, 0x0000587e, - 0x137e0103, - 0x884e0006, - 0x00587e13, -/* 0x06ff: i2c_bitw */ - 0x7e00f800, - 0x4e000613, - 0x587e03e8, - 0x76bb0000, +/* 0x0738: i2c_bitw_out */ +/* 0x073a: i2c_bitr */ + 0x010300f8, + 0x00060e7e, + 0x7e03e84e, + 0xbb000058, + 0x65b60076, + 0x9450f904, + 0x56bb0465, + 0xfd50bd02, + 0x50fc0475, + 0x0006507e, + 0xf40464b6, + 0x3c7e1a11, + 0x00030006, + 0x0005f47e, + 0x7e13884e, + 0xf0000058, + 0x31f4013c, +/* 0x077d: i2c_bitr_done */ +/* 0x077f: i2c_get_byte */ + 0x0500f801, +/* 0x0783: i2c_get_byte_next */ + 0xb6080400, + 0x76bb0154, 0x0465b600, 0x659450f9, 0x0256bb04, 0x75fd50bd, 0x7e50fc04, - 0xb6000655, + 0xb600073a, 0x11f40464, - 0x13884e17, - 0x0000587e, - 0xf97e0003, - 0x884e0005, - 0x00587e13, -/* 0x073d: i2c_bitw_out */ -/* 0x073f: i2c_bitr */ - 0x0300f800, - 0x06137e01, - 0x03e84e00, - 0x0000587e, + 0x0553fd2a, + 0xf40142b6, + 0x0103d81b, 0xb60076bb, 0x50f90465, 0xbb046594, 0x50bd0256, 0xfc0475fd, - 0x06557e50, + 0x06fa7e50, 0x0464b600, - 0x7e1a11f4, - 0x03000641, - 0x05f97e00, - 0x13884e00, - 0x0000587e, - 0xf4013cf0, -/* 0x0782: i2c_bitr_done */ - 0x00f80131, -/* 0x0784: i2c_get_byte */ - 0x08040005, -/* 0x0788: i2c_get_byte_next */ - 0xbb0154b6, - 0x65b60076, - 0x9450f904, - 0x56bb0465, - 0xfd50bd02, - 0x50fc0475, - 0x00073f7e, - 0xf40464b6, - 0x53fd2a11, - 0x0142b605, - 0x03d81bf4, - 0x0076bb01, - 0xf90465b6, - 0x04659450, - 0xbd0256bb, - 0x0475fd50, - 0xff7e50fc, - 0x64b60006, -/* 0x07d1: i2c_get_byte_done */ -/* 0x07d3: i2c_put_byte */ - 0x0400f804, -/* 0x07d5: i2c_put_byte_next */ - 0x0142b608, - 0xbb3854ff, +/* 0x07cc: i2c_get_byte_done */ +/* 0x07ce: i2c_put_byte */ + 0x080400f8, +/* 0x07d0: i2c_put_byte_next */ + 0xff0142b6, + 0x76bb3854, + 0x0465b600, + 0x659450f9, + 0x0256bb04, + 0x75fd50bd, + 0x7e50fc04, + 0xb60006fa, + 0x11f40464, + 0x0046b034, + 0xbbd81bf4, 0x65b60076, 0x9450f904, 0x56bb0465, 0xfd50bd02, 0x50fc0475, - 0x0006ff7e, + 0x00073a7e, 0xf40464b6, - 0x46b03411, - 0xd81bf400, + 0x76bb0f11, + 0x0136b000, + 0xf4061bf4, +/* 0x0826: i2c_put_byte_done */ + 0x00f80132, +/* 0x0828: i2c_addr */ 0xb60076bb, 0x50f90465, 0xbb046594, 0x50bd0256, 0xfc0475fd, - 0x073f7e50, + 0x06737e50, 0x0464b600, - 0xbb0f11f4, - 0x36b00076, - 0x061bf401, -/* 0x082b: i2c_put_byte_done */ - 0xf80132f4, -/* 0x082d: i2c_addr */ - 0x0076bb00, + 0xe72911f4, + 0xb6012ec3, + 0x53fd0134, + 0x0076bb05, 0xf90465b6, 0x04659450, 0xbd0256bb, 0x0475fd50, - 0x787e50fc, - 0x64b60006, - 0x2911f404, - 0x012ec3e7, - 0xfd0134b6, - 0x76bb0553, - 0x0465b600, - 0x659450f9, - 0x0256bb04, - 0x75fd50bd, - 0x7e50fc04, - 0xb60007d3, -/* 0x0872: i2c_addr_done */ - 0x00f80464, -/* 0x0874: i2c_acquire_addr */ - 0xb6f8cec7, - 0xe0b705e4, - 0x00f8d014, -/* 0x0880: i2c_acquire */ - 0x0008747e, + 0xce7e50fc, + 0x64b60007, +/* 0x086d: i2c_addr_done */ +/* 0x086f: i2c_acquire_addr */ + 0xc700f804, + 0xe4b6f8ce, + 0x14e0b705, +/* 0x087b: i2c_acquire */ + 0x7e00f8d0, + 0x7e00086f, + 0xf0000004, + 0x2d7e03d9, + 0x00f80000, +/* 0x088c: i2c_release */ + 0x00086f7e, 0x0000047e, - 0x7e03d9f0, + 0x7e03daf0, 0xf800002d, -/* 0x0891: i2c_release */ - 0x08747e00, - 0x00047e00, - 0x03daf000, - 0x00002d7e, -/* 0x08a2: i2c_recv */ - 0x32f400f8, - 0xf8c1c701, - 0xb00214b6, - 0x1ff52816, - 0x13b80134, - 0x98000cf4, - 0x13b80032, - 0x98000ccc, - 0x31f40031, - 0xf9d0f902, - 0xd6d0f9e0, - 0x10000000, - 0xbb016792, - 0x65b60076, - 0x9450f904, - 0x56bb0465, - 0xfd50bd02, - 0x50fc0475, - 0x0008807e, - 0xfc0464b6, - 0x00d6b0d0, - 0x00b01bf5, - 0x76bb0005, +/* 0x089d: i2c_recv */ + 0x0132f400, + 0xb6f8c1c7, + 0x16b00214, + 0x341ff528, + 0xf413b801, + 0x3298000c, + 0xcc13b800, + 0x3198000c, + 0x0231f400, + 0xe0f9d0f9, + 0x00d6d0f9, + 0x92100000, + 0x76bb0167, 0x0465b600, 0x659450f9, 0x0256bb04, 0x75fd50bd, 0x7e50fc04, - 0xb600082d, - 0x11f50464, - 0xc5c700cc, - 0x0076bbe0, - 0xf90465b6, - 0x04659450, - 0xbd0256bb, - 0x0475fd50, - 0xd37e50fc, - 0x64b60007, - 0xa911f504, - 0xbb010500, - 0x65b60076, - 0x9450f904, - 0x56bb0465, - 0xfd50bd02, - 0x50fc0475, - 0x00082d7e, - 0xf50464b6, - 0xbb008711, - 0x65b60076, - 0x9450f904, - 0x56bb0465, - 0xfd50bd02, - 0x50fc0475, - 0x0007847e, - 0xf40464b6, - 0x5bcb6711, - 0x0076bbe0, + 0xb600087b, + 0xd0fc0464, + 0xf500d6b0, + 0x0500b01b, + 0x0076bb00, 0xf90465b6, 0x04659450, 0xbd0256bb, 0x0475fd50, - 0xd07e50fc, - 0x64b60006, - 0xbd5bb204, - 0x410ef474, -/* 0x09a4: i2c_recv_not_rd08 */ - 0xf401d6b0, - 0x00053b1b, - 0x00082d7e, - 0xc73211f4, - 0xd37ee0c5, - 0x11f40007, - 0x7e000528, - 0xf400082d, - 0xb5c71f11, - 0x07d37ee0, - 0x1511f400, - 0x0006d07e, - 0xc5c774bd, - 0x091bf408, - 0xf40232f4, -/* 0x09e2: i2c_recv_not_wr08 */ -/* 0x09e2: i2c_recv_done */ - 0xcec7030e, - 0x08917ef8, - 0xfce0fc00, - 0x0912f4d0, - 0x9f7e7cb2, -/* 0x09f6: i2c_recv_exit */ - 0x00f80002, -/* 0x09f8: i2c_init */ -/* 0x09fa: test_recv */ - 0x584100f8, - 0x0011cf04, - 0x400110b6, - 0x01f60458, - 0xde04bd00, - 0x134fd900, - 0x0001de7e, -/* 0x0a16: test_init */ - 0x004e00f8, - 0x01de7e08, -/* 0x0a1f: idle_recv */ + 0x287e50fc, + 0x64b60008, + 0xcc11f504, + 0xe0c5c700, + 0xb60076bb, + 0x50f90465, + 0xbb046594, + 0x50bd0256, + 0xfc0475fd, + 0x07ce7e50, + 0x0464b600, + 0x00a911f5, + 0x76bb0105, + 0x0465b600, + 0x659450f9, + 0x0256bb04, + 0x75fd50bd, + 0x7e50fc04, + 0xb6000828, + 0x11f50464, + 0x76bb0087, + 0x0465b600, + 0x659450f9, + 0x0256bb04, + 0x75fd50bd, + 0x7e50fc04, + 0xb600077f, + 0x11f40464, + 0xe05bcb67, + 0xb60076bb, + 0x50f90465, + 0xbb046594, + 0x50bd0256, + 0xfc0475fd, + 0x06cb7e50, + 0x0464b600, + 0x74bd5bb2, +/* 0x099f: i2c_recv_not_rd08 */ + 0xb0410ef4, + 0x1bf401d6, + 0x7e00053b, + 0xf4000828, + 0xc5c73211, + 0x07ce7ee0, + 0x2811f400, + 0x287e0005, + 0x11f40008, + 0xe0b5c71f, + 0x0007ce7e, + 0x7e1511f4, + 0xbd0006cb, + 0x08c5c774, + 0xf4091bf4, + 0x0ef40232, +/* 0x09dd: i2c_recv_not_wr08 */ +/* 0x09dd: i2c_recv_done */ + 0xf8cec703, + 0x00088c7e, + 0xd0fce0fc, + 0xb20912f4, + 0x029f7e7c, +/* 0x09f1: i2c_recv_exit */ +/* 0x09f3: i2c_init */ 0xf800f800, -/* 0x0a21: idle */ - 0x0031f400, - 0xcf045441, - 0x10b60011, - 0x04544001, - 0xbd0001f6, -/* 0x0a35: idle_loop */ - 0xf4580104, -/* 0x0a3a: idle_proc */ -/* 0x0a3a: idle_proc_exec */ - 0x10f90232, - 0xa87e1eb2, - 0x10fc0002, - 0xf40911f4, - 0x0ef40231, -/* 0x0a4d: idle_proc_next */ - 0x5810b6f0, - 0x1bf41fa6, - 0xe002f4e8, - 0xf40028f4, - 0x0000c60e, +/* 0x09f5: test_recv */ + 0x04584100, + 0xb60011cf, + 0x58400110, + 0x0001f604, + 0x00de04bd, + 0x7e134fd9, + 0xf80001de, +/* 0x0a11: test_init */ + 0x08004e00, + 0x0001de7e, +/* 0x0a1a: idle_recv */ + 0x00f800f8, +/* 0x0a1c: idle */ + 0x410031f4, + 0x11cf0454, + 0x0110b600, + 0xf6045440, + 0x04bd0001, +/* 0x0a30: idle_loop */ + 0x32f45801, +/* 0x0a35: idle_proc */ +/* 0x0a35: idle_proc_exec */ + 0xb210f902, + 0x02a87e1e, + 0xf410fc00, + 0x31f40911, + 0xf00ef402, +/* 0x0a48: idle_proc_next */ + 0xa65810b6, + 0xe81bf41f, + 0xf4e002f4, + 0x0ef40028, + 0x000000c6, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/gt215.fuc3.h b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/gt215.fuc3.h index 6a2572e8945a..defddf5957ee 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/gt215.fuc3.h +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/gt215.fuc3.h @@ -47,8 +47,8 @@ static uint32_t gt215_pmu_data[] = { 0x00000000, 0x00000000, 0x584d454d, - 0x0000083a, - 0x0000082c, + 0x00000833, + 0x00000825, 0x00000000, 0x00000000, 0x00000000, @@ -69,8 +69,8 @@ static uint32_t gt215_pmu_data[] = { 0x00000000, 0x00000000, 0x46524550, - 0x0000083e, - 0x0000083c, + 0x00000837, + 0x00000835, 0x00000000, 0x00000000, 0x00000000, @@ -91,8 +91,8 @@ static uint32_t gt215_pmu_data[] = { 0x00000000, 0x00000000, 0x5f433249, - 0x00000c6e, - 0x00000b11, + 0x00000c67, + 0x00000b0a, 0x00000000, 0x00000000, 0x00000000, @@ -113,8 +113,8 @@ static uint32_t gt215_pmu_data[] = { 0x00000000, 0x00000000, 0x54534554, - 0x00000c97, - 0x00000c70, + 0x00000c90, + 0x00000c69, 0x00000000, 0x00000000, 0x00000000, @@ -135,8 +135,8 @@ static uint32_t gt215_pmu_data[] = { 0x00000000, 0x00000000, 0x454c4449, - 0x00000ca3, - 0x00000ca1, + 0x00000c9c, + 0x00000c9a, 0x00000000, 0x00000000, 0x00000000, @@ -234,22 +234,22 @@ static uint32_t gt215_pmu_data[] = { /* 0x037c: memx_func_next */ 0x00000002, 0x00000000, - 0x000005a0, + 0x0000059f, 0x00000003, 0x00000002, - 0x00000632, + 0x0000062f, 0x00040004, 0x00000000, - 0x0000064e, + 0x0000064b, 0x00010005, 0x00000000, - 0x0000066b, + 0x00000668, 0x00010006, 0x00000000, - 0x000005f0, + 0x000005ef, 0x00000007, 0x00000000, - 0x00000676, + 0x00000673, /* 0x03c4: memx_func_tail */ /* 0x03c4: memx_ts_start */ 0x00000000, @@ -1305,560 +1305,560 @@ static uint32_t gt215_pmu_code[] = { 0x67f102d7, 0x63f1fffc, 0x76fdffff, - 0x0267f104, - 0x0576fd00, - 0x70f980f9, - 0xe0fcd0fc, - 0xf04021f4, + 0x0267f004, + 0xf90576fd, + 0xfc70f980, + 0xf4e0fcd0, + 0x67f04021, + 0xe007f104, + 0x0604b607, + 0xbd0006d0, +/* 0x0581: memx_func_enter_wait */ + 0xc067f104, + 0x0664b607, + 0xf00066cf, + 0x0bf40464, + 0x2c67f0f3, + 0xcf0664b6, + 0x06800066, +/* 0x059f: memx_func_leave */ + 0xf000f8f1, + 0x64b62c67, + 0x0066cf06, + 0xf0f20680, 0x07f10467, - 0x04b607e0, + 0x04b607e4, 0x0006d006, -/* 0x0582: memx_func_enter_wait */ +/* 0x05ba: memx_func_leave_wait */ 0x67f104bd, 0x64b607c0, 0x0066cf06, 0xf40464f0, - 0x67f0f30b, - 0x0664b62c, - 0x800066cf, - 0x00f8f106, -/* 0x05a0: memx_func_leave */ - 0xb62c67f0, - 0x66cf0664, - 0xf2068000, - 0xf10467f0, - 0xb607e407, - 0x06d00604, -/* 0x05bb: memx_func_leave_wait */ - 0xf104bd00, - 0xb607c067, - 0x66cf0664, - 0x0464f000, - 0xf1f31bf4, - 0xb9161087, - 0x21f4028e, - 0x02d7b904, - 0xffcc67f1, - 0xffff63f1, - 0xf90476fd, - 0xfc70f980, - 0xf4e0fcd0, - 0x00f84021, -/* 0x05f0: memx_func_wait_vblank */ - 0xb0001698, - 0x0bf40066, - 0x0166b013, - 0xf4060bf4, -/* 0x0602: memx_func_wait_vblank_head1 */ - 0x77f12e0e, - 0x0ef40020, -/* 0x0609: memx_func_wait_vblank_head0 */ - 0x0877f107, -/* 0x060d: memx_func_wait_vblank_0 */ - 0xc467f100, - 0x0664b607, - 0xfd0066cf, - 0x1bf40467, -/* 0x061d: memx_func_wait_vblank_1 */ - 0xc467f1f3, - 0x0664b607, - 0xfd0066cf, - 0x0bf40467, -/* 0x062d: memx_func_wait_vblank_fini */ - 0x0410b6f3, -/* 0x0632: memx_func_wr32 */ - 0x169800f8, - 0x01159800, - 0xf90810b6, - 0xfc50f960, - 0xf4e0fcd0, - 0x42b64021, - 0xe91bf402, -/* 0x064e: memx_func_wait */ - 0x87f000f8, - 0x0684b62c, - 0x980088cf, - 0x1d98001e, - 0x021c9801, - 0xb6031b98, - 0x21f41010, -/* 0x066b: memx_func_delay */ - 0x9800f8a3, - 0x10b6001e, - 0x7e21f404, -/* 0x0676: memx_func_train */ - 0x57f100f8, - 0x77f10003, - 0x97f10000, - 0x93f00000, - 0x029eb970, - 0xb90421f4, - 0xe7f102d8, - 0x21f42710, -/* 0x0695: memx_func_train_loop_outer */ - 0x0158e07e, - 0x0083f101, - 0xe097f102, - 0x1193f011, - 0x80f990f9, + 0x87f1f31b, + 0x8eb91610, + 0x0421f402, + 0xf102d7b9, + 0xf1ffcc67, + 0xfdffff63, + 0x80f90476, + 0xd0fc70f9, + 0x21f4e0fc, +/* 0x05ef: memx_func_wait_vblank */ + 0x9800f840, + 0x66b00016, + 0x120bf400, + 0xf40166b0, + 0x0ef4060b, +/* 0x0601: memx_func_wait_vblank_head1 */ + 0x2077f02c, +/* 0x0607: memx_func_wait_vblank_head0 */ + 0xf0060ef4, +/* 0x060a: memx_func_wait_vblank_0 */ + 0x67f10877, + 0x64b607c4, + 0x0066cf06, + 0xf40467fd, +/* 0x061a: memx_func_wait_vblank_1 */ + 0x67f1f31b, + 0x64b607c4, + 0x0066cf06, + 0xf40467fd, +/* 0x062a: memx_func_wait_vblank_fini */ + 0x10b6f30b, +/* 0x062f: memx_func_wr32 */ + 0x9800f804, + 0x15980016, + 0x0810b601, + 0x50f960f9, 0xe0fcd0fc, - 0xf94021f4, - 0x0067f150, -/* 0x06b5: memx_func_train_loop_inner */ - 0x1187f100, - 0x9068ff11, - 0xfd109894, - 0x97f10589, - 0x93f00720, - 0xf990f910, - 0xfcd0fc80, - 0x4021f4e0, - 0x008097f1, - 0xb91093f0, - 0x21f4029e, - 0x02d8b904, - 0xf92088c5, + 0xb64021f4, + 0x1bf40242, +/* 0x064b: memx_func_wait */ + 0xf000f8e9, + 0x84b62c87, + 0x0088cf06, + 0x98001e98, + 0x1c98011d, + 0x031b9802, + 0xf41010b6, + 0x00f8a321, +/* 0x0668: memx_func_delay */ + 0xb6001e98, + 0x21f40410, +/* 0x0673: memx_func_train */ + 0xf000f87e, + 0x77f00357, + 0x0097f100, + 0x7093f000, + 0xf4029eb9, + 0xd8b90421, + 0x10e7f102, + 0x7e21f427, +/* 0x0690: memx_func_train_loop_outer */ + 0x010158e0, + 0x020083f1, + 0x11e097f1, + 0xf91193f0, + 0xfc80f990, + 0xf4e0fcd0, + 0x50f94021, +/* 0x06af: memx_func_train_loop_inner */ + 0xf10067f0, + 0xff111187, + 0x98949068, + 0x0589fd10, + 0x072097f1, + 0xf91093f0, 0xfc80f990, 0xf4e0fcd0, 0x97f14021, - 0x93f0053c, - 0x0287f110, - 0x0083f130, - 0xf990f980, + 0x93f00080, + 0x029eb910, + 0xb90421f4, + 0x88c502d8, + 0xf990f920, 0xfcd0fc80, 0x4021f4e0, - 0x0560e7f1, - 0xf110e3f0, - 0xf10000d7, - 0x908000d3, - 0xb7f100dc, - 0xb3f08480, - 0xa321f41e, - 0x000057f1, - 0xffff97f1, - 0x830093f1, -/* 0x0734: memx_func_train_loop_4x */ - 0x0080a7f1, - 0xb910a3f0, - 0x21f402ae, - 0x02d8b904, - 0xffdfb7f1, - 0xffffb3f1, - 0xf9048bfd, - 0xfc80f9a0, + 0x053c97f1, + 0xf11093f0, + 0xf1300287, + 0xf9800083, + 0xfc80f990, 0xf4e0fcd0, - 0xa7f14021, - 0xa3f0053c, - 0x0287f110, - 0x0083f130, - 0xf9a0f980, - 0xfcd0fc80, - 0x4021f4e0, - 0x0560e7f1, - 0xf110e3f0, - 0xf10000d7, - 0xb98000d3, - 0xb7f102dc, - 0xb3f02710, - 0xa321f400, - 0xf402eeb9, - 0xddb90421, - 0x949dff02, + 0xe7f14021, + 0xe3f00560, + 0x00d7f110, + 0x00d3f100, + 0x00dc9080, + 0x8480b7f1, + 0xf41eb3f0, + 0x57f0a321, + 0xff97f100, + 0x0093f1ff, +/* 0x072d: memx_func_train_loop_4x */ + 0x80a7f183, + 0x10a3f000, + 0xf402aeb9, + 0xd8b90421, + 0xdfb7f102, + 0xffb3f1ff, + 0x048bfdff, + 0x80f9a0f9, + 0xe0fcd0fc, + 0xf14021f4, + 0xf0053ca7, + 0x87f110a3, + 0x83f13002, + 0xa0f98000, + 0xd0fc80f9, + 0x21f4e0fc, + 0x60e7f140, + 0x10e3f005, + 0x0000d7f1, + 0x8000d3f1, + 0xf102dcb9, + 0xf02710b7, + 0x21f400b3, + 0x02eeb9a3, + 0xb90421f4, + 0x9dff02dd, + 0x0150b694, + 0xf4045670, + 0x7aa0921e, + 0xa9800bcc, + 0x0160b600, + 0x700470b6, + 0x1ef51066, + 0x50fcff01, 0x700150b6, - 0x1ef40456, - 0xcc7aa092, - 0x00a9800b, - 0xb60160b6, - 0x66700470, - 0x001ef510, - 0xb650fcff, - 0x56700150, - 0xd41ef507, -/* 0x07c7: memx_exec */ - 0xf900f8fe, - 0xb9d0f9e0, - 0xb2b902c1, -/* 0x07d1: memx_exec_next */ - 0x00139802, - 0xe70410b6, - 0xe701f034, - 0xb601e033, - 0x30f00132, - 0xde35980c, - 0x12b855f9, - 0xe41ef406, - 0x98f10b98, - 0xcbbbf20c, - 0xc4b7f102, - 0x06b4b607, - 0xfc00bbcf, - 0xf5e0fcd0, + 0x1ef50756, + 0x00f8fed6, +/* 0x07c0: memx_exec */ + 0xd0f9e0f9, + 0xb902c1b9, +/* 0x07ca: memx_exec_next */ + 0x139802b2, + 0x0410b600, + 0x01f034e7, + 0x01e033e7, + 0xf00132b6, + 0x35980c30, + 0xb855f9de, + 0x1ef40612, + 0xf10b98e4, + 0xbbf20c98, + 0xb7f102cb, + 0xb4b607c4, + 0x00bbcf06, + 0xe0fcd0fc, + 0x033621f5, +/* 0x0806: memx_info */ + 0xc67000f8, + 0x0e0bf401, +/* 0x080c: memx_info_data */ + 0x03ccc7f1, + 0x0800b7f1, +/* 0x0817: memx_info_train */ + 0xf10b0ef4, + 0xf10bccc7, +/* 0x081f: memx_info_send */ + 0xf50100b7, 0xf8033621, -/* 0x080d: memx_info */ - 0x01c67000, -/* 0x0813: memx_info_data */ - 0xf10e0bf4, - 0xf103ccc7, - 0xf40800b7, -/* 0x081e: memx_info_train */ - 0xc7f10b0e, - 0xb7f10bcc, -/* 0x0826: memx_info_send */ - 0x21f50100, - 0x00f80336, -/* 0x082c: memx_recv */ - 0xf401d6b0, - 0xd6b0980b, - 0xd80bf400, -/* 0x083a: memx_init */ - 0x00f800f8, -/* 0x083c: perf_recv */ -/* 0x083e: perf_init */ - 0x00f800f8, -/* 0x0840: i2c_drive_scl */ - 0xf40036b0, - 0x07f1110b, - 0x04b607e0, - 0x0001d006, - 0x00f804bd, -/* 0x0854: i2c_drive_scl_lo */ - 0x07e407f1, - 0xd00604b6, - 0x04bd0001, -/* 0x0862: i2c_drive_sda */ - 0x36b000f8, - 0x110bf400, - 0x07e007f1, - 0xd00604b6, - 0x04bd0002, -/* 0x0876: i2c_drive_sda_lo */ - 0x07f100f8, - 0x04b607e4, - 0x0002d006, - 0x00f804bd, -/* 0x0884: i2c_sense_scl */ - 0xf10132f4, - 0xb607c437, - 0x33cf0634, - 0x0431fd00, - 0xf4060bf4, -/* 0x089a: i2c_sense_scl_done */ - 0x00f80131, -/* 0x089c: i2c_sense_sda */ - 0xf10132f4, - 0xb607c437, - 0x33cf0634, - 0x0432fd00, - 0xf4060bf4, -/* 0x08b2: i2c_sense_sda_done */ - 0x00f80131, -/* 0x08b4: i2c_raise_scl */ - 0x47f140f9, - 0x37f00898, - 0x4021f501, -/* 0x08c1: i2c_raise_scl_wait */ +/* 0x0825: memx_recv */ + 0x01d6b000, + 0xb0980bf4, + 0x0bf400d6, +/* 0x0833: memx_init */ + 0xf800f8d8, +/* 0x0835: perf_recv */ +/* 0x0837: perf_init */ + 0xf800f800, +/* 0x0839: i2c_drive_scl */ + 0x0036b000, + 0xf1110bf4, + 0xb607e007, + 0x01d00604, + 0xf804bd00, +/* 0x084d: i2c_drive_scl_lo */ + 0xe407f100, + 0x0604b607, + 0xbd0001d0, +/* 0x085b: i2c_drive_sda */ + 0xb000f804, + 0x0bf40036, + 0xe007f111, + 0x0604b607, + 0xbd0002d0, +/* 0x086f: i2c_drive_sda_lo */ + 0xf100f804, + 0xb607e407, + 0x02d00604, + 0xf804bd00, +/* 0x087d: i2c_sense_scl */ + 0x0132f400, + 0x07c437f1, + 0xcf0634b6, + 0x31fd0033, + 0x060bf404, +/* 0x0893: i2c_sense_scl_done */ + 0xf80131f4, +/* 0x0895: i2c_sense_sda */ + 0x0132f400, + 0x07c437f1, + 0xcf0634b6, + 0x32fd0033, + 0x060bf404, +/* 0x08ab: i2c_sense_sda_done */ + 0xf80131f4, +/* 0x08ad: i2c_raise_scl */ + 0xf140f900, + 0xf0089847, + 0x21f50137, +/* 0x08ba: i2c_raise_scl_wait */ + 0xe7f10839, + 0x21f403e8, + 0x7d21f57e, + 0x0901f408, + 0xf40142b6, +/* 0x08ce: i2c_raise_scl_done */ + 0x40fcef1b, +/* 0x08d2: i2c_start */ + 0x21f500f8, + 0x11f4087d, + 0x9521f50d, + 0x0611f408, +/* 0x08e3: i2c_start_rep */ + 0xf0300ef4, + 0x21f50037, + 0x37f00839, + 0x5b21f501, + 0x0076bb08, + 0xf90465b6, + 0x04659450, + 0xbd0256bb, + 0x0475fd50, + 0x21f550fc, + 0x64b608ad, + 0x1f11f404, +/* 0x0910: i2c_start_send */ + 0xf50037f0, + 0xf1085b21, + 0xf41388e7, + 0x37f07e21, + 0x3921f500, + 0x88e7f108, + 0x7e21f413, +/* 0x092c: i2c_start_out */ +/* 0x092e: i2c_stop */ + 0x37f000f8, + 0x3921f500, + 0x0037f008, + 0x085b21f5, + 0x03e8e7f1, + 0xf07e21f4, + 0x21f50137, + 0xe7f10839, + 0x21f41388, + 0x0137f07e, + 0x085b21f5, + 0x1388e7f1, + 0xf87e21f4, +/* 0x0961: i2c_bitw */ + 0x5b21f500, 0xe8e7f108, 0x7e21f403, - 0x088421f5, - 0xb60901f4, - 0x1bf40142, -/* 0x08d5: i2c_raise_scl_done */ - 0xf840fcef, -/* 0x08d9: i2c_start */ - 0x8421f500, - 0x0d11f408, - 0x089c21f5, - 0xf40611f4, -/* 0x08ea: i2c_start_rep */ - 0x37f0300e, - 0x4021f500, - 0x0137f008, - 0x086221f5, 0xb60076bb, 0x50f90465, 0xbb046594, 0x50bd0256, 0xfc0475fd, - 0xb421f550, + 0xad21f550, 0x0464b608, -/* 0x0917: i2c_start_send */ - 0xf01f11f4, - 0x21f50037, - 0xe7f10862, - 0x21f41388, - 0x0037f07e, - 0x084021f5, - 0x1388e7f1, -/* 0x0933: i2c_start_out */ - 0xf87e21f4, -/* 0x0935: i2c_stop */ - 0x0037f000, - 0x084021f5, - 0xf50037f0, - 0xf1086221, - 0xf403e8e7, + 0xf11811f4, + 0xf41388e7, 0x37f07e21, - 0x4021f501, + 0x3921f500, 0x88e7f108, 0x7e21f413, - 0xf50137f0, - 0xf1086221, - 0xf41388e7, - 0x00f87e21, -/* 0x0968: i2c_bitw */ - 0x086221f5, - 0x03e8e7f1, - 0xbb7e21f4, - 0x65b60076, - 0x9450f904, - 0x56bb0465, - 0xfd50bd02, - 0x50fc0475, - 0x08b421f5, - 0xf40464b6, - 0xe7f11811, +/* 0x09a0: i2c_bitw_out */ +/* 0x09a2: i2c_bitr */ + 0x37f000f8, + 0x5b21f501, + 0xe8e7f108, + 0x7e21f403, + 0xb60076bb, + 0x50f90465, + 0xbb046594, + 0x50bd0256, + 0xfc0475fd, + 0xad21f550, + 0x0464b608, + 0xf51b11f4, + 0xf0089521, + 0x21f50037, + 0xe7f10839, 0x21f41388, - 0x0037f07e, - 0x084021f5, - 0x1388e7f1, -/* 0x09a7: i2c_bitw_out */ - 0xf87e21f4, -/* 0x09a9: i2c_bitr */ - 0x0137f000, - 0x086221f5, - 0x03e8e7f1, - 0xbb7e21f4, - 0x65b60076, - 0x9450f904, - 0x56bb0465, - 0xfd50bd02, - 0x50fc0475, - 0x08b421f5, - 0xf40464b6, - 0x21f51b11, - 0x37f0089c, - 0x4021f500, - 0x88e7f108, - 0x7e21f413, - 0xf4013cf0, -/* 0x09ee: i2c_bitr_done */ - 0x00f80131, -/* 0x09f0: i2c_get_byte */ - 0xf00057f0, -/* 0x09f6: i2c_get_byte_next */ - 0x54b60847, + 0x013cf07e, +/* 0x09e7: i2c_bitr_done */ + 0xf80131f4, +/* 0x09e9: i2c_get_byte */ + 0x0057f000, +/* 0x09ef: i2c_get_byte_next */ + 0xb60847f0, + 0x76bb0154, + 0x0465b600, + 0x659450f9, + 0x0256bb04, + 0x75fd50bd, + 0xf550fc04, + 0xb609a221, + 0x11f40464, + 0x0553fd2b, + 0xf40142b6, + 0x37f0d81b, 0x0076bb01, 0xf90465b6, 0x04659450, 0xbd0256bb, 0x0475fd50, 0x21f550fc, - 0x64b609a9, - 0x2b11f404, - 0xb60553fd, - 0x1bf40142, - 0x0137f0d8, - 0xb60076bb, - 0x50f90465, - 0xbb046594, - 0x50bd0256, - 0xfc0475fd, - 0x6821f550, - 0x0464b609, -/* 0x0a40: i2c_get_byte_done */ -/* 0x0a42: i2c_put_byte */ - 0x47f000f8, -/* 0x0a45: i2c_put_byte_next */ - 0x0142b608, - 0xbb3854ff, - 0x65b60076, - 0x9450f904, - 0x56bb0465, - 0xfd50bd02, - 0x50fc0475, - 0x096821f5, - 0xf40464b6, - 0x46b03411, - 0xd81bf400, + 0x64b60961, +/* 0x0a39: i2c_get_byte_done */ +/* 0x0a3b: i2c_put_byte */ + 0xf000f804, +/* 0x0a3e: i2c_put_byte_next */ + 0x42b60847, + 0x3854ff01, 0xb60076bb, 0x50f90465, 0xbb046594, 0x50bd0256, 0xfc0475fd, - 0xa921f550, + 0x6121f550, 0x0464b609, - 0xbb0f11f4, - 0x36b00076, - 0x061bf401, -/* 0x0a9b: i2c_put_byte_done */ - 0xf80132f4, -/* 0x0a9d: i2c_addr */ - 0x0076bb00, + 0xb03411f4, + 0x1bf40046, + 0x0076bbd8, 0xf90465b6, 0x04659450, 0xbd0256bb, 0x0475fd50, 0x21f550fc, - 0x64b608d9, - 0x2911f404, - 0x012ec3e7, - 0xfd0134b6, - 0x76bb0553, + 0x64b609a2, + 0x0f11f404, + 0xb00076bb, + 0x1bf40136, + 0x0132f406, +/* 0x0a94: i2c_put_byte_done */ +/* 0x0a96: i2c_addr */ + 0x76bb00f8, 0x0465b600, 0x659450f9, 0x0256bb04, 0x75fd50bd, 0xf550fc04, - 0xb60a4221, -/* 0x0ae2: i2c_addr_done */ - 0x00f80464, -/* 0x0ae4: i2c_acquire_addr */ - 0xb6f8cec7, - 0xe0b702e4, - 0xee980d1c, -/* 0x0af3: i2c_acquire */ - 0xf500f800, - 0xf40ae421, - 0xd9f00421, - 0x4021f403, -/* 0x0b02: i2c_release */ - 0x21f500f8, - 0x21f40ae4, - 0x03daf004, - 0xf84021f4, -/* 0x0b11: i2c_recv */ - 0x0132f400, - 0xb6f8c1c7, - 0x16b00214, - 0x3a1ff528, - 0xf413a001, - 0x0032980c, - 0x0ccc13a0, - 0xf4003198, - 0xd0f90231, - 0xd0f9e0f9, - 0x000067f1, - 0x100063f1, - 0xbb016792, + 0xb608d221, + 0x11f40464, + 0x2ec3e729, + 0x0134b601, + 0xbb0553fd, 0x65b60076, 0x9450f904, 0x56bb0465, 0xfd50bd02, 0x50fc0475, - 0x0af321f5, - 0xfc0464b6, - 0x00d6b0d0, - 0x00b31bf5, - 0xbb0057f0, + 0x0a3b21f5, +/* 0x0adb: i2c_addr_done */ + 0xf80464b6, +/* 0x0add: i2c_acquire_addr */ + 0xf8cec700, + 0xb702e4b6, + 0x980d1ce0, + 0x00f800ee, +/* 0x0aec: i2c_acquire */ + 0x0add21f5, + 0xf00421f4, + 0x21f403d9, +/* 0x0afb: i2c_release */ + 0xf500f840, + 0xf40add21, + 0xdaf00421, + 0x4021f403, +/* 0x0b0a: i2c_recv */ + 0x32f400f8, + 0xf8c1c701, + 0xb00214b6, + 0x1ff52816, + 0x13a0013a, + 0x32980cf4, + 0xcc13a000, + 0x0031980c, + 0xf90231f4, + 0xf9e0f9d0, + 0x0067f1d0, + 0x0063f100, + 0x01679210, + 0xb60076bb, + 0x50f90465, + 0xbb046594, + 0x50bd0256, + 0xfc0475fd, + 0xec21f550, + 0x0464b60a, + 0xd6b0d0fc, + 0xb31bf500, + 0x0057f000, + 0xb60076bb, + 0x50f90465, + 0xbb046594, + 0x50bd0256, + 0xfc0475fd, + 0x9621f550, + 0x0464b60a, + 0x00d011f5, + 0xbbe0c5c7, 0x65b60076, 0x9450f904, 0x56bb0465, 0xfd50bd02, 0x50fc0475, - 0x0a9d21f5, + 0x0a3b21f5, 0xf50464b6, - 0xc700d011, - 0x76bbe0c5, + 0xf000ad11, + 0x76bb0157, 0x0465b600, 0x659450f9, 0x0256bb04, 0x75fd50bd, 0xf550fc04, - 0xb60a4221, + 0xb60a9621, 0x11f50464, - 0x57f000ad, - 0x0076bb01, - 0xf90465b6, - 0x04659450, - 0xbd0256bb, - 0x0475fd50, - 0x21f550fc, - 0x64b60a9d, - 0x8a11f504, - 0x0076bb00, - 0xf90465b6, - 0x04659450, - 0xbd0256bb, - 0x0475fd50, - 0x21f550fc, - 0x64b609f0, - 0x6a11f404, - 0xbbe05bcb, - 0x65b60076, - 0x9450f904, - 0x56bb0465, - 0xfd50bd02, - 0x50fc0475, - 0x093521f5, - 0xb90464b6, - 0x74bd025b, -/* 0x0c17: i2c_recv_not_rd08 */ - 0xb0430ef4, - 0x1bf401d6, - 0x0057f03d, - 0x0a9d21f5, - 0xc73311f4, - 0x21f5e0c5, - 0x11f40a42, - 0x0057f029, - 0x0a9d21f5, - 0xc71f11f4, - 0x21f5e0b5, - 0x11f40a42, - 0x3521f515, - 0xc774bd09, - 0x1bf408c5, - 0x0232f409, -/* 0x0c57: i2c_recv_not_wr08 */ -/* 0x0c57: i2c_recv_done */ - 0xc7030ef4, - 0x21f5f8ce, - 0xe0fc0b02, - 0x12f4d0fc, - 0x027cb90a, - 0x033621f5, -/* 0x0c6c: i2c_recv_exit */ -/* 0x0c6e: i2c_init */ + 0x76bb008a, + 0x0465b600, + 0x659450f9, + 0x0256bb04, + 0x75fd50bd, + 0xf550fc04, + 0xb609e921, + 0x11f40464, + 0xe05bcb6a, + 0xb60076bb, + 0x50f90465, + 0xbb046594, + 0x50bd0256, + 0xfc0475fd, + 0x2e21f550, + 0x0464b609, + 0xbd025bb9, + 0x430ef474, +/* 0x0c10: i2c_recv_not_rd08 */ + 0xf401d6b0, + 0x57f03d1b, + 0x9621f500, + 0x3311f40a, + 0xf5e0c5c7, + 0xf40a3b21, + 0x57f02911, + 0x9621f500, + 0x1f11f40a, + 0xf5e0b5c7, + 0xf40a3b21, + 0x21f51511, + 0x74bd092e, + 0xf408c5c7, + 0x32f4091b, + 0x030ef402, +/* 0x0c50: i2c_recv_not_wr08 */ +/* 0x0c50: i2c_recv_done */ + 0xf5f8cec7, + 0xfc0afb21, + 0xf4d0fce0, + 0x7cb90a12, + 0x3621f502, +/* 0x0c65: i2c_recv_exit */ +/* 0x0c67: i2c_init */ + 0xf800f803, +/* 0x0c69: test_recv */ + 0xd817f100, + 0x0614b605, + 0xb60011cf, + 0x07f10110, + 0x04b605d8, + 0x0001d006, + 0xe7f104bd, + 0xe3f1d900, + 0x21f5134f, + 0x00f80256, +/* 0x0c90: test_init */ + 0x0800e7f1, + 0x025621f5, +/* 0x0c9a: idle_recv */ 0x00f800f8, -/* 0x0c70: test_recv */ - 0x05d817f1, - 0xcf0614b6, - 0x10b60011, - 0xd807f101, - 0x0604b605, - 0xbd0001d0, - 0x00e7f104, - 0x4fe3f1d9, - 0x5621f513, -/* 0x0c97: test_init */ - 0xf100f802, - 0xf50800e7, - 0xf8025621, -/* 0x0ca1: idle_recv */ -/* 0x0ca3: idle */ - 0xf400f800, - 0x17f10031, - 0x14b605d4, - 0x0011cf06, - 0xf10110b6, - 0xb605d407, - 0x01d00604, -/* 0x0cbf: idle_loop */ - 0xf004bd00, - 0x32f45817, -/* 0x0cc5: idle_proc */ -/* 0x0cc5: idle_proc_exec */ - 0xb910f902, - 0x21f5021e, - 0x10fc033f, - 0xf40911f4, - 0x0ef40231, -/* 0x0cd9: idle_proc_next */ - 0x5810b6ef, - 0xf4061fb8, - 0x02f4e61b, - 0x0028f4dd, - 0x00bb0ef4, +/* 0x0c9c: idle */ + 0xf10031f4, + 0xb605d417, + 0x11cf0614, + 0x0110b600, + 0x05d407f1, + 0xd00604b6, + 0x04bd0001, +/* 0x0cb8: idle_loop */ + 0xf45817f0, +/* 0x0cbe: idle_proc */ +/* 0x0cbe: idle_proc_exec */ + 0x10f90232, + 0xf5021eb9, + 0xfc033f21, + 0x0911f410, + 0xf40231f4, +/* 0x0cd2: idle_proc_next */ + 0x10b6ef0e, + 0x061fb858, + 0xf4e61bf4, + 0x28f4dd02, + 0xbb0ef400, + 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/memx.fuc b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/memx.fuc index ec03f9a4290b..1663bf943d77 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/memx.fuc +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/memx.fuc @@ -82,15 +82,15 @@ memx_train_tail: // $r0 - zero memx_func_enter: #if NVKM_PPWR_CHIPSET == GT215 - movw $r8 0x1610 + mov $r8 0x1610 nv_rd32($r7, $r8) imm32($r6, 0xfffffffc) and $r7 $r6 - movw $r6 0x2 + mov $r6 0x2 or $r7 $r6 nv_wr32($r8, $r7) #else - movw $r6 0x001620 + mov $r6 0x001620 imm32($r7, ~0x00000aa2); nv_rd32($r8, $r6) and $r8 $r7 @@ -101,7 +101,7 @@ memx_func_enter: and $r8 $r7 nv_wr32($r6, $r8) - movw $r6 0x0026f0 + mov $r6 0x0026f0 nv_rd32($r8, $r6) and $r8 $r7 nv_wr32($r6, $r8) @@ -136,19 +136,19 @@ memx_func_leave: bra nz #memx_func_leave_wait #if NVKM_PPWR_CHIPSET == GT215 - movw $r8 0x1610 + mov $r8 0x1610 nv_rd32($r7, $r8) imm32($r6, 0xffffffcc) and $r7 $r6 nv_wr32($r8, $r7) #else - movw $r6 0x0026f0 + mov $r6 0x0026f0 imm32($r7, 0x00000001) nv_rd32($r8, $r6) or $r8 $r7 nv_wr32($r6, $r8) - movw $r6 0x001620 + mov $r6 0x001620 nv_rd32($r8, $r6) or $r8 $r7 nv_wr32($r6, $r8) @@ -177,11 +177,11 @@ memx_func_wait_vblank: bra #memx_func_wait_vblank_fini memx_func_wait_vblank_head1: - movw $r7 0x20 + mov $r7 0x20 bra #memx_func_wait_vblank_0 memx_func_wait_vblank_head0: - movw $r7 0x8 + mov $r7 0x8 memx_func_wait_vblank_0: nv_iord($r6, NV_PPWR_INPUT) @@ -273,13 +273,13 @@ memx_func_train: // $r5 - outer loop counter // $r6 - inner loop counter // $r7 - entry counter (#memx_train_head + $r7) - movw $r5 0x3 - movw $r7 0x0 + mov $r5 0x3 + mov $r7 0x0 // Read random memory to wake up... things imm32($r9, 0x700000) nv_rd32($r8,$r9) - movw $r14 0x2710 + mov $r14 0x2710 call(nsec) memx_func_train_loop_outer: @@ -289,9 +289,9 @@ memx_func_train: nv_wr32($r9, $r8) push $r5 - movw $r6 0x0 + mov $r6 0x0 memx_func_train_loop_inner: - movw $r8 0x1111 + mov $r8 0x1111 mulu $r9 $r6 $r8 shl b32 $r8 $r9 0x10 or $r8 $r9 @@ -315,7 +315,7 @@ memx_func_train: // $r5 - inner inner loop counter // $r9 - result - movw $r5 0 + mov $r5 0 imm32($r9, 0x8300ffff) memx_func_train_loop_4x: imm32($r10, 0x100080) -- GitLab From 2cd5100363b794cdd26d878cbde0c12c33687e7d Mon Sep 17 00:00:00 2001 From: Sebastian Ott Date: Tue, 23 Jan 2018 13:58:05 +0100 Subject: [PATCH 0989/1635] s390/eadm: fix CONFIG_BLOCK include dependency [ Upstream commit 366b77ae43c5a3bf1a367f15ec8bc16e05035f14 ] Commit 2a842acab109 ("block: introduce new block status code type") added blk_status_t usage to the eadm subchannel driver. However blk_status_t is unknown when included via for CONFIG_BLOCK=n. Only include since this is the only dependency eadm has. This fixes build failures like below: In file included from drivers/s390/cio/eadm_sch.c:24:0: ./arch/s390/include/asm/eadm.h:111:4: error: unknown type name 'blk_status_t'; did you mean 'si_status'? blk_status_t error); Reported-by: Heiko Carstens Signed-off-by: Sebastian Ott Signed-off-by: Martin Schwidefsky Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/s390/include/asm/eadm.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/s390/include/asm/eadm.h b/arch/s390/include/asm/eadm.h index eb5323161f11..bb63b2afdf6f 100644 --- a/arch/s390/include/asm/eadm.h +++ b/arch/s390/include/asm/eadm.h @@ -4,7 +4,7 @@ #include #include -#include +#include struct arqb { u64 data; -- GitLab From 074372c8124cbd62a8edf8b979fa814b4e223ece Mon Sep 17 00:00:00 2001 From: Subash Abhinov Kasiviswanathan Date: Wed, 31 Jan 2018 04:50:01 -0700 Subject: [PATCH 0990/1635] netfilter: ipv6: nf_defrag: Kill frag queue on RFC2460 failure [ Upstream commit ea23d5e3bf340e413b8e05c13da233c99c64142b ] Failures were seen in ICMPv6 fragmentation timeout tests if they were run after the RFC2460 failure tests. Kernel was not sending out the ICMPv6 fragment reassembly time exceeded packet after the fragmentation reassembly timeout of 1 minute had elapsed. This happened because the frag queue was not released if an error in IPv6 fragmentation header was detected by RFC2460. Fixes: 83f1999caeb1 ("netfilter: ipv6: nf_defrag: Pass on packets to stack per RFC2460") Signed-off-by: Subash Abhinov Kasiviswanathan Signed-off-by: Pablo Neira Ayuso Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- net/ipv6/netfilter/nf_conntrack_reasm.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/ipv6/netfilter/nf_conntrack_reasm.c b/net/ipv6/netfilter/nf_conntrack_reasm.c index 5edfe66a3d7a..64ec23388450 100644 --- a/net/ipv6/netfilter/nf_conntrack_reasm.c +++ b/net/ipv6/netfilter/nf_conntrack_reasm.c @@ -263,6 +263,7 @@ static int nf_ct_frag6_queue(struct frag_queue *fq, struct sk_buff *skb, * this case. -DaveM */ pr_debug("end of fragment not rounded to 8 bytes.\n"); + inet_frag_kill(&fq->q, &nf_frags); return -EPROTO; } if (end > fq->q.len) { -- GitLab From 423505471f5ed18ed88afe66592931f91245fce2 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Fri, 2 Feb 2018 15:56:18 +0100 Subject: [PATCH 0991/1635] x86/power: Fix swsusp_arch_resume prototype [ Upstream commit 328008a72d38b5bde6491e463405c34a81a65d3e ] The declaration for swsusp_arch_resume marks it as 'asmlinkage', but the definition in x86-32 does not, and it fails to include the header with the declaration. This leads to a warning when building with link-time-optimizations: kernel/power/power.h:108:23: error: type of 'swsusp_arch_resume' does not match original declaration [-Werror=lto-type-mismatch] extern asmlinkage int swsusp_arch_resume(void); ^ arch/x86/power/hibernate_32.c:148:0: note: 'swsusp_arch_resume' was previously declared here int swsusp_arch_resume(void) This moves the declaration into a globally visible header file and fixes up both x86 definitions to match it. Signed-off-by: Arnd Bergmann Signed-off-by: Thomas Gleixner Cc: Len Brown Cc: Andi Kleen Cc: Nicolas Pitre Cc: linux-pm@vger.kernel.org Cc: "Rafael J. Wysocki" Cc: Pavel Machek Cc: Bart Van Assche Link: https://lkml.kernel.org/r/20180202145634.200291-2-arnd@arndb.de Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/x86/power/hibernate_32.c | 2 +- arch/x86/power/hibernate_64.c | 2 +- include/linux/suspend.h | 2 ++ kernel/power/power.h | 3 --- 4 files changed, 4 insertions(+), 5 deletions(-) diff --git a/arch/x86/power/hibernate_32.c b/arch/x86/power/hibernate_32.c index c35fdb585c68..afc4ed7b1578 100644 --- a/arch/x86/power/hibernate_32.c +++ b/arch/x86/power/hibernate_32.c @@ -145,7 +145,7 @@ static inline void resume_init_first_level_page_table(pgd_t *pg_dir) #endif } -int swsusp_arch_resume(void) +asmlinkage int swsusp_arch_resume(void) { int error; diff --git a/arch/x86/power/hibernate_64.c b/arch/x86/power/hibernate_64.c index f910c514438f..0ef5e5204968 100644 --- a/arch/x86/power/hibernate_64.c +++ b/arch/x86/power/hibernate_64.c @@ -174,7 +174,7 @@ static int relocate_restore_code(void) return 0; } -int swsusp_arch_resume(void) +asmlinkage int swsusp_arch_resume(void) { int error; diff --git a/include/linux/suspend.h b/include/linux/suspend.h index d60b0f5c38d5..8544357d92d0 100644 --- a/include/linux/suspend.h +++ b/include/linux/suspend.h @@ -384,6 +384,8 @@ extern int swsusp_page_is_forbidden(struct page *); extern void swsusp_set_page_free(struct page *); extern void swsusp_unset_page_free(struct page *); extern unsigned long get_safe_page(gfp_t gfp_mask); +extern asmlinkage int swsusp_arch_suspend(void); +extern asmlinkage int swsusp_arch_resume(void); extern void hibernation_set_ops(const struct platform_hibernation_ops *ops); extern int hibernate(void); diff --git a/kernel/power/power.h b/kernel/power/power.h index f29cd178df90..9e58bdc8a562 100644 --- a/kernel/power/power.h +++ b/kernel/power/power.h @@ -104,9 +104,6 @@ extern int in_suspend; extern dev_t swsusp_resume_device; extern sector_t swsusp_resume_block; -extern asmlinkage int swsusp_arch_suspend(void); -extern asmlinkage int swsusp_arch_resume(void); - extern int create_basic_memory_bitmaps(void); extern void free_basic_memory_bitmaps(void); extern int hibernate_preallocate_memory(void); -- GitLab From ee06ed9ba5182bfdbc829f150b594c7f14a9d62f Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Fri, 2 Feb 2018 15:56:17 +0100 Subject: [PATCH 0992/1635] x86/dumpstack: Avoid uninitlized variable [ Upstream commit ebfc15019cfa72496c674ffcb0b8ef10790dcddc ] In some configurations, 'partial' does not get initialized, as shown by this gcc-8 warning: arch/x86/kernel/dumpstack.c: In function 'show_trace_log_lvl': arch/x86/kernel/dumpstack.c:156:4: error: 'partial' may be used uninitialized in this function [-Werror=maybe-uninitialized] show_regs_if_on_stack(&stack_info, regs, partial); ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ This initializes it to false, to get the previous behavior in this case. Fixes: a9cdbe72c4e8 ("x86/dumpstack: Fix partial register dumps") Signed-off-by: Arnd Bergmann Signed-off-by: Thomas Gleixner Cc: Andi Kleen Cc: Nicolas Pitre Cc: Peter Zijlstra Cc: Dave Hansen Cc: Andy Lutomirski Cc: Josh Poimboeuf Cc: Borislav Petkov Cc: Vlastimil Babka Link: https://lkml.kernel.org/r/20180202145634.200291-1-arnd@arndb.de Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/x86/kernel/dumpstack.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/kernel/dumpstack.c b/arch/x86/kernel/dumpstack.c index afbecff161d1..a2d8a3908670 100644 --- a/arch/x86/kernel/dumpstack.c +++ b/arch/x86/kernel/dumpstack.c @@ -109,7 +109,7 @@ void show_trace_log_lvl(struct task_struct *task, struct pt_regs *regs, struct stack_info stack_info = {0}; unsigned long visit_mask = 0; int graph_idx = 0; - bool partial; + bool partial = false; printk("%sCall Trace:\n", log_lvl); -- GitLab From 573cb560b4edd71a6b9dd41cdc39d27abb8dda30 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Sat, 3 Feb 2018 11:25:20 +0100 Subject: [PATCH 0993/1635] firmware: dmi_scan: Fix handling of empty DMI strings [ Upstream commit a7770ae194569e96a93c48aceb304edded9cc648 ] The handling of empty DMI strings looks quite broken to me: * Strings from 1 to 7 spaces are not considered empty. * True empty DMI strings (string index set to 0) are not considered empty, and result in allocating a 0-char string. * Strings with invalid index also result in allocating a 0-char string. * Strings starting with 8 spaces are all considered empty, even if non-space characters follow (sounds like a weird thing to do, but I have actually seen occurrences of this in DMI tables before.) * Strings which are considered empty are reported as 8 spaces, instead of being actually empty. Some of these issues are the result of an off-by-one error in memcmp, the rest is incorrect by design. So let's get it square: missing strings and strings made of only spaces, regardless of their length, should be treated as empty and no memory should be allocated for them. All other strings are non-empty and should be allocated. Signed-off-by: Jean Delvare Fixes: 79da4721117f ("x86: fix DMI out of memory problems") Cc: Parag Warudkar Cc: Ingo Molnar Cc: Thomas Gleixner Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/firmware/dmi_scan.c | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/drivers/firmware/dmi_scan.c b/drivers/firmware/dmi_scan.c index 783041964439..e8db9659a36b 100644 --- a/drivers/firmware/dmi_scan.c +++ b/drivers/firmware/dmi_scan.c @@ -18,7 +18,7 @@ EXPORT_SYMBOL_GPL(dmi_kobj); * of and an antecedent to, SMBIOS, which stands for System * Management BIOS. See further: http://www.dmtf.org/standards */ -static const char dmi_empty_string[] = " "; +static const char dmi_empty_string[] = ""; static u32 dmi_ver __initdata; static u32 dmi_len; @@ -44,25 +44,21 @@ static int dmi_memdev_nr; static const char * __init dmi_string_nosave(const struct dmi_header *dm, u8 s) { const u8 *bp = ((u8 *) dm) + dm->length; + const u8 *nsp; if (s) { - s--; - while (s > 0 && *bp) { + while (--s > 0 && *bp) bp += strlen(bp) + 1; - s--; - } - - if (*bp != 0) { - size_t len = strlen(bp)+1; - size_t cmp_len = len > 8 ? 8 : len; - if (!memcmp(bp, dmi_empty_string, cmp_len)) - return dmi_empty_string; + /* Strings containing only spaces are considered empty */ + nsp = bp; + while (*nsp == ' ') + nsp++; + if (*nsp != '\0') return bp; - } } - return ""; + return dmi_empty_string; } static const char * __init dmi_string(const struct dmi_header *dm, u8 s) -- GitLab From 51939996acde4bce855f70a32544aaf44f8e3f0a Mon Sep 17 00:00:00 2001 From: Chen Yu Date: Mon, 29 Jan 2018 10:26:46 +0800 Subject: [PATCH 0994/1635] ACPI: processor_perflib: Do not send _PPC change notification if not ready [ Upstream commit ba1edb9a5125a617d612f98eead14b9b84e75c3a ] The following warning was triggered after resumed from S3 - if all the nonboot CPUs were put offline before suspend: [ 1840.329515] unchecked MSR access error: RDMSR from 0x771 at rIP: 0xffffffff86061e3a (native_read_msr+0xa/0x30) [ 1840.329516] Call Trace: [ 1840.329521] __rdmsr_on_cpu+0x33/0x50 [ 1840.329525] generic_exec_single+0x81/0xb0 [ 1840.329527] smp_call_function_single+0xd2/0x100 [ 1840.329530] ? acpi_ds_result_pop+0xdd/0xf2 [ 1840.329532] ? acpi_ds_create_operand+0x215/0x23c [ 1840.329534] rdmsrl_on_cpu+0x57/0x80 [ 1840.329536] ? cpumask_next+0x1b/0x20 [ 1840.329538] ? rdmsrl_on_cpu+0x57/0x80 [ 1840.329541] intel_pstate_update_perf_limits+0xf3/0x220 [ 1840.329544] ? notifier_call_chain+0x4a/0x70 [ 1840.329546] intel_pstate_set_policy+0x4e/0x150 [ 1840.329548] cpufreq_set_policy+0xcd/0x2f0 [ 1840.329550] cpufreq_update_policy+0xb2/0x130 [ 1840.329552] ? cpufreq_update_policy+0x130/0x130 [ 1840.329556] acpi_processor_ppc_has_changed+0x65/0x80 [ 1840.329558] acpi_processor_notify+0x80/0x100 [ 1840.329561] acpi_ev_notify_dispatch+0x44/0x5c [ 1840.329563] acpi_os_execute_deferred+0x14/0x20 [ 1840.329565] process_one_work+0x193/0x3c0 [ 1840.329567] worker_thread+0x35/0x3b0 [ 1840.329569] kthread+0x125/0x140 [ 1840.329571] ? process_one_work+0x3c0/0x3c0 [ 1840.329572] ? kthread_park+0x60/0x60 [ 1840.329575] ? do_syscall_64+0x67/0x180 [ 1840.329577] ret_from_fork+0x25/0x30 [ 1840.329585] unchecked MSR access error: WRMSR to 0x774 (tried to write 0x0000000000000000) at rIP: 0xffffffff86061f78 (native_write_msr+0x8/0x30) [ 1840.329586] Call Trace: [ 1840.329587] __wrmsr_on_cpu+0x37/0x40 [ 1840.329589] generic_exec_single+0x81/0xb0 [ 1840.329592] smp_call_function_single+0xd2/0x100 [ 1840.329594] ? acpi_ds_create_operand+0x215/0x23c [ 1840.329595] ? cpumask_next+0x1b/0x20 [ 1840.329597] wrmsrl_on_cpu+0x57/0x70 [ 1840.329598] ? rdmsrl_on_cpu+0x57/0x80 [ 1840.329599] ? wrmsrl_on_cpu+0x57/0x70 [ 1840.329602] intel_pstate_hwp_set+0xd3/0x150 [ 1840.329604] intel_pstate_set_policy+0x119/0x150 [ 1840.329606] cpufreq_set_policy+0xcd/0x2f0 [ 1840.329607] cpufreq_update_policy+0xb2/0x130 [ 1840.329610] ? cpufreq_update_policy+0x130/0x130 [ 1840.329613] acpi_processor_ppc_has_changed+0x65/0x80 [ 1840.329615] acpi_processor_notify+0x80/0x100 [ 1840.329617] acpi_ev_notify_dispatch+0x44/0x5c [ 1840.329619] acpi_os_execute_deferred+0x14/0x20 [ 1840.329620] process_one_work+0x193/0x3c0 [ 1840.329622] worker_thread+0x35/0x3b0 [ 1840.329624] kthread+0x125/0x140 [ 1840.329625] ? process_one_work+0x3c0/0x3c0 [ 1840.329626] ? kthread_park+0x60/0x60 [ 1840.329628] ? do_syscall_64+0x67/0x180 [ 1840.329631] ret_from_fork+0x25/0x30 This is because if there's only one online CPU, the MSR_PM_ENABLE (package wide)can not be enabled after resumed, due to intel_pstate_hwp_enable() will only be invoked on AP's online process after resumed - if there's no AP online, the HWP remains disabled after resumed (BIOS has disabled it in S3). Then if there comes a _PPC change notification which touches HWP register during this stage, the warning is triggered. Since we don't call acpi_processor_register_performance() when HWP is enabled, the pr->performance will be NULL. When this is NULL we don't need to do _PPC change notification. Reported-by: Doug Smythies Suggested-by: Srinivas Pandruvada Signed-off-by: Yu Chen Signed-off-by: Rafael J. Wysocki Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/acpi/processor_perflib.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/acpi/processor_perflib.c b/drivers/acpi/processor_perflib.c index 18b72eec3507..c7cf48ad5cb9 100644 --- a/drivers/acpi/processor_perflib.c +++ b/drivers/acpi/processor_perflib.c @@ -159,7 +159,7 @@ void acpi_processor_ppc_has_changed(struct acpi_processor *pr, int event_flag) { int ret; - if (ignore_ppc) { + if (ignore_ppc || !pr->performance) { /* * Only when it is notification event, the _OST object * will be evaluated. Otherwise it is skipped. -- GitLab From f920e914801c57f6853a62bba081fd6f3b11aede Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 26 Jan 2018 16:02:58 +0100 Subject: [PATCH 0995/1635] ACPI / bus: Do not call _STA on battery devices with unmet dependencies [ Upstream commit 54ddce7062242036402242242c07c60c0b505f84 ] The battery code uses acpi_device->dep_unmet to check for unmet deps and if there are unmet deps it does not bind to the device to avoid errors about missing OpRegions when calling ACPI methods on the device. The missing OpRegions when there are unmet deps problem also applies to the _STA method of some battery devices and calling it too early results in errors like these: [ 0.123579] ACPI Error: No handler for Region [ECRM] (00000000ba9edc4c) [GenericSerialBus] (20170831/evregion-166) [ 0.123601] ACPI Error: Region GenericSerialBus (ID=9) has no handler (20170831/exfldio-299) [ 0.123618] ACPI Error: Method parse/execution failed \_SB.I2C1.BAT1._STA, AE_NOT_EXIST (20170831/psparse-550) This commit fixes these errors happening when acpi_get_bus_status gets called by checking dep_unmet for battery devices and reporting a status of 0 until all dependencies are met. Signed-off-by: Hans de Goede Signed-off-by: Rafael J. Wysocki Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/acpi/bus.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index b6d58cc58f5f..f0348e388d01 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -146,6 +146,12 @@ int acpi_bus_get_status(struct acpi_device *device) return 0; } + /* Battery devices must have their deps met before calling _STA */ + if (acpi_device_is_battery(device) && device->dep_unmet) { + acpi_set_device_status(device, 0); + return 0; + } + status = acpi_bus_get_status_handle(device->handle, &sta); if (ACPI_FAILURE(status)) return -ENODEV; -- GitLab From 74abca65f1e43f747ee429441792be9394667944 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 26 Jan 2018 16:02:59 +0100 Subject: [PATCH 0996/1635] ACPI / scan: Use acpi_bus_get_status() to initialize ACPI_TYPE_DEVICE devs [ Upstream commit 63347db0affadcbccd5613116ea8431c70139b3e ] The acpi_get_bus_status wrapper for acpi_bus_get_status_handle has some code to handle certain device quirks, in some cases we also need this quirk handling for the initial _STA call. Specifically on some devices calling _STA before all _DEP dependencies are met results in errors like these: [ 0.123579] ACPI Error: No handler for Region [ECRM] (00000000ba9edc4c) [GenericSerialBus] (20170831/evregion-166) [ 0.123601] ACPI Error: Region GenericSerialBus (ID=9) has no handler (20170831/exfldio-299) [ 0.123618] ACPI Error: Method parse/execution failed \_SB.I2C1.BAT1._STA, AE_NOT_EXIST (20170831/psparse-550) acpi_get_bus_status already has code to avoid this, so by using it we also silence these errors from the initial _STA call. Note that in order for the acpi_get_bus_status handling for this to work, we initialize dep_unmet to 1 until acpi_device_dep_initialize gets called, this means that battery devices will be instantiated with an initial status of 0. This is not a problem, acpi_bus_attach will get called soon after the instantiation anyways and it will update the status as first point of order. Signed-off-by: Hans de Goede Signed-off-by: Rafael J. Wysocki Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/acpi/scan.c | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 2f2f50322ffb..c0984d33c4c8 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -1568,6 +1568,8 @@ void acpi_init_device_object(struct acpi_device *device, acpi_handle handle, device_initialize(&device->dev); dev_set_uevent_suppress(&device->dev, true); acpi_init_coherency(device); + /* Assume there are unmet deps until acpi_device_dep_initialize() runs */ + device->dep_unmet = 1; } void acpi_device_add_finalize(struct acpi_device *device) @@ -1591,6 +1593,14 @@ static int acpi_add_single_object(struct acpi_device **child, } acpi_init_device_object(device, handle, type, sta); + /* + * For ACPI_BUS_TYPE_DEVICE getting the status is delayed till here so + * that we can call acpi_bus_get_status() and use its quirk handling. + * Note this must be done before the get power-/wakeup_dev-flags calls. + */ + if (type == ACPI_BUS_TYPE_DEVICE) + acpi_bus_get_status(device); + acpi_bus_get_power_flags(device); acpi_bus_get_wakeup_device_flags(device); @@ -1663,9 +1673,11 @@ static int acpi_bus_type_and_status(acpi_handle handle, int *type, return -ENODEV; *type = ACPI_BUS_TYPE_DEVICE; - status = acpi_bus_get_status_handle(handle, sta); - if (ACPI_FAILURE(status)) - *sta = 0; + /* + * acpi_add_single_object updates this once we've an acpi_device + * so that acpi_bus_get_status' quirk handling can be used. + */ + *sta = 0; break; case ACPI_TYPE_PROCESSOR: *type = ACPI_BUS_TYPE_PROCESSOR; @@ -1763,6 +1775,8 @@ static void acpi_device_dep_initialize(struct acpi_device *adev) acpi_status status; int i; + adev->dep_unmet = 0; + if (!acpi_has_method(adev->handle, "_DEP")) return; -- GitLab From 3e01c16d87511071679d3d3d14c0f8d37b856b52 Mon Sep 17 00:00:00 2001 From: Yonghong Song Date: Fri, 2 Feb 2018 22:37:15 -0800 Subject: [PATCH 0997/1635] bpf: fix selftests/bpf test_kmod.sh failure when CONFIG_BPF_JIT_ALWAYS_ON=y [ Upstream commit 09584b406742413ac4c8d7e030374d4daa045b69 ] With CONFIG_BPF_JIT_ALWAYS_ON is defined in the config file, tools/testing/selftests/bpf/test_kmod.sh failed like below: [root@localhost bpf]# ./test_kmod.sh sysctl: setting key "net.core.bpf_jit_enable": Invalid argument [ JIT enabled:0 hardened:0 ] [ 132.175681] test_bpf: #297 BPF_MAXINSNS: Jump, gap, jump, ... FAIL to prog_create err=-524 len=4096 [ 132.458834] test_bpf: Summary: 348 PASSED, 1 FAILED, [340/340 JIT'ed] [ JIT enabled:1 hardened:0 ] [ 133.456025] test_bpf: #297 BPF_MAXINSNS: Jump, gap, jump, ... FAIL to prog_create err=-524 len=4096 [ 133.730935] test_bpf: Summary: 348 PASSED, 1 FAILED, [340/340 JIT'ed] [ JIT enabled:1 hardened:1 ] [ 134.769730] test_bpf: #297 BPF_MAXINSNS: Jump, gap, jump, ... FAIL to prog_create err=-524 len=4096 [ 135.050864] test_bpf: Summary: 348 PASSED, 1 FAILED, [340/340 JIT'ed] [ JIT enabled:1 hardened:2 ] [ 136.442882] test_bpf: #297 BPF_MAXINSNS: Jump, gap, jump, ... FAIL to prog_create err=-524 len=4096 [ 136.821810] test_bpf: Summary: 348 PASSED, 1 FAILED, [340/340 JIT'ed] [root@localhost bpf]# The test_kmod.sh load/remove test_bpf.ko multiple times with different settings for sysctl net.core.bpf_jit_{enable,harden}. The failed test #297 of test_bpf.ko is designed such that JIT always fails. Commit 290af86629b2 (bpf: introduce BPF_JIT_ALWAYS_ON config) introduced the following tightening logic: ... if (!bpf_prog_is_dev_bound(fp->aux)) { fp = bpf_int_jit_compile(fp); #ifdef CONFIG_BPF_JIT_ALWAYS_ON if (!fp->jited) { *err = -ENOTSUPP; return fp; } #endif ... With this logic, Test #297 always gets return value -ENOTSUPP when CONFIG_BPF_JIT_ALWAYS_ON is defined, causing the test failure. This patch fixed the failure by marking Test #297 as expected failure when CONFIG_BPF_JIT_ALWAYS_ON is defined. Fixes: 290af86629b2 (bpf: introduce BPF_JIT_ALWAYS_ON config) Signed-off-by: Yonghong Song Signed-off-by: Daniel Borkmann Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- lib/test_bpf.c | 31 ++++++++++++++++++++++++++----- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/lib/test_bpf.c b/lib/test_bpf.c index 6fbb73f3f531..64701b4c9900 100644 --- a/lib/test_bpf.c +++ b/lib/test_bpf.c @@ -83,6 +83,7 @@ struct bpf_test { __u32 result; } test[MAX_SUBTESTS]; int (*fill_helper)(struct bpf_test *self); + int expected_errcode; /* used when FLAG_EXPECTED_FAIL is set in the aux */ __u8 frag_data[MAX_DATA]; int stack_depth; /* for eBPF only, since tests don't call verifier */ }; @@ -1987,7 +1988,9 @@ static struct bpf_test tests[] = { }, CLASSIC | FLAG_NO_DATA | FLAG_EXPECTED_FAIL, { }, - { } + { }, + .fill_helper = NULL, + .expected_errcode = -EINVAL, }, { "check: div_k_0", @@ -1997,7 +2000,9 @@ static struct bpf_test tests[] = { }, CLASSIC | FLAG_NO_DATA | FLAG_EXPECTED_FAIL, { }, - { } + { }, + .fill_helper = NULL, + .expected_errcode = -EINVAL, }, { "check: unknown insn", @@ -2008,7 +2013,9 @@ static struct bpf_test tests[] = { }, CLASSIC | FLAG_EXPECTED_FAIL, { }, - { } + { }, + .fill_helper = NULL, + .expected_errcode = -EINVAL, }, { "check: out of range spill/fill", @@ -2018,7 +2025,9 @@ static struct bpf_test tests[] = { }, CLASSIC | FLAG_NO_DATA | FLAG_EXPECTED_FAIL, { }, - { } + { }, + .fill_helper = NULL, + .expected_errcode = -EINVAL, }, { "JUMPS + HOLES", @@ -2110,6 +2119,8 @@ static struct bpf_test tests[] = { CLASSIC | FLAG_NO_DATA | FLAG_EXPECTED_FAIL, { }, { }, + .fill_helper = NULL, + .expected_errcode = -EINVAL, }, { "check: LDX + RET X", @@ -2120,6 +2131,8 @@ static struct bpf_test tests[] = { CLASSIC | FLAG_NO_DATA | FLAG_EXPECTED_FAIL, { }, { }, + .fill_helper = NULL, + .expected_errcode = -EINVAL, }, { /* Mainly checking JIT here. */ "M[]: alt STX + LDX", @@ -2294,6 +2307,8 @@ static struct bpf_test tests[] = { CLASSIC | FLAG_NO_DATA | FLAG_EXPECTED_FAIL, { }, { }, + .fill_helper = NULL, + .expected_errcode = -EINVAL, }, { /* Passes checker but fails during runtime. */ "LD [SKF_AD_OFF-1]", @@ -5356,6 +5371,7 @@ static struct bpf_test tests[] = { { }, { }, .fill_helper = bpf_fill_maxinsns4, + .expected_errcode = -EINVAL, }, { /* Mainly checking JIT here. */ "BPF_MAXINSNS: Very long jump", @@ -5411,10 +5427,15 @@ static struct bpf_test tests[] = { { "BPF_MAXINSNS: Jump, gap, jump, ...", { }, +#ifdef CONFIG_BPF_JIT_ALWAYS_ON + CLASSIC | FLAG_NO_DATA | FLAG_EXPECTED_FAIL, +#else CLASSIC | FLAG_NO_DATA, +#endif { }, { { 0, 0xababcbac } }, .fill_helper = bpf_fill_maxinsns11, + .expected_errcode = -ENOTSUPP, }, { "BPF_MAXINSNS: ld_abs+get_processor_id", @@ -6193,7 +6214,7 @@ static struct bpf_prog *generate_filter(int which, int *err) *err = bpf_prog_create(&fp, &fprog); if (tests[which].aux & FLAG_EXPECTED_FAIL) { - if (*err == -EINVAL) { + if (*err == tests[which].expected_errcode) { pr_cont("PASS\n"); /* Verifier rejected filter as expected. */ *err = 0; -- GitLab From f938c2acc829689a29f3b1b2aa123285c31b2c67 Mon Sep 17 00:00:00 2001 From: Matt Redfearn Date: Mon, 29 Jan 2018 11:26:45 +0000 Subject: [PATCH 0998/1635] MIPS: TXx9: use IS_BUILTIN() for CONFIG_LEDS_CLASS [ Upstream commit 0cde5b44a30f1daaef1c34e08191239dc63271c4 ] When commit b27311e1cace ("MIPS: TXx9: Add RBTX4939 board support") added board support for the RBTX4939, it added a call to led_classdev_register even if the LED class is built as a module. Built-in arch code cannot call module code directly like this. Commit b33b44073734 ("MIPS: TXX9: use IS_ENABLED() macro") subsequently changed the inclusion of this code to a single check that CONFIG_LEDS_CLASS is either builtin or a module, but the same issue remains. This leads to MIPS allmodconfig builds failing when CONFIG_MACH_TX49XX=y is set: arch/mips/txx9/rbtx4939/setup.o: In function `rbtx4939_led_probe': setup.c:(.init.text+0xc0): undefined reference to `of_led_classdev_register' make: *** [Makefile:999: vmlinux] Error 1 Fix this by using the IS_BUILTIN() macro instead. Fixes: b27311e1cace ("MIPS: TXx9: Add RBTX4939 board support") Signed-off-by: Matt Redfearn Reviewed-by: James Hogan Cc: Ralf Baechle Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/18544/ Signed-off-by: James Hogan Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/mips/txx9/rbtx4939/setup.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/mips/txx9/rbtx4939/setup.c b/arch/mips/txx9/rbtx4939/setup.c index 8b937300fb7f..fd26fadc8617 100644 --- a/arch/mips/txx9/rbtx4939/setup.c +++ b/arch/mips/txx9/rbtx4939/setup.c @@ -186,7 +186,7 @@ static void __init rbtx4939_update_ioc_pen(void) #define RBTX4939_MAX_7SEGLEDS 8 -#if IS_ENABLED(CONFIG_LEDS_CLASS) +#if IS_BUILTIN(CONFIG_LEDS_CLASS) static u8 led_val[RBTX4939_MAX_7SEGLEDS]; struct rbtx4939_led_data { struct led_classdev cdev; @@ -261,7 +261,7 @@ static inline void rbtx4939_led_setup(void) static void __rbtx4939_7segled_putc(unsigned int pos, unsigned char val) { -#if IS_ENABLED(CONFIG_LEDS_CLASS) +#if IS_BUILTIN(CONFIG_LEDS_CLASS) unsigned long flags; local_irq_save(flags); /* bit7: reserved for LED class */ -- GitLab From 76e3ea2f95632d23aa12e954940c69e32544330b Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Thu, 1 Feb 2018 09:38:11 +0100 Subject: [PATCH 0999/1635] perf record: Fix period option handling [ Upstream commit f290aa1ffa45ed7e37599840878b4dae68269ee1 ] Stephan reported we don't unset PERIOD sample type when --no-period is specified. Adding the unset check and reset PERIOD if --no-period is specified. Committer notes: Check the sample_type, it shouldn't have PERF_SAMPLE_PERIOD there when --no-period is used. Before: # perf record --no-period sleep 1 [ perf record: Woken up 1 times to write data ] [ perf record: Captured and wrote 0.018 MB perf.data (7 samples) ] # perf evlist -v cycles:ppp: size: 112, { sample_period, sample_freq }: 4000, sample_type: IP|TID|TIME|PERIOD, disabled: 1, inherit: 1, mmap: 1, comm: 1, freq: 1, enable_on_exec: 1, task: 1, precise_ip: 3, sample_id_all: 1, exclude_guest: 1, mmap2: 1, comm_exec: 1 # After: [root@jouet ~]# perf record --no-period sleep 1 [ perf record: Woken up 1 times to write data ] [ perf record: Captured and wrote 0.019 MB perf.data (17 samples) ] [root@jouet ~]# perf evlist -v cycles:ppp: size: 112, { sample_period, sample_freq }: 4000, sample_type: IP|TID|TIME, disabled: 1, inherit: 1, mmap: 1, comm: 1, freq: 1, enable_on_exec: 1, task: 1, precise_ip: 3, sample_id_all: 1, exclude_guest: 1, mmap2: 1, comm_exec: 1 [root@jouet ~]# Reported-by: Stephane Eranian Signed-off-by: Jiri Olsa Tested-by: Arnaldo Carvalho de Melo Tested-by: Stephane Eranian Cc: Alexander Shishkin Cc: Andi Kleen Cc: David Ahern Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/20180201083812.11359-3-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- tools/perf/builtin-record.c | 3 ++- tools/perf/perf.h | 1 + tools/perf/util/evsel.c | 11 ++++++++--- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 1957abc1c8cf..b205c1340456 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -1611,7 +1611,8 @@ static struct option __record_options[] = { OPT_BOOLEAN_SET('T', "timestamp", &record.opts.sample_time, &record.opts.sample_time_set, "Record the sample timestamps"), - OPT_BOOLEAN('P', "period", &record.opts.period, "Record the sample period"), + OPT_BOOLEAN_SET('P', "period", &record.opts.period, &record.opts.period_set, + "Record the sample period"), OPT_BOOLEAN('n', "no-samples", &record.opts.no_samples, "don't sample"), OPT_BOOLEAN_SET('N', "no-buildid-cache", &record.no_buildid_cache, diff --git a/tools/perf/perf.h b/tools/perf/perf.h index f75f3dec7485..55086389fc06 100644 --- a/tools/perf/perf.h +++ b/tools/perf/perf.h @@ -50,6 +50,7 @@ struct record_opts { bool sample_time_set; bool sample_cpu; bool period; + bool period_set; bool running_time; bool full_auxtrace; bool auxtrace_snapshot_mode; diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index 2ffac0a477e5..e9f08327a34e 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c @@ -943,9 +943,6 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts, if (target__has_cpu(&opts->target) || opts->sample_cpu) perf_evsel__set_sample_bit(evsel, CPU); - if (opts->period) - perf_evsel__set_sample_bit(evsel, PERIOD); - /* * When the user explicitly disabled time don't force it here. */ @@ -1047,6 +1044,14 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts, apply_config_terms(evsel, opts); evsel->ignore_missing_thread = opts->ignore_missing_thread; + + /* The --period option takes the precedence. */ + if (opts->period_set) { + if (opts->period) + perf_evsel__set_sample_bit(evsel, PERIOD); + else + perf_evsel__reset_sample_bit(evsel, PERIOD); + } } static int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads) -- GitLab From b1f9f9fb3f99d8942991aa5976de73fd865937ec Mon Sep 17 00:00:00 2001 From: Matt Redfearn Date: Fri, 5 Jan 2018 10:31:07 +0000 Subject: [PATCH 1000/1635] MIPS: Generic: Support GIC in EIC mode [ Upstream commit 7bf8b16d1b60419c865e423b907a05f413745b3e ] The GIC supports running in External Interrupt Controller (EIC) mode, and will signal this via cpu_has_veic if enabled in hardware. Currently the generic kernel will panic if cpu_has_veic is set - but the GIC can legitimately set this flag if either configured to boot in EIC mode, or if the GIC driver enables this mode. Make the kernel not panic in this case, and instead just check if the GIC is present. If so, use it's CPU local interrupt routing functions. If an EIC is present, but it is not the GIC, then the kernel does not know how to get the VIRQ for the CPU local interrupts and should panic. Support for alternative EICs being present is needed here for the generic kernel to support them. Suggested-by: Paul Burton Signed-off-by: Matt Redfearn Cc: Ralf Baechle Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/18191/ Signed-off-by: James Hogan Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/mips/generic/irq.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/arch/mips/generic/irq.c b/arch/mips/generic/irq.c index 394f8161e462..cb7fdaeef426 100644 --- a/arch/mips/generic/irq.c +++ b/arch/mips/generic/irq.c @@ -22,10 +22,10 @@ int get_c0_fdc_int(void) { int mips_cpu_fdc_irq; - if (cpu_has_veic) - panic("Unimplemented!"); - else if (mips_gic_present()) + if (mips_gic_present()) mips_cpu_fdc_irq = gic_get_c0_fdc_int(); + else if (cpu_has_veic) + panic("Unimplemented!"); else if (cp0_fdc_irq >= 0) mips_cpu_fdc_irq = MIPS_CPU_IRQ_BASE + cp0_fdc_irq; else @@ -38,10 +38,10 @@ int get_c0_perfcount_int(void) { int mips_cpu_perf_irq; - if (cpu_has_veic) - panic("Unimplemented!"); - else if (mips_gic_present()) + if (mips_gic_present()) mips_cpu_perf_irq = gic_get_c0_perfcount_int(); + else if (cpu_has_veic) + panic("Unimplemented!"); else if (cp0_perfcount_irq >= 0) mips_cpu_perf_irq = MIPS_CPU_IRQ_BASE + cp0_perfcount_irq; else @@ -54,10 +54,10 @@ unsigned int get_c0_compare_int(void) { int mips_cpu_timer_irq; - if (cpu_has_veic) - panic("Unimplemented!"); - else if (mips_gic_present()) + if (mips_gic_present()) mips_cpu_timer_irq = gic_get_c0_compare_int(); + else if (cpu_has_veic) + panic("Unimplemented!"); else mips_cpu_timer_irq = MIPS_CPU_IRQ_BASE + cp0_compare_irq; -- GitLab From 2f79b5e52d46db124ad04c994ce0c2d43244de85 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Thu, 1 Feb 2018 09:38:10 +0100 Subject: [PATCH 1001/1635] perf evsel: Fix period/freq terms setup [ Upstream commit 49c0ae80eb32426fa133246200628e529067c595 ] Stephane reported that we don't set properly PERIOD sample type for events with period term defined. Before: $ perf record -e cpu/cpu-cycles,period=1000/u ls $ perf evlist -v cpu/cpu-cycles,period=1000/u: ... sample_type: IP|TID|TIME|PERIOD, ... After: $ perf record -e cpu/cpu-cycles,period=1000/u ls $ perf evlist -v cpu/cpu-cycles,period=1000/u: ... sample_type: IP|TID|TIME, ... Setting PERIOD sample type based on period term setup. Committer note: When we use -c or a period=N term in the event definition, then we don't need to ask the kernel, for this event, via perf_event_attr.sample_type |= PERF_SAMPLE_PERIOD, to put the event period in each sample for this event, as we know it already, it is in perf_event_attr.sample_period. Reported-by: Stephane Eranian Signed-off-by: Jiri Olsa Tested-by: Stephane Eranian Cc: Alexander Shishkin Cc: Andi Kleen Cc: David Ahern Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/20180201083812.11359-2-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- tools/perf/util/evsel.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index e9f08327a34e..226a9245d1db 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c @@ -736,12 +736,14 @@ static void apply_config_terms(struct perf_evsel *evsel, if (!(term->weak && opts->user_interval != ULLONG_MAX)) { attr->sample_period = term->val.period; attr->freq = 0; + perf_evsel__reset_sample_bit(evsel, PERIOD); } break; case PERF_EVSEL__CONFIG_TERM_FREQ: if (!(term->weak && opts->user_freq != UINT_MAX)) { attr->sample_freq = term->val.freq; attr->freq = 1; + perf_evsel__set_sample_bit(evsel, PERIOD); } break; case PERF_EVSEL__CONFIG_TERM_TIME: -- GitLab From 70f3461c23ffb394676cb53c2eb1095208a52327 Mon Sep 17 00:00:00 2001 From: Ross Lagerwall Date: Thu, 11 Jan 2018 09:36:38 +0000 Subject: [PATCH 1002/1635] xen-netfront: Fix race between device setup and open [ Upstream commit f599c64fdf7d9c108e8717fb04bc41c680120da4 ] When a netfront device is set up it registers a netdev fairly early on, before it has set up the queues and is actually usable. A userspace tool like NetworkManager will immediately try to open it and access its state as soon as it appears. The bug can be reproduced by hotplugging VIFs until the VM runs out of grant refs. It registers the netdev but fails to set up any queues (since there are no more grant refs). In the meantime, NetworkManager opens the device and the kernel crashes trying to access the queues (of which there are none). Fix this in two ways: * For initial setup, register the netdev much later, after the queues are setup. This avoids the race entirely. * During a suspend/resume cycle, the frontend reconnects to the backend and the queues are recreated. It is possible (though highly unlikely) to race with something opening the device and accessing the queues after they have been destroyed but before they have been recreated. Extend the region covered by the rtnl semaphore to protect against this race. There is a possibility that we fail to recreate the queues so check for this in the open function. Signed-off-by: Ross Lagerwall Reviewed-by: Boris Ostrovsky Signed-off-by: Juergen Gross Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/xen-netfront.c | 46 ++++++++++++++++++++------------------ 1 file changed, 24 insertions(+), 22 deletions(-) diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c index a9ba9fe263ca..f07b9c9bb5ba 100644 --- a/drivers/net/xen-netfront.c +++ b/drivers/net/xen-netfront.c @@ -351,6 +351,9 @@ static int xennet_open(struct net_device *dev) unsigned int i = 0; struct netfront_queue *queue = NULL; + if (!np->queues) + return -ENODEV; + for (i = 0; i < num_queues; ++i) { queue = &np->queues[i]; napi_enable(&queue->napi); @@ -1358,18 +1361,8 @@ static int netfront_probe(struct xenbus_device *dev, #ifdef CONFIG_SYSFS info->netdev->sysfs_groups[0] = &xennet_dev_group; #endif - err = register_netdev(info->netdev); - if (err) { - pr_warn("%s: register_netdev err=%d\n", __func__, err); - goto fail; - } return 0; - - fail: - xennet_free_netdev(netdev); - dev_set_drvdata(&dev->dev, NULL); - return err; } static void xennet_end_access(int ref, void *page) @@ -1738,8 +1731,6 @@ static void xennet_destroy_queues(struct netfront_info *info) { unsigned int i; - rtnl_lock(); - for (i = 0; i < info->netdev->real_num_tx_queues; i++) { struct netfront_queue *queue = &info->queues[i]; @@ -1748,8 +1739,6 @@ static void xennet_destroy_queues(struct netfront_info *info) netif_napi_del(&queue->napi); } - rtnl_unlock(); - kfree(info->queues); info->queues = NULL; } @@ -1765,8 +1754,6 @@ static int xennet_create_queues(struct netfront_info *info, if (!info->queues) return -ENOMEM; - rtnl_lock(); - for (i = 0; i < *num_queues; i++) { struct netfront_queue *queue = &info->queues[i]; @@ -1775,7 +1762,7 @@ static int xennet_create_queues(struct netfront_info *info, ret = xennet_init_queue(queue); if (ret < 0) { - dev_warn(&info->netdev->dev, + dev_warn(&info->xbdev->dev, "only created %d queues\n", i); *num_queues = i; break; @@ -1789,10 +1776,8 @@ static int xennet_create_queues(struct netfront_info *info, netif_set_real_num_tx_queues(info->netdev, *num_queues); - rtnl_unlock(); - if (*num_queues == 0) { - dev_err(&info->netdev->dev, "no queues\n"); + dev_err(&info->xbdev->dev, "no queues\n"); return -EINVAL; } return 0; @@ -1829,6 +1814,7 @@ static int talk_to_netback(struct xenbus_device *dev, goto out; } + rtnl_lock(); if (info->queues) xennet_destroy_queues(info); @@ -1839,6 +1825,7 @@ static int talk_to_netback(struct xenbus_device *dev, info->queues = NULL; goto out; } + rtnl_unlock(); /* Create shared ring, alloc event channel -- for each queue */ for (i = 0; i < num_queues; ++i) { @@ -1935,8 +1922,10 @@ static int talk_to_netback(struct xenbus_device *dev, xenbus_transaction_end(xbt, 1); destroy_ring: xennet_disconnect_backend(info); + rtnl_lock(); xennet_destroy_queues(info); out: + rtnl_unlock(); device_unregister(&dev->dev); return err; } @@ -1966,6 +1955,15 @@ static int xennet_connect(struct net_device *dev) netdev_update_features(dev); rtnl_unlock(); + if (dev->reg_state == NETREG_UNINITIALIZED) { + err = register_netdev(dev); + if (err) { + pr_warn("%s: register_netdev err=%d\n", __func__, err); + device_unregister(&np->xbdev->dev); + return err; + } + } + /* * All public and private state should now be sane. Get * ready to start sending and receiving packets and give the driver @@ -2156,10 +2154,14 @@ static int xennet_remove(struct xenbus_device *dev) xennet_disconnect_backend(info); - unregister_netdev(info->netdev); + if (info->netdev->reg_state == NETREG_REGISTERED) + unregister_netdev(info->netdev); - if (info->queues) + if (info->queues) { + rtnl_lock(); xennet_destroy_queues(info); + rtnl_unlock(); + } xennet_free_netdev(info->netdev); return 0; -- GitLab From 05c062c3685e227a22c96c93e1149fcad383ecbf Mon Sep 17 00:00:00 2001 From: Ross Lagerwall Date: Thu, 11 Jan 2018 09:36:37 +0000 Subject: [PATCH 1003/1635] xen/grant-table: Use put_page instead of free_page [ Upstream commit 3ac7292a25db1c607a50752055a18aba32ac2176 ] The page given to gnttab_end_foreign_access() to free could be a compound page so use put_page() instead of free_page() since it can handle both compound and single pages correctly. This bug was discovered when migrating a Xen VM with several VIFs and CONFIG_DEBUG_VM enabled. It hits a BUG usually after fewer than 10 iterations. All netfront devices disconnect from the backend during a suspend/resume and this will call gnttab_end_foreign_access() if a netfront queue has an outstanding skb. The mismatch between calling get_page() and free_page() on a compound page causes a reference counting error which is detected when DEBUG_VM is enabled. Signed-off-by: Ross Lagerwall Reviewed-by: Boris Ostrovsky Signed-off-by: Juergen Gross Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/xen/grant-table.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/xen/grant-table.c b/drivers/xen/grant-table.c index 2c6a9114d332..1fb374466e84 100644 --- a/drivers/xen/grant-table.c +++ b/drivers/xen/grant-table.c @@ -328,7 +328,7 @@ static void gnttab_handle_deferred(unsigned long unused) if (entry->page) { pr_debug("freeing g.e. %#x (pfn %#lx)\n", entry->ref, page_to_pfn(entry->page)); - __free_page(entry->page); + put_page(entry->page); } else pr_info("freeing g.e. %#x\n", entry->ref); kfree(entry); @@ -384,7 +384,7 @@ void gnttab_end_foreign_access(grant_ref_t ref, int readonly, if (gnttab_end_foreign_access_ref(ref, readonly)) { put_free_entry(ref); if (page != 0) - free_page(page); + put_page(virt_to_page(page)); } else gnttab_add_deferred(ref, readonly, page ? virt_to_page(page) : NULL); -- GitLab From a8e7a4e243747fdf64a459e0eb2e5091ffee9fe1 Mon Sep 17 00:00:00 2001 From: John Fastabend Date: Mon, 5 Feb 2018 10:17:54 -0800 Subject: [PATCH 1004/1635] bpf: sockmap, fix leaking maps with attached but not detached progs [ Upstream commit 3d9e952697de89b53227f06d4241f275eb99cfc4 ] When a program is attached to a map we increment the program refcnt to ensure that the program is not removed while it is potentially being referenced from sockmap side. However, if this same program also references the map (this is a reasonably common pattern in my programs) then the verifier will also increment the maps refcnt from the verifier. This is to ensure the map doesn't get garbage collected while the program has a reference to it. So we are left in a state where the map holds the refcnt on the program stopping it from being removed and releasing the map refcnt. And vice versa the program holds a refcnt on the map stopping it from releasing the refcnt on the prog. All this is fine as long as users detach the program while the map fd is still around. But, if the user omits this detach command we are left with a dangling map we can no longer release. To resolve this when the map fd is released decrement the program references and remove any reference from the map to the program. This fixes the issue with possibly dangling map and creates a user side API constraint. That is, the map fd must be held open for programs to be attached to a map. Fixes: 174a79ff9515 ("bpf: sockmap with sk redirect support") Signed-off-by: John Fastabend Signed-off-by: Daniel Borkmann Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- kernel/bpf/sockmap.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/kernel/bpf/sockmap.c b/kernel/bpf/sockmap.c index 1890be7ea9cd..53a4787c08d8 100644 --- a/kernel/bpf/sockmap.c +++ b/kernel/bpf/sockmap.c @@ -601,11 +601,6 @@ static void sock_map_free(struct bpf_map *map) } rcu_read_unlock(); - if (stab->bpf_verdict) - bpf_prog_put(stab->bpf_verdict); - if (stab->bpf_parse) - bpf_prog_put(stab->bpf_parse); - sock_map_remove_complete(stab); } @@ -877,6 +872,19 @@ static int sock_map_update_elem(struct bpf_map *map, return err; } +static void sock_map_release(struct bpf_map *map, struct file *map_file) +{ + struct bpf_stab *stab = container_of(map, struct bpf_stab, map); + struct bpf_prog *orig; + + orig = xchg(&stab->bpf_parse, NULL); + if (orig) + bpf_prog_put(orig); + orig = xchg(&stab->bpf_verdict, NULL); + if (orig) + bpf_prog_put(orig); +} + const struct bpf_map_ops sock_map_ops = { .map_alloc = sock_map_alloc, .map_free = sock_map_free, @@ -884,6 +892,7 @@ const struct bpf_map_ops sock_map_ops = { .map_get_next_key = sock_map_get_next_key, .map_update_elem = sock_map_update_elem, .map_delete_elem = sock_map_delete_elem, + .map_release = sock_map_release, }; BPF_CALL_4(bpf_sock_map_update, struct bpf_sock_ops_kern *, bpf_sock, -- GitLab From 693b9589c297e0b05359f62a6b8dc73289c0e3e4 Mon Sep 17 00:00:00 2001 From: Guanglei Li Date: Tue, 6 Feb 2018 10:43:21 +0800 Subject: [PATCH 1005/1635] RDS: IB: Fix null pointer issue [ Upstream commit 2c0aa08631b86a4678dbc93b9caa5248014b4458 ] Scenario: 1. Port down and do fail over 2. Ap do rds_bind syscall PID: 47039 TASK: ffff89887e2fe640 CPU: 47 COMMAND: "kworker/u:6" #0 [ffff898e35f159f0] machine_kexec at ffffffff8103abf9 #1 [ffff898e35f15a60] crash_kexec at ffffffff810b96e3 #2 [ffff898e35f15b30] oops_end at ffffffff8150f518 #3 [ffff898e35f15b60] no_context at ffffffff8104854c #4 [ffff898e35f15ba0] __bad_area_nosemaphore at ffffffff81048675 #5 [ffff898e35f15bf0] bad_area_nosemaphore at ffffffff810487d3 #6 [ffff898e35f15c00] do_page_fault at ffffffff815120b8 #7 [ffff898e35f15d10] page_fault at ffffffff8150ea95 [exception RIP: unknown or invalid address] RIP: 0000000000000000 RSP: ffff898e35f15dc8 RFLAGS: 00010282 RAX: 00000000fffffffe RBX: ffff889b77f6fc00 RCX:ffffffff81c99d88 RDX: 0000000000000000 RSI: ffff896019ee08e8 RDI:ffff889b77f6fc00 RBP: ffff898e35f15df0 R8: ffff896019ee08c8 R9:0000000000000000 R10: 0000000000000400 R11: 0000000000000000 R12:ffff896019ee08c0 R13: ffff889b77f6fe68 R14: ffffffff81c99d80 R15: ffffffffa022a1e0 ORIG_RAX: ffffffffffffffff CS: 0010 SS: 0018 #8 [ffff898e35f15dc8] cma_ndev_work_handler at ffffffffa022a228 [rdma_cm] #9 [ffff898e35f15df8] process_one_work at ffffffff8108a7c6 #10 [ffff898e35f15e58] worker_thread at ffffffff8108bda0 #11 [ffff898e35f15ee8] kthread at ffffffff81090fe6 PID: 45659 TASK: ffff880d313d2500 CPU: 31 COMMAND: "oracle_45659_ap" #0 [ffff881024ccfc98] __schedule at ffffffff8150bac4 #1 [ffff881024ccfd40] schedule at ffffffff8150c2cf #2 [ffff881024ccfd50] __mutex_lock_slowpath at ffffffff8150cee7 #3 [ffff881024ccfdc0] mutex_lock at ffffffff8150cdeb #4 [ffff881024ccfde0] rdma_destroy_id at ffffffffa022a027 [rdma_cm] #5 [ffff881024ccfe10] rds_ib_laddr_check at ffffffffa0357857 [rds_rdma] #6 [ffff881024ccfe50] rds_trans_get_preferred at ffffffffa0324c2a [rds] #7 [ffff881024ccfe80] rds_bind at ffffffffa031d690 [rds] #8 [ffff881024ccfeb0] sys_bind at ffffffff8142a670 PID: 45659 PID: 47039 rds_ib_laddr_check /* create id_priv with a null event_handler */ rdma_create_id rdma_bind_addr cma_acquire_dev /* add id_priv to cma_dev->id_list */ cma_attach_to_dev cma_ndev_work_handler /* event_hanlder is null */ id_priv->id.event_handler Signed-off-by: Guanglei Li Signed-off-by: Honglei Wang Reviewed-by: Junxiao Bi Reviewed-by: Yanjun Zhu Reviewed-by: Leon Romanovsky Acked-by: Santosh Shilimkar Acked-by: Doug Ledford Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- net/rds/ib.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/net/rds/ib.c b/net/rds/ib.c index a0954ace3774..c21eb4850b9d 100644 --- a/net/rds/ib.c +++ b/net/rds/ib.c @@ -346,7 +346,8 @@ static int rds_ib_laddr_check(struct net *net, __be32 addr) /* Create a CMA ID and try to bind it. This catches both * IB and iWARP capable NICs. */ - cm_id = rdma_create_id(&init_net, NULL, NULL, RDMA_PS_TCP, IB_QPT_RC); + cm_id = rdma_create_id(&init_net, rds_rdma_cm_event_handler, + NULL, RDMA_PS_TCP, IB_QPT_RC); if (IS_ERR(cm_id)) return PTR_ERR(cm_id); -- GitLab From 4ec317a41d80145de90bd320928da6916572b6f0 Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Wed, 31 Jan 2018 12:12:20 +0000 Subject: [PATCH 1006/1635] arm64: spinlock: Fix theoretical trylock() A-B-A with LSE atomics [ Upstream commit 202fb4ef81e3ec765c23bd1e6746a5c25b797d0e ] If the spinlock "next" ticket wraps around between the initial LDR and the cmpxchg in the LSE version of spin_trylock, then we can erroneously think that we have successfuly acquired the lock because we only check whether the next ticket return by the cmpxchg is equal to the owner ticket in our updated lock word. This patch fixes the issue by performing a full 32-bit check of the lock word when trying to determine whether or not the CASA instruction updated memory. Reported-by: Catalin Marinas Signed-off-by: Will Deacon Signed-off-by: Catalin Marinas Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/arm64/include/asm/spinlock.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm64/include/asm/spinlock.h b/arch/arm64/include/asm/spinlock.h index 95ad7102b63c..82375b896be5 100644 --- a/arch/arm64/include/asm/spinlock.h +++ b/arch/arm64/include/asm/spinlock.h @@ -89,8 +89,8 @@ static inline int arch_spin_trylock(arch_spinlock_t *lock) " cbnz %w1, 1f\n" " add %w1, %w0, %3\n" " casa %w0, %w1, %2\n" - " and %w1, %w1, #0xffff\n" - " eor %w1, %w1, %w0, lsr #16\n" + " sub %w1, %w1, %3\n" + " eor %w1, %w1, %w0\n" "1:") : "=&r" (lockval), "=&r" (tmp), "+Q" (*lock) : "I" (1 << TICKET_SHIFT) -- GitLab From 05e52e5bd103a335288415d5399cdb120a05a5e4 Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Tue, 6 Feb 2018 15:36:59 -0800 Subject: [PATCH 1007/1635] proc: fix /proc/*/map_files lookup [ Upstream commit ac7f1061c2c11bb8936b1b6a94cdb48de732f7a4 ] Current code does: if (sscanf(dentry->d_name.name, "%lx-%lx", start, end) != 2) However sscanf() is broken garbage. It silently accepts whitespace between format specifiers (did you know that?). It silently accepts valid strings which result in integer overflow. Do not use sscanf() for any even remotely reliable parsing code. OK # readlink '/proc/1/map_files/55a23af39000-55a23b05b000' /lib/systemd/systemd broken # readlink '/proc/1/map_files/ 55a23af39000-55a23b05b000' /lib/systemd/systemd broken # readlink '/proc/1/map_files/55a23af39000-55a23b05b000 ' /lib/systemd/systemd very broken # readlink '/proc/1/map_files/1000000000000000055a23af39000-55a23b05b000' /lib/systemd/systemd Andrei said: : This patch breaks criu. It was a bug in criu. And this bug is on a minor : path, which works when memfd_create() isn't available. It is a reason why : I ask to not backport this patch to stable kernels. : : In CRIU this bug can be triggered, only if this patch will be backported : to a kernel which version is lower than v3.16. Link: http://lkml.kernel.org/r/20171120212706.GA14325@avx2 Signed-off-by: Alexey Dobriyan Cc: Pavel Emelyanov Cc: Andrei Vagin Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- fs/proc/base.c | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/fs/proc/base.c b/fs/proc/base.c index 9d357b2ea6cb..2ff11a693360 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -100,6 +100,8 @@ #include "internal.h" #include "fd.h" +#include "../../lib/kstrtox.h" + /* NOTE: * Implementing inode permission operations in /proc is almost * certainly an error. Permission checks need to happen during @@ -1908,8 +1910,33 @@ bool proc_fill_cache(struct file *file, struct dir_context *ctx, static int dname_to_vma_addr(struct dentry *dentry, unsigned long *start, unsigned long *end) { - if (sscanf(dentry->d_name.name, "%lx-%lx", start, end) != 2) + const char *str = dentry->d_name.name; + unsigned long long sval, eval; + unsigned int len; + + len = _parse_integer(str, 16, &sval); + if (len & KSTRTOX_OVERFLOW) + return -EINVAL; + if (sval != (unsigned long)sval) + return -EINVAL; + str += len; + + if (*str != '-') return -EINVAL; + str++; + + len = _parse_integer(str, 16, &eval); + if (len & KSTRTOX_OVERFLOW) + return -EINVAL; + if (eval != (unsigned long)eval) + return -EINVAL; + str += len; + + if (*str != '\0') + return -EINVAL; + + *start = sval; + *end = eval; return 0; } -- GitLab From 4b95781cb6f37398e424e70e089e380f297693f5 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Tue, 23 Jan 2018 21:43:08 +0100 Subject: [PATCH 1008/1635] PM / domains: Fix up domain-idle-states OF parsing [ Upstream commit a3381e3a65cbaf612c8f584906c4dba27e84267c ] Commit b539cc82d493 (PM / Domains: Ignore domain-idle-states that are not compatible), made it possible to ignore non-compatible domain-idle-states OF nodes. However, in case that happens while doing the OF parsing, the number of elements in the allocated array would exceed the numbers actually needed, thus wasting memory. Fix this by pre-iterating the genpd OF node and counting the number of compatible domain-idle-states nodes, before doing the allocation. While doing this, it makes sense to rework the code a bit to avoid open coding, of parts responsible for the OF node iteration. Let's also take the opportunity to clarify the function header for of_genpd_parse_idle_states(), about what is being returned in case of errors. Fixes: b539cc82d493 (PM / Domains: Ignore domain-idle-states that are not compatible) Signed-off-by: Ulf Hansson Reviewed-by: Lina Iyer Signed-off-by: Rafael J. Wysocki Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/base/power/domain.c | 76 ++++++++++++++++++++++--------------- 1 file changed, 45 insertions(+), 31 deletions(-) diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c index 70f8904f46a3..b3b78079aa9f 100644 --- a/drivers/base/power/domain.c +++ b/drivers/base/power/domain.c @@ -2206,6 +2206,38 @@ static int genpd_parse_state(struct genpd_power_state *genpd_state, return 0; } +static int genpd_iterate_idle_states(struct device_node *dn, + struct genpd_power_state *states) +{ + int ret; + struct of_phandle_iterator it; + struct device_node *np; + int i = 0; + + ret = of_count_phandle_with_args(dn, "domain-idle-states", NULL); + if (ret <= 0) + return ret; + + /* Loop over the phandles until all the requested entry is found */ + of_for_each_phandle(&it, ret, dn, "domain-idle-states", NULL, 0) { + np = it.node; + if (!of_match_node(idle_state_match, np)) + continue; + if (states) { + ret = genpd_parse_state(&states[i], np); + if (ret) { + pr_err("Parsing idle state node %pOF failed with err %d\n", + np, ret); + of_node_put(np); + return ret; + } + } + i++; + } + + return i; +} + /** * of_genpd_parse_idle_states: Return array of idle states for the genpd. * @@ -2215,49 +2247,31 @@ static int genpd_parse_state(struct genpd_power_state *genpd_state, * * Returns the device states parsed from the OF node. The memory for the states * is allocated by this function and is the responsibility of the caller to - * free the memory after use. + * free the memory after use. If no domain idle states is found it returns + * -EINVAL and in case of errors, a negative error code. */ int of_genpd_parse_idle_states(struct device_node *dn, struct genpd_power_state **states, int *n) { struct genpd_power_state *st; - struct device_node *np; - int i = 0; - int err, ret; - int count; - struct of_phandle_iterator it; - const struct of_device_id *match_id; + int ret; - count = of_count_phandle_with_args(dn, "domain-idle-states", NULL); - if (count <= 0) - return -EINVAL; + ret = genpd_iterate_idle_states(dn, NULL); + if (ret <= 0) + return ret < 0 ? ret : -EINVAL; - st = kcalloc(count, sizeof(*st), GFP_KERNEL); + st = kcalloc(ret, sizeof(*st), GFP_KERNEL); if (!st) return -ENOMEM; - /* Loop over the phandles until all the requested entry is found */ - of_for_each_phandle(&it, err, dn, "domain-idle-states", NULL, 0) { - np = it.node; - match_id = of_match_node(idle_state_match, np); - if (!match_id) - continue; - ret = genpd_parse_state(&st[i++], np); - if (ret) { - pr_err - ("Parsing idle state node %pOF failed with err %d\n", - np, ret); - of_node_put(np); - kfree(st); - return ret; - } + ret = genpd_iterate_idle_states(dn, st); + if (ret <= 0) { + kfree(st); + return ret < 0 ? ret : -EINVAL; } - *n = i; - if (!i) - kfree(st); - else - *states = st; + *states = st; + *n = ret; return 0; } -- GitLab From 05921c492fdb6046e5a91a83dba3320701421902 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Fri, 2 Feb 2018 16:48:47 +0100 Subject: [PATCH 1009/1635] cifs: silence compiler warnings showing up with gcc-8.0.0 [ Upstream commit ade7db991b47ab3016a414468164f4966bd08202 ] This bug was fixed before, but came up again with the latest compiler in another function: fs/cifs/cifssmb.c: In function 'CIFSSMBSetEA': fs/cifs/cifssmb.c:6362:3: error: 'strncpy' offset 8 is out of the bounds [0, 4] [-Werror=array-bounds] strncpy(parm_data->list[0].name, ea_name, name_len); Let's apply the same fix that was used for the other instances. Fixes: b2a3ad9ca502 ("cifs: silence compiler warnings showing up with gcc-4.7.0") Signed-off-by: Arnd Bergmann Signed-off-by: Steve French Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- fs/cifs/cifssmb.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 35dc5bf01ee2..7fd39ea6e22e 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -6331,9 +6331,7 @@ CIFSSMBSetEA(const unsigned int xid, struct cifs_tcon *tcon, pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_EA); - parm_data = - (struct fealist *) (((char *) &pSMB->hdr.Protocol) + - offset); + parm_data = (void *)pSMB + offsetof(struct smb_hdr, Protocol) + offset; pSMB->ParameterOffset = cpu_to_le16(param_offset); pSMB->DataOffset = cpu_to_le16(offset); pSMB->SetupCount = 1; -- GitLab From f89edd17aff46a3970f302add6949700198dfd92 Mon Sep 17 00:00:00 2001 From: Coly Li Date: Wed, 7 Feb 2018 11:41:41 -0800 Subject: [PATCH 1010/1635] bcache: properly set task state in bch_writeback_thread() [ Upstream commit 99361bbf26337186f02561109c17a4c4b1a7536a ] Kernel thread routine bch_writeback_thread() has the following code block, 447 down_write(&dc->writeback_lock); 448~450 if (check conditions) { 451 up_write(&dc->writeback_lock); 452 set_current_state(TASK_INTERRUPTIBLE); 453 454 if (kthread_should_stop()) 455 return 0; 456 457 schedule(); 458 continue; 459 } If condition check is true, its task state is set to TASK_INTERRUPTIBLE and call schedule() to wait for others to wake up it. There are 2 issues in current code, 1, Task state is set to TASK_INTERRUPTIBLE after the condition checks, if another process changes the condition and call wake_up_process(dc-> writeback_thread), then at line 452 task state is set back to TASK_INTERRUPTIBLE, the writeback kernel thread will lose a chance to be waken up. 2, At line 454 if kthread_should_stop() is true, writeback kernel thread will return to kernel/kthread.c:kthread() with TASK_INTERRUPTIBLE and call do_exit(). It is not good to enter do_exit() with task state TASK_INTERRUPTIBLE, in following code path might_sleep() is called and a warning message is reported by __might_sleep(): "WARNING: do not call blocking ops when !TASK_RUNNING; state=1 set at [xxxx]". For the first issue, task state should be set before condition checks. Ineed because dc->writeback_lock is required when modifying all the conditions, calling set_current_state() inside code block where dc-> writeback_lock is hold is safe. But this is quite implicit, so I still move set_current_state() before all the condition checks. For the second issue, frankley speaking it does not hurt when kernel thread exits with TASK_INTERRUPTIBLE state, but this warning message scares users, makes them feel there might be something risky with bcache and hurt their data. Setting task state to TASK_RUNNING before returning fixes this problem. In alloc.c:allocator_wait(), there is also a similar issue, and is also fixed in this patch. Changelog: v3: merge two similar fixes into one patch v2: fix the race issue in v1 patch. v1: initial buggy fix. Signed-off-by: Coly Li Reviewed-by: Hannes Reinecke Reviewed-by: Michael Lyle Cc: Michael Lyle Cc: Junhui Tang Signed-off-by: Jens Axboe Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/md/bcache/alloc.c | 4 +++- drivers/md/bcache/writeback.c | 7 +++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/drivers/md/bcache/alloc.c b/drivers/md/bcache/alloc.c index f0dc8e2aee65..8c13a9036d07 100644 --- a/drivers/md/bcache/alloc.c +++ b/drivers/md/bcache/alloc.c @@ -287,8 +287,10 @@ do { \ break; \ \ mutex_unlock(&(ca)->set->bucket_lock); \ - if (kthread_should_stop()) \ + if (kthread_should_stop()) { \ + set_current_state(TASK_RUNNING); \ return 0; \ + } \ \ schedule(); \ mutex_lock(&(ca)->set->bucket_lock); \ diff --git a/drivers/md/bcache/writeback.c b/drivers/md/bcache/writeback.c index 70454f2ad2fa..f046dedc59ab 100644 --- a/drivers/md/bcache/writeback.c +++ b/drivers/md/bcache/writeback.c @@ -420,18 +420,21 @@ static int bch_writeback_thread(void *arg) while (!kthread_should_stop()) { down_write(&dc->writeback_lock); + set_current_state(TASK_INTERRUPTIBLE); if (!atomic_read(&dc->has_dirty) || (!test_bit(BCACHE_DEV_DETACHING, &dc->disk.flags) && !dc->writeback_running)) { up_write(&dc->writeback_lock); - set_current_state(TASK_INTERRUPTIBLE); - if (kthread_should_stop()) + if (kthread_should_stop()) { + set_current_state(TASK_RUNNING); return 0; + } schedule(); continue; } + set_current_state(TASK_RUNNING); searched_full_index = refill_dirty(dc); -- GitLab From 311e31419b7240151de0cf7aa3f2d972ee103a5c Mon Sep 17 00:00:00 2001 From: Tang Junhui Date: Wed, 7 Feb 2018 11:41:43 -0800 Subject: [PATCH 1011/1635] bcache: fix for allocator and register thread race MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit 682811b3ce1a5a4e20d700939a9042f01dbc66c4 ] After long time running of random small IO writing, I reboot the machine, and after the machine power on, I found bcache got stuck, the stack is: [root@ceph153 ~]# cat /proc/2510/task/*/stack [] closure_sync+0x25/0x90 [bcache] [] bch_journal+0x118/0x2b0 [bcache] [] bch_journal_meta+0x47/0x70 [bcache] [] bch_prio_write+0x237/0x340 [bcache] [] bch_allocator_thread+0x3c8/0x3d0 [bcache] [] kthread+0xcf/0xe0 [] ret_from_fork+0x58/0x90 [] 0xffffffffffffffff [root@ceph153 ~]# cat /proc/2038/task/*/stack [] __bch_btree_map_nodes+0x12d/0x150 [bcache] [] bch_btree_insert+0xf1/0x170 [bcache] [] bch_journal_replay+0x13f/0x230 [bcache] [] run_cache_set+0x79a/0x7c2 [bcache] [] register_bcache+0xd48/0x1310 [bcache] [] kobj_attr_store+0xf/0x20 [] sysfs_write_file+0xc6/0x140 [] vfs_write+0xbd/0x1e0 [] SyS_write+0x7f/0xe0 [] system_call_fastpath+0x16/0x1 The stack shows the register thread and allocator thread were getting stuck when registering cache device. I reboot the machine several times, the issue always exsit in this machine. I debug the code, and found the call trace as bellow: register_bcache() ==>run_cache_set() ==>bch_journal_replay() ==>bch_btree_insert() ==>__bch_btree_map_nodes() ==>btree_insert_fn() ==>btree_split() //node need split ==>btree_check_reserve() In btree_check_reserve(), It will check if there is enough buckets of RESERVE_BTREE type, since allocator thread did not work yet, so no buckets of RESERVE_BTREE type allocated, so the register thread waits on c->btree_cache_wait, and goes to sleep. Then the allocator thread initialized, the call trace is bellow: bch_allocator_thread() ==>bch_prio_write() ==>bch_journal_meta() ==>bch_journal() ==>journal_wait_for_write() In journal_wait_for_write(), It will check if journal is full by journal_full(), but the long time random small IO writing causes the exhaustion of journal buckets(journal.blocks_free=0), In order to release the journal buckets, the allocator calls btree_flush_write() to flush keys to btree nodes, and waits on c->journal.wait until btree nodes writing over or there has already some journal buckets space, then the allocator thread goes to sleep. but in btree_flush_write(), since bch_journal_replay() is not finished, so no btree nodes have journal (condition "if (btree_current_write(b)->journal)" never satisfied), so we got no btree node to flush, no journal bucket released, and allocator sleep all the times. Through the above analysis, we can see that: 1) Register thread wait for allocator thread to allocate buckets of RESERVE_BTREE type; 2) Alloctor thread wait for register thread to replay journal, so it can flush btree nodes and get journal bucket. then they are all got stuck by waiting for each other. Hua Rui provided a patch for me, by allocating some buckets of RESERVE_BTREE type in advance, so the register thread can get bucket when btree node splitting and no need to waiting for the allocator thread. I tested it, it has effect, and register thread run a step forward, but finally are still got stuck, the reason is only 8 bucket of RESERVE_BTREE type were allocated, and in bch_journal_replay(), after 2 btree nodes splitting, only 4 bucket of RESERVE_BTREE type left, then btree_check_reserve() is not satisfied anymore, so it goes to sleep again, and in the same time, alloctor thread did not flush enough btree nodes to release a journal bucket, so they all got stuck again. So we need to allocate more buckets of RESERVE_BTREE type in advance, but how much is enough? By experience and test, I think it should be as much as journal buckets. Then I modify the code as this patch, and test in the machine, and it works. This patch modified base on Hua Rui’s patch, and allocate more buckets of RESERVE_BTREE type in advance to avoid register thread and allocate thread going to wait for each other. [patch v2] ca->sb.njournal_buckets would be 0 in the first time after cache creation, and no journal exists, so just 8 btree buckets is OK. Signed-off-by: Hua Rui Signed-off-by: Tang Junhui Reviewed-by: Michael Lyle Signed-off-by: Jens Axboe Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/md/bcache/btree.c | 9 ++++++--- drivers/md/bcache/super.c | 13 ++++++++++++- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/drivers/md/bcache/btree.c b/drivers/md/bcache/btree.c index 1598d1e04989..89d088cf95d9 100644 --- a/drivers/md/bcache/btree.c +++ b/drivers/md/bcache/btree.c @@ -1868,14 +1868,17 @@ void bch_initial_gc_finish(struct cache_set *c) */ for_each_cache(ca, c, i) { for_each_bucket(b, ca) { - if (fifo_full(&ca->free[RESERVE_PRIO])) + if (fifo_full(&ca->free[RESERVE_PRIO]) && + fifo_full(&ca->free[RESERVE_BTREE])) break; if (bch_can_invalidate_bucket(ca, b) && !GC_MARK(b)) { __bch_invalidate_one_bucket(ca, b); - fifo_push(&ca->free[RESERVE_PRIO], - b - ca->buckets); + if (!fifo_push(&ca->free[RESERVE_PRIO], + b - ca->buckets)) + fifo_push(&ca->free[RESERVE_BTREE], + b - ca->buckets); } } } diff --git a/drivers/md/bcache/super.c b/drivers/md/bcache/super.c index 5d0430777dda..ff0737bdfde7 100644 --- a/drivers/md/bcache/super.c +++ b/drivers/md/bcache/super.c @@ -1829,6 +1829,7 @@ void bch_cache_release(struct kobject *kobj) static int cache_alloc(struct cache *ca) { size_t free; + size_t btree_buckets; struct bucket *b; __module_get(THIS_MODULE); @@ -1836,9 +1837,19 @@ static int cache_alloc(struct cache *ca) bio_init(&ca->journal.bio, ca->journal.bio.bi_inline_vecs, 8); + /* + * when ca->sb.njournal_buckets is not zero, journal exists, + * and in bch_journal_replay(), tree node may split, + * so bucket of RESERVE_BTREE type is needed, + * the worst situation is all journal buckets are valid journal, + * and all the keys need to replay, + * so the number of RESERVE_BTREE type buckets should be as much + * as journal buckets + */ + btree_buckets = ca->sb.njournal_buckets ?: 8; free = roundup_pow_of_two(ca->sb.nbuckets) >> 10; - if (!init_fifo(&ca->free[RESERVE_BTREE], 8, GFP_KERNEL) || + if (!init_fifo(&ca->free[RESERVE_BTREE], btree_buckets, GFP_KERNEL) || !init_fifo_exact(&ca->free[RESERVE_PRIO], prio_buckets(ca), GFP_KERNEL) || !init_fifo(&ca->free[RESERVE_MOVINGGC], free, GFP_KERNEL) || !init_fifo(&ca->free[RESERVE_NONE], free, GFP_KERNEL) || -- GitLab From 4c8e0270dc7afb10d4e06be4adfd177db5cb3cb8 Mon Sep 17 00:00:00 2001 From: Tang Junhui Date: Wed, 7 Feb 2018 11:41:46 -0800 Subject: [PATCH 1012/1635] bcache: fix for data collapse after re-attaching an attached device [ Upstream commit 73ac105be390c1de42a2f21643c9778a5e002930 ] back-end device sdm has already attached a cache_set with ID f67ebe1f-f8bc-4d73-bfe5-9dc88607f119, then try to attach with another cache set, and it returns with an error: [root]# cd /sys/block/sdm/bcache [root]# echo 5ccd0a63-148e-48b8-afa2-aca9cbd6279f > attach -bash: echo: write error: Invalid argument After that, execute a command to modify the label of bcache device: [root]# echo data_disk1 > label Then we reboot the system, when the system power on, the back-end device can not attach to cache_set, a messages show in the log: Feb 5 12:05:52 ceph152 kernel: [922385.508498] bcache: bch_cached_dev_attach() couldn't find uuid for sdm in set In sysfs_attach(), dc->sb.set_uuid was assigned to the value which input through sysfs, no matter whether it is success or not in bch_cached_dev_attach(). For example, If the back-end device has already attached to an cache set, bch_cached_dev_attach() would fail, but dc->sb.set_uuid was changed. Then modify the label of bcache device, it will call bch_write_bdev_super(), which would write the dc->sb.set_uuid to the super block, so we record a wrong cache set ID in the super block, after the system reboot, the cache set couldn't find the uuid of the back-end device, so the bcache device couldn't exist and use any more. In this patch, we don't assigned cache set ID to dc->sb.set_uuid in sysfs_attach() directly, but input it into bch_cached_dev_attach(), and assigned dc->sb.set_uuid to the cache set ID after the back-end device attached to the cache set successful. Signed-off-by: Tang Junhui Reviewed-by: Michael Lyle Signed-off-by: Jens Axboe Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/md/bcache/bcache.h | 2 +- drivers/md/bcache/super.c | 10 ++++++---- drivers/md/bcache/sysfs.c | 6 ++++-- 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/drivers/md/bcache/bcache.h b/drivers/md/bcache/bcache.h index abd31e847f96..e4a3f692057b 100644 --- a/drivers/md/bcache/bcache.h +++ b/drivers/md/bcache/bcache.h @@ -906,7 +906,7 @@ void bcache_write_super(struct cache_set *); int bch_flash_dev_create(struct cache_set *c, uint64_t size); -int bch_cached_dev_attach(struct cached_dev *, struct cache_set *); +int bch_cached_dev_attach(struct cached_dev *, struct cache_set *, uint8_t *); void bch_cached_dev_detach(struct cached_dev *); void bch_cached_dev_run(struct cached_dev *); void bcache_device_stop(struct bcache_device *); diff --git a/drivers/md/bcache/super.c b/drivers/md/bcache/super.c index ff0737bdfde7..fe6e4c319b7c 100644 --- a/drivers/md/bcache/super.c +++ b/drivers/md/bcache/super.c @@ -939,7 +939,8 @@ void bch_cached_dev_detach(struct cached_dev *dc) cached_dev_put(dc); } -int bch_cached_dev_attach(struct cached_dev *dc, struct cache_set *c) +int bch_cached_dev_attach(struct cached_dev *dc, struct cache_set *c, + uint8_t *set_uuid) { uint32_t rtime = cpu_to_le32(get_seconds()); struct uuid_entry *u; @@ -948,7 +949,8 @@ int bch_cached_dev_attach(struct cached_dev *dc, struct cache_set *c) bdevname(dc->bdev, buf); - if (memcmp(dc->sb.set_uuid, c->sb.set_uuid, 16)) + if ((set_uuid && memcmp(set_uuid, c->sb.set_uuid, 16)) || + (!set_uuid && memcmp(dc->sb.set_uuid, c->sb.set_uuid, 16))) return -ENOENT; if (dc->disk.c) { @@ -1190,7 +1192,7 @@ static void register_bdev(struct cache_sb *sb, struct page *sb_page, list_add(&dc->list, &uncached_devices); list_for_each_entry(c, &bch_cache_sets, list) - bch_cached_dev_attach(dc, c); + bch_cached_dev_attach(dc, c, NULL); if (BDEV_STATE(&dc->sb) == BDEV_STATE_NONE || BDEV_STATE(&dc->sb) == BDEV_STATE_STALE) @@ -1712,7 +1714,7 @@ static void run_cache_set(struct cache_set *c) bcache_write_super(c); list_for_each_entry_safe(dc, t, &uncached_devices, list) - bch_cached_dev_attach(dc, c); + bch_cached_dev_attach(dc, c, NULL); flash_devs_run(c); diff --git a/drivers/md/bcache/sysfs.c b/drivers/md/bcache/sysfs.c index 234b2f5b286d..6dd03cf9053b 100644 --- a/drivers/md/bcache/sysfs.c +++ b/drivers/md/bcache/sysfs.c @@ -265,11 +265,13 @@ STORE(__cached_dev) } if (attr == &sysfs_attach) { - if (bch_parse_uuid(buf, dc->sb.set_uuid) < 16) + uint8_t set_uuid[16]; + + if (bch_parse_uuid(buf, set_uuid) < 16) return -EINVAL; list_for_each_entry(c, &bch_cache_sets, list) { - v = bch_cached_dev_attach(dc, c); + v = bch_cached_dev_attach(dc, c, set_uuid); if (!v) return size; } -- GitLab From c4c9fd55899fd780ee010eda172fe574c65bf56e Mon Sep 17 00:00:00 2001 From: Tang Junhui Date: Wed, 7 Feb 2018 11:41:45 -0800 Subject: [PATCH 1013/1635] bcache: return attach error when no cache set exist [ Upstream commit 7f4fc93d4713394ee8f1cd44c238e046e11b4f15 ] I attach a back-end device to a cache set, and the cache set is not registered yet, this back-end device did not attach successfully, and no error returned: [root]# echo 87859280-fec6-4bcc-20df7ca8f86b > /sys/block/sde/bcache/attach [root]# In sysfs_attach(), the return value "v" is initialized to "size" in the beginning, and if no cache set exist in bch_cache_sets, the "v" value would not change any more, and return to sysfs, sysfs regard it as success since the "size" is a positive number. This patch fixes this issue by assigning "v" with "-ENOENT" in the initialization. Signed-off-by: Tang Junhui Reviewed-by: Michael Lyle Signed-off-by: Jens Axboe Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/md/bcache/sysfs.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/md/bcache/sysfs.c b/drivers/md/bcache/sysfs.c index 6dd03cf9053b..5d81cd06af00 100644 --- a/drivers/md/bcache/sysfs.c +++ b/drivers/md/bcache/sysfs.c @@ -193,7 +193,7 @@ STORE(__cached_dev) { struct cached_dev *dc = container_of(kobj, struct cached_dev, disk.kobj); - ssize_t v = size; + ssize_t v; struct cache_set *c; struct kobj_uevent_env *env; @@ -270,6 +270,7 @@ STORE(__cached_dev) if (bch_parse_uuid(buf, set_uuid) < 16) return -EINVAL; + v = -ENOENT; list_for_each_entry(c, &bch_cache_sets, list) { v = bch_cached_dev_attach(dc, c, set_uuid); if (!v) @@ -277,7 +278,7 @@ STORE(__cached_dev) } pr_err("Can't attach %s: cache set not found", buf); - size = v; + return v; } if (attr == &sysfs_detach && dc->disk.c) -- GitLab From ae9c78af577f3741357851e6e98223d67f07d4a6 Mon Sep 17 00:00:00 2001 From: Chen Yu Date: Mon, 29 Jan 2018 10:27:57 +0800 Subject: [PATCH 1014/1635] cpufreq: intel_pstate: Enable HWP during system resume on CPU0 [ Upstream commit 70f6bf2a3b7e40c3f802b0ea837762a8bc6c1430 ] When maxcpus=1 is in the kernel command line, the BP is responsible for re-enabling the HWP - because currently only the APs invoke intel_pstate_hwp_enable() during their online process - which might put the system into unstable state after resume. Fix this by enabling the HWP explicitly on BP during resume. Reported-by: Doug Smythies Suggested-by: Srinivas Pandruvada Signed-off-by: Yu Chen [ rjw: Subject/changelog, minor modifications ] Signed-off-by: Rafael J. Wysocki Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/cpufreq/intel_pstate.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c index 93a0e88bef76..20226d4243f2 100644 --- a/drivers/cpufreq/intel_pstate.c +++ b/drivers/cpufreq/intel_pstate.c @@ -779,6 +779,8 @@ static int intel_pstate_hwp_save_state(struct cpufreq_policy *policy) return 0; } +static void intel_pstate_hwp_enable(struct cpudata *cpudata); + static int intel_pstate_resume(struct cpufreq_policy *policy) { if (!hwp_active) @@ -786,6 +788,9 @@ static int intel_pstate_resume(struct cpufreq_policy *policy) mutex_lock(&intel_pstate_limits_lock); + if (policy->cpu == 0) + intel_pstate_hwp_enable(all_cpu_data[policy->cpu]); + all_cpu_data[policy->cpu]->epp_policy = 0; intel_pstate_hwp_set(policy->cpu); -- GitLab From c5ce9e5b57cc24142e38b6441c23e0e8bac4ef54 Mon Sep 17 00:00:00 2001 From: "Steven Rostedt (VMware)" Date: Tue, 6 Feb 2018 17:19:03 -0500 Subject: [PATCH 1015/1635] selftests/ftrace: Add some missing glob checks [ Upstream commit 97fe22adf33f06519bfdf7dad33bcd562e366c8f ] Al Viro discovered a bug in the glob ftrace filtering code where "*a*b" is treated the same as "a*b", and functions that would be selected by "*a*b" but not "a*b" are not selected with "*a*b". Add tests for patterns "*a*b" and "a*b*" to the glob selftest. Link: http://lkml.kernel.org/r/20180127170748.GF13338@ZenIV.linux.org.uk Cc: Shuah Khan Acked-by: Masami Hiramatsu Signed-off-by: Steven Rostedt (VMware) Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- .../selftests/ftrace/test.d/ftrace/func-filter-glob.tc | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tools/testing/selftests/ftrace/test.d/ftrace/func-filter-glob.tc b/tools/testing/selftests/ftrace/test.d/ftrace/func-filter-glob.tc index 589d52b211b7..27a54a17da65 100644 --- a/tools/testing/selftests/ftrace/test.d/ftrace/func-filter-glob.tc +++ b/tools/testing/selftests/ftrace/test.d/ftrace/func-filter-glob.tc @@ -29,6 +29,12 @@ ftrace_filter_check '*schedule*' '^.*schedule.*$' # filter by *, end match ftrace_filter_check 'schedule*' '^schedule.*$' +# filter by *mid*end +ftrace_filter_check '*aw*lock' '.*aw.*lock$' + +# filter by start*mid* +ftrace_filter_check 'mutex*try*' '^mutex.*try.*' + # Advanced full-glob matching feature is recently supported. # Skip the tests if we are sure the kernel does not support it. if grep -q 'accepts: .* glob-matching-pattern' README ; then -- GitLab From e781fff7b78ffd1ae7149e8f5ac7512dab32cfa5 Mon Sep 17 00:00:00 2001 From: David Howells Date: Thu, 8 Feb 2018 15:59:07 +0000 Subject: [PATCH 1016/1635] rxrpc: Don't put crypto buffers on the stack [ Upstream commit 8c2f826dc36314059ac146c78d3bf8056b626446 ] Don't put buffers of data to be handed to crypto on the stack as this may cause an assertion failure in the kernel (see below). Fix this by using an kmalloc'd buffer instead. kernel BUG at ./include/linux/scatterlist.h:147! ... RIP: 0010:rxkad_encrypt_response.isra.6+0x191/0x1b0 [rxrpc] RSP: 0018:ffffbe2fc06cfca8 EFLAGS: 00010246 RAX: 0000000000000000 RBX: ffff989277d59900 RCX: 0000000000000028 RDX: 0000259dc06cfd88 RSI: 0000000000000025 RDI: ffffbe30406cfd88 RBP: ffffbe2fc06cfd60 R08: ffffbe2fc06cfd08 R09: ffffbe2fc06cfd08 R10: 0000000000000000 R11: 0000000000000000 R12: 1ffff7c5f80d9f95 R13: ffffbe2fc06cfd88 R14: ffff98927a3f7aa0 R15: ffffbe2fc06cfd08 FS: 0000000000000000(0000) GS:ffff98927fc00000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 000055b1ff28f0f8 CR3: 000000001b412003 CR4: 00000000003606f0 DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 Call Trace: rxkad_respond_to_challenge+0x297/0x330 [rxrpc] rxrpc_process_connection+0xd1/0x690 [rxrpc] ? process_one_work+0x1c3/0x680 ? __lock_is_held+0x59/0xa0 process_one_work+0x249/0x680 worker_thread+0x3a/0x390 ? process_one_work+0x680/0x680 kthread+0x121/0x140 ? kthread_create_worker_on_cpu+0x70/0x70 ret_from_fork+0x3a/0x50 Reported-by: Jonathan Billings Reported-by: Marc Dionne Signed-off-by: David Howells Tested-by: Jonathan Billings Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- net/rxrpc/conn_event.c | 1 + net/rxrpc/rxkad.c | 92 +++++++++++++++++++++++------------------- 2 files changed, 52 insertions(+), 41 deletions(-) diff --git a/net/rxrpc/conn_event.c b/net/rxrpc/conn_event.c index 59a51a56e7c8..0435c4167a1a 100644 --- a/net/rxrpc/conn_event.c +++ b/net/rxrpc/conn_event.c @@ -404,6 +404,7 @@ void rxrpc_process_connection(struct work_struct *work) case -EKEYEXPIRED: case -EKEYREJECTED: goto protocol_error; + case -ENOMEM: case -EAGAIN: goto requeue_and_leave; case -ECONNABORTED: diff --git a/net/rxrpc/rxkad.c b/net/rxrpc/rxkad.c index c38b3a1de56c..77cb23c7bd0a 100644 --- a/net/rxrpc/rxkad.c +++ b/net/rxrpc/rxkad.c @@ -773,8 +773,7 @@ static int rxkad_respond_to_challenge(struct rxrpc_connection *conn, { const struct rxrpc_key_token *token; struct rxkad_challenge challenge; - struct rxkad_response resp - __attribute__((aligned(8))); /* must be aligned for crypto */ + struct rxkad_response *resp; struct rxrpc_skb_priv *sp = rxrpc_skb(skb); const char *eproto; u32 version, nonce, min_level, abort_code; @@ -818,26 +817,29 @@ static int rxkad_respond_to_challenge(struct rxrpc_connection *conn, token = conn->params.key->payload.data[0]; /* build the response packet */ - memset(&resp, 0, sizeof(resp)); - - resp.version = htonl(RXKAD_VERSION); - resp.encrypted.epoch = htonl(conn->proto.epoch); - resp.encrypted.cid = htonl(conn->proto.cid); - resp.encrypted.securityIndex = htonl(conn->security_ix); - resp.encrypted.inc_nonce = htonl(nonce + 1); - resp.encrypted.level = htonl(conn->params.security_level); - resp.kvno = htonl(token->kad->kvno); - resp.ticket_len = htonl(token->kad->ticket_len); - - resp.encrypted.call_id[0] = htonl(conn->channels[0].call_counter); - resp.encrypted.call_id[1] = htonl(conn->channels[1].call_counter); - resp.encrypted.call_id[2] = htonl(conn->channels[2].call_counter); - resp.encrypted.call_id[3] = htonl(conn->channels[3].call_counter); + resp = kzalloc(sizeof(struct rxkad_response), GFP_NOFS); + if (!resp) + return -ENOMEM; + + resp->version = htonl(RXKAD_VERSION); + resp->encrypted.epoch = htonl(conn->proto.epoch); + resp->encrypted.cid = htonl(conn->proto.cid); + resp->encrypted.securityIndex = htonl(conn->security_ix); + resp->encrypted.inc_nonce = htonl(nonce + 1); + resp->encrypted.level = htonl(conn->params.security_level); + resp->kvno = htonl(token->kad->kvno); + resp->ticket_len = htonl(token->kad->ticket_len); + resp->encrypted.call_id[0] = htonl(conn->channels[0].call_counter); + resp->encrypted.call_id[1] = htonl(conn->channels[1].call_counter); + resp->encrypted.call_id[2] = htonl(conn->channels[2].call_counter); + resp->encrypted.call_id[3] = htonl(conn->channels[3].call_counter); /* calculate the response checksum and then do the encryption */ - rxkad_calc_response_checksum(&resp); - rxkad_encrypt_response(conn, &resp, token->kad); - return rxkad_send_response(conn, &sp->hdr, &resp, token->kad); + rxkad_calc_response_checksum(resp); + rxkad_encrypt_response(conn, resp, token->kad); + ret = rxkad_send_response(conn, &sp->hdr, resp, token->kad); + kfree(resp); + return ret; protocol_error: trace_rxrpc_rx_eproto(NULL, sp->hdr.serial, eproto); @@ -1048,8 +1050,7 @@ static int rxkad_verify_response(struct rxrpc_connection *conn, struct sk_buff *skb, u32 *_abort_code) { - struct rxkad_response response - __attribute__((aligned(8))); /* must be aligned for crypto */ + struct rxkad_response *response; struct rxrpc_skb_priv *sp = rxrpc_skb(skb); struct rxrpc_crypt session_key; const char *eproto; @@ -1061,17 +1062,22 @@ static int rxkad_verify_response(struct rxrpc_connection *conn, _enter("{%d,%x}", conn->debug_id, key_serial(conn->server_key)); + ret = -ENOMEM; + response = kzalloc(sizeof(struct rxkad_response), GFP_NOFS); + if (!response) + goto temporary_error; + eproto = tracepoint_string("rxkad_rsp_short"); abort_code = RXKADPACKETSHORT; if (skb_copy_bits(skb, sizeof(struct rxrpc_wire_header), - &response, sizeof(response)) < 0) + response, sizeof(*response)) < 0) goto protocol_error; - if (!pskb_pull(skb, sizeof(response))) + if (!pskb_pull(skb, sizeof(*response))) BUG(); - version = ntohl(response.version); - ticket_len = ntohl(response.ticket_len); - kvno = ntohl(response.kvno); + version = ntohl(response->version); + ticket_len = ntohl(response->ticket_len); + kvno = ntohl(response->kvno); _proto("Rx RESPONSE %%%u { v=%u kv=%u tl=%u }", sp->hdr.serial, version, kvno, ticket_len); @@ -1105,31 +1111,31 @@ static int rxkad_verify_response(struct rxrpc_connection *conn, ret = rxkad_decrypt_ticket(conn, skb, ticket, ticket_len, &session_key, &expiry, _abort_code); if (ret < 0) - goto temporary_error_free; + goto temporary_error_free_resp; /* use the session key from inside the ticket to decrypt the * response */ - rxkad_decrypt_response(conn, &response, &session_key); + rxkad_decrypt_response(conn, response, &session_key); eproto = tracepoint_string("rxkad_rsp_param"); abort_code = RXKADSEALEDINCON; - if (ntohl(response.encrypted.epoch) != conn->proto.epoch) + if (ntohl(response->encrypted.epoch) != conn->proto.epoch) goto protocol_error_free; - if (ntohl(response.encrypted.cid) != conn->proto.cid) + if (ntohl(response->encrypted.cid) != conn->proto.cid) goto protocol_error_free; - if (ntohl(response.encrypted.securityIndex) != conn->security_ix) + if (ntohl(response->encrypted.securityIndex) != conn->security_ix) goto protocol_error_free; - csum = response.encrypted.checksum; - response.encrypted.checksum = 0; - rxkad_calc_response_checksum(&response); + csum = response->encrypted.checksum; + response->encrypted.checksum = 0; + rxkad_calc_response_checksum(response); eproto = tracepoint_string("rxkad_rsp_csum"); - if (response.encrypted.checksum != csum) + if (response->encrypted.checksum != csum) goto protocol_error_free; spin_lock(&conn->channel_lock); for (i = 0; i < RXRPC_MAXCALLS; i++) { struct rxrpc_call *call; - u32 call_id = ntohl(response.encrypted.call_id[i]); + u32 call_id = ntohl(response->encrypted.call_id[i]); eproto = tracepoint_string("rxkad_rsp_callid"); if (call_id > INT_MAX) @@ -1153,12 +1159,12 @@ static int rxkad_verify_response(struct rxrpc_connection *conn, eproto = tracepoint_string("rxkad_rsp_seq"); abort_code = RXKADOUTOFSEQUENCE; - if (ntohl(response.encrypted.inc_nonce) != conn->security_nonce + 1) + if (ntohl(response->encrypted.inc_nonce) != conn->security_nonce + 1) goto protocol_error_free; eproto = tracepoint_string("rxkad_rsp_level"); abort_code = RXKADLEVELFAIL; - level = ntohl(response.encrypted.level); + level = ntohl(response->encrypted.level); if (level > RXRPC_SECURITY_ENCRYPT) goto protocol_error_free; conn->params.security_level = level; @@ -1168,9 +1174,10 @@ static int rxkad_verify_response(struct rxrpc_connection *conn, * as for a client connection */ ret = rxrpc_get_server_data_key(conn, &session_key, expiry, kvno); if (ret < 0) - goto temporary_error_free; + goto temporary_error_free_ticket; kfree(ticket); + kfree(response); _leave(" = 0"); return 0; @@ -1179,12 +1186,15 @@ static int rxkad_verify_response(struct rxrpc_connection *conn, protocol_error_free: kfree(ticket); protocol_error: + kfree(response); trace_rxrpc_rx_eproto(NULL, sp->hdr.serial, eproto); *_abort_code = abort_code; return -EPROTO; -temporary_error_free: +temporary_error_free_ticket: kfree(ticket); +temporary_error_free_resp: + kfree(response); temporary_error: /* Ignore the response packet if we got a temporary error such as * ENOMEM. We just want to send the challenge again. Note that we -- GitLab From 0b1fa241dd86820659cb477caa73e3c232d344e2 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Fri, 2 Feb 2018 14:28:59 -0500 Subject: [PATCH 1017/1635] svcrdma: Fix Read chunk round-up [ Upstream commit 175e03101d36c3034f3c80038d4c28838351a7f2 ] A single NFSv4 WRITE compound can often have three operations: PUTFH, WRITE, then GETATTR. When the WRITE payload is sent in a Read chunk, the client places the GETATTR in the inline part of the RPC/RDMA message, just after the WRITE operation (sans payload). The position value in the Read chunk enables the receiver to insert the Read chunk at the correct place in the received XDR stream; that is between the WRITE and GETATTR. According to RFC 8166, an NFS/RDMA client does not have to add XDR round-up to the Read chunk that carries the WRITE payload. The receiver adds XDR round-up padding if it is absent and the receiver's XDR decoder requires it to be present. Commit 193bcb7b3719 ("svcrdma: Populate tail iovec when receiving") attempted to add support for receiving such a compound so that just the WRITE payload appears in rq_arg's page list, and the trailing GETATTR is placed in rq_arg's tail iovec. (TCP just strings the whole compound into the head iovec and page list, without regard to the alignment of the WRITE payload). The server transport logic also had to accommodate the optional XDR round-up of the Read chunk, which it did simply by lengthening the tail iovec when round-up was needed. This approach is adequate for the NFSv2 and NFSv3 WRITE decoders. Unfortunately it is not sufficient for nfsd4_decode_write. When the Read chunk length is a couple of bytes less than PAGE_SIZE, the computation at the end of nfsd4_decode_write allows argp->pagelen to go negative, which breaks the logic in read_buf that looks for the tail iovec. The result is that a WRITE operation whose payload length is just less than a multiple of a page succeeds, but the subsequent GETATTR in the same compound fails with NFS4ERR_OP_ILLEGAL because the XDR decoder can't find it. Clients ignore the error, but they must update their attribute cache via a separate round trip. As nfsd4_decode_write appears to expect the payload itself to always have appropriate XDR round-up, have svc_rdma_build_normal_read_chunk add the Read chunk XDR round-up to the page_len rather than lengthening the tail iovec. Reported-by: Olga Kornievskaia Fixes: 193bcb7b3719 ("svcrdma: Populate tail iovec when receiving") Signed-off-by: Chuck Lever Tested-by: Olga Kornievskaia Signed-off-by: J. Bruce Fields Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- net/sunrpc/xprtrdma/svc_rdma_rw.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/net/sunrpc/xprtrdma/svc_rdma_rw.c b/net/sunrpc/xprtrdma/svc_rdma_rw.c index 9bd04549a1ad..12b9a7e0b6d2 100644 --- a/net/sunrpc/xprtrdma/svc_rdma_rw.c +++ b/net/sunrpc/xprtrdma/svc_rdma_rw.c @@ -727,12 +727,16 @@ static int svc_rdma_build_normal_read_chunk(struct svc_rqst *rqstp, head->arg.head[0].iov_len - info->ri_position; head->arg.head[0].iov_len = info->ri_position; - /* Read chunk may need XDR roundup (see RFC 5666, s. 3.7). + /* Read chunk may need XDR roundup (see RFC 8166, s. 3.4.5.2). * - * NFSv2/3 write decoders need the length of the tail to - * contain the size of the roundup padding. + * If the client already rounded up the chunk length, the + * length does not change. Otherwise, the length of the page + * list is increased to include XDR round-up. + * + * Currently these chunks always start at page offset 0, + * thus the rounded-up length never crosses a page boundary. */ - head->arg.tail[0].iov_len += 4 - (info->ri_chunklen & 3); + info->ri_chunklen = XDR_QUADLEN(info->ri_chunklen) << 2; head->arg.page_len = info->ri_chunklen; head->arg.len += info->ri_chunklen; -- GitLab From 327aac8ccbc54a0a320428664385b1d8bd8fd033 Mon Sep 17 00:00:00 2001 From: Mathieu Malaterre Date: Wed, 7 Feb 2018 20:35:00 +0100 Subject: [PATCH 1018/1635] net: Extra '_get' in declaration of arch_get_platform_mac_address MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit e728789c52afccc1275cba1dd812f03abe16ea3c ] In commit c7f5d105495a ("net: Add eth_platform_get_mac_address() helper."), two declarations were added: int eth_platform_get_mac_address(struct device *dev, u8 *mac_addr); unsigned char *arch_get_platform_get_mac_address(void); An extra '_get' was introduced in arch_get_platform_get_mac_address, remove it. Fix compile warning using W=1: CC net/ethernet/eth.o net/ethernet/eth.c:523:24: warning: no previous prototype for ‘arch_get_platform_mac_address’ [-Wmissing-prototypes] unsigned char * __weak arch_get_platform_mac_address(void) ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~ AR net/ethernet/built-in.o Signed-off-by: Mathieu Malaterre Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- include/linux/etherdevice.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/etherdevice.h b/include/linux/etherdevice.h index 2d9f80848d4b..c643cc7fefb5 100644 --- a/include/linux/etherdevice.h +++ b/include/linux/etherdevice.h @@ -31,7 +31,7 @@ #ifdef __KERNEL__ struct device; int eth_platform_get_mac_address(struct device *dev, u8 *mac_addr); -unsigned char *arch_get_platform_get_mac_address(void); +unsigned char *arch_get_platform_mac_address(void); u32 eth_get_headlen(void *data, unsigned int max_len); __be16 eth_type_trans(struct sk_buff *skb, struct net_device *dev); extern const struct header_ops eth_header_ops; -- GitLab From d6b00490a04d2434088c87c3afe2e827bdaab61b Mon Sep 17 00:00:00 2001 From: Jesper Dangaard Brouer Date: Thu, 8 Feb 2018 12:48:32 +0100 Subject: [PATCH 1019/1635] tools/libbpf: handle issues with bpf ELF objects containing .eh_frames [ Upstream commit e3d91b0ca523d53158f435a3e13df7f0cb360ea2 ] V3: More generic skipping of relo-section (suggested by Daniel) If clang >= 4.0.1 is missing the option '-target bpf', it will cause llc/llvm to create two ELF sections for "Exception Frames", with section names '.eh_frame' and '.rel.eh_frame'. The BPF ELF loader library libbpf fails when loading files with these sections. The other in-kernel BPF ELF loader in samples/bpf/bpf_load.c, handle this gracefully. And iproute2 loader also seems to work with these "eh" sections. The issue in libbpf is caused by bpf_object__elf_collect() skipping some sections, and later when performing relocation it will be pointing to a skipped section, as these sections cannot be found by bpf_object__find_prog_by_idx() in bpf_object__collect_reloc(). This is a general issue that also occurs for other sections, like debug sections which are also skipped and can have relo section. As suggested by Daniel. To avoid keeping state about all skipped sections, instead perform a direct qlookup in the ELF object. Lookup the section that the relo-section points to and check if it contains executable machine instructions (denoted by the sh_flags SHF_EXECINSTR). Use this check to also skip irrelevant relo-sections. Note, for samples/bpf/ the '-target bpf' parameter to clang cannot be used due to incompatibility with asm embedded headers, that some of the samples include. This is explained in more details by Yonghong Song in bpf_devel_QA. Signed-off-by: Jesper Dangaard Brouer Signed-off-by: Daniel Borkmann Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- tools/lib/bpf/libbpf.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c index 35f6dfcdc565..701d29c8364f 100644 --- a/tools/lib/bpf/libbpf.c +++ b/tools/lib/bpf/libbpf.c @@ -661,6 +661,24 @@ bpf_object__init_maps(struct bpf_object *obj) return bpf_object__validate_maps(obj); } +static bool section_have_execinstr(struct bpf_object *obj, int idx) +{ + Elf_Scn *scn; + GElf_Shdr sh; + + scn = elf_getscn(obj->efile.elf, idx); + if (!scn) + return false; + + if (gelf_getshdr(scn, &sh) != &sh) + return false; + + if (sh.sh_flags & SHF_EXECINSTR) + return true; + + return false; +} + static int bpf_object__elf_collect(struct bpf_object *obj) { Elf *elf = obj->efile.elf; @@ -742,6 +760,14 @@ static int bpf_object__elf_collect(struct bpf_object *obj) } else if (sh.sh_type == SHT_REL) { void *reloc = obj->efile.reloc; int nr_reloc = obj->efile.nr_reloc + 1; + int sec = sh.sh_info; /* points to other section */ + + /* Only do relo for section with exec instructions */ + if (!section_have_execinstr(obj, sec)) { + pr_debug("skip relo %s(%d) for section(%d)\n", + name, idx, sec); + continue; + } reloc = realloc(reloc, sizeof(*obj->efile.reloc) * nr_reloc); -- GitLab From f58e4ecb9b2e75b8a2a32b990241f16363fd3673 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Wed, 7 Feb 2018 19:49:54 +1100 Subject: [PATCH 1020/1635] KVM: PPC: Book3S HV: Fix handling of secondary HPTEG in HPT resizing code [ Upstream commit 05f2bb0313a2855e491dadfc8319b7da261d7074 ] This fixes the computation of the HPTE index to use when the HPT resizing code encounters a bolted HPTE which is stored in its secondary HPTE group. The code inverts the HPTE group number, which is correct, but doesn't then mask it with new_hash_mask. As a result, new_pteg will be effectively negative, resulting in new_hptep pointing before the new HPT, which will corrupt memory. In addition, this removes two BUG_ON statements. The condition that the BUG_ONs were testing -- that we have computed the hash value incorrectly -- has never been observed in testing, and if it did occur, would only affect the guest, not the host. Given that BUG_ON should only be used in conditions where the kernel (i.e. the host kernel, in this case) can't possibly continue execution, it is not appropriate here. Reviewed-by: David Gibson Signed-off-by: Paul Mackerras Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/kvm/book3s_64_mmu_hv.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/arch/powerpc/kvm/book3s_64_mmu_hv.c b/arch/powerpc/kvm/book3s_64_mmu_hv.c index 2645d484e945..df9b53f40b1e 100644 --- a/arch/powerpc/kvm/book3s_64_mmu_hv.c +++ b/arch/powerpc/kvm/book3s_64_mmu_hv.c @@ -1348,12 +1348,8 @@ static unsigned long resize_hpt_rehash_hpte(struct kvm_resize_hpt *resize, } new_pteg = hash & new_hash_mask; - if (vpte & HPTE_V_SECONDARY) { - BUG_ON(~pteg != (hash & old_hash_mask)); - new_pteg = ~new_pteg; - } else { - BUG_ON(pteg != (hash & old_hash_mask)); - } + if (vpte & HPTE_V_SECONDARY) + new_pteg = ~hash & new_hash_mask; new_idx = new_pteg * HPTES_PER_GROUP + (idx % HPTES_PER_GROUP); new_hptep = (__be64 *)(new->virt + (new_idx << 4)); -- GitLab From 26bebd5a7865376d5944b0206d7b271ab76f116b Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Fri, 9 Feb 2018 09:39:42 -0500 Subject: [PATCH 1021/1635] SUNRPC: Don't call __UDPX_INC_STATS() from a preemptible context [ Upstream commit 0afa6b4412988019db14c6bfb8c6cbdf120ca9ad ] Calling __UDPX_INC_STATS() from a preemptible context leads to a warning of the form: BUG: using __this_cpu_add() in preemptible [00000000] code: kworker/u5:0/31 caller is xs_udp_data_receive_workfn+0x194/0x270 CPU: 1 PID: 31 Comm: kworker/u5:0 Not tainted 4.15.0-rc8-00076-g90ea9f1 #2 Workqueue: xprtiod xs_udp_data_receive_workfn Call Trace: dump_stack+0x85/0xc1 check_preemption_disabled+0xce/0xe0 xs_udp_data_receive_workfn+0x194/0x270 process_one_work+0x318/0x620 worker_thread+0x20a/0x390 ? process_one_work+0x620/0x620 kthread+0x120/0x130 ? __kthread_bind_mask+0x60/0x60 ret_from_fork+0x24/0x30 Since we're taking a spinlock in those functions anyway, let's fix the issue by moving the call so that it occurs under the spinlock. Reported-by: kernel test robot Signed-off-by: Trond Myklebust Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- net/sunrpc/xprtsock.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index 8cb40f8ffa5b..30192abfdc3b 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c @@ -1069,18 +1069,18 @@ static void xs_udp_data_read_skb(struct rpc_xprt *xprt, /* Suck it into the iovec, verify checksum if not done by hw. */ if (csum_partial_copy_to_xdr(&rovr->rq_private_buf, skb)) { - __UDPX_INC_STATS(sk, UDP_MIB_INERRORS); spin_lock(&xprt->recv_lock); + __UDPX_INC_STATS(sk, UDP_MIB_INERRORS); goto out_unpin; } - __UDPX_INC_STATS(sk, UDP_MIB_INDATAGRAMS); spin_lock_bh(&xprt->transport_lock); xprt_adjust_cwnd(xprt, task, copied); spin_unlock_bh(&xprt->transport_lock); spin_lock(&xprt->recv_lock); xprt_complete_rqst(task, copied); + __UDPX_INC_STATS(sk, UDP_MIB_INDATAGRAMS); out_unpin: xprt_unpin_rqst(rovr); out_unlock: -- GitLab From ee5fe4bdcf2aea19ee238d6c3844dfe3c7c77e8b Mon Sep 17 00:00:00 2001 From: Niklas Cassel Date: Fri, 9 Feb 2018 17:22:45 +0100 Subject: [PATCH 1022/1635] net: stmmac: discard disabled flags in interrupt status register [ Upstream commit 1b84ca187510f60f00f4e15255043ce19bb30410 ] The interrupt status register in both dwmac1000 and dwmac4 ignores interrupt enable (for dwmac4) / interrupt mask (for dwmac1000). Therefore, if we want to check only the bits that can actually trigger an irq, we have to filter the interrupt status register manually. Commit 0a764db10337 ("stmmac: Discard masked flags in interrupt status register") fixed this for dwmac1000. Fix the same issue for dwmac4. Just like commit 0a764db10337 ("stmmac: Discard masked flags in interrupt status register"), this makes sure that we do not get spurious link up/link down prints. Signed-off-by: Niklas Cassel Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c b/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c index 2f7d7ec59962..e1d03489ae63 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c @@ -562,10 +562,12 @@ static int dwmac4_irq_status(struct mac_device_info *hw, struct stmmac_extra_stats *x) { void __iomem *ioaddr = hw->pcsr; - u32 intr_status; + u32 intr_status = readl(ioaddr + GMAC_INT_STATUS); + u32 intr_enable = readl(ioaddr + GMAC_INT_EN); int ret = 0; - intr_status = readl(ioaddr + GMAC_INT_STATUS); + /* Discard disabled bits */ + intr_status &= intr_enable; /* Not used events (e.g. MMC interrupts) are not handled. */ if ((intr_status & mmc_tx_irq)) -- GitLab From 85bd5c686fe9e60557b5d8610110c49381ed4a07 Mon Sep 17 00:00:00 2001 From: Daniel Borkmann Date: Fri, 9 Feb 2018 14:49:44 +0100 Subject: [PATCH 1023/1635] bpf: fix rlimit in reuseport net selftest [ Upstream commit 941ff6f11c020913f5cddf543a9ec63475d7c082 ] Fix two issues in the reuseport_bpf selftests that were reported by Linaro CI: [...] + ./reuseport_bpf ---- IPv4 UDP ---- Testing EBPF mod 10... Reprograming, testing mod 5... ./reuseport_bpf: ebpf error. log: 0: (bf) r6 = r1 1: (20) r0 = *(u32 *)skb[0] 2: (97) r0 %= 10 3: (95) exit processed 4 insns : Operation not permitted + echo FAIL [...] ---- IPv4 TCP ---- Testing EBPF mod 10... ./reuseport_bpf: failed to bind send socket: Address already in use + echo FAIL [...] For the former adjust rlimit since this was the cause of failure for loading the BPF prog, and for the latter add SO_REUSEADDR. Reported-by: Naresh Kamboju Link: https://bugs.linaro.org/show_bug.cgi?id=3502 Signed-off-by: Daniel Borkmann Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- tools/testing/selftests/net/reuseport_bpf.c | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/tools/testing/selftests/net/reuseport_bpf.c b/tools/testing/selftests/net/reuseport_bpf.c index 4a8217448f20..cad14cd0ea92 100644 --- a/tools/testing/selftests/net/reuseport_bpf.c +++ b/tools/testing/selftests/net/reuseport_bpf.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #ifndef ARRAY_SIZE @@ -190,11 +191,14 @@ static void send_from(struct test_params p, uint16_t sport, char *buf, struct sockaddr * const saddr = new_any_sockaddr(p.send_family, sport); struct sockaddr * const daddr = new_loopback_sockaddr(p.send_family, p.recv_port); - const int fd = socket(p.send_family, p.protocol, 0); + const int fd = socket(p.send_family, p.protocol, 0), one = 1; if (fd < 0) error(1, errno, "failed to create send socket"); + if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one))) + error(1, errno, "failed to set reuseaddr"); + if (bind(fd, saddr, sockaddr_size())) error(1, errno, "failed to bind send socket"); @@ -433,6 +437,21 @@ void enable_fastopen(void) } } +static struct rlimit rlim_old, rlim_new; + +static __attribute__((constructor)) void main_ctor(void) +{ + getrlimit(RLIMIT_MEMLOCK, &rlim_old); + rlim_new.rlim_cur = rlim_old.rlim_cur + (1UL << 20); + rlim_new.rlim_max = rlim_old.rlim_max + (1UL << 20); + setrlimit(RLIMIT_MEMLOCK, &rlim_new); +} + +static __attribute__((destructor)) void main_dtor(void) +{ + setrlimit(RLIMIT_MEMLOCK, &rlim_old); +} + int main(void) { fprintf(stderr, "---- IPv4 UDP ----\n"); -- GitLab From afa0ce071488154e28d60b510dd0a3c3d86f7992 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 9 Feb 2018 22:55:28 +0100 Subject: [PATCH 1024/1635] ACPI / EC: Restore polling during noirq suspend/resume phases [ Upstream commit 3cd091a773936c54344a519f7ee1379ccb620bee ] Commit 662591461c4b (ACPI / EC: Drop EC noirq hooks to fix a regression) modified the ACPI EC driver so that it doesn't switch over to busy polling mode during noirq stages of system suspend and resume in an attempt to fix an issue resulting from that behavior. However, that modification introduced a system resume regression on Thinkpad X240, so make the EC driver switch over to the polling mode during noirq stages of system suspend and resume again, which effectively reverts the problematic commit. Fixes: 662591461c4b (ACPI / EC: Drop EC noirq hooks to fix a regression) Link: https://bugzilla.kernel.org/show_bug.cgi?id=197863 Reported-by: Markus Demleitner Tested-by: Markus Demleitner Signed-off-by: Rafael J. Wysocki Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/acpi/ec.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index 6adcda057b36..58bc28aff3aa 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -1927,6 +1927,9 @@ static int acpi_ec_suspend_noirq(struct device *dev) ec->reference_count >= 1) acpi_set_gpe(NULL, ec->gpe, ACPI_GPE_DISABLE); + if (acpi_sleep_no_ec_events()) + acpi_ec_enter_noirq(ec); + return 0; } @@ -1934,6 +1937,9 @@ static int acpi_ec_resume_noirq(struct device *dev) { struct acpi_ec *ec = acpi_driver_data(to_acpi_device(dev)); + if (acpi_sleep_no_ec_events()) + acpi_ec_leave_noirq(ec); + if (ec_no_wakeup && test_bit(EC_FLAGS_STARTED, &ec->flags) && ec->reference_count >= 1) acpi_set_gpe(NULL, ec->gpe, ACPI_GPE_ENABLE); -- GitLab From c064b7c1d203cd5d781c316ac9c8049ba772684f Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Fri, 9 Feb 2018 08:11:26 -0800 Subject: [PATCH 1025/1635] PM / wakeirq: Fix unbalanced IRQ enable for wakeirq [ Upstream commit 69728051f5bf15efaf6edfbcfe1b5a49a2437918 ] If a device is runtime PM suspended when we enter suspend and has a dedicated wake IRQ, we can get the following warning: WARNING: CPU: 0 PID: 108 at kernel/irq/manage.c:526 enable_irq+0x40/0x94 [ 102.087860] Unbalanced enable for IRQ 147 ... (enable_irq) from [] (dev_pm_arm_wake_irq+0x4c/0x60) (dev_pm_arm_wake_irq) from [] (device_wakeup_arm_wake_irqs+0x58/0x9c) (device_wakeup_arm_wake_irqs) from [] (dpm_suspend_noirq+0x10/0x48) (dpm_suspend_noirq) from [] (suspend_devices_and_enter+0x30c/0xf14) (suspend_devices_and_enter) from [] (enter_state+0xad4/0xbd8) (enter_state) from [] (pm_suspend+0x38/0x98) (pm_suspend) from [] (state_store+0x68/0xc8) This is because the dedicated wake IRQ for the device may have been already enabled earlier by dev_pm_enable_wake_irq_check(). Fix the issue by checking for runtime PM suspended status. This issue can be easily reproduced by setting serial console log level to zero, letting the serial console idle, and suspend the system from an ssh terminal. On resume, dmesg will have the warning above. The reason why I have not run into this issue earlier has been that I typically run my PM test cases from on a serial console instead over ssh. Fixes: c84345597558 (PM / wakeirq: Enable dedicated wakeirq for suspend) Signed-off-by: Tony Lindgren Signed-off-by: Rafael J. Wysocki Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/base/power/wakeirq.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/base/power/wakeirq.c b/drivers/base/power/wakeirq.c index ae0429827f31..67c50738834b 100644 --- a/drivers/base/power/wakeirq.c +++ b/drivers/base/power/wakeirq.c @@ -323,7 +323,8 @@ void dev_pm_arm_wake_irq(struct wake_irq *wirq) return; if (device_may_wakeup(wirq->dev)) { - if (wirq->status & WAKE_IRQ_DEDICATED_ALLOCATED) + if (wirq->status & WAKE_IRQ_DEDICATED_ALLOCATED && + !pm_runtime_status_suspended(wirq->dev)) enable_irq(wirq->irq); enable_irq_wake(wirq->irq); @@ -345,7 +346,8 @@ void dev_pm_disarm_wake_irq(struct wake_irq *wirq) if (device_may_wakeup(wirq->dev)) { disable_irq_wake(wirq->irq); - if (wirq->status & WAKE_IRQ_DEDICATED_ALLOCATED) + if (wirq->status & WAKE_IRQ_DEDICATED_ALLOCATED && + !pm_runtime_status_suspended(wirq->dev)) disable_irq_nosync(wirq->irq); } } -- GitLab From f4d6e4598a29f6f7df6937d943c01e1eeb9ee871 Mon Sep 17 00:00:00 2001 From: Jia Zhang Date: Mon, 12 Feb 2018 22:44:53 +0800 Subject: [PATCH 1026/1635] vfs/proc/kcore, x86/mm/kcore: Fix SMAP fault when dumping vsyscall user page [ Upstream commit 595dd46ebfc10be041a365d0a3fa99df50b6ba73 ] Commit: df04abfd181a ("fs/proc/kcore.c: Add bounce buffer for ktext data") ... introduced a bounce buffer to work around CONFIG_HARDENED_USERCOPY=y. However, accessing the vsyscall user page will cause an SMAP fault. Replace memcpy() with copy_from_user() to fix this bug works, but adding a common way to handle this sort of user page may be useful for future. Currently, only vsyscall page requires KCORE_USER. Signed-off-by: Jia Zhang Reviewed-by: Jiri Olsa Cc: Al Viro Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: jolsa@redhat.com Link: http://lkml.kernel.org/r/1518446694-21124-2-git-send-email-zhang.jia@linux.alibaba.com Signed-off-by: Ingo Molnar Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/x86/mm/init_64.c | 3 +-- fs/proc/kcore.c | 4 ++++ include/linux/kcore.h | 1 + 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/arch/x86/mm/init_64.c b/arch/x86/mm/init_64.c index fe85d1204db8..642357aff216 100644 --- a/arch/x86/mm/init_64.c +++ b/arch/x86/mm/init_64.c @@ -1180,8 +1180,7 @@ void __init mem_init(void) after_bootmem = 1; /* Register memory areas for /proc/kcore */ - kclist_add(&kcore_vsyscall, (void *)VSYSCALL_ADDR, - PAGE_SIZE, KCORE_OTHER); + kclist_add(&kcore_vsyscall, (void *)VSYSCALL_ADDR, PAGE_SIZE, KCORE_USER); mem_init_print_info(NULL); } diff --git a/fs/proc/kcore.c b/fs/proc/kcore.c index e8a93bc8285d..d1e82761de81 100644 --- a/fs/proc/kcore.c +++ b/fs/proc/kcore.c @@ -510,6 +510,10 @@ read_kcore(struct file *file, char __user *buffer, size_t buflen, loff_t *fpos) /* we have to zero-fill user buffer even if no read */ if (copy_to_user(buffer, buf, tsz)) return -EFAULT; + } else if (m->type == KCORE_USER) { + /* User page is handled prior to normal kernel page: */ + if (copy_to_user(buffer, (char *)start, tsz)) + return -EFAULT; } else { if (kern_addr_valid(start)) { /* diff --git a/include/linux/kcore.h b/include/linux/kcore.h index 7ff25a808fef..80db19d3a505 100644 --- a/include/linux/kcore.h +++ b/include/linux/kcore.h @@ -10,6 +10,7 @@ enum kcore_type { KCORE_VMALLOC, KCORE_RAM, KCORE_VMEMMAP, + KCORE_USER, KCORE_OTHER, }; -- GitLab From 288b373264c51f490676a860c705ec70e4d83a67 Mon Sep 17 00:00:00 2001 From: "Aneesh Kumar K.V" Date: Tue, 13 Feb 2018 16:39:33 +0530 Subject: [PATCH 1027/1635] powerpc/mm/hash64: Zero PGD pages on allocation [ Upstream commit fc5c2f4a55a2c258e12013cdf287cf266dbcd2a7 ] On powerpc we allocate page table pages from slab caches of different sizes. Currently we have a constructor that zeroes out the objects when we allocate them for the first time. We expect the objects to be zeroed out when we free the the object back to slab cache. This happens in the unmap path. For hugetlb pages we call huge_pte_get_and_clear() to do that. With the current configuration of page table size, both PUD and PGD level tables are allocated from the same slab cache. At the PUD level, we use the second half of the table to store the slot information. But we never clear that when unmapping. When such a freed object is then allocated for a PGD page, the second half of the page table page will not be zeroed as expected. This results in a kernel crash. Fix it by always clearing PGD pages when they're allocated. Signed-off-by: Aneesh Kumar K.V [mpe: Change log wording and formatting, add whitespace] Signed-off-by: Michael Ellerman Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/include/asm/book3s/64/pgalloc.h | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/arch/powerpc/include/asm/book3s/64/pgalloc.h b/arch/powerpc/include/asm/book3s/64/pgalloc.h index 1fcfa425cefa..f326b40b7c7b 100644 --- a/arch/powerpc/include/asm/book3s/64/pgalloc.h +++ b/arch/powerpc/include/asm/book3s/64/pgalloc.h @@ -73,10 +73,16 @@ static inline void radix__pgd_free(struct mm_struct *mm, pgd_t *pgd) static inline pgd_t *pgd_alloc(struct mm_struct *mm) { + pgd_t *pgd; + if (radix_enabled()) return radix__pgd_alloc(mm); - return kmem_cache_alloc(PGT_CACHE(PGD_INDEX_SIZE), - pgtable_gfp_flags(mm, GFP_KERNEL)); + + pgd = kmem_cache_alloc(PGT_CACHE(PGD_INDEX_SIZE), + pgtable_gfp_flags(mm, GFP_KERNEL)); + memset(pgd, 0, PGD_TABLE_SIZE); + + return pgd; } static inline void pgd_free(struct mm_struct *mm, pgd_t *pgd) -- GitLab From 5350cb0111d23ff50b66bcdd9ee5fdf3d64a9f01 Mon Sep 17 00:00:00 2001 From: "mike.travis@hpe.com" Date: Mon, 5 Feb 2018 16:15:04 -0600 Subject: [PATCH 1028/1635] x86/platform/UV: Fix GAM Range Table entries less than 1GB [ Upstream commit c25d99d20ba69824a1e2cc118e04b877cd427afc ] The latest UV platforms include the new ApachePass NVDIMMs into the UV address space. This has introduced address ranges in the Global Address Map Table that are less than the previous lowest range, which was 2GB. Fix the address calculation so it accommodates address ranges from bytes to exabytes. Signed-off-by: Mike Travis Reviewed-by: Andrew Banman Reviewed-by: Dimitri Sivanich Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Russ Anderson Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/20180205221503.190219903@stormcage.americas.sgi.com Signed-off-by: Ingo Molnar Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/x86/kernel/apic/x2apic_uv_x.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/arch/x86/kernel/apic/x2apic_uv_x.c b/arch/x86/kernel/apic/x2apic_uv_x.c index c0b694810ff4..02cfc615e3fb 100644 --- a/arch/x86/kernel/apic/x2apic_uv_x.c +++ b/arch/x86/kernel/apic/x2apic_uv_x.c @@ -1140,16 +1140,25 @@ static void __init decode_gam_rng_tbl(unsigned long ptr) uv_gre_table = gre; for (; gre->type != UV_GAM_RANGE_TYPE_UNUSED; gre++) { + unsigned long size = ((unsigned long)(gre->limit - lgre) + << UV_GAM_RANGE_SHFT); + int order = 0; + char suffix[] = " KMGTPE"; + + while (size > 9999 && order < sizeof(suffix)) { + size /= 1024; + order++; + } + if (!index) { pr_info("UV: GAM Range Table...\n"); pr_info("UV: # %20s %14s %5s %4s %5s %3s %2s\n", "Range", "", "Size", "Type", "NASID", "SID", "PN"); } - pr_info("UV: %2d: 0x%014lx-0x%014lx %5luG %3d %04x %02x %02x\n", + pr_info("UV: %2d: 0x%014lx-0x%014lx %5lu%c %3d %04x %02x %02x\n", index++, (unsigned long)lgre << UV_GAM_RANGE_SHFT, (unsigned long)gre->limit << UV_GAM_RANGE_SHFT, - ((unsigned long)(gre->limit - lgre)) >> - (30 - UV_GAM_RANGE_SHFT), /* 64M -> 1G */ + size, suffix[order], gre->type, gre->nasid, gre->sockid, gre->pnode); lgre = gre->limit; -- GitLab From c74e004c62739d6a6a002730d57fe851ff42f346 Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Tue, 13 Feb 2018 13:22:57 +0000 Subject: [PATCH 1029/1635] locking/qspinlock: Ensure node->count is updated before initialising node [ Upstream commit 11dc13224c975efcec96647a4768a6f1bb7a19a8 ] When queuing on the qspinlock, the count field for the current CPU's head node is incremented. This needn't be atomic because locking in e.g. IRQ context is balanced and so an IRQ will return with node->count as it found it. However, the compiler could in theory reorder the initialisation of node[idx] before the increment of the head node->count, causing an IRQ to overwrite the initialised node and potentially corrupt the lock state. Avoid the potential for this harmful compiler reordering by placing a barrier() between the increment of the head node->count and the subsequent node initialisation. Signed-off-by: Will Deacon Acked-by: Peter Zijlstra (Intel) Cc: Linus Torvalds Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/1518528177-19169-3-git-send-email-will.deacon@arm.com Signed-off-by: Ingo Molnar Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- kernel/locking/qspinlock.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/kernel/locking/qspinlock.c b/kernel/locking/qspinlock.c index 294294c71ba4..50dc42aeaa56 100644 --- a/kernel/locking/qspinlock.c +++ b/kernel/locking/qspinlock.c @@ -379,6 +379,14 @@ void queued_spin_lock_slowpath(struct qspinlock *lock, u32 val) tail = encode_tail(smp_processor_id(), idx); node += idx; + + /* + * Ensure that we increment the head node->count before initialising + * the actual node. If the compiler is kind enough to reorder these + * stores, then an IRQ could overwrite our assignments. + */ + barrier(); + node->locked = 0; node->next = NULL; pv_init_node(node); -- GitLab From 74cd9414788ca5de87b2df2103d39a7705f202f1 Mon Sep 17 00:00:00 2001 From: Nicholas Piggin Date: Tue, 13 Feb 2018 17:45:11 +1000 Subject: [PATCH 1030/1635] powerpc/powernv: IMC fix out of bounds memory access at shutdown [ Upstream commit e7bde88cdb4f0e432398a7d29ca2a15d2c18952a ] The OPAL IMC driver's shutdown handler disables nest PMU counters by walking nodes and taking the first CPU out of their cpumask, which is used to index into the paca (get_hard_smp_processor_id()). This does not always do the right thing, and in particular for CPU-less nodes it returns NR_CPUS and that overruns the paca and dereferences random memory. Fix it by being more careful about checking returned CPU, and only using online CPUs. It's not clear this shutdown code makes sense after commit 885dcd709b ("powerpc/perf: Add nest IMC PMU support"), but this should not make things worse Currently the bug causes us to call OPAL with a junk CPU number. A separate patch in development to change the way pacas are allocated escalates this bug into a crash: Unable to handle kernel paging request for data at address 0x2a21af1eeb000076 Faulting instruction address: 0xc0000000000a5468 Oops: Kernel access of bad area, sig: 11 [#1] ... NIP opal_imc_counters_shutdown+0x148/0x1d0 LR opal_imc_counters_shutdown+0x134/0x1d0 Call Trace: opal_imc_counters_shutdown+0x134/0x1d0 (unreliable) platform_drv_shutdown+0x44/0x60 device_shutdown+0x1f8/0x350 kernel_restart_prepare+0x54/0x70 kernel_restart+0x28/0xc0 SyS_reboot+0x1d0/0x2c0 system_call+0x58/0x6c Signed-off-by: Nicholas Piggin Signed-off-by: Michael Ellerman Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/platforms/powernv/opal-imc.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/arch/powerpc/platforms/powernv/opal-imc.c b/arch/powerpc/platforms/powernv/opal-imc.c index b150f4deaccf..6914b289c86b 100644 --- a/arch/powerpc/platforms/powernv/opal-imc.c +++ b/arch/powerpc/platforms/powernv/opal-imc.c @@ -126,9 +126,11 @@ static void disable_nest_pmu_counters(void) const struct cpumask *l_cpumask; get_online_cpus(); - for_each_online_node(nid) { + for_each_node_with_cpus(nid) { l_cpumask = cpumask_of_node(nid); - cpu = cpumask_first(l_cpumask); + cpu = cpumask_first_and(l_cpumask, cpu_online_mask); + if (cpu >= nr_cpu_ids) + continue; opal_imc_counters_stop(OPAL_IMC_COUNTERS_NEST, get_hard_smp_processor_id(cpu)); } -- GitLab From 2d8d8d23c485d78b00c6a44629b711987ac1234b Mon Sep 17 00:00:00 2001 From: Thomas Richter Date: Wed, 17 Jan 2018 09:38:31 +0100 Subject: [PATCH 1031/1635] perf test: Fix test trace+probe_libc_inet_pton.sh for s390x [ Upstream commit 7a92453620d42c3a5fea94a864dc6aa04c262b93 ] On Intel test case trace+probe_libc_inet_pton.sh succeeds and the output is: [root@f27 perf]# ./perf trace --no-syscalls -e probe_libc:inet_pton/max-stack=3/ ping -6 -c 1 ::1 PING ::1(::1) 56 data bytes 64 bytes from ::1: icmp_seq=1 ttl=64 time=0.037 ms --- ::1 ping statistics --- 1 packets transmitted, 1 received, 0% packet loss, time 0ms rtt min/avg/max/mdev = 0.037/0.037/0.037/0.000 ms 0.000 probe_libc:inet_pton:(7fa40ac618a0)) __GI___inet_pton (/usr/lib64/libc-2.26.so) getaddrinfo (/usr/lib64/libc-2.26.so) main (/usr/bin/ping) The kernel stack unwinder is used, it is specified implicitly as call-graph=fp (frame pointer). On s390x only dwarf is available for stack unwinding. It is also done in user space. This requires different parameter setup and result checking for s390x and Intel. This patch adds separate perf trace setup and result checking for Intel and s390x. On s390x specify this command line to get a call-graph and handle the different call graph result checking: [root@s35lp76 perf]# ./perf trace --no-syscalls -e probe_libc:inet_pton/call-graph=dwarf/ ping -6 -c 1 ::1 PING ::1(::1) 56 data bytes 64 bytes from ::1: icmp_seq=1 ttl=64 time=0.041 ms --- ::1 ping statistics --- 1 packets transmitted, 1 received, 0% packet loss, time 0ms rtt min/avg/max/mdev = 0.041/0.041/0.041/0.000 ms 0.000 probe_libc:inet_pton:(3ffb9942060)) __GI___inet_pton (/usr/lib64/libc-2.26.so) gaih_inet (inlined) __GI_getaddrinfo (inlined) main (/usr/bin/ping) __libc_start_main (/usr/lib64/libc-2.26.so) _start (/usr/bin/ping) [root@s35lp76 perf]# Before: [root@s8360047 perf]# ./perf test -vv 58 58: probe libc's inet_pton & backtrace it with ping : --- start --- test child forked, pid 26349 PING ::1(::1) 56 data bytes 64 bytes from ::1: icmp_seq=1 ttl=64 time=0.079 ms --- ::1 ping statistics --- 1 packets transmitted, 1 received, 0% packet loss, time 0ms rtt min/avg/max/mdev = 0.079/0.079/0.079/0.000 ms 0.000 probe_libc:inet_pton:(3ff925c2060)) test child finished with -1 ---- end ---- probe libc's inet_pton & backtrace it with ping: FAILED! [root@s8360047 perf]# After: [root@s35lp76 perf]# ./perf test -vv 57 57: probe libc's inet_pton & backtrace it with ping : --- start --- test child forked, pid 38708 PING ::1(::1) 56 data bytes 64 bytes from ::1: icmp_seq=1 ttl=64 time=0.038 ms --- ::1 ping statistics --- 1 packets transmitted, 1 received, 0% packet loss, time 0ms rtt min/avg/max/mdev = 0.038/0.038/0.038/0.000 ms 0.000 probe_libc:inet_pton:(3ff87342060)) __GI___inet_pton (/usr/lib64/libc-2.26.so) gaih_inet (inlined) __GI_getaddrinfo (inlined) main (/usr/bin/ping) __libc_start_main (/usr/lib64/libc-2.26.so) _start (/usr/bin/ping) test child finished with 0 ---- end ---- probe libc's inet_pton & backtrace it with ping: Ok [root@s35lp76 perf]# On Intel the test case runs unchanged and succeeds. Signed-off-by: Thomas Richter Reviewed-by: Hendrik Brueckner Tested-by: Arnaldo Carvalho de Melo Cc: Heiko Carstens Cc: Martin Schwidefsky Link: http://lkml.kernel.org/r/20180117083831.101001-1-tmricht@linux.vnet.ibm.com Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- .../tests/shell/trace+probe_libc_inet_pton.sh | 21 +++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/tools/perf/tests/shell/trace+probe_libc_inet_pton.sh b/tools/perf/tests/shell/trace+probe_libc_inet_pton.sh index 7a84d73324e3..a2f757da49d9 100755 --- a/tools/perf/tests/shell/trace+probe_libc_inet_pton.sh +++ b/tools/perf/tests/shell/trace+probe_libc_inet_pton.sh @@ -22,10 +22,23 @@ trace_libc_inet_pton_backtrace() { expected[4]="rtt min.*" expected[5]="[0-9]+\.[0-9]+[[:space:]]+probe_libc:inet_pton:\([[:xdigit:]]+\)" expected[6]=".*inet_pton[[:space:]]\($libc\)$" - expected[7]="getaddrinfo[[:space:]]\($libc\)$" - expected[8]=".*\(.*/bin/ping.*\)$" + case "$(uname -m)" in + s390x) + eventattr='call-graph=dwarf' + expected[7]="gaih_inet[[:space:]]\(inlined\)$" + expected[8]="__GI_getaddrinfo[[:space:]]\(inlined\)$" + expected[9]="main[[:space:]]\(.*/bin/ping.*\)$" + expected[10]="__libc_start_main[[:space:]]\($libc\)$" + expected[11]="_start[[:space:]]\(.*/bin/ping.*\)$" + ;; + *) + eventattr='max-stack=3' + expected[7]="getaddrinfo[[:space:]]\($libc\)$" + expected[8]=".*\(.*/bin/ping.*\)$" + ;; + esac - perf trace --no-syscalls -e probe_libc:inet_pton/max-stack=3/ ping -6 -c 1 ::1 2>&1 | grep -v ^$ | while read line ; do + perf trace --no-syscalls -e probe_libc:inet_pton/$eventattr/ ping -6 -c 1 ::1 2>&1 | grep -v ^$ | while read line ; do echo $line echo "$line" | egrep -q "${expected[$idx]}" if [ $? -ne 0 ] ; then @@ -33,7 +46,7 @@ trace_libc_inet_pton_backtrace() { exit 1 fi let idx+=1 - [ $idx -eq 9 ] && break + [ -z "${expected[$idx]}" ] && break done } -- GitLab From c834b955d3f00789b2c95a6e642a058f12ae9096 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Thu, 1 Feb 2018 09:03:29 -0800 Subject: [PATCH 1032/1635] irqchip/gic-v3: Ignore disabled ITS nodes [ Upstream commit 95a2562590c2f64a0398183f978d5cf3db6d0284 ] On some platforms there's an ITS available but it's not enabled because reading or writing the registers is denied by the firmware. In fact, reading or writing them will cause the system to reset. We could remove the node from DT in such a case, but it's better to skip nodes that are marked as "disabled" in DT so that we can describe the hardware that exists and use the status property to indicate how the firmware has configured things. Cc: Stuart Yoder Cc: Laurentiu Tudor Cc: Greg Kroah-Hartman Cc: Marc Zyngier Cc: Rajendra Nayak Signed-off-by: Stephen Boyd Signed-off-by: Marc Zyngier Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/irqchip/irq-gic-v3-its-pci-msi.c | 2 ++ drivers/irqchip/irq-gic-v3-its-platform-msi.c | 2 ++ drivers/irqchip/irq-gic-v3-its.c | 2 ++ drivers/staging/fsl-mc/bus/irq-gic-v3-its-fsl-mc-msi.c | 2 ++ 4 files changed, 8 insertions(+) diff --git a/drivers/irqchip/irq-gic-v3-its-pci-msi.c b/drivers/irqchip/irq-gic-v3-its-pci-msi.c index 14a8c0a7e095..25a98de5cfb2 100644 --- a/drivers/irqchip/irq-gic-v3-its-pci-msi.c +++ b/drivers/irqchip/irq-gic-v3-its-pci-msi.c @@ -132,6 +132,8 @@ static int __init its_pci_of_msi_init(void) for (np = of_find_matching_node(NULL, its_device_id); np; np = of_find_matching_node(np, its_device_id)) { + if (!of_device_is_available(np)) + continue; if (!of_property_read_bool(np, "msi-controller")) continue; diff --git a/drivers/irqchip/irq-gic-v3-its-platform-msi.c b/drivers/irqchip/irq-gic-v3-its-platform-msi.c index 833a90fe33ae..8881a053c173 100644 --- a/drivers/irqchip/irq-gic-v3-its-platform-msi.c +++ b/drivers/irqchip/irq-gic-v3-its-platform-msi.c @@ -154,6 +154,8 @@ static void __init its_pmsi_of_init(void) for (np = of_find_matching_node(NULL, its_device_id); np; np = of_find_matching_node(np, its_device_id)) { + if (!of_device_is_available(np)) + continue; if (!of_property_read_bool(np, "msi-controller")) continue; diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c index af57f8473a88..13f195c9743e 100644 --- a/drivers/irqchip/irq-gic-v3-its.c +++ b/drivers/irqchip/irq-gic-v3-its.c @@ -3083,6 +3083,8 @@ static int __init its_of_probe(struct device_node *node) for (np = of_find_matching_node(node, its_device_id); np; np = of_find_matching_node(np, its_device_id)) { + if (!of_device_is_available(np)) + continue; if (!of_property_read_bool(np, "msi-controller")) { pr_warn("%pOF: no msi-controller property, ITS ignored\n", np); diff --git a/drivers/staging/fsl-mc/bus/irq-gic-v3-its-fsl-mc-msi.c b/drivers/staging/fsl-mc/bus/irq-gic-v3-its-fsl-mc-msi.c index 123e4af58408..50260cb5056d 100644 --- a/drivers/staging/fsl-mc/bus/irq-gic-v3-its-fsl-mc-msi.c +++ b/drivers/staging/fsl-mc/bus/irq-gic-v3-its-fsl-mc-msi.c @@ -75,6 +75,8 @@ int __init its_fsl_mc_msi_init(void) for (np = of_find_matching_node(NULL, its_device_id); np; np = of_find_matching_node(np, its_device_id)) { + if (!of_device_is_available(np)) + continue; if (!of_property_read_bool(np, "msi-controller")) continue; -- GitLab From 4032cd4fd3aec5d76d5ad9451f6d31ff6003c7cf Mon Sep 17 00:00:00 2001 From: Michael Kelley Date: Wed, 14 Feb 2018 02:54:03 +0000 Subject: [PATCH 1033/1635] cpumask: Make for_each_cpu_wrap() available on UP as well [ Upstream commit d207af2eab3f8668b95ad02b21930481c42806fd ] for_each_cpu_wrap() was originally added in the #else half of a large "#if NR_CPUS == 1" statement, but was omitted in the #if half. This patch adds the missing #if half to prevent compile errors when NR_CPUS is 1. Reported-by: kbuild test robot Signed-off-by: Michael Kelley Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: kys@microsoft.com Cc: martin.petersen@oracle.com Cc: mikelley@microsoft.com Fixes: c743f0a5c50f ("sched/fair, cpumask: Export for_each_cpu_wrap()") Link: http://lkml.kernel.org/r/SN6PR1901MB2045F087F59450507D4FCC17CBF50@SN6PR1901MB2045.namprd19.prod.outlook.com Signed-off-by: Ingo Molnar Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- include/linux/cpumask.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/linux/cpumask.h b/include/linux/cpumask.h index 8d3125c493b2..db461a07bf38 100644 --- a/include/linux/cpumask.h +++ b/include/linux/cpumask.h @@ -165,6 +165,8 @@ static inline unsigned int cpumask_local_spread(unsigned int i, int node) for ((cpu) = 0; (cpu) < 1; (cpu)++, (void)mask) #define for_each_cpu_not(cpu, mask) \ for ((cpu) = 0; (cpu) < 1; (cpu)++, (void)mask) +#define for_each_cpu_wrap(cpu, mask, start) \ + for ((cpu) = 0; (cpu) < 1; (cpu)++, (void)mask, (void)(start)) #define for_each_cpu_and(cpu, mask, and) \ for ((cpu) = 0; (cpu) < 1; (cpu)++, (void)mask, (void)and) #else -- GitLab From de16dfcc510d8ec2981e4ed97e51d17c043cdaec Mon Sep 17 00:00:00 2001 From: Mark Salter Date: Fri, 2 Feb 2018 09:20:29 -0500 Subject: [PATCH 1034/1635] irqchip/gic-v3: Change pr_debug message to pr_devel [ Upstream commit b6dd4d83dc2f78cebc9a7e6e7e4bc2be4d29b94d ] The pr_debug() in gic-v3 gic_send_sgi() can trigger a circular locking warning: GICv3: CPU10: ICC_SGI1R_EL1 5000400 ====================================================== WARNING: possible circular locking dependency detected 4.15.0+ #1 Tainted: G W ------------------------------------------------------ dynamic_debug01/1873 is trying to acquire lock: ((console_sem).lock){-...}, at: [<0000000099c891ec>] down_trylock+0x20/0x4c but task is already holding lock: (&rq->lock){-.-.}, at: [<00000000842e1587>] __task_rq_lock+0x54/0xdc which lock already depends on the new lock. the existing dependency chain (in reverse order) is: -> #2 (&rq->lock){-.-.}: __lock_acquire+0x3b4/0x6e0 lock_acquire+0xf4/0x2a8 _raw_spin_lock+0x4c/0x60 task_fork_fair+0x3c/0x148 sched_fork+0x10c/0x214 copy_process.isra.32.part.33+0x4e8/0x14f0 _do_fork+0xe8/0x78c kernel_thread+0x48/0x54 rest_init+0x34/0x2a4 start_kernel+0x45c/0x488 -> #1 (&p->pi_lock){-.-.}: __lock_acquire+0x3b4/0x6e0 lock_acquire+0xf4/0x2a8 _raw_spin_lock_irqsave+0x58/0x70 try_to_wake_up+0x48/0x600 wake_up_process+0x28/0x34 __up.isra.0+0x60/0x6c up+0x60/0x68 __up_console_sem+0x4c/0x7c console_unlock+0x328/0x634 vprintk_emit+0x25c/0x390 dev_vprintk_emit+0xc4/0x1fc dev_printk_emit+0x88/0xa8 __dev_printk+0x58/0x9c _dev_info+0x84/0xa8 usb_new_device+0x100/0x474 hub_port_connect+0x280/0x92c hub_event+0x740/0xa84 process_one_work+0x240/0x70c worker_thread+0x60/0x400 kthread+0x110/0x13c ret_from_fork+0x10/0x18 -> #0 ((console_sem).lock){-...}: validate_chain.isra.34+0x6e4/0xa20 __lock_acquire+0x3b4/0x6e0 lock_acquire+0xf4/0x2a8 _raw_spin_lock_irqsave+0x58/0x70 down_trylock+0x20/0x4c __down_trylock_console_sem+0x3c/0x9c console_trylock+0x20/0xb0 vprintk_emit+0x254/0x390 vprintk_default+0x58/0x90 vprintk_func+0xbc/0x164 printk+0x80/0xa0 __dynamic_pr_debug+0x84/0xac gic_raise_softirq+0x184/0x18c smp_cross_call+0xac/0x218 smp_send_reschedule+0x3c/0x48 resched_curr+0x60/0x9c check_preempt_curr+0x70/0xdc wake_up_new_task+0x310/0x470 _do_fork+0x188/0x78c SyS_clone+0x44/0x50 __sys_trace_return+0x0/0x4 other info that might help us debug this: Chain exists of: (console_sem).lock --> &p->pi_lock --> &rq->lock Possible unsafe locking scenario: CPU0 CPU1 ---- ---- lock(&rq->lock); lock(&p->pi_lock); lock(&rq->lock); lock((console_sem).lock); *** DEADLOCK *** 2 locks held by dynamic_debug01/1873: #0: (&p->pi_lock){-.-.}, at: [<000000001366df53>] wake_up_new_task+0x40/0x470 #1: (&rq->lock){-.-.}, at: [<00000000842e1587>] __task_rq_lock+0x54/0xdc stack backtrace: CPU: 10 PID: 1873 Comm: dynamic_debug01 Tainted: G W 4.15.0+ #1 Hardware name: GIGABYTE R120-T34-00/MT30-GS2-00, BIOS T48 10/02/2017 Call trace: dump_backtrace+0x0/0x188 show_stack+0x24/0x2c dump_stack+0xa4/0xe0 print_circular_bug.isra.31+0x29c/0x2b8 check_prev_add.constprop.39+0x6c8/0x6dc validate_chain.isra.34+0x6e4/0xa20 __lock_acquire+0x3b4/0x6e0 lock_acquire+0xf4/0x2a8 _raw_spin_lock_irqsave+0x58/0x70 down_trylock+0x20/0x4c __down_trylock_console_sem+0x3c/0x9c console_trylock+0x20/0xb0 vprintk_emit+0x254/0x390 vprintk_default+0x58/0x90 vprintk_func+0xbc/0x164 printk+0x80/0xa0 __dynamic_pr_debug+0x84/0xac gic_raise_softirq+0x184/0x18c smp_cross_call+0xac/0x218 smp_send_reschedule+0x3c/0x48 resched_curr+0x60/0x9c check_preempt_curr+0x70/0xdc wake_up_new_task+0x310/0x470 _do_fork+0x188/0x78c SyS_clone+0x44/0x50 __sys_trace_return+0x0/0x4 GICv3: CPU0: ICC_SGI1R_EL1 12000 This could be fixed with printk_deferred() but that might lessen its usefulness for debugging. So change it to pr_devel to keep it out of production kernels. Developers working on gic-v3 can enable it as needed in their kernels. Signed-off-by: Mark Salter Signed-off-by: Marc Zyngier Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/irqchip/irq-gic-v3.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c index 848fcdf6a112..3d7374655587 100644 --- a/drivers/irqchip/irq-gic-v3.c +++ b/drivers/irqchip/irq-gic-v3.c @@ -645,7 +645,7 @@ static void gic_send_sgi(u64 cluster_id, u16 tlist, unsigned int irq) MPIDR_TO_SGI_AFFINITY(cluster_id, 1) | tlist << ICC_SGI1R_TARGET_LIST_SHIFT); - pr_debug("CPU%d: ICC_SGI1R_EL1 %llx\n", smp_processor_id(), val); + pr_devel("CPU%d: ICC_SGI1R_EL1 %llx\n", smp_processor_id(), val); gic_write_sgi1r(val); } -- GitLab From 76cd54fa70ce7c02e81bc4c3a06de32cdaa84b29 Mon Sep 17 00:00:00 2001 From: Max Gurtovoy Date: Mon, 5 Mar 2018 20:09:48 +0200 Subject: [PATCH 1035/1635] RDMA/core: Reduce poll batch for direct cq polling [ Upstream commit d3b9e8ad425cfd5b9116732e057f1b48e4d3bcb8 ] Fix warning limit for kernel stack consumption: drivers/infiniband/core/cq.c: In function 'ib_process_cq_direct': drivers/infiniband/core/cq.c:78:1: error: the frame size of 1032 bytes is larger than 1024 bytes [-Werror=frame-larger-than=] Using smaller ib_wc array on the stack brings us comfortably below that limit again. Fixes: 246d8b184c10 ("IB/cq: Don't force IB_POLL_DIRECT poll context for ib_process_cq_direct") Reported-by: Arnd Bergmann Reviewed-by: Sergey Gorenko Signed-off-by: Max Gurtovoy Signed-off-by: Leon Romanovsky Reviewed-by: Bart Van Assche Acked-by: Arnd Bergmann Signed-off-by: Jason Gunthorpe Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/infiniband/core/cq.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/drivers/infiniband/core/cq.c b/drivers/infiniband/core/cq.c index c8c5a5a7f433..757d308bebe8 100644 --- a/drivers/infiniband/core/cq.c +++ b/drivers/infiniband/core/cq.c @@ -17,6 +17,7 @@ /* # of WCs to poll for with a single call to ib_poll_cq */ #define IB_POLL_BATCH 16 +#define IB_POLL_BATCH_DIRECT 8 /* # of WCs to iterate over before yielding */ #define IB_POLL_BUDGET_IRQ 256 @@ -25,18 +26,18 @@ #define IB_POLL_FLAGS \ (IB_CQ_NEXT_COMP | IB_CQ_REPORT_MISSED_EVENTS) -static int __ib_process_cq(struct ib_cq *cq, int budget, struct ib_wc *poll_wc) +static int __ib_process_cq(struct ib_cq *cq, int budget, struct ib_wc *wcs, + int batch) { int i, n, completed = 0; - struct ib_wc *wcs = poll_wc ? : cq->wc; /* * budget might be (-1) if the caller does not * want to bound this call, thus we need unsigned * minimum here. */ - while ((n = ib_poll_cq(cq, min_t(u32, IB_POLL_BATCH, - budget - completed), wcs)) > 0) { + while ((n = ib_poll_cq(cq, min_t(u32, batch, + budget - completed), wcs)) > 0) { for (i = 0; i < n; i++) { struct ib_wc *wc = &wcs[i]; @@ -48,8 +49,7 @@ static int __ib_process_cq(struct ib_cq *cq, int budget, struct ib_wc *poll_wc) completed += n; - if (n != IB_POLL_BATCH || - (budget != -1 && completed >= budget)) + if (n != batch || (budget != -1 && completed >= budget)) break; } @@ -72,9 +72,9 @@ static int __ib_process_cq(struct ib_cq *cq, int budget, struct ib_wc *poll_wc) */ int ib_process_cq_direct(struct ib_cq *cq, int budget) { - struct ib_wc wcs[IB_POLL_BATCH]; + struct ib_wc wcs[IB_POLL_BATCH_DIRECT]; - return __ib_process_cq(cq, budget, wcs); + return __ib_process_cq(cq, budget, wcs, IB_POLL_BATCH_DIRECT); } EXPORT_SYMBOL(ib_process_cq_direct); @@ -88,7 +88,7 @@ static int ib_poll_handler(struct irq_poll *iop, int budget) struct ib_cq *cq = container_of(iop, struct ib_cq, iop); int completed; - completed = __ib_process_cq(cq, budget, NULL); + completed = __ib_process_cq(cq, budget, cq->wc, IB_POLL_BATCH); if (completed < budget) { irq_poll_complete(&cq->iop); if (ib_req_notify_cq(cq, IB_POLL_FLAGS) > 0) @@ -108,7 +108,8 @@ static void ib_cq_poll_work(struct work_struct *work) struct ib_cq *cq = container_of(work, struct ib_cq, work); int completed; - completed = __ib_process_cq(cq, IB_POLL_BUDGET_WORKQUEUE, NULL); + completed = __ib_process_cq(cq, IB_POLL_BUDGET_WORKQUEUE, cq->wc, + IB_POLL_BATCH); if (completed >= IB_POLL_BUDGET_WORKQUEUE || ib_req_notify_cq(cq, IB_POLL_FLAGS) > 0) queue_work(ib_comp_wq, &cq->work); -- GitLab From 89f3232c394e8946905b3c3b57ed593872003d60 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 26 Mar 2018 15:29:57 +0200 Subject: [PATCH 1036/1635] alarmtimer: Init nanosleep alarm timer on stack commit bd03143007eb9b03a7f2316c677780561b68ba2a upstream. syszbot reported the following debugobjects splat: ODEBUG: object is on stack, but not annotated WARNING: CPU: 0 PID: 4185 at lib/debugobjects.c:328 RIP: 0010:debug_object_is_on_stack lib/debugobjects.c:327 [inline] debug_object_init+0x17/0x20 lib/debugobjects.c:391 debug_hrtimer_init kernel/time/hrtimer.c:410 [inline] debug_init kernel/time/hrtimer.c:458 [inline] hrtimer_init+0x8c/0x410 kernel/time/hrtimer.c:1259 alarm_init kernel/time/alarmtimer.c:339 [inline] alarm_timer_nsleep+0x164/0x4d0 kernel/time/alarmtimer.c:787 SYSC_clock_nanosleep kernel/time/posix-timers.c:1226 [inline] SyS_clock_nanosleep+0x235/0x330 kernel/time/posix-timers.c:1204 do_syscall_64+0x281/0x940 arch/x86/entry/common.c:287 entry_SYSCALL_64_after_hwframe+0x42/0xb7 This happens because the hrtimer for the alarm nanosleep is on stack, but the code does not use the proper debug objects initialization. Split out the code for the allocated use cases and invoke hrtimer_init_on_stack() for the nanosleep related functions. Reported-by: syzbot+a3e0726462b2e346a31d@syzkaller.appspotmail.com Signed-off-by: Thomas Gleixner Cc: John Stultz Cc: syzkaller-bugs@googlegroups.com Link: https://lkml.kernel.org/r/alpine.DEB.2.21.1803261528270.1585@nanos.tec.linutronix.de Signed-off-by: Greg Kroah-Hartman --- kernel/time/alarmtimer.c | 34 ++++++++++++++++++++++++++-------- 1 file changed, 26 insertions(+), 8 deletions(-) diff --git a/kernel/time/alarmtimer.c b/kernel/time/alarmtimer.c index ec09ce9a6012..639321bf2e39 100644 --- a/kernel/time/alarmtimer.c +++ b/kernel/time/alarmtimer.c @@ -326,6 +326,17 @@ static int alarmtimer_resume(struct device *dev) } #endif +static void +__alarm_init(struct alarm *alarm, enum alarmtimer_type type, + enum alarmtimer_restart (*function)(struct alarm *, ktime_t)) +{ + timerqueue_init(&alarm->node); + alarm->timer.function = alarmtimer_fired; + alarm->function = function; + alarm->type = type; + alarm->state = ALARMTIMER_STATE_INACTIVE; +} + /** * alarm_init - Initialize an alarm structure * @alarm: ptr to alarm to be initialized @@ -335,13 +346,9 @@ static int alarmtimer_resume(struct device *dev) void alarm_init(struct alarm *alarm, enum alarmtimer_type type, enum alarmtimer_restart (*function)(struct alarm *, ktime_t)) { - timerqueue_init(&alarm->node); hrtimer_init(&alarm->timer, alarm_bases[type].base_clockid, - HRTIMER_MODE_ABS); - alarm->timer.function = alarmtimer_fired; - alarm->function = function; - alarm->type = type; - alarm->state = ALARMTIMER_STATE_INACTIVE; + HRTIMER_MODE_ABS); + __alarm_init(alarm, type, function); } EXPORT_SYMBOL_GPL(alarm_init); @@ -719,6 +726,8 @@ static int alarmtimer_do_nsleep(struct alarm *alarm, ktime_t absexp, __set_current_state(TASK_RUNNING); + destroy_hrtimer_on_stack(&alarm->timer); + if (!alarm->data) return 0; @@ -740,6 +749,15 @@ static int alarmtimer_do_nsleep(struct alarm *alarm, ktime_t absexp, return -ERESTART_RESTARTBLOCK; } +static void +alarm_init_on_stack(struct alarm *alarm, enum alarmtimer_type type, + enum alarmtimer_restart (*function)(struct alarm *, ktime_t)) +{ + hrtimer_init_on_stack(&alarm->timer, alarm_bases[type].base_clockid, + HRTIMER_MODE_ABS); + __alarm_init(alarm, type, function); +} + /** * alarm_timer_nsleep_restart - restartblock alarmtimer nsleep * @restart: ptr to restart block @@ -752,7 +770,7 @@ static long __sched alarm_timer_nsleep_restart(struct restart_block *restart) ktime_t exp = restart->nanosleep.expires; struct alarm alarm; - alarm_init(&alarm, type, alarmtimer_nsleep_wakeup); + alarm_init_on_stack(&alarm, type, alarmtimer_nsleep_wakeup); return alarmtimer_do_nsleep(&alarm, exp, type); } @@ -784,7 +802,7 @@ static int alarm_timer_nsleep(const clockid_t which_clock, int flags, if (!capable(CAP_WAKE_ALARM)) return -EPERM; - alarm_init(&alarm, type, alarmtimer_nsleep_wakeup); + alarm_init_on_stack(&alarm, type, alarmtimer_nsleep_wakeup); exp = timespec64_to_ktime(*tsreq); /* Convert (if necessary) to absolute time */ -- GitLab From fab0b3ce67a54f45848ee5d6023ef9a42153a2c9 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Tue, 27 Feb 2018 19:42:31 +0100 Subject: [PATCH 1037/1635] netfilter: x_tables: cap allocations at 512 mbyte commit 19926968ea86a286aa6fbea16ee3f2e7442f10f0 upstream. Arbitrary limit, however, this still allows huge rulesets (> 1 million rules). This helps with automated fuzzer as it prevents oom-killer invocation. Signed-off-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso Signed-off-by: Greg Kroah-Hartman --- net/netfilter/x_tables.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c index a450a1c8804b..d1d29015d91f 100644 --- a/net/netfilter/x_tables.c +++ b/net/netfilter/x_tables.c @@ -40,6 +40,7 @@ MODULE_AUTHOR("Harald Welte "); MODULE_DESCRIPTION("{ip,ip6,arp,eb}_tables backend module"); #define XT_PCPU_BLOCK_SIZE 4096 +#define XT_MAX_TABLE_SIZE (512 * 1024 * 1024) struct compat_delta { unsigned int offset; /* offset in kernel */ @@ -1031,7 +1032,7 @@ struct xt_table_info *xt_alloc_table_info(unsigned int size) struct xt_table_info *info = NULL; size_t sz = sizeof(*info) + size; - if (sz < sizeof(*info)) + if (sz < sizeof(*info) || sz >= XT_MAX_TABLE_SIZE) return NULL; /* Pedantry: prevent them from hitting BUG() in vmalloc.c --RR */ -- GitLab From 82b68ecde5d056588799f0d38e675bbb81fe3b46 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Tue, 27 Feb 2018 19:42:33 +0100 Subject: [PATCH 1038/1635] netfilter: x_tables: add counters allocation wrapper commit c84ca954ac9fa67a6ce27f91f01e4451c74fd8f6 upstream. allows to have size checks in a single spot. This is supposed to reduce oom situations when fuzz-testing xtables. Signed-off-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso Signed-off-by: Greg Kroah-Hartman --- include/linux/netfilter/x_tables.h | 1 + net/ipv4/netfilter/arp_tables.c | 2 +- net/ipv4/netfilter/ip_tables.c | 2 +- net/ipv6/netfilter/ip6_tables.c | 2 +- net/netfilter/x_tables.c | 15 +++++++++++++++ 5 files changed, 19 insertions(+), 3 deletions(-) diff --git a/include/linux/netfilter/x_tables.h b/include/linux/netfilter/x_tables.h index 8e46c35d654b..56c4ed8c91b8 100644 --- a/include/linux/netfilter/x_tables.h +++ b/include/linux/netfilter/x_tables.h @@ -301,6 +301,7 @@ int xt_data_to_user(void __user *dst, const void *src, void *xt_copy_counters_from_user(const void __user *user, unsigned int len, struct xt_counters_info *info, bool compat); +struct xt_counters *xt_counters_alloc(unsigned int counters); struct xt_table *xt_register_table(struct net *net, const struct xt_table *table, diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c index aa4c3b7f7da4..e77ee449831c 100644 --- a/net/ipv4/netfilter/arp_tables.c +++ b/net/ipv4/netfilter/arp_tables.c @@ -883,7 +883,7 @@ static int __do_replace(struct net *net, const char *name, struct arpt_entry *iter; ret = 0; - counters = vzalloc(num_counters * sizeof(struct xt_counters)); + counters = xt_counters_alloc(num_counters); if (!counters) { ret = -ENOMEM; goto out; diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c index cadb82a906b8..a7a3f1d66d0a 100644 --- a/net/ipv4/netfilter/ip_tables.c +++ b/net/ipv4/netfilter/ip_tables.c @@ -1044,7 +1044,7 @@ __do_replace(struct net *net, const char *name, unsigned int valid_hooks, struct ipt_entry *iter; ret = 0; - counters = vzalloc(num_counters * sizeof(struct xt_counters)); + counters = xt_counters_alloc(num_counters); if (!counters) { ret = -ENOMEM; goto out; diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c index a0a31972fc75..fad6b384836d 100644 --- a/net/ipv6/netfilter/ip6_tables.c +++ b/net/ipv6/netfilter/ip6_tables.c @@ -1063,7 +1063,7 @@ __do_replace(struct net *net, const char *name, unsigned int valid_hooks, struct ip6t_entry *iter; ret = 0; - counters = vzalloc(num_counters * sizeof(struct xt_counters)); + counters = xt_counters_alloc(num_counters); if (!counters) { ret = -ENOMEM; goto out; diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c index d1d29015d91f..9c38627e09ea 100644 --- a/net/netfilter/x_tables.c +++ b/net/netfilter/x_tables.c @@ -1187,6 +1187,21 @@ static int xt_jumpstack_alloc(struct xt_table_info *i) return 0; } +struct xt_counters *xt_counters_alloc(unsigned int counters) +{ + struct xt_counters *mem; + + if (counters == 0 || counters > INT_MAX / sizeof(*mem)) + return NULL; + + counters *= sizeof(*mem); + if (counters > XT_MAX_TABLE_SIZE) + return NULL; + + return vzalloc(counters); +} +EXPORT_SYMBOL(xt_counters_alloc); + struct xt_table_info * xt_replace_table(struct xt_table *table, unsigned int num_counters, -- GitLab From 8d92d53365395c97cf819a10cda4693f792cd5b6 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Tue, 27 Feb 2018 19:42:34 +0100 Subject: [PATCH 1039/1635] netfilter: compat: prepare xt_compat_init_offsets to return errors commit 9782a11efc072faaf91d4aa60e9d23553f918029 upstream. should have no impact, function still always returns 0. This patch is only to ease review. Signed-off-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso Signed-off-by: Greg Kroah-Hartman --- include/linux/netfilter/x_tables.h | 2 +- net/bridge/netfilter/ebtables.c | 10 ++++++++-- net/ipv4/netfilter/arp_tables.c | 10 +++++++--- net/ipv4/netfilter/ip_tables.c | 8 ++++++-- net/ipv6/netfilter/ip6_tables.c | 10 +++++++--- net/netfilter/x_tables.c | 4 +++- 6 files changed, 32 insertions(+), 12 deletions(-) diff --git a/include/linux/netfilter/x_tables.h b/include/linux/netfilter/x_tables.h index 56c4ed8c91b8..54f346a45cd0 100644 --- a/include/linux/netfilter/x_tables.h +++ b/include/linux/netfilter/x_tables.h @@ -508,7 +508,7 @@ void xt_compat_unlock(u_int8_t af); int xt_compat_add_offset(u_int8_t af, unsigned int offset, int delta); void xt_compat_flush_offsets(u_int8_t af); -void xt_compat_init_offsets(u_int8_t af, unsigned int number); +int xt_compat_init_offsets(u8 af, unsigned int number); int xt_compat_calc_jump(u_int8_t af, unsigned int offset); int xt_compat_match_offset(const struct xt_match *match); diff --git a/net/bridge/netfilter/ebtables.c b/net/bridge/netfilter/ebtables.c index 16eb99458df4..014a73b46064 100644 --- a/net/bridge/netfilter/ebtables.c +++ b/net/bridge/netfilter/ebtables.c @@ -1819,10 +1819,14 @@ static int compat_table_info(const struct ebt_table_info *info, { unsigned int size = info->entries_size; const void *entries = info->entries; + int ret; newinfo->entries_size = size; - xt_compat_init_offsets(NFPROTO_BRIDGE, info->nentries); + ret = xt_compat_init_offsets(NFPROTO_BRIDGE, info->nentries); + if (ret) + return ret; + return EBT_ENTRY_ITERATE(entries, size, compat_calc_entry, info, entries, newinfo); } @@ -2257,7 +2261,9 @@ static int compat_do_replace(struct net *net, void __user *user, xt_compat_lock(NFPROTO_BRIDGE); - xt_compat_init_offsets(NFPROTO_BRIDGE, tmp.nentries); + ret = xt_compat_init_offsets(NFPROTO_BRIDGE, tmp.nentries); + if (ret < 0) + goto out_unlock; ret = compat_copy_entries(entries_tmp, tmp.entries_size, &state); if (ret < 0) goto out_unlock; diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c index e77ee449831c..356ae7da4f16 100644 --- a/net/ipv4/netfilter/arp_tables.c +++ b/net/ipv4/netfilter/arp_tables.c @@ -768,7 +768,9 @@ static int compat_table_info(const struct xt_table_info *info, memcpy(newinfo, info, offsetof(struct xt_table_info, entries)); newinfo->initial_entries = 0; loc_cpu_entry = info->entries; - xt_compat_init_offsets(NFPROTO_ARP, info->number); + ret = xt_compat_init_offsets(NFPROTO_ARP, info->number); + if (ret) + return ret; xt_entry_foreach(iter, loc_cpu_entry, info->size) { ret = compat_calc_entry(iter, info, loc_cpu_entry, newinfo); if (ret != 0) @@ -1157,7 +1159,7 @@ static int translate_compat_table(struct xt_table_info **pinfo, struct compat_arpt_entry *iter0; struct arpt_replace repl; unsigned int size; - int ret = 0; + int ret; info = *pinfo; entry0 = *pentry0; @@ -1166,7 +1168,9 @@ static int translate_compat_table(struct xt_table_info **pinfo, j = 0; xt_compat_lock(NFPROTO_ARP); - xt_compat_init_offsets(NFPROTO_ARP, compatr->num_entries); + ret = xt_compat_init_offsets(NFPROTO_ARP, compatr->num_entries); + if (ret) + goto out_unlock; /* Walk through entries, checking offsets. */ xt_entry_foreach(iter0, entry0, compatr->size) { ret = check_compat_entry_size_and_hooks(iter0, info, &size, diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c index a7a3f1d66d0a..1a925f2394ad 100644 --- a/net/ipv4/netfilter/ip_tables.c +++ b/net/ipv4/netfilter/ip_tables.c @@ -931,7 +931,9 @@ static int compat_table_info(const struct xt_table_info *info, memcpy(newinfo, info, offsetof(struct xt_table_info, entries)); newinfo->initial_entries = 0; loc_cpu_entry = info->entries; - xt_compat_init_offsets(AF_INET, info->number); + ret = xt_compat_init_offsets(AF_INET, info->number); + if (ret) + return ret; xt_entry_foreach(iter, loc_cpu_entry, info->size) { ret = compat_calc_entry(iter, info, loc_cpu_entry, newinfo); if (ret != 0) @@ -1407,7 +1409,9 @@ translate_compat_table(struct net *net, j = 0; xt_compat_lock(AF_INET); - xt_compat_init_offsets(AF_INET, compatr->num_entries); + ret = xt_compat_init_offsets(AF_INET, compatr->num_entries); + if (ret) + goto out_unlock; /* Walk through entries, checking offsets. */ xt_entry_foreach(iter0, entry0, compatr->size) { ret = check_compat_entry_size_and_hooks(iter0, info, &size, diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c index fad6b384836d..c5fe42e6b7f7 100644 --- a/net/ipv6/netfilter/ip6_tables.c +++ b/net/ipv6/netfilter/ip6_tables.c @@ -949,7 +949,9 @@ static int compat_table_info(const struct xt_table_info *info, memcpy(newinfo, info, offsetof(struct xt_table_info, entries)); newinfo->initial_entries = 0; loc_cpu_entry = info->entries; - xt_compat_init_offsets(AF_INET6, info->number); + ret = xt_compat_init_offsets(AF_INET6, info->number); + if (ret) + return ret; xt_entry_foreach(iter, loc_cpu_entry, info->size) { ret = compat_calc_entry(iter, info, loc_cpu_entry, newinfo); if (ret != 0) @@ -1415,7 +1417,7 @@ translate_compat_table(struct net *net, struct compat_ip6t_entry *iter0; struct ip6t_replace repl; unsigned int size; - int ret = 0; + int ret; info = *pinfo; entry0 = *pentry0; @@ -1424,7 +1426,9 @@ translate_compat_table(struct net *net, j = 0; xt_compat_lock(AF_INET6); - xt_compat_init_offsets(AF_INET6, compatr->num_entries); + ret = xt_compat_init_offsets(AF_INET6, compatr->num_entries); + if (ret) + goto out_unlock; /* Walk through entries, checking offsets. */ xt_entry_foreach(iter0, entry0, compatr->size) { ret = check_compat_entry_size_and_hooks(iter0, info, &size, diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c index 9c38627e09ea..7ad3d861cb83 100644 --- a/net/netfilter/x_tables.c +++ b/net/netfilter/x_tables.c @@ -605,10 +605,12 @@ int xt_compat_calc_jump(u_int8_t af, unsigned int offset) } EXPORT_SYMBOL_GPL(xt_compat_calc_jump); -void xt_compat_init_offsets(u_int8_t af, unsigned int number) +int xt_compat_init_offsets(u8 af, unsigned int number) { xt[af].number = number; xt[af].cur = 0; + + return 0; } EXPORT_SYMBOL(xt_compat_init_offsets); -- GitLab From 764f2162d97a498269c9b67607fe163692a79aa7 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Tue, 27 Feb 2018 19:42:35 +0100 Subject: [PATCH 1040/1635] netfilter: compat: reject huge allocation requests commit 7d7d7e02111e9a4dc9d0658597f528f815d820fd upstream. no need to bother even trying to allocating huge compat offset arrays, such ruleset is rejected later on anyway becaus we refuse to allocate overly large rule blobs. However, compat translation happens before blob allocation, so we should add a check there too. This is supposed to help with fuzzing by avoiding oom-killer. Signed-off-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso Signed-off-by: Greg Kroah-Hartman --- net/netfilter/x_tables.c | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c index 7ad3d861cb83..926e7d76ac2e 100644 --- a/net/netfilter/x_tables.c +++ b/net/netfilter/x_tables.c @@ -555,14 +555,8 @@ int xt_compat_add_offset(u_int8_t af, unsigned int offset, int delta) { struct xt_af *xp = &xt[af]; - if (!xp->compat_tab) { - if (!xp->number) - return -EINVAL; - xp->compat_tab = vmalloc(sizeof(struct compat_delta) * xp->number); - if (!xp->compat_tab) - return -ENOMEM; - xp->cur = 0; - } + if (WARN_ON(!xp->compat_tab)) + return -ENOMEM; if (xp->cur >= xp->number) return -EINVAL; @@ -607,6 +601,22 @@ EXPORT_SYMBOL_GPL(xt_compat_calc_jump); int xt_compat_init_offsets(u8 af, unsigned int number) { + size_t mem; + + if (!number || number > (INT_MAX / sizeof(struct compat_delta))) + return -EINVAL; + + if (WARN_ON(xt[af].compat_tab)) + return -EINVAL; + + mem = sizeof(struct compat_delta) * number; + if (mem > XT_MAX_TABLE_SIZE) + return -ENOMEM; + + xt[af].compat_tab = vmalloc(mem); + if (!xt[af].compat_tab) + return -ENOMEM; + xt[af].number = number; xt[af].cur = 0; -- GitLab From 5bcf169444540cbb8646cb415087f5ec83f60432 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Tue, 27 Feb 2018 19:42:32 +0100 Subject: [PATCH 1041/1635] netfilter: x_tables: limit allocation requests for blob rule heads commit 9d5c12a7c08f67999772065afd50fb222072114e upstream. This is a very conservative limit (134217728 rules), but good enough to not trigger frequent oom from syzkaller. Signed-off-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso Signed-off-by: Greg Kroah-Hartman --- net/netfilter/x_tables.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c index 926e7d76ac2e..8e054c63b54e 100644 --- a/net/netfilter/x_tables.c +++ b/net/netfilter/x_tables.c @@ -819,6 +819,9 @@ EXPORT_SYMBOL(xt_check_entry_offsets); */ unsigned int *xt_alloc_entry_offsets(unsigned int size) { + if (size > XT_MAX_TABLE_SIZE / sizeof(unsigned int)) + return NULL; + return kvmalloc_array(size, sizeof(unsigned int), GFP_KERNEL | __GFP_ZERO); } -- GitLab From 66038084560d12457f4dd9e5cfb1d7a7859f70a2 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Sun, 15 Apr 2018 11:23:51 +0200 Subject: [PATCH 1042/1635] perf: Fix sample_max_stack maximum check commit 5af44ca53d019de47efe6dbc4003dd518e5197ed upstream. The syzbot hit KASAN bug in perf_callchain_store having the entry stored behind the allocated bounds [1]. We miss the sample_max_stack check for the initial event that allocates callchain buffers. This missing check allows to create an event with sample_max_stack value bigger than the global sysctl maximum: # sysctl -a | grep perf_event_max_stack kernel.perf_event_max_stack = 127 # perf record -vv -C 1 -e cycles/max-stack=256/ kill ... perf_event_attr: size 112 ... sample_max_stack 256 ------------------------------------------------------------ sys_perf_event_open: pid -1 cpu 1 group_fd -1 flags 0x8 = 4 Note the '-C 1', which forces perf record to create just single event. Otherwise it opens event for every cpu, then the sample_max_stack check fails on the second event and all's fine. The fix is to run the sample_max_stack check also for the first event with callchains. [1] https://marc.info/?l=linux-kernel&m=152352732920874&w=2 Reported-by: syzbot+7c449856228b63ac951e@syzkaller.appspotmail.com Signed-off-by: Jiri Olsa Cc: Alexander Shishkin Cc: Andi Kleen Cc: H. Peter Anvin Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: syzkaller-bugs@googlegroups.com Cc: x86@kernel.org Fixes: 97c79a38cd45 ("perf core: Per event callchain limit") Link: http://lkml.kernel.org/r/20180415092352.12403-2-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: Greg Kroah-Hartman --- kernel/events/callchain.c | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/kernel/events/callchain.c b/kernel/events/callchain.c index 1b2be63c8528..fa4f47a0a631 100644 --- a/kernel/events/callchain.c +++ b/kernel/events/callchain.c @@ -119,19 +119,22 @@ int get_callchain_buffers(int event_max_stack) goto exit; } + /* + * If requesting per event more than the global cap, + * return a different error to help userspace figure + * this out. + * + * And also do it here so that we have &callchain_mutex held. + */ + if (event_max_stack > sysctl_perf_event_max_stack) { + err = -EOVERFLOW; + goto exit; + } + if (count > 1) { /* If the allocation failed, give up */ if (!callchain_cpus_entries) err = -ENOMEM; - /* - * If requesting per event more than the global cap, - * return a different error to help userspace figure - * this out. - * - * And also do it here so that we have &callchain_mutex held. - */ - if (event_max_stack > sysctl_perf_event_max_stack) - err = -EOVERFLOW; goto exit; } -- GitLab From 01e71c218219fe40c620a53b2d37beafd95c4e14 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Sun, 15 Apr 2018 11:23:50 +0200 Subject: [PATCH 1043/1635] perf: Return proper values for user stack errors commit 78b562fbfa2cf0a9fcb23c3154756b690f4905c1 upstream. Return immediately when we find issue in the user stack checks. The error value could get overwritten by following check for PERF_SAMPLE_REGS_INTR. Signed-off-by: Jiri Olsa Cc: Alexander Shishkin Cc: Andi Kleen Cc: H. Peter Anvin Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Thomas Gleixner Cc: syzkaller-bugs@googlegroups.com Cc: x86@kernel.org Fixes: 60e2364e60e8 ("perf: Add ability to sample machine state on interrupt") Link: http://lkml.kernel.org/r/20180415092352.12403-1-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: Greg Kroah-Hartman --- kernel/events/core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kernel/events/core.c b/kernel/events/core.c index e9b0beca830f..cb8274d7824f 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -9750,9 +9750,9 @@ static int perf_copy_attr(struct perf_event_attr __user *uattr, * __u16 sample size limit. */ if (attr->sample_stack_user >= USHRT_MAX) - ret = -EINVAL; + return -EINVAL; else if (!IS_ALIGNED(attr->sample_stack_user, sizeof(u64))) - ret = -EINVAL; + return -EINVAL; } if (attr->sample_type & PERF_SAMPLE_REGS_INTR) -- GitLab From 75dceb6872b3526a5269a28553f9a35972d03bba Mon Sep 17 00:00:00 2001 From: Leon Romanovsky Date: Sun, 11 Mar 2018 13:51:32 +0200 Subject: [PATCH 1044/1635] RDMA/mlx5: Fix NULL dereference while accessing XRC_TGT QPs commit 75a4598209cbe45540baa316c3b51d9db222e96e upstream. mlx5 modify_qp() relies on FW that the error will be thrown if wrong state is supplied. The missing check in FW causes the following crash while using XRC_TGT QPs. [ 14.769632] BUG: unable to handle kernel NULL pointer dereference at (null) [ 14.771085] IP: mlx5_ib_modify_qp+0xf60/0x13f0 [ 14.771894] PGD 800000001472e067 P4D 800000001472e067 PUD 14529067 PMD 0 [ 14.773126] Oops: 0002 [#1] SMP PTI [ 14.773763] CPU: 0 PID: 365 Comm: ubsan Not tainted 4.16.0-rc1-00038-g8151138c0793 #119 [ 14.775192] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.7.5-0-ge51488c-20140602_164612-nilsson.home.kraxel.org 04/01/2014 [ 14.777522] RIP: 0010:mlx5_ib_modify_qp+0xf60/0x13f0 [ 14.778417] RSP: 0018:ffffbf48001c7bd8 EFLAGS: 00010246 [ 14.779346] RAX: 0000000000000000 RBX: ffff9a8f9447d400 RCX: 0000000000000000 [ 14.780643] RDX: 0000000000000000 RSI: 000000000000000a RDI: 0000000000000000 [ 14.781930] RBP: 0000000000000000 R08: 00000000000217b0 R09: ffffffffbc9c1504 [ 14.783214] R10: fffff4a180519480 R11: ffff9a8f94523600 R12: ffff9a8f9493e240 [ 14.784507] R13: ffff9a8f9447d738 R14: 000000000000050a R15: 0000000000000000 [ 14.785800] FS: 00007f545b466700(0000) GS:ffff9a8f9fc00000(0000) knlGS:0000000000000000 [ 14.787073] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 14.787792] CR2: 0000000000000000 CR3: 00000000144be000 CR4: 00000000000006b0 [ 14.788689] Call Trace: [ 14.789007] _ib_modify_qp+0x71/0x120 [ 14.789475] modify_qp.isra.20+0x207/0x2f0 [ 14.790010] ib_uverbs_modify_qp+0x90/0xe0 [ 14.790532] ib_uverbs_write+0x1d2/0x3c0 [ 14.791049] ? __handle_mm_fault+0x93c/0xe40 [ 14.791644] __vfs_write+0x36/0x180 [ 14.792096] ? handle_mm_fault+0xc1/0x210 [ 14.792601] vfs_write+0xad/0x1e0 [ 14.793018] SyS_write+0x52/0xc0 [ 14.793422] do_syscall_64+0x75/0x180 [ 14.793888] entry_SYSCALL_64_after_hwframe+0x21/0x86 [ 14.794527] RIP: 0033:0x7f545ad76099 [ 14.794975] RSP: 002b:00007ffd78787468 EFLAGS: 00000287 ORIG_RAX: 0000000000000001 [ 14.795958] RAX: ffffffffffffffda RBX: 0000000000000000 RCX: 00007f545ad76099 [ 14.797075] RDX: 0000000000000078 RSI: 0000000020009000 RDI: 0000000000000003 [ 14.798140] RBP: 00007ffd78787470 R08: 00007ffd78787480 R09: 00007ffd78787480 [ 14.799207] R10: 00007ffd78787480 R11: 0000000000000287 R12: 00005599ada98760 [ 14.800277] R13: 00007ffd78787560 R14: 0000000000000000 R15: 0000000000000000 [ 14.801341] Code: 4c 8b 1c 24 48 8b 83 70 02 00 00 48 c7 83 cc 02 00 00 00 00 00 00 48 c7 83 24 03 00 00 00 00 00 00 c7 83 2c 03 00 00 00 00 00 00 00 00 00 00 00 48 8b 83 70 02 00 00 c7 40 04 00 00 00 00 4c [ 14.804012] RIP: mlx5_ib_modify_qp+0xf60/0x13f0 RSP: ffffbf48001c7bd8 [ 14.804838] CR2: 0000000000000000 [ 14.805288] ---[ end trace 3f1da0df5c8b7c37 ]--- Cc: syzkaller Reported-by: Maor Gottlieb Signed-off-by: Leon Romanovsky Signed-off-by: Doug Ledford Signed-off-by: Greg Kroah-Hartman --- drivers/infiniband/hw/mlx5/qp.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/infiniband/hw/mlx5/qp.c b/drivers/infiniband/hw/mlx5/qp.c index e1978d91a2f7..464c78f8cec9 100644 --- a/drivers/infiniband/hw/mlx5/qp.c +++ b/drivers/infiniband/hw/mlx5/qp.c @@ -2923,7 +2923,8 @@ static int __mlx5_ib_modify_qp(struct ib_qp *ibqp, * If we moved a kernel QP to RESET, clean up all old CQ * entries and reinitialize the QP. */ - if (new_state == IB_QPS_RESET && !ibqp->uobject) { + if (new_state == IB_QPS_RESET && + !ibqp->uobject && ibqp->qp_type != IB_QPT_XRC_TGT) { mlx5_ib_cq_clean(recv_cq, base->mqp.qpn, ibqp->srq ? to_msrq(ibqp->srq) : NULL); if (send_cq != recv_cq) -- GitLab From 679833ea18221fe703ebf56213c1b1ca1731bad6 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Thu, 29 Mar 2018 14:48:30 -0700 Subject: [PATCH 1045/1635] Revert "KVM: X86: Fix SMRAM accessing even if VM is shutdown" commit 2c151b25441ae5c2da66472abd165af785c9ecd2 upstream. The bug that led to commit 95e057e25892eaa48cad1e2d637b80d0f1a4fac5 was a benign warning (no adverse affects other than the warning itself) that was detected by syzkaller. Further inspection shows that the WARN_ON in question, in handle_ept_misconfig(), is unnecessary and flawed (this was also briefly discussed in the original patch: https://patchwork.kernel.org/patch/10204649). * The WARN_ON is unnecessary as kvm_mmu_page_fault() will WARN if reserved bits are set in the SPTEs, i.e. it covers the case where an EPT misconfig occurred because of a KVM bug. * The WARN_ON is flawed because it will fire on any system error code that is hit while handling the fault, e.g. -ENOMEM can be returned by mmu_topup_memory_caches() while handling a legitmate MMIO EPT misconfig. The original behavior of returning -EFAULT when userspace munmaps an HVA without first removing the memslot is correct and desirable, i.e. KVM is letting userspace know it has generated a bad address. Returning RET_PF_EMULATE masks the WARN_ON in the EPT misconfig path, but does not fix the underlying bug, i.e. the WARN_ON is bogus. Furthermore, returning RET_PF_EMULATE has the unwanted side effect of causing KVM to attempt to emulate an instruction on any page fault with an invalid HVA translation, e.g. a not-present EPT violation on a VM_PFNMAP VMA whose fault handler failed to insert a PFN. * There is no guarantee that the fault is directly related to the instruction, i.e. the fault could have been triggered by a side effect memory access in the guest, e.g. while vectoring a #DB or writing a tracing record. This could cause KVM to effectively mask the fault if KVM doesn't model the behavior leading to the fault, i.e. emulation could succeed and resume the guest. * If emulation does fail, KVM will return EMULATION_FAILED instead of -EFAULT, which is a red herring as the user will either debug a bogus emulation attempt or scratch their head wondering why we were attempting emulation in the first place. TL;DR: revert to returning -EFAULT and remove the bogus WARN_ON in handle_ept_misconfig in a future patch. This reverts commit 95e057e25892eaa48cad1e2d637b80d0f1a4fac5. Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini Signed-off-by: Greg Kroah-Hartman --- arch/x86/kvm/mmu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c index f438e0c4aa8c..43bbece92632 100644 --- a/arch/x86/kvm/mmu.c +++ b/arch/x86/kvm/mmu.c @@ -3019,7 +3019,7 @@ static int kvm_handle_bad_page(struct kvm_vcpu *vcpu, gfn_t gfn, kvm_pfn_t pfn) return RET_PF_RETRY; } - return RET_PF_EMULATE; + return -EFAULT; } static void transparent_hugepage_adjust(struct kvm_vcpu *vcpu, -- GitLab From f606893fbbc64d68510c5cc3e64e39971e5f26e0 Mon Sep 17 00:00:00 2001 From: Benjamin Beichler Date: Wed, 7 Mar 2018 18:11:07 +0100 Subject: [PATCH 1046/1635] mac80211_hwsim: fix use-after-free bug in hwsim_exit_net commit 8cfd36a0b53aeb4ec21d81eb79706697b84dfc3d upstream. When destroying a net namespace, all hwsim interfaces, which are not created in default namespace are deleted. But the async deletion of the interfaces could last longer than the actual destruction of the namespace, which results to an use after free bug. Therefore use synchronous deletion in this case. Fixes: 100cb9ff40e0 ("mac80211_hwsim: Allow managing radios from non-initial namespaces") Reported-by: syzbot+70ce058e01259de7bb1d@syzkaller.appspotmail.com Signed-off-by: Benjamin Beichler Signed-off-by: Johannes Berg Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/mac80211_hwsim.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 977fd7aa2082..d686ba10fecc 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -3427,8 +3427,11 @@ static void __net_exit hwsim_exit_net(struct net *net) continue; list_del(&data->list); - INIT_WORK(&data->destroy_work, destroy_radio); - schedule_work(&data->destroy_work); + spin_unlock_bh(&hwsim_radio_lock); + mac80211_hwsim_del_radio(data, wiphy_name(data->hw->wiphy), + NULL); + spin_lock_bh(&hwsim_radio_lock); + } spin_unlock_bh(&hwsim_radio_lock); } -- GitLab From 753be7e83bb80128b4a2aa24214c98466905827c Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 26 Apr 2018 11:02:22 +0200 Subject: [PATCH 1047/1635] Linux 4.14.37 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 0a1f941899f4..ee330f5449e6 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 VERSION = 4 PATCHLEVEL = 14 -SUBLEVEL = 36 +SUBLEVEL = 37 EXTRAVERSION = NAME = Petit Gorille -- GitLab From 17c597fda70e665a68ea99d5d1407c05bb976230 Mon Sep 17 00:00:00 2001 From: Vinayak Menon Date: Fri, 23 Mar 2018 11:25:43 +0530 Subject: [PATCH 1048/1635] mm: ratelimit swap write errors Ratelimit the swap write errors to avoid logbuf getting filled up by these messages. These pages remove the useful page allocation failure messages (when zram is used as swap) from logbuf, thus making the debugging difficult. Change-Id: I9d4229a76b2551d7baca603112d53012d8722415 Signed-off-by: Vinayak Menon Signed-off-by: Charan Teja Reddy --- mm/page_io.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/mm/page_io.c b/mm/page_io.c index 5d882de3fbfd..624f1e2f2d34 100644 --- a/mm/page_io.c +++ b/mm/page_io.c @@ -63,8 +63,9 @@ void end_swap_bio_write(struct bio *bio) * Also clear PG_reclaim to avoid rotate_reclaimable_page() */ set_page_dirty(page); - pr_alert("Write-error on swap-device (%u:%u:%llu)\n", - MAJOR(bio_dev(bio)), MINOR(bio_dev(bio)), + pr_alert_ratelimited("Write-error on swap-device (%u:%u:%llu)\n", + MAJOR(bio_dev(bio)), + MINOR(bio_dev(bio)), (unsigned long long)bio->bi_iter.bi_sector); ClearPageReclaim(page); } -- GitLab From 4fc4613635c1254a5f068d91f2407ab64936ed84 Mon Sep 17 00:00:00 2001 From: Rohit Vaswani Date: Thu, 7 Feb 2013 12:15:11 -0800 Subject: [PATCH 1049/1635] Revert "ARM: dma-mapping: remove dmac_clean_range and dmac_inv_range" This partially reverts 'commit 702b94bff3c505 ("ARM: dma-mapping: remove dmac_clean_range and dmac_inv_range")' Some MSM drivers still use the dmac_clean and dmac_inv_range APIs. Bring back the defines and exports for v7 CPUs. Change-Id: I69017d73da1065a5eeb9c87c899b6a51be5ebfe6 Signed-off-by: Rohit Vaswani Signed-off-by: Abhimanyu Kapur [sramana: resolved minor merge conflicts] Signed-off-by: Srinivas Ramana [akdwived: Made change for checkpatch error] Signed-off-by: Avaneesh Kumar Dwivedi --- arch/arm/include/asm/cacheflush.h | 21 +++++++++++++++++++++ arch/arm/include/asm/glue-cache.h | 2 ++ arch/arm/mm/cache-v7.S | 4 ++-- arch/arm/mm/proc-macros.S | 2 ++ arch/arm/mm/proc-syms.c | 3 +++ 5 files changed, 30 insertions(+), 2 deletions(-) diff --git a/arch/arm/include/asm/cacheflush.h b/arch/arm/include/asm/cacheflush.h index 74504b154256..f7ba4389f0fa 100644 --- a/arch/arm/include/asm/cacheflush.h +++ b/arch/arm/include/asm/cacheflush.h @@ -94,6 +94,21 @@ * DMA Cache Coherency * =================== * + * dma_inv_range(start, end) + * + * Invalidate (discard) the specified virtual address range. + * May not write back any entries. If 'start' or 'end' + * are not cache line aligned, those lines must be written + * back. + * - start - virtual start address + * - end - virtual end address + * + * dma_clean_range(start, end) + * + * Clean (write back) the specified virtual address range. + * - start - virtual start address + * - end - virtual end address + * * dma_flush_range(start, end) * * Clean and invalidate the specified virtual address range. @@ -115,6 +130,8 @@ struct cpu_cache_fns { void (*dma_map_area)(const void *, size_t, int); void (*dma_unmap_area)(const void *, size_t, int); + void (*dma_inv_range)(const void *, const void *); + void (*dma_clean_range)(const void *, const void *); void (*dma_flush_range)(const void *, const void *); } __no_randomize_layout; @@ -140,6 +157,8 @@ extern struct cpu_cache_fns cpu_cache; * is visible to DMA, or data written by DMA to system memory is * visible to the CPU. */ +#define dmac_inv_range cpu_cache.dma_inv_range +#define dmac_clean_range cpu_cache.dma_clean_range #define dmac_flush_range cpu_cache.dma_flush_range #else @@ -159,6 +178,8 @@ extern void __cpuc_flush_dcache_area(void *, size_t); * is visible to DMA, or data written by DMA to system memory is * visible to the CPU. */ +extern void dmac_inv_range(const void *start, const void *end); +extern void dmac_clean_range(const void *start, const void *end); extern void dmac_flush_range(const void *, const void *); #endif diff --git a/arch/arm/include/asm/glue-cache.h b/arch/arm/include/asm/glue-cache.h index 01c3d92624e5..d14f31047a5c 100644 --- a/arch/arm/include/asm/glue-cache.h +++ b/arch/arm/include/asm/glue-cache.h @@ -155,6 +155,8 @@ static inline void nop_dma_unmap_area(const void *s, size_t l, int f) { } #define __cpuc_flush_dcache_area __glue(_CACHE,_flush_kern_dcache_area) #define dmac_flush_range __glue(_CACHE,_dma_flush_range) +#define dmac_inv_range __glue(_CACHE, _dma_inv_range) +#define dmac_clean_range __glue(_CACHE, _dma_clean_range) #endif #endif diff --git a/arch/arm/mm/cache-v7.S b/arch/arm/mm/cache-v7.S index de78109d002d..4c850aa3af2b 100644 --- a/arch/arm/mm/cache-v7.S +++ b/arch/arm/mm/cache-v7.S @@ -349,7 +349,7 @@ ENDPROC(v7_flush_kern_dcache_area) * - start - virtual start address of region * - end - virtual end address of region */ -v7_dma_inv_range: +ENTRY(v7_dma_inv_range) dcache_line_size r2, r3 sub r3, r2, #1 tst r0, r3 @@ -377,7 +377,7 @@ ENDPROC(v7_dma_inv_range) * - start - virtual start address of region * - end - virtual end address of region */ -v7_dma_clean_range: +ENTRY(v7_dma_clean_range) dcache_line_size r2, r3 sub r3, r2, #1 bic r0, r0, r3 diff --git a/arch/arm/mm/proc-macros.S b/arch/arm/mm/proc-macros.S index f10e31d0730a..841614a83431 100644 --- a/arch/arm/mm/proc-macros.S +++ b/arch/arm/mm/proc-macros.S @@ -324,6 +324,8 @@ ENTRY(\name\()_cache_fns) .long \name\()_flush_kern_dcache_area .long \name\()_dma_map_area .long \name\()_dma_unmap_area + .long \name\()_dma_inv_range + .long \name\()_dma_clean_range .long \name\()_dma_flush_range .size \name\()_cache_fns, . - \name\()_cache_fns .endm diff --git a/arch/arm/mm/proc-syms.c b/arch/arm/mm/proc-syms.c index 054b491ff764..70e8b7d34434 100644 --- a/arch/arm/mm/proc-syms.c +++ b/arch/arm/mm/proc-syms.c @@ -30,6 +30,9 @@ EXPORT_SYMBOL(__cpuc_flush_user_all); EXPORT_SYMBOL(__cpuc_flush_user_range); EXPORT_SYMBOL(__cpuc_coherent_kern_range); EXPORT_SYMBOL(__cpuc_flush_dcache_area); +EXPORT_SYMBOL(dmac_inv_range); +EXPORT_SYMBOL(dmac_clean_range); +EXPORT_SYMBOL(dmac_flush_range); #else EXPORT_SYMBOL(cpu_cache); #endif -- GitLab From a2e2803e978303ee11fbe8011786e9b54557e612 Mon Sep 17 00:00:00 2001 From: Trilok Soni Date: Wed, 5 Aug 2015 16:46:13 -0700 Subject: [PATCH 1050/1635] arm: optimize memcpy_{from,to}io() and memset_io Optimize memcpy_{from,to}io() and memset_io() by transferring in double words as much as possible with minimized barrier usage. This simplest optimization brings faster throughput compare to current byte-by-byte read and write with barrier in the loop. This patch is based on arm64 optimization. Change-Id: Ib0b67ba516c25a17047314ff916a348db07350e9 Signed-off-by: Trilok Soni --- arch/arm/kernel/io.c | 72 ++++++++++++++++++++++++++++++++++++-------- 1 file changed, 59 insertions(+), 13 deletions(-) diff --git a/arch/arm/kernel/io.c b/arch/arm/kernel/io.c index 60b621295d6c..a20e48c50d85 100644 --- a/arch/arm/kernel/io.c +++ b/arch/arm/kernel/io.c @@ -4,6 +4,8 @@ #include #include +#define IO_CHECK_ALIGN(v, a) ((((unsigned long)(v)) & ((a) - 1)) == 0) + static DEFINE_RAW_SPINLOCK(__io_lock); /* @@ -40,46 +42,90 @@ EXPORT_SYMBOL(atomic_io_modify); /* * Copy data from IO memory space to "real" memory space. - * This needs to be optimized. */ void _memcpy_fromio(void *to, const volatile void __iomem *from, size_t count) { - unsigned char *t = to; - while (count) { + while (count && (!IO_CHECK_ALIGN(from, 8) || !IO_CHECK_ALIGN(to, 8))) { + *(u8 *)to = readb_relaxed_no_log(from); + from++; + to++; count--; - *t = readb(from); - t++; + } + + while (count >= 8) { + *(u64 *)to = readq_relaxed_no_log(from); + from += 8; + to += 8; + count -= 8; + } + + while (count) { + *(u8 *)to = readb_relaxed_no_log(from); from++; + to++; + count--; } } EXPORT_SYMBOL(_memcpy_fromio); /* * Copy data from "real" memory space to IO memory space. - * This needs to be optimized. */ void _memcpy_toio(volatile void __iomem *to, const void *from, size_t count) { - const unsigned char *f = from; + void *p = (void __force *)to; + + while (count && (!IO_CHECK_ALIGN(p, 8) || !IO_CHECK_ALIGN(from, 8))) { + writeb_relaxed_no_log(*(volatile u8 *)from, p); + from++; + p++; + count--; + } + + while (count >= 8) { + writeq_relaxed_no_log(*(volatile u64 *)from, p); + from += 8; + p += 8; + count -= 8; + } + while (count) { + writeb_relaxed_no_log(*(volatile u8 *)from, p); + from++; + p++; count--; - writeb(*f, to); - f++; - to++; } } EXPORT_SYMBOL(_memcpy_toio); /* * "memset" on IO memory space. - * This needs to be optimized. */ void _memset_io(volatile void __iomem *dst, int c, size_t count) { + void *p = (void __force *)dst; + u64 qc = c; + + qc |= qc << 8; + qc |= qc << 16; + qc |= qc << 32; + + while (count && !IO_CHECK_ALIGN(p, 8)) { + writeb_relaxed_no_log(c, p); + p++; + count--; + } + + while (count >= 8) { + writeq_relaxed_no_log(qc, p); + p += 8; + count -= 8; + } + while (count) { + writeb_relaxed_no_log(c, p); + p++; count--; - writeb(c, dst); - dst++; } } EXPORT_SYMBOL(_memset_io); -- GitLab From 45bade4adfd6095df756aa5228a803a5eb74d204 Mon Sep 17 00:00:00 2001 From: Avaneesh Kumar Dwivedi Date: Wed, 25 Apr 2018 13:40:28 +0530 Subject: [PATCH 1051/1635] fs: Add noinline to reduce core_sys_select stack size Maximum stack size for arm32 devices is (configured by FRAME_WARN) 1024. Core_sys_select()'s stacksize (=1208) exceeds this limit. Adding noinline attribute to reduce stack size. Change-Id: I7dbbc99987baf57c91241f6972996541bec0a2c2 Signed-off-by: Avaneesh Kumar Dwivedi --- fs/select.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/fs/select.c b/fs/select.c index 063067e606ca..160721531f0b 100644 --- a/fs/select.c +++ b/fs/select.c @@ -361,7 +361,7 @@ typedef struct { * * Use "unsigned long" accesses to let user-mode fd_set's be long-aligned. */ -static inline +static noinline_for_stack int get_fd_set(unsigned long nr, void __user *ufdset, unsigned long *fdset) { nr = FDS_BYTES(nr); @@ -372,7 +372,7 @@ int get_fd_set(unsigned long nr, void __user *ufdset, unsigned long *fdset) return 0; } -static inline unsigned long __must_check +static noinline_for_stack unsigned long __must_check set_fd_set(unsigned long nr, void __user *ufdset, unsigned long *fdset) { if (ufdset) @@ -380,7 +380,7 @@ set_fd_set(unsigned long nr, void __user *ufdset, unsigned long *fdset) return 0; } -static inline +static noinline_for_stack void zero_fd_set(unsigned long nr, unsigned long *fdset) { memset(fdset, 0, FDS_BYTES(nr)); @@ -449,7 +449,8 @@ static inline void wait_key_set(poll_table *wait, unsigned long in, wait->_key |= POLLOUT_SET; } -static int do_select(int n, fd_set_bits *fds, struct timespec64 *end_time) +static int noinline_for_stack +do_select(int n, fd_set_bits *fds, struct timespec64 *end_time) { ktime_t expire, *to = NULL; struct poll_wqueues table; -- GitLab From 97e199c81380e810ed7eae3843f3f77014231d5a Mon Sep 17 00:00:00 2001 From: Avaneesh Kumar Dwivedi Date: Wed, 25 Apr 2018 19:30:48 +0530 Subject: [PATCH 1052/1635] defconfig: qcs405: Enable CONFIG_NEON support for qcs405 Buildroot build, throws undefined instruction error without proper floating point config enabled. Enabling config neon to avoid same. Change-Id: I727c10db8dec466e88d25f7ac50968c919b2d792 Signed-off-by: Avaneesh Kumar Dwivedi --- arch/arm/configs/qcs405-perf_defconfig | 2 ++ arch/arm/configs/qcs405_defconfig | 2 ++ 2 files changed, 4 insertions(+) diff --git a/arch/arm/configs/qcs405-perf_defconfig b/arch/arm/configs/qcs405-perf_defconfig index 88ccdd905d46..7f433892d375 100644 --- a/arch/arm/configs/qcs405-perf_defconfig +++ b/arch/arm/configs/qcs405-perf_defconfig @@ -40,6 +40,8 @@ CONFIG_BUILD_ARM_APPENDED_DTB_IMAGE=y CONFIG_CPU_IDLE=y CONFIG_ARM_CPUIDLE=y CONFIG_VFP=y +CONFIG_NEON=y +CONFIG_KERNEL_MODE_NEON=y # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set CONFIG_PM_AUTOSLEEP=y CONFIG_PM_WAKELOCKS=y diff --git a/arch/arm/configs/qcs405_defconfig b/arch/arm/configs/qcs405_defconfig index f865ec11eb54..cffa932330b6 100644 --- a/arch/arm/configs/qcs405_defconfig +++ b/arch/arm/configs/qcs405_defconfig @@ -44,6 +44,8 @@ CONFIG_BUILD_ARM_APPENDED_DTB_IMAGE=y CONFIG_CPU_IDLE=y CONFIG_ARM_CPUIDLE=y CONFIG_VFP=y +CONFIG_NEON=y +CONFIG_KERNEL_MODE_NEON=y # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set CONFIG_PM_AUTOSLEEP=y CONFIG_PM_WAKELOCKS=y -- GitLab From bf98c4ce040e0ab65b42dcdaf4ca4f7b2377d27b Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 19 Oct 2017 10:32:13 +0200 Subject: [PATCH 1053/1635] UPSTREAM: tracing: always define trace_{irq,preempt}_{enable_disable} We get a build error in the irqsoff tracer in some configurations: kernel/trace/trace_irqsoff.c: In function 'trace_preempt_on': kernel/trace/trace_irqsoff.c:855:2: error: implicit declaration of function 'trace_preempt_enable_rcuidle'; did you mean 'trace_irq_enable_rcuidle'? [-Werror=implicit-function-declaration] trace_preempt_enable_rcuidle(a0, a1); The problem is that trace_preempt_enable_rcuidle() has different definition based on multiple Kconfig symbols, but not all combinations have a valid definition. This changes the conditions so that we always get exactly one definition of each of the four tracing macros. I have not tried to verify that these definitions are sensible, but now we can build all randconfig combinations again. Link: http://lkml.kernel.org/r/20171019083230.2450779-1-arnd@arndb.de Change-Id: Ie3bb3f61d6f0574282025c1a978cf4528f88a2db Fixes: d59158162e03 ("tracing: Add support for preempt and irq enable/disable events") Acked-by: Joel Fernandes Signed-off-by: Arnd Bergmann Signed-off-by: Steven Rostedt (VMware) --- include/trace/events/preemptirq.h | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/include/trace/events/preemptirq.h b/include/trace/events/preemptirq.h index f5024c560d8f..9c4eb33c5a1d 100644 --- a/include/trace/events/preemptirq.h +++ b/include/trace/events/preemptirq.h @@ -56,15 +56,18 @@ DEFINE_EVENT(preemptirq_template, preempt_enable, #include -#else /* !CONFIG_PREEMPTIRQ_EVENTS */ +#endif /* !CONFIG_PREEMPTIRQ_EVENTS */ +#if !defined(CONFIG_PREEMPTIRQ_EVENTS) || defined(CONFIG_PROVE_LOCKING) #define trace_irq_enable(...) #define trace_irq_disable(...) -#define trace_preempt_enable(...) -#define trace_preempt_disable(...) #define trace_irq_enable_rcuidle(...) #define trace_irq_disable_rcuidle(...) +#endif + +#if !defined(CONFIG_PREEMPTIRQ_EVENTS) || !defined(CONFIG_DEBUG_PREEMPT) +#define trace_preempt_enable(...) +#define trace_preempt_disable(...) #define trace_preempt_enable_rcuidle(...) #define trace_preempt_disable_rcuidle(...) - #endif -- GitLab From 7364785d6e4cdb037b2b37b0c8c5033555ee046f Mon Sep 17 00:00:00 2001 From: Skylar Chang Date: Wed, 25 Apr 2018 14:29:26 -0700 Subject: [PATCH 1054/1635] msm: ipa3: remove noncached from IPANAT remove calling pgprot_noncached in IPANAT during mmap. Change-Id: I6b8c41dac8bf6e780b326132201476b8a582a183 Signed-off-by: Skylar Chang --- drivers/platform/msm/ipa/ipa_v3/ipa_nat.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_nat.c b/drivers/platform/msm/ipa/ipa_v3/ipa_nat.c index 7e6442df4b50..8f92e04e3caa 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_nat.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_nat.c @@ -80,6 +80,7 @@ static int ipa3_nat_ipv6ct_mmap(struct file *filp, struct vm_area_struct *vma) unsigned long vsize = vma->vm_end - vma->vm_start; unsigned long phys_addr; int result = 0; + struct ipa_smmu_cb_ctx *cb = ipa3_get_smmu_ctx(IPA_SMMU_CB_AP); IPADBG("\n"); @@ -111,8 +112,14 @@ static int ipa3_nat_ipv6ct_mmap(struct file *filp, struct vm_area_struct *vma) goto bail; } } + /* check if smmu enable & dma_coherent mode */ + if (!cb->valid || + !is_device_dma_coherent(cb->dev)) { + vma->vm_page_prot = + pgprot_noncached(vma->vm_page_prot); + IPADBG("App smmu enable in DMA mode\n"); + } - vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); if (dev->is_sys_mem) { IPADBG("Mapping system memory\n"); IPADBG("map sz=0x%zx\n", dev->size); -- GitLab From 2214773e9ca5ec9acdb120fdaa22af2c2881b6aa Mon Sep 17 00:00:00 2001 From: Subbaraman Narayanamurthy Date: Mon, 16 Apr 2018 14:00:12 -0700 Subject: [PATCH 1055/1635] leds: qpnp-flash-v2: Modify current code calculation Currently, the code calculated for a desired target current and IRES is rounded up since DIV_ROUND_UP is used in the calculation. With a higher IRES (12.5 mA), code can be configured to a higher value. Fix this by using DIV_ROUND_CLOSEST so that the optimal code can be obtained. Change-Id: I51c1b15fff3ff2a23cb256f2ae1d341f5271adf2 Signed-off-by: Subbaraman Narayanamurthy --- drivers/leds/leds-qpnp-flash-v2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/leds/leds-qpnp-flash-v2.c b/drivers/leds/leds-qpnp-flash-v2.c index 47788708db13..85904d66ec49 100644 --- a/drivers/leds/leds-qpnp-flash-v2.c +++ b/drivers/leds/leds-qpnp-flash-v2.c @@ -321,7 +321,7 @@ static inline int get_current_reg_code(int target_curr_ma, int ires_ua) if (!ires_ua || !target_curr_ma || (target_curr_ma < (ires_ua / 1000))) return 0; - return DIV_ROUND_UP(target_curr_ma * 1000, ires_ua) - 1; + return DIV_ROUND_CLOSEST(target_curr_ma * 1000, ires_ua) - 1; } static int qpnp_flash_led_read(struct qpnp_flash_led *led, u16 addr, u8 *data) -- GitLab From 85ccd0ce462d87109a6041fb8f42fc0d33b49a72 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Tue, 27 Feb 2018 13:11:21 -0800 Subject: [PATCH 1056/1635] UPSTREAM: console: Drop added "static" for newport_con Commit 4fe505119778 ("console: Expand dummy functions for CFI") accidentally added "static" to newport_con instance of struct consw, while trying to normalize the declarations. This, however, needed to stay non-static as it has an extern. Reported-by: kbuild test robot Fixes: 4fe505119778 ("console: Expand dummy functions for CFI") Signed-off-by: Kees Cook Signed-off-by: Greg Kroah-Hartman (cherry picked from commit f54450ad1942287cc76b38021c0441fc4901d2de) Change-Id: If64e3c52eb81603da6807a3bbf5c809441504530 --- drivers/video/console/newport_con.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/video/console/newport_con.c b/drivers/video/console/newport_con.c index 6897bd0fc00e..7f2526b43b33 100644 --- a/drivers/video/console/newport_con.c +++ b/drivers/video/console/newport_con.c @@ -680,7 +680,7 @@ static int newport_set_origin(struct vc_data *vc) static void newport_save_screen(struct vc_data *vc) { } -static const struct consw newport_con = { +const struct consw newport_con = { .owner = THIS_MODULE, .con_startup = newport_startup, .con_init = newport_init, -- GitLab From 5f72dcad878294fee326dae04f1ecf8bcc25baf3 Mon Sep 17 00:00:00 2001 From: Ajay Singh Parmar Date: Thu, 26 Apr 2018 12:30:08 -0700 Subject: [PATCH 1057/1635] drm/msm/dsi-staging: use correct of node Use the correct of node for display to avoid failing to read display properties. Change-Id: Ic72dba3e0752588b43317357110243ba43ebd580 Signed-off-by: Ajay Singh Parmar --- drivers/gpu/drm/msm/dsi-staging/dsi_display.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_display.c b/drivers/gpu/drm/msm/dsi-staging/dsi_display.c index 53ba61ccbb10..ef9fc327d33a 100644 --- a/drivers/gpu/drm/msm/dsi-staging/dsi_display.c +++ b/drivers/gpu/drm/msm/dsi-staging/dsi_display.c @@ -3945,7 +3945,7 @@ static void dsi_display_setup(struct dsi_display *display) } - display->display_type = of_get_property(pdev->dev.of_node, + display->display_type = of_get_property(display->disp_node, "qcom,display-type", NULL); if (!display->display_type) display->display_type = "unknown"; -- GitLab From f0294792301c5638d8f927ad423fcb9a97d59993 Mon Sep 17 00:00:00 2001 From: Ajay Singh Parmar Date: Fri, 20 Apr 2018 00:18:10 -0700 Subject: [PATCH 1058/1635] drm/dsi-staging: enable DSI_PARSER sub-module Enable the compilation of DSI_PARSER sub-module which is a text parser and is used for parsing the panel configurations. CRs-Fixed: 2223812 Change-Id: I2c3403ebbcfd6b6aa9db449e01567645dc756dc5 Signed-off-by: Ajay Singh Parmar --- drivers/gpu/drm/msm/Kconfig | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/gpu/drm/msm/Kconfig b/drivers/gpu/drm/msm/Kconfig index eb6929025766..36e0be99cf9a 100644 --- a/drivers/gpu/drm/msm/Kconfig +++ b/drivers/gpu/drm/msm/Kconfig @@ -71,6 +71,16 @@ config DRM_MSM_DSI_STAGING Interface and DSI stands for Display Serial Interface which powers the primary display of your mobile device. +config DSI_PARSER + bool "Enable DSI panel configuration parser" + depends on DYNAMIC_DEBUG + default y + help + Choose this option if you need text parser for a DSI panel + configurations which can parse a given text file and get the + panel configurations. Also, this module provides a set of APIs + which can be used to get the parsed data. + config DRM_MSM_DSI_PLL bool "Enable DSI PLL driver in MSM DRM" depends on DRM_MSM_DSI && COMMON_CLK -- GitLab From bb2e97c06dab957973e6f5b905b85a2d58d1785e Mon Sep 17 00:00:00 2001 From: Pavankumar Kondeti Date: Wed, 28 Jun 2017 12:00:31 +0530 Subject: [PATCH 1059/1635] softirq: defer softirq processing to ksoftirqd if CPU is busy with RT Defer the softirq processing to ksoftirqd if a RT task is running or queued on the current CPU. This complements the RT task placement algorithm which tries to find a CPU that is not currently busy with softirqs. Currently NET_TX, NET_RX, BLOCK and TASKLET softirqs are only deferred as they can potentially run for long time. Change-Id: Id7665244af6bbd5a96d9e591cf26154e9eaa860c Signed-off-by: Pavankumar Kondeti [satyap@codeaurora.org: trivial merge conflict resolution.] Signed-off-by: Satya Durga Srinivasu Prabhala --- include/linux/sched.h | 5 +++++ kernel/sched/cpupri.c | 11 +++++++++++ kernel/softirq.c | 5 ++++- 3 files changed, 20 insertions(+), 1 deletion(-) diff --git a/include/linux/sched.h b/include/linux/sched.h index 15fc9e3c0691..3df6845100a6 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -1565,6 +1565,7 @@ extern int task_can_attach(struct task_struct *p, const struct cpumask *cs_cpus_ #ifdef CONFIG_SMP extern void do_set_cpus_allowed(struct task_struct *p, const struct cpumask *new_mask); extern int set_cpus_allowed_ptr(struct task_struct *p, const struct cpumask *new_mask); +extern bool cpupri_check_rt(void); #else static inline void do_set_cpus_allowed(struct task_struct *p, const struct cpumask *new_mask) { @@ -1575,6 +1576,10 @@ static inline int set_cpus_allowed_ptr(struct task_struct *p, const struct cpuma return -EINVAL; return 0; } +static inline bool cpupri_check_rt(void) +{ + return false; +} #endif #ifndef cpu_relax_yield diff --git a/kernel/sched/cpupri.c b/kernel/sched/cpupri.c index 5b08553e29cb..41574c969715 100644 --- a/kernel/sched/cpupri.c +++ b/kernel/sched/cpupri.c @@ -277,3 +277,14 @@ void cpupri_cleanup(struct cpupri *cp) for (i = 0; i < CPUPRI_NR_PRIORITIES; i++) free_cpumask_var(cp->pri_to_cpu[i].mask); } + +/* + * cpupri_check_rt - check if CPU has a RT task + * should be called from rcu-sched read section. + */ +bool cpupri_check_rt(void) +{ + int cpu = raw_smp_processor_id(); + + return cpu_rq(cpu)->rd->cpupri.cpu_to_pri[cpu] > CPUPRI_NORMAL; +} diff --git a/kernel/softirq.c b/kernel/softirq.c index 378e509c429f..e0f9c734f8b6 100644 --- a/kernel/softirq.c +++ b/kernel/softirq.c @@ -245,6 +245,8 @@ static inline bool lockdep_softirq_start(void) { return false; } static inline void lockdep_softirq_end(bool in_hardirq) { } #endif +#define long_softirq_pending() (local_softirq_pending() & LONG_SOFTIRQ_MASK) +#define defer_for_rt() (long_softirq_pending() && cpupri_check_rt()) asmlinkage __visible void __softirq_entry __do_softirq(void) { unsigned long end = jiffies + MAX_SOFTIRQ_TIME; @@ -308,6 +310,7 @@ asmlinkage __visible void __softirq_entry __do_softirq(void) pending = local_softirq_pending(); if (pending) { if (time_before(jiffies, end) && !need_resched() && + !defer_for_rt() && --max_restart) goto restart; @@ -363,7 +366,7 @@ static inline void invoke_softirq(void) if (ksoftirqd_running()) return; - if (!force_irqthreads) { + if (!force_irqthreads && !defer_for_rt()) { #ifdef CONFIG_HAVE_IRQ_EXIT_ON_IRQ_STACK /* * We can safely execute softirq on the current stack if -- GitLab From f646d63f5592f8a01651de19ba63954c9b1a9b32 Mon Sep 17 00:00:00 2001 From: Lingutla Chandrasekhar Date: Thu, 1 Mar 2018 18:36:36 +0530 Subject: [PATCH 1060/1635] Revert "softirq: Let ksoftirqd do its job" Ksfotirqd is a normal priority CFS task. It can experience higher scheduling latency under heavy load conditions. Currently once asynchronous softirq processing is deferred to ksoftirqd, softirqs are not processed further until ksoftirqd task gets a chance to run. High latencies for softirqs like TIMER, HI TASKLET is not acceptable. So revert 'commit 4cd13c21b207 ("softirq: Let ksoftirqd do its job")'. Change-Id: I38a1a88b5f42dd534c65d739dbb7e4321a7904db Signed-off-by: Lingutla Chandrasekhar Signed-off-by: Satya Durga Srinivasu Prabhala --- kernel/softirq.c | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/kernel/softirq.c b/kernel/softirq.c index e0f9c734f8b6..b3d3f3cd0280 100644 --- a/kernel/softirq.c +++ b/kernel/softirq.c @@ -84,17 +84,6 @@ static void wakeup_softirqd(void) wake_up_process(tsk); } -/* - * If ksoftirqd is scheduled, we do not want to process pending softirqs - * right now. Let ksoftirqd handle this at its own rate, to get fairness. - */ -static bool ksoftirqd_running(void) -{ - struct task_struct *tsk = __this_cpu_read(ksoftirqd); - - return tsk && (tsk->state == TASK_RUNNING); -} - /* * preempt_count and SOFTIRQ_OFFSET usage: * - preempt_count is changed by SOFTIRQ_OFFSET on entering or leaving @@ -336,7 +325,7 @@ asmlinkage __visible void do_softirq(void) pending = local_softirq_pending(); - if (pending && !ksoftirqd_running()) + if (pending) do_softirq_own_stack(); local_irq_restore(flags); @@ -363,9 +352,6 @@ void irq_enter(void) static inline void invoke_softirq(void) { - if (ksoftirqd_running()) - return; - if (!force_irqthreads && !defer_for_rt()) { #ifdef CONFIG_HAVE_IRQ_EXIT_ON_IRQ_STACK /* -- GitLab From 298e04a2ff07ebe3302ea04f1f728975bc2a9d05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Davidsson?= Date: Thu, 25 Jan 2018 12:06:21 +0100 Subject: [PATCH 1061/1635] softirq: Don't defer all softirq during RT task MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since 'commit f332a9d53e33 ("softirq: defer softirq processing to ksoftirqd if CPU is busy with RT")', all softirqs are deferred to ksoftirqd if one of the potentially long softirqs are pending. This can significantly delay processing of tasklets and timers, which are frequently designed to be running at high priority. Defer only the potentially slow softirqs to ksoftirqd. Change-Id: I7a2ef7c59749ccf086066c59962ff326786da6f4 Signed-off-by: Björn Davidsson [clingutla@codeaurora.org:- Renamed local variables and refactored deferred logic to macro for avoiding potential deadlock.] Signed-off-by: Lingutla Chandrasekhar Signed-off-by: Satya Durga Srinivasu Prabhala --- kernel/softirq.c | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/kernel/softirq.c b/kernel/softirq.c index b3d3f3cd0280..81740f20ca13 100644 --- a/kernel/softirq.c +++ b/kernel/softirq.c @@ -234,8 +234,16 @@ static inline bool lockdep_softirq_start(void) { return false; } static inline void lockdep_softirq_end(bool in_hardirq) { } #endif -#define long_softirq_pending() (local_softirq_pending() & LONG_SOFTIRQ_MASK) -#define defer_for_rt() (long_softirq_pending() && cpupri_check_rt()) +#define softirq_deferred_for_rt(pending) \ +({ \ + __u32 deferred = 0; \ + if (cpupri_check_rt()) { \ + deferred = pending & LONG_SOFTIRQ_MASK; \ + pending &= ~LONG_SOFTIRQ_MASK; \ + } \ + deferred; \ +}) + asmlinkage __visible void __softirq_entry __do_softirq(void) { unsigned long end = jiffies + MAX_SOFTIRQ_TIME; @@ -243,6 +251,7 @@ asmlinkage __visible void __softirq_entry __do_softirq(void) int max_restart = MAX_SOFTIRQ_RESTART; struct softirq_action *h; bool in_hardirq; + __u32 deferred; __u32 pending; int softirq_bit; @@ -254,14 +263,14 @@ asmlinkage __visible void __softirq_entry __do_softirq(void) current->flags &= ~PF_MEMALLOC; pending = local_softirq_pending(); + deferred = softirq_deferred_for_rt(pending); account_irq_enter_time(current); - __local_bh_disable_ip(_RET_IP_, SOFTIRQ_OFFSET); in_hardirq = lockdep_softirq_start(); restart: /* Reset the pending bitmask before enabling irqs */ - set_softirq_pending(0); + set_softirq_pending(deferred); __this_cpu_write(active_softirqs, pending); local_irq_enable(); @@ -297,15 +306,16 @@ asmlinkage __visible void __softirq_entry __do_softirq(void) local_irq_disable(); pending = local_softirq_pending(); + deferred = softirq_deferred_for_rt(pending); + if (pending) { if (time_before(jiffies, end) && !need_resched() && - !defer_for_rt() && --max_restart) goto restart; - - wakeup_softirqd(); } + if (pending | deferred) + wakeup_softirqd(); lockdep_softirq_end(in_hardirq); account_irq_exit_time(current); __local_bh_enable(SOFTIRQ_OFFSET); @@ -352,7 +362,7 @@ void irq_enter(void) static inline void invoke_softirq(void) { - if (!force_irqthreads && !defer_for_rt()) { + if (!force_irqthreads) { #ifdef CONFIG_HAVE_IRQ_EXIT_ON_IRQ_STACK /* * We can safely execute softirq on the current stack if -- GitLab From 00ecef007b8c96208ae7ae87c0b0f1c15c068da6 Mon Sep 17 00:00:00 2001 From: Deepak Katragadda Date: Wed, 25 Apr 2018 10:10:16 -0700 Subject: [PATCH 1062/1635] clk: qcom: gdsc-regulator: Add MMCX specific logic When clients call the regulator_is_enabled() API for GDSCs that are sourced off of the MMCX rail, any register accesses that will be made as part of the callback rely on the presumption that the MMCX rail is enabled. When the rail is disabled, the corresponding ahb clocks that are needed for these registers to be accessible will also be turned off, thus leading to an unclocked access. Check to make sure that the MMCX rail is enabled prior to reading or writing to the MM registers. Along similar lines, add logic to enable the parent rail for the GDSC prior to reading and writing to the GDSC registers during the set_mode and get_mode callbacks. Change-Id: I8265bc147efd2acd1d6638638eb78935762feee8 Signed-off-by: Deepak Katragadda --- drivers/clk/qcom/gdsc-regulator.c | 73 +++++++++++++++++++++++++++++-- 1 file changed, 70 insertions(+), 3 deletions(-) diff --git a/drivers/clk/qcom/gdsc-regulator.c b/drivers/clk/qcom/gdsc-regulator.c index 8d845aa9f6b4..1027452246c4 100644 --- a/drivers/clk/qcom/gdsc-regulator.c +++ b/drivers/clk/qcom/gdsc-regulator.c @@ -131,7 +131,7 @@ static int poll_gdsc_status(struct gdsc *sc, enum gdscr_status status) * bit in the GDSCR to be set or reset after the GDSC state * changes. Hence, keep on checking for a reasonable number * of times until the bit is set with the least possible delay - * between succeessive tries. + * between successive tries. */ udelay(1); } @@ -147,6 +147,30 @@ static int gdsc_is_enabled(struct regulator_dev *rdev) if (!sc->toggle_logic) return !sc->resets_asserted; + if (sc->parent_regulator) { + /* + * The parent regulator for the GDSC is required to be on to + * make any register accesses to the GDSC base. Return false + * if the parent supply is disabled. + */ + if (regulator_is_enabled(sc->parent_regulator) <= 0) + return false; + + /* + * Place an explicit vote on the parent rail to cover cases when + * it might be disabled between this point and reading the GDSC + * registers. + */ + if (regulator_set_voltage(sc->parent_regulator, + RPMH_REGULATOR_LEVEL_LOW_SVS, INT_MAX)) + return false; + + if (regulator_enable(sc->parent_regulator)) { + regulator_set_voltage(sc->parent_regulator, 0, INT_MAX); + return false; + } + } + regmap_read(sc->regmap, REG_OFFSET, ®val); if (regval & PWR_ON_MASK) { @@ -155,10 +179,20 @@ static int gdsc_is_enabled(struct regulator_dev *rdev) * votable GDS registers. Check the SW_COLLAPSE_MASK to * determine if HLOS has voted for it. */ - if (!(regval & SW_COLLAPSE_MASK)) + if (!(regval & SW_COLLAPSE_MASK)) { + if (sc->parent_regulator) { + regulator_disable(sc->parent_regulator); + regulator_set_voltage(sc->parent_regulator, 0, + INT_MAX); + } return true; + } } + if (sc->parent_regulator) { + regulator_disable(sc->parent_regulator); + regulator_set_voltage(sc->parent_regulator, 0, INT_MAX); + } return false; } @@ -412,9 +446,33 @@ static unsigned int gdsc_get_mode(struct regulator_dev *rdev) { struct gdsc *sc = rdev_get_drvdata(rdev); uint32_t regval; + int ret; mutex_lock(&gdsc_seq_lock); + + if (sc->parent_regulator) { + ret = regulator_set_voltage(sc->parent_regulator, + RPMH_REGULATOR_LEVEL_LOW_SVS, INT_MAX); + if (ret) { + mutex_unlock(&gdsc_seq_lock); + return ret; + } + + ret = regulator_enable(sc->parent_regulator); + if (ret) { + regulator_set_voltage(sc->parent_regulator, 0, INT_MAX); + mutex_unlock(&gdsc_seq_lock); + return ret; + } + } + regmap_read(sc->regmap, REG_OFFSET, ®val); + + if (sc->parent_regulator) { + regulator_disable(sc->parent_regulator); + regulator_set_voltage(sc->parent_regulator, 0, INT_MAX); + } + mutex_unlock(&gdsc_seq_lock); if (regval & HW_CONTROL_MASK) @@ -438,6 +496,13 @@ static int gdsc_set_mode(struct regulator_dev *rdev, unsigned int mode) mutex_unlock(&gdsc_seq_lock); return ret; } + + ret = regulator_enable(sc->parent_regulator); + if (ret) { + regulator_set_voltage(sc->parent_regulator, 0, INT_MAX); + mutex_unlock(&gdsc_seq_lock); + return ret; + } } regmap_read(sc->regmap, REG_OFFSET, ®val); @@ -483,8 +548,10 @@ static int gdsc_set_mode(struct regulator_dev *rdev, unsigned int mode) break; } - if (sc->parent_regulator) + if (sc->parent_regulator) { + regulator_disable(sc->parent_regulator); regulator_set_voltage(sc->parent_regulator, 0, INT_MAX); + } mutex_unlock(&gdsc_seq_lock); -- GitLab From 4afd422ac214f3cc4260cb8c6484495526677026 Mon Sep 17 00:00:00 2001 From: Siddartha Mohanadoss Date: Thu, 26 Apr 2018 11:12:18 -0700 Subject: [PATCH 1063/1635] ARM: dts: msm: Disable PM855B ADC_TM device for SM8150 platform Disable ADC_TM node as the device is configured to use by BAT_THERM and BAT_ID channel in boot and enabling it overwrites the configuration for these channels. Change-Id: Ib7e2d4a330959789d15954ca2f90f3fdca715867 Signed-off-by: Siddartha Mohanadoss --- arch/arm64/boot/dts/qcom/pm855b.dtsi | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/boot/dts/qcom/pm855b.dtsi b/arch/arm64/boot/dts/qcom/pm855b.dtsi index f7e27363bf8a..93ec56783e5e 100644 --- a/arch/arm64/boot/dts/qcom/pm855b.dtsi +++ b/arch/arm64/boot/dts/qcom/pm855b.dtsi @@ -151,6 +151,7 @@ #size-cells = <0>; #thermal-sensor-cells = <1>; io-channels = <&pm855b_vadc ADC_AMUX_THM2_PU2>; + status = "disabled"; }; pm855b_charger: qcom,qpnp-smb5 { -- GitLab From c29808b20591133efda265b7bdc6fd672d8dea8c Mon Sep 17 00:00:00 2001 From: "Bao D. Nguyen" Date: Fri, 13 Apr 2018 13:17:00 -0700 Subject: [PATCH 1064/1635] phy: qcom-ufs: Update UFS PHY calibration sequence Updated the UFS PHY sequence per the updated PHY Hardware Programming Guide. Change-Id: I80bafe5d61a8051cdf0a99ce04e01acf549b056a Signed-off-by: Bao D. Nguyen --- drivers/phy/qualcomm/phy-qcom-ufs-qmp-v4.c | 7 +- drivers/phy/qualcomm/phy-qcom-ufs-qmp-v4.h | 81 +++++++++++++--------- drivers/phy/qualcomm/phy-qcom-ufs.c | 4 +- 3 files changed, 55 insertions(+), 37 deletions(-) diff --git a/drivers/phy/qualcomm/phy-qcom-ufs-qmp-v4.c b/drivers/phy/qualcomm/phy-qcom-ufs-qmp-v4.c index 220bc5699077..c571c5bbf378 100644 --- a/drivers/phy/qualcomm/phy-qcom-ufs-qmp-v4.c +++ b/drivers/phy/qualcomm/phy-qcom-ufs-qmp-v4.c @@ -19,6 +19,9 @@ static int ufs_qcom_phy_qmp_v4_phy_calibrate(struct ufs_qcom_phy *ufs_qcom_phy, bool is_rate_B) { + writel_relaxed(0x01, ufs_qcom_phy->mmio + UFS_PHY_SW_RESET); + /* Ensure PHY is in reset before writing PHY calibration data */ + wmb(); /* * Writing PHY calibration in this order: * 1. Write Rate-A calibration first (1-lane mode). @@ -33,8 +36,10 @@ int ufs_qcom_phy_qmp_v4_phy_calibrate(struct ufs_qcom_phy *ufs_qcom_phy, if (is_rate_B) ufs_qcom_phy_write_tbl(ufs_qcom_phy, phy_cal_table_rate_B, ARRAY_SIZE(phy_cal_table_rate_B)); + + writel_relaxed(0x00, ufs_qcom_phy->mmio + UFS_PHY_SW_RESET); /* flush buffered writes */ - mb(); + wmb(); return 0; } diff --git a/drivers/phy/qualcomm/phy-qcom-ufs-qmp-v4.h b/drivers/phy/qualcomm/phy-qcom-ufs-qmp-v4.h index bb1c669a7aeb..a5eb4651037b 100644 --- a/drivers/phy/qualcomm/phy-qcom-ufs-qmp-v4.h +++ b/drivers/phy/qualcomm/phy-qcom-ufs-qmp-v4.h @@ -55,6 +55,7 @@ #define QSERDES_COM_LOCK_CMP2_MODE1 COM_OFF(0xB8) #define QSERDES_COM_BIN_VCOCAL_CMP_CODE1_MODE1 COM_OFF(0x1B4) #define QSERDES_COM_BIN_VCOCAL_CMP_CODE2_MODE1 COM_OFF(0x1B8) +#define QSERDES_COM_CMN_IPTRIM COM_OFF(0x60) /* UFS PHY registers */ #define UFS_PHY_PHY_START PHY_OFF(0x00) @@ -125,6 +126,9 @@ #define QSERDES_RX0_RX_MODE_10_HIGH2 RX_OFF(0, 0x1A0) #define QSERDES_RX0_RX_MODE_10_HIGH3 RX_OFF(0, 0x1A4) #define QSERDES_RX0_RX_MODE_10_HIGH4 RX_OFF(0, 0x1A8) +#define QSERDES_RX0_AC_JTAG_ENABLE RX_OFF(0, 0x68) +#define QSERDES_RX0_UCDR_FO_GAIN RX_OFF(0, 0x08) +#define QSERDES_RX0_UCDR_SO_GAIN RX_OFF(0, 0x14) #define QSERDES_RX1_SIGDET_LVL RX_OFF(1, 0x120) #define QSERDES_RX1_SIGDET_CNTRL RX_OFF(1, 0x11C) @@ -158,7 +162,9 @@ #define QSERDES_RX1_RX_MODE_10_HIGH2 RX_OFF(1, 0x1A0) #define QSERDES_RX1_RX_MODE_10_HIGH3 RX_OFF(1, 0x1A4) #define QSERDES_RX1_RX_MODE_10_HIGH4 RX_OFF(1, 0x1A8) - +#define QSERDES_RX1_AC_JTAG_ENABLE RX_OFF(1, 0x68) +#define QSERDES_RX1_UCDR_FO_GAIN RX_OFF(1, 0x08) +#define QSERDES_RX1_UCDR_SO_GAIN RX_OFF(1, 0x14) #define UFS_PHY_RX_LINECFG_DISABLE_BIT BIT(1) @@ -198,6 +204,7 @@ static struct ufs_qcom_phy_calibration phy_cal_table_rate_A[] = { UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLL_CCTRL_MODE1, 0x36), UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_LOCK_CMP1_MODE1, 0x32), UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_LOCK_CMP2_MODE1, 0x0F), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_CMN_IPTRIM, 0x20), UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_BIN_VCOCAL_CMP_CODE1_MODE1, 0xDD), UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_BIN_VCOCAL_CMP_CODE2_MODE1, 0x23), UFS_QCOM_PHY_CAL_ENTRY(QSERDES_TX0_PWM_GEAR_1_DIVIDER_BAND0_1, 0x06), @@ -211,34 +218,49 @@ static struct ufs_qcom_phy_calibration phy_cal_table_rate_A[] = { UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX0_SIGDET_DEGLITCH_CNTRL, 0x1E), UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX0_RX_BAND, 0x18), UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX0_UCDR_FASTLOCK_FO_GAIN, 0x0A), - UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX0_UCDR_SO_SATURATION_AND_ENABLE, 0x7F), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX0_UCDR_SO_SATURATION_AND_ENABLE, 0x4B), UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX0_UCDR_PI_CONTROLS, 0xF1), UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX0_UCDR_FASTLOCK_COUNT_LOW, 0x80), UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX0_UCDR_PI_CTRL2, 0x80), UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX0_RX_TERM_BW, 0x1B), UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX0_RX_EQU_ADAPTOR_CNTRL2, 0x06), - UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX0_RX_EQU_ADAPTOR_CNTRL3, 0x4E), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX0_RX_EQU_ADAPTOR_CNTRL3, 0x04), UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX0_RX_EQU_ADAPTOR_CNTRL4, 0x1D), - UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX0_RX_OFFSET_ADAPTOR_CNTRL2, 0x27), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX0_RX_OFFSET_ADAPTOR_CNTRL2, 0x00), UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX0_RX_IDAC_MEASURE_TIME, 0x10), UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX0_RX_IDAC_TSETTLE_LOW, 0xC0), UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX0_RX_IDAC_TSETTLE_HIGH, 0x00), - UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX0_RX_MODE_00_LOW, 0xE0), - UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX0_RX_MODE_00_HIGH, 0xC8), - UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX0_RX_MODE_00_HIGH2, 0xC8), - UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX0_RX_MODE_00_HIGH3, 0x09), - UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX0_RX_MODE_00_HIGH4, 0xB1), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX0_RX_MODE_00_LOW, 0x36), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX0_RX_MODE_00_HIGH, 0x36), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX0_RX_MODE_00_HIGH2, 0xF6), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX0_RX_MODE_00_HIGH3, 0x3B), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX0_RX_MODE_00_HIGH4, 0x3D), UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX0_RX_MODE_01_LOW, 0xE0), UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX0_RX_MODE_01_HIGH, 0xC8), UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX0_RX_MODE_01_HIGH2, 0xC8), - UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX0_RX_MODE_01_HIGH3, 0x09), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX0_RX_MODE_01_HIGH3, 0x3B), UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX0_RX_MODE_01_HIGH4, 0xB1), UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX0_RX_MODE_10_LOW, 0xE0), UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX0_RX_MODE_10_HIGH, 0xC8), UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX0_RX_MODE_10_HIGH2, 0xC8), - UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX0_RX_MODE_10_HIGH3, 0x09), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX0_RX_MODE_10_HIGH3, 0x3B), UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX0_RX_MODE_10_HIGH4, 0xB1), - UFS_QCOM_PHY_CAL_ENTRY(UFS_PHY_RX_MIN_HIBERN8_TIME, 0x9A), /* 8 us */ + UFS_QCOM_PHY_CAL_ENTRY(UFS_PHY_RX_MIN_HIBERN8_TIME, 0xFF), + UFS_QCOM_PHY_CAL_ENTRY(UFS_PHY_RX_SIGDET_CTRL2, 0x6F), + UFS_QCOM_PHY_CAL_ENTRY(UFS_PHY_TX_LARGE_AMP_DRV_LVL, 0x0A), + UFS_QCOM_PHY_CAL_ENTRY(UFS_PHY_TX_SMALL_AMP_DRV_LVL, 0x02), + UFS_QCOM_PHY_CAL_ENTRY(UFS_PHY_TX_MID_TERM_CTRL1, 0x43), + UFS_QCOM_PHY_CAL_ENTRY(UFS_PHY_DEBUG_BUS_CLKSEL, 0x1F), + UFS_QCOM_PHY_CAL_ENTRY(UFS_PHY_PLL_CNTL, 0x03), + UFS_QCOM_PHY_CAL_ENTRY(UFS_PHY_TIMER_20US_CORECLK_STEPS_MSB, 0x16), + UFS_QCOM_PHY_CAL_ENTRY(UFS_PHY_TIMER_20US_CORECLK_STEPS_LSB, 0xD8), + UFS_QCOM_PHY_CAL_ENTRY(UFS_PHY_TX_PWM_GEAR_BAND, 0xAA), + UFS_QCOM_PHY_CAL_ENTRY(UFS_PHY_TX_HS_GEAR_BAND, 0x06), + UFS_QCOM_PHY_CAL_ENTRY(UFS_PHY_TX_HSGEAR_CAPABILITY, 0x03), + UFS_QCOM_PHY_CAL_ENTRY(UFS_PHY_RX_HSGEAR_CAPABILITY, 0x03), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX0_AC_JTAG_ENABLE, 0x00), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX0_UCDR_FO_GAIN, 0x0C), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX0_UCDR_SO_GAIN, 0x04), }; static struct ufs_qcom_phy_calibration phy_cal_table_2nd_lane[] = { @@ -253,46 +275,37 @@ static struct ufs_qcom_phy_calibration phy_cal_table_2nd_lane[] = { UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX1_SIGDET_DEGLITCH_CNTRL, 0x1E), UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX1_RX_BAND, 0x18), UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX1_UCDR_FASTLOCK_FO_GAIN, 0x0A), - UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX1_UCDR_SO_SATURATION_AND_ENABLE, 0x7F), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX1_UCDR_SO_SATURATION_AND_ENABLE, 0x4B), UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX1_UCDR_PI_CONTROLS, 0xF1), UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX1_UCDR_FASTLOCK_COUNT_LOW, 0x80), UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX1_UCDR_PI_CTRL2, 0x80), UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX1_RX_TERM_BW, 0x1B), UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX1_RX_EQU_ADAPTOR_CNTRL2, 0x06), - UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX1_RX_EQU_ADAPTOR_CNTRL3, 0x4E), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX1_RX_EQU_ADAPTOR_CNTRL3, 0x04), UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX1_RX_EQU_ADAPTOR_CNTRL4, 0x1D), - UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX1_RX_OFFSET_ADAPTOR_CNTRL2, 0x27), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX1_RX_OFFSET_ADAPTOR_CNTRL2, 0x00), UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX1_RX_IDAC_MEASURE_TIME, 0x10), UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX1_RX_IDAC_TSETTLE_LOW, 0xC0), UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX1_RX_IDAC_TSETTLE_HIGH, 0x00), - UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX1_RX_MODE_00_LOW, 0xE0), - UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX1_RX_MODE_00_HIGH, 0xC8), - UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX1_RX_MODE_00_HIGH2, 0xC8), - UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX1_RX_MODE_00_HIGH3, 0x09), - UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX1_RX_MODE_00_HIGH4, 0xB1), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX1_RX_MODE_00_LOW, 0x36), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX1_RX_MODE_00_HIGH, 0x36), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX1_RX_MODE_00_HIGH2, 0xF6), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX1_RX_MODE_00_HIGH3, 0x3B), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX1_RX_MODE_00_HIGH4, 0x3D), UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX1_RX_MODE_01_LOW, 0xE0), UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX1_RX_MODE_01_HIGH, 0xC8), UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX1_RX_MODE_01_HIGH2, 0xC8), - UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX1_RX_MODE_01_HIGH3, 0x09), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX1_RX_MODE_01_HIGH3, 0x3B), UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX1_RX_MODE_01_HIGH4, 0xB1), UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX1_RX_MODE_10_LOW, 0xE0), UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX1_RX_MODE_10_HIGH, 0xC8), UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX1_RX_MODE_10_HIGH2, 0xC8), - UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX1_RX_MODE_10_HIGH3, 0x09), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX1_RX_MODE_10_HIGH3, 0x3B), UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX1_RX_MODE_10_HIGH4, 0xB1), UFS_QCOM_PHY_CAL_ENTRY(UFS_PHY_MULTI_LANE_CTRL1, 0x02), - UFS_QCOM_PHY_CAL_ENTRY(UFS_PHY_RX_SIGDET_CTRL2, 0x6C), - UFS_QCOM_PHY_CAL_ENTRY(UFS_PHY_TX_LARGE_AMP_DRV_LVL, 0x0A), - UFS_QCOM_PHY_CAL_ENTRY(UFS_PHY_TX_SMALL_AMP_DRV_LVL, 0x02), - UFS_QCOM_PHY_CAL_ENTRY(UFS_PHY_TX_MID_TERM_CTRL1, 0x43), - UFS_QCOM_PHY_CAL_ENTRY(UFS_PHY_DEBUG_BUS_CLKSEL, 0x1F), - UFS_QCOM_PHY_CAL_ENTRY(UFS_PHY_PLL_CNTL, 0x03), - UFS_QCOM_PHY_CAL_ENTRY(UFS_PHY_TIMER_20US_CORECLK_STEPS_MSB, 0x16), - UFS_QCOM_PHY_CAL_ENTRY(UFS_PHY_TIMER_20US_CORECLK_STEPS_LSB, 0xD8), - UFS_QCOM_PHY_CAL_ENTRY(UFS_PHY_TX_PWM_GEAR_BAND, 0xAA), - UFS_QCOM_PHY_CAL_ENTRY(UFS_PHY_TX_HS_GEAR_BAND, 0x06), - UFS_QCOM_PHY_CAL_ENTRY(UFS_PHY_TX_HSGEAR_CAPABILITY, 0x03), - UFS_QCOM_PHY_CAL_ENTRY(UFS_PHY_RX_HSGEAR_CAPABILITY, 0x03), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX1_AC_JTAG_ENABLE, 0x00), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX1_UCDR_FO_GAIN, 0x0C), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX1_UCDR_SO_GAIN, 0x04), }; static struct ufs_qcom_phy_calibration phy_cal_table_rate_B[] = { diff --git a/drivers/phy/qualcomm/phy-qcom-ufs.c b/drivers/phy/qualcomm/phy-qcom-ufs.c index ced3bade49b8..acf632a527ca 100644 --- a/drivers/phy/qualcomm/phy-qcom-ufs.c +++ b/drivers/phy/qualcomm/phy-qcom-ufs.c @@ -311,8 +311,8 @@ int ufs_qcom_phy_init_vregulators(struct ufs_qcom_phy *phy_common) if (err) goto out; - err = ufs_qcom_phy_init_vreg(phy_common->dev, &phy_common->vddp_ref_clk, - "vddp-ref-clk"); + ufs_qcom_phy_init_vreg(phy_common->dev, &phy_common->vddp_ref_clk, + "vddp-ref-clk"); out: return err; -- GitLab From 23fb7597e6df2935bbfd0cca5a4c3ad837043aa4 Mon Sep 17 00:00:00 2001 From: Sami Tolvanen Date: Fri, 17 Nov 2017 15:37:42 -0800 Subject: [PATCH 1065/1635] FROMLIST: kbuild: add __cc-ifversion and compiler-specific variants This change adds macros for testing both compiler name and version. Current cc-version, cc-ifversion etc. macros that test gcc version are left unchanged to prevent compatibility issues with existing tests. Bug: 62093296 Bug: 67506682 Change-Id: I14965fcc21dae8dfe31881b172214bf6f8a9f440 (am from https://patchwork.kernel.org/patch/10085767/) Signed-off-by: Sami Tolvanen --- scripts/Kbuild.include | 37 ++++++++++++++++++++++++++++++++++--- 1 file changed, 34 insertions(+), 3 deletions(-) diff --git a/scripts/Kbuild.include b/scripts/Kbuild.include index 97769465de13..b2c913479f9a 100644 --- a/scripts/Kbuild.include +++ b/scripts/Kbuild.include @@ -142,6 +142,37 @@ cc-disable-warning = $(call try-run,\ # Expands to either gcc or clang cc-name = $(shell $(CC) -v 2>&1 | grep -q "clang version" && echo clang || echo gcc) +# __cc-version +# Returns compiler version +__cc-version = $(shell $(CONFIG_SHELL) $(srctree)/scripts/$(cc-name)-version.sh $(CC)) + +# __cc-fullversion +# Returns full compiler version +__cc-fullversion = $(shell $(CONFIG_SHELL) \ + $(srctree)/scripts/$(cc-name)-version.sh -p $(CC)) + +# __cc-ifversion +# Matches compiler name and version +# Usage: EXTRA_CFLAGS += $(call cc-if-name-version, gcc, -lt, 0402, -O1) +__cc-ifversion = $(shell [ $(cc-name) = $(1) ] && [ $(__cc-version) $(2) $(3) ] && echo $(4) || echo $(5)) + +# __cc-if-fullversion +# Matches compiler name and full version +# Usage: EXTRA_CFLAGS += $(call cc-if-name-fullversion, gcc, -lt, 040502, -O1) +__cc-if-fullversion = $(shell [ $(cc-name) = $(1) ] && [ $(__cc-fullversion) $(2) $(3) ] && echo $(4) || echo $(5)) + +# gcc-ifversion +gcc-ifversion = $(call __cc-ifversion, gcc, $(1), $(2), $(3), $(4)) + +# gcc-if-fullversion +gcc-if-fullversion = (call __cc-if-fullversion, gcc, $(1), $(2), $(3), $(4)) + +# clang-ifversion +clang-ifversion = $(call __cc-ifversion, clang, $(1), $(2), $(3), $(4)) + +# clang-if-fullversion +clang-if-fullversion = (call __cc-if-fullversion, clang, $(1), $(2), $(3), $(4)) + # cc-version cc-version = $(shell $(CONFIG_SHELL) $(srctree)/scripts/gcc-version.sh $(CC)) @@ -149,9 +180,9 @@ cc-version = $(shell $(CONFIG_SHELL) $(srctree)/scripts/gcc-version.sh $(CC)) cc-fullversion = $(shell $(CONFIG_SHELL) \ $(srctree)/scripts/gcc-version.sh -p $(CC)) -# cc-ifversion -# Usage: EXTRA_CFLAGS += $(call cc-ifversion, -lt, 0402, -O1) -cc-ifversion = $(shell [ $(cc-version) $(1) $(2) ] && echo $(3) || echo $(4)) +# backward compatibility +cc-ifversion = $(gcc-ifversion) +cc-if-fullversion = $(gcc-if-fullversion) # cc-if-fullversion # Usage: EXTRA_CFLAGS += $(call cc-if-fullversion, -lt, 040502, -O1) -- GitLab From 9945e128a0960902c62d5aae50f799328871f6d7 Mon Sep 17 00:00:00 2001 From: Sami Tolvanen Date: Tue, 13 Feb 2018 13:59:47 -0800 Subject: [PATCH 1066/1635] FROMLIST: kbuild: fix LD_DEAD_CODE_DATA_ELIMINATION Don't remove .head.text or .exitcall.exit when linking with --gc-sections, and include .init.text.* in .init.text and .init.rodata.* in .init.rodata. Bug: 62093296 Bug: 67506682 Change-Id: Ia0f9e735d04c2322dcc8bcfc94241f0551b149c4 (am from https://patchwork.kernel.org/patch/10085773/) Reviewed-by: Nicholas Piggin Signed-off-by: Sami Tolvanen --- include/asm-generic/vmlinux.lds.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h index 353f52fdc35e..f4a6799cfbc5 100644 --- a/include/asm-generic/vmlinux.lds.h +++ b/include/asm-generic/vmlinux.lds.h @@ -105,7 +105,7 @@ #ifdef CONFIG_FTRACE_MCOUNT_RECORD #define MCOUNT_REC() . = ALIGN(8); \ VMLINUX_SYMBOL(__start_mcount_loc) = .; \ - *(__mcount_loc) \ + KEEP(*(__mcount_loc)) \ VMLINUX_SYMBOL(__stop_mcount_loc) = .; #else #define MCOUNT_REC() @@ -512,7 +512,7 @@ VMLINUX_SYMBOL(__softirqentry_text_end) = .; /* Section used for early init (in .S files) */ -#define HEAD_TEXT *(.head.text) +#define HEAD_TEXT KEEP(*(.head.text)) #define HEAD_TEXT_SECTION \ .head.text : AT(ADDR(.head.text) - LOAD_OFFSET) { \ @@ -557,7 +557,7 @@ MEM_DISCARD(init.data) \ KERNEL_CTORS() \ MCOUNT_REC() \ - *(.init.rodata) \ + *(.init.rodata .init.rodata.*) \ FTRACE_EVENTS() \ TRACE_SYSCALLS() \ KPROBE_BLACKLIST() \ @@ -576,7 +576,7 @@ EARLYCON_TABLE() #define INIT_TEXT \ - *(.init.text) \ + *(.init.text .init.text.*) \ *(.text.startup) \ MEM_DISCARD(init.text) @@ -593,7 +593,7 @@ MEM_DISCARD(exit.text) #define EXIT_CALL \ - *(.exitcall.exit) + KEEP(*(.exitcall.exit)) /* * bss (Block Started by Symbol) - uninitialized data -- GitLab From 2621d4912f40e250b845fe1977b1ee7f55cd162b Mon Sep 17 00:00:00 2001 From: Sami Tolvanen Date: Tue, 13 Feb 2018 14:00:14 -0800 Subject: [PATCH 1067/1635] ANDROID: arm64: fix LD_DEAD_CODE_DATA_ELIMINATION Keep .entry.tramp.text to avoid the "Entry trampoline text too big" error while linking. Bug: 62093296 Bug: 67506682 Change-Id: Idab3216244bd2f8537bb2a5bb47e25e8588394da Signed-off-by: Sami Tolvanen --- arch/arm64/kernel/vmlinux.lds.S | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/kernel/vmlinux.lds.S b/arch/arm64/kernel/vmlinux.lds.S index ddfd3c0942f7..e9ad6914a4fb 100644 --- a/arch/arm64/kernel/vmlinux.lds.S +++ b/arch/arm64/kernel/vmlinux.lds.S @@ -61,7 +61,7 @@ jiffies = jiffies_64; #define TRAMP_TEXT \ . = ALIGN(PAGE_SIZE); \ VMLINUX_SYMBOL(__entry_tramp_text_start) = .; \ - *(.entry.tramp.text) \ + KEEP(*(.entry.tramp.text)) \ . = ALIGN(PAGE_SIZE); \ VMLINUX_SYMBOL(__entry_tramp_text_end) = .; #else -- GitLab From 3571151aaef3a5009360106d2bc9cb1ece04a12d Mon Sep 17 00:00:00 2001 From: Sami Tolvanen Date: Tue, 10 Oct 2017 10:56:17 -0700 Subject: [PATCH 1068/1635] FROMLIST: arm64: keep .altinstructions and .altinstr_replacement Make sure the linker doesn't remove .altinstructions or .altinstr_replacement when CONFIG_LD_DEAD_CODE_DATA_ELIMINATION is enabled. Bug: 62093296 Bug: 67506682 Change-Id: I73f8a96679083909ec6865ee87519163ac7dcbe3 (am from https://patchwork.kernel.org/patch/10085799/) Signed-off-by: Sami Tolvanen --- arch/arm64/kernel/vmlinux.lds.S | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm64/kernel/vmlinux.lds.S b/arch/arm64/kernel/vmlinux.lds.S index e9ad6914a4fb..cb3e4393b412 100644 --- a/arch/arm64/kernel/vmlinux.lds.S +++ b/arch/arm64/kernel/vmlinux.lds.S @@ -150,11 +150,11 @@ SECTIONS . = ALIGN(4); .altinstructions : { __alt_instructions = .; - *(.altinstructions) + KEEP(*(.altinstructions)) __alt_instructions_end = .; } .altinstr_replacement : { - *(.altinstr_replacement) + KEEP(*(.altinstr_replacement)) } . = ALIGN(PAGE_SIZE); -- GitLab From e68f37bdf3afaeaba36f6a166d0beb06bd53c53a Mon Sep 17 00:00:00 2001 From: Sami Tolvanen Date: Wed, 25 Oct 2017 12:33:58 -0700 Subject: [PATCH 1069/1635] FROMLIST: kbuild: add ld-name macro GNU gold may require different flags than GNU ld. Add a macro for detecting the linker. Bug: 62093296 Bug: 67506682 Change-Id: I777f14bf4fd902de1f8dc73d7ecc3c0403eae5f5 (am from https://patchwork.kernel.org/patch/10085775/) Reviewed-by: Nick Desaulniers Signed-off-by: Sami Tolvanen --- scripts/Kbuild.include | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/scripts/Kbuild.include b/scripts/Kbuild.include index b2c913479f9a..ae167b7b187b 100644 --- a/scripts/Kbuild.include +++ b/scripts/Kbuild.include @@ -204,6 +204,10 @@ ld-option = $(call try-run,\ # Important: no spaces around options ar-option = $(call try-run, $(AR) rc$(1) "$$TMP",$(1),$(2)) +# ld-name +# Expands to either bfd or gold +ld-name = $(shell $(LD) -v 2>&1 | grep -q "GNU gold" && echo gold || echo bfd) + # ld-version # Note this is mainly for HJ Lu's 3 number binutil versions ld-version = $(shell $(LD) --version | $(srctree)/scripts/ld-version.sh) -- GitLab From f8029e5db9939c8187784cb42a36932d52539b9b Mon Sep 17 00:00:00 2001 From: Sami Tolvanen Date: Fri, 17 Nov 2017 15:55:54 -0800 Subject: [PATCH 1070/1635] FROMLIST: kbuild: add __ld-ifversion and linker-specific macros Add macros for testing both linker name and version. Bug: 62093296 Bug: 67506682 Change-Id: Icbb13e9bb889017cd4a7457a62dea7e0335c53b5 (am from https://patchwork.kernel.org/patch/10085789/) Signed-off-by: Sami Tolvanen --- scripts/Kbuild.include | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/scripts/Kbuild.include b/scripts/Kbuild.include index ae167b7b187b..76f57f595785 100644 --- a/scripts/Kbuild.include +++ b/scripts/Kbuild.include @@ -216,6 +216,18 @@ ld-version = $(shell $(LD) --version | $(srctree)/scripts/ld-version.sh) # Usage: $(call ld-ifversion, -ge, 22252, y) ld-ifversion = $(shell [ $(ld-version) $(1) $(2) ] && echo $(3) || echo $(4)) +# __ld-ifversion +# Usage: $(call __ld-ifversion, gold, -ge, 112000000, y) +__ld-ifversion = $(shell [ $(ld-name) = $(1) ] && [ $(ld-version) $(2) $(3) ] && echo $(4) || echo $(5)) + +# bfd-ifversion +# Usage: $(call bfd-ifversion, -ge, 227000000, y) +bfd-ifversion = $(call __ld-ifversion, bfd, $(1), $(2), $(3), $(4)) + +# gold-ifversion +# Usage: $(call gold-ifversion, -ge, 112000000, y) +gold-ifversion = $(call __ld-ifversion, gold, $(1), $(2), $(3), $(4)) + ###### ### -- GitLab From 50e31375639c02e57df6e316264f216aed072253 Mon Sep 17 00:00:00 2001 From: Sami Tolvanen Date: Wed, 1 Nov 2017 08:42:49 -0700 Subject: [PATCH 1071/1635] FROMLIST: arm64: explicitly pass --no-fix-cortex-a53-843419 to GNU gold Some versions of GNU gold are known to produce broken code with --fix-cortex-a53-843419 as explained in this bug: https://sourceware.org/bugzilla/show_bug.cgi?id=21491 If ARM64_ERRATUM_843419 is disabled and we're using GNU gold, pass --no-fix-cortex-a53-843419 to the linker to ensure the erratum fix is not used even if the linker is configured to enable it by default. This change also adds a warning if the erratum fix is enabled and gold version <1.14 is used. Bug: 62093296 Bug: 67506682 Change-Id: I5669fa920292adc0fd973035f27dafd4a76d919a (am from https://patchwork.kernel.org/patch/10085777/) Signed-off-by: Sami Tolvanen --- arch/arm64/Makefile | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/arch/arm64/Makefile b/arch/arm64/Makefile index 78df900d75b5..519d13a4d92f 100644 --- a/arch/arm64/Makefile +++ b/arch/arm64/Makefile @@ -26,8 +26,17 @@ ifeq ($(CONFIG_ARM64_ERRATUM_843419),y) ifeq ($(call ld-option, --fix-cortex-a53-843419),) $(warning ld does not support --fix-cortex-a53-843419; kernel may be susceptible to erratum) else + ifeq ($(call gold-ifversion, -lt, 114000000, y), y) +$(warning This version of GNU gold may generate incorrect code with --fix-cortex-a53-843419;\ + see https://sourceware.org/bugzilla/show_bug.cgi?id=21491) + endif LDFLAGS_vmlinux += --fix-cortex-a53-843419 endif +else + ifeq ($(ld-name),gold) +# Pass --no-fix-cortex-a53-843419 to ensure the erratum fix is disabled +LDFLAGS += --no-fix-cortex-a53-843419 + endif endif KBUILD_DEFCONFIG := defconfig -- GitLab From 774deee3fcc3b62d69598017119596579d375420 Mon Sep 17 00:00:00 2001 From: Sami Tolvanen Date: Fri, 4 Aug 2017 12:44:35 -0700 Subject: [PATCH 1072/1635] FROMLIST: arm64: add a workaround for GNU gold with ARM64_MODULE_PLTS All current versions of GNU gold crash when linking kernel modules with ARM64_MODULE_PLTS due to a known bug: https://sourceware.org/bugzilla/show_bug.cgi?id=14592 To work around the problem, this change removes NOLOAD from .plt and .init.plt. Bug: 62093296 Bug: 67506682 Change-Id: Ie59c15dc2e60859361b5c7dac5a515eabf8bb005 (am from https://patchwork.kernel.org/patch/10085781/) Acked-by: Ard Biesheuvel Signed-off-by: Sami Tolvanen --- arch/arm64/kernel/module.lds | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/arm64/kernel/module.lds b/arch/arm64/kernel/module.lds index 22e36a21c113..99eb7c292494 100644 --- a/arch/arm64/kernel/module.lds +++ b/arch/arm64/kernel/module.lds @@ -1,5 +1,5 @@ SECTIONS { - .plt (NOLOAD) : { BYTE(0) } - .init.plt (NOLOAD) : { BYTE(0) } - .text.ftrace_trampoline (NOLOAD) : { BYTE(0) } + .plt : { BYTE(0) } + .init.plt : { BYTE(0) } + .text.ftrace_trampoline : { BYTE(0) } } -- GitLab From d9df1dc7455a50a218f11e43b4d366726efc8714 Mon Sep 17 00:00:00 2001 From: Sami Tolvanen Date: Wed, 1 Nov 2017 11:23:22 -0700 Subject: [PATCH 1073/1635] FROMLIST: arm64: fix -m for GNU gold GNU gold supports different emulations than bfd. Use aarch64_elf64_*_vec instead of aarch64linux. Bug: 62093296 Bug: 67506682 Change-Id: I538c69571dc035afb15c7093471b5184f3bf453b (am from https://patchwork.kernel.org/patch/10083925/) Acked-by: Yury Norov Signed-off-by: Sami Tolvanen --- arch/arm64/Makefile | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/arch/arm64/Makefile b/arch/arm64/Makefile index 519d13a4d92f..90a387a0d013 100644 --- a/arch/arm64/Makefile +++ b/arch/arm64/Makefile @@ -79,14 +79,22 @@ KBUILD_CPPFLAGS += -mbig-endian CHECKFLAGS += -D__AARCH64EB__ AS += -EB LD += -EB +ifeq ($(ld-name),gold) +LDFLAGS += -maarch64_elf64_be_vec +else LDFLAGS += -maarch64linuxb +endif UTS_MACHINE := aarch64_be else KBUILD_CPPFLAGS += -mlittle-endian CHECKFLAGS += -D__AARCH64EL__ AS += -EL LD += -EL +ifeq ($(ld-name),gold) +LDFLAGS += -maarch64_elf64_le_vec +else LDFLAGS += -maarch64linux +endif UTS_MACHINE := aarch64 endif -- GitLab From af1f94d0afc1d5da04ad6327235f78b3a98f0736 Mon Sep 17 00:00:00 2001 From: Sami Tolvanen Date: Tue, 28 Nov 2017 08:48:49 -0800 Subject: [PATCH 1074/1635] FROMLIST: kbuild: add support for clang LTO This change adds the configuration option CONFIG_LTO_CLANG, and build system support for clang's Link Time Optimization (LTO). In preparation for LTO support for other compilers, potentially common parts of the changes are gated behind CONFIG_LTO instead. With -flto, instead of object files, clang produces LLVM bitcode, which is compiled into a native object at link time, allowing the final binary to be optimized globally. For more details, see: https://llvm.org/docs/LinkTimeOptimization.html While the kernel normally uses GNU ld for linking, LLVM supports LTO only with lld or GNU gold linkers. This patch set assumes gold will be used with the LLVMgold plug-in to perform the LTO link step. Due to potential incompatibilities with GNU ld, this change also adds LDFINAL_vmlinux for using a different linker for the vmlinux_link step, and defaults to using GNU ld. Assuming LLVMgold.so is in LD_LIBRARY_PATH and CONFIG_LTO_CLANG has been selected, an LTO kernel can be built simply by running make CC=clang. LTO requires clang >= 5.0 and gold from binutils >= 2.27. Bug: 62093296 Bug: 67506682 Change-Id: Ibcd9fc7ec501b4f30b43b4877897615645f8655f (am from https://patchwork.kernel.org/patch/10060329/) Signed-off-by: Sami Tolvanen --- Makefile | 54 ++++++++++++++++++++++- arch/Kconfig | 40 +++++++++++++++++ scripts/Makefile.build | 92 ++++++++++++++++++++++++++++++++++++---- scripts/Makefile.modpost | 40 ++++++++++++++--- scripts/link-vmlinux.sh | 68 ++++++++++++++++++++++++++--- 5 files changed, 270 insertions(+), 24 deletions(-) diff --git a/Makefile b/Makefile index 3c976a69ca2b..67e96818a79a 100644 --- a/Makefile +++ b/Makefile @@ -377,6 +377,7 @@ endif # Make variables (CC, etc...) AS = $(CROSS_COMPILE)as LD = $(CROSS_COMPILE)ld +LDGOLD = $(CROSS_COMPILE)ld.gold CC = $(CROSS_COMPILE)gcc CPP = $(CC) -E AR = $(CROSS_COMPILE)ar @@ -636,6 +637,20 @@ CFLAGS_GCOV := -fprofile-arcs -ftest-coverage -fno-tree-loop-im $(call cc-disabl CFLAGS_KCOV := $(call cc-option,-fsanitize-coverage=trace-pc,) export CFLAGS_GCOV CFLAGS_KCOV +# Make toolchain changes before including arch/$(SRCARCH)/Makefile to ensure +# ar/cc/ld-* macros return correct values. +ifdef CONFIG_LTO_CLANG +# use GNU gold with LLVMgold for LTO linking, and LD for vmlinux_link +LDFINAL_vmlinux := $(LD) +LD := $(LDGOLD) +LDFLAGS += -plugin LLVMgold.so +# use llvm-ar for building symbol tables from IR files, and llvm-dis instead +# of objdump for processing symbol versions and exports +LLVM_AR := llvm-ar +LLVM_DIS := llvm-dis +export LLVM_AR LLVM_DIS +endif + # The arch Makefile can set ARCH_{CPP,A,C}FLAGS to override the default # values of the respective KBUILD_* variables ARCH_CPPFLAGS := @@ -794,6 +809,26 @@ KBUILD_CFLAGS += $(call cc-option,-ffunction-sections,) KBUILD_CFLAGS += $(call cc-option,-fdata-sections,) endif +ifdef CONFIG_LTO_CLANG +lto-clang-flags := -flto -fvisibility=hidden + +# allow disabling only clang LTO where needed +DISABLE_LTO_CLANG := -fno-lto -fvisibility=default +export DISABLE_LTO_CLANG +endif + +ifdef CONFIG_LTO +lto-flags := $(lto-clang-flags) +KBUILD_CFLAGS += $(lto-flags) + +DISABLE_LTO := $(DISABLE_LTO_CLANG) +export DISABLE_LTO + +# LDFINAL_vmlinux and LDFLAGS_FINAL_vmlinux can be set to override +# the linker and flags for vmlinux_link. +export LDFINAL_vmlinux LDFLAGS_FINAL_vmlinux +endif + # arch Makefile may override CC so keep this after arch Makefile is included NOSTDINC_FLAGS += -nostdinc -isystem $(shell $(CC) -print-file-name=include) CHECKFLAGS += $(NOSTDINC_FLAGS) @@ -1111,6 +1146,22 @@ prepare-objtool: $(objtool_target) # CC_STACKPROTECTOR_STRONG! Why did it build with _REGULAR?!") PHONY += prepare-compiler-check prepare-compiler-check: FORCE +# Make sure we're using a supported toolchain with LTO_CLANG +ifdef CONFIG_LTO_CLANG + ifneq ($(call clang-ifversion, -ge, 0500, y), y) + @echo Cannot use CONFIG_LTO_CLANG: requires clang 5.0 or later >&2 && exit 1 + endif + ifneq ($(call gold-ifversion, -ge, 112000000, y), y) + @echo Cannot use CONFIG_LTO_CLANG: requires GNU gold 1.12 or later >&2 && exit 1 + endif +endif +# Make sure compiler supports LTO flags +ifdef lto-flags + ifeq ($(call cc-option, $(lto-flags)),) + @echo Cannot use CONFIG_LTO: $(lto-flags) not supported by compiler \ + >&2 && exit 1 + endif +endif # Make sure compiler supports requested stack protector flag. ifdef stackp-name ifeq ($(call cc-option, $(stackp-flag)),) @@ -1584,7 +1635,8 @@ clean: $(clean-dirs) -o -name modules.builtin -o -name '.tmp_*.o.*' \ -o -name '*.c.[012]*.*' \ -o -name '*.ll' \ - -o -name '*.gcno' \) -type f -print | xargs rm -f + -o -name '*.gcno' \ + -o -name '*.*.symversions' \) -type f -print | xargs rm -f # Generate tags for editors # --------------------------------------------------------------------------- diff --git a/arch/Kconfig b/arch/Kconfig index 400b9e1b2f27..e59db803807f 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -605,6 +605,46 @@ config LD_DEAD_CODE_DATA_ELIMINATION sections (e.g., '.text.init'). Typically '.' in section names is used to distinguish them from label names / C identifiers. +config LTO + def_bool n + +config ARCH_SUPPORTS_LTO_CLANG + bool + help + An architecture should select this option it supports: + - compiling with clang, + - compiling inline assembly with clang's integrated assembler, + - and linking with either lld or GNU gold w/ LLVMgold. + +choice + prompt "Link-Time Optimization (LTO) (EXPERIMENTAL)" + default LTO_NONE + help + This option turns on Link-Time Optimization (LTO). + +config LTO_NONE + bool "None" + +config LTO_CLANG + bool "Use clang Link Time Optimization (LTO) (EXPERIMENTAL)" + depends on ARCH_SUPPORTS_LTO_CLANG + depends on !FTRACE_MCOUNT_RECORD + select LTO + select THIN_ARCHIVES + select LD_DEAD_CODE_DATA_ELIMINATION + help + This option enables clang's Link Time Optimization (LTO), which allows + the compiler to optimize the kernel globally at link time. If you + enable this option, the compiler generates LLVM IR instead of object + files, and the actual compilation from IR occurs at the LTO link step, + which may take several minutes. + + If you select this option, you must compile the kernel with clang >= + 5.0 (make CC=clang) and GNU gold from binutils >= 2.27, and have the + LLVMgold plug-in in LD_LIBRARY_PATH. + +endchoice + config HAVE_ARCH_WITHIN_STACK_FRAMES bool help diff --git a/scripts/Makefile.build b/scripts/Makefile.build index 7143da06d702..bda756f438f1 100644 --- a/scripts/Makefile.build +++ b/scripts/Makefile.build @@ -210,6 +210,23 @@ else cmd_cc_o_c = $(CC) $(c_flags) -c -o $(@D)/.tmp_$(@F) $< +ifdef CONFIG_LTO_CLANG +# Generate .o.symversions files for each .o with exported symbols, and link these +# to the kernel and/or modules at the end. +cmd_modversions_c = \ + if $(OBJDUMP) -h $(@D)/.tmp_$(@F) >/dev/null 2>/dev/null; then \ + if $(OBJDUMP) -h $(@D)/.tmp_$(@F) | grep -q __ksymtab; then \ + $(call cmd_gensymtypes_c,$(KBUILD_SYMTYPES),$(@:.o=.symtypes)) \ + > $(@D)/$(@F).symversions; \ + fi; \ + else \ + if $(LLVM_DIS) -o=- $(@D)/.tmp_$(@F) | grep -q __ksymtab; then \ + $(call cmd_gensymtypes_c,$(KBUILD_SYMTYPES),$(@:.o=.symtypes)) \ + > $(@D)/$(@F).symversions; \ + fi; \ + fi; \ + mv -f $(@D)/.tmp_$(@F) $@; +else cmd_modversions_c = \ if $(OBJDUMP) -h $(@D)/.tmp_$(@F) | grep -q __ksymtab; then \ $(call cmd_gensymtypes_c,$(KBUILD_SYMTYPES),$(@:.o=.symtypes)) \ @@ -222,6 +239,7 @@ cmd_modversions_c = \ mv -f $(@D)/.tmp_$(@F) $@; \ fi; endif +endif ifdef CONFIG_FTRACE_MCOUNT_RECORD ifdef BUILD_C_RECORDMCOUNT @@ -462,8 +480,29 @@ $(sort $(subdir-obj-y)): $(subdir-ym) ; # ifdef builtin-target +ifdef CONFIG_LTO_CLANG + ifdef CONFIG_MODVERSIONS + # combine symversions for later processing + update_lto_symversions = \ + rm -f $@.symversions; \ + for i in $(filter-out FORCE,$^); do \ + if [ -f $$i.symversions ]; then \ + cat $$i.symversions \ + >> $@.symversions; \ + fi; \ + done; + endif + # rebuild the symbol table with llvm-ar to include IR files + update_lto_symtable = ; \ + mv -f $@ $@.tmp; \ + $(LLVM_AR) rcsT$(KBUILD_ARFLAGS) $@ \ + $$($(AR) t $@.tmp); \ + rm -f $@.tmp +endif + ifdef CONFIG_THIN_ARCHIVES - cmd_make_builtin = rm -f $@; $(AR) rcSTP$(KBUILD_ARFLAGS) + cmd_make_builtin = $(update_lto_symversions) \ + rm -f $@; $(AR) rcSTP$(KBUILD_ARFLAGS) cmd_make_empty_builtin = rm -f $@; $(AR) rcSTP$(KBUILD_ARFLAGS) quiet_cmd_link_o_target = AR $@ else @@ -504,7 +543,11 @@ ifdef lib-target quiet_cmd_link_l_target = AR $@ ifdef CONFIG_THIN_ARCHIVES - cmd_link_l_target = rm -f $@; $(AR) rcsTP$(KBUILD_ARFLAGS) $@ $(lib-y) + cmd_link_l_target = \ + $(update_lto_symversions) \ + rm -f $@; \ + $(AR) rcsTP$(KBUILD_ARFLAGS) $@ $(lib-y) \ + $(update_lto_symtable) else cmd_link_l_target = rm -f $@; $(AR) rcs$(KBUILD_ARFLAGS) $@ $(lib-y) endif @@ -522,14 +565,36 @@ else ref_prefix = EXTERN( endif -quiet_cmd_export_list = EXPORTS $@ -cmd_export_list = $(OBJDUMP) -h $< | \ - sed -ne '/___ksymtab/s/.*+\([^ ]*\).*/$(ref_prefix)\1)/p' >$(ksyms-lds);\ - rm -f $(dummy-object);\ +filter_export_list = sed -ne '/___ksymtab/s/.*+\([^ "]*\).*/$(ref_prefix)\1)/p' +link_export_list = rm -f $(dummy-object);\ echo | $(CC) $(a_flags) -c -o $(dummy-object) -x assembler -;\ $(LD) $(ld_flags) -r -o $@ -T $(ksyms-lds) $(dummy-object);\ rm $(dummy-object) $(ksyms-lds) +quiet_cmd_export_list = EXPORTS $@ + +ifdef CONFIG_LTO_CLANG +# objdump doesn't understand IR files and llvm-dis doesn't support archives, +# so we'll walk through each file in the archive separately +cmd_export_list = \ + rm -f $(ksyms-lds); \ + for o in $$($(AR) t $<); do \ + if $(OBJDUMP) -h $$o >/dev/null 2>/dev/null; then \ + $(OBJDUMP) -h $$o | \ + $(filter_export_list) \ + >>$(ksyms-lds); \ + else \ + $(LLVM_DIS) -o=- $$o | \ + $(filter_export_list) \ + >>$(ksyms-lds); \ + fi; \ + done; \ + $(link_export_list) +else +cmd_export_list = $(OBJDUMP) -h $< | $(filter_export_list) >$(ksyms-lds); \ + $(link_export_list) +endif + $(obj)/lib-ksyms.o: $(lib-target) FORCE $(call if_changed,export_list) @@ -557,23 +622,32 @@ cmd_link_multi-link = $(LD) $(ld_flags) -r -o $@ $(link_multi_deps) $(cmd_secana ifdef CONFIG_THIN_ARCHIVES quiet_cmd_link_multi-y = AR $@ - cmd_link_multi-y = rm -f $@; $(AR) rcSTP$(KBUILD_ARFLAGS) $@ $(link_multi_deps) + cmd_link_multi-y = $(update_lto_symversions) \ + rm -f $@; $(AR) rcSTP$(KBUILD_ARFLAGS) $@ $(link_multi_deps) \ + $(update_lto_symtable) else quiet_cmd_link_multi-y = LD $@ cmd_link_multi-y = $(cmd_link_multi-link) endif quiet_cmd_link_multi-m = LD [M] $@ -cmd_link_multi-m = $(cmd_link_multi-link) + +ifdef CONFIG_LTO_CLANG + # don't compile IR until needed + cmd_link_multi-m = $(cmd_link_multi-y) +else + cmd_link_multi-m = $(cmd_link_multi-link) +endif $(multi-used-y): FORCE $(call if_changed,link_multi-y) -$(call multi_depend, $(multi-used-y), .o, -objs -y) $(multi-used-m): FORCE $(call if_changed,link_multi-m) @{ echo $(@:.o=.ko); echo $(link_multi_deps); \ $(cmd_undef_syms); } > $(MODVERDIR)/$(@F:.o=.mod) + +$(call multi_depend, $(multi-used-y), .o, -objs -y) $(call multi_depend, $(multi-used-m), .o, -objs -y -m) targets += $(multi-used-y) $(multi-used-m) diff --git a/scripts/Makefile.modpost b/scripts/Makefile.modpost index 991db7d6e4df..c86c99b4a1cf 100644 --- a/scripts/Makefile.modpost +++ b/scripts/Makefile.modpost @@ -83,12 +83,28 @@ modpost = scripts/mod/modpost \ MODPOST_OPT=$(subst -i,-n,$(filter -i,$(MAKEFLAGS))) +# If CONFIG_LTO_CLANG is enabled, .o files are either LLVM IR, or empty, so we +# need to link them into actual objects before passing them to modpost +modpost-ext = $(if $(CONFIG_LTO_CLANG),.lto,) + +ifdef CONFIG_LTO_CLANG +quiet_cmd_cc_lto_link_modules = LD [M] $@ +cmd_cc_lto_link_modules = \ + $(LD) $(ld_flags) -r -o $(@) \ + $(shell [ -s $(@:$(modpost-ext).o=.o.symversions) ] && \ + echo -T $(@:$(modpost-ext).o=.o.symversions)) \ + --whole-archive $(filter-out FORCE,$^) + +$(modules:.ko=$(modpost-ext).o): %$(modpost-ext).o: %.o FORCE + $(call if_changed,cc_lto_link_modules) +endif + # We can go over command line length here, so be careful. quiet_cmd_modpost = MODPOST $(words $(filter-out vmlinux FORCE, $^)) modules - cmd_modpost = $(MODLISTCMD) | sed 's/\.ko$$/.o/' | $(modpost) $(MODPOST_OPT) -s -T - + cmd_modpost = $(MODLISTCMD) | sed 's/\.ko$$/$(modpost-ext)\.o/' | $(modpost) $(MODPOST_OPT) -s -T - PHONY += __modpost -__modpost: $(modules:.ko=.o) FORCE +__modpost: $(modules:.ko=$(modpost-ext).o) FORCE $(call cmd,modpost) $(wildcard vmlinux) quiet_cmd_kernel-mod = MODPOST $@ @@ -98,8 +114,7 @@ vmlinux.o: FORCE $(call cmd,kernel-mod) # Declare generated files as targets for modpost -$(modules:.ko=.mod.c): __modpost ; - +$(modules:.ko=$(modpost-ext).mod.c): __modpost ; # Step 5), compile all *.mod.c files @@ -110,22 +125,33 @@ quiet_cmd_cc_o_c = CC $@ cmd_cc_o_c = $(CC) $(c_flags) $(KBUILD_CFLAGS_MODULE) $(CFLAGS_MODULE) \ -c -o $@ $< -$(modules:.ko=.mod.o): %.mod.o: %.mod.c FORCE +$(modules:.ko=.mod.o): %.mod.o: %$(modpost-ext).mod.c FORCE $(call if_changed_dep,cc_o_c) -targets += $(modules:.ko=.mod.o) +targets += $(modules:.ko=$(modpost-ext).mod.o) ARCH_POSTLINK := $(wildcard $(srctree)/arch/$(SRCARCH)/Makefile.postlink) # Step 6), final link of the modules with optional arch pass after final link quiet_cmd_ld_ko_o = LD [M] $@ + +ifdef CONFIG_LTO_CLANG + cmd_ld_ko_o = \ + $(LD) -r $(LDFLAGS) \ + $(KBUILD_LDFLAGS_MODULE) $(LDFLAGS_MODULE) \ + $(shell [ -s $(@:.ko=.o.symversions) ] && \ + echo -T $(@:.ko=.o.symversions)) \ + -o $@ --whole-archive \ + $(filter-out FORCE,$(^:$(modpost-ext).o=.o)) +else cmd_ld_ko_o = \ $(LD) -r $(LDFLAGS) \ $(KBUILD_LDFLAGS_MODULE) $(LDFLAGS_MODULE) \ -o $@ $(filter-out FORCE,$^) ; \ $(if $(ARCH_POSTLINK), $(MAKE) -f $(ARCH_POSTLINK) $@, true) +endif -$(modules): %.ko :%.o %.mod.o FORCE +$(modules): %.ko: %$(modpost-ext).o %.mod.o FORCE +$(call if_changed,ld_ko_o) targets += $(modules) diff --git a/scripts/link-vmlinux.sh b/scripts/link-vmlinux.sh index e6818b8e7141..ece268ceaaa1 100755 --- a/scripts/link-vmlinux.sh +++ b/scripts/link-vmlinux.sh @@ -61,7 +61,38 @@ archive_builtin() ${AR} rcsTP${KBUILD_ARFLAGS} built-in.o \ ${KBUILD_VMLINUX_INIT} \ ${KBUILD_VMLINUX_MAIN} + + if [ -n "${CONFIG_LTO_CLANG}" ]; then + mv -f built-in.o built-in.o.tmp + ${LLVM_AR} rcsT${KBUILD_ARFLAGS} built-in.o $(${AR} t built-in.o.tmp) + rm -f built-in.o.tmp + fi + fi +} + +# If CONFIG_LTO_CLANG is selected, collect generated symbol versions into +# .tmp_symversions +modversions() +{ + if [ -z "${CONFIG_LTO_CLANG}" ]; then + return fi + + if [ -z "${CONFIG_MODVERSIONS}" ]; then + return + fi + + rm -f .tmp_symversions + + for a in built-in.o ${KBUILD_VMLINUX_LIBS}; do + for o in $(${AR} t $a); do + if [ -f ${o}.symversions ]; then + cat ${o}.symversions >> .tmp_symversions + fi + done + done + + echo "-T .tmp_symversions" } # Link of vmlinux.o used for section mismatch analysis @@ -84,7 +115,16 @@ modpost_link() ${KBUILD_VMLINUX_LIBS} \ --end-group" fi - ${LD} ${LDFLAGS} -r -o ${1} ${objects} + + if [ -n "${CONFIG_LTO_CLANG}" ]; then + # This might take a while, so indicate that we're doing + # an LTO link + info LTO vmlinux.o + else + info LD vmlinux.o + fi + + ${LD} ${LDFLAGS} -r -o ${1} $(modversions) ${objects} } # Link of vmlinux @@ -96,8 +136,16 @@ vmlinux_link() local objects if [ "${SRCARCH}" != "um" ]; then - if [ -n "${CONFIG_THIN_ARCHIVES}" ]; then - objects="--whole-archive \ + local ld=${LD} + local ldflags="${LDFLAGS} ${LDFLAGS_vmlinux}" + + if [ -n "${LDFINAL_vmlinux}" ]; then + ld=${LDFINAL_vmlinux} + ldflags="${LDFLAGS_FINAL_vmlinux} ${LDFLAGS_vmlinux}" + fi + + if [[ -n "${CONFIG_THIN_ARCHIVES}" && -z "${CONFIG_LTO_CLANG}" ]]; then + objects="--whole-archive \ built-in.o \ --no-whole-archive \ --start-group \ @@ -113,8 +161,7 @@ vmlinux_link() ${1}" fi - ${LD} ${LDFLAGS} ${LDFLAGS_vmlinux} -o ${2} \ - -T ${lds} ${objects} + ${ld} ${ldflags} -o ${2} -T ${lds} ${objects} else if [ -n "${CONFIG_THIN_ARCHIVES}" ]; then objects="-Wl,--whole-archive \ @@ -141,7 +188,6 @@ vmlinux_link() fi } - # Create ${2} .o file with all symbols from the ${1} object file kallsyms() { @@ -192,6 +238,7 @@ cleanup() rm -f .tmp_System.map rm -f .tmp_kallsyms* rm -f .tmp_version + rm -f .tmp_symversions rm -f .tmp_vmlinux* rm -f built-in.o rm -f System.map @@ -253,12 +300,19 @@ ${MAKE} -f "${srctree}/scripts/Makefile.build" obj=init GCC_PLUGINS_CFLAGS="${GC archive_builtin #link vmlinux.o -info LD vmlinux.o modpost_link vmlinux.o # modpost vmlinux.o to check for section mismatches ${MAKE} -f "${srctree}/scripts/Makefile.modpost" vmlinux.o +if [ -n "${CONFIG_LTO_CLANG}" ]; then + # Re-use vmlinux.o, so we can avoid the slow LTO link step in + # vmlinux_link + KBUILD_VMLINUX_INIT= + KBUILD_VMLINUX_MAIN=vmlinux.o + KBUILD_VMLINUX_LIBS= +fi + kallsymso="" kallsyms_vmlinux="" if [ -n "${CONFIG_KALLSYMS}" ]; then -- GitLab From 9abcee5156e441679298a03a5af29675c6161802 Mon Sep 17 00:00:00 2001 From: Sami Tolvanen Date: Fri, 16 Jun 2017 12:52:57 -0700 Subject: [PATCH 1075/1635] FROMLIST: kbuild: fix dynamic ftrace with clang LTO With CONFIG_LTO_CLANG enabled, LLVM IR won't be compiled into object files until modpost_link. This change postpones calls to recordmcount until after this step. In order to exclude ftrace_process_locs from inspection, we add a new code section .text..ftrace, which we tell recordmcount to ignore, and a __norecordmcount attribute for moving functions to this section. Bug: 62093296 Bug: 67506682 Change-Id: Iba2c053968206acf533fadab1eb34a743b5088ee (am from https://patchwork.kernel.org/patch/10060327/) Signed-off-by: Sami Tolvanen --- arch/Kconfig | 2 +- include/asm-generic/vmlinux.lds.h | 1 + include/linux/compiler-clang.h | 7 +++++++ include/linux/compiler_types.h | 4 ++++ kernel/trace/ftrace.c | 6 +++--- scripts/Makefile.build | 14 +++++++++++++- scripts/Makefile.modpost | 4 ++++ scripts/link-vmlinux.sh | 16 ++++++++++++++++ scripts/recordmcount.c | 3 ++- 9 files changed, 51 insertions(+), 6 deletions(-) diff --git a/arch/Kconfig b/arch/Kconfig index e59db803807f..534589f07e7b 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -628,7 +628,7 @@ config LTO_NONE config LTO_CLANG bool "Use clang Link Time Optimization (LTO) (EXPERIMENTAL)" depends on ARCH_SUPPORTS_LTO_CLANG - depends on !FTRACE_MCOUNT_RECORD + depends on !FTRACE_MCOUNT_RECORD || HAVE_C_RECORDMCOUNT select LTO select THIN_ARCHIVES select LD_DEAD_CODE_DATA_ELIMINATION diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h index f4a6799cfbc5..d60eaf87e8d9 100644 --- a/include/asm-generic/vmlinux.lds.h +++ b/include/asm-generic/vmlinux.lds.h @@ -460,6 +460,7 @@ ALIGN_FUNCTION(); \ *(.text.hot TEXT_MAIN .text.fixup .text.unlikely) \ *(.text..refcount) \ + *(.text..ftrace) \ *(.ref.text) \ MEM_KEEP(init.text) \ MEM_KEEP(exit.text) \ diff --git a/include/linux/compiler-clang.h b/include/linux/compiler-clang.h index 070f85d92c15..9f9ab1461367 100644 --- a/include/linux/compiler-clang.h +++ b/include/linux/compiler-clang.h @@ -21,3 +21,10 @@ #ifdef __noretpoline #undef __noretpoline #endif + +#ifdef CONFIG_LTO_CLANG +#ifdef CONFIG_FTRACE_MCOUNT_RECORD +#define __norecordmcount \ + __attribute__((__section__(".text..ftrace"))) +#endif +#endif diff --git a/include/linux/compiler_types.h b/include/linux/compiler_types.h index 6b79a9bba9a7..231c413c615a 100644 --- a/include/linux/compiler_types.h +++ b/include/linux/compiler_types.h @@ -253,6 +253,10 @@ struct ftrace_likely_data { # define __nostackprotector #endif +#ifndef __norecordmcount +#define __norecordmcount +#endif + /* * Assume alignment of return value. */ diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index 7379bcf3baa0..c52b8e4e173a 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c @@ -5572,9 +5572,9 @@ static int ftrace_cmp_ips(const void *a, const void *b) return 0; } -static int ftrace_process_locs(struct module *mod, - unsigned long *start, - unsigned long *end) +static int __norecordmcount ftrace_process_locs(struct module *mod, + unsigned long *start, + unsigned long *end) { struct ftrace_page *start_pg; struct ftrace_page *pg; diff --git a/scripts/Makefile.build b/scripts/Makefile.build index bda756f438f1..b5b05f115775 100644 --- a/scripts/Makefile.build +++ b/scripts/Makefile.build @@ -246,6 +246,12 @@ ifdef BUILD_C_RECORDMCOUNT ifeq ("$(origin RECORDMCOUNT_WARN)", "command line") RECORDMCOUNT_FLAGS = -w endif + +ifdef CONFIG_LTO_CLANG +# With LTO, we postpone running recordmcount until after the LTO link step, so +# let's export the parameters for the link script. +export RECORDMCOUNT_FLAGS +else # Due to recursion, we must skip empty.o. # The empty.o file is created in the make process in order to determine # the target endianness and word size. It is made before all other C @@ -254,22 +260,28 @@ sub_cmd_record_mcount = \ if [ $(@) != "scripts/mod/empty.o" ]; then \ $(objtree)/scripts/recordmcount $(RECORDMCOUNT_FLAGS) "$(@)"; \ fi; +endif + recordmcount_source := $(srctree)/scripts/recordmcount.c \ $(srctree)/scripts/recordmcount.h -else +else # !BUILD_C_RECORDMCOUNT sub_cmd_record_mcount = set -e ; perl $(srctree)/scripts/recordmcount.pl "$(ARCH)" \ "$(if $(CONFIG_CPU_BIG_ENDIAN),big,little)" \ "$(if $(CONFIG_64BIT),64,32)" \ "$(OBJDUMP)" "$(OBJCOPY)" "$(CC) $(KBUILD_CFLAGS)" \ "$(LD)" "$(NM)" "$(RM)" "$(MV)" \ "$(if $(part-of-module),1,0)" "$(@)"; + recordmcount_source := $(srctree)/scripts/recordmcount.pl endif # BUILD_C_RECORDMCOUNT + +ifndef CONFIG_LTO_CLANG cmd_record_mcount = \ if [ "$(findstring $(CC_FLAGS_FTRACE),$(_c_flags))" = \ "$(CC_FLAGS_FTRACE)" ]; then \ $(sub_cmd_record_mcount) \ fi; +endif endif # CONFIG_FTRACE_MCOUNT_RECORD ifdef CONFIG_STACK_VALIDATION diff --git a/scripts/Makefile.modpost b/scripts/Makefile.modpost index c86c99b4a1cf..acd7ea0b5f26 100644 --- a/scripts/Makefile.modpost +++ b/scripts/Makefile.modpost @@ -143,6 +143,10 @@ ifdef CONFIG_LTO_CLANG echo -T $(@:.ko=.o.symversions)) \ -o $@ --whole-archive \ $(filter-out FORCE,$(^:$(modpost-ext).o=.o)) + + ifdef CONFIG_FTRACE_MCOUNT_RECORD + cmd_ld_ko_o += ; $(objtree)/scripts/recordmcount $(RECORDMCOUNT_FLAGS) $@ + endif else cmd_ld_ko_o = \ $(LD) -r $(LDFLAGS) \ diff --git a/scripts/link-vmlinux.sh b/scripts/link-vmlinux.sh index ece268ceaaa1..cfa44718cef7 100755 --- a/scripts/link-vmlinux.sh +++ b/scripts/link-vmlinux.sh @@ -127,6 +127,19 @@ modpost_link() ${LD} ${LDFLAGS} -r -o ${1} $(modversions) ${objects} } +# If CONFIG_LTO_CLANG is selected, we postpone running recordmcount until +# we have compiled LLVM IR to an object file. +recordmcount() +{ + if [ -z "${CONFIG_LTO_CLANG}" ]; then + return + fi + + if [ -n "${CONFIG_FTRACE_MCOUNT_RECORD}" ]; then + scripts/recordmcount ${RECORDMCOUNT_FLAGS} $* + fi +} + # Link of vmlinux # ${1} - optional extra .o files # ${2} - output file @@ -311,6 +324,9 @@ if [ -n "${CONFIG_LTO_CLANG}" ]; then KBUILD_VMLINUX_INIT= KBUILD_VMLINUX_MAIN=vmlinux.o KBUILD_VMLINUX_LIBS= + + # Call recordmcount if needed + recordmcount vmlinux.o fi kallsymso="" diff --git a/scripts/recordmcount.c b/scripts/recordmcount.c index 16e086dcc567..69a769904da7 100644 --- a/scripts/recordmcount.c +++ b/scripts/recordmcount.c @@ -420,7 +420,8 @@ is_mcounted_section_name(char const *const txtname) strcmp(".softirqentry.text", txtname) == 0 || strcmp(".kprobes.text", txtname) == 0 || strcmp(".cpuidle.text", txtname) == 0 || - strcmp(".text.unlikely", txtname) == 0; + (strncmp(".text.", txtname, 6) == 0 && + strcmp(".text..ftrace", txtname) != 0); } /* 32 bit and 64 bit are very similar */ -- GitLab From fbac51e86363869e1bbbdf42a81cf26b6fe434e1 Mon Sep 17 00:00:00 2001 From: Sami Tolvanen Date: Mon, 10 Apr 2017 12:32:24 -0700 Subject: [PATCH 1076/1635] FROMLIST: scripts/mod: disable LTO for empty.c With CONFIG_LTO_CLANG, clang generates LLVM IR instead of ELF object files. As empty.o is used for probing target properties, disable LTO for it to produce an object file instead. Bug: 62093296 Bug: 67506682 Change-Id: I0c7ac7ee0134465cac4a8c3a9c7e8b6347076a2b (am from https://patchwork.kernel.org/patch/10060317/) Signed-off-by: Sami Tolvanen --- scripts/mod/Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/mod/Makefile b/scripts/mod/Makefile index 42c5d50f2bcc..e014b2fdd069 100644 --- a/scripts/mod/Makefile +++ b/scripts/mod/Makefile @@ -1,5 +1,6 @@ # SPDX-License-Identifier: GPL-2.0 OBJECT_FILES_NON_STANDARD := y +CFLAGS_empty.o += $(DISABLE_LTO) hostprogs-y := modpost mk_elfconfig always := $(hostprogs-y) empty.o -- GitLab From 1642d70c0d44daf75d5b0238d97e3f6419b8e892 Mon Sep 17 00:00:00 2001 From: Sami Tolvanen Date: Mon, 1 May 2017 11:08:05 -0700 Subject: [PATCH 1077/1635] FROMLIST: efi/libstub: disable LTO With CONFIG_LTO_CLANG, we produce LLVM IR instead of object files. Since LTO is not really needed here and the Makefile assumes we produce an object file, disable LTO for libstub. Bug: 62093296 Bug: 67506682 Change-Id: Ieaa3d7e2c694655788f480f4351bf7c4d3fce090 (am from https://patchwork.kernel.org/patch/10060309/) Acked-by: Ard Biesheuvel Signed-off-by: Sami Tolvanen --- drivers/firmware/efi/libstub/Makefile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/firmware/efi/libstub/Makefile b/drivers/firmware/efi/libstub/Makefile index adaa4a964f0c..69b3fbfb7f97 100644 --- a/drivers/firmware/efi/libstub/Makefile +++ b/drivers/firmware/efi/libstub/Makefile @@ -20,7 +20,8 @@ cflags-$(CONFIG_EFI_ARMSTUB) += -I$(srctree)/scripts/dtc/libfdt KBUILD_CFLAGS := $(cflags-y) -DDISABLE_BRANCH_PROFILING \ -D__NO_FORTIFY \ $(call cc-option,-ffreestanding) \ - $(call cc-option,-fno-stack-protector) + $(call cc-option,-fno-stack-protector) \ + $(DISABLE_LTO) GCOV_PROFILE := n KASAN_SANITIZE := n -- GitLab From 6b066ebd4e9f593784d385d6ea915ab1ec9ffaf3 Mon Sep 17 00:00:00 2001 From: Alex Matveev Date: Tue, 14 Nov 2017 15:06:17 -0800 Subject: [PATCH 1078/1635] FROMLIST: arm64: make mrs_s and msr_s macros work with LTO Clang's integrated assembler does not allow assembly macros defined in one inline asm block using the .macro directive to be used across separate asm blocks. LLVM developers consider this a feature and not a bug, recommending code refactoring: https://bugs.llvm.org/show_bug.cgi?id=19749 As binutils doesn't allow macros to be redefined, this change uses UNDEFINE_MRS_S and UNDEFINE_MSR_S to define corresponding macros in-place and workaround gcc and clang limitations on redefining macros across different assembler blocks. Bug: 62093296 Bug: 67506682 Change-Id: I803fff57f639b0921ef81f90ec4befe802e7eecf (am from https://patchwork.kernel.org/patch/10060343/) Signed-off-by: Alex Matveev Signed-off-by: Yury Norov Signed-off-by: Sami Tolvanen --- arch/arm64/include/asm/kvm_hyp.h | 8 +++-- arch/arm64/include/asm/sysreg.h | 55 +++++++++++++++++++++----------- 2 files changed, 43 insertions(+), 20 deletions(-) diff --git a/arch/arm64/include/asm/kvm_hyp.h b/arch/arm64/include/asm/kvm_hyp.h index 4572a9b560fa..20bfb8e676e0 100644 --- a/arch/arm64/include/asm/kvm_hyp.h +++ b/arch/arm64/include/asm/kvm_hyp.h @@ -29,7 +29,9 @@ ({ \ u64 reg; \ asm volatile(ALTERNATIVE("mrs %0, " __stringify(r##nvh),\ - "mrs_s %0, " __stringify(r##vh),\ + DEFINE_MRS_S \ + "mrs_s %0, " __stringify(r##vh) "\n"\ + UNDEFINE_MRS_S, \ ARM64_HAS_VIRT_HOST_EXTN) \ : "=r" (reg)); \ reg; \ @@ -39,7 +41,9 @@ do { \ u64 __val = (u64)(v); \ asm volatile(ALTERNATIVE("msr " __stringify(r##nvh) ", %x0",\ - "msr_s " __stringify(r##vh) ", %x0",\ + DEFINE_MSR_S \ + "msr_s " __stringify(r##vh) ", %x0\n"\ + UNDEFINE_MSR_S, \ ARM64_HAS_VIRT_HOST_EXTN) \ : : "rZ" (__val)); \ } while (0) diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h index ede80d47d0ef..3bdec2f5cbb4 100644 --- a/arch/arm64/include/asm/sysreg.h +++ b/arch/arm64/include/asm/sysreg.h @@ -465,20 +465,39 @@ #include -asm( -" .irp num,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30\n" -" .equ .L__reg_num_x\\num, \\num\n" -" .endr\n" +#define __DEFINE_MRS_MSR_S_REGNUM \ +" .irp num,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30\n" \ +" .equ .L__reg_num_x\\num, \\num\n" \ +" .endr\n" \ " .equ .L__reg_num_xzr, 31\n" -"\n" -" .macro mrs_s, rt, sreg\n" - __emit_inst(0xd5200000|(\\sreg)|(.L__reg_num_\\rt)) + +#define DEFINE_MRS_S \ + __DEFINE_MRS_MSR_S_REGNUM \ +" .macro mrs_s, rt, sreg\n" \ +" .inst 0xd5200000|(\\sreg)|(.L__reg_num_\\rt)\n" \ " .endm\n" -"\n" -" .macro msr_s, sreg, rt\n" - __emit_inst(0xd5000000|(\\sreg)|(.L__reg_num_\\rt)) + +#define DEFINE_MSR_S \ + __DEFINE_MRS_MSR_S_REGNUM \ +" .macro msr_s, sreg, rt\n" \ +" .inst 0xd5000000|(\\sreg)|(.L__reg_num_\\rt)\n" \ " .endm\n" -); + +#define UNDEFINE_MRS_S \ +" .purgem mrs_s\n" + +#define UNDEFINE_MSR_S \ +" .purgem msr_s\n" + +#define __mrs_s(r, v) \ + DEFINE_MRS_S \ +" mrs_s %0, " __stringify(r) "\n" \ + UNDEFINE_MRS_S : "=r" (v) + +#define __msr_s(r, v) \ + DEFINE_MSR_S \ +" msr_s " __stringify(r) ", %x0\n" \ + UNDEFINE_MSR_S : : "rZ" (v) /* * Unlike read_cpuid, calls to read_sysreg are never expected to be @@ -504,15 +523,15 @@ asm( * For registers without architectural names, or simply unsupported by * GAS. */ -#define read_sysreg_s(r) ({ \ - u64 __val; \ - asm volatile("mrs_s %0, " __stringify(r) : "=r" (__val)); \ - __val; \ +#define read_sysreg_s(r) ({ \ + u64 __val; \ + asm volatile(__mrs_s(r, __val)); \ + __val; \ }) -#define write_sysreg_s(v, r) do { \ - u64 __val = (u64)(v); \ - asm volatile("msr_s " __stringify(r) ", %x0" : : "rZ" (__val)); \ +#define write_sysreg_s(v, r) do { \ + u64 __val = (u64)(v); \ + asm volatile(__msr_s(r, __val)); \ } while (0) static inline void config_sctlr_el1(u32 clear, u32 set) -- GitLab From 05fc028f049491ece8c53560b68622baf24433e0 Mon Sep 17 00:00:00 2001 From: Sami Tolvanen Date: Thu, 16 Nov 2017 15:56:44 -0800 Subject: [PATCH 1079/1635] ANDROID: arm64: pass code model to LLVMgold With LTO_CLANG, even if we pass -mcmodel to clang, the flag isn't stored in the generated LLVM IR, which means it won't be used for the actual compilation at link time. Therefore, the flag needs to be passed to LLVMgold to actually take effect. Bug: 62093296 Bug: 67506682 Change-Id: I5cd21f97c800466f1bce039df56101ce4087ae20 Signed-off-by: Sami Tolvanen --- arch/arm64/Makefile | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/arm64/Makefile b/arch/arm64/Makefile index 90a387a0d013..e64f5f0c5fd7 100644 --- a/arch/arm64/Makefile +++ b/arch/arm64/Makefile @@ -102,6 +102,10 @@ CHECKFLAGS += -D__aarch64__ -m64 ifeq ($(CONFIG_ARM64_MODULE_CMODEL_LARGE), y) KBUILD_CFLAGS_MODULE += -mcmodel=large +ifeq ($(CONFIG_LTO_CLANG), y) +# Code model is not stored in LLVM IR, so we need to pass it also to LLVMgold +LDFLAGS += -plugin-opt=-code-model=large +endif endif ifeq ($(CONFIG_ARM64_MODULE_PLTS),y) -- GitLab From 9842120b602d83d52edffbfc0a19632924b6ce14 Mon Sep 17 00:00:00 2001 From: Sami Tolvanen Date: Mon, 29 Jan 2018 11:19:19 -0800 Subject: [PATCH 1080/1635] ANDROID: arm64: disable ARM64_ERRATUM_843419 for clang LTO CONFIG_LTO_CLANG depends on GNU gold, which can generate ADR_PREL_PG_HI21 relocations with --fix-cortex-a53-843419, even when -code-model=large has been passed to LLVMgold. Since ARM64_ERRATUM_843419 disables kernel support for these relocations, disable the erratum when LTO is used. Bug: 67506682 Change-Id: I5d419cae432a26af5b6eff362b869639c64c6fb3 Signed-off-by: Sami Tolvanen --- arch/arm64/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index cc904e0a1a59..4126a91a48f4 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -433,7 +433,7 @@ config ARM64_ERRATUM_845719 config ARM64_ERRATUM_843419 bool "Cortex-A53: 843419: A load or store might access an incorrect address" - default y + default y if !LTO_CLANG select ARM64_MODULE_CMODEL_LARGE if MODULES help This option links the kernel with '--fix-cortex-a53-843419' and -- GitLab From 10dd8c281cb5adabef002984d6d5fe48fee6f2d2 Mon Sep 17 00:00:00 2001 From: Sami Tolvanen Date: Fri, 10 Nov 2017 14:00:24 -0800 Subject: [PATCH 1081/1635] FROMLIST: arm64: disable RANDOMIZE_MODULE_REGION_FULL with LTO_CLANG RANDOMIZE_MODULE_REGION_FULL results in "overflow in relocation type 275" when loading a module linked with GNU gold. As a workaround, disable when LTO_CLANG is selected. Bug: 62093296 Bug: 67506682 Change-Id: I6af3de0dc2e6a5053c527d7cb7fb45cb249b68b3 (am from https://patchwork.kernel.org/patch/10060337/) Signed-off-by: Sami Tolvanen --- arch/arm64/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index 4126a91a48f4..3d8edf2bfb8c 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -1047,7 +1047,7 @@ config RANDOMIZE_BASE config RANDOMIZE_MODULE_REGION_FULL bool "Randomize the module region independently from the core kernel" - depends on RANDOMIZE_BASE + depends on RANDOMIZE_BASE && !LTO_CLANG default y help Randomizes the location of the module region without considering the -- GitLab From bad1692b1ae8c148c71671e12b910543496e471f Mon Sep 17 00:00:00 2001 From: Sami Tolvanen Date: Thu, 2 Nov 2017 09:34:42 -0700 Subject: [PATCH 1082/1635] FROMLIST: arm64: select ARCH_SUPPORTS_LTO_CLANG Allow CONFIG_LTO_CLANG to be enabled for the architecture. Bug: 62093296 Bug: 67506682 Change-Id: Id8e06b49877c4de2f15b51fc432d601b83b2c68f (am from https://patchwork.kernel.org/patch/10060333/) Signed-off-by: Sami Tolvanen --- arch/arm64/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index 3d8edf2bfb8c..785b5eccd4a3 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -24,6 +24,7 @@ config ARM64 select ARCH_HAVE_NMI_SAFE_CMPXCHG if ACPI_APEI_SEA select ARCH_USE_CMPXCHG_LOCKREF select ARCH_SUPPORTS_MEMORY_FAILURE + select ARCH_SUPPORTS_LTO_CLANG select ARCH_SUPPORTS_ATOMIC_RMW select ARCH_SUPPORTS_NUMA_BALANCING select ARCH_WANT_COMPAT_IPC_PARSE_VERSION -- GitLab From 84cf1990330703c1d560ec63cba820e508707519 Mon Sep 17 00:00:00 2001 From: Sami Tolvanen Date: Tue, 19 Dec 2017 08:55:23 -0800 Subject: [PATCH 1083/1635] ANDROID: arm64: vdso: disable LTO Due to a bug in clang, vdso fails to build when both LTO_CLANG and CC_OPTIMIZE_FOR_SIZE are enabled: https://bugs.llvm.org/show_bug.cgi?id=32155 Disable LTO for vdso to work around the problem. Bug: 62093296 Bug: 67506682 Change-Id: I1d0279535fd389db4c829e4556f9ef728f240a34 Signed-off-by: Sami Tolvanen --- arch/arm64/kernel/vdso/Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/kernel/vdso/Makefile b/arch/arm64/kernel/vdso/Makefile index b215c712d897..ef3f9d9d4062 100644 --- a/arch/arm64/kernel/vdso/Makefile +++ b/arch/arm64/kernel/vdso/Makefile @@ -15,6 +15,7 @@ obj-vdso := $(addprefix $(obj)/, $(obj-vdso)) ccflags-y := -shared -fno-common -fno-builtin ccflags-y += -nostdlib -Wl,-soname=linux-vdso.so.1 \ $(call cc-ldoption, -Wl$(comma)--hash-style=sysv) +ccflags-y += $(DISABLE_LTO) # Disable gcov profiling for VDSO code GCOV_PROFILE := n -- GitLab From 0cdcef50ae124a8ca42c3797f8a6511934e6e483 Mon Sep 17 00:00:00 2001 From: Sami Tolvanen Date: Tue, 5 Dec 2017 12:54:13 -0800 Subject: [PATCH 1084/1635] ANDROID: drivers/misc: disable LTO for lkdtm_rodata.o Disable LTO for lkdtm_rodata.o to allow objcopy to be used to manipulate sections. Bug: 62093296 Bug: 67506682 Change-Id: Iedd1a3a2a9b06f44e7ceb6ac287ea764eaf5ef0a Signed-off-by: Sami Tolvanen --- drivers/misc/Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index 63e802aebb03..a4ccc7d3f914 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -69,6 +69,7 @@ lkdtm-$(CONFIG_LKDTM) += lkdtm_rodata_objcopy.o lkdtm-$(CONFIG_LKDTM) += lkdtm_usercopy.o KCOV_INSTRUMENT_lkdtm_rodata.o := n +CFLAGS_lkdtm_rodata.o += $(DISABLE_LTO) OBJCOPYFLAGS := OBJCOPYFLAGS_lkdtm_rodata_objcopy.o := \ -- GitLab From 727e8415818e53ba15d4e6106e7931aca5cb9032 Mon Sep 17 00:00:00 2001 From: Sami Tolvanen Date: Fri, 8 Dec 2017 15:49:24 -0800 Subject: [PATCH 1085/1635] ANDROID: HACK: init: ensure initcall ordering with LTO With LTO, LLVM sorts initcalls in a single translation unit alphabetically based on the name of the function (or actually, the variable stored in the initcall section). Use __COUNTER__ in the variable name in an attempt to preserve the intended order. Bug: 62093296 Bug: 67506682 Change-Id: I4fa3cb93cba967a1440ac53328eb6b8ac649ff36 Signed-off-by: Sami Tolvanen --- include/linux/init.h | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/include/linux/init.h b/include/linux/init.h index 07cab8a053af..750739747e2e 100644 --- a/include/linux/init.h +++ b/include/linux/init.h @@ -153,6 +153,15 @@ extern bool initcall_debug; #ifndef __ASSEMBLY__ +#ifdef CONFIG_LTO_CLANG + /* prepend the variable name with __COUNTER__ to ensure correct ordering */ + #define ___initcall_name2(c, fn, id) __initcall_##c##_##fn##id + #define ___initcall_name1(c, fn, id) ___initcall_name2(c, fn, id) + #define __initcall_name(fn, id) ___initcall_name1(__COUNTER__, fn, id) +#else + #define __initcall_name(fn, id) __initcall_##fn##id +#endif + /* * initcalls are now grouped by functionality into separate * subsections. Ordering inside the subsections is determined @@ -170,7 +179,7 @@ extern bool initcall_debug; */ #define __define_initcall(fn, id) \ - static initcall_t __initcall_##fn##id __used \ + static initcall_t __initcall_name(fn, id) __used \ __attribute__((__section__(".initcall" #id ".init"))) = fn; /* -- GitLab From d590fd127d473216c7877e18088c53f445b45d2d Mon Sep 17 00:00:00 2001 From: Sami Tolvanen Date: Thu, 11 May 2017 15:03:36 -0700 Subject: [PATCH 1086/1635] ANDROID: add support for clang Control Flow Integrity (CFI) This change adds the CONFIG_CFI_CLANG option, CFI error handling, and a faster look-up table for cross module CFI checks. Bug: 67506682 Change-Id: Ic009f0a629b552a0eb16e6d89808c7029e91447d Signed-off-by: Sami Tolvanen --- Makefile | 32 ++++ arch/Kconfig | 28 +++ include/asm-generic/vmlinux.lds.h | 3 + include/linux/cfi.h | 38 ++++ include/linux/compiler-clang.h | 2 + include/linux/compiler_types.h | 4 + include/linux/init.h | 2 +- include/linux/module.h | 5 + init/Kconfig | 2 +- kernel/Makefile | 4 + kernel/cfi.c | 300 ++++++++++++++++++++++++++++++ kernel/module.c | 27 +++ net/Kconfig | 1 + 13 files changed, 446 insertions(+), 2 deletions(-) create mode 100644 include/linux/cfi.h create mode 100644 kernel/cfi.c diff --git a/Makefile b/Makefile index 67e96818a79a..064c38ebb209 100644 --- a/Makefile +++ b/Makefile @@ -829,6 +829,33 @@ export DISABLE_LTO export LDFINAL_vmlinux LDFLAGS_FINAL_vmlinux endif +ifdef CONFIG_CFI_CLANG +cfi-clang-flags += -fsanitize=cfi +DISABLE_CFI_CLANG := -fno-sanitize=cfi +ifdef CONFIG_MODULES +cfi-clang-flags += -fsanitize-cfi-cross-dso +DISABLE_CFI_CLANG += -fno-sanitize-cfi-cross-dso +endif +ifdef CONFIG_CFI_PERMISSIVE +cfi-clang-flags += -fsanitize-recover=cfi -fno-sanitize-trap=cfi +endif + +# also disable CFI when LTO is disabled +DISABLE_LTO_CLANG += $(DISABLE_CFI_CLANG) +# allow disabling only clang CFI where needed +export DISABLE_CFI_CLANG +endif + +ifdef CONFIG_CFI +# cfi-flags are re-tested in prepare-compiler-check +cfi-flags := $(cfi-clang-flags) +KBUILD_CFLAGS += $(cfi-flags) + +DISABLE_CFI := $(DISABLE_CFI_CLANG) +DISABLE_LTO += $(DISABLE_CFI) +export DISABLE_CFI +endif + # arch Makefile may override CC so keep this after arch Makefile is included NOSTDINC_FLAGS += -nostdinc -isystem $(shell $(CC) -print-file-name=include) CHECKFLAGS += $(NOSTDINC_FLAGS) @@ -1175,6 +1202,11 @@ ifdef stackp-check @echo Cannot use CONFIG_CC_STACKPROTECTOR_$(stackp-name): \ $(stackp-flag) available but compiler is broken >&2 && exit 1 endif +endif +ifdef cfi-flags + ifeq ($(call cc-option, $(cfi-flags)),) + @echo Cannot use CONFIG_CFI: $(cfi-flags) not supported by compiler >&2 && exit 1 + endif endif @: diff --git a/arch/Kconfig b/arch/Kconfig index 534589f07e7b..03cff3c16b1c 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -645,6 +645,34 @@ config LTO_CLANG endchoice +config CFI + bool + +config CFI_PERMISSIVE + bool "Use CFI in permissive mode" + depends on CFI + help + When selected, Control Flow Integrity (CFI) violations result in a + warning instead of a kernel panic. This option is useful for finding + CFI violations in drivers during development. + +config CFI_CLANG + bool "Use clang Control Flow Integrity (CFI) (EXPERIMENTAL)" + depends on LTO_CLANG + depends on KALLSYMS + select CFI + help + This option enables clang Control Flow Integrity (CFI), which adds + runtime checking for indirect function calls. + +config CFI_CLANG_SHADOW + bool "Use CFI shadow to speed up cross-module checks" + default y + depends on CFI_CLANG + help + If you select this option, the kernel builds a fast look-up table of + CFI check functions in loaded modules to reduce overhead. + config HAVE_ARCH_WITHIN_STACK_FRAMES bool help diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h index d60eaf87e8d9..6612cf2f760b 100644 --- a/include/asm-generic/vmlinux.lds.h +++ b/include/asm-generic/vmlinux.lds.h @@ -67,10 +67,12 @@ */ #ifdef CONFIG_LD_DEAD_CODE_DATA_ELIMINATION #define TEXT_MAIN .text .text.[0-9a-zA-Z_]* +#define TEXT_CFI_MAIN .text.cfi .text.[0-9a-zA-Z_]*.cfi #define DATA_MAIN .data .data.[0-9a-zA-Z_]* #define BSS_MAIN .bss .bss.[0-9a-zA-Z_]* #else #define TEXT_MAIN .text +#define TEXT_CFI_MAIN .text.cfi #define DATA_MAIN .data #define BSS_MAIN .bss #endif @@ -461,6 +463,7 @@ *(.text.hot TEXT_MAIN .text.fixup .text.unlikely) \ *(.text..refcount) \ *(.text..ftrace) \ + *(TEXT_CFI_MAIN) \ *(.ref.text) \ MEM_KEEP(init.text) \ MEM_KEEP(exit.text) \ diff --git a/include/linux/cfi.h b/include/linux/cfi.h new file mode 100644 index 000000000000..e27033d5dd53 --- /dev/null +++ b/include/linux/cfi.h @@ -0,0 +1,38 @@ +#ifndef _LINUX_CFI_H +#define _LINUX_CFI_H + +#include + +#ifdef CONFIG_CFI_CLANG +#ifdef CONFIG_MODULES + +typedef void (*cfi_check_fn)(uint64_t, void *, void *); + +/* Compiler-generated function in each module, and the kernel */ +#define CFI_CHECK_FN __cfi_check +#define CFI_CHECK_FN_NAME __stringify(CFI_CHECK_FN) + +extern void CFI_CHECK_FN(uint64_t, void *, void *); + +#ifdef CONFIG_CFI_CLANG_SHADOW +extern void cfi_module_add(struct module *mod, unsigned long min_addr, + unsigned long max_addr); + +extern void cfi_module_remove(struct module *mod, unsigned long min_addr, + unsigned long max_addr); +#else +static inline void cfi_module_add(struct module *mod, unsigned long min_addr, + unsigned long max_addr) +{ +} + +static inline void cfi_module_remove(struct module *mod, unsigned long min_addr, + unsigned long max_addr) +{ +} +#endif /* CONFIG_CFI_CLANG_SHADOW */ + +#endif /* CONFIG_MODULES */ +#endif /* CONFIG_CFI_CLANG */ + +#endif /* _LINUX_CFI_H */ diff --git a/include/linux/compiler-clang.h b/include/linux/compiler-clang.h index 9f9ab1461367..af722dea7562 100644 --- a/include/linux/compiler-clang.h +++ b/include/linux/compiler-clang.h @@ -27,4 +27,6 @@ #define __norecordmcount \ __attribute__((__section__(".text..ftrace"))) #endif + +#define __nocfi __attribute__((no_sanitize("cfi"))) #endif diff --git a/include/linux/compiler_types.h b/include/linux/compiler_types.h index 231c413c615a..247b5715c9ac 100644 --- a/include/linux/compiler_types.h +++ b/include/linux/compiler_types.h @@ -257,6 +257,10 @@ struct ftrace_likely_data { #define __norecordmcount #endif +#ifndef __nocfi +#define __nocfi +#endif + /* * Assume alignment of return value. */ diff --git a/include/linux/init.h b/include/linux/init.h index 750739747e2e..f138e5b918c2 100644 --- a/include/linux/init.h +++ b/include/linux/init.h @@ -47,7 +47,7 @@ /* These are for everybody (although not all archs will actually discard it in modules) */ -#define __init __section(.init.text) __cold __inittrace __latent_entropy __noinitretpoline +#define __init __section(.init.text) __cold __inittrace __latent_entropy __noinitretpoline __nocfi #define __initdata __section(.init.data) #define __initconst __section(.init.rodata) #define __exitdata __section(.exit.data) diff --git a/include/linux/module.h b/include/linux/module.h index b1cc541f2ddf..b28e0940b428 100644 --- a/include/linux/module.h +++ b/include/linux/module.h @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -346,6 +347,10 @@ struct module { const s32 *crcs; unsigned int num_syms; +#ifdef CONFIG_CFI_CLANG + cfi_check_fn cfi_check; +#endif + /* Kernel parameters. */ #ifdef CONFIG_SYSFS struct mutex param_lock; diff --git a/init/Kconfig b/init/Kconfig index cc828a1d2232..0d0798a6706d 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -1929,7 +1929,7 @@ endif # MODULES config MODULES_TREE_LOOKUP def_bool y - depends on PERF_EVENTS || TRACING + depends on PERF_EVENTS || TRACING || CFI_CLANG config INIT_ALL_POSSIBLE bool diff --git a/kernel/Makefile b/kernel/Makefile index 172d151d429c..de59ee7b2422 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -34,6 +34,9 @@ KASAN_SANITIZE_kcov.o := n # cond_syscall is currently not LTO compatible CFLAGS_sys_ni.o = $(DISABLE_LTO) +# Don't instrument error handlers +CFLAGS_cfi.o = $(DISABLE_CFI_CLANG) + obj-y += sched/ obj-y += locking/ obj-y += power/ @@ -101,6 +104,7 @@ obj-$(CONFIG_TRACEPOINTS) += trace/ obj-$(CONFIG_IRQ_WORK) += irq_work.o obj-$(CONFIG_CPU_PM) += cpu_pm.o obj-$(CONFIG_BPF) += bpf/ +obj-$(CONFIG_CFI_CLANG) += cfi.o obj-$(CONFIG_PERF_EVENTS) += events/ diff --git a/kernel/cfi.c b/kernel/cfi.c new file mode 100644 index 000000000000..7c403dc5091c --- /dev/null +++ b/kernel/cfi.c @@ -0,0 +1,300 @@ +/* + * CFI (Control Flow Integrity) error and slowpath handling + * + * Copyright (C) 2017 Google, Inc. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Compiler-defined handler names */ +#ifdef CONFIG_CFI_PERMISSIVE +#define cfi_failure_handler __ubsan_handle_cfi_check_fail +#define cfi_slowpath_handler __cfi_slowpath_diag +#else /* enforcing */ +#define cfi_failure_handler __ubsan_handle_cfi_check_fail_abort +#define cfi_slowpath_handler __cfi_slowpath +#endif /* CONFIG_CFI_PERMISSIVE */ + +static inline void handle_cfi_failure() +{ +#ifdef CONFIG_CFI_PERMISSIVE + WARN_RATELIMIT(1, "CFI failure:\n"); +#else + pr_err("CFI failure:\n"); + BUG(); +#endif +} + +#ifdef CONFIG_MODULES +#ifdef CONFIG_CFI_CLANG_SHADOW +struct shadow_range { + /* Module address range */ + unsigned long mod_min_addr; + unsigned long mod_max_addr; + /* Module page range */ + unsigned long min_page; + unsigned long max_page; +}; + +#define SHADOW_ORDER 1 +#define SHADOW_PAGES (1 << SHADOW_ORDER) +#define SHADOW_SIZE \ + ((SHADOW_PAGES * PAGE_SIZE - sizeof(struct shadow_range)) / sizeof(u16)) +#define SHADOW_INVALID 0xFFFF + +struct cfi_shadow { + /* Page range covered by the shadow */ + struct shadow_range r; + /* Page offsets to __cfi_check functions in modules */ + u16 shadow[SHADOW_SIZE]; +}; + +static DEFINE_SPINLOCK(shadow_update_lock); +static struct cfi_shadow __rcu *cfi_shadow __read_mostly = NULL; + +static inline int ptr_to_shadow(const struct cfi_shadow *s, unsigned long ptr) +{ + unsigned long index; + unsigned long page = ptr >> PAGE_SHIFT; + + if (unlikely(page < s->r.min_page)) + return -1; /* Outside of module area */ + + index = page - s->r.min_page; + + if (index >= SHADOW_SIZE) + return -1; /* Cannot be addressed with shadow */ + + return (int)index; +} + +static inline unsigned long shadow_to_ptr(const struct cfi_shadow *s, + int index) +{ + BUG_ON(index < 0 || index >= SHADOW_SIZE); + + if (unlikely(s->shadow[index] == SHADOW_INVALID)) + return 0; + + return (s->r.min_page + s->shadow[index]) << PAGE_SHIFT; +} + +static void prepare_next_shadow(const struct cfi_shadow __rcu *prev, + struct cfi_shadow *next) +{ + int i, index, check; + + /* Mark everything invalid */ + memset(next->shadow, 0xFF, sizeof(next->shadow)); + + if (!prev) + return; /* No previous shadow */ + + /* If the base address didn't change, update is not needed */ + if (prev->r.min_page == next->r.min_page) { + memcpy(next->shadow, prev->shadow, sizeof(next->shadow)); + return; + } + + /* Convert the previous shadow to the new address range */ + for (i = 0; i < SHADOW_SIZE; ++i) { + if (prev->shadow[i] == SHADOW_INVALID) + continue; + + index = ptr_to_shadow(next, shadow_to_ptr(prev, i)); + if (index < 0) + continue; + + check = ptr_to_shadow(next, + shadow_to_ptr(prev, prev->shadow[i])); + if (check < 0) + continue; + + next->shadow[index] = (u16)check; + } +} + +static void add_module_to_shadow(struct cfi_shadow *s, struct module *mod) +{ + unsigned long ptr; + unsigned long min_page_addr; + unsigned long max_page_addr; + unsigned long check = (unsigned long)mod->cfi_check; + int check_index = ptr_to_shadow(s, check); + + BUG_ON((check & PAGE_MASK) != check); /* Must be page aligned */ + + if (check_index < 0) + return; /* Module not addressable with shadow */ + + min_page_addr = (unsigned long)mod->core_layout.base & PAGE_MASK; + max_page_addr = (unsigned long)mod->core_layout.base + + mod->core_layout.text_size; + max_page_addr &= PAGE_MASK; + + /* For each page, store the check function index in the shadow */ + for (ptr = min_page_addr; ptr <= max_page_addr; ptr += PAGE_SIZE) { + int index = ptr_to_shadow(s, ptr); + if (index >= 0) { + /* Assume a page only contains code for one module */ + BUG_ON(s->shadow[index] != SHADOW_INVALID); + s->shadow[index] = (u16)check_index; + } + } +} + +static void remove_module_from_shadow(struct cfi_shadow *s, struct module *mod) +{ + unsigned long ptr; + unsigned long min_page_addr; + unsigned long max_page_addr; + + min_page_addr = (unsigned long)mod->core_layout.base & PAGE_MASK; + max_page_addr = (unsigned long)mod->core_layout.base + + mod->core_layout.text_size; + max_page_addr &= PAGE_MASK; + + for (ptr = min_page_addr; ptr <= max_page_addr; ptr += PAGE_SIZE) { + int index = ptr_to_shadow(s, ptr); + if (index >= 0) + s->shadow[index] = SHADOW_INVALID; + } +} + +typedef void (*update_shadow_fn)(struct cfi_shadow *, struct module *); + +static void update_shadow(struct module *mod, unsigned long min_addr, + unsigned long max_addr, update_shadow_fn fn) +{ + struct cfi_shadow *prev; + struct cfi_shadow *next = (struct cfi_shadow *) + __get_free_pages(GFP_KERNEL, SHADOW_ORDER); + + BUG_ON(!next); + + next->r.mod_min_addr = min_addr; + next->r.mod_max_addr = max_addr; + next->r.min_page = min_addr >> PAGE_SHIFT; + next->r.max_page = max_addr >> PAGE_SHIFT; + + spin_lock(&shadow_update_lock); + prev = rcu_dereference_protected(cfi_shadow, 1); + prepare_next_shadow(prev, next); + + fn(next, mod); + set_memory_ro((unsigned long)next, SHADOW_PAGES); + rcu_assign_pointer(cfi_shadow, next); + + spin_unlock(&shadow_update_lock); + synchronize_rcu(); + + if (prev) { + set_memory_rw((unsigned long)prev, SHADOW_PAGES); + free_pages((unsigned long)prev, SHADOW_ORDER); + } +} + +void cfi_module_add(struct module *mod, unsigned long min_addr, + unsigned long max_addr) +{ + update_shadow(mod, min_addr, max_addr, add_module_to_shadow); +} +EXPORT_SYMBOL(cfi_module_add); + +void cfi_module_remove(struct module *mod, unsigned long min_addr, + unsigned long max_addr) +{ + update_shadow(mod, min_addr, max_addr, remove_module_from_shadow); +} +EXPORT_SYMBOL(cfi_module_remove); + +static inline cfi_check_fn ptr_to_check_fn(const struct cfi_shadow __rcu *s, + unsigned long ptr) +{ + int index; + unsigned long check; + + if (unlikely(!s)) + return NULL; /* No shadow available */ + + if (ptr < s->r.mod_min_addr || ptr > s->r.mod_max_addr) + return NULL; /* Not in a mapped module */ + + index = ptr_to_shadow(s, ptr); + if (index < 0) + return NULL; /* Cannot be addressed with shadow */ + + return (cfi_check_fn)shadow_to_ptr(s, index); +} +#endif /* CONFIG_CFI_CLANG_SHADOW */ + +static inline cfi_check_fn find_module_cfi_check(void *ptr) +{ + struct module *mod; + + preempt_disable(); + mod = __module_address((unsigned long)ptr); + preempt_enable(); + + if (mod) + return mod->cfi_check; + + return CFI_CHECK_FN; +} + +static inline cfi_check_fn find_cfi_check(void *ptr) +{ +#ifdef CONFIG_CFI_CLANG_SHADOW + cfi_check_fn f; + + if (!rcu_access_pointer(cfi_shadow)) + return CFI_CHECK_FN; /* No loaded modules */ + + /* Look up the __cfi_check function to use */ + rcu_read_lock(); + f = ptr_to_check_fn(rcu_dereference(cfi_shadow), (unsigned long)ptr); + rcu_read_unlock(); + + if (f) + return f; + + /* + * Fall back to find_module_cfi_check, which works also for a larger + * module address space, but is slower. + */ +#endif /* CONFIG_CFI_CLANG_SHADOW */ + + return find_module_cfi_check(ptr); +} + +void cfi_slowpath_handler(uint64_t id, void *ptr, void *diag) +{ + cfi_check_fn check = find_cfi_check(ptr); + + if (likely(check)) + check(id, ptr, diag); + else /* Don't allow unchecked modules */ + handle_cfi_failure(); +} +EXPORT_SYMBOL(cfi_slowpath_handler); +#endif /* CONFIG_MODULES */ + +void cfi_failure_handler(void *data, void *value, void *vtable) +{ + handle_cfi_failure(); +} +EXPORT_SYMBOL(cfi_failure_handler); + +void __cfi_check_fail(void *data, void *value) +{ + handle_cfi_failure(); +} diff --git a/kernel/module.c b/kernel/module.c index 690c0651c40f..365a85deff6a 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -2121,6 +2121,8 @@ void __weak module_arch_freeing_init(struct module *mod) { } +static void cfi_cleanup(struct module *mod); + /* Free a module, remove from lists, etc. */ static void free_module(struct module *mod) { @@ -2162,6 +2164,10 @@ static void free_module(struct module *mod) /* This may be empty, but that's OK */ disable_ro_nx(&mod->init_layout); + + /* Clean up CFI for the module. */ + cfi_cleanup(mod); + module_arch_freeing_init(mod); module_memfree(mod->init_layout.base); kfree(mod->args); @@ -3359,6 +3365,8 @@ int __weak module_finalize(const Elf_Ehdr *hdr, return 0; } +static void cfi_init(struct module *mod); + static int post_relocation(struct module *mod, const struct load_info *info) { /* Sort exception table now relocations are done. */ @@ -3371,6 +3379,9 @@ static int post_relocation(struct module *mod, const struct load_info *info) /* Setup kallsyms-specific fields. */ add_kallsyms(mod, info); + /* Setup CFI for the module. */ + cfi_init(mod); + /* Arch-specific module finalizing. */ return module_finalize(info->hdr, info->sechdrs, mod); } @@ -4109,6 +4120,22 @@ int module_kallsyms_on_each_symbol(int (*fn)(void *, const char *, } #endif /* CONFIG_KALLSYMS */ +static void cfi_init(struct module *mod) +{ +#ifdef CONFIG_CFI_CLANG + mod->cfi_check = + (cfi_check_fn)mod_find_symname(mod, CFI_CHECK_FN_NAME); + cfi_module_add(mod, module_addr_min, module_addr_max); +#endif +} + +static void cfi_cleanup(struct module *mod) +{ +#ifdef CONFIG_CFI_CLANG + cfi_module_remove(mod, module_addr_min, module_addr_max); +#endif +} + /* Maximum number of characters written by module_flags() */ #define MODULE_FLAGS_BUF_SIZE (TAINT_FLAGS_COUNT + 4) diff --git a/net/Kconfig b/net/Kconfig index 454a26178f6d..999cc6beacc3 100644 --- a/net/Kconfig +++ b/net/Kconfig @@ -290,6 +290,7 @@ config BPF_JIT bool "enable BPF Just In Time compiler" depends on HAVE_CBPF_JIT || HAVE_EBPF_JIT depends on MODULES + depends on !CFI ---help--- Berkeley Packet Filter filtering capabilities are normally handled by an interpreter. This option allows kernel to generate a native -- GitLab From 926c9941d261ccdb81c81be63cb9e6b03498f5e5 Mon Sep 17 00:00:00 2001 From: Sami Tolvanen Date: Wed, 14 Feb 2018 10:26:35 -0800 Subject: [PATCH 1087/1635] ANDROID: kallsyms: strip the .cfi postfix from symbols with CONFIG_CFI_CLANG With CFI enabled, LLVM appends .cfi to most function names, which potentially breaks user space tools. While stripping the postfix is not optimal either, this should at least create less confusion. Bug: 67506682 Bug: 73328469 Change-Id: I253f34a562629032ddd792b8498e171109ea7cbc Signed-off-by: Sami Tolvanen --- kernel/kallsyms.c | 49 ++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 44 insertions(+), 5 deletions(-) diff --git a/kernel/kallsyms.c b/kernel/kallsyms.c index 127e7cfafa55..3314c0c6c030 100644 --- a/kernel/kallsyms.c +++ b/kernel/kallsyms.c @@ -302,6 +302,24 @@ int kallsyms_lookup_size_offset(unsigned long addr, unsigned long *symbolsize, !!__bpf_address_lookup(addr, symbolsize, offset, namebuf); } +#ifdef CONFIG_CFI_CLANG +/* + * LLVM appends .cfi to function names when CONFIG_CFI_CLANG is enabled, + * which causes confusion and potentially breaks user space tools, so we + * will strip the postfix from expanded symbol names. + */ +static inline void cleanup_symbol_name(char *s) +{ + char *res; + + res = strrchr(s, '.'); + if (res && !strcmp(res, ".cfi")) + *res = '\0'; +} +#else +static inline void cleanup_symbol_name(char *s) {} +#endif + /* * Lookup an address * - modname is set to NULL if it's in the kernel. @@ -328,7 +346,9 @@ const char *kallsyms_lookup(unsigned long addr, namebuf, KSYM_NAME_LEN); if (modname) *modname = NULL; - return namebuf; + + ret = namebuf; + goto found; } /* See if it's in a module or a BPF JITed image. */ @@ -337,11 +357,16 @@ const char *kallsyms_lookup(unsigned long addr, if (!ret) ret = bpf_address_lookup(addr, symbolsize, offset, modname, namebuf); + +found: + cleanup_symbol_name(namebuf); return ret; } int lookup_symbol_name(unsigned long addr, char *symname) { + int res; + symname[0] = '\0'; symname[KSYM_NAME_LEN - 1] = '\0'; @@ -352,15 +377,23 @@ int lookup_symbol_name(unsigned long addr, char *symname) /* Grab name */ kallsyms_expand_symbol(get_symbol_offset(pos), symname, KSYM_NAME_LEN); - return 0; + goto found; } /* See if it's in a module. */ - return lookup_module_symbol_name(addr, symname); + res = lookup_module_symbol_name(addr, symname); + if (res) + return res; + +found: + cleanup_symbol_name(symname); + return 0; } int lookup_symbol_attrs(unsigned long addr, unsigned long *size, unsigned long *offset, char *modname, char *name) { + int res; + name[0] = '\0'; name[KSYM_NAME_LEN - 1] = '\0'; @@ -372,10 +405,16 @@ int lookup_symbol_attrs(unsigned long addr, unsigned long *size, kallsyms_expand_symbol(get_symbol_offset(pos), name, KSYM_NAME_LEN); modname[0] = '\0'; - return 0; + goto found; } /* See if it's in a module. */ - return lookup_module_symbol_attrs(addr, size, offset, modname, name); + res = lookup_module_symbol_attrs(addr, size, offset, modname, name); + if (res) + return res; + +found: + cleanup_symbol_name(name); + return 0; } /* Look up a kernel symbol and return it in a text buffer. */ -- GitLab From 2b5ee2e8c5f44f175710d446adb07a8eb992844d Mon Sep 17 00:00:00 2001 From: Sami Tolvanen Date: Fri, 18 Aug 2017 14:31:23 -0700 Subject: [PATCH 1088/1635] ANDROID: arm64: disable CFI for cpu_replace_ttbr1 Disable CFI to allow an indirect call to a physical address. Bug: 67506682 Change-Id: I0ec38f34245a4ad52f508f6989093526d3bf442f Signed-off-by: Sami Tolvanen --- arch/arm64/include/asm/mmu_context.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/include/asm/mmu_context.h b/arch/arm64/include/asm/mmu_context.h index 779d7a2ec5ec..f7ff06580721 100644 --- a/arch/arm64/include/asm/mmu_context.h +++ b/arch/arm64/include/asm/mmu_context.h @@ -132,7 +132,7 @@ static inline void cpu_install_idmap(void) * Atomically replaces the active TTBR1_EL1 PGD with a new VA-compatible PGD, * avoiding the possibility of conflicting TLB entries being allocated. */ -static inline void cpu_replace_ttbr1(pgd_t *pgd) +static inline void __nocfi cpu_replace_ttbr1(pgd_t *pgd) { typedef void (ttbr_replace_func)(phys_addr_t); extern ttbr_replace_func idmap_cpu_replace_ttbr1; -- GitLab From 5c8fae60b7ba7853adab0287d4ecb9ddd208c478 Mon Sep 17 00:00:00 2001 From: Greg Hackmann Date: Mon, 9 Apr 2018 13:48:49 -0700 Subject: [PATCH 1089/1635] ANDROID: arm64: mark kpti_install_ng_mappings as __nocfi 4.9.93 panics on boot when CFI_CLANG and UNMAP_KERNEL_AT_EL0 are both enabled. From Sami Tolvanen: "kpti_install_ng_mappings makes an indirect call to a physical address, which trips CFI. Adding the __nocfi attribute to this function should fix the problem." Bug: 77811249 Change-Id: I87d1ceb29f1ba2caee8954547596f4236bdfc31f Reported-by: Jean-Baptiste Theou Signed-off-by: Greg Hackmann --- arch/arm64/kernel/cpufeature.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c index 345d4e521191..332313a33ba8 100644 --- a/arch/arm64/kernel/cpufeature.c +++ b/arch/arm64/kernel/cpufeature.c @@ -842,7 +842,7 @@ static bool unmap_kernel_at_el0(const struct arm64_cpu_capabilities *entry, ID_AA64PFR0_CSV3_SHIFT); } -static int kpti_install_ng_mappings(void *__unused) +static int __nocfi kpti_install_ng_mappings(void *__unused) { typedef void (kpti_remap_fn)(int, int, phys_addr_t); extern kpti_remap_fn idmap_kpti_install_ng_mappings; -- GitLab From eb409e493b987af26cbdebba1c87e0868a77e08b Mon Sep 17 00:00:00 2001 From: Sami Tolvanen Date: Mon, 23 Apr 2018 12:52:07 -0700 Subject: [PATCH 1090/1635] ANDROID: arm64: kvm: disable CFI Disable CFI for code that runs at EL2 because __cfi_check only understands EL1 addresses. Bug: 67506682 Change-Id: Ia582943be0b31669d88464fd99228a5368b1aa6a Signed-off-by: Sami Tolvanen --- arch/arm64/kvm/hyp/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/kvm/hyp/Makefile b/arch/arm64/kvm/hyp/Makefile index 19fa1c6b6b69..bfa00a9e161d 100644 --- a/arch/arm64/kvm/hyp/Makefile +++ b/arch/arm64/kvm/hyp/Makefile @@ -3,7 +3,7 @@ # Makefile for Kernel-based Virtual Machine module, HYP part # -ccflags-y += -fno-stack-protector -DDISABLE_BRANCH_PROFILING +ccflags-y += -fno-stack-protector -DDISABLE_BRANCH_PROFILING $(DISABLE_CFI) ifeq ($(cc-name),clang) ccflags-y += -fno-jump-tables -- GitLab From a4b6b9aacb0283a5335f4034d6542f452969f7b6 Mon Sep 17 00:00:00 2001 From: Sami Tolvanen Date: Thu, 10 Aug 2017 09:39:53 -0700 Subject: [PATCH 1091/1635] ANDROID: arch/arm64/crypto: fix CFI in SHA CE Add C wrappers to allow indirect calls to sha[12]_ce_transform without tripping CFI. Bug: 67506682 Change-Id: If872f30095994206bc768eee13670be552b2a247 Signed-off-by: Sami Tolvanen --- arch/arm64/crypto/sha1-ce-glue.c | 8 ++++++++ arch/arm64/crypto/sha2-ce-glue.c | 8 ++++++++ 2 files changed, 16 insertions(+) diff --git a/arch/arm64/crypto/sha1-ce-glue.c b/arch/arm64/crypto/sha1-ce-glue.c index efbeb3e0dcfb..656b959bcdaa 100644 --- a/arch/arm64/crypto/sha1-ce-glue.c +++ b/arch/arm64/crypto/sha1-ce-glue.c @@ -29,6 +29,14 @@ struct sha1_ce_state { asmlinkage void sha1_ce_transform(struct sha1_ce_state *sst, u8 const *src, int blocks); +#ifdef CONFIG_CFI_CLANG +static inline void __cfi_sha1_ce_transform(struct sha1_state *sst, + u8 const *src, int blocks) +{ + sha1_ce_transform((struct sha1_ce_state *)sst, src, blocks); +} +#define sha1_ce_transform __cfi_sha1_ce_transform +#endif const u32 sha1_ce_offsetof_count = offsetof(struct sha1_ce_state, sst.count); const u32 sha1_ce_offsetof_finalize = offsetof(struct sha1_ce_state, finalize); diff --git a/arch/arm64/crypto/sha2-ce-glue.c b/arch/arm64/crypto/sha2-ce-glue.c index fd1ff2b13dfa..ddda74844c43 100644 --- a/arch/arm64/crypto/sha2-ce-glue.c +++ b/arch/arm64/crypto/sha2-ce-glue.c @@ -29,6 +29,14 @@ struct sha256_ce_state { asmlinkage void sha2_ce_transform(struct sha256_ce_state *sst, u8 const *src, int blocks); +#ifdef CONFIG_CFI_CLANG +static inline void __cfi_sha2_ce_transform(struct sha256_state *sst, + u8 const *src, int blocks) +{ + sha2_ce_transform((struct sha256_ce_state *)sst, src, blocks); +} +#define sha2_ce_transform __cfi_sha2_ce_transform +#endif const u32 sha256_ce_offsetof_count = offsetof(struct sha256_ce_state, sst.count); -- GitLab From 8d106c4f2708e8a0ed5c4d5f2e4e57b64a0b7b1a Mon Sep 17 00:00:00 2001 From: Sami Tolvanen Date: Fri, 18 Aug 2017 10:00:51 -0700 Subject: [PATCH 1092/1635] ANDROID: v4l2-ioctl: fix function types for IOCTL_INFO_STD Bug: 67506682 Change-Id: I0bfdb4a198e8fb8719ac6aa884fd39e163dbf762 Signed-off-by: Sami Tolvanen --- drivers/media/v4l2-core/v4l2-ioctl.c | 71 ++++++++++++++++++---------- 1 file changed, 45 insertions(+), 26 deletions(-) diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c index d06941cc6a55..9a3a7245e886 100644 --- a/drivers/media/v4l2-core/v4l2-ioctl.c +++ b/drivers/media/v4l2-core/v4l2-ioctl.c @@ -2480,11 +2480,8 @@ struct v4l2_ioctl_info { unsigned int ioctl; u32 flags; const char * const name; - union { - u32 offset; - int (*func)(const struct v4l2_ioctl_ops *ops, - struct file *file, void *fh, void *p); - } u; + int (*func)(const struct v4l2_ioctl_ops *ops, struct file *file, + void *fh, void *p); void (*debug)(const void *arg, bool write_only); }; @@ -2492,27 +2489,23 @@ struct v4l2_ioctl_info { #define INFO_FL_PRIO (1 << 0) /* This control can be valid if the filehandle passes a control handler. */ #define INFO_FL_CTRL (1 << 1) -/* This is a standard ioctl, no need for special code */ -#define INFO_FL_STD (1 << 2) /* This is ioctl has its own function */ -#define INFO_FL_FUNC (1 << 3) +#define INFO_FL_FUNC (1 << 2) /* Queuing ioctl */ -#define INFO_FL_QUEUE (1 << 4) +#define INFO_FL_QUEUE (1 << 3) /* Always copy back result, even on error */ -#define INFO_FL_ALWAYS_COPY (1 << 5) +#define INFO_FL_ALWAYS_COPY (1 << 4) /* Zero struct from after the field to the end */ #define INFO_FL_CLEAR(v4l2_struct, field) \ ((offsetof(struct v4l2_struct, field) + \ sizeof(((struct v4l2_struct *)0)->field)) << 16) #define INFO_FL_CLEAR_MASK (_IOC_SIZEMASK << 16) -#define IOCTL_INFO_STD(_ioctl, _vidioc, _debug, _flags) \ - [_IOC_NR(_ioctl)] = { \ - .ioctl = _ioctl, \ - .flags = _flags | INFO_FL_STD, \ - .name = #_ioctl, \ - .u.offset = offsetof(struct v4l2_ioctl_ops, _vidioc), \ - .debug = _debug, \ +#define DEFINE_IOCTL_STD_FNC(_vidioc) \ + static int __v4l_ ## _vidioc ## _fnc( \ + const struct v4l2_ioctl_ops *ops, \ + struct file *file, void *fh, void *p) { \ + return ops->_vidioc(file, fh, p); \ } #define IOCTL_INFO_FNC(_ioctl, _func, _debug, _flags) \ @@ -2520,10 +2513,42 @@ struct v4l2_ioctl_info { .ioctl = _ioctl, \ .flags = _flags | INFO_FL_FUNC, \ .name = #_ioctl, \ - .u.func = _func, \ + .func = _func, \ .debug = _debug, \ } +#define IOCTL_INFO_STD(_ioctl, _vidioc, _debug, _flags) \ + IOCTL_INFO_FNC(_ioctl, __v4l_ ## _vidioc ## _fnc, _debug, _flags) + +DEFINE_IOCTL_STD_FNC(vidioc_g_fbuf) +DEFINE_IOCTL_STD_FNC(vidioc_s_fbuf) +DEFINE_IOCTL_STD_FNC(vidioc_expbuf) +DEFINE_IOCTL_STD_FNC(vidioc_g_std) +DEFINE_IOCTL_STD_FNC(vidioc_g_audio) +DEFINE_IOCTL_STD_FNC(vidioc_s_audio) +DEFINE_IOCTL_STD_FNC(vidioc_g_input) +DEFINE_IOCTL_STD_FNC(vidioc_g_edid) +DEFINE_IOCTL_STD_FNC(vidioc_s_edid) +DEFINE_IOCTL_STD_FNC(vidioc_g_output) +DEFINE_IOCTL_STD_FNC(vidioc_g_audout) +DEFINE_IOCTL_STD_FNC(vidioc_s_audout) +DEFINE_IOCTL_STD_FNC(vidioc_g_jpegcomp) +DEFINE_IOCTL_STD_FNC(vidioc_s_jpegcomp) +DEFINE_IOCTL_STD_FNC(vidioc_enumaudio) +DEFINE_IOCTL_STD_FNC(vidioc_enumaudout) +DEFINE_IOCTL_STD_FNC(vidioc_enum_framesizes) +DEFINE_IOCTL_STD_FNC(vidioc_enum_frameintervals) +DEFINE_IOCTL_STD_FNC(vidioc_g_enc_index) +DEFINE_IOCTL_STD_FNC(vidioc_encoder_cmd) +DEFINE_IOCTL_STD_FNC(vidioc_try_encoder_cmd) +DEFINE_IOCTL_STD_FNC(vidioc_decoder_cmd) +DEFINE_IOCTL_STD_FNC(vidioc_try_decoder_cmd) +DEFINE_IOCTL_STD_FNC(vidioc_s_dv_timings) +DEFINE_IOCTL_STD_FNC(vidioc_g_dv_timings) +DEFINE_IOCTL_STD_FNC(vidioc_enum_dv_timings) +DEFINE_IOCTL_STD_FNC(vidioc_query_dv_timings) +DEFINE_IOCTL_STD_FNC(vidioc_dv_timings_cap) + static struct v4l2_ioctl_info v4l2_ioctls[] = { IOCTL_INFO_FNC(VIDIOC_QUERYCAP, v4l_querycap, v4l_print_querycap, 0), IOCTL_INFO_FNC(VIDIOC_ENUM_FMT, v4l_enum_fmt, v4l_print_fmtdesc, INFO_FL_CLEAR(v4l2_fmtdesc, type)), @@ -2708,14 +2733,8 @@ static long __video_do_ioctl(struct file *file, } write_only = _IOC_DIR(cmd) == _IOC_WRITE; - if (info->flags & INFO_FL_STD) { - typedef int (*vidioc_op)(struct file *file, void *fh, void *p); - const void *p = vfd->ioctl_ops; - const vidioc_op *vidioc = p + info->u.offset; - - ret = (*vidioc)(file, fh, arg); - } else if (info->flags & INFO_FL_FUNC) { - ret = info->u.func(ops, file, fh, arg); + if (info->flags & INFO_FL_FUNC) { + ret = info->func(ops, file, fh, arg); } else if (!ops->vidioc_default) { ret = -ENOTTY; } else { -- GitLab From 8c7bbeac500da6c010252562395076bcd0021c3a Mon Sep 17 00:00:00 2001 From: Sami Tolvanen Date: Fri, 19 Jan 2018 08:51:17 -0800 Subject: [PATCH 1093/1635] ANDROID: media-device: fix ioctl function types Bug: 67506682 Change-Id: I233081071d90aeea56a2201ff618e8b530c52610 Signed-off-by: Sami Tolvanen --- drivers/media/media-device.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/drivers/media/media-device.c b/drivers/media/media-device.c index e79f72b8b858..98de74862d47 100644 --- a/drivers/media/media-device.c +++ b/drivers/media/media-device.c @@ -54,9 +54,10 @@ static int media_device_close(struct file *filp) return 0; } -static int media_device_get_info(struct media_device *dev, - struct media_device_info *info) +static long media_device_get_info(struct media_device *dev, void *arg) { + struct media_device_info *info = (struct media_device_info *)arg; + memset(info, 0, sizeof(*info)); if (dev->driver_name[0]) @@ -93,9 +94,9 @@ static struct media_entity *find_entity(struct media_device *mdev, u32 id) return NULL; } -static long media_device_enum_entities(struct media_device *mdev, - struct media_entity_desc *entd) +static long media_device_enum_entities(struct media_device *mdev, void *arg) { + struct media_entity_desc *entd = (struct media_entity_desc *)arg; struct media_entity *ent; ent = find_entity(mdev, entd->id); @@ -146,9 +147,9 @@ static void media_device_kpad_to_upad(const struct media_pad *kpad, upad->flags = kpad->flags; } -static long media_device_enum_links(struct media_device *mdev, - struct media_links_enum *links) +static long media_device_enum_links(struct media_device *mdev, void *arg) { + struct media_links_enum *links = (struct media_links_enum *)arg; struct media_entity *entity; entity = find_entity(mdev, links->entity); @@ -194,9 +195,9 @@ static long media_device_enum_links(struct media_device *mdev, return 0; } -static long media_device_setup_link(struct media_device *mdev, - struct media_link_desc *linkd) +static long media_device_setup_link(struct media_device *mdev, void *arg) { + struct media_link_desc *linkd = (struct media_link_desc *)arg; struct media_link *link = NULL; struct media_entity *source; struct media_entity *sink; @@ -222,9 +223,9 @@ static long media_device_setup_link(struct media_device *mdev, return __media_entity_setup_link(link, linkd->flags); } -static long media_device_get_topology(struct media_device *mdev, - struct media_v2_topology *topo) +static long media_device_get_topology(struct media_device *mdev, void *arg) { + struct media_v2_topology *topo = (struct media_v2_topology *)arg; struct media_entity *entity; struct media_interface *intf; struct media_pad *pad; -- GitLab From c1e98bf267313ac96139bc5927d7de8c8ff37160 Mon Sep 17 00:00:00 2001 From: Sami Tolvanen Date: Wed, 25 Apr 2018 16:08:11 -0700 Subject: [PATCH 1094/1635] ANDROID: mm: fix filler function type mismatch Bug: 67506682 Change-Id: I6f615164ccd86b407540ada9bbcb39d910395db9 Signed-off-by: Sami Tolvanen --- include/linux/pagemap.h | 4 ++-- mm/filemap.c | 6 +++--- mm/readahead.c | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/include/linux/pagemap.h b/include/linux/pagemap.h index e08b5339023c..9369e9cea295 100644 --- a/include/linux/pagemap.h +++ b/include/linux/pagemap.h @@ -243,7 +243,7 @@ static inline gfp_t readahead_gfp_mask(struct address_space *x) __GFP_COLD | __GFP_NORETRY | __GFP_NOWARN; } -typedef int filler_t(void *, struct page *); +typedef int filler_t(struct file *, struct page *); pgoff_t page_cache_next_hole(struct address_space *mapping, pgoff_t index, unsigned long max_scan); @@ -394,7 +394,7 @@ extern int read_cache_pages(struct address_space *mapping, static inline struct page *read_mapping_page(struct address_space *mapping, pgoff_t index, void *data) { - filler_t *filler = (filler_t *)mapping->a_ops->readpage; + filler_t *filler = mapping->a_ops->readpage; return read_cache_page(mapping, index, filler, data); } diff --git a/mm/filemap.c b/mm/filemap.c index e2e738cc08b1..51aef4e992ea 100644 --- a/mm/filemap.c +++ b/mm/filemap.c @@ -2665,7 +2665,7 @@ static struct page *wait_on_page_read(struct page *page) static struct page *do_read_cache_page(struct address_space *mapping, pgoff_t index, - int (*filler)(void *, struct page *), + int (*filler)(struct file *, struct page *), void *data, gfp_t gfp) { @@ -2772,7 +2772,7 @@ static struct page *do_read_cache_page(struct address_space *mapping, */ struct page *read_cache_page(struct address_space *mapping, pgoff_t index, - int (*filler)(void *, struct page *), + int (*filler)(struct file *, struct page *), void *data) { return do_read_cache_page(mapping, index, filler, data, mapping_gfp_mask(mapping)); @@ -2794,7 +2794,7 @@ struct page *read_cache_page_gfp(struct address_space *mapping, pgoff_t index, gfp_t gfp) { - filler_t *filler = (filler_t *)mapping->a_ops->readpage; + filler_t *filler = mapping->a_ops->readpage; return do_read_cache_page(mapping, index, filler, NULL, gfp); } diff --git a/mm/readahead.c b/mm/readahead.c index c4ca70239233..655d973433b1 100644 --- a/mm/readahead.c +++ b/mm/readahead.c @@ -81,7 +81,7 @@ static void read_cache_pages_invalidate_pages(struct address_space *mapping, * Hides the details of the LRU cache etc from the filesystems. */ int read_cache_pages(struct address_space *mapping, struct list_head *pages, - int (*filler)(void *, struct page *), void *data) + int (*filler)(struct file *, struct page *), void *data) { struct page *page; int ret = 0; -- GitLab From f8a66951fe204cbdb2e863105f35ca9579e2bc35 Mon Sep 17 00:00:00 2001 From: Sami Tolvanen Date: Wed, 25 Apr 2018 16:08:28 -0700 Subject: [PATCH 1095/1635] ANDROID: fs: fuse: fix filler function type mismatch Bug: 67506682 Change-Id: Iabe7cdcc90dd2ea62976860531b8cbfcd76bd64b Signed-off-by: Sami Tolvanen --- fs/fuse/file.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fs/fuse/file.c b/fs/fuse/file.c index cb7dff5c45d7..3bbbc0cc5556 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c @@ -837,9 +837,9 @@ struct fuse_fill_data { unsigned nr_pages; }; -static int fuse_readpages_fill(void *_data, struct page *page) +static int fuse_readpages_fill(struct file *_data, struct page *page) { - struct fuse_fill_data *data = _data; + struct fuse_fill_data *data = (struct fuse_fill_data *)_data; struct fuse_req *req = data->req; struct inode *inode = data->inode; struct fuse_conn *fc = get_fuse_conn(inode); -- GitLab From 5785368dfd1c7ebd1c3bdb524c7d15d0e8847519 Mon Sep 17 00:00:00 2001 From: Sami Tolvanen Date: Tue, 13 Feb 2018 13:01:39 -0800 Subject: [PATCH 1096/1635] ANDROID: fs: nfs: fix filler function type Bug: 67506682 Change-Id: I04d4b1b9ab0720a4f342d6617dd132de8654b94c Signed-off-by: Sami Tolvanen --- fs/nfs/dir.c | 5 +++-- fs/nfs/read.c | 2 +- fs/nfs/symlink.c | 5 +++-- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index bf2c43635062..64dc8ea8f42f 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c @@ -671,8 +671,9 @@ int nfs_readdir_xdr_to_array(nfs_readdir_descriptor_t *desc, struct page *page, * We only need to convert from xdr once so future lookups are much simpler */ static -int nfs_readdir_filler(nfs_readdir_descriptor_t *desc, struct page* page) +int nfs_readdir_filler(struct file *file, struct page* page) { + nfs_readdir_descriptor_t *desc = (nfs_readdir_descriptor_t *)file; struct inode *inode = file_inode(desc->file); int ret; @@ -705,7 +706,7 @@ static struct page *get_cache_page(nfs_readdir_descriptor_t *desc) { return read_cache_page(desc->file->f_mapping, - desc->page_index, (filler_t *)nfs_readdir_filler, desc); + desc->page_index, nfs_readdir_filler, desc); } /* diff --git a/fs/nfs/read.c b/fs/nfs/read.c index 48d7277c60a9..42dbf4f4d5aa 100644 --- a/fs/nfs/read.c +++ b/fs/nfs/read.c @@ -354,7 +354,7 @@ struct nfs_readdesc { }; static int -readpage_async_filler(void *data, struct page *page) +readpage_async_filler(struct file *data, struct page *page) { struct nfs_readdesc *desc = (struct nfs_readdesc *)data; struct nfs_page *new; diff --git a/fs/nfs/symlink.c b/fs/nfs/symlink.c index 06eb44b47885..220d5ba2bd9b 100644 --- a/fs/nfs/symlink.c +++ b/fs/nfs/symlink.c @@ -26,8 +26,9 @@ * and straight-forward than readdir caching. */ -static int nfs_symlink_filler(struct inode *inode, struct page *page) +static int nfs_symlink_filler(struct file *file, struct page *page) { + struct inode *inode = (struct inode *)file; int error; error = NFS_PROTO(inode)->readlink(inode, page, 0, PAGE_SIZE); @@ -66,7 +67,7 @@ static const char *nfs_get_link(struct dentry *dentry, if (err) return err; page = read_cache_page(&inode->i_data, 0, - (filler_t *)nfs_symlink_filler, inode); + nfs_symlink_filler, inode); if (IS_ERR(page)) return ERR_CAST(page); } -- GitLab From cf1e629fd5aa812a91a8c5b6ca293fbecf962548 Mon Sep 17 00:00:00 2001 From: Sami Tolvanen Date: Fri, 2 Mar 2018 09:02:16 -0800 Subject: [PATCH 1097/1635] ANDROID: fs: afs: fix filler function type Bug: 67506682 Change-Id: I76d208c8606ee5af144891d14bd309912d4d788d Signed-off-by: Sami Tolvanen --- fs/afs/file.c | 14 ++++++++++---- fs/afs/internal.h | 2 +- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/fs/afs/file.c b/fs/afs/file.c index 510cba15fa56..e6e949cdeb51 100644 --- a/fs/afs/file.c +++ b/fs/afs/file.c @@ -140,12 +140,11 @@ static void afs_file_readpage_read_complete(struct page *page, /* * read page from file, directory or symlink, given a key to use */ -int afs_page_filler(void *data, struct page *page) +static int __afs_page_filler(struct key *key, struct page *page) { struct inode *inode = page->mapping->host; struct afs_vnode *vnode = AFS_FS_I(inode); struct afs_read *req; - struct key *key = data; int ret; _enter("{%x},{%lu},{%lu}", key_serial(key), inode->i_ino, page->index); @@ -249,6 +248,13 @@ int afs_page_filler(void *data, struct page *page) return ret; } +int afs_page_filler(struct file *data, struct page *page) +{ + struct key *key = (struct key *)data; + + return __afs_page_filler(key, page); +} + /* * read page from file, directory or symlink, given a file to nominate the key * to be used @@ -261,14 +267,14 @@ static int afs_readpage(struct file *file, struct page *page) if (file) { key = file->private_data; ASSERT(key != NULL); - ret = afs_page_filler(key, page); + ret = __afs_page_filler(key, page); } else { struct inode *inode = page->mapping->host; key = afs_request_key(AFS_FS_S(inode->i_sb)->volume->cell); if (IS_ERR(key)) { ret = PTR_ERR(key); } else { - ret = afs_page_filler(key, page); + ret = __afs_page_filler(key, page); key_put(key); } } diff --git a/fs/afs/internal.h b/fs/afs/internal.h index 82e16556afea..ed42f21a6239 100644 --- a/fs/afs/internal.h +++ b/fs/afs/internal.h @@ -485,7 +485,7 @@ extern const struct file_operations afs_file_operations; extern int afs_open(struct inode *, struct file *); extern int afs_release(struct inode *, struct file *); -extern int afs_page_filler(void *, struct page *); +extern int afs_page_filler(struct file *, struct page *); extern void afs_put_read(struct afs_read *); /* -- GitLab From 982dcb70b2c26bfea84a189bbe889ee93117cb3b Mon Sep 17 00:00:00 2001 From: Sami Tolvanen Date: Fri, 2 Mar 2018 09:04:53 -0800 Subject: [PATCH 1098/1635] ANDROID: fs: exofs: fix filler function type Bug: 67506682 Change-Id: I42f297bfe07a1b7916790415f35ad4f2574ceec7 Signed-off-by: Sami Tolvanen --- fs/exofs/inode.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/fs/exofs/inode.c b/fs/exofs/inode.c index 0ac62811b341..f17715d140b5 100644 --- a/fs/exofs/inode.c +++ b/fs/exofs/inode.c @@ -377,9 +377,8 @@ static int read_exec(struct page_collect *pcol) * and will start a new collection. Eventually caller must submit the last * segment if present. */ -static int readpage_strip(void *data, struct page *page) +static int __readpage_strip(struct page_collect *pcol, struct page *page) { - struct page_collect *pcol = data; struct inode *inode = pcol->inode; struct exofs_i_info *oi = exofs_i(inode); loff_t i_size = i_size_read(inode); @@ -470,6 +469,13 @@ static int readpage_strip(void *data, struct page *page) return ret; } +static int readpage_strip(struct file *data, struct page *page) +{ + struct page_collect *pcol = (struct page_collect *)data; + + return __readpage_strip(pcol, page); +} + static int exofs_readpages(struct file *file, struct address_space *mapping, struct list_head *pages, unsigned nr_pages) { @@ -499,7 +505,7 @@ static int _readpage(struct page *page, bool read_4_write) _pcol_init(&pcol, 1, page->mapping->host); pcol.read_4_write = read_4_write; - ret = readpage_strip(&pcol, page); + ret = __readpage_strip(&pcol, page); if (ret) { EXOFS_ERR("_readpage => %d\n", ret); return ret; -- GitLab From 3faaae7b99af31d86341ea486978eb6af4746e7b Mon Sep 17 00:00:00 2001 From: Sami Tolvanen Date: Fri, 2 Mar 2018 09:06:24 -0800 Subject: [PATCH 1099/1635] ANDROID: fs: gfs2: fix filler function type Bug: 67506682 Change-Id: I50a3f85965de6e041d0f40e7bf9c2ced15ccfd49 Signed-off-by: Sami Tolvanen --- fs/gfs2/aops.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/gfs2/aops.c b/fs/gfs2/aops.c index 68ed06962537..6eac9430dcf7 100644 --- a/fs/gfs2/aops.c +++ b/fs/gfs2/aops.c @@ -523,7 +523,7 @@ static int stuffed_readpage(struct gfs2_inode *ip, struct page *page) * */ -static int __gfs2_readpage(void *file, struct page *page) +static int __gfs2_readpage(struct file *file, struct page *page) { struct gfs2_inode *ip = GFS2_I(page->mapping->host); struct gfs2_sbd *sdp = GFS2_SB(page->mapping->host); -- GitLab From d23515ea8a7fdd0f5015b81232d3ef2056cf577e Mon Sep 17 00:00:00 2001 From: Sami Tolvanen Date: Fri, 2 Mar 2018 13:05:33 -0800 Subject: [PATCH 1100/1635] ANDROID: staging: lustre: fix filler function type Bug: 67506682 Change-Id: I3a65178adb47119a3dcbc6ca4bcf350085a73ffc Signed-off-by: Sami Tolvanen --- drivers/staging/lustre/lustre/mdc/mdc_request.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/staging/lustre/lustre/mdc/mdc_request.c b/drivers/staging/lustre/lustre/mdc/mdc_request.c index 6ef8ddec4ab6..8c97acd79211 100644 --- a/drivers/staging/lustre/lustre/mdc/mdc_request.c +++ b/drivers/staging/lustre/lustre/mdc/mdc_request.c @@ -1121,9 +1121,9 @@ struct readpage_param { * in PAGE_SIZE (if PAGE_SIZE greater than LU_PAGE_SIZE), and the * lu_dirpage for this integrated page will be adjusted. **/ -static int mdc_read_page_remote(void *data, struct page *page0) +static int mdc_read_page_remote(struct file *data, struct page *page0) { - struct readpage_param *rp = data; + struct readpage_param *rp = (struct readpage_param *)data; struct page **page_pool; struct page *page; struct lu_dirpage *dp; -- GitLab From e5f45f612ad521b0be23c10e519f7e992b5db3e1 Mon Sep 17 00:00:00 2001 From: Avraham Stern Date: Mon, 19 Feb 2018 14:48:38 +0200 Subject: [PATCH 1101/1635] cfg80211: clear wep keys after disconnection When a low level driver calls cfg80211_disconnected(), wep keys are not cleared. As a result, following connection requests will fail since cfg80211 internal state shows a connection is still in progress. Fix this by clearing the wep keys when disconnecting. Signed-off-by: Avraham Stern Signed-off-by: Luca Coelho Signed-off-by: Johannes Berg Git-commit: 3027a8e799b20fc922496a12f8ad2f9f36a8a696 Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211-next.git Change-Id: If86c857b350d3941e016108d44c60ab9b583f7a3 CRs-Fixed: 2229833 Signed-off-by: Zhu Jianmin --- net/wireless/sme.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/net/wireless/sme.c b/net/wireless/sme.c index 3dd05a08c60a..d014aea07160 100644 --- a/net/wireless/sme.c +++ b/net/wireless/sme.c @@ -989,6 +989,8 @@ void __cfg80211_disconnected(struct net_device *dev, const u8 *ie, wdev->current_bss = NULL; wdev->ssid_len = 0; wdev->conn_owner_nlportid = 0; + kzfree(wdev->connect_keys); + wdev->connect_keys = NULL; nl80211_send_disconnected(rdev, dev, reason, ie, ie_len, from_ap); -- GitLab From ad18b97ee4e03cbe19fd99fd850760570fd4ce16 Mon Sep 17 00:00:00 2001 From: Veera Sundaram Sankaran Date: Thu, 26 Apr 2018 18:38:39 -0700 Subject: [PATCH 1102/1635] drm/msm/sde: fix INTF_2 TEAR_IRQ register index Currently both INTF_1 and INTF_2 TEAR_IRQs are pointing to the same register index, resulting in wrong programming. Fix the register index value for the INTF_2 IRQ registers in sde_intr_set table. Change-Id: I887fa57d31fd712d5d7937137b73aaa340173be6 Signed-off-by: Veera Sundaram Sankaran --- drivers/gpu/drm/msm/sde/sde_hw_interrupts.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/msm/sde/sde_hw_interrupts.c b/drivers/gpu/drm/msm/sde/sde_hw_interrupts.c index 9b4e07df3e45..0b57dfe6345d 100644 --- a/drivers/gpu/drm/msm/sde/sde_hw_interrupts.c +++ b/drivers/gpu/drm/msm/sde/sde_hw_interrupts.c @@ -849,13 +849,13 @@ static const struct sde_irq_type sde_irq_map[] = { /* BEGIN MAP_RANGE: 352-383 INTF_2_TEAR INTR */ /* irq_idx: 352-354 */ { SDE_IRQ_TYPE_INTF_TEAR_AUTO_REF, INTF_2, - SDE_INTR_INTF_TEAR_AUTOREFRESH_DONE, 10}, + SDE_INTR_INTF_TEAR_AUTOREFRESH_DONE, 11}, { SDE_IRQ_TYPE_INTF_TEAR_WR_PTR, INTF_2, - SDE_INTR_INTF_TEAR_WR_PTR, 10}, + SDE_INTR_INTF_TEAR_WR_PTR, 11}, { SDE_IRQ_TYPE_INTF_TEAR_RD_PTR, INTF_2, - SDE_INTR_INTF_TEAR_RD_PTR, 10}, + SDE_INTR_INTF_TEAR_RD_PTR, 11}, { SDE_IRQ_TYPE_INTF_TEAR_TE_CHECK, INTF_2, - SDE_INTR_INTF_TEAR_TE_DETECTED, 10}, + SDE_INTR_INTF_TEAR_TE_DETECTED, 11}, /* irq_idx: 355 */ { SDE_IRQ_TYPE_INTF_TEAR_TEAR_CHECK, INTF_2, SDE_INTR_INTF_TEAR_TEAR_DETECTED, 11}, -- GitLab From b3025dc40a9018fbe7629352b244e24f18cb5fd5 Mon Sep 17 00:00:00 2001 From: Lynus Vaz Date: Mon, 9 Apr 2018 14:45:36 +0530 Subject: [PATCH 1103/1635] msm: kgsl: Use a common sharedmem init function Since we initialize the kgsl sharedmem structures from various places, use a common function to avoid code duplication. Change-Id: I5953dc44f4fbd89ce57dffe933369f58a6c19bde Signed-off-by: Lynus Vaz --- drivers/gpu/msm/kgsl.c | 70 ++++++++------------------------ drivers/gpu/msm/kgsl_iommu.c | 7 ++-- drivers/gpu/msm/kgsl_sharedmem.c | 38 +++++++++++++++-- drivers/gpu/msm/kgsl_sharedmem.h | 9 ++-- 4 files changed, 61 insertions(+), 63 deletions(-) diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c index 772571b90473..9e7f2d834caa 100644 --- a/drivers/gpu/msm/kgsl.c +++ b/drivers/gpu/msm/kgsl.c @@ -2405,7 +2405,6 @@ long kgsl_ioctl_gpuobj_import(struct kgsl_device_private *dev_priv, struct kgsl_gpuobj_import *param = data; struct kgsl_mem_entry *entry; int ret, fd = -1; - struct kgsl_mmu *mmu = &dev_priv->device->mmu; entry = kgsl_mem_entry_create(); if (entry == NULL) @@ -2419,18 +2418,10 @@ long kgsl_ioctl_gpuobj_import(struct kgsl_device_private *dev_priv, | KGSL_MEMFLAGS_FORCE_32BIT | KGSL_MEMFLAGS_IOCOHERENT; - /* Disable IO coherence if it is not supported on the chip */ - if (!MMU_FEATURE(mmu, KGSL_MMU_IO_COHERENT)) - param->flags &= ~((uint64_t)KGSL_MEMFLAGS_IOCOHERENT); - if (kgsl_is_compat_task()) param->flags |= KGSL_MEMFLAGS_FORCE_32BIT; - entry->memdesc.flags = param->flags; - - if (MMU_FEATURE(mmu, KGSL_MMU_NEED_GUARD_PAGE)) - entry->memdesc.priv |= KGSL_MEMDESC_GUARD_PAGE; - + kgsl_memdesc_init(dev_priv->device, &entry->memdesc, param->flags); if (param->type == KGSL_USER_MEM_TYPE_ADDR) ret = _gpuobj_map_useraddr(dev_priv->device, private->pagetable, entry, param); @@ -2669,6 +2660,7 @@ long kgsl_ioctl_map_user_mem(struct kgsl_device_private *dev_priv, struct kgsl_process_private *private = dev_priv->process_priv; struct kgsl_mmu *mmu = &dev_priv->device->mmu; unsigned int memtype; + uint64_t flags; /* * If content protection is not enabled and secure buffer @@ -2705,30 +2697,17 @@ long kgsl_ioctl_map_user_mem(struct kgsl_device_private *dev_priv, * Note: CACHEMODE is ignored for this call. Caching should be * determined by type of allocation being mapped. */ - param->flags &= KGSL_MEMFLAGS_GPUREADONLY - | KGSL_MEMTYPE_MASK - | KGSL_MEMALIGN_MASK - | KGSL_MEMFLAGS_USE_CPU_MAP - | KGSL_MEMFLAGS_SECURE - | KGSL_MEMFLAGS_IOCOHERENT; - - /* Disable IO coherence if it is not supported on the chip */ - if (!MMU_FEATURE(mmu, KGSL_MMU_IO_COHERENT)) - param->flags &= ~((uint64_t)KGSL_MEMFLAGS_IOCOHERENT); - - entry->memdesc.flags = (uint64_t) param->flags; + flags = param->flags & (KGSL_MEMFLAGS_GPUREADONLY + | KGSL_MEMTYPE_MASK + | KGSL_MEMALIGN_MASK + | KGSL_MEMFLAGS_USE_CPU_MAP + | KGSL_MEMFLAGS_SECURE + | KGSL_MEMFLAGS_IOCOHERENT); if (kgsl_is_compat_task()) - entry->memdesc.flags |= KGSL_MEMFLAGS_FORCE_32BIT; - - if (!kgsl_mmu_use_cpu_map(mmu)) - entry->memdesc.flags &= ~((uint64_t) KGSL_MEMFLAGS_USE_CPU_MAP); - - if (MMU_FEATURE(mmu, KGSL_MMU_NEED_GUARD_PAGE)) - entry->memdesc.priv |= KGSL_MEMDESC_GUARD_PAGE; + flags |= KGSL_MEMFLAGS_FORCE_32BIT; - if (param->flags & KGSL_MEMFLAGS_SECURE) - entry->memdesc.priv |= KGSL_MEMDESC_SECURE; + kgsl_memdesc_init(dev_priv->device, &entry->memdesc, flags); switch (memtype) { case KGSL_MEM_ENTRY_USER: @@ -3124,10 +3103,6 @@ struct kgsl_mem_entry *gpumem_alloc_entry( | KGSL_MEMFLAGS_FORCE_32BIT | KGSL_MEMFLAGS_IOCOHERENT; - /* Turn off SVM if the system doesn't support it */ - if (!kgsl_mmu_use_cpu_map(mmu)) - flags &= ~((uint64_t) KGSL_MEMFLAGS_USE_CPU_MAP); - /* Return not supported error if secure memory isn't enabled */ if (!kgsl_mmu_is_secured(mmu) && (flags & KGSL_MEMFLAGS_SECURE)) { @@ -3136,10 +3111,6 @@ struct kgsl_mem_entry *gpumem_alloc_entry( return ERR_PTR(-EOPNOTSUPP); } - /* Secure memory disables advanced addressing modes */ - if (flags & KGSL_MEMFLAGS_SECURE) - flags &= ~((uint64_t) KGSL_MEMFLAGS_USE_CPU_MAP); - /* Cap the alignment bits to the highest number we can handle */ align = MEMFLAGS(flags, KGSL_MEMALIGN_MASK, KGSL_MEMALIGN_SHIFT); if (align >= ilog2(KGSL_MAX_ALIGN)) { @@ -3158,20 +3129,10 @@ struct kgsl_mem_entry *gpumem_alloc_entry( flags = kgsl_filter_cachemode(flags); - /* Disable IO coherence if it is not supported on the chip */ - if (!MMU_FEATURE(mmu, KGSL_MMU_IO_COHERENT)) - flags &= ~((uint64_t)KGSL_MEMFLAGS_IOCOHERENT); - entry = kgsl_mem_entry_create(); if (entry == NULL) return ERR_PTR(-ENOMEM); - if (MMU_FEATURE(mmu, KGSL_MMU_NEED_GUARD_PAGE)) - entry->memdesc.priv |= KGSL_MEMDESC_GUARD_PAGE; - - if (flags & KGSL_MEMFLAGS_SECURE) - entry->memdesc.priv |= KGSL_MEMDESC_SECURE; - ret = kgsl_allocate_user(dev_priv->device, &entry->memdesc, size, flags); if (ret != 0) @@ -3355,6 +3316,7 @@ long kgsl_ioctl_sparse_phys_alloc(struct kgsl_device_private *dev_priv, struct kgsl_process_private *process = dev_priv->process_priv; struct kgsl_sparse_phys_alloc *param = data; struct kgsl_mem_entry *entry; + uint64_t flags; int ret; int id; @@ -3387,11 +3349,12 @@ long kgsl_ioctl_sparse_phys_alloc(struct kgsl_device_private *dev_priv, entry->id = id; entry->priv = process; - entry->memdesc.flags = KGSL_MEMFLAGS_SPARSE_PHYS; - kgsl_memdesc_set_align(&entry->memdesc, ilog2(param->pagesize)); + flags = KGSL_MEMFLAGS_SPARSE_PHYS | + ((ilog2(param->pagesize) << KGSL_MEMALIGN_SHIFT) & + KGSL_MEMALIGN_MASK); ret = kgsl_allocate_user(dev_priv->device, &entry->memdesc, - param->size, entry->memdesc.flags); + param->size, flags); if (ret) goto err_remove_idr; @@ -3480,7 +3443,8 @@ long kgsl_ioctl_sparse_virt_alloc(struct kgsl_device_private *dev_priv, if (entry == NULL) return -ENOMEM; - entry->memdesc.flags = KGSL_MEMFLAGS_SPARSE_VIRT; + kgsl_memdesc_init(dev_priv->device, &entry->memdesc, + KGSL_MEMFLAGS_SPARSE_VIRT); entry->memdesc.size = param->size; entry->memdesc.cur_bindings = 0; kgsl_memdesc_set_align(&entry->memdesc, ilog2(param->pagesize)); diff --git a/drivers/gpu/msm/kgsl_iommu.c b/drivers/gpu/msm/kgsl_iommu.c index 1bbbeb497532..b59ee50d7e74 100644 --- a/drivers/gpu/msm/kgsl_iommu.c +++ b/drivers/gpu/msm/kgsl_iommu.c @@ -260,13 +260,12 @@ static void kgsl_setup_qdss_desc(struct kgsl_device *device) return; } - gpu_qdss_desc.flags = 0; + kgsl_memdesc_init(device, &gpu_qdss_desc, 0); gpu_qdss_desc.priv = 0; gpu_qdss_desc.physaddr = gpu_qdss_entry[0]; gpu_qdss_desc.size = gpu_qdss_entry[1]; gpu_qdss_desc.pagetable = NULL; gpu_qdss_desc.ops = NULL; - gpu_qdss_desc.dev = device->dev->parent; gpu_qdss_desc.hostptr = NULL; result = memdesc_sg_dma(&gpu_qdss_desc, gpu_qdss_desc.physaddr, @@ -305,13 +304,12 @@ static void kgsl_setup_qtimer_desc(struct kgsl_device *device) return; } - gpu_qtimer_desc.flags = 0; + kgsl_memdesc_init(device, &gpu_qtimer_desc, 0); gpu_qtimer_desc.priv = 0; gpu_qtimer_desc.physaddr = gpu_qtimer_entry[0]; gpu_qtimer_desc.size = gpu_qtimer_entry[1]; gpu_qtimer_desc.pagetable = NULL; gpu_qtimer_desc.ops = NULL; - gpu_qtimer_desc.dev = device->dev->parent; gpu_qtimer_desc.hostptr = NULL; result = memdesc_sg_dma(&gpu_qtimer_desc, gpu_qtimer_desc.physaddr, @@ -1483,6 +1481,7 @@ static int _setstate_alloc(struct kgsl_device *device, { int ret; + kgsl_memdesc_init(device, &iommu->setstate, 0); ret = kgsl_sharedmem_alloc_contig(device, &iommu->setstate, PAGE_SIZE); if (!ret) { diff --git a/drivers/gpu/msm/kgsl_sharedmem.c b/drivers/gpu/msm/kgsl_sharedmem.c index b9c170f76f3a..9a0bb9d33a66 100644 --- a/drivers/gpu/msm/kgsl_sharedmem.c +++ b/drivers/gpu/msm/kgsl_sharedmem.c @@ -341,7 +341,7 @@ int kgsl_allocate_user(struct kgsl_device *device, { int ret; - memdesc->flags = flags; + kgsl_memdesc_init(device, memdesc, flags); if (kgsl_mmu_get_mmutype(device) == KGSL_MMU_TYPE_NONE) ret = kgsl_sharedmem_alloc_contig(device, memdesc, size); @@ -696,6 +696,40 @@ int kgsl_cache_range_op(struct kgsl_memdesc *memdesc, uint64_t offset, } EXPORT_SYMBOL(kgsl_cache_range_op); +void kgsl_memdesc_init(struct kgsl_device *device, + struct kgsl_memdesc *memdesc, uint64_t flags) +{ + struct kgsl_mmu *mmu = &device->mmu; + unsigned int align; + + memset(memdesc, 0, sizeof(*memdesc)); + /* Turn off SVM if the system doesn't support it */ + if (!kgsl_mmu_use_cpu_map(mmu)) + flags &= ~((uint64_t) KGSL_MEMFLAGS_USE_CPU_MAP); + + /* Secure memory disables advanced addressing modes */ + if (flags & KGSL_MEMFLAGS_SECURE) + flags &= ~((uint64_t) KGSL_MEMFLAGS_USE_CPU_MAP); + + /* Disable IO coherence if it is not supported on the chip */ + if (!MMU_FEATURE(mmu, KGSL_MMU_IO_COHERENT)) + flags &= ~((uint64_t) KGSL_MEMFLAGS_IOCOHERENT); + + if (MMU_FEATURE(mmu, KGSL_MMU_NEED_GUARD_PAGE)) + memdesc->priv |= KGSL_MEMDESC_GUARD_PAGE; + + if (flags & KGSL_MEMFLAGS_SECURE) + memdesc->priv |= KGSL_MEMDESC_SECURE; + + memdesc->flags = flags; + memdesc->dev = device->dev->parent; + + align = max_t(unsigned int, + (memdesc->flags & KGSL_MEMALIGN_MASK) >> KGSL_MEMALIGN_SHIFT, + ilog2(PAGE_SIZE)); + kgsl_memdesc_set_align(memdesc, align); +} + int kgsl_sharedmem_page_alloc_user(struct kgsl_memdesc *memdesc, uint64_t size) @@ -896,8 +930,6 @@ void kgsl_sharedmem_free(struct kgsl_memdesc *memdesc) if (memdesc->pages) kgsl_free(memdesc->pages); - - memset(memdesc, 0, sizeof(*memdesc)); } EXPORT_SYMBOL(kgsl_sharedmem_free); diff --git a/drivers/gpu/msm/kgsl_sharedmem.h b/drivers/gpu/msm/kgsl_sharedmem.h index 55bb34f748db..976752d67b22 100644 --- a/drivers/gpu/msm/kgsl_sharedmem.h +++ b/drivers/gpu/msm/kgsl_sharedmem.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2002,2007-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2002,2007-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -57,6 +57,9 @@ int kgsl_cache_range_op(struct kgsl_memdesc *memdesc, uint64_t offset, uint64_t size, unsigned int op); +void kgsl_memdesc_init(struct kgsl_device *device, + struct kgsl_memdesc *memdesc, uint64_t flags); + void kgsl_process_init_sysfs(struct kgsl_device *device, struct kgsl_process_private *private); void kgsl_process_uninit_sysfs(struct kgsl_process_private *private); @@ -282,8 +285,8 @@ static inline int kgsl_allocate_global(struct kgsl_device *device, { int ret; - memdesc->flags = flags; - memdesc->priv = priv; + kgsl_memdesc_init(device, memdesc, flags); + memdesc->priv |= priv; if (((memdesc->priv & KGSL_MEMDESC_CONTIG) != 0) || (kgsl_mmu_get_mmutype(device) == KGSL_MMU_TYPE_NONE)) -- GitLab From e3b9dc9972b8025a801884a024fa140214bc781f Mon Sep 17 00:00:00 2001 From: Lynus Vaz Date: Tue, 3 Apr 2018 17:47:20 +0530 Subject: [PATCH 1104/1635] msm: kgsl: Force VA alignment and padding if required Some targets require all GPU virtual mappings to be aligned to and padded up to a particular size. Allocate a padding page and map it into the virtual space as many times as necessary to make up the size required by the target. Change-Id: I8f41c83bf88c20cf619ce2a7a63c31a05b732c4d Signed-off-by: Lynus Vaz --- drivers/gpu/msm/adreno.c | 8 +++ drivers/gpu/msm/adreno.h | 2 + drivers/gpu/msm/kgsl.c | 4 ++ drivers/gpu/msm/kgsl.h | 2 + drivers/gpu/msm/kgsl_iommu.c | 57 ++++++++++------- drivers/gpu/msm/kgsl_mmu.h | 6 +- drivers/gpu/msm/kgsl_sharedmem.c | 106 +++++++++++++++++++++++-------- drivers/gpu/msm/kgsl_sharedmem.h | 8 ++- 8 files changed, 142 insertions(+), 51 deletions(-) diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c index 29bca42aa1cd..9e0717ec271f 100644 --- a/drivers/gpu/msm/adreno.c +++ b/drivers/gpu/msm/adreno.c @@ -1281,6 +1281,14 @@ static int adreno_probe(struct platform_device *pdev) if (adreno_support_64bit(adreno_dev)) device->mmu.features |= KGSL_MMU_64BIT; + /* Default to 4K alignment (in other words, no additional padding) */ + device->mmu.va_padding = PAGE_SIZE; + + if (adreno_dev->gpucore->va_padding) { + device->mmu.features |= KGSL_MMU_PAD_VA; + device->mmu.va_padding = adreno_dev->gpucore->va_padding; + } + status = kgsl_device_platform_probe(device); if (status) { device->pdev = NULL; diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h index 4437ef2ea9c6..6f8153cc2b80 100644 --- a/drivers/gpu/msm/adreno.h +++ b/drivers/gpu/msm/adreno.h @@ -355,6 +355,7 @@ struct adreno_firmware { * @regfw_name: Filename for the register sequence firmware * @gpmu_tsens: ID for the temporature sensor used by the GPMU * @max_power: Max possible power draw of a core, units elephant tail hairs + * @va_padding: Size to pad allocations to, zero if not required */ struct adreno_gpu_core { enum adreno_gpurev gpurev; @@ -385,6 +386,7 @@ struct adreno_gpu_core { const char *regfw_name; unsigned int gpmu_tsens; unsigned int max_power; + uint64_t va_padding; }; diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c index 9e7f2d834caa..7d68c7c18902 100644 --- a/drivers/gpu/msm/kgsl.c +++ b/drivers/gpu/msm/kgsl.c @@ -4361,6 +4361,10 @@ static unsigned long _get_svm_area(struct kgsl_process_private *private, return -ERANGE; if (flags & MAP_FIXED) { + /* We must honor alignment requirements */ + if (!IS_ALIGNED(hint, align)) + return -EINVAL; + /* we must use addr 'hint' or fail */ return _gpu_set_svm_region(private, entry, hint, len); } else if (hint != 0) { diff --git a/drivers/gpu/msm/kgsl.h b/drivers/gpu/msm/kgsl.h index be81d646a566..f495515dad69 100644 --- a/drivers/gpu/msm/kgsl.h +++ b/drivers/gpu/msm/kgsl.h @@ -210,6 +210,7 @@ struct kgsl_memdesc_ops { * @physaddr: Physical address of the memory object * @size: Size of the memory object * @mapsize: Size of memory mapped in userspace + * @pad_to: Size that we pad the memdesc to * @priv: Internal flags and settings * @sgt: Scatter gather table for allocated pages * @ops: Function hooks for the memdesc memory type @@ -229,6 +230,7 @@ struct kgsl_memdesc { phys_addr_t physaddr; uint64_t size; uint64_t mapsize; + uint64_t pad_to; unsigned int priv; struct sg_table *sgt; struct kgsl_memdesc_ops *ops; diff --git a/drivers/gpu/msm/kgsl_iommu.c b/drivers/gpu/msm/kgsl_iommu.c index b59ee50d7e74..d9fe198b433f 100644 --- a/drivers/gpu/msm/kgsl_iommu.c +++ b/drivers/gpu/msm/kgsl_iommu.c @@ -232,7 +232,7 @@ static void kgsl_iommu_add_global(struct kgsl_mmu *mmu, memdesc->gpuaddr = KGSL_IOMMU_GLOBAL_MEM_BASE(mmu) + global_pt_alloc; memdesc->priv |= KGSL_MEMDESC_GLOBAL; - global_pt_alloc += memdesc->size; + global_pt_alloc += kgsl_memdesc_footprint(memdesc); global_pt_entries[global_pt_count].memdesc = memdesc; strlcpy(global_pt_entries[global_pt_count].name, name, @@ -368,22 +368,33 @@ static int _attach_pt(struct kgsl_iommu_pt *iommu_pt, return ret; } -static int _iommu_map_sync_pc(struct kgsl_pagetable *pt, - uint64_t gpuaddr, phys_addr_t physaddr, - uint64_t size, unsigned int flags) +static int _iommu_map_single_page_sync_pc(struct kgsl_pagetable *pt, + uint64_t gpuaddr, phys_addr_t physaddr, int times, + unsigned int flags) { struct kgsl_iommu_pt *iommu_pt = pt->priv; - int ret; + size_t mapped = 0; + int i; + int ret = 0; _iommu_sync_mmu_pc(true); - ret = iommu_map(iommu_pt->domain, gpuaddr, physaddr, size, flags); + for (i = 0; i < times; i++) { + ret = iommu_map(iommu_pt->domain, gpuaddr + mapped, + physaddr, PAGE_SIZE, flags); + if (ret) + break; + mapped += PAGE_SIZE; + } + + if (ret) + iommu_unmap(iommu_pt->domain, gpuaddr, mapped); _iommu_sync_mmu_pc(false); if (ret) { - KGSL_CORE_ERR("map err: 0x%016llX, 0x%llx, 0x%x, %d\n", - gpuaddr, size, flags, ret); + KGSL_CORE_ERR("map err: 0x%016llX, 0x%lx, 0x%x, %d\n", + gpuaddr, PAGE_SIZE * times, flags, ret); return -ENODEV; } @@ -503,7 +514,7 @@ static int _iommu_map_sg_sync_pc(struct kgsl_pagetable *pt, */ static struct page *kgsl_guard_page; -static struct kgsl_memdesc kgsl_secure_guard_page_memdesc; +static struct page *kgsl_secure_guard_page; /* * The dummy page is a placeholder/extra page to be used for sparse mappings. @@ -1458,7 +1469,8 @@ static void kgsl_iommu_close(struct kgsl_mmu *mmu) if (iommu->regbase != NULL) iounmap(iommu->regbase); - kgsl_sharedmem_free(&kgsl_secure_guard_page_memdesc); + kgsl_free_secure_page(kgsl_secure_guard_page); + kgsl_secure_guard_page = NULL; if (kgsl_guard_page != NULL) { __free_page(kgsl_guard_page); @@ -1730,9 +1742,11 @@ static int _iommu_map_guard_page(struct kgsl_pagetable *pt, uint64_t gpuaddr, unsigned int protflags) { + uint64_t pad_size; phys_addr_t physaddr; - if (!kgsl_memdesc_has_guard_page(memdesc)) + pad_size = kgsl_memdesc_footprint(memdesc) - memdesc->size; + if (!pad_size) return 0; /* @@ -1742,21 +1756,16 @@ static int _iommu_map_guard_page(struct kgsl_pagetable *pt, * mapped to save 1MB of memory if CPZ is not used. */ if (kgsl_memdesc_is_secured(memdesc)) { - struct scatterlist *sg; - unsigned int sgp_size = pt->mmu->secure_align_mask + 1; - - if (!kgsl_secure_guard_page_memdesc.sgt) { - if (kgsl_allocate_user(KGSL_MMU_DEVICE(pt->mmu), - &kgsl_secure_guard_page_memdesc, - sgp_size, KGSL_MEMFLAGS_SECURE)) { + if (!kgsl_secure_guard_page) { + kgsl_secure_guard_page = kgsl_alloc_secure_page(); + if (!kgsl_secure_guard_page) { KGSL_CORE_ERR( "Secure guard page alloc failed\n"); return -ENOMEM; } } - sg = kgsl_secure_guard_page_memdesc.sgt->sgl; - physaddr = page_to_phys(sg_page(sg)); + physaddr = page_to_phys(kgsl_secure_guard_page); } else { if (kgsl_guard_page == NULL) { kgsl_guard_page = alloc_page(GFP_KERNEL | __GFP_ZERO | @@ -1768,9 +1777,11 @@ static int _iommu_map_guard_page(struct kgsl_pagetable *pt, physaddr = page_to_phys(kgsl_guard_page); } - return _iommu_map_sync_pc(pt, gpuaddr, physaddr, - kgsl_memdesc_guard_page_size(memdesc), - protflags & ~IOMMU_WRITE); + if (!MMU_FEATURE(pt->mmu, KGSL_MMU_PAD_VA)) + protflags &= ~IOMMU_WRITE; + + return _iommu_map_single_page_sync_pc(pt, gpuaddr, physaddr, + pad_size >> PAGE_SHIFT, protflags); } static unsigned int _get_protection_flags(struct kgsl_memdesc *memdesc) diff --git a/drivers/gpu/msm/kgsl_mmu.h b/drivers/gpu/msm/kgsl_mmu.h index 430a14081d35..4b06654fc21a 100644 --- a/drivers/gpu/msm/kgsl_mmu.h +++ b/drivers/gpu/msm/kgsl_mmu.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2002,2007-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2002,2007-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -140,6 +140,8 @@ struct kgsl_mmu_pt_ops { #define KGSL_MMU_NEED_GUARD_PAGE BIT(9) /* The device supports IO coherency */ #define KGSL_MMU_IO_COHERENT BIT(10) +/* The device requires VA mappings padded up to a given size */ +#define KGSL_MMU_PAD_VA BIT(11) /** * struct kgsl_mmu - Master definition for KGSL MMU devices @@ -151,6 +153,7 @@ struct kgsl_mmu_pt_ops { * @secured: True if the MMU needs to be secured * @feature: Static list of MMU features * @secure_aligned_mask: Mask that secure buffers need to be aligned to + * @va_padding: Size to pad VA mappings to * @priv: Union of sub-device specific members */ struct kgsl_mmu { @@ -162,6 +165,7 @@ struct kgsl_mmu { bool secured; unsigned long features; unsigned int secure_align_mask; + uint64_t va_padding; union { struct kgsl_iommu iommu; } priv; diff --git a/drivers/gpu/msm/kgsl_sharedmem.c b/drivers/gpu/msm/kgsl_sharedmem.c index 9a0bb9d33a66..f2a41eb1c5e9 100644 --- a/drivers/gpu/msm/kgsl_sharedmem.c +++ b/drivers/gpu/msm/kgsl_sharedmem.c @@ -407,6 +407,39 @@ static void kgsl_page_alloc_unmap_kernel(struct kgsl_memdesc *memdesc) mutex_unlock(&kernel_map_global_lock); } +static int kgsl_lock_sgt(struct sg_table *sgt) +{ + struct scatterlist *sg; + int dest_perms = PERM_READ | PERM_WRITE; + int source_vm = VMID_HLOS; + int dest_vm = VMID_CP_PIXEL; + int ret; + int i; + + ret = hyp_assign_table(sgt, &source_vm, 1, &dest_vm, &dest_perms, 1); + if (!ret) { + /* Set private bit for each sg to indicate that its secured */ + for_each_sg(sgt->sgl, sg, sgt->nents, i) + SetPagePrivate(sg_page(sg)); + } + return ret; +} + +static int kgsl_unlock_sgt(struct sg_table *sgt) +{ + int dest_perms = PERM_READ | PERM_WRITE | PERM_EXEC; + int source_vm = VMID_CP_PIXEL; + int dest_vm = VMID_HLOS; + int ret; + struct sg_page_iter sg_iter; + + ret = hyp_assign_table(sgt, &source_vm, 1, &dest_vm, &dest_perms, 1); + + for_each_sg_page(sgt->sgl, &sg_iter, sgt->nents, 0) + ClearPagePrivate(sg_page_iter_page(&sg_iter)); + return ret; +} + static void kgsl_page_alloc_free(struct kgsl_memdesc *memdesc) { kgsl_page_alloc_unmap_kernel(memdesc); @@ -416,12 +449,8 @@ static void kgsl_page_alloc_free(struct kgsl_memdesc *memdesc) /* Secure buffers need to be unlocked before being freed */ if (memdesc->priv & KGSL_MEMDESC_TZ_LOCKED) { int ret; - int dest_perms = PERM_READ | PERM_WRITE | PERM_EXEC; - int source_vm = VMID_CP_PIXEL; - int dest_vm = VMID_HLOS; - ret = hyp_assign_table(memdesc->sgt, &source_vm, 1, - &dest_vm, &dest_perms, 1); + ret = kgsl_unlock_sgt(memdesc->sgt); if (ret) { pr_err("Secure buf unlock failed: gpuaddr: %llx size: %llx ret: %d\n", memdesc->gpuaddr, memdesc->size, ret); @@ -432,15 +461,6 @@ static void kgsl_page_alloc_free(struct kgsl_memdesc *memdesc) atomic_long_sub(memdesc->size, &kgsl_driver.stats.page_alloc); } - if (memdesc->priv & KGSL_MEMDESC_TZ_LOCKED) { - struct sg_page_iter sg_iter; - - for_each_sg_page(memdesc->sgt->sgl, &sg_iter, - memdesc->sgt->nents, 0) - ClearPagePrivate(sg_page_iter_page(&sg_iter)); - - } - /* Free pages using the pages array for non secure paged memory */ if (memdesc->pages != NULL) kgsl_pool_free_pages(memdesc->pages, memdesc->page_count); @@ -722,6 +742,7 @@ void kgsl_memdesc_init(struct kgsl_device *device, memdesc->priv |= KGSL_MEMDESC_SECURE; memdesc->flags = flags; + memdesc->pad_to = mmu->va_padding; memdesc->dev = device->dev->parent; align = max_t(unsigned int, @@ -841,12 +862,6 @@ kgsl_sharedmem_page_alloc_user(struct kgsl_memdesc *memdesc, /* Call to the hypervisor to lock any secure buffer allocations */ if (memdesc->flags & KGSL_MEMFLAGS_SECURE) { - unsigned int i; - struct scatterlist *sg; - int dest_perms = PERM_READ | PERM_WRITE; - int source_vm = VMID_HLOS; - int dest_vm = VMID_CP_PIXEL; - memdesc->sgt = kmalloc(sizeof(struct sg_table), GFP_KERNEL); if (memdesc->sgt == NULL) { ret = -ENOMEM; @@ -860,8 +875,7 @@ kgsl_sharedmem_page_alloc_user(struct kgsl_memdesc *memdesc, goto done; } - ret = hyp_assign_table(memdesc->sgt, &source_vm, 1, - &dest_vm, &dest_perms, 1); + ret = kgsl_lock_sgt(memdesc->sgt); if (ret) { sg_free_table(memdesc->sgt); kfree(memdesc->sgt); @@ -869,10 +883,6 @@ kgsl_sharedmem_page_alloc_user(struct kgsl_memdesc *memdesc, goto done; } - /* Set private bit for each sg to indicate that its secured */ - for_each_sg(memdesc->sgt->sgl, sg, memdesc->sgt->nents, i) - SetPagePrivate(sg_page(sg)); - memdesc->priv |= KGSL_MEMDESC_TZ_LOCKED; /* Record statistics */ @@ -933,6 +943,50 @@ void kgsl_sharedmem_free(struct kgsl_memdesc *memdesc) } EXPORT_SYMBOL(kgsl_sharedmem_free); +void kgsl_free_secure_page(struct page *page) +{ + struct sg_table sgt; + struct scatterlist sgl; + + if (!page) + return; + + sgt.sgl = &sgl; + sgt.nents = 1; + sgt.orig_nents = 1; + sg_init_table(&sgl, 1); + sg_set_page(&sgl, page, PAGE_SIZE, 0); + + kgsl_unlock_sgt(&sgt); + __free_page(page); +} + +struct page *kgsl_alloc_secure_page(void) +{ + struct page *page; + struct sg_table sgt; + struct scatterlist sgl; + int status; + + page = alloc_page(GFP_KERNEL | __GFP_ZERO | + __GFP_NORETRY | __GFP_HIGHMEM); + if (!page) + return NULL; + + sgt.sgl = &sgl; + sgt.nents = 1; + sgt.orig_nents = 1; + sg_init_table(&sgl, 1); + sg_set_page(&sgl, page, PAGE_SIZE, 0); + + status = kgsl_lock_sgt(&sgt); + if (status) { + __free_page(page); + return NULL; + } + return page; +} + int kgsl_sharedmem_readl(const struct kgsl_memdesc *memdesc, uint32_t *dst, diff --git a/drivers/gpu/msm/kgsl_sharedmem.h b/drivers/gpu/msm/kgsl_sharedmem.h index 976752d67b22..6811363da4db 100644 --- a/drivers/gpu/msm/kgsl_sharedmem.h +++ b/drivers/gpu/msm/kgsl_sharedmem.h @@ -76,6 +76,10 @@ void kgsl_get_memory_usage(char *str, size_t len, uint64_t memflags); int kgsl_sharedmem_page_alloc_user(struct kgsl_memdesc *memdesc, uint64_t size); +void kgsl_free_secure_page(struct page *page); + +struct page *kgsl_alloc_secure_page(void); + #define MEMFLAGS(_flags, _mask, _shift) \ ((unsigned int) (((_flags) & (_mask)) >> (_shift))) @@ -131,6 +135,7 @@ kgsl_memdesc_get_memtype(const struct kgsl_memdesc *memdesc) static inline int kgsl_memdesc_set_align(struct kgsl_memdesc *memdesc, unsigned int align) { + align = max_t(unsigned int, align, ilog2(memdesc->pad_to)); if (align > 32) align = 32; @@ -262,7 +267,8 @@ kgsl_memdesc_use_cpu_map(const struct kgsl_memdesc *memdesc) static inline uint64_t kgsl_memdesc_footprint(const struct kgsl_memdesc *memdesc) { - return memdesc->size + kgsl_memdesc_guard_page_size(memdesc); + return ALIGN(memdesc->size + kgsl_memdesc_guard_page_size(memdesc), + memdesc->pad_to); } /* -- GitLab From 69d80059f2245402a77a1a3dea2457cadd94d2a9 Mon Sep 17 00:00:00 2001 From: Lynus Vaz Date: Tue, 10 Apr 2018 12:34:16 +0530 Subject: [PATCH 1105/1635] msm: kgsl: Specify 64K padding for A640 A640v1 devices require GPU VA aligned and padded up to 64K. Change-Id: I3157de5137231d90c9fc18f0afc74c79d3c23a15 Signed-off-by: Lynus Vaz --- drivers/gpu/msm/adreno-gpulist.h | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/msm/adreno-gpulist.h b/drivers/gpu/msm/adreno-gpulist.h index 79fa645537ad..1c937d99a5a1 100644 --- a/drivers/gpu/msm/adreno-gpulist.h +++ b/drivers/gpu/msm/adreno-gpulist.h @@ -397,5 +397,6 @@ static const struct adreno_gpu_core adreno_gpulist[] = { .gpmu_minor = 0x000, .gpmu_tsens = 0x000C000D, .max_power = 5448, + .va_padding = SZ_64K, }, }; -- GitLab From 11f7cc673dc838244e3f8bbbae257abf7fa7fd88 Mon Sep 17 00:00:00 2001 From: Tharun Kumar Merugu Date: Wed, 25 Apr 2018 15:50:45 +0530 Subject: [PATCH 1106/1635] msm: adsprpc: workaround to enable smmu stage 1 for slpi sm8150 has a hardware bug in the slpi-smmu interface where the stream ID is not removed from the IOVA. This software workaround modifies the start address of the IOVA address space for fastrpc slpi context banks. Change-Id: I5368749b6f21ee33bf0c93b77403f2d34520718b Acked-by: Thyagarajan Venkatanarayanan Signed-off-by: Tharun Kumar Merugu --- drivers/char/adsprpc.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/drivers/char/adsprpc.c b/drivers/char/adsprpc.c index 78ad6abed073..dfc6cb2ce960 100644 --- a/drivers/char/adsprpc.c +++ b/drivers/char/adsprpc.c @@ -430,7 +430,7 @@ static void fastrpc_buf_free(struct fastrpc_buf *buf, int cache) int destVM[1] = {VMID_HLOS}; int destVMperm[1] = {PERM_READ | PERM_WRITE | PERM_EXEC}; - if (fl->sctx->smmu.cb) + if (fl->sctx->smmu.cb && fl->cid != SDSP_DOMAIN_ID) buf->phys &= ~((uint64_t)fl->sctx->smmu.cb << 32); vmid = fl->apps->channel[fl->cid].vmid; if (vmid) { @@ -754,7 +754,8 @@ static int fastrpc_mmap_create(struct fastrpc_file *fl, int fd, } map->phys = sg_dma_address(map->table->sgl); if (sess->smmu.cb) { - map->phys += ((uint64_t)sess->smmu.cb << 32); + if (fl->cid != SDSP_DOMAIN_ID) + map->phys += ((uint64_t)sess->smmu.cb << 32); for_each_sg(map->table->sgl, sgl, map->table->nents, sgl_index) map->size += sg_dma_len(sgl); @@ -831,7 +832,7 @@ static int fastrpc_buf_alloc(struct fastrpc_file *fl, size_t size, } if (err) goto bail; - if (fl->sctx->smmu.cb) + if (fl->sctx->smmu.cb && fl->cid != SDSP_DOMAIN_ID) buf->phys += ((uint64_t)fl->sctx->smmu.cb << 32); vmid = fl->apps->channel[fl->cid].vmid; if (vmid) { @@ -2958,8 +2959,8 @@ static int fastrpc_cb_probe(struct device *dev) struct fastrpc_session_ctx *sess; struct of_phandle_args iommuspec; const char *name; - unsigned int start = 0x80000000; - int err = 0, i; + dma_addr_t start = 0x80000000; + int err = 0, cid, i; int secure_vmid = VMID_CP_PIXEL; VERIFY(err, NULL != (name = of_get_property(dev->of_node, @@ -2975,6 +2976,7 @@ static int fastrpc_cb_probe(struct device *dev) VERIFY(err, i < NUM_CHANNELS); if (err) goto bail; + cid = i; chan = &gcinfo[i]; VERIFY(err, chan->sesscount < NUM_SESSIONS); if (err) @@ -2991,6 +2993,10 @@ static int fastrpc_cb_probe(struct device *dev) "dma-coherent"); sess->smmu.secure = of_property_read_bool(dev->of_node, "qcom,secure-context-bank"); + if (cid == SDSP_DOMAIN_ID) { + start += ((uint64_t)sess->smmu.cb << 32); + dma_set_mask(dev, DMA_BIT_MASK(36)); + } if (sess->smmu.secure) start = 0x60000000; VERIFY(err, !IS_ERR_OR_NULL(sess->smmu.mapping = -- GitLab From 3cb08ff1d473b1fa69e75010bcf85ba99fe42321 Mon Sep 17 00:00:00 2001 From: Mukesh Kumar Savaliya Date: Sat, 3 Feb 2018 23:07:40 +0530 Subject: [PATCH 1107/1635] ARM: dts: msm: Add initial QUPV3 and Slimbus DT nodes for SDM640 Add initial device tree nodes for QUPV3 serial engine and Slimbus instances to support buses protocols. Change-Id: I39e57c6827cab0a66680b7b8ba1abc79dad5db3b Signed-off-by: Mukesh Kumar Savaliya Signed-off-by: Shrey Vijay --- arch/arm64/boot/dts/qcom/sdm640-pinctrl.dtsi | 375 +++++++++++++++++++ arch/arm64/boot/dts/qcom/sdm640-qupv3.dtsi | 290 +++++++++++++- arch/arm64/boot/dts/qcom/sdm640.dtsi | 45 +++ 3 files changed, 709 insertions(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/sdm640-pinctrl.dtsi b/arch/arm64/boot/dts/qcom/sdm640-pinctrl.dtsi index e5771c6f8ff0..ca16558f0005 100644 --- a/arch/arm64/boot/dts/qcom/sdm640-pinctrl.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm640-pinctrl.dtsi @@ -20,6 +20,8 @@ interrupt-controller; #interrupt-cells = <2>; + /* QUPv3_0 South SE mappings */ + /* SE 0 pin mappings */ qupv3_se0_2uart_pins: qupv3_se0_2uart_pins { qupv3_se0_2uart_active: qupv3_se0_2uart_active { mux { @@ -48,6 +50,379 @@ }; }; + /* SE 1 pin mappings */ + qupv3_se1_i2c_pins: qupv3_se1_i2c_pins { + qupv3_se1_i2c_active: qupv3_se1_i2c_active { + mux { + pins = "gpio4", "gpio5"; + function = "qup01"; + }; + + config { + pins = "gpio4", "gpio5"; + drive-strength = <2>; + bias-disable; + }; + }; + + qupv3_se1_i2c_sleep: qupv3_se1_i2c_sleep { + mux { + pins = "gpio4", "gpio5"; + function = "gpio"; + }; + + config { + pins = "gpio4", "gpio5"; + drive-strength = <2>; + bias-pull-up; + }; + }; + }; + + /* SE 2 pin mappings */ + qupv3_se2_i2c_pins: qupv3_se2_i2c_pins { + qupv3_se2_i2c_active: qupv3_se2_i2c_active { + mux { + pins = "gpio0", "gpio1"; + function = "qup02"; + }; + + config { + pins = "gpio0", "gpio1"; + drive-strength = <2>; + bias-disable; + }; + }; + + qupv3_se2_i2c_sleep: qupv3_se2_i2c_sleep { + mux { + pins = "gpio0", "gpio1"; + function = "gpio"; + }; + + config { + pins = "gpio0", "gpio1"; + drive-strength = <2>; + bias-pull-up; + }; + }; + }; + + qupv3_se2_spi_pins: qupv3_se2_spi_pins { + qupv3_se2_spi_active: qupv3_se2_spi_active { + mux { + pins = "gpio0", "gpio1", "gpio2", + "gpio3"; + function = "qup02"; + }; + + config { + pins = "gpio0", "gpio1", "gpio2", + "gpio3"; + drive-strength = <6>; + bias-disable; + }; + }; + + qupv3_se2_spi_sleep: qupv3_se2_spi_sleep { + mux { + pins = "gpio0", "gpio1", "gpio2", + "gpio3"; + function = "gpio"; + }; + + config { + pins = "gpio0", "gpio1", "gpio2", + "gpio3"; + drive-strength = <6>; + bias-disable; + }; + }; + }; + + /* SE 3 pin mappings */ + qupv3_se3_i2c_pins: qupv3_se3_i2c_pins { + qupv3_se3_i2c_active: qupv3_se3_i2c_active { + mux { + pins = "gpio18", "gpio19"; + function = "qup03"; + }; + + config { + pins = "gpio18", "gpio19"; + drive-strength = <2>; + bias-disable; + }; + }; + + qupv3_se3_i2c_sleep: qupv3_se3_i2c_sleep { + mux { + pins = "gpio18", "gpio19"; + function = "gpio"; + }; + + config { + pins = "gpio18", "gpio19"; + drive-strength = <2>; + bias-pull-up; + }; + }; + }; + + /* QUPv3_1 North instances */ + /* SE 4 pin mappings */ + qupv3_se4_i2c_pins: qupv3_se4_i2c_pins { + qupv3_se4_i2c_active: qupv3_se4_i2c_active { + mux { + pins = "gpio20", "gpio21"; + function = "qup10"; + }; + + config { + pins = "gpio20", "gpio21"; + drive-strength = <2>; + bias-disable; + }; + }; + + qupv3_se4_i2c_sleep: qupv3_se4_i2c_sleep { + mux { + pins = "gpio20", "gpio21"; + function = "gpio"; + }; + + config { + pins = "gpio20", "gpio21"; + drive-strength = <2>; + bias-pull-up; + }; + }; + }; + + qupv3_se4_spi_pins: qupv3_se4_spi_pins { + qupv3_se4_spi_active: qupv3_se4_spi_active { + mux { + pins = "gpio20", "gpio21", "gpio22", + "gpio23"; + function = "qup10"; + }; + + config { + pins = "gpio20", "gpio21", "gpio22", + "gpio23"; + drive-strength = <6>; + bias-disable; + }; + }; + + qupv3_se4_spi_sleep: qupv3_se4_spi_sleep { + mux { + pins = "gpio20", "gpio21", "gpio22", + "gpio23"; + function = "gpio"; + }; + + config { + pins = "gpio20", "gpio21", "gpio22", + "gpio23"; + drive-strength = <6>; + bias-disable; + }; + }; + }; + + /* SE 5 pin mappings */ + qupv3_se5_i2c_pins: qupv3_se5_i2c_pins { + qupv3_se5_i2c_active: qupv3_se5_i2c_active { + mux { + pins = "gpio14", "gpio15"; + function = "qup11"; + }; + + config { + pins = "gpio14", "gpio15"; + drive-strength = <2>; + bias-disable; + }; + }; + + qupv3_se5_i2c_sleep: qupv3_se5_i2c_sleep { + mux { + pins = "gpio14", "gpio15"; + function = "gpio"; + }; + + config { + pins = "gpio14", "gpio15"; + drive-strength = <2>; + bias-pull-up; + }; + }; + }; + + /* SE 6 pin mappings */ + qupv3_se6_i2c_pins: qupv3_se6_i2c_pins { + qupv3_se6_i2c_active: qupv3_se6_i2c_active { + mux { + pins = "gpio6", "gpio7"; + function = "qup12"; + }; + + config { + pins = "gpio6", "gpio7"; + drive-strength = <2>; + bias-disable; + }; + }; + + qupv3_se6_i2c_sleep: qupv3_se6_i2c_sleep { + mux { + pins = "gpio6", "gpio7"; + function = "gpio"; + }; + + config { + pins = "gpio6", "gpio7"; + drive-strength = <2>; + bias-pull-up; + }; + }; + }; + + qupv3_se6_spi_pins: qupv3_se6_spi_pins { + qupv3_se6_spi_active: qupv3_se6_spi_active { + mux { + pins = "gpio6", "gpio7", "gpio8", + "gpio9"; + function = "qup12"; + }; + + config { + pins = "gpio6", "gpio7", "gpio8", + "gpio9"; + drive-strength = <6>; + bias-disable; + }; + }; + + qupv3_se6_spi_sleep: qupv3_se6_spi_sleep { + mux { + pins = "gpio6", "gpio7", "gpio8", + "gpio9"; + function = "gpio"; + }; + + config { + pins = "gpio6", "gpio7", "gpio8", + "gpio9"; + drive-strength = <6>; + bias-disable; + }; + }; + }; + + /* SE 7 pin mappings */ + qupv3_se7_i2c_pins: qupv3_se7_i2c_pins { + qupv3_se7_i2c_active: qupv3_se7_i2c_active { + mux { + pins = "gpio10", "gpio11"; + function = "qup13"; + }; + + config { + pins = "gpio10", "gpio11"; + drive-strength = <2>; + bias-disable; + }; + }; + + qupv3_se7_i2c_sleep: qupv3_se7_i2c_sleep { + mux { + pins = "gpio10", "gpio11"; + function = "gpio"; + }; + + config { + pins = "gpio10", "gpio11"; + drive-strength = <2>; + bias-pull-up; + }; + }; + }; + + qupv3_se7_spi_pins: qupv3_se7_spi_pins { + qupv3_se7_spi_active: qupv3_se7_spi_active { + mux { + pins = "gpio10", "gpio11", "gpio12", + "gpio13"; + function = "qup13"; + }; + + config { + pins = "gpio10", "gpio11", "gpio12", + "gpio13"; + drive-strength = <6>; + bias-disable; + }; + }; + + qupv3_se7_spi_sleep: qupv3_se7_spi_sleep { + mux { + pins = "gpio10", "gpio11", "gpio12", + "gpio13"; + function = "gpio"; + }; + + config { + pins = "gpio10", "gpio11", "gpio12", + "gpio13"; + drive-strength = <6>; + bias-disable; + }; + }; + }; + + qupv3_se7_4uart_pins: qupv3_se7_4uart_pins { + qupv3_se7_ctsrx: qupv3_se7_ctsrx { + mux { + pins = "gpio10", "gpio13"; + function = "qup13"; + }; + + config { + pins = "gpio10", "gpio13"; + drive-strength = <2>; + bias-no-pull; + }; + }; + + qupv3_se7_rts: qupv3_se7_rts { + mux { + pins = "gpio11"; + function = "qup13"; + }; + + config { + pins = "gpio11"; + drive-strength = <2>; + bias-pull-down; + }; + }; + + qupv3_se7_tx: qupv3_se7_tx { + mux { + pins = "gpio12"; + function = "qup13"; + }; + + config { + pins = "gpio12"; + drive-strength = <2>; + bias-pull-up; + }; + }; + }; + /* SDC pin type */ sdc1_clk_on: sdc1_clk_on { config { diff --git a/arch/arm64/boot/dts/qcom/sdm640-qupv3.dtsi b/arch/arm64/boot/dts/qcom/sdm640-qupv3.dtsi index 6e3e61c63084..1ab49b81d108 100644 --- a/arch/arm64/boot/dts/qcom/sdm640-qupv3.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm640-qupv3.dtsi @@ -13,12 +13,30 @@ #include &soc { - /* QUPv3 North Instances */ + /* + * QUPv3 North & South Instances + * North 0 : SE 4 + * North 1 : SE 5 + * North 2 : SE 6 + * North 3 : SE 7 + * South 0 : SE 0 + * South 1 : SE 1 + * South 2 : SE 2 + * South 3 : SE 3 + */ + + /* QUPv3 South Instances */ qupv3_0: qcom,qupv3_0_geni_se@8c0000 { compatible = "qcom,qupv3-geni-se"; reg = <0x8c0000 0x6000>; qcom,bus-mas-id = ; qcom,bus-slv-id = ; + qcom,iommu-s1-bypass; + + iommu_qupv3_0_geni_se_cb: qcom,iommu_qupv3_0_geni_se_cb { + compatible = "qcom,qupv3-geni-se-cb"; + iommus = <&apps_smmu 0xc3 0x0>; + }; }; /* Debug UART Instance for CDP/MTP platform */ @@ -37,4 +55,274 @@ qcom,wrapper-core = <&qupv3_0>; status = "disabled"; }; + + /* I2C */ + qupv3_se1_i2c: i2c@884000 { + compatible = "qcom,i2c-geni"; + reg = <0x884000 0x4000>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&clock_gcc GCC_QUPV3_WRAP0_S1_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>; + dmas = <&gpi_dma0 0 1 3 64 0>, + <&gpi_dma0 1 1 3 64 0>; + dma-names = "tx", "rx"; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se1_i2c_active>; + pinctrl-1 = <&qupv3_se1_i2c_sleep>; + qcom,wrapper-core = <&qupv3_0>; + status = "disabled"; + }; + + qupv3_se2_i2c: i2c@888000 { + compatible = "qcom,i2c-geni"; + reg = <0x888000 0x4000>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&clock_gcc GCC_QUPV3_WRAP0_S2_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>; + dmas = <&gpi_dma0 0 2 3 64 0>, + <&gpi_dma0 1 2 3 64 0>; + dma-names = "tx", "rx"; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se2_i2c_active>; + pinctrl-1 = <&qupv3_se2_i2c_sleep>; + qcom,wrapper-core = <&qupv3_0>; + status = "disabled"; + }; + + qupv3_se3_i2c: i2c@88c000 { + compatible = "qcom,i2c-geni"; + reg = <0x88c000 0x4000>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&clock_gcc GCC_QUPV3_WRAP0_S3_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>; + dmas = <&gpi_dma0 0 3 3 64 0>, + <&gpi_dma0 1 3 3 64 0>; + dma-names = "tx", "rx"; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se3_i2c_active>; + pinctrl-1 = <&qupv3_se3_i2c_sleep>; + qcom,wrapper-core = <&qupv3_0>; + status = "disabled"; + }; + + /* SPI */ + qupv3_se2_spi: spi@888000 { + compatible = "qcom,spi-geni"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x888000 0x4000>; + reg-names = "se_phys"; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&clock_gcc GCC_QUPV3_WRAP0_S2_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se2_spi_active>; + pinctrl-1 = <&qupv3_se2_spi_sleep>; + interrupts = ; + spi-max-frequency = <50000000>; + qcom,wrapper-core = <&qupv3_0>; + dmas = <&gpi_dma0 0 2 1 64 0>, + <&gpi_dma0 1 2 1 64 0>; + dma-names = "tx", "rx"; + status = "disabled"; + }; + + /* QUPv3 North instances */ + qupv3_1: qcom,qupv3_1_geni_se@ac0000 { + compatible = "qcom,qupv3-geni-se"; + reg = <0xac0000 0x6000>; + qcom,bus-mas-id = ; + qcom,bus-slv-id = ; + qcom,iommu-s1-bypass; + + iommu_qupv3_1_geni_se_cb: qcom,iommu_qupv3_1_geni_se_cb { + compatible = "qcom,qupv3-geni-se-cb"; + iommus = <&apps_smmu 0x363 0x0>; + }; + }; + + /* I2C */ + qupv3_se4_i2c: i2c@a80000 { + compatible = "qcom,i2c-geni"; + reg = <0xa80000 0x4000>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&clock_gcc GCC_QUPV3_WRAP1_S0_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_1_M_AHB_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_1_S_AHB_CLK>; + dmas = <&gpi_dma1 0 0 3 64 0>, + <&gpi_dma1 1 0 3 64 0>; + dma-names = "tx", "rx"; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se4_i2c_active>; + pinctrl-1 = <&qupv3_se4_i2c_sleep>; + qcom,wrapper-core = <&qupv3_1>; + status = "disabled"; + }; + + qupv3_se5_i2c: i2c@a84000 { + compatible = "qcom,i2c-geni"; + reg = <0xa84000 0x4000>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&clock_gcc GCC_QUPV3_WRAP1_S1_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_1_M_AHB_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_1_S_AHB_CLK>; + dmas = <&gpi_dma1 0 1 3 64 0>, + <&gpi_dma1 1 1 3 64 0>; + dma-names = "tx", "rx"; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se5_i2c_active>; + pinctrl-1 = <&qupv3_se5_i2c_sleep>; + qcom,wrapper-core = <&qupv3_1>; + status = "disabled"; + }; + + qupv3_se6_i2c: i2c@a88000 { + compatible = "qcom,i2c-geni"; + reg = <0xa88000 0x4000>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&clock_gcc GCC_QUPV3_WRAP1_S2_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_1_M_AHB_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_1_S_AHB_CLK>; + dmas = <&gpi_dma1 0 2 3 64 0>, + <&gpi_dma1 1 2 3 64 0>; + dma-names = "tx", "rx"; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se6_i2c_active>; + pinctrl-1 = <&qupv3_se6_i2c_sleep>; + qcom,wrapper-core = <&qupv3_1>; + status = "disabled"; + }; + + qupv3_se7_i2c: i2c@a8c000 { + compatible = "qcom,i2c-geni"; + reg = <0xa8c000 0x4000>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&clock_gcc GCC_QUPV3_WRAP1_S3_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_1_M_AHB_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_1_S_AHB_CLK>; + dmas = <&gpi_dma1 0 3 3 64 0>, + <&gpi_dma1 1 3 3 64 0>; + dma-names = "tx", "rx"; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se7_i2c_active>; + pinctrl-1 = <&qupv3_se7_i2c_sleep>; + qcom,wrapper-core = <&qupv3_1>; + status = "disabled"; + }; + + /* SPI */ + qupv3_se4_spi: spi@a80000 { + compatible = "qcom,spi-geni"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0xa80000 0x4000>; + reg-names = "se_phys"; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&clock_gcc GCC_QUPV3_WRAP1_S0_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_1_M_AHB_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_1_S_AHB_CLK>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se4_spi_active>; + pinctrl-1 = <&qupv3_se4_spi_sleep>; + interrupts = ; + spi-max-frequency = <50000000>; + qcom,wrapper-core = <&qupv3_1>; + dmas = <&gpi_dma1 0 0 1 64 0>, + <&gpi_dma1 1 0 1 64 0>; + dma-names = "tx", "rx"; + status = "disabled"; + }; + + qupv3_se6_spi: spi@a88000 { + compatible = "qcom,spi-geni"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0xa88000 0x4000>; + reg-names = "se_phys"; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&clock_gcc GCC_QUPV3_WRAP1_S2_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_1_M_AHB_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_1_S_AHB_CLK>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se6_spi_active>; + pinctrl-1 = <&qupv3_se6_spi_sleep>; + interrupts = ; + spi-max-frequency = <50000000>; + qcom,wrapper-core = <&qupv3_1>; + dmas = <&gpi_dma1 0 2 1 64 0>, + <&gpi_dma1 1 2 1 64 0>; + dma-names = "tx", "rx"; + status = "disabled"; + }; + + qupv3_se7_spi: spi@a8c000 { + compatible = "qcom,spi-geni"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0xa8c000 0x4000>; + reg-names = "se_phys"; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&clock_gcc GCC_QUPV3_WRAP1_S3_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_1_M_AHB_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_1_S_AHB_CLK>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se7_spi_active>; + pinctrl-1 = <&qupv3_se7_spi_sleep>; + interrupts = ; + spi-max-frequency = <50000000>; + qcom,wrapper-core = <&qupv3_1>; + dmas = <&gpi_dma1 0 3 1 64 0>, + <&gpi_dma1 1 3 1 64 0>; + dma-names = "tx", "rx"; + status = "disabled"; + }; + + /* + * HS UART instances. HS UART usecases can be supported on these + * instances only. + */ + qupv3_se7_4uart: qcom,qup_uart@0xa8c000 { + compatible = "qcom,msm-geni-serial-hs"; + reg = <0xa8c000 0x4000>; + reg-names = "se_phys"; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&clock_gcc GCC_QUPV3_WRAP1_S3_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_1_M_AHB_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_1_S_AHB_CLK>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se7_ctsrx>, <&qupv3_se7_rts>, + <&qupv3_se7_tx>; + pinctrl-1 = <&qupv3_se7_ctsrx>, <&qupv3_se7_rts>, + <&qupv3_se7_tx>; + interrupts-extended = <&pdc GIC_SPI 356 0>, + <&tlmm 13 0>; + status = "disabled"; + qcom,wakeup-byte = <0xFD>; + qcom,wrapper-core = <&qupv3_1>; + }; }; diff --git a/arch/arm64/boot/dts/qcom/sdm640.dtsi b/arch/arm64/boot/dts/qcom/sdm640.dtsi index aaf7786cd472..74946ee2929d 100644 --- a/arch/arm64/boot/dts/qcom/sdm640.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm640.dtsi @@ -33,6 +33,11 @@ serial0 = &qupv3_se0_2uart; sdhc1 = &sdhc_1; /* SDC1 eMMC slot */ sdhc2 = &sdhc_2; /* SDC2 SD Card slot */ + spi0 = &qupv3_se4_spi; + i2c0 = &qupv3_se5_i2c; + i2c1 = &qupv3_se1_i2c; + i2c2 = &qupv3_se3_i2c; + hsuart0 = &qupv3_se7_4uart; }; cpus { @@ -953,6 +958,46 @@ #interrupt-cells = <4>; cell-index = <0>; }; + + slim_aud: slim@62dc0000 { + cell-index = <1>; + compatible = "qcom,slim-ngd"; + reg = <0x62dc0000 0x2c000>, + <0x62d84000 0x2a000>; + reg-names = "slimbus_physical", "slimbus_bam_physical"; + interrupts = <0 163 0>, <0 164 0>; + interrupt-names = "slimbus_irq", "slimbus_bam_irq"; + qcom,apps-ch-pipes = <0x7c0000>; + qcom,ea-pc = <0x2f0>; + status = "disabled"; + qcom,iommu-s1-bypass; + + iommu_slim_aud_ctrl_cb: qcom,iommu_slim_ctrl_cb { + compatible = "qcom,iommu-slim-ctrl-cb"; + iommus = <&apps_smmu 0x17e6 0x0>, + <&apps_smmu 0x17ed 0x0>, + <&apps_smmu 0x17ee 0x1>, + <&apps_smmu 0x17f0 0x1>; + }; + + }; + + slim_qca: slim@62e40000 { + cell-index = <3>; + compatible = "qcom,slim-ngd"; + reg = <0x62e40000 0x2c000>, + <0x62e04000 0x20000>; + reg-names = "slimbus_physical", "slimbus_bam_physical"; + interrupts = <0 291 0>, <0 292 0>; + interrupt-names = "slimbus_irq", "slimbus_bam_irq"; + status = "disabled"; + qcom,iommu-s1-bypass; + + iommu_slim_qca_ctrl_cb: qcom,iommu_slim_ctrl_cb { + compatible = "qcom,iommu-slim-ctrl-cb"; + iommus = <&apps_smmu 0x17f3 0x0>; + }; + }; }; #include "sdm640-pinctrl.dtsi" -- GitLab From 8b0014cce0bbd83ac27ca3849611a1fbb48f4e4d Mon Sep 17 00:00:00 2001 From: Tharun Kumar Merugu Date: Wed, 25 Apr 2018 15:42:50 +0530 Subject: [PATCH 1108/1635] ARM: dts: msm: add slpi context banks for fastrpc in sm8150 Add slpi context banks for fastrpc in sm8150 to enable smmu stage 1 for slpi Change-Id: Id8fe18414f208e60e0a80b95564d3d4015e9e4d0 Acked-by: Thyagarajan Venkatanarayanan Signed-off-by: Tharun Kumar Merugu --- arch/arm64/boot/dts/qcom/sm8150.dtsi | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sm8150.dtsi b/arch/arm64/boot/dts/qcom/sm8150.dtsi index dd28cfca9eaa..1fdb72a47d6d 100644 --- a/arch/arm64/boot/dts/qcom/sm8150.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150.dtsi @@ -2172,6 +2172,27 @@ iommus = <&apps_smmu 0x1b25 0x0>; dma-coherent; }; + + qcom,msm_fastrpc_compute_cb13 { + compatible = "qcom,msm-fastrpc-compute-cb"; + label = "sdsprpc-smd"; + iommus = <&apps_smmu 0x5a1 0x0>; + dma-coherent; + }; + + qcom,msm_fastrpc_compute_cb14 { + compatible = "qcom,msm-fastrpc-compute-cb"; + label = "sdsprpc-smd"; + iommus = <&apps_smmu 0x5a2 0x0>; + dma-coherent; + }; + + qcom,msm_fastrpc_compute_cb15 { + compatible = "qcom,msm-fastrpc-compute-cb"; + label = "sdsprpc-smd"; + iommus = <&apps_smmu 0x5a3 0x0>; + dma-coherent; + }; }; sdhc_2: sdhci@8804000 { -- GitLab From 568f07761c0653e4fc5c3c05aca262643503d144 Mon Sep 17 00:00:00 2001 From: Tharun Kumar Merugu Date: Wed, 25 Apr 2018 15:46:34 +0530 Subject: [PATCH 1109/1635] ARM: dts: msm: share slpi context bank for fastrpc in sm8150 Add a property to one slpi context bank to control how many fastrpc sessions can share the same context bank. Change-Id: Ie36da30b9a374c9eadd43d1c7d2d9429170b1721 Acked-by: Thyagarajan Venkatanarayanan Signed-off-by: Tharun Kumar Merugu --- arch/arm64/boot/dts/qcom/sm8150.dtsi | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/boot/dts/qcom/sm8150.dtsi b/arch/arm64/boot/dts/qcom/sm8150.dtsi index 1fdb72a47d6d..2e7bf7fd53c0 100644 --- a/arch/arm64/boot/dts/qcom/sm8150.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150.dtsi @@ -2191,6 +2191,7 @@ compatible = "qcom,msm-fastrpc-compute-cb"; label = "sdsprpc-smd"; iommus = <&apps_smmu 0x5a3 0x0>; + shared-cb = <5>; dma-coherent; }; }; -- GitLab From 94f9aae83b4072382b3b466e332b3af87009297a Mon Sep 17 00:00:00 2001 From: Sudarshan Rajagopalan Date: Wed, 11 Apr 2018 12:11:38 -0700 Subject: [PATCH 1110/1635] ARM: dts: msm: Enable deep pre-fetch for kgsl smmu for sm8150 Enable context caching with deep pre-fetch of length 16 x 4k pages for all context banks of kgsl smmu. Change-Id: I7c0d954a843c65ea74daa600218d152b810417a8 Signed-off-by: Sudarshan Rajagopalan --- arch/arm64/boot/dts/qcom/msm-arm-smmu-sm8150.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/msm-arm-smmu-sm8150.dtsi b/arch/arm64/boot/dts/qcom/msm-arm-smmu-sm8150.dtsi index c89f2a3569ce..279c141e33a6 100644 --- a/arch/arm64/boot/dts/qcom/msm-arm-smmu-sm8150.dtsi +++ b/arch/arm64/boot/dts/qcom/msm-arm-smmu-sm8150.dtsi @@ -383,6 +383,6 @@ }; &kgsl_smmu { - qcom,actlr = <0x0 0x407 0x1>; + qcom,actlr = <0x0 0x407 0x303>; }; -- GitLab From 5c0153742eec1c2138ea4cbb6b2ea9e1dc9c0f06 Mon Sep 17 00:00:00 2001 From: Prasad Sodagudi Date: Sat, 11 Apr 2015 06:06:26 +0530 Subject: [PATCH 1111/1635] lib: spinlock: Trigger a watchdog bite on spin_dump for rwlock Currently dump_stack is printed once a spin_bug is detected for rwlock. So provide an options to trigger a panic or watchdog bite for debugging rwlock magic corruptions and lockups. Change-Id: I20807e8eceb8b81635e58701d1f9f9bd36ab5877 Signed-off-by: Prasad Sodagudi --- kernel/locking/spinlock_debug.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/kernel/locking/spinlock_debug.c b/kernel/locking/spinlock_debug.c index 10e6d8b148c8..c18dadd02af4 100644 --- a/kernel/locking/spinlock_debug.c +++ b/kernel/locking/spinlock_debug.c @@ -150,6 +150,11 @@ static void rwlock_bug(rwlock_t *lock, const char *msg) printk(KERN_EMERG "BUG: rwlock %s on CPU#%d, %s/%d, %p\n", msg, raw_smp_processor_id(), current->comm, task_pid_nr(current), lock); +#ifdef CONFIG_DEBUG_SPINLOCK_BITE_ON_BUG + msm_trigger_wdog_bite(); +#elif defined(CONFIG_DEBUG_SPINLOCK_PANIC_ON_BUG) + BUG(); +#endif dump_stack(); } -- GitLab From 217d5d5c93a2dd2f8de0b25de084814941a24448 Mon Sep 17 00:00:00 2001 From: Kyle Piefer Date: Wed, 18 Apr 2018 11:34:07 -0700 Subject: [PATCH 1112/1635] msm: kgsl: Use the firmware to host error HFI The HFI supports a firmware to host message for conveying firmware errors. Set up the HFI infrastructure to use this message. Change-Id: I5119e7a26e0265987dd674b27484acc69f73561c Signed-off-by: Kyle Piefer --- drivers/gpu/msm/kgsl_hfi.c | 71 ++++++++++++++++++++++---------------- drivers/gpu/msm/kgsl_hfi.h | 2 ++ 2 files changed, 43 insertions(+), 30 deletions(-) diff --git a/drivers/gpu/msm/kgsl_hfi.c b/drivers/gpu/msm/kgsl_hfi.c index 6751982b1588..f03e9f3be3ab 100644 --- a/drivers/gpu/msm/kgsl_hfi.c +++ b/drivers/gpu/msm/kgsl_hfi.c @@ -478,8 +478,10 @@ static void receive_err_req(struct gmu_device *gmu, void *rcvd) { struct hfi_err_cmd *cmd = rcvd; - dev_err(&gmu->pdev->dev, "HFI Error Received: %d %d %d\n", - cmd->error_code, cmd->data[0], cmd->data[1]); + dev_err(&gmu->pdev->dev, "HFI Error Received: %d %d %s\n", + ((cmd->error_code >> 16) & 0xFFFF), + (cmd->error_code & 0xFFFF), + (char *) cmd->data); } static void receive_debug_req(struct gmu_device *gmu, void *rcvd) @@ -518,40 +520,49 @@ void hfi_receiver(unsigned long data) { struct gmu_device *gmu; uint32_t rcvd[MAX_RCVD_SIZE]; + int read_queue[] = { + HFI_MSG_IDX, + HFI_DBG_IDX, + }; + int q; if (!data) return; gmu = (struct gmu_device *)data; - while (hfi_queue_read(gmu, HFI_MSG_IDX, rcvd, sizeof(rcvd)) > 0) { - /* Special case if we're v1 */ - if (HFI_VER_MAJOR(&gmu->hfi) < 2) { - hfi_v1_receiver(gmu, rcvd); - continue; - } - - /* V2 ACK Handler */ - if (MSG_HDR_GET_TYPE(rcvd[0]) == HFI_MSG_ACK) { - receive_ack_cmd(gmu, rcvd); - continue; - } - - /* V2 Request Handler */ - switch (MSG_HDR_GET_ID(rcvd[0])) { - case F2H_MSG_ERR: /* No Reply */ - receive_err_req(gmu, rcvd); - break; - case F2H_MSG_DEBUG: /* No Reply */ - receive_debug_req(gmu, rcvd); - break; - default: /* No Reply */ - dev_err(&gmu->pdev->dev, - "HFI request %d not supported\n", - MSG_HDR_GET_ID(rcvd[0])); - break; - } - }; + /* While we are here, check all of the queues for messages */ + for (q = 0; q < ARRAY_SIZE(read_queue); q++) { + while (hfi_queue_read(gmu, read_queue[q], + rcvd, sizeof(rcvd)) > 0) { + /* Special case if we're v1 */ + if (HFI_VER_MAJOR(&gmu->hfi) < 2) { + hfi_v1_receiver(gmu, rcvd); + continue; + } + + /* V2 ACK Handler */ + if (MSG_HDR_GET_TYPE(rcvd[0]) == HFI_MSG_ACK) { + receive_ack_cmd(gmu, rcvd); + continue; + } + + /* V2 Request Handler */ + switch (MSG_HDR_GET_ID(rcvd[0])) { + case F2H_MSG_ERR: /* No Reply */ + receive_err_req(gmu, rcvd); + break; + case F2H_MSG_DEBUG: /* No Reply */ + receive_debug_req(gmu, rcvd); + break; + default: /* No Reply */ + dev_err(&gmu->pdev->dev, + "HFI request %d not supported\n", + MSG_HDR_GET_ID(rcvd[0])); + break; + } + }; + } } #define GMU_VER_MAJOR(ver) (((ver) >> 28) & 0xF) diff --git a/drivers/gpu/msm/kgsl_hfi.h b/drivers/gpu/msm/kgsl_hfi.h index e358f5c63915..71a469c525ee 100644 --- a/drivers/gpu/msm/kgsl_hfi.h +++ b/drivers/gpu/msm/kgsl_hfi.h @@ -61,6 +61,8 @@ #define HFI_IRQ_CM3_FAULT_MASK BIT(15) #define HFI_IRQ_OOB_MASK GENMASK(31, 16) #define HFI_IRQ_MASK (HFI_IRQ_MSGQ_MASK |\ + HFI_IRQ_SIDEMSGQ_MASK |\ + HFI_IRQ_DBGQ_MASK |\ HFI_IRQ_CM3_FAULT_MASK) #define CLKSET_OPTION_DEFAULT 0 -- GitLab From eced5346360e67d2e2b7f7e3315351f72677ce23 Mon Sep 17 00:00:00 2001 From: Peng Xu Date: Fri, 27 Apr 2018 10:51:27 -0700 Subject: [PATCH 1113/1635] cfg80211/nl80211: add DFS offload flag Add wiphy EXT_FEATURE flag to indicate that HW or driver does all DFS actions by itself. User-space functionality already implemented in hostapd using vendor-specific (QCA) OUI to advertise DFS offload support. Need to introduce generic flag to inform about DFS offload support. For devices with DFS_OFFLOAD flag set user-space will no longer need to issue CAC or do any actions in response to "radar detected" events. HW will do everything by itself and send events to user-space to indicate that CAC was started/finished, etc. Signed-off-by: Dmitrii Lebed Signed-off-by: Johannes Berg Git-commit: 13cf6dec93e021ebd297619ea1926aea31b6430b Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211-next.git CRs-fixed: 2232773 Change-Id: Ib6e425762612c4b41f10638ce6e5fa9fb5133640 Signed-off-by: --- include/uapi/linux/nl80211.h | 7 +++++++ net/wireless/nl80211.c | 12 ++++++++---- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index 8460228068cf..cc71d730b34e 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -4927,6 +4927,12 @@ enum nl80211_feature_flags { * handshake with 802.1X in station mode (will pass EAP frames to the host * and accept the set_pmk/del_pmk commands), doing it in the host might not * be supported. + * @NL80211_EXT_FEATURE_DFS_OFFLOAD: HW/driver will offload DFS actions. + * Device or driver will do all DFS-related actions by itself, + * informing user-space about CAC progress, radar detection event, + * channel change triggered by radar detection event. + * No need to start CAC from user-space, no need to react to + * "radar detected" event. * * @NUM_NL80211_EXT_FEATURES: number of extended features. * @MAX_NL80211_EXT_FEATURES: highest extended feature index. @@ -4949,6 +4955,7 @@ enum nl80211_ext_feature_index { NL80211_EXT_FEATURE_FILS_SK_OFFLOAD, NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_PSK, NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_1X, + NL80211_EXT_FEATURE_DFS_OFFLOAD, /* add new features before the definition below */ NUM_NL80211_EXT_FEATURES, diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index a1957584ebed..fa42a435943d 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -7457,12 +7457,13 @@ static int nl80211_start_radar_detection(struct sk_buff *skb, struct cfg80211_registered_device *rdev = info->user_ptr[0]; struct net_device *dev = info->user_ptr[1]; struct wireless_dev *wdev = dev->ieee80211_ptr; + struct wiphy *wiphy = wdev->wiphy; struct cfg80211_chan_def chandef; enum nl80211_dfs_regions dfs_region; unsigned int cac_time_ms; int err; - dfs_region = reg_get_dfs_region(wdev->wiphy); + dfs_region = reg_get_dfs_region(wiphy); if (dfs_region == NL80211_DFS_UNSET) return -EINVAL; @@ -7476,17 +7477,20 @@ static int nl80211_start_radar_detection(struct sk_buff *skb, if (wdev->cac_started) return -EBUSY; - err = cfg80211_chandef_dfs_required(wdev->wiphy, &chandef, - wdev->iftype); + err = cfg80211_chandef_dfs_required(wiphy, &chandef, wdev->iftype); if (err < 0) return err; if (err == 0) return -EINVAL; - if (!cfg80211_chandef_dfs_usable(wdev->wiphy, &chandef)) + if (!cfg80211_chandef_dfs_usable(wiphy, &chandef)) return -EINVAL; + /* CAC start is offloaded to HW and can't be started manually */ + if (wiphy_ext_feature_isset(wiphy, NL80211_EXT_FEATURE_DFS_OFFLOAD)) + return -EOPNOTSUPP; + if (!rdev->ops->start_radar_detection) return -EOPNOTSUPP; -- GitLab From f94cb947c55bfa760e043d05ceb2c0d16eaef5d8 Mon Sep 17 00:00:00 2001 From: Carter Cooper Date: Fri, 13 Apr 2018 14:26:41 -0600 Subject: [PATCH 1114/1635] msm: kgsl: Add GMU memory to snapshot Dump GMU memory in the snapshot since it is vital to understanding GMU issues. Change-Id: I07784747343e65c5b0684af4b7951e16c2db33b2 Signed-off-by: Carter Cooper --- drivers/gpu/msm/adreno_a6xx_snapshot.c | 48 +++++++++++++++++++++++++- drivers/gpu/msm/kgsl_gmu.c | 2 -- drivers/gpu/msm/kgsl_hfi.h | 2 ++ drivers/gpu/msm/kgsl_snapshot.h | 15 +++++++- 4 files changed, 63 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/msm/adreno_a6xx_snapshot.c b/drivers/gpu/msm/adreno_a6xx_snapshot.c index afd1be551417..9dd9691055f0 100644 --- a/drivers/gpu/msm/adreno_a6xx_snapshot.c +++ b/drivers/gpu/msm/adreno_a6xx_snapshot.c @@ -19,6 +19,7 @@ #include "a6xx_reg.h" #include "adreno_a6xx.h" #include "kgsl_gmu.h" +#include "kgsl_hfi.h" #define A6XX_NUM_CTXTS 2 #define A6XX_NUM_AXI_ARB_BLOCKS 2 @@ -1447,6 +1448,37 @@ static void a6xx_snapshot_debugbus(struct kgsl_device *device, } } +struct gmu_mem_type_desc { + struct gmu_memdesc *memdesc; + uint32_t type; +}; + +static size_t a6xx_snapshot_gmu_mem(struct kgsl_device *device, + u8 *buf, size_t remain, void *priv) +{ + struct kgsl_snapshot_gmu *header = (struct kgsl_snapshot_gmu *)buf; + struct gmu_mem_type_desc *desc = priv; + unsigned int *data = (unsigned int *)(buf + sizeof(*header)); + + if (priv == NULL) + return 0; + + if (remain < desc->memdesc->size + sizeof(*header)) { + KGSL_CORE_ERR( + "snapshot: Not enough memory for the gmu section %d\n", + desc->type); + return 0; + } + + header->type = desc->type; + header->size = desc->memdesc->size; + + /* Just copy the ringbuffer, there are no active IBs */ + memcpy(data, desc->memdesc->hostptr, desc->memdesc->size); + + return desc->memdesc->size + sizeof(*header); +} + /* * a6xx_snapshot_gmu() - A6XX GMU snapshot function * @adreno_dev: Device being snapshotted @@ -1459,12 +1491,26 @@ void a6xx_snapshot_gmu(struct adreno_device *adreno_dev, struct kgsl_snapshot *snapshot) { struct kgsl_device *device = KGSL_DEVICE(adreno_dev); + struct gmu_device *gmu = &device->gmu; + struct gmu_mem_type_desc desc[] = { + {gmu->hfi_mem, SNAPSHOT_GMU_HFIMEM}, + {gmu->gmu_log, SNAPSHOT_GMU_LOG}, + {gmu->bw_mem, SNAPSHOT_GMU_BWMEM}, + {gmu->dump_mem, SNAPSHOT_GMU_DUMPMEM} }; struct adreno_gpudev *gpudev = ADRENO_GPU_DEVICE(adreno_dev); - unsigned int val; + unsigned int val, i; if (!kgsl_gmu_isenabled(device)) return; + for (i = 0; i < ARRAY_SIZE(desc); i++) { + if (desc[i].memdesc) + kgsl_snapshot_add_section(device, + KGSL_SNAPSHOT_SECTION_GMU, + snapshot, a6xx_snapshot_gmu_mem, + &desc[i]); + } + adreno_snapshot_registers(device, snapshot, a6xx_gmu_registers, ARRAY_SIZE(a6xx_gmu_registers) / 2); diff --git a/drivers/gpu/msm/kgsl_gmu.c b/drivers/gpu/msm/kgsl_gmu.c index ea10b84c93f1..4a5cc48903f0 100644 --- a/drivers/gpu/msm/kgsl_gmu.c +++ b/drivers/gpu/msm/kgsl_gmu.c @@ -68,8 +68,6 @@ struct gmu_iommu_context { struct iommu_domain *domain; }; -#define HFIMEM_SIZE (HFI_QUEUE_SIZE * (HFI_QUEUE_MAX + 1)) - #define DUMPMEM_SIZE SZ_16K #define DUMMY_SIZE SZ_4K diff --git a/drivers/gpu/msm/kgsl_hfi.h b/drivers/gpu/msm/kgsl_hfi.h index e358f5c63915..4845794ee07a 100644 --- a/drivers/gpu/msm/kgsl_hfi.h +++ b/drivers/gpu/msm/kgsl_hfi.h @@ -25,6 +25,8 @@ #define HFI_QUEUE_DISPATCH_CNT 1 #define HFI_QUEUE_MAX (HFI_QUEUE_DEFAULT_CNT + HFI_QUEUE_DISPATCH_CNT) +#define HFIMEM_SIZE (HFI_QUEUE_SIZE * (HFI_QUEUE_MAX + 1)) + #define HFI_CMD_ID 0 #define HFI_MSG_ID 1 #define HFI_DBG_ID 2 diff --git a/drivers/gpu/msm/kgsl_snapshot.h b/drivers/gpu/msm/kgsl_snapshot.h index 340a7db2f67a..c1ef28f7eddb 100644 --- a/drivers/gpu/msm/kgsl_snapshot.h +++ b/drivers/gpu/msm/kgsl_snapshot.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -59,6 +59,7 @@ struct kgsl_snapshot_section_header { #define KGSL_SNAPSHOT_SECTION_MEMLIST_V2 0x0E02 #define KGSL_SNAPSHOT_SECTION_SHADER 0x1201 #define KGSL_SNAPSHOT_SECTION_MVC 0x1501 +#define KGSL_SNAPSHOT_SECTION_GMU 0x1601 #define KGSL_SNAPSHOT_SECTION_END 0xFFFF @@ -183,6 +184,18 @@ struct kgsl_snapshot_ib_v2 { __u64 size; /* Size of the IB */ } __packed; +#define SNAPSHOT_GMU_OTHER 0 +#define SNAPSHOT_GMU_HFIMEM 1 +#define SNAPSHOT_GMU_LOG 2 +#define SNAPSHOT_GMU_BWMEM 3 +#define SNAPSHOT_GMU_DUMPMEM 4 +#define SNAPSHOT_GMU_DCACHE 5 + +/* Indirect buffer sub-section header */ +struct kgsl_snapshot_gmu { + int type; /* Type of data to dump */ + int size; /* Size in bytes to dump */ +} __packed; /* Register sub-section header */ struct kgsl_snapshot_regs { -- GitLab From 34d61ef0790987ce33f6d5a11d5e111d74e9bedb Mon Sep 17 00:00:00 2001 From: Konstantin Dorfman Date: Sun, 29 Apr 2018 10:00:14 +0300 Subject: [PATCH 1115/1635] defconfig: sm8150: enable spss_utils driver Enable Secure Processor Subsystem (SPSS) Utilities driver for perf_defconfig. This driver selects the firmware file for SPSS PIL. Change-Id: I789e18631631cd9cf5f67111c2b949edb4083823 Signed-off-by: Reut Zysman Signed-off-by: Konstantin Dorfman --- arch/arm64/configs/sm8150-perf_defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/configs/sm8150-perf_defconfig b/arch/arm64/configs/sm8150-perf_defconfig index 16eeebf21664..bd4239b26df3 100644 --- a/arch/arm64/configs/sm8150-perf_defconfig +++ b/arch/arm64/configs/sm8150-perf_defconfig @@ -509,6 +509,7 @@ CONFIG_QCOM_BUS_SCALING=y CONFIG_QCOM_BUS_CONFIG_RPMH=y CONFIG_QCOM_COMMAND_DB=y CONFIG_QCOM_EARLY_RANDOM=y +CONFIG_MSM_SPSS_UTILS=y CONFIG_MSM_SPCOM=y CONFIG_QTI_RPMH_API=y CONFIG_QSEE_IPC_IRQ_BRIDGE=y -- GitLab From 0534184a384380a943aeea27f5c57e6026342417 Mon Sep 17 00:00:00 2001 From: Maulik Shah Date: Sun, 29 Apr 2018 02:24:24 +0530 Subject: [PATCH 1116/1635] ARM: dts: msm: Add RPMH master stats node for sdm640 RPMH master stats supports to display various master stats information using sysfs. Add rpmh master stats node. Also change cx-off mode to cx-ret since sdm640 do not support cx-off modes. Update psci mode information accordingly. Change-Id: I167ed541c531986f2598faf73245d54d7110d3a6 Signed-off-by: Maulik Shah --- arch/arm64/boot/dts/qcom/sdm640-pm.dtsi | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sdm640-pm.dtsi b/arch/arm64/boot/dts/qcom/sdm640-pm.dtsi index 81a883a79d74..303f0634f01b 100644 --- a/arch/arm64/boot/dts/qcom/sdm640-pm.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm640-pm.dtsi @@ -46,10 +46,10 @@ qcom,is-reset; }; - qcom,pm-cluster-level@2 { /* Cx off */ + qcom,pm-cluster-level@2 { /* Cx Ret */ reg = <2>; - label = "cx-off"; - qcom,psci-mode = <0x224>; + label = "cx-ret"; + qcom,psci-mode = <0x124>; qcom,latency-us = <4562>; qcom,ss-power = <290>; qcom,energy-overhead = <6989829>; @@ -62,7 +62,7 @@ qcom,pm-cluster-level@3 { /* LLCC off, AOSS sleep */ reg = <3>; label = "llcc-off"; - qcom,psci-mode = <0xC24>; + qcom,psci-mode = <0xB24>; qcom,latency-us = <6562>; qcom,ss-power = <165>; qcom,energy-overhead = <7000029>; @@ -166,4 +166,9 @@ reg = <0xc300000 0x1000>, <0xc3f0004 0x4>; reg-names = "phys_addr_base", "offset_addr"; }; + + qcom,rpmh-master-stats@b221200 { + compatible = "qcom,rpmh-master-stats-v1"; + reg = <0xb221200 0x60>; + }; }; -- GitLab From 94c0308279ec7d550a675140e73262cf0732b70a Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 26 Apr 2018 17:28:00 +0200 Subject: [PATCH 1117/1635] Revert "pinctrl: intel: Initialize GPIO properly when used through irqchip" This reverts commit f5a26acf0162477af6ee4c11b4fb9cffe5d3e257 Mike writes: It seems that commit f5a26acf0162 ("pinctrl: intel: Initialize GPIO properly when used through irqchip") can cause problems on some Skylake systems with Sunrisepoint PCH-H. Namely on certain systems it may turn the backlight PWM pin from native mode to GPIO which makes the screen blank during boot. There is more information here: https://bugzilla.redhat.com/show_bug.cgi?id=1543769 The actual reason is that GPIO numbering used in BIOS is using "Windows" numbers meaning that they don't match the hardware 1:1 and because of this a wrong pin (backlight PWM) is picked and switched to GPIO mode. There is a proper fix for this but since it has quite many dependencies on commits that cannot be considered stable material, I suggest we revert commit f5a26acf0162 from stable trees 4.9, 4.14 and 4.15 to prevent the backlight issue. Reported-by: Mika Westerberg Fixes: f5a26acf0162 ("pinctrl: intel: Initialize GPIO properly when used through irqchip") Cc: Daniel Drake Cc: Chris Chiu Cc: Linus Walleij Signed-off-by: Greg Kroah-Hartman --- drivers/pinctrl/intel/pinctrl-intel.c | 23 ++++++++--------------- 1 file changed, 8 insertions(+), 15 deletions(-) diff --git a/drivers/pinctrl/intel/pinctrl-intel.c b/drivers/pinctrl/intel/pinctrl-intel.c index 72b4527d690f..71df0f70b61f 100644 --- a/drivers/pinctrl/intel/pinctrl-intel.c +++ b/drivers/pinctrl/intel/pinctrl-intel.c @@ -427,18 +427,6 @@ static void __intel_gpio_set_direction(void __iomem *padcfg0, bool input) writel(value, padcfg0); } -static void intel_gpio_set_gpio_mode(void __iomem *padcfg0) -{ - u32 value; - - /* Put the pad into GPIO mode */ - value = readl(padcfg0) & ~PADCFG0_PMODE_MASK; - /* Disable SCI/SMI/NMI generation */ - value &= ~(PADCFG0_GPIROUTIOXAPIC | PADCFG0_GPIROUTSCI); - value &= ~(PADCFG0_GPIROUTSMI | PADCFG0_GPIROUTNMI); - writel(value, padcfg0); -} - static int intel_gpio_request_enable(struct pinctrl_dev *pctldev, struct pinctrl_gpio_range *range, unsigned pin) @@ -446,6 +434,7 @@ static int intel_gpio_request_enable(struct pinctrl_dev *pctldev, struct intel_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); void __iomem *padcfg0; unsigned long flags; + u32 value; raw_spin_lock_irqsave(&pctrl->lock, flags); @@ -455,7 +444,13 @@ static int intel_gpio_request_enable(struct pinctrl_dev *pctldev, } padcfg0 = intel_get_padcfg(pctrl, pin, PADCFG0); - intel_gpio_set_gpio_mode(padcfg0); + /* Put the pad into GPIO mode */ + value = readl(padcfg0) & ~PADCFG0_PMODE_MASK; + /* Disable SCI/SMI/NMI generation */ + value &= ~(PADCFG0_GPIROUTIOXAPIC | PADCFG0_GPIROUTSCI); + value &= ~(PADCFG0_GPIROUTSMI | PADCFG0_GPIROUTNMI); + writel(value, padcfg0); + /* Disable TX buffer and enable RX (this will be input) */ __intel_gpio_set_direction(padcfg0, true); @@ -940,8 +935,6 @@ static int intel_gpio_irq_type(struct irq_data *d, unsigned type) raw_spin_lock_irqsave(&pctrl->lock, flags); - intel_gpio_set_gpio_mode(reg); - value = readl(reg); value &= ~(PADCFG0_RXEVCFG_MASK | PADCFG0_RXINV); -- GitLab From 00c54b3544112fa2e19a6c19fb1fa9cc4802b0d4 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Fri, 23 Feb 2018 12:44:37 +0100 Subject: [PATCH 1118/1635] drm: bridge: dw-hdmi: Fix overflow workaround for Amlogic Meson GX SoCs commit 9c305eb442f3b371fc722ade827bbf673514123e upstream. The Amlogic Meson GX SoCs, embedded the v2.01a controller, has been also identified needing this workaround. This patch adds the corresponding version to enable a single iteration for this specific version. Fixes: be41fc55f1aa ("drm: bridge: dw-hdmi: Handle overflow workaround based on device version") Acked-by: Archit Taneja [narmstrong: s/identifies/identified and rebased against Jernej's change] Signed-off-by: Neil Armstrong Link: https://patchwork.freedesktop.org/patch/msgid/1519386277-25902-1-git-send-email-narmstrong@baylibre.com [narmstrong: v4.14 to v4.16 backport] Cc: # 4.14.x Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c index bf14214fa464..4db31b89507c 100644 --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c @@ -1634,6 +1634,8 @@ static void dw_hdmi_clear_overflow(struct dw_hdmi *hdmi) * (and possibly on the platform). So far only i.MX6Q (v1.30a) and * i.MX6DL (v1.31a) have been identified as needing the workaround, with * 4 and 1 iterations respectively. + * The Amlogic Meson GX SoCs (v2.01a) have been identified as needing + * the workaround with a single iteration. */ switch (hdmi->version) { @@ -1641,6 +1643,7 @@ static void dw_hdmi_clear_overflow(struct dw_hdmi *hdmi) count = 4; break; case 0x131a: + case 0x201a: count = 1; break; default: -- GitLab From 3b38734ed9fe7e12fa71aa9a99e31e92a7d74f53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Jab=C5=82o=C5=84ski?= Date: Thu, 8 Mar 2018 14:52:05 -0800 Subject: [PATCH 1119/1635] i40e: Fix attach VF to VM issue MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 028daf80117376b22909becd9720daaefdfceff4 upstream. Fix for "Resource temporarily unavailable" problem when virsh is trying to attach a device to VM. When the VF driver is loaded on host and virsh is trying to attach it to the VM and set a MAC address, it ends with a race condition between i40e_reset_vf and i40e_ndo_set_vf_mac functions. The bug is fixed by adding polling in i40e_ndo_set_vf_mac function For when the VF is in Reset mode. Signed-off-by: Paweł Jabłoński Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher Cc: Sinan Kaya Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c index e368b0237a1b..4a85a24ced1c 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c +++ b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c @@ -2781,6 +2781,7 @@ int i40e_ndo_set_vf_mac(struct net_device *netdev, int vf_id, u8 *mac) int ret = 0; struct hlist_node *h; int bkt; + u8 i; /* validate the request */ if (vf_id >= pf->num_alloc_vfs) { @@ -2792,6 +2793,16 @@ int i40e_ndo_set_vf_mac(struct net_device *netdev, int vf_id, u8 *mac) vf = &(pf->vf[vf_id]); vsi = pf->vsi[vf->lan_vsi_idx]; + + /* When the VF is resetting wait until it is done. + * It can take up to 200 milliseconds, + * but wait for up to 300 milliseconds to be safe. + */ + for (i = 0; i < 15; i++) { + if (test_bit(I40E_VF_STATE_INIT, &vf->vf_states)) + break; + msleep(20); + } if (!test_bit(I40E_VF_STATE_INIT, &vf->vf_states)) { dev_err(&pf->pdev->dev, "VF %d still in reset. Try again.\n", vf_id); -- GitLab From ac5881b7814d53d9834b25f3845d6f18a0f027ba Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Mon, 5 Mar 2018 13:34:49 +0200 Subject: [PATCH 1120/1635] tpm: cmd_ready command can be issued only after granting locality commit 888d867df4417deffc33927e6fc2c6925736fe92 upstream. The correct sequence is to first request locality and only after that perform cmd_ready handshake, otherwise the hardware will drop the subsequent message as from the device point of view the cmd_ready handshake wasn't performed. Symmetrically locality has to be relinquished only after going idle handshake has completed, this requires that go_idle has to poll for the completion and as well locality relinquish has to poll for completion so it is not overridden in back to back commands flow. Two wrapper functions are added (request_locality relinquish_locality) to simplify the error handling. The issue is only visible on devices that support multiple localities. Fixes: 877c57d0d0ca ("tpm_crb: request and relinquish locality 0") Signed-off-by: Tomas Winkler Reviewed-by: Jarkko Sakkinen Tested-by: Jarkko Sakkinen Signed-off-by: Jarkko Sakkinen Signed-off-by: Greg Kroah-Hartman --- drivers/char/tpm/tpm-interface.c | 54 ++++++++++++---- drivers/char/tpm/tpm_crb.c | 108 +++++++++++++++++++++---------- drivers/char/tpm/tpm_tis_core.c | 4 +- include/linux/tpm.h | 2 +- 4 files changed, 120 insertions(+), 48 deletions(-) diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c index 1d01a8f77db1..48a30eb1e844 100644 --- a/drivers/char/tpm/tpm-interface.c +++ b/drivers/char/tpm/tpm-interface.c @@ -369,6 +369,36 @@ static int tpm_validate_command(struct tpm_chip *chip, return -EINVAL; } +static int tpm_request_locality(struct tpm_chip *chip) +{ + int rc; + + if (!chip->ops->request_locality) + return 0; + + rc = chip->ops->request_locality(chip, 0); + if (rc < 0) + return rc; + + chip->locality = rc; + + return 0; +} + +static void tpm_relinquish_locality(struct tpm_chip *chip) +{ + int rc; + + if (!chip->ops->relinquish_locality) + return; + + rc = chip->ops->relinquish_locality(chip, chip->locality); + if (rc) + dev_err(&chip->dev, "%s: : error %d\n", __func__, rc); + + chip->locality = -1; +} + /** * tmp_transmit - Internal kernel interface to transmit TPM commands. * @@ -422,8 +452,6 @@ ssize_t tpm_transmit(struct tpm_chip *chip, struct tpm_space *space, if (!(flags & TPM_TRANSMIT_UNLOCKED)) mutex_lock(&chip->tpm_mutex); - if (chip->dev.parent) - pm_runtime_get_sync(chip->dev.parent); if (chip->ops->clk_enable != NULL) chip->ops->clk_enable(chip, true); @@ -431,14 +459,15 @@ ssize_t tpm_transmit(struct tpm_chip *chip, struct tpm_space *space, /* Store the decision as chip->locality will be changed. */ need_locality = chip->locality == -1; - if (!(flags & TPM_TRANSMIT_RAW) && - need_locality && chip->ops->request_locality) { - rc = chip->ops->request_locality(chip, 0); + if (!(flags & TPM_TRANSMIT_RAW) && need_locality) { + rc = tpm_request_locality(chip); if (rc < 0) goto out_no_locality; - chip->locality = rc; } + if (chip->dev.parent) + pm_runtime_get_sync(chip->dev.parent); + rc = tpm2_prepare_space(chip, space, ordinal, buf); if (rc) goto out; @@ -499,17 +528,16 @@ ssize_t tpm_transmit(struct tpm_chip *chip, struct tpm_space *space, rc = tpm2_commit_space(chip, space, ordinal, buf, &len); out: - if (need_locality && chip->ops->relinquish_locality) { - chip->ops->relinquish_locality(chip, chip->locality); - chip->locality = -1; - } + if (chip->dev.parent) + pm_runtime_put_sync(chip->dev.parent); + + if (need_locality) + tpm_relinquish_locality(chip); + out_no_locality: if (chip->ops->clk_enable != NULL) chip->ops->clk_enable(chip, false); - if (chip->dev.parent) - pm_runtime_put_sync(chip->dev.parent); - if (!(flags & TPM_TRANSMIT_UNLOCKED)) mutex_unlock(&chip->tpm_mutex); return rc ? rc : len; diff --git a/drivers/char/tpm/tpm_crb.c b/drivers/char/tpm/tpm_crb.c index 8f0a98dea327..bb756ad7897e 100644 --- a/drivers/char/tpm/tpm_crb.c +++ b/drivers/char/tpm/tpm_crb.c @@ -117,6 +117,25 @@ struct tpm2_crb_smc { u32 smc_func_id; }; +static bool crb_wait_for_reg_32(u32 __iomem *reg, u32 mask, u32 value, + unsigned long timeout) +{ + ktime_t start; + ktime_t stop; + + start = ktime_get(); + stop = ktime_add(start, ms_to_ktime(timeout)); + + do { + if ((ioread32(reg) & mask) == value) + return true; + + usleep_range(50, 100); + } while (ktime_before(ktime_get(), stop)); + + return ((ioread32(reg) & mask) == value); +} + /** * crb_go_idle - request tpm crb device to go the idle state * @@ -132,37 +151,24 @@ struct tpm2_crb_smc { * * Return: 0 always */ -static int __maybe_unused crb_go_idle(struct device *dev, struct crb_priv *priv) +static int crb_go_idle(struct device *dev, struct crb_priv *priv) { if ((priv->flags & CRB_FL_ACPI_START) || (priv->flags & CRB_FL_CRB_SMC_START)) return 0; iowrite32(CRB_CTRL_REQ_GO_IDLE, &priv->regs_t->ctrl_req); - /* we don't really care when this settles */ + if (!crb_wait_for_reg_32(&priv->regs_t->ctrl_req, + CRB_CTRL_REQ_GO_IDLE/* mask */, + 0, /* value */ + TPM2_TIMEOUT_C)) { + dev_warn(dev, "goIdle timed out\n"); + return -ETIME; + } return 0; } -static bool crb_wait_for_reg_32(u32 __iomem *reg, u32 mask, u32 value, - unsigned long timeout) -{ - ktime_t start; - ktime_t stop; - - start = ktime_get(); - stop = ktime_add(start, ms_to_ktime(timeout)); - - do { - if ((ioread32(reg) & mask) == value) - return true; - - usleep_range(50, 100); - } while (ktime_before(ktime_get(), stop)); - - return false; -} - /** * crb_cmd_ready - request tpm crb device to enter ready state * @@ -177,8 +183,7 @@ static bool crb_wait_for_reg_32(u32 __iomem *reg, u32 mask, u32 value, * * Return: 0 on success -ETIME on timeout; */ -static int __maybe_unused crb_cmd_ready(struct device *dev, - struct crb_priv *priv) +static int crb_cmd_ready(struct device *dev, struct crb_priv *priv) { if ((priv->flags & CRB_FL_ACPI_START) || (priv->flags & CRB_FL_CRB_SMC_START)) @@ -196,11 +201,11 @@ static int __maybe_unused crb_cmd_ready(struct device *dev, return 0; } -static int crb_request_locality(struct tpm_chip *chip, int loc) +static int __crb_request_locality(struct device *dev, + struct crb_priv *priv, int loc) { - struct crb_priv *priv = dev_get_drvdata(&chip->dev); u32 value = CRB_LOC_STATE_LOC_ASSIGNED | - CRB_LOC_STATE_TPM_REG_VALID_STS; + CRB_LOC_STATE_TPM_REG_VALID_STS; if (!priv->regs_h) return 0; @@ -208,21 +213,45 @@ static int crb_request_locality(struct tpm_chip *chip, int loc) iowrite32(CRB_LOC_CTRL_REQUEST_ACCESS, &priv->regs_h->loc_ctrl); if (!crb_wait_for_reg_32(&priv->regs_h->loc_state, value, value, TPM2_TIMEOUT_C)) { - dev_warn(&chip->dev, "TPM_LOC_STATE_x.requestAccess timed out\n"); + dev_warn(dev, "TPM_LOC_STATE_x.requestAccess timed out\n"); return -ETIME; } return 0; } -static void crb_relinquish_locality(struct tpm_chip *chip, int loc) +static int crb_request_locality(struct tpm_chip *chip, int loc) { struct crb_priv *priv = dev_get_drvdata(&chip->dev); + return __crb_request_locality(&chip->dev, priv, loc); +} + +static int __crb_relinquish_locality(struct device *dev, + struct crb_priv *priv, int loc) +{ + u32 mask = CRB_LOC_STATE_LOC_ASSIGNED | + CRB_LOC_STATE_TPM_REG_VALID_STS; + u32 value = CRB_LOC_STATE_TPM_REG_VALID_STS; + if (!priv->regs_h) - return; + return 0; iowrite32(CRB_LOC_CTRL_RELINQUISH, &priv->regs_h->loc_ctrl); + if (!crb_wait_for_reg_32(&priv->regs_h->loc_state, mask, value, + TPM2_TIMEOUT_C)) { + dev_warn(dev, "TPM_LOC_STATE_x.requestAccess timed out\n"); + return -ETIME; + } + + return 0; +} + +static int crb_relinquish_locality(struct tpm_chip *chip, int loc) +{ + struct crb_priv *priv = dev_get_drvdata(&chip->dev); + + return __crb_relinquish_locality(&chip->dev, priv, loc); } static u8 crb_status(struct tpm_chip *chip) @@ -466,6 +495,10 @@ static int crb_map_io(struct acpi_device *device, struct crb_priv *priv, dev_warn(dev, FW_BUG "Bad ACPI memory layout"); } + ret = __crb_request_locality(dev, priv, 0); + if (ret) + return ret; + priv->regs_t = crb_map_res(dev, priv, &io_res, buf->control_address, sizeof(struct crb_regs_tail)); if (IS_ERR(priv->regs_t)) @@ -522,6 +555,8 @@ static int crb_map_io(struct acpi_device *device, struct crb_priv *priv, crb_go_idle(dev, priv); + __crb_relinquish_locality(dev, priv, 0); + return ret; } @@ -589,10 +624,14 @@ static int crb_acpi_add(struct acpi_device *device) chip->acpi_dev_handle = device->handle; chip->flags = TPM_CHIP_FLAG_TPM2; - rc = crb_cmd_ready(dev, priv); + rc = __crb_request_locality(dev, priv, 0); if (rc) return rc; + rc = crb_cmd_ready(dev, priv); + if (rc) + goto out; + pm_runtime_get_noresume(dev); pm_runtime_set_active(dev); pm_runtime_enable(dev); @@ -602,12 +641,15 @@ static int crb_acpi_add(struct acpi_device *device) crb_go_idle(dev, priv); pm_runtime_put_noidle(dev); pm_runtime_disable(dev); - return rc; + goto out; } - pm_runtime_put(dev); + pm_runtime_put_sync(dev); - return 0; +out: + __crb_relinquish_locality(dev, priv, 0); + + return rc; } static int crb_acpi_remove(struct acpi_device *device) diff --git a/drivers/char/tpm/tpm_tis_core.c b/drivers/char/tpm/tpm_tis_core.c index a21e31c2b952..58123df6b5f6 100644 --- a/drivers/char/tpm/tpm_tis_core.c +++ b/drivers/char/tpm/tpm_tis_core.c @@ -77,11 +77,13 @@ static bool check_locality(struct tpm_chip *chip, int l) return false; } -static void release_locality(struct tpm_chip *chip, int l) +static int release_locality(struct tpm_chip *chip, int l) { struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev); tpm_tis_write8(priv, TPM_ACCESS(l), TPM_ACCESS_ACTIVE_LOCALITY); + + return 0; } static int request_locality(struct tpm_chip *chip, int l) diff --git a/include/linux/tpm.h b/include/linux/tpm.h index 881312d85574..2a6c3d96b31f 100644 --- a/include/linux/tpm.h +++ b/include/linux/tpm.h @@ -49,7 +49,7 @@ struct tpm_class_ops { bool (*update_timeouts)(struct tpm_chip *chip, unsigned long *timeout_cap); int (*request_locality)(struct tpm_chip *chip, int loc); - void (*relinquish_locality)(struct tpm_chip *chip, int loc); + int (*relinquish_locality)(struct tpm_chip *chip, int loc); void (*clk_enable)(struct tpm_chip *chip, bool value); }; -- GitLab From f6891ec29c597405c0223ac20bdaf64f65acba3a Mon Sep 17 00:00:00 2001 From: "Winkler, Tomas" Date: Mon, 5 Mar 2018 14:48:25 +0200 Subject: [PATCH 1121/1635] tpm: tpm-interface: fix tpm_transmit/_cmd kdoc commit 65520d46a4adbf7f23bbb6d9b1773513f7bc7821 upstream. Fix tmp_ -> tpm_ typo and add reference to 'space' parameter in kdoc for tpm_transmit and tpm_transmit_cmd functions. Signed-off-by: Tomas Winkler Reviewed-by: Jarkko Sakkinen Signed-off-by: Jarkko Sakkinen Signed-off-by: Greg Kroah-Hartman --- drivers/char/tpm/tpm-interface.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c index 48a30eb1e844..ea2d6a25ae46 100644 --- a/drivers/char/tpm/tpm-interface.c +++ b/drivers/char/tpm/tpm-interface.c @@ -400,9 +400,10 @@ static void tpm_relinquish_locality(struct tpm_chip *chip) } /** - * tmp_transmit - Internal kernel interface to transmit TPM commands. + * tpm_transmit - Internal kernel interface to transmit TPM commands. * * @chip: TPM chip to use + * @space: tpm space * @buf: TPM command buffer * @bufsiz: length of the TPM command buffer * @flags: tpm transmit flags - bitmap @@ -544,10 +545,11 @@ ssize_t tpm_transmit(struct tpm_chip *chip, struct tpm_space *space, } /** - * tmp_transmit_cmd - send a tpm command to the device + * tpm_transmit_cmd - send a tpm command to the device * The function extracts tpm out header return code * * @chip: TPM chip to use + * @space: tpm space * @buf: TPM command buffer * @bufsiz: length of the buffer * @min_rsp_body_length: minimum expected length of response body -- GitLab From 781eeb7af2bdd4e7d0450f7b7cd5c39a04c7a841 Mon Sep 17 00:00:00 2001 From: James Bottomley Date: Wed, 21 Mar 2018 11:43:48 -0700 Subject: [PATCH 1122/1635] tpm: add retry logic MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit e2fb992d82c626c43ed0566e07c410e56a087af3 upstream. TPM2 can return TPM2_RC_RETRY to any command and when it does we get unexpected failures inside the kernel that surprise users (this is mostly observed in the trusted key handling code). The UEFI 2.6 spec has advice on how to handle this: The firmware SHALL not return TPM2_RC_RETRY prior to the completion of the call to ExitBootServices(). Implementer’s Note: the implementation of this function should check the return value in the TPM response and, if it is TPM2_RC_RETRY, resend the command. The implementation may abort if a sufficient number of retries has been done. So we follow that advice in our tpm_transmit() code using TPM2_DURATION_SHORT as the initial wait duration and TPM2_DURATION_LONG as the maximum wait time. This should fix all the in-kernel use cases and also means that user space TSS implementations don't have to have their own retry handling. Signed-off-by: James Bottomley Cc: stable@vger.kernel.org Reviewed-by: Jarkko Sakkinen Tested-by: Jarkko Sakkinen Signed-off-by: Jarkko Sakkinen Signed-off-by: Greg Kroah-Hartman --- drivers/char/tpm/tpm-interface.c | 75 +++++++++++++++++++++++++------- drivers/char/tpm/tpm.h | 1 + 2 files changed, 61 insertions(+), 15 deletions(-) diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c index ea2d6a25ae46..dba5259def60 100644 --- a/drivers/char/tpm/tpm-interface.c +++ b/drivers/char/tpm/tpm-interface.c @@ -399,21 +399,10 @@ static void tpm_relinquish_locality(struct tpm_chip *chip) chip->locality = -1; } -/** - * tpm_transmit - Internal kernel interface to transmit TPM commands. - * - * @chip: TPM chip to use - * @space: tpm space - * @buf: TPM command buffer - * @bufsiz: length of the TPM command buffer - * @flags: tpm transmit flags - bitmap - * - * Return: - * 0 when the operation is successful. - * A negative number for system errors (errno). - */ -ssize_t tpm_transmit(struct tpm_chip *chip, struct tpm_space *space, - u8 *buf, size_t bufsiz, unsigned int flags) +static ssize_t tpm_try_transmit(struct tpm_chip *chip, + struct tpm_space *space, + u8 *buf, size_t bufsiz, + unsigned int flags) { struct tpm_output_header *header = (void *)buf; int rc; @@ -544,6 +533,62 @@ ssize_t tpm_transmit(struct tpm_chip *chip, struct tpm_space *space, return rc ? rc : len; } +/** + * tpm_transmit - Internal kernel interface to transmit TPM commands. + * + * @chip: TPM chip to use + * @space: tpm space + * @buf: TPM command buffer + * @bufsiz: length of the TPM command buffer + * @flags: tpm transmit flags - bitmap + * + * A wrapper around tpm_try_transmit that handles TPM2_RC_RETRY + * returns from the TPM and retransmits the command after a delay up + * to a maximum wait of TPM2_DURATION_LONG. + * + * Note: TPM1 never returns TPM2_RC_RETRY so the retry logic is TPM2 + * only + * + * Return: + * the length of the return when the operation is successful. + * A negative number for system errors (errno). + */ +ssize_t tpm_transmit(struct tpm_chip *chip, struct tpm_space *space, + u8 *buf, size_t bufsiz, unsigned int flags) +{ + struct tpm_output_header *header = (struct tpm_output_header *)buf; + /* space for header and handles */ + u8 save[TPM_HEADER_SIZE + 3*sizeof(u32)]; + unsigned int delay_msec = TPM2_DURATION_SHORT; + u32 rc = 0; + ssize_t ret; + const size_t save_size = min(space ? sizeof(save) : TPM_HEADER_SIZE, + bufsiz); + + /* + * Subtlety here: if we have a space, the handles will be + * transformed, so when we restore the header we also have to + * restore the handles. + */ + memcpy(save, buf, save_size); + + for (;;) { + ret = tpm_try_transmit(chip, space, buf, bufsiz, flags); + if (ret < 0) + break; + rc = be32_to_cpu(header->return_code); + if (rc != TPM2_RC_RETRY) + break; + delay_msec *= 2; + if (delay_msec > TPM2_DURATION_LONG) { + dev_err(&chip->dev, "TPM is in retry loop\n"); + break; + } + tpm_msleep(delay_msec); + memcpy(buf, save, save_size); + } + return ret; +} /** * tpm_transmit_cmd - send a tpm command to the device * The function extracts tpm out header return code diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h index 0b5b499f726a..b83b30a3eea5 100644 --- a/drivers/char/tpm/tpm.h +++ b/drivers/char/tpm/tpm.h @@ -106,6 +106,7 @@ enum tpm2_return_codes { TPM2_RC_COMMAND_CODE = 0x0143, TPM2_RC_TESTING = 0x090A, /* RC_WARN */ TPM2_RC_REFERENCE_H0 = 0x0910, + TPM2_RC_RETRY = 0x0922, }; enum tpm2_algorithms { -- GitLab From 5f50186dd8106ee83e767225278ebafe8484b4a1 Mon Sep 17 00:00:00 2001 From: Karthikeyan Periyasamy Date: Tue, 27 Mar 2018 11:25:29 +0300 Subject: [PATCH 1123/1635] Revert "ath10k: send (re)assoc peer command when NSS changed" commit 55cc11da69895a680940c1733caabc37be685f5e upstream. This reverts commit 55884c045d31a29cf69db8332d1064a1b61dd159. When Ath10k is in AP mode and an unassociated STA sends a VHT action frame (Operating Mode Notification for the NSS change) periodically to AP this causes ath10k to call ath10k_station_assoc() which sends WMI_PEER_ASSOC_CMDID during NSS update. Over the time (with a certain client it can happen within 15 mins when there are over 500 of these VHT action frames) continuous calls of WMI_PEER_ASSOC_CMDID cause firmware to assert due to resource exhaust. To my knowledge setting WMI_PEER_NSS peer param itself enough to handle NSS updates and no need to call ath10k_station_assoc(). So revert the original commit from 2014 as it's unclear why the change was really needed. Now the firmware assert doesn't happen anymore. Issue observed in QCA9984 platform with firmware version:10.4-3.5.3-00053. This Change tested in QCA9984 with firmware version: 10.4-3.5.3-00053 and QCA988x platform with firmware version: 10.2.4-1.0-00036. Firmware Assert log: ath10k_pci 0002:01:00.0: firmware crashed! (guid e61f1274-9acd-4c5b-bcca-e032ea6e723c) ath10k_pci 0002:01:00.0: qca9984/qca9994 hw1.0 target 0x01000000 chip_id 0x00000000 sub 168c:cafe ath10k_pci 0002:01:00.0: kconfig debug 1 debugfs 1 tracing 0 dfs 1 testmode 1 ath10k_pci 0002:01:00.0: firmware ver 10.4-3.5.3-00053 api 5 features no-p2p,mfp,peer-flow-ctrl,btcoex-param,allows-mesh-bcast crc32 4c56a386 ath10k_pci 0002:01:00.0: board_file api 2 bmi_id 0:4 crc32 c2271344 ath10k_pci 0002:01:00.0: htt-ver 2.2 wmi-op 6 htt-op 4 cal otp max-sta 512 raw 0 hwcrypto 1 ath10k_pci 0002:01:00.0: firmware register dump: ath10k_pci 0002:01:00.0: [00]: 0x0000000A 0x000015B3 0x00981E5F 0x00975B31 ath10k_pci 0002:01:00.0: [04]: 0x00981E5F 0x00060530 0x00000011 0x00446C60 ath10k_pci 0002:01:00.0: [08]: 0x0042F1FC 0x00458080 0x00000017 0x00000000 ath10k_pci 0002:01:00.0: [12]: 0x00000009 0x00000000 0x00973ABC 0x00973AD2 ath10k_pci 0002:01:00.0: [16]: 0x00973AB0 0x00960E62 0x009606CA 0x00000000 ath10k_pci 0002:01:00.0: [20]: 0x40981E5F 0x004066DC 0x00400000 0x00981E34 ath10k_pci 0002:01:00.0: [24]: 0x80983B48 0x0040673C 0x000000C0 0xC0981E5F ath10k_pci 0002:01:00.0: [28]: 0x80993DEB 0x0040676C 0x00431AB8 0x0045D0C4 ath10k_pci 0002:01:00.0: [32]: 0x80993E5C 0x004067AC 0x004303C0 0x0045D0C4 ath10k_pci 0002:01:00.0: [36]: 0x80994AAB 0x004067DC 0x00000000 0x0045D0C4 ath10k_pci 0002:01:00.0: [40]: 0x809971A0 0x0040681C 0x004303C0 0x00441B00 ath10k_pci 0002:01:00.0: [44]: 0x80991904 0x0040688C 0x004303C0 0x0045D0C4 ath10k_pci 0002:01:00.0: [48]: 0x80963AD3 0x00406A7C 0x004303C0 0x009918FC ath10k_pci 0002:01:00.0: [52]: 0x80960E80 0x00406A9C 0x0000001F 0x00400000 ath10k_pci 0002:01:00.0: [56]: 0x80960E51 0x00406ACC 0x00400000 0x00000000 ath10k_pci 0002:01:00.0: Copy Engine register dump: ath10k_pci 0002:01:00.0: index: addr: sr_wr_idx: sr_r_idx: dst_wr_idx: dst_r_idx: ath10k_pci 0002:01:00.0: [00]: 0x0004a000 15 15 3 3 ath10k_pci 0002:01:00.0: [01]: 0x0004a400 17 17 212 213 ath10k_pci 0002:01:00.0: [02]: 0x0004a800 21 21 20 21 ath10k_pci 0002:01:00.0: [03]: 0x0004ac00 25 25 27 25 ath10k_pci 0002:01:00.0: [04]: 0x0004b000 515 515 144 104 ath10k_pci 0002:01:00.0: [05]: 0x0004b400 28 28 155 156 ath10k_pci 0002:01:00.0: [06]: 0x0004b800 12 12 12 12 ath10k_pci 0002:01:00.0: [07]: 0x0004bc00 1 1 1 1 ath10k_pci 0002:01:00.0: [08]: 0x0004c000 0 0 127 0 ath10k_pci 0002:01:00.0: [09]: 0x0004c400 1 1 1 1 ath10k_pci 0002:01:00.0: [10]: 0x0004c800 0 0 0 0 ath10k_pci 0002:01:00.0: [11]: 0x0004cc00 0 0 0 0 ath10k_pci 0002:01:00.0: CE[1] write_index 212 sw_index 213 hw_index 0 nentries_mask 0x000001ff ath10k_pci 0002:01:00.0: CE[2] write_index 20 sw_index 21 hw_index 0 nentries_mask 0x0000007f ath10k_pci 0002:01:00.0: CE[5] write_index 155 sw_index 156 hw_index 0 nentries_mask 0x000001ff ath10k_pci 0002:01:00.0: DMA addr: nbytes: meta data: byte swap: gather: ath10k_pci 0002:01:00.0: [455]: 0x580c0042 0 0 0 0 ath10k_pci 0002:01:00.0: [456]: 0x594a0010 0 0 0 1 ath10k_pci 0002:01:00.0: [457]: 0x580c0042 0 0 0 0 ath10k_pci 0002:01:00.0: [458]: 0x594a0038 0 0 0 1 ath10k_pci 0002:01:00.0: [459]: 0x580c0a42 0 0 0 0 ath10k_pci 0002:01:00.0: [460]: 0x594a0060 0 0 0 1 ath10k_pci 0002:01:00.0: [461]: 0x580c0c42 0 0 0 0 ath10k_pci 0002:01:00.0: [462]: 0x594a0010 0 0 0 1 ath10k_pci 0002:01:00.0: [463]: 0x580c0c42 0 0 0 0 ath10k_pci 0002:01:00.0: [464]: 0x594a0038 0 0 0 1 ath10k_pci 0002:01:00.0: [465]: 0x580c0a42 0 0 0 0 ath10k_pci 0002:01:00.0: [466]: 0x594a0060 0 0 0 1 ath10k_pci 0002:01:00.0: [467]: 0x580c0042 0 0 0 0 ath10k_pci 0002:01:00.0: [468]: 0x594a0010 0 0 0 1 ath10k_pci 0002:01:00.0: [469]: 0x580c1c42 0 0 0 0 ath10k_pci 0002:01:00.0: [470]: 0x594a0010 0 0 0 1 ath10k_pci 0002:01:00.0: [471]: 0x580c1c42 0 0 0 0 ath10k_pci 0002:01:00.0: [472]: 0x594a0010 0 0 0 1 ath10k_pci 0002:01:00.0: [473]: 0x580c1c42 0 0 0 0 ath10k_pci 0002:01:00.0: [474]: 0x594a0010 0 0 0 1 ath10k_pci 0002:01:00.0: [475]: 0x580c0642 0 0 0 0 ath10k_pci 0002:01:00.0: [476]: 0x594a0038 0 0 0 1 ath10k_pci 0002:01:00.0: [477]: 0x580c0842 0 0 0 0 ath10k_pci 0002:01:00.0: [478]: 0x594a0060 0 0 0 1 ath10k_pci 0002:01:00.0: [479]: 0x580c0042 0 0 0 0 ath10k_pci 0002:01:00.0: [480]: 0x594a0010 0 0 0 1 ath10k_pci 0002:01:00.0: [481]: 0x580c0042 0 0 0 0 ath10k_pci 0002:01:00.0: [482]: 0x594a0038 0 0 0 1 ath10k_pci 0002:01:00.0: [483]: 0x580c0842 0 0 0 0 ath10k_pci 0002:01:00.0: [484]: 0x594a0060 0 0 0 1 ath10k_pci 0002:01:00.0: [485]: 0x580c0642 0 0 0 0 ath10k_pci 0002:01:00.0: [486]: 0x594a0010 0 0 0 1 ath10k_pci 0002:01:00.0: [487]: 0x580c0642 0 0 0 0 ath10k_pci 0002:01:00.0: [488]: 0x594a0038 0 0 0 1 ath10k_pci 0002:01:00.0: [489]: 0x580c0842 0 0 0 0 ath10k_pci 0002:01:00.0: [490]: 0x594a0060 0 0 0 1 ath10k_pci 0002:01:00.0: [491]: 0x580c0042 0 0 0 0 ath10k_pci 0002:01:00.0: [492]: 0x58174040 0 1 0 0 ath10k_pci 0002:01:00.0: [493]: 0x5a946040 0 1 0 0 ath10k_pci 0002:01:00.0: [494]: 0x59909040 0 1 0 0 ath10k_pci 0002:01:00.0: [495]: 0x5ae5a040 0 1 0 0 ath10k_pci 0002:01:00.0: [496]: 0x58096040 0 1 0 0 ath10k_pci 0002:01:00.0: [497]: 0x594a0010 0 0 0 1 ath10k_pci 0002:01:00.0: [498]: 0x580c0642 0 0 0 0 ath10k_pci 0002:01:00.0: [499]: 0x5c1e0040 0 1 0 0 ath10k_pci 0002:01:00.0: [500]: 0x58153040 0 1 0 0 ath10k_pci 0002:01:00.0: [501]: 0x58129040 0 1 0 0 ath10k_pci 0002:01:00.0: [502]: 0x5952f040 0 1 0 0 ath10k_pci 0002:01:00.0: [503]: 0x59535040 0 1 0 0 ath10k_pci 0002:01:00.0: [504]: 0x594a0010 0 0 0 1 ath10k_pci 0002:01:00.0: [505]: 0x580c0042 0 0 0 0 ath10k_pci 0002:01:00.0: [506]: 0x594a0010 0 0 0 1 ath10k_pci 0002:01:00.0: [507]: 0x580c0042 0 0 0 0 ath10k_pci 0002:01:00.0: [508]: 0x594a0010 0 0 0 1 ath10k_pci 0002:01:00.0: [509]: 0x580c0042 0 0 0 0 ath10k_pci 0002:01:00.0: [510]: 0x594a0010 0 0 0 1 ath10k_pci 0002:01:00.0: [511]: 0x580c0042 0 0 0 0 ath10k_pci 0002:01:00.0: [512]: 0x5adcc040 0 1 0 0 ath10k_pci 0002:01:00.0: [513]: 0x5cf3d040 0 1 0 0 ath10k_pci 0002:01:00.0: [514]: 0x5c1e9040 64 1 0 0 ath10k_pci 0002:01:00.0: [515]: 0x00000000 0 0 0 0 Signed-off-by: Karthikeyan Periyasamy Signed-off-by: Kalle Valo Cc: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/ath/ath10k/mac.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 252c2206cbb5..c1772215702a 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -5955,9 +5955,8 @@ static void ath10k_sta_rc_update_wk(struct work_struct *wk) sta->addr, smps, err); } - if (changed & IEEE80211_RC_SUPP_RATES_CHANGED || - changed & IEEE80211_RC_NSS_CHANGED) { - ath10k_dbg(ar, ATH10K_DBG_MAC, "mac update sta %pM supp rates/nss\n", + if (changed & IEEE80211_RC_SUPP_RATES_CHANGED) { + ath10k_dbg(ar, ATH10K_DBG_MAC, "mac update sta %pM supp rates\n", sta->addr); err = ath10k_station_assoc(ar, arvif->vif, sta, true); -- GitLab From e0286ea0846c7fb6ebae03f305f6895f7e64b836 Mon Sep 17 00:00:00 2001 From: Xin Long Date: Sun, 22 Apr 2018 19:11:50 +0800 Subject: [PATCH 1124/1635] bonding: do not set slave_dev npinfo before slave_enable_netpoll in bond_enslave [ Upstream commit ddea788c63094f7c483783265563dd5b50052e28 ] After Commit 8a8efa22f51b ("bonding: sync netpoll code with bridge"), it would set slave_dev npinfo in slave_enable_netpoll when enslaving a dev if bond->dev->npinfo was set. However now slave_dev npinfo is set with bond->dev->npinfo before calling slave_enable_netpoll. With slave_dev npinfo set, __netpoll_setup called in slave_enable_netpoll will not call slave dev's .ndo_netpoll_setup(). It causes that the lower dev of this slave dev can't set its npinfo. One way to reproduce it: # modprobe bonding # brctl addbr br0 # brctl addif br0 eth1 # ifconfig bond0 192.168.122.1/24 up # ifenslave bond0 eth2 # systemctl restart netconsole # ifenslave bond0 br0 # ifconfig eth2 down # systemctl restart netconsole The netpoll won't really work. This patch is to remove that slave_dev npinfo setting in bond_enslave(). Fixes: 8a8efa22f51b ("bonding: sync netpoll code with bridge") Signed-off-by: Xin Long Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/bonding/bond_main.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 82f28ffccddf..bf3be2e6d4a8 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -1656,8 +1656,7 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) } /* switch(bond_mode) */ #ifdef CONFIG_NET_POLL_CONTROLLER - slave_dev->npinfo = bond->dev->npinfo; - if (slave_dev->npinfo) { + if (bond->dev->npinfo) { if (slave_enable_netpoll(new_slave)) { netdev_info(bond_dev, "master_dev is using netpoll, but new slave device does not support netpoll\n"); res = -EBUSY; -- GitLab From 8d34c67734593fc6b10b92905381c365de2c9ff6 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Sun, 22 Apr 2018 18:29:23 -0700 Subject: [PATCH 1125/1635] ipv6: add RTA_TABLE and RTA_PREFSRC to rtm_ipv6_policy [ Upstream commit aa8f8778493c85fff480cdf8b349b1e1dcb5f243 ] KMSAN reported use of uninit-value that I tracked to lack of proper size check on RTA_TABLE attribute. I also believe RTA_PREFSRC lacks a similar check. Fixes: 86872cb57925 ("[IPv6] route: FIB6 configuration using struct fib6_config") Fixes: c3968a857a6b ("ipv6: RTA_PREFSRC support for ipv6 route source address selection") Signed-off-by: Eric Dumazet Reported-by: syzbot Acked-by: David Ahern Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv6/route.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 0126d9bfa670..e04c534b573e 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -2959,6 +2959,7 @@ void rt6_mtu_change(struct net_device *dev, unsigned int mtu) static const struct nla_policy rtm_ipv6_policy[RTA_MAX+1] = { [RTA_GATEWAY] = { .len = sizeof(struct in6_addr) }, + [RTA_PREFSRC] = { .len = sizeof(struct in6_addr) }, [RTA_OIF] = { .type = NLA_U32 }, [RTA_IIF] = { .type = NLA_U32 }, [RTA_PRIORITY] = { .type = NLA_U32 }, @@ -2970,6 +2971,7 @@ static const struct nla_policy rtm_ipv6_policy[RTA_MAX+1] = { [RTA_EXPIRES] = { .type = NLA_U32 }, [RTA_UID] = { .type = NLA_U32 }, [RTA_MARK] = { .type = NLA_U32 }, + [RTA_TABLE] = { .type = NLA_U32 }, }; static int rtm_to_fib6_config(struct sk_buff *skb, struct nlmsghdr *nlh, -- GitLab From a370d8a3aaf268896eabaf510e1e8ca4b7ea0a34 Mon Sep 17 00:00:00 2001 From: Ahmed Abdelsalam Date: Fri, 20 Apr 2018 15:58:05 +0200 Subject: [PATCH 1126/1635] ipv6: sr: fix NULL pointer dereference in seg6_do_srh_encap()- v4 pkts [ Upstream commit a957fa190aa9d9168b33d460a5241a6d088c6265 ] In case of seg6 in encap mode, seg6_do_srh_encap() calls set_tun_src() in order to set the src addr of outer IPv6 header. The net_device is required for set_tun_src(). However calling ip6_dst_idev() on dst_entry in case of IPv4 traffic results on the following bug. Using just dst->dev should fix this BUG. [ 196.242461] BUG: unable to handle kernel NULL pointer dereference at 0000000000000000 [ 196.242975] PGD 800000010f076067 P4D 800000010f076067 PUD 10f060067 PMD 0 [ 196.243329] Oops: 0000 [#1] SMP PTI [ 196.243468] Modules linked in: nfsd auth_rpcgss nfs_acl nfs lockd grace fscache sunrpc crct10dif_pclmul crc32_pclmul ghash_clmulni_intel pcbc aesni_intel aes_x86_64 crypto_simd cryptd input_leds glue_helper led_class pcspkr serio_raw mac_hid video autofs4 hid_generic usbhid hid e1000 i2c_piix4 ahci pata_acpi libahci [ 196.244362] CPU: 2 PID: 1089 Comm: ping Not tainted 4.16.0+ #1 [ 196.244606] Hardware name: innotek GmbH VirtualBox/VirtualBox, BIOS VirtualBox 12/01/2006 [ 196.244968] RIP: 0010:seg6_do_srh_encap+0x1ac/0x300 [ 196.245236] RSP: 0018:ffffb2ce00b23a60 EFLAGS: 00010202 [ 196.245464] RAX: 0000000000000000 RBX: ffff8c7f53eea300 RCX: 0000000000000000 [ 196.245742] RDX: 0000f10000000000 RSI: ffff8c7f52085a6c RDI: ffff8c7f41166850 [ 196.246018] RBP: ffffb2ce00b23aa8 R08: 00000000000261e0 R09: ffff8c7f41166800 [ 196.246294] R10: ffffdce5040ac780 R11: ffff8c7f41166828 R12: ffff8c7f41166808 [ 196.246570] R13: ffff8c7f52085a44 R14: ffffffffb73211c0 R15: ffff8c7e69e44200 [ 196.246846] FS: 00007fc448789700(0000) GS:ffff8c7f59d00000(0000) knlGS:0000000000000000 [ 196.247286] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 196.247526] CR2: 0000000000000000 CR3: 000000010f05a000 CR4: 00000000000406e0 [ 196.247804] Call Trace: [ 196.247972] seg6_do_srh+0x15b/0x1c0 [ 196.248156] seg6_output+0x3c/0x220 [ 196.248341] ? prandom_u32+0x14/0x20 [ 196.248526] ? ip_idents_reserve+0x6c/0x80 [ 196.248723] ? __ip_select_ident+0x90/0x100 [ 196.248923] ? ip_append_data.part.50+0x6c/0xd0 [ 196.249133] lwtunnel_output+0x44/0x70 [ 196.249328] ip_send_skb+0x15/0x40 [ 196.249515] raw_sendmsg+0x8c3/0xac0 [ 196.249701] ? _copy_from_user+0x2e/0x60 [ 196.249897] ? rw_copy_check_uvector+0x53/0x110 [ 196.250106] ? _copy_from_user+0x2e/0x60 [ 196.250299] ? copy_msghdr_from_user+0xce/0x140 [ 196.250508] sock_sendmsg+0x36/0x40 [ 196.250690] ___sys_sendmsg+0x292/0x2a0 [ 196.250881] ? _cond_resched+0x15/0x30 [ 196.251074] ? copy_termios+0x1e/0x70 [ 196.251261] ? _copy_to_user+0x22/0x30 [ 196.251575] ? tty_mode_ioctl+0x1c3/0x4e0 [ 196.251782] ? _cond_resched+0x15/0x30 [ 196.251972] ? mutex_lock+0xe/0x30 [ 196.252152] ? vvar_fault+0xd2/0x110 [ 196.252337] ? __do_fault+0x1f/0xc0 [ 196.252521] ? __handle_mm_fault+0xc1f/0x12d0 [ 196.252727] ? __sys_sendmsg+0x63/0xa0 [ 196.252919] __sys_sendmsg+0x63/0xa0 [ 196.253107] do_syscall_64+0x72/0x200 [ 196.253305] entry_SYSCALL_64_after_hwframe+0x3d/0xa2 [ 196.253530] RIP: 0033:0x7fc4480b0690 [ 196.253715] RSP: 002b:00007ffde9f252f8 EFLAGS: 00000246 ORIG_RAX: 000000000000002e [ 196.254053] RAX: ffffffffffffffda RBX: 0000000000000040 RCX: 00007fc4480b0690 [ 196.254331] RDX: 0000000000000000 RSI: 000000000060a360 RDI: 0000000000000003 [ 196.254608] RBP: 00007ffde9f253f0 R08: 00000000002d1e81 R09: 0000000000000002 [ 196.254884] R10: 00007ffde9f250c0 R11: 0000000000000246 R12: 0000000000b22070 [ 196.255205] R13: 20c49ba5e353f7cf R14: 431bde82d7b634db R15: 00007ffde9f278fe [ 196.255484] Code: a5 0f b6 45 c0 41 88 41 28 41 0f b6 41 2c 48 c1 e0 04 49 8b 54 01 38 49 8b 44 01 30 49 89 51 20 49 89 41 18 48 8b 83 b0 00 00 00 <48> 8b 30 49 8b 86 08 0b 00 00 48 8b 40 20 48 8b 50 08 48 0b 10 [ 196.256190] RIP: seg6_do_srh_encap+0x1ac/0x300 RSP: ffffb2ce00b23a60 [ 196.256445] CR2: 0000000000000000 [ 196.256676] ---[ end trace 71af7d093603885c ]--- Fixes: 8936ef7604c11 ("ipv6: sr: fix NULL pointer dereference when setting encap source address") Signed-off-by: Ahmed Abdelsalam Acked-by: David Lebrun Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv6/seg6_iptunnel.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/ipv6/seg6_iptunnel.c b/net/ipv6/seg6_iptunnel.c index f343e6f0fc95..5fe139484919 100644 --- a/net/ipv6/seg6_iptunnel.c +++ b/net/ipv6/seg6_iptunnel.c @@ -136,7 +136,7 @@ int seg6_do_srh_encap(struct sk_buff *skb, struct ipv6_sr_hdr *osrh, int proto) isrh->nexthdr = proto; hdr->daddr = isrh->segments[isrh->first_segment]; - set_tun_src(net, ip6_dst_idev(dst)->dev, &hdr->daddr, &hdr->saddr); + set_tun_src(net, dst->dev, &hdr->daddr, &hdr->saddr); #ifdef CONFIG_IPV6_SEG6_HMAC if (sr_has_hmac(isrh)) { -- GitLab From c7a936b1dd0f75727b776479f739236a05317f7b Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Tue, 17 Apr 2018 12:07:06 -0700 Subject: [PATCH 1127/1635] KEYS: DNS: limit the length of option strings [ Upstream commit 9c438d7a3a52dcc2b9ed095cb87d3a5e83cf7e60 ] Adding a dns_resolver key whose payload contains a very long option name resulted in that string being printed in full. This hit the WARN_ONCE() in set_precision() during the printk(), because printk() only supports a precision of up to 32767 bytes: precision 1000000 too large WARNING: CPU: 0 PID: 752 at lib/vsprintf.c:2189 vsnprintf+0x4bc/0x5b0 Fix it by limiting option strings (combined name + value) to a much more reasonable 128 bytes. The exact limit is arbitrary, but currently the only recognized option is formatted as "dnserror=%lu" which fits well within this limit. Also ratelimit the printks. Reproducer: perl -e 'print "#", "A" x 1000000, "\x00"' | keyctl padd dns_resolver desc @s This bug was found using syzkaller. Reported-by: Mark Rutland Fixes: 4a2d789267e0 ("DNS: If the DNS server returns an error, allow that to be cached [ver #2]") Signed-off-by: Eric Biggers Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/dns_resolver/dns_key.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/net/dns_resolver/dns_key.c b/net/dns_resolver/dns_key.c index e1d4d898a007..f0252768ecf4 100644 --- a/net/dns_resolver/dns_key.c +++ b/net/dns_resolver/dns_key.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -91,9 +92,9 @@ dns_resolver_preparse(struct key_preparsed_payload *prep) next_opt = memchr(opt, '#', end - opt) ?: end; opt_len = next_opt - opt; - if (!opt_len) { - printk(KERN_WARNING - "Empty option to dns_resolver key\n"); + if (opt_len <= 0 || opt_len > 128) { + pr_warn_ratelimited("Invalid option length (%d) for dns_resolver key\n", + opt_len); return -EINVAL; } @@ -127,10 +128,8 @@ dns_resolver_preparse(struct key_preparsed_payload *prep) } bad_option_value: - printk(KERN_WARNING - "Option '%*.*s' to dns_resolver key:" - " bad/missing value\n", - opt_nlen, opt_nlen, opt); + pr_warn_ratelimited("Option '%*.*s' to dns_resolver key: bad/missing value\n", + opt_nlen, opt_nlen, opt); return -EINVAL; } while (opt = next_opt + 1, opt < end); } -- GitLab From dbf57fd1e05efc0d37503af5f08a532aff2c9823 Mon Sep 17 00:00:00 2001 From: Guillaume Nault Date: Mon, 23 Apr 2018 16:15:14 +0200 Subject: [PATCH 1128/1635] l2tp: check sockaddr length in pppol2tp_connect() [ Upstream commit eb1c28c05894a4b1f6b56c5bf072205e64cfa280 ] Check sockaddr_len before dereferencing sp->sa_protocol, to ensure that it actually points to valid data. Fixes: fd558d186df2 ("l2tp: Split pppol2tp patch into separate l2tp and ppp parts") Reported-by: syzbot+a70ac890b23b1bf29f5c@syzkaller.appspotmail.com Signed-off-by: Guillaume Nault Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/l2tp/l2tp_ppp.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/net/l2tp/l2tp_ppp.c b/net/l2tp/l2tp_ppp.c index 0c2738349442..8bef35aa8786 100644 --- a/net/l2tp/l2tp_ppp.c +++ b/net/l2tp/l2tp_ppp.c @@ -591,6 +591,13 @@ static int pppol2tp_connect(struct socket *sock, struct sockaddr *uservaddr, lock_sock(sk); error = -EINVAL; + + if (sockaddr_len != sizeof(struct sockaddr_pppol2tp) && + sockaddr_len != sizeof(struct sockaddr_pppol2tpv3) && + sockaddr_len != sizeof(struct sockaddr_pppol2tpin6) && + sockaddr_len != sizeof(struct sockaddr_pppol2tpv3in6)) + goto end; + if (sp->sa_protocol != PX_PROTO_OL2TP) goto end; -- GitLab From 15efa783286c6f4fb3deeff215c7fb33667b40a9 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 11 Apr 2018 14:46:00 -0700 Subject: [PATCH 1129/1635] net: validate attribute sizes in neigh_dump_table() [ Upstream commit 7dd07c143a4b54d050e748bee4b4b9e94a7b1744 ] Since neigh_dump_table() calls nlmsg_parse() without giving policy constraints, attributes can have arbirary size that we must validate Reported by syzbot/KMSAN : BUG: KMSAN: uninit-value in neigh_master_filtered net/core/neighbour.c:2292 [inline] BUG: KMSAN: uninit-value in neigh_dump_table net/core/neighbour.c:2348 [inline] BUG: KMSAN: uninit-value in neigh_dump_info+0x1af0/0x2250 net/core/neighbour.c:2438 CPU: 1 PID: 3575 Comm: syzkaller268891 Not tainted 4.16.0+ #83 Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/01/2011 Call Trace: __dump_stack lib/dump_stack.c:17 [inline] dump_stack+0x185/0x1d0 lib/dump_stack.c:53 kmsan_report+0x142/0x240 mm/kmsan/kmsan.c:1067 __msan_warning_32+0x6c/0xb0 mm/kmsan/kmsan_instr.c:676 neigh_master_filtered net/core/neighbour.c:2292 [inline] neigh_dump_table net/core/neighbour.c:2348 [inline] neigh_dump_info+0x1af0/0x2250 net/core/neighbour.c:2438 netlink_dump+0x9ad/0x1540 net/netlink/af_netlink.c:2225 __netlink_dump_start+0x1167/0x12a0 net/netlink/af_netlink.c:2322 netlink_dump_start include/linux/netlink.h:214 [inline] rtnetlink_rcv_msg+0x1435/0x1560 net/core/rtnetlink.c:4598 netlink_rcv_skb+0x355/0x5f0 net/netlink/af_netlink.c:2447 rtnetlink_rcv+0x50/0x60 net/core/rtnetlink.c:4653 netlink_unicast_kernel net/netlink/af_netlink.c:1311 [inline] netlink_unicast+0x1672/0x1750 net/netlink/af_netlink.c:1337 netlink_sendmsg+0x1048/0x1310 net/netlink/af_netlink.c:1900 sock_sendmsg_nosec net/socket.c:630 [inline] sock_sendmsg net/socket.c:640 [inline] ___sys_sendmsg+0xec0/0x1310 net/socket.c:2046 __sys_sendmsg net/socket.c:2080 [inline] SYSC_sendmsg+0x2a3/0x3d0 net/socket.c:2091 SyS_sendmsg+0x54/0x80 net/socket.c:2087 do_syscall_64+0x309/0x430 arch/x86/entry/common.c:287 entry_SYSCALL_64_after_hwframe+0x3d/0xa2 RIP: 0033:0x43fed9 RSP: 002b:00007ffddbee2798 EFLAGS: 00000213 ORIG_RAX: 000000000000002e RAX: ffffffffffffffda RBX: 00000000004002c8 RCX: 000000000043fed9 RDX: 0000000000000000 RSI: 0000000020005000 RDI: 0000000000000003 RBP: 00000000006ca018 R08: 00000000004002c8 R09: 00000000004002c8 R10: 00000000004002c8 R11: 0000000000000213 R12: 0000000000401800 R13: 0000000000401890 R14: 0000000000000000 R15: 0000000000000000 Uninit was created at: kmsan_save_stack_with_flags mm/kmsan/kmsan.c:278 [inline] kmsan_internal_poison_shadow+0xb8/0x1b0 mm/kmsan/kmsan.c:188 kmsan_kmalloc+0x94/0x100 mm/kmsan/kmsan.c:314 kmsan_slab_alloc+0x11/0x20 mm/kmsan/kmsan.c:321 slab_post_alloc_hook mm/slab.h:445 [inline] slab_alloc_node mm/slub.c:2737 [inline] __kmalloc_node_track_caller+0xaed/0x11c0 mm/slub.c:4369 __kmalloc_reserve net/core/skbuff.c:138 [inline] __alloc_skb+0x2cf/0x9f0 net/core/skbuff.c:206 alloc_skb include/linux/skbuff.h:984 [inline] netlink_alloc_large_skb net/netlink/af_netlink.c:1183 [inline] netlink_sendmsg+0x9a6/0x1310 net/netlink/af_netlink.c:1875 sock_sendmsg_nosec net/socket.c:630 [inline] sock_sendmsg net/socket.c:640 [inline] ___sys_sendmsg+0xec0/0x1310 net/socket.c:2046 __sys_sendmsg net/socket.c:2080 [inline] SYSC_sendmsg+0x2a3/0x3d0 net/socket.c:2091 SyS_sendmsg+0x54/0x80 net/socket.c:2087 do_syscall_64+0x309/0x430 arch/x86/entry/common.c:287 entry_SYSCALL_64_after_hwframe+0x3d/0xa2 Fixes: 21fdd092acc7 ("net: Add support for filtering neigh dump by master device") Signed-off-by: Eric Dumazet Cc: David Ahern Reported-by: syzbot Acked-by: David Ahern Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/core/neighbour.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/net/core/neighbour.c b/net/core/neighbour.c index 741ae2554190..a209d834daa2 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c @@ -2323,12 +2323,16 @@ static int neigh_dump_table(struct neigh_table *tbl, struct sk_buff *skb, err = nlmsg_parse(nlh, sizeof(struct ndmsg), tb, NDA_MAX, NULL, NULL); if (!err) { - if (tb[NDA_IFINDEX]) + if (tb[NDA_IFINDEX]) { + if (nla_len(tb[NDA_IFINDEX]) != sizeof(u32)) + return -EINVAL; filter_idx = nla_get_u32(tb[NDA_IFINDEX]); - - if (tb[NDA_MASTER]) + } + if (tb[NDA_MASTER]) { + if (nla_len(tb[NDA_MASTER]) != sizeof(u32)) + return -EINVAL; filter_master_idx = nla_get_u32(tb[NDA_MASTER]); - + } if (filter_idx || filter_master_idx) flags |= NLM_F_DUMP_FILTERED; } -- GitLab From cb225e80c9a3364c43ae4219da05ebb5a4b86c39 Mon Sep 17 00:00:00 2001 From: Cong Wang Date: Thu, 19 Apr 2018 12:25:38 -0700 Subject: [PATCH 1130/1635] llc: delete timers synchronously in llc_sk_free() [ Upstream commit b905ef9ab90115d001c1658259af4b1c65088779 ] The connection timers of an llc sock could be still flying after we delete them in llc_sk_free(), and even possibly after we free the sock. We could just wait synchronously here in case of troubles. Note, I leave other call paths as they are, since they may not have to wait, at least we can change them to synchronously when needed. Also, move the code to net/llc/llc_conn.c, which is apparently a better place. Reported-by: Signed-off-by: Cong Wang Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- include/net/llc_conn.h | 1 + net/llc/llc_c_ac.c | 9 +-------- net/llc/llc_conn.c | 22 +++++++++++++++++++++- 3 files changed, 23 insertions(+), 9 deletions(-) diff --git a/include/net/llc_conn.h b/include/net/llc_conn.h index fe994d2e5286..ea985aa7a6c5 100644 --- a/include/net/llc_conn.h +++ b/include/net/llc_conn.h @@ -97,6 +97,7 @@ static __inline__ char llc_backlog_type(struct sk_buff *skb) struct sock *llc_sk_alloc(struct net *net, int family, gfp_t priority, struct proto *prot, int kern); +void llc_sk_stop_all_timers(struct sock *sk, bool sync); void llc_sk_free(struct sock *sk); void llc_sk_reset(struct sock *sk); diff --git a/net/llc/llc_c_ac.c b/net/llc/llc_c_ac.c index ea225bd2672c..f8d4ab8ca1a5 100644 --- a/net/llc/llc_c_ac.c +++ b/net/llc/llc_c_ac.c @@ -1096,14 +1096,7 @@ int llc_conn_ac_inc_tx_win_size(struct sock *sk, struct sk_buff *skb) int llc_conn_ac_stop_all_timers(struct sock *sk, struct sk_buff *skb) { - struct llc_sock *llc = llc_sk(sk); - - del_timer(&llc->pf_cycle_timer.timer); - del_timer(&llc->ack_timer.timer); - del_timer(&llc->rej_sent_timer.timer); - del_timer(&llc->busy_state_timer.timer); - llc->ack_must_be_send = 0; - llc->ack_pf = 0; + llc_sk_stop_all_timers(sk, false); return 0; } diff --git a/net/llc/llc_conn.c b/net/llc/llc_conn.c index 5e91b47f0d2a..9a42448eb182 100644 --- a/net/llc/llc_conn.c +++ b/net/llc/llc_conn.c @@ -951,6 +951,26 @@ struct sock *llc_sk_alloc(struct net *net, int family, gfp_t priority, struct pr return sk; } +void llc_sk_stop_all_timers(struct sock *sk, bool sync) +{ + struct llc_sock *llc = llc_sk(sk); + + if (sync) { + del_timer_sync(&llc->pf_cycle_timer.timer); + del_timer_sync(&llc->ack_timer.timer); + del_timer_sync(&llc->rej_sent_timer.timer); + del_timer_sync(&llc->busy_state_timer.timer); + } else { + del_timer(&llc->pf_cycle_timer.timer); + del_timer(&llc->ack_timer.timer); + del_timer(&llc->rej_sent_timer.timer); + del_timer(&llc->busy_state_timer.timer); + } + + llc->ack_must_be_send = 0; + llc->ack_pf = 0; +} + /** * llc_sk_free - Frees a LLC socket * @sk - socket to free @@ -963,7 +983,7 @@ void llc_sk_free(struct sock *sk) llc->state = LLC_CONN_OUT_OF_SVC; /* Stop all (possibly) running timers */ - llc_conn_ac_stop_all_timers(sk, NULL); + llc_sk_stop_all_timers(sk, true); #ifdef DEBUG_LLC_CONN_ALLOC printk(KERN_INFO "%s: unackq=%d, txq=%d\n", __func__, skb_queue_len(&llc->pdu_unack_q), -- GitLab From b76d3f3309cf7d7ae8ef5e4b2c2010ae39189bc6 Mon Sep 17 00:00:00 2001 From: Jann Horn Date: Fri, 20 Apr 2018 15:57:30 +0200 Subject: [PATCH 1131/1635] tcp: don't read out-of-bounds opsize [ Upstream commit 7e5a206ab686f098367b61aca989f5cdfa8114a3 ] The old code reads the "opsize" variable from out-of-bounds memory (first byte behind the segment) if a broken TCP segment ends directly after an opcode that is neither EOL nor NOP. The result of the read isn't used for anything, so the worst thing that could theoretically happen is a pagefault; and since the physmap is usually mostly contiguous, even that seems pretty unlikely. The following C reproducer triggers the uninitialized read - however, you can't actually see anything happen unless you put something like a pr_warn() in tcp_parse_md5sig_option() to print the opsize. ==================================== #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include void systemf(const char *command, ...) { char *full_command; va_list ap; va_start(ap, command); if (vasprintf(&full_command, command, ap) == -1) err(1, "vasprintf"); va_end(ap); printf("systemf: <<<%s>>>\n", full_command); system(full_command); } char *devname; int tun_alloc(char *name) { int fd = open("/dev/net/tun", O_RDWR); if (fd == -1) err(1, "open tun dev"); static struct ifreq req = { .ifr_flags = IFF_TUN|IFF_NO_PI }; strcpy(req.ifr_name, name); if (ioctl(fd, TUNSETIFF, &req)) err(1, "TUNSETIFF"); devname = req.ifr_name; printf("device name: %s\n", devname); return fd; } #define IPADDR(a,b,c,d) (((a)<<0)+((b)<<8)+((c)<<16)+((d)<<24)) void sum_accumulate(unsigned int *sum, void *data, int len) { assert((len&2)==0); for (int i=0; i> 16) + (sum & 0xffff); sum = (sum >> 16) + (sum & 0xffff); return htons(~sum); } void fix_ip_sum(struct iphdr *ip) { unsigned int sum = 0; sum_accumulate(&sum, ip, sizeof(*ip)); ip->check = sum_final(sum); } void fix_tcp_sum(struct iphdr *ip, struct tcphdr *tcp) { unsigned int sum = 0; struct { unsigned int saddr; unsigned int daddr; unsigned char pad; unsigned char proto_num; unsigned short tcp_len; } fakehdr = { .saddr = ip->saddr, .daddr = ip->daddr, .proto_num = ip->protocol, .tcp_len = htons(ntohs(ip->tot_len) - ip->ihl*4) }; sum_accumulate(&sum, &fakehdr, sizeof(fakehdr)); sum_accumulate(&sum, tcp, tcp->doff*4); tcp->check = sum_final(sum); } int main(void) { int tun_fd = tun_alloc("inject_dev%d"); systemf("ip link set %s up", devname); systemf("ip addr add 192.168.42.1/24 dev %s", devname); struct { struct iphdr ip; struct tcphdr tcp; unsigned char tcp_opts[20]; } __attribute__((packed)) syn_packet = { .ip = { .ihl = sizeof(struct iphdr)/4, .version = 4, .tot_len = htons(sizeof(syn_packet)), .ttl = 30, .protocol = IPPROTO_TCP, /* FIXUP check */ .saddr = IPADDR(192,168,42,2), .daddr = IPADDR(192,168,42,1) }, .tcp = { .source = htons(1), .dest = htons(1337), .seq = 0x12345678, .doff = (sizeof(syn_packet.tcp)+sizeof(syn_packet.tcp_opts))/4, .syn = 1, .window = htons(64), .check = 0 /*FIXUP*/ }, .tcp_opts = { /* INVALID: trailing MD5SIG opcode after NOPs */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 19 } }; fix_ip_sum(&syn_packet.ip); fix_tcp_sum(&syn_packet.ip, &syn_packet.tcp); while (1) { int write_res = write(tun_fd, &syn_packet, sizeof(syn_packet)); if (write_res != sizeof(syn_packet)) err(1, "packet write failed"); } } ==================================== Fixes: cfb6eeb4c860 ("[TCP]: MD5 Signature Option (RFC2385) support.") Signed-off-by: Jann Horn Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv4/tcp_input.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 14474acea0bb..ebbb54bcbcac 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -3892,11 +3892,8 @@ const u8 *tcp_parse_md5sig_option(const struct tcphdr *th) int length = (th->doff << 2) - sizeof(*th); const u8 *ptr = (const u8 *)(th + 1); - /* If the TCP option is too short, we can short cut */ - if (length < TCPOLEN_MD5SIG) - return NULL; - - while (length > 0) { + /* If not enough data remaining, we can short cut */ + while (length >= TCPOLEN_MD5SIG) { int opcode = *ptr++; int opsize; -- GitLab From 7c2352520e513dfb4f2a7a84fe3502ec1fd40705 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Sun, 15 Apr 2018 17:52:04 -0700 Subject: [PATCH 1132/1635] net: af_packet: fix race in PACKET_{R|T}X_RING [ Upstream commit 5171b37d959641bbc619781caf62e61f7b940871 ] In order to remove the race caught by syzbot [1], we need to lock the socket before using po->tp_version as this could change under us otherwise. This means lock_sock() and release_sock() must be done by packet_set_ring() callers. [1] : BUG: KMSAN: uninit-value in packet_set_ring+0x1254/0x3870 net/packet/af_packet.c:4249 CPU: 0 PID: 20195 Comm: syzkaller707632 Not tainted 4.16.0+ #83 Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/01/2011 Call Trace: __dump_stack lib/dump_stack.c:17 [inline] dump_stack+0x185/0x1d0 lib/dump_stack.c:53 kmsan_report+0x142/0x240 mm/kmsan/kmsan.c:1067 __msan_warning_32+0x6c/0xb0 mm/kmsan/kmsan_instr.c:676 packet_set_ring+0x1254/0x3870 net/packet/af_packet.c:4249 packet_setsockopt+0x12c6/0x5a90 net/packet/af_packet.c:3662 SYSC_setsockopt+0x4b8/0x570 net/socket.c:1849 SyS_setsockopt+0x76/0xa0 net/socket.c:1828 do_syscall_64+0x309/0x430 arch/x86/entry/common.c:287 entry_SYSCALL_64_after_hwframe+0x3d/0xa2 RIP: 0033:0x449099 RSP: 002b:00007f42b5307ce8 EFLAGS: 00000246 ORIG_RAX: 0000000000000036 RAX: ffffffffffffffda RBX: 000000000070003c RCX: 0000000000449099 RDX: 0000000000000005 RSI: 0000000000000107 RDI: 0000000000000003 RBP: 0000000000700038 R08: 000000000000001c R09: 0000000000000000 R10: 00000000200000c0 R11: 0000000000000246 R12: 0000000000000000 R13: 000000000080eecf R14: 00007f42b53089c0 R15: 0000000000000001 Local variable description: ----req_u@packet_setsockopt Variable was created at: packet_setsockopt+0x13f/0x5a90 net/packet/af_packet.c:3612 SYSC_setsockopt+0x4b8/0x570 net/socket.c:1849 Fixes: f6fb8f100b80 ("af-packet: TPACKET_V3 flexible buffer implementation.") Signed-off-by: Eric Dumazet Reported-by: syzbot Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/packet/af_packet.c | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index f4a0587b7d5e..e829f4065dbf 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -3017,6 +3017,7 @@ static int packet_release(struct socket *sock) packet_flush_mclist(sk); + lock_sock(sk); if (po->rx_ring.pg_vec) { memset(&req_u, 0, sizeof(req_u)); packet_set_ring(sk, &req_u, 1, 0); @@ -3026,6 +3027,7 @@ static int packet_release(struct socket *sock) memset(&req_u, 0, sizeof(req_u)); packet_set_ring(sk, &req_u, 1, 1); } + release_sock(sk); f = fanout_release(sk); @@ -3654,6 +3656,7 @@ packet_setsockopt(struct socket *sock, int level, int optname, char __user *optv union tpacket_req_u req_u; int len; + lock_sock(sk); switch (po->tp_version) { case TPACKET_V1: case TPACKET_V2: @@ -3664,12 +3667,17 @@ packet_setsockopt(struct socket *sock, int level, int optname, char __user *optv len = sizeof(req_u.req3); break; } - if (optlen < len) - return -EINVAL; - if (copy_from_user(&req_u.req, optval, len)) - return -EFAULT; - return packet_set_ring(sk, &req_u, 0, - optname == PACKET_TX_RING); + if (optlen < len) { + ret = -EINVAL; + } else { + if (copy_from_user(&req_u.req, optval, len)) + ret = -EFAULT; + else + ret = packet_set_ring(sk, &req_u, 0, + optname == PACKET_TX_RING); + } + release_sock(sk); + return ret; } case PACKET_COPY_THRESH: { @@ -4219,8 +4227,6 @@ static int packet_set_ring(struct sock *sk, union tpacket_req_u *req_u, /* Added to avoid minimal code churn */ struct tpacket_req *req = &req_u->req; - lock_sock(sk); - rb = tx_ring ? &po->tx_ring : &po->rx_ring; rb_queue = tx_ring ? &sk->sk_write_queue : &sk->sk_receive_queue; @@ -4358,7 +4364,6 @@ static int packet_set_ring(struct sock *sk, union tpacket_req_u *req_u, if (pg_vec) free_pg_vec(pg_vec, order, req->tp_block_nr); out: - release_sock(sk); return err; } -- GitLab From d5387e66388f73152afe7f8e341fccc4469bba10 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 11 Apr 2018 14:36:28 -0700 Subject: [PATCH 1133/1635] tcp: md5: reject TCP_MD5SIG or TCP_MD5SIG_EXT on established sockets [ Upstream commit 7212303268918b9a203aebeacfdbd83b5e87b20d ] syzbot/KMSAN reported an uninit-value in tcp_parse_options() [1] I believe this was caused by a TCP_MD5SIG being set on live flow. This is highly unexpected, since TCP option space is limited. For instance, presence of TCP MD5 option automatically disables TCP TimeStamp option at SYN/SYNACK time, which we can not do once flow has been established. Really, adding/deleting an MD5 key only makes sense on sockets in CLOSE or LISTEN state. [1] BUG: KMSAN: uninit-value in tcp_parse_options+0xd74/0x1a30 net/ipv4/tcp_input.c:3720 CPU: 1 PID: 6177 Comm: syzkaller192004 Not tainted 4.16.0+ #83 Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/01/2011 Call Trace: __dump_stack lib/dump_stack.c:17 [inline] dump_stack+0x185/0x1d0 lib/dump_stack.c:53 kmsan_report+0x142/0x240 mm/kmsan/kmsan.c:1067 __msan_warning_32+0x6c/0xb0 mm/kmsan/kmsan_instr.c:676 tcp_parse_options+0xd74/0x1a30 net/ipv4/tcp_input.c:3720 tcp_fast_parse_options net/ipv4/tcp_input.c:3858 [inline] tcp_validate_incoming+0x4f1/0x2790 net/ipv4/tcp_input.c:5184 tcp_rcv_established+0xf60/0x2bb0 net/ipv4/tcp_input.c:5453 tcp_v4_do_rcv+0x6cd/0xd90 net/ipv4/tcp_ipv4.c:1469 sk_backlog_rcv include/net/sock.h:908 [inline] __release_sock+0x2d6/0x680 net/core/sock.c:2271 release_sock+0x97/0x2a0 net/core/sock.c:2786 tcp_sendmsg+0xd6/0x100 net/ipv4/tcp.c:1464 inet_sendmsg+0x48d/0x740 net/ipv4/af_inet.c:764 sock_sendmsg_nosec net/socket.c:630 [inline] sock_sendmsg net/socket.c:640 [inline] SYSC_sendto+0x6c3/0x7e0 net/socket.c:1747 SyS_sendto+0x8a/0xb0 net/socket.c:1715 do_syscall_64+0x309/0x430 arch/x86/entry/common.c:287 entry_SYSCALL_64_after_hwframe+0x3d/0xa2 RIP: 0033:0x448fe9 RSP: 002b:00007fd472c64d38 EFLAGS: 00000216 ORIG_RAX: 000000000000002c RAX: ffffffffffffffda RBX: 00000000006e5a30 RCX: 0000000000448fe9 RDX: 000000000000029f RSI: 0000000020a88f88 RDI: 0000000000000004 RBP: 00000000006e5a34 R08: 0000000020e68000 R09: 0000000000000010 R10: 00000000200007fd R11: 0000000000000216 R12: 0000000000000000 R13: 00007fff074899ef R14: 00007fd472c659c0 R15: 0000000000000009 Uninit was created at: kmsan_save_stack_with_flags mm/kmsan/kmsan.c:278 [inline] kmsan_internal_poison_shadow+0xb8/0x1b0 mm/kmsan/kmsan.c:188 kmsan_kmalloc+0x94/0x100 mm/kmsan/kmsan.c:314 kmsan_slab_alloc+0x11/0x20 mm/kmsan/kmsan.c:321 slab_post_alloc_hook mm/slab.h:445 [inline] slab_alloc_node mm/slub.c:2737 [inline] __kmalloc_node_track_caller+0xaed/0x11c0 mm/slub.c:4369 __kmalloc_reserve net/core/skbuff.c:138 [inline] __alloc_skb+0x2cf/0x9f0 net/core/skbuff.c:206 alloc_skb include/linux/skbuff.h:984 [inline] tcp_send_ack+0x18c/0x910 net/ipv4/tcp_output.c:3624 __tcp_ack_snd_check net/ipv4/tcp_input.c:5040 [inline] tcp_ack_snd_check net/ipv4/tcp_input.c:5053 [inline] tcp_rcv_established+0x2103/0x2bb0 net/ipv4/tcp_input.c:5469 tcp_v4_do_rcv+0x6cd/0xd90 net/ipv4/tcp_ipv4.c:1469 sk_backlog_rcv include/net/sock.h:908 [inline] __release_sock+0x2d6/0x680 net/core/sock.c:2271 release_sock+0x97/0x2a0 net/core/sock.c:2786 tcp_sendmsg+0xd6/0x100 net/ipv4/tcp.c:1464 inet_sendmsg+0x48d/0x740 net/ipv4/af_inet.c:764 sock_sendmsg_nosec net/socket.c:630 [inline] sock_sendmsg net/socket.c:640 [inline] SYSC_sendto+0x6c3/0x7e0 net/socket.c:1747 SyS_sendto+0x8a/0xb0 net/socket.c:1715 do_syscall_64+0x309/0x430 arch/x86/entry/common.c:287 entry_SYSCALL_64_after_hwframe+0x3d/0xa2 Fixes: cfb6eeb4c860 ("[TCP]: MD5 Signature Option (RFC2385) support.") Signed-off-by: Eric Dumazet Reported-by: syzbot Acked-by: Yuchung Cheng Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv4/tcp.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 38b9a6276a9d..e8d8140cd33f 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -2742,8 +2742,10 @@ static int do_tcp_setsockopt(struct sock *sk, int level, #ifdef CONFIG_TCP_MD5SIG case TCP_MD5SIG: case TCP_MD5SIG_EXT: - /* Read the IP->Key mappings from userspace */ - err = tp->af_specific->md5_parse(sk, optname, optval, optlen); + if ((1 << sk->sk_state) & (TCPF_CLOSE | TCPF_LISTEN)) + err = tp->af_specific->md5_parse(sk, optname, optval, optlen); + else + err = -EINVAL; break; #endif case TCP_USER_TIMEOUT: -- GitLab From 012e5e5b6991c83d96173f643ab1cafb7e38c451 Mon Sep 17 00:00:00 2001 From: Wolfgang Bumiller Date: Thu, 12 Apr 2018 10:46:55 +0200 Subject: [PATCH 1134/1635] net: fix deadlock while clearing neighbor proxy table [ Upstream commit 53b76cdf7e8fecec1d09e38aad2f8579882591a8 ] When coming from ndisc_netdev_event() in net/ipv6/ndisc.c, neigh_ifdown() is called with &nd_tbl, locking this while clearing the proxy neighbor entries when eg. deleting an interface. Calling the table's pndisc_destructor() with the lock still held, however, can cause a deadlock: When a multicast listener is available an IGMP packet of type ICMPV6_MGM_REDUCTION may be sent out. When reaching ip6_finish_output2(), if no neighbor entry for the target address is found, __neigh_create() is called with &nd_tbl, which it'll want to lock. Move the elements into their own list, then unlock the table and perform the destruction. Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=199289 Fixes: 6fd6ce2056de ("ipv6: Do not depend on rt->n in ip6_finish_output2().") Signed-off-by: Wolfgang Bumiller Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/core/neighbour.c | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/net/core/neighbour.c b/net/core/neighbour.c index a209d834daa2..514d697d4691 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c @@ -55,7 +55,8 @@ static void neigh_timer_handler(unsigned long arg); static void __neigh_notify(struct neighbour *n, int type, int flags, u32 pid); static void neigh_update_notify(struct neighbour *neigh, u32 nlmsg_pid); -static int pneigh_ifdown(struct neigh_table *tbl, struct net_device *dev); +static int pneigh_ifdown_and_unlock(struct neigh_table *tbl, + struct net_device *dev); #ifdef CONFIG_PROC_FS static const struct file_operations neigh_stat_seq_fops; @@ -291,8 +292,7 @@ int neigh_ifdown(struct neigh_table *tbl, struct net_device *dev) { write_lock_bh(&tbl->lock); neigh_flush_dev(tbl, dev); - pneigh_ifdown(tbl, dev); - write_unlock_bh(&tbl->lock); + pneigh_ifdown_and_unlock(tbl, dev); del_timer_sync(&tbl->proxy_timer); pneigh_queue_purge(&tbl->proxy_queue); @@ -681,9 +681,10 @@ int pneigh_delete(struct neigh_table *tbl, struct net *net, const void *pkey, return -ENOENT; } -static int pneigh_ifdown(struct neigh_table *tbl, struct net_device *dev) +static int pneigh_ifdown_and_unlock(struct neigh_table *tbl, + struct net_device *dev) { - struct pneigh_entry *n, **np; + struct pneigh_entry *n, **np, *freelist = NULL; u32 h; for (h = 0; h <= PNEIGH_HASHMASK; h++) { @@ -691,16 +692,23 @@ static int pneigh_ifdown(struct neigh_table *tbl, struct net_device *dev) while ((n = *np) != NULL) { if (!dev || n->dev == dev) { *np = n->next; - if (tbl->pdestructor) - tbl->pdestructor(n); - if (n->dev) - dev_put(n->dev); - kfree(n); + n->next = freelist; + freelist = n; continue; } np = &n->next; } } + write_unlock_bh(&tbl->lock); + while ((n = freelist)) { + freelist = n->next; + n->next = NULL; + if (tbl->pdestructor) + tbl->pdestructor(n); + if (n->dev) + dev_put(n->dev); + kfree(n); + } return -ENOENT; } -- GitLab From 7b4f4d759c8ea9b4b607d13d3c89c59dd78a6ed7 Mon Sep 17 00:00:00 2001 From: Paolo Abeni Date: Fri, 13 Apr 2018 13:59:25 +0200 Subject: [PATCH 1135/1635] team: avoid adding twice the same option to the event list [ Upstream commit 4fb0534fb7bbc2346ba7d3a072b538007f4135a5 ] When parsing the options provided by the user space, team_nl_cmd_options_set() insert them in a temporary list to send multiple events with a single message. While each option's attribute is correctly validated, the code does not check for duplicate entries before inserting into the event list. Exploiting the above, the syzbot was able to trigger the following splat: kernel BUG at lib/list_debug.c:31! invalid opcode: 0000 [#1] SMP KASAN Dumping ftrace buffer: (ftrace buffer empty) Modules linked in: CPU: 0 PID: 4466 Comm: syzkaller556835 Not tainted 4.16.0+ #17 Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/01/2011 RIP: 0010:__list_add_valid+0xaa/0xb0 lib/list_debug.c:29 RSP: 0018:ffff8801b04bf248 EFLAGS: 00010286 RAX: 0000000000000058 RBX: ffff8801c8fc7a90 RCX: 0000000000000000 RDX: 0000000000000058 RSI: ffffffff815fbf41 RDI: ffffed0036097e3f RBP: ffff8801b04bf260 R08: ffff8801b0b2a700 R09: ffffed003b604f90 R10: ffffed003b604f90 R11: ffff8801db027c87 R12: ffff8801c8fc7a90 R13: ffff8801c8fc7a90 R14: dffffc0000000000 R15: 0000000000000000 FS: 0000000000b98880(0000) GS:ffff8801db000000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 000000000043fc30 CR3: 00000001afe8e000 CR4: 00000000001406f0 DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 Call Trace: __list_add include/linux/list.h:60 [inline] list_add include/linux/list.h:79 [inline] team_nl_cmd_options_set+0x9ff/0x12b0 drivers/net/team/team.c:2571 genl_family_rcv_msg+0x889/0x1120 net/netlink/genetlink.c:599 genl_rcv_msg+0xc6/0x170 net/netlink/genetlink.c:624 netlink_rcv_skb+0x172/0x440 net/netlink/af_netlink.c:2448 genl_rcv+0x28/0x40 net/netlink/genetlink.c:635 netlink_unicast_kernel net/netlink/af_netlink.c:1310 [inline] netlink_unicast+0x58b/0x740 net/netlink/af_netlink.c:1336 netlink_sendmsg+0x9f0/0xfa0 net/netlink/af_netlink.c:1901 sock_sendmsg_nosec net/socket.c:629 [inline] sock_sendmsg+0xd5/0x120 net/socket.c:639 ___sys_sendmsg+0x805/0x940 net/socket.c:2117 __sys_sendmsg+0x115/0x270 net/socket.c:2155 SYSC_sendmsg net/socket.c:2164 [inline] SyS_sendmsg+0x29/0x30 net/socket.c:2162 do_syscall_64+0x29e/0x9d0 arch/x86/entry/common.c:287 entry_SYSCALL_64_after_hwframe+0x42/0xb7 RIP: 0033:0x4458b9 RSP: 002b:00007ffd1d4a7278 EFLAGS: 00000213 ORIG_RAX: 000000000000002e RAX: ffffffffffffffda RBX: 000000000000001b RCX: 00000000004458b9 RDX: 0000000000000010 RSI: 0000000020000d00 RDI: 0000000000000004 RBP: 00000000004a74ed R08: 0000000000000000 R09: 0000000000000000 R10: 0000000000000000 R11: 0000000000000213 R12: 00007ffd1d4a7348 R13: 0000000000402a60 R14: 0000000000000000 R15: 0000000000000000 Code: 75 e8 eb a9 48 89 f7 48 89 75 e8 e8 d1 85 7b fe 48 8b 75 e8 eb bb 48 89 f2 48 89 d9 4c 89 e6 48 c7 c7 a0 84 d8 87 e8 ea 67 28 fe <0f> 0b 0f 1f 40 00 48 b8 00 00 00 00 00 fc ff df 55 48 89 e5 41 RIP: __list_add_valid+0xaa/0xb0 lib/list_debug.c:29 RSP: ffff8801b04bf248 This changeset addresses the avoiding list_add() if the current option is already present in the event list. Reported-and-tested-by: syzbot+4d4af685432dc0e56c91@syzkaller.appspotmail.com Signed-off-by: Paolo Abeni Fixes: 2fcdb2c9e659 ("team: allow to send multiple set events in one message") Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/team/team.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/drivers/net/team/team.c b/drivers/net/team/team.c index 2a366554c503..91a0209756d5 100644 --- a/drivers/net/team/team.c +++ b/drivers/net/team/team.c @@ -261,6 +261,17 @@ static void __team_option_inst_mark_removed_port(struct team *team, } } +static bool __team_option_inst_tmp_find(const struct list_head *opts, + const struct team_option_inst *needle) +{ + struct team_option_inst *opt_inst; + + list_for_each_entry(opt_inst, opts, tmp_list) + if (opt_inst == needle) + return true; + return false; +} + static int __team_options_register(struct team *team, const struct team_option *option, size_t option_count) @@ -2561,6 +2572,14 @@ static int team_nl_cmd_options_set(struct sk_buff *skb, struct genl_info *info) if (err) goto team_put; opt_inst->changed = true; + + /* dumb/evil user-space can send us duplicate opt, + * keep only the last one + */ + if (__team_option_inst_tmp_find(&opt_inst_list, + opt_inst)) + continue; + list_add(&opt_inst->tmp_list, &opt_inst_list); } if (!opt_found) { -- GitLab From 07cb0b54d7d99d0c67f8f7aebc1bb8f276bdf2b8 Mon Sep 17 00:00:00 2001 From: Ursula Braun Date: Thu, 19 Apr 2018 15:56:40 +0200 Subject: [PATCH 1136/1635] net/smc: fix shutdown in state SMC_LISTEN [ Upstream commit 1255fcb2a655f05e02f3a74675a6d6525f187afd ] Calling shutdown with SHUT_RD and SHUT_RDWR for a listening SMC socket crashes, because commit 127f49705823 ("net/smc: release clcsock from tcp_listen_worker") releases the internal clcsock in smc_close_active() and sets smc->clcsock to NULL. For SHUT_RD the smc_close_active() call is removed. For SHUT_RDWR the kernel_sock_shutdown() call is omitted, since the clcsock is already released. Fixes: 127f49705823 ("net/smc: release clcsock from tcp_listen_worker") Signed-off-by: Ursula Braun Reported-by: Stephen Hemminger Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/smc/af_smc.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/net/smc/af_smc.c b/net/smc/af_smc.c index a6d604fd9695..f9c289e05707 100644 --- a/net/smc/af_smc.c +++ b/net/smc/af_smc.c @@ -1203,14 +1203,12 @@ static int smc_shutdown(struct socket *sock, int how) rc = smc_close_shutdown_write(smc); break; case SHUT_RD: - if (sk->sk_state == SMC_LISTEN) - rc = smc_close_active(smc); - else - rc = 0; - /* nothing more to do because peer is not involved */ + rc = 0; + /* nothing more to do because peer is not involved */ break; } - rc1 = kernel_sock_shutdown(smc->clcsock, how); + if (smc->clcsock) + rc1 = kernel_sock_shutdown(smc->clcsock, how); /* map sock_shutdown_cmd constants to sk_shutdown value range */ sk->sk_shutdown |= how + 1; -- GitLab From 70a615d7daa04923d9f255307de26819f2f6dbd4 Mon Sep 17 00:00:00 2001 From: Xin Long Date: Tue, 24 Apr 2018 14:33:37 +0800 Subject: [PATCH 1137/1635] team: fix netconsole setup over team MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit 9cf2f437ca5b39828984064fad213e68fc17ef11 ] The same fix in Commit dbe173079ab5 ("bridge: fix netconsole setup over bridge") is also needed for team driver. While at it, remove the unnecessary parameter *team from team_port_enable_netpoll(). v1->v2: - fix it in a better way, as does bridge. Fixes: 0fb52a27a04a ("team: cleanup netpoll clode") Reported-by: João Avelino Bellomo Filho Signed-off-by: Xin Long Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/team/team.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/drivers/net/team/team.c b/drivers/net/team/team.c index 91a0209756d5..8a222ae5950e 100644 --- a/drivers/net/team/team.c +++ b/drivers/net/team/team.c @@ -1072,14 +1072,11 @@ static void team_port_leave(struct team *team, struct team_port *port) } #ifdef CONFIG_NET_POLL_CONTROLLER -static int team_port_enable_netpoll(struct team *team, struct team_port *port) +static int __team_port_enable_netpoll(struct team_port *port) { struct netpoll *np; int err; - if (!team->dev->npinfo) - return 0; - np = kzalloc(sizeof(*np), GFP_KERNEL); if (!np) return -ENOMEM; @@ -1093,6 +1090,14 @@ static int team_port_enable_netpoll(struct team *team, struct team_port *port) return err; } +static int team_port_enable_netpoll(struct team_port *port) +{ + if (!port->team->dev->npinfo) + return 0; + + return __team_port_enable_netpoll(port); +} + static void team_port_disable_netpoll(struct team_port *port) { struct netpoll *np = port->np; @@ -1107,7 +1112,7 @@ static void team_port_disable_netpoll(struct team_port *port) kfree(np); } #else -static int team_port_enable_netpoll(struct team *team, struct team_port *port) +static int team_port_enable_netpoll(struct team_port *port) { return 0; } @@ -1215,7 +1220,7 @@ static int team_port_add(struct team *team, struct net_device *port_dev) goto err_vids_add; } - err = team_port_enable_netpoll(team, port); + err = team_port_enable_netpoll(port); if (err) { netdev_err(dev, "Failed to enable netpoll on device %s\n", portname); @@ -1912,7 +1917,7 @@ static int team_netpoll_setup(struct net_device *dev, mutex_lock(&team->lock); list_for_each_entry(port, &team->port_list, list) { - err = team_port_enable_netpoll(team, port); + err = __team_port_enable_netpoll(port); if (err) { __team_netpoll_cleanup(team); break; -- GitLab From 6da813d79cfaa8dbc545e194484185b6b5639c92 Mon Sep 17 00:00:00 2001 From: Willem de Bruijn Date: Mon, 23 Apr 2018 17:37:03 -0400 Subject: [PATCH 1138/1635] packet: fix bitfield update race [ Upstream commit a6361f0ca4b25460f2cdf3235ebe8115f622901e ] Updates to the bitfields in struct packet_sock are not atomic. Serialize these read-modify-write cycles. Move po->running into a separate variable. Its writes are protected by po->bind_lock (except for one startup case at packet_create). Also replace a textual precondition warning with lockdep annotation. All others are set only in packet_setsockopt. Serialize these updates by holding the socket lock. Analogous to other field updates, also hold the lock when testing whether a ring is active (pg_vec). Fixes: 8dc419447415 ("[PACKET]: Add optional checksum computation for recvmsg") Reported-by: DaeRyong Jeong Reported-by: Byoungyoung Lee Signed-off-by: Willem de Bruijn Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/packet/af_packet.c | 60 +++++++++++++++++++++++++++++++----------- net/packet/internal.h | 10 +++---- 2 files changed, 49 insertions(+), 21 deletions(-) diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index e829f4065dbf..3994b71f8197 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -331,11 +331,11 @@ static void packet_pick_tx_queue(struct net_device *dev, struct sk_buff *skb) skb_set_queue_mapping(skb, queue_index); } -/* register_prot_hook must be invoked with the po->bind_lock held, +/* __register_prot_hook must be invoked through register_prot_hook * or from a context in which asynchronous accesses to the packet * socket is not possible (packet_create()). */ -static void register_prot_hook(struct sock *sk) +static void __register_prot_hook(struct sock *sk) { struct packet_sock *po = pkt_sk(sk); @@ -350,8 +350,13 @@ static void register_prot_hook(struct sock *sk) } } -/* {,__}unregister_prot_hook() must be invoked with the po->bind_lock - * held. If the sync parameter is true, we will temporarily drop +static void register_prot_hook(struct sock *sk) +{ + lockdep_assert_held_once(&pkt_sk(sk)->bind_lock); + __register_prot_hook(sk); +} + +/* If the sync parameter is true, we will temporarily drop * the po->bind_lock and do a synchronize_net to make sure no * asynchronous packet processing paths still refer to the elements * of po->prot_hook. If the sync parameter is false, it is the @@ -361,6 +366,8 @@ static void __unregister_prot_hook(struct sock *sk, bool sync) { struct packet_sock *po = pkt_sk(sk); + lockdep_assert_held_once(&po->bind_lock); + po->running = 0; if (po->fanout) @@ -3261,7 +3268,7 @@ static int packet_create(struct net *net, struct socket *sock, int protocol, if (proto) { po->prot_hook.type = proto; - register_prot_hook(sk); + __register_prot_hook(sk); } mutex_lock(&net->packet.sklist_lock); @@ -3743,12 +3750,18 @@ packet_setsockopt(struct socket *sock, int level, int optname, char __user *optv if (optlen != sizeof(val)) return -EINVAL; - if (po->rx_ring.pg_vec || po->tx_ring.pg_vec) - return -EBUSY; if (copy_from_user(&val, optval, sizeof(val))) return -EFAULT; - po->tp_loss = !!val; - return 0; + + lock_sock(sk); + if (po->rx_ring.pg_vec || po->tx_ring.pg_vec) { + ret = -EBUSY; + } else { + po->tp_loss = !!val; + ret = 0; + } + release_sock(sk); + return ret; } case PACKET_AUXDATA: { @@ -3759,7 +3772,9 @@ packet_setsockopt(struct socket *sock, int level, int optname, char __user *optv if (copy_from_user(&val, optval, sizeof(val))) return -EFAULT; + lock_sock(sk); po->auxdata = !!val; + release_sock(sk); return 0; } case PACKET_ORIGDEV: @@ -3771,7 +3786,9 @@ packet_setsockopt(struct socket *sock, int level, int optname, char __user *optv if (copy_from_user(&val, optval, sizeof(val))) return -EFAULT; + lock_sock(sk); po->origdev = !!val; + release_sock(sk); return 0; } case PACKET_VNET_HDR: @@ -3780,15 +3797,20 @@ packet_setsockopt(struct socket *sock, int level, int optname, char __user *optv if (sock->type != SOCK_RAW) return -EINVAL; - if (po->rx_ring.pg_vec || po->tx_ring.pg_vec) - return -EBUSY; if (optlen < sizeof(val)) return -EINVAL; if (copy_from_user(&val, optval, sizeof(val))) return -EFAULT; - po->has_vnet_hdr = !!val; - return 0; + lock_sock(sk); + if (po->rx_ring.pg_vec || po->tx_ring.pg_vec) { + ret = -EBUSY; + } else { + po->has_vnet_hdr = !!val; + ret = 0; + } + release_sock(sk); + return ret; } case PACKET_TIMESTAMP: { @@ -3826,11 +3848,17 @@ packet_setsockopt(struct socket *sock, int level, int optname, char __user *optv if (optlen != sizeof(val)) return -EINVAL; - if (po->rx_ring.pg_vec || po->tx_ring.pg_vec) - return -EBUSY; if (copy_from_user(&val, optval, sizeof(val))) return -EFAULT; - po->tp_tx_has_off = !!val; + + lock_sock(sk); + if (po->rx_ring.pg_vec || po->tx_ring.pg_vec) { + ret = -EBUSY; + } else { + po->tp_tx_has_off = !!val; + ret = 0; + } + release_sock(sk); return 0; } case PACKET_QDISC_BYPASS: diff --git a/net/packet/internal.h b/net/packet/internal.h index a1d2b2319ae9..3bb7c5fb3bff 100644 --- a/net/packet/internal.h +++ b/net/packet/internal.h @@ -112,10 +112,12 @@ struct packet_sock { int copy_thresh; spinlock_t bind_lock; struct mutex pg_vec_lock; - unsigned int running:1, /* prot_hook is attached*/ - auxdata:1, + unsigned int running; /* bind_lock must be held */ + unsigned int auxdata:1, /* writer must hold sock lock */ origdev:1, - has_vnet_hdr:1; + has_vnet_hdr:1, + tp_loss:1, + tp_tx_has_off:1; int pressure; int ifindex; /* bound device */ __be16 num; @@ -125,8 +127,6 @@ struct packet_sock { enum tpacket_versions tp_version; unsigned int tp_hdrlen; unsigned int tp_reserve; - unsigned int tp_loss:1; - unsigned int tp_tx_has_off:1; unsigned int tp_tstamp; struct net_device __rcu *cached_dev; int (*xmit)(struct sk_buff *skb); -- GitLab From ed2ba25f6d509431103ea3916f6db34595d62406 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Mon, 16 Apr 2018 08:29:42 -0700 Subject: [PATCH 1139/1635] tipc: add policy for TIPC_NLA_NET_ADDR [ Upstream commit ec518f21cb1a1b1f8a516499ea05c60299e04963 ] Before syzbot/KMSAN bites, add the missing policy for TIPC_NLA_NET_ADDR Fixes: 27c21416727a ("tipc: add net set to new netlink api") Signed-off-by: Eric Dumazet Cc: Jon Maloy Cc: Ying Xue Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/tipc/netlink.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/net/tipc/netlink.c b/net/tipc/netlink.c index b76f13f6fea1..d4e0bbeee727 100644 --- a/net/tipc/netlink.c +++ b/net/tipc/netlink.c @@ -79,7 +79,8 @@ const struct nla_policy tipc_nl_sock_policy[TIPC_NLA_SOCK_MAX + 1] = { const struct nla_policy tipc_nl_net_policy[TIPC_NLA_NET_MAX + 1] = { [TIPC_NLA_NET_UNSPEC] = { .type = NLA_UNSPEC }, - [TIPC_NLA_NET_ID] = { .type = NLA_U32 } + [TIPC_NLA_NET_ID] = { .type = NLA_U32 }, + [TIPC_NLA_NET_ADDR] = { .type = NLA_U32 }, }; const struct nla_policy tipc_nl_link_policy[TIPC_NLA_LINK_MAX + 1] = { -- GitLab From 88b7895e7c6ddeec0986ec90d6983d655006b796 Mon Sep 17 00:00:00 2001 From: Guillaume Nault Date: Mon, 23 Apr 2018 16:38:27 +0200 Subject: [PATCH 1140/1635] pppoe: check sockaddr length in pppoe_connect() [ Upstream commit a49e2f5d5fb141884452ddb428f551b123d436b5 ] We must validate sockaddr_len, otherwise userspace can pass fewer data than we expect and we end up accessing invalid data. Fixes: 224cf5ad14c0 ("ppp: Move the PPP drivers") Reported-by: syzbot+4f03bdf92fdf9ef5ddab@syzkaller.appspotmail.com Signed-off-by: Guillaume Nault Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/ppp/pppoe.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/net/ppp/pppoe.c b/drivers/net/ppp/pppoe.c index 5aa59f41bf8c..71e2aef6b7a1 100644 --- a/drivers/net/ppp/pppoe.c +++ b/drivers/net/ppp/pppoe.c @@ -620,6 +620,10 @@ static int pppoe_connect(struct socket *sock, struct sockaddr *uservaddr, lock_sock(sk); error = -EINVAL; + + if (sockaddr_len != sizeof(struct sockaddr_pppox)) + goto end; + if (sp->sa_protocol != PX_PROTO_OE) goto end; -- GitLab From dd997151740f1abcd13aaa3da719f712cf959759 Mon Sep 17 00:00:00 2001 From: Toshiaki Makita Date: Tue, 17 Apr 2018 18:46:14 +0900 Subject: [PATCH 1141/1635] vlan: Fix reading memory beyond skb->tail in skb_vlan_tagged_multi [ Upstream commit 7ce2367254e84753bceb07327aaf5c953cfce117 ] Syzkaller spotted an old bug which leads to reading skb beyond tail by 4 bytes on vlan tagged packets. This is caused because skb_vlan_tagged_multi() did not check skb_headlen. BUG: KMSAN: uninit-value in eth_type_vlan include/linux/if_vlan.h:283 [inline] BUG: KMSAN: uninit-value in skb_vlan_tagged_multi include/linux/if_vlan.h:656 [inline] BUG: KMSAN: uninit-value in vlan_features_check include/linux/if_vlan.h:672 [inline] BUG: KMSAN: uninit-value in dflt_features_check net/core/dev.c:2949 [inline] BUG: KMSAN: uninit-value in netif_skb_features+0xd1b/0xdc0 net/core/dev.c:3009 CPU: 1 PID: 3582 Comm: syzkaller435149 Not tainted 4.16.0+ #82 Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/01/2011 Call Trace: __dump_stack lib/dump_stack.c:17 [inline] dump_stack+0x185/0x1d0 lib/dump_stack.c:53 kmsan_report+0x142/0x240 mm/kmsan/kmsan.c:1067 __msan_warning_32+0x6c/0xb0 mm/kmsan/kmsan_instr.c:676 eth_type_vlan include/linux/if_vlan.h:283 [inline] skb_vlan_tagged_multi include/linux/if_vlan.h:656 [inline] vlan_features_check include/linux/if_vlan.h:672 [inline] dflt_features_check net/core/dev.c:2949 [inline] netif_skb_features+0xd1b/0xdc0 net/core/dev.c:3009 validate_xmit_skb+0x89/0x1320 net/core/dev.c:3084 __dev_queue_xmit+0x1cb2/0x2b60 net/core/dev.c:3549 dev_queue_xmit+0x4b/0x60 net/core/dev.c:3590 packet_snd net/packet/af_packet.c:2944 [inline] packet_sendmsg+0x7c57/0x8a10 net/packet/af_packet.c:2969 sock_sendmsg_nosec net/socket.c:630 [inline] sock_sendmsg net/socket.c:640 [inline] sock_write_iter+0x3b9/0x470 net/socket.c:909 do_iter_readv_writev+0x7bb/0x970 include/linux/fs.h:1776 do_iter_write+0x30d/0xd40 fs/read_write.c:932 vfs_writev fs/read_write.c:977 [inline] do_writev+0x3c9/0x830 fs/read_write.c:1012 SYSC_writev+0x9b/0xb0 fs/read_write.c:1085 SyS_writev+0x56/0x80 fs/read_write.c:1082 do_syscall_64+0x309/0x430 arch/x86/entry/common.c:287 entry_SYSCALL_64_after_hwframe+0x3d/0xa2 RIP: 0033:0x43ffa9 RSP: 002b:00007fff2cff3948 EFLAGS: 00000217 ORIG_RAX: 0000000000000014 RAX: ffffffffffffffda RBX: 00000000004002c8 RCX: 000000000043ffa9 RDX: 0000000000000001 RSI: 0000000020000080 RDI: 0000000000000003 RBP: 00000000006cb018 R08: 0000000000000000 R09: 0000000000000000 R10: 0000000000000000 R11: 0000000000000217 R12: 00000000004018d0 R13: 0000000000401960 R14: 0000000000000000 R15: 0000000000000000 Uninit was created at: kmsan_save_stack_with_flags mm/kmsan/kmsan.c:278 [inline] kmsan_internal_poison_shadow+0xb8/0x1b0 mm/kmsan/kmsan.c:188 kmsan_kmalloc+0x94/0x100 mm/kmsan/kmsan.c:314 kmsan_slab_alloc+0x11/0x20 mm/kmsan/kmsan.c:321 slab_post_alloc_hook mm/slab.h:445 [inline] slab_alloc_node mm/slub.c:2737 [inline] __kmalloc_node_track_caller+0xaed/0x11c0 mm/slub.c:4369 __kmalloc_reserve net/core/skbuff.c:138 [inline] __alloc_skb+0x2cf/0x9f0 net/core/skbuff.c:206 alloc_skb include/linux/skbuff.h:984 [inline] alloc_skb_with_frags+0x1d4/0xb20 net/core/skbuff.c:5234 sock_alloc_send_pskb+0xb56/0x1190 net/core/sock.c:2085 packet_alloc_skb net/packet/af_packet.c:2803 [inline] packet_snd net/packet/af_packet.c:2894 [inline] packet_sendmsg+0x6444/0x8a10 net/packet/af_packet.c:2969 sock_sendmsg_nosec net/socket.c:630 [inline] sock_sendmsg net/socket.c:640 [inline] sock_write_iter+0x3b9/0x470 net/socket.c:909 do_iter_readv_writev+0x7bb/0x970 include/linux/fs.h:1776 do_iter_write+0x30d/0xd40 fs/read_write.c:932 vfs_writev fs/read_write.c:977 [inline] do_writev+0x3c9/0x830 fs/read_write.c:1012 SYSC_writev+0x9b/0xb0 fs/read_write.c:1085 SyS_writev+0x56/0x80 fs/read_write.c:1082 do_syscall_64+0x309/0x430 arch/x86/entry/common.c:287 entry_SYSCALL_64_after_hwframe+0x3d/0xa2 Fixes: 58e998c6d239 ("offloading: Force software GSO for multiple vlan tags.") Reported-and-tested-by: syzbot+0bbe42c764feafa82c5a@syzkaller.appspotmail.com Signed-off-by: Toshiaki Makita Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- include/linux/if_vlan.h | 7 +++++-- net/core/dev.c | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/include/linux/if_vlan.h b/include/linux/if_vlan.h index 5e6a2d4dc366..ab927383c99d 100644 --- a/include/linux/if_vlan.h +++ b/include/linux/if_vlan.h @@ -584,7 +584,7 @@ static inline bool skb_vlan_tagged(const struct sk_buff *skb) * Returns true if the skb is tagged with multiple vlan headers, regardless * of whether it is hardware accelerated or not. */ -static inline bool skb_vlan_tagged_multi(const struct sk_buff *skb) +static inline bool skb_vlan_tagged_multi(struct sk_buff *skb) { __be16 protocol = skb->protocol; @@ -594,6 +594,9 @@ static inline bool skb_vlan_tagged_multi(const struct sk_buff *skb) if (likely(!eth_type_vlan(protocol))) return false; + if (unlikely(!pskb_may_pull(skb, VLAN_ETH_HLEN))) + return false; + veh = (struct vlan_ethhdr *)skb->data; protocol = veh->h_vlan_encapsulated_proto; } @@ -611,7 +614,7 @@ static inline bool skb_vlan_tagged_multi(const struct sk_buff *skb) * * Returns features without unsafe ones if the skb has multiple tags. */ -static inline netdev_features_t vlan_features_check(const struct sk_buff *skb, +static inline netdev_features_t vlan_features_check(struct sk_buff *skb, netdev_features_t features) { if (skb_vlan_tagged_multi(skb)) { diff --git a/net/core/dev.c b/net/core/dev.c index 4be2a4047640..e7d56c5adde6 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -2903,7 +2903,7 @@ netdev_features_t passthru_features_check(struct sk_buff *skb, } EXPORT_SYMBOL(passthru_features_check); -static netdev_features_t dflt_features_check(const struct sk_buff *skb, +static netdev_features_t dflt_features_check(struct sk_buff *skb, struct net_device *dev, netdev_features_t features) { -- GitLab From f42036e8051e75e4a74aa4f9bec53631c5981da5 Mon Sep 17 00:00:00 2001 From: Tom Lendacky Date: Mon, 23 Apr 2018 11:43:08 -0500 Subject: [PATCH 1142/1635] amd-xgbe: Add pre/post auto-negotiation phy hooks [ Upstream commit 4d945663a6a0acf3cbe45940503f2eb9584bfee7 ] Add hooks to the driver auto-negotiation (AN) flow to allow the different phy implementations to perform any steps necessary to improve AN. Signed-off-by: Tom Lendacky Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/amd/xgbe/xgbe-mdio.c | 16 ++++++++++++++-- drivers/net/ethernet/amd/xgbe/xgbe.h | 5 +++++ 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c b/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c index 072b9f664597..e3d361e242aa 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c @@ -437,6 +437,9 @@ static void xgbe_an73_disable(struct xgbe_prv_data *pdata) static void xgbe_an_restart(struct xgbe_prv_data *pdata) { + if (pdata->phy_if.phy_impl.an_pre) + pdata->phy_if.phy_impl.an_pre(pdata); + switch (pdata->an_mode) { case XGBE_AN_MODE_CL73: case XGBE_AN_MODE_CL73_REDRV: @@ -453,6 +456,9 @@ static void xgbe_an_restart(struct xgbe_prv_data *pdata) static void xgbe_an_disable(struct xgbe_prv_data *pdata) { + if (pdata->phy_if.phy_impl.an_post) + pdata->phy_if.phy_impl.an_post(pdata); + switch (pdata->an_mode) { case XGBE_AN_MODE_CL73: case XGBE_AN_MODE_CL73_REDRV: @@ -637,11 +643,11 @@ static enum xgbe_an xgbe_an73_incompat_link(struct xgbe_prv_data *pdata) return XGBE_AN_NO_LINK; } - xgbe_an73_disable(pdata); + xgbe_an_disable(pdata); xgbe_switch_mode(pdata); - xgbe_an73_restart(pdata); + xgbe_an_restart(pdata); return XGBE_AN_INCOMPAT_LINK; } @@ -820,6 +826,9 @@ static void xgbe_an37_state_machine(struct xgbe_prv_data *pdata) pdata->an_result = pdata->an_state; pdata->an_state = XGBE_AN_READY; + if (pdata->phy_if.phy_impl.an_post) + pdata->phy_if.phy_impl.an_post(pdata); + netif_dbg(pdata, link, pdata->netdev, "CL37 AN result: %s\n", xgbe_state_as_string(pdata->an_result)); } @@ -903,6 +912,9 @@ static void xgbe_an73_state_machine(struct xgbe_prv_data *pdata) pdata->kx_state = XGBE_RX_BPA; pdata->an_start = 0; + if (pdata->phy_if.phy_impl.an_post) + pdata->phy_if.phy_impl.an_post(pdata); + netif_dbg(pdata, link, pdata->netdev, "CL73 AN result: %s\n", xgbe_state_as_string(pdata->an_result)); } diff --git a/drivers/net/ethernet/amd/xgbe/xgbe.h b/drivers/net/ethernet/amd/xgbe/xgbe.h index ad102c8bac7b..fa0b51ea1b95 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe.h +++ b/drivers/net/ethernet/amd/xgbe/xgbe.h @@ -833,6 +833,7 @@ struct xgbe_hw_if { /* This structure represents implementation specific routines for an * implementation of a PHY. All routines are required unless noted below. * Optional routines: + * an_pre, an_post * kr_training_pre, kr_training_post */ struct xgbe_phy_impl_if { @@ -875,6 +876,10 @@ struct xgbe_phy_impl_if { /* Process results of auto-negotiation */ enum xgbe_mode (*an_outcome)(struct xgbe_prv_data *); + /* Pre/Post auto-negotiation support */ + void (*an_pre)(struct xgbe_prv_data *); + void (*an_post)(struct xgbe_prv_data *); + /* Pre/Post KR training enablement support */ void (*kr_training_pre)(struct xgbe_prv_data *); void (*kr_training_post)(struct xgbe_prv_data *); -- GitLab From 29b623b60549d5897af0842bf439d897de0560d8 Mon Sep 17 00:00:00 2001 From: Xin Long Date: Thu, 12 Apr 2018 14:24:31 +0800 Subject: [PATCH 1143/1635] sctp: do not check port in sctp_inet6_cmp_addr [ Upstream commit 1071ec9d453a38023579714b64a951a2fb982071 ] pf->cmp_addr() is called before binding a v6 address to the sock. It should not check ports, like in sctp_inet_cmp_addr. But sctp_inet6_cmp_addr checks the addr by invoking af(6)->cmp_addr, sctp_v6_cmp_addr where it also compares the ports. This would cause that setsockopt(SCTP_SOCKOPT_BINDX_ADD) could bind multiple duplicated IPv6 addresses after Commit 40b4f0fd74e4 ("sctp: lack the check for ports in sctp_v6_cmp_addr"). This patch is to remove af->cmp_addr called in sctp_inet6_cmp_addr, but do the proper check for both v6 addrs and v4mapped addrs. v1->v2: - define __sctp_v6_cmp_addr to do the common address comparison used for both pf and af v6 cmp_addr. Fixes: 40b4f0fd74e4 ("sctp: lack the check for ports in sctp_v6_cmp_addr") Reported-by: Jianwen Ji Signed-off-by: Xin Long Acked-by: Neil Horman Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/sctp/ipv6.c | 60 ++++++++++++++++++++++++------------------------- 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c index 08b5705e7381..7219a1c041f7 100644 --- a/net/sctp/ipv6.c +++ b/net/sctp/ipv6.c @@ -521,46 +521,49 @@ static void sctp_v6_to_addr(union sctp_addr *addr, struct in6_addr *saddr, addr->v6.sin6_scope_id = 0; } -/* Compare addresses exactly. - * v4-mapped-v6 is also in consideration. - */ -static int sctp_v6_cmp_addr(const union sctp_addr *addr1, - const union sctp_addr *addr2) +static int __sctp_v6_cmp_addr(const union sctp_addr *addr1, + const union sctp_addr *addr2) { if (addr1->sa.sa_family != addr2->sa.sa_family) { if (addr1->sa.sa_family == AF_INET && addr2->sa.sa_family == AF_INET6 && - ipv6_addr_v4mapped(&addr2->v6.sin6_addr)) { - if (addr2->v6.sin6_port == addr1->v4.sin_port && - addr2->v6.sin6_addr.s6_addr32[3] == - addr1->v4.sin_addr.s_addr) - return 1; - } + ipv6_addr_v4mapped(&addr2->v6.sin6_addr) && + addr2->v6.sin6_addr.s6_addr32[3] == + addr1->v4.sin_addr.s_addr) + return 1; + if (addr2->sa.sa_family == AF_INET && addr1->sa.sa_family == AF_INET6 && - ipv6_addr_v4mapped(&addr1->v6.sin6_addr)) { - if (addr1->v6.sin6_port == addr2->v4.sin_port && - addr1->v6.sin6_addr.s6_addr32[3] == - addr2->v4.sin_addr.s_addr) - return 1; - } + ipv6_addr_v4mapped(&addr1->v6.sin6_addr) && + addr1->v6.sin6_addr.s6_addr32[3] == + addr2->v4.sin_addr.s_addr) + return 1; + return 0; } - if (addr1->v6.sin6_port != addr2->v6.sin6_port) - return 0; + if (!ipv6_addr_equal(&addr1->v6.sin6_addr, &addr2->v6.sin6_addr)) return 0; + /* If this is a linklocal address, compare the scope_id. */ - if (ipv6_addr_type(&addr1->v6.sin6_addr) & IPV6_ADDR_LINKLOCAL) { - if (addr1->v6.sin6_scope_id && addr2->v6.sin6_scope_id && - (addr1->v6.sin6_scope_id != addr2->v6.sin6_scope_id)) { - return 0; - } - } + if ((ipv6_addr_type(&addr1->v6.sin6_addr) & IPV6_ADDR_LINKLOCAL) && + addr1->v6.sin6_scope_id && addr2->v6.sin6_scope_id && + addr1->v6.sin6_scope_id != addr2->v6.sin6_scope_id) + return 0; return 1; } +/* Compare addresses exactly. + * v4-mapped-v6 is also in consideration. + */ +static int sctp_v6_cmp_addr(const union sctp_addr *addr1, + const union sctp_addr *addr2) +{ + return __sctp_v6_cmp_addr(addr1, addr2) && + addr1->v6.sin6_port == addr2->v6.sin6_port; +} + /* Initialize addr struct to INADDR_ANY. */ static void sctp_v6_inaddr_any(union sctp_addr *addr, __be16 port) { @@ -845,8 +848,8 @@ static int sctp_inet6_cmp_addr(const union sctp_addr *addr1, const union sctp_addr *addr2, struct sctp_sock *opt) { - struct sctp_af *af1, *af2; struct sock *sk = sctp_opt2sk(opt); + struct sctp_af *af1, *af2; af1 = sctp_get_af_specific(addr1->sa.sa_family); af2 = sctp_get_af_specific(addr2->sa.sa_family); @@ -862,10 +865,7 @@ static int sctp_inet6_cmp_addr(const union sctp_addr *addr1, if (sctp_is_any(sk, addr1) || sctp_is_any(sk, addr2)) return 1; - if (addr1->sa.sa_family != addr2->sa.sa_family) - return 0; - - return af1->cmp_addr(addr1, addr2); + return __sctp_v6_cmp_addr(addr1, addr2); } /* Verify that the provided sockaddr looks bindable. Common verification, -- GitLab From 346ba2f22107ad3aa6769cf4abcf564bea920e41 Mon Sep 17 00:00:00 2001 From: Tom Lendacky Date: Mon, 23 Apr 2018 11:43:17 -0500 Subject: [PATCH 1144/1635] amd-xgbe: Improve KR auto-negotiation and training [ Upstream commit 96f4d430c507ed4856048c2dc9c1a2ea5b5e74e4 ] Update xgbe-phy-v2.c to make use of the auto-negotiation (AN) phy hooks to improve the ability to successfully complete Clause 73 AN when running at 10gbps. Hardware can sometimes have issues with CDR lock when the AN DME page exchange is being performed. The AN and KR training hooks are used as follows: - The pre AN hook is used to disable CDR tracking in the PHY so that the DME page exchange can be successfully and consistently completed. - The post KR training hook is used to re-enable the CDR tracking so that KR training can successfully complete. - The post AN hook is used to check for an unsuccessful AN which will increase a CDR tracking enablement delay (up to a maximum value). Add two debugfs entries to allow control over use of the CDR tracking workaround. The debugfs entries allow the CDR tracking workaround to be disabled and determine whether to re-enable CDR tracking before or after link training has been initiated. Also, with these changes the receiver reset cycle that is performed during the link status check can be performed less often. Signed-off-by: Tom Lendacky Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/amd/xgbe/xgbe-common.h | 8 ++ drivers/net/ethernet/amd/xgbe/xgbe-debugfs.c | 16 +++ drivers/net/ethernet/amd/xgbe/xgbe-main.c | 1 + drivers/net/ethernet/amd/xgbe/xgbe-mdio.c | 8 +- drivers/net/ethernet/amd/xgbe/xgbe-pci.c | 2 + drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c | 125 ++++++++++++++++++- drivers/net/ethernet/amd/xgbe/xgbe.h | 4 + 7 files changed, 160 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-common.h b/drivers/net/ethernet/amd/xgbe/xgbe-common.h index 7ea72ef11a55..d272dc6984ac 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-common.h +++ b/drivers/net/ethernet/amd/xgbe/xgbe-common.h @@ -1321,6 +1321,10 @@ #define MDIO_VEND2_AN_STAT 0x8002 #endif +#ifndef MDIO_VEND2_PMA_CDR_CONTROL +#define MDIO_VEND2_PMA_CDR_CONTROL 0x8056 +#endif + #ifndef MDIO_CTRL1_SPEED1G #define MDIO_CTRL1_SPEED1G (MDIO_CTRL1_SPEED10G & ~BMCR_SPEED100) #endif @@ -1369,6 +1373,10 @@ #define XGBE_AN_CL37_TX_CONFIG_MASK 0x08 #define XGBE_AN_CL37_MII_CTRL_8BIT 0x0100 +#define XGBE_PMA_CDR_TRACK_EN_MASK 0x01 +#define XGBE_PMA_CDR_TRACK_EN_OFF 0x00 +#define XGBE_PMA_CDR_TRACK_EN_ON 0x01 + /* Bit setting and getting macros * The get macro will extract the current bit field value from within * the variable diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-debugfs.c b/drivers/net/ethernet/amd/xgbe/xgbe-debugfs.c index 7d128be61310..b91143947ed2 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-debugfs.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-debugfs.c @@ -519,6 +519,22 @@ void xgbe_debugfs_init(struct xgbe_prv_data *pdata) "debugfs_create_file failed\n"); } + if (pdata->vdata->an_cdr_workaround) { + pfile = debugfs_create_bool("an_cdr_workaround", 0600, + pdata->xgbe_debugfs, + &pdata->debugfs_an_cdr_workaround); + if (!pfile) + netdev_err(pdata->netdev, + "debugfs_create_bool failed\n"); + + pfile = debugfs_create_bool("an_cdr_track_early", 0600, + pdata->xgbe_debugfs, + &pdata->debugfs_an_cdr_track_early); + if (!pfile) + netdev_err(pdata->netdev, + "debugfs_create_bool failed\n"); + } + kfree(buf); } diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-main.c b/drivers/net/ethernet/amd/xgbe/xgbe-main.c index d91fa595be98..e31d9d1fb6a6 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-main.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-main.c @@ -349,6 +349,7 @@ int xgbe_config_netdev(struct xgbe_prv_data *pdata) XGMAC_SET_BITS(pdata->rss_options, MAC_RSSCR, UDP4TE, 1); /* Call MDIO/PHY initialization routine */ + pdata->debugfs_an_cdr_workaround = pdata->vdata->an_cdr_workaround; ret = pdata->phy_if.phy_init(pdata); if (ret) return ret; diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c b/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c index e3d361e242aa..1b45cd73a258 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c @@ -432,6 +432,8 @@ static void xgbe_an73_disable(struct xgbe_prv_data *pdata) xgbe_an73_set(pdata, false, false); xgbe_an73_disable_interrupts(pdata); + pdata->an_start = 0; + netif_dbg(pdata, link, pdata->netdev, "CL73 AN disabled\n"); } @@ -511,11 +513,11 @@ static enum xgbe_an xgbe_an73_tx_training(struct xgbe_prv_data *pdata, XMDIO_WRITE(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_PMD_CTRL, reg); - if (pdata->phy_if.phy_impl.kr_training_post) - pdata->phy_if.phy_impl.kr_training_post(pdata); - netif_dbg(pdata, link, pdata->netdev, "KR training initiated\n"); + + if (pdata->phy_if.phy_impl.kr_training_post) + pdata->phy_if.phy_impl.kr_training_post(pdata); } return XGBE_AN_PAGE_RECEIVED; diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-pci.c b/drivers/net/ethernet/amd/xgbe/xgbe-pci.c index eb23f9ba1a9a..82d1f416ee2a 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-pci.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-pci.c @@ -456,6 +456,7 @@ static const struct xgbe_version_data xgbe_v2a = { .irq_reissue_support = 1, .tx_desc_prefetch = 5, .rx_desc_prefetch = 5, + .an_cdr_workaround = 1, }; static const struct xgbe_version_data xgbe_v2b = { @@ -470,6 +471,7 @@ static const struct xgbe_version_data xgbe_v2b = { .irq_reissue_support = 1, .tx_desc_prefetch = 5, .rx_desc_prefetch = 5, + .an_cdr_workaround = 1, }; static const struct pci_device_id xgbe_pci_table[] = { diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c b/drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c index 3304a291aa96..b48efc04c4da 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c @@ -147,6 +147,14 @@ /* Rate-change complete wait/retry count */ #define XGBE_RATECHANGE_COUNT 500 +/* CDR delay values for KR support (in usec) */ +#define XGBE_CDR_DELAY_INIT 10000 +#define XGBE_CDR_DELAY_INC 10000 +#define XGBE_CDR_DELAY_MAX 100000 + +/* RRC frequency during link status check */ +#define XGBE_RRC_FREQUENCY 10 + enum xgbe_port_mode { XGBE_PORT_MODE_RSVD = 0, XGBE_PORT_MODE_BACKPLANE, @@ -355,6 +363,10 @@ struct xgbe_phy_data { unsigned int redrv_addr; unsigned int redrv_lane; unsigned int redrv_model; + + /* KR AN support */ + unsigned int phy_cdr_notrack; + unsigned int phy_cdr_delay; }; /* I2C, MDIO and GPIO lines are muxed, so only one device at a time */ @@ -2361,7 +2373,7 @@ static int xgbe_phy_link_status(struct xgbe_prv_data *pdata, int *an_restart) return 1; /* No link, attempt a receiver reset cycle */ - if (phy_data->rrc_count++) { + if (phy_data->rrc_count++ > XGBE_RRC_FREQUENCY) { phy_data->rrc_count = 0; xgbe_phy_rrc(pdata); } @@ -2669,6 +2681,103 @@ static bool xgbe_phy_port_enabled(struct xgbe_prv_data *pdata) return true; } +static void xgbe_phy_cdr_track(struct xgbe_prv_data *pdata) +{ + struct xgbe_phy_data *phy_data = pdata->phy_data; + + if (!pdata->debugfs_an_cdr_workaround) + return; + + if (!phy_data->phy_cdr_notrack) + return; + + usleep_range(phy_data->phy_cdr_delay, + phy_data->phy_cdr_delay + 500); + + XMDIO_WRITE_BITS(pdata, MDIO_MMD_PMAPMD, MDIO_VEND2_PMA_CDR_CONTROL, + XGBE_PMA_CDR_TRACK_EN_MASK, + XGBE_PMA_CDR_TRACK_EN_ON); + + phy_data->phy_cdr_notrack = 0; +} + +static void xgbe_phy_cdr_notrack(struct xgbe_prv_data *pdata) +{ + struct xgbe_phy_data *phy_data = pdata->phy_data; + + if (!pdata->debugfs_an_cdr_workaround) + return; + + if (phy_data->phy_cdr_notrack) + return; + + XMDIO_WRITE_BITS(pdata, MDIO_MMD_PMAPMD, MDIO_VEND2_PMA_CDR_CONTROL, + XGBE_PMA_CDR_TRACK_EN_MASK, + XGBE_PMA_CDR_TRACK_EN_OFF); + + xgbe_phy_rrc(pdata); + + phy_data->phy_cdr_notrack = 1; +} + +static void xgbe_phy_kr_training_post(struct xgbe_prv_data *pdata) +{ + if (!pdata->debugfs_an_cdr_track_early) + xgbe_phy_cdr_track(pdata); +} + +static void xgbe_phy_kr_training_pre(struct xgbe_prv_data *pdata) +{ + if (pdata->debugfs_an_cdr_track_early) + xgbe_phy_cdr_track(pdata); +} + +static void xgbe_phy_an_post(struct xgbe_prv_data *pdata) +{ + struct xgbe_phy_data *phy_data = pdata->phy_data; + + switch (pdata->an_mode) { + case XGBE_AN_MODE_CL73: + case XGBE_AN_MODE_CL73_REDRV: + if (phy_data->cur_mode != XGBE_MODE_KR) + break; + + xgbe_phy_cdr_track(pdata); + + switch (pdata->an_result) { + case XGBE_AN_READY: + case XGBE_AN_COMPLETE: + break; + default: + if (phy_data->phy_cdr_delay < XGBE_CDR_DELAY_MAX) + phy_data->phy_cdr_delay += XGBE_CDR_DELAY_INC; + else + phy_data->phy_cdr_delay = XGBE_CDR_DELAY_INIT; + break; + } + break; + default: + break; + } +} + +static void xgbe_phy_an_pre(struct xgbe_prv_data *pdata) +{ + struct xgbe_phy_data *phy_data = pdata->phy_data; + + switch (pdata->an_mode) { + case XGBE_AN_MODE_CL73: + case XGBE_AN_MODE_CL73_REDRV: + if (phy_data->cur_mode != XGBE_MODE_KR) + break; + + xgbe_phy_cdr_notrack(pdata); + break; + default: + break; + } +} + static void xgbe_phy_stop(struct xgbe_prv_data *pdata) { struct xgbe_phy_data *phy_data = pdata->phy_data; @@ -2680,6 +2789,9 @@ static void xgbe_phy_stop(struct xgbe_prv_data *pdata) xgbe_phy_sfp_reset(phy_data); xgbe_phy_sfp_mod_absent(pdata); + /* Reset CDR support */ + xgbe_phy_cdr_track(pdata); + /* Power off the PHY */ xgbe_phy_power_off(pdata); @@ -2712,6 +2824,9 @@ static int xgbe_phy_start(struct xgbe_prv_data *pdata) /* Start in highest supported mode */ xgbe_phy_set_mode(pdata, phy_data->start_mode); + /* Reset CDR support */ + xgbe_phy_cdr_track(pdata); + /* After starting the I2C controller, we can check for an SFP */ switch (phy_data->port_mode) { case XGBE_PORT_MODE_SFP: @@ -3019,6 +3134,8 @@ static int xgbe_phy_init(struct xgbe_prv_data *pdata) } } + phy_data->phy_cdr_delay = XGBE_CDR_DELAY_INIT; + /* Register for driving external PHYs */ mii = devm_mdiobus_alloc(pdata->dev); if (!mii) { @@ -3071,4 +3188,10 @@ void xgbe_init_function_ptrs_phy_v2(struct xgbe_phy_if *phy_if) phy_impl->an_advertising = xgbe_phy_an_advertising; phy_impl->an_outcome = xgbe_phy_an_outcome; + + phy_impl->an_pre = xgbe_phy_an_pre; + phy_impl->an_post = xgbe_phy_an_post; + + phy_impl->kr_training_pre = xgbe_phy_kr_training_pre; + phy_impl->kr_training_post = xgbe_phy_kr_training_post; } diff --git a/drivers/net/ethernet/amd/xgbe/xgbe.h b/drivers/net/ethernet/amd/xgbe/xgbe.h index fa0b51ea1b95..95d4b56448c6 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe.h +++ b/drivers/net/ethernet/amd/xgbe/xgbe.h @@ -994,6 +994,7 @@ struct xgbe_version_data { unsigned int irq_reissue_support; unsigned int tx_desc_prefetch; unsigned int rx_desc_prefetch; + unsigned int an_cdr_workaround; }; struct xgbe_vxlan_data { @@ -1262,6 +1263,9 @@ struct xgbe_prv_data { unsigned int debugfs_xprop_reg; unsigned int debugfs_xi2c_reg; + + bool debugfs_an_cdr_workaround; + bool debugfs_an_cdr_track_early; }; /* Function prototypes*/ -- GitLab From 9a66123182a64083b5f8606dcdd7963e48b90d62 Mon Sep 17 00:00:00 2001 From: Doron Roberts-Kedes Date: Fri, 20 Apr 2018 12:11:11 -0700 Subject: [PATCH 1145/1635] strparser: Do not call mod_delayed_work with a timeout of LONG_MAX [ Upstream commit 7c5aba211dd61f41d737a2c51729eb9fdcd3edf4 ] struct sock's sk_rcvtimeo is initialized to LONG_MAX/MAX_SCHEDULE_TIMEOUT in sock_init_data. Calling mod_delayed_work with a timeout of LONG_MAX causes spurious execution of the work function. timer->expires is set equal to jiffies + LONG_MAX. When timer_base->clk falls behind the current value of jiffies, the delta between timer_base->clk and jiffies + LONG_MAX causes the expiration to be in the past. Returning early from strp_start_timer if timeo == LONG_MAX solves this problem. Found while testing net/tls_sw recv path. Fixes: 43a0c6751a322847 ("strparser: Stream parser for messages") Reviewed-by: Tejun Heo Signed-off-by: Doron Roberts-Kedes Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/strparser/strparser.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/strparser/strparser.c b/net/strparser/strparser.c index 4a3a3f1331ee..6b5a7fffc62c 100644 --- a/net/strparser/strparser.c +++ b/net/strparser/strparser.c @@ -67,7 +67,7 @@ static void strp_abort_strp(struct strparser *strp, int err) static void strp_start_timer(struct strparser *strp, long timeo) { - if (timeo) + if (timeo && timeo != LONG_MAX) mod_delayed_work(strp_wq, &strp->msg_timer_work, timeo); } -- GitLab From 109feb04c85152dcff5c9922760dacd1b89b7ddd Mon Sep 17 00:00:00 2001 From: Tom Lendacky Date: Mon, 23 Apr 2018 11:43:34 -0500 Subject: [PATCH 1146/1635] amd-xgbe: Only use the SFP supported transceiver signals [ Upstream commit 117df655f8ed51adb6e6b163812a06ebeae9f453 ] The SFP eeprom indicates the transceiver signals (Rx LOS, Tx Fault, etc.) that it supports. Update the driver to include checking the eeprom data when deciding whether to use a transceiver signal. Signed-off-by: Tom Lendacky Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c | 71 ++++++++++++++++----- 1 file changed, 54 insertions(+), 17 deletions(-) diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c b/drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c index b48efc04c4da..aac884314000 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c @@ -253,6 +253,10 @@ enum xgbe_sfp_speed { #define XGBE_SFP_BASE_VENDOR_SN 4 #define XGBE_SFP_BASE_VENDOR_SN_LEN 16 +#define XGBE_SFP_EXTD_OPT1 1 +#define XGBE_SFP_EXTD_OPT1_RX_LOS BIT(1) +#define XGBE_SFP_EXTD_OPT1_TX_FAULT BIT(3) + #define XGBE_SFP_EXTD_DIAG 28 #define XGBE_SFP_EXTD_DIAG_ADDR_CHANGE BIT(2) @@ -332,6 +336,7 @@ struct xgbe_phy_data { unsigned int sfp_gpio_address; unsigned int sfp_gpio_mask; + unsigned int sfp_gpio_inputs; unsigned int sfp_gpio_rx_los; unsigned int sfp_gpio_tx_fault; unsigned int sfp_gpio_mod_absent; @@ -986,6 +991,49 @@ static void xgbe_phy_sfp_external_phy(struct xgbe_prv_data *pdata) phy_data->sfp_phy_avail = 1; } +static bool xgbe_phy_check_sfp_rx_los(struct xgbe_phy_data *phy_data) +{ + u8 *sfp_extd = phy_data->sfp_eeprom.extd; + + if (!(sfp_extd[XGBE_SFP_EXTD_OPT1] & XGBE_SFP_EXTD_OPT1_RX_LOS)) + return false; + + if (phy_data->sfp_gpio_mask & XGBE_GPIO_NO_RX_LOS) + return false; + + if (phy_data->sfp_gpio_inputs & (1 << phy_data->sfp_gpio_rx_los)) + return true; + + return false; +} + +static bool xgbe_phy_check_sfp_tx_fault(struct xgbe_phy_data *phy_data) +{ + u8 *sfp_extd = phy_data->sfp_eeprom.extd; + + if (!(sfp_extd[XGBE_SFP_EXTD_OPT1] & XGBE_SFP_EXTD_OPT1_TX_FAULT)) + return false; + + if (phy_data->sfp_gpio_mask & XGBE_GPIO_NO_TX_FAULT) + return false; + + if (phy_data->sfp_gpio_inputs & (1 << phy_data->sfp_gpio_tx_fault)) + return true; + + return false; +} + +static bool xgbe_phy_check_sfp_mod_absent(struct xgbe_phy_data *phy_data) +{ + if (phy_data->sfp_gpio_mask & XGBE_GPIO_NO_MOD_ABSENT) + return false; + + if (phy_data->sfp_gpio_inputs & (1 << phy_data->sfp_gpio_mod_absent)) + return true; + + return false; +} + static bool xgbe_phy_belfuse_parse_quirks(struct xgbe_prv_data *pdata) { struct xgbe_phy_data *phy_data = pdata->phy_data; @@ -1031,6 +1079,10 @@ static void xgbe_phy_sfp_parse_eeprom(struct xgbe_prv_data *pdata) if (sfp_base[XGBE_SFP_BASE_EXT_ID] != XGBE_SFP_EXT_ID_SFP) return; + /* Update transceiver signals (eeprom extd/options) */ + phy_data->sfp_tx_fault = xgbe_phy_check_sfp_tx_fault(phy_data); + phy_data->sfp_rx_los = xgbe_phy_check_sfp_rx_los(phy_data); + if (xgbe_phy_sfp_parse_quirks(pdata)) return; @@ -1196,7 +1248,6 @@ static int xgbe_phy_sfp_read_eeprom(struct xgbe_prv_data *pdata) static void xgbe_phy_sfp_signals(struct xgbe_prv_data *pdata) { struct xgbe_phy_data *phy_data = pdata->phy_data; - unsigned int gpio_input; u8 gpio_reg, gpio_ports[2]; int ret; @@ -1211,23 +1262,9 @@ static void xgbe_phy_sfp_signals(struct xgbe_prv_data *pdata) return; } - gpio_input = (gpio_ports[1] << 8) | gpio_ports[0]; - - if (phy_data->sfp_gpio_mask & XGBE_GPIO_NO_MOD_ABSENT) { - /* No GPIO, just assume the module is present for now */ - phy_data->sfp_mod_absent = 0; - } else { - if (!(gpio_input & (1 << phy_data->sfp_gpio_mod_absent))) - phy_data->sfp_mod_absent = 0; - } - - if (!(phy_data->sfp_gpio_mask & XGBE_GPIO_NO_RX_LOS) && - (gpio_input & (1 << phy_data->sfp_gpio_rx_los))) - phy_data->sfp_rx_los = 1; + phy_data->sfp_gpio_inputs = (gpio_ports[1] << 8) | gpio_ports[0]; - if (!(phy_data->sfp_gpio_mask & XGBE_GPIO_NO_TX_FAULT) && - (gpio_input & (1 << phy_data->sfp_gpio_tx_fault))) - phy_data->sfp_tx_fault = 1; + phy_data->sfp_mod_absent = xgbe_phy_check_sfp_mod_absent(phy_data); } static void xgbe_phy_sfp_mod_absent(struct xgbe_prv_data *pdata) -- GitLab From 2f781ebfb08ffdc62d3cb82cd9129aba86b8a70e Mon Sep 17 00:00:00 2001 From: Doron Roberts-Kedes Date: Wed, 11 Apr 2018 15:05:16 -0700 Subject: [PATCH 1147/1635] strparser: Fix incorrect strp->need_bytes value. [ Upstream commit 9d0c75bf6e03d9bf80c55b0f677dc9b982958fd5 ] strp_data_ready resets strp->need_bytes to 0 if strp_peek_len indicates that the remainder of the message has been received. However, do_strp_work does not reset strp->need_bytes to 0. If do_strp_work completes a partial message, the value of strp->need_bytes will continue to reflect the needed bytes of the previous message, causing future invocations of strp_data_ready to return early if strp->need_bytes is less than strp_peek_len. Resetting strp->need_bytes to 0 in __strp_recv on handing a full message to the upper layer solves this problem. __strp_recv also calculates strp->need_bytes using stm->accum_len before stm->accum_len has been incremented by cand_len. This can cause strp->need_bytes to be equal to the full length of the message instead of the full length minus the accumulated length. This, in turn, causes strp_data_ready to return early, even when there is sufficient data to complete the partial message. Incrementing stm->accum_len before using it to calculate strp->need_bytes solves this problem. Found while testing net/tls_sw recv path. Fixes: 43a0c6751a322847 ("strparser: Stream parser for messages") Signed-off-by: Doron Roberts-Kedes Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/strparser/strparser.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/net/strparser/strparser.c b/net/strparser/strparser.c index 6b5a7fffc62c..c741365f77da 100644 --- a/net/strparser/strparser.c +++ b/net/strparser/strparser.c @@ -296,9 +296,9 @@ static int __strp_recv(read_descriptor_t *desc, struct sk_buff *orig_skb, strp_start_timer(strp, timeo); } + stm->accum_len += cand_len; strp->need_bytes = stm->strp.full_len - stm->accum_len; - stm->accum_len += cand_len; stm->early_eaten = cand_len; STRP_STATS_ADD(strp->stats.bytes, cand_len); desc->count = 0; /* Stop reading socket */ @@ -321,6 +321,7 @@ static int __strp_recv(read_descriptor_t *desc, struct sk_buff *orig_skb, /* Hurray, we have a new message! */ cancel_delayed_work(&strp->msg_timer_work); strp->skb_head = NULL; + strp->need_bytes = 0; STRP_STATS_INCR(strp->stats.msgs); /* Give skb to upper layer */ @@ -410,9 +411,7 @@ void strp_data_ready(struct strparser *strp) return; if (strp->need_bytes) { - if (strp_peek_len(strp) >= strp->need_bytes) - strp->need_bytes = 0; - else + if (strp_peek_len(strp) < strp->need_bytes) return; } -- GitLab From da499024f6fe0899af76346abc93542494aa9e05 Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Fri, 20 Apr 2018 15:15:03 -0400 Subject: [PATCH 1148/1635] net: sched: ife: signal not finding metaid [ Upstream commit f6cd14537ff9919081be19b9c53b9b19c0d3ea97 ] We need to record stats for received metadata that we dont know how to process. Have find_decode_metaid() return -ENOENT to capture this. Signed-off-by: Alexander Aring Reviewed-by: Yotam Gigi Acked-by: Jamal Hadi Salim Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/sched/act_ife.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/sched/act_ife.c b/net/sched/act_ife.c index 8ccd35825b6b..4b4e4d490f42 100644 --- a/net/sched/act_ife.c +++ b/net/sched/act_ife.c @@ -605,7 +605,7 @@ static int find_decode_metaid(struct sk_buff *skb, struct tcf_ife_info *ife, } } - return 0; + return -ENOENT; } static int tcf_ife_decode(struct sk_buff *skb, const struct tc_action *a, -- GitLab From 75020d6319eec226a5829359a23322a69f1d7525 Mon Sep 17 00:00:00 2001 From: Soheil Hassas Yeganeh Date: Sat, 14 Apr 2018 20:45:20 -0400 Subject: [PATCH 1149/1635] tcp: clear tp->packets_out when purging write queue Clear tp->packets_out when purging the write queue, otherwise tcp_rearm_rto() mistakenly assumes TCP write queue is not empty. This results in NULL pointer dereference. Also, remove the redundant `tp->packets_out = 0` from tcp_disconnect(), since tcp_disconnect() calls tcp_write_queue_purge(). Fixes: a27fd7a8ed38 (tcp: purge write queue upon RST) Reported-by: Subash Abhinov Kasiviswanathan Reported-by: Sami Farin Tested-by: Sami Farin Signed-off-by: Eric Dumazet Signed-off-by: Soheil Hassas Yeganeh Acked-by: Yuchung Cheng Acked-by: Neal Cardwell Signed-off-by: Greg Kroah-Hartman --- include/net/tcp.h | 1 + net/ipv4/tcp.c | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/include/net/tcp.h b/include/net/tcp.h index d323d4fa742c..fb653736f335 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -1616,6 +1616,7 @@ static inline void tcp_write_queue_purge(struct sock *sk) sk_mem_reclaim(sk); tcp_clear_all_retrans_hints(tcp_sk(sk)); tcp_init_send_head(sk); + tcp_sk(sk)->packets_out = 0; } static inline struct sk_buff *tcp_write_queue_head(const struct sock *sk) diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index e8d8140cd33f..d023f879e7bb 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -2354,7 +2354,6 @@ int tcp_disconnect(struct sock *sk, int flags) icsk->icsk_backoff = 0; tp->snd_cwnd = 2; icsk->icsk_probes_out = 0; - tp->packets_out = 0; tp->snd_ssthresh = TCP_INFINITE_SSTHRESH; tp->snd_cwnd_cnt = 0; tp->window_clamp = 0; -- GitLab From 388f3d9708fcc96cea44fe343ffe055e58ba6e6b Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Fri, 20 Apr 2018 15:15:04 -0400 Subject: [PATCH 1150/1635] net: sched: ife: handle malformed tlv length [ Upstream commit cc74eddd0ff325d57373cea99f642b787d7f76f5 ] There is currently no handling to check on a invalid tlv length. This patch adds such handling to avoid killing the kernel with a malformed ife packet. Signed-off-by: Alexander Aring Reviewed-by: Yotam Gigi Acked-by: Jamal Hadi Salim Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- include/net/ife.h | 3 ++- net/ife/ife.c | 35 +++++++++++++++++++++++++++++++++-- net/sched/act_ife.c | 7 ++++++- 3 files changed, 41 insertions(+), 4 deletions(-) diff --git a/include/net/ife.h b/include/net/ife.h index 44b9c00f7223..e117617e3c34 100644 --- a/include/net/ife.h +++ b/include/net/ife.h @@ -12,7 +12,8 @@ void *ife_encode(struct sk_buff *skb, u16 metalen); void *ife_decode(struct sk_buff *skb, u16 *metalen); -void *ife_tlv_meta_decode(void *skbdata, u16 *attrtype, u16 *dlen, u16 *totlen); +void *ife_tlv_meta_decode(void *skbdata, const void *ifehdr_end, u16 *attrtype, + u16 *dlen, u16 *totlen); int ife_tlv_meta_encode(void *skbdata, u16 attrtype, u16 dlen, const void *dval); diff --git a/net/ife/ife.c b/net/ife/ife.c index 7d1ec76e7f43..7fbe70a0af4b 100644 --- a/net/ife/ife.c +++ b/net/ife/ife.c @@ -92,12 +92,43 @@ struct meta_tlvhdr { __be16 len; }; +static bool __ife_tlv_meta_valid(const unsigned char *skbdata, + const unsigned char *ifehdr_end) +{ + const struct meta_tlvhdr *tlv; + u16 tlvlen; + + if (unlikely(skbdata + sizeof(*tlv) > ifehdr_end)) + return false; + + tlv = (const struct meta_tlvhdr *)skbdata; + tlvlen = ntohs(tlv->len); + + /* tlv length field is inc header, check on minimum */ + if (tlvlen < NLA_HDRLEN) + return false; + + /* overflow by NLA_ALIGN check */ + if (NLA_ALIGN(tlvlen) < tlvlen) + return false; + + if (unlikely(skbdata + NLA_ALIGN(tlvlen) > ifehdr_end)) + return false; + + return true; +} + /* Caller takes care of presenting data in network order */ -void *ife_tlv_meta_decode(void *skbdata, u16 *attrtype, u16 *dlen, u16 *totlen) +void *ife_tlv_meta_decode(void *skbdata, const void *ifehdr_end, u16 *attrtype, + u16 *dlen, u16 *totlen) { - struct meta_tlvhdr *tlv = (struct meta_tlvhdr *) skbdata; + struct meta_tlvhdr *tlv; + + if (!__ife_tlv_meta_valid(skbdata, ifehdr_end)) + return NULL; + tlv = (struct meta_tlvhdr *)skbdata; *dlen = ntohs(tlv->len) - NLA_HDRLEN; *attrtype = ntohs(tlv->type); diff --git a/net/sched/act_ife.c b/net/sched/act_ife.c index 4b4e4d490f42..85757af7f150 100644 --- a/net/sched/act_ife.c +++ b/net/sched/act_ife.c @@ -639,7 +639,12 @@ static int tcf_ife_decode(struct sk_buff *skb, const struct tc_action *a, u16 mtype; u16 dlen; - curr_data = ife_tlv_meta_decode(tlv_data, &mtype, &dlen, NULL); + curr_data = ife_tlv_meta_decode(tlv_data, ifehdr_end, &mtype, + &dlen, NULL); + if (!curr_data) { + qstats_drop_inc(this_cpu_ptr(ife->common.cpu_qstats)); + return TC_ACT_SHOT; + } if (find_decode_metaid(skb, ife, mtype, dlen, curr_data)) { /* abuse overlimits to count when we receive metadata -- GitLab From 4c2c574cf6ed0bbbddaac3d78061116230adea11 Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Fri, 20 Apr 2018 15:15:05 -0400 Subject: [PATCH 1151/1635] net: sched: ife: check on metadata length [ Upstream commit d57493d6d1be26c8ac8516a4463bfe24956978eb ] This patch checks if sk buffer is available to dererence ife header. If not then NULL will returned to signal an malformed ife packet. This avoids to crashing the kernel from outside. Signed-off-by: Alexander Aring Reviewed-by: Yotam Gigi Acked-by: Jamal Hadi Salim Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ife/ife.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/net/ife/ife.c b/net/ife/ife.c index 7fbe70a0af4b..13bbf8cb6a39 100644 --- a/net/ife/ife.c +++ b/net/ife/ife.c @@ -69,6 +69,9 @@ void *ife_decode(struct sk_buff *skb, u16 *metalen) int total_pull; u16 ifehdrln; + if (!pskb_may_pull(skb, skb->dev->hard_header_len + IFE_METAHDRLEN)) + return NULL; + ifehdr = (struct ifeheadr *) (skb->data + skb->dev->hard_header_len); ifehdrln = ntohs(ifehdr->metalen); total_pull = skb->dev->hard_header_len + ifehdrln; -- GitLab From 543a60112f019f8968ec6312721f8ccc3f26a0df Mon Sep 17 00:00:00 2001 From: Cong Wang Date: Wed, 18 Apr 2018 11:51:56 -0700 Subject: [PATCH 1152/1635] llc: hold llc_sap before release_sock() [ Upstream commit f7e43672683b097bb074a8fe7af9bc600a23f231 ] syzbot reported we still access llc->sap in llc_backlog_rcv() after it is freed in llc_sap_remove_socket(): Call Trace: __dump_stack lib/dump_stack.c:77 [inline] dump_stack+0x1b9/0x294 lib/dump_stack.c:113 print_address_description+0x6c/0x20b mm/kasan/report.c:256 kasan_report_error mm/kasan/report.c:354 [inline] kasan_report.cold.7+0x242/0x2fe mm/kasan/report.c:412 __asan_report_load1_noabort+0x14/0x20 mm/kasan/report.c:430 llc_conn_ac_send_sabme_cmd_p_set_x+0x3a8/0x460 net/llc/llc_c_ac.c:785 llc_exec_conn_trans_actions net/llc/llc_conn.c:475 [inline] llc_conn_service net/llc/llc_conn.c:400 [inline] llc_conn_state_process+0x4e1/0x13a0 net/llc/llc_conn.c:75 llc_backlog_rcv+0x195/0x1e0 net/llc/llc_conn.c:891 sk_backlog_rcv include/net/sock.h:909 [inline] __release_sock+0x12f/0x3a0 net/core/sock.c:2335 release_sock+0xa4/0x2b0 net/core/sock.c:2850 llc_ui_release+0xc8/0x220 net/llc/af_llc.c:204 llc->sap is refcount'ed and llc_sap_remove_socket() is paired with llc_sap_add_socket(). This can be amended by holding its refcount before llc_sap_remove_socket() and releasing it after release_sock(). Reported-by: Signed-off-by: Cong Wang Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/llc/af_llc.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/net/llc/af_llc.c b/net/llc/af_llc.c index c38d16f22d2a..c8950d88a695 100644 --- a/net/llc/af_llc.c +++ b/net/llc/af_llc.c @@ -189,6 +189,7 @@ static int llc_ui_release(struct socket *sock) { struct sock *sk = sock->sk; struct llc_sock *llc; + struct llc_sap *sap; if (unlikely(sk == NULL)) goto out; @@ -199,9 +200,15 @@ static int llc_ui_release(struct socket *sock) llc->laddr.lsap, llc->daddr.lsap); if (!llc_send_disc(sk)) llc_ui_wait_for_disc(sk, sk->sk_rcvtimeo); + sap = llc->sap; + /* Hold this for release_sock(), so that llc_backlog_rcv() could still + * use it. + */ + llc_sap_hold(sap); if (!sock_flag(sk, SOCK_ZAPPED)) llc_sap_remove_socket(llc->sap, sk); release_sock(sk); + llc_sap_put(sap); if (llc->dev) dev_put(llc->dev); sock_put(sk); -- GitLab From 7814c479de7ae7b36649cd2644287e47eca46b49 Mon Sep 17 00:00:00 2001 From: Cong Wang Date: Thu, 19 Apr 2018 21:54:34 -0700 Subject: [PATCH 1153/1635] llc: fix NULL pointer deref for SOCK_ZAPPED [ Upstream commit 3a04ce7130a7e5dad4e78d45d50313747f8c830f ] For SOCK_ZAPPED socket, we don't need to care about llc->sap, so we should just skip these refcount functions in this case. Fixes: f7e43672683b ("llc: hold llc_sap before release_sock()") Reported-by: kernel test robot Signed-off-by: Cong Wang Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/llc/af_llc.c | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/net/llc/af_llc.c b/net/llc/af_llc.c index c8950d88a695..cf41d9b4a0b8 100644 --- a/net/llc/af_llc.c +++ b/net/llc/af_llc.c @@ -189,7 +189,6 @@ static int llc_ui_release(struct socket *sock) { struct sock *sk = sock->sk; struct llc_sock *llc; - struct llc_sap *sap; if (unlikely(sk == NULL)) goto out; @@ -200,15 +199,19 @@ static int llc_ui_release(struct socket *sock) llc->laddr.lsap, llc->daddr.lsap); if (!llc_send_disc(sk)) llc_ui_wait_for_disc(sk, sk->sk_rcvtimeo); - sap = llc->sap; - /* Hold this for release_sock(), so that llc_backlog_rcv() could still - * use it. - */ - llc_sap_hold(sap); - if (!sock_flag(sk, SOCK_ZAPPED)) + if (!sock_flag(sk, SOCK_ZAPPED)) { + struct llc_sap *sap = llc->sap; + + /* Hold this for release_sock(), so that llc_backlog_rcv() + * could still use it. + */ + llc_sap_hold(sap); llc_sap_remove_socket(llc->sap, sk); - release_sock(sk); - llc_sap_put(sap); + release_sock(sk); + llc_sap_put(sap); + } else { + release_sock(sk); + } if (llc->dev) dev_put(llc->dev); sock_put(sk); -- GitLab From 16c36a2c763296de03291a1317df376eadb0b09b Mon Sep 17 00:00:00 2001 From: Ivan Khoronzhuk Date: Thu, 19 Apr 2018 22:49:09 +0300 Subject: [PATCH 1154/1635] net: ethernet: ti: cpsw: fix tx vlan priority mapping [ Upstream commit 5e391dc5a8d801a2410d0032ad4a428d1d61800c ] The CPDMA_TX_PRIORITY_MAP in real is vlan pcp field priority mapping register and basically replaces vlan pcp field for tagged packets. So, set it to be 1:1 mapping. Otherwise, it will cause unexpected change of egress vlan tagged packets, like prio 2 -> prio 5. Fixes: e05107e6b747 ("net: ethernet: ti: cpsw: add multi queue support") Reviewed-by: Grygorii Strashko Signed-off-by: Ivan Khoronzhuk Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/ti/cpsw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c index a5bb7b19040e..992c43b1868f 100644 --- a/drivers/net/ethernet/ti/cpsw.c +++ b/drivers/net/ethernet/ti/cpsw.c @@ -124,7 +124,7 @@ do { \ #define RX_PRIORITY_MAPPING 0x76543210 #define TX_PRIORITY_MAPPING 0x33221100 -#define CPDMA_TX_PRIORITY_MAP 0x01234567 +#define CPDMA_TX_PRIORITY_MAP 0x76543210 #define CPSW_VLAN_AWARE BIT(1) #define CPSW_ALE_VLAN_AWARE 1 -- GitLab From d86aacaaf9d2f5f9fc1e96f53173124ce077f140 Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Thu, 19 Apr 2018 08:30:48 +0300 Subject: [PATCH 1155/1635] virtio_net: split out ctrl buffer [ Upstream commit 12e571693837d6164bda61e316b1944972ee0d97 ] When sending control commands, virtio net sets up several buffers for DMA. The buffers are all part of the net device which means it's actually allocated by kvmalloc so it's in theory (on extreme memory pressure) possible to get a vmalloc'ed buffer which on some platforms means we can't DMA there. Fix up by moving the DMA buffers into a separate structure. Reported-by: Mikulas Patocka Suggested-by: Eric Dumazet Signed-off-by: Michael S. Tsirkin Acked-by: Jason Wang Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/virtio_net.c | 68 +++++++++++++++++++++++----------------- 1 file changed, 39 insertions(+), 29 deletions(-) diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index b0a038e6fda0..63b096c47f1e 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -116,6 +116,17 @@ struct receive_queue { char name[40]; }; +/* Control VQ buffers: protected by the rtnl lock */ +struct control_buf { + struct virtio_net_ctrl_hdr hdr; + virtio_net_ctrl_ack status; + struct virtio_net_ctrl_mq mq; + u8 promisc; + u8 allmulti; + u16 vid; + u64 offloads; +}; + struct virtnet_info { struct virtio_device *vdev; struct virtqueue *cvq; @@ -164,14 +175,7 @@ struct virtnet_info { struct hlist_node node; struct hlist_node node_dead; - /* Control VQ buffers: protected by the rtnl lock */ - struct virtio_net_ctrl_hdr ctrl_hdr; - virtio_net_ctrl_ack ctrl_status; - struct virtio_net_ctrl_mq ctrl_mq; - u8 ctrl_promisc; - u8 ctrl_allmulti; - u16 ctrl_vid; - u64 ctrl_offloads; + struct control_buf *ctrl; /* Ethtool settings */ u8 duplex; @@ -1340,25 +1344,25 @@ static bool virtnet_send_command(struct virtnet_info *vi, u8 class, u8 cmd, /* Caller should know better */ BUG_ON(!virtio_has_feature(vi->vdev, VIRTIO_NET_F_CTRL_VQ)); - vi->ctrl_status = ~0; - vi->ctrl_hdr.class = class; - vi->ctrl_hdr.cmd = cmd; + vi->ctrl->status = ~0; + vi->ctrl->hdr.class = class; + vi->ctrl->hdr.cmd = cmd; /* Add header */ - sg_init_one(&hdr, &vi->ctrl_hdr, sizeof(vi->ctrl_hdr)); + sg_init_one(&hdr, &vi->ctrl->hdr, sizeof(vi->ctrl->hdr)); sgs[out_num++] = &hdr; if (out) sgs[out_num++] = out; /* Add return status. */ - sg_init_one(&stat, &vi->ctrl_status, sizeof(vi->ctrl_status)); + sg_init_one(&stat, &vi->ctrl->status, sizeof(vi->ctrl->status)); sgs[out_num] = &stat; BUG_ON(out_num + 1 > ARRAY_SIZE(sgs)); virtqueue_add_sgs(vi->cvq, sgs, out_num, 1, vi, GFP_ATOMIC); if (unlikely(!virtqueue_kick(vi->cvq))) - return vi->ctrl_status == VIRTIO_NET_OK; + return vi->ctrl->status == VIRTIO_NET_OK; /* Spin for a response, the kick causes an ioport write, trapping * into the hypervisor, so the request should be handled immediately. @@ -1367,7 +1371,7 @@ static bool virtnet_send_command(struct virtnet_info *vi, u8 class, u8 cmd, !virtqueue_is_broken(vi->cvq)) cpu_relax(); - return vi->ctrl_status == VIRTIO_NET_OK; + return vi->ctrl->status == VIRTIO_NET_OK; } static int virtnet_set_mac_address(struct net_device *dev, void *p) @@ -1478,8 +1482,8 @@ static int _virtnet_set_queues(struct virtnet_info *vi, u16 queue_pairs) if (!vi->has_cvq || !virtio_has_feature(vi->vdev, VIRTIO_NET_F_MQ)) return 0; - vi->ctrl_mq.virtqueue_pairs = cpu_to_virtio16(vi->vdev, queue_pairs); - sg_init_one(&sg, &vi->ctrl_mq, sizeof(vi->ctrl_mq)); + vi->ctrl->mq.virtqueue_pairs = cpu_to_virtio16(vi->vdev, queue_pairs); + sg_init_one(&sg, &vi->ctrl->mq, sizeof(vi->ctrl->mq)); if (!virtnet_send_command(vi, VIRTIO_NET_CTRL_MQ, VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET, &sg)) { @@ -1537,22 +1541,22 @@ static void virtnet_set_rx_mode(struct net_device *dev) if (!virtio_has_feature(vi->vdev, VIRTIO_NET_F_CTRL_RX)) return; - vi->ctrl_promisc = ((dev->flags & IFF_PROMISC) != 0); - vi->ctrl_allmulti = ((dev->flags & IFF_ALLMULTI) != 0); + vi->ctrl->promisc = ((dev->flags & IFF_PROMISC) != 0); + vi->ctrl->allmulti = ((dev->flags & IFF_ALLMULTI) != 0); - sg_init_one(sg, &vi->ctrl_promisc, sizeof(vi->ctrl_promisc)); + sg_init_one(sg, &vi->ctrl->promisc, sizeof(vi->ctrl->promisc)); if (!virtnet_send_command(vi, VIRTIO_NET_CTRL_RX, VIRTIO_NET_CTRL_RX_PROMISC, sg)) dev_warn(&dev->dev, "Failed to %sable promisc mode.\n", - vi->ctrl_promisc ? "en" : "dis"); + vi->ctrl->promisc ? "en" : "dis"); - sg_init_one(sg, &vi->ctrl_allmulti, sizeof(vi->ctrl_allmulti)); + sg_init_one(sg, &vi->ctrl->allmulti, sizeof(vi->ctrl->allmulti)); if (!virtnet_send_command(vi, VIRTIO_NET_CTRL_RX, VIRTIO_NET_CTRL_RX_ALLMULTI, sg)) dev_warn(&dev->dev, "Failed to %sable allmulti mode.\n", - vi->ctrl_allmulti ? "en" : "dis"); + vi->ctrl->allmulti ? "en" : "dis"); uc_count = netdev_uc_count(dev); mc_count = netdev_mc_count(dev); @@ -1598,8 +1602,8 @@ static int virtnet_vlan_rx_add_vid(struct net_device *dev, struct virtnet_info *vi = netdev_priv(dev); struct scatterlist sg; - vi->ctrl_vid = vid; - sg_init_one(&sg, &vi->ctrl_vid, sizeof(vi->ctrl_vid)); + vi->ctrl->vid = vid; + sg_init_one(&sg, &vi->ctrl->vid, sizeof(vi->ctrl->vid)); if (!virtnet_send_command(vi, VIRTIO_NET_CTRL_VLAN, VIRTIO_NET_CTRL_VLAN_ADD, &sg)) @@ -1613,8 +1617,8 @@ static int virtnet_vlan_rx_kill_vid(struct net_device *dev, struct virtnet_info *vi = netdev_priv(dev); struct scatterlist sg; - vi->ctrl_vid = vid; - sg_init_one(&sg, &vi->ctrl_vid, sizeof(vi->ctrl_vid)); + vi->ctrl->vid = vid; + sg_init_one(&sg, &vi->ctrl->vid, sizeof(vi->ctrl->vid)); if (!virtnet_send_command(vi, VIRTIO_NET_CTRL_VLAN, VIRTIO_NET_CTRL_VLAN_DEL, &sg)) @@ -1912,9 +1916,9 @@ static int virtnet_restore_up(struct virtio_device *vdev) static int virtnet_set_guest_offloads(struct virtnet_info *vi, u64 offloads) { struct scatterlist sg; - vi->ctrl_offloads = cpu_to_virtio64(vi->vdev, offloads); + vi->ctrl->offloads = cpu_to_virtio64(vi->vdev, offloads); - sg_init_one(&sg, &vi->ctrl_offloads, sizeof(vi->ctrl_offloads)); + sg_init_one(&sg, &vi->ctrl->offloads, sizeof(vi->ctrl->offloads)); if (!virtnet_send_command(vi, VIRTIO_NET_CTRL_GUEST_OFFLOADS, VIRTIO_NET_CTRL_GUEST_OFFLOADS_SET, &sg)) { @@ -2134,6 +2138,7 @@ static void virtnet_free_queues(struct virtnet_info *vi) kfree(vi->rq); kfree(vi->sq); + kfree(vi->ctrl); } static void _free_receive_bufs(struct virtnet_info *vi) @@ -2326,6 +2331,9 @@ static int virtnet_alloc_queues(struct virtnet_info *vi) { int i; + vi->ctrl = kzalloc(sizeof(*vi->ctrl), GFP_KERNEL); + if (!vi->ctrl) + goto err_ctrl; vi->sq = kzalloc(sizeof(*vi->sq) * vi->max_queue_pairs, GFP_KERNEL); if (!vi->sq) goto err_sq; @@ -2351,6 +2359,8 @@ static int virtnet_alloc_queues(struct virtnet_info *vi) err_rq: kfree(vi->sq); err_sq: + kfree(vi->ctrl); +err_ctrl: return -ENOMEM; } -- GitLab From 55c80adf0d0e528f4e4de92cecc5bf7c9201fc8a Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Thu, 19 Apr 2018 08:30:49 +0300 Subject: [PATCH 1156/1635] virtio_net: fix adding vids on big-endian [ Upstream commit d7fad4c840f33a6bd333dd7fbb3006edbcf0017a ] Programming vids (adding or removing them) still passes guest-endian values in the DMA buffer. That's wrong if guest is big-endian and when virtio 1 is enabled. Note: this is on top of a previous patch: virtio_net: split out ctrl buffer Fixes: 9465a7a6f ("virtio_net: enable v1.0 support") Signed-off-by: Michael S. Tsirkin Acked-by: Jason Wang Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/virtio_net.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index 63b096c47f1e..bb15b3012aa5 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -123,7 +123,7 @@ struct control_buf { struct virtio_net_ctrl_mq mq; u8 promisc; u8 allmulti; - u16 vid; + __virtio16 vid; u64 offloads; }; @@ -1602,7 +1602,7 @@ static int virtnet_vlan_rx_add_vid(struct net_device *dev, struct virtnet_info *vi = netdev_priv(dev); struct scatterlist sg; - vi->ctrl->vid = vid; + vi->ctrl->vid = cpu_to_virtio16(vi->vdev, vid); sg_init_one(&sg, &vi->ctrl->vid, sizeof(vi->ctrl->vid)); if (!virtnet_send_command(vi, VIRTIO_NET_CTRL_VLAN, @@ -1617,7 +1617,7 @@ static int virtnet_vlan_rx_kill_vid(struct net_device *dev, struct virtnet_info *vi = netdev_priv(dev); struct scatterlist sg; - vi->ctrl->vid = vid; + vi->ctrl->vid = cpu_to_virtio16(vi->vdev, vid); sg_init_one(&sg, &vi->ctrl->vid, sizeof(vi->ctrl->vid)); if (!virtnet_send_command(vi, VIRTIO_NET_CTRL_VLAN, -- GitLab From b44533a06fd8f50c425c9cfa3cbfa70f62c39a84 Mon Sep 17 00:00:00 2001 From: Vasily Gorbik Date: Fri, 27 Apr 2018 07:36:25 +0200 Subject: [PATCH 1157/1635] s390: introduce CPU alternatives [ Upstream commit 686140a1a9c41d85a4212a1c26d671139b76404b ] Implement CPU alternatives, which allows to optionally patch newer instructions at runtime, based on CPU facilities availability. A new kernel boot parameter "noaltinstr" disables patching. Current implementation is derived from x86 alternatives. Although ideal instructions padding (when altinstr is longer then oldinstr) is added at compile time, and no oldinstr nops optimization has to be done at runtime. Also couple of compile time sanity checks are done: 1. oldinstr and altinstr must be <= 254 bytes long, 2. oldinstr and altinstr must not have an odd length. alternative(oldinstr, altinstr, facility); alternative_2(oldinstr, altinstr1, facility1, altinstr2, facility2); Both compile time and runtime padding consists of either 6/4/2 bytes nop or a jump (brcl) + 2 bytes nop filler if padding is longer then 6 bytes. .altinstructions and .altinstr_replacement sections are part of __init_begin : __init_end region and are freed after initialization. Signed-off-by: Vasily Gorbik Signed-off-by: Martin Schwidefsky Signed-off-by: Greg Kroah-Hartman --- .../admin-guide/kernel-parameters.txt | 3 + arch/s390/Kconfig | 17 ++ arch/s390/include/asm/alternative.h | 163 ++++++++++++++++++ arch/s390/kernel/Makefile | 1 + arch/s390/kernel/alternative.c | 110 ++++++++++++ arch/s390/kernel/module.c | 17 ++ arch/s390/kernel/setup.c | 3 + arch/s390/kernel/vmlinux.lds.S | 23 +++ 8 files changed, 337 insertions(+) create mode 100644 arch/s390/include/asm/alternative.h create mode 100644 arch/s390/kernel/alternative.c diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt index fb385af482ff..8cfb44ffe853 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt @@ -2541,6 +2541,9 @@ noalign [KNL,ARM] + noaltinstr [S390] Disables alternative instructions patching + (CPU alternatives feature). + noapic [SMP,APIC] Tells the kernel to not make use of any IOAPICs that may be present in the system. diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig index ae55e715cc74..28e553c90a9a 100644 --- a/arch/s390/Kconfig +++ b/arch/s390/Kconfig @@ -538,6 +538,22 @@ config ARCH_RANDOM If unsure, say Y. +config ALTERNATIVES + def_bool y + prompt "Patch optimized instructions for running CPU type" + help + When enabled the kernel code is compiled with additional + alternative instructions blocks optimized for newer CPU types. + These alternative instructions blocks are patched at kernel boot + time when running CPU supports them. This mechanism is used to + optimize some critical code paths (i.e. spinlocks) for newer CPUs + even if kernel is build to support older machine generations. + + This mechanism could be disabled by appending "noaltinstr" + option to the kernel command line. + + If unsure, say Y. + endmenu menu "Memory setup" @@ -812,6 +828,7 @@ config PFAULT config SHARED_KERNEL bool "VM shared kernel support" depends on !JUMP_LABEL + depends on !ALTERNATIVES help Select this option, if you want to share the text segment of the Linux kernel between different VM guests. This reduces memory diff --git a/arch/s390/include/asm/alternative.h b/arch/s390/include/asm/alternative.h new file mode 100644 index 000000000000..6c268f6a51d3 --- /dev/null +++ b/arch/s390/include/asm/alternative.h @@ -0,0 +1,163 @@ +#ifndef _ASM_S390_ALTERNATIVE_H +#define _ASM_S390_ALTERNATIVE_H + +#ifndef __ASSEMBLY__ + +#include +#include +#include + +struct alt_instr { + s32 instr_offset; /* original instruction */ + s32 repl_offset; /* offset to replacement instruction */ + u16 facility; /* facility bit set for replacement */ + u8 instrlen; /* length of original instruction */ + u8 replacementlen; /* length of new instruction */ +} __packed; + +#ifdef CONFIG_ALTERNATIVES +extern void apply_alternative_instructions(void); +extern void apply_alternatives(struct alt_instr *start, struct alt_instr *end); +#else +static inline void apply_alternative_instructions(void) {}; +static inline void apply_alternatives(struct alt_instr *start, + struct alt_instr *end) {}; +#endif +/* + * |661: |662: |6620 |663: + * +-----------+---------------------+ + * | oldinstr | oldinstr_padding | + * | +----------+----------+ + * | | | | + * | | >6 bytes |6/4/2 nops| + * | |6 bytes jg-----------> + * +-----------+---------------------+ + * ^^ static padding ^^ + * + * .altinstr_replacement section + * +---------------------+-----------+ + * |6641: |6651: + * | alternative instr 1 | + * +-----------+---------+- - - - - -+ + * |6642: |6652: | + * | alternative instr 2 | padding + * +---------------------+- - - - - -+ + * ^ runtime ^ + * + * .altinstructions section + * +---------------------------------+ + * | alt_instr entries for each | + * | alternative instr | + * +---------------------------------+ + */ + +#define b_altinstr(num) "664"#num +#define e_altinstr(num) "665"#num + +#define e_oldinstr_pad_end "663" +#define oldinstr_len "662b-661b" +#define oldinstr_total_len e_oldinstr_pad_end"b-661b" +#define altinstr_len(num) e_altinstr(num)"b-"b_altinstr(num)"b" +#define oldinstr_pad_len(num) \ + "-(((" altinstr_len(num) ")-(" oldinstr_len ")) > 0) * " \ + "((" altinstr_len(num) ")-(" oldinstr_len "))" + +#define INSTR_LEN_SANITY_CHECK(len) \ + ".if " len " > 254\n" \ + "\t.error \"cpu alternatives does not support instructions " \ + "blocks > 254 bytes\"\n" \ + ".endif\n" \ + ".if (" len ") %% 2\n" \ + "\t.error \"cpu alternatives instructions length is odd\"\n" \ + ".endif\n" + +#define OLDINSTR_PADDING(oldinstr, num) \ + ".if " oldinstr_pad_len(num) " > 6\n" \ + "\tjg " e_oldinstr_pad_end "f\n" \ + "6620:\n" \ + "\t.fill (" oldinstr_pad_len(num) " - (6620b-662b)) / 2, 2, 0x0700\n" \ + ".else\n" \ + "\t.fill " oldinstr_pad_len(num) " / 6, 6, 0xc0040000\n" \ + "\t.fill " oldinstr_pad_len(num) " %% 6 / 4, 4, 0x47000000\n" \ + "\t.fill " oldinstr_pad_len(num) " %% 6 %% 4 / 2, 2, 0x0700\n" \ + ".endif\n" + +#define OLDINSTR(oldinstr, num) \ + "661:\n\t" oldinstr "\n662:\n" \ + OLDINSTR_PADDING(oldinstr, num) \ + e_oldinstr_pad_end ":\n" \ + INSTR_LEN_SANITY_CHECK(oldinstr_len) + +#define OLDINSTR_2(oldinstr, num1, num2) \ + "661:\n\t" oldinstr "\n662:\n" \ + ".if " altinstr_len(num1) " < " altinstr_len(num2) "\n" \ + OLDINSTR_PADDING(oldinstr, num2) \ + ".else\n" \ + OLDINSTR_PADDING(oldinstr, num1) \ + ".endif\n" \ + e_oldinstr_pad_end ":\n" \ + INSTR_LEN_SANITY_CHECK(oldinstr_len) + +#define ALTINSTR_ENTRY(facility, num) \ + "\t.long 661b - .\n" /* old instruction */ \ + "\t.long " b_altinstr(num)"b - .\n" /* alt instruction */ \ + "\t.word " __stringify(facility) "\n" /* facility bit */ \ + "\t.byte " oldinstr_total_len "\n" /* source len */ \ + "\t.byte " altinstr_len(num) "\n" /* alt instruction len */ + +#define ALTINSTR_REPLACEMENT(altinstr, num) /* replacement */ \ + b_altinstr(num)":\n\t" altinstr "\n" e_altinstr(num) ":\n" \ + INSTR_LEN_SANITY_CHECK(altinstr_len(num)) + +#ifdef CONFIG_ALTERNATIVES +/* alternative assembly primitive: */ +#define ALTERNATIVE(oldinstr, altinstr, facility) \ + ".pushsection .altinstr_replacement, \"ax\"\n" \ + ALTINSTR_REPLACEMENT(altinstr, 1) \ + ".popsection\n" \ + OLDINSTR(oldinstr, 1) \ + ".pushsection .altinstructions,\"a\"\n" \ + ALTINSTR_ENTRY(facility, 1) \ + ".popsection\n" + +#define ALTERNATIVE_2(oldinstr, altinstr1, facility1, altinstr2, facility2)\ + ".pushsection .altinstr_replacement, \"ax\"\n" \ + ALTINSTR_REPLACEMENT(altinstr1, 1) \ + ALTINSTR_REPLACEMENT(altinstr2, 2) \ + ".popsection\n" \ + OLDINSTR_2(oldinstr, 1, 2) \ + ".pushsection .altinstructions,\"a\"\n" \ + ALTINSTR_ENTRY(facility1, 1) \ + ALTINSTR_ENTRY(facility2, 2) \ + ".popsection\n" +#else +/* Alternative instructions are disabled, let's put just oldinstr in */ +#define ALTERNATIVE(oldinstr, altinstr, facility) \ + oldinstr "\n" + +#define ALTERNATIVE_2(oldinstr, altinstr1, facility1, altinstr2, facility2) \ + oldinstr "\n" +#endif + +/* + * Alternative instructions for different CPU types or capabilities. + * + * This allows to use optimized instructions even on generic binary + * kernels. + * + * oldinstr is padded with jump and nops at compile time if altinstr is + * longer. altinstr is padded with jump and nops at run-time during patching. + * + * For non barrier like inlines please define new variants + * without volatile and memory clobber. + */ +#define alternative(oldinstr, altinstr, facility) \ + asm volatile(ALTERNATIVE(oldinstr, altinstr, facility) : : : "memory") + +#define alternative_2(oldinstr, altinstr1, facility1, altinstr2, facility2) \ + asm volatile(ALTERNATIVE_2(oldinstr, altinstr1, facility1, \ + altinstr2, facility2) ::: "memory") + +#endif /* __ASSEMBLY__ */ + +#endif /* _ASM_S390_ALTERNATIVE_H */ diff --git a/arch/s390/kernel/Makefile b/arch/s390/kernel/Makefile index 4ce2d05929a7..23cdabe61b77 100644 --- a/arch/s390/kernel/Makefile +++ b/arch/s390/kernel/Makefile @@ -75,6 +75,7 @@ obj-$(CONFIG_KPROBES) += kprobes.o obj-$(CONFIG_FUNCTION_TRACER) += mcount.o ftrace.o obj-$(CONFIG_CRASH_DUMP) += crash_dump.o obj-$(CONFIG_UPROBES) += uprobes.o +obj-$(CONFIG_ALTERNATIVES) += alternative.o obj-$(CONFIG_PERF_EVENTS) += perf_event.o perf_cpum_cf.o perf_cpum_sf.o obj-$(CONFIG_PERF_EVENTS) += perf_cpum_cf_events.o diff --git a/arch/s390/kernel/alternative.c b/arch/s390/kernel/alternative.c new file mode 100644 index 000000000000..315986a06cf5 --- /dev/null +++ b/arch/s390/kernel/alternative.c @@ -0,0 +1,110 @@ +#include +#include +#include + +#define MAX_PATCH_LEN (255 - 1) + +static int __initdata_or_module alt_instr_disabled; + +static int __init disable_alternative_instructions(char *str) +{ + alt_instr_disabled = 1; + return 0; +} + +early_param("noaltinstr", disable_alternative_instructions); + +struct brcl_insn { + u16 opc; + s32 disp; +} __packed; + +static u16 __initdata_or_module nop16 = 0x0700; +static u32 __initdata_or_module nop32 = 0x47000000; +static struct brcl_insn __initdata_or_module nop48 = { + 0xc004, 0 +}; + +static const void *nops[] __initdata_or_module = { + &nop16, + &nop32, + &nop48 +}; + +static void __init_or_module add_jump_padding(void *insns, unsigned int len) +{ + struct brcl_insn brcl = { + 0xc0f4, + len / 2 + }; + + memcpy(insns, &brcl, sizeof(brcl)); + insns += sizeof(brcl); + len -= sizeof(brcl); + + while (len > 0) { + memcpy(insns, &nop16, 2); + insns += 2; + len -= 2; + } +} + +static void __init_or_module add_padding(void *insns, unsigned int len) +{ + if (len > 6) + add_jump_padding(insns, len); + else if (len >= 2) + memcpy(insns, nops[len / 2 - 1], len); +} + +static void __init_or_module __apply_alternatives(struct alt_instr *start, + struct alt_instr *end) +{ + struct alt_instr *a; + u8 *instr, *replacement; + u8 insnbuf[MAX_PATCH_LEN]; + + /* + * The scan order should be from start to end. A later scanned + * alternative code can overwrite previously scanned alternative code. + */ + for (a = start; a < end; a++) { + int insnbuf_sz = 0; + + instr = (u8 *)&a->instr_offset + a->instr_offset; + replacement = (u8 *)&a->repl_offset + a->repl_offset; + + if (!test_facility(a->facility)) + continue; + + if (unlikely(a->instrlen % 2 || a->replacementlen % 2)) { + WARN_ONCE(1, "cpu alternatives instructions length is " + "odd, skipping patching\n"); + continue; + } + + memcpy(insnbuf, replacement, a->replacementlen); + insnbuf_sz = a->replacementlen; + + if (a->instrlen > a->replacementlen) { + add_padding(insnbuf + a->replacementlen, + a->instrlen - a->replacementlen); + insnbuf_sz += a->instrlen - a->replacementlen; + } + + s390_kernel_write(instr, insnbuf, insnbuf_sz); + } +} + +void __init_or_module apply_alternatives(struct alt_instr *start, + struct alt_instr *end) +{ + if (!alt_instr_disabled) + __apply_alternatives(start, end); +} + +extern struct alt_instr __alt_instructions[], __alt_instructions_end[]; +void __init apply_alternative_instructions(void) +{ + apply_alternatives(__alt_instructions, __alt_instructions_end); +} diff --git a/arch/s390/kernel/module.c b/arch/s390/kernel/module.c index 1a27f307a920..6d9f73bb4142 100644 --- a/arch/s390/kernel/module.c +++ b/arch/s390/kernel/module.c @@ -31,6 +31,7 @@ #include #include #include +#include #if 0 #define DEBUGP printk @@ -429,6 +430,22 @@ int module_finalize(const Elf_Ehdr *hdr, const Elf_Shdr *sechdrs, struct module *me) { + const Elf_Shdr *s; + char *secstrings; + + if (IS_ENABLED(CONFIG_ALTERNATIVES)) { + secstrings = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset; + for (s = sechdrs; s < sechdrs + hdr->e_shnum; s++) { + if (!strcmp(".altinstructions", + secstrings + s->sh_name)) { + /* patch .altinstructions */ + void *aseg = (void *)s->sh_addr; + + apply_alternatives(aseg, aseg + s->sh_size); + } + } + } + jump_label_apply_nops(me); return 0; } diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c index 164a1e16b53e..c6d2d54d5d0e 100644 --- a/arch/s390/kernel/setup.c +++ b/arch/s390/kernel/setup.c @@ -66,6 +66,7 @@ #include #include #include +#include #include "entry.h" /* @@ -955,6 +956,8 @@ void __init setup_arch(char **cmdline_p) conmode_default(); set_preferred_console(); + apply_alternative_instructions(); + /* Setup zfcpdump support */ setup_zfcpdump(); diff --git a/arch/s390/kernel/vmlinux.lds.S b/arch/s390/kernel/vmlinux.lds.S index 96a713a470e7..3f6c93a82297 100644 --- a/arch/s390/kernel/vmlinux.lds.S +++ b/arch/s390/kernel/vmlinux.lds.S @@ -105,6 +105,29 @@ SECTIONS EXIT_DATA } + /* + * struct alt_inst entries. From the header (alternative.h): + * "Alternative instructions for different CPU types or capabilities" + * Think locking instructions on spinlocks. + * Note, that it is a part of __init region. + */ + . = ALIGN(8); + .altinstructions : { + __alt_instructions = .; + *(.altinstructions) + __alt_instructions_end = .; + } + + /* + * And here are the replacement instructions. The linker sticks + * them as binary blobs. The .altinstructions has enough data to + * get the address and the length of them to patch the kernel safely. + * Note, that it is a part of __init region. + */ + .altinstr_replacement : { + *(.altinstr_replacement) + } + /* early.c uses stsi, which requires page aligned data. */ . = ALIGN(PAGE_SIZE); INIT_DATA_SECTION(0x100) -- GitLab From 37e79747128bbabdff0e244a41bdcd4892a4e7cb Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Fri, 27 Apr 2018 07:36:26 +0200 Subject: [PATCH 1158/1635] s390: enable CPU alternatives unconditionally [ Upstream commit 049a2c2d486e8cc82c5cd79fa479c5b105b109e9 ] Remove the CPU_ALTERNATIVES config option and enable the code unconditionally. The config option was only added to avoid a conflict with the named saved segment support. Since that code is gone there is no reason to keep the CPU_ALTERNATIVES config option. Just enable it unconditionally to also reduce the number of config options and make it less likely that something breaks. Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky Signed-off-by: Greg Kroah-Hartman --- arch/s390/Kconfig | 16 ---------------- arch/s390/include/asm/alternative.h | 20 +++----------------- arch/s390/kernel/Makefile | 3 +-- arch/s390/kernel/module.c | 15 ++++++--------- 4 files changed, 10 insertions(+), 44 deletions(-) diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig index 28e553c90a9a..06e53763154b 100644 --- a/arch/s390/Kconfig +++ b/arch/s390/Kconfig @@ -538,22 +538,6 @@ config ARCH_RANDOM If unsure, say Y. -config ALTERNATIVES - def_bool y - prompt "Patch optimized instructions for running CPU type" - help - When enabled the kernel code is compiled with additional - alternative instructions blocks optimized for newer CPU types. - These alternative instructions blocks are patched at kernel boot - time when running CPU supports them. This mechanism is used to - optimize some critical code paths (i.e. spinlocks) for newer CPUs - even if kernel is build to support older machine generations. - - This mechanism could be disabled by appending "noaltinstr" - option to the kernel command line. - - If unsure, say Y. - endmenu menu "Memory setup" diff --git a/arch/s390/include/asm/alternative.h b/arch/s390/include/asm/alternative.h index 6c268f6a51d3..a72002056b54 100644 --- a/arch/s390/include/asm/alternative.h +++ b/arch/s390/include/asm/alternative.h @@ -15,14 +15,9 @@ struct alt_instr { u8 replacementlen; /* length of new instruction */ } __packed; -#ifdef CONFIG_ALTERNATIVES -extern void apply_alternative_instructions(void); -extern void apply_alternatives(struct alt_instr *start, struct alt_instr *end); -#else -static inline void apply_alternative_instructions(void) {}; -static inline void apply_alternatives(struct alt_instr *start, - struct alt_instr *end) {}; -#endif +void apply_alternative_instructions(void); +void apply_alternatives(struct alt_instr *start, struct alt_instr *end); + /* * |661: |662: |6620 |663: * +-----------+---------------------+ @@ -109,7 +104,6 @@ static inline void apply_alternatives(struct alt_instr *start, b_altinstr(num)":\n\t" altinstr "\n" e_altinstr(num) ":\n" \ INSTR_LEN_SANITY_CHECK(altinstr_len(num)) -#ifdef CONFIG_ALTERNATIVES /* alternative assembly primitive: */ #define ALTERNATIVE(oldinstr, altinstr, facility) \ ".pushsection .altinstr_replacement, \"ax\"\n" \ @@ -130,14 +124,6 @@ static inline void apply_alternatives(struct alt_instr *start, ALTINSTR_ENTRY(facility1, 1) \ ALTINSTR_ENTRY(facility2, 2) \ ".popsection\n" -#else -/* Alternative instructions are disabled, let's put just oldinstr in */ -#define ALTERNATIVE(oldinstr, altinstr, facility) \ - oldinstr "\n" - -#define ALTERNATIVE_2(oldinstr, altinstr1, facility1, altinstr2, facility2) \ - oldinstr "\n" -#endif /* * Alternative instructions for different CPU types or capabilities. diff --git a/arch/s390/kernel/Makefile b/arch/s390/kernel/Makefile index 23cdabe61b77..41d706897a30 100644 --- a/arch/s390/kernel/Makefile +++ b/arch/s390/kernel/Makefile @@ -57,7 +57,7 @@ obj-y += processor.o sys_s390.o ptrace.o signal.o cpcmd.o ebcdic.o nmi.o obj-y += debug.o irq.o ipl.o dis.o diag.o vdso.o als.o obj-y += sysinfo.o jump_label.o lgr.o os_info.o machine_kexec.o pgm_check.o obj-y += runtime_instr.o cache.o fpu.o dumpstack.o guarded_storage.o -obj-y += entry.o reipl.o relocate_kernel.o kdebugfs.o +obj-y += entry.o reipl.o relocate_kernel.o kdebugfs.o alternative.o extra-y += head.o head64.o vmlinux.lds @@ -75,7 +75,6 @@ obj-$(CONFIG_KPROBES) += kprobes.o obj-$(CONFIG_FUNCTION_TRACER) += mcount.o ftrace.o obj-$(CONFIG_CRASH_DUMP) += crash_dump.o obj-$(CONFIG_UPROBES) += uprobes.o -obj-$(CONFIG_ALTERNATIVES) += alternative.o obj-$(CONFIG_PERF_EVENTS) += perf_event.o perf_cpum_cf.o perf_cpum_sf.o obj-$(CONFIG_PERF_EVENTS) += perf_cpum_cf_events.o diff --git a/arch/s390/kernel/module.c b/arch/s390/kernel/module.c index 6d9f73bb4142..7b87991416fd 100644 --- a/arch/s390/kernel/module.c +++ b/arch/s390/kernel/module.c @@ -433,16 +433,13 @@ int module_finalize(const Elf_Ehdr *hdr, const Elf_Shdr *s; char *secstrings; - if (IS_ENABLED(CONFIG_ALTERNATIVES)) { - secstrings = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset; - for (s = sechdrs; s < sechdrs + hdr->e_shnum; s++) { - if (!strcmp(".altinstructions", - secstrings + s->sh_name)) { - /* patch .altinstructions */ - void *aseg = (void *)s->sh_addr; + secstrings = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset; + for (s = sechdrs; s < sechdrs + hdr->e_shnum; s++) { + if (!strcmp(".altinstructions", secstrings + s->sh_name)) { + /* patch .altinstructions */ + void *aseg = (void *)s->sh_addr; - apply_alternatives(aseg, aseg + s->sh_size); - } + apply_alternatives(aseg, aseg + s->sh_size); } } -- GitLab From ea5566fecd035bc5d84d8bd341b655238134deb8 Mon Sep 17 00:00:00 2001 From: Christian Borntraeger Date: Fri, 27 Apr 2018 07:36:27 +0200 Subject: [PATCH 1159/1635] KVM: s390: wire up bpb feature MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit 35b3fde6203b932b2b1a5b53b3d8808abc9c4f60 ] The new firmware interfaces for branch prediction behaviour changes are transparently available for the guest. Nevertheless, there is new state attached that should be migrated and properly resetted. Provide a mechanism for handling reset, migration and VSIE. Signed-off-by: Christian Borntraeger Reviewed-by: David Hildenbrand Reviewed-by: Cornelia Huck [Changed capability number to 152. - Radim] Signed-off-by: Radim Krčmář Signed-off-by: Martin Schwidefsky Signed-off-by: Greg Kroah-Hartman --- arch/s390/include/asm/kvm_host.h | 3 ++- arch/s390/include/uapi/asm/kvm.h | 5 ++++- arch/s390/kvm/kvm-s390.c | 12 ++++++++++++ arch/s390/kvm/vsie.c | 10 ++++++++++ include/uapi/linux/kvm.h | 1 + 5 files changed, 29 insertions(+), 2 deletions(-) diff --git a/arch/s390/include/asm/kvm_host.h b/arch/s390/include/asm/kvm_host.h index 51375e766e90..d660e784e445 100644 --- a/arch/s390/include/asm/kvm_host.h +++ b/arch/s390/include/asm/kvm_host.h @@ -210,7 +210,8 @@ struct kvm_s390_sie_block { __u16 ipa; /* 0x0056 */ __u32 ipb; /* 0x0058 */ __u32 scaoh; /* 0x005c */ - __u8 reserved60; /* 0x0060 */ +#define FPF_BPBC 0x20 + __u8 fpf; /* 0x0060 */ #define ECB_GS 0x40 #define ECB_TE 0x10 #define ECB_SRSI 0x04 diff --git a/arch/s390/include/uapi/asm/kvm.h b/arch/s390/include/uapi/asm/kvm.h index 9ad172dcd912..a3938db010f7 100644 --- a/arch/s390/include/uapi/asm/kvm.h +++ b/arch/s390/include/uapi/asm/kvm.h @@ -228,6 +228,7 @@ struct kvm_guest_debug_arch { #define KVM_SYNC_RICCB (1UL << 7) #define KVM_SYNC_FPRS (1UL << 8) #define KVM_SYNC_GSCB (1UL << 9) +#define KVM_SYNC_BPBC (1UL << 10) /* length and alignment of the sdnx as a power of two */ #define SDNXC 8 #define SDNXL (1UL << SDNXC) @@ -251,7 +252,9 @@ struct kvm_sync_regs { }; __u8 reserved[512]; /* for future vector expansion */ __u32 fpc; /* valid on KVM_SYNC_VRS or KVM_SYNC_FPRS */ - __u8 padding1[52]; /* riccb needs to be 64byte aligned */ + __u8 bpbc : 1; /* bp mode */ + __u8 reserved2 : 7; + __u8 padding1[51]; /* riccb needs to be 64byte aligned */ __u8 riccb[64]; /* runtime instrumentation controls block */ __u8 padding2[192]; /* sdnx needs to be 256byte aligned */ union { diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c index 0bce918db11a..4f6adbea592b 100644 --- a/arch/s390/kvm/kvm-s390.c +++ b/arch/s390/kvm/kvm-s390.c @@ -449,6 +449,9 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext) case KVM_CAP_S390_GS: r = test_facility(133); break; + case KVM_CAP_S390_BPB: + r = test_facility(82); + break; default: r = 0; } @@ -2231,6 +2234,8 @@ int kvm_arch_vcpu_init(struct kvm_vcpu *vcpu) kvm_s390_set_prefix(vcpu, 0); if (test_kvm_facility(vcpu->kvm, 64)) vcpu->run->kvm_valid_regs |= KVM_SYNC_RICCB; + if (test_kvm_facility(vcpu->kvm, 82)) + vcpu->run->kvm_valid_regs |= KVM_SYNC_BPBC; if (test_kvm_facility(vcpu->kvm, 133)) vcpu->run->kvm_valid_regs |= KVM_SYNC_GSCB; /* fprs can be synchronized via vrs, even if the guest has no vx. With @@ -2372,6 +2377,7 @@ static void kvm_s390_vcpu_initial_reset(struct kvm_vcpu *vcpu) current->thread.fpu.fpc = 0; vcpu->arch.sie_block->gbea = 1; vcpu->arch.sie_block->pp = 0; + vcpu->arch.sie_block->fpf &= ~FPF_BPBC; vcpu->arch.pfault_token = KVM_S390_PFAULT_TOKEN_INVALID; kvm_clear_async_pf_completion_queue(vcpu); if (!kvm_s390_user_cpu_state_ctrl(vcpu->kvm)) @@ -3318,6 +3324,11 @@ static void sync_regs(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) vcpu->arch.sie_block->ecd |= ECD_HOSTREGMGMT; vcpu->arch.gs_enabled = 1; } + if ((kvm_run->kvm_dirty_regs & KVM_SYNC_BPBC) && + test_kvm_facility(vcpu->kvm, 82)) { + vcpu->arch.sie_block->fpf &= ~FPF_BPBC; + vcpu->arch.sie_block->fpf |= kvm_run->s.regs.bpbc ? FPF_BPBC : 0; + } save_access_regs(vcpu->arch.host_acrs); restore_access_regs(vcpu->run->s.regs.acrs); /* save host (userspace) fprs/vrs */ @@ -3364,6 +3375,7 @@ static void store_regs(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) kvm_run->s.regs.pft = vcpu->arch.pfault_token; kvm_run->s.regs.pfs = vcpu->arch.pfault_select; kvm_run->s.regs.pfc = vcpu->arch.pfault_compare; + kvm_run->s.regs.bpbc = (vcpu->arch.sie_block->fpf & FPF_BPBC) == FPF_BPBC; save_access_regs(vcpu->run->s.regs.acrs); restore_access_regs(vcpu->arch.host_acrs); /* Save guest register state */ diff --git a/arch/s390/kvm/vsie.c b/arch/s390/kvm/vsie.c index a74204db759b..80c4fde9bdcc 100644 --- a/arch/s390/kvm/vsie.c +++ b/arch/s390/kvm/vsie.c @@ -234,6 +234,12 @@ static void unshadow_scb(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page) memcpy(scb_o->gcr, scb_s->gcr, 128); scb_o->pp = scb_s->pp; + /* branch prediction */ + if (test_kvm_facility(vcpu->kvm, 82)) { + scb_o->fpf &= ~FPF_BPBC; + scb_o->fpf |= scb_s->fpf & FPF_BPBC; + } + /* interrupt intercept */ switch (scb_s->icptcode) { case ICPT_PROGI: @@ -280,6 +286,7 @@ static int shadow_scb(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page) scb_s->ecb3 = 0; scb_s->ecd = 0; scb_s->fac = 0; + scb_s->fpf = 0; rc = prepare_cpuflags(vcpu, vsie_page); if (rc) @@ -339,6 +346,9 @@ static int shadow_scb(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page) prefix_unmapped(vsie_page); scb_s->ecb |= ECB_TE; } + /* branch prediction */ + if (test_kvm_facility(vcpu->kvm, 82)) + scb_s->fpf |= scb_o->fpf & FPF_BPBC; /* SIMD */ if (test_kvm_facility(vcpu->kvm, 129)) { scb_s->eca |= scb_o->eca & ECA_VX; diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h index 7e99999d6236..857bad91c454 100644 --- a/include/uapi/linux/kvm.h +++ b/include/uapi/linux/kvm.h @@ -931,6 +931,7 @@ struct kvm_ppc_resize_hpt { #define KVM_CAP_PPC_SMT_POSSIBLE 147 #define KVM_CAP_HYPERV_SYNIC2 148 #define KVM_CAP_HYPERV_VP_INDEX 149 +#define KVM_CAP_S390_BPB 152 #ifdef KVM_CAP_IRQ_ROUTING -- GitLab From 2ae8b68382ce0c5e911090b502e0fda14191c730 Mon Sep 17 00:00:00 2001 From: Martin Schwidefsky Date: Fri, 27 Apr 2018 07:36:28 +0200 Subject: [PATCH 1160/1635] s390: scrub registers on kernel entry and KVM exit [ Upstream commit 7041d28115e91f2144f811ffe8a195c696b1e1d0 ] Clear all user space registers on entry to the kernel and all KVM guest registers on KVM guest exit if the register does not contain either a parameter or a result value. Reviewed-by: Christian Borntraeger Signed-off-by: Martin Schwidefsky Signed-off-by: Greg Kroah-Hartman --- arch/s390/kernel/entry.S | 47 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/arch/s390/kernel/entry.S b/arch/s390/kernel/entry.S index 7c6904d616d8..b8ddc0a2f03d 100644 --- a/arch/s390/kernel/entry.S +++ b/arch/s390/kernel/entry.S @@ -248,6 +248,12 @@ ENTRY(sie64a) sie_exit: lg %r14,__SF_EMPTY+8(%r15) # load guest register save area stmg %r0,%r13,0(%r14) # save guest gprs 0-13 + xgr %r0,%r0 # clear guest registers to + xgr %r1,%r1 # prevent speculative use + xgr %r2,%r2 + xgr %r3,%r3 + xgr %r4,%r4 + xgr %r5,%r5 lmg %r6,%r14,__SF_GPRS(%r15) # restore kernel registers lg %r2,__SF_EMPTY+16(%r15) # return exit reason code br %r14 @@ -282,6 +288,8 @@ ENTRY(system_call) .Lsysc_vtime: UPDATE_VTIME %r8,%r9,__LC_SYNC_ENTER_TIMER stmg %r0,%r7,__PT_R0(%r11) + # clear user controlled register to prevent speculative use + xgr %r0,%r0 mvc __PT_R8(64,%r11),__LC_SAVE_AREA_SYNC mvc __PT_PSW(16,%r11),__LC_SVC_OLD_PSW mvc __PT_INT_CODE(4,%r11),__LC_SVC_ILC @@ -550,6 +558,15 @@ ENTRY(pgm_check_handler) 3: stg %r10,__THREAD_last_break(%r14) 4: la %r11,STACK_FRAME_OVERHEAD(%r15) stmg %r0,%r7,__PT_R0(%r11) + # clear user controlled registers to prevent speculative use + xgr %r0,%r0 + xgr %r1,%r1 + xgr %r2,%r2 + xgr %r3,%r3 + xgr %r4,%r4 + xgr %r5,%r5 + xgr %r6,%r6 + xgr %r7,%r7 mvc __PT_R8(64,%r11),__LC_SAVE_AREA_SYNC stmg %r8,%r9,__PT_PSW(%r11) mvc __PT_INT_CODE(4,%r11),__LC_PGM_ILC @@ -615,6 +632,16 @@ ENTRY(io_int_handler) lmg %r8,%r9,__LC_IO_OLD_PSW SWITCH_ASYNC __LC_SAVE_AREA_ASYNC,__LC_ASYNC_ENTER_TIMER stmg %r0,%r7,__PT_R0(%r11) + # clear user controlled registers to prevent speculative use + xgr %r0,%r0 + xgr %r1,%r1 + xgr %r2,%r2 + xgr %r3,%r3 + xgr %r4,%r4 + xgr %r5,%r5 + xgr %r6,%r6 + xgr %r7,%r7 + xgr %r10,%r10 mvc __PT_R8(64,%r11),__LC_SAVE_AREA_ASYNC stmg %r8,%r9,__PT_PSW(%r11) mvc __PT_INT_CODE(12,%r11),__LC_SUBCHANNEL_ID @@ -820,6 +847,16 @@ ENTRY(ext_int_handler) lmg %r8,%r9,__LC_EXT_OLD_PSW SWITCH_ASYNC __LC_SAVE_AREA_ASYNC,__LC_ASYNC_ENTER_TIMER stmg %r0,%r7,__PT_R0(%r11) + # clear user controlled registers to prevent speculative use + xgr %r0,%r0 + xgr %r1,%r1 + xgr %r2,%r2 + xgr %r3,%r3 + xgr %r4,%r4 + xgr %r5,%r5 + xgr %r6,%r6 + xgr %r7,%r7 + xgr %r10,%r10 mvc __PT_R8(64,%r11),__LC_SAVE_AREA_ASYNC stmg %r8,%r9,__PT_PSW(%r11) lghi %r1,__LC_EXT_PARAMS2 @@ -982,6 +1019,16 @@ ENTRY(mcck_int_handler) .Lmcck_skip: lghi %r14,__LC_GPREGS_SAVE_AREA+64 stmg %r0,%r7,__PT_R0(%r11) + # clear user controlled registers to prevent speculative use + xgr %r0,%r0 + xgr %r1,%r1 + xgr %r2,%r2 + xgr %r3,%r3 + xgr %r4,%r4 + xgr %r5,%r5 + xgr %r6,%r6 + xgr %r7,%r7 + xgr %r10,%r10 mvc __PT_R8(64,%r11),0(%r14) stmg %r8,%r9,__PT_PSW(%r11) xc __PT_FLAGS(8,%r11),__PT_FLAGS(%r11) -- GitLab From 2ae89b86a77fd96ca9a20236730bf599becc7550 Mon Sep 17 00:00:00 2001 From: Martin Schwidefsky Date: Fri, 27 Apr 2018 07:36:29 +0200 Subject: [PATCH 1161/1635] s390: add optimized array_index_mask_nospec [ Upstream commit e2dd833389cc4069a96b57bdd24227b5f52288f5 ] Add an optimized version of the array_index_mask_nospec function for s390 based on a compare and a subtract with borrow. Signed-off-by: Martin Schwidefsky Signed-off-by: Greg Kroah-Hartman --- arch/s390/include/asm/barrier.h | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/arch/s390/include/asm/barrier.h b/arch/s390/include/asm/barrier.h index 10432607a573..f9eddbca79d2 100644 --- a/arch/s390/include/asm/barrier.h +++ b/arch/s390/include/asm/barrier.h @@ -49,6 +49,30 @@ do { \ #define __smp_mb__before_atomic() barrier() #define __smp_mb__after_atomic() barrier() +/** + * array_index_mask_nospec - generate a mask for array_idx() that is + * ~0UL when the bounds check succeeds and 0 otherwise + * @index: array element index + * @size: number of elements in array + */ +#define array_index_mask_nospec array_index_mask_nospec +static inline unsigned long array_index_mask_nospec(unsigned long index, + unsigned long size) +{ + unsigned long mask; + + if (__builtin_constant_p(size) && size > 0) { + asm(" clgr %2,%1\n" + " slbgr %0,%0\n" + :"=d" (mask) : "d" (size-1), "d" (index) :"cc"); + return mask; + } + asm(" clgr %1,%2\n" + " slbgr %0,%0\n" + :"=d" (mask) : "d" (size), "d" (index) :"cc"); + return ~mask; +} + #include #endif /* __ASM_BARRIER_H */ -- GitLab From c257f81b6d4557bc1c22972696305d1f397f2030 Mon Sep 17 00:00:00 2001 From: Martin Schwidefsky Date: Fri, 27 Apr 2018 07:36:30 +0200 Subject: [PATCH 1162/1635] s390/alternative: use a copy of the facility bit mask [ Upstream commit cf1489984641369611556bf00c48f945c77bcf02 ] To be able to switch off specific CPU alternatives with kernel parameters make a copy of the facility bit mask provided by STFLE and use the copy for the decision to apply an alternative. Reviewed-by: David Hildenbrand Reviewed-by: Cornelia Huck Signed-off-by: Martin Schwidefsky Signed-off-by: Greg Kroah-Hartman --- arch/s390/include/asm/facility.h | 18 ++++++++++++++++++ arch/s390/include/asm/lowcore.h | 3 ++- arch/s390/kernel/alternative.c | 3 ++- arch/s390/kernel/early.c | 3 +++ arch/s390/kernel/setup.c | 4 +++- arch/s390/kernel/smp.c | 4 +++- 6 files changed, 31 insertions(+), 4 deletions(-) diff --git a/arch/s390/include/asm/facility.h b/arch/s390/include/asm/facility.h index f040644575b7..2d58478c2745 100644 --- a/arch/s390/include/asm/facility.h +++ b/arch/s390/include/asm/facility.h @@ -15,6 +15,24 @@ #define MAX_FACILITY_BIT (sizeof(((struct lowcore *)0)->stfle_fac_list) * 8) +static inline void __set_facility(unsigned long nr, void *facilities) +{ + unsigned char *ptr = (unsigned char *) facilities; + + if (nr >= MAX_FACILITY_BIT) + return; + ptr[nr >> 3] |= 0x80 >> (nr & 7); +} + +static inline void __clear_facility(unsigned long nr, void *facilities) +{ + unsigned char *ptr = (unsigned char *) facilities; + + if (nr >= MAX_FACILITY_BIT) + return; + ptr[nr >> 3] &= ~(0x80 >> (nr & 7)); +} + static inline int __test_facility(unsigned long nr, void *facilities) { unsigned char *ptr; diff --git a/arch/s390/include/asm/lowcore.h b/arch/s390/include/asm/lowcore.h index 917f7344cab6..26d742f8dd93 100644 --- a/arch/s390/include/asm/lowcore.h +++ b/arch/s390/include/asm/lowcore.h @@ -155,7 +155,8 @@ struct lowcore { __u8 pad_0x0e20[0x0f00-0x0e20]; /* 0x0e20 */ /* Extended facility list */ - __u64 stfle_fac_list[32]; /* 0x0f00 */ + __u64 stfle_fac_list[16]; /* 0x0f00 */ + __u64 alt_stfle_fac_list[16]; /* 0x0f80 */ __u8 pad_0x1000[0x11b0-0x1000]; /* 0x1000 */ /* Pointer to the machine check extended save area */ diff --git a/arch/s390/kernel/alternative.c b/arch/s390/kernel/alternative.c index 315986a06cf5..f5060af61176 100644 --- a/arch/s390/kernel/alternative.c +++ b/arch/s390/kernel/alternative.c @@ -74,7 +74,8 @@ static void __init_or_module __apply_alternatives(struct alt_instr *start, instr = (u8 *)&a->instr_offset + a->instr_offset; replacement = (u8 *)&a->repl_offset + a->repl_offset; - if (!test_facility(a->facility)) + if (!__test_facility(a->facility, + S390_lowcore.alt_stfle_fac_list)) continue; if (unlikely(a->instrlen % 2 || a->replacementlen % 2)) { diff --git a/arch/s390/kernel/early.c b/arch/s390/kernel/early.c index f7b280f0ab16..901d62eb1ff8 100644 --- a/arch/s390/kernel/early.c +++ b/arch/s390/kernel/early.c @@ -329,6 +329,9 @@ static noinline __init void setup_facility_list(void) { stfle(S390_lowcore.stfle_fac_list, ARRAY_SIZE(S390_lowcore.stfle_fac_list)); + memcpy(S390_lowcore.alt_stfle_fac_list, + S390_lowcore.stfle_fac_list, + sizeof(S390_lowcore.alt_stfle_fac_list)); } static __init void detect_diag9c(void) diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c index c6d2d54d5d0e..a9f05162d294 100644 --- a/arch/s390/kernel/setup.c +++ b/arch/s390/kernel/setup.c @@ -339,7 +339,9 @@ static void __init setup_lowcore(void) lc->preempt_count = S390_lowcore.preempt_count; lc->stfl_fac_list = S390_lowcore.stfl_fac_list; memcpy(lc->stfle_fac_list, S390_lowcore.stfle_fac_list, - MAX_FACILITY_BIT/8); + sizeof(lc->stfle_fac_list)); + memcpy(lc->alt_stfle_fac_list, S390_lowcore.alt_stfle_fac_list, + sizeof(lc->alt_stfle_fac_list)); if (MACHINE_HAS_VX || MACHINE_HAS_GS) { unsigned long bits, size; diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c index 7ffaf9fd6d19..e906b77deb90 100644 --- a/arch/s390/kernel/smp.c +++ b/arch/s390/kernel/smp.c @@ -282,7 +282,9 @@ static void pcpu_prepare_secondary(struct pcpu *pcpu, int cpu) __ctl_store(lc->cregs_save_area, 0, 15); save_access_regs((unsigned int *) lc->access_regs_save_area); memcpy(lc->stfle_fac_list, S390_lowcore.stfle_fac_list, - MAX_FACILITY_BIT/8); + sizeof(lc->stfle_fac_list)); + memcpy(lc->alt_stfle_fac_list, S390_lowcore.alt_stfle_fac_list, + sizeof(lc->alt_stfle_fac_list)); } static void pcpu_attach_task(struct pcpu *pcpu, struct task_struct *tsk) -- GitLab From 43cccd87c184dc7414d74fb2deab8dd271129676 Mon Sep 17 00:00:00 2001 From: Martin Schwidefsky Date: Fri, 27 Apr 2018 07:36:31 +0200 Subject: [PATCH 1163/1635] s390: add options to change branch prediction behaviour for the kernel [ Upstream commit d768bd892fc8f066cd3aa000eb1867bcf32db0ee ] Add the PPA instruction to the system entry and exit path to switch the kernel to a different branch prediction behaviour. The instructions are added via CPU alternatives and can be disabled with the "nospec" or the "nobp=0" kernel parameter. If the default behaviour selected with CONFIG_KERNEL_NOBP is set to "n" then the "nobp=1" parameter can be used to enable the changed kernel branch prediction. Acked-by: Cornelia Huck Signed-off-by: Martin Schwidefsky Signed-off-by: Greg Kroah-Hartman --- arch/s390/Kconfig | 17 +++++++++++ arch/s390/include/asm/processor.h | 1 + arch/s390/kernel/alternative.c | 23 +++++++++++++++ arch/s390/kernel/early.c | 2 ++ arch/s390/kernel/entry.S | 48 +++++++++++++++++++++++++++++++ arch/s390/kernel/ipl.c | 1 + arch/s390/kernel/smp.c | 2 ++ 7 files changed, 94 insertions(+) diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig index 06e53763154b..6fdcf4f90ab2 100644 --- a/arch/s390/Kconfig +++ b/arch/s390/Kconfig @@ -538,6 +538,23 @@ config ARCH_RANDOM If unsure, say Y. +config KERNEL_NOBP + def_bool n + prompt "Enable modified branch prediction for the kernel by default" + help + If this option is selected the kernel will switch to a modified + branch prediction mode if the firmware interface is available. + The modified branch prediction mode improves the behaviour in + regard to speculative execution. + + With the option enabled the kernel parameter "nobp=0" or "nospec" + can be used to run the kernel in the normal branch prediction mode. + + With the option disabled the modified branch prediction mode is + enabled with the "nobp=1" kernel parameter. + + If unsure, say N. + endmenu menu "Memory setup" diff --git a/arch/s390/include/asm/processor.h b/arch/s390/include/asm/processor.h index 9cf92abe23c3..9c442f663fda 100644 --- a/arch/s390/include/asm/processor.h +++ b/arch/s390/include/asm/processor.h @@ -89,6 +89,7 @@ void cpu_detect_mhz_feature(void); extern const struct seq_operations cpuinfo_op; extern int sysctl_ieee_emulation_warnings; extern void execve_tail(void); +extern void __bpon(void); /* * User space process size: 2GB for 31 bit, 4TB or 8PT for 64 bit. diff --git a/arch/s390/kernel/alternative.c b/arch/s390/kernel/alternative.c index f5060af61176..ed21de98b79e 100644 --- a/arch/s390/kernel/alternative.c +++ b/arch/s390/kernel/alternative.c @@ -14,6 +14,29 @@ static int __init disable_alternative_instructions(char *str) early_param("noaltinstr", disable_alternative_instructions); +static int __init nobp_setup_early(char *str) +{ + bool enabled; + int rc; + + rc = kstrtobool(str, &enabled); + if (rc) + return rc; + if (enabled && test_facility(82)) + __set_facility(82, S390_lowcore.alt_stfle_fac_list); + else + __clear_facility(82, S390_lowcore.alt_stfle_fac_list); + return 0; +} +early_param("nobp", nobp_setup_early); + +static int __init nospec_setup_early(char *str) +{ + __clear_facility(82, S390_lowcore.alt_stfle_fac_list); + return 0; +} +early_param("nospec", nospec_setup_early); + struct brcl_insn { u16 opc; s32 disp; diff --git a/arch/s390/kernel/early.c b/arch/s390/kernel/early.c index 901d62eb1ff8..a3219837fa70 100644 --- a/arch/s390/kernel/early.c +++ b/arch/s390/kernel/early.c @@ -332,6 +332,8 @@ static noinline __init void setup_facility_list(void) memcpy(S390_lowcore.alt_stfle_fac_list, S390_lowcore.stfle_fac_list, sizeof(S390_lowcore.alt_stfle_fac_list)); + if (!IS_ENABLED(CONFIG_KERNEL_NOBP)) + __clear_facility(82, S390_lowcore.alt_stfle_fac_list); } static __init void detect_diag9c(void) diff --git a/arch/s390/kernel/entry.S b/arch/s390/kernel/entry.S index b8ddc0a2f03d..b1a61b06118a 100644 --- a/arch/s390/kernel/entry.S +++ b/arch/s390/kernel/entry.S @@ -158,6 +158,34 @@ _PIF_WORK = (_PIF_PER_TRAP | _PIF_SYSCALL_RESTART) tm off+\addr, \mask .endm + .macro BPOFF + .pushsection .altinstr_replacement, "ax" +660: .long 0xb2e8c000 + .popsection +661: .long 0x47000000 + .pushsection .altinstructions, "a" + .long 661b - . + .long 660b - . + .word 82 + .byte 4 + .byte 4 + .popsection + .endm + + .macro BPON + .pushsection .altinstr_replacement, "ax" +662: .long 0xb2e8d000 + .popsection +663: .long 0x47000000 + .pushsection .altinstructions, "a" + .long 663b - . + .long 662b - . + .word 82 + .byte 4 + .byte 4 + .popsection + .endm + .section .kprobes.text, "ax" .Ldummy: /* @@ -170,6 +198,11 @@ _PIF_WORK = (_PIF_PER_TRAP | _PIF_SYSCALL_RESTART) */ nop 0 +ENTRY(__bpon) + .globl __bpon + BPON + br %r14 + /* * Scheduler resume function, called by switch_to * gpr2 = (task_struct *) prev @@ -226,8 +259,11 @@ ENTRY(sie64a) jnz .Lsie_skip TSTMSK __LC_CPU_FLAGS,_CIF_FPU jo .Lsie_skip # exit if fp/vx regs changed + BPON .Lsie_entry: sie 0(%r14) +.Lsie_exit: + BPOFF .Lsie_skip: ni __SIE_PROG0C+3(%r14),0xfe # no longer in SIE lctlg %c1,%c1,__LC_USER_ASCE # load primary asce @@ -279,6 +315,7 @@ ENTRY(system_call) stpt __LC_SYNC_ENTER_TIMER .Lsysc_stmg: stmg %r8,%r15,__LC_SAVE_AREA_SYNC + BPOFF lg %r12,__LC_CURRENT lghi %r13,__TASK_thread lghi %r14,_PIF_SYSCALL @@ -325,6 +362,7 @@ ENTRY(system_call) jnz .Lsysc_work # check for work TSTMSK __LC_CPU_FLAGS,_CIF_WORK jnz .Lsysc_work + BPON .Lsysc_restore: lg %r14,__LC_VDSO_PER_CPU lmg %r0,%r10,__PT_R0(%r11) @@ -522,6 +560,7 @@ ENTRY(kernel_thread_starter) ENTRY(pgm_check_handler) stpt __LC_SYNC_ENTER_TIMER + BPOFF stmg %r8,%r15,__LC_SAVE_AREA_SYNC lg %r10,__LC_LAST_BREAK lg %r12,__LC_CURRENT @@ -626,6 +665,7 @@ ENTRY(pgm_check_handler) ENTRY(io_int_handler) STCK __LC_INT_CLOCK stpt __LC_ASYNC_ENTER_TIMER + BPOFF stmg %r8,%r15,__LC_SAVE_AREA_ASYNC lg %r12,__LC_CURRENT larl %r13,cleanup_critical @@ -676,9 +716,13 @@ ENTRY(io_int_handler) lg %r14,__LC_VDSO_PER_CPU lmg %r0,%r10,__PT_R0(%r11) mvc __LC_RETURN_PSW(16),__PT_PSW(%r11) + tm __PT_PSW+1(%r11),0x01 # returning to user ? + jno .Lio_exit_kernel + BPON .Lio_exit_timer: stpt __LC_EXIT_TIMER mvc __VDSO_ECTG_BASE(16,%r14),__LC_EXIT_TIMER +.Lio_exit_kernel: lmg %r11,%r15,__PT_R11(%r11) lpswe __LC_RETURN_PSW .Lio_done: @@ -841,6 +885,7 @@ ENTRY(io_int_handler) ENTRY(ext_int_handler) STCK __LC_INT_CLOCK stpt __LC_ASYNC_ENTER_TIMER + BPOFF stmg %r8,%r15,__LC_SAVE_AREA_ASYNC lg %r12,__LC_CURRENT larl %r13,cleanup_critical @@ -889,6 +934,7 @@ ENTRY(psw_idle) .Lpsw_idle_stcctm: #endif oi __LC_CPU_FLAGS+7,_CIF_ENABLED_WAIT + BPON STCK __CLOCK_IDLE_ENTER(%r2) stpt __TIMER_IDLE_ENTER(%r2) .Lpsw_idle_lpsw: @@ -989,6 +1035,7 @@ load_fpu_regs: */ ENTRY(mcck_int_handler) STCK __LC_MCCK_CLOCK + BPOFF la %r1,4095 # revalidate r1 spt __LC_CPU_TIMER_SAVE_AREA-4095(%r1) # revalidate cpu timer lmg %r0,%r15,__LC_GPREGS_SAVE_AREA-4095(%r1)# revalidate gprs @@ -1054,6 +1101,7 @@ ENTRY(mcck_int_handler) mvc __LC_RETURN_MCCK_PSW(16),__PT_PSW(%r11) # move return PSW tm __LC_RETURN_MCCK_PSW+1,0x01 # returning to user ? jno 0f + BPON stpt __LC_EXIT_TIMER mvc __VDSO_ECTG_BASE(16,%r14),__LC_EXIT_TIMER 0: lmg %r11,%r15,__PT_R11(%r11) diff --git a/arch/s390/kernel/ipl.c b/arch/s390/kernel/ipl.c index d1a0e2c521d7..b565e784bae8 100644 --- a/arch/s390/kernel/ipl.c +++ b/arch/s390/kernel/ipl.c @@ -564,6 +564,7 @@ static struct kset *ipl_kset; static void __ipl_run(void *unused) { + __bpon(); diag308(DIAG308_LOAD_CLEAR, NULL); if (MACHINE_IS_VM) __cpcmd("IPL", NULL, 0, NULL); diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c index e906b77deb90..98f3e5ef07ee 100644 --- a/arch/s390/kernel/smp.c +++ b/arch/s390/kernel/smp.c @@ -334,6 +334,7 @@ static void pcpu_delegate(struct pcpu *pcpu, void (*func)(void *), mem_assign_absolute(lc->restart_fn, (unsigned long) func); mem_assign_absolute(lc->restart_data, (unsigned long) data); mem_assign_absolute(lc->restart_source, source_cpu); + __bpon(); asm volatile( "0: sigp 0,%0,%2 # sigp restart to target cpu\n" " brc 2,0b # busy, try again\n" @@ -909,6 +910,7 @@ void __cpu_die(unsigned int cpu) void __noreturn cpu_die(void) { idle_task_exit(); + __bpon(); pcpu_sigp_retry(pcpu_devices + smp_processor_id(), SIGP_STOP, 0); for (;;) ; } -- GitLab From 0bd4c47c20265763f280bddeabfc3e67b24a26f0 Mon Sep 17 00:00:00 2001 From: Martin Schwidefsky Date: Fri, 27 Apr 2018 07:36:32 +0200 Subject: [PATCH 1164/1635] s390: run user space and KVM guests with modified branch prediction [ Upstream commit 6b73044b2b0081ee3dd1cd6eaab7dee552601efb ] Define TIF_ISOLATE_BP and TIF_ISOLATE_BP_GUEST and add the necessary plumbing in entry.S to be able to run user space and KVM guests with limited branch prediction. To switch a user space process to limited branch prediction the s390_isolate_bp() function has to be call, and to run a vCPU of a KVM guest associated with the current task with limited branch prediction call s390_isolate_bp_guest(). Signed-off-by: Martin Schwidefsky Signed-off-by: Greg Kroah-Hartman --- arch/s390/include/asm/processor.h | 3 ++ arch/s390/include/asm/thread_info.h | 4 +++ arch/s390/kernel/entry.S | 51 ++++++++++++++++++++++++++--- arch/s390/kernel/processor.c | 18 ++++++++++ 4 files changed, 71 insertions(+), 5 deletions(-) diff --git a/arch/s390/include/asm/processor.h b/arch/s390/include/asm/processor.h index 9c442f663fda..0a39cd102c49 100644 --- a/arch/s390/include/asm/processor.h +++ b/arch/s390/include/asm/processor.h @@ -378,6 +378,9 @@ extern void memcpy_absolute(void *, void *, size_t); memcpy_absolute(&(dest), &__tmp, sizeof(__tmp)); \ } while (0) +extern int s390_isolate_bp(void); +extern int s390_isolate_bp_guest(void); + #endif /* __ASSEMBLY__ */ #endif /* __ASM_S390_PROCESSOR_H */ diff --git a/arch/s390/include/asm/thread_info.h b/arch/s390/include/asm/thread_info.h index 0880a37b6d3b..301b4f70bf31 100644 --- a/arch/s390/include/asm/thread_info.h +++ b/arch/s390/include/asm/thread_info.h @@ -60,6 +60,8 @@ int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src); #define TIF_GUARDED_STORAGE 4 /* load guarded storage control block */ #define TIF_PATCH_PENDING 5 /* pending live patching update */ #define TIF_PGSTE 6 /* New mm's will use 4K page tables */ +#define TIF_ISOLATE_BP 8 /* Run process with isolated BP */ +#define TIF_ISOLATE_BP_GUEST 9 /* Run KVM guests with isolated BP */ #define TIF_31BIT 16 /* 32bit process */ #define TIF_MEMDIE 17 /* is terminating due to OOM killer */ @@ -80,6 +82,8 @@ int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src); #define _TIF_UPROBE _BITUL(TIF_UPROBE) #define _TIF_GUARDED_STORAGE _BITUL(TIF_GUARDED_STORAGE) #define _TIF_PATCH_PENDING _BITUL(TIF_PATCH_PENDING) +#define _TIF_ISOLATE_BP _BITUL(TIF_ISOLATE_BP) +#define _TIF_ISOLATE_BP_GUEST _BITUL(TIF_ISOLATE_BP_GUEST) #define _TIF_31BIT _BITUL(TIF_31BIT) #define _TIF_SINGLE_STEP _BITUL(TIF_SINGLE_STEP) diff --git a/arch/s390/kernel/entry.S b/arch/s390/kernel/entry.S index b1a61b06118a..bb9a6a9808e9 100644 --- a/arch/s390/kernel/entry.S +++ b/arch/s390/kernel/entry.S @@ -106,6 +106,7 @@ _PIF_WORK = (_PIF_PER_TRAP | _PIF_SYSCALL_RESTART) aghi %r15,-(STACK_FRAME_OVERHEAD + __PT_SIZE) j 3f 1: UPDATE_VTIME %r14,%r15,\timer + BPENTER __TI_flags(%r12),_TIF_ISOLATE_BP 2: lg %r15,__LC_ASYNC_STACK # load async stack 3: la %r11,STACK_FRAME_OVERHEAD(%r15) .endm @@ -186,6 +187,40 @@ _PIF_WORK = (_PIF_PER_TRAP | _PIF_SYSCALL_RESTART) .popsection .endm + .macro BPENTER tif_ptr,tif_mask + .pushsection .altinstr_replacement, "ax" +662: .word 0xc004, 0x0000, 0x0000 # 6 byte nop + .word 0xc004, 0x0000, 0x0000 # 6 byte nop + .popsection +664: TSTMSK \tif_ptr,\tif_mask + jz . + 8 + .long 0xb2e8d000 + .pushsection .altinstructions, "a" + .long 664b - . + .long 662b - . + .word 82 + .byte 12 + .byte 12 + .popsection + .endm + + .macro BPEXIT tif_ptr,tif_mask + TSTMSK \tif_ptr,\tif_mask + .pushsection .altinstr_replacement, "ax" +662: jnz . + 8 + .long 0xb2e8d000 + .popsection +664: jz . + 8 + .long 0xb2e8c000 + .pushsection .altinstructions, "a" + .long 664b - . + .long 662b - . + .word 82 + .byte 8 + .byte 8 + .popsection + .endm + .section .kprobes.text, "ax" .Ldummy: /* @@ -240,9 +275,11 @@ ENTRY(__switch_to) */ ENTRY(sie64a) stmg %r6,%r14,__SF_GPRS(%r15) # save kernel registers + lg %r12,__LC_CURRENT stg %r2,__SF_EMPTY(%r15) # save control block pointer stg %r3,__SF_EMPTY+8(%r15) # save guest register save area xc __SF_EMPTY+16(8,%r15),__SF_EMPTY+16(%r15) # reason code = 0 + mvc __SF_EMPTY+24(8,%r15),__TI_flags(%r12) # copy thread flags TSTMSK __LC_CPU_FLAGS,_CIF_FPU # load guest fp/vx registers ? jno .Lsie_load_guest_gprs brasl %r14,load_fpu_regs # load guest fp/vx regs @@ -259,11 +296,12 @@ ENTRY(sie64a) jnz .Lsie_skip TSTMSK __LC_CPU_FLAGS,_CIF_FPU jo .Lsie_skip # exit if fp/vx regs changed - BPON + BPEXIT __SF_EMPTY+24(%r15),(_TIF_ISOLATE_BP|_TIF_ISOLATE_BP_GUEST) .Lsie_entry: sie 0(%r14) .Lsie_exit: BPOFF + BPENTER __SF_EMPTY+24(%r15),(_TIF_ISOLATE_BP|_TIF_ISOLATE_BP_GUEST) .Lsie_skip: ni __SIE_PROG0C+3(%r14),0xfe # no longer in SIE lctlg %c1,%c1,__LC_USER_ASCE # load primary asce @@ -324,6 +362,7 @@ ENTRY(system_call) la %r11,STACK_FRAME_OVERHEAD(%r15) # pointer to pt_regs .Lsysc_vtime: UPDATE_VTIME %r8,%r9,__LC_SYNC_ENTER_TIMER + BPENTER __TI_flags(%r12),_TIF_ISOLATE_BP stmg %r0,%r7,__PT_R0(%r11) # clear user controlled register to prevent speculative use xgr %r0,%r0 @@ -362,7 +401,7 @@ ENTRY(system_call) jnz .Lsysc_work # check for work TSTMSK __LC_CPU_FLAGS,_CIF_WORK jnz .Lsysc_work - BPON + BPEXIT __TI_flags(%r12),_TIF_ISOLATE_BP .Lsysc_restore: lg %r14,__LC_VDSO_PER_CPU lmg %r0,%r10,__PT_R0(%r11) @@ -587,6 +626,7 @@ ENTRY(pgm_check_handler) aghi %r15,-(STACK_FRAME_OVERHEAD + __PT_SIZE) j 4f 2: UPDATE_VTIME %r14,%r15,__LC_SYNC_ENTER_TIMER + BPENTER __TI_flags(%r12),_TIF_ISOLATE_BP lg %r15,__LC_KERNEL_STACK lgr %r14,%r12 aghi %r14,__TASK_thread # pointer to thread_struct @@ -718,7 +758,7 @@ ENTRY(io_int_handler) mvc __LC_RETURN_PSW(16),__PT_PSW(%r11) tm __PT_PSW+1(%r11),0x01 # returning to user ? jno .Lio_exit_kernel - BPON + BPEXIT __TI_flags(%r12),_TIF_ISOLATE_BP .Lio_exit_timer: stpt __LC_EXIT_TIMER mvc __VDSO_ECTG_BASE(16,%r14),__LC_EXIT_TIMER @@ -1101,7 +1141,7 @@ ENTRY(mcck_int_handler) mvc __LC_RETURN_MCCK_PSW(16),__PT_PSW(%r11) # move return PSW tm __LC_RETURN_MCCK_PSW+1,0x01 # returning to user ? jno 0f - BPON + BPEXIT __TI_flags(%r12),_TIF_ISOLATE_BP stpt __LC_EXIT_TIMER mvc __VDSO_ECTG_BASE(16,%r14),__LC_EXIT_TIMER 0: lmg %r11,%r15,__PT_R11(%r11) @@ -1228,7 +1268,8 @@ cleanup_critical: clg %r9,BASED(.Lsie_crit_mcck_length) jh 1f oi __LC_CPU_FLAGS+7, _CIF_MCCK_GUEST -1: lg %r9,__SF_EMPTY(%r15) # get control block pointer +1: BPENTER __SF_EMPTY+24(%r15),(_TIF_ISOLATE_BP|_TIF_ISOLATE_BP_GUEST) + lg %r9,__SF_EMPTY(%r15) # get control block pointer ni __SIE_PROG0C+3(%r9),0xfe # no longer in SIE lctlg %c1,%c1,__LC_USER_ASCE # load primary asce larl %r9,sie_exit # skip forward to sie_exit diff --git a/arch/s390/kernel/processor.c b/arch/s390/kernel/processor.c index 5362fd868d0d..6fe2e1875058 100644 --- a/arch/s390/kernel/processor.c +++ b/arch/s390/kernel/processor.c @@ -197,3 +197,21 @@ const struct seq_operations cpuinfo_op = { .stop = c_stop, .show = show_cpuinfo, }; + +int s390_isolate_bp(void) +{ + if (!test_facility(82)) + return -EOPNOTSUPP; + set_thread_flag(TIF_ISOLATE_BP); + return 0; +} +EXPORT_SYMBOL(s390_isolate_bp); + +int s390_isolate_bp_guest(void) +{ + if (!test_facility(82)) + return -EOPNOTSUPP; + set_thread_flag(TIF_ISOLATE_BP_GUEST); + return 0; +} +EXPORT_SYMBOL(s390_isolate_bp_guest); -- GitLab From b609eb65f3158b986e7b80e4fa48665291a50564 Mon Sep 17 00:00:00 2001 From: Martin Schwidefsky Date: Fri, 27 Apr 2018 07:36:33 +0200 Subject: [PATCH 1165/1635] s390: introduce execute-trampolines for branches [ Upstream commit f19fbd5ed642dc31c809596412dab1ed56f2f156 ] Add CONFIG_EXPOLINE to enable the use of the new -mindirect-branch= and -mfunction_return= compiler options to create a kernel fortified against the specte v2 attack. With CONFIG_EXPOLINE=y all indirect branches will be issued with an execute type instruction. For z10 or newer the EXRL instruction will be used, for older machines the EX instruction. The typical indirect call basr %r14,%r1 is replaced with a PC relative call to a new thunk brasl %r14,__s390x_indirect_jump_r1 The thunk contains the EXRL/EX instruction to the indirect branch __s390x_indirect_jump_r1: exrl 0,0f j . 0: br %r1 The detour via the execute type instruction has a performance impact. To get rid of the detour the new kernel parameter "nospectre_v2" and "spectre_v2=[on,off,auto]" can be used. If the parameter is specified the kernel and module code will be patched at runtime. Signed-off-by: Martin Schwidefsky Signed-off-by: Greg Kroah-Hartman --- arch/s390/Kconfig | 28 +++++++ arch/s390/Makefile | 10 +++ arch/s390/include/asm/lowcore.h | 4 +- arch/s390/include/asm/nospec-branch.h | 18 ++++ arch/s390/kernel/Makefile | 4 + arch/s390/kernel/entry.S | 113 ++++++++++++++++++++------ arch/s390/kernel/module.c | 62 ++++++++++++-- arch/s390/kernel/nospec-branch.c | 101 +++++++++++++++++++++++ arch/s390/kernel/setup.c | 4 + arch/s390/kernel/smp.c | 1 + arch/s390/kernel/vmlinux.lds.S | 14 ++++ drivers/s390/char/Makefile | 2 + 12 files changed, 326 insertions(+), 35 deletions(-) create mode 100644 arch/s390/include/asm/nospec-branch.h create mode 100644 arch/s390/kernel/nospec-branch.c diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig index 6fdcf4f90ab2..39cd1ed804a8 100644 --- a/arch/s390/Kconfig +++ b/arch/s390/Kconfig @@ -555,6 +555,34 @@ config KERNEL_NOBP If unsure, say N. +config EXPOLINE + def_bool n + prompt "Avoid speculative indirect branches in the kernel" + help + Compile the kernel with the expoline compiler options to guard + against kernel-to-user data leaks by avoiding speculative indirect + branches. + Requires a compiler with -mindirect-branch=thunk support for full + protection. The kernel may run slower. + + If unsure, say N. + +choice + prompt "Expoline default" + depends on EXPOLINE + default EXPOLINE_FULL + +config EXPOLINE_OFF + bool "spectre_v2=off" + +config EXPOLINE_MEDIUM + bool "spectre_v2=auto" + +config EXPOLINE_FULL + bool "spectre_v2=on" + +endchoice + endmenu menu "Memory setup" diff --git a/arch/s390/Makefile b/arch/s390/Makefile index dac821cfcd43..98f50b2fc0ec 100644 --- a/arch/s390/Makefile +++ b/arch/s390/Makefile @@ -81,6 +81,16 @@ ifeq ($(call cc-option-yn,-mwarn-dynamicstack),y) cflags-$(CONFIG_WARN_DYNAMIC_STACK) += -mwarn-dynamicstack endif +ifdef CONFIG_EXPOLINE + ifeq ($(call cc-option-yn,$(CC_FLAGS_MARCH) -mindirect-branch=thunk),y) + CC_FLAGS_EXPOLINE := -mindirect-branch=thunk + CC_FLAGS_EXPOLINE += -mfunction-return=thunk + CC_FLAGS_EXPOLINE += -mindirect-branch-table + export CC_FLAGS_EXPOLINE + cflags-y += $(CC_FLAGS_EXPOLINE) + endif +endif + ifdef CONFIG_FUNCTION_TRACER # make use of hotpatch feature if the compiler supports it cc_hotpatch := -mhotpatch=0,3 diff --git a/arch/s390/include/asm/lowcore.h b/arch/s390/include/asm/lowcore.h index 26d742f8dd93..88a212df0dbc 100644 --- a/arch/s390/include/asm/lowcore.h +++ b/arch/s390/include/asm/lowcore.h @@ -140,7 +140,9 @@ struct lowcore { /* Per cpu primary space access list */ __u32 paste[16]; /* 0x0400 */ - __u8 pad_0x04c0[0x0e00-0x0440]; /* 0x0440 */ + /* br %r1 trampoline */ + __u16 br_r1_trampoline; /* 0x0440 */ + __u8 pad_0x0442[0x0e00-0x0442]; /* 0x0442 */ /* * 0xe00 contains the address of the IPL Parameter Information diff --git a/arch/s390/include/asm/nospec-branch.h b/arch/s390/include/asm/nospec-branch.h new file mode 100644 index 000000000000..7df48e5cf36f --- /dev/null +++ b/arch/s390/include/asm/nospec-branch.h @@ -0,0 +1,18 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _ASM_S390_EXPOLINE_H +#define _ASM_S390_EXPOLINE_H + +#ifndef __ASSEMBLY__ + +#include + +extern int nospec_call_disable; +extern int nospec_return_disable; + +void nospec_init_branches(void); +void nospec_call_revert(s32 *start, s32 *end); +void nospec_return_revert(s32 *start, s32 *end); + +#endif /* __ASSEMBLY__ */ + +#endif /* _ASM_S390_EXPOLINE_H */ diff --git a/arch/s390/kernel/Makefile b/arch/s390/kernel/Makefile index 41d706897a30..3882b29f8d02 100644 --- a/arch/s390/kernel/Makefile +++ b/arch/s390/kernel/Makefile @@ -29,6 +29,7 @@ UBSAN_SANITIZE_early.o := n # ifneq ($(CC_FLAGS_MARCH),-march=z900) CFLAGS_REMOVE_als.o += $(CC_FLAGS_MARCH) +CFLAGS_REMOVE_als.o += $(CC_FLAGS_EXPOLINE) CFLAGS_als.o += -march=z900 AFLAGS_REMOVE_head.o += $(CC_FLAGS_MARCH) AFLAGS_head.o += -march=z900 @@ -61,6 +62,9 @@ obj-y += entry.o reipl.o relocate_kernel.o kdebugfs.o alternative.o extra-y += head.o head64.o vmlinux.lds +obj-$(CONFIG_EXPOLINE) += nospec-branch.o +CFLAGS_REMOVE_expoline.o += $(CC_FLAGS_EXPOLINE) + obj-$(CONFIG_MODULES) += module.o obj-$(CONFIG_SMP) += smp.o obj-$(CONFIG_SCHED_TOPOLOGY) += topology.o diff --git a/arch/s390/kernel/entry.S b/arch/s390/kernel/entry.S index bb9a6a9808e9..1888b1010e20 100644 --- a/arch/s390/kernel/entry.S +++ b/arch/s390/kernel/entry.S @@ -221,6 +221,68 @@ _PIF_WORK = (_PIF_PER_TRAP | _PIF_SYSCALL_RESTART) .popsection .endm +#ifdef CONFIG_EXPOLINE + + .macro GEN_BR_THUNK name,reg,tmp + .section .text.\name,"axG",@progbits,\name,comdat + .globl \name + .hidden \name + .type \name,@function +\name: + .cfi_startproc +#ifdef CONFIG_HAVE_MARCH_Z10_FEATURES + exrl 0,0f +#else + larl \tmp,0f + ex 0,0(\tmp) +#endif + j . +0: br \reg + .cfi_endproc + .endm + + GEN_BR_THUNK __s390x_indirect_jump_r1use_r9,%r9,%r1 + GEN_BR_THUNK __s390x_indirect_jump_r1use_r14,%r14,%r1 + GEN_BR_THUNK __s390x_indirect_jump_r11use_r14,%r14,%r11 + + .macro BASR_R14_R9 +0: brasl %r14,__s390x_indirect_jump_r1use_r9 + .pushsection .s390_indirect_branches,"a",@progbits + .long 0b-. + .popsection + .endm + + .macro BR_R1USE_R14 +0: jg __s390x_indirect_jump_r1use_r14 + .pushsection .s390_indirect_branches,"a",@progbits + .long 0b-. + .popsection + .endm + + .macro BR_R11USE_R14 +0: jg __s390x_indirect_jump_r11use_r14 + .pushsection .s390_indirect_branches,"a",@progbits + .long 0b-. + .popsection + .endm + +#else /* CONFIG_EXPOLINE */ + + .macro BASR_R14_R9 + basr %r14,%r9 + .endm + + .macro BR_R1USE_R14 + br %r14 + .endm + + .macro BR_R11USE_R14 + br %r14 + .endm + +#endif /* CONFIG_EXPOLINE */ + + .section .kprobes.text, "ax" .Ldummy: /* @@ -236,7 +298,7 @@ _PIF_WORK = (_PIF_PER_TRAP | _PIF_SYSCALL_RESTART) ENTRY(__bpon) .globl __bpon BPON - br %r14 + BR_R1USE_R14 /* * Scheduler resume function, called by switch_to @@ -261,9 +323,9 @@ ENTRY(__switch_to) mvc __LC_CURRENT_PID(4,%r0),__TASK_pid(%r3) # store pid of next lmg %r6,%r15,__SF_GPRS(%r15) # load gprs of next task TSTMSK __LC_MACHINE_FLAGS,MACHINE_FLAG_LPP - bzr %r14 + jz 0f .insn s,0xb2800000,__LC_LPP # set program parameter - br %r14 +0: BR_R1USE_R14 .L__critical_start: @@ -330,7 +392,7 @@ sie_exit: xgr %r5,%r5 lmg %r6,%r14,__SF_GPRS(%r15) # restore kernel registers lg %r2,__SF_EMPTY+16(%r15) # return exit reason code - br %r14 + BR_R1USE_R14 .Lsie_fault: lghi %r14,-EFAULT stg %r14,__SF_EMPTY+16(%r15) # set exit reason code @@ -389,7 +451,7 @@ ENTRY(system_call) lgf %r9,0(%r8,%r10) # get system call add. TSTMSK __TI_flags(%r12),_TIF_TRACE jnz .Lsysc_tracesys - basr %r14,%r9 # call sys_xxxx + BASR_R14_R9 # call sys_xxxx stg %r2,__PT_R2(%r11) # store return value .Lsysc_return: @@ -566,7 +628,7 @@ ENTRY(system_call) lmg %r3,%r7,__PT_R3(%r11) stg %r7,STACK_FRAME_OVERHEAD(%r15) lg %r2,__PT_ORIG_GPR2(%r11) - basr %r14,%r9 # call sys_xxx + BASR_R14_R9 # call sys_xxx stg %r2,__PT_R2(%r11) # store return value .Lsysc_tracenogo: TSTMSK __TI_flags(%r12),_TIF_TRACE @@ -590,7 +652,7 @@ ENTRY(ret_from_fork) lmg %r9,%r10,__PT_R9(%r11) # load gprs ENTRY(kernel_thread_starter) la %r2,0(%r10) - basr %r14,%r9 + BASR_R14_R9 j .Lsysc_tracenogo /* @@ -667,9 +729,9 @@ ENTRY(pgm_check_handler) nill %r10,0x007f sll %r10,2 je .Lpgm_return - lgf %r1,0(%r10,%r1) # load address of handler routine + lgf %r9,0(%r10,%r1) # load address of handler routine lgr %r2,%r11 # pass pointer to pt_regs - basr %r14,%r1 # branch to interrupt-handler + BASR_R14_R9 # branch to interrupt-handler .Lpgm_return: LOCKDEP_SYS_EXIT tm __PT_PSW+1(%r11),0x01 # returning to user ? @@ -979,7 +1041,7 @@ ENTRY(psw_idle) stpt __TIMER_IDLE_ENTER(%r2) .Lpsw_idle_lpsw: lpswe __SF_EMPTY(%r15) - br %r14 + BR_R1USE_R14 .Lpsw_idle_end: /* @@ -993,7 +1055,7 @@ ENTRY(save_fpu_regs) lg %r2,__LC_CURRENT aghi %r2,__TASK_thread TSTMSK __LC_CPU_FLAGS,_CIF_FPU - bor %r14 + jo .Lsave_fpu_regs_exit stfpc __THREAD_FPU_fpc(%r2) lg %r3,__THREAD_FPU_regs(%r2) TSTMSK __LC_MACHINE_FLAGS,MACHINE_FLAG_VX @@ -1020,7 +1082,8 @@ ENTRY(save_fpu_regs) std 15,120(%r3) .Lsave_fpu_regs_done: oi __LC_CPU_FLAGS+7,_CIF_FPU - br %r14 +.Lsave_fpu_regs_exit: + BR_R1USE_R14 .Lsave_fpu_regs_end: EXPORT_SYMBOL(save_fpu_regs) @@ -1038,7 +1101,7 @@ load_fpu_regs: lg %r4,__LC_CURRENT aghi %r4,__TASK_thread TSTMSK __LC_CPU_FLAGS,_CIF_FPU - bnor %r14 + jno .Lload_fpu_regs_exit lfpc __THREAD_FPU_fpc(%r4) TSTMSK __LC_MACHINE_FLAGS,MACHINE_FLAG_VX lg %r4,__THREAD_FPU_regs(%r4) # %r4 <- reg save area @@ -1065,7 +1128,8 @@ load_fpu_regs: ld 15,120(%r4) .Lload_fpu_regs_done: ni __LC_CPU_FLAGS+7,255-_CIF_FPU - br %r14 +.Lload_fpu_regs_exit: + BR_R1USE_R14 .Lload_fpu_regs_end: .L__critical_end: @@ -1237,7 +1301,7 @@ cleanup_critical: jl 0f clg %r9,BASED(.Lcleanup_table+104) # .Lload_fpu_regs_end jl .Lcleanup_load_fpu_regs -0: br %r14 +0: BR_R11USE_R14 .align 8 .Lcleanup_table: @@ -1273,7 +1337,7 @@ cleanup_critical: ni __SIE_PROG0C+3(%r9),0xfe # no longer in SIE lctlg %c1,%c1,__LC_USER_ASCE # load primary asce larl %r9,sie_exit # skip forward to sie_exit - br %r14 + BR_R11USE_R14 #endif .Lcleanup_system_call: @@ -1326,7 +1390,7 @@ cleanup_critical: stg %r15,56(%r11) # r15 stack pointer # set new psw address and exit larl %r9,.Lsysc_do_svc - br %r14 + BR_R11USE_R14 .Lcleanup_system_call_insn: .quad system_call .quad .Lsysc_stmg @@ -1338,7 +1402,7 @@ cleanup_critical: .Lcleanup_sysc_tif: larl %r9,.Lsysc_tif - br %r14 + BR_R11USE_R14 .Lcleanup_sysc_restore: # check if stpt has been executed @@ -1355,14 +1419,14 @@ cleanup_critical: mvc 0(64,%r11),__PT_R8(%r9) lmg %r0,%r7,__PT_R0(%r9) 1: lmg %r8,%r9,__LC_RETURN_PSW - br %r14 + BR_R11USE_R14 .Lcleanup_sysc_restore_insn: .quad .Lsysc_exit_timer .quad .Lsysc_done - 4 .Lcleanup_io_tif: larl %r9,.Lio_tif - br %r14 + BR_R11USE_R14 .Lcleanup_io_restore: # check if stpt has been executed @@ -1376,7 +1440,7 @@ cleanup_critical: mvc 0(64,%r11),__PT_R8(%r9) lmg %r0,%r7,__PT_R0(%r9) 1: lmg %r8,%r9,__LC_RETURN_PSW - br %r14 + BR_R11USE_R14 .Lcleanup_io_restore_insn: .quad .Lio_exit_timer .quad .Lio_done - 4 @@ -1429,17 +1493,17 @@ cleanup_critical: # prepare return psw nihh %r8,0xfcfd # clear irq & wait state bits lg %r9,48(%r11) # return from psw_idle - br %r14 + BR_R11USE_R14 .Lcleanup_idle_insn: .quad .Lpsw_idle_lpsw .Lcleanup_save_fpu_regs: larl %r9,save_fpu_regs - br %r14 + BR_R11USE_R14 .Lcleanup_load_fpu_regs: larl %r9,load_fpu_regs - br %r14 + BR_R11USE_R14 /* * Integer constants @@ -1459,7 +1523,6 @@ cleanup_critical: .Lsie_crit_mcck_length: .quad .Lsie_skip - .Lsie_entry #endif - .section .rodata, "a" #define SYSCALL(esame,emu) .long esame .globl sys_call_table diff --git a/arch/s390/kernel/module.c b/arch/s390/kernel/module.c index 7b87991416fd..89d7ab711255 100644 --- a/arch/s390/kernel/module.c +++ b/arch/s390/kernel/module.c @@ -32,6 +32,8 @@ #include #include #include +#include +#include #if 0 #define DEBUGP printk @@ -169,7 +171,11 @@ int module_frob_arch_sections(Elf_Ehdr *hdr, Elf_Shdr *sechdrs, me->arch.got_offset = me->core_layout.size; me->core_layout.size += me->arch.got_size; me->arch.plt_offset = me->core_layout.size; - me->core_layout.size += me->arch.plt_size; + if (me->arch.plt_size) { + if (IS_ENABLED(CONFIG_EXPOLINE) && !nospec_call_disable) + me->arch.plt_size += PLT_ENTRY_SIZE; + me->core_layout.size += me->arch.plt_size; + } return 0; } @@ -323,9 +329,21 @@ static int apply_rela(Elf_Rela *rela, Elf_Addr base, Elf_Sym *symtab, unsigned int *ip; ip = me->core_layout.base + me->arch.plt_offset + info->plt_offset; - ip[0] = 0x0d10e310; /* basr 1,0; lg 1,10(1); br 1 */ - ip[1] = 0x100a0004; - ip[2] = 0x07f10000; + ip[0] = 0x0d10e310; /* basr 1,0 */ + ip[1] = 0x100a0004; /* lg 1,10(1) */ + if (IS_ENABLED(CONFIG_EXPOLINE) && + !nospec_call_disable) { + unsigned int *ij; + ij = me->core_layout.base + + me->arch.plt_offset + + me->arch.plt_size - PLT_ENTRY_SIZE; + ip[2] = 0xa7f40000 + /* j __jump_r1 */ + (unsigned int)(u16) + (((unsigned long) ij - 8 - + (unsigned long) ip) / 2); + } else { + ip[2] = 0x07f10000; /* br %r1 */ + } ip[3] = (unsigned int) (val >> 32); ip[4] = (unsigned int) val; info->plt_initialized = 1; @@ -431,16 +449,42 @@ int module_finalize(const Elf_Ehdr *hdr, struct module *me) { const Elf_Shdr *s; - char *secstrings; + char *secstrings, *secname; + void *aseg; + + if (IS_ENABLED(CONFIG_EXPOLINE) && + !nospec_call_disable && me->arch.plt_size) { + unsigned int *ij; + + ij = me->core_layout.base + me->arch.plt_offset + + me->arch.plt_size - PLT_ENTRY_SIZE; + if (test_facility(35)) { + ij[0] = 0xc6000000; /* exrl %r0,.+10 */ + ij[1] = 0x0005a7f4; /* j . */ + ij[2] = 0x000007f1; /* br %r1 */ + } else { + ij[0] = 0x44000000 | (unsigned int) + offsetof(struct lowcore, br_r1_trampoline); + ij[1] = 0xa7f40000; /* j . */ + } + } secstrings = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset; for (s = sechdrs; s < sechdrs + hdr->e_shnum; s++) { - if (!strcmp(".altinstructions", secstrings + s->sh_name)) { - /* patch .altinstructions */ - void *aseg = (void *)s->sh_addr; + aseg = (void *) s->sh_addr; + secname = secstrings + s->sh_name; + if (!strcmp(".altinstructions", secname)) + /* patch .altinstructions */ apply_alternatives(aseg, aseg + s->sh_size); - } + + if (IS_ENABLED(CONFIG_EXPOLINE) && + (!strcmp(".nospec_call_table", secname))) + nospec_call_revert(aseg, aseg + s->sh_size); + + if (IS_ENABLED(CONFIG_EXPOLINE) && + (!strcmp(".nospec_return_table", secname))) + nospec_return_revert(aseg, aseg + s->sh_size); } jump_label_apply_nops(me); diff --git a/arch/s390/kernel/nospec-branch.c b/arch/s390/kernel/nospec-branch.c new file mode 100644 index 000000000000..86ee26a612cf --- /dev/null +++ b/arch/s390/kernel/nospec-branch.c @@ -0,0 +1,101 @@ +// SPDX-License-Identifier: GPL-2.0 +#include +#include +#include + +int nospec_call_disable = IS_ENABLED(EXPOLINE_OFF); +int nospec_return_disable = !IS_ENABLED(EXPOLINE_FULL); + +static int __init nospectre_v2_setup_early(char *str) +{ + nospec_call_disable = 1; + nospec_return_disable = 1; + return 0; +} +early_param("nospectre_v2", nospectre_v2_setup_early); + +static int __init spectre_v2_setup_early(char *str) +{ + if (str && !strncmp(str, "on", 2)) { + nospec_call_disable = 0; + nospec_return_disable = 0; + } + if (str && !strncmp(str, "off", 3)) { + nospec_call_disable = 1; + nospec_return_disable = 1; + } + if (str && !strncmp(str, "auto", 4)) { + nospec_call_disable = 0; + nospec_return_disable = 1; + } + return 0; +} +early_param("spectre_v2", spectre_v2_setup_early); + +static void __init_or_module __nospec_revert(s32 *start, s32 *end) +{ + enum { BRCL_EXPOLINE, BRASL_EXPOLINE } type; + u8 *instr, *thunk, *br; + u8 insnbuf[6]; + s32 *epo; + + /* Second part of the instruction replace is always a nop */ + memcpy(insnbuf + 2, (char[]) { 0x47, 0x00, 0x00, 0x00 }, 4); + for (epo = start; epo < end; epo++) { + instr = (u8 *) epo + *epo; + if (instr[0] == 0xc0 && (instr[1] & 0x0f) == 0x04) + type = BRCL_EXPOLINE; /* brcl instruction */ + else if (instr[0] == 0xc0 && (instr[1] & 0x0f) == 0x05) + type = BRASL_EXPOLINE; /* brasl instruction */ + else + continue; + thunk = instr + (*(int *)(instr + 2)) * 2; + if (thunk[0] == 0xc6 && thunk[1] == 0x00) + /* exrl %r0, */ + br = thunk + (*(int *)(thunk + 2)) * 2; + else if (thunk[0] == 0xc0 && (thunk[1] & 0x0f) == 0x00 && + thunk[6] == 0x44 && thunk[7] == 0x00 && + (thunk[8] & 0x0f) == 0x00 && thunk[9] == 0x00 && + (thunk[1] & 0xf0) == (thunk[8] & 0xf0)) + /* larl %rx, + ex %r0,0(%rx) */ + br = thunk + (*(int *)(thunk + 2)) * 2; + else + continue; + if (br[0] != 0x07 || (br[1] & 0xf0) != 0xf0) + continue; + switch (type) { + case BRCL_EXPOLINE: + /* brcl to thunk, replace with br + nop */ + insnbuf[0] = br[0]; + insnbuf[1] = (instr[1] & 0xf0) | (br[1] & 0x0f); + break; + case BRASL_EXPOLINE: + /* brasl to thunk, replace with basr + nop */ + insnbuf[0] = 0x0d; + insnbuf[1] = (instr[1] & 0xf0) | (br[1] & 0x0f); + break; + } + + s390_kernel_write(instr, insnbuf, 6); + } +} + +void __init_or_module nospec_call_revert(s32 *start, s32 *end) +{ + if (nospec_call_disable) + __nospec_revert(start, end); +} + +void __init_or_module nospec_return_revert(s32 *start, s32 *end) +{ + if (nospec_return_disable) + __nospec_revert(start, end); +} + +extern s32 __nospec_call_start[], __nospec_call_end[]; +extern s32 __nospec_return_start[], __nospec_return_end[]; +void __init nospec_init_branches(void) +{ + nospec_call_revert(__nospec_call_start, __nospec_call_end); + nospec_return_revert(__nospec_return_start, __nospec_return_end); +} diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c index a9f05162d294..63d5cbb9a8b4 100644 --- a/arch/s390/kernel/setup.c +++ b/arch/s390/kernel/setup.c @@ -67,6 +67,7 @@ #include #include #include +#include #include "entry.h" /* @@ -384,6 +385,7 @@ static void __init setup_lowcore(void) #ifdef CONFIG_SMP lc->spinlock_lockval = arch_spin_lockval(0); #endif + lc->br_r1_trampoline = 0x07f1; /* br %r1 */ set_prefix((u32)(unsigned long) lc); lowcore_ptr[0] = lc; @@ -959,6 +961,8 @@ void __init setup_arch(char **cmdline_p) set_preferred_console(); apply_alternative_instructions(); + if (IS_ENABLED(CONFIG_EXPOLINE)) + nospec_init_branches(); /* Setup zfcpdump support */ setup_zfcpdump(); diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c index 98f3e5ef07ee..ae5df4177803 100644 --- a/arch/s390/kernel/smp.c +++ b/arch/s390/kernel/smp.c @@ -228,6 +228,7 @@ static int pcpu_alloc_lowcore(struct pcpu *pcpu, int cpu) lc->mcesad = mcesa_origin | mcesa_bits; lc->cpu_nr = cpu; lc->spinlock_lockval = arch_spin_lockval(cpu); + lc->br_r1_trampoline = 0x07f1; /* br %r1 */ if (vdso_alloc_per_cpu(lc)) goto out; lowcore_ptr[cpu] = lc; diff --git a/arch/s390/kernel/vmlinux.lds.S b/arch/s390/kernel/vmlinux.lds.S index 3f6c93a82297..85dd3c7bdd86 100644 --- a/arch/s390/kernel/vmlinux.lds.S +++ b/arch/s390/kernel/vmlinux.lds.S @@ -128,6 +128,20 @@ SECTIONS *(.altinstr_replacement) } + /* + * Table with the patch locations to undo expolines + */ + .nospec_call_table : { + __nospec_call_start = . ; + *(.s390_indirect*) + __nospec_call_end = . ; + } + .nospec_return_table : { + __nospec_return_start = . ; + *(.s390_return*) + __nospec_return_end = . ; + } + /* early.c uses stsi, which requires page aligned data. */ . = ALIGN(PAGE_SIZE); INIT_DATA_SECTION(0x100) diff --git a/drivers/s390/char/Makefile b/drivers/s390/char/Makefile index 05ac6ba15a53..ecc24a46e71a 100644 --- a/drivers/s390/char/Makefile +++ b/drivers/s390/char/Makefile @@ -17,6 +17,8 @@ CFLAGS_REMOVE_sclp_early_core.o += $(CC_FLAGS_MARCH) CFLAGS_sclp_early_core.o += -march=z900 endif +CFLAGS_REMOVE_sclp_early_core.o += $(CC_FLAGS_EXPOLINE) + obj-y += ctrlchar.o keyboard.o defkeymap.o sclp.o sclp_rw.o sclp_quiesce.o \ sclp_cmd.o sclp_config.o sclp_cpi_sys.o sclp_ocf.o sclp_ctl.o \ sclp_early.o sclp_early_core.o -- GitLab From 1d966a6aded36b2f0d2f4d7a1c88a94f96ea59ac Mon Sep 17 00:00:00 2001 From: Christian Borntraeger Date: Fri, 27 Apr 2018 07:36:34 +0200 Subject: [PATCH 1166/1635] KVM: s390: force bp isolation for VSIE [ Upstream commit f315104ad8b0c32be13eac628569ae707c332cb5 ] If the guest runs with bp isolation when doing a SIE instruction, we must also run the nested guest with bp isolation when emulating that SIE instruction. This is done by activating BPBC in the lpar, which acts as an override for lower level guests. Signed-off-by: Christian Borntraeger Reviewed-by: Janosch Frank Reviewed-by: David Hildenbrand Signed-off-by: Christian Borntraeger Signed-off-by: Martin Schwidefsky Signed-off-by: Greg Kroah-Hartman --- arch/s390/kvm/vsie.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/arch/s390/kvm/vsie.c b/arch/s390/kvm/vsie.c index 80c4fde9bdcc..eb7b530d1783 100644 --- a/arch/s390/kvm/vsie.c +++ b/arch/s390/kvm/vsie.c @@ -831,6 +831,7 @@ static int do_vsie_run(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page) { struct kvm_s390_sie_block *scb_s = &vsie_page->scb_s; struct kvm_s390_sie_block *scb_o = vsie_page->scb_o; + int guest_bp_isolation; int rc; handle_last_fault(vcpu, vsie_page); @@ -841,6 +842,20 @@ static int do_vsie_run(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page) s390_handle_mcck(); srcu_read_unlock(&vcpu->kvm->srcu, vcpu->srcu_idx); + + /* save current guest state of bp isolation override */ + guest_bp_isolation = test_thread_flag(TIF_ISOLATE_BP_GUEST); + + /* + * The guest is running with BPBC, so we have to force it on for our + * nested guest. This is done by enabling BPBC globally, so the BPBC + * control in the SCB (which the nested guest can modify) is simply + * ignored. + */ + if (test_kvm_facility(vcpu->kvm, 82) && + vcpu->arch.sie_block->fpf & FPF_BPBC) + set_thread_flag(TIF_ISOLATE_BP_GUEST); + local_irq_disable(); guest_enter_irqoff(); local_irq_enable(); @@ -850,6 +865,11 @@ static int do_vsie_run(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page) local_irq_disable(); guest_exit_irqoff(); local_irq_enable(); + + /* restore guest state for bp isolation override */ + if (!guest_bp_isolation) + clear_thread_flag(TIF_ISOLATE_BP_GUEST); + vcpu->srcu_idx = srcu_read_lock(&vcpu->kvm->srcu); if (rc == -EINTR) { -- GitLab From 6288e169a25e416c656604be74f436002fa567a0 Mon Sep 17 00:00:00 2001 From: Eugeniu Rosca Date: Fri, 27 Apr 2018 07:36:35 +0200 Subject: [PATCH 1167/1635] s390: Replace IS_ENABLED(EXPOLINE_*) with IS_ENABLED(CONFIG_EXPOLINE_*) [ Upstream commit 2cb370d615e9fbed9e95ed222c2c8f337181aa90 ] I've accidentally stumbled upon the IS_ENABLED(EXPOLINE_*) lines, which obviously always evaluate to false. Fix this. Fixes: f19fbd5ed642 ("s390: introduce execute-trampolines for branches") Signed-off-by: Eugeniu Rosca Signed-off-by: Martin Schwidefsky Signed-off-by: Greg Kroah-Hartman --- arch/s390/kernel/nospec-branch.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/s390/kernel/nospec-branch.c b/arch/s390/kernel/nospec-branch.c index 86ee26a612cf..57f55c24c21c 100644 --- a/arch/s390/kernel/nospec-branch.c +++ b/arch/s390/kernel/nospec-branch.c @@ -3,8 +3,8 @@ #include #include -int nospec_call_disable = IS_ENABLED(EXPOLINE_OFF); -int nospec_return_disable = !IS_ENABLED(EXPOLINE_FULL); +int nospec_call_disable = IS_ENABLED(CONFIG_EXPOLINE_OFF); +int nospec_return_disable = !IS_ENABLED(CONFIG_EXPOLINE_FULL); static int __init nospectre_v2_setup_early(char *str) { -- GitLab From 74a93ae5c328da09951990e1fece3382b544616c Mon Sep 17 00:00:00 2001 From: Martin Schwidefsky Date: Fri, 27 Apr 2018 07:36:36 +0200 Subject: [PATCH 1168/1635] s390: do not bypass BPENTER for interrupt system calls [ Upstream commit d5feec04fe578c8dbd9e2e1439afc2f0af761ed4 ] The system call path can be interrupted before the switch back to the standard branch prediction with BPENTER has been done. The critical section cleanup code skips forward to .Lsysc_do_svc and bypasses the BPENTER. In this case the kernel and all subsequent code will run with the limited branch prediction. Fixes: eacf67eb9b32 ("s390: run user space and KVM guests with modified branch prediction") Signed-off-by: Martin Schwidefsky Signed-off-by: Greg Kroah-Hartman --- arch/s390/kernel/entry.S | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/s390/kernel/entry.S b/arch/s390/kernel/entry.S index 1888b1010e20..6473cd81c8f6 100644 --- a/arch/s390/kernel/entry.S +++ b/arch/s390/kernel/entry.S @@ -1375,6 +1375,7 @@ cleanup_critical: stg %r15,__LC_SYSTEM_TIMER 0: # update accounting time stamp mvc __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER + BPENTER __TI_flags(%r12),_TIF_ISOLATE_BP # set up saved register r11 lg %r15,__LC_KERNEL_STACK la %r9,STACK_FRAME_OVERHEAD(%r15) -- GitLab From 6cdc4b21d219d47a96317942667339460281959d Mon Sep 17 00:00:00 2001 From: Christian Borntraeger Date: Fri, 27 Apr 2018 07:36:37 +0200 Subject: [PATCH 1169/1635] s390/entry.S: fix spurious zeroing of r0 [ Upstream commit d3f468963cd6fd6d2aa5e26aed8b24232096d0e1 ] when a system call is interrupted we might call the critical section cleanup handler that re-does some of the operations. When we are between .Lsysc_vtime and .Lsysc_do_svc we might also redo the saving of the problem state registers r0-r7: .Lcleanup_system_call: [...] 0: # update accounting time stamp mvc __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER # set up saved register r11 lg %r15,__LC_KERNEL_STACK la %r9,STACK_FRAME_OVERHEAD(%r15) stg %r9,24(%r11) # r11 pt_regs pointer # fill pt_regs mvc __PT_R8(64,%r9),__LC_SAVE_AREA_SYNC ---> stmg %r0,%r7,__PT_R0(%r9) The problem is now, that we might have already zeroed out r0. The fix is to move the zeroing of r0 after sysc_do_svc. Reported-by: Farhan Ali Fixes: 7041d28115e91 ("s390: scrub registers on kernel entry and KVM exit") Signed-off-by: Christian Borntraeger Signed-off-by: Martin Schwidefsky Signed-off-by: Martin Schwidefsky Signed-off-by: Martin Schwidefsky Signed-off-by: Greg Kroah-Hartman --- arch/s390/kernel/entry.S | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/s390/kernel/entry.S b/arch/s390/kernel/entry.S index 6473cd81c8f6..ed9aaa212d4a 100644 --- a/arch/s390/kernel/entry.S +++ b/arch/s390/kernel/entry.S @@ -426,13 +426,13 @@ ENTRY(system_call) UPDATE_VTIME %r8,%r9,__LC_SYNC_ENTER_TIMER BPENTER __TI_flags(%r12),_TIF_ISOLATE_BP stmg %r0,%r7,__PT_R0(%r11) - # clear user controlled register to prevent speculative use - xgr %r0,%r0 mvc __PT_R8(64,%r11),__LC_SAVE_AREA_SYNC mvc __PT_PSW(16,%r11),__LC_SVC_OLD_PSW mvc __PT_INT_CODE(4,%r11),__LC_SVC_ILC stg %r14,__PT_FLAGS(%r11) .Lsysc_do_svc: + # clear user controlled register to prevent speculative use + xgr %r0,%r0 # load address of system call table lg %r10,__THREAD_sysc_table(%r13,%r12) llgh %r8,__PT_INT_CODE+2(%r11) -- GitLab From ea1bbd53f0558fa625f07fd69f5dbb58cbb8a95c Mon Sep 17 00:00:00 2001 From: Martin Schwidefsky Date: Fri, 27 Apr 2018 07:36:38 +0200 Subject: [PATCH 1170/1635] s390: move nobp parameter functions to nospec-branch.c [ Upstream commit b2e2f43a01bace1a25bdbae04c9f9846882b727a ] Keep the code for the nobp parameter handling with the code for expolines. Both are related to the spectre v2 mitigation. Signed-off-by: Martin Schwidefsky Signed-off-by: Greg Kroah-Hartman --- arch/s390/kernel/Makefile | 4 ++-- arch/s390/kernel/alternative.c | 23 ----------------------- arch/s390/kernel/nospec-branch.c | 27 +++++++++++++++++++++++++++ 3 files changed, 29 insertions(+), 25 deletions(-) diff --git a/arch/s390/kernel/Makefile b/arch/s390/kernel/Makefile index 3882b29f8d02..a3a4cafb6080 100644 --- a/arch/s390/kernel/Makefile +++ b/arch/s390/kernel/Makefile @@ -59,11 +59,11 @@ obj-y += debug.o irq.o ipl.o dis.o diag.o vdso.o als.o obj-y += sysinfo.o jump_label.o lgr.o os_info.o machine_kexec.o pgm_check.o obj-y += runtime_instr.o cache.o fpu.o dumpstack.o guarded_storage.o obj-y += entry.o reipl.o relocate_kernel.o kdebugfs.o alternative.o +obj-y += nospec-branch.o extra-y += head.o head64.o vmlinux.lds -obj-$(CONFIG_EXPOLINE) += nospec-branch.o -CFLAGS_REMOVE_expoline.o += $(CC_FLAGS_EXPOLINE) +CFLAGS_REMOVE_nospec-branch.o += $(CC_FLAGS_EXPOLINE) obj-$(CONFIG_MODULES) += module.o obj-$(CONFIG_SMP) += smp.o diff --git a/arch/s390/kernel/alternative.c b/arch/s390/kernel/alternative.c index ed21de98b79e..f5060af61176 100644 --- a/arch/s390/kernel/alternative.c +++ b/arch/s390/kernel/alternative.c @@ -14,29 +14,6 @@ static int __init disable_alternative_instructions(char *str) early_param("noaltinstr", disable_alternative_instructions); -static int __init nobp_setup_early(char *str) -{ - bool enabled; - int rc; - - rc = kstrtobool(str, &enabled); - if (rc) - return rc; - if (enabled && test_facility(82)) - __set_facility(82, S390_lowcore.alt_stfle_fac_list); - else - __clear_facility(82, S390_lowcore.alt_stfle_fac_list); - return 0; -} -early_param("nobp", nobp_setup_early); - -static int __init nospec_setup_early(char *str) -{ - __clear_facility(82, S390_lowcore.alt_stfle_fac_list); - return 0; -} -early_param("nospec", nospec_setup_early); - struct brcl_insn { u16 opc; s32 disp; diff --git a/arch/s390/kernel/nospec-branch.c b/arch/s390/kernel/nospec-branch.c index 57f55c24c21c..3ce59d044a4d 100644 --- a/arch/s390/kernel/nospec-branch.c +++ b/arch/s390/kernel/nospec-branch.c @@ -3,6 +3,31 @@ #include #include +static int __init nobp_setup_early(char *str) +{ + bool enabled; + int rc; + + rc = kstrtobool(str, &enabled); + if (rc) + return rc; + if (enabled && test_facility(82)) + __set_facility(82, S390_lowcore.alt_stfle_fac_list); + else + __clear_facility(82, S390_lowcore.alt_stfle_fac_list); + return 0; +} +early_param("nobp", nobp_setup_early); + +static int __init nospec_setup_early(char *str) +{ + __clear_facility(82, S390_lowcore.alt_stfle_fac_list); + return 0; +} +early_param("nospec", nospec_setup_early); + +#ifdef CONFIG_EXPOLINE + int nospec_call_disable = IS_ENABLED(CONFIG_EXPOLINE_OFF); int nospec_return_disable = !IS_ENABLED(CONFIG_EXPOLINE_FULL); @@ -99,3 +124,5 @@ void __init nospec_init_branches(void) nospec_call_revert(__nospec_call_start, __nospec_call_end); nospec_return_revert(__nospec_return_start, __nospec_return_end); } + +#endif /* CONFIG_EXPOLINE */ -- GitLab From 719b84c9aec27953da3da75838f50fd89ea950a2 Mon Sep 17 00:00:00 2001 From: Martin Schwidefsky Date: Fri, 27 Apr 2018 07:36:39 +0200 Subject: [PATCH 1171/1635] s390: add automatic detection of the spectre defense [ Upstream commit 6e179d64126b909f0b288fa63cdbf07c531e9b1d ] Automatically decide between nobp vs. expolines if the spectre_v2=auto kernel parameter is specified or CONFIG_EXPOLINE_AUTO=y is set. The decision made at boot time due to CONFIG_EXPOLINE_AUTO=y being set can be overruled with the nobp, nospec and spectre_v2 kernel parameters. Signed-off-by: Martin Schwidefsky Signed-off-by: Greg Kroah-Hartman --- arch/s390/Kconfig | 2 +- arch/s390/Makefile | 2 +- arch/s390/include/asm/nospec-branch.h | 6 +-- arch/s390/kernel/alternative.c | 1 + arch/s390/kernel/module.c | 11 ++--- arch/s390/kernel/nospec-branch.c | 68 +++++++++++++++++---------- 6 files changed, 52 insertions(+), 38 deletions(-) diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig index 39cd1ed804a8..7a238d47c5c6 100644 --- a/arch/s390/Kconfig +++ b/arch/s390/Kconfig @@ -575,7 +575,7 @@ choice config EXPOLINE_OFF bool "spectre_v2=off" -config EXPOLINE_MEDIUM +config EXPOLINE_AUTO bool "spectre_v2=auto" config EXPOLINE_FULL diff --git a/arch/s390/Makefile b/arch/s390/Makefile index 98f50b2fc0ec..ec3fa105f448 100644 --- a/arch/s390/Makefile +++ b/arch/s390/Makefile @@ -87,7 +87,7 @@ ifdef CONFIG_EXPOLINE CC_FLAGS_EXPOLINE += -mfunction-return=thunk CC_FLAGS_EXPOLINE += -mindirect-branch-table export CC_FLAGS_EXPOLINE - cflags-y += $(CC_FLAGS_EXPOLINE) + cflags-y += $(CC_FLAGS_EXPOLINE) -DCC_USING_EXPOLINE endif endif diff --git a/arch/s390/include/asm/nospec-branch.h b/arch/s390/include/asm/nospec-branch.h index 7df48e5cf36f..35bf28fe4c64 100644 --- a/arch/s390/include/asm/nospec-branch.h +++ b/arch/s390/include/asm/nospec-branch.h @@ -6,12 +6,10 @@ #include -extern int nospec_call_disable; -extern int nospec_return_disable; +extern int nospec_disable; void nospec_init_branches(void); -void nospec_call_revert(s32 *start, s32 *end); -void nospec_return_revert(s32 *start, s32 *end); +void nospec_revert(s32 *start, s32 *end); #endif /* __ASSEMBLY__ */ diff --git a/arch/s390/kernel/alternative.c b/arch/s390/kernel/alternative.c index f5060af61176..b57b293998dc 100644 --- a/arch/s390/kernel/alternative.c +++ b/arch/s390/kernel/alternative.c @@ -1,6 +1,7 @@ #include #include #include +#include #define MAX_PATCH_LEN (255 - 1) diff --git a/arch/s390/kernel/module.c b/arch/s390/kernel/module.c index 89d7ab711255..7b337f85ca2f 100644 --- a/arch/s390/kernel/module.c +++ b/arch/s390/kernel/module.c @@ -172,7 +172,7 @@ int module_frob_arch_sections(Elf_Ehdr *hdr, Elf_Shdr *sechdrs, me->core_layout.size += me->arch.got_size; me->arch.plt_offset = me->core_layout.size; if (me->arch.plt_size) { - if (IS_ENABLED(CONFIG_EXPOLINE) && !nospec_call_disable) + if (IS_ENABLED(CONFIG_EXPOLINE) && !nospec_disable) me->arch.plt_size += PLT_ENTRY_SIZE; me->core_layout.size += me->arch.plt_size; } @@ -331,8 +331,7 @@ static int apply_rela(Elf_Rela *rela, Elf_Addr base, Elf_Sym *symtab, info->plt_offset; ip[0] = 0x0d10e310; /* basr 1,0 */ ip[1] = 0x100a0004; /* lg 1,10(1) */ - if (IS_ENABLED(CONFIG_EXPOLINE) && - !nospec_call_disable) { + if (IS_ENABLED(CONFIG_EXPOLINE) && !nospec_disable) { unsigned int *ij; ij = me->core_layout.base + me->arch.plt_offset + @@ -453,7 +452,7 @@ int module_finalize(const Elf_Ehdr *hdr, void *aseg; if (IS_ENABLED(CONFIG_EXPOLINE) && - !nospec_call_disable && me->arch.plt_size) { + !nospec_disable && me->arch.plt_size) { unsigned int *ij; ij = me->core_layout.base + me->arch.plt_offset + @@ -480,11 +479,11 @@ int module_finalize(const Elf_Ehdr *hdr, if (IS_ENABLED(CONFIG_EXPOLINE) && (!strcmp(".nospec_call_table", secname))) - nospec_call_revert(aseg, aseg + s->sh_size); + nospec_revert(aseg, aseg + s->sh_size); if (IS_ENABLED(CONFIG_EXPOLINE) && (!strcmp(".nospec_return_table", secname))) - nospec_return_revert(aseg, aseg + s->sh_size); + nospec_revert(aseg, aseg + s->sh_size); } jump_label_apply_nops(me); diff --git a/arch/s390/kernel/nospec-branch.c b/arch/s390/kernel/nospec-branch.c index 3ce59d044a4d..daa36a38a8b7 100644 --- a/arch/s390/kernel/nospec-branch.c +++ b/arch/s390/kernel/nospec-branch.c @@ -11,10 +11,17 @@ static int __init nobp_setup_early(char *str) rc = kstrtobool(str, &enabled); if (rc) return rc; - if (enabled && test_facility(82)) + if (enabled && test_facility(82)) { + /* + * The user explicitely requested nobp=1, enable it and + * disable the expoline support. + */ __set_facility(82, S390_lowcore.alt_stfle_fac_list); - else + if (IS_ENABLED(CONFIG_EXPOLINE)) + nospec_disable = 1; + } else { __clear_facility(82, S390_lowcore.alt_stfle_fac_list); + } return 0; } early_param("nobp", nobp_setup_early); @@ -28,31 +35,46 @@ early_param("nospec", nospec_setup_early); #ifdef CONFIG_EXPOLINE -int nospec_call_disable = IS_ENABLED(CONFIG_EXPOLINE_OFF); -int nospec_return_disable = !IS_ENABLED(CONFIG_EXPOLINE_FULL); +int nospec_disable = IS_ENABLED(CONFIG_EXPOLINE_OFF); static int __init nospectre_v2_setup_early(char *str) { - nospec_call_disable = 1; - nospec_return_disable = 1; + nospec_disable = 1; return 0; } early_param("nospectre_v2", nospectre_v2_setup_early); +static int __init spectre_v2_auto_early(void) +{ + if (IS_ENABLED(CC_USING_EXPOLINE)) { + /* + * The kernel has been compiled with expolines. + * Keep expolines enabled and disable nobp. + */ + nospec_disable = 0; + __clear_facility(82, S390_lowcore.alt_stfle_fac_list); + } + /* + * If the kernel has not been compiled with expolines the + * nobp setting decides what is done, this depends on the + * CONFIG_KERNEL_NP option and the nobp/nospec parameters. + */ + return 0; +} +#ifdef CONFIG_EXPOLINE_AUTO +early_initcall(spectre_v2_auto_early); +#endif + static int __init spectre_v2_setup_early(char *str) { if (str && !strncmp(str, "on", 2)) { - nospec_call_disable = 0; - nospec_return_disable = 0; - } - if (str && !strncmp(str, "off", 3)) { - nospec_call_disable = 1; - nospec_return_disable = 1; - } - if (str && !strncmp(str, "auto", 4)) { - nospec_call_disable = 0; - nospec_return_disable = 1; + nospec_disable = 0; + __clear_facility(82, S390_lowcore.alt_stfle_fac_list); } + if (str && !strncmp(str, "off", 3)) + nospec_disable = 1; + if (str && !strncmp(str, "auto", 4)) + spectre_v2_auto_early(); return 0; } early_param("spectre_v2", spectre_v2_setup_early); @@ -105,15 +127,9 @@ static void __init_or_module __nospec_revert(s32 *start, s32 *end) } } -void __init_or_module nospec_call_revert(s32 *start, s32 *end) -{ - if (nospec_call_disable) - __nospec_revert(start, end); -} - -void __init_or_module nospec_return_revert(s32 *start, s32 *end) +void __init_or_module nospec_revert(s32 *start, s32 *end) { - if (nospec_return_disable) + if (nospec_disable) __nospec_revert(start, end); } @@ -121,8 +137,8 @@ extern s32 __nospec_call_start[], __nospec_call_end[]; extern s32 __nospec_return_start[], __nospec_return_end[]; void __init nospec_init_branches(void) { - nospec_call_revert(__nospec_call_start, __nospec_call_end); - nospec_return_revert(__nospec_return_start, __nospec_return_end); + nospec_revert(__nospec_call_start, __nospec_call_end); + nospec_revert(__nospec_return_start, __nospec_return_end); } #endif /* CONFIG_EXPOLINE */ -- GitLab From 68cb884e12288cdbc044895affd528ceb98a815b Mon Sep 17 00:00:00 2001 From: Martin Schwidefsky Date: Fri, 27 Apr 2018 07:36:40 +0200 Subject: [PATCH 1172/1635] s390: report spectre mitigation via syslog [ Upstream commit bc035599718412cfba9249aa713f90ef13f13ee9 ] Add a boot message if either of the spectre defenses is active. The message is "Spectre V2 mitigation: execute trampolines." or "Spectre V2 mitigation: limited branch prediction." Signed-off-by: Martin Schwidefsky Signed-off-by: Greg Kroah-Hartman --- arch/s390/kernel/nospec-branch.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/arch/s390/kernel/nospec-branch.c b/arch/s390/kernel/nospec-branch.c index daa36a38a8b7..7387ebace891 100644 --- a/arch/s390/kernel/nospec-branch.c +++ b/arch/s390/kernel/nospec-branch.c @@ -33,6 +33,16 @@ static int __init nospec_setup_early(char *str) } early_param("nospec", nospec_setup_early); +static int __init nospec_report(void) +{ + if (IS_ENABLED(CC_USING_EXPOLINE) && !nospec_disable) + pr_info("Spectre V2 mitigation: execute trampolines.\n"); + if (__test_facility(82, S390_lowcore.alt_stfle_fac_list)) + pr_info("Spectre V2 mitigation: limited branch prediction.\n"); + return 0; +} +arch_initcall(nospec_report); + #ifdef CONFIG_EXPOLINE int nospec_disable = IS_ENABLED(CONFIG_EXPOLINE_OFF); -- GitLab From fce1bf054f0bc1dec6fef6cf5840c6ad7c662e17 Mon Sep 17 00:00:00 2001 From: Martin Schwidefsky Date: Fri, 27 Apr 2018 07:36:41 +0200 Subject: [PATCH 1173/1635] s390: add sysfs attributes for spectre [ Upstream commit d424986f1d6b16079b3231db0314923f4f8deed1 ] Set CONFIG_GENERIC_CPU_VULNERABILITIES and provide the two functions cpu_show_spectre_v1 and cpu_show_spectre_v2 to report the spectre mitigations. Signed-off-by: Martin Schwidefsky Signed-off-by: Greg Kroah-Hartman --- arch/s390/Kconfig | 1 + arch/s390/kernel/nospec-branch.c | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig index 7a238d47c5c6..49fb6614ea8c 100644 --- a/arch/s390/Kconfig +++ b/arch/s390/Kconfig @@ -121,6 +121,7 @@ config S390 select GENERIC_CLOCKEVENTS select GENERIC_CPU_AUTOPROBE select GENERIC_CPU_DEVICES if !SMP + select GENERIC_CPU_VULNERABILITIES select GENERIC_FIND_FIRST_BIT select GENERIC_SMP_IDLE_THREAD select GENERIC_TIME_VSYSCALL diff --git a/arch/s390/kernel/nospec-branch.c b/arch/s390/kernel/nospec-branch.c index 7387ebace891..73c06d42792d 100644 --- a/arch/s390/kernel/nospec-branch.c +++ b/arch/s390/kernel/nospec-branch.c @@ -1,5 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 #include +#include #include #include @@ -43,6 +44,24 @@ static int __init nospec_report(void) } arch_initcall(nospec_report); +#ifdef CONFIG_SYSFS +ssize_t cpu_show_spectre_v1(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "Mitigation: __user pointer sanitization\n"); +} + +ssize_t cpu_show_spectre_v2(struct device *dev, + struct device_attribute *attr, char *buf) +{ + if (IS_ENABLED(CC_USING_EXPOLINE) && !nospec_disable) + return sprintf(buf, "Mitigation: execute trampolines\n"); + if (__test_facility(82, S390_lowcore.alt_stfle_fac_list)) + return sprintf(buf, "Mitigation: limited branch prediction.\n"); + return sprintf(buf, "Vulnerable\n"); +} +#endif + #ifdef CONFIG_EXPOLINE int nospec_disable = IS_ENABLED(CONFIG_EXPOLINE_OFF); -- GitLab From f836b34fb0562cf193a076769a5adf71b030f59f Mon Sep 17 00:00:00 2001 From: Martin Schwidefsky Date: Fri, 27 Apr 2018 07:36:42 +0200 Subject: [PATCH 1174/1635] s390: correct nospec auto detection init order [ Upstream commit 6a3d1e81a434fc311f224b8be77258bafc18ccc6 ] With CONFIG_EXPOLINE_AUTO=y the call of spectre_v2_auto_early() via early_initcall is done *after* the early_param functions. This overwrites any settings done with the nobp/no_spectre_v2/spectre_v2 parameters. The code patching for the kernel is done after the evaluation of the early parameters but before the early_initcall is done. The end result is a kernel image that is patched correctly but the kernel modules are not. Make sure that the nospec auto detection function is called before the early parameters are evaluated and before the code patching is done. Fixes: 6e179d64126b ("s390: add automatic detection of the spectre defense") Signed-off-by: Martin Schwidefsky Signed-off-by: Greg Kroah-Hartman --- arch/s390/include/asm/nospec-branch.h | 1 + arch/s390/kernel/nospec-branch.c | 8 ++------ arch/s390/kernel/setup.c | 3 +++ 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/arch/s390/include/asm/nospec-branch.h b/arch/s390/include/asm/nospec-branch.h index 35bf28fe4c64..b4bd8c41e9d3 100644 --- a/arch/s390/include/asm/nospec-branch.h +++ b/arch/s390/include/asm/nospec-branch.h @@ -9,6 +9,7 @@ extern int nospec_disable; void nospec_init_branches(void); +void nospec_auto_detect(void); void nospec_revert(s32 *start, s32 *end); #endif /* __ASSEMBLY__ */ diff --git a/arch/s390/kernel/nospec-branch.c b/arch/s390/kernel/nospec-branch.c index 73c06d42792d..9f3b5b382743 100644 --- a/arch/s390/kernel/nospec-branch.c +++ b/arch/s390/kernel/nospec-branch.c @@ -73,7 +73,7 @@ static int __init nospectre_v2_setup_early(char *str) } early_param("nospectre_v2", nospectre_v2_setup_early); -static int __init spectre_v2_auto_early(void) +void __init nospec_auto_detect(void) { if (IS_ENABLED(CC_USING_EXPOLINE)) { /* @@ -88,11 +88,7 @@ static int __init spectre_v2_auto_early(void) * nobp setting decides what is done, this depends on the * CONFIG_KERNEL_NP option and the nobp/nospec parameters. */ - return 0; } -#ifdef CONFIG_EXPOLINE_AUTO -early_initcall(spectre_v2_auto_early); -#endif static int __init spectre_v2_setup_early(char *str) { @@ -103,7 +99,7 @@ static int __init spectre_v2_setup_early(char *str) if (str && !strncmp(str, "off", 3)) nospec_disable = 1; if (str && !strncmp(str, "auto", 4)) - spectre_v2_auto_early(); + nospec_auto_detect(); return 0; } early_param("spectre_v2", spectre_v2_setup_early); diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c index 63d5cbb9a8b4..98c1f7941142 100644 --- a/arch/s390/kernel/setup.c +++ b/arch/s390/kernel/setup.c @@ -897,6 +897,9 @@ void __init setup_arch(char **cmdline_p) init_mm.end_data = (unsigned long) &_edata; init_mm.brk = (unsigned long) &_end; + if (IS_ENABLED(CONFIG_EXPOLINE_AUTO)) + nospec_auto_detect(); + parse_early_param(); #ifdef CONFIG_CRASH_DUMP /* Deactivate elfcorehdr= kernel parameter */ -- GitLab From 5787b55b50196ad1e462789acc49d5bcefff57fb Mon Sep 17 00:00:00 2001 From: Martin Schwidefsky Date: Fri, 27 Apr 2018 07:36:43 +0200 Subject: [PATCH 1175/1635] s390: correct module section names for expoline code revert [ Upstream commit 6cf09958f32b9667bb3ebadf74367c791112771b ] The main linker script vmlinux.lds.S for the kernel image merges the expoline code patch tables into two section ".nospec_call_table" and ".nospec_return_table". This is *not* done for the modules, there the sections retain their original names as generated by gcc: ".s390_indirect_call", ".s390_return_mem" and ".s390_return_reg". The module_finalize code has to check for the compiler generated section names, otherwise no code patching is done. This slows down the module code in case of "spectre_v2=off". Cc: stable@vger.kernel.org # 4.16 Fixes: f19fbd5ed6 ("s390: introduce execute-trampolines for branches") Signed-off-by: Martin Schwidefsky Signed-off-by: Greg Kroah-Hartman --- arch/s390/kernel/module.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/s390/kernel/module.c b/arch/s390/kernel/module.c index 7b337f85ca2f..b441e069e674 100644 --- a/arch/s390/kernel/module.c +++ b/arch/s390/kernel/module.c @@ -478,11 +478,11 @@ int module_finalize(const Elf_Ehdr *hdr, apply_alternatives(aseg, aseg + s->sh_size); if (IS_ENABLED(CONFIG_EXPOLINE) && - (!strcmp(".nospec_call_table", secname))) + (!strncmp(".s390_indirect", secname, 14))) nospec_revert(aseg, aseg + s->sh_size); if (IS_ENABLED(CONFIG_EXPOLINE) && - (!strcmp(".nospec_return_table", secname))) + (!strncmp(".s390_return", secname, 12))) nospec_revert(aseg, aseg + s->sh_size); } -- GitLab From fcc347bc1e34ef384335438680871e16edc5710d Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Thu, 22 Feb 2018 15:19:37 +0100 Subject: [PATCH 1176/1635] microblaze: Setup dependencies for ASM optimized lib functions commit 18ffc0cce4ff947a2acc9b2e06ae5309a6e6fb43 upstream. The patch: "microblaze: Setup proper dependency for optimized lib functions" (sha1: 7b6ce52be3f86520524711a6f33f3866f9339694) didn't setup all dependencies properly. Optimized lib functions in C are also present for little endian and optimized library functions in assembler are implemented only for big endian version. Reported-by: kbuild test robot Signed-off-by: Michal Simek Cc: Arnd Bergmann Signed-off-by: Greg Kroah-Hartman --- arch/microblaze/Kconfig.platform | 1 + arch/microblaze/lib/fastcopy.S | 4 ---- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/arch/microblaze/Kconfig.platform b/arch/microblaze/Kconfig.platform index 1b3d8c849101..f7f1739c11b9 100644 --- a/arch/microblaze/Kconfig.platform +++ b/arch/microblaze/Kconfig.platform @@ -20,6 +20,7 @@ config OPT_LIB_FUNCTION config OPT_LIB_ASM bool "Optimalized lib function ASM" depends on OPT_LIB_FUNCTION && (XILINX_MICROBLAZE0_USE_BARREL = 1) + depends on CPU_BIG_ENDIAN default n help Allows turn on optimalized library function (memcpy and memmove). diff --git a/arch/microblaze/lib/fastcopy.S b/arch/microblaze/lib/fastcopy.S index 62021d7e249e..fdc48bb065d8 100644 --- a/arch/microblaze/lib/fastcopy.S +++ b/arch/microblaze/lib/fastcopy.S @@ -29,10 +29,6 @@ * between mem locations with size of xfer spec'd in bytes */ -#ifdef __MICROBLAZEEL__ -#error Microblaze LE not support ASM optimized lib func. Disable OPT_LIB_ASM. -#endif - #include .text .globl memcpy -- GitLab From a252b9732243da8f9ff2b761cd020b386e944972 Mon Sep 17 00:00:00 2001 From: Klaus Goger Date: Tue, 5 Dec 2017 08:11:58 +0100 Subject: [PATCH 1177/1635] arm64: dts: rockchip: remove vdd_log from rk3399-puma commit 87eba0716011e528f7841026f2cc65683219d0ad upstream. vdd_log has no consumer and therefore will not be set to a specific voltage. Still the PWM output pin gets configured and thence the vdd_log output voltage will changed from it's default. Depending on the idle state of the PWM this will slightly over or undervoltage the logic supply of the RK3399 and cause instability with GbE (undervoltage) and PCIe (overvoltage). Since the default value set by a voltage divider is the correct supply voltage and we don't need to change it during runtime we remove the rail from the devicetree completely so the PWM pin will not be configured. Signed-off-by: Klaus Goger Signed-off-by: Heiko Stuebner Cc: Jakob Unterwurzacher Signed-off-by: Greg Kroah-Hartman --- arch/arm64/boot/dts/rockchip/rk3399-puma.dtsi | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/arch/arm64/boot/dts/rockchip/rk3399-puma.dtsi b/arch/arm64/boot/dts/rockchip/rk3399-puma.dtsi index 910628d18add..1fc5060d7027 100644 --- a/arch/arm64/boot/dts/rockchip/rk3399-puma.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3399-puma.dtsi @@ -155,17 +155,6 @@ regulator-min-microvolt = <5000000>; regulator-max-microvolt = <5000000>; }; - - vdd_log: vdd-log { - compatible = "pwm-regulator"; - pwms = <&pwm2 0 25000 0>; - regulator-name = "vdd_log"; - regulator-min-microvolt = <800000>; - regulator-max-microvolt = <1400000>; - regulator-always-on; - regulator-boot-on; - status = "okay"; - }; }; &cpu_b0 { -- GitLab From 540e7b5be492df4aab0ebbd13f658cc096149575 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Fri, 27 Apr 2018 13:49:00 +0200 Subject: [PATCH 1178/1635] Revert "mm/hmm: fix header file if/else/endif maze" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit 25df8b83e867dcfb660123e9589ebf6f094fcdd3 which is commit b28b08de436a638c82d0cf3dcdbdbad055baf1fc upstream. There are still build errors with this patch applied, and the upstream patches do not seem to apply anymore, so reverting this patch seems like the best thing to do at this point in time. Reported-by: Randy Dunlap Cc: Arnd Bergmann Cc: Михаил Носов Cc: Jérôme Glisse Cc: Balbir Singh Cc: Andrew Morton Cc: Ralph Campbell Cc: John Hubbard Cc: Evgeny Baskakov Cc: Andrew Morton Cc: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- include/linux/hmm.h | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/include/linux/hmm.h b/include/linux/hmm.h index 8198faf16ed6..96e69979f84d 100644 --- a/include/linux/hmm.h +++ b/include/linux/hmm.h @@ -498,16 +498,23 @@ struct hmm_device { struct hmm_device *hmm_device_new(void *drvdata); void hmm_device_put(struct hmm_device *hmm_device); #endif /* CONFIG_DEVICE_PRIVATE || CONFIG_DEVICE_PUBLIC */ +#endif /* IS_ENABLED(CONFIG_HMM) */ /* Below are for HMM internal use only! Not to be used by device driver! */ +#if IS_ENABLED(CONFIG_HMM_MIRROR) void hmm_mm_destroy(struct mm_struct *mm); static inline void hmm_mm_init(struct mm_struct *mm) { mm->hmm = NULL; } +#else /* IS_ENABLED(CONFIG_HMM_MIRROR) */ +static inline void hmm_mm_destroy(struct mm_struct *mm) {} +static inline void hmm_mm_init(struct mm_struct *mm) {} +#endif /* IS_ENABLED(CONFIG_HMM_MIRROR) */ + + #else /* IS_ENABLED(CONFIG_HMM) */ static inline void hmm_mm_destroy(struct mm_struct *mm) {} static inline void hmm_mm_init(struct mm_struct *mm) {} -#endif /* IS_ENABLED(CONFIG_HMM) */ #endif /* LINUX_HMM_H */ -- GitLab From 77df079be9b480fbac36d407e76df4c29d719407 Mon Sep 17 00:00:00 2001 From: Tetsuo Handa Date: Tue, 10 Apr 2018 15:15:16 +0900 Subject: [PATCH 1179/1635] commoncap: Handle memory allocation failure. commit 1f5781725dcbb026438e77091c91a94f678c3522 upstream. syzbot is reporting NULL pointer dereference at xattr_getsecurity() [1], for cap_inode_getsecurity() is returning sizeof(struct vfs_cap_data) when memory allocation failed. Return -ENOMEM if memory allocation failed. [1] https://syzkaller.appspot.com/bug?id=a55ba438506fe68649a5f50d2d82d56b365e0107 Signed-off-by: Tetsuo Handa Fixes: 8db6c34f1dbc8e06 ("Introduce v3 namespaced file capabilities") Reported-by: syzbot Cc: stable # 4.14+ Acked-by: Serge E. Hallyn Acked-by: James Morris Signed-off-by: Eric W. Biederman Signed-off-by: Greg Kroah-Hartman --- security/commoncap.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/security/commoncap.c b/security/commoncap.c index 7b01431d1e19..1c1f64582bb5 100644 --- a/security/commoncap.c +++ b/security/commoncap.c @@ -449,6 +449,8 @@ int cap_inode_getsecurity(struct inode *inode, const char *name, void **buffer, magic |= VFS_CAP_FLAGS_EFFECTIVE; memcpy(&cap->data, &nscap->data, sizeof(__le32) * 2 * VFS_CAP_U32); cap->magic_etc = cpu_to_le32(magic); + } else { + size = -ENOMEM; } } kfree(tmpbuf); -- GitLab From f4df47e36ac052e772899b0d141daed1c9b008ae Mon Sep 17 00:00:00 2001 From: "Martin K. Petersen" Date: Wed, 18 Apr 2018 22:54:59 -0400 Subject: [PATCH 1180/1635] scsi: mptsas: Disable WRITE SAME commit 94e5395d2403c8bc2504a7cbe4c4caaacb7b8b84 upstream. First generation MPT Fusion controllers can not translate WRITE SAME when the attached device is a SATA drive. Disable WRITE SAME support. Reported-by: Nikola Ciprich Cc: Signed-off-by: Martin K. Petersen Signed-off-by: Greg Kroah-Hartman --- drivers/message/fusion/mptsas.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/message/fusion/mptsas.c b/drivers/message/fusion/mptsas.c index 345f6035599e..f1d93676b0fc 100644 --- a/drivers/message/fusion/mptsas.c +++ b/drivers/message/fusion/mptsas.c @@ -1995,6 +1995,7 @@ static struct scsi_host_template mptsas_driver_template = { .cmd_per_lun = 7, .use_clustering = ENABLE_CLUSTERING, .shost_attrs = mptscsih_host_attrs, + .no_write_same = 1, }; static int mptsas_get_linkerrors(struct sas_phy *phy) -- GitLab From 68c09d548bfc61aec99fa9a24e703c3d6fdba9b1 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 18 Apr 2018 12:51:31 +0300 Subject: [PATCH 1181/1635] cdrom: information leak in cdrom_ioctl_media_changed() commit 9de4ee40547fd315d4a0ed1dd15a2fa3559ad707 upstream. This cast is wrong. "cdi->capacity" is an int and "arg" is an unsigned long. The way the check is written now, if one of the high 32 bits is set then we could read outside the info->slots[] array. This bug is pretty old and it predates git. Reviewed-by: Christoph Hellwig Cc: stable@vger.kernel.org Signed-off-by: Dan Carpenter Signed-off-by: Jens Axboe Signed-off-by: Greg Kroah-Hartman --- drivers/cdrom/cdrom.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c index e36d160c458f..5f7d86509f2f 100644 --- a/drivers/cdrom/cdrom.c +++ b/drivers/cdrom/cdrom.c @@ -2374,7 +2374,7 @@ static int cdrom_ioctl_media_changed(struct cdrom_device_info *cdi, if (!CDROM_CAN(CDC_SELECT_DISC) || arg == CDSL_CURRENT) return media_changed(cdi, 1); - if ((unsigned int)arg >= cdi->capacity) + if (arg >= cdi->capacity) return -EINVAL; info = kmalloc(sizeof(*info), GFP_KERNEL); -- GitLab From 75b98294e09a9a027eecaff448b4c59f521b6b56 Mon Sep 17 00:00:00 2001 From: Robert Kolchmeyer Date: Thu, 19 Apr 2018 10:44:33 -0700 Subject: [PATCH 1182/1635] fsnotify: Fix fsnotify_mark_connector race commit d90a10e2444ba5a351fa695917258ff4c5709fa5 upstream. fsnotify() acquires a reference to a fsnotify_mark_connector through the SRCU-protected pointer to_tell->i_fsnotify_marks. However, it appears that no precautions are taken in fsnotify_put_mark() to ensure that fsnotify() drops its reference to this fsnotify_mark_connector before assigning a value to its 'destroy_next' field. This can result in fsnotify_put_mark() assigning a value to a connector's 'destroy_next' field right before fsnotify() tries to traverse the linked list referenced by the connector's 'list' field. Since these two fields are members of the same union, this behavior results in a kernel panic. This issue is resolved by moving the connector's 'destroy_next' field into the object pointer union. This should work since the object pointer access is protected by both a spinlock and the value of the 'flags' field, and the 'flags' field is cleared while holding the spinlock in fsnotify_put_mark() before 'destroy_next' is updated. It shouldn't be possible for another thread to accidentally read from the object pointer after the 'destroy_next' field is updated. The offending behavior here is extremely unlikely; since fsnotify_put_mark() removes references to a connector (specifically, it ensures that the connector is unreachable from the inode it was formerly attached to) before updating its 'destroy_next' field, a sizeable chunk of code in fsnotify_put_mark() has to execute in the short window between when fsnotify() acquires the connector reference and saves the value of its 'list' field. On the HEAD kernel, I've only been able to reproduce this by inserting a udelay(1) in fsnotify(). However, I've been able to reproduce this issue without inserting a udelay(1) anywhere on older unmodified release kernels, so I believe it's worth fixing at HEAD. References: https://bugzilla.kernel.org/show_bug.cgi?id=199437 Fixes: 08991e83b7286635167bab40927665a90fb00d81 CC: stable@vger.kernel.org Signed-off-by: Robert Kolchmeyer Signed-off-by: Jan Kara Signed-off-by: Greg Kroah-Hartman --- include/linux/fsnotify_backend.h | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/include/linux/fsnotify_backend.h b/include/linux/fsnotify_backend.h index 3597ef78df4d..ce74278a454a 100644 --- a/include/linux/fsnotify_backend.h +++ b/include/linux/fsnotify_backend.h @@ -217,12 +217,10 @@ struct fsnotify_mark_connector { union { /* Object pointer [lock] */ struct inode *inode; struct vfsmount *mnt; - }; - union { - struct hlist_head list; /* Used listing heads to free after srcu period expires */ struct fsnotify_mark_connector *destroy_next; }; + struct hlist_head list; }; /* -- GitLab From 43f8a4f2c8b2d7cd2565f8f455aa9e336ad31df0 Mon Sep 17 00:00:00 2001 From: Finn Thain Date: Wed, 11 Apr 2018 20:50:14 -0400 Subject: [PATCH 1183/1635] m68k/mac: Don't remap SWIM MMIO region commit b64576cbf36afa5fabf3b31f62a1994c429ef855 upstream. For reasons I don't understand, calling ioremap() then iounmap() on the SWIM MMIO region causes a hang on 68030 (but not on 68040). ~# modprobe swim_mod SWIM floppy driver Version 0.2 (2008-10-30) SWIM device not found ! watchdog: BUG: soft lockup - CPU#0 stuck for 23s! [modprobe:285] Modules linked in: swim_mod(+) Format 00 Vector: 0064 PC: 000075aa Status: 2000 Not tainted ORIG_D0: ffffffff D0: d00c0000 A2: 007c2370 A1: 003f810c A0: 00040000 D5: d0096800 D4: d0097e00 D3: 00000001 D2: 00000003 D1: 00000000 Non-Maskable Interrupt Modules linked in: swim_mod(+) PC: [<000075ba>] __iounmap+0x24/0x10e SR: 2000 SP: 007abc48 a2: 007c2370 d0: d00c0000 d1: 000001a0 d2: 00000019 d3: 00000001 d4: d0097e00 d5: d0096800 a0: 00040000 a1: 003f810c Process modprobe (pid: 285, task=007c2370) Frame format=0 Stack from 007abc7c: ffffffed 00000000 006a4060 004712e0 007abca0 000076ea d0080000 00080000 010bb4b8 007abcd8 010ba542 d0096000 00000000 00000000 00000001 010bb59c 00000000 007abf30 010bb4b8 0047760a 0047763c 00477612 00616540 007abcec 0020a91a 00477600 0047760a 010bb4cc 007abd18 002092f2 0047760a 00333b06 007abd5c 00000000 0047760a 010bb4cc 00404f90 004776b8 00000001 007abd38 00209446 010bb4cc 0047760a 010bb4cc 0020938e 0031f8be 00616540 007abd64 Call Trace: [<000076ea>] iounmap+0x46/0x5a [<00080000>] shrink_page_list+0x7f6/0xe06 [<010ba542>] swim_probe+0xe4/0x496 [swim_mod] [<0020a91a>] platform_drv_probe+0x20/0x5e [<002092f2>] driver_probe_device+0x21c/0x2b8 [<00333b06>] mutex_lock+0x0/0x2e [<00209446>] __driver_attach+0xb8/0xce [<0020938e>] __driver_attach+0x0/0xce [<0031f8be>] klist_next+0x0/0xa0 [<00207562>] bus_for_each_dev+0x74/0xba [<000344c0>] blocking_notifier_call_chain+0x0/0x20 [<00333b06>] mutex_lock+0x0/0x2e [<00208e44>] driver_attach+0x1a/0x1e [<0020938e>] __driver_attach+0x0/0xce [<00207e26>] bus_add_driver+0x188/0x234 [<000344c0>] blocking_notifier_call_chain+0x0/0x20 [<00209894>] driver_register+0x58/0x104 [<000344c0>] blocking_notifier_call_chain+0x0/0x20 [<010bd000>] swim_init+0x0/0x2c [swim_mod] [<0020a7be>] __platform_driver_register+0x38/0x3c [<010bd028>] swim_init+0x28/0x2c [swim_mod] [<000020dc>] do_one_initcall+0x38/0x196 [<000344c0>] blocking_notifier_call_chain+0x0/0x20 [<003331cc>] mutex_unlock+0x0/0x3e [<00333b06>] mutex_lock+0x0/0x2e [<003331cc>] mutex_unlock+0x0/0x3e [<00333b06>] mutex_lock+0x0/0x2e [<003331cc>] mutex_unlock+0x0/0x3e [<00333b06>] mutex_lock+0x0/0x2e [<003331cc>] mutex_unlock+0x0/0x3e [<00333b06>] mutex_lock+0x0/0x2e [<00075008>] __free_pages+0x0/0x38 [<000045c0>] mangle_kernel_stack+0x30/0xda [<000344c0>] blocking_notifier_call_chain+0x0/0x20 [<003331cc>] mutex_unlock+0x0/0x3e [<00333b06>] mutex_lock+0x0/0x2e [<0005ced4>] do_init_module+0x42/0x266 [<010bd000>] swim_init+0x0/0x2c [swim_mod] [<000344c0>] blocking_notifier_call_chain+0x0/0x20 [<0005eda0>] load_module+0x1a30/0x1e70 [<0000465d>] mangle_kernel_stack+0xcd/0xda [<00331c64>] __generic_copy_from_user+0x0/0x46 [<0033256e>] _cond_resched+0x0/0x32 [<00331b9c>] memset+0x0/0x98 [<0033256e>] _cond_resched+0x0/0x32 [<0005f25c>] SyS_init_module+0x7c/0x112 [<00002000>] _start+0x0/0x8 [<00002000>] _start+0x0/0x8 [<00331c82>] __generic_copy_from_user+0x1e/0x46 [<0005f2b2>] SyS_init_module+0xd2/0x112 [<0000465d>] mangle_kernel_stack+0xcd/0xda [<00002b40>] syscall+0x8/0xc [<0000465d>] mangle_kernel_stack+0xcd/0xda [<0008c00c>] pcpu_balance_workfn+0xb2/0x40e Code: 2200 7419 e4a9 e589 2841 d9fc 0000 1000 <2414> 7203 c282 7602 b681 6600 0096 0242 fe00 0482 0000 0000 e9c0 11c3 ed89 2642 There's no need to call ioremap() for the SWIM address range, as it lies within the usual IO device region at 0x5000 0000, which has already been mapped by head.S. Remove the redundant ioremap() and iounmap() calls to fix the hang. Cc: Laurent Vivier Cc: stable@vger.kernel.org # v4.14+ Tested-by: Stan Johnson Signed-off-by: Finn Thain Acked-by: Laurent Vivier Signed-off-by: Jens Axboe Signed-off-by: Greg Kroah-Hartman --- drivers/block/swim.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/drivers/block/swim.c b/drivers/block/swim.c index 84434d3ea19b..ef4361dc5b26 100644 --- a/drivers/block/swim.c +++ b/drivers/block/swim.c @@ -911,7 +911,7 @@ static int swim_probe(struct platform_device *dev) goto out; } - swim_base = ioremap(res->start, resource_size(res)); + swim_base = (struct swim __iomem *)res->start; if (!swim_base) { ret = -ENOMEM; goto out_release_io; @@ -923,7 +923,7 @@ static int swim_probe(struct platform_device *dev) if (!get_swim_mode(swim_base)) { printk(KERN_INFO "SWIM device not found !\n"); ret = -ENODEV; - goto out_iounmap; + goto out_release_io; } /* set platform driver data */ @@ -931,7 +931,7 @@ static int swim_probe(struct platform_device *dev) swd = kzalloc(sizeof(struct swim_priv), GFP_KERNEL); if (!swd) { ret = -ENOMEM; - goto out_iounmap; + goto out_release_io; } platform_set_drvdata(dev, swd); @@ -945,8 +945,6 @@ static int swim_probe(struct platform_device *dev) out_kfree: kfree(swd); -out_iounmap: - iounmap(swim_base); out_release_io: release_mem_region(res->start, resource_size(res)); out: @@ -974,8 +972,6 @@ static int swim_remove(struct platform_device *dev) for (drive = 0; drive < swd->floppy_count; drive++) floppy_eject(&swd->unit[drive]); - iounmap(swd->base); - res = platform_get_resource(dev, IORESOURCE_MEM, 0); if (res) release_mem_region(res->start, resource_size(res)); -- GitLab From 0dd9146a229147c526223cb06bf3468261ec79eb Mon Sep 17 00:00:00 2001 From: Finn Thain Date: Wed, 11 Apr 2018 20:50:14 -0400 Subject: [PATCH 1184/1635] block/swim: Check drive type commit 8a500df63d07d8aee44b7ee2c54e462e47ce93ec upstream. The SWIM chip is compatible with GCR-mode Sony 400K/800K drives but this driver only supports MFM mode. Therefore only Sony FDHD drives are supported. Skip incompatible drives. Cc: Laurent Vivier Cc: Jens Axboe Cc: stable@vger.kernel.org # v4.14+ Tested-by: Stan Johnson Signed-off-by: Finn Thain Acked-by: Laurent Vivier Signed-off-by: Jens Axboe Signed-off-by: Greg Kroah-Hartman --- drivers/block/swim.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/block/swim.c b/drivers/block/swim.c index ef4361dc5b26..eb8b7573586d 100644 --- a/drivers/block/swim.c +++ b/drivers/block/swim.c @@ -834,10 +834,12 @@ static int swim_floppy_init(struct swim_priv *swd) /* scan floppy drives */ swim_drive(base, INTERNAL_DRIVE); - if (swim_readbit(base, DRIVE_PRESENT)) + if (swim_readbit(base, DRIVE_PRESENT) && + !swim_readbit(base, ONEMEG_DRIVE)) swim_add_floppy(swd, INTERNAL_DRIVE); swim_drive(base, EXTERNAL_DRIVE); - if (swim_readbit(base, DRIVE_PRESENT)) + if (swim_readbit(base, DRIVE_PRESENT) && + !swim_readbit(base, ONEMEG_DRIVE)) swim_add_floppy(swd, EXTERNAL_DRIVE); /* register floppy drives */ -- GitLab From b7100feb26d21c27a8a75e5351a618bbc94fff49 Mon Sep 17 00:00:00 2001 From: Finn Thain Date: Wed, 11 Apr 2018 20:50:14 -0400 Subject: [PATCH 1185/1635] block/swim: Don't log an error message for an invalid ioctl commit 8e2ab5a4efaac77fb93e5b5b109d0b3976fdd3a0 upstream. The 'eject' shell command may send various different ioctl commands. This leads to error messages on the console even though the FDEJECT ioctl succeeds. ~# eject floppy SWIM floppy_ioctl: unknown cmd 21257 SWIM floppy_ioctl: unknown cmd 1 Don't log an error message for an invalid ioctl, just do as the swim3 driver does and return -ENOTTY. Cc: Laurent Vivier Cc: Jens Axboe Cc: stable@vger.kernel.org # v4.14+ Tested-by: Stan Johnson Signed-off-by: Finn Thain Acked-by: Laurent Vivier Reviewed-by: Geert Uytterhoeven Signed-off-by: Jens Axboe Signed-off-by: Greg Kroah-Hartman --- drivers/block/swim.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/drivers/block/swim.c b/drivers/block/swim.c index eb8b7573586d..095f22acd709 100644 --- a/drivers/block/swim.c +++ b/drivers/block/swim.c @@ -727,14 +727,9 @@ static int floppy_ioctl(struct block_device *bdev, fmode_t mode, if (copy_to_user((void __user *) param, (void *) &floppy_type, sizeof(struct floppy_struct))) return -EFAULT; - break; - - default: - printk(KERN_DEBUG "SWIM floppy_ioctl: unknown cmd %d\n", - cmd); - return -ENOSYS; + return 0; } - return 0; + return -ENOTTY; } static int floppy_getgeo(struct block_device *bdev, struct hd_geometry *geo) -- GitLab From f359e87feb8859f687e43bb99f52e566ee82b347 Mon Sep 17 00:00:00 2001 From: Finn Thain Date: Wed, 11 Apr 2018 20:50:14 -0400 Subject: [PATCH 1186/1635] block/swim: Remove extra put_disk() call from error path commit c1d6207cc0eef2a7f8551f9c7420d8776268f6e1 upstream. Cc: Laurent Vivier Cc: Jens Axboe Cc: stable@vger.kernel.org # v4.14+ Fixes: 103db8b2dfa5 ("[PATCH] swim: stop sharing request queue across multiple gendisks") Tested-by: Stan Johnson Signed-off-by: Finn Thain Acked-by: Laurent Vivier Reviewed-by: Geert Uytterhoeven Signed-off-by: Jens Axboe Signed-off-by: Greg Kroah-Hartman --- drivers/block/swim.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/block/swim.c b/drivers/block/swim.c index 095f22acd709..3b3e5b134e2a 100644 --- a/drivers/block/swim.c +++ b/drivers/block/swim.c @@ -858,7 +858,6 @@ static int swim_floppy_init(struct swim_priv *swd) &swd->lock); if (!swd->unit[drive].disk->queue) { err = -ENOMEM; - put_disk(swd->unit[drive].disk); goto exit_put_disks; } blk_queue_bounce_limit(swd->unit[drive].disk->queue, -- GitLab From cdb0d5fa252864dccb223ba5437598c2b1684289 Mon Sep 17 00:00:00 2001 From: Finn Thain Date: Wed, 11 Apr 2018 20:50:14 -0400 Subject: [PATCH 1187/1635] block/swim: Rename macros to avoid inconsistent inverted logic commit 56a1c5ee54f69dd767fb61d301883dc919ddc259 upstream. The Sony drive status bits use active-low logic. The swim_readbit() function converts that to 'C' logic for readability. Hence, the sense of the names of the status bit macros should not be inverted. Mostly they are correct. However, the TWOMEG_DRIVE, MFM_MODE and TWOMEG_MEDIA macros have inverted sense (like MkLinux). Fix this inconsistency and make the following patches less confusing. The same problem affects swim3.c so fix that too. No functional change. The FDHD drive status bits are documented in sonydriv.cpp from MAME and in swimiii.h from MkLinux. Cc: Laurent Vivier Cc: Benjamin Herrenschmidt Cc: linuxppc-dev@lists.ozlabs.org Cc: Jens Axboe Cc: stable@vger.kernel.org # v4.14+ Tested-by: Stan Johnson Signed-off-by: Finn Thain Acked-by: Laurent Vivier Signed-off-by: Jens Axboe Signed-off-by: Greg Kroah-Hartman --- drivers/block/swim.c | 8 ++++---- drivers/block/swim3.c | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/block/swim.c b/drivers/block/swim.c index 3b3e5b134e2a..2ab70494ace4 100644 --- a/drivers/block/swim.c +++ b/drivers/block/swim.c @@ -110,7 +110,7 @@ struct iwm { /* Select values for swim_select and swim_readbit */ #define READ_DATA_0 0x074 -#define TWOMEG_DRIVE 0x075 +#define ONEMEG_DRIVE 0x075 #define SINGLE_SIDED 0x076 #define DRIVE_PRESENT 0x077 #define DISK_IN 0x170 @@ -118,9 +118,9 @@ struct iwm { #define TRACK_ZERO 0x172 #define TACHO 0x173 #define READ_DATA_1 0x174 -#define MFM_MODE 0x175 +#define GCR_MODE 0x175 #define SEEK_COMPLETE 0x176 -#define ONEMEG_MEDIA 0x177 +#define TWOMEG_MEDIA 0x177 /* Bits in handshake register */ @@ -612,7 +612,7 @@ static void setup_medium(struct floppy_state *fs) struct floppy_struct *g; fs->disk_in = 1; fs->write_protected = swim_readbit(base, WRITE_PROT); - fs->type = swim_readbit(base, ONEMEG_MEDIA); + fs->type = swim_readbit(base, TWOMEG_MEDIA); if (swim_track00(base)) printk(KERN_ERR diff --git a/drivers/block/swim3.c b/drivers/block/swim3.c index 9f931f8f6b4c..0d7527c6825a 100644 --- a/drivers/block/swim3.c +++ b/drivers/block/swim3.c @@ -148,7 +148,7 @@ struct swim3 { #define MOTOR_ON 2 #define RELAX 3 /* also eject in progress */ #define READ_DATA_0 4 -#define TWOMEG_DRIVE 5 +#define ONEMEG_DRIVE 5 #define SINGLE_SIDED 6 /* drive or diskette is 4MB type? */ #define DRIVE_PRESENT 7 #define DISK_IN 8 @@ -156,9 +156,9 @@ struct swim3 { #define TRACK_ZERO 10 #define TACHO 11 #define READ_DATA_1 12 -#define MFM_MODE 13 +#define GCR_MODE 13 #define SEEK_COMPLETE 14 -#define ONEMEG_MEDIA 15 +#define TWOMEG_MEDIA 15 /* Definitions of values used in writing and formatting */ #define DATA_ESCAPE 0x99 -- GitLab From 8c37ac3c04e7122843505c7bfd054fbb7f320777 Mon Sep 17 00:00:00 2001 From: Finn Thain Date: Wed, 11 Apr 2018 20:50:14 -0400 Subject: [PATCH 1188/1635] block/swim: Select appropriate drive on device open commit b3906535ccc6cd04c42f9b1c7e31d1947b3ebc74 upstream. The driver supports internal and external FDD units so the floppy_open function must not hard-code the drive location. Cc: Laurent Vivier Cc: Jens Axboe Cc: stable@vger.kernel.org # v4.14+ Tested-by: Stan Johnson Signed-off-by: Finn Thain Acked-by: Laurent Vivier Signed-off-by: Jens Axboe Signed-off-by: Greg Kroah-Hartman --- drivers/block/swim.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/block/swim.c b/drivers/block/swim.c index 2ab70494ace4..b82aaa49df47 100644 --- a/drivers/block/swim.c +++ b/drivers/block/swim.c @@ -646,7 +646,7 @@ static int floppy_open(struct block_device *bdev, fmode_t mode) swim_write(base, setup, S_IBM_DRIVE | S_FCLK_DIV2); udelay(10); - swim_drive(base, INTERNAL_DRIVE); + swim_drive(base, fs->location); swim_motor(base, ON); swim_action(base, SETMFM); if (fs->ejected) -- GitLab From 06dc2e91959344adafbf34071d8c1d23e719c67d Mon Sep 17 00:00:00 2001 From: Finn Thain Date: Wed, 11 Apr 2018 20:50:14 -0400 Subject: [PATCH 1189/1635] block/swim: Fix array bounds check commit 7ae6a2b6cc058005ee3d0d2b9ce27688e51afa4b upstream. In the floppy_find() function in swim.c is a call to get_disk(swd->unit[drive].disk). The actual parameter to this call can be a NULL pointer when drive == swd->floppy_count. This causes an oops in get_disk(). Data read fault at 0x00000198 in Super Data (pc=0x1be5b6) BAD KERNEL BUSERR Oops: 00000000 Modules linked in: swim_mod ipv6 mac8390 PC: [<001be5b6>] get_disk+0xc/0x76 SR: 2004 SP: 9a078bc1 a2: 0213ed90 d0: 00000000 d1: 00000000 d2: 00000000 d3: 000000ff d4: 00000002 d5: 02983590 a0: 02332e00 a1: 022dfd64 Process dd (pid: 285, task=020ab25b) Frame format=B ssw=074d isc=4a88 isb=6732 daddr=00000198 dobuf=00000000 baddr=001be5bc dibuf=bfffffff ver=f Stack from 022dfca4: 00000000 0203fc00 0213ed90 022dfcc0 02982936 00000000 00200000 022dfd08 0020f85a 00200000 022dfd64 02332e00 004040fc 00000014 001be77e 022dfd64 00334e4a 001be3f8 0800001d 022dfd64 01c04b60 01c04b70 022aba80 029828f8 02332e00 022dfd2c 001be7ac 0203fc00 00200000 022dfd64 02103a00 01c04b60 01c04b60 0200e400 022dfd68 000e191a 00200000 022dfd64 02103a00 0800001d 00000000 00000003 000b89de 00500000 02103a00 01c04b60 02103a08 01c04c2e Call Trace: [<02982936>] floppy_find+0x3e/0x4a [swim_mod] [<00200000>] uart_remove_one_port+0x1a2/0x260 [<0020f85a>] kobj_lookup+0xde/0x132 [<00200000>] uart_remove_one_port+0x1a2/0x260 [<001be77e>] get_gendisk+0x0/0x130 [<00334e4a>] mutex_lock+0x0/0x2e [<001be3f8>] disk_block_events+0x0/0x6c [<029828f8>] floppy_find+0x0/0x4a [swim_mod] [<001be7ac>] get_gendisk+0x2e/0x130 [<00200000>] uart_remove_one_port+0x1a2/0x260 [<000e191a>] __blkdev_get+0x32/0x45a [<00200000>] uart_remove_one_port+0x1a2/0x260 [<000b89de>] complete_walk+0x0/0x8a [<000e1e22>] blkdev_get+0xe0/0x29a [<000e1fdc>] blkdev_open+0x0/0xb0 [<000b89de>] complete_walk+0x0/0x8a [<000e1fdc>] blkdev_open+0x0/0xb0 [<000e01cc>] bd_acquire+0x74/0x8a [<000e205c>] blkdev_open+0x80/0xb0 [<000e1fdc>] blkdev_open+0x0/0xb0 [<000abf24>] do_dentry_open+0x1a4/0x322 [<00020000>] __do_proc_douintvec+0x22/0x27e [<000b89de>] complete_walk+0x0/0x8a [<000baa62>] link_path_walk+0x0/0x48e [<000ba3f8>] inode_permission+0x20/0x54 [<000ac0e4>] vfs_open+0x42/0x78 [<000bc372>] path_openat+0x2b2/0xeaa [<000bc0c0>] path_openat+0x0/0xeaa [<0004463e>] __irq_wake_thread+0x0/0x4e [<0003a45a>] task_tick_fair+0x18/0xc8 [<000bd00a>] do_filp_open+0xa0/0xea [<000abae0>] do_sys_open+0x11a/0x1ee [<00020000>] __do_proc_douintvec+0x22/0x27e [<000abbf4>] SyS_open+0x1e/0x22 [<00020000>] __do_proc_douintvec+0x22/0x27e [<00002b40>] syscall+0x8/0xc [<00020000>] __do_proc_douintvec+0x22/0x27e [<0000c00b>] dyadic+0x1/0x28 Code: 4e5e 4e75 4e56 fffc 2f0b 2f02 266e 0008 <206b> 0198 4a88 6732 2428 002c 661e 486b 0058 4eb9 0032 0b96 588f 4a88 672c 2008 Disabling lock debugging due to kernel taint Fix the array index bounds check to avoid this. Cc: Laurent Vivier Cc: Jens Axboe Cc: stable@vger.kernel.org # v4.14+ Fixes: 8852ecd97488 ("[PATCH] m68k: mac - Add SWIM floppy support") Tested-by: Stan Johnson Signed-off-by: Finn Thain Acked-by: Laurent Vivier Reviewed-by: Geert Uytterhoeven Signed-off-by: Jens Axboe Signed-off-by: Greg Kroah-Hartman --- drivers/block/swim.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/block/swim.c b/drivers/block/swim.c index b82aaa49df47..763931aebc15 100644 --- a/drivers/block/swim.c +++ b/drivers/block/swim.c @@ -790,7 +790,7 @@ static struct kobject *floppy_find(dev_t dev, int *part, void *data) struct swim_priv *swd = data; int drive = (*part & 3); - if (drive > swd->floppy_count) + if (drive >= swd->floppy_count) return NULL; *part = 0; -- GitLab From d82923c017deeeec73ce871e742de42935f871cf Mon Sep 17 00:00:00 2001 From: Finn Thain Date: Wed, 11 Apr 2018 20:50:14 -0400 Subject: [PATCH 1190/1635] block/swim: Fix IO error at end of medium commit 5a13388d7aa1177b98d7168330ecbeeac52f844d upstream. Reading to the end of a 720K disk results in an IO error instead of EOF because the block layer thinks the disk has 2880 sectors. (Partly this is a result of inverted logic of the ONEMEG_MEDIA bit that's now fixed.) Initialize the density and head count in swim_add_floppy() to agree with the device size passed to set_capacity() during drive probe. Call set_capacity() again upon device open, after refreshing the density and head count values. Cc: Laurent Vivier Cc: Jens Axboe Cc: stable@vger.kernel.org # v4.14+ Tested-by: Stan Johnson Signed-off-by: Finn Thain Acked-by: Laurent Vivier Signed-off-by: Jens Axboe Signed-off-by: Greg Kroah-Hartman --- drivers/block/swim.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/drivers/block/swim.c b/drivers/block/swim.c index 763931aebc15..e88d50f75a4a 100644 --- a/drivers/block/swim.c +++ b/drivers/block/swim.c @@ -612,7 +612,6 @@ static void setup_medium(struct floppy_state *fs) struct floppy_struct *g; fs->disk_in = 1; fs->write_protected = swim_readbit(base, WRITE_PROT); - fs->type = swim_readbit(base, TWOMEG_MEDIA); if (swim_track00(base)) printk(KERN_ERR @@ -620,6 +619,9 @@ static void setup_medium(struct floppy_state *fs) swim_track00(base); + fs->type = swim_readbit(base, TWOMEG_MEDIA) ? + HD_MEDIA : DD_MEDIA; + fs->head_number = swim_readbit(base, SINGLE_SIDED) ? 1 : 2; get_floppy_geometry(fs, 0, &g); fs->total_secs = g->size; fs->secpercyl = g->head * g->sect; @@ -656,6 +658,8 @@ static int floppy_open(struct block_device *bdev, fmode_t mode) goto out; } + set_capacity(fs->disk, fs->total_secs); + if (mode & FMODE_NDELAY) return 0; @@ -808,10 +812,9 @@ static int swim_add_floppy(struct swim_priv *swd, enum drive_location location) swim_motor(base, OFF); - if (swim_readbit(base, SINGLE_SIDED)) - fs->head_number = 1; - else - fs->head_number = 2; + fs->type = HD_MEDIA; + fs->head_number = 2; + fs->ref_count = 0; fs->ejected = 1; -- GitLab From a75bf6f71744ec27db4092a1e9a00536e9c4c1d1 Mon Sep 17 00:00:00 2001 From: Peter Xu Date: Thu, 15 Mar 2018 14:06:39 +0800 Subject: [PATCH 1191/1635] tracing: Fix missing tab for hwlat_detector print format commit 9a0fd675304d410f3a9586e1b333e16f4658d56c upstream. It's been missing for a while but no one is touching that up. Fix it. Link: http://lkml.kernel.org/r/20180315060639.9578-1-peterx@redhat.com CC: Ingo Molnar Cc:stable@vger.kernel.org Fixes: 7b2c86250122d ("tracing: Add NMI tracing in hwlat detector") Signed-off-by: Peter Xu Signed-off-by: Steven Rostedt (VMware) Signed-off-by: Greg Kroah-Hartman --- kernel/trace/trace_entries.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/trace/trace_entries.h b/kernel/trace/trace_entries.h index e954ae3d82c0..e3a658bac10f 100644 --- a/kernel/trace/trace_entries.h +++ b/kernel/trace/trace_entries.h @@ -356,7 +356,7 @@ FTRACE_ENTRY(hwlat, hwlat_entry, __field( unsigned int, seqnum ) ), - F_printk("cnt:%u\tts:%010llu.%010lu\tinner:%llu\touter:%llunmi-ts:%llu\tnmi-count:%u\n", + F_printk("cnt:%u\tts:%010llu.%010lu\tinner:%llu\touter:%llu\tnmi-ts:%llu\tnmi-count:%u\n", __entry->seqnum, __entry->tv_sec, __entry->tv_nsec, -- GitLab From 3b5c2e1d163a500821079938fbfd55afcc82ac55 Mon Sep 17 00:00:00 2001 From: Sebastian Ott Date: Wed, 11 Apr 2018 11:21:17 +0200 Subject: [PATCH 1192/1635] s390/cio: update chpid descriptor after resource accessibility event commit af2e460ade0b0180d0f3812ca4f4f59cc9597f3e upstream. Channel path descriptors have been seen as something stable (as long as the chpid is configured). Recent tests have shown that the descriptor can also be altered when the link state of a channel path changes. Thus it is necessary to update the descriptor during handling of resource accessibility events. Cc: Signed-off-by: Sebastian Ott Reviewed-by: Peter Oberparleiter Signed-off-by: Martin Schwidefsky Signed-off-by: Greg Kroah-Hartman --- drivers/s390/cio/chsc.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/drivers/s390/cio/chsc.c b/drivers/s390/cio/chsc.c index 7b0b295b2313..69687c16a150 100644 --- a/drivers/s390/cio/chsc.c +++ b/drivers/s390/cio/chsc.c @@ -451,6 +451,7 @@ static void chsc_process_sei_link_incident(struct chsc_sei_nt0_area *sei_area) static void chsc_process_sei_res_acc(struct chsc_sei_nt0_area *sei_area) { + struct channel_path *chp; struct chp_link link; struct chp_id chpid; int status; @@ -463,10 +464,17 @@ static void chsc_process_sei_res_acc(struct chsc_sei_nt0_area *sei_area) chpid.id = sei_area->rsid; /* allocate a new channel path structure, if needed */ status = chp_get_status(chpid); - if (status < 0) - chp_new(chpid); - else if (!status) + if (!status) return; + + if (status < 0) { + chp_new(chpid); + } else { + chp = chpid_to_chp(chpid); + mutex_lock(&chp->lock); + chp_update_desc(chp); + mutex_unlock(&chp->lock); + } memset(&link, 0, sizeof(struct chp_link)); link.chpid = chpid; if ((sei_area->vf & 0xc0) != 0) { -- GitLab From 5dad51054d8a72117a8601ccfeb76a1086942bfd Mon Sep 17 00:00:00 2001 From: Stefan Haberland Date: Thu, 12 Apr 2018 13:38:22 +0200 Subject: [PATCH 1193/1635] s390/dasd: fix IO error for newly defined devices commit 5d27a2bf6e14f5c7d1033ad1e993fcd0eba43e83 upstream. When a new CKD storage volume is defined at the storage server, Linux may be relying on outdated information about that volume, which leads to the following errors: 1. Command Reject Errors for minidisk on z/VM: dasd-eckd.b3193d: 0.0.XXXX: An error occurred in the DASD device driver, reason=09 dasd(eckd): I/O status report for device 0.0.XXXX: dasd(eckd): in req: 00000000XXXXXXXX CC:00 FC:04 AC:00 SC:17 DS:02 CS:00 RC:0 dasd(eckd): device 0.0.2046: Failing CCW: 00000000XXXXXXXX dasd(eckd): Sense(hex) 0- 7: 80 00 00 00 00 00 00 00 dasd(eckd): Sense(hex) 8-15: 00 00 00 00 00 00 00 00 dasd(eckd): Sense(hex) 16-23: 00 00 00 00 e1 00 0f 00 dasd(eckd): Sense(hex) 24-31: 00 00 40 e2 00 00 00 00 dasd(eckd): 24 Byte: 0 MSG 0, no MSGb to SYSOP 2. Equipment Check errors on LPAR or for dedicated devices on z/VM: dasd(eckd): I/O status report for device 0.0.XXXX: dasd(eckd): in req: 00000000XXXXXXXX CC:00 FC:04 AC:00 SC:17 DS:0E CS:40 fcxs:01 schxs:00 RC:0 dasd(eckd): device 0.0.9713: Failing TCW: 00000000XXXXXXXX dasd(eckd): Sense(hex) 0- 7: 10 00 00 00 13 58 4d 0f dasd(eckd): Sense(hex) 8-15: 67 00 00 00 00 00 00 04 dasd(eckd): Sense(hex) 16-23: e5 18 05 33 97 01 0f 0f dasd(eckd): Sense(hex) 24-31: 00 00 40 e2 00 04 58 0d dasd(eckd): 24 Byte: 0 MSG f, no MSGb to SYSOP Fix this problem by using the up-to-date information provided during online processing via the device specific SNEQ to detect the case of outdated LCU data. If there is a difference, perform a re-read of that data. Cc: stable@vger.kernel.org Reviewed-by: Jan Hoeppner Signed-off-by: Stefan Haberland Signed-off-by: Martin Schwidefsky Signed-off-by: Greg Kroah-Hartman --- drivers/s390/block/dasd_alias.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/drivers/s390/block/dasd_alias.c b/drivers/s390/block/dasd_alias.c index 62f5f04d8f61..5e963fe0e38d 100644 --- a/drivers/s390/block/dasd_alias.c +++ b/drivers/s390/block/dasd_alias.c @@ -592,13 +592,22 @@ static int _schedule_lcu_update(struct alias_lcu *lcu, int dasd_alias_add_device(struct dasd_device *device) { struct dasd_eckd_private *private = device->private; - struct alias_lcu *lcu; + __u8 uaddr = private->uid.real_unit_addr; + struct alias_lcu *lcu = private->lcu; unsigned long flags; int rc; - lcu = private->lcu; rc = 0; spin_lock_irqsave(&lcu->lock, flags); + /* + * Check if device and lcu type differ. If so, the uac data may be + * outdated and needs to be updated. + */ + if (private->uid.type != lcu->uac->unit[uaddr].ua_type) { + lcu->flags |= UPDATE_PENDING; + DBF_DEV_EVENT(DBF_WARNING, device, "%s", + "uid type mismatch - trigger rescan"); + } if (!(lcu->flags & UPDATE_PENDING)) { rc = _add_device_to_lcu(lcu, device, device); if (rc) -- GitLab From c371fe019001c56ac3d91a8a2c30158c1be5fcc0 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Mon, 16 Apr 2018 12:22:24 +0200 Subject: [PATCH 1194/1635] s390/uprobes: implement arch_uretprobe_is_alive() commit 783c3b53b9506db3e05daacfe34e0287eebb09d8 upstream. Implement s390 specific arch_uretprobe_is_alive() to avoid SIGSEGVs observed with uretprobes in combination with setjmp/longjmp. See commit 2dea1d9c38e4 ("powerpc/uprobes: Implement arch_uretprobe_is_alive()") for more details. With this implemented all test cases referenced in the above commit pass. Reported-by: Ziqian SUN Cc: # v4.3+ Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky Signed-off-by: Greg Kroah-Hartman --- arch/s390/kernel/uprobes.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/arch/s390/kernel/uprobes.c b/arch/s390/kernel/uprobes.c index d9d1f512f019..5007fac01bb5 100644 --- a/arch/s390/kernel/uprobes.c +++ b/arch/s390/kernel/uprobes.c @@ -150,6 +150,15 @@ unsigned long arch_uretprobe_hijack_return_addr(unsigned long trampoline, return orig; } +bool arch_uretprobe_is_alive(struct return_instance *ret, enum rp_check ctx, + struct pt_regs *regs) +{ + if (ctx == RP_CHECK_CHAIN_CALL) + return user_stack_pointer(regs) <= ret->stack; + else + return user_stack_pointer(regs) < ret->stack; +} + /* Instruction Emulation */ static void adjust_psw_addr(psw_t *psw, unsigned long len) -- GitLab From 3e4915873cff08e6b02b5807336ef559690ddecf Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Tue, 17 Apr 2018 18:23:50 +0200 Subject: [PATCH 1195/1635] ACPI / video: Only default only_lcd to true on Win8-ready _desktops_ commit 53fa1f6e8a5958da698a31edf366ffe90596b490 upstream. Commit 5928c281524f (ACPI / video: Default lcd_only to true on Win8-ready and newer machines) made only_lcd default to true on all machines where acpi_osi_is_win8() returns true, including laptops. The purpose of this is to avoid the bogus / non-working acpi backlight interface which many newer BIOS-es define on desktop machines. But this is causing a regression on some laptops, specifically on the Dell XPS 13 2013 model, which does not have the LCD flag set for its fully functional ACPI backlight interface. Rather then DMI quirking our way out of this, this commits changes the logic for setting only_lcd to true, to only do this on machines with a desktop (or server) dmi chassis-type. Note that we cannot simply only check the chassis-type and not register the backlight interface based on that as there are some laptops and tablets which have their chassis-type set to "3" aka desktop. Hopefully the combination of checking the LCD flag, but only on devices with a desktop(ish) chassis-type will avoid the needs for DMI quirks for this, or at least limit the amount of DMI quirks which we need to a minimum. Fixes: 5928c281524f (ACPI / video: Default lcd_only to true on Win8-ready and newer machines) Reported-and-tested-by: James Hogan Signed-off-by: Hans de Goede Cc: 4.15+ # 4.15+ Signed-off-by: Rafael J. Wysocki Signed-off-by: Greg Kroah-Hartman --- drivers/acpi/acpi_video.c | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/drivers/acpi/acpi_video.c b/drivers/acpi/acpi_video.c index f53ccc680238..dbdd460a9958 100644 --- a/drivers/acpi/acpi_video.c +++ b/drivers/acpi/acpi_video.c @@ -2123,6 +2123,25 @@ static int __init intel_opregion_present(void) return opregion; } +static bool dmi_is_desktop(void) +{ + const char *chassis_type; + + chassis_type = dmi_get_system_info(DMI_CHASSIS_TYPE); + if (!chassis_type) + return false; + + if (!strcmp(chassis_type, "3") || /* 3: Desktop */ + !strcmp(chassis_type, "4") || /* 4: Low Profile Desktop */ + !strcmp(chassis_type, "5") || /* 5: Pizza Box */ + !strcmp(chassis_type, "6") || /* 6: Mini Tower */ + !strcmp(chassis_type, "7") || /* 7: Tower */ + !strcmp(chassis_type, "11")) /* 11: Main Server Chassis */ + return true; + + return false; +} + int acpi_video_register(void) { int ret = 0; @@ -2143,8 +2162,12 @@ int acpi_video_register(void) * win8 ready (where we also prefer the native backlight driver, so * normally the acpi_video code should not register there anyways). */ - if (only_lcd == -1) - only_lcd = acpi_osi_is_win8(); + if (only_lcd == -1) { + if (dmi_is_desktop() && acpi_osi_is_win8()) + only_lcd = true; + else + only_lcd = false; + } dmi_check_system(video_dmi_table); -- GitLab From a87463f7420cd33c8cb3ece420468023c16f27b4 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Sun, 29 Apr 2018 11:33:18 +0200 Subject: [PATCH 1196/1635] Linux 4.14.38 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index ee330f5449e6..27a8d5c37180 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 VERSION = 4 PATCHLEVEL = 14 -SUBLEVEL = 37 +SUBLEVEL = 38 EXTRAVERSION = NAME = Petit Gorille -- GitLab From 19f433920266d159612ce47344cb052b665de8a0 Mon Sep 17 00:00:00 2001 From: Maulik Shah Date: Sun, 29 Apr 2018 14:39:26 +0530 Subject: [PATCH 1197/1635] defconfig: sdm: Enable RPM STATS driver for sdm640 Enable RPM stats driver. Change-Id: Id339f6c413e677b52e6a15e200450721138033ce Signed-off-by: Maulik Shah --- arch/arm64/configs/sdmsteppe-perf_defconfig | 1 + arch/arm64/configs/sdmsteppe_defconfig | 1 + 2 files changed, 2 insertions(+) diff --git a/arch/arm64/configs/sdmsteppe-perf_defconfig b/arch/arm64/configs/sdmsteppe-perf_defconfig index 43ddf66f2a0f..4b15bc7aa0b1 100644 --- a/arch/arm64/configs/sdmsteppe-perf_defconfig +++ b/arch/arm64/configs/sdmsteppe-perf_defconfig @@ -502,6 +502,7 @@ CONFIG_QCOM_EARLY_RANDOM=y CONFIG_QTI_RPMH_API=y CONFIG_QCOM_GLINK=y CONFIG_QCOM_GLINK_PKT=y +CONFIG_QTI_RPM_STATS_LOG=y CONFIG_MSM_CDSP_LOADER=y CONFIG_MSM_EVENT_TIMER=y CONFIG_MSM_PM=y diff --git a/arch/arm64/configs/sdmsteppe_defconfig b/arch/arm64/configs/sdmsteppe_defconfig index b727134b2f70..0fcc65545c32 100644 --- a/arch/arm64/configs/sdmsteppe_defconfig +++ b/arch/arm64/configs/sdmsteppe_defconfig @@ -517,6 +517,7 @@ CONFIG_QCOM_EARLY_RANDOM=y CONFIG_QTI_RPMH_API=y CONFIG_QCOM_GLINK=y CONFIG_QCOM_GLINK_PKT=y +CONFIG_QTI_RPM_STATS_LOG=y CONFIG_MSM_CDSP_LOADER=y CONFIG_MSM_EVENT_TIMER=y CONFIG_MSM_PM=y -- GitLab From f883f7b7e24337a74de3a661245d42eb96a24cf2 Mon Sep 17 00:00:00 2001 From: Taniya Das Date: Thu, 22 Mar 2018 15:42:24 +0530 Subject: [PATCH 1198/1635] clk: qcom: Add debug clock controller for QCS405 Add the debug mux structure with inputs for measuring the clocks on QCS405. Change-Id: Iba9a2c063e0731f49336634ebacd05e06e81623a Signed-off-by: Taniya Das --- .../bindings/clock/qcom,debugcc.txt | 3 +- drivers/clk/qcom/Kconfig | 8 + drivers/clk/qcom/Makefile | 1 + drivers/clk/qcom/debugcc-qcs405.c | 364 ++++++++++++++++++ 4 files changed, 375 insertions(+), 1 deletion(-) create mode 100644 drivers/clk/qcom/debugcc-qcs405.c diff --git a/Documentation/devicetree/bindings/clock/qcom,debugcc.txt b/Documentation/devicetree/bindings/clock/qcom,debugcc.txt index 710246f51417..e0e95547c8a0 100644 --- a/Documentation/devicetree/bindings/clock/qcom,debugcc.txt +++ b/Documentation/devicetree/bindings/clock/qcom,debugcc.txt @@ -2,7 +2,8 @@ Qualcomm Technologies, Inc. Debug Clock Controller Binding ---------------------------------------------------------- Required properties : -- compatible: Shall contain "qcom,debugcc-sm8150". +- compatible: Shall contain "qcom,debugcc-sm8150", + "qcom,debugcc-qcs405". - qcom,gcc: phandle to the GCC device node. - qcom,videocc: phandle to the Video CC device node. - qcom,camcc: phandle to the Camera CC device node. diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig index e86ffd2c0cb3..9d5fbacb03e3 100644 --- a/drivers/clk/qcom/Kconfig +++ b/drivers/clk/qcom/Kconfig @@ -324,3 +324,11 @@ config MDM_GCC_QCS405 QCS405 devices. Say Y if you want to use peripheral devices such as UART, SPI, I2C, USB, SD/eMMC, PCIe, etc. + +config MDM_DEBUGCC_QCS405 + tristate "QCS405 Debug Clock Controller" + depends on COMMON_CLK_QCOM + help + Support for the debug clock controller on Qualcomm Technologies, Inc + QCS405 devices. + Say Y if you want to support the clock measurement functionality. diff --git a/drivers/clk/qcom/Makefile b/drivers/clk/qcom/Makefile index bdabc90ba6e9..b0026c82358e 100644 --- a/drivers/clk/qcom/Makefile +++ b/drivers/clk/qcom/Makefile @@ -33,6 +33,7 @@ obj-$(CONFIG_MSM_CLK_AOP_QMP) += clk-aop-qmp.o obj-$(CONFIG_MSM_CLK_RPMH) += clk-rpmh.o obj-$(CONFIG_MSM_DEBUGCC_SM8150) += debugcc-sm8150.o obj-$(CONFIG_MSM_DISPCC_SM8150) += dispcc-sm8150.o +obj-$(CONFIG_MDM_DEBUGCC_QCS405) += debugcc-qcs405.o obj-$(CONFIG_MSM_GCC_8660) += gcc-msm8660.o obj-$(CONFIG_MSM_GCC_8916) += gcc-msm8916.o obj-$(CONFIG_MSM_GCC_8960) += gcc-msm8960.o diff --git a/drivers/clk/qcom/debugcc-qcs405.c b/drivers/clk/qcom/debugcc-qcs405.c new file mode 100644 index 000000000000..b231337d2e4f --- /dev/null +++ b/drivers/clk/qcom/debugcc-qcs405.c @@ -0,0 +1,364 @@ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#define pr_fmt(fmt) "clk: %s: " fmt, __func__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "clk-debug.h" + +static struct measure_clk_data debug_mux_priv = { + .ctl_reg = 0x74004, + .status_reg = 0x74008, + .xo_div4_cbcr = 0x30034, +}; + +static const char *const debug_mux_parent_names[] = { + "snoc_clk", + "pnoc_clk", + "bimc_clk", + "qpic_clk", + "ce1_clk", + "wcnss_m_clk", + "gcc_apss_ahb_clk", + "gcc_bimc_gfx_clk", + "gcc_blsp1_ahb_clk", + "gcc_blsp1_qup0_i2c_apps_clk", + "gcc_blsp1_qup0_spi_apps_clk", + "gcc_blsp1_qup1_i2c_apps_clk", + "gcc_blsp1_qup1_spi_apps_clk", + "gcc_blsp1_qup2_i2c_apps_clk", + "gcc_blsp1_qup2_spi_apps_clk", + "gcc_blsp1_qup3_i2c_apps_clk", + "gcc_blsp1_qup3_spi_apps_clk", + "gcc_blsp1_qup4_i2c_apps_clk", + "gcc_blsp1_qup4_spi_apps_clk", + "gcc_blsp1_uart0_apps_clk", + "gcc_blsp1_uart1_apps_clk", + "gcc_blsp1_uart2_apps_clk", + "gcc_blsp1_uart3_apps_clk", + "gcc_blsp2_ahb_clk", + "gcc_blsp2_qup0_i2c_apps_clk", + "gcc_blsp2_qup0_spi_apps_clk", + "gcc_blsp2_uart0_apps_clk", + "gcc_boot_rom_ahb_clk", + "gcc_dcc_clk", + "gcc_eth_axi_clk", + "gcc_eth_ptp_clk", + "gcc_eth_rgmii_clk", + "gcc_eth_slave_ahb_clk", + "gcc_geni_ir_s_clk", + "gcc_gp1_clk", + "gcc_gp2_clk", + "gcc_gp3_clk", + "gcc_mdss_ahb_clk", + "gcc_mdss_axi_clk", + "gcc_mdss_byte0_clk", + "gcc_mdss_esc0_clk", + "gcc_mdss_hdmi_app_clk", + "gcc_mdss_hdmi_pclk_clk", + "gcc_mdss_mdp_clk", + "gcc_mdss_pclk0_clk", + "gcc_mdss_vsync_clk", + "gcc_oxili_ahb_clk", + "gcc_oxili_gfx3d_clk", + "gcc_pcie_0_aux_clk", + "gcc_pcie_0_cfg_ahb_clk", + "gcc_pcie_0_mstr_axi_clk", + "gcc_pcie_0_pipe_clk", + "gcc_pcie_0_slv_axi_clk", + "gcc_pcnoc_usb2_clk", + "gcc_pcnoc_usb3_clk", + "gcc_pdm2_clk", + "gcc_pdm_ahb_clk", + "gcc_prng_ahb_clk", + "gcc_pwm0_xo512_clk", + "gcc_pwm1_xo512_clk", + "gcc_pwm2_xo512_clk", + "gcc_sdcc1_ahb_clk", + "gcc_sdcc1_apps_clk", + "gcc_sdcc1_ice_core_clk", + "gcc_sdcc2_ahb_clk", + "gcc_sdcc2_apps_clk", + "gcc_sys_noc_usb3_clk", + "gcc_usb20_mock_utmi_clk", + "gcc_usb2a_phy_sleep_clk", + "gcc_usb30_master_clk", + "gcc_usb30_mock_utmi_clk", + "gcc_usb30_sleep_clk", + "gcc_usb3_phy_aux_clk", + "gcc_usb3_phy_pipe_clk", + "gcc_usb_hs_inactivity_timers_clk", + "gcc_usb_hs_phy_cfg_ahb_clk", + "gcc_usb_hs_system_clk", +}; + +static struct clk_debug_mux gcc_debug_mux = { + .priv = &debug_mux_priv, + .debug_offset = 0x74000, + .post_div_offset = 0x74000, + .cbcr_offset = 0x74000, + .src_sel_mask = 0x1FF, + .src_sel_shift = 0, + .post_div_mask = 0xF000, + .post_div_shift = 12, + .en_mask = BIT(16), + MUX_SRC_LIST( + { "snoc_clk", 0x000, 4, GCC, + 0x000, 0x1FF, 0, 0xF000, 12, 4, 0x74000, 0x74000, 0x74000 }, + { "pnoc_clk", 0x008, 4, GCC, + 0x008, 0x1FF, 0, 0xF000, 12, 4, 0x74000, 0x74000, 0x74000 }, + { "bimc_clk", 0x15A, 4, GCC, + 0x15A, 0x1FF, 0, 0xF000, 12, 4, 0x74000, 0x74000, 0x74000 }, + { "qpic_clk", 0x0C0, 4, GCC, + 0x0C0, 0x1FF, 0, 0xF000, 12, 4, 0x74000, 0x74000, 0x74000 }, + { "ce1_clk", 0x138, 4, GCC, + 0x138, 0x1FF, 0, 0xF000, 12, 4, 0x74000, 0x74000, 0x74000 }, + { "wcnss_m_clk", 0x08A, 4, GCC, + 0x08A, 0x1FF, 0, 0xF000, 12, 4, 0x74000, 0x74000, 0x74000 }, + { "gcc_apss_ahb_clk", 0x168, 4, GCC, + 0x168, 0x1FF, 0, 0xF000, 12, 4, 0x74000, 0x74000, 0x74000 }, + { "gcc_bimc_gfx_clk", 0x2D, 4, GCC, + 0x2D, 0x1FF, 0, 0xF000, 12, 4, 0x74000, 0x74000, 0x74000 }, + { "gcc_blsp1_ahb_clk", 0x88, 4, GCC, + 0x88, 0x1FF, 0, 0xF000, 12, 4, 0x74000, 0x74000, 0x74000 }, + { "gcc_blsp1_qup0_i2c_apps_clk", 0x99, 4, GCC, + 0x99, 0x1FF, 0, 0xF000, 12, 4, 0x74000, 0x74000, 0x74000 }, + { "gcc_blsp1_qup0_spi_apps_clk", 0x98, 4, GCC, + 0x98, 0x1FF, 0, 0xF000, 12, 4, 0x74000, 0x74000, 0x74000 }, + { "gcc_blsp1_qup1_i2c_apps_clk", 0x8B, 4, GCC, + 0x8B, 0x1FF, 0, 0xF000, 12, 4, 0x74000, 0x74000, 0x74000 }, + { "gcc_blsp1_qup1_spi_apps_clk", 0x8A, 4, GCC, + 0x8A, 0x1FF, 0, 0xF000, 12, 4, 0x74000, 0x74000, 0x74000 }, + { "gcc_blsp1_qup2_i2c_apps_clk", 0x8F, 4, GCC, + 0x8F, 0x1FF, 0, 0xF000, 12, 4, 0x74000, 0x74000, 0x74000 }, + { "gcc_blsp1_qup2_spi_apps_clk", 0x8E, 4, GCC, + 0x8E, 0x1FF, 0, 0xF000, 12, 4, 0x74000, 0x74000, 0x74000 }, + { "gcc_blsp1_qup3_i2c_apps_clk", 0x93, 4, GCC, + 0x93, 0x1FF, 0, 0xF000, 12, 4, 0x74000, 0x74000, 0x74000 }, + { "gcc_blsp1_qup3_spi_apps_clk", 0x92, 4, GCC, + 0x92, 0x1FF, 0, 0xF000, 12, 4, 0x74000, 0x74000, 0x74000 }, + { "gcc_blsp1_qup4_i2c_apps_clk", 0x95, 4, GCC, + 0x95, 0x1FF, 0, 0xF000, 12, 4, 0x74000, 0x74000, 0x74000 }, + { "gcc_blsp1_qup4_spi_apps_clk", 0x94, 4, GCC, + 0x94, 0x1FF, 0, 0xF000, 12, 4, 0x74000, 0x74000, 0x74000 }, + { "gcc_blsp1_uart0_apps_clk", 0x9A, 4, GCC, + 0x9A, 0x1FF, 0, 0xF000, 12, 4, 0x74000, 0x74000, 0x74000 }, + { "gcc_blsp1_uart1_apps_clk", 0x8C, 4, GCC, + 0x8C, 0x1FF, 0, 0xF000, 12, 4, 0x74000, 0x74000, 0x74000 }, + { "gcc_blsp1_uart2_apps_clk", 0x90, 4, GCC, + 0x90, 0x1FF, 0, 0xF000, 12, 4, 0x74000, 0x74000, 0x74000 }, + { "gcc_blsp1_uart3_apps_clk", 0x96, 4, GCC, + 0x96, 0x1FF, 0, 0xF000, 12, 4, 0x74000, 0x74000, 0x74000 }, + { "gcc_blsp2_ahb_clk", 0xA0, 4, GCC, + 0xA0, 0x1FF, 0, 0xF000, 12, 4, 0x74000, 0x74000, 0x74000 }, + { "gcc_blsp2_qup0_i2c_apps_clk", 0xA2, 4, GCC, + 0xA2, 0x1FF, 0, 0xF000, 12, 4, 0x74000, 0x74000, 0x74000 }, + { "gcc_blsp2_qup0_spi_apps_clk", 0xA3, 4, GCC, + 0xA3, 0x1FF, 0, 0xF000, 12, 4, 0x74000, 0x74000, 0x74000 }, + { "gcc_blsp2_uart0_apps_clk", 0xA4, 4, GCC, + 0xA4, 0x1FF, 0, 0xF000, 12, 4, 0x74000, 0x74000, 0x74000 }, + { "gcc_boot_rom_ahb_clk", 0xF8, 4, GCC, + 0xF8, 0x1FF, 0, 0xF000, 12, 4, 0x74000, 0x74000, 0x74000 }, + { "gcc_dcc_clk", 0x1B9, 4, GCC, + 0x1B9, 0x1FF, 0, 0xF000, 12, 4, 0x74000, 0x74000, 0x74000 }, + { "gcc_eth_axi_clk", 0x80, 4, GCC, + 0x80, 0x1FF, 0, 0xF000, 12, 4, 0x74000, 0x74000, 0x74000 }, + { "gcc_eth_ptp_clk", 0x83, 4, GCC, + 0x83, 0x1FF, 0, 0xF000, 12, 4, 0x74000, 0x74000, 0x74000 }, + { "gcc_eth_rgmii_clk", 0x81, 4, GCC, + 0x81, 0x1FF, 0, 0xF000, 12, 4, 0x74000, 0x74000, 0x74000 }, + { "gcc_eth_slave_ahb_clk", 0x82, 4, GCC, + 0x82, 0x1FF, 0, 0xF000, 12, 4, 0x74000, 0x74000, 0x74000 }, + { "gcc_geni_ir_s_clk", 0xEE, 4, GCC, + 0xEE, 0x1FF, 0, 0xF000, 12, 4, 0x74000, 0x74000, 0x74000 }, + { "gcc_gp1_clk", 0x10, 4, GCC, + 0x10, 0x1FF, 0, 0xF000, 12, 4, 0x74000, 0x74000, 0x74000 }, + { "gcc_gp2_clk", 0x11, 4, GCC, + 0x11, 0x1FF, 0, 0xF000, 12, 4, 0x74000, 0x74000, 0x74000 }, + { "gcc_gp3_clk", 0x12, 4, GCC, + 0x12, 0x1FF, 0, 0xF000, 12, 4, 0x74000, 0x74000, 0x74000 }, + { "gcc_mdss_ahb_clk", 0x1F6, 4, GCC, + 0x1F6, 0x1FF, 0, 0xF000, 12, 4, 0x74000, 0x74000, 0x74000 }, + { "gcc_mdss_axi_clk", 0x1F7, 4, GCC, + 0x1F7, 0x1FF, 0, 0xF000, 12, 4, 0x74000, 0x74000, 0x74000 }, + { "gcc_mdss_byte0_clk", 0x1FC, 4, GCC, + 0x1FC, 0x1FF, 0, 0xF000, 12, 4, 0x74000, 0x74000, 0x74000 }, + { "gcc_mdss_esc0_clk", 0x1FD, 4, GCC, + 0x1FD, 0x1FF, 0, 0xF000, 12, 4, 0x74000, 0x74000, 0x74000 }, + { "gcc_mdss_hdmi_app_clk", 0x1F2, 4, GCC, + 0x1F2, 0x1FF, 0, 0xF000, 12, 4, 0x74000, 0x74000, 0x74000 }, + { "gcc_mdss_hdmi_pclk_clk", 0x1F1, 4, GCC, + 0x1F1, 0x1FF, 0, 0xF000, 12, 4, 0x74000, 0x74000, 0x74000 }, + { "gcc_mdss_mdp_clk", 0x1F9, 4, GCC, + 0x1F9, 0x1FF, 0, 0xF000, 12, 4, 0x74000, 0x74000, 0x74000 }, + { "gcc_mdss_pclk0_clk", 0x1F8, 4, GCC, + 0x1F8, 0x1FF, 0, 0xF000, 12, 4, 0x74000, 0x74000, 0x74000 }, + { "gcc_mdss_vsync_clk", 0x1FB, 4, GCC, + 0x1FB, 0x1FF, 0, 0xF000, 12, 4, 0x74000, 0x74000, 0x74000 }, + { "gcc_oxili_ahb_clk", 0x1EB, 4, GCC, + 0x1EB, 0x1FF, 0, 0xF000, 12, 4, 0x74000, 0x74000, 0x74000 }, + { "gcc_oxili_gfx3d_clk", 0x1EA, 4, GCC, + 0x1EA, 0x1FF, 0, 0xF000, 12, 4, 0x74000, 0x74000, 0x74000 }, + { "gcc_pcie_0_aux_clk", 0xAB, 4, GCC, + 0xAB, 0x1FF, 0, 0xF000, 12, 4, 0x74000, 0x74000, 0x74000 }, + { "gcc_pcie_0_cfg_ahb_clk", 0xAA, 4, GCC, + 0xAA, 0x1FF, 0, 0xF000, 12, 4, 0x74000, 0x74000, 0x74000 }, + { "gcc_pcie_0_mstr_axi_clk", 0xA9, 4, GCC, + 0xA9, 0x1FF, 0, 0xF000, 12, 4, 0x74000, 0x74000, 0x74000 }, + { "gcc_pcie_0_pipe_clk", 0xAC, 4, GCC, + 0xAC, 0x1FF, 0, 0xF000, 12, 4, 0x74000, 0x74000, 0x74000 }, + { "gcc_pcie_0_slv_axi_clk", 0xA8, 4, GCC, + 0xA8, 0x1FF, 0, 0xF000, 12, 4, 0x74000, 0x74000, 0x74000 }, + { "gcc_pcnoc_usb2_clk", 0x9, 4, GCC, + 0x9, 0x1FF, 0, 0xF000, 12, 4, 0x74000, 0x74000, 0x74000 }, + { "gcc_pcnoc_usb3_clk", 0xA, 4, GCC, + 0xA, 0x1FF, 0, 0xF000, 12, 4, 0x74000, 0x74000, 0x74000 }, + { "gcc_pdm2_clk", 0xD2, 4, GCC, + 0xD2, 0x1FF, 0, 0xF000, 12, 4, 0x74000, 0x74000, 0x74000 }, + { "gcc_pdm_ahb_clk", 0xD0, 4, GCC, + 0xD0, 0x1FF, 0, 0xF000, 12, 4, 0x74000, 0x74000, 0x74000 }, + { "gcc_prng_ahb_clk", 0xD8, 4, GCC, + 0xD8, 0x1FF, 0, 0xF000, 12, 4, 0x74000, 0x74000, 0x74000 }, + { "gcc_pwm0_xo512_clk", 0xD3, 4, GCC, + 0xD3, 0x1FF, 0, 0xF000, 12, 4, 0x74000, 0x74000, 0x74000 }, + { "gcc_pwm1_xo512_clk", 0xD4, 4, GCC, + 0xD4, 0x1FF, 0, 0xF000, 12, 4, 0x74000, 0x74000, 0x74000 }, + { "gcc_pwm2_xo512_clk", 0xD5, 4, GCC, + 0xD5, 0x1FF, 0, 0xF000, 12, 4, 0x74000, 0x74000, 0x74000 }, + { "gcc_sdcc1_ahb_clk", 0x69, 4, GCC, + 0x69, 0x1FF, 0, 0xF000, 12, 4, 0x74000, 0x74000, 0x74000 }, + { "gcc_sdcc1_apps_clk", 0x68, 4, GCC, + 0x68, 0x1FF, 0, 0xF000, 12, 4, 0x74000, 0x74000, 0x74000 }, + { "gcc_sdcc1_ice_core_clk", 0x6A, 4, GCC, + 0x6A, 0x1FF, 0, 0xF000, 12, 4, 0x74000, 0x74000, 0x74000 }, + { "gcc_sdcc2_ahb_clk", 0x71, 4, GCC, + 0x71, 0x1FF, 0, 0xF000, 12, 4, 0x74000, 0x74000, 0x74000 }, + { "gcc_sdcc2_apps_clk", 0x70, 4, GCC, + 0x70, 0x1FF, 0, 0xF000, 12, 4, 0x74000, 0x74000, 0x74000 }, + { "gcc_sys_noc_usb3_clk", 0x1, 4, GCC, + 0x1, 0x1FF, 0, 0xF000, 12, 4, 0x74000, 0x74000, 0x74000 }, + { "gcc_usb20_mock_utmi_clk", 0x65, 4, GCC, + 0x65, 0x1FF, 0, 0xF000, 12, 4, 0x74000, 0x74000, 0x74000 }, + { "gcc_usb2a_phy_sleep_clk", 0x63, 4, GCC, + 0x63, 0x1FF, 0, 0xF000, 12, 4, 0x74000, 0x74000, 0x74000 }, + { "gcc_usb30_master_clk", 0x78, 4, GCC, + 0x78, 0x1FF, 0, 0xF000, 12, 4, 0x74000, 0x74000, 0x74000 }, + { "gcc_usb30_mock_utmi_clk", 0x7A, 4, GCC, + 0x7A, 0x1FF, 0, 0xF000, 12, 4, 0x74000, 0x74000, 0x74000 }, + { "gcc_usb30_sleep_clk", 0x79, 4, GCC, + 0x79, 0x1FF, 0, 0xF000, 12, 4, 0x74000, 0x74000, 0x74000 }, + { "gcc_usb3_phy_aux_clk", 0x7C, 4, GCC, + 0x7C, 0x1FF, 0, 0xF000, 12, 4, 0x74000, 0x74000, 0x74000 }, + { "gcc_usb3_phy_pipe_clk", 0x7B, 4, GCC, + 0x7B, 0x1FF, 0, 0xF000, 12, 4, 0x74000, 0x74000, 0x74000 }, + { "gcc_usb_hs_inactivity_timers_clk", 0x62, 4, GCC, + 0x62, 0x1FF, 0, 0xF000, 12, 4, 0x74000, 0x74000, 0x74000 }, + { "gcc_usb_hs_phy_cfg_ahb_clk", 0x64, 4, GCC, + 0x64, 0x1FF, 0, 0xF000, 12, 4, 0x74000, 0x74000, 0x74000 }, + { "gcc_usb_hs_system_clk", 0x60, 4, GCC, + 0x60, 0x1FF, 0, 0xF000, 12, 4, 0x74000, 0x74000, 0x74000 }, + ), + .hw.init = &(struct clk_init_data){ + .name = "gcc_debug_mux", + .ops = &clk_debug_mux_ops, + .parent_names = debug_mux_parent_names, + .num_parents = ARRAY_SIZE(debug_mux_parent_names), + .flags = CLK_IS_MEASURE, + }, +}; + +static const struct of_device_id clk_debug_match_table[] = { + { .compatible = "qcom,debugcc-qcs405" }, + { } +}; + +static int map_debug_bases(struct platform_device *pdev, char *base, int cc) +{ + if (!of_get_property(pdev->dev.of_node, base, NULL)) + return -ENODEV; + + gcc_debug_mux.regmap[cc] = + syscon_regmap_lookup_by_phandle(pdev->dev.of_node, + base); + if (IS_ERR(gcc_debug_mux.regmap[cc])) { + pr_err("Failed to map %s (ret=%ld)\n", base, + PTR_ERR(gcc_debug_mux.regmap[cc])); + return PTR_ERR(gcc_debug_mux.regmap[cc]); + } + return 0; +} + +static int clk_debug_qcs405_probe(struct platform_device *pdev) +{ + struct clk *clk; + int ret = 0; + + clk = devm_clk_get(&pdev->dev, "xo_clk_src"); + if (IS_ERR(clk)) { + if (PTR_ERR(clk) != -EPROBE_DEFER) + dev_err(&pdev->dev, "Unable to get xo clock\n"); + return PTR_ERR(clk); + } + + debug_mux_priv.cxo = clk; + + gcc_debug_mux.regmap = devm_kcalloc(&pdev->dev, MAX_NUM_CC, + sizeof(*gcc_debug_mux.regmap), GFP_KERNEL); + if (!gcc_debug_mux.regmap) + return -ENOMEM; + + ret = map_debug_bases(pdev, "qcom,gcc", GCC); + if (ret) + return ret; + + clk = devm_clk_register(&pdev->dev, &gcc_debug_mux.hw); + if (IS_ERR(clk)) { + dev_err(&pdev->dev, "Unable to register GCC debug mux\n"); + return PTR_ERR(clk); + } + + ret = clk_debug_measure_register(&gcc_debug_mux.hw); + if (ret) + dev_err(&pdev->dev, "Could not register Measure clock\n"); + + return ret; +} + +static struct platform_driver clk_debug_driver = { + .probe = clk_debug_qcs405_probe, + .driver = { + .name = "debugcc-qcs405", + .of_match_table = clk_debug_match_table, + .owner = THIS_MODULE, + }, +}; + +int __init clk_debug_qcs405_init(void) +{ + return platform_driver_register(&clk_debug_driver); +} +fs_initcall(clk_debug_qcs405_init); + +MODULE_DESCRIPTION("QTI DEBUG CC QCS405 Driver"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:debugcc-qcs405"); -- GitLab From 1790d30e860226470044552bd16661aa1179d4a3 Mon Sep 17 00:00:00 2001 From: Maya Erez Date: Sun, 29 Apr 2018 10:19:08 +0300 Subject: [PATCH 1199/1635] wil6210: increase RX status ring size HW can halt in case it has available descriptors but has no RX status messages for storing their completions. Increase RX status ring size in order to prevent such a case. In addition, add a module param to allow changing the count of RX buffer IDs. The count is checked in order to guarantee that it doesn't exceed the RX status ring size. Change-Id: Iea134dc68451816babbd9a40df7a6684bc947468 Signed-off-by: Maya Erez --- drivers/net/wireless/ath/wil6210/txrx_edma.c | 30 ++++++++++++++++---- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/ath/wil6210/txrx_edma.c b/drivers/net/wireless/ath/wil6210/txrx_edma.c index 0600794c2208..dca1589baf6c 100644 --- a/drivers/net/wireless/ath/wil6210/txrx_edma.c +++ b/drivers/net/wireless/ath/wil6210/txrx_edma.c @@ -29,8 +29,10 @@ /* limit status ring size in range [ring size..max ring size] */ #define WIL_SRING_SIZE_ORDER_MIN (WIL_RING_SIZE_ORDER_MIN) #define WIL_SRING_SIZE_ORDER_MAX (WIL_RING_SIZE_ORDER_MAX) -#define WIL_RX_SRING_SIZE_ORDER_DEFAULT (10) +/* RX sring order should be bigger than RX ring order */ +#define WIL_RX_SRING_SIZE_ORDER_DEFAULT (11) #define WIL_TX_SRING_SIZE_ORDER_DEFAULT (12) +#define WIL_RX_BUFF_ARR_SIZE_DEFAULT (1536) #define WIL_EDMA_MAX_DATA_OFFSET (2) bool use_compressed_rx_status = true; @@ -63,16 +65,27 @@ static const struct kernel_param_ops sring_order_ops = { .get = param_get_uint, }; +/* Status ring size should be bigger than the number of RX buffers in order + * to prevent backpressure on the status ring, which may cause HW freeze. + */ static uint rx_status_ring_order = WIL_RX_SRING_SIZE_ORDER_DEFAULT; module_param_cb(rx_status_ring_order, &sring_order_ops, &rx_status_ring_order, 0444); -MODULE_PARM_DESC(rx_status_ring_order, " Rx status ring order; size = 1 << order. Default: 10"); +MODULE_PARM_DESC(rx_status_ring_order, " Rx status ring order; size = 1 << order. Default: 11"); static uint tx_status_ring_order = WIL_TX_SRING_SIZE_ORDER_DEFAULT; module_param_cb(tx_status_ring_order, &sring_order_ops, &tx_status_ring_order, 0444); MODULE_PARM_DESC(tx_status_ring_order, " Tx status ring order; size = 1 << order. Default: 12"); +/* Number of RX buffer IDs should be bigger than the RX descriptor ring size + * as in HW reorder flow, the HW can consume additional buffers before + * releasing the previous ones. + */ +static uint rx_buff_id_count = WIL_RX_BUFF_ARR_SIZE_DEFAULT; +module_param(rx_buff_id_count, uint, 0444); +MODULE_PARM_DESC(rx_buff_id_count, " Rx buffer IDs count: default: 1536"); + static void wil_tx_desc_unmap_edma(struct device *dev, union wil_tx_desc *desc, struct wil_ctx *ctx) @@ -273,8 +286,7 @@ static int wil_rx_refill_edma(struct wil6210_priv *wil) rc = wil_ring_alloc_skb_edma(wil, ring, ring->swhead); if (unlikely(rc)) { if (rc == -EAGAIN) - wil_err_ratelimited(wil, - "No free buffer IDs found\n"); + wil_dbg_txrx(wil, "No free buffer ID found\n"); else wil_err_ratelimited(wil, "Error %d in refill desc[%d]\n", @@ -693,8 +705,16 @@ static int wil_rx_init_edma(struct wil6210_priv *wil, u16 desc_ring_size) if (rc) goto err_free_status; + if (rx_buff_id_count >= status_ring_size) { + wil_info(wil, + "rx_buff_id_count %d exceeds sring_size %d. set it to %d\n", + rx_buff_id_count, status_ring_size, + status_ring_size - 1); + rx_buff_id_count = status_ring_size - 1; + } + /* Allocate Rx buffer array */ - rc = wil_init_rx_buff_arr(wil, desc_ring_size + status_ring_size); + rc = wil_init_rx_buff_arr(wil, rx_buff_id_count); if (rc) goto err_free_desc; -- GitLab From e1d9c5ae0213c86ab3e7ec833525568b9cd835fc Mon Sep 17 00:00:00 2001 From: Kiran Gunda Date: Tue, 10 Apr 2018 18:09:22 +0530 Subject: [PATCH 1200/1635] ARM: dts: msm: Add device nodes for pm640 and pm640l Add the device nodes such as PON, GPIOs, MISC, LCDB, WLED and other PMIC infra and IO modules for pm640 and pm640l. Change-Id: I1902efa518b25abc9d559abda65270cac47674ef Signed-off-by: Kiran Gunda --- arch/arm64/boot/dts/qcom/pm640.dtsi | 110 +++++++++++ arch/arm64/boot/dts/qcom/pm640l.dtsi | 267 +++++++++++++++++++++++++++ arch/arm64/boot/dts/qcom/sdm640.dtsi | 2 + 3 files changed, 379 insertions(+) create mode 100644 arch/arm64/boot/dts/qcom/pm640.dtsi create mode 100644 arch/arm64/boot/dts/qcom/pm640l.dtsi diff --git a/arch/arm64/boot/dts/qcom/pm640.dtsi b/arch/arm64/boot/dts/qcom/pm640.dtsi new file mode 100644 index 000000000000..bd28008c9a6e --- /dev/null +++ b/arch/arm64/boot/dts/qcom/pm640.dtsi @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include + +&spmi_bus { + qcom,pm640@0 { + compatible = "qcom,spmi-pmic"; + reg = <0x0 SPMI_USID>; + #address-cells = <1>; + #size-cells = <1>; + + pm640_revid: qcom,revid@100 { + compatible = "qcom,qpnp-revid"; + reg = <0x100 0x100>; + }; + + qcom,power-on@800 { + compatible = "qcom,qpnp-power-on"; + reg = <0x800 0x100>; + interrupts = <0x0 0x8 0x0 IRQ_TYPE_NONE>, + <0x0 0x8 0x1 IRQ_TYPE_NONE>; + interrupt-names = "kpdpwr", "resin"; + qcom,pon-dbc-delay = <15625>; + qcom,kpdpwr-sw-debounce; + qcom,system-reset; + qcom,store-hard-reset-reason; + + qcom,pon_1 { + qcom,pon-type = ; + qcom,pull-up = <1>; + linux,code = ; + }; + + qcom,pon_2 { + qcom,pon-type = ; + qcom,pull-up = <1>; + linux,code = ; + }; + }; + + pm640_misc: qcom,misc@900 { + compatible = "qcom,qpnp-misc"; + reg = <0x900 0x100>; + }; + + pm640_tz: qcom,temp-alarm@2400 { + compatible = "qcom,spmi-temp-alarm"; + reg = <0x2400 0x100>; + interrupts = <0x0 0x24 0x0 IRQ_TYPE_EDGE_RISING>; + #thermal-sensor-cells = <0>; + qcom,temperature-threshold-set = <1>; + }; + + pm640_clkdiv: clock-controller@5b00 { + compatible = "qcom,spmi-clkdiv"; + reg = <0x5b00 0x100>; + #clock-cells = <1>; + qcom,num-clkdivs = <1>; + clock-output-names = "pm640_div_clk1"; + clocks = <&clock_rpmh RPMH_CXO_CLK>; + clock-names = "xo"; + }; + + pm640_gpios: pinctrl@c000 { + compatible = "qcom,spmi-gpio"; + reg = <0xc000 0xa00>; + interrupts = <0x0 0xc0 0 IRQ_TYPE_NONE>, + <0x0 0xc1 0 IRQ_TYPE_NONE>, + <0x0 0xc2 0 IRQ_TYPE_NONE>, + <0x0 0xc3 0 IRQ_TYPE_NONE>, + <0x0 0xc6 0 IRQ_TYPE_NONE>, + <0x0 0xc7 0 IRQ_TYPE_NONE>; + interrupt-names = "pm640_gpio1", "pm640_gpio2", + "pm640_gpio3", "pm640_gpio4", + "pm640_gpio7", "pm640_gpio8"; + gpio-controller; + #gpio-cells = <2>; + qcom,gpios-disallowed = <5 6 9 10>; + }; + }; + + qcom,pm640@1 { + compatible ="qcom,spmi-pmic"; + reg = <0x1 SPMI_USID>; + #address-cells = <1>; + #size-cells = <1>; + + pm640_vib: qcom,vibrator@5300 { + compatible = "qcom,qpnp-vibrator-ldo"; + reg = <0x5300 0x100>; + qcom,vib-ldo-volt-uv = <3000000>; + qcom,vib-overdrive-volt-uv = <3544000>; + }; + }; +}; + diff --git a/arch/arm64/boot/dts/qcom/pm640l.dtsi b/arch/arm64/boot/dts/qcom/pm640l.dtsi new file mode 100644 index 000000000000..13ff649480bb --- /dev/null +++ b/arch/arm64/boot/dts/qcom/pm640l.dtsi @@ -0,0 +1,267 @@ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include + +&spmi_bus { + qcom,pm640l@4 { + compatible = "qcom,spmi-pmic"; + reg = <0x4 SPMI_USID>; + #address-cells = <1>; + #size-cells = <1>; + + pm640l_revid: qcom,revid@100 { + compatible = "qcom,qpnp-revid"; + reg = <0x100 0x100>; + }; + + qcom,power-on@800 { + compatible = "qcom,qpnp-power-on"; + reg = <0x800 0x100>; + }; + + pm640l_tz: qcom,temp-alarm@2400 { + compatible = "qcom,spmi-temp-alarm"; + reg = <0x2400 0x100>; + interrupts = <0x4 0x24 0x0 IRQ_TYPE_EDGE_RISING>; + #thermal-sensor-cells = <0>; + qcom,temperature-threshold-set = <1>; + }; + + pm640l_clkdiv: clock-controller@5b00 { + compatible = "qcom,spmi-clkdiv"; + reg = <0x5b00 0x100>; + #clock-cells = <1>; + qcom,num-clkdivs = <1>; + clock-output-names = "pm640l_div_clk1"; + clocks = <&clock_rpmh RPMH_CXO_CLK>; + clock-names = "xo"; + }; + + pm640l_gpios: pinctrl@c000 { + compatible = "qcom,spmi-gpio"; + reg = <0xc000 0xc00>; + interrupts = <0x4 0xc0 0 IRQ_TYPE_NONE>, + <0x4 0xc1 0 IRQ_TYPE_NONE>, + <0x4 0xc2 0 IRQ_TYPE_NONE>, + <0x4 0xc3 0 IRQ_TYPE_NONE>, + <0x4 0xc4 0 IRQ_TYPE_NONE>, + <0x4 0xc5 0 IRQ_TYPE_NONE>, + <0x4 0xc7 0 IRQ_TYPE_NONE>, + <0x4 0xc8 0 IRQ_TYPE_NONE>, + <0x4 0xc9 0 IRQ_TYPE_NONE>, + <0x4 0xca 0 IRQ_TYPE_NONE>, + <0x4 0xcb 0 IRQ_TYPE_NONE>; + interrupt-names = "pm640l_gpio1", "pm640l_gpio2", + "pm640l_gpio3", "pm640l_gpio4", + "pm640l_gpio5", "pm640l_gpio6", + "pm640l_gpio8", "pm640l_gpio9", + "pm640l_gpio10", "pm640l_gpio11", + "pm640l_gpio12"; + gpio-controller; + #gpio-cells = <2>; + qcom,gpios-disallowed = <7>; + }; + }; + + qcom,pm640l@5 { + compatible ="qcom,spmi-pmic"; + reg = <0x5 SPMI_USID>; + #address-cells = <1>; + #size-cells = <1>; + + pm640l_lcdb: qcom,lcdb@ec00 { + compatible = "qcom,qpnp-lcdb-regulator"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0xec00 0x100>; + interrupts = <0x5 0xec 0x1 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "sc-irq"; + qcom,pmic-revid = <&pm640l_revid>; + status = "disabled"; + + lcdb_ldo_vreg: ldo { + label = "ldo"; + regulator-name = "lcdb_ldo"; + regulator-min-microvolt = <4000000>; + regulator-max-microvolt = <6000000>; + }; + + lcdb_ncp_vreg: ncp { + label = "ncp"; + regulator-name = "lcdb_ncp"; + regulator-min-microvolt = <4000000>; + regulator-max-microvolt = <6000000>; + }; + }; + + flash_led: qcom,leds@d300 { + compatible = "qcom,qpnp-flash-led-v2"; + status = "okay"; + reg = <0xd300 0x100>; + label = "flash"; + interrupts = <0x5 0xd3 0x0 IRQ_TYPE_EDGE_RISING>, + <0x5 0xd3 0x3 IRQ_TYPE_EDGE_RISING>, + <0x5 0xd3 0x4 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "led-fault-irq", + "all-ramp-down-done-irq", + "all-ramp-up-done-irq"; + qcom,hdrm-auto-mode; + qcom,short-circuit-det; + qcom,open-circuit-det; + qcom,vph-droop-det; + qcom,thermal-derate-en; + qcom,thermal-derate-current = <200 500 1000>; + qcom,isc-delay = <192>; + qcom,pmic-revid = <&pm640l_revid>; + + pm640l_flash0: qcom,flash_0 { + label = "flash"; + qcom,led-name = "led:flash_0"; + qcom,max-current = <1500>; + qcom,default-led-trigger = "flash0_trigger"; + qcom,id = <0>; + qcom,current-ma = <1000>; + qcom,duration-ms = <1280>; + qcom,ires-ua = <12500>; + qcom,hdrm-voltage-mv = <325>; + qcom,hdrm-vol-hi-lo-win-mv = <100>; + }; + + pm640l_flash1: qcom,flash_1 { + label = "flash"; + qcom,led-name = "led:flash_1"; + qcom,max-current = <1500>; + qcom,default-led-trigger = "flash1_trigger"; + qcom,id = <1>; + qcom,current-ma = <1000>; + qcom,duration-ms = <1280>; + qcom,ires-ua = <12500>; + qcom,hdrm-voltage-mv = <325>; + qcom,hdrm-vol-hi-lo-win-mv = <100>; + }; + + pm640l_flash2: qcom,flash_2 { + label = "flash"; + qcom,led-name = "led:flash_2"; + qcom,max-current = <750>; + qcom,default-led-trigger = "flash2_trigger"; + qcom,id = <2>; + qcom,current-ma = <500>; + qcom,duration-ms = <1280>; + qcom,ires-ua = <12500>; + qcom,hdrm-voltage-mv = <325>; + qcom,hdrm-vol-hi-lo-win-mv = <100>; + status = "disabled"; + }; + + pm640l_torch0: qcom,torch_0 { + label = "torch"; + qcom,led-name = "led:torch_0"; + qcom,max-current = <500>; + qcom,default-led-trigger = "torch0_trigger"; + qcom,id = <0>; + qcom,current-ma = <300>; + qcom,ires-ua = <12500>; + qcom,hdrm-voltage-mv = <325>; + qcom,hdrm-vol-hi-lo-win-mv = <100>; + }; + + pm640l_torch1: qcom,torch_1 { + label = "torch"; + qcom,led-name = "led:torch_1"; + qcom,max-current = <500>; + qcom,default-led-trigger = "torch1_trigger"; + qcom,id = <1>; + qcom,current-ma = <300>; + qcom,ires-ua = <12500>; + qcom,hdrm-voltage-mv = <325>; + qcom,hdrm-vol-hi-lo-win-mv = <100>; + }; + + pm640l_torch2: qcom,torch_2 { + label = "torch"; + qcom,led-name = "led:torch_2"; + qcom,max-current = <500>; + qcom,default-led-trigger = "torch2_trigger"; + qcom,id = <2>; + qcom,current-ma = <300>; + qcom,ires-ua = <12500>; + qcom,hdrm-voltage-mv = <325>; + qcom,hdrm-vol-hi-lo-win-mv = <100>; + status = "disabled"; + }; + + pm640l_switch0: qcom,led_switch_0 { + label = "switch"; + qcom,led-name = "led:switch_0"; + qcom,led-mask = <1>; + qcom,default-led-trigger = "switch0_trigger"; + }; + + pm640l_switch1: qcom,led_switch_1 { + label = "switch"; + qcom,led-name = "led:switch_1"; + qcom,led-mask = <2>; + qcom,default-led-trigger = "switch1_trigger"; + }; + + pm640l_switch2: qcom,led_switch_2 { + label = "switch"; + qcom,led-name = "led:switch_2"; + qcom,led-mask = <3>; + qcom,default-led-trigger = "switch2_trigger"; + }; + }; + + pm640l_wled: qcom,wled@d800 { + compatible = "qcom,pm640l-spmi-wled"; + reg = <0xd800 0x100>, <0xd900 0x100>; + reg-names = "wled-ctrl-base", "wled-sink-base"; + label = "backlight"; + interrupts = <0x5 0xd8 0x1 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "ovp-irq"; + qcom,pmic-revid = <&pm640l_revid>; + qcom,auto-calibration; + status = "disabled"; + }; + + pm640l_lpg: qcom,pwms@b100 { + compatible = "qcom,pwm-lpg"; + reg = <0xb100 0x300>; + reg-names = "lpg-base"; + #pwm-cells = <2>; + }; + + pm640l_rgb_led: qcom,leds@d000 { + compatible = "qcom,tri-led"; + reg = <0xd000 0x100>; + red { + label = "red"; + pwms = <&pm640l_lpg 0 1000000>; + led-sources = <0>; + }; + green { + label = "green"; + pwms = <&pm640l_lpg 1 1000000>; + led-sources = <1>; + }; + blue { + label = "blue"; + pwms = <&pm640l_lpg 2 1000000>; + led-sources = <2>; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm640.dtsi b/arch/arm64/boot/dts/qcom/sdm640.dtsi index 70f8f4c721ff..f7c3eaa9f44d 100644 --- a/arch/arm64/boot/dts/qcom/sdm640.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm640.dtsi @@ -1001,6 +1001,8 @@ }; }; +#include "pm640.dtsi" +#include "pm640l.dtsi" #include "sdm640-pinctrl.dtsi" #include "sdm640-stub-regulator.dtsi" #include "sdm640-pm.dtsi" -- GitLab From 5e5be2ccf1c68201f42ba6105621f53b9e593206 Mon Sep 17 00:00:00 2001 From: Mohammed Javid Date: Tue, 3 Apr 2018 17:15:49 +0530 Subject: [PATCH 1201/1635] arm: msm: ipa: Add support to get MHI config dynamically Add support to get platform info with respect to MHI dynamically for sdx20. Change-Id: Ie38df2d3bbe80856a0b7cd49511ce64cb9aa4ce8 Signed-off-by: Mohammed Javid --- Documentation/devicetree/bindings/platform/msm/ipa.txt | 2 ++ drivers/platform/msm/ipa/ipa_v3/ipa.c | 9 +++++++++ drivers/platform/msm/ipa/ipa_v3/ipa_i.h | 1 + 3 files changed, 12 insertions(+) diff --git a/Documentation/devicetree/bindings/platform/msm/ipa.txt b/Documentation/devicetree/bindings/platform/msm/ipa.txt index 7a3f3fd2642d..ac31663c9d99 100644 --- a/Documentation/devicetree/bindings/platform/msm/ipa.txt +++ b/Documentation/devicetree/bindings/platform/msm/ipa.txt @@ -37,6 +37,8 @@ Optional: compatible "qcom,ipa-smmu-uc-cb" - qcom,use-a2-service: determine if A2 service will be used - qcom,use-ipa-tethering-bridge: determine if tethering bridge will be used +- qcom,use-ipa-in-mhi-mode: Boolean context flag to indicate whether + device booting in MHI config or not. - qcom,use-ipa-bamdma-a2-bridge: determine if a2/ipa hw bridge will be used - qcom,ee: which EE is assigned to (non-secure) APPS from IPA-BAM POV. This is a number diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa.c b/drivers/platform/msm/ipa/ipa_v3/ipa.c index 7dafcbfb88d5..839067cf9250 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa.c @@ -4983,6 +4983,7 @@ static int ipa3_pre_init(const struct ipa3_plat_drv_res *resource_p, ipa3_ctx->gsi_ch20_wa = resource_p->gsi_ch20_wa; ipa3_ctx->use_ipa_pm = resource_p->use_ipa_pm; ipa3_ctx->ipa3_active_clients_logging.log_rdy = false; + ipa3_ctx->ipa_config_is_mhi = resource_p->ipa_mhi_dynamic_config; ipa3_ctx->mhi_evid_limits[0] = resource_p->mhi_evid_limits[0]; ipa3_ctx->mhi_evid_limits[1] = resource_p->mhi_evid_limits[1]; @@ -5510,6 +5511,7 @@ static int get_ipa_dts_configuration(struct platform_device *pdev, ipa_drv_res->ipa3_hw_mode = 0; ipa_drv_res->modem_cfg_emb_pipe_flt = false; ipa_drv_res->ipa_wdi2 = false; + ipa_drv_res->ipa_mhi_dynamic_config = false; ipa_drv_res->use_64_bit_dma_mask = false; ipa_drv_res->use_bw_vote = false; ipa_drv_res->wan_rx_ring_size = IPA_GENERIC_RX_POOL_SZ; @@ -5572,6 +5574,13 @@ static int get_ipa_dts_configuration(struct platform_device *pdev, ipa_drv_res->use_ipa_teth_bridge ? "True" : "False"); + ipa_drv_res->ipa_mhi_dynamic_config = + of_property_read_bool(pdev->dev.of_node, + "qcom,use-ipa-in-mhi-mode"); + IPADBG(": ipa_mhi_dynamic_config (%s)\n", + ipa_drv_res->ipa_mhi_dynamic_config + ? "True" : "False"); + ipa_drv_res->modem_cfg_emb_pipe_flt = of_property_read_bool(pdev->dev.of_node, "qcom,modem-cfg-emb-pipe-flt"); diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h index c492c37912e1..eb942cea65c3 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h @@ -1437,6 +1437,7 @@ struct ipa3_plat_drv_res { bool gsi_ch20_wa; bool tethered_flow_control; u32 mhi_evid_limits[2]; /* start and end values */ + bool ipa_mhi_dynamic_config; u32 ipa_tz_unlock_reg_num; struct ipa_tz_unlock_reg_info *ipa_tz_unlock_reg; bool use_ipa_pm; -- GitLab From 7da443c5dd34880eb6af6c4f6c57b896ece7de2e Mon Sep 17 00:00:00 2001 From: Ramakrishnan Ganesh Date: Fri, 30 Mar 2018 12:13:05 -0700 Subject: [PATCH 1202/1635] rpmh_master_stat: Adjust accumulated sleep duration Adjust the accumulated sleep duration to show more accurate sleep times for masters in low power mode. Change-Id: I83b549775da70b6cf33aa3859ae894d9d73925eb Signed-off-by: Ramakrishnan Ganesh --- drivers/soc/qcom/rpmh_master_stat.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/drivers/soc/qcom/rpmh_master_stat.c b/drivers/soc/qcom/rpmh_master_stat.c index 615464fd260f..283e367cf439 100644 --- a/drivers/soc/qcom/rpmh_master_stat.c +++ b/drivers/soc/qcom/rpmh_master_stat.c @@ -24,6 +24,7 @@ #include #include #include +#include #include "rpmh_master_stat.h" #define UNIT_DIST 0x14 @@ -102,6 +103,18 @@ static ssize_t msm_rpmh_master_stats_print_data(char *prvbuf, ssize_t length, struct msm_rpmh_master_stats *record, const char *name) { + uint64_t accumulated_duration = record->accumulated_duration; + /* + * If a master is in sleep when reading the sleep stats from SMEM + * adjust the accumulated sleep duration to show actual sleep time. + * This ensures that the displayed stats are real when used for + * the purpose of computing battery utilization. + */ + if (record->last_entered > record->last_exited) + accumulated_duration += + (arch_counter_get_cntvct() + - record->last_entered); + return snprintf(prvbuf, length, "%s\n\tVersion:0x%x\n" "\tSleep Count:0x%x\n" "\tSleep Last Entered At:0x%llx\n" @@ -109,7 +122,7 @@ static ssize_t msm_rpmh_master_stats_print_data(char *prvbuf, ssize_t length, "\tSleep Accumulated Duration:0x%llx\n\n", name, record->version_id, record->counts, record->last_entered, record->last_exited, - record->accumulated_duration); + accumulated_duration); } static ssize_t msm_rpmh_master_stats_show(struct kobject *kobj, @@ -129,7 +142,7 @@ static ssize_t msm_rpmh_master_stats_show(struct kobject *kobj, /* Read SMEM data written by other masters */ - for (i = 0, length = 0; i < ARRAY_SIZE(rpmh_masters); i++) { + for (i = 0; i < ARRAY_SIZE(rpmh_masters); i++) { record = (struct msm_rpmh_master_stats *) qcom_smem_get( rpmh_masters[i].pid, rpmh_masters[i].smem_id, &size); -- GitLab From c6fa242a9ff60b8acfdba1c5f09f11bef2355ef3 Mon Sep 17 00:00:00 2001 From: Ashay Jaiswal Date: Thu, 12 Apr 2018 18:11:00 +0530 Subject: [PATCH 1203/1635] power: smb5: add support to configure JEITA threshold Add support to read JEITA hard/soft ADC code from battery profile and configure charger hardware. Change-Id: Ic515e6f62316695f9fc228ba87be47937d418d84 Signed-off-by: Ashay Jaiswal --- .../bindings/batterydata/batterydata.txt | 8 ++ .../bindings/power/supply/qcom/qpnp-smb5.txt | 5 +- drivers/power/supply/qcom/smb5-lib.c | 100 ++++++++++++++++++ drivers/power/supply/qcom/smb5-lib.h | 2 + drivers/power/supply/qcom/smb5-reg.h | 1 + 5 files changed, 112 insertions(+), 4 deletions(-) diff --git a/Documentation/devicetree/bindings/batterydata/batterydata.txt b/Documentation/devicetree/bindings/batterydata/batterydata.txt index 59113c39145e..9d80eb9d1859 100644 --- a/Documentation/devicetree/bindings/batterydata/batterydata.txt +++ b/Documentation/devicetree/bindings/batterydata/batterydata.txt @@ -106,6 +106,12 @@ Profile data node optional properties: the low and high thresholds. The threshold values in range should be in ascending and shouldn't overlap. It support 8 ranges at max. +- qcom,jeita-soft-thresholds: A tuple entry to specify ADC code for battery's soft JEITA + threshold. + . +- qcom,jeita-hard-thresholds: A tuple entry to specify ADC code for battery's hard JEITA + threshold. + . Profile data node required subnodes: - qcom,fcc-temp-lut : An 1-dimensional lookup table node that encodes @@ -170,6 +176,8 @@ qcom,palladium-batterydata { qcom,v-cutoff-uv = <3400000>; qcom,chg-term-ua = <100000>; qcom,batt-id-kohm = <75>; + qcom,jeita-soft-thresholds = <0x3ecc 0x1bff>; + qcom,jeita-hard-thresholds = <0x4aff 0x15aa>; qcom,step-chg-ranges = <3600000 4000000 3000000 4001000 4200000 2800000 4201000 4400000 2000000>; diff --git a/Documentation/devicetree/bindings/power/supply/qcom/qpnp-smb5.txt b/Documentation/devicetree/bindings/power/supply/qcom/qpnp-smb5.txt index 954e729fa205..e79863279792 100644 --- a/Documentation/devicetree/bindings/power/supply/qcom/qpnp-smb5.txt +++ b/Documentation/devicetree/bindings/power/supply/qcom/qpnp-smb5.txt @@ -174,10 +174,7 @@ Charger specific properties: Usage: optional Value type: Definition: Specifies the phandle of the node which contains the battery - profiles supported on the device. This is only specified - when step charging and sw-jeita configurations are desired - to be get from these properties defined in battery profile: - qcom,step-chg-ranges, qcom,jeita-fcc-ranges, qcom,jeita-fv-ranges. + profiles supported on the device. - qcom,flash-derating-soc Usage: optional diff --git a/drivers/power/supply/qcom/smb5-lib.c b/drivers/power/supply/qcom/smb5-lib.c index 3c6730626a48..ae9d4c623bd8 100644 --- a/drivers/power/supply/qcom/smb5-lib.c +++ b/drivers/power/supply/qcom/smb5-lib.c @@ -19,6 +19,7 @@ #include #include #include +#include #include "smb5-lib.h" #include "smb5-reg.h" #include "battery.h" @@ -597,6 +598,8 @@ static int smblib_notifier_call(struct notifier_block *nb, chg->bms_psy = psy; if (ev == PSY_EVENT_PROP_CHANGED) schedule_work(&chg->bms_update_work); + if (!chg->jeita_configured) + schedule_work(&chg->jeita_update_work); } if (!chg->pl.psy && !strcmp(psy->desc->name, "parallel")) { @@ -3542,6 +3545,100 @@ static void smblib_pl_enable_work(struct work_struct *work) vote(chg->awake_votable, PL_DELAY_VOTER, false, 0); } +#define JEITA_SOFT 0 +#define JEITA_HARD 1 +static int smblib_update_jeita(struct smb_charger *chg, u32 *thresholds, + int type) +{ + int rc; + u16 temp, base; + + base = CHGR_JEITA_THRESHOLD_BASE_REG(type); + + temp = thresholds[1] & 0xFFFF; + temp = ((temp & 0xFF00) >> 8) | ((temp & 0xFF) << 8); + rc = smblib_batch_write(chg, base, (u8 *)&temp, 2); + if (rc < 0) { + smblib_err(chg, + "Couldn't configure Jeita %s hot threshold rc=%d\n", + (type == JEITA_SOFT) ? "Soft" : "Hard", rc); + return rc; + } + + temp = thresholds[0] & 0xFFFF; + temp = ((temp & 0xFF00) >> 8) | ((temp & 0xFF) << 8); + rc = smblib_batch_write(chg, base + 2, (u8 *)&temp, 2); + if (rc < 0) { + smblib_err(chg, + "Couldn't configure Jeita %s cold threshold rc=%d\n", + (type == JEITA_SOFT) ? "Soft" : "Hard", rc); + return rc; + } + + smblib_dbg(chg, PR_MISC, "%s Jeita threshold configured\n", + (type == JEITA_SOFT) ? "Soft" : "Hard"); + + return 0; +} + +static void jeita_update_work(struct work_struct *work) +{ + struct smb_charger *chg = container_of(work, struct smb_charger, + jeita_update_work); + struct device_node *node = chg->dev->of_node; + struct device_node *batt_node, *pnode; + union power_supply_propval val; + int rc; + u32 jeita_thresholds[2]; + + batt_node = of_find_node_by_name(node, "qcom,battery-data"); + if (!batt_node) { + smblib_err(chg, "Batterydata not available\n"); + goto out; + } + + rc = power_supply_get_property(chg->bms_psy, + POWER_SUPPLY_PROP_RESISTANCE_ID, &val); + if (rc < 0) { + smblib_err(chg, "Failed to get batt-id rc=%d\n", rc); + goto out; + } + + pnode = of_batterydata_get_best_profile(batt_node, + val.intval / 1000, NULL); + if (IS_ERR(pnode)) { + rc = PTR_ERR(pnode); + smblib_err(chg, "Failed to detect valid battery profile %d\n", + rc); + goto out; + } + + rc = of_property_read_u32_array(pnode, "qcom,jeita-hard-thresholds", + jeita_thresholds, 2); + if (!rc) { + rc = smblib_update_jeita(chg, jeita_thresholds, JEITA_HARD); + if (rc < 0) { + smblib_err(chg, "Couldn't configure Hard Jeita rc=%d\n", + rc); + goto out; + } + } + + rc = of_property_read_u32_array(pnode, "qcom,jeita-soft-thresholds", + jeita_thresholds, 2); + if (!rc) { + rc = smblib_update_jeita(chg, jeita_thresholds, JEITA_SOFT); + if (rc < 0) { + smblib_err(chg, "Couldn't configure Soft Jeita rc=%d\n", + rc); + goto out; + } + } + +out: + chg->jeita_configured = true; +} + static int smblib_create_votables(struct smb_charger *chg) { int rc = 0; @@ -3654,6 +3751,7 @@ int smblib_init(struct smb_charger *chg) mutex_init(&chg->lock); INIT_WORK(&chg->bms_update_work, bms_update_work); INIT_WORK(&chg->pl_update_work, pl_update_work); + INIT_WORK(&chg->jeita_update_work, jeita_update_work); INIT_DELAYED_WORK(&chg->clear_hdc_work, clear_hdc_work); INIT_DELAYED_WORK(&chg->icl_change_work, smblib_icl_change_work); INIT_DELAYED_WORK(&chg->pl_enable_work, smblib_pl_enable_work); @@ -3663,6 +3761,7 @@ int smblib_init(struct smb_charger *chg) chg->fake_input_current_limited = -EINVAL; chg->fake_batt_status = -EINVAL; chg->sink_src_mode = UNATTACHED_MODE; + chg->jeita_configured = false; switch (chg->mode) { case PARALLEL_MASTER: @@ -3720,6 +3819,7 @@ int smblib_deinit(struct smb_charger *chg) switch (chg->mode) { case PARALLEL_MASTER: cancel_work_sync(&chg->bms_update_work); + cancel_work_sync(&chg->jeita_update_work); cancel_work_sync(&chg->pl_update_work); cancel_delayed_work_sync(&chg->clear_hdc_work); cancel_delayed_work_sync(&chg->icl_change_work); diff --git a/drivers/power/supply/qcom/smb5-lib.h b/drivers/power/supply/qcom/smb5-lib.h index cafd34cc83e7..29e067000349 100644 --- a/drivers/power/supply/qcom/smb5-lib.h +++ b/drivers/power/supply/qcom/smb5-lib.h @@ -305,6 +305,7 @@ struct smb_charger { /* work */ struct work_struct bms_update_work; struct work_struct pl_update_work; + struct work_struct jeita_update_work; struct delayed_work ps_change_timeout_work; struct delayed_work clear_hdc_work; struct delayed_work icl_change_work; @@ -352,6 +353,7 @@ struct smb_charger { int hw_max_icl_ua; int auto_recharge_soc; enum sink_src_mode sink_src_mode; + bool jeita_configured; /* workaround flag */ u32 wa_flags; diff --git a/drivers/power/supply/qcom/smb5-reg.h b/drivers/power/supply/qcom/smb5-reg.h index 83cef8aa0bfc..035e8c0774d3 100644 --- a/drivers/power/supply/qcom/smb5-reg.h +++ b/drivers/power/supply/qcom/smb5-reg.h @@ -101,6 +101,7 @@ enum { #define JEITA_CCCOMP_CFG_HOT_REG (CHGR_BASE + 0x92) #define JEITA_CCCOMP_CFG_COLD_REG (CHGR_BASE + 0x93) +#define CHGR_JEITA_THRESHOLD_BASE_REG(i) (CHGR_BASE + 0x94 + (i * 4)) /******************************** * DCDC Peripheral Registers * ********************************/ -- GitLab From 7804efaf9d1244419c924099efdab56e3a740080 Mon Sep 17 00:00:00 2001 From: Vijayanand Jitta Date: Thu, 26 Apr 2018 09:59:31 +0530 Subject: [PATCH 1204/1635] ARM: dts: msm: Update to Memory map v5 for sdm640 Add SecData carveout region, smem carveout region and align aop region to memory map for sdm640. Change-Id: Id8dc0ccecfa59868e74ec1c6155477cc06fa0cf8 Signed-off-by: Vijayanand Jitta --- arch/arm64/boot/dts/qcom/sdm640.dtsi | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sdm640.dtsi b/arch/arm64/boot/dts/qcom/sdm640.dtsi index 70f8f4c721ff..24c85441c98e 100644 --- a/arch/arm64/boot/dts/qcom/sdm640.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm640.dtsi @@ -340,16 +340,28 @@ reg = <0 0x85700000 0 0x600000>; }; - xbl_region: xbl_region@85e00000 { + xbl_aop_mem: xbl_aop_mem@85e00000 { compatible = "removed-dma-pool"; no-map; - reg = <0 0x85e00000 0 0x100000>; + reg = <0x0 0x85e00000 0x0 0x1ff000>; }; - removed_region: removed_region@85fc0000 { + sec_apps_mem: sec_apps_region@85fff000 { compatible = "removed-dma-pool"; no-map; - reg = <0 0x85fc0000 0 0x2f40000>; + reg = <0x0 0x85fff000 0x0 0x1000>; + }; + + smem_region: smem@86000000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0x86000000 0x0 0x200000>; + }; + + removed_region: removed_region@86200000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0 0x86200000 0 0x2d00000>; }; pil_camera_mem: camera_region@8ab00000 { -- GitLab From 07b566961c967d176aef350aa2ee6eb3d6deb919 Mon Sep 17 00:00:00 2001 From: Lingutla Chandrasekhar Date: Tue, 24 Apr 2018 19:31:30 +0530 Subject: [PATCH 1205/1635] sched: Use proper conditional flags to fix 32 bit compile failures Fix 32-bit compilation issues by using proper conditional checks for preempt and irqsoff trace event threshold variables. Change-Id: I2b67cf6c33890e5373e69091c4812bec9302dee5 Signed-off-by: Lingutla Chandrasekhar --- include/linux/sched/sysctl.h | 6 +++--- kernel/sched/core.c | 11 +++++------ kernel/sysctl.c | 5 +++-- kernel/trace/trace_irqsoff.c | 12 ++++++------ 4 files changed, 17 insertions(+), 17 deletions(-) diff --git a/include/linux/sched/sysctl.h b/include/linux/sched/sysctl.h index de569df2bfa8..2df98acfeb5a 100644 --- a/include/linux/sched/sysctl.h +++ b/include/linux/sched/sysctl.h @@ -48,11 +48,11 @@ walt_proc_update_handler(struct ctl_table *table, int write, #endif -#if defined(CONFIG_DEBUG_PREEMPT) || defined(CONFIG_PREEMPT_TRACER) || \ - defined(CONFIG_PREEMPTIRQ_EVENTS) +#if defined(CONFIG_PREEMPT_TRACER) || defined(CONFIG_DEBUG_PREEMPT) extern unsigned int sysctl_preemptoff_tracing_threshold_ns; +#endif +#if defined(CONFIG_PREEMPTIRQ_EVENTS) && defined(CONFIG_IRQSOFF_TRACER) extern unsigned int sysctl_irqsoff_tracing_threshold_ns; - #endif enum sched_tunable_scaling { diff --git a/kernel/sched/core.c b/kernel/sched/core.c index 51ec8efad437..4df40a9a6c3f 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -89,12 +89,6 @@ int sysctl_sched_rt_runtime = 950000; /* CPUs with isolated domains */ cpumask_var_t cpu_isolated_map; -/* - * preemptoff stack tracing threshold in ns. - * default: 1ms - */ -unsigned int sysctl_preemptoff_tracing_threshold_ns = 1000000UL; - /* * __task_rq_lock - lock the rq @p resides on. */ @@ -3206,6 +3200,11 @@ u64 scheduler_tick_max_deferment(void) #if defined(CONFIG_PREEMPT) && (defined(CONFIG_DEBUG_PREEMPT) || \ defined(CONFIG_PREEMPT_TRACER)) +/* + * preemptoff stack tracing threshold in ns. + * default: 1ms + */ +unsigned int sysctl_preemptoff_tracing_threshold_ns = 1000000UL; struct preempt_store { u64 ts; diff --git a/kernel/sysctl.c b/kernel/sysctl.c index b5704bf594e1..3de374052b96 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -310,8 +310,7 @@ static struct ctl_table kern_table[] = { .mode = 0644, .proc_handler = proc_dointvec, }, -#if defined(CONFIG_DEBUG_PREEMPT) || defined(CONFIG_PREEMPT_TRACER) || \ - defined(CONFIG_PREEMPTIRQ_EVENTS) +#if defined(CONFIG_PREEMPT_TRACER) || defined(CONFIG_DEBUG_PREEMPT) { .procname = "preemptoff_tracing_threshold_ns", .data = &sysctl_preemptoff_tracing_threshold_ns, @@ -319,6 +318,8 @@ static struct ctl_table kern_table[] = { .mode = 0644, .proc_handler = proc_dointvec, }, +#endif +#if defined(CONFIG_IRQSOFF_TRACER) && defined(CONFIG_PREEMPTIRQ_EVENTS) { .procname = "irqsoff_tracing_threshold_ns", .data = &sysctl_irqsoff_tracing_threshold_ns, diff --git a/kernel/trace/trace_irqsoff.c b/kernel/trace/trace_irqsoff.c index 85b14eb4c0a6..dff44f617e9b 100644 --- a/kernel/trace/trace_irqsoff.c +++ b/kernel/trace/trace_irqsoff.c @@ -41,12 +41,6 @@ static int save_flags; static void stop_irqsoff_tracer(struct trace_array *tr, int graph); static int start_irqsoff_tracer(struct trace_array *tr, int graph); -/* - * irqsoff stack tracing threshold in ns. - * default: 1ms - */ -unsigned int sysctl_irqsoff_tracing_threshold_ns = 1000000UL; - #ifdef CONFIG_PREEMPT_TRACER static inline int preempt_trace(void) @@ -475,6 +469,12 @@ void time_hardirqs_off(unsigned long a0, unsigned long a1) #else /* !CONFIG_PROVE_LOCKING */ #ifdef CONFIG_PREEMPTIRQ_EVENTS +/* + * irqsoff stack tracing threshold in ns. + * default: 1ms + */ +unsigned int sysctl_irqsoff_tracing_threshold_ns = 1000000UL; + struct irqsoff_store { u64 ts; unsigned long caddr[4]; -- GitLab From 9c5c9e75810a87d95137630bb3bcf686bada5a4a Mon Sep 17 00:00:00 2001 From: "Bao D. Nguyen" Date: Fri, 13 Apr 2018 13:20:21 -0700 Subject: [PATCH 1206/1635] ARM: dts: msm: Enable UFS Device for SM8150 Enable UFS as primary storage device for SM8150 platforms. Change-Id: I91d30b6d7befde84bc26630b8e3364613c7c4bb2 Signed-off-by: Bao D. Nguyen --- arch/arm64/boot/dts/qcom/sm8150-cdp.dtsi | 4 ++++ arch/arm64/boot/dts/qcom/sm8150-mtp.dtsi | 4 ++++ arch/arm64/boot/dts/qcom/sm8150-qrd.dtsi | 4 ++++ 3 files changed, 12 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sm8150-cdp.dtsi b/arch/arm64/boot/dts/qcom/sm8150-cdp.dtsi index 570f3a6d8137..09c61e89742e 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-cdp.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-cdp.dtsi @@ -232,6 +232,8 @@ vdda-pll-supply = <&pm855l_l3>; vdda-phy-max-microamp = <90200>; vdda-pll-max-microamp = <19000>; + + status = "ok"; }; &ufshc_mem { @@ -245,6 +247,8 @@ qcom,vddp-ref-clk-supply = <&pm855_l9>; qcom,vddp-ref-clk-max-microamp = <100>; + + status = "ok"; }; &sdhc_2 { diff --git a/arch/arm64/boot/dts/qcom/sm8150-mtp.dtsi b/arch/arm64/boot/dts/qcom/sm8150-mtp.dtsi index 3607f5a38a32..b459873e4d45 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-mtp.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-mtp.dtsi @@ -236,6 +236,8 @@ vdda-pll-supply = <&pm855l_l3>; vdda-phy-max-microamp = <90200>; vdda-pll-max-microamp = <19000>; + + status = "ok"; }; &ufshc_mem { @@ -249,6 +251,8 @@ qcom,vddp-ref-clk-supply = <&pm855_l9>; qcom,vddp-ref-clk-max-microamp = <100>; + + status = "ok"; }; &pm855l_wled { diff --git a/arch/arm64/boot/dts/qcom/sm8150-qrd.dtsi b/arch/arm64/boot/dts/qcom/sm8150-qrd.dtsi index cf63ff6565ec..6f91f21c8ffa 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-qrd.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-qrd.dtsi @@ -228,6 +228,8 @@ vdda-pll-supply = <&pm855l_l3>; vdda-phy-max-microamp = <90200>; vdda-pll-max-microamp = <19000>; + + status = "ok"; }; &ufshc_mem { @@ -241,6 +243,8 @@ qcom,vddp-ref-clk-supply = <&pm855_l9>; qcom,vddp-ref-clk-max-microamp = <100>; + + status = "ok"; }; &sdhc_2 { -- GitLab From 1383baade45365e2a294d1ef18ff797e58cc0394 Mon Sep 17 00:00:00 2001 From: Rohit Gupta Date: Tue, 24 Apr 2018 10:14:09 -0700 Subject: [PATCH 1207/1635] PM / devfreq: devbw: Switch to OPP APIs OPP framework exposes a set of functions that could be used to fetch the list of supported bandwidth values from DT and to query the list for an appropriate value while honoring requests from governors/clients. Use OPP table APIs and get rid of frequency table logic to make the code more concise and upstream friendly. Change-Id: I120ae7230bdbfaaa9523263c65a8b84470583071 Signed-off-by: Rohit Gupta --- .../devicetree/bindings/devfreq/devbw.txt | 47 ++++++++++----- drivers/devfreq/devfreq_devbw.c | 57 ++++--------------- 2 files changed, 43 insertions(+), 61 deletions(-) diff --git a/Documentation/devicetree/bindings/devfreq/devbw.txt b/Documentation/devicetree/bindings/devfreq/devbw.txt index ece0fa761e83..217e46e35fa4 100644 --- a/Documentation/devicetree/bindings/devfreq/devbw.txt +++ b/Documentation/devicetree/bindings/devfreq/devbw.txt @@ -9,11 +9,11 @@ Required properties: - compatible: Must be "qcom,devbw" - qcom,src-dst-ports: A list of tuples where each tuple consists of a bus master port number and a bus slave port number. -- qcom,bw-tbl: A list of meaningful instantaneous bandwidth values - (in MB/s) that can be requested from the device - master port to the slave port. The list of values - depend on the supported bus/slave frequencies and the - bus width. +- operating-points-v2: A phandle to the OPP v2 table that holds meaningful + instantaneous bandwidth values (in MB/s) that can be + requested from the device master port to the slave port. + The list of values depend on the supported bus/slave + frequencies and the bus width. Optional properties: - qcom,active-only: Indicates that the bandwidth votes need to be @@ -23,17 +23,36 @@ Optional properties: Example: + bw_opp_table: bw-opp-table { + compatible = "operating-points-v2"; + opp-75 { + opp-hz = /bits/ 64 < 572 >; /* 75 MHz */ + }; + opp-150 { + opp-hz = /bits/ 64 < 1144 >; /* 150 MHz */ + }; + opp-200 { + opp-hz = /bits/ 64 < 1525 >; /* 200 MHz */ + }; + opp-307 { + opp-hz = /bits/ 64 < 2342 >; /* 307 MHz */ + }; + opp-460 { + opp-hz = /bits/ 64 < 3509 >; /* 460 MHz */ + }; + opp-614 { + opp-hz = /bits/ 64 < 4684 >; /* 614 MHz */ + }; + opp-800 { + opp-hz = /bits/ 64 < 6103 >; /* 800 MHz */ + }; + opp-931 { + opp-hz = /bits/ 64 < 7102 >; /* 931 MHz */ + }; + }; qcom,cpubw { compatible = "qcom,devbw"; qcom,src-dst-ports = <1 512>, <2 512>; qcom,active-only; - qcom,bw-tbl = - < 572 /* 75 MHz */ >, - < 1144 /* 150 MHz */ >, - < 1525 /* 200 MHz */ >, - < 2342 /* 307 MHz */ >, - < 3509 /* 460 MHz */ >, - < 4684 /* 614 MHz */ >, - < 6103 /* 800 MHz */ >, - < 7102 /* 931 MHz */ >; + operating-points-v2 = <&bw_opp_table>; }; diff --git a/drivers/devfreq/devfreq_devbw.c b/drivers/devfreq/devfreq_devbw.c index 5c7959c23ad2..b17f4e21962e 100644 --- a/drivers/devfreq/devfreq_devbw.c +++ b/drivers/devfreq/devfreq_devbw.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved. + * Copyright (c) 2013-2014, 2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -78,33 +78,15 @@ static int set_bw(struct device *dev, int new_ib, int new_ab) return ret; } -static void find_freq(struct devfreq_dev_profile *p, unsigned long *freq, - u32 flags) -{ - int i; - unsigned long atmost, atleast, f; - - atmost = p->freq_table[0]; - atleast = p->freq_table[p->max_state-1]; - for (i = 0; i < p->max_state; i++) { - f = p->freq_table[i]; - if (f <= *freq) - atmost = max(f, atmost); - if (f >= *freq) - atleast = min(f, atleast); - } - - if (flags & DEVFREQ_FLAG_LEAST_UPPER_BOUND) - *freq = atmost; - else - *freq = atleast; -} - static int devbw_target(struct device *dev, unsigned long *freq, u32 flags) { struct dev_data *d = dev_get_drvdata(dev); + struct dev_pm_opp *opp; + + opp = devfreq_recommended_opp(dev, freq, flags); + if (!IS_ERR(opp)) + dev_pm_opp_put(opp); - find_freq(&d->dp, freq, flags); return set_bw(dev, *freq, d->gov_ab); } @@ -118,14 +100,13 @@ static int devbw_get_dev_status(struct device *dev, } #define PROP_PORTS "qcom,src-dst-ports" -#define PROP_TBL "qcom,bw-tbl" #define PROP_ACTIVE "qcom,active-only" int devfreq_add_devbw(struct device *dev) { struct dev_data *d; struct devfreq_dev_profile *p; - u32 *data, ports[MAX_PATHS * 2]; + u32 ports[MAX_PATHS * 2]; const char *gov_name; int ret, len, i, num_paths; @@ -174,27 +155,9 @@ int devfreq_add_devbw(struct device *dev) p->target = devbw_target; p->get_dev_status = devbw_get_dev_status; - if (of_find_property(dev->of_node, PROP_TBL, &len)) { - len /= sizeof(*data); - data = devm_kzalloc(dev, len * sizeof(*data), GFP_KERNEL); - if (!data) - return -ENOMEM; - - p->freq_table = devm_kzalloc(dev, - len * sizeof(*p->freq_table), - GFP_KERNEL); - if (!p->freq_table) - return -ENOMEM; - - ret = of_property_read_u32_array(dev->of_node, PROP_TBL, - data, len); - if (ret) - return ret; - - for (i = 0; i < len; i++) - p->freq_table[i] = data[i]; - p->max_state = len; - } + ret = dev_pm_opp_of_add_table(dev); + if (ret) + dev_err(dev, "Couldn't parse OPP table:%d\n", ret); d->bus_client = msm_bus_scale_register_client(&d->bw_data); if (!d->bus_client) { -- GitLab From e6ea82281ca0f03cae210f7e6bc5a1a8f533a551 Mon Sep 17 00:00:00 2001 From: Rohit Gupta Date: Tue, 24 Apr 2018 11:05:27 -0700 Subject: [PATCH 1208/1635] ARM: dts: msm: Replace devbw freq tables with OPP tables for SM8150 The devfreq devbw framework has switched from parsing frequency tables to parsing OPP tables. So replace all the devbw frequency tables with OPP tables. Change-Id: I7568306ca8ca5fe32488c011d0d77c17d6502013 Signed-off-by: Rohit Gupta --- arch/arm64/boot/dts/qcom/sm8150-gpu.dtsi | 15 +-- arch/arm64/boot/dts/qcom/sm8150.dtsi | 143 ++++++++++------------- 2 files changed, 60 insertions(+), 98 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sm8150-gpu.dtsi b/arch/arm64/boot/dts/qcom/sm8150-gpu.dtsi index 20c76ba6c8fb..e6982d118219 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-gpu.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-gpu.dtsi @@ -26,20 +26,7 @@ compatible = "qcom,devbw"; governor = "bw_vbif"; qcom,src-dst-ports = <26 512>; - qcom,bw-tbl = - < 0 /* off */ >, - < 381 /* 100 MHz */ >, - < 572 /* 150 MHz */ >, - < 762 /* 200 MHz */ >, - < 1144 /* 300 MHz */ >, - < 1571 /* 412 MHz */ >, - < 2086 /* 547 MHz */ >, - < 2597 /* 681 MHz */ >, - < 2929 /* 768 MHz */ >, - < 3879 /* 1017 MHz */ >, - < 4943 /* 1296 MHz */ >, - < 5931 /* 1555 MHz */ >, - < 6881 /* 1804 MHz */ >; + operating-points-v2 = <&suspendable_ddr_bw_opp_table>; }; gpu_opp_table: gpu-opp-table { diff --git a/arch/arm64/boot/dts/qcom/sm8150.dtsi b/arch/arm64/boot/dts/qcom/sm8150.dtsi index 3f7021ae3fb3..0b612f3af684 100644 --- a/arch/arm64/boot/dts/qcom/sm8150.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150.dtsi @@ -27,6 +27,7 @@ #include #define MHZ_TO_MBPS(mhz, w) ((mhz * 1000000 * w) / (1024 * 1024)) +#define BW_OPP_ENTRY(mhz, w) opp-mhz {opp-hz = /bits/ 64 ;} / { model = "Qualcomm Technologies, Inc. SM8150"; @@ -910,19 +911,23 @@ reg-names = "lagg-base"; }; + llcc_bw_opp_table: llcc-bw-opp-table { + compatible = "operating-points-v2"; + BW_OPP_ENTRY( 150, 16); /* 2288 MB/s */ + BW_OPP_ENTRY( 200, 16); /* 3051 MB/s */ + BW_OPP_ENTRY( 403, 16); /* 6149 MB/s */ + BW_OPP_ENTRY( 533, 16); /* 8132 MB/s */ + BW_OPP_ENTRY( 666, 16); /* 10162 MB/s */ + BW_OPP_ENTRY( 777, 16); /* 11856 MB/s */ + }; + cpu_cpu_llcc_bw: qcom,cpu-cpu-llcc-bw { compatible = "qcom,devbw"; governor = "performance"; qcom,src-dst-ports = ; qcom,active-only; - qcom,bw-tbl = - < MHZ_TO_MBPS(150, 16) >, /* 2288 MB/s */ - < MHZ_TO_MBPS(200, 16) >, /* 4577 MB/s */ - < MHZ_TO_MBPS(403, 16) >, /* 6149 MB/s */ - < MHZ_TO_MBPS(533, 16) >, /* 8132 MB/s */ - < MHZ_TO_MBPS(666, 16) >, /* 10162 MB/s */ - < MHZ_TO_MBPS(777, 16) >; /* 11856 MB/s */ + operating-points-v2 = <&llcc_bw_opp_table>; }; cpu_cpu_llcc_bwmon: qcom,cpu-cpu-llcc-bwmon@90b6400 { @@ -936,24 +941,28 @@ qcom,count-unit = <0x10000>; }; + ddr_bw_opp_table: ddr-bw-opp-table { + compatible = "operating-points-v2"; + BW_OPP_ENTRY( 200, 4); /* 762 MB/s */ + BW_OPP_ENTRY( 300, 4); /* 1144 MB/s */ + BW_OPP_ENTRY( 451, 4); /* 1720 MB/s */ + BW_OPP_ENTRY( 547, 4); /* 2086 MB/s */ + BW_OPP_ENTRY( 681, 4); /* 2597 MB/s */ + BW_OPP_ENTRY( 768, 4); /* 2929 MB/s */ + BW_OPP_ENTRY(1017, 4); /* 3879 MB/s */ + BW_OPP_ENTRY(1296, 4); /* 4943 MB/s */ + BW_OPP_ENTRY(1555, 4); /* 5931 MB/s */ + BW_OPP_ENTRY(1804, 4); /* 6881 MB/s */ + BW_OPP_ENTRY(2092, 4); /* 7980 MB/s */ + }; + cpu_llcc_ddr_bw: qcom,cpu-llcc-ddr-bw { compatible = "qcom,devbw"; governor = "performance"; qcom,src-dst-ports = ; qcom,active-only; - qcom,bw-tbl = - < MHZ_TO_MBPS( 200, 4) >, /* 762 MB/s */ - < MHZ_TO_MBPS( 300, 4) >, /* 1144 MB/s */ - < MHZ_TO_MBPS( 451, 4) >, /* 1720 MB/s */ - < MHZ_TO_MBPS( 547, 4) >, /* 2086 MB/s */ - < MHZ_TO_MBPS( 681, 4) >, /* 2597 MB/s */ - < MHZ_TO_MBPS( 768, 4) >, /* 2929 MB/s */ - < MHZ_TO_MBPS(1017, 4) >, /* 3879 MB/s */ - < MHZ_TO_MBPS(1296, 4) >, /* 4943 MB/s */ - < MHZ_TO_MBPS(1555, 4) >, /* 5931 MB/s */ - < MHZ_TO_MBPS(1804, 4) >, /* 6881 MB/s */ - < MHZ_TO_MBPS(2092, 4) >; /* 7980 MB/s */ + operating-points-v2 = <&ddr_bw_opp_table>; }; cpu_llcc_ddr_bwmon: qcom,cpu-llcc-ddr-bwmon@90cd000 { @@ -966,23 +975,27 @@ qcom,count-unit = <0x10000>; }; + suspendable_ddr_bw_opp_table: suspendable-ddr-bw-opp-table { + compatible = "operating-points-v2"; + BW_OPP_ENTRY( 0, 4); /* 0 MB/s */ + BW_OPP_ENTRY( 200, 4); /* 762 MB/s */ + BW_OPP_ENTRY( 300, 4); /* 1144 MB/s */ + BW_OPP_ENTRY( 451, 4); /* 1720 MB/s */ + BW_OPP_ENTRY( 547, 4); /* 2086 MB/s */ + BW_OPP_ENTRY( 681, 4); /* 2597 MB/s */ + BW_OPP_ENTRY( 768, 4); /* 2929 MB/s */ + BW_OPP_ENTRY(1017, 4); /* 3879 MB/s */ + BW_OPP_ENTRY(1296, 4); /* 4943 MB/s */ + BW_OPP_ENTRY(1555, 4); /* 5931 MB/s */ + BW_OPP_ENTRY(1804, 4); /* 6881 MB/s */ + BW_OPP_ENTRY(2092, 4); /* 7980 MB/s */ + }; + npu_npu_ddr_bw: qcom,npu-npu-ddr-bw { compatible = "qcom,devbw"; governor = "performance"; qcom,src-dst-ports = ; - qcom,bw-tbl = - < MHZ_TO_MBPS( 0, 4) >, /* 0 MB/s */ - < MHZ_TO_MBPS( 200, 4) >, /* 762 MB/s */ - < MHZ_TO_MBPS( 300, 4) >, /* 1144 MB/s */ - < MHZ_TO_MBPS( 451, 4) >, /* 1720 MB/s */ - < MHZ_TO_MBPS( 547, 4) >, /* 2086 MB/s */ - < MHZ_TO_MBPS( 681, 4) >, /* 2597 MB/s */ - < MHZ_TO_MBPS( 768, 4) >, /* 2929 MB/s */ - < MHZ_TO_MBPS(1017, 4) >, /* 3879 MB/s */ - < MHZ_TO_MBPS(1296, 4) >, /* 4943 MB/s */ - < MHZ_TO_MBPS(1555, 4) >, /* 5931 MB/s */ - < MHZ_TO_MBPS(1804, 4) >, /* 6881 MB/s */ - < MHZ_TO_MBPS(2092, 4) >; /* 7980 MB/s */ + operating-points-v2 = <&suspendable_ddr_bw_opp_table>; }; npu_npu_ddr_bwmon: qcom,npu-npu-ddr-bwmon@9960300 { @@ -1051,13 +1064,7 @@ qcom,src-dst-ports = ; qcom,active-only; - qcom,bw-tbl = - < MHZ_TO_MBPS(150, 16) >, /* 2288 MB/s */ - < MHZ_TO_MBPS(200, 16) >, /* 4577 MB/s */ - < MHZ_TO_MBPS(403, 16) >, /* 6149 MB/s */ - < MHZ_TO_MBPS(533, 16) >, /* 8132 MB/s */ - < MHZ_TO_MBPS(666, 16) >, /* 10162 MB/s */ - < MHZ_TO_MBPS(777, 16) >; /* 11856 MB/s */ + operating-points-v2 = <&llcc_bw_opp_table>; }; cpu0_cpu_llcc_latmon: qcom,cpu0-cpu-llcc-latmon { @@ -1080,13 +1087,7 @@ qcom,src-dst-ports = ; qcom,active-only; - qcom,bw-tbl = - < MHZ_TO_MBPS(150, 16) >, /* 2288 MB/s */ - < MHZ_TO_MBPS(200, 16) >, /* 4577 MB/s */ - < MHZ_TO_MBPS(403, 16) >, /* 6149 MB/s */ - < MHZ_TO_MBPS(533, 16) >, /* 8132 MB/s */ - < MHZ_TO_MBPS(666, 16) >, /* 10162 MB/s */ - < MHZ_TO_MBPS(777, 16) >; /* 11856 MB/s */ + operating-points-v2 = <&llcc_bw_opp_table>; }; cpu4_cpu_llcc_latmon: qcom,cpu4-cpu-llcc-latmon { @@ -1109,18 +1110,7 @@ qcom,src-dst-ports = ; qcom,active-only; - qcom,bw-tbl = - < MHZ_TO_MBPS( 200, 4) >, /* 762 MB/s */ - < MHZ_TO_MBPS( 300, 4) >, /* 1144 MB/s */ - < MHZ_TO_MBPS( 451, 4) >, /* 1720 MB/s */ - < MHZ_TO_MBPS( 547, 4) >, /* 2086 MB/s */ - < MHZ_TO_MBPS( 681, 4) >, /* 2597 MB/s */ - < MHZ_TO_MBPS( 768, 4) >, /* 2929 MB/s */ - < MHZ_TO_MBPS(1017, 4) >, /* 3879 MB/s */ - < MHZ_TO_MBPS(1296, 4) >, /* 4943 MB/s */ - < MHZ_TO_MBPS(1555, 4) >, /* 5931 MB/s */ - < MHZ_TO_MBPS(1804, 4) >, /* 6881 MB/s */ - < MHZ_TO_MBPS(2092, 4) >; /* 7980 MB/s */ + operating-points-v2 = <&ddr_bw_opp_table>; }; cpu0_llcc_ddr_latmon: qcom,cpu0-llcc-ddr-latmon { @@ -1143,18 +1133,7 @@ qcom,src-dst-ports = ; qcom,active-only; - qcom,bw-tbl = - < MHZ_TO_MBPS( 200, 4) >, /* 762 MB/s */ - < MHZ_TO_MBPS( 300, 4) >, /* 1144 MB/s */ - < MHZ_TO_MBPS( 451, 4) >, /* 1720 MB/s */ - < MHZ_TO_MBPS( 547, 4) >, /* 2086 MB/s */ - < MHZ_TO_MBPS( 681, 4) >, /* 2597 MB/s */ - < MHZ_TO_MBPS( 768, 4) >, /* 2929 MB/s */ - < MHZ_TO_MBPS(1017, 4) >, /* 3879 MB/s */ - < MHZ_TO_MBPS(1296, 4) >, /* 4943 MB/s */ - < MHZ_TO_MBPS(1555, 4) >, /* 5931 MB/s */ - < MHZ_TO_MBPS(1804, 4) >, /* 6881 MB/s */ - < MHZ_TO_MBPS(2092, 4) >; /* 7980 MB/s */ + operating-points-v2 = <&ddr_bw_opp_table>; }; cpu4_llcc_ddr_latmon: qcom,cpu4-llcc-ddr-latmon { @@ -1178,18 +1157,7 @@ qcom,src-dst-ports = ; qcom,active-only; - qcom,bw-tbl = - < MHZ_TO_MBPS( 200, 4) >, /* 762 MB/s */ - < MHZ_TO_MBPS( 300, 4) >, /* 1144 MB/s */ - < MHZ_TO_MBPS( 451, 4) >, /* 1720 MB/s */ - < MHZ_TO_MBPS( 547, 4) >, /* 2086 MB/s */ - < MHZ_TO_MBPS( 681, 4) >, /* 2597 MB/s */ - < MHZ_TO_MBPS( 768, 4) >, /* 2929 MB/s */ - < MHZ_TO_MBPS(1017, 4) >, /* 3879 MB/s */ - < MHZ_TO_MBPS(1296, 4) >, /* 4943 MB/s */ - < MHZ_TO_MBPS(1555, 4) >, /* 5931 MB/s */ - < MHZ_TO_MBPS(1804, 4) >, /* 6881 MB/s */ - < MHZ_TO_MBPS(2092, 4) >; /* 7980 MB/s */ + operating-points-v2 = <&ddr_bw_opp_table>; }; cpu4_computemon: qcom,cpu4-computemon { @@ -1271,13 +1239,20 @@ clock-frequency = <32768>; }; + keepalive_opp_table: keepalive-opp-table { + compatible = "operating-points-v2"; + opp-1 { + opp-hz = /bits/ 64 < 1 >; + }; + }; + snoc_cnoc_keepalive: qcom,snoc_cnoc_keepalive { compatible = "qcom,devbw"; governor = "powersave"; qcom,src-dst-ports = <1 627>; qcom,active-only; status = "ok"; - qcom,bw-tbl = < 1 >; + operating-points-v2 = <&keepalive_opp_table>; }; cdsp_keepalive: qcom,cdsp_keepalive { @@ -1286,7 +1261,7 @@ qcom,src-dst-ports = <154 10070>; qcom,active-only; status = "ok"; - qcom,bw-tbl = < 1 >; + operating-points-v2 = <&keepalive_opp_table>; }; clock_rpmh: qcom,rpmhclk { -- GitLab From 4c07bdbfa00a247cb28f071b7c0ed8c723c85465 Mon Sep 17 00:00:00 2001 From: Ping Li Date: Mon, 30 Apr 2018 13:11:53 -0700 Subject: [PATCH 1209/1635] drm/msm/sde: Fix possible uninitialized variable error Fix possible uninitialized variable error for PA hsic and sixzone cases. Change-Id: If59f3c097ff66008e717f9e04ffd0149c3b71d28 Signed-off-by: Ping Li --- drivers/gpu/drm/msm/sde/sde_hw_dspp.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/msm/sde/sde_hw_dspp.c b/drivers/gpu/drm/msm/sde/sde_hw_dspp.c index b9350ff9f65d..eb2ccb1acb12 100644 --- a/drivers/gpu/drm/msm/sde/sde_hw_dspp.c +++ b/drivers/gpu/drm/msm/sde/sde_hw_dspp.c @@ -45,7 +45,7 @@ static struct sde_dspp_cfg *_dspp_offset(enum sde_dspp dspp, static void _setup_dspp_ops(struct sde_hw_dspp *c, unsigned long features) { - int i = 0, ret; + int i = 0, ret = 0; if (!c || !c->cap || !c->cap->sblk) return; @@ -71,7 +71,7 @@ static void _setup_dspp_ops(struct sde_hw_dspp *c, unsigned long features) break; case SDE_DSPP_HSIC: if (c->cap->sblk->hsic.version == - SDE_COLOR_PROCESS_VER(0x1, 0x7)) + SDE_COLOR_PROCESS_VER(0x1, 0x7)) { ret = reg_dmav1_init_dspp_op_v4(i, c->idx); if (!ret) c->ops.setup_pa_hsic = @@ -79,6 +79,7 @@ static void _setup_dspp_ops(struct sde_hw_dspp *c, unsigned long features) else c->ops.setup_pa_hsic = sde_setup_dspp_pa_hsic_v17; + } break; case SDE_DSPP_MEMCOLOR: if (c->cap->sblk->memcolor.version == @@ -107,7 +108,7 @@ static void _setup_dspp_ops(struct sde_hw_dspp *c, unsigned long features) break; case SDE_DSPP_SIXZONE: if (c->cap->sblk->sixzone.version == - SDE_COLOR_PROCESS_VER(0x1, 0x7)) + SDE_COLOR_PROCESS_VER(0x1, 0x7)) { ret = reg_dmav1_init_dspp_op_v4(i, c->idx); if (!ret) c->ops.setup_sixzone = @@ -115,6 +116,7 @@ static void _setup_dspp_ops(struct sde_hw_dspp *c, unsigned long features) else c->ops.setup_sixzone = sde_setup_dspp_sixzone_v17; + } break; case SDE_DSPP_DITHER: if (c->cap->sblk->dither.version == -- GitLab From bc21a5da30312691330e30a4347ff64d4ea9ff30 Mon Sep 17 00:00:00 2001 From: Zhen Kong Date: Wed, 25 Apr 2018 16:15:35 -0700 Subject: [PATCH 1210/1635] qseecom: fix memory issues for qseecom kernel client APIs qseecom kernel client APIs don't use dmabuf to get contiguous buf from ion heap, make change to use the correctly configured qseecom device for dma_alloc_coherent to fix allocation error; update cache operation if dmabuf is not used; and call dma_free_coherent() for app shutdown. Change-Id: I1ee942c5046e7cdbc23ce69584d1e2c996958346 Signed-off-by: Zhen Kong --- drivers/misc/qseecom.c | 58 +++++++++++++++++++++++++++--------------- 1 file changed, 38 insertions(+), 20 deletions(-) diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c index 48a68e97367e..71193f94c5cb 100644 --- a/drivers/misc/qseecom.c +++ b/drivers/misc/qseecom.c @@ -1309,7 +1309,9 @@ static int __qseecom_set_sb_memory(struct qseecom_registered_listener_list *svc, } return 0; err: - qseecom_vaddr_unmap(svc->sb_virt, svc->sgt, svc->attach, svc->dmabuf); + if (svc->dmabuf) + qseecom_vaddr_unmap(svc->sb_virt, svc->sgt, svc->attach, + svc->dmabuf); return ret; } @@ -1407,7 +1409,7 @@ static int qseecom_unregister_listener(struct qseecom_dev_handle *data) } } - if (ptr_svc->sb_virt) + if (ptr_svc->dmabuf) qseecom_vaddr_unmap(ptr_svc->sb_virt, ptr_svc->sgt, ptr_svc->attach, ptr_svc->dmabuf); @@ -1709,7 +1711,8 @@ static int qseecom_set_client_mem_param(struct qseecom_dev_handle *data, return ret; exit: - qseecom_vaddr_unmap(data->client.sb_virt, data->client.sgt, + if (data->client.dmabuf) + qseecom_vaddr_unmap(data->client.sb_virt, data->client.sgt, data->client.attach, data->client.dmabuf); return ret; } @@ -2617,7 +2620,7 @@ static int qseecom_load_app(struct qseecom_dev_handle *data, void __user *argp) loadapp_err: __qseecom_disable_clk_scale_down(data); - if (vaddr) + if (dmabuf) qseecom_vaddr_unmap(vaddr, sgt, attach, dmabuf); enable_clk_err: if (qseecom.support_bus_scaling) { @@ -2766,7 +2769,7 @@ static int qseecom_unload_app(struct qseecom_dev_handle *data, flags1); } unload_exit: - if (data->client.sb_virt) + if (data->client.dmabuf) qseecom_vaddr_unmap(data->client.sb_virt, data->client.sgt, data->client.attach, data->client.dmabuf); data->released = true; @@ -3270,11 +3273,13 @@ static int __qseecom_send_cmd(struct qseecom_dev_handle *data, else *(uint32_t *)cmd_buf = QSEOS_CLIENT_SEND_DATA_COMMAND_WHITELIST; - ret = qseecom_dmabuf_cache_operations(data->client.dmabuf, + if (data->client.dmabuf) { + ret = qseecom_dmabuf_cache_operations(data->client.dmabuf, QSEECOM_CACHE_CLEAN); - if (ret) { - pr_err("cache operation failed %d\n", ret); - return ret; + if (ret) { + pr_err("cache operation failed %d\n", ret); + return ret; + } } __qseecom_reentrancy_check_if_this_app_blocked(ptr_app); @@ -3287,11 +3292,13 @@ static int __qseecom_send_cmd(struct qseecom_dev_handle *data, ret, data->client.app_id); goto exit; } - ret = qseecom_dmabuf_cache_operations(data->client.dmabuf, + if (data->client.dmabuf) { + ret = qseecom_dmabuf_cache_operations(data->client.dmabuf, QSEECOM_CACHE_INVALIDATE); - if (ret) { - pr_err("cache operation failed %d\n", ret); - return ret; + if (ret) { + pr_err("cache operation failed %d\n", ret); + return ret; + } } if (qseecom.qsee_reentrancy_support) { @@ -3597,7 +3604,7 @@ static int __qseecom_allocate_sg_list_buffer(struct qseecom_dev_handle *data, /* Allocate a contiguous kernel buffer */ size = sg_ptr->nents * SG_ENTRY_SZ_64BIT; size = (size + PAGE_SIZE) & PAGE_MASK; - buf = dma_alloc_coherent(qseecom.pdev, + buf = dma_alloc_coherent(qseecom.dev, size, &coh_pmem, GFP_KERNEL); if (buf == NULL) { pr_err("failed to alloc memory for sg buf\n"); @@ -4141,7 +4148,7 @@ static int __qseecom_alloc_coherent_buf( /* Allocate a contiguous kernel buffer */ size = (size + PAGE_SIZE) & PAGE_MASK; - buf = dma_alloc_coherent(qseecom.pdev, + buf = dma_alloc_coherent(qseecom.dev, size, &coh_pmem, GFP_KERNEL); if (buf == NULL) { pr_err("failed to alloc memory for size %d\n", size); @@ -4155,6 +4162,7 @@ static int __qseecom_alloc_coherent_buf( static void __qseecom_free_coherent_buf(uint32_t size, u8 *vaddr, phys_addr_t paddr) { + size = (size + PAGE_SIZE) & PAGE_MASK; dma_free_coherent(qseecom.pdev, size, vaddr, paddr); } @@ -4289,7 +4297,8 @@ static int __qseecom_load_fw(struct qseecom_dev_handle *data, char *appname, } exit_free_img_data: - __qseecom_free_coherent_buf(fw_size, img_data, pa); + if (img_data) + __qseecom_free_coherent_buf(fw_size, img_data, pa); return ret; } @@ -4400,7 +4409,8 @@ static int qseecom_load_commonlib_image(struct qseecom_dev_handle *data, } exit_free_img_data: - __qseecom_free_coherent_buf(fw_size, img_data, pa); + if (img_data) + __qseecom_free_coherent_buf(fw_size, img_data, pa); return ret; } @@ -4634,6 +4644,9 @@ int qseecom_shutdown_app(struct qseecom_handle **handle) mutex_unlock(&app_access_lock); if (ret == 0) { + if (data->client.sb_virt) + __qseecom_free_coherent_buf(data->client.sb_length, + data->client.sb_virt, data->client.sb_phys); kzfree(data); kzfree(*handle); kzfree(kclient); @@ -4702,7 +4715,12 @@ int qseecom_send_command(struct qseecom_handle *handle, void *send_buf, if (!strcmp(data->client.app_name, "securemm")) data->use_legacy_cmd = true; + dmac_flush_range(req.cmd_req_buf, req.cmd_req_buf + req.cmd_req_len); + ret = __qseecom_send_cmd(data, &req); + + dmac_flush_range(req.resp_buf, req.resp_buf + req.resp_len); + data->use_legacy_cmd = false; if (qseecom.support_bus_scaling) __qseecom_add_bw_scale_down_timer( @@ -5330,7 +5348,7 @@ static int qseecom_load_external_elf(struct qseecom_dev_handle *data, } exit_cpu_restore: - if (va) + if (dmabuf) qseecom_vaddr_unmap(va, sgt, attach, dmabuf); return ret; } @@ -6425,7 +6443,7 @@ static int __qseecom_qteec_handle_pre_alc_fd(struct qseecom_dev_handle *data, size = sizeof(uint32_t) + sizeof(struct qseecom_sg_entry) * sg_ptr->nents; size = (size + PAGE_SIZE) & PAGE_MASK; - buf = dma_alloc_coherent(qseecom.pdev, + buf = dma_alloc_coherent(qseecom.dev, size, &coh_pmem, GFP_KERNEL); if (buf == NULL) { pr_err("failed to alloc memory for sg buf\n"); @@ -7673,7 +7691,7 @@ static int qseecom_release(struct inode *inode, struct file *file) break; case QSEECOM_SECURE_SERVICE: case QSEECOM_GENERIC: - if (data->client.sb_virt) + if (data->client.dmabuf) qseecom_vaddr_unmap(data->client.sb_virt, data->client.sgt, data->client.attach, data->client.dmabuf); -- GitLab From fc01ed4e51cabb227e088c5fac7ca9837cf08d9d Mon Sep 17 00:00:00 2001 From: Nicholas Troast Date: Tue, 5 Sep 2017 12:56:19 -0700 Subject: [PATCH 1211/1635] power: add SMB1390 charge pump driver SMB1390 is a charge pump PMIC and is used as a companion charger to the primary charging PMIC. This driver implements all of the required functionality to be used as a parallel charger. This is a snapshot of commit "power: add SMB1390 charge pump driver" in kernel 4.9, with two modifications: - cp_class_attrs -> cp_class_groups. This change was necessitated by 'commit ced6473e7486 ("driver core: class: add class_groups support")' and 'commit ecbaa83ee84c ("driver core: remove class_attrs from struct class")'. - Use the IIO framework to read die temperature instead of the older qpnp-vadc framework. Also, add an INFO message to signify successful probing of driver. CRs-Fixed: 2200333 Change-Id: I9e58773241a2b9865067ac563ca96a75afc34611 Signed-off-by: Nicholas Troast Signed-off-by: Ashay Jaiswal Signed-off-by: Umang Agrawal Signed-off-by: Guru Das Srinagesh --- .../power/supply/qcom/smb1390-charger.txt | 76 ++ drivers/power/supply/qcom/Kconfig | 8 + drivers/power/supply/qcom/Makefile | 1 + drivers/power/supply/qcom/smb1390-charger.c | 767 ++++++++++++++++++ 4 files changed, 852 insertions(+) create mode 100644 Documentation/devicetree/bindings/power/supply/qcom/smb1390-charger.txt create mode 100644 drivers/power/supply/qcom/smb1390-charger.c diff --git a/Documentation/devicetree/bindings/power/supply/qcom/smb1390-charger.txt b/Documentation/devicetree/bindings/power/supply/qcom/smb1390-charger.txt new file mode 100644 index 000000000000..f40a7158c83c --- /dev/null +++ b/Documentation/devicetree/bindings/power/supply/qcom/smb1390-charger.txt @@ -0,0 +1,76 @@ +Qualcomm Technologies, Inc. SMB1390 Charger Specific Bindings + +SMB1390 charge pump is paired with QTI family of standalone chargers to +enable a high current, high efficiency Li+ battery charging system. + +======================= +Required Node Structure +======================= + +SMB1390 Charger must be described in two levels of device nodes. + +================================== +First Level Node - SMB1390 Charger +================================== + +Charger specific properties: +- compatible + Usage: required + Value type: + Definition: "qcom,smb1390-charger". + +- qcom,pmic-revid + Usage: required + Value type: phandle + Definition: Should specify the phandle of SMB's revid module. This is used + to identify the SMB subtype. + +- io-channels +- io-channel-names + Usage: required + Value type: + Definition: For details about IIO bindings see: + Documentation/devicetree/bindings/iio/iio-bindings.txt + +================================================ +Second Level Nodes - SMB1390 Charger Peripherals +================================================ + +Peripheral specific properties: +- interrupts + Usage: required + Value type: + Definition: Peripheral interrupt specifier. + +- interrupt-names + Usage: required + Value type: + Definition: Interrupt names. This list must match up 1-to-1 with the + interrupts specified in the 'interrupts' property. + +======= +Example +======= + +smb1390_charger: qcom,charge_pump { + compatible = "qcom,smb1390-charger"; + qcom,pmic-revid = <&smb1390_revid>; + interrupt-parent = <&smb1390>; + status = "disabled"; + + io-channels = <&pm855b_vadc ADC_AMUX_THM2>; + io-channel-names = "cp_die_temp"; + + qcom,core { + interrupts = <0x10 0x0 IRQ_TYPE_EDGE_RISING>, + <0x10 0x1 IRQ_TYPE_EDGE_RISING>, + <0x10 0x2 IRQ_TYPE_EDGE_RISING>, + <0x10 0x3 IRQ_TYPE_EDGE_RISING>, + <0x10 0x4 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "switcher-off-window", + "switcher-off-fault", + "vph-ov-soft", + "ilim", + "temp-alarm"; + }; +}; diff --git a/drivers/power/supply/qcom/Kconfig b/drivers/power/supply/qcom/Kconfig index b62c83a8880f..38da3b400660 100644 --- a/drivers/power/supply/qcom/Kconfig +++ b/drivers/power/supply/qcom/Kconfig @@ -75,4 +75,12 @@ config QPNP_QNOVO module. It also allows userspace code to read diagnostics of voltage and current measured during certain phases of the pulses. +config SMB1390_CHARGE_PUMP + tristate "SMB1390 Charge Pump" + depends on MFD_I2C_PMIC + help + Say Y to include support for SMB1390 Charge Pump. + SMB1390 is a div2 charge pump capable of delivering 6A charge current + with very high efficiency. + endmenu diff --git a/drivers/power/supply/qcom/Makefile b/drivers/power/supply/qcom/Makefile index 3281b14af4d1..e4cf697b73b4 100644 --- a/drivers/power/supply/qcom/Makefile +++ b/drivers/power/supply/qcom/Makefile @@ -5,3 +5,4 @@ obj-$(CONFIG_QPNP_SMB2) += step-chg-jeita.o battery.o qpnp-smb2.o smb-lib.o pmi obj-$(CONFIG_SMB138X_CHARGER) += step-chg-jeita.o smb138x-charger.o smb-lib.o pmic-voter.o storm-watch.o battery.o obj-$(CONFIG_QPNP_QNOVO) += qpnp-qnovo.o battery.o obj-$(CONFIG_QPNP_SMB5) += step-chg-jeita.o battery.o qpnp-smb5.o smb5-lib.o pmic-voter.o storm-watch.o schgm-flash.o +obj-$(CONFIG_SMB1390_CHARGE_PUMP) += smb1390-charger.o pmic-voter.o diff --git a/drivers/power/supply/qcom/smb1390-charger.c b/drivers/power/supply/qcom/smb1390-charger.c new file mode 100644 index 000000000000..58374f811292 --- /dev/null +++ b/drivers/power/supply/qcom/smb1390-charger.c @@ -0,0 +1,767 @@ +/* Copyright (c) 2017-2018 The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#define pr_fmt(fmt) "SMB1390: %s: " fmt, __func__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define CORE_STATUS1_REG 0x1006 +#define WIN_OV_BIT BIT(0) +#define WIN_UV_BIT BIT(1) +#define EN_PIN_OUT_BIT BIT(2) +#define LCM_AUTO_BIT BIT(3) +#define LCM_PIN_BIT BIT(4) +#define ILIM_BIT BIT(5) +#define TEMP_ALARM_BIT BIT(6) +#define VPH_OV_SOFT_BIT BIT(7) + +#define CORE_STATUS2_REG 0x1007 +#define SWITCHER_HOLD_OFF_BIT BIT(0) +#define VPH_OV_HARD_BIT BIT(1) +#define TSD_BIT BIT(2) +#define IREV_BIT BIT(3) +#define IOC_BIT BIT(4) +#define VIN_UV_BIT BIT(5) +#define VIN_OV_BIT BIT(6) +#define EN_PIN_OUT2_BIT BIT(7) + +#define CORE_STATUS3_REG 0x1008 +#define EN_SL_BIT BIT(0) +#define IIN_REF_SS_DONE_BIT BIT(1) +#define FLYCAP_SS_DONE_BIT BIT(2) +#define SL_DETECTED_BIT BIT(3) + +#define CORE_INT_RT_STS_REG 0x1010 +#define SWITCHER_OFF_WINDOW_STS_BIT BIT(0) +#define SWITCHER_OFF_FAULT_STS_BIT BIT(1) +#define TSD_STS_BIT BIT(2) +#define IREV_STS_BIT BIT(3) +#define VPH_OV_HARD_STS_BIT BIT(4) +#define VPH_OV_SOFT_STS_BIT BIT(5) +#define ILIM_STS_BIT BIT(6) +#define TEMP_ALARM_STS_BIT BIT(7) + +#define CORE_CONTROL1_REG 0x1020 +#define CMD_EN_SWITCHER_BIT BIT(0) +#define CMD_EN_SL_BIT BIT(1) + +#define CORE_FTRIM_ILIM_REG 0x1030 +#define CFG_ILIM_MASK GENMASK(4, 0) + +#define CP_VOTER "CP_VOTER" +#define USER_VOTER "USER_VOTER" +#define ILIM_VOTER "ILIM_VOTER" +#define FCC_VOTER "FCC_VOTER" +#define ICL_VOTER "ICL_VOTER" +#define USB_VOTER "USB_VOTER" + +enum { + SWITCHER_OFF_WINDOW_IRQ = 0, + SWITCHER_OFF_FAULT_IRQ, + TSD_IRQ, + IREV_IRQ, + VPH_OV_HARD_IRQ, + VPH_OV_SOFT_IRQ, + ILIM_IRQ, + TEMP_ALARM_IRQ, + NUM_IRQS, +}; + +struct smb1390_iio { + struct iio_channel *die_temp_chan; +}; + +struct smb1390 { + struct device *dev; + struct regmap *regmap; + struct notifier_block nb; + struct class cp_class; + + /* work structs */ + struct work_struct status_change_work; + struct work_struct taper_work; + + /* mutexes */ + spinlock_t status_change_lock; + + /* votables */ + struct votable *disable_votable; + struct votable *ilim_votable; + struct votable *pl_disable_votable; + struct votable *fcc_votable; + struct votable *hvdcp_hw_inov_dis_votable; + + /* power supplies */ + struct power_supply *usb_psy; + struct power_supply *batt_psy; + + int irqs[NUM_IRQS]; + bool status_change_running; + bool taper_work_running; + struct smb1390_iio iio; +}; + +struct smb_irq { + const char *name; + const irq_handler_t handler; + const bool wake; +}; + +static const struct smb_irq smb_irqs[]; + +static int smb1390_read(struct smb1390 *chip, int reg, int *val) +{ + int rc; + + rc = regmap_read(chip->regmap, reg, val); + if (rc < 0) + pr_err("Couldn't read 0x%04x\n", reg); + + return rc; +} + +static int smb1390_masked_write(struct smb1390 *chip, int reg, int mask, + int val) +{ + int rc; + + pr_debug("Writing 0x%02x to 0x%04x with mask 0x%02x\n", val, reg, mask); + rc = regmap_update_bits(chip->regmap, reg, mask, val); + if (rc < 0) + pr_err("Couldn't write 0x%02x to 0x%04x with mask 0x%02x\n", + val, reg, mask); + + return rc; +} + +static bool is_psy_voter_available(struct smb1390 *chip) +{ + if (!chip->batt_psy) { + chip->batt_psy = power_supply_get_by_name("battery"); + if (!chip->batt_psy) { + pr_debug("Couldn't find battery psy\n"); + return false; + } + } + + if (!chip->usb_psy) { + chip->usb_psy = power_supply_get_by_name("usb"); + if (!chip->usb_psy) { + pr_debug("Couldn't find usb psy\n"); + return false; + } + } + + if (!chip->fcc_votable) { + chip->fcc_votable = find_votable("FCC"); + if (!chip->fcc_votable) { + pr_debug("Couldn't find FCC votable\n"); + return false; + } + } + + if (!chip->pl_disable_votable) { + chip->pl_disable_votable = find_votable("PL_DISABLE"); + if (!chip->pl_disable_votable) { + pr_debug("Couldn't find PL_DISABLE votable\n"); + return false; + } + } + + if (!chip->hvdcp_hw_inov_dis_votable) { + chip->hvdcp_hw_inov_dis_votable = + find_votable("HVDCP_HW_INOV_DIS"); + if (!chip->hvdcp_hw_inov_dis_votable) { + pr_debug("Couldn't find HVDCP_HW_INOV_DIS votable\n"); + return false; + } + } + + return true; +} + +static irqreturn_t default_irq_handler(int irq, void *data) +{ + struct smb1390 *chip = data; + int i; + + for (i = 0; i < NUM_IRQS; ++i) { + if (irq == chip->irqs[i]) + pr_debug("%s IRQ triggered\n", smb_irqs[i].name); + } + + kobject_uevent(&chip->dev->kobj, KOBJ_CHANGE); + return IRQ_HANDLED; +} + +static const struct smb_irq smb_irqs[] = { + [SWITCHER_OFF_WINDOW_IRQ] = { + .name = "switcher-off-window", + .handler = default_irq_handler, + .wake = true, + }, + [SWITCHER_OFF_FAULT_IRQ] = { + .name = "switcher-off-fault", + .handler = default_irq_handler, + .wake = true, + }, + [TSD_IRQ] = { + .name = "tsd-fault", + .handler = default_irq_handler, + .wake = true, + }, + [IREV_IRQ] = { + .name = "irev-fault", + .handler = default_irq_handler, + .wake = true, + }, + [VPH_OV_HARD_IRQ] = { + .name = "vph-ov-hard", + .handler = default_irq_handler, + .wake = true, + }, + [VPH_OV_SOFT_IRQ] = { + .name = "vph-ov-soft", + .handler = default_irq_handler, + .wake = true, + }, + [ILIM_IRQ] = { + .name = "ilim", + .handler = default_irq_handler, + .wake = true, + }, + [TEMP_ALARM_IRQ] = { + .name = "temp-alarm", + .handler = default_irq_handler, + .wake = true, + }, +}; + +/* SYSFS functions for reporting smb1390 charge pump state */ +static ssize_t stat1_show(struct class *c, struct class_attribute *attr, + char *buf) +{ + struct smb1390 *chip = container_of(c, struct smb1390, cp_class); + int rc, val; + + rc = smb1390_read(chip, CORE_STATUS1_REG, &val); + if (rc < 0) + return -EINVAL; + + return snprintf(buf, PAGE_SIZE, "%x\n", val); +} +static CLASS_ATTR_RO(stat1); + +static ssize_t stat2_show(struct class *c, struct class_attribute *attr, + char *buf) +{ + struct smb1390 *chip = container_of(c, struct smb1390, cp_class); + int rc, val; + + rc = smb1390_read(chip, CORE_STATUS2_REG, &val); + if (rc < 0) + return -EINVAL; + + return snprintf(buf, PAGE_SIZE, "%x\n", val); +} +static CLASS_ATTR_RO(stat2); + +static ssize_t enable_show(struct class *c, struct class_attribute *attr, + char *buf) +{ + struct smb1390 *chip = container_of(c, struct smb1390, cp_class); + + return snprintf(buf, PAGE_SIZE, "%d\n", + !get_effective_result(chip->disable_votable)); +} + +static ssize_t enable_store(struct class *c, struct class_attribute *attr, + const char *buf, size_t count) +{ + struct smb1390 *chip = container_of(c, struct smb1390, cp_class); + unsigned long val; + + if (kstrtoul(buf, 0, &val)) + return -EINVAL; + + vote(chip->disable_votable, USER_VOTER, !val, 0); + return count; +} +static CLASS_ATTR_RW(enable); + +static ssize_t die_temp_show(struct class *c, struct class_attribute *attr, + char *buf) +{ + struct smb1390 *chip = container_of(c, struct smb1390, cp_class); + int die_temp_deciC = 0; + int rc; + + rc = iio_read_channel_processed(chip->iio.die_temp_chan, + &die_temp_deciC); + + return snprintf(buf, PAGE_SIZE, "%d\n", die_temp_deciC / 100); +} +static CLASS_ATTR_RO(die_temp); + +static struct attribute *cp_class_attrs[] = { + &class_attr_stat1.attr, + &class_attr_stat2.attr, + &class_attr_enable.attr, + &class_attr_die_temp.attr, + NULL, +}; +ATTRIBUTE_GROUPS(cp_class); + +/* voter callbacks */ +static int smb1390_disable_vote_cb(struct votable *votable, void *data, + int disable, const char *client) +{ + struct smb1390 *chip = data; + int rc = 0; + + if (!is_psy_voter_available(chip)) + return -EAGAIN; + + if (disable) { + rc = smb1390_masked_write(chip, CORE_CONTROL1_REG, + CMD_EN_SWITCHER_BIT, 0); + if (rc < 0) + return rc; + + vote(chip->hvdcp_hw_inov_dis_votable, CP_VOTER, false, 0); + vote(chip->pl_disable_votable, CP_VOTER, false, 0); + } else { + vote(chip->hvdcp_hw_inov_dis_votable, CP_VOTER, true, 0); + vote(chip->pl_disable_votable, CP_VOTER, true, 0); + rc = smb1390_masked_write(chip, CORE_CONTROL1_REG, + CMD_EN_SWITCHER_BIT, CMD_EN_SWITCHER_BIT); + if (rc < 0) + return rc; + } + + /* charging may have been disabled by ILIM; send uevent */ + kobject_uevent(&chip->dev->kobj, KOBJ_CHANGE); + return rc; +} + +static int smb1390_ilim_vote_cb(struct votable *votable, void *data, + int ilim_uA, const char *client) +{ + struct smb1390 *chip = data; + int rc = 0; + + if (!is_psy_voter_available(chip)) + return -EAGAIN; + + /* ILIM should always have at least one active vote */ + if (!client) { + pr_err("Client missing\n"); + return -EINVAL; + } + + /* ILIM less than 1A is not accurate; disable charging */ + if (ilim_uA < 1000000) { + pr_debug("ILIM %duA is too low to allow charging\n", ilim_uA); + vote(chip->disable_votable, ILIM_VOTER, true, 0); + } else { + pr_debug("setting ILIM to %duA\n", ilim_uA); + rc = smb1390_masked_write(chip, CORE_FTRIM_ILIM_REG, + CFG_ILIM_MASK, + DIV_ROUND_CLOSEST(ilim_uA - 500000, 100000)); + if (rc < 0) + pr_err("Failed to write ILIM Register, rc=%d\n", rc); + if (rc >= 0) + vote(chip->disable_votable, ILIM_VOTER, false, 0); + } + + return rc; +} + +static int smb1390_notifier_cb(struct notifier_block *nb, + unsigned long event, void *data) +{ + struct smb1390 *chip = container_of(nb, struct smb1390, nb); + struct power_supply *psy = data; + unsigned long flags; + + if (event != PSY_EVENT_PROP_CHANGED) + return NOTIFY_OK; + + if (strcmp(psy->desc->name, "battery") == 0 + || strcmp(psy->desc->name, "usb") == 0 + || strcmp(psy->desc->name, "main") == 0) { + spin_lock_irqsave(&chip->status_change_lock, flags); + if (!chip->status_change_running) { + chip->status_change_running = true; + pm_stay_awake(chip->dev); + schedule_work(&chip->status_change_work); + } + spin_unlock_irqrestore(&chip->status_change_lock, flags); + } + + return NOTIFY_OK; +} + +static void smb1390_status_change_work(struct work_struct *work) +{ + struct smb1390 *chip = container_of(work, struct smb1390, + status_change_work); + union power_supply_propval pval = {0, }; + int rc; + + if (!is_psy_voter_available(chip)) + goto out; + + rc = power_supply_get_property(chip->usb_psy, + POWER_SUPPLY_PROP_TYPEC_MODE, &pval); + if (rc < 0) { + pr_err("Couldn't get usb present rc=%d\n", rc); + goto out; + } + + if (pval.intval != POWER_SUPPLY_TYPEC_SOURCE_DEFAULT + && pval.intval != POWER_SUPPLY_TYPEC_SOURCE_MEDIUM + && pval.intval != POWER_SUPPLY_TYPEC_SOURCE_HIGH) { + vote(chip->disable_votable, USB_VOTER, true, 0); + vote(chip->fcc_votable, CP_VOTER, false, 0); + } else { + vote(chip->disable_votable, USB_VOTER, false, 0); + + /* + * ILIM is set based on the primary chargers AICL result. This + * ensures VBUS does not collapse due to the current drawn via + * MID. + */ + rc = power_supply_get_property(chip->usb_psy, + POWER_SUPPLY_PROP_INPUT_CURRENT_SETTLED, &pval); + if (rc < 0) + pr_err("Couldn't get usb icl rc=%d\n", rc); + else + vote(chip->ilim_votable, ICL_VOTER, true, pval.intval); + + /* input current is always half the charge current */ + vote(chip->ilim_votable, FCC_VOTER, true, + get_effective_result(chip->fcc_votable) / 2); + + /* + * all votes that would result in disabling the charge pump have + * been cast; ensure the charhe pump is still enabled before + * continuing. + */ + if (get_effective_result(chip->disable_votable)) + goto out; + + rc = power_supply_get_property(chip->batt_psy, + POWER_SUPPLY_PROP_CHARGE_TYPE, &pval); + if (rc < 0) { + pr_err("Couldn't get charge type rc=%d\n", rc); + } else if (pval.intval == + POWER_SUPPLY_CHARGE_TYPE_TAPER) { + /* + * mutual exclusion is already guaranteed by + * chip->status_change_running + */ + if (!chip->taper_work_running) { + chip->taper_work_running = true; + queue_work(system_long_wq, + &chip->taper_work); + } + } + } + +out: + pm_relax(chip->dev); + chip->status_change_running = false; +} + +static void smb1390_taper_work(struct work_struct *work) +{ + struct smb1390 *chip = container_of(work, struct smb1390, taper_work); + union power_supply_propval pval = {0, }; + int rc, fcc_uA; + + if (!is_psy_voter_available(chip)) + goto out; + + do { + fcc_uA = get_effective_result(chip->fcc_votable) - 100000; + pr_debug("taper work reducing FCC to %duA\n", fcc_uA); + vote(chip->fcc_votable, CP_VOTER, true, fcc_uA); + + rc = power_supply_get_property(chip->batt_psy, + POWER_SUPPLY_PROP_CHARGE_TYPE, &pval); + if (rc < 0) { + pr_err("Couldn't get charge type rc=%d\n", rc); + goto out; + } + + msleep(500); + } while (fcc_uA >= 2000000 + && pval.intval == POWER_SUPPLY_CHARGE_TYPE_TAPER); + +out: + pr_debug("taper work exit\n"); + chip->taper_work_running = false; +} + +static int smb1390_parse_dt(struct smb1390 *chip) +{ + int rc; + + rc = of_property_match_string(chip->dev->of_node, "io-channel-names", + "cp_die_temp"); + if (rc >= 0) { + chip->iio.die_temp_chan = + iio_channel_get(chip->dev, "cp_die_temp"); + rc = PTR_ERR(chip->iio.die_temp_chan); + if (IS_ERR(chip->iio.die_temp_chan)) { + if (rc != -EPROBE_DEFER) + dev_err(chip->dev, + "cp_die_temp channel unavailable %ld\n", + PTR_ERR(chip->iio.die_temp_chan)); + chip->iio.die_temp_chan = NULL; + return rc; + } + } + + return rc; +} + +static void smb1390_release_channels(struct smb1390 *chip) +{ + if (!IS_ERR_OR_NULL(chip->iio.die_temp_chan)) + iio_channel_release(chip->iio.die_temp_chan); +} + +static int smb1390_create_votables(struct smb1390 *chip) +{ + chip->disable_votable = create_votable("CP_DISABLE", + VOTE_SET_ANY, smb1390_disable_vote_cb, chip); + if (IS_ERR(chip->disable_votable)) + return PTR_ERR(chip->disable_votable); + + chip->ilim_votable = create_votable("CP_ILIM", + VOTE_MIN, smb1390_ilim_vote_cb, chip); + if (IS_ERR(chip->ilim_votable)) + return PTR_ERR(chip->ilim_votable); + + return 0; +} + +static void smb1390_destroy_votables(struct smb1390 *chip) +{ + destroy_votable(chip->disable_votable); + destroy_votable(chip->ilim_votable); +} + +static int smb1390_init_hw(struct smb1390 *chip) +{ + /* + * charge pump is initially disabled; this indirectly votes to allow + * traditional parallel charging if present + */ + vote(chip->disable_votable, USER_VOTER, true, 0); + return 0; +} + +static int smb1390_get_irq_index_byname(const char *irq_name) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(smb_irqs); i++) { + if (strcmp(smb_irqs[i].name, irq_name) == 0) + return i; + } + + return -ENOENT; +} + +static int smb1390_request_interrupt(struct smb1390 *chip, + struct device_node *node, + const char *irq_name) +{ + int rc = 0, irq, irq_index; + + irq = of_irq_get_byname(node, irq_name); + if (irq < 0) { + pr_err("Couldn't get irq %s byname\n", irq_name); + return irq; + } + + irq_index = smb1390_get_irq_index_byname(irq_name); + if (irq_index < 0) { + pr_err("%s is not a defined irq\n", irq_name); + return irq_index; + } + + if (!smb_irqs[irq_index].handler) + return 0; + + rc = devm_request_threaded_irq(chip->dev, irq, NULL, + smb_irqs[irq_index].handler, + IRQF_ONESHOT, irq_name, chip); + if (rc < 0) { + pr_err("Couldn't request irq %d rc=%d\n", irq, rc); + return rc; + } + + chip->irqs[irq_index] = irq; + if (smb_irqs[irq_index].wake) + enable_irq_wake(irq); + + return rc; +} + +static int smb1390_request_interrupts(struct smb1390 *chip) +{ + struct device_node *node = chip->dev->of_node; + struct device_node *child; + int rc = 0; + const char *name; + struct property *prop; + + for_each_available_child_of_node(node, child) { + of_property_for_each_string(child, "interrupt-names", + prop, name) { + rc = smb1390_request_interrupt(chip, child, name); + if (rc < 0) { + pr_err("Couldn't request interrupt %s rc=%d\n", + name, rc); + return rc; + } + } + } + + return rc; +} + +static int smb1390_probe(struct platform_device *pdev) +{ + struct smb1390 *chip; + int rc; + + chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL); + if (!chip) + return -ENOMEM; + + chip->dev = &pdev->dev; + spin_lock_init(&chip->status_change_lock); + + chip->regmap = dev_get_regmap(chip->dev->parent, NULL); + if (!chip->regmap) { + pr_err("Couldn't get regmap\n"); + return -EINVAL; + } + + INIT_WORK(&chip->status_change_work, smb1390_status_change_work); + INIT_WORK(&chip->taper_work, smb1390_taper_work); + + rc = smb1390_parse_dt(chip); + if (rc < 0) { + pr_err("Couldn't parse device tree rc=%d\n", rc); + goto out_work; + } + + rc = smb1390_create_votables(chip); + if (rc < 0) { + pr_err("Couldn't create votables rc=%d\n", rc); + goto out_work; + } + + rc = smb1390_init_hw(chip); + if (rc < 0) { + pr_err("Couldn't init hardware rc=%d\n", rc); + goto out_votables; + } + + chip->nb.notifier_call = smb1390_notifier_cb; + rc = power_supply_reg_notifier(&chip->nb); + if (rc < 0) { + pr_err("Couldn't register psy notifier rc=%d\n", rc); + goto out_votables; + } + + chip->cp_class.name = "charge_pump"; + chip->cp_class.owner = THIS_MODULE; + chip->cp_class.class_groups = cp_class_groups; + rc = class_register(&chip->cp_class); + if (rc < 0) { + pr_err("Couldn't register charge_pump sysfs class rc=%d\n", rc); + goto out_notifier; + + } + + rc = smb1390_request_interrupts(chip); + if (rc < 0) { + pr_err("Couldn't request interrupts rc=%d\n", rc); + goto out_class; + } + + pr_info("smb1390 probed successfully"); + return 0; + +out_class: + class_unregister(&chip->cp_class); +out_notifier: + power_supply_unreg_notifier(&chip->nb); +out_votables: + smb1390_destroy_votables(chip); +out_work: + cancel_work(&chip->taper_work); + cancel_work(&chip->status_change_work); + return rc; +} + +static int smb1390_remove(struct platform_device *pdev) +{ + struct smb1390 *chip = platform_get_drvdata(pdev); + + class_unregister(&chip->cp_class); + power_supply_unreg_notifier(&chip->nb); + + /* explicitly disable charging */ + vote(chip->disable_votable, USER_VOTER, true, 0); + cancel_work(&chip->taper_work); + cancel_work(&chip->status_change_work); + smb1390_destroy_votables(chip); + smb1390_release_channels(chip); + return 0; +} + +static const struct of_device_id match_table[] = { + { .compatible = "qcom,smb1390-charger", }, + { }, +}; + +static struct platform_driver smb1390_driver = { + .driver = { + .name = "qcom,smb1390-charger", + .owner = THIS_MODULE, + .of_match_table = match_table, + }, + .probe = smb1390_probe, + .remove = smb1390_remove, +}; +module_platform_driver(smb1390_driver); + +MODULE_DESCRIPTION("SMB1390 Charge Pump Driver"); +MODULE_LICENSE("GPL v2"); -- GitLab From cb7ed0fa264be47e90ded7d3893b8b55c3d4dcee Mon Sep 17 00:00:00 2001 From: Guru Das Srinagesh Date: Tue, 10 Apr 2018 17:47:44 -0700 Subject: [PATCH 1212/1635] defconfig: sm8150: enable PMIC smb1390 charger driver Enable smb1390 as a companion charger for PM855B. Change-Id: I19411cbf50f459145ad0636042fdfc6d2f6d67f5 Signed-off-by: Guru Das Srinagesh --- arch/arm64/configs/sm8150-perf_defconfig | 2 ++ arch/arm64/configs/sm8150_defconfig | 2 ++ 2 files changed, 4 insertions(+) diff --git a/arch/arm64/configs/sm8150-perf_defconfig b/arch/arm64/configs/sm8150-perf_defconfig index bd4239b26df3..72be26287395 100644 --- a/arch/arm64/configs/sm8150-perf_defconfig +++ b/arch/arm64/configs/sm8150-perf_defconfig @@ -323,6 +323,7 @@ CONFIG_POWER_RESET_XGENE=y CONFIG_POWER_RESET_SYSCON=y CONFIG_QPNP_FG_GEN4=y CONFIG_QPNP_SMB5=y +CONFIG_SMB1390_CHARGE_PUMP=y CONFIG_THERMAL=y CONFIG_THERMAL_WRITABLE_TRIPS=y CONFIG_THERMAL_GOV_USER_SPACE=y @@ -339,6 +340,7 @@ CONFIG_REGULATOR_COOLING_DEVICE=y CONFIG_QTI_BCL_PMIC5=y CONFIG_QTI_BCL_SOC_DRIVER=y CONFIG_QTI_ADC_TM=y +CONFIG_MFD_I2C_PMIC=y CONFIG_MFD_SPMI_PMIC=y CONFIG_REGULATOR_FIXED_VOLTAGE=y CONFIG_REGULATOR_PROXY_CONSUMER=y diff --git a/arch/arm64/configs/sm8150_defconfig b/arch/arm64/configs/sm8150_defconfig index 5bf92e55b3dc..373a48cc8291 100644 --- a/arch/arm64/configs/sm8150_defconfig +++ b/arch/arm64/configs/sm8150_defconfig @@ -334,6 +334,7 @@ CONFIG_POWER_RESET_XGENE=y CONFIG_POWER_RESET_SYSCON=y CONFIG_QPNP_FG_GEN4=y CONFIG_QPNP_SMB5=y +CONFIG_SMB1390_CHARGE_PUMP=y CONFIG_THERMAL=y CONFIG_THERMAL_WRITABLE_TRIPS=y CONFIG_THERMAL_GOV_USER_SPACE=y @@ -350,6 +351,7 @@ CONFIG_REGULATOR_COOLING_DEVICE=y CONFIG_QTI_BCL_PMIC5=y CONFIG_QTI_BCL_SOC_DRIVER=y CONFIG_QTI_ADC_TM=y +CONFIG_MFD_I2C_PMIC=y CONFIG_MFD_SPMI_PMIC=y CONFIG_REGULATOR_FIXED_VOLTAGE=y CONFIG_REGULATOR_PROXY_CONSUMER=y -- GitLab From 40f5bcdef9508386f9f027b4e93dc971271d2642 Mon Sep 17 00:00:00 2001 From: Nicholas Troast Date: Mon, 25 Sep 2017 11:11:16 -0700 Subject: [PATCH 1213/1635] ARM: dts: msm: Add SMB1390 device and enable it on MTP and QRD Specify the configuration for the charger device that is present on SMB1390, which will be used for SM8150 platforms. Also enable SMB1390 on SM8150 MTP and QRD platforms. Change-Id: Icb08255fdc9ac15ac5e7c0423cf0298706720350 Signed-off-by: Nicholas Troast Signed-off-by: Guru Das Srinagesh --- arch/arm64/boot/dts/qcom/sm8150-mtp.dtsi | 5 +++ arch/arm64/boot/dts/qcom/sm8150-qrd.dtsi | 5 +++ arch/arm64/boot/dts/qcom/smb1390.dtsi | 56 ++++++++++++++++++++++++ 3 files changed, 66 insertions(+) create mode 100644 arch/arm64/boot/dts/qcom/smb1390.dtsi diff --git a/arch/arm64/boot/dts/qcom/sm8150-mtp.dtsi b/arch/arm64/boot/dts/qcom/sm8150-mtp.dtsi index 8af4a6d4e91d..e042088e05cb 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-mtp.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-mtp.dtsi @@ -18,6 +18,7 @@ #include "sm8150-sde-display.dtsi" #include "sm8150-camera-sensor-mtp.dtsi" #include "sm8150-thermal-overlay.dtsi" +#include "smb1390.dtsi" &qupv3_se12_2uart { status = "ok"; @@ -543,3 +544,7 @@ "usb_in_current", "chg_temp"; }; + +&smb1390_charger { + status = "ok"; +}; diff --git a/arch/arm64/boot/dts/qcom/sm8150-qrd.dtsi b/arch/arm64/boot/dts/qcom/sm8150-qrd.dtsi index 4cbc4ff67a9b..d65aab1e0c0f 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-qrd.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-qrd.dtsi @@ -18,6 +18,7 @@ #include "sm8150-sde-display.dtsi" #include "sm8150-camera-sensor-qrd.dtsi" #include "sm8150-thermal-overlay.dtsi" +#include "smb1390.dtsi" &vendor { bluetooth: bt_wcn3990 { @@ -519,3 +520,7 @@ "usb_in_current", "chg_temp"; }; + +&smb1390_charger { + status = "ok"; +}; diff --git a/arch/arm64/boot/dts/qcom/smb1390.dtsi b/arch/arm64/boot/dts/qcom/smb1390.dtsi new file mode 100644 index 000000000000..b8b8854b8c47 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/smb1390.dtsi @@ -0,0 +1,56 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include + +&qupv3_se4_i2c { + smb1390: qcom,smb1390@10 { + compatible = "qcom,i2c-pmic"; + reg = <0x10>; + #address-cells = <1>; + #size-cells = <0>; + interrupt-parent = <&spmi_bus>; + interrupts = <0x2 0xC5 0x0 IRQ_TYPE_LEVEL_LOW>; + interrupt_names = "smb1390"; + interrupt-controller; + #interrupt-cells = <3>; + qcom,periph-map = <0x10>; + + smb1390_revid: qcom,revid { + compatible = "qcom,qpnp-revid"; + reg = <0x100>; + }; + + smb1390_charger: qcom,charge_pump { + compatible = "qcom,smb1390-charger"; + qcom,pmic-revid = <&smb1390_revid>; + interrupt-parent = <&smb1390>; + status = "disabled"; + + io-channels = <&pm855b_vadc ADC_AMUX_THM2>; + io-channel-names = "cp_die_temp"; + + qcom,core { + interrupts = <0x10 0x0 IRQ_TYPE_EDGE_RISING>, + <0x10 0x1 IRQ_TYPE_EDGE_RISING>, + <0x10 0x2 IRQ_TYPE_EDGE_RISING>, + <0x10 0x3 IRQ_TYPE_EDGE_RISING>, + <0x10 0x4 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "switcher-off-window", + "switcher-off-fault", + "vph-ov-soft", + "ilim", + "temp-alarm"; + }; + }; + }; +}; -- GitLab From c79f18b605b957468bd167a67e9b579be4590f12 Mon Sep 17 00:00:00 2001 From: Narendra Muppalla Date: Wed, 25 Apr 2018 15:44:34 -0700 Subject: [PATCH 1214/1635] drm/msm/sde: retain memory for display ram dump feature DRM display module releases the splash buffer memory after first frame trigger from client. For display ram dump feature bootloader needs memory to show image in ramdump mode. This change retains memory for ramdump display. Change-Id: I6d587bceba3a35e81090786a3772f06298f6bd36 Signed-off-by: Narendra Muppalla --- drivers/gpu/drm/msm/sde/sde_hw_mdss.h | 5 +++ drivers/gpu/drm/msm/sde/sde_kms.c | 48 +++++++++++++++++++++------ 2 files changed, 42 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/msm/sde/sde_hw_mdss.h b/drivers/gpu/drm/msm/sde/sde_hw_mdss.h index b30c3f0e6f24..25e53edd5f3a 100644 --- a/drivers/gpu/drm/msm/sde/sde_hw_mdss.h +++ b/drivers/gpu/drm/msm/sde/sde_hw_mdss.h @@ -579,6 +579,9 @@ struct ctl_top { * @splash_base: Base address of continuous splash region reserved * by bootloader * @splash_size: Size of continuous splash region + * @ramdump_base: Base address of ramdump display region reserved + * by bootloader + * @ramdump_size: Size of ramdump buffer region * @top: struct ctl_top objects * @ctl_ids: stores the valid MDSS ctl block ids for the current mode * @lm_ids: stores the valid MDSS layer mixer block ids for the current mode @@ -593,6 +596,8 @@ struct sde_splash_data { bool resource_handoff_pending; unsigned long splash_base; u32 splash_size; + unsigned long ramdump_base; + u32 ramdump_size; struct ctl_top top[CTL_MAX - CTL_0]; u8 ctl_ids[CTL_MAX - CTL_0]; u8 lm_ids[LM_MAX - LM_0]; diff --git a/drivers/gpu/drm/msm/sde/sde_kms.c b/drivers/gpu/drm/msm/sde/sde_kms.c index eea767450709..cad89d399a87 100644 --- a/drivers/gpu/drm/msm/sde/sde_kms.c +++ b/drivers/gpu/drm/msm/sde/sde_kms.c @@ -801,18 +801,22 @@ static int sde_kms_prepare_secure_transition(struct msm_kms *kms, } static int _sde_kms_release_splash_buffer(unsigned int mem_addr, - unsigned int size) + unsigned int splash_buffer_size, + unsigned int ramdump_buffer_size) { unsigned long pfn_start, pfn_end, pfn_idx; int ret = 0; - if (!mem_addr || !size) + if (!mem_addr || !splash_buffer_size) SDE_ERROR("invalid params\n"); + mem_addr += ramdump_buffer_size; + splash_buffer_size -= ramdump_buffer_size; + pfn_start = mem_addr >> PAGE_SHIFT; - pfn_end = (mem_addr + size) >> PAGE_SHIFT; + pfn_end = (mem_addr + splash_buffer_size) >> PAGE_SHIFT; - ret = memblock_free(mem_addr, size); + ret = memblock_free(mem_addr, splash_buffer_size); if (ret) { SDE_ERROR("continuous splash memory free failed:%d\n", ret); return ret; @@ -993,7 +997,8 @@ static void _sde_kms_release_splash_resource(struct sde_kms *sde_kms, rc = _sde_kms_release_splash_buffer( sde_kms->splash_data.splash_base, - sde_kms->splash_data.splash_size); + sde_kms->splash_data.splash_size, + sde_kms->splash_data.ramdump_size); if (rc) pr_err("failed to release splash memory\n"); sde_kms->splash_data.splash_base = 0; @@ -1691,7 +1696,8 @@ static void _sde_kms_hw_destroy(struct sde_kms *sde_kms, _sde_kms_release_displays(sde_kms); (void)_sde_kms_release_splash_buffer( sde_kms->splash_data.splash_base, - sde_kms->splash_data.splash_size); + sde_kms->splash_data.splash_size, + sde_kms->splash_data.ramdump_size); /* safe to call these more than once during shutdown */ _sde_debugfs_destroy(sde_kms); @@ -2803,8 +2809,8 @@ static int sde_kms_pd_disable(struct generic_pm_domain *genpd) static int _sde_kms_get_splash_data(struct sde_splash_data *data) { int ret = 0; - struct device_node *parent, *node; - struct resource r; + struct device_node *parent, *node, *node1; + struct resource r, r1; if (!data) return -EINVAL; @@ -2829,9 +2835,29 @@ static int _sde_kms_get_splash_data(struct sde_splash_data *data) data->splash_base = (unsigned long)r.start; data->splash_size = (r.end - r.start) + 1; - pr_info("found continuous splash base address:%lx size:%x\n", - data->splash_base, - data->splash_size); + node1 = of_find_node_by_name(parent, "disp_rdump_region"); + if (!node1) + SDE_DEBUG("failed to find disp ramdump memory reservation\n"); + + if (!node1 || of_address_to_resource(node1, 0, &r1)) { + SDE_DEBUG("failed to find data for disp ramdump memory\n"); + data->ramdump_base = 0; + data->ramdump_size = 0; + } else { + data->ramdump_base = (unsigned long)r1.start; + data->ramdump_size = (r1.end - r1.start) + 1; + } + + if ((data->ramdump_base && data->ramdump_base != data->splash_base) || + (data->ramdump_size > data->splash_size)) { + SDE_ERROR("ramdump/splash buffer addr/size mismatched\n"); + data->ramdump_base = 0; + data->ramdump_size = 0; + } + + pr_info("cont spla base adds:%lx size:%x rdump adds=:%lx size:%x\n", + data->splash_base, data->splash_size, + data->ramdump_base, data->ramdump_size); return ret; } -- GitLab From 266ec0d5c79494bf946afca97bb30bc5203f98ec Mon Sep 17 00:00:00 2001 From: Narendra Muppalla Date: Wed, 25 Apr 2018 15:58:30 -0700 Subject: [PATCH 1215/1635] ARM: dts: msm: reserve memory for display ramdump for sm8150 Reserve memory for display ramdump feature on sm8150 target. This memory buffer would be configured by the bootloader and needs to be retained forever. Change-Id: If31a6d04a847b5a86aa29e861b55c52c5a99efb4 Signed-off-by: Narendra Muppalla --- arch/arm64/boot/dts/qcom/sm8150.dtsi | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sm8150.dtsi b/arch/arm64/boot/dts/qcom/sm8150.dtsi index eb7e9b4c7fd4..abbd150b99b1 100644 --- a/arch/arm64/boot/dts/qcom/sm8150.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150.dtsi @@ -687,6 +687,11 @@ label = "cont_splash_region"; }; + disp_rdump_memory: disp_rdump_region@9c000000 { + reg = <0x0 0x9c000000 0x0 0x00800000>; + label = "disp_rdump_region"; + }; + adsp_mem: adsp_region { compatible = "shared-dma-pool"; alloc-ranges = <0x0 0x00000000 0x0 0xffffffff>; -- GitLab From 6b5e299a62768b00328e603bb777e84e3b013ba1 Mon Sep 17 00:00:00 2001 From: Sameer Thalappil Date: Tue, 6 Feb 2018 14:54:41 -0800 Subject: [PATCH 1216/1635] icnss: Add support for early assert indication When there is a FW assert, icnss receives the PD down notification only after the PD dump is pushed to the filesystem. And if there is a delay in pushing the dump, the notification is delayed as well, that could result in various timeout in WLAN host without knowing that FW is already asserted. So add support to send FW assert early indication to host thru smp2p channel. CRs-Fixed: 2185226 Change-Id: I470f17a31ae05685e7e3a4701b32ff792e14677e Signed-off-by: Sameer Thalappil --- .../devicetree/bindings/cnss/icnss.txt | 2 + drivers/soc/qcom/icnss.c | 84 ++++++++++++++++++- drivers/soc/qcom/icnss_private.h | 2 + 3 files changed, 84 insertions(+), 4 deletions(-) diff --git a/Documentation/devicetree/bindings/cnss/icnss.txt b/Documentation/devicetree/bindings/cnss/icnss.txt index ad9d190255a0..e70109dd1098 100644 --- a/Documentation/devicetree/bindings/cnss/icnss.txt +++ b/Documentation/devicetree/bindings/cnss/icnss.txt @@ -30,6 +30,7 @@ Optional properties: - qcom,smmu-s1-bypass: Boolean context flag to set SMMU to S1 bypass - qcom,wlan-msa-fixed-region: phandle, specifier pairs to children of /reserved-memory - qcom,gpio-force-fatal-error: SMP2P bit triggered by WLAN FW to force error fatal. + - qcom,gpio-early-crash-ind: SMP2P bit triggered by WLAN FW to indicate FW is in assert. Example: @@ -61,4 +62,5 @@ Example: vdd-0.8-cx-mx-supply = <&pm8998_l5>; qcom,vdd-0.8-cx-mx-config = <800000 800000 2400 1000>; qcom,gpio-forced-fatal-error = <&smp2pgpio_wlan_1_in 0 0>; + qcom,gpio-early-crash-ind = <&smp2pgpio_wlan_1_in 1 0>; }; diff --git a/drivers/soc/qcom/icnss.c b/drivers/soc/qcom/icnss.c index f17abed813ed..c2ce85c6284f 100644 --- a/drivers/soc/qcom/icnss.c +++ b/drivers/soc/qcom/icnss.c @@ -272,6 +272,8 @@ static char *icnss_driver_event_to_str(enum icnss_driver_event_type type) return "UNREGISTER_DRIVER"; case ICNSS_DRIVER_EVENT_PD_SERVICE_DOWN: return "PD_SERVICE_DOWN"; + case ICNSS_DRIVER_EVENT_FW_EARLY_CRASH_IND: + return "FW_EARLY_CRASH_IND"; case ICNSS_DRIVER_EVENT_MAX: return "EVENT_MAX"; } @@ -633,7 +635,24 @@ static irqreturn_t fw_error_fatal_handler(int irq, void *ctx) return IRQ_HANDLED; } -static void icnss_register_force_error_fatal(struct icnss_priv *priv) +static irqreturn_t fw_crash_indication_handler(int irq, void *ctx) +{ + struct icnss_priv *priv = ctx; + + icnss_pr_err("Received early crash indication from FW\n"); + + if (priv) { + set_bit(ICNSS_FW_DOWN, &priv->state); + icnss_ignore_fw_timeout(true); + } + + icnss_driver_event_post(ICNSS_DRIVER_EVENT_FW_EARLY_CRASH_IND, + 0, NULL); + + return IRQ_HANDLED; +} + +static void register_fw_error_notifications(struct icnss_priv *priv) { int gpio, irq, ret; @@ -656,11 +675,38 @@ static void icnss_register_force_error_fatal(struct icnss_priv *priv) ret = request_irq(irq, fw_error_fatal_handler, IRQF_TRIGGER_RISING, "wlanfw-err", priv); if (ret < 0) { - icnss_pr_err("Unable to regiser for error fatal IRQ handler %d", + icnss_pr_err("Unable to register for error fatal IRQ handler %d", irq); return; } icnss_pr_dbg("FW force error fatal handler registered\n"); + + if (!of_find_property(priv->pdev->dev.of_node, + "qcom,gpio-early-crash-ind", NULL)) { + icnss_pr_dbg("FW early crash indication handler not registered\n"); + return; + } + gpio = of_get_named_gpio(priv->pdev->dev.of_node, + "qcom,gpio-early-crash-ind", 0); + if (!gpio_is_valid(gpio)) { + icnss_pr_err("Invalid GPIO for early crash indication %d\n", + gpio); + return; + } + irq = gpio_to_irq(gpio); + if (irq < 0) { + icnss_pr_err("Invalid IRQ for early crash indication %u\n", + irq); + return; + } + ret = request_irq(irq, fw_crash_indication_handler, + IRQF_TRIGGER_RISING, "wlanfw-early-crash-ind", priv); + if (ret < 0) { + icnss_pr_err("Unable to register for early crash indication IRQ handler %d", + irq); + return; + } + icnss_pr_dbg("FW crash indication handler registered\n"); } int icnss_call_driver_uevent(struct icnss_priv *priv, @@ -733,7 +779,7 @@ static int icnss_driver_event_server_arrive(void *data) wlfw_dynamic_feature_mask_send_sync_msg(penv, dynamic_feature_mask); - icnss_register_force_error_fatal(penv); + register_fw_error_notifications(penv); return ret; @@ -825,6 +871,7 @@ static int icnss_pd_restart_complete(struct icnss_priv *priv) icnss_call_driver_shutdown(priv); clear_bit(ICNSS_PD_RESTART, &priv->state); + priv->early_crash_ind = false; if (!priv->ops || !priv->ops->reinit) goto out; @@ -979,7 +1026,7 @@ static int icnss_fw_crashed(struct icnss_priv *priv, if (test_bit(ICNSS_DRIVER_PROBED, &priv->state)) icnss_call_driver_uevent(priv, ICNSS_UEVENT_FW_CRASHED, NULL); - if (event_data->fw_rejuvenate) + if (event_data && event_data->fw_rejuvenate) wlfw_rejuvenate_ack_send_sync_msg(priv); return 0; @@ -994,6 +1041,12 @@ static int icnss_driver_event_pd_service_down(struct icnss_priv *priv, if (!test_bit(ICNSS_WLFW_EXISTS, &priv->state)) goto out; + if (priv->early_crash_ind) { + icnss_pr_dbg("PD Down ignored as early indication is processed: %d, state: 0x%lx\n", + event_data->crashed, priv->state); + goto out; + } + if (test_bit(ICNSS_PD_RESTART, &priv->state) && event_data->crashed) { icnss_pr_err("PD Down while recovery inprogress, crashed: %d, state: 0x%lx\n", event_data->crashed, priv->state); @@ -1015,6 +1068,25 @@ static int icnss_driver_event_pd_service_down(struct icnss_priv *priv, return ret; } +static int icnss_driver_event_early_crash_ind(struct icnss_priv *priv, + void *data) +{ + int ret = 0; + + if (!test_bit(ICNSS_WLFW_EXISTS, &priv->state)) + goto out; + + priv->early_crash_ind = true; + icnss_fw_crashed(priv, NULL); + +out: + kfree(data); + icnss_ignore_fw_timeout(false); + + return ret; +} + + static void icnss_driver_event_work(struct work_struct *work) { struct icnss_driver_event *event; @@ -1056,6 +1128,10 @@ static void icnss_driver_event_work(struct work_struct *work) ret = icnss_driver_event_pd_service_down(penv, event->data); break; + case ICNSS_DRIVER_EVENT_FW_EARLY_CRASH_IND: + ret = icnss_driver_event_early_crash_ind(penv, + event->data); + break; default: icnss_pr_err("Invalid Event type: %d", event->type); kfree(event); diff --git a/drivers/soc/qcom/icnss_private.h b/drivers/soc/qcom/icnss_private.h index 7e77037c9248..38b0fcf1ee0a 100644 --- a/drivers/soc/qcom/icnss_private.h +++ b/drivers/soc/qcom/icnss_private.h @@ -111,6 +111,7 @@ enum icnss_driver_event_type { ICNSS_DRIVER_EVENT_REGISTER_DRIVER, ICNSS_DRIVER_EVENT_UNREGISTER_DRIVER, ICNSS_DRIVER_EVENT_PD_SERVICE_DOWN, + ICNSS_DRIVER_EVENT_FW_EARLY_CRASH_IND, ICNSS_DRIVER_EVENT_MAX, }; @@ -340,6 +341,7 @@ struct icnss_priv { bool bypass_s1_smmu; bool force_err_fatal; bool allow_recursive_recovery; + bool early_crash_ind; u8 cause_for_rejuvenation; u8 requesting_sub_system; u16 line_number; -- GitLab From 07f6ba2085c8d2b036de5b26211f8f55354b9f77 Mon Sep 17 00:00:00 2001 From: Sameer Thalappil Date: Wed, 25 Apr 2018 11:11:58 -0700 Subject: [PATCH 1217/1635] ARM: dts: msm: Add support for early assert indication Add support for early WLAN FW assert indication thru smp2p. Change-Id: I38f0e42cf0f5e054e2c6d7caa58515842034bc48 Signed-off-by: Sameer Thalappil --- arch/arm64/boot/dts/qcom/sm8150.dtsi | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/boot/dts/qcom/sm8150.dtsi b/arch/arm64/boot/dts/qcom/sm8150.dtsi index dd28cfca9eaa..54611cc3f983 100644 --- a/arch/arm64/boot/dts/qcom/sm8150.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150.dtsi @@ -3209,6 +3209,7 @@ <0 425 0 /* CE11 */ >; qcom,wlan-msa-memory = <0x100000>; qcom,gpio-force-fatal-error = <&smp2pgpio_wlan_1_in 0 0>; + qcom,gpio-early-crash-ind = <&smp2pgpio_wlan_1_in 1 0>; qcom,smmu-s1-bypass; vdd-cx-mx-supply = <&pm855_l1>; -- GitLab From 0d9a0c2d3573d9100787fe88bc0bf82a72fe77df Mon Sep 17 00:00:00 2001 From: Sudarshan Rajagopalan Date: Wed, 7 Feb 2018 16:46:59 -0800 Subject: [PATCH 1218/1635] iommu: io-pgtable-arm: Implement IOMMU_USE_LLC_NWA With the GPU moving onto a new SMMU, the override was removed due to the way MMU-500 was integrated. Hence, the method of hinting the SMMU of the upstream device's bus attributes would no longer work for GPU. Instead, encode the MAIR and TCR register through the IOMMU_USE_LLC_NWA attribute flag to map the memory into System Cache with no Write-Allocate. MAIR Encoding: Bits[7:4] => 0b1110 = Outer Write-back read-allocate, no write-allocate Bits[3:0] => 0b0100 = Inner non-cacheable normal memory TCR Encoding: SH => 0b10 = Outer Shareable ORGN => 0b11 = Write-Back, no Write-Allocate cacheable Change-Id: I34db1ebfb5f4e080ca01328176bcabc368e9ddab Signed-off-by: Sudarshan Rajagopalan --- Documentation/DMA-attributes.txt | 7 +++++++ arch/arm64/mm/dma-mapping.c | 2 ++ drivers/iommu/arm-smmu.c | 21 ++++++++++++++++++++- drivers/iommu/dma-iommu.c | 3 +++ drivers/iommu/io-pgtable-arm.c | 24 ++++++++++++++++++++++-- drivers/iommu/io-pgtable.h | 5 +++++ include/linux/dma-mapping.h | 7 +++++++ include/linux/iommu.h | 4 ++++ 8 files changed, 70 insertions(+), 3 deletions(-) diff --git a/Documentation/DMA-attributes.txt b/Documentation/DMA-attributes.txt index 8f8d97f65d73..7972942f8c19 100644 --- a/Documentation/DMA-attributes.txt +++ b/Documentation/DMA-attributes.txt @@ -156,3 +156,10 @@ accesses to DMA buffers in both privileged "supervisor" and unprivileged subsystem that the buffer is fully accessible at the elevated privilege level (and ideally inaccessible or at least read-only at the lesser-privileged levels). + +DMA_ATTR_IOMMU_USE_LLC_NWA +------------------------------------ + +DMA_ATTR_IOMMU_USE_LLC_NWA: Overrides the bus attributes to use +System Cache(LLC) with allocation policy as Inner Non-Cacheable, Outer Cacheable: +Write-Back, Read-Allocate, No Write-Allocate policy. \ No newline at end of file diff --git a/arch/arm64/mm/dma-mapping.c b/arch/arm64/mm/dma-mapping.c index 87fe156574f6..3a9b5e83c9d4 100644 --- a/arch/arm64/mm/dma-mapping.c +++ b/arch/arm64/mm/dma-mapping.c @@ -1092,6 +1092,8 @@ static int __get_iommu_pgprot(unsigned long attrs, int prot, prot |= IOMMU_NOEXEC; if (attrs & DMA_ATTR_IOMMU_USE_UPSTREAM_HINT) prot |= IOMMU_USE_UPSTREAM_HINT; + if (attrs & DMA_ATTR_IOMMU_USE_LLC_NWA) + prot |= IOMMU_USE_LLC_NWA; if (coherent) prot |= IOMMU_CACHE; diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c index 6fb07c709f26..1eaede6e1b59 100644 --- a/drivers/iommu/arm-smmu.c +++ b/drivers/iommu/arm-smmu.c @@ -1679,7 +1679,10 @@ static int arm_smmu_init_domain_context(struct iommu_domain *domain, quirks |= IO_PGTABLE_QUIRK_QCOM_USE_UPSTREAM_HINT; if (is_iommu_pt_coherent(smmu_domain)) quirks |= IO_PGTABLE_QUIRK_NO_DMA; - if ((quirks & IO_PGTABLE_QUIRK_QCOM_USE_UPSTREAM_HINT) && + if (smmu_domain->attributes & (1 << DOMAIN_ATTR_USE_LLC_NWA)) + quirks |= IO_PGTABLE_QUIRK_QCOM_USE_LLC_NWA; + if (((quirks & IO_PGTABLE_QUIRK_QCOM_USE_UPSTREAM_HINT) || + (quirks & IO_PGTABLE_QUIRK_QCOM_USE_LLC_NWA)) && (smmu->model == QCOM_SMMUV500)) quirks |= IO_PGTABLE_QUIRK_QSMMUV500_NON_SHAREABLE; @@ -2819,6 +2822,11 @@ static int arm_smmu_domain_get_attr(struct iommu_domain *domain, (1 << DOMAIN_ATTR_USE_UPSTREAM_HINT)); ret = 0; break; + case DOMAIN_ATTR_USE_LLC_NWA: + *((int *)data) = !!(smmu_domain->attributes & + (1 << DOMAIN_ATTR_USE_LLC_NWA)); + ret = 0; + break; case DOMAIN_ATTR_EARLY_MAP: *((int *)data) = !!(smmu_domain->attributes & (1 << DOMAIN_ATTR_EARLY_MAP)); @@ -3001,6 +3009,17 @@ static int arm_smmu_domain_set_attr(struct iommu_domain *domain, 1 << DOMAIN_ATTR_USE_UPSTREAM_HINT; ret = 0; break; + case DOMAIN_ATTR_USE_LLC_NWA: + /* can't be changed while attached */ + if (smmu_domain->smmu != NULL) { + ret = -EBUSY; + break; + } + if (*((int *)data)) + smmu_domain->attributes |= + 1 << DOMAIN_ATTR_USE_LLC_NWA; + ret = 0; + break; case DOMAIN_ATTR_EARLY_MAP: { int early_map = *((int *)data); diff --git a/drivers/iommu/dma-iommu.c b/drivers/iommu/dma-iommu.c index bb5c7c711f32..7ea5788f8484 100644 --- a/drivers/iommu/dma-iommu.c +++ b/drivers/iommu/dma-iommu.c @@ -381,6 +381,9 @@ int dma_info_to_prot(enum dma_data_direction dir, bool coherent, if (attrs & DMA_ATTR_IOMMU_USE_UPSTREAM_HINT) prot |= IOMMU_USE_UPSTREAM_HINT; + if (attrs & DMA_ATTR_IOMMU_USE_LLC_NWA) + prot |= IOMMU_USE_LLC_NWA; + switch (dir) { case DMA_BIDIRECTIONAL: return prot | IOMMU_READ | IOMMU_WRITE; diff --git a/drivers/iommu/io-pgtable-arm.c b/drivers/iommu/io-pgtable-arm.c index c95cddf5c06d..c26b8e9604aa 100644 --- a/drivers/iommu/io-pgtable-arm.c +++ b/drivers/iommu/io-pgtable-arm.c @@ -169,15 +169,18 @@ #define ARM_LPAE_TCR_PS_48_BIT 0x5ULL #define ARM_LPAE_MAIR_ATTR_SHIFT(n) ((n) << 3) +#define ARM_LPAE_MAIR1_ATTR_SHIFT(n) ((n-4) << 3) #define ARM_LPAE_MAIR_ATTR_MASK 0xff #define ARM_LPAE_MAIR_ATTR_DEVICE 0x04 #define ARM_LPAE_MAIR_ATTR_NC 0x44 #define ARM_LPAE_MAIR_ATTR_WBRWA 0xff #define ARM_LPAE_MAIR_ATTR_UPSTREAM 0xf4 +#define ARM_LPAE_MAIR_ATTR_LLC_NWA 0xe4 #define ARM_LPAE_MAIR_ATTR_IDX_NC 0 #define ARM_LPAE_MAIR_ATTR_IDX_CACHE 1 #define ARM_LPAE_MAIR_ATTR_IDX_DEV 2 #define ARM_LPAE_MAIR_ATTR_IDX_UPSTREAM 3 +#define ARM_LPAE_MAIR_ATTR_IDX_LLC_NWA 0x4ULL /* IOPTE accessors */ #define iopte_deref(pte, d) \ @@ -583,6 +586,9 @@ static arm_lpae_iopte arm_lpae_prot_to_pte(struct arm_lpae_io_pgtable *data, else if (prot & IOMMU_USE_UPSTREAM_HINT) pte |= (ARM_LPAE_MAIR_ATTR_IDX_UPSTREAM << ARM_LPAE_PTE_ATTRINDX_SHIFT); + else if (prot & IOMMU_USE_LLC_NWA) + pte |= (ARM_LPAE_MAIR_ATTR_IDX_LLC_NWA + << ARM_LPAE_PTE_ATTRINDX_SHIFT); } else { pte = ARM_LPAE_PTE_HAP_FAULT; if (prot & IOMMU_READ) @@ -1117,7 +1123,8 @@ arm_64_lpae_alloc_pgtable_s1(struct io_pgtable_cfg *cfg, void *cookie) if (cfg->quirks & ~(IO_PGTABLE_QUIRK_ARM_NS | IO_PGTABLE_QUIRK_NO_DMA | IO_PGTABLE_QUIRK_QCOM_USE_UPSTREAM_HINT - | IO_PGTABLE_QUIRK_QSMMUV500_NON_SHAREABLE)) + | IO_PGTABLE_QUIRK_QSMMUV500_NON_SHAREABLE + | IO_PGTABLE_QUIRK_QCOM_USE_LLC_NWA)) return NULL; data = arm_lpae_alloc_pgtable(cfg); @@ -1138,6 +1145,15 @@ arm_64_lpae_alloc_pgtable_s1(struct io_pgtable_cfg *cfg, void *cookie) reg = (ARM_LPAE_TCR_SH_OS << ARM_LPAE_TCR_SH0_SHIFT) | (ARM_LPAE_TCR_RGN_NC << ARM_LPAE_TCR_IRGN0_SHIFT) | (ARM_LPAE_TCR_RGN_WBWA << ARM_LPAE_TCR_ORGN0_SHIFT); + else if ((cfg->quirks & IO_PGTABLE_QUIRK_QCOM_USE_LLC_NWA) && + (cfg->quirks & IO_PGTABLE_QUIRK_QSMMUV500_NON_SHAREABLE)) + reg = (ARM_LPAE_TCR_SH_NS << ARM_LPAE_TCR_SH0_SHIFT) | + (ARM_LPAE_TCR_RGN_NC << ARM_LPAE_TCR_IRGN0_SHIFT) | + (ARM_LPAE_TCR_RGN_WB << ARM_LPAE_TCR_ORGN0_SHIFT); + else if (cfg->quirks & IO_PGTABLE_QUIRK_QCOM_USE_LLC_NWA) + reg = (ARM_LPAE_TCR_SH_OS << ARM_LPAE_TCR_SH0_SHIFT) | + (ARM_LPAE_TCR_RGN_NC << ARM_LPAE_TCR_IRGN0_SHIFT) | + (ARM_LPAE_TCR_RGN_WB << ARM_LPAE_TCR_ORGN0_SHIFT); else reg = (ARM_LPAE_TCR_SH_OS << ARM_LPAE_TCR_SH0_SHIFT) | (ARM_LPAE_TCR_RGN_NC << ARM_LPAE_TCR_IRGN0_SHIFT) | @@ -1195,7 +1211,11 @@ arm_64_lpae_alloc_pgtable_s1(struct io_pgtable_cfg *cfg, void *cookie) << ARM_LPAE_MAIR_ATTR_SHIFT(ARM_LPAE_MAIR_ATTR_IDX_UPSTREAM)); cfg->arm_lpae_s1_cfg.mair[0] = reg; - cfg->arm_lpae_s1_cfg.mair[1] = 0; + + reg = ARM_LPAE_MAIR_ATTR_LLC_NWA + << ARM_LPAE_MAIR1_ATTR_SHIFT(ARM_LPAE_MAIR_ATTR_IDX_LLC_NWA); + + cfg->arm_lpae_s1_cfg.mair[1] = reg; /* Looking good; allocate a pgd */ data->pgd = __arm_lpae_alloc_pages(data->pgd_size, GFP_KERNEL, diff --git a/drivers/iommu/io-pgtable.h b/drivers/iommu/io-pgtable.h index d53c22339001..2b6c758c3c38 100644 --- a/drivers/iommu/io-pgtable.h +++ b/drivers/iommu/io-pgtable.h @@ -93,6 +93,10 @@ struct io_pgtable_cfg { * set in TCR for the page table walker. Use attributes specified * by the upstream hw instead. * + * IO_PGTABLE_QUIRK_QCOM_USE_LLC_NWA: Override the attributes + * set in TCR for the page table walker with Write-Back, + * no Write-Allocate cacheable encoding. + * */ #define IO_PGTABLE_QUIRK_ARM_NS BIT(0) #define IO_PGTABLE_QUIRK_NO_PERMS BIT(1) @@ -101,6 +105,7 @@ struct io_pgtable_cfg { #define IO_PGTABLE_QUIRK_NO_DMA BIT(4) #define IO_PGTABLE_QUIRK_QSMMUV500_NON_SHAREABLE BIT(5) #define IO_PGTABLE_QUIRK_QCOM_USE_UPSTREAM_HINT BIT(6) + #define IO_PGTABLE_QUIRK_QCOM_USE_LLC_NWA BIT(7) unsigned long quirks; unsigned long pgsize_bitmap; unsigned int ias; diff --git a/include/linux/dma-mapping.h b/include/linux/dma-mapping.h index f30972e4e8ca..911b7248d6f4 100644 --- a/include/linux/dma-mapping.h +++ b/include/linux/dma-mapping.h @@ -112,6 +112,13 @@ */ #define DMA_ATTR_PRIVILEGED (1UL << 17) +/* + * DMA_ATTR_IOMMU_USE_LLC_NWA: Overrides the bus attributes to use the System + * Cache(LLC) with allocation policy as Inner Non-Cacheable, Outer Cacheable: + * Write-Back, Read-Allocate, No Write-Allocate policy. + */ +#define DMA_ATTR_IOMMU_USE_LLC_NWA (1UL << 18) + #define DMA_ERROR_CODE (~(dma_addr_t)0) /* diff --git a/include/linux/iommu.h b/include/linux/iommu.h index 9ce5316bdee6..7ea1d94ed675 100644 --- a/include/linux/iommu.h +++ b/include/linux/iommu.h @@ -46,6 +46,9 @@ /* Use upstream device's bus attribute */ #define IOMMU_USE_UPSTREAM_HINT (1 << 6) +/* Use upstream device's bus attribute with no write-allocate cache policy */ +#define IOMMU_USE_LLC_NWA (1 << 7) + struct iommu_ops; struct iommu_group; struct bus_type; @@ -155,6 +158,7 @@ enum iommu_attr { DOMAIN_ATTR_CB_STALL_DISABLE, DOMAIN_ATTR_BITMAP_IOVA_ALLOCATOR, DOMAIN_ATTR_QCOM_MMU500_ERRATA_MIN_IOVA_ALIGN, + DOMAIN_ATTR_USE_LLC_NWA, DOMAIN_ATTR_MAX, }; -- GitLab From 8b9327b8910742e32b1a6b71cd5c4c2780f09933 Mon Sep 17 00:00:00 2001 From: Ajay Singh Parmar Date: Mon, 30 Apr 2018 11:05:40 -0700 Subject: [PATCH 1219/1635] ARM: dts: msm: update dsi display nodes for sdmshrike Update the dsi device tree nodes for different displays as per new design where dsi driver is probed only once and has references to all display nodes. Change-Id: I71952e6fad8b83ddfbad8c7aaac3fec356e90392 Signed-off-by: Ajay Singh Parmar --- .../boot/dts/qcom/sdmshrike-sde-display.dtsi | 316 +++++------------- 1 file changed, 87 insertions(+), 229 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sdmshrike-sde-display.dtsi b/arch/arm64/boot/dts/qcom/sdmshrike-sde-display.dtsi index 3b0a83016880..2b007fccfb6c 100644 --- a/arch/arm64/boot/dts/qcom/sdmshrike-sde-display.dtsi +++ b/arch/arm64/boot/dts/qcom/sdmshrike-sde-display.dtsi @@ -106,376 +106,234 @@ }; dsi_sharp_4k_dsc_video_display: qcom,dsi-display@0 { - compatible = "qcom,dsi-display"; label = "dsi_sharp_4k_dsc_video_display"; qcom,display-type = "primary"; - qcom,dsi-ctrl = <&mdss_dsi0 &mdss_dsi1>; - qcom,dsi-phy = <&mdss_dsi_phy0 &mdss_dsi_phy1>; - clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>, - <&mdss_dsi0_pll PCLK_MUX_0_CLK>; - clock-names = "src_byte_clk", "src_pixel_clk"; - - pinctrl-names = "panel_active", "panel_suspend"; - pinctrl-0 = <&sde_dsi_active &sde_te_active>; - pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend>; - qcom,platform-te-gpio = <&tlmm 8 0>; - qcom,platform-reset-gpio = <&tlmm 7 0>; - qcom,panel-mode-gpio = <&tlmm 6 0>; + qcom,dsi-ctrl-num = <0 1>; + qcom,dsi-phy-num = <0 1>; + qcom,dsi-select-clocks = "src_byte_clk0", "src_pixel_clk0"; qcom,dsi-panel = <&dsi_sharp_4k_dsc_video>; - - vddio-supply = <&pm855p_l1>; - lab-supply = <&lcdb_ldo_vreg>; - ibb-supply = <&lcdb_ncp_vreg>; }; dsi_sharp_4k_dsc_cmd_display: qcom,dsi-display@1 { - compatible = "qcom,dsi-display"; label = "dsi_sharp_4k_dsc_cmd_display"; qcom,display-type = "primary"; - qcom,dsi-ctrl = <&mdss_dsi0 &mdss_dsi1>; - qcom,dsi-phy = <&mdss_dsi_phy0 &mdss_dsi_phy1>; - clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>, - <&mdss_dsi0_pll PCLK_MUX_0_CLK>; - clock-names = "src_byte_clk", "src_pixel_clk"; - - pinctrl-names = "panel_active", "panel_suspend"; - pinctrl-0 = <&sde_dsi_active &sde_te_active>; - pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend>; - qcom,platform-te-gpio = <&tlmm 8 0>; - qcom,platform-reset-gpio = <&tlmm 7 0>; - qcom,panel-mode-gpio = <&tlmm 6 0>; + qcom,dsi-ctrl-num = <0 1>; + qcom,dsi-phy-num = <0 1>; + qcom,dsi-select-clocks = "src_byte_clk0", "src_pixel_clk0"; qcom,dsi-panel = <&dsi_sharp_4k_dsc_cmd>; - vddio-supply = <&pm855p_l1>; - lab-supply = <&lcdb_ldo_vreg>; - ibb-supply = <&lcdb_ncp_vreg>; }; dsi_sharp_1080_cmd_display: qcom,dsi-display@2 { - compatible = "qcom,dsi-display"; label = "dsi_sharp_1080_cmd_display"; qcom,display-type = "primary"; - qcom,dsi-ctrl = <&mdss_dsi0>; - qcom,dsi-phy = <&mdss_dsi_phy0>; - clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>, - <&mdss_dsi0_pll PCLK_MUX_0_CLK>; - clock-names = "src_byte_clk", "src_pixel_clk"; + qcom,dsi-ctrl-num = <0>; + qcom,dsi-phy-num = <0>; + qcom,dsi-select-clocks = "src_byte_clk0", "src_pixel_clk0"; - pinctrl-names = "panel_active", "panel_suspend"; - pinctrl-0 = <&sde_dsi_active &sde_te_active>; - pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend>; - qcom,platform-te-gpio = <&tlmm 8 0>; - qcom,platform-reset-gpio = <&tlmm 7 0>; - qcom,panel-mode-gpio = <&tlmm 6 0>; qcom,dsi-panel = <&dsi_sharp_1080_cmd>; - - vddio-supply = <&pm855p_l1>; - lab-supply = <&lcdb_ldo_vreg>; - ibb-supply = <&lcdb_ncp_vreg>; }; dsi_dual_sharp_1080_120hz_cmd_display: qcom,dsi-display@3 { - compatible = "qcom,dsi-display"; label = "dsi_dual_sharp_1080_120hz_cmd_display"; qcom,display-type = "primary"; - pinctrl-names = "panel_active", "panel_suspend"; - pinctrl-0 = <&sde_dsi_active &sde_te_active>; - pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend>; - qcom,dsi-ctrl = <&mdss_dsi0 &mdss_dsi1>; - qcom,dsi-phy = <&mdss_dsi_phy0 &mdss_dsi_phy1>; - clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>, - <&mdss_dsi0_pll PCLK_MUX_0_CLK>; - clock-names = "src_byte_clk", "src_pixel_clk"; + qcom,dsi-ctrl-num = <0 1>; + qcom,dsi-phy-num = <0 1>; + qcom,dsi-select-clocks = "src_byte_clk0", "src_pixel_clk0"; - qcom,platform-te-gpio = <&tlmm 8 0>; - qcom,platform-reset-gpio = <&tlmm 7 0>; - qcom,panel-mode-gpio = <&tlmm 6 0>; qcom,dsi-panel = <&dsi_dual_sharp_1080_120hz_cmd>; - - vddio-supply = <&pm855p_l1>; - lab-supply = <&lcdb_ldo_vreg>; - ibb-supply = <&lcdb_ncp_vreg>; }; dsi_dual_nt35597_truly_video_display: qcom,dsi-display@4 { - compatible = "qcom,dsi-display"; label = "dsi_dual_nt35597_truly_video_display"; qcom,display-type = "primary"; - qcom,dsi-ctrl = <&mdss_dsi0 &mdss_dsi1>; - qcom,dsi-phy = <&mdss_dsi_phy0 &mdss_dsi_phy1>; - clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>, - <&mdss_dsi0_pll PCLK_MUX_0_CLK>; - clock-names = "src_byte_clk", "src_pixel_clk"; + qcom,dsi-ctrl-num = <0 1>; + qcom,dsi-phy-num = <0 1>; + qcom,dsi-select-clocks = "src_byte_clk0", "src_pixel_clk0"; - pinctrl-names = "panel_active", "panel_suspend"; - pinctrl-0 = <&sde_dsi_active &sde_te_active>; - pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend>; - qcom,platform-te-gpio = <&tlmm 8 0>; - qcom,platform-reset-gpio = <&tlmm 7 0>; - qcom,panel-mode-gpio = <&tlmm 6 0>; qcom,dsi-panel = <&dsi_dual_nt35597_truly_video>; - - vddio-supply = <&pm855p_l1>; - lab-supply = <&lcdb_ldo_vreg>; - ibb-supply = <&lcdb_ncp_vreg>; }; dsi_dual_nt35597_truly_cmd_display: qcom,dsi-display@5 { - compatible = "qcom,dsi-display"; label = "dsi_dual_nt35597_truly_cmd_display"; qcom,display-type = "primary"; - qcom,dsi-ctrl = <&mdss_dsi0 &mdss_dsi1>; - qcom,dsi-phy = <&mdss_dsi_phy0 &mdss_dsi_phy1>; - clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>, - <&mdss_dsi0_pll PCLK_MUX_0_CLK>; - clock-names = "src_byte_clk", "src_pixel_clk"; + qcom,dsi-ctrl-num = <0 1>; + qcom,dsi-phy-num = <0 1>; + qcom,dsi-select-clocks = "src_byte_clk0", "src_pixel_clk0"; - pinctrl-names = "panel_active", "panel_suspend"; - pinctrl-0 = <&sde_dsi_active &sde_te_active>; - pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend>; - qcom,platform-te-gpio = <&tlmm 8 0>; - qcom,platform-reset-gpio = <&tlmm 7 0>; - qcom,panel-mode-gpio = <&tlmm 6 0>; qcom,dsi-panel = <&dsi_dual_nt35597_truly_cmd>; - - vddio-supply = <&pm855p_l1>; - lab-supply = <&lcdb_ldo_vreg>; - ibb-supply = <&lcdb_ncp_vreg>; }; dsi_nt35597_truly_dsc_cmd_display: qcom,dsi-display@6 { - compatible = "qcom,dsi-display"; label = "dsi_nt35597_truly_dsc_cmd_display"; qcom,display-type = "primary"; - qcom,dsi-ctrl = <&mdss_dsi1>; - qcom,dsi-phy = <&mdss_dsi_phy1>; - clocks = <&mdss_dsi1_pll BYTECLK_MUX_1_CLK>, - <&mdss_dsi1_pll PCLK_MUX_1_CLK>; - clock-names = "src_byte_clk", "src_pixel_clk"; + qcom,dsi-ctrl-num = <1>; + qcom,dsi-phy-num = <1>; + qcom,dsi-select-clocks = "src_byte_clk1", "src_pixel_clk1"; - pinctrl-names = "panel_active", "panel_suspend"; - pinctrl-0 = <&sde_dsi_active &sde_te_active>; - pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend>; - qcom,platform-te-gpio = <&tlmm 8 0>; - qcom,platform-reset-gpio = <&tlmm 7 0>; - qcom,panel-mode-gpio = <&tlmm 6 0>; qcom,dsi-panel = <&dsi_nt35597_truly_dsc_cmd>; - - vddio-supply = <&pm855p_l1>; - lab-supply = <&lcdb_ldo_vreg>; - ibb-supply = <&lcdb_ncp_vreg>; }; dsi_nt35597_truly_dsc_video_display: qcom,dsi-display@7 { - compatible = "qcom,dsi-display"; label = "dsi_nt35597_truly_dsc_video_display"; qcom,display-type = "primary"; - qcom,dsi-ctrl = <&mdss_dsi1>; - qcom,dsi-phy = <&mdss_dsi_phy1>; - clocks = <&mdss_dsi1_pll BYTECLK_MUX_1_CLK>, - <&mdss_dsi1_pll PCLK_MUX_1_CLK>; - clock-names = "src_byte_clk", "src_pixel_clk"; + qcom,dsi-ctrl-num = <1>; + qcom,dsi-phy-num = <1>; + qcom,dsi-select-clocks = "src_byte_clk1", "src_pixel_clk1"; - pinctrl-names = "panel_active", "panel_suspend"; - pinctrl-0 = <&sde_dsi_active &sde_te_active>; - pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend>; - qcom,platform-te-gpio = <&tlmm 8 0>; - qcom,platform-reset-gpio = <&tlmm 7 0>; - qcom,panel-mode-gpio = <&tlmm 6 0>; qcom,dsi-panel = <&dsi_nt35597_truly_dsc_video>; - - vddio-supply = <&pm855p_l1>; - lab-supply = <&lcdb_ldo_vreg>; - ibb-supply = <&lcdb_ncp_vreg>; }; dsi_sim_vid_display: qcom,dsi-display@8 { - compatible = "qcom,dsi-display"; label = "dsi_sim_vid_display"; qcom,display-type = "primary"; - qcom,dsi-ctrl = <&mdss_dsi0>; - qcom,dsi-phy = <&mdss_dsi_phy0>; - clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>, - <&mdss_dsi0_pll PCLK_MUX_0_CLK>; - clock-names = "src_byte_clk", "src_pixel_clk"; - - pinctrl-names = "panel_active", "panel_suspend"; - pinctrl-0 = <&sde_dsi_active &sde_te_active>; - pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend>; + qcom,dsi-ctrl-num = <0>; + qcom,dsi-phy-num = <0>; + qcom,dsi-select-clocks = "src_byte_clk0", "src_pixel_clk0"; qcom,dsi-panel = <&dsi_sim_vid>; }; dsi_dual_sim_vid_display: qcom,dsi-display@9 { - compatible = "qcom,dsi-display"; label = "dsi_dual_sim_vid_display"; qcom,display-type = "primary"; - qcom,dsi-ctrl = <&mdss_dsi0 &mdss_dsi1>; - qcom,dsi-phy = <&mdss_dsi_phy0 &mdss_dsi_phy1>; - clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>, - <&mdss_dsi0_pll PCLK_MUX_0_CLK>; - clock-names = "src_byte_clk", "src_pixel_clk"; - - pinctrl-names = "panel_active", "panel_suspend"; - pinctrl-0 = <&sde_dsi_active &sde_te_active>; - pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend>; + qcom,dsi-ctrl-num = <0 1>; + qcom,dsi-phy-num = <0 1>; + qcom,dsi-select-clocks = "src_byte_clk0", "src_pixel_clk0"; qcom,dsi-panel = <&dsi_dual_sim_vid>; }; dsi_sim_cmd_display: qcom,dsi-display@10 { - compatible = "qcom,dsi-display"; label = "dsi_sim_cmd_display"; qcom,display-type = "primary"; - qcom,dsi-ctrl = <&mdss_dsi0>; - qcom,dsi-phy = <&mdss_dsi_phy0>; - clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>, - <&mdss_dsi0_pll PCLK_MUX_0_CLK>; - clock-names = "src_byte_clk", "src_pixel_clk"; - - pinctrl-names = "panel_active", "panel_suspend"; - pinctrl-0 = <&sde_dsi_active &sde_te_active>; - pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend>; + qcom,dsi-ctrl-num = <0>; + qcom,dsi-phy-num = <0>; + qcom,dsi-select-clocks = "src_byte_clk0", "src_pixel_clk0"; qcom,dsi-panel = <&dsi_sim_cmd>; }; dsi_dual_sim_cmd_display: qcom,dsi-display@11 { - compatible = "qcom,dsi-display"; label = "dsi_dual_sim_cmd_display"; qcom,display-type = "primary"; - qcom,dsi-ctrl = <&mdss_dsi0 &mdss_dsi1>; - qcom,dsi-phy = <&mdss_dsi_phy0 &mdss_dsi_phy1>; - clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>, - <&mdss_dsi0_pll PCLK_MUX_0_CLK>; - clock-names = "src_byte_clk", "src_pixel_clk"; - - pinctrl-names = "panel_active", "panel_suspend"; - pinctrl-0 = <&sde_dsi_active &sde_te_active>; - pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend>; + qcom,dsi-ctrl-num = <0 1>; + qcom,dsi-phy-num = <0 1>; + qcom,dsi-select-clocks = "src_byte_clk0", "src_pixel_clk0"; qcom,dsi-panel = <&dsi_dual_sim_cmd>; }; dsi_sim_dsc_375_cmd_display: qcom,dsi-display@12 { - compatible = "qcom,dsi-display"; label = "dsi_sim_dsc_375_cmd_display"; qcom,display-type = "primary"; - qcom,dsi-ctrl = <&mdss_dsi0>; - qcom,dsi-phy = <&mdss_dsi_phy0>; - clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>, - <&mdss_dsi0_pll PCLK_MUX_0_CLK>; - clock-names = "src_byte_clk", "src_pixel_clk"; - - pinctrl-names = "panel_active", "panel_suspend"; - pinctrl-0 = <&sde_dsi_active &sde_te_active>; - pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend>; + qcom,dsi-ctrl-num = <0>; + qcom,dsi-phy-num = <0>; + qcom,dsi-select-clocks = "src_byte_clk0", "src_pixel_clk0"; qcom,dsi-panel = <&dsi_sim_dsc_375_cmd>; }; dsi_dual_sim_dsc_375_cmd_display: qcom,dsi-display@13 { - compatible = "qcom,dsi-display"; label = "dsi_dual_sim_dsc_375_cmd_display"; qcom,display-type = "primary"; - qcom,dsi-ctrl = <&mdss_dsi0 &mdss_dsi1>; - qcom,dsi-phy = <&mdss_dsi_phy0 &mdss_dsi_phy1>; - clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>, - <&mdss_dsi0_pll PCLK_MUX_0_CLK>; - clock-names = "src_byte_clk", "src_pixel_clk"; - - pinctrl-names = "panel_active", "panel_suspend"; - pinctrl-0 = <&sde_dsi_active &sde_te_active>; - pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend>; + qcom,dsi-ctrl-num = <0 1>; + qcom,dsi-phy-num = <0 1>; + qcom,dsi-select-clocks = "src_byte_clk0", "src_pixel_clk0"; qcom,dsi-panel = <&dsi_dual_sim_dsc_375_cmd>; }; dsi_sw43404_amoled_cmd_display: qcom,dsi-display@14 { - compatible = "qcom,dsi-display"; label = "dsi_sw43404_amoled_cmd_display"; qcom,display-type = "primary"; - qcom,dsi-ctrl = <&mdss_dsi0>; - qcom,dsi-phy = <&mdss_dsi_phy0>; - clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>, - <&mdss_dsi0_pll PCLK_MUX_0_CLK>; - clock-names = "src_byte_clk", "src_pixel_clk"; - - pinctrl-names = "panel_active", "panel_suspend"; - pinctrl-0 = <&sde_dsi_active &sde_te_active>; - pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend>; - qcom,platform-te-gpio = <&tlmm 8 0>; - qcom,platform-reset-gpio = <&tlmm 7 0>; - qcom,panel-mode-gpio = <&tlmm 6 0>; + qcom,dsi-ctrl-num = <0>; + qcom,dsi-phy-num = <0>; + qcom,dsi-select-clocks = "src_byte_clk0", "src_pixel_clk0"; qcom,dsi-panel = <&dsi_sw43404_amoled_cmd>; - vddio-supply = <&pm855p_l1>; }; dsi_nt35695b_truly_fhd_cmd_display: qcom,dsi-display@15 { - compatible = "qcom,dsi-display"; label = "dsi_nt35695b_truly_fhd_cmd_display"; qcom,display-type = "primary"; - qcom,dsi-ctrl = <&mdss_dsi0>; - qcom,dsi-phy = <&mdss_dsi_phy0>; - clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>, - <&mdss_dsi0_pll PCLK_MUX_0_CLK>; - clock-names = "src_byte_clk", "src_pixel_clk"; - - pinctrl-names = "panel_active", "panel_suspend"; - pinctrl-0 = <&sde_dsi_active &sde_te_active>; - pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend>; - qcom,platform-te-gpio = <&tlmm 8 0>; - qcom,platform-reset-gpio = <&tlmm 7 0>; - qcom,panel-mode-gpio = <&tlmm 6 0>; + qcom,dsi-ctrl-num = <0>; + qcom,dsi-phy-num = <0>; + qcom,dsi-select-clocks = "src_byte_clk0", "src_pixel_clk0"; qcom,dsi-panel = <&dsi_nt35695b_truly_fhd_cmd>; - vddio-supply = <&pm855p_l1>; - lab-supply = <&lcdb_ldo_vreg>; - ibb-supply = <&lcdb_ncp_vreg>; }; dsi_nt35695b_truly_fhd_video_display: qcom,dsi-display@16 { - compatible = "qcom,dsi-display"; label = "dsi_nt35695b_truly_fhd_video_display"; qcom,display-type = "primary"; - qcom,dsi-ctrl = <&mdss_dsi0>; - qcom,dsi-phy = <&mdss_dsi_phy0>; + qcom,dsi-ctrl-num = <0>; + qcom,dsi-phy-num = <0>; + qcom,dsi-select-clocks = "src_byte_clk0", "src_pixel_clk0"; + + qcom,dsi-panel = <&dsi_nt35695b_truly_fhd_video>; + }; + + sde_dsi: qcom,dsi-display { + compatible = "qcom,dsi-display"; + + qcom,dsi-ctrl = <&mdss_dsi0 &mdss_dsi1>; + qcom,dsi-phy = <&mdss_dsi_phy0 &mdss_dsi_phy1>; + clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>, - <&mdss_dsi0_pll PCLK_MUX_0_CLK>; - clock-names = "src_byte_clk", "src_pixel_clk"; + <&mdss_dsi0_pll PCLK_MUX_0_CLK>, + <&mdss_dsi1_pll BYTECLK_MUX_1_CLK>, + <&mdss_dsi1_pll PCLK_MUX_1_CLK>; + clock-names = "src_byte_clk0", "src_pixel_clk0", + "src_byte_clk1", "src_pixel_clk1"; pinctrl-names = "panel_active", "panel_suspend"; pinctrl-0 = <&sde_dsi_active &sde_te_active>; pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend>; - qcom,platform-te-gpio = <&tlmm 8 0>; - qcom,platform-reset-gpio = <&tlmm 7 0>; - qcom,panel-mode-gpio = <&tlmm 6 0>; - qcom,dsi-panel = <&dsi_nt35695b_truly_fhd_video>; + qcom,platform-te-gpio = <&tlmm 8 0>; vddio-supply = <&pm855p_l1>; lab-supply = <&lcdb_ldo_vreg>; ibb-supply = <&lcdb_ncp_vreg>; + + qcom,dsi-display-list = + <&dsi_sharp_4k_dsc_video_display + &dsi_sharp_4k_dsc_cmd_display + &dsi_sharp_1080_cmd_display + &dsi_dual_sharp_1080_120hz_cmd_display + &dsi_dual_nt35597_truly_video_display + &dsi_dual_nt35597_truly_cmd_display + &dsi_nt35597_truly_dsc_cmd_display + &dsi_nt35597_truly_dsc_video_display + &dsi_sim_vid_display + &dsi_dual_sim_vid_display + &dsi_sim_cmd_display + &dsi_dual_sim_cmd_display + &dsi_sim_dsc_375_cmd_display + &dsi_dual_sim_dsc_375_cmd_display + &dsi_sw43404_amoled_cmd_display + &dsi_nt35695b_truly_fhd_cmd_display + &dsi_nt35695b_truly_fhd_video_display>; }; sde_wb: qcom,wb-display@0 { @@ -494,7 +352,7 @@ }; &mdss_mdp { - connectors = <&sde_wb>; + connectors = <&sde_wb &sde_dsi>; }; /* PHY TIMINGS REVISION P */ -- GitLab From cc972f42c47072e33157b80733d7be88d33c459d Mon Sep 17 00:00:00 2001 From: Dhaval Patel Date: Wed, 21 Mar 2018 19:18:13 -0700 Subject: [PATCH 1220/1635] drm/msm: allow ab/ib vote update without rsc client Allow ab/ib vote update without rsc client to avoid failure log message. Change-Id: I5ae29122838430b880e1e823b4ceb9e6d9046b34 Signed-off-by: Dhaval Patel --- drivers/gpu/drm/msm/sde_rsc.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/msm/sde_rsc.c b/drivers/gpu/drm/msm/sde_rsc.c index 3a70746fae1e..f811ca149b36 100644 --- a/drivers/gpu/drm/msm/sde_rsc.c +++ b/drivers/gpu/drm/msm/sde_rsc.c @@ -898,23 +898,22 @@ EXPORT_SYMBOL(sde_rsc_client_state_update); int sde_rsc_client_vote(struct sde_rsc_client *caller_client, u32 bus_id, u64 ab_vote, u64 ib_vote) { - int rc = 0; + int rc = 0, rsc_index; struct sde_rsc_priv *rsc; - if (!caller_client) { - pr_err("invalid client for ab/ib vote\n"); - return -EINVAL; - } else if (caller_client->rsc_index >= MAX_RSC_COUNT) { + if (caller_client && caller_client->rsc_index >= MAX_RSC_COUNT) { pr_err("invalid rsc index\n"); return -EINVAL; } - rsc = rsc_prv_list[caller_client->rsc_index]; + rsc_index = caller_client ? caller_client->rsc_index : SDE_RSC_INDEX; + rsc = rsc_prv_list[rsc_index]; if (!rsc) return -EINVAL; pr_debug("client:%s ab:%llu ib:%llu\n", - caller_client->name, ab_vote, ib_vote); + caller_client ? caller_client->name : "unknown", + ab_vote, ib_vote); mutex_lock(&rsc->client_lock); rc = sde_rsc_clk_enable(&rsc->phandle, rsc->pclient, true); -- GitLab From 9428ec4e7bfdab1b06c481e5154df3c2863c7785 Mon Sep 17 00:00:00 2001 From: Sriharsha Allenki Date: Tue, 20 Mar 2018 10:34:56 +0530 Subject: [PATCH 1221/1635] ARM: dts: msm: Add USB related nodes for QCS405 Add basic USB nodes to support USB in peripheral mode for QCS405. Signed-off-by: Sriharsha Allenki Change-Id: I193fbd30be832123e6c9bdf5c2d2c163bf2ddf07 --- arch/arm64/boot/dts/qcom/qcs405-rumi.dtsi | 32 +++++++++++++++++++ arch/arm64/boot/dts/qcom/qcs405.dtsi | 38 +++++++++++++++++++++++ 2 files changed, 70 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/qcs405-rumi.dtsi b/arch/arm64/boot/dts/qcom/qcs405-rumi.dtsi index 4c27aa9f1ea2..6fa2c1767ac2 100644 --- a/arch/arm64/boot/dts/qcom/qcs405-rumi.dtsi +++ b/arch/arm64/boot/dts/qcom/qcs405-rumi.dtsi @@ -13,6 +13,30 @@ #include "qcs405.dtsi" &soc { + usb_emu_phy: usb_emu_phy@78ccd00 { + compatible = "qcom,usb-emu-phy"; + reg = <0x78ccd00 0x9500>, + <0x79b8800 0x100>; + reg-names = "base", "qcratch_base"; + + qcom,emu-init-seq = <0xfff0 0x4 + 0xfff3 0x4 + 0x40 0x4 + 0xfff3 0x4 + 0xfff0 0x4 + 0x100000 0x20 + 0x0 0x20 + 0x1a0 0x20 + 0x100000 0x3c + 0x0 0x3c + 0x10060 0x3c + 0x0 0x4>; + }; + + usb_nop_phy: usb_nop_phy { + compatible = "usb-nop-xceiv"; + }; + timer { clock-frequency = <0x100000>; }; @@ -21,3 +45,11 @@ clock-frequency = <0x100000>; }; }; + +&usb0 { + dwc3@78c0000 { + usb-phy = <&usb_emu_phy>, <&usb_nop_phy>; + maximum-speed = "high-speed"; + dr_mode = "peripheral"; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/qcs405.dtsi b/arch/arm64/boot/dts/qcom/qcs405.dtsi index ddec57236062..e1cfd5b30826 100644 --- a/arch/arm64/boot/dts/qcom/qcs405.dtsi +++ b/arch/arm64/boot/dts/qcom/qcs405.dtsi @@ -275,6 +275,44 @@ }; thermal_zones: thermal-zones {}; + + usb0: hsusb@78c0000 { + compatible = "qcom,dwc-usb3-msm"; + reg = <0x78c0000 0x100000>; + reg-names = "core_base"; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + interrupts = <0 32 0>; + interrupt-names = "pwr_event_irq"; + /* Using dummy Xo clock, need to check the proper mapping */ + clocks = <&clock_gcc GCC_USB_HS_SYSTEM_CLK>, + <&clock_gcc GCC_PCNOC_USB2_CLK>, + <&clock_gcc GCC_USB30_SLEEP_CLK>, + <&clock_gcc GCC_USB_HS_INACTIVITY_TIMERS_CLK>, + <&clock_gcc GCC_USB20_MOCK_UTMI_CLK>; + clock-names = "core_clk", "iface_clk", "xo", + "sleep_clk", "utmi_clk"; + + qcom,core-clk-rate = <200000000>; + qcom,core-clk-rate-hs = <66666667>; + qcom,dwc-usb3-msm-tx-fifo-size = <27696>; + resets = <&clock_gcc GCC_USB_HS_BCR>; + reset-names = "core_reset"; + + dwc3@78c0000 { + compatible = "snps,dwc3"; + reg = <0x78c0000 0xcd00>; + interrupt-parent = <&intc>; + interrupts = <0 44 0>; + tx-fifo-resize; + linux,sysdev_is_parent; + snps,disable-clk-gating; + snps,has-lpm-erratum; + snps,hird-threshold = /bits/ 8 <0x10>; + }; + }; }; #include "qcs405-gdsc.dtsi" -- GitLab From 7a6a4f7dcac13b88c24bd2a1e12b85c2c8af8a6b Mon Sep 17 00:00:00 2001 From: Sriharsha Allenki Date: Thu, 12 Apr 2018 15:30:21 +0530 Subject: [PATCH 1222/1635] defconfig: Enable USB related configs for QCS405 Enable USB related configs to enable USB on QCS405 rumi. Signed-off-by: Sriharsha Allenki Change-Id: Ib9b6f2003c4549f414447bd71e124b7142c5cc1a --- arch/arm/configs/qcs405_defconfig | 6 ++++++ arch/arm64/configs/qcs405_defconfig | 5 +++++ 2 files changed, 11 insertions(+) diff --git a/arch/arm/configs/qcs405_defconfig b/arch/arm/configs/qcs405_defconfig index 5ee3a2fef45c..98019caeae14 100644 --- a/arch/arm/configs/qcs405_defconfig +++ b/arch/arm/configs/qcs405_defconfig @@ -257,6 +257,7 @@ CONFIG_SPI_DEBUG=y CONFIG_SPI_SPIDEV=y CONFIG_PINCTRL_QCS405=y CONFIG_GPIOLIB=y +CONFIG_POWER_SUPPLY=y CONFIG_THERMAL=y CONFIG_MFD_SYSCON=y CONFIG_REGULATOR=y @@ -302,14 +303,19 @@ CONFIG_USB_STORAGE_ALAUDA=y CONFIG_USB_STORAGE_KARMA=y CONFIG_USB_STORAGE_CYPRESS_ATACB=y CONFIG_USB_DWC3=y +CONFIG_USB_DWC3_MSM=y CONFIG_USB_SERIAL=y CONFIG_USB_EHSET_TEST_FIXTURE=y CONFIG_NOP_USB_XCEIV=y +CONFIG_USB_QCOM_EMU_PHY=y CONFIG_DUAL_ROLE_USB_INTF=y CONFIG_USB_GADGET=y CONFIG_USB_GADGET_DEBUG_FILES=y CONFIG_USB_GADGET_DEBUG_FS=y CONFIG_USB_GADGET_VBUS_DRAW=500 +CONFIG_USB_CONFIGFS=y +CONFIG_USB_CONFIGFS_F_FS=y +CONFIG_USB_CONFIGFS_F_DIAG=y CONFIG_MMC=y CONFIG_MMC_BLOCK_MINORS=32 CONFIG_MMC_TEST=m diff --git a/arch/arm64/configs/qcs405_defconfig b/arch/arm64/configs/qcs405_defconfig index 64f939a877af..cb95c7374bcc 100644 --- a/arch/arm64/configs/qcs405_defconfig +++ b/arch/arm64/configs/qcs405_defconfig @@ -303,14 +303,19 @@ CONFIG_USB_STORAGE_ALAUDA=y CONFIG_USB_STORAGE_KARMA=y CONFIG_USB_STORAGE_CYPRESS_ATACB=y CONFIG_USB_DWC3=y +CONFIG_USB_DWC3_MSM=y CONFIG_USB_SERIAL=y CONFIG_USB_EHSET_TEST_FIXTURE=y CONFIG_NOP_USB_XCEIV=y +CONFIG_USB_QCOM_EMU_PHY=y CONFIG_DUAL_ROLE_USB_INTF=y CONFIG_USB_GADGET=y CONFIG_USB_GADGET_DEBUG_FILES=y CONFIG_USB_GADGET_DEBUG_FS=y CONFIG_USB_GADGET_VBUS_DRAW=500 +CONFIG_USB_CONFIGFS=y +CONFIG_USB_CONFIGFS_F_FS=y +CONFIG_USB_CONFIGFS_F_DIAG=y CONFIG_MMC=y CONFIG_MMC_BLOCK_MINORS=32 CONFIG_MMC_TEST=m -- GitLab From b70692367dbb7353bbad8ddee80e2a0e630cf2a4 Mon Sep 17 00:00:00 2001 From: Dhoat Harpal Date: Mon, 30 Apr 2018 19:30:06 +0530 Subject: [PATCH 1223/1635] ARM: dts: msm: Add MPROC device nodes for QCS405 Add SMEM, TCSR Mutex, Glink and SMP2P devices for enabling interprocessor communication with MPSS, LPASS and CDSP. CRs-Fixed: 2223479 Change-Id: If9de674da77a040c4cc465b7f6b9cf0e07a1b953 Signed-off-by: Dhoat Harpal --- arch/arm64/boot/dts/qcom/qcs405.dtsi | 200 +++++++++++++++++++++++++++ 1 file changed, 200 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/qcs405.dtsi b/arch/arm64/boot/dts/qcom/qcs405.dtsi index ddec57236062..5315abcbafef 100644 --- a/arch/arm64/boot/dts/qcom/qcs405.dtsi +++ b/arch/arm64/boot/dts/qcom/qcs405.dtsi @@ -11,6 +11,7 @@ * GNU General Public License for more details. */ +#include #include "skeleton64.dtsi" #include #include @@ -30,6 +31,11 @@ #address-cells = <2>; #size-cells = <2>; ranges; + + smem_region: smem@85f00000 { + no-map; + reg = <0x0 0x85f00000 0x0 0x200000>; + }; }; aliases { }; @@ -274,6 +280,200 @@ #thermal-sensor-cells = <1>; }; + tcsr_mutex_block: syscon@1905000 { + compatible = "syscon"; + reg = <0x1905000 0x20000>; + }; + + tcsr_mutex: hwlock { + compatible = "qcom,tcsr-mutex"; + syscon = <&tcsr_mutex_block 0 0x1000>; + #hwlock-cells = <1>; + }; + + smem: qcom,smem { + compatible = "qcom,smem"; + memory-region = <&smem_region>; + hwlocks = <&tcsr_mutex 3>; + }; + + rpm_msg_ram: memory@60000 { + compatible = "qcom,rpm-msg-ram"; + reg = <0x60000 0x6000>; + }; + + apcs: syscon@b011000 { + compatible = "syscon"; + reg = <0xb011000 0x4>; + }; + + apcs_glb: mailbox@b011000 { + compatible = "qcom,msm8916-apcs-kpss-global"; + reg = <0xb011000 0x1000>; + + #mbox-cells = <1>; + }; + + rpm-glink { + compatible = "qcom,glink-rpm"; + interrupts = ; + qcom,rpm-msg-ram = <&rpm_msg_ram>; + mboxes = <&apcs_glb 0>; + }; + + qcom,glink { + compatible = "qcom,glink"; + modem { + qcom,remote-pid = <1>; + transport = "smem"; + mboxes = <&apcs_glb 16>; + mbox-names = "mpss_smem"; + interrupts = ; + + modem_qrtr { + qcom,glink-channels = "IPCRTR"; + qcom,intents = <0x800 5 + 0x2000 3 + 0x4400 2>; + }; + }; + + adsp { + qcom,remote-pid = <2>; + transport = "smem"; + mboxes = <&apcs_glb 8>; + mbox-names = "adsp_smem"; + interrupts = ; + + adsp_qrtr { + qcom,glink-channels = "IPCRTR"; + qcom,intents = <0x800 5 + 0x2000 3 + 0x4400 2>; + }; + + apr_tal_rpmsg { + qcom,glink-channels = "apr_audio_svc"; + qcom,intents = <0x200 20>; + }; + }; + + cdsp { + qcom,remote-pid = <5>; + transport = "smem"; + mboxes = <&apcs_glb 12>; + mbox-names = "cdsp_smem"; + interrupts = ; + + cdsp_qrtr { + qcom,glink-channels = "IPCRTR"; + qcom,intents = <0x800 5 + 0x2000 3 + 0x4400 2>; + }; + }; + }; + + qcom,glinkpkt { + compatible = "qcom,glinkpkt"; + + qcom,glinkpkt-at-mdm0 { + qcom,glinkpkt-edge = "mpss"; + qcom,glinkpkt-ch-name = "DS"; + qcom,glinkpkt-dev-name = "at_mdm0"; + }; + + qcom,glinkpkt-apr-apps2 { + qcom,glinkpkt-edge = "adsp"; + qcom,glinkpkt-ch-name = "apr_apps2"; + qcom,glinkpkt-dev-name = "apr_apps2"; + }; + + qcom,glinkpkt-data40-cntl { + qcom,glinkpkt-edge = "mpss"; + qcom,glinkpkt-ch-name = "DATA40_CNTL"; + qcom,glinkpkt-dev-name = "smdcntl8"; + }; + + qcom,glinkpkt-data1 { + qcom,glinkpkt-edge = "mpss"; + qcom,glinkpkt-ch-name = "DATA1"; + qcom,glinkpkt-dev-name = "smd7"; + }; + + qcom,glinkpkt-data4 { + qcom,glinkpkt-edge = "mpss"; + qcom,glinkpkt-ch-name = "DATA4"; + qcom,glinkpkt-dev-name = "smd8"; + }; + + qcom,glinkpkt-data11 { + qcom,glinkpkt-edge = "mpss"; + qcom,glinkpkt-ch-name = "DATA11"; + qcom,glinkpkt-dev-name = "smd11"; + }; + }; + + qcom,smp2p-modem { + compatible = "qcom,smp2p"; + qcom,smem = <435>, <428>; + interrupts = ; + qcom,ipc = <&apcs 0 18>; + qcom,local-pid = <0>; + qcom,remote-pid = <1>; + + modem_smp2p_out: master-kernel { + qcom,entry-name = "master-kernel"; + #qcom,smem-state-cells = <1>; + }; + + modem_smp2p_in: slave-kernel { + qcom,entry-name = "slave-kernel"; + interrupt-controller; + #interrupt-cells = <2>; + }; + }; + + qcom,smp2p-adsp { + compatible = "qcom,smp2p"; + qcom,smem = <443>, <429>; + interrupts = ; + qcom,ipc = <&apcs 0 10>; + qcom,local-pid = <0>; + qcom,remote-pid = <2>; + + adsp_smp2p_out: master-kernel { + qcom,entry-name = "master-kernel"; + #qcom,smem-state-cells = <1>; + }; + + adsp_smp2p_in: slave-kernel { + qcom,entry-name = "slave-kernel"; + interrupt-controller; + #interrupt-cells = <2>; + }; + }; + + qcom,smp2p-cdsp { + compatible = "qcom,smp2p"; + qcom,smem = <94>, <432>; + interrupts = ; + qcom,ipc = <&apcs 0 14>; + qcom,local-pid = <0>; + qcom,remote-pid = <5>; + + cdsp_smp2p_out: master-kernel { + qcom,entry-name = "master-kernel"; + #qcom,smem-state-cells = <1>; + }; + + cdsp_smp2p_in: slave-kernel { + qcom,entry-name = "slave-kernel"; + interrupt-controller; + #interrupt-cells = <2>; + }; + }; + thermal_zones: thermal-zones {}; }; -- GitLab From 50b76e4b5e9ae4786cd96dd88ebbd66d09c4d05b Mon Sep 17 00:00:00 2001 From: Deepak Kumar Date: Tue, 24 Apr 2018 14:11:53 +0530 Subject: [PATCH 1224/1635] msm: kgsl: Track RSCC sleep sequence state RSCC wake-up sequence should only be triggered if RSCC sleep sequence was done earlier i.e. they should always be balanced to make sure GMU FW, RSCC and PDC state are in sync. Add GMU_RSCC_SLEEP_SEQ_DONE GMU flag to track whether RSCC sleep sequence was done or not and trigger sleep and wake-up sequence based on this flag to make they are always balanced. Change-Id: I78d8be52a770bd6e939da91fa68b6fd01f10034e Signed-off-by: Deepak Kumar --- drivers/gpu/msm/adreno_a6xx_gmu.c | 15 ++++++++++++--- drivers/gpu/msm/kgsl_gmu.c | 4 ++-- drivers/gpu/msm/kgsl_gmu.h | 5 ++--- 3 files changed, 16 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/msm/adreno_a6xx_gmu.c b/drivers/gpu/msm/adreno_a6xx_gmu.c index e73da1e2db7d..bb9ac7dfb43c 100644 --- a/drivers/gpu/msm/adreno_a6xx_gmu.c +++ b/drivers/gpu/msm/adreno_a6xx_gmu.c @@ -319,6 +319,10 @@ static int a6xx_rpmh_power_on_gpu(struct kgsl_device *device) struct device *dev = &gmu->pdev->dev; int val; + /* Only trigger wakeup sequence if sleep sequence was done earlier */ + if (!test_bit(GMU_RSCC_SLEEP_SEQ_DONE, &gmu->flags)) + return 0; + kgsl_gmu_regread(device, A6XX_GPU_CC_GX_DOMAIN_MISC, &val); if (!(val & 0x1)) dev_err_ratelimited(&gmu->pdev->dev, @@ -348,6 +352,9 @@ static int a6xx_rpmh_power_on_gpu(struct kgsl_device *device) kgsl_gmu_regwrite(device, A6XX_GMU_RSCC_CONTROL_REQ, 0); + /* Clear sleep sequence flag as wakeup sequence is successful */ + clear_bit(GMU_RSCC_SLEEP_SEQ_DONE, &gmu->flags); + /* Enable the power counter because it was disabled before slumber */ kgsl_gmu_regwrite(device, A6XX_GMU_CX_GMU_POWER_COUNTER_ENABLE, 1); @@ -363,6 +370,9 @@ static int a6xx_rpmh_power_off_gpu(struct kgsl_device *device) struct adreno_device *adreno_dev = ADRENO_DEVICE(device); int ret; + if (test_bit(GMU_RSCC_SLEEP_SEQ_DONE, &gmu->flags)) + return 0; + /* RSC sleep sequence is different on v1 */ if (adreno_is_a630v1(adreno_dev)) kgsl_gmu_regwrite(device, A6XX_RSCC_TIMESTAMP_UNIT1_EN_DRV0, 1); @@ -405,6 +415,7 @@ static int a6xx_rpmh_power_off_gpu(struct kgsl_device *device) test_bit(ADRENO_LM_CTRL, &adreno_dev->pwrctrl_flag)) kgsl_gmu_regwrite(device, A6XX_GMU_AO_SPARE_CNTL, 0); + set_bit(GMU_RSCC_SLEEP_SEQ_DONE, &gmu->flags); return 0; } @@ -851,15 +862,13 @@ static int a6xx_gmu_fw_start(struct kgsl_device *device, unsigned int chipid = 0; switch (boot_state) { - case GMU_RESET: - /* fall through */ case GMU_COLD_BOOT: /* Turn on TCM retention */ kgsl_gmu_regwrite(device, A6XX_GMU_GENERAL_7, 1); if (!test_and_set_bit(GMU_BOOT_INIT_DONE, &gmu->flags)) _load_gmu_rpmh_ucode(device); - else if (boot_state != GMU_RESET) { + else { ret = a6xx_rpmh_power_on_gpu(device); if (ret) return ret; diff --git a/drivers/gpu/msm/kgsl_gmu.c b/drivers/gpu/msm/kgsl_gmu.c index 4a5cc48903f0..084fbb4fc005 100644 --- a/drivers/gpu/msm/kgsl_gmu.c +++ b/drivers/gpu/msm/kgsl_gmu.c @@ -1729,7 +1729,7 @@ int gmu_start(struct kgsl_device *device) gmu_irq_enable(device); ret = gpudev->rpmh_gpu_pwrctrl( - adreno_dev, GMU_FW_START, GMU_RESET, 0); + adreno_dev, GMU_FW_START, GMU_COLD_BOOT, 0); if (ret) goto error_gmu; @@ -1746,7 +1746,7 @@ int gmu_start(struct kgsl_device *device) hfi_stop(gmu); ret = gpudev->rpmh_gpu_pwrctrl(adreno_dev, GMU_FW_START, - GMU_RESET, 0); + GMU_COLD_BOOT, 0); if (ret) goto error_gmu; diff --git a/drivers/gpu/msm/kgsl_gmu.h b/drivers/gpu/msm/kgsl_gmu.h index 39d249403bb9..a02566758cb4 100644 --- a/drivers/gpu/msm/kgsl_gmu.h +++ b/drivers/gpu/msm/kgsl_gmu.h @@ -99,6 +99,7 @@ enum gmu_flags { GMU_DCVS_REPLAY, GMU_GPMU, GMU_ENABLED, + GMU_RSCC_SLEEP_SEQ_DONE, }; /** @@ -136,13 +137,11 @@ struct rpmh_votes_t { /* * These are the different ways the GMU can boot. GMU_WARM_BOOT is waking up - * from slumber. GMU_COLD_BOOT is booting for the first time. GMU_RESET - * is a soft reset of the GMU. + * from slumber. GMU_COLD_BOOT is booting for the first time. */ enum gmu_boot { GMU_WARM_BOOT = 0, GMU_COLD_BOOT = 1, - GMU_RESET = 2 }; enum gmu_load_mode { -- GitLab From 9b9c16b87cb26b9113aa2934aba8610452f0e2fd Mon Sep 17 00:00:00 2001 From: Mahesh Sivasubramanian Date: Tue, 31 Oct 2017 14:53:25 +0530 Subject: [PATCH 1225/1635] qos: Pass the list of cpus with affected qos to notifer Send the list of cpus whose qos has been affected along with the changed value. Driver listening in for notifier can use this to apply the qos value for the respective cpus. Wakeup cpus even if the aggregated qos value does not change but the cpumask changes. Change-Id: I8f3c2ea624784c806c55de41cc7c7fcf8ebf02da Signed-off-by: Mahesh Sivasubramanian Signed-off-by: Maulik Shah --- kernel/power/qos.c | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/kernel/power/qos.c b/kernel/power/qos.c index bb8207515f51..64b5c0e5187d 100644 --- a/kernel/power/qos.c +++ b/kernel/power/qos.c @@ -266,7 +266,8 @@ static const struct file_operations pm_qos_debug_fops = { .release = single_release, }; -static inline void pm_qos_set_value_for_cpus(struct pm_qos_constraints *c) +static inline void pm_qos_set_value_for_cpus(struct pm_qos_constraints *c, + struct cpumask *cpus) { struct pm_qos_request *req = NULL; int cpu; @@ -292,8 +293,11 @@ static inline void pm_qos_set_value_for_cpus(struct pm_qos_constraints *c) } } - for_each_possible_cpu(cpu) + for_each_possible_cpu(cpu) { + if (c->target_per_cpu[cpu] != qos_val[cpu]) + cpumask_set_cpu(cpu, cpus); c->target_per_cpu[cpu] = qos_val[cpu]; + } } /** @@ -312,6 +316,7 @@ int pm_qos_update_target(struct pm_qos_constraints *c, struct plist_node *node, { unsigned long flags; int prev_value, curr_value, new_value; + struct cpumask cpus; int ret; spin_lock_irqsave(&pm_qos_lock, flags); @@ -342,18 +347,24 @@ int pm_qos_update_target(struct pm_qos_constraints *c, struct plist_node *node, } curr_value = pm_qos_get_value(c); + cpumask_clear(&cpus); pm_qos_set_value(c, curr_value); - pm_qos_set_value_for_cpus(c); + pm_qos_set_value_for_cpus(c, &cpus); spin_unlock_irqrestore(&pm_qos_lock, flags); trace_pm_qos_update_target(action, prev_value, curr_value); - if (prev_value != curr_value) { + + /* + * if cpu mask bits are set, call the notifier call chain + * to update the new qos restriction for the cores + */ + + if (!cpumask_empty(&cpus)) { ret = 1; if (c->notifiers) blocking_notifier_call_chain(c->notifiers, - (unsigned long)curr_value, - NULL); + (unsigned long)curr_value, &cpus); } else { ret = 0; } -- GitLab From 3d756e207a804c3809166c6c2438a63c99f43963 Mon Sep 17 00:00:00 2001 From: Saranya Chidura Date: Tue, 1 May 2018 16:40:49 +0530 Subject: [PATCH 1226/1635] coresight: tmc: add iommu header file Coresight ETR uses IOMMU mapping. Include the IOMMU header file for proper functionality. Change-Id: I83f000028f0149cb4ac51572910200c6fb7ec377 Signed-off-by: Saranya Chidura --- drivers/hwtracing/coresight/coresight-tmc.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/hwtracing/coresight/coresight-tmc.c b/drivers/hwtracing/coresight/coresight-tmc.c index 54b208b8809a..fd7a7e1f11fa 100644 --- a/drivers/hwtracing/coresight/coresight-tmc.c +++ b/drivers/hwtracing/coresight/coresight-tmc.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include "coresight-priv.h" -- GitLab From a3f651d8879429bb58052c7b4b19e084060c3faa Mon Sep 17 00:00:00 2001 From: Raghavendra Kakarla Date: Thu, 26 Apr 2018 15:15:32 +0530 Subject: [PATCH 1227/1635] drivers: lpm-levels: return zero for parse_cluster_params function return zero from parse_cluster_params when parse params successfully. Change-Id: I3d3eeb0de8a2568031b4fb24e72c7749c50f8204 Signed-off-by: Raghavendra Kakarla --- drivers/cpuidle/lpm-levels-of.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/cpuidle/lpm-levels-of.c b/drivers/cpuidle/lpm-levels-of.c index 9e001c18ccb9..c3e3a9ce4706 100644 --- a/drivers/cpuidle/lpm-levels-of.c +++ b/drivers/cpuidle/lpm-levels-of.c @@ -474,7 +474,7 @@ static int parse_cluster_params(struct device_node *node, /* Set default_level to 0 as default */ c->default_level = 0; - return ret; + return 0; fail: pr_err("Failed to read key: %s ret: %d\n", key, ret); -- GitLab From c60d298e400e5ea05a9dfa9aef475a2815632de8 Mon Sep 17 00:00:00 2001 From: Konstantin Dorfman Date: Tue, 1 May 2018 17:24:01 +0300 Subject: [PATCH 1228/1635] soc: qcom: spcom: create control channel For commands that don't required SPU communication (is-link-up and create channel), instead of using sp_kernel channel (the one used for application loading) use /dev/spcom control channel. Change-Id: I6e66949f7eb4ef9822b0b5ab37e9146c7ce23ab3 Signed-off-by: Kineret Berger Signed-off-by: Konstantin Dorfman --- drivers/soc/qcom/spcom.c | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/drivers/soc/qcom/spcom.c b/drivers/soc/qcom/spcom.c index 828d3f4a976b..5394445ecfc4 100644 --- a/drivers/soc/qcom/spcom.c +++ b/drivers/soc/qcom/spcom.c @@ -981,6 +981,11 @@ static int spcom_handle_write(struct spcom_channel *ch, pr_debug("cmd_id [0x%x]\n", cmd_id); + if (!ch && cmd_id != SPCOM_CMD_CREATE_CHANNEL) { + pr_err("channel context is null\n"); + return -EINVAL; + } + switch (cmd_id) { case SPCOM_CMD_SEND: ret = spcom_handle_send_command(ch, buf, buf_size); @@ -1350,14 +1355,17 @@ static ssize_t spcom_device_write(struct file *filp, ch = filp->private_data; if (!ch) { - pr_err("invalid ch pointer, command not allowed.\n"); - return -EINVAL; - } - - /* Check if remote side connect */ - if (!spcom_is_channel_connected(ch)) { - pr_err("ch [%s] remote side not connected\n", ch->name); - return -ENOTCONN; + if (strcmp(name, DEVICE_NAME) != 0) { + pr_err("invalid ch pointer, command not allowed.\n"); + return -EINVAL; + } + pr_debug("control device - no channel context.\n"); + } else { + /* Check if remote side connect */ + if (!spcom_is_channel_connected(ch)) { + pr_err("ch [%s] remote side not connect.\n", ch->name); + return -ENOTCONN; + } } if (size > SPCOM_MAX_COMMAND_SIZE) { @@ -2079,7 +2087,7 @@ static int __init spcom_init(void) { int ret; - pr_debug("spcom driver version 2.0 4-Mar-2018\n"); + pr_info("spcom driver version 2.1 23-April-2018.\n"); ret = platform_driver_register(&spcom_driver); if (ret) -- GitLab From 83a9a284eb69b6629ed2b37aa49745f2595b7948 Mon Sep 17 00:00:00 2001 From: Sami Tolvanen Date: Mon, 30 Apr 2018 12:23:14 -0700 Subject: [PATCH 1229/1635] cfi: print target address on failure Bug: 78862212 Bug: 67506682 Change-Id: Ifaa3e3f8fc5f19649f4857d185d50383b4a89055 Signed-off-by: Sami Tolvanen --- kernel/cfi.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/kernel/cfi.c b/kernel/cfi.c index 7c403dc5091c..c32e6b358797 100644 --- a/kernel/cfi.c +++ b/kernel/cfi.c @@ -24,12 +24,12 @@ #define cfi_slowpath_handler __cfi_slowpath #endif /* CONFIG_CFI_PERMISSIVE */ -static inline void handle_cfi_failure() +static inline void handle_cfi_failure(void *ptr) { #ifdef CONFIG_CFI_PERMISSIVE - WARN_RATELIMIT(1, "CFI failure:\n"); + WARN_RATELIMIT(1, "CFI failure (target: [<%px>] %pF):\n", ptr, ptr); #else - pr_err("CFI failure:\n"); + pr_err("CFI failure (target: [<%px>] %pF):\n", ptr, ptr); BUG(); #endif } @@ -283,18 +283,18 @@ void cfi_slowpath_handler(uint64_t id, void *ptr, void *diag) if (likely(check)) check(id, ptr, diag); else /* Don't allow unchecked modules */ - handle_cfi_failure(); + handle_cfi_failure(ptr); } EXPORT_SYMBOL(cfi_slowpath_handler); #endif /* CONFIG_MODULES */ -void cfi_failure_handler(void *data, void *value, void *vtable) +void cfi_failure_handler(void *data, void *ptr, void *vtable) { - handle_cfi_failure(); + handle_cfi_failure(ptr); } EXPORT_SYMBOL(cfi_failure_handler); -void __cfi_check_fail(void *data, void *value) +void __cfi_check_fail(void *data, void *ptr) { - handle_cfi_failure(); + handle_cfi_failure(ptr); } -- GitLab From 19dd742f109f5ddb3cdd0c79d4acee2876f442af Mon Sep 17 00:00:00 2001 From: "Isaac J. Manjarres" Date: Tue, 1 May 2018 10:27:08 -0700 Subject: [PATCH 1230/1635] defconfig: Enable full reference count validation Enable full reference count validation to avoid use-after-free cases that may appear because of reference count overflows. Change-Id: I48fd937efaba9754a1bdd48ca27ffac45eaad852 Signed-off-by: Isaac J. Manjarres --- arch/arm64/configs/sm8150-perf_defconfig | 1 + arch/arm64/configs/sm8150_defconfig | 1 + 2 files changed, 2 insertions(+) diff --git a/arch/arm64/configs/sm8150-perf_defconfig b/arch/arm64/configs/sm8150-perf_defconfig index bd4239b26df3..46678d76a8c4 100644 --- a/arch/arm64/configs/sm8150-perf_defconfig +++ b/arch/arm64/configs/sm8150-perf_defconfig @@ -43,6 +43,7 @@ CONFIG_SLAB_FREELIST_RANDOM=y CONFIG_SLAB_FREELIST_HARDENED=y CONFIG_PROFILING=y CONFIG_CC_STACKPROTECTOR_STRONG=y +CONFIG_REFCOUNT_FULL=y CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y CONFIG_MODULE_FORCE_UNLOAD=y diff --git a/arch/arm64/configs/sm8150_defconfig b/arch/arm64/configs/sm8150_defconfig index 5bf92e55b3dc..18326758f2bc 100644 --- a/arch/arm64/configs/sm8150_defconfig +++ b/arch/arm64/configs/sm8150_defconfig @@ -43,6 +43,7 @@ CONFIG_SLAB_FREELIST_RANDOM=y CONFIG_SLAB_FREELIST_HARDENED=y CONFIG_PROFILING=y CONFIG_CC_STACKPROTECTOR_STRONG=y +CONFIG_REFCOUNT_FULL=y CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y CONFIG_MODULE_FORCE_UNLOAD=y -- GitLab From d1b23ee9e752bdba17eb133f053bed71ba0342ed Mon Sep 17 00:00:00 2001 From: Michael Adisumarta Date: Tue, 1 May 2018 10:28:27 -0700 Subject: [PATCH 1231/1635] msm: ipa4: USB_CONS QMB update for 4.1 Change USB CONS register to use DDR instead of PCIE Change-Id: I45e1dce339f079866a3dc3ffd343d9becc0068fa Crs-fixed: 2219398 Signed-off-by: Michael Adisumarta --- drivers/platform/msm/ipa/ipa_v3/ipa_utils.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c index 873418eb1a30..78641106fef1 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c @@ -1613,7 +1613,7 @@ static const struct ipa_ep_configuration ipa3_ep_mapping true, IPA_v4_0_GROUP_UL_DL, false, IPA_DPS_HPS_SEQ_TYPE_INVALID, - QMB_MASTER_SELECT_PCIE, + QMB_MASTER_SELECT_DDR, { 19, 12, 9, 9, IPA_EE_AP } }, [IPA_4_1][IPA_CLIENT_USB_DPL_CONS] = { true, IPA_v4_0_GROUP_UL_DL, -- GitLab From d4ce94ce405ffebdd0dc336767a6b190669a58fe Mon Sep 17 00:00:00 2001 From: Chris Lew Date: Wed, 18 Apr 2018 17:55:28 -0700 Subject: [PATCH 1232/1635] soc: qcom: glink_probe: Add support for spi transport Add support to probe the glink spi transport for the wdsp processor. The WDSP processor notifiers about SSR through a component manager instead of the PIL SSR framework. If the SPI transport is required, register the SPI transport immediately instead of waiting for an up notification from the SSR framework. Change-Id: I313b6acae305d43a0e328c78fde255243be76eab Signed-off-by: Chris Lew --- drivers/soc/qcom/glink_probe.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/soc/qcom/glink_probe.c b/drivers/soc/qcom/glink_probe.c index cc1b52387a0b..89655eda90d0 100644 --- a/drivers/soc/qcom/glink_probe.c +++ b/drivers/soc/qcom/glink_probe.c @@ -364,6 +364,15 @@ static void probe_subsystem(struct device *dev, struct device_node *np) } else if (!strcmp(transport, "spss")) { einfo->register_fn = glink_probe_spss_reg; einfo->unregister_fn = glink_probe_spss_unreg; + } else if (!strcmp(transport, "spi")) { + /* SPI SSR is self contained */ + einfo->glink = qcom_glink_spi_register(dev, np); + if (IS_ERR_OR_NULL(einfo->glink)) { + GLINK_ERR(dev, "%s failed\n", einfo->ssr_label); + goto free_einfo; + } + list_add_tail(&einfo->list, &edge_infos); + return; } einfo->nb.notifier_call = glink_probe_ssr_cb; -- GitLab From 1a538cb0879d8646437836d540b6e952d9103f63 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Thu, 12 Apr 2018 11:48:09 -0400 Subject: [PATCH 1233/1635] ext4: prevent right-shifting extents beyond EXT_MAX_BLOCKS commit 349fa7d6e1935f49bf4161c4900711b2989180a9 upstream. During the "insert range" fallocate operation, extents starting at the range offset are shifted "right" (to a higher file offset) by the range length. But, as shown by syzbot, it's not validated that this doesn't cause extents to be shifted beyond EXT_MAX_BLOCKS. In that case ->ee_block can wrap around, corrupting the extent tree. Fix it by returning an error if the space between the end of the last extent and EXT4_MAX_BLOCKS is smaller than the range being inserted. This bug can be reproduced by running the following commands when the current directory is on an ext4 filesystem with a 4k block size: fallocate -l 8192 file fallocate --keep-size -o 0xfffffffe000 -l 4096 -n file fallocate --insert-range -l 8192 file Then after unmounting the filesystem, e2fsck reports corruption. Reported-by: syzbot+06c885be0edcdaeab40c@syzkaller.appspotmail.com Fixes: 331573febb6a ("ext4: Add support FALLOC_FL_INSERT_RANGE for fallocate") Cc: stable@vger.kernel.org # v4.2+ Signed-off-by: Eric Biggers Signed-off-by: Theodore Ts'o Signed-off-by: Greg Kroah-Hartman --- fs/ext4/extents.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index c941251ac0c0..883e89a903d1 100644 --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c @@ -5346,8 +5346,9 @@ ext4_ext_shift_extents(struct inode *inode, handle_t *handle, stop = le32_to_cpu(extent->ee_block); /* - * In case of left shift, Don't start shifting extents until we make - * sure the hole is big enough to accommodate the shift. + * For left shifts, make sure the hole on the left is big enough to + * accommodate the shift. For right shifts, make sure the last extent + * won't be shifted beyond EXT_MAX_BLOCKS. */ if (SHIFT == SHIFT_LEFT) { path = ext4_find_extent(inode, start - 1, &path, @@ -5367,9 +5368,14 @@ ext4_ext_shift_extents(struct inode *inode, handle_t *handle, if ((start == ex_start && shift > ex_start) || (shift > start - ex_end)) { - ext4_ext_drop_refs(path); - kfree(path); - return -EINVAL; + ret = -EINVAL; + goto out; + } + } else { + if (shift > EXT_MAX_BLOCKS - + (stop + ext4_ext_get_actual_len(extent))) { + ret = -EINVAL; + goto out; } } -- GitLab From 4a3674acbf8b076bb42b68f5d95f0877acabf210 Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Wed, 18 Apr 2018 11:49:31 -0400 Subject: [PATCH 1234/1635] ext4: set h_journal if there is a failure starting a reserved handle commit b2569260d55228b617bd82aba6d0db2faeeb4116 upstream. If ext4 tries to start a reserved handle via jbd2_journal_start_reserved(), and the journal has been aborted, this can result in a NULL pointer dereference. This is because the fields h_journal and h_transaction in the handle structure share the same memory, via a union, so jbd2_journal_start_reserved() will clear h_journal before calling start_this_handle(). If this function fails due to an aborted handle, h_journal will still be NULL, and the call to jbd2_journal_free_reserved() will pass a NULL journal to sub_reserve_credits(). This can be reproduced by running "kvm-xfstests -c dioread_nolock generic/475". Cc: stable@kernel.org # 3.11 Fixes: 8f7d89f36829b ("jbd2: transaction reservation support") Signed-off-by: Theodore Ts'o Reviewed-by: Andreas Dilger Reviewed-by: Jan Kara Signed-off-by: Greg Kroah-Hartman --- fs/jbd2/transaction.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/jbd2/transaction.c b/fs/jbd2/transaction.c index c0681814c379..07793e25c976 100644 --- a/fs/jbd2/transaction.c +++ b/fs/jbd2/transaction.c @@ -535,6 +535,7 @@ int jbd2_journal_start_reserved(handle_t *handle, unsigned int type, */ ret = start_this_handle(journal, handle, GFP_NOFS); if (ret < 0) { + handle->h_journal = journal; jbd2_journal_free_reserved(handle); return ret; } -- GitLab From 55cc3bb0a6c7da92dd1332cc8e1651dc2be89bfc Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Thu, 26 Apr 2018 00:44:46 -0400 Subject: [PATCH 1235/1635] ext4: add MODULE_SOFTDEP to ensure crc32c is included in the initramfs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 7ef79ad52136712172eb0525bf0b462516bf2f93 upstream. Fixes: a45403b51582 ("ext4: always initialize the crc32c checksum driver") Reported-by: François Valenduc Signed-off-by: Theodore Ts'o Cc: stable@vger.kernel.org Signed-off-by: Greg Kroah-Hartman --- fs/ext4/super.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 3a605c672649..9102ae7709d3 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -5865,5 +5865,6 @@ static void __exit ext4_exit_fs(void) MODULE_AUTHOR("Remy Card, Stephen Tweedie, Andrew Morton, Andreas Dilger, Theodore Ts'o and others"); MODULE_DESCRIPTION("Fourth Extended Filesystem"); MODULE_LICENSE("GPL"); +MODULE_SOFTDEP("pre: crc32c"); module_init(ext4_init_fs) module_exit(ext4_exit_fs) -- GitLab From b39430ea068797bb45b72429db3743064280b1be Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Mon, 26 Mar 2018 23:54:10 -0400 Subject: [PATCH 1236/1635] ext4: add validity checks for bitmap block numbers commit 7dac4a1726a9c64a517d595c40e95e2d0d135f6f upstream. An privileged attacker can cause a crash by mounting a crafted ext4 image which triggers a out-of-bounds read in the function ext4_valid_block_bitmap() in fs/ext4/balloc.c. This issue has been assigned CVE-2018-1093. BugLink: https://bugzilla.kernel.org/show_bug.cgi?id=199181 BugLink: https://bugzilla.redhat.com/show_bug.cgi?id=1560782 Reported-by: Wen Xu Signed-off-by: Theodore Ts'o Cc: stable@vger.kernel.org Signed-off-by: Greg Kroah-Hartman --- fs/ext4/balloc.c | 16 ++++++++++++++-- fs/ext4/ialloc.c | 7 +++++++ 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/fs/ext4/balloc.c b/fs/ext4/balloc.c index db5be5e2e6f2..6dafd9d001c7 100644 --- a/fs/ext4/balloc.c +++ b/fs/ext4/balloc.c @@ -338,20 +338,25 @@ static ext4_fsblk_t ext4_valid_block_bitmap(struct super_block *sb, /* check whether block bitmap block number is set */ blk = ext4_block_bitmap(sb, desc); offset = blk - group_first_block; - if (!ext4_test_bit(EXT4_B2C(sbi, offset), bh->b_data)) + if (offset < 0 || EXT4_B2C(sbi, offset) >= sb->s_blocksize || + !ext4_test_bit(EXT4_B2C(sbi, offset), bh->b_data)) /* bad block bitmap */ return blk; /* check whether the inode bitmap block number is set */ blk = ext4_inode_bitmap(sb, desc); offset = blk - group_first_block; - if (!ext4_test_bit(EXT4_B2C(sbi, offset), bh->b_data)) + if (offset < 0 || EXT4_B2C(sbi, offset) >= sb->s_blocksize || + !ext4_test_bit(EXT4_B2C(sbi, offset), bh->b_data)) /* bad block bitmap */ return blk; /* check whether the inode table block number is set */ blk = ext4_inode_table(sb, desc); offset = blk - group_first_block; + if (offset < 0 || EXT4_B2C(sbi, offset) >= sb->s_blocksize || + EXT4_B2C(sbi, offset + sbi->s_itb_per_group) >= sb->s_blocksize) + return blk; next_zero_bit = ext4_find_next_zero_bit(bh->b_data, EXT4_B2C(sbi, offset + EXT4_SB(sb)->s_itb_per_group), EXT4_B2C(sbi, offset)); @@ -417,6 +422,7 @@ struct buffer_head * ext4_read_block_bitmap_nowait(struct super_block *sb, ext4_group_t block_group) { struct ext4_group_desc *desc; + struct ext4_sb_info *sbi = EXT4_SB(sb); struct buffer_head *bh; ext4_fsblk_t bitmap_blk; int err; @@ -425,6 +431,12 @@ ext4_read_block_bitmap_nowait(struct super_block *sb, ext4_group_t block_group) if (!desc) return ERR_PTR(-EFSCORRUPTED); bitmap_blk = ext4_block_bitmap(sb, desc); + if ((bitmap_blk <= le32_to_cpu(sbi->s_es->s_first_data_block)) || + (bitmap_blk >= ext4_blocks_count(sbi->s_es))) { + ext4_error(sb, "Invalid block bitmap block %llu in " + "block_group %u", bitmap_blk, block_group); + return ERR_PTR(-EFSCORRUPTED); + } bh = sb_getblk(sb, bitmap_blk); if (unlikely(!bh)) { ext4_error(sb, "Cannot get buffer for block bitmap - " diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c index 7ec55dd8db56..f420124ac035 100644 --- a/fs/ext4/ialloc.c +++ b/fs/ext4/ialloc.c @@ -122,6 +122,7 @@ static struct buffer_head * ext4_read_inode_bitmap(struct super_block *sb, ext4_group_t block_group) { struct ext4_group_desc *desc; + struct ext4_sb_info *sbi = EXT4_SB(sb); struct buffer_head *bh = NULL; ext4_fsblk_t bitmap_blk; int err; @@ -131,6 +132,12 @@ ext4_read_inode_bitmap(struct super_block *sb, ext4_group_t block_group) return ERR_PTR(-EFSCORRUPTED); bitmap_blk = ext4_inode_bitmap(sb, desc); + if ((bitmap_blk <= le32_to_cpu(sbi->s_es->s_first_data_block)) || + (bitmap_blk >= ext4_blocks_count(sbi->s_es))) { + ext4_error(sb, "Invalid inode bitmap blk %llu in " + "block_group %u", bitmap_blk, block_group); + return ERR_PTR(-EFSCORRUPTED); + } bh = sb_getblk(sb, bitmap_blk); if (unlikely(!bh)) { ext4_error(sb, "Cannot read inode bitmap - " -- GitLab From ae0db58dabe5463dcbcce095e83177536ed22d6a Mon Sep 17 00:00:00 2001 From: Lukas Czerner Date: Tue, 24 Apr 2018 11:31:44 -0400 Subject: [PATCH 1237/1635] ext4: fix bitmap position validation commit 22be37acce25d66ecf6403fc8f44df9c5ded2372 upstream. Currently in ext4_valid_block_bitmap() we expect the bitmap to be positioned anywhere between 0 and s_blocksize clusters, but that's wrong because the bitmap can be placed anywhere in the block group. This causes false positives when validating bitmaps on perfectly valid file system layouts. Fix it by checking whether the bitmap is within the group boundary. The problem can be reproduced using the following mkfs -t ext3 -E stride=256 /dev/vdb1 mount /dev/vdb1 /mnt/test cd /mnt/test wget https://cdn.kernel.org/pub/linux/kernel/v4.x/linux-4.16.3.tar.xz tar xf linux-4.16.3.tar.xz This will result in the warnings in the logs EXT4-fs error (device vdb1): ext4_validate_block_bitmap:399: comm tar: bg 84: block 2774529: invalid block bitmap [ Changed slightly for clarity and to not drop a overflow test -- TYT ] Signed-off-by: Lukas Czerner Signed-off-by: Theodore Ts'o Reported-by: Ilya Dryomov Fixes: 7dac4a1726a9 ("ext4: add validity checks for bitmap block numbers") Cc: stable@vger.kernel.org Signed-off-by: Greg Kroah-Hartman --- fs/ext4/balloc.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/fs/ext4/balloc.c b/fs/ext4/balloc.c index 6dafd9d001c7..58db8109defa 100644 --- a/fs/ext4/balloc.c +++ b/fs/ext4/balloc.c @@ -321,6 +321,7 @@ static ext4_fsblk_t ext4_valid_block_bitmap(struct super_block *sb, struct ext4_sb_info *sbi = EXT4_SB(sb); ext4_grpblk_t offset; ext4_grpblk_t next_zero_bit; + ext4_grpblk_t max_bit = EXT4_CLUSTERS_PER_GROUP(sb); ext4_fsblk_t blk; ext4_fsblk_t group_first_block; @@ -338,7 +339,7 @@ static ext4_fsblk_t ext4_valid_block_bitmap(struct super_block *sb, /* check whether block bitmap block number is set */ blk = ext4_block_bitmap(sb, desc); offset = blk - group_first_block; - if (offset < 0 || EXT4_B2C(sbi, offset) >= sb->s_blocksize || + if (offset < 0 || EXT4_B2C(sbi, offset) >= max_bit || !ext4_test_bit(EXT4_B2C(sbi, offset), bh->b_data)) /* bad block bitmap */ return blk; @@ -346,7 +347,7 @@ static ext4_fsblk_t ext4_valid_block_bitmap(struct super_block *sb, /* check whether the inode bitmap block number is set */ blk = ext4_inode_bitmap(sb, desc); offset = blk - group_first_block; - if (offset < 0 || EXT4_B2C(sbi, offset) >= sb->s_blocksize || + if (offset < 0 || EXT4_B2C(sbi, offset) >= max_bit || !ext4_test_bit(EXT4_B2C(sbi, offset), bh->b_data)) /* bad block bitmap */ return blk; @@ -354,8 +355,8 @@ static ext4_fsblk_t ext4_valid_block_bitmap(struct super_block *sb, /* check whether the inode table block number is set */ blk = ext4_inode_table(sb, desc); offset = blk - group_first_block; - if (offset < 0 || EXT4_B2C(sbi, offset) >= sb->s_blocksize || - EXT4_B2C(sbi, offset + sbi->s_itb_per_group) >= sb->s_blocksize) + if (offset < 0 || EXT4_B2C(sbi, offset) >= max_bit || + EXT4_B2C(sbi, offset + sbi->s_itb_per_group) >= max_bit) return blk; next_zero_bit = ext4_find_next_zero_bit(bh->b_data, EXT4_B2C(sbi, offset + EXT4_SB(sb)->s_itb_per_group), -- GitLab From 812b51a630005ed8d0a947bece1f430474b724bf Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Wed, 11 Apr 2018 15:23:56 -0400 Subject: [PATCH 1238/1635] random: set up the NUMA crng instances after the CRNG is fully initialized commit 8ef35c866f8862df074a49a93b0309725812dea8 upstream. Until the primary_crng is fully initialized, don't initialize the NUMA crng nodes. Otherwise users of /dev/urandom on NUMA systems before the CRNG is fully initialized can get very bad quality randomness. Of course everyone should move to getrandom(2) where this won't be an issue, but there's a lot of legacy code out there. This related to CVE-2018-1108. Reported-by: Jann Horn Fixes: 1e7f583af67b ("random: make /dev/urandom scalable for silly...") Cc: stable@kernel.org # 4.8+ Signed-off-by: Theodore Ts'o Signed-off-by: Greg Kroah-Hartman --- drivers/char/random.c | 46 +++++++++++++++++++++++++------------------ 1 file changed, 27 insertions(+), 19 deletions(-) diff --git a/drivers/char/random.c b/drivers/char/random.c index 58a2ff7df392..4fb73009698c 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -787,6 +787,32 @@ static void crng_initialize(struct crng_state *crng) crng->init_time = jiffies - CRNG_RESEED_INTERVAL - 1; } +#ifdef CONFIG_NUMA +static void numa_crng_init(void) +{ + int i; + struct crng_state *crng; + struct crng_state **pool; + + pool = kcalloc(nr_node_ids, sizeof(*pool), GFP_KERNEL|__GFP_NOFAIL); + for_each_online_node(i) { + crng = kmalloc_node(sizeof(struct crng_state), + GFP_KERNEL | __GFP_NOFAIL, i); + spin_lock_init(&crng->lock); + crng_initialize(crng); + pool[i] = crng; + } + mb(); + if (cmpxchg(&crng_node_pool, NULL, pool)) { + for_each_node(i) + kfree(pool[i]); + kfree(pool); + } +} +#else +static void numa_crng_init(void) {} +#endif + /* * crng_fast_load() can be called by code in the interrupt service * path. So we can't afford to dilly-dally. @@ -893,6 +919,7 @@ static void crng_reseed(struct crng_state *crng, struct entropy_store *r) spin_unlock_irqrestore(&crng->lock, flags); if (crng == &primary_crng && crng_init < 2) { invalidate_batched_entropy(); + numa_crng_init(); crng_init = 2; process_random_ready_list(); wake_up_interruptible(&crng_init_wait); @@ -1731,29 +1758,10 @@ static void init_std_data(struct entropy_store *r) */ static int rand_initialize(void) { -#ifdef CONFIG_NUMA - int i; - struct crng_state *crng; - struct crng_state **pool; -#endif - init_std_data(&input_pool); init_std_data(&blocking_pool); crng_initialize(&primary_crng); crng_global_init_time = jiffies; - -#ifdef CONFIG_NUMA - pool = kcalloc(nr_node_ids, sizeof(*pool), GFP_KERNEL|__GFP_NOFAIL); - for_each_online_node(i) { - crng = kmalloc_node(sizeof(struct crng_state), - GFP_KERNEL | __GFP_NOFAIL, i); - spin_lock_init(&crng->lock); - crng_initialize(crng); - pool[i] = crng; - } - mb(); - crng_node_pool = pool; -#endif return 0; } early_initcall(rand_initialize); -- GitLab From ffc5b50a2b53d180d977b969034cad1a9fb45d8b Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Mon, 23 Apr 2018 18:51:28 -0400 Subject: [PATCH 1239/1635] random: fix possible sleeping allocation from irq context commit 6c1e851c4edc13a43adb3ea4044e3fc8f43ccf7d upstream. We can do a sleeping allocation from an irq context when CONFIG_NUMA is enabled. Fix this by initializing the NUMA crng instances in a workqueue. Reported-by: Tetsuo Handa Reported-by: syzbot+9de458f6a5e713ee8c1a@syzkaller.appspotmail.com Fixes: 8ef35c866f8862df ("random: set up the NUMA crng instances...") Cc: stable@vger.kernel.org Signed-off-by: Theodore Ts'o Signed-off-by: Greg Kroah-Hartman --- drivers/char/random.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/char/random.c b/drivers/char/random.c index 4fb73009698c..fb7502b0f8cb 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -788,7 +788,7 @@ static void crng_initialize(struct crng_state *crng) } #ifdef CONFIG_NUMA -static void numa_crng_init(void) +static void do_numa_crng_init(struct work_struct *work) { int i; struct crng_state *crng; @@ -809,6 +809,13 @@ static void numa_crng_init(void) kfree(pool); } } + +static DECLARE_WORK(numa_crng_init_work, do_numa_crng_init); + +static void numa_crng_init(void) +{ + schedule_work(&numa_crng_init_work); +} #else static void numa_crng_init(void) {} #endif -- GitLab From 76dbabb38a18ff7ec20de36e9dabcadccca9ad69 Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Wed, 25 Apr 2018 01:12:32 -0400 Subject: [PATCH 1240/1635] random: rate limit unseeded randomness warnings commit 4e00b339e264802851aff8e73cde7d24b57b18ce upstream. On systems without sufficient boot randomness, no point spamming dmesg. Signed-off-by: Theodore Ts'o Cc: stable@vger.kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/char/random.c | 39 ++++++++++++++++++++++++++++++++++----- 1 file changed, 34 insertions(+), 5 deletions(-) diff --git a/drivers/char/random.c b/drivers/char/random.c index fb7502b0f8cb..ddc493d976fd 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -261,6 +261,7 @@ #include #include #include +#include #include #include #include @@ -438,6 +439,16 @@ static void _crng_backtrack_protect(struct crng_state *crng, static void process_random_ready_list(void); static void _get_random_bytes(void *buf, int nbytes); +static struct ratelimit_state unseeded_warning = + RATELIMIT_STATE_INIT("warn_unseeded_randomness", HZ, 3); +static struct ratelimit_state urandom_warning = + RATELIMIT_STATE_INIT("warn_urandom_randomness", HZ, 3); + +static int ratelimit_disable __read_mostly; + +module_param_named(ratelimit_disable, ratelimit_disable, int, 0644); +MODULE_PARM_DESC(ratelimit_disable, "Disable random ratelimit suppression"); + /********************************************************************** * * OS independent entropy store. Here are the functions which handle @@ -931,6 +942,18 @@ static void crng_reseed(struct crng_state *crng, struct entropy_store *r) process_random_ready_list(); wake_up_interruptible(&crng_init_wait); pr_notice("random: crng init done\n"); + if (unseeded_warning.missed) { + pr_notice("random: %d get_random_xx warning(s) missed " + "due to ratelimiting\n", + unseeded_warning.missed); + unseeded_warning.missed = 0; + } + if (urandom_warning.missed) { + pr_notice("random: %d urandom warning(s) missed " + "due to ratelimiting\n", + urandom_warning.missed); + urandom_warning.missed = 0; + } } } @@ -1574,8 +1597,9 @@ static void _warn_unseeded_randomness(const char *func_name, void *caller, #ifndef CONFIG_WARN_ALL_UNSEEDED_RANDOM print_once = true; #endif - pr_notice("random: %s called from %pS with crng_init=%d\n", - func_name, caller, crng_init); + if (__ratelimit(&unseeded_warning)) + pr_notice("random: %s called from %pS with crng_init=%d\n", + func_name, caller, crng_init); } /* @@ -1769,6 +1793,10 @@ static int rand_initialize(void) init_std_data(&blocking_pool); crng_initialize(&primary_crng); crng_global_init_time = jiffies; + if (ratelimit_disable) { + urandom_warning.interval = 0; + unseeded_warning.interval = 0; + } return 0; } early_initcall(rand_initialize); @@ -1836,9 +1864,10 @@ urandom_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos) if (!crng_ready() && maxwarn > 0) { maxwarn--; - printk(KERN_NOTICE "random: %s: uninitialized urandom read " - "(%zd bytes read)\n", - current->comm, nbytes); + if (__ratelimit(&urandom_warning)) + printk(KERN_NOTICE "random: %s: uninitialized " + "urandom read (%zd bytes read)\n", + current->comm, nbytes); spin_lock_irqsave(&primary_crng.lock, flags); crng_init_cnt = 0; spin_unlock_irqrestore(&primary_crng.lock, flags); -- GitLab From 470bf16ae1ab7172133fe3c6b4506a75f86d314f Mon Sep 17 00:00:00 2001 From: Shuah Khan Date: Thu, 5 Apr 2018 16:29:50 -0600 Subject: [PATCH 1241/1635] usbip: usbip_event: fix to not print kernel pointer address commit 4c982482341c64f55daf69b6caa5a2bcd9b43824 upstream. Fix it to not print kernel pointer address. Remove the conditional and debug message as it isn't very useful. Signed-off-by: Shuah Khan Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/usb/usbip/usbip_event.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/usb/usbip/usbip_event.c b/drivers/usb/usbip/usbip_event.c index f1635662c299..f8f7f3803a99 100644 --- a/drivers/usb/usbip/usbip_event.c +++ b/drivers/usb/usbip/usbip_event.c @@ -105,10 +105,6 @@ static void event_handler(struct work_struct *work) unset_event(ud, USBIP_EH_UNUSABLE); } - /* Stop the error handler. */ - if (ud->event & USBIP_EH_BYE) - usbip_dbg_eh("removed %p\n", ud); - wake_up(&ud->eh_waitq); } } -- GitLab From 944edaf13deeb0db5847bddf956c4316e53d6f2c Mon Sep 17 00:00:00 2001 From: Shuah Khan Date: Thu, 5 Apr 2018 16:29:04 -0600 Subject: [PATCH 1242/1635] usbip: usbip_host: fix to hold parent lock for device_attach() calls commit 4bfb141bc01312a817d36627cc47c93f801c216d upstream. usbip_host calls device_attach() without holding dev->parent lock. Fix it. Signed-off-by: Shuah Khan Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/usb/usbip/stub_main.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/usb/usbip/stub_main.c b/drivers/usb/usbip/stub_main.c index 6968c906fa29..b59a253a8479 100644 --- a/drivers/usb/usbip/stub_main.c +++ b/drivers/usb/usbip/stub_main.c @@ -200,7 +200,12 @@ static ssize_t rebind_store(struct device_driver *dev, const char *buf, if (!bid) return -ENODEV; + /* device_attach() callers should hold parent lock for USB */ + if (bid->udev->dev.parent) + device_lock(bid->udev->dev.parent); ret = device_attach(&bid->udev->dev); + if (bid->udev->dev.parent) + device_unlock(bid->udev->dev.parent); if (ret < 0) { dev_err(&bid->udev->dev, "rebind failed\n"); return ret; -- GitLab From 4abe5b775a16e131466f40861b90632d719da1b5 Mon Sep 17 00:00:00 2001 From: Shuah Khan Date: Mon, 2 Apr 2018 14:52:32 -0600 Subject: [PATCH 1243/1635] usbip: vhci_hcd: Fix usb device and sockfd leaks commit 9020a7efe537856eb3e826ebebdf38a5d07a7857 upstream. vhci_hcd fails to do reset to put usb device and sockfd in the module remove/stop paths. Fix the leak. Signed-off-by: Shuah Khan Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/usb/usbip/usbip_common.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/usbip/usbip_common.h b/drivers/usb/usbip/usbip_common.h index 33737b612b1f..c81c44c13a56 100644 --- a/drivers/usb/usbip/usbip_common.h +++ b/drivers/usb/usbip/usbip_common.h @@ -257,7 +257,7 @@ enum usbip_side { #define VUDC_EVENT_ERROR_USB (USBIP_EH_SHUTDOWN | USBIP_EH_UNUSABLE) #define VUDC_EVENT_ERROR_MALLOC (USBIP_EH_SHUTDOWN | USBIP_EH_UNUSABLE) -#define VDEV_EVENT_REMOVED (USBIP_EH_SHUTDOWN | USBIP_EH_BYE) +#define VDEV_EVENT_REMOVED (USBIP_EH_SHUTDOWN | USBIP_EH_RESET | USBIP_EH_BYE) #define VDEV_EVENT_DOWN (USBIP_EH_SHUTDOWN | USBIP_EH_RESET) #define VDEV_EVENT_ERROR_TCP (USBIP_EH_SHUTDOWN | USBIP_EH_RESET) #define VDEV_EVENT_ERROR_MALLOC (USBIP_EH_SHUTDOWN | USBIP_EH_UNUSABLE) -- GitLab From b792b1f7d01ca95db8b39046e2a539def5ffc4f2 Mon Sep 17 00:00:00 2001 From: Shuah Khan Date: Thu, 5 Apr 2018 16:31:49 -0600 Subject: [PATCH 1244/1635] usbip: vhci_hcd: check rhport before using in vhci_hub_control() commit 5b22f676118ff25049382041da0db8012e57c9e8 upstream. Validate !rhport < 0 before using it to access port_status array. Signed-off-by: Shuah Khan Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/usb/usbip/vhci_hcd.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/drivers/usb/usbip/vhci_hcd.c b/drivers/usb/usbip/vhci_hcd.c index 89858aeed647..05aa1ba351b6 100644 --- a/drivers/usb/usbip/vhci_hcd.c +++ b/drivers/usb/usbip/vhci_hcd.c @@ -368,6 +368,8 @@ static int vhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, usbip_dbg_vhci_rh(" ClearHubFeature\n"); break; case ClearPortFeature: + if (rhport < 0) + goto error; switch (wValue) { case USB_PORT_FEAT_SUSPEND: if (hcd->speed == HCD_USB3) { @@ -525,11 +527,16 @@ static int vhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, goto error; } + if (rhport < 0) + goto error; + vhci_hcd->port_status[rhport] |= USB_PORT_STAT_SUSPEND; break; case USB_PORT_FEAT_POWER: usbip_dbg_vhci_rh( " SetPortFeature: USB_PORT_FEAT_POWER\n"); + if (rhport < 0) + goto error; if (hcd->speed == HCD_USB3) vhci_hcd->port_status[rhport] |= USB_SS_PORT_STAT_POWER; else @@ -538,6 +545,8 @@ static int vhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, case USB_PORT_FEAT_BH_PORT_RESET: usbip_dbg_vhci_rh( " SetPortFeature: USB_PORT_FEAT_BH_PORT_RESET\n"); + if (rhport < 0) + goto error; /* Applicable only for USB3.0 hub */ if (hcd->speed != HCD_USB3) { pr_err("USB_PORT_FEAT_BH_PORT_RESET req not " @@ -548,6 +557,8 @@ static int vhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, case USB_PORT_FEAT_RESET: usbip_dbg_vhci_rh( " SetPortFeature: USB_PORT_FEAT_RESET\n"); + if (rhport < 0) + goto error; /* if it's already enabled, disable */ if (hcd->speed == HCD_USB3) { vhci_hcd->port_status[rhport] = 0; @@ -568,6 +579,8 @@ static int vhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, default: usbip_dbg_vhci_rh(" SetPortFeature: default %d\n", wValue); + if (rhport < 0) + goto error; if (hcd->speed == HCD_USB3) { if ((vhci_hcd->port_status[rhport] & USB_SS_PORT_STAT_POWER) != 0) { -- GitLab From 64abd2428e54ead122a4e713a0abfb9627fa3e02 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Sun, 22 Apr 2018 14:31:03 +0200 Subject: [PATCH 1245/1635] Revert "xhci: plat: Register shutdown for xhci_plat" commit c20f53c58261b121d0989e147368803b9773b413 upstream. This reverts commit b07c12517f2aed0add8ce18146bb426b14099392 It is incomplete and causes hangs on devices when shutting down. It needs a much more "complete" fix in order to work properly. As that fix has not been merged, revert this patch for now before it causes any more problems. Cc: Greg Hackmann Cc: Adam Wallis Cc: Mathias Nyman Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-plat.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c index 1cb6eaef4ae1..7d9e085f7b85 100644 --- a/drivers/usb/host/xhci-plat.c +++ b/drivers/usb/host/xhci-plat.c @@ -423,7 +423,6 @@ MODULE_DEVICE_TABLE(acpi, usb_xhci_acpi_match); static struct platform_driver usb_xhci_driver = { .probe = xhci_plat_probe, .remove = xhci_plat_remove, - .shutdown = usb_hcd_platform_shutdown, .driver = { .name = "xhci-hcd", .pm = &xhci_plat_pm_ops, -- GitLab From 0b932b1ca9dad9ba18b58efb56074d3431c81166 Mon Sep 17 00:00:00 2001 From: Kai-Heng Feng Date: Fri, 20 Apr 2018 16:52:50 +0300 Subject: [PATCH 1246/1635] xhci: Fix USB ports for Dell Inspiron 5775 commit 621faf4f6a181b6e012c1d1865213f36f4159b7f upstream. The Dell Inspiron 5775 is a Raven Ridge. The Enable Slot command timed out when a USB device gets plugged: [ 212.156326] xhci_hcd 0000:03:00.3: Error while assigning device slot ID [ 212.156340] xhci_hcd 0000:03:00.3: Max number of devices this xHCI host supports is 64. [ 212.156348] usb usb2-port3: couldn't allocate usb_device AMD suggests that a delay before xHC suspends can fix the issue. I can confirm it fixes the issue, so use the suspend delay quirk for Raven Ridge's xHC. Cc: stable@vger.kernel.org Signed-off-by: Kai-Heng Feng Signed-off-by: Mathias Nyman Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-pci.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c index 3fb57cf8abb8..d79ab0d85924 100644 --- a/drivers/usb/host/xhci-pci.c +++ b/drivers/usb/host/xhci-pci.c @@ -134,7 +134,10 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci) if (pdev->vendor == PCI_VENDOR_ID_AMD && usb_amd_find_chipset_info()) xhci->quirks |= XHCI_AMD_PLL_FIX; - if (pdev->vendor == PCI_VENDOR_ID_AMD && pdev->device == 0x43bb) + if (pdev->vendor == PCI_VENDOR_ID_AMD && + (pdev->device == 0x15e0 || + pdev->device == 0x15e1 || + pdev->device == 0x43bb)) xhci->quirks |= XHCI_SUSPEND_DELAY; if (pdev->vendor == PCI_VENDOR_ID_AMD) -- GitLab From 8f30aa32b716b728163893a90be929f5e9e6c071 Mon Sep 17 00:00:00 2001 From: Collin May Date: Sat, 7 Apr 2018 14:32:48 -0700 Subject: [PATCH 1247/1635] USB: serial: simple: add libtransistor console commit fe710508b6ba9d28730f3021fed70e7043433b2e upstream. Add simple driver for libtransistor USB console. This device is implemented in software: https://github.com/reswitched/libtransistor/blob/development/lib/usb_serial.c Signed-off-by: Collin May Cc: stable Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/Kconfig | 1 + drivers/usb/serial/usb-serial-simple.c | 7 +++++++ 2 files changed, 8 insertions(+) diff --git a/drivers/usb/serial/Kconfig b/drivers/usb/serial/Kconfig index c66b93664d54..c508e2d7104b 100644 --- a/drivers/usb/serial/Kconfig +++ b/drivers/usb/serial/Kconfig @@ -62,6 +62,7 @@ config USB_SERIAL_SIMPLE - Fundamental Software dongle. - Google USB serial devices - HP4x calculators + - Libtransistor USB console - a number of Motorola phones - Motorola Tetra devices - Novatel Wireless GPS receivers diff --git a/drivers/usb/serial/usb-serial-simple.c b/drivers/usb/serial/usb-serial-simple.c index 6aa7ff2c1cf7..2674da40d9cd 100644 --- a/drivers/usb/serial/usb-serial-simple.c +++ b/drivers/usb/serial/usb-serial-simple.c @@ -66,6 +66,11 @@ DEVICE(flashloader, FLASHLOADER_IDS); 0x01) } DEVICE(google, GOOGLE_IDS); +/* Libtransistor USB console */ +#define LIBTRANSISTOR_IDS() \ + { USB_DEVICE(0x1209, 0x8b00) } +DEVICE(libtransistor, LIBTRANSISTOR_IDS); + /* ViVOpay USB Serial Driver */ #define VIVOPAY_IDS() \ { USB_DEVICE(0x1d5f, 0x1004) } /* ViVOpay 8800 */ @@ -113,6 +118,7 @@ static struct usb_serial_driver * const serial_drivers[] = { &funsoft_device, &flashloader_device, &google_device, + &libtransistor_device, &vivopay_device, &moto_modem_device, &motorola_tetra_device, @@ -129,6 +135,7 @@ static const struct usb_device_id id_table[] = { FUNSOFT_IDS(), FLASHLOADER_IDS(), GOOGLE_IDS(), + LIBTRANSISTOR_IDS(), VIVOPAY_IDS(), MOTO_IDS(), MOTOROLA_TETRA_IDS(), -- GitLab From 747120e77100fccc05923a104bca3e9c729af87b Mon Sep 17 00:00:00 2001 From: Vasyl Vavrychuk Date: Wed, 11 Apr 2018 17:05:13 +0300 Subject: [PATCH 1248/1635] USB: serial: ftdi_sio: use jtag quirk for Arrow USB Blaster commit 470b5d6f0cf4674be2d1ec94e54283a1770b6a1a upstream. Arrow USB Blaster integrated on MAX1000 board uses the same vendor ID (0x0403) and product ID (0x6010) as the "original" FTDI device. This patch avoids picking up by ftdi_sio of the first interface of this USB device. After that this device can be used by Arrow user-space JTAG driver. Signed-off-by: Vasyl Vavrychuk Cc: stable Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/ftdi_sio.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index a2a5232751cb..385f2ae3be24 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -1902,7 +1902,8 @@ static int ftdi_8u2232c_probe(struct usb_serial *serial) return ftdi_jtag_probe(serial); if (udev->product && - (!strcmp(udev->product, "BeagleBone/XDS100V2") || + (!strcmp(udev->product, "Arrow USB Blaster") || + !strcmp(udev->product, "BeagleBone/XDS100V2") || !strcmp(udev->product, "SNAP Connect E10"))) return ftdi_jtag_probe(serial); -- GitLab From f310eb70657e991c68c085e41b66e7c119cb392b Mon Sep 17 00:00:00 2001 From: Kyle Roeschley Date: Mon, 9 Apr 2018 10:23:55 -0500 Subject: [PATCH 1249/1635] USB: serial: cp210x: add ID for NI USB serial console commit 1e23aace21515a8f7615a1de016c0ea8d4e0cc6e upstream. Added the USB VID and PID for the USB serial console on some National Instruments devices. Signed-off-by: Kyle Roeschley Cc: stable Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/cp210x.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c index 2836acf73a07..d0f00274d16c 100644 --- a/drivers/usb/serial/cp210x.c +++ b/drivers/usb/serial/cp210x.c @@ -217,6 +217,7 @@ static const struct usb_device_id id_table[] = { { USB_DEVICE(0x3195, 0xF190) }, /* Link Instruments MSO-19 */ { USB_DEVICE(0x3195, 0xF280) }, /* Link Instruments MSO-28 */ { USB_DEVICE(0x3195, 0xF281) }, /* Link Instruments MSO-28 */ + { USB_DEVICE(0x3923, 0x7A0B) }, /* National Instruments USB Serial Console */ { USB_DEVICE(0x413C, 0x9500) }, /* DW700 GPS USB interface */ { } /* Terminating Entry */ }; -- GitLab From 333909311d70b035306a86b0139daaf480a25624 Mon Sep 17 00:00:00 2001 From: Heikki Krogerus Date: Wed, 18 Apr 2018 15:34:10 +0300 Subject: [PATCH 1250/1635] usb: typec: ucsi: Increase command completion timeout value commit b1b59e16075f5e5da2943ce8de724ab96bc3c6c2 upstream. On some boards, under heavy load, the EC firmware is unable to complete commands even in one second. Increasing the command completion timeout value to five seconds. Reported-by: Quanxian Wang Fixes: c1b0bc2dabfa ("usb: typec: Add support for UCSI interface") Cc: Signed-off-by: Heikki Krogerus Signed-off-by: Greg Kroah-Hartman --- drivers/usb/typec/ucsi/ucsi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/typec/ucsi/ucsi.c b/drivers/usb/typec/ucsi/ucsi.c index 714c5bcedf2b..dd24c5c1534d 100644 --- a/drivers/usb/typec/ucsi/ucsi.c +++ b/drivers/usb/typec/ucsi/ucsi.c @@ -31,7 +31,7 @@ * difficult to estimate the time it takes for the system to process the command * before it is actually passed to the PPM. */ -#define UCSI_TIMEOUT_MS 1000 +#define UCSI_TIMEOUT_MS 5000 /* * UCSI_SWAP_TIMEOUT_MS - Timeout for role swap requests -- GitLab From c59dc4d135192123523f35ff60243295a4f9d40a Mon Sep 17 00:00:00 2001 From: Kamil Lulko Date: Thu, 19 Apr 2018 16:54:02 -0700 Subject: [PATCH 1251/1635] usb: core: Add quirk for HP v222w 16GB Mini commit 3180dabe08e3653bf0a838553905d88f3773f29c upstream. Add DELAY_INIT quirk to fix the following problem with HP v222w 16GB Mini: usb 1-3: unable to read config index 0 descriptor/start: -110 usb 1-3: can't read configurations, error -110 usb 1-3: can't set config #1, error -110 Signed-off-by: Kamil Lulko Signed-off-by: Kuppuswamy Sathyanarayanan Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/quirks.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c index 4f1c6f8d4352..40ce175655e6 100644 --- a/drivers/usb/core/quirks.c +++ b/drivers/usb/core/quirks.c @@ -45,6 +45,9 @@ static const struct usb_device_id usb_quirk_list[] = { { USB_DEVICE(0x03f0, 0x0701), .driver_info = USB_QUIRK_STRING_FETCH_255 }, + /* HP v222w 16GB Mini USB Drive */ + { USB_DEVICE(0x03f0, 0x3f40), .driver_info = USB_QUIRK_DELAY_INIT }, + /* Creative SB Audigy 2 NX */ { USB_DEVICE(0x041e, 0x3020), .driver_info = USB_QUIRK_RESET_RESUME }, -- GitLab From e6d2055ba32f0878b09f3068af10a4ba445f84a8 Mon Sep 17 00:00:00 2001 From: Ravi Chandra Sadineni Date: Fri, 20 Apr 2018 11:08:21 -0700 Subject: [PATCH 1252/1635] USB: Increment wakeup count on remote wakeup. commit 83a62c51ba7b3c0bf45150c4eac7aefc6c785e94 upstream. On chromebooks we depend on wakeup count to identify the wakeup source. But currently USB devices do not increment the wakeup count when they trigger the remote wake. This patch addresses the same. Resume condition is reported differently on USB 2.0 and USB 3.0 devices. On USB 2.0 devices, a wake capable device, if wake enabled, drives resume signal to indicate a remote wake (USB 2.0 spec section 7.1.7.7). The upstream facing port then sets C_PORT_SUSPEND bit and reports a port change event (USB 2.0 spec section 11.24.2.7.2.3). Thus if a port has resumed before driving the resume signal from the host and C_PORT_SUSPEND is set, then the device attached to the given port might be the reason for the last system wakeup. Increment the wakeup count for the same. On USB 3.0 devices, a function may signal that it wants to exit from device suspend by sending a Function Wake Device Notification to the host (USB3.0 spec section 8.5.6.4) Thus on receiving the Function Wake, increment the wakeup count. Signed-off-by: Ravi Chandra Sadineni Acked-by: Alan Stern Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hcd.c | 1 + drivers/usb/core/hub.c | 10 +++++++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 75ad6718858c..d0b2e0ed9bab 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -2376,6 +2376,7 @@ void usb_hcd_resume_root_hub (struct usb_hcd *hcd) spin_lock_irqsave (&hcd_root_hub_lock, flags); if (hcd->rh_registered) { + pm_wakeup_event(&hcd->self.root_hub->dev, 0); set_bit(HCD_FLAG_WAKEUP_PENDING, &hcd->flags); queue_work(pm_wq, &hcd->wakeup_work); } diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 8f7d94239ee3..442be7f312f6 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -650,12 +650,17 @@ void usb_wakeup_notification(struct usb_device *hdev, unsigned int portnum) { struct usb_hub *hub; + struct usb_port *port_dev; if (!hdev) return; hub = usb_hub_to_struct_hub(hdev); if (hub) { + port_dev = hub->ports[portnum - 1]; + if (port_dev && port_dev->child) + pm_wakeup_event(&port_dev->child->dev, 0); + set_bit(portnum, hub->wakeup_bits); kick_hub_wq(hub); } @@ -3415,8 +3420,11 @@ int usb_port_resume(struct usb_device *udev, pm_message_t msg) /* Skip the initial Clear-Suspend step for a remote wakeup */ status = hub_port_status(hub, port1, &portstatus, &portchange); - if (status == 0 && !port_is_suspended(hub, portstatus)) + if (status == 0 && !port_is_suspended(hub, portstatus)) { + if (portchange & USB_PORT_STAT_C_SUSPEND) + pm_wakeup_event(&udev->dev, 0); goto SuspendCleared; + } /* see 7.1.7.7; affects power usage, but not budgeting */ if (hub_is_superspeed(hub->hdev)) -- GitLab From cf7405f67543bcb8b334c1e79fcd75ad172f7599 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 24 Apr 2018 11:11:48 +0200 Subject: [PATCH 1253/1635] ALSA: usb-audio: Skip broken EU on Dell dock USB-audio commit 1d8d6428d1da642ddd75b0be2d1bb1123ff8e017 upstream. The Dell Dock USB-audio device with 0bda:4014 is behaving notoriously bad, and we have already applied some workaround to avoid the firmware hiccup. Yet we still need to skip one thing, the Extension Unit at ID 4, which doesn't react correctly to the mixer ctl access. Bugzilla: https://bugzilla.suse.com/show_bug.cgi?id=1090658 Cc: Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/usb/mixer_maps.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sound/usb/mixer_maps.c b/sound/usb/mixer_maps.c index 9038b2e7df73..eaa03acd4686 100644 --- a/sound/usb/mixer_maps.c +++ b/sound/usb/mixer_maps.c @@ -353,8 +353,11 @@ static struct usbmix_name_map bose_companion5_map[] = { /* * Dell usb dock with ALC4020 codec had a firmware problem where it got * screwed up when zero volume is passed; just skip it as a workaround + * + * Also the extension unit gives an access error, so skip it as well. */ static const struct usbmix_name_map dell_alc4020_map[] = { + { 4, NULL }, /* extension unit */ { 16, NULL }, { 19, NULL }, { 0 } -- GitLab From 7ae93ff136a00eccc0027d9a01c95680a9e8d756 Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Fri, 20 Apr 2018 20:22:40 +0300 Subject: [PATCH 1254/1635] virtio: add ability to iterate over vqs commit 24a7e4d20783c0514850f24a5c41ede46ab058f0 upstream. For cleanup it's helpful to be able to simply scan all vqs and discard all data. Add an iterator to do that. Cc: stable@vger.kernel.org Signed-off-by: Michael S. Tsirkin Signed-off-by: Greg Kroah-Hartman --- include/linux/virtio.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/include/linux/virtio.h b/include/linux/virtio.h index 988c7355bc22..fa1b5da2804e 100644 --- a/include/linux/virtio.h +++ b/include/linux/virtio.h @@ -157,6 +157,9 @@ int virtio_device_freeze(struct virtio_device *dev); int virtio_device_restore(struct virtio_device *dev); #endif +#define virtio_device_for_each_vq(vdev, vq) \ + list_for_each_entry(vq, &vdev->vqs, list) + /** * virtio_driver - operations for a virtio I/O driver * @driver: underlying device driver (populate name and owner). -- GitLab From 4217a339b37dd8b0c001ec54f85ea84eab7f4feb Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Fri, 20 Apr 2018 19:54:23 +0300 Subject: [PATCH 1255/1635] virtio_console: don't tie bufs to a vq commit 2855b33514d290c51d52d94e25d3ef942cd4d578 upstream. an allocated buffer doesn't need to be tied to a vq - only vq->vdev is ever used. Pass the function the just what it needs - the vdev. Cc: stable@vger.kernel.org Signed-off-by: Michael S. Tsirkin Signed-off-by: Greg Kroah-Hartman --- drivers/char/virtio_console.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c index d1aed2513bd9..3cccdf904528 100644 --- a/drivers/char/virtio_console.c +++ b/drivers/char/virtio_console.c @@ -422,7 +422,7 @@ static void reclaim_dma_bufs(void) } } -static struct port_buffer *alloc_buf(struct virtqueue *vq, size_t buf_size, +static struct port_buffer *alloc_buf(struct virtio_device *vdev, size_t buf_size, int pages) { struct port_buffer *buf; @@ -445,16 +445,16 @@ static struct port_buffer *alloc_buf(struct virtqueue *vq, size_t buf_size, return buf; } - if (is_rproc_serial(vq->vdev)) { + if (is_rproc_serial(vdev)) { /* * Allocate DMA memory from ancestor. When a virtio * device is created by remoteproc, the DMA memory is * associated with the grandparent device: * vdev => rproc => platform-dev. */ - if (!vq->vdev->dev.parent || !vq->vdev->dev.parent->parent) + if (!vdev->dev.parent || !vdev->dev.parent->parent) goto free_buf; - buf->dev = vq->vdev->dev.parent->parent; + buf->dev = vdev->dev.parent->parent; /* Increase device refcnt to avoid freeing it */ get_device(buf->dev); @@ -838,7 +838,7 @@ static ssize_t port_fops_write(struct file *filp, const char __user *ubuf, count = min((size_t)(32 * 1024), count); - buf = alloc_buf(port->out_vq, count, 0); + buf = alloc_buf(port->portdev->vdev, count, 0); if (!buf) return -ENOMEM; @@ -957,7 +957,7 @@ static ssize_t port_fops_splice_write(struct pipe_inode_info *pipe, if (ret < 0) goto error_out; - buf = alloc_buf(port->out_vq, 0, pipe->nrbufs); + buf = alloc_buf(port->portdev->vdev, 0, pipe->nrbufs); if (!buf) { ret = -ENOMEM; goto error_out; @@ -1374,7 +1374,7 @@ static unsigned int fill_queue(struct virtqueue *vq, spinlock_t *lock) nr_added_bufs = 0; do { - buf = alloc_buf(vq, PAGE_SIZE, 0); + buf = alloc_buf(vq->vdev, PAGE_SIZE, 0); if (!buf) break; -- GitLab From 6b1c41a0f7183702abb7a104c6c7e196ad69a6b3 Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Fri, 20 Apr 2018 20:24:23 +0300 Subject: [PATCH 1256/1635] virtio_console: free buffers after reset MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit a7a69ec0d8e4a58be7db88d33cbfa2912807bb2b upstream. Console driver is out of spec. The spec says: A driver MUST NOT decrement the available idx on a live virtqueue (ie. there is no way to “unexpose” buffers). and it does exactly that by trying to detach unused buffers without doing a device reset first. Defer detaching the buffers until device unplug. Of course this means we might get an interrupt for a vq without an attached port now. Handle that by discarding the consumed buffer. Reported-by: Tiwei Bie Fixes: b3258ff1d6 ("virtio: Decrement avail idx on buffer detach") Cc: stable@vger.kernel.org Signed-off-by: Michael S. Tsirkin Signed-off-by: Greg Kroah-Hartman --- drivers/char/virtio_console.c | 49 +++++++++++++++++------------------ 1 file changed, 24 insertions(+), 25 deletions(-) diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c index 3cccdf904528..ddec05313465 100644 --- a/drivers/char/virtio_console.c +++ b/drivers/char/virtio_console.c @@ -1402,7 +1402,6 @@ static int add_port(struct ports_device *portdev, u32 id) { char debugfs_name[16]; struct port *port; - struct port_buffer *buf; dev_t devt; unsigned int nr_added_bufs; int err; @@ -1513,8 +1512,6 @@ static int add_port(struct ports_device *portdev, u32 id) return 0; free_inbufs: - while ((buf = virtqueue_detach_unused_buf(port->in_vq))) - free_buf(buf, true); free_device: device_destroy(pdrvdata.class, port->dev->devt); free_cdev: @@ -1539,34 +1536,14 @@ static void remove_port(struct kref *kref) static void remove_port_data(struct port *port) { - struct port_buffer *buf; - spin_lock_irq(&port->inbuf_lock); /* Remove unused data this port might have received. */ discard_port_data(port); spin_unlock_irq(&port->inbuf_lock); - /* Remove buffers we queued up for the Host to send us data in. */ - do { - spin_lock_irq(&port->inbuf_lock); - buf = virtqueue_detach_unused_buf(port->in_vq); - spin_unlock_irq(&port->inbuf_lock); - if (buf) - free_buf(buf, true); - } while (buf); - spin_lock_irq(&port->outvq_lock); reclaim_consumed_buffers(port); spin_unlock_irq(&port->outvq_lock); - - /* Free pending buffers from the out-queue. */ - do { - spin_lock_irq(&port->outvq_lock); - buf = virtqueue_detach_unused_buf(port->out_vq); - spin_unlock_irq(&port->outvq_lock); - if (buf) - free_buf(buf, true); - } while (buf); } /* @@ -1791,13 +1768,24 @@ static void control_work_handler(struct work_struct *work) spin_unlock(&portdev->c_ivq_lock); } +static void flush_bufs(struct virtqueue *vq, bool can_sleep) +{ + struct port_buffer *buf; + unsigned int len; + + while ((buf = virtqueue_get_buf(vq, &len))) + free_buf(buf, can_sleep); +} + static void out_intr(struct virtqueue *vq) { struct port *port; port = find_port_by_vq(vq->vdev->priv, vq); - if (!port) + if (!port) { + flush_bufs(vq, false); return; + } wake_up_interruptible(&port->waitqueue); } @@ -1808,8 +1796,10 @@ static void in_intr(struct virtqueue *vq) unsigned long flags; port = find_port_by_vq(vq->vdev->priv, vq); - if (!port) + if (!port) { + flush_bufs(vq, false); return; + } spin_lock_irqsave(&port->inbuf_lock, flags); port->inbuf = get_inbuf(port); @@ -1984,6 +1974,15 @@ static const struct file_operations portdev_fops = { static void remove_vqs(struct ports_device *portdev) { + struct virtqueue *vq; + + virtio_device_for_each_vq(portdev->vdev, vq) { + struct port_buffer *buf; + + flush_bufs(vq, true); + while ((buf = virtqueue_detach_unused_buf(vq))) + free_buf(buf, true); + } portdev->vdev->config->del_vqs(portdev->vdev); kfree(portdev->in_vqs); kfree(portdev->out_vqs); -- GitLab From 75fc6f2d39bfe32db91980408247edc77d189a5a Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Fri, 20 Apr 2018 20:49:04 +0300 Subject: [PATCH 1257/1635] virtio_console: drop custom control queue cleanup commit 61a8950c5c5708cf2068b29ffde94e454e528208 upstream. We now cleanup all VQs on device removal - no need to handle the control VQ specially. Cc: stable@vger.kernel.org Signed-off-by: Michael S. Tsirkin Signed-off-by: Greg Kroah-Hartman --- drivers/char/virtio_console.c | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c index ddec05313465..95e6c339b898 100644 --- a/drivers/char/virtio_console.c +++ b/drivers/char/virtio_console.c @@ -1988,21 +1988,6 @@ static void remove_vqs(struct ports_device *portdev) kfree(portdev->out_vqs); } -static void remove_controlq_data(struct ports_device *portdev) -{ - struct port_buffer *buf; - unsigned int len; - - if (!use_multiport(portdev)) - return; - - while ((buf = virtqueue_get_buf(portdev->c_ivq, &len))) - free_buf(buf, true); - - while ((buf = virtqueue_detach_unused_buf(portdev->c_ivq))) - free_buf(buf, true); -} - /* * Once we're further in boot, we get probed like any other virtio * device. @@ -2163,7 +2148,6 @@ static void virtcons_remove(struct virtio_device *vdev) * have to just stop using the port, as the vqs are going * away. */ - remove_controlq_data(portdev); remove_vqs(portdev); kfree(portdev); } @@ -2208,7 +2192,6 @@ static int virtcons_freeze(struct virtio_device *vdev) */ if (use_multiport(portdev)) virtqueue_disable_cb(portdev->c_ivq); - remove_controlq_data(portdev); list_for_each_entry(port, &portdev->ports, list) { virtqueue_disable_cb(port->in_vq); -- GitLab From e9287108acce9b3611bc45a76801fbe242347e60 Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Fri, 20 Apr 2018 20:51:18 +0300 Subject: [PATCH 1258/1635] virtio_console: move removal code commit aa44ec867030a72e8aa127977e37dec551d8df19 upstream. Will make it reusable for error handling. Cc: stable@vger.kernel.org Signed-off-by: Michael S. Tsirkin Signed-off-by: Greg Kroah-Hartman --- drivers/char/virtio_console.c | 72 +++++++++++++++++------------------ 1 file changed, 36 insertions(+), 36 deletions(-) diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c index 95e6c339b898..bcf0376e0d04 100644 --- a/drivers/char/virtio_console.c +++ b/drivers/char/virtio_console.c @@ -1988,6 +1988,42 @@ static void remove_vqs(struct ports_device *portdev) kfree(portdev->out_vqs); } +static void virtcons_remove(struct virtio_device *vdev) +{ + struct ports_device *portdev; + struct port *port, *port2; + + portdev = vdev->priv; + + spin_lock_irq(&pdrvdata_lock); + list_del(&portdev->list); + spin_unlock_irq(&pdrvdata_lock); + + /* Disable interrupts for vqs */ + vdev->config->reset(vdev); + /* Finish up work that's lined up */ + if (use_multiport(portdev)) + cancel_work_sync(&portdev->control_work); + else + cancel_work_sync(&portdev->config_work); + + list_for_each_entry_safe(port, port2, &portdev->ports, list) + unplug_port(port); + + unregister_chrdev(portdev->chr_major, "virtio-portsdev"); + + /* + * When yanking out a device, we immediately lose the + * (device-side) queues. So there's no point in keeping the + * guest side around till we drop our final reference. This + * also means that any ports which are in an open state will + * have to just stop using the port, as the vqs are going + * away. + */ + remove_vqs(portdev); + kfree(portdev); +} + /* * Once we're further in boot, we get probed like any other virtio * device. @@ -2116,42 +2152,6 @@ static int virtcons_probe(struct virtio_device *vdev) return err; } -static void virtcons_remove(struct virtio_device *vdev) -{ - struct ports_device *portdev; - struct port *port, *port2; - - portdev = vdev->priv; - - spin_lock_irq(&pdrvdata_lock); - list_del(&portdev->list); - spin_unlock_irq(&pdrvdata_lock); - - /* Disable interrupts for vqs */ - vdev->config->reset(vdev); - /* Finish up work that's lined up */ - if (use_multiport(portdev)) - cancel_work_sync(&portdev->control_work); - else - cancel_work_sync(&portdev->config_work); - - list_for_each_entry_safe(port, port2, &portdev->ports, list) - unplug_port(port); - - unregister_chrdev(portdev->chr_major, "virtio-portsdev"); - - /* - * When yanking out a device, we immediately lose the - * (device-side) queues. So there's no point in keeping the - * guest side around till we drop our final reference. This - * also means that any ports which are in an open state will - * have to just stop using the port, as the vqs are going - * away. - */ - remove_vqs(portdev); - kfree(portdev); -} - static struct virtio_device_id id_table[] = { { VIRTIO_ID_CONSOLE, VIRTIO_DEV_ANY_ID }, { 0 }, -- GitLab From 998d43ce034b98466e0aa1b8d56b6d524c7d0d4e Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Fri, 20 Apr 2018 21:00:13 +0300 Subject: [PATCH 1259/1635] virtio_console: reset on out of memory commit 5c60300d68da32ca77f7f978039dc72bfc78b06b upstream. When out of memory and we can't add ctrl vq buffers, probe fails. Unfortunately the error handling is out of spec: it calls del_vqs without bothering to reset the device first. To fix, call the full cleanup function in this case. Cc: stable@vger.kernel.org Signed-off-by: Michael S. Tsirkin Signed-off-by: Greg Kroah-Hartman --- drivers/char/virtio_console.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c index bcf0376e0d04..a089474cb046 100644 --- a/drivers/char/virtio_console.c +++ b/drivers/char/virtio_console.c @@ -2090,6 +2090,7 @@ static int virtcons_probe(struct virtio_device *vdev) spin_lock_init(&portdev->ports_lock); INIT_LIST_HEAD(&portdev->ports); + INIT_LIST_HEAD(&portdev->list); virtio_device_ready(portdev->vdev); @@ -2107,8 +2108,15 @@ static int virtcons_probe(struct virtio_device *vdev) if (!nr_added_bufs) { dev_err(&vdev->dev, "Error allocating buffers for control queue\n"); - err = -ENOMEM; - goto free_vqs; + /* + * The host might want to notify mgmt sw about device + * add failure. + */ + __send_control_msg(portdev, VIRTIO_CONSOLE_BAD_ID, + VIRTIO_CONSOLE_DEVICE_READY, 0); + /* Device was functional: we need full cleanup. */ + virtcons_remove(vdev); + return -ENOMEM; } } else { /* @@ -2139,11 +2147,6 @@ static int virtcons_probe(struct virtio_device *vdev) return 0; -free_vqs: - /* The host might want to notify mgmt sw about device add failure */ - __send_control_msg(portdev, VIRTIO_CONSOLE_BAD_ID, - VIRTIO_CONSOLE_DEVICE_READY, 0); - remove_vqs(portdev); free_chrdev: unregister_chrdev(portdev->chr_major, "virtio-portsdev"); free: -- GitLab From c0ed8ece4ef395e8b1665fdba276b7285c44f0ab Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Tue, 3 Apr 2018 11:59:04 +0200 Subject: [PATCH 1260/1635] drm/virtio: fix vq wait_event condition commit d02d270014f70dcab0117776b81a37b6fca745ae upstream. Wait until we have enough space in the virt queue to actually queue up our request. Avoids the guest spinning in case we have a non-zero amount of free entries but not enough for the request. Cc: stable@vger.kernel.org Reported-by: Alain Magloire Signed-off-by: Gerd Hoffmann Reviewed-by: Dave Airlie Link: http://patchwork.freedesktop.org/patch/msgid/20180403095904.11152-1-kraxel@redhat.com Signed-off-by: Sean Paul Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/virtio/virtgpu_vq.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/virtio/virtgpu_vq.c b/drivers/gpu/drm/virtio/virtgpu_vq.c index 9eb96fb2c147..26a2da1f712d 100644 --- a/drivers/gpu/drm/virtio/virtgpu_vq.c +++ b/drivers/gpu/drm/virtio/virtgpu_vq.c @@ -291,7 +291,7 @@ static int virtio_gpu_queue_ctrl_buffer_locked(struct virtio_gpu_device *vgdev, ret = virtqueue_add_sgs(vq, sgs, outcnt, incnt, vbuf, GFP_ATOMIC); if (ret == -ENOSPC) { spin_unlock(&vgdev->ctrlq.qlock); - wait_event(vgdev->ctrlq.ack_queue, vq->num_free); + wait_event(vgdev->ctrlq.ack_queue, vq->num_free >= outcnt + incnt); spin_lock(&vgdev->ctrlq.qlock); goto retry; } else { @@ -366,7 +366,7 @@ static int virtio_gpu_queue_cursor(struct virtio_gpu_device *vgdev, ret = virtqueue_add_sgs(vq, sgs, outcnt, 0, vbuf, GFP_ATOMIC); if (ret == -ENOSPC) { spin_unlock(&vgdev->cursorq.qlock); - wait_event(vgdev->cursorq.ack_queue, vq->num_free); + wait_event(vgdev->cursorq.ack_queue, vq->num_free >= outcnt); spin_lock(&vgdev->cursorq.qlock); goto retry; } else { -- GitLab From 4854b9665c8193291199e7b3d53c63a14a19a802 Mon Sep 17 00:00:00 2001 From: Tetsuo Handa Date: Thu, 5 Apr 2018 19:40:16 +0900 Subject: [PATCH 1261/1635] tty: Don't call panic() at tty_ldisc_init() commit 903f9db10f18f735e62ba447147b6c434b6af003 upstream. syzbot is reporting kernel panic [1] triggered by memory allocation failure at tty_ldisc_get() from tty_ldisc_init(). But since both tty_ldisc_get() and caller of tty_ldisc_init() can cleanly handle errors, tty_ldisc_init() does not need to call panic() when tty_ldisc_get() failed. [1] https://syzkaller.appspot.com/bug?id=883431818e036ae6a9981156a64b821110f39187 Signed-off-by: Tetsuo Handa Reported-by: syzbot Cc: Greg Kroah-Hartman Cc: Jiri Slaby Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/tty/tty_io.c | 5 ++++- drivers/tty/tty_ldisc.c | 5 +++-- include/linux/tty.h | 2 +- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c index 52627478ab61..562d31073f9a 100644 --- a/drivers/tty/tty_io.c +++ b/drivers/tty/tty_io.c @@ -2815,7 +2815,10 @@ struct tty_struct *alloc_tty_struct(struct tty_driver *driver, int idx) kref_init(&tty->kref); tty->magic = TTY_MAGIC; - tty_ldisc_init(tty); + if (tty_ldisc_init(tty)) { + kfree(tty); + return NULL; + } tty->session = NULL; tty->pgrp = NULL; mutex_init(&tty->legacy_mutex); diff --git a/drivers/tty/tty_ldisc.c b/drivers/tty/tty_ldisc.c index 7c895684c3ef..77eac4ab1737 100644 --- a/drivers/tty/tty_ldisc.c +++ b/drivers/tty/tty_ldisc.c @@ -823,12 +823,13 @@ EXPORT_SYMBOL_GPL(tty_ldisc_release); * the tty structure is not completely set up when this call is made. */ -void tty_ldisc_init(struct tty_struct *tty) +int tty_ldisc_init(struct tty_struct *tty) { struct tty_ldisc *ld = tty_ldisc_get(tty, N_TTY); if (IS_ERR(ld)) - panic("n_tty: init_tty"); + return PTR_ERR(ld); tty->ldisc = ld; + return 0; } /** diff --git a/include/linux/tty.h b/include/linux/tty.h index 47f8af22f216..1dd587ba6d88 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h @@ -701,7 +701,7 @@ extern int tty_unregister_ldisc(int disc); extern int tty_set_ldisc(struct tty_struct *tty, int disc); extern int tty_ldisc_setup(struct tty_struct *tty, struct tty_struct *o_tty); extern void tty_ldisc_release(struct tty_struct *tty); -extern void tty_ldisc_init(struct tty_struct *tty); +extern int __must_check tty_ldisc_init(struct tty_struct *tty); extern void tty_ldisc_deinit(struct tty_struct *tty); extern int tty_ldisc_receive_buf(struct tty_ldisc *ld, const unsigned char *p, char *f, int count); -- GitLab From 6ba9a47d1fc5ce78e47026d98621366712c554f7 Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Sat, 7 Apr 2018 10:19:50 -0700 Subject: [PATCH 1262/1635] tty: n_gsm: Fix long delays with control frame timeouts in ADM mode commit e9ec22547986dd32c5c70da78107ce35dbff1344 upstream. Commit ea3d8465ab9b ("tty: n_gsm: Allow ADM response in addition to UA for control dlci") added support for DLCI to stay in Asynchronous Disconnected Mode (ADM). But we still get long delays waiting for commands to other DLCI to complete: --> 5) C: SABM(P) Q> 0) C: UIH(F) Q> 0) C: UIH(F) Q> 0) C: UIH(F) ... This happens because gsm_control_send() sets cretries timer to T2 that is by default set to 34. This will cause resend for T2 times for the control frame. In ADM mode, we will never get a response so the control frame, so retries are just delaying all the commands. Let's fix the issue by setting DLCI_MODE_ADM flag after detecting the ADM mode for the control DLCI. Then we can use that in gsm_control_send() to set retries to 1. This means the control frame will be sent once allowing the other end at an opportunity to switch from ADM to ABM mode. Note that retries will be decremented in gsm_control_retransmit() so we don't want to set it to 0 here. Fixes: ea3d8465ab9b ("tty: n_gsm: Allow ADM response in addition to UA for control dlci") Cc: linux-serial@vger.kernel.org Cc: Alan Cox Cc: Dan Williams Cc: Jiri Prchal Cc: Jiri Slaby Cc: Marcel Partap Cc: Merlijn Wajer Cc: Michael Nazzareno Trimarchi Cc: Michael Scott Cc: Pavel Machek Cc: Peter Hurley Cc: Russ Gorby Cc: Sascha Hauer Cc: Sebastian Reichel Signed-off-by: Tony Lindgren Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/tty/n_gsm.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c index 7253e8d2c6d9..e80d8c7c0761 100644 --- a/drivers/tty/n_gsm.c +++ b/drivers/tty/n_gsm.c @@ -133,6 +133,9 @@ struct gsm_dlci { struct mutex mutex; /* Link layer */ + int mode; +#define DLCI_MODE_ABM 0 /* Normal Asynchronous Balanced Mode */ +#define DLCI_MODE_ADM 1 /* Asynchronous Disconnected Mode */ spinlock_t lock; /* Protects the internal state */ struct timer_list t1; /* Retransmit timer for SABM and UA */ int retries; @@ -1376,7 +1379,13 @@ static struct gsm_control *gsm_control_send(struct gsm_mux *gsm, ctrl->data = data; ctrl->len = clen; gsm->pending_cmd = ctrl; - gsm->cretries = gsm->n2; + + /* If DLCI0 is in ADM mode skip retries, it won't respond */ + if (gsm->dlci[0]->mode == DLCI_MODE_ADM) + gsm->cretries = 1; + else + gsm->cretries = gsm->n2; + mod_timer(&gsm->t2_timer, jiffies + gsm->t2 * HZ / 100); gsm_control_transmit(gsm, ctrl); spin_unlock_irqrestore(&gsm->control_lock, flags); @@ -1484,6 +1493,7 @@ static void gsm_dlci_t1(unsigned long data) if (debug & 8) pr_info("DLCI %d opening in ADM mode.\n", dlci->addr); + dlci->mode = DLCI_MODE_ADM; gsm_dlci_open(dlci); } else { gsm_dlci_close(dlci); -- GitLab From 6a50af86a62be245cf093c3de2c02790da1491df Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Sat, 7 Apr 2018 10:19:51 -0700 Subject: [PATCH 1263/1635] tty: n_gsm: Fix DLCI handling for ADM mode if debug & 2 is not set commit b2d89ad9c9682e795ed6eeb9ed455789ad6cedf1 upstream. At least on droid 4 with control channel in ADM mode, there is no response to Modem Status Command (MSC). Currently gsmtty_modem_update() expects to have data in dlci->modem_rx unless debug & 2 is set. This means that on droid 4, things only work if debug & 2 is set. Let's fix the issue by ignoring empty dlci->modem_rx for ADM mode. In the AMD mode, CMD_MSC will never respond and gsm_process_modem() won't get called to set dlci->modem_rx. And according to ts_127010v140000p.pdf, MSC is only relevant if basic option is chosen, so let's test for that too. Fixes: ea3d8465ab9b ("tty: n_gsm: Allow ADM response in addition to UA for control dlci") Cc: linux-serial@vger.kernel.org Cc: Alan Cox Cc: Dan Williams Cc: Jiri Prchal Cc: Jiri Slaby Cc: Marcel Partap Cc: Merlijn Wajer Cc: Michael Nazzareno Trimarchi Cc: Michael Scott Cc: Pavel Machek Cc: Peter Hurley Cc: Russ Gorby Cc: Sascha Hauer Cc: Sebastian Reichel Signed-off-by: Tony Lindgren Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/tty/n_gsm.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c index e80d8c7c0761..f46bd1af7a10 100644 --- a/drivers/tty/n_gsm.c +++ b/drivers/tty/n_gsm.c @@ -2885,11 +2885,22 @@ static int gsmtty_modem_update(struct gsm_dlci *dlci, u8 brk) static int gsm_carrier_raised(struct tty_port *port) { struct gsm_dlci *dlci = container_of(port, struct gsm_dlci, port); + struct gsm_mux *gsm = dlci->gsm; + /* Not yet open so no carrier info */ if (dlci->state != DLCI_OPEN) return 0; if (debug & 2) return 1; + + /* + * Basic mode with control channel in ADM mode may not respond + * to CMD_MSC at all and modem_rx is empty. + */ + if (gsm->encoding == 0 && gsm->dlci[0]->mode == DLCI_MODE_ADM && + !dlci->modem_rx) + return 1; + return dlci->modem_rx & TIOCM_CD; } -- GitLab From 877f418171af2aae702cf0878ae2ec44eab5e89a Mon Sep 17 00:00:00 2001 From: Tetsuo Handa Date: Mon, 16 Apr 2018 20:06:34 +0900 Subject: [PATCH 1264/1635] tty: Avoid possible error pointer dereference at tty_ldisc_restore(). commit 598c2d41ff44889dd8eced4f117403e472158d85 upstream. syzbot is reporting crashes [1] triggered by memory allocation failure at tty_ldisc_get() from tty_ldisc_restore(). While syzbot stops at WARN_ON() due to panic_on_warn == true, panic_on_warn == false will after all trigger an OOPS by dereferencing old->ops->num if IS_ERR(old) == true. We can simplify tty_ldisc_restore() as three calls (old->ops->num, N_TTY, N_NULL) to tty_ldisc_failto() in addition to avoiding possible error pointer dereference. If someone reports kernel panic triggered by forcing all memory allocations for tty_ldisc_restore() to fail, we can consider adding __GFP_NOFAIL for tty_ldisc_restore() case. [1] https://syzkaller.appspot.com/bug?id=6ac359c61e71d22e06db7f8f88243feb11d927e7 Reported-by: syzbot+40b7287c2dc987c48c81@syzkaller.appspotmail.com Signed-off-by: Tetsuo Handa Cc: Greg Kroah-Hartman Cc: Jiri Slaby Cc: Dmitry Vyukov Cc: Johannes Weiner Cc: Alan Cox Cc: Christoph Hellwig Cc: Michal Hocko Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/tty/tty_ldisc.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/drivers/tty/tty_ldisc.c b/drivers/tty/tty_ldisc.c index 77eac4ab1737..b36f4aa05b92 100644 --- a/drivers/tty/tty_ldisc.c +++ b/drivers/tty/tty_ldisc.c @@ -526,19 +526,16 @@ static int tty_ldisc_failto(struct tty_struct *tty, int ld) static void tty_ldisc_restore(struct tty_struct *tty, struct tty_ldisc *old) { /* There is an outstanding reference here so this is safe */ - old = tty_ldisc_get(tty, old->ops->num); - WARN_ON(IS_ERR(old)); - tty->ldisc = old; - tty_set_termios_ldisc(tty, old->ops->num); - if (tty_ldisc_open(tty, old) < 0) { - tty_ldisc_put(old); + if (tty_ldisc_failto(tty, old->ops->num) < 0) { + const char *name = tty_name(tty); + + pr_warn("Falling back ldisc for %s.\n", name); /* The traditional behaviour is to fall back to N_TTY, we want to avoid falling back to N_NULL unless we have no choice to avoid the risk of breaking anything */ if (tty_ldisc_failto(tty, N_TTY) < 0 && tty_ldisc_failto(tty, N_NULL) < 0) - panic("Couldn't open N_NULL ldisc for %s.", - tty_name(tty)); + panic("Couldn't open N_NULL ldisc for %s.", name); } } -- GitLab From 545906124041557d02f0dd29a59aef3182fd3ccb Mon Sep 17 00:00:00 2001 From: Tetsuo Handa Date: Wed, 25 Apr 2018 20:12:31 +0900 Subject: [PATCH 1265/1635] tty: Use __GFP_NOFAIL for tty_ldisc_get() commit bcdd0ca8cb8730573afebcaae4138f8f4c8eaa20 upstream. syzbot is reporting crashes triggered by memory allocation fault injection at tty_ldisc_get() [1]. As an attempt to handle OOM in a graceful way, we have tried commit 5362544bebe85071 ("tty: don't panic on OOM in tty_set_ldisc()"). But we reverted that attempt by commit a8983d01f9b7d600 ("Revert "tty: don't panic on OOM in tty_set_ldisc()"") due to reproducible crash. We should spend resource for finding and fixing race condition bugs rather than complicate error paths for 2 * sizeof(void *) bytes allocation failure. [1] https://syzkaller.appspot.com/bug?id=489d33fa386453859ead58ff5171d43772b13aa3 Signed-off-by: Tetsuo Handa Reported-by: syzbot Cc: Michal Hocko Cc: Vegard Nossum Cc: Dmitry Vyukov Cc: Jiri Slaby Cc: Peter Hurley Cc: One Thousand Gnomes Cc: Linus Torvalds Cc: stable Signed-off-by: Greg Kroah-Hartman Signed-off-by: Greg Kroah-Hartman --- drivers/tty/tty_ldisc.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/drivers/tty/tty_ldisc.c b/drivers/tty/tty_ldisc.c index b36f4aa05b92..ca656ef8de64 100644 --- a/drivers/tty/tty_ldisc.c +++ b/drivers/tty/tty_ldisc.c @@ -175,12 +175,11 @@ static struct tty_ldisc *tty_ldisc_get(struct tty_struct *tty, int disc) return ERR_CAST(ldops); } - ld = kmalloc(sizeof(struct tty_ldisc), GFP_KERNEL); - if (ld == NULL) { - put_ldops(ldops); - return ERR_PTR(-ENOMEM); - } - + /* + * There is no way to handle allocation failure of only 16 bytes. + * Let's simplify error handling and save more memory. + */ + ld = kmalloc(sizeof(struct tty_ldisc), GFP_KERNEL | __GFP_NOFAIL); ld->ops = ldops; ld->tty = tty; -- GitLab From ba9c9886a40ddaeaa07e8fc81da3bbc755192115 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Sun, 22 Apr 2018 21:19:24 +0900 Subject: [PATCH 1266/1635] ALSA: dice: fix OUI for TC group commit 10412c420af9ba1f3de8483a95d360e5eb5bfc84 upstream. OUI for TC Electronic is 0x000166, for TC GROUP A/S. 0x001486 is for Echo Digital Audio Corporation. Fixes: 7cafc65b3aa1 ('ALSA: dice: force to add two pcm devices for listed models') Cc: # v4.6+ Reference: http://standards-oui.ieee.org/oui/oui.txt Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/firewire/dice/dice.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/firewire/dice/dice.c b/sound/firewire/dice/dice.c index 4ddb4cdd054b..96bb01b6b751 100644 --- a/sound/firewire/dice/dice.c +++ b/sound/firewire/dice/dice.c @@ -14,7 +14,7 @@ MODULE_LICENSE("GPL v2"); #define OUI_WEISS 0x001c6a #define OUI_LOUD 0x000ff2 #define OUI_FOCUSRITE 0x00130e -#define OUI_TCELECTRONIC 0x001486 +#define OUI_TCELECTRONIC 0x000166 #define DICE_CATEGORY_ID 0x04 #define WEISS_CATEGORY_ID 0x00 -- GitLab From d03fbe62e173c8946b271e521d7b9237ae4d2305 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Thu, 26 Apr 2018 22:00:29 +0900 Subject: [PATCH 1267/1635] ALSA: dice: fix error path to destroy initialized stream data commit 0f925660a7bc49b269c163249a5d06da3a0c7b0a upstream. In error path of snd_dice_stream_init_duplex(), stream data for incoming packet can be left to be initialized. This commit fixes it. Fixes: 436b5abe2224 ('ALSA: dice: handle whole available isochronous streams') Cc: # v4.6+ Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/firewire/dice/dice-stream.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/firewire/dice/dice-stream.c b/sound/firewire/dice/dice-stream.c index 8573289c381e..928a255bfc35 100644 --- a/sound/firewire/dice/dice-stream.c +++ b/sound/firewire/dice/dice-stream.c @@ -435,7 +435,7 @@ int snd_dice_stream_init_duplex(struct snd_dice *dice) err = init_stream(dice, AMDTP_IN_STREAM, i); if (err < 0) { for (; i >= 0; i--) - destroy_stream(dice, AMDTP_OUT_STREAM, i); + destroy_stream(dice, AMDTP_IN_STREAM, i); goto end; } } -- GitLab From 19baecfc11058e923d66cd0b32e9339ec94f6b92 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 25 Apr 2018 16:19:13 +0200 Subject: [PATCH 1268/1635] ALSA: hda - Skip jack and others for non-existing PCM streams commit 8a7d6003df41cb16f6b3b620da044fbd92d2f5ee upstream. When CONFIG_SND_DYNAMIC_MINORS isn't set, there are only limited number of devices available, and HD-audio, especially with HDMI/DP codec, will fail to create more than two devices. The driver warns about the lack of such devices and skips the PCM device creations, but the HDMI driver still tries to create the corresponding JACK, SPDIF and ELD controls even for the non-existing PCM substreams. This results in confusion on user-space, and even may break the operation. Similarly, Intel HDMI/DP codec builds the ELD notification from i915 graphics driver, and this may be broken if a notification is sent for the non-existing PCM stream. This patch adds the check of the existence of the assigned PCM substream in the both scenarios above, and skips the further operation if the PCM substream is not assigned. Fixes: 9152085defb6 ("ALSA: hda - add DP MST audio support") Cc: Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/pci/hda/patch_hdmi.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index b4f1b6e88305..7d7eb1354eee 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -1383,6 +1383,8 @@ static void hdmi_pcm_setup_pin(struct hdmi_spec *spec, pcm = get_pcm_rec(spec, per_pin->pcm_idx); else return; + if (!pcm->pcm) + return; if (!test_bit(per_pin->pcm_idx, &spec->pcm_in_use)) return; @@ -2151,8 +2153,13 @@ static int generic_hdmi_build_controls(struct hda_codec *codec) int dev, err; int pin_idx, pcm_idx; - for (pcm_idx = 0; pcm_idx < spec->pcm_used; pcm_idx++) { + if (!get_pcm_rec(spec, pcm_idx)->pcm) { + /* no PCM: mark this for skipping permanently */ + set_bit(pcm_idx, &spec->pcm_bitmap); + continue; + } + err = generic_hdmi_build_jack(codec, pcm_idx); if (err < 0) return err; -- GitLab From b67a05364e5daf88fc37d1c84e8b91ea460f0aae Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 24 Apr 2018 07:56:07 +0200 Subject: [PATCH 1269/1635] ALSA: opl3: Hardening for potential Spectre v1 commit 7f054a5bee0987f1e2d4e59daea462421c76f2cb upstream. As recently Smatch suggested, one place in OPL3 driver may expand the array directly from the user-space value with speculation: sound/drivers/opl3/opl3_synth.c:476 snd_opl3_set_voice() warn: potential spectre issue 'snd_opl3_regmap' This patch puts array_index_nospec() for hardening against it. BugLink: https://marc.info/?l=linux-kernel&m=152411496503418&w=2 Reported-by: Dan Carpenter Cc: Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/drivers/opl3/opl3_synth.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/sound/drivers/opl3/opl3_synth.c b/sound/drivers/opl3/opl3_synth.c index ddcc1a325a61..42920a243328 100644 --- a/sound/drivers/opl3/opl3_synth.c +++ b/sound/drivers/opl3/opl3_synth.c @@ -21,6 +21,7 @@ #include #include +#include #include #include @@ -448,7 +449,7 @@ static int snd_opl3_set_voice(struct snd_opl3 * opl3, struct snd_dm_fm_voice * v { unsigned short reg_side; unsigned char op_offset; - unsigned char voice_offset; + unsigned char voice_offset, voice_op; unsigned short opl3_reg; unsigned char reg_val; @@ -473,7 +474,9 @@ static int snd_opl3_set_voice(struct snd_opl3 * opl3, struct snd_dm_fm_voice * v voice_offset = voice->voice - MAX_OPL2_VOICES; } /* Get register offset of operator */ - op_offset = snd_opl3_regmap[voice_offset][voice->op]; + voice_offset = array_index_nospec(voice_offset, MAX_OPL2_VOICES); + voice_op = array_index_nospec(voice->op, 4); + op_offset = snd_opl3_regmap[voice_offset][voice_op]; reg_val = 0x00; /* Set amplitude modulation (tremolo) effect */ -- GitLab From 8f1705268fd2ad526a9845ea5a44bf82abec853e Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 24 Apr 2018 08:01:48 +0200 Subject: [PATCH 1270/1635] ALSA: asihpi: Hardening for potential Spectre v1 commit f9d94b57e30fd1575b4935045b32d738668aa74b upstream. As recently Smatch suggested, a couple of places in ASIHPI driver may expand the array directly from the user-space value with speculation: sound/pci/asihpi/hpimsginit.c:70 hpi_init_response() warn: potential spectre issue 'res_size' (local cap) sound/pci/asihpi/hpioctl.c:189 asihpi_hpi_ioctl() warn: potential spectre issue 'adapters' This patch puts array_index_nospec() for hardening against them. BugLink: https://marc.info/?l=linux-kernel&m=152411496503418&w=2 Reported-by: Dan Carpenter Cc: Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/pci/asihpi/hpimsginit.c | 13 +++++++++---- sound/pci/asihpi/hpioctl.c | 4 +++- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/sound/pci/asihpi/hpimsginit.c b/sound/pci/asihpi/hpimsginit.c index 7eb617175fde..a31a70dccecf 100644 --- a/sound/pci/asihpi/hpimsginit.c +++ b/sound/pci/asihpi/hpimsginit.c @@ -23,6 +23,7 @@ #include "hpi_internal.h" #include "hpimsginit.h" +#include /* The actual message size for each object type */ static u16 msg_size[HPI_OBJ_MAXINDEX + 1] = HPI_MESSAGE_SIZE_BY_OBJECT; @@ -39,10 +40,12 @@ static void hpi_init_message(struct hpi_message *phm, u16 object, { u16 size; - if ((object > 0) && (object <= HPI_OBJ_MAXINDEX)) + if ((object > 0) && (object <= HPI_OBJ_MAXINDEX)) { + object = array_index_nospec(object, HPI_OBJ_MAXINDEX + 1); size = msg_size[object]; - else + } else { size = sizeof(*phm); + } memset(phm, 0, size); phm->size = size; @@ -66,10 +69,12 @@ void hpi_init_response(struct hpi_response *phr, u16 object, u16 function, { u16 size; - if ((object > 0) && (object <= HPI_OBJ_MAXINDEX)) + if ((object > 0) && (object <= HPI_OBJ_MAXINDEX)) { + object = array_index_nospec(object, HPI_OBJ_MAXINDEX + 1); size = res_size[object]; - else + } else { size = sizeof(*phr); + } memset(phr, 0, sizeof(*phr)); phr->size = size; diff --git a/sound/pci/asihpi/hpioctl.c b/sound/pci/asihpi/hpioctl.c index 5badd08e1d69..b1a2a7ea4172 100644 --- a/sound/pci/asihpi/hpioctl.c +++ b/sound/pci/asihpi/hpioctl.c @@ -33,6 +33,7 @@ #include #include #include +#include #ifdef MODULE_FIRMWARE MODULE_FIRMWARE("asihpi/dsp5000.bin"); @@ -186,7 +187,8 @@ long asihpi_hpi_ioctl(struct file *file, unsigned int cmd, unsigned long arg) struct hpi_adapter *pa = NULL; if (hm->h.adapter_index < ARRAY_SIZE(adapters)) - pa = &adapters[hm->h.adapter_index]; + pa = &adapters[array_index_nospec(hm->h.adapter_index, + ARRAY_SIZE(adapters))]; if (!pa || !pa->adapter || !pa->adapter->type) { hpi_init_response(&hr->r0, hm->h.object, -- GitLab From f8616ffbb78d84d256106a96a2b7b02cd7123961 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 24 Apr 2018 08:03:14 +0200 Subject: [PATCH 1271/1635] ALSA: hdspm: Hardening for potential Spectre v1 commit 10513142a7114d251670361ad40cba2c61403406 upstream. As recently Smatch suggested, a couple of places in HDSP MADI driver may expand the array directly from the user-space value with speculation: sound/pci/rme9652/hdspm.c:5717 snd_hdspm_channel_info() warn: potential spectre issue 'hdspm->channel_map_out' (local cap) sound/pci/rme9652/hdspm.c:5734 snd_hdspm_channel_info() warn: potential spectre issue 'hdspm->channel_map_in' (local cap) This patch puts array_index_nospec() for hardening against them. BugLink: https://marc.info/?l=linux-kernel&m=152411496503418&w=2 Reported-by: Dan Carpenter Cc: Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/pci/rme9652/hdspm.c | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c index f20d42714e4d..343f533906ba 100644 --- a/sound/pci/rme9652/hdspm.c +++ b/sound/pci/rme9652/hdspm.c @@ -137,6 +137,7 @@ #include #include #include +#include #include #include @@ -5698,40 +5699,43 @@ static int snd_hdspm_channel_info(struct snd_pcm_substream *substream, struct snd_pcm_channel_info *info) { struct hdspm *hdspm = snd_pcm_substream_chip(substream); + unsigned int channel = info->channel; if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - if (snd_BUG_ON(info->channel >= hdspm->max_channels_out)) { + if (snd_BUG_ON(channel >= hdspm->max_channels_out)) { dev_info(hdspm->card->dev, "snd_hdspm_channel_info: output channel out of range (%d)\n", - info->channel); + channel); return -EINVAL; } - if (hdspm->channel_map_out[info->channel] < 0) { + channel = array_index_nospec(channel, hdspm->max_channels_out); + if (hdspm->channel_map_out[channel] < 0) { dev_info(hdspm->card->dev, "snd_hdspm_channel_info: output channel %d mapped out\n", - info->channel); + channel); return -EINVAL; } - info->offset = hdspm->channel_map_out[info->channel] * + info->offset = hdspm->channel_map_out[channel] * HDSPM_CHANNEL_BUFFER_BYTES; } else { - if (snd_BUG_ON(info->channel >= hdspm->max_channels_in)) { + if (snd_BUG_ON(channel >= hdspm->max_channels_in)) { dev_info(hdspm->card->dev, "snd_hdspm_channel_info: input channel out of range (%d)\n", - info->channel); + channel); return -EINVAL; } - if (hdspm->channel_map_in[info->channel] < 0) { + channel = array_index_nospec(channel, hdspm->max_channels_in); + if (hdspm->channel_map_in[channel] < 0) { dev_info(hdspm->card->dev, "snd_hdspm_channel_info: input channel %d mapped out\n", - info->channel); + channel); return -EINVAL; } - info->offset = hdspm->channel_map_in[info->channel] * + info->offset = hdspm->channel_map_in[channel] * HDSPM_CHANNEL_BUFFER_BYTES; } -- GitLab From 9d57d45965dd1acd6a256787ad17e644af605a67 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 24 Apr 2018 08:04:41 +0200 Subject: [PATCH 1272/1635] ALSA: rme9652: Hardening for potential Spectre v1 commit f526afcd8f71945c23ce581d7864ace93de8a4f7 upstream. As recently Smatch suggested, one place in RME9652 driver may expand the array directly from the user-space value with speculation: sound/pci/rme9652/rme9652.c:2074 snd_rme9652_channel_info() warn: potential spectre issue 'rme9652->channel_map' (local cap) This patch puts array_index_nospec() for hardening against it. BugLink: https://marc.info/?l=linux-kernel&m=152411496503418&w=2 Reported-by: Dan Carpenter Cc: Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/pci/rme9652/rme9652.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/sound/pci/rme9652/rme9652.c b/sound/pci/rme9652/rme9652.c index df648b1d9217..edd765e22377 100644 --- a/sound/pci/rme9652/rme9652.c +++ b/sound/pci/rme9652/rme9652.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include @@ -2071,9 +2072,10 @@ static int snd_rme9652_channel_info(struct snd_pcm_substream *substream, if (snd_BUG_ON(info->channel >= RME9652_NCHANNELS)) return -EINVAL; - if ((chn = rme9652->channel_map[info->channel]) < 0) { + chn = rme9652->channel_map[array_index_nospec(info->channel, + RME9652_NCHANNELS)]; + if (chn < 0) return -EINVAL; - } info->offset = chn * RME9652_CHANNEL_BUFFER_BYTES; info->first = 0; -- GitLab From 6ab1a94d17dbf959f5910f56edda84889f5ddd39 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 24 Apr 2018 07:45:56 +0200 Subject: [PATCH 1273/1635] ALSA: control: Hardening for potential Spectre v1 commit 088e861edffb84879cf0c0d1b02eda078c3a0ffe upstream. As recently Smatch suggested, a few places in ALSA control core codes may expand the array directly from the user-space value with speculation: sound/core/control.c:1003 snd_ctl_elem_lock() warn: potential spectre issue 'kctl->vd' sound/core/control.c:1031 snd_ctl_elem_unlock() warn: potential spectre issue 'kctl->vd' sound/core/control.c:844 snd_ctl_elem_info() warn: potential spectre issue 'kctl->vd' sound/core/control.c:891 snd_ctl_elem_read() warn: potential spectre issue 'kctl->vd' sound/core/control.c:939 snd_ctl_elem_write() warn: potential spectre issue 'kctl->vd' Although all these seem doing only the first load without further reference, we may want to stay in a safer side, so hardening with array_index_nospec() would still make sense. In this patch, we put array_index_nospec() to the common snd_ctl_get_ioff*() helpers instead of each caller. These helpers are also referred from some drivers, too, and basically all usages are to calculate the array index from the user-space value, hence it's better to cover there. BugLink: https://marc.info/?l=linux-kernel&m=152411496503418&w=2 Reported-by: Dan Carpenter Cc: Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- include/sound/control.h | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/include/sound/control.h b/include/sound/control.h index ca13a44ae9d4..6011a58d3e20 100644 --- a/include/sound/control.h +++ b/include/sound/control.h @@ -23,6 +23,7 @@ */ #include +#include #include #define snd_kcontrol_chip(kcontrol) ((kcontrol)->private_data) @@ -148,12 +149,14 @@ int snd_ctl_get_preferred_subdevice(struct snd_card *card, int type); static inline unsigned int snd_ctl_get_ioffnum(struct snd_kcontrol *kctl, struct snd_ctl_elem_id *id) { - return id->numid - kctl->id.numid; + unsigned int ioff = id->numid - kctl->id.numid; + return array_index_nospec(ioff, kctl->count); } static inline unsigned int snd_ctl_get_ioffidx(struct snd_kcontrol *kctl, struct snd_ctl_elem_id *id) { - return id->index - kctl->id.index; + unsigned int ioff = id->index - kctl->id.index; + return array_index_nospec(ioff, kctl->count); } static inline unsigned int snd_ctl_get_ioff(struct snd_kcontrol *kctl, struct snd_ctl_elem_id *id) -- GitLab From 00e0495d83277d43078aa99b3186cc527af792a5 Mon Sep 17 00:00:00 2001 From: Jeffery Miller Date: Fri, 20 Apr 2018 23:20:46 -0500 Subject: [PATCH 1274/1635] ALSA: pcm: Return negative delays from SNDRV_PCM_IOCTL_DELAY. commit 912e4c332037e7ed063c164985c36fb2b549ea3a upstream. The commit c2c86a97175f ("ALSA: pcm: Remove set_fs() in PCM core code") changed SNDRV_PCM_IOCTL_DELAY to return an inconsistent error instead of a negative delay. Originally the call would succeed and return the negative delay. The Chromium OS Audio Server (CRAS) gets confused and hangs when the error is returned instead of the negative delay. Help CRAS avoid the issue by rolling back the behavior to return a negative delay instead of an error. Fixes: c2c86a97175f ("ALSA: pcm: Remove set_fs() in PCM core code") Signed-off-by: Jeffery Miller Cc: # v4.13+ Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/core/pcm_compat.c | 7 ++++--- sound/core/pcm_native.c | 23 +++++++++++------------ 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/sound/core/pcm_compat.c b/sound/core/pcm_compat.c index b719d0bd833e..06d7c40af570 100644 --- a/sound/core/pcm_compat.c +++ b/sound/core/pcm_compat.c @@ -27,10 +27,11 @@ static int snd_pcm_ioctl_delay_compat(struct snd_pcm_substream *substream, s32 __user *src) { snd_pcm_sframes_t delay; + int err; - delay = snd_pcm_delay(substream); - if (delay < 0) - return delay; + err = snd_pcm_delay(substream, &delay); + if (err) + return err; if (put_user(delay, src)) return -EFAULT; return 0; diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index eba2bedcbc81..5f68258a1dfc 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -2689,7 +2689,8 @@ static int snd_pcm_hwsync(struct snd_pcm_substream *substream) return err; } -static snd_pcm_sframes_t snd_pcm_delay(struct snd_pcm_substream *substream) +static int snd_pcm_delay(struct snd_pcm_substream *substream, + snd_pcm_sframes_t *delay) { struct snd_pcm_runtime *runtime = substream->runtime; int err; @@ -2705,7 +2706,9 @@ static snd_pcm_sframes_t snd_pcm_delay(struct snd_pcm_substream *substream) n += runtime->delay; } snd_pcm_stream_unlock_irq(substream); - return err < 0 ? err : n; + if (!err) + *delay = n; + return err; } static int snd_pcm_sync_ptr(struct snd_pcm_substream *substream, @@ -2913,11 +2916,13 @@ static int snd_pcm_common_ioctl(struct file *file, return snd_pcm_hwsync(substream); case SNDRV_PCM_IOCTL_DELAY: { - snd_pcm_sframes_t delay = snd_pcm_delay(substream); + snd_pcm_sframes_t delay; snd_pcm_sframes_t __user *res = arg; + int err; - if (delay < 0) - return delay; + err = snd_pcm_delay(substream, &delay); + if (err) + return err; if (put_user(delay, res)) return -EFAULT; return 0; @@ -3005,13 +3010,7 @@ int snd_pcm_kernel_ioctl(struct snd_pcm_substream *substream, case SNDRV_PCM_IOCTL_DROP: return snd_pcm_drop(substream); case SNDRV_PCM_IOCTL_DELAY: - { - result = snd_pcm_delay(substream); - if (result < 0) - return result; - *frames = result; - return 0; - } + return snd_pcm_delay(substream, frames); default: return -EINVAL; } -- GitLab From 30ddc329d56281c0c1d038d5f572af3c31e6b0a6 Mon Sep 17 00:00:00 2001 From: David Henningsson Date: Sat, 21 Apr 2018 14:57:40 +0200 Subject: [PATCH 1275/1635] ALSA: core: Report audio_tstamp in snd_pcm_sync_ptr commit f853dcaae2f5bbe021161e421bd1576845bae8f6 upstream. It looks like a simple mistake that this struct member was forgotten. Audio_tstamp isn't used much, and on some archs (such as x86) this ioctl is not used by default, so that might be the reason why this has slipped for so long. Fixes: 4eeaaeaea1ce ("ALSA: core: add hooks for audio timestamps") Signed-off-by: David Henningsson Reviewed-by: Takashi Sakamoto Cc: # v3.8+ Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/core/pcm_native.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 5f68258a1dfc..ab3bf36786b6 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -2751,6 +2751,7 @@ static int snd_pcm_sync_ptr(struct snd_pcm_substream *substream, sync_ptr.s.status.hw_ptr = status->hw_ptr; sync_ptr.s.status.tstamp = status->tstamp; sync_ptr.s.status.suspended_state = status->suspended_state; + sync_ptr.s.status.audio_tstamp = status->audio_tstamp; snd_pcm_stream_unlock_irq(substream); if (copy_to_user(_sync_ptr, &sync_ptr, sizeof(sync_ptr))) return -EFAULT; -- GitLab From 4a52a2127240ea5149a83ab80c7adacb4e36e7a4 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 24 Apr 2018 07:26:59 +0200 Subject: [PATCH 1276/1635] ALSA: seq: oss: Fix unbalanced use lock for synth MIDI device commit f5e94b4c6ebdabe0f602d796e0430180927521a0 upstream. When get_synthdev() is called for a MIDI device, it returns the fixed midi_synth_dev without the use refcounting. OTOH, the caller is supposed to unreference unconditionally after the usage, so this would lead to unbalanced refcount. This patch corrects the behavior and keep up the refcount balance also for the MIDI synth device. Cc: Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/core/seq/oss/seq_oss_synth.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/sound/core/seq/oss/seq_oss_synth.c b/sound/core/seq/oss/seq_oss_synth.c index cd0e0ebbfdb1..9e2b250ae780 100644 --- a/sound/core/seq/oss/seq_oss_synth.c +++ b/sound/core/seq/oss/seq_oss_synth.c @@ -363,10 +363,14 @@ get_synthdev(struct seq_oss_devinfo *dp, int dev) return NULL; if (! dp->synths[dev].opened) return NULL; - if (dp->synths[dev].is_midi) - return &midi_synth_dev; - if ((rec = get_sdev(dev)) == NULL) - return NULL; + if (dp->synths[dev].is_midi) { + rec = &midi_synth_dev; + snd_use_lock_use(&rec->use_lock); + } else { + rec = get_sdev(dev); + if (!rec) + return NULL; + } if (! rec->opened) { snd_use_lock_free(&rec->use_lock); return NULL; -- GitLab From bda3aba8c0a161232d634c1ef695e72683f9f20a Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 24 Apr 2018 07:31:54 +0200 Subject: [PATCH 1277/1635] ALSA: seq: oss: Hardening for potential Spectre v1 commit 8d218dd8116695ecda7164f97631c069938aa22e upstream. As Smatch recently suggested, a few places in OSS sequencer codes may expand the array directly from the user-space value with speculation, namely there are a significant amount of references to either info->ch[] or dp->synths[] array: sound/core/seq/oss/seq_oss_event.c:315 note_on_event() warn: potential spectre issue 'info->ch' (local cap) sound/core/seq/oss/seq_oss_event.c:362 note_off_event() warn: potential spectre issue 'info->ch' (local cap) sound/core/seq/oss/seq_oss_synth.c:470 snd_seq_oss_synth_load_patch() warn: potential spectre issue 'dp->synths' (local cap) sound/core/seq/oss/seq_oss_event.c:293 note_on_event() warn: potential spectre issue 'dp->synths' sound/core/seq/oss/seq_oss_event.c:353 note_off_event() warn: potential spectre issue 'dp->synths' sound/core/seq/oss/seq_oss_synth.c:506 snd_seq_oss_synth_sysex() warn: potential spectre issue 'dp->synths' sound/core/seq/oss/seq_oss_synth.c:580 snd_seq_oss_synth_ioctl() warn: potential spectre issue 'dp->synths' Although all these seem doing only the first load without further reference, we may want to stay in a safer side, so hardening with array_index_nospec() would still make sense. We may put array_index_nospec() at each place, but here we take a different approach: - For dp->synths[], change the helpers to retrieve seq_oss_synthinfo pointer directly instead of the array expansion at each place - For info->ch[], harden in a normal way, as there are only a couple of places As a result, the existing helper, snd_seq_oss_synth_is_valid() is replaced with snd_seq_oss_synth_info(). Also, we cover MIDI device where a similar array expansion is done, too, although it wasn't reported by Smatch. BugLink: https://marc.info/?l=linux-kernel&m=152411496503418&w=2 Reported-by: Dan Carpenter Cc: Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/core/seq/oss/seq_oss_event.c | 15 +++--- sound/core/seq/oss/seq_oss_midi.c | 2 + sound/core/seq/oss/seq_oss_synth.c | 75 +++++++++++++++++------------- sound/core/seq/oss/seq_oss_synth.h | 3 +- 4 files changed, 55 insertions(+), 40 deletions(-) diff --git a/sound/core/seq/oss/seq_oss_event.c b/sound/core/seq/oss/seq_oss_event.c index c3908862bc8b..86ca584c27b2 100644 --- a/sound/core/seq/oss/seq_oss_event.c +++ b/sound/core/seq/oss/seq_oss_event.c @@ -26,6 +26,7 @@ #include #include "seq_oss_readq.h" #include "seq_oss_writeq.h" +#include /* @@ -287,10 +288,10 @@ note_on_event(struct seq_oss_devinfo *dp, int dev, int ch, int note, int vel, st { struct seq_oss_synthinfo *info; - if (!snd_seq_oss_synth_is_valid(dp, dev)) + info = snd_seq_oss_synth_info(dp, dev); + if (!info) return -ENXIO; - info = &dp->synths[dev]; switch (info->arg.event_passing) { case SNDRV_SEQ_OSS_PROCESS_EVENTS: if (! info->ch || ch < 0 || ch >= info->nr_voices) { @@ -298,6 +299,7 @@ note_on_event(struct seq_oss_devinfo *dp, int dev, int ch, int note, int vel, st return set_note_event(dp, dev, SNDRV_SEQ_EVENT_NOTEON, ch, note, vel, ev); } + ch = array_index_nospec(ch, info->nr_voices); if (note == 255 && info->ch[ch].note >= 0) { /* volume control */ int type; @@ -347,10 +349,10 @@ note_off_event(struct seq_oss_devinfo *dp, int dev, int ch, int note, int vel, s { struct seq_oss_synthinfo *info; - if (!snd_seq_oss_synth_is_valid(dp, dev)) + info = snd_seq_oss_synth_info(dp, dev); + if (!info) return -ENXIO; - info = &dp->synths[dev]; switch (info->arg.event_passing) { case SNDRV_SEQ_OSS_PROCESS_EVENTS: if (! info->ch || ch < 0 || ch >= info->nr_voices) { @@ -358,6 +360,7 @@ note_off_event(struct seq_oss_devinfo *dp, int dev, int ch, int note, int vel, s return set_note_event(dp, dev, SNDRV_SEQ_EVENT_NOTEON, ch, note, vel, ev); } + ch = array_index_nospec(ch, info->nr_voices); if (info->ch[ch].note >= 0) { note = info->ch[ch].note; info->ch[ch].vel = 0; @@ -381,7 +384,7 @@ note_off_event(struct seq_oss_devinfo *dp, int dev, int ch, int note, int vel, s static int set_note_event(struct seq_oss_devinfo *dp, int dev, int type, int ch, int note, int vel, struct snd_seq_event *ev) { - if (! snd_seq_oss_synth_is_valid(dp, dev)) + if (!snd_seq_oss_synth_info(dp, dev)) return -ENXIO; ev->type = type; @@ -399,7 +402,7 @@ set_note_event(struct seq_oss_devinfo *dp, int dev, int type, int ch, int note, static int set_control_event(struct seq_oss_devinfo *dp, int dev, int type, int ch, int param, int val, struct snd_seq_event *ev) { - if (! snd_seq_oss_synth_is_valid(dp, dev)) + if (!snd_seq_oss_synth_info(dp, dev)) return -ENXIO; ev->type = type; diff --git a/sound/core/seq/oss/seq_oss_midi.c b/sound/core/seq/oss/seq_oss_midi.c index b30b2139e3f0..9debd1b8fd28 100644 --- a/sound/core/seq/oss/seq_oss_midi.c +++ b/sound/core/seq/oss/seq_oss_midi.c @@ -29,6 +29,7 @@ #include "../seq_lock.h" #include #include +#include /* @@ -315,6 +316,7 @@ get_mididev(struct seq_oss_devinfo *dp, int dev) { if (dev < 0 || dev >= dp->max_mididev) return NULL; + dev = array_index_nospec(dev, dp->max_mididev); return get_mdev(dev); } diff --git a/sound/core/seq/oss/seq_oss_synth.c b/sound/core/seq/oss/seq_oss_synth.c index 9e2b250ae780..278ebb993122 100644 --- a/sound/core/seq/oss/seq_oss_synth.c +++ b/sound/core/seq/oss/seq_oss_synth.c @@ -26,6 +26,7 @@ #include #include #include +#include /* * constants @@ -339,17 +340,13 @@ snd_seq_oss_synth_cleanup(struct seq_oss_devinfo *dp) dp->max_synthdev = 0; } -/* - * check if the specified device is MIDI mapped device - */ -static int -is_midi_dev(struct seq_oss_devinfo *dp, int dev) +static struct seq_oss_synthinfo * +get_synthinfo_nospec(struct seq_oss_devinfo *dp, int dev) { if (dev < 0 || dev >= dp->max_synthdev) - return 0; - if (dp->synths[dev].is_midi) - return 1; - return 0; + return NULL; + dev = array_index_nospec(dev, SNDRV_SEQ_OSS_MAX_SYNTH_DEVS); + return &dp->synths[dev]; } /* @@ -359,11 +356,13 @@ static struct seq_oss_synth * get_synthdev(struct seq_oss_devinfo *dp, int dev) { struct seq_oss_synth *rec; - if (dev < 0 || dev >= dp->max_synthdev) + struct seq_oss_synthinfo *info = get_synthinfo_nospec(dp, dev); + + if (!info) return NULL; - if (! dp->synths[dev].opened) + if (!info->opened) return NULL; - if (dp->synths[dev].is_midi) { + if (info->is_midi) { rec = &midi_synth_dev; snd_use_lock_use(&rec->use_lock); } else { @@ -406,10 +405,8 @@ snd_seq_oss_synth_reset(struct seq_oss_devinfo *dp, int dev) struct seq_oss_synth *rec; struct seq_oss_synthinfo *info; - if (snd_BUG_ON(dev < 0 || dev >= dp->max_synthdev)) - return; - info = &dp->synths[dev]; - if (! info->opened) + info = get_synthinfo_nospec(dp, dev); + if (!info || !info->opened) return; if (info->sysex) info->sysex->len = 0; /* reset sysex */ @@ -458,12 +455,14 @@ snd_seq_oss_synth_load_patch(struct seq_oss_devinfo *dp, int dev, int fmt, const char __user *buf, int p, int c) { struct seq_oss_synth *rec; + struct seq_oss_synthinfo *info; int rc; - if (dev < 0 || dev >= dp->max_synthdev) + info = get_synthinfo_nospec(dp, dev); + if (!info) return -ENXIO; - if (is_midi_dev(dp, dev)) + if (info->is_midi) return 0; if ((rec = get_synthdev(dp, dev)) == NULL) return -ENXIO; @@ -471,24 +470,25 @@ snd_seq_oss_synth_load_patch(struct seq_oss_devinfo *dp, int dev, int fmt, if (rec->oper.load_patch == NULL) rc = -ENXIO; else - rc = rec->oper.load_patch(&dp->synths[dev].arg, fmt, buf, p, c); + rc = rec->oper.load_patch(&info->arg, fmt, buf, p, c); snd_use_lock_free(&rec->use_lock); return rc; } /* - * check if the device is valid synth device + * check if the device is valid synth device and return the synth info */ -int -snd_seq_oss_synth_is_valid(struct seq_oss_devinfo *dp, int dev) +struct seq_oss_synthinfo * +snd_seq_oss_synth_info(struct seq_oss_devinfo *dp, int dev) { struct seq_oss_synth *rec; + rec = get_synthdev(dp, dev); if (rec) { snd_use_lock_free(&rec->use_lock); - return 1; + return get_synthinfo_nospec(dp, dev); } - return 0; + return NULL; } @@ -503,16 +503,18 @@ snd_seq_oss_synth_sysex(struct seq_oss_devinfo *dp, int dev, unsigned char *buf, int i, send; unsigned char *dest; struct seq_oss_synth_sysex *sysex; + struct seq_oss_synthinfo *info; - if (! snd_seq_oss_synth_is_valid(dp, dev)) + info = snd_seq_oss_synth_info(dp, dev); + if (!info) return -ENXIO; - sysex = dp->synths[dev].sysex; + sysex = info->sysex; if (sysex == NULL) { sysex = kzalloc(sizeof(*sysex), GFP_KERNEL); if (sysex == NULL) return -ENOMEM; - dp->synths[dev].sysex = sysex; + info->sysex = sysex; } send = 0; @@ -557,10 +559,12 @@ snd_seq_oss_synth_sysex(struct seq_oss_devinfo *dp, int dev, unsigned char *buf, int snd_seq_oss_synth_addr(struct seq_oss_devinfo *dp, int dev, struct snd_seq_event *ev) { - if (! snd_seq_oss_synth_is_valid(dp, dev)) + struct seq_oss_synthinfo *info = snd_seq_oss_synth_info(dp, dev); + + if (!info) return -EINVAL; - snd_seq_oss_fill_addr(dp, ev, dp->synths[dev].arg.addr.client, - dp->synths[dev].arg.addr.port); + snd_seq_oss_fill_addr(dp, ev, info->arg.addr.client, + info->arg.addr.port); return 0; } @@ -572,16 +576,18 @@ int snd_seq_oss_synth_ioctl(struct seq_oss_devinfo *dp, int dev, unsigned int cmd, unsigned long addr) { struct seq_oss_synth *rec; + struct seq_oss_synthinfo *info; int rc; - if (is_midi_dev(dp, dev)) + info = get_synthinfo_nospec(dp, dev); + if (!info || info->is_midi) return -ENXIO; if ((rec = get_synthdev(dp, dev)) == NULL) return -ENXIO; if (rec->oper.ioctl == NULL) rc = -ENXIO; else - rc = rec->oper.ioctl(&dp->synths[dev].arg, cmd, addr); + rc = rec->oper.ioctl(&info->arg, cmd, addr); snd_use_lock_free(&rec->use_lock); return rc; } @@ -593,7 +599,10 @@ snd_seq_oss_synth_ioctl(struct seq_oss_devinfo *dp, int dev, unsigned int cmd, u int snd_seq_oss_synth_raw_event(struct seq_oss_devinfo *dp, int dev, unsigned char *data, struct snd_seq_event *ev) { - if (! snd_seq_oss_synth_is_valid(dp, dev) || is_midi_dev(dp, dev)) + struct seq_oss_synthinfo *info; + + info = snd_seq_oss_synth_info(dp, dev); + if (!info || info->is_midi) return -ENXIO; ev->type = SNDRV_SEQ_EVENT_OSS; memcpy(ev->data.raw8.d, data, 8); diff --git a/sound/core/seq/oss/seq_oss_synth.h b/sound/core/seq/oss/seq_oss_synth.h index 74ac55f166b6..a63f9e22974d 100644 --- a/sound/core/seq/oss/seq_oss_synth.h +++ b/sound/core/seq/oss/seq_oss_synth.h @@ -37,7 +37,8 @@ void snd_seq_oss_synth_cleanup(struct seq_oss_devinfo *dp); void snd_seq_oss_synth_reset(struct seq_oss_devinfo *dp, int dev); int snd_seq_oss_synth_load_patch(struct seq_oss_devinfo *dp, int dev, int fmt, const char __user *buf, int p, int c); -int snd_seq_oss_synth_is_valid(struct seq_oss_devinfo *dp, int dev); +struct seq_oss_synthinfo *snd_seq_oss_synth_info(struct seq_oss_devinfo *dp, + int dev); int snd_seq_oss_synth_sysex(struct seq_oss_devinfo *dp, int dev, unsigned char *buf, struct snd_seq_event *ev); int snd_seq_oss_synth_addr(struct seq_oss_devinfo *dp, int dev, struct snd_seq_event *ev); -- GitLab From d680a34d82b6475ab4fea343c8390f115b72b41a Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 24 Apr 2018 07:50:50 +0200 Subject: [PATCH 1278/1635] ALSA: hda: Hardening for potential Spectre v1 commit 69fa6f19b95597618ab30438a27b67ad93daa7c7 upstream. As recently Smatch suggested, one place in HD-audio hwdep ioctl codes may expand the array directly from the user-space value with speculation: sound/pci/hda/hda_local.h:467 get_wcaps() warn: potential spectre issue 'codec->wcaps' As get_wcaps() itself is a fairly frequently called inline function, and there is only one single call with a user-space value, we replace only the latter one to open-code locally with array_index_nospec() hardening in this patch. BugLink: https://marc.info/?l=linux-kernel&m=152411496503418&w=2 Reported-by: Dan Carpenter Cc: Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/pci/hda/hda_hwdep.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/sound/pci/hda/hda_hwdep.c b/sound/pci/hda/hda_hwdep.c index 57df06e76968..cc009a4a3d1d 100644 --- a/sound/pci/hda/hda_hwdep.c +++ b/sound/pci/hda/hda_hwdep.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include "hda_codec.h" #include "hda_local.h" @@ -51,7 +52,16 @@ static int get_wcap_ioctl(struct hda_codec *codec, if (get_user(verb, &arg->verb)) return -EFAULT; - res = get_wcaps(codec, verb >> 24); + /* open-code get_wcaps(verb>>24) with nospec */ + verb >>= 24; + if (verb < codec->core.start_nid || + verb >= codec->core.start_nid + codec->core.num_nodes) { + res = 0; + } else { + verb -= codec->core.start_nid; + verb = array_index_nospec(verb, codec->core.num_nodes); + res = codec->wcaps[verb]; + } if (put_user(res, &arg->res)) return -EFAULT; return 0; -- GitLab From c9df23efe5ccdf646be0aad10b744c8d09a56ee1 Mon Sep 17 00:00:00 2001 From: Kailang Yang Date: Wed, 25 Apr 2018 15:31:52 +0800 Subject: [PATCH 1279/1635] ALSA: hda/realtek - Add some fixes for ALC233 commit ea04a1dbf8b1d6af759d58e705636fde48583f8f upstream. Fill COEF to change EAPD to verb control. Assigned codec type. This is an additional fix over 92f974df3460 ("ALSA: hda/realtek - New vendor ID for ALC233"). [ More notes: according to Kailang, the chip is 10ec:0235 bonding for ALC233b, which is equivalent with ALC255. It's only used for Lenovo. The chip needs no alc_process_coef_fw() for headset unlike ALC255. ] Signed-off-by: Kailang Yang Cc: Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/pci/hda/patch_realtek.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 590887d9b7a1..2acaea757c37 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -331,6 +331,7 @@ static void alc_fill_eapd_coef(struct hda_codec *codec) /* fallthrough */ case 0x10ec0215: case 0x10ec0233: + case 0x10ec0235: case 0x10ec0236: case 0x10ec0255: case 0x10ec0256: @@ -7015,6 +7016,7 @@ static int patch_alc269(struct hda_codec *codec) case 0x10ec0298: spec->codec_variant = ALC269_TYPE_ALC298; break; + case 0x10ec0235: case 0x10ec0255: spec->codec_variant = ALC269_TYPE_ALC255; break; -- GitLab From 53c4197a2d7e88272afae14e3b1f844f8469af01 Mon Sep 17 00:00:00 2001 From: Kailang Yang Date: Wed, 25 Apr 2018 16:05:27 +0800 Subject: [PATCH 1280/1635] ALSA: hda/realtek - Update ALC255 depop optimize commit ab3b8e5159b5335c81ba2d09ee5054d4a1b5a7a6 upstream. Add ALC255 its own depop functions for alc_init and alc_shutup. Assign it to ALC256 usage. Signed-off-by: Kailang Yang Cc: Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/pci/hda/patch_realtek.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 2acaea757c37..6db14af58441 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -7019,6 +7019,8 @@ static int patch_alc269(struct hda_codec *codec) case 0x10ec0235: case 0x10ec0255: spec->codec_variant = ALC269_TYPE_ALC255; + spec->shutup = alc256_shutup; + spec->init_hook = alc256_init; break; case 0x10ec0236: case 0x10ec0256: -- GitLab From 3d4612bf62c8f355a478169cba68cffe9d11bd82 Mon Sep 17 00:00:00 2001 From: Kailang Yang Date: Wed, 25 Apr 2018 17:07:27 +0800 Subject: [PATCH 1281/1635] ALSA: hda/realtek - change the location for one of two front mics commit 65811834ba56e9ed88117cf6c09880416c9951ab upstream. On this Lenovo ThinkCentre machine. There are two front mics, we change the location for one of them. Relation: f33f79f3d0e5 ("ALSA: hda/realtek - change the location for one of two front microphones") Signed-off-by: Kailang Yang Cc: Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/pci/hda/patch_realtek.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 6db14af58441..59daf9901466 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -6436,6 +6436,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x17aa, 0x30bb, "ThinkCentre AIO", ALC233_FIXUP_LENOVO_LINE2_MIC_HOTKEY), SND_PCI_QUIRK(0x17aa, 0x30e2, "ThinkCentre AIO", ALC233_FIXUP_LENOVO_LINE2_MIC_HOTKEY), SND_PCI_QUIRK(0x17aa, 0x310c, "ThinkCentre Station", ALC294_FIXUP_LENOVO_MIC_LOCATION), + SND_PCI_QUIRK(0x17aa, 0x312f, "ThinkCentre Station", ALC294_FIXUP_LENOVO_MIC_LOCATION), SND_PCI_QUIRK(0x17aa, 0x3138, "ThinkCentre Station", ALC294_FIXUP_LENOVO_MIC_LOCATION), SND_PCI_QUIRK(0x17aa, 0x313c, "ThinkCentre Station", ALC294_FIXUP_LENOVO_MIC_LOCATION), SND_PCI_QUIRK(0x17aa, 0x3112, "ThinkCentre AIO", ALC233_FIXUP_LENOVO_LINE2_MIC_HOTKEY), -- GitLab From 6c677c5968aaa8122f314aca78c7210bf01cb890 Mon Sep 17 00:00:00 2001 From: Thor Thayer Date: Mon, 23 Apr 2018 12:45:11 -0500 Subject: [PATCH 1282/1635] mtd: spi-nor: cadence-quadspi: Fix page fault kernel panic commit 47016b341fc3b3fd4909e058c6fa38f165b53646 upstream. The current Cadence QSPI driver caused a kernel panic when loading a Root Filesystem from QSPI. The problem was caused by reading more bytes than needed because the QSPI operated on 4 bytes at a time. [ 7.947754] spi_nor_read[1048]:from 0x037cad74, len 1 [bfe07fff] [ 7.956247] cqspi_read[910]:offset 0x58502516, buffer=bfe07fff [ 7.956247] [ 7.966046] Unable to handle kernel paging request at virtual address bfe08002 [ 7.973239] pgd = eebfc000 [ 7.975931] [bfe08002] *pgd=2fffb811, *pte=00000000, *ppte=00000000 Notice above how only 1 byte needed to be read but by reading 4 bytes into the end of a mapped page, an unrecoverable page fault occurred. This patch uses a temporary buffer to hold the 4 bytes read and then copies only the bytes required into the buffer. A min() function is used to limit the length to prevent buffer overflows. Request testing of this patch on other platforms. This was tested on the Intel Arria10 SoCFPGA DevKit. Fixes: 0cf1725676a97fc8 ("mtd: spi-nor: cqspi: Fix build on arches missing readsl/writesl") Signed-off-by: Thor Thayer Cc: Reviewed-by: Marek Vasut Signed-off-by: Boris Brezillon Signed-off-by: Greg Kroah-Hartman --- drivers/mtd/spi-nor/cadence-quadspi.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/drivers/mtd/spi-nor/cadence-quadspi.c b/drivers/mtd/spi-nor/cadence-quadspi.c index 53c7d8e0327a..8d89204b90d2 100644 --- a/drivers/mtd/spi-nor/cadence-quadspi.c +++ b/drivers/mtd/spi-nor/cadence-quadspi.c @@ -495,7 +495,9 @@ static int cqspi_indirect_read_execute(struct spi_nor *nor, void __iomem *reg_base = cqspi->iobase; void __iomem *ahb_base = cqspi->ahb_base; unsigned int remaining = n_rx; + unsigned int mod_bytes = n_rx % 4; unsigned int bytes_to_read = 0; + u8 *rxbuf_end = rxbuf + n_rx; int ret = 0; writel(remaining, reg_base + CQSPI_REG_INDIRECTRDBYTES); @@ -523,11 +525,24 @@ static int cqspi_indirect_read_execute(struct spi_nor *nor, } while (bytes_to_read != 0) { + unsigned int word_remain = round_down(remaining, 4); + bytes_to_read *= cqspi->fifo_width; bytes_to_read = bytes_to_read > remaining ? remaining : bytes_to_read; - ioread32_rep(ahb_base, rxbuf, - DIV_ROUND_UP(bytes_to_read, 4)); + bytes_to_read = round_down(bytes_to_read, 4); + /* Read 4 byte word chunks then single bytes */ + if (bytes_to_read) { + ioread32_rep(ahb_base, rxbuf, + (bytes_to_read / 4)); + } else if (!word_remain && mod_bytes) { + unsigned int temp = ioread32(ahb_base); + + bytes_to_read = mod_bytes; + memcpy(rxbuf, &temp, min((unsigned int) + (rxbuf_end - rxbuf), + bytes_to_read)); + } rxbuf += bytes_to_read; remaining -= bytes_to_read; bytes_to_read = cqspi_get_rd_sram_level(cqspi); -- GitLab From 1de1ad0c2c4262a9eafcbede4e662aa503f71f6c Mon Sep 17 00:00:00 2001 From: Joakim Tjernlund Date: Thu, 1 Mar 2018 14:39:39 +0100 Subject: [PATCH 1283/1635] mtd: cfi: cmdset_0001: Do not allow read/write to suspend erase block. commit 6510bbc88e3258631831ade49033537081950605 upstream. Currently it is possible to read and/or write to suspend EB's. Writing /dev/mtdX or /dev/mtdblockX from several processes may break the flash state machine. Signed-off-by: Joakim Tjernlund Cc: Reviewed-by: Richard Weinberger Signed-off-by: Boris Brezillon Signed-off-by: Greg Kroah-Hartman --- drivers/mtd/chips/cfi_cmdset_0001.c | 16 +++++++++++----- include/linux/mtd/flashchip.h | 1 + 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/drivers/mtd/chips/cfi_cmdset_0001.c b/drivers/mtd/chips/cfi_cmdset_0001.c index 5e1b68cbcd0a..a239ed4cb076 100644 --- a/drivers/mtd/chips/cfi_cmdset_0001.c +++ b/drivers/mtd/chips/cfi_cmdset_0001.c @@ -831,21 +831,25 @@ static int chip_ready (struct map_info *map, struct flchip *chip, unsigned long (mode == FL_WRITING && (cfip->SuspendCmdSupport & 1)))) goto sleep; + /* Do not allow suspend iff read/write to EB address */ + if ((adr & chip->in_progress_block_mask) == + chip->in_progress_block_addr) + goto sleep; /* Erase suspend */ - map_write(map, CMD(0xB0), adr); + map_write(map, CMD(0xB0), chip->in_progress_block_addr); /* If the flash has finished erasing, then 'erase suspend' * appears to make some (28F320) flash devices switch to * 'read' mode. Make sure that we switch to 'read status' * mode so we get the right data. --rmk */ - map_write(map, CMD(0x70), adr); + map_write(map, CMD(0x70), chip->in_progress_block_addr); chip->oldstate = FL_ERASING; chip->state = FL_ERASE_SUSPENDING; chip->erase_suspended = 1; for (;;) { - status = map_read(map, adr); + status = map_read(map, chip->in_progress_block_addr); if (map_word_andequal(map, status, status_OK, status_OK)) break; @@ -1041,8 +1045,8 @@ static void put_chip(struct map_info *map, struct flchip *chip, unsigned long ad sending the 0x70 (Read Status) command to an erasing chip and expecting it to be ignored, that's what we do. */ - map_write(map, CMD(0xd0), adr); - map_write(map, CMD(0x70), adr); + map_write(map, CMD(0xd0), chip->in_progress_block_addr); + map_write(map, CMD(0x70), chip->in_progress_block_addr); chip->oldstate = FL_READY; chip->state = FL_ERASING; break; @@ -1933,6 +1937,8 @@ static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip, map_write(map, CMD(0xD0), adr); chip->state = FL_ERASING; chip->erase_suspended = 0; + chip->in_progress_block_addr = adr; + chip->in_progress_block_mask = ~(len - 1); ret = INVAL_CACHE_AND_WAIT(map, chip, adr, adr, len, diff --git a/include/linux/mtd/flashchip.h b/include/linux/mtd/flashchip.h index b63fa457febd..3529683f691e 100644 --- a/include/linux/mtd/flashchip.h +++ b/include/linux/mtd/flashchip.h @@ -85,6 +85,7 @@ struct flchip { unsigned int write_suspended:1; unsigned int erase_suspended:1; unsigned long in_progress_block_addr; + unsigned long in_progress_block_mask; struct mutex mutex; wait_queue_head_t wq; /* Wait on here when we're waiting for the chip -- GitLab From 204e0761846b2458a2b803faa4619f0830cf26de Mon Sep 17 00:00:00 2001 From: Joakim Tjernlund Date: Thu, 1 Mar 2018 14:39:40 +0100 Subject: [PATCH 1284/1635] mtd: cfi: cmdset_0001: Workaround Micron Erase suspend bug. commit 46a16a2283f9e678a4e26829175e0c37a5191860 upstream. Some Micron chips does not work well wrt Erase suspend for boot blocks. This avoids the issue by not allowing Erase suspend for the boot blocks for the 28F00AP30(1GBit) chip. Signed-off-by: Joakim Tjernlund Cc: Reviewed-by: Richard Weinberger Signed-off-by: Boris Brezillon Signed-off-by: Greg Kroah-Hartman --- drivers/mtd/chips/cfi_cmdset_0001.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/drivers/mtd/chips/cfi_cmdset_0001.c b/drivers/mtd/chips/cfi_cmdset_0001.c index a239ed4cb076..e1b603ca0170 100644 --- a/drivers/mtd/chips/cfi_cmdset_0001.c +++ b/drivers/mtd/chips/cfi_cmdset_0001.c @@ -45,6 +45,7 @@ #define I82802AB 0x00ad #define I82802AC 0x00ac #define PF38F4476 0x881c +#define M28F00AP30 0x8963 /* STMicroelectronics chips */ #define M50LPW080 0x002F #define M50FLW080A 0x0080 @@ -375,6 +376,17 @@ static void cfi_fixup_major_minor(struct cfi_private *cfi, extp->MinorVersion = '1'; } +static int cfi_is_micron_28F00AP30(struct cfi_private *cfi, struct flchip *chip) +{ + /* + * Micron(was Numonyx) 1Gbit bottom boot are buggy w.r.t + * Erase Supend for their small Erase Blocks(0x8000) + */ + if (cfi->mfr == CFI_MFR_INTEL && cfi->id == M28F00AP30) + return 1; + return 0; +} + static inline struct cfi_pri_intelext * read_pri_intelext(struct map_info *map, __u16 adr) { @@ -836,6 +848,11 @@ static int chip_ready (struct map_info *map, struct flchip *chip, unsigned long chip->in_progress_block_addr) goto sleep; + /* do not suspend small EBs, buggy Micron Chips */ + if (cfi_is_micron_28F00AP30(cfi, chip) && + (chip->in_progress_block_mask == ~(0x8000-1))) + goto sleep; + /* Erase suspend */ map_write(map, CMD(0xB0), chip->in_progress_block_addr); -- GitLab From f69cd2d30a800776f241b3ea16279628fc4dd724 Mon Sep 17 00:00:00 2001 From: Joakim Tjernlund Date: Thu, 1 Mar 2018 14:39:41 +0100 Subject: [PATCH 1285/1635] mtd: cfi: cmdset_0002: Do not allow read/write to suspend erase block. commit 7b70eb14392a7cf505f9b358d06c33b5af73d1e7 upstream. Currently it is possible to read and/or write to suspend EB's. Writing /dev/mtdX or /dev/mtdblockX from several processes may break the flash state machine. Taken from cfi_cmdset_0001 driver. Signed-off-by: Joakim Tjernlund Cc: Reviewed-by: Richard Weinberger Signed-off-by: Boris Brezillon Signed-off-by: Greg Kroah-Hartman --- drivers/mtd/chips/cfi_cmdset_0002.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/mtd/chips/cfi_cmdset_0002.c b/drivers/mtd/chips/cfi_cmdset_0002.c index 56aa6b75213d..d524a64ed754 100644 --- a/drivers/mtd/chips/cfi_cmdset_0002.c +++ b/drivers/mtd/chips/cfi_cmdset_0002.c @@ -816,9 +816,10 @@ static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr (mode == FL_WRITING && (cfip->EraseSuspend & 0x2)))) goto sleep; - /* We could check to see if we're trying to access the sector - * that is currently being erased. However, no user will try - * anything like that so we just wait for the timeout. */ + /* Do not allow suspend iff read/write to EB address */ + if ((adr & chip->in_progress_block_mask) == + chip->in_progress_block_addr) + goto sleep; /* Erase suspend */ /* It's harmless to issue the Erase-Suspend and Erase-Resume @@ -2267,6 +2268,7 @@ static int __xipram do_erase_chip(struct map_info *map, struct flchip *chip) chip->state = FL_ERASING; chip->erase_suspended = 0; chip->in_progress_block_addr = adr; + chip->in_progress_block_mask = ~(map->size - 1); INVALIDATE_CACHE_UDELAY(map, chip, adr, map->size, @@ -2356,6 +2358,7 @@ static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip, chip->state = FL_ERASING; chip->erase_suspended = 0; chip->in_progress_block_addr = adr; + chip->in_progress_block_mask = ~(len - 1); INVALIDATE_CACHE_UDELAY(map, chip, adr, len, -- GitLab From 6840b774dc4d211ac546af5a2e02bb02fad0b162 Mon Sep 17 00:00:00 2001 From: Marc Gonzalez Date: Thu, 5 Apr 2018 14:57:59 +0200 Subject: [PATCH 1286/1635] mtd: rawnand: tango: Fix struct clk memory leak commit 007b4e8b705a4eff184d567c5a8b496622f9e116 upstream. Use devm_clk_get() to let Linux manage struct clk memory. Fixes: 6956e2385a16 ("add tango NAND flash controller support") Cc: stable@vger.kernel.org Reported-by: Xidong Wang Signed-off-by: Marc Gonzalez Reviewed-by: Miquel Raynal Signed-off-by: Boris Brezillon Signed-off-by: Greg Kroah-Hartman --- drivers/mtd/nand/tango_nand.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mtd/nand/tango_nand.c b/drivers/mtd/nand/tango_nand.c index 766906f03943..ce366816a7ef 100644 --- a/drivers/mtd/nand/tango_nand.c +++ b/drivers/mtd/nand/tango_nand.c @@ -654,7 +654,7 @@ static int tango_nand_probe(struct platform_device *pdev) writel_relaxed(MODE_RAW, nfc->pbus_base + PBUS_PAD_MODE); - clk = clk_get(&pdev->dev, NULL); + clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(clk)) return PTR_ERR(clk); -- GitLab From a5f4276787d63f726b751d80b5b51f0c8d4d0384 Mon Sep 17 00:00:00 2001 From: Dmitry Vyukov Date: Wed, 11 Apr 2018 17:22:43 +0200 Subject: [PATCH 1287/1635] kobject: don't use WARN for registration failures commit 3e14c6abbfb5c94506edda9d8e2c145d79375798 upstream. This WARNING proved to be noisy. The function still returns an error and callers should handle it. That's how most of kernel code works. Downgrade the WARNING to pr_err() and leave WARNINGs for kernel bugs. Signed-off-by: Dmitry Vyukov Reported-by: syzbot+209c0f67f99fec8eb14b@syzkaller.appspotmail.com Reported-by: syzbot+7fb6d9525a4528104e05@syzkaller.appspotmail.com Reported-by: syzbot+2e63711063e2d8f9ea27@syzkaller.appspotmail.com Reported-by: syzbot+de73361ee4971b6e6f75@syzkaller.appspotmail.com Cc: stable Signed-off-by: Greg Kroah-Hartman --- lib/kobject.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/lib/kobject.c b/lib/kobject.c index 763d70a18941..34f847252c02 100644 --- a/lib/kobject.c +++ b/lib/kobject.c @@ -234,14 +234,12 @@ static int kobject_add_internal(struct kobject *kobj) /* be noisy on error issues */ if (error == -EEXIST) - WARN(1, "%s failed for %s with " - "-EEXIST, don't try to register things with " - "the same name in the same directory.\n", - __func__, kobject_name(kobj)); + pr_err("%s failed for %s with -EEXIST, don't try to register things with the same name in the same directory.\n", + __func__, kobject_name(kobj)); else - WARN(1, "%s failed for %s (error: %d parent: %s)\n", - __func__, kobject_name(kobj), error, - parent ? kobject_name(parent) : "'none'"); + pr_err("%s failed for %s (error: %d parent: %s)\n", + __func__, kobject_name(kobj), error, + parent ? kobject_name(parent) : "'none'"); } else kobj->state_in_sysfs = 1; -- GitLab From b23b4174275d397281023703ce19ff793e6dfd98 Mon Sep 17 00:00:00 2001 From: Mahesh Rajashekhara Date: Tue, 17 Apr 2018 17:03:12 +0530 Subject: [PATCH 1288/1635] scsi: sd: Defer spinning up drive while SANITIZE is in progress commit 505aa4b6a8834a2300971c5220c380c3271ebde3 upstream. A drive being sanitized will return NOT READY / ASC 0x4 / ASCQ 0x1b ("LOGICAL UNIT NOT READY. SANITIZE IN PROGRESS"). Prevent spinning up the drive until this condition clears. [mkp: tweaked commit message] Signed-off-by: Mahesh Rajashekhara Cc: Signed-off-by: Martin K. Petersen Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/sd.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 72db0f7d221a..2f9912de2212 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -2132,6 +2132,8 @@ sd_spinup_disk(struct scsi_disk *sdkp) break; /* standby */ if (sshdr.asc == 4 && sshdr.ascq == 0xc) break; /* unavailable */ + if (sshdr.asc == 4 && sshdr.ascq == 0x1b) + break; /* sanitize in progress */ /* * Issue command to spin up drive when not ready */ -- GitLab From be10336a907253a6066d802c11b6edaf7cf397f8 Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Tue, 17 Apr 2018 17:08:52 -0600 Subject: [PATCH 1289/1635] bfq-iosched: ensure to clear bic/bfqq pointers when preparing request commit 72961c4e6082be79825265d9193272b8a1634dec upstream. Even if we don't have an IO context attached to a request, we still need to clear the priv[0..1] pointers, as they could be pointing to previously used bic/bfqq structures. If we don't do so, we'll either corrupt memory on dispatching a request, or cause an imbalance in counters. Inspired by a fix from Kees. Reported-by: Oleksandr Natalenko Reported-by: Kees Cook Cc: stable@vger.kernel.org Fixes: aee69d78dec0 ("block, bfq: introduce the BFQ-v0 I/O scheduler as an extra scheduler") Signed-off-by: Jens Axboe Signed-off-by: Greg Kroah-Hartman --- block/bfq-iosched.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/block/bfq-iosched.c b/block/bfq-iosched.c index 0f860cf0d56d..56c9cd01fd1d 100644 --- a/block/bfq-iosched.c +++ b/block/bfq-iosched.c @@ -4447,8 +4447,16 @@ static void bfq_prepare_request(struct request *rq, struct bio *bio) bool new_queue = false; bool bfqq_already_existing = false, split = false; - if (!rq->elv.icq) + /* + * Even if we don't have an icq attached, we should still clear + * the scheduler pointers, as they might point to previously + * allocated bic/bfqq structs. + */ + if (!rq->elv.icq) { + rq->elv.priv[0] = rq->elv.priv[1] = NULL; return; + } + bic = icq_to_bic(rq->elv.icq); spin_lock_irq(&bfqd->lock); -- GitLab From bddabeb71f3fc2577d7576251507f36320cecdb1 Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Fri, 20 Apr 2018 10:24:04 +0200 Subject: [PATCH 1290/1635] vfio: ccw: process ssch with interrupts disabled commit 3368e547c52b96586f0edf9657ca12b94d8e61a7 upstream. When we call ssch, an interrupt might already be pending once we return from the START SUBCHANNEL instruction. Therefore we need to make sure interrupts are disabled while holding the subchannel lock until after we're done with our processing. Cc: stable@vger.kernel.org #v4.12+ Reviewed-by: Dong Jia Shi Acked-by: Halil Pasic Acked-by: Pierre Morel Signed-off-by: Cornelia Huck Signed-off-by: Martin Schwidefsky Signed-off-by: Greg Kroah-Hartman --- drivers/s390/cio/vfio_ccw_fsm.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/drivers/s390/cio/vfio_ccw_fsm.c b/drivers/s390/cio/vfio_ccw_fsm.c index c30420c517b1..e96b85579f21 100644 --- a/drivers/s390/cio/vfio_ccw_fsm.c +++ b/drivers/s390/cio/vfio_ccw_fsm.c @@ -20,12 +20,12 @@ static int fsm_io_helper(struct vfio_ccw_private *private) int ccode; __u8 lpm; unsigned long flags; + int ret; sch = private->sch; spin_lock_irqsave(sch->lock, flags); private->state = VFIO_CCW_STATE_BUSY; - spin_unlock_irqrestore(sch->lock, flags); orb = cp_get_orb(&private->cp, (u32)(addr_t)sch, sch->lpm); @@ -38,10 +38,12 @@ static int fsm_io_helper(struct vfio_ccw_private *private) * Initialize device status information */ sch->schib.scsw.cmd.actl |= SCSW_ACTL_START_PEND; - return 0; + ret = 0; + break; case 1: /* Status pending */ case 2: /* Busy */ - return -EBUSY; + ret = -EBUSY; + break; case 3: /* Device/path not operational */ { lpm = orb->cmd.lpm; @@ -51,13 +53,16 @@ static int fsm_io_helper(struct vfio_ccw_private *private) sch->lpm = 0; if (cio_update_schib(sch)) - return -ENODEV; - - return sch->lpm ? -EACCES : -ENODEV; + ret = -ENODEV; + else + ret = sch->lpm ? -EACCES : -ENODEV; + break; } default: - return ccode; + ret = ccode; } + spin_unlock_irqrestore(sch->lock, flags); + return ret; } static void fsm_notoper(struct vfio_ccw_private *private, -- GitLab From fd0485e2cc7b5f69889dca223b2c9f7cba6e91f4 Mon Sep 17 00:00:00 2001 From: Martijn Coenen Date: Wed, 28 Mar 2018 11:14:50 +0200 Subject: [PATCH 1291/1635] ANDROID: binder: prevent transactions into own process. commit 7aa135fcf26377f92dc0680a57566b4c7f3e281b upstream. This can't happen with normal nodes (because you can't get a ref to a node you own), but it could happen with the context manager; to make the behavior consistent with regular nodes, reject transactions into the context manager by the process owning it. Reported-by: syzbot+09e05aba06723a94d43d@syzkaller.appspotmail.com Signed-off-by: Martijn Coenen Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/android/binder.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/android/binder.c b/drivers/android/binder.c index b7efdc8badee..a86c27948fca 100644 --- a/drivers/android/binder.c +++ b/drivers/android/binder.c @@ -2785,6 +2785,14 @@ static void binder_transaction(struct binder_proc *proc, else return_error = BR_DEAD_REPLY; mutex_unlock(&context->context_mgr_node_lock); + if (target_node && target_proc == proc) { + binder_user_error("%d:%d got transaction to context manager from process owning it\n", + proc->pid, thread->pid); + return_error = BR_FAILED_REPLY; + return_error_param = -EINVAL; + return_error_line = __LINE__; + goto err_invalid_target_handle; + } } if (!target_node) { /* -- GitLab From e90b89088a109f1c49befd8a7f9f7d970d093e62 Mon Sep 17 00:00:00 2001 From: Victor Gu Date: Fri, 6 Apr 2018 16:55:31 +0200 Subject: [PATCH 1292/1635] PCI: aardvark: Fix logic in advk_pcie_{rd,wr}_conf() commit 660661afcd40ed7f515ef3369721ed58e80c0fc5 upstream. The PCI configuration space read/write functions were special casing the situation where PCI_SLOT(devfn) != 0, and returned PCIBIOS_DEVICE_NOT_FOUND in this case. However, while this is what is intended for the root bus, it is not intended for the child busses, as it prevents discovering devices with PCI_SLOT(x) != 0. Therefore, we return PCIBIOS_DEVICE_NOT_FOUND only if we're on the root bus. Fixes: 8c39d710363c1 ("PCI: aardvark: Add Aardvark PCI host controller driver") Cc: Signed-off-by: Victor Gu Reviewed-by: Wilson Ding Reviewed-by: Nadav Haklai [Thomas: tweak commit log.] Signed-off-by: Thomas Petazzoni Signed-off-by: Lorenzo Pieralisi Signed-off-by: Greg Kroah-Hartman --- drivers/pci/host/pci-aardvark.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/pci/host/pci-aardvark.c b/drivers/pci/host/pci-aardvark.c index 26ed0c08f209..3e7d1e22d33e 100644 --- a/drivers/pci/host/pci-aardvark.c +++ b/drivers/pci/host/pci-aardvark.c @@ -440,7 +440,7 @@ static int advk_pcie_rd_conf(struct pci_bus *bus, u32 devfn, u32 reg; int ret; - if (PCI_SLOT(devfn) != 0) { + if ((bus->number == pcie->root_bus_nr) && PCI_SLOT(devfn) != 0) { *val = 0xffffffff; return PCIBIOS_DEVICE_NOT_FOUND; } @@ -494,7 +494,7 @@ static int advk_pcie_wr_conf(struct pci_bus *bus, u32 devfn, int offset; int ret; - if (PCI_SLOT(devfn) != 0) + if ((bus->number == pcie->root_bus_nr) && PCI_SLOT(devfn) != 0) return PCIBIOS_DEVICE_NOT_FOUND; if (where % size) -- GitLab From f0ae21a86eb52970966d73094a402338e1fc85ac Mon Sep 17 00:00:00 2001 From: Victor Gu Date: Fri, 6 Apr 2018 16:55:32 +0200 Subject: [PATCH 1293/1635] PCI: aardvark: Set PIO_ADDR_LS correctly in advk_pcie_rd_conf() commit 4fa3999ee672c54a5498ce98e20fe3fdf9c1cbb4 upstream. When setting the PIO_ADDR_LS register during a configuration read, we were properly passing the device number, function number and register number, but not the bus number, causing issues when reading the configuration of PCIe devices. Fixes: 8c39d710363c1 ("PCI: aardvark: Add Aardvark PCI host controller driver") Cc: Signed-off-by: Victor Gu Reviewed-by: Wilson Ding Reviewed-by: Nadav Haklai [Thomas: tweak commit log.] Signed-off-by: Thomas Petazzoni Signed-off-by: Lorenzo Pieralisi Signed-off-by: Greg Kroah-Hartman --- drivers/pci/host/pci-aardvark.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/pci/host/pci-aardvark.c b/drivers/pci/host/pci-aardvark.c index 3e7d1e22d33e..08d86f12c644 100644 --- a/drivers/pci/host/pci-aardvark.c +++ b/drivers/pci/host/pci-aardvark.c @@ -175,8 +175,6 @@ #define PCIE_CONFIG_WR_TYPE0 0xa #define PCIE_CONFIG_WR_TYPE1 0xb -/* PCI_BDF shifts 8bit, so we need extra 4bit shift */ -#define PCIE_BDF(dev) (dev << 4) #define PCIE_CONF_BUS(bus) (((bus) & 0xff) << 20) #define PCIE_CONF_DEV(dev) (((dev) & 0x1f) << 15) #define PCIE_CONF_FUNC(fun) (((fun) & 0x7) << 12) @@ -459,7 +457,7 @@ static int advk_pcie_rd_conf(struct pci_bus *bus, u32 devfn, advk_writel(pcie, reg, PIO_CTRL); /* Program the address registers */ - reg = PCIE_BDF(devfn) | PCIE_CONF_REG(where); + reg = PCIE_CONF_ADDR(bus->number, devfn, where); advk_writel(pcie, reg, PIO_ADDR_LS); advk_writel(pcie, 0, PIO_ADDR_MS); -- GitLab From 6b3751e249ff93f065ae90bb9b5e66cc42da9fcc Mon Sep 17 00:00:00 2001 From: Victor Gu Date: Fri, 6 Apr 2018 16:55:33 +0200 Subject: [PATCH 1294/1635] PCI: aardvark: Use ISR1 instead of ISR0 interrupt in legacy irq mode commit 3430f924a62905891c8fa9a3b97ea52007795bc3 upstream. The Aardvark has two interrupts sets: - first set is bit[23:16] of PCIe ISR 0 register(RD0074840h) - second set is bit[11:8] of PCIe ISR 1 register(RD0074848h) Only one set should be used, while another set should be masked. The second set, ISR1, is more advanced, the Legacy INT_X status bit is asserted once Assert_INTX message is received, and de-asserted after Deassert_INTX message is received which matches what the driver is currently doing in the ->irq_mask() and ->irq_unmask() functions. The ISR0 requires additional work to deassert the interrupt, which the driver does not currently implement, therefore it needs fixing. Update the driver to use ISR1 register set, fixing current implementation. Fixes: 8c39d710363c1 ("PCI: aardvark: Add Aardvark PCI host controller driver") Link: https://bugzilla.kernel.org/show_bug.cgi?id=196339 Signed-off-by: Victor Gu [Thomas: tweak commit log.] Signed-off-by: Thomas Petazzoni [lorenzo.pieralisi@arm.com: updated the commit log] Signed-off-by: Lorenzo Pieralisi Reviewed-by: Evan Wang Reviewed-by: Nadav Haklai Cc: Signed-off-by: Greg Kroah-Hartman --- drivers/pci/host/pci-aardvark.c | 41 +++++++++++++++++++-------------- 1 file changed, 24 insertions(+), 17 deletions(-) diff --git a/drivers/pci/host/pci-aardvark.c b/drivers/pci/host/pci-aardvark.c index 08d86f12c644..6bdc598e9980 100644 --- a/drivers/pci/host/pci-aardvark.c +++ b/drivers/pci/host/pci-aardvark.c @@ -103,7 +103,8 @@ #define PCIE_ISR1_MASK_REG (CONTROL_BASE_ADDR + 0x4C) #define PCIE_ISR1_POWER_STATE_CHANGE BIT(4) #define PCIE_ISR1_FLUSH BIT(5) -#define PCIE_ISR1_ALL_MASK GENMASK(5, 4) +#define PCIE_ISR1_INTX_ASSERT(val) BIT(8 + (val)) +#define PCIE_ISR1_ALL_MASK GENMASK(11, 4) #define PCIE_MSI_ADDR_LOW_REG (CONTROL_BASE_ADDR + 0x50) #define PCIE_MSI_ADDR_HIGH_REG (CONTROL_BASE_ADDR + 0x54) #define PCIE_MSI_STATUS_REG (CONTROL_BASE_ADDR + 0x58) @@ -610,9 +611,9 @@ static void advk_pcie_irq_mask(struct irq_data *d) irq_hw_number_t hwirq = irqd_to_hwirq(d); u32 mask; - mask = advk_readl(pcie, PCIE_ISR0_MASK_REG); - mask |= PCIE_ISR0_INTX_ASSERT(hwirq); - advk_writel(pcie, mask, PCIE_ISR0_MASK_REG); + mask = advk_readl(pcie, PCIE_ISR1_MASK_REG); + mask |= PCIE_ISR1_INTX_ASSERT(hwirq); + advk_writel(pcie, mask, PCIE_ISR1_MASK_REG); } static void advk_pcie_irq_unmask(struct irq_data *d) @@ -621,9 +622,9 @@ static void advk_pcie_irq_unmask(struct irq_data *d) irq_hw_number_t hwirq = irqd_to_hwirq(d); u32 mask; - mask = advk_readl(pcie, PCIE_ISR0_MASK_REG); - mask &= ~PCIE_ISR0_INTX_ASSERT(hwirq); - advk_writel(pcie, mask, PCIE_ISR0_MASK_REG); + mask = advk_readl(pcie, PCIE_ISR1_MASK_REG); + mask &= ~PCIE_ISR1_INTX_ASSERT(hwirq); + advk_writel(pcie, mask, PCIE_ISR1_MASK_REG); } static int advk_pcie_irq_map(struct irq_domain *h, @@ -766,29 +767,35 @@ static void advk_pcie_handle_msi(struct advk_pcie *pcie) static void advk_pcie_handle_int(struct advk_pcie *pcie) { - u32 val, mask, status; + u32 isr0_val, isr0_mask, isr0_status; + u32 isr1_val, isr1_mask, isr1_status; int i, virq; - val = advk_readl(pcie, PCIE_ISR0_REG); - mask = advk_readl(pcie, PCIE_ISR0_MASK_REG); - status = val & ((~mask) & PCIE_ISR0_ALL_MASK); + isr0_val = advk_readl(pcie, PCIE_ISR0_REG); + isr0_mask = advk_readl(pcie, PCIE_ISR0_MASK_REG); + isr0_status = isr0_val & ((~isr0_mask) & PCIE_ISR0_ALL_MASK); - if (!status) { - advk_writel(pcie, val, PCIE_ISR0_REG); + isr1_val = advk_readl(pcie, PCIE_ISR1_REG); + isr1_mask = advk_readl(pcie, PCIE_ISR1_MASK_REG); + isr1_status = isr1_val & ((~isr1_mask) & PCIE_ISR1_ALL_MASK); + + if (!isr0_status && !isr1_status) { + advk_writel(pcie, isr0_val, PCIE_ISR0_REG); + advk_writel(pcie, isr1_val, PCIE_ISR1_REG); return; } /* Process MSI interrupts */ - if (status & PCIE_ISR0_MSI_INT_PENDING) + if (isr0_status & PCIE_ISR0_MSI_INT_PENDING) advk_pcie_handle_msi(pcie); /* Process legacy interrupts */ for (i = 0; i < PCI_NUM_INTX; i++) { - if (!(status & PCIE_ISR0_INTX_ASSERT(i))) + if (!(isr1_status & PCIE_ISR1_INTX_ASSERT(i))) continue; - advk_writel(pcie, PCIE_ISR0_INTX_ASSERT(i), - PCIE_ISR0_REG); + advk_writel(pcie, PCIE_ISR1_INTX_ASSERT(i), + PCIE_ISR1_REG); virq = irq_find_mapping(pcie->irq_domain, i); generic_handle_irq(virq); -- GitLab From 1a6e0a900bced2df5f6e52ee475d13e5d5e692b3 Mon Sep 17 00:00:00 2001 From: Evan Wang Date: Fri, 6 Apr 2018 16:55:34 +0200 Subject: [PATCH 1295/1635] PCI: aardvark: Fix PCIe Max Read Request Size setting commit fc31c4e347c9dad50544d01d5ee98b22c7df88bb upstream. There is an obvious typo issue in the definition of the PCIe maximum read request size: a bit shift is directly used as a value, while it should be used to shift the correct value. Fixes: 8c39d710363c1 ("PCI: aardvark: Add Aardvark PCI host controller driver") Cc: Signed-off-by: Evan Wang Reviewed-by: Victor Gu Reviewed-by: Nadav Haklai [Thomas: tweak commit log.] Signed-off-by: Thomas Petazzoni Signed-off-by: Lorenzo Pieralisi Signed-off-by: Greg Kroah-Hartman --- drivers/pci/host/pci-aardvark.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/pci/host/pci-aardvark.c b/drivers/pci/host/pci-aardvark.c index 6bdc598e9980..9bfc22b5da4b 100644 --- a/drivers/pci/host/pci-aardvark.c +++ b/drivers/pci/host/pci-aardvark.c @@ -32,6 +32,7 @@ #define PCIE_CORE_DEV_CTRL_STATS_MAX_PAYLOAD_SZ_SHIFT 5 #define PCIE_CORE_DEV_CTRL_STATS_SNOOP_DISABLE (0 << 11) #define PCIE_CORE_DEV_CTRL_STATS_MAX_RD_REQ_SIZE_SHIFT 12 +#define PCIE_CORE_DEV_CTRL_STATS_MAX_RD_REQ_SZ 0x2 #define PCIE_CORE_LINK_CTRL_STAT_REG 0xd0 #define PCIE_CORE_LINK_L0S_ENTRY BIT(0) #define PCIE_CORE_LINK_TRAINING BIT(5) @@ -298,7 +299,8 @@ static void advk_pcie_setup_hw(struct advk_pcie *pcie) reg = PCIE_CORE_DEV_CTRL_STATS_RELAX_ORDER_DISABLE | (7 << PCIE_CORE_DEV_CTRL_STATS_MAX_PAYLOAD_SZ_SHIFT) | PCIE_CORE_DEV_CTRL_STATS_SNOOP_DISABLE | - PCIE_CORE_DEV_CTRL_STATS_MAX_RD_REQ_SIZE_SHIFT; + (PCIE_CORE_DEV_CTRL_STATS_MAX_RD_REQ_SZ << + PCIE_CORE_DEV_CTRL_STATS_MAX_RD_REQ_SIZE_SHIFT); advk_writel(pcie, reg, PCIE_CORE_DEV_CTRL_STATS_REG); /* Program PCIe Control 2 to disable strict ordering */ -- GitLab From bcd73c772ec1991094de7064b035770e491e293a Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 10 Apr 2018 15:21:43 +0200 Subject: [PATCH 1296/1635] ARM: amba: Make driver_override output consistent with other buses commit 5f53624662eaac89598641cee6cd54fc192572d9 upstream. For AMBA devices with unconfigured driver override, the "driver_override" sysfs virtual file is empty, while it contains "(null)" for platform and PCI devices. Make AMBA consistent with other buses by dropping the test for a NULL pointer. Note that contrary to popular belief, sprintf() handles NULL pointers fine; they are printed as "(null)". Signed-off-by: Geert Uytterhoeven Cc: stable Reviewed-by: Todd Kjos Signed-off-by: Greg Kroah-Hartman --- drivers/amba/bus.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/amba/bus.c b/drivers/amba/bus.c index e0f74ddc22b7..f349dae94212 100644 --- a/drivers/amba/bus.c +++ b/drivers/amba/bus.c @@ -70,9 +70,6 @@ static ssize_t driver_override_show(struct device *_dev, { struct amba_device *dev = to_amba_device(_dev); - if (!dev->driver_override) - return 0; - return sprintf(buf, "%s\n", dev->driver_override); } -- GitLab From 23abff7b984ff46b78b9964f9cdba42036b4149a Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 10 Apr 2018 15:21:44 +0200 Subject: [PATCH 1297/1635] ARM: amba: Fix race condition with driver_override commit 6a7228d90d42bcacfe38786756ba62762b91c20a upstream. The driver_override implementation is susceptible to a race condition when different threads are reading vs storing a different driver override. Add locking to avoid this race condition. Cfr. commits 6265539776a0810b ("driver core: platform: fix race condition with driver_override") and 9561475db680f714 ("PCI: Fix race condition with driver_override"). Fixes: 3cf385713460eb2b ("ARM: 8256/1: driver coamba: add device binding path 'driver_override'") Signed-off-by: Geert Uytterhoeven Reviewed-by: Todd Kjos Cc: stable Signed-off-by: Greg Kroah-Hartman Signed-off-by: Greg Kroah-Hartman --- drivers/amba/bus.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/drivers/amba/bus.c b/drivers/amba/bus.c index f349dae94212..8c7d0c64ebe0 100644 --- a/drivers/amba/bus.c +++ b/drivers/amba/bus.c @@ -69,8 +69,12 @@ static ssize_t driver_override_show(struct device *_dev, struct device_attribute *attr, char *buf) { struct amba_device *dev = to_amba_device(_dev); + ssize_t len; - return sprintf(buf, "%s\n", dev->driver_override); + device_lock(_dev); + len = sprintf(buf, "%s\n", dev->driver_override); + device_unlock(_dev); + return len; } static ssize_t driver_override_store(struct device *_dev, @@ -78,7 +82,7 @@ static ssize_t driver_override_store(struct device *_dev, const char *buf, size_t count) { struct amba_device *dev = to_amba_device(_dev); - char *driver_override, *old = dev->driver_override, *cp; + char *driver_override, *old, *cp; if (count > PATH_MAX) return -EINVAL; @@ -91,12 +95,15 @@ static ssize_t driver_override_store(struct device *_dev, if (cp) *cp = '\0'; + device_lock(_dev); + old = dev->driver_override; if (strlen(driver_override)) { dev->driver_override = driver_override; } else { kfree(driver_override); dev->driver_override = NULL; } + device_unlock(_dev); kfree(old); -- GitLab From f671ee8de31a3c2702250e64e5f18ebceb21f1e6 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 10 Apr 2018 15:21:45 +0200 Subject: [PATCH 1298/1635] ARM: amba: Don't read past the end of sysfs "driver_override" buffer commit d2ffed5185df9d8d9ccd150e4340e3b6f96a8381 upstream. When printing the driver_override parameter when it is 4095 and 4094 bytes long, the printing code would access invalid memory because we need count + 1 bytes for printing. Cfr. commits 4efe874aace57dba ("PCI: Don't read past the end of sysfs "driver_override" buffer") and bf563b01c2895a4b ("driver core: platform: Don't read past the end of "driver_override" buffer"). Fixes: 3cf385713460eb2b ("ARM: 8256/1: driver coamba: add device binding path 'driver_override'") Signed-off-by: Geert Uytterhoeven Reviewed-by: Todd Kjos Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/amba/bus.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/amba/bus.c b/drivers/amba/bus.c index 8c7d0c64ebe0..8a99fbe5759f 100644 --- a/drivers/amba/bus.c +++ b/drivers/amba/bus.c @@ -84,7 +84,8 @@ static ssize_t driver_override_store(struct device *_dev, struct amba_device *dev = to_amba_device(_dev); char *driver_override, *old, *cp; - if (count > PATH_MAX) + /* We need to keep extra room for a newline */ + if (count >= (PAGE_SIZE - 1)) return -EINVAL; driver_override = kstrndup(buf, count, GFP_KERNEL); -- GitLab From 0ddb53a67cbdd8eda6bd4e72870b7de0499e2e7b Mon Sep 17 00:00:00 2001 From: Thor Thayer Date: Mon, 26 Mar 2018 14:50:00 -0500 Subject: [PATCH 1299/1635] ARM: socfpga_defconfig: Remove QSPI Sector 4K size force commit 6e8fe39989720b87439fee7817a5ca362b16d931 upstream. Remove QSPI Sector 4K size force which is causing QSPI boot problems with the JFFS2 root filesystem. Fixes the following error: "Magic bitmask 0x1985 not found at ..." Cc: stable@vger.kernel.org Signed-off-by: Thor Thayer Signed-off-by: Dinh Nguyen Signed-off-by: Greg Kroah-Hartman --- arch/arm/configs/socfpga_defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/configs/socfpga_defconfig b/arch/arm/configs/socfpga_defconfig index 2620ce790db0..371fca4e1ab7 100644 --- a/arch/arm/configs/socfpga_defconfig +++ b/arch/arm/configs/socfpga_defconfig @@ -57,6 +57,7 @@ CONFIG_MTD_M25P80=y CONFIG_MTD_NAND=y CONFIG_MTD_NAND_DENALI_DT=y CONFIG_MTD_SPI_NOR=y +# CONFIG_MTD_SPI_NOR_USE_4K_SECTORS is not set CONFIG_SPI_CADENCE_QUADSPI=y CONFIG_OF_OVERLAY=y CONFIG_OF_CONFIGFS=y -- GitLab From 5a5ea34017993e6714dec7c741d1d9e263ec3638 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Wed, 4 Apr 2018 14:48:24 +0100 Subject: [PATCH 1300/1635] KVM: arm/arm64: Close VMID generation race commit f0cf47d939d0b4b4f660c5aaa4276fa3488f3391 upstream. Before entering the guest, we check whether our VMID is still part of the current generation. In order to avoid taking a lock, we start with checking that the generation is still current, and only if not current do we take the lock, recheck, and update the generation and VMID. This leaves open a small race: A vcpu can bump up the global generation number as well as the VM's, but has not updated the VMID itself yet. At that point another vcpu from the same VM comes in, checks the generation (and finds it not needing anything), and jumps into the guest. At this point, we end-up with two vcpus belonging to the same VM running with two different VMIDs. Eventually, the VMID used by the second vcpu will get reassigned, and things will really go wrong... A simple solution would be to drop this initial check, and always take the lock. This is likely to cause performance issues. A middle ground is to convert the spinlock to a rwlock, and only take the read lock on the fast path. If the check fails at that point, drop it and acquire the write lock, rechecking the condition. This ensures that the above scenario doesn't occur. Cc: stable@vger.kernel.org Reported-by: Mark Rutland Tested-by: Shannon Zhao Signed-off-by: Marc Zyngier Signed-off-by: Greg Kroah-Hartman --- virt/kvm/arm/arm.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/virt/kvm/arm/arm.c b/virt/kvm/arm/arm.c index 1366462a3ab2..9bee849db682 100644 --- a/virt/kvm/arm/arm.c +++ b/virt/kvm/arm/arm.c @@ -61,7 +61,7 @@ static DEFINE_PER_CPU(struct kvm_vcpu *, kvm_arm_running_vcpu); static atomic64_t kvm_vmid_gen = ATOMIC64_INIT(1); static u32 kvm_next_vmid; static unsigned int kvm_vmid_bits __read_mostly; -static DEFINE_SPINLOCK(kvm_vmid_lock); +static DEFINE_RWLOCK(kvm_vmid_lock); static bool vgic_present; @@ -462,11 +462,16 @@ static void update_vttbr(struct kvm *kvm) { phys_addr_t pgd_phys; u64 vmid; + bool new_gen; - if (!need_new_vmid_gen(kvm)) + read_lock(&kvm_vmid_lock); + new_gen = need_new_vmid_gen(kvm); + read_unlock(&kvm_vmid_lock); + + if (!new_gen) return; - spin_lock(&kvm_vmid_lock); + write_lock(&kvm_vmid_lock); /* * We need to re-check the vmid_gen here to ensure that if another vcpu @@ -474,7 +479,7 @@ static void update_vttbr(struct kvm *kvm) * use the same vmid. */ if (!need_new_vmid_gen(kvm)) { - spin_unlock(&kvm_vmid_lock); + write_unlock(&kvm_vmid_lock); return; } @@ -508,7 +513,7 @@ static void update_vttbr(struct kvm *kvm) vmid = ((u64)(kvm->arch.vmid) << VTTBR_VMID_SHIFT) & VTTBR_VMID_MASK(kvm_vmid_bits); kvm->arch.vttbr = pgd_phys | vmid; - spin_unlock(&kvm_vmid_lock); + write_unlock(&kvm_vmid_lock); } static int kvm_vcpu_first_run_init(struct kvm_vcpu *vcpu) -- GitLab From f2acc8dc0644194efba8474d3a4dc13752430894 Mon Sep 17 00:00:00 2001 From: Balbir Singh Date: Fri, 6 Apr 2018 15:24:23 +1000 Subject: [PATCH 1301/1635] powerpc/mm: Flush cache on memory hot(un)plug commit fb5924fddf9ee31db04da7ad4e8c3434a387101b upstream. This patch adds support for flushing potentially dirty cache lines when memory is hot-plugged/hot-un-plugged. The support is currently limited to 64 bit systems. The bug was exposed when mappings for a device were actually hot-unplugged and plugged in back later. A similar issue was observed during the development of memtrace, but memtrace does it's own flushing of region via a custom routine. These patches do a flush both on hotplug/unplug to clear any stale data in the cache w.r.t mappings, there is a small race window where a clean cache line may be created again just prior to tearing down the mapping. The patches were tested by disabling the flush routines in memtrace and doing I/O on the trace file. The system immediately checkstops (quite reliablly if prior to the hot-unplug of the memtrace region, we memset the regions we are about to hot unplug). After these patches no custom flushing is needed in the memtrace code. Fixes: 9d5171a8f248 ("powerpc/powernv: Enable removal of memory for in memory tracing") Cc: stable@vger.kernel.org # v4.14+ Signed-off-by: Balbir Singh Acked-by: Reza Arbab Reviewed-by: Rashmica Gupta Signed-off-by: Michael Ellerman Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/mm/mem.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/powerpc/mm/mem.c b/arch/powerpc/mm/mem.c index 4362b86ef84c..9c2f83331e5b 100644 --- a/arch/powerpc/mm/mem.c +++ b/arch/powerpc/mm/mem.c @@ -143,6 +143,7 @@ int arch_add_memory(int nid, u64 start, u64 size, bool want_memblock) start, start + size, rc); return -EFAULT; } + flush_inval_dcache_range(start, start + size); return __add_pages(nid, start_pfn, nr_pages, want_memblock); } @@ -171,6 +172,7 @@ int arch_remove_memory(u64 start, u64 size) /* Remove htab bolted mappings for this section of memory */ start = (unsigned long)__va(start); + flush_inval_dcache_range(start, start + size); ret = remove_section_mapping(start, start + size); /* Ensure all vmalloc mappings are flushed in case they also -- GitLab From a32a944a60c854ab44cf873dfc1954828f50b046 Mon Sep 17 00:00:00 2001 From: Alistair Popple Date: Tue, 17 Apr 2018 19:11:28 +1000 Subject: [PATCH 1302/1635] powerpc/powernv/npu: Do a PID GPU TLB flush when invalidating a large address range commit d0cf9b561ca97d5245bb9e0c4774b7fadd897d67 upstream. The NPU has a limited number of address translation shootdown (ATSD) registers and the GPU has limited bandwidth to process ATSDs. This can result in contention of ATSD registers leading to soft lockups on some threads, particularly when invalidating a large address range in pnv_npu2_mn_invalidate_range(). At some threshold it becomes more efficient to flush the entire GPU TLB for the given MM context (PID) than individually flushing each address in the range. This patch will result in ranges greater than 2MB being converted from 32+ ATSDs into a single ATSD which will flush the TLB for the given PID on each GPU. Fixes: 1ab66d1fbada ("powerpc/powernv: Introduce address translation services for Nvlink2") Cc: stable@vger.kernel.org # v4.12+ Signed-off-by: Alistair Popple Acked-by: Balbir Singh Tested-by: Balbir Singh Signed-off-by: Michael Ellerman Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/platforms/powernv/npu-dma.c | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/arch/powerpc/platforms/powernv/npu-dma.c b/arch/powerpc/platforms/powernv/npu-dma.c index 2cb6cbea4b3b..4043109f4051 100644 --- a/arch/powerpc/platforms/powernv/npu-dma.c +++ b/arch/powerpc/platforms/powernv/npu-dma.c @@ -33,6 +33,13 @@ #define npu_to_phb(x) container_of(x, struct pnv_phb, npu) +/* + * When an address shootdown range exceeds this threshold we invalidate the + * entire TLB on the GPU for the given PID rather than each specific address in + * the range. + */ +#define ATSD_THRESHOLD (2*1024*1024) + /* * Other types of TCE cache invalidation are not functional in the * hardware. @@ -621,11 +628,19 @@ static void pnv_npu2_mn_invalidate_range(struct mmu_notifier *mn, struct npu_context *npu_context = mn_to_npu_context(mn); unsigned long address; - for (address = start; address < end; address += PAGE_SIZE) - mmio_invalidate(npu_context, 1, address, false); + if (end - start > ATSD_THRESHOLD) { + /* + * Just invalidate the entire PID if the address range is too + * large. + */ + mmio_invalidate(npu_context, 0, 0, true); + } else { + for (address = start; address < end; address += PAGE_SIZE) + mmio_invalidate(npu_context, 1, address, false); - /* Do the flush only on the final addess == end */ - mmio_invalidate(npu_context, 1, address, true); + /* Do the flush only on the final addess == end */ + mmio_invalidate(npu_context, 1, address, true); + } } static const struct mmu_notifier_ops nv_nmmu_notifier_ops = { -- GitLab From 674d38ea185006d46a4022920aed29525e137a7e Mon Sep 17 00:00:00 2001 From: Stephan Mueller Date: Thu, 12 Apr 2018 08:40:55 +0200 Subject: [PATCH 1303/1635] crypto: drbg - set freed buffers to NULL commit eea0d3ea7546961f69f55b26714ac8fd71c7c020 upstream. During freeing of the internal buffers used by the DRBG, set the pointer to NULL. It is possible that the context with the freed buffers is reused. In case of an error during initialization where the pointers do not yet point to allocated memory, the NULL value prevents a double free. Cc: stable@vger.kernel.org Fixes: 3cfc3b9721123 ("crypto: drbg - use aligned buffers") Signed-off-by: Stephan Mueller Reported-by: syzbot+75397ee3df5c70164154@syzkaller.appspotmail.com Signed-off-by: Herbert Xu Signed-off-by: Greg Kroah-Hartman --- crypto/drbg.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/crypto/drbg.c b/crypto/drbg.c index 70018397e59a..6c3221313753 100644 --- a/crypto/drbg.c +++ b/crypto/drbg.c @@ -1134,8 +1134,10 @@ static inline void drbg_dealloc_state(struct drbg_state *drbg) if (!drbg) return; kzfree(drbg->Vbuf); + drbg->Vbuf = NULL; drbg->V = NULL; kzfree(drbg->Cbuf); + drbg->Cbuf = NULL; drbg->C = NULL; kzfree(drbg->scratchpadbuf); drbg->scratchpadbuf = NULL; -- GitLab From b02bbcce8ea3594b798ae57a7bb5e5dcf23f5e61 Mon Sep 17 00:00:00 2001 From: Nicolin Chen Date: Sun, 8 Apr 2018 16:57:35 -0700 Subject: [PATCH 1304/1635] ASoC: fsl_esai: Fix divisor calculation failure at lower ratio commit c656941df9bc80f7ec65b92ca73c42f8b0b62628 upstream. When the desired ratio is less than 256, the savesub (tolerance) in the calculation would become 0. This will then fail the loop- search immediately without reporting any errors. But if the ratio is smaller enough, there is no need to calculate the tolerance because PM divisor alone is enough to get the ratio. So a simple fix could be just to set PM directly instead of going into the loop-search. Reported-by: Marek Vasut Signed-off-by: Nicolin Chen Tested-by: Marek Vasut Reviewed-by: Fabio Estevam Signed-off-by: Mark Brown Cc: stable@vger.kernel.org Signed-off-by: Greg Kroah-Hartman --- sound/soc/fsl/fsl_esai.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/sound/soc/fsl/fsl_esai.c b/sound/soc/fsl/fsl_esai.c index cef79a1a620b..81268760b7a9 100644 --- a/sound/soc/fsl/fsl_esai.c +++ b/sound/soc/fsl/fsl_esai.c @@ -144,6 +144,13 @@ static int fsl_esai_divisor_cal(struct snd_soc_dai *dai, bool tx, u32 ratio, psr = ratio <= 256 * maxfp ? ESAI_xCCR_xPSR_BYPASS : ESAI_xCCR_xPSR_DIV8; + /* Do not loop-search if PM (1 ~ 256) alone can serve the ratio */ + if (ratio <= 256) { + pm = ratio; + fp = 1; + goto out; + } + /* Set the max fluctuation -- 0.1% of the max devisor */ savesub = (psr ? 1 : 8) * 256 * maxfp / 1000; -- GitLab From 76f7b52b5bf0b03dc1af1df3ecceb5384a4046ca Mon Sep 17 00:00:00 2001 From: Ilya Dryomov Date: Mon, 23 Apr 2018 15:25:10 +0200 Subject: [PATCH 1305/1635] libceph: un-backoff on tick when we have a authenticated session commit facb9f6eba3df4e8027301cc0e514dc582a1b366 upstream. This means that if we do some backoff, then authenticate, and are healthy for an extended period of time, a subsequent failure won't leave us starting our hunting sequence with a large backoff. Mirrors ceph.git commit d466bc6e66abba9b464b0b69687cf45c9dccf383. Cc: stable@vger.kernel.org # 4.7+ Signed-off-by: Ilya Dryomov Reviewed-by: Jason Dillaman Signed-off-by: Greg Kroah-Hartman --- net/ceph/mon_client.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/net/ceph/mon_client.c b/net/ceph/mon_client.c index 9ae1bab8c05d..72d87095f74b 100644 --- a/net/ceph/mon_client.c +++ b/net/ceph/mon_client.c @@ -209,6 +209,14 @@ static void reopen_session(struct ceph_mon_client *monc) __open_session(monc); } +static void un_backoff(struct ceph_mon_client *monc) +{ + monc->hunt_mult /= 2; /* reduce by 50% */ + if (monc->hunt_mult < 1) + monc->hunt_mult = 1; + dout("%s hunt_mult now %d\n", __func__, monc->hunt_mult); +} + /* * Reschedule delayed work timer. */ @@ -963,6 +971,7 @@ static void delayed_work(struct work_struct *work) if (!monc->hunting) { ceph_con_keepalive(&monc->con); __validate_auth(monc); + un_backoff(monc); } if (is_auth && @@ -1123,9 +1132,7 @@ static void finish_hunting(struct ceph_mon_client *monc) dout("%s found mon%d\n", __func__, monc->cur_mon); monc->hunting = false; monc->had_a_connection = true; - monc->hunt_mult /= 2; /* reduce by 50% */ - if (monc->hunt_mult < 1) - monc->hunt_mult = 1; + un_backoff(monc); } } -- GitLab From c2bc3eb5599f945568106acca364d6f5f1ec1f37 Mon Sep 17 00:00:00 2001 From: Ilya Dryomov Date: Mon, 23 Apr 2018 15:25:10 +0200 Subject: [PATCH 1306/1635] libceph: reschedule a tick in finish_hunting() commit 7b4c443d139f1d2b5570da475f7a9cbcef86740c upstream. If we go without an established session for a while, backoff delay will climb to 30 seconds. The keepalive timeout is also 30 seconds, so it's pretty easily hit after a prolonged hunting for a monitor: we don't get a chance to send out a keepalive in time, which means we never get back a keepalive ack in time, cutting an established session and attempting to connect to a different monitor every 30 seconds: [Sun Apr 1 23:37:05 2018] libceph: mon0 10.80.20.99:6789 session established [Sun Apr 1 23:37:36 2018] libceph: mon0 10.80.20.99:6789 session lost, hunting for new mon [Sun Apr 1 23:37:36 2018] libceph: mon2 10.80.20.103:6789 session established [Sun Apr 1 23:38:07 2018] libceph: mon2 10.80.20.103:6789 session lost, hunting for new mon [Sun Apr 1 23:38:07 2018] libceph: mon1 10.80.20.100:6789 session established [Sun Apr 1 23:38:37 2018] libceph: mon1 10.80.20.100:6789 session lost, hunting for new mon [Sun Apr 1 23:38:37 2018] libceph: mon2 10.80.20.103:6789 session established [Sun Apr 1 23:39:08 2018] libceph: mon2 10.80.20.103:6789 session lost, hunting for new mon The regular keepalive interval is 10 seconds. After ->hunting is cleared in finish_hunting(), call __schedule_delayed() to ensure we send out a keepalive after 10 seconds. Cc: stable@vger.kernel.org # 4.7+ Link: http://tracker.ceph.com/issues/23537 Signed-off-by: Ilya Dryomov Reviewed-by: Jason Dillaman Signed-off-by: Greg Kroah-Hartman --- net/ceph/mon_client.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/ceph/mon_client.c b/net/ceph/mon_client.c index 72d87095f74b..f14498a7eaec 100644 --- a/net/ceph/mon_client.c +++ b/net/ceph/mon_client.c @@ -1133,6 +1133,7 @@ static void finish_hunting(struct ceph_mon_client *monc) monc->hunting = false; monc->had_a_connection = true; un_backoff(monc); + __schedule_delayed(monc); } } -- GitLab From 7563d6f2be58010edecd145faa06bcd82251caa0 Mon Sep 17 00:00:00 2001 From: Ilya Dryomov Date: Tue, 24 Apr 2018 19:10:55 +0200 Subject: [PATCH 1307/1635] libceph: validate con->state at the top of try_write() commit 9c55ad1c214d9f8c4594ac2c3fa392c1c32431a7 upstream. ceph_con_workfn() validates con->state before calling try_read() and then try_write(). However, try_read() temporarily releases con->mutex, notably in process_message() and ceph_con_in_msg_alloc(), opening the window for ceph_con_close() to sneak in, close the connection and release con->sock. When try_write() is called on the assumption that con->state is still valid (i.e. not STANDBY or CLOSED), a NULL sock gets passed to the networking stack: BUG: unable to handle kernel NULL pointer dereference at 0000000000000020 IP: selinux_socket_sendmsg+0x5/0x20 Make sure con->state is valid at the top of try_write() and add an explicit BUG_ON for this, similar to try_read(). Cc: stable@vger.kernel.org Link: https://tracker.ceph.com/issues/23706 Signed-off-by: Ilya Dryomov Reviewed-by: Jason Dillaman Signed-off-by: Greg Kroah-Hartman --- net/ceph/messenger.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c index ad93342c90d7..5c4e85296cf6 100644 --- a/net/ceph/messenger.c +++ b/net/ceph/messenger.c @@ -2530,6 +2530,11 @@ static int try_write(struct ceph_connection *con) int ret = 1; dout("try_write start %p state %lu\n", con, con->state); + if (con->state != CON_STATE_PREOPEN && + con->state != CON_STATE_CONNECTING && + con->state != CON_STATE_NEGOTIATING && + con->state != CON_STATE_OPEN) + return 0; more: dout("try_write out_kvec_bytes %d\n", con->out_kvec_bytes); @@ -2555,6 +2560,8 @@ static int try_write(struct ceph_connection *con) } more_kvec: + BUG_ON(!con->sock); + /* kvec data queued? */ if (con->out_kvec_left) { ret = write_partial_kvec(con); -- GitLab From 9922fd0c681f4755422900c529290d393229d38d Mon Sep 17 00:00:00 2001 From: Anatolij Gustschin Date: Sun, 15 Apr 2018 11:33:08 -0700 Subject: [PATCH 1308/1635] fpga-manager: altera-ps-spi: preserve nCONFIG state commit 881c93c0fb73328845898344208fa0bf0d62cac6 upstream. If the driver module is loaded when FPGA is configured, the FPGA is reset because nconfig is pulled low (low-active gpio inited with GPIOD_OUT_HIGH activates the signal which means setting its value to low). Init nconfig with GPIOD_OUT_LOW to prevent this. Signed-off-by: Anatolij Gustschin Acked-by: Alan Tull Signed-off-by: Moritz Fischer Cc: stable # 4.14+ Signed-off-by: Greg Kroah-Hartman --- drivers/fpga/altera-ps-spi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/fpga/altera-ps-spi.c b/drivers/fpga/altera-ps-spi.c index 14f14efdf0d5..06d212a3d49d 100644 --- a/drivers/fpga/altera-ps-spi.c +++ b/drivers/fpga/altera-ps-spi.c @@ -249,7 +249,7 @@ static int altera_ps_probe(struct spi_device *spi) conf->data = of_id->data; conf->spi = spi; - conf->config = devm_gpiod_get(&spi->dev, "nconfig", GPIOD_OUT_HIGH); + conf->config = devm_gpiod_get(&spi->dev, "nconfig", GPIOD_OUT_LOW); if (IS_ERR(conf->config)) { dev_err(&spi->dev, "Failed to get config gpio: %ld\n", PTR_ERR(conf->config)); -- GitLab From 3a5465d0b61d91d9185570be027cf5e166af3d59 Mon Sep 17 00:00:00 2001 From: Daniel Kurtz Date: Fri, 6 Apr 2018 17:21:53 -0600 Subject: [PATCH 1309/1635] earlycon: Use a pointer table to fix __earlycon_table stride commit dd709e72cb934eefd44de8d9969097173fbf45dc upstream. Commit 99492c39f39f ("earlycon: Fix __earlycon_table stride") tried to fix __earlycon_table stride by forcing the earlycon_id struct alignment to 32 and asking the linker to 32-byte align the __earlycon_table symbol. This fix was based on commit 07fca0e57fca92 ("tracing: Properly align linker defined symbols") which tried a similar fix for the tracing subsystem. However, this fix doesn't quite work because there is no guarantee that gcc will place structures packed into an array format. In fact, gcc 4.9 chooses to 64-byte align these structs by inserting additional padding between the entries because it has no clue that they are supposed to be in an array. If we are unlucky, the linker will assign symbol "__earlycon_table" to a 32-byte aligned address which does not correspond to the 64-byte aligned contents of section "__earlycon_table". To address this same problem, the fix to the tracing system was subsequently re-implemented using a more robust table of pointers approach by commits: 3d56e331b653 ("tracing: Replace syscall_meta_data struct array with pointer array") 654986462939 ("tracepoints: Fix section alignment using pointer array") e4a9ea5ee7c8 ("tracing: Replace trace_event struct array with pointer array") Let's use this same "array of pointers to structs" approach for EARLYCON_TABLE. Fixes: 99492c39f39f ("earlycon: Fix __earlycon_table stride") Signed-off-by: Daniel Kurtz Suggested-by: Aaron Durbin Reviewed-by: Rob Herring Tested-by: Guenter Roeck Reviewed-by: Guenter Roeck Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/of/fdt.c | 7 +++++-- drivers/tty/serial/earlycon.c | 6 ++++-- include/asm-generic/vmlinux.lds.h | 2 +- include/linux/serial_core.h | 21 ++++++++++++++------- 4 files changed, 24 insertions(+), 12 deletions(-) diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c index ce30c9a588a4..6337c394bfe3 100644 --- a/drivers/of/fdt.c +++ b/drivers/of/fdt.c @@ -975,7 +975,7 @@ int __init early_init_dt_scan_chosen_stdout(void) int offset; const char *p, *q, *options = NULL; int l; - const struct earlycon_id *match; + const struct earlycon_id **p_match; const void *fdt = initial_boot_params; offset = fdt_path_offset(fdt, "/chosen"); @@ -1002,7 +1002,10 @@ int __init early_init_dt_scan_chosen_stdout(void) return 0; } - for (match = __earlycon_table; match < __earlycon_table_end; match++) { + for (p_match = __earlycon_table; p_match < __earlycon_table_end; + p_match++) { + const struct earlycon_id *match = *p_match; + if (!match->compatible[0]) continue; diff --git a/drivers/tty/serial/earlycon.c b/drivers/tty/serial/earlycon.c index 17dba0af5ee9..ac667b47f199 100644 --- a/drivers/tty/serial/earlycon.c +++ b/drivers/tty/serial/earlycon.c @@ -172,7 +172,7 @@ static int __init register_earlycon(char *buf, const struct earlycon_id *match) */ int __init setup_earlycon(char *buf) { - const struct earlycon_id *match; + const struct earlycon_id **p_match; if (!buf || !buf[0]) return -EINVAL; @@ -180,7 +180,9 @@ int __init setup_earlycon(char *buf) if (early_con.flags & CON_ENABLED) return -EALREADY; - for (match = __earlycon_table; match < __earlycon_table_end; match++) { + for (p_match = __earlycon_table; p_match < __earlycon_table_end; + p_match++) { + const struct earlycon_id *match = *p_match; size_t len = strlen(match->name); if (strncmp(buf, match->name, len)) diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h index 353f52fdc35e..fcec26d60d8c 100644 --- a/include/asm-generic/vmlinux.lds.h +++ b/include/asm-generic/vmlinux.lds.h @@ -170,7 +170,7 @@ #endif #ifdef CONFIG_SERIAL_EARLYCON -#define EARLYCON_TABLE() STRUCT_ALIGN(); \ +#define EARLYCON_TABLE() . = ALIGN(8); \ VMLINUX_SYMBOL(__earlycon_table) = .; \ KEEP(*(__earlycon_table)) \ VMLINUX_SYMBOL(__earlycon_table_end) = .; diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h index 5553e04e59c9..74fc82d22310 100644 --- a/include/linux/serial_core.h +++ b/include/linux/serial_core.h @@ -351,10 +351,10 @@ struct earlycon_id { char name[16]; char compatible[128]; int (*setup)(struct earlycon_device *, const char *options); -} __aligned(32); +}; -extern const struct earlycon_id __earlycon_table[]; -extern const struct earlycon_id __earlycon_table_end[]; +extern const struct earlycon_id *__earlycon_table[]; +extern const struct earlycon_id *__earlycon_table_end[]; #if defined(CONFIG_SERIAL_EARLYCON) && !defined(MODULE) #define EARLYCON_USED_OR_UNUSED __used @@ -362,12 +362,19 @@ extern const struct earlycon_id __earlycon_table_end[]; #define EARLYCON_USED_OR_UNUSED __maybe_unused #endif -#define OF_EARLYCON_DECLARE(_name, compat, fn) \ - static const struct earlycon_id __UNIQUE_ID(__earlycon_##_name) \ - EARLYCON_USED_OR_UNUSED __section(__earlycon_table) \ +#define _OF_EARLYCON_DECLARE(_name, compat, fn, unique_id) \ + static const struct earlycon_id unique_id \ + EARLYCON_USED_OR_UNUSED __initconst \ = { .name = __stringify(_name), \ .compatible = compat, \ - .setup = fn } + .setup = fn }; \ + static const struct earlycon_id EARLYCON_USED_OR_UNUSED \ + __section(__earlycon_table) \ + * const __PASTE(__p, unique_id) = &unique_id + +#define OF_EARLYCON_DECLARE(_name, compat, fn) \ + _OF_EARLYCON_DECLARE(_name, compat, fn, \ + __UNIQUE_ID(__earlycon_##_name)) #define EARLYCON_DECLARE(_name, fn) OF_EARLYCON_DECLARE(_name, "", fn) -- GitLab From 20b0f757da3be5a7c5f14f95250b9c8efcaee02d Mon Sep 17 00:00:00 2001 From: Shilpasri G Bhat Date: Wed, 25 Apr 2018 16:29:31 +0530 Subject: [PATCH 1310/1635] cpufreq: powernv: Fix hardlockup due to synchronous smp_call in timer interrupt commit c0f7f5b6c69107ca92909512533e70258ee19188 upstream. gpstate_timer_handler() uses synchronous smp_call to set the pstate on the requested core. This causes the below hard lockup: smp_call_function_single+0x110/0x180 (unreliable) smp_call_function_any+0x180/0x250 gpstate_timer_handler+0x1e8/0x580 call_timer_fn+0x50/0x1c0 expire_timers+0x138/0x1f0 run_timer_softirq+0x1e8/0x270 __do_softirq+0x158/0x3e4 irq_exit+0xe8/0x120 timer_interrupt+0x9c/0xe0 decrementer_common+0x114/0x120 -- interrupt: 901 at doorbell_global_ipi+0x34/0x50 LR = arch_send_call_function_ipi_mask+0x120/0x130 arch_send_call_function_ipi_mask+0x4c/0x130 smp_call_function_many+0x340/0x450 pmdp_invalidate+0x98/0xe0 change_huge_pmd+0xe0/0x270 change_protection_range+0xb88/0xe40 mprotect_fixup+0x140/0x340 SyS_mprotect+0x1b4/0x350 system_call+0x58/0x6c One way to avoid this is removing the smp-call. We can ensure that the timer always runs on one of the policy-cpus. If the timer gets migrated to a cpu outside the policy then re-queue it back on the policy->cpus. This way we can get rid of the smp-call which was being used to set the pstate on the policy->cpus. Fixes: 7bc54b652f13 ("timers, cpufreq/powernv: Initialize the gpstate timer as pinned") Cc: stable@vger.kernel.org # v4.8+ Reported-by: Nicholas Piggin Reported-by: Pridhiviraj Paidipeddi Signed-off-by: Shilpasri G Bhat Acked-by: Nicholas Piggin Acked-by: Viresh Kumar Acked-by: Vaidyanathan Srinivasan Signed-off-by: Michael Ellerman Signed-off-by: Greg Kroah-Hartman --- drivers/cpufreq/powernv-cpufreq.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/drivers/cpufreq/powernv-cpufreq.c b/drivers/cpufreq/powernv-cpufreq.c index 6b3a63545619..a28bb8f3f395 100644 --- a/drivers/cpufreq/powernv-cpufreq.c +++ b/drivers/cpufreq/powernv-cpufreq.c @@ -646,6 +646,16 @@ void gpstate_timer_handler(unsigned long data) if (!spin_trylock(&gpstates->gpstate_lock)) return; + /* + * If the timer has migrated to the different cpu then bring + * it back to one of the policy->cpus + */ + if (!cpumask_test_cpu(raw_smp_processor_id(), policy->cpus)) { + gpstates->timer.expires = jiffies + msecs_to_jiffies(1); + add_timer_on(&gpstates->timer, cpumask_first(policy->cpus)); + spin_unlock(&gpstates->gpstate_lock); + return; + } /* * If PMCR was last updated was using fast_swtich then @@ -685,10 +695,8 @@ void gpstate_timer_handler(unsigned long data) if (gpstate_idx != gpstates->last_lpstate_idx) queue_gpstate_timer(gpstates); + set_pstate(&freq_data); spin_unlock(&gpstates->gpstate_lock); - - /* Timer may get migrated to a different cpu on cpu hot unplug */ - smp_call_function_any(policy->cpus, set_pstate, &freq_data, 1); } /* -- GitLab From 79340bda01ab2704b11bae18e592304e41948492 Mon Sep 17 00:00:00 2001 From: Nicholas Piggin Date: Tue, 10 Apr 2018 21:49:32 +1000 Subject: [PATCH 1311/1635] rtc: opal: Fix OPAL RTC driver OPAL_BUSY loops commit 682e6b4da5cbe8e9a53f979a58c2a9d7dc997175 upstream. The OPAL RTC driver does not sleep in case it gets OPAL_BUSY or OPAL_BUSY_EVENT from firmware, which causes large scheduling latencies, up to 50 seconds have been observed here when RTC stops responding (BMC reboot can do it). Fix this by converting it to the standard form OPAL_BUSY loop that sleeps. Fixes: 628daa8d5abf ("powerpc/powernv: Add RTC and NVRAM support plus RTAS fallbacks") Cc: stable@vger.kernel.org # v3.2+ Signed-off-by: Nicholas Piggin Acked-by: Alexandre Belloni Signed-off-by: Michael Ellerman Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/platforms/powernv/opal-rtc.c | 8 +++-- drivers/rtc/rtc-opal.c | 37 ++++++++++++++--------- 2 files changed, 28 insertions(+), 17 deletions(-) diff --git a/arch/powerpc/platforms/powernv/opal-rtc.c b/arch/powerpc/platforms/powernv/opal-rtc.c index f8868864f373..aa2a5139462e 100644 --- a/arch/powerpc/platforms/powernv/opal-rtc.c +++ b/arch/powerpc/platforms/powernv/opal-rtc.c @@ -48,10 +48,12 @@ unsigned long __init opal_get_boot_time(void) while (rc == OPAL_BUSY || rc == OPAL_BUSY_EVENT) { rc = opal_rtc_read(&__y_m_d, &__h_m_s_ms); - if (rc == OPAL_BUSY_EVENT) + if (rc == OPAL_BUSY_EVENT) { + mdelay(OPAL_BUSY_DELAY_MS); opal_poll_events(NULL); - else if (rc == OPAL_BUSY) - mdelay(10); + } else if (rc == OPAL_BUSY) { + mdelay(OPAL_BUSY_DELAY_MS); + } } if (rc != OPAL_SUCCESS) return 0; diff --git a/drivers/rtc/rtc-opal.c b/drivers/rtc/rtc-opal.c index 304e891e35fc..60f2250fd96b 100644 --- a/drivers/rtc/rtc-opal.c +++ b/drivers/rtc/rtc-opal.c @@ -57,7 +57,7 @@ static void tm_to_opal(struct rtc_time *tm, u32 *y_m_d, u64 *h_m_s_ms) static int opal_get_rtc_time(struct device *dev, struct rtc_time *tm) { - long rc = OPAL_BUSY; + s64 rc = OPAL_BUSY; int retries = 10; u32 y_m_d; u64 h_m_s_ms; @@ -66,13 +66,17 @@ static int opal_get_rtc_time(struct device *dev, struct rtc_time *tm) while (rc == OPAL_BUSY || rc == OPAL_BUSY_EVENT) { rc = opal_rtc_read(&__y_m_d, &__h_m_s_ms); - if (rc == OPAL_BUSY_EVENT) + if (rc == OPAL_BUSY_EVENT) { + msleep(OPAL_BUSY_DELAY_MS); opal_poll_events(NULL); - else if (retries-- && (rc == OPAL_HARDWARE - || rc == OPAL_INTERNAL_ERROR)) - msleep(10); - else if (rc != OPAL_BUSY && rc != OPAL_BUSY_EVENT) - break; + } else if (rc == OPAL_BUSY) { + msleep(OPAL_BUSY_DELAY_MS); + } else if (rc == OPAL_HARDWARE || rc == OPAL_INTERNAL_ERROR) { + if (retries--) { + msleep(10); /* Wait 10ms before retry */ + rc = OPAL_BUSY; /* go around again */ + } + } } if (rc != OPAL_SUCCESS) @@ -87,21 +91,26 @@ static int opal_get_rtc_time(struct device *dev, struct rtc_time *tm) static int opal_set_rtc_time(struct device *dev, struct rtc_time *tm) { - long rc = OPAL_BUSY; + s64 rc = OPAL_BUSY; int retries = 10; u32 y_m_d = 0; u64 h_m_s_ms = 0; tm_to_opal(tm, &y_m_d, &h_m_s_ms); + while (rc == OPAL_BUSY || rc == OPAL_BUSY_EVENT) { rc = opal_rtc_write(y_m_d, h_m_s_ms); - if (rc == OPAL_BUSY_EVENT) + if (rc == OPAL_BUSY_EVENT) { + msleep(OPAL_BUSY_DELAY_MS); opal_poll_events(NULL); - else if (retries-- && (rc == OPAL_HARDWARE - || rc == OPAL_INTERNAL_ERROR)) - msleep(10); - else if (rc != OPAL_BUSY && rc != OPAL_BUSY_EVENT) - break; + } else if (rc == OPAL_BUSY) { + msleep(OPAL_BUSY_DELAY_MS); + } else if (rc == OPAL_HARDWARE || rc == OPAL_INTERNAL_ERROR) { + if (retries--) { + msleep(10); /* Wait 10ms before retry */ + rc = OPAL_BUSY; /* go around again */ + } + } } return rc == OPAL_SUCCESS ? 0 : -EIO; -- GitLab From 559121f5a1657899f534cf78a3f90feb8fa573f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolai=20H=C3=A4hnle?= Date: Thu, 12 Apr 2018 16:34:19 +0200 Subject: [PATCH 1312/1635] drm/amdgpu: set COMPUTE_PGM_RSRC1 for SGPR/VGPR clearing shaders MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 75569c182e4f65cd8826a5853dc9cbca703cbd0e upstream. Otherwise, the SQ may skip some of the register writes, or shader waves may be allocated where we don't expect them, so that as a result we don't actually reset all of the register SRAMs. This can lead to spurious ECC errors later on if a shader uses an uninitialized register. Signed-off-by: Nicolai Hähnle Reviewed-by: Alex Deucher Signed-off-by: Alex Deucher Cc: stable@vger.kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c index fc260c13b1da..a7e54820a330 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c @@ -1398,10 +1398,11 @@ static const u32 sgpr_init_compute_shader[] = static const u32 vgpr_init_regs[] = { mmCOMPUTE_STATIC_THREAD_MGMT_SE0, 0xffffffff, - mmCOMPUTE_RESOURCE_LIMITS, 0, + mmCOMPUTE_RESOURCE_LIMITS, 0x1000000, /* CU_GROUP_COUNT=1 */ mmCOMPUTE_NUM_THREAD_X, 256*4, mmCOMPUTE_NUM_THREAD_Y, 1, mmCOMPUTE_NUM_THREAD_Z, 1, + mmCOMPUTE_PGM_RSRC1, 0x100004f, /* VGPRS=15 (64 logical VGPRs), SGPRS=1 (16 SGPRs), BULKY=1 */ mmCOMPUTE_PGM_RSRC2, 20, mmCOMPUTE_USER_DATA_0, 0xedcedc00, mmCOMPUTE_USER_DATA_1, 0xedcedc01, @@ -1418,10 +1419,11 @@ static const u32 vgpr_init_regs[] = static const u32 sgpr1_init_regs[] = { mmCOMPUTE_STATIC_THREAD_MGMT_SE0, 0x0f, - mmCOMPUTE_RESOURCE_LIMITS, 0x1000000, + mmCOMPUTE_RESOURCE_LIMITS, 0x1000000, /* CU_GROUP_COUNT=1 */ mmCOMPUTE_NUM_THREAD_X, 256*5, mmCOMPUTE_NUM_THREAD_Y, 1, mmCOMPUTE_NUM_THREAD_Z, 1, + mmCOMPUTE_PGM_RSRC1, 0x240, /* SGPRS=9 (80 GPRS) */ mmCOMPUTE_PGM_RSRC2, 20, mmCOMPUTE_USER_DATA_0, 0xedcedc00, mmCOMPUTE_USER_DATA_1, 0xedcedc01, @@ -1442,6 +1444,7 @@ static const u32 sgpr2_init_regs[] = mmCOMPUTE_NUM_THREAD_X, 256*5, mmCOMPUTE_NUM_THREAD_Y, 1, mmCOMPUTE_NUM_THREAD_Z, 1, + mmCOMPUTE_PGM_RSRC1, 0x240, /* SGPRS=9 (80 GPRS) */ mmCOMPUTE_PGM_RSRC2, 20, mmCOMPUTE_USER_DATA_0, 0xedcedc00, mmCOMPUTE_USER_DATA_1, 0xedcedc01, -- GitLab From bf1d7023c901324eac0f8bc813d8b7317b85af65 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Thu, 19 Apr 2018 18:51:09 +0300 Subject: [PATCH 1313/1635] drm/i915: Enable display WA#1183 from its correct spot MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit ac315c621f01d4b8a53dec317c7ae322fd26ff38 upstream. The DMC FW specific part of display WA#1183 is supposed to be enabled whenever enabling DC5 or DC6, so move it to the DC6 enable function from the DC6 disable function. I noticed this after Daniel's patch to remove the unused skl_disable_dc6() function. Fixes: 53421c2fe99c ("drm/i915: Apply Display WA #1183 on skl, kbl, and cfl") Cc: Lucas De Marchi Cc: Rodrigo Vivi Cc: Ville Syrjälä Cc: Daniel Vetter Cc: Signed-off-by: Imre Deak Reviewed-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20180419155109.29451-1-imre.deak@intel.com (cherry picked from commit b49be6622f08187129561cff0409f7b06b33de57) Signed-off-by: Joonas Lahtinen Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/i915/intel_runtime_pm.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_runtime_pm.c b/drivers/gpu/drm/i915/intel_runtime_pm.c index bcccacba1ec6..bcfc1c235966 100644 --- a/drivers/gpu/drm/i915/intel_runtime_pm.c +++ b/drivers/gpu/drm/i915/intel_runtime_pm.c @@ -622,19 +622,18 @@ void skl_enable_dc6(struct drm_i915_private *dev_priv) DRM_DEBUG_KMS("Enabling DC6\n"); - gen9_set_dc_state(dev_priv, DC_STATE_EN_UPTO_DC6); + /* Wa Display #1183: skl,kbl,cfl */ + if (IS_GEN9_BC(dev_priv)) + I915_WRITE(GEN8_CHICKEN_DCPR_1, I915_READ(GEN8_CHICKEN_DCPR_1) | + SKL_SELECT_ALTERNATE_DC_EXIT); + gen9_set_dc_state(dev_priv, DC_STATE_EN_UPTO_DC6); } void skl_disable_dc6(struct drm_i915_private *dev_priv) { DRM_DEBUG_KMS("Disabling DC6\n"); - /* Wa Display #1183: skl,kbl,cfl */ - if (IS_GEN9_BC(dev_priv)) - I915_WRITE(GEN8_CHICKEN_DCPR_1, I915_READ(GEN8_CHICKEN_DCPR_1) | - SKL_SELECT_ALTERNATE_DC_EXIT); - gen9_set_dc_state(dev_priv, DC_STATE_DISABLE); } -- GitLab From d1f1f7771a6a5f81047ecf948c5a580c916f6c3d Mon Sep 17 00:00:00 2001 From: Josh Poimboeuf Date: Thu, 15 Mar 2018 22:11:54 -0500 Subject: [PATCH 1314/1635] objtool, perf: Fix GCC 8 -Wrestrict error MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 854e55ad289ef8888e7991f0ada85d5846f5afb9 upstream. Starting with recent GCC 8 builds, objtool and perf fail to build with the following error: ../str_error_r.c: In function ‘str_error_r’: ../str_error_r.c:25:3: error: passing argument 1 to restrict-qualified parameter aliases with argument 5 [-Werror=restrict] snprintf(buf, buflen, "INTERNAL ERROR: strerror_r(%d, %p, %zd)=%d", errnum, buf, buflen, err); The code seems harmless, but there's probably no benefit in printing the 'buf' pointer in this situation anyway, so just remove it to make GCC happy. Reported-by: Laura Abbott Signed-off-by: Josh Poimboeuf Tested-by: Laura Abbott Cc: Adrian Hunter Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: http://lkml.kernel.org/r/20180316031154.juk2uncs7baffctp@treble Signed-off-by: Arnaldo Carvalho de Melo Cc: Fredrik Schön Signed-off-by: Greg Kroah-Hartman --- tools/lib/str_error_r.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/lib/str_error_r.c b/tools/lib/str_error_r.c index d6d65537b0d9..6aad8308a0ac 100644 --- a/tools/lib/str_error_r.c +++ b/tools/lib/str_error_r.c @@ -22,6 +22,6 @@ char *str_error_r(int errnum, char *buf, size_t buflen) { int err = strerror_r(errnum, buf, buflen); if (err) - snprintf(buf, buflen, "INTERNAL ERROR: strerror_r(%d, %p, %zd)=%d", errnum, buf, buflen, err); + snprintf(buf, buflen, "INTERNAL ERROR: strerror_r(%d, [buf], %zd)=%d", errnum, buflen, err); return buf; } -- GitLab From 8e99c881e497e7f7528f693c563e204ae888a846 Mon Sep 17 00:00:00 2001 From: Sergey Senozhatsky Date: Tue, 6 Feb 2018 15:37:52 -0800 Subject: [PATCH 1315/1635] tools/lib/subcmd/pager.c: do not alias select() params MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit ad343a98e74e85aa91d844310e797f96fee6983b upstream. Use a separate fd set for select()-s exception fds param to fix the following gcc warning: pager.c:36:12: error: passing argument 2 to restrict-qualified parameter aliases with argument 4 [-Werror=restrict] select(1, &in, NULL, &in, NULL); ^~~ ~~~ Link: http://lkml.kernel.org/r/20180101105626.7168-1-sergey.senozhatsky@gmail.com Signed-off-by: Sergey Senozhatsky Cc: Arnaldo Carvalho de Melo Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Cc: Fredrik Schön Signed-off-by: Greg Kroah-Hartman --- tools/lib/subcmd/pager.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tools/lib/subcmd/pager.c b/tools/lib/subcmd/pager.c index 5ba754d17952..9997a8805a82 100644 --- a/tools/lib/subcmd/pager.c +++ b/tools/lib/subcmd/pager.c @@ -30,10 +30,13 @@ static void pager_preexec(void) * have real input */ fd_set in; + fd_set exception; FD_ZERO(&in); + FD_ZERO(&exception); FD_SET(0, &in); - select(1, &in, NULL, &in, NULL); + FD_SET(0, &exception); + select(1, &in, NULL, &exception, NULL); setenv("LESS", "FRSX", 0); } -- GitLab From ce911a5b1fea9700f797c3bd5dc9d9d94c996ac3 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 24 Apr 2018 23:19:51 +0200 Subject: [PATCH 1316/1635] x86/ipc: Fix x32 version of shmid64_ds and msqid64_ds commit 1a512c0882bd311c5b5561840fcfbe4c25b8f319 upstream. A bugfix broke the x32 shmid64_ds and msqid64_ds data structure layout (as seen from user space) a few years ago: Originally, __BITS_PER_LONG was defined as 64 on x32, so we did not have padding after the 64-bit __kernel_time_t fields, After __BITS_PER_LONG got changed to 32, applications would observe extra padding. In other parts of the uapi headers we seem to have a mix of those expecting either 32 or 64 on x32 applications, so we can't easily revert the path that broke these two structures. Instead, this patch decouples x32 from the other architectures and moves it back into arch specific headers, partially reverting the even older commit 73a2d096fdf2 ("x86: remove all now-duplicate header files"). It's not clear whether this ever made any difference, since at least glibc carries its own (correct) copy of both of these header files, so possibly no application has ever observed the definitions here. Based on a suggestion from H.J. Lu, I tried out the tool from https://github.com/hjl-tools/linux-header to find other such bugs, which pointed out the same bug in statfs(), which also has a separate (correct) copy in glibc. Fixes: f4b4aae18288 ("x86/headers/uapi: Fix __BITS_PER_LONG value for x32 builds") Signed-off-by: Arnd Bergmann Signed-off-by: Thomas Gleixner Cc: "H . J . Lu" Cc: Jeffrey Walton Cc: stable@vger.kernel.org Cc: "H. Peter Anvin" Link: https://lkml.kernel.org/r/20180424212013.3967461-1-arnd@arndb.de Signed-off-by: Greg Kroah-Hartman --- arch/x86/include/uapi/asm/msgbuf.h | 31 ++++++++++++++++++++++ arch/x86/include/uapi/asm/shmbuf.h | 42 ++++++++++++++++++++++++++++++ 2 files changed, 73 insertions(+) diff --git a/arch/x86/include/uapi/asm/msgbuf.h b/arch/x86/include/uapi/asm/msgbuf.h index 809134c644a6..90ab9a795b49 100644 --- a/arch/x86/include/uapi/asm/msgbuf.h +++ b/arch/x86/include/uapi/asm/msgbuf.h @@ -1 +1,32 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +#ifndef __ASM_X64_MSGBUF_H +#define __ASM_X64_MSGBUF_H + +#if !defined(__x86_64__) || !defined(__ILP32__) #include +#else +/* + * The msqid64_ds structure for x86 architecture with x32 ABI. + * + * On x86-32 and x86-64 we can just use the generic definition, but + * x32 uses the same binary layout as x86_64, which is differnet + * from other 32-bit architectures. + */ + +struct msqid64_ds { + struct ipc64_perm msg_perm; + __kernel_time_t msg_stime; /* last msgsnd time */ + __kernel_time_t msg_rtime; /* last msgrcv time */ + __kernel_time_t msg_ctime; /* last change time */ + __kernel_ulong_t msg_cbytes; /* current number of bytes on queue */ + __kernel_ulong_t msg_qnum; /* number of messages in queue */ + __kernel_ulong_t msg_qbytes; /* max number of bytes on queue */ + __kernel_pid_t msg_lspid; /* pid of last msgsnd */ + __kernel_pid_t msg_lrpid; /* last receive pid */ + __kernel_ulong_t __unused4; + __kernel_ulong_t __unused5; +}; + +#endif + +#endif /* __ASM_GENERIC_MSGBUF_H */ diff --git a/arch/x86/include/uapi/asm/shmbuf.h b/arch/x86/include/uapi/asm/shmbuf.h index 83c05fc2de38..644421f3823b 100644 --- a/arch/x86/include/uapi/asm/shmbuf.h +++ b/arch/x86/include/uapi/asm/shmbuf.h @@ -1 +1,43 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +#ifndef __ASM_X86_SHMBUF_H +#define __ASM_X86_SHMBUF_H + +#if !defined(__x86_64__) || !defined(__ILP32__) #include +#else +/* + * The shmid64_ds structure for x86 architecture with x32 ABI. + * + * On x86-32 and x86-64 we can just use the generic definition, but + * x32 uses the same binary layout as x86_64, which is differnet + * from other 32-bit architectures. + */ + +struct shmid64_ds { + struct ipc64_perm shm_perm; /* operation perms */ + size_t shm_segsz; /* size of segment (bytes) */ + __kernel_time_t shm_atime; /* last attach time */ + __kernel_time_t shm_dtime; /* last detach time */ + __kernel_time_t shm_ctime; /* last change time */ + __kernel_pid_t shm_cpid; /* pid of creator */ + __kernel_pid_t shm_lpid; /* pid of last operator */ + __kernel_ulong_t shm_nattch; /* no. of current attaches */ + __kernel_ulong_t __unused4; + __kernel_ulong_t __unused5; +}; + +struct shminfo64 { + __kernel_ulong_t shmmax; + __kernel_ulong_t shmmin; + __kernel_ulong_t shmmni; + __kernel_ulong_t shmseg; + __kernel_ulong_t shmall; + __kernel_ulong_t __unused1; + __kernel_ulong_t __unused2; + __kernel_ulong_t __unused3; + __kernel_ulong_t __unused4; +}; + +#endif + +#endif /* __ASM_X86_SHMBUF_H */ -- GitLab From b319531024d9b3c4d63965efc92d8e04803f42ce Mon Sep 17 00:00:00 2001 From: Yazen Ghannam Date: Tue, 3 Apr 2018 09:02:28 -0500 Subject: [PATCH 1317/1635] x86/smpboot: Don't use mwait_play_dead() on AMD systems commit da6fa7ef67f07108a1b0cb9fd9e7fcaabd39c051 upstream. Recent AMD systems support using MWAIT for C1 state. However, MWAIT will not allow deeper cstates than C1 on current systems. play_dead() expects to use the deepest state available. The deepest state available on AMD systems is reached through SystemIO or HALT. If MWAIT is available, it is preferred over the other methods, so the CPU never reaches the deepest possible state. Don't try to use MWAIT to play_dead() on AMD systems. Instead, use CPUIDLE to enter the deepest state advertised by firmware. If CPUIDLE is not available then fallback to HALT. Signed-off-by: Yazen Ghannam Signed-off-by: Thomas Gleixner Reviewed-by: Borislav Petkov Cc: stable@vger.kernel.org Cc: Yazen Ghannam Link: https://lkml.kernel.org/r/20180403140228.58540-1-Yazen.Ghannam@amd.com Signed-off-by: Greg Kroah-Hartman --- arch/x86/kernel/smpboot.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c index 2651ca2112c4..6b841262b790 100644 --- a/arch/x86/kernel/smpboot.c +++ b/arch/x86/kernel/smpboot.c @@ -1613,6 +1613,8 @@ static inline void mwait_play_dead(void) void *mwait_ptr; int i; + if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD) + return; if (!this_cpu_has(X86_FEATURE_MWAIT)) return; if (!this_cpu_has(X86_FEATURE_CLFLUSH)) -- GitLab From 7c6bcaac737fa72dd8aef00cb38b9c96b9b04cd8 Mon Sep 17 00:00:00 2001 From: Borislav Petkov Date: Sat, 21 Apr 2018 10:19:29 +0200 Subject: [PATCH 1318/1635] x86/microcode/intel: Save microcode patch unconditionally commit 84749d83758af6576552046b215b9b7f37f9556b upstream. save_mc_for_early() was a no-op on !CONFIG_HOTPLUG_CPU but the generic_load_microcode() path saves the microcode patches it has found into the cache of patches which is used for late loading too. Regardless of whether CPU hotplug is used or not. Make the saving unconditional so that late loading can find the proper patch. Reported-by: Vitezslav Samel Signed-off-by: Borislav Petkov Signed-off-by: Thomas Gleixner Tested-by: Vitezslav Samel Tested-by: Ashok Raj Cc: stable@vger.kernel.org Link: http://lkml.kernel.org/r/20180418081140.GA2439@pc11.op.pod.cz Link: https://lkml.kernel.org/r/20180421081930.15741-1-bp@alien8.de Signed-off-by: Greg Kroah-Hartman --- arch/x86/kernel/cpu/microcode/intel.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/arch/x86/kernel/cpu/microcode/intel.c b/arch/x86/kernel/cpu/microcode/intel.c index 32b8e5724f96..1c2cfa0644aa 100644 --- a/arch/x86/kernel/cpu/microcode/intel.c +++ b/arch/x86/kernel/cpu/microcode/intel.c @@ -485,7 +485,6 @@ static void show_saved_mc(void) */ static void save_mc_for_early(u8 *mc, unsigned int size) { -#ifdef CONFIG_HOTPLUG_CPU /* Synchronization during CPU hotplug. */ static DEFINE_MUTEX(x86_cpu_microcode_mutex); @@ -495,7 +494,6 @@ static void save_mc_for_early(u8 *mc, unsigned int size) show_saved_mc(); mutex_unlock(&x86_cpu_microcode_mutex); -#endif } static bool load_builtin_intel_microcode(struct cpio_data *cp) -- GitLab From 922e5129eb011ebbc62c416bc1c423a20ae359d7 Mon Sep 17 00:00:00 2001 From: Borislav Petkov Date: Sat, 21 Apr 2018 10:19:30 +0200 Subject: [PATCH 1319/1635] x86/microcode: Do not exit early from __reload_late() commit 09e182d17e8891dd73baba961a0f5a82e9274c97 upstream. Vitezslav reported a case where the "Timeout during microcode update!" panic would hit. After a deeper look, it turned out that his .config had CONFIG_HOTPLUG_CPU disabled which practically made save_mc_for_early() a no-op. When that happened, the discovered microcode patch wasn't saved into the cache and the late loading path wouldn't find any. This, then, lead to early exit from __reload_late() and thus CPUs waiting until the timeout is reached, leading to the panic. In hindsight, that function should have been written so it does not return before the post-synchronization. Oh well, I know better now... Fixes: bb8c13d61a62 ("x86/microcode: Fix CPU synchronization routine") Reported-by: Vitezslav Samel Signed-off-by: Borislav Petkov Signed-off-by: Thomas Gleixner Tested-by: Vitezslav Samel Tested-by: Ashok Raj Cc: stable@vger.kernel.org Link: http://lkml.kernel.org/r/20180418081140.GA2439@pc11.op.pod.cz Link: https://lkml.kernel.org/r/20180421081930.15741-2-bp@alien8.de Signed-off-by: Greg Kroah-Hartman --- arch/x86/kernel/cpu/microcode/core.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/arch/x86/kernel/cpu/microcode/core.c b/arch/x86/kernel/cpu/microcode/core.c index 021c90464cc2..c8e0cda0f272 100644 --- a/arch/x86/kernel/cpu/microcode/core.c +++ b/arch/x86/kernel/cpu/microcode/core.c @@ -564,14 +564,12 @@ static int __reload_late(void *info) apply_microcode_local(&err); spin_unlock(&update_lock); + /* siblings return UCODE_OK because their engine got updated already */ if (err > UCODE_NFOUND) { pr_warn("Error reloading microcode on CPU %d\n", cpu); - return -1; - /* siblings return UCODE_OK because their engine got updated already */ + ret = -1; } else if (err == UCODE_UPDATED || err == UCODE_OK) { ret = 1; - } else { - return ret; } /* -- GitLab From a2066aa76a7a487b93bc6135b6add2f0036d4ef6 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Tue, 24 Apr 2018 21:22:18 +0200 Subject: [PATCH 1320/1635] tick/sched: Do not mess with an enqueued hrtimer commit 1f71addd34f4c442bec7d7c749acc1beb58126f2 upstream. Kaike reported that in tests rdma hrtimers occasionaly stopped working. He did great debugging, which provided enough context to decode the problem. CPU 3 CPU 2 idle start sched_timer expires = 712171000000 queue->next = sched_timer start rdmavt timer. expires = 712172915662 lock(baseof(CPU3)) tick_nohz_stop_tick() tick = 716767000000 timerqueue_add(tmr) hrtimer_set_expires(sched_timer, tick); sched_timer->expires = 716767000000 <---- FAIL if (tmr->expires < queue->next->expires) hrtimer_start(sched_timer) queue->next = tmr; lock(baseof(CPU3)) unlock(baseof(CPU3)) timerqueue_remove() timerqueue_add() ts->sched_timer is queued and queue->next is pointing to it, but then ts->sched_timer.expires is modified. This not only corrupts the ordering of the timerqueue RB tree, it also makes CPU2 see the new expiry time of timerqueue->next->expires when checking whether timerqueue->next needs to be updated. So CPU2 sees that the rdma timer is earlier than timerqueue->next and sets the rdma timer as new next. Depending on whether it had also seen the new time at RB tree enqueue, it might have queued the rdma timer at the wrong place and then after removing the sched_timer the RB tree is completely hosed. The problem was introduced with a commit which tried to solve inconsistency between the hrtimer in the tick_sched data and the underlying hardware clockevent. It split out hrtimer_set_expires() to store the new tick time in both the NOHZ and the NOHZ + HIGHRES case, but missed the fact that in the NOHZ + HIGHRES case the hrtimer might still be queued. Use hrtimer_start(timer, tick...) for the NOHZ + HIGHRES case which sets timer->expires after canceling the timer and move the hrtimer_set_expires() invocation into the NOHZ only code path which is not affected as it merily uses the hrtimer as next event storage so code pathes can be shared with the NOHZ + HIGHRES case. Fixes: d4af6d933ccf ("nohz: Fix spurious warning when hrtimer and clockevent get out of sync") Reported-by: "Wan Kaike" Signed-off-by: Thomas Gleixner Acked-by: Frederic Weisbecker Cc: "Marciniszyn Mike" Cc: Anna-Maria Gleixner Cc: linux-rdma@vger.kernel.org Cc: "Dalessandro Dennis" Cc: "Fleck John" Cc: stable@vger.kernel.org Cc: Peter Zijlstra Cc: Frederic Weisbecker Cc: "Weiny Ira" Cc: "linux-rdma@vger.kernel.org" Link: https://lkml.kernel.org/r/alpine.DEB.2.21.1804241637390.1679@nanos.tec.linutronix.de Link: https://lkml.kernel.org/r/alpine.DEB.2.21.1804242119210.1597@nanos.tec.linutronix.de Signed-off-by: Greg Kroah-Hartman --- kernel/time/tick-sched.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c index dfa4a117fee3..bb2af74e6b62 100644 --- a/kernel/time/tick-sched.c +++ b/kernel/time/tick-sched.c @@ -820,12 +820,13 @@ static ktime_t tick_nohz_stop_sched_tick(struct tick_sched *ts, goto out; } - hrtimer_set_expires(&ts->sched_timer, tick); - - if (ts->nohz_mode == NOHZ_MODE_HIGHRES) - hrtimer_start_expires(&ts->sched_timer, HRTIMER_MODE_ABS_PINNED); - else + if (ts->nohz_mode == NOHZ_MODE_HIGHRES) { + hrtimer_start(&ts->sched_timer, tick, HRTIMER_MODE_ABS_PINNED); + } else { + hrtimer_set_expires(&ts->sched_timer, tick); tick_program_event(tick, 1); + } + out: /* * Update the estimated sleep length until the next timer -- GitLab From e5a290c4ff77c9fb3fcb1dee7cfb356969daeee2 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Sun, 21 Jan 2018 16:42:56 +0000 Subject: [PATCH 1321/1635] arm/arm64: KVM: Add PSCI version selection API commit 85bd0ba1ff9875798fad94218b627ea9f768f3c3 upstream. Although we've implemented PSCI 0.1, 0.2 and 1.0, we expose either 0.1 or 1.0 to a guest, defaulting to the latest version of the PSCI implementation that is compatible with the requested version. This is no different from doing a firmware upgrade on KVM. But in order to give a chance to hypothetical badly implemented guests that would have a fit by discovering something other than PSCI 0.2, let's provide a new API that allows userspace to pick one particular version of the API. This is implemented as a new class of "firmware" registers, where we expose the PSCI version. This allows the PSCI version to be save/restored as part of a guest migration, and also set to any supported version if the guest requires it. Cc: stable@vger.kernel.org #4.16 Reviewed-by: Christoffer Dall Signed-off-by: Marc Zyngier Signed-off-by: Greg Kroah-Hartman --- Documentation/virtual/kvm/api.txt | 9 +++- Documentation/virtual/kvm/arm/psci.txt | 30 +++++++++++++ arch/arm/include/asm/kvm_host.h | 3 ++ arch/arm/include/uapi/asm/kvm.h | 6 +++ arch/arm/kvm/guest.c | 13 ++++++ arch/arm64/include/asm/kvm_host.h | 3 ++ arch/arm64/include/uapi/asm/kvm.h | 6 +++ arch/arm64/kvm/guest.c | 14 +++++- include/kvm/arm_psci.h | 16 ++++++- virt/kvm/arm/psci.c | 60 ++++++++++++++++++++++++++ 10 files changed, 156 insertions(+), 4 deletions(-) create mode 100644 Documentation/virtual/kvm/arm/psci.txt diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt index 0f9089416b4c..88ad78c6f605 100644 --- a/Documentation/virtual/kvm/api.txt +++ b/Documentation/virtual/kvm/api.txt @@ -1940,6 +1940,9 @@ ARM 32-bit VFP control registers have the following id bit patterns: ARM 64-bit FP registers have the following id bit patterns: 0x4030 0000 0012 0 +ARM firmware pseudo-registers have the following bit pattern: + 0x4030 0000 0014 + arm64 registers are mapped using the lower 32 bits. The upper 16 of that is the register group type, or coprocessor number: @@ -1956,6 +1959,9 @@ arm64 CCSIDR registers are demultiplexed by CSSELR value: arm64 system registers have the following id bit patterns: 0x6030 0000 0013 +arm64 firmware pseudo-registers have the following bit pattern: + 0x6030 0000 0014 + MIPS registers are mapped using the lower 32 bits. The upper 16 of that is the register group type: @@ -2490,7 +2496,8 @@ Possible features: and execute guest code when KVM_RUN is called. - KVM_ARM_VCPU_EL1_32BIT: Starts the CPU in a 32bit mode. Depends on KVM_CAP_ARM_EL1_32BIT (arm64 only). - - KVM_ARM_VCPU_PSCI_0_2: Emulate PSCI v0.2 for the CPU. + - KVM_ARM_VCPU_PSCI_0_2: Emulate PSCI v0.2 (or a future revision + backward compatible with v0.2) for the CPU. Depends on KVM_CAP_ARM_PSCI_0_2. - KVM_ARM_VCPU_PMU_V3: Emulate PMUv3 for the CPU. Depends on KVM_CAP_ARM_PMU_V3. diff --git a/Documentation/virtual/kvm/arm/psci.txt b/Documentation/virtual/kvm/arm/psci.txt new file mode 100644 index 000000000000..aafdab887b04 --- /dev/null +++ b/Documentation/virtual/kvm/arm/psci.txt @@ -0,0 +1,30 @@ +KVM implements the PSCI (Power State Coordination Interface) +specification in order to provide services such as CPU on/off, reset +and power-off to the guest. + +The PSCI specification is regularly updated to provide new features, +and KVM implements these updates if they make sense from a virtualization +point of view. + +This means that a guest booted on two different versions of KVM can +observe two different "firmware" revisions. This could cause issues if +a given guest is tied to a particular PSCI revision (unlikely), or if +a migration causes a different PSCI version to be exposed out of the +blue to an unsuspecting guest. + +In order to remedy this situation, KVM exposes a set of "firmware +pseudo-registers" that can be manipulated using the GET/SET_ONE_REG +interface. These registers can be saved/restored by userspace, and set +to a convenient value if required. + +The following register is defined: + +* KVM_REG_ARM_PSCI_VERSION: + + - Only valid if the vcpu has the KVM_ARM_VCPU_PSCI_0_2 feature set + (and thus has already been initialized) + - Returns the current PSCI version on GET_ONE_REG (defaulting to the + highest PSCI version implemented by KVM and compatible with v0.2) + - Allows any PSCI version implemented by KVM and compatible with + v0.2 to be set with SET_ONE_REG + - Affects the whole VM (even if the register view is per-vcpu) diff --git a/arch/arm/include/asm/kvm_host.h b/arch/arm/include/asm/kvm_host.h index 31fbb9285f62..8f973e3b7348 100644 --- a/arch/arm/include/asm/kvm_host.h +++ b/arch/arm/include/asm/kvm_host.h @@ -75,6 +75,9 @@ struct kvm_arch { /* Interrupt controller */ struct vgic_dist vgic; int max_vcpus; + + /* Mandated version of PSCI */ + u32 psci_version; }; #define KVM_NR_MEM_OBJS 40 diff --git a/arch/arm/include/uapi/asm/kvm.h b/arch/arm/include/uapi/asm/kvm.h index 1f57bbe82b6f..df24fc8da1bc 100644 --- a/arch/arm/include/uapi/asm/kvm.h +++ b/arch/arm/include/uapi/asm/kvm.h @@ -180,6 +180,12 @@ struct kvm_arch_memory_slot { #define KVM_REG_ARM_VFP_FPINST 0x1009 #define KVM_REG_ARM_VFP_FPINST2 0x100A +/* KVM-as-firmware specific pseudo-registers */ +#define KVM_REG_ARM_FW (0x0014 << KVM_REG_ARM_COPROC_SHIFT) +#define KVM_REG_ARM_FW_REG(r) (KVM_REG_ARM | KVM_REG_SIZE_U64 | \ + KVM_REG_ARM_FW | ((r) & 0xffff)) +#define KVM_REG_ARM_PSCI_VERSION KVM_REG_ARM_FW_REG(0) + /* Device Control API: ARM VGIC */ #define KVM_DEV_ARM_VGIC_GRP_ADDR 0 #define KVM_DEV_ARM_VGIC_GRP_DIST_REGS 1 diff --git a/arch/arm/kvm/guest.c b/arch/arm/kvm/guest.c index 1e0784ebbfd6..a18f33edc471 100644 --- a/arch/arm/kvm/guest.c +++ b/arch/arm/kvm/guest.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -176,6 +177,7 @@ static unsigned long num_core_regs(void) unsigned long kvm_arm_num_regs(struct kvm_vcpu *vcpu) { return num_core_regs() + kvm_arm_num_coproc_regs(vcpu) + + kvm_arm_get_fw_num_regs(vcpu) + NUM_TIMER_REGS; } @@ -196,6 +198,11 @@ int kvm_arm_copy_reg_indices(struct kvm_vcpu *vcpu, u64 __user *uindices) uindices++; } + ret = kvm_arm_copy_fw_reg_indices(vcpu, uindices); + if (ret) + return ret; + uindices += kvm_arm_get_fw_num_regs(vcpu); + ret = copy_timer_indices(vcpu, uindices); if (ret) return ret; @@ -214,6 +221,9 @@ int kvm_arm_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg) if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_CORE) return get_core_reg(vcpu, reg); + if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_FW) + return kvm_arm_get_fw_reg(vcpu, reg); + if (is_timer_reg(reg->id)) return get_timer_reg(vcpu, reg); @@ -230,6 +240,9 @@ int kvm_arm_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg) if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_CORE) return set_core_reg(vcpu, reg); + if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_FW) + return kvm_arm_set_fw_reg(vcpu, reg); + if (is_timer_reg(reg->id)) return set_timer_reg(vcpu, reg); diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h index 8ad208cb866c..8abec9f7f430 100644 --- a/arch/arm64/include/asm/kvm_host.h +++ b/arch/arm64/include/asm/kvm_host.h @@ -71,6 +71,9 @@ struct kvm_arch { /* Interrupt controller */ struct vgic_dist vgic; + + /* Mandated version of PSCI */ + u32 psci_version; }; #define KVM_NR_MEM_OBJS 40 diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h index 51149ec75fe4..9f74ce5899f0 100644 --- a/arch/arm64/include/uapi/asm/kvm.h +++ b/arch/arm64/include/uapi/asm/kvm.h @@ -200,6 +200,12 @@ struct kvm_arch_memory_slot { #define KVM_REG_ARM_TIMER_CNT ARM64_SYS_REG(3, 3, 14, 3, 2) #define KVM_REG_ARM_TIMER_CVAL ARM64_SYS_REG(3, 3, 14, 0, 2) +/* KVM-as-firmware specific pseudo-registers */ +#define KVM_REG_ARM_FW (0x0014 << KVM_REG_ARM_COPROC_SHIFT) +#define KVM_REG_ARM_FW_REG(r) (KVM_REG_ARM64 | KVM_REG_SIZE_U64 | \ + KVM_REG_ARM_FW | ((r) & 0xffff)) +#define KVM_REG_ARM_PSCI_VERSION KVM_REG_ARM_FW_REG(0) + /* Device Control API: ARM VGIC */ #define KVM_DEV_ARM_VGIC_GRP_ADDR 0 #define KVM_DEV_ARM_VGIC_GRP_DIST_REGS 1 diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c index 5c7f657dd207..811f04c5760e 100644 --- a/arch/arm64/kvm/guest.c +++ b/arch/arm64/kvm/guest.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -205,7 +206,7 @@ static int get_timer_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg) unsigned long kvm_arm_num_regs(struct kvm_vcpu *vcpu) { return num_core_regs() + kvm_arm_num_sys_reg_descs(vcpu) - + NUM_TIMER_REGS; + + kvm_arm_get_fw_num_regs(vcpu) + NUM_TIMER_REGS; } /** @@ -225,6 +226,11 @@ int kvm_arm_copy_reg_indices(struct kvm_vcpu *vcpu, u64 __user *uindices) uindices++; } + ret = kvm_arm_copy_fw_reg_indices(vcpu, uindices); + if (ret) + return ret; + uindices += kvm_arm_get_fw_num_regs(vcpu); + ret = copy_timer_indices(vcpu, uindices); if (ret) return ret; @@ -243,6 +249,9 @@ int kvm_arm_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg) if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_CORE) return get_core_reg(vcpu, reg); + if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_FW) + return kvm_arm_get_fw_reg(vcpu, reg); + if (is_timer_reg(reg->id)) return get_timer_reg(vcpu, reg); @@ -259,6 +268,9 @@ int kvm_arm_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg) if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_CORE) return set_core_reg(vcpu, reg); + if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_FW) + return kvm_arm_set_fw_reg(vcpu, reg); + if (is_timer_reg(reg->id)) return set_timer_reg(vcpu, reg); diff --git a/include/kvm/arm_psci.h b/include/kvm/arm_psci.h index e518e4e3dfb5..4b1548129fa2 100644 --- a/include/kvm/arm_psci.h +++ b/include/kvm/arm_psci.h @@ -37,10 +37,15 @@ static inline int kvm_psci_version(struct kvm_vcpu *vcpu, struct kvm *kvm) * Our PSCI implementation stays the same across versions from * v0.2 onward, only adding the few mandatory functions (such * as FEATURES with 1.0) that are required by newer - * revisions. It is thus safe to return the latest. + * revisions. It is thus safe to return the latest, unless + * userspace has instructed us otherwise. */ - if (test_bit(KVM_ARM_VCPU_PSCI_0_2, vcpu->arch.features)) + if (test_bit(KVM_ARM_VCPU_PSCI_0_2, vcpu->arch.features)) { + if (vcpu->kvm->arch.psci_version) + return vcpu->kvm->arch.psci_version; + return KVM_ARM_PSCI_LATEST; + } return KVM_ARM_PSCI_0_1; } @@ -48,4 +53,11 @@ static inline int kvm_psci_version(struct kvm_vcpu *vcpu, struct kvm *kvm) int kvm_hvc_call_handler(struct kvm_vcpu *vcpu); +struct kvm_one_reg; + +int kvm_arm_get_fw_num_regs(struct kvm_vcpu *vcpu); +int kvm_arm_copy_fw_reg_indices(struct kvm_vcpu *vcpu, u64 __user *uindices); +int kvm_arm_get_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg); +int kvm_arm_set_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg); + #endif /* __KVM_ARM_PSCI_H__ */ diff --git a/virt/kvm/arm/psci.c b/virt/kvm/arm/psci.c index 6919352cbf15..c4762bef13c6 100644 --- a/virt/kvm/arm/psci.c +++ b/virt/kvm/arm/psci.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -427,3 +428,62 @@ int kvm_hvc_call_handler(struct kvm_vcpu *vcpu) smccc_set_retval(vcpu, val, 0, 0, 0); return 1; } + +int kvm_arm_get_fw_num_regs(struct kvm_vcpu *vcpu) +{ + return 1; /* PSCI version */ +} + +int kvm_arm_copy_fw_reg_indices(struct kvm_vcpu *vcpu, u64 __user *uindices) +{ + if (put_user(KVM_REG_ARM_PSCI_VERSION, uindices)) + return -EFAULT; + + return 0; +} + +int kvm_arm_get_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg) +{ + if (reg->id == KVM_REG_ARM_PSCI_VERSION) { + void __user *uaddr = (void __user *)(long)reg->addr; + u64 val; + + val = kvm_psci_version(vcpu, vcpu->kvm); + if (copy_to_user(uaddr, &val, KVM_REG_SIZE(reg->id))) + return -EFAULT; + + return 0; + } + + return -EINVAL; +} + +int kvm_arm_set_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg) +{ + if (reg->id == KVM_REG_ARM_PSCI_VERSION) { + void __user *uaddr = (void __user *)(long)reg->addr; + bool wants_02; + u64 val; + + if (copy_from_user(&val, uaddr, KVM_REG_SIZE(reg->id))) + return -EFAULT; + + wants_02 = test_bit(KVM_ARM_VCPU_PSCI_0_2, vcpu->arch.features); + + switch (val) { + case KVM_ARM_PSCI_0_1: + if (wants_02) + return -EINVAL; + vcpu->kvm->arch.psci_version = val; + return 0; + case KVM_ARM_PSCI_0_2: + case KVM_ARM_PSCI_1_0: + if (!wants_02) + return -EINVAL; + vcpu->kvm->arch.psci_version = val; + return 0; + } + } + + return -EINVAL; +} -- GitLab From 7fddff51f245b01d1dab2a6461d706170ff5b519 Mon Sep 17 00:00:00 2001 From: Michael Neuling Date: Mon, 26 Mar 2018 15:17:07 +1100 Subject: [PATCH 1322/1635] powerpc/eeh: Fix race with driver un/bind commit f0295e047fcf52ccb42561fb7de6942f5201b676 upstream. The current EEH callbacks can race with a driver unbind. This can result in a backtraces like this: EEH: Frozen PHB#0-PE#1fc detected EEH: PE location: S000009, PHB location: N/A CPU: 2 PID: 2312 Comm: kworker/u258:3 Not tainted 4.15.6-openpower1 #2 Workqueue: nvme-wq nvme_reset_work [nvme] Call Trace: dump_stack+0x9c/0xd0 (unreliable) eeh_dev_check_failure+0x420/0x470 eeh_check_failure+0xa0/0xa4 nvme_reset_work+0x138/0x1414 [nvme] process_one_work+0x1ec/0x328 worker_thread+0x2e4/0x3a8 kthread+0x14c/0x154 ret_from_kernel_thread+0x5c/0xc8 nvme nvme1: Removing after probe failure status: -19 cpu 0x23: Vector: 300 (Data Access) at [c000000ff50f3800] pc: c0080000089a0eb0: nvme_error_detected+0x4c/0x90 [nvme] lr: c000000000026564: eeh_report_error+0xe0/0x110 sp: c000000ff50f3a80 msr: 9000000000009033 dar: 400 dsisr: 40000000 current = 0xc000000ff507c000 paca = 0xc00000000fdc9d80 softe: 0 irq_happened: 0x01 pid = 782, comm = eehd Linux version 4.15.6-openpower1 (smc@smc-desktop) (gcc version 6.4.0 (Buildroot 2017.11.2-00008-g4b6188e)) #2 SM P Tue Feb 27 12:33:27 PST 2018 enter ? for help eeh_report_error+0xe0/0x110 eeh_pe_dev_traverse+0xc0/0xdc eeh_handle_normal_event+0x184/0x4c4 eeh_handle_event+0x30/0x288 eeh_event_handler+0x124/0x170 kthread+0x14c/0x154 ret_from_kernel_thread+0x5c/0xc8 The first part is an EEH (on boot), the second half is the resulting crash. nvme probe starts the nvme_reset_work() worker thread. This worker thread starts touching the device which see a device error (EEH) and hence queues up an event in the powerpc EEH worker thread. nvme_reset_work() then continues and runs nvme_remove_dead_ctrl_work() which results in unbinding the driver from the device and hence releases all resources. At the same time, the EEH worker thread starts doing the EEH .error_detected() driver callback, which no longer works since the resources have been freed. This fixes the problem in the same way the generic PCIe AER code (in drivers/pci/pcie/aer/aerdrv_core.c) does. It makes the EEH code hold the device_lock() while performing the driver EEH callbacks and associated code. This ensures either the callbacks are no longer register, or if they are registered the driver will not be removed from underneath us. This has been broken forever. The EEH call backs were first introduced in 2005 (in 77bd7415610) but it's not clear if a lock was needed back then. Fixes: 77bd74156101 ("[PATCH] powerpc: PCI Error Recovery: PPC64 core recovery routines") Cc: stable@vger.kernel.org # v2.6.16+ Signed-off-by: Michael Neuling Reviewed-by: Benjamin Herrenschmidt Signed-off-by: Michael Ellerman Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/kernel/eeh_driver.c | 61 ++++++++++++++++++++------------ 1 file changed, 38 insertions(+), 23 deletions(-) diff --git a/arch/powerpc/kernel/eeh_driver.c b/arch/powerpc/kernel/eeh_driver.c index 8b840191df59..ca2243df9cb2 100644 --- a/arch/powerpc/kernel/eeh_driver.c +++ b/arch/powerpc/kernel/eeh_driver.c @@ -207,18 +207,18 @@ static void *eeh_report_error(void *data, void *userdata) if (!dev || eeh_dev_removed(edev) || eeh_pe_passed(edev->pe)) return NULL; + + device_lock(&dev->dev); dev->error_state = pci_channel_io_frozen; driver = eeh_pcid_get(dev); - if (!driver) return NULL; + if (!driver) goto out_no_dev; eeh_disable_irq(dev); if (!driver->err_handler || - !driver->err_handler->error_detected) { - eeh_pcid_put(dev); - return NULL; - } + !driver->err_handler->error_detected) + goto out; rc = driver->err_handler->error_detected(dev, pci_channel_io_frozen); @@ -227,7 +227,10 @@ static void *eeh_report_error(void *data, void *userdata) if (*res == PCI_ERS_RESULT_NONE) *res = rc; edev->in_error = true; +out: eeh_pcid_put(dev); +out_no_dev: + device_unlock(&dev->dev); return NULL; } @@ -250,15 +253,14 @@ static void *eeh_report_mmio_enabled(void *data, void *userdata) if (!dev || eeh_dev_removed(edev) || eeh_pe_passed(edev->pe)) return NULL; + device_lock(&dev->dev); driver = eeh_pcid_get(dev); - if (!driver) return NULL; + if (!driver) goto out_no_dev; if (!driver->err_handler || !driver->err_handler->mmio_enabled || - (edev->mode & EEH_DEV_NO_HANDLER)) { - eeh_pcid_put(dev); - return NULL; - } + (edev->mode & EEH_DEV_NO_HANDLER)) + goto out; rc = driver->err_handler->mmio_enabled(dev); @@ -266,7 +268,10 @@ static void *eeh_report_mmio_enabled(void *data, void *userdata) if (rc == PCI_ERS_RESULT_NEED_RESET) *res = rc; if (*res == PCI_ERS_RESULT_NONE) *res = rc; +out: eeh_pcid_put(dev); +out_no_dev: + device_unlock(&dev->dev); return NULL; } @@ -289,20 +294,20 @@ static void *eeh_report_reset(void *data, void *userdata) if (!dev || eeh_dev_removed(edev) || eeh_pe_passed(edev->pe)) return NULL; + + device_lock(&dev->dev); dev->error_state = pci_channel_io_normal; driver = eeh_pcid_get(dev); - if (!driver) return NULL; + if (!driver) goto out_no_dev; eeh_enable_irq(dev); if (!driver->err_handler || !driver->err_handler->slot_reset || (edev->mode & EEH_DEV_NO_HANDLER) || - (!edev->in_error)) { - eeh_pcid_put(dev); - return NULL; - } + (!edev->in_error)) + goto out; rc = driver->err_handler->slot_reset(dev); if ((*res == PCI_ERS_RESULT_NONE) || @@ -310,7 +315,10 @@ static void *eeh_report_reset(void *data, void *userdata) if (*res == PCI_ERS_RESULT_DISCONNECT && rc == PCI_ERS_RESULT_NEED_RESET) *res = rc; +out: eeh_pcid_put(dev); +out_no_dev: + device_unlock(&dev->dev); return NULL; } @@ -361,10 +369,12 @@ static void *eeh_report_resume(void *data, void *userdata) if (!dev || eeh_dev_removed(edev) || eeh_pe_passed(edev->pe)) return NULL; + + device_lock(&dev->dev); dev->error_state = pci_channel_io_normal; driver = eeh_pcid_get(dev); - if (!driver) return NULL; + if (!driver) goto out_no_dev; was_in_error = edev->in_error; edev->in_error = false; @@ -374,13 +384,15 @@ static void *eeh_report_resume(void *data, void *userdata) !driver->err_handler->resume || (edev->mode & EEH_DEV_NO_HANDLER) || !was_in_error) { edev->mode &= ~EEH_DEV_NO_HANDLER; - eeh_pcid_put(dev); - return NULL; + goto out; } driver->err_handler->resume(dev); +out: eeh_pcid_put(dev); +out_no_dev: + device_unlock(&dev->dev); return NULL; } @@ -400,22 +412,25 @@ static void *eeh_report_failure(void *data, void *userdata) if (!dev || eeh_dev_removed(edev) || eeh_pe_passed(edev->pe)) return NULL; + + device_lock(&dev->dev); dev->error_state = pci_channel_io_perm_failure; driver = eeh_pcid_get(dev); - if (!driver) return NULL; + if (!driver) goto out_no_dev; eeh_disable_irq(dev); if (!driver->err_handler || - !driver->err_handler->error_detected) { - eeh_pcid_put(dev); - return NULL; - } + !driver->err_handler->error_detected) + goto out; driver->err_handler->error_detected(dev, pci_channel_io_perm_failure); +out: eeh_pcid_put(dev); +out_no_dev: + device_unlock(&dev->dev); return NULL; } -- GitLab From 7d6240f0fb85430ae4f490824fdf8d0a078dfcd2 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Tue, 1 May 2018 12:58:27 -0700 Subject: [PATCH 1323/1635] Linux 4.14.39 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 27a8d5c37180..248b99283f71 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 VERSION = 4 PATCHLEVEL = 14 -SUBLEVEL = 38 +SUBLEVEL = 39 EXTRAVERSION = NAME = Petit Gorille -- GitLab From ea1373dc81f550abd9346cab4849c9211ce0d2e6 Mon Sep 17 00:00:00 2001 From: Chris Lew Date: Wed, 18 Apr 2018 17:59:44 -0700 Subject: [PATCH 1324/1635] defconfig: sm8150: Enable RPMSG GLINK spi transport The RPMSG GLINK spi transport enables communication to the wdsp processor over a spi bus. The glink spi driver receives notifications about processor status from a component manager and internally handles SSR. Change-Id: Ie0b67e87c06dd50a37a9993c7dee19e5918f09e4 Signed-off-by: Chris Lew --- arch/arm64/configs/sm8150-perf_defconfig | 1 + arch/arm64/configs/sm8150_defconfig | 1 + 2 files changed, 2 insertions(+) diff --git a/arch/arm64/configs/sm8150-perf_defconfig b/arch/arm64/configs/sm8150-perf_defconfig index 64a922f9348f..0e11ae7a0767 100644 --- a/arch/arm64/configs/sm8150-perf_defconfig +++ b/arch/arm64/configs/sm8150-perf_defconfig @@ -481,6 +481,7 @@ CONFIG_IOMMU_TESTS=y CONFIG_RPMSG_CHAR=y CONFIG_RPMSG_QCOM_GLINK_SMEM=y CONFIG_RPMSG_QCOM_GLINK_SPSS=y +CONFIG_RPMSG_QCOM_GLINK_SPI=y CONFIG_QCOM_CPUSS_DUMP=y CONFIG_QCOM_RUN_QUEUE_STATS=y CONFIG_QCOM_LLCC=y diff --git a/arch/arm64/configs/sm8150_defconfig b/arch/arm64/configs/sm8150_defconfig index af8f88e260f1..87d4917f6f6e 100644 --- a/arch/arm64/configs/sm8150_defconfig +++ b/arch/arm64/configs/sm8150_defconfig @@ -499,6 +499,7 @@ CONFIG_IOMMU_TESTS=y CONFIG_RPMSG_CHAR=y CONFIG_RPMSG_QCOM_GLINK_SMEM=y CONFIG_RPMSG_QCOM_GLINK_SPSS=y +CONFIG_RPMSG_QCOM_GLINK_SPI=y CONFIG_QCOM_CPUSS_DUMP=y CONFIG_QCOM_RUN_QUEUE_STATS=y CONFIG_QCOM_LLCC=y -- GitLab From 161a5f7f691501c35826f60f5a2dfec7ba1481ed Mon Sep 17 00:00:00 2001 From: Maheshwar Ajja Date: Tue, 1 May 2018 13:08:56 -0700 Subject: [PATCH 1325/1635] msm: fastcvpd: Fix multiple function definition issue fastcvpd_video_suspend() is defined multiple times resulting in compilation error if fastcvpd.h is included. Fix the error by removing multiple definition in fastcvpd.h Change-Id: I187aa8c0e346bac855e0c7e1360f15aefc8d2016 Signed-off-by: Maheshwar Ajja --- include/linux/fastcvpd.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/fastcvpd.h b/include/linux/fastcvpd.h index 6c7fc529ca20..aa54baef4a2f 100644 --- a/include/linux/fastcvpd.h +++ b/include/linux/fastcvpd.h @@ -70,7 +70,7 @@ static inline int fastcvpd_video_send_cmd_hfi_queue( return -ENODEV; } -static inline int fastcvpd_video_suspend(uint32_t session_flag) +static inline int fastcvpd_video_shutdown(uint32_t session_flag) { return -ENODEV; } -- GitLab From 8239cf576da76c3b6f0656ba9fa4c84f0f4ce228 Mon Sep 17 00:00:00 2001 From: Maheshwar Ajja Date: Wed, 18 Apr 2018 18:49:16 -0700 Subject: [PATCH 1326/1635] msm: vidc: Add CVP interface api usage Video driver is expected to call below CVP apis when required to have CVP and Video functionality co-exist together - fastcvpd_video_send_cmd_hfi_queue() - fastcvpd_video_suspend() - fastcvpd_video_resume() - fastcvpd_video_shutdown() Change-Id: Ie7cdd68b1857619a7b52f9e8d2e971922860c9a9 Signed-off-by: Maheshwar Ajja --- drivers/media/platform/msm/vidc/msm_cvp.c | 59 ++++ drivers/media/platform/msm/vidc/msm_cvp.h | 2 + drivers/media/platform/msm/vidc/venus_hfi.c | 306 ++++++++++++++++-- drivers/media/platform/msm/vidc/venus_hfi.h | 6 + drivers/media/platform/msm/vidc/vidc_hfi.h | 5 + .../media/platform/msm/vidc/vidc_hfi_api.h | 2 + 6 files changed, 358 insertions(+), 22 deletions(-) diff --git a/drivers/media/platform/msm/vidc/msm_cvp.c b/drivers/media/platform/msm/vidc/msm_cvp.c index 8c41bac888a7..d1705b0c1af4 100644 --- a/drivers/media/platform/msm/vidc/msm_cvp.c +++ b/drivers/media/platform/msm/vidc/msm_cvp.c @@ -311,8 +311,29 @@ static int msm_cvp_request_power(struct msm_vidc_inst *inst, dprintk(VIDC_ERR, "%s: failed to scale clocks and bus for inst %pK (%#x)\n", __func__, inst, hash32_ptr(inst->session)); + goto exit; + } + + if (!inst->clk_data.min_freq && !inst->clk_data.ddr_bw && + !inst->clk_data.sys_cache_bw) { + rc = msm_cvp_inst_pause(inst); + if (rc) { + dprintk(VIDC_ERR, + "%s: failed to pause inst %pK (%#x)\n", + __func__, inst, hash32_ptr(inst->session)); + goto exit; + } + } else { + rc = msm_cvp_inst_resume(inst); + if (rc) { + dprintk(VIDC_ERR, + "%s: failed to resume inst %pK (%#x)\n", + __func__, inst, hash32_ptr(inst->session)); + goto exit; + } } +exit: return rc; } @@ -515,6 +536,44 @@ int msm_cvp_ctrl_init(struct msm_vidc_inst *inst, ARRAY_SIZE(msm_cvp_ctrls), ctrl_ops); } +int msm_cvp_inst_pause(struct msm_vidc_inst *inst) +{ + int rc; + struct hfi_device *hdev; + + if (!inst || !inst->core || !inst->core->device) { + dprintk(VIDC_ERR, "%s: invalid params\n", __func__); + return -EINVAL; + } + hdev = inst->core->device; + + rc = call_hfi_op(hdev, session_pause, (void *)inst->session); + if (rc) + dprintk(VIDC_ERR, "%s: failed to pause inst %pK (%#x)\n", + __func__, inst, hash32_ptr(inst->session)); + + return rc; +} + +int msm_cvp_inst_resume(struct msm_vidc_inst *inst) +{ + int rc; + struct hfi_device *hdev; + + if (!inst || !inst->core || !inst->core->device) { + dprintk(VIDC_ERR, "%s: invalid params\n", __func__); + return -EINVAL; + } + hdev = inst->core->device; + + rc = call_hfi_op(hdev, session_resume, (void *)inst->session); + if (rc) + dprintk(VIDC_ERR, "%s: failed to resume inst %pK (%#x)\n", + __func__, inst, hash32_ptr(inst->session)); + + return rc; +} + int msm_cvp_inst_deinit(struct msm_vidc_inst *inst) { int rc = 0; diff --git a/drivers/media/platform/msm/vidc/msm_cvp.h b/drivers/media/platform/msm/vidc/msm_cvp.h index ea6ae4196fb5..f8dc75f443db 100644 --- a/drivers/media/platform/msm/vidc/msm_cvp.h +++ b/drivers/media/platform/msm/vidc/msm_cvp.h @@ -26,6 +26,8 @@ void handle_session_unregister_buffer_done(enum hal_command_response cmd, int msm_vidc_cvp(struct msm_vidc_inst *inst, struct msm_vidc_arg *arg); int msm_cvp_inst_init(struct msm_vidc_inst *inst); int msm_cvp_inst_deinit(struct msm_vidc_inst *inst); +int msm_cvp_inst_pause(struct msm_vidc_inst *inst); +int msm_cvp_inst_resume(struct msm_vidc_inst *inst); int msm_cvp_ctrl_init(struct msm_vidc_inst *inst, const struct v4l2_ctrl_ops *ctrl_ops); #endif diff --git a/drivers/media/platform/msm/vidc/venus_hfi.c b/drivers/media/platform/msm/vidc/venus_hfi.c index 69ac5683070a..93c58eff4ea4 100644 --- a/drivers/media/platform/msm/vidc/venus_hfi.c +++ b/drivers/media/platform/msm/vidc/venus_hfi.c @@ -34,6 +34,7 @@ #include #include #include +#include #include "hfi_packetization.h" #include "msm_vidc_debug.h" #include "venus_hfi.h" @@ -104,6 +105,7 @@ static int __enable_subcaches(struct venus_hfi_device *device); static int __set_subcaches(struct venus_hfi_device *device); static int __release_subcaches(struct venus_hfi_device *device); static int __disable_subcaches(struct venus_hfi_device *device); +static int __power_collapse(struct venus_hfi_device *device, bool force); static int venus_hfi_noc_error_info(void *dev); /** @@ -252,6 +254,216 @@ static void __sim_modify_cmd_packet(u8 *packet, struct venus_hfi_device *device) } } +static int __dsp_send_hfi_queue(struct venus_hfi_device *device) +{ + int rc; + + if (!device->res->domain_cvp) + return 0; + + if (!device->dsp_iface_q_table.mem_data.dma_handle) { + dprintk(VIDC_ERR, "%s: invalid dsm_handle\n", __func__); + return -EINVAL; + } + + if (device->dsp_flags & DSP_INIT) { + dprintk(VIDC_DBG, "%s: dsp already inited\n"); + return 0; + } + + dprintk(VIDC_DBG, "%s: hfi queue %#x size %d\n", + __func__, device->dsp_iface_q_table.mem_data.dma_handle, + device->dsp_iface_q_table.mem_data.size); + rc = fastcvpd_video_send_cmd_hfi_queue( + (phys_addr_t *)device->dsp_iface_q_table.mem_data.dma_handle, + device->dsp_iface_q_table.mem_data.size); + if (rc) { + dprintk(VIDC_ERR, "%s: dsp init failed\n", __func__); + return rc; + } + + device->dsp_flags |= DSP_INIT; + dprintk(VIDC_DBG, "%s: dsp inited\n", __func__); + return rc; +} + +static int __dsp_suspend(struct venus_hfi_device *device, bool force, u32 flags) +{ + int rc; + struct hal_session *temp; + + if (!device->res->domain_cvp) + return 0; + + if (!(device->dsp_flags & DSP_INIT)) + return 0; + + if (device->dsp_flags & DSP_SUSPEND) + return 0; + + list_for_each_entry(temp, &device->sess_head, list) { + /* if forceful suspend, don't check session pause info */ + if (force) + continue; + if (temp->domain == HAL_VIDEO_DOMAIN_CVP) { + /* don't suspend if cvp session is not paused */ + if (!(temp->flags & SESSION_PAUSE)) { + dprintk(VIDC_DBG, + "%s: cvp session %x not paused\n", + __func__, hash32_ptr(temp)); + return -EBUSY; + } + } + } + + dprintk(VIDC_DBG, "%s: suspend dsp\n", __func__); + rc = fastcvpd_video_suspend(flags); + if (rc) { + dprintk(VIDC_ERR, "%s: dsp suspend failed with error %d\n", + __func__, rc); + return -EINVAL; + } + + device->dsp_flags |= DSP_SUSPEND; + dprintk(VIDC_DBG, "%s: dsp suspended\n", __func__); + return 0; +} + +static int __dsp_resume(struct venus_hfi_device *device, u32 flags) +{ + int rc; + + if (!device->res->domain_cvp) + return 0; + + if (!(device->dsp_flags & DSP_SUSPEND)) { + dprintk(VIDC_DBG, "%s: dsp not suspended\n", __func__); + return 0; + } + + dprintk(VIDC_DBG, "%s: resume dsp\n", __func__); + rc = fastcvpd_video_resume(flags); + if (rc) { + dprintk(VIDC_ERR, + "%s: dsp resume failed with error %d\n", + __func__, rc); + return rc; + } + + device->dsp_flags &= ~DSP_SUSPEND; + dprintk(VIDC_DBG, "%s: dsp resumed\n", __func__); + return rc; +} + +static int __dsp_shutdown(struct venus_hfi_device *device, u32 flags) +{ + int rc; + + if (!device->res->domain_cvp) + return 0; + + if (!(device->dsp_flags & DSP_INIT)) { + dprintk(VIDC_DBG, "%s: dsp not inited\n", __func__); + return 0; + } + + dprintk(VIDC_DBG, "%s: shutdown dsp\n", __func__); + rc = fastcvpd_video_shutdown(flags); + if (rc) { + dprintk(VIDC_ERR, + "%s: dsp shutdown failed with error %d\n", + __func__, rc); + WARN_ON(1); + } + + device->dsp_flags &= ~DSP_INIT; + dprintk(VIDC_DBG, "%s: dsp shutdown successful\n", __func__); + return rc; +} + +static int __session_pause(struct venus_hfi_device *device, + struct hal_session *session) +{ + int rc = 0; + + /* ignore if session paused already */ + if (session->flags & SESSION_PAUSE) + return 0; + + session->flags |= SESSION_PAUSE; + dprintk(VIDC_DBG, "%s: cvp session %x paused\n", __func__, + hash32_ptr(session)); + + return rc; +} + +static int __session_resume(struct venus_hfi_device *device, + struct hal_session *session) +{ + int rc = 0; + + /* ignore if session already resumed */ + if (!(session->flags & SESSION_PAUSE)) + return 0; + + session->flags &= ~SESSION_PAUSE; + dprintk(VIDC_DBG, "%s: cvp session %x resumed\n", __func__, + hash32_ptr(session)); + + rc = __resume(device); + if (rc) { + dprintk(VIDC_ERR, "%s: resume failed\n", __func__); + goto exit; + } + + if (device->dsp_flags & DSP_SUSPEND) { + dprintk(VIDC_ERR, "%s: dsp not resumed\n", __func__); + rc = -EINVAL; + goto exit; + } + +exit: + return rc; +} + +static int venus_hfi_session_pause(void *sess) +{ + int rc; + struct hal_session *session = sess; + struct venus_hfi_device *device; + + if (!session || !session->device) { + dprintk(VIDC_ERR, "%s: invalid params\n", __func__); + return -EINVAL; + } + device = session->device; + + mutex_lock(&device->lock); + rc = __session_pause(device, session); + mutex_unlock(&device->lock); + + return rc; +} + +static int venus_hfi_session_resume(void *sess) +{ + int rc; + struct hal_session *session = sess; + struct venus_hfi_device *device; + + if (!session || !session->device) { + dprintk(VIDC_ERR, "%s: invalid params\n", __func__); + return -EINVAL; + } + device = session->device; + + mutex_lock(&device->lock); + rc = __session_resume(device, session); + mutex_unlock(&device->lock); + + return rc; +} + static int __acquire_regulator(struct regulator_info *rinfo, struct venus_hfi_device *device) { @@ -1098,14 +1310,18 @@ static int venus_hfi_suspend(void *dev) } dprintk(VIDC_DBG, "Suspending Venus\n"); - flush_delayed_work(&venus_hfi_pm_work); - mutex_lock(&device->lock); - if (device->power_enabled) { + rc = __power_collapse(device, true); + if (rc) { dprintk(VIDC_WARN, "%s: Venus is busy\n", __func__); rc = -EBUSY; } mutex_unlock(&device->lock); + + /* Cancel pending delayed works if any */ + if (!rc) + cancel_delayed_work(&venus_hfi_pm_work); + return rc; } @@ -1957,6 +2173,7 @@ static int venus_hfi_core_init(void *device) __enable_subcaches(device); __set_subcaches(device); + __dsp_send_hfi_queue(device); if (dev->res->pm_qos_latency_us) { #ifdef CONFIG_SMP @@ -1998,6 +2215,8 @@ static int venus_hfi_core_release(void *dev) __resume(device); __set_state(device, VENUS_STATE_DEINIT); + __dsp_shutdown(device, 0); + __unload_fw(device); /* unlink all sessions from device */ @@ -2988,9 +3207,6 @@ static int __prepare_pc(struct venus_hfi_device *device) static void venus_hfi_pm_handler(struct work_struct *work) { int rc = 0; - u32 wfi_status = 0, idle_status = 0, pc_ready = 0; - int count = 0; - const int max_tries = 10; struct venus_hfi_device *device = list_first_entry( &hal_ctxt.dev_head, struct venus_hfi_device, list); @@ -3012,7 +3228,51 @@ static void venus_hfi_pm_handler(struct work_struct *work) __process_fatal_error(device); return; } + mutex_lock(&device->lock); + rc = __power_collapse(device, false); + mutex_unlock(&device->lock); + switch (rc) { + case 0: + device->skip_pc_count = 0; + /* Cancel pending delayed works if any */ + cancel_delayed_work(&venus_hfi_pm_work); + dprintk(VIDC_PROF, "%s: power collapse successful!\n", + __func__); + break; + case -EBUSY: + device->skip_pc_count = 0; + dprintk(VIDC_DBG, "%s: retry PC as dsp is busy\n", __func__); + queue_delayed_work(device->venus_pm_workq, + &venus_hfi_pm_work, msecs_to_jiffies( + device->res->msm_vidc_pwr_collapse_delay)); + break; + case -EAGAIN: + device->skip_pc_count++; + dprintk(VIDC_WARN, "%s: retry power collapse (count %d)\n", + __func__, device->skip_pc_count); + queue_delayed_work(device->venus_pm_workq, + &venus_hfi_pm_work, msecs_to_jiffies( + device->res->msm_vidc_pwr_collapse_delay)); + break; + default: + dprintk(VIDC_ERR, "%s: power collapse failed\n", __func__); + break; + } +} + +static int __power_collapse(struct venus_hfi_device *device, bool force) +{ + int rc = 0; + u32 wfi_status = 0, idle_status = 0, pc_ready = 0; + u32 flags = 0; + int count = 0; + const int max_tries = 10; + + if (!device) { + dprintk(VIDC_ERR, "%s: invalid params\n", __func__); + return -EINVAL; + } if (!device->power_enabled) { dprintk(VIDC_DBG, "%s: Power already disabled\n", __func__); @@ -3023,8 +3283,15 @@ static void venus_hfi_pm_handler(struct work_struct *work) if (!rc) { dprintk(VIDC_WARN, "Core is in bad state, Skipping power collapse\n"); - goto skip_power_off; + return -EINVAL; } + + rc = __dsp_suspend(device, force, flags); + if (rc == -EBUSY) + goto exit; + else if (rc) + goto skip_power_off; + pc_ready = __read_register(device, VIDC_CTRL_STATUS) & VIDC_CTRL_STATUS_PC_READY; if (!pc_ready) { @@ -3077,23 +3344,14 @@ static void venus_hfi_pm_handler(struct work_struct *work) if (rc) dprintk(VIDC_ERR, "Failed __suspend\n"); - /* Cancel pending delayed works if any */ - cancel_delayed_work(&venus_hfi_pm_work); - device->skip_pc_count = 0; - - mutex_unlock(&device->lock); - return; +exit: + return rc; skip_power_off: - device->skip_pc_count++; - dprintk(VIDC_WARN, "Skip PC(%d, %#x, %#x, %#x)\n", - device->skip_pc_count, wfi_status, idle_status, pc_ready); - queue_delayed_work(device->venus_pm_workq, - &venus_hfi_pm_work, - msecs_to_jiffies( - device->res->msm_vidc_pwr_collapse_delay)); -exit: - mutex_unlock(&device->lock); + dprintk(VIDC_WARN, "Skip PC(%#x, %#x, %#x)\n", + wfi_status, idle_status, pc_ready); + + return -EAGAIN; } static void __process_sys_error(struct venus_hfi_device *device) @@ -4420,6 +4678,7 @@ static inline int __suspend(struct venus_hfi_device *device) static inline int __resume(struct venus_hfi_device *device) { int rc = 0; + u32 flags = 0; if (!device) { dprintk(VIDC_ERR, "Invalid params: %pK\n", device); @@ -4472,6 +4731,7 @@ static inline int __resume(struct venus_hfi_device *device) __enable_subcaches(device); __set_subcaches(device); + __dsp_resume(device, flags); dprintk(VIDC_PROF, "Resumed from power collapse\n"); exit: @@ -4890,6 +5150,8 @@ static void venus_init_hfi_callbacks(struct hfi_device *hdev) hdev->session_flush = venus_hfi_session_flush; hdev->session_set_property = venus_hfi_session_set_property; hdev->session_get_property = venus_hfi_session_get_property; + hdev->session_pause = venus_hfi_session_pause; + hdev->session_resume = venus_hfi_session_resume; hdev->scale_clocks = venus_hfi_scale_clocks; hdev->vote_bus = venus_hfi_vote_buses; hdev->get_fw_info = venus_hfi_get_fw_info; diff --git a/drivers/media/platform/msm/vidc/venus_hfi.h b/drivers/media/platform/msm/vidc/venus_hfi.h index 6993a2aaf8bd..ef9e2ec59320 100644 --- a/drivers/media/platform/msm/vidc/venus_hfi.h +++ b/drivers/media/platform/msm/vidc/venus_hfi.h @@ -220,6 +220,11 @@ struct venus_resources { struct msm_vidc_fw fw; }; +enum dsp_flag { + DSP_INIT = BIT(0), + DSP_SUSPEND = BIT(1), +}; + enum venus_hfi_state { VENUS_STATE_DEINIT = 1, VENUS_STATE_INIT, @@ -245,6 +250,7 @@ struct venus_hfi_device { struct vidc_mem_addr mem_addr; struct vidc_iface_q_info iface_queues[VIDC_IFACEQ_NUMQ]; struct vidc_iface_q_info dsp_iface_queues[VIDC_IFACEQ_NUMQ]; + u32 dsp_flags; struct hal_data *hal_data; struct workqueue_struct *vidc_workq; struct workqueue_struct *venus_pm_workq; diff --git a/drivers/media/platform/msm/vidc/vidc_hfi.h b/drivers/media/platform/msm/vidc/vidc_hfi.h index e953a0983995..b8e86b5ce07e 100644 --- a/drivers/media/platform/msm/vidc/vidc_hfi.h +++ b/drivers/media/platform/msm/vidc/vidc_hfi.h @@ -829,12 +829,17 @@ struct hfi_cmd_session_continue_packet { u32 session_id; }; +enum session_flags { + SESSION_PAUSE = BIT(1), +}; + struct hal_session { struct list_head list; void *session_id; bool is_decoder; enum hal_video_codec codec; enum hal_domain domain; + u32 flags; void *device; }; diff --git a/drivers/media/platform/msm/vidc/vidc_hfi_api.h b/drivers/media/platform/msm/vidc/vidc_hfi_api.h index 5fd1c9092f25..2a9cab047ff2 100644 --- a/drivers/media/platform/msm/vidc/vidc_hfi_api.h +++ b/drivers/media/platform/msm/vidc/vidc_hfi_api.h @@ -1444,6 +1444,8 @@ struct hfi_device { int (*session_set_property)(void *sess, enum hal_property ptype, void *pdata); int (*session_get_property)(void *sess, enum hal_property ptype); + int (*session_pause)(void *sess); + int (*session_resume)(void *sess); int (*scale_clocks)(void *dev, u32 freq); int (*vote_bus)(void *dev, struct vidc_bus_vote_data *data, int num_data); -- GitLab From 2bff4f60c9e4e5395b7a9d3ad513938e1167ef55 Mon Sep 17 00:00:00 2001 From: Urvashi Agrawal Date: Mon, 2 Apr 2018 16:45:30 -0700 Subject: [PATCH 1327/1635] ARM: dts: msm: Add GPU properties for sdmshrike Add device-specific GPU properties for sdmshrike. Add GMU clocks, registers, interrupts, bus, freq plan, SMMU properties, and GPU power levels. Change-Id: I52d7dfa0e0e7898ef40de8c02024851f8b992429 Signed-off-by: Urvashi Agrawal --- arch/arm64/boot/dts/qcom/sdmshrike-gpu.dtsi | 393 ++++++++++++++++++++ arch/arm64/boot/dts/qcom/sdmshrike.dtsi | 1 + 2 files changed, 394 insertions(+) create mode 100644 arch/arm64/boot/dts/qcom/sdmshrike-gpu.dtsi diff --git a/arch/arm64/boot/dts/qcom/sdmshrike-gpu.dtsi b/arch/arm64/boot/dts/qcom/sdmshrike-gpu.dtsi new file mode 100644 index 000000000000..76a1e5379fc6 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdmshrike-gpu.dtsi @@ -0,0 +1,393 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +&soc { + pil_gpu: qcom,kgsl-hyp { + compatible = "qcom,pil-tz-generic"; + qcom,pas-id = <13>; + qcom,firmware-name = "a640_zap"; + }; + + msm_bus: qcom,kgsl-busmon{ + label = "kgsl-busmon"; + compatible = "qcom,kgsl-busmon"; + }; + + gpubw: qcom,gpubw { + compatible = "qcom,devbw"; + governor = "bw_vbif"; + qcom,src-dst-ports = <26 512>; + qcom,bw-tbl = + < 0 /* off */ >, + < 381 /* 100 MHz */ >, + < 572 /* 150 MHz */ >, + < 762 /* 200 MHz */ >, + < 1144 /* 300 MHz */ >, + < 1571 /* 412 MHz */ >, + < 2086 /* 547 MHz */ >, + < 2597 /* 681 MHz */ >, + < 2929 /* 768 MHz */ >, + < 3879 /* 1017 MHz */ >, + < 4943 /* 1296 MHz */ >, + < 5931 /* 1555 MHz */ >, + < 6881 /* 1804 MHz */ >; + }; + + gpu_opp_table: gpu-opp-table { + compatible = "operating-points-v2"; + + opp-514000000 { + opp-hz = /bits/ 64 <514000000>; + opp-microvolt = ; + }; + + opp-500000000 { + opp-hz = /bits/ 64 <500000000>; + opp-microvolt = ; + }; + + opp-461000000 { + opp-hz = /bits/ 64 <461000000>; + opp-microvolt = ; + }; + + opp-405000000 { + opp-hz = /bits/ 64 <405000000>; + opp-microvolt = ; + }; + + opp-315000000 { + opp-hz = /bits/ 64 <315000000>; + opp-microvolt = ; + }; + + opp-256000000 { + opp-hz = /bits/ 64 <256000000>; + opp-microvolt = ; + }; + + opp-177000000 { + opp-hz = /bits/ 64 <177000000>; + opp-microvolt = ; + }; + }; + + msm_gpu: qcom,kgsl-3d0@2c00000 { + label = "kgsl-3d0"; + compatible = "qcom,kgsl-3d0", "qcom,kgsl-3d"; + status = "ok"; + reg = <0x2c00000 0x40000>; + reg-names = "kgsl_3d0_reg_memory"; + interrupts = <0 300 0>; + interrupt-names = "kgsl_3d0_irq"; + qcom,id = <0>; + + qcom,chipid = <0x6080000>; + + qcom,initial-pwrlevel = <5>; + + qcom,idle-timeout = <80>; /* msecs */ + qcom,no-nap; + + qcom,highest-bank-bit = <16>; + + qcom,min-access-length = <32>; + + qcom,ubwc-mode = <3>; + + qcom,snapshot-size = <1048576>; /* bytes */ + + qcom,gpu-qdss-stm = <0x161c0000 0x40000>; /* base addr, size */ + + qcom,tsens-name = "tsens_tz_sensor12"; + #cooling-cells = <2>; + + qcom,pm-qos-active-latency = <460>; + + clocks = <&clock_gpucc GPU_CC_CXO_CLK>, + <&clock_gcc GCC_DDRSS_GPU_AXI_CLK>, + <&clock_gcc GCC_GPU_MEMNOC_GFX_CLK>, + <&clock_gpucc GPU_CC_CX_GMU_CLK>, + <&clock_gpucc GPU_CC_AHB_CLK>; + + clock-names = "rbbmtimer_clk", "mem_clk", + "mem_iface_clk", "gmu_clk", + "gpu_cc_ahb"; + + qcom,isense-clk-on-level = <1>; + + /* Bus Scale Settings */ + qcom,gpubw-dev = <&gpubw>; + qcom,bus-control; + qcom,msm-bus,name = "grp3d"; + qcom,bus-width = <32>; + qcom,msm-bus,num-cases = <13>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <26 512 0 0>, + <26 512 0 400000>, /* 1 bus=100 */ + <26 512 0 600000>, /* 2 bus=150 */ + <26 512 0 800000>, /* 3 bus=200 */ + <26 512 0 1200000>, /* 4 bus=300 */ + <26 512 0 1648000>, /* 5 bus=412 */ + <26 512 0 2188000>, /* 6 bus=547 */ + <26 512 0 2724000>, /* 7 bus=681 */ + <26 512 0 3072000>, /* 8 bus=768 */ + <26 512 0 4068000>, /* 9 bus=1017 */ + <26 512 0 5184000>, /* 10 bus=1296 */ + <26 512 0 6220000>, /* 11 bus=1555 */ + <26 512 0 7216000>; /* 12 bus=1804 */ + + /* GDSC regulator names */ + regulator-names = "vddcx", "vdd"; + /* GDSC oxili regulators */ + vddcx-supply = <&gpu_cx_gdsc>; + vdd-supply = <&gpu_gx_gdsc>; + + /* GPU OPP data */ + operating-points-v2 = <&gpu_opp_table>; + + /* GPU related llc slices */ + cache-slice-names = "gpu", "gpuhtw"; + cache-slices = <&llcc 12>, <&llcc 11>; + + /* GPU Mempools */ + qcom,gpu-mempools { + #address-cells = <1>; + #size-cells = <0>; + compatible = "qcom,gpu-mempools"; + + /* 4K Page Pool configuration */ + qcom,gpu-mempool@0 { + reg = <0>; + qcom,mempool-page-size = <4096>; + qcom,mempool-reserved = <2048>; + qcom,mempool-allocate; + }; + /* 8K Page Pool configuration */ + qcom,gpu-mempool@1 { + reg = <1>; + qcom,mempool-page-size = <8192>; + qcom,mempool-reserved = <1024>; + qcom,mempool-allocate; + }; + /* 64K Page Pool configuration */ + qcom,gpu-mempool@2 { + reg = <2>; + qcom,mempool-page-size = <65536>; + qcom,mempool-reserved = <256>; + }; + /* 1M Page Pool configuration */ + qcom,gpu-mempool@3 { + reg = <3>; + qcom,mempool-page-size = <1048576>; + qcom,mempool-reserved = <32>; + }; + }; + + /* Power levels */ + qcom,gpu-pwrlevels { + #address-cells = <1>; + #size-cells = <0>; + + compatible = "qcom,gpu-pwrlevels"; + + qcom,gpu-pwrlevel@0 { + reg = <0>; + qcom,gpu-freq = <514000000>; + qcom,bus-freq = <12>; + qcom,bus-min = <11>; + qcom,bus-max = <12>; + }; + + qcom,gpu-pwrlevel@1 { + reg = <1>; + qcom,gpu-freq = <500000000>; + qcom,bus-freq = <12>; + qcom,bus-min = <10>; + qcom,bus-max = <12>; + }; + + qcom,gpu-pwrlevel@2 { + reg = <2>; + qcom,gpu-freq = <461000000>; + qcom,bus-freq = <10>; + qcom,bus-min = <9>; + qcom,bus-max = <11>; + }; + + qcom,gpu-pwrlevel@3 { + reg = <3>; + qcom,gpu-freq = <405000000>; + qcom,bus-freq = <9>; + qcom,bus-min = <8>; + qcom,bus-max = <10>; + }; + + qcom,gpu-pwrlevel@4 { + reg = <4>; + qcom,gpu-freq = <315000000>; + qcom,bus-freq = <8>; + qcom,bus-min = <7>; + qcom,bus-max = <9>; + }; + + qcom,gpu-pwrlevel@5 { + reg = <5>; + qcom,gpu-freq = <256000000>; + qcom,bus-freq = <5>; + qcom,bus-min = <5>; + qcom,bus-max = <7>; + }; + + qcom,gpu-pwrlevel@6 { + reg = <6>; + qcom,gpu-freq = <177000000>; + qcom,bus-freq = <4>; + qcom,bus-min = <3>; + qcom,bus-max = <5>; + }; + + qcom,gpu-pwrlevel@7 { + reg = <7>; + qcom,gpu-freq = <0>; + qcom,bus-freq = <0>; + qcom,bus-min = <0>; + qcom,bus-max = <0>; + }; + }; + }; + + kgsl_msm_iommu: qcom,kgsl-iommu@2ca0000 { + compatible = "qcom,kgsl-smmu-v2"; + + reg = <0x2ca0000 0x10000>; + /* CB5(ATOS) & CB5/6/7 are protected by HYP */ + qcom,protect = <0x40000 0xc000>; + qcom,micro-mmu-control = <0x6000>; + + clocks =<&clock_gcc GCC_GPU_CFG_AHB_CLK>, + <&clock_gcc GCC_DDRSS_GPU_AXI_CLK>, + <&clock_gcc GCC_GPU_MEMNOC_GFX_CLK>; + + clock-names = "iface_clk", "mem_clk", "mem_iface_clk"; + + qcom,secure_align_mask = <0xfff>; + qcom,global_pt; + qcom,retention; + qcom,hyp_secure_alloc; + + gfx3d_user: gfx3d_user { + compatible = "qcom,smmu-kgsl-cb"; + label = "gfx3d_user"; + iommus = <&kgsl_smmu 0x0 0xC01>; + qcom,gpu-offset = <0x48000>; + }; + + gfx3d_secure: gfx3d_secure { + compatible = "qcom,smmu-kgsl-cb"; + label = "gfx3d_secure"; + iommus = <&kgsl_smmu 0x2 0xC00>; + }; + }; + + gmu_opp_table: gmu-opp-table { + compatible = "operating-points-v2"; + + opp-200000000 { + opp-hz = /bits/ 64 <200000000>; + opp-microvolt = ; + }; + + opp-400000000 { + opp-hz = /bits/ 64 <400000000>; + opp-microvolt = ; + }; + + opp-500000000 { + opp-hz = /bits/ 64 <500000000>; + opp-microvolt = ; + }; + }; + + gmu: qcom,gmu@2c6a000 { + label = "kgsl-gmu"; + compatible = "qcom,gpu-gmu"; + + reg = <0x2c6a000 0x30000>, <0xb200000 0x300000>; + reg-names = "kgsl_gmu_reg", "kgsl_gmu_pdc_reg"; + + interrupts = <0 304 0>, <0 305 0>; + interrupt-names = "kgsl_hfi_irq", "kgsl_gmu_irq"; + + qcom,msm-bus,name = "cnoc"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <26 10036 0 0>, /* CNOC off */ + <26 10036 0 100>; /* CNOC on */ + + regulator-names = "vddcx", "vdd"; + vddcx-supply = <&gpu_cx_gdsc>; + vdd-supply = <&gpu_gx_gdsc>; + + /* GMU OPP data */ + operating-points-v2 = <&gmu_opp_table>; + + clocks = <&clock_gpucc GPU_CC_CX_GMU_CLK>, + <&clock_gpucc GPU_CC_CXO_CLK>, + <&clock_gcc GCC_DDRSS_GPU_AXI_CLK>, + <&clock_gcc GCC_GPU_MEMNOC_GFX_CLK>, + <&clock_gpucc GPU_CC_AHB_CLK>; + + clock-names = "gmu_clk", "cxo_clk", "axi_clk", + "memnoc_clk", "gpu_cc_ahb"; + + qcom,gmu-pwrlevels { + #address-cells = <1>; + #size-cells = <0>; + + compatible = "qcom,gmu-pwrlevels"; + + /* GMU power levels must go from lowest to highest */ + qcom,gmu-pwrlevel@0 { + reg = <0>; + qcom,gmu-freq = <0>; + }; + + qcom,gmu-pwrlevel@1 { + reg = <1>; + qcom,gmu-freq = <200000000>; + }; + + qcom,gmu-pwrlevel@2 { + reg = <2>; + qcom,gmu-freq = <400000000>; + }; + + qcom,gmu-pwrlevel@3 { + reg = <3>; + qcom,gmu-freq = <500000000>; + }; + }; + + gmu_user: gmu_user { + compatible = "qcom,smmu-gmu-user-cb"; + iommus = <&kgsl_smmu 0x4 0xC00>; + }; + + gmu_kernel: gmu_kernel { + compatible = "qcom,smmu-gmu-kernel-cb"; + iommus = <&kgsl_smmu 0x5 0xC00>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/sdmshrike.dtsi b/arch/arm64/boot/dts/qcom/sdmshrike.dtsi index 2e35b7e9a29d..f1c368db35c1 100644 --- a/arch/arm64/boot/dts/qcom/sdmshrike.dtsi +++ b/arch/arm64/boot/dts/qcom/sdmshrike.dtsi @@ -1485,3 +1485,4 @@ #include "sdmshrike-usb.dtsi" #include "sdmshrike-qupv3.dtsi" #include "sm8150-audio.dtsi" +#include "sdmshrike-gpu.dtsi" -- GitLab From 89387fa1796c16fdd41bc82396a64fcdc70e238c Mon Sep 17 00:00:00 2001 From: Shivendra Kakrania Date: Tue, 1 May 2018 14:06:12 -0700 Subject: [PATCH 1328/1635] msm: vidc: Updating video llc bw calculation for sm8150 Fixed an issue in video llc bw calculation which was leading to max llc bw votes. Change-Id: I5cffa00b196b7769e2dd39560f4b4bc47d4d50b3 CRs-Fixed: 2201248 Signed-off-by: Shivendra Kakrania --- .../media/platform/msm/vidc/governors/msm_vidc_dyn_gov.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/media/platform/msm/vidc/governors/msm_vidc_dyn_gov.c b/drivers/media/platform/msm/vidc/governors/msm_vidc_dyn_gov.c index d0601e1cdfdd..5dbed452206c 100644 --- a/drivers/media/platform/msm/vidc/governors/msm_vidc_dyn_gov.c +++ b/drivers/media/platform/msm/vidc/governors/msm_vidc_dyn_gov.c @@ -489,8 +489,8 @@ static unsigned long __calculate_decoder(struct vidc_bus_vote_data *d, if (llc_ref_read_l2_cache_enabled) { ddr.dpb_read = fp_div(ddr.dpb_read, - d->codec == HAL_VIDEO_CODEC_H264 ? FP(0, 15, 100) : - FP(0, 30, 100)); + d->codec == HAL_VIDEO_CODEC_H264 ? FP(1, 15, 100) : + FP(1, 30, 100)); llc.dpb_read = dpb_total - ddr.dpb_read; } @@ -570,7 +570,8 @@ static unsigned long __calculate_decoder(struct vidc_bus_vote_data *d, {"opb read", DUMP_FP_FMT, ddr.opb_read}, {"opb write", DUMP_FP_FMT, ddr.opb_write}, {"dpb read", DUMP_FP_FMT, ddr.dpb_read}, - {"dbb write", DUMP_FP_FMT, ddr.dpb_write}, + {"dpb write", DUMP_FP_FMT, ddr.dpb_write}, + {"dpb total", DUMP_FP_FMT, dpb_total}, {"INTERMEDIATE LLC B/W", "", DUMP_HEADER_MAGIC}, {"llc dpb read", DUMP_FP_FMT, llc.dpb_read}, {"llc line buffer read", DUMP_FP_FMT, llc.line_buffer_read}, @@ -834,6 +835,8 @@ static unsigned long __calculate_encoder(struct vidc_bus_vote_data *d, mese_read_factor}, {"qsmmu_bw_overhead_factor", DUMP_FP_FMT, qsmmu_bw_overhead_factor}, + {"bw for NV12 8bpc)", DUMP_FP_FMT, y_bw_no_ubwc_8bpp}, + {"bw for NV12 10bpc)", DUMP_FP_FMT, y_bw_no_ubwc_10bpp}, {"INTERMEDIATE B/W DDR", "", DUMP_HEADER_MAGIC}, {"vsp read", DUMP_FP_FMT, ddr.vsp_read}, -- GitLab From 6499baf92d1a325e52856ee2e4c378a261df2f65 Mon Sep 17 00:00:00 2001 From: Matt Wagantall Date: Fri, 20 Mar 2015 12:54:57 -0700 Subject: [PATCH 1329/1635] exit: Add PANIC_ON_RECURSIVE_FAULT Kconfig option If a recursive fault is detected during do_exit(), tasks are left to sit and wait in an un-interruptible sleep until the system reboots (typically manually). Add Kconfig option to change this behaviour and force a panic. This is particularly important if a critical system task encounters a recursive fault (ex. a kworker). Otherwise, the system may be unusable, but since the scheduler is still running system watchdogs may continue to be pet. Change-Id: Ifc26fc79d6066f05a3b2c4d27f78bf4f8d2bd640 Signed-off-by: Matt Wagantall --- kernel/exit.c | 4 ++++ lib/Kconfig.debug | 11 +++++++++++ 2 files changed, 15 insertions(+) diff --git a/kernel/exit.c b/kernel/exit.c index b60a21b18b16..129005ce76ae 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -797,7 +797,11 @@ void __noreturn do_exit(long code) * leave this task alone and wait for reboot. */ if (unlikely(tsk->flags & PF_EXITING)) { +#ifdef CONFIG_PANIC_ON_RECURSIVE_FAULT + panic("Recursive fault!\n"); +#else pr_alert("Fixing recursive fault but reboot is needed!\n"); +#endif /* * We can do this unlocked here. The futex code uses * this flag just to verify whether the pi state diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index 04f0880a5fd1..74506964a517 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -879,6 +879,17 @@ config BOOTPARAM_SOFTLOCKUP_PANIC_VALUE default 0 if !BOOTPARAM_SOFTLOCKUP_PANIC default 1 if BOOTPARAM_SOFTLOCKUP_PANIC +config PANIC_ON_RECURSIVE_FAULT + bool "Panic on recursive faults during task exit" + help + Panic upon the detection of a recursive fault during task exit, + rather than putting the task into an uninterruptible sleep. + This is particularly useful for debugging system hangs in + scenarios where the task experiencing the fault is critical + for system operation, rendering the system inoperable. + + Say N if unsure. + config DETECT_HUNG_TASK bool "Detect Hung Tasks" depends on DEBUG_KERNEL -- GitLab From e12d7388ab276d980b7d990d9862bf65ef4f90a0 Mon Sep 17 00:00:00 2001 From: Steve Cohen Date: Thu, 26 Apr 2018 15:28:56 -0400 Subject: [PATCH 1330/1635] drm/msm/sde: remove duplicate event log in video vblank irq Remove an eventlog containing information that has already been recorded during the video mode physical encoder vblank irq. Change-Id: Ie4a75aac8af8ea609ecf24feccce70c6113a727c Signed-off-by: Steve Cohen --- drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c b/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c index 514c3a72ede4..8d6787fb90f4 100644 --- a/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c +++ b/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c @@ -475,8 +475,6 @@ static void sde_encoder_phys_vid_vblank_irq(void *arg, int irq_idx) SDE_EVT32_IRQ(DRMID(phys_enc->parent), phys_enc->hw_intf->idx - INTF_0, old_cnt, new_cnt, reset_status ? SDE_EVTLOG_ERROR : 0, flush_register, event); - SDE_EVT32_IRQ(DRMID(phys_enc->parent), phys_enc->hw_intf->idx - INTF_0, - old_cnt, new_cnt, flush_register, event); /* Signal any waiting atomic commit thread */ wake_up_all(&phys_enc->pending_kickoff_wq); -- GitLab From c31cc95196a401a6b01b0e866951dc091585bb94 Mon Sep 17 00:00:00 2001 From: Vaibhav Deshu Venkatesh Date: Tue, 1 May 2018 14:42:09 -0700 Subject: [PATCH 1331/1635] msm: vidc: Remove prints while handling interrupts We have a lot of unnecessary prints while handling interrupts. Remove the ones which are not needed. CRs-Fixed: 2234389 Change-Id: I3605f13c0370da27913144611c8b95fe084144b1 Signed-off-by: Vaibhav Deshu Venkatesh --- drivers/media/platform/msm/vidc/venus_hfi.c | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/drivers/media/platform/msm/vidc/venus_hfi.c b/drivers/media/platform/msm/vidc/venus_hfi.c index 69ac5683070a..c0e7244847df 100644 --- a/drivers/media/platform/msm/vidc/venus_hfi.c +++ b/drivers/media/platform/msm/vidc/venus_hfi.c @@ -2040,7 +2040,7 @@ static int __get_q_size(struct venus_hfi_device *dev, unsigned int q_index) static void __core_clear_interrupt(struct venus_hfi_device *device) { - u32 intr_status = 0; + u32 intr_status = 0, mask = 0; if (!device) { dprintk(VIDC_ERR, "%s: NULL device\n", __func__); @@ -2048,10 +2048,11 @@ static void __core_clear_interrupt(struct venus_hfi_device *device) } intr_status = __read_register(device, VIDC_WRAPPER_INTR_STATUS); + mask = (VIDC_WRAPPER_INTR_STATUS_A2H_BMSK | + VIDC_WRAPPER_INTR_STATUS_A2HWD_BMSK | + VIDC_CTRL_INIT_IDLE_MSG_BMSK); - if (intr_status & VIDC_WRAPPER_INTR_STATUS_A2H_BMSK || - intr_status & VIDC_WRAPPER_INTR_STATUS_A2HWD_BMSK || - intr_status & VIDC_CTRL_INIT_IDLE_MSG_BMSK) { + if (intr_status & mask) { device->intr_status |= intr_status; device->reg_count++; dprintk(VIDC_DBG, @@ -2059,9 +2060,6 @@ static void __core_clear_interrupt(struct venus_hfi_device *device) device, device->reg_count, intr_status); } else { device->spur_count++; - dprintk(VIDC_INFO, - "SPURIOUS_INTR for device: %pK: times: %d interrupt_status: %d\n", - device, device->spur_count, intr_status); } __write_register(device, VIDC_CPU_CS_A2HSOFTINTCLR, 1); @@ -3392,7 +3390,6 @@ static void venus_hfi_core_work_handler(struct work_struct *work) mutex_lock(&device->lock); - dprintk(VIDC_DBG, "Handling interrupt\n"); if (!__core_in_valid_state(device)) { dprintk(VIDC_DBG, "%s - Core not in init state\n", __func__); @@ -3437,7 +3434,6 @@ static void venus_hfi_core_work_handler(struct work_struct *work) if (!(intr_status & VIDC_WRAPPER_INTR_STATUS_A2HWD_BMSK)) enable_irq(device->hal_data->irq); - dprintk(VIDC_DBG, "Handling interrupt done\n"); /* * XXX: Don't add any code beyond here. Reacquiring locks after release * it above doesn't guarantee the atomicity that we're aiming for. @@ -3450,7 +3446,6 @@ static irqreturn_t venus_hfi_isr(int irq, void *dev) { struct venus_hfi_device *device = dev; - dprintk(VIDC_INFO, "Received an interrupt %d\n", irq); disable_irq_nosync(irq); queue_work(device->vidc_workq, &venus_hfi_work); return IRQ_HANDLED; -- GitLab From 351a136b2b8ddc591ca916d24b01fee92eb511a5 Mon Sep 17 00:00:00 2001 From: Harshdeep Dhatt Date: Mon, 16 Apr 2018 13:50:31 -0600 Subject: [PATCH 1332/1635] msm: kgsl: Enable GPU system cache usage on A640 System cache feature on A640 is different than A630. We still use the LLCC driver API to activate/deactivate GPU slices. But, the SCID configuration registers have moved from CX_MISC to GBIF register space. Also, the GPU HTW SCID cannot be configured via these registers on A640 because of the way MMU500 is integrated. The GPU HTW SCID will be configured via NoC override in the xbl image. Lastly, the page attributes are no longer configured via register write. They are now specified in the smmu pagetable entries. Change-Id: Ic47fcc96a704cf50b84f14177225a75eab2a82aa Signed-off-by: Harshdeep Dhatt --- drivers/gpu/msm/a6xx_reg.h | 1 + drivers/gpu/msm/adreno.c | 30 ++++++++++++++++++++++++++++-- drivers/gpu/msm/adreno_a6xx.c | 29 +++++++++++++++++++++++++---- 3 files changed, 54 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/msm/a6xx_reg.h b/drivers/gpu/msm/a6xx_reg.h index ab3280512697..cfbc753e7178 100644 --- a/drivers/gpu/msm/a6xx_reg.h +++ b/drivers/gpu/msm/a6xx_reg.h @@ -814,6 +814,7 @@ #define GBIF_AXI1_WRITE_DATA_TOTAL_BEATS 47 /* GBIF registers */ +#define A6XX_GBIF_SCACHE_CNTL1 0x3c02 #define A6XX_GBIF_QSB_SIDE0 0x3c03 #define A6XX_GBIF_QSB_SIDE1 0x3c04 #define A6XX_GBIF_QSB_SIDE2 0x3c05 diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c index 29bca42aa1cd..1679561ed2f7 100644 --- a/drivers/gpu/msm/adreno.c +++ b/drivers/gpu/msm/adreno.c @@ -112,8 +112,8 @@ static struct adreno_device device_3d0 = { .profile.enabled = false, .active_list = LIST_HEAD_INIT(device_3d0.active_list), .active_list_lock = __SPIN_LOCK_UNLOCKED(device_3d0.active_list_lock), - .gpu_llc_slice_enable = false, - .gpuhtw_llc_slice_enable = false, + .gpu_llc_slice_enable = true, + .gpuhtw_llc_slice_enable = true, .preempt = { .preempt_level = 1, .skipsaverestore = 1, @@ -1322,6 +1322,24 @@ static int adreno_probe(struct platform_device *pdev) /* Initialize coresight for the target */ adreno_coresight_init(adreno_dev); + /* Get the system cache slice descriptor for GPU */ + adreno_dev->gpu_llc_slice = adreno_llc_getd(&pdev->dev, "gpu"); + if (IS_ERR(adreno_dev->gpu_llc_slice)) { + KGSL_DRV_WARN(device, + "Failed to get GPU LLC slice descriptor %ld\n", + PTR_ERR(adreno_dev->gpu_llc_slice)); + adreno_dev->gpu_llc_slice = NULL; + } + + /* Get the system cache slice descriptor for GPU pagetables */ + adreno_dev->gpuhtw_llc_slice = adreno_llc_getd(&pdev->dev, "gpuhtw"); + if (IS_ERR(adreno_dev->gpuhtw_llc_slice)) { + KGSL_DRV_WARN(device, + "Failed to get gpuhtw LLC slice descriptor %ld\n", + PTR_ERR(adreno_dev->gpuhtw_llc_slice)); + adreno_dev->gpuhtw_llc_slice = NULL; + } + #ifdef CONFIG_INPUT if (!device->pwrctrl.input_disable) { adreno_input_handler.private = device; @@ -1951,6 +1969,14 @@ static int _adreno_start(struct adreno_device *adreno_dev) /* Start the GPU */ gpudev->start(adreno_dev); + /* + * The system cache control registers + * live on the CX/GX rail. Hence need + * reprogramming everytime the GPU + * comes out of power collapse. + */ + adreno_llc_setup(device); + /* Re-initialize the coresight registers if applicable */ adreno_coresight_start(adreno_dev); diff --git a/drivers/gpu/msm/adreno_a6xx.c b/drivers/gpu/msm/adreno_a6xx.c index 6c5dac651254..b34182631465 100644 --- a/drivers/gpu/msm/adreno_a6xx.c +++ b/drivers/gpu/msm/adreno_a6xx.c @@ -1440,17 +1440,24 @@ static void a6xx_llc_configure_gpu_scid(struct adreno_device *adreno_dev) uint32_t gpu_scid; uint32_t gpu_cntl1_val = 0; int i; - void __iomem *gpu_cx_reg; gpu_scid = adreno_llc_get_scid(adreno_dev->gpu_llc_slice); for (i = 0; i < A6XX_LLC_NUM_GPU_SCIDS; i++) gpu_cntl1_val = (gpu_cntl1_val << A6XX_GPU_LLC_SCID_NUM_BITS) | gpu_scid; - gpu_cx_reg = ioremap(A6XX_GPU_CX_REG_BASE, A6XX_GPU_CX_REG_SIZE); - _reg_rmw(gpu_cx_reg + A6XX_GPU_CX_MISC_SYSTEM_CACHE_CNTL_1, + if (adreno_is_a640(adreno_dev)) { + kgsl_regrmw(KGSL_DEVICE(adreno_dev), A6XX_GBIF_SCACHE_CNTL1, A6XX_GPU_LLC_SCID_MASK, gpu_cntl1_val); - iounmap(gpu_cx_reg); + } else { + void __iomem *gpu_cx_reg; + + gpu_cx_reg = ioremap(A6XX_GPU_CX_REG_BASE, + A6XX_GPU_CX_REG_SIZE); + _reg_rmw(gpu_cx_reg + A6XX_GPU_CX_MISC_SYSTEM_CACHE_CNTL_1, + A6XX_GPU_LLC_SCID_MASK, gpu_cntl1_val); + iounmap(gpu_cx_reg); + } } /* @@ -1462,6 +1469,13 @@ static void a6xx_llc_configure_gpuhtw_scid(struct adreno_device *adreno_dev) uint32_t gpuhtw_scid; void __iomem *gpu_cx_reg; + /* + * On A640, the GPUHTW SCID is configured via a NoC override in the + * XBL image. + */ + if (adreno_is_a640(adreno_dev)) + return; + gpuhtw_scid = adreno_llc_get_scid(adreno_dev->gpuhtw_llc_slice); gpu_cx_reg = ioremap(A6XX_GPU_CX_REG_BASE, A6XX_GPU_CX_REG_SIZE); @@ -1479,6 +1493,13 @@ static void a6xx_llc_enable_overrides(struct adreno_device *adreno_dev) { void __iomem *gpu_cx_reg; + /* + * Attributes override through GBIF is not supported with MMU-500. + * Attributes are used as configured through SMMU pagetable entries. + */ + if (adreno_is_a640(adreno_dev)) + return; + /* * 0x3: readnoallocoverrideen=0 * read-no-alloc=0 - Allocate lines on read miss -- GitLab From 83a32db935ece79ae3b33d02dc74fb04bd073be3 Mon Sep 17 00:00:00 2001 From: Harshdeep Dhatt Date: Tue, 17 Apr 2018 15:32:43 -0600 Subject: [PATCH 1333/1635] msm: kgsl: Use DOMAIN_ATTR_USE_LLC_NWA attribute on A640, setting the memory attributes for system cache allocation has changed with the new MMU integration. Now we need to specify this attribute for a domain, in order to set the memory attributes for page table walk to be read-allocate, write-no-allocate. Also, use the new IOMMU_USE_LLC_NWA flag to specify the same attributes for the rest of the GPU traffic. Change-Id: I38029a77a3470ef5305a4cdcdfd40f5bdc69cfcf Signed-off-by: Harshdeep Dhatt --- drivers/gpu/msm/kgsl_iommu.c | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/msm/kgsl_iommu.c b/drivers/gpu/msm/kgsl_iommu.c index b59ee50d7e74..c76441a7e471 100644 --- a/drivers/gpu/msm/kgsl_iommu.c +++ b/drivers/gpu/msm/kgsl_iommu.c @@ -1153,8 +1153,13 @@ void _enable_gpuhtw_llc(struct kgsl_mmu *mmu, struct kgsl_iommu_pt *iommu_pt) return; /* Domain attribute to enable system cache for GPU pagetable walks */ - ret = iommu_domain_set_attr(iommu_pt->domain, + if (adreno_is_a640(adreno_dev)) + ret = iommu_domain_set_attr(iommu_pt->domain, + DOMAIN_ATTR_USE_LLC_NWA, &gpuhtw_llc_enable); + else + ret = iommu_domain_set_attr(iommu_pt->domain, DOMAIN_ATTR_USE_UPSTREAM_HINT, &gpuhtw_llc_enable); + /* * Warn that the system cache will not be used for GPU * pagetable walks. This is not a fatal error. @@ -1773,10 +1778,21 @@ static int _iommu_map_guard_page(struct kgsl_pagetable *pt, protflags & ~IOMMU_WRITE); } -static unsigned int _get_protection_flags(struct kgsl_memdesc *memdesc) +static unsigned int _get_protection_flags(struct kgsl_pagetable *pt, + struct kgsl_memdesc *memdesc) { unsigned int flags = IOMMU_READ | IOMMU_WRITE | - IOMMU_NOEXEC | IOMMU_USE_UPSTREAM_HINT; + IOMMU_NOEXEC; + int ret, llc_nwa = 0; + struct kgsl_iommu_pt *iommu_pt = pt->priv; + + ret = iommu_domain_get_attr(iommu_pt->domain, + DOMAIN_ATTR_USE_LLC_NWA, &llc_nwa); + + if (ret || (llc_nwa == 0)) + flags |= IOMMU_USE_UPSTREAM_HINT; + else + flags |= IOMMU_USE_LLC_NWA; if (memdesc->flags & KGSL_MEMFLAGS_GPUREADONLY) flags &= ~IOMMU_WRITE; @@ -1800,7 +1816,7 @@ kgsl_iommu_map(struct kgsl_pagetable *pt, int ret; uint64_t addr = memdesc->gpuaddr; uint64_t size = memdesc->size; - unsigned int flags = _get_protection_flags(memdesc); + unsigned int flags = _get_protection_flags(pt, memdesc); struct sg_table *sgt = NULL; /* @@ -1930,7 +1946,7 @@ static int kgsl_iommu_map_offset(struct kgsl_pagetable *pt, uint64_t size, uint64_t feature_flag) { int pg_sz; - unsigned int protflags = _get_protection_flags(memdesc); + unsigned int protflags = _get_protection_flags(pt, memdesc); int ret; struct sg_table *sgt = NULL; -- GitLab From 927a921d05f6477c4f33dbea943d007cba9cc8ce Mon Sep 17 00:00:00 2001 From: Guru Das Srinagesh Date: Tue, 1 May 2018 16:06:29 -0700 Subject: [PATCH 1334/1635] power: smb1390: Fix device tree parsing error Currently, SMB1390 probe is failing because the parsing function is returning a raw pointer value as its return code, which is then interpreted as an error condition. This is happening because the return code of the parsing function is being overridden with the PTR_ERR value of the die_temp_chan pointer regardless of whether it is an erroneous value or not. Fix this by overriding the return code of the parsing function only if the die_temp_chan pointer is determined to be an error. CRs-Fixed: 2234393 Change-Id: I307b30ffac63f4e1b51b71bd3e03693256219b7d Signed-off-by: Guru Das Srinagesh --- drivers/power/supply/qcom/smb1390-charger.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/power/supply/qcom/smb1390-charger.c b/drivers/power/supply/qcom/smb1390-charger.c index 58374f811292..950acf33e4c4 100644 --- a/drivers/power/supply/qcom/smb1390-charger.c +++ b/drivers/power/supply/qcom/smb1390-charger.c @@ -532,12 +532,12 @@ static int smb1390_parse_dt(struct smb1390 *chip) if (rc >= 0) { chip->iio.die_temp_chan = iio_channel_get(chip->dev, "cp_die_temp"); - rc = PTR_ERR(chip->iio.die_temp_chan); if (IS_ERR(chip->iio.die_temp_chan)) { + rc = PTR_ERR(chip->iio.die_temp_chan); if (rc != -EPROBE_DEFER) dev_err(chip->dev, "cp_die_temp channel unavailable %ld\n", - PTR_ERR(chip->iio.die_temp_chan)); + rc); chip->iio.die_temp_chan = NULL; return rc; } -- GitLab From d714098d35e7a392b506de23ee37acfe4c30c748 Mon Sep 17 00:00:00 2001 From: Amar Singhal Date: Wed, 21 Mar 2018 16:07:22 -0700 Subject: [PATCH 1335/1635] defconfig: Enable cellular hints in regulatory cfg80211 The user-space may send regulatory hint that has cellular sub-type enabled. To process such events, enable CONFIG_CFG80211_REG_CELLULAR_HINTS. Change-Id: Ib947e1327019665ff7ca29f54227722e940890f3 Signed-off-by: Amar Singhal CRs-Fixed: 2201959 --- arch/arm64/configs/sdmshrike-perf_defconfig | 2 ++ arch/arm64/configs/sdmshrike_defconfig | 2 ++ arch/arm64/configs/sdmsteppe-perf_defconfig | 2 ++ arch/arm64/configs/sdmsteppe_defconfig | 2 ++ arch/arm64/configs/sm8150-perf_defconfig | 2 ++ arch/arm64/configs/sm8150_defconfig | 2 ++ 6 files changed, 12 insertions(+) diff --git a/arch/arm64/configs/sdmshrike-perf_defconfig b/arch/arm64/configs/sdmshrike-perf_defconfig index 93111b16ae13..75a748c2e54b 100644 --- a/arch/arm64/configs/sdmshrike-perf_defconfig +++ b/arch/arm64/configs/sdmshrike-perf_defconfig @@ -197,6 +197,8 @@ CONFIG_QRTR=y CONFIG_QRTR_SMD=y CONFIG_BT=y CONFIG_CFG80211=y +CONFIG_CFG80211_CERTIFICATION_ONUS=y +CONFIG_CFG80211_REG_CELLULAR_HINTS=y CONFIG_CFG80211_INTERNAL_REGDB=y CONFIG_RFKILL=y CONFIG_FW_LOADER_USER_HELPER_FALLBACK=y diff --git a/arch/arm64/configs/sdmshrike_defconfig b/arch/arm64/configs/sdmshrike_defconfig index 55c79d91ec2f..830f06dc204a 100644 --- a/arch/arm64/configs/sdmshrike_defconfig +++ b/arch/arm64/configs/sdmshrike_defconfig @@ -204,6 +204,8 @@ CONFIG_QRTR=y CONFIG_QRTR_SMD=y CONFIG_BT=y CONFIG_CFG80211=y +CONFIG_CFG80211_CERTIFICATION_ONUS=y +CONFIG_CFG80211_REG_CELLULAR_HINTS=y CONFIG_CFG80211_INTERNAL_REGDB=y # CONFIG_CFG80211_CRDA_SUPPORT is not set CONFIG_RFKILL=y diff --git a/arch/arm64/configs/sdmsteppe-perf_defconfig b/arch/arm64/configs/sdmsteppe-perf_defconfig index 4b15bc7aa0b1..3a656b63ec01 100644 --- a/arch/arm64/configs/sdmsteppe-perf_defconfig +++ b/arch/arm64/configs/sdmsteppe-perf_defconfig @@ -228,6 +228,8 @@ CONFIG_SOCKEV_NLMCAST=y CONFIG_BT=y CONFIG_MSM_BT_POWER=y CONFIG_CFG80211=y +CONFIG_CFG80211_CERTIFICATION_ONUS=y +CONFIG_CFG80211_REG_CELLULAR_HINTS=y CONFIG_CFG80211_INTERNAL_REGDB=y CONFIG_RFKILL=y CONFIG_NFC_NQ=y diff --git a/arch/arm64/configs/sdmsteppe_defconfig b/arch/arm64/configs/sdmsteppe_defconfig index 0fcc65545c32..9d052dd6eeb6 100644 --- a/arch/arm64/configs/sdmsteppe_defconfig +++ b/arch/arm64/configs/sdmsteppe_defconfig @@ -233,6 +233,8 @@ CONFIG_SOCKEV_NLMCAST=y CONFIG_BT=y CONFIG_MSM_BT_POWER=y CONFIG_CFG80211=y +CONFIG_CFG80211_CERTIFICATION_ONUS=y +CONFIG_CFG80211_REG_CELLULAR_HINTS=y CONFIG_CFG80211_INTERNAL_REGDB=y # CONFIG_CFG80211_CRDA_SUPPORT is not set CONFIG_RFKILL=y diff --git a/arch/arm64/configs/sm8150-perf_defconfig b/arch/arm64/configs/sm8150-perf_defconfig index bd4239b26df3..c08444e9ad65 100644 --- a/arch/arm64/configs/sm8150-perf_defconfig +++ b/arch/arm64/configs/sm8150-perf_defconfig @@ -230,6 +230,8 @@ CONFIG_SOCKEV_NLMCAST=y CONFIG_BT=y CONFIG_MSM_BT_POWER=y CONFIG_CFG80211=y +CONFIG_CFG80211_CERTIFICATION_ONUS=y +CONFIG_CFG80211_REG_CELLULAR_HINTS=y CONFIG_CFG80211_INTERNAL_REGDB=y CONFIG_RFKILL=y CONFIG_NFC_NQ=y diff --git a/arch/arm64/configs/sm8150_defconfig b/arch/arm64/configs/sm8150_defconfig index 5bf92e55b3dc..277ab1a3ab3c 100644 --- a/arch/arm64/configs/sm8150_defconfig +++ b/arch/arm64/configs/sm8150_defconfig @@ -236,6 +236,8 @@ CONFIG_SOCKEV_NLMCAST=y CONFIG_BT=y CONFIG_MSM_BT_POWER=y CONFIG_CFG80211=y +CONFIG_CFG80211_CERTIFICATION_ONUS=y +CONFIG_CFG80211_REG_CELLULAR_HINTS=y CONFIG_CFG80211_INTERNAL_REGDB=y # CONFIG_CFG80211_CRDA_SUPPORT is not set CONFIG_RFKILL=y -- GitLab From af687ac3227ae2181561445d0ba380706b2e546a Mon Sep 17 00:00:00 2001 From: Prateek Sood Date: Tue, 1 May 2018 11:19:07 +0530 Subject: [PATCH 1336/1635] llcc: Update SCT table entries Modify llcc SCT table entries for sdm640. Change-Id: I7087a38eb11176824d370f21ee1c18c4b60e012c Signed-off-by: Prateek Sood --- drivers/soc/qcom/llcc-sdm640.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/drivers/soc/qcom/llcc-sdm640.c b/drivers/soc/qcom/llcc-sdm640.c index 61c3cae66d9b..f746e1ec4269 100644 --- a/drivers/soc/qcom/llcc-sdm640.c +++ b/drivers/soc/qcom/llcc-sdm640.c @@ -57,14 +57,9 @@ } static struct llcc_slice_config sdm640_data[] = { - SCT_ENTRY("cpuss", 1, 1, 256, 1, 0, 0x3, 0x0, 0, 0, 0, 1, 1), - SCT_ENTRY("rotator", 4, 4, 256, 2, 1, 0x3, 0x0, 2, 0, 0, 1, 0), - SCT_ENTRY("voice", 5, 5, 256, 1, 0, 0x3, 0x0, 0, 0, 0, 1, 0), - SCT_ENTRY("audio", 6, 6, 256, 1, 0, 0x3, 0x0, 0, 0, 0, 1, 0), - SCT_ENTRY("modem", 8, 8, 256, 1, 0, 0x3, 0x0, 0, 0, 0, 1, 0), - SCT_ENTRY("gpu", 12, 12, 0, 1, 0, 0x3, 0x0, 0, 0, 0, 1, 0), - SCT_ENTRY("mmuhwt", 13, 13, 256, 1, 0, 0x3, 0x0, 0, 0, 0, 0, 1), - SCT_ENTRY("audiohw", 22, 22, 256, 1, 1, 0x3, 0x0, 0, 0, 0, 1, 0), + SCT_ENTRY("cpuss", 1, 1, 256, 1, 0, 0xF, 0x0, 0, 0, 0, 1, 1), + SCT_ENTRY("modem", 8, 8, 256, 1, 0, 0xF, 0x0, 0, 0, 0, 1, 0), + SCT_ENTRY("mmuhwt", 13, 13, 256, 1, 0, 0xF, 0x0, 0, 0, 0, 0, 1), }; static int sdm640_qcom_llcc_probe(struct platform_device *pdev) -- GitLab From b71c1bfd4066e949f34a43013d1bd3bd9f66ed0a Mon Sep 17 00:00:00 2001 From: Ashay Jaiswal Date: Wed, 28 Feb 2018 17:13:05 +0530 Subject: [PATCH 1337/1635] power: smb5: fix FLOAT charger ICL handling Update FLOAT charger ICL configuration handling, ICL for float charger is configured as follows: On FLOAT charger detection ICL will be configured to 100mA, once USB driver is complete ICL will be configured based on the enumeration result. Change-Id: I8eb79077b79a37b2888d7091e68ca34de6036645 Signed-off-by: Ashay Jaiswal --- drivers/power/supply/qcom/battery.c | 22 ++++++- drivers/power/supply/qcom/battery.h | 2 +- drivers/power/supply/qcom/smb-lib.c | 2 +- drivers/power/supply/qcom/smb5-lib.c | 92 +++++++++++++++++++++++----- 4 files changed, 100 insertions(+), 18 deletions(-) diff --git a/drivers/power/supply/qcom/battery.c b/drivers/power/supply/qcom/battery.c index 4b88e04533ac..1433373ff110 100644 --- a/drivers/power/supply/qcom/battery.c +++ b/drivers/power/supply/qcom/battery.c @@ -70,6 +70,7 @@ struct pl_data { int charge_type; int total_settled_ua; int pl_settled_ua; + u32 wa_flags; struct class qcom_batt_class; struct wakeup_source *pl_ws; struct notifier_block nb; @@ -81,6 +82,10 @@ enum print_reason { PR_PARALLEL = BIT(0), }; +enum { + AICL_RERUN_WA_BIT = BIT(0), +}; + static int debug_mask; module_param_named(debug_mask, debug_mask, int, 0600); @@ -539,7 +544,7 @@ static int usb_icl_vote_callback(struct votable *votable, void *data, if (icl_ua > pval.intval) rerun_aicl = true; - if (rerun_aicl) { + if (rerun_aicl && (chip->wa_flags & AICL_RERUN_WA_BIT)) { /* set a lower ICL */ pval.intval = max(pval.intval - ICL_STEP_UA, ICL_STEP_UA); power_supply_set_property(chip->main_psy, @@ -1015,8 +1020,20 @@ static int pl_determine_initial_status(struct pl_data *chip) return 0; } +static void pl_config_init(struct pl_data *chip, int smb_version) +{ + switch (smb_version) { + case PMI8998_SUBTYPE: + case PM660_SUBTYPE: + chip->wa_flags = AICL_RERUN_WA_BIT; + break; + default: + break; + } +} + #define DEFAULT_RESTRICTED_CURRENT_UA 1000000 -int qcom_batt_init(void) +int qcom_batt_init(int smb_version) { struct pl_data *chip; int rc = 0; @@ -1031,6 +1048,7 @@ int qcom_batt_init(void) if (!chip) return -ENOMEM; chip->slave_pct = 50; + pl_config_init(chip, smb_version); chip->restricted_current = DEFAULT_RESTRICTED_CURRENT_UA; chip->pl_ws = wakeup_source_register("qcom-battery"); diff --git a/drivers/power/supply/qcom/battery.h b/drivers/power/supply/qcom/battery.h index 38626e733a09..94e8800adb68 100644 --- a/drivers/power/supply/qcom/battery.h +++ b/drivers/power/supply/qcom/battery.h @@ -12,6 +12,6 @@ #ifndef __BATTERY_H #define __BATTERY_H -int qcom_batt_init(void); +int qcom_batt_init(int smb_version); void qcom_batt_deinit(void); #endif /* __BATTERY_H */ diff --git a/drivers/power/supply/qcom/smb-lib.c b/drivers/power/supply/qcom/smb-lib.c index 7a8b520b5ec1..fc0ba98cf341 100644 --- a/drivers/power/supply/qcom/smb-lib.c +++ b/drivers/power/supply/qcom/smb-lib.c @@ -5047,7 +5047,7 @@ int smblib_init(struct smb_charger *chg) switch (chg->mode) { case PARALLEL_MASTER: - rc = qcom_batt_init(); + rc = qcom_batt_init(chg->smb_version); if (rc < 0) { smblib_err(chg, "Couldn't init qcom_batt_init rc=%d\n", rc); diff --git a/drivers/power/supply/qcom/smb5-lib.c b/drivers/power/supply/qcom/smb5-lib.c index ae9d4c623bd8..1869fb848f80 100644 --- a/drivers/power/supply/qcom/smb5-lib.c +++ b/drivers/power/supply/qcom/smb5-lib.c @@ -700,6 +700,13 @@ static void smblib_uusb_removal(struct smb_charger *chg) chg->pulse_cnt = 0; chg->uusb_apsd_rerun_done = false; + /* write back the default FLOAT charger configuration */ + rc = smblib_masked_write(chg, USBIN_OPTIONS_2_CFG_REG, + (u8)FLOAT_OPTIONS_MASK, chg->float_cfg); + if (rc < 0) + smblib_err(chg, "Couldn't write float charger options rc=%d\n", + rc); + /* clear USB ICL vote for USB_PSY_VOTER */ rc = vote(chg->usb_icl_votable, USB_PSY_VOTER, false, 0); if (rc < 0) @@ -891,6 +898,9 @@ int smblib_set_icl_current(struct smb_charger *chg, int icl_ua) goto out; } + /* Re-run AICL */ + if (chg->real_charger_type != POWER_SUPPLY_TYPE_USB) + rc = smblib_rerun_aicl(chg); out: return rc; } @@ -2142,16 +2152,40 @@ static int smblib_handle_usb_current(struct smb_charger *chg, if (chg->real_charger_type == POWER_SUPPLY_TYPE_USB_FLOAT) { if (usb_current == -ETIMEDOUT) { - /* - * Valid FLOAT charger, report the current based - * of Rp - */ - typec_mode = smblib_get_prop_typec_mode(chg); - rp_ua = get_rp_based_dcp_current(chg, typec_mode); - rc = vote(chg->usb_icl_votable, SW_ICL_MAX_VOTER, - true, rp_ua); - if (rc < 0) + if ((chg->float_cfg & FLOAT_OPTIONS_MASK) + == FORCE_FLOAT_SDP_CFG_BIT) { + /* + * Confiugure USB500 mode if Float charger is + * configured for SDP mode. + */ + rc = set_sdp_current(chg, USBIN_500MA); + if (rc < 0) + smblib_err(chg, + "Couldn't set SDP ICL rc=%d\n", + rc); + return rc; + } + + if (chg->connector_type == + POWER_SUPPLY_CONNECTOR_TYPEC) { + /* + * Valid FLOAT charger, report the current + * based of Rp. + */ + typec_mode = smblib_get_prop_typec_mode(chg); + rp_ua = get_rp_based_dcp_current(chg, + typec_mode); + rc = vote(chg->usb_icl_votable, + SW_ICL_MAX_VOTER, true, rp_ua); + if (rc < 0) + return rc; + } else { + rc = vote(chg->usb_icl_votable, + SW_ICL_MAX_VOTER, true, DCP_CURRENT_UA); + if (rc < 0) + return rc; + } } else { /* * FLOAT charger detected as SDP by USB driver, @@ -2171,9 +2205,20 @@ static int smblib_handle_usb_current(struct smb_charger *chg, } else { rc = vote(chg->usb_icl_votable, USB_PSY_VOTER, true, usb_current); + if (rc < 0) { + pr_err("Couldn't vote ICL USB_PSY_VOTER rc=%d\n", rc); + return rc; + } + + rc = vote(chg->usb_icl_votable, SW_ICL_MAX_VOTER, false, 0); + if (rc < 0) { + pr_err("Couldn't remove SW_ICL_MAX vote rc=%d\n", rc); + return rc; + } + } - return rc; + return 0; } int smblib_set_prop_sdp_current_max(struct smb_charger *chg, @@ -2884,9 +2929,13 @@ static void update_sw_icl_max(struct smb_charger *chg, int pst) if (chg->pd_active) return; - /* HVDCP 2/3, handled separately */ + /* + * HVDCP 2/3, handled separately + * For UNKNOWN(input not present) return without updating ICL + */ if (pst == POWER_SUPPLY_TYPE_USB_HVDCP - || pst == POWER_SUPPLY_TYPE_USB_HVDCP_3) + || pst == POWER_SUPPLY_TYPE_USB_HVDCP_3 + || pst == POWER_SUPPLY_TYPE_UNKNOWN) return; /* TypeC rp med or high, use rp value */ @@ -2948,12 +2997,12 @@ static void smblib_handle_apsd_done(struct smb_charger *chg, bool rising) switch (apsd_result->bit) { case SDP_CHARGER_BIT: case CDP_CHARGER_BIT: + case FLOAT_CHARGER_BIT: if ((chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB) || chg->use_extcon) smblib_notify_device_mode(chg, true); break; case OCP_CHARGER_BIT: - case FLOAT_CHARGER_BIT: case DCP_CHARGER_BIT: break; default: @@ -3163,6 +3212,21 @@ static void smblib_handle_rp_change(struct smb_charger *chg, int typec_mode) { const struct apsd_result *apsd = smblib_get_apsd_result(chg); + /* + * We want the ICL vote @ 100mA for a FLOAT charger + * until the detection by the USB stack is complete. + * Ignore the Rp changes unless there is a + * pre-existing valid vote or FLOAT is configured for + * SDP current. + */ + if (apsd->pst == POWER_SUPPLY_TYPE_USB_FLOAT) { + if (get_client_vote(chg->usb_icl_votable, SW_ICL_MAX_VOTER) + <= USBIN_100MA + || (chg->float_cfg & FLOAT_OPTIONS_MASK) + == FORCE_FLOAT_SDP_CFG_BIT) + return; + } + update_sw_icl_max(chg, apsd->pst); smblib_dbg(chg, PR_MISC, "CC change old_mode=%d new_mode=%d\n", @@ -3765,7 +3829,7 @@ int smblib_init(struct smb_charger *chg) switch (chg->mode) { case PARALLEL_MASTER: - rc = qcom_batt_init(); + rc = qcom_batt_init(chg->smb_version); if (rc < 0) { smblib_err(chg, "Couldn't init qcom_batt_init rc=%d\n", rc); -- GitLab From 93a1395419ae152569d0f3ff7fd14682be4c99df Mon Sep 17 00:00:00 2001 From: Ashay Jaiswal Date: Sun, 4 Mar 2018 19:46:40 +0530 Subject: [PATCH 1338/1635] power_supply: Add HVDCP_OPTI_ALLOWED property Add POWER_SUPPLY_PROP_HVDCP_OPTI_ALLOWED to enable/disable optimization by userspace daemon. Change-Id: I084711fe4ef49c942005da1a986afed13e727312 Signed-off-by: Ashay Jaiswal --- drivers/power/supply/power_supply_sysfs.c | 1 + include/linux/power_supply.h | 1 + 2 files changed, 2 insertions(+) diff --git a/drivers/power/supply/power_supply_sysfs.c b/drivers/power/supply/power_supply_sysfs.c index 087746014ce9..2e1975ee6761 100644 --- a/drivers/power/supply/power_supply_sysfs.c +++ b/drivers/power/supply/power_supply_sysfs.c @@ -367,6 +367,7 @@ static struct device_attribute power_supply_attrs[] = { POWER_SUPPLY_ATTR(batt_profile_version), POWER_SUPPLY_ATTR(batt_full_current), POWER_SUPPLY_ATTR(recharge_soc), + POWER_SUPPLY_ATTR(hvdcp_opti_allowed), /* Local extensions of type int64_t */ POWER_SUPPLY_ATTR(charge_counter_ext), /* Properties of type `const char *' */ diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h index 8f8d700552d2..12c6c6c08e43 100644 --- a/include/linux/power_supply.h +++ b/include/linux/power_supply.h @@ -280,6 +280,7 @@ enum power_supply_property { POWER_SUPPLY_PROP_BATT_PROFILE_VERSION, POWER_SUPPLY_PROP_BATT_FULL_CURRENT, POWER_SUPPLY_PROP_RECHARGE_SOC, + POWER_SUPPLY_PROP_HVDCP_OPTI_ALLOWED, /* Local extensions of type int64_t */ POWER_SUPPLY_PROP_CHARGE_COUNTER_EXT, /* Properties of type `const char *' */ -- GitLab From b728380ac23a4c6e80f583b22852c1409eff8d9b Mon Sep 17 00:00:00 2001 From: Saranya Chidura Date: Wed, 2 May 2018 14:40:32 +0530 Subject: [PATCH 1339/1635] ARM: dts: qcom: add GIC interrupt controller header in qcs405 Include GIC interrupt controller header file in qcs405 DT file for successful registration of interrupts. Change-Id: I702949f133f09687af54f2e6c9a34166759be5d0 Signed-off-by: Saranya Chidura --- arch/arm64/boot/dts/qcom/qcs405.dtsi | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/boot/dts/qcom/qcs405.dtsi b/arch/arm64/boot/dts/qcom/qcs405.dtsi index 91eee94a1ebb..bbe6b08ed638 100644 --- a/arch/arm64/boot/dts/qcom/qcs405.dtsi +++ b/arch/arm64/boot/dts/qcom/qcs405.dtsi @@ -15,6 +15,7 @@ #include #include #include +#include / { model = "Qualcomm Technologies, Inc. QCS405"; -- GitLab From 0f80150f51f36603cd5afde12eb38aea034fa899 Mon Sep 17 00:00:00 2001 From: Mahesh Sivasubramanian Date: Tue, 31 Oct 2017 17:36:01 +0530 Subject: [PATCH 1340/1635] cpuidle: Wakeup only cpus for which qos has changed. The pm_qos framework passes down a mask of cpus for which the qos has changed. cpuidle driver uses this info to wakeup only those cpus for the new qos to take effect. This would prevent waking up cpus for which the qos values remains unchanged. Change-Id: Ibb79937674a8f16920c6b8f224a21d2f72a0f9ce Signed-off-by: Mahesh Sivasubramanian Signed-off-by: Maulik Shah --- drivers/cpuidle/cpuidle.c | 29 +++++++++++++++++++++++++---- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c index e47e14101768..22f9e87c5073 100644 --- a/drivers/cpuidle/cpuidle.c +++ b/drivers/cpuidle/cpuidle.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -634,16 +635,36 @@ EXPORT_SYMBOL_GPL(cpuidle_register); #ifdef CONFIG_SMP +static void wake_up_idle_cpus(void *v) +{ + int cpu; + struct cpumask cpus; + + if (v) { + cpumask_andnot(&cpus, v, cpu_isolated_mask); + cpumask_and(&cpus, &cpus, cpu_online_mask); + } else + cpumask_andnot(&cpus, cpu_online_mask, cpu_isolated_mask); + + preempt_disable(); + for_each_cpu(cpu, &cpus) { + if (cpu == smp_processor_id()) + continue; + wake_up_if_idle(cpu); + } + preempt_enable(); +} + /* * This function gets called when a part of the kernel has a new latency - * requirement. This means we need to get all processors out of their C-state, - * and then recalculate a new suitable C-state. Just do a cross-cpu IPI; that - * wakes them all right up. + * requirement. This means we need to get only those processors out of their + * C-state for which qos requirement is changed, and then recalculate a new + * suitable C-state. Just do a cross-cpu IPI; that wakes them all right up. */ static int cpuidle_latency_notify(struct notifier_block *b, unsigned long l, void *v) { - wake_up_all_idle_cpus(); + wake_up_idle_cpus(v); return NOTIFY_OK; } -- GitLab From d2e9ac504ab87526820eee31a0d1ab3e96d1f357 Mon Sep 17 00:00:00 2001 From: Vijaykumar Badiger Date: Tue, 17 Apr 2018 11:05:03 -0700 Subject: [PATCH 1341/1635] ARM: dts: msm: Add device tree for sm8150-auto Add initial device tree support for SM8150 based automotive platforms. Change-Id: I2fd0864b7b9371f750599da9ab54932ab91874bb Signed-off-by: Vijaykumar Badiger --- .../devicetree/bindings/arm/msm/msm.txt | 2 ++ arch/arm64/boot/dts/qcom/Makefile | 3 +++ .../dts/qcom/sm8150-auto-adp-star-overlay.dts | 23 ++++++++++++++++ .../boot/dts/qcom/sm8150-auto-adp-star.dts | 22 +++++++++++++++ .../boot/dts/qcom/sm8150-auto-adp-star.dtsi | 27 +++++++++++++++++++ arch/arm64/boot/dts/qcom/sm8150-auto.dts | 22 +++++++++++++++ arch/arm64/boot/dts/qcom/sm8150-auto.dtsi | 19 +++++++++++++ 7 files changed, 118 insertions(+) create mode 100644 arch/arm64/boot/dts/qcom/sm8150-auto-adp-star-overlay.dts create mode 100644 arch/arm64/boot/dts/qcom/sm8150-auto-adp-star.dts create mode 100644 arch/arm64/boot/dts/qcom/sm8150-auto-adp-star.dtsi create mode 100644 arch/arm64/boot/dts/qcom/sm8150-auto.dts create mode 100644 arch/arm64/boot/dts/qcom/sm8150-auto.dtsi diff --git a/Documentation/devicetree/bindings/arm/msm/msm.txt b/Documentation/devicetree/bindings/arm/msm/msm.txt index cfae9a1400ff..7c4383ebfba5 100644 --- a/Documentation/devicetree/bindings/arm/msm/msm.txt +++ b/Documentation/devicetree/bindings/arm/msm/msm.txt @@ -145,3 +145,5 @@ compatible = "qcom,sdm640-qrd" compatible = "qcom,qcs405-rumi" compatible = "qcom,qcs405-mtp" compatible = "qcom,qcs405-cdp" +compatible = "qcom,sm8150-auto-adp-star" +compatible = "qcom,auto-adp-star" diff --git a/arch/arm64/boot/dts/qcom/Makefile b/arch/arm64/boot/dts/qcom/Makefile index 065da48cf5a8..ab3d6f9942a0 100644 --- a/arch/arm64/boot/dts/qcom/Makefile +++ b/arch/arm64/boot/dts/qcom/Makefile @@ -16,6 +16,7 @@ ifeq ($(CONFIG_BUILD_ARM64_DT_OVERLAY),y) sm8150-mtp-overlay.dtbo \ sm8150-rumi-overlay.dtbo \ sm8150-qrd-overlay.dtbo \ + sm8150-auto-adp-star-overlay.dtbo \ sm8150p-cdp-overlay.dtbo \ sm8150p-mtp-overlay.dtbo \ sm8150p-qrd-overlay.dtbo \ @@ -26,6 +27,7 @@ sm8150-cdp-overlay.dtbo-base := sm8150.dtb sm8150-v2.dtb sm8150-mtp-overlay.dtbo-base := sm8150.dtb sm8150-v2.dtb sm8150-rumi-overlay.dtbo-base := sm8150.dtb sm8150-v2.dtb sm8150-qrd-overlay.dtbo-base := sm8150.dtb sm8150-v2.dtb +sm8150-auto-adp-star-overlay.dtbo-base := sm8150-auto.dtb sm8150-sdx50m-cdp-overlay.dtbo-base := sm8150.dtb sm8150-v2.dtb sm8150-sdx50m-mtp-overlay.dtbo-base := sm8150.dtb sm8150-v2.dtb sm8150p-mtp-overlay.dtbo-base := sm8150p.dtb sm8150p-v2.dtb @@ -35,6 +37,7 @@ dtb-$(CONFIG_ARCH_SM8150) += sm8150-rumi.dtb \ sm8150-mtp.dtb \ sm8150-cdp.dtb \ sm8150-qrd.dtb \ + sm8150-auto-adp-star.dtb \ sm8150-v2-rumi.dtb \ sm8150-v2-mtp.dtb \ sm8150-v2-cdp.dtb \ diff --git a/arch/arm64/boot/dts/qcom/sm8150-auto-adp-star-overlay.dts b/arch/arm64/boot/dts/qcom/sm8150-auto-adp-star-overlay.dts new file mode 100644 index 000000000000..889797e681af --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sm8150-auto-adp-star-overlay.dts @@ -0,0 +1,23 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/dts-v1/; +/plugin/; + +#include "sm8150-auto-adp-star.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SM8150 AUTO-ADP-STAR"; + compatible = "qcom,sm8150-auto-adp-star", "qcom,sm8150", + "qcom,auto-adp-star"; + qcom,board-id = <25 0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sm8150-auto-adp-star.dts b/arch/arm64/boot/dts/qcom/sm8150-auto-adp-star.dts new file mode 100644 index 000000000000..250b080ae57c --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sm8150-auto-adp-star.dts @@ -0,0 +1,22 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/dts-v1/; +#include "sm8150-auto.dtsi" +#include "sm8150-auto-adp-star.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SM8150 AUTO-ADP-STAR"; + compatible = "qcom,sm8150-auto-adp-star", "qcom,sm8150", + "qcom,auto-adp-star"; + qcom,board-id = <25 0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sm8150-auto-adp-star.dtsi b/arch/arm64/boot/dts/qcom/sm8150-auto-adp-star.dtsi new file mode 100644 index 000000000000..a305b5cdb72b --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sm8150-auto-adp-star.dtsi @@ -0,0 +1,27 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +&soc { + qcom,lpass@17300000 { + status = "disabled"; + }; + + qcom,ssc@5c00000 { + status = "disabled"; + }; + + qcom,glink { + modem { + status = "disabled"; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/sm8150-auto.dts b/arch/arm64/boot/dts/qcom/sm8150-auto.dts new file mode 100644 index 000000000000..7dcd050726bb --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sm8150-auto.dts @@ -0,0 +1,22 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/dts-v1/; + +#include "sm8150-auto.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SM8150 AUTO SoC"; + compatible = "qcom,sm8150"; + qcom,pmic-name = "PM855"; + qcom,board-id = <0 0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sm8150-auto.dtsi b/arch/arm64/boot/dts/qcom/sm8150-auto.dtsi new file mode 100644 index 000000000000..fdf597af85be --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sm8150-auto.dtsi @@ -0,0 +1,19 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "sm8150.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SM8150 AUTO"; + qcom,msm-name = "SM8150 AUTO"; + qcom,msm-id = <362 0x10000>; +}; -- GitLab From 931f0da6e2136a29b5865aea5e1917870fc7db88 Mon Sep 17 00:00:00 2001 From: David Collins Date: Fri, 20 Apr 2018 17:30:35 -0700 Subject: [PATCH 1342/1635] ARM: dts: msm: remap PMIC regulators for sm8150-auto The power grid for sm8150-auto differs substantially from that of baseline sm8150. PMIC Combinations: SM8150: PM855 + PM855L + PM855B + PM8009 SM8150 Auto: PM855 + PM855 Add all rpmh-regulator devices supported by SM8150 Auto and remap SoC level PMIC regulator phandles to match the SM8150 Auto power grid. Change-Id: I34bf8ebec4abd2881932dff886b103f9ceab8f70 Signed-off-by: David Collins --- .../boot/dts/qcom/sm8150-auto-regulator.dtsi | 707 ++++++++++++++++++ arch/arm64/boot/dts/qcom/sm8150-auto.dtsi | 283 +++++++ arch/arm64/boot/dts/qcom/sm8150.dtsi | 4 +- 3 files changed, 992 insertions(+), 2 deletions(-) create mode 100644 arch/arm64/boot/dts/qcom/sm8150-auto-regulator.dtsi diff --git a/arch/arm64/boot/dts/qcom/sm8150-auto-regulator.dtsi b/arch/arm64/boot/dts/qcom/sm8150-auto-regulator.dtsi new file mode 100644 index 000000000000..c9394a4100e3 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sm8150-auto-regulator.dtsi @@ -0,0 +1,707 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include + +&soc { + /* RPMh regulators: */ + + rpmh-regulator-smpa4 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "smpa4"; + S4A: pm855_1_s4: regulator-pm855-1-s4 { + regulator-name = "pm855_1_s4"; + qcom,set = ; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + qcom,init-voltage = <1800000>; + }; + }; + + rpmh-regulator-smpa5 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "smpa5"; + S5A: pm855_1_s5: regulator-pm855-1-s5 { + regulator-name = "pm855_1_s5"; + qcom,set = ; + regulator-min-microvolt = <1824000>; + regulator-max-microvolt = <2040000>; + qcom,init-voltage = <1824000>; + }; + }; + + rpmh-regulator-smpa6 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "smpa6"; + S6A: pm855_1_s6: regulator-pm855-1-s6 { + regulator-name = "pm855_1_s6"; + qcom,set = ; + regulator-min-microvolt = <600000>; + regulator-max-microvolt = <1128000>; + qcom,init-voltage = <600000>; + }; + }; + + rpmh-regulator-smpa7 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "smpa7"; + S7A: pm855_1_s7: regulator-pm855-1-s7 { + regulator-name = "pm855_1_s7"; + qcom,set = ; + regulator-min-microvolt = <600000>; + regulator-max-microvolt = <600000>; + qcom,init-voltage = <600000>; + }; + }; + + /* PM855_1 S8 = VDD_MODEM supply */ + rpmh-regulator-msslvl { + compatible = "qcom,rpmh-arc-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "mss.lvl"; + S1A_LEVEL: pm855_1_s8_level: regulator-pm855-1-s8-level { + regulator-name = "pm855_1_s8_level"; + qcom,set = ; + regulator-min-microvolt + = ; + regulator-max-microvolt + = ; + qcom,init-voltage-level + = ; + }; + }; + + rpmh-regulator-ldoa1 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldoa1"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + L1A: pm855_1_l1: regulator-pm855-1-l1 { + regulator-name = "pm855_1_l1"; + qcom,set = ; + regulator-min-microvolt = <752000>; + regulator-max-microvolt = <752000>; + qcom,init-voltage = <752000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoa2 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldoa2"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 10000>; + L2A: pm855_1_l2: regulator-pm855-1-l2 { + regulator-name = "pm855_1_l2"; + qcom,set = ; + regulator-min-microvolt = <3072000>; + regulator-max-microvolt = <3072000>; + qcom,init-voltage = <3072000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoa3 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldoa3"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + L3A: pm855_1_l3: regulator-pm855-1-l3 { + regulator-name = "pm855_1_l3"; + qcom,set = ; + regulator-min-microvolt = <480000>; + regulator-max-microvolt = <932000>; + qcom,init-voltage = <480000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoa5 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldoa5"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + + L5A: pm855_1_l5: regulator-pm855-1-l5 { + regulator-name = "pm855_1_l5"; + qcom,set = ; + regulator-min-microvolt = <880000>; + regulator-max-microvolt = <880000>; + qcom,init-voltage = <880000>; + qcom,init-mode = ; + }; + + L5A_AO: pm855_1_l5_ao: regulator-pm855-1-l5-ao { + regulator-name = "pm855_1_l5_ao"; + qcom,set = ; + regulator-min-microvolt = <880000>; + regulator-max-microvolt = <880000>; + qcom,init-voltage = <880000>; + qcom,init-mode = ; + }; + + regulator-pm855-1-l5-so { + regulator-name = "pm855_1_l5_so"; + qcom,set = ; + regulator-min-microvolt = <880000>; + regulator-max-microvolt = <880000>; + qcom,init-voltage = <880000>; + qcom,init-mode = ; + qcom,init-enable = <0>; + }; + }; + + rpmh-regulator-ldoa6 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldoa6"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 10000>; + L6A: pm855_1_l6: regulator-pm855-1-l6 { + regulator-name = "pm855_1_l6"; + qcom,set = ; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + qcom,init-voltage = <1200000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoa7 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldoa7"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + L7A: pm855_1_l7: regulator-pm855-1-l7 { + regulator-name = "pm855_1_l7"; + qcom,set = ; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + qcom,init-voltage = <1800000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoa10 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldoa10"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 10000>; + L10A: pm855_1_l10: regulator-pm855-1-l10 { + regulator-name = "pm855_1_l10"; + qcom,set = ; + regulator-min-microvolt = <2504000>; + regulator-max-microvolt = <2960000>; + qcom,init-voltage = <2504000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoa11 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldoa11"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + L11A: pm855_1_l11: regulator-pm855-1-l11 { + regulator-name = "pm855_1_l11"; + qcom,set = ; + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <800000>; + qcom,init-voltage = <800000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoa12 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldoa12"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + L12A: pm855_1_l12: regulator-pm855-1-l12 { + regulator-name = "pm855_1_l12"; + qcom,set = ; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + qcom,init-voltage = <1800000>; + qcom,init-mode = ; + }; + + L12A_AO: pm855_1_l12_ao: regulator-pm855-1-l12-ao { + regulator-name = "pm855_1_l12_ao"; + qcom,set = ; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + qcom,init-voltage = <1800000>; + qcom,init-mode = ; + }; + + regulator-pm855-1-l12-so { + regulator-name = "pm855_1_l12_so"; + qcom,set = ; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + qcom,init-voltage = <1800000>; + qcom,init-mode = ; + qcom,init-enable = <0>; + }; + }; + + rpmh-regulator-ldoa13 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldoa13"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + L13A: pm855_1_l13: regulator-pm855-1-l13 { + regulator-name = "pm855_1_l13"; + qcom,set = ; + regulator-min-microvolt = <2704000>; + regulator-max-microvolt = <2704000>; + qcom,init-voltage = <2704000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoa15 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldoa15"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + L15A: pm855_1_l15: regulator-pm855-1-l15 { + regulator-name = "pm855_1_l15"; + qcom,set = ; + regulator-min-microvolt = <1704000>; + regulator-max-microvolt = <1704000>; + qcom,init-voltage = <1704000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoa16 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldoa16"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + L16A: pm855_1_l16: regulator-pm855-1-l16 { + regulator-name = "pm855_1_l16"; + qcom,set = ; + regulator-min-microvolt = <2704000>; + regulator-max-microvolt = <2960000>; + qcom,init-voltage = <2704000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoa17 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldoa17"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + L17A: pm855_1_l17: regulator-pm855-1-l17 { + regulator-name = "pm855_1_l17"; + qcom,set = ; + regulator-min-microvolt = <2704000>; + regulator-max-microvolt = <2960000>; + qcom,init-voltage = <2704000>; + qcom,init-mode = ; + }; + }; + + /* PM855_2 S3 + S2 + S1 = 3 phase VDD_GFX supply */ + rpmh-regulator-gfxlvl { + compatible = "qcom,rpmh-arc-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "gfx.lvl"; + S3C_LEVEL: pm855_2_s3_level: regulator-pm855-2-s3-level { + regulator-name = "pm855_2_s3_level"; + qcom,set = ; + regulator-min-microvolt + = ; + regulator-max-microvolt + = ; + qcom,init-voltage-level + = ; + }; + }; + + rpmh-regulator-smpc4 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "smpc4"; + S4C: pm855_2_s4: regulator-pm855-2-s4 { + regulator-name = "pm855_2_s4"; + qcom,set = ; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1400000>; + qcom,init-voltage = <1200000>; + }; + }; + + rpmh-regulator-smpc5 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "smpc5"; + S5C: pm855_2_s5: regulator-pm855-2-s5 { + regulator-name = "pm855_2_s5"; + qcom,set = ; + regulator-min-microvolt = <1824000>; + regulator-max-microvolt = <2040000>; + qcom,init-voltage = <1824000>; + }; + }; + + rpmh-regulator-smpc6 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "smpc6"; + S6C: pm855_2_s6: regulator-pm855-2-s6 { + regulator-name = "pm855_2_s6"; + qcom,set = ; + regulator-min-microvolt = <1128000>; + regulator-max-microvolt = <1128000>; + qcom,init-voltage = <1128000>; + }; + }; + + /* PM855_2 S9 + S8 + S7 = VDD_CX supply */ + rpmh-regulator-cxlvl { + compatible = "qcom,rpmh-arc-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "cx.lvl"; + pm855_2_s9_level-parent-supply = <&VDD_MX_LEVEL>; + pm855_2_s9_level_ao-parent-supply = <&VDD_MX_LEVEL_AO>; + + VDD_CX_LEVEL: VDD_MMCX_LEVEL: + S9C_LEVEL: pm855_2_s9_level: regulator-pm855-2-s9-level { + regulator-name = "pm855_2_s9_level"; + qcom,set = ; + regulator-min-microvolt + = ; + regulator-max-microvolt + = ; + qcom,init-voltage-level + = ; + qcom,min-dropout-voltage-level = <(-1)>; + }; + + VDD_CX_LEVEL_AO: VDD_MMCX_LEVEL_AO: S9C_LEVEL_AO: + pm855_2_s9_level_ao: regulator-pm855-2-s9-level-ao { + regulator-name = "pm855_2_s9_level_ao"; + qcom,set = ; + regulator-min-microvolt + = ; + regulator-max-microvolt + = ; + qcom,init-voltage-level + = ; + qcom,min-dropout-voltage-level = <(-1)>; + }; + + cx_cdev: regulator-cdev { + compatible = "qcom,rpmh-reg-cdev"; + mboxes = <&qmp_aop 0>; + qcom,reg-resource-name = "cx"; + #cooling-cells = <2>; + }; + }; + + /* PM855_2 S10 = VDD_MX supply */ + rpmh-regulator-mxlvl { + compatible = "qcom,rpmh-arc-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "mx.lvl"; + + VDD_MX_LEVEL: + S10C_LEVEL: pm855_2_s10_level: regulator-pm855-2-s10-level { + regulator-name = "pm855_2_s10_level"; + qcom,set = ; + regulator-min-microvolt + = ; + regulator-max-microvolt + = ; + qcom,init-voltage-level + = ; + }; + + VDD_MX_LEVEL_AO: S10C_LEVEL_AO: + pm855_2_s10_level_ao: regulator-pm855-2-s10-level-ao { + regulator-name = "pm855_2_s10_level_ao"; + qcom,set = ; + regulator-min-microvolt + = ; + regulator-max-microvolt + = ; + qcom,init-voltage-level + = ; + }; + + mx_cdev: mx-cdev-lvl { + compatible = "qcom,regulator-cooling-device"; + regulator-cdev-supply = <&VDD_MX_LEVEL>; + regulator-levels = ; + #cooling-cells = <2>; + }; + }; + + rpmh-regulator-ldoc1 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldoc1"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + L1C: pm855_2_l1: regulator-pm855-2-l1 { + regulator-name = "pm855_2_l1"; + qcom,set = ; + regulator-min-microvolt = <1304000>; + regulator-max-microvolt = <1304000>; + qcom,init-voltage = <1304000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoc2 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldoc2"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + L2C: pm855_2_l2: regulator-pm855-2-l2 { + regulator-name = "pm855_2_l2"; + qcom,set = ; + regulator-min-microvolt = <1704000>; + regulator-max-microvolt = <2928000>; + qcom,init-voltage = <1704000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoc5 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldoc5"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + L5C: pm855_2_l5: regulator-pm855-2-l5 { + regulator-name = "pm855_2_l5"; + qcom,set = ; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + qcom,init-voltage = <1200000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoc7 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldoc7"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + L7C: pm855_2_l7: regulator-pm855-2-l7 { + regulator-name = "pm855_2_l7"; + qcom,set = ; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + qcom,init-voltage = <1800000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoc8 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldoc8"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + L8C: pm855_2_l8: regulator-pm855-2-l8 { + regulator-name = "pm855_2_l8"; + qcom,set = ; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + qcom,init-voltage = <1200000>; + qcom,init-mode = ; + }; + }; + + /* PM855_2 L11 = VDD_EBI supply */ + rpmh-regulator-ebilvl { + compatible = "qcom,rpmh-arc-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ebi.lvl"; + L11C_LEVEL: pm855_2_l11_level: regulator-pm855-2-l11-level { + regulator-name = "pm855_2_l11_level"; + qcom,set = ; + regulator-min-microvolt + = ; + regulator-max-microvolt + = ; + qcom,init-voltage-level + = ; + }; + + ebi_cdev: regulator-cdev { + compatible = "qcom,rpmh-reg-cdev"; + mboxes = <&qmp_aop 0>; + qcom,reg-resource-name = "ebi"; + #cooling-cells = <2>; + }; + }; + + rpmh-regulator-ldoc12 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldoc12"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + L12C: pm855_2_l12: regulator-pm855-2-l12 { + regulator-name = "pm855_2_l12"; + qcom,set = ; + regulator-min-microvolt = <1704000>; + regulator-max-microvolt = <1888000>; + qcom,init-voltage = <1704000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoc13 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldoc13"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + L13C: pm855_2_l13: regulator-pm855-2-l13 { + regulator-name = "pm855_2_l13"; + qcom,set = ; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <2960000>; + qcom,init-voltage = <1800000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoc16 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldoc16"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + L16C: pm855_2_l16: regulator-pm855-2-l16 { + regulator-name = "pm855_2_l16"; + qcom,set = ; + regulator-min-microvolt = <2704000>; + regulator-max-microvolt = <3008000>; + qcom,init-voltage = <2704000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoc18 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldoc18"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + proxy-supply = <&pm855_2_l18>; + L18C: pm855_2_l18: regulator-pm855-2-l18 { + regulator-name = "pm855_2_l18"; + qcom,set = ; + regulator-min-microvolt = <880000>; + regulator-max-microvolt = <880000>; + qcom,proxy-consumer-enable; + qcom,proxy-consumer-current = <23800>; + qcom,init-voltage = <880000>; + qcom,init-mode = ; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/sm8150-auto.dtsi b/arch/arm64/boot/dts/qcom/sm8150-auto.dtsi index fdf597af85be..256c7fd01c79 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-auto.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-auto.dtsi @@ -17,3 +17,286 @@ qcom,msm-name = "SM8150 AUTO"; qcom,msm-id = <362 0x10000>; }; + +/* Remove regulator nodes specific to SM8150 */ +&soc { + /delete-node/ regulator-pm855-s4; + /delete-node/ rpmh-regulator-msslvl; + /delete-node/ rpmh-regulator-smpa2; + /delete-node/ rpmh-regulator-ebilvl; + /delete-node/ rpmh-regulator-smpa5; + /delete-node/ rpmh-regulator-smpa6; + /delete-node/ rpmh-regulator-ldoa1; + /delete-node/ rpmh-regulator-ldoa2; + /delete-node/ rpmh-regulator-ldoa3; + /delete-node/ rpmh-regulator-lmxlvl; + /delete-node/ rpmh-regulator-ldoa5; + /delete-node/ rpmh-regulator-ldoa6; + /delete-node/ rpmh-regulator-ldoa7; + /delete-node/ rpmh-regulator-lcxlvl; + /delete-node/ rpmh-regulator-ldoa9; + /delete-node/ rpmh-regulator-ldoa10; + /delete-node/ rpmh-regulator-ldoa11; + /delete-node/ rpmh-regulator-ldoa12; + /delete-node/ rpmh-regulator-ldoa13; + /delete-node/ rpmh-regulator-ldoa14; + /delete-node/ rpmh-regulator-ldoa15; + /delete-node/ rpmh-regulator-ldoa16; + /delete-node/ rpmh-regulator-ldoa17; + /delete-node/ rpmh-regulator-smpc1; + /delete-node/ rpmh-regulator-gfxlvl; + /delete-node/ rpmh-regulator-mxlvl; + /delete-node/ rpmh-regulator-mmcxlvl; + /delete-node/ rpmh-regulator-cxlvl; + /delete-node/ rpmh-regulator-smpc8; + /delete-node/ rpmh-regulator-ldoc1; + /delete-node/ rpmh-regulator-ldoc2; + /delete-node/ rpmh-regulator-ldoc3; + /delete-node/ rpmh-regulator-ldoc4; + /delete-node/ rpmh-regulator-ldoc5; + /delete-node/ rpmh-regulator-ldoc6; + /delete-node/ rpmh-regulator-ldoc7; + /delete-node/ rpmh-regulator-ldoc8; + /delete-node/ rpmh-regulator-ldoc9; + /delete-node/ rpmh-regulator-ldoc10; + /delete-node/ rpmh-regulator-ldoc11; + /delete-node/ rpmh-regulator-bobc1; + /delete-node/ rpmh-regulator-smpf2; + /delete-node/ rpmh-regulator-ldof2; + /delete-node/ rpmh-regulator-ldof5; + /delete-node/ rpmh-regulator-ldof6; +}; + +/* Add regulator nodes specific to SM8150 Auto */ +#include "sm8150-auto-regulator.dtsi" + +&cam_csiphy0 { + mipi-csi-vdd-supply = <&pm855_2_l8>; +}; + +&cam_csiphy1 { + mipi-csi-vdd-supply = <&pm855_2_l8>; +}; + +&cam_csiphy2 { + mipi-csi-vdd-supply = <&pm855_2_l8>; +}; + +&cam_csiphy3 { + mipi-csi-vdd-supply = <&pm855_2_l8>; +}; + +&pcie0 { + vreg-1.8-supply = <&pm855_2_l8>; + vreg-0.9-supply = <&pm855_2_l18>; +}; + +&pcie1 { + vreg-1.8-supply = <&pm855_2_l8>; + vreg-0.9-supply = <&pm855_2_l18>; +}; + +&mdss_dsi_phy0 { + vdda-0p9-supply = <&pm855_2_l18>; +}; + +&mdss_dsi_phy1 { + vdda-0p9-supply = <&pm855_2_l18>; +}; + +&mdss_dsi0 { + vdda-1p2-supply = <&pm855_2_l8>; +}; + +&mdss_dsi1 { + vdda-1p2-supply = <&pm855_2_l8>; +}; + +&sde_dp { + vdda-1p2-supply = <&pm855_2_l8>; + vdda-0p9-supply = <&pm855_2_l18>; +}; + +&lmh_dcvs1 { + isens_vref_0p8-supply = <&pm855_1_l5_ao>; + isens_vref_1p8-supply = <&pm855_1_l12_ao>; +}; + +&usb2_phy0 { + vdd-supply = <&pm855_1_l5>; + vdda18-supply = <&pm855_1_l12>; + vdda33-supply = <&pm855_1_l2>; +}; + +&usb_qmp_dp_phy { + vdd-supply = <&pm855_1_l5>; + core-supply = <&pm855_2_l8>; +}; + +&icnss { + vdd-cx-mx-supply = <&pm855_1_l1>; + vdd-1.8-xo-supply = <&pm855_1_l7>; + vdd-1.3-rfa-supply = <&pm855_2_l1>; + /delete-property/ vdd-3.3-ch0-supply; +}; + +&pil_ssc { + vdd_cx-supply = <&VDD_CX_LEVEL>; + vdd_mx-supply = <&VDD_MX_LEVEL>; +}; + +&pil_modem { + vdd_mss-supply = <&pm855_1_s8_level>; +}; + +&wil6210 { + /delete-property/ vddio-supply; +}; + +&gpu_gx_gdsc { + parent-supply = <&pm855_2_s3_level>; + vdd_parent-supply = <&pm855_2_s3_level>; +}; + +&thermal_zones { + aoss0-lowf { + cooling-maps { + /delete-node/ mmcx_vdd_cdev; + }; + }; + cpu-0-0-lowf { + cooling-maps { + /delete-node/ mmcx_vdd_cdev; + }; + }; + cpu-0-1-lowf { + cooling-maps { + /delete-node/ mmcx_vdd_cdev; + }; + }; + cpu-0-2-lowf { + cooling-maps { + /delete-node/ mmcx_vdd_cdev; + }; + }; + cpu-0-3-lowf { + cooling-maps { + /delete-node/ mmcx_vdd_cdev; + }; + }; + cpuss-0-lowf { + cooling-maps { + /delete-node/ mmcx_vdd_cdev; + }; + }; + cpuss-1-lowf { + cooling-maps { + /delete-node/ mmcx_vdd_cdev; + }; + }; + cpu-1-0-lowf { + cooling-maps { + /delete-node/ mmcx_vdd_cdev; + }; + }; + cpu-1-1-lowf { + cooling-maps { + /delete-node/ mmcx_vdd_cdev; + }; + }; + cpu-1-2-lowf { + cooling-maps { + /delete-node/ mmcx_vdd_cdev; + }; + }; + cpu-1-3-lowf { + cooling-maps { + /delete-node/ mmcx_vdd_cdev; + }; + }; + cpu-1-4-lowf { + cooling-maps { + /delete-node/ mmcx_vdd_cdev; + }; + }; + cpu-1-5-lowf { + cooling-maps { + /delete-node/ mmcx_vdd_cdev; + }; + }; + cpu-1-6-lowf { + cooling-maps { + /delete-node/ mmcx_vdd_cdev; + }; + }; + cpu-1-7-lowf { + cooling-maps { + /delete-node/ mmcx_vdd_cdev; + }; + }; + gpuss-0-lowf { + cooling-maps { + /delete-node/ mmcx_vdd_cdev; + }; + }; + aoss-1-lowf { + cooling-maps { + /delete-node/ mmcx_vdd_cdev; + }; + }; + cwlan-lowf { + cooling-maps { + /delete-node/ mmcx_vdd_cdev; + }; + }; + video-lowf { + cooling-maps { + /delete-node/ mmcx_vdd_cdev; + }; + }; + ddr-lowf { + cooling-maps { + /delete-node/ mmcx_vdd_cdev; + }; + }; + q6-hvx-lowf { + cooling-maps { + /delete-node/ mmcx_vdd_cdev; + }; + }; + camera-lowf { + cooling-maps { + /delete-node/ mmcx_vdd_cdev; + }; + }; + cmpss-lowf { + cooling-maps { + /delete-node/ mmcx_vdd_cdev; + }; + }; + mdm-core-lowf { + cooling-maps { + /delete-node/ mmcx_vdd_cdev; + }; + }; + npu-lowf { + cooling-maps { + /delete-node/ mmcx_vdd_cdev; + }; + }; + mdm-vec-lowf { + cooling-maps { + /delete-node/ mmcx_vdd_cdev; + }; + }; + mdm-scl-lowf { + cooling-maps { + /delete-node/ mmcx_vdd_cdev; + }; + }; + gpuss-1-lowf { + cooling-maps { + /delete-node/ mmcx_vdd_cdev; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/sm8150.dtsi b/arch/arm64/boot/dts/qcom/sm8150.dtsi index c48ad94ac3d0..4cd0eafe8680 100644 --- a/arch/arm64/boot/dts/qcom/sm8150.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150.dtsi @@ -1585,7 +1585,7 @@ mbox-names = "adsp-pil"; }; - qcom,ssc@5c00000 { + pil_ssc: qcom,ssc@5c00000 { compatible = "qcom,pil-tz-generic"; reg = <0x5c00000 0x4000>; @@ -3306,7 +3306,7 @@ mbox-names = "aop"; }; - qcom,icnss@18800000 { + icnss: qcom,icnss@18800000 { compatible = "qcom,icnss"; reg = <0x18800000 0x800000>, <0xa0000000 0x10000000>, -- GitLab From 02e1552facb643e8d57932a964a4e2302a95c876 Mon Sep 17 00:00:00 2001 From: David Collins Date: Fri, 27 Apr 2018 16:02:57 -0700 Subject: [PATCH 1343/1635] ARM: dts: msm: add PM855 PMIC devices for sm8150-auto Add PMIC devices for the primary PM855 and secondary PM855 chips found on sm8150-auto boards. Change-Id: I8c6ac5601e3b2205070822d32b062741502b1f5c Signed-off-by: David Collins --- arch/arm64/boot/dts/qcom/pm855.dtsi | 1 + .../boot/dts/qcom/sm8150-auto-adp-star.dtsi | 2 + .../dts/qcom/sm8150-auto-pmic-overlay.dtsi | 89 +++++++++++++++++++ 3 files changed, 92 insertions(+) create mode 100644 arch/arm64/boot/dts/qcom/sm8150-auto-pmic-overlay.dtsi diff --git a/arch/arm64/boot/dts/qcom/pm855.dtsi b/arch/arm64/boot/dts/qcom/pm855.dtsi index dba9da14b9ac..1797ef3ac5e4 100644 --- a/arch/arm64/boot/dts/qcom/pm855.dtsi +++ b/arch/arm64/boot/dts/qcom/pm855.dtsi @@ -11,6 +11,7 @@ * GNU General Public License for more details. */ +#include #include #include #include diff --git a/arch/arm64/boot/dts/qcom/sm8150-auto-adp-star.dtsi b/arch/arm64/boot/dts/qcom/sm8150-auto-adp-star.dtsi index a305b5cdb72b..92896f741968 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-auto-adp-star.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-auto-adp-star.dtsi @@ -10,6 +10,8 @@ * GNU General Public License for more details. */ +#include "sm8150-auto-pmic-overlay.dtsi" + &soc { qcom,lpass@17300000 { status = "disabled"; diff --git a/arch/arm64/boot/dts/qcom/sm8150-auto-pmic-overlay.dtsi b/arch/arm64/boot/dts/qcom/sm8150-auto-pmic-overlay.dtsi new file mode 100644 index 000000000000..f281bd57ecf4 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sm8150-auto-pmic-overlay.dtsi @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "pm855.dtsi" + +pm855_1_tz: &pm855_tz { +}; + +pm855_1_clkdiv: &pm855_clkdiv { + clock-output-names = "pm855_1_div_clk1", "pm855_1_div_clk2"; +}; + +pm855_1_rtc: &pm855_rtc { +}; + +pm855_1_gpios: &pm855_gpios { + interrupts = <0x0 0xc0 0 IRQ_TYPE_NONE>, + <0x0 0xc2 0 IRQ_TYPE_NONE>, + <0x0 0xc3 0 IRQ_TYPE_NONE>, + <0x0 0xc5 0 IRQ_TYPE_NONE>, + <0x0 0xc8 0 IRQ_TYPE_NONE>, + <0x0 0xc9 0 IRQ_TYPE_NONE>; + interrupt-names = "pm855_1_gpio1", "pm855_1_gpio3", + "pm855_1_gpio4", "pm855_1_gpio6", + "pm855_1_gpio9", "pm855_1_gpio10"; + qcom,gpios-disallowed = <2 5 7 8>; +}; + +/* PM855_2: */ +&spmi_bus { + qcom,pm855@4 { + compatible = "qcom,spmi-pmic"; + reg = <0x4 SPMI_USID>; + #address-cells = <1>; + #size-cells = <1>; + + qcom,power-on@800 { + compatible = "qcom,qpnp-power-on"; + reg = <0x800 0x100>; + }; + + pm855_2_clkdiv: clock-controller@5b00 { + compatible = "qcom,spmi-clkdiv"; + reg = <0x5b00 0x200>; + #clock-cells = <1>; + qcom,num-clkdivs = <2>; + clock-output-names = "pm855_2_div_clk1", + "pm855_2_div_clk2"; + clocks = <&clock_rpmh RPMH_CXO_CLK>; + clock-names = "xo"; + }; + + pm855_2_gpios: pinctrl@c000 { + compatible = "qcom,spmi-gpio"; + reg = <0xc000 0xa00>; + interrupts = <0x4 0xc0 0 IRQ_TYPE_NONE>, + <0x4 0xc2 0 IRQ_TYPE_NONE>, + <0x4 0xc3 0 IRQ_TYPE_NONE>, + <0x4 0xc5 0 IRQ_TYPE_NONE>, + <0x4 0xc7 0 IRQ_TYPE_NONE>, + <0x4 0xc8 0 IRQ_TYPE_NONE>, + <0x4 0xc9 0 IRQ_TYPE_NONE>; + interrupt-names = "pm855_2_gpio1", "pm855_2_gpio3", + "pm855_2_gpio4", "pm855_2_gpio6", + "pm855_2_gpio8", "pm855_2_gpio9", + "pm855_2_gpio10"; + gpio-controller; + #gpio-cells = <2>; + qcom,gpios-disallowed = <2 5 7>; + }; + }; + + qcom,pm855@5 { + compatible ="qcom,spmi-pmic"; + reg = <0x5 SPMI_USID>; + #address-cells = <1>; + #size-cells = <1>; + }; +}; -- GitLab From d65ddfcbf3592c2651a2b12ca331d4ad1c14af11 Mon Sep 17 00:00:00 2001 From: David Collins Date: Fri, 27 Apr 2018 17:19:38 -0700 Subject: [PATCH 1344/1635] ARM: dts: msm: add gpio_key devices for buttons on sm8150-auto ADP STAR Add pinctrl configurations for home and volume up buttons which utilize PM855_1 GPIOs 1 and 6 respectively. Add gpio_key devices for these buttons on SM8150 Auto ADP STAR board. Change-Id: I62e291cdee2c2e089ab1bf8587a98d6b57162925 Signed-off-by: David Collins --- .../boot/dts/qcom/sm8150-auto-adp-star.dtsi | 32 +++++++++++++++++++ .../dts/qcom/sm8150-auto-pmic-overlay.dtsi | 23 +++++++++++++ 2 files changed, 55 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sm8150-auto-adp-star.dtsi b/arch/arm64/boot/dts/qcom/sm8150-auto-adp-star.dtsi index 92896f741968..cc9662c46445 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-auto-adp-star.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-auto-adp-star.dtsi @@ -10,6 +10,9 @@ * GNU General Public License for more details. */ +#include +#include + #include "sm8150-auto-pmic-overlay.dtsi" &soc { @@ -26,4 +29,33 @@ status = "disabled"; }; }; + + gpio_keys { + compatible = "gpio-keys"; + label = "gpio-keys"; + + pinctrl-names = "default"; + pinctrl-0 = <&key_home_default + &key_vol_up_default>; + + home { + label = "home"; + gpios = <&pm855_1_gpios 1 GPIO_ACTIVE_LOW>; + linux,input-type = <1>; + linux,code = ; + gpio-key,wakeup; + debounce-interval = <15>; + linux,can-disable; + }; + + vol_up { + label = "volume_up"; + gpios = <&pm855_1_gpios 6 GPIO_ACTIVE_LOW>; + linux,input-type = <1>; + linux,code = ; + gpio-key,wakeup; + debounce-interval = <15>; + linux,can-disable; + }; + }; }; diff --git a/arch/arm64/boot/dts/qcom/sm8150-auto-pmic-overlay.dtsi b/arch/arm64/boot/dts/qcom/sm8150-auto-pmic-overlay.dtsi index f281bd57ecf4..59cef9fed9e2 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-auto-pmic-overlay.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-auto-pmic-overlay.dtsi @@ -87,3 +87,26 @@ pm855_1_gpios: &pm855_gpios { #size-cells = <1>; }; }; + +/* PMIC GPIO pin control configurations: */ +&pm855_1_gpios { + key_home { + key_home_default: key_home_default { + pins = "gpio1"; + function = "normal"; + input-enable; + bias-pull-up; + power-source = <0>; + }; + }; + + key_vol_up { + key_vol_up_default: key_vol_up_default { + pins = "gpio6"; + function = "normal"; + input-enable; + bias-pull-up; + power-source = <1>; + }; + }; +}; -- GitLab From 74219b399456f78d2ca793fbd3d5284f5e81c8b1 Mon Sep 17 00:00:00 2001 From: Abhijit Kulkarni Date: Wed, 2 May 2018 10:29:28 -0700 Subject: [PATCH 1345/1635] drm/msm/sde: fix restore handling for encoders When physical cmd mode encoders are restored after power collapse the interface flush bits get cleared when the incoming commit is triggered. This change fixes the trigger kickoff pending functionality by checking if a restore is in progress. Hw prepare is handled during the restore phase. Change-Id: I45253c604edf303eb6fbc3e7fb1110e50b67f1f8 Signed-off-by: Abhijit Kulkarni Signed-off-by: Veera Sundaram Sankaran --- drivers/gpu/drm/msm/sde/sde_encoder.c | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/msm/sde/sde_encoder.c b/drivers/gpu/drm/msm/sde/sde_encoder.c index 59cd95b35b0b..d1333d4271b7 100644 --- a/drivers/gpu/drm/msm/sde/sde_encoder.c +++ b/drivers/gpu/drm/msm/sde/sde_encoder.c @@ -205,6 +205,7 @@ enum sde_enc_rc_states { * @input_handler: handler for input device events * @topology: topology of the display * @vblank_enabled: boolean to track userspace vblank vote + * @idle_pc_restore: flag to indicate idle_pc_restore happened * @rsc_config: rsc configuration for display vtotal, fps, etc. * @cur_conn_roi: current connector roi * @prv_conn_roi: previous connector roi to optimize if unchanged @@ -251,6 +252,7 @@ struct sde_encoder_virt { struct input_handler *input_handler; struct msm_display_topology topology; bool vblank_enabled; + bool idle_pc_restore; struct sde_rsc_cmd_config rsc_config; struct sde_rect cur_conn_roi; @@ -2713,11 +2715,18 @@ void sde_encoder_virt_restore(struct drm_encoder *drm_enc) sde_enc = to_sde_encoder_virt(drm_enc); memset(&sde_enc->cur_master->intf_cfg_v1, 0, sizeof(sde_enc->cur_master->intf_cfg_v1)); + sde_enc->idle_pc_restore = true; for (i = 0; i < sde_enc->num_phys_encs; i++) { struct sde_encoder_phys *phys = sde_enc->phys_encs[i]; - if (phys && (phys != sde_enc->cur_master) && phys->ops.restore) + if (!phys) + continue; + + if (phys->hw_ctl && phys->hw_ctl->ops.clear_pending_flush) + phys->hw_ctl->ops.clear_pending_flush(phys->hw_ctl); + + if ((phys != sde_enc->cur_master) && phys->ops.restore) phys->ops.restore(phys); } @@ -3584,7 +3593,13 @@ void sde_encoder_trigger_kickoff_pending(struct drm_encoder *drm_enc) if (phys && phys->hw_ctl) { ctl = phys->hw_ctl; - if (ctl->ops.clear_pending_flush) + /* + * avoid clearing the pending flush during the first + * frame update after idle power collpase as the + * restore path would have updated the pending flush + */ + if (!sde_enc->idle_pc_restore && + ctl->ops.clear_pending_flush) ctl->ops.clear_pending_flush(ctl); /* update only for command mode primary ctl */ @@ -3594,6 +3609,7 @@ void sde_encoder_trigger_kickoff_pending(struct drm_encoder *drm_enc) ctl->ops.trigger_pending(ctl); } } + sde_enc->idle_pc_restore = false; } static void _sde_encoder_setup_dither(struct sde_encoder_phys *phys) -- GitLab From 2e1aa2a25a58fdb54e991f2e54c9c4dd466d6a36 Mon Sep 17 00:00:00 2001 From: Abhijit Kulkarni Date: Tue, 3 Apr 2018 10:28:48 -0700 Subject: [PATCH 1346/1635] drm/msm: disp rsc sequence update This change updates the mode2 entry and exit sequence for sdm8150. This is based on recommendatation in hardware programming guide recommendation. Change-Id: I131678ff0c1293623e1e2e6c50acf0a454261aef Signed-off-by: Abhijit Kulkarni --- drivers/gpu/drm/msm/sde_power_handle.c | 52 ++++++++++++-------------- drivers/gpu/drm/msm/sde_rsc_hw.c | 42 +++++++++++---------- 2 files changed, 46 insertions(+), 48 deletions(-) diff --git a/drivers/gpu/drm/msm/sde_power_handle.c b/drivers/gpu/drm/msm/sde_power_handle.c index 40542abf4e0c..29c868eebecf 100644 --- a/drivers/gpu/drm/msm/sde_power_handle.c +++ b/drivers/gpu/drm/msm/sde_power_handle.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -56,12 +56,9 @@ static void sde_power_event_trigger_locked(struct sde_power_handle *phandle, } } -static int sde_power_rsc_update(struct sde_power_handle *phandle, bool enable) +static inline void sde_power_rsc_client_init(struct sde_power_handle *phandle) { - u32 rsc_state; - int ret = 0; - - /* creates the rsc client on the first enable */ + /* creates the rsc client */ if (!phandle->rsc_client_init) { phandle->rsc_client = sde_rsc_client_create(SDE_RSC_INDEX, "sde_power_handle", false); @@ -72,6 +69,12 @@ static int sde_power_rsc_update(struct sde_power_handle *phandle, bool enable) } phandle->rsc_client_init = true; } +} + +static int sde_power_rsc_update(struct sde_power_handle *phandle, bool enable) +{ + u32 rsc_state; + int ret = 0; rsc_state = enable ? SDE_RSC_CLK_STATE : SDE_RSC_IDLE_STATE; @@ -890,6 +893,9 @@ int sde_power_resource_enable(struct sde_power_handle *phandle, if (!changed) goto end; + /* RSC client init */ + sde_power_rsc_client_init(phandle); + if (enable) { sde_power_event_trigger_locked(phandle, SDE_POWER_EVENT_PRE_ENABLE); @@ -903,21 +909,11 @@ int sde_power_resource_enable(struct sde_power_handle *phandle, goto data_bus_hdl_err; } } - /* - * - When the target is RSCC enabled, regulator should - * be enabled by the s/w only for the first time during - * bootup. After that, RSCC hardware takes care of enabling/ - * disabling it. - * - When the target is not RSCC enabled, regulator should - * be totally handled by the software. - */ - if (!phandle->rsc_client) { - rc = msm_dss_enable_vreg(mp->vreg_config, mp->num_vreg, - enable); - if (rc) { - pr_err("failed to enable vregs rc=%d\n", rc); - goto vreg_err; - } + rc = msm_dss_enable_vreg(mp->vreg_config, mp->num_vreg, + enable); + if (rc) { + pr_err("failed to enable vregs rc=%d\n", rc); + goto vreg_err; } rc = sde_power_reg_bus_update(phandle->reg_bus_hdl, @@ -927,13 +923,13 @@ int sde_power_resource_enable(struct sde_power_handle *phandle, goto reg_bus_hdl_err; } + SDE_EVT32_VERBOSE(enable, SDE_EVTLOG_FUNC_CASE1); rc = sde_power_rsc_update(phandle, true); if (rc) { pr_err("failed to update rsc\n"); goto rsc_err; } - SDE_EVT32_VERBOSE(enable, SDE_EVTLOG_FUNC_CASE1); rc = msm_dss_enable_clk(mp->clk_config, mp->num_clk, enable); if (rc) { pr_err("clock enable failed rc:%d\n", rc); @@ -948,16 +944,15 @@ int sde_power_resource_enable(struct sde_power_handle *phandle, SDE_POWER_EVENT_PRE_DISABLE); SDE_EVT32_VERBOSE(enable, SDE_EVTLOG_FUNC_CASE2); - msm_dss_enable_clk(mp->clk_config, mp->num_clk, enable); - sde_power_rsc_update(phandle, false); + msm_dss_enable_clk(mp->clk_config, mp->num_clk, enable); + sde_power_reg_bus_update(phandle->reg_bus_hdl, max_usecase_ndx); - if (!phandle->rsc_client) - msm_dss_enable_vreg(mp->vreg_config, mp->num_vreg, - enable); + msm_dss_enable_vreg(mp->vreg_config, mp->num_vreg, enable); + for (i = 0 ; i < SDE_POWER_HANDLE_DBUS_ID_MAX; i++) sde_power_data_bus_update(&phandle->data_bus_handle[i], enable); @@ -977,8 +972,7 @@ int sde_power_resource_enable(struct sde_power_handle *phandle, rsc_err: sde_power_reg_bus_update(phandle->reg_bus_hdl, prev_usecase_ndx); reg_bus_hdl_err: - if (!phandle->rsc_client) - msm_dss_enable_vreg(mp->vreg_config, mp->num_vreg, 0); + msm_dss_enable_vreg(mp->vreg_config, mp->num_vreg, 0); vreg_err: for (i = 0 ; i < SDE_POWER_HANDLE_DBUS_ID_MAX; i++) sde_power_data_bus_update(&phandle->data_bus_handle[i], 0); diff --git a/drivers/gpu/drm/msm/sde_rsc_hw.c b/drivers/gpu/drm/msm/sde_rsc_hw.c index 35f1d55e1777..a87ae69a0847 100644 --- a/drivers/gpu/drm/msm/sde_rsc_hw.c +++ b/drivers/gpu/drm/msm/sde_rsc_hw.c @@ -191,39 +191,40 @@ static int rsc_hw_seq_memory_init_v2(struct sde_rsc_priv *rsc) 0x38bb9ebe, rsc->debug_mode); dss_reg_w(&rsc->drv_io, SDE_RSCC_SEQ_MEM_0_DRV0 + 0x10, 0xbeff39e0, rsc->debug_mode); - - /* Mode - 2 sequence */ dss_reg_w(&rsc->drv_io, SDE_RSCC_SEQ_MEM_0_DRV0 + 0x14, 0x20209b9e, rsc->debug_mode); + + /* Mode - 2 sequence */ dss_reg_w(&rsc->drv_io, SDE_RSCC_SEQ_MEM_0_DRV0 + 0x18, - 0xfab9baa0, rsc->debug_mode); + 0xb9bae5a0, rsc->debug_mode); dss_reg_w(&rsc->drv_io, SDE_RSCC_SEQ_MEM_0_DRV0 + 0x1c, - 0xfebdbbf9, rsc->debug_mode); + 0xbdbbf9fa, rsc->debug_mode); dss_reg_w(&rsc->drv_io, SDE_RSCC_SEQ_MEM_0_DRV0 + 0x20, - 0xa138999a, rsc->debug_mode); + 0x38999afe, rsc->debug_mode); dss_reg_w(&rsc->drv_io, SDE_RSCC_SEQ_MEM_0_DRV0 + 0x24, - 0xa2e081e1, rsc->debug_mode); + 0xac81e1a1, rsc->debug_mode); dss_reg_w(&rsc->drv_io, SDE_RSCC_SEQ_MEM_0_DRV0 + 0x28, - 0x9d3982e2, rsc->debug_mode); - - /* tcs sleep & wake sequence */ + 0x82e2a2e0, rsc->debug_mode); dss_reg_w(&rsc->drv_io, SDE_RSCC_SEQ_MEM_0_DRV0 + 0x2c, - 0x20209bfd, rsc->debug_mode); + 0x8cfd9d39, rsc->debug_mode); dss_reg_w(&rsc->drv_io, SDE_RSCC_SEQ_MEM_0_DRV0 + 0x30, - 0x01a6fcbc, rsc->debug_mode); + 0xbc20209b, rsc->debug_mode); + + /* tcs sleep & wake sequence */ dss_reg_w(&rsc->drv_io, SDE_RSCC_SEQ_MEM_0_DRV0 + 0x34, - 0x20209ce6, rsc->debug_mode); + 0xe601a6fc, rsc->debug_mode); dss_reg_w(&rsc->drv_io, SDE_RSCC_SEQ_MEM_0_DRV0 + 0x38, - 0x01a7fcbc, rsc->debug_mode); + 0xbc20209c, rsc->debug_mode); dss_reg_w(&rsc->drv_io, SDE_RSCC_SEQ_MEM_0_DRV0 + 0x3c, - 0x00209ce7, rsc->debug_mode); - + 0xe701a7fc, rsc->debug_mode); + dss_reg_w(&rsc->drv_io, SDE_RSCC_SEQ_MEM_0_DRV0 + 0x40, + 0x0000209c, rsc->debug_mode); /* branch address */ dss_reg_w(&rsc->drv_io, SDE_RSCC_SEQ_CFG_BR_ADDR_0_DRV0, - 0x30, rsc->debug_mode); + 0x33, rsc->debug_mode); dss_reg_w(&rsc->drv_io, SDE_RSCC_SEQ_CFG_BR_ADDR_1_DRV0, - 0x38, rsc->debug_mode); + 0x3b, rsc->debug_mode); /* start address */ dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_OVERRIDE_CTRL_DRV0, @@ -550,8 +551,11 @@ static int sde_rsc_mode2_entry(struct sde_rsc_priv *rsc) } if (rc) { - pr_err("mdss gdsc power down failed rc:%d\n", rc); - SDE_EVT32(rc, SDE_EVTLOG_ERROR); + reg = dss_reg_r(&rsc->drv_io, + SDE_RSCC_SEQ_PROGRAM_COUNTER, rsc->debug_mode); + pr_err("mdss gdsc power down failed, instruction:0x%x, rc:%d\n", + reg, rc); + SDE_EVT32(rc, reg, SDE_EVTLOG_ERROR); goto end; } -- GitLab From 90a540c973e33e6785657977b40829fead0aa344 Mon Sep 17 00:00:00 2001 From: Harshdeep Dhatt Date: Wed, 25 Apr 2018 12:35:53 -0600 Subject: [PATCH 1347/1635] msm: kgsl: Use del_timer() where appropriate The real use of del_timer_sync() comes in cases where we want to free shared resources, shared with the timer handler. In those cases, we want to make sure that if the timer handler was running on another cpu, it must finish executing before we go ahead with free'ing the shared resources. So basically, to avoid a use-after-free. However, in this code path, we are not going to destroy the shared resources. So, here we don't need to wait for timer to finish, we can return immediately. Change-Id: I9bf7a6b215f5ba86049f5df6bc82eed6958cf89d Signed-off-by: Harshdeep Dhatt --- drivers/gpu/msm/kgsl_drawobj.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/msm/kgsl_drawobj.c b/drivers/gpu/msm/kgsl_drawobj.c index 527c68f74344..b69a2f03896e 100644 --- a/drivers/gpu/msm/kgsl_drawobj.c +++ b/drivers/gpu/msm/kgsl_drawobj.c @@ -180,7 +180,7 @@ static bool drawobj_sync_expire(struct kgsl_device *device, * for dispatch */ if (!kgsl_drawobj_events_pending(event->syncobj)) { - del_timer_sync(&syncobj->timer); + del_timer(&syncobj->timer); if (device->ftbl->drawctxt_sched) device->ftbl->drawctxt_sched(device, -- GitLab From a98b7115c2b873874642f4ab073ea8f2b34527f0 Mon Sep 17 00:00:00 2001 From: Chris Lew Date: Wed, 2 May 2018 11:32:54 -0700 Subject: [PATCH 1348/1635] qrtr: Add support for multiple nodes on a single ept An ept can be associated with multiple node ids in network. The node tree should keep track of how to send to a specific node id where as the node list should keep track of all the adjacent nodes in the network. Use the node list to broadcast control messages to adjacent nodes. Change-Id: If0f4828da149b6e590525518a8410f497f5e3894 Signed-off-by: Chris Lew --- net/qrtr/qrtr.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/net/qrtr/qrtr.c b/net/qrtr/qrtr.c index 8273f44b27af..18c0bcae5124 100644 --- a/net/qrtr/qrtr.c +++ b/net/qrtr/qrtr.c @@ -150,9 +150,15 @@ static int qrtr_bcast_enqueue(struct qrtr_node *node, struct sk_buff *skb, static void __qrtr_node_release(struct kref *kref) { struct qrtr_node *node = container_of(kref, struct qrtr_node, ref); + struct radix_tree_iter iter; + void **slot; - if (node->nid != QRTR_EP_NID_AUTO) - radix_tree_delete(&qrtr_nodes, node->nid); + if (node->nid != QRTR_EP_NID_AUTO) { + radix_tree_for_each_slot(slot, &qrtr_nodes, &iter, 0) { + if (node == *slot) + radix_tree_delete(&qrtr_nodes, iter.index); + } + } list_del(&node->item); mutex_unlock(&qrtr_node_lock); @@ -232,12 +238,15 @@ static struct qrtr_node *qrtr_node_lookup(unsigned int nid) */ static void qrtr_node_assign(struct qrtr_node *node, unsigned int nid) { - if (node->nid != QRTR_EP_NID_AUTO || nid == QRTR_EP_NID_AUTO) + if (nid == QRTR_EP_NID_AUTO) return; mutex_lock(&qrtr_node_lock); - radix_tree_insert(&qrtr_nodes, nid, node); - node->nid = nid; + if (!radix_tree_lookup(&qrtr_nodes, nid)) + radix_tree_insert(&qrtr_nodes, nid, node); + + if (node->nid == QRTR_EP_NID_AUTO) + node->nid = nid; mutex_unlock(&qrtr_node_lock); } -- GitLab From 72f2215d879e8c48cfe9548df8cc7d46c4af2b0f Mon Sep 17 00:00:00 2001 From: Chris Lew Date: Wed, 2 May 2018 11:27:27 -0700 Subject: [PATCH 1349/1635] qrtr: Rename qrtr_all_nodes to qrtr_all_epts The node list only respresents the adjacent nodes in the system. Rename the list to qrtr_all_epts to better describe the list contents. Change-Id: I168ca597d5b9b30d6c064c2a56b6e8b2dffa387b Signed-off-by: Chris Lew --- net/qrtr/qrtr.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/net/qrtr/qrtr.c b/net/qrtr/qrtr.c index 18c0bcae5124..f8aa5898afcc 100644 --- a/net/qrtr/qrtr.c +++ b/net/qrtr/qrtr.c @@ -106,8 +106,8 @@ static unsigned int qrtr_local_nid = -1; /* for node ids */ static RADIX_TREE(qrtr_nodes, GFP_KERNEL); /* broadcast list */ -static LIST_HEAD(qrtr_all_nodes); -/* lock for qrtr_nodes, qrtr_all_nodes and node reference */ +static LIST_HEAD(qrtr_all_epts); +/* lock for qrtr_nodes, qrtr_all_epts and node reference */ static DEFINE_MUTEX(qrtr_node_lock); /* local port allocation management */ @@ -446,7 +446,7 @@ int qrtr_endpoint_register(struct qrtr_endpoint *ep, unsigned int nid) qrtr_node_assign(node, nid); mutex_lock(&qrtr_node_lock); - list_add(&node->item, &qrtr_all_nodes); + list_add(&node->item, &qrtr_all_epts); mutex_unlock(&qrtr_node_lock); ep->node = node; @@ -712,7 +712,7 @@ static int qrtr_bcast_enqueue(struct qrtr_node *node, struct sk_buff *skb, struct sk_buff *skbn; mutex_lock(&qrtr_node_lock); - list_for_each_entry(node, &qrtr_all_nodes, item) { + list_for_each_entry(node, &qrtr_all_epts, item) { skbn = skb_clone(skb, GFP_KERNEL); if (!skbn) break; -- GitLab From f85c9652703c1733fc586f0bec79fa8c93849cb9 Mon Sep 17 00:00:00 2001 From: Hemant Kumar Date: Wed, 2 May 2018 15:50:45 -0700 Subject: [PATCH 1350/1635] usb: dwc3: Add a NULL check in dwc3_resume_work() If extcon property is not present dwc3_resume_work() dereferences extcon notifier block pointer to get the extcon device. This results into NULL pointer dereference. Add NULL check for extcon to skip extcon related handling. Change-Id: I0581cf13a6f577ebaf28817c6afe5839b08b2e95 Signed-off-by: Hemant Kumar --- drivers/usb/dwc3/dwc3-msm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c index 008c23d880dd..7e8b706c8f10 100644 --- a/drivers/usb/dwc3/dwc3-msm.c +++ b/drivers/usb/dwc3/dwc3-msm.c @@ -2513,10 +2513,10 @@ static void dwc3_resume_work(struct work_struct *w) dev_dbg(mdwc->dev, "%s: dwc3 resume work\n", __func__); - if (mdwc->vbus_active && !mdwc->in_restart) { + if (mdwc->extcon && mdwc->vbus_active && !mdwc->in_restart) { extcon_id = EXTCON_USB; edev = mdwc->extcon[mdwc->ext_idx].edev; - } else if (mdwc->id_state == DWC3_ID_GROUND) { + } else if (mdwc->extcon && mdwc->id_state == DWC3_ID_GROUND) { extcon_id = EXTCON_USB_HOST; edev = mdwc->extcon[mdwc->ext_idx].edev; } -- GitLab From 7e56ff05a2238c7a3e8ea1f9fc4a0309da2b297d Mon Sep 17 00:00:00 2001 From: Pavankumar Kondeti Date: Wed, 22 Mar 2017 14:49:54 +0530 Subject: [PATCH 1351/1635] proc: Add files for specifying scheduling related per-task attributes Add procfs files for specifying the scheduling related per-task attributes like wake_up_idle, init_task_load and sched_group_id. Change-Id: I97db385522c7317fbc6f78cbae5c2550b73afd27 Signed-off-by: Srivatsa Vaddagiri Signed-off-by: Pavankumar Kondeti Signed-off-by: Puja Gupta --- fs/proc/base.c | 205 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 205 insertions(+) diff --git a/fs/proc/base.c b/fs/proc/base.c index fd4d97b5e0d6..ca189083ab20 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -1457,6 +1457,204 @@ static const struct file_operations proc_pid_sched_operations = { #endif +/* + * Print out various scheduling related per-task fields: + */ + +#ifdef CONFIG_SMP + +static int sched_wake_up_idle_show(struct seq_file *m, void *v) +{ + struct inode *inode = m->private; + struct task_struct *p; + + p = get_proc_task(inode); + if (!p) + return -ESRCH; + + seq_printf(m, "%d\n", sched_get_wake_up_idle(p)); + + put_task_struct(p); + + return 0; +} + +static ssize_t +sched_wake_up_idle_write(struct file *file, const char __user *buf, + size_t count, loff_t *offset) +{ + struct inode *inode = file_inode(file); + struct task_struct *p; + char buffer[PROC_NUMBUF]; + int wake_up_idle, err; + + memset(buffer, 0, sizeof(buffer)); + if (count > sizeof(buffer) - 1) + count = sizeof(buffer) - 1; + if (copy_from_user(buffer, buf, count)) { + err = -EFAULT; + goto out; + } + + err = kstrtoint(strstrip(buffer), 0, &wake_up_idle); + if (err) + goto out; + + p = get_proc_task(inode); + if (!p) + return -ESRCH; + + err = sched_set_wake_up_idle(p, wake_up_idle); + + put_task_struct(p); + +out: + return err < 0 ? err : count; +} + +static int sched_wake_up_idle_open(struct inode *inode, struct file *filp) +{ + return single_open(filp, sched_wake_up_idle_show, inode); +} + +static const struct file_operations proc_pid_sched_wake_up_idle_operations = { + .open = sched_wake_up_idle_open, + .read = seq_read, + .write = sched_wake_up_idle_write, + .llseek = seq_lseek, + .release = single_release, +}; + +#endif /* CONFIG_SMP */ + +#ifdef CONFIG_SCHED_WALT + +static int sched_init_task_load_show(struct seq_file *m, void *v) +{ + struct inode *inode = m->private; + struct task_struct *p; + + p = get_proc_task(inode); + if (!p) + return -ESRCH; + + seq_printf(m, "%d\n", sched_get_init_task_load(p)); + + put_task_struct(p); + + return 0; +} + +static ssize_t +sched_init_task_load_write(struct file *file, const char __user *buf, + size_t count, loff_t *offset) +{ + struct inode *inode = file_inode(file); + struct task_struct *p; + char buffer[PROC_NUMBUF]; + int init_task_load, err; + + memset(buffer, 0, sizeof(buffer)); + if (count > sizeof(buffer) - 1) + count = sizeof(buffer) - 1; + if (copy_from_user(buffer, buf, count)) { + err = -EFAULT; + goto out; + } + + err = kstrtoint(strstrip(buffer), 0, &init_task_load); + if (err) + goto out; + + p = get_proc_task(inode); + if (!p) + return -ESRCH; + + err = sched_set_init_task_load(p, init_task_load); + + put_task_struct(p); + +out: + return err < 0 ? err : count; +} + +static int sched_init_task_load_open(struct inode *inode, struct file *filp) +{ + return single_open(filp, sched_init_task_load_show, inode); +} + +static const struct file_operations proc_pid_sched_init_task_load_operations = { + .open = sched_init_task_load_open, + .read = seq_read, + .write = sched_init_task_load_write, + .llseek = seq_lseek, + .release = single_release, +}; + +static int sched_group_id_show(struct seq_file *m, void *v) +{ + struct inode *inode = m->private; + struct task_struct *p; + + p = get_proc_task(inode); + if (!p) + return -ESRCH; + + seq_printf(m, "%d\n", sched_get_group_id(p)); + + put_task_struct(p); + + return 0; +} + +static ssize_t +sched_group_id_write(struct file *file, const char __user *buf, + size_t count, loff_t *offset) +{ + struct inode *inode = file_inode(file); + struct task_struct *p; + char buffer[PROC_NUMBUF]; + int group_id, err; + + memset(buffer, 0, sizeof(buffer)); + if (count > sizeof(buffer) - 1) + count = sizeof(buffer) - 1; + if (copy_from_user(buffer, buf, count)) { + err = -EFAULT; + goto out; + } + + err = kstrtoint(strstrip(buffer), 0, &group_id); + if (err) + goto out; + + p = get_proc_task(inode); + if (!p) + return -ESRCH; + + err = sched_set_group_id(p, group_id); + + put_task_struct(p); + +out: + return err < 0 ? err : count; +} + +static int sched_group_id_open(struct inode *inode, struct file *filp) +{ + return single_open(filp, sched_group_id_show, inode); +} + +static const struct file_operations proc_pid_sched_group_id_operations = { + .open = sched_group_id_open, + .read = seq_read, + .write = sched_group_id_write, + .llseek = seq_lseek, + .release = single_release, +}; + +#endif /* CONFIG_SCHED_WALT */ + #ifdef CONFIG_SCHED_AUTOGROUP /* * Print out autogroup related information: @@ -2933,6 +3131,13 @@ static const struct pid_entry tgid_base_stuff[] = { ONE("status", S_IRUGO, proc_pid_status), ONE("personality", S_IRUSR, proc_pid_personality), ONE("limits", S_IRUGO, proc_pid_limits), +#ifdef CONFIG_SMP + REG("sched_wake_up_idle", 00644, proc_pid_sched_wake_up_idle_operations), +#endif +#ifdef CONFIG_SCHED_WALT + REG("sched_init_task_load", 00644, proc_pid_sched_init_task_load_operations), + REG("sched_group_id", 00666, proc_pid_sched_group_id_operations), +#endif #ifdef CONFIG_SCHED_DEBUG REG("sched", S_IRUGO|S_IWUSR, proc_pid_sched_operations), #endif -- GitLab From 8ee25ad00b3d338bd821ca8876f2490dcd787b32 Mon Sep 17 00:00:00 2001 From: Runmin Wang Date: Tue, 1 May 2018 19:01:30 -0700 Subject: [PATCH 1352/1635] sched/core: Fix an ordering issue in wake_up_new_task If a task is activated before the window_start on the rq is initialized, its ravg would get reset to 0. However, the init load on this task is already pushed into the cumulative_runnable_avg. When the task is dequeued, the task demand (which is reset to 0) will be removed from the cumulative_runnable_avg, and as a result, the init load will be left on the runqueue and cra will not be 0 even when CPU is idle. Change-Id: I7619206dde275f7b64bfcfed206bf0c9a7245cf9 Signed-off-by: Runmin Wang --- kernel/sched/core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/sched/core.c b/kernel/sched/core.c index 4df40a9a6c3f..9ce3f624fe8e 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -2573,8 +2573,8 @@ void wake_up_new_task(struct task_struct *p) update_rq_clock(rq); post_init_entity_util_avg(&p->se); - activate_task(rq, p, ENQUEUE_NOCLOCK); mark_task_starting(p); + activate_task(rq, p, ENQUEUE_NOCLOCK); p->on_rq = TASK_ON_RQ_QUEUED; trace_sched_wakeup_new(p); -- GitLab From a78d3789a6651fc65446b3e603410ef037d3d55e Mon Sep 17 00:00:00 2001 From: Narendra Muppalla Date: Wed, 2 May 2018 11:25:43 -0700 Subject: [PATCH 1353/1635] ARM: dts: msm: update phy timing for 3.75 dsc panel on sm8150 target This change updates simulation dsi panel phy timings for command mode panel with 3.75:1 DSC configuration on sm8150 target. Change-Id: I0025c797bab90b2c93284152abb383c85060fd69 Signed-off-by: Narendra Muppalla --- arch/arm64/boot/dts/qcom/sm8150-sde-display.dtsi | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sm8150-sde-display.dtsi b/arch/arm64/boot/dts/qcom/sm8150-sde-display.dtsi index a2c397c7eb0d..b5e5de83aa1b 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-sde-display.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-sde-display.dtsi @@ -608,14 +608,14 @@ qcom,mdss-dsi-t-clk-pre = <0x2d>; qcom,mdss-dsi-display-timings { timing@0 { /* 1080p */ - qcom,mdss-dsi-panel-phy-timings = [00 1A 06 06 22 20 07 - 07 04 03 04 00]; + qcom,mdss-dsi-panel-phy-timings = [00 1c 08 07 23 22 07 + 07 05 03 04 00 18 17]; qcom,display-topology = <1 1 1>; qcom,default-topology-index = <0>; }; timing@1 { /* qhd */ - qcom,mdss-dsi-panel-phy-timings = [00 1A 06 06 22 20 07 - 07 04 03 04 00]; + qcom,mdss-dsi-panel-phy-timings = [00 1e 08 07 24 22 08 + 08 05 03 04 00 19 18]; qcom,display-topology = <1 1 1>, <2 2 1>, /* dsc merge */ <2 1 1>; /* 3d mux */ -- GitLab From 10a478b2b121cd72af3a307af0b3f02014bfe097 Mon Sep 17 00:00:00 2001 From: Sujeev Dias Date: Mon, 23 Apr 2018 13:18:04 -0700 Subject: [PATCH 1354/1635] mhi: core: start UL channel before DL channel For some MHI clients, initial handshake starts from device. Soon as host starts device to host (DL) channel, device sends initial 'hello' packet to host. Then client immediately try to respond back to device but fails since uplink (UL) channel is not yet started. To avoid this race condition, always prepare the UL channel first. So, channel is ready to respond to any packets from device. CRs-Fixed: 2229675 Change-Id: If0f196a93c4912d7109176ee814deb39c1ac090a Signed-off-by: Sujeev Dias --- drivers/bus/mhi/core/mhi_main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/bus/mhi/core/mhi_main.c b/drivers/bus/mhi/core/mhi_main.c index 761c0600dd40..b023cf8819de 100644 --- a/drivers/bus/mhi/core/mhi_main.c +++ b/drivers/bus/mhi/core/mhi_main.c @@ -1385,7 +1385,7 @@ int mhi_prepare_for_transfer(struct mhi_device *mhi_dev) struct mhi_chan *mhi_chan; for (dir = 0; dir < 2; dir++) { - mhi_chan = dir ? mhi_dev->ul_chan : mhi_dev->dl_chan; + mhi_chan = dir ? mhi_dev->dl_chan : mhi_dev->ul_chan; if (!mhi_chan) continue; @@ -1402,7 +1402,7 @@ int mhi_prepare_for_transfer(struct mhi_device *mhi_dev) error_open_chan: for (--dir; dir >= 0; dir--) { - mhi_chan = dir ? mhi_dev->ul_chan : mhi_dev->dl_chan; + mhi_chan = dir ? mhi_dev->dl_chan : mhi_dev->ul_chan; if (!mhi_chan) continue; -- GitLab From 04a9ef2957b2457b1ccc31887758147b4d203c56 Mon Sep 17 00:00:00 2001 From: Chris Lew Date: Wed, 2 May 2018 15:01:46 -0700 Subject: [PATCH 1355/1635] qrtr: Initialize the local nid to 1 Android restrictions prevent the usage of NET_ADMIN so QRTR can not be correctly configured to node id 1 on Android targets. Init the local nid to 1 so it does not need to be configured by the ns. Change-Id: I679626c7b96aa7a074c69cc4fdc806a5dbde4639 Signed-off-by: Chris Lew --- net/qrtr/qrtr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/qrtr/qrtr.c b/net/qrtr/qrtr.c index 8273f44b27af..63fb0d23f327 100644 --- a/net/qrtr/qrtr.c +++ b/net/qrtr/qrtr.c @@ -101,7 +101,7 @@ static inline struct qrtr_sock *qrtr_sk(struct sock *sk) return container_of(sk, struct qrtr_sock, sk); } -static unsigned int qrtr_local_nid = -1; +static unsigned int qrtr_local_nid = 1; /* for node ids */ static RADIX_TREE(qrtr_nodes, GFP_KERNEL); -- GitLab From e0aacc3443793615599015067f50afa3e826c24f Mon Sep 17 00:00:00 2001 From: Chris Lew Date: Tue, 1 May 2018 13:18:27 -0700 Subject: [PATCH 1356/1635] qrtr: Align header and payload Remote IPC Router drivers expect the received packet to be aligned. This case is only exposed using the MHI transport because it does not ensure the packet will be received as one chunk like RPMSG GLINK. Change-Id: I0e5c27e3c5896e6721c8bbbfcda29551f0968626 Signed-off-by: Chris Lew --- net/qrtr/qrtr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/qrtr/qrtr.c b/net/qrtr/qrtr.c index f8aa5898afcc..54df04a41bd8 100644 --- a/net/qrtr/qrtr.c +++ b/net/qrtr/qrtr.c @@ -203,7 +203,7 @@ static int qrtr_node_enqueue(struct qrtr_node *node, struct sk_buff *skb, hdr->size = cpu_to_le32(len); hdr->confirm_rx = 0; - skb_put_padto(skb, ALIGN(len, 4)); + skb_put_padto(skb, ALIGN(len, 4) + sizeof(*hdr)); mutex_lock(&node->ep_lock); if (node->ep) -- GitLab From abd3961d05be14c8132ba9f7756c95d221aa33ac Mon Sep 17 00:00:00 2001 From: Chris Lew Date: Tue, 1 May 2018 13:31:38 -0700 Subject: [PATCH 1357/1635] qrtr: Only broadcast to initialized nodes Messages should only be broadcasted on nodes that have finished the HELLO packet handshake. Ensure that the HELLO packet has been received before broadcasting a control message to that node. Change-Id: Id2f26c088a1a41a391c936cde9fb251c0b0c2144 Signed-off-by: Chris Lew --- net/qrtr/qrtr.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/net/qrtr/qrtr.c b/net/qrtr/qrtr.c index 54df04a41bd8..19c663d85c1d 100644 --- a/net/qrtr/qrtr.c +++ b/net/qrtr/qrtr.c @@ -713,6 +713,8 @@ static int qrtr_bcast_enqueue(struct qrtr_node *node, struct sk_buff *skb, mutex_lock(&qrtr_node_lock); list_for_each_entry(node, &qrtr_all_epts, item) { + if (node->nid == QRTR_EP_NID_AUTO) + continue; skbn = skb_clone(skb, GFP_KERNEL); if (!skbn) break; -- GitLab From 5598f6c4ecb9d5a33c590af0c70b7ee1c2ca2cd0 Mon Sep 17 00:00:00 2001 From: Tony Truong Date: Wed, 2 May 2018 15:40:10 -0700 Subject: [PATCH 1358/1635] msm: pcie: clear Request Exit L1 bit when enabling L1 via debugfs When enabling L1 via debugfs commands, the request exit L1 bit needs to be cleared so the link can enter L1. Change-Id: I41b6d3b856473bebc1337eb467763a6f66914e41 Signed-off-by: Tony Truong --- drivers/pci/host/pci-msm.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/pci/host/pci-msm.c b/drivers/pci/host/pci-msm.c index 5cdac364a0fc..4b28e527efff 100644 --- a/drivers/pci/host/pci-msm.c +++ b/drivers/pci/host/pci-msm.c @@ -1455,6 +1455,10 @@ static void msm_pcie_sel_debug_testcase(struct msm_pcie_dev_t *dev, pci_walk_bus(bus, &msm_pcie_config_l1_enable, dev); + /* enable l1 mode, clear bit 5 (REQ_NOT_ENTR_L1) */ + msm_pcie_write_mask(dev->parf + + PCIE20_PARF_PM_CTRL, BIT(5), 0); + msm_pcie_config_l1_enable(dev->dev, dev); } break; -- GitLab From 129ae4fbdaeb2ec76df1f4e4654b6f0eba6f9896 Mon Sep 17 00:00:00 2001 From: Hemant Kumar Date: Fri, 27 Apr 2018 13:43:21 -0700 Subject: [PATCH 1359/1635] ARM: dts: msm: Enable primary usb port in HS mode on sm8150-auto-adp-star On sm8150-auto-adp-star primary usb port can only run in high speed mode. Hence set max-speed to high speed and disable super speed phy. Change-Id: I25f5a116ebc9b1b8c40aaa11d02424ad31caf581 Signed-off-by: Hemant Kumar --- arch/arm64/boot/dts/qcom/sm8150-auto.dtsi | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sm8150-auto.dtsi b/arch/arm64/boot/dts/qcom/sm8150-auto.dtsi index 256c7fd01c79..51d91e8ee294 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-auto.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-auto.dtsi @@ -300,3 +300,10 @@ }; }; }; + +&usb0 { + dwc3@a600000 { + usb-phy = <&usb2_phy0>, <&usb_nop_phy>; + maximum-speed = "high-speed"; + }; +}; -- GitLab From 14584cbed5606c6bede59232ade1415b35be379e Mon Sep 17 00:00:00 2001 From: Hareesh Gundu Date: Sun, 22 Apr 2018 11:45:32 +0530 Subject: [PATCH 1360/1635] msm: kgsl: Abstract out GMU from the GMU core MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A6xx GPUs have different variants of GMU. Abstract out current GMU implementation under GMU core, so that it’s easy to add new code for different GMU variants. Change-Id: I0dae15bc6905b869c34bbbdebc0b5e9e2f7ff25b Signed-off-by: Hareesh Gundu --- drivers/gpu/msm/Makefile | 1 + drivers/gpu/msm/adreno.c | 164 +++++---- drivers/gpu/msm/adreno.h | 33 +- drivers/gpu/msm/adreno_a6xx.c | 45 ++- drivers/gpu/msm/adreno_a6xx.h | 13 +- drivers/gpu/msm/adreno_a6xx_gmu.c | 474 ++++++++++++++++++------- drivers/gpu/msm/adreno_a6xx_preempt.c | 16 +- drivers/gpu/msm/adreno_a6xx_snapshot.c | 124 +------ drivers/gpu/msm/adreno_dispatch.c | 2 +- drivers/gpu/msm/adreno_perfcounter.c | 11 +- drivers/gpu/msm/adreno_snapshot.c | 12 +- drivers/gpu/msm/adreno_sysfs.c | 45 +-- drivers/gpu/msm/kgsl_device.h | 64 +--- drivers/gpu/msm/kgsl_gmu.c | 318 +++++++++-------- drivers/gpu/msm/kgsl_gmu.h | 90 +---- drivers/gpu/msm/kgsl_gmu_core.c | 219 ++++++++++++ drivers/gpu/msm/kgsl_gmu_core.h | 185 ++++++++++ drivers/gpu/msm/kgsl_hfi.c | 10 +- drivers/gpu/msm/kgsl_hfi.h | 12 - drivers/gpu/msm/kgsl_pwrctrl.c | 52 +-- 20 files changed, 1117 insertions(+), 773 deletions(-) create mode 100644 drivers/gpu/msm/kgsl_gmu_core.c create mode 100644 drivers/gpu/msm/kgsl_gmu_core.h diff --git a/drivers/gpu/msm/Makefile b/drivers/gpu/msm/Makefile index b7d636066354..54350e72a9f2 100644 --- a/drivers/gpu/msm/Makefile +++ b/drivers/gpu/msm/Makefile @@ -12,6 +12,7 @@ msm_kgsl_core-y = \ kgsl_snapshot.o \ kgsl_events.o \ kgsl_pool.o \ + kgsl_gmu_core.o \ kgsl_gmu.o \ kgsl_hfi.o diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c index dd7f5bda1a77..2acefa0e023a 100644 --- a/drivers/gpu/msm/adreno.c +++ b/drivers/gpu/msm/adreno.c @@ -24,6 +24,7 @@ #include #include "kgsl.h" +#include "kgsl_gmu_core.h" #include "kgsl_pwrscale.h" #include "kgsl_sharedmem.h" #include "kgsl_iommu.h" @@ -79,9 +80,6 @@ static struct adreno_device device_3d0 = { .pwrscale = KGSL_PWRSCALE_INIT(&adreno_tz_data), .name = DEVICE_3D0_NAME, .id = KGSL_DEVICE_3D0, - .gmu = { - .load_mode = TCM_BOOT, - }, .pwrctrl = { .irq_name = "kgsl_3d0_irq", }, @@ -634,7 +632,7 @@ static irqreturn_t adreno_irq_handler(struct kgsl_device *device) * This is usually harmless because the GMU will abort power collapse * and change the fence back to ALLOW. Poll so that this can happen. */ - if (kgsl_gmu_isenabled(device)) { + if (gmu_core_isenabled(device)) { do { adreno_readreg(adreno_dev, ADRENO_REG_GMU_AO_AHB_FENCE_CTRL, @@ -1229,7 +1227,6 @@ static int adreno_probe(struct platform_device *pdev) struct kgsl_device *device; struct adreno_device *adreno_dev; int status; - unsigned long flags; adreno_dev = adreno_get_dev(pdev); @@ -1265,9 +1262,7 @@ static int adreno_probe(struct platform_device *pdev) * Another part of GPU power probe in platform_probe * needs GMU initialized. */ - flags = ADRENO_FEATURE(adreno_dev, ADRENO_GPMU) ? BIT(GMU_GPMU) : 0; - - status = gmu_probe(device, flags); + status = gmu_core_probe(device); if (status) { device->pdev = NULL; return status; @@ -1447,7 +1442,7 @@ static int adreno_remove(struct platform_device *pdev) adreno_perfcounter_close(adreno_dev); kgsl_device_platform_remove(device); - gmu_remove(device); + gmu_core_remove(device); if (test_bit(ADRENO_DEVICE_PWRON_FIXUP, &adreno_dev->priv)) { kgsl_free_global(device, &adreno_dev->pwron_fixup); @@ -1648,7 +1643,7 @@ static bool regulators_left_on(struct kgsl_device *device) { int i; - if (kgsl_gmu_gpmu_isenabled(device)) + if (gmu_core_gpmu_isenabled(device)) return false; for (i = 0; i < KGSL_MAX_REGULATORS; i++) { @@ -1764,6 +1759,7 @@ static int _adreno_start(struct adreno_device *adreno_dev) { struct kgsl_device *device = KGSL_DEVICE(adreno_dev); struct adreno_gpudev *gpudev = ADRENO_GPU_DEVICE(adreno_dev); + struct gmu_dev_ops *gmu_dev_ops = GMU_DEVICE_OPS(device); int status = -EINVAL, ret; unsigned int state = device->state; bool regulator_left_on; @@ -1824,17 +1820,14 @@ static int _adreno_start(struct adreno_device *adreno_dev) } /* Send OOB request to turn on the GX */ - if (gpudev->oob_set) { - status = gpudev->oob_set(adreno_dev, oob_gpu); + if (gmu_dev_ops->oob_set) { + status = gmu_dev_ops->oob_set(adreno_dev, oob_gpu); if (status) goto error_mmu_off; } - if (adreno_is_a640(adreno_dev)) { - struct hfi_start_cmd req; - - /* Send hfi start msg */ - status = hfi_send_req(&device->gmu, H2F_MSG_START, &req); + if (gmu_dev_ops->hfi_start_msg) { + status = gmu_dev_ops->hfi_start_msg(adreno_dev); if (status) goto error_mmu_off; } @@ -2011,19 +2004,19 @@ static int _adreno_start(struct adreno_device *adreno_dev) pmqos_active_vote); /* Send OOB request to allow IFPC */ - if (gpudev->oob_clear) { - gpudev->oob_clear(adreno_dev, oob_gpu); + if (gmu_dev_ops->oob_clear) { + gmu_dev_ops->oob_clear(adreno_dev, oob_gpu); /* If we made it this far, the BOOT OOB was sent to the GMU */ if (ADRENO_QUIRK(adreno_dev, ADRENO_QUIRK_HFI_USE_REG)) - gpudev->oob_clear(adreno_dev, oob_boot_slumber); + gmu_dev_ops->oob_clear(adreno_dev, oob_boot_slumber); } return 0; error_oob_clear: - if (gpudev->oob_clear) - gpudev->oob_clear(adreno_dev, oob_gpu); + if (gmu_dev_ops->oob_clear) + gmu_dev_ops->oob_clear(adreno_dev, oob_gpu); error_mmu_off: kgsl_mmu_stop(&device->mmu); @@ -2068,24 +2061,21 @@ int adreno_start(struct kgsl_device *device, int priority) static int adreno_stop(struct kgsl_device *device) { struct adreno_device *adreno_dev = ADRENO_DEVICE(device); - struct adreno_gpudev *gpudev = ADRENO_GPU_DEVICE(adreno_dev); + struct gmu_dev_ops *gmu_dev_ops = GMU_DEVICE_OPS(device); int error = 0; if (!test_bit(ADRENO_DEVICE_STARTED, &adreno_dev->priv)) return 0; /* Turn the power on one last time before stopping */ - if (gpudev->oob_set) { - error = gpudev->oob_set(adreno_dev, oob_gpu); + if (gmu_dev_ops->oob_set) { + error = gmu_dev_ops->oob_set(adreno_dev, oob_gpu); if (error) { - struct gmu_device *gmu = &device->gmu; - - gpudev->oob_clear(adreno_dev, oob_gpu); - if (gmu->gx_gdsc && - regulator_is_enabled(gmu->gx_gdsc)) { + gmu_dev_ops->oob_clear(adreno_dev, oob_gpu); + if (gmu_core_regulator_isenabled(device)) { /* GPU is on. Try recovery */ - set_bit(GMU_FAULT, &gmu->flags); - gmu_snapshot(device); + gmu_core_setbit(device, GMU_FAULT); + gmu_core_snapshot(device); error = -EINVAL; } else { return error; @@ -2114,8 +2104,8 @@ static int adreno_stop(struct kgsl_device *device) /* Save physical performance counter values before GPU power down*/ adreno_perfcounter_save(adreno_dev); - if (gpudev->oob_clear) - gpudev->oob_clear(adreno_dev, oob_gpu); + if (gmu_dev_ops->oob_clear) + gmu_dev_ops->oob_clear(adreno_dev, oob_gpu); /* * Saving perfcounters will use an OOB to put the GMU into @@ -2123,12 +2113,11 @@ static int adreno_stop(struct kgsl_device *device) * GMU to return to the lowest idle level. This is * because some idle level transitions require VBIF and MMU. */ - if (!error && gpudev->wait_for_lowest_idle && - gpudev->wait_for_lowest_idle(adreno_dev)) { - struct gmu_device *gmu = &device->gmu; + if (!error && gmu_dev_ops->wait_for_lowest_idle && + gmu_dev_ops->wait_for_lowest_idle(adreno_dev)) { - set_bit(GMU_FAULT, &gmu->flags); - gmu_snapshot(device); + gmu_core_setbit(device, GMU_FAULT); + gmu_core_snapshot(device); /* * Assume GMU hang after 10ms without responding. * It shall be relative safe to clear vbif and stop @@ -2773,10 +2762,11 @@ int adreno_soft_reset(struct kgsl_device *device) { struct adreno_device *adreno_dev = ADRENO_DEVICE(device); struct adreno_gpudev *gpudev = ADRENO_GPU_DEVICE(adreno_dev); + struct gmu_dev_ops *gmu_dev_ops = GMU_DEVICE_OPS(device); int ret; - if (gpudev->oob_set) { - ret = gpudev->oob_set(adreno_dev, oob_gpu); + if (gmu_dev_ops->oob_set) { + ret = gmu_dev_ops->oob_set(adreno_dev, oob_gpu); if (ret) return ret; } @@ -2799,8 +2789,8 @@ int adreno_soft_reset(struct kgsl_device *device) else ret = _soft_reset(adreno_dev); if (ret) { - if (gpudev->oob_clear) - gpudev->oob_clear(adreno_dev, oob_gpu); + if (gmu_dev_ops->oob_clear) + gmu_dev_ops->oob_clear(adreno_dev, oob_gpu); return ret; } @@ -2853,8 +2843,8 @@ int adreno_soft_reset(struct kgsl_device *device) /* Restore physical performance counter values after soft reset */ adreno_perfcounter_restore(adreno_dev); - if (gpudev->oob_clear) - gpudev->oob_clear(adreno_dev, oob_gpu); + if (gmu_dev_ops->oob_clear) + gmu_dev_ops->oob_clear(adreno_dev, oob_gpu); return ret; } @@ -3109,44 +3099,72 @@ static void adreno_regwrite(struct kgsl_device *device, __raw_writel(value, reg); } -static void adreno_gmu_regwrite(struct kgsl_device *device, - unsigned int offsetwords, - unsigned int value) +/* + * adreno_gmu_fenced_write() - Check if there is a GMU and it is enabled + * @adreno_dev: Pointer to the Adreno device device that owns the GMU + * @offset: 32bit register enum that is to be written + * @val: The value to be written to the register + * @fence_mask: The value to poll the fence status register + * + * Check the WRITEDROPPED0/1 bit in the FENCE_STATUS register to check if + * the write to the fenced register went through. If it didn't then we retry + * the write until it goes through or we time out. + */ +int adreno_gmu_fenced_write(struct adreno_device *adreno_dev, + enum adreno_regs offset, unsigned int val, + unsigned int fence_mask) { - void __iomem *reg; - struct gmu_device *gmu = &device->gmu; + unsigned int status, i; + struct adreno_gpudev *gpudev = ADRENO_GPU_DEVICE(adreno_dev); + unsigned int reg_offset = gpudev->reg_offsets->offsets[offset]; - trace_kgsl_regwrite(device, offsetwords, value); + adreno_writereg(adreno_dev, offset, val); - offsetwords -= gmu->gmu2gpu_offset; - reg = gmu->reg_virt + (offsetwords << 2); + if (!gmu_core_isenabled(KGSL_DEVICE(adreno_dev))) + return 0; - /* - * ensure previous writes post before this one, - * i.e. act like normal writel() - */ - wmb(); - __raw_writel(value, reg); + for (i = 0; i < GMU_CORE_WAKEUP_RETRY_MAX; i++) { + adreno_read_gmureg(adreno_dev, ADRENO_REG_GMU_AHB_FENCE_STATUS, + &status); + + /* + * If !writedropped0/1, then the write to fenced register + * was successful + */ + if (!(status & fence_mask)) + return 0; + /* Wait a small amount of time before trying again */ + udelay(GMU_CORE_WAKEUP_DELAY_US); + + /* Try to write the fenced register again */ + adreno_writereg(adreno_dev, offset, val); + } + + dev_err(adreno_dev->dev.dev, + "GMU fenced register write timed out: reg 0x%x\n", reg_offset); + return -ETIMEDOUT; } -static void adreno_gmu_regread(struct kgsl_device *device, - unsigned int offsetwords, - unsigned int *value) +unsigned int adreno_gmu_ifpc_show(struct adreno_device *adreno_dev) { - void __iomem *reg; - struct gmu_device *gmu = &device->gmu; + struct gmu_dev_ops *gmu_dev_ops = GMU_DEVICE_OPS( + KGSL_DEVICE(adreno_dev)); - offsetwords -= gmu->gmu2gpu_offset; + if (gmu_dev_ops->ifpc_show) + return gmu_dev_ops->ifpc_show(adreno_dev); - reg = gmu->reg_virt + (offsetwords << 2); + return 0; +} - *value = __raw_readl(reg); +int adreno_gmu_ifpc_store(struct adreno_device *adreno_dev, unsigned int val) +{ + struct gmu_dev_ops *gmu_dev_ops = GMU_DEVICE_OPS( + KGSL_DEVICE(adreno_dev)); - /* - * ensure this read finishes before the next one. - * i.e. act like normal readl() - */ - rmb(); + if (gmu_dev_ops->ifpc_store) + return gmu_dev_ops->ifpc_store(adreno_dev, val); + + return -EINVAL; } bool adreno_is_cx_dbgc_register(struct kgsl_device *device, @@ -3600,8 +3618,6 @@ static const struct kgsl_functable adreno_functable = { /* Mandatory functions */ .regread = adreno_regread, .regwrite = adreno_regwrite, - .gmu_regread = adreno_gmu_regread, - .gmu_regwrite = adreno_gmu_regwrite, .idle = adreno_idle, .isidle = adreno_isidle, .suspend_context = adreno_suspend_context, diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h index 6f8153cc2b80..18ff39e4a3e4 100644 --- a/drivers/gpu/msm/adreno.h +++ b/drivers/gpu/msm/adreno.h @@ -23,7 +23,7 @@ #include "adreno_perfcounter.h" #include #include -#include "kgsl_gmu.h" +#include "kgsl_gmu_core.h" #include "a4xx_reg.h" @@ -912,7 +912,8 @@ struct adreno_gpudev { /* GPU specific function hooks */ void (*irq_trace)(struct adreno_device *, unsigned int status); void (*snapshot)(struct adreno_device *, struct kgsl_snapshot *); - void (*snapshot_gmu)(struct adreno_device *, struct kgsl_snapshot *); + void (*snapshot_debugbus)(struct adreno_device *adreno_dev, + struct kgsl_snapshot *snapshot); void (*platform_setup)(struct adreno_device *); void (*init)(struct adreno_device *); void (*remove)(struct adreno_device *); @@ -953,17 +954,9 @@ struct adreno_gpudev { void (*llc_configure_gpuhtw_scid)(struct adreno_device *adreno_dev); void (*llc_enable_overrides)(struct adreno_device *adreno_dev); void (*pre_reset)(struct adreno_device *); - int (*oob_set)(struct adreno_device *adreno_dev, - enum oob_request req); - void (*oob_clear)(struct adreno_device *adreno_dev, - enum oob_request req); void (*gpu_keepalive)(struct adreno_device *adreno_dev, bool state); - int (*rpmh_gpu_pwrctrl)(struct adreno_device *, unsigned int ops, - unsigned int arg1, unsigned int arg2); bool (*hw_isidle)(struct adreno_device *); - int (*wait_for_lowest_idle)(struct adreno_device *); - int (*wait_for_gmu_idle)(struct adreno_device *); const char *(*iommu_fault_block)(struct adreno_device *adreno_dev, unsigned int fsynr1); int (*reset)(struct kgsl_device *, int fault); @@ -1369,7 +1362,7 @@ static inline void adreno_read_gmureg(struct adreno_device *adreno_dev, struct adreno_gpudev *gpudev = ADRENO_GPU_DEVICE(adreno_dev); if (adreno_checkreg_off(adreno_dev, offset_name)) - kgsl_gmu_regread(KGSL_DEVICE(adreno_dev), + gmu_core_regread(KGSL_DEVICE(adreno_dev), gpudev->reg_offsets->offsets[offset_name], val); else *val = 0; @@ -1388,7 +1381,7 @@ static inline void adreno_write_gmureg(struct adreno_device *adreno_dev, struct adreno_gpudev *gpudev = ADRENO_GPU_DEVICE(adreno_dev); if (adreno_checkreg_off(adreno_dev, offset_name)) - kgsl_gmu_regwrite(KGSL_DEVICE(adreno_dev), + gmu_core_regwrite(KGSL_DEVICE(adreno_dev), gpudev->reg_offsets->offsets[offset_name], val); } @@ -1858,15 +1851,16 @@ static inline unsigned int counter_delta(struct kgsl_device *device, static inline int adreno_perfcntr_active_oob_get( struct adreno_device *adreno_dev) { - struct adreno_gpudev *gpudev = ADRENO_GPU_DEVICE(adreno_dev); + struct gmu_dev_ops *gmu_dev_ops = GMU_DEVICE_OPS( + KGSL_DEVICE(adreno_dev)); int ret; ret = kgsl_active_count_get(KGSL_DEVICE(adreno_dev)); if (ret) return ret; - if (gpudev->oob_set) { - ret = gpudev->oob_set(adreno_dev, oob_perfcntr); + if (gmu_dev_ops->oob_set) { + ret = gmu_dev_ops->oob_set(adreno_dev, oob_perfcntr); if (ret) kgsl_active_count_put(KGSL_DEVICE(adreno_dev)); } @@ -1877,10 +1871,11 @@ static inline int adreno_perfcntr_active_oob_get( static inline void adreno_perfcntr_active_oob_put( struct adreno_device *adreno_dev) { - struct adreno_gpudev *gpudev = ADRENO_GPU_DEVICE(adreno_dev); + struct gmu_dev_ops *gmu_dev_ops = GMU_DEVICE_OPS( + KGSL_DEVICE(adreno_dev)); - if (gpudev->oob_clear) - gpudev->oob_clear(adreno_dev, oob_perfcntr); + if (gmu_dev_ops->oob_clear) + gmu_dev_ops->oob_clear(adreno_dev, oob_perfcntr); kgsl_active_count_put(KGSL_DEVICE(adreno_dev)); } @@ -1941,6 +1936,8 @@ static inline void adreno_deassert_gbif_halt(struct adreno_device *adreno_dev) int adreno_gmu_fenced_write(struct adreno_device *adreno_dev, enum adreno_regs offset, unsigned int val, unsigned int fence_mask); +unsigned int adreno_gmu_ifpc_show(struct adreno_device *adreno_dev); +int adreno_gmu_ifpc_store(struct adreno_device *adreno_dev, unsigned int val); int adreno_clear_pending_transactions(struct kgsl_device *device); #endif /*__ADRENO_H */ diff --git a/drivers/gpu/msm/adreno_a6xx.c b/drivers/gpu/msm/adreno_a6xx.c index b34182631465..3f542093ec1b 100644 --- a/drivers/gpu/msm/adreno_a6xx.c +++ b/drivers/gpu/msm/adreno_a6xx.c @@ -27,7 +27,6 @@ #include "kgsl_sharedmem.h" #include "kgsl_log.h" #include "kgsl.h" -#include "kgsl_gmu.h" #include "kgsl_hfi.h" #include "kgsl_trace.h" @@ -460,7 +459,7 @@ static void a6xx_init(struct adreno_device *adreno_dev) * If the GMU is not enabled, rewrite the offset for the always on * counters to point to the CP always on instead of GMU always on */ - if (!kgsl_gmu_isenabled(KGSL_DEVICE(adreno_dev))) + if (!gmu_core_isenabled(KGSL_DEVICE(adreno_dev))) _update_always_on_regs(adreno_dev); a6xx_pwrup_reglist_init(adreno_dev); @@ -593,12 +592,12 @@ static void a6xx_hwcg_set(struct adreno_device *adreno_dev, bool on) if (!test_bit(ADRENO_HWCG_CTRL, &adreno_dev->pwrctrl_flag)) on = false; - if (kgsl_gmu_isenabled(device)) { - kgsl_gmu_regwrite(device, A6XX_GPU_GMU_AO_GMU_CGC_MODE_CNTL, + if (gmu_core_isenabled(device)) { + gmu_core_regwrite(device, A6XX_GPU_GMU_AO_GMU_CGC_MODE_CNTL, on ? __get_gmu_ao_cgc_mode_cntl(adreno_dev) : 0); - kgsl_gmu_regwrite(device, A6XX_GPU_GMU_AO_GMU_CGC_DELAY_CNTL, + gmu_core_regwrite(device, A6XX_GPU_GMU_AO_GMU_CGC_DELAY_CNTL, on ? __get_gmu_ao_cgc_delay_cntl(adreno_dev) : 0); - kgsl_gmu_regwrite(device, A6XX_GPU_GMU_AO_GMU_CGC_HYST_CNTL, + gmu_core_regwrite(device, A6XX_GPU_GMU_AO_GMU_CGC_HYST_CNTL, on ? __get_gmu_ao_cgc_hyst_cntl(adreno_dev) : 0); } @@ -621,13 +620,13 @@ static void a6xx_hwcg_set(struct adreno_device *adreno_dev, bool on) regs = a6xx_hwcg_registers[i].regs; /* Disable SP clock before programming HWCG registers */ - kgsl_gmu_regrmw(device, A6XX_GPU_GMU_GX_SPTPRAC_CLOCK_CONTROL, 1, 0); + gmu_core_regrmw(device, A6XX_GPU_GMU_GX_SPTPRAC_CLOCK_CONTROL, 1, 0); for (j = 0; j < a6xx_hwcg_registers[i].count; j++) kgsl_regwrite(device, regs[j].off, on ? regs[j].val : 0); /* Enable SP clock */ - kgsl_gmu_regrmw(device, A6XX_GPU_GMU_GX_SPTPRAC_CLOCK_CONTROL, 0, 1); + gmu_core_regrmw(device, A6XX_GPU_GMU_GX_SPTPRAC_CLOCK_CONTROL, 0, 1); /* enable top level HWCG */ kgsl_regwrite(device, A6XX_RBBM_CLOCK_CNTL, @@ -703,12 +702,13 @@ static void a6xx_patch_pwrup_reglist(struct adreno_device *adreno_dev) static void a6xx_start(struct adreno_device *adreno_dev) { struct kgsl_device *device = KGSL_DEVICE(adreno_dev); + struct gmu_dev_ops *gmu_dev_ops = GMU_DEVICE_OPS(device); unsigned int bit, mal, mode, glbl_inv; unsigned int amsbc = 0; static bool patch_reglist; /* runtime adjust callbacks based on feature sets */ - if (!kgsl_gmu_isenabled(device)) + if (!gmu_core_isenabled(device)) /* Legacy idle management if gmu is disabled */ ADRENO_GPU_DEVICE(adreno_dev)->hw_isidle = NULL; /* enable hardware clockgating */ @@ -845,9 +845,8 @@ static void a6xx_start(struct adreno_device *adreno_dev) * 3. HFI * At this point, we are guaranteed all. */ - if (ADRENO_FEATURE(adreno_dev, ADRENO_LM) && - test_bit(ADRENO_LM_CTRL, &adreno_dev->pwrctrl_flag)) - a6xx_gmu_enable_lm(device); + if (gmu_dev_ops->enable_lm) + gmu_dev_ops->enable_lm(device); } /* @@ -1196,11 +1195,13 @@ static inline void a6xx_gpu_keepalive(struct adreno_device *adreno_dev, ADRENO_REG_GMU_PWR_COL_KEEPALIVE, state); } +/* Bitmask for GPU idle status check */ +#define GPUBUSYIGNAHB BIT(23) static bool a6xx_hw_isidle(struct adreno_device *adreno_dev) { unsigned int reg; - kgsl_gmu_regread(KGSL_DEVICE(adreno_dev), + gmu_core_regread(KGSL_DEVICE(adreno_dev), A6XX_GPU_GMU_AO_GPU_CX_BUSY_STATUS, ®); if (reg & GPUBUSYIGNAHB) return false; @@ -1215,6 +1216,7 @@ static int a6xx_microcode_read(struct adreno_device *adreno_dev) { int ret; struct kgsl_device *device = KGSL_DEVICE(adreno_dev); + struct gmu_dev_ops *gmu_dev_ops = GMU_DEVICE_OPS(device); struct adreno_firmware *sqe_fw = ADRENO_FW(adreno_dev, ADRENO_FW_SQE); if (sqe_fw->memdesc.hostptr == NULL) { @@ -1224,7 +1226,7 @@ static int a6xx_microcode_read(struct adreno_device *adreno_dev) return ret; } - return a6xx_gmu_load_firmware(device); + return gmu_dev_ops->load_firmware(device); } static int a6xx_soft_reset(struct adreno_device *adreno_dev) @@ -1238,7 +1240,7 @@ static int a6xx_soft_reset(struct adreno_device *adreno_dev) * For the soft reset case with GMU enabled this part is done * by the GMU firmware */ - if (kgsl_gmu_isenabled(device) && + if (gmu_core_isenabled(device) && !test_bit(ADRENO_DEVICE_HARD_RESET, &adreno_dev->priv)) return 0; @@ -1281,7 +1283,7 @@ static void a6xx_count_throttles(struct adreno_device *adreno_dev, !test_bit(ADRENO_LM_CTRL, &adreno_dev->pwrctrl_flag)) return; - kgsl_gmu_regread(KGSL_DEVICE(adreno_dev), + gmu_core_regread(KGSL_DEVICE(adreno_dev), adreno_dev->lm_threshold_count, &adreno_dev->lm_threshold_cross); } @@ -1302,7 +1304,7 @@ static int a6xx_reset(struct kgsl_device *device, int fault) int i = 0; /* Use the regular reset sequence for No GMU */ - if (!kgsl_gmu_isenabled(device)) + if (!gmu_core_isenabled(device)) return adreno_reset(device, fault); /* Transition from ACTIVE to RESET state */ @@ -2494,7 +2496,7 @@ static int a6xx_enable_pwr_counters(struct adreno_device *adreno_dev, if (counter == 0) return -EINVAL; - if (!kgsl_gmu_isenabled(device)) + if (!gmu_core_isenabled(device)) return -ENODEV; kgsl_regwrite(device, A6XX_GPU_GMU_AO_GPU_CX_BUSY_MASK, 0xFF000000); @@ -2795,7 +2797,7 @@ struct adreno_gpudev adreno_a6xx_gpudev = { .reg_offsets = &a6xx_reg_offsets, .start = a6xx_start, .snapshot = a6xx_snapshot, - .snapshot_gmu = a6xx_snapshot_gmu, + .snapshot_debugbus = a6xx_snapshot_debugbus, .irq = &a6xx_irq, .snapshot_data = &a6xx_snapshot_data, .irq_trace = trace_kgsl_a5xx_irq_status, @@ -2813,13 +2815,8 @@ struct adreno_gpudev adreno_a6xx_gpudev = { .llc_configure_gpu_scid = a6xx_llc_configure_gpu_scid, .llc_configure_gpuhtw_scid = a6xx_llc_configure_gpuhtw_scid, .llc_enable_overrides = a6xx_llc_enable_overrides, - .oob_set = a6xx_gmu_oob_set, - .oob_clear = a6xx_gmu_oob_clear, .gpu_keepalive = a6xx_gpu_keepalive, - .rpmh_gpu_pwrctrl = a6xx_gmu_rpmh_gpu_pwrctrl, .hw_isidle = a6xx_hw_isidle, /* Replaced by NULL if GMU is disabled */ - .wait_for_lowest_idle = a6xx_gmu_wait_for_lowest_idle, - .wait_for_gmu_idle = a6xx_gmu_wait_for_idle, .iommu_fault_block = a6xx_iommu_fault_block, .reset = a6xx_reset, .soft_reset = a6xx_soft_reset, diff --git a/drivers/gpu/msm/adreno_a6xx.h b/drivers/gpu/msm/adreno_a6xx.h index 955de617b6ea..c40dcccf0bf8 100644 --- a/drivers/gpu/msm/adreno_a6xx.h +++ b/drivers/gpu/msm/adreno_a6xx.h @@ -129,18 +129,11 @@ void a6xx_preemption_context_destroy(struct kgsl_context *context); void a6xx_snapshot(struct adreno_device *adreno_dev, struct kgsl_snapshot *snapshot); -void a6xx_snapshot_gmu(struct adreno_device *adreno_dev, +void a6xx_snapshot_debugbus(struct adreno_device *adreno_dev, + struct kgsl_snapshot *snapshot); +void a6xx_gmu_snapshot(struct adreno_device *adreno_dev, struct kgsl_snapshot *snapshot); void a6xx_crashdump_init(struct adreno_device *adreno_dev); - -int a6xx_gmu_oob_set(struct adreno_device *adreno_dev, enum oob_request req); -void a6xx_gmu_oob_clear(struct adreno_device *adreno_dev, enum oob_request req); -void a6xx_gmu_enable_lm(struct kgsl_device *device); -int a6xx_gmu_load_firmware(struct kgsl_device *device); -int a6xx_gmu_rpmh_gpu_pwrctrl(struct adreno_device *adreno_dev, - unsigned int mode, unsigned int arg1, unsigned int arg2); -int a6xx_gmu_wait_for_lowest_idle(struct adreno_device *adreno_dev); -int a6xx_gmu_wait_for_idle(struct adreno_device *adreno_dev); int a6xx_gmu_sptprac_enable(struct adreno_device *adreno_dev); void a6xx_gmu_sptprac_disable(struct adreno_device *adreno_dev); bool a6xx_gmu_gx_is_on(struct adreno_device *adreno_dev); diff --git a/drivers/gpu/msm/adreno_a6xx_gmu.c b/drivers/gpu/msm/adreno_a6xx_gmu.c index bb9ac7dfb43c..e12a8b96258d 100644 --- a/drivers/gpu/msm/adreno_a6xx_gmu.c +++ b/drivers/gpu/msm/adreno_a6xx_gmu.c @@ -15,12 +15,53 @@ #include #include +#include "kgsl_gmu_core.h" +#include "kgsl_gmu.h" +#include "kgsl_trace.h" + #include "adreno.h" #include "a6xx_reg.h" #include "adreno_a6xx.h" -#include "adreno_cp_parser.h" +#include "adreno_snapshot.h" #include "adreno_trace.h" -#include "kgsl_trace.h" + +static const unsigned int a6xx_gmu_gx_registers[] = { + /* GMU GX */ + 0x1A800, 0x1A800, 0x1A810, 0x1A813, 0x1A816, 0x1A816, 0x1A818, 0x1A81B, + 0x1A81E, 0x1A81E, 0x1A820, 0x1A823, 0x1A826, 0x1A826, 0x1A828, 0x1A82B, + 0x1A82E, 0x1A82E, 0x1A830, 0x1A833, 0x1A836, 0x1A836, 0x1A838, 0x1A83B, + 0x1A83E, 0x1A83E, 0x1A840, 0x1A843, 0x1A846, 0x1A846, 0x1A880, 0x1A884, + 0x1A900, 0x1A92B, 0x1A940, 0x1A940, +}; + +static const unsigned int a6xx_gmu_registers[] = { + /* GMU TCM */ + 0x1B400, 0x1C3FF, 0x1C400, 0x1D3FF, + /* GMU CX */ + 0x1F400, 0x1F407, 0x1F410, 0x1F412, 0x1F500, 0x1F500, 0x1F507, 0x1F50A, + 0x1F800, 0x1F804, 0x1F807, 0x1F808, 0x1F80B, 0x1F80C, 0x1F80F, 0x1F81C, + 0x1F824, 0x1F82A, 0x1F82D, 0x1F830, 0x1F840, 0x1F853, 0x1F887, 0x1F889, + 0x1F8A0, 0x1F8A2, 0x1F8A4, 0x1F8AF, 0x1F8C0, 0x1F8C3, 0x1F8D0, 0x1F8D0, + 0x1F8E4, 0x1F8E4, 0x1F8E8, 0x1F8EC, 0x1F900, 0x1F903, 0x1F940, 0x1F940, + 0x1F942, 0x1F944, 0x1F94C, 0x1F94D, 0x1F94F, 0x1F951, 0x1F954, 0x1F954, + 0x1F957, 0x1F958, 0x1F95D, 0x1F95D, 0x1F962, 0x1F962, 0x1F964, 0x1F965, + 0x1F980, 0x1F986, 0x1F990, 0x1F99E, 0x1F9C0, 0x1F9C0, 0x1F9C5, 0x1F9CC, + 0x1F9E0, 0x1F9E2, 0x1F9F0, 0x1F9F0, 0x1FA00, 0x1FA01, + /* GPU RSCC */ + 0x2348C, 0x2348C, 0x23501, 0x23502, 0x23740, 0x23742, 0x23744, 0x23747, + 0x2374C, 0x23787, 0x237EC, 0x237EF, 0x237F4, 0x2382F, 0x23894, 0x23897, + 0x2389C, 0x238D7, 0x2393C, 0x2393F, 0x23944, 0x2397F, + /* GMU AO */ + 0x23B00, 0x23B16, 0x23C00, 0x23C00, + /* GPU CC */ + 0x24000, 0x24012, 0x24040, 0x24052, 0x24400, 0x24404, 0x24407, 0x2440B, + 0x24415, 0x2441C, 0x2441E, 0x2442D, 0x2443C, 0x2443D, 0x2443F, 0x24440, + 0x24442, 0x24449, 0x24458, 0x2445A, 0x24540, 0x2455E, 0x24800, 0x24802, + 0x24C00, 0x24C02, 0x25400, 0x25402, 0x25800, 0x25802, 0x25C00, 0x25C02, + 0x26000, 0x26002, + /* GPU CC ACD */ + 0x26400, 0x26416, 0x26420, 0x26427, +}; #define RSC_CMD_OFFSET 2 #define PDC_CMD_OFFSET 4 @@ -42,40 +83,40 @@ static void _regwrite(void __iomem *regbase, static void _load_gmu_rpmh_ucode(struct kgsl_device *device) { struct adreno_device *adreno_dev = ADRENO_DEVICE(device); - struct gmu_device *gmu = &device->gmu; + struct gmu_device *gmu = KGSL_GMU_DEVICE(device); /* Disable SDE clock gating */ - kgsl_gmu_regwrite(device, A6XX_GPU_RSCC_RSC_STATUS0_DRV0, BIT(24)); + gmu_core_regwrite(device, A6XX_GPU_RSCC_RSC_STATUS0_DRV0, BIT(24)); /* Setup RSC PDC handshake for sleep and wakeup */ - kgsl_gmu_regwrite(device, A6XX_RSCC_PDC_SLAVE_ID_DRV0, 1); - kgsl_gmu_regwrite(device, A6XX_RSCC_HIDDEN_TCS_CMD0_DATA, 0); - kgsl_gmu_regwrite(device, A6XX_RSCC_HIDDEN_TCS_CMD0_ADDR, 0); - kgsl_gmu_regwrite(device, + gmu_core_regwrite(device, A6XX_RSCC_PDC_SLAVE_ID_DRV0, 1); + gmu_core_regwrite(device, A6XX_RSCC_HIDDEN_TCS_CMD0_DATA, 0); + gmu_core_regwrite(device, A6XX_RSCC_HIDDEN_TCS_CMD0_ADDR, 0); + gmu_core_regwrite(device, A6XX_RSCC_HIDDEN_TCS_CMD0_DATA + RSC_CMD_OFFSET, 0); - kgsl_gmu_regwrite(device, + gmu_core_regwrite(device, A6XX_RSCC_HIDDEN_TCS_CMD0_ADDR + RSC_CMD_OFFSET, 0); - kgsl_gmu_regwrite(device, + gmu_core_regwrite(device, A6XX_RSCC_HIDDEN_TCS_CMD0_DATA + RSC_CMD_OFFSET * 2, 0x80000000); - kgsl_gmu_regwrite(device, + gmu_core_regwrite(device, A6XX_RSCC_HIDDEN_TCS_CMD0_ADDR + RSC_CMD_OFFSET * 2, 0); - kgsl_gmu_regwrite(device, A6XX_RSCC_OVERRIDE_START_ADDR, 0); - kgsl_gmu_regwrite(device, A6XX_RSCC_PDC_SEQ_START_ADDR, 0x4520); - kgsl_gmu_regwrite(device, A6XX_RSCC_PDC_MATCH_VALUE_LO, 0x4510); - kgsl_gmu_regwrite(device, A6XX_RSCC_PDC_MATCH_VALUE_HI, 0x4514); + gmu_core_regwrite(device, A6XX_RSCC_OVERRIDE_START_ADDR, 0); + gmu_core_regwrite(device, A6XX_RSCC_PDC_SEQ_START_ADDR, 0x4520); + gmu_core_regwrite(device, A6XX_RSCC_PDC_MATCH_VALUE_LO, 0x4510); + gmu_core_regwrite(device, A6XX_RSCC_PDC_MATCH_VALUE_HI, 0x4514); /* Enable timestamp event for v1 only */ if (adreno_is_a630v1(adreno_dev)) - kgsl_gmu_regwrite(device, A6XX_RSCC_TIMESTAMP_UNIT1_EN_DRV0, 1); + gmu_core_regwrite(device, A6XX_RSCC_TIMESTAMP_UNIT1_EN_DRV0, 1); /* Load RSC sequencer uCode for sleep and wakeup */ - kgsl_gmu_regwrite(device, A6XX_RSCC_SEQ_MEM_0_DRV0, 0xA7A506A0); - kgsl_gmu_regwrite(device, A6XX_RSCC_SEQ_MEM_0_DRV0 + 1, 0xA1E6A6E7); - kgsl_gmu_regwrite(device, A6XX_RSCC_SEQ_MEM_0_DRV0 + 2, 0xA2E081E1); - kgsl_gmu_regwrite(device, A6XX_RSCC_SEQ_MEM_0_DRV0 + 3, 0xE9A982E2); - kgsl_gmu_regwrite(device, A6XX_RSCC_SEQ_MEM_0_DRV0 + 4, 0x0020E8A8); + gmu_core_regwrite(device, A6XX_RSCC_SEQ_MEM_0_DRV0, 0xA7A506A0); + gmu_core_regwrite(device, A6XX_RSCC_SEQ_MEM_0_DRV0 + 1, 0xA1E6A6E7); + gmu_core_regwrite(device, A6XX_RSCC_SEQ_MEM_0_DRV0 + 2, 0xA2E081E1); + gmu_core_regwrite(device, A6XX_RSCC_SEQ_MEM_0_DRV0 + 3, 0xE9A982E2); + gmu_core_regwrite(device, A6XX_RSCC_SEQ_MEM_0_DRV0 + 4, 0x0020E8A8); /* Load PDC sequencer uCode for power up and power down sequence */ _regwrite(gmu->pdc_reg_virt, PDC_GPU_SEQ_MEM_0, 0xFEBEA1E1); @@ -157,7 +198,7 @@ static int timed_poll_check(struct kgsl_device *device, t = jiffies + msecs_to_jiffies(timeout); do { - kgsl_gmu_regread(device, offset, &value); + gmu_core_regread(device, offset, &value); if ((value & mask) == expected_ret) return 0; /* Wait 100us to reduce unnecessary AHB bus traffic */ @@ -165,7 +206,7 @@ static int timed_poll_check(struct kgsl_device *device, } while (!time_after(jiffies, t)); /* Double check one last time */ - kgsl_gmu_regread(device, offset, &value); + gmu_core_regread(device, offset, &value); if ((value & mask) == expected_ret) return 0; @@ -189,39 +230,39 @@ static int timed_poll_check(struct kgsl_device *device, static void a6xx_gmu_power_config(struct kgsl_device *device) { struct adreno_device *adreno_dev = ADRENO_DEVICE(device); - struct gmu_device *gmu = &device->gmu; + struct gmu_device *gmu = KGSL_GMU_DEVICE(device); /* Configure registers for idle setting. The setting is cumulative */ /* Disable GMU WB/RB buffer and caches at boot */ - kgsl_gmu_regwrite(device, A6XX_GMU_SYS_BUS_CONFIG, 0x1); - kgsl_gmu_regwrite(device, A6XX_GMU_ICACHE_CONFIG, 0x1); - kgsl_gmu_regwrite(device, A6XX_GMU_DCACHE_CONFIG, 0x1); + gmu_core_regwrite(device, A6XX_GMU_SYS_BUS_CONFIG, 0x1); + gmu_core_regwrite(device, A6XX_GMU_ICACHE_CONFIG, 0x1); + gmu_core_regwrite(device, A6XX_GMU_DCACHE_CONFIG, 0x1); - kgsl_gmu_regwrite(device, + gmu_core_regwrite(device, A6XX_GMU_PWR_COL_INTER_FRAME_CTRL, 0x9C40400); switch (gmu->idle_level) { case GPU_HW_MIN_VOLT: - kgsl_gmu_regrmw(device, A6XX_GMU_RPMH_CTRL, 0, + gmu_core_regrmw(device, A6XX_GMU_RPMH_CTRL, 0, MIN_BW_ENABLE_MASK); - kgsl_gmu_regrmw(device, A6XX_GMU_RPMH_HYST_CTRL, 0, + gmu_core_regrmw(device, A6XX_GMU_RPMH_HYST_CTRL, 0, MIN_BW_HYST); /* fall through */ case GPU_HW_NAP: - kgsl_gmu_regrmw(device, A6XX_GMU_GPU_NAP_CTRL, 0, + gmu_core_regrmw(device, A6XX_GMU_GPU_NAP_CTRL, 0, HW_NAP_ENABLE_MASK); /* fall through */ case GPU_HW_IFPC: - kgsl_gmu_regwrite(device, A6XX_GMU_PWR_COL_INTER_FRAME_HYST, + gmu_core_regwrite(device, A6XX_GMU_PWR_COL_INTER_FRAME_HYST, GMU_PWR_COL_HYST); - kgsl_gmu_regrmw(device, A6XX_GMU_PWR_COL_INTER_FRAME_CTRL, 0, + gmu_core_regrmw(device, A6XX_GMU_PWR_COL_INTER_FRAME_CTRL, 0, IFPC_ENABLE_MASK); /* fall through */ case GPU_HW_SPTP_PC: - kgsl_gmu_regwrite(device, A6XX_GMU_PWR_COL_SPTPRAC_HYST, + gmu_core_regwrite(device, A6XX_GMU_PWR_COL_SPTPRAC_HYST, GMU_PWR_COL_HYST); - kgsl_gmu_regrmw(device, A6XX_GMU_PWR_COL_INTER_FRAME_CTRL, 0, + gmu_core_regrmw(device, A6XX_GMU_PWR_COL_INTER_FRAME_CTRL, 0, SPTP_ENABLE_MASK); /* fall through */ default: @@ -231,12 +272,12 @@ static void a6xx_gmu_power_config(struct kgsl_device *device) /* ACD feature enablement */ if (ADRENO_FEATURE(adreno_dev, ADRENO_LM) && test_bit(ADRENO_LM_CTRL, &adreno_dev->pwrctrl_flag)) - kgsl_gmu_regrmw(device, A6XX_GMU_BOOT_KMD_LM_HANDSHAKE, 0, + gmu_core_regrmw(device, A6XX_GMU_BOOT_KMD_LM_HANDSHAKE, 0, BIT(10)); /* Enable RPMh GPU client */ if (ADRENO_FEATURE(adreno_dev, ADRENO_RPMH)) - kgsl_gmu_regrmw(device, A6XX_GMU_RPMH_CTRL, 0, + gmu_core_regrmw(device, A6XX_GMU_RPMH_CTRL, 0, RPMH_ENABLE_MASK); } @@ -246,17 +287,17 @@ static void a6xx_gmu_power_config(struct kgsl_device *device) */ static int a6xx_gmu_start(struct kgsl_device *device) { - struct gmu_device *gmu = &device->gmu; + struct gmu_device *gmu = KGSL_GMU_DEVICE(device); kgsl_regwrite(device, A6XX_GMU_CX_GMU_WFI_CONFIG, 0x0); /* Write 1 first to make sure the GMU is reset */ - kgsl_gmu_regwrite(device, A6XX_GMU_CM3_SYSRESET, 1); + gmu_core_regwrite(device, A6XX_GMU_CM3_SYSRESET, 1); /* Make sure putting in reset doesn't happen after clearing */ wmb(); /* Bring GMU out of reset */ - kgsl_gmu_regwrite(device, A6XX_GMU_CM3_SYSRESET, 0); + gmu_core_regwrite(device, A6XX_GMU_CM3_SYSRESET, 0); if (timed_poll_check(device, A6XX_GMU_CM3_FW_INIT_RESULT, 0xBABEFACE, @@ -275,11 +316,11 @@ static int a6xx_gmu_start(struct kgsl_device *device) */ static int a6xx_gmu_hfi_start(struct kgsl_device *device) { - struct gmu_device *gmu = &device->gmu; + struct gmu_device *gmu = KGSL_GMU_DEVICE(device); - kgsl_gmu_regrmw(device, A6XX_GMU_GMU2HOST_INTR_MASK, + gmu_core_regrmw(device, A6XX_GMU_GMU2HOST_INTR_MASK, HFI_IRQ_MSGQ_MASK, 0); - kgsl_gmu_regwrite(device, A6XX_GMU_HFI_CTRL_INIT, 1); + gmu_core_regwrite(device, A6XX_GMU_HFI_CTRL_INIT, 1); if (timed_poll_check(device, A6XX_GMU_HFI_CTRL_STATUS, @@ -297,9 +338,9 @@ static uint64_t read_AO_counter(struct kgsl_device *device) { unsigned int l, h, h1; - kgsl_gmu_regread(device, A6XX_GMU_CX_GMU_ALWAYS_ON_COUNTER_H, &h); - kgsl_gmu_regread(device, A6XX_GMU_CX_GMU_ALWAYS_ON_COUNTER_L, &l); - kgsl_gmu_regread(device, A6XX_GMU_CX_GMU_ALWAYS_ON_COUNTER_H, &h1); + gmu_core_regread(device, A6XX_GMU_CX_GMU_ALWAYS_ON_COUNTER_H, &h); + gmu_core_regread(device, A6XX_GMU_CX_GMU_ALWAYS_ON_COUNTER_L, &l); + gmu_core_regread(device, A6XX_GMU_CX_GMU_ALWAYS_ON_COUNTER_H, &h1); /* * If there's no change in COUNTER_H we have no overflow so return, @@ -309,13 +350,13 @@ static uint64_t read_AO_counter(struct kgsl_device *device) if (h == h1) return (uint64_t) l | ((uint64_t) h << 32); - kgsl_gmu_regread(device, A6XX_GMU_CX_GMU_ALWAYS_ON_COUNTER_L, &l); + gmu_core_regread(device, A6XX_GMU_CX_GMU_ALWAYS_ON_COUNTER_L, &l); return (uint64_t) l | ((uint64_t) h1 << 32); } static int a6xx_rpmh_power_on_gpu(struct kgsl_device *device) { - struct gmu_device *gmu = &device->gmu; + struct gmu_device *gmu = KGSL_GMU_DEVICE(device); struct device *dev = &gmu->pdev->dev; int val; @@ -323,13 +364,13 @@ static int a6xx_rpmh_power_on_gpu(struct kgsl_device *device) if (!test_bit(GMU_RSCC_SLEEP_SEQ_DONE, &gmu->flags)) return 0; - kgsl_gmu_regread(device, A6XX_GPU_CC_GX_DOMAIN_MISC, &val); + gmu_core_regread(device, A6XX_GPU_CC_GX_DOMAIN_MISC, &val); if (!(val & 0x1)) dev_err_ratelimited(&gmu->pdev->dev, "GMEM CLAMP IO not set while GFX rail off\n"); /* RSC wake sequence */ - kgsl_gmu_regwrite(device, A6XX_GMU_RSCC_CONTROL_REQ, BIT(1)); + gmu_core_regwrite(device, A6XX_GMU_RSCC_CONTROL_REQ, BIT(1)); /* Write request before polling */ wmb(); @@ -350,13 +391,13 @@ static int a6xx_rpmh_power_on_gpu(struct kgsl_device *device) 0xFFFFFFFF)) goto error_rsc; - kgsl_gmu_regwrite(device, A6XX_GMU_RSCC_CONTROL_REQ, 0); + gmu_core_regwrite(device, A6XX_GMU_RSCC_CONTROL_REQ, 0); /* Clear sleep sequence flag as wakeup sequence is successful */ clear_bit(GMU_RSCC_SLEEP_SEQ_DONE, &gmu->flags); /* Enable the power counter because it was disabled before slumber */ - kgsl_gmu_regwrite(device, A6XX_GMU_CX_GMU_POWER_COUNTER_ENABLE, 1); + gmu_core_regwrite(device, A6XX_GMU_CX_GMU_POWER_COUNTER_ENABLE, 1); return 0; error_rsc: @@ -366,7 +407,7 @@ static int a6xx_rpmh_power_on_gpu(struct kgsl_device *device) static int a6xx_rpmh_power_off_gpu(struct kgsl_device *device) { - struct gmu_device *gmu = &device->gmu; + struct gmu_device *gmu = KGSL_GMU_DEVICE(device); struct adreno_device *adreno_dev = ADRENO_DEVICE(device); int ret; @@ -375,9 +416,9 @@ static int a6xx_rpmh_power_off_gpu(struct kgsl_device *device) /* RSC sleep sequence is different on v1 */ if (adreno_is_a630v1(adreno_dev)) - kgsl_gmu_regwrite(device, A6XX_RSCC_TIMESTAMP_UNIT1_EN_DRV0, 1); + gmu_core_regwrite(device, A6XX_RSCC_TIMESTAMP_UNIT1_EN_DRV0, 1); - kgsl_gmu_regwrite(device, A6XX_GMU_RSCC_CONTROL_REQ, 1); + gmu_core_regwrite(device, A6XX_GMU_RSCC_CONTROL_REQ, 1); /* Make sure the request completes before continuing */ wmb(); @@ -401,19 +442,19 @@ static int a6xx_rpmh_power_off_gpu(struct kgsl_device *device) /* Read to clear the timestamp valid signal. Don't care what we read. */ if (adreno_is_a630v1(adreno_dev)) { - kgsl_gmu_regread(device, + gmu_core_regread(device, A6XX_RSCC_TIMESTAMP_UNIT0_TIMESTAMP_L_DRV0, &ret); - kgsl_gmu_regread(device, + gmu_core_regread(device, A6XX_RSCC_TIMESTAMP_UNIT0_TIMESTAMP_H_DRV0, &ret); } - kgsl_gmu_regwrite(device, A6XX_GMU_RSCC_CONTROL_REQ, 0); + gmu_core_regwrite(device, A6XX_GMU_RSCC_CONTROL_REQ, 0); if (ADRENO_FEATURE(adreno_dev, ADRENO_LM) && test_bit(ADRENO_LM_CTRL, &adreno_dev->pwrctrl_flag)) - kgsl_gmu_regwrite(device, A6XX_GMU_AO_SPARE_CNTL, 0); + gmu_core_regwrite(device, A6XX_GMU_AO_SPARE_CNTL, 0); set_bit(GMU_RSCC_SLEEP_SEQ_DONE, &gmu->flags); return 0; @@ -436,7 +477,7 @@ static int a6xx_rpmh_power_off_gpu(struct kgsl_device *device) static int load_gmu_fw(struct kgsl_device *device) { - struct gmu_device *gmu = &device->gmu; + struct gmu_device *gmu = KGSL_GMU_DEVICE(device); uint32_t *fwptr = gmu->fw_image->hostptr; int i, j, ret; int start_addr, size_in_bytes, num_dwords, tcm_slot, num_records; @@ -462,7 +503,7 @@ static int load_gmu_fw(struct kgsl_device *device) tcm_slot = start_addr / sizeof(uint32_t); for (j = 0; j < num_dwords; j++) - kgsl_gmu_regwrite(device, + gmu_core_regwrite(device, A6XX_GMU_CM3_ITCM_START + tcm_slot + j, fwptr[j]); } else if ((start_addr >= GMU_DTCM_VA_START) && @@ -471,7 +512,7 @@ static int load_gmu_fw(struct kgsl_device *device) / sizeof(uint32_t); for (j = 0; j < num_dwords; j++) - kgsl_gmu_regwrite(device, + gmu_core_regwrite(device, A6XX_GMU_CM3_DTCM_START + tcm_slot + j, fwptr[j]); } else if ((start_addr >= GMU_ICACHE_VA_START) && @@ -499,22 +540,22 @@ static int load_gmu_fw(struct kgsl_device *device) * @adreno_dev: Pointer to adreno device * @req: Which of the OOB bits to request */ -int a6xx_gmu_oob_set(struct adreno_device *adreno_dev, +static int a6xx_gmu_oob_set(struct adreno_device *adreno_dev, enum oob_request req) { struct kgsl_device *device = KGSL_DEVICE(adreno_dev); - struct gmu_device *gmu = &device->gmu; + struct gmu_device *gmu = KGSL_GMU_DEVICE(device); int ret = 0; int set, check; - if (!kgsl_gmu_isenabled(device)) + if (!gmu_core_isenabled(device)) return 0; if (adreno_is_a640(adreno_dev)) { set = BIT(30 - req * 2); check = BIT(31 - req); - if ((device->gmu.hfi.version & 0x1F) == 0) { + if ((gmu->hfi.version & 0x1F) == 0) { /* LEGACY for intermediate oobs */ set = BIT(req + 16); check = BIT(req + 16); @@ -530,7 +571,7 @@ int a6xx_gmu_oob_set(struct adreno_device *adreno_dev, check = BIT(req + 24); } - kgsl_gmu_regwrite(device, A6XX_GMU_HOST2GMU_INTR_SET, set); + gmu_core_regwrite(device, A6XX_GMU_HOST2GMU_INTR_SET, set); if (timed_poll_check(device, A6XX_GMU_GMU2HOST_INTR_INFO, @@ -542,7 +583,7 @@ int a6xx_gmu_oob_set(struct adreno_device *adreno_dev, "OOB_set(0x%x) timed out\n", set); } - kgsl_gmu_regwrite(device, A6XX_GMU_GMU2HOST_INTR_CLR, check); + gmu_core_regwrite(device, A6XX_GMU_GMU2HOST_INTR_CLR, check); trace_kgsl_gmu_oob_set(set); return ret; @@ -553,14 +594,14 @@ int a6xx_gmu_oob_set(struct adreno_device *adreno_dev, * @adreno_dev: Pointer to the adreno device that has the GMU * @req: Which of the OOB bits to clear */ -void a6xx_gmu_oob_clear(struct adreno_device *adreno_dev, +static inline void a6xx_gmu_oob_clear(struct adreno_device *adreno_dev, enum oob_request req) { struct kgsl_device *device = KGSL_DEVICE(adreno_dev); - struct gmu_device *gmu = &device->gmu; + struct gmu_device *gmu = KGSL_GMU_DEVICE(device); int clear; - if (!kgsl_gmu_isenabled(device)) + if (!gmu_core_isenabled(device)) return; if (adreno_is_a640(adreno_dev)) { @@ -571,16 +612,26 @@ void a6xx_gmu_oob_clear(struct adreno_device *adreno_dev, return; } /* LEGACY for intermediate oobs */ - if ((device->gmu.hfi.version & 0x1F) == 0) + if ((gmu->hfi.version & 0x1F) == 0) clear = BIT(req + 24); } else clear = BIT(req + 24); - kgsl_gmu_regwrite(device, A6XX_GMU_HOST2GMU_INTR_SET, clear); + gmu_core_regwrite(device, A6XX_GMU_HOST2GMU_INTR_SET, clear); trace_kgsl_gmu_oob_clear(clear); } +static int a6xx_gmu_hfi_start_msg(struct adreno_device *adreno_dev) +{ + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); + struct hfi_start_cmd req; + if (!adreno_is_a640(adreno_dev)) + return 0; + + /* Send hfi start msg */ + return hfi_send_req(KGSL_GMU_DEVICE(device), H2F_MSG_START, &req); +} #define FREQ_VOTE(idx, ack) (((idx) & 0xFF) | (((ack) & 0xF) << 28)) #define BW_VOTE(idx) ((((idx) & 0xFFF) << 12) | ((idx) & 0xFFF)) @@ -599,16 +650,16 @@ static int a6xx_gmu_dcvs_nohfi(struct kgsl_device *device, struct adreno_device *adreno_dev = ADRENO_DEVICE(device); int ret; - kgsl_gmu_regwrite(device, A6XX_GMU_DCVS_ACK_OPTION, DCVS_ACK_NONBLOCK); + gmu_core_regwrite(device, A6XX_GMU_DCVS_ACK_OPTION, DCVS_ACK_NONBLOCK); - kgsl_gmu_regwrite(device, A6XX_GMU_DCVS_PERF_SETTING, + gmu_core_regwrite(device, A6XX_GMU_DCVS_PERF_SETTING, FREQ_VOTE(perf_idx, CLKSET_OPTION_ATLEAST)); - kgsl_gmu_regwrite(device, A6XX_GMU_DCVS_BW_SETTING, BW_VOTE(bw_idx)); + gmu_core_regwrite(device, A6XX_GMU_DCVS_BW_SETTING, BW_VOTE(bw_idx)); ret = a6xx_gmu_oob_set(adreno_dev, oob_dcvs); if (ret == 0) - kgsl_gmu_regread(device, A6XX_GMU_DCVS_RETURN, &ret); + gmu_core_regread(device, A6XX_GMU_DCVS_RETURN, &ret); a6xx_gmu_oob_clear(adreno_dev, oob_dcvs); @@ -618,7 +669,7 @@ static int a6xx_complete_rpmh_votes(struct kgsl_device *device) { int ret = 0; - if (!kgsl_gmu_isenabled(device)) + if (!gmu_core_isenabled(device)) return ret; ret |= timed_poll_check(device, A6XX_RSCC_TCS0_DRV0_STATUS, BIT(0), @@ -647,15 +698,15 @@ static int a6xx_complete_rpmh_votes(struct kgsl_device *device) int a6xx_gmu_sptprac_enable(struct adreno_device *adreno_dev) { struct kgsl_device *device = KGSL_DEVICE(adreno_dev); - struct gmu_device *gmu = &device->gmu; + struct gmu_device *gmu = KGSL_GMU_DEVICE(device); - if (!kgsl_gmu_gpmu_isenabled(device)) + if (!gmu_core_gpmu_isenabled(device)) return -EINVAL; if (!adreno_has_sptprac_gdsc(adreno_dev)) return 0; - kgsl_gmu_regwrite(device, A6XX_GMU_GX_SPTPRAC_POWER_CONTROL, + gmu_core_regwrite(device, A6XX_GMU_GX_SPTPRAC_POWER_CONTROL, SPTPRAC_POWERON_CTRL_MASK); if (timed_poll_check(device, @@ -677,19 +728,19 @@ int a6xx_gmu_sptprac_enable(struct adreno_device *adreno_dev) void a6xx_gmu_sptprac_disable(struct adreno_device *adreno_dev) { struct kgsl_device *device = KGSL_DEVICE(adreno_dev); - struct gmu_device *gmu = &device->gmu; + struct gmu_device *gmu = KGSL_GMU_DEVICE(device); if (!adreno_has_sptprac_gdsc(adreno_dev)) return; - if (!kgsl_gmu_gpmu_isenabled(device)) + if (!gmu_core_gpmu_isenabled(device)) return; /* Ensure that retention is on */ - kgsl_gmu_regrmw(device, A6XX_GPU_CC_GX_GDSCR, 0, + gmu_core_regrmw(device, A6XX_GPU_CC_GX_GDSCR, 0, A6XX_RETAIN_FF_ENABLE_ENABLE_MASK); - kgsl_gmu_regwrite(device, A6XX_GMU_GX_SPTPRAC_POWER_CONTROL, + gmu_core_regwrite(device, A6XX_GMU_GX_SPTPRAC_POWER_CONTROL, SPTPRAC_POWEROFF_CTRL_MASK); if (timed_poll_check(device, @@ -716,10 +767,10 @@ bool a6xx_gmu_gx_is_on(struct adreno_device *adreno_dev) struct kgsl_device *device = KGSL_DEVICE(adreno_dev); unsigned int val; - if (!kgsl_gmu_isenabled(device)) + if (!gmu_core_isenabled(device)) return true; - kgsl_gmu_regread(device, A6XX_GMU_SPTPRAC_PWR_CLK_STATUS, &val); + gmu_core_regread(device, A6XX_GMU_SPTPRAC_PWR_CLK_STATUS, &val); return is_on(val); } @@ -734,10 +785,10 @@ bool a6xx_gmu_sptprac_is_on(struct adreno_device *adreno_dev) struct kgsl_device *device = KGSL_DEVICE(adreno_dev); unsigned int val; - if (!kgsl_gmu_isenabled(device) || !adreno_has_sptprac_gdsc(adreno_dev)) + if (!gmu_core_isenabled(device) || !adreno_has_sptprac_gdsc(adreno_dev)) return true; - kgsl_gmu_regread(device, A6XX_GMU_SPTPRAC_PWR_CLK_STATUS, &val); + gmu_core_regread(device, A6XX_GMU_SPTPRAC_PWR_CLK_STATUS, &val); return !(val & (SPTPRAC_POWER_OFF | SP_CLK_OFF)); } @@ -750,15 +801,15 @@ static int a6xx_gmu_gfx_rail_on(struct kgsl_device *device) { struct adreno_device *adreno_dev = ADRENO_DEVICE(device); struct kgsl_pwrctrl *pwr = &device->pwrctrl; - struct gmu_device *gmu = &device->gmu; + struct gmu_device *gmu = KGSL_GMU_DEVICE(device); unsigned int perf_idx = pwr->num_pwrlevels - pwr->default_pwrlevel - 1; uint32_t default_opp = gmu->rpmh_votes.gx_votes[perf_idx]; - kgsl_gmu_regwrite(device, A6XX_GMU_BOOT_SLUMBER_OPTION, + gmu_core_regwrite(device, A6XX_GMU_BOOT_SLUMBER_OPTION, OOB_BOOT_OPTION); - kgsl_gmu_regwrite(device, A6XX_GMU_GX_VOTE_IDX, + gmu_core_regwrite(device, A6XX_GMU_GX_VOTE_IDX, ARC_VOTE_GET_PRI(default_opp)); - kgsl_gmu_regwrite(device, A6XX_GMU_MX_VOTE_IDX, + gmu_core_regwrite(device, A6XX_GMU_MX_VOTE_IDX, ARC_VOTE_GET_SEC(default_opp)); return a6xx_gmu_oob_set(adreno_dev, oob_boot_slumber); @@ -784,24 +835,24 @@ static bool idle_trandition_complete(unsigned int idle_level, return true; } -int a6xx_gmu_wait_for_lowest_idle(struct adreno_device *adreno_dev) +static int a6xx_gmu_wait_for_lowest_idle(struct adreno_device *adreno_dev) { struct kgsl_device *device = KGSL_DEVICE(adreno_dev); - struct gmu_device *gmu = &device->gmu; + struct gmu_device *gmu = KGSL_GMU_DEVICE(device); unsigned int reg, reg1; unsigned long t; uint64_t ts1, ts2, ts3; - if (!kgsl_gmu_isenabled(device)) + if (!gmu_core_isenabled(device)) return 0; ts1 = read_AO_counter(device); t = jiffies + msecs_to_jiffies(GMU_IDLE_TIMEOUT); do { - kgsl_gmu_regread(device, + gmu_core_regread(device, A6XX_GPU_GMU_CX_GMU_RPMH_POWER_STATE, ®); - kgsl_gmu_regread(device, + gmu_core_regread(device, A6XX_GMU_SPTPRAC_PWR_CLK_STATUS, ®1); if (idle_trandition_complete(gmu->idle_level, reg, reg1)) @@ -813,8 +864,8 @@ int a6xx_gmu_wait_for_lowest_idle(struct adreno_device *adreno_dev) ts2 = read_AO_counter(device); /* Check one last time */ - kgsl_gmu_regread(device, A6XX_GPU_GMU_CX_GMU_RPMH_POWER_STATE, ®); - kgsl_gmu_regread(device, A6XX_GMU_SPTPRAC_PWR_CLK_STATUS, ®1); + gmu_core_regread(device, A6XX_GPU_GMU_CX_GMU_RPMH_POWER_STATE, ®); + gmu_core_regread(device, A6XX_GMU_SPTPRAC_PWR_CLK_STATUS, ®1); if (idle_trandition_complete(gmu->idle_level, reg, reg1)) return 0; @@ -826,17 +877,19 @@ int a6xx_gmu_wait_for_lowest_idle(struct adreno_device *adreno_dev) return -ETIMEDOUT; } -int a6xx_gmu_wait_for_idle(struct adreno_device *adreno_dev) +/* Bitmask for GPU idle status check */ +#define CXGXCPUBUSYIGNAHB BIT(30) +static int a6xx_gmu_wait_for_idle(struct adreno_device *adreno_dev) { struct kgsl_device *device = KGSL_DEVICE(adreno_dev); - struct gmu_device *gmu = &device->gmu; + struct gmu_device *gmu = KGSL_GMU_DEVICE(device); unsigned int status2; uint64_t ts1; ts1 = read_AO_counter(device); if (timed_poll_check(device, A6XX_GPU_GMU_AO_GPU_CX_BUSY_STATUS, 0, GMU_START_TIMEOUT, CXGXCPUBUSYIGNAHB)) { - kgsl_gmu_regread(device, + gmu_core_regread(device, A6XX_GPU_GMU_AO_GPU_CX_BUSY_STATUS2, &status2); dev_err(&gmu->pdev->dev, "GMU not idling: status2=0x%x %llx %llx\n", @@ -856,15 +909,16 @@ static int a6xx_gmu_fw_start(struct kgsl_device *device, unsigned int boot_state) { struct adreno_device *adreno_dev = ADRENO_DEVICE(device); - struct gmu_device *gmu = &device->gmu; + struct gmu_device *gmu = KGSL_GMU_DEVICE(device); struct gmu_memdesc *mem_addr = gmu->hfi_mem; + uint32_t gmu_log_info; int ret; unsigned int chipid = 0; switch (boot_state) { case GMU_COLD_BOOT: /* Turn on TCM retention */ - kgsl_gmu_regwrite(device, A6XX_GMU_GENERAL_7, 1); + gmu_core_regwrite(device, A6XX_GMU_GENERAL_7, 1); if (!test_and_set_bit(GMU_BOOT_INIT_DONE, &gmu->flags)) _load_gmu_rpmh_ucode(device); @@ -895,14 +949,14 @@ static int a6xx_gmu_fw_start(struct kgsl_device *device, } /* Clear init result to make sure we are getting fresh value */ - kgsl_gmu_regwrite(device, A6XX_GMU_CM3_FW_INIT_RESULT, 0); - kgsl_gmu_regwrite(device, A6XX_GMU_CM3_BOOT_CONFIG, gmu->load_mode); + gmu_core_regwrite(device, A6XX_GMU_CM3_FW_INIT_RESULT, 0); + gmu_core_regwrite(device, A6XX_GMU_CM3_BOOT_CONFIG, gmu->load_mode); - kgsl_gmu_regwrite(device, A6XX_GMU_HFI_QTBL_ADDR, + gmu_core_regwrite(device, A6XX_GMU_HFI_QTBL_ADDR, mem_addr->gmuaddr); - kgsl_gmu_regwrite(device, A6XX_GMU_HFI_QTBL_INFO, 1); + gmu_core_regwrite(device, A6XX_GMU_HFI_QTBL_INFO, 1); - kgsl_gmu_regwrite(device, A6XX_GMU_AHB_FENCE_RANGE_0, + gmu_core_regwrite(device, A6XX_GMU_AHB_FENCE_RANGE_0, FENCE_RANGE_MASK); /* Pass chipid to GMU FW, must happen before starting GMU */ @@ -918,8 +972,13 @@ static int a6xx_gmu_fw_start(struct kgsl_device *device, chipid = chipid | (ADRENO_CHIPID_MINOR(adreno_dev->chipid) << 12) | (ADRENO_CHIPID_PATCH(adreno_dev->chipid) << 8); - kgsl_gmu_regwrite(device, A6XX_GMU_HFI_SFR_ADDR, chipid); - init_gmu_log_base(device); + gmu_core_regwrite(device, A6XX_GMU_HFI_SFR_ADDR, chipid); + + /* Log size is encoded in (number of 4K units - 1) */ + gmu_log_info = (gmu->gmu_log->gmuaddr & 0xFFFFF000) | + ((LOGMEM_SIZE/SZ_4K - 1) & 0xFF); + gmu_core_regwrite(device, A6XX_GPU_GMU_CX_GMU_PWR_COL_CP_MSG, + gmu_log_info); /* Configure power control and bring the GMU out of reset */ a6xx_gmu_power_config(device); @@ -954,16 +1013,16 @@ static int a6xx_gmu_fw_start(struct kgsl_device *device, * a6xx_gmu_load_firmware() - Load the ucode into the GPMU RAM & PDC/RSC * @device: Pointer to KGSL device */ -int a6xx_gmu_load_firmware(struct kgsl_device *device) +static int a6xx_gmu_load_firmware(struct kgsl_device *device) { const struct firmware *fw = NULL; const struct adreno_device *adreno_dev = ADRENO_DEVICE(device); - struct gmu_device *gmu = &device->gmu; + struct gmu_device *gmu = KGSL_GMU_DEVICE(device); const struct adreno_gpu_core *gpucore = adreno_dev->gpucore; int image_size, ret = -EINVAL; /* there is no GMU */ - if (!kgsl_gmu_isenabled(device)) + if (!gmu_core_isenabled(device)) return 0; /* GMU fw already saved and verified so do nothing new */ @@ -1003,16 +1062,16 @@ static int a6xx_llm_glm_handshake(struct kgsl_device *device) { unsigned int val; const struct adreno_device *adreno_dev = ADRENO_DEVICE(device); - struct gmu_device *gmu = &device->gmu; + struct gmu_device *gmu = KGSL_GMU_DEVICE(device); if (!ADRENO_FEATURE(adreno_dev, ADRENO_LM) || - !test_bit(ADRENO_LM_CTRL, &adreno_dev->pwrctrl_flag)) + !test_bit(ADRENO_LM_CTRL, &adreno_dev->pwrctrl_flag)) return 0; - kgsl_gmu_regread(device, A6XX_GMU_LLM_GLM_SLEEP_CTRL, &val); + gmu_core_regread(device, A6XX_GMU_LLM_GLM_SLEEP_CTRL, &val); if (!(val & A6XX_STATE_OF_CHILD)) { - kgsl_gmu_regrmw(device, A6XX_GMU_LLM_GLM_SLEEP_CTRL, 0, BIT(4)); - kgsl_gmu_regrmw(device, A6XX_GMU_LLM_GLM_SLEEP_CTRL, 0, + gmu_core_regrmw(device, A6XX_GMU_LLM_GLM_SLEEP_CTRL, 0, BIT(4)); + gmu_core_regrmw(device, A6XX_GMU_LLM_GLM_SLEEP_CTRL, 0, A6XX_IDLE_FULL_LLM); if (timed_poll_check(device, A6XX_GMU_LLM_GLM_SLEEP_STATUS, A6XX_IDLE_FULL_ACK, GPU_RESET_TIMEOUT, @@ -1034,10 +1093,10 @@ static void a6xx_isense_disable(struct kgsl_device *device) !test_bit(ADRENO_LM_CTRL, &adreno_dev->pwrctrl_flag)) return; - kgsl_gmu_regread(device, A6XX_GPU_CS_ENABLE_REG, &val); + gmu_core_regread(device, A6XX_GPU_CS_ENABLE_REG, &val); if (val) { - kgsl_gmu_regwrite(device, A6XX_GPU_CS_ENABLE_REG, 0); - kgsl_gmu_regwrite(device, A6XX_GMU_ISENSE_CTRL, 0); + gmu_core_regwrite(device, A6XX_GPU_CS_ENABLE_REG, 0); + gmu_core_regwrite(device, A6XX_GMU_ISENSE_CTRL, 0); } } @@ -1045,7 +1104,7 @@ static int a6xx_gmu_suspend(struct kgsl_device *device) { /* Max GX clients on A6xx is 2: GMU and KMD */ int ret = 0, max_client_num = 2; - struct gmu_device *gmu = &device->gmu; + struct gmu_device *gmu = KGSL_GMU_DEVICE(device); struct adreno_device *adreno_dev = ADRENO_DEVICE(device); /* do it only if LM feature is enabled */ @@ -1099,13 +1158,13 @@ static int a6xx_gmu_notify_slumber(struct kgsl_device *device) { struct adreno_device *adreno_dev = ADRENO_DEVICE(device); struct kgsl_pwrctrl *pwr = &device->pwrctrl; - struct gmu_device *gmu = &device->gmu; + struct gmu_device *gmu = KGSL_GMU_DEVICE(device); int bus_level = pwr->pwrlevels[pwr->default_pwrlevel].bus_freq; int perf_idx = gmu->num_gpupwrlevels - pwr->default_pwrlevel - 1; int ret, state; /* Disable the power counter so that the GMU is not busy */ - kgsl_gmu_regwrite(device, A6XX_GMU_CX_GMU_POWER_COUNTER_ENABLE, 0); + gmu_core_regwrite(device, A6XX_GMU_CX_GMU_POWER_COUNTER_ENABLE, 0); /* Turn off SPTPRAC if we own it */ if (gmu->idle_level < GPU_HW_SPTP_PC) @@ -1121,16 +1180,16 @@ static int a6xx_gmu_notify_slumber(struct kgsl_device *device) goto out; } - kgsl_gmu_regwrite(device, A6XX_GMU_BOOT_SLUMBER_OPTION, + gmu_core_regwrite(device, A6XX_GMU_BOOT_SLUMBER_OPTION, OOB_SLUMBER_OPTION); - kgsl_gmu_regwrite(device, A6XX_GMU_GX_VOTE_IDX, perf_idx); - kgsl_gmu_regwrite(device, A6XX_GMU_MX_VOTE_IDX, bus_level); + gmu_core_regwrite(device, A6XX_GMU_GX_VOTE_IDX, perf_idx); + gmu_core_regwrite(device, A6XX_GMU_MX_VOTE_IDX, bus_level); ret = a6xx_gmu_oob_set(adreno_dev, oob_boot_slumber); a6xx_gmu_oob_clear(adreno_dev, oob_boot_slumber); if (!ret) { - kgsl_gmu_regread(device, + gmu_core_regread(device, A6XX_GPU_GMU_CX_GMU_RPMH_POWER_STATE, &state); if (state != GPU_HW_SLUMBER) { dev_err(&gmu->pdev->dev, @@ -1142,7 +1201,7 @@ static int a6xx_gmu_notify_slumber(struct kgsl_device *device) out: /* Make sure the fence is in ALLOW mode */ - kgsl_gmu_regwrite(device, A6XX_GMU_AO_AHB_FENCE_CTRL, 0); + gmu_core_regwrite(device, A6XX_GMU_AO_AHB_FENCE_CTRL, 0); return ret; } @@ -1153,11 +1212,11 @@ static int a6xx_gmu_notify_slumber(struct kgsl_device *device) * @arg1: first argument for mode control * @arg2: second argument for mode control */ -int a6xx_gmu_rpmh_gpu_pwrctrl(struct adreno_device *adreno_dev, +static int a6xx_gmu_rpmh_gpu_pwrctrl(struct adreno_device *adreno_dev, unsigned int mode, unsigned int arg1, unsigned int arg2) { struct kgsl_device *device = KGSL_DEVICE(adreno_dev); - struct gmu_device *gmu = &device->gmu; + struct gmu_device *gmu = KGSL_GMU_DEVICE(device); int ret; switch (mode) { @@ -1215,15 +1274,19 @@ static uint32_t lm_limit(struct adreno_device *adreno_dev) void a6xx_gmu_enable_lm(struct kgsl_device *device) { int result; - struct gmu_device *gmu = &device->gmu; + struct gmu_device *gmu = KGSL_GMU_DEVICE(device); struct adreno_device *adreno_dev = ADRENO_DEVICE(device); struct device *dev = &gmu->pdev->dev; struct hfi_lmconfig_cmd cmd; - kgsl_gmu_regwrite(device, A6XX_GPU_GMU_CX_GMU_PWR_THRESHOLD, + if (!ADRENO_FEATURE(adreno_dev, ADRENO_LM) || + !test_bit(ADRENO_LM_CTRL, &adreno_dev->pwrctrl_flag)) + return; + + gmu_core_regwrite(device, A6XX_GPU_GMU_CX_GMU_PWR_THRESHOLD, GPU_LIMIT_THRESHOLD_ENABLE | lm_limit(adreno_dev)); - kgsl_gmu_regwrite(device, A6XX_GMU_AO_SPARE_CNTL, 1); - kgsl_gmu_regwrite(device, A6XX_GPU_GMU_CX_GMU_ISENSE_CTRL, 0x1); + gmu_core_regwrite(device, A6XX_GMU_AO_SPARE_CNTL, 1); + gmu_core_regwrite(device, A6XX_GPU_GMU_CX_GMU_ISENSE_CTRL, 0x1); gmu->lm_config = LIMITS_CONFIG(1, 1, 1, 0, 0); gmu->bcl_config = 0; @@ -1240,5 +1303,142 @@ void a6xx_gmu_enable_lm(struct kgsl_device *device) result = hfi_send_req(gmu, H2F_MSG_LM_CFG, &cmd); if (result) dev_err(dev, "Failure enabling limits management:%d\n", result); +} + +static int a6xx_gmu_ifpc_store(struct adreno_device *adreno_dev, + unsigned int val) +{ + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); + struct gmu_device *gmu = KGSL_GMU_DEVICE(device); + unsigned int requested_idle_level; + + if (!gmu_core_isenabled(device) || + !ADRENO_FEATURE(adreno_dev, ADRENO_IFPC)) + return -EINVAL; + + if ((val && gmu->idle_level >= GPU_HW_IFPC) || + (!val && gmu->idle_level < GPU_HW_IFPC)) + return 0; + + if (val) + requested_idle_level = GPU_HW_IFPC; + else { + if (ADRENO_FEATURE(adreno_dev, ADRENO_SPTP_PC)) + requested_idle_level = GPU_HW_SPTP_PC; + else + requested_idle_level = GPU_HW_ACTIVE; + } + + mutex_lock(&device->mutex); + + /* Power down the GPU before changing the idle level */ + kgsl_pwrctrl_change_state(device, KGSL_STATE_SUSPEND); + gmu->idle_level = requested_idle_level; + kgsl_pwrctrl_change_state(device, KGSL_STATE_SLUMBER); + + mutex_unlock(&device->mutex); + + return 0; +} +static unsigned int a6xx_gmu_ifpc_show(struct adreno_device *adreno_dev) +{ + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); + struct gmu_device *gmu = KGSL_GMU_DEVICE(device); + + return gmu_core_isenabled(device) && gmu->idle_level >= GPU_HW_IFPC; +} + +struct gmu_mem_type_desc { + struct gmu_memdesc *memdesc; + uint32_t type; +}; + +static size_t a6xx_snapshot_gmu_mem(struct kgsl_device *device, + u8 *buf, size_t remain, void *priv) +{ + struct kgsl_snapshot_gmu *header = (struct kgsl_snapshot_gmu *)buf; + struct gmu_mem_type_desc *desc = priv; + unsigned int *data = (unsigned int *)(buf + sizeof(*header)); + + if (priv == NULL) + return 0; + + if (remain < desc->memdesc->size + sizeof(*header)) { + KGSL_CORE_ERR( + "snapshot: Not enough memory for the gmu section %d\n", + desc->type); + return 0; + } + + header->type = desc->type; + header->size = desc->memdesc->size; + + /* Just copy the ringbuffer, there are no active IBs */ + memcpy(data, desc->memdesc->hostptr, desc->memdesc->size); + + return desc->memdesc->size + sizeof(*header); } + +/* + * a6xx_gmu_snapshot() - A6XX GMU snapshot function + * @adreno_dev: Device being snapshotted + * @snapshot: Pointer to the snapshot instance + * + * This is where all of the A6XX GMU specific bits and pieces are grabbed + * into the snapshot memory + */ +void a6xx_gmu_snapshot(struct adreno_device *adreno_dev, + struct kgsl_snapshot *snapshot) +{ + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); + struct gmu_device *gmu = KGSL_GMU_DEVICE(device); + struct gmu_mem_type_desc desc[] = { + {gmu->hfi_mem, SNAPSHOT_GMU_HFIMEM}, + {gmu->gmu_log, SNAPSHOT_GMU_LOG}, + {gmu->bw_mem, SNAPSHOT_GMU_BWMEM}, + {gmu->dump_mem, SNAPSHOT_GMU_DUMPMEM} }; + struct adreno_gpudev *gpudev = ADRENO_GPU_DEVICE(adreno_dev); + unsigned int val, i; + + if (!gmu_core_isenabled(device)) + return; + + for (i = 0; i < ARRAY_SIZE(desc); i++) { + if (desc[i].memdesc) + kgsl_snapshot_add_section(device, + KGSL_SNAPSHOT_SECTION_GMU, + snapshot, a6xx_snapshot_gmu_mem, + &desc[i]); + } + + adreno_snapshot_registers(device, snapshot, a6xx_gmu_registers, + ARRAY_SIZE(a6xx_gmu_registers) / 2); + + if (gpudev->gx_is_on(adreno_dev)) { + /* Set fence to ALLOW mode so registers can be read */ + kgsl_regwrite(device, A6XX_GMU_AO_AHB_FENCE_CTRL, 0); + kgsl_regread(device, A6XX_GMU_AO_AHB_FENCE_CTRL, &val); + + KGSL_DRV_ERR(device, "set FENCE to ALLOW mode:%x\n", val); + adreno_snapshot_registers(device, snapshot, + a6xx_gmu_gx_registers, + ARRAY_SIZE(a6xx_gmu_gx_registers) / 2); + } +} + +struct gmu_dev_ops adreno_a6xx_gmudev = { + .load_firmware = a6xx_gmu_load_firmware, + .oob_set = a6xx_gmu_oob_set, + .oob_clear = a6xx_gmu_oob_clear, + .hfi_start_msg = a6xx_gmu_hfi_start_msg, + .enable_lm = a6xx_gmu_enable_lm, + .rpmh_gpu_pwrctrl = a6xx_gmu_rpmh_gpu_pwrctrl, + .wait_for_lowest_idle = a6xx_gmu_wait_for_lowest_idle, + .wait_for_gmu_idle = a6xx_gmu_wait_for_idle, + .sptprac_enable = a6xx_gmu_sptprac_enable, + .sptprac_disable = a6xx_gmu_sptprac_disable, + .ifpc_store = a6xx_gmu_ifpc_store, + .ifpc_show = a6xx_gmu_ifpc_show, + .snapshot = a6xx_gmu_snapshot, +}; diff --git a/drivers/gpu/msm/adreno_a6xx_preempt.c b/drivers/gpu/msm/adreno_a6xx_preempt.c index 38db00bc03b0..0c308edea824 100644 --- a/drivers/gpu/msm/adreno_a6xx_preempt.c +++ b/drivers/gpu/msm/adreno_a6xx_preempt.c @@ -15,6 +15,7 @@ #include "a6xx_reg.h" #include "adreno_trace.h" #include "adreno_pm4types.h" +#include "kgsl_gmu_core.h" #define PREEMPT_RECORD(_field) \ offsetof(struct a6xx_cp_preemption_record, _field) @@ -35,7 +36,8 @@ static void _update_wptr(struct adreno_device *adreno_dev, bool reset_timer) struct adreno_ringbuffer *rb = adreno_dev->cur_rb; unsigned int wptr; unsigned long flags; - struct adreno_gpudev *gpudev = ADRENO_GPU_DEVICE(adreno_dev); + struct gmu_dev_ops *gmu_dev_ops = GMU_DEVICE_OPS( + KGSL_DEVICE(adreno_dev)); /* * Need to make sure GPU is up before we read the @@ -44,8 +46,8 @@ static void _update_wptr(struct adreno_device *adreno_dev, bool reset_timer) if (in_interrupt() == 0) { int status; - if (gpudev->oob_set) { - status = gpudev->oob_set(adreno_dev, oob_preempt); + if (gmu_dev_ops->oob_set) { + status = gmu_dev_ops->oob_set(adreno_dev, oob_preempt); if (status) return; } @@ -73,8 +75,8 @@ static void _update_wptr(struct adreno_device *adreno_dev, bool reset_timer) spin_unlock_irqrestore(&rb->preempt_lock, flags); if (in_interrupt() == 0) { - if (gpudev->oob_clear) - gpudev->oob_clear(adreno_dev, oob_preempt); + if (gmu_dev_ops->oob_clear) + gmu_dev_ops->oob_clear(adreno_dev, oob_preempt); } } @@ -316,7 +318,7 @@ void a6xx_preemption_trigger(struct adreno_device *adreno_dev) * free when the GPU is already powered on, whereas an OOB requires an * unconditional handshake with the GMU. */ - kgsl_gmu_regrmw(device, A6XX_GMU_AO_SPARE_CNTL, 0x0, 0x2); + gmu_core_regrmw(device, A6XX_GMU_AO_SPARE_CNTL, 0x0, 0x2); /* * Fenced writes on this path will make sure the GPU is woken up @@ -397,7 +399,7 @@ void a6xx_preemption_callback(struct adreno_device *adreno_dev, int bit) * We can now safely clear the preemption keepalive bit, allowing * power collapse to resume its regular activity. */ - kgsl_gmu_regrmw(KGSL_DEVICE(adreno_dev), A6XX_GMU_AO_SPARE_CNTL, 0x2, + gmu_core_regrmw(KGSL_DEVICE(adreno_dev), A6XX_GMU_AO_SPARE_CNTL, 0x2, 0x0); del_timer(&adreno_dev->preempt.timer); diff --git a/drivers/gpu/msm/adreno_a6xx_snapshot.c b/drivers/gpu/msm/adreno_a6xx_snapshot.c index 9dd9691055f0..6b92c077367f 100644 --- a/drivers/gpu/msm/adreno_a6xx_snapshot.c +++ b/drivers/gpu/msm/adreno_a6xx_snapshot.c @@ -18,8 +18,6 @@ #include "adreno_snapshot.h" #include "a6xx_reg.h" #include "adreno_a6xx.h" -#include "kgsl_gmu.h" -#include "kgsl_hfi.h" #define A6XX_NUM_CTXTS 2 #define A6XX_NUM_AXI_ARB_BLOCKS 2 @@ -245,44 +243,6 @@ static const unsigned int a6xx_gbif_registers[] = { 0x3C00, 0X3C0B, 0X3C40, 0X3C47, 0X3CC0, 0X3CD1, 0xE3A, 0xE3A, }; -static const unsigned int a6xx_gmu_gx_registers[] = { - /* GMU GX */ - 0x1A800, 0x1A800, 0x1A810, 0x1A813, 0x1A816, 0x1A816, 0x1A818, 0x1A81B, - 0x1A81E, 0x1A81E, 0x1A820, 0x1A823, 0x1A826, 0x1A826, 0x1A828, 0x1A82B, - 0x1A82E, 0x1A82E, 0x1A830, 0x1A833, 0x1A836, 0x1A836, 0x1A838, 0x1A83B, - 0x1A83E, 0x1A83E, 0x1A840, 0x1A843, 0x1A846, 0x1A846, 0x1A880, 0x1A884, - 0x1A900, 0x1A92B, 0x1A940, 0x1A940, -}; - -static const unsigned int a6xx_gmu_registers[] = { - /* GMU TCM */ - 0x1B400, 0x1C3FF, 0x1C400, 0x1D3FF, - /* GMU CX */ - 0x1F400, 0x1F407, 0x1F410, 0x1F412, 0x1F500, 0x1F500, 0x1F507, 0x1F50A, - 0x1F800, 0x1F804, 0x1F807, 0x1F808, 0x1F80B, 0x1F80C, 0x1F80F, 0x1F81C, - 0x1F824, 0x1F82A, 0x1F82D, 0x1F830, 0x1F840, 0x1F853, 0x1F887, 0x1F889, - 0x1F8A0, 0x1F8A2, 0x1F8A4, 0x1F8AF, 0x1F8C0, 0x1F8C3, 0x1F8D0, 0x1F8D0, - 0x1F8E4, 0x1F8E4, 0x1F8E8, 0x1F8EC, 0x1F900, 0x1F903, 0x1F940, 0x1F940, - 0x1F942, 0x1F944, 0x1F94C, 0x1F94D, 0x1F94F, 0x1F951, 0x1F954, 0x1F954, - 0x1F957, 0x1F958, 0x1F95D, 0x1F95D, 0x1F962, 0x1F962, 0x1F964, 0x1F965, - 0x1F980, 0x1F986, 0x1F990, 0x1F99E, 0x1F9C0, 0x1F9C0, 0x1F9C5, 0x1F9CC, - 0x1F9E0, 0x1F9E2, 0x1F9F0, 0x1F9F0, 0x1FA00, 0x1FA01, - /* GPU RSCC */ - 0x2348C, 0x2348C, 0x23501, 0x23502, 0x23740, 0x23742, 0x23744, 0x23747, - 0x2374C, 0x23787, 0x237EC, 0x237EF, 0x237F4, 0x2382F, 0x23894, 0x23897, - 0x2389C, 0x238D7, 0x2393C, 0x2393F, 0x23944, 0x2397F, - /* GMU AO */ - 0x23B00, 0x23B16, 0x23C00, 0x23C00, - /* GPU CC */ - 0x24000, 0x24012, 0x24040, 0x24052, 0x24400, 0x24404, 0x24407, 0x2440B, - 0x24415, 0x2441C, 0x2441E, 0x2442D, 0x2443C, 0x2443D, 0x2443F, 0x24440, - 0x24442, 0x24449, 0x24458, 0x2445A, 0x24540, 0x2455E, 0x24800, 0x24802, - 0x24C00, 0x24C02, 0x25400, 0x25402, 0x25800, 0x25802, 0x25C00, 0x25C02, - 0x26000, 0x26002, - /* GPU CC ACD */ - 0x26400, 0x26416, 0x26420, 0x26427, -}; - static const unsigned int a6xx_rb_rac_registers[] = { 0x8E04, 0x8E05, 0x8E07, 0x8E08, 0x8E10, 0x8E1C, 0x8E20, 0x8E25, 0x8E28, 0x8E28, 0x8E2C, 0x8E2F, 0x8E50, 0x8E52, @@ -1324,11 +1284,11 @@ static size_t a6xx_snapshot_cx_dbgc_debugbus_block(struct kgsl_device *device, } /* a6xx_snapshot_debugbus() - Capture debug bus data */ -static void a6xx_snapshot_debugbus(struct kgsl_device *device, +void a6xx_snapshot_debugbus(struct adreno_device *adreno_dev, struct kgsl_snapshot *snapshot) { int i; - struct adreno_device *adreno_dev = ADRENO_DEVICE(device); + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); kgsl_regwrite(device, A6XX_DBGC_CFG_DBGBUS_CNTLT, (0xf << A6XX_DBGC_CFG_DBGBUS_CNTLT_SEGT_SHIFT) | @@ -1448,85 +1408,7 @@ static void a6xx_snapshot_debugbus(struct kgsl_device *device, } } -struct gmu_mem_type_desc { - struct gmu_memdesc *memdesc; - uint32_t type; -}; - -static size_t a6xx_snapshot_gmu_mem(struct kgsl_device *device, - u8 *buf, size_t remain, void *priv) -{ - struct kgsl_snapshot_gmu *header = (struct kgsl_snapshot_gmu *)buf; - struct gmu_mem_type_desc *desc = priv; - unsigned int *data = (unsigned int *)(buf + sizeof(*header)); - - if (priv == NULL) - return 0; - - if (remain < desc->memdesc->size + sizeof(*header)) { - KGSL_CORE_ERR( - "snapshot: Not enough memory for the gmu section %d\n", - desc->type); - return 0; - } - - header->type = desc->type; - header->size = desc->memdesc->size; - - /* Just copy the ringbuffer, there are no active IBs */ - memcpy(data, desc->memdesc->hostptr, desc->memdesc->size); - - return desc->memdesc->size + sizeof(*header); -} - -/* - * a6xx_snapshot_gmu() - A6XX GMU snapshot function - * @adreno_dev: Device being snapshotted - * @snapshot: Pointer to the snapshot instance - * - * This is where all of the A6XX GMU specific bits and pieces are grabbed - * into the snapshot memory - */ -void a6xx_snapshot_gmu(struct adreno_device *adreno_dev, - struct kgsl_snapshot *snapshot) -{ - struct kgsl_device *device = KGSL_DEVICE(adreno_dev); - struct gmu_device *gmu = &device->gmu; - struct gmu_mem_type_desc desc[] = { - {gmu->hfi_mem, SNAPSHOT_GMU_HFIMEM}, - {gmu->gmu_log, SNAPSHOT_GMU_LOG}, - {gmu->bw_mem, SNAPSHOT_GMU_BWMEM}, - {gmu->dump_mem, SNAPSHOT_GMU_DUMPMEM} }; - struct adreno_gpudev *gpudev = ADRENO_GPU_DEVICE(adreno_dev); - unsigned int val, i; - if (!kgsl_gmu_isenabled(device)) - return; - - for (i = 0; i < ARRAY_SIZE(desc); i++) { - if (desc[i].memdesc) - kgsl_snapshot_add_section(device, - KGSL_SNAPSHOT_SECTION_GMU, - snapshot, a6xx_snapshot_gmu_mem, - &desc[i]); - } - - adreno_snapshot_registers(device, snapshot, a6xx_gmu_registers, - ARRAY_SIZE(a6xx_gmu_registers) / 2); - - if (gpudev->gx_is_on(adreno_dev)) { - /* Set fence to ALLOW mode so registers can be read */ - kgsl_regwrite(device, A6XX_GMU_AO_AHB_FENCE_CTRL, 0); - kgsl_regread(device, A6XX_GMU_AO_AHB_FENCE_CTRL, &val); - - KGSL_DRV_ERR(device, "set FENCE to ALLOW mode:%x\n", val); - adreno_snapshot_registers(device, snapshot, - a6xx_gmu_gx_registers, - ARRAY_SIZE(a6xx_gmu_gx_registers) / 2); - } - - a6xx_snapshot_debugbus(device, snapshot); -} /* a6xx_snapshot_sqe() - Dump SQE data in snapshot */ static size_t a6xx_snapshot_sqe(struct kgsl_device *device, u8 *buf, @@ -1614,7 +1496,7 @@ void a6xx_snapshot(struct adreno_device *adreno_dev, unsigned int i; /* GMU TCM data dumped through AHB */ - a6xx_snapshot_gmu(adreno_dev, snapshot); + a6xx_gmu_snapshot(adreno_dev, snapshot); sptprac_on = gpudev->sptprac_is_on(adreno_dev); diff --git a/drivers/gpu/msm/adreno_dispatch.c b/drivers/gpu/msm/adreno_dispatch.c index 85e814ad8ee5..5686c980dd39 100644 --- a/drivers/gpu/msm/adreno_dispatch.c +++ b/drivers/gpu/msm/adreno_dispatch.c @@ -2094,7 +2094,7 @@ static int dispatcher_do_fault(struct adreno_device *adreno_dev) return 0; /* Mask all GMU interrupts */ - if (kgsl_gmu_isenabled(device)) { + if (gmu_core_isenabled(device)) { adreno_write_gmureg(adreno_dev, ADRENO_REG_GMU_AO_HOST_INTERRUPT_MASK, 0xFFFFFFFF); diff --git a/drivers/gpu/msm/adreno_perfcounter.c b/drivers/gpu/msm/adreno_perfcounter.c index e54a5e6857ae..066423c1265c 100644 --- a/drivers/gpu/msm/adreno_perfcounter.c +++ b/drivers/gpu/msm/adreno_perfcounter.c @@ -171,8 +171,9 @@ void adreno_perfcounter_restore(struct adreno_device *adreno_dev) */ inline void adreno_perfcounter_save(struct adreno_device *adreno_dev) { - struct adreno_gpudev *gpudev = ADRENO_GPU_DEVICE(adreno_dev); struct adreno_perfcounters *counters = ADRENO_PERFCOUNTERS(adreno_dev); + struct gmu_dev_ops *gmu_dev_ops = GMU_DEVICE_OPS( + KGSL_DEVICE(adreno_dev)); struct adreno_perfcount_group *group; unsigned int counter, groupid; int ret = 0; @@ -180,8 +181,8 @@ inline void adreno_perfcounter_save(struct adreno_device *adreno_dev) if (counters == NULL) return; - if (gpudev->oob_set) - ret = gpudev->oob_set(adreno_dev, oob_perfcntr); + if (gmu_dev_ops->oob_set) + ret = gmu_dev_ops->oob_set(adreno_dev, oob_perfcntr); /* if oob_set timeout, clear the mask and return */ if (ret) @@ -208,8 +209,8 @@ inline void adreno_perfcounter_save(struct adreno_device *adreno_dev) } done: - if (gpudev->oob_clear) - gpudev->oob_clear(adreno_dev, oob_perfcntr); + if (gmu_dev_ops->oob_clear) + gmu_dev_ops->oob_clear(adreno_dev, oob_perfcntr); } static int adreno_perfcounter_enable(struct adreno_device *adreno_dev, diff --git a/drivers/gpu/msm/adreno_snapshot.c b/drivers/gpu/msm/adreno_snapshot.c index b5999e6fb6a2..df55407564f9 100644 --- a/drivers/gpu/msm/adreno_snapshot.c +++ b/drivers/gpu/msm/adreno_snapshot.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -13,6 +13,7 @@ #include "kgsl.h" #include "kgsl_sharedmem.h" #include "kgsl_snapshot.h" +#include "kgsl_gmu_core.h" #include "adreno.h" #include "adreno_pm4types.h" @@ -956,11 +957,16 @@ void adreno_snapshot_gmu(struct kgsl_device *device, struct kgsl_snapshot *snapshot) { struct adreno_device *adreno_dev = ADRENO_DEVICE(device); + struct gmu_dev_ops *gmu_dev_ops = GMU_DEVICE_OPS(device); struct adreno_gpudev *gpudev = ADRENO_GPU_DEVICE(adreno_dev); /* Add GMU specific sections */ - if (gpudev->snapshot_gmu) - gpudev->snapshot_gmu(adreno_dev, snapshot); + if (gmu_dev_ops && gmu_dev_ops->snapshot) + gmu_dev_ops->snapshot(adreno_dev, snapshot); + + if (gpudev->snapshot_debugbus) + gpudev->snapshot_debugbus(adreno_dev, snapshot); + } /* diff --git a/drivers/gpu/msm/adreno_sysfs.c b/drivers/gpu/msm/adreno_sysfs.c index 022aa9f1f994..232770e347e5 100644 --- a/drivers/gpu/msm/adreno_sysfs.c +++ b/drivers/gpu/msm/adreno_sysfs.c @@ -242,23 +242,6 @@ static int _preemption_store(struct adreno_device *adreno_dev, return 0; } -static int _gmu_idle_level_store(struct adreno_device *adreno_dev, - unsigned int val) -{ - struct kgsl_device *device = KGSL_DEVICE(adreno_dev); - struct gmu_device *gmu = &device->gmu; - - mutex_lock(&device->mutex); - - /* Power down the GPU before changing the idle level */ - kgsl_pwrctrl_change_state(device, KGSL_STATE_SUSPEND); - gmu->idle_level = val; - kgsl_pwrctrl_change_state(device, KGSL_STATE_SLUMBER); - - mutex_unlock(&device->mutex); - return 0; -} - static unsigned int _preemption_show(struct adreno_device *adreno_dev) { return adreno_is_preemption_enabled(adreno_dev); @@ -309,36 +292,12 @@ static unsigned int _lm_show(struct adreno_device *adreno_dev) static int _ifpc_store(struct adreno_device *adreno_dev, unsigned int val) { - struct kgsl_device *device = KGSL_DEVICE(adreno_dev); - struct gmu_device *gmu = &device->gmu; - unsigned int requested_idle_level; - - if (!kgsl_gmu_isenabled(device) || - !ADRENO_FEATURE(adreno_dev, ADRENO_IFPC)) - return -EINVAL; - - if ((val && gmu->idle_level >= GPU_HW_IFPC) || - (!val && gmu->idle_level < GPU_HW_IFPC)) - return 0; - - if (val) - requested_idle_level = GPU_HW_IFPC; - else { - if (ADRENO_FEATURE(adreno_dev, ADRENO_SPTP_PC)) - requested_idle_level = GPU_HW_SPTP_PC; - else - requested_idle_level = GPU_HW_ACTIVE; - } - - return _gmu_idle_level_store(adreno_dev, requested_idle_level); + return adreno_gmu_ifpc_store(adreno_dev, val); } static unsigned int _ifpc_show(struct adreno_device *adreno_dev) { - struct kgsl_device *device = KGSL_DEVICE(adreno_dev); - struct gmu_device *gmu = &device->gmu; - - return kgsl_gmu_isenabled(device) && gmu->idle_level >= GPU_HW_IFPC; + return adreno_gmu_ifpc_show(adreno_dev); } static unsigned int _preempt_count_show(struct adreno_device *adreno_dev) diff --git a/drivers/gpu/msm/kgsl_device.h b/drivers/gpu/msm/kgsl_device.h index 817e6f06cf81..704671f5685c 100644 --- a/drivers/gpu/msm/kgsl_device.h +++ b/drivers/gpu/msm/kgsl_device.h @@ -26,7 +26,7 @@ #include "kgsl_snapshot.h" #include "kgsl_sharedmem.h" #include "kgsl_drawobj.h" -#include "kgsl_gmu.h" +#include "kgsl_gmu_core.h" #define KGSL_IOCTL_FUNC(_cmd, _func) \ [_IOC_NR((_cmd))] = \ @@ -128,10 +128,6 @@ struct kgsl_functable { int (*init)(struct kgsl_device *device); int (*start)(struct kgsl_device *device, int priority); int (*stop)(struct kgsl_device *device); - void (*gmu_regread)(struct kgsl_device *device, - unsigned int offsetwords, unsigned int *value); - void (*gmu_regwrite)(struct kgsl_device *device, - unsigned int offsetwords, unsigned int value); int (*getproperty)(struct kgsl_device *device, unsigned int type, void __user *value, size_t sizebytes); @@ -269,7 +265,7 @@ struct kgsl_device { const char *shadermemname; struct kgsl_mmu mmu; - struct gmu_device gmu; + struct gmu_core_device gmu_core; struct completion hwaccess_gate; struct completion halt_gate; const struct kgsl_functable *ftbl; @@ -566,26 +562,14 @@ static inline bool kgsl_is_register_offset(struct kgsl_device *device, return ((offsetwords * sizeof(uint32_t)) < device->reg_len); } -static inline bool kgsl_is_gmu_offset(struct kgsl_device *device, - unsigned int offsetwords) -{ - struct gmu_device *gmu = &device->gmu; - - return (gmu->pdev && - (offsetwords >= gmu->gmu2gpu_offset) && - ((offsetwords - gmu->gmu2gpu_offset) * sizeof(uint32_t) < - gmu->reg_len)); -} - static inline void kgsl_regread(struct kgsl_device *device, unsigned int offsetwords, unsigned int *value) { if (kgsl_is_register_offset(device, offsetwords)) device->ftbl->regread(device, offsetwords, value); - else if (device->ftbl->gmu_regread && - kgsl_is_gmu_offset(device, offsetwords)) - device->ftbl->gmu_regread(device, offsetwords, value); + else if (gmu_core_is_register_offset(device, offsetwords)) + gmu_core_regread(device, offsetwords, value); else { WARN(1, "Out of bounds register read: 0x%x\n", offsetwords); *value = 0; @@ -598,31 +582,12 @@ static inline void kgsl_regwrite(struct kgsl_device *device, { if (kgsl_is_register_offset(device, offsetwords)) device->ftbl->regwrite(device, offsetwords, value); - else if (device->ftbl->gmu_regwrite && - kgsl_is_gmu_offset(device, offsetwords)) - device->ftbl->gmu_regwrite(device, offsetwords, value); + else if (gmu_core_is_register_offset(device, offsetwords)) + gmu_core_regwrite(device, offsetwords, value); else WARN(1, "Out of bounds register write: 0x%x\n", offsetwords); } -static inline void kgsl_gmu_regread(struct kgsl_device *device, - unsigned int offsetwords, - unsigned int *value) -{ - if (device->ftbl->gmu_regread) - device->ftbl->gmu_regread(device, offsetwords, value); - else - *value = 0; -} - -static inline void kgsl_gmu_regwrite(struct kgsl_device *device, - unsigned int offsetwords, - unsigned int value) -{ - if (device->ftbl->gmu_regwrite) - device->ftbl->gmu_regwrite(device, offsetwords, value); -} - static inline void kgsl_regrmw(struct kgsl_device *device, unsigned int offsetwords, unsigned int mask, unsigned int bits) @@ -634,17 +599,6 @@ static inline void kgsl_regrmw(struct kgsl_device *device, kgsl_regwrite(device, offsetwords, val | bits); } -static inline void kgsl_gmu_regrmw(struct kgsl_device *device, - unsigned int offsetwords, - unsigned int mask, unsigned int bits) -{ - unsigned int val = 0; - - kgsl_gmu_regread(device, offsetwords, &val); - val &= ~mask; - kgsl_gmu_regwrite(device, offsetwords, val | bits); -} - static inline int kgsl_idle(struct kgsl_device *device) { return device->ftbl->idle(device); @@ -689,13 +643,11 @@ static inline struct kgsl_device *kgsl_device_from_dev(struct device *dev) static inline int kgsl_state_is_awake(struct kgsl_device *device) { - struct gmu_device *gmu = &device->gmu; - if (device->state == KGSL_STATE_ACTIVE || device->state == KGSL_STATE_AWARE) return true; - else if (kgsl_gmu_isenabled(device) && - test_bit(GMU_CLK_ON, &gmu->flags)) + else if (gmu_core_isenabled(device) && + gmu_core_testbit(device, GMU_CLK_ON)) return true; else return false; diff --git a/drivers/gpu/msm/kgsl_gmu.c b/drivers/gpu/msm/kgsl_gmu.c index 084fbb4fc005..bd5f86f02435 100644 --- a/drivers/gpu/msm/kgsl_gmu.c +++ b/drivers/gpu/msm/kgsl_gmu.c @@ -28,13 +28,7 @@ #include "kgsl_hfi.h" #include "a6xx_reg.h" #include "adreno.h" - -#undef MODULE_PARAM_PREFIX -#define MODULE_PARAM_PREFIX "kgsl_gmu." - -static bool nogmu; -module_param(nogmu, bool, 0444); -MODULE_PARM_DESC(nogmu, "Disable the GMU"); +#include "kgsl_trace.h" #define GMU_CONTEXT_USER 0 #define GMU_CONTEXT_KERNEL 1 @@ -72,8 +66,6 @@ struct gmu_iommu_context { #define DUMMY_SIZE SZ_4K -#define LOGMEM_SIZE SZ_4K - #define GMU_DCACHE_CHUNK_SIZE (60 * SZ_4K) /* GMU DCache VA size - 240KB */ /* Define target specific GMU VMA configurations */ @@ -109,18 +101,7 @@ struct gmu_iommu_context gmu_ctx[] = { static struct gmu_memdesc gmu_kmem_entries[GMU_KERNEL_ENTRIES]; static unsigned long gmu_kmem_bitmap; static unsigned int num_uncached_entries; - -void init_gmu_log_base(struct kgsl_device *device) -{ - uint32_t gmu_log_info; - struct gmu_device *gmu = &device->gmu; - - /* Log size is encoded in (number of 4K units - 1) */ - gmu_log_info = (gmu->gmu_log->gmuaddr & 0xFFFFF000) | - ((LOGMEM_SIZE/SZ_4K - 1) & 0xFF); - kgsl_gmu_regwrite(device, A6XX_GPU_GMU_CX_GMU_PWR_COL_CP_MSG, - gmu_log_info); -} +static void gmu_remove(struct kgsl_device *device); static int _gmu_iommu_fault_handler(struct device *dev, unsigned long addr, int flags, const char *name) @@ -548,12 +529,13 @@ static void gmu_memory_close(struct gmu_device *gmu) /* * gmu_memory_probe() - probe GMU IOMMU context banks and allocate memory * to share with GMU in kernel mode. + * @device: Pointer to KGSL device * @gmu: Pointer to GMU device * @node: Pointer to GMU device node */ -static int gmu_memory_probe(struct gmu_device *gmu, struct device_node *node) +static int gmu_memory_probe(struct kgsl_device *device, + struct gmu_device *gmu, struct device_node *node) { - struct kgsl_device *device = container_of(gmu, struct kgsl_device, gmu); struct adreno_device *adreno_dev = ADRENO_DEVICE(device); int ret; @@ -614,12 +596,12 @@ static int gmu_memory_probe(struct gmu_device *gmu, struct device_node *node) * The function converts GPU power level and bus level index used by KGSL * to index being used by GMU/RPMh. */ -int gmu_dcvs_set(struct gmu_device *gmu, +static int gmu_dcvs_set(struct kgsl_device *device, unsigned int gpu_pwrlevel, unsigned int bus_level) { - struct kgsl_device *device = container_of(gmu, struct kgsl_device, gmu); + struct gmu_device *gmu = KGSL_GMU_DEVICE(device); struct adreno_device *adreno_dev = ADRENO_DEVICE(device); - struct adreno_gpudev *gpudev = ADRENO_GPU_DEVICE(adreno_dev); + struct gmu_dev_ops *gmu_dev_ops = GMU_DEVICE_OPS(device); struct hfi_gx_bw_perf_vote_cmd req = { .ack_type = DCVS_ACK_BLOCK, .freq = INVALID_DCVS_IDX, @@ -637,7 +619,7 @@ int gmu_dcvs_set(struct gmu_device *gmu, return -EINVAL; if (ADRENO_QUIRK(adreno_dev, ADRENO_QUIRK_HFI_USE_REG)) { - int ret = gpudev->rpmh_gpu_pwrctrl(adreno_dev, + int ret = gmu_dev_ops->rpmh_gpu_pwrctrl(adreno_dev, GMU_DCVS_NOHFI, req.freq, req.bw); if (ret) { @@ -780,19 +762,18 @@ static int setup_volt_dependency_tbl(uint32_t *votes, /* * rpmh_arc_votes_init() - initialized RPMh votes needed for rails voltage * scaling by GMU. + * @device: Pointer to KGSL device * @gmu: Pointer to GMU device * @pri_rail: Pointer to primary power rail VLVL table * @sec_rail: Pointer to second/dependent power rail VLVL table * of pri_rail VLVL table * @type: the type of the primary rail, GPU or GMU */ -static int rpmh_arc_votes_init(struct gmu_device *gmu, - struct rpmh_arc_vals *pri_rail, - struct rpmh_arc_vals *sec_rail, - unsigned int type) +static int rpmh_arc_votes_init(struct kgsl_device *device, + struct gmu_device *gmu, struct rpmh_arc_vals *pri_rail, + struct rpmh_arc_vals *sec_rail, unsigned int type) { struct device *dev; - struct kgsl_device *device = container_of(gmu, struct kgsl_device, gmu); unsigned int num_freqs; uint32_t *votes; unsigned int vlvl_tbl[MAX_GX_LEVELS]; @@ -967,7 +948,8 @@ static int gmu_bus_vote_init(struct gmu_device *gmu, struct kgsl_pwrctrl *pwr) return ret; } -static int gmu_rpmh_init(struct gmu_device *gmu, struct kgsl_pwrctrl *pwr) +static int gmu_rpmh_init(struct kgsl_device *device, + struct gmu_device *gmu, struct kgsl_pwrctrl *pwr) { struct rpmh_arc_vals gfx_arc, cx_arc, mx_arc; int ret; @@ -990,17 +972,17 @@ static int gmu_rpmh_init(struct gmu_device *gmu, struct kgsl_pwrctrl *pwr) if (ret) return ret; - ret = rpmh_arc_votes_init(gmu, &gfx_arc, &mx_arc, GPU_ARC_VOTE); + ret = rpmh_arc_votes_init(device, gmu, &gfx_arc, &mx_arc, GPU_ARC_VOTE); if (ret) return ret; - return rpmh_arc_votes_init(gmu, &cx_arc, &mx_arc, GMU_ARC_VOTE); + return rpmh_arc_votes_init(device, gmu, &cx_arc, &mx_arc, GMU_ARC_VOTE); } static irqreturn_t gmu_irq_handler(int irq, void *data) { - struct gmu_device *gmu = data; - struct kgsl_device *device = container_of(gmu, struct kgsl_device, gmu); + struct kgsl_device *device = data; + struct gmu_device *gmu = KGSL_GMU_DEVICE(device); struct adreno_device *adreno_dev = ADRENO_DEVICE(device); unsigned int status = 0; @@ -1038,9 +1020,9 @@ static irqreturn_t gmu_irq_handler(int irq, void *data) static irqreturn_t hfi_irq_handler(int irq, void *data) { - struct kgsl_hfi *hfi = data; - struct gmu_device *gmu = container_of(hfi, struct gmu_device, hfi); - struct kgsl_device *device = container_of(gmu, struct kgsl_device, gmu); + struct kgsl_device *device = data; + struct gmu_device *gmu = KGSL_GMU_DEVICE(device); + struct kgsl_hfi *hfi = &gmu->hfi; struct adreno_device *adreno_dev = ADRENO_DEVICE(device); unsigned int status = 0; @@ -1182,9 +1164,8 @@ static int gmu_clocks_probe(struct gmu_device *gmu, struct device_node *node) return 0; } -static int gmu_gpu_bw_probe(struct gmu_device *gmu) +static int gmu_gpu_bw_probe(struct kgsl_device *device, struct gmu_device *gmu) { - struct kgsl_device *device = container_of(gmu, struct kgsl_device, gmu); struct msm_bus_scale_pdata *bus_scale_table; struct msm_bus_paths *usecase; struct msm_bus_vectors *vector; @@ -1280,7 +1261,7 @@ static int gmu_regulators_probe(struct gmu_device *gmu, return 0; } -static int gmu_irq_probe(struct gmu_device *gmu) +static int gmu_irq_probe(struct kgsl_device *device, struct gmu_device *gmu) { int ret; struct kgsl_hfi *hfi = &gmu->hfi; @@ -1290,7 +1271,7 @@ static int gmu_irq_probe(struct gmu_device *gmu) ret = devm_request_irq(&gmu->pdev->dev, hfi->hfi_interrupt_num, hfi_irq_handler, IRQF_TRIGGER_HIGH, - "HFI", hfi); + "HFI", device); if (ret) { dev_err(&gmu->pdev->dev, "request_irq(%d) failed: %d\n", hfi->hfi_interrupt_num, ret); @@ -1302,7 +1283,7 @@ static int gmu_irq_probe(struct gmu_device *gmu) ret = devm_request_irq(&gmu->pdev->dev, gmu->gmu_interrupt_num, gmu_irq_handler, IRQF_TRIGGER_HIGH, - "GMU", gmu); + "GMU", device); if (ret) dev_err(&gmu->pdev->dev, "request_irq(%d) failed: %d\n", gmu->gmu_interrupt_num, ret); @@ -1313,7 +1294,7 @@ static int gmu_irq_probe(struct gmu_device *gmu) static void gmu_irq_enable(struct kgsl_device *device) { struct adreno_device *adreno_dev = ADRENO_DEVICE(device); - struct gmu_device *gmu = &device->gmu; + struct gmu_device *gmu = KGSL_GMU_DEVICE(device); struct kgsl_hfi *hfi = &gmu->hfi; /* Clear any pending IRQs before unmasking on GMU */ @@ -1336,7 +1317,7 @@ static void gmu_irq_enable(struct kgsl_device *device) static void gmu_irq_disable(struct kgsl_device *device) { struct adreno_device *adreno_dev = ADRENO_DEVICE(device); - struct gmu_device *gmu = &device->gmu; + struct gmu_device *gmu = KGSL_GMU_DEVICE(device); struct kgsl_hfi *hfi = &gmu->hfi; /* Disable all IRQs on host */ @@ -1357,38 +1338,28 @@ static void gmu_irq_disable(struct kgsl_device *device) } /* Do not access any GMU registers in GMU probe function */ -int gmu_probe(struct kgsl_device *device, unsigned long flags) +static int gmu_probe(struct kgsl_device *device, + struct device_node *node, unsigned long flags) { - struct device_node *node; - struct gmu_device *gmu = &device->gmu; + struct gmu_device *gmu; struct gmu_memdesc *mem_addr = NULL; - struct kgsl_hfi *hfi = &gmu->hfi; + struct kgsl_hfi *hfi; struct kgsl_pwrctrl *pwr = &device->pwrctrl; struct adreno_device *adreno_dev = ADRENO_DEVICE(device); int i = 0, ret = -ENXIO; - /* Make sure no flags enabled by default, probably don't need */ - gmu->flags = 0; - gmu->ver = ~0U; + gmu = kzalloc(sizeof(struct gmu_device), GFP_KERNEL); - /* Normalize flags for input feature requests */ - flags &= BIT(GMU_GPMU); - - node = of_find_compatible_node(device->pdev->dev.of_node, - NULL, "qcom,gpu-gmu"); - /* No GMU in dt, no worries...hopefully */ - if (node == NULL) { - /* If we are trying to use GPMU and no GMU, that's bad */ - if (flags & BIT(GMU_GPMU)) - return -ENXIO; - /* Otherwise it's ok and nothing to do */ - return 0; - } + if (gmu == NULL) + return -ENOMEM; + + hfi = &gmu->hfi; + gmu->load_mode = TCM_BOOT; - /* Ok, now say the flags are enabled */ + gmu->ver = ~0U; gmu->flags = flags; - device->gmu.pdev = of_find_device_by_node(node); + gmu->pdev = of_find_device_by_node(node); of_dma_configure(&gmu->pdev->dev, node); /* Set up GMU regulators */ @@ -1402,7 +1373,7 @@ int gmu_probe(struct kgsl_device *device, unsigned long flags) goto error; /* Set up GMU IOMMU and shared memory with GMU */ - ret = gmu_memory_probe(&device->gmu, node); + ret = gmu_memory_probe(device, gmu, node); if (ret) goto error; mem_addr = gmu->hfi_mem; @@ -1416,10 +1387,12 @@ int gmu_probe(struct kgsl_device *device, unsigned long flags) if (ret) goto error; - gmu->gmu2gpu_offset = (gmu->reg_phys - device->reg_phys) >> 2; + device->gmu_core.gmu2gpu_offset = + (gmu->reg_phys - device->reg_phys) >> 2; + device->gmu_core.reg_len = gmu->reg_len; /* Initialize HFI and GMU interrupts */ - ret = gmu_irq_probe(gmu); + ret = gmu_irq_probe(device, gmu); if (ret) goto error; @@ -1446,7 +1419,7 @@ int gmu_probe(struct kgsl_device *device, unsigned long flags) } /* Initializes GPU b/w levels configuration */ - ret = gmu_gpu_bw_probe(gmu); + ret = gmu_gpu_bw_probe(device, gmu); if (ret) goto error; @@ -1456,7 +1429,7 @@ int gmu_probe(struct kgsl_device *device, unsigned long flags) goto error; /* Populates RPMh configurations */ - ret = gmu_rpmh_init(gmu, pwr); + ret = gmu_rpmh_init(device, gmu, pwr); if (ret) goto error; @@ -1478,6 +1451,9 @@ int gmu_probe(struct kgsl_device *device, unsigned long flags) clear_bit(ADRENO_LM_CTRL, &adreno_dev->pwrctrl_flag); set_bit(GMU_ENABLED, &gmu->flags); + device->gmu_core.ptr = (void *)gmu; + device->gmu_core.dev_ops = &adreno_a6xx_gmudev; + return 0; error: @@ -1485,8 +1461,6 @@ int gmu_probe(struct kgsl_device *device, unsigned long flags) return ret; } - - static int gmu_enable_clks(struct gmu_device *gmu) { int ret, j = 0; @@ -1588,8 +1562,8 @@ static int gmu_disable_gdsc(struct gmu_device *gmu) static int gmu_suspend(struct kgsl_device *device) { struct adreno_device *adreno_dev = ADRENO_DEVICE(device); - struct adreno_gpudev *gpudev = ADRENO_GPU_DEVICE(adreno_dev); - struct gmu_device *gmu = &device->gmu; + struct gmu_dev_ops *gmu_dev_ops = GMU_DEVICE_OPS(device); + struct gmu_device *gmu = KGSL_GMU_DEVICE(device); if (!test_bit(GMU_CLK_ON, &gmu->flags)) return 0; @@ -1599,7 +1573,7 @@ static int gmu_suspend(struct kgsl_device *device) clear_bit(GMU_HFI_ON, &gmu->flags); gmu_irq_disable(device); - if (gpudev->rpmh_gpu_pwrctrl(adreno_dev, GMU_SUSPEND, 0, 0)) + if (gmu_dev_ops->rpmh_gpu_pwrctrl(adreno_dev, GMU_SUSPEND, 0, 0)) return -EINVAL; gmu_disable_clks(gmu); @@ -1608,10 +1582,10 @@ static int gmu_suspend(struct kgsl_device *device) return 0; } -void gmu_snapshot(struct kgsl_device *device) +static void gmu_snapshot(struct kgsl_device *device) { struct adreno_device *adreno_dev = ADRENO_DEVICE(device); - struct gmu_device *gmu = &device->gmu; + struct gmu_device *gmu = KGSL_GMU_DEVICE(device); /* Mask so there's no interrupt caused by NMI */ adreno_write_gmureg(adreno_dev, @@ -1665,13 +1639,13 @@ static void gmu_change_gpu_pwrlevel(struct kgsl_device *device, } /* To be called to power on both GPU and GMU */ -int gmu_start(struct kgsl_device *device) +static int gmu_start(struct kgsl_device *device) { int ret = 0; struct adreno_device *adreno_dev = ADRENO_DEVICE(device); - struct adreno_gpudev *gpudev = ADRENO_GPU_DEVICE(adreno_dev); + struct gmu_dev_ops *gmu_dev_ops = GMU_DEVICE_OPS(device); struct kgsl_pwrctrl *pwr = &device->pwrctrl; - struct gmu_device *gmu = &device->gmu; + struct gmu_device *gmu = KGSL_GMU_DEVICE(device); switch (device->state) { case KGSL_STATE_INIT: @@ -1688,7 +1662,7 @@ int gmu_start(struct kgsl_device *device) dev_err(&gmu->pdev->dev, "Failed to allocate gmu b/w: %d\n", ret); - ret = gpudev->rpmh_gpu_pwrctrl(adreno_dev, GMU_FW_START, + ret = gmu_dev_ops->rpmh_gpu_pwrctrl(adreno_dev, GMU_FW_START, GMU_COLD_BOOT, 0); if (ret) goto error_gmu; @@ -1708,7 +1682,7 @@ int gmu_start(struct kgsl_device *device) gmu_enable_clks(gmu); gmu_irq_enable(device); - ret = gpudev->rpmh_gpu_pwrctrl(adreno_dev, GMU_FW_START, + ret = gmu_dev_ops->rpmh_gpu_pwrctrl(adreno_dev, GMU_FW_START, GMU_COLD_BOOT, 0); if (ret) goto error_gmu; @@ -1728,7 +1702,7 @@ int gmu_start(struct kgsl_device *device) gmu_enable_clks(gmu); gmu_irq_enable(device); - ret = gpudev->rpmh_gpu_pwrctrl( + ret = gmu_dev_ops->rpmh_gpu_pwrctrl( adreno_dev, GMU_FW_START, GMU_COLD_BOOT, 0); if (ret) goto error_gmu; @@ -1745,8 +1719,8 @@ int gmu_start(struct kgsl_device *device) /* GMU fast boot */ hfi_stop(gmu); - ret = gpudev->rpmh_gpu_pwrctrl(adreno_dev, GMU_FW_START, - GMU_COLD_BOOT, 0); + ret = gmu_dev_ops->rpmh_gpu_pwrctrl(adreno_dev, + GMU_FW_START, GMU_COLD_BOOT, 0); if (ret) goto error_gmu; @@ -1763,33 +1737,34 @@ int gmu_start(struct kgsl_device *device) error_gmu: if (ADRENO_QUIRK(adreno_dev, ADRENO_QUIRK_HFI_USE_REG)) - gpudev->oob_clear(adreno_dev, oob_boot_slumber); - gmu_snapshot(device); + gmu_dev_ops->oob_clear(adreno_dev, oob_boot_slumber); + gmu_core_snapshot(device); return ret; } /* Caller shall ensure GPU is ready for SLUMBER */ -void gmu_stop(struct kgsl_device *device) +static void gmu_stop(struct kgsl_device *device) { - struct gmu_device *gmu = &device->gmu; + struct gmu_device *gmu = KGSL_GMU_DEVICE(device); struct adreno_device *adreno_dev = ADRENO_DEVICE(device); - struct adreno_gpudev *gpudev = ADRENO_GPU_DEVICE(adreno_dev); + struct gmu_dev_ops *gmu_dev_ops = GMU_DEVICE_OPS(device); int ret = 0; if (!test_bit(GMU_CLK_ON, &gmu->flags)) return; /* Wait for the lowest idle level we requested */ - if (gpudev->wait_for_lowest_idle && - gpudev->wait_for_lowest_idle(adreno_dev)) + if (gmu_dev_ops->wait_for_lowest_idle && + gmu_dev_ops->wait_for_lowest_idle(adreno_dev)) goto error; - ret = gpudev->rpmh_gpu_pwrctrl(adreno_dev, GMU_NOTIFY_SLUMBER, 0, 0); + ret = gmu_dev_ops->rpmh_gpu_pwrctrl(adreno_dev, + GMU_NOTIFY_SLUMBER, 0, 0); if (ret) goto error; - if (gpudev->wait_for_gmu_idle && - gpudev->wait_for_gmu_idle(adreno_dev)) + if (gmu_dev_ops->wait_for_gmu_idle && + gmu_dev_ops->wait_for_gmu_idle(adreno_dev)) goto error; /* Pending message in all queues are abandoned */ @@ -1797,7 +1772,7 @@ void gmu_stop(struct kgsl_device *device) clear_bit(GMU_HFI_ON, &gmu->flags); gmu_irq_disable(device); - gpudev->rpmh_gpu_pwrctrl(adreno_dev, GMU_FW_STOP, 0, 0); + gmu_dev_ops->rpmh_gpu_pwrctrl(adreno_dev, GMU_FW_STOP, 0, 0); gmu_disable_clks(gmu); gmu_disable_gdsc(gmu); @@ -1812,18 +1787,20 @@ void gmu_stop(struct kgsl_device *device) */ set_bit(GMU_FAULT, &gmu->flags); dev_err(&gmu->pdev->dev, "Failed to stop GMU\n"); - gmu_snapshot(device); + gmu_core_snapshot(device); } -void gmu_remove(struct kgsl_device *device) +static void gmu_remove(struct kgsl_device *device) { - struct gmu_device *gmu = &device->gmu; - struct kgsl_hfi *hfi = &gmu->hfi; + struct gmu_device *gmu = KGSL_GMU_DEVICE(device); + struct kgsl_hfi *hfi; int i = 0; - if (!device->gmu.pdev) + if (gmu == NULL || gmu->pdev == NULL) return; + hfi = &gmu->hfi; + tasklet_kill(&hfi->tasklet); gmu_stop(device); @@ -1865,7 +1842,7 @@ void gmu_remove(struct kgsl_device *device) gmu->reg_virt = NULL; } - gmu_memory_close(&device->gmu); + gmu_memory_close(gmu); for (i = 0; i < MAX_GMU_CLKS; i++) { if (gmu->clks[i]) { @@ -1884,64 +1861,107 @@ void gmu_remove(struct kgsl_device *device) gmu->cx_gdsc = NULL; } - device->gmu.flags = 0; - device->gmu.pdev = NULL; + gmu->flags = 0; + gmu->pdev = NULL; + kfree(gmu); +} + +static void gmu_regwrite(struct kgsl_device *device, + unsigned int offsetwords, unsigned int value) +{ + struct gmu_device *gmu = KGSL_GMU_DEVICE(device); + void __iomem *reg; + + trace_kgsl_regwrite(device, offsetwords, value); + + offsetwords -= device->gmu_core.gmu2gpu_offset; + reg = gmu->reg_virt + (offsetwords << 2); + + /* + * ensure previous writes post before this one, + * i.e. act like normal writel() + */ + wmb(); + __raw_writel(value, reg); +} + +static void gmu_regread(struct kgsl_device *device, + unsigned int offsetwords, unsigned int *value) +{ + struct gmu_device *gmu = KGSL_GMU_DEVICE(device); + void __iomem *reg; + + offsetwords -= device->gmu_core.gmu2gpu_offset; + + reg = gmu->reg_virt + (offsetwords << 2); + + *value = __raw_readl(reg); + + /* + * ensure this read finishes before the next one. + * i.e. act like normal readl() + */ + rmb(); } /* Check if GPMU is in charge of power features */ -bool kgsl_gmu_gpmu_isenabled(struct kgsl_device *device) +static bool gmu_gpmu_isenabled(struct kgsl_device *device) { - return test_bit(GMU_GPMU, &(device->gmu.flags)); + struct gmu_device *gmu = KGSL_GMU_DEVICE(device); + + return test_bit(GMU_GPMU, &gmu->flags); } /* Check if GMU is enabled. Only set once GMU is fully initialized */ -bool kgsl_gmu_isenabled(struct kgsl_device *device) +static bool gmu_isenabled(struct kgsl_device *device) { - return !nogmu && test_bit(GMU_ENABLED, &device->gmu.flags); + struct gmu_device *gmu = KGSL_GMU_DEVICE(device); + + return test_bit(GMU_ENABLED, &gmu->flags); } -/* - * adreno_gmu_fenced_write() - Check if there is a GMU and it is enabled - * @adreno_dev: Pointer to the Adreno device device that owns the GMU - * @offset: 32bit register enum that is to be written - * @val: The value to be written to the register - * @fence_mask: The value to poll the fence status register - * - * Check the WRITEDROPPED0/1 bit in the FENCE_STATUS register to check if - * the write to the fenced register went through. If it didn't then we retry - * the write until it goes through or we time out. - */ -int adreno_gmu_fenced_write(struct adreno_device *adreno_dev, - enum adreno_regs offset, unsigned int val, - unsigned int fence_mask) +static void gmu_set_bit(struct kgsl_device *device, enum gmu_core_flags flag) { - unsigned int status, i; - struct adreno_gpudev *gpudev = ADRENO_GPU_DEVICE(adreno_dev); - unsigned int reg_offset = gpudev->reg_offsets->offsets[offset]; + struct gmu_device *gmu = KGSL_GMU_DEVICE(device); + + set_bit(flag, &gmu->flags); +} - adreno_writereg(adreno_dev, offset, val); +static void gmu_clear_bit(struct kgsl_device *device, enum gmu_core_flags flag) +{ + struct gmu_device *gmu = KGSL_GMU_DEVICE(device); - if (!kgsl_gmu_isenabled(KGSL_DEVICE(adreno_dev))) - return 0; + clear_bit(flag, &gmu->flags); +} - for (i = 0; i < GMU_WAKEUP_RETRY_MAX; i++) { - adreno_read_gmureg(adreno_dev, ADRENO_REG_GMU_AHB_FENCE_STATUS, - &status); +static int gmu_test_bit(struct kgsl_device *device, enum gmu_core_flags flag) +{ + struct gmu_device *gmu = KGSL_GMU_DEVICE(device); - /* - * If !writedropped0/1, then the write to fenced register - * was successful - */ - if (!(status & fence_mask)) - return 0; - /* Wait a small amount of time before trying again */ - udelay(GMU_WAKEUP_DELAY_US); + return test_bit(flag, &gmu->flags); +} - /* Try to write the fenced register again */ - adreno_writereg(adreno_dev, offset, val); - } +static bool gmu_regulator_isenabled(struct kgsl_device *device) +{ + struct gmu_device *gmu = KGSL_GMU_DEVICE(device); - dev_err(adreno_dev->dev.dev, - "GMU fenced register write timed out: reg 0x%x\n", reg_offset); - return -ETIMEDOUT; + return (gmu->gx_gdsc && regulator_is_enabled(gmu->gx_gdsc)); } + + +struct gmu_core_ops gmu_ops = { + .probe = gmu_probe, + .remove = gmu_remove, + .regread = gmu_regread, + .regwrite = gmu_regwrite, + .isenabled = gmu_isenabled, + .gpmu_isenabled = gmu_gpmu_isenabled, + .start = gmu_start, + .stop = gmu_stop, + .set_bit = gmu_set_bit, + .clear_bit = gmu_clear_bit, + .test_bit = gmu_test_bit, + .dcvs_set = gmu_dcvs_set, + .snapshot = gmu_snapshot, + .regulator_isenabled = gmu_regulator_isenabled, +}; diff --git a/drivers/gpu/msm/kgsl_gmu.h b/drivers/gpu/msm/kgsl_gmu.h index a02566758cb4..33605c8a0432 100644 --- a/drivers/gpu/msm/kgsl_gmu.h +++ b/drivers/gpu/msm/kgsl_gmu.h @@ -15,22 +15,9 @@ #include "kgsl_hfi.h" -#define GMU_INT_WDOG_BITE BIT(0) -#define GMU_INT_RSCC_COMP BIT(1) -#define GMU_INT_FENCE_ERR BIT(3) -#define GMU_INT_DBD_WAKEUP BIT(4) -#define GMU_INT_HOST_AHB_BUS_ERR BIT(5) -#define GMU_AO_INT_MASK \ - (GMU_INT_WDOG_BITE | \ - GMU_INT_HOST_AHB_BUS_ERR | \ - GMU_INT_FENCE_ERR) - #define MAX_GMUFW_SIZE 0x2000 /* in bytes */ #define FENCE_RANGE_MASK ((0x1 << 31) | ((0xA << 2) << 18) | (0x8A0)) -#define FENCE_STATUS_WRITEDROPPED0_MASK 0x1 -#define FENCE_STATUS_WRITEDROPPED1_MASK 0x2 - #define BWMEM_SIZE (12 + (4 * NUM_BW_LEVELS)) /*in bytes*/ /* Bitmask for GPU low power mode enabling and hysterisis*/ @@ -54,10 +41,6 @@ CX_VOTE_ENABLE | \ GFX_VOTE_ENABLE) -/* Bitmask for GPU idle status check */ -#define GPUBUSYIGNAHB BIT(23) -#define CXGXCPUBUSYIGNAHB BIT(30) - /* GMU timeouts */ #define GMU_IDLE_TIMEOUT 100 /* ms */ @@ -65,42 +48,11 @@ #define OOB_BOOT_OPTION 0 #define OOB_SLUMBER_OPTION 1 -/* - * OOB requests values. These range from 0 to 7 and then - * the BIT() offset into the actual value is calculated - * later based on the request. This keeps the math clean - * and easy to ensure not reaching over/under the range - * of 8 bits. - */ -enum oob_request { - oob_gpu = 0, - oob_perfcntr = 1, - oob_preempt = 2, - oob_boot_slumber = 6, /* reserved special case */ - oob_dcvs = 7, /* reserved special case */ -}; - -/* - * Wait time before trying to write the register again. - * Hopefully the GMU has finished waking up during this delay. - * This delay must be less than the IFPC main hysteresis or - * the GMU will start shutting down before we try again. - */ -#define GMU_WAKEUP_DELAY_US 10 -/* Max amount of tries to wake up the GMU. */ -#define GMU_WAKEUP_RETRY_MAX 60 +/* For GMU Logs*/ +#define LOGMEM_SIZE SZ_4K -/* Bits for the flags field in the gmu structure */ -enum gmu_flags { - GMU_BOOT_INIT_DONE = 0, - GMU_CLK_ON, - GMU_HFI_ON, - GMU_FAULT, - GMU_DCVS_REPLAY, - GMU_GPMU, - GMU_ENABLED, - GMU_RSCC_SLEEP_SEQ_DONE, -}; +extern struct gmu_dev_ops adreno_a6xx_gmudev; +#define KGSL_GMU_DEVICE(_a) ((struct gmu_device *)((_a)->gmu_core.ptr)) /** * struct gmu_memdesc - Gmu shared memory object descriptor @@ -132,18 +84,6 @@ struct rpmh_votes_t { struct gmu_bw_votes cnoc_votes; }; -#define MAX_GMU_CLKS 6 -#define DEFAULT_GMU_FREQ_IDX 1 - -/* - * These are the different ways the GMU can boot. GMU_WARM_BOOT is waking up - * from slumber. GMU_COLD_BOOT is booting for the first time. - */ -enum gmu_boot { - GMU_WARM_BOOT = 0, - GMU_COLD_BOOT = 1, -}; - enum gmu_load_mode { CACHED_LOAD_BOOT, CACHED_BOOT, @@ -177,9 +117,6 @@ enum gpu_idle_level { * @reg_phys: GMU CSR physical address * @reg_virt: GMU CSR virtual address * @reg_len: GMU CSR range - * @gmu2gpu_offset: address difference between GMU register set - * and GPU register set, the offset will be used when accessing - * gmu registers using offset defined in GPU register space. * @pdc_reg_virt: starting kernel virtual address for RPMh PDC registers * @gmu_interrupt_num: GMU interrupt number * @fw_image: descriptor of GMU memory that has GMU image in it @@ -217,7 +154,6 @@ struct gmu_device { unsigned long reg_phys; void __iomem *reg_virt; unsigned int reg_len; - unsigned int gmu2gpu_offset; void __iomem *pdc_reg_virt; unsigned int gmu_interrupt_num; struct gmu_memdesc cached_fw_image; @@ -251,20 +187,8 @@ struct gmu_device { unsigned int fault_count; }; -struct kgsl_device; -void gmu_snapshot(struct kgsl_device *device); - -bool kgsl_gmu_gpmu_isenabled(struct kgsl_device *device); -bool kgsl_gmu_isenabled(struct kgsl_device *device); - -int gmu_probe(struct kgsl_device *device, unsigned long flags); -void gmu_remove(struct kgsl_device *device); -int allocate_gmu_image(struct gmu_device *gmu, unsigned int size); -int gmu_start(struct kgsl_device *device); -void gmu_stop(struct kgsl_device *device); -int gmu_dcvs_set(struct gmu_device *gmu, unsigned int gpu_pwrlevel, - unsigned int bus_level); -int allocate_gmu_cached_fw(struct gmu_device *gmu); bool is_cached_fw_size_valid(uint32_t size_in_bytes); -void init_gmu_log_base(struct kgsl_device *device); +int allocate_gmu_cached_fw(struct gmu_device *gmu); +int allocate_gmu_image(struct gmu_device *gmu, unsigned int size); + #endif /* __KGSL_GMU_H */ diff --git a/drivers/gpu/msm/kgsl_gmu_core.c b/drivers/gpu/msm/kgsl_gmu_core.c new file mode 100644 index 000000000000..3a60a53dc3e2 --- /dev/null +++ b/drivers/gpu/msm/kgsl_gmu_core.c @@ -0,0 +1,219 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "kgsl_device.h" +#include "kgsl_gmu_core.h" +#include "a6xx_reg.h" +#include "adreno.h" + +#undef MODULE_PARAM_PREFIX +#define MODULE_PARAM_PREFIX "kgsl_gmu." + +static bool nogmu; +module_param(nogmu, bool, 0444); +MODULE_PARM_DESC(nogmu, "Disable the GMU"); + +static const struct { + char *compat; + struct gmu_core_ops *core_ops; +} gmu_subtypes[] = { + {"qcom,gpu-gmu", &gmu_ops}, +}; + +int gmu_core_probe(struct kgsl_device *device) +{ + struct device_node *node; + struct gmu_core_ops *gmu_core_ops; + unsigned long flags; + int i = 0, ret = -ENXIO; + + flags = ADRENO_FEATURE(ADRENO_DEVICE(device), ADRENO_GPMU) ? + BIT(GMU_GPMU) : 0; + + for (i = 0; i < ARRAY_SIZE(gmu_subtypes); i++) { + node = of_find_compatible_node(device->pdev->dev.of_node, + NULL, gmu_subtypes[i].compat); + + if (node != NULL) + gmu_core_ops = gmu_subtypes[i].core_ops; + } + + /* No GMU in dt, no worries...hopefully */ + if (node == NULL) { + /* If we are trying to use GPMU and no GMU, that's bad */ + if (flags & BIT(GMU_GPMU)) + return ret; + /* Otherwise it's ok and nothing to do */ + return 0; + } + + if (gmu_core_ops && gmu_core_ops->probe) { + ret = gmu_core_ops->probe(device, node, flags); + if (ret == 0) + device->gmu_core.core_ops = gmu_core_ops; + } + + return ret; +} + +void gmu_core_remove(struct kgsl_device *device) +{ + struct gmu_core_ops *gmu_core_ops = GMU_CORE_OPS(device); + + if (gmu_core_ops && gmu_core_ops->remove) + gmu_core_ops->remove(device); +} + +bool gmu_core_isenabled(struct kgsl_device *device) +{ + struct gmu_core_ops *gmu_core_ops = GMU_CORE_OPS(device); + + if (gmu_core_ops && gmu_core_ops->isenabled) + return !nogmu && gmu_core_ops->isenabled(device); + + return false; +} + +bool gmu_core_gpmu_isenabled(struct kgsl_device *device) +{ + struct gmu_core_ops *gmu_core_ops = GMU_CORE_OPS(device); + + if (gmu_core_ops && gmu_core_ops->gpmu_isenabled) + return gmu_core_ops->gpmu_isenabled(device); + + return false; +} + +int gmu_core_start(struct kgsl_device *device) +{ + struct gmu_core_ops *gmu_core_ops = GMU_CORE_OPS(device); + + if (gmu_core_ops && gmu_core_ops->start) + return gmu_core_ops->start(device); + + return -EINVAL; +} + +void gmu_core_stop(struct kgsl_device *device) +{ + struct gmu_core_ops *gmu_core_ops = GMU_CORE_OPS(device); + + if (gmu_core_ops && gmu_core_ops->stop) + gmu_core_ops->stop(device); +} + +void gmu_core_snapshot(struct kgsl_device *device) +{ + struct gmu_core_ops *gmu_core_ops = GMU_CORE_OPS(device); + + if (gmu_core_ops && gmu_core_ops->snapshot) + gmu_core_ops->snapshot(device); +} + +int gmu_core_dcvs_set(struct kgsl_device *device, unsigned int gpu_pwrlevel, + unsigned int bus_level) +{ + struct gmu_core_ops *gmu_core_ops = GMU_CORE_OPS(device); + + if (gmu_core_ops && gmu_core_ops->dcvs_set) + return gmu_core_ops->dcvs_set(device, gpu_pwrlevel, bus_level); + + return -EINVAL; +} + +void gmu_core_setbit(struct kgsl_device *device, enum gmu_core_flags flag) +{ + struct gmu_core_ops *gmu_core_ops = GMU_CORE_OPS(device); + + if (gmu_core_ops && gmu_core_ops->set_bit) + return gmu_core_ops->set_bit(device, flag); +} + +void gmu_core_clearbit(struct kgsl_device *device, enum gmu_core_flags flag) +{ + struct gmu_core_ops *gmu_core_ops = GMU_CORE_OPS(device); + + if (gmu_core_ops && gmu_core_ops->clear_bit) + return gmu_core_ops->clear_bit(device, flag); +} + +int gmu_core_testbit(struct kgsl_device *device, enum gmu_core_flags flag) +{ + struct gmu_core_ops *gmu_core_ops = GMU_CORE_OPS(device); + + if (gmu_core_ops && gmu_core_ops->test_bit) + return gmu_core_ops->test_bit(device, flag); + + return -EINVAL; +} + +bool gmu_core_regulator_isenabled(struct kgsl_device *device) +{ + struct gmu_core_ops *gmu_core_ops = GMU_CORE_OPS(device); + + if (gmu_core_ops && gmu_core_ops->regulator_isenabled) + return gmu_core_ops->regulator_isenabled(device); + + return false; +} + +bool gmu_core_is_register_offset(struct kgsl_device *device, + unsigned int offsetwords) +{ + return (gmu_core_isenabled(device) && + (offsetwords >= device->gmu_core.gmu2gpu_offset) && + ((offsetwords - device->gmu_core.gmu2gpu_offset) * + sizeof(uint32_t) < device->gmu_core.reg_len)); +} + +void gmu_core_regread(struct kgsl_device *device, unsigned int offsetwords, + unsigned int *value) +{ + struct gmu_core_ops *gmu_core_ops = GMU_CORE_OPS(device); + + if (gmu_core_ops && gmu_core_ops->regread) + gmu_core_ops->regread(device, offsetwords, value); + else + *value = 0; +} + +void gmu_core_regwrite(struct kgsl_device *device, unsigned int offsetwords, + unsigned int value) +{ + struct gmu_core_ops *gmu_core_ops = GMU_CORE_OPS(device); + + if (gmu_core_ops && gmu_core_ops->regwrite) + gmu_core_ops->regwrite(device, offsetwords, value); +} + +void gmu_core_regrmw(struct kgsl_device *device, + unsigned int offsetwords, + unsigned int mask, unsigned int bits) +{ + unsigned int val = 0; + + gmu_core_regread(device, offsetwords, &val); + val &= ~mask; + gmu_core_regwrite(device, offsetwords, val | bits); +} diff --git a/drivers/gpu/msm/kgsl_gmu_core.h b/drivers/gpu/msm/kgsl_gmu_core.h new file mode 100644 index 000000000000..40a9eddb604f --- /dev/null +++ b/drivers/gpu/msm/kgsl_gmu_core.h @@ -0,0 +1,185 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +#ifndef __KGSL_GMU_CORE_H +#define __KGSL_GMU_CORE_H + +#define GMU_INT_WDOG_BITE BIT(0) +#define GMU_INT_RSCC_COMP BIT(1) +#define GMU_INT_FENCE_ERR BIT(3) +#define GMU_INT_DBD_WAKEUP BIT(4) +#define GMU_INT_HOST_AHB_BUS_ERR BIT(5) +#define GMU_AO_INT_MASK \ + (GMU_INT_WDOG_BITE | \ + GMU_INT_HOST_AHB_BUS_ERR | \ + GMU_INT_FENCE_ERR) + +/* GMU_DEVICE - Given an KGSL device return the GMU specific struct */ +#define GMU_DEVICE_OPS(_a) ((_a)->gmu_core.dev_ops) +#define GMU_CORE_OPS(_a) ((_a)->gmu_core.core_ops) + +#define NUM_BW_LEVELS 100 +#define MAX_GX_LEVELS 16 +#define MAX_CX_LEVELS 4 +#define MAX_CNOC_LEVELS 2 +#define MAX_CNOC_CMDS 6 +#define MAX_BW_CMDS 8 +#define INVALID_DCVS_IDX 0xFF + +#if MAX_CNOC_LEVELS > MAX_GX_LEVELS +#error "CNOC levels cannot exceed GX levels" +#endif + +#define MAX_GMU_CLKS 6 +#define DEFAULT_GMU_FREQ_IDX 1 + +/* + * These are the different ways the GMU can boot. GMU_WARM_BOOT is waking up + * from slumber. GMU_COLD_BOOT is booting for the first time. GMU_RESET + * is a soft reset of the GMU. + */ +enum gmu_core_boot { + GMU_WARM_BOOT = 0, + GMU_COLD_BOOT = 1, + GMU_RESET = 2 +}; + +/* Bits for the flags field in the gmu structure */ +enum gmu_core_flags { + GMU_BOOT_INIT_DONE = 0, + GMU_CLK_ON, + GMU_HFI_ON, + GMU_FAULT, + GMU_DCVS_REPLAY, + GMU_GPMU, + GMU_ENABLED, + GMU_RSCC_SLEEP_SEQ_DONE, +}; + +/* + * OOB requests values. These range from 0 to 7 and then + * the BIT() offset into the actual value is calculated + * later based on the request. This keeps the math clean + * and easy to ensure not reaching over/under the range + * of 8 bits. + */ +enum oob_request { + oob_gpu = 0, + oob_perfcntr = 1, + oob_preempt = 2, + oob_boot_slumber = 6, /* reserved special case */ + oob_dcvs = 7, /* reserved special case */ +}; + +/* + * Wait time before trying to write the register again. + * Hopefully the GMU has finished waking up during this delay. + * This delay must be less than the IFPC main hysteresis or + * the GMU will start shutting down before we try again. + */ +#define GMU_CORE_WAKEUP_DELAY_US 10 +/* Max amount of tries to wake up the GMU. */ +#define GMU_CORE_WAKEUP_RETRY_MAX 60 + +#define FENCE_STATUS_WRITEDROPPED0_MASK 0x1 +#define FENCE_STATUS_WRITEDROPPED1_MASK 0x2 + +struct kgsl_device; +struct adreno_device; +struct kgsl_snapshot; + +struct gmu_core_ops { + int (*probe)(struct kgsl_device *device, struct device_node *node, + unsigned long flags); + void (*remove)(struct kgsl_device *device); + void (*regread)(struct kgsl_device *device, + unsigned int offsetwords, unsigned int *value); + void (*regwrite)(struct kgsl_device *device, + unsigned int offsetwords, unsigned int value); + bool (*isenabled)(struct kgsl_device *device); + bool (*gpmu_isenabled)(struct kgsl_device *device); + int (*dcvs_set)(struct kgsl_device *device, + unsigned int gpu_pwrlevel, unsigned int bus_level); + void (*set_bit)(struct kgsl_device *device, enum gmu_core_flags flag); + void (*clear_bit)(struct kgsl_device *device, enum gmu_core_flags flag); + int (*test_bit)(struct kgsl_device *device, enum gmu_core_flags flag); + int (*start)(struct kgsl_device *device); + void (*stop)(struct kgsl_device *device); + void (*snapshot)(struct kgsl_device *device); + int (*get_idle_level)(struct kgsl_device *device); + void (*set_idle_level)(struct kgsl_device *device, unsigned int val); + bool (*regulator_isenabled)(struct kgsl_device *device); +}; + +struct gmu_dev_ops { + int (*load_firmware)(struct kgsl_device *device); + int (*oob_set)(struct adreno_device *adreno_dev, + enum oob_request req); + void (*oob_clear)(struct adreno_device *adreno_dev, + enum oob_request req); + int (*hfi_start_msg)(struct adreno_device *adreno_dev); + void (*enable_lm)(struct kgsl_device *device); + int (*rpmh_gpu_pwrctrl)(struct adreno_device *, unsigned int ops, + unsigned int arg1, unsigned int arg2); + int (*wait_for_lowest_idle)(struct adreno_device *); + int (*wait_for_gmu_idle)(struct adreno_device *); + int (*sptprac_enable)(struct adreno_device *adreno_dev); + void (*sptprac_disable)(struct adreno_device *adreno_dev); + int (*ifpc_store)(struct adreno_device *adreno_dev, + unsigned int val); + unsigned int (*ifpc_show)(struct adreno_device *adreno_dev); + void (*snapshot)(struct adreno_device *, struct kgsl_snapshot *); +}; + +/** + * struct gmu_core_device - GMU Core device structure + * @ptr: Pointer to GMU device structure + * @gmu2gpu_offset: address difference between GMU register set + * and GPU register set, the offset will be used when accessing + * gmu registers using offset defined in GPU register space. + * @reg_len: GMU registers length + * @core_ops: Pointer to gmu core operations + * @dev_ops: Pointer to gmu device operations + */ +struct gmu_core_device { + void *ptr; + unsigned int gmu2gpu_offset; + unsigned int reg_len; + struct gmu_core_ops *core_ops; + struct gmu_dev_ops *dev_ops; +}; + +/* GMU core functions */ +extern struct gmu_core_ops gmu_ops; + +int gmu_core_probe(struct kgsl_device *device); +void gmu_core_remove(struct kgsl_device *device); +int gmu_core_start(struct kgsl_device *device); +void gmu_core_stop(struct kgsl_device *device); +void gmu_core_snapshot(struct kgsl_device *device); +bool gmu_core_gpmu_isenabled(struct kgsl_device *device); +bool gmu_core_isenabled(struct kgsl_device *device); +int gmu_core_dcvs_set(struct kgsl_device *device, unsigned int gpu_pwrlevel, + unsigned int bus_level); +void gmu_core_setbit(struct kgsl_device *device, enum gmu_core_flags flag); +void gmu_core_clearbit(struct kgsl_device *device, enum gmu_core_flags flag); +int gmu_core_testbit(struct kgsl_device *device, enum gmu_core_flags flag); +bool gmu_core_regulator_isenabled(struct kgsl_device *device); +bool gmu_core_is_register_offset(struct kgsl_device *device, + unsigned int offsetwords); +void gmu_core_regread(struct kgsl_device *device, unsigned int offsetwords, + unsigned int *value); +void gmu_core_regwrite(struct kgsl_device *device, unsigned int offsetwords, + unsigned int value); +void gmu_core_regrmw(struct kgsl_device *device, unsigned int offsetwords, + unsigned int mask, unsigned int bits); +#endif /* __KGSL_GMU_CORE_H */ diff --git a/drivers/gpu/msm/kgsl_hfi.c b/drivers/gpu/msm/kgsl_hfi.c index 6751982b1588..bac248d1cb42 100644 --- a/drivers/gpu/msm/kgsl_hfi.c +++ b/drivers/gpu/msm/kgsl_hfi.c @@ -105,7 +105,7 @@ static int hfi_queue_read(struct gmu_device *gmu, uint32_t queue_idx, static int hfi_queue_write(struct gmu_device *gmu, uint32_t queue_idx, uint32_t *msg) { - struct kgsl_device *device = container_of(gmu, struct kgsl_device, gmu); + struct kgsl_device *device = kgsl_get_device(KGSL_DEVICE_3D0); struct hfi_queue_table *tbl = gmu->hfi_mem->hostptr; struct hfi_queue_header *hdr = &tbl->qhdr[queue_idx]; uint32_t *queue; @@ -559,9 +559,9 @@ void hfi_receiver(unsigned long data) #define GMU_VERSION(major, minor) \ ((((major) & 0xF) << 28) | (((minor) & 0xFFF) << 16)) -static int hfi_verify_fw_version(struct gmu_device *gmu) +static int hfi_verify_fw_version(struct kgsl_device *device, + struct gmu_device *gmu) { - struct kgsl_device *device = container_of(gmu, struct kgsl_device, gmu); struct adreno_device *adreno_dev = ADRENO_DEVICE(device); int result; unsigned int ver, major, minor; @@ -603,7 +603,7 @@ static int hfi_verify_fw_version(struct gmu_device *gmu) int hfi_start(struct gmu_device *gmu, uint32_t boot_state) { - struct kgsl_device *device = container_of(gmu, struct kgsl_device, gmu); + struct kgsl_device *device = kgsl_get_device(KGSL_DEVICE_3D0); struct adreno_device *adreno_dev = ADRENO_DEVICE(device); int result; @@ -616,7 +616,7 @@ int hfi_start(struct gmu_device *gmu, uint32_t boot_state) return result; } - result = hfi_verify_fw_version(gmu); + result = hfi_verify_fw_version(device, gmu); if (result) return result; diff --git a/drivers/gpu/msm/kgsl_hfi.h b/drivers/gpu/msm/kgsl_hfi.h index 4845794ee07a..42b9788f96c8 100644 --- a/drivers/gpu/msm/kgsl_hfi.h +++ b/drivers/gpu/msm/kgsl_hfi.h @@ -198,18 +198,6 @@ enum hfi_msg_type { #define H2F_MSG_CONTEXT_RULE 140 /* AKA constraint */ #define F2H_MSG_CONTEXT_BAD 150 -#define NUM_BW_LEVELS 100 -#define MAX_GX_LEVELS 16 -#define MAX_CX_LEVELS 4 -#define MAX_CNOC_LEVELS 2 -#define MAX_CNOC_CMDS 6 -#define MAX_BW_CMDS 8 -#define INVALID_DCVS_IDX 0xFF - -#if MAX_CNOC_LEVELS > MAX_GX_LEVELS -#error "CNOC levels cannot exceed GX levels" -#endif - /* H2F */ struct hfi_gmu_init_cmd { uint32_t hdr; diff --git a/drivers/gpu/msm/kgsl_pwrctrl.c b/drivers/gpu/msm/kgsl_pwrctrl.c index 1ad0a6e3b637..fd53cc13e736 100644 --- a/drivers/gpu/msm/kgsl_pwrctrl.c +++ b/drivers/gpu/msm/kgsl_pwrctrl.c @@ -26,7 +26,6 @@ #include "kgsl.h" #include "kgsl_pwrscale.h" #include "kgsl_device.h" -#include "kgsl_gmu.h" #include "kgsl_trace.h" #define KGSL_PWRFLAGS_POWER_ON 0 @@ -226,7 +225,7 @@ static int kgsl_bus_scale_request(struct kgsl_device *device, int ret = 0; /* GMU scales BW */ - if (kgsl_gmu_gpmu_isenabled(device)) + if (gmu_core_gpmu_isenabled(device)) return 0; if (pwr->pcl) { @@ -248,28 +247,32 @@ static int kgsl_bus_scale_request(struct kgsl_device *device, int kgsl_clk_set_rate(struct kgsl_device *device, unsigned int pwrlevel) { - struct gmu_device *gmu = &device->gmu; struct kgsl_pwrctrl *pwr = &device->pwrctrl; struct kgsl_pwrlevel *pl = &pwr->pwrlevels[pwrlevel]; int ret = 0; /* GMU scales GPU freq */ - if (kgsl_gmu_gpmu_isenabled(device)) { + if (gmu_core_gpmu_isenabled(device)) { + int num_gpupwrlevels = pwr->num_pwrlevels; + /* If GMU has not been started, save it */ - if (!test_bit(GMU_HFI_ON, &gmu->flags)) { + if (!gmu_core_testbit(device, GMU_HFI_ON)) { /* store clock change request */ - set_bit(GMU_DCVS_REPLAY, &gmu->flags); + gmu_core_setbit(device, GMU_DCVS_REPLAY); return 0; } + if (num_gpupwrlevels < 0) + return -EINVAL; + /* If the GMU is on we cannot vote for the lowest level */ - if (pwrlevel == (gmu->num_gpupwrlevels - 1)) { + if (pwrlevel == (num_gpupwrlevels - 1)) { WARN(1, "Cannot set 0 GPU frequency with GMU\n"); return -EINVAL; } - ret = gmu_dcvs_set(gmu, pwrlevel, INVALID_DCVS_IDX); + ret = gmu_core_dcvs_set(device, pwrlevel, INVALID_DCVS_IDX); /* indicate actual clock change */ - clear_bit(GMU_DCVS_REPLAY, &gmu->flags); + gmu_core_clearbit(device, GMU_DCVS_REPLAY); } else /* Linux clock driver scales GPU freq */ ret = kgsl_pwrctrl_clk_set_rate(pwr->grp_clks[0], @@ -442,7 +445,7 @@ void kgsl_pwrctrl_pwrlevel_change(struct kgsl_device *device, kgsl_pwrctrl_set_thermal_cycle(device, new_level); if (new_level == old_level && - !test_bit(GMU_DCVS_REPLAY, &device->gmu.flags)) + !gmu_core_testbit(device, GMU_DCVS_REPLAY)) return; kgsl_pwrscale_update_stats(device); @@ -1701,7 +1704,7 @@ static void kgsl_pwrctrl_clk(struct kgsl_device *device, int state, struct kgsl_pwrctrl *pwr = &device->pwrctrl; int i = 0; - if (kgsl_gmu_gpmu_isenabled(device)) + if (gmu_core_gpmu_isenabled(device)) return; if (test_bit(KGSL_PWRFLAGS_CLK_ON, &pwr->ctrl_flags)) return; @@ -1877,7 +1880,7 @@ static int kgsl_pwrctrl_pwrrail(struct kgsl_device *device, int state) struct kgsl_pwrctrl *pwr = &device->pwrctrl; int status = 0; - if (kgsl_gmu_gpmu_isenabled(device)) + if (gmu_core_gpmu_isenabled(device)) return 0; /* * Disabling the regulator means also disabling dependent clocks. @@ -2576,7 +2579,7 @@ void kgsl_pre_hwaccess(struct kgsl_device *device) * A register access without device power will cause a fatal timeout. * This is not valid for targets with a GMU. */ - if (!kgsl_gmu_gpmu_isenabled(device)) + if (!gmu_core_gpmu_isenabled(device)) WARN_ON(!kgsl_pwrctrl_isenabled(device)); } EXPORT_SYMBOL(kgsl_pre_hwaccess); @@ -2597,8 +2600,8 @@ static int kgsl_pwrctrl_enable(struct kgsl_device *device) kgsl_pwrctrl_pwrlevel_change(device, level); - if (kgsl_gmu_gpmu_isenabled(device)) { - int ret = gmu_start(device); + if (gmu_core_gpmu_isenabled(device)) { + int ret = gmu_core_start(device); if (!ret) kgsl_pwrctrl_axi(device, KGSL_PWRFLAGS_ON); @@ -2616,9 +2619,9 @@ static int kgsl_pwrctrl_enable(struct kgsl_device *device) static void kgsl_pwrctrl_disable(struct kgsl_device *device) { - if (kgsl_gmu_gpmu_isenabled(device)) { + if (gmu_core_gpmu_isenabled(device)) { kgsl_pwrctrl_axi(device, KGSL_PWRFLAGS_OFF); - return gmu_stop(device); + return gmu_core_stop(device); } /* Order pwrrail/clk sequence based upon platform */ @@ -2761,14 +2764,13 @@ static int _aware(struct kgsl_device *device) { int status = 0; - struct gmu_device *gmu = &device->gmu; unsigned int state = device->state; switch (device->state) { case KGSL_STATE_RESET: - if (!kgsl_gmu_gpmu_isenabled(device)) + if (!gmu_core_gpmu_isenabled(device)) break; - status = gmu_start(device); + status = gmu_core_start(device); break; case KGSL_STATE_INIT: status = kgsl_pwrctrl_enable(device); @@ -2783,8 +2785,8 @@ _aware(struct kgsl_device *device) break; case KGSL_STATE_SLUMBER: /* if GMU already in FAULT */ - if (kgsl_gmu_isenabled(device) && - test_bit(GMU_FAULT, &gmu->flags)) { + if (gmu_core_isenabled(device) && + gmu_core_testbit(device, GMU_FAULT)) { status = -EINVAL; break; } @@ -2796,10 +2798,10 @@ _aware(struct kgsl_device *device) } if (status) { - if (kgsl_gmu_isenabled(device)) { + if (gmu_core_isenabled(device)) { /* GMU hang recovery */ kgsl_pwrctrl_set_state(device, KGSL_STATE_RESET); - set_bit(GMU_FAULT, &gmu->flags); + gmu_core_setbit(device, GMU_FAULT); status = kgsl_pwrctrl_enable(device); if (status) { /* @@ -2817,7 +2819,7 @@ _aware(struct kgsl_device *device) KGSL_STATE_AWARE); } - clear_bit(GMU_FAULT, &gmu->flags); + gmu_core_clearbit(device, GMU_FAULT); return status; } -- GitLab From 1b227655c5843b876888fdf72d1b2d82d29e652d Mon Sep 17 00:00:00 2001 From: Laura Abbott Date: Mon, 14 Apr 2014 19:42:04 -0700 Subject: [PATCH 1361/1635] arm: Allow remapping lowmem as 4K pages Lowmem is currently mapped with sections (1MB/2MB) whenever possible due to TLB performance boosts. Sections cannot easily be changed at runtime however which makes implementing certain features annoying. Add an option to map lowmem with 4K patches. This is intended to be used as a debugging feature and should NOT be used for performance testing. Change-Id: I9612a99b8e05a022f5ba7e568f21307cf66b5667 Signed-off-by: Laura Abbott Signed-off-by: Susheel Khiani Signed-off-by: Charan Teja Reddy --- arch/arm/Kconfig.debug | 11 +++++ arch/arm/mm/mmu.c | 95 ++++++++++++++++++++++++++++++++++++++++++ arch/arm/mm/pageattr.c | 3 +- 3 files changed, 108 insertions(+), 1 deletion(-) diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug index 7ab23ba86a0e..cbd447251355 100644 --- a/arch/arm/Kconfig.debug +++ b/arch/arm/Kconfig.debug @@ -63,6 +63,17 @@ config DEBUG_USER 8 - SIGSEGV faults 16 - SIGBUS faults +config FORCE_PAGES + bool "Force lowmem to be mapped with 4K pages" + help + There are some advanced debug features that can only be done when + memory is mapped with pages instead of sections. Enable this option + to always map lowmem pages with pages. This may have a performance + cost due to increased TLB pressure. + + If unsure say N. + + # These options are only for real kernel hackers who want to get their hands dirty. config DEBUG_LL bool "Kernel low-level debugging functions (read help!)" diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c index e46a6a446cdd..b537340acec6 100644 --- a/arch/arm/mm/mmu.c +++ b/arch/arm/mm/mmu.c @@ -1586,6 +1586,100 @@ static void __init early_paging_init(const struct machine_desc *mdesc) #endif +#ifdef CONFIG_FORCE_PAGES +/* + * remap a PMD into pages + * We split a single pmd here none of this two pmd nonsense + */ +static noinline void __init split_pmd(pmd_t *pmd, unsigned long addr, + unsigned long end, unsigned long pfn, + const struct mem_type *type) +{ + pte_t *pte, *start_pte; + + start_pte = early_alloc(PTE_HWTABLE_OFF + PTE_HWTABLE_SIZE); + + pte = start_pte; + + do { + set_pte_ext(pte, pfn_pte(pfn, type->prot_pte), 0); + pfn++; + } while (pte++, addr += PAGE_SIZE, addr != end); + + *pmd = __pmd((__pa(start_pte) + PTE_HWTABLE_OFF) | type->prot_l1); + mb(); /* let pmd be programmed */ + flush_pmd_entry(pmd); + flush_tlb_all(); +} + +/* + * It's significantly easier to remap as pages later after all memory is + * mapped. Everything is sections so all we have to do is split + */ +static void __init remap_pages(void) +{ + struct memblock_region *reg; + + for_each_memblock(memory, reg) { + phys_addr_t phys_start = reg->base; + phys_addr_t phys_end = reg->base + reg->size; + unsigned long addr = (unsigned long)__va(phys_start); + unsigned long end = (unsigned long)__va(phys_end); + pmd_t *pmd = NULL; + unsigned long next; + unsigned long pfn = __phys_to_pfn(phys_start); + bool fixup = false; + unsigned long saved_start = addr; + + if (phys_end > arm_lowmem_limit) + end = (unsigned long)__va(arm_lowmem_limit); + if (phys_start >= phys_end) + break; + + pmd = pmd_offset( + pud_offset(pgd_offset(&init_mm, addr), addr), addr); + +#ifndef CONFIG_ARM_LPAE + if (addr & SECTION_SIZE) { + fixup = true; + pmd_empty_section_gap((addr - SECTION_SIZE) & PMD_MASK); + pmd++; + } + + if (end & SECTION_SIZE) + pmd_empty_section_gap(end); +#endif + + do { + next = addr + SECTION_SIZE; + + if (pmd_none(*pmd) || pmd_bad(*pmd)) + split_pmd(pmd, addr, next, pfn, + &mem_types[MT_MEMORY_RWX]); + pmd++; + pfn += SECTION_SIZE >> PAGE_SHIFT; + + } while (addr = next, addr < end); + + if (fixup) { + /* + * Put a faulting page table here to avoid detecting no + * pmd when accessing an odd section boundary. This + * needs to be faulting to help catch errors and avoid + * speculation + */ + pmd = pmd_off_k(saved_start); + pmd[0] = pmd[1] & ~1; + } + } +} +#else +static void __init remap_pages(void) +{ + +} +#endif + static void __init early_fixmap_shutdown(void) { int i; @@ -1628,6 +1722,7 @@ void __init paging_init(const struct machine_desc *mdesc) memblock_set_current_limit(arm_lowmem_limit); dma_contiguous_remap(); early_fixmap_shutdown(); + remap_pages(); devicemaps_init(mdesc); kmap_init(); tcm_init(); diff --git a/arch/arm/mm/pageattr.c b/arch/arm/mm/pageattr.c index 1403cb4a0c3d..86e441bad6e3 100644 --- a/arch/arm/mm/pageattr.c +++ b/arch/arm/mm/pageattr.c @@ -56,7 +56,8 @@ static int change_memory_common(unsigned long addr, int numpages, if (!size) return 0; - if (!in_range(start, size, MODULES_VADDR, MODULES_END) && + if (!IS_ENABLED(CONFIG_FORCE_PAGES) && + !in_range(start, size, MODULES_VADDR, MODULES_END) && !in_range(start, size, VMALLOC_START, VMALLOC_END)) return -EINVAL; -- GitLab From b4c5ccb9750805dfce2ce6ebd3fa54c29f42e915 Mon Sep 17 00:00:00 2001 From: Shiraz Hashim Date: Wed, 21 May 2014 09:35:08 +0530 Subject: [PATCH 1362/1635] arm: mm: fix pte allocation with CONFIG_FORCE_PAGES feature CONFIG_FORCE_PAGES introduces a debug option to mark free pages as read only in order to trigger a fault if any code attempts to write to a page on the buddy list. In order to achieve this it splits all section mappings in to PAGE_SIZE pages during boot. While doing this split, it wrongly allocates a pte (of page size) for each pmd. Linux however in armv7 short descriptor format, uses same second level pte for 2 consecutive pmds offset by the actual second level table size. Refer comments in kernel file arch/arm/include/asm/pgtable-2level.h for details. Fix this by allocating pte for a section mapped pmd while providing required offset if pte already exists. Change-Id: Iadbaa5e71e4b220208a7275bf039a2a413349e42 Signed-off-by: Shiraz Hashim Signed-off-by: Charan Teja Reddy --- arch/arm/mm/mmu.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c index b537340acec6..fe9923e7deca 100644 --- a/arch/arm/mm/mmu.c +++ b/arch/arm/mm/mmu.c @@ -1596,8 +1596,25 @@ static noinline void __init split_pmd(pmd_t *pmd, unsigned long addr, const struct mem_type *type) { pte_t *pte, *start_pte; + pmd_t *base_pmd; - start_pte = early_alloc(PTE_HWTABLE_OFF + PTE_HWTABLE_SIZE); + base_pmd = pmd_offset( + pud_offset(pgd_offset(&init_mm, addr), addr), addr); + + if (pmd_none(*base_pmd) || pmd_bad(*base_pmd)) { + start_pte = early_alloc(PTE_HWTABLE_OFF + PTE_HWTABLE_SIZE); +#ifndef CONFIG_ARM_LPAE + /* + * Following is needed when new pte is allocated for pmd[1] + * cases, which may happen when base (start) address falls + * under pmd[1]. + */ + if (addr & SECTION_SIZE) + start_pte += pte_index(addr); +#endif + } else { + start_pte = pte_offset_kernel(base_pmd, addr); + } pte = start_pte; -- GitLab From 89e53bc55a3842ac9e061161880c34e6604d7d04 Mon Sep 17 00:00:00 2001 From: Shiraz Hashim Date: Tue, 30 Jun 2015 09:14:46 +0530 Subject: [PATCH 1363/1635] arm: mm: consider only lowmem regions while remap Consider only those memory blocks with lowmem while remapping into 4KB regions using CONFIG_FORCE_PAGES feature. Change-Id: Ie209fce6c310f911d8cf02d977e226660684a6ab Signed-off-by: Shiraz Hashim Signed-off-by: Charan Teja Reddy --- arch/arm/mm/mmu.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c index fe9923e7deca..fbe829011806 100644 --- a/arch/arm/mm/mmu.c +++ b/arch/arm/mm/mmu.c @@ -1648,6 +1648,8 @@ static void __init remap_pages(void) bool fixup = false; unsigned long saved_start = addr; + if (phys_start > arm_lowmem_limit) + break; if (phys_end > arm_lowmem_limit) end = (unsigned long)__va(arm_lowmem_limit); if (phys_start >= phys_end) -- GitLab From dcf5ac4cccc96184c0aae9649f3f41fefabf789a Mon Sep 17 00:00:00 2001 From: Shiraz Hashim Date: Sat, 12 Sep 2015 11:50:24 +0530 Subject: [PATCH 1364/1635] arm: keep address range pmd aligned while remap During early init, all dma areas are remapped to PAGE_SIZE granularity. Since full pmd regions are cleared to be remapped into PAGE_SIZE, ensure that address range is pmd size aligned while not crossing memory boundaries. This would ensure that even if address region is not pmd aligned, its mapping would not be cleared but factored in to PAGE_SIZE regions. Change-Id: Iad4ad7fd6169cdc693d532821aba453465addb7c Signed-off-by: Shiraz Hashim Signed-off-by: Charan Teja Reddy --- arch/arm/mm/dma-mapping.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c index f002379d4837..5ee7fe5af1f6 100644 --- a/arch/arm/mm/dma-mapping.c +++ b/arch/arm/mm/dma-mapping.c @@ -487,6 +487,15 @@ void __init dma_contiguous_remap(void) struct map_desc map; unsigned long addr; + /* + * Make start and end PMD_SIZE aligned, observing memory + * boundaries + */ + if (memblock_is_memory(start & PMD_MASK)) + start = start & PMD_MASK; + if (memblock_is_memory(ALIGN(end, PMD_SIZE))) + end = ALIGN(end, PMD_SIZE); + if (end > arm_lowmem_limit) end = arm_lowmem_limit; if (start >= end) @@ -507,8 +516,13 @@ void __init dma_contiguous_remap(void) * and ensures that this code is architecturally compliant. */ for (addr = __phys_to_virt(start); addr < __phys_to_virt(end); - addr += PMD_SIZE) - pmd_clear(pmd_off_k(addr)); + addr += PMD_SIZE) { + pmd_t *pmd; + + pmd = pmd_off_k(addr); + if (pmd_bad(*pmd)) + pmd_clear(pmd); + } flush_tlb_kernel_range(__phys_to_virt(start), __phys_to_virt(end)); -- GitLab From 85247b2f9deb28c9ac879f4ba818333d3c71b540 Mon Sep 17 00:00:00 2001 From: Laura Abbott Date: Mon, 29 Oct 2012 11:54:38 -0700 Subject: [PATCH 1365/1635] arm: dma: Expand the page protection attributes Currently, the decision on which page protection to use is limited to writecombine and coherent. Expand to include strongly ordered memory and non consistent memory. Change-Id: I7585fe3ce804cf321a5585c3d93deb7a7c95045c Signed-off-by: Laura Abbott Signed-off-by: Charan Teja Reddy --- arch/arm/mm/dma-mapping.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c index 5ee7fe5af1f6..a99249f7ea2d 100644 --- a/arch/arm/mm/dma-mapping.c +++ b/arch/arm/mm/dma-mapping.c @@ -662,9 +662,14 @@ static void __free_from_contiguous(struct device *dev, struct page *page, static inline pgprot_t __get_dma_pgprot(unsigned long attrs, pgprot_t prot) { - prot = (attrs & DMA_ATTR_WRITE_COMBINE) ? - pgprot_writecombine(prot) : - pgprot_dmacoherent(prot); + if (attrs & DMA_ATTR_WRITE_COMBINE) + prot = pgprot_writecombine(prot); + else if (attrs & DMA_ATTR_STRONGLY_ORDERED) + prot = pgprot_stronglyordered(prot); + /* if non-consistent just pass back what was given */ + else if ((attrs & DMA_ATTR_NON_CONSISTENT) == 0) + prot = pgprot_dmacoherent(prot); + return prot; } -- GitLab From 706381f2030d9caf2f1f52a196db7396eb8aa665 Mon Sep 17 00:00:00 2001 From: Chintan Pandya Date: Tue, 26 May 2015 17:59:11 +0530 Subject: [PATCH 1366/1635] arm: dma-mapping: map sg lists into the SMMU as virtually contiguous In arm_iommu_map_sg, currently we map each individual link in the given scatterlist into the SMMU individually such that they may or may not be virtually contiguous. However, in most of our use cases we actually want the entire sg list mapped into the SMMU as a single contiguous range. This was missing for arm 32bit, add it. Change-Id: Ibf67f29a60b8d19e526c4719590f2f473ea9dca5 Signed-off-by: Chintan Pandya Signed-off-by: Charan Teja Reddy --- arch/arm/mm/dma-mapping.c | 36 ++++++++++++++++++++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c index a99249f7ea2d..d12881d00d6c 100644 --- a/arch/arm/mm/dma-mapping.c +++ b/arch/arm/mm/dma-mapping.c @@ -1843,7 +1843,31 @@ int arm_coherent_iommu_map_sg(struct device *dev, struct scatterlist *sg, int arm_iommu_map_sg(struct device *dev, struct scatterlist *sg, int nents, enum dma_data_direction dir, unsigned long attrs) { - return __iommu_map_sg(dev, sg, nents, dir, attrs, false); + struct scatterlist *s; + int i; + size_t ret; + struct dma_iommu_mapping *mapping = dev->archdata.mapping; + unsigned int total_length = 0, current_offset = 0; + dma_addr_t iova; + int prot = __dma_direction_to_prot(dir); + + for_each_sg(sg, s, nents, i) + total_length += s->length; + + iova = __alloc_iova(mapping, total_length); + ret = iommu_map_sg(mapping->domain, iova, sg, nents, prot); + if (ret != total_length) { + __free_iova(mapping, iova, total_length); + return 0; + } + + for_each_sg(sg, s, nents, i) { + s->dma_address = iova + current_offset; + s->dma_length = total_length - current_offset; + current_offset += s->length; + } + + return nents; } static void __iommu_unmap_sg(struct device *dev, struct scatterlist *sg, @@ -1894,7 +1918,15 @@ void arm_iommu_unmap_sg(struct device *dev, struct scatterlist *sg, int nents, enum dma_data_direction dir, unsigned long attrs) { - __iommu_unmap_sg(dev, sg, nents, dir, attrs, false); + struct dma_iommu_mapping *mapping = dev->archdata.mapping; + unsigned int total_length = sg_dma_len(sg); + dma_addr_t iova = sg_dma_address(sg); + + total_length = PAGE_ALIGN((iova & ~PAGE_MASK) + total_length); + iova &= PAGE_MASK; + + iommu_unmap_range(mapping->domain, iova, total_length); + __free_iova(mapping, iova, total_length); } /** -- GitLab From 09b917028e151e2bb0fa3ccf4530f90ae8963b04 Mon Sep 17 00:00:00 2001 From: Charan Teja Reddy Date: Mon, 24 Oct 2016 20:12:33 +0530 Subject: [PATCH 1367/1635] dma-mapping: use iommu_unmap for unmapping address Use the iommu_unmap() instead of iommu_unmap_range() for unmapping of address ranges. Change-Id: I3f2f7108b21adc2672e7f15ca24667c1c80a9453 Signed-off-by: Charan Teja Reddy --- arch/arm/mm/dma-mapping.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c index d12881d00d6c..180a8887852c 100644 --- a/arch/arm/mm/dma-mapping.c +++ b/arch/arm/mm/dma-mapping.c @@ -1925,7 +1925,7 @@ void arm_iommu_unmap_sg(struct device *dev, struct scatterlist *sg, int nents, total_length = PAGE_ALIGN((iova & ~PAGE_MASK) + total_length); iova &= PAGE_MASK; - iommu_unmap_range(mapping->domain, iova, total_length); + iommu_unmap(mapping->domain, iova, total_length); __free_iova(mapping, iova, total_length); } -- GitLab From c3d0d491a52fc5e83aca4a9d4919f6acc163cccd Mon Sep 17 00:00:00 2001 From: Liam Mark Date: Fri, 2 Dec 2016 10:31:07 -0800 Subject: [PATCH 1368/1635] arm: dma-mapping: handle IOVA address zero The IOVA allocator used by these calls supports IOVA address zero so properly handle IOVA address zero. Change-Id: Iaaad45b42503f05f95d1333e010f6d8e3bdb1949 Signed-off-by: Liam Mark Signed-off-by: Charan Teja Reddy --- arch/arm/mm/dma-mapping.c | 9 --------- 1 file changed, 9 deletions(-) diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c index 180a8887852c..10413cad20af 100644 --- a/arch/arm/mm/dma-mapping.c +++ b/arch/arm/mm/dma-mapping.c @@ -2036,9 +2036,6 @@ static void arm_coherent_iommu_unmap_page(struct device *dev, dma_addr_t handle, int offset = handle & ~PAGE_MASK; int len = PAGE_ALIGN(size + offset); - if (!iova) - return; - iommu_unmap(mapping->domain, iova, len); __free_iova(mapping, iova, len); } @@ -2136,9 +2133,6 @@ static void arm_iommu_sync_single_for_cpu(struct device *dev, struct page *page = phys_to_page(iommu_iova_to_phys(mapping->domain, iova)); unsigned int offset = handle & ~PAGE_MASK; - if (!iova) - return; - __dma_page_dev_to_cpu(page, offset, size, dir); } @@ -2150,9 +2144,6 @@ static void arm_iommu_sync_single_for_device(struct device *dev, struct page *page = phys_to_page(iommu_iova_to_phys(mapping->domain, iova)); unsigned int offset = handle & ~PAGE_MASK; - if (!iova) - return; - __dma_page_cpu_to_dev(page, offset, size, dir); } -- GitLab From f6f6f4e8a50feebecaa5f3762808d8be386dfbcb Mon Sep 17 00:00:00 2001 From: Shiraz Hashim Date: Wed, 7 Oct 2015 18:59:01 +0530 Subject: [PATCH 1369/1635] arm: mm: program ptes for access restriction CONFIG_RODATA allows strict kernel mapping permissions to be followed and accordingly maps regions as read-only, not-executable etc. correspondingly. CONFIG_RODATA however assumes all memory regions to be SECTION_SIZE aligned and section mapped for performance reasons. With CONFIG_FORCE_PAGES, we force all kernel mappings as page mapped thus breaking CONFIG_RODATA. Provide provision to apply permissions at page (pte) level, if CONFIG_RODATA does not find section mapping. Change-Id: I8dbf5c3741836bc63a231d8a471cf0306662993b Signed-off-by: Shiraz Hashim Signed-off-by: Charan Teja Reddy --- arch/arm/mm/init.c | 58 ++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 54 insertions(+), 4 deletions(-) diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c index 0f6d1537f330..8902e2d3e217 100644 --- a/arch/arm/mm/init.c +++ b/arch/arm/mm/init.c @@ -600,6 +600,9 @@ struct section_perm { pmdval_t mask; pmdval_t prot; pmdval_t clear; + pteval_t ptemask; + pteval_t pteprot; + pteval_t pteclear; }; /* First section-aligned location at or after __start_rodata. */ @@ -613,6 +616,8 @@ static struct section_perm nx_perms[] = { .end = (unsigned long)_stext, .mask = ~PMD_SECT_XN, .prot = PMD_SECT_XN, + .ptemask = ~L_PTE_XN, + .pteprot = L_PTE_XN, }, /* Make init RW (set NX). */ { @@ -621,6 +626,8 @@ static struct section_perm nx_perms[] = { .end = (unsigned long)_sdata, .mask = ~PMD_SECT_XN, .prot = PMD_SECT_XN, + .ptemask = ~L_PTE_XN, + .pteprot = L_PTE_XN, }, /* Make rodata NX (set RO in ro_perms below). */ { @@ -629,6 +636,8 @@ static struct section_perm nx_perms[] = { .end = (unsigned long)__init_begin, .mask = ~PMD_SECT_XN, .prot = PMD_SECT_XN, + .ptemask = ~L_PTE_XN, + .pteprot = L_PTE_XN, }, }; @@ -646,6 +655,8 @@ static struct section_perm ro_perms[] = { .prot = PMD_SECT_APX | PMD_SECT_AP_WRITE, .clear = PMD_SECT_AP_WRITE, #endif + .ptemask = ~L_PTE_RDONLY, + .pteprot = L_PTE_RDONLY, }, }; @@ -654,6 +665,35 @@ static struct section_perm ro_perms[] = { * copied into each mm). During startup, this is the init_mm. Is only * safe to be called with preemption disabled, as under stop_machine(). */ +struct pte_data { + pteval_t mask; + pteval_t val; +}; + +static int __pte_update(pte_t *ptep, pgtable_t token, unsigned long addr, + void *d) +{ + struct pte_data *data = d; + pte_t pte = *ptep; + + pte = __pte((pte_val(*ptep) & data->mask) | data->val); + set_pte_ext(ptep, pte, 0); + + return 0; +} + +static inline void pte_update(unsigned long addr, pteval_t mask, + pteval_t prot, struct mm_struct *mm) +{ + struct pte_data data; + + data.mask = mask; + data.val = prot; + + apply_to_page_range(mm, addr, SECTION_SIZE, __pte_update, &data); + flush_tlb_kernel_range(addr, addr + SECTION_SIZE); +} + static inline void section_update(unsigned long addr, pmdval_t mask, pmdval_t prot, struct mm_struct *mm) { @@ -702,11 +742,21 @@ void set_section_perms(struct section_perm *perms, int n, bool set, for (addr = perms[i].start; addr < perms[i].end; - addr += SECTION_SIZE) - section_update(addr, perms[i].mask, - set ? perms[i].prot : perms[i].clear, mm); + addr += SECTION_SIZE) { + pmd_t *pmd; + + pmd = pmd_offset(pud_offset(pgd_offset(mm, addr), + addr), addr); + if (pmd_bad(*pmd)) + section_update(addr, perms[i].mask, + set ? perms[i].prot : perms[i].clear, + mm); + else + pte_update(addr, perms[i].ptemask, + set ? perms[i].pteprot : perms[i].pteclear, + mm); + } } - } /** -- GitLab From 94852b7fc178bdbf29bb48d616793a37a7cd576d Mon Sep 17 00:00:00 2001 From: Sujeev Dias Date: Wed, 2 May 2018 19:37:53 -0700 Subject: [PATCH 1370/1635] mhi: core: remove inline declarations from header file No need to have dummy inline functions since client drivers are not supposed to call MHI related functions if MHI bus driver is not enabled. CRs-Fixed: 2235421 Change-Id: I5cb0fe5be4931f5610913d2e68a07785a4c743fb Signed-off-by: Sujeev Dias --- include/linux/mhi.h | 133 -------------------------------------------- 1 file changed, 133 deletions(-) diff --git a/include/linux/mhi.h b/include/linux/mhi.h index 1b3c644f2cdc..3e2e2abbf290 100644 --- a/include/linux/mhi.h +++ b/include/linux/mhi.h @@ -347,8 +347,6 @@ static inline void mhi_free_controller(struct mhi_controller *mhi_cntrl) kfree(mhi_cntrl); } -#if defined(CONFIG_MHI_BUS) - /** * mhi_driver_register - Register driver with MHI framework * @mhi_drv: mhi_driver structure @@ -527,137 +525,6 @@ int mhi_download_rddm_img(struct mhi_controller *mhi_cntrl, bool in_panic); */ int mhi_force_rddm_mode(struct mhi_controller *mhi_cntrl); -#else - -static inline int mhi_driver_register(struct mhi_driver *mhi_drv) -{ - return -EINVAL; -} - -static inline void mhi_driver_unregister(struct mhi_driver *mhi_drv) -{ -} - -static inline int mhi_device_configure(struct mhi_device *mhi_div, - enum dma_data_direction dir, - struct mhi_buf *mhi_buf, - int elements) -{ - return -EINVAL; -} - -static inline void mhi_device_get(struct mhi_device *mhi_dev) -{ -} - -static inline int mhi_device_get_sync(struct mhi_device *mhi_dev) -{ - return -EINVAL; -} - -static inline void mhi_device_put(struct mhi_device *mhi_dev) -{ -} - -static inline int mhi_prepare_for_transfer(struct mhi_device *mhi_dev) -{ - return -EINVAL; -} - -static inline void mhi_unprepare_from_transfer(struct mhi_device *mhi_dev) -{ - -} - -static inline int mhi_get_no_free_descriptors(struct mhi_device *mhi_dev, - enum dma_data_direction dir) -{ - return -EINVAL; -} - -static inline int mhi_poll(struct mhi_device *mhi_dev, u32 budget) -{ - return -EINVAL; -} - -static inline long mhi_ioctl(struct mhi_device *mhi_dev, - unsigned int cmd, - unsigned long arg) -{ - return -EINVAL; -} - -static inline struct mhi_controller *mhi_alloc_controller(size_t size) -{ - return NULL; -} - -static inline int of_register_mhi_controller(struct mhi_controller *mhi_cntrl) -{ - return -EINVAL; -} - -static inline void mhi_unregister_mhi_controller( - struct mhi_controller *mhi_cntrl) -{ -} - -static inline struct mhi_controller *mhi_bdf_to_controller(u32 domain, - u32 bus, - u32 slot, - u32 dev_id) -{ - return NULL; -} - -static inline int mhi_prepare_for_power_up(struct mhi_controller *mhi_cntrl) -{ - return -EINVAL; -} - -static inline int mhi_async_power_up(struct mhi_controller *mhi_cntrl) -{ - return -EINVAL; -} - -static inline int mhi_sync_power_up(struct mhi_controller *mhi_cntrl) -{ - return -EINVAL; -} - -static inline void mhi_power_down(struct mhi_controller *mhi_cntrl, - bool graceful) -{ -} - -static inline void mhi_unprepare_after_power_down( - struct mhi_controller *mhi_cntrl) -{ -} - -static inline int mhi_pm_suspend(struct mhi_controller *mhi_cntrl) -{ - return -EINVAL; -} - -static inline int mhi_pm_resume(struct mhi_controller *mhi_cntrl) -{ - return -EINVAL; -} - -static inline int mhi_download_rddm_img(struct mhi_controller *mhi_cntrl, - bool in_panic) -{ - return -EINVAL; -} - -static inlint int mhi_force_rddm_mode(struct mhi_controller *mhi_cntrl) -{ - return -EINVAL; -} - -#endif - #ifndef CONFIG_ARCH_QCOM #ifdef CONFIG_MHI_DEBUG -- GitLab From 3f519f34d9338bad2bb18cff5836c2242fb1d01d Mon Sep 17 00:00:00 2001 From: Tirupathi Reddy Date: Mon, 26 Feb 2018 13:42:21 +0530 Subject: [PATCH 1371/1635] ARM: dts: msm: add PMS405 peripheral devices Add new device tree files pms405-rpm-regulator.dtsi and pms405.dtsi which contain devices for PMS405 peripherals. Change-Id: Iae62b910c3f0574d7f77958268aa2b8e5d8aac61 Signed-off-by: Tirupathi Reddy --- .../boot/dts/qcom/pms405-rpm-regulator.dtsi | 304 ++++++++++++++++++ arch/arm64/boot/dts/qcom/pms405.dtsi | 103 ++++++ 2 files changed, 407 insertions(+) create mode 100644 arch/arm64/boot/dts/qcom/pms405-rpm-regulator.dtsi create mode 100644 arch/arm64/boot/dts/qcom/pms405.dtsi diff --git a/arch/arm64/boot/dts/qcom/pms405-rpm-regulator.dtsi b/arch/arm64/boot/dts/qcom/pms405-rpm-regulator.dtsi new file mode 100644 index 000000000000..dd0200ef5027 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/pms405-rpm-regulator.dtsi @@ -0,0 +1,304 @@ +/* Copyright (c) 2018 The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +&rpm_bus { + /* VDD_MX/CX supply */ + rpm-regulator-smpa1 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "rwmx"; + qcom,resource-id = <1>; + qcom,regulator-type = <1>; + qcom,hpm-min-load = <100000>; + status = "disabled"; + + regulator-s1 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pms405_s1"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + /* VDD_LPI_CX supply */ + rpm-regulator-smpa2 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "rwlc"; + qcom,resource-id = <2>; + qcom,regulator-type = <1>; + qcom,hpm-min-load = <100000>; + status = "disabled"; + + regulator-s2 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pms405_s2"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-smpa3 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "smpa"; + qcom,resource-id = <3>; + qcom,regulator-type = <1>; + qcom,hpm-min-load = <100000>; + status = "disabled"; + + regulator-s3 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pms405_s3"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-smpa4 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "smpa"; + qcom,resource-id = <4>; + qcom,regulator-type = <1>; + qcom,hpm-min-load = <100000>; + status = "disabled"; + + regulator-s4 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pms405_s4"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-smpa5 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "smpa"; + qcom,resource-id = <5>; + qcom,regulator-type = <1>; + qcom,hpm-min-load = <100000>; + status = "disabled"; + + regulator-s5 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pms405_s5"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-ldoa1 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "ldoa"; + qcom,resource-id = <1>; + qcom,regulator-type = <0>; + qcom,hpm-min-load = <10000>; + status = "disabled"; + + regulator-l1 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pms405_l1"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-ldoa2 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "ldoa"; + qcom,resource-id = <2>; + qcom,regulator-type = <0>; + qcom,hpm-min-load = <10000>; + status = "disabled"; + + regulator-l2 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pms405_l2"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-ldoa3 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "ldoa"; + qcom,resource-id = <3>; + qcom,regulator-type = <0>; + qcom,hpm-min-load = <10000>; + status = "disabled"; + + regulator-l3 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pms405_l3"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-ldoa4 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "ldoa"; + qcom,resource-id = <4>; + qcom,regulator-type = <0>; + qcom,hpm-min-load = <10000>; + status = "disabled"; + + regulator-l4 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pms405_l4"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-ldoa5 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "ldoa"; + qcom,resource-id = <5>; + qcom,regulator-type = <0>; + qcom,hpm-min-load = <10000>; + status = "disabled"; + + regulator-l5 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pms405_l5"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-ldoa6 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "ldoa"; + qcom,resource-id = <6>; + qcom,regulator-type = <0>; + qcom,hpm-min-load = <10000>; + status = "disabled"; + + regulator-l6 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pms405_l6"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-ldoa7 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "ldoa"; + qcom,resource-id = <7>; + qcom,regulator-type = <0>; + qcom,hpm-min-load = <10000>; + status = "disabled"; + + regulator-l7 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pms405_l7"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-ldoa8 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "ldoa"; + qcom,resource-id = <8>; + qcom,regulator-type = <0>; + qcom,hpm-min-load = <10000>; + status = "disabled"; + + regulator-l8 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pms405_l8"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + /* VDD_LPI_MX supply */ + rpm-regulator-ldoa9 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "rwlm"; + qcom,resource-id = <0>; + qcom,regulator-type = <0>; + qcom,hpm-min-load = <10000>; + status = "disabled"; + + regulator-l9 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pms405_l9"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-ldoa10 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "ldoa"; + qcom,resource-id = <10>; + qcom,regulator-type = <0>; + qcom,hpm-min-load = <10000>; + status = "disabled"; + + regulator-l10 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pms405_l10"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-ldoa11 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "ldoa"; + qcom,resource-id = <11>; + qcom,regulator-type = <0>; + qcom,hpm-min-load = <10000>; + status = "disabled"; + + regulator-l11 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pms405_l11"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-ldoa12 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "ldoa"; + qcom,resource-id = <12>; + qcom,regulator-type = <0>; + qcom,hpm-min-load = <10000>; + status = "disabled"; + + regulator-l12 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pms405_l12"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-ldoa13 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "ldoa"; + qcom,resource-id = <13>; + qcom,regulator-type = <0>; + qcom,hpm-min-load = <10000>; + status = "disabled"; + + regulator-l13 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pms405_l13"; + qcom,set = <3>; + status = "disabled"; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/pms405.dtsi b/arch/arm64/boot/dts/qcom/pms405.dtsi new file mode 100644 index 000000000000..969812d89468 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/pms405.dtsi @@ -0,0 +1,103 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include + +&spmi_bus { + qcom,pms405@0 { + compatible ="qcom,spmi-pmic"; + reg = <0x0 SPMI_USID>; + #address-cells = <1>; + #size-cells = <1>; + + qcom,revid@100 { + compatible = "qcom,qpnp-revid"; + reg = <0x100 0x100>; + }; + + pms405_pon: qcom,power-on@800 { + compatible = "qcom,qpnp-power-on"; + reg = <0x800 0x100>; + interrupts = <0x0 0x8 0x0>; + interrupt-names = "kpdpwr"; + qcom,pon-dbc-delay = <15625>; + + qcom,pon_1 { + qcom,pon-type = <0>; + qcom,pull-up = <1>; + linux,code = ; + }; + }; + + pms405_misc: qcom,misc@900 { + compatible = "qcom,qpnp-misc"; + reg = <0x900 0x100>; + }; + + /* QCS405 + PMS405 GPIO configuration */ + pms405_gpios: pinctrl@c000 { + compatible = "qcom,spmi-gpio"; + reg = <0xc000 0xc00>; + interrupts = <0x0 0xc1 0 IRQ_TYPE_NONE>, + <0x0 0xc2 0 IRQ_TYPE_NONE>, + <0x0 0xc3 0 IRQ_TYPE_NONE>, + <0x0 0xc4 0 IRQ_TYPE_NONE>, + <0x0 0xc5 0 IRQ_TYPE_NONE>, + <0x0 0xc6 0 IRQ_TYPE_NONE>, + <0x0 0xc7 0 IRQ_TYPE_NONE>, + <0x0 0xca 0 IRQ_TYPE_NONE>, + <0x0 0xcb 0 IRQ_TYPE_NONE>; + interrupt-names = "pms405_gpio2", "pms405_gpio3", + "pms405_gpio4", "pms405_gpio5", + "pms405_gpio6", "pms405_gpio7", + "pms405_gpio8", "pms405_gpio11", + "pms405_gpio12"; + gpio-controller; + #gpio-cells = <2>; + #address-cells = <1>; + #size-cells = <1>; + qcom,gpios-disallowed = <1 9 10>; + }; + + qcom,pms405_rtc { + compatible = "qcom,qpnp-rtc"; + #address-cells = <1>; + #size-cells = <1>; + qcom,qpnp-rtc-write = <0>; + qcom,qpnp-rtc-alarm-pwrup = <0>; + + qcom,pms405_rtc_rw@6000 { + reg = <0x6000 0x100>; + }; + + qcom,pms405_rtc_alarm@6100 { + reg = <0x6100 0x100>; + interrupts = <0x0 0x61 0x1 IRQ_TYPE_NONE>; + }; + }; + }; + + qcom,pms405@1 { + compatible = "qcom,spmi-pmic"; + reg = <0x1 SPMI_USID>; + #address-cells = <1>; + #size-cells = <1>; + + pms405_pwm: qcom,pwms@bc00 { + compatible = "qcom,pwm-lpg"; + reg = <0xbc00 0x200>; + reg-names = "lpg-base"; + #pwm-cells = <2>; + }; + }; +}; -- GitLab From 4b5d64db5d098b6d1e2ea464624df05da05038a5 Mon Sep 17 00:00:00 2001 From: Tirupathi Reddy Date: Tue, 6 Feb 2018 11:57:52 +0530 Subject: [PATCH 1372/1635] ARM: dts: msm: add PMS405 peripherals for QCS405 QCS405 uses PMS405 PMIC. Add PMS405 peripherals to QCS405 device tree. Also add RPM managed regulator devices for QCS405 so that the client requests made for these regulators are aggregated by the RPM processor along with the requests from other processors. QCS405 rumi platform does not contain PMS405. Remove PMS405 peripherals and RPM managed regulator devices from QCS405 RUMI device tree and add stub regulator devices. Change-Id: Id8a98091e719a29e66c441d3652f6c27e8af596b Signed-off-by: Tirupathi Reddy Signed-off-by: Anirudh Ghayal --- .../arm64/boot/dts/qcom/qcs405-regulator.dtsi | 259 ++++++++++++++++++ arch/arm64/boot/dts/qcom/qcs405-rumi.dtsi | 29 ++ .../boot/dts/qcom/qcs405-stub-regulator.dtsi | 186 +++++++++++++ arch/arm64/boot/dts/qcom/qcs405.dtsi | 29 ++ 4 files changed, 503 insertions(+) create mode 100644 arch/arm64/boot/dts/qcom/qcs405-regulator.dtsi create mode 100644 arch/arm64/boot/dts/qcom/qcs405-stub-regulator.dtsi diff --git a/arch/arm64/boot/dts/qcom/qcs405-regulator.dtsi b/arch/arm64/boot/dts/qcom/qcs405-regulator.dtsi new file mode 100644 index 000000000000..3546fb08a5ed --- /dev/null +++ b/arch/arm64/boot/dts/qcom/qcs405-regulator.dtsi @@ -0,0 +1,259 @@ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include + +&rpm_bus { + /* PMS405 S1 - VDD_MX/CX supply */ + rpm-regulator-smpa1 { + status = "okay"; + pms405_s1_level: regulator-s1-level { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pms405_s1_level"; + qcom,set = <3>; + regulator-min-microvolt = + ; + regulator-max-microvolt = + ; + qcom,use-voltage-level; + }; + + pms405_s1_floor_level: regulator-s1-floor-level { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pms405_s1_floor_level"; + qcom,set = <3>; + regulator-min-microvolt = + ; + regulator-max-microvolt = + ; + qcom,use-voltage-floor-level; + qcom,always-send-voltage; + }; + + pms405_s1_level_ao: regulator-s1-level-ao { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pms405_s1_level_ao"; + qcom,set = <1>; + regulator-min-microvolt = + ; + regulator-max-microvolt = + ; + qcom,use-voltage-level; + }; + }; + + /* PMS405 S2 - VDD_LPI_CX supply */ + rpm-regulator-smpa2 { + status = "okay"; + pms405_s2_level: regulator-s2-level { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pms405_s2_level"; + qcom,set = <3>; + regulator-min-microvolt = + ; + regulator-max-microvolt = + ; + qcom,use-voltage-level; + }; + + pms405_s2_floor_level: regulator-s2-floor-level { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pms405_s2_floor_level"; + qcom,set = <3>; + regulator-min-microvolt = + ; + regulator-max-microvolt = + ; + qcom,use-voltage-floor-level; + qcom,always-send-voltage; + }; + }; + + rpm-regulator-smpa4 { + status = "okay"; + pms405_s4: regulator-s4 { + regulator-min-microvolt = <1728000>; + regulator-max-microvolt = <1920000>; + qcom,init-voltage = <1728000>; + status = "okay"; + }; + }; + + rpm-regulator-ldoa1 { + status = "okay"; + pms405_l1: regulator-l1 { + regulator-min-microvolt = <1240000>; + regulator-max-microvolt = <1352000>; + qcom,init-voltage = <1240000>; + status = "okay"; + }; + }; + + rpm-regulator-ldoa2 { + status = "okay"; + pms405_l2: regulator-l2 { + regulator-min-microvolt = <1048000>; + regulator-max-microvolt = <1280000>; + qcom,init-voltage = <1048000>; + status = "okay"; + }; + }; + + rpm-regulator-ldoa3 { + status = "okay"; + pms405_l3: regulator-l3 { + regulator-min-microvolt = <976000>; + regulator-max-microvolt = <1160000>; + qcom,init-voltage = <976000>; + status = "okay"; + }; + }; + + rpm-regulator-ldoa4 { + status = "okay"; + pms405_l4: regulator-l4 { + regulator-min-microvolt = <1144000>; + regulator-max-microvolt = <1256000>; + qcom,init-voltage = <1144000>; + status = "okay"; + }; + }; + + rpm-regulator-ldoa5 { + status = "okay"; + pms405_l5: regulator-l5 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + qcom,init-voltage = <1800000>; + status = "okay"; + }; + + pms405_l5_ao: regulator-l5-ao { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pms405_l5_ao"; + qcom,set = <1>; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + qcom,init-voltage = <1800000>; + status = "okay"; + }; + }; + + rpm-regulator-ldoa6 { + status = "okay"; + pms405_l6: regulator-l6 { + regulator-min-microvolt = <1704000>; + regulator-max-microvolt = <1896000>; + qcom,init-voltage = <1704000>; + status = "okay"; + }; + }; + + rpm-regulator-ldoa7 { + status = "okay"; + pms405_l7: regulator-l7 { + regulator-min-microvolt = <1616000>; + regulator-max-microvolt = <3000000>; + qcom,init-voltage = <1616000>; + status = "okay"; + }; + }; + + rpm-regulator-ldoa8 { + status = "okay"; + pms405_l8: regulator-l8 { + regulator-min-microvolt = <1136000>; + regulator-max-microvolt = <1352000>; + qcom,init-voltage = <1136000>; + status = "okay"; + }; + }; + + /* PMS405 L9 - VDD_LPI_MX supply */ + rpm-regulator-ldoa9 { + status = "okay"; + pms405_l9_level: regulator-l9-level { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pms405_l9_level"; + qcom,set = <3>; + regulator-min-microvolt = + ; + regulator-max-microvolt = + ; + qcom,use-voltage-level; + }; + + pms405_l9_floor_level: regulator-l9-floor-level { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pms405_l9_floor_level"; + qcom,set = <3>; + regulator-min-microvolt = + ; + regulator-max-microvolt = + ; + qcom,use-voltage-floor-level; + qcom,always-send-voltage; + }; + }; + + rpm-regulator-ldoa10 { + status = "okay"; + pms405_l10: regulator-l10 { + regulator-min-microvolt = <2936000>; + regulator-max-microvolt = <3088000>; + qcom,init-voltage = <2936000>; + status = "okay"; + }; + }; + + rpm-regulator-ldoa11 { + status = "okay"; + pms405_l11: regulator-l11 { + regulator-min-microvolt = <2696000>; + regulator-max-microvolt = <3304000>; + qcom,init-voltage = <2696000>; + status = "okay"; + }; + }; + + rpm-regulator-ldoa12 { + status = "okay"; + pms405_l12: regulator-l12 { + regulator-min-microvolt = <2968000>; + regulator-max-microvolt = <3300000>; + qcom,init-voltage = <2968000>; + status = "okay"; + }; + }; + + rpm-regulator-ldoa13 { + status = "okay"; + pms405_l13: regulator-l13 { + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <3300000>; + qcom,init-voltage = <3000000>; + status = "okay"; + }; + }; +}; + +/* Stub regulators */ +/ { + /* VDD_APC supply */ + apc_vreg_corner: regulator-apc-corner { + compatible = "qcom,stub-regulator"; + regulator-name = "apc_corner"; + regulator-min-microvolt = <1>; + regulator-max-microvolt = <3>; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/qcs405-rumi.dtsi b/arch/arm64/boot/dts/qcom/qcs405-rumi.dtsi index 6fa2c1767ac2..563a0cbb88e9 100644 --- a/arch/arm64/boot/dts/qcom/qcs405-rumi.dtsi +++ b/arch/arm64/boot/dts/qcom/qcs405-rumi.dtsi @@ -53,3 +53,32 @@ dr_mode = "peripheral"; }; }; + +&rpm_bus { + /delete-node/ rpm-regulator-smpa1; + /delete-node/ rpm-regulator-smpa2; + /delete-node/ rpm-regulator-smpa4; + /delete-node/ rpm-regulator-ldoa1; + /delete-node/ rpm-regulator-ldoa2; + /delete-node/ rpm-regulator-ldoa3; + /delete-node/ rpm-regulator-ldoa4; + /delete-node/ rpm-regulator-ldoa5; + /delete-node/ rpm-regulator-ldoa6; + /delete-node/ rpm-regulator-ldoa7; + /delete-node/ rpm-regulator-ldoa8; + /delete-node/ rpm-regulator-ldoa9; + /delete-node/ rpm-regulator-ldoa10; + /delete-node/ rpm-regulator-ldoa11; + /delete-node/ rpm-regulator-ldoa12; + /delete-node/ rpm-regulator-ldoa13; +}; + +&soc { + /delete-node/ qcom,spmi@200f000; +}; + +&rpm_bus { + rpm-standalone; +}; + +#include "qcs405-stub-regulator.dtsi" diff --git a/arch/arm64/boot/dts/qcom/qcs405-stub-regulator.dtsi b/arch/arm64/boot/dts/qcom/qcs405-stub-regulator.dtsi new file mode 100644 index 000000000000..378135169d42 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/qcs405-stub-regulator.dtsi @@ -0,0 +1,186 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/* Stub regulators */ + +/ { + /* PMS405_S1 - VDD_MX/CX supply */ + pms405_s1_level: regulator-pms405-s1-level { + compatible = "qcom,stub-regulator"; + regulator-name = "pms405_s1_level"; + qcom,hpm-min-load = <100000>; + regulator-min-microvolt = ; + regulator-max-microvolt = ; + }; + + pms405_s1_floor_level: regulator-pms405-s1-floor-level { + compatible = "qcom,stub-regulator"; + regulator-name = "pms405_s1_floor_level"; + qcom,hpm-min-load = <100000>; + regulator-min-microvolt = ; + regulator-max-microvolt = ; + }; + + pms405_s1_level_ao: regulator-pms405-s1-level-ao { + compatible = "qcom,stub-regulator"; + regulator-name = "pms405_s1_level_ao"; + qcom,hpm-min-load = <100000>; + regulator-min-microvolt = ; + regulator-max-microvolt = ; + }; + + /* PMS405_S2 - VDD_LPI_CX supply */ + pms405_s2_level: regulator-pms405-s2-level { + compatible = "qcom,stub-regulator"; + regulator-name = "pms405_s2_level"; + qcom,hpm-min-load = <100000>; + regulator-min-microvolt = ; + regulator-max-microvolt = ; + }; + + pms405_s2_floor_level: regulator-pms405-s2-floor-level { + compatible = "qcom,stub-regulator"; + regulator-name = "pms405_s2_floor_level"; + qcom,hpm-min-load = <100000>; + regulator-min-microvolt = ; + regulator-max-microvolt = ; + }; + + pms405_s4: regulator-pms405-s4 { + compatible = "qcom,stub-regulator"; + regulator-name = "pms405_s4"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <1728000>; + regulator-max-microvolt = <1920000>; + }; + + pms405_l1: regulator-pms405-l1 { + compatible = "qcom,stub-regulator"; + regulator-name = "pms405_l1"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <1240000>; + regulator-max-microvolt = <1352000>; + }; + + pms405_l2: regulator-pms405-l2 { + compatible = "qcom,stub-regulator"; + regulator-name = "pms405_l2"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <1048000>; + regulator-max-microvolt = <1280000>; + }; + + pms405_l3: regulator-pms405-l3 { + compatible = "qcom,stub-regulator"; + regulator-name = "pms405_l3"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <976000>; + regulator-max-microvolt = <1160000>; + }; + + pms405_l4: regulator-pms405-l4 { + compatible = "qcom,stub-regulator"; + regulator-name = "pms405_l4"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <1144000>; + regulator-max-microvolt = <1256000>; + }; + + pms405_l5: regulator-pms405-l5 { + compatible = "qcom,stub-regulator"; + regulator-name = "pms405_l5"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + }; + + pms405_l5_ao: regulator-pms405-l5-ao { + compatible = "qcom,stub-regulator"; + regulator-name = "pms405_l5_ao"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + }; + + pms405_l6: regulator-pms405-l6 { + compatible = "qcom,stub-regulator"; + regulator-name = "pms405_l6"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <1704000>; + regulator-max-microvolt = <1896000>; + }; + + pms405_l7: regulator-pms405-l7 { + compatible = "qcom,stub-regulator"; + regulator-name = "pms405_l7"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <1616000>; + regulator-max-microvolt = <3000000>; + }; + + pms405_l8: regulator-pms405-l8 { + compatible = "qcom,stub-regulator"; + regulator-name = "pms405_l8"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <1136000>; + regulator-max-microvolt = <1352000>; + }; + + /* PMS405 L9 - VDD_LPI_MX supply */ + pms405_l9_level: regulator-pms405-l9-level { + compatible = "qcom,stub-regulator"; + regulator-name = "pms405_l9_level"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = ; + regulator-max-microvolt = ; + }; + + pms405_l9_floor_level: regulator-pms405-l9-floor-level { + compatible = "qcom,stub-regulator"; + regulator-name = "pms405_l9_floor_level"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = ; + regulator-max-microvolt = ; + }; + + pms405_l10: regulator-pms405-l10 { + compatible = "qcom,stub-regulator"; + regulator-name = "pms405_l10"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <2936000>; + regulator-max-microvolt = <3088000>; + }; + + pms405_l11: regulator-pms405-l11 { + compatible = "qcom,stub-regulator"; + regulator-name = "pms405_l11"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <2696000>; + regulator-max-microvolt = <3304000>; + }; + + pms405_l12: regulator-pms405-l12 { + compatible = "qcom,stub-regulator"; + regulator-name = "pms405_l12"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <2968000>; + regulator-max-microvolt = <3300000>; + }; + + pms405_l13: regulator-pms405-l13 { + compatible = "qcom,stub-regulator"; + regulator-name = "pms405_l13"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <3300000>; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/qcs405.dtsi b/arch/arm64/boot/dts/qcom/qcs405.dtsi index dbf4d04af696..4e85b474ff9f 100644 --- a/arch/arm64/boot/dts/qcom/qcs405.dtsi +++ b/arch/arm64/boot/dts/qcom/qcs405.dtsi @@ -15,6 +15,7 @@ #include #include #include +#include #include / { @@ -209,6 +210,31 @@ qcom,save-reg; }; + rpm_bus: qcom,rpm-smd { + compatible = "qcom,rpm-smd"; + rpm-channel-name = "rpm_requests"; + rpm-channel-type = <15>; /* SMD_APPS_RPM */ + }; + + spmi_bus: qcom,spmi@200f000 { + compatible = "qcom,spmi-pmic-arb"; + reg = <0x200f000 0x1000>, + <0x2400000 0x800000>, + <0x2c00000 0x800000>, + <0x3800000 0x200000>, + <0x200a000 0x2100>; + reg-names = "core", "chnls", "obsrvr", "intr", "cnfg"; + interrupt-names = "periph_irq"; + interrupts = ; + qcom,ee = <0>; + qcom,channel = <0>; + #address-cells = <2>; + #size-cells = <0>; + interrupt-controller; + #interrupt-cells = <4>; + cell-index = <0>; + }; + qcom,wdt@b017000 { compatible = "qcom,msm-watchdog"; reg = <0xb017000 0x1000>; @@ -318,6 +344,9 @@ #include "qcs405-gdsc.dtsi" #include "qcs405-thermal.dtsi" +#include "pms405.dtsi" +#include "pms405-rpm-regulator.dtsi" +#include "qcs405-regulator.dtsi" &gdsc_mdss { status = "ok"; -- GitLab From b521331577b754fc10c0c06288066863d0c15778 Mon Sep 17 00:00:00 2001 From: Vinayak Menon Date: Thu, 17 Dec 2015 08:35:36 +0530 Subject: [PATCH 1373/1635] mm: memory: reduce fault_around_bytes mapping multiple pages on a fault result in page_check_references hitting more number of referenced inactive pages and this results in increased pressure on reclaim. Reduce it to the lowest possible value. Reduced kswapd wakeups are observed with this change. Change-Id: I03c6cac9f28fa328abab7b40f5f01144084a147c Signed-off-by: Vinayak Menon Signed-off-by: Patrick Daly Signed-off-by: Sudarshan Rajagopalan Signed-off-by: Charan Teja Reddy --- mm/memory.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mm/memory.c b/mm/memory.c index fc7779165dcf..57f678e93414 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -3443,7 +3443,7 @@ int finish_fault(struct vm_fault *vmf) } static unsigned long fault_around_bytes __read_mostly = - rounddown_pow_of_two(65536); + rounddown_pow_of_two(4096); #ifdef CONFIG_DEBUG_FS static int fault_around_bytes_get(void *data, u64 *val) -- GitLab From 392e2f537fd214980f1bd211b202737173f0cc71 Mon Sep 17 00:00:00 2001 From: Vinayak Menon Date: Sun, 19 Feb 2017 20:00:31 +1100 Subject: [PATCH 1374/1635] mm: vmscan: do not pass reclaimed slab to vmpressure During global reclaim, the nr_reclaimed passed to vmpressure includes the pages reclaimed from slab. But the corresponding scanned slab pages is not passed. There is an impact to the vmpressure values because of this. While moving from kernel version 3.18 to 4.4, a difference is seen in the vmpressure values for the same workload resulting in a different behaviour of the vmpressure consumer. One such case is of a vmpressure based lowmemorykiller. It is observed that the vmpressure events are received late and less in number resulting in tasks not being killed at the right time. The following numbers show the impact on reclaim activity due to the change in behaviour of lowmemorykiller on a 4GB device. The test launches a number of apps in sequence and repeats it multiple times. v4.4 v3.18 pgpgin 163016456 145617236 pgpgout 4366220 4188004 workingset_refault 29857868 26781854 workingset_activate 6293946 5634625 pswpin 1327601 1133912 pswpout 3593842 3229602 pgalloc_dma 99520618 94402970 pgalloc_normal 104046854 98124798 pgfree 203772640 192600737 pgmajfault 2126962 1851836 pgsteal_kswapd_dma 19732899 18039462 pgsteal_kswapd_normal 19945336 17977706 pgsteal_direct_dma 206757 131376 pgsteal_direct_normal 236783 138247 pageoutrun 116622 108370 allocstall 7220 4684 compact_stall 931 856 This is a regression introduced by commit 6b4f7799c6a5 ("mm: vmscan: invoke slab shrinkers from shrink_zone()"). So do not consider reclaimed slab pages for vmpressure calculation. The reclaimed pages from slab can be excluded because the freeing of a page by slab shrinking depends on each slab's object population, making the cost model (i.e. scan:free) different from that of LRU. Also, not every shrinker accounts the pages it reclaims. But ideally the pages reclaimed from slab should be passed to vmpressure, otherwise higher vmpressure levels can be triggered even when there is a reclaim progress. But accounting only the reclaimed slab pages without the scanned, and adding something which does not fit into the cost model just adds noise to the vmpressure values. Fixes: 6b4f7799c6a5 ("mm: vmscan: invoke slab shrinkers from shrink_zone()") Acked-by: Minchan Kim Cc: Johannes Weiner Cc: Mel Gorman Cc: Vlastimil Babka Cc: Michal Hocko Cc: Rik van Riel Cc: Vladimir Davydov Cc: Anton Vorontsov Cc: Shiraz Hashim Signed-off-by: Andrew Morton Git-commit: 97a9668a428e9651a4aa3ff5d4e7e60024be2d87 Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git Change-Id: If46b1cee6fd9723bebd87d76e0bb8451de05a9c1 Signed-off-by: Vinayak Menon Signed-off-by: Patrick Daly Signed-off-by: Sudarshan Rajagopalan Signed-off-by: Charan Teja Reddy --- mm/vmscan.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/mm/vmscan.c b/mm/vmscan.c index b3f5e337b64a..cb9d16b089ab 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -2666,16 +2666,23 @@ static bool shrink_node(pg_data_t *pgdat, struct scan_control *sc) sc->nr_scanned - nr_scanned, node_lru_pages); + /* + * Record the subtree's reclaim efficiency. The reclaimed + * pages from slab is excluded here because the corresponding + * scanned pages is not accounted. Moreover, freeing a page + * by slab shrinking depends on each slab's object population, + * making the cost model (i.e. scan:free) different from that + * of LRU. + */ + vmpressure(sc->gfp_mask, sc->target_mem_cgroup, true, + sc->nr_scanned - nr_scanned, + sc->nr_reclaimed - nr_reclaimed); + if (reclaim_state) { sc->nr_reclaimed += reclaim_state->reclaimed_slab; reclaim_state->reclaimed_slab = 0; } - /* Record the subtree's reclaim efficiency */ - vmpressure(sc->gfp_mask, sc->target_mem_cgroup, true, - sc->nr_scanned - nr_scanned, - sc->nr_reclaimed - nr_reclaimed); - if (sc->nr_reclaimed - nr_reclaimed) reclaimable = true; -- GitLab From e2081732118a097672c99bf39d12783c278acc4e Mon Sep 17 00:00:00 2001 From: Prakash Gupta Date: Tue, 10 Apr 2018 15:13:21 +0530 Subject: [PATCH 1375/1635] ion: ion_system_heap: update supported page-orders for ion pool The supported mappings for ARMv8 are 1GB, 2MB, 64KB and 4KB. So 1MB allocations from ion pool is not used for ARMv8 section map. Such allocations end up being mapped as multiple 64K sections map, while still using 1MB contiguous memory. In case of ARMv7s, page-order 9 allocations are not used as section map. Drop page-order 8 ion pool for builds using ARMv8 pagetables and page-order 9 ion pool for builds using ARMv7s. Change-Id: Ifff2d8f1cf61ce443311d16c11b8edc191b27a22 Signed-off-by: Prakash Gupta --- drivers/staging/android/ion/ion_system_heap.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/staging/android/ion/ion_system_heap.h b/drivers/staging/android/ion/ion_system_heap.h index a9f12103d254..6a913d62c9b5 100644 --- a/drivers/staging/android/ion/ion_system_heap.h +++ b/drivers/staging/android/ion/ion_system_heap.h @@ -16,7 +16,11 @@ #define _ION_SYSTEM_HEAP_H #ifndef CONFIG_ALLOC_BUFFERS_IN_4K_CHUNKS -static const unsigned int orders[] = {9, 8, 4, 0}; +#if defined(CONFIG_IOMMU_IO_PGTABLE_ARMV7S) +static const unsigned int orders[] = {8, 4, 0}; +#else +static const unsigned int orders[] = {9, 4, 0}; +#endif #else static const unsigned int orders[] = {0}; #endif -- GitLab From 27c4b5fc1e486bd3d7d78ddd9429a6cf46a7ed00 Mon Sep 17 00:00:00 2001 From: Tharun Kumar Merugu Date: Thu, 3 May 2018 17:46:29 +0530 Subject: [PATCH 1376/1635] msm: adsprpc: validate VMID before hyp assign Verify that VMID is not NULL before hyp assign call in init process and memory map on remote subsystem. Change-Id: I10a96b4efde61c5aa572748dda3596fb2301c6b2 Acked-by: Thyagarajan Venkatanarayanan Signed-off-by: Tharun Kumar Merugu --- drivers/char/adsprpc.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/char/adsprpc.c b/drivers/char/adsprpc.c index dfc6cb2ce960..6d6f54a9f9cd 100644 --- a/drivers/char/adsprpc.c +++ b/drivers/char/adsprpc.c @@ -1893,7 +1893,8 @@ static int fastrpc_init_process(struct fastrpc_file *fl, if (err && (init->flags == FASTRPC_INIT_CREATE_STATIC)) me->staticpd_flags = 0; if (mem && err) { - if (mem->flags == ADSP_MMAP_REMOTE_HEAP_ADDR) + if (mem->flags == ADSP_MMAP_REMOTE_HEAP_ADDR + && me->channel[fl->cid].rhvm.vmid) hyp_assign_phys(mem->phys, (uint64_t)mem->size, me->channel[fl->cid].rhvm.vmid, me->channel[fl->cid].rhvm.vmcount, @@ -1989,7 +1990,8 @@ static int fastrpc_mmap_on_dsp(struct fastrpc_file *fl, uint32_t flags, desc.arginfo = SCM_ARGS(3); err = scm_call2(SCM_SIP_FNID(SCM_SVC_PIL, TZ_PIL_PROTECT_MEM_SUBSYS_ID), &desc); - } else if (flags == ADSP_MMAP_REMOTE_HEAP_ADDR) { + } else if (flags == ADSP_MMAP_REMOTE_HEAP_ADDR + && me->channel[fl->cid].rhvm.vmid) { VERIFY(err, !hyp_assign_phys(map->phys, (uint64_t)map->size, hlosvm, 1, me->channel[fl->cid].rhvm.vmid, me->channel[fl->cid].rhvm.vmperm, -- GitLab From 9bcf9baa5e34673f56733f1533279746b47aae76 Mon Sep 17 00:00:00 2001 From: Tharun Kumar Merugu Date: Wed, 2 May 2018 17:55:17 +0530 Subject: [PATCH 1377/1635] msm: adsprpc: duplicate session info for shared context banks Duplicate fastrpc session contexts for shared context banks depending on the maximum number of sessions allowed. Change-Id: I7028e70836e3ec32b789aefd0e9ef08dab87d881 Acked-by: Thyagarajan Venkatanarayanan Signed-off-by: Tharun Kumar Merugu --- .../devicetree/bindings/qdsp/msm-fastrpc.txt | 17 +++++++++------ drivers/char/adsprpc.c | 21 ++++++++++++++++++- 2 files changed, 31 insertions(+), 7 deletions(-) diff --git a/Documentation/devicetree/bindings/qdsp/msm-fastrpc.txt b/Documentation/devicetree/bindings/qdsp/msm-fastrpc.txt index c5b48aebb6f5..5e104f92b5f5 100644 --- a/Documentation/devicetree/bindings/qdsp/msm-fastrpc.txt +++ b/Documentation/devicetree/bindings/qdsp/msm-fastrpc.txt @@ -21,10 +21,13 @@ Optional subnodes: - qcom,msm-fastrpc-rpmsg : Child node for rpmsg instead of glink for IPC Subnode Required properties: -- compatible : Must be "qcom,msm-fastrpc-compute-cb" -- label: Label describing the channel this context bank belongs to -- iommus : A list of phandle and IOMMU specifier pairs that describe the +- compatible : Must be "qcom,msm-fastrpc-compute-cb" +- label : Label describing the channel this context bank belongs to +- iommus : A list of phandle and IOMMU specifier pairs that describe the IOMMU master interfaces of the device +- dma-coherent : A flag marking a context bank as I/O coherent +- shared-cb : A value indicating how many fastrpc sessions can share a + context bank Example: qcom,msm_fastrpc { @@ -42,12 +45,14 @@ Example: qcom,msm_fastrpc_compute_cb_1 { compatible = "qcom,msm-fastrpc-compute-cb"; label = "adsprpc-smd"; - iommus = <&apps_smmu 0x1401 0x0>, + iommus = <&apps_smmu 0x1401 0x0>; + dma-coherent; }; qcom,msm_fastrpc_compute_cb_2 { compatible = "qcom,msm-fastrpc-compute-cb"; - label = "adsprpc-smd"; - iommus = <&apps_smmu 0x1402 0x0>, + label = "sdsprpc-smd"; + iommus = <&apps_smmu 0x1402 0x0>; + shared-cb = <5>; }; }; diff --git a/drivers/char/adsprpc.c b/drivers/char/adsprpc.c index dfc6cb2ce960..dcbc05f0dd28 100644 --- a/drivers/char/adsprpc.c +++ b/drivers/char/adsprpc.c @@ -2960,7 +2960,8 @@ static int fastrpc_cb_probe(struct device *dev) struct of_phandle_args iommuspec; const char *name; dma_addr_t start = 0x80000000; - int err = 0, cid, i; + int err = 0; + unsigned int sharedcb_count = 0, cid, i, j; int secure_vmid = VMID_CP_PIXEL; VERIFY(err, NULL != (name = of_get_property(dev->of_node, @@ -3022,6 +3023,24 @@ static int fastrpc_cb_probe(struct device *dev) dma_set_max_seg_size(sess->smmu.dev, DMA_BIT_MASK(32)); dma_set_seg_boundary(sess->smmu.dev, DMA_BIT_MASK(64)); + if (of_get_property(dev->of_node, "shared-cb", NULL) != NULL) { + VERIFY(err, !of_property_read_u32(dev->of_node, "shared-cb", + &sharedcb_count)); + if (err) + goto bail; + if (sharedcb_count > 0) { + struct fastrpc_session_ctx *dup_sess; + + for (j = 1; j < sharedcb_count && + chan->sesscount < NUM_SESSIONS; j++) { + chan->sesscount++; + dup_sess = &chan->session[chan->sesscount]; + memcpy(dup_sess, sess, + sizeof(struct fastrpc_session_ctx)); + } + } + } + chan->sesscount++; debugfs_global_file = debugfs_create_file("global", 0644, debugfs_root, NULL, &debugfs_fops); -- GitLab From 155c348febfa2635aa8e04e908c032f268ded032 Mon Sep 17 00:00:00 2001 From: Alexei Avshalom Lazar Date: Thu, 3 May 2018 16:22:50 +0300 Subject: [PATCH 1378/1635] wil6210: set ip_summed to CHECKSUM_UNNECESSARY if no error found In EDMA, checksum was not set to CHECKSUM_UNNECESSARY when no errors were reported from HW, causing checksum to be calculated by network stack. Change-Id: I4847ddbf1dcb5151fbbd4f12ce467096e839a8c5 Signed-off-by: Alexei Avshalom Lazar --- drivers/net/wireless/ath/wil6210/txrx_edma.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/wil6210/txrx_edma.c b/drivers/net/wireless/ath/wil6210/txrx_edma.c index dca1589baf6c..11d6c9277e4d 100644 --- a/drivers/net/wireless/ath/wil6210/txrx_edma.c +++ b/drivers/net/wireless/ath/wil6210/txrx_edma.c @@ -848,8 +848,10 @@ static int wil_rx_edma_check_errors(struct wil6210_priv *wil, void *msg, int l4_rx_status; error = wil_rx_status_get_error(msg); - if (!error) + if (!error) { + skb->ip_summed = CHECKSUM_UNNECESSARY; return 0; + } l2_rx_status = wil_rx_status_get_l2_rx_status(msg); if (l2_rx_status != 0) { -- GitLab From f88175ac878de7582451ca8d252532e6767488b8 Mon Sep 17 00:00:00 2001 From: Konstantin Dorfman Date: Tue, 1 May 2018 17:26:58 +0300 Subject: [PATCH 1379/1635] soc: qcom: spcom: add kernel-pil support for SPU Add an API to userspace that supports SPU PIL. This API restart SPU. Change-Id: I934dec53a931e3b97092892b7f1f80599355f961 Signed-off-by: Kineret Berger Signed-off-by: Konstantin Dorfman --- drivers/soc/qcom/spcom.c | 29 ++++++++++++++++++++++++++++- include/uapi/linux/spcom.h | 3 +++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/drivers/soc/qcom/spcom.c b/drivers/soc/qcom/spcom.c index 5394445ecfc4..b1a5374675bd 100644 --- a/drivers/soc/qcom/spcom.c +++ b/drivers/soc/qcom/spcom.c @@ -68,6 +68,7 @@ #include #include #include +#include /** * Request buffer size. @@ -521,6 +522,28 @@ static int spcom_handle_create_channel_command(void *cmd_buf, int cmd_size) return ret; } +/** + * spcom_handle_restart_sp_command() - Handle Restart SP command from + * user space. + * + * Return: 0 on successful operation, negative value otherwise. + */ +static int spcom_handle_restart_sp_command(void) +{ + void *subsystem_get_retval = NULL; + + pr_err("restart - PIL FW loading process initiated\n"); + + subsystem_get_retval = subsystem_get("spss"); + if (!subsystem_get_retval) { + pr_err("restart - unable to trigger PIL process for FW loading\n"); + return -EINVAL; + } + + pr_err("restart - PIL FW loading process is complete\n"); + return 0; +} + /** * spcom_handle_send_command() - Handle send request/response from user space. * @@ -981,7 +1004,8 @@ static int spcom_handle_write(struct spcom_channel *ch, pr_debug("cmd_id [0x%x]\n", cmd_id); - if (!ch && cmd_id != SPCOM_CMD_CREATE_CHANNEL) { + if (!ch && cmd_id != SPCOM_CMD_CREATE_CHANNEL + && cmd_id != SPCOM_CMD_RESTART_SP) { pr_err("channel context is null\n"); return -EINVAL; } @@ -1002,6 +1026,9 @@ static int spcom_handle_write(struct spcom_channel *ch, case SPCOM_CMD_CREATE_CHANNEL: ret = spcom_handle_create_channel_command(buf, buf_size); break; + case SPCOM_CMD_RESTART_SP: + ret = spcom_handle_restart_sp_command(); + break; default: pr_err("Invalid Command Id [0x%x].\n", (int) cmd->cmd_id); ret = -EINVAL; diff --git a/include/uapi/linux/spcom.h b/include/uapi/linux/spcom.h index 22c6e6224540..e8469f438af0 100644 --- a/include/uapi/linux/spcom.h +++ b/include/uapi/linux/spcom.h @@ -57,6 +57,9 @@ enum spcom_cmd_id { SPCOM_CMD_UNLOCK_ION_BUF = 0x554C434B, /* "ULCK" = 0x4C4F434B */ SPCOM_CMD_FSSR = 0x46535352, /* "FSSR" = 0x46535352 */ SPCOM_CMD_CREATE_CHANNEL = 0x43524554, /* "CRET" = 0x43524554 */ +#define SPCOM_CMD_RESTART_SP \ + SPCOM_CMD_RESTART_SP + SPCOM_CMD_RESTART_SP = 0x52535452, /* "RSTR" = 0x52535452 */ }; /* -- GitLab From d085a5ea206e138f7dca0960ef02e964d1be2016 Mon Sep 17 00:00:00 2001 From: Shiraz Hashim Date: Thu, 3 May 2018 19:56:50 +0530 Subject: [PATCH 1380/1635] arm: mm: Fix build error due to variable input to BUILD_BUG_ON BUILD_BUG_ON() expands to a build error based on value of constant bool parameter passed to it. Presently, early_fixmap_shutdown while iterating through permanent_fixed_address and calling fix_to_virt on each of them, ends up passing non-constant value to the same. It is observed that with '-Oz' build option LLVM compiler fails to guess the right value to expand BUILD_BUG_ON and incorrectly raises following error. arch/arm/mm/mmu.o: In function `fix_to_virt': include/asm-generic/fixmap.h:31: undefined reference to `__compiletime_assert_31' make[2]: *** [vmlinux] Error 1 make[2]: Leaving directory `build/kobj' make[1]: *** [sub-make] Error 2 Modify early_fixmap_shutdown to bypass fix_to_virt and directly use __fixt_to_virt and validate boundaries, passing constant values to BUILD_BUG_ON. Change-Id: Ib0bd771ec0bdae0fbc00ed0c0df8f716cc0386b5 Signed-off-by: Shiraz Hashim --- arch/arm/mm/mmu.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c index fbe829011806..e9597cfa03cd 100644 --- a/arch/arm/mm/mmu.c +++ b/arch/arm/mm/mmu.c @@ -1708,11 +1708,13 @@ static void __init early_fixmap_shutdown(void) pmd_clear(fixmap_pmd(va)); local_flush_tlb_kernel_page(va); + BUILD_BUG_ON(__end_of_permanent_fixed_addresses > + __end_of_fixed_addresses); for (i = 0; i < __end_of_permanent_fixed_addresses; i++) { pte_t *pte; struct map_desc map; - map.virtual = fix_to_virt(i); + map.virtual = __fix_to_virt(i); pte = pte_offset_early_fixmap(pmd_off_k(map.virtual), map.virtual); /* Only i/o device mappings are supported ATM */ -- GitLab From 68f84175bc993064dd4269620176b28df105bd79 Mon Sep 17 00:00:00 2001 From: Taniya Das Date: Thu, 3 May 2018 23:04:15 +0530 Subject: [PATCH 1381/1635] ARM: dts: msm: Update the vdd-cx handle name for QCS405 The regulator handle has been updated and thus the GCC node needs to update the handle name. Change-Id: I80177abbe6dda08b758c19a55ec369c3644d3854 Signed-off-by: Taniya Das --- arch/arm64/boot/dts/qcom/qcs405.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/qcs405.dtsi b/arch/arm64/boot/dts/qcom/qcs405.dtsi index dbf4d04af696..f79c2e91b3a8 100644 --- a/arch/arm64/boot/dts/qcom/qcs405.dtsi +++ b/arch/arm64/boot/dts/qcom/qcs405.dtsi @@ -147,7 +147,7 @@ compatible = "qcom,gcc-qcs405", "syscon"; reg = <0x1800000 0x80000>; reg-names = "cc_base"; - vdd_cx-supply = <&pmd9655_s1_level>; + vdd_cx-supply = <&pms405_s1_level>; clocks = <&clock_rpmcc RPM_SMD_XO_CLK_SRC>; clock-names = "cxo"; #clock-cells = <1>; -- GitLab From 0a2677767c0b2045534e270357cad653a90b5986 Mon Sep 17 00:00:00 2001 From: Mohammed Javid Date: Thu, 15 Mar 2018 16:32:33 +0530 Subject: [PATCH 1382/1635] msm: ipa4: enable adpl for all UL consumers. HPS_REP_SEQ_TYPE needs to be set to 8 for all UL consumer pipes which require ADPL support. Otherwise ADPL packets will contain payload even when partial header is selected. Change-Id: Ic12168add4c48beb7e9cd75f3c69f5cfe767910a Acked-by: Chaitanya Pratapa Signed-off-by: Mohammed Javid --- drivers/platform/msm/ipa/ipa_v3/ipa_utils.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c index 78641106fef1..3f3aa92e1098 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c @@ -88,6 +88,8 @@ #define IPA_DPS_HPS_SEQ_TYPE_PKT_PROCESS_DEC_UCP 0x00000013 /* 2 Packet Processing pass + no decipher + uCP */ #define IPA_DPS_HPS_SEQ_TYPE_2ND_PKT_PROCESS_PASS_NO_DEC_UCP 0x00000004 +/* 2 Packet Processing pass + no decipher + uCP + HPS REP DMA Parser. */ +#define IPA_DPS_HPS_REP_SEQ_TYPE_2PKT_PROC_PASS_NO_DEC_UCP_DMAP 0x00000804 /* 2 Packet Processing pass + decipher + uCP */ #define IPA_DPS_HPS_SEQ_TYPE_2ND_PKT_PROCESS_PASS_DEC_UCP 0x00000015 /* Packet Processing + no decipher + no uCP */ @@ -1147,13 +1149,13 @@ static const struct ipa_ep_configuration ipa3_ep_mapping [IPA_4_0][IPA_CLIENT_WLAN1_PROD] = { true, IPA_v4_0_GROUP_UL_DL, true, - IPA_DPS_HPS_SEQ_TYPE_2ND_PKT_PROCESS_PASS_NO_DEC_UCP, + IPA_DPS_HPS_REP_SEQ_TYPE_2PKT_PROC_PASS_NO_DEC_UCP_DMAP, QMB_MASTER_SELECT_DDR, { 6, 2, 8, 16, IPA_EE_UC } }, [IPA_4_0][IPA_CLIENT_USB_PROD] = { true, IPA_v4_0_GROUP_UL_DL, true, - IPA_DPS_HPS_SEQ_TYPE_2ND_PKT_PROCESS_PASS_NO_DEC_UCP, + IPA_DPS_HPS_REP_SEQ_TYPE_2PKT_PROC_PASS_NO_DEC_UCP_DMAP, QMB_MASTER_SELECT_DDR, { 0, 8, 8, 16, IPA_EE_AP } }, [IPA_4_0][IPA_CLIENT_APPS_LAN_PROD] = { @@ -1165,7 +1167,7 @@ static const struct ipa_ep_configuration ipa3_ep_mapping [IPA_4_0][IPA_CLIENT_APPS_WAN_PROD] = { true, IPA_v4_0_GROUP_UL_DL, true, - IPA_DPS_HPS_SEQ_TYPE_2ND_PKT_PROCESS_PASS_NO_DEC_UCP, + IPA_DPS_HPS_REP_SEQ_TYPE_2PKT_PROC_PASS_NO_DEC_UCP_DMAP, QMB_MASTER_SELECT_DDR, { 2, 3, 16, 32, IPA_EE_AP } }, [IPA_4_0][IPA_CLIENT_APPS_CMD_PROD] = { @@ -1177,13 +1179,13 @@ static const struct ipa_ep_configuration ipa3_ep_mapping [IPA_4_0][IPA_CLIENT_ODU_PROD] = { true, IPA_v4_0_GROUP_UL_DL, true, - IPA_DPS_HPS_SEQ_TYPE_2ND_PKT_PROCESS_PASS_NO_DEC_UCP, + IPA_DPS_HPS_REP_SEQ_TYPE_2PKT_PROC_PASS_NO_DEC_UCP_DMAP, QMB_MASTER_SELECT_DDR, { 1, 0, 8, 16, IPA_EE_AP } }, [IPA_4_0][IPA_CLIENT_ETHERNET_PROD] = { true, IPA_v4_0_GROUP_UL_DL, true, - IPA_DPS_HPS_SEQ_TYPE_2ND_PKT_PROCESS_PASS_NO_DEC_UCP, + IPA_DPS_HPS_REP_SEQ_TYPE_2PKT_PROC_PASS_NO_DEC_UCP_DMAP, QMB_MASTER_SELECT_DDR, { 9, 0, 8, 16, IPA_EE_UC } }, [IPA_4_0][IPA_CLIENT_Q6_WAN_PROD] = { -- GitLab From 8549a863ce9e116ed060506e1f25f7780181a380 Mon Sep 17 00:00:00 2001 From: Narendra Muppalla Date: Fri, 13 Oct 2017 11:46:34 -0700 Subject: [PATCH 1383/1635] ARM: dts: msm: add resolution switch support for sim cmd panel on sm8150 This change adds resolution switch support for simulator single dsi command mode panel on sm8150 target. Change-Id: Ibf76133e6be839882e2039d1b929fc9dc5a0ba49 Signed-off-by: Narendra Muppalla --- .../boot/dts/qcom/dsi-panel-sim-cmd.dtsi | 144 ++++++++++++++++-- .../boot/dts/qcom/sm8150-sde-display.dtsi | 26 +++- 2 files changed, 154 insertions(+), 16 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-sim-cmd.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-sim-cmd.dtsi index 50da1bf4ab2f..c49583e0d92a 100644 --- a/arch/arm64/boot/dts/qcom/dsi-panel-sim-cmd.dtsi +++ b/arch/arm64/boot/dts/qcom/dsi-panel-sim-cmd.dtsi @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2015, 2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2015, 2017-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -49,26 +49,22 @@ qcom,mdss-dsi-display-timings { timing@0{ - qcom,mdss-dsi-panel-width = <640>; - qcom,mdss-dsi-panel-height = <480>; - qcom,mdss-dsi-h-front-porch = <20>; - qcom,mdss-dsi-h-back-porch = <20>; - qcom,mdss-dsi-h-pulse-width = <16>; + qcom,mdss-dsi-panel-width = <1440>; + qcom,mdss-dsi-panel-height = <2560>; + qcom,mdss-dsi-h-front-porch = <120>; + qcom,mdss-dsi-h-back-porch = <100>; + qcom,mdss-dsi-h-pulse-width = <40>; qcom,mdss-dsi-h-sync-skew = <0>; - qcom,mdss-dsi-v-back-porch = <16>; - qcom,mdss-dsi-v-front-porch = <4>; - qcom,mdss-dsi-v-pulse-width = <1>; + qcom,mdss-dsi-v-back-porch = <100>; + qcom,mdss-dsi-v-front-porch = <100>; + qcom,mdss-dsi-v-pulse-width = <40>; qcom,mdss-dsi-h-left-border = <0>; qcom,mdss-dsi-h-right-border = <0>; qcom,mdss-dsi-v-top-border = <0>; qcom,mdss-dsi-v-bottom-border = <0>; - qcom,mdss-dsi-h-sync-pulse = <0>; qcom,mdss-dsi-panel-framerate = <60>; - qcom,mdss-dsi-hor-line-idle = <0 40 256>, - <40 120 128>, - <120 240 64>; qcom,mdss-dsi-panel-timings = - [cd 32 22 00 60 64 26 34 29 03 04 00]; + [00 21 09 09 24 23 08 08 08 03 04 00]; qcom,mdss-dsi-on-command = [29 01 00 00 00 00 02 b0 03 05 01 00 00 0a 00 01 00 @@ -98,6 +94,126 @@ [05 01 00 00 32 00 02 28 00 05 01 00 00 78 00 02 10 00]; qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + + qcom,compression-mode = "dsc"; + qcom,mdss-dsc-slice-height = <40>; + qcom,mdss-dsc-slice-width = <720>; + qcom,mdss-dsc-slice-per-pkt = <1>; + qcom,mdss-dsc-bit-per-component = <8>; + qcom,mdss-dsc-bit-per-pixel = <8>; + qcom,mdss-dsc-block-prediction-enable; + }; + + timing@1{ + qcom,mdss-dsi-panel-width = <1080>; + qcom,mdss-dsi-panel-height = <1920>; + qcom,mdss-dsi-h-front-porch = <120>; + qcom,mdss-dsi-h-back-porch = <460>; + qcom,mdss-dsi-h-pulse-width = <40>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <100>; + qcom,mdss-dsi-v-front-porch = <740>; + qcom,mdss-dsi-v-pulse-width = <40>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-panel-timings = + [00 21 09 09 24 23 08 08 08 03 04 00]; + qcom,mdss-dsi-on-command = + [29 01 00 00 00 00 02 b0 03 + 05 01 00 00 0a 00 01 00 + /* Soft reset, wait 10ms */ + 15 01 00 00 0a 00 02 3a 77 + /* Set Pixel format (24 bpp) */ + 39 01 00 00 0a 00 05 2a 00 00 04 ff + /* Set Column address */ + 39 01 00 00 0a 00 05 2b 00 00 05 9f + /* Set page address */ + 15 01 00 00 0a 00 02 35 00 + /* Set tear on */ + 39 01 00 00 0a 00 03 44 00 00 + /* Set tear scan line */ + 15 01 00 00 0a 00 02 51 ff + /* write display brightness */ + 15 01 00 00 0a 00 02 53 24 + /* write control brightness */ + 15 01 00 00 0a 00 02 55 00 + /* CABC brightness */ + 05 01 00 00 78 00 01 11 + /* exit sleep mode, wait 120ms */ + 05 01 00 00 10 00 01 29]; + /* Set display on, wait 16ms */ + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command = + [05 01 00 00 32 00 02 28 00 + 05 01 00 00 78 00 02 10 00]; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + + qcom,compression-mode = "dsc"; + qcom,mdss-dsc-slice-height = <40>; + qcom,mdss-dsc-slice-width = <540>; + qcom,mdss-dsc-slice-per-pkt = <1>; + qcom,mdss-dsc-bit-per-component = <8>; + qcom,mdss-dsc-bit-per-pixel = <8>; + qcom,mdss-dsc-block-prediction-enable; + }; + + timing@2{ + qcom,mdss-dsi-panel-width = <720>; + qcom,mdss-dsi-panel-height = <1280>; + qcom,mdss-dsi-h-front-porch = <100>; + qcom,mdss-dsi-h-back-porch = <840>; + qcom,mdss-dsi-h-pulse-width = <40>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <100>; + qcom,mdss-dsi-v-front-porch = <1380>; + qcom,mdss-dsi-v-pulse-width = <40>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-panel-timings = + [00 21 09 09 24 23 08 08 08 03 04 00]; + qcom,mdss-dsi-on-command = + [29 01 00 00 00 00 02 b0 03 + 05 01 00 00 0a 00 01 00 + /* Soft reset, wait 10ms */ + 15 01 00 00 0a 00 02 3a 77 + /* Set Pixel format (24 bpp) */ + 39 01 00 00 0a 00 05 2a 00 00 04 ff + /* Set Column address */ + 39 01 00 00 0a 00 05 2b 00 00 05 9f + /* Set page address */ + 15 01 00 00 0a 00 02 35 00 + /* Set tear on */ + 39 01 00 00 0a 00 03 44 00 00 + /* Set tear scan line */ + 15 01 00 00 0a 00 02 51 ff + /* write display brightness */ + 15 01 00 00 0a 00 02 53 24 + /* write control brightness */ + 15 01 00 00 0a 00 02 55 00 + /* CABC brightness */ + 05 01 00 00 78 00 01 11 + /* exit sleep mode, wait 120ms */ + 05 01 00 00 10 00 01 29]; + /* Set display on, wait 16ms */ + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command = + [05 01 00 00 32 00 02 28 00 + 05 01 00 00 78 00 02 10 00]; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + + qcom,compression-mode = "dsc"; + qcom,mdss-dsc-slice-height = <40>; + qcom,mdss-dsc-slice-width = <360>; + qcom,mdss-dsc-slice-per-pkt = <1>; + qcom,mdss-dsc-bit-per-component = <8>; + qcom,mdss-dsc-bit-per-pixel = <8>; + qcom,mdss-dsc-block-prediction-enable; }; }; }; diff --git a/arch/arm64/boot/dts/qcom/sm8150-sde-display.dtsi b/arch/arm64/boot/dts/qcom/sm8150-sde-display.dtsi index a2c397c7eb0d..696b70cae304 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-sde-display.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-sde-display.dtsi @@ -571,8 +571,30 @@ qcom,mdss-dsi-panel-phy-timings = [00 1c 08 07 23 22 07 07 05 03 04 00 18 17]; qcom,display-topology = <1 0 1>, - <2 0 1>; - qcom,default-topology-index = <0>; + <2 2 1>; + qcom,default-topology-index = <1>; + qcom,panel-roi-alignment = <720 40 720 40 720 40>; + qcom,partial-update-enabled = "single_roi"; + }; + + timing@1{ + qcom,mdss-dsi-panel-phy-timings = [00 1c 08 07 23 22 07 + 07 05 03 04 00 18 17]; + qcom,display-topology = <1 0 1>, + <2 2 1>; + qcom,default-topology-index = <1>; + qcom,panel-roi-alignment = <540 40 540 40 540 40>; + qcom,partial-update-enabled = "single_roi"; + }; + + timing@2{ + qcom,mdss-dsi-panel-phy-timings = [00 1c 08 07 23 22 07 + 07 05 03 04 00 18 17]; + qcom,display-topology = <1 0 1>, + <2 2 1>; + qcom,default-topology-index = <1>; + qcom,panel-roi-alignment = <360 40 360 40 360 40>; + qcom,partial-update-enabled = "single_roi"; }; }; }; -- GitLab From 932de6ff4bd95b1bf55d1a52ec7d0e0eb71ccdfc Mon Sep 17 00:00:00 2001 From: Hans Chang Date: Tue, 1 May 2018 14:17:37 -0700 Subject: [PATCH 1384/1635] ARM:dts:msm: add defconfig for SM8150 automotive Create defconfig for SM8150 automtoive ADP Change-Id: Ie2cec249aa656cd53390e5f9f0f40aea0759d524 Signed-off-by: Hans Chang --- arch/arm64/configs/sm8150-auto-perf_defconfig | 613 ++++++++++++++++ arch/arm64/configs/sm8150-auto_defconfig | 693 ++++++++++++++++++ 2 files changed, 1306 insertions(+) create mode 100644 arch/arm64/configs/sm8150-auto-perf_defconfig create mode 100644 arch/arm64/configs/sm8150-auto_defconfig diff --git a/arch/arm64/configs/sm8150-auto-perf_defconfig b/arch/arm64/configs/sm8150-auto-perf_defconfig new file mode 100644 index 000000000000..bd4239b26df3 --- /dev/null +++ b/arch/arm64/configs/sm8150-auto-perf_defconfig @@ -0,0 +1,613 @@ +CONFIG_LOCALVERSION="-perf" +# CONFIG_LOCALVERSION_AUTO is not set +CONFIG_AUDIT=y +# CONFIG_AUDITSYSCALL is not set +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_IRQ_TIME_ACCOUNTING=y +CONFIG_SCHED_WALT=y +CONFIG_TASKSTATS=y +CONFIG_TASK_XACCT=y +CONFIG_TASK_IO_ACCOUNTING=y +CONFIG_RCU_EXPERT=y +CONFIG_RCU_FAST_NO_HZ=y +CONFIG_RCU_NOCB_CPU=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_LOG_CPU_MAX_BUF_SHIFT=17 +CONFIG_MEMCG=y +CONFIG_MEMCG_SWAP=y +CONFIG_RT_GROUP_SCHED=y +CONFIG_CGROUP_FREEZER=y +CONFIG_CPUSETS=y +CONFIG_CGROUP_CPUACCT=y +CONFIG_CGROUP_BPF=y +CONFIG_SCHED_CORE_CTL=y +CONFIG_NAMESPACES=y +# CONFIG_UTS_NS is not set +# CONFIG_PID_NS is not set +CONFIG_SCHED_AUTOGROUP=y +CONFIG_SCHED_TUNE=y +CONFIG_DEFAULT_USE_ENERGY_AWARE=y +CONFIG_BLK_DEV_INITRD=y +# CONFIG_RD_XZ is not set +# CONFIG_RD_LZO is not set +# CONFIG_RD_LZ4 is not set +CONFIG_KALLSYMS_ALL=y +CONFIG_BPF_SYSCALL=y +# CONFIG_MEMBARRIER is not set +CONFIG_EMBEDDED=y +# CONFIG_SLUB_DEBUG is not set +# CONFIG_COMPAT_BRK is not set +CONFIG_SLAB_FREELIST_RANDOM=y +CONFIG_SLAB_FREELIST_HARDENED=y +CONFIG_PROFILING=y +CONFIG_CC_STACKPROTECTOR_STRONG=y +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +CONFIG_MODULE_FORCE_UNLOAD=y +CONFIG_MODVERSIONS=y +CONFIG_MODULE_SIG=y +CONFIG_MODULE_SIG_FORCE=y +CONFIG_MODULE_SIG_SHA512=y +CONFIG_PARTITION_ADVANCED=y +CONFIG_ARCH_QCOM=y +CONFIG_ARCH_SM8150=y +CONFIG_PCI=y +CONFIG_PCI_MSM=y +CONFIG_SCHED_MC=y +CONFIG_NR_CPUS=8 +CONFIG_PREEMPT=y +CONFIG_HZ_100=y +CONFIG_CMA=y +CONFIG_ZSMALLOC=y +CONFIG_SECCOMP=y +# CONFIG_UNMAP_KERNEL_AT_EL0 is not set +# CONFIG_HARDEN_BRANCH_PREDICTOR is not set +CONFIG_ARMV8_DEPRECATED=y +CONFIG_SWP_EMULATION=y +CONFIG_CP15_BARRIER_EMULATION=y +CONFIG_SETEND_EMULATION=y +# CONFIG_ARM64_VHE is not set +CONFIG_RANDOMIZE_BASE=y +# CONFIG_EFI is not set +CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE=y +# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set +CONFIG_COMPAT=y +CONFIG_PM_AUTOSLEEP=y +CONFIG_PM_WAKELOCKS=y +CONFIG_PM_WAKELOCKS_LIMIT=0 +# CONFIG_PM_WAKELOCKS_GC is not set +CONFIG_CPU_IDLE=y +CONFIG_ARM_CPUIDLE=y +CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_GOV_POWERSAVE=y +CONFIG_CPU_FREQ_GOV_USERSPACE=y +CONFIG_CPU_FREQ_GOV_ONDEMAND=y +CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y +CONFIG_CPU_BOOST=y +CONFIG_CPU_FREQ_GOV_SCHEDUTIL=y +CONFIG_NET=y +CONFIG_PACKET=y +CONFIG_UNIX=y +CONFIG_XFRM_USER=y +CONFIG_XFRM_STATISTICS=y +CONFIG_NET_KEY=y +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_ADVANCED_ROUTER=y +CONFIG_IP_MULTIPLE_TABLES=y +CONFIG_IP_ROUTE_VERBOSE=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +CONFIG_INET_AH=y +CONFIG_INET_ESP=y +CONFIG_INET_IPCOMP=y +CONFIG_INET_DIAG_DESTROY=y +CONFIG_IPV6_ROUTER_PREF=y +CONFIG_IPV6_ROUTE_INFO=y +CONFIG_IPV6_OPTIMISTIC_DAD=y +CONFIG_INET6_AH=y +CONFIG_INET6_ESP=y +CONFIG_INET6_IPCOMP=y +CONFIG_IPV6_MIP6=y +CONFIG_IPV6_MULTIPLE_TABLES=y +CONFIG_IPV6_SUBTREES=y +CONFIG_NETFILTER=y +CONFIG_NF_CONNTRACK=y +CONFIG_NF_CONNTRACK_SECMARK=y +CONFIG_NF_CONNTRACK_EVENTS=y +CONFIG_NF_CONNTRACK_AMANDA=y +CONFIG_NF_CONNTRACK_FTP=y +CONFIG_NF_CONNTRACK_H323=y +CONFIG_NF_CONNTRACK_IRC=y +CONFIG_NF_CONNTRACK_NETBIOS_NS=y +CONFIG_NF_CONNTRACK_PPTP=y +CONFIG_NF_CONNTRACK_SANE=y +CONFIG_NF_CONNTRACK_TFTP=y +CONFIG_NF_CT_NETLINK=y +CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y +CONFIG_NETFILTER_XT_TARGET_CONNMARK=y +CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=y +CONFIG_NETFILTER_XT_TARGET_IDLETIMER=y +CONFIG_NETFILTER_XT_TARGET_HARDIDLETIMER=y +CONFIG_NETFILTER_XT_TARGET_LOG=y +CONFIG_NETFILTER_XT_TARGET_MARK=y +CONFIG_NETFILTER_XT_TARGET_NFLOG=y +CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y +CONFIG_NETFILTER_XT_TARGET_NOTRACK=y +CONFIG_NETFILTER_XT_TARGET_TEE=y +CONFIG_NETFILTER_XT_TARGET_TPROXY=y +CONFIG_NETFILTER_XT_TARGET_TRACE=y +CONFIG_NETFILTER_XT_TARGET_SECMARK=y +CONFIG_NETFILTER_XT_TARGET_TCPMSS=y +CONFIG_NETFILTER_XT_MATCH_COMMENT=y +CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y +CONFIG_NETFILTER_XT_MATCH_CONNMARK=y +CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y +CONFIG_NETFILTER_XT_MATCH_DSCP=y +CONFIG_NETFILTER_XT_MATCH_ESP=y +CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y +CONFIG_NETFILTER_XT_MATCH_HELPER=y +CONFIG_NETFILTER_XT_MATCH_IPRANGE=y +# CONFIG_NETFILTER_XT_MATCH_L2TP is not set +CONFIG_NETFILTER_XT_MATCH_LENGTH=y +CONFIG_NETFILTER_XT_MATCH_LIMIT=y +CONFIG_NETFILTER_XT_MATCH_MAC=y +CONFIG_NETFILTER_XT_MATCH_MARK=y +CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y +CONFIG_NETFILTER_XT_MATCH_POLICY=y +CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y +CONFIG_NETFILTER_XT_MATCH_QTAGUID=y +CONFIG_NETFILTER_XT_MATCH_QUOTA=y +CONFIG_NETFILTER_XT_MATCH_QUOTA2=y +CONFIG_NETFILTER_XT_MATCH_SOCKET=y +CONFIG_NETFILTER_XT_MATCH_STATE=y +CONFIG_NETFILTER_XT_MATCH_STATISTIC=y +CONFIG_NETFILTER_XT_MATCH_STRING=y +CONFIG_NETFILTER_XT_MATCH_TIME=y +CONFIG_NETFILTER_XT_MATCH_U32=y +CONFIG_NF_CONNTRACK_IPV4=y +CONFIG_NF_SOCKET_IPV4=y +CONFIG_IP_NF_IPTABLES=y +CONFIG_IP_NF_MATCH_AH=y +CONFIG_IP_NF_MATCH_ECN=y +CONFIG_IP_NF_MATCH_RPFILTER=y +CONFIG_IP_NF_MATCH_TTL=y +CONFIG_IP_NF_FILTER=y +CONFIG_IP_NF_TARGET_REJECT=y +CONFIG_IP_NF_NAT=y +CONFIG_IP_NF_TARGET_MASQUERADE=y +CONFIG_IP_NF_TARGET_NETMAP=y +CONFIG_IP_NF_TARGET_REDIRECT=y +CONFIG_IP_NF_MANGLE=y +CONFIG_IP_NF_RAW=y +CONFIG_IP_NF_SECURITY=y +CONFIG_IP_NF_ARPTABLES=y +CONFIG_IP_NF_ARPFILTER=y +CONFIG_IP_NF_ARP_MANGLE=y +CONFIG_NF_CONNTRACK_IPV6=y +CONFIG_NF_SOCKET_IPV6=y +CONFIG_IP6_NF_IPTABLES=y +CONFIG_IP6_NF_MATCH_RPFILTER=y +CONFIG_IP6_NF_FILTER=y +CONFIG_IP6_NF_TARGET_REJECT=y +CONFIG_IP6_NF_MANGLE=y +CONFIG_IP6_NF_RAW=y +CONFIG_BRIDGE_NF_EBTABLES=y +CONFIG_BRIDGE_EBT_BROUTE=y +CONFIG_L2TP=y +CONFIG_L2TP_V3=y +CONFIG_L2TP_IP=y +CONFIG_L2TP_ETH=y +CONFIG_BRIDGE=y +CONFIG_NET_SCHED=y +CONFIG_NET_SCH_HTB=y +CONFIG_NET_SCH_PRIO=y +CONFIG_NET_SCH_MULTIQ=y +CONFIG_NET_SCH_INGRESS=y +CONFIG_NET_CLS_FW=y +CONFIG_NET_CLS_U32=y +CONFIG_CLS_U32_MARK=y +CONFIG_NET_CLS_FLOW=y +CONFIG_NET_EMATCH=y +CONFIG_NET_EMATCH_CMP=y +CONFIG_NET_EMATCH_NBYTE=y +CONFIG_NET_EMATCH_U32=y +CONFIG_NET_EMATCH_META=y +CONFIG_NET_EMATCH_TEXT=y +CONFIG_NET_CLS_ACT=y +CONFIG_NET_ACT_GACT=y +CONFIG_NET_ACT_MIRRED=y +CONFIG_NET_ACT_SKBEDIT=y +CONFIG_QRTR=y +CONFIG_QRTR_SMD=y +CONFIG_QRTR_MHI=y +CONFIG_RMNET_DATA=y +CONFIG_RMNET_DATA_FC=y +CONFIG_RMNET_DATA_DEBUG_PKT=y +CONFIG_SOCKEV_NLMCAST=y +CONFIG_BT=y +CONFIG_MSM_BT_POWER=y +CONFIG_CFG80211=y +CONFIG_CFG80211_INTERNAL_REGDB=y +CONFIG_RFKILL=y +CONFIG_NFC_NQ=y +CONFIG_FW_LOADER_USER_HELPER_FALLBACK=y +CONFIG_REGMAP_ALLOW_WRITE_DEBUGFS=y +CONFIG_DMA_CMA=y +CONFIG_MHI_BUS=y +CONFIG_MHI_QCOM=y +CONFIG_MHI_NETDEV=y +CONFIG_MHI_UCI=y +CONFIG_ZRAM=y +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=8192 +CONFIG_QSEECOM=y +CONFIG_UID_SYS_STATS=y +CONFIG_MEMORY_STATE_TIME=y +CONFIG_SCSI=y +CONFIG_BLK_DEV_SD=y +CONFIG_CHR_DEV_SG=y +CONFIG_CHR_DEV_SCH=y +CONFIG_SCSI_CONSTANTS=y +CONFIG_SCSI_SCAN_ASYNC=y +CONFIG_SCSI_UFSHCD=y +CONFIG_SCSI_UFSHCD_PLATFORM=y +CONFIG_SCSI_UFS_QCOM=y +CONFIG_MD=y +CONFIG_BLK_DEV_DM=y +CONFIG_DM_UEVENT=y +CONFIG_DM_VERITY=y +CONFIG_DM_VERITY_FEC=y +CONFIG_NETDEVICES=y +CONFIG_BONDING=y +CONFIG_DUMMY=y +CONFIG_TUN=y +CONFIG_SKY2=y +CONFIG_RMNET=y +CONFIG_SMSC911X=y +CONFIG_PPP=y +CONFIG_PPP_BSDCOMP=y +CONFIG_PPP_DEFLATE=y +CONFIG_PPP_FILTER=y +CONFIG_PPP_MPPE=y +CONFIG_PPP_MULTILINK=y +CONFIG_PPPOE=y +CONFIG_PPPOL2TP=y +CONFIG_PPPOLAC=y +CONFIG_PPPOPNS=y +CONFIG_PPP_ASYNC=y +CONFIG_PPP_SYNC_TTY=y +CONFIG_USB_USBNET=y +CONFIG_WIL6210=m +CONFIG_WCNSS_MEM_PRE_ALLOC=y +CONFIG_CLD_LL_CORE=y +CONFIG_INPUT_EVDEV=y +CONFIG_KEYBOARD_GPIO=y +# CONFIG_INPUT_MOUSE is not set +CONFIG_INPUT_TOUCHSCREEN=y +CONFIG_TOUCHSCREEN_ST=y +CONFIG_INPUT_MISC=y +CONFIG_INPUT_HBTP_INPUT=y +CONFIG_INPUT_QPNP_POWER_ON=y +CONFIG_INPUT_UINPUT=y +# CONFIG_SERIO_SERPORT is not set +# CONFIG_VT is not set +# CONFIG_LEGACY_PTYS is not set +# CONFIG_DEVMEM is not set +CONFIG_SERIAL_MSM_GENI=y +CONFIG_HW_RANDOM=y +CONFIG_HW_RANDOM_MSM_LEGACY=y +CONFIG_DIAG_CHAR=y +CONFIG_MSM_FASTCVPD=y +CONFIG_MSM_ADSPRPC=y +CONFIG_I2C_CHARDEV=y +CONFIG_I2C_QCOM_GENI=y +CONFIG_SPI=y +CONFIG_SPI_QCOM_GENI=y +CONFIG_SPI_SPIDEV=y +CONFIG_SPMI=y +CONFIG_SPMI_SIMULATOR=y +CONFIG_PM855_PMIC_SIMULATOR=y +CONFIG_PM855B_PMIC_SIMULATOR=y +CONFIG_PM855L_PMIC_SIMULATOR=y +CONFIG_SLIMBUS_MSM_NGD=y +CONFIG_PINCTRL_QCOM_SPMI_PMIC=y +CONFIG_PINCTRL_SM8150=y +CONFIG_GPIO_SYSFS=y +CONFIG_POWER_RESET_QCOM=y +CONFIG_QCOM_DLOAD_MODE=y +CONFIG_POWER_RESET_XGENE=y +CONFIG_POWER_RESET_SYSCON=y +CONFIG_QPNP_FG_GEN4=y +CONFIG_QPNP_SMB5=y +CONFIG_THERMAL=y +CONFIG_THERMAL_WRITABLE_TRIPS=y +CONFIG_THERMAL_GOV_USER_SPACE=y +CONFIG_THERMAL_GOV_LOW_LIMITS=y +CONFIG_CPU_THERMAL=y +CONFIG_DEVFREQ_THERMAL=y +CONFIG_QCOM_SPMI_TEMP_ALARM=y +CONFIG_THERMAL_TSENS=y +CONFIG_QTI_THERMAL_LIMITS_DCVS=y +CONFIG_QTI_VIRTUAL_SENSOR=y +CONFIG_QTI_AOP_REG_COOLING_DEVICE=y +CONFIG_QTI_QMI_COOLING_DEVICE=y +CONFIG_REGULATOR_COOLING_DEVICE=y +CONFIG_QTI_BCL_PMIC5=y +CONFIG_QTI_BCL_SOC_DRIVER=y +CONFIG_QTI_ADC_TM=y +CONFIG_MFD_SPMI_PMIC=y +CONFIG_REGULATOR_FIXED_VOLTAGE=y +CONFIG_REGULATOR_PROXY_CONSUMER=y +CONFIG_REGULATOR_QPNP_LCDB=y +CONFIG_REGULATOR_REFGEN=y +CONFIG_REGULATOR_RPMH=y +CONFIG_REGULATOR_STUB=y +CONFIG_MEDIA_SUPPORT=y +CONFIG_MEDIA_CAMERA_SUPPORT=y +CONFIG_MEDIA_CONTROLLER=y +CONFIG_VIDEO_V4L2_SUBDEV_API=y +CONFIG_VIDEO_ADV_DEBUG=y +CONFIG_VIDEO_FIXED_MINOR_RANGES=y +CONFIG_V4L_PLATFORM_DRIVERS=y +CONFIG_SPECTRA_CAMERA=y +CONFIG_MSM_VIDC_V4L2=y +CONFIG_MSM_VIDC_GOVERNORS=y +CONFIG_MSM_SDE_ROTATOR=y +CONFIG_MSM_SDE_ROTATOR_EVTLOG_DEBUG=y +CONFIG_MSM_NPU=y +CONFIG_DRM=y +CONFIG_DRM_MSM_REGISTER_LOGGING=y +CONFIG_DRM_SDE_EVTLOG_DEBUG=y +CONFIG_DRM_SDE_RSC=y +CONFIG_FB_ARMCLCD=y +CONFIG_BACKLIGHT_QCOM_SPMI_WLED=y +CONFIG_LOGO=y +# CONFIG_LOGO_LINUX_MONO is not set +# CONFIG_LOGO_LINUX_VGA16 is not set +CONFIG_SOUND=y +CONFIG_SND=y +CONFIG_SND_DYNAMIC_MINORS=y +CONFIG_SND_USB_AUDIO=y +CONFIG_SND_USB_AUDIO_QMI=y +CONFIG_SND_SOC=y +CONFIG_UHID=y +CONFIG_HID_APPLE=y +CONFIG_HID_ELECOM=y +CONFIG_HID_MAGICMOUSE=y +CONFIG_HID_MICROSOFT=y +CONFIG_HID_MULTITOUCH=y +CONFIG_HID_PLANTRONICS=y +CONFIG_USB=y +CONFIG_USB_ANNOUNCE_NEW_DEVICES=y +CONFIG_USB_XHCI_HCD=y +CONFIG_USB_EHCI_HCD=y +CONFIG_USB_EHCI_HCD_PLATFORM=y +CONFIG_USB_OHCI_HCD=y +CONFIG_USB_OHCI_HCD_PLATFORM=y +CONFIG_USB_STORAGE=y +CONFIG_USB_DWC3=y +CONFIG_USB_DWC3_MSM=y +CONFIG_USB_ISP1760=y +CONFIG_USB_ISP1760_HOST_ROLE=y +CONFIG_NOP_USB_XCEIV=y +CONFIG_USB_QCOM_EMU_PHY=y +CONFIG_USB_MSM_SSPHY_QMP=y +CONFIG_MSM_HSUSB_PHY=y +CONFIG_DUAL_ROLE_USB_INTF=y +CONFIG_USB_GADGET=y +CONFIG_USB_GADGET_VBUS_DRAW=900 +CONFIG_USB_CONFIGFS=y +CONFIG_USB_CONFIGFS_NCM=y +CONFIG_USB_CONFIGFS_MASS_STORAGE=y +CONFIG_USB_CONFIGFS_F_FS=y +CONFIG_USB_CONFIGFS_F_MTP=y +CONFIG_USB_CONFIGFS_F_PTP=y +CONFIG_USB_CONFIGFS_F_ACC=y +CONFIG_USB_CONFIGFS_F_AUDIO_SRC=y +CONFIG_USB_CONFIGFS_UEVENT=y +CONFIG_USB_CONFIGFS_F_MIDI=y +CONFIG_USB_CONFIGFS_F_HID=y +CONFIG_USB_CONFIGFS_F_DIAG=y +CONFIG_USB_CONFIGFS_F_CDEV=y +CONFIG_USB_CONFIGFS_F_CCID=y +CONFIG_USB_CONFIGFS_F_GSI=y +CONFIG_USB_CONFIGFS_F_QDSS=y +CONFIG_USB_PD_POLICY=y +CONFIG_QPNP_USB_PDPHY=y +CONFIG_MMC=y +CONFIG_MMC_PERF_PROFILING=y +CONFIG_MMC_BLOCK_MINORS=32 +CONFIG_MMC_BLOCK_DEFERRED_RESUME=y +CONFIG_MMC_TEST=y +CONFIG_MMC_PARANOID_SD_INIT=y +CONFIG_MMC_CLKGATE=y +CONFIG_MMC_SDHCI=y +CONFIG_MMC_SDHCI_PLTFM=y +CONFIG_MMC_SDHCI_MSM=y +CONFIG_NEW_LEDS=y +CONFIG_LEDS_CLASS=y +CONFIG_LEDS_QPNP_FLASH_V2=y +CONFIG_LEDS_QPNP_HAPTICS=y +CONFIG_LEDS_QTI_TRI_LED=y +CONFIG_LEDS_TRIGGER_TIMER=y +CONFIG_EDAC=y +CONFIG_EDAC_KRYO_ARM64=y +CONFIG_EDAC_KRYO_ARM64_PANIC_ON_CE=y +CONFIG_EDAC_KRYO_ARM64_PANIC_ON_UE=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_DRV_QPNP=y +CONFIG_DMADEVICES=y +CONFIG_QCOM_GPI_DMA=y +CONFIG_UIO=y +CONFIG_UIO_MSM_SHAREDMEM=y +CONFIG_STAGING=y +CONFIG_ASHMEM=y +CONFIG_ION=y +CONFIG_QCOM_GENI_SE=y +CONFIG_QPNP_REVID=y +CONFIG_SPS=y +CONFIG_SPS_SUPPORT_NDP_BAM=y +CONFIG_USB_BAM=y +CONFIG_IPA3=y +CONFIG_IPA_WDI_UNIFIED_API=y +CONFIG_RMNET_IPA3=y +CONFIG_RNDIS_IPA=y +CONFIG_IPA_UT=y +CONFIG_MSM_11AD=m +CONFIG_QCOM_MDSS_PLL=y +CONFIG_SPMI_PMIC_CLKDIV=y +CONFIG_MSM_CLK_AOP_QMP=y +CONFIG_MSM_GCC_SM8150=y +CONFIG_MSM_NPUCC_SM8150=y +CONFIG_MSM_VIDEOCC_SM8150=y +CONFIG_MSM_CAMCC_SM8150=y +CONFIG_CLOCK_CPU_OSM=y +CONFIG_MSM_DISPCC_SM8150=y +CONFIG_MSM_DEBUGCC_SM8150=y +CONFIG_MSM_CLK_RPMH=y +CONFIG_MSM_GPUCC_SM8150=y +CONFIG_HWSPINLOCK=y +CONFIG_HWSPINLOCK_QCOM=y +CONFIG_QCOM_APCS_IPC=y +CONFIG_MSM_QMP=y +CONFIG_IOMMU_IO_PGTABLE_FAST=y +CONFIG_ARM_SMMU=y +CONFIG_QCOM_LAZY_MAPPING=y +CONFIG_IOMMU_DEBUG=y +CONFIG_IOMMU_DEBUG_TRACKING=y +CONFIG_IOMMU_TESTS=y +CONFIG_RPMSG_CHAR=y +CONFIG_RPMSG_QCOM_GLINK_SMEM=y +CONFIG_RPMSG_QCOM_GLINK_SPSS=y +CONFIG_QCOM_CPUSS_DUMP=y +CONFIG_QCOM_RUN_QUEUE_STATS=y +CONFIG_QCOM_LLCC=y +CONFIG_QCOM_SM8150_LLCC=y +CONFIG_QCOM_QMI_HELPERS=y +CONFIG_QCOM_SMEM=y +CONFIG_QCOM_MEMORY_DUMP_V2=y +CONFIG_QCOM_WATCHDOG_V2=y +CONFIG_QCOM_FORCE_WDOG_BITE_ON_PANIC=y +CONFIG_QCOM_SMP2P=y +CONFIG_MSM_SERVICE_LOCATOR=y +CONFIG_MSM_SERVICE_NOTIFIER=y +CONFIG_MSM_SUBSYSTEM_RESTART=y +CONFIG_MSM_PIL=y +CONFIG_MSM_SYSMON_QMI_COMM=y +CONFIG_MSM_PIL_SSR_GENERIC=y +CONFIG_MSM_BOOT_STATS=y +CONFIG_QCOM_DCC_V2=y +CONFIG_QCOM_SECURE_BUFFER=y +CONFIG_ICNSS=y +CONFIG_ICNSS_QMI=y +CONFIG_QCOM_EUD=y +CONFIG_QCOM_BUS_SCALING=y +CONFIG_QCOM_BUS_CONFIG_RPMH=y +CONFIG_QCOM_COMMAND_DB=y +CONFIG_QCOM_EARLY_RANDOM=y +CONFIG_MSM_SPSS_UTILS=y +CONFIG_MSM_SPCOM=y +CONFIG_QTI_RPMH_API=y +CONFIG_QSEE_IPC_IRQ_BRIDGE=y +CONFIG_QCOM_GLINK=y +CONFIG_QCOM_GLINK_PKT=y +CONFIG_QTI_RPM_STATS_LOG=y +CONFIG_MSM_CDSP_LOADER=y +CONFIG_QCOM_SMCINVOKE=y +CONFIG_MSM_EVENT_TIMER=y +CONFIG_MSM_PM=y +CONFIG_QCOM_FSA4480_I2C=y +CONFIG_MSM_PERFORMANCE=y +CONFIG_QMP_DEBUGFS_CLIENT=y +CONFIG_DEVFREQ_GOV_PASSIVE=y +CONFIG_QCOM_BIMC_BWMON=y +CONFIG_ARM_MEMLAT_MON=y +CONFIG_QCOMCCI_HWMON=y +CONFIG_QCOM_M4M_HWMON=y +CONFIG_DEVFREQ_GOV_QCOM_BW_HWMON=y +CONFIG_DEVFREQ_GOV_QCOM_CACHE_HWMON=y +CONFIG_DEVFREQ_GOV_MEMLAT=y +CONFIG_DEVFREQ_SIMPLE_DEV=y +CONFIG_QCOM_DEVFREQ_DEVBW=y +CONFIG_EXTCON_USB_GPIO=y +CONFIG_IIO=y +CONFIG_QCOM_SPMI_ADC5=y +CONFIG_PWM=y +CONFIG_PWM_QTI_LPG=y +CONFIG_QCOM_KGSL=y +CONFIG_ARM_GIC_V3_ACL=y +CONFIG_ARM_DSU_PMU=y +CONFIG_QCOM_LLCC_PMU=y +CONFIG_RAS=y +CONFIG_ANDROID=y +CONFIG_ANDROID_BINDER_IPC=y +CONFIG_NVMEM_SPMI_SDAM=y +CONFIG_SENSORS_SSC=y +CONFIG_ESOC=y +CONFIG_ESOC_DEV=y +CONFIG_ESOC_CLIENT=y +CONFIG_ESOC_MDM_4x=y +CONFIG_ESOC_MDM_DRV=y +CONFIG_ESOC_MDM_DBG_ENG=y +CONFIG_MSM_TZ_LOG=y +CONFIG_EXT2_FS=y +CONFIG_EXT2_FS_XATTR=y +CONFIG_EXT3_FS=y +CONFIG_EXT4_FS_SECURITY=y +CONFIG_EXT4_ENCRYPTION=y +CONFIG_QUOTA=y +CONFIG_QUOTA_NETLINK_INTERFACE=y +CONFIG_FUSE_FS=y +CONFIG_MSDOS_FS=y +CONFIG_VFAT_FS=y +CONFIG_TMPFS_POSIX_ACL=y +CONFIG_ECRYPT_FS=y +CONFIG_ECRYPT_FS_MESSAGING=y +CONFIG_SDCARD_FS=y +CONFIG_NLS_CODEPAGE_437=y +CONFIG_NLS_ISO8859_1=y +CONFIG_PRINTK_TIME=y +CONFIG_DEBUG_INFO=y +CONFIG_MAGIC_SYSRQ=y +CONFIG_PANIC_TIMEOUT=5 +CONFIG_SCHEDSTATS=y +# CONFIG_DEBUG_PREEMPT is not set +CONFIG_IPC_LOGGING=y +CONFIG_DEBUG_ALIGN_RODATA=y +CONFIG_CORESIGHT=y +CONFIG_CORESIGHT_LINK_AND_SINK_TMC=y +CONFIG_CORESIGHT_SOURCE_ETM4X=y +CONFIG_CORESIGHT_DYNAMIC_REPLICATOR=y +CONFIG_CORESIGHT_STM=y +CONFIG_CORESIGHT_CTI=y +CONFIG_CORESIGHT_TPDA=y +CONFIG_CORESIGHT_TPDM=y +CONFIG_CORESIGHT_HWEVENT=y +CONFIG_CORESIGHT_DUMMY=y +CONFIG_CORESIGHT_REMOTE_ETM=y +CONFIG_CORESIGHT_REMOTE_ETM_DEFAULT_ENABLE=0 +CONFIG_CORESIGHT_EVENT=y +CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y +CONFIG_SECURITY=y +CONFIG_HARDENED_USERCOPY=y +CONFIG_FORTIFY_SOURCE=y +CONFIG_SECURITY_SELINUX=y +CONFIG_SECURITY_SMACK=y +CONFIG_CRYPTO_XCBC=y +CONFIG_CRYPTO_MD4=y +CONFIG_CRYPTO_TWOFISH=y +CONFIG_CRYPTO_ANSI_CPRNG=y +CONFIG_CRYPTO_DEV_QCOM_MSM_QCE=y +CONFIG_CRYPTO_DEV_QCRYPTO=y +CONFIG_CRYPTO_DEV_QCEDEV=y +CONFIG_ARM64_CRYPTO=y +CONFIG_CRYPTO_SHA1_ARM64_CE=y +CONFIG_CRYPTO_SHA2_ARM64_CE=y +CONFIG_CRYPTO_GHASH_ARM64_CE=y +CONFIG_CRYPTO_AES_ARM64_CE_CCM=y +CONFIG_CRYPTO_AES_ARM64_CE_BLK=y +CONFIG_CRYPTO_AES_ARM64_NEON_BLK=y diff --git a/arch/arm64/configs/sm8150-auto_defconfig b/arch/arm64/configs/sm8150-auto_defconfig new file mode 100644 index 000000000000..5bf92e55b3dc --- /dev/null +++ b/arch/arm64/configs/sm8150-auto_defconfig @@ -0,0 +1,693 @@ +# CONFIG_LOCALVERSION_AUTO is not set +CONFIG_AUDIT=y +# CONFIG_AUDITSYSCALL is not set +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_IRQ_TIME_ACCOUNTING=y +CONFIG_SCHED_WALT=y +CONFIG_TASKSTATS=y +CONFIG_TASK_XACCT=y +CONFIG_TASK_IO_ACCOUNTING=y +CONFIG_RCU_EXPERT=y +CONFIG_RCU_FAST_NO_HZ=y +CONFIG_RCU_NOCB_CPU=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_LOG_CPU_MAX_BUF_SHIFT=17 +CONFIG_MEMCG=y +CONFIG_MEMCG_SWAP=y +CONFIG_RT_GROUP_SCHED=y +CONFIG_CGROUP_FREEZER=y +CONFIG_CPUSETS=y +CONFIG_CGROUP_CPUACCT=y +CONFIG_CGROUP_BPF=y +CONFIG_CGROUP_DEBUG=y +CONFIG_SCHED_CORE_CTL=y +CONFIG_NAMESPACES=y +# CONFIG_UTS_NS is not set +# CONFIG_PID_NS is not set +CONFIG_SCHED_AUTOGROUP=y +CONFIG_SCHED_TUNE=y +CONFIG_DEFAULT_USE_ENERGY_AWARE=y +CONFIG_BLK_DEV_INITRD=y +# CONFIG_RD_XZ is not set +# CONFIG_RD_LZO is not set +# CONFIG_RD_LZ4 is not set +CONFIG_CC_OPTIMIZE_FOR_SIZE=y +CONFIG_KALLSYMS_ALL=y +CONFIG_BPF_SYSCALL=y +# CONFIG_MEMBARRIER is not set +CONFIG_EMBEDDED=y +# CONFIG_COMPAT_BRK is not set +CONFIG_SLAB_FREELIST_RANDOM=y +CONFIG_SLAB_FREELIST_HARDENED=y +CONFIG_PROFILING=y +CONFIG_CC_STACKPROTECTOR_STRONG=y +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +CONFIG_MODULE_FORCE_UNLOAD=y +CONFIG_MODVERSIONS=y +CONFIG_MODULE_SIG=y +CONFIG_MODULE_SIG_FORCE=y +CONFIG_MODULE_SIG_SHA512=y +# CONFIG_BLK_DEV_BSG is not set +CONFIG_PARTITION_ADVANCED=y +# CONFIG_IOSCHED_DEADLINE is not set +CONFIG_ARCH_QCOM=y +CONFIG_ARCH_SM8150=y +CONFIG_PCI=y +CONFIG_PCI_MSM=y +CONFIG_SCHED_MC=y +CONFIG_NR_CPUS=8 +CONFIG_PREEMPT=y +CONFIG_HZ_100=y +CONFIG_CLEANCACHE=y +CONFIG_CMA=y +CONFIG_CMA_DEBUGFS=y +CONFIG_ZSMALLOC=y +CONFIG_SECCOMP=y +# CONFIG_UNMAP_KERNEL_AT_EL0 is not set +# CONFIG_HARDEN_BRANCH_PREDICTOR is not set +CONFIG_ARMV8_DEPRECATED=y +CONFIG_SWP_EMULATION=y +CONFIG_CP15_BARRIER_EMULATION=y +CONFIG_SETEND_EMULATION=y +# CONFIG_ARM64_VHE is not set +CONFIG_RANDOMIZE_BASE=y +CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE=y +# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set +CONFIG_COMPAT=y +CONFIG_PM_AUTOSLEEP=y +CONFIG_PM_WAKELOCKS=y +CONFIG_PM_WAKELOCKS_LIMIT=0 +# CONFIG_PM_WAKELOCKS_GC is not set +CONFIG_PM_DEBUG=y +CONFIG_CPU_IDLE=y +CONFIG_ARM_CPUIDLE=y +CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_GOV_POWERSAVE=y +CONFIG_CPU_FREQ_GOV_USERSPACE=y +CONFIG_CPU_FREQ_GOV_ONDEMAND=y +CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y +CONFIG_CPU_BOOST=y +CONFIG_CPU_FREQ_GOV_SCHEDUTIL=y +CONFIG_NET=y +CONFIG_PACKET=y +CONFIG_UNIX=y +CONFIG_XFRM_USER=y +CONFIG_XFRM_STATISTICS=y +CONFIG_NET_KEY=y +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_ADVANCED_ROUTER=y +CONFIG_IP_MULTIPLE_TABLES=y +CONFIG_IP_ROUTE_VERBOSE=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +CONFIG_INET_AH=y +CONFIG_INET_ESP=y +CONFIG_INET_IPCOMP=y +CONFIG_INET_DIAG_DESTROY=y +CONFIG_IPV6_ROUTER_PREF=y +CONFIG_IPV6_ROUTE_INFO=y +CONFIG_IPV6_OPTIMISTIC_DAD=y +CONFIG_INET6_AH=y +CONFIG_INET6_ESP=y +CONFIG_INET6_IPCOMP=y +CONFIG_IPV6_MIP6=y +CONFIG_IPV6_MULTIPLE_TABLES=y +CONFIG_IPV6_SUBTREES=y +CONFIG_NETFILTER=y +CONFIG_NF_CONNTRACK=y +CONFIG_NF_CONNTRACK_SECMARK=y +CONFIG_NF_CONNTRACK_EVENTS=y +CONFIG_NF_CONNTRACK_AMANDA=y +CONFIG_NF_CONNTRACK_FTP=y +CONFIG_NF_CONNTRACK_H323=y +CONFIG_NF_CONNTRACK_IRC=y +CONFIG_NF_CONNTRACK_NETBIOS_NS=y +CONFIG_NF_CONNTRACK_PPTP=y +CONFIG_NF_CONNTRACK_SANE=y +CONFIG_NF_CONNTRACK_TFTP=y +CONFIG_NF_CT_NETLINK=y +CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y +CONFIG_NETFILTER_XT_TARGET_CONNMARK=y +CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=y +CONFIG_NETFILTER_XT_TARGET_IDLETIMER=y +CONFIG_NETFILTER_XT_TARGET_HARDIDLETIMER=y +CONFIG_NETFILTER_XT_TARGET_LOG=y +CONFIG_NETFILTER_XT_TARGET_MARK=y +CONFIG_NETFILTER_XT_TARGET_NFLOG=y +CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y +CONFIG_NETFILTER_XT_TARGET_NOTRACK=y +CONFIG_NETFILTER_XT_TARGET_TEE=y +CONFIG_NETFILTER_XT_TARGET_TPROXY=y +CONFIG_NETFILTER_XT_TARGET_TRACE=y +CONFIG_NETFILTER_XT_TARGET_SECMARK=y +CONFIG_NETFILTER_XT_TARGET_TCPMSS=y +CONFIG_NETFILTER_XT_MATCH_COMMENT=y +CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y +CONFIG_NETFILTER_XT_MATCH_CONNMARK=y +CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y +CONFIG_NETFILTER_XT_MATCH_DSCP=y +CONFIG_NETFILTER_XT_MATCH_ESP=y +CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y +CONFIG_NETFILTER_XT_MATCH_HELPER=y +CONFIG_NETFILTER_XT_MATCH_IPRANGE=y +# CONFIG_NETFILTER_XT_MATCH_L2TP is not set +CONFIG_NETFILTER_XT_MATCH_LENGTH=y +CONFIG_NETFILTER_XT_MATCH_LIMIT=y +CONFIG_NETFILTER_XT_MATCH_MAC=y +CONFIG_NETFILTER_XT_MATCH_MARK=y +CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y +CONFIG_NETFILTER_XT_MATCH_POLICY=y +CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y +CONFIG_NETFILTER_XT_MATCH_QTAGUID=y +CONFIG_NETFILTER_XT_MATCH_QUOTA=y +CONFIG_NETFILTER_XT_MATCH_QUOTA2=y +CONFIG_NETFILTER_XT_MATCH_SOCKET=y +CONFIG_NETFILTER_XT_MATCH_STATE=y +CONFIG_NETFILTER_XT_MATCH_STATISTIC=y +CONFIG_NETFILTER_XT_MATCH_STRING=y +CONFIG_NETFILTER_XT_MATCH_TIME=y +CONFIG_NETFILTER_XT_MATCH_U32=y +CONFIG_NF_CONNTRACK_IPV4=y +CONFIG_NF_SOCKET_IPV4=y +CONFIG_IP_NF_IPTABLES=y +CONFIG_IP_NF_MATCH_AH=y +CONFIG_IP_NF_MATCH_ECN=y +CONFIG_IP_NF_MATCH_RPFILTER=y +CONFIG_IP_NF_MATCH_TTL=y +CONFIG_IP_NF_FILTER=y +CONFIG_IP_NF_TARGET_REJECT=y +CONFIG_IP_NF_NAT=y +CONFIG_IP_NF_TARGET_MASQUERADE=y +CONFIG_IP_NF_TARGET_NETMAP=y +CONFIG_IP_NF_TARGET_REDIRECT=y +CONFIG_IP_NF_MANGLE=y +CONFIG_IP_NF_RAW=y +CONFIG_IP_NF_SECURITY=y +CONFIG_IP_NF_ARPTABLES=y +CONFIG_IP_NF_ARPFILTER=y +CONFIG_IP_NF_ARP_MANGLE=y +CONFIG_NF_CONNTRACK_IPV6=y +CONFIG_NF_SOCKET_IPV6=y +CONFIG_IP6_NF_IPTABLES=y +CONFIG_IP6_NF_MATCH_RPFILTER=y +CONFIG_IP6_NF_FILTER=y +CONFIG_IP6_NF_TARGET_REJECT=y +CONFIG_IP6_NF_MANGLE=y +CONFIG_IP6_NF_RAW=y +CONFIG_BRIDGE_NF_EBTABLES=y +CONFIG_BRIDGE_EBT_BROUTE=y +CONFIG_L2TP=y +CONFIG_L2TP_DEBUGFS=y +CONFIG_L2TP_V3=y +CONFIG_L2TP_IP=y +CONFIG_L2TP_ETH=y +CONFIG_BRIDGE=y +CONFIG_NET_SCHED=y +CONFIG_NET_SCH_HTB=y +CONFIG_NET_SCH_PRIO=y +CONFIG_NET_SCH_MULTIQ=y +CONFIG_NET_SCH_INGRESS=y +CONFIG_NET_CLS_FW=y +CONFIG_NET_CLS_U32=y +CONFIG_CLS_U32_MARK=y +CONFIG_NET_CLS_FLOW=y +CONFIG_NET_EMATCH=y +CONFIG_NET_EMATCH_CMP=y +CONFIG_NET_EMATCH_NBYTE=y +CONFIG_NET_EMATCH_U32=y +CONFIG_NET_EMATCH_META=y +CONFIG_NET_EMATCH_TEXT=y +CONFIG_NET_CLS_ACT=y +CONFIG_NET_ACT_GACT=y +CONFIG_NET_ACT_MIRRED=y +CONFIG_NET_ACT_SKBEDIT=y +CONFIG_DNS_RESOLVER=y +CONFIG_QRTR=y +CONFIG_QRTR_SMD=y +CONFIG_QRTR_MHI=y +CONFIG_RMNET_DATA=y +CONFIG_RMNET_DATA_FC=y +CONFIG_RMNET_DATA_DEBUG_PKT=y +CONFIG_SOCKEV_NLMCAST=y +CONFIG_BT=y +CONFIG_MSM_BT_POWER=y +CONFIG_CFG80211=y +CONFIG_CFG80211_INTERNAL_REGDB=y +# CONFIG_CFG80211_CRDA_SUPPORT is not set +CONFIG_RFKILL=y +CONFIG_NFC_NQ=y +CONFIG_FW_LOADER_USER_HELPER_FALLBACK=y +CONFIG_REGMAP_ALLOW_WRITE_DEBUGFS=y +CONFIG_DMA_CMA=y +CONFIG_MHI_BUS=y +CONFIG_MHI_DEBUG=y +CONFIG_MHI_QCOM=y +CONFIG_MHI_NETDEV=y +CONFIG_MHI_UCI=y +CONFIG_ZRAM=y +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=8192 +CONFIG_QSEECOM=y +CONFIG_UID_SYS_STATS=y +CONFIG_MEMORY_STATE_TIME=y +CONFIG_SCSI=y +CONFIG_BLK_DEV_SD=y +CONFIG_CHR_DEV_SG=y +CONFIG_CHR_DEV_SCH=y +CONFIG_SCSI_CONSTANTS=y +CONFIG_SCSI_LOGGING=y +CONFIG_SCSI_SCAN_ASYNC=y +CONFIG_SCSI_UFSHCD=y +CONFIG_SCSI_UFSHCD_PLATFORM=y +CONFIG_SCSI_UFS_QCOM=y +CONFIG_SCSI_UFSHCD_CMD_LOGGING=y +CONFIG_MD=y +CONFIG_BLK_DEV_DM=y +CONFIG_DM_UEVENT=y +CONFIG_DM_VERITY=y +CONFIG_DM_VERITY_FEC=y +CONFIG_NETDEVICES=y +CONFIG_BONDING=y +CONFIG_DUMMY=y +CONFIG_TUN=y +CONFIG_RMNET=y +CONFIG_PHYLIB=y +CONFIG_PPP=y +CONFIG_PPP_BSDCOMP=y +CONFIG_PPP_DEFLATE=y +CONFIG_PPP_FILTER=y +CONFIG_PPP_MPPE=y +CONFIG_PPP_MULTILINK=y +CONFIG_PPPOE=y +CONFIG_PPPOL2TP=y +CONFIG_PPPOLAC=y +CONFIG_PPPOPNS=y +CONFIG_PPP_ASYNC=y +CONFIG_PPP_SYNC_TTY=y +CONFIG_WIL6210=m +CONFIG_WCNSS_MEM_PRE_ALLOC=y +CONFIG_CLD_LL_CORE=y +CONFIG_INPUT_EVDEV=y +CONFIG_KEYBOARD_GPIO=y +# CONFIG_INPUT_MOUSE is not set +CONFIG_INPUT_JOYSTICK=y +CONFIG_INPUT_TOUCHSCREEN=y +CONFIG_TOUCHSCREEN_ST=y +CONFIG_INPUT_MISC=y +CONFIG_INPUT_HBTP_INPUT=y +CONFIG_INPUT_QPNP_POWER_ON=y +CONFIG_INPUT_UINPUT=y +# CONFIG_SERIO_SERPORT is not set +# CONFIG_VT is not set +# CONFIG_LEGACY_PTYS is not set +CONFIG_SERIAL_MSM_GENI=y +CONFIG_SERIAL_MSM_GENI_CONSOLE=y +CONFIG_SERIAL_DEV_BUS=y +CONFIG_TTY_PRINTK=y +CONFIG_HW_RANDOM=y +CONFIG_HW_RANDOM_MSM_LEGACY=y +CONFIG_DIAG_CHAR=y +CONFIG_MSM_FASTCVPD=y +CONFIG_MSM_ADSPRPC=y +CONFIG_I2C_CHARDEV=y +CONFIG_I2C_QCOM_GENI=y +CONFIG_SPI=y +CONFIG_SPI_QCOM_GENI=y +CONFIG_SPI_SPIDEV=y +CONFIG_SPMI=y +CONFIG_SPMI_SIMULATOR=y +CONFIG_PM855_PMIC_SIMULATOR=y +CONFIG_PM855B_PMIC_SIMULATOR=y +CONFIG_PM855L_PMIC_SIMULATOR=y +CONFIG_SLIMBUS_MSM_NGD=y +CONFIG_PINCTRL_QCOM_SPMI_PMIC=y +CONFIG_PINCTRL_SM8150=y +CONFIG_GPIO_SYSFS=y +CONFIG_POWER_RESET_QCOM=y +CONFIG_QCOM_DLOAD_MODE=y +CONFIG_POWER_RESET_XGENE=y +CONFIG_POWER_RESET_SYSCON=y +CONFIG_QPNP_FG_GEN4=y +CONFIG_QPNP_SMB5=y +CONFIG_THERMAL=y +CONFIG_THERMAL_WRITABLE_TRIPS=y +CONFIG_THERMAL_GOV_USER_SPACE=y +CONFIG_THERMAL_GOV_LOW_LIMITS=y +CONFIG_CPU_THERMAL=y +CONFIG_DEVFREQ_THERMAL=y +CONFIG_QCOM_SPMI_TEMP_ALARM=y +CONFIG_THERMAL_TSENS=y +CONFIG_QTI_THERMAL_LIMITS_DCVS=y +CONFIG_QTI_VIRTUAL_SENSOR=y +CONFIG_QTI_AOP_REG_COOLING_DEVICE=y +CONFIG_QTI_QMI_COOLING_DEVICE=y +CONFIG_REGULATOR_COOLING_DEVICE=y +CONFIG_QTI_BCL_PMIC5=y +CONFIG_QTI_BCL_SOC_DRIVER=y +CONFIG_QTI_ADC_TM=y +CONFIG_MFD_SPMI_PMIC=y +CONFIG_REGULATOR_FIXED_VOLTAGE=y +CONFIG_REGULATOR_PROXY_CONSUMER=y +CONFIG_REGULATOR_QPNP_LCDB=y +CONFIG_REGULATOR_REFGEN=y +CONFIG_REGULATOR_RPMH=y +CONFIG_REGULATOR_STUB=y +CONFIG_MEDIA_SUPPORT=y +CONFIG_MEDIA_CAMERA_SUPPORT=y +CONFIG_MEDIA_CONTROLLER=y +CONFIG_VIDEO_V4L2_SUBDEV_API=y +CONFIG_VIDEO_ADV_DEBUG=y +CONFIG_VIDEO_FIXED_MINOR_RANGES=y +CONFIG_V4L_PLATFORM_DRIVERS=y +CONFIG_SPECTRA_CAMERA=y +CONFIG_MSM_VIDC_V4L2=y +CONFIG_MSM_VIDC_GOVERNORS=y +CONFIG_MSM_SDE_ROTATOR=y +CONFIG_MSM_SDE_ROTATOR_EVTLOG_DEBUG=y +CONFIG_MSM_NPU=y +CONFIG_DRM=y +CONFIG_DRM_MSM_REGISTER_LOGGING=y +CONFIG_DRM_SDE_EVTLOG_DEBUG=y +CONFIG_DRM_SDE_RSC=y +CONFIG_FB_VIRTUAL=y +CONFIG_BACKLIGHT_LCD_SUPPORT=y +CONFIG_BACKLIGHT_CLASS_DEVICE=y +CONFIG_BACKLIGHT_QCOM_SPMI_WLED=y +CONFIG_LOGO=y +# CONFIG_LOGO_LINUX_MONO is not set +# CONFIG_LOGO_LINUX_VGA16 is not set +CONFIG_SOUND=y +CONFIG_SND=y +CONFIG_SND_DYNAMIC_MINORS=y +CONFIG_SND_USB_AUDIO=y +CONFIG_SND_USB_AUDIO_QMI=y +CONFIG_SND_SOC=y +CONFIG_UHID=y +CONFIG_HID_APPLE=y +CONFIG_HID_ELECOM=y +CONFIG_HID_MAGICMOUSE=y +CONFIG_HID_MICROSOFT=y +CONFIG_HID_MULTITOUCH=y +CONFIG_HID_PLANTRONICS=y +CONFIG_USB=y +CONFIG_USB_ANNOUNCE_NEW_DEVICES=y +CONFIG_USB_XHCI_HCD=y +CONFIG_USB_EHCI_HCD=y +CONFIG_USB_EHCI_HCD_PLATFORM=y +CONFIG_USB_OHCI_HCD=y +CONFIG_USB_OHCI_HCD_PLATFORM=y +CONFIG_USB_STORAGE=y +CONFIG_USB_DWC3=y +CONFIG_USB_DWC3_MSM=y +CONFIG_USB_ISP1760=y +CONFIG_USB_ISP1760_HOST_ROLE=y +CONFIG_NOP_USB_XCEIV=y +CONFIG_USB_QCOM_EMU_PHY=y +CONFIG_USB_MSM_SSPHY_QMP=y +CONFIG_MSM_HSUSB_PHY=y +CONFIG_DUAL_ROLE_USB_INTF=y +CONFIG_USB_GADGET=y +CONFIG_USB_GADGET_VBUS_DRAW=900 +CONFIG_USB_CONFIGFS=y +CONFIG_USB_CONFIGFS_NCM=y +CONFIG_USB_CONFIGFS_MASS_STORAGE=y +CONFIG_USB_CONFIGFS_F_FS=y +CONFIG_USB_CONFIGFS_F_MTP=y +CONFIG_USB_CONFIGFS_F_PTP=y +CONFIG_USB_CONFIGFS_F_ACC=y +CONFIG_USB_CONFIGFS_F_AUDIO_SRC=y +CONFIG_USB_CONFIGFS_UEVENT=y +CONFIG_USB_CONFIGFS_F_MIDI=y +CONFIG_USB_CONFIGFS_F_HID=y +CONFIG_USB_CONFIGFS_F_DIAG=y +CONFIG_USB_CONFIGFS_F_CDEV=y +CONFIG_USB_CONFIGFS_F_CCID=y +CONFIG_USB_CONFIGFS_F_GSI=y +CONFIG_USB_CONFIGFS_F_QDSS=y +CONFIG_USB_PD_POLICY=y +CONFIG_QPNP_USB_PDPHY=y +CONFIG_MMC=y +CONFIG_MMC_PERF_PROFILING=y +CONFIG_MMC_BLOCK_MINORS=32 +CONFIG_MMC_BLOCK_DEFERRED_RESUME=y +CONFIG_MMC_TEST=y +CONFIG_MMC_RING_BUFFER=y +CONFIG_MMC_PARANOID_SD_INIT=y +CONFIG_MMC_CLKGATE=y +CONFIG_MMC_SDHCI=y +CONFIG_MMC_SDHCI_PLTFM=y +CONFIG_MMC_SDHCI_MSM=y +CONFIG_NEW_LEDS=y +CONFIG_LEDS_CLASS=y +CONFIG_LEDS_QPNP_FLASH_V2=y +CONFIG_LEDS_QPNP_HAPTICS=y +CONFIG_LEDS_QTI_TRI_LED=y +CONFIG_LEDS_TRIGGER_TIMER=y +CONFIG_EDAC=y +CONFIG_EDAC_KRYO_ARM64=y +CONFIG_EDAC_KRYO_ARM64_PANIC_ON_CE=y +CONFIG_EDAC_KRYO_ARM64_PANIC_ON_UE=y +CONFIG_EDAC_QCOM_LLCC=y +CONFIG_EDAC_QCOM_LLCC_PANIC_ON_CE=y +CONFIG_EDAC_QCOM_LLCC_PANIC_ON_UE=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_DRV_QPNP=y +CONFIG_DMADEVICES=y +CONFIG_QCOM_GPI_DMA=y +CONFIG_QCOM_GPI_DMA_DEBUG=y +CONFIG_UIO=y +CONFIG_UIO_MSM_SHAREDMEM=y +CONFIG_STAGING=y +CONFIG_ASHMEM=y +CONFIG_ION=y +CONFIG_QCOM_GENI_SE=y +CONFIG_QPNP_REVID=y +CONFIG_SPS=y +CONFIG_SPS_SUPPORT_NDP_BAM=y +CONFIG_USB_BAM=y +CONFIG_IPA3=y +CONFIG_IPA_WDI_UNIFIED_API=y +CONFIG_RMNET_IPA3=y +CONFIG_RNDIS_IPA=y +CONFIG_IPA_UT=y +CONFIG_MSM_11AD=m +CONFIG_QCOM_MDSS_PLL=y +CONFIG_SPMI_PMIC_CLKDIV=y +CONFIG_MSM_CLK_AOP_QMP=y +CONFIG_MSM_GCC_SM8150=y +CONFIG_MSM_NPUCC_SM8150=y +CONFIG_MSM_VIDEOCC_SM8150=y +CONFIG_MSM_CAMCC_SM8150=y +CONFIG_CLOCK_CPU_OSM=y +CONFIG_MSM_DISPCC_SM8150=y +CONFIG_MSM_DEBUGCC_SM8150=y +CONFIG_MSM_CLK_RPMH=y +CONFIG_MSM_GPUCC_SM8150=y +CONFIG_HWSPINLOCK=y +CONFIG_HWSPINLOCK_QCOM=y +CONFIG_QCOM_APCS_IPC=y +CONFIG_MSM_QMP=y +CONFIG_IOMMU_IO_PGTABLE_FAST=y +CONFIG_ARM_SMMU=y +CONFIG_QCOM_LAZY_MAPPING=y +CONFIG_IOMMU_DEBUG=y +CONFIG_IOMMU_DEBUG_TRACKING=y +CONFIG_IOMMU_TESTS=y +CONFIG_RPMSG_CHAR=y +CONFIG_RPMSG_QCOM_GLINK_SMEM=y +CONFIG_RPMSG_QCOM_GLINK_SPSS=y +CONFIG_QCOM_CPUSS_DUMP=y +CONFIG_QCOM_RUN_QUEUE_STATS=y +CONFIG_QCOM_LLCC=y +CONFIG_QCOM_SM8150_LLCC=y +CONFIG_QCOM_QMI_HELPERS=y +CONFIG_QCOM_SMEM=y +CONFIG_QCOM_MEMORY_DUMP_V2=y +CONFIG_QCOM_WATCHDOG_V2=y +CONFIG_QCOM_FORCE_WDOG_BITE_ON_PANIC=y +CONFIG_QCOM_WDOG_IPI_ENABLE=y +CONFIG_QCOM_SMP2P=y +CONFIG_MSM_SERVICE_LOCATOR=y +CONFIG_MSM_SERVICE_NOTIFIER=y +CONFIG_MSM_SUBSYSTEM_RESTART=y +CONFIG_MSM_PIL=y +CONFIG_MSM_SYSMON_QMI_COMM=y +CONFIG_MSM_PIL_SSR_GENERIC=y +CONFIG_MSM_BOOT_STATS=y +CONFIG_MSM_CORE_HANG_DETECT=y +CONFIG_QCOM_DCC_V2=y +CONFIG_MSM_GLADIATOR_HANG_DETECT=y +CONFIG_QCOM_SECURE_BUFFER=y +CONFIG_ICNSS=y +CONFIG_ICNSS_DEBUG=y +CONFIG_ICNSS_QMI=y +CONFIG_QCOM_EUD=y +CONFIG_QCOM_BUS_SCALING=y +CONFIG_QCOM_BUS_CONFIG_RPMH=y +CONFIG_QCOM_COMMAND_DB=y +CONFIG_QCOM_EARLY_RANDOM=y +CONFIG_MSM_SPSS_UTILS=y +CONFIG_MSM_SPCOM=y +CONFIG_QTI_RPMH_API=y +CONFIG_QSEE_IPC_IRQ_BRIDGE=y +CONFIG_QCOM_GLINK=y +CONFIG_QCOM_GLINK_PKT=y +CONFIG_QTI_RPM_STATS_LOG=y +CONFIG_MSM_CDSP_LOADER=y +CONFIG_QCOM_SMCINVOKE=y +CONFIG_MSM_EVENT_TIMER=y +CONFIG_MSM_PM=y +CONFIG_QCOM_FSA4480_I2C=y +CONFIG_MSM_PERFORMANCE=y +CONFIG_QMP_DEBUGFS_CLIENT=y +CONFIG_DEVFREQ_GOV_PASSIVE=y +CONFIG_QCOM_BIMC_BWMON=y +CONFIG_ARM_MEMLAT_MON=y +CONFIG_QCOMCCI_HWMON=y +CONFIG_QCOM_M4M_HWMON=y +CONFIG_DEVFREQ_GOV_QCOM_BW_HWMON=y +CONFIG_DEVFREQ_GOV_QCOM_CACHE_HWMON=y +CONFIG_DEVFREQ_GOV_MEMLAT=y +CONFIG_DEVFREQ_SIMPLE_DEV=y +CONFIG_QCOM_DEVFREQ_DEVBW=y +CONFIG_EXTCON_USB_GPIO=y +CONFIG_IIO=y +CONFIG_QCOM_SPMI_ADC5=y +CONFIG_PWM=y +CONFIG_PWM_QTI_LPG=y +CONFIG_QCOM_KGSL=y +CONFIG_ARM_GIC_V3_ACL=y +CONFIG_PHY_XGENE=y +CONFIG_ARM_DSU_PMU=y +CONFIG_QCOM_LLCC_PMU=y +CONFIG_RAS=y +CONFIG_ANDROID=y +CONFIG_ANDROID_BINDER_IPC=y +CONFIG_NVMEM_SPMI_SDAM=y +CONFIG_SENSORS_SSC=y +CONFIG_ESOC=y +CONFIG_ESOC_DEV=y +CONFIG_ESOC_CLIENT=y +CONFIG_ESOC_DEBUG=y +CONFIG_ESOC_MDM_4x=y +CONFIG_ESOC_MDM_DRV=y +CONFIG_ESOC_MDM_DBG_ENG=y +CONFIG_MSM_TZ_LOG=y +CONFIG_EXT2_FS=y +CONFIG_EXT2_FS_XATTR=y +CONFIG_EXT3_FS=y +CONFIG_EXT4_FS_SECURITY=y +CONFIG_EXT4_ENCRYPTION=y +CONFIG_QUOTA=y +CONFIG_QUOTA_NETLINK_INTERFACE=y +CONFIG_FUSE_FS=y +CONFIG_MSDOS_FS=y +CONFIG_VFAT_FS=y +CONFIG_TMPFS_POSIX_ACL=y +CONFIG_EFIVAR_FS=y +CONFIG_ECRYPT_FS=y +CONFIG_ECRYPT_FS_MESSAGING=y +CONFIG_SDCARD_FS=y +# CONFIG_NETWORK_FILESYSTEMS is not set +CONFIG_NLS_CODEPAGE_437=y +CONFIG_NLS_ISO8859_1=y +CONFIG_PRINTK_TIME=y +CONFIG_DYNAMIC_DEBUG=y +CONFIG_DEBUG_INFO=y +CONFIG_PAGE_OWNER=y +CONFIG_PAGE_OWNER_ENABLE_DEFAULT=y +CONFIG_DEBUG_SECTION_MISMATCH=y +# CONFIG_SECTION_MISMATCH_WARN_ONLY is not set +CONFIG_MAGIC_SYSRQ=y +CONFIG_DEBUG_PAGEALLOC=y +CONFIG_SLUB_DEBUG_PANIC_ON=y +CONFIG_DEBUG_PAGEALLOC_ENABLE_DEFAULT=y +CONFIG_PAGE_POISONING=y +CONFIG_DEBUG_OBJECTS=y +CONFIG_DEBUG_OBJECTS_FREE=y +CONFIG_DEBUG_OBJECTS_TIMERS=y +CONFIG_DEBUG_OBJECTS_WORK=y +CONFIG_DEBUG_OBJECTS_PERCPU_COUNTER=y +CONFIG_SLUB_DEBUG_ON=y +CONFIG_DEBUG_KMEMLEAK=y +CONFIG_DEBUG_KMEMLEAK_EARLY_LOG_SIZE=4000 +CONFIG_DEBUG_KMEMLEAK_DEFAULT_OFF=y +CONFIG_DEBUG_STACK_USAGE=y +CONFIG_DEBUG_MEMORY_INIT=y +CONFIG_SOFTLOCKUP_DETECTOR=y +CONFIG_WQ_WATCHDOG=y +CONFIG_PANIC_TIMEOUT=5 +CONFIG_PANIC_ON_SCHED_BUG=y +CONFIG_PANIC_ON_RT_THROTTLING=y +CONFIG_SCHEDSTATS=y +CONFIG_SCHED_STACK_END_CHECK=y +# CONFIG_DEBUG_PREEMPT is not set +CONFIG_DEBUG_SPINLOCK=y +CONFIG_DEBUG_MUTEXES=y +CONFIG_DEBUG_ATOMIC_SLEEP=y +CONFIG_LOCK_TORTURE_TEST=m +CONFIG_DEBUG_SG=y +CONFIG_DEBUG_NOTIFIERS=y +CONFIG_DEBUG_CREDENTIALS=y +CONFIG_RCU_TORTURE_TEST=m +CONFIG_FAULT_INJECTION=y +CONFIG_FAIL_PAGE_ALLOC=y +CONFIG_UFS_FAULT_INJECTION=y +CONFIG_FAULT_INJECTION_DEBUG_FS=y +CONFIG_FAULT_INJECTION_STACKTRACE_FILTER=y +CONFIG_IPC_LOGGING=y +CONFIG_QCOM_RTB=y +CONFIG_QCOM_RTB_SEPARATE_CPUS=y +CONFIG_FUNCTION_TRACER=y +CONFIG_PREEMPTIRQ_EVENTS=y +CONFIG_IRQSOFF_TRACER=y +CONFIG_PREEMPT_TRACER=y +CONFIG_BLK_DEV_IO_TRACE=y +CONFIG_LKDTM=m +CONFIG_ATOMIC64_SELFTEST=m +CONFIG_TEST_USER_COPY=m +CONFIG_MEMTEST=y +CONFIG_BUG_ON_DATA_CORRUPTION=y +CONFIG_PID_IN_CONTEXTIDR=y +CONFIG_ARM64_STRICT_BREAK_BEFORE_MAKE=y +CONFIG_CORESIGHT=y +CONFIG_CORESIGHT_LINK_AND_SINK_TMC=y +CONFIG_CORESIGHT_SOURCE_ETM4X=y +CONFIG_CORESIGHT_DYNAMIC_REPLICATOR=y +CONFIG_CORESIGHT_STM=y +CONFIG_CORESIGHT_CTI=y +CONFIG_CORESIGHT_TPDA=y +CONFIG_CORESIGHT_TPDM=y +CONFIG_CORESIGHT_HWEVENT=y +CONFIG_CORESIGHT_DUMMY=y +CONFIG_CORESIGHT_REMOTE_ETM=y +CONFIG_CORESIGHT_REMOTE_ETM_DEFAULT_ENABLE=0 +CONFIG_CORESIGHT_TGU=y +CONFIG_CORESIGHT_EVENT=y +CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y +CONFIG_SECURITY=y +CONFIG_HARDENED_USERCOPY=y +CONFIG_HARDENED_USERCOPY_PAGESPAN=y +CONFIG_FORTIFY_SOURCE=y +CONFIG_SECURITY_SELINUX=y +CONFIG_SECURITY_SMACK=y +CONFIG_CRYPTO_XCBC=y +CONFIG_CRYPTO_MD4=y +CONFIG_CRYPTO_TWOFISH=y +CONFIG_CRYPTO_ANSI_CPRNG=y +CONFIG_CRYPTO_DEV_QCOM_MSM_QCE=y +CONFIG_CRYPTO_DEV_QCRYPTO=y +CONFIG_CRYPTO_DEV_QCEDEV=y +CONFIG_ARM64_CRYPTO=y +CONFIG_CRYPTO_SHA1_ARM64_CE=y +CONFIG_CRYPTO_SHA2_ARM64_CE=y +CONFIG_CRYPTO_GHASH_ARM64_CE=y +CONFIG_CRYPTO_AES_ARM64_CE_CCM=y +CONFIG_CRYPTO_AES_ARM64_CE_BLK=y +CONFIG_CRYPTO_AES_ARM64_NEON_BLK=y +CONFIG_XZ_DEC=y -- GitLab From e82ad3cc7d0fc4f6905f7df8b98895fc53ce7599 Mon Sep 17 00:00:00 2001 From: Tatenda Chipeperekwa Date: Tue, 24 Apr 2018 14:54:35 -0700 Subject: [PATCH 1385/1635] ARM: dts: msm: add device node for MSM HDCP driver on sm8150 Add device node for the MSM HDCP driver which manages communication between HLOS and TZ for HDCP related operations. CRs-Fixed: 2213798 Change-Id: I9fd0f75c77625da2e725f866d8361dd8124102ee Signed-off-by: Tatenda Chipeperekwa --- arch/arm64/boot/dts/qcom/sm8150.dtsi | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sm8150.dtsi b/arch/arm64/boot/dts/qcom/sm8150.dtsi index 82210c5e82bb..5bd57e9ba765 100644 --- a/arch/arm64/boot/dts/qcom/sm8150.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150.dtsi @@ -2764,6 +2764,10 @@ <&apps_smmu 0x0516 0x0011>; }; + qcom_msmhdcp: qcom,msm_hdcp { + compatible = "qcom,msm-hdcp"; + }; + qcom_crypto: qcrypto@1de0000 { compatible = "qcom,qcrypto"; reg = <0x1de0000 0x20000>, -- GitLab From ba29d6992af2888af1d24013f4f73d359e2423cf Mon Sep 17 00:00:00 2001 From: Tatenda Chipeperekwa Date: Tue, 24 Apr 2018 15:15:18 -0700 Subject: [PATCH 1386/1635] defconfig: sm8150: enable HDCP driver Enable the HDCP driver in order to add support for HDCP over external display interfaces such as DisplayPort. Change-Id: If77634085360733100dc4b3769b4bf4e2a57f382 Signed-off-by: Tatenda Chipeperekwa --- arch/arm64/configs/sm8150-perf_defconfig | 1 + arch/arm64/configs/sm8150_defconfig | 1 + 2 files changed, 2 insertions(+) diff --git a/arch/arm64/configs/sm8150-perf_defconfig b/arch/arm64/configs/sm8150-perf_defconfig index 99104ced0af1..e6d518d373f8 100644 --- a/arch/arm64/configs/sm8150-perf_defconfig +++ b/arch/arm64/configs/sm8150-perf_defconfig @@ -245,6 +245,7 @@ CONFIG_ZRAM=y CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_SIZE=8192 +CONFIG_HDCP_QSEECOM=y CONFIG_QSEECOM=y CONFIG_UID_SYS_STATS=y CONFIG_MEMORY_STATE_TIME=y diff --git a/arch/arm64/configs/sm8150_defconfig b/arch/arm64/configs/sm8150_defconfig index bbb70090722f..539c6faecc60 100644 --- a/arch/arm64/configs/sm8150_defconfig +++ b/arch/arm64/configs/sm8150_defconfig @@ -253,6 +253,7 @@ CONFIG_ZRAM=y CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_SIZE=8192 +CONFIG_HDCP_QSEECOM=y CONFIG_QSEECOM=y CONFIG_UID_SYS_STATS=y CONFIG_MEMORY_STATE_TIME=y -- GitLab From 20f0a47d26a99a8824f7846c64bb105a88d7ccc9 Mon Sep 17 00:00:00 2001 From: Tatenda Chipeperekwa Date: Wed, 2 May 2018 14:43:51 -0700 Subject: [PATCH 1387/1635] ARM: dts: msm: add DSI and DP PHY refgen for sm8150 Add refgen regulator support for DSI and DP PHY, so it can be enabled/disabled when required. Change-Id: I3aba81787f82dbf55df82b16cd8644ea9bbba047 Signed-off-by: Tatenda Chipeperekwa --- arch/arm64/boot/dts/qcom/sm8150-sde.dtsi | 40 ++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sm8150-sde.dtsi b/arch/arm64/boot/dts/qcom/sm8150-sde.dtsi index a102ad743a96..fa3ca42ea887 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-sde.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-sde.dtsi @@ -507,6 +507,19 @@ qcom,supply-disable-load = <4>; }; }; + qcom,core-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + + qcom,core-supply-entry@0 { + reg = <0>; + qcom,supply-name = "refgen"; + qcom,supply-min-voltage = <0>; + qcom,supply-max-voltage = <0>; + qcom,supply-enable-load = <0>; + qcom,supply-disable-load = <0>; + }; + }; }; mdss_dsi1: qcom,mdss_dsi_ctrl1@ae96000 { @@ -540,6 +553,19 @@ qcom,supply-disable-load = <4>; }; }; + qcom,core-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + + qcom,core-supply-entry@0 { + reg = <0>; + qcom,supply-name = "refgen"; + qcom,supply-min-voltage = <0>; + qcom,supply-max-voltage = <0>; + qcom,supply-enable-load = <0>; + qcom,supply-disable-load = <0>; + }; + }; }; mdss_dsi_phy0: qcom,mdss_dsi_phy0@ae94400 { @@ -700,5 +726,19 @@ qcom,supply-disable-load = <32>; }; }; + + qcom,core-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + + qcom,core-supply-entry@0 { + reg = <0>; + qcom,supply-name = "refgen"; + qcom,supply-min-voltage = <0>; + qcom,supply-max-voltage = <0>; + qcom,supply-enable-load = <0>; + qcom,supply-disable-load = <0>; + }; + }; }; }; -- GitLab From 8cdee15ccb60fc78bf2d920489d617d0f44c42bb Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Thu, 3 May 2018 13:14:01 -0600 Subject: [PATCH 1388/1635] net: qualcomm: rmnet: check for null ep to avoid null pointer dereference The call to rmnet_get_endpoint can potentially return NULL so check for this to avoid any subsequent null pointer dereferences on a NULL ep. Detected by CoverityScan, CID#1465385 ("Dereference null return value") CRs-Fixed: 2156182 Change-Id: I2119f695279b0f1f65e5848f00193a5e3d8f3063 Fixes: 23790ef12082 ("net: qualcomm: rmnet: Allow to configure flags for existing devices") Signed-off-by: Colin Ian King Signed-off-by: David S. Miller Git-commit: 0c29ba1b43df1eb7d8beb03fc929d2dac4c15f7e Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git Signed-off-by: Subash Abhinov Kasiviswanathan --- drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c b/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c index 43fd9ec80825..8416c9a27765 100644 --- a/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c +++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c @@ -318,6 +318,8 @@ static int rmnet_changelink(struct net_device *dev, struct nlattr *tb[], if (data[IFLA_RMNET_MUX_ID]) { mux_id = nla_get_u16(data[IFLA_RMNET_MUX_ID]); ep = rmnet_get_endpoint(port, priv->mux_id); + if (!ep) + return -ENODEV; hlist_del_init_rcu(&ep->hlnode); hlist_add_head_rcu(&ep->hlnode, &port->muxed_ep[mux_id]); -- GitLab From bb2fea907bfa13dd683d1cec3f092bb1044f0bd0 Mon Sep 17 00:00:00 2001 From: Abhijit Kulkarni Date: Wed, 2 May 2018 17:25:27 -0700 Subject: [PATCH 1389/1635] drm/msm/sde: control regulator only in normal mode This change ensures that regualator is not controlled by software driver once it is programmed as hw controlled. Display RSC will put the mdss gdsc in hw controlled mode and after that all sw clients should not enable/disable it. Since it is guaranteed that sde driver will always put the vote to turn on gdsc, this ensures that regulator is enabled before any display hw access from clients. Change-Id: I289f7c63a7b5a57b5a36fed31452ba0ab8808430 Signed-off-by: Abhijit Kulkarni --- drivers/gpu/drm/msm/sde_io_util.c | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/msm/sde_io_util.c b/drivers/gpu/drm/msm/sde_io_util.c index d5a438e5f26c..685ca5458a60 100644 --- a/drivers/gpu/drm/msm/sde_io_util.c +++ b/drivers/gpu/drm/msm/sde_io_util.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2015, 2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2015, 2017-2018 The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -217,6 +217,7 @@ int msm_dss_enable_vreg(struct dss_vreg *in_vreg, int num_vreg, int enable) { int i = 0, rc = 0; bool need_sleep; + int reg_mode; if (enable) { for (i = 0; i < num_vreg; i++) { @@ -227,6 +228,17 @@ int msm_dss_enable_vreg(struct dss_vreg *in_vreg, int num_vreg, int enable) in_vreg[i].vreg_name, rc); goto vreg_set_opt_mode_fail; } + reg_mode = regulator_get_mode(in_vreg[i].vreg); + if (reg_mode == REGULATOR_MODE_FAST) { + DEV_DBG("%pS->%s: %s operation not allowed\n", + __builtin_return_address(0), __func__, + in_vreg[i].vreg_name); + /* + * This regulator is controlled by Hw cannot be + * controlled by Sw vote + */ + continue; + } need_sleep = !regulator_is_enabled(in_vreg[i].vreg); if (in_vreg[i].pre_on_sleep && need_sleep) usleep_range(in_vreg[i].pre_on_sleep * 1000, @@ -252,6 +264,17 @@ int msm_dss_enable_vreg(struct dss_vreg *in_vreg, int num_vreg, int enable) } } else { for (i = num_vreg-1; i >= 0; i--) { + reg_mode = regulator_get_mode(in_vreg[i].vreg); + if (reg_mode == REGULATOR_MODE_FAST) { + DEV_DBG("%pS->%s: %s operation not allowed\n", + __builtin_return_address(0), __func__, + in_vreg[i].vreg_name); + /* + * This regulator is controlled by Hw cannot be + * controlled by Sw vote + */ + continue; + } if (in_vreg[i].pre_off_sleep) usleep_range(in_vreg[i].pre_off_sleep * 1000, in_vreg[i].pre_off_sleep * 1000); -- GitLab From 32f98a16c65b7827ad2beaaad725221d9a2d9e1d Mon Sep 17 00:00:00 2001 From: Pavankumar Kondeti Date: Thu, 8 Mar 2018 12:29:07 +0530 Subject: [PATCH 1390/1635] sched/fair: Consider only idle CPUs for active migration A tasks that is not fit on its current CPU is actively migrated to a higher capacity CPU from the scheduler tick path. Since active migration involves stopping the currently running task and migrating to a different CPU, it is better to do this only if the target CPU is idle. The task does not have to necessarily run on the lower capacity cluster until the next tick. When a higher capacity CPU becomes idle, it can pull the misfit task running on the lower capacity CPU. Change-Id: Idda0bd6ac8cc4bc22f5eddc69236014d04708ecd Signed-off-by: Pavankumar Kondeti --- kernel/sched/fair.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index b1f9df289d39..5080196187b8 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -7284,6 +7284,12 @@ static inline int find_best_target(struct task_struct *p, int *backup_cpu, continue; } + /* + * Consider only idle CPUs for active migration. + */ + if (p->state == TASK_RUNNING) + continue; + /* * Case C) Non latency sensitive tasks on ACTIVE CPUs. * -- GitLab From b91fc8e9017c8027f47acdb5d2f907b4ec36a831 Mon Sep 17 00:00:00 2001 From: Anurag Chouhan Date: Fri, 19 Jan 2018 15:59:25 +0530 Subject: [PATCH 1391/1635] icnss: Avoid qmi exchange when fw is down Currently wlan Host driver call exported API's which invoke qmi exchanges irrespective of the firmware status which leads to QMI timeouts. To address this issue avoid sending qmi request to firmware when firmware is down. CRs-Fixed: 2175302 Change-Id: Ie5e340cebf7ee7f6143472e7dca0dfd9600d1b7d Signed-off-by: Anurag Chouhan --- drivers/soc/qcom/icnss.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/soc/qcom/icnss.c b/drivers/soc/qcom/icnss.c index f17abed813ed..61160a2d9830 100644 --- a/drivers/soc/qcom/icnss.c +++ b/drivers/soc/qcom/icnss.c @@ -1655,6 +1655,12 @@ int icnss_set_fw_log_mode(struct device *dev, uint8_t fw_log_mode) if (!dev) return -ENODEV; + if (test_bit(ICNSS_FW_DOWN, &penv->state)) { + icnss_pr_err("FW down, ignoring fw_log_mode state: 0x%lx\n", + penv->state); + return -EINVAL; + } + icnss_pr_dbg("FW log mode: %u\n", fw_log_mode); ret = wlfw_ini_send_sync_msg(penv, fw_log_mode); @@ -1741,6 +1747,12 @@ int icnss_wlan_enable(struct device *dev, struct icnss_wlan_enable_cfg *config, enum icnss_driver_mode mode, const char *host_version) { + if (test_bit(ICNSS_FW_DOWN, &penv->state)) { + icnss_pr_err("FW down, ignoring wlan_enable state: 0x%lx\n", + penv->state); + return -EINVAL; + } + return icnss_send_wlan_enable_to_fw(penv, config, mode, host_version); } EXPORT_SYMBOL(icnss_wlan_enable); -- GitLab From d01723081cdc902852d08e6656694b860bd13018 Mon Sep 17 00:00:00 2001 From: Sridhar Parasuram Date: Wed, 4 Apr 2018 11:55:01 -0700 Subject: [PATCH 1392/1635] defconfig: arm64: Add misc_debug_defconfig for memory and fuzzing tests Add misc_debug_defconfig which can be used for generating kasan/kcov enabled builds by merging this config using merge_config.sh script with other target defconfigs during build generation. Change-Id: I4469d08ecb47bdaabd9aef9f894208f83ca2d757 Signed-off-by: Sridhar Parasuram --- arch/arm64/configs/misc_debug_defconfig | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 arch/arm64/configs/misc_debug_defconfig diff --git a/arch/arm64/configs/misc_debug_defconfig b/arch/arm64/configs/misc_debug_defconfig new file mode 100644 index 000000000000..316fec31dbf4 --- /dev/null +++ b/arch/arm64/configs/misc_debug_defconfig @@ -0,0 +1,4 @@ +CONFIG_FRAME_WARN=0 +CONFIG_KASAN=y +CONFIG_KASAN_INLINE=y +CONFIG_KCOV=y -- GitLab From b6091b341da7e6d8bbae63b3fcc5e39d9d2b1507 Mon Sep 17 00:00:00 2001 From: Subbaraman Narayanamurthy Date: Thu, 3 May 2018 19:04:09 -0700 Subject: [PATCH 1393/1635] power: qpnp-fg-gen4: Fix debug battery id reporting Currently, for getting debug battery id thresholds, only lower threshold register is read twice. Fix this by reading higher threshold register. Change-Id: I9dee9f79bd0ccd1f73694e30e399f757815e139f Signed-off-by: Subbaraman Narayanamurthy --- drivers/power/supply/qcom/qpnp-fg-gen4.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/power/supply/qcom/qpnp-fg-gen4.c b/drivers/power/supply/qcom/qpnp-fg-gen4.c index 97bf0c51ee62..3d5a3e666902 100644 --- a/drivers/power/supply/qcom/qpnp-fg-gen4.c +++ b/drivers/power/supply/qcom/qpnp-fg-gen4.c @@ -446,7 +446,7 @@ static int fg_gen4_get_debug_batt_id(struct fg_dev *fg, int *batt_id) batt_id[0] = (30000 * tmp) / (MAX_BIAS_CODE - tmp); - rc = fg_read(fg, ADC_RR_FAKE_BATT_LOW_LSB(fg), (u8 *)&tmp, 2); + rc = fg_read(fg, ADC_RR_FAKE_BATT_HIGH_LSB(fg), (u8 *)&tmp, 2); if (rc < 0) { pr_err("failed to read addr=0x%04x, rc=%d\n", ADC_RR_FAKE_BATT_HIGH_LSB(fg), rc); -- GitLab From 364eb6aac0311fc9d7a1b3f02d8ce0a81029880a Mon Sep 17 00:00:00 2001 From: Liangliang Lu Date: Tue, 12 Dec 2017 17:18:16 +0800 Subject: [PATCH 1394/1635] usb: gadget: f_fs: Do not match when function do not bind Ep0 interrupt bottom half may execute after f_fs unbind. Return false if function already unbind. Change-Id: I66864400cea2ce4ae4596b966194f9235835dfee Signed-off-by: Liangliang Lu --- drivers/usb/gadget/function/f_fs.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c index 30650cacdee0..705d19665795 100644 --- a/drivers/usb/gadget/function/f_fs.c +++ b/drivers/usb/gadget/function/f_fs.c @@ -3546,6 +3546,11 @@ static bool ffs_func_req_match(struct usb_function *f, { struct ffs_function *func = ffs_func_from_usb(f); + if (!test_bit(FFS_FL_BOUND, &func->ffs->flags)) { + ffs_log("ffs function do not bind yet.\n"); + return false; + } + if (config0 && !(func->ffs->user_flags & FUNCTIONFS_CONFIG0_SETUP)) return false; -- GitLab From 0b74e100d6381df424f1c481fe83f6a803ca5630 Mon Sep 17 00:00:00 2001 From: David Ng Date: Thu, 3 May 2018 19:36:14 -0700 Subject: [PATCH 1395/1635] Android.bp: Initial header export bp for Android (qseecom only) Initial Android blueprint makefile for kernel header export; qseecom.h UAPI for now. Change-Id: Ia0af480167e19d099789548a2229b46abbd977f8 Signed-off-by: David Ng --- Android.bp | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 Android.bp diff --git a/Android.bp b/Android.bp new file mode 100644 index 000000000000..4341e3a71dad --- /dev/null +++ b/Android.bp @@ -0,0 +1,27 @@ +cc_binary_host { + name: "unifdef", + srcs: ["scripts/unifdef.c"], + sanitize: { + never: true, + } +} + +gensrcs { + name: "qseecom-kernel-includes", + + // move to out/ as root for header generation because of scripts/unifdef + // storage - at the expense of extra ../ references + cmd: "pushd out && mkdir -p scripts && rm -f scripts/unifdef && ln -s ../../$(location unifdef) scripts/unifdef && ../$(location scripts/headers_install.sh) `dirname ../$(out)` ../ $(in) && popd", + + tools: ["unifdef"], + tool_files: ["scripts/headers_install.sh"], + export_include_dirs: ["include/uapi"], + srcs: ["include/uapi/linux/qseecom.h"], + output_extension: "h", +} + +cc_library_headers { + name: "qseecom-kernel-headers", + generated_headers: ["qseecom-kernel-includes"], + export_generated_headers: ["qseecom-kernel-includes"], +} -- GitLab From 366093401d7316190ff601071da508a058b2327d Mon Sep 17 00:00:00 2001 From: Charan Teja Reddy Date: Fri, 4 May 2018 12:13:16 +0530 Subject: [PATCH 1396/1635] arm: dma-mapping: use proper api to get prot attribute Use proper API to get the IOMMU protection attributes which are used in pagetable mappings. Change-Id: I755fd6ee030ed3d1a3f443ac3624512e0ba66ee4 Fixes: Ibf67f29a60b ("arm: dma-mapping: map sg lists into the SMMU as virtually contiguous") Signed-off-by: Charan Teja Reddy --- arch/arm/mm/dma-mapping.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c index 10413cad20af..aba8ef827345 100644 --- a/arch/arm/mm/dma-mapping.c +++ b/arch/arm/mm/dma-mapping.c @@ -1849,7 +1849,7 @@ int arm_iommu_map_sg(struct device *dev, struct scatterlist *sg, struct dma_iommu_mapping *mapping = dev->archdata.mapping; unsigned int total_length = 0, current_offset = 0; dma_addr_t iova; - int prot = __dma_direction_to_prot(dir); + int prot = __dma_info_to_prot(dir, attrs); for_each_sg(sg, s, nents, i) total_length += s->length; -- GitLab From c8838f26fd0da744672bd112b841a2e76c462dbb Mon Sep 17 00:00:00 2001 From: Hareesh Gundu Date: Fri, 4 May 2018 13:57:34 +0530 Subject: [PATCH 1397/1635] msm: kgsl: Get kgsl device from the hfi_start() caller To avoid any kgsl device NULL pointer dereference in hfi_start() get kgsl device from the hfi_start() caller. Change-Id: I2c27067234d96097d0c894a3fb986afb20062b60 Signed-off-by: Hareesh Gundu --- drivers/gpu/msm/kgsl_gmu.c | 8 ++++---- drivers/gpu/msm/kgsl_hfi.c | 4 ++-- drivers/gpu/msm/kgsl_hfi.h | 3 ++- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/msm/kgsl_gmu.c b/drivers/gpu/msm/kgsl_gmu.c index bd5f86f02435..75d7334b8b54 100644 --- a/drivers/gpu/msm/kgsl_gmu.c +++ b/drivers/gpu/msm/kgsl_gmu.c @@ -1667,7 +1667,7 @@ static int gmu_start(struct kgsl_device *device) if (ret) goto error_gmu; - ret = hfi_start(gmu, GMU_COLD_BOOT); + ret = hfi_start(device, gmu, GMU_COLD_BOOT); if (ret) goto error_gmu; @@ -1687,7 +1687,7 @@ static int gmu_start(struct kgsl_device *device) if (ret) goto error_gmu; - ret = hfi_start(gmu, GMU_COLD_BOOT); + ret = hfi_start(device, gmu, GMU_COLD_BOOT); if (ret) goto error_gmu; @@ -1708,7 +1708,7 @@ static int gmu_start(struct kgsl_device *device) goto error_gmu; - ret = hfi_start(gmu, GMU_COLD_BOOT); + ret = hfi_start(device, gmu, GMU_COLD_BOOT); if (ret) goto error_gmu; @@ -1724,7 +1724,7 @@ static int gmu_start(struct kgsl_device *device) if (ret) goto error_gmu; - ret = hfi_start(gmu, GMU_COLD_BOOT); + ret = hfi_start(device, gmu, GMU_COLD_BOOT); if (ret) goto error_gmu; } diff --git a/drivers/gpu/msm/kgsl_hfi.c b/drivers/gpu/msm/kgsl_hfi.c index 89024c0e2a64..69bb16c1db33 100644 --- a/drivers/gpu/msm/kgsl_hfi.c +++ b/drivers/gpu/msm/kgsl_hfi.c @@ -601,9 +601,9 @@ static int hfi_verify_fw_version(struct kgsl_device *device, return 0; } -int hfi_start(struct gmu_device *gmu, uint32_t boot_state) +int hfi_start(struct kgsl_device *device, + struct gmu_device *gmu, uint32_t boot_state) { - struct kgsl_device *device = kgsl_get_device(KGSL_DEVICE_3D0); struct adreno_device *adreno_dev = ADRENO_DEVICE(device); int result; diff --git a/drivers/gpu/msm/kgsl_hfi.h b/drivers/gpu/msm/kgsl_hfi.h index c7a16261401f..d1100e05ebaa 100644 --- a/drivers/gpu/msm/kgsl_hfi.h +++ b/drivers/gpu/msm/kgsl_hfi.h @@ -613,7 +613,8 @@ struct kgsl_hfi { struct gmu_device; struct gmu_memdesc; -int hfi_start(struct gmu_device *gmu, uint32_t boot_state); +int hfi_start(struct kgsl_device *device, struct gmu_device *gmu, + uint32_t boot_state); void hfi_stop(struct gmu_device *gmu); void hfi_receiver(unsigned long data); void hfi_init(struct kgsl_hfi *hfi, struct gmu_memdesc *mem_addr, -- GitLab From e5e0637f3206cfca6524bc7aca23430293d2e2c7 Mon Sep 17 00:00:00 2001 From: Manoj Prabhu B Date: Fri, 4 May 2018 14:35:11 +0530 Subject: [PATCH 1398/1635] diag: Add new WLAN_RSN event id The patch adds new WLAN_RSN_INFO event as latest ID. Change-Id: Ic76506632ea0aa61c79c52824556b6aaeb0b04e6 Signed-off-by: Manoj Prabhu B --- include/linux/diagchar.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/diagchar.h b/include/linux/diagchar.h index 3c7ec2264935..a3d9563e7f4e 100644 --- a/include/linux/diagchar.h +++ b/include/linux/diagchar.h @@ -146,7 +146,7 @@ * a new RANGE of SSIDs to the msg_mask_tbl. */ #define MSG_MASK_TBL_CNT 26 -#define APPS_EVENT_LAST_ID 0x0C5A +#define APPS_EVENT_LAST_ID 0x0C5B #define MSG_SSID_0 0 #define MSG_SSID_0_LAST 125 -- GitLab From 45624040e609efa9e2421d7e1b57766fee276ac2 Mon Sep 17 00:00:00 2001 From: Naresh Maradana Date: Thu, 27 Jul 2017 10:41:57 -0700 Subject: [PATCH 1399/1635] ARM: RTIC 3.0: Enabling MPGen Added RTIC environmental variable check. If set, this will trigger RTIC MPGen during the kernel build. MPGen generates and embeds the kernel MP.s (measurement parameters) to the vmlinux. It has to be called during the kernel build, before vmlinux is generated. RTIC MP.s to be consumed by the RTIC TA. Acked-by: Alex Mavrin Change-Id: Id64ae893f750337abbecfea0b461f2d3ae508d00 Signed-off-by: Naresh Maradana --- arch/arm64/boot/Makefile | 11 ++++++++++ scripts/link-vmlinux.sh | 45 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+) mode change 100755 => 100644 scripts/link-vmlinux.sh diff --git a/arch/arm64/boot/Makefile b/arch/arm64/boot/Makefile index 83d3577b0b69..831c7042fb4e 100644 --- a/arch/arm64/boot/Makefile +++ b/arch/arm64/boot/Makefile @@ -28,6 +28,17 @@ DTB_LIST := $(dtb-y) endif DTB_OBJS := $(shell find $(obj)/dts/ -name \*.dtb) +# Add RTIC DTB to the DTB list if RTIC MPGen is enabled +ifdef RTIC_MPGEN +DTB_OBJS += rtic_mp.dtb +endif + +rtic_mp.dtb: vmlinux FORCE + $(RTIC_MPGEN) --objcopy="${OBJCOPY}" --objdump="${OBJDUMP}" \ + --binpath="" --vmlinux="vmlinux" --config=${KCONFIG_CONFIG} \ + --cc="${CC}" --dts=rtic_mp.dts && \ + $(DTC) -O dtb -o rtic_mp.dtb -b 0 $(DTC_FLAGS) rtic_mp.dts + $(obj)/Image: vmlinux FORCE $(call if_changed,objcopy) diff --git a/scripts/link-vmlinux.sh b/scripts/link-vmlinux.sh old mode 100755 new mode 100644 index cfa44718cef7..bd8968ee14ef --- a/scripts/link-vmlinux.sh +++ b/scripts/link-vmlinux.sh @@ -232,6 +232,28 @@ kallsyms() ${CC} ${aflags} -c -o ${2} ${afile} } +# Generates ${2} .o file with RTIC MP's from the ${1} object file (vmlinux) +# ${3} the file name where the sizes of the RTIC MP structure are stored +# just in case, save copy of the RTIC mp to ${4} +# Note: RTIC_MPGEN has to be set if MPGen is available +rtic_mp() +{ + # assume that RTIC_MP_O generation may fail + RTIC_MP_O= + + local aflags="${KBUILD_AFLAGS} ${KBUILD_AFLAGS_KERNEL} \ + ${NOSTDINC_FLAGS} ${LINUXINCLUDE} ${KBUILD_CPPFLAGS}" + + ${RTIC_MPGEN} --objcopy="${OBJCOPY}" --objdump="${OBJDUMP}" \ + --binpath='' --vmlinux=${1} --config=${KCONFIG_CONFIG} && \ + cat rtic_mp.c | ${CC} ${aflags} -c -o ${2} -x c - && \ + cp rtic_mp.c ${4} && \ + ${NM} --print-size --size-sort ${2} > ${3} && \ + RTIC_MP_O=${2} + # NM - save generated variable sizes for verification + # RTIC_MP_O is our retval - great success if set to generated .o file +} + # Create map file with all symbols from ${1} # See mksymap for additional details mksysmap() @@ -257,6 +279,8 @@ cleanup() rm -f System.map rm -f vmlinux rm -f vmlinux.o + rm -f .tmp_rtic_mp_sz* + rm -f rtic_mp.* } on_exit() @@ -329,6 +353,15 @@ if [ -n "${CONFIG_LTO_CLANG}" ]; then recordmcount vmlinux.o fi +# Generate RTIC MP placeholder compile unit of the correct size +# and add it to the list of link objects +# this needs to be done before generating kallsyms +if [ ! -z ${RTIC_MPGEN+x} ]; then + rtic_mp vmlinux.o rtic_mp.o .tmp_rtic_mp_sz1 .tmp_rtic_mp1.c + KBUILD_VMLINUX_LIBS+=" " + KBUILD_VMLINUX_LIBS+=$RTIC_MP_O +fi + kallsymso="" kallsyms_vmlinux="" if [ -n "${CONFIG_KALLSYMS}" ]; then @@ -381,6 +414,18 @@ if [ -n "${CONFIG_KALLSYMS}" ]; then fi fi +# Update RTIC MP object by replacing the place holder +# with actual MP data of the same size +# Also double check that object size did not change +if [ ! -z ${RTIC_MPGEN+x} ]; then + rtic_mp "${kallsyms_vmlinux}" rtic_mp.o .tmp_rtic_mp_sz2 \ + .tmp_rtic_mp2.c + if ! cmp -s .tmp_rtic_mp_sz1 .tmp_rtic_mp_sz2; then + echo >&2 'ERROR: RTIC MP object files size mismatch' + exit 1 + fi +fi + info LD vmlinux vmlinux_link "${kallsymso}" vmlinux -- GitLab From a45def9b1ff7eafbbc7f726d413e467b23f63a64 Mon Sep 17 00:00:00 2001 From: Prateek Sood Date: Thu, 3 May 2018 18:06:23 +0530 Subject: [PATCH 1400/1635] msm: sdm640: Replace sdm640 with sm6150 Update the code name from sdm640 to sm6150. Rename all files that contain "sdm640" in their names, and update all file content that contains "sdm640". Change-Id: Ia39a22a2cf0ad63ce4acc4ce515a3e4bf1690730 Signed-off-by: Prateek Sood --- .../devicetree/bindings/arm/msm/msm.txt | 12 ++-- .../devicetree/bindings/arm/msm/qcom,llcc.txt | 2 +- ...{qti,pdc-sdm640.txt => qti,pdc-sm6150.txt} | 2 +- ...com,sdm640-pinctrl => qcom,sm6150-pinctrl} | 8 +-- arch/arm64/Kconfig.platforms | 6 +- arch/arm64/boot/dts/qcom/Makefile | 26 ++++---- ...u-sdm640.dtsi => msm-arm-smmu-sm6150.dtsi} | 0 ...cdp-overlay.dts => sm6150-cdp-overlay.dts} | 6 +- .../qcom/{sdm640-cdp.dts => sm6150-cdp.dts} | 8 +-- .../qcom/{sdm640-cdp.dtsi => sm6150-cdp.dtsi} | 0 .../{sdm640-gdsc.dtsi => sm6150-gdsc.dtsi} | 0 .../qcom/{sdm640-ion.dtsi => sm6150-ion.dtsi} | 0 ...mtp-overlay.dts => sm6150-mtp-overlay.dts} | 6 +- .../qcom/{sdm640-mtp.dts => sm6150-mtp.dts} | 8 +-- .../qcom/{sdm640-mtp.dtsi => sm6150-mtp.dtsi} | 0 ...dm640-pinctrl.dtsi => sm6150-pinctrl.dtsi} | 2 +- .../qcom/{sdm640-pm.dtsi => sm6150-pm.dtsi} | 0 ...qrd-overlay.dts => sm6150-qrd-overlay.dts} | 6 +- .../qcom/{sdm640-qrd.dts => sm6150-qrd.dts} | 8 +-- .../qcom/{sdm640-qrd.dtsi => sm6150-qrd.dtsi} | 0 .../{sdm640-qupv3.dtsi => sm6150-qupv3.dtsi} | 0 ...mi-overlay.dts => sm6150-rumi-overlay.dts} | 6 +- .../qcom/{sdm640-rumi.dts => sm6150-rumi.dts} | 8 +-- .../{sdm640-rumi.dtsi => sm6150-rumi.dtsi} | 0 ...ulator.dtsi => sm6150-stub-regulator.dtsi} | 0 .../boot/dts/qcom/{sdm640.dts => sm6150.dts} | 6 +- .../dts/qcom/{sdm640.dtsi => sm6150.dtsi} | 36 +++++------ arch/arm64/configs/sdmsteppe-perf_defconfig | 5 +- arch/arm64/configs/sdmsteppe_defconfig | 6 +- drivers/irqchip/qcom/Kconfig | 8 +-- drivers/irqchip/qcom/Makefile | 2 +- .../qcom/{pdc-sdm640.c => pdc-sm6150.c} | 6 +- drivers/pinctrl/qcom/Kconfig | 6 +- drivers/pinctrl/qcom/Makefile | 2 +- .../{pinctrl-sdm640.c => pinctrl-sm6150.c} | 60 +++++++++---------- drivers/soc/qcom/Kconfig | 6 +- drivers/soc/qcom/Makefile | 2 +- .../soc/qcom/{llcc-sdm640.c => llcc-sm6150.c} | 34 +++++------ drivers/soc/qcom/socinfo.c | 8 +-- ...com,camcc-sdm640.h => qcom,camcc-sm6150.h} | 4 +- ...com,cpucc-sdm640.h => qcom,cpucc-sm6150.h} | 4 +- ...m,dispcc-sdm640.h => qcom,dispcc-sm6150.h} | 4 +- .../{qcom,gcc-sdm640.h => qcom,gcc-sm6150.h} | 4 +- ...com,gpucc-sdm640.h => qcom,gpucc-sm6150.h} | 4 +- ...videocc-sdm640.h => qcom,videocc-sm6150.h} | 4 +- include/soc/qcom/socinfo.h | 8 +-- 46 files changed, 167 insertions(+), 166 deletions(-) rename Documentation/devicetree/bindings/interrupt-controller/{qti,pdc-sdm640.txt => qti,pdc-sm6150.txt} (98%) rename Documentation/devicetree/bindings/pinctrl/{qcom,sdm640-pinctrl => qcom,sm6150-pinctrl} (97%) rename arch/arm64/boot/dts/qcom/{msm-arm-smmu-sdm640.dtsi => msm-arm-smmu-sm6150.dtsi} (100%) rename arch/arm64/boot/dts/qcom/{sdm640-cdp-overlay.dts => sm6150-cdp-overlay.dts} (82%) rename arch/arm64/boot/dts/qcom/{sdm640-cdp.dts => sm6150-cdp.dts} (78%) rename arch/arm64/boot/dts/qcom/{sdm640-cdp.dtsi => sm6150-cdp.dtsi} (100%) rename arch/arm64/boot/dts/qcom/{sdm640-gdsc.dtsi => sm6150-gdsc.dtsi} (100%) rename arch/arm64/boot/dts/qcom/{sdm640-ion.dtsi => sm6150-ion.dtsi} (100%) rename arch/arm64/boot/dts/qcom/{sdm640-mtp-overlay.dts => sm6150-mtp-overlay.dts} (82%) rename arch/arm64/boot/dts/qcom/{sdm640-mtp.dts => sm6150-mtp.dts} (78%) rename arch/arm64/boot/dts/qcom/{sdm640-mtp.dtsi => sm6150-mtp.dtsi} (100%) rename arch/arm64/boot/dts/qcom/{sdm640-pinctrl.dtsi => sm6150-pinctrl.dtsi} (99%) rename arch/arm64/boot/dts/qcom/{sdm640-pm.dtsi => sm6150-pm.dtsi} (100%) rename arch/arm64/boot/dts/qcom/{sdm640-qrd-overlay.dts => sm6150-qrd-overlay.dts} (82%) rename arch/arm64/boot/dts/qcom/{sdm640-qrd.dts => sm6150-qrd.dts} (78%) rename arch/arm64/boot/dts/qcom/{sdm640-qrd.dtsi => sm6150-qrd.dtsi} (100%) rename arch/arm64/boot/dts/qcom/{sdm640-qupv3.dtsi => sm6150-qupv3.dtsi} (100%) rename arch/arm64/boot/dts/qcom/{sdm640-rumi-overlay.dts => sm6150-rumi-overlay.dts} (81%) rename arch/arm64/boot/dts/qcom/{sdm640-rumi.dts => sm6150-rumi.dts} (78%) rename arch/arm64/boot/dts/qcom/{sdm640-rumi.dtsi => sm6150-rumi.dtsi} (100%) rename arch/arm64/boot/dts/qcom/{sdm640-stub-regulator.dtsi => sm6150-stub-regulator.dtsi} (100%) rename arch/arm64/boot/dts/qcom/{sdm640.dts => sm6150.dts} (84%) rename arch/arm64/boot/dts/qcom/{sdm640.dtsi => sm6150.dtsi} (97%) rename drivers/irqchip/qcom/{pdc-sdm640.c => pdc-sm6150.c} (97%) rename drivers/pinctrl/qcom/{pinctrl-sdm640.c => pinctrl-sm6150.c} (97%) rename drivers/soc/qcom/{llcc-sdm640.c => llcc-sm6150.c} (77%) rename include/dt-bindings/clock/{qcom,camcc-sdm640.h => qcom,camcc-sm6150.h} (97%) rename include/dt-bindings/clock/{qcom,cpucc-sdm640.h => qcom,cpucc-sm6150.h} (91%) rename include/dt-bindings/clock/{qcom,dispcc-sdm640.h => qcom,dispcc-sm6150.h} (95%) rename include/dt-bindings/clock/{qcom,gcc-sdm640.h => qcom,gcc-sm6150.h} (98%) rename include/dt-bindings/clock/{qcom,gpucc-sdm640.h => qcom,gpucc-sm6150.h} (94%) rename include/dt-bindings/clock/{qcom,videocc-sdm640.h => qcom,videocc-sm6150.h} (92%) diff --git a/Documentation/devicetree/bindings/arm/msm/msm.txt b/Documentation/devicetree/bindings/arm/msm/msm.txt index 7c4383ebfba5..124e0b7b2083 100644 --- a/Documentation/devicetree/bindings/arm/msm/msm.txt +++ b/Documentation/devicetree/bindings/arm/msm/msm.txt @@ -47,8 +47,8 @@ SoCs: - SDMSHRIKE compatible = "qcom,sdmshrike" -- SDM640 - compatible = "qcom,sdm640" +- SM6150 + compatible = "qcom,sm6150" - QCS405 compatible = "qcom,qcs405" @@ -138,10 +138,10 @@ compatible = "qcom,sm8150p-qrd" compatible = "qcom,sdmshrike-rumi" compatible = "qcom,sdmshrike-mtp" compatible = "qcom,sdmshrike-cdp" -compatible = "qcom,sdm640-rumi" -compatible = "qcom,sdm640-mtp" -compatible = "qcom,sdm640-cdp" -compatible = "qcom,sdm640-qrd" +compatible = "qcom,sm6150-rumi" +compatible = "qcom,sm6150-mtp" +compatible = "qcom,sm6150-cdp" +compatible = "qcom,sm6150-qrd" compatible = "qcom,qcs405-rumi" compatible = "qcom,qcs405-mtp" compatible = "qcom,qcs405-cdp" diff --git a/Documentation/devicetree/bindings/arm/msm/qcom,llcc.txt b/Documentation/devicetree/bindings/arm/msm/qcom,llcc.txt index fb96c49c112c..57583eafb5b9 100644 --- a/Documentation/devicetree/bindings/arm/msm/qcom,llcc.txt +++ b/Documentation/devicetree/bindings/arm/msm/qcom,llcc.txt @@ -94,7 +94,7 @@ compatible devices: qcom,sdm670-llcc, qcom,sm8150-llcc, qcom,sdmshrike-llcc, - qcom,sdm640-llcc + qcom,sm6150-llcc Example: diff --git a/Documentation/devicetree/bindings/interrupt-controller/qti,pdc-sdm640.txt b/Documentation/devicetree/bindings/interrupt-controller/qti,pdc-sm6150.txt similarity index 98% rename from Documentation/devicetree/bindings/interrupt-controller/qti,pdc-sdm640.txt rename to Documentation/devicetree/bindings/interrupt-controller/qti,pdc-sm6150.txt index 059e3ccbd35f..4ee8ae29f7ea 100644 --- a/Documentation/devicetree/bindings/interrupt-controller/qti,pdc-sdm640.txt +++ b/Documentation/devicetree/bindings/interrupt-controller/qti,pdc-sm6150.txt @@ -55,7 +55,7 @@ Properties: Example: pdcgic: interrupt-controller@0xb220000{ - compatible = "qcom,pdc-sdm640"; + compatible = "qcom,pdc-sm6150"; reg = <0xb220000 0x30000>; #interrupt-cells = <3>; interrupt-parent = <&intc>; diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,sdm640-pinctrl b/Documentation/devicetree/bindings/pinctrl/qcom,sm6150-pinctrl similarity index 97% rename from Documentation/devicetree/bindings/pinctrl/qcom,sdm640-pinctrl rename to Documentation/devicetree/bindings/pinctrl/qcom,sm6150-pinctrl index f585a341a455..9787c416f8d9 100644 --- a/Documentation/devicetree/bindings/pinctrl/qcom,sdm640-pinctrl +++ b/Documentation/devicetree/bindings/pinctrl/qcom,sm6150-pinctrl @@ -1,12 +1,12 @@ -Qualcomm Technologies, Inc. SDM640 TLMM block +Qualcomm Technologies, Inc. SM6150 TLMM block This binding describes the Top Level Mode Multiplexer block found in the -SDM640 platform. +SM6150 platform. - compatible: Usage: required Value type: - Definition: must be "qcom,sdm640-pinctrl" + Definition: must be "qcom,sm6150-pinctrl" - reg: Usage: required @@ -176,7 +176,7 @@ to specify in a pin configuration subnode: Example: tlmm: pinctrl@03000000 { - compatible = "qcom,sdm640-pinctrl"; + compatible = "qcom,sm6150-pinctrl"; reg = <0x03000000 0xdc2000>; interrupts = <0 208 0>; gpio-controller; diff --git a/arch/arm64/Kconfig.platforms b/arch/arm64/Kconfig.platforms index e393bbcd8b91..b5f071638148 100644 --- a/arch/arm64/Kconfig.platforms +++ b/arch/arm64/Kconfig.platforms @@ -159,12 +159,12 @@ config ARCH_SDMSHRIKE If you do not wish to build a kernel that runs on this chipset, say 'N' here. -config ARCH_SDM640 - bool "Enable Support for Qualcomm Technologies, Inc. SDM640" +config ARCH_SM6150 + bool "Enable Support for Qualcomm Technologies, Inc. SM6150" depends on ARCH_QCOM select COMMON_CLK_QCOM help - This enables support for the SDM640 chipset. If you do not + This enables support for the SM6150 chipset. If you do not wish to build a kernel that runs on this chipset, say 'N' here. config ARCH_QCS405 diff --git a/arch/arm64/boot/dts/qcom/Makefile b/arch/arm64/boot/dts/qcom/Makefile index ab3d6f9942a0..08947733d11e 100644 --- a/arch/arm64/boot/dts/qcom/Makefile +++ b/arch/arm64/boot/dts/qcom/Makefile @@ -64,21 +64,21 @@ dtb-$(CONFIG_ARCH_SDMSHRIKE) += sdmshrike-rumi.dtb \ endif ifeq ($(CONFIG_BUILD_ARM64_DT_OVERLAY),y) - dtbo-$(CONFIG_ARCH_SDM640) += \ - sdm640-cdp-overlay.dtbo \ - sdm640-mtp-overlay.dtbo \ - sdm640-rumi-overlay.dtbo \ - sdm640-qrd-overlay.dtbo \ + dtbo-$(CONFIG_ARCH_SM6150) += \ + sm6150-cdp-overlay.dtbo \ + sm6150-mtp-overlay.dtbo \ + sm6150-rumi-overlay.dtbo \ + sm6150-qrd-overlay.dtbo \ -sdm640-cdp-overlay.dtbo-base := sdm640.dtb -sdm640-mtp-overlay.dtbo-base := sdm640.dtb -sdm640-rumi-overlay.dtbo-base := sdm640.dtb -sdm640-qrd-overlay.dtbo-base := sdm640.dtb +sm6150-cdp-overlay.dtbo-base := sm6150.dtb +sm6150-mtp-overlay.dtbo-base := sm6150.dtb +sm6150-rumi-overlay.dtbo-base := sm6150.dtb +sm6150-qrd-overlay.dtbo-base := sm6150.dtb else -dtb-$(CONFIG_ARCH_SDM640) += sdm640-rumi.dtb \ - sdm640-mtp.dtb \ - sdm640-cdp.dtb \ - sdm640-qrd.dtb +dtb-$(CONFIG_ARCH_SM6150) += sm6150-rumi.dtb \ + sm6150-mtp.dtb \ + sm6150-cdp.dtb \ + sm6150-qrd.dtb endif ifeq ($(CONFIG_ARM64),y) diff --git a/arch/arm64/boot/dts/qcom/msm-arm-smmu-sdm640.dtsi b/arch/arm64/boot/dts/qcom/msm-arm-smmu-sm6150.dtsi similarity index 100% rename from arch/arm64/boot/dts/qcom/msm-arm-smmu-sdm640.dtsi rename to arch/arm64/boot/dts/qcom/msm-arm-smmu-sm6150.dtsi diff --git a/arch/arm64/boot/dts/qcom/sdm640-cdp-overlay.dts b/arch/arm64/boot/dts/qcom/sm6150-cdp-overlay.dts similarity index 82% rename from arch/arm64/boot/dts/qcom/sdm640-cdp-overlay.dts rename to arch/arm64/boot/dts/qcom/sm6150-cdp-overlay.dts index ee9624342bf1..36c64e4d5610 100644 --- a/arch/arm64/boot/dts/qcom/sdm640-cdp-overlay.dts +++ b/arch/arm64/boot/dts/qcom/sm6150-cdp-overlay.dts @@ -15,10 +15,10 @@ #include -#include "sdm640-cdp.dtsi" +#include "sm6150-cdp.dtsi" / { - model = "Qualcomm Technologies, Inc. SDM640 CDP"; - compatible = "qcom,sdm640-cdp", "qcom,sdm640", "qcom,cdp"; + model = "Qualcomm Technologies, Inc. SM6150 CDP"; + compatible = "qcom,sm6150-cdp", "qcom,sm6150", "qcom,cdp"; qcom,board-id = <1 0>; }; diff --git a/arch/arm64/boot/dts/qcom/sdm640-cdp.dts b/arch/arm64/boot/dts/qcom/sm6150-cdp.dts similarity index 78% rename from arch/arm64/boot/dts/qcom/sdm640-cdp.dts rename to arch/arm64/boot/dts/qcom/sm6150-cdp.dts index 54ca0de8c86c..14c73223a7d9 100644 --- a/arch/arm64/boot/dts/qcom/sdm640-cdp.dts +++ b/arch/arm64/boot/dts/qcom/sm6150-cdp.dts @@ -12,11 +12,11 @@ /dts-v1/; -#include "sdm640.dtsi" -#include "sdm640-cdp.dtsi" +#include "sm6150.dtsi" +#include "sm6150-cdp.dtsi" / { - model = "Qualcomm Technologies, Inc. SDM640 CDP"; - compatible = "qcom,sdm640-cdp", "qcom,sdm640", "qcom,cdp"; + model = "Qualcomm Technologies, Inc. SM6150 CDP"; + compatible = "qcom,sm6150-cdp", "qcom,sm6150", "qcom,cdp"; qcom,board-id = <1 0>; }; diff --git a/arch/arm64/boot/dts/qcom/sdm640-cdp.dtsi b/arch/arm64/boot/dts/qcom/sm6150-cdp.dtsi similarity index 100% rename from arch/arm64/boot/dts/qcom/sdm640-cdp.dtsi rename to arch/arm64/boot/dts/qcom/sm6150-cdp.dtsi diff --git a/arch/arm64/boot/dts/qcom/sdm640-gdsc.dtsi b/arch/arm64/boot/dts/qcom/sm6150-gdsc.dtsi similarity index 100% rename from arch/arm64/boot/dts/qcom/sdm640-gdsc.dtsi rename to arch/arm64/boot/dts/qcom/sm6150-gdsc.dtsi diff --git a/arch/arm64/boot/dts/qcom/sdm640-ion.dtsi b/arch/arm64/boot/dts/qcom/sm6150-ion.dtsi similarity index 100% rename from arch/arm64/boot/dts/qcom/sdm640-ion.dtsi rename to arch/arm64/boot/dts/qcom/sm6150-ion.dtsi diff --git a/arch/arm64/boot/dts/qcom/sdm640-mtp-overlay.dts b/arch/arm64/boot/dts/qcom/sm6150-mtp-overlay.dts similarity index 82% rename from arch/arm64/boot/dts/qcom/sdm640-mtp-overlay.dts rename to arch/arm64/boot/dts/qcom/sm6150-mtp-overlay.dts index db566fcc43ab..cdb2c0e4e556 100644 --- a/arch/arm64/boot/dts/qcom/sdm640-mtp-overlay.dts +++ b/arch/arm64/boot/dts/qcom/sm6150-mtp-overlay.dts @@ -15,10 +15,10 @@ #include -#include "sdm640-mtp.dtsi" +#include "sm6150-mtp.dtsi" / { - model = "Qualcomm Technologies, Inc. SDM640 MTP"; - compatible = "qcom,sdm640-mtp", "qcom,sdm640", "qcom,mtp"; + model = "Qualcomm Technologies, Inc. SM6150 MTP"; + compatible = "qcom,sm6150-mtp", "qcom,sm6150", "qcom,mtp"; qcom,board-id = <8 0>; }; diff --git a/arch/arm64/boot/dts/qcom/sdm640-mtp.dts b/arch/arm64/boot/dts/qcom/sm6150-mtp.dts similarity index 78% rename from arch/arm64/boot/dts/qcom/sdm640-mtp.dts rename to arch/arm64/boot/dts/qcom/sm6150-mtp.dts index c86f376477a8..a45cad060403 100644 --- a/arch/arm64/boot/dts/qcom/sdm640-mtp.dts +++ b/arch/arm64/boot/dts/qcom/sm6150-mtp.dts @@ -12,11 +12,11 @@ /dts-v1/; -#include "sdm640.dtsi" -#include "sdm640-mtp.dtsi" +#include "sm6150.dtsi" +#include "sm6150-mtp.dtsi" / { - model = "Qualcomm Technologies, Inc. SDM640 MTP"; - compatible = "qcom,sdm640-mtp", "qcom,sdm640", "qcom,mtp"; + model = "Qualcomm Technologies, Inc. SM6150 MTP"; + compatible = "qcom,sm6150-mtp", "qcom,sm6150", "qcom,mtp"; qcom,board-id = <8 0>; }; diff --git a/arch/arm64/boot/dts/qcom/sdm640-mtp.dtsi b/arch/arm64/boot/dts/qcom/sm6150-mtp.dtsi similarity index 100% rename from arch/arm64/boot/dts/qcom/sdm640-mtp.dtsi rename to arch/arm64/boot/dts/qcom/sm6150-mtp.dtsi diff --git a/arch/arm64/boot/dts/qcom/sdm640-pinctrl.dtsi b/arch/arm64/boot/dts/qcom/sm6150-pinctrl.dtsi similarity index 99% rename from arch/arm64/boot/dts/qcom/sdm640-pinctrl.dtsi rename to arch/arm64/boot/dts/qcom/sm6150-pinctrl.dtsi index ca16558f0005..1126ddac9394 100644 --- a/arch/arm64/boot/dts/qcom/sdm640-pinctrl.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6150-pinctrl.dtsi @@ -12,7 +12,7 @@ &soc { tlmm: pinctrl@03000000 { - compatible = "qcom,sdm640-pinctrl"; + compatible = "qcom,sm6150-pinctrl"; reg = <0x03000000 0xdc2000>; interrupts = <0 208 0>; gpio-controller; diff --git a/arch/arm64/boot/dts/qcom/sdm640-pm.dtsi b/arch/arm64/boot/dts/qcom/sm6150-pm.dtsi similarity index 100% rename from arch/arm64/boot/dts/qcom/sdm640-pm.dtsi rename to arch/arm64/boot/dts/qcom/sm6150-pm.dtsi diff --git a/arch/arm64/boot/dts/qcom/sdm640-qrd-overlay.dts b/arch/arm64/boot/dts/qcom/sm6150-qrd-overlay.dts similarity index 82% rename from arch/arm64/boot/dts/qcom/sdm640-qrd-overlay.dts rename to arch/arm64/boot/dts/qcom/sm6150-qrd-overlay.dts index df0d066520b7..2854d1471c99 100644 --- a/arch/arm64/boot/dts/qcom/sdm640-qrd-overlay.dts +++ b/arch/arm64/boot/dts/qcom/sm6150-qrd-overlay.dts @@ -15,10 +15,10 @@ #include -#include "sdm640-qrd.dtsi" +#include "sm6150-qrd.dtsi" / { - model = "Qualcomm Technologies, Inc. SDM640 QRD"; - compatible = "qcom,sdm640-qrd", "qcom,sdm640", "qcom,qrd"; + model = "Qualcomm Technologies, Inc. SM6150 QRD"; + compatible = "qcom,sm6150-qrd", "qcom,sm6150", "qcom,qrd"; qcom,board-id = <11 0>; }; diff --git a/arch/arm64/boot/dts/qcom/sdm640-qrd.dts b/arch/arm64/boot/dts/qcom/sm6150-qrd.dts similarity index 78% rename from arch/arm64/boot/dts/qcom/sdm640-qrd.dts rename to arch/arm64/boot/dts/qcom/sm6150-qrd.dts index 477c2f11906b..8be78315c266 100644 --- a/arch/arm64/boot/dts/qcom/sdm640-qrd.dts +++ b/arch/arm64/boot/dts/qcom/sm6150-qrd.dts @@ -12,11 +12,11 @@ /dts-v1/; -#include "sdm640.dtsi" -#include "sdm640-qrd.dtsi" +#include "sm6150.dtsi" +#include "sm6150-qrd.dtsi" / { - model = "Qualcomm Technologies, Inc. SDM640 QRD"; - compatible = "qcom,sdm640-qrd", "qcom,sdm640", "qcom,qrd"; + model = "Qualcomm Technologies, Inc. SM6150 QRD"; + compatible = "qcom,sm6150-qrd", "qcom,sm6150", "qcom,qrd"; qcom,board-id = <11 0>; }; diff --git a/arch/arm64/boot/dts/qcom/sdm640-qrd.dtsi b/arch/arm64/boot/dts/qcom/sm6150-qrd.dtsi similarity index 100% rename from arch/arm64/boot/dts/qcom/sdm640-qrd.dtsi rename to arch/arm64/boot/dts/qcom/sm6150-qrd.dtsi diff --git a/arch/arm64/boot/dts/qcom/sdm640-qupv3.dtsi b/arch/arm64/boot/dts/qcom/sm6150-qupv3.dtsi similarity index 100% rename from arch/arm64/boot/dts/qcom/sdm640-qupv3.dtsi rename to arch/arm64/boot/dts/qcom/sm6150-qupv3.dtsi diff --git a/arch/arm64/boot/dts/qcom/sdm640-rumi-overlay.dts b/arch/arm64/boot/dts/qcom/sm6150-rumi-overlay.dts similarity index 81% rename from arch/arm64/boot/dts/qcom/sdm640-rumi-overlay.dts rename to arch/arm64/boot/dts/qcom/sm6150-rumi-overlay.dts index 99df00b141ae..7b5115ecdb68 100644 --- a/arch/arm64/boot/dts/qcom/sdm640-rumi-overlay.dts +++ b/arch/arm64/boot/dts/qcom/sm6150-rumi-overlay.dts @@ -15,10 +15,10 @@ #include -#include "sdm640-rumi.dtsi" +#include "sm6150-rumi.dtsi" / { - model = "Qualcomm Technologies, Inc. SDM640 RUMI"; - compatible = "qcom,sdm640-rumi", "qcom,sdm640", "qcom,rumi"; + model = "Qualcomm Technologies, Inc. SM6150 RUMI"; + compatible = "qcom,sm6150-rumi", "qcom,sm6150", "qcom,rumi"; qcom,board-id = <15 0>; }; diff --git a/arch/arm64/boot/dts/qcom/sdm640-rumi.dts b/arch/arm64/boot/dts/qcom/sm6150-rumi.dts similarity index 78% rename from arch/arm64/boot/dts/qcom/sdm640-rumi.dts rename to arch/arm64/boot/dts/qcom/sm6150-rumi.dts index 0e3a602c1dac..fd344ffd4673 100644 --- a/arch/arm64/boot/dts/qcom/sdm640-rumi.dts +++ b/arch/arm64/boot/dts/qcom/sm6150-rumi.dts @@ -13,11 +13,11 @@ /dts-v1/; /memreserve/ 0x90000000 0x00000100; -#include "sdm640.dtsi" -#include "sdm640-rumi.dtsi" +#include "sm6150.dtsi" +#include "sm6150-rumi.dtsi" / { - model = "Qualcomm Technologies, Inc. SDM640 RUMI"; - compatible = "qcom,sdm640-rumi", "qcom,sdm640", "qcom,rumi"; + model = "Qualcomm Technologies, Inc. SM6150 RUMI"; + compatible = "qcom,sm6150-rumi", "qcom,sm6150", "qcom,rumi"; qcom,board-id = <15 0>; }; diff --git a/arch/arm64/boot/dts/qcom/sdm640-rumi.dtsi b/arch/arm64/boot/dts/qcom/sm6150-rumi.dtsi similarity index 100% rename from arch/arm64/boot/dts/qcom/sdm640-rumi.dtsi rename to arch/arm64/boot/dts/qcom/sm6150-rumi.dtsi diff --git a/arch/arm64/boot/dts/qcom/sdm640-stub-regulator.dtsi b/arch/arm64/boot/dts/qcom/sm6150-stub-regulator.dtsi similarity index 100% rename from arch/arm64/boot/dts/qcom/sdm640-stub-regulator.dtsi rename to arch/arm64/boot/dts/qcom/sm6150-stub-regulator.dtsi diff --git a/arch/arm64/boot/dts/qcom/sdm640.dts b/arch/arm64/boot/dts/qcom/sm6150.dts similarity index 84% rename from arch/arm64/boot/dts/qcom/sdm640.dts rename to arch/arm64/boot/dts/qcom/sm6150.dts index e03818f554e1..31c44c4c0305 100644 --- a/arch/arm64/boot/dts/qcom/sdm640.dts +++ b/arch/arm64/boot/dts/qcom/sm6150.dts @@ -12,10 +12,10 @@ /dts-v1/; -#include "sdm640.dtsi" +#include "sm6150.dtsi" / { - model = "Qualcomm Technologies, Inc. SDM640 SoC"; - compatible = "qcom,sdm640"; + model = "Qualcomm Technologies, Inc. SM6150 SoC"; + compatible = "qcom,sm6150"; qcom,board-id = <0 0>; }; diff --git a/arch/arm64/boot/dts/qcom/sdm640.dtsi b/arch/arm64/boot/dts/qcom/sm6150.dtsi similarity index 97% rename from arch/arm64/boot/dts/qcom/sdm640.dtsi rename to arch/arm64/boot/dts/qcom/sm6150.dtsi index f7ea87bf2f9d..dd1e09215346 100644 --- a/arch/arm64/boot/dts/qcom/sdm640.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6150.dtsi @@ -14,18 +14,18 @@ #include #include #include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include #include #include / { - model = "Qualcomm Technologies, Inc. SDM640"; - compatible = "qcom,sdm640"; + model = "Qualcomm Technologies, Inc. SM6150"; + compatible = "qcom,sm6150"; qcom,msm-id = <355 0x0>; interrupt-parent = <&pdc>; @@ -503,7 +503,7 @@ }; pdc: interrupt-controller@b220000{ - compatible = "qcom,pdc-sdm640"; + compatible = "qcom,pdc-sm6150"; reg = <0xb220000 0x400>; #interrupt-cells = <3>; interrupt-parent = <&intc>; @@ -930,8 +930,8 @@ qcom,llcc-banks-off = <0x0>; qcom,llcc-broadcast-off = <0x400000>; - llcc: qcom,sdm640-llcc { - compatible = "qcom,sdm640-llcc"; + llcc: qcom,sm6150-llcc { + compatible = "qcom,sm6150-llcc"; #cache-cells = <1>; max-slices = <32>; cap-based-alloc-and-pwr-collapse; @@ -1060,11 +1060,11 @@ #include "pm640.dtsi" #include "pm640l.dtsi" -#include "sdm640-pinctrl.dtsi" -#include "sdm640-stub-regulator.dtsi" -#include "sdm640-pm.dtsi" -#include "sdm640-gdsc.dtsi" -#include "sdm640-qupv3.dtsi" +#include "sm6150-pinctrl.dtsi" +#include "sm6150-stub-regulator.dtsi" +#include "sm6150-pm.dtsi" +#include "sm6150-gdsc.dtsi" +#include "sm6150-qupv3.dtsi" &emac_gdsc { status = "ok"; @@ -1162,5 +1162,5 @@ status = "ok"; }; -#include "sdm640-ion.dtsi" -#include "msm-arm-smmu-sdm640.dtsi" +#include "sm6150-ion.dtsi" +#include "msm-arm-smmu-sm6150.dtsi" diff --git a/arch/arm64/configs/sdmsteppe-perf_defconfig b/arch/arm64/configs/sdmsteppe-perf_defconfig index 3a656b63ec01..8deba27ba401 100644 --- a/arch/arm64/configs/sdmsteppe-perf_defconfig +++ b/arch/arm64/configs/sdmsteppe-perf_defconfig @@ -53,6 +53,7 @@ CONFIG_MODULE_SIG_SHA512=y CONFIG_PARTITION_ADVANCED=y CONFIG_ARCH_QCOM=y CONFIG_ARCH_SM8150=y +CONFIG_ARCH_SM6150=y CONFIG_PCI=y CONFIG_PCI_MSM=y CONFIG_SCHED_MC=y @@ -309,7 +310,7 @@ CONFIG_PM855B_PMIC_SIMULATOR=y CONFIG_PM855L_PMIC_SIMULATOR=y CONFIG_SLIMBUS_MSM_NGD=y CONFIG_PINCTRL_QCOM_SPMI_PMIC=y -CONFIG_PINCTRL_SDM640=y +CONFIG_PINCTRL_SM6150=y CONFIG_GPIO_SYSFS=y CONFIG_POWER_RESET_QCOM=y CONFIG_QCOM_DLOAD_MODE=y @@ -478,7 +479,7 @@ CONFIG_RPMSG_QCOM_GLINK_SPSS=y CONFIG_QCOM_CPUSS_DUMP=y CONFIG_QCOM_RUN_QUEUE_STATS=y CONFIG_QCOM_LLCC=y -CONFIG_QCOM_SDM640_LLCC=y +CONFIG_QCOM_SM6150_LLCC=y CONFIG_QCOM_QMI_HELPERS=y CONFIG_QCOM_SMEM=y CONFIG_QCOM_MEMORY_DUMP_V2=y diff --git a/arch/arm64/configs/sdmsteppe_defconfig b/arch/arm64/configs/sdmsteppe_defconfig index 9d052dd6eeb6..60c548962a1a 100644 --- a/arch/arm64/configs/sdmsteppe_defconfig +++ b/arch/arm64/configs/sdmsteppe_defconfig @@ -54,7 +54,7 @@ CONFIG_MODULE_SIG_SHA512=y CONFIG_PARTITION_ADVANCED=y # CONFIG_IOSCHED_DEADLINE is not set CONFIG_ARCH_QCOM=y -CONFIG_ARCH_SDM640=y +CONFIG_ARCH_SM6150=y CONFIG_PCI=y CONFIG_PCI_MSM=y CONFIG_SCHED_MC=y @@ -318,7 +318,7 @@ CONFIG_PM855B_PMIC_SIMULATOR=y CONFIG_PM855L_PMIC_SIMULATOR=y CONFIG_SLIMBUS_MSM_NGD=y CONFIG_PINCTRL_QCOM_SPMI_PMIC=y -CONFIG_PINCTRL_SDM640=y +CONFIG_PINCTRL_SM6150=y CONFIG_GPIO_SYSFS=y CONFIG_POWER_RESET_QCOM=y CONFIG_QCOM_DLOAD_MODE=y @@ -494,7 +494,7 @@ CONFIG_RPMSG_QCOM_GLINK_SPSS=y CONFIG_QCOM_CPUSS_DUMP=y CONFIG_QCOM_RUN_QUEUE_STATS=y CONFIG_QCOM_LLCC=y -CONFIG_QCOM_SDM640_LLCC=y +CONFIG_QCOM_SM6150_LLCC=y CONFIG_QCOM_QMI_HELPERS=y CONFIG_QCOM_SMEM=y CONFIG_QCOM_MEMORY_DUMP_V2=y diff --git a/drivers/irqchip/qcom/Kconfig b/drivers/irqchip/qcom/Kconfig index e8e1842ee6b3..654b081c2658 100644 --- a/drivers/irqchip/qcom/Kconfig +++ b/drivers/irqchip/qcom/Kconfig @@ -14,9 +14,9 @@ config QTI_PDC_SM8150 help QTI Power Domain Controller for SM8150 -config QTI_PDC_SDM640 - bool "QTI PDC SDM640" +config QTI_PDC_SM6150 + bool "QTI PDC SM6150" select QTI_PDC - default y if ARCH_SDM640 + default y if ARCH_SM6150 help - QTI Power Domain Controller for SDM640 + QTI Power Domain Controller for SM6150 diff --git a/drivers/irqchip/qcom/Makefile b/drivers/irqchip/qcom/Makefile index 2691b19c6769..92e98bb1287d 100644 --- a/drivers/irqchip/qcom/Makefile +++ b/drivers/irqchip/qcom/Makefile @@ -1,3 +1,3 @@ obj-$(CONFIG_QTI_PDC) += pdc.o obj-$(CONFIG_QTI_PDC_SM8150) += pdc-sm8150.o -obj-$(CONFIG_QTI_PDC_SDM640) += pdc-sdm640.o +obj-$(CONFIG_QTI_PDC_SM6150) += pdc-sm6150.o diff --git a/drivers/irqchip/qcom/pdc-sdm640.c b/drivers/irqchip/qcom/pdc-sm6150.c similarity index 97% rename from drivers/irqchip/qcom/pdc-sdm640.c rename to drivers/irqchip/qcom/pdc-sm6150.c index 02e1d7c2fe67..4a471059e3d1 100644 --- a/drivers/irqchip/qcom/pdc-sdm640.c +++ b/drivers/irqchip/qcom/pdc-sm6150.c @@ -14,7 +14,7 @@ #include #include "pdc.h" -static struct pdc_pin sdm640_data[] = { +static struct pdc_pin sm6150_data[] = { {0, 512},/*rpmh_wake*/ {1, 513},/*ee0_apps_hlos_spmi_periph_irq*/ {2, 514},/*ee1_apps_trustzone_spmi_periph_irq*/ @@ -146,7 +146,7 @@ static struct pdc_pin sdm640_data[] = { static int __init qcom_pdc_gic_init(struct device_node *node, struct device_node *parent) { - return qcom_pdc_init(node, parent, sdm640_data); + return qcom_pdc_init(node, parent, sm6150_data); } -IRQCHIP_DECLARE(pdc_sdm640, "qcom,pdc-sdm640", qcom_pdc_gic_init); +IRQCHIP_DECLARE(pdc_sm6150, "qcom,pdc-sm6150", qcom_pdc_gic_init); diff --git a/drivers/pinctrl/qcom/Kconfig b/drivers/pinctrl/qcom/Kconfig index 2dc42cb40dba..062ee60ba17b 100644 --- a/drivers/pinctrl/qcom/Kconfig +++ b/drivers/pinctrl/qcom/Kconfig @@ -166,12 +166,12 @@ config PINCTRL_SDMSHRIKE Qualcomm Technologies Inc TLMM block found on the Qualcomm Technologies Inc SDMSHRIKE platform. -config PINCTRL_SDM640 - tristate "Qualcomm Technologies Inc SDM640 pin controller driver" +config PINCTRL_SM6150 + tristate "Qualcomm Technologies Inc SM6150 pin controller driver" depends on GPIOLIB && OF select PINCTRL_MSM help This is the pinctrl, pinmux, pinconf and gpiolib driver for the Qualcomm Technologies Inc TLMM block found on the Qualcomm - Technologies Inc SDM640 platform. + Technologies Inc SM6150 platform. endif diff --git a/drivers/pinctrl/qcom/Makefile b/drivers/pinctrl/qcom/Makefile index 0435aca11c33..8cfd857a8ff6 100644 --- a/drivers/pinctrl/qcom/Makefile +++ b/drivers/pinctrl/qcom/Makefile @@ -21,4 +21,4 @@ obj-$(CONFIG_PINCTRL_QCOM_SSBI_PMIC) += pinctrl-ssbi-gpio.o obj-$(CONFIG_PINCTRL_QCOM_SSBI_PMIC) += pinctrl-ssbi-mpp.o obj-$(CONFIG_PINCTRL_SM8150) += pinctrl-sm8150.o obj-$(CONFIG_PINCTRL_SDMSHRIKE) += pinctrl-sdmshrike.o -obj-$(CONFIG_PINCTRL_SDM640) += pinctrl-sdm640.o +obj-$(CONFIG_PINCTRL_SM6150) += pinctrl-sm6150.o diff --git a/drivers/pinctrl/qcom/pinctrl-sdm640.c b/drivers/pinctrl/qcom/pinctrl-sm6150.c similarity index 97% rename from drivers/pinctrl/qcom/pinctrl-sdm640.c rename to drivers/pinctrl/qcom/pinctrl-sm6150.c index 0d692cc5eb30..937ffde55963 100644 --- a/drivers/pinctrl/qcom/pinctrl-sdm640.c +++ b/drivers/pinctrl/qcom/pinctrl-sm6150.c @@ -121,7 +121,7 @@ .intr_detection_bit = -1, \ .intr_detection_width = -1, \ } -static const struct pinctrl_pin_desc sdm640_pins[] = { +static const struct pinctrl_pin_desc sm6150_pins[] = { PINCTRL_PIN(0, "GPIO_0"), PINCTRL_PIN(1, "GPIO_1"), PINCTRL_PIN(2, "GPIO_2"), @@ -390,7 +390,7 @@ static const unsigned int sdc2_cmd_pins[] = { 128 }; static const unsigned int sdc2_data_pins[] = { 129 }; static const unsigned int ufs_reset_pins[] = { 130 }; -enum sdm640_functions { +enum sm6150_functions { msm_mux_qup02, msm_mux_gpio, msm_mux_qdss_gpio6, @@ -1148,7 +1148,7 @@ static const char * const mclk2_groups[] = { "gpio122", }; -static const struct msm_function sdm640_functions[] = { +static const struct msm_function sm6150_functions[] = { FUNCTION(qup02), FUNCTION(gpio), FUNCTION(qdss_gpio6), @@ -1339,7 +1339,7 @@ static const struct msm_function sdm640_functions[] = { * pin descriptor registered with pinctrl core. * Clients would not be able to request these dummy pin groups. */ -static const struct msm_pingroup sdm640_groups[] = { +static const struct msm_pingroup sm6150_groups[] = { [0] = PINGROUP(0, WEST, qup02, NA, qdss_gpio6, NA, NA, NA, NA, NA, NA), [1] = PINGROUP(1, WEST, qup02, NA, qdss_gpio7, NA, NA, NA, NA, NA, NA), [2] = PINGROUP(2, WEST, qup02, NA, qdss_gpio8, NA, NA, NA, NA, NA, NA), @@ -1558,7 +1558,7 @@ static const struct msm_pingroup sdm640_groups[] = { [130] = UFS_RESET(ufs_reset, 0x9f000), }; -static struct msm_dir_conn sdm640_dir_conn[] = { +static struct msm_dir_conn sm6150_dir_conn[] = { {1, 525}, {3, 511}, {7, 535}, @@ -1628,51 +1628,51 @@ static struct msm_dir_conn sdm640_dir_conn[] = { {0, 209}, }; -static const struct msm_pinctrl_soc_data sdm640_pinctrl = { - .pins = sdm640_pins, - .npins = ARRAY_SIZE(sdm640_pins), - .functions = sdm640_functions, - .nfunctions = ARRAY_SIZE(sdm640_functions), - .groups = sdm640_groups, - .ngroups = ARRAY_SIZE(sdm640_groups), +static const struct msm_pinctrl_soc_data sm6150_pinctrl = { + .pins = sm6150_pins, + .npins = ARRAY_SIZE(sm6150_pins), + .functions = sm6150_functions, + .nfunctions = ARRAY_SIZE(sm6150_functions), + .groups = sm6150_groups, + .ngroups = ARRAY_SIZE(sm6150_groups), .ngpios = 123, - .dir_conn = sdm640_dir_conn, - .n_dir_conns = ARRAY_SIZE(sdm640_dir_conn), + .dir_conn = sm6150_dir_conn, + .n_dir_conns = ARRAY_SIZE(sm6150_dir_conn), .dir_conn_irq_base = 216, }; -static int sdm640_pinctrl_probe(struct platform_device *pdev) +static int sm6150_pinctrl_probe(struct platform_device *pdev) { - return msm_pinctrl_probe(pdev, &sdm640_pinctrl); + return msm_pinctrl_probe(pdev, &sm6150_pinctrl); } -static const struct of_device_id sdm640_pinctrl_of_match[] = { - { .compatible = "qcom,sdm640-pinctrl", }, +static const struct of_device_id sm6150_pinctrl_of_match[] = { + { .compatible = "qcom,sm6150-pinctrl", }, { }, }; -static struct platform_driver sdm640_pinctrl_driver = { +static struct platform_driver sm6150_pinctrl_driver = { .driver = { - .name = "sdm640-pinctrl", + .name = "sm6150-pinctrl", .owner = THIS_MODULE, - .of_match_table = sdm640_pinctrl_of_match, + .of_match_table = sm6150_pinctrl_of_match, }, - .probe = sdm640_pinctrl_probe, + .probe = sm6150_pinctrl_probe, .remove = msm_pinctrl_remove, }; -static int __init sdm640_pinctrl_init(void) +static int __init sm6150_pinctrl_init(void) { - return platform_driver_register(&sdm640_pinctrl_driver); + return platform_driver_register(&sm6150_pinctrl_driver); } -arch_initcall(sdm640_pinctrl_init); +arch_initcall(sm6150_pinctrl_init); -static void __exit sdm640_pinctrl_exit(void) +static void __exit sm6150_pinctrl_exit(void) { - platform_driver_unregister(&sdm640_pinctrl_driver); + platform_driver_unregister(&sm6150_pinctrl_driver); } -module_exit(sdm640_pinctrl_exit); +module_exit(sm6150_pinctrl_exit); -MODULE_DESCRIPTION("QTI sdm640 pinctrl driver"); +MODULE_DESCRIPTION("QTI sm6150 pinctrl driver"); MODULE_LICENSE("GPL v2"); -MODULE_DEVICE_TABLE(of, sdm640_pinctrl_of_match); +MODULE_DEVICE_TABLE(of, sm6150_pinctrl_of_match); diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig index ccabe672250a..3c04d023fb54 100644 --- a/drivers/soc/qcom/Kconfig +++ b/drivers/soc/qcom/Kconfig @@ -67,11 +67,11 @@ config QCOM_SDMSHRIKE_LLCC data required to configure LLCC so that clients can start using the LLCC slices. -config QCOM_SDM640_LLCC - tristate "Qualcomm Technologies, Inc. SDM640 LLCC driver" +config QCOM_SM6150_LLCC + tristate "Qualcomm Technologies, Inc. SM6150 LLCC driver" depends on QCOM_LLCC help - Say yes here to enable the LLCC driver for SDM640. This is provides + Say yes here to enable the LLCC driver for SM6150. This is provides data required to configure LLCC so that clients can start using the LLCC slices. diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile index d5bdf2b12065..9c995f1f799b 100644 --- a/drivers/soc/qcom/Makefile +++ b/drivers/soc/qcom/Makefile @@ -7,7 +7,7 @@ obj-$(CONFIG_QCOM_MDT_LOADER) += mdt_loader.o obj-$(CONFIG_QCOM_LLCC) += llcc-core.o llcc-slice.o obj-$(CONFIG_QCOM_SM8150_LLCC) += llcc-sm8150.o obj-$(CONFIG_QCOM_SDMSHRIKE_LLCC) += llcc-sdmshrike.o -obj-$(CONFIG_QCOM_SDM640_LLCC) += llcc-sdm640.o +obj-$(CONFIG_QCOM_SM6150_LLCC) += llcc-sm6150.o obj-$(CONFIG_QCOM_LLCC_AMON) += llcc-amon.o obj-$(CONFIG_QCOM_PM) += spm.o obj-$(CONFIG_QCOM_QMI_HELPERS) += qmi_helpers.o diff --git a/drivers/soc/qcom/llcc-sdm640.c b/drivers/soc/qcom/llcc-sm6150.c similarity index 77% rename from drivers/soc/qcom/llcc-sdm640.c rename to drivers/soc/qcom/llcc-sm6150.c index f746e1ec4269..b6dfbd3d55d4 100644 --- a/drivers/soc/qcom/llcc-sdm640.c +++ b/drivers/soc/qcom/llcc-sm6150.c @@ -56,44 +56,44 @@ .activate_on_init = a, \ } -static struct llcc_slice_config sdm640_data[] = { +static struct llcc_slice_config sm6150_data[] = { SCT_ENTRY("cpuss", 1, 1, 256, 1, 0, 0xF, 0x0, 0, 0, 0, 1, 1), SCT_ENTRY("modem", 8, 8, 256, 1, 0, 0xF, 0x0, 0, 0, 0, 1, 0), SCT_ENTRY("mmuhwt", 13, 13, 256, 1, 0, 0xF, 0x0, 0, 0, 0, 0, 1), }; -static int sdm640_qcom_llcc_probe(struct platform_device *pdev) +static int sm6150_qcom_llcc_probe(struct platform_device *pdev) { - return qcom_llcc_probe(pdev, sdm640_data, - ARRAY_SIZE(sdm640_data)); + return qcom_llcc_probe(pdev, sm6150_data, + ARRAY_SIZE(sm6150_data)); } -static const struct of_device_id sdm640_qcom_llcc_of_match[] = { - { .compatible = "qcom,sdm640-llcc", }, +static const struct of_device_id sm6150_qcom_llcc_of_match[] = { + { .compatible = "qcom,sm6150-llcc", }, { }, }; -static struct platform_driver sdm640_qcom_llcc_driver = { +static struct platform_driver sm6150_qcom_llcc_driver = { .driver = { - .name = "sdm640-llcc", + .name = "sm6150-llcc", .owner = THIS_MODULE, - .of_match_table = sdm640_qcom_llcc_of_match, + .of_match_table = sm6150_qcom_llcc_of_match, }, - .probe = sdm640_qcom_llcc_probe, + .probe = sm6150_qcom_llcc_probe, .remove = qcom_llcc_remove, }; -static int __init sdm640_init_qcom_llcc_init(void) +static int __init sm6150_init_qcom_llcc_init(void) { - return platform_driver_register(&sdm640_qcom_llcc_driver); + return platform_driver_register(&sm6150_qcom_llcc_driver); } -module_init(sdm640_init_qcom_llcc_init); +module_init(sm6150_init_qcom_llcc_init); -static void __exit sdm640_exit_qcom_llcc_exit(void) +static void __exit sm6150_exit_qcom_llcc_exit(void) { - platform_driver_unregister(&sdm640_qcom_llcc_driver); + platform_driver_unregister(&sm6150_qcom_llcc_driver); } -module_exit(sdm640_exit_qcom_llcc_exit); +module_exit(sm6150_exit_qcom_llcc_exit); -MODULE_DESCRIPTION("Qualcomm Technologies Inc sdm640 LLCC driver"); +MODULE_DESCRIPTION("Qualcomm Technologies Inc sm6150 LLCC driver"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/soc/qcom/socinfo.c b/drivers/soc/qcom/socinfo.c index b4132861a773..f39317c63aa6 100644 --- a/drivers/soc/qcom/socinfo.c +++ b/drivers/soc/qcom/socinfo.c @@ -310,8 +310,8 @@ static struct msm_soc_info cpu_of_id[] = { /* sdmshrike ID */ [340] = {MSM_CPU_SDMSHRIKE, "SDMSHRIKE"}, - /* sdm640 ID */ - [355] = {MSM_CPU_SDM640, "SDM640"}, + /* sm6150 ID */ + [355] = {MSM_CPU_SM6150, "SM6150"}, /* qcs405 ID */ [352] = {MSM_CPU_QCS405, "QCS405"}, @@ -1175,9 +1175,9 @@ static void * __init setup_dummy_socinfo(void) dummy_socinfo.id = 340; strlcpy(dummy_socinfo.build_id, "sdmshrike - ", sizeof(dummy_socinfo.build_id)); - } else if (early_machine_is_sdm640()) { + } else if (early_machine_is_sm6150()) { dummy_socinfo.id = 355; - strlcpy(dummy_socinfo.build_id, "sdm640 - ", + strlcpy(dummy_socinfo.build_id, "sm6150 - ", sizeof(dummy_socinfo.build_id)); } else if (early_machine_is_qcs405()) { dummy_socinfo.id = 352; diff --git a/include/dt-bindings/clock/qcom,camcc-sdm640.h b/include/dt-bindings/clock/qcom,camcc-sm6150.h similarity index 97% rename from include/dt-bindings/clock/qcom,camcc-sdm640.h rename to include/dt-bindings/clock/qcom,camcc-sm6150.h index c409704772b7..65a64f8d9f29 100644 --- a/include/dt-bindings/clock/qcom,camcc-sdm640.h +++ b/include/dt-bindings/clock/qcom,camcc-sm6150.h @@ -11,8 +11,8 @@ * GNU General Public License for more details. */ -#ifndef _DT_BINDINGS_CLK_QCOM_CAM_CC_SDM640_H -#define _DT_BINDINGS_CLK_QCOM_CAM_CC_SDM640_H +#ifndef _DT_BINDINGS_CLK_QCOM_CAM_CC_SM6150_H +#define _DT_BINDINGS_CLK_QCOM_CAM_CC_SM6150_H #define CAM_CC_BPS_AHB_CLK 0 #define CAM_CC_BPS_AREG_CLK 1 diff --git a/include/dt-bindings/clock/qcom,cpucc-sdm640.h b/include/dt-bindings/clock/qcom,cpucc-sm6150.h similarity index 91% rename from include/dt-bindings/clock/qcom,cpucc-sdm640.h rename to include/dt-bindings/clock/qcom,cpucc-sm6150.h index cafa178f8549..2a60ef821775 100644 --- a/include/dt-bindings/clock/qcom,cpucc-sdm640.h +++ b/include/dt-bindings/clock/qcom,cpucc-sm6150.h @@ -11,8 +11,8 @@ * GNU General Public License for more details. */ -#ifndef _DT_BINDINGS_CLK_QCOM_CPU_CC_SDM640_H -#define _DT_BINDINGS_CLK_QCOM_CPU_CC_SDM640_H +#ifndef _DT_BINDINGS_CLK_QCOM_CPU_CC_SM6150_H +#define _DT_BINDINGS_CLK_QCOM_CPU_CC_SM6150_H #define PWRCL_CLK 0 #define PERFCL_CLK 1 diff --git a/include/dt-bindings/clock/qcom,dispcc-sdm640.h b/include/dt-bindings/clock/qcom,dispcc-sm6150.h similarity index 95% rename from include/dt-bindings/clock/qcom,dispcc-sdm640.h rename to include/dt-bindings/clock/qcom,dispcc-sm6150.h index c80063e18f98..dc002dbdfba3 100644 --- a/include/dt-bindings/clock/qcom,dispcc-sdm640.h +++ b/include/dt-bindings/clock/qcom,dispcc-sm6150.h @@ -11,8 +11,8 @@ * GNU General Public License for more details. */ -#ifndef _DT_BINDINGS_CLK_QCOM_DISP_CC_SDM640_H -#define _DT_BINDINGS_CLK_QCOM_DISP_CC_SDM640_H +#ifndef _DT_BINDINGS_CLK_QCOM_DISP_CC_SM6150_H +#define _DT_BINDINGS_CLK_QCOM_DISP_CC_SM6150_H #define DISP_CC_DEBUG_CLK 0 #define DISP_CC_MDSS_AHB_CLK 1 diff --git a/include/dt-bindings/clock/qcom,gcc-sdm640.h b/include/dt-bindings/clock/qcom,gcc-sm6150.h similarity index 98% rename from include/dt-bindings/clock/qcom,gcc-sdm640.h rename to include/dt-bindings/clock/qcom,gcc-sm6150.h index db0355272d2a..711f19c1d55d 100644 --- a/include/dt-bindings/clock/qcom,gcc-sdm640.h +++ b/include/dt-bindings/clock/qcom,gcc-sm6150.h @@ -11,8 +11,8 @@ * GNU General Public License for more details. */ -#ifndef _DT_BINDINGS_CLK_QCOM_GCC_SDM640_H -#define _DT_BINDINGS_CLK_QCOM_GCC_SDM640_H +#ifndef _DT_BINDINGS_CLK_QCOM_GCC_SM6150_H +#define _DT_BINDINGS_CLK_QCOM_GCC_SM6150_H #define GCC_AGGRE_UFS_PHY_AXI_CLK 0 #define GCC_AGGRE_UFS_PHY_AXI_HW_CTL_CLK 1 diff --git a/include/dt-bindings/clock/qcom,gpucc-sdm640.h b/include/dt-bindings/clock/qcom,gpucc-sm6150.h similarity index 94% rename from include/dt-bindings/clock/qcom,gpucc-sdm640.h rename to include/dt-bindings/clock/qcom,gpucc-sm6150.h index 4e14ac0d1833..15ad06ad4e7d 100644 --- a/include/dt-bindings/clock/qcom,gpucc-sdm640.h +++ b/include/dt-bindings/clock/qcom,gpucc-sm6150.h @@ -11,8 +11,8 @@ * GNU General Public License for more details. */ -#ifndef _DT_BINDINGS_CLK_QCOM_GPU_CC_SDM640_H -#define _DT_BINDINGS_CLK_QCOM_GPU_CC_SDM640_H +#ifndef _DT_BINDINGS_CLK_QCOM_GPU_CC_SM6150_H +#define _DT_BINDINGS_CLK_QCOM_GPU_CC_SM6150_H #define GPU_CC_AHB_CLK 0 #define GPU_CC_CRC_AHB_CLK 1 diff --git a/include/dt-bindings/clock/qcom,videocc-sdm640.h b/include/dt-bindings/clock/qcom,videocc-sm6150.h similarity index 92% rename from include/dt-bindings/clock/qcom,videocc-sdm640.h rename to include/dt-bindings/clock/qcom,videocc-sm6150.h index ba29726911ea..be71dfb72427 100644 --- a/include/dt-bindings/clock/qcom,videocc-sdm640.h +++ b/include/dt-bindings/clock/qcom,videocc-sm6150.h @@ -11,8 +11,8 @@ * GNU General Public License for more details. */ -#ifndef _DT_BINDINGS_CLK_QCOM_VIDEO_CC_SDM640_H -#define _DT_BINDINGS_CLK_QCOM_VIDEO_CC_SDM640_H +#ifndef _DT_BINDINGS_CLK_QCOM_VIDEO_CC_SM6150_H +#define _DT_BINDINGS_CLK_QCOM_VIDEO_CC_SM6150_H #define VIDEO_CC_APB_CLK 0 #define VIDEO_CC_AT_CLK 1 diff --git a/include/soc/qcom/socinfo.h b/include/soc/qcom/socinfo.h index 224a2f1cb005..62074135a3e3 100644 --- a/include/soc/qcom/socinfo.h +++ b/include/soc/qcom/socinfo.h @@ -61,8 +61,8 @@ of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,sm8150") #define early_machine_is_sdmshrike() \ of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,sdmshrike") -#define early_machine_is_sdm640() \ - of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,sdm640") +#define early_machine_is_sm6150() \ + of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,sm6150") #define early_machine_is_qcs405() \ of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,qcs405") #else @@ -85,7 +85,7 @@ #define early_machine_is_msm8996() 0 #define early_machine_is_sm8150() 0 #define early_machine_is_sdmshrike() 0 -#define early_machine_is_sdm640() 0 +#define early_machine_is_sm6150() 0 #define early_machine_is_qcs405() 0 #endif @@ -109,7 +109,7 @@ enum msm_cpu { MSM_CPU_8996, MSM_CPU_SM8150, MSM_CPU_SDMSHRIKE, - MSM_CPU_SDM640, + MSM_CPU_SM6150, MSM_CPU_QCS405, }; -- GitLab From ca1e8d5910297b5a6d69add7b7f3b0c74b69e236 Mon Sep 17 00:00:00 2001 From: Veera Sundaram Sankaran Date: Wed, 2 May 2018 19:30:36 -0700 Subject: [PATCH 1401/1635] drm/msm: handle dma_map_attachment before physical address access The scatter gather table might not be populated while trying to access the dma_addr of secure-ui/secure-camera buffers. The physical and dma address are accessible only through the sg_table. Make sure dma_map_attachment is done before accessing the dma/phy address. Change-Id: I3efe953a45fdda155af570d89a92c968c0151d7f Signed-off-by: Veera Sundaram Sankaran --- drivers/gpu/drm/msm/msm_gem.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/msm/msm_gem.c b/drivers/gpu/drm/msm/msm_gem.c index ee81014c6278..ba2b63798973 100644 --- a/drivers/gpu/drm/msm/msm_gem.c +++ b/drivers/gpu/drm/msm/msm_gem.c @@ -323,14 +323,20 @@ uint64_t msm_gem_mmap_offset(struct drm_gem_object *obj) dma_addr_t msm_gem_get_dma_addr(struct drm_gem_object *obj) { struct msm_gem_object *msm_obj = to_msm_bo(obj); - struct drm_device *dev = obj->dev; + struct sg_table *sgt; - if (IS_ERR_OR_NULL(msm_obj->sgt)) { - dev_err(dev->dev, "invalid scatter/gather table\n"); - return 0; + if (!msm_obj->sgt) { + sgt = dma_buf_map_attachment(obj->import_attach, + DMA_BIDIRECTIONAL); + if (IS_ERR_OR_NULL(sgt)) { + DRM_ERROR("dma_buf_map_attachment failure, err=%d\n", + PTR_ERR(sgt)); + return 0; + } + msm_obj->sgt = sgt; } - return sg_dma_address(msm_obj->sgt->sgl); + return sg_phys(msm_obj->sgt->sgl); } static struct msm_gem_vma *add_vma(struct drm_gem_object *obj, -- GitLab From 176456415bcd4a336db9220b53e0001f082f1f27 Mon Sep 17 00:00:00 2001 From: Satya Durga Srinivasu Prabhala Date: Fri, 4 May 2018 12:31:47 -0700 Subject: [PATCH 1402/1635] sched/fair: always use task_fits_max check task_fits_max calls task_fits_capacity if the CPU is not the max capacity CPU. Instead of using both the APIs stick to single API. Change-Id: Iaa6ddfc352dfa954c9d3a0bb2ed1ad034bec85cf Signed-off-by: Satya Durga Srinivasu Prabhala --- kernel/sched/fair.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index 5080196187b8..ac12f1ee912b 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -6965,15 +6965,11 @@ static int cpu_util_wake(int cpu, struct task_struct *p) return (util >= capacity) ? capacity : util; } -static inline int task_fits_capacity(struct task_struct *p, +static inline bool task_fits_capacity(struct task_struct *p, long capacity, int cpu) { unsigned int margin; - unsigned long max_capacity = cpu_rq(cpu)->rd->max_cpu_capacity; - - if (capacity == max_capacity) - return true; if (capacity_orig_of(task_cpu(p)) > capacity_orig_of(cpu)) margin = sched_capacity_margin_down[task_cpu(p)]; @@ -7401,7 +7397,7 @@ static int wake_cap(struct task_struct *p, int cpu, int prev_cpu) /* Bring task utilization in sync with prev_cpu */ sync_entity_load_avg(&p->se); - return !task_fits_capacity(p, min_cap, cpu); + return !task_fits_max(p, cpu); } bool __cpu_overutilized(int cpu, int delta) @@ -8126,8 +8122,7 @@ static void check_preempt_wakeup(struct rq *rq, struct task_struct *p, int wake_ static inline void update_misfit_task(struct rq *rq, struct task_struct *p) { #ifdef CONFIG_SMP - rq->misfit_task = !task_fits_capacity(p, capacity_orig_of(rq->cpu), - rq->cpu); + rq->misfit_task = !task_fits_max(p, rq->cpu); #endif } -- GitLab From e12d0c6a3c3f7c88d46f5853de0dc4847b741e1c Mon Sep 17 00:00:00 2001 From: "Isaac J. Manjarres" Date: Fri, 4 May 2018 13:47:27 -0700 Subject: [PATCH 1403/1635] Revert "defconfig: Enable full reference count validation" This reverts commit 19dd742f109f5ddb3cdd0c79d4acee2876f442af. Change-Id: I6f241fc30dce4e85d3a10a535a8eb957b6a94970 Signed-off-by: Isaac J. Manjarres --- arch/arm64/configs/sm8150-perf_defconfig | 1 - arch/arm64/configs/sm8150_defconfig | 1 - 2 files changed, 2 deletions(-) diff --git a/arch/arm64/configs/sm8150-perf_defconfig b/arch/arm64/configs/sm8150-perf_defconfig index 8eb58176dcab..ad1124c9aaa4 100644 --- a/arch/arm64/configs/sm8150-perf_defconfig +++ b/arch/arm64/configs/sm8150-perf_defconfig @@ -43,7 +43,6 @@ CONFIG_SLAB_FREELIST_RANDOM=y CONFIG_SLAB_FREELIST_HARDENED=y CONFIG_PROFILING=y CONFIG_CC_STACKPROTECTOR_STRONG=y -CONFIG_REFCOUNT_FULL=y CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y CONFIG_MODULE_FORCE_UNLOAD=y diff --git a/arch/arm64/configs/sm8150_defconfig b/arch/arm64/configs/sm8150_defconfig index aec7ee989375..b27fb82a3307 100644 --- a/arch/arm64/configs/sm8150_defconfig +++ b/arch/arm64/configs/sm8150_defconfig @@ -43,7 +43,6 @@ CONFIG_SLAB_FREELIST_RANDOM=y CONFIG_SLAB_FREELIST_HARDENED=y CONFIG_PROFILING=y CONFIG_CC_STACKPROTECTOR_STRONG=y -CONFIG_REFCOUNT_FULL=y CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y CONFIG_MODULE_FORCE_UNLOAD=y -- GitLab From 0518b7028ace397c9b319b8504e4493edc580ce0 Mon Sep 17 00:00:00 2001 From: Vaibhav Deshu Venkatesh Date: Fri, 4 May 2018 14:34:48 -0700 Subject: [PATCH 1404/1635] msm: vidc: Add support for Adaptive B Add support to enable/disable adaptive B frames. It is enabled by default by firmware. CRs-Fixed: 2234389 Change-Id: Ia1cf6338430448151dd6f6f1cd93a9a967944cf2 Signed-off-by: Vaibhav Deshu Venkatesh --- .../media/platform/msm/vidc/hfi_packetization.c | 8 ++++++++ drivers/media/platform/msm/vidc/msm_venc.c | 14 ++++++++++++++ drivers/media/platform/msm/vidc/vidc_hfi_api.h | 1 + drivers/media/platform/msm/vidc/vidc_hfi_helper.h | 2 ++ include/uapi/linux/v4l2-controls.h | 3 +++ 5 files changed, 28 insertions(+) diff --git a/drivers/media/platform/msm/vidc/hfi_packetization.c b/drivers/media/platform/msm/vidc/hfi_packetization.c index c461e6c1ae8b..2e335fdf6552 100644 --- a/drivers/media/platform/msm/vidc/hfi_packetization.c +++ b/drivers/media/platform/msm/vidc/hfi_packetization.c @@ -1377,6 +1377,14 @@ int create_pkt_cmd_session_set_property( pkt->size += sizeof(u32); break; } + case HAL_PARAM_VENC_ADAPTIVE_B: + { + create_pkt_enable(pkt->rg_property_data, + HFI_PROPERTY_PARAM_VENC_ADAPTIVE_B, + ((struct hal_enable *)pdata)->enable); + pkt->size += sizeof(struct hfi_enable); + break; + } case HAL_PARAM_VDEC_CONCEAL_COLOR: { struct hfi_conceal_color *hfi; diff --git a/drivers/media/platform/msm/vidc/msm_venc.c b/drivers/media/platform/msm/vidc/msm_venc.c index 2ac86ca75a69..a768ef00e13f 100644 --- a/drivers/media/platform/msm/vidc/msm_venc.c +++ b/drivers/media/platform/msm/vidc/msm_venc.c @@ -291,6 +291,15 @@ static struct msm_vidc_ctrl msm_venc_ctrls[] = { .menu_skip_mask = 0, .qmenu = NULL, }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_ADAPTIVE_B, + .name = "Adaptive B frames", + .type = V4L2_CTRL_TYPE_BOOLEAN, + .minimum = V4L2_MPEG_MSM_VIDC_DISABLE, + .maximum = V4L2_MPEG_MSM_VIDC_ENABLE, + .default_value = V4L2_MPEG_MSM_VIDC_ENABLE, + .step = 1, + }, { .id = V4L2_CID_MIN_BUFFERS_FOR_CAPTURE, .name = "CAPTURE Count", @@ -1307,6 +1316,11 @@ int msm_venc_s_ctrl(struct msm_vidc_inst *inst, struct v4l2_ctrl *ctrl) pdata = &intra_period; break; } + case V4L2_CID_MPEG_VIDC_VIDEO_ADAPTIVE_B: + property_id = HAL_PARAM_VENC_ADAPTIVE_B; + enable.enable = ctrl->val; + pdata = &enable; + break; case V4L2_CID_MPEG_VIDC_VIDEO_REQUEST_IFRAME: property_id = HAL_CONFIG_VENC_REQUEST_IFRAME; request_iframe.enable = true; diff --git a/drivers/media/platform/msm/vidc/vidc_hfi_api.h b/drivers/media/platform/msm/vidc/vidc_hfi_api.h index 2a9cab047ff2..5c690843748d 100644 --- a/drivers/media/platform/msm/vidc/vidc_hfi_api.h +++ b/drivers/media/platform/msm/vidc/vidc_hfi_api.h @@ -145,6 +145,7 @@ enum hal_property { HAL_PARAM_VENC_SESSION_QP_RANGE, HAL_CONFIG_VENC_INTRA_PERIOD, HAL_CONFIG_VENC_IDR_PERIOD, + HAL_PARAM_VENC_ADAPTIVE_B, HAL_PARAM_VPE_ROTATION, HAL_PARAM_VENC_INTRA_REFRESH, HAL_PARAM_VENC_MULTI_SLICE_CONTROL, diff --git a/drivers/media/platform/msm/vidc/vidc_hfi_helper.h b/drivers/media/platform/msm/vidc/vidc_hfi_helper.h index 467c56bb3795..481c7bb61bce 100644 --- a/drivers/media/platform/msm/vidc/vidc_hfi_helper.h +++ b/drivers/media/platform/msm/vidc/vidc_hfi_helper.h @@ -327,6 +327,8 @@ struct hfi_buffer_info { (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x035) #define HFI_PROPERTY_PARAM_VENC_HDR10_PQ_SEI \ (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x036) +#define HFI_PROPERTY_PARAM_VENC_ADAPTIVE_B \ + (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x037) #define HFI_PROPERTY_CONFIG_VENC_COMMON_START \ (HFI_DOMAIN_BASE_VENC + HFI_ARCH_COMMON_OFFSET + 0x6000) diff --git a/include/uapi/linux/v4l2-controls.h b/include/uapi/linux/v4l2-controls.h index 603cd4692f2c..e2db9b17fbeb 100644 --- a/include/uapi/linux/v4l2-controls.h +++ b/include/uapi/linux/v4l2-controls.h @@ -930,6 +930,9 @@ enum v4l2_mpeg_vidc_video_vp9_level { V4L2_MPEG_VIDC_VIDEO_VP9_LEVEL_51 = 10, }; +#define V4L2_CID_MPEG_VIDC_VIDEO_ADAPTIVE_B \ + (V4L2_CID_MPEG_MSM_VIDC_BASE + 98) + #define V4L2_CID_MPEG_VIDC_VIDEO_I_FRAME_QP \ (V4L2_CID_MPEG_MSM_VIDC_BASE + 99) #define V4L2_CID_MPEG_VIDC_VIDEO_P_FRAME_QP \ -- GitLab From 97013cb4cfd087c0baa7dac1a8256205cfb319b4 Mon Sep 17 00:00:00 2001 From: Abhijit Kulkarni Date: Thu, 26 Apr 2018 17:51:40 -0700 Subject: [PATCH 1405/1635] ARM: msm: dts: remove active vote from reg-bus on sm8150 This change removes the active vote on register bus. This change is required with the MMCX separation since display driver now turns off the MMCX, so bus driver should not touch any display registers when the cpus go to idle state. Change-Id: Ife70c81d8b7df6285121fcb212d637c25eb46b54 Signed-off-by: Abhijit Kulkarni --- arch/arm64/boot/dts/qcom/sm8150-sde.dtsi | 2 -- 1 file changed, 2 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sm8150-sde.dtsi b/arch/arm64/boot/dts/qcom/sm8150-sde.dtsi index a102ad743a96..eff0dd5a463b 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-sde.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-sde.dtsi @@ -313,7 +313,6 @@ qcom,msm-bus,name = "mdss_reg"; qcom,msm-bus,num-cases = <4>; qcom,msm-bus,num-paths = <1>; - qcom,msm-bus,active-only; qcom,msm-bus,vectors-KBps = <1 590 0 0>, <1 590 0 76800>, @@ -457,7 +456,6 @@ qcom,msm-bus,name = "mdss_rot_reg"; qcom,msm-bus,num-cases = <2>; qcom,msm-bus,num-paths = <1>; - qcom,msm-bus,active-only; qcom,msm-bus,vectors-KBps = <1 590 0 0>, <1 590 0 76800>; -- GitLab From 8cb7ad2858d593a5706a9a8f7a65e932cd04f2fb Mon Sep 17 00:00:00 2001 From: Deepak Katragadda Date: Tue, 1 May 2018 10:39:11 -0700 Subject: [PATCH 1406/1635] clk: qcom: debugcc-sm8150: Remove measurement support for unused clocks Clock framework limits the number of parents for any clock to 256. Remove support for rarely used clocks that have been listed as parents for the GCC debug mux in order to work around this issue temporarily. Change-Id: I21c537c284b235584104dbab060a3684f818645b Signed-off-by: Deepak Katragadda --- drivers/clk/qcom/debugcc-sm8150.c | 87 ------------------------------- 1 file changed, 87 deletions(-) diff --git a/drivers/clk/qcom/debugcc-sm8150.c b/drivers/clk/qcom/debugcc-sm8150.c index e16102c23b56..889880b1bdbc 100644 --- a/drivers/clk/qcom/debugcc-sm8150.c +++ b/drivers/clk/qcom/debugcc-sm8150.c @@ -53,7 +53,6 @@ static const char *const debug_mux_parent_names[] = { "cam_cc_csiphy3_clk", "cam_cc_fd_core_clk", "cam_cc_fd_core_uar_clk", - "cam_cc_gdsc_clk", "cam_cc_icp_ahb_clk", "cam_cc_icp_clk", "cam_cc_ife_0_axi_clk", @@ -86,8 +85,6 @@ static const char *const debug_mux_parent_names[] = { "cam_cc_mclk1_clk", "cam_cc_mclk2_clk", "cam_cc_mclk3_clk", - "cam_cc_qdss_debug_clk", - "cam_cc_qdss_debug_xo_clk", "disp_cc_mdss_ahb_clk", "disp_cc_mdss_byte0_clk", "disp_cc_mdss_byte0_intf_clk", @@ -130,7 +127,6 @@ static const char *const debug_mux_parent_names[] = { "gcc_aggre_ufs_phy_axi_clk", "gcc_aggre_usb3_prim_axi_clk", "gcc_aggre_usb3_sec_axi_clk", - "gcc_boot_rom_ahb_clk", "gcc_camera_ahb_clk", "gcc_camera_hf_axi_clk", "gcc_camera_sf_axi_clk", @@ -141,8 +137,6 @@ static const char *const debug_mux_parent_names[] = { "gcc_cfg_noc_usb3_prim_axi_clk", "gcc_cfg_noc_usb3_sec_axi_clk", "gcc_cpuss_ahb_clk", - "gcc_cpuss_dvm_bus_clk", - "gcc_cpuss_gnoc_clk", "gcc_cpuss_rbcpr_clk", "gcc_ddrss_gpu_axi_clk", "gcc_disp_ahb_clk", @@ -186,11 +180,6 @@ static const char *const debug_mux_parent_names[] = { "gcc_pdm_ahb_clk", "gcc_pdm_xo4_clk", "gcc_prng_ahb_clk", - "gcc_qmip_camera_nrt_ahb_clk", - "gcc_qmip_camera_rt_ahb_clk", - "gcc_qmip_disp_ahb_clk", - "gcc_qmip_video_cvp_ahb_clk", - "gcc_qmip_video_vcodec_ahb_clk", "gcc_qspi_cnoc_periph_ahb_clk", "gcc_qspi_core_clk", "gcc_qupv3_wrap0_core_2x_clk", @@ -219,19 +208,12 @@ static const char *const debug_mux_parent_names[] = { "gcc_qupv3_wrap2_s3_clk", "gcc_qupv3_wrap2_s4_clk", "gcc_qupv3_wrap2_s5_clk", - "gcc_qupv3_wrap_0_m_ahb_clk", - "gcc_qupv3_wrap_0_s_ahb_clk", - "gcc_qupv3_wrap_1_m_ahb_clk", - "gcc_qupv3_wrap_1_s_ahb_clk", - "gcc_qupv3_wrap_2_m_ahb_clk", - "gcc_qupv3_wrap_2_s_ahb_clk", "gcc_sdcc2_ahb_clk", "gcc_sdcc2_apps_clk", "gcc_sdcc4_ahb_clk", "gcc_sdcc4_apps_clk", "gcc_sys_noc_cpuss_ahb_clk", "gcc_tsif_ahb_clk", - "gcc_tsif_inactivity_timers_clk", "gcc_tsif_ref_clk", "gcc_ufs_card_ahb_clk", "gcc_ufs_card_axi_clk", @@ -251,10 +233,8 @@ static const char *const debug_mux_parent_names[] = { "gcc_ufs_phy_unipro_core_clk", "gcc_usb30_prim_master_clk", "gcc_usb30_prim_mock_utmi_clk", - "gcc_usb30_prim_sleep_clk", "gcc_usb30_sec_master_clk", "gcc_usb30_sec_mock_utmi_clk", - "gcc_usb30_sec_sleep_clk", "gcc_usb3_prim_phy_aux_clk", "gcc_usb3_prim_phy_com_aux_clk", "gcc_usb3_prim_phy_pipe_clk", @@ -266,22 +246,16 @@ static const char *const debug_mux_parent_names[] = { "gcc_video_axi1_clk", "gcc_video_axic_clk", "gcc_video_xo_clk", - "gpu_cc_acd_ahb_clk", - "gpu_cc_acd_cxo_clk", "gpu_cc_ahb_clk", - "gpu_cc_crc_ahb_clk", "gpu_cc_cx_apb_clk", "gpu_cc_cx_gmu_clk", "gpu_cc_cx_qdss_at_clk", "gpu_cc_cx_qdss_trig_clk", - "gpu_cc_cx_qdss_tsctr_clk", "gpu_cc_cx_snoc_dvm_clk", "gpu_cc_cxo_aon_clk", "gpu_cc_cxo_clk", "gpu_cc_gx_gmu_clk", - "gpu_cc_gx_qdss_tsctr_clk", "gpu_cc_gx_vsense_clk", - "gpu_cc_sleep_clk", "measure_only_gpu_cc_cx_gfx3d_clk", "measure_only_gpu_cc_cx_gfx3d_slv_clk", "measure_only_gpu_cc_gx_gfx3d_clk", @@ -297,10 +271,7 @@ static const char *const debug_mux_parent_names[] = { "npu_cc_npu_core_clk", "npu_cc_npu_core_cti_clk", "npu_cc_npu_cpc_clk", - "npu_cc_npu_cpc_timer_clk", "npu_cc_perf_cnt_clk", - "npu_cc_qtimer_core_clk", - "npu_cc_sleep_clk", "npu_cc_xo_clk", "video_cc_iris_ahb_clk", "video_cc_mvs0_core_clk", @@ -359,8 +330,6 @@ static struct clk_debug_mux gcc_debug_mux = { 0x28, 0xFF, 0, 0xF, 0, 4, 0xD000, 0xD004, 0xD008 }, { "cam_cc_fd_core_uar_clk", 0x55, 1, CAM_CC, 0x29, 0xFF, 0, 0xF, 0, 4, 0xD000, 0xD004, 0xD008 }, - { "cam_cc_gdsc_clk", 0x55, 1, CAM_CC, - 0x3C, 0xFF, 0, 0xF, 0, 4, 0xD000, 0xD004, 0xD008 }, { "cam_cc_icp_ahb_clk", 0x55, 1, CAM_CC, 0x37, 0xFF, 0, 0xF, 0, 4, 0xD000, 0xD004, 0xD008 }, { "cam_cc_icp_clk", 0x55, 1, CAM_CC, @@ -425,10 +394,6 @@ static struct clk_debug_mux gcc_debug_mux = { 0x3, 0xFF, 0, 0xF, 0, 4, 0xD000, 0xD004, 0xD008 }, { "cam_cc_mclk3_clk", 0x55, 1, CAM_CC, 0x4, 0xFF, 0, 0xF, 0, 4, 0xD000, 0xD004, 0xD008 }, - { "cam_cc_qdss_debug_clk", 0x55, 1, CAM_CC, - 0x3D, 0xFF, 0, 0xF, 0, 4, 0xD000, 0xD004, 0xD008 }, - { "cam_cc_qdss_debug_xo_clk", 0x55, 1, CAM_CC, - 0x3E, 0xFF, 0, 0xF, 0, 4, 0xD000, 0xD004, 0xD008 }, { "disp_cc_mdss_ahb_clk", 0x56, 1, DISP_CC, 0x2B, 0xFF, 0, 0x3, 0, 4, 0x7000, 0x5008, 0x500C }, { "disp_cc_mdss_byte0_clk", 0x56, 1, DISP_CC, @@ -513,8 +478,6 @@ static struct clk_debug_mux gcc_debug_mux = { 0x13E, 0x3FF, 0, 0xF, 0, 1, 0x62000, 0x62004, 0x62008 }, { "gcc_aggre_usb3_sec_axi_clk", 0x13F, 1, GCC, 0x13F, 0x3FF, 0, 0xF, 0, 1, 0x62000, 0x62004, 0x62008 }, - { "gcc_boot_rom_ahb_clk", 0xA0, 1, GCC, - 0xA0, 0x3FF, 0, 0xF, 0, 1, 0x62000, 0x62004, 0x62008 }, { "gcc_camera_ahb_clk", 0x43, 1, GCC, 0x43, 0x3FF, 0, 0xF, 0, 1, 0x62000, 0x62004, 0x62008 }, { "gcc_camera_hf_axi_clk", 0x4D, 1, GCC, @@ -535,10 +498,6 @@ static struct clk_debug_mux gcc_debug_mux = { 0x23, 0x3FF, 0, 0xF, 0, 1, 0x62000, 0x62004, 0x62008 }, { "gcc_cpuss_ahb_clk", 0xE0, 1, GCC, 0xE0, 0x3FF, 0, 0xF, 0, 1, 0x62000, 0x62004, 0x62008 }, - { "gcc_cpuss_dvm_bus_clk", 0xE5, 1, GCC, - 0xE5, 0x3FF, 0, 0xF, 0, 1, 0x62000, 0x62004, 0x62008 }, - { "gcc_cpuss_gnoc_clk", 0xE1, 1, GCC, - 0xE1, 0x3FF, 0, 0xF, 0, 1, 0x62000, 0x62004, 0x62008 }, { "gcc_cpuss_rbcpr_clk", 0xE2, 1, GCC, 0xE2, 0x3FF, 0, 0xF, 0, 1, 0x62000, 0x62004, 0x62008 }, { "gcc_ddrss_gpu_axi_clk", 0xC0, 1, GCC, @@ -625,16 +584,6 @@ static struct clk_debug_mux gcc_debug_mux = { 0x99, 0x3FF, 0, 0xF, 0, 1, 0x62000, 0x62004, 0x62008 }, { "gcc_prng_ahb_clk", 0x9B, 1, GCC, 0x9B, 0x3FF, 0, 0xF, 0, 1, 0x62000, 0x62004, 0x62008 }, - { "gcc_qmip_camera_nrt_ahb_clk", 0x47, 1, GCC, - 0x47, 0x3FF, 0, 0xF, 0, 1, 0x62000, 0x62004, 0x62008 }, - { "gcc_qmip_camera_rt_ahb_clk", 0x48, 1, GCC, - 0x48, 0x3FF, 0, 0xF, 0, 1, 0x62000, 0x62004, 0x62008 }, - { "gcc_qmip_disp_ahb_clk", 0x49, 1, GCC, - 0x49, 0x3FF, 0, 0xF, 0, 1, 0x62000, 0x62004, 0x62008 }, - { "gcc_qmip_video_cvp_ahb_clk", 0x45, 1, GCC, - 0x45, 0x3FF, 0, 0xF, 0, 1, 0x62000, 0x62004, 0x62008 }, - { "gcc_qmip_video_vcodec_ahb_clk", 0x46, 1, GCC, - 0x46, 0x3FF, 0, 0xF, 0, 1, 0x62000, 0x62004, 0x62008 }, { "gcc_qspi_cnoc_periph_ahb_clk", 0x178, 1, GCC, 0x178, 0x3FF, 0, 0xF, 0, 1, 0x62000, 0x62004, 0x62008 }, { "gcc_qspi_core_clk", 0x179, 1, GCC, @@ -691,18 +640,6 @@ static struct clk_debug_mux gcc_debug_mux = { 0x189, 0x3FF, 0, 0xF, 0, 1, 0x62000, 0x62004, 0x62008 }, { "gcc_qupv3_wrap2_s5_clk", 0x18A, 1, GCC, 0x18A, 0x3FF, 0, 0xF, 0, 1, 0x62000, 0x62004, 0x62008 }, - { "gcc_qupv3_wrap_0_m_ahb_clk", 0x82, 1, GCC, - 0x82, 0x3FF, 0, 0xF, 0, 1, 0x62000, 0x62004, 0x62008 }, - { "gcc_qupv3_wrap_0_s_ahb_clk", 0x83, 1, GCC, - 0x83, 0x3FF, 0, 0xF, 0, 1, 0x62000, 0x62004, 0x62008 }, - { "gcc_qupv3_wrap_1_m_ahb_clk", 0x8E, 1, GCC, - 0x8E, 0x3FF, 0, 0xF, 0, 1, 0x62000, 0x62004, 0x62008 }, - { "gcc_qupv3_wrap_1_s_ahb_clk", 0x8F, 1, GCC, - 0x8F, 0x3FF, 0, 0xF, 0, 1, 0x62000, 0x62004, 0x62008 }, - { "gcc_qupv3_wrap_2_m_ahb_clk", 0x181, 1, GCC, - 0x181, 0x3FF, 0, 0xF, 0, 1, 0x62000, 0x62004, 0x62008 }, - { "gcc_qupv3_wrap_2_s_ahb_clk", 0x182, 1, GCC, - 0x182, 0x3FF, 0, 0xF, 0, 1, 0x62000, 0x62004, 0x62008 }, { "gcc_sdcc2_ahb_clk", 0x7F, 1, GCC, 0x7F, 0x3FF, 0, 0xF, 0, 1, 0x62000, 0x62004, 0x62008 }, { "gcc_sdcc2_apps_clk", 0x7E, 1, GCC, @@ -715,8 +652,6 @@ static struct clk_debug_mux gcc_debug_mux = { 0xC, 0x3FF, 0, 0xF, 0, 1, 0x62000, 0x62004, 0x62008 }, { "gcc_tsif_ahb_clk", 0x9C, 1, GCC, 0x9C, 0x3FF, 0, 0xF, 0, 1, 0x62000, 0x62004, 0x62008 }, - { "gcc_tsif_inactivity_timers_clk", 0x9E, 1, GCC, - 0x9E, 0x3FF, 0, 0xF, 0, 1, 0x62000, 0x62004, 0x62008 }, { "gcc_tsif_ref_clk", 0x9D, 1, GCC, 0x9D, 0x3FF, 0, 0xF, 0, 1, 0x62000, 0x62004, 0x62008 }, { "gcc_ufs_card_ahb_clk", 0x107, 1, GCC, @@ -755,14 +690,10 @@ static struct clk_debug_mux gcc_debug_mux = { 0x6B, 0x3FF, 0, 0xF, 0, 1, 0x62000, 0x62004, 0x62008 }, { "gcc_usb30_prim_mock_utmi_clk", 0x6D, 1, GCC, 0x6D, 0x3FF, 0, 0xF, 0, 1, 0x62000, 0x62004, 0x62008 }, - { "gcc_usb30_prim_sleep_clk", 0x6C, 1, GCC, - 0x6C, 0x3FF, 0, 0xF, 0, 1, 0x62000, 0x62004, 0x62008 }, { "gcc_usb30_sec_master_clk", 0x72, 1, GCC, 0x72, 0x3FF, 0, 0xF, 0, 1, 0x62000, 0x62004, 0x62008 }, { "gcc_usb30_sec_mock_utmi_clk", 0x74, 1, GCC, 0x74, 0x3FF, 0, 0xF, 0, 1, 0x62000, 0x62004, 0x62008 }, - { "gcc_usb30_sec_sleep_clk", 0x73, 1, GCC, - 0x73, 0x3FF, 0, 0xF, 0, 1, 0x62000, 0x62004, 0x62008 }, { "gcc_usb3_prim_phy_aux_clk", 0x6E, 1, GCC, 0x6E, 0x3FF, 0, 0xF, 0, 1, 0x62000, 0x62004, 0x62008 }, { "gcc_usb3_prim_phy_com_aux_clk", 0x6F, 1, GCC, @@ -785,14 +716,8 @@ static struct clk_debug_mux gcc_debug_mux = { 0x4C, 0x3FF, 0, 0xF, 0, 1, 0x62000, 0x62004, 0x62008 }, { "gcc_video_xo_clk", 0x51, 1, GCC, 0x51, 0x3FF, 0, 0xF, 0, 1, 0x62000, 0x62004, 0x62008 }, - { "gpu_cc_acd_ahb_clk", 0x162, 1, GPU_CC, - 0x20, 0xFF, 0, 0x3, 0, 2, 0x1568, 0x10FC, 0x1100 }, - { "gpu_cc_acd_cxo_clk", 0x162, 1, GPU_CC, - 0x1F, 0xFF, 0, 0x3, 0, 2, 0x1568, 0x10FC, 0x1100 }, { "gpu_cc_ahb_clk", 0x162, 1, GPU_CC, 0x10, 0xFF, 0, 0x3, 0, 2, 0x1568, 0x10FC, 0x1100 }, - { "gpu_cc_crc_ahb_clk", 0x162, 1, GPU_CC, - 0x11, 0xFF, 0, 0x3, 0, 2, 0x1568, 0x10FC, 0x1100 }, { "gpu_cc_cx_apb_clk", 0x162, 1, GPU_CC, 0x14, 0xFF, 0, 0x3, 0, 2, 0x1568, 0x10FC, 0x1100 }, { "gpu_cc_cx_gmu_clk", 0x162, 1, GPU_CC, @@ -801,8 +726,6 @@ static struct clk_debug_mux gcc_debug_mux = { 0x12, 0xFF, 0, 0x3, 0, 2, 0x1568, 0x10FC, 0x1100 }, { "gpu_cc_cx_qdss_trig_clk", 0x162, 1, GPU_CC, 0x17, 0xFF, 0, 0x3, 0, 2, 0x1568, 0x10FC, 0x1100 }, - { "gpu_cc_cx_qdss_tsctr_clk", 0x162, 1, GPU_CC, - 0x13, 0xFF, 0, 0x3, 0, 2, 0x1568, 0x10FC, 0x1100 }, { "gpu_cc_cx_snoc_dvm_clk", 0x162, 1, GPU_CC, 0x15, 0xFF, 0, 0x3, 0, 2, 0x1568, 0x10FC, 0x1100 }, { "gpu_cc_cxo_aon_clk", 0x162, 1, GPU_CC, @@ -811,12 +734,8 @@ static struct clk_debug_mux gcc_debug_mux = { 0x19, 0xFF, 0, 0x3, 0, 2, 0x1568, 0x10FC, 0x1100 }, { "gpu_cc_gx_gmu_clk", 0x162, 1, GPU_CC, 0xF, 0xFF, 0, 0x3, 0, 2, 0x1568, 0x10FC, 0x1100 }, - { "gpu_cc_gx_qdss_tsctr_clk", 0x162, 1, GPU_CC, - 0xD, 0xFF, 0, 0x3, 0, 2, 0x1568, 0x10FC, 0x1100 }, { "gpu_cc_gx_vsense_clk", 0x162, 1, GPU_CC, 0xC, 0xFF, 0, 0x3, 0, 2, 0x1568, 0x10FC, 0x1100 }, - { "gpu_cc_sleep_clk", 0x162, 1, GPU_CC, - 0x16, 0xFF, 0, 0x3, 0, 2, 0x1568, 0x10FC, 0x1100 }, { "measure_only_gpu_cc_cx_gfx3d_clk", 0x162, 1, GPU_CC, 0x1A, 0xFF, 0, 0x3, 0, 2, 0x1568, 0x10FC, 0x1100 }, { "measure_only_gpu_cc_cx_gfx3d_slv_clk", 0x162, 1, GPU_CC, @@ -847,14 +766,8 @@ static struct clk_debug_mux gcc_debug_mux = { 0xC, 0xFF, 0, 0x3, 0, 2, 0x4000, 0x3004, 0x3008 }, { "npu_cc_npu_cpc_clk", 0x180, 1, NPU_CC, 0x3, 0xFF, 0, 0x3, 0, 2, 0x4000, 0x3004, 0x3008 }, - { "npu_cc_npu_cpc_timer_clk", 0x180, 1, NPU_CC, - 0x5, 0xFF, 0, 0x3, 0, 2, 0x4000, 0x3004, 0x3008 }, { "npu_cc_perf_cnt_clk", 0x180, 1, NPU_CC, 0x10, 0xFF, 0, 0x3, 0, 2, 0x4000, 0x3004, 0x3008 }, - { "npu_cc_qtimer_core_clk", 0x180, 1, NPU_CC, - 0x6, 0xFF, 0, 0x3, 0, 2, 0x4000, 0x3004, 0x3008 }, - { "npu_cc_sleep_clk", 0x180, 1, NPU_CC, - 0x7, 0xFF, 0, 0x3, 0, 2, 0x4000, 0x3004, 0x3008 }, { "npu_cc_xo_clk", 0x180, 1, NPU_CC, 0x11, 0xFF, 0, 0x3, 0, 2, 0x4000, 0x3004, 0x3008 }, { "video_cc_iris_ahb_clk", 0x57, 1, VIDEO_CC, -- GitLab From 3ddce5d89ab2a764fc6804aab09e74014ace8e61 Mon Sep 17 00:00:00 2001 From: Sujeev Dias Date: Fri, 4 May 2018 08:20:40 -0700 Subject: [PATCH 1407/1635] mhi: core: prepare all the descriptors before ringing hardware doorbell While mhi host queues new buffers to transfer ring during start, process completion transfer thread will queue a buffer to same channel after receiving a completion event. To avoid this scenario, prepare all descriptors before ringing the hardware doorbell so there will not be any completion packets to process. CRs-Fixed: 2236500 Change-Id: I91f065932ef46dc3520fd1a8ad634e2b65badff1 Signed-off-by: Sujeev Dias --- drivers/bus/mhi/core/mhi_main.c | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/drivers/bus/mhi/core/mhi_main.c b/drivers/bus/mhi/core/mhi_main.c index b023cf8819de..1c03b07fdec4 100644 --- a/drivers/bus/mhi/core/mhi_main.c +++ b/drivers/bus/mhi/core/mhi_main.c @@ -1101,13 +1101,8 @@ static int __mhi_prepare_channel(struct mhi_controller *mhi_cntrl, mhi_chan->ch_state = MHI_CH_STATE_ENABLED; write_unlock_irq(&mhi_chan->lock); - read_lock_bh(&mhi_cntrl->pm_lock); - mhi_cntrl->wake_put(mhi_cntrl, false); - read_unlock_bh(&mhi_cntrl->pm_lock); - /* pre allocate buffer for xfer ring */ if (mhi_chan->pre_alloc) { - struct mhi_device *mhi_dev = mhi_chan->mhi_dev; int nr_el = get_nr_avail_ring_elements(mhi_cntrl, &mhi_chan->tre_ring); @@ -1120,17 +1115,30 @@ static int __mhi_prepare_channel(struct mhi_controller *mhi_cntrl, goto error_pre_alloc; } - ret = mhi_queue_buf(mhi_dev, mhi_chan, buf, MHI_MAX_MTU, - MHI_EOT); + /* prepare transfer descriptors */ + ret = mhi_chan->gen_tre(mhi_cntrl, mhi_chan, buf, buf, + MHI_MAX_MTU, MHI_EOT); if (ret) { - MHI_ERR("Chan:%d error queue buffer\n", + MHI_ERR("Chan:%d error prepare buffer\n", mhi_chan->chan); kfree(buf); goto error_pre_alloc; } } + + read_lock_bh(&mhi_cntrl->pm_lock); + if (MHI_DB_ACCESS_VALID(mhi_cntrl->pm_state)) { + read_lock_irq(&mhi_chan->lock); + mhi_ring_chan_db(mhi_cntrl, mhi_chan); + read_unlock_irq(&mhi_chan->lock); + } + read_unlock_bh(&mhi_cntrl->pm_lock); } + read_lock_bh(&mhi_cntrl->pm_lock); + mhi_cntrl->wake_put(mhi_cntrl, false); + read_unlock_bh(&mhi_cntrl->pm_lock); + mutex_unlock(&mhi_chan->mutex); MHI_LOG("Chan:%d successfully moved to start state\n", mhi_chan->chan); @@ -1152,6 +1160,11 @@ static int __mhi_prepare_channel(struct mhi_controller *mhi_cntrl, return ret; error_pre_alloc: + + read_lock_bh(&mhi_cntrl->pm_lock); + mhi_cntrl->wake_put(mhi_cntrl, false); + read_unlock_bh(&mhi_cntrl->pm_lock); + mutex_unlock(&mhi_chan->mutex); __mhi_unprepare_channel(mhi_cntrl, mhi_chan); -- GitLab From fa8f4eb58818cb4edb4932891489307c6ac17876 Mon Sep 17 00:00:00 2001 From: Tatenda Chipeperekwa Date: Fri, 4 May 2018 16:43:42 -0700 Subject: [PATCH 1408/1635] drm/msm/dp: fix PHY CTS programming sequence on sm8150 Fix the PHY CTS programming sequence in order to support test automation on sm8150. Change-Id: Ie4ff790645650051a450c99ceaaaa48c6d456bfd Signed-off-by: Tatenda Chipeperekwa --- drivers/gpu/drm/msm/dp/dp_ctrl.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/msm/dp/dp_ctrl.c b/drivers/gpu/drm/msm/dp/dp_ctrl.c index 487bddcbef6f..ba9566e9170c 100644 --- a/drivers/gpu/drm/msm/dp/dp_ctrl.c +++ b/drivers/gpu/drm/msm/dp/dp_ctrl.c @@ -759,12 +759,16 @@ static void dp_ctrl_process_phy_test_request(struct dp_ctrl *dp_ctrl) * link clocks and core clocks. */ ctrl->dp_ctrl.reset(&ctrl->dp_ctrl); + ctrl->dp_ctrl.stream_off(&ctrl->dp_ctrl, ctrl->panel); ctrl->dp_ctrl.off(&ctrl->dp_ctrl); + ctrl->aux->init(ctrl->aux, ctrl->parser->aux_cfg); + ret = ctrl->dp_ctrl.on(&ctrl->dp_ctrl, ctrl->mst_mode); if (ret) pr_err("failed to enable DP controller\n"); + ctrl->dp_ctrl.stream_on(&ctrl->dp_ctrl, ctrl->panel); pr_debug("end\n"); } @@ -905,6 +909,11 @@ static int dp_ctrl_stream_on(struct dp_ctrl *dp_ctrl, struct dp_panel *panel) goto end; } + if (ctrl->link->sink_request & DP_TEST_LINK_PHY_TEST_PATTERN) { + dp_ctrl_send_phy_test_pattern(ctrl); + return 0; + } + rc = dp_ctrl_mst_stream_setup(ctrl, panel); if (rc) goto end; @@ -991,9 +1000,6 @@ static int dp_ctrl_on(struct dp_ctrl *dp_ctrl, bool mst_mode) dp_ctrl_enable_mainlink_clocks(ctrl); } - if (ctrl->link->sink_request & DP_TEST_LINK_PHY_TEST_PATTERN) - dp_ctrl_send_phy_test_pattern(ctrl); - ctrl->power_on = true; pr_debug("End-\n"); -- GitLab From b7535b3e973f99ae7a02df7b6d131c598f5727f9 Mon Sep 17 00:00:00 2001 From: Vijaykumar Badiger Date: Fri, 4 May 2018 17:27:25 -0700 Subject: [PATCH 1409/1635] ARM: dts: msm: Add sdhc support for sm8150-auto Adding SD card support for auto ADP Star. Change-Id: Ia01c6c0eaaa28ce9ee7f481151deb7426a0f6008 Signed-off-by: Vijaykumar Badiger --- .../boot/dts/qcom/sm8150-auto-adp-star.dtsi | 20 +++++++++++++++++++ .../dts/qcom/sm8150-auto-pmic-overlay.dtsi | 10 ++++++++++ 2 files changed, 30 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sm8150-auto-adp-star.dtsi b/arch/arm64/boot/dts/qcom/sm8150-auto-adp-star.dtsi index cc9662c46445..10087f62683c 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-auto-adp-star.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-auto-adp-star.dtsi @@ -59,3 +59,23 @@ }; }; }; + +&sdhc_2 { + vdd-supply = <&pm855_1_l17>; + qcom,vdd-voltage-level = <2950000 2960000>; + qcom,vdd-current-level = <200 800000>; + + vdd-io-supply = <&pm855_2_l13>; + qcom,vdd-io-voltage-level = <1808000 2960000>; + qcom,vdd-io-current-level = <200 22000>; + + pinctrl-names = "active", "sleep"; + pinctrl-0 = <&sdc2_clk_on + &sdc2_cmd_on &sdc2_data_on &storage_cd_default>; + pinctrl-1 = <&sdc2_clk_off + &sdc2_cmd_off &sdc2_data_off &storage_cd_default>; + + cd-gpios = <&pm855_1_gpios 4 GPIO_ACTIVE_LOW>; + + status = "ok"; +}; diff --git a/arch/arm64/boot/dts/qcom/sm8150-auto-pmic-overlay.dtsi b/arch/arm64/boot/dts/qcom/sm8150-auto-pmic-overlay.dtsi index 59cef9fed9e2..cde5ee6c0807 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-auto-pmic-overlay.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-auto-pmic-overlay.dtsi @@ -100,6 +100,16 @@ pm855_1_gpios: &pm855_gpios { }; }; + storage_sd_detect { + storage_cd_default: storage_cd_default { + pins = "gpio4"; + function = "normal"; + input-enable; + bias-pull-up; + power-source = <0>; + }; + }; + key_vol_up { key_vol_up_default: key_vol_up_default { pins = "gpio6"; -- GitLab From 7fd49f2041282fa4f8f6bbdec15d5b1cd984c6b5 Mon Sep 17 00:00:00 2001 From: Jishnu Prakash Date: Wed, 18 Apr 2018 12:17:38 +0530 Subject: [PATCH 1410/1635] thermal: tsens: Update TSENS support for SDM640 Offset for some TSENS registers are different in SDM640. Update register offset value and add new TSENS device ID for SDM640. Change-Id: Ie31c62f6f68d8a207741127de8eb5f83ed043929 Signed-off-by: Jishnu Prakash --- Documentation/devicetree/bindings/thermal/tsens.txt | 2 ++ drivers/thermal/msm-tsens.c | 3 +++ drivers/thermal/tsens.h | 2 ++ drivers/thermal/tsens2xxx.c | 8 +++++++- 4 files changed, 14 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/thermal/tsens.txt b/Documentation/devicetree/bindings/thermal/tsens.txt index 21932c12b6ea..3002e4ce6b51 100644 --- a/Documentation/devicetree/bindings/thermal/tsens.txt +++ b/Documentation/devicetree/bindings/thermal/tsens.txt @@ -21,6 +21,8 @@ Required properties: should be "qcom,tsens24xx" for 2.4 TSENS controller. should be "qcom,msm8937-tsens" for 8937 TSENS driver. should be "qcom,qcs405-tsens" for QCS405 TSENS driver. + should be "qcom,sdm640-tsens" for 640 TSENS driver. + The compatible property is used to identify the respective controller to use for the corresponding SoC. - reg : offset and length of the TSENS registers with associated property in reg-names diff --git a/drivers/thermal/msm-tsens.c b/drivers/thermal/msm-tsens.c index f304f798f01f..c89ccc6d03b1 100644 --- a/drivers/thermal/msm-tsens.c +++ b/drivers/thermal/msm-tsens.c @@ -81,6 +81,9 @@ static const struct of_device_id tsens_table[] = { { .compatible = "qcom,sdm630-tsens", .data = &data_tsens23xx, }, + { .compatible = "qcom,sdm640-tsens", + .data = &data_tsens23xx, + }, { .compatible = "qcom,sdm845-tsens", .data = &data_tsens24xx, }, diff --git a/drivers/thermal/tsens.h b/drivers/thermal/tsens.h index c9e08a281182..0c696d3d5a26 100644 --- a/drivers/thermal/tsens.h +++ b/drivers/thermal/tsens.h @@ -131,6 +131,8 @@ struct tsens_data { u32 wd_bark_mask; bool mtc; bool valid_status_check; + u32 ver_major; + u32 ver_minor; }; struct tsens_mtc_sysfs { diff --git a/drivers/thermal/tsens2xxx.c b/drivers/thermal/tsens2xxx.c index 55420bf5e422..6584000ae94b 100644 --- a/drivers/thermal/tsens2xxx.c +++ b/drivers/thermal/tsens2xxx.c @@ -59,6 +59,7 @@ #define TSENS_TM_SCALE_DECI_MILLIDEG 100 #define TSENS_DEBUG_WDOG_TRIGGER_COUNT 5 #define TSENS_TM_WATCHDOG_LOG(n) ((n) + 0x13c) +#define TSENS_TM_WATCHDOG_LOG_v23(n) ((n) + 0x170) #define TSENS_EN BIT(0) #define TSENS_CTRL_SENSOR_EN_MASK(n) ((n >> 3) & 0xffff) #define TSENS_TM_TRDY(n) ((n) + 0xe4) @@ -321,7 +322,10 @@ static irqreturn_t tsens_tm_critical_irq_thread(int irq, void *data) TSENS_TM_SN_CRITICAL_THRESHOLD(tm->tsens_tm_addr); wd_critical_addr = TSENS_TM_CRITICAL_INT_STATUS(tm->tsens_tm_addr); - wd_log_addr = TSENS_TM_WATCHDOG_LOG(tm->tsens_tm_addr); + if (tm->ctrl_data->ver_major == 2 && tm->ctrl_data->ver_minor == 3) + wd_log_addr = TSENS_TM_WATCHDOG_LOG_v23(tm->tsens_tm_addr); + else + wd_log_addr = TSENS_TM_WATCHDOG_LOG(tm->tsens_tm_addr); if (tm->ctrl_data->wd_bark) { wd_mask = readl_relaxed(wd_critical_addr); @@ -643,6 +647,8 @@ const struct tsens_data data_tsens23xx = { .wd_bark_mask = 1, .ops = &ops_tsens2xxx, .mtc = false, + .ver_major = 2, + .ver_minor = 3, }; const struct tsens_data data_tsens24xx = { -- GitLab From 7be3a3f56428aff3ce5109885f64cb21882e82fd Mon Sep 17 00:00:00 2001 From: Ghanim Fodi Date: Thu, 3 May 2018 10:40:10 +0300 Subject: [PATCH 1411/1635] msm: ipa3: Fix QMB configuration for IPA test pipes IPA test pipes which are used for unit-tests has wrong QMB configuration. It needs to be DDR QMB and not PCIE QMB which is used for MHI data path. Change-Id: I7600916835f4d38ae379e5f81212f9717ba1c7e7 Signed-off-by: Ghanim Fodi --- drivers/platform/msm/ipa/ipa_v3/ipa_utils.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c index 3f3aa92e1098..29ea76d316ed 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c @@ -1311,31 +1311,31 @@ static const struct ipa_ep_configuration ipa3_ep_mapping true, IPA_v4_0_GROUP_UL_DL, false, IPA_DPS_HPS_SEQ_TYPE_INVALID, - QMB_MASTER_SELECT_PCIE, + QMB_MASTER_SELECT_DDR, { 11, 6, 9, 9, IPA_EE_AP } }, [IPA_4_0][IPA_CLIENT_TEST1_CONS] = { true, IPA_v4_0_GROUP_UL_DL, false, IPA_DPS_HPS_SEQ_TYPE_INVALID, - QMB_MASTER_SELECT_PCIE, + QMB_MASTER_SELECT_DDR, { 11, 6, 9, 9, IPA_EE_AP } }, [IPA_4_0][IPA_CLIENT_TEST2_CONS] = { true, IPA_v4_0_GROUP_UL_DL, false, IPA_DPS_HPS_SEQ_TYPE_INVALID, - QMB_MASTER_SELECT_PCIE, + QMB_MASTER_SELECT_DDR, { 12, 2, 5, 5, IPA_EE_AP } }, [IPA_4_0][IPA_CLIENT_TEST3_CONS] = { true, IPA_v4_0_GROUP_UL_DL, false, IPA_DPS_HPS_SEQ_TYPE_INVALID, - QMB_MASTER_SELECT_PCIE, + QMB_MASTER_SELECT_DDR, { 19, 12, 9, 9, IPA_EE_AP } }, [IPA_4_0][IPA_CLIENT_TEST4_CONS] = { true, IPA_v4_0_GROUP_UL_DL, false, IPA_DPS_HPS_SEQ_TYPE_INVALID, - QMB_MASTER_SELECT_PCIE, + QMB_MASTER_SELECT_DDR, { 21, 14, 9, 9, IPA_EE_AP } }, /* Dummy consumer (pipe 31) is used in L2TP rt rule */ [IPA_4_0][IPA_CLIENT_DUMMY_CONS] = { @@ -1665,7 +1665,7 @@ static const struct ipa_ep_configuration ipa3_ep_mapping true, IPA_v4_0_GROUP_UL_DL, false, IPA_DPS_HPS_SEQ_TYPE_INVALID, - QMB_MASTER_SELECT_PCIE, + QMB_MASTER_SELECT_DDR, { 11, 6, 9, 9, IPA_EE_AP } }, [IPA_4_1][IPA_CLIENT_TEST1_CONS] = { true, IPA_v4_0_GROUP_UL_DL, @@ -1677,7 +1677,7 @@ static const struct ipa_ep_configuration ipa3_ep_mapping true, IPA_v4_0_GROUP_UL_DL, false, IPA_DPS_HPS_SEQ_TYPE_INVALID, - QMB_MASTER_SELECT_PCIE, + QMB_MASTER_SELECT_DDR, { 12, 2, 9, 9, IPA_EE_AP } }, [IPA_4_1][IPA_CLIENT_TEST3_CONS] = { true, IPA_v4_0_GROUP_UL_DL, @@ -1689,7 +1689,7 @@ static const struct ipa_ep_configuration ipa3_ep_mapping true, IPA_v4_0_GROUP_UL_DL, false, IPA_DPS_HPS_SEQ_TYPE_INVALID, - QMB_MASTER_SELECT_PCIE, + QMB_MASTER_SELECT_DDR, { 21, 14, 9, 9, IPA_EE_AP } }, /* Dummy consumer (pipe 31) is used in L2TP rt rule */ [IPA_4_1][IPA_CLIENT_DUMMY_CONS] = { -- GitLab From 8853713d2ef7e31fdd6704a080571b22794b1e77 Mon Sep 17 00:00:00 2001 From: Amir Levy Date: Tue, 1 May 2018 13:25:37 +0300 Subject: [PATCH 1412/1635] msm: ipa4: add IOCTL for reading vlan mode Add IOCTL for reading LAN interfaces VLAN mode from user space. Change-Id: I85634b21adf2b1b79feb1b282597289e89ad1df1 Signed-off-by: Amir Levy --- drivers/platform/msm/ipa/ipa_v3/ipa.c | 24 ++++++++++++++++++ drivers/platform/msm/ipa/ipa_v3/ipa_i.h | 1 + drivers/platform/msm/ipa/ipa_v3/ipa_utils.c | 2 +- include/linux/ipa.h | 13 ---------- include/uapi/linux/msm_ipa.h | 27 +++++++++++++++++++++ 5 files changed, 53 insertions(+), 14 deletions(-) diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa.c b/drivers/platform/msm/ipa/ipa_v3/ipa.c index 839067cf9250..d5a11d4398af 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa.c @@ -682,6 +682,7 @@ static long ipa3_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) u32 pyld_sz; u8 header[128] = { 0 }; u8 *param = NULL; + bool is_vlan_mode; struct ipa_ioc_nat_alloc_mem nat_mem; struct ipa_ioc_nat_ipv6ct_table_alloc table_alloc; struct ipa_ioc_v4_nat_init nat_init; @@ -691,6 +692,7 @@ static long ipa3_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) struct ipa_ioc_nat_pdn_entry mdfy_pdn; struct ipa_ioc_rm_dependency rm_depend; struct ipa_ioc_nat_dma_cmd *table_dma_cmd; + struct ipa_ioc_get_vlan_mode vlan_mode; size_t sz; int pre_entry; @@ -1785,6 +1787,28 @@ static long ipa3_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) } break; + case IPA_IOC_GET_VLAN_MODE: + if (copy_from_user(&vlan_mode, (const void __user *)arg, + sizeof(struct ipa_ioc_get_vlan_mode))) { + retval = -EFAULT; + break; + } + retval = ipa3_is_vlan_mode( + vlan_mode.iface, + &is_vlan_mode); + if (retval) + break; + + vlan_mode.is_vlan_mode = is_vlan_mode; + + if (copy_to_user((void __user *)arg, + &vlan_mode, + sizeof(struct ipa_ioc_get_vlan_mode))) { + retval = -EFAULT; + break; + } + break; + case IPA_IOC_ADD_VLAN_IFACE: if (ipa3_send_vlan_l2tp_msg(arg, ADD_VLAN_IFACE)) { retval = -EFAULT; diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h index eb942cea65c3..b03657e15d70 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h @@ -2361,4 +2361,5 @@ void __ipa_gsi_irq_rx_scedule_poll(struct ipa3_sys_context *sys); int ipa3_tz_unlock_reg(struct ipa_tz_unlock_reg_info *reg_info, u16 num_regs); void ipa3_init_imm_cmd_desc(struct ipa3_desc *desc, struct ipahal_imm_cmd_pyld *cmd_pyld); +int ipa3_is_vlan_mode(enum ipa_vlan_ifaces iface, bool *res); #endif /* _IPA3_I_H_ */ diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c index 29ea76d316ed..e4576eae7f63 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c @@ -4645,7 +4645,7 @@ static void ipa3_set_tag_process_before_gating(bool val) * * Returns: 0 on success, negative on failure */ -static int ipa3_is_vlan_mode(enum ipa_vlan_ifaces iface, bool *res) +int ipa3_is_vlan_mode(enum ipa_vlan_ifaces iface, bool *res) { if (!res) { IPAERR("NULL out param\n"); diff --git a/include/linux/ipa.h b/include/linux/ipa.h index f663d601e307..a8513fdce071 100644 --- a/include/linux/ipa.h +++ b/include/linux/ipa.h @@ -115,19 +115,6 @@ enum hdr_total_len_or_pad_type { IPA_HDR_TOTAL_LEN = 1, }; -/** -* enum ipa_vlan_ifaces - vlan interfaces types -* @IPA_VLAN_IF_EMAC: used for EMAC ethernet device -* @IPA_VLAN_IF_RNDIS: used for RNDIS USB device -* @IPA_VLAN_IF_ECM: used for ECM USB device -*/ -enum ipa_vlan_ifaces { - IPA_VLAN_IF_EMAC, - IPA_VLAN_IF_RNDIS, - IPA_VLAN_IF_ECM, - IPA_VLAN_IF_MAX -}; - /** * struct ipa_ep_cfg_nat - NAT configuration in IPA end-point * @nat_en: This defines the default NAT mode for the pipe: in case of diff --git a/include/uapi/linux/msm_ipa.h b/include/uapi/linux/msm_ipa.h index 3c923254559f..71bd5b8c971a 100644 --- a/include/uapi/linux/msm_ipa.h +++ b/include/uapi/linux/msm_ipa.h @@ -95,6 +95,7 @@ #define IPA_IOCTL_ALLOC_IPV6CT_TABLE 53 #define IPA_IOCTL_DEL_NAT_TABLE 54 #define IPA_IOCTL_DEL_IPV6CT_TABLE 55 +#define IPA_IOCTL_GET_VLAN_MODE 56 /** * max size of the header to be inserted @@ -1848,6 +1849,29 @@ struct ipa_tether_device_info { struct ipa_lan_client lan_client[IPA_MAX_NUM_HW_PATH_CLIENTS]; }; +/** + * enum ipa_vlan_ifaces - vlan interfaces types + */ +enum ipa_vlan_ifaces { + IPA_VLAN_IF_ETH, + IPA_VLAN_IF_RNDIS, + IPA_VLAN_IF_ECM +}; + +#define IPA_VLAN_IF_EMAC IPA_VLAN_IF_ETH +#define IPA_VLAN_IF_MAX (IPA_VLAN_IF_ECM + 1) + +/** + * struct ipa_get_vlan_mode - get vlan mode of a Lan interface + * @iface: Lan interface type to be queried. + * @is_vlan_mode: output parameter, is interface in vlan mode, valid only when + * ioctl return val is non-negative + */ +struct ipa_ioc_get_vlan_mode { + enum ipa_vlan_ifaces iface; + uint32_t is_vlan_mode; +}; + /** * actual IOCTLs supported by IPA driver */ @@ -2026,6 +2050,9 @@ struct ipa_tether_device_info { #define IPA_IOC_DEL_L2TP_VLAN_MAPPING _IOWR(IPA_IOC_MAGIC, \ IPA_IOCTL_DEL_L2TP_VLAN_MAPPING, \ struct ipa_ioc_l2tp_vlan_mapping_info *) +#define IPA_IOC_GET_VLAN_MODE _IOWR(IPA_IOC_MAGIC, \ + IPA_IOCTL_GET_VLAN_MODE, \ + struct ipa_ioc_get_vlan_mode *) /* * unique magic number of the Tethering bridge ioctls */ -- GitLab From ffade0bc7fcbc91a1a09d690c6606b09cf2174e4 Mon Sep 17 00:00:00 2001 From: Anil Kumar Mamidala Date: Fri, 22 Apr 2016 12:42:51 +0530 Subject: [PATCH 1413/1635] qos: Register irq notify after adding the qos request Before adding the irq affinity based qos request to the list, if the affinity of the interrupt changes it will trigger notify call. This notifier call will try to update the qos request. Accessing the qos request which is not yet added to the list leads to a NULL pointer exception. Avoid this race by registering the notifier after adding the qos request. Change-Id: I99869cc233573b5db10e4f3224d65c29511050ea Signed-off-by: Anil Kumar Mamidala --- kernel/power/qos.c | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/kernel/power/qos.c b/kernel/power/qos.c index 64b5c0e5187d..701fc202c2b9 100644 --- a/kernel/power/qos.c +++ b/kernel/power/qos.c @@ -587,12 +587,11 @@ void pm_qos_add_request(struct pm_qos_request *req, #ifdef CONFIG_SMP case PM_QOS_REQ_AFFINE_IRQ: if (irq_can_set_affinity(req->irq)) { - int ret = 0; struct irq_desc *desc = irq_to_desc(req->irq); struct cpumask *mask; if (!desc) - break; + return; mask = desc->irq_data.common->affinity; @@ -602,13 +601,6 @@ void pm_qos_add_request(struct pm_qos_request *req, req->irq_notify.notify = pm_qos_irq_notify; req->irq_notify.release = pm_qos_irq_release; - ret = irq_set_affinity_notifier(req->irq, - &req->irq_notify); - if (ret) { - WARN(1, "IRQ affinity notify set failed\n"); - req->type = PM_QOS_REQ_ALL_CORES; - cpumask_setall(&req->cpus_affine); - } } else { req->type = PM_QOS_REQ_ALL_CORES; cpumask_setall(&req->cpus_affine); @@ -630,6 +622,24 @@ void pm_qos_add_request(struct pm_qos_request *req, trace_pm_qos_add_request(pm_qos_class, value); pm_qos_update_target(pm_qos_array[pm_qos_class]->constraints, &req->node, PM_QOS_ADD_REQ, value); + +#ifdef CONFIG_SMP + if (req->type == PM_QOS_REQ_AFFINE_IRQ && + irq_can_set_affinity(req->irq)) { + int ret = 0; + + ret = irq_set_affinity_notifier(req->irq, + &req->irq_notify); + if (ret) { + WARN(1, "IRQ affinity notify set failed\n"); + req->type = PM_QOS_REQ_ALL_CORES; + cpumask_setall(&req->cpus_affine); + pm_qos_update_target( + pm_qos_array[pm_qos_class]->constraints, + &req->node, PM_QOS_UPDATE_REQ, value); + } + } +#endif } EXPORT_SYMBOL_GPL(pm_qos_add_request); -- GitLab From 9a16fed8f0c387e5061e9d1fa18387ba08c686e8 Mon Sep 17 00:00:00 2001 From: Sayali Lokhande Date: Mon, 26 Mar 2018 16:04:45 +0530 Subject: [PATCH 1414/1635] ARM: dts: msm: Enable sdhc1 and sdhc2 for qcs405 Add DT entries to support emmc and sd card on qcs405 platform. Change-Id: I91b2035dfa7fa76625c0dccfa8f86174bde30542 Signed-off-by: Sayali Lokhande --- arch/arm64/boot/dts/qcom/qcs405-pinctrl.dtsi | 138 +++++++++++++++++++ arch/arm64/boot/dts/qcom/qcs405-rumi.dtsi | 34 +++++ arch/arm64/boot/dts/qcom/qcs405.dtsi | 55 +++++++- 3 files changed, 226 insertions(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/qcs405-pinctrl.dtsi b/arch/arm64/boot/dts/qcom/qcs405-pinctrl.dtsi index 470b0322f829..0463c5c63720 100644 --- a/arch/arm64/boot/dts/qcom/qcs405-pinctrl.dtsi +++ b/arch/arm64/boot/dts/qcom/qcs405-pinctrl.dtsi @@ -643,5 +643,143 @@ }; }; }; + + /* SDC pin type */ + sdc1_clk_on: sdc1_clk_on { + config { + pins = "sdc1_clk"; + bias-disable; /* NO pull */ + drive-strength = <16>; /* 16 MA */ + }; + }; + + sdc1_clk_off: sdc1_clk_off { + config { + pins = "sdc1_clk"; + bias-disable; /* NO pull */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + sdc1_cmd_on: sdc1_cmd_on { + config { + pins = "sdc1_cmd"; + bias-pull-up; /* pull up */ + drive-strength = <10>; /* 10 MA */ + }; + }; + + sdc1_cmd_off: sdc1_cmd_off { + config { + pins = "sdc1_cmd"; + num-grp-pins = <1>; + bias-pull-up; /* pull up */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + sdc1_data_on: sdc1_data_on { + config { + pins = "sdc1_data"; + bias-pull-up; /* pull up */ + drive-strength = <10>; /* 10 MA */ + }; + }; + + sdc1_data_off: sdc1_data_off { + config { + pins = "sdc1_data"; + bias-pull-up; /* pull up */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + sdc1_rclk_on: sdc1_rclk_on { + config { + pins = "sdc1_rclk"; + bias-pull-down; /* pull down */ + }; + }; + + sdc1_rclk_off: sdc1_rclk_off { + config { + pins = "sdc1_rclk"; + bias-pull-down; /* pull down */ + }; + }; + + sdc2_clk_on: sdc2_clk_on { + config { + pins = "sdc2_clk"; + bias-disable; /* NO pull */ + drive-strength = <16>; /* 16 MA */ + }; + }; + + sdc2_clk_off: sdc2_clk_off { + config { + pins = "sdc2_clk"; + bias-disable; /* NO pull */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + sdc2_cmd_on: sdc2_cmd_on { + config { + pins = "sdc2_cmd"; + bias-pull-up; /* pull up */ + drive-strength = <10>; /* 10 MA */ + }; + }; + + sdc2_cmd_off: sdc2_cmd_off { + config { + pins = "sdc2_cmd"; + bias-pull-up; /* pull up */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + sdc2_data_on: sdc2_data_on { + config { + pins = "sdc2_data"; + bias-pull-up; /* pull up */ + drive-strength = <10>; /* 10 MA */ + }; + }; + + sdc2_data_off: sdc2_data_off { + config { + pins = "sdc2_data"; + bias-pull-up; /* pull up */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + sdc2_cd_on: cd_on { + mux { + pins = "gpio21"; /* sdcard_det */ + function = "gpio"; + }; + + config { + pins = "gpio21"; + drive-strength = <2>; + bias-pull-up; + }; + }; + + sdc2_cd_off: cd_off { + mux { + pins = "gpio21"; + function = "gpio"; + }; + + config { + pins = "gpio21"; + drive-strength = <2>; + bias-disable; + }; + }; }; }; diff --git a/arch/arm64/boot/dts/qcom/qcs405-rumi.dtsi b/arch/arm64/boot/dts/qcom/qcs405-rumi.dtsi index 563a0cbb88e9..d9d3d53be1ec 100644 --- a/arch/arm64/boot/dts/qcom/qcs405-rumi.dtsi +++ b/arch/arm64/boot/dts/qcom/qcs405-rumi.dtsi @@ -82,3 +82,37 @@ }; #include "qcs405-stub-regulator.dtsi" + +&sdhc_1 { + /* VDD external regulator is enabled/disabled by pms405_l6 */ + vdd-io-supply = <&pms405_l6>; + qcom,vdd-io-always-on; + qcom,vdd-io-lpm-sup; + qcom,vdd-io-voltage-level = <1704000 1800000>; + qcom,vdd-io-current-level = <0 325000>; + + pinctrl-names = "active", "sleep"; + pinctrl-0 = <&sdc1_clk_on &sdc1_cmd_on &sdc1_data_on>; + pinctrl-1 = <&sdc1_clk_off &sdc1_cmd_off &sdc1_data_off>; + + qcom,clk-rates = <400000 20000000 25000000 50000000>; + qcom,bus-speed-mode = "HS200_1p8v", "DDR_1p8v"; + + status = "ok"; +}; + +&sdhc_2 { + /* VDD is an external regulator eLDO5 */ + vdd-io-supply = <&pms405_l11>; + qcom,vdd-io-voltage-level = <2696000 3304000>; + qcom,vdd-io-current-level = <0 22000>; + + pinctrl-names = "active", "sleep"; + pinctrl-0 = <&sdc2_clk_on &sdc2_cmd_on &sdc2_data_on>; + pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off>; + + qcom,clk-rates = <400000 20000000 25000000 50000000>; + qcom,bus-speed-mode = "SDR12", "SDR25", "SDR50"; + + status = "disabled"; +}; diff --git a/arch/arm64/boot/dts/qcom/qcs405.dtsi b/arch/arm64/boot/dts/qcom/qcs405.dtsi index f07ca3bb25a0..760a8049b5eb 100644 --- a/arch/arm64/boot/dts/qcom/qcs405.dtsi +++ b/arch/arm64/boot/dts/qcom/qcs405.dtsi @@ -40,7 +40,10 @@ }; }; - aliases { }; + aliases { + sdhc1 = &sdhc_1; /* SDC1 eMMC slot */ + sdhc2 = &sdhc_2; /* SDC2 SD Card slot */ + }; soc: soc { }; @@ -540,6 +543,56 @@ snps,hird-threshold = /bits/ 8 <0x10>; }; }; + + sdhc_1: sdhci@7804000 { + compatible = "qcom,sdhci-msm-v5"; + reg = <0x7804000 0x1000>, <0x7805000 0x1000>; + reg-names = "hc_mem", "cmdq_mem"; + + interrupts = <0 123 0>, <0 138 0>; + interrupt-names = "hc_irq", "pwr_irq"; + + qcom,bus-width = <8>; + qcom,large-address-bus; + + qcom,clk-rates = <400000 20000000 25000000 50000000 100000000 + 192000000 384000000>; + qcom,bus-speed-mode = "HS400_1p8v", "HS200_1p8v", "DDR_1p8v"; + + qcom,devfreq,freq-table = <50000000 200000000>; + + clocks = <&clock_gcc GCC_SDCC1_AHB_CLK>, + <&clock_gcc GCC_SDCC1_APPS_CLK>; + clock-names = "iface_clk", "core_clk"; + + qcom,nonremovable; + status = "disabled"; + }; + + sdhc_2: sdhci@7844000 { + compatible = "qcom,sdhci-msm-v5"; + reg = <0x7844000 0x1000>; + reg-names = "hc_mem"; + + interrupts = <0 125 0>, <0 221 0>; + interrupt-names = "hc_irq", "pwr_irq"; + + qcom,bus-width = <4>; + qcom,large-address-bus; + + qcom,clk-rates = <400000 20000000 25000000 + 50000000 100000000 201500000>; + qcom,bus-speed-mode = "SDR12", "SDR25", "SDR50", "DDR50", + "SDR104"; + + qcom,devfreq,freq-table = <50000000 201500000>; + + clocks = <&clock_gcc GCC_SDCC2_AHB_CLK>, + <&clock_gcc GCC_SDCC2_APPS_CLK>; + clock-names = "iface_clk", "core_clk"; + + status = "disabled"; + }; }; #include "qcs405-gdsc.dtsi" -- GitLab From 2a7c6e97fa65a0fa21ea48ec28d44a1bd6824562 Mon Sep 17 00:00:00 2001 From: Sayali Lokhande Date: Thu, 12 Apr 2018 18:17:05 +0530 Subject: [PATCH 1415/1635] ARM: config: Enable MMC related configs for qcs405 Enable mmc configs for supporting mmc features like perf profiling, deferred resume, ring buffer and clock gating. Change-Id: I28f0911d63453030988e49df7a6f75b92f98ce1c Signed-off-by: Sayali Lokhande --- arch/arm/configs/qcs405-perf_defconfig | 4 ++++ arch/arm/configs/qcs405_defconfig | 5 +++++ arch/arm64/configs/qcs405-perf_defconfig | 4 ++++ arch/arm64/configs/qcs405_defconfig | 5 +++++ 4 files changed, 18 insertions(+) diff --git a/arch/arm/configs/qcs405-perf_defconfig b/arch/arm/configs/qcs405-perf_defconfig index 6c8ed29ed2da..f8e4b24f29ed 100644 --- a/arch/arm/configs/qcs405-perf_defconfig +++ b/arch/arm/configs/qcs405-perf_defconfig @@ -301,11 +301,15 @@ CONFIG_DUAL_ROLE_USB_INTF=y CONFIG_USB_GADGET=y CONFIG_USB_GADGET_VBUS_DRAW=500 CONFIG_MMC=y +CONFIG_MMC_PERF_PROFILING=y CONFIG_MMC_BLOCK_MINORS=32 +CONFIG_MMC_BLOCK_DEFERRED_RESUME=y CONFIG_MMC_TEST=m CONFIG_MMC_PARANOID_SD_INIT=y +CONFIG_MMC_CLKGATE=y CONFIG_MMC_SDHCI=y CONFIG_MMC_SDHCI_PLTFM=y +CONFIG_MMC_SDHCI_MSM=y CONFIG_RTC_CLASS=y CONFIG_DMADEVICES=y CONFIG_UIO=y diff --git a/arch/arm/configs/qcs405_defconfig b/arch/arm/configs/qcs405_defconfig index 5ddcb0c1079c..4afb653542c4 100644 --- a/arch/arm/configs/qcs405_defconfig +++ b/arch/arm/configs/qcs405_defconfig @@ -318,11 +318,16 @@ CONFIG_USB_CONFIGFS=y CONFIG_USB_CONFIGFS_F_FS=y CONFIG_USB_CONFIGFS_F_DIAG=y CONFIG_MMC=y +CONFIG_MMC_PERF_PROFILING=y CONFIG_MMC_BLOCK_MINORS=32 +CONFIG_MMC_BLOCK_DEFERRED_RESUME=y CONFIG_MMC_TEST=m +CONFIG_MMC_RING_BUFFER=y CONFIG_MMC_PARANOID_SD_INIT=y +CONFIG_MMC_CLKGATE=y CONFIG_MMC_SDHCI=y CONFIG_MMC_SDHCI_PLTFM=y +CONFIG_MMC_SDHCI_MSM=y CONFIG_RTC_CLASS=y CONFIG_DMADEVICES=y CONFIG_UIO=y diff --git a/arch/arm64/configs/qcs405-perf_defconfig b/arch/arm64/configs/qcs405-perf_defconfig index c1bd23430490..d02dfe6e937c 100644 --- a/arch/arm64/configs/qcs405-perf_defconfig +++ b/arch/arm64/configs/qcs405-perf_defconfig @@ -300,11 +300,15 @@ CONFIG_DUAL_ROLE_USB_INTF=y CONFIG_USB_GADGET=y CONFIG_USB_GADGET_VBUS_DRAW=500 CONFIG_MMC=y +CONFIG_MMC_PERF_PROFILING=y CONFIG_MMC_BLOCK_MINORS=32 +CONFIG_MMC_BLOCK_DEFERRED_RESUME=y CONFIG_MMC_TEST=m CONFIG_MMC_PARANOID_SD_INIT=y +CONFIG_MMC_CLKGATE=y CONFIG_MMC_SDHCI=y CONFIG_MMC_SDHCI_PLTFM=y +CONFIG_MMC_SDHCI_MSM=y CONFIG_RTC_CLASS=y CONFIG_DMADEVICES=y CONFIG_QCOM_SPS_DMA=y diff --git a/arch/arm64/configs/qcs405_defconfig b/arch/arm64/configs/qcs405_defconfig index cb95c7374bcc..45668468d3bb 100644 --- a/arch/arm64/configs/qcs405_defconfig +++ b/arch/arm64/configs/qcs405_defconfig @@ -317,11 +317,16 @@ CONFIG_USB_CONFIGFS=y CONFIG_USB_CONFIGFS_F_FS=y CONFIG_USB_CONFIGFS_F_DIAG=y CONFIG_MMC=y +CONFIG_MMC_PERF_PROFILING=y CONFIG_MMC_BLOCK_MINORS=32 +CONFIG_MMC_BLOCK_DEFERRED_RESUME=y CONFIG_MMC_TEST=m +CONFIG_MMC_RING_BUFFER=y CONFIG_MMC_PARANOID_SD_INIT=y +CONFIG_MMC_CLKGATE=y CONFIG_MMC_SDHCI=y CONFIG_MMC_SDHCI_PLTFM=y +CONFIG_MMC_SDHCI_MSM=y CONFIG_RTC_CLASS=y CONFIG_DMADEVICES=y CONFIG_QCOM_SPS_DMA=y -- GitLab From 1c95d27e3dcda19da91e4256f91064a3330e6e99 Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Thu, 19 Oct 2017 13:19:20 +0100 Subject: [PATCH 1416/1635] arm64: traps: Don't print stack or raw PC/LR values in backtraces Printing raw pointer values in backtraces has potential security implications and are of questionable value anyway. This patch follows x86's lead and removes the "Exception stack:" dump from kernel backtraces, as well as converting PC/LR values to symbols such as "sysrq_handle_crash+0x20/0x30". Change-Id: I417aa84c4314b9f53aaeb7f9bd0051f20373f884 Tested-by: Laura Abbott Signed-off-by: Will Deacon Git-commit: a25ffd3a6302a67814280274d8f1aa4ae2ea4b59 Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git Signed-off-by: Chintan Pandya --- arch/arm64/kernel/process.c | 8 ++--- arch/arm64/kernel/traps.c | 65 ++----------------------------------- 2 files changed, 6 insertions(+), 67 deletions(-) diff --git a/arch/arm64/kernel/process.c b/arch/arm64/kernel/process.c index 6fd6528a3b51..08f2c94d1c20 100644 --- a/arch/arm64/kernel/process.c +++ b/arch/arm64/kernel/process.c @@ -254,11 +254,9 @@ void __show_regs(struct pt_regs *regs) } show_regs_print_info(KERN_DEFAULT); - print_symbol("PC is at %s\n", instruction_pointer(regs)); - print_symbol("LR is at %s\n", lr); - printk("pc : [<%016llx>] lr : [<%016llx>] pstate: %08llx\n", - regs->pc, lr, regs->pstate); - printk("sp : %016llx\n", sp); + print_symbol("pc : %s\n", regs->pc); + print_symbol("lr : %s\n", lr); + printk("sp : %016llx pstate : %08llx\n", sp, regs->pstate); i = top_reg; diff --git a/arch/arm64/kernel/traps.c b/arch/arm64/kernel/traps.c index 207778611fb9..0249306818c9 100644 --- a/arch/arm64/kernel/traps.c +++ b/arch/arm64/kernel/traps.c @@ -60,55 +60,9 @@ static const char *handler[]= { int show_unhandled_signals = 0; -/* - * Dump out the contents of some kernel memory nicely... - */ -static void dump_mem(const char *lvl, const char *str, unsigned long bottom, - unsigned long top) -{ - unsigned long first; - mm_segment_t fs; - int i; - - /* - * We need to switch to kernel mode so that we can use __get_user - * to safely read from kernel space. - */ - fs = get_fs(); - set_fs(KERNEL_DS); - - printk("%s%s(0x%016lx to 0x%016lx)\n", lvl, str, bottom, top); - - for (first = bottom & ~31; first < top; first += 32) { - unsigned long p; - char str[sizeof(" 12345678") * 8 + 1]; - - memset(str, ' ', sizeof(str)); - str[sizeof(str) - 1] = '\0'; - - for (p = first, i = 0; i < (32 / 8) - && p < top; i++, p += 8) { - if (p >= bottom && p < top) { - unsigned long val; - - if (__get_user(val, (unsigned long *)p) == 0) - sprintf(str + i * 17, " %016lx", val); - else - sprintf(str + i * 17, " ????????????????"); - } - } - printk("%s%04lx:%s\n", lvl, first & 0xffff, str); - } - - set_fs(fs); -} - static void dump_backtrace_entry(unsigned long where) { - /* - * Note that 'where' can have a physical address, but it's not handled. - */ - print_ip_sym(where); + printk(" %pS\n", (void *)where); } static void __dump_instr(const char *lvl, struct pt_regs *regs) @@ -173,10 +127,7 @@ void dump_backtrace(struct pt_regs *regs, struct task_struct *tsk) skip = !!regs; printk("Call trace:\n"); - while (1) { - unsigned long stack; - int ret; - + do { /* skip until specified stack frame */ if (!skip) { dump_backtrace_entry(frame.pc); @@ -191,17 +142,7 @@ void dump_backtrace(struct pt_regs *regs, struct task_struct *tsk) */ dump_backtrace_entry(regs->pc); } - ret = unwind_frame(tsk, &frame); - if (ret < 0) - break; - if (in_entry_text(frame.pc)) { - stack = frame.fp - offsetof(struct pt_regs, stackframe); - - if (on_accessible_stack(tsk, stack)) - dump_mem("", "Exception stack", stack, - stack + sizeof(struct pt_regs)); - } - } + } while (!unwind_frame(tsk, &frame)); put_task_stack(tsk); } -- GitLab From a441381ca6f94ffd2fb75be3ee9fa1be6bd078f2 Mon Sep 17 00:00:00 2001 From: Konstantin Dorfman Date: Mon, 7 May 2018 11:53:43 +0300 Subject: [PATCH 1417/1635] spcom: fix deadlock when add/remove new channel This change resolves following 2 deadlocks: The register_rpmsg_drv() called under ch->lock. When newly created (by rpmsg layer) rpmsg device probe arrives during the rpmsg driver is registering - deadlock on channel lock occurs. When channel is closing (by unregister_rpmsg_drv(), under ch->lock) this causes call to spcom_rpdev_remove() for the rpmsg device (managed by unregestered driver). The spcom_rpdev_remove() causes deadlock on ch->lock. To resolve these deadlocks move register/unregister_rpmsg_drv() calls out of the ch->lock. Also, do not need to unregister_rpmsg_drv() on spcom_device_release() - since SP side never initiates glink_close() Change-Id: I77661f82f3719d1153483ef31f8ff9fef7fb99a3 Signed-off-by: Konstantin Dorfman --- drivers/soc/qcom/spcom.c | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/drivers/soc/qcom/spcom.c b/drivers/soc/qcom/spcom.c index 5394445ecfc4..0f77c18629ae 100644 --- a/drivers/soc/qcom/spcom.c +++ b/drivers/soc/qcom/spcom.c @@ -1300,13 +1300,6 @@ static int spcom_device_release(struct inode *inode, struct file *filp) ch->is_busy = false; ch->pid = 0; ch->txn_id = INITIAL_TXN_ID; /* use non-zero nonce for debug */ - - if (strcmp(name, "sp_kernel") != 0) { - ret = spcom_unregister_rpmsg_drv(ch); - if (ret != 0) - pr_err("can't unregister rpmsg drv\n", ret); - } - mutex_unlock(&ch->lock); filp->private_data = NULL; @@ -1621,7 +1614,6 @@ static int spcom_create_channel_chardev(const char *name) return ret; } - mutex_lock(&ch->lock); ret = spcom_register_rpmsg_drv(ch); if (ret < 0) { pr_err("register rpmsg driver failed %d\n", ret); @@ -1653,6 +1645,7 @@ static int spcom_create_channel_chardev(const char *name) goto exit_destroy_device; } atomic_inc(&spcom_dev->chdev_count); + mutex_lock(&ch->lock); ch->cdev = cdev; ch->dev = dev; mutex_unlock(&ch->lock); @@ -1939,10 +1932,7 @@ static void spcom_rpdev_remove(struct rpmsg_device *rpdev) dev_info(&rpdev->dev, "rpmsg device %s removed\n", rpdev->id.name); } -/* - * register rpmsg driver to match with channel ch_name - * function shold be called under ch->lock - */ +/* register rpmsg driver to match with channel ch_name */ static int spcom_register_rpmsg_drv(struct spcom_channel *ch) { struct rpmsg_driver *rpdrv; @@ -1989,25 +1979,27 @@ static int spcom_register_rpmsg_drv(struct spcom_channel *ch) kfree(drv_name); return ret; } - // the function caller should mutex_lock(&ch->lock) + mutex_lock(&ch->lock); ch->rpdrv = rpdrv; ch->rpmsg_abort = false; + mutex_unlock(&ch->lock); return 0; } -/* function shold be called under ch->lock */ static int spcom_unregister_rpmsg_drv(struct spcom_channel *ch) { if (!ch->rpdrv) return -ENODEV; unregister_rpmsg_driver(ch->rpdrv); + mutex_lock(&ch->lock); kfree(ch->rpdrv->drv.name); kfree((void *)ch->rpdrv->id_table); kfree(ch->rpdrv); ch->rpdrv = NULL; ch->rpmsg_abort = true; /* will unblock spcom_rx() */ + mutex_unlock(&ch->lock); return 0; } -- GitLab From b5f2284cfdb5c955eec32b3444f3fc70cd8d3537 Mon Sep 17 00:00:00 2001 From: Naresh Malladi Date: Fri, 16 Jun 2017 11:56:21 +0530 Subject: [PATCH 1418/1635] drivers: cpuidle: lpm-levels: Remove IPI check on hotplugged cores Currently checking pending IPIs even on cores which are hotplugged out successfully. This check should happen only for cores which are online. Change-Id: I8fe49638f308eab97455e7cca62b01b617596de4 Signed-off-by: Naresh Malladi Signed-off-by: Maulik Shah --- drivers/cpuidle/lpm-levels.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/cpuidle/lpm-levels.c b/drivers/cpuidle/lpm-levels.c index 4ad9220b43f3..3a091ea013c7 100644 --- a/drivers/cpuidle/lpm-levels.c +++ b/drivers/cpuidle/lpm-levels.c @@ -1026,9 +1026,8 @@ static int cluster_configure(struct lpm_cluster *cluster, int idx, cpu_online_mask); if (!cpumask_equal(&cluster->num_children_in_sync, &cluster->child_cpus) - || is_IPI_pending(&cluster->num_children_in_sync)) { + || is_IPI_pending(&online_cpus)) return -EPERM; - } if (idx != cluster->default_level) { update_debug_pc_event(CLUSTER_ENTER, idx, -- GitLab From b9d5b78171cc153bc28b441c23d91e5a765bcf77 Mon Sep 17 00:00:00 2001 From: Mohammed Javid Date: Thu, 19 Apr 2018 13:41:16 +0530 Subject: [PATCH 1419/1635] msm: ipa: rmnet: Make code changes with respect to CR#2046006 Check for CAP_NET_ADMIN capability of the user space application which tries to access rmnet driver IOCTL. Change-Id: If6bb4b54659306c5103b5e34bf02c7234c851e0a CRs-Fixed: 2226355 Signed-off-by: Mohammed Javid --- drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c b/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c index b142f1079fe1..357e5efc4add 100644 --- a/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c +++ b/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c @@ -1531,6 +1531,8 @@ static int ipa3_wwan_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) /* Extended IOCTLs */ case RMNET_IOCTL_EXTENDED: + if (!ns_capable(dev_net(dev)->user_ns, CAP_NET_ADMIN)) + return -EPERM; IPAWANDBG("get ioctl: RMNET_IOCTL_EXTENDED\n"); if (copy_from_user(&ext_ioctl_data, (u8 *)ifr->ifr_ifru.ifru_data, -- GitLab From 91f9d7fcfd9ced4116ddfefe4c4cdabbc0af713a Mon Sep 17 00:00:00 2001 From: Dhoat Harpal Date: Mon, 7 May 2018 15:54:17 +0530 Subject: [PATCH 1420/1635] defconfig: arm: qcs405: Enable MPROC drivers Enable SMEM, RPMSG and Glink drivers for communication with MPSS, LPASS and CDSP. CRs-Fixed: 2223479 Change-Id: Ic7a0b662a0870f2e97f8a19abdb789b44c990efb Signed-off-by: Dhoat Harpal --- arch/arm/configs/qcs405-perf_defconfig | 12 +++++++++++- arch/arm/configs/qcs405_defconfig | 10 +++++++++- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/arch/arm/configs/qcs405-perf_defconfig b/arch/arm/configs/qcs405-perf_defconfig index 6c8ed29ed2da..1c11acabf51c 100644 --- a/arch/arm/configs/qcs405-perf_defconfig +++ b/arch/arm/configs/qcs405-perf_defconfig @@ -170,6 +170,8 @@ CONFIG_NET_EMATCH_U32=y CONFIG_NET_EMATCH_META=y CONFIG_NET_EMATCH_TEXT=y CONFIG_NET_CLS_ACT=y +CONFIG_QRTR=y +CONFIG_QRTR_SMD=y CONFIG_RMNET_DATA=y CONFIG_RMNET_DATA_FC=y CONFIG_BT=y @@ -250,7 +252,6 @@ CONFIG_SPI_SPIDEV=y CONFIG_PINCTRL_QCS405=y CONFIG_GPIOLIB=y CONFIG_THERMAL=y -CONFIG_MFD_SYSCON=y CONFIG_REGULATOR=y CONFIG_REGULATOR_FIXED_VOLTAGE=y CONFIG_REGULATOR_FAN53555=y @@ -315,13 +316,22 @@ CONFIG_ION=y CONFIG_COMMON_CLK_QCOM=y CONFIG_MDM_GCC_QCS405=y CONFIG_HWSPINLOCK=y +CONFIG_HWSPINLOCK_QCOM=y CONFIG_MAILBOX=y +CONFIG_QCOM_APCS_IPC=y +CONFIG_RPMSG_CHAR=y +CONFIG_RPMSG_QCOM_GLINK_RPM=y +CONFIG_RPMSG_QCOM_GLINK_SMEM=y +CONFIG_QCOM_QMI_HELPERS=y CONFIG_QCOM_SMEM=y CONFIG_QCOM_SCM=y +CONFIG_QCOM_SMP2P=y CONFIG_MSM_SUBSYSTEM_RESTART=y CONFIG_MSM_PIL=y CONFIG_MSM_BOOT_STATS=y CONFIG_MSM_CORE_HANG_DETECT=y +CONFIG_QCOM_GLINK=y +CONFIG_QCOM_GLINK_PKT=y CONFIG_PWM=y CONFIG_ANDROID=y CONFIG_ANDROID_BINDER_IPC=y diff --git a/arch/arm/configs/qcs405_defconfig b/arch/arm/configs/qcs405_defconfig index 5ddcb0c1079c..c93cc273e139 100644 --- a/arch/arm/configs/qcs405_defconfig +++ b/arch/arm/configs/qcs405_defconfig @@ -177,6 +177,7 @@ CONFIG_NET_EMATCH_META=y CONFIG_NET_EMATCH_TEXT=y CONFIG_NET_CLS_ACT=y CONFIG_QRTR=y +CONFIG_QRTR_SMD=y CONFIG_RMNET_DATA=y CONFIG_RMNET_DATA_FC=y CONFIG_RMNET_DATA_DEBUG_PKT=y @@ -260,7 +261,6 @@ CONFIG_PINCTRL_QCS405=y CONFIG_GPIOLIB=y CONFIG_POWER_SUPPLY=y CONFIG_THERMAL=y -CONFIG_MFD_SYSCON=y CONFIG_REGULATOR=y CONFIG_REGULATOR_FIXED_VOLTAGE=y CONFIG_REGULATOR_FAN53555=y @@ -332,17 +332,25 @@ CONFIG_ION=y CONFIG_COMMON_CLK_QCOM=y CONFIG_MDM_GCC_QCS405=y CONFIG_HWSPINLOCK=y +CONFIG_HWSPINLOCK_QCOM=y CONFIG_MAILBOX=y +CONFIG_QCOM_APCS_IPC=y CONFIG_QCOM_LAZY_MAPPING=y CONFIG_IOMMU_DEBUG=y CONFIG_QCOM_IOMMU=y +CONFIG_RPMSG_CHAR=y +CONFIG_RPMSG_QCOM_GLINK_RPM=y +CONFIG_RPMSG_QCOM_GLINK_SMEM=y CONFIG_QCOM_QMI_HELPERS=y CONFIG_QCOM_SMEM=y CONFIG_QCOM_SCM=y +CONFIG_QCOM_SMP2P=y CONFIG_MSM_SUBSYSTEM_RESTART=y CONFIG_MSM_PIL=y CONFIG_MSM_BOOT_STATS=y CONFIG_MSM_CORE_HANG_DETECT=y +CONFIG_QCOM_GLINK=y +CONFIG_QCOM_GLINK_PKT=y # CONFIG_MSM_JTAGV8 is not set CONFIG_PWM=y CONFIG_ANDROID=y -- GitLab From 9b0eb78de658d19e6eb091db34856ced2bb3199d Mon Sep 17 00:00:00 2001 From: Dhoat Harpal Date: Mon, 16 Apr 2018 20:15:38 +0530 Subject: [PATCH 1421/1635] ARM: dts: msm: Add MPROC device nodes for SM6150 Add SMEM, TCSR Mutex, Glink and SMP2P devices for enabling interprocessor communication with MPSS, LPASS and CDSP. CRs-Fixed: 2237294 Change-Id: Ia075d46cbc936b787ffb666f84b1318cc355645f Signed-off-by: Dhoat Harpal --- arch/arm64/boot/dts/qcom/sm6150.dtsi | 277 +++++++++++++++++++++++++++ 1 file changed, 277 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sm6150.dtsi b/arch/arm64/boot/dts/qcom/sm6150.dtsi index dd1e09215346..539f467982f1 100644 --- a/arch/arm64/boot/dts/qcom/sm6150.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6150.dtsi @@ -1056,6 +1056,283 @@ iommus = <&apps_smmu 0x17f3 0x0>; }; }; + + tcsr_mutex_block: syscon@1f40000 { + compatible = "syscon"; + reg = <0x1f40000 0x20000>; + }; + + tcsr_mutex: hwlock { + compatible = "qcom,tcsr-mutex"; + syscon = <&tcsr_mutex_block 0 0x1000>; + #hwlock-cells = <1>; + }; + + smem: qcom,smem { + compatible = "qcom,smem"; + memory-region = <&smem_region>; + hwlocks = <&tcsr_mutex 3>; + }; + + apcs: syscon@17c0000c { + compatible = "syscon"; + reg = <0x17c0000c 0x4>; + }; + + apcs_glb: mailbox@17c00000 { + compatible = "qcom,sm8150-apcs-hmss-global"; + reg = <0x17c00000 0x1000>; + + #mbox-cells = <1>; + }; + + qcom,glink { + compatible = "qcom,glink"; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + glink_modem: modem { + qcom,remote-pid = <1>; + transport = "smem"; + mboxes = <&apcs_glb 12>; + mbox-names = "mpss_smem"; + interrupts = ; + + label = "modem"; + qcom,glink-label = "mpss"; + + qcom,modem_qrtr { + qcom,glink-channels = "IPCRTR"; + qcom,intents = <0x800 5 + 0x2000 3 + 0x4400 2>; + }; + + qcom,msm_fastrpc_rpmsg { + compatible = "qcom,msm-fastrpc-rpmsg"; + qcom,glink-channels = "fastrpcglink-apps-dsp"; + qcom,intents = <0x64 64>; + }; + + qcom,modem_ds { + qcom,glink-channels = "DS"; + qcom,intents = <0x4000 0x2>; + }; + + qcom,modem_glink_ssr { + qcom,glink-channels = "glink_ssr"; + qcom,notify-edges = <&glink_adsp>, + <&glink_cdsp>; + }; + }; + + glink_adsp: adsp { + qcom,remote-pid = <2>; + transport = "smem"; + mboxes = <&apcs_glb 24>; + mbox-names = "adsp_smem"; + interrupts = ; + + label = "adsp"; + qcom,glink-label = "lpass"; + + qcom,adsp_qrtr { + qcom,glink-channels = "IPCRTR"; + qcom,intents = <0x800 5 + 0x2000 3 + 0x4400 2>; + }; + + qcom,apr_tal_rpmsg { + qcom,glink-channels = "apr_audio_svc"; + qcom,intents = <0x200 20>; + }; + + qcom,msm_fastrpc_rpmsg { + compatible = "qcom,msm-fastrpc-rpmsg"; + qcom,glink-channels = "fastrpcglink-apps-dsp"; + qcom,intents = <0x64 64>; + }; + + qcom,adsp_glink_ssr { + qcom,glink-channels = "glink_ssr"; + qcom,notify-edges = <&glink_modem>, + <&glink_cdsp>; + }; + }; + + glink_cdsp: cdsp { + qcom,remote-pid = <5>; + transport = "smem"; + mboxes = <&apcs_glb 4>; + mbox-names = "cdsp_smem"; + interrupts = ; + + label = "cdsp"; + qcom,glink-label = "cdsp"; + + qcom,cdsp_qrtr { + qcom,glink-channels = "IPCRTR"; + qcom,intents = <0x800 5 + 0x2000 3 + 0x4400 2>; + }; + + qcom,msm_fastrpc_rpmsg { + compatible = "qcom,msm-fastrpc-rpmsg"; + qcom,glink-channels = "fastrpcglink-apps-dsp"; + qcom,intents = <0x64 64>; + }; + + qcom,cdsp_glink_ssr { + qcom,glink-channels = "glink_ssr"; + qcom,notify-edges = <&glink_modem>, + <&glink_adsp>; + }; + }; + + glink_spi_xprt_wdsp: wdsp { + qcom,remote-pid = <10>; + transport = "spi"; + tx-descriptors = <0x12000 0x12004>; + rx-descriptors = <0x1200c 0x12010>; + + qcom,wdsp_ctrl { + qcom,glink-channels = "g_glink_ctrl"; + qcom,intents = <0x400 1>; + }; + + qcom,wdsp_ild { + qcom,glink-channels = + "g_glink_persistent_data_ild"; + }; + + qcom,wdsp_nild { + qcom,glink-channels = + "g_glink_persistent_data_nild"; + }; + + qcom,wdsp_data { + qcom,glink-channels = "g_glink_audio_data"; + qcom,intents = <0x1000 2>; + }; + }; + }; + + qcom,glinkpkt { + compatible = "qcom,glinkpkt"; + + qcom,glinkpkt-at-mdm0 { + qcom,glinkpkt-edge = "mpss"; + qcom,glinkpkt-ch-name = "DS"; + qcom,glinkpkt-dev-name = "at_mdm0"; + }; + + qcom,glinkpkt-apr-apps2 { + qcom,glinkpkt-edge = "adsp"; + qcom,glinkpkt-ch-name = "apr_apps2"; + qcom,glinkpkt-dev-name = "apr_apps2"; + }; + + qcom,glinkpkt-data40-cntl { + qcom,glinkpkt-edge = "mpss"; + qcom,glinkpkt-ch-name = "DATA40_CNTL"; + qcom,glinkpkt-dev-name = "smdcntl8"; + }; + + qcom,glinkpkt-data1 { + qcom,glinkpkt-edge = "mpss"; + qcom,glinkpkt-ch-name = "DATA1"; + qcom,glinkpkt-dev-name = "smd7"; + }; + + qcom,glinkpkt-data4 { + qcom,glinkpkt-edge = "mpss"; + qcom,glinkpkt-ch-name = "DATA4"; + qcom,glinkpkt-dev-name = "smd8"; + }; + + qcom,glinkpkt-data11 { + qcom,glinkpkt-edge = "mpss"; + qcom,glinkpkt-ch-name = "DATA11"; + qcom,glinkpkt-dev-name = "smd11"; + }; + }; + + qmp_aop: qcom,qmp-aop@c300000 { + compatible = "qcom,qmp-mbox"; + reg = <0xc300000 0x1000>, <0x17c0000C 0x4>; + reg-names = "msgram", "irq-reg-base"; + qcom,irq-mask = <0x1>; + interrupts = ; + + label = "aop"; + qcom,early-boot; + priority = <0>; + mbox-desc-offset = <0x0>; + #mbox-cells = <1>; + }; + + qcom,smp2p-modem { + compatible = "qcom,smp2p"; + qcom,smem = <435>, <428>; + interrupts = ; + qcom,ipc = <&apcs 0 14>; + qcom,local-pid = <0>; + qcom,remote-pid = <1>; + + modem_smp2p_out: master-kernel { + qcom,entry-name = "master-kernel"; + #qcom,smem-state-cells = <1>; + }; + + modem_smp2p_in: slave-kernel { + qcom,entry-name = "slave-kernel"; + interrupt-controller; + #interrupt-cells = <2>; + }; + }; + + qcom,smp2p-adsp { + compatible = "qcom,smp2p"; + qcom,smem = <443>, <429>; + interrupts = ; + qcom,ipc = <&apcs 0 26>; + qcom,local-pid = <0>; + qcom,remote-pid = <2>; + + adsp_smp2p_out: master-kernel { + qcom,entry-name = "master-kernel"; + #qcom,smem-state-cells = <1>; + }; + + adsp_smp2p_in: slave-kernel { + qcom,entry-name = "slave-kernel"; + interrupt-controller; + #interrupt-cells = <2>; + }; + }; + + qcom,smp2p-cdsp { + compatible = "qcom,smp2p"; + qcom,smem = <94>, <432>; + interrupts = ; + qcom,ipc = <&apcs 0 6>; + qcom,local-pid = <0>; + qcom,remote-pid = <5>; + + cdsp_smp2p_out: master-kernel { + qcom,entry-name = "master-kernel"; + #qcom,smem-state-cells = <1>; + }; + + cdsp_smp2p_in: slave-kernel { + qcom,entry-name = "slave-kernel"; + interrupt-controller; + #interrupt-cells = <2>; + }; + }; }; #include "pm640.dtsi" -- GitLab From 56dc607578b191a1b3c5489171c6de01183e036d Mon Sep 17 00:00:00 2001 From: Charan Teja Reddy Date: Wed, 7 Dec 2016 18:40:57 +0530 Subject: [PATCH 1422/1635] arm: dma_mapping: Support for DOMAIN_ATTR_S1_BYPASS attribute For iommus which do not use stage1 translation, stage2 may not be aware of the device's dma_mask requirements. Choose the dma_ops such that allocations are made within the dma_mask region and bounce buffers are used as necessary. Change-Id: I63ae3ff9e5ab608892d12db7a813264d234699ee Signed-off-by: Charan Teja Reddy --- arch/arm/mm/dma-mapping.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c index aba8ef827345..71e941536369 100644 --- a/arch/arm/mm/dma-mapping.c +++ b/arch/arm/mm/dma-mapping.c @@ -2332,12 +2332,16 @@ int arm_iommu_attach_device(struct device *dev, struct dma_iommu_mapping *mapping) { int err; + int s1_bypass = 0; err = __arm_iommu_attach_device(dev, mapping); if (err) return err; - set_dma_ops(dev, &iommu_ops); + iommu_domain_get_attr(mapping->domain, DOMAIN_ATTR_S1_BYPASS, + &s1_bypass); + if (!s1_bypass) + set_dma_ops(dev, &iommu_ops); return 0; } EXPORT_SYMBOL_GPL(arm_iommu_attach_device); @@ -2352,6 +2356,7 @@ EXPORT_SYMBOL_GPL(arm_iommu_attach_device); void arm_iommu_detach_device(struct device *dev) { struct dma_iommu_mapping *mapping; + int s1_bypass = 0; mapping = to_dma_iommu_mapping(dev); if (!mapping) { @@ -2362,7 +2367,8 @@ void arm_iommu_detach_device(struct device *dev) iommu_detach_device(mapping->domain, dev); kref_put(&mapping->kref, release_iommu_mapping); to_dma_iommu_mapping(dev) = NULL; - set_dma_ops(dev, NULL); + if (!s1_bypass) + set_dma_ops(dev, NULL); pr_debug("Detached IOMMU controller from %s device.\n", dev_name(dev)); } -- GitLab From 06c43d9e79a46559d2183e6ac438ef038378e399 Mon Sep 17 00:00:00 2001 From: Shiraz Hashim Date: Fri, 11 Aug 2017 17:49:28 +0530 Subject: [PATCH 1423/1635] arm: provision page alloc debug support Equip arm to support ARCH_SUPPORTS_DEBUG_PAGEALLOC and enable it by default. Having this support means all pages freed at buddy level would be marked as read-only and would help catch any scribbling over free page area. Allocated pages mapping attributes is restored to read/write. ARCH_SUPPORTS_DEBUG_PAGEALLOC needs FORCE_PAGES which ensures all kernel mapping are populated with page granularity and it would ensure page level accesses can be rightly configured. Change-Id: I9b23d1fb0b9594cc148b082c104da9a773c26057 Signed-off-by: Shiraz Hashim Signed-off-by: Charan Teja Reddy --- arch/arm/Kconfig.debug | 4 ++++ arch/arm/mm/pageattr.c | 18 +++++++++++++++++- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug index cbd447251355..a6cebd5e9a6b 100644 --- a/arch/arm/Kconfig.debug +++ b/arch/arm/Kconfig.debug @@ -63,6 +63,10 @@ config DEBUG_USER 8 - SIGSEGV faults 16 - SIGBUS faults +config ARCH_SUPPORTS_DEBUG_PAGEALLOC + def_bool y + depends on FORCE_PAGES + config FORCE_PAGES bool "Force lowmem to be mapped with 4K pages" help diff --git a/arch/arm/mm/pageattr.c b/arch/arm/mm/pageattr.c index 86e441bad6e3..365dc9d7756c 100644 --- a/arch/arm/mm/pageattr.c +++ b/arch/arm/mm/pageattr.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, The Linux Foundation. All rights reserved. + * Copyright (c) 2014,2017-2018 The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -98,3 +98,19 @@ int set_memory_x(unsigned long addr, int numpages) __pgprot(0), __pgprot(L_PTE_XN)); } + +#ifdef CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC +void __kernel_map_pages(struct page *page, int numpages, int enable) +{ + unsigned long addr; + + if (PageHighMem(page)) + return; + + addr = (unsigned long) page_address(page); + if (enable) + set_memory_rw(addr, numpages); + else + set_memory_ro(addr, numpages); +} +#endif -- GitLab From eb5c4e0e0d4e27ba4d500e55bd9a20f80fceeaee Mon Sep 17 00:00:00 2001 From: Charan Teja Reddy Date: Tue, 18 Apr 2017 18:45:19 +0530 Subject: [PATCH 1424/1635] arm: dma-mapping: WARN_ON if iova is not 128M aligned Enforce 128M alignment on the IOVA for the proper virtual address to be returned by the bitmap_() API's through alloc_iova(). The current implementation causes the bitmap index search out of bounds of a page if not 128M aligned. Change-Id: Ie57ca0b7465c91d318145ed270b7d47d822c8eeb Fixes:I88ddd98a76b ("arm/arm64: dma-mapping: Fix iova region size") Signed-off-by: Charan Teja Reddy --- arch/arm/mm/dma-mapping.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c index aba8ef827345..42482fcd7833 100644 --- a/arch/arm/mm/dma-mapping.c +++ b/arch/arm/mm/dma-mapping.c @@ -2218,6 +2218,9 @@ arm_iommu_create_mapping(struct bus_type *bus, dma_addr_t base, u64 size) if (!bitmap_size) return ERR_PTR(-EINVAL); + WARN(!IS_ALIGNED(size, SZ_128M), + "size is not aligned to 128M, alignment enforced"); + if (bitmap_size > PAGE_SIZE) { extensions = bitmap_size / PAGE_SIZE; bitmap_size = PAGE_SIZE; -- GitLab From 1323aed90816db1e32b6e33f6d6f5fa6280b900d Mon Sep 17 00:00:00 2001 From: Jilai Wang Date: Mon, 7 May 2018 08:10:29 -0400 Subject: [PATCH 1425/1635] npu: Don't disable post clk if not enabled If post clock is not enabled, don't disable it to avoid crash. Change-Id: I422903fb2ccb6da5b4f892b9ef4185751ae929d9 Signed-off-by: Jilai Wang --- drivers/media/platform/msm/npu/npu_dev.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/media/platform/msm/npu/npu_dev.c b/drivers/media/platform/msm/npu/npu_dev.c index 4abd72a66320..461bfd2a1bfd 100644 --- a/drivers/media/platform/msm/npu/npu_dev.c +++ b/drivers/media/platform/msm/npu/npu_dev.c @@ -536,6 +536,11 @@ static void npu_disable_core_clocks(struct npu_device *npu_dev) for (i = (npu_dev->core_clk_num)-1; i >= 0 ; i--) { if (npu_is_exclude_clock(core_clks[i].clk_name)) continue; + if (!npu_dev->host_ctx.fw_enabled) { + if (npu_is_post_clock(npu_dev->core_clks[i].clk_name)) + continue; + } + pr_debug("disabling clock [%s]\n", core_clks[i].clk_name); clk_disable_unprepare(core_clks[i].clk); } -- GitLab From c294736830c80058721cc8a65eb1512503817860 Mon Sep 17 00:00:00 2001 From: Charan Teja Reddy Date: Mon, 9 Apr 2018 14:58:04 +0530 Subject: [PATCH 1426/1635] ARM: dts: msm: add memory map for qcs405 Add support for initial memory map configuration for qcs405 target. Change-Id: I35740a4173a5439a040a604d3e5d08eaff33effd Signed-off-by: Charan Teja Reddy --- arch/arm64/boot/dts/qcom/qcs405.dtsi | 61 ++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/qcs405.dtsi b/arch/arm64/boot/dts/qcom/qcs405.dtsi index f07ca3bb25a0..a1479c2a30b6 100644 --- a/arch/arm64/boot/dts/qcom/qcs405.dtsi +++ b/arch/arm64/boot/dts/qcom/qcs405.dtsi @@ -34,10 +34,71 @@ #size-cells = <2>; ranges; + removed_region0: removed_region@85600000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0x85600000 0x0 0x900000>; + }; + smem_region: smem@85f00000 { no-map; reg = <0x0 0x85f00000 0x0 0x200000>; }; + + removed_region1: removed_region@86100000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0x86100000 0x0 0x300000>; + }; + + wlan_fw_mem: wlan_fw_mem@86400000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0x86400000 0x0 0x1c00000>; + }; + + adsp_fw_mem: adsp_fw_mem@88000000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0x88000000 0x0 0x1a00000>; + }; + + cdsp_fw_mem: cdsp_fw_mem@89a00000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0x89a00000 0x0 0x600000>; + }; + + secure_mem: secure_region { + compatible = "shared-dma-pool"; + reusable; + alignment = <0 0x400000>; + size = <0 0x7000000>; + }; + + qseecom_mem: qseecom_region { + compatible = "shared-dma-pool"; + reusable; + alignment = <0 0x400000>; + size = <0 0x1000000>; + }; + + adsp_mem: adsp_region { + compatible = "shared-dma-pool"; + reusable; + alignment = <0 0x400000>; + size = <0 0x400000>; + }; + + /* global autoconfigured region for contiguous allocations */ + linux,cma { + compatible = "shared-dma-pool"; + alloc-ranges = <0 0x00000000 0 0xffffffff>; + reusable; + alignment = <0 0x400000>; + size = <0 0x1000000>; + linux,cma-default; + }; }; aliases { }; -- GitLab From 5a6ca6534892e6c04fb36760311ba6b34b8e4108 Mon Sep 17 00:00:00 2001 From: Jonathan Avila Date: Wed, 2 May 2018 08:52:08 -0700 Subject: [PATCH 1427/1635] devfreq: memlat: Add suspend/resume for mem_latency Add suspend/resume support for the mem_latency governor. Uses hwmon driver- defined suspend/resume calls in addition to monitor start/stop calls within the devfreq framework. Change-Id: I900b322a05cd0312f082d70640e21851879cb18c Signed-off-by: Jonathan Avila --- drivers/devfreq/governor_memlat.c | 72 ++++++++++++++++++++++++++++++- 1 file changed, 71 insertions(+), 1 deletion(-) diff --git a/drivers/devfreq/governor_memlat.c b/drivers/devfreq/governor_memlat.c index 12a90d41bc37..184f33f0ef18 100644 --- a/drivers/devfreq/governor_memlat.c +++ b/drivers/devfreq/governor_memlat.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. + * Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -43,6 +43,7 @@ struct memlat_node { struct memlat_hwmon *hw; struct devfreq_governor *gov; struct attribute_group *attr_grp; + unsigned long resume_freq; }; static LIST_HEAD(memlat_list); @@ -212,6 +213,39 @@ static int gov_start(struct devfreq *df) return ret; } +static int gov_suspend(struct devfreq *df) +{ + struct memlat_node *node = df->data; + unsigned long prev_freq = df->previous_freq; + + node->mon_started = false; + devfreq_monitor_suspend(df); + + mutex_lock(&df->lock); + update_devfreq(df); + mutex_unlock(&df->lock); + + node->resume_freq = max(prev_freq, 1UL); + + return 0; +} + +static int gov_resume(struct devfreq *df) +{ + struct memlat_node *node = df->data; + + mutex_lock(&df->lock); + update_devfreq(df); + mutex_unlock(&df->lock); + + node->resume_freq = 0; + + devfreq_monitor_resume(df); + node->mon_started = true; + + return 0; +} + static void gov_stop(struct devfreq *df) { struct memlat_node *node = df->data; @@ -233,6 +267,18 @@ static int devfreq_memlat_get_freq(struct devfreq *df, unsigned long max_freq = 0; unsigned int ratio; + /* + * node->resume_freq is set to 0 at the end of resume (after the update) + * and is set to df->prev_freq at the end of suspend (after the update). + * This function will be called as part of the update_devfreq call in + * both scenarios. As a result, this block will cause a 0 vote during + * suspend and a vote for df->prev_freq during resume. + */ + if (!node->mon_started) { + *freq = node->resume_freq; + return 0; + } + hw->get_cnt(hw); for (i = 0; i < hw->num_cores; i++) { @@ -331,6 +377,30 @@ static int devfreq_memlat_ev_handler(struct devfreq *df, "Disabled Memory Latency governor\n"); break; + case DEVFREQ_GOV_SUSPEND: + ret = gov_suspend(df); + if (ret) { + dev_err(df->dev.parent, + "Unable to suspend memlat governor (%d)\n", + ret); + return ret; + } + + dev_dbg(df->dev.parent, "Suspended memlat governor\n"); + break; + + case DEVFREQ_GOV_RESUME: + ret = gov_resume(df); + if (ret) { + dev_err(df->dev.parent, + "Unable to resume memlat governor (%d)\n", + ret); + return ret; + } + + dev_dbg(df->dev.parent, "Resumed memlat governor\n"); + break; + case DEVFREQ_GOV_INTERVAL: sample_ms = *(unsigned int *)data; sample_ms = max(MIN_MS, sample_ms); -- GitLab From d40c391cafa81f3c37625f678717d3b9e3292351 Mon Sep 17 00:00:00 2001 From: Deepak Katragadda Date: Tue, 13 Mar 2018 15:33:33 -0700 Subject: [PATCH 1428/1635] clk: qcom: debugcc-sm8150: Add measurement support for CPU clocks on SM8150 Add support to measure the rate of the l3, silver, gold, and gold plus clock domains on SM8150. Change-Id: Iec24b9d00ce302e7d19d46a4129c03b4a312f9a7 Signed-off-by: Deepak Katragadda --- .../devicetree/bindings/clock/qcom,debugcc.txt | 2 ++ arch/arm64/boot/dts/qcom/sm8150.dtsi | 6 ++++++ drivers/clk/qcom/clk-cpu-osm.c | 3 +++ drivers/clk/qcom/debugcc-sm8150.c | 16 ++++++++++++++++ 4 files changed, 27 insertions(+) diff --git a/Documentation/devicetree/bindings/clock/qcom,debugcc.txt b/Documentation/devicetree/bindings/clock/qcom,debugcc.txt index e0e95547c8a0..1b558f0f83fe 100644 --- a/Documentation/devicetree/bindings/clock/qcom,debugcc.txt +++ b/Documentation/devicetree/bindings/clock/qcom,debugcc.txt @@ -9,6 +9,7 @@ Required properties : - qcom,camcc: phandle to the Camera CC device node. - qcom,dispcc: phandle to the Display CC device node. - qcom,npucc: phandle to the NPU CC device node. +- qcom,cpucc: phandle to the CPU CC debug device node. - clock-names: Shall contain "xo_clk_src" - clocks: phandle + clock reference to the CXO clock. - #clock-cells : Shall contain 1. @@ -21,6 +22,7 @@ Example: qcom,camcc = <&clock_camcc>; qcom,dispcc = <&clock_dispcc>; qcom,npucc = <&clock_npucc>; + qcom,cpucc = <&cpucc_debug>; clock-names = "xo_clk_src"; clocks = <&clock_rpmh RPMH_CXO_CLK>; #clock-cells = <1>; diff --git a/arch/arm64/boot/dts/qcom/sm8150.dtsi b/arch/arm64/boot/dts/qcom/sm8150.dtsi index 5caf89841f6f..47f2d8970a0b 100644 --- a/arch/arm64/boot/dts/qcom/sm8150.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150.dtsi @@ -1421,6 +1421,11 @@ #reset-cells = <1>; }; + cpucc_debug: syscon@182a0018 { + compatible = "syscon"; + reg = <0x182a0018 0x4>; + }; + clock_cpucc: qcom,cpucc { compatible = "qcom,clk-cpu-osm"; reg = <0x18321000 0x1400>, @@ -1442,6 +1447,7 @@ qcom,dispcc = <&clock_dispcc>; qcom,npucc = <&clock_npucc>; qcom,gpucc = <&clock_gpucc>; + qcom,cpucc = <&cpucc_debug>; clock-names = "xo_clk_src"; clocks = <&clock_rpmh RPMH_CXO_CLK>; #clock-cells = <1>; diff --git a/drivers/clk/qcom/clk-cpu-osm.c b/drivers/clk/qcom/clk-cpu-osm.c index f176a22b01f8..434ea0bc3b1a 100644 --- a/drivers/clk/qcom/clk-cpu-osm.c +++ b/drivers/clk/qcom/clk-cpu-osm.c @@ -36,6 +36,7 @@ #include "common.h" #include "clk-regmap.h" #include "clk-voter.h" +#include "clk-debug.h" #define OSM_INIT_RATE 300000000UL #define XO_RATE 19200000UL @@ -169,6 +170,7 @@ static int clk_osm_search_table(struct osm_entry *table, int entries, long rate) const struct clk_ops clk_ops_cpu_osm = { .round_rate = clk_osm_round_rate, .list_rate = clk_osm_list_rate, + .debug_init = clk_debug_measure_add, }; static int clk_core_set_rate(struct clk_hw *hw, unsigned long rate, @@ -264,6 +266,7 @@ const static struct clk_ops clk_ops_l3_osm = { .list_rate = clk_osm_list_rate, .recalc_rate = l3_clk_recalc_rate, .set_rate = l3_clk_set_rate, + .debug_init = clk_debug_measure_add, }; static struct clk_init_data osm_clks_init[] = { diff --git a/drivers/clk/qcom/debugcc-sm8150.c b/drivers/clk/qcom/debugcc-sm8150.c index 889880b1bdbc..d30acb6ce87e 100644 --- a/drivers/clk/qcom/debugcc-sm8150.c +++ b/drivers/clk/qcom/debugcc-sm8150.c @@ -278,6 +278,10 @@ static const char *const debug_mux_parent_names[] = { "video_cc_mvs1_core_clk", "video_cc_mvsc_core_clk", "video_cc_xo_clk", + "l3_clk", + "pwrcl_clk", + "perfcl_clk", + "perfpcl_clk" }; static struct clk_debug_mux gcc_debug_mux = { @@ -780,6 +784,14 @@ static struct clk_debug_mux gcc_debug_mux = { 0x1, 0x3F, 0, 0x7, 0, 5, 0xA4C, 0x938, 0x940 }, { "video_cc_xo_clk", 0x57, 1, VIDEO_CC, 0x8, 0x3F, 0, 0x7, 0, 5, 0xA4C, 0x938, 0x940 }, + { "l3_clk", 0xE8, 4, CPU_CC, + 0x46, 0x7F, 4, 0xf, 11, 1, 0x0, 0x0, U32_MAX, 16 }, + { "pwrcl_clk", 0xE8, 4, CPU_CC, + 0x44, 0x7F, 4, 0xf, 11, 1, 0x0, 0x0, U32_MAX, 16 }, + { "perfcl_clk", 0xE8, 4, CPU_CC, + 0x45, 0x7F, 4, 0xf, 11, 1, 0x0, 0x0, U32_MAX, 16 }, + { "perfpcl_clk", 0xE8, 4, CPU_CC, + 0x47, 0x7F, 4, 0xf, 11, 1, 0x0, 0x0, U32_MAX, 16 }, ), .hw.init = &(struct clk_init_data){ .name = "gcc_debug_mux", @@ -854,6 +866,10 @@ static int clk_debug_sm8150_probe(struct platform_device *pdev) if (ret) return ret; + ret = map_debug_bases(pdev, "qcom,cpucc", CPU_CC); + if (ret) + return ret; + clk = devm_clk_register(&pdev->dev, &gcc_debug_mux.hw); if (IS_ERR(clk)) { dev_err(&pdev->dev, "Unable to register GCC debug mux\n"); -- GitLab From ca8867c680401054a949872c74ce90c823478f48 Mon Sep 17 00:00:00 2001 From: Dhaval Patel Date: Wed, 21 Feb 2018 11:05:32 -0800 Subject: [PATCH 1429/1635] drm/msm/sde: avoid flagging autorefresh poll timeout Autorefresh poll timeout may fail due to couple of conditions like display continuous splash disabled or autorefresh disable close to panel vsync. Avoid flagging poll timeout error because these conditions are recoverable. Change-Id: I6adf6d29faeb72746c6bb2b4538902569b180164 Signed-off-by: Dhaval Patel --- drivers/gpu/drm/msm/sde/sde_rm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/msm/sde/sde_rm.c b/drivers/gpu/drm/msm/sde/sde_rm.c index fe2e5511c4fa..92734565d80b 100644 --- a/drivers/gpu/drm/msm/sde/sde_rm.c +++ b/drivers/gpu/drm/msm/sde/sde_rm.c @@ -1211,7 +1211,7 @@ static u32 _sde_rm_poll_intr_status_for_cont_splash(struct sde_hw_intr *intr, } SDE_EVT32(status, irq_idx_pp_done, SDE_EVTLOG_ERROR); - SDE_ERROR("polling timed out. status = 0x%x\n", status); + SDE_DEBUG("polling timed out. status = 0x%x\n", status); return -ETIMEDOUT; } -- GitLab From 134d6ab2ebaabee70d424f9bc5f6d03897c9e345 Mon Sep 17 00:00:00 2001 From: Dhaval Patel Date: Thu, 22 Feb 2018 14:50:22 -0800 Subject: [PATCH 1430/1635] drm/msm/sde: avoid secure flag clear for multirect pipe Smart DMA hardware pipe allows secure buffer on rect_0 while non-secure buffer on rect_1 and vice versa. Current invalid address type programming may clear the buffer type bits when either rectangle configuration is coming out of order. For example, rect_0 configures the address type to secure when it parses buffer configuration. Rect_1 may wipe out the earlier programming if it is using non-secure buffer. This patch fixes the address type programming race condition. Change-Id: Ibf9f2408f55a98339fb977e709dd1ece23cfb784 Signed-off-by: Dhaval Patel [cohens@codeaurora.org: resolved trivial merge conflict] Signed-off-by: Steve Cohen --- drivers/gpu/drm/msm/msm_smmu.c | 4 ++-- drivers/gpu/drm/msm/sde/sde_hw_sspp.c | 23 ++++++++++++++--------- 2 files changed, 16 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/msm/msm_smmu.c b/drivers/gpu/drm/msm/msm_smmu.c index 6ce641e5750d..adc440cee46b 100644 --- a/drivers/gpu/drm/msm/msm_smmu.c +++ b/drivers/gpu/drm/msm/msm_smmu.c @@ -249,7 +249,7 @@ static int msm_smmu_map_dma_buf(struct msm_mmu *mmu, struct sg_table *sgt, &sgt->sgl->dma_address, sgt->sgl->dma_length, dir, attrs); SDE_EVT32(sgt->sgl->dma_address, sgt->sgl->dma_length, - dir, attrs); + dir, attrs, client->secure); } return 0; @@ -272,7 +272,7 @@ static void msm_smmu_unmap_dma_buf(struct msm_mmu *mmu, struct sg_table *sgt, &sgt->sgl->dma_address, sgt->sgl->dma_length, dir); SDE_EVT32(sgt->sgl->dma_address, sgt->sgl->dma_length, - dir); + dir, client->secure); } if (!(flags & MSM_BO_EXTBUF)) diff --git a/drivers/gpu/drm/msm/sde/sde_hw_sspp.c b/drivers/gpu/drm/msm/sde/sde_hw_sspp.c index 4533a1a825f3..8bf8e17331d9 100644 --- a/drivers/gpu/drm/msm/sde/sde_hw_sspp.c +++ b/drivers/gpu/drm/msm/sde/sde_hw_sspp.c @@ -389,19 +389,24 @@ static void sde_hw_sspp_setup_secure(struct sde_hw_pipe *ctx, c = &ctx->hw; - if (enable) { - if ((rect_mode == SDE_SSPP_RECT_SOLO) - || (rect_mode == SDE_SSPP_RECT_0)) - secure_bit_mask = - (rect_mode == SDE_SSPP_RECT_SOLO) ? 0xF : 0x5; - else - secure_bit_mask = 0xA; + if ((rect_mode == SDE_SSPP_RECT_SOLO) + || (rect_mode == SDE_SSPP_RECT_0)) + secure_bit_mask = + (rect_mode == SDE_SSPP_RECT_SOLO) ? 0xF : 0x5; + else + secure_bit_mask = 0xA; - secure = SDE_REG_READ(c, SSPP_SRC_ADDR_SW_STATUS + idx); + secure = SDE_REG_READ(c, SSPP_SRC_ADDR_SW_STATUS + idx); + + if (enable) secure |= secure_bit_mask; - } + else + secure &= ~secure_bit_mask; SDE_REG_WRITE(c, SSPP_SRC_ADDR_SW_STATUS + idx, secure); + + /* multiple planes share same sw_status register */ + wmb(); } -- GitLab From 7b23a7fc17e3b0cf04c9340f3710d6fb384d2e6c Mon Sep 17 00:00:00 2001 From: Krishna Manikandan Date: Thu, 25 May 2017 11:50:56 +0530 Subject: [PATCH 1431/1635] fbdev: core: Initialise structure to prevent kernel information leak The structure fix is initialised before its usage to prevent kernel information leak during copy_to_user. Change-Id: Ice4da4c9bd6095a4387e1d16cb20ca474accb9dc Signed-off-by: Krishna Manikandan --- drivers/video/fbdev/core/fbmem.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/video/fbdev/core/fbmem.c b/drivers/video/fbdev/core/fbmem.c index f741ba8df01b..1b4f1d5d07d6 100644 --- a/drivers/video/fbdev/core/fbmem.c +++ b/drivers/video/fbdev/core/fbmem.c @@ -1099,6 +1099,13 @@ static long do_fb_ioctl(struct fb_info *info, unsigned int cmd, void __user *argp = (void __user *)arg; long ret = 0; + memset(&var, 0, sizeof(var)); + memset(&fix, 0, sizeof(fix)); + memset(&con2fb, 0, sizeof(con2fb)); + memset(&cmap_from, 0, sizeof(cmap_from)); + memset(&cmap, 0, sizeof(cmap)); + memset(&event, 0, sizeof(event)); + switch (cmd) { case FBIOGET_VSCREENINFO: if (!lock_fb_info(info)) -- GitLab From 2837e8552cf51f012a8934b85879a80451897819 Mon Sep 17 00:00:00 2001 From: Harsh Sahu Date: Fri, 23 Mar 2018 00:29:30 -0700 Subject: [PATCH 1432/1635] msm: sde: check buffer size before writing to user buffer Check the number of bytes to copy against the size of the user buffer before copy to user to avoid buffer overflow. Change-Id: I95083227cfefaf1a81815296145b0c370127e061 Signed-off-by: Harsh Sahu --- drivers/media/platform/msm/sde/rotator/sde_rotator_debug.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_debug.c b/drivers/media/platform/msm/sde/rotator/sde_rotator_debug.c index 916f978ffdd1..f902135e1fdf 100644 --- a/drivers/media/platform/msm/sde/rotator/sde_rotator_debug.c +++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_debug.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -568,6 +568,11 @@ static ssize_t sde_rot_evtlog_dump_read(struct file *file, char __user *buff, if (__sde_rot_evtlog_dump_calc_range()) { len = sde_rot_evtlog_dump_entry(evtlog_buf, SDE_ROT_EVTLOG_BUF_MAX); + if (len < 0 || len > count) { + pr_err("len is more than the user buffer size\n"); + return 0; + } + if (copy_to_user(buff, evtlog_buf, len)) return -EFAULT; *ppos += len; -- GitLab From d12ce4621407499c6a362685d4328255159d4173 Mon Sep 17 00:00:00 2001 From: Veera Sundaram Sankaran Date: Wed, 7 Mar 2018 14:24:52 -0800 Subject: [PATCH 1433/1635] drm/msm/sde: enable secure-ui-misr feature for sdm845 target Enable the secure-ui-misr feature flag and add the blocked xin-mask for sdm845 target. The blocked xin-mask defines which xin-clients should be be blocked during secure-ui session. Change-Id: If89768ad7cda2e36b9ffff7810113e4e02b1e30e Signed-off-by: Veera Sundaram Sankaran --- drivers/gpu/drm/msm/sde/sde_hw_catalog.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/msm/sde/sde_hw_catalog.c b/drivers/gpu/drm/msm/sde/sde_hw_catalog.c index b1970be1ed43..0a401897837f 100644 --- a/drivers/gpu/drm/msm/sde/sde_hw_catalog.c +++ b/drivers/gpu/drm/msm/sde/sde_hw_catalog.c @@ -3522,16 +3522,20 @@ static int _sde_hardware_pre_caps(struct sde_mdss_cfg *sde_cfg, uint32_t hw_rev) rc = sde_hardware_format_caps(sde_cfg, hw_rev); if (IS_MSM8996_TARGET(hw_rev)) { - /* update msm8996 target here */ sde_cfg->perf.min_prefill_lines = 21; } else if (IS_MSM8998_TARGET(hw_rev)) { - /* update msm8998 target here */ sde_cfg->has_wb_ubwc = true; sde_cfg->perf.min_prefill_lines = 25; sde_cfg->vbif_qos_nlvl = 4; sde_cfg->ts_prefill_rev = 1; - } else if (IS_SDM845_TARGET(hw_rev) || IS_SDM670_TARGET(hw_rev)) { - /* update sdm845 target here */ + } else if (IS_SDM845_TARGET(hw_rev)) { + sde_cfg->has_wb_ubwc = true; + sde_cfg->perf.min_prefill_lines = 24; + sde_cfg->vbif_qos_nlvl = 8; + sde_cfg->ts_prefill_rev = 2; + sde_cfg->sui_misr_supported = true; + sde_cfg->sui_block_xin_mask = 0x3F71; + } else if (IS_SDM670_TARGET(hw_rev)) { sde_cfg->has_wb_ubwc = true; sde_cfg->perf.min_prefill_lines = 24; sde_cfg->vbif_qos_nlvl = 8; -- GitLab From 93a9dcc32086fbb49be7449cbde36721082de966 Mon Sep 17 00:00:00 2001 From: Veera Sundaram Sankaran Date: Sun, 25 Mar 2018 18:56:10 -0700 Subject: [PATCH 1434/1635] drm/msm/sde: enable few secure-ui related feature flags for sm8150 target Enable the secure-ui-misr feature flag and add the blocked xin-mask for sm8150 target. The blocked xin-mask defines which xin-clients should be be blocked during secure-ui session. And add the supported blend-stage during secure-ui restriction. Change-Id: I6e952e398cd72353ad8da12fd1d09d6eba265d1c Signed-off-by: Veera Sundaram Sankaran --- drivers/gpu/drm/msm/sde/sde_hw_catalog.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/gpu/drm/msm/sde/sde_hw_catalog.c b/drivers/gpu/drm/msm/sde/sde_hw_catalog.c index 0a401897837f..46533248d4c4 100644 --- a/drivers/gpu/drm/msm/sde/sde_hw_catalog.c +++ b/drivers/gpu/drm/msm/sde/sde_hw_catalog.c @@ -3548,6 +3548,8 @@ static int _sde_hardware_pre_caps(struct sde_mdss_cfg *sde_cfg, uint32_t hw_rev) sde_cfg->ctl_rev = SDE_CTL_CFG_VERSION_1_0_0; sde_cfg->delay_prg_fetch_start = true; sde_cfg->sui_ns_allowed = true; + sde_cfg->sui_misr_supported = true; + sde_cfg->sui_block_xin_mask = 0x3F71; } else if (IS_SDMSHRIKE_TARGET(hw_rev)) { sde_cfg->has_wb_ubwc = true; sde_cfg->perf.min_prefill_lines = 24; @@ -3573,6 +3575,10 @@ static int _sde_hardware_post_caps(struct sde_mdss_cfg *sde_cfg, if (!sde_cfg) return -EINVAL; + if (IS_SM8150_TARGET(hw_rev)) + sde_cfg->sui_supported_blendstage = + sde_cfg->max_mixer_blendstages - SDE_STAGE_0; + for (i = 0; i < sde_cfg->sspp_count; i++) { if (sde_cfg->sspp[i].sblk) { max_horz_deci = max(max_horz_deci, -- GitLab From 01f251ddb49bd317e23aad86663456dfc93b0fd1 Mon Sep 17 00:00:00 2001 From: Steve Cohen Date: Fri, 4 May 2018 17:37:22 -0400 Subject: [PATCH 1435/1635] drm/msm/sde: increment pending kickoff count after trigger start Increment the pending kickoff counter after the CTL start is triggered. This resolves a race condition when the vblank IRQ occurs after this counter has been incremented but before the new flush settings have been written to the HW causing frame buffers to be unmapped while HW is still accessing them. Change-Id: Idb5969c4349d4c036ca4c1739c920b6bebc97dd8 Signed-off-by: Steve Cohen --- drivers/gpu/drm/msm/sde/sde_encoder.c | 31 +++++++++++++++++++-------- 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/msm/sde/sde_encoder.c b/drivers/gpu/drm/msm/sde/sde_encoder.c index d1333d4271b7..239afa447f70 100644 --- a/drivers/gpu/drm/msm/sde/sde_encoder.c +++ b/drivers/gpu/drm/msm/sde/sde_encoder.c @@ -3410,17 +3410,10 @@ static void _sde_encoder_kickoff_phys(struct sde_encoder_virt *sde_enc) set_bit(i, sde_enc->frame_busy_mask); if (!phys->ops.needs_single_flush || - !phys->ops.needs_single_flush(phys)) { - pending_kickoff_cnt = - sde_encoder_phys_inc_pending(phys); + !phys->ops.needs_single_flush(phys)) _sde_encoder_trigger_flush(&sde_enc->base, phys, 0x0); - SDE_EVT32(pending_kickoff_cnt, SDE_EVTLOG_FUNC_CASE1); - } else if (ctl->ops.get_pending_flush) { - pending_kickoff_cnt = - sde_encoder_phys_inc_pending(phys); + else if (ctl->ops.get_pending_flush) ctl->ops.get_pending_flush(ctl, &pending_flush); - SDE_EVT32(pending_kickoff_cnt, SDE_EVTLOG_FUNC_CASE2); - } } /* for split flush, combine pending flush masks and send to master */ @@ -3433,6 +3426,26 @@ static void _sde_encoder_kickoff_phys(struct sde_encoder_virt *sde_enc) _sde_encoder_trigger_start(sde_enc->cur_master); + /* update pending_kickoff_cnt AFTER next frame is queued in HW */ + for (i = 0; i < sde_enc->num_phys_encs; i++) { + struct sde_encoder_phys *phys = sde_enc->phys_encs[i]; + + if (!phys || phys->enable_state == SDE_ENC_DISABLED) + continue; + + if (!phys->ops.needs_single_flush || + !phys->ops.needs_single_flush(phys)) { + pending_kickoff_cnt = + sde_encoder_phys_inc_pending(phys); + SDE_EVT32(pending_kickoff_cnt, SDE_EVTLOG_FUNC_CASE1); + } else { + pending_kickoff_cnt = + sde_encoder_phys_inc_pending(phys); + SDE_EVT32(pending_kickoff_cnt, + pending_flush.pending_flush_mask, + SDE_EVTLOG_FUNC_CASE2); + } + } } static void _sde_encoder_ppsplit_swap_intf_for_right_only_update( -- GitLab From 9219c292e8c9314c79dd38a2ccc8c403a8197019 Mon Sep 17 00:00:00 2001 From: Sujeev Dias Date: Fri, 20 Apr 2018 17:59:18 -0700 Subject: [PATCH 1436/1635] mhi: core: add support for bi-direction or directionless channels MHI channels are not always unidirectional. Some offload channels are either bi-directional or has no direction associate with it, add support for such channels. CRs-Fixed: 2229699 Change-Id: I6cb3b879eb3d90e9bbf8704805a16f1b43306e0d Signed-off-by: Sujeev Dias --- Documentation/devicetree/bindings/bus/mhi.txt | 2 ++ drivers/bus/mhi/core/mhi_init.c | 19 ++++++++++++++++++- drivers/bus/mhi/core/mhi_main.c | 10 ++++++++-- 3 files changed, 28 insertions(+), 3 deletions(-) diff --git a/Documentation/devicetree/bindings/bus/mhi.txt b/Documentation/devicetree/bindings/bus/mhi.txt index 172ae7b79de4..a05f756d2a5b 100644 --- a/Documentation/devicetree/bindings/bus/mhi.txt +++ b/Documentation/devicetree/bindings/bus/mhi.txt @@ -22,8 +22,10 @@ Main node properties: 2nd element: Transfer ring length in elements 3rd element: Event ring associated with this channel 4th element: Channel direction as defined by enum dma_data_direction + 0 = Bidirectional data transfer 1 = UL data transfer 2 = DL data transfer + 3 = No direction, not a regular data transfer channel 5th element: Channel doorbell mode configuration as defined by enum MHI_BRSTMODE 2 = burst mode disabled diff --git a/drivers/bus/mhi/core/mhi_init.c b/drivers/bus/mhi/core/mhi_init.c index 8f103ed81cd1..8f58f4705afd 100644 --- a/drivers/bus/mhi/core/mhi_init.c +++ b/drivers/bus/mhi/core/mhi_init.c @@ -616,7 +616,19 @@ int mhi_device_configure(struct mhi_device *mhi_dev, struct mhi_chan_ctxt *ch_ctxt; int er_index, chan; - mhi_chan = (dir == DMA_TO_DEVICE) ? mhi_dev->ul_chan : mhi_dev->dl_chan; + switch (dir) { + case DMA_TO_DEVICE: + mhi_chan = mhi_dev->ul_chan; + break; + case DMA_BIDIRECTIONAL: + case DMA_FROM_DEVICE: + case DMA_NONE: + mhi_chan = mhi_dev->dl_chan; + break; + default: + return -EINVAL; + } + er_index = mhi_chan->er_index; chan = mhi_chan->chan; @@ -830,6 +842,11 @@ static int of_parse_ch_cfg(struct mhi_controller *mhi_cntrl, mhi_chan->xfer_type != MHI_XFER_BUFFER)) goto error_chan_cfg; + /* bi-dir and dirctionless channels must be a offload chan */ + if ((mhi_chan->dir == DMA_BIDIRECTIONAL || + mhi_chan->dir == DMA_NONE) && !mhi_chan->offload_ch) + goto error_chan_cfg; + /* if mhi host allocate the buffers then client cannot queue */ if (mhi_chan->pre_alloc) mhi_chan->queue_xfer = mhi_queue_nop; diff --git a/drivers/bus/mhi/core/mhi_main.c b/drivers/bus/mhi/core/mhi_main.c index 1c03b07fdec4..a678ce24a00f 100644 --- a/drivers/bus/mhi/core/mhi_main.c +++ b/drivers/bus/mhi/core/mhi_main.c @@ -525,12 +525,18 @@ void mhi_create_devices(struct mhi_controller *mhi_cntrl) if (!mhi_dev) return; - if (mhi_chan->dir == DMA_TO_DEVICE) { + switch (mhi_chan->dir) { + case DMA_TO_DEVICE: mhi_dev->ul_chan = mhi_chan; mhi_dev->ul_chan_id = mhi_chan->chan; mhi_dev->ul_xfer = mhi_chan->queue_xfer; mhi_dev->ul_event_id = mhi_chan->er_index; - } else { + break; + case DMA_NONE: + case DMA_BIDIRECTIONAL: + mhi_dev->ul_chan_id = mhi_chan->chan; + case DMA_FROM_DEVICE: + /* we use dl_chan for offload channels */ mhi_dev->dl_chan = mhi_chan; mhi_dev->dl_chan_id = mhi_chan->chan; mhi_dev->dl_xfer = mhi_chan->queue_xfer; -- GitLab From 2ee8b1e231b00850f3a49b5ae5dcc943e4abf9ec Mon Sep 17 00:00:00 2001 From: Deepak Katragadda Date: Mon, 7 May 2018 14:29:43 -0700 Subject: [PATCH 1437/1635] clk: qcom: gpucc-sm8150: Remove control of the GPU ACD clocks The gpu_cc_acd_ahb_clk and gpu_cc_acd_cxo_clk clocks are to managed by the graphics firmware directly on SM8150 and SDMSHRIKE. Remove all control of these clocks from Linux. Change-Id: I16614255cb9c277ea0b732630a9f8c3f8891751a Signed-off-by: Deepak Katragadda --- drivers/clk/qcom/gpucc-sm8150.c | 29 ----------- include/dt-bindings/clock/qcom,gpucc-sm8150.h | 49 +++++++++---------- 2 files changed, 23 insertions(+), 55 deletions(-) diff --git a/drivers/clk/qcom/gpucc-sm8150.c b/drivers/clk/qcom/gpucc-sm8150.c index 6e236cc41ced..a11b2b5856b7 100644 --- a/drivers/clk/qcom/gpucc-sm8150.c +++ b/drivers/clk/qcom/gpucc-sm8150.c @@ -143,32 +143,6 @@ static struct clk_rcg2 gpu_cc_gmu_clk_src = { }, }; -static struct clk_branch gpu_cc_acd_ahb_clk = { - .halt_reg = 0x1168, - .halt_check = BRANCH_HALT, - .clkr = { - .enable_reg = 0x1168, - .enable_mask = BIT(0), - .hw.init = &(struct clk_init_data){ - .name = "gpu_cc_acd_ahb_clk", - .ops = &clk_branch2_ops, - }, - }, -}; - -static struct clk_branch gpu_cc_acd_cxo_clk = { - .halt_reg = 0x1164, - .halt_check = BRANCH_HALT, - .clkr = { - .enable_reg = 0x1164, - .enable_mask = BIT(0), - .hw.init = &(struct clk_init_data){ - .name = "gpu_cc_acd_cxo_clk", - .ops = &clk_branch2_ops, - }, - }, -}; - static struct clk_branch gpu_cc_ahb_clk = { .halt_reg = 0x1078, .halt_check = BRANCH_HALT, @@ -411,8 +385,6 @@ struct clk_hw *gpu_cc_sm8150_hws[] = { }; static struct clk_regmap *gpu_cc_sm8150_clocks[] = { - [GPU_CC_ACD_AHB_CLK] = &gpu_cc_acd_ahb_clk.clkr, - [GPU_CC_ACD_CXO_CLK] = &gpu_cc_acd_cxo_clk.clkr, [GPU_CC_AHB_CLK] = &gpu_cc_ahb_clk.clkr, [GPU_CC_CRC_AHB_CLK] = &gpu_cc_crc_ahb_clk.clkr, [GPU_CC_CX_APB_CLK] = &gpu_cc_cx_apb_clk.clkr, @@ -433,7 +405,6 @@ static struct clk_regmap *gpu_cc_sm8150_clocks[] = { }; static const struct qcom_reset_map gpu_cc_sm8150_resets[] = { - [GPUCC_GPU_CC_ACD_BCR] = { 0x1160 }, [GPUCC_GPU_CC_CX_BCR] = { 0x1068 }, [GPUCC_GPU_CC_GMU_BCR] = { 0x111c }, [GPUCC_GPU_CC_GX_BCR] = { 0x1008 }, diff --git a/include/dt-bindings/clock/qcom,gpucc-sm8150.h b/include/dt-bindings/clock/qcom,gpucc-sm8150.h index 213f024283e8..6092b356d212 100644 --- a/include/dt-bindings/clock/qcom,gpucc-sm8150.h +++ b/include/dt-bindings/clock/qcom,gpucc-sm8150.h @@ -15,34 +15,31 @@ #define _DT_BINDINGS_CLK_QCOM_GPU_CC_SM8150_H /* GPUCC clock registers */ -#define GPU_CC_ACD_AHB_CLK 0 -#define GPU_CC_ACD_CXO_CLK 1 -#define GPU_CC_AHB_CLK 2 -#define GPU_CC_CRC_AHB_CLK 3 -#define GPU_CC_CX_APB_CLK 4 -#define GPU_CC_CX_GMU_CLK 5 -#define GPU_CC_CX_QDSS_AT_CLK 6 -#define GPU_CC_CX_QDSS_TRIG_CLK 7 -#define GPU_CC_CX_QDSS_TSCTR_CLK 8 -#define GPU_CC_CX_SNOC_DVM_CLK 9 -#define GPU_CC_CXO_AON_CLK 10 -#define GPU_CC_CXO_CLK 11 -#define GPU_CC_GMU_CLK_SRC 12 -#define GPU_CC_GX_GMU_CLK 13 -#define GPU_CC_GX_QDSS_TSCTR_CLK 14 -#define GPU_CC_GX_VSENSE_CLK 15 -#define GPU_CC_PLL1 16 -#define GPU_CC_PLL_TEST_CLK 17 -#define GPU_CC_SLEEP_CLK 18 +#define GPU_CC_AHB_CLK 0 +#define GPU_CC_CRC_AHB_CLK 1 +#define GPU_CC_CX_APB_CLK 2 +#define GPU_CC_CX_GMU_CLK 3 +#define GPU_CC_CX_QDSS_AT_CLK 4 +#define GPU_CC_CX_QDSS_TRIG_CLK 5 +#define GPU_CC_CX_QDSS_TSCTR_CLK 6 +#define GPU_CC_CX_SNOC_DVM_CLK 7 +#define GPU_CC_CXO_AON_CLK 8 +#define GPU_CC_CXO_CLK 9 +#define GPU_CC_GMU_CLK_SRC 10 +#define GPU_CC_GX_GMU_CLK 11 +#define GPU_CC_GX_QDSS_TSCTR_CLK 12 +#define GPU_CC_GX_VSENSE_CLK 13 +#define GPU_CC_PLL1 14 +#define GPU_CC_PLL_TEST_CLK 15 +#define GPU_CC_SLEEP_CLK 16 /* GPUCC reset clock registers */ -#define GPUCC_GPU_CC_ACD_BCR 0 -#define GPUCC_GPU_CC_CX_BCR 1 -#define GPUCC_GPU_CC_GFX3D_AON_BCR 2 -#define GPUCC_GPU_CC_GMU_BCR 3 -#define GPUCC_GPU_CC_GX_BCR 4 -#define GPUCC_GPU_CC_SPDM_BCR 5 -#define GPUCC_GPU_CC_XO_BCR 6 +#define GPUCC_GPU_CC_CX_BCR 0 +#define GPUCC_GPU_CC_GFX3D_AON_BCR 1 +#define GPUCC_GPU_CC_GMU_BCR 2 +#define GPUCC_GPU_CC_GX_BCR 3 +#define GPUCC_GPU_CC_SPDM_BCR 4 +#define GPUCC_GPU_CC_XO_BCR 5 /* Dummy clocks for rate measurement */ #define MEASURE_ONLY_GPU_CC_CX_GFX3D_CLK 0 -- GitLab From 626b43f897aa9dac015b07a5b3063776c8a4a142 Mon Sep 17 00:00:00 2001 From: Laura Abbott Date: Wed, 2 May 2018 15:06:36 -0700 Subject: [PATCH 1438/1635] arm64: Stop printing the virtual memory layout Printing kernel addresses should be done in limited circumstances, mostly for debugging purposes. Printing out the virtual memory layout at every kernel bootup doesn't really fall into this category so delete the prints. There are other ways to get the same information. Change-Id: I39688092f969771c7f78ee88fed595d47122a93e Acked-by: Kees Cook Signed-off-by: Laura Abbott Signed-off-by: Catalin Marinas Git-Repo: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/ Git-Commit: 071929dbdd865f779a89ba3f1e06ba8d17dd3743 [ckadabi] Added config option Signed-off-by: Channagoud Kadabi --- arch/arm64/mm/init.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/arm64/mm/init.c b/arch/arm64/mm/init.c index 885402869696..2734f7d213f4 100644 --- a/arch/arm64/mm/init.c +++ b/arch/arm64/mm/init.c @@ -602,6 +602,7 @@ void __init mem_init(void) mem_init_print_info(NULL); +#ifdef CONFIG_PRINT_VMEMLAYOUT #define MLK(b, t) b, t, ((t) - (b)) >> 10 #define MLM(b, t) b, t, ((t) - (b)) >> 20 #define MLG(b, t) b, t, ((t) - (b)) >> 30 @@ -644,7 +645,7 @@ void __init mem_init(void) #undef MLK #undef MLM #undef MLK_ROUNDUP - +#endif /* * Check boundaries twice: Some fundamental inconsistencies can be * detected at build time already. -- GitLab From 96a19ec5722f6e999e3f8ea5e73954e4945419a0 Mon Sep 17 00:00:00 2001 From: Channagoud Kadabi Date: Mon, 7 May 2018 15:22:11 -0700 Subject: [PATCH 1439/1635] arm64: Kconfig: Add Kconfig option for vmem layout Kconfig option to control printing virtual memory layout of kernel. Change-Id: I0fd83dc47d985432c5a786db456b2c6c1676563b Signed-off-by: Channagoud Kadabi --- arch/arm64/Kconfig | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index 2bf1059ed070..05b24751131e 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -879,6 +879,15 @@ config HARDEN_BRANCH_PREDICTOR If unsure, say Y. +config PRINT_VMEMLAYOUT + bool "Enable debug option to print kernel virtual memory layout" + help + Enable support for printing kernel virtual memory layout for debugging + purpose. If disabled kernel would not show any information about + virtual memory layout during boot up. + + If unsure, say N. + menuconfig ARMV8_DEPRECATED bool "Emulate deprecated/obsolete ARMv8 instructions" depends on COMPAT -- GitLab From 41e9022ba4f0160fd6ebd9498c7507871c8a5747 Mon Sep 17 00:00:00 2001 From: Channagoud Kadabi Date: Wed, 2 May 2018 15:28:40 -0700 Subject: [PATCH 1440/1635] defconfig: sm8150: Enable vmem layout prints Config option to print kernel virtual memory layout by default on debug builds. Change-Id: I07076085d7906c8ac7da61f1eb3a0efab27c6fec Signed-off-by: Channagoud Kadabi --- arch/arm64/configs/sm8150_defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/configs/sm8150_defconfig b/arch/arm64/configs/sm8150_defconfig index 29444b3801bb..81aca1ba02fb 100644 --- a/arch/arm64/configs/sm8150_defconfig +++ b/arch/arm64/configs/sm8150_defconfig @@ -68,6 +68,7 @@ CONFIG_ZSMALLOC=y CONFIG_SECCOMP=y # CONFIG_UNMAP_KERNEL_AT_EL0 is not set # CONFIG_HARDEN_BRANCH_PREDICTOR is not set +CONFIG_PRINT_VMEMLAYOUT=y CONFIG_ARMV8_DEPRECATED=y CONFIG_SWP_EMULATION=y CONFIG_CP15_BARRIER_EMULATION=y -- GitLab From 659f996b88d64a1938da3115a129f74a3d62cdf3 Mon Sep 17 00:00:00 2001 From: Aravind Venkateswaran Date: Thu, 3 May 2018 16:06:09 -0700 Subject: [PATCH 1441/1635] clk/qcom/mdss: update power-up sequence for DSI 7nm PLL Add the required programming to assert the reset for the PHY digital domain as part of the PLL power up sequence. This is required to support scenarios where the PHY digital and analog supply rails may get collapsed in idle screen. Change-Id: I20c3f0576253674d8bc2ce01cbb23c221924a13f Signed-off-by: Aravind Venkateswaran --- drivers/clk/qcom/mdss/mdss-dsi-pll-7nm.c | 28 ++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/drivers/clk/qcom/mdss/mdss-dsi-pll-7nm.c b/drivers/clk/qcom/mdss/mdss-dsi-pll-7nm.c index 2166f36eca77..5be31f562ed4 100644 --- a/drivers/clk/qcom/mdss/mdss-dsi-pll-7nm.c +++ b/drivers/clk/qcom/mdss/mdss-dsi-pll-7nm.c @@ -191,6 +191,7 @@ #define PHY_CMN_CTRL_0 0x024 #define PHY_CMN_CTRL_3 0x030 #define PHY_CMN_PLL_CNTRL 0x03C +#define PHY_CMN_GLBL_DIGTOP_SPARE4 0x128 /* Bit definition of SSC control registers */ #define SSC_CENTER BIT(0) @@ -880,10 +881,24 @@ static void dsi_pll_enable_global_clk(struct mdss_pll_resources *rsc) u32 data; MDSS_PLL_REG_W(rsc->phy_base, PHY_CMN_CTRL_3, 0x04); + data = MDSS_PLL_REG_R(rsc->phy_base, PHY_CMN_CLK_CFG1); MDSS_PLL_REG_W(rsc->phy_base, PHY_CMN_CLK_CFG1, (data | BIT(5))); } +static void dsi_pll_phy_dig_reset(struct mdss_pll_resources *rsc) +{ + /* + * Reset the PHY digital domain. This would be needed when + * coming out of a CX or analog rail power collapse while + * ensuring that the pads maintain LP00 or LP11 state + */ + MDSS_PLL_REG_W(rsc->phy_base, PHY_CMN_GLBL_DIGTOP_SPARE4, BIT(0)); + wmb(); /* Ensure that the reset is asserted */ + MDSS_PLL_REG_W(rsc->phy_base, PHY_CMN_GLBL_DIGTOP_SPARE4, 0x0); + wmb(); /* Ensure that the reset is deasserted */ +} + static int dsi_pll_enable(struct dsi_pll_vco_clk *vco) { int rc; @@ -917,13 +932,18 @@ static int dsi_pll_enable(struct dsi_pll_vco_clk *vco) rsc->pll_on = true; - dsi_pll_enable_global_clk(rsc); + /* + * assert power on reset for PHY digital in case the PLL is + * enabled after CX of analog domain power collapse. This needs + * to be done before enabling the global clk. + */ + dsi_pll_phy_dig_reset(rsc); if (rsc->slave) - dsi_pll_enable_global_clk(rsc->slave); + dsi_pll_phy_dig_reset(rsc->slave); - MDSS_PLL_REG_W(rsc->phy_base, PHY_CMN_RBUF_CTRL, 0x01); + dsi_pll_enable_global_clk(rsc); if (rsc->slave) - MDSS_PLL_REG_W(rsc->slave->phy_base, PHY_CMN_RBUF_CTRL, 0x01); + dsi_pll_enable_global_clk(rsc->slave); error: return rc; -- GitLab From 03279156b16b241398efa755fab96aa4b6292aff Mon Sep 17 00:00:00 2001 From: Kyle Piefer Date: Thu, 3 May 2018 15:50:43 -0700 Subject: [PATCH 1442/1635] msm: kgsl: Temporarily mask the watchdog upon receiving it Once the GMU watchdog interrupt is cleared and the handler returns, if the device has not been reset the interrupt will fire again. This can cause storms of GMU watchdog interrupts that flood the system when something goes wrong. Mask the GMU watchdog interrupt when we receive it, so that we do not receive it again before we finish recovering. It will be unmasked again the next time the GMU boots. Change-Id: Ieb9090f9ed274d581f706dced683f811c66bba70 Signed-off-by: Kyle Piefer --- drivers/gpu/msm/kgsl_gmu.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/msm/kgsl_gmu.c b/drivers/gpu/msm/kgsl_gmu.c index bd5f86f02435..1ff50871fb1e 100644 --- a/drivers/gpu/msm/kgsl_gmu.c +++ b/drivers/gpu/msm/kgsl_gmu.c @@ -984,7 +984,7 @@ static irqreturn_t gmu_irq_handler(int irq, void *data) struct kgsl_device *device = data; struct gmu_device *gmu = KGSL_GMU_DEVICE(device); struct adreno_device *adreno_dev = ADRENO_DEVICE(device); - unsigned int status = 0; + unsigned int mask, status = 0; adreno_read_gmureg(ADRENO_DEVICE(device), ADRENO_REG_GMU_AO_HOST_INTERRUPT_STATUS, &status); @@ -993,6 +993,13 @@ static irqreturn_t gmu_irq_handler(int irq, void *data) /* Ignore GMU_INT_RSCC_COMP and GMU_INT_DBD WAKEUP interrupts */ if (status & GMU_INT_WDOG_BITE) { + /* Temporarily mask the watchdog interrupt to prevent a storm */ + adreno_read_gmureg(adreno_dev, + ADRENO_REG_GMU_AO_HOST_INTERRUPT_MASK, &mask); + adreno_write_gmureg(adreno_dev, + ADRENO_REG_GMU_AO_HOST_INTERRUPT_MASK, + (mask | GMU_INT_WDOG_BITE)); + dev_err_ratelimited(&gmu->pdev->dev, "GMU watchdog expired interrupt received\n"); adreno_set_gpu_fault(adreno_dev, ADRENO_GMU_FAULT); -- GitLab From 1b6a19806970465ff1562034a03bc8eedbbc55da Mon Sep 17 00:00:00 2001 From: Maheshwar Ajja Date: Mon, 7 May 2018 13:03:17 -0700 Subject: [PATCH 1443/1635] msm: vidc: Add video decoder batching Video decoder batching is implemented based on output buffer flow to save power. Change-Id: Ib1ee883c382c99e75c513becc9eb7c63f1989a07 Signed-off-by: Maheshwar Ajja --- drivers/media/platform/msm/vidc/msm_vdec.c | 6 +- drivers/media/platform/msm/vidc/msm_vidc.c | 160 +++++++++++--- .../media/platform/msm/vidc/msm_vidc_clocks.c | 40 +++- .../media/platform/msm/vidc/msm_vidc_clocks.h | 1 + .../media/platform/msm/vidc/msm_vidc_common.c | 195 ++++++++++++++---- .../media/platform/msm/vidc/msm_vidc_common.h | 49 ++++- .../platform/msm/vidc/msm_vidc_internal.h | 6 + .../platform/msm/vidc/msm_vidc_platform.c | 4 + .../platform/msm/vidc/msm_vidc_res_parse.c | 2 + .../platform/msm/vidc/msm_vidc_resources.h | 1 + 10 files changed, 385 insertions(+), 79 deletions(-) diff --git a/drivers/media/platform/msm/vidc/msm_vdec.c b/drivers/media/platform/msm/vidc/msm_vdec.c index 033fc60d1536..5044fbf7c2ce 100644 --- a/drivers/media/platform/msm/vidc/msm_vdec.c +++ b/drivers/media/platform/msm/vidc/msm_vdec.c @@ -717,12 +717,14 @@ int msm_vdec_enum_fmt(struct msm_vidc_inst *inst, struct v4l2_fmtdesc *f) int msm_vdec_inst_init(struct msm_vidc_inst *inst) { int rc = 0; + struct msm_vidc_core *core; struct msm_vidc_format *fmt = NULL; - if (!inst) { + if (!inst || !inst->core) { dprintk(VIDC_ERR, "Invalid input = %pK\n", inst); return -EINVAL; } + core = inst->core; inst->prop.height[CAPTURE_PORT] = DEFAULT_HEIGHT; inst->prop.width[CAPTURE_PORT] = DEFAULT_WIDTH; inst->prop.height[OUTPUT_PORT] = DEFAULT_HEIGHT; @@ -740,6 +742,8 @@ int msm_vdec_inst_init(struct msm_vidc_inst *inst) inst->bufq[CAPTURE_PORT].num_planes = 1; inst->prop.fps = DEFAULT_FPS; inst->clk_data.operating_rate = 0; + if (core->resources.decode_batching) + inst->batch.size = MAX_DEC_BATCH_SIZE; /* By default, initialize CAPTURE port to UBWC YUV format */ fmt = msm_comm_get_pixel_fmt_fourcc(vdec_formats, diff --git a/drivers/media/platform/msm/vidc/msm_vidc.c b/drivers/media/platform/msm/vidc/msm_vidc.c index 4374878a8e6f..2f3e557b8e2f 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc.c +++ b/drivers/media/platform/msm/vidc/msm_vidc.c @@ -231,16 +231,25 @@ EXPORT_SYMBOL(msm_vidc_query_ctrl); int msm_vidc_s_fmt(void *instance, struct v4l2_format *f) { + int rc = 0; struct msm_vidc_inst *inst = instance; if (!inst || !f) return -EINVAL; if (inst->session_type == MSM_VIDC_DECODER) - return msm_vdec_s_fmt(instance, f); + rc = msm_vdec_s_fmt(instance, f); if (inst->session_type == MSM_VIDC_ENCODER) - return msm_venc_s_fmt(instance, f); - return -EINVAL; + rc = msm_venc_s_fmt(instance, f); + + dprintk(VIDC_DBG, + "s_fmt: %x : type %d wxh %dx%d pixelfmt %#x num_planes %d size[0] %d size[1] %d in_reconfig %d\n", + hash32_ptr(inst->session), f->type, + f->fmt.pix_mp.width, f->fmt.pix_mp.height, + f->fmt.pix_mp.pixelformat, f->fmt.pix_mp.num_planes, + f->fmt.pix_mp.plane_fmt[0].sizeimage, + f->fmt.pix_mp.plane_fmt[1].sizeimage, inst->in_reconfig); + return rc; } EXPORT_SYMBOL(msm_vidc_s_fmt); @@ -297,6 +306,13 @@ int msm_vidc_g_fmt(void *instance, struct v4l2_format *f) f->fmt.pix_mp.plane_fmt[0].reserved[0] = VENUS_Y_SCANLINES(color_format, inst->prop.height[port]); + dprintk(VIDC_DBG, + "g_fmt: %x : type %d wxh %dx%d pixelfmt %#x num_planes %d size[0] %d size[1] %d in_reconfig %d\n", + hash32_ptr(inst->session), f->type, + f->fmt.pix_mp.width, f->fmt.pix_mp.height, + f->fmt.pix_mp.pixelformat, f->fmt.pix_mp.num_planes, + f->fmt.pix_mp.plane_fmt[0].sizeimage, + f->fmt.pix_mp.plane_fmt[1].sizeimage, inst->in_reconfig); exit: return rc; } @@ -837,6 +853,11 @@ static int msm_vidc_queue_setup(struct vb2_queue *q, rc = -EINVAL; break; } + + dprintk(VIDC_DBG, + "queue_setup: %x : type %d num_buffers %d num_planes %d sizes[0] %d sizes[1] %d\n", + hash32_ptr(inst->session), q->type, *num_buffers, + *num_planes, sizes[0], sizes[1]); return rc; } @@ -983,6 +1004,15 @@ static inline int start_streaming(struct msm_vidc_inst *inst) } } + if (is_batching_allowed(inst)) { + dprintk(VIDC_DBG, + "%s: batching enabled for inst %pK (%#x)\n", + __func__, inst, hash32_ptr(inst->session)); + inst->batch.enable = true; + /* this will disable dcvs as batching enabled */ + msm_dcvs_try_enable(inst); + } + /* * For seq_changed_insufficient, driver should set session_continue * to firmware after the following sequence @@ -1164,42 +1194,111 @@ static void msm_vidc_stop_streaming(struct vb2_queue *q) inst, q->type); } -static void msm_vidc_buf_queue(struct vb2_buffer *vb2) +static int msm_vidc_queue_buf(struct msm_vidc_inst *inst, + struct vb2_buffer *vb2) { int rc = 0; - struct msm_vidc_inst *inst = NULL; - struct msm_vidc_buffer *mbuf = NULL; + struct msm_vidc_buffer *mbuf; - inst = vb2_get_drv_priv(vb2->vb2_queue); - if (!inst) { - dprintk(VIDC_ERR, "%s: invalid inst\n", __func__); - return; + if (!inst || !vb2) { + dprintk(VIDC_ERR, "%s: invalid params\n", __func__); + return -EINVAL; } mbuf = msm_comm_get_vidc_buffer(inst, vb2); if (IS_ERR_OR_NULL(mbuf)) { + /* + * if the buffer has RBR_PENDING flag (-EEXIST) then don't queue + * it now, it will be queued via msm_comm_qbuf_rbr() as part of + * RBR event processing. + */ if (PTR_ERR(mbuf) == -EEXIST) - return; - print_vb2_buffer(VIDC_ERR, "failed to get vidc-buf", - inst, vb2); - rc = -EINVAL; - goto error; + return 0; + dprintk(VIDC_ERR, "%s: failed to get vidc-buf\n", __func__); + return -EINVAL; } if (!kref_get_mbuf(inst, mbuf)) { dprintk(VIDC_ERR, "%s: mbuf not found\n", __func__); - rc = -EINVAL; - goto error; + return -EINVAL; } - rc = msm_comm_qbuf(inst, mbuf); if (rc) - print_vidc_buffer(VIDC_ERR, "failed qbuf", inst, mbuf); - + dprintk(VIDC_ERR, "%s: failed qbuf\n", __func__); kref_put_mbuf(mbuf); -error: + return rc; +} + +static int msm_vidc_queue_buf_decode_batch(struct msm_vidc_inst *inst, + struct vb2_buffer *vb2) +{ + int rc; + struct msm_vidc_buffer *mbuf; + + if (!inst || !vb2) { + dprintk(VIDC_ERR, "%s: invalid params\n", __func__); + return -EINVAL; + } + + mbuf = msm_comm_get_vidc_buffer(inst, vb2); + if (IS_ERR_OR_NULL(mbuf)) { + dprintk(VIDC_ERR, "%s: failed to get vidc-buf\n", __func__); + return -EINVAL; + } + if (!kref_get_mbuf(inst, mbuf)) { + dprintk(VIDC_ERR, "%s: mbuf not found\n", __func__); + return -EINVAL; + } + /* + * If this buffer has RBR_EPNDING then it will not be queued + * but it may trigger full batch queuing in below function. + */ + rc = msm_comm_qbuf_decode_batch(inst, mbuf); if (rc) + dprintk(VIDC_ERR, "%s: failed qbuf\n", __func__); + kref_put_mbuf(mbuf); + + return rc; +} + +static int msm_vidc_queue_buf_batch(struct msm_vidc_inst *inst, + struct vb2_buffer *vb2) +{ + int rc; + + if (!inst || !vb2) { + dprintk(VIDC_ERR, "%s: invalid params\n", __func__); + return -EINVAL; + } + + if (inst->session_type == MSM_VIDC_DECODER && + vb2->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) + rc = msm_vidc_queue_buf_decode_batch(inst, vb2); + else + rc = msm_vidc_queue_buf(inst, vb2); + + return rc; +} + +static void msm_vidc_buf_queue(struct vb2_buffer *vb2) +{ + int rc = 0; + struct msm_vidc_inst *inst = NULL; + + inst = vb2_get_drv_priv(vb2->vb2_queue); + if (!inst) { + dprintk(VIDC_ERR, "%s: invalid inst\n", __func__); + return; + } + + if (inst->batch.enable) + rc = msm_vidc_queue_buf_batch(inst, vb2); + else + rc = msm_vidc_queue_buf(inst, vb2); + if (rc) { + print_vb2_buffer(VIDC_ERR, "failed vb2-qbuf", inst, vb2); msm_comm_generate_session_error(inst); + } } static const struct vb2_ops msm_vidc_vb2q_ops = { @@ -1402,7 +1501,8 @@ static int msm_vidc_get_count(struct msm_vidc_inst *inst, ctrl->val = bufreq->buffer_count_min_host; return 0; } - if (ctrl->val > bufreq->buffer_count_min_host) { + if (ctrl->val > bufreq->buffer_count_min_host && + ctrl->val <= MAX_NUM_OUTPUT_BUFFERS) { dprintk(VIDC_DBG, "Buffer count Host changed from %d to %d\n", bufreq->buffer_count_min_host, @@ -1421,6 +1521,12 @@ static int msm_vidc_get_count(struct msm_vidc_inst *inst, msm_vidc_update_host_buff_counts(inst); ctrl->val = bufreq->buffer_count_min_host; + dprintk(VIDC_DBG, + "g_count: %x : OUTPUT: min %d min_host %d actual %d\n", + hash32_ptr(inst->session), + bufreq->buffer_count_min, + bufreq->buffer_count_min_host, + bufreq->buffer_count_actual); return rc; } else if (ctrl->id == V4L2_CID_MIN_BUFFERS_FOR_CAPTURE) { @@ -1452,7 +1558,8 @@ static int msm_vidc_get_count(struct msm_vidc_inst *inst, bufreq->buffer_count_min_host = ctrl->val; } - if (ctrl->val > bufreq->buffer_count_min_host) { + if (ctrl->val > bufreq->buffer_count_min_host && + ctrl->val <= MAX_NUM_CAPTURE_BUFFERS) { dprintk(VIDC_DBG, "Buffer count Host changed from %d to %d\n", bufreq->buffer_count_min_host, @@ -1471,7 +1578,12 @@ static int msm_vidc_get_count(struct msm_vidc_inst *inst, msm_vidc_update_host_buff_counts(inst); ctrl->val = bufreq->buffer_count_min_host; - + dprintk(VIDC_DBG, + "g_count: %x : CAPTURE: min %d min_host %d actual %d\n", + hash32_ptr(inst->session), + bufreq->buffer_count_min, + bufreq->buffer_count_min_host, + bufreq->buffer_count_actual); return rc; } return -EINVAL; diff --git a/drivers/media/platform/msm/vidc/msm_vidc_clocks.c b/drivers/media/platform/msm/vidc/msm_vidc_clocks.c index fc9dc1ffc7f9..4b30929ea670 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc_clocks.c +++ b/drivers/media/platform/msm/vidc/msm_vidc_clocks.c @@ -65,7 +65,7 @@ static inline unsigned long int get_ubwc_compression_ratio( return compression_ratio; } -static inline int msm_vidc_get_mbs_per_frame(struct msm_vidc_inst *inst) +int msm_vidc_get_mbs_per_frame(struct msm_vidc_inst *inst) { int height, width; @@ -370,8 +370,9 @@ static int msm_dcvs_scale_clocks(struct msm_vidc_inst *inst) return -EINVAL; } - if (!inst->clk_data.dcvs_mode) { - dprintk(VIDC_DBG, "DCVS is not enabled\n"); + if (!inst->clk_data.dcvs_mode || inst->batch.enable) { + dprintk(VIDC_DBG, "Skip DCVS (dcvs %d, batching %d)\n", + inst->clk_data.dcvs_mode, inst->batch.enable); return 0; } @@ -871,16 +872,16 @@ int msm_dcvs_try_enable(struct msm_vidc_inst *inst) if (msm_vidc_clock_voting || inst->flags & VIDC_THUMBNAIL || - inst->clk_data.low_latency_mode) { - dprintk(VIDC_PROF, - "This session doesn't need DCVS : %pK\n", - inst); + inst->clk_data.low_latency_mode || + inst->batch.enable) { + dprintk(VIDC_PROF, "DCVS disabled: %pK\n", inst); inst->clk_data.extra_capture_buffer_count = 0; inst->clk_data.extra_output_buffer_count = 0; inst->clk_data.dcvs_mode = false; return false; } inst->clk_data.dcvs_mode = true; + dprintk(VIDC_PROF, "DCVS enabled: %pK\n", inst); inst->clk_data.extra_capture_buffer_count = DCVS_DEC_EXTRA_OUTPUT_BUFFERS; @@ -996,14 +997,35 @@ void msm_clock_data_reset(struct msm_vidc_inst *inst) int msm_vidc_get_extra_buff_count(struct msm_vidc_inst *inst, enum hal_buffer buffer_type) { - if (!inst) { + int count = 0; + + if (!inst || !inst->core) { dprintk(VIDC_ERR, "%s Invalid args\n", __func__); return 0; } + /* + * no extra buffers for thumbnail session because + * neither dcvs nor batching will be enabled + */ + if (is_thumbnail_session(inst)) + return 0; - return buffer_type == HAL_BUFFER_INPUT ? + count = buffer_type == HAL_BUFFER_INPUT ? inst->clk_data.extra_output_buffer_count : inst->clk_data.extra_capture_buffer_count; + + /* + * if platform supports decode batching ensure minimum + * batch size count of extra buffers added on output port + */ + if (buffer_type == HAL_BUFFER_OUTPUT) { + if (inst->core->resources.decode_batching && + is_decode_session(inst) && + count < inst->batch.size) + count = inst->batch.size; + } + + return count; } int msm_vidc_decide_work_route(struct msm_vidc_inst *inst) diff --git a/drivers/media/platform/msm/vidc/msm_vidc_clocks.h b/drivers/media/platform/msm/vidc/msm_vidc_clocks.h index aef9021154b4..8020bc1c0065 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc_clocks.h +++ b/drivers/media/platform/msm/vidc/msm_vidc_clocks.h @@ -29,6 +29,7 @@ int msm_vidc_get_extra_buff_count(struct msm_vidc_inst *inst, int msm_vidc_set_clocks(struct msm_vidc_core *core); int msm_comm_vote_bus(struct msm_vidc_core *core); int msm_dcvs_try_enable(struct msm_vidc_inst *inst); +int msm_vidc_get_mbs_per_frame(struct msm_vidc_inst *inst); int msm_comm_scale_clocks_and_bus(struct msm_vidc_inst *inst); int msm_comm_init_clocks_and_bus_data(struct msm_vidc_inst *inst); void msm_comm_free_freq_table(struct msm_vidc_inst *inst); diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c index 5ace08c854fe..a9bf66952f61 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc_common.c +++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c @@ -74,36 +74,6 @@ const char *const mpeg_video_vidc_extradata[] = { static void handle_session_error(enum hal_command_response cmd, void *data); static void msm_vidc_print_running_insts(struct msm_vidc_core *core); -bool msm_comm_turbo_session(struct msm_vidc_inst *inst) -{ - return !!(inst->flags & VIDC_TURBO); -} - -static inline bool is_thumbnail_session(struct msm_vidc_inst *inst) -{ - return !!(inst->flags & VIDC_THUMBNAIL); -} - -static inline bool is_low_power_session(struct msm_vidc_inst *inst) -{ - return !!(inst->flags & VIDC_LOW_POWER); -} - -static inline bool is_realtime_session(struct msm_vidc_inst *inst) -{ - return !!(inst->flags & VIDC_REALTIME); -} - -int msm_comm_g_ctrl(struct msm_vidc_inst *inst, struct v4l2_control *ctrl) -{ - return v4l2_g_ctrl(&inst->ctrl_handler, ctrl); -} - -int msm_comm_s_ctrl(struct msm_vidc_inst *inst, struct v4l2_control *ctrl) -{ - return v4l2_s_ctrl(NULL, &inst->ctrl_handler, ctrl); -} - int msm_comm_g_ctrl_for_id(struct msm_vidc_inst *inst, int id) { int rc = 0; @@ -795,7 +765,7 @@ int msm_comm_get_inst_load(struct msm_vidc_inst *inst, load = 0; } - if (msm_comm_turbo_session(inst)) { + if (is_turbo_session(inst)) { if (!(quirks & LOAD_CALC_IGNORE_TURBO_LOAD)) load = inst->core->resources.max_load; } @@ -2773,6 +2743,35 @@ static bool is_thermal_permissible(struct msm_vidc_core *core) return true; } +bool is_batching_allowed(struct msm_vidc_inst *inst) +{ + bool allowed = false; + + if (!inst || !inst->core) + return false; + + /* + * Enable decode batching based on below conditions + * - decode session + * - platform supports batching + * - session resolution <= 1080p + * - low latency not enabled + * - not a thumbnail session + * - realtime session + * - UBWC color format + */ + if (is_decode_session(inst) && inst->core->resources.decode_batching && + (msm_vidc_get_mbs_per_frame(inst) <= + MAX_DEC_BATCH_WIDTH * MAX_DEC_BATCH_HEIGHT) && + !inst->clk_data.low_latency_mode && + !is_thumbnail_session(inst) && is_realtime_session(inst) && + (inst->fmts[CAPTURE_PORT].fourcc == V4L2_PIX_FMT_NV12_UBWC || + inst->fmts[CAPTURE_PORT].fourcc == V4L2_PIX_FMT_NV12_TP10_UBWC)) + allowed = true; + + return allowed; +} + static int msm_comm_session_abort(struct msm_vidc_inst *inst) { int rc = 0, abort_completion = 0; @@ -3107,7 +3106,7 @@ static void msm_vidc_print_running_insts(struct msm_vidc_core *core) if (is_thumbnail_session(temp)) strlcat(properties, "N", sizeof(properties)); - if (msm_comm_turbo_session(temp)) + if (is_turbo_session(temp)) strlcat(properties, "T", sizeof(properties)); dprintk(VIDC_ERR, "%4d|%4d|%4d|%4d|%4s\n", @@ -3977,6 +3976,30 @@ enum hal_buffer get_hal_buffer_type(unsigned int type, } } +static int num_pending_qbufs(struct msm_vidc_inst *inst, u32 type) +{ + int count = 0; + struct msm_vidc_buffer *mbuf; + + if (!inst) { + dprintk(VIDC_ERR, "%s: invalid params\n", __func__); + return 0; + } + + mutex_lock(&inst->registeredbufs.lock); + list_for_each_entry(mbuf, &inst->registeredbufs.list, list) { + if (mbuf->vvb.vb2_buf.type != type) + continue; + /* Count only deferred buffers */ + if (!(mbuf->flags & MSM_VIDC_FLAG_DEFERRED)) + continue; + count++; + } + mutex_unlock(&inst->registeredbufs.lock); + + return count; +} + static int msm_comm_qbuf_to_hfi(struct msm_vidc_inst *inst, struct msm_vidc_buffer *mbuf) { @@ -4114,10 +4137,87 @@ int msm_comm_qbufs(struct msm_vidc_inst *inst) return rc; } +/* + * msm_comm_qbuf_decode_batch - count the buffers which are not queued to + * firmware yet (count includes rbr pending buffers too) and + * queue the buffers at once if full batch count reached. + * Don't queue rbr pending buffers as they would be queued + * when rbr event arrived from firmware. + */ +int msm_comm_qbuf_decode_batch(struct msm_vidc_inst *inst, + struct msm_vidc_buffer *mbuf) +{ + int rc = 0; + u32 count = 0; + struct msm_vidc_buffer *buf; + + if (!inst || !mbuf) { + dprintk(VIDC_ERR, "%s: Invalid arguments\n", __func__); + return -EINVAL; + } + + if (inst->state == MSM_VIDC_CORE_INVALID) { + dprintk(VIDC_ERR, "%s: inst is in bad state\n", __func__); + return -EINVAL; + } + + if (inst->state != MSM_VIDC_START_DONE) { + mbuf->flags |= MSM_VIDC_FLAG_DEFERRED; + print_vidc_buffer(VIDC_DBG, "qbuf deferred", inst, mbuf); + return 0; + } + + /* + * Don't batch for initial few buffers to avoid startup latency increase + * due to batching + */ + if (inst->count.fbd < 30) + return msm_comm_qbuf(inst, mbuf); + + count = num_pending_qbufs(inst, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); + if (count < inst->batch.size) { + mbuf->flags |= MSM_VIDC_FLAG_DEFERRED; + print_vidc_buffer(VIDC_DBG, "qbuf_batch deferred", inst, mbuf); + return 0; + } + + rc = msm_comm_scale_clocks_and_bus(inst); + if (rc) + dprintk(VIDC_ERR, "%s: scale clocks failed\n", __func__); + + mutex_lock(&inst->registeredbufs.lock); + list_for_each_entry(buf, &inst->registeredbufs.list, list) { + /* Don't queue if buffer is not CAPTURE_MPLANE */ + if (!(buf->vvb.vb2_buf.type & + V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)) + continue; + /* Don't queue if buffer is not a deferred buffer */ + if (!(buf->flags & MSM_VIDC_FLAG_DEFERRED)) + continue; + /* Don't queue if RBR event is pending on this buffer */ + if (buf->flags & MSM_VIDC_FLAG_RBR_PENDING) + continue; + print_vidc_buffer(VIDC_DBG, "qbuf", inst, buf); + rc = msm_comm_qbuf_to_hfi(inst, buf); + if (rc) { + dprintk(VIDC_ERR, "%s: Failed qbuf to hfi: %d\n", + __func__, rc); + break; + } + /* Queue pending buffers till the current buffer only */ + if (buf == mbuf) + break; + } + mutex_unlock(&inst->registeredbufs.lock); + + return rc; +} + int msm_vidc_update_host_buff_counts(struct msm_vidc_inst *inst) { int extra_buffers; struct hal_buffer_requirements *bufreq; + struct hal_buffer_requirements *bufreq_extra; bufreq = get_buff_req_buffer(inst, HAL_BUFFER_INPUT); @@ -4130,11 +4230,24 @@ int msm_vidc_update_host_buff_counts(struct msm_vidc_inst *inst) extra_buffers = msm_vidc_get_extra_buff_count(inst, HAL_BUFFER_INPUT); bufreq->buffer_count_min_host = bufreq->buffer_count_min + extra_buffers; - bufreq = get_buff_req_buffer(inst, HAL_BUFFER_EXTRADATA_INPUT); - if (bufreq) { - if (bufreq->buffer_count_min) - bufreq->buffer_count_min_host = - bufreq->buffer_count_min + extra_buffers; + + /* decode batching needs minimum batch size count of input buffers */ + if (is_decode_session(inst) && !is_thumbnail_session(inst) && + inst->core->resources.decode_batching && + bufreq->buffer_count_min_host < inst->batch.size) + bufreq->buffer_count_min_host = inst->batch.size; + + /* adjust min_host count for VP9 decoder */ + if (is_decode_session(inst) && !is_thumbnail_session(inst) && + inst->fmts[OUTPUT_PORT].fourcc == V4L2_PIX_FMT_VP9 && + bufreq->buffer_count_min_host < MIN_NUM_OUTPUT_BUFFERS_VP9) + bufreq->buffer_count_min_host = MIN_NUM_OUTPUT_BUFFERS_VP9; + + bufreq_extra = get_buff_req_buffer(inst, HAL_BUFFER_EXTRADATA_INPUT); + if (bufreq_extra) { + if (bufreq_extra->buffer_count_min) + bufreq_extra->buffer_count_min_host = + bufreq->buffer_count_min_host; } if (msm_comm_get_stream_output_mode(inst) == @@ -6065,15 +6178,9 @@ struct msm_vidc_buffer *msm_comm_get_vidc_buffer(struct msm_vidc_inst *inst, if (found_plane0) rc = -EEXIST; } - /* - * If RBR pending on this buffer then enable RBR_PENDING flag - * and clear the DEFERRED flag to avoid this buffer getting - * queued to video hardware in msm_comm_qbuf() which tries to - * queue all the DEFERRED buffers. - */ if (rc == -EEXIST) { + /* enable RBR pending */ mbuf->flags |= MSM_VIDC_FLAG_RBR_PENDING; - mbuf->flags &= ~MSM_VIDC_FLAG_DEFERRED; } } diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.h b/drivers/media/platform/msm/vidc/msm_vidc_common.h index 1261fe68c627..423cae632590 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc_common.h +++ b/drivers/media/platform/msm/vidc/msm_vidc_common.h @@ -15,6 +15,10 @@ #define _MSM_VIDC_COMMON_H_ #include "msm_vidc_internal.h" +#define MAX_DEC_BATCH_SIZE 6 +#define MAX_DEC_BATCH_WIDTH 1920 +#define MAX_DEC_BATCH_HEIGHT 1088 + struct vb2_buf_entry { struct list_head list; struct vb2_buffer *vb; @@ -34,6 +38,48 @@ enum load_calc_quirks { LOAD_CALC_IGNORE_NON_REALTIME_LOAD = 1 << 2, }; +static inline bool is_turbo_session(struct msm_vidc_inst *inst) +{ + return !!(inst->flags & VIDC_TURBO); +} + +static inline bool is_thumbnail_session(struct msm_vidc_inst *inst) +{ + return !!(inst->flags & VIDC_THUMBNAIL); +} + +static inline bool is_low_power_session(struct msm_vidc_inst *inst) +{ + return !!(inst->flags & VIDC_LOW_POWER); +} + +static inline bool is_realtime_session(struct msm_vidc_inst *inst) +{ + return !!(inst->flags & VIDC_REALTIME); +} + +static inline bool is_decode_session(struct msm_vidc_inst *inst) +{ + return inst->session_type == MSM_VIDC_DECODER; +} + +static inline bool is_encode_session(struct msm_vidc_inst *inst) +{ + return inst->session_type == MSM_VIDC_ENCODER; +} + +static inline int msm_comm_g_ctrl(struct msm_vidc_inst *inst, + struct v4l2_control *ctrl) +{ + return v4l2_g_ctrl(&inst->ctrl_handler, ctrl); +} + +static inline int msm_comm_s_ctrl(struct msm_vidc_inst *inst, + struct v4l2_control *ctrl) +{ + return v4l2_s_ctrl(NULL, &inst->ctrl_handler, ctrl); +} +bool is_batching_allowed(struct msm_vidc_inst *inst); enum hal_buffer get_hal_buffer_type(unsigned int type, unsigned int plane_num); void put_inst(struct msm_vidc_inst *inst); @@ -172,5 +218,6 @@ void msm_comm_store_mark_data(struct msm_vidc_list *data_list, void msm_comm_fetch_mark_data(struct msm_vidc_list *data_list, u32 index, u32 *mark_data, u32 *mark_target); int msm_comm_release_mark_data(struct msm_vidc_inst *inst); - +int msm_comm_qbuf_decode_batch(struct msm_vidc_inst *inst, + struct msm_vidc_buffer *mbuf); #endif diff --git a/drivers/media/platform/msm/vidc/msm_vidc_internal.h b/drivers/media/platform/msm/vidc/msm_vidc_internal.h index 8d4090e259c1..29b4d821e52d 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc_internal.h +++ b/drivers/media/platform/msm/vidc/msm_vidc_internal.h @@ -287,6 +287,11 @@ struct buf_count { int ebd; }; +struct batch_mode { + bool enable; + u32 size; +}; + struct clock_data { int buffer_counter; int load; @@ -417,6 +422,7 @@ struct msm_vidc_inst { u32 entropy_mode; struct msm_vidc_codec_data *codec_data; struct hal_hdr10_pq_sei hdr10_sei_params; + struct batch_mode batch; }; extern struct msm_vidc_drv *vidc_driver; diff --git a/drivers/media/platform/msm/vidc/msm_vidc_platform.c b/drivers/media/platform/msm/vidc/msm_vidc_platform.c index 3a0ff07d32b7..1301580a89a7 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc_platform.c +++ b/drivers/media/platform/msm/vidc/msm_vidc_platform.c @@ -167,6 +167,10 @@ static struct msm_vidc_common_data sm8150_common_data[] = { .key = "qcom,domain-cvp", .value = 1, }, + { + .key = "qcom,decode-batching", + .value = 1, + }, }; static struct msm_vidc_common_data sdm845_common_data[] = { diff --git a/drivers/media/platform/msm/vidc/msm_vidc_res_parse.c b/drivers/media/platform/msm/vidc/msm_vidc_res_parse.c index 4ebed83ee1c4..a1bf73744cb3 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc_res_parse.c +++ b/drivers/media/platform/msm/vidc/msm_vidc_res_parse.c @@ -790,6 +790,8 @@ int read_platform_resources_from_drv_data( "qcom,domain-attr-non-fatal-faults"); res->cache_pagetables = find_key_value(platform_data, "qcom,domain-attr-cache-pagetables"); + res->decode_batching = find_key_value(platform_data, + "qcom,decode-batching"); res->csc_coeff_data = &platform_data->csc_data; diff --git a/drivers/media/platform/msm/vidc/msm_vidc_resources.h b/drivers/media/platform/msm/vidc/msm_vidc_resources.h index b6bd509da1cc..a32a94ce2acd 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc_resources.h +++ b/drivers/media/platform/msm/vidc/msm_vidc_resources.h @@ -192,6 +192,7 @@ struct msm_vidc_platform_resources { bool domain_cvp; bool non_fatal_pagefaults; bool cache_pagetables; + bool decode_batching; struct msm_vidc_codec_data *codec_data; int codec_data_count; struct msm_vidc_csc_coeff *csc_coeff_data; -- GitLab From aa3aa443f4f2b2eaee83af39abd4a2915c71646d Mon Sep 17 00:00:00 2001 From: Jack Pham Date: Mon, 7 May 2018 16:23:08 -0700 Subject: [PATCH 1444/1635] usb: pd: release SS lane only if USB host is started Now that we check for the "USB Communications Capable" bit in either the Source Capabilities message (in sink mode) or Request (in source mode), USB host mode is sometimes not even started. In case DP driver requests to release SS lanes, there is no need to restart USB host in this case, so add a check for that, otherwise an error value will be returned which could be interpreted as a failure to release the SS lanes. Change-Id: I0e2f9df5f93677692e05713335fc7ba178d20b87 Signed-off-by: Jack Pham --- drivers/usb/pd/policy_engine.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/usb/pd/policy_engine.c b/drivers/usb/pd/policy_engine.c index a79712a1d571..0f5a7c6ade33 100644 --- a/drivers/usb/pd/policy_engine.c +++ b/drivers/usb/pd/policy_engine.c @@ -564,10 +564,13 @@ static int usbpd_release_ss_lane(struct usbpd *pd, goto err_exit; } - ret = extcon_blocking_sync(pd->extcon, EXTCON_USB_HOST, 0); - if (ret) { - usbpd_err(&pd->dev, "err(%d) for releasing ss lane", ret); - goto err_exit; + if (pd->peer_usb_comm) { + ret = extcon_blocking_sync(pd->extcon, EXTCON_USB_HOST, 0); + if (ret) { + usbpd_err(&pd->dev, "err(%d) for releasing ss lane", + ret); + goto err_exit; + } } pd->ss_lane_svid = hdlr->svid; -- GitLab From 945dddafe7a919e810848f033edf09a446002fa1 Mon Sep 17 00:00:00 2001 From: Sujeev Dias Date: Mon, 23 Apr 2018 15:58:07 -0700 Subject: [PATCH 1445/1635] mhi: core: fix incorrect mhi device probe failure mhi device drivers do not always required to assign a status_cb function pointer during driver registration. Fail probe only if selected device requires notifications from MHI host and status_cb is not assigned. CRs-Fixed: 2237541 Change-Id: Ie26737f0f281e172007f7b468d7b072d589341df Signed-off-by: Sujeev Dias --- drivers/bus/mhi/core/mhi_init.c | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/drivers/bus/mhi/core/mhi_init.c b/drivers/bus/mhi/core/mhi_init.c index 8f58f4705afd..9cfa88fe0dfb 100644 --- a/drivers/bus/mhi/core/mhi_init.c +++ b/drivers/bus/mhi/core/mhi_init.c @@ -1139,26 +1139,27 @@ static int mhi_driver_probe(struct device *dev) struct mhi_event *mhi_event; struct mhi_chan *ul_chan = mhi_dev->ul_chan; struct mhi_chan *dl_chan = mhi_dev->dl_chan; - bool offload_ch = ((ul_chan && ul_chan->offload_ch) || - (dl_chan && dl_chan->offload_ch)); - /* all offload channels require status_cb to be defined */ - if (offload_ch) { - if (!mhi_dev->status_cb) + + if (ul_chan) { + /* lpm notification require status_cb */ + if (ul_chan->lpm_notify && !mhi_drv->status_cb) return -EINVAL; - mhi_dev->status_cb = mhi_drv->status_cb; - } - if (ul_chan && !offload_ch) { - if (!mhi_drv->ul_xfer_cb) + if (!ul_chan->offload_ch && !mhi_drv->ul_xfer_cb) return -EINVAL; + ul_chan->xfer_cb = mhi_drv->ul_xfer_cb; + mhi_dev->status_cb = mhi_drv->status_cb; } - if (dl_chan && !offload_ch) { - if (!mhi_drv->dl_xfer_cb) + if (dl_chan) { + if (dl_chan->lpm_notify && !mhi_drv->status_cb) return -EINVAL; - dl_chan->xfer_cb = mhi_drv->dl_xfer_cb; + + if (!dl_chan->offload_ch && !mhi_drv->dl_xfer_cb) + return -EINVAL; + mhi_event = &mhi_cntrl->mhi_event[dl_chan->er_index]; /* @@ -1168,6 +1169,10 @@ static int mhi_driver_probe(struct device *dev) */ if (mhi_event->cl_manage && !mhi_drv->status_cb) return -EINVAL; + + dl_chan->xfer_cb = mhi_drv->dl_xfer_cb; + + /* ul & dl uses same status cb */ mhi_dev->status_cb = mhi_drv->status_cb; } -- GitLab From 709ebf7c6ee2757673c8b236921553001b0e5f89 Mon Sep 17 00:00:00 2001 From: Vijaykumar Badiger Date: Sat, 5 May 2018 17:19:57 -0700 Subject: [PATCH 1446/1635] soc: qcom: Add sa8150 SoC information into socinfo driver Add SA8150 SoC information to socinfo driver. Change-Id: I80fb5d62481128ca6d46635e64204e5fa841f896 Signed-off-by: Vijaykumar Badiger --- drivers/soc/qcom/socinfo.c | 7 +++++++ include/soc/qcom/socinfo.h | 4 ++++ 2 files changed, 11 insertions(+) diff --git a/drivers/soc/qcom/socinfo.c b/drivers/soc/qcom/socinfo.c index f39317c63aa6..d5f1cf0972af 100644 --- a/drivers/soc/qcom/socinfo.c +++ b/drivers/soc/qcom/socinfo.c @@ -307,6 +307,9 @@ static struct msm_soc_info cpu_of_id[] = { /* sm8150 ID */ [339] = {MSM_CPU_SM8150, "SM8150"}, + /* sa8150 ID */ + [362] = {MSM_CPU_SA8150, "SA8150"}, + /* sdmshrike ID */ [340] = {MSM_CPU_SDMSHRIKE, "SDMSHRIKE"}, @@ -1171,6 +1174,10 @@ static void * __init setup_dummy_socinfo(void) dummy_socinfo.id = 339; strlcpy(dummy_socinfo.build_id, "sm8150 - ", sizeof(dummy_socinfo.build_id)); + } else if (early_machine_is_sa8150()) { + dummy_socinfo.id = 362; + strlcpy(dummy_socinfo.build_id, "sa8150 - ", + sizeof(dummy_socinfo.build_id)); } else if (early_machine_is_sdmshrike()) { dummy_socinfo.id = 340; strlcpy(dummy_socinfo.build_id, "sdmshrike - ", diff --git a/include/soc/qcom/socinfo.h b/include/soc/qcom/socinfo.h index 62074135a3e3..e033efc8cd37 100644 --- a/include/soc/qcom/socinfo.h +++ b/include/soc/qcom/socinfo.h @@ -59,6 +59,8 @@ of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,msm8996-cdp") #define early_machine_is_sm8150() \ of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,sm8150") +#define early_machine_is_sa8150() \ + of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,sa8150") #define early_machine_is_sdmshrike() \ of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,sdmshrike") #define early_machine_is_sm6150() \ @@ -84,6 +86,7 @@ #define early_machine_is_apq8084() 0 #define early_machine_is_msm8996() 0 #define early_machine_is_sm8150() 0 +#define early_machine_is_sa8150() 0 #define early_machine_is_sdmshrike() 0 #define early_machine_is_sm6150() 0 #define early_machine_is_qcs405() 0 @@ -108,6 +111,7 @@ enum msm_cpu { MSM_CPU_8084, MSM_CPU_8996, MSM_CPU_SM8150, + MSM_CPU_SA8150, MSM_CPU_SDMSHRIKE, MSM_CPU_SM6150, MSM_CPU_QCS405, -- GitLab From a0d79a3b58d6377ec5e2fd913e9856366bf720a8 Mon Sep 17 00:00:00 2001 From: Chris Lew Date: Mon, 7 May 2018 18:40:57 -0700 Subject: [PATCH 1447/1635] soc: qcom: glink_pkt: Add one to refcounting Extra validation on the refcount APIs expect refcounts to be initialized to a non zero value. In order to avoid warnings for "increment on 0", start the refcount at 1. Change-Id: I08ffca896cda6b1ec78168751a732b8157a30763 Signed-off-by: Chris Lew --- drivers/soc/qcom/glink_pkt.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/drivers/soc/qcom/glink_pkt.c b/drivers/soc/qcom/glink_pkt.c index a4fb9c19ff62..3d3766b90443 100644 --- a/drivers/soc/qcom/glink_pkt.c +++ b/drivers/soc/qcom/glink_pkt.c @@ -308,7 +308,8 @@ int glink_pkt_release(struct inode *inode, struct file *file) gpdev->ch_name, current->comm, task_pid_nr(current), refcount_read(&gpdev->refcount)); - if (refcount_dec_and_test(&gpdev->refcount)) { + refcount_dec(&gpdev->refcount); + if (refcount_read(&gpdev->refcount) == 1) { spin_lock_irqsave(&gpdev->queue_lock, flags); /* Discard all SKBs */ @@ -345,7 +346,7 @@ ssize_t glink_pkt_read(struct file *file, char __user *buf, struct sk_buff *skb; int use; - if (!gpdev || !refcount_read(&gpdev->refcount)) { + if (!gpdev || refcount_read(&gpdev->refcount) == 1) { GLINK_PKT_ERR("invalid device handle\n", __func__); return -EINVAL; } @@ -416,7 +417,7 @@ ssize_t glink_pkt_write(struct file *file, const char __user *buf, int ret; gpdev = file->private_data; - if (!gpdev || !refcount_read(&gpdev->refcount)) { + if (!gpdev || refcount_read(&gpdev->refcount) == 1) { GLINK_PKT_ERR("invalid device handle\n", __func__); return -EINVAL; } @@ -466,7 +467,7 @@ static unsigned int glink_pkt_poll(struct file *file, poll_table *wait) unsigned long flags; gpdev = file->private_data; - if (!gpdev || !refcount_read(&gpdev->refcount)) { + if (!gpdev || refcount_read(&gpdev->refcount) == 1) { GLINK_PKT_ERR("invalid device handle\n", __func__); return POLLERR; } @@ -561,7 +562,7 @@ static long glink_pkt_ioctl(struct file *file, unsigned int cmd, int ret; gpdev = file->private_data; - if (!gpdev || !refcount_read(&gpdev->refcount)) { + if (!gpdev || refcount_read(&gpdev->refcount) == 1) { GLINK_PKT_ERR("invalid device handle\n", __func__); return -EINVAL; } @@ -733,7 +734,7 @@ static int glink_pkt_create_device(struct device *parent, dev = &gpdev->dev; mutex_init(&gpdev->lock); - refcount_set(&gpdev->refcount, 0); + refcount_set(&gpdev->refcount, 1); init_completion(&gpdev->ch_open); /* Default open timeout for open is 120 sec */ -- GitLab From 81a2f9e41cfd5031b91bf5b0b4834743726422ec Mon Sep 17 00:00:00 2001 From: Chris Lew Date: Mon, 7 May 2018 18:44:55 -0700 Subject: [PATCH 1448/1635] rpmsg: glink: Set tail pointer to 0 at end of FIFO When wrapping around the FIFO, the remote expects the tail pointer to be reset to 0 on the edge case where the tail equals the FIFO length. Change-Id: Ib0d2e7c3e9a3524a37792ec8cef3a2aac90e1bf6 Signed-off-by: Chris Lew --- drivers/rpmsg/qcom_glink_smem.c | 2 +- drivers/rpmsg/qcom_glink_spss.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/rpmsg/qcom_glink_smem.c b/drivers/rpmsg/qcom_glink_smem.c index b776adc6702d..a914914df4f5 100644 --- a/drivers/rpmsg/qcom_glink_smem.c +++ b/drivers/rpmsg/qcom_glink_smem.c @@ -116,7 +116,7 @@ static void glink_smem_rx_advance(struct qcom_glink_pipe *np, tail = le32_to_cpu(*pipe->tail); tail += count; - if (tail > pipe->native.length) + if (tail >= pipe->native.length) tail -= pipe->native.length; *pipe->tail = cpu_to_le32(tail); diff --git a/drivers/rpmsg/qcom_glink_spss.c b/drivers/rpmsg/qcom_glink_spss.c index 7ff798326d9e..1df692388add 100644 --- a/drivers/rpmsg/qcom_glink_spss.c +++ b/drivers/rpmsg/qcom_glink_spss.c @@ -105,7 +105,7 @@ static void glink_spss_rx_advance(struct qcom_glink_pipe *np, tail = le32_to_cpu(*pipe->tail); tail += count; - if (tail > pipe->native.length) + if (tail >= pipe->native.length) tail -= pipe->native.length; *pipe->tail = cpu_to_le32(tail); -- GitLab From 53fb96733c01f49340e2e21c32a8117cdb1800a5 Mon Sep 17 00:00:00 2001 From: Yuan Zhao Date: Fri, 4 May 2018 14:09:02 +0800 Subject: [PATCH 1449/1635] ARM: dts: msm: Modify the LM and power config for QRD SM8150 display Since the continue splash feature was enabled by UEFI, the LM config should be the same as UEFI config. The power supply of the panel should be kept on when kernel booting up. Change-Id: I6070e20975d4a4a108d482647af154ca685967a9 Signed-off-by: Yuan Zhao --- arch/arm64/boot/dts/qcom/sm8150-sde-display.dtsi | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sm8150-sde-display.dtsi b/arch/arm64/boot/dts/qcom/sm8150-sde-display.dtsi index a152f000fab1..cd99f6a12e60 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-sde-display.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-sde-display.dtsi @@ -40,7 +40,7 @@ pins = "gpio130"; drive-strength = <8>; bias-disable = <0>; - output-low; + output-high; }; }; }; @@ -128,6 +128,7 @@ regulator-enable-ramp-delay = <233>; gpio = <&tlmm 130 0>; enable-active-high; + regulator-boot-on; pinctrl-names = "default"; pintctrl-0 = <&display_panel_avdd_eldo_default>; }; @@ -672,7 +673,7 @@ timing@0 { qcom,mdss-dsi-panel-phy-timings = [00 1a 07 06 22 21 07 07 04 03 04 00 16 16]; - qcom,display-topology = <1 1 1>; + qcom,display-topology = <2 1 1>; qcom,default-topology-index = <0>; }; }; -- GitLab From cc072dd5e94184a3dd48372d3c5c7ebad8e0249a Mon Sep 17 00:00:00 2001 From: Sonal Gupta Date: Thu, 3 May 2018 14:48:59 -0700 Subject: [PATCH 1450/1635] ARM: dts: msm: Increase Secure Display Heap size for SM8150 Increase secure display heap size from 92 MB to 120 MB for Secure UI use case to support UHD screen size on SM8150 platforms. Change-Id: Ia7431d463e5c2968850c4771c3a1e04b775274bc Signed-off-by: Sonal Gupta --- arch/arm64/boot/dts/qcom/sm8150.dtsi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sm8150.dtsi b/arch/arm64/boot/dts/qcom/sm8150.dtsi index 5caf89841f6f..aad8b8c85143 100644 --- a/arch/arm64/boot/dts/qcom/sm8150.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150.dtsi @@ -717,12 +717,12 @@ size = <0x0 0x800000>; }; - secure_display_memory: secure_display_region { + secure_display_memory: secure_display_region { /* Secure UI */ compatible = "shared-dma-pool"; alloc-ranges = <0x0 0x00000000 0x0 0xffffffff>; reusable; alignment = <0x0 0x400000>; - size = <0x0 0x5c00000>; + size = <0x0 0x7800000>; }; dump_mem: mem_dump_region { -- GitLab From de7fdb351c05d03a5fb6398da26ef9280df68cb5 Mon Sep 17 00:00:00 2001 From: Harry Yang Date: Wed, 2 May 2018 13:10:09 -0700 Subject: [PATCH 1451/1635] power: smb5: Fix fast charge current step size The current CHGR_FAST_CHARGE_CURRENT_CFG step size is is 25000uA, while the right value per spec should be 50000uA. Correct it. CRs-Fixed: 2237758 Change-Id: I6c201fb10ec6eb0ffc70c14e83d69e7fff7ec121 Signed-off-by: Harry Yang --- drivers/power/supply/qcom/qpnp-smb5.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/power/supply/qcom/qpnp-smb5.c b/drivers/power/supply/qcom/qpnp-smb5.c index e84f7830cef8..79f572a1b941 100644 --- a/drivers/power/supply/qcom/qpnp-smb5.c +++ b/drivers/power/supply/qcom/qpnp-smb5.c @@ -103,7 +103,7 @@ static struct smb_params smb5_pm855b_params = { .reg = CHGR_FAST_CHARGE_CURRENT_CFG_REG, .min_u = 0, .max_u = 8000000, - .step_u = 25000, + .step_u = 50000, }, .fv = { .name = "float voltage", -- GitLab From f44c52b97311fc045ffe351982fda5d741693f8f Mon Sep 17 00:00:00 2001 From: Charan Teja Reddy Date: Mon, 9 Apr 2018 21:20:27 +0530 Subject: [PATCH 1452/1635] ARM: dts: msm: add ion heaps for qcs405 Add ion heaps support that is used to manage one or more memory pools on qcs405. Change-Id: Icf9e1460d28751f4ad5a8d85827f89fede17f84c Signed-off-by: Charan Teja Reddy --- arch/arm64/boot/dts/qcom/qcs405-ion.dtsi | 30 ++++++++++++++++++++++++ arch/arm64/boot/dts/qcom/qcs405.dtsi | 1 + 2 files changed, 31 insertions(+) create mode 100644 arch/arm64/boot/dts/qcom/qcs405-ion.dtsi diff --git a/arch/arm64/boot/dts/qcom/qcs405-ion.dtsi b/arch/arm64/boot/dts/qcom/qcs405-ion.dtsi new file mode 100644 index 000000000000..0fc6ca98c1b7 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/qcs405-ion.dtsi @@ -0,0 +1,30 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +&soc { + qcom,ion { + compatible = "qcom,msm-ion"; + #address-cells = <1>; + #size-cells = <0>; + + system_heap: qcom,ion-heap@25 { + reg = <25>; + qcom,ion-heap-type = "SYSTEM"; + }; + + qcom,ion-heap@27 { /* QSEECOM HEAP */ + reg = <27>; + memory-region = <&qseecom_mem>; + qcom,ion-heap-type = "DMA"; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/qcs405.dtsi b/arch/arm64/boot/dts/qcom/qcs405.dtsi index a1479c2a30b6..38fe976da357 100644 --- a/arch/arm64/boot/dts/qcom/qcs405.dtsi +++ b/arch/arm64/boot/dts/qcom/qcs405.dtsi @@ -110,6 +110,7 @@ #include "qcs405-pinctrl.dtsi" #include "qcs405-blsp.dtsi" #include "qcs405-cpu.dtsi" +#include "qcs405-ion.dtsi" &soc { #address-cells = <1>; -- GitLab From 120532ddbb42d2a83ec0172fb5e1801f8b24ec33 Mon Sep 17 00:00:00 2001 From: Zhongbo Shi Date: Wed, 2 May 2018 13:55:06 +0800 Subject: [PATCH 1453/1635] msm: vidc: add control to support NAL size config Add a control V4L2_CID_MPEG_VIDC_VIDEO_STREAM_FORMAT to support multi-slice NAL size query and configure. Change-Id: I6974a66db1daf75b95cde5772880d00cdf60bacf Signed-off-by: Zhongbo Shi --- include/uapi/linux/v4l2-controls.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/include/uapi/linux/v4l2-controls.h b/include/uapi/linux/v4l2-controls.h index 603cd4692f2c..5cbd9c19a15f 100644 --- a/include/uapi/linux/v4l2-controls.h +++ b/include/uapi/linux/v4l2-controls.h @@ -687,6 +687,12 @@ enum v4l2_mpeg_vidc_video_pictype_dec_mode { V4L2_MPEG_VIDC_VIDEO_PICTYPE_DECODE_B = 4, }; +#define V4L2_CID_MPEG_VIDC_VIDEO_STREAM_FORMAT (V4L2_CID_MPEG_MSM_VIDC_BASE+2) +enum v4l2_mpeg_vidc_video_stream_format { + V4L2_MPEG_VIDC_VIDEO_NAL_FORMAT_STARTCODES = 0, + V4L2_MPEG_VIDC_VIDEO_NAL_FORMAT_FOUR_BYTE_LENGTH = 4, +}; + #define V4L2_CID_MPEG_VIDC_VIDEO_OUTPUT_ORDER (V4L2_CID_MPEG_MSM_VIDC_BASE+3) enum v4l2_mpeg_vidc_video_output_order { V4L2_MPEG_VIDC_VIDEO_OUTPUT_ORDER_DISPLAY = 0, -- GitLab From be6e6f729a874a3498d6904f3aaf6b95cd33e557 Mon Sep 17 00:00:00 2001 From: Prateek Sood Date: Mon, 7 May 2018 12:08:26 +0530 Subject: [PATCH 1454/1635] defconfig: msm: disable ARCH_SM8150 in SM6150 defconfig Disable ARCH_SM8150 from sm6150 perf defconfig. Change-Id: I297d45b0d4e9fc587fb787980bf86f6d712d30c3 Signed-off-by: Prateek Sood --- arch/arm64/configs/sdmsteppe-perf_defconfig | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/arm64/configs/sdmsteppe-perf_defconfig b/arch/arm64/configs/sdmsteppe-perf_defconfig index 8deba27ba401..32ed0b0d85dc 100644 --- a/arch/arm64/configs/sdmsteppe-perf_defconfig +++ b/arch/arm64/configs/sdmsteppe-perf_defconfig @@ -52,7 +52,6 @@ CONFIG_MODULE_SIG_FORCE=y CONFIG_MODULE_SIG_SHA512=y CONFIG_PARTITION_ADVANCED=y CONFIG_ARCH_QCOM=y -CONFIG_ARCH_SM8150=y CONFIG_ARCH_SM6150=y CONFIG_PCI=y CONFIG_PCI_MSM=y -- GitLab From 88861a1e0827e66be23f12ee01601109e5a79bcb Mon Sep 17 00:00:00 2001 From: Skylar Chang Date: Tue, 10 Apr 2018 11:39:05 -0700 Subject: [PATCH 1455/1635] msm: ipa: add support for HW stats to QMI Populate new fields in the QMI message to send information regarding HW stats location in SRAM. Change-Id: Idaae117081fad6a5cf797eefd5399aa9a4cc35f9 Acked-by: Ady Abraham Signed-off-by: Mohammed Javid Signed-off-by: Skylar Chang --- .../platform/msm/ipa/ipa_v3/ipa_qmi_service.c | 14 ++++ .../msm/ipa/ipa_v3/ipa_qmi_service_v01.c | 81 +++++++++++++++++++ include/uapi/linux/ipa_qmi_service_v01.h | 39 ++++++++- 3 files changed, 133 insertions(+), 1 deletion(-) diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.c b/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.c index 09b34c1d91c9..1249b1408b19 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.c @@ -425,6 +425,20 @@ static int ipa3_qmi_init_modem_send_sync_msg(void) req.v6_hash_filter_tbl_start_addr = IPA_MEM_PART(v6_flt_hash_ofst) + smem_restr_bytes; + req.hw_stats_quota_base_addr_valid = true; + req.hw_stats_quota_base_addr = + IPA_MEM_PART(stats_quota_ofst) + smem_restr_bytes; + + req.hw_stats_quota_size_valid = true; + req.hw_stats_quota_size = IPA_MEM_PART(stats_quota_size); + + req.hw_drop_stats_base_addr_valid = true; + req.hw_drop_stats_base_addr = + IPA_MEM_PART(stats_drop_ofst) + smem_restr_bytes; + + req.hw_drop_stats_table_size_valid = true; + req.hw_drop_stats_table_size = IPA_MEM_PART(stats_drop_size); + if (!ipa3_uc_loaded_check()) { /* First time boot */ req.is_ssr_bootup_valid = false; req.is_ssr_bootup = 0; diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service_v01.c b/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service_v01.c index 6878e0a23ca3..05c4682e4c3b 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service_v01.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service_v01.c @@ -1092,11 +1092,92 @@ struct qmi_elem_info ipa3_init_modem_driver_req_msg_data_v01_ei[] = { struct ipa_init_modem_driver_req_msg_v01, v6_hash_filter_tbl_start_addr), }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .is_array = NO_ARRAY, + .tlv_type = 0x1F, + .offset = offsetof( + struct ipa_init_modem_driver_req_msg_v01, + hw_stats_quota_base_addr_valid), + }, + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint32_t), + .is_array = NO_ARRAY, + .tlv_type = 0x1F, + .offset = offsetof( + struct ipa_init_modem_driver_req_msg_v01, + hw_stats_quota_base_addr), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .is_array = NO_ARRAY, + .tlv_type = 0x20, + .offset = offsetof( + struct ipa_init_modem_driver_req_msg_v01, + hw_stats_quota_size_valid), + }, + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint32_t), + .is_array = NO_ARRAY, + .tlv_type = 0x20, + .offset = offsetof( + struct ipa_init_modem_driver_req_msg_v01, + hw_stats_quota_size), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .is_array = NO_ARRAY, + .tlv_type = 0x21, + .offset = offsetof( + struct ipa_init_modem_driver_req_msg_v01, + hw_drop_stats_base_addr_valid), + }, + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint32_t), + .is_array = NO_ARRAY, + .tlv_type = 0x21, + .offset = offsetof( + struct ipa_init_modem_driver_req_msg_v01, + hw_drop_stats_base_addr), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .is_array = NO_ARRAY, + .tlv_type = 0x22, + .offset = offsetof( + struct ipa_init_modem_driver_req_msg_v01, + hw_drop_stats_table_size_valid), + }, + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint32_t), + .is_array = NO_ARRAY, + .tlv_type = 0x22, + .offset = offsetof( + struct ipa_init_modem_driver_req_msg_v01, + hw_drop_stats_table_size), + }, { .data_type = QMI_EOTI, .is_array = NO_ARRAY, .tlv_type = QMI_COMMON_TLV_TYPE, }, + }; struct qmi_elem_info ipa3_init_modem_driver_resp_msg_data_v01_ei[] = { diff --git a/include/uapi/linux/ipa_qmi_service_v01.h b/include/uapi/linux/ipa_qmi_service_v01.h index 1d48dfd50515..0b403cf20b25 100644 --- a/include/uapi/linux/ipa_qmi_service_v01.h +++ b/include/uapi/linux/ipa_qmi_service_v01.h @@ -56,6 +56,11 @@ #define QMI_IPA_MAX_CLIENT_DST_PIPES_V01 8 #define QMI_IPA_MAX_UL_FIREWALL_RULES_V01 64 +/* + * Indicates presence of newly added member to support HW stats. + */ +#define IPA_QMI_SUPPORTS_STATS + #define IPA_INT_MAX ((int)(~0U>>1)) #define IPA_INT_MIN (-IPA_INT_MAX - 1) @@ -316,6 +321,38 @@ struct ipa_init_modem_driver_req_msg_v01 { * table in IPAv3 onwards. Denotes the offset from the start of * the IPA shared memory. */ + + /* Optional + * Modem HW Stats Quota Base address + * Must be set to true if hw_stats_quota_base_addr + * is being passed + */ + uint8_t hw_stats_quota_base_addr_valid; + uint32_t hw_stats_quota_base_addr; + + /* Optional + * Modem HW Stats Quota Size + * Must be set to true if hw_stats_quota_size + * is being passed + */ + uint8_t hw_stats_quota_size_valid; + uint32_t hw_stats_quota_size; + + /* Optional + * Modem HW Drop Stats Table Start Address + * Must be set to true if hw_drop_stats_base_addr + * is being passed + */ + uint8_t hw_drop_stats_base_addr_valid; + uint32_t hw_drop_stats_base_addr; + + /* Optional + * Modem HW Drop Stats Table size + * Must be set to true if hw_drop_stats_table_size + * is being passed + */ + uint8_t hw_drop_stats_table_size_valid; + uint32_t hw_drop_stats_table_size; }; /* Message */ /* Response Message; Requests the modem IPA driver about initialization */ @@ -1953,7 +1990,7 @@ struct ipa_configure_ul_firewall_rules_ind_msg_v01 { #define QMI_IPA_INSTALL_UL_FIREWALL_RULES_IND_V01 0x003A /* add for max length*/ -#define QMI_IPA_INIT_MODEM_DRIVER_REQ_MAX_MSG_LEN_V01 134 +#define QMI_IPA_INIT_MODEM_DRIVER_REQ_MAX_MSG_LEN_V01 162 #define QMI_IPA_INIT_MODEM_DRIVER_RESP_MAX_MSG_LEN_V01 25 #define QMI_IPA_INDICATION_REGISTER_REQ_MAX_MSG_LEN_V01 8 #define QMI_IPA_INDICATION_REGISTER_RESP_MAX_MSG_LEN_V01 7 -- GitLab From 6ae245ae93521948f07de9ff435ff5ec13700723 Mon Sep 17 00:00:00 2001 From: Kiran Gunda Date: Tue, 8 May 2018 16:33:50 +0530 Subject: [PATCH 1456/1635] ARM: dts: msm: Disable the spmi bus node for sm6150 rumi As the PMIC is not present on the rumi, disable the spmi bus node to avoid the un-successful PMIC read/writes from the clients. Change-Id: Ie2633101ae4778c4f43e5d1dba2f9b19e0fd4003 Signed-off-by: Kiran Gunda --- arch/arm64/boot/dts/qcom/sm6150-rumi.dtsi | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sm6150-rumi.dtsi b/arch/arm64/boot/dts/qcom/sm6150-rumi.dtsi index 1fd5029c0d78..0fc5827e667a 100644 --- a/arch/arm64/boot/dts/qcom/sm6150-rumi.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6150-rumi.dtsi @@ -71,3 +71,7 @@ status = "disabled"; }; + +&spmi_bus { + status = "disabled"; +}; -- GitLab From ed7428aea5b3e3c7ef9ad83c5747e83f771271b0 Mon Sep 17 00:00:00 2001 From: Tharun Kumar Merugu Date: Tue, 8 May 2018 18:28:54 +0530 Subject: [PATCH 1457/1635] ARM: dts: msm: update fastrpc context bank iommu for sm8150 Update the stream ID and SMR mask in IOMMU info for fastrpc context bank 3 in sm8150. Change-Id: Ib00794545ba8f4a3210cb88b4b2cc7b27f6e220c Acked-by: Thyagarajan Venkatanarayanan Signed-off-by: Tharun Kumar Merugu --- arch/arm64/boot/dts/qcom/sm8150.dtsi | 29 ++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sm8150.dtsi b/arch/arm64/boot/dts/qcom/sm8150.dtsi index 5caf89841f6f..0f05ca3ce1f3 100644 --- a/arch/arm64/boot/dts/qcom/sm8150.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150.dtsi @@ -2167,14 +2167,6 @@ dma-coherent; }; - qcom,msm_fastrpc_compute_cb3 { - compatible = "qcom,msm-fastrpc-compute-cb"; - label = "cdsprpc-smd"; - iommus = <&apps_smmu 0x3 0x3440>, - <&apps_smmu 0x23 0x3400>; - dma-coherent; - }; - qcom,msm_fastrpc_compute_cb4 { compatible = "qcom,msm-fastrpc-compute-cb"; label = "cdsprpc-smd"; @@ -2212,19 +2204,28 @@ dma-coherent; }; - qcom,msm_fastrpc_compute_cb9 { + qcom,msm_fastrpc_compute_cb2 { compatible = "qcom,msm-fastrpc-compute-cb"; label = "cdsprpc-smd"; - qcom,secure-context-bank; - iommus = <&apps_smmu 0x9 0x3460>; + iommus = <&apps_smmu 0x2 0x3440>, + <&apps_smmu 0x22 0x3400>; dma-coherent; }; - qcom,msm_fastrpc_compute_cb2 { + qcom,msm_fastrpc_compute_cb3 { compatible = "qcom,msm-fastrpc-compute-cb"; label = "cdsprpc-smd"; - iommus = <&apps_smmu 0x2 0x3440>, - <&apps_smmu 0x22 0x3400>; + iommus = <&apps_smmu 0x3 0x3440>, + <&apps_smmu 0x1423 0x0>, + <&apps_smmu 0x2023 0x0>; + dma-coherent; + }; + + qcom,msm_fastrpc_compute_cb9 { + compatible = "qcom,msm-fastrpc-compute-cb"; + label = "cdsprpc-smd"; + qcom,secure-context-bank; + iommus = <&apps_smmu 0x9 0x3460>; dma-coherent; }; -- GitLab From 2789647760413ac82eb0a1210d515aae84f606fb Mon Sep 17 00:00:00 2001 From: Adam Bickett Date: Sun, 6 May 2018 15:44:11 -0700 Subject: [PATCH 1458/1635] ARM: dts: msm: Fix ap2mdm_pon_reset configuration for SM8150+SDX50 MDM PON control should not be driven low except when set by esoc. Remove output-low property to meet this requirement. Change-Id: Iae7742e51b46e633846212a2dcc10a9cf47875a2 Signed-off-by: Adam Bickett --- arch/arm64/boot/dts/qcom/sm8150-sdx50m.dtsi | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/sm8150-sdx50m.dtsi b/arch/arm64/boot/dts/qcom/sm8150-sdx50m.dtsi index 28eba3e155f2..206aad4c56eb 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-sdx50m.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-sdx50m.dtsi @@ -33,7 +33,6 @@ /* MDM PON conrol*/ pins = "gpio9"; function = "normal"; - output-low; power-source = <1>; /* 1.8V */ }; }; -- GitLab From fbd0e387f94e80002838bc03b15f950a8a5b9d6c Mon Sep 17 00:00:00 2001 From: Deepak Katragadda Date: Tue, 8 May 2018 09:52:54 -0700 Subject: [PATCH 1459/1635] clk: qcom: videocc-sm8150: Update the RCG configuration for iris_clk_src Update the frequency table for the video_cc_iris_clk_src RCG to use a uniform RCG pre-divider of 2 for all supported frequencies. Change-Id: Ie22bbcd74a34ae9ec384bd053d6c3eae253f8a7e Signed-off-by: Deepak Katragadda --- drivers/clk/qcom/videocc-sm8150.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/clk/qcom/videocc-sm8150.c b/drivers/clk/qcom/videocc-sm8150.c index c14b34b28e0e..c18ee37dc8b9 100644 --- a/drivers/clk/qcom/videocc-sm8150.c +++ b/drivers/clk/qcom/videocc-sm8150.c @@ -106,9 +106,9 @@ static const struct freq_tbl ftbl_video_cc_iris_clk_src[] = { F(200000000, P_VIDEO_PLL0_OUT_MAIN, 2, 0, 0), F(225000000, P_VIDEO_PLL0_OUT_MAIN, 2, 0, 0), F(300000000, P_VIDEO_PLL0_OUT_MAIN, 2, 0, 0), - F(365000000, P_VIDEO_PLL0_OUT_MAIN, 3, 0, 0), - F(432000000, P_VIDEO_PLL0_OUT_MAIN, 3, 0, 0), - F(480000000, P_VIDEO_PLL0_OUT_MAIN, 3, 0, 0), + F(365000000, P_VIDEO_PLL0_OUT_MAIN, 2, 0, 0), + F(432000000, P_VIDEO_PLL0_OUT_MAIN, 2, 0, 0), + F(480000000, P_VIDEO_PLL0_OUT_MAIN, 2, 0, 0), { } }; -- GitLab From d8406c316048e2333da60c3194cb9ac58ea33dd5 Mon Sep 17 00:00:00 2001 From: Odelu Kukatla Date: Tue, 28 Nov 2017 17:46:34 +0530 Subject: [PATCH 1460/1635] msm: msm_bus: Add mutex lock for floor vote data Floor vote data needs to be protected with mutex lock to avoid double free of memory due to race condtion. Change-Id: Ifaa01a14d273ccba6b9463aff3a41c0038b05f06 Signed-off-by: Odelu Kukatla --- drivers/soc/qcom/msm_bus/msm_bus_dbg_voter.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/drivers/soc/qcom/msm_bus/msm_bus_dbg_voter.c b/drivers/soc/qcom/msm_bus/msm_bus_dbg_voter.c index 1f35f49dad5e..622a90fc2c32 100644 --- a/drivers/soc/qcom/msm_bus/msm_bus_dbg_voter.c +++ b/drivers/soc/qcom/msm_bus/msm_bus_dbg_voter.c @@ -27,6 +27,7 @@ struct msm_bus_floor_client_type { }; static struct class *bus_floor_class; +static DEFINE_RT_MUTEX(msm_bus_floor_vote_lock); #define MAX_VOTER_NAME (50) #define DEFAULT_NODE_WIDTH (8) #define DBG_NAME(s) (strnstr(s, "-", 7) + 1) @@ -64,18 +65,22 @@ static ssize_t bus_floor_active_only_store(struct device *dev, { struct msm_bus_floor_client_type *cl; + rt_mutex_lock(&msm_bus_floor_vote_lock); cl = dev_get_drvdata(dev); if (!cl) { pr_err("%s: Can't find cl", __func__); + rt_mutex_unlock(&msm_bus_floor_vote_lock); return 0; } if (kstrtoint(buf, 10, &cl->active_only) != 0) { pr_err("%s:return error", __func__); + rt_mutex_unlock(&msm_bus_floor_vote_lock); return -EINVAL; } + rt_mutex_unlock(&msm_bus_floor_vote_lock); return n; } @@ -100,20 +105,24 @@ static ssize_t bus_floor_vote_store(struct device *dev, struct msm_bus_floor_client_type *cl; int ret = 0; + rt_mutex_lock(&msm_bus_floor_vote_lock); cl = dev_get_drvdata(dev); if (!cl) { pr_err("%s: Can't find cl", __func__); + rt_mutex_unlock(&msm_bus_floor_vote_lock); return 0; } if (kstrtoull(buf, 10, &cl->cur_vote_hz) != 0) { pr_err("%s:return error", __func__); + rt_mutex_unlock(&msm_bus_floor_vote_lock); return -EINVAL; } ret = msm_bus_floor_vote_context(dev_name(dev), cl->cur_vote_hz, cl->active_only); + rt_mutex_unlock(&msm_bus_floor_vote_lock); return n; } @@ -126,15 +135,18 @@ static ssize_t bus_floor_vote_store_api(struct device *dev, char name[10]; u64 vote_khz = 0; + rt_mutex_lock(&msm_bus_floor_vote_lock); cl = dev_get_drvdata(dev); if (!cl) { pr_err("%s: Can't find cl", __func__); + rt_mutex_unlock(&msm_bus_floor_vote_lock); return 0; } if (sscanf(buf, "%9s %llu", name, &vote_khz) != 2) { pr_err("%s:return error", __func__); + rt_mutex_unlock(&msm_bus_floor_vote_lock); return -EINVAL; } @@ -142,6 +154,7 @@ static ssize_t bus_floor_vote_store_api(struct device *dev, __func__, name, vote_khz); ret = msm_bus_floor_vote(name, vote_khz); + rt_mutex_unlock(&msm_bus_floor_vote_lock); return n; } -- GitLab From 7d2b75be77e627cd34e6fef7955b9eadbb902ab0 Mon Sep 17 00:00:00 2001 From: Vamsi Krishna Samavedam Date: Mon, 7 May 2018 23:19:46 -0700 Subject: [PATCH 1461/1635] usb: dwc3-msm: Reduce bus bandwidth vote based on device type Driver currently votes for nominal bus bandwidth to enable/support enhanced super speed devices. Vote can be reduced when high speed devices (such as headset) are connected to allow additional power savings. Change-Id: I19277f223051d322b7bdf74c629627d39ac2b801 Signed-off-by: Vamsi Krishna Samavedam --- drivers/usb/dwc3/dwc3-msm.c | 79 ++++++++++++++++++++++++++++--------- 1 file changed, 61 insertions(+), 18 deletions(-) diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c index 008c23d880dd..76daf5b7c700 100644 --- a/drivers/usb/dwc3/dwc3-msm.c +++ b/drivers/usb/dwc3/dwc3-msm.c @@ -2113,6 +2113,60 @@ static void configure_nonpdc_usb_interrupt(struct dwc3_msm *mdwc, } } +enum bus_vote { + BUS_VOTE_INVALID, + BUS_VOTE_SUSPEND, + BUS_VOTE_NOMINAL, + BUS_VOTE_SVS +}; + +static int dwc3_msm_update_bus_bw(struct dwc3_msm *mdwc, enum bus_vote bv) +{ + int ret = 0; + struct dwc3 *dwc = platform_get_drvdata(mdwc->dwc3); + + if (!mdwc->bus_perf_client) + return 0; + + dbg_event(0xFF, "bus_vote_start", bv); + + switch (bv) { + case BUS_VOTE_SVS: + /* On some platforms SVS does not have separate vote. Vote for + * nominal if svs usecase does not exist + */ + if (mdwc->bus_scale_table->num_usecases == 2) + goto nominal_vote; + + /* index starts from zero */ + ret = msm_bus_scale_client_update_request( + mdwc->bus_perf_client, 2); + if (ret) + dev_err(mdwc->dev, "bus bw voting failed %d\n", ret); + break; + case BUS_VOTE_NOMINAL: +nominal_vote: + ret = msm_bus_scale_client_update_request( + mdwc->bus_perf_client, 1); + if (ret) + dev_err(mdwc->dev, "bus bw voting failed %d\n", ret); + break; + case BUS_VOTE_SUSPEND: + ret = msm_bus_scale_client_update_request( + mdwc->bus_perf_client, 0); + if (ret) + dev_err(mdwc->dev, "bus bw voting failed %d\n", ret); + break; + default: + dev_err(mdwc->dev, "Unsupported bus vote:%d\n", bv); + ret = -EINVAL; + } + + dbg_event(0xFF, "bus_vote_end", bv); + + return ret; + +} static int dwc3_msm_suspend(struct dwc3_msm *mdwc) { int ret; @@ -2244,15 +2298,7 @@ static int dwc3_msm_suspend(struct dwc3_msm *mdwc) } } - /* Remove bus voting */ - if (mdwc->bus_perf_client) { - dbg_event(0xFF, "bus_devote_start", 0); - ret = msm_bus_scale_client_update_request( - mdwc->bus_perf_client, 0); - dbg_event(0xFF, "bus_devote_finish", 0); - if (ret) - dev_err(mdwc->dev, "bus bw unvoting failed %d\n", ret); - } + dwc3_msm_update_bus_bw(mdwc, BUS_VOTE_SUSPEND); /* * release wakeup source with timeout to defer system suspend to @@ -2310,15 +2356,10 @@ static int dwc3_msm_resume(struct dwc3_msm *mdwc) pm_stay_awake(mdwc->dev); - /* Enable bus voting */ - if (mdwc->bus_perf_client) { - dbg_event(0xFF, "bus_vote_start", 1); - ret = msm_bus_scale_client_update_request( - mdwc->bus_perf_client, 1); - dbg_event(0xFF, "bus_vote_finish", 1); - if (ret) - dev_err(mdwc->dev, "bus bw voting failed %d\n", ret); - } + if (mdwc->in_host_mode && mdwc->max_rh_port_speed == USB_SPEED_HIGH) + dwc3_msm_update_bus_bw(mdwc, BUS_VOTE_SVS); + else + dwc3_msm_update_bus_bw(mdwc, BUS_VOTE_NOMINAL); /* Vote for TCXO while waking up USB HSPHY */ ret = clk_prepare_enable(mdwc->xo_clk); @@ -3530,6 +3571,7 @@ static int dwc3_msm_host_notifier(struct notifier_block *nb, "set hs core clk rate %ld\n", mdwc->core_clk_rate_hs); mdwc->max_rh_port_speed = USB_SPEED_HIGH; + dwc3_msm_update_bus_bw(mdwc, BUS_VOTE_SVS); } else { mdwc->max_rh_port_speed = USB_SPEED_SUPER; } @@ -3555,6 +3597,7 @@ static int dwc3_msm_host_notifier(struct notifier_block *nb, dev_dbg(mdwc->dev, "set core clk rate %ld\n", mdwc->core_clk_rate); mdwc->max_rh_port_speed = USB_SPEED_UNKNOWN; + dwc3_msm_update_bus_bw(mdwc, BUS_VOTE_NOMINAL); } } -- GitLab From 3d0f91bd76b410175698a0c408824da8fa4940d2 Mon Sep 17 00:00:00 2001 From: Vamsi Krishna Samavedam Date: Mon, 7 May 2018 23:44:40 -0700 Subject: [PATCH 1462/1635] ARM: dts: msm: Add additional bus bandwidth usecase on SM8150 Add additional bus bandwidth usecase so that driver can vote for it based on device connection speed. Change-Id: I6ee8f2284e2a6b27edd88ff7994d0a9eb697cc72 Signed-off-by: Vamsi Krishna Samavedam --- arch/arm64/boot/dts/qcom/sm8150-usb.dtsi | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/sm8150-usb.dtsi b/arch/arm64/boot/dts/qcom/sm8150-usb.dtsi index 3b8a17867a98..97a4a7690b9e 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-usb.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-usb.dtsi @@ -55,15 +55,24 @@ qcom,dwc-usb3-msm-tx-fifo-size = <27696>; qcom,msm-bus,name = "usb0"; - qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-cases = <3>; qcom,msm-bus,num-paths = <3>; qcom,msm-bus,vectors-KBps = + /* suspend vote */ , , , + + /* nominal vote */ , , + , + + /* svs vote */ + , + , ; dwc3@a600000 { -- GitLab From b398b596a9e9018b44adc556c447cf08417a7b69 Mon Sep 17 00:00:00 2001 From: Patrick Daly Date: Mon, 13 Nov 2017 19:27:08 -0800 Subject: [PATCH 1463/1635] iommu: debug: Fix leaky context banks The contents of struct device->archdata contain private information for the dma layer and should not be accessed by device drivers. In this particular instance, the archdata->mapping field is set to NULL after arm_iommu_detach_device(), leading to arm_iommu_relase_mapping(NULL). This returns without freeing context banks or other resources. Change-Id: I974eb7ddc562e80c2d8a9e5260abf554e20042fa Signed-off-by: Patrick Daly --- drivers/iommu/iommu-debug.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/iommu/iommu-debug.c b/drivers/iommu/iommu-debug.c index 1b84e1374eb3..65dd81e8650d 100644 --- a/drivers/iommu/iommu-debug.c +++ b/drivers/iommu/iommu-debug.c @@ -161,6 +161,7 @@ static void *test_virt_addr; struct iommu_debug_device { struct device *dev; struct iommu_domain *domain; + struct dma_iommu_mapping *mapping; u64 iova; u64 phys; size_t len; @@ -1329,6 +1330,8 @@ static ssize_t __iommu_debug_dma_attach_write(struct file *file, if (arm_iommu_attach_device(dev, dma_mapping)) goto out_release_mapping; + + ddev->mapping = dma_mapping; pr_err("Attached\n"); } else { if (!dev->archdata.mapping) { @@ -1342,7 +1345,7 @@ static ssize_t __iommu_debug_dma_attach_write(struct file *file, goto out; } arm_iommu_detach_device(dev); - arm_iommu_release_mapping(dev->archdata.mapping); + arm_iommu_release_mapping(ddev->mapping); pr_err("Detached\n"); } retval = count; -- GitLab From 087358698b5de60aabc33d215e6ebf9612c2ddc2 Mon Sep 17 00:00:00 2001 From: Odelu Kukatla Date: Thu, 22 Feb 2018 23:41:05 +0530 Subject: [PATCH 1464/1635] msm: msm_bus: Add proxy bus client driver Add a proxy client driver which can be used to cast a proxy bandwidth vote during boot up for a critical resource which is removed at the end of boot. This is required to ensure that a certain minimum state for a critical resource at the beginning of boot up before the clients have probed and voted for required state. Change-Id: I34638c458604231a68b926bbe5110dcf96162352 Signed-off-by: Odelu Kukatla --- .../bindings/arm/msm/proxy-client.txt | 34 +++++++ drivers/soc/qcom/msm_bus/Makefile | 2 +- .../soc/qcom/msm_bus/msm_bus_proxy_client.c | 93 +++++++++++++++++++ 3 files changed, 128 insertions(+), 1 deletion(-) create mode 100644 Documentation/devicetree/bindings/arm/msm/proxy-client.txt create mode 100644 drivers/soc/qcom/msm_bus/msm_bus_proxy_client.c diff --git a/Documentation/devicetree/bindings/arm/msm/proxy-client.txt b/Documentation/devicetree/bindings/arm/msm/proxy-client.txt new file mode 100644 index 000000000000..29cfaf90016c --- /dev/null +++ b/Documentation/devicetree/bindings/arm/msm/proxy-client.txt @@ -0,0 +1,34 @@ +Bus Proxy Client Bindings + +Bus proxy client provides means to cast proxy bandwidth votes during bootup +which is removed at the end of boot. This feature can be used in situations +where a shared resource can be scaled between several possible perfomance +levels and hardware requires that it be at a high level at the beginning of +boot before the client has probed and voted for required bandwidth. + +Required properties: +- compatible: Must be "qcom,bus-proxy-client". + +Optional properties: +- qcom,msm-bus,name: String representing the client-name. +- qcom,msm-bus,num-cases: Total number of usecases. +- qcom,msm-bus,active-only: Boolean context flag for requests in active or + dual (active & sleep) contex. +- qcom,msm-bus,num-paths: Total number of master-slave pairs. +- qcom,msm-bus,vectors-KBps: Arrays of unsigned integers representing: + master-id, slave-id, arbitrated bandwidth + in KBps, instantaneous bandwidth in KBps. + +Example: + + qcom,proxy-client { + compatible = "qcom,bus-proxy-client"; + qcom,msm-bus,name = "proxy_client"; + qcom,msm-bus,num-cases = <3>; + qcom,msm-bus,num-paths = <2>; + qcom,msm-bus,active-only; + qcom,msm-bus,vectors-KBps = + <22 512 0 0>, <23 512 0 0>, + <22 512 0 6400000>, <23 512 0 6400000>, + <22 512 0 6400000>, <23 512 0 6400000>; + }; diff --git a/drivers/soc/qcom/msm_bus/Makefile b/drivers/soc/qcom/msm_bus/Makefile index 1103360e182a..b33835657e1f 100644 --- a/drivers/soc/qcom/msm_bus/Makefile +++ b/drivers/soc/qcom/msm_bus/Makefile @@ -7,7 +7,7 @@ obj-$(CONFIG_MSM_RPM_SMD) += msm_bus_rpm_smd.o ifdef CONFIG_QCOM_BUS_CONFIG_RPMH obj-y += msm_bus_fabric_rpmh.o msm_bus_arb_rpmh.o msm_bus_rules.o \ - msm_bus_bimc_rpmh.o msm_bus_noc_rpmh.o + msm_bus_bimc_rpmh.o msm_bus_noc_rpmh.o msm_bus_proxy_client.o obj-$(CONFIG_OF) += msm_bus_of_rpmh.o else obj-y += msm_bus_fabric_adhoc.o msm_bus_arb_adhoc.o \ diff --git a/drivers/soc/qcom/msm_bus/msm_bus_proxy_client.c b/drivers/soc/qcom/msm_bus/msm_bus_proxy_client.c new file mode 100644 index 000000000000..cdf61f6c8644 --- /dev/null +++ b/drivers/soc/qcom/msm_bus/msm_bus_proxy_client.c @@ -0,0 +1,93 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include + +struct proxy_client { + struct msm_bus_scale_pdata *pdata; + unsigned int client_handle; +}; + +static struct proxy_client proxy_client_info; + +static int msm_bus_device_proxy_client_probe(struct platform_device *pdev) +{ + int ret; + + proxy_client_info.pdata = msm_bus_cl_get_pdata(pdev); + + if (!proxy_client_info.pdata) + return 0; + + proxy_client_info.client_handle = + msm_bus_scale_register_client(proxy_client_info.pdata); + + if (!proxy_client_info.client_handle) { + dev_err(&pdev->dev, "Unable to register bus client\n"); + return -ENODEV; + } + + ret = msm_bus_scale_client_update_request( + proxy_client_info.client_handle, 1); + if (ret) + dev_err(&pdev->dev, "Bandwidth update failed (%d)\n", ret); + + return ret; +} + +static const struct of_device_id proxy_client_match[] = { + {.compatible = "qcom,bus-proxy-client"}, + {} +}; + +static struct platform_driver msm_bus_proxy_client_driver = { + .probe = msm_bus_device_proxy_client_probe, + .driver = { + .name = "msm_bus_proxy_client_device", + .owner = THIS_MODULE, + .of_match_table = proxy_client_match, + }, +}; + +static int __init msm_bus_proxy_client_init_driver(void) +{ + int rc; + + rc = platform_driver_register(&msm_bus_proxy_client_driver); + if (rc) { + pr_err("Failed to register proxy client device driver"); + return rc; + } + + return rc; +} + +static int __init msm_bus_proxy_client_unvote(void) +{ + int ret; + + if (!proxy_client_info.pdata || !proxy_client_info.client_handle) + return 0; + + ret = msm_bus_scale_client_update_request( + proxy_client_info.client_handle, 0); + if (ret) + pr_err("%s: bandwidth update request failed (%d)\n", + __func__, ret); + + msm_bus_scale_unregister_client(proxy_client_info.client_handle); + + return 0; +} + +subsys_initcall_sync(msm_bus_proxy_client_init_driver); +late_initcall_sync(msm_bus_proxy_client_unvote); -- GitLab From 6b7b9e7814e0ae928399cf04864c83160d20a2d0 Mon Sep 17 00:00:00 2001 From: Aravind Venkateswaran Date: Tue, 8 May 2018 15:36:49 -0700 Subject: [PATCH 1465/1635] drm/msm/dsi-staging: fix default value for DSI clockout control DSI clockout control setting for t-clk-pre and t-clk-post is an optional parameter for certain chip versions. When these bindings are not specified, current implementation has default values which may result in incorrect settings. Fix this by setting the default value to 0x00. Change-Id: Iecbc4f2d6311263c7dac4af40f72cf746e48cb86 Signed-off-by: Aravind Venkateswaran --- .../devicetree/bindings/drm/msm/mdss-dsi-panel.txt | 4 ++-- drivers/gpu/drm/msm/dsi-staging/dsi_panel.c | 10 ++-------- 2 files changed, 4 insertions(+), 10 deletions(-) diff --git a/Documentation/devicetree/bindings/drm/msm/mdss-dsi-panel.txt b/Documentation/devicetree/bindings/drm/msm/mdss-dsi-panel.txt index 152146613a7e..a9b05550c7c4 100644 --- a/Documentation/devicetree/bindings/drm/msm/mdss-dsi-panel.txt +++ b/Documentation/devicetree/bindings/drm/msm/mdss-dsi-panel.txt @@ -241,9 +241,9 @@ Optional properties: - qcom,mdss-dsi-lane-2-state: Boolean that specifies whether data lane 2 is enabled. - qcom,mdss-dsi-lane-3-state: Boolean that specifies whether data lane 3 is enabled. - qcom,mdss-dsi-t-clk-post: Specifies the byte clock cycles after mode switch. - 0x03 = default value. + 0x00 = default value. - qcom,mdss-dsi-t-clk-pre: Specifies the byte clock cycles before mode switch. - 0x24 = default value. + 0x00 = default value. - qcom,mdss-dsi-stream: Specifies the packet stream to be used. 0 = stream 0 (default) 1 = stream 1 diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c b/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c index 4705d7d96830..58e8782ce966 100644 --- a/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c +++ b/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c @@ -984,20 +984,14 @@ static int dsi_panel_parse_misc_host_config(struct dsi_host_common_cfg *host, int rc = 0; rc = utils->read_u32(utils->data, "qcom,mdss-dsi-t-clk-post", &val); - if (rc) { - pr_debug("[%s] Fallback to default t_clk_post value\n", name); - host->t_clk_post = 0x03; - } else { + if (!rc) { host->t_clk_post = val; pr_debug("[%s] t_clk_post = %d\n", name, val); } val = 0; rc = utils->read_u32(utils->data, "qcom,mdss-dsi-t-clk-pre", &val); - if (rc) { - pr_debug("[%s] Fallback to default t_clk_pre value\n", name); - host->t_clk_pre = 0x24; - } else { + if (!rc) { host->t_clk_pre = val; pr_debug("[%s] t_clk_pre = %d\n", name, val); } -- GitLab From 2eec26e7fb3c8392639cd08350a5f8c0aa582c40 Mon Sep 17 00:00:00 2001 From: Subbaraman Narayanamurthy Date: Tue, 8 May 2018 15:45:14 -0700 Subject: [PATCH 1466/1635] power: qpnp-fg-gen4: Fix using uninitialized mutex lock Initialize the mutex lock used for TTF calculation before using it. Change-Id: I938f7aa903e45020bcd2cab2e2eaf6df35ca53b7 Signed-off-by: Subbaraman Narayanamurthy --- drivers/power/supply/qcom/qpnp-fg-gen4.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/power/supply/qcom/qpnp-fg-gen4.c b/drivers/power/supply/qcom/qpnp-fg-gen4.c index 3d5a3e666902..8b066a630dac 100644 --- a/drivers/power/supply/qcom/qpnp-fg-gen4.c +++ b/drivers/power/supply/qcom/qpnp-fg-gen4.c @@ -3143,6 +3143,7 @@ static int fg_gen4_probe(struct platform_device *pdev) mutex_init(&fg->bus_lock); mutex_init(&fg->sram_rw_lock); mutex_init(&fg->charge_full_lock); + mutex_init(&chip->ttf.lock); init_completion(&fg->soc_update); init_completion(&fg->soc_ready); INIT_WORK(&fg->status_change_work, status_change_work); -- GitLab From 2ddc5804da3328123366fdd8ef0ec8d7d4be49f0 Mon Sep 17 00:00:00 2001 From: Aravind Venkateswaran Date: Tue, 8 May 2018 15:41:29 -0700 Subject: [PATCH 1467/1635] ARM: dts: msm: remove unused DSI PHY timing setting for SM8150 The DSI PHY clockout timing parameters are not configured using the t-clk-pre and t-clk-post parameters for SM8150. Remove these bindings from all supported displays on SM8150. Change-Id: I8ee1c665ea845b9a6cdc4acf89309960445c98ff Signed-off-by: Aravind Venkateswaran --- .../boot/dts/qcom/sm8150-sde-display.dtsi | 34 ------------------- 1 file changed, 34 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sm8150-sde-display.dtsi b/arch/arm64/boot/dts/qcom/sm8150-sde-display.dtsi index a2c397c7eb0d..c65f88d0fec3 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-sde-display.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-sde-display.dtsi @@ -399,8 +399,6 @@ /* PHY TIMINGS REVISION P */ &dsi_dual_nt35597_truly_video { - qcom,mdss-dsi-t-clk-post = <0x17>; - qcom,mdss-dsi-t-clk-pre = <0x18>; qcom,mdss-dsi-display-timings { timing@0{ qcom,mdss-dsi-panel-phy-timings = [00 1c 08 07 23 22 07 @@ -413,8 +411,6 @@ }; &dsi_dual_nt35597_truly_cmd { - qcom,mdss-dsi-t-clk-post = <0x17>; - qcom,mdss-dsi-t-clk-pre = <0x18>; qcom,mdss-dsi-display-timings { timing@0{ qcom,mdss-dsi-panel-phy-timings = [00 1c 08 07 23 22 07 @@ -427,8 +423,6 @@ }; &dsi_nt35597_truly_dsc_cmd { - qcom,mdss-dsi-t-clk-post = <0x15>; - qcom,mdss-dsi-t-clk-pre = <0x12>; qcom,mdss-dsi-display-timings { timing@0{ qcom,mdss-dsi-panel-phy-timings = [00 15 05 05 20 1f 05 @@ -442,8 +436,6 @@ }; &dsi_nt35597_truly_dsc_video { - qcom,mdss-dsi-t-clk-post = <0x15>; - qcom,mdss-dsi-t-clk-pre = <0x12>; qcom,mdss-dsi-display-timings { timing@0{ qcom,mdss-dsi-panel-phy-timings = [00 15 05 05 20 1f 05 @@ -457,8 +449,6 @@ }; &dsi_sharp_4k_dsc_video { - qcom,mdss-dsi-t-clk-post = <0x18>; - qcom,mdss-dsi-t-clk-pre = <0x19>; qcom,mdss-dsi-display-timings { timing@0{ qcom,mdss-dsi-panel-phy-timings = [00 1e 08 07 24 22 08 @@ -470,8 +460,6 @@ }; &dsi_sharp_4k_dsc_cmd { - qcom,mdss-dsi-t-clk-post = <0x18>; - qcom,mdss-dsi-t-clk-pre = <0x19>; qcom,mdss-dsi-display-timings { timing@0{ qcom,mdss-dsi-panel-phy-timings = [00 1e 08 07 24 22 08 @@ -483,8 +471,6 @@ }; &dsi_nt35695b_truly_fhd_video { - qcom,mdss-dsi-t-clk-post = <0x17>; - qcom,mdss-dsi-t-clk-pre = <0x19>; qcom,mdss-dsi-display-timings { timing@0 { qcom,mdss-dsi-panel-phy-timings = [00 1e 08 07 24 22 @@ -496,8 +482,6 @@ }; &dsi_nt35695b_truly_fhd_cmd { - qcom,mdss-dsi-t-clk-post = <0x17>; - qcom,mdss-dsi-t-clk-pre = <0x19>; qcom,mdss-dsi-display-timings { timing@0 { qcom,mdss-dsi-panel-phy-timings = [00 1e 08 07 24 22 @@ -509,8 +493,6 @@ }; &dsi_dual_sharp_1080_120hz_cmd { - qcom,mdss-dsi-t-clk-post = <0x0f>; - qcom,mdss-dsi-t-clk-pre = <0x36>; qcom,mdss-dsi-display-timings { timing@0{ qcom,mdss-dsi-panel-phy-timings = [00 24 09 09 26 24 09 @@ -523,8 +505,6 @@ }; &dsi_sharp_1080_cmd { - qcom,mdss-dsi-t-clk-post = <0x0c>; - qcom,mdss-dsi-t-clk-pre = <0x29>; qcom,mdss-dsi-display-timings { timing@0{ qcom,mdss-dsi-panel-phy-timings = [00 1A 06 06 22 20 07 @@ -536,8 +516,6 @@ }; &dsi_sim_vid { - qcom,mdss-dsi-t-clk-post = <0x15>; - qcom,mdss-dsi-t-clk-pre = <0x12>; qcom,mdss-dsi-display-timings { timing@0{ qcom,mdss-dsi-panel-phy-timings = [00 1c 08 07 23 22 07 @@ -550,8 +528,6 @@ }; &dsi_dual_sim_vid { - qcom,mdss-dsi-t-clk-post = <0x15>; - qcom,mdss-dsi-t-clk-pre = <0x12>; qcom,mdss-dsi-display-timings { timing@0{ qcom,mdss-dsi-panel-phy-timings = [00 1c 08 07 23 22 07 @@ -564,8 +540,6 @@ }; &dsi_sim_cmd { - qcom,mdss-dsi-t-clk-post = <0x15>; - qcom,mdss-dsi-t-clk-pre = <0x12>; qcom,mdss-dsi-display-timings { timing@0{ qcom,mdss-dsi-panel-phy-timings = [00 1c 08 07 23 22 07 @@ -578,8 +552,6 @@ }; &dsi_dual_sim_cmd { - qcom,mdss-dsi-t-clk-post = <0x15>; - qcom,mdss-dsi-t-clk-pre = <0x12>; qcom,mdss-dsi-display-timings { timing@0{ qcom,mdss-dsi-panel-phy-timings = [00 24 09 09 26 24 09 @@ -604,8 +576,6 @@ }; &dsi_sim_dsc_375_cmd { - qcom,mdss-dsi-t-clk-post = <0x0d>; - qcom,mdss-dsi-t-clk-pre = <0x2d>; qcom,mdss-dsi-display-timings { timing@0 { /* 1080p */ qcom,mdss-dsi-panel-phy-timings = [00 1A 06 06 22 20 07 @@ -625,8 +595,6 @@ }; &dsi_dual_sim_dsc_375_cmd { - qcom,mdss-dsi-t-clk-post = <0x0d>; - qcom,mdss-dsi-t-clk-pre = <0x2d>; qcom,mdss-dsi-display-timings { timing@0 { /* qhd */ qcom,mdss-dsi-panel-phy-timings = [00 1c 08 07 23 22 07 @@ -644,8 +612,6 @@ }; &dsi_sw43404_amoled_cmd { - qcom,mdss-dsi-t-clk-post = <0x16>; - qcom,mdss-dsi-t-clk-pre = <0x16>; qcom,mdss-dsi-display-timings { timing@0 { qcom,mdss-dsi-panel-phy-timings = [00 1a 07 06 22 21 07 -- GitLab From 5ee46e93e6d9eb3f9ccf699809d5a4bfd55e21aa Mon Sep 17 00:00:00 2001 From: Skylar Chang Date: Mon, 7 May 2018 17:50:24 -0700 Subject: [PATCH 1468/1635] msm: ipa4: enable adpl for msmnile HPS_REP_SEQ_TYPE needs to be set to 8 for all UL consumer pipes which require ADPL support. Otherwise ADPL packets will contain payload even when partial header is selected. Change-Id: I67f3ab7bf6aba19b99db54d4d29078a674496022 Signed-off-by: Skylar Chang --- drivers/platform/msm/ipa/ipa_v3/ipa_utils.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c index e4576eae7f63..609be4fa595e 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c @@ -1509,13 +1509,13 @@ static const struct ipa_ep_configuration ipa3_ep_mapping [IPA_4_1][IPA_CLIENT_WLAN1_PROD] = { true, IPA_v4_0_GROUP_UL_DL, true, - IPA_DPS_HPS_SEQ_TYPE_2ND_PKT_PROCESS_PASS_NO_DEC_UCP, + IPA_DPS_HPS_REP_SEQ_TYPE_2PKT_PROC_PASS_NO_DEC_UCP_DMAP, QMB_MASTER_SELECT_DDR, { 6, 2, 8, 16, IPA_EE_UC } }, [IPA_4_1][IPA_CLIENT_USB_PROD] = { true, IPA_v4_0_GROUP_UL_DL, true, - IPA_DPS_HPS_SEQ_TYPE_2ND_PKT_PROCESS_PASS_NO_DEC_UCP, + IPA_DPS_HPS_REP_SEQ_TYPE_2PKT_PROC_PASS_NO_DEC_UCP_DMAP, QMB_MASTER_SELECT_DDR, { 0, 8, 8, 16, IPA_EE_AP } }, [IPA_4_1][IPA_CLIENT_APPS_LAN_PROD] = { @@ -1527,7 +1527,7 @@ static const struct ipa_ep_configuration ipa3_ep_mapping [IPA_4_1][IPA_CLIENT_APPS_WAN_PROD] = { true, IPA_v4_0_GROUP_UL_DL, true, - IPA_DPS_HPS_SEQ_TYPE_2ND_PKT_PROCESS_PASS_NO_DEC_UCP, + IPA_DPS_HPS_REP_SEQ_TYPE_2PKT_PROC_PASS_NO_DEC_UCP_DMAP, QMB_MASTER_SELECT_DDR, { 2, 3, 16, 32, IPA_EE_AP } }, [IPA_4_1][IPA_CLIENT_APPS_CMD_PROD] = { @@ -1539,13 +1539,13 @@ static const struct ipa_ep_configuration ipa3_ep_mapping [IPA_4_1][IPA_CLIENT_ODU_PROD] = { true, IPA_v4_0_GROUP_UL_DL, true, - IPA_DPS_HPS_SEQ_TYPE_2ND_PKT_PROCESS_PASS_NO_DEC_UCP, + IPA_DPS_HPS_REP_SEQ_TYPE_2PKT_PROC_PASS_NO_DEC_UCP_DMAP, QMB_MASTER_SELECT_DDR, { 1, 0, 8, 16, IPA_EE_AP } }, [IPA_4_1][IPA_CLIENT_ETHERNET_PROD] = { true, IPA_v4_0_GROUP_UL_DL, true, - IPA_DPS_HPS_SEQ_TYPE_2ND_PKT_PROCESS_PASS_NO_DEC_UCP, + IPA_DPS_HPS_REP_SEQ_TYPE_2PKT_PROC_PASS_NO_DEC_UCP_DMAP, QMB_MASTER_SELECT_DDR, { 9, 0, 8, 16, IPA_EE_UC } }, [IPA_4_1][IPA_CLIENT_Q6_WAN_PROD] = { -- GitLab From 063b276c2822c60d44ed11b929dde386704f75ef Mon Sep 17 00:00:00 2001 From: David Dai Date: Thu, 26 Apr 2018 18:15:21 -0700 Subject: [PATCH 1469/1635] ARM: dts: msm: Add proxy init client for MM config slaves for sm8150 Due to the GDSCs now voting for slave config bandwidth, they can potentially disconnect the multimedia configuration slaves from CNOC preventing multimedia clock drivers from accessing their clock controller register space. Keep a proxy vote to these config slaves so that disconnect does not happen during probe. Change-Id: I156f33aa7b809360aae6022f92d6ec071bcaf96a Signed-off-by: David Dai --- arch/arm64/boot/dts/qcom/sm8150.dtsi | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sm8150.dtsi b/arch/arm64/boot/dts/qcom/sm8150.dtsi index aad8b8c85143..249cb4b6779a 100644 --- a/arch/arm64/boot/dts/qcom/sm8150.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150.dtsi @@ -1296,6 +1296,21 @@ clock-frequency = <32768>; }; + bus_proxy_client: qcom,bus_proxy_client { + compatible = "qcom,bus-proxy-client"; + qcom,msm-bus,name = "bus-proxy-client"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <3>; + qcom,msm-bus,vectors-KBps = + , + , + , + , + , + ; + status = "ok"; + }; + keepalive_opp_table: keepalive-opp-table { compatible = "operating-points-v2"; opp-1 { -- GitLab From da43a7117a0baacfe815c34606c8fa3eb2d7782e Mon Sep 17 00:00:00 2001 From: "Bao D. Nguyen" Date: Tue, 8 May 2018 16:01:42 -0700 Subject: [PATCH 1470/1635] scsi: ufs: Set VS_CORE_CLK with values queried from DT/Clk Driver Setting the DME_VS_CORE_CLK_CTRL using the Unipro clock frequencies queried from the Device Tree and the clock driver instead of using hardcoded values in the UFS driver. Change-Id: Id39ee17a149ab0f7581931ac4152756f2ee60de2 Signed-off-by: Bao D. Nguyen --- drivers/scsi/ufs/ufs-qcom.c | 54 ++++++++++++++++++++++++++++--------- 1 file changed, 42 insertions(+), 12 deletions(-) diff --git a/drivers/scsi/ufs/ufs-qcom.c b/drivers/scsi/ufs/ufs-qcom.c index 0fc6602bce11..841f01104ba8 100644 --- a/drivers/scsi/ufs/ufs-qcom.c +++ b/drivers/scsi/ufs/ufs-qcom.c @@ -2325,6 +2325,9 @@ static int ufs_qcom_clk_scale_up_pre_change(struct ufs_hba *hba) struct ufs_qcom_host *host = ufshcd_get_variant(hba); struct ufs_pa_layer_attr *attr = &host->dev_req_params; int err = 0; + struct ufs_clk_info *clki; + struct list_head *head = &hba->clk_list_head; + u32 max_freq = 0; if (!ufs_qcom_cap_qunipro(host)) goto out; @@ -2333,8 +2336,25 @@ static int ufs_qcom_clk_scale_up_pre_change(struct ufs_hba *hba) __ufs_qcom_cfg_timers(hba, attr->gear_rx, attr->pwr_rx, attr->hs_rate, false, true); - /* set unipro core clock cycles to 150 and clear clock divider */ - err = ufs_qcom_set_dme_vs_core_clk_ctrl_clear_div(hba, 150, 6); + list_for_each_entry(clki, head, list) { + if (!IS_ERR_OR_NULL(clki->clk) && + (!strcmp(clki->name, "core_clk_unipro"))) { + max_freq = clki->max_freq; + break; + } + } + + switch (max_freq) { + case 300000000: + err = ufs_qcom_set_dme_vs_core_clk_ctrl_clear_div(hba, 300, 12); + break; + case 150000000: + err = ufs_qcom_set_dme_vs_core_clk_ctrl_clear_div(hba, 150, 6); + break; + default: + err = -EINVAL; + break; + } out: return err; } @@ -2344,6 +2364,9 @@ static int ufs_qcom_clk_scale_down_post_change(struct ufs_hba *hba) struct ufs_qcom_host *host = ufshcd_get_variant(hba); struct ufs_pa_layer_attr *attr = &host->dev_req_params; int err = 0; + struct ufs_clk_info *clki; + struct list_head *head = &hba->clk_list_head; + u32 curr_freq = 0; if (!ufs_qcom_cap_qunipro(host)) return 0; @@ -2352,18 +2375,25 @@ static int ufs_qcom_clk_scale_down_post_change(struct ufs_hba *hba) ufs_qcom_cfg_timers(hba, attr->gear_rx, attr->pwr_rx, attr->hs_rate, false); - if (ufs_qcom_cap_svs2(host)) - /* - * For SVS2 set unipro core clock cycles to 38 and - * clear clock divider - */ + list_for_each_entry(clki, head, list) { + if (!IS_ERR_OR_NULL(clki->clk) && + (!strcmp(clki->name, "core_clk_unipro"))) { + curr_freq = clk_get_rate(clki->clk); + break; + } + } + + switch (curr_freq) { + case 37500000: err = ufs_qcom_set_dme_vs_core_clk_ctrl_clear_div(hba, 38, 2); - else - /* - * For SVS set unipro core clock cycles to 75 and - * clear clock divider - */ + break; + case 75000000: err = ufs_qcom_set_dme_vs_core_clk_ctrl_clear_div(hba, 75, 3); + break; + default: + err = -EINVAL; + break; + } return err; } -- GitLab From 2020fc0ce1a37f9080f7faeefe8988e91767d5d9 Mon Sep 17 00:00:00 2001 From: "Bao D. Nguyen" Date: Tue, 8 May 2018 16:23:47 -0700 Subject: [PATCH 1471/1635] ARM: dts: msm: Update Supported UFS Clock Frequencies for SM8150 Updated the supported GCC_UFS_PHY_AXI_CLK and GCC_UFS_PHY_UNIPRO_CORE_CLK clock frequencies for the SM8150. Change-Id: I27faab83e3355a7fd16013ef333d33f028509d92 Signed-off-by: Bao D. Nguyen --- arch/arm64/boot/dts/qcom/sm8150.dtsi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sm8150.dtsi b/arch/arm64/boot/dts/qcom/sm8150.dtsi index aad8b8c85143..d0639715eba9 100644 --- a/arch/arm64/boot/dts/qcom/sm8150.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150.dtsi @@ -2072,10 +2072,10 @@ <&clock_gcc GCC_UFS_PHY_RX_SYMBOL_0_CLK>, <&clock_gcc GCC_UFS_PHY_RX_SYMBOL_1_CLK>; freq-table-hz = - <50000000 200000000>, + <37500000 300000000>, <0 0>, <0 0>, - <37500000 150000000>, + <37500000 300000000>, <75000000 300000000>, <0 0>, <0 0>, -- GitLab From 0d46746a1b79fc3ec685cd38e3631c692b65e5cd Mon Sep 17 00:00:00 2001 From: David Collins Date: Tue, 24 Apr 2018 18:41:57 -0700 Subject: [PATCH 1472/1635] clk: qcom: gdsc-regulator: add support to manage bus bandwidth requests Add support to vote for bus bandwidth in GDSC regulator callback functions. This is needed for GDSC instances which access registers via a bus that can be disconnected. Change-Id: I8dff3d42eeed67230c81418ea9be88e81bdb44ce Signed-off-by: David Collins --- .../bindings/regulator/gdsc-regulator.txt | 11 ++ drivers/clk/qcom/gdsc-regulator.c | 162 ++++++++++++++++-- 2 files changed, 158 insertions(+), 15 deletions(-) diff --git a/Documentation/devicetree/bindings/regulator/gdsc-regulator.txt b/Documentation/devicetree/bindings/regulator/gdsc-regulator.txt index 19a9d35978c6..5c93e5666634 100644 --- a/Documentation/devicetree/bindings/regulator/gdsc-regulator.txt +++ b/Documentation/devicetree/bindings/regulator/gdsc-regulator.txt @@ -61,6 +61,17 @@ Optional properties: - reset-names: reset signal name strings sorted in the same order as the resets property. These can be supplied only if we support qcom,skip-logic-collapse. + - qcom,msm-bus,name: Name to use for the bus client. See [1] for details. + - qcom,msm-bus,num-cases: Must be 2 if qcom,msm-bus,name is specified. The + first case corresponds to no bus request and the second + case corresponds to a minimum bus request. See [1] for + details. + - qcom,msm-bus,num-paths: Should be 1 if qcom,msm-bus,name is specified. See + [1] for details. + - qcom,msm-bus,vectors-KBps: Required if qcom,msm-bus,name is specified. See + [1] for an explanation of the data format. + +[1]: Documentation/devicetree/bindings/arm/msm/msm_bus.txt Example: gdsc_oxili_gx: qcom,gdsc@fd8c4024 { diff --git a/drivers/clk/qcom/gdsc-regulator.c b/drivers/clk/qcom/gdsc-regulator.c index 1027452246c4..714ceead73f4 100644 --- a/drivers/clk/qcom/gdsc-regulator.c +++ b/drivers/clk/qcom/gdsc-regulator.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -62,6 +63,8 @@ struct gdsc { struct clk **clocks; struct regulator *parent_regulator; struct reset_control **reset_clocks; + struct msm_bus_scale_pdata *bus_pdata; + u32 bus_handle; bool toggle_mem; bool toggle_periph; bool toggle_logic; @@ -72,6 +75,7 @@ struct gdsc { bool is_gdsc_enabled; bool allow_clear; bool reset_aon; + bool is_bus_enabled; int clock_count; int reset_count; int root_clk_idx; @@ -143,6 +147,8 @@ static int gdsc_is_enabled(struct regulator_dev *rdev) { struct gdsc *sc = rdev_get_drvdata(rdev); uint32_t regval; + int ret; + bool is_enabled = false; if (!sc->toggle_logic) return !sc->resets_asserted; @@ -171,6 +177,15 @@ static int gdsc_is_enabled(struct regulator_dev *rdev) } } + if (sc->bus_handle && !sc->is_bus_enabled) { + ret = msm_bus_scale_client_update_request(sc->bus_handle, 1); + if (ret) { + dev_err(&rdev->dev, "bus scaling failed, ret=%d\n", + ret); + goto end; + } + } + regmap_read(sc->regmap, REG_OFFSET, ®val); if (regval & PWR_ON_MASK) { @@ -179,21 +194,20 @@ static int gdsc_is_enabled(struct regulator_dev *rdev) * votable GDS registers. Check the SW_COLLAPSE_MASK to * determine if HLOS has voted for it. */ - if (!(regval & SW_COLLAPSE_MASK)) { - if (sc->parent_regulator) { - regulator_disable(sc->parent_regulator); - regulator_set_voltage(sc->parent_regulator, 0, - INT_MAX); - } - return true; - } + if (!(regval & SW_COLLAPSE_MASK)) + is_enabled = true; } + + if (sc->bus_handle && !sc->is_bus_enabled) + msm_bus_scale_client_update_request(sc->bus_handle, 0); +end: if (sc->parent_regulator) { regulator_disable(sc->parent_regulator); regulator_set_voltage(sc->parent_regulator, 0, INT_MAX); } - return false; + + return is_enabled; } static int gdsc_enable(struct regulator_dev *rdev) @@ -213,6 +227,16 @@ static int gdsc_enable(struct regulator_dev *rdev) } } + if (sc->bus_handle) { + ret = msm_bus_scale_client_update_request(sc->bus_handle, 1); + if (ret) { + dev_err(&rdev->dev, "bus scaling failed, ret=%d\n", + ret); + goto end; + } + sc->is_bus_enabled = true; + } + if (sc->root_en || sc->force_root_en) clk_prepare_enable(sc->clocks[sc->root_clk_idx]); @@ -350,6 +374,10 @@ static int gdsc_enable(struct regulator_dev *rdev) sc->is_gdsc_enabled = true; end: + if (ret && sc->bus_handle) { + msm_bus_scale_client_update_request(sc->bus_handle, 0); + sc->is_bus_enabled = false; + } if (sc->parent_regulator) regulator_set_voltage(sc->parent_regulator, 0, INT_MAX); @@ -432,6 +460,14 @@ static int gdsc_disable(struct regulator_dev *rdev) if ((sc->is_gdsc_enabled && sc->root_en) || sc->force_root_en) clk_disable_unprepare(sc->clocks[sc->root_clk_idx]); + if (sc->bus_handle) { + ret = msm_bus_scale_client_update_request(sc->bus_handle, 0); + if (ret) + dev_err(&rdev->dev, "bus scaling failed, ret=%d\n", + ret); + sc->is_bus_enabled = false; + } + if (sc->parent_regulator) regulator_set_voltage(sc->parent_regulator, 0, INT_MAX); @@ -466,8 +502,26 @@ static unsigned int gdsc_get_mode(struct regulator_dev *rdev) } } + if (sc->bus_handle && !sc->is_bus_enabled) { + ret = msm_bus_scale_client_update_request(sc->bus_handle, 1); + if (ret) { + dev_err(&rdev->dev, "bus scaling failed, ret=%d\n", + ret); + if (sc->parent_regulator) { + regulator_disable(sc->parent_regulator); + regulator_set_voltage(sc->parent_regulator, 0, + INT_MAX); + } + mutex_unlock(&gdsc_seq_lock); + return ret; + } + } + regmap_read(sc->regmap, REG_OFFSET, ®val); + if (sc->bus_handle && !sc->is_bus_enabled) + msm_bus_scale_client_update_request(sc->bus_handle, 0); + if (sc->parent_regulator) { regulator_disable(sc->parent_regulator); regulator_set_voltage(sc->parent_regulator, 0, INT_MAX); @@ -505,6 +559,21 @@ static int gdsc_set_mode(struct regulator_dev *rdev, unsigned int mode) } } + if (sc->bus_handle && !sc->is_bus_enabled) { + ret = msm_bus_scale_client_update_request(sc->bus_handle, 1); + if (ret) { + dev_err(&rdev->dev, "bus scaling failed, ret=%d\n", + ret); + if (sc->parent_regulator) { + regulator_disable(sc->parent_regulator); + regulator_set_voltage(sc->parent_regulator, 0, + INT_MAX); + } + mutex_unlock(&gdsc_seq_lock); + return ret; + } + } + regmap_read(sc->regmap, REG_OFFSET, ®val); switch (mode) { @@ -548,6 +617,9 @@ static int gdsc_set_mode(struct regulator_dev *rdev, unsigned int mode) break; } + if (sc->bus_handle && !sc->is_bus_enabled) + msm_bus_scale_client_update_request(sc->bus_handle, 0); + if (sc->parent_regulator) { regulator_disable(sc->parent_regulator); regulator_set_voltage(sc->parent_regulator, 0, INT_MAX); @@ -710,6 +782,34 @@ static int gdsc_probe(struct platform_device *pdev) sc->reset_aon = of_property_read_bool(pdev->dev.of_node, "qcom,reset-aon-logic"); + if (of_find_property(pdev->dev.of_node, "qcom,msm-bus,name", NULL)) { + sc->bus_pdata = msm_bus_cl_get_pdata(pdev); + if (!sc->bus_pdata) { + dev_err(&pdev->dev, "Failed to get bus config data\n"); + return -EINVAL; + } + + sc->bus_handle = msm_bus_scale_register_client(sc->bus_pdata); + if (!sc->bus_handle) { + dev_err(&pdev->dev, "Failed to register bus client\n"); + /* + * msm_bus_scale_register_client() returns 0 for all + * errors including when called before the bus driver + * probes. Therefore, return -EPROBE_DEFER here so that + * probing can be retried and this case handled. + */ + return -EPROBE_DEFER; + } + + ret = msm_bus_scale_client_update_request(sc->bus_handle, 1); + if (ret) { + dev_err(&pdev->dev, "bus scaling failed, ret=%d\n", + ret); + goto err; + } + sc->is_bus_enabled = true; + } + sc->rdesc.id = atomic_inc_return(&gdsc_count); sc->rdesc.ops = &gdsc_ops; sc->rdesc.type = REGULATOR_VOLTAGE; @@ -760,14 +860,17 @@ static int gdsc_probe(struct platform_device *pdev) sc->reset_count = 0; } else if (sc->reset_count < 0) { dev_err(&pdev->dev, "Failed to get reset clock names\n"); - return -EINVAL; + ret = -EINVAL; + goto err; } sc->reset_clocks = devm_kzalloc(&pdev->dev, sizeof(struct reset_control *) * sc->reset_count, GFP_KERNEL); - if (!sc->reset_clocks) - return -ENOMEM; + if (!sc->reset_clocks) { + ret = -ENOMEM; + goto err; + } for (i = 0; i < sc->reset_count; i++) { const char *reset_name; @@ -782,7 +885,8 @@ static int gdsc_probe(struct platform_device *pdev) if (rc != -EPROBE_DEFER) dev_err(&pdev->dev, "Failed to get %s\n", reset_name); - return rc; + ret = rc; + goto err; } } @@ -793,7 +897,19 @@ static int gdsc_probe(struct platform_device *pdev) if (ret) { dev_err(&pdev->dev, "%s enable timed out: 0x%x\n", sc->rdesc.name, regval); - return ret; + goto err; + } + } + + if (sc->bus_handle) { + regmap_read(sc->regmap, REG_OFFSET, ®val); + if (!(regval & PWR_ON_MASK) || (regval & SW_COLLAPSE_MASK)) { + /* + * Software is not enabling the GDSC so remove the + * bus vote. + */ + msm_bus_scale_client_update_request(sc->bus_handle, 0); + sc->is_bus_enabled = false; } } @@ -823,10 +939,20 @@ static int gdsc_probe(struct platform_device *pdev) if (IS_ERR(sc->rdev)) { dev_err(&pdev->dev, "regulator_register(\"%s\") failed.\n", sc->rdesc.name); - return PTR_ERR(sc->rdev); + ret = PTR_ERR(sc->rdev); + goto err; } return 0; + +err: + if (sc->bus_handle) { + if (sc->is_bus_enabled) + msm_bus_scale_client_update_request(sc->bus_handle, 0); + msm_bus_scale_unregister_client(sc->bus_handle); + } + + return ret; } static int gdsc_remove(struct platform_device *pdev) @@ -835,6 +961,12 @@ static int gdsc_remove(struct platform_device *pdev) regulator_unregister(sc->rdev); + if (sc->bus_handle) { + if (sc->is_bus_enabled) + msm_bus_scale_client_update_request(sc->bus_handle, 0); + msm_bus_scale_unregister_client(sc->bus_handle); + } + return 0; } -- GitLab From 995e280f93e75f58a62994eb335af64e9d29f9ad Mon Sep 17 00:00:00 2001 From: David Collins Date: Wed, 25 Apr 2018 15:27:13 -0700 Subject: [PATCH 1473/1635] ARM: dts: msm: add AHB bus configurations for SM8150 multimedia GDSCs The AHB bus must be enabled in order to access the control register of multimedia GDSCs. Add bus configurations for all multimedia GDSCs so that the slave is connected to the config NOC before any GDSC register accesses. Change-Id: Ic32286cfb34f8a4c824f938e23efc091eff13ca4 Signed-off-by: David Collins --- arch/arm64/boot/dts/qcom/sm8150.dtsi | 60 ++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sm8150.dtsi b/arch/arm64/boot/dts/qcom/sm8150.dtsi index 249cb4b6779a..7cb3ca84e9fd 100644 --- a/arch/arm64/boot/dts/qcom/sm8150.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150.dtsi @@ -3497,6 +3497,12 @@ clocks = <&clock_gcc GCC_CAMERA_AHB_CLK>; parent-supply = <&VDD_MMCX_LEVEL>; vdd_parent-supply = <&VDD_MMCX_LEVEL>; + qcom,msm-bus,name = "bps_gdsc_ahb"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + ; status = "ok"; }; @@ -3505,6 +3511,12 @@ clocks = <&clock_gcc GCC_CAMERA_AHB_CLK>; parent-supply = <&VDD_MMCX_LEVEL>; vdd_parent-supply = <&VDD_MMCX_LEVEL>; + qcom,msm-bus,name = "ipe_0_gdsc_ahb"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + ; status = "ok"; }; @@ -3513,6 +3525,12 @@ clocks = <&clock_gcc GCC_CAMERA_AHB_CLK>; parent-supply = <&VDD_MMCX_LEVEL>; vdd_parent-supply = <&VDD_MMCX_LEVEL>; + qcom,msm-bus,name = "ipe_1_gdsc_ahb"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + ; status = "ok"; }; @@ -3521,6 +3539,12 @@ clocks = <&clock_gcc GCC_CAMERA_AHB_CLK>; parent-supply = <&VDD_MMCX_LEVEL>; vdd_parent-supply = <&VDD_MMCX_LEVEL>; + qcom,msm-bus,name = "ife_0_gdsc_ahb"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + ; status = "ok"; }; @@ -3529,6 +3553,12 @@ clocks = <&clock_gcc GCC_CAMERA_AHB_CLK>; parent-supply = <&VDD_MMCX_LEVEL>; vdd_parent-supply = <&VDD_MMCX_LEVEL>; + qcom,msm-bus,name = "ife_1_gdsc_ahb"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + ; status = "ok"; }; @@ -3537,6 +3567,12 @@ clocks = <&clock_gcc GCC_CAMERA_AHB_CLK>; parent-supply = <&VDD_MMCX_LEVEL>; vdd_parent-supply = <&VDD_MMCX_LEVEL>; + qcom,msm-bus,name = "titan_top_gdsc_ahb"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + ; status = "ok"; }; @@ -3545,6 +3581,12 @@ clocks = <&clock_gcc GCC_DISP_AHB_CLK>; parent-supply = <&VDD_MMCX_LEVEL>; vdd_parent-supply = <&VDD_MMCX_LEVEL>; + qcom,msm-bus,name = "mdss_core_gdsc_ahb"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + ; status = "ok"; }; @@ -3563,6 +3605,12 @@ clocks = <&clock_gcc GCC_VIDEO_AHB_CLK>; parent-supply = <&VDD_MMCX_LEVEL>; vdd_parent-supply = <&VDD_MMCX_LEVEL>; + qcom,msm-bus,name = "mvsc_gdsc_ahb"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + ; status = "ok"; }; @@ -3571,6 +3619,12 @@ clocks = <&clock_gcc GCC_VIDEO_AHB_CLK>; parent-supply = <&VDD_MMCX_LEVEL>; vdd_parent-supply = <&VDD_MMCX_LEVEL>; + qcom,msm-bus,name = "mvs0_gdsc_ahb"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + ; status = "ok"; }; @@ -3579,6 +3633,12 @@ clocks = <&clock_gcc GCC_VIDEO_AHB_CLK>; parent-supply = <&VDD_MMCX_LEVEL>; vdd_parent-supply = <&VDD_MMCX_LEVEL>; + qcom,msm-bus,name = "mvs1_gdsc_ahb"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + ; status = "ok"; }; -- GitLab From 2294dae773be8f5985522d9445cab92d8501df93 Mon Sep 17 00:00:00 2001 From: Sujeev Dias Date: Mon, 30 Apr 2018 17:46:16 -0700 Subject: [PATCH 1474/1635] mhi: core: add support to start channels automatically Add support to start MHI channels automatically after finishing mhi device probe. This helps to simplify clients's driver and remove duplicate code between multiple clients. CRs-Fixed: 2237688 Change-Id: Ie11d5f4327a9c8039d1caab5cb2b89cc19e59b82 Signed-off-by: Sujeev Dias --- Documentation/devicetree/bindings/bus/mhi.txt | 2 ++ drivers/bus/mhi/core/mhi_init.c | 12 +++++++++++- drivers/bus/mhi/core/mhi_internal.h | 2 ++ 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/bus/mhi.txt b/Documentation/devicetree/bindings/bus/mhi.txt index a05f756d2a5b..b74fe736a11c 100644 --- a/Documentation/devicetree/bindings/bus/mhi.txt +++ b/Documentation/devicetree/bindings/bus/mhi.txt @@ -57,6 +57,8 @@ Main node properties: BIT(3) : MHI bus driver pre-allocate buffer for this channel. If set, clients not allowed to queue buffers. Valid only for DL direction. + BIT(4) : MHI host driver to automatically start channels once + mhi device driver probe is complete. - mhi,chan-names Usage: required diff --git a/drivers/bus/mhi/core/mhi_init.c b/drivers/bus/mhi/core/mhi_init.c index 9cfa88fe0dfb..d50c802ee8a8 100644 --- a/drivers/bus/mhi/core/mhi_init.c +++ b/drivers/bus/mhi/core/mhi_init.c @@ -836,6 +836,7 @@ static int of_parse_ch_cfg(struct mhi_controller *mhi_cntrl, mhi_chan->db_cfg.reset_req = !!(bit_cfg & MHI_CH_CFG_BIT_DBMODE_RESET_CH); mhi_chan->pre_alloc = !!(bit_cfg & MHI_CH_CFG_BIT_PRE_ALLOC); + mhi_chan->auto_start = !!(bit_cfg & MHI_CH_CFG_BIT_AUTO_START); if (mhi_chan->pre_alloc && (mhi_chan->dir != DMA_FROM_DEVICE || @@ -1139,6 +1140,8 @@ static int mhi_driver_probe(struct device *dev) struct mhi_event *mhi_event; struct mhi_chan *ul_chan = mhi_dev->ul_chan; struct mhi_chan *dl_chan = mhi_dev->dl_chan; + bool auto_start = false; + int ret; if (ul_chan) { @@ -1151,6 +1154,7 @@ static int mhi_driver_probe(struct device *dev) ul_chan->xfer_cb = mhi_drv->ul_xfer_cb; mhi_dev->status_cb = mhi_drv->status_cb; + auto_start = ul_chan->auto_start; } if (dl_chan) { @@ -1174,9 +1178,15 @@ static int mhi_driver_probe(struct device *dev) /* ul & dl uses same status cb */ mhi_dev->status_cb = mhi_drv->status_cb; + auto_start = (auto_start || dl_chan->auto_start); } - return mhi_drv->probe(mhi_dev, mhi_dev->id); + ret = mhi_drv->probe(mhi_dev, mhi_dev->id); + + if (!ret && auto_start) + mhi_prepare_for_transfer(mhi_dev); + + return ret; } static int mhi_driver_remove(struct device *dev) diff --git a/drivers/bus/mhi/core/mhi_internal.h b/drivers/bus/mhi/core/mhi_internal.h index f35162baa2de..bd26ad6b257c 100644 --- a/drivers/bus/mhi/core/mhi_internal.h +++ b/drivers/bus/mhi/core/mhi_internal.h @@ -340,6 +340,7 @@ enum MHI_CH_CFG { #define MHI_CH_CFG_BIT_OFFLOAD_CH BIT(1) /* satellite mhi devices */ #define MHI_CH_CFG_BIT_DBMODE_RESET_CH BIT(2) /* require db mode to reset */ #define MHI_CH_CFG_BIT_PRE_ALLOC BIT(3) /* host allocate buffers for DL */ +#define MHI_CH_CFG_BIT_AUTO_START BIT(4) /* host auto start channels */ enum MHI_EV_CFG { MHI_EV_CFG_ELEMENTS = 0, @@ -567,6 +568,7 @@ struct mhi_chan { bool configured; bool offload_ch; bool pre_alloc; + bool auto_start; /* functions that generate the transfer ring elements */ int (*gen_tre)(struct mhi_controller *, struct mhi_chan *, void *, void *, size_t, enum MHI_FLAGS); -- GitLab From 61fc79fbbf2930b74472e975665de0f6478d94da Mon Sep 17 00:00:00 2001 From: Sujeev Dias Date: Thu, 12 Apr 2018 18:32:16 -0700 Subject: [PATCH 1475/1635] mhi: core: fix null pointer dereference during channel reset During MHI device destroy, MHI host does a channel reset. As part of channel reset, MHI device drivers requires access to mhi device pointer associated with current channel. Defer setting mhi device to null until channel reset is complete. CRs-Fixed: 2237717 Change-Id: Ic3fb99e17c01c305fb521cc9fe59e7a1da7cc592 Signed-off-by: Sujeev Dias --- drivers/bus/mhi/core/mhi_init.c | 3 +++ drivers/bus/mhi/core/mhi_main.c | 16 ---------------- 2 files changed, 3 insertions(+), 16 deletions(-) diff --git a/drivers/bus/mhi/core/mhi_init.c b/drivers/bus/mhi/core/mhi_init.c index d50c802ee8a8..b30143823631 100644 --- a/drivers/bus/mhi/core/mhi_init.c +++ b/drivers/bus/mhi/core/mhi_init.c @@ -1242,6 +1242,9 @@ static int mhi_driver_remove(struct device *dev) !mhi_chan->offload_ch) mhi_deinit_chan_ctxt(mhi_cntrl, mhi_chan); + /* remove associated device */ + mhi_chan->mhi_dev = NULL; + mutex_unlock(&mhi_chan->mutex); } diff --git a/drivers/bus/mhi/core/mhi_main.c b/drivers/bus/mhi/core/mhi_main.c index a678ce24a00f..4695fe7605eb 100644 --- a/drivers/bus/mhi/core/mhi_main.c +++ b/drivers/bus/mhi/core/mhi_main.c @@ -461,32 +461,16 @@ int mhi_queue_buf(struct mhi_device *mhi_dev, int mhi_destroy_device(struct device *dev, void *data) { struct mhi_device *mhi_dev; - struct mhi_driver *mhi_drv; struct mhi_controller *mhi_cntrl; - struct mhi_chan *mhi_chan; - int dir; if (dev->bus != &mhi_bus_type) return 0; mhi_dev = to_mhi_device(dev); - mhi_drv = to_mhi_driver(dev->driver); mhi_cntrl = mhi_dev->mhi_cntrl; MHI_LOG("destroy device for chan:%s\n", mhi_dev->chan_name); - for (dir = 0; dir < 2; dir++) { - mhi_chan = dir ? mhi_dev->ul_chan : mhi_dev->dl_chan; - - if (!mhi_chan) - continue; - - /* remove device associated with the channel */ - mutex_lock(&mhi_chan->mutex); - mhi_chan->mhi_dev = NULL; - mutex_unlock(&mhi_chan->mutex); - } - /* notify the client and remove the device from mhi bus */ device_del(dev); put_device(dev); -- GitLab From 79363022454db53c9e4add4f3aa2575eec569fdd Mon Sep 17 00:00:00 2001 From: Sujeev Dias Date: Wed, 2 May 2018 13:55:54 -0700 Subject: [PATCH 1476/1635] mhi: core: add a separate callback handler for downlink DTR channel As part of boot up sequence, some external modems transfer initial device settings to host due to legacy requirements. Since we cannot prevent this, silently accept the packets and discard it. CRs-Fixed: 2238249 Change-Id: I5d8be63fe54b86fa9d5cbf9a70288eab9f6f2fe4 Signed-off-by: Sujeev Dias --- drivers/bus/mhi/core/mhi_dtr.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/drivers/bus/mhi/core/mhi_dtr.c b/drivers/bus/mhi/core/mhi_dtr.c index bc1735937d37..a70ec2553ba0 100644 --- a/drivers/bus/mhi/core/mhi_dtr.c +++ b/drivers/bus/mhi/core/mhi_dtr.c @@ -119,8 +119,13 @@ long mhi_ioctl(struct mhi_device *mhi_dev, unsigned int cmd, unsigned long arg) } EXPORT_SYMBOL(mhi_ioctl); -static void mhi_dtr_xfer_cb(struct mhi_device *mhi_dev, - struct mhi_result *mhi_result) +static void mhi_dtr_dl_xfer_cb(struct mhi_device *mhi_dev, + struct mhi_result *mhi_result) +{ +} + +static void mhi_dtr_ul_xfer_cb(struct mhi_device *mhi_dev, + struct mhi_result *mhi_result) { struct mhi_controller *mhi_cntrl = mhi_dev->mhi_cntrl; struct mhi_chan *dtr_chan = mhi_cntrl->dtr_dev->ul_chan; @@ -163,8 +168,8 @@ static struct mhi_driver mhi_dtr_driver = { .id_table = mhi_dtr_table, .remove = mhi_dtr_remove, .probe = mhi_dtr_probe, - .ul_xfer_cb = mhi_dtr_xfer_cb, - .dl_xfer_cb = mhi_dtr_xfer_cb, + .ul_xfer_cb = mhi_dtr_ul_xfer_cb, + .dl_xfer_cb = mhi_dtr_dl_xfer_cb, .driver = { .name = "MHI_DTR", .owner = THIS_MODULE, -- GitLab From 620d46a7e1c2a4c97ba6a491580a05eac195cc4e Mon Sep 17 00:00:00 2001 From: "Bao D. Nguyen" Date: Tue, 8 May 2018 18:51:26 -0700 Subject: [PATCH 1477/1635] phy: qcom-ufs: Update UFS's PHY Calibration Sequence The setting of UFS_MEM_MPHY_UFS_QSERDES_COM_CMN_IPTRIM parameter is not required in the updated UFS PHY's Hardware Programming Guide. Remove it to follow the Hardware Programming Guide document. Change-Id: I2639905d203c84a42836fec7e92de3229a6117f3 Signed-off-by: Bao D. Nguyen --- drivers/phy/qualcomm/phy-qcom-ufs-qmp-v4.h | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/phy/qualcomm/phy-qcom-ufs-qmp-v4.h b/drivers/phy/qualcomm/phy-qcom-ufs-qmp-v4.h index a5eb4651037b..5d45115ed5f4 100644 --- a/drivers/phy/qualcomm/phy-qcom-ufs-qmp-v4.h +++ b/drivers/phy/qualcomm/phy-qcom-ufs-qmp-v4.h @@ -204,7 +204,6 @@ static struct ufs_qcom_phy_calibration phy_cal_table_rate_A[] = { UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLL_CCTRL_MODE1, 0x36), UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_LOCK_CMP1_MODE1, 0x32), UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_LOCK_CMP2_MODE1, 0x0F), - UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_CMN_IPTRIM, 0x20), UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_BIN_VCOCAL_CMP_CODE1_MODE1, 0xDD), UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_BIN_VCOCAL_CMP_CODE2_MODE1, 0x23), UFS_QCOM_PHY_CAL_ENTRY(QSERDES_TX0_PWM_GEAR_1_DIVIDER_BAND0_1, 0x06), -- GitLab From ff25c3b17479ae7101074f8b887e890eaa68a94e Mon Sep 17 00:00:00 2001 From: Hemant Kumar Date: Wed, 8 Mar 2017 19:05:14 -0800 Subject: [PATCH 1478/1635] usb: gadget: f_ncm: allocate/free net device upon driver bind/unbind Driver registers net device in bind but does not unregister it upon driver unbind. Upon composition switch ncm net device is no longer in use, hence unregister and free it in driver unbind. Unregistering net device sends notification to user space which can be used by user space entities to perform necessary actions for example updating UI. Symmetrically allocate and register net device in driver bind. Change-Id: Ie1bb781aba8efee20cc98c1d6bf264403c3b087e Signed-off-by: Hemant Kumar --- drivers/usb/gadget/function/f_ncm.c | 58 +++++++++++++++++------------ 1 file changed, 34 insertions(+), 24 deletions(-) diff --git a/drivers/usb/gadget/function/f_ncm.c b/drivers/usb/gadget/function/f_ncm.c index 239e211c5271..d0faf68a648c 100644 --- a/drivers/usb/gadget/function/f_ncm.c +++ b/drivers/usb/gadget/function/f_ncm.c @@ -1422,17 +1422,39 @@ static int ncm_bind(struct usb_configuration *c, struct usb_function *f) */ if (!ncm_opts->bound) { mutex_lock(&ncm_opts->lock); + ncm_opts->net = gether_setup_default(); + if (IS_ERR(ncm_opts->net)) { + status = PTR_ERR(ncm_opts->net); + mutex_unlock(&ncm_opts->lock); + goto error; + } gether_set_gadget(ncm_opts->net, cdev->gadget); status = gether_register_netdev(ncm_opts->net); mutex_unlock(&ncm_opts->lock); - if (status) - return status; + if (status) { + free_netdev(ncm_opts->net); + goto error; + } ncm_opts->bound = true; } + + /* export host's Ethernet address in CDC format */ + status = gether_get_host_addr_cdc(ncm_opts->net, ncm->ethaddr, + sizeof(ncm->ethaddr)); + if (status < 12) { /* strlen("01234567890a") */ + ERROR(cdev, "%s: failed to get host eth addr, err %d\n", + __func__, status); + status = -EINVAL; + goto netdev_cleanup; + } + ncm->port.ioport = netdev_priv(ncm_opts->net); + us = usb_gstrings_attach(cdev, ncm_strings, ARRAY_SIZE(ncm_string_defs)); - if (IS_ERR(us)) - return PTR_ERR(us); + if (IS_ERR(us)) { + status = PTR_ERR(us); + goto netdev_cleanup; + } ncm_control_intf.iInterface = us[STRING_CTRL_IDX].id; ncm_data_nop_intf.iInterface = us[STRING_DATA_IDX].id; ncm_data_intf.iInterface = us[STRING_DATA_IDX].id; @@ -1533,7 +1555,10 @@ static int ncm_bind(struct usb_configuration *c, struct usb_function *f) kfree(ncm->notify_req->buf); usb_ep_free_request(ncm->notify, ncm->notify_req); } +netdev_cleanup: + gether_cleanup(netdev_priv(ncm_opts->net)); +error: ERROR(cdev, "%s: can't bind, err %d\n", f->name, status); return status; @@ -1628,8 +1653,6 @@ static void ncm_free_inst(struct usb_function_instance *f) opts = container_of(f, struct f_ncm_opts, func_inst); if (opts->bound) gether_cleanup(netdev_priv(opts->net)); - else - free_netdev(opts->net); kfree(opts); } @@ -1642,12 +1665,6 @@ static struct usb_function_instance *ncm_alloc_inst(void) return ERR_PTR(-ENOMEM); mutex_init(&opts->lock); opts->func_inst.free_func_inst = ncm_free_inst; - opts->net = gether_setup_default(); - if (IS_ERR(opts->net)) { - struct net_device *net = opts->net; - kfree(opts); - return ERR_CAST(net); - } config_group_init_type_name(&opts->func_inst.group, "", &ncm_func_type); @@ -1678,6 +1695,8 @@ static void ncm_free(struct usb_function *f) static void ncm_unbind(struct usb_configuration *c, struct usb_function *f) { struct f_ncm *ncm = func_to_ncm(f); + struct f_ncm_opts *opts = container_of(f->fi, struct f_ncm_opts, + func_inst); DBG(c->cdev, "ncm unbind\n"); @@ -1689,13 +1708,15 @@ static void ncm_unbind(struct usb_configuration *c, struct usb_function *f) kfree(ncm->notify_req->buf); usb_ep_free_request(ncm->notify, ncm->notify_req); + + gether_cleanup(netdev_priv(opts->net)); + opts->bound = false; } static struct usb_function *ncm_alloc(struct usb_function_instance *fi) { struct f_ncm *ncm; struct f_ncm_opts *opts; - int status; /* allocate and initialize one new instance */ ncm = kzalloc(sizeof(*ncm), GFP_KERNEL); @@ -1705,20 +1726,9 @@ static struct usb_function *ncm_alloc(struct usb_function_instance *fi) opts = container_of(fi, struct f_ncm_opts, func_inst); mutex_lock(&opts->lock); opts->refcnt++; - - /* export host's Ethernet address in CDC format */ - status = gether_get_host_addr_cdc(opts->net, ncm->ethaddr, - sizeof(ncm->ethaddr)); - if (status < 12) { /* strlen("01234567890a") */ - kfree(ncm); - mutex_unlock(&opts->lock); - return ERR_PTR(-EINVAL); - } ncm_string_defs[STRING_MAC_IDX].s = ncm->ethaddr; - spin_lock_init(&ncm->lock); ncm_reset_values(ncm); - ncm->port.ioport = netdev_priv(opts->net); mutex_unlock(&opts->lock); ncm->port.is_fixed = true; ncm->port.supports_multi_frame = true; -- GitLab From dd753cb709e3e09c6cd52a920e849caa2d0179a8 Mon Sep 17 00:00:00 2001 From: Vamsi Krishna Samavedam Date: Wed, 2 May 2018 10:47:59 -0700 Subject: [PATCH 1479/1635] usb: gadget: diag: Notify cable status while opening channel Client will miss cable connect notification if USB cable is already connected before channel is opened. Notify client through notify callback if usb cable is already connected when channel is opened. Change-Id: I5f94cd8c572522edb575d498fa2108c1a5b938c8 Signed-off-by: Vamsi Krishna Samavedam --- drivers/usb/gadget/function/f_diag.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/usb/gadget/function/f_diag.c b/drivers/usb/gadget/function/f_diag.c index a4217e3b5b6b..02de6c31739a 100644 --- a/drivers/usb/gadget/function/f_diag.c +++ b/drivers/usb/gadget/function/f_diag.c @@ -331,6 +331,8 @@ struct usb_diag_ch *usb_diag_open(const char *name, void *priv, struct usb_diag_ch *ch; unsigned long flags; int found = 0; + bool connected = false; + struct diag_context *dev; spin_lock_irqsave(&ch_lock, flags); /* Check if we already have a channel with this name */ @@ -358,6 +360,16 @@ struct usb_diag_ch *usb_diag_open(const char *name, void *priv, spin_unlock_irqrestore(&ch_lock, flags); } + if (ch->priv_usb) { + dev = ch->priv_usb; + spin_lock_irqsave(&dev->lock, flags); + connected = dev->configured; + spin_unlock_irqrestore(&dev->lock, flags); + } + + if (ch->notify && connected) + ch->notify(priv, USB_DIAG_CONNECT, NULL); + return ch; } EXPORT_SYMBOL(usb_diag_open); -- GitLab From b67da3ea9e862bde85fea325d5847a332afffb39 Mon Sep 17 00:00:00 2001 From: Maulik Shah Date: Wed, 9 May 2018 11:49:13 +0530 Subject: [PATCH 1480/1635] ARM: dts: msm: Add QMP debugfs client on sm6150 The QMP debugfs client uses the QMP mailbox driver to communicate with the Always On processor. Change-Id: Id801858b8e40aa276897a32565c62076ca793c9e Signed-off-by: Maulik Shah --- arch/arm64/boot/dts/qcom/sm6150.dtsi | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sm6150.dtsi b/arch/arm64/boot/dts/qcom/sm6150.dtsi index 539f467982f1..6ceba108843e 100644 --- a/arch/arm64/boot/dts/qcom/sm6150.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6150.dtsi @@ -714,6 +714,12 @@ status = "ok"; }; + aop-msg-client { + compatible = "qcom,debugfs-qmp-client"; + mboxes = <&qmp_aop 0>; + mbox-names = "aop"; + }; + qcom,msm-rtb { compatible = "qcom,msm-rtb"; qcom,rtb-size = <0x100000>; -- GitLab From 02ac5aa37631253d269a177bd3f6495d173ac33e Mon Sep 17 00:00:00 2001 From: Ghanim Fodi Date: Sun, 6 May 2018 18:10:48 +0300 Subject: [PATCH 1481/1635] msm: ipa3: fix debugfs creation order IPA unit-test module is initialized by IPA ready callback. The ready callback is called before creating IPA debugfs root folder in which IPA unit-test module depends on. Change-Id: Id3e867cd074730a3006e124d1074bedef081920a Signed-off-by: Ghanim Fodi --- drivers/platform/msm/ipa/ipa_v3/ipa.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa.c b/drivers/platform/msm/ipa/ipa_v3/ipa.c index d5a11d4398af..11790bdd8603 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa.c @@ -4643,12 +4643,12 @@ static int ipa3_post_init(const struct ipa3_plat_drv_res *resource_p, ipa3_ctx->ipa_initialization_complete = true; mutex_unlock(&ipa3_ctx->lock); + ipa3_debugfs_init(); + ipa3_trigger_ipa_ready_cbs(); complete_all(&ipa3_ctx->init_completion_obj); pr_info("IPA driver initialization was successful.\n"); - ipa3_debugfs_init(); - return 0; fail_teth_bridge_driver_init: -- GitLab From 2929775053f7a99eeae469f62f4c2bcf1d251b90 Mon Sep 17 00:00:00 2001 From: Pavankumar Kondeti Date: Tue, 8 May 2018 12:15:08 +0530 Subject: [PATCH 1482/1635] sched/walt: Fix stale window start marker passed to the schedutil With commit d8c5bfcc07ee ("sched: Make sure window start passed to schedutil is consistent"), the rq->load_reported_window is presented to the governor as the window_start marker. The rq->load_reported_window is updated when load is reported to governor only during a window rollover. So it should be consistent with the current window start mark. But for a just hotplugged in CPU, the rq->load_reported_window is not updated until the next window rollover. If the load is reported for any other reason before the next window rollover, the window start marker passed to the schedutil would be stale and leads to a BUG_ON() in schedutil. The recent window start marker is cached in WALT in walt_irq_work_lastq_ws. Use this instead of load_reported_window to fix this problem. The rq->window_start is cached in rq->load_reported_window to filter the utilization updates in the same window. This is not needed since utilization updates are not sent when SCHED_CPUFREQ_WALT flag is not set. So kill the load_reported_window maintenance. Change-Id: Idaefcb0b9cecb15ea436ac7a66cb6da81e3852a1 Signed-off-by: Pavankumar Kondeti --- kernel/sched/sched.h | 19 +++---------------- kernel/sched/walt.c | 2 +- 2 files changed, 4 insertions(+), 17 deletions(-) diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h index 062b760cb2c5..63bc0801159e 100644 --- a/kernel/sched/sched.h +++ b/kernel/sched/sched.h @@ -852,7 +852,6 @@ struct rq { int cstate, wakeup_latency, wakeup_energy; u64 window_start; s64 cum_window_start; - u64 load_reported_window; unsigned long walt_flags; u64 cur_irqload; @@ -1966,6 +1965,8 @@ cpu_util_freq_pelt(int cpu) } #ifdef CONFIG_SCHED_WALT +extern atomic64_t walt_irq_work_lastq_ws; + static inline unsigned long cpu_util_freq_walt(int cpu, struct sched_walt_cpu_load *walt_load) { @@ -2002,7 +2003,7 @@ cpu_util_freq_walt(int cpu, struct sched_walt_cpu_load *walt_load) walt_load->prev_window_util = util; walt_load->nl = nl; walt_load->pl = pl; - walt_load->ws = rq->load_reported_window; + walt_load->ws = atomic64_read(&walt_irq_work_lastq_ws); } return (util >= capacity) ? capacity : util; @@ -2453,22 +2454,8 @@ static inline void cpufreq_update_util(struct rq *rq, unsigned int flags) struct update_util_data *data; #ifdef CONFIG_SCHED_WALT - unsigned int exception_flags = SCHED_CPUFREQ_INTERCLUSTER_MIG | - SCHED_CPUFREQ_PL | SCHED_CPUFREQ_EARLY_DET | - SCHED_CPUFREQ_FORCE_UPDATE; - - /* - * Skip if we've already reported, but not if this is an inter-cluster - * migration. Also only allow WALT update sites. - */ if (!(flags & SCHED_CPUFREQ_WALT)) return; - if (!sched_disable_window_stats && - (rq->load_reported_window == rq->window_start) && - !(flags & exception_flags)) - return; - if (!(flags & exception_flags)) - rq->load_reported_window = rq->window_start; #endif data = rcu_dereference_sched(*per_cpu_ptr(&cpufreq_update_util_data, diff --git a/kernel/sched/walt.c b/kernel/sched/walt.c index bec6aef86664..d06f8ae28186 100644 --- a/kernel/sched/walt.c +++ b/kernel/sched/walt.c @@ -45,7 +45,7 @@ const char *migrate_type_names[] = {"GROUP_TO_RQ", "RQ_TO_GROUP", static struct cpu_cycle_counter_cb cpu_cycle_counter_cb; static bool use_cycle_counter; DEFINE_MUTEX(cluster_lock); -static atomic64_t walt_irq_work_lastq_ws; +atomic64_t walt_irq_work_lastq_ws; static struct irq_work walt_cpufreq_irq_work; static struct irq_work walt_migration_irq_work; -- GitLab From 6c616d52be8441bccee3a2dd8c8f7c05a103706b Mon Sep 17 00:00:00 2001 From: Pavankumar Kondeti Date: Tue, 8 May 2018 12:34:32 +0530 Subject: [PATCH 1483/1635] sched/walt: Add missing pl notification support The pl notification support is missed while porting the WALT to 4.14 kernel. Add it now. Change-Id: I51723a77b263d6143f99926f05310243891322ae Signed-off-by: Pavankumar Kondeti --- kernel/sched/core.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/kernel/sched/core.c b/kernel/sched/core.c index 4df40a9a6c3f..4d51c1fb9659 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -2171,6 +2171,14 @@ try_to_wake_up(struct task_struct *p, unsigned int state, int wake_flags, out: raw_spin_unlock_irqrestore(&p->pi_lock, flags); + if (success && sched_predl) { + raw_spin_lock_irqsave(&cpu_rq(cpu)->lock, flags); + if (do_pl_notif(cpu_rq(cpu))) + cpufreq_update_util(cpu_rq(cpu), + SCHED_CPUFREQ_WALT | + SCHED_CPUFREQ_PL); + raw_spin_unlock_irqrestore(&cpu_rq(cpu)->lock, flags); + } return success; } -- GitLab From a7bc6394174a22ab02866f5cb2b6e2af789d92a0 Mon Sep 17 00:00:00 2001 From: Srinivas Ramana Date: Wed, 9 May 2018 14:53:38 +0530 Subject: [PATCH 1484/1635] ARM: dts: msm: Correct the timer frequency on sm6150 RUMI RUMI platform has the CP15 timers running at 1MHZ. Correct the frequency parameter to match this. Change-Id: I0c8dd0a6c552b2d51457fbe73c94b20f4b8b5941 Signed-off-by: Srinivas Ramana --- arch/arm64/boot/dts/qcom/sm6150-rumi.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/sm6150-rumi.dtsi b/arch/arm64/boot/dts/qcom/sm6150-rumi.dtsi index 1fd5029c0d78..8822e0a1dc13 100644 --- a/arch/arm64/boot/dts/qcom/sm6150-rumi.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6150-rumi.dtsi @@ -12,7 +12,7 @@ &soc { timer { - clock-frequency = <5500000>; + clock-frequency = <1000000>; }; timer@0x17c00000 { -- GitLab From e9a5597d9a3c9630b3d10090c7427ede07bedb11 Mon Sep 17 00:00:00 2001 From: Pengfei Liu Date: Wed, 9 May 2018 21:26:19 +0800 Subject: [PATCH 1485/1635] msm: camera: Initial parameters of eeprom Initial parameters to avoid random value break the flow. Change-Id: Icd0b1d87b49849d5d6ba12859be52a87f760882d Signed-off-by: Pengfei Liu --- .../camera/cam_sensor_module/cam_eeprom/cam_eeprom_core.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_eeprom/cam_eeprom_core.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_eeprom/cam_eeprom_core.c index 30b9d967c405..970d50977ad5 100644 --- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_eeprom/cam_eeprom_core.c +++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_eeprom/cam_eeprom_core.c @@ -31,10 +31,10 @@ static int cam_eeprom_read_memory(struct cam_eeprom_ctrl_t *e_ctrl, { int rc = 0; int j; - struct cam_sensor_i2c_reg_setting i2c_reg_settings; - struct cam_sensor_i2c_reg_array i2c_reg_array; + struct cam_sensor_i2c_reg_setting i2c_reg_settings = {0}; + struct cam_sensor_i2c_reg_array i2c_reg_array = {0}; struct cam_eeprom_memory_map_t *emap = block->map; - struct cam_eeprom_soc_private *eb_info; + struct cam_eeprom_soc_private *eb_info = NULL; uint8_t *memptr = block->mapdata; if (!e_ctrl) { -- GitLab From f9cf7b56e37574c62249af9b53b5747435afd3b3 Mon Sep 17 00:00:00 2001 From: Willem de Bruijn Date: Thu, 26 Apr 2018 13:42:15 -0400 Subject: [PATCH 1486/1635] udp: expose inet cork to udp UDP segmentation offload needs access to inet_cork in the udp layer. Pass the struct to ip(6)_make_skb instead of allocating it on the stack in that function itself. This patch is a noop otherwise. Change-Id: I75917a4f2f27aa26133d466663913fec4ae48470 Signed-off-by: Willem de Bruijn Signed-off-by: David S. Miller Git-commit: 1cd7884dfd78df6284d27b008823b0b4a808f196 Git-repo: https://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next.git Signed-off-by: Sean Tranchetti --- include/net/ip.h | 2 +- include/net/ipv6.h | 1 + net/ipv4/ip_output.c | 17 ++++++++--------- net/ipv4/udp.c | 4 +++- net/ipv6/ip6_output.c | 20 ++++++++++---------- net/ipv6/udp.c | 3 ++- 6 files changed, 25 insertions(+), 22 deletions(-) diff --git a/include/net/ip.h b/include/net/ip.h index 9e4a1b639317..bb5c5a7bdbfc 100644 --- a/include/net/ip.h +++ b/include/net/ip.h @@ -160,7 +160,7 @@ struct sk_buff *ip_make_skb(struct sock *sk, struct flowi4 *fl4, int len, int odd, struct sk_buff *skb), void *from, int length, int transhdrlen, struct ipcm_cookie *ipc, struct rtable **rtp, - unsigned int flags); + struct inet_cork *cork, unsigned int flags); static inline struct sk_buff *ip_finish_skb(struct sock *sk, struct flowi4 *fl4) { diff --git a/include/net/ipv6.h b/include/net/ipv6.h index 9596aa93d6ef..7c56755d70a0 100644 --- a/include/net/ipv6.h +++ b/include/net/ipv6.h @@ -905,6 +905,7 @@ struct sk_buff *ip6_make_skb(struct sock *sk, void *from, int length, int transhdrlen, struct ipcm6_cookie *ipc6, struct flowi6 *fl6, struct rt6_info *rt, unsigned int flags, + struct inet_cork_full *cork, const struct sockcm_cookie *sockc); static inline struct sk_buff *ip6_finish_skb(struct sock *sk) diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index e8e675be60ec..c3c7f28b260c 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -1460,9 +1460,8 @@ struct sk_buff *ip_make_skb(struct sock *sk, int len, int odd, struct sk_buff *skb), void *from, int length, int transhdrlen, struct ipcm_cookie *ipc, struct rtable **rtp, - unsigned int flags) + struct inet_cork *cork, unsigned int flags) { - struct inet_cork cork; struct sk_buff_head queue; int err; @@ -1471,22 +1470,22 @@ struct sk_buff *ip_make_skb(struct sock *sk, __skb_queue_head_init(&queue); - cork.flags = 0; - cork.addr = 0; - cork.opt = NULL; - err = ip_setup_cork(sk, &cork, ipc, rtp); + cork->flags = 0; + cork->addr = 0; + cork->opt = NULL; + err = ip_setup_cork(sk, cork, ipc, rtp); if (err) return ERR_PTR(err); - err = __ip_append_data(sk, fl4, &queue, &cork, + err = __ip_append_data(sk, fl4, &queue, cork, ¤t->task_frag, getfrag, from, length, transhdrlen, flags); if (err) { - __ip_flush_pending_frames(sk, &queue, &cork); + __ip_flush_pending_frames(sk, &queue, cork); return ERR_PTR(err); } - return __ip_make_skb(sk, fl4, &queue, &cork); + return __ip_make_skb(sk, fl4, &queue, cork); } /* diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index f521778a7c72..b594a454990b 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -1048,9 +1048,11 @@ int udp_sendmsg(struct sock *sk, struct msghdr *msg, size_t len) /* Lockless fast path for the non-corking case. */ if (!corkreq) { + struct inet_cork cork; + skb = ip_make_skb(sk, fl4, getfrag, msg, ulen, sizeof(struct udphdr), &ipc, &rt, - msg->msg_flags); + &cork, msg->msg_flags); err = PTR_ERR(skb); if (!IS_ERR_OR_NULL(skb)) err = udp_send_skb(skb, fl4); diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index ffbb81609016..f5a9253b8be4 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -1735,9 +1735,9 @@ struct sk_buff *ip6_make_skb(struct sock *sk, void *from, int length, int transhdrlen, struct ipcm6_cookie *ipc6, struct flowi6 *fl6, struct rt6_info *rt, unsigned int flags, + struct inet_cork_full *cork, const struct sockcm_cookie *sockc) { - struct inet_cork_full cork; struct inet6_cork v6_cork; struct sk_buff_head queue; int exthdrlen = (ipc6->opt ? ipc6->opt->opt_flen : 0); @@ -1748,27 +1748,27 @@ struct sk_buff *ip6_make_skb(struct sock *sk, __skb_queue_head_init(&queue); - cork.base.flags = 0; - cork.base.addr = 0; - cork.base.opt = NULL; - cork.base.dst = NULL; + cork->base.flags = 0; + cork->base.addr = 0; + cork->base.opt = NULL; + cork->base.dst = NULL; v6_cork.opt = NULL; - err = ip6_setup_cork(sk, &cork, &v6_cork, ipc6, rt, fl6); + err = ip6_setup_cork(sk, cork, &v6_cork, ipc6, rt, fl6); if (err) { - ip6_cork_release(&cork, &v6_cork); + ip6_cork_release(cork, &v6_cork); return ERR_PTR(err); } if (ipc6->dontfrag < 0) ipc6->dontfrag = inet6_sk(sk)->dontfrag; - err = __ip6_append_data(sk, fl6, &queue, &cork.base, &v6_cork, + err = __ip6_append_data(sk, fl6, &queue, &cork->base, &v6_cork, ¤t->task_frag, getfrag, from, length + exthdrlen, transhdrlen + exthdrlen, flags, ipc6, sockc); if (err) { - __ip6_flush_pending_frames(sk, &queue, &cork, &v6_cork); + __ip6_flush_pending_frames(sk, &queue, cork, &v6_cork); return ERR_PTR(err); } - return __ip6_make_skb(sk, &queue, &cork, &v6_cork); + return __ip6_make_skb(sk, &queue, cork, &v6_cork); } diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index 40d7234c27b9..4c2dd65ba97b 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c @@ -1335,12 +1335,13 @@ int udpv6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len) /* Lockless fast path for the non-corking case */ if (!corkreq) { + struct inet_cork_full cork; struct sk_buff *skb; skb = ip6_make_skb(sk, getfrag, msg, ulen, sizeof(struct udphdr), &ipc6, &fl6, (struct rt6_info *)dst, - msg->msg_flags, &sockc); + msg->msg_flags, &cork, &sockc); err = PTR_ERR(skb); if (!IS_ERR_OR_NULL(skb)) err = udp_v6_send_skb(skb, &fl6); -- GitLab From 42d65f0675cdb6014c92ef837b88194de1784366 Mon Sep 17 00:00:00 2001 From: Willem de Bruijn Date: Thu, 26 Apr 2018 13:42:16 -0400 Subject: [PATCH 1487/1635] udp: add udp gso Implement generic segmentation offload support for udp datagrams. A follow-up patch adds support to the protocol stack to generate such packets. UDP GSO is not UFO. UFO fragments a single large datagram. GSO splits a large payload into a number of discrete UDP datagrams. The implementation adds a GSO type SKB_UDP_GSO_L4 to differentiate it from UFO (SKB_UDP_GSO). IPPROTO_UDPLITE is excluded, as that protocol has no gso handler registered. Change-Id: Iff5e2f40ba816b4ee6675fa5a8f47d78c2ba91cb Signed-off-by: Willem de Bruijn Signed-off-by: David S. Miller Git-commit: ee80d1ebe5ba7f4bd74959c873119175a4fc08d3 Git-repo: https://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next.git Signed-off-by: Sean Tranchetti --- include/linux/skbuff.h | 2 ++ include/net/udp.h | 4 ++++ net/core/skbuff.c | 2 ++ net/ipv4/udp_offload.c | 52 +++++++++++++++++++++++++++++++++++++++++- net/ipv6/ip6_offload.c | 6 +++-- net/ipv6/udp_offload.c | 19 ++++++++++++++- 6 files changed, 81 insertions(+), 4 deletions(-) diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index be45224b01d7..d6ac8af60d7f 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -570,6 +570,8 @@ enum { SKB_GSO_ESP = 1 << 15, SKB_GSO_UDP = 1 << 16, + + SKB_GSO_UDP_L4 = 1 << 17, }; #if BITS_PER_LONG > 32 diff --git a/include/net/udp.h b/include/net/udp.h index 6c759c8594e2..9126e0d53500 100644 --- a/include/net/udp.h +++ b/include/net/udp.h @@ -174,6 +174,10 @@ struct sk_buff **udp_gro_receive(struct sk_buff **head, struct sk_buff *skb, struct udphdr *uh, udp_lookup_t lookup); int udp_gro_complete(struct sk_buff *skb, int nhoff, udp_lookup_t lookup); +struct sk_buff *__udp_gso_segment(struct sk_buff *gso_skb, + netdev_features_t features, + unsigned int mss, __sum16 check); + static inline struct udphdr *udp_gro_udphdr(struct sk_buff *skb) { struct udphdr *uh; diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 564beb7e6d1c..1542fb4203e2 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -4895,6 +4895,8 @@ unsigned int skb_gso_transport_seglen(const struct sk_buff *skb) thlen = tcp_hdrlen(skb); } else if (unlikely(shinfo->gso_type & SKB_GSO_SCTP)) { thlen = sizeof(struct sctphdr); + } else if (shinfo->gso_type & SKB_GSO_UDP_L4) { + thlen = sizeof(struct udphdr); } /* UFO sets gso_size to the size of the fragmentation * payload, i.e. the size of the L4 (UDP) header is already diff --git a/net/ipv4/udp_offload.c b/net/ipv4/udp_offload.c index ea6e6e7df0ee..6b09220ca407 100644 --- a/net/ipv4/udp_offload.c +++ b/net/ipv4/udp_offload.c @@ -187,6 +187,53 @@ struct sk_buff *skb_udp_tunnel_segment(struct sk_buff *skb, } EXPORT_SYMBOL(skb_udp_tunnel_segment); +struct sk_buff *__udp_gso_segment(struct sk_buff *gso_skb, + netdev_features_t features, + unsigned int mss, __sum16 check) +{ + struct sk_buff *segs, *seg; + unsigned int hdrlen; + struct udphdr *uh; + + if (gso_skb->len <= sizeof(*uh) + mss) + return ERR_PTR(-EINVAL); + + hdrlen = gso_skb->data - skb_mac_header(gso_skb); + skb_pull(gso_skb, sizeof(*uh)); + + segs = skb_segment(gso_skb, features); + if (unlikely(IS_ERR_OR_NULL(segs))) + return segs; + + for (seg = segs; seg; seg = seg->next) { + uh = udp_hdr(seg); + uh->len = htons(seg->len - hdrlen); + uh->check = check; + + /* last packet can be partial gso_size */ + if (!seg->next) + csum_replace2(&uh->check, htons(mss), + htons(seg->len - hdrlen - sizeof(*uh))); + } + + return segs; +} + +static struct sk_buff *__udp4_gso_segment(struct sk_buff *gso_skb, + netdev_features_t features) +{ + const struct iphdr *iph = ip_hdr(gso_skb); + unsigned int mss = skb_shinfo(gso_skb)->gso_size; + + if (!can_checksum_protocol(features, htons(ETH_P_IP))) + return ERR_PTR(-EIO); + + return __udp_gso_segment(gso_skb, features, mss, + udp_v4_check(sizeof(struct udphdr) + mss, + iph->saddr, iph->daddr, 0)); +} +EXPORT_SYMBOL_GPL(__udp4_gso_segment); + static struct sk_buff *udp4_ufo_fragment(struct sk_buff *skb, netdev_features_t features) { @@ -203,12 +250,15 @@ static struct sk_buff *udp4_ufo_fragment(struct sk_buff *skb, goto out; } - if (!(skb_shinfo(skb)->gso_type & SKB_GSO_UDP)) + if (!(skb_shinfo(skb)->gso_type & (SKB_GSO_UDP | SKB_GSO_UDP_L4))) goto out; if (!pskb_may_pull(skb, sizeof(struct udphdr))) goto out; + if (skb_shinfo(skb)->gso_type & SKB_GSO_UDP_L4) + return __udp4_gso_segment(skb, features); + mss = skb_shinfo(skb)->gso_size; if (unlikely(skb->len <= mss)) goto out; diff --git a/net/ipv6/ip6_offload.c b/net/ipv6/ip6_offload.c index 4a87f9428ca5..5b3f2f89ef41 100644 --- a/net/ipv6/ip6_offload.c +++ b/net/ipv6/ip6_offload.c @@ -88,9 +88,11 @@ static struct sk_buff *ipv6_gso_segment(struct sk_buff *skb, if (skb->encapsulation && skb_shinfo(skb)->gso_type & (SKB_GSO_IPXIP4 | SKB_GSO_IPXIP6)) - udpfrag = proto == IPPROTO_UDP && encap; + udpfrag = proto == IPPROTO_UDP && encap && + (skb_shinfo(skb)->gso_type & SKB_GSO_UDP); else - udpfrag = proto == IPPROTO_UDP && !skb->encapsulation; + udpfrag = proto == IPPROTO_UDP && !skb->encapsulation && + (skb_shinfo(skb)->gso_type & SKB_GSO_UDP); ops = rcu_dereference(inet6_offloads[proto]); if (likely(ops && ops->callbacks.gso_segment)) { diff --git a/net/ipv6/udp_offload.c b/net/ipv6/udp_offload.c index 2a04dc9c781b..f7b85b1e6b3e 100644 --- a/net/ipv6/udp_offload.c +++ b/net/ipv6/udp_offload.c @@ -17,6 +17,20 @@ #include #include "ip6_offload.h" +static struct sk_buff *__udp6_gso_segment(struct sk_buff *gso_skb, + netdev_features_t features) +{ + const struct ipv6hdr *ip6h = ipv6_hdr(gso_skb); + unsigned int mss = skb_shinfo(gso_skb)->gso_size; + + if (!can_checksum_protocol(features, htons(ETH_P_IPV6))) + return ERR_PTR(-EIO); + + return __udp_gso_segment(gso_skb, features, mss, + udp_v6_check(sizeof(struct udphdr) + mss, + &ip6h->saddr, &ip6h->daddr, 0)); +} + static struct sk_buff *udp6_ufo_fragment(struct sk_buff *skb, netdev_features_t features) { @@ -42,12 +56,15 @@ static struct sk_buff *udp6_ufo_fragment(struct sk_buff *skb, const struct ipv6hdr *ipv6h; struct udphdr *uh; - if (!(skb_shinfo(skb)->gso_type & SKB_GSO_UDP)) + if (!(skb_shinfo(skb)->gso_type & (SKB_GSO_UDP | SKB_GSO_UDP_L4))) goto out; if (!pskb_may_pull(skb, sizeof(struct udphdr))) goto out; + if (skb_shinfo(skb)->gso_type & SKB_GSO_UDP_L4) + return __udp6_gso_segment(skb, features); + /* Do software UFO. Complete and fill in the UDP checksum as HW cannot * do checksum of UDP packets sent as multiple IP fragments. */ -- GitLab From b667d4d62c751dc68f8b8a9d0960e0353257fbd9 Mon Sep 17 00:00:00 2001 From: Willem de Bruijn Date: Thu, 26 Apr 2018 13:42:17 -0400 Subject: [PATCH 1488/1635] udp: generate gso with UDP_SEGMENT Support generic segmentation offload for udp datagrams. Callers can concatenate and send at once the payload of multiple datagrams with the same destination. To set segment size, the caller sets socket option UDP_SEGMENT to the length of each discrete payload. This value must be smaller than or equal to the relevant MTU. A follow-up patch adds cmsg UDP_SEGMENT to specify segment size on a per send call basis. Total byte length may then exceed MTU. If not an exact multiple of segment size, the last segment will be shorter. The implementation adds a gso_size field to the udp socket, ip(v6) cmsg cookie and inet_cork structure to be able to set the value at setsockopt or cmsg time and to work with both lockless and corked paths. Initial benchmark numbers show UDP GSO about as expensive as TCP GSO. tcp tso 3197 MB/s 54232 msg/s 54232 calls/s 6,457,754,262 cycles tcp gso 1765 MB/s 29939 msg/s 29939 calls/s 11,203,021,806 cycles tcp without tso/gso * 739 MB/s 12548 msg/s 12548 calls/s 11,205,483,630 cycles udp 876 MB/s 14873 msg/s 624666 calls/s 11,205,777,429 cycles udp gso 2139 MB/s 36282 msg/s 36282 calls/s 11,204,374,561 cycles [*] after reverting commit 0a6b2a1dc2a2 ("tcp: switch to GSO being always on") Measured total system cycles ('-a') for one core while pinning both the network receive path and benchmark process to that core: perf stat -a -C 12 -e cycles \ ./udpgso_bench_tx -C 12 -4 -D "$DST" -l 4 Note the reduction in calls/s with GSO. Bytes per syscall drops increases from 1470 to 61818. Change-Id: I0a51351c8ccb5d77eb5cdedbb9ee9e49d34832cb Signed-off-by: Willem de Bruijn Signed-off-by: David S. Miller Git-commit: bec1f6f697362c5bc635dacd7ac8499d0a10a4e7 Git-repo: https://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next.git Signed-off-by: Sean Tranchetti --- include/linux/udp.h | 3 +++ include/net/inet_sock.h | 1 + include/net/ip.h | 1 + include/net/ipv6.h | 1 + include/uapi/linux/udp.h | 1 + net/ipv4/ip_output.c | 9 ++++++--- net/ipv4/udp.c | 33 ++++++++++++++++++++++++++++++--- net/ipv6/ip6_output.c | 6 ++++-- net/ipv6/udp.c | 23 ++++++++++++++++++++--- 9 files changed, 67 insertions(+), 11 deletions(-) diff --git a/include/linux/udp.h b/include/linux/udp.h index eaea63bc79bb..ca840345571b 100644 --- a/include/linux/udp.h +++ b/include/linux/udp.h @@ -55,6 +55,7 @@ struct udp_sock { * when the socket is uncorked. */ __u16 len; /* total length of pending frames */ + __u16 gso_size; /* * Fields specific to UDP-Lite. */ @@ -87,6 +88,8 @@ struct udp_sock { int forward_deficit; }; +#define UDP_MAX_SEGMENTS (1 << 6UL) + static inline struct udp_sock *udp_sk(const struct sock *sk) { return (struct udp_sock *)sk; diff --git a/include/net/inet_sock.h b/include/net/inet_sock.h index 8e51b4a69088..876caecb1408 100644 --- a/include/net/inet_sock.h +++ b/include/net/inet_sock.h @@ -146,6 +146,7 @@ struct inet_cork { __u8 ttl; __s16 tos; char priority; + __u16 gso_size; }; struct inet_cork_full { diff --git a/include/net/ip.h b/include/net/ip.h index bb5c5a7bdbfc..bc002f0b6b57 100644 --- a/include/net/ip.h +++ b/include/net/ip.h @@ -74,6 +74,7 @@ struct ipcm_cookie { __u8 ttl; __s16 tos; char priority; + __u16 gso_size; }; #define IPCB(skb) ((struct inet_skb_parm*)((skb)->cb)) diff --git a/include/net/ipv6.h b/include/net/ipv6.h index 7c56755d70a0..bd406ad01596 100644 --- a/include/net/ipv6.h +++ b/include/net/ipv6.h @@ -257,6 +257,7 @@ struct ipcm6_cookie { __s16 tclass; __s8 dontfrag; struct ipv6_txoptions *opt; + __u16 gso_size; }; static inline struct ipv6_txoptions *txopt_get(const struct ipv6_pinfo *np) diff --git a/include/uapi/linux/udp.h b/include/uapi/linux/udp.h index efb7b5991c2f..09d00f8c442b 100644 --- a/include/uapi/linux/udp.h +++ b/include/uapi/linux/udp.h @@ -32,6 +32,7 @@ struct udphdr { #define UDP_ENCAP 100 /* Set the socket to accept encapsulated packets */ #define UDP_NO_CHECK6_TX 101 /* Disable sending checksum for UDP6X */ #define UDP_NO_CHECK6_RX 102 /* Disable accpeting checksum for UDP6 */ +#define UDP_SEGMENT 103 /* Set GSO segmentation size */ /* UDP encapsulation types */ #define UDP_ENCAP_ESPINUDP_NON_IKE 1 /* draft-ietf-ipsec-nat-t-ike-00/01 */ diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index c3c7f28b260c..ef34a6d128d8 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -881,7 +881,8 @@ static int __ip_append_data(struct sock *sk, skb = skb_peek_tail(queue); exthdrlen = !skb ? rt->dst.header_len : 0; - mtu = cork->fragsize; + mtu = cork->gso_size ? IP_MAX_MTU : cork->fragsize; + if (cork->tx_flags & SKBTX_ANY_SW_TSTAMP && sk->sk_tsflags & SOF_TIMESTAMPING_OPT_ID) tskey = sk->sk_tskey++; @@ -905,7 +906,7 @@ static int __ip_append_data(struct sock *sk, if (transhdrlen && length + fragheaderlen <= mtu && rt->dst.dev->features & (NETIF_F_HW_CSUM | NETIF_F_IP_CSUM) && - !(flags & MSG_MORE) && + (!(flags & MSG_MORE) || cork->gso_size) && !exthdrlen) csummode = CHECKSUM_PARTIAL; @@ -1125,6 +1126,8 @@ static int ip_setup_cork(struct sock *sk, struct inet_cork *cork, *rtp = NULL; cork->fragsize = ip_sk_use_pmtu(sk) ? dst_mtu(&rt->dst) : rt->dst.dev->mtu; + + cork->gso_size = sk->sk_type == SOCK_DGRAM ? ipc->gso_size : 0; cork->dst = &rt->dst; cork->length = 0; cork->ttl = ipc->ttl; @@ -1204,7 +1207,7 @@ ssize_t ip_append_page(struct sock *sk, struct flowi4 *fl4, struct page *page, return -EOPNOTSUPP; hh_len = LL_RESERVED_SPACE(rt->dst.dev); - mtu = cork->fragsize; + mtu = cork->gso_size ? IP_MAX_MTU : cork->fragsize; fragheaderlen = sizeof(struct iphdr) + (opt ? opt->optlen : 0); maxfraglen = ((mtu - fragheaderlen) & ~7) + fragheaderlen; diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index b594a454990b..478db7a34ab6 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -788,7 +788,8 @@ void udp_set_csum(bool nocheck, struct sk_buff *skb, } EXPORT_SYMBOL(udp_set_csum); -static int udp_send_skb(struct sk_buff *skb, struct flowi4 *fl4) +static int udp_send_skb(struct sk_buff *skb, struct flowi4 *fl4, + struct inet_cork *cork) { struct sock *sk = skb->sk; struct inet_sock *inet = inet_sk(sk); @@ -808,6 +809,21 @@ static int udp_send_skb(struct sk_buff *skb, struct flowi4 *fl4) uh->len = htons(len); uh->check = 0; + if (cork->gso_size) { + const int hlen = skb_network_header_len(skb) + + sizeof(struct udphdr); + + if (hlen + cork->gso_size > cork->fragsize) + return -EINVAL; + if (skb->len > cork->gso_size * UDP_MAX_SEGMENTS) + return -EINVAL; + if (skb->ip_summed != CHECKSUM_PARTIAL || is_udplite) + return -EIO; + + skb_shinfo(skb)->gso_size = cork->gso_size; + skb_shinfo(skb)->gso_type = SKB_GSO_UDP_L4; + } + if (is_udplite) /* UDP-Lite */ csum = udplite_csum(skb); @@ -859,7 +875,7 @@ int udp_push_pending_frames(struct sock *sk) if (!skb) goto out; - err = udp_send_skb(skb, fl4); + err = udp_send_skb(skb, fl4, &inet->cork.base); out: up->len = 0; @@ -953,6 +969,7 @@ int udp_sendmsg(struct sock *sk, struct msghdr *msg, size_t len) ipc.sockc.tsflags = sk->sk_tsflags; ipc.addr = inet->inet_saddr; ipc.oif = sk->sk_bound_dev_if; + ipc.gso_size = up->gso_size; if (msg->msg_controllen) { err = ip_cmsg_send(sk, msg, &ipc, sk->sk_family == AF_INET6); @@ -1055,7 +1072,7 @@ int udp_sendmsg(struct sock *sk, struct msghdr *msg, size_t len) &cork, msg->msg_flags); err = PTR_ERR(skb); if (!IS_ERR_OR_NULL(skb)) - err = udp_send_skb(skb, fl4); + err = udp_send_skb(skb, fl4, &cork); goto out; } @@ -2373,6 +2390,12 @@ int udp_lib_setsockopt(struct sock *sk, int level, int optname, up->no_check6_rx = valbool; break; + case UDP_SEGMENT: + if (val < 0 || val > USHRT_MAX) + return -EINVAL; + up->gso_size = val; + break; + /* * UDP-Lite's partial checksum coverage (RFC 3828). */ @@ -2463,6 +2486,10 @@ int udp_lib_getsockopt(struct sock *sk, int level, int optname, val = up->no_check6_rx; break; + case UDP_SEGMENT: + val = up->gso_size; + break; + /* The following two cannot be changed on UDP sockets, the return is * always 0 (which corresponds to the full checksum coverage of UDP). */ case UDPLITE_SEND_CSCOV: diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index f5a9253b8be4..b56aa46761f3 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -1228,6 +1228,8 @@ static int ip6_setup_cork(struct sock *sk, struct inet_cork_full *cork, if (mtu < IPV6_MIN_MTU) return -EINVAL; cork->base.fragsize = mtu; + cork->base.gso_size = sk->sk_type == SOCK_DGRAM ? ipc6->gso_size : 0; + if (dst_allfrag(rt->dst.path)) cork->base.flags |= IPCORK_ALLFRAG; cork->base.length = 0; @@ -1268,7 +1270,7 @@ static int __ip6_append_data(struct sock *sk, dst_exthdrlen = rt->dst.header_len - rt->rt6i_nfheader_len; } - mtu = cork->fragsize; + mtu = cork->gso_size ? IP6_MAX_MTU : cork->fragsize; orig_mtu = mtu; hh_len = LL_RESERVED_SPACE(rt->dst.dev); @@ -1316,7 +1318,7 @@ static int __ip6_append_data(struct sock *sk, if (transhdrlen && sk->sk_protocol == IPPROTO_UDP && headersize == sizeof(struct ipv6hdr) && length <= mtu - headersize && - !(flags & MSG_MORE) && + (!(flags & MSG_MORE) || cork->gso_size) && rt->dst.dev->features & (NETIF_F_IPV6_CSUM | NETIF_F_HW_CSUM)) csummode = CHECKSUM_PARTIAL; diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index 4c2dd65ba97b..200b1b5130d7 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c @@ -1034,7 +1034,8 @@ static void udp6_hwcsum_outgoing(struct sock *sk, struct sk_buff *skb, * Sending */ -static int udp_v6_send_skb(struct sk_buff *skb, struct flowi6 *fl6) +static int udp_v6_send_skb(struct sk_buff *skb, struct flowi6 *fl6, + struct inet_cork *cork) { struct sock *sk = skb->sk; struct udphdr *uh; @@ -1053,6 +1054,21 @@ static int udp_v6_send_skb(struct sk_buff *skb, struct flowi6 *fl6) uh->len = htons(len); uh->check = 0; + if (cork->gso_size) { + const int hlen = skb_network_header_len(skb) + + sizeof(struct udphdr); + + if (hlen + cork->gso_size > cork->fragsize) + return -EINVAL; + if (skb->len > cork->gso_size * UDP_MAX_SEGMENTS) + return -EINVAL; + if (skb->ip_summed != CHECKSUM_PARTIAL || is_udplite) + return -EIO; + + skb_shinfo(skb)->gso_size = cork->gso_size; + skb_shinfo(skb)->gso_type = SKB_GSO_UDP_L4; + } + if (is_udplite) csum = udplite_csum(skb); else if (udp_sk(sk)->no_check6_tx) { /* UDP csum disabled */ @@ -1104,7 +1120,7 @@ static int udp_v6_push_pending_frames(struct sock *sk) if (!skb) goto out; - err = udp_v6_send_skb(skb, &fl6); + err = udp_v6_send_skb(skb, &fl6, &inet_sk(sk)->cork.base); out: up->len = 0; @@ -1138,6 +1154,7 @@ int udpv6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len) ipc6.hlimit = -1; ipc6.tclass = -1; ipc6.dontfrag = -1; + ipc6.gso_size = up->gso_size; sockc.tsflags = sk->sk_tsflags; /* destination address check */ @@ -1344,7 +1361,7 @@ int udpv6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len) msg->msg_flags, &cork, &sockc); err = PTR_ERR(skb); if (!IS_ERR_OR_NULL(skb)) - err = udp_v6_send_skb(skb, &fl6); + err = udp_v6_send_skb(skb, &fl6, &cork.base); goto release_dst; } -- GitLab From fa5b13be9287e0d95a6edb75022f25c567ea3737 Mon Sep 17 00:00:00 2001 From: Willem de Bruijn Date: Thu, 26 Apr 2018 13:42:18 -0400 Subject: [PATCH 1489/1635] udp: better wmem accounting on gso skb_segment by default transfers allocated wmem from the gso skb to the tail of the segment list. This underreports real truesize of the list, especially if the tail might be dropped. Similar to tcp_gso_segment, update wmem_alloc with the aggregate list truesize and make each segment responsible for its own share by setting skb->destructor. Clear gso_skb->destructor prior to calling skb_segment to skip the default assignment to tail. Change-Id: I8f36b6d134f35fa9e4cbb012fcc9a3efcc91ba55 Signed-off-by: Willem de Bruijn Signed-off-by: David S. Miller Git-commit: ad405857b174ed31a97982bb129c320d03321cf5 Git-repo: https://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next.git Signed-off-by: Sean Tranchetti --- net/ipv4/udp_offload.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/net/ipv4/udp_offload.c b/net/ipv4/udp_offload.c index 6b09220ca407..d806529b9b3d 100644 --- a/net/ipv4/udp_offload.c +++ b/net/ipv4/udp_offload.c @@ -191,6 +191,8 @@ struct sk_buff *__udp_gso_segment(struct sk_buff *gso_skb, netdev_features_t features, unsigned int mss, __sum16 check) { + struct sock *sk = gso_skb->sk; + unsigned int sum_truesize = 0; struct sk_buff *segs, *seg; unsigned int hdrlen; struct udphdr *uh; @@ -201,9 +203,15 @@ struct sk_buff *__udp_gso_segment(struct sk_buff *gso_skb, hdrlen = gso_skb->data - skb_mac_header(gso_skb); skb_pull(gso_skb, sizeof(*uh)); + /* clear destructor to avoid skb_segment assigning it to tail */ + WARN_ON_ONCE(gso_skb->destructor != sock_wfree); + gso_skb->destructor = NULL; + segs = skb_segment(gso_skb, features); - if (unlikely(IS_ERR_OR_NULL(segs))) + if (unlikely(IS_ERR_OR_NULL(segs))) { + gso_skb->destructor = sock_wfree; return segs; + } for (seg = segs; seg; seg = seg->next) { uh = udp_hdr(seg); @@ -214,8 +222,14 @@ struct sk_buff *__udp_gso_segment(struct sk_buff *gso_skb, if (!seg->next) csum_replace2(&uh->check, htons(mss), htons(seg->len - hdrlen - sizeof(*uh))); + + seg->destructor = sock_wfree; + seg->sk = sk; + sum_truesize += seg->truesize; } + refcount_add(sum_truesize - gso_skb->truesize, &sk->sk_wmem_alloc); + return segs; } -- GitLab From 8ca26b213ac57451b7ea5e78bcfeeeffc321356c Mon Sep 17 00:00:00 2001 From: Willem de Bruijn Date: Thu, 26 Apr 2018 13:42:19 -0400 Subject: [PATCH 1490/1635] udp: paged allocation with gso When sending large datagrams that are later segmented, store data in page frags to avoid copying from linear in skb_segment. Change-Id: Iac57a69872655bc4f375260ddb2c9f0f06153cf4 Signed-off-by: Willem de Bruijn Signed-off-by: David S. Miller Git-commit: 15e36f5b8e982debe43e425d2e12d34e022d51e9 Git-repo: https://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next.git Signed-off-by: Sean Tranchetti --- net/ipv4/ip_output.c | 15 +++++++++++---- net/ipv6/ip6_output.c | 19 ++++++++++++++----- 2 files changed, 25 insertions(+), 9 deletions(-) diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index ef34a6d128d8..5ce268784a6e 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -877,11 +877,13 @@ static int __ip_append_data(struct sock *sk, int csummode = CHECKSUM_NONE; struct rtable *rt = (struct rtable *)cork->dst; u32 tskey = 0; + bool paged; skb = skb_peek_tail(queue); exthdrlen = !skb ? rt->dst.header_len : 0; mtu = cork->gso_size ? IP_MAX_MTU : cork->fragsize; + paged = !!cork->gso_size; if (cork->tx_flags & SKBTX_ANY_SW_TSTAMP && sk->sk_tsflags & SOF_TIMESTAMPING_OPT_ID) @@ -933,6 +935,7 @@ static int __ip_append_data(struct sock *sk, unsigned int fraglen; unsigned int fraggap; unsigned int alloclen; + unsigned int pagedlen = 0; struct sk_buff *skb_prev; alloc_new_skb: skb_prev = skb; @@ -953,8 +956,12 @@ static int __ip_append_data(struct sock *sk, if ((flags & MSG_MORE) && !(rt->dst.dev->features&NETIF_F_SG)) alloclen = mtu; - else + else if (!paged) alloclen = fraglen; + else { + alloclen = min_t(int, fraglen, MAX_HEADER); + pagedlen = fraglen - alloclen; + } alloclen += exthdrlen; @@ -999,7 +1006,7 @@ static int __ip_append_data(struct sock *sk, /* * Find where to start putting bytes. */ - data = skb_put(skb, fraglen + exthdrlen); + data = skb_put(skb, fraglen + exthdrlen - pagedlen); skb_set_network_header(skb, exthdrlen); skb->transport_header = (skb->network_header + fragheaderlen); @@ -1015,7 +1022,7 @@ static int __ip_append_data(struct sock *sk, pskb_trim_unique(skb_prev, maxfraglen); } - copy = datalen - transhdrlen - fraggap; + copy = datalen - transhdrlen - fraggap - pagedlen; if (copy > 0 && getfrag(from, data + transhdrlen, offset, copy, fraggap, skb) < 0) { err = -EFAULT; kfree_skb(skb); @@ -1023,7 +1030,7 @@ static int __ip_append_data(struct sock *sk, } offset += copy; - length -= datalen - fraggap; + length -= copy + transhdrlen; transhdrlen = 0; exthdrlen = 0; csummode = CHECKSUM_NONE; diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index b56aa46761f3..7c50c8317459 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -1263,6 +1263,7 @@ static int __ip6_append_data(struct sock *sk, struct ipv6_txoptions *opt = v6_cork->opt; int csummode = CHECKSUM_NONE; unsigned int maxnonfragsize, headersize; + bool paged; skb = skb_peek_tail(queue); if (!skb) { @@ -1270,6 +1271,7 @@ static int __ip6_append_data(struct sock *sk, dst_exthdrlen = rt->dst.header_len - rt->rt6i_nfheader_len; } + paged = !!cork->gso_size; mtu = cork->gso_size ? IP6_MAX_MTU : cork->fragsize; orig_mtu = mtu; @@ -1361,6 +1363,7 @@ static int __ip6_append_data(struct sock *sk, unsigned int fraglen; unsigned int fraggap; unsigned int alloclen; + unsigned int pagedlen = 0; alloc_new_skb: /* There's no room in the current skb */ if (skb) @@ -1383,11 +1386,17 @@ static int __ip6_append_data(struct sock *sk, if (datalen > (cork->length <= mtu && !(cork->flags & IPCORK_ALLFRAG) ? mtu : maxfraglen) - fragheaderlen) datalen = maxfraglen - fragheaderlen - rt->dst.trailer_len; + fraglen = datalen + fragheaderlen; + if ((flags & MSG_MORE) && !(rt->dst.dev->features&NETIF_F_SG)) alloclen = mtu; - else - alloclen = datalen + fragheaderlen; + else if (!paged) + alloclen = fraglen; + else { + alloclen = min_t(int, fraglen, MAX_HEADER); + pagedlen = fraglen - alloclen; + } alloclen += dst_exthdrlen; @@ -1409,7 +1418,7 @@ static int __ip6_append_data(struct sock *sk, */ alloclen += sizeof(struct frag_hdr); - copy = datalen - transhdrlen - fraggap; + copy = datalen - transhdrlen - fraggap - pagedlen; if (copy < 0) { err = -EINVAL; goto error; @@ -1449,7 +1458,7 @@ static int __ip6_append_data(struct sock *sk, /* * Find where to start putting bytes */ - data = skb_put(skb, fraglen); + data = skb_put(skb, fraglen - pagedlen); skb_set_network_header(skb, exthdrlen); data += fragheaderlen; skb->transport_header = (skb->network_header + @@ -1472,7 +1481,7 @@ static int __ip6_append_data(struct sock *sk, } offset += copy; - length -= datalen - fraggap; + length -= copy + transhdrlen; transhdrlen = 0; exthdrlen = 0; dst_exthdrlen = 0; -- GitLab From fcfec3354b1232fa71fd173c5e77ba69223504e0 Mon Sep 17 00:00:00 2001 From: Willem de Bruijn Date: Thu, 26 Apr 2018 13:42:20 -0400 Subject: [PATCH 1491/1635] udp: add gso segment cmsg Allow specifying segment size in the send call. The new control message performs the same function as socket option UDP_SEGMENT while avoiding the extra system call. Change-Id: I335dfba959d264ee181f6bc8da29cebb7685e7e1 Signed-off-by: Willem de Bruijn Signed-off-by: David S. Miller Git-commit: 2e8de8576343ab540856082916bfb84d17288b08 Git-repo: https://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next.git Signed-off-by: Sean Tranchetti --- include/net/udp.h | 1 + net/ipv4/udp.c | 43 +++++++++++++++++++++++++++++++++++++++++-- net/ipv6/udp.c | 5 ++++- 3 files changed, 46 insertions(+), 3 deletions(-) diff --git a/include/net/udp.h b/include/net/udp.h index 9126e0d53500..c5e986ab5c73 100644 --- a/include/net/udp.h +++ b/include/net/udp.h @@ -273,6 +273,7 @@ int udp_abort(struct sock *sk, int err); int udp_sendmsg(struct sock *sk, struct msghdr *msg, size_t len); int udp_push_pending_frames(struct sock *sk); void udp_flush_pending_frames(struct sock *sk); +int udp_cmsg_send(struct sock *sk, struct msghdr *msg, u16 *gso_size); void udp4_hwcsum(struct sk_buff *skb, __be32 src, __be32 dst); int udp_rcv(struct sk_buff *skb); int udp_ioctl(struct sock *sk, int cmd, unsigned long arg); diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 478db7a34ab6..c7c43a1922a6 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -884,6 +884,42 @@ int udp_push_pending_frames(struct sock *sk) } EXPORT_SYMBOL(udp_push_pending_frames); +static int __udp_cmsg_send(struct cmsghdr *cmsg, u16 *gso_size) +{ + switch (cmsg->cmsg_type) { + case UDP_SEGMENT: + if (cmsg->cmsg_len != CMSG_LEN(sizeof(__u16))) + return -EINVAL; + *gso_size = *(__u16 *)CMSG_DATA(cmsg); + return 0; + default: + return -EINVAL; + } +} + +int udp_cmsg_send(struct sock *sk, struct msghdr *msg, u16 *gso_size) +{ + struct cmsghdr *cmsg; + bool need_ip = false; + int err; + + for_each_cmsghdr(cmsg, msg) { + if (!CMSG_OK(msg, cmsg)) + return -EINVAL; + + if (cmsg->cmsg_level != SOL_UDP) { + need_ip = true; + continue; + } + + err = __udp_cmsg_send(cmsg, gso_size); + if (err) + return err; + } + + return need_ip; +} + int udp_sendmsg(struct sock *sk, struct msghdr *msg, size_t len) { struct inet_sock *inet = inet_sk(sk); @@ -972,8 +1008,11 @@ int udp_sendmsg(struct sock *sk, struct msghdr *msg, size_t len) ipc.gso_size = up->gso_size; if (msg->msg_controllen) { - err = ip_cmsg_send(sk, msg, &ipc, sk->sk_family == AF_INET6); - if (unlikely(err)) { + err = udp_cmsg_send(sk, msg, &ipc.gso_size); + if (err > 0) + err = ip_cmsg_send(sk, msg, &ipc, + sk->sk_family == AF_INET6); + if (unlikely(err < 0)) { kfree(ipc.opt); return err; } diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index 200b1b5130d7..a8f5c04bbaff 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c @@ -1287,7 +1287,10 @@ int udpv6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len) opt->tot_len = sizeof(*opt); ipc6.opt = opt; - err = ip6_datagram_send_ctl(sock_net(sk), sk, msg, &fl6, &ipc6, &sockc); + err = udp_cmsg_send(sk, msg, &ipc6.gso_size); + if (err > 0) + err = ip6_datagram_send_ctl(sock_net(sk), sk, msg, &fl6, + &ipc6, &sockc); if (err < 0) { fl6_sock_release(flowlabel); return err; -- GitLab From d60dea92703e5d4c9819317c649c319d17b1a3c9 Mon Sep 17 00:00:00 2001 From: Willem de Bruijn Date: Thu, 26 Apr 2018 13:42:21 -0400 Subject: [PATCH 1492/1635] udp: add gso support to virtual devices Virtual devices such as tunnels and bonding can handle large packets. Only segment packets when reaching a physical or loopback device. Change-Id: I70a98ff455780a45ce3baea7b97e823716509802 Signed-off-by: Willem de Bruijn Signed-off-by: David S. Miller Git-commit: 83aa025f535f76733e334e3d2a4d8577c8441a7e Git-repo: https://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next.git Signed-off-by: Sean Tranchetti --- Documentation/networking/netdev-features.txt | 7 +++++++ include/linux/netdev_features.h | 5 ++++- include/linux/netdevice.h | 1 + net/core/ethtool.c | 1 + 4 files changed, 13 insertions(+), 1 deletion(-) diff --git a/Documentation/networking/netdev-features.txt b/Documentation/networking/netdev-features.txt index 7413eb05223b..dfb2707c7fa4 100644 --- a/Documentation/networking/netdev-features.txt +++ b/Documentation/networking/netdev-features.txt @@ -113,6 +113,13 @@ whatever headers there might be. NETIF_F_TSO_ECN means that hardware can properly split packets with CWR bit set, be it TCPv4 (when NETIF_F_TSO is enabled) or TCPv6 (NETIF_F_TSO6). + * Transmit UDP segmentation offload + +NETIF_F_GSO_UDP_GSO_L4 accepts a single UDP header with a payload that exceeds +gso_size. On segmentation, it segments the payload on gso_size boundaries and +replicates the network and UDP headers (fixing up the last one if less than +gso_size). + * Transmit DMA from high memory On platforms where this is relevant, NETIF_F_HIGHDMA signals that diff --git a/include/linux/netdev_features.h b/include/linux/netdev_features.h index b1b0ca7ccb2b..284f2822b740 100644 --- a/include/linux/netdev_features.h +++ b/include/linux/netdev_features.h @@ -55,8 +55,9 @@ enum { NETIF_F_GSO_SCTP_BIT, /* ... SCTP fragmentation */ NETIF_F_GSO_ESP_BIT, /* ... ESP with TSO */ NETIF_F_GSO_UDP_BIT, /* ... UFO, deprecated except tuntap */ + NETIF_F_GSO_UDP_L4_BIT, /* ... UDP payload GSO (not UFO) */ /**/NETIF_F_GSO_LAST = /* last bit, see GSO_MASK */ - NETIF_F_GSO_UDP_BIT, + NETIF_F_GSO_UDP_L4_BIT, NETIF_F_FCOE_CRC_BIT, /* FCoE CRC32 */ NETIF_F_SCTP_CRC_BIT, /* SCTP checksum offload */ @@ -142,6 +143,7 @@ enum { #define NETIF_F_HW_ESP __NETIF_F(HW_ESP) #define NETIF_F_HW_ESP_TX_CSUM __NETIF_F(HW_ESP_TX_CSUM) #define NETIF_F_RX_UDP_TUNNEL_PORT __NETIF_F(RX_UDP_TUNNEL_PORT) +#define NETIF_F_GSO_UDP_L4 __NETIF_F(GSO_UDP_L4) #define for_each_netdev_feature(mask_addr, bit) \ for_each_set_bit(bit, (unsigned long *)mask_addr, NETDEV_FEATURE_COUNT) @@ -211,6 +213,7 @@ enum { NETIF_F_GSO_GRE_CSUM | \ NETIF_F_GSO_IPXIP4 | \ NETIF_F_GSO_IPXIP6 | \ + NETIF_F_GSO_UDP_L4 | \ NETIF_F_GSO_UDP_TUNNEL | \ NETIF_F_GSO_UDP_TUNNEL_CSUM) diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 48d0aa647eb3..fa7ee2e6c827 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -4106,6 +4106,7 @@ static inline bool net_gso_ok(netdev_features_t features, int gso_type) BUILD_BUG_ON(SKB_GSO_SCTP != (NETIF_F_GSO_SCTP >> NETIF_F_GSO_SHIFT)); BUILD_BUG_ON(SKB_GSO_ESP != (NETIF_F_GSO_ESP >> NETIF_F_GSO_SHIFT)); BUILD_BUG_ON(SKB_GSO_UDP != (NETIF_F_GSO_UDP >> NETIF_F_GSO_SHIFT)); + BUILD_BUG_ON(SKB_GSO_UDP_L4 != (NETIF_F_GSO_UDP_L4 >> NETIF_F_GSO_SHIFT)); return (features & feature) == feature; } diff --git a/net/core/ethtool.c b/net/core/ethtool.c index 373f7ebd1629..9563358f928d 100644 --- a/net/core/ethtool.c +++ b/net/core/ethtool.c @@ -90,6 +90,7 @@ static const char netdev_features_strings[NETDEV_FEATURE_COUNT][ETH_GSTRING_LEN] [NETIF_F_GSO_PARTIAL_BIT] = "tx-gso-partial", [NETIF_F_GSO_SCTP_BIT] = "tx-sctp-segmentation", [NETIF_F_GSO_ESP_BIT] = "tx-esp-segmentation", + [NETIF_F_GSO_UDP_L4_BIT] = "tx-udp-segmentation", [NETIF_F_FCOE_CRC_BIT] = "tx-checksum-fcoe-crc", [NETIF_F_SCTP_CRC_BIT] = "tx-checksum-sctp", -- GitLab From 1cc0e6eea6c5f362d78b262604e79f97cdf7c364 Mon Sep 17 00:00:00 2001 From: Sean Tranchetti Date: Mon, 30 Apr 2018 17:22:50 -0600 Subject: [PATCH 1493/1635] udp: Complement partial checksum for GSO packet Using the udp_v4_check() function to calculate the pseudo header for the newly segmented UDP packets results in assigning the complement of the value to the UDP header checksum field. Always undo the complement the partial checksum value in order to match the case where GSO is not used on the UDP transmit path. Change-Id: Iba9e8f1e7a2a134bcac02b8f366755e6b2e03fb5 Fixes: ee80d1ebe5ba ("udp: add udp gso") Signed-off-by: Sean Tranchetti Acked-by: Willem de Bruijn Signed-off-by: David S. Miller Git-commit: 6c035ba7e73aba4536a1112f9a0901ab40aab460 Git-repo: https://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next.git Signed-off-by: Sean Tranchetti --- net/ipv4/udp_offload.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/ipv4/udp_offload.c b/net/ipv4/udp_offload.c index d806529b9b3d..c4724f2a2f31 100644 --- a/net/ipv4/udp_offload.c +++ b/net/ipv4/udp_offload.c @@ -223,6 +223,7 @@ struct sk_buff *__udp_gso_segment(struct sk_buff *gso_skb, csum_replace2(&uh->check, htons(mss), htons(seg->len - hdrlen - sizeof(*uh))); + uh->check = ~uh->check; seg->destructor = sock_wfree; seg->sk = sk; sum_truesize += seg->truesize; -- GitLab From 6cd07873e93918e5beb971504db8b3031c874c22 Mon Sep 17 00:00:00 2001 From: "Raju P.L.S.S.S.N" Date: Tue, 31 Oct 2017 16:50:30 +0530 Subject: [PATCH 1494/1635] soc: qcom: Add RPM SMD Driver This is a snapshot of the RPM-SMD driver functionality as of 'commit 9c23726ad4df ("leds: qpnp-flash: Fix 11 Use-after-free(UAF) for debugfs")' on msm-4.4 branch. Change-Id: I502300cf26b67679a9344a89b2feaa0dbcc5fb59 Signed-off-by: Raju P.L.S.S.S.N --- Documentation/arm/msm/rpm.txt | 157 ++ .../devicetree/bindings/arm/msm/rpm-smd.txt | 41 + drivers/soc/qcom/Kconfig | 8 + drivers/soc/qcom/Makefile | 4 + drivers/soc/qcom/rpm-smd-debug.c | 151 ++ drivers/soc/qcom/rpm-smd.c | 2165 +++++++++++++++++ include/soc/qcom/rpm-notifier.h | 63 + include/soc/qcom/rpm-smd.h | 494 ++++ include/trace/events/trace_rpm_smd.h | 111 + 9 files changed, 3194 insertions(+) create mode 100644 Documentation/arm/msm/rpm.txt create mode 100644 Documentation/devicetree/bindings/arm/msm/rpm-smd.txt create mode 100644 drivers/soc/qcom/rpm-smd-debug.c create mode 100644 drivers/soc/qcom/rpm-smd.c create mode 100644 include/soc/qcom/rpm-notifier.h create mode 100644 include/soc/qcom/rpm-smd.h create mode 100644 include/trace/events/trace_rpm_smd.h diff --git a/Documentation/arm/msm/rpm.txt b/Documentation/arm/msm/rpm.txt new file mode 100644 index 000000000000..d5be6a7e2890 --- /dev/null +++ b/Documentation/arm/msm/rpm.txt @@ -0,0 +1,157 @@ +Introduction +============ + +Resource Power Manager (RPM) + +RPM is a dedicated hardware engine for managing shared SoC resources, +which includes buses, clocks, power rails, etc. The goal of RPM is +to achieve the maximum power savings while satisfying the SoC's +operational and performance requirements. RPM accepts resource +requests from multiple RPM masters. It arbitrates and aggregates the +requests, and configures the shared resources. The RPM masters are +the application processor, the modem processor, as well as some +hardware accelerators. + +The RPM driver provides an API for interacting with RPM. Kernel code +calls the RPM driver to request RPM-managed, shared resources. +Kernel code can also register with the driver for RPM notifications, +which are sent when the status of shared resources change. + +Hardware description +==================== + +RPM exposes a separate region of registers to each of the RPM masters. +In general, each register represents some shared resource(s). At a +very basic level, a master requests resources by writing to the +registers, then generating an interrupt to RPM. RPM processes the +request, writes acknowledgment to the registers, then generates an +interrupt to the master. + +In addition to the master-specific regions, RPM also exposes a shared +region that contains the current status of the shared resources. Only +RPM can write to the status region, but every master can read from it. + +RPM contains internal logics that aggregate and arbitrate among +requests from the various RPM masters. It interfaces with the PMIC, +the bus arbitration block, and the clock controller block in order to +configure the shared resources. + +Software description +==================== + +The RPM driver encapsulates the low level RPM interactions, which +rely on reading/writing registers and generating/processing +interrupts, and provides a higher level synchronuous set/clear/get +interface. Most functions take an array of id-value pairs. +The ids identify the RPM registers which would correspond to some +RPM resources, the values specify the new resource values. + +The RPM driver synchronizes accesses to RPM. It protects against +simultaneous accesses from multiple tasks, on SMP cores, in task +contexts, and in atomic contexts. + +Design +====== + +Design goals: +- Encapsulate low level RPM interactions. +- Provide a synchronuous set/clear/get interface. +- Synchronize simultaneous software accesses to RPM. + +Power Management +================ + +RPM is part of the power management architecture for MSM 8660. RPM +manages shared system resources to lower system power. + +SMP/multi-core +============== + +The RPM driver uses mutex to synchronize client accesses among tasks. +It uses spinlocks to synchronize accesses from atomic contexts and +SMP cores. + +Security +======== + +None. + +Performance +=========== + +None. + +Interface +========= + +msm_rpm_get_status(): +The function reads the shared status region and returns the current +resource values, which are the arbitrated/aggregated results across +all RPM masters. + +msm_rpm_set(): +The function makes a resource request to RPM. + +msm_rpm_set_noirq(): +The function is similar to msm_rpm_set() except that it must be +called with interrupts masked. If possible, use msm_rpm_set() +instead, to maximize CPU throughput. + +msm_rpm_clear(): +The function makes a resource request to RPM to clear resource values. +Once the values are cleared, the resources revert back to their default +values for this RPM master. RPM internally uses the default values as +the requests from this RPM master when arbitrating and aggregating with +requests from other RPM masters. + +msm_rpm_clear_noirq(): +The function is similar to msm_rpm_clear() except that it must be +called with interrupts masked. If possible, use msm_rpm_clear() +instead, to maximize CPU throughput. + +msm_rpm_register_notification(): +The function registers for RPM notification. When the specified +resources change their status on RPM, RPM sends out notifications +and the driver will "up" the semaphore in struct +msm_rpm_notification. + +msm_rpm_unregister_notification(): +The function unregisters a notification. + +msm_rpm_init(): +The function initializes the RPM driver with platform specific data. + +Driver parameters +================= + +None. + +Config options +============== + +MSM_RPM + +Dependencies +============ + +None. + +User space utilities +==================== + +None. + +Other +===== + +None. + +Known issues +============ + +None. + +To do +===== + +None. diff --git a/Documentation/devicetree/bindings/arm/msm/rpm-smd.txt b/Documentation/devicetree/bindings/arm/msm/rpm-smd.txt new file mode 100644 index 000000000000..4cba3ecaeb90 --- /dev/null +++ b/Documentation/devicetree/bindings/arm/msm/rpm-smd.txt @@ -0,0 +1,41 @@ +Resource Power Manager(RPM) + +RPM is a dedicated hardware engine for managing shared SoC resources, +which includes buses, clocks, power rails, etc. The goal of RPM is +to achieve the maximum power savings while satisfying the SoC's +operational and performance requirements. RPM accepts resource +requests from multiple RPM masters. It arbitrates and aggregates the +requests, and configures the shared resources. The RPM masters are +the application processor, the modem processor, as well as hardware +accelerators. The RPM driver communicates with the hardware engine using +SMD. + +The devicetree representation of the SPM block should be: + +Required properties + +- compatible: "qcom,rpm-smd" or "qcom,rpm-glink" +- rpm-channel-name: The string corresponding to the channel name of the + peripheral subsystem. Required for both smd and + glink transports. +- rpm-channel-type: The interal SMD edge for this subsystem found in + +- qcom,glink-edge: Logical name of the remote subsystem. This is a required + property when rpm-smd driver using glink as trasport. + +Optional properties +- rpm-standalone: Allow RPM driver to run in standalone mode irrespective of RPM + channel presence. +- reg: Contains the memory address at which rpm messaging format version is + stored. If this field is not present, the target only supports v0 format. + +Example: + + qcom,rpm-smd@68150 { + compatible = "qcom,rpm-smd", "qcom,rpm-glink"; + reg = <0x68150 0x3200>; + qcom,rpm-channel-name = "rpm_requests"; + qcom,rpm-channel-type = 15; /* SMD_APPS_RPM */ + qcom,glink-edge = "rpm"; + } +} diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig index 3c04d023fb54..e70525c3465a 100644 --- a/drivers/soc/qcom/Kconfig +++ b/drivers/soc/qcom/Kconfig @@ -406,6 +406,14 @@ config MINIDUMP_MAX_ENTRIES help This defines maximum number of entries to be allocated for application subsytem in Minidump table. +config MSM_RPM_SMD + bool "RPM driver using SMD protocol" + help + RPM is the dedicated hardware engine for managing shared SoC + resources. This config adds driver support for using SMD as a + transport layer communication with RPM hardware. It also selects + the MSM_MPM config that programs the MPM module to monitor interrupts + during sleep modes. config QCOM_BUS_SCALING bool "Bus scaling driver" diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile index 9c995f1f799b..e00336f11482 100644 --- a/drivers/soc/qcom/Makefile +++ b/drivers/soc/qcom/Makefile @@ -75,3 +75,7 @@ ifdef CONFIG_QTI_RPMH_API endif obj-$(CONFIG_QMP_DEBUGFS_CLIENT) += qmp-debugfs-client.o obj-$(CONFIG_MSM_PERFORMANCE) += msm_performance.o +obj-$(CONFIG_MSM_RPM_SMD) += rpm-smd.o +ifdef CONFIG_DEBUG_FS +obj-$(CONFIG_MSM_RPM_SMD) += rpm-smd-debug.o +endif diff --git a/drivers/soc/qcom/rpm-smd-debug.c b/drivers/soc/qcom/rpm-smd-debug.c new file mode 100644 index 000000000000..6ae9f088e52d --- /dev/null +++ b/drivers/soc/qcom/rpm-smd-debug.c @@ -0,0 +1,151 @@ +/* Copyright (c) 2013-2014, 2017, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#define pr_fmt(fmt) "rpm-smd-debug: %s(): " fmt, __func__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MAX_MSG_BUFFER 350 +#define MAX_KEY_VALUE_PAIRS 20 + +static struct dentry *rpm_debugfs_dir; + +static u32 string_to_uint(const u8 *str) +{ + int i, len; + u32 output = 0; + + len = strnlen(str, sizeof(u32)); + for (i = 0; i < len; i++) + output |= str[i] << (i * 8); + + return output; +} + +static ssize_t rsc_ops_write(struct file *fp, const char __user *user_buffer, + size_t count, loff_t *position) +{ + char buf[MAX_MSG_BUFFER], rsc_type_str[6] = {}, rpm_set[8] = {}, + key_str[6] = {}; + int i, pos = -1, set = -1, nelems = -1; + char *cmp; + uint32_t rsc_type = 0, rsc_id = 0, key = 0, data = 0; + struct msm_rpm_request *req; + + count = min(count, sizeof(buf) - 1); + if (copy_from_user(&buf, user_buffer, count)) + return -EFAULT; + buf[count] = '\0'; + cmp = strstrip(buf); + + if (sscanf(cmp, "%7s %5s %u %d %n", rpm_set, rsc_type_str, + &rsc_id, &nelems, &pos) != 4) { + pr_err("Invalid number of arguments passed\n"); + goto err; + } + + if (strlen(rpm_set) > 6 || strlen(rsc_type_str) > 4) { + pr_err("Invalid value of set or resource type\n"); + goto err; + } + + if (!strcmp(rpm_set, "active")) + set = 0; + else if (!strcmp(rpm_set, "sleep")) + set = 1; + + rsc_type = string_to_uint(rsc_type_str); + + if (set < 0 || nelems < 0) { + pr_err("Invalid value of set or nelems\n"); + goto err; + } + if (nelems > MAX_KEY_VALUE_PAIRS) { + pr_err("Exceeded max no of key-value entries\n"); + goto err; + } + + req = msm_rpm_create_request(set, rsc_type, rsc_id, nelems); + if (!req) + return -ENOMEM; + + for (i = 0; i < nelems; i++) { + cmp += pos; + if (sscanf(cmp, "%5s %n", key_str, &pos) != 1) { + pr_err("Invalid number of arguments passed\n"); + goto err; + } + + if (strlen(key_str) > 4) { + pr_err("Key value cannot be more than 4 charecters"); + goto err; + } + key = string_to_uint(key_str); + if (!key) { + pr_err("Key values entered incorrectly\n"); + goto err; + } + + cmp += pos; + if (sscanf(cmp, "%u %n", &data, &pos) != 1) { + pr_err("Invalid number of arguments passed\n"); + goto err; + } + + if (msm_rpm_add_kvp_data(req, key, + (void *)&data, sizeof(data))) + goto err_request; + } + + if (msm_rpm_wait_for_ack(msm_rpm_send_request(req))) + pr_err("Sending the RPM message failed\n"); + +err_request: + msm_rpm_free_request(req); +err: + return count; +} + +static const struct file_operations rsc_ops = { + .write = rsc_ops_write, +}; + +static int __init rpm_smd_debugfs_init(void) +{ + rpm_debugfs_dir = debugfs_create_dir("rpm_send_msg", NULL); + if (!rpm_debugfs_dir) + return -ENOMEM; + + if (!debugfs_create_file("message", 0200, rpm_debugfs_dir, NULL, + &rsc_ops)) + return -ENOMEM; + + return 0; +} +late_initcall(rpm_smd_debugfs_init); + +static void __exit rpm_smd_debugfs_exit(void) +{ + debugfs_remove_recursive(rpm_debugfs_dir); +} +module_exit(rpm_smd_debugfs_exit); + +MODULE_DESCRIPTION("RPM SMD Debug Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/soc/qcom/rpm-smd.c b/drivers/soc/qcom/rpm-smd.c new file mode 100644 index 000000000000..c04916cfbd77 --- /dev/null +++ b/drivers/soc/qcom/rpm-smd.c @@ -0,0 +1,2165 @@ +/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#define pr_fmt(fmt) "%s: " fmt, __func__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define CREATE_TRACE_POINTS +#include + +/* Debug Definitions */ +enum { + MSM_RPM_LOG_REQUEST_PRETTY = BIT(0), + MSM_RPM_LOG_REQUEST_RAW = BIT(1), + MSM_RPM_LOG_REQUEST_SHOW_MSG_ID = BIT(2), +}; + +static int msm_rpm_debug_mask; +module_param_named( + debug_mask, msm_rpm_debug_mask, int, 0644 +); + +struct msm_rpm_driver_data { + const char *ch_name; + uint32_t ch_type; + struct smd_channel *ch_info; + struct work_struct work; + spinlock_t smd_lock_write; + spinlock_t smd_lock_read; + struct completion smd_open; +}; + +struct glink_apps_rpm_data { + const char *name; + const char *edge; + const char *xprt; + void *glink_handle; + struct glink_link_info *link_info; + struct glink_open_config *open_cfg; + struct work_struct work; +}; + +static bool glink_enabled; +static struct glink_apps_rpm_data *glink_data; + +#define DEFAULT_BUFFER_SIZE 256 +#define DEBUG_PRINT_BUFFER_SIZE 512 +#define MAX_SLEEP_BUFFER 128 +#define GFP_FLAG(noirq) (noirq ? GFP_ATOMIC : GFP_NOIO) +#define INV_RSC "resource does not exist" +#define ERR "err\0" +#define MAX_ERR_BUFFER_SIZE 128 +#define MAX_WAIT_ON_ACK 24 +#define INIT_ERROR 1 +#define V1_PROTOCOL_VERSION 0x31726576 /* rev1 */ +#define V0_PROTOCOL_VERSION 0 /* rev0 */ +#define RPM_MSG_TYPE_OFFSET 16 +#define RPM_MSG_TYPE_SIZE 8 +#define RPM_SET_TYPE_OFFSET 28 +#define RPM_SET_TYPE_SIZE 4 +#define RPM_REQ_LEN_OFFSET 0 +#define RPM_REQ_LEN_SIZE 16 +#define RPM_MSG_VERSION_OFFSET 24 +#define RPM_MSG_VERSION_SIZE 8 +#define RPM_MSG_VERSION 1 +#define RPM_MSG_SET_OFFSET 28 +#define RPM_MSG_SET_SIZE 4 +#define RPM_RSC_ID_OFFSET 16 +#define RPM_RSC_ID_SIZE 12 +#define RPM_DATA_LEN_OFFSET 0 +#define RPM_DATA_LEN_SIZE 16 +#define RPM_HDR_SIZE ((rpm_msg_fmt_ver == RPM_MSG_V0_FMT) ?\ + sizeof(struct rpm_v0_hdr) : sizeof(struct rpm_v1_hdr)) +#define CLEAR_FIELD(offset, size) (~GENMASK(offset + size - 1, offset)) + +static ATOMIC_NOTIFIER_HEAD(msm_rpm_sleep_notifier); +static bool standalone; +static int probe_status = -EPROBE_DEFER; +static int msm_rpm_read_smd_data(char *buf); +static void msm_rpm_process_ack(uint32_t msg_id, int errno); + +int msm_rpm_register_notifier(struct notifier_block *nb) +{ + return atomic_notifier_chain_register(&msm_rpm_sleep_notifier, nb); +} + +int msm_rpm_unregister_notifier(struct notifier_block *nb) +{ + return atomic_notifier_chain_unregister(&msm_rpm_sleep_notifier, nb); +} + +static struct workqueue_struct *msm_rpm_smd_wq; + +enum { + MSM_RPM_MSG_REQUEST_TYPE = 0, + MSM_RPM_MSG_TYPE_NR, +}; + +static const uint32_t msm_rpm_request_service_v1[MSM_RPM_MSG_TYPE_NR] = { + 0x716572, /* 'req\0' */ +}; + +enum { + RPM_V1_REQUEST_SERVICE, + RPM_V1_SYSTEMDB_SERVICE, + RPM_V1_COMMAND_SERVICE, + RPM_V1_ACK_SERVICE, + RPM_V1_NACK_SERVICE, +} msm_rpm_request_service_v2; + +struct rpm_v0_hdr { + uint32_t service_type; + uint32_t request_len; +}; + +struct rpm_v1_hdr { + uint32_t request_hdr; +}; + +struct rpm_message_header_v0 { + struct rpm_v0_hdr hdr; + uint32_t msg_id; + enum msm_rpm_set set; + uint32_t resource_type; + uint32_t resource_id; + uint32_t data_len; +}; + +struct rpm_message_header_v1 { + struct rpm_v1_hdr hdr; + uint32_t msg_id; + uint32_t resource_type; + uint32_t request_details; +}; + +struct msm_rpm_ack_msg_v0 { + uint32_t req; + uint32_t req_len; + uint32_t rsc_id; + uint32_t msg_len; + uint32_t id_ack; +}; + +struct msm_rpm_ack_msg_v1 { + uint32_t request_hdr; + uint32_t id_ack; +}; + +struct kvp { + unsigned int k; + unsigned int s; +}; + +struct msm_rpm_kvp_data { + uint32_t key; + uint32_t nbytes; /* number of bytes */ + uint8_t *value; + bool valid; +}; + +struct slp_buf { + struct rb_node node; + char ubuf[MAX_SLEEP_BUFFER]; + char *buf; + bool valid; +}; + +enum rpm_msg_fmts { + RPM_MSG_V0_FMT, + RPM_MSG_V1_FMT +}; + +static uint32_t rpm_msg_fmt_ver; +module_param_named( + rpm_msg_fmt_ver, rpm_msg_fmt_ver, uint, 0444 +); + +static struct rb_root tr_root = RB_ROOT; +static int (*msm_rpm_send_buffer)(char *buf, uint32_t size, bool noirq); +static int msm_rpm_send_smd_buffer(char *buf, uint32_t size, bool noirq); +static int msm_rpm_glink_send_buffer(char *buf, uint32_t size, bool noirq); +static uint32_t msm_rpm_get_next_msg_id(void); + +static inline uint32_t get_offset_value(uint32_t val, uint32_t offset, + uint32_t size) +{ + return (((val) & GENMASK(offset + size - 1, offset)) + >> offset); +} + +static inline void change_offset_value(uint32_t *val, uint32_t offset, + uint32_t size, int32_t val1) +{ + uint32_t member = *val; + uint32_t offset_val = get_offset_value(member, offset, size); + uint32_t mask = (1 << size) - 1; + + offset_val += val1; + *val &= CLEAR_FIELD(offset, size); + *val |= ((offset_val & mask) << offset); +} + +static inline void set_offset_value(uint32_t *val, uint32_t offset, + uint32_t size, uint32_t val1) +{ + uint32_t mask = (1 << size) - 1; + + *val &= CLEAR_FIELD(offset, size); + *val |= ((val1 & mask) << offset); +} +static uint32_t get_msg_id(char *buf) +{ + if (rpm_msg_fmt_ver == RPM_MSG_V0_FMT) + return ((struct rpm_message_header_v0 *)buf)->msg_id; + + return ((struct rpm_message_header_v1 *)buf)->msg_id; + +} + +static uint32_t get_ack_msg_id(char *buf) +{ + if (rpm_msg_fmt_ver == RPM_MSG_V0_FMT) + return ((struct msm_rpm_ack_msg_v0 *)buf)->id_ack; + + return ((struct msm_rpm_ack_msg_v1 *)buf)->id_ack; + +} + +static uint32_t get_rsc_type(char *buf) +{ + if (rpm_msg_fmt_ver == RPM_MSG_V0_FMT) + return ((struct rpm_message_header_v0 *)buf)->resource_type; + + return ((struct rpm_message_header_v1 *)buf)->resource_type; + +} + +static uint32_t get_set_type(char *buf) +{ + if (rpm_msg_fmt_ver == RPM_MSG_V0_FMT) + return ((struct rpm_message_header_v0 *)buf)->set; + + return get_offset_value(((struct rpm_message_header_v1 *)buf)-> + request_details, RPM_SET_TYPE_OFFSET, + RPM_SET_TYPE_SIZE); +} + +static uint32_t get_data_len(char *buf) +{ + if (rpm_msg_fmt_ver == RPM_MSG_V0_FMT) + return ((struct rpm_message_header_v0 *)buf)->data_len; + + return get_offset_value(((struct rpm_message_header_v1 *)buf)-> + request_details, RPM_DATA_LEN_OFFSET, + RPM_DATA_LEN_SIZE); +} + +static uint32_t get_rsc_id(char *buf) +{ + if (rpm_msg_fmt_ver == RPM_MSG_V0_FMT) + return ((struct rpm_message_header_v0 *)buf)->resource_id; + + return get_offset_value(((struct rpm_message_header_v1 *)buf)-> + request_details, RPM_RSC_ID_OFFSET, + RPM_RSC_ID_SIZE); +} + +static uint32_t get_ack_req_len(char *buf) +{ + if (rpm_msg_fmt_ver == RPM_MSG_V0_FMT) + return ((struct msm_rpm_ack_msg_v0 *)buf)->req_len; + + return get_offset_value(((struct msm_rpm_ack_msg_v1 *)buf)-> + request_hdr, RPM_REQ_LEN_OFFSET, + RPM_REQ_LEN_SIZE); +} + +static uint32_t get_ack_msg_type(char *buf) +{ + if (rpm_msg_fmt_ver == RPM_MSG_V0_FMT) + return ((struct msm_rpm_ack_msg_v0 *)buf)->req; + + return get_offset_value(((struct msm_rpm_ack_msg_v1 *)buf)-> + request_hdr, RPM_MSG_TYPE_OFFSET, + RPM_MSG_TYPE_SIZE); +} + +static uint32_t get_req_len(char *buf) +{ + if (rpm_msg_fmt_ver == RPM_MSG_V0_FMT) + return ((struct rpm_message_header_v0 *)buf)->hdr.request_len; + + return get_offset_value(((struct rpm_message_header_v1 *)buf)-> + hdr.request_hdr, RPM_REQ_LEN_OFFSET, + RPM_REQ_LEN_SIZE); +} + +static void set_msg_ver(char *buf, uint32_t val) +{ + if (rpm_msg_fmt_ver) { + set_offset_value(&((struct rpm_message_header_v1 *)buf)-> + hdr.request_hdr, RPM_MSG_VERSION_OFFSET, + RPM_MSG_VERSION_SIZE, val); + } else { + set_offset_value(&((struct rpm_message_header_v1 *)buf)-> + hdr.request_hdr, RPM_MSG_VERSION_OFFSET, + RPM_MSG_VERSION_SIZE, 0); + } +} + +static void set_req_len(char *buf, uint32_t val) +{ + if (rpm_msg_fmt_ver == RPM_MSG_V0_FMT) { + ((struct rpm_message_header_v0 *)buf)->hdr.request_len = val; + } else { + set_offset_value(&((struct rpm_message_header_v1 *)buf)-> + hdr.request_hdr, RPM_REQ_LEN_OFFSET, + RPM_REQ_LEN_SIZE, val); + } +} + +static void change_req_len(char *buf, int32_t val) +{ + if (rpm_msg_fmt_ver == RPM_MSG_V0_FMT) { + ((struct rpm_message_header_v0 *)buf)->hdr.request_len += val; + } else { + change_offset_value(&((struct rpm_message_header_v1 *)buf)-> + hdr.request_hdr, RPM_REQ_LEN_OFFSET, + RPM_REQ_LEN_SIZE, val); + } +} + +static void set_msg_type(char *buf, uint32_t val) +{ + if (rpm_msg_fmt_ver == RPM_MSG_V0_FMT) { + ((struct rpm_message_header_v0 *)buf)->hdr.service_type = + msm_rpm_request_service_v1[val]; + } else { + set_offset_value(&((struct rpm_message_header_v1 *)buf)-> + hdr.request_hdr, RPM_MSG_TYPE_OFFSET, + RPM_MSG_TYPE_SIZE, RPM_V1_REQUEST_SERVICE); + } +} + +static void set_rsc_id(char *buf, uint32_t val) +{ + if (rpm_msg_fmt_ver == RPM_MSG_V0_FMT) + ((struct rpm_message_header_v0 *)buf)->resource_id = val; + else + set_offset_value(&((struct rpm_message_header_v1 *)buf)-> + request_details, RPM_RSC_ID_OFFSET, + RPM_RSC_ID_SIZE, val); +} + +static void set_data_len(char *buf, uint32_t val) +{ + if (rpm_msg_fmt_ver == RPM_MSG_V0_FMT) + ((struct rpm_message_header_v0 *)buf)->data_len = val; + else + set_offset_value(&((struct rpm_message_header_v1 *)buf)-> + request_details, RPM_DATA_LEN_OFFSET, + RPM_DATA_LEN_SIZE, val); +} +static void change_data_len(char *buf, int32_t val) +{ + if (rpm_msg_fmt_ver == RPM_MSG_V0_FMT) + ((struct rpm_message_header_v0 *)buf)->data_len += val; + else + change_offset_value(&((struct rpm_message_header_v1 *)buf)-> + request_details, RPM_DATA_LEN_OFFSET, + RPM_DATA_LEN_SIZE, val); +} + +static void set_set_type(char *buf, uint32_t val) +{ + if (rpm_msg_fmt_ver == RPM_MSG_V0_FMT) + ((struct rpm_message_header_v0 *)buf)->set = val; + else + set_offset_value(&((struct rpm_message_header_v1 *)buf)-> + request_details, RPM_SET_TYPE_OFFSET, + RPM_SET_TYPE_SIZE, val); +} +static void set_msg_id(char *buf, uint32_t val) +{ + if (rpm_msg_fmt_ver == RPM_MSG_V0_FMT) + ((struct rpm_message_header_v0 *)buf)->msg_id = val; + else + ((struct rpm_message_header_v1 *)buf)->msg_id = val; + +} + +static void set_rsc_type(char *buf, uint32_t val) +{ + if (rpm_msg_fmt_ver == RPM_MSG_V0_FMT) + ((struct rpm_message_header_v0 *)buf)->resource_type = val; + else + ((struct rpm_message_header_v1 *)buf)->resource_type = val; +} + +static inline int get_buf_len(char *buf) +{ + return get_req_len(buf) + RPM_HDR_SIZE; +} + +static inline struct kvp *get_first_kvp(char *buf) +{ + if (rpm_msg_fmt_ver == RPM_MSG_V0_FMT) + return (struct kvp *)(buf + + sizeof(struct rpm_message_header_v0)); + else + return (struct kvp *)(buf + + sizeof(struct rpm_message_header_v1)); +} + +static inline struct kvp *get_next_kvp(struct kvp *k) +{ + return (struct kvp *)((void *)k + sizeof(*k) + k->s); +} + +static inline void *get_data(struct kvp *k) +{ + return (void *)k + sizeof(*k); +} + + +static void delete_kvp(char *buf, struct kvp *d) +{ + struct kvp *n; + int dec; + uint32_t size; + + n = get_next_kvp(d); + dec = (void *)n - (void *)d; + size = get_data_len(buf) - + ((void *)n - (void *)get_first_kvp(buf)); + + memcpy((void *)d, (void *)n, size); + + change_data_len(buf, -dec); + change_req_len(buf, -dec); +} + +static inline void update_kvp_data(struct kvp *dest, struct kvp *src) +{ + memcpy(get_data(dest), get_data(src), src->s); +} + +static void add_kvp(char *buf, struct kvp *n) +{ + int32_t inc = sizeof(*n) + n->s; + + if (get_req_len(buf) + inc > MAX_SLEEP_BUFFER) { + WARN_ON(get_req_len(buf) + inc > MAX_SLEEP_BUFFER); + return; + } + + memcpy(buf + get_buf_len(buf), n, inc); + + change_data_len(buf, inc); + change_req_len(buf, inc); +} + +static struct slp_buf *tr_search(struct rb_root *root, char *slp) +{ + unsigned int type = get_rsc_type(slp); + unsigned int id = get_rsc_id(slp); + struct rb_node *node = root->rb_node; + + while (node) { + struct slp_buf *cur = rb_entry(node, struct slp_buf, node); + unsigned int ctype = get_rsc_type(cur->buf); + unsigned int cid = get_rsc_id(cur->buf); + + if (type < ctype) + node = node->rb_left; + else if (type > ctype) + node = node->rb_right; + else if (id < cid) + node = node->rb_left; + else if (id > cid) + node = node->rb_right; + else + return cur; + } + return NULL; +} + +static int tr_insert(struct rb_root *root, struct slp_buf *slp) +{ + unsigned int type = get_rsc_type(slp->buf); + unsigned int id = get_rsc_id(slp->buf); + struct rb_node **node = &(root->rb_node), *parent = NULL; + + while (*node) { + struct slp_buf *curr = rb_entry(*node, struct slp_buf, node); + unsigned int ctype = get_rsc_type(curr->buf); + unsigned int cid = get_rsc_id(curr->buf); + + parent = *node; + + if (type < ctype) + node = &((*node)->rb_left); + else if (type > ctype) + node = &((*node)->rb_right); + else if (id < cid) + node = &((*node)->rb_left); + else if (id > cid) + node = &((*node)->rb_right); + else + return -EINVAL; + } + + rb_link_node(&slp->node, parent, node); + rb_insert_color(&slp->node, root); + slp->valid = true; + return 0; +} + +#define for_each_kvp(buf, k) \ + for (k = (struct kvp *)get_first_kvp(buf); \ + ((void *)k - (void *)get_first_kvp(buf)) < \ + get_data_len(buf);\ + k = get_next_kvp(k)) + + +static void tr_update(struct slp_buf *s, char *buf) +{ + struct kvp *e, *n; + + for_each_kvp(buf, n) { + bool found = false; + + for_each_kvp(s->buf, e) { + if (n->k == e->k) { + found = true; + if (n->s == e->s) { + void *e_data = get_data(e); + void *n_data = get_data(n); + + if (memcmp(e_data, n_data, n->s)) { + update_kvp_data(e, n); + s->valid = true; + } + } else { + delete_kvp(s->buf, e); + add_kvp(s->buf, n); + s->valid = true; + } + break; + } + + } + if (!found) { + add_kvp(s->buf, n); + s->valid = true; + } + } +} +static atomic_t msm_rpm_msg_id = ATOMIC_INIT(0); + +struct msm_rpm_request { + uint8_t *client_buf; + struct msm_rpm_kvp_data *kvp; + uint32_t num_elements; + uint32_t write_idx; + uint8_t *buf; + uint32_t numbytes; +}; + +/* + * Data related to message acknowledgment + */ + +LIST_HEAD(msm_rpm_wait_list); + +struct msm_rpm_wait_data { + struct list_head list; + uint32_t msg_id; + bool ack_recd; + int errno; + struct completion ack; + bool delete_on_ack; +}; +DEFINE_SPINLOCK(msm_rpm_list_lock); + + + +LIST_HEAD(msm_rpm_ack_list); + +static struct tasklet_struct data_tasklet; + +static inline uint32_t msm_rpm_get_msg_id_from_ack(uint8_t *buf) +{ + return get_ack_msg_id(buf); +} + +static inline int msm_rpm_get_error_from_ack(uint8_t *buf) +{ + uint8_t *tmp; + uint32_t req_len = get_ack_req_len(buf); + uint32_t msg_type = get_ack_msg_type(buf); + int rc = -ENODEV; + uint32_t err; + uint32_t ack_msg_size = rpm_msg_fmt_ver ? + sizeof(struct msm_rpm_ack_msg_v1) : + sizeof(struct msm_rpm_ack_msg_v0); + + if (rpm_msg_fmt_ver == RPM_MSG_V0_FMT && + msg_type == RPM_V1_ACK_SERVICE) { + return 0; + } else if (rpm_msg_fmt_ver && msg_type == RPM_V1_NACK_SERVICE) { + err = *(uint32_t *)(buf + sizeof(struct msm_rpm_ack_msg_v1)); + return err; + } + + req_len -= ack_msg_size; + req_len += 2 * sizeof(uint32_t); + if (!req_len) + return 0; + + pr_err("%s:rpm returned error or nack req_len: %d id_ack: %d\n", + __func__, req_len, get_ack_msg_id(buf)); + + tmp = buf + ack_msg_size; + + if (memcmp(tmp, ERR, sizeof(uint32_t))) { + pr_err("%s rpm returned error\n", __func__); + WARN_ON(1); + } + + tmp += 2 * sizeof(uint32_t); + + if (!(memcmp(tmp, INV_RSC, min_t(uint32_t, req_len, + sizeof(INV_RSC))-1))) { + pr_err("%s(): RPM NACK Unsupported resource\n", __func__); + rc = -EINVAL; + } else { + pr_err("%s(): RPM NACK Invalid header\n", __func__); + } + + return rc; +} + +int msm_rpm_smd_buffer_request(struct msm_rpm_request *cdata, + uint32_t size, gfp_t flag) +{ + struct slp_buf *slp; + static DEFINE_SPINLOCK(slp_buffer_lock); + unsigned long flags; + char *buf; + + buf = cdata->buf; + + if (size > MAX_SLEEP_BUFFER) + return -ENOMEM; + + spin_lock_irqsave(&slp_buffer_lock, flags); + slp = tr_search(&tr_root, buf); + + if (!slp) { + slp = kzalloc(sizeof(struct slp_buf), GFP_ATOMIC); + if (!slp) { + spin_unlock_irqrestore(&slp_buffer_lock, flags); + return -ENOMEM; + } + slp->buf = PTR_ALIGN(&slp->ubuf[0], sizeof(u32)); + memcpy(slp->buf, buf, size); + if (tr_insert(&tr_root, slp)) + pr_err("Error updating sleep request\n"); + } else { + /* handle unsent requests */ + tr_update(slp, buf); + } + trace_rpm_smd_sleep_set(get_msg_id(cdata->client_buf), + get_rsc_type(cdata->client_buf), + get_req_len(cdata->client_buf)); + + spin_unlock_irqrestore(&slp_buffer_lock, flags); + + return 0; +} + +static struct msm_rpm_driver_data msm_rpm_data = { + .smd_open = COMPLETION_INITIALIZER(msm_rpm_data.smd_open), +}; + +static int msm_rpm_glink_rx_poll(void *glink_handle) +{ + int ret; + + ret = glink_rpm_rx_poll(glink_handle); + if (ret >= 0) + /* + * Sleep for 50us at a time before checking + * for packet availability. The 50us is based + * on the the time rpm could take to process + * and send an ack for the sleep set request. + */ + udelay(50); + else + pr_err("Not receieve an ACK from RPM. ret = %d\n", ret); + + return ret; +} + +/* + * Returns + * = 0 on successful reads + * > 0 on successful reads with no further data + * standard Linux error codes on failure. + */ +static int msm_rpm_read_sleep_ack(void) +{ + int ret; + char buf[MAX_ERR_BUFFER_SIZE] = {0}; + + if (glink_enabled) + ret = msm_rpm_glink_rx_poll(glink_data->glink_handle); + else { + ret = msm_rpm_read_smd_data(buf); + if (!ret) + ret = smd_is_pkt_avail(msm_rpm_data.ch_info); + } + return ret; +} + +static int msm_rpm_flush_requests(bool print) +{ + struct rb_node *t; + int ret; + int count = 0; + + for (t = rb_first(&tr_root); t; t = rb_next(t)) { + + struct slp_buf *s = rb_entry(t, struct slp_buf, node); + unsigned int type = get_rsc_type(s->buf); + unsigned int id = get_rsc_id(s->buf); + + if (!s->valid) + continue; + + set_msg_id(s->buf, msm_rpm_get_next_msg_id()); + + if (!glink_enabled) + ret = msm_rpm_send_smd_buffer(s->buf, + get_buf_len(s->buf), true); + else + ret = msm_rpm_glink_send_buffer(s->buf, + get_buf_len(s->buf), true); + + WARN_ON(ret != get_buf_len(s->buf)); + trace_rpm_smd_send_sleep_set(get_msg_id(s->buf), type, id); + + s->valid = false; + count++; + + /* + * RPM acks need to be handled here if we have sent 24 + * messages such that we do not overrun SMD buffer. Since + * we expect only sleep sets at this point (RPM PC would be + * disallowed if we had pending active requests), we need not + * process these sleep set acks. + */ + if (count >= MAX_WAIT_ON_ACK) { + int ret = msm_rpm_read_sleep_ack(); + + if (ret >= 0) + count--; + else + return ret; + } + } + return 0; +} + +static void msm_rpm_notify_sleep_chain(char *buf, + struct msm_rpm_kvp_data *kvp) +{ + struct msm_rpm_notifier_data notif; + + notif.rsc_type = get_rsc_type(buf); + notif.rsc_id = get_req_len(buf); + notif.key = kvp->key; + notif.size = kvp->nbytes; + notif.value = kvp->value; + atomic_notifier_call_chain(&msm_rpm_sleep_notifier, 0, ¬if); +} + +static int msm_rpm_add_kvp_data_common(struct msm_rpm_request *handle, + uint32_t key, const uint8_t *data, int size, bool noirq) +{ + uint32_t i; + uint32_t data_size, msg_size; + + if (probe_status) + return probe_status; + + if (!handle || !data) { + pr_err("%s(): Invalid handle/data\n", __func__); + return -EINVAL; + } + + if (size < 0) + return -EINVAL; + + data_size = ALIGN(size, SZ_4); + msg_size = data_size + 8; + + for (i = 0; i < handle->write_idx; i++) { + if (handle->kvp[i].key != key) + continue; + if (handle->kvp[i].nbytes != data_size) { + kfree(handle->kvp[i].value); + handle->kvp[i].value = NULL; + } else { + if (!memcmp(handle->kvp[i].value, data, data_size)) + return 0; + } + break; + } + + if (i >= handle->num_elements) { + pr_err("Number of resources exceeds max allocated\n"); + return -ENOMEM; + } + + if (i == handle->write_idx) + handle->write_idx++; + + if (!handle->kvp[i].value) { + handle->kvp[i].value = kzalloc(data_size, GFP_FLAG(noirq)); + + if (!handle->kvp[i].value) + return -ENOMEM; + } else { + /* We enter the else case, if a key already exists but the + * data doesn't match. In which case, we should zero the data + * out. + */ + memset(handle->kvp[i].value, 0, data_size); + } + + if (!handle->kvp[i].valid) + change_data_len(handle->client_buf, msg_size); + else + change_data_len(handle->client_buf, + (data_size - handle->kvp[i].nbytes)); + + handle->kvp[i].nbytes = data_size; + handle->kvp[i].key = key; + memcpy(handle->kvp[i].value, data, size); + handle->kvp[i].valid = true; + + return 0; + +} + +static struct msm_rpm_request *msm_rpm_create_request_common( + enum msm_rpm_set set, uint32_t rsc_type, uint32_t rsc_id, + int num_elements, bool noirq) +{ + struct msm_rpm_request *cdata; + uint32_t buf_size; + + if (probe_status) + return ERR_PTR(probe_status); + + cdata = kzalloc(sizeof(struct msm_rpm_request), + GFP_FLAG(noirq)); + + if (!cdata) { + pr_err("Cannot allocate memory for client data\n"); + goto cdata_alloc_fail; + } + + if (rpm_msg_fmt_ver == RPM_MSG_V0_FMT) + buf_size = sizeof(struct rpm_message_header_v0); + else + buf_size = sizeof(struct rpm_message_header_v1); + + cdata->client_buf = kzalloc(buf_size, GFP_FLAG(noirq)); + + if (!cdata->client_buf) + goto client_buf_alloc_fail; + + set_set_type(cdata->client_buf, set); + set_rsc_type(cdata->client_buf, rsc_type); + set_rsc_id(cdata->client_buf, rsc_id); + + cdata->num_elements = num_elements; + cdata->write_idx = 0; + + cdata->kvp = kcalloc(num_elements, sizeof(struct msm_rpm_kvp_data), + GFP_FLAG(noirq)); + + if (!cdata->kvp) { + pr_warn("%s(): Cannot allocate memory for key value data\n", + __func__); + goto kvp_alloc_fail; + } + + cdata->buf = kzalloc(DEFAULT_BUFFER_SIZE, GFP_FLAG(noirq)); + + if (!cdata->buf) + goto buf_alloc_fail; + + cdata->numbytes = DEFAULT_BUFFER_SIZE; + return cdata; + +buf_alloc_fail: + kfree(cdata->kvp); +kvp_alloc_fail: + kfree(cdata->client_buf); +client_buf_alloc_fail: + kfree(cdata); +cdata_alloc_fail: + return NULL; + +} + +void msm_rpm_free_request(struct msm_rpm_request *handle) +{ + int i; + + if (!handle) + return; + for (i = 0; i < handle->num_elements; i++) + kfree(handle->kvp[i].value); + kfree(handle->kvp); + kfree(handle->client_buf); + kfree(handle->buf); + kfree(handle); +} +EXPORT_SYMBOL(msm_rpm_free_request); + +struct msm_rpm_request *msm_rpm_create_request( + enum msm_rpm_set set, uint32_t rsc_type, + uint32_t rsc_id, int num_elements) +{ + return msm_rpm_create_request_common(set, rsc_type, rsc_id, + num_elements, false); +} +EXPORT_SYMBOL(msm_rpm_create_request); + +struct msm_rpm_request *msm_rpm_create_request_noirq( + enum msm_rpm_set set, uint32_t rsc_type, + uint32_t rsc_id, int num_elements) +{ + return msm_rpm_create_request_common(set, rsc_type, rsc_id, + num_elements, true); +} +EXPORT_SYMBOL(msm_rpm_create_request_noirq); + +int msm_rpm_add_kvp_data(struct msm_rpm_request *handle, + uint32_t key, const uint8_t *data, int size) +{ + return msm_rpm_add_kvp_data_common(handle, key, data, size, false); + +} +EXPORT_SYMBOL(msm_rpm_add_kvp_data); + +int msm_rpm_add_kvp_data_noirq(struct msm_rpm_request *handle, + uint32_t key, const uint8_t *data, int size) +{ + return msm_rpm_add_kvp_data_common(handle, key, data, size, true); +} +EXPORT_SYMBOL(msm_rpm_add_kvp_data_noirq); + +/* Runs in interrupt context */ +static void msm_rpm_notify(void *data, unsigned int event) +{ + struct msm_rpm_driver_data *pdata = (struct msm_rpm_driver_data *)data; + + WARN_ON(!pdata); + + if (!(pdata->ch_info)) + return; + + switch (event) { + case SMD_EVENT_DATA: + tasklet_schedule(&data_tasklet); + trace_rpm_smd_interrupt_notify("interrupt notification"); + break; + case SMD_EVENT_OPEN: + complete(&pdata->smd_open); + break; + case SMD_EVENT_CLOSE: + case SMD_EVENT_STATUS: + case SMD_EVENT_REOPEN_READY: + break; + default: + pr_info("Unknown SMD event\n"); + + } +} + +bool msm_rpm_waiting_for_ack(void) +{ + bool ret; + unsigned long flags; + + spin_lock_irqsave(&msm_rpm_list_lock, flags); + ret = list_empty(&msm_rpm_wait_list); + spin_unlock_irqrestore(&msm_rpm_list_lock, flags); + + return !ret; +} + +static struct msm_rpm_wait_data *msm_rpm_get_entry_from_msg_id(uint32_t msg_id) +{ + struct list_head *ptr; + struct msm_rpm_wait_data *elem = NULL; + unsigned long flags; + + spin_lock_irqsave(&msm_rpm_list_lock, flags); + + list_for_each(ptr, &msm_rpm_wait_list) { + elem = list_entry(ptr, struct msm_rpm_wait_data, list); + if (elem && (elem->msg_id == msg_id)) + break; + elem = NULL; + } + spin_unlock_irqrestore(&msm_rpm_list_lock, flags); + return elem; +} + +static uint32_t msm_rpm_get_next_msg_id(void) +{ + uint32_t id; + + /* + * A message id of 0 is used by the driver to indicate a error + * condition. The RPM driver uses a id of 1 to indicate unsent data + * when the data sent over hasn't been modified. This isn't a error + * scenario and wait for ack returns a success when the message id is 1. + */ + + do { + id = atomic_inc_return(&msm_rpm_msg_id); + } while ((id == 0) || (id == 1) || msm_rpm_get_entry_from_msg_id(id)); + + return id; +} + +static int msm_rpm_add_wait_list(uint32_t msg_id, bool delete_on_ack) +{ + unsigned long flags; + struct msm_rpm_wait_data *data = + kzalloc(sizeof(struct msm_rpm_wait_data), GFP_ATOMIC); + + if (!data) + return -ENOMEM; + + init_completion(&data->ack); + data->ack_recd = false; + data->msg_id = msg_id; + data->errno = INIT_ERROR; + data->delete_on_ack = delete_on_ack; + spin_lock_irqsave(&msm_rpm_list_lock, flags); + if (delete_on_ack) + list_add_tail(&data->list, &msm_rpm_wait_list); + else + list_add(&data->list, &msm_rpm_wait_list); + spin_unlock_irqrestore(&msm_rpm_list_lock, flags); + + return 0; +} + +static void msm_rpm_free_list_entry(struct msm_rpm_wait_data *elem) +{ + unsigned long flags; + + spin_lock_irqsave(&msm_rpm_list_lock, flags); + list_del(&elem->list); + spin_unlock_irqrestore(&msm_rpm_list_lock, flags); + kfree(elem); +} + +static void msm_rpm_process_ack(uint32_t msg_id, int errno) +{ + struct list_head *ptr, *next; + struct msm_rpm_wait_data *elem = NULL; + unsigned long flags; + + spin_lock_irqsave(&msm_rpm_list_lock, flags); + + list_for_each_safe(ptr, next, &msm_rpm_wait_list) { + elem = list_entry(ptr, struct msm_rpm_wait_data, list); + if (elem->msg_id == msg_id) { + elem->errno = errno; + elem->ack_recd = true; + complete(&elem->ack); + if (elem->delete_on_ack) { + list_del(&elem->list); + kfree(elem); + } + break; + } + } + /* Special case where the sleep driver doesn't + * wait for ACKs. This would decrease the latency involved with + * entering RPM assisted power collapse. + */ + if (!elem) + trace_rpm_smd_ack_recvd(0, msg_id, 0xDEADBEEF); + + spin_unlock_irqrestore(&msm_rpm_list_lock, flags); +} + +struct msm_rpm_kvp_packet { + uint32_t id; + uint32_t len; + uint32_t val; +}; + +static int msm_rpm_read_smd_data(char *buf) +{ + int pkt_sz; + int bytes_read = 0; + + pkt_sz = smd_cur_packet_size(msm_rpm_data.ch_info); + + if (!pkt_sz) + return -EAGAIN; + + if (pkt_sz > MAX_ERR_BUFFER_SIZE) { + pr_err("rpm_smd pkt_sz is greater than max size\n"); + goto error; + } + + if (pkt_sz != smd_read_avail(msm_rpm_data.ch_info)) + return -EAGAIN; + + do { + int len; + + len = smd_read(msm_rpm_data.ch_info, buf + bytes_read, pkt_sz); + pkt_sz -= len; + bytes_read += len; + + } while (pkt_sz > 0); + + if (pkt_sz < 0) { + pr_err("rpm_smd pkt_sz is less than zero\n"); + goto error; + } + return 0; +error: + WARN_ON(1); + + return 0; +} + +static void data_fn_tasklet(unsigned long data) +{ + uint32_t msg_id; + int errno; + char buf[MAX_ERR_BUFFER_SIZE] = {0}; + + spin_lock(&msm_rpm_data.smd_lock_read); + while (smd_is_pkt_avail(msm_rpm_data.ch_info)) { + if (msm_rpm_read_smd_data(buf)) + break; + msg_id = msm_rpm_get_msg_id_from_ack(buf); + errno = msm_rpm_get_error_from_ack(buf); + trace_rpm_smd_ack_recvd(0, msg_id, errno); + msm_rpm_process_ack(msg_id, errno); + } + spin_unlock(&msm_rpm_data.smd_lock_read); +} + +static void msm_rpm_log_request(struct msm_rpm_request *cdata) +{ + char buf[DEBUG_PRINT_BUFFER_SIZE]; + size_t buflen = DEBUG_PRINT_BUFFER_SIZE; + char name[5]; + u32 value; + uint32_t i; + int j, prev_valid; + int valid_count = 0; + int pos = 0; + uint32_t res_type, rsc_id; + + name[4] = 0; + + for (i = 0; i < cdata->write_idx; i++) + if (cdata->kvp[i].valid) + valid_count++; + + pos += scnprintf(buf + pos, buflen - pos, "%sRPM req: ", KERN_INFO); + if (msm_rpm_debug_mask & MSM_RPM_LOG_REQUEST_SHOW_MSG_ID) + pos += scnprintf(buf + pos, buflen - pos, "msg_id=%u, ", + get_msg_id(cdata->client_buf)); + pos += scnprintf(buf + pos, buflen - pos, "s=%s", + (get_set_type(cdata->client_buf) == + MSM_RPM_CTX_ACTIVE_SET ? "act" : "slp")); + + res_type = get_rsc_type(cdata->client_buf); + rsc_id = get_rsc_id(cdata->client_buf); + if ((msm_rpm_debug_mask & MSM_RPM_LOG_REQUEST_PRETTY) + && (msm_rpm_debug_mask & MSM_RPM_LOG_REQUEST_RAW)) { + /* Both pretty and raw formatting */ + memcpy(name, &res_type, sizeof(uint32_t)); + pos += scnprintf(buf + pos, buflen - pos, + ", rsc_type=0x%08X (%s), rsc_id=%u; ", + res_type, name, rsc_id); + + for (i = 0, prev_valid = 0; i < cdata->write_idx; i++) { + if (!cdata->kvp[i].valid) + continue; + + memcpy(name, &cdata->kvp[i].key, sizeof(uint32_t)); + pos += scnprintf(buf + pos, buflen - pos, + "[key=0x%08X (%s), value=%s", + cdata->kvp[i].key, name, + (cdata->kvp[i].nbytes ? "0x" : "null")); + + for (j = 0; j < cdata->kvp[i].nbytes; j++) + pos += scnprintf(buf + pos, buflen - pos, + "%02X ", + cdata->kvp[i].value[j]); + + if (cdata->kvp[i].nbytes) + pos += scnprintf(buf + pos, buflen - pos, "("); + + for (j = 0; j < cdata->kvp[i].nbytes; j += 4) { + value = 0; + memcpy(&value, &cdata->kvp[i].value[j], + min_t(uint32_t, sizeof(uint32_t), + cdata->kvp[i].nbytes - j)); + pos += scnprintf(buf + pos, buflen - pos, "%u", + value); + if (j + 4 < cdata->kvp[i].nbytes) + pos += scnprintf(buf + pos, + buflen - pos, " "); + } + if (cdata->kvp[i].nbytes) + pos += scnprintf(buf + pos, buflen - pos, ")"); + pos += scnprintf(buf + pos, buflen - pos, "]"); + if (prev_valid + 1 < valid_count) + pos += scnprintf(buf + pos, buflen - pos, ", "); + prev_valid++; + } + } else if (msm_rpm_debug_mask & MSM_RPM_LOG_REQUEST_PRETTY) { + /* Pretty formatting only */ + memcpy(name, &res_type, sizeof(uint32_t)); + pos += scnprintf(buf + pos, buflen - pos, " %s %u; ", name, + rsc_id); + + for (i = 0, prev_valid = 0; i < cdata->write_idx; i++) { + if (!cdata->kvp[i].valid) + continue; + + memcpy(name, &cdata->kvp[i].key, sizeof(uint32_t)); + pos += scnprintf(buf + pos, buflen - pos, "%s=%s", + name, (cdata->kvp[i].nbytes ? "" : "null")); + + for (j = 0; j < cdata->kvp[i].nbytes; j += 4) { + value = 0; + memcpy(&value, &cdata->kvp[i].value[j], + min_t(uint32_t, sizeof(uint32_t), + cdata->kvp[i].nbytes - j)); + pos += scnprintf(buf + pos, buflen - pos, "%u", + value); + + if (j + 4 < cdata->kvp[i].nbytes) + pos += scnprintf(buf + pos, + buflen - pos, " "); + } + if (prev_valid + 1 < valid_count) + pos += scnprintf(buf + pos, buflen - pos, ", "); + prev_valid++; + } + } else { + /* Raw formatting only */ + pos += scnprintf(buf + pos, buflen - pos, + ", rsc_type=0x%08X, rsc_id=%u; ", res_type, rsc_id); + + for (i = 0, prev_valid = 0; i < cdata->write_idx; i++) { + if (!cdata->kvp[i].valid) + continue; + + pos += scnprintf(buf + pos, buflen - pos, + "[key=0x%08X, value=%s", + cdata->kvp[i].key, + (cdata->kvp[i].nbytes ? "0x" : "null")); + for (j = 0; j < cdata->kvp[i].nbytes; j++) { + pos += scnprintf(buf + pos, buflen - pos, + "%02X", + cdata->kvp[i].value[j]); + if (j + 1 < cdata->kvp[i].nbytes) + pos += scnprintf(buf + pos, + buflen - pos, " "); + } + pos += scnprintf(buf + pos, buflen - pos, "]"); + if (prev_valid + 1 < valid_count) + pos += scnprintf(buf + pos, buflen - pos, ", "); + prev_valid++; + } + } + + pos += scnprintf(buf + pos, buflen - pos, "\n"); + printk(buf); +} + +static int msm_rpm_send_smd_buffer(char *buf, uint32_t size, bool noirq) +{ + unsigned long flags; + int ret; + + spin_lock_irqsave(&msm_rpm_data.smd_lock_write, flags); + ret = smd_write_avail(msm_rpm_data.ch_info); + + while ((ret = smd_write_avail(msm_rpm_data.ch_info)) < size) { + if (ret < 0) + break; + if (!noirq) { + spin_unlock_irqrestore( + &msm_rpm_data.smd_lock_write, flags); + cpu_relax(); + spin_lock_irqsave( + &msm_rpm_data.smd_lock_write, flags); + } else + udelay(5); + } + + if (ret < 0) { + pr_err("SMD not initialized\n"); + spin_unlock_irqrestore( + &msm_rpm_data.smd_lock_write, flags); + return ret; + } + + ret = smd_write(msm_rpm_data.ch_info, buf, size); + spin_unlock_irqrestore(&msm_rpm_data.smd_lock_write, flags); + return ret; +} + +static int msm_rpm_glink_send_buffer(char *buf, uint32_t size, bool noirq) +{ + int ret; + unsigned long flags; + int timeout = 50; + + spin_lock_irqsave(&msm_rpm_data.smd_lock_write, flags); + do { + ret = glink_tx(glink_data->glink_handle, buf, buf, + size, GLINK_TX_SINGLE_THREADED); + if (ret == -EBUSY || ret == -ENOSPC) { + if (!noirq) { + spin_unlock_irqrestore( + &msm_rpm_data.smd_lock_write, flags); + cpu_relax(); + spin_lock_irqsave( + &msm_rpm_data.smd_lock_write, flags); + } else { + udelay(5); + } + timeout--; + } else { + ret = 0; + } + } while (ret && timeout); + spin_unlock_irqrestore(&msm_rpm_data.smd_lock_write, flags); + + if (!timeout) + return 0; + else + return size; +} + +static int msm_rpm_send_data(struct msm_rpm_request *cdata, + int msg_type, bool noirq, bool noack) +{ + uint8_t *tmpbuff; + int ret; + uint32_t i; + uint32_t msg_size; + int msg_hdr_sz, req_hdr_sz; + uint32_t data_len = get_data_len(cdata->client_buf); + uint32_t set = get_set_type(cdata->client_buf); + uint32_t msg_id; + + if (probe_status) + return probe_status; + + if (!data_len) + return 1; + + msg_hdr_sz = rpm_msg_fmt_ver ? sizeof(struct rpm_message_header_v1) : + sizeof(struct rpm_message_header_v0); + + req_hdr_sz = RPM_HDR_SIZE; + set_msg_type(cdata->client_buf, msg_type); + + set_req_len(cdata->client_buf, data_len + msg_hdr_sz - req_hdr_sz); + msg_size = get_req_len(cdata->client_buf) + req_hdr_sz; + + /* populate data_len */ + if (msg_size > cdata->numbytes) { + kfree(cdata->buf); + cdata->numbytes = msg_size; + cdata->buf = kzalloc(msg_size, GFP_FLAG(noirq)); + } + + if (!cdata->buf) { + pr_err("Failed malloc\n"); + return 0; + } + + tmpbuff = cdata->buf; + + tmpbuff += msg_hdr_sz; + for (i = 0; (i < cdata->write_idx); i++) { + /* Sanity check */ + WARN_ON((tmpbuff - cdata->buf) > cdata->numbytes); + + if (!cdata->kvp[i].valid) + continue; + + memcpy(tmpbuff, &cdata->kvp[i].key, sizeof(uint32_t)); + tmpbuff += sizeof(uint32_t); + + memcpy(tmpbuff, &cdata->kvp[i].nbytes, sizeof(uint32_t)); + tmpbuff += sizeof(uint32_t); + + memcpy(tmpbuff, cdata->kvp[i].value, cdata->kvp[i].nbytes); + tmpbuff += cdata->kvp[i].nbytes; + + if (set == MSM_RPM_CTX_SLEEP_SET) + msm_rpm_notify_sleep_chain(cdata->client_buf, + &cdata->kvp[i]); + + } + + memcpy(cdata->buf, cdata->client_buf, msg_hdr_sz); + if ((set == MSM_RPM_CTX_SLEEP_SET) && + !msm_rpm_smd_buffer_request(cdata, msg_size, + GFP_FLAG(noirq))) + return 1; + + msg_id = msm_rpm_get_next_msg_id(); + /* Set the version bit for new protocol */ + set_msg_ver(cdata->buf, rpm_msg_fmt_ver); + set_msg_id(cdata->buf, msg_id); + set_msg_id(cdata->client_buf, msg_id); + + if (msm_rpm_debug_mask + & (MSM_RPM_LOG_REQUEST_PRETTY | MSM_RPM_LOG_REQUEST_RAW)) + msm_rpm_log_request(cdata); + + if (standalone) { + for (i = 0; (i < cdata->write_idx); i++) + cdata->kvp[i].valid = false; + + set_data_len(cdata->client_buf, 0); + ret = msg_id; + return ret; + } + + msm_rpm_add_wait_list(msg_id, noack); + + ret = msm_rpm_send_buffer(&cdata->buf[0], msg_size, noirq); + + if (ret == msg_size) { + for (i = 0; (i < cdata->write_idx); i++) + cdata->kvp[i].valid = false; + set_data_len(cdata->client_buf, 0); + ret = msg_id; + trace_rpm_smd_send_active_set(msg_id, + get_rsc_type(cdata->client_buf), + get_rsc_id(cdata->client_buf)); + } else if (ret < msg_size) { + struct msm_rpm_wait_data *rc; + + ret = 0; + pr_err("Failed to write data msg_size:%d ret:%d msg_id:%d\n", + msg_size, ret, msg_id); + rc = msm_rpm_get_entry_from_msg_id(msg_id); + if (rc) + msm_rpm_free_list_entry(rc); + } + return ret; +} + +static int _msm_rpm_send_request(struct msm_rpm_request *handle, bool noack) +{ + int ret; + static DEFINE_MUTEX(send_mtx); + + mutex_lock(&send_mtx); + ret = msm_rpm_send_data(handle, MSM_RPM_MSG_REQUEST_TYPE, false, noack); + mutex_unlock(&send_mtx); + + return ret; +} + +int msm_rpm_send_request(struct msm_rpm_request *handle) +{ + return _msm_rpm_send_request(handle, false); +} +EXPORT_SYMBOL(msm_rpm_send_request); + +int msm_rpm_send_request_noirq(struct msm_rpm_request *handle) +{ + return msm_rpm_send_data(handle, MSM_RPM_MSG_REQUEST_TYPE, true, false); +} +EXPORT_SYMBOL(msm_rpm_send_request_noirq); + +void *msm_rpm_send_request_noack(struct msm_rpm_request *handle) +{ + int ret; + + ret = _msm_rpm_send_request(handle, true); + + return ret < 0 ? ERR_PTR(ret) : NULL; +} +EXPORT_SYMBOL(msm_rpm_send_request_noack); + +int msm_rpm_wait_for_ack(uint32_t msg_id) +{ + struct msm_rpm_wait_data *elem; + int rc = 0; + + if (!msg_id) { + pr_err("Invalid msg id\n"); + return -ENOMEM; + } + + if (msg_id == 1) + return rc; + + if (standalone) + return rc; + + elem = msm_rpm_get_entry_from_msg_id(msg_id); + if (!elem) + return rc; + + wait_for_completion(&elem->ack); + trace_rpm_smd_ack_recvd(0, msg_id, 0xDEADFEED); + + rc = elem->errno; + msm_rpm_free_list_entry(elem); + + return rc; +} +EXPORT_SYMBOL(msm_rpm_wait_for_ack); + +static void msm_rpm_smd_read_data_noirq(uint32_t msg_id) +{ + uint32_t id = 0; + + while (id != msg_id) { + if (smd_is_pkt_avail(msm_rpm_data.ch_info)) { + int errno; + char buf[MAX_ERR_BUFFER_SIZE] = {}; + + msm_rpm_read_smd_data(buf); + id = msm_rpm_get_msg_id_from_ack(buf); + errno = msm_rpm_get_error_from_ack(buf); + trace_rpm_smd_ack_recvd(1, msg_id, errno); + msm_rpm_process_ack(id, errno); + } + } +} + +static void msm_rpm_glink_read_data_noirq(struct msm_rpm_wait_data *elem) +{ + int ret; + + /* Use rx_poll method to read the message from RPM */ + while (elem->errno) { + ret = glink_rpm_rx_poll(glink_data->glink_handle); + if (ret >= 0) { + /* + * We might have receieve the notification. + * Now we have to check whether the notification + * received is what we are interested? + * Wait for few usec to get the notification + * before re-trying the poll again. + */ + udelay(50); + } else { + pr_err("rx poll return error = %d\n", ret); + } + } +} + +int msm_rpm_wait_for_ack_noirq(uint32_t msg_id) +{ + struct msm_rpm_wait_data *elem; + unsigned long flags; + int rc = 0; + + if (!msg_id) { + pr_err("Invalid msg id\n"); + return -ENOMEM; + } + + if (msg_id == 1) + return 0; + + if (standalone) + return 0; + + spin_lock_irqsave(&msm_rpm_data.smd_lock_read, flags); + + elem = msm_rpm_get_entry_from_msg_id(msg_id); + + if (!elem) + /* Should this be a bug + * Is it ok for another thread to read the msg? + */ + goto wait_ack_cleanup; + + if (elem->errno != INIT_ERROR) { + rc = elem->errno; + msm_rpm_free_list_entry(elem); + goto wait_ack_cleanup; + } + + if (!glink_enabled) + msm_rpm_smd_read_data_noirq(msg_id); + else + msm_rpm_glink_read_data_noirq(elem); + + rc = elem->errno; + + msm_rpm_free_list_entry(elem); +wait_ack_cleanup: + spin_unlock_irqrestore(&msm_rpm_data.smd_lock_read, flags); + + if (!glink_enabled) + if (smd_is_pkt_avail(msm_rpm_data.ch_info)) + tasklet_schedule(&data_tasklet); + return rc; +} +EXPORT_SYMBOL(msm_rpm_wait_for_ack_noirq); + +void *msm_rpm_send_message_noack(enum msm_rpm_set set, uint32_t rsc_type, + uint32_t rsc_id, struct msm_rpm_kvp *kvp, int nelems) +{ + int i, rc; + struct msm_rpm_request *req = + msm_rpm_create_request_common(set, rsc_type, rsc_id, nelems, + false); + + if (IS_ERR(req)) + return req; + + if (!req) + return ERR_PTR(ENOMEM); + + for (i = 0; i < nelems; i++) { + rc = msm_rpm_add_kvp_data(req, kvp[i].key, + kvp[i].data, kvp[i].length); + if (rc) + goto bail; + } + + rc = PTR_ERR(msm_rpm_send_request_noack(req)); +bail: + msm_rpm_free_request(req); + return rc < 0 ? ERR_PTR(rc) : NULL; +} +EXPORT_SYMBOL(msm_rpm_send_message_noack); + +int msm_rpm_send_message(enum msm_rpm_set set, uint32_t rsc_type, + uint32_t rsc_id, struct msm_rpm_kvp *kvp, int nelems) +{ + int i, rc; + struct msm_rpm_request *req = + msm_rpm_create_request(set, rsc_type, rsc_id, nelems); + + if (IS_ERR(req)) + return PTR_ERR(req); + + if (!req) + return -ENOMEM; + + for (i = 0; i < nelems; i++) { + rc = msm_rpm_add_kvp_data(req, kvp[i].key, + kvp[i].data, kvp[i].length); + if (rc) + goto bail; + } + + rc = msm_rpm_wait_for_ack(msm_rpm_send_request(req)); +bail: + msm_rpm_free_request(req); + return rc; +} +EXPORT_SYMBOL(msm_rpm_send_message); + +int msm_rpm_send_message_noirq(enum msm_rpm_set set, uint32_t rsc_type, + uint32_t rsc_id, struct msm_rpm_kvp *kvp, int nelems) +{ + int i, rc; + struct msm_rpm_request *req = + msm_rpm_create_request_noirq(set, rsc_type, rsc_id, nelems); + + if (IS_ERR(req)) + return PTR_ERR(req); + + if (!req) + return -ENOMEM; + + for (i = 0; i < nelems; i++) { + rc = msm_rpm_add_kvp_data_noirq(req, kvp[i].key, + kvp[i].data, kvp[i].length); + if (rc) + goto bail; + } + + rc = msm_rpm_wait_for_ack_noirq(msm_rpm_send_request_noirq(req)); +bail: + msm_rpm_free_request(req); + return rc; +} +EXPORT_SYMBOL(msm_rpm_send_message_noirq); + +/** + * During power collapse, the rpm driver disables the SMD interrupts to make + * sure that the interrupt doesn't wakes us from sleep. + */ +int msm_rpm_enter_sleep(bool print, const struct cpumask *cpumask) +{ + int ret = 0; + + if (standalone) + return 0; + + if (!glink_enabled) + ret = smd_mask_receive_interrupt(msm_rpm_data.ch_info, + true, cpumask); + else + ret = glink_rpm_mask_rx_interrupt(glink_data->glink_handle, + true, (void *)cpumask); + + if (!ret) { + ret = msm_rpm_flush_requests(print); + + if (ret) { + if (!glink_enabled) + smd_mask_receive_interrupt( + msm_rpm_data.ch_info, false, NULL); + else + glink_rpm_mask_rx_interrupt( + glink_data->glink_handle, false, NULL); + } + } + return ret; +} +EXPORT_SYMBOL(msm_rpm_enter_sleep); + +/** + * When the system resumes from power collapse, the SMD interrupt disabled by + * enter function has to reenabled to continue processing SMD message. + */ +void msm_rpm_exit_sleep(void) +{ + int ret; + + if (standalone) + return; + + do { + ret = msm_rpm_read_sleep_ack(); + } while (ret > 0); + + if (!glink_enabled) + smd_mask_receive_interrupt(msm_rpm_data.ch_info, false, NULL); + else + glink_rpm_mask_rx_interrupt(glink_data->glink_handle, + false, NULL); +} +EXPORT_SYMBOL(msm_rpm_exit_sleep); + +/* + * Whenever there is a data from RPM, notify_rx will be called. + * This function is invoked either interrupt OR polling context. + */ +static void msm_rpm_trans_notify_rx(void *handle, const void *priv, + const void *pkt_priv, const void *ptr, size_t size) +{ + uint32_t msg_id; + int errno; + char buf[MAX_ERR_BUFFER_SIZE] = {0}; + struct msm_rpm_wait_data *elem; + static DEFINE_SPINLOCK(rx_notify_lock); + unsigned long flags; + + if (!size) + return; + + WARN_ON(size > MAX_ERR_BUFFER_SIZE); + + spin_lock_irqsave(&rx_notify_lock, flags); + memcpy(buf, ptr, size); + msg_id = msm_rpm_get_msg_id_from_ack(buf); + errno = msm_rpm_get_error_from_ack(buf); + elem = msm_rpm_get_entry_from_msg_id(msg_id); + + /* + * It is applicable for sleep set requests + * Sleep set requests are not added to the + * wait queue list. Without this check we + * run into NULL pointer deferrence issue. + */ + if (!elem) { + spin_unlock_irqrestore(&rx_notify_lock, flags); + glink_rx_done(handle, ptr, 0); + return; + } + + msm_rpm_process_ack(msg_id, errno); + spin_unlock_irqrestore(&rx_notify_lock, flags); + + glink_rx_done(handle, ptr, 0); +} + +static void msm_rpm_trans_notify_state(void *handle, const void *priv, + unsigned int event) +{ + switch (event) { + case GLINK_CONNECTED: + glink_data->glink_handle = handle; + + if (IS_ERR_OR_NULL(glink_data->glink_handle)) { + pr_err("glink_handle %d\n", + (int)PTR_ERR(glink_data->glink_handle)); + WARN_ON(1); + } + + /* + * Do not allow clients to send data to RPM until glink + * is fully open. + */ + probe_status = 0; + pr_info("glink config params: transport=%s, edge=%s, name=%s\n", + glink_data->xprt, + glink_data->edge, + glink_data->name); + break; + default: + pr_err("Unrecognized event %d\n", event); + break; + }; +} + +static void msm_rpm_trans_notify_tx_done(void *handle, const void *priv, + const void *pkt_priv, const void *ptr) +{ +} + +static void msm_rpm_glink_open_work(struct work_struct *work) +{ + pr_debug("Opening glink channel\n"); + glink_data->glink_handle = glink_open(glink_data->open_cfg); + + if (IS_ERR_OR_NULL(glink_data->glink_handle)) { + pr_err("Error: glink_open failed %d\n", + (int)PTR_ERR(glink_data->glink_handle)); + WARN_ON(1); + } +} + +static void msm_rpm_glink_notifier_cb(struct glink_link_state_cb_info *cb_info, + void *priv) +{ + struct glink_open_config *open_config; + static bool first = true; + + if (!cb_info) { + pr_err("Missing callback data\n"); + return; + } + + switch (cb_info->link_state) { + case GLINK_LINK_STATE_UP: + if (first) + first = false; + else + break; + open_config = kzalloc(sizeof(*open_config), GFP_KERNEL); + if (!open_config) { + pr_err("Could not allocate memory\n"); + break; + } + + glink_data->open_cfg = open_config; + pr_debug("glink link state up cb receieved\n"); + INIT_WORK(&glink_data->work, msm_rpm_glink_open_work); + + open_config->priv = glink_data; + open_config->name = glink_data->name; + open_config->edge = glink_data->edge; + open_config->notify_rx = msm_rpm_trans_notify_rx; + open_config->notify_tx_done = msm_rpm_trans_notify_tx_done; + open_config->notify_state = msm_rpm_trans_notify_state; + schedule_work(&glink_data->work); + break; + default: + pr_err("Unrecognised state = %d\n", cb_info->link_state); + break; + }; +} + +static int msm_rpm_glink_dt_parse(struct platform_device *pdev, + struct glink_apps_rpm_data *glink_data) +{ + char *key = NULL; + int ret; + + if (of_device_is_compatible(pdev->dev.of_node, "qcom,rpm-glink")) { + glink_enabled = true; + } else { + pr_warn("qcom,rpm-glink compatible not matches\n"); + ret = -EINVAL; + return ret; + } + + key = "qcom,glink-edge"; + ret = of_property_read_string(pdev->dev.of_node, key, + &glink_data->edge); + if (ret) { + pr_err("Failed to read node: %s, key=%s\n", + pdev->dev.of_node->full_name, key); + return ret; + } + + key = "rpm-channel-name"; + ret = of_property_read_string(pdev->dev.of_node, key, + &glink_data->name); + if (ret) + pr_err("%s(): Failed to read node: %s, key=%s\n", __func__, + pdev->dev.of_node->full_name, key); + + return ret; +} + +static int msm_rpm_glink_link_setup(struct glink_apps_rpm_data *glink_data, + struct platform_device *pdev) +{ + struct glink_link_info *link_info; + void *link_state_cb_handle; + struct device *dev = &pdev->dev; + int ret = 0; + + link_info = devm_kzalloc(dev, sizeof(struct glink_link_info), + GFP_KERNEL); + if (!link_info) { + ret = -ENOMEM; + return ret; + } + + glink_data->link_info = link_info; + + /* + * Setup link info parameters + */ + link_info->edge = glink_data->edge; + link_info->glink_link_state_notif_cb = + msm_rpm_glink_notifier_cb; + link_state_cb_handle = glink_register_link_state_cb(link_info, NULL); + if (IS_ERR_OR_NULL(link_state_cb_handle)) { + pr_err("Could not register cb\n"); + ret = PTR_ERR(link_state_cb_handle); + return ret; + } + + spin_lock_init(&msm_rpm_data.smd_lock_read); + spin_lock_init(&msm_rpm_data.smd_lock_write); + + return ret; +} + +static int msm_rpm_dev_glink_probe(struct platform_device *pdev) +{ + int ret = -ENOMEM; + struct device *dev = &pdev->dev; + + glink_data = devm_kzalloc(dev, sizeof(*glink_data), GFP_KERNEL); + if (!glink_data) + return ret; + + ret = msm_rpm_glink_dt_parse(pdev, glink_data); + if (ret < 0) { + devm_kfree(dev, glink_data); + return ret; + } + + ret = msm_rpm_glink_link_setup(glink_data, pdev); + if (ret < 0) { + /* + * If the glink setup fails there is no + * fall back mechanism to SMD. + */ + pr_err("GLINK setup fail ret = %d\n", ret); + WARN_ON(1); + } + + return ret; +} + +static int msm_rpm_dev_probe(struct platform_device *pdev) +{ + char *key = NULL; + int ret = 0; + void __iomem *reg_base; + uint32_t version = V0_PROTOCOL_VERSION; /* set to default v0 format */ + + /* + * Check for standalone support + */ + key = "rpm-standalone"; + standalone = of_property_read_bool(pdev->dev.of_node, key); + if (standalone) { + probe_status = ret; + goto skip_init; + } + + reg_base = of_iomap(pdev->dev.of_node, 0); + + if (reg_base) { + version = readq_relaxed(reg_base); + iounmap(reg_base); + } + + if (version == V1_PROTOCOL_VERSION) + rpm_msg_fmt_ver = RPM_MSG_V1_FMT; + + pr_debug("RPM-SMD running version %d/n", rpm_msg_fmt_ver); + + ret = msm_rpm_dev_glink_probe(pdev); + if (!ret) { + pr_info("APSS-RPM communication over GLINK\n"); + msm_rpm_send_buffer = msm_rpm_glink_send_buffer; + of_platform_populate(pdev->dev.of_node, NULL, NULL, + &pdev->dev); + return ret; + } + msm_rpm_send_buffer = msm_rpm_send_smd_buffer; + + key = "rpm-channel-name"; + ret = of_property_read_string(pdev->dev.of_node, key, + &msm_rpm_data.ch_name); + if (ret) { + pr_err("%s(): Failed to read node: %s, key=%s\n", __func__, + pdev->dev.of_node->full_name, key); + goto fail; + } + + key = "rpm-channel-type"; + ret = of_property_read_u32(pdev->dev.of_node, key, + &msm_rpm_data.ch_type); + if (ret) { + pr_err("%s(): Failed to read node: %s, key=%s\n", __func__, + pdev->dev.of_node->full_name, key); + goto fail; + } + + ret = smd_named_open_on_edge(msm_rpm_data.ch_name, + msm_rpm_data.ch_type, + &msm_rpm_data.ch_info, + &msm_rpm_data, + msm_rpm_notify); + if (ret) { + if (ret != -EPROBE_DEFER) { + pr_err("%s: Cannot open RPM channel %s %d\n", + __func__, msm_rpm_data.ch_name, + msm_rpm_data.ch_type); + } + goto fail; + } + + spin_lock_init(&msm_rpm_data.smd_lock_write); + spin_lock_init(&msm_rpm_data.smd_lock_read); + tasklet_init(&data_tasklet, data_fn_tasklet, 0); + + wait_for_completion(&msm_rpm_data.smd_open); + + smd_disable_read_intr(msm_rpm_data.ch_info); + + msm_rpm_smd_wq = alloc_workqueue("rpm-smd", + WQ_UNBOUND | WQ_MEM_RECLAIM | WQ_HIGHPRI, 1); + if (!msm_rpm_smd_wq) { + pr_err("%s: Unable to alloc rpm-smd workqueue\n", __func__); + ret = -EINVAL; + goto fail; + } + queue_work(msm_rpm_smd_wq, &msm_rpm_data.work); + + probe_status = ret; +skip_init: + of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev); + + if (standalone) + pr_info("RPM running in standalone mode\n"); +fail: + return probe_status; +} + +static const struct of_device_id msm_rpm_match_table[] = { + {.compatible = "qcom,rpm-smd"}, + {.compatible = "qcom,rpm-glink"}, + {}, +}; + +static struct platform_driver msm_rpm_device_driver = { + .probe = msm_rpm_dev_probe, + .driver = { + .name = "rpm-smd", + .owner = THIS_MODULE, + .of_match_table = msm_rpm_match_table, + }, +}; + +int __init msm_rpm_driver_init(void) +{ + static bool registered; + + if (registered) + return 0; + registered = true; + + return platform_driver_register(&msm_rpm_device_driver); +} +EXPORT_SYMBOL(msm_rpm_driver_init); +arch_initcall(msm_rpm_driver_init); diff --git a/include/soc/qcom/rpm-notifier.h b/include/soc/qcom/rpm-notifier.h new file mode 100644 index 000000000000..22e1e2631df1 --- /dev/null +++ b/include/soc/qcom/rpm-notifier.h @@ -0,0 +1,63 @@ +/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +#ifndef __ARCH_ARM_MACH_MSM_RPM_NOTIF_H +#define __ARCH_ARM_MACH_MSM_RPM_NOTIF_H + +struct msm_rpm_notifier_data { + uint32_t rsc_type; + uint32_t rsc_id; + uint32_t key; + uint32_t size; + uint8_t *value; +}; +/** + * msm_rpm_register_notifier - Register for sleep set notifications + * + * @nb - notifier block to register + * + * return 0 on success, errno on failure. + */ +int msm_rpm_register_notifier(struct notifier_block *nb); + +/** + * msm_rpm_unregister_notifier - Unregister previously registered notifications + * + * @nb - notifier block to unregister + * + * return 0 on success, errno on failure. + */ +int msm_rpm_unregister_notifier(struct notifier_block *nb); + +/** + * msm_rpm_enter_sleep - Notify RPM driver to prepare for entering sleep + * + * @bool - flag to enable print contents of sleep buffer. + * @cpumask - cpumask of next wakeup cpu + * + * return 0 on success errno on failure. + */ +int msm_rpm_enter_sleep(bool print, const struct cpumask *cpumask); + +/** + * msm_rpm_exit_sleep - Notify RPM driver about resuming from power collapse + */ +void msm_rpm_exit_sleep(void); + +/** + * msm_rpm_waiting_for_ack - Indicate if there is RPM message + * pending acknowledgment. + * returns true for pending messages and false otherwise + */ +bool msm_rpm_waiting_for_ack(void); + +#endif /*__ARCH_ARM_MACH_MSM_RPM_NOTIF_H */ diff --git a/include/soc/qcom/rpm-smd.h b/include/soc/qcom/rpm-smd.h new file mode 100644 index 000000000000..853f82341556 --- /dev/null +++ b/include/soc/qcom/rpm-smd.h @@ -0,0 +1,494 @@ +/* Copyright (c) 2012, 2014-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include + +#ifndef __ARCH_ARM_MACH_MSM_RPM_SMD_H +#define __ARCH_ARM_MACH_MSM_RPM_SMD_H + +#define SMD_EVENT_DATA 1 +#define SMD_EVENT_OPEN 2 +#define SMD_EVENT_CLOSE 3 +#define SMD_EVENT_STATUS 4 +#define SMD_EVENT_REOPEN_READY 5 + +enum { + GLINK_CONNECTED, + GLINK_LOCAL_DISCONNECTED, + GLINK_REMOTE_DISCONNECTED, +}; + +enum tx_flags { + GLINK_TX_REQ_INTENT = 0x1, + GLINK_TX_SINGLE_THREADED = 0x2, + GLINK_TX_TRACER_PKT = 0x4, + GLINK_TX_ATOMIC = 0x8, +}; + +enum glink_link_state { + GLINK_LINK_STATE_UP, + GLINK_LINK_STATE_DOWN, +}; + +struct glink_link_state_cb_info { + const char *transport; + const char *edge; + enum glink_link_state link_state; +}; + +struct glink_link_info { + const char *transport; + const char *edge; + void (*glink_link_state_notif_cb)( + struct glink_link_state_cb_info *cb_info, + void *priv); +}; + +struct smd_channel { + void __iomem *send; /* some variant of smd_half_channel */ + void __iomem *recv; /* some variant of smd_half_channel */ + unsigned char *send_data; + unsigned char *recv_data; + unsigned int fifo_size; + struct list_head ch_list; + unsigned int current_packet; + unsigned int n; + void *priv; + void (*notify)(void *priv, unsigned int flags); + int (*read)(struct smd_channel *ch, void *data, int len); + int (*write)(struct smd_channel *ch, const void *data, int len, + bool int_ntfy); + int (*read_avail)(struct smd_channel *ch); + int (*write_avail)(struct smd_channel *ch); + int (*read_from_cb)(struct smd_channel *ch, void *data, int len); + void (*update_state)(struct smd_channel *ch); + unsigned int last_state; + void (*notify_other_cpu)(struct smd_channel *ch); + void * (*read_from_fifo)(void *dest, const void *src, size_t num_bytes); + void * (*write_to_fifo)(void *dest, const void *src, size_t num_bytes); + char name[20]; + struct platform_device pdev; + unsigned int type; + int pending_pkt_sz; + char is_pkt_ch; + /* + * private internal functions to access *send and *recv. + * never to be exported outside of smd + */ + struct smd_half_channel_access *half_ch; +}; + +struct glink_open_config { + void *priv; + uint32_t options; + const char *transport; + const char *edge; + const char *name; + unsigned int rx_intent_req_timeout_ms; + void (*notify_rx)(void *handle, const void *priv, const void *pkt_priv, + const void *ptr, size_t size); + void (*notify_tx_done)(void *handle, const void *priv, + const void *pkt_priv, const void *ptr); + void (*notify_state)(void *handle, const void *priv, + unsigned int event); + bool (*notify_rx_intent_req)(void *handle, const void *priv, + size_t req_size); + void (*notify_rxv)(void *handle, const void *priv, const void *pkt_priv, + void *iovec, size_t size, + void * (*vbuf_provider)(void *iovec, size_t offset, + size_t *size), + void * (*pbuf_provider)(void *iovec, size_t offset, + size_t *size)); + void (*notify_rx_sigs)(void *handle, const void *priv, + uint32_t old_sigs, uint32_t new_sigs); + void (*notify_rx_abort)(void *handle, const void *priv, + const void *pkt_priv); + void (*notify_tx_abort)(void *handle, const void *priv, + const void *pkt_priv); + void (*notify_rx_tracer_pkt)(void *handle, const void *priv, + const void *pkt_priv, const void *ptr, size_t size); + void (*notify_remote_rx_intent)(void *handle, const void *priv, + size_t size); +}; + +/** + * enum msm_rpm_set - RPM enumerations for sleep/active set + * %MSM_RPM_CTX_SET_0: Set resource parameters for active mode. + * %MSM_RPM_CTX_SET_SLEEP: Set resource parameters for sleep. + */ +enum msm_rpm_set { + MSM_RPM_CTX_ACTIVE_SET, + MSM_RPM_CTX_SLEEP_SET, +}; + +struct msm_rpm_request; + +struct msm_rpm_kvp { + uint32_t key; + uint32_t length; + uint8_t *data; +}; +#ifdef CONFIG_MSM_RPM_SMD +/** + * msm_rpm_request() - Creates a parent element to identify the + * resource on the RPM, that stores the KVPs for different fields modified + * for a hardware resource + * + * @set: if the device is setting the active/sleep set parameter + * for the resource + * @rsc_type: unsigned 32 bit integer that identifies the type of the resource + * @rsc_id: unsigned 32 bit that uniquely identifies a resource within a type + * @num_elements: number of KVPs pairs associated with the resource + * + * returns pointer to a msm_rpm_request on success, NULL on error + */ +struct msm_rpm_request *msm_rpm_create_request( + enum msm_rpm_set set, uint32_t rsc_type, + uint32_t rsc_id, int num_elements); + +/** + * msm_rpm_request_noirq() - Creates a parent element to identify the + * resource on the RPM, that stores the KVPs for different fields modified + * for a hardware resource. This function is similar to msm_rpm_create_request + * except that it has to be called with interrupts masked. + * + * @set: if the device is setting the active/sleep set parameter + * for the resource + * @rsc_type: unsigned 32 bit integer that identifies the type of the resource + * @rsc_id: unsigned 32 bit that uniquely identifies a resource within a type + * @num_elements: number of KVPs pairs associated with the resource + * + * returns pointer to a msm_rpm_request on success, NULL on error + */ +struct msm_rpm_request *msm_rpm_create_request_noirq( + enum msm_rpm_set set, uint32_t rsc_type, + uint32_t rsc_id, int num_elements); + +/** + * msm_rpm_add_kvp_data() - Adds a Key value pair to a existing RPM resource. + * + * @handle: RPM resource handle to which the data should be appended + * @key: unsigned integer identify the parameter modified + * @data: byte array that contains the value corresponding to key. + * @size: size of data in bytes. + * + * returns 0 on success or errno + */ +int msm_rpm_add_kvp_data(struct msm_rpm_request *handle, + uint32_t key, const uint8_t *data, int size); + +/** + * msm_rpm_add_kvp_data_noirq() - Adds a Key value pair to a existing RPM + * resource. This function is similar to msm_rpm_add_kvp_data except that it + * has to be called with interrupts masked. + * + * @handle: RPM resource handle to which the data should be appended + * @key: unsigned integer identify the parameter modified + * @data: byte array that contains the value corresponding to key. + * @size: size of data in bytes. + * + * returns 0 on success or errno + */ +int msm_rpm_add_kvp_data_noirq(struct msm_rpm_request *handle, + uint32_t key, const uint8_t *data, int size); + +/** msm_rpm_free_request() - clean up the RPM request handle created with + * msm_rpm_create_request + * + * @handle: RPM resource handle to be cleared. + */ + +void msm_rpm_free_request(struct msm_rpm_request *handle); + +/** + * msm_rpm_send_request() - Send the RPM messages using SMD. The function + * assigns a message id before sending the data out to the RPM. RPM hardware + * uses the message id to acknowledge the messages. + * + * @handle: pointer to the msm_rpm_request for the resource being modified. + * + * returns non-zero message id on success and zero on a failed transaction. + * The drivers use message id to wait for ACK from RPM. + */ +int msm_rpm_send_request(struct msm_rpm_request *handle); + +/** + * msm_rpm_send_request_noack() - Send the RPM messages using SMD. The function + * assigns a message id before sending the data out to the RPM. RPM hardware + * uses the message id to acknowledge the messages, but this API does not wait + * on the ACK for this message id and it does not add the message id to the wait + * list. + * + * @handle: pointer to the msm_rpm_request for the resource being modified. + * + * returns NULL on success and PTR_ERR on a failed transaction. + */ +void *msm_rpm_send_request_noack(struct msm_rpm_request *handle); + +/** + * msm_rpm_send_request_noirq() - Send the RPM messages using SMD. The + * function assigns a message id before sending the data out to the RPM. + * RPM hardware uses the message id to acknowledge the messages. This function + * is similar to msm_rpm_send_request except that it has to be called with + * interrupts masked. + * + * @handle: pointer to the msm_rpm_request for the resource being modified. + * + * returns non-zero message id on success and zero on a failed transaction. + * The drivers use message id to wait for ACK from RPM. + */ +int msm_rpm_send_request_noirq(struct msm_rpm_request *handle); + +/** + * msm_rpm_wait_for_ack() - A blocking call that waits for acknowledgment of + * a message from RPM. + * + * @msg_id: the return from msm_rpm_send_requests + * + * returns 0 on success or errno + */ +int msm_rpm_wait_for_ack(uint32_t msg_id); + +/** + * msm_rpm_wait_for_ack_noirq() - A blocking call that waits for acknowledgment + * of a message from RPM. This function is similar to msm_rpm_wait_for_ack + * except that it has to be called with interrupts masked. + * + * @msg_id: the return from msm_rpm_send_request + * + * returns 0 on success or errno + */ +int msm_rpm_wait_for_ack_noirq(uint32_t msg_id); + +/** + * msm_rpm_send_message() -Wrapper function for clients to send data given an + * array of key value pairs. + * + * @set: if the device is setting the active/sleep set parameter + * for the resource + * @rsc_type: unsigned 32 bit integer that identifies the type of the resource + * @rsc_id: unsigned 32 bit that uniquely identifies a resource within a type + * @kvp: array of KVP data. + * @nelem: number of KVPs pairs associated with the message. + * + * returns 0 on success and errno on failure. + */ +int msm_rpm_send_message(enum msm_rpm_set set, uint32_t rsc_type, + uint32_t rsc_id, struct msm_rpm_kvp *kvp, int nelems); + +/** + * msm_rpm_send_message_noack() -Wrapper function for clients to send data + * given an array of key value pairs without waiting for ack. + * + * @set: if the device is setting the active/sleep set parameter + * for the resource + * @rsc_type: unsigned 32 bit integer that identifies the type of the resource + * @rsc_id: unsigned 32 bit that uniquely identifies a resource within a type + * @kvp: array of KVP data. + * @nelem: number of KVPs pairs associated with the message. + * + * returns NULL on success and PTR_ERR(errno) on failure. + */ +void *msm_rpm_send_message_noack(enum msm_rpm_set set, uint32_t rsc_type, + uint32_t rsc_id, struct msm_rpm_kvp *kvp, int nelems); + +/** + * msm_rpm_send_message_noirq() -Wrapper function for clients to send data + * given an array of key value pairs. This function is similar to the + * msm_rpm_send_message() except that it has to be called with interrupts + * disabled. Clients should choose the irq version when possible for system + * performance. + * + * @set: if the device is setting the active/sleep set parameter + * for the resource + * @rsc_type: unsigned 32 bit integer that identifies the type of the resource + * @rsc_id: unsigned 32 bit that uniquely identifies a resource within a type + * @kvp: array of KVP data. + * @nelem: number of KVPs pairs associated with the message. + * + * returns 0 on success and errno on failure. + */ +int msm_rpm_send_message_noirq(enum msm_rpm_set set, uint32_t rsc_type, + uint32_t rsc_id, struct msm_rpm_kvp *kvp, int nelems); + +/** + * msm_rpm_driver_init() - Initialization function that registers for a + * rpm platform driver. + * + * returns 0 on success. + */ +int __init msm_rpm_driver_init(void); + +#else + +static inline struct msm_rpm_request *msm_rpm_create_request( + enum msm_rpm_set set, uint32_t rsc_type, + uint32_t rsc_id, int num_elements) +{ + return NULL; +} + +static inline struct msm_rpm_request *msm_rpm_create_request_noirq( + enum msm_rpm_set set, uint32_t rsc_type, + uint32_t rsc_id, int num_elements) +{ + return NULL; + +} +static inline uint32_t msm_rpm_add_kvp_data(struct msm_rpm_request *handle, + uint32_t key, const uint8_t *data, int count) +{ + return 0; +} +static inline uint32_t msm_rpm_add_kvp_data_noirq( + struct msm_rpm_request *handle, uint32_t key, + const uint8_t *data, int count) +{ + return 0; +} + +static inline void msm_rpm_free_request(struct msm_rpm_request *handle) +{ +} + +static inline int msm_rpm_send_request(struct msm_rpm_request *handle) +{ + return 0; +} + +static inline int msm_rpm_send_request_noirq(struct msm_rpm_request *handle) +{ + return 0; + +} + +static inline void *msm_rpm_send_request_noack(struct msm_rpm_request *handle) +{ + return NULL; +} + +static inline int msm_rpm_send_message(enum msm_rpm_set set, uint32_t rsc_type, + uint32_t rsc_id, struct msm_rpm_kvp *kvp, int nelems) +{ + return 0; +} + +static inline int msm_rpm_send_message_noirq(enum msm_rpm_set set, + uint32_t rsc_type, uint32_t rsc_id, struct msm_rpm_kvp *kvp, + int nelems) +{ + return 0; +} + +static inline void *msm_rpm_send_message_noack(enum msm_rpm_set set, + uint32_t rsc_type, uint32_t rsc_id, struct msm_rpm_kvp *kvp, + int nelems) +{ + return NULL; +} + +static inline int msm_rpm_wait_for_ack(uint32_t msg_id) +{ + return 0; + +} +static inline int msm_rpm_wait_for_ack_noirq(uint32_t msg_id) +{ + return 0; +} + +static inline int __init msm_rpm_driver_init(void) +{ + return 0; +} +#endif + +static inline int glink_rpm_rx_poll(void *handle) +{ + return -ENODEV; +} + +static inline int smd_is_pkt_avail(struct smd_channel *ch) +{ + return -ENODEV; +} + +static inline int smd_cur_packet_size(struct smd_channel *ch) +{ + return -ENODEV; +} + +static inline int smd_read_avail(struct smd_channel *ch) +{ + return -ENODEV; +} + +static inline int smd_read(struct smd_channel *ch, void *data, int len) +{ + return -ENODEV; +} + +static inline int smd_write_avail(struct smd_channel *ch) +{ + return -ENODEV; +} +static inline int smd_write(struct smd_channel *ch, const void *data, int len) +{ + return -ENODEV; +} + +static inline int glink_tx(void *handle, void *pkt_priv, void *data, + size_t size, uint32_t tx_flags) +{ + return -ENODEV; +} + +static inline int smd_mask_receive_interrupt(struct smd_channel *ch, bool mask, + const struct cpumask *cpumask) +{ + return -ENODEV; +} + +static inline int glink_rpm_mask_rx_interrupt(void *handle, bool mask, + void *pstruct) +{ + return -ENODEV; +} + +static inline int glink_rx_done(void *handle, const void *ptr, bool reuse) +{ + return -ENODEV; +} +static inline void *glink_open(const struct glink_open_config *cfg_ptr) +{ + return NULL; +} + +static inline void *glink_register_link_state_cb( + struct glink_link_info *link_info, void *priv) +{ + return NULL; +} + +static inline int smd_named_open_on_edge(const char *name, uint32_t edge, + struct smd_channel **_ch, void *priv, + void (*notify)(void *, unsigned int)) +{ + return -ENODEV; +} + +static inline void smd_disable_read_intr(struct smd_channel *ch) +{ +} + +#endif /*__ARCH_ARM_MACH_MSM_RPM_SMD_H*/ diff --git a/include/trace/events/trace_rpm_smd.h b/include/trace/events/trace_rpm_smd.h new file mode 100644 index 000000000000..1afc06b282f2 --- /dev/null +++ b/include/trace/events/trace_rpm_smd.h @@ -0,0 +1,111 @@ +/* Copyright (c) 2012, 2014-2017, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#undef TRACE_SYSTEM +#define TRACE_SYSTEM rpm_smd + +#if !defined(_TRACE_RPM_SMD_H) || defined(TRACE_HEADER_MULTI_READ) +#define _TRACE_RPM_SMD_H + +#include + +TRACE_EVENT(rpm_smd_ack_recvd, + + TP_PROTO(unsigned int irq, unsigned int msg_id, int errno), + + TP_ARGS(irq, msg_id, errno), + + TP_STRUCT__entry( + __field(int, irq) + __field(int, msg_id) + __field(int, errno) + ), + + TP_fast_assign( + __entry->irq = irq; + __entry->msg_id = msg_id; + __entry->errno = errno; + ), + + TP_printk("ctx:%s msg_id:%d errno:%08x", + __entry->irq ? "noslp" : "sleep", + __entry->msg_id, + __entry->errno) +); + +TRACE_EVENT(rpm_smd_interrupt_notify, + + TP_PROTO(char *dummy), + + TP_ARGS(dummy), + + TP_STRUCT__entry( + __field(char *, dummy) + ), + + TP_fast_assign( + __entry->dummy = dummy; + ), + + TP_printk("%s", __entry->dummy) +); + +DECLARE_EVENT_CLASS(rpm_send_msg, + + TP_PROTO(unsigned int msg_id, unsigned int rsc_type, + unsigned int rsc_id), + + TP_ARGS(msg_id, rsc_type, rsc_id), + + TP_STRUCT__entry( + __field(u32, msg_id) + __field(u32, rsc_type) + __field(u32, rsc_id) + __array(char, name, 5) + ), + + TP_fast_assign( + __entry->msg_id = msg_id; + __entry->name[4] = 0; + __entry->rsc_type = rsc_type; + __entry->rsc_id = rsc_id; + memcpy(__entry->name, &rsc_type, sizeof(uint32_t)); + + ), + + TP_printk("msg_id:%d, rsc_type:0x%08x(%s), rsc_id:0x%08x", + __entry->msg_id, + __entry->rsc_type, __entry->name, + __entry->rsc_id) +); + +DEFINE_EVENT(rpm_send_msg, rpm_smd_sleep_set, + TP_PROTO(unsigned int msg_id, unsigned int rsc_type, + unsigned int rsc_id), + TP_ARGS(msg_id, rsc_type, rsc_id) +); + +DEFINE_EVENT(rpm_send_msg, rpm_smd_send_sleep_set, + TP_PROTO(unsigned int msg_id, unsigned int rsc_type, + unsigned int rsc_id), + TP_ARGS(msg_id, rsc_type, rsc_id) +); + +DEFINE_EVENT(rpm_send_msg, rpm_smd_send_active_set, + TP_PROTO(unsigned int msg_id, unsigned int rsc_type, + unsigned int rsc_id), + TP_ARGS(msg_id, rsc_type, rsc_id) +); + +#endif +#define TRACE_INCLUDE_FILE trace_rpm_smd +#include -- GitLab From 02b9a686484b7edf4c8c2feb79e5b7bf4ff78217 Mon Sep 17 00:00:00 2001 From: Chris Lew Date: Wed, 9 May 2018 13:44:52 -0700 Subject: [PATCH 1495/1635] ARM: dts: msm: Fix wdsp glink node for sm8150 WDSP does not have a remote pid assigned to it because it is not a smem based processor. Remove the fake value since the remote pid is not required anymore. Add the label and glink label tags so glink register returns successfully. Change-Id: I35a08893d5fa90a818608d1b5e7c8fa082787889 Signed-off-by: Chris Lew --- arch/arm64/boot/dts/qcom/sm8150.dtsi | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/sm8150.dtsi b/arch/arm64/boot/dts/qcom/sm8150.dtsi index 39a57b3cc791..e867adf41704 100644 --- a/arch/arm64/boot/dts/qcom/sm8150.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150.dtsi @@ -2574,11 +2574,13 @@ }; glink_spi_xprt_wdsp: wdsp { - qcom,remote-pid = <10>; transport = "spi"; tx-descriptors = <0x12000 0x12004>; rx-descriptors = <0x1200c 0x12010>; + label = "wdsp"; + qcom,glink-label = "wdsp"; + qcom,wdsp_ctrl { qcom,glink-channels = "g_glink_ctrl"; qcom,intents = <0x400 1>; -- GitLab From 99c633523f9c0a8ccf02f8df6a786502e2a6660b Mon Sep 17 00:00:00 2001 From: Tony Truong Date: Mon, 30 Apr 2018 14:17:26 -0700 Subject: [PATCH 1496/1635] ARM: dts: msm: disable wil6210 for sm8150-sdx50m There is no WiGiG device connected on sm8150-sdx50m. Disable wil6210 on sm8150-sdx50m to prevent it from trying to initiate PCIe enumeration. Change-Id: I2ead8b06f3e0eaf2ca8ea05a3f172cb673259790 Signed-off-by: Tony Truong --- arch/arm64/boot/dts/qcom/sm8150-sdx50m.dtsi | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sm8150-sdx50m.dtsi b/arch/arm64/boot/dts/qcom/sm8150-sdx50m.dtsi index 27d4838f8320..258b23860f1b 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-sdx50m.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-sdx50m.dtsi @@ -38,6 +38,10 @@ }; }; +&wil6210 { + status = "disabled"; +}; + &mhi_0 { esoc-names = "mdm"; esoc-0 = <&mdm3>; -- GitLab From 0c1d40f5434dcd3224c2beafc8dd35f3b2bea49d Mon Sep 17 00:00:00 2001 From: Jilai Wang Date: Thu, 3 May 2018 16:59:19 -0400 Subject: [PATCH 1497/1635] npu: Save and restore BWMON registers NPU driver needs to save/restore some BWMON registers when suspend/resume bw monitor device. Change-Id: Id7f54bdf1d8d4dfad54d421dad22123db8e610cb Signed-off-by: Jilai Wang --- drivers/media/platform/msm/npu/npu_common.h | 12 +++++++ drivers/media/platform/msm/npu/npu_dev.c | 35 +++++++++++++++++++++ drivers/media/platform/msm/npu/npu_hw.h | 7 +++++ 3 files changed, 54 insertions(+) diff --git a/drivers/media/platform/msm/npu/npu_common.h b/drivers/media/platform/msm/npu/npu_common.h index 4ef0506afd98..0342cd02f0e7 100644 --- a/drivers/media/platform/msm/npu/npu_common.h +++ b/drivers/media/platform/msm/npu/npu_common.h @@ -136,6 +136,18 @@ struct npu_pwrlevel { long clk_freq[NUM_TOTAL_CLKS]; }; +/* + * struct npu_reg - Struct holding npu register information + * @ off - register offset + * @ val - register value + * @ valid - if register value is valid + */ +struct npu_reg { + uint32_t off; + uint32_t val; + bool valid; +}; + /** * struct npu_pwrctrl - Power control settings for a NPU device * @pwr_vote_num - voting information for power enable diff --git a/drivers/media/platform/msm/npu/npu_dev.c b/drivers/media/platform/msm/npu/npu_dev.c index 461bfd2a1bfd..d0a768059326 100644 --- a/drivers/media/platform/msm/npu/npu_dev.c +++ b/drivers/media/platform/msm/npu/npu_dev.c @@ -146,6 +146,15 @@ static const char * const npu_exclude_rate_clocks[] = { "bto_core_clk" }; +static struct npu_reg npu_saved_bw_registers[] = { + { BWMON2_SAMPLING_WINDOW, 0, false }, + { BWMON2_BYTE_COUNT_THRESHOLD_HIGH, 0, false }, + { BWMON2_BYTE_COUNT_THRESHOLD_MEDIUM, 0, false }, + { BWMON2_BYTE_COUNT_THRESHOLD_LOW, 0, false }, + { BWMON2_ZONE_ACTIONS, 0, false }, + { BWMON2_ZONE_COUNT_THRESHOLD, 0, false }, +}; + /* ------------------------------------------------------------------------- * Entry Points for Probe * ------------------------------------------------------------------------- @@ -406,6 +415,30 @@ int npu_set_uc_power_level(struct npu_device *npu_dev, * Bandwidth Related * ------------------------------------------------------------------------- */ +static void npu_save_bw_registers(struct npu_device *npu_dev) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(npu_saved_bw_registers); i++) { + npu_saved_bw_registers[i].val = REGR(npu_dev, + npu_saved_bw_registers[i].off); + npu_saved_bw_registers[i].valid = true; + } +} + +static void npu_restore_bw_registers(struct npu_device *npu_dev) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(npu_saved_bw_registers); i++) { + if (npu_saved_bw_registers[i].valid) { + REGW(npu_dev, npu_saved_bw_registers[i].off, + npu_saved_bw_registers[i].val); + npu_saved_bw_registers[i].valid = false; + } + } +} + static void npu_suspend_devbw(struct npu_device *npu_dev) { struct npu_pwrctrl *pwr = &npu_dev->pwrctrl; @@ -417,6 +450,7 @@ static void npu_suspend_devbw(struct npu_device *npu_dev) if (ret) pr_err("devfreq_suspend_devbw failed rc:%d\n", ret); + npu_save_bw_registers(npu_dev); } } @@ -427,6 +461,7 @@ static void npu_resume_devbw(struct npu_device *npu_dev) if (!pwr->bwmon_enabled) { pwr->bwmon_enabled = 1; + npu_restore_bw_registers(npu_dev); ret = devfreq_resume_devbw(pwr->devbw); if (ret) diff --git a/drivers/media/platform/msm/npu/npu_hw.h b/drivers/media/platform/msm/npu/npu_hw.h index 0c1e15bc0095..8ab802e41ee6 100644 --- a/drivers/media/platform/msm/npu/npu_hw.h +++ b/drivers/media/platform/msm/npu/npu_hw.h @@ -31,6 +31,13 @@ #define NPU_GPR14 (0x00100138) #define NPU_GPR15 (0x0010013C) +#define BWMON2_SAMPLING_WINDOW (0x001605A8) +#define BWMON2_BYTE_COUNT_THRESHOLD_HIGH (0x001605AC) +#define BWMON2_BYTE_COUNT_THRESHOLD_MEDIUM (0x001605B0) +#define BWMON2_BYTE_COUNT_THRESHOLD_LOW (0x001605B4) +#define BWMON2_ZONE_ACTIONS (0x001605B8) +#define BWMON2_ZONE_COUNT_THRESHOLD (0x001605BC) + #define CAL_DP_DMA_WR_RLD_CMD_0 (0x00580000) #define CAL_DP_DMA_RD_RLD_CMD_0 (0x00580004) #define CAL_DP_DMA_RD_RLD_CMD_1 (0x00580008) -- GitLab From fac956cbf1f3dc75219bcc7cec9b7acea91d3ab7 Mon Sep 17 00:00:00 2001 From: Tony Truong Date: Thu, 19 Apr 2018 15:38:29 -0700 Subject: [PATCH 1498/1635] ARM: dts: msm: realign PCIe1 SIDs to base SID for SM8150 PCIe core generates SID based on BDF (bus, device, function) hashing. Since root complex (RC) BDF is 0, the core will map it to the first zero out register which is its base SID. Realign all PCIe1 SIDs to its base SID for SM8150. Change-Id: I718640e5397983d62a946d3849358e978ca06cb4 Signed-off-by: Tony Truong --- arch/arm64/boot/dts/qcom/sm8150-pcie.dtsi | 32 +++++++++++------------ 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sm8150-pcie.dtsi b/arch/arm64/boot/dts/qcom/sm8150-pcie.dtsi index ed74b29fc452..15138c70df06 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-pcie.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-pcie.dtsi @@ -543,22 +543,22 @@ qcom,smmu-sid-base = <0x1e00>; - iommu-map = <0x0 &apps_smmu 0x1e10 0x1>, - <0x100 &apps_smmu 0x1e11 0x1>, - <0x200 &apps_smmu 0x1e12 0x1>, - <0x300 &apps_smmu 0x1e13 0x1>, - <0x400 &apps_smmu 0x1e14 0x1>, - <0x500 &apps_smmu 0x1e15 0x1>, - <0x600 &apps_smmu 0x1e16 0x1>, - <0x700 &apps_smmu 0x1e17 0x1>, - <0x800 &apps_smmu 0x1e18 0x1>, - <0x900 &apps_smmu 0x1e19 0x1>, - <0xa00 &apps_smmu 0x1e1a 0x1>, - <0xb00 &apps_smmu 0x1e1b 0x1>, - <0xc00 &apps_smmu 0x1e1c 0x1>, - <0xd00 &apps_smmu 0x1e1d 0x1>, - <0xe00 &apps_smmu 0x1e1e 0x1>, - <0xf00 &apps_smmu 0x1e1f 0x1>; + iommu-map = <0x0 &apps_smmu 0x1e00 0x1>, + <0x100 &apps_smmu 0x1e01 0x1>, + <0x200 &apps_smmu 0x1e02 0x1>, + <0x300 &apps_smmu 0x1e03 0x1>, + <0x400 &apps_smmu 0x1e04 0x1>, + <0x500 &apps_smmu 0x1e05 0x1>, + <0x600 &apps_smmu 0x1e06 0x1>, + <0x700 &apps_smmu 0x1e07 0x1>, + <0x800 &apps_smmu 0x1e08 0x1>, + <0x900 &apps_smmu 0x1e09 0x1>, + <0xa00 &apps_smmu 0x1e0a 0x1>, + <0xb00 &apps_smmu 0x1e0b 0x1>, + <0xc00 &apps_smmu 0x1e0c 0x1>, + <0xd00 &apps_smmu 0x1e0d 0x1>, + <0xe00 &apps_smmu 0x1e0e 0x1>, + <0xf00 &apps_smmu 0x1e0f 0x1>; qcom,msm-bus,name = "pcie1"; qcom,msm-bus,num-cases = <2>; -- GitLab From 09915150093b307d36ff1946fda099734f73468d Mon Sep 17 00:00:00 2001 From: Chris Lew Date: Tue, 1 May 2018 13:29:03 -0700 Subject: [PATCH 1499/1635] qrtr: mhi: Configure IPC mhi channel to autostart MHI will autostart the channel after the probe returns. This removes the race where packets can be received while the probe is running. Change-Id: I057621f283e71b1901d4b2d6a299964f0345a384 Signed-off-by: Chris Lew --- net/qrtr/mhi.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/net/qrtr/mhi.c b/net/qrtr/mhi.c index f2c67b93e07e..9370e48b5cbe 100644 --- a/net/qrtr/mhi.c +++ b/net/qrtr/mhi.c @@ -103,10 +103,6 @@ static int qcom_mhi_qrtr_probe(struct mhi_device *mhi_dev, dev_set_drvdata(&mhi_dev->dev, qdev); - rc = mhi_prepare_for_transfer(mhi_dev); - if (rc) - return rc; - dev_dbg(qdev->dev, "Qualcomm MHI QRTR driver probed\n"); return 0; -- GitLab From ab9aead5f3ea073c9671b8e8fe26c5cfe0eb54d5 Mon Sep 17 00:00:00 2001 From: "Bao D. Nguyen" Date: Wed, 9 May 2018 18:00:49 -0700 Subject: [PATCH 1500/1635] mmc: block: Add MMC's Header Files for User Space Apps Add MMC's header files needed by the user space applications. The added files are originally from the kernel version 4.9. Change-Id: I173b0eab341fc25305472fd92d4cbda299a08fb1 Signed-off-by: Bao D. Nguyen --- include/uapi/linux/mmc/Kbuild | 6 +++ include/uapi/linux/mmc/core.h | 37 ++++++++++++++++++ include/uapi/linux/mmc/mmc.h | 73 +++++++++++++++++++++++++++++++++++ 3 files changed, 116 insertions(+) create mode 100644 include/uapi/linux/mmc/Kbuild create mode 100644 include/uapi/linux/mmc/core.h create mode 100644 include/uapi/linux/mmc/mmc.h diff --git a/include/uapi/linux/mmc/Kbuild b/include/uapi/linux/mmc/Kbuild new file mode 100644 index 000000000000..ce4e88593605 --- /dev/null +++ b/include/uapi/linux/mmc/Kbuild @@ -0,0 +1,6 @@ +# UAPI Header export list +header-y += core.h +header-y += core.h +header-y += ioctl.h +header-y += mmc.h +header-y += mmc.h diff --git a/include/uapi/linux/mmc/core.h b/include/uapi/linux/mmc/core.h new file mode 100644 index 000000000000..6a0a2b1628cf --- /dev/null +++ b/include/uapi/linux/mmc/core.h @@ -0,0 +1,37 @@ +#ifndef UAPI_MMC_CORE_H +#define UAPI_MMC_CORE_H + +#define MMC_RSP_PRESENT (1 << 0) +#define MMC_RSP_136 (1 << 1) /* 136 bit response */ +#define MMC_RSP_CRC (1 << 2) /* expect valid crc */ +#define MMC_RSP_BUSY (1 << 3) /* card may send busy */ +#define MMC_RSP_OPCODE (1 << 4) /* response contains opcode */ + +#define MMC_CMD_MASK (3 << 5) /* non-SPI command type */ +#define MMC_CMD_AC (0 << 5) +#define MMC_CMD_ADTC (1 << 5) +#define MMC_CMD_BC (2 << 5) +#define MMC_CMD_BCR (3 << 5) + +#define MMC_RSP_SPI_S1 (1 << 7) /* one status byte */ +#define MMC_RSP_SPI_S2 (1 << 8) /* second byte */ +#define MMC_RSP_SPI_B4 (1 << 9) /* four data bytes */ +#define MMC_RSP_SPI_BUSY (1 << 10) /* card may send busy */ + +/* + * These are the native response types, and correspond to valid bit + * patterns of the above flags. One additional valid pattern + * is all zeros, which means we don't expect a response. + */ +#define MMC_RSP_NONE (0) +#define MMC_RSP_R1 (MMC_RSP_PRESENT|MMC_RSP_CRC|MMC_RSP_OPCODE) +#define MMC_RSP_R1B (MMC_RSP_PRESENT|MMC_RSP_CRC|MMC_RSP_OPCODE|\ + MMC_RSP_BUSY) +#define MMC_RSP_R2 (MMC_RSP_PRESENT|MMC_RSP_136|MMC_RSP_CRC) +#define MMC_RSP_R3 (MMC_RSP_PRESENT) +#define MMC_RSP_R4 (MMC_RSP_PRESENT) +#define MMC_RSP_R5 (MMC_RSP_PRESENT|MMC_RSP_CRC|MMC_RSP_OPCODE) +#define MMC_RSP_R6 (MMC_RSP_PRESENT|MMC_RSP_CRC|MMC_RSP_OPCODE) +#define MMC_RSP_R7 (MMC_RSP_PRESENT|MMC_RSP_CRC|MMC_RSP_OPCODE) + +#endif /* UAPI_MMC_CORE_H */ diff --git a/include/uapi/linux/mmc/mmc.h b/include/uapi/linux/mmc/mmc.h new file mode 100644 index 000000000000..8de329bfe47e --- /dev/null +++ b/include/uapi/linux/mmc/mmc.h @@ -0,0 +1,73 @@ +#ifndef UAPI_MMC_MMC_H +#define UAPI_MMC_MMC_H + +/* Standard MMC commands (4.1) type argument response */ + /* class 1 */ +#define MMC_GO_IDLE_STATE 0 /* bc */ +#define MMC_SEND_OP_COND 1 /* bcr [31:0] OCR R3 */ +#define MMC_ALL_SEND_CID 2 /* bcr R2 */ +#define MMC_SET_RELATIVE_ADDR 3 /* ac [31:16] RCA R1 */ +#define MMC_SET_DSR 4 /* bc [31:16] RCA */ +#define MMC_SLEEP_AWAKE 5 /* ac [31:16] RCA 15:flg R1b */ +#define MMC_SWITCH 6 /* ac [31:0] See below R1b */ +#define MMC_SELECT_CARD 7 /* ac [31:16] RCA R1 */ +#define MMC_SEND_EXT_CSD 8 /* adtc R1 */ +#define MMC_SEND_CSD 9 /* ac [31:16] RCA R2 */ +#define MMC_SEND_CID 10 /* ac [31:16] RCA R2 */ +#define MMC_READ_DAT_UNTIL_STOP 11 /* adtc [31:0] dadr R1 */ +#define MMC_STOP_TRANSMISSION 12 /* ac R1b */ +#define MMC_SEND_STATUS 13 /* ac [31:16] RCA R1 */ +#define MMC_BUS_TEST_R 14 /* adtc R1 */ +#define MMC_GO_INACTIVE_STATE 15 /* ac [31:16] RCA */ +#define MMC_BUS_TEST_W 19 /* adtc R1 */ +#define MMC_SPI_READ_OCR 58 /* spi spi_R3 */ +#define MMC_SPI_CRC_ON_OFF 59 /* spi [0:0] flag spi_R1 */ + + /* class 2 */ +#define MMC_SET_BLOCKLEN 16 /* ac [31:0] block len R1 */ +#define MMC_READ_SINGLE_BLOCK 17 /* adtc [31:0] data addr R1 */ +#define MMC_READ_MULTIPLE_BLOCK 18 /* adtc [31:0] data addr R1 */ +#define MMC_SEND_TUNING_BLOCK 19 /* adtc R1 */ +#define MMC_SEND_TUNING_BLOCK_HS200 21 /* adtc R1 */ +#define MMC_SEND_TUNING_BLOCK_HS400 MMC_SEND_TUNING_BLOCK_HS200 + +#define MMC_TUNING_BLK_PATTERN_4BIT_SIZE 64 +#define MMC_TUNING_BLK_PATTERN_8BIT_SIZE 128 + + /* class 3 */ +#define MMC_WRITE_DAT_UNTIL_STOP 20 /* adtc [31:0] data addr R1 */ + + /* class 4 */ +#define MMC_SET_BLOCK_COUNT 23 /* adtc [31:0] data addr R1 */ +#define MMC_WRITE_BLOCK 24 /* adtc [31:0] data addr R1 */ +#define MMC_WRITE_MULTIPLE_BLOCK 25 /* adtc R1 */ +#define MMC_PROGRAM_CID 26 /* adtc R1 */ +#define MMC_PROGRAM_CSD 27 /* adtc R1 */ + + /* class 6 */ +#define MMC_SET_WRITE_PROT 28 /* ac [31:0] data addr R1b */ +#define MMC_CLR_WRITE_PROT 29 /* ac [31:0] data addr R1b */ +#define MMC_SEND_WRITE_PROT 30 /* adtc [31:0] wpdata addr R1 */ + + /* class 5 */ +#define MMC_ERASE_GROUP_START 35 /* ac [31:0] data addr R1 */ +#define MMC_ERASE_GROUP_END 36 /* ac [31:0] data addr R1 */ +#define MMC_ERASE 38 /* ac R1b */ + + /* class 9 */ +#define MMC_FAST_IO 39 /* ac R4 */ +#define MMC_GO_IRQ_STATE 40 /* bcr R5 */ + + /* class 7 */ +#define MMC_LOCK_UNLOCK 42 /* adtc R1b */ + + /* class 8 */ +#define MMC_APP_CMD 55 /* ac [31:16] RCA R1 */ +#define MMC_GEN_CMD 56 /* adtc [0] RD/WR R1 */ + +/* class 11 */ +#define MMC_CMDQ_TASK_MGMT 48 /* ac [31:0] task ID R1b */ +#define DISCARD_QUEUE 0x1 +#define DISCARD_TASK 0x2 + +#endif /* UAPI_MMC_MMC_H */ -- GitLab From 25bdfd2b551595701c30a4f1e2d51d8a86f166e8 Mon Sep 17 00:00:00 2001 From: Jack Pham Date: Tue, 13 Mar 2018 18:54:17 -0700 Subject: [PATCH 1501/1635] usb: dwc3-msm: Reduce usage of usb power_supply On platforms with multiple USB controller instances, usually only one is associated with the charger and the single instance of the "usb" power_supply. Thus the non-charging instances do not need to access it. Even in that case it is now only useful for setting max current based on enumeration in device mode. It is no longer required to query for PROP_PRESENT during probe so getting of the usb_psy can be removed there as well. Finally remove setting of PROP_BOOST_CURRENT which is also no longer used. Change-Id: I6f393105b65c6580a92e3161d16b1e2dce11a37d Signed-off-by: Jack Pham --- drivers/usb/dwc3/dwc3-msm.c | 47 ++----------------------------------- 1 file changed, 2 insertions(+), 45 deletions(-) diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c index 008c23d880dd..f5b04265e5af 100644 --- a/drivers/usb/dwc3/dwc3-msm.c +++ b/drivers/usb/dwc3/dwc3-msm.c @@ -3110,7 +3110,6 @@ static int dwc3_msm_probe(struct platform_device *pdev) { struct device_node *node = pdev->dev.of_node, *dwc3_node; struct device *dev = &pdev->dev; - union power_supply_propval pval = {0}; struct dwc3_msm *mdwc; struct dwc3 *dwc; struct resource *res; @@ -3361,26 +3360,12 @@ static int dwc3_msm_probe(struct platform_device *pdev) } mutex_init(&mdwc->suspend_resume_mutex); - mdwc->usb_psy = power_supply_get_by_name("usb"); - if (!mdwc->usb_psy) { - dev_warn(mdwc->dev, "Could not get usb power_supply\n"); - pval.intval = -EINVAL; - } else { - power_supply_get_property(mdwc->usb_psy, - POWER_SUPPLY_PROP_PRESENT, &pval); - } ret = dwc3_msm_extcon_register(mdwc); if (ret) - goto put_psy; + goto put_dwc3; - if (!pval.intval) { - /* USB cable is not connected */ - schedule_delayed_work(&mdwc->sm_work, 0); - } else { - if (!mdwc->vbus_active && mdwc->id_state && pval.intval > 0) - dev_info(mdwc->dev, "charger detection in progress\n"); - } + schedule_delayed_work(&mdwc->sm_work, 0); device_create_file(&pdev->dev, &dev_attr_mode); device_create_file(&pdev->dev, &dev_attr_speed); @@ -3395,10 +3380,6 @@ static int dwc3_msm_probe(struct platform_device *pdev) return 0; -put_psy: - if (mdwc->usb_psy) - power_supply_put(mdwc->usb_psy); - put_dwc3: if (mdwc->bus_perf_client) msm_bus_scale_unregister_client(mdwc->bus_perf_client); @@ -3499,18 +3480,10 @@ static int dwc3_msm_host_notifier(struct notifier_block *nb, struct dwc3_msm *mdwc = container_of(nb, struct dwc3_msm, host_nb); struct dwc3 *dwc = platform_get_drvdata(mdwc->dwc3); struct usb_device *udev = ptr; - union power_supply_propval pval; - unsigned int max_power; if (event != USB_DEVICE_ADD && event != USB_DEVICE_REMOVE) return NOTIFY_DONE; - if (!mdwc->usb_psy) { - mdwc->usb_psy = power_supply_get_by_name("usb"); - if (!mdwc->usb_psy) - return NOTIFY_DONE; - } - /* * For direct-attach devices, new udev is direct child of root hub * i.e. dwc -> xhci -> root_hub -> udev @@ -3533,23 +3506,7 @@ static int dwc3_msm_host_notifier(struct notifier_block *nb, } else { mdwc->max_rh_port_speed = USB_SPEED_SUPER; } - - if (udev->speed >= USB_SPEED_SUPER) - max_power = udev->actconfig->desc.bMaxPower * 8; - else - max_power = udev->actconfig->desc.bMaxPower * 2; - dev_dbg(mdwc->dev, "%s configured bMaxPower:%d (mA)\n", - dev_name(&udev->dev), max_power); - - /* inform PMIC of max power so it can optimize boost */ - pval.intval = max_power * 1000; - power_supply_set_property(mdwc->usb_psy, - POWER_SUPPLY_PROP_BOOST_CURRENT, &pval); } else { - pval.intval = 0; - power_supply_set_property(mdwc->usb_psy, - POWER_SUPPLY_PROP_BOOST_CURRENT, &pval); - /* set rate back to default core clk rate */ clk_set_rate(mdwc->core_clk, mdwc->core_clk_rate); dev_dbg(mdwc->dev, "set core clk rate %ld\n", -- GitLab From 98eb6b6f5077ee7a4a02383cc2c72ee5e4cc26dd Mon Sep 17 00:00:00 2001 From: Jack Pham Date: Fri, 16 Mar 2018 14:03:52 -0700 Subject: [PATCH 1502/1635] extcon: usb-gpio: Add support for optional VBUS output enable GPIO On many platforms 5V VBUS output can be provided by external circuitry and turned on via GPIO. For convenience, on micro-AB ports this can be done in conjunction when ID pin becomes low meaning USB_HOST mode is to be entered. Add support for an optional "vbus-out" GPIO to this driver. Change-Id: Id58e5dca5375b8140c75ce7cd6769dd8a31a2af7 Signed-off-by: Jack Pham --- .../devicetree/bindings/extcon/extcon-usb-gpio.txt | 3 +++ drivers/extcon/extcon-usb-gpio.c | 13 ++++++++++++- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/extcon/extcon-usb-gpio.txt b/Documentation/devicetree/bindings/extcon/extcon-usb-gpio.txt index dfc14f71e81f..1e904ca94538 100644 --- a/Documentation/devicetree/bindings/extcon/extcon-usb-gpio.txt +++ b/Documentation/devicetree/bindings/extcon/extcon-usb-gpio.txt @@ -10,6 +10,9 @@ Either one of id-gpio or vbus-gpio must be present. Both can be present as well. - id-gpio: gpio for USB ID pin. See gpio binding. - vbus-gpio: gpio for USB VBUS pin. +Optional properties: +- vbus-out-gpio: gpio for enabling VBUS output (e.g. when entering host mode) + Example: Examples of extcon-usb-gpio node in dra7-evm.dts as listed below: extcon_usb1 { compatible = "linux,extcon-usb-gpio"; diff --git a/drivers/extcon/extcon-usb-gpio.c b/drivers/extcon/extcon-usb-gpio.c index 9c925b05b7aa..85c6dee974cc 100644 --- a/drivers/extcon/extcon-usb-gpio.c +++ b/drivers/extcon/extcon-usb-gpio.c @@ -36,6 +36,7 @@ struct usb_extcon_info { struct gpio_desc *id_gpiod; struct gpio_desc *vbus_gpiod; + struct gpio_desc *vbus_out_gpiod; int id_irq; int vbus_irq; @@ -80,12 +81,17 @@ static void usb_extcon_detect_cable(struct work_struct *work) gpiod_get_value_cansleep(info->vbus_gpiod) : id; /* at first we clean states which are no longer active */ - if (id) + if (id) { + if (info->vbus_out_gpiod) + gpiod_set_value_cansleep(info->vbus_out_gpiod, 0); extcon_set_state_sync(info->edev, EXTCON_USB_HOST, false); + } if (!vbus) extcon_set_state_sync(info->edev, EXTCON_USB, false); if (!id) { + if (info->vbus_out_gpiod) + gpiod_set_value_cansleep(info->vbus_out_gpiod, 1); extcon_set_state_sync(info->edev, EXTCON_USB_HOST, true); } else { if (vbus) @@ -121,6 +127,8 @@ static int usb_extcon_probe(struct platform_device *pdev) info->id_gpiod = devm_gpiod_get_optional(&pdev->dev, "id", GPIOD_IN); info->vbus_gpiod = devm_gpiod_get_optional(&pdev->dev, "vbus", GPIOD_IN); + info->vbus_out_gpiod = devm_gpiod_get_optional(&pdev->dev, "vbus-out", + GPIOD_OUT_HIGH); if (!info->id_gpiod && !info->vbus_gpiod) { dev_err(dev, "failed to get gpios\n"); @@ -133,6 +141,9 @@ static int usb_extcon_probe(struct platform_device *pdev) if (IS_ERR(info->vbus_gpiod)) return PTR_ERR(info->vbus_gpiod); + if (IS_ERR(info->vbus_out_gpiod)) + return PTR_ERR(info->vbus_out_gpiod); + info->edev = devm_extcon_dev_allocate(dev, usb_extcon_cable); if (IS_ERR(info->edev)) { dev_err(dev, "failed to allocate extcon device\n"); -- GitLab From bea9622fa0e4f89aedaee1d7dce10388210aceda Mon Sep 17 00:00:00 2001 From: Fenglin Wu Date: Tue, 8 May 2018 12:50:55 +0800 Subject: [PATCH 1503/1635] ARM: dts: msm: update LPG/LED configuration in PM855L Add ramp configurations for the LPG channels so that the RGB LEDs connecting to these channels can be controlled with blinking patterns. Also add timer as the default trigger for RGB LEDs. Change-Id: I7a416a724cfca177b1ab16546ffa197e56f70e26 Signed-off-by: Fenglin Wu --- arch/arm64/boot/dts/qcom/pm855l.dtsi | 41 ++++++++++++++++++++++++++-- 1 file changed, 39 insertions(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/pm855l.dtsi b/arch/arm64/boot/dts/qcom/pm855l.dtsi index 5edc237769d2..39317f5d237e 100644 --- a/arch/arm64/boot/dts/qcom/pm855l.dtsi +++ b/arch/arm64/boot/dts/qcom/pm855l.dtsi @@ -296,9 +296,43 @@ pm855l_lpg: qcom,pwms@b100 { compatible = "qcom,pwm-lpg"; - reg = <0xb100 0x300>; - reg-names = "lpg-base"; + reg = <0xb100 0x300>, <0xb000 0x100>; + reg-names = "lpg-base", "lut-base"; #pwm-cells = <2>; + qcom,lut-patterns = <0 10 20 30 40 50 60 70 80 90 100 + 90 80 70 60 50 40 30 20 10 0>; + lpg1 { + qcom,lpg-chan-id = <1>; + qcom,ramp-step-ms = <100>; + qcom,ramp-pause-hi-count = <2>; + qcom,ramp-pause-lo-count = <2>; + qcom,ramp-low-index = <0>; + qcom,ramp-high-index = <20>; + qcom,ramp-from-low-to-high; + qcom,ramp-pattern-repeat; + }; + + lpg2 { + qcom,lpg-chan-id = <2>; + qcom,ramp-step-ms = <100>; + qcom,ramp-pause-hi-count = <2>; + qcom,ramp-pause-lo-count = <2>; + qcom,ramp-low-index = <0>; + qcom,ramp-high-index = <20>; + qcom,ramp-from-low-to-high; + qcom,ramp-pattern-repeat; + }; + + lpg3 { + qcom,lpg-chan-id = <3>; + qcom,ramp-step-ms = <100>; + qcom,ramp-pause-hi-count = <2>; + qcom,ramp-pause-lo-count = <2>; + qcom,ramp-low-index = <0>; + qcom,ramp-high-index = <20>; + qcom,ramp-from-low-to-high; + qcom,ramp-pattern-repeat; + }; }; pm855l_rgb_led: qcom,leds@d000 { @@ -308,16 +342,19 @@ label = "red"; pwms = <&pm855l_lpg 0 1000000>; led-sources = <0>; + linux,default-trigger = "timer"; }; green { label = "green"; pwms = <&pm855l_lpg 1 1000000>; led-sources = <1>; + linux,default-trigger = "timer"; }; blue { label = "blue"; pwms = <&pm855l_lpg 2 1000000>; led-sources = <2>; + linux,default-trigger = "timer"; }; }; }; -- GitLab From 8319c94653b61087a4593091cac3c34147bb4422 Mon Sep 17 00:00:00 2001 From: Manikanta Kanamarlapudi Date: Thu, 15 Feb 2018 16:41:59 +0530 Subject: [PATCH 1504/1635] msm: vidc: Add support to config nal size for encoder Parse nal video stream format supported capabilities from sys init done msg packet and update in session capabilities. Add interface to query and configure nal size by clients using V4L2_CID_MPEG_VIDC_VIDEO_STREAM_FORMAT control. Change-Id: I3300139bf4d2ea16e8bdf294e55b0032a37073d6 Signed-off-by: Zhongbo Shi --- .../platform/msm/vidc/hfi_response_handler.c | 40 +++++++++++++++++++ drivers/media/platform/msm/vidc/msm_venc.c | 31 +++++++++++++- drivers/media/platform/msm/vidc/msm_vidc.c | 4 ++ 3 files changed, 74 insertions(+), 1 deletion(-) diff --git a/drivers/media/platform/msm/vidc/hfi_response_handler.c b/drivers/media/platform/msm/vidc/hfi_response_handler.c index 98b0de785294..9d098d7408c0 100644 --- a/drivers/media/platform/msm/vidc/hfi_response_handler.c +++ b/drivers/media/platform/msm/vidc/hfi_response_handler.c @@ -858,6 +858,37 @@ static int copy_caps_to_sessions(struct hfi_capability_supported *cap, return 0; } +static int copy_nal_stream_format_caps_to_sessions(u32 nal_stream_format_value, + struct msm_vidc_capability *capabilities, u32 num_sessions, + u32 codecs, u32 domain) +{ + u32 i = 0; + struct msm_vidc_capability *capability; + u32 sess_codec; + u32 sess_domain; + + for (i = 0; i < num_sessions; i++) { + sess_codec = 0; + sess_domain = 0; + capability = &capabilities[i]; + + if (capability->codec) + sess_codec = + vidc_get_hfi_codec(capability->codec); + if (capability->domain) + sess_domain = + vidc_get_hfi_domain(capability->domain); + + if (!(sess_codec & codecs && sess_domain & domain)) + continue; + + capability->nal_stream_format.nal_stream_format_supported = + nal_stream_format_value; + } + + return 0; +} + static enum vidc_status hfi_parse_init_done_properties( struct msm_vidc_capability *capabilities, u32 num_sessions, u8 *data_ptr, u32 num_properties, @@ -986,6 +1017,15 @@ static enum vidc_status hfi_parse_init_done_properties( } case HFI_PROPERTY_PARAM_NAL_STREAM_FORMAT_SUPPORTED: { + struct hfi_nal_stream_format_supported *prop = + (struct hfi_nal_stream_format_supported *) + (data_ptr + next_offset); + + copy_nal_stream_format_caps_to_sessions( + prop->nal_stream_format_supported, + capabilities, num_sessions, + codecs, domain); + next_offset += sizeof(struct hfi_nal_stream_format_supported); num_properties--; diff --git a/drivers/media/platform/msm/vidc/msm_venc.c b/drivers/media/platform/msm/vidc/msm_venc.c index 2ac86ca75a69..05d304a90320 100644 --- a/drivers/media/platform/msm/vidc/msm_venc.c +++ b/drivers/media/platform/msm/vidc/msm_venc.c @@ -147,6 +147,15 @@ static const char *const iframe_sizes[] = { "Unlimited" }; +static const char *const mpeg_video_stream_format[] = { + "NAL Format Start Codes", + "NAL Format One NAL Per Buffer", + "NAL Format One Byte Length", + "NAL Format Two Byte Length", + "NAL Format Four Byte Length", + NULL +}; + static struct msm_vidc_ctrl msm_venc_ctrls[] = { { .id = V4L2_CID_MPEG_VIDC_VIDEO_IDR_PERIOD, @@ -1097,7 +1106,19 @@ static struct msm_vidc_ctrl msm_venc_ctrls[] = { .step = 1, .qmenu = NULL, }, - + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_STREAM_FORMAT, + .name = "NAL Format", + .type = V4L2_CTRL_TYPE_MENU, + .minimum = V4L2_MPEG_VIDC_VIDEO_NAL_FORMAT_STARTCODES, + .maximum = V4L2_MPEG_VIDC_VIDEO_NAL_FORMAT_FOUR_BYTE_LENGTH, + .default_value = V4L2_MPEG_VIDC_VIDEO_NAL_FORMAT_STARTCODES, + .menu_skip_mask = ~( + (1 << V4L2_MPEG_VIDC_VIDEO_NAL_FORMAT_STARTCODES) | + (1 << V4L2_MPEG_VIDC_VIDEO_NAL_FORMAT_FOUR_BYTE_LENGTH) + ), + .qmenu = mpeg_video_stream_format, + }, }; #define NUM_CTRLS ARRAY_SIZE(msm_venc_ctrls) @@ -1226,6 +1247,7 @@ int msm_venc_s_ctrl(struct msm_vidc_inst *inst, struct v4l2_ctrl *ctrl) struct hal_vui_timing_info vui_timing_info = {0}; enum hal_iframesize_type iframesize_type = HAL_IFRAMESIZE_TYPE_DEFAULT; u32 color_primaries, custom_matrix; + struct hal_nal_stream_format_select stream_format; if (!inst || !inst->core || !inst->core->device) { dprintk(VIDC_ERR, "%s invalid parameters\n", __func__); @@ -2024,6 +2046,13 @@ int msm_venc_s_ctrl(struct msm_vidc_inst *inst, struct v4l2_ctrl *ctrl) vui_timing_info.time_scale = NSEC_PER_SEC; break; } + case V4L2_CID_MPEG_VIDC_VIDEO_STREAM_FORMAT: + { + property_id = HAL_PARAM_NAL_STREAM_FORMAT_SELECT; + stream_format.nal_stream_format_select = BIT(ctrl->val); + pdata = &stream_format; + break; + } case V4L2_CID_MPEG_VIDC_VIDEO_LTRCOUNT: case V4L2_CID_MPEG_VIDC_VENC_PARAM_SAR_WIDTH: case V4L2_CID_MPEG_VIDC_VENC_PARAM_SAR_HEIGHT: diff --git a/drivers/media/platform/msm/vidc/msm_vidc.c b/drivers/media/platform/msm/vidc/msm_vidc.c index 4374878a8e6f..bf03300d9706 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc.c +++ b/drivers/media/platform/msm/vidc/msm_vidc.c @@ -1553,6 +1553,10 @@ static int try_get_ctrl(struct msm_vidc_inst *inst, struct v4l2_ctrl *ctrl) case V4L2_CID_MPEG_VIDC_VIDEO_TME_PAYLOAD_VERSION: ctrl->val = inst->capability.tme_version; break; + case V4L2_CID_MPEG_VIDC_VIDEO_STREAM_FORMAT: + ctrl->val = + inst->capability.nal_stream_format.nal_stream_format_supported; + break; default: /* * Other controls aren't really volatile, shouldn't need to -- GitLab From 23ce9b785f44904496cce6b3ae8cdc4b43b7f1ac Mon Sep 17 00:00:00 2001 From: Jayant Shekhar Date: Tue, 27 Feb 2018 14:43:53 +0530 Subject: [PATCH 1505/1635] msm/sde/rotator: Correct Offline Rotator OT settings Update the OT settings as per latest DCVS recommended settings. Change-Id: I157413522c9a6422f40e91d2ec5c3dfe323988f7 Signed-off-by: Jayant Shekhar --- .../platform/msm/sde/rotator/sde_rotator_base.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_base.c b/drivers/media/platform/msm/sde/rotator/sde_rotator_base.c index 0d1b82e24dfa..5fc3fc04e5a7 100644 --- a/drivers/media/platform/msm/sde/rotator/sde_rotator_base.c +++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_base.c @@ -217,12 +217,18 @@ u32 sde_mdp_get_ot_limit(u32 width, u32 height, u32 pixfmt, u32 fps, u32 is_rd) SDEROT_DBG("w:%d h:%d fps:%d pixfmt:%8.8x yuv:%d res:%llu rd:%d\n", width, height, fps, pixfmt, is_yuv, res, is_rd); + if (!is_yuv) + goto exit; + + /* + * If (total_source_pixels <= 62208000 && YUV) -> RD/WROT=2 //1080p30 + * If (total_source_pixels <= 124416000 && YUV) -> RD/WROT=4 //1080p60 + * If (total_source_pixels <= 2160p && YUV && FPS <= 30) -> RD/WROT = 32 + */ if (res <= (RES_1080p * 30)) ot_lim = 2; else if (res <= (RES_1080p * 60)) ot_lim = 4; - else if (res <= (RES_UHD * 30)) - ot_lim = 8; exit: SDEROT_DBG("ot_lim=%d\n", ot_lim); @@ -252,6 +258,8 @@ static u32 get_ot_limit(u32 reg_off, u32 bit_off, val &= (0xFF << bit_off); val = val >> bit_off; + SDEROT_EVTLOG(val, ot_lim); + if (val == ot_lim) ot_lim = 0; -- GitLab From 4895a58267abb7a2e331b259f181d23c77d13077 Mon Sep 17 00:00:00 2001 From: Maulik Shah Date: Mon, 7 May 2018 12:19:17 +0530 Subject: [PATCH 1506/1635] drivers: cpuidle: lpm-levels: Update failure print Remove unused goto statement and update failure print. Change-Id: Ie85dc1c5f42c6434961bc3787c09012c406b3f75 Signed-off-by: Maulik Shah --- drivers/cpuidle/lpm-levels.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/cpuidle/lpm-levels.c b/drivers/cpuidle/lpm-levels.c index 3a091ea013c7..c7865bc273c6 100644 --- a/drivers/cpuidle/lpm-levels.c +++ b/drivers/cpuidle/lpm-levels.c @@ -1753,12 +1753,10 @@ static int __init lpm_levels_module_init(void) #endif rc = platform_driver_register(&lpm_driver); - if (rc) { - pr_info("Error registering %s\n", lpm_driver.driver.name); - goto fail; - } + if (rc) + pr_info("Error registering %s rc=%d\n", lpm_driver.driver.name, + rc); -fail: return rc; } late_initcall(lpm_levels_module_init); -- GitLab From bfd2244eb07f23c42d2d49606a25a087714ab987 Mon Sep 17 00:00:00 2001 From: Saranya Chidura Date: Fri, 4 May 2018 12:32:19 +0530 Subject: [PATCH 1507/1635] defconfig: set the default remote_etm to 0 for qcs405 Set CORESIGHT_REMOTE_ETM_DEFAULT_ENABLE config to 0 for qcs405. Change-Id: I2a8a2bbfe5d9c2efba0e5bb9271b45c5d0cfc2e8 Signed-off-by: Saranya Chidura --- arch/arm/configs/qcs405_defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/configs/qcs405_defconfig b/arch/arm/configs/qcs405_defconfig index 5ddcb0c1079c..33403ac916fe 100644 --- a/arch/arm/configs/qcs405_defconfig +++ b/arch/arm/configs/qcs405_defconfig @@ -404,6 +404,7 @@ CONFIG_CORESIGHT_TPDA=y CONFIG_CORESIGHT_TPDM=y CONFIG_CORESIGHT_HWEVENT=y CONFIG_CORESIGHT_REMOTE_ETM=y +CONFIG_CORESIGHT_REMOTE_ETM_DEFAULT_ENABLE=0 CONFIG_CORESIGHT_EVENT=y CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y CONFIG_SECURITY=y -- GitLab From 7b6565dbcb00060e1881123a6340d1aadb9bd2dc Mon Sep 17 00:00:00 2001 From: "Isaac J. Manjarres" Date: Fri, 4 May 2018 16:02:44 -0700 Subject: [PATCH 1508/1635] lib: refcount: Cause kernel panic on refcount error detection Currently, when using the refcount API functions, a warning is printed out once to let a user of the refcount API know that an error case has been detected. Then the refcount functions will silently return, without modifying the reference count, which could be mistaken for a successful modification. This can allow for improper use of the object associated with that refcount later. Trigger a kernel panic in case of refcount error detection to prevent misuse of objects associated with refcounts. Change-Id: Ifb6a331d08a7d6c285225bc9667d2f4054db3561 Signed-off-by: Isaac J. Manjarres --- arch/Kconfig | 9 +++++++++ lib/refcount.c | 33 ++++++++++++++++++++++++++------- 2 files changed, 35 insertions(+), 7 deletions(-) diff --git a/arch/Kconfig b/arch/Kconfig index 03cff3c16b1c..6ba7bbb16c68 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -1027,4 +1027,13 @@ config REFCOUNT_FULL against various use-after-free conditions that can be used in security flaw exploits. +config PANIC_ON_REFCOUNT_ERROR + bool "Kernel panic on refcount error detection" + depends on REFCOUNT_FULL + help + If enabled, the kernel will panic when the refcount library + has detected any type of error (e.g. potential use-after-free + or potential memory-leaks) with an object associated with that + reference counter. + source "kernel/gcov/Kconfig" diff --git a/lib/refcount.c b/lib/refcount.c index 0eb48353abe3..6d0d2fc7de13 100644 --- a/lib/refcount.c +++ b/lib/refcount.c @@ -38,6 +38,18 @@ #include #include +#ifdef CONFIG_PANIC_ON_REFCOUNT_ERROR +#define REFCOUNT_WARN_ONCE(cond, msg) \ +do { \ + if (cond) { \ + printk(msg); \ + BUG(); \ + } \ +} while (0) +#else +#define REFCOUNT_WARN_ONCE(cond, msg) WARN_ONCE(cond, msg) +#endif /* CONFIG_PANIC_ON_REFCOUNT_ERROR */ + #ifdef CONFIG_REFCOUNT_FULL /** @@ -75,7 +87,8 @@ bool refcount_add_not_zero(unsigned int i, refcount_t *r) } while (!atomic_try_cmpxchg_relaxed(&r->refs, &val, new)); - WARN_ONCE(new == UINT_MAX, "refcount_t: saturated; leaking memory.\n"); + REFCOUNT_WARN_ONCE(new == UINT_MAX, + "refcount_t: saturated; leaking memory.\n"); return true; } @@ -99,7 +112,8 @@ EXPORT_SYMBOL(refcount_add_not_zero); */ void refcount_add(unsigned int i, refcount_t *r) { - WARN_ONCE(!refcount_add_not_zero(i, r), "refcount_t: addition on 0; use-after-free.\n"); + REFCOUNT_WARN_ONCE(!refcount_add_not_zero(i, r), + "refcount_t: addition on 0; use-after-free.\n"); } EXPORT_SYMBOL(refcount_add); @@ -130,7 +144,8 @@ bool refcount_inc_not_zero(refcount_t *r) } while (!atomic_try_cmpxchg_relaxed(&r->refs, &val, new)); - WARN_ONCE(new == UINT_MAX, "refcount_t: saturated; leaking memory.\n"); + REFCOUNT_WARN_ONCE(new == UINT_MAX, + "refcount_t: saturated; leaking memory.\n"); return true; } @@ -150,7 +165,8 @@ EXPORT_SYMBOL(refcount_inc_not_zero); */ void refcount_inc(refcount_t *r) { - WARN_ONCE(!refcount_inc_not_zero(r), "refcount_t: increment on 0; use-after-free.\n"); + REFCOUNT_WARN_ONCE(!refcount_inc_not_zero(r), + "refcount_t: increment on 0; use-after-free.\n"); } EXPORT_SYMBOL(refcount_inc); @@ -184,7 +200,8 @@ bool refcount_sub_and_test(unsigned int i, refcount_t *r) new = val - i; if (new > val) { - WARN_ONCE(new > val, "refcount_t: underflow; use-after-free.\n"); + REFCOUNT_WARN_ONCE(new > val, + "refcount_t: underflow; use-after-free.\n"); return false; } @@ -225,7 +242,8 @@ EXPORT_SYMBOL(refcount_dec_and_test); */ void refcount_dec(refcount_t *r) { - WARN_ONCE(refcount_dec_and_test(r), "refcount_t: decrement hit 0; leaking memory.\n"); + REFCOUNT_WARN_ONCE(refcount_dec_and_test(r), + "refcount_t: decrement hit 0; leaking memory.\n"); } EXPORT_SYMBOL(refcount_dec); #endif /* CONFIG_REFCOUNT_FULL */ @@ -278,7 +296,8 @@ bool refcount_dec_not_one(refcount_t *r) new = val - 1; if (new > val) { - WARN_ONCE(new > val, "refcount_t: underflow; use-after-free.\n"); + REFCOUNT_WARN_ONCE(new > val, + "refcount_t: underflow; use-after-free.\n"); return true; } -- GitLab From 45f4a9a5b3204c0ea55ca1a5393ab3ec67b07685 Mon Sep 17 00:00:00 2001 From: "Isaac J. Manjarres" Date: Wed, 9 May 2018 17:57:42 -0700 Subject: [PATCH 1509/1635] defconfig: Enable full reference count validation Enable full reference count validation to prevent use-after-free cases and memory leak cases that may appear because of reference count overflows. Change-Id: Iedf2f84a081fa4129f68388cb27ba4c0381a587c Signed-off-by: Isaac J. Manjarres --- arch/arm64/configs/sm8150-perf_defconfig | 1 + arch/arm64/configs/sm8150_defconfig | 2 ++ 2 files changed, 3 insertions(+) diff --git a/arch/arm64/configs/sm8150-perf_defconfig b/arch/arm64/configs/sm8150-perf_defconfig index 1a34842a97b1..ca3a0f4def60 100644 --- a/arch/arm64/configs/sm8150-perf_defconfig +++ b/arch/arm64/configs/sm8150-perf_defconfig @@ -43,6 +43,7 @@ CONFIG_SLAB_FREELIST_RANDOM=y CONFIG_SLAB_FREELIST_HARDENED=y CONFIG_PROFILING=y CONFIG_CC_STACKPROTECTOR_STRONG=y +CONFIG_REFCOUNT_FULL=y CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y CONFIG_MODULE_FORCE_UNLOAD=y diff --git a/arch/arm64/configs/sm8150_defconfig b/arch/arm64/configs/sm8150_defconfig index 81aca1ba02fb..c4c66cec853b 100644 --- a/arch/arm64/configs/sm8150_defconfig +++ b/arch/arm64/configs/sm8150_defconfig @@ -43,6 +43,8 @@ CONFIG_SLAB_FREELIST_RANDOM=y CONFIG_SLAB_FREELIST_HARDENED=y CONFIG_PROFILING=y CONFIG_CC_STACKPROTECTOR_STRONG=y +CONFIG_REFCOUNT_FULL=y +CONFIG_PANIC_ON_REFCOUNT_ERROR=y CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y CONFIG_MODULE_FORCE_UNLOAD=y -- GitLab From 6b6db03a0a7ecf0eccea072640eb4f8d3b84e72f Mon Sep 17 00:00:00 2001 From: Shefali Jain Date: Thu, 10 May 2018 12:11:55 +0530 Subject: [PATCH 1510/1635] defconfig: Enable RPM clock driver for QCS405 Enable RPM clock controller driver support. Change-Id: I46bc4c31f035ff3f7075a8f2f816e251c0041fd6 Signed-off-by: Shefali Jain --- arch/arm/configs/qcs405-perf_defconfig | 3 +++ arch/arm/configs/qcs405_defconfig | 3 +++ arch/arm64/configs/qcs405-perf_defconfig | 3 +++ arch/arm64/configs/qcs405_defconfig | 3 +++ 4 files changed, 12 insertions(+) diff --git a/arch/arm/configs/qcs405-perf_defconfig b/arch/arm/configs/qcs405-perf_defconfig index 56aa4d4932b7..cd1dfe5b0910 100644 --- a/arch/arm/configs/qcs405-perf_defconfig +++ b/arch/arm/configs/qcs405-perf_defconfig @@ -318,6 +318,7 @@ CONFIG_STAGING=y CONFIG_ASHMEM=y CONFIG_ION=y CONFIG_COMMON_CLK_QCOM=y +CONFIG_QCOM_CLK_SMD_RPM=y CONFIG_MDM_GCC_QCS405=y CONFIG_HWSPINLOCK=y CONFIG_HWSPINLOCK_QCOM=y @@ -326,8 +327,10 @@ CONFIG_QCOM_APCS_IPC=y CONFIG_RPMSG_CHAR=y CONFIG_RPMSG_QCOM_GLINK_RPM=y CONFIG_RPMSG_QCOM_GLINK_SMEM=y +CONFIG_RPMSG_QCOM_SMD=y CONFIG_QCOM_QMI_HELPERS=y CONFIG_QCOM_SMEM=y +CONFIG_QCOM_SMD_RPM=y CONFIG_QCOM_SCM=y CONFIG_QCOM_SMP2P=y CONFIG_MSM_SUBSYSTEM_RESTART=y diff --git a/arch/arm/configs/qcs405_defconfig b/arch/arm/configs/qcs405_defconfig index b63e4b7f4685..2d13d80f29df 100644 --- a/arch/arm/configs/qcs405_defconfig +++ b/arch/arm/configs/qcs405_defconfig @@ -335,6 +335,7 @@ CONFIG_STAGING=y CONFIG_ASHMEM=y CONFIG_ION=y CONFIG_COMMON_CLK_QCOM=y +CONFIG_QCOM_CLK_SMD_RPM=y CONFIG_MDM_GCC_QCS405=y CONFIG_HWSPINLOCK=y CONFIG_HWSPINLOCK_QCOM=y @@ -346,8 +347,10 @@ CONFIG_QCOM_IOMMU=y CONFIG_RPMSG_CHAR=y CONFIG_RPMSG_QCOM_GLINK_RPM=y CONFIG_RPMSG_QCOM_GLINK_SMEM=y +CONFIG_RPMSG_QCOM_SMD=y CONFIG_QCOM_QMI_HELPERS=y CONFIG_QCOM_SMEM=y +CONFIG_QCOM_SMD_RPM=y CONFIG_QCOM_SCM=y CONFIG_QCOM_SMP2P=y CONFIG_MSM_SUBSYSTEM_RESTART=y diff --git a/arch/arm64/configs/qcs405-perf_defconfig b/arch/arm64/configs/qcs405-perf_defconfig index d02dfe6e937c..b6d8a368489a 100644 --- a/arch/arm64/configs/qcs405-perf_defconfig +++ b/arch/arm64/configs/qcs405-perf_defconfig @@ -316,12 +316,15 @@ CONFIG_UIO=y CONFIG_STAGING=y CONFIG_ASHMEM=y CONFIG_ION=y +CONFIG_QCOM_CLK_SMD_RPM=y CONFIG_MDM_GCC_QCS405=y CONFIG_HWSPINLOCK=y CONFIG_MAILBOX=y CONFIG_IOMMU_IO_PGTABLE_LPAE=y +CONFIG_RPMSG_QCOM_SMD=y CONFIG_QCOM_QMI_HELPERS=y CONFIG_QCOM_SMEM=y +CONFIG_QCOM_SMD_RPM=y CONFIG_QCOM_SCM=y CONFIG_MSM_SUBSYSTEM_RESTART=y CONFIG_MSM_PIL=y diff --git a/arch/arm64/configs/qcs405_defconfig b/arch/arm64/configs/qcs405_defconfig index 45668468d3bb..bcbe976ccdae 100644 --- a/arch/arm64/configs/qcs405_defconfig +++ b/arch/arm64/configs/qcs405_defconfig @@ -334,13 +334,16 @@ CONFIG_UIO=y CONFIG_STAGING=y CONFIG_ASHMEM=y CONFIG_ION=y +CONFIG_QCOM_CLK_SMD_RPM=y CONFIG_MDM_GCC_QCS405=y CONFIG_HWSPINLOCK=y CONFIG_MAILBOX=y CONFIG_IOMMU_IO_PGTABLE_LPAE=y CONFIG_QCOM_LAZY_MAPPING=y +CONFIG_RPMSG_QCOM_SMD=y CONFIG_QCOM_QMI_HELPERS=y CONFIG_QCOM_SMEM=y +CONFIG_QCOM_SMD_RPM=y CONFIG_QCOM_SCM=y CONFIG_MSM_SUBSYSTEM_RESTART=y CONFIG_MSM_PIL=y -- GitLab From 0c2ccf6aec16ba78a95c5ab3fc342f3166a2d80f Mon Sep 17 00:00:00 2001 From: Shefali Jain Date: Thu, 10 May 2018 11:14:47 +0530 Subject: [PATCH 1511/1635] ARM: dts: msm: Update the RPM clock node for QCS405 Update the RPM clock controller node to use the RPM SMD clock controller driver to register the RPM clocks. Change-Id: I6eb83f87c257820d200492381915fa88670a9386 Signed-off-by: Shefali Jain --- arch/arm64/boot/dts/qcom/qcs405.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/qcs405.dtsi b/arch/arm64/boot/dts/qcom/qcs405.dtsi index bac0002029d3..d399bb869114 100644 --- a/arch/arm64/boot/dts/qcom/qcs405.dtsi +++ b/arch/arm64/boot/dts/qcom/qcs405.dtsi @@ -211,7 +211,7 @@ }; clock_rpmcc: qcom,rpmcc { - compatible = "qcom,dummycc"; + compatible = "qcom,rpmcc-qcs405"; #clock-cells = <1>; }; -- GitLab From 3d838ac74cfa79ef08040ebe2a92703de57a2615 Mon Sep 17 00:00:00 2001 From: Liangliang Lu Date: Thu, 10 May 2018 14:43:29 +0800 Subject: [PATCH 1512/1635] ARM: dts: msm: Remove USB speed limitation on QRD8150 Remove USB speed limitation on QRD8150 since USB3 can work. Change-Id: Id65e1ea790e277a214ee8bc2f0ebe978dd1d8ce8 Signed-off-by: Liangliang Lu --- arch/arm64/boot/dts/qcom/sm8150-qrd.dtsi | 7 ------- 1 file changed, 7 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sm8150-qrd.dtsi b/arch/arm64/boot/dts/qcom/sm8150-qrd.dtsi index 06f7223c85d3..0e0850ca3023 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-qrd.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-qrd.dtsi @@ -138,13 +138,6 @@ qcom,wsa-aux-dev-prefix = "SpkrRight", "SpkrRight"; }; -/* Force USB to high speed mode before USB re-driver enabled on QRD855 */ -&usb0 { - dwc3@a600000 { - maximum-speed = "high-speed"; - }; -}; - &qupv3_se9_i2c { status = "ok"; nq@28 { -- GitLab From 7e38a57734319481a4a78681f649b17ac3e03319 Mon Sep 17 00:00:00 2001 From: Kota Priyanka Date: Wed, 2 May 2018 17:23:23 -0700 Subject: [PATCH 1513/1635] qbt1000: Remove redundant check on qseecom buffer size Add changes to remove redundant size check on qseecom buffer. Change-Id: I951ca82b81f38357edcbfd3f2e992c6b16cba517 Signed-off-by: Kota Priyanka --- drivers/soc/qcom/qbt1000.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/drivers/soc/qcom/qbt1000.c b/drivers/soc/qcom/qbt1000.c index 5323a9fe5e77..0b2a543658a7 100644 --- a/drivers/soc/qcom/qbt1000.c +++ b/drivers/soc/qcom/qbt1000.c @@ -210,11 +210,6 @@ static int send_tz_cmd(struct qbt1000_drvdata *drvdata, goto end; } - if (aligned_cmd - cmd + cmd_len > g_app_buf_size) { - rc = -ENOMEM; - goto end; - } - if (is_user_space) { rc = copy_from_user(aligned_cmd, (void __user *)cmd, cmd_len); -- GitLab From df63d96221041e8eb7c6a6efd77346a14fcec1cc Mon Sep 17 00:00:00 2001 From: Raghavendra Kakarla Date: Wed, 21 Mar 2018 20:54:38 +0530 Subject: [PATCH 1514/1635] defconfig: Enable MSM_RPM_SMD support Enable MSM_RPM_SMD driver support in qcs405. Change-Id: Ib3e23f96cf9292c2eb22eb76c2201c3c741cec4a Signed-off-by: Raghavendra Kakarla --- arch/arm64/configs/qcs405-perf_defconfig | 1 + arch/arm64/configs/qcs405_defconfig | 1 + 2 files changed, 2 insertions(+) diff --git a/arch/arm64/configs/qcs405-perf_defconfig b/arch/arm64/configs/qcs405-perf_defconfig index d02dfe6e937c..59b2034ba122 100644 --- a/arch/arm64/configs/qcs405-perf_defconfig +++ b/arch/arm64/configs/qcs405-perf_defconfig @@ -327,6 +327,7 @@ CONFIG_MSM_SUBSYSTEM_RESTART=y CONFIG_MSM_PIL=y CONFIG_MSM_BOOT_STATS=y CONFIG_MSM_CORE_HANG_DETECT=y +CONFIG_MSM_RPM_SMD=y CONFIG_PWM=y CONFIG_ANDROID=y CONFIG_ANDROID_BINDER_IPC=y diff --git a/arch/arm64/configs/qcs405_defconfig b/arch/arm64/configs/qcs405_defconfig index 45668468d3bb..969529846565 100644 --- a/arch/arm64/configs/qcs405_defconfig +++ b/arch/arm64/configs/qcs405_defconfig @@ -346,6 +346,7 @@ CONFIG_MSM_SUBSYSTEM_RESTART=y CONFIG_MSM_PIL=y CONFIG_MSM_BOOT_STATS=y CONFIG_MSM_CORE_HANG_DETECT=y +CONFIG_MSM_RPM_SMD=y CONFIG_PWM=y CONFIG_ANDROID=y CONFIG_ANDROID_BINDER_IPC=y -- GitLab From 6ea5e17f5a5444b006f70950fd5fc7bc1f2a3eb7 Mon Sep 17 00:00:00 2001 From: Jishnu Prakash Date: Mon, 7 May 2018 19:13:45 +0530 Subject: [PATCH 1515/1635] thermal: tsens: Update TSENS device ID for SM6150 Change TSENS device name to SM6150 to match updates. Change-Id: I3647110cc9a644256bb4f13be93b70258dda5214 Signed-off-by: Jishnu Prakash --- Documentation/devicetree/bindings/thermal/tsens.txt | 2 +- drivers/thermal/msm-tsens.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/thermal/tsens.txt b/Documentation/devicetree/bindings/thermal/tsens.txt index 3002e4ce6b51..dcb4bda84f2b 100644 --- a/Documentation/devicetree/bindings/thermal/tsens.txt +++ b/Documentation/devicetree/bindings/thermal/tsens.txt @@ -21,7 +21,7 @@ Required properties: should be "qcom,tsens24xx" for 2.4 TSENS controller. should be "qcom,msm8937-tsens" for 8937 TSENS driver. should be "qcom,qcs405-tsens" for QCS405 TSENS driver. - should be "qcom,sdm640-tsens" for 640 TSENS driver. + should be "qcom,sm6150-tsens" for 6150 TSENS driver. The compatible property is used to identify the respective controller to use for the corresponding SoC. diff --git a/drivers/thermal/msm-tsens.c b/drivers/thermal/msm-tsens.c index c89ccc6d03b1..dfbb3befbc99 100644 --- a/drivers/thermal/msm-tsens.c +++ b/drivers/thermal/msm-tsens.c @@ -81,7 +81,7 @@ static const struct of_device_id tsens_table[] = { { .compatible = "qcom,sdm630-tsens", .data = &data_tsens23xx, }, - { .compatible = "qcom,sdm640-tsens", + { .compatible = "qcom,sm6150-tsens", .data = &data_tsens23xx, }, { .compatible = "qcom,sdm845-tsens", -- GitLab From 7be8c3b40693ed7f69b3d7243d92885a4313b151 Mon Sep 17 00:00:00 2001 From: Ghanim Fodi Date: Thu, 10 May 2018 13:44:04 +0300 Subject: [PATCH 1516/1635] msm: gsi: add support for prefetch escape buffer only GSI 2.0 supports escape buffers only configuration for GSI prefetch. Add this capability and expose it to the client drivers Change-Id: Id2525fbd62e2b366be809d4866ef324c785a1716 Signed-off-by: Ghanim Fodi --- drivers/platform/msm/gsi/gsi.c | 4 ++++ drivers/platform/msm/gsi/gsi_reg.h | 4 +++- include/linux/msm_gsi.h | 6 ++++++ 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/drivers/platform/msm/gsi/gsi.c b/drivers/platform/msm/gsi/gsi.c index e936e3e33297..1a020b8e47bd 100644 --- a/drivers/platform/msm/gsi/gsi.c +++ b/drivers/platform/msm/gsi/gsi.c @@ -1635,6 +1635,10 @@ static void gsi_program_chan_ctx(struct gsi_chan_props *props, unsigned int ee, GSI_EE_n_GSI_CH_k_QOS_MAX_PREFETCH_BMSK) | ((props->use_db_eng << GSI_EE_n_GSI_CH_k_QOS_USE_DB_ENG_SHFT) & GSI_EE_n_GSI_CH_k_QOS_USE_DB_ENG_BMSK)); + if (gsi_ctx->per.ver >= GSI_VER_2_0) + val |= ((props->prefetch_mode << + GSI_EE_n_GSI_CH_k_QOS_USE_ESCAPE_BUF_ONLY_SHFT) + & GSI_EE_n_GSI_CH_k_QOS_USE_ESCAPE_BUF_ONLY_BMSK); gsi_writel(val, gsi_ctx->base + GSI_EE_n_GSI_CH_k_QOS_OFFS(props->ch_id, ee)); } diff --git a/drivers/platform/msm/gsi/gsi_reg.h b/drivers/platform/msm/gsi/gsi_reg.h index 3c35b02486da..2067ac922a74 100644 --- a/drivers/platform/msm/gsi/gsi_reg.h +++ b/drivers/platform/msm/gsi/gsi_reg.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -1124,6 +1124,8 @@ #define GSI_EE_n_GSI_CH_k_QOS_RMSK 0x303 #define GSI_EE_n_GSI_CH_k_QOS_MAXk 30 #define GSI_EE_n_GSI_CH_k_QOS_MAXn 3 +#define GSI_EE_n_GSI_CH_k_QOS_USE_ESCAPE_BUF_ONLY_BMSK 0x400 +#define GSI_EE_n_GSI_CH_k_QOS_USE_ESCAPE_BUF_ONLY_SHFT 0xa #define GSI_EE_n_GSI_CH_k_QOS_USE_DB_ENG_BMSK 0x200 #define GSI_EE_n_GSI_CH_k_QOS_USE_DB_ENG_SHFT 0x9 #define GSI_EE_n_GSI_CH_k_QOS_MAX_PREFETCH_BMSK 0x100 diff --git a/include/linux/msm_gsi.h b/include/linux/msm_gsi.h index 2154688a4d0c..a587beb2e978 100644 --- a/include/linux/msm_gsi.h +++ b/include/linux/msm_gsi.h @@ -219,6 +219,11 @@ enum gsi_max_prefetch { GSI_TWO_PREFETCH_SEG = 0x1 }; +enum gsi_prefetch_mode { + GSI_USE_PREFETCH_BUFS = 0x0, + GSI_ESCAPE_BUF_ONLY = 0x1 +}; + enum gsi_chan_evt { GSI_CHAN_EVT_INVALID = 0x0, GSI_CHAN_EVT_SUCCESS = 0x1, @@ -357,6 +362,7 @@ struct gsi_chan_props { enum gsi_chan_use_db_eng use_db_eng; enum gsi_max_prefetch max_prefetch; uint8_t low_weight; + enum gsi_prefetch_mode prefetch_mode; void (*xfer_cb)(struct gsi_chan_xfer_notify *notify); void (*err_cb)(struct gsi_chan_err_notify *notify); void *chan_user_data; -- GitLab From 78f7ba41dca51e150487bf3d38b072604dc3c38b Mon Sep 17 00:00:00 2001 From: Devi Sandeep Endluri V V Date: Fri, 27 Apr 2018 19:50:32 +0530 Subject: [PATCH 1517/1635] defconfig: Enable CONFIG_NETFILTER_XT_MATCH_BPF Enable bpf match support for targets with kernel 4.9 and above so that iptable command from netd (userspace module) with -m bpf doesn't fail. CRs-Fixed: 2228931 Change-Id: Ie592632768615a780dc86da8da21f8f1b65177d5 Signed-off-by: Devi Sandeep Endluri V V --- arch/arm64/configs/sm8150-perf_defconfig | 1 + arch/arm64/configs/sm8150_defconfig | 1 + 2 files changed, 2 insertions(+) diff --git a/arch/arm64/configs/sm8150-perf_defconfig b/arch/arm64/configs/sm8150-perf_defconfig index 1a34842a97b1..e8a9e454ce77 100644 --- a/arch/arm64/configs/sm8150-perf_defconfig +++ b/arch/arm64/configs/sm8150-perf_defconfig @@ -141,6 +141,7 @@ CONFIG_NETFILTER_XT_TARGET_TPROXY=y CONFIG_NETFILTER_XT_TARGET_TRACE=y CONFIG_NETFILTER_XT_TARGET_SECMARK=y CONFIG_NETFILTER_XT_TARGET_TCPMSS=y +CONFIG_NETFILTER_XT_MATCH_BPF=y CONFIG_NETFILTER_XT_MATCH_COMMENT=y CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y CONFIG_NETFILTER_XT_MATCH_CONNMARK=y diff --git a/arch/arm64/configs/sm8150_defconfig b/arch/arm64/configs/sm8150_defconfig index 81aca1ba02fb..8c5a553c78a5 100644 --- a/arch/arm64/configs/sm8150_defconfig +++ b/arch/arm64/configs/sm8150_defconfig @@ -146,6 +146,7 @@ CONFIG_NETFILTER_XT_TARGET_TPROXY=y CONFIG_NETFILTER_XT_TARGET_TRACE=y CONFIG_NETFILTER_XT_TARGET_SECMARK=y CONFIG_NETFILTER_XT_TARGET_TCPMSS=y +CONFIG_NETFILTER_XT_MATCH_BPF=y CONFIG_NETFILTER_XT_MATCH_COMMENT=y CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y CONFIG_NETFILTER_XT_MATCH_CONNMARK=y -- GitLab From a183532b58d41115a6a935443d066baf01866ef9 Mon Sep 17 00:00:00 2001 From: Sandeep Panda Date: Thu, 15 Mar 2018 22:48:46 +0530 Subject: [PATCH 1518/1635] drm/msm/dsi-staging: disable dsi irq before core clock off Disable dsi irq before dsi core clock off, since dsi irq disable sequence involves register access and this may lead to NOC errors. Change-Id: If0444c6da1c37ad0159080ff96e6b9bc892f98a9 Signed-off-by: Sandeep Panda --- drivers/gpu/drm/msm/dsi-staging/dsi_display.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_display.c b/drivers/gpu/drm/msm/dsi-staging/dsi_display.c index e8b5d66e4db7..31f94b08c42d 100644 --- a/drivers/gpu/drm/msm/dsi-staging/dsi_display.c +++ b/drivers/gpu/drm/msm/dsi-staging/dsi_display.c @@ -2654,6 +2654,8 @@ int dsi_pre_clkoff_cb(void *priv, pr_err("%s: failed to disable ulps. rc=%d\n", __func__, rc); } + /* dsi will not be able to serve irqs from here on */ + dsi_display_ctrl_irq_update(display, false); } return rc; @@ -2761,9 +2763,6 @@ int dsi_post_clkoff_cb(void *priv, if ((clk_type & DSI_CORE_CLK) && (curr_state == DSI_CLK_OFF)) { - /* dsi will not be able to serve irqs from here */ - dsi_display_ctrl_irq_update(display, false); - rc = dsi_display_phy_power_off(display); if (rc) pr_err("[%s] failed to power off PHY, rc=%d\n", -- GitLab From f85da32bf0e023316831bb72747dc0c00fe67758 Mon Sep 17 00:00:00 2001 From: Jack Pham Date: Thu, 10 May 2018 12:10:53 -0700 Subject: [PATCH 1519/1635] usb: dwc3: gadget: remove unbalanced pm_runtime_put() Previously the pm_runtime_get() call from __dwc3_gadget_ep_queue() and corresponding pm_runtime_put() in dwc3_gadget_giveback() were removed due to our modifications on how runtime PM is handled. However commit 59d3a952e4f3 ("usb: dwc3: gadget: never call ->complete() from ->ep_queue()") was brought in via stable merge and added back the pm_runtime_put() to the new function dwc3_del_and_unmap_request() causing the PM usage_count to grow more and more negative each time peripheral mode was started and stopped. Remove this pm_runtime_put() as the negative count causes host mode to not work due to xhci-plat child thinking that its parent is not in RPM_ACTIVE state. Change-Id: I5c055e26aa35d337cec7db441fe50b4ee05a7eb4 Signed-off-by: Jack Pham --- drivers/usb/dwc3/gadget.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 6a9a40584d85..925194ace52c 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -293,9 +293,6 @@ void dwc3_gadget_del_and_unmap_request(struct dwc3_ep *dep, req->trb = NULL; trace_dwc3_gadget_giveback(req); - - if (dep->number > 1) - pm_runtime_put(dwc->dev); } /** -- GitLab From acb694fb78b6ed85e0c1a1d3c861b6235e5d2f46 Mon Sep 17 00:00:00 2001 From: Veera Sundaram Sankaran Date: Wed, 9 May 2018 11:07:34 -0700 Subject: [PATCH 1520/1635] drm/msm/sde: disable inner/outer shareable setting in VBIF Disable the inner & outer shareable setting in MDP VBIF according to the memory team requirement. Change-Id: I1380d463b51bdd8aa57291e436babcad71c24558 Signed-off-by: Veera Sundaram Sankaran --- drivers/gpu/drm/msm/sde/sde_hw_vbif.c | 42 +++++++++++++++++++++++---- 1 file changed, 36 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/msm/sde/sde_hw_vbif.c b/drivers/gpu/drm/msm/sde/sde_hw_vbif.c index 6e6a542d4e98..837a7c4fd0cc 100644 --- a/drivers/gpu/drm/msm/sde/sde_hw_vbif.c +++ b/drivers/gpu/drm/msm/sde/sde_hw_vbif.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -33,6 +33,8 @@ #define VBIF_OUT_WR_LIM_CONF0 0x00D4 #define VBIF_OUT_AXI_AMEMTYPE_CONF0 0x0160 #define VBIF_OUT_AXI_AMEMTYPE_CONF1 0x0164 +#define VBIF_OUT_AXI_ASHARED 0x0170 +#define VBIF_OUT_AXI_AINNERSHARED 0x0174 #define VBIF_XIN_PND_ERR 0x0190 #define VBIF_XIN_SRC_ERR 0x0194 #define VBIF_XIN_CLR_ERR 0x019C @@ -73,11 +75,12 @@ static void sde_hw_set_mem_type(struct sde_hw_vbif *vbif, * Assume 4 bits per bit field, 8 fields per 32-bit register so * 16 bit fields maximum across two registers */ - if (!vbif || xin_id >= MAX_XIN_COUNT || xin_id >= 16) + if (!vbif || xin_id >= MAX_XIN_COUNT) return; c = &vbif->hw; + /* enable cacheable */ if (xin_id >= 8) { xin_id -= 8; reg_off = VBIF_OUT_AXI_AMEMTYPE_CONF1; @@ -91,6 +94,30 @@ static void sde_hw_set_mem_type(struct sde_hw_vbif *vbif, SDE_REG_WRITE(c, reg_off, reg_val); } +static void sde_hw_set_mem_type_v1(struct sde_hw_vbif *vbif, + u32 xin_id, u32 value) +{ + struct sde_hw_blk_reg_map *c; + u32 reg_val; + + if (!vbif || xin_id >= MAX_XIN_COUNT) + return; + + sde_hw_set_mem_type(vbif, xin_id, value); + + c = &vbif->hw; + + /* disable outer shareable */ + reg_val = SDE_REG_READ(c, VBIF_OUT_AXI_ASHARED); + reg_val &= ~BIT(xin_id); + SDE_REG_WRITE(c, VBIF_OUT_AXI_ASHARED, 0); + + /* disable inner shareable */ + reg_val = SDE_REG_READ(c, VBIF_OUT_AXI_AINNERSHARED); + reg_val &= ~BIT(xin_id); + SDE_REG_WRITE(c, VBIF_OUT_AXI_AINNERSHARED, 0); +} + static void sde_hw_set_limit_conf(struct sde_hw_vbif *vbif, u32 xin_id, bool rd, u32 limit) { @@ -205,8 +232,8 @@ static void sde_hw_set_write_gather_en(struct sde_hw_vbif *vbif, u32 xin_id) SDE_REG_WRITE(c, VBIF_WRITE_GATHER_EN, reg_val); } -static void _setup_vbif_ops(struct sde_hw_vbif_ops *ops, - unsigned long cap) +static void _setup_vbif_ops(const struct sde_mdss_cfg *m, + struct sde_hw_vbif_ops *ops, unsigned long cap) { ops->set_limit_conf = sde_hw_set_limit_conf; ops->get_limit_conf = sde_hw_get_limit_conf; @@ -214,7 +241,10 @@ static void _setup_vbif_ops(struct sde_hw_vbif_ops *ops, ops->get_halt_ctrl = sde_hw_get_halt_ctrl; if (test_bit(SDE_VBIF_QOS_REMAP, &cap)) ops->set_qos_remap = sde_hw_set_qos_remap; - ops->set_mem_type = sde_hw_set_mem_type; + if (IS_SM8150_TARGET(m->hwversion)) + ops->set_mem_type = sde_hw_set_mem_type_v1; + else + ops->set_mem_type = sde_hw_set_mem_type; ops->clear_errors = sde_hw_clear_errors; ops->set_write_gather_en = sde_hw_set_write_gather_en; } @@ -262,7 +292,7 @@ struct sde_hw_vbif *sde_hw_vbif_init(enum sde_vbif idx, */ c->idx = idx; c->cap = cfg; - _setup_vbif_ops(&c->ops, c->cap->features); + _setup_vbif_ops(m, &c->ops, c->cap->features); /* no need to register sub-range in sde dbg, dump entire vbif io base */ -- GitLab From 0ae4a7dd4dc4261f362bdd6e22a6eb6f2b06b6a6 Mon Sep 17 00:00:00 2001 From: Ram Chandrasekar Date: Mon, 16 Apr 2018 09:47:20 -0600 Subject: [PATCH 1521/1635] ARM: dts: msm: Add thermal mitigation config for NPU in SM8150 Add thermal configuration for monitoring NPU temperature and mitigate. The current config monitors for a 95C threshold and uses step-wise algorithm to mitigate. Change-Id: I294ed0107e20e7b3e98fada76ef10ea37e69e6d2 Signed-off-by: Ram Chandrasekar --- arch/arm64/boot/dts/qcom/sm8150-thermal.dtsi | 22 ++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sm8150-thermal.dtsi b/arch/arm64/boot/dts/qcom/sm8150-thermal.dtsi index 08421f3841f1..a58ef5406ffa 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-thermal.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-thermal.dtsi @@ -2344,4 +2344,26 @@ }; }; }; + + npu-step { + polling-delay-passive = <10>; + polling-delay = <0>; + thermal-sensors = <&tsens1 8>; + thermal-governor = "step_wise"; + trips { + npu_trip0: npu-trip0 { + temperature = <95000>; + hysteresis = <0>; + type = "passive"; + }; + }; + cooling-maps { + npu_cdev { + trip = <&npu_trip0>; + cooling-device = + <&msm_npu THERMAL_NO_LIMIT + THERMAL_NO_LIMIT>; + }; + }; + }; }; -- GitLab From 6b6c2964f075730f0e0ca490ee0d89dfead35577 Mon Sep 17 00:00:00 2001 From: Dhaval Patel Date: Wed, 21 Mar 2018 21:04:25 -0700 Subject: [PATCH 1522/1635] msm: sde: avoid dynamic kthread create for each rot session Each rotator session open request creates a thread and destroys it on close session. These threads are created to trigger rotation complete fences. Such dynamic allocation can easily be avoided by creating threads at probe time. Change-Id: I1a443ca8627b5cf2b2e770ad7ea2863c52aa7d9b Signed-off-by: Dhaval Patel --- .../msm/sde/rotator/sde_rotator_core.c | 2 +- .../msm/sde/rotator/sde_rotator_core.h | 14 +++- .../msm/sde/rotator/sde_rotator_dev.c | 73 +++++++++++++------ .../msm/sde/rotator/sde_rotator_dev.h | 16 +++- 4 files changed, 77 insertions(+), 28 deletions(-) diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_core.c b/drivers/media/platform/msm/sde/rotator/sde_rotator_core.c index 5d9b267375bd..585582deeee9 100644 --- a/drivers/media/platform/msm/sde/rotator/sde_rotator_core.c +++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_core.c @@ -3400,7 +3400,7 @@ int sde_rotator_resume(struct platform_device *dev) */ int sde_rotator_session_open(struct sde_rot_mgr *mgr, struct sde_rot_file_private **pprivate, int session_id, - struct sde_rot_queue *queue) + struct sde_rot_queue_v1 *queue) { int ret; struct sde_rot_file_private *private; diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_core.h b/drivers/media/platform/msm/sde/rotator/sde_rotator_core.h index 8421873a9297..f6fdb9072503 100644 --- a/drivers/media/platform/msm/sde/rotator/sde_rotator_core.h +++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_core.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -242,6 +242,12 @@ struct sde_rot_queue { struct sde_rot_hw_resource *hw; }; +struct sde_rot_queue_v1 { + struct kthread_worker *rot_kw; + struct task_struct *rot_thread; + struct sde_rot_timeline *timeline; + struct sde_rot_hw_resource *hw; +}; /* * struct sde_rot_entry_container - rotation request * @list: list of active requests managed by rotator manager @@ -294,7 +300,7 @@ struct sde_rot_entry { struct kthread_work commit_work; struct kthread_work done_work; struct sde_rot_queue *commitq; - struct sde_rot_queue *fenceq; + struct sde_rot_queue_v1 *fenceq; struct sde_rot_queue *doneq; struct sde_rot_entry_container *request; @@ -351,7 +357,7 @@ struct sde_rot_file_private { struct list_head req_list; struct list_head perf_list; struct sde_rot_mgr *mgr; - struct sde_rot_queue *fenceq; + struct sde_rot_queue_v1 *fenceq; }; /* @@ -586,7 +592,7 @@ void sde_rotator_core_dump(struct sde_rot_mgr *mgr); */ int sde_rotator_session_open(struct sde_rot_mgr *mgr, struct sde_rot_file_private **pprivate, int session_id, - struct sde_rot_queue *queue); + struct sde_rot_queue_v1 *queue); /* * sde_rotator_session_close - close the given rotator per file session diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.c b/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.c index 9606c5c562ab..c94e9162d97f 100644 --- a/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.c +++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -925,6 +925,7 @@ struct sde_rotator_ctx *sde_rotator_ctx_open( ctx->rotate = 0; ctx->secure = 0; ctx->abort_pending = 0; + ctx->kthread_id = -1; ctx->format_cap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; ctx->format_cap.fmt.pix.pixelformat = SDE_PIX_FMT_Y_CBCR_H2V2; ctx->format_cap.fmt.pix.width = 640; @@ -982,18 +983,22 @@ struct sde_rotator_ctx *sde_rotator_ctx_open( goto error_create_sysfs; } - snprintf(name, sizeof(name), "rot_fenceq_%d_%d", rot_dev->dev->id, - ctx->session_id); - kthread_init_worker(&ctx->work_queue.rot_kw); - ctx->work_queue.rot_thread = kthread_run(kthread_worker_fn, - &ctx->work_queue.rot_kw, name); - if (IS_ERR(ctx->work_queue.rot_thread)) { - SDEDEV_ERR(ctx->rot_dev->dev, "fail allocate kthread\n"); - ret = -EPERM; - ctx->work_queue.rot_thread = NULL; - goto error_alloc_workqueue; + for (i = 0; i < MAX_ROT_OPEN_SESSION; i++) { + if (rot_dev->kthread_free[i]) { + rot_dev->kthread_free[i] = false; + ctx->kthread_id = i; + ctx->work_queue.rot_kw = &rot_dev->rot_kw[i]; + ctx->work_queue.rot_thread = rot_dev->rot_thread[i]; + break; + } + } + + if (ctx->kthread_id < 0) { + SDEDEV_ERR(ctx->rot_dev->dev, + "fail to acquire the kthread\n"); + ret = -EINVAL; + goto error_alloc_kthread; } - SDEDEV_DBG(ctx->rot_dev->dev, "kthread name=%s\n", name); snprintf(name, sizeof(name), "%d_%d", rot_dev->dev->id, ctx->session_id); @@ -1052,9 +1057,9 @@ struct sde_rotator_ctx *sde_rotator_ctx_open( error_open_session: sde_rot_mgr_unlock(rot_dev->mgr); sde_rotator_destroy_timeline(ctx->work_queue.timeline); - kthread_flush_worker(&ctx->work_queue.rot_kw); - kthread_stop(ctx->work_queue.rot_thread); -error_alloc_workqueue: + rot_dev->kthread_free[ctx->kthread_id] = true; + ctx->kthread_id = -1; +error_alloc_kthread: sysfs_remove_group(&ctx->kobj, &sde_rotator_fs_attr_group); error_create_sysfs: kobject_put(&ctx->kobj); @@ -1129,8 +1134,10 @@ static int sde_rotator_ctx_release(struct sde_rotator_ctx *ctx, mutex_lock(&rot_dev->lock); SDEDEV_DBG(rot_dev->dev, "release context s:%d\n", session_id); sde_rotator_destroy_timeline(ctx->work_queue.timeline); - kthread_flush_worker(&ctx->work_queue.rot_kw); - kthread_stop(ctx->work_queue.rot_thread); + if (ctx->kthread_id >= 0 && ctx->work_queue.rot_kw) { + kthread_flush_worker(ctx->work_queue.rot_kw); + rot_dev->kthread_free[ctx->kthread_id] = true; + } sysfs_remove_group(&ctx->kobj, &sde_rotator_fs_attr_group); kobject_put(&ctx->kobj); if (ctx->file) { @@ -1817,7 +1824,7 @@ int sde_rotator_inline_commit(void *handle, struct sde_rotator_inline_cmd *cmd, } else { SDEROT_ERR("invalid stats timestamp\n"); } - req->retire_kw = &ctx->work_queue.rot_kw; + req->retire_kw = ctx->work_queue.rot_kw; req->retire_work = &request->retire_work; trace_rot_entry_fence( @@ -3170,7 +3177,7 @@ static int sde_rotator_process_buffers(struct sde_rotator_ctx *ctx, goto error_init_request; } - req->retire_kw = &ctx->work_queue.rot_kw; + req->retire_kw = ctx->work_queue.rot_kw; req->retire_work = &request->retire_work; ret = sde_rotator_handle_request_common( @@ -3468,7 +3475,7 @@ static int sde_rotator_job_ready(void *priv) list_del_init(&request->list); list_add_tail(&request->list, &ctx->pending_list); spin_unlock(&ctx->list_lock); - kthread_queue_work(&ctx->work_queue.rot_kw, + kthread_queue_work(ctx->work_queue.rot_kw, &request->submit_work); } } else if (request && !atomic_read(&request->req->pending_count)) { @@ -3522,7 +3529,8 @@ static int sde_rotator_probe(struct platform_device *pdev) { struct sde_rotator_device *rot_dev; struct video_device *vdev; - int ret; + int ret, i; + char name[32]; SDEDEV_DBG(&pdev->dev, "SDE v4l2 rotator probed\n"); @@ -3605,9 +3613,29 @@ static int sde_rotator_probe(struct platform_device *pdev) rot_dev->debugfs_root = sde_rotator_create_debugfs(rot_dev); + for (i = 0; i < MAX_ROT_OPEN_SESSION; i++) { + snprintf(name, sizeof(name), "rot_fenceq_%d_%d", + rot_dev->dev->id, i); + kthread_init_worker(&rot_dev->rot_kw[i]); + rot_dev->rot_thread[i] = kthread_run(kthread_worker_fn, + &rot_dev->rot_kw[i], name); + if (IS_ERR(rot_dev->rot_thread[i])) { + SDEDEV_ERR(rot_dev->dev, + "fail allocate kthread i:%d\n", i); + ret = -EPERM; + goto error_kthread_create; + } + rot_dev->kthread_free[i] = true; + } + SDEDEV_INFO(&pdev->dev, "SDE v4l2 rotator probe success\n"); return 0; +error_kthread_create: + for (i--; i >= 0; i--) + kthread_stop(rot_dev->rot_thread[i]); + sde_rotator_destroy_debugfs(rot_dev->debugfs_root); + video_unregister_device(rot_dev->vdev); error_video_register: video_device_release(vdev); error_alloc_video_device: @@ -3630,6 +3658,7 @@ static int sde_rotator_probe(struct platform_device *pdev) static int sde_rotator_remove(struct platform_device *pdev) { struct sde_rotator_device *rot_dev; + int i; rot_dev = platform_get_drvdata(pdev); if (rot_dev == NULL) { @@ -3638,6 +3667,8 @@ static int sde_rotator_remove(struct platform_device *pdev) } sde_rotator_pm_qos_remove(rot_dev->mdata); + for (i = MAX_ROT_OPEN_SESSION - 1; i >= 0; i--) + kthread_stop(rot_dev->rot_thread[i]); sde_rotator_destroy_debugfs(rot_dev->debugfs_root); video_unregister_device(rot_dev->vdev); video_device_release(rot_dev->vdev); diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.h b/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.h index 2bf439a04f51..ed3b7af0dee0 100644 --- a/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.h +++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -41,6 +41,8 @@ /* maximum number of outstanding requests per ctx session */ #define SDE_ROTATOR_REQUEST_MAX 2 +#define MAX_ROT_OPEN_SESSION 16 + struct sde_rotator_device; struct sde_rotator_ctx; @@ -137,6 +139,7 @@ struct sde_rotator_request { * @retired_list: list of retired/free request * @requests: static allocation of free requests * @rotcfg: current core rotation configuration + * @kthread_id: thread_id used for fence management */ struct sde_rotator_ctx { struct kobject kobj; @@ -161,7 +164,7 @@ struct sde_rotator_ctx { struct sde_rotator_vbinfo *vbinfo_cap; struct sde_rotator_vbinfo *vbinfo_out; wait_queue_head_t wait_queue; - struct sde_rot_queue work_queue; + struct sde_rot_queue_v1 work_queue; struct sde_rot_file_private *private; struct llcc_slice_desc *slice; u32 commit_sequence_id; @@ -171,6 +174,8 @@ struct sde_rotator_ctx { struct list_head retired_list; struct sde_rotator_request requests[SDE_ROTATOR_REQUEST_MAX]; struct sde_rotation_config rotcfg; + + int kthread_id; }; /* @@ -209,6 +214,9 @@ struct sde_rotator_statistics { * @open_timeout: maximum wait time for ctx open in msec * @open_wq: wait queue for ctx open * @excl_ctx: Pointer to exclusive ctx + * @rot_kw: rotator thread work + * @rot_thread: rotator threads + * @kthread_free: check if thread is available or not */ struct sde_rotator_device { struct mutex lock; @@ -234,6 +242,10 @@ struct sde_rotator_device { u32 open_timeout; wait_queue_head_t open_wq; struct sde_rotator_ctx *excl_ctx; + + struct kthread_worker rot_kw[MAX_ROT_OPEN_SESSION]; + struct task_struct *rot_thread[MAX_ROT_OPEN_SESSION]; + bool kthread_free[MAX_ROT_OPEN_SESSION]; }; static inline -- GitLab From 0bb7059ca8b6805800278e712fd090b6f12b50db Mon Sep 17 00:00:00 2001 From: Dhaval Patel Date: Tue, 3 Apr 2018 17:20:20 -0700 Subject: [PATCH 1523/1635] rot: add null checks before calling release API Add null checks before calling release API in sde rotator dev. Change-Id: Ia6e2f436caba3f2d0fbabad90150cd67592124d3 Signed-off-by: Dhaval Patel --- .../msm/sde/rotator/sde_rotator_dev.c | 20 ++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.c b/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.c index c94e9162d97f..7d8f5fc9caeb 100644 --- a/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.c +++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.c @@ -964,6 +964,7 @@ struct sde_rotator_ctx *sde_rotator_ctx_open( ctx, sde_rotator_queue_init); if (IS_ERR_OR_NULL(ctx->fh.m2m_ctx)) { ret = PTR_ERR(ctx->fh.m2m_ctx); + ctx->fh.m2m_ctx = NULL; goto error_m2m_init; } } @@ -1064,6 +1065,10 @@ struct sde_rotator_ctx *sde_rotator_ctx_open( error_create_sysfs: kobject_put(&ctx->kobj); error_kobj_init: + if (ctx->file) { + v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); + ctx->fh.m2m_ctx = NULL; + } error_m2m_init: if (ctx->file) { v4l2_fh_del(&ctx->fh); @@ -1101,10 +1106,12 @@ static int sde_rotator_ctx_release(struct sde_rotator_ctx *ctx, if (ctx->file) { v4l2_ctrl_handler_free(&ctx->ctrl_handler); SDEDEV_DBG(rot_dev->dev, "release streams s:%d\n", session_id); - v4l2_m2m_streamoff(file, ctx->fh.m2m_ctx, + if (ctx->fh.m2m_ctx) { + v4l2_m2m_streamoff(file, ctx->fh.m2m_ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); - v4l2_m2m_streamoff(file, ctx->fh.m2m_ctx, + v4l2_m2m_streamoff(file, ctx->fh.m2m_ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); + } } mutex_unlock(&rot_dev->lock); SDEDEV_DBG(rot_dev->dev, "release submit work s:%d\n", session_id); @@ -1141,9 +1148,12 @@ static int sde_rotator_ctx_release(struct sde_rotator_ctx *ctx, sysfs_remove_group(&ctx->kobj, &sde_rotator_fs_attr_group); kobject_put(&ctx->kobj); if (ctx->file) { - v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); - v4l2_fh_del(&ctx->fh); - v4l2_fh_exit(&ctx->fh); + if (ctx->fh.m2m_ctx) + v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); + if (ctx->fh.vdev) { + v4l2_fh_del(&ctx->fh); + v4l2_fh_exit(&ctx->fh); + } } kfree(ctx->vbinfo_out); kfree(ctx->vbinfo_cap); -- GitLab From 33087ad63f43f4c322bc7232aab0b0e05207384a Mon Sep 17 00:00:00 2001 From: Pengfei Liu Date: Wed, 9 May 2018 17:33:28 +0800 Subject: [PATCH 1524/1635] ARM: dts: msm: Update analog voltage for eeprom on sm8150 QRD platform Change analog voltage minimum threshold from 2.85 to 2.856V for eeprom device on sm8150 QRD platform. Change-Id: I9fb83ff438cdfeb8c2ebb4193969c4fdb698fdf1 Signed-off-by: Pengfei Liu --- .../boot/dts/qcom/sm8150-camera-sensor-qrd.dtsi | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sm8150-camera-sensor-qrd.dtsi b/arch/arm64/boot/dts/qcom/sm8150-camera-sensor-qrd.dtsi index 22ae92b07442..88a22ce3ed92 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-camera-sensor-qrd.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-camera-sensor-qrd.dtsi @@ -58,8 +58,8 @@ cam_vaf-supply = <&pm8009_s2>; regulator-names = "cam_vaf"; rgltr-cntrl-support; - rgltr-min-voltage = <2850000>; - rgltr-max-voltage = <2850000>; + rgltr-min-voltage = <2856000>; + rgltr-max-voltage = <2856000>; rgltr-load-current = <0>; }; @@ -157,8 +157,8 @@ regulator-names = "cam_vio", "cam_vana", "cam_vdig", "cam_clk", "cam_vaf"; rgltr-cntrl-support; - rgltr-min-voltage = <0 2850000 1200000 0 2856000>; - rgltr-max-voltage = <0 2850000 1200000 0 2856000>; + rgltr-min-voltage = <0 2856000 1200000 0 2856000>; + rgltr-max-voltage = <0 2856000 1200000 0 2856000>; rgltr-load-current = <0 80000 1200000 0 0>; gpio-no-mux = <0>; pinctrl-names = "cam_default", "cam_suspend"; @@ -196,8 +196,8 @@ regulator-names = "cam_vio", "cam_vana", "cam_vdig", "cam_clk", "cam_vaf"; rgltr-cntrl-support; - rgltr-min-voltage = <0 2850000 1200000 0 2856000>; - rgltr-max-voltage = <0 2850000 1200000 0 2856000>; + rgltr-min-voltage = <0 2856000 1200000 0 2856000>; + rgltr-max-voltage = <0 2856000 1200000 0 2856000>; rgltr-load-current = <0 80000 1200000 0 0>; gpio-no-mux = <0>; pinctrl-names = "cam_default", "cam_suspend"; -- GitLab From d87f968cad85a2a8e19378a405153c448d8ce9d7 Mon Sep 17 00:00:00 2001 From: Raghavendra Rao Ananta Date: Thu, 10 May 2018 17:22:57 -0700 Subject: [PATCH 1525/1635] perf: Fix idle notifier setup in arm64 PMU driver The registration to idle notifier is missing in the PMU driver. Registering it so that the idle events are properly handled, that is, the counter values are updated before the cpu goes into idle. Change-Id: If2a74ed8189f96fa28a05037d86e20e5b53b4a88 Signed-off-by: Raghavendra Rao Ananta --- arch/arm64/kernel/perf_event.c | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/arch/arm64/kernel/perf_event.c b/arch/arm64/kernel/perf_event.c index d73a6db9adf0..2d0e5030f1c1 100644 --- a/arch/arm64/kernel/perf_event.c +++ b/arch/arm64/kernel/perf_event.c @@ -1005,18 +1005,14 @@ static int armv8pmu_probe_pmu(struct arm_pmu *cpu_pmu) __armv8pmu_probe_pmu, &probe, 1); if (ret) - goto probe_fail; + return ret; - if (!probe.present) { - ret = -ENODEV; - goto probe_fail; - } + if (!probe.present) + return -ENODEV; - return 0; + idle_notifier_register(&pmu_idle_nb->perf_cpu_idle_nb); -probe_fail: - idle_notifier_unregister(&pmu_idle_nb->perf_cpu_idle_nb); - return ret; + return 0; } static int armv8_pmu_init(struct arm_pmu *cpu_pmu) -- GitLab From 4ab7ea4dce16ecb317ea7096179422ce17d1f082 Mon Sep 17 00:00:00 2001 From: Can Guo Date: Tue, 1 May 2018 23:59:07 -0700 Subject: [PATCH 1526/1635] scsi: ufs: add UFS fault injection to hibernate enter and exit Extend UFS fault injection capability by adding fault injection to hibernate enter and exit path. Change-Id: I6ef25a4c17a99ad2c8c5df387ee5d952f42ff55e Signed-off-by: Can Guo --- drivers/scsi/ufs/ufs-debugfs.c | 22 ++++++++++++++++++++++ drivers/scsi/ufs/ufs-debugfs.h | 4 +++- drivers/scsi/ufs/ufshcd.c | 4 ++++ 3 files changed, 29 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/ufs/ufs-debugfs.c b/drivers/scsi/ufs/ufs-debugfs.c index 44b50c04e22c..ee805a01c2f2 100644 --- a/drivers/scsi/ufs/ufs-debugfs.c +++ b/drivers/scsi/ufs/ufs-debugfs.c @@ -100,6 +100,16 @@ static const int err_inject_query_err_codes[] = { 0xFF, }; +static const int err_inject_hibern8_err_codes[] = { + -EIO, + -ETIMEDOUT, + -1, + PWR_REMOTE, + PWR_BUSY, + PWR_ERROR_CAP, + PWR_FATAL_ERROR, +}; + static struct ufsdbg_err_scenario err_scen_arr[] = { { "ERR_INJECT_INTR", @@ -126,6 +136,16 @@ static struct ufsdbg_err_scenario err_scen_arr[] = { err_inject_query_err_codes, ARRAY_SIZE(err_inject_query_err_codes), }, + { + "ERR_INJECT_HIBERN8_ENTER", + err_inject_hibern8_err_codes, + ARRAY_SIZE(err_inject_hibern8_err_codes), + }, + { + "ERR_INJECT_HIBERN8_EXIT", + err_inject_hibern8_err_codes, + ARRAY_SIZE(err_inject_hibern8_err_codes), + }, }; static bool inject_fatal_err_tr(struct ufs_hba *hba, u8 ocs_err) @@ -281,6 +301,8 @@ void ufsdbg_error_inject_dispatcher(struct ufs_hba *hba, case ERR_INJECT_UIC: case ERR_INJECT_DME_ATTR: case ERR_INJECT_QUERY: + case ERR_INJECT_HIBERN8_ENTER: + case ERR_INJECT_HIBERN8_EXIT: goto should_fail; default: dev_err(hba->dev, "%s: unsupported error scenario\n", diff --git a/drivers/scsi/ufs/ufs-debugfs.h b/drivers/scsi/ufs/ufs-debugfs.h index bad918e12c59..d8907a6827cd 100644 --- a/drivers/scsi/ufs/ufs-debugfs.h +++ b/drivers/scsi/ufs/ufs-debugfs.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2016, 2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -29,6 +29,8 @@ enum ufsdbg_err_inject_scenario { ERR_INJECT_UIC, ERR_INJECT_DME_ATTR, ERR_INJECT_QUERY, + ERR_INJECT_HIBERN8_ENTER, + ERR_INJECT_HIBERN8_EXIT, ERR_INJECT_MAX_ERR_SCENARIOS, }; diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index 8566809a47c5..f34cec37711c 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -5190,6 +5190,8 @@ static int __ufshcd_uic_hibern8_enter(struct ufs_hba *hba) trace_ufshcd_profile_hibern8(dev_name(hba->dev), "enter", ktime_to_us(ktime_sub(ktime_get(), start)), ret); + ufsdbg_error_inject_dispatcher(hba, ERR_INJECT_HIBERN8_ENTER, 0, &ret); + /* * Do full reinit if enter failed or if LINERESET was detected during * Hibern8 operation. After LINERESET, link moves to default PWM-G1 @@ -5255,6 +5257,8 @@ int ufshcd_uic_hibern8_exit(struct ufs_hba *hba) trace_ufshcd_profile_hibern8(dev_name(hba->dev), "exit", ktime_to_us(ktime_sub(ktime_get(), start)), ret); + ufsdbg_error_inject_dispatcher(hba, ERR_INJECT_HIBERN8_EXIT, 0, &ret); + /* Do full reinit if exit failed */ if (ret) { ufshcd_update_error_stats(hba, UFS_ERR_HIBERN8_EXIT); -- GitLab From 71a6be452bbecdc53952155b5d7074b5b853d8ba Mon Sep 17 00:00:00 2001 From: Guru Das Srinagesh Date: Wed, 9 May 2018 15:27:14 -0700 Subject: [PATCH 1527/1635] ARM: dts: msm: Fix interrupts definition in SMB1390 device SMB1390 has eight interrupts in total. Add the ones that were missing from the initial commit and arrange all of them in the right order to match the one-to-one mapping between each interrupt and its corresponding bit in the Interrupt Real-Time Status register. CRs-Fixed: 2239205 Change-Id: I7b960f54fc1b6318be6f0c070fe160078e2fe398 Signed-off-by: Guru Das Srinagesh --- arch/arm64/boot/dts/qcom/smb1390.dtsi | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/smb1390.dtsi b/arch/arm64/boot/dts/qcom/smb1390.dtsi index b8b8854b8c47..ef7fba85db74 100644 --- a/arch/arm64/boot/dts/qcom/smb1390.dtsi +++ b/arch/arm64/boot/dts/qcom/smb1390.dtsi @@ -44,9 +44,15 @@ <0x10 0x1 IRQ_TYPE_EDGE_RISING>, <0x10 0x2 IRQ_TYPE_EDGE_RISING>, <0x10 0x3 IRQ_TYPE_EDGE_RISING>, - <0x10 0x4 IRQ_TYPE_EDGE_RISING>; + <0x10 0x4 IRQ_TYPE_EDGE_RISING>, + <0x10 0x5 IRQ_TYPE_EDGE_RISING>, + <0x10 0x6 IRQ_TYPE_EDGE_RISING>, + <0x10 0x7 IRQ_TYPE_EDGE_RISING>; interrupt-names = "switcher-off-window", "switcher-off-fault", + "tsd-fault", + "irev-fault", + "vph-ov-hard", "vph-ov-soft", "ilim", "temp-alarm"; -- GitLab From 1ac089f634fb721d8a96345a5842d07e79f8c8db Mon Sep 17 00:00:00 2001 From: Veera Sundaram Sankaran Date: Tue, 8 May 2018 18:08:29 -0700 Subject: [PATCH 1528/1635] drm/msm/sde: avoid fill-level calculation for QoS/danger/safe LUTs Add plane feature flag to avoid calculating the fill-levels and add parsing code to get macrotile-qseed lut configs for QoS/danger/safe. Change-Id: If92f926b133466c329dcab7a29653a9a1370397f Signed-off-by: Veera Sundaram Sankaran --- .../devicetree/bindings/display/msm/sde.txt | 25 +++++++++++++--- drivers/gpu/drm/msm/sde/sde_hw_catalog.c | 29 ++++++++++++++++++- drivers/gpu/drm/msm/sde/sde_hw_catalog.h | 3 ++ drivers/gpu/drm/msm/sde/sde_plane.c | 9 ++++++ 4 files changed, 61 insertions(+), 5 deletions(-) diff --git a/Documentation/devicetree/bindings/display/msm/sde.txt b/Documentation/devicetree/bindings/display/msm/sde.txt index 84f0e124618e..923d145ff49c 100644 --- a/Documentation/devicetree/bindings/display/msm/sde.txt +++ b/Documentation/devicetree/bindings/display/msm/sde.txt @@ -352,8 +352,8 @@ Optional properties: priority for realtime clients. - qcom,sde-vbif-qos-nrt-remap: This array is used to program vbif qos remapper register priority for non-realtime clients. -- qcom,sde-danger-lut: A 4 cell property, with a format of , +- qcom,sde-danger-lut: Array of 5 cell property, with a format of + , indicating the danger luts on sspp. - qcom,sde-safe-lut-linear: Array of 2 cell property, with a format of in ascending fill level @@ -363,6 +363,11 @@ Optional properties: in ascending fill level indicating the safe luts for macrotile format on sspp. Zero fill level on the last entry identifies the default lut. +- qcom,sde-safe-lut-macrotile-qseed: Array of 2 cell property, with a format of + in ascending fill level + indicating the safe luts for macrotile format + with qseed3 on sspp. + Zero fill level on the last entry identifies the default lut. - qcom,sde-safe-lut-nrt: Array of 2 cell property, with a format of in ascending fill level indicating the safe luts for nrt (e.g wfd) on sspp. @@ -379,6 +384,11 @@ Optional properties: in ascending fill level indicating the qos luts for macrotile format on sspp. Zero fill level on the last entry identifies the default lut. +- qcom,sde-qos-lut-macrotile-qseed: Array of 3 cell property, with a format of + in ascending fill level + indicating the qos luts for macrotile format + with qseed3 enabled on sspp. + Zero fill level on the last entry identifies the default lut. - qcom,sde-qos-lut-nrt: Array of 3 cell property, with a format of in ascending fill level indicating the qos luts for nrt (e.g wfd) on sspp. @@ -617,8 +627,13 @@ Example: qcom,sde-wb-clk-ctrl = <0x2bc 16>; qcom,sde-danger-lut = <0x0000000f 0x0000ffff 0x00000000 - 0x00000000>; - qcom,sde-safe-lut = <0xfffc 0xff00 0xffff 0xffff>; + 0x00000000 0x0000ffff>; + qcom,sde-safe-lut-linear = <0 0xfff8>; + qcom,sde-safe-lut-macrotile = <0 0xf000>; + qcom,sde-safe-lut-macrotile-qseed = <0 0xf000>; + qcom,sde-safe-lut-nrt = <0 0xffff>; + qcom,sde-safe-lut-cwb = <0 0xffff>; + qcom,sde-qos-lut-linear = <4 0x00000000 0x00000357>, <5 0x00000000 0x00003357>, @@ -639,6 +654,8 @@ Example: <13 0x00002233 0x44556677>, <14 0x00012233 0x44556677>, <0 0x00112233 0x44556677>; + qcom,sde-qos-lut-macrotile-qseed = + <0 0x00112233 0x66777777>; qcom,sde-qos-lut-nrt = <0 0x00000000 0x00000000>; qcom,sde-qos-lut-cwb = diff --git a/drivers/gpu/drm/msm/sde/sde_hw_catalog.c b/drivers/gpu/drm/msm/sde/sde_hw_catalog.c index 46533248d4c4..78889591f583 100644 --- a/drivers/gpu/drm/msm/sde/sde_hw_catalog.c +++ b/drivers/gpu/drm/msm/sde/sde_hw_catalog.c @@ -201,6 +201,8 @@ enum { PERF_CDP_SETTING, PERF_CPU_MASK, PERF_CPU_DMA_LATENCY, + PERF_QOS_LUT_MACROTILE_QSEED, + PERF_SAFE_LUT_MACROTILE_QSEED, PERF_PROP_MAX, }; @@ -497,6 +499,10 @@ static struct sde_prop_type sde_perf_prop[] = { {PERF_CPU_MASK, "qcom,sde-qos-cpu-mask", false, PROP_TYPE_U32}, {PERF_CPU_DMA_LATENCY, "qcom,sde-qos-cpu-dma-latency", false, PROP_TYPE_U32}, + {PERF_QOS_LUT_MACROTILE_QSEED, "qcom,sde-qos-lut-macrotile-qseed", + false, PROP_TYPE_U32_ARRAY}, + {PERF_SAFE_LUT_MACROTILE_QSEED, "qcom,sde-safe-lut-macrotile-qseed", + false, PROP_TYPE_U32_ARRAY}, }; static struct sde_prop_type sspp_prop[] = { @@ -3133,6 +3139,18 @@ static int sde_perf_parse_dt(struct device_node *np, struct sde_mdss_cfg *cfg) if (rc) goto freeprop; + rc = _validate_dt_entry(np, + &sde_perf_prop[PERF_QOS_LUT_MACROTILE_QSEED], 1, + &prop_count[PERF_QOS_LUT_MACROTILE_QSEED], NULL); + if (rc) + goto freeprop; + + rc = _validate_dt_entry(np, + &sde_perf_prop[PERF_SAFE_LUT_MACROTILE_QSEED], 1, + &prop_count[PERF_SAFE_LUT_MACROTILE_QSEED], NULL); + if (rc) + goto freeprop; + rc = _read_dt_entry(np, sde_perf_prop, ARRAY_SIZE(sde_perf_prop), prop_count, prop_exists, prop_value); if (rc) @@ -3239,6 +3257,8 @@ static int sde_perf_parse_dt(struct device_node *np, struct sde_mdss_cfg *cfg) PERF_SAFE_LUT_NRT, [SDE_QOS_LUT_USAGE_CWB] = PERF_SAFE_LUT_CWB, + [SDE_QOS_LUT_USAGE_MACROTILE_QSEED] = + PERF_SAFE_LUT_MACROTILE_QSEED, }; const u32 entry_size = 2; int m, count; @@ -3281,6 +3301,8 @@ static int sde_perf_parse_dt(struct device_node *np, struct sde_mdss_cfg *cfg) PERF_QOS_LUT_NRT, [SDE_QOS_LUT_USAGE_CWB] = PERF_QOS_LUT_CWB, + [SDE_QOS_LUT_USAGE_MACROTILE_QSEED] = + PERF_QOS_LUT_MACROTILE_QSEED, }; const u32 entry_size = 3; int m, count; @@ -3575,10 +3597,15 @@ static int _sde_hardware_post_caps(struct sde_mdss_cfg *sde_cfg, if (!sde_cfg) return -EINVAL; - if (IS_SM8150_TARGET(hw_rev)) + if (IS_SM8150_TARGET(hw_rev)) { sde_cfg->sui_supported_blendstage = sde_cfg->max_mixer_blendstages - SDE_STAGE_0; + for (i = 0; i < sde_cfg->sspp_count; i++) + set_bit(SDE_SSPP_QOS_FL_NOCALC, + &sde_cfg->sspp[i].features); + } + for (i = 0; i < sde_cfg->sspp_count; i++) { if (sde_cfg->sspp[i].sblk) { max_horz_deci = max(max_horz_deci, diff --git a/drivers/gpu/drm/msm/sde/sde_hw_catalog.h b/drivers/gpu/drm/msm/sde/sde_hw_catalog.h index 4f40349927d6..dee834c05895 100644 --- a/drivers/gpu/drm/msm/sde/sde_hw_catalog.h +++ b/drivers/gpu/drm/msm/sde/sde_hw_catalog.h @@ -156,6 +156,7 @@ enum { * @SDE_SSPP_DGM_CSC Support of color space conversion in DGM block * @SDE_SSPP_SEC_UI_ALLOWED Allows secure-ui layers * @SDE_SSPP_BLOCK_SEC_UI Blocks secure-ui layers + * @SDE_SSPP_QOS_FL_NOCALC Avoid fill level calculation for QoS/danger/safe * @SDE_SSPP_MAX maximum value */ enum { @@ -188,6 +189,7 @@ enum { SDE_SSPP_DGM_CSC, SDE_SSPP_SEC_UI_ALLOWED, SDE_SSPP_BLOCK_SEC_UI, + SDE_SSPP_QOS_FL_NOCALC, SDE_SSPP_MAX }; @@ -450,6 +452,7 @@ enum sde_qos_lut_usage { SDE_QOS_LUT_USAGE_MACROTILE, SDE_QOS_LUT_USAGE_NRT, SDE_QOS_LUT_USAGE_CWB, + SDE_QOS_LUT_USAGE_MACROTILE_QSEED, SDE_QOS_LUT_USAGE_MAX, }; diff --git a/drivers/gpu/drm/msm/sde/sde_plane.c b/drivers/gpu/drm/msm/sde/sde_plane.c index c4ba4c44490d..5f8cb4c125c1 100644 --- a/drivers/gpu/drm/msm/sde/sde_plane.c +++ b/drivers/gpu/drm/msm/sde/sde_plane.c @@ -287,6 +287,9 @@ static inline int _sde_plane_calc_fill_level(struct drm_plane *plane, } psde = to_sde_plane(plane); + if (psde->features & BIT(SDE_SSPP_QOS_FL_NOCALC)) + return 0; + pstate = to_sde_plane_state(plane->state); rstate = &pstate->rot; fixed_buff_size = psde->pipe_sblk->pixel_ram_size; @@ -405,6 +408,8 @@ static void _sde_plane_set_qos_lut(struct drm_plane *plane, if (fmt && SDE_FORMAT_IS_LINEAR(fmt)) lut_usage = SDE_QOS_LUT_USAGE_LINEAR; + else if (psde->features & BIT(SDE_SSPP_SCALER_QSEED3)) + lut_usage = SDE_QOS_LUT_USAGE_MACROTILE_QSEED; else lut_usage = SDE_QOS_LUT_USAGE_MACROTILE; } @@ -469,6 +474,10 @@ static void _sde_plane_set_danger_lut(struct drm_plane *plane, danger_lut = psde->catalog->perf.danger_lut_tbl [SDE_QOS_LUT_USAGE_LINEAR]; lut_usage = SDE_QOS_LUT_USAGE_LINEAR; + } else if (psde->features & BIT(SDE_SSPP_SCALER_QSEED3)) { + danger_lut = psde->catalog->perf.danger_lut_tbl + [SDE_QOS_LUT_USAGE_MACROTILE_QSEED]; + lut_usage = SDE_QOS_LUT_USAGE_MACROTILE_QSEED; } else { danger_lut = psde->catalog->perf.danger_lut_tbl [SDE_QOS_LUT_USAGE_MACROTILE]; -- GitLab From 4a8d7386c98977633be91b845da557ec2a2d80a8 Mon Sep 17 00:00:00 2001 From: Veera Sundaram Sankaran Date: Tue, 8 May 2018 18:11:44 -0700 Subject: [PATCH 1529/1635] ARM: dts: msm: update QoS/danger/safe LUT settings for sm8150 target Update the LUT settings for real-time and non-real-time usecases on sm8150 target based on the new recommendation. Change-Id: Ic8e8eb9d80aa66f6ce271f0ef4569589796e19cc Signed-off-by: Veera Sundaram Sankaran --- arch/arm64/boot/dts/qcom/sm8150-sde.dtsi | 56 +++++++----------------- 1 file changed, 17 insertions(+), 39 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sm8150-sde.dtsi b/arch/arm64/boot/dts/qcom/sm8150-sde.dtsi index 76367e588dae..df0861107ee0 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-sde.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-sde.dtsi @@ -166,44 +166,22 @@ qcom,sde-vbif-qos-rt-remap = <3 3 4 4 5 5 6 6>; qcom,sde-vbif-qos-nrt-remap = <3 3 3 3 3 3 3 3>; - qcom,sde-danger-lut = <0x0000000f 0x0000ffff 0x00000000 - 0x00000000>; - qcom,sde-safe-lut-linear = - <4 0xfff8>, - <0 0xfff0>; - qcom,sde-safe-lut-macrotile = - <10 0xfe00>, - <11 0xfc00>, - <12 0xf800>, - <0 0xf000>; - qcom,sde-safe-lut-nrt = - <0 0xffff>; - qcom,sde-safe-lut-cwb = - <0 0xffff>; - qcom,sde-qos-lut-linear = - <4 0x00000000 0x00000357>, - <5 0x00000000 0x00003357>, - <6 0x00000000 0x00023357>, - <7 0x00000000 0x00223357>, - <8 0x00000000 0x02223357>, - <9 0x00000000 0x22223357>, - <10 0x00000002 0x22223357>, - <11 0x00000022 0x22223357>, - <12 0x00000222 0x22223357>, - <13 0x00002222 0x22223357>, - <14 0x00012222 0x22223357>, - <0 0x00112222 0x22223357>; - qcom,sde-qos-lut-macrotile = - <10 0x00000003 0x44556677>, - <11 0x00000033 0x44556677>, - <12 0x00000233 0x44556677>, - <13 0x00002233 0x44556677>, - <14 0x00012233 0x44556677>, - <0 0x00112233 0x44556677>; - qcom,sde-qos-lut-nrt = - <0 0x00000000 0x00000000>; - qcom,sde-qos-lut-cwb = - <0 0x75300000 0x00000000>; + /* macrotile & macrotile-qseed has the same configs */ + qcom,sde-danger-lut = <0x0000000f 0x0000ffff + 0x00000000 0x00000000 0x0000ffff>; + + qcom,sde-safe-lut-linear = <0 0xfff8>; + qcom,sde-safe-lut-macrotile = <0 0xf000>; + /* same as safe-lut-macrotile */ + qcom,sde-safe-lut-macrotile-qseed = <0 0xf000>; + qcom,sde-safe-lut-nrt = <0 0xffff>; + qcom,sde-safe-lut-cwb = <0 0xffff>; + + qcom,sde-qos-lut-linear = <0 0x00112222 0x22223357>; + qcom,sde-qos-lut-macrotile = <0 0x00112233 0x44556677>; + qcom,sde-qos-lut-macrotile-qseed = <0 0x00112233 0x66777777>; + qcom,sde-qos-lut-nrt = <0 0x00000000 0x00000000>; + qcom,sde-qos-lut-cwb = <0 0x75300000 0x00000000>; qcom,sde-cdp-setting = <1 1>, <1 0>; @@ -441,7 +419,7 @@ qcom,mdss-inline-rot-qos-lut = <0x44556677 0x00112233 0x44556677 0x00112233>; qcom,mdss-inline-rot-danger-lut = <0x0055aaff 0x0000ffff>; - qcom,mdss-inline-rot-safe-lut = <0x0000f000 0x0000ff00>; + qcom,mdss-inline-rot-safe-lut = <0x0000f000 0x0000f000>; qcom,mdss-default-ot-rd-limit = <32>; qcom,mdss-default-ot-wr-limit = <32>; -- GitLab From d6fc16c722bcbbdf54a6607eb18ee470f71f1daa Mon Sep 17 00:00:00 2001 From: Veera Sundaram Sankaran Date: Wed, 9 May 2018 18:40:02 -0700 Subject: [PATCH 1530/1635] ARM: dts: msm: update max-bw & per-pipe-max-bw for sm8150 target Update the bandwidth settings for SDE based on the new recommendation for sm8150 target. Change-Id: I0a02e09e15b05555aa733765eb3505206982be27 Signed-off-by: Veera Sundaram Sankaran --- arch/arm64/boot/dts/qcom/sm8150-sde.dtsi | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sm8150-sde.dtsi b/arch/arm64/boot/dts/qcom/sm8150-sde.dtsi index df0861107ee0..77f613398f54 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-sde.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-sde.dtsi @@ -123,6 +123,11 @@ qcom,sde-mixer-blend-op-off = <0x20 0x38 0x50 0x68 0x80 0x98 0xb0 0xc8 0xe0 0xf8 0x110>; + qcom,sde-max-per-pipe-bw-kbps = <4500000 4500000 + 4500000 4500000 + 4500000 4500000 + 4500000 4500000>; + /* offsets are relative to "mdp_phys + qcom,sde-off */ qcom,sde-sspp-clk-ctrl = <0x2ac 0>, <0x2b4 0>, <0x2bc 0>, <0x2c4 0>, @@ -147,8 +152,8 @@ qcom,sde-has-dest-scaler; qcom,sde-max-dest-scaler-input-linewidth = <2048>; qcom,sde-max-dest-scaler-output-linewidth = <2560>; - qcom,sde-max-bw-low-kbps = <9600000>; - qcom,sde-max-bw-high-kbps = <9600000>; + qcom,sde-max-bw-low-kbps = <12800000>; + qcom,sde-max-bw-high-kbps = <12800000>; qcom,sde-min-core-ib-kbps = <2400000>; qcom,sde-min-llcc-ib-kbps = <800000>; qcom,sde-min-dram-ib-kbps = <800000>; -- GitLab From 677372448c7fd7743f3a08ff5192e360c7ae292a Mon Sep 17 00:00:00 2001 From: Ray Zhang Date: Tue, 17 Apr 2018 10:46:31 +0800 Subject: [PATCH 1531/1635] msm: clk: qcom: power on PLL when reading PLL registers On sm8150 platform, reading register of DSI PLL would fail if PLL is not powered up, so enable DSI PLL power before reading operation. CRs-Fixed: 2225631 Change-Id: I2d589ee39b95234b06c8ad6556725f94deea2c10 Signed-off-by: Ray Zhang Signed-off-by: Yujun Zhang --- drivers/clk/qcom/mdss/mdss-dsi-pll-7nm.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/drivers/clk/qcom/mdss/mdss-dsi-pll-7nm.c b/drivers/clk/qcom/mdss/mdss-dsi-pll-7nm.c index 5be31f562ed4..0e7d35acee51 100644 --- a/drivers/clk/qcom/mdss/mdss-dsi-pll-7nm.c +++ b/drivers/clk/qcom/mdss/mdss-dsi-pll-7nm.c @@ -254,6 +254,7 @@ static inline int pll_reg_read(void *context, unsigned int reg, unsigned int *val) { int rc = 0; + u32 data; struct mdss_pll_resources *rsc = context; rc = mdss_pll_resource_enable(rsc, true); @@ -262,7 +263,19 @@ static inline int pll_reg_read(void *context, unsigned int reg, return rc; } + /* + * DSI PHY/PLL should be both powered on when reading PLL + * registers. Since PHY power has been enabled in DSI PHY + * driver, only PLL power is needed to enable here. + */ + data = MDSS_PLL_REG_R(rsc->phy_base, PHY_CMN_CTRL_0); + MDSS_PLL_REG_W(rsc->phy_base, PHY_CMN_CTRL_0, data | BIT(5)); + ndelay(250); + *val = MDSS_PLL_REG_R(rsc->pll_base, reg); + + MDSS_PLL_REG_W(rsc->phy_base, PHY_CMN_CTRL_0, data); + (void)mdss_pll_resource_enable(rsc, false); return rc; -- GitLab From 87e223454680673351c8fc2c86d00da36aac6e9b Mon Sep 17 00:00:00 2001 From: David Collins Date: Thu, 20 Apr 2017 16:34:46 -0700 Subject: [PATCH 1532/1635] spmi: spmi-pmic-arb-debug: add clock management support Add support to enable and disable the clock used by the SPMI PMIC arbiter debug bus. This is needed to avoid unclocked accesses. Change-Id: If9eee1317a88c143452d8b46b89aff89d1e956b7 Signed-off-by: David Collins --- .../spmi/qcom,spmi-pmic-arb-debug.txt | 15 +++++++++++ drivers/spmi/spmi-pmic-arb-debug.c | 27 +++++++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/Documentation/devicetree/bindings/spmi/qcom,spmi-pmic-arb-debug.txt b/Documentation/devicetree/bindings/spmi/qcom,spmi-pmic-arb-debug.txt index ceac719878e7..2131c33237f0 100644 --- a/Documentation/devicetree/bindings/spmi/qcom,spmi-pmic-arb-debug.txt +++ b/Documentation/devicetree/bindings/spmi/qcom,spmi-pmic-arb-debug.txt @@ -35,6 +35,19 @@ Supported Properties: the corresponding addresses are specified in the reg property. +- clocks + Usage: optional + Value type: + Definition: Clock tuple consisting of a phandle to a clock controller + device and the clock ID number for the SPMI debug controller + clock. + +- clock-names + Usage: required if clocks property is specified + Value type: + Definition: Defines the name of the clock defined in the "clocks" + property. This must be "core_clk". + - #address-cells Usage: required Value type: @@ -57,6 +70,8 @@ qcom,spmi-debug@6b22000 { compatible = "qcom,spmi-pmic-arb-debug"; reg = <0x6b22000 0x60>, <0x7820A8 4>; reg-names = "core", "fuse"; + clocks = <&clock_aop QDSS_CLK>; + clock-names = "core_clk"; qcom,fuse-disable-bit = <12>; #address-cells = <2>; #size-cells = <0>; diff --git a/drivers/spmi/spmi-pmic-arb-debug.c b/drivers/spmi/spmi-pmic-arb-debug.c index c5a31a9d84eb..2c90bef1224f 100644 --- a/drivers/spmi/spmi-pmic-arb-debug.c +++ b/drivers/spmi/spmi-pmic-arb-debug.c @@ -11,6 +11,7 @@ * GNU General Public License for more details. */ +#include #include #include #include @@ -69,6 +70,7 @@ enum pmic_arb_cmd_op_code { struct spmi_pmic_arb_debug { void __iomem *addr; raw_spinlock_t lock; + struct clk *clock; }; static inline void pmic_arb_debug_write(struct spmi_pmic_arb_debug *pa, @@ -181,6 +183,12 @@ static int pmic_arb_debug_read_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid, else return -EINVAL; + rc = clk_prepare_enable(pa->clock); + if (rc) { + pr_err("%s: failed to enable core clock, rc=%d\n", + __func__, rc); + return rc; + } raw_spin_lock_irqsave(&pa->lock, flags); rc = pmic_arb_debug_issue_command(ctrl, opc, sid, addr, len); @@ -192,6 +200,7 @@ static int pmic_arb_debug_read_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid, buf[i] = pmic_arb_debug_read(pa, PMIC_ARB_DEBUG_RDATA(i)); done: raw_spin_unlock_irqrestore(&pa->lock, flags); + clk_disable_unprepare(pa->clock); return rc; } @@ -221,6 +230,12 @@ static int pmic_arb_debug_write_cmd(struct spmi_controller *ctrl, u8 opc, else return -EINVAL; + rc = clk_prepare_enable(pa->clock); + if (rc) { + pr_err("%s: failed to enable core clock, rc=%d\n", + __func__, rc); + return rc; + } raw_spin_lock_irqsave(&pa->lock, flags); /* Write data to FIFO */ @@ -230,6 +245,7 @@ static int pmic_arb_debug_write_cmd(struct spmi_controller *ctrl, u8 opc, rc = pmic_arb_debug_issue_command(ctrl, opc, sid, addr, len); raw_spin_unlock_irqrestore(&pa->lock, flags); + clk_disable_unprepare(pa->clock); return rc; } @@ -293,6 +309,17 @@ static int spmi_pmic_arb_debug_probe(struct platform_device *pdev) goto err_put_ctrl; } + if (of_find_property(pdev->dev.of_node, "clock-names", NULL)) { + pa->clock = devm_clk_get(&pdev->dev, "core_clk"); + if (IS_ERR(pa->clock)) { + rc = PTR_ERR(pa->clock); + if (rc != -EPROBE_DEFER) + dev_err(&pdev->dev, "unable to request core clock, rc=%d\n", + rc); + goto err_put_ctrl; + } + } + platform_set_drvdata(pdev, ctrl); raw_spin_lock_init(&pa->lock); -- GitLab From 3a2fd6fb8de5b462c4a3f05fd2c6599e2ed6228f Mon Sep 17 00:00:00 2001 From: Vinayak Menon Date: Mon, 13 Jul 2015 13:24:55 +0530 Subject: [PATCH 1533/1635] mm: vmstat: add pageoutclean vmstat events currently count pgpgout, but that includes only the writebacks, and not the reclaim of clean pages. Add an event to count clean page evictions. This is helpful to evaluate page thrashing cases. Change-Id: Icfb797877a544a58c289074bdc290dfbc1384514 Signed-off-by: Vinayak Menon Signed-off-by: Charan Teja Reddy --- include/linux/vm_event_item.h | 2 +- mm/filemap.c | 6 ++++-- mm/vmstat.c | 1 + 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/include/linux/vm_event_item.h b/include/linux/vm_event_item.h index 5c7f010676a7..d3a8dbee8038 100644 --- a/include/linux/vm_event_item.h +++ b/include/linux/vm_event_item.h @@ -22,7 +22,7 @@ #define FOR_ALL_ZONES(xx) DMA_ZONE(xx) DMA32_ZONE(xx) xx##_NORMAL, HIGHMEM_ZONE(xx) xx##_MOVABLE -enum vm_event_item { PGPGIN, PGPGOUT, PSWPIN, PSWPOUT, +enum vm_event_item { PGPGIN, PGPGOUT, PGPGOUTCLEAN, PSWPIN, PSWPOUT, FOR_ALL_ZONES(PGALLOC), FOR_ALL_ZONES(ALLOCSTALL), FOR_ALL_ZONES(PGSCAN_SKIP), diff --git a/mm/filemap.c b/mm/filemap.c index 51aef4e992ea..f7ccba83429b 100644 --- a/mm/filemap.c +++ b/mm/filemap.c @@ -194,10 +194,12 @@ void __delete_from_page_cache(struct page *page, void *shadow) * invalidate any existing cleancache entries. We can't leave * stale data around in the cleancache once our page is gone */ - if (PageUptodate(page) && PageMappedToDisk(page)) + if (PageUptodate(page) && PageMappedToDisk(page)) { + count_vm_event(PGPGOUTCLEAN); cleancache_put_page(page); - else + } else { cleancache_invalidate_page(mapping, page); + } VM_BUG_ON_PAGE(PageTail(page), page); VM_BUG_ON_PAGE(page_mapped(page), page); diff --git a/mm/vmstat.c b/mm/vmstat.c index f23151305209..e75cfb1b883e 100644 --- a/mm/vmstat.c +++ b/mm/vmstat.c @@ -1099,6 +1099,7 @@ const char * const vmstat_text[] = { /* enum vm_event_item counters */ "pgpgin", "pgpgout", + "pgpgoutclean", "pswpin", "pswpout", -- GitLab From 19fb7af150d19bb76824496b794e80121fde0fc0 Mon Sep 17 00:00:00 2001 From: Kiran Gunda Date: Fri, 11 May 2018 11:52:34 +0530 Subject: [PATCH 1534/1635] ARM: dts: msm: Rename the PMIC DT files and DT nodes Rename the PMIC device tree files and nodes as below. "pm640" =====> pm6150 "pm640l" =====> pm6150l Change-Id: I8e57f24abbebf8ae9fe56369a7d2d53042c44c77 Signed-off-by: Kiran Gunda --- .../leds/backlight/qcom-spmi-wled.txt | 2 +- .../boot/dts/qcom/{pm640.dtsi => pm6150.dtsi} | 24 +-- .../dts/qcom/{pm640l.dtsi => pm6150l.dtsi} | 66 +++---- arch/arm64/boot/dts/qcom/sm6150-rumi.dtsi | 8 +- .../boot/dts/qcom/sm6150-stub-regulator.dtsi | 178 +++++++++--------- arch/arm64/boot/dts/qcom/sm6150.dtsi | 4 +- drivers/video/backlight/qcom-spmi-wled.c | 2 +- 7 files changed, 142 insertions(+), 142 deletions(-) rename arch/arm64/boot/dts/qcom/{pm640.dtsi => pm6150.dtsi} (86%) rename arch/arm64/boot/dts/qcom/{pm640l.dtsi => pm6150l.dtsi} (83%) diff --git a/Documentation/devicetree/bindings/leds/backlight/qcom-spmi-wled.txt b/Documentation/devicetree/bindings/leds/backlight/qcom-spmi-wled.txt index a877264aa6c5..22921230900b 100644 --- a/Documentation/devicetree/bindings/leds/backlight/qcom-spmi-wled.txt +++ b/Documentation/devicetree/bindings/leds/backlight/qcom-spmi-wled.txt @@ -10,7 +10,7 @@ platforms. The PMIC is connected to the host processor via SPMI bus. Definition: should be one of the below. "qcom,pmi8998-spmi-wled", "qcom,pm855l-spmi-wled", - "qcom,pm640l-spmi-wled" + "qcom,pm6150l-spmi-wled" - reg Usage: required diff --git a/arch/arm64/boot/dts/qcom/pm640.dtsi b/arch/arm64/boot/dts/qcom/pm6150.dtsi similarity index 86% rename from arch/arm64/boot/dts/qcom/pm640.dtsi rename to arch/arm64/boot/dts/qcom/pm6150.dtsi index bd28008c9a6e..ff70579dd561 100644 --- a/arch/arm64/boot/dts/qcom/pm640.dtsi +++ b/arch/arm64/boot/dts/qcom/pm6150.dtsi @@ -17,13 +17,13 @@ #include &spmi_bus { - qcom,pm640@0 { + qcom,pm6150@0 { compatible = "qcom,spmi-pmic"; reg = <0x0 SPMI_USID>; #address-cells = <1>; #size-cells = <1>; - pm640_revid: qcom,revid@100 { + pm6150_revid: qcom,revid@100 { compatible = "qcom,qpnp-revid"; reg = <0x100 0x100>; }; @@ -52,12 +52,12 @@ }; }; - pm640_misc: qcom,misc@900 { + pm6150_misc: qcom,misc@900 { compatible = "qcom,qpnp-misc"; reg = <0x900 0x100>; }; - pm640_tz: qcom,temp-alarm@2400 { + pm6150_tz: qcom,temp-alarm@2400 { compatible = "qcom,spmi-temp-alarm"; reg = <0x2400 0x100>; interrupts = <0x0 0x24 0x0 IRQ_TYPE_EDGE_RISING>; @@ -65,17 +65,17 @@ qcom,temperature-threshold-set = <1>; }; - pm640_clkdiv: clock-controller@5b00 { + pm6150_clkdiv: clock-controller@5b00 { compatible = "qcom,spmi-clkdiv"; reg = <0x5b00 0x100>; #clock-cells = <1>; qcom,num-clkdivs = <1>; - clock-output-names = "pm640_div_clk1"; + clock-output-names = "pm6150_div_clk1"; clocks = <&clock_rpmh RPMH_CXO_CLK>; clock-names = "xo"; }; - pm640_gpios: pinctrl@c000 { + pm6150_gpios: pinctrl@c000 { compatible = "qcom,spmi-gpio"; reg = <0xc000 0xa00>; interrupts = <0x0 0xc0 0 IRQ_TYPE_NONE>, @@ -84,22 +84,22 @@ <0x0 0xc3 0 IRQ_TYPE_NONE>, <0x0 0xc6 0 IRQ_TYPE_NONE>, <0x0 0xc7 0 IRQ_TYPE_NONE>; - interrupt-names = "pm640_gpio1", "pm640_gpio2", - "pm640_gpio3", "pm640_gpio4", - "pm640_gpio7", "pm640_gpio8"; + interrupt-names = "pm6150_gpio1", "pm6150_gpio2", + "pm6150_gpio3", "pm6150_gpio4", + "pm6150_gpio7", "pm6150_gpio8"; gpio-controller; #gpio-cells = <2>; qcom,gpios-disallowed = <5 6 9 10>; }; }; - qcom,pm640@1 { + qcom,pm6150@1 { compatible ="qcom,spmi-pmic"; reg = <0x1 SPMI_USID>; #address-cells = <1>; #size-cells = <1>; - pm640_vib: qcom,vibrator@5300 { + pm6150_vib: qcom,vibrator@5300 { compatible = "qcom,qpnp-vibrator-ldo"; reg = <0x5300 0x100>; qcom,vib-ldo-volt-uv = <3000000>; diff --git a/arch/arm64/boot/dts/qcom/pm640l.dtsi b/arch/arm64/boot/dts/qcom/pm6150l.dtsi similarity index 83% rename from arch/arm64/boot/dts/qcom/pm640l.dtsi rename to arch/arm64/boot/dts/qcom/pm6150l.dtsi index 13ff649480bb..1bfc77bd3a0d 100644 --- a/arch/arm64/boot/dts/qcom/pm640l.dtsi +++ b/arch/arm64/boot/dts/qcom/pm6150l.dtsi @@ -15,13 +15,13 @@ #include &spmi_bus { - qcom,pm640l@4 { + qcom,pm6150l@4 { compatible = "qcom,spmi-pmic"; reg = <0x4 SPMI_USID>; #address-cells = <1>; #size-cells = <1>; - pm640l_revid: qcom,revid@100 { + pm6150l_revid: qcom,revid@100 { compatible = "qcom,qpnp-revid"; reg = <0x100 0x100>; }; @@ -31,7 +31,7 @@ reg = <0x800 0x100>; }; - pm640l_tz: qcom,temp-alarm@2400 { + pm6150l_tz: qcom,temp-alarm@2400 { compatible = "qcom,spmi-temp-alarm"; reg = <0x2400 0x100>; interrupts = <0x4 0x24 0x0 IRQ_TYPE_EDGE_RISING>; @@ -39,17 +39,17 @@ qcom,temperature-threshold-set = <1>; }; - pm640l_clkdiv: clock-controller@5b00 { + pm6150l_clkdiv: clock-controller@5b00 { compatible = "qcom,spmi-clkdiv"; reg = <0x5b00 0x100>; #clock-cells = <1>; qcom,num-clkdivs = <1>; - clock-output-names = "pm640l_div_clk1"; + clock-output-names = "pm6150l_div_clk1"; clocks = <&clock_rpmh RPMH_CXO_CLK>; clock-names = "xo"; }; - pm640l_gpios: pinctrl@c000 { + pm6150l_gpios: pinctrl@c000 { compatible = "qcom,spmi-gpio"; reg = <0xc000 0xc00>; interrupts = <0x4 0xc0 0 IRQ_TYPE_NONE>, @@ -63,32 +63,32 @@ <0x4 0xc9 0 IRQ_TYPE_NONE>, <0x4 0xca 0 IRQ_TYPE_NONE>, <0x4 0xcb 0 IRQ_TYPE_NONE>; - interrupt-names = "pm640l_gpio1", "pm640l_gpio2", - "pm640l_gpio3", "pm640l_gpio4", - "pm640l_gpio5", "pm640l_gpio6", - "pm640l_gpio8", "pm640l_gpio9", - "pm640l_gpio10", "pm640l_gpio11", - "pm640l_gpio12"; + interrupt-names = "pm6150l_gpio1", "pm6150l_gpio2", + "pm6150l_gpio3", "pm6150l_gpio4", + "pm6150l_gpio5", "pm6150l_gpio6", + "pm6150l_gpio8", "pm6150l_gpio9", + "pm6150l_gpio10", "pm6150l_gpio11", + "pm6150l_gpio12"; gpio-controller; #gpio-cells = <2>; qcom,gpios-disallowed = <7>; }; }; - qcom,pm640l@5 { + qcom,pm6150l@5 { compatible ="qcom,spmi-pmic"; reg = <0x5 SPMI_USID>; #address-cells = <1>; #size-cells = <1>; - pm640l_lcdb: qcom,lcdb@ec00 { + pm6150l_lcdb: qcom,lcdb@ec00 { compatible = "qcom,qpnp-lcdb-regulator"; #address-cells = <1>; #size-cells = <1>; reg = <0xec00 0x100>; interrupts = <0x5 0xec 0x1 IRQ_TYPE_EDGE_RISING>; interrupt-names = "sc-irq"; - qcom,pmic-revid = <&pm640l_revid>; + qcom,pmic-revid = <&pm6150l_revid>; status = "disabled"; lcdb_ldo_vreg: ldo { @@ -124,9 +124,9 @@ qcom,thermal-derate-en; qcom,thermal-derate-current = <200 500 1000>; qcom,isc-delay = <192>; - qcom,pmic-revid = <&pm640l_revid>; + qcom,pmic-revid = <&pm6150l_revid>; - pm640l_flash0: qcom,flash_0 { + pm6150l_flash0: qcom,flash_0 { label = "flash"; qcom,led-name = "led:flash_0"; qcom,max-current = <1500>; @@ -139,7 +139,7 @@ qcom,hdrm-vol-hi-lo-win-mv = <100>; }; - pm640l_flash1: qcom,flash_1 { + pm6150l_flash1: qcom,flash_1 { label = "flash"; qcom,led-name = "led:flash_1"; qcom,max-current = <1500>; @@ -152,7 +152,7 @@ qcom,hdrm-vol-hi-lo-win-mv = <100>; }; - pm640l_flash2: qcom,flash_2 { + pm6150l_flash2: qcom,flash_2 { label = "flash"; qcom,led-name = "led:flash_2"; qcom,max-current = <750>; @@ -166,7 +166,7 @@ status = "disabled"; }; - pm640l_torch0: qcom,torch_0 { + pm6150l_torch0: qcom,torch_0 { label = "torch"; qcom,led-name = "led:torch_0"; qcom,max-current = <500>; @@ -178,7 +178,7 @@ qcom,hdrm-vol-hi-lo-win-mv = <100>; }; - pm640l_torch1: qcom,torch_1 { + pm6150l_torch1: qcom,torch_1 { label = "torch"; qcom,led-name = "led:torch_1"; qcom,max-current = <500>; @@ -190,7 +190,7 @@ qcom,hdrm-vol-hi-lo-win-mv = <100>; }; - pm640l_torch2: qcom,torch_2 { + pm6150l_torch2: qcom,torch_2 { label = "torch"; qcom,led-name = "led:torch_2"; qcom,max-current = <500>; @@ -203,21 +203,21 @@ status = "disabled"; }; - pm640l_switch0: qcom,led_switch_0 { + pm6150l_switch0: qcom,led_switch_0 { label = "switch"; qcom,led-name = "led:switch_0"; qcom,led-mask = <1>; qcom,default-led-trigger = "switch0_trigger"; }; - pm640l_switch1: qcom,led_switch_1 { + pm6150l_switch1: qcom,led_switch_1 { label = "switch"; qcom,led-name = "led:switch_1"; qcom,led-mask = <2>; qcom,default-led-trigger = "switch1_trigger"; }; - pm640l_switch2: qcom,led_switch_2 { + pm6150l_switch2: qcom,led_switch_2 { label = "switch"; qcom,led-name = "led:switch_2"; qcom,led-mask = <3>; @@ -225,41 +225,41 @@ }; }; - pm640l_wled: qcom,wled@d800 { - compatible = "qcom,pm640l-spmi-wled"; + pm6150l_wled: qcom,wled@d800 { + compatible = "qcom,pm6150l-spmi-wled"; reg = <0xd800 0x100>, <0xd900 0x100>; reg-names = "wled-ctrl-base", "wled-sink-base"; label = "backlight"; interrupts = <0x5 0xd8 0x1 IRQ_TYPE_EDGE_RISING>; interrupt-names = "ovp-irq"; - qcom,pmic-revid = <&pm640l_revid>; + qcom,pmic-revid = <&pm6150l_revid>; qcom,auto-calibration; status = "disabled"; }; - pm640l_lpg: qcom,pwms@b100 { + pm6150l_lpg: qcom,pwms@b100 { compatible = "qcom,pwm-lpg"; reg = <0xb100 0x300>; reg-names = "lpg-base"; #pwm-cells = <2>; }; - pm640l_rgb_led: qcom,leds@d000 { + pm6150l_rgb_led: qcom,leds@d000 { compatible = "qcom,tri-led"; reg = <0xd000 0x100>; red { label = "red"; - pwms = <&pm640l_lpg 0 1000000>; + pwms = <&pm6150l_lpg 0 1000000>; led-sources = <0>; }; green { label = "green"; - pwms = <&pm640l_lpg 1 1000000>; + pwms = <&pm6150l_lpg 1 1000000>; led-sources = <1>; }; blue { label = "blue"; - pwms = <&pm640l_lpg 2 1000000>; + pwms = <&pm6150l_lpg 2 1000000>; led-sources = <2>; }; }; diff --git a/arch/arm64/boot/dts/qcom/sm6150-rumi.dtsi b/arch/arm64/boot/dts/qcom/sm6150-rumi.dtsi index 14190fc61f64..a7e3ae508387 100644 --- a/arch/arm64/boot/dts/qcom/sm6150-rumi.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6150-rumi.dtsi @@ -29,11 +29,11 @@ }; &sdhc_1 { - vdd-supply = <&pm640l_l11>; + vdd-supply = <&pm6150l_l11>; qcom,vdd-voltage-level = <2960000 2960000>; qcom,vdd-current-level = <200 570000>; - vdd-io-supply = <&pm640_l12>; + vdd-io-supply = <&pm6150_l12>; qcom,vdd-io-always-on; qcom,vdd-io-lpm-sup; qcom,vdd-io-voltage-level = <1800000 1800000>; @@ -52,11 +52,11 @@ }; &sdhc_2 { - vdd-supply = <&pm640l_l9>; + vdd-supply = <&pm6150l_l9>; qcom,vdd-voltage-level = <2960000 2960000>; qcom,vdd-current-level = <200 800000>; - vdd-io-supply = <&pm640l_l6>; + vdd-io-supply = <&pm6150l_l6>; qcom,vdd-io-voltage-level = <1800000 2950000>; qcom,vdd-io-current-level = <200 22000>; diff --git a/arch/arm64/boot/dts/qcom/sm6150-stub-regulator.dtsi b/arch/arm64/boot/dts/qcom/sm6150-stub-regulator.dtsi index ad9c499b245d..cc5cf2746b83 100644 --- a/arch/arm64/boot/dts/qcom/sm6150-stub-regulator.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6150-stub-regulator.dtsi @@ -15,342 +15,342 @@ /* Stub regulators */ / { - /* pm640 S1 - VDD_CX supply */ - pm640_s1_level: regulator-pm640-s1 { + /* pm6150 S1 - VDD_CX supply */ + pm6150_s1_level: regulator-pm6150-s1 { compatible = "qcom,stub-regulator"; - regulator-name = "pm640_s1_level"; + regulator-name = "pm6150_s1_level"; qcom,hpm-min-load = <100000>; regulator-min-microvolt = ; regulator-max-microvolt = ; }; - pm640_s1_level_ao: regulator-pm640-s1-level-ao { + pm6150_s1_level_ao: regulator-pm6150-s1-level-ao { compatible = "qcom,stub-regulator"; - regulator-name = "pm640_s1_level_ao"; + regulator-name = "pm6150_s1_level_ao"; qcom,hpm-min-load = <100000>; regulator-min-microvolt = ; regulator-max-microvolt = ; }; - /* pm640 S3 - VDD_MX supply */ - pm640_s3_level: regulator-pm640-s3 { + /* pm6150 S3 - VDD_MX supply */ + pm6150_s3_level: regulator-pm6150-s3 { compatible = "qcom,stub-regulator"; - regulator-name = "pm640_s3_level"; + regulator-name = "pm6150_s3_level"; qcom,hpm-min-load = <100000>; regulator-min-microvolt = ; regulator-max-microvolt = ; }; - pm640_s3_level_ao: regulator-pm640-s3-level-ao { + pm6150_s3_level_ao: regulator-pm6150-s3-level-ao { compatible = "qcom,stub-regulator"; - regulator-name = "pm640_s3_level_ao"; + regulator-name = "pm6150_s3_level_ao"; qcom,hpm-min-load = <100000>; regulator-min-microvolt = ; regulator-max-microvolt = ; }; - pm640l_s1: regulator-pm640l-s1 { + pm6150l_s1: regulator-pm6150l-s1 { compatible = "qcom,stub-regulator"; - regulator-name = "pm640l_s1"; + regulator-name = "pm6150l_s1"; qcom,hpm-min-load = <100000>; regulator-min-microvolt = <1128000>; regulator-max-microvolt = <1128000>; }; - pm640l_s2: regulator-pm640l-s2 { + pm6150l_s2: regulator-pm6150l-s2 { compatible = "qcom,stub-regulator"; - regulator-name = "pm640l_s2"; + regulator-name = "pm6150l_s2"; qcom,hpm-min-load = <100000>; regulator-min-microvolt = <600000>; regulator-max-microvolt = <600000>; }; - /* pm640l S7 - VDD_MSS supply */ - pm640l_s7_level: regulator-pm640l-s7 { + /* pm6150l S7 - VDD_MSS supply */ + pm6150l_s7_level: regulator-pm6150l-s7 { compatible = "qcom,stub-regulator"; - regulator-name = "pm640l_s7_level"; + regulator-name = "pm6150l_s7_level"; qcom,hpm-min-load = <100000>; regulator-min-microvolt = ; regulator-max-microvolt = ; }; - pm640l_s7_level_ao: regulator-pm640l-s7-level-ao { + pm6150l_s7_level_ao: regulator-pm6150l-s7-level-ao { compatible = "qcom,stub-regulator"; - regulator-name = "pm640l_s7_level_ao"; + regulator-name = "pm6150l_s7_level_ao"; qcom,hpm-min-load = <100000>; regulator-min-microvolt = ; regulator-max-microvolt = ; }; - pm640l_s8: regulator-pm640l-s8 { + pm6150l_s8: regulator-pm6150l-s8 { compatible = "qcom,stub-regulator"; - regulator-name = "pm640l_s8"; + regulator-name = "pm6150l_s8"; qcom,hpm-min-load = <100000>; regulator-min-microvolt = <1352000>; regulator-max-microvolt = <1352000>; }; - pm640_l1: regulator-pm640-l1 { + pm6150_l1: regulator-pm6150-l1 { compatible = "qcom,stub-regulator"; - regulator-name = "pm640_l1"; + regulator-name = "pm6150_l1"; qcom,hpm-min-load = <10000>; regulator-min-microvolt = <1200000>; regulator-max-microvolt = <1200000>; }; - pm640_l2: regulator-pm640-l2 { + pm6150_l2: regulator-pm6150-l2 { compatible = "qcom,stub-regulator"; - regulator-name = "pm640_l2"; + regulator-name = "pm6150_l2"; qcom,hpm-min-load = <10000>; regulator-min-microvolt = <1000000>; regulator-max-microvolt = <1000000>; }; - pm640_l3: regulator-pm640-l3 { + pm6150_l3: regulator-pm6150-l3 { compatible = "qcom,stub-regulator"; - regulator-name = "pm640_l3"; + regulator-name = "pm6150_l3"; qcom,hpm-min-load = <10000>; regulator-min-microvolt = <1000000>; regulator-max-microvolt = <1000000>; }; - pm640_l4: regulator-pm640-l4 { + pm6150_l4: regulator-pm6150-l4 { compatible = "qcom,stub-regulator"; - regulator-name = "pm640_l4"; + regulator-name = "pm6150_l4"; qcom,hpm-min-load = <10000>; regulator-min-microvolt = <900000>; regulator-max-microvolt = <928000>; }; - pm640_l5: regulator-pm640-l5 { + pm6150_l5: regulator-pm6150-l5 { compatible = "qcom,stub-regulator"; - regulator-name = "pm640_l5"; + regulator-name = "pm6150_l5"; qcom,hpm-min-load = <10000>; regulator-min-microvolt = <2700000>; regulator-max-microvolt = <2704000>; }; - pm640_l6: regulator-pm640-l6 { + pm6150_l6: regulator-pm6150-l6 { compatible = "qcom,stub-regulator"; - regulator-name = "pm640_l6"; + regulator-name = "pm6150_l6"; qcom,hpm-min-load = <10000>; regulator-min-microvolt = <600000>; regulator-max-microvolt = <600000>; }; - /* pm640 L7 - LPI_MX supply */ - pm640_l7_level: regulator-pm640-l7 { + /* pm6150 L7 - LPI_MX supply */ + pm6150_l7_level: regulator-pm6150-l7 { compatible = "qcom,stub-regulator"; - regulator-name = "pm640_l7_level"; + regulator-name = "pm6150_l7_level"; qcom,hpm-min-load = <10000>; regulator-min-microvolt = ; regulator-max-microvolt = ; }; - pm640_l7_level_ao: regulator-pm640-l7-level-ao { + pm6150_l7_level_ao: regulator-pm6150-l7-level-ao { compatible = "qcom,stub-regulator"; - regulator-name = "pm640_l7_level_ao"; + regulator-name = "pm6150_l7_level_ao"; qcom,hpm-min-load = <10000>; regulator-min-microvolt = ; regulator-max-microvolt = ; }; - /* pm640 L8 - LPI_CX supply */ - pm640_l8_level: regulator-pm640-l8 { + /* pm6150 L8 - LPI_CX supply */ + pm6150_l8_level: regulator-pm6150-l8 { compatible = "qcom,stub-regulator"; - regulator-name = "pm640_l8_level"; + regulator-name = "pm6150_l8_level"; qcom,hpm-min-load = <10000>; regulator-min-microvolt = ; regulator-max-microvolt = ; }; - pm640_l8_level_ao: regulator-pm640-l8_level_ao { + pm6150_l8_level_ao: regulator-pm6150-l8_level_ao { compatible = "qcom,stub-regulator"; - regulator-name = "pm640_l8_level_ao"; + regulator-name = "pm6150_l8_level_ao"; qcom,hpm-min-load = <10000>; regulator-min-microvolt = ; regulator-max-microvolt = ; }; - pm640_l9: regulator-pm640-l9 { + pm6150_l9: regulator-pm6150-l9 { compatible = "qcom,stub-regulator"; - regulator-name = "pm640_l9"; + regulator-name = "pm6150_l9"; qcom,hpm-min-load = <10000>; regulator-min-microvolt = <728000>; regulator-max-microvolt = <728000>; }; - pm640_l10: regulator-pm640-l10 { + pm6150_l10: regulator-pm6150-l10 { compatible = "qcom,stub-regulator"; - regulator-name = "pm640_l10"; + regulator-name = "pm6150_l10"; qcom,hpm-min-load = <10000>; regulator-min-microvolt = <1800000>; regulator-max-microvolt = <1800000>; }; - pm640_l11: regulator-pm640-l11 { + pm6150_l11: regulator-pm6150-l11 { compatible = "qcom,stub-regulator"; - regulator-name = "pm640_l11"; + regulator-name = "pm6150_l11"; qcom,hpm-min-load = <10000>; regulator-min-microvolt = <1800000>; regulator-max-microvolt = <1800000>; }; - pm640_l12: regulator-pm640-l12 { + pm6150_l12: regulator-pm6150-l12 { compatible = "qcom,stub-regulator"; - regulator-name = "pm640_l12"; + regulator-name = "pm6150_l12"; qcom,hpm-min-load = <10000>; regulator-min-microvolt = <1800000>; regulator-max-microvolt = <1800000>; }; - pm640_l13: regulator-pm640-l13 { + pm6150_l13: regulator-pm6150-l13 { compatible = "qcom,stub-regulator"; - regulator-name = "pm640_l13"; + regulator-name = "pm6150_l13"; qcom,hpm-min-load = <10000>; regulator-min-microvolt = <1800000>; regulator-max-microvolt = <1800000>; }; - pm640_l14: regulator-pm640-l14 { + pm6150_l14: regulator-pm6150-l14 { compatible = "qcom,stub-regulator"; - regulator-name = "pm640_l14"; + regulator-name = "pm6150_l14"; qcom,hpm-min-load = <10000>; regulator-min-microvolt = <1800000>; regulator-max-microvolt = <1800000>; }; - pm640_l15: regulator-pm640-l15 { + pm6150_l15: regulator-pm6150-l15 { compatible = "qcom,stub-regulator"; - regulator-name = "pm640_l15"; + regulator-name = "pm6150_l15"; qcom,hpm-min-load = <10000>; regulator-min-microvolt = <1800000>; regulator-max-microvolt = <1800000>; }; - pm640_l16: regulator-pm640-l16 { + pm6150_l16: regulator-pm6150-l16 { compatible = "qcom,stub-regulator"; - regulator-name = "pm640_l16"; + regulator-name = "pm6150_l16"; qcom,hpm-min-load = <10000>; regulator-min-microvolt = <2700000>; regulator-max-microvolt = <2704000>; }; - pm640_l17: regulator-pm640-l17 { + pm6150_l17: regulator-pm6150-l17 { compatible = "qcom,stub-regulator"; - regulator-name = "pm640_l17"; + regulator-name = "pm6150_l17"; qcom,hpm-min-load = <10000>; regulator-min-microvolt = <3100000>; regulator-max-microvolt = <3128000>; }; - pm640_l18: regulator-pm640-l18 { + pm6150_l18: regulator-pm6150-l18 { compatible = "qcom,stub-regulator"; - regulator-name = "pm640_l18"; + regulator-name = "pm6150_l18"; qcom,hpm-min-load = <10000>; regulator-min-microvolt = <3000000>; regulator-max-microvolt = <3300000>; }; - pm640_l19: regulator-pm640-l19 { + pm6150_l19: regulator-pm6150-l19 { compatible = "qcom,stub-regulator"; - regulator-name = "pm640_l19"; + regulator-name = "pm6150_l19"; qcom,hpm-min-load = <10000>; regulator-min-microvolt = <2848000>; regulator-max-microvolt = <2848000>; }; - pm640l_l1: regulator-pm640l-l1 { + pm6150l_l1: regulator-pm6150l-l1 { compatible = "qcom,stub-regulator"; - regulator-name = "pm640l_l1"; + regulator-name = "pm6150l_l1"; qcom,hpm-min-load = <10000>; regulator-min-microvolt = <1800000>; regulator-max-microvolt = <1800000>; }; - pm640l_l2: regulator-pm640l-l2 { + pm6150l_l2: regulator-pm6150l-l2 { compatible = "qcom,stub-regulator"; - regulator-name = "pm640l_l2"; + regulator-name = "pm6150l_l2"; qcom,hpm-min-load = <10000>; regulator-min-microvolt = <1300000>; regulator-max-microvolt = <1304000>; }; - pm640l_l3: regulator-pm640l-l3 { + pm6150l_l3: regulator-pm6150l-l3 { compatible = "qcom,stub-regulator"; - regulator-name = "pm640l_l3"; + regulator-name = "pm6150l_l3"; qcom,hpm-min-load = <10000>; regulator-min-microvolt = <1200000>; regulator-max-microvolt = <1250000>; }; - pm640l_l4: regulator-pm640l-l4 { + pm6150l_l4: regulator-pm6150l-l4 { compatible = "qcom,stub-regulator"; - regulator-name = "pm640l_l4"; + regulator-name = "pm6150l_l4"; qcom,hpm-min-load = <10000>; regulator-min-microvolt = <1800000>; regulator-max-microvolt = <2950000>; }; - pm640l_l5: regulator-pm640l-l5 { + pm6150l_l5: regulator-pm6150l-l5 { compatible = "qcom,stub-regulator"; - regulator-name = "pm640l_l5"; + regulator-name = "pm6150l_l5"; qcom,hpm-min-load = <10000>; regulator-min-microvolt = <1800000>; regulator-max-microvolt = <2950000>; }; - pm640l_l6: regulator-pm640l-l6 { + pm6150l_l6: regulator-pm6150l-l6 { compatible = "qcom,stub-regulator"; - regulator-name = "pm640l_l6"; + regulator-name = "pm6150l_l6"; qcom,hpm-min-load = <5000>; regulator-min-microvolt = <1800000>; regulator-max-microvolt = <2950000>; }; - pm640l_l7: regulator-pm640l-l7 { + pm6150l_l7: regulator-pm6150l-l7 { compatible = "qcom,stub-regulator"; - regulator-name = "pm640l_l7"; + regulator-name = "pm6150l_l7"; qcom,hpm-min-load = <10000>; regulator-min-microvolt = <3008000>; regulator-max-microvolt = <3008000>; }; - pm640l_l8: regulator-pm640l-l8 { + pm6150l_l8: regulator-pm6150l-l8 { compatible = "qcom,stub-regulator"; - regulator-name = "pm640l_l8"; + regulator-name = "pm6150l_l8"; qcom,hpm-min-load = <10000>; regulator-min-microvolt = <1800000>; regulator-max-microvolt = <1800000>; }; - pm640l_l9: regulator-pm640l-l9 { + pm6150l_l9: regulator-pm6150l-l9 { compatible = "qcom,stub-regulator"; - regulator-name = "pm640l_l9"; + regulator-name = "pm6150l_l9"; qcom,hpm-min-load = <10000>; regulator-min-microvolt = <2960000>; regulator-max-microvolt = <2960000>; }; - pm640l_l10: regulator-pm640l-l10 { + pm6150l_l10: regulator-pm6150l-l10 { compatible = "qcom,stub-regulator"; - regulator-name = "pm640l_l10"; + regulator-name = "pm6150l_l10"; qcom,hpm-min-load = <10000>; regulator-min-microvolt = <3304000>; regulator-max-microvolt = <3304000>; }; - pm640l_l11: regulator-pm640l-l11 { + pm6150l_l11: regulator-pm6150l-l11 { compatible = "qcom,stub-regulator"; - regulator-name = "pm640l_l11"; + regulator-name = "pm6150l_l11"; qcom,hpm-min-load = <10000>; regulator-min-microvolt = <2960000>; regulator-max-microvolt = <2960000>; }; - pm640l_bob: regulator-pm640l-bob { + pm6150l_bob: regulator-pm6150l-bob { compatible = "qcom,stub-regulator"; - regulator-name = "pm640l_bob"; + regulator-name = "pm6150l_bob"; regulator-min-microvolt = <3300000>; regulator-max-microvolt = <3300000>; }; diff --git a/arch/arm64/boot/dts/qcom/sm6150.dtsi b/arch/arm64/boot/dts/qcom/sm6150.dtsi index 6ceba108843e..8026fdb729b8 100644 --- a/arch/arm64/boot/dts/qcom/sm6150.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6150.dtsi @@ -1341,8 +1341,8 @@ }; }; -#include "pm640.dtsi" -#include "pm640l.dtsi" +#include "pm6150.dtsi" +#include "pm6150l.dtsi" #include "sm6150-pinctrl.dtsi" #include "sm6150-stub-regulator.dtsi" #include "sm6150-pm.dtsi" diff --git a/drivers/video/backlight/qcom-spmi-wled.c b/drivers/video/backlight/qcom-spmi-wled.c index 2ceb797c02c8..08e0da8743a6 100644 --- a/drivers/video/backlight/qcom-spmi-wled.c +++ b/drivers/video/backlight/qcom-spmi-wled.c @@ -1514,7 +1514,7 @@ static int wled_probe(struct platform_device *pdev) static const struct of_device_id wled_match_table[] = { { .compatible = "qcom,pmi8998-spmi-wled", .data = &version_table[0] }, { .compatible = "qcom,pm855l-spmi-wled", .data = &version_table[2] }, - { .compatible = "qcom,pm640l-spmi-wled", .data = &version_table[2] }, + { .compatible = "qcom,pm6150l-spmi-wled", .data = &version_table[2] }, { }, }; -- GitLab From 6093c334a7959831a17dfba6d08504a8e127880d Mon Sep 17 00:00:00 2001 From: Vinayak Menon Date: Sat, 17 Jan 2015 21:51:48 +0530 Subject: [PATCH 1535/1635] mm: compaction: fix the page state calculation in too_many_isolated Commit "mm: vmscan: fix the page state calculation in too_many_isolated" fixed an issue where a number of tasks were blocked in reclaim path for seconds, because of vmstat_diff not being synced in time. A similar problem can happen in isolate_migratepages_block, where similar calculation is performed. This patch fixes that. Change-Id: Ie74f108ef770da688017b515fe37faea6f384589 Signed-off-by: Vinayak Menon Signed-off-by: Charan Teja Reddy --- mm/compaction.c | 42 +++++++++++++++++++++++++++++++++++++----- 1 file changed, 37 insertions(+), 5 deletions(-) diff --git a/mm/compaction.c b/mm/compaction.c index 85395dc6eb13..b95be8976399 100644 --- a/mm/compaction.c +++ b/mm/compaction.c @@ -631,20 +631,52 @@ isolate_freepages_range(struct compact_control *cc, } /* Similar to reclaim, but different enough that they don't share logic */ -static bool too_many_isolated(struct zone *zone) +static bool __too_many_isolated(struct zone *zone, int safe) { unsigned long active, inactive, isolated; - inactive = node_page_state(zone->zone_pgdat, NR_INACTIVE_FILE) + + if (safe) { + inactive = node_page_state_snapshot(zone->zone_pgdat, + NR_INACTIVE_FILE) + + node_page_state_snapshot(zone->zone_pgdat, + NR_INACTIVE_ANON); + active = node_page_state_snapshot(zone->zone_pgdat, + NR_ACTIVE_FILE) + + node_page_state_snapshot(zone->zone_pgdat, + NR_ACTIVE_ANON); + isolated = node_page_state_snapshot(zone->zone_pgdat, + NR_ISOLATED_FILE) + + node_page_state_snapshot(zone->zone_pgdat, + NR_ISOLATED_ANON); + } else { + inactive = node_page_state(zone->zone_pgdat, NR_INACTIVE_FILE) + node_page_state(zone->zone_pgdat, NR_INACTIVE_ANON); - active = node_page_state(zone->zone_pgdat, NR_ACTIVE_FILE) + + active = node_page_state(zone->zone_pgdat, NR_ACTIVE_FILE) + node_page_state(zone->zone_pgdat, NR_ACTIVE_ANON); - isolated = node_page_state(zone->zone_pgdat, NR_ISOLATED_FILE) + + isolated = node_page_state(zone->zone_pgdat, NR_ISOLATED_FILE) + node_page_state(zone->zone_pgdat, NR_ISOLATED_ANON); + } return isolated > (inactive + active) / 2; } +/* Similar to reclaim, but different enough that they don't share logic */ +static bool too_many_isolated(struct compact_control *cc) +{ + /* + * __too_many_isolated(safe=0) is fast but inaccurate, because it + * doesn't account for the vm_stat_diff[] counters. So if it looks + * like too_many_isolated() is about to return true, fall back to the + * slower, more accurate zone_page_state_snapshot(). + */ + if (unlikely(__too_many_isolated(cc->zone, 0))) { + if (cc->mode != MIGRATE_ASYNC) + return __too_many_isolated(cc->zone, 1); + } + + return false; +} + /** * isolate_migratepages_block() - isolate all migrate-able pages within * a single pageblock @@ -682,7 +714,7 @@ isolate_migratepages_block(struct compact_control *cc, unsigned long low_pfn, * list by either parallel reclaimers or compaction. If there are, * delay for some time until fewer pages are isolated */ - while (unlikely(too_many_isolated(zone))) { + while (unlikely(too_many_isolated(cc))) { /* async migration should just abort */ if (cc->mode == MIGRATE_ASYNC) return 0; -- GitLab From d41bb92c0c61b0d3ecc446437127f777f0544133 Mon Sep 17 00:00:00 2001 From: Harry Yang Date: Fri, 11 May 2018 00:39:16 -0700 Subject: [PATCH 1536/1635] power: smb1390: remove unnecessary votables Votable pl_disable is used to make sure in SW level only one secondary charger active at one time if multiple are present. However, this is the way HW works. Another votable hvdcp_hw_inov_dis_votable is also useless in SM1850 because SW INOV is always the choice. Drop both votables. Change-Id: I8ba9bc7a897c3245ac556a4a474113b247faaf27 Signed-off-by: Harry Yang --- drivers/power/supply/qcom/smb1390-charger.c | 23 --------------------- 1 file changed, 23 deletions(-) diff --git a/drivers/power/supply/qcom/smb1390-charger.c b/drivers/power/supply/qcom/smb1390-charger.c index 950acf33e4c4..a181b386ea70 100644 --- a/drivers/power/supply/qcom/smb1390-charger.c +++ b/drivers/power/supply/qcom/smb1390-charger.c @@ -106,9 +106,7 @@ struct smb1390 { /* votables */ struct votable *disable_votable; struct votable *ilim_votable; - struct votable *pl_disable_votable; struct votable *fcc_votable; - struct votable *hvdcp_hw_inov_dis_votable; /* power supplies */ struct power_supply *usb_psy; @@ -179,23 +177,6 @@ static bool is_psy_voter_available(struct smb1390 *chip) } } - if (!chip->pl_disable_votable) { - chip->pl_disable_votable = find_votable("PL_DISABLE"); - if (!chip->pl_disable_votable) { - pr_debug("Couldn't find PL_DISABLE votable\n"); - return false; - } - } - - if (!chip->hvdcp_hw_inov_dis_votable) { - chip->hvdcp_hw_inov_dis_votable = - find_votable("HVDCP_HW_INOV_DIS"); - if (!chip->hvdcp_hw_inov_dis_votable) { - pr_debug("Couldn't find HVDCP_HW_INOV_DIS votable\n"); - return false; - } - } - return true; } @@ -347,11 +328,7 @@ static int smb1390_disable_vote_cb(struct votable *votable, void *data, if (rc < 0) return rc; - vote(chip->hvdcp_hw_inov_dis_votable, CP_VOTER, false, 0); - vote(chip->pl_disable_votable, CP_VOTER, false, 0); } else { - vote(chip->hvdcp_hw_inov_dis_votable, CP_VOTER, true, 0); - vote(chip->pl_disable_votable, CP_VOTER, true, 0); rc = smb1390_masked_write(chip, CORE_CONTROL1_REG, CMD_EN_SWITCHER_BIT, CMD_EN_SWITCHER_BIT); if (rc < 0) -- GitLab From fa97dae4cdffe16241527705a7fa430e47ac17d2 Mon Sep 17 00:00:00 2001 From: Deepak Kumar Date: Thu, 26 Apr 2018 11:16:55 +0530 Subject: [PATCH 1537/1635] msm: kgsl: Log external and transaction stalled iommu faults Add check to log external and transaction stalled iommu faults also instead of dumping fault type as unknown for these faults. Signed-off-by: Deepak Kumar Change-Id: Id95082eba94d480335a3c5569d7ab34f6c500c71 --- drivers/gpu/msm/kgsl_gmu.c | 4 ++++ drivers/gpu/msm/kgsl_iommu.c | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/drivers/gpu/msm/kgsl_gmu.c b/drivers/gpu/msm/kgsl_gmu.c index 1ff50871fb1e..e72a32102546 100644 --- a/drivers/gpu/msm/kgsl_gmu.c +++ b/drivers/gpu/msm/kgsl_gmu.c @@ -112,6 +112,10 @@ static int _gmu_iommu_fault_handler(struct device *dev, fault_type = "translation"; else if (flags & IOMMU_FAULT_PERMISSION) fault_type = "permission"; + else if (flags & IOMMU_FAULT_EXTERNAL) + fault_type = "external"; + else if (flags & IOMMU_FAULT_TRANSACTION_STALLED) + fault_type = "transaction stalled"; dev_err(dev, "GMU fault addr = %lX, context=%s (%s %s fault)\n", addr, name, diff --git a/drivers/gpu/msm/kgsl_iommu.c b/drivers/gpu/msm/kgsl_iommu.c index 9517bc52471f..439e3d24a32d 100644 --- a/drivers/gpu/msm/kgsl_iommu.c +++ b/drivers/gpu/msm/kgsl_iommu.c @@ -796,6 +796,10 @@ static int kgsl_iommu_fault_handler(struct iommu_domain *domain, fault_type = "translation"; else if (flags & IOMMU_FAULT_PERMISSION) fault_type = "permission"; + else if (flags & IOMMU_FAULT_EXTERNAL) + fault_type = "external"; + else if (flags & IOMMU_FAULT_TRANSACTION_STALLED) + fault_type = "transaction stalled"; if (kgsl_iommu_suppress_pagefault(addr, write, context)) { iommu->pagefault_suppression_count++; -- GitLab From e86dee8e71df936cc758414c20641e603c5dedab Mon Sep 17 00:00:00 2001 From: Dhaval Patel Date: Tue, 6 Mar 2018 13:15:10 -0800 Subject: [PATCH 1538/1635] drm/msm: update rsc mode_2 entry failure sequence sde rsc mode_2 entry may fail due to sequence busy in mode_0 or mode_1. It can be avoided by manually triggering the f1 qtimer interrupt and execute the mode sequence. This change tries to run the recovery sequence for 3 times to avoid mode_2 entry failure. Change-Id: Ie373c31668e985e7b1c6fd4cb4753cc8a127619f Signed-off-by: Dhaval Patel --- drivers/gpu/drm/msm/sde_rsc_hw.c | 80 ++++++++++++++++++++++++++------ 1 file changed, 66 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/msm/sde_rsc_hw.c b/drivers/gpu/drm/msm/sde_rsc_hw.c index a87ae69a0847..71cd4a049ead 100644 --- a/drivers/gpu/drm/msm/sde_rsc_hw.c +++ b/drivers/gpu/drm/msm/sde_rsc_hw.c @@ -99,6 +99,10 @@ #define MAX_CHECK_LOOPS 500 #define POWER_CTRL_BIT_12 12 +#define SDE_RSC_MODE_0_VAL 0 +#define SDE_RSC_MODE_1_VAL 1 +#define MAX_MODE2_ENTRY_TRY 3 + static void rsc_event_trigger(struct sde_rsc_priv *rsc, uint32_t event_type) { struct sde_rsc_event *event; @@ -489,23 +493,12 @@ static int sde_rsc_mode2_exit(struct sde_rsc_priv *rsc, return rc; } -static int sde_rsc_mode2_entry(struct sde_rsc_priv *rsc) +static int sde_rsc_mode2_entry_trigger(struct sde_rsc_priv *rsc) { int rc; int count, wrapper_status; unsigned long reg; - if (rsc->power_collapse_block) - return -EINVAL; - - rc = regulator_set_mode(rsc->fs, REGULATOR_MODE_FAST); - if (rc) { - pr_err("vdd reg fast mode set failed rc:%d\n", rc); - return rc; - } - - rsc_event_trigger(rsc, SDE_RSC_EVENT_PRE_CORE_PC); - /* update qtimers to high during clk & video mode state */ if ((rsc->current_state == SDE_RSC_VID_STATE) || (rsc->current_state == SDE_RSC_CLK_STATE)) { @@ -550,15 +543,74 @@ static int sde_rsc_mode2_entry(struct sde_rsc_priv *rsc) usleep_range(10, 100); } + return rc; +} + +static void sde_rsc_reset_mode_0_1(struct sde_rsc_priv *rsc) +{ + u32 seq_busy, current_mode, curr_inst_addr; + + seq_busy = dss_reg_r(&rsc->drv_io, SDE_RSCC_SEQ_BUSY_DRV0, + rsc->debug_mode); + current_mode = dss_reg_r(&rsc->drv_io, SDE_RSCC_SOLVER_STATUS2_DRV0, + rsc->debug_mode); + curr_inst_addr = dss_reg_r(&rsc->drv_io, SDE_RSCC_SEQ_PROGRAM_COUNTER, + rsc->debug_mode); + SDE_EVT32(seq_busy, current_mode, curr_inst_addr); + + if (seq_busy && (current_mode == SDE_RSC_MODE_0_VAL || + current_mode == SDE_RSC_MODE_1_VAL)) { + dss_reg_w(&rsc->wrapper_io, SDE_RSCC_F1_QTMR_V1_CNTP_CVAL_LO, + 0xffffffff, rsc->debug_mode); + dss_reg_w(&rsc->wrapper_io, SDE_RSCC_F1_QTMR_V1_CNTP_CVAL_HI, + 0xffffffff, rsc->debug_mode); + /* unstick f1 qtimer */ + wmb(); + + dss_reg_w(&rsc->wrapper_io, SDE_RSCC_F1_QTMR_V1_CNTP_CVAL_LO, + 0x0, rsc->debug_mode); + dss_reg_w(&rsc->wrapper_io, SDE_RSCC_F1_QTMR_V1_CNTP_CVAL_HI, + 0x0, rsc->debug_mode); + /* manually trigger f1 qtimer interrupt */ + wmb(); + } +} + +static int sde_rsc_mode2_entry(struct sde_rsc_priv *rsc) +{ + int rc = 0, i; + u32 reg; + + if (rsc->power_collapse_block) + return -EINVAL; + + rc = regulator_set_mode(rsc->fs, REGULATOR_MODE_FAST); if (rc) { + pr_err("vdd reg fast mode set failed rc:%d\n", rc); + return rc; + } + + rsc_event_trigger(rsc, SDE_RSC_EVENT_PRE_CORE_PC); + + for (i = 0; i <= MAX_MODE2_ENTRY_TRY; i++) { + rc = sde_rsc_mode2_entry_trigger(rsc); + if (!rc) + break; + reg = dss_reg_r(&rsc->drv_io, SDE_RSCC_SEQ_PROGRAM_COUNTER, rsc->debug_mode); pr_err("mdss gdsc power down failed, instruction:0x%x, rc:%d\n", reg, rc); SDE_EVT32(rc, reg, SDE_EVTLOG_ERROR); - goto end; + + /* avoid touching f1 qtimer for last try */ + if (i != MAX_MODE2_ENTRY_TRY) + sde_rsc_reset_mode_0_1(rsc); } + if (rc) + goto end; + if ((rsc->current_state == SDE_RSC_VID_STATE) || (rsc->current_state == SDE_RSC_CLK_STATE)) { dss_reg_w(&rsc->wrapper_io, SDE_RSCC_WRAPPER_OVERRIDE_CTRL, @@ -632,7 +684,7 @@ static int sde_rsc_state_update(struct sde_rsc_priv *rsc, reg = dss_reg_r(&rsc->wrapper_io, SDE_RSCC_WRAPPER_OVERRIDE_CTRL, rsc->debug_mode); - reg &= ~(BIT(8) | BIT(0)); + reg &= ~BIT(0); dss_reg_w(&rsc->wrapper_io, SDE_RSCC_WRAPPER_OVERRIDE_CTRL, reg, rsc->debug_mode); /* make sure that solver mode is disabled */ -- GitLab From 53d88e8dbf06a0e829bf5d69b7d7e5b254fd5d69 Mon Sep 17 00:00:00 2001 From: Dhaval Patel Date: Wed, 14 Mar 2018 13:03:32 -0700 Subject: [PATCH 1539/1635] drm/msm/sde: update mode-2 entry/exit sequence Disable mode-2 selection from RSC hardware after sw has triggered it manually. This avoids double shutdown issue if panel does not generate a vsync after solver enabled. The change also updates F0 Qtimer trigger for mode_2 entry triggered during mode_0 or mode_1. Change-Id: Ic7a993acbdb7cdeb4ff9654846b430cdf0938d7a Signed-off-by: Dhaval Patel --- drivers/gpu/drm/msm/sde_rsc_hw.c | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/msm/sde_rsc_hw.c b/drivers/gpu/drm/msm/sde_rsc_hw.c index 71cd4a049ead..7679a8828ac8 100644 --- a/drivers/gpu/drm/msm/sde_rsc_hw.c +++ b/drivers/gpu/drm/msm/sde_rsc_hw.c @@ -488,6 +488,9 @@ static int sde_rsc_mode2_exit(struct sde_rsc_priv *rsc, if (rc) pr_err("vdd reg is not enabled yet\n"); + dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_SOLVER_MODES_ENABLED_DRV0, + 0x3, rsc->debug_mode); + rsc_event_trigger(rsc, SDE_RSC_EVENT_POST_CORE_RESTORE); return rc; @@ -560,19 +563,33 @@ static void sde_rsc_reset_mode_0_1(struct sde_rsc_priv *rsc) if (seq_busy && (current_mode == SDE_RSC_MODE_0_VAL || current_mode == SDE_RSC_MODE_1_VAL)) { - dss_reg_w(&rsc->wrapper_io, SDE_RSCC_F1_QTMR_V1_CNTP_CVAL_LO, - 0xffffffff, rsc->debug_mode); dss_reg_w(&rsc->wrapper_io, SDE_RSCC_F1_QTMR_V1_CNTP_CVAL_HI, + 0xffffff, rsc->debug_mode); + dss_reg_w(&rsc->wrapper_io, SDE_RSCC_F1_QTMR_V1_CNTP_CVAL_LO, 0xffffffff, rsc->debug_mode); /* unstick f1 qtimer */ wmb(); - dss_reg_w(&rsc->wrapper_io, SDE_RSCC_F1_QTMR_V1_CNTP_CVAL_LO, - 0x0, rsc->debug_mode); dss_reg_w(&rsc->wrapper_io, SDE_RSCC_F1_QTMR_V1_CNTP_CVAL_HI, 0x0, rsc->debug_mode); + dss_reg_w(&rsc->wrapper_io, SDE_RSCC_F1_QTMR_V1_CNTP_CVAL_LO, + 0x0, rsc->debug_mode); /* manually trigger f1 qtimer interrupt */ wmb(); + + dss_reg_w(&rsc->wrapper_io, SDE_RSCC_F0_QTMR_V1_CNTP_CVAL_HI, + 0xffffff, rsc->debug_mode); + dss_reg_w(&rsc->wrapper_io, SDE_RSCC_F0_QTMR_V1_CNTP_CVAL_LO, + 0xffffffff, rsc->debug_mode); + /* unstick f0 qtimer */ + wmb(); + + dss_reg_w(&rsc->wrapper_io, SDE_RSCC_F0_QTMR_V1_CNTP_CVAL_HI, + 0x0, rsc->debug_mode); + dss_reg_w(&rsc->wrapper_io, SDE_RSCC_F0_QTMR_V1_CNTP_CVAL_LO, + 0x0, rsc->debug_mode); + /* manually trigger f0 qtimer interrupt */ + wmb(); } } @@ -590,6 +607,8 @@ static int sde_rsc_mode2_entry(struct sde_rsc_priv *rsc) return rc; } + dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_SOLVER_MODES_ENABLED_DRV0, + 0x7, rsc->debug_mode); rsc_event_trigger(rsc, SDE_RSC_EVENT_PRE_CORE_PC); for (i = 0; i <= MAX_MODE2_ENTRY_TRY; i++) { -- GitLab From e8706ba149bc8c224fe09b3420860b62a1624309 Mon Sep 17 00:00:00 2001 From: Dhaval Patel Date: Wed, 9 May 2018 14:10:04 -0700 Subject: [PATCH 1540/1635] drm/msm/sde: remove duplicate intf te irq entries Remove duplicate intf_1 and intf_2 te interrupt entries from irq list table. Change-Id: If21007d6166c28f88540dafcb1c8c909038dcc9c Signed-off-by: Dhaval Patel --- drivers/gpu/drm/msm/sde/sde_hw_interrupts.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/gpu/drm/msm/sde/sde_hw_interrupts.c b/drivers/gpu/drm/msm/sde/sde_hw_interrupts.c index 0b57dfe6345d..ecf4a4ff99c1 100644 --- a/drivers/gpu/drm/msm/sde/sde_hw_interrupts.c +++ b/drivers/gpu/drm/msm/sde/sde_hw_interrupts.c @@ -805,8 +805,6 @@ static const struct sde_irq_type sde_irq_map[] = { SDE_INTR_INTF_TEAR_WR_PTR, 10}, { SDE_IRQ_TYPE_INTF_TEAR_RD_PTR, INTF_1, SDE_INTR_INTF_TEAR_RD_PTR, 10}, - { SDE_IRQ_TYPE_INTF_TEAR_TE_CHECK, INTF_1, - SDE_INTR_INTF_TEAR_TE_DETECTED, 10}, /* irq_idx: 323 */ { SDE_IRQ_TYPE_INTF_TEAR_TEAR_CHECK, INTF_1, SDE_INTR_INTF_TEAR_TEAR_DETECTED, 10}, @@ -854,8 +852,6 @@ static const struct sde_irq_type sde_irq_map[] = { SDE_INTR_INTF_TEAR_WR_PTR, 11}, { SDE_IRQ_TYPE_INTF_TEAR_RD_PTR, INTF_2, SDE_INTR_INTF_TEAR_RD_PTR, 11}, - { SDE_IRQ_TYPE_INTF_TEAR_TE_CHECK, INTF_2, - SDE_INTR_INTF_TEAR_TE_DETECTED, 11}, /* irq_idx: 355 */ { SDE_IRQ_TYPE_INTF_TEAR_TEAR_CHECK, INTF_2, SDE_INTR_INTF_TEAR_TEAR_DETECTED, 11}, -- GitLab From a9408316986df23231b93b735217729da0824271 Mon Sep 17 00:00:00 2001 From: Dhaval Patel Date: Wed, 9 May 2018 14:11:14 -0700 Subject: [PATCH 1541/1635] drm/msm: avoid power event setting during mode_2 exit RSC rev_2 supports 64 bit timer counter and power event BIT(13) set/reset is not required during mode_2 exit sequence. Update the rsc sequence based revision. Change-Id: I82428056e0b05136c801de40c73914c022129830 Signed-off-by: Dhaval Patel --- drivers/gpu/drm/msm/sde_rsc_hw.c | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/msm/sde_rsc_hw.c b/drivers/gpu/drm/msm/sde_rsc_hw.c index 7679a8828ac8..509ae503eaf9 100644 --- a/drivers/gpu/drm/msm/sde_rsc_hw.c +++ b/drivers/gpu/drm/msm/sde_rsc_hw.c @@ -103,6 +103,9 @@ #define SDE_RSC_MODE_1_VAL 1 #define MAX_MODE2_ENTRY_TRY 3 +#define SDE_RSC_REV_1 0x1 +#define SDE_RSC_REV_2 0x2 + static void rsc_event_trigger(struct sde_rsc_priv *rsc, uint32_t event_type) { struct sde_rsc_event *event; @@ -457,11 +460,13 @@ static int sde_rsc_mode2_exit(struct sde_rsc_priv *rsc, dss_reg_w(&rsc->wrapper_io, SDE_RSCC_WRAPPER_CTRL, reg, rsc->debug_mode); - reg = dss_reg_r(&rsc->wrapper_io, SDE_RSCC_SPARE_PWR_EVENT, + if (rsc->version < SDE_RSC_REV_2) { + reg = dss_reg_r(&rsc->wrapper_io, SDE_RSCC_SPARE_PWR_EVENT, rsc->debug_mode); - reg |= BIT(13); - dss_reg_w(&rsc->wrapper_io, SDE_RSCC_SPARE_PWR_EVENT, + reg |= BIT(13); + dss_reg_w(&rsc->wrapper_io, SDE_RSCC_SPARE_PWR_EVENT, reg, rsc->debug_mode); + } /* make sure that mode-2 exit before wait*/ wmb(); @@ -480,11 +485,14 @@ static int sde_rsc_mode2_exit(struct sde_rsc_priv *rsc, usleep_range(10, 100); } - reg = dss_reg_r(&rsc->wrapper_io, SDE_RSCC_SPARE_PWR_EVENT, + if (rsc->version < SDE_RSC_REV_2) { + reg = dss_reg_r(&rsc->wrapper_io, SDE_RSCC_SPARE_PWR_EVENT, rsc->debug_mode); - reg &= ~BIT(13); - dss_reg_w(&rsc->wrapper_io, SDE_RSCC_SPARE_PWR_EVENT, + reg &= ~BIT(13); + dss_reg_w(&rsc->wrapper_io, SDE_RSCC_SPARE_PWR_EVENT, reg, rsc->debug_mode); + } + if (rc) pr_err("vdd reg is not enabled yet\n"); @@ -742,7 +750,7 @@ int rsc_hw_init(struct sde_rsc_priv *rsc) goto end; } - if (rsc->version == 2) + if (rsc->version == SDE_RSC_REV_2) rc = rsc_hw_seq_memory_init_v2(rsc); else rc = rsc_hw_seq_memory_init(rsc); -- GitLab From 139a0ae5e3d9509e39cf0967a3fc40dfd7eebe03 Mon Sep 17 00:00:00 2001 From: Veera Sundaram Sankaran Date: Thu, 10 May 2018 14:22:37 -0700 Subject: [PATCH 1542/1635] drm/msm/sde: program QoS/danger/safe LUTs for WB block Enable programming the writeback QoS/danger/safe LUTs based on the device tree configs. Change-Id: I75a72e6671317b4f26b8a4759d85a244deb60bb8 Signed-off-by: Veera Sundaram Sankaran --- drivers/gpu/drm/msm/sde/sde_encoder_phys_wb.c | 67 +++++++++++++++++++ 1 file changed, 67 insertions(+) diff --git a/drivers/gpu/drm/msm/sde/sde_encoder_phys_wb.c b/drivers/gpu/drm/msm/sde/sde_encoder_phys_wb.c index 729d14047c9d..59acecf73550 100644 --- a/drivers/gpu/drm/msm/sde/sde_encoder_phys_wb.c +++ b/drivers/gpu/drm/msm/sde/sde_encoder_phys_wb.c @@ -153,6 +153,71 @@ static void sde_encoder_phys_wb_set_qos_remap( sde_vbif_set_qos_remap(phys_enc->sde_kms, &qos_params); } +static u64 _sde_encoder_phys_wb_get_qos_lut(const struct sde_qos_lut_tbl *tbl, + u32 total_fl) +{ + int i; + + if (!tbl || !tbl->nentry || !tbl->entries) + return 0; + + for (i = 0; i < tbl->nentry; i++) + if (total_fl <= tbl->entries[i].fl) + return tbl->entries[i].lut; + + /* if last fl is zero, use as default */ + if (!tbl->entries[i-1].fl) + return tbl->entries[i-1].lut; + + return 0; +} + +/** + * sde_encoder_phys_wb_set_qos - set QoS/danger/safe LUTs for writeback + * @phys_enc: Pointer to physical encoder + */ +static void sde_encoder_phys_wb_set_qos(struct sde_encoder_phys *phys_enc) +{ + struct sde_encoder_phys_wb *wb_enc; + struct sde_hw_wb *hw_wb; + struct sde_hw_wb_qos_cfg qos_cfg; + struct sde_mdss_cfg *catalog; + + if (!phys_enc || !phys_enc->sde_kms || !phys_enc->sde_kms->catalog) { + SDE_ERROR("invalid parameter(s)\n"); + return; + } + catalog = phys_enc->sde_kms->catalog; + + wb_enc = to_sde_encoder_phys_wb(phys_enc); + if (!wb_enc->hw_wb) { + SDE_ERROR("invalid writeback hardware\n"); + return; + } + + hw_wb = wb_enc->hw_wb; + + memset(&qos_cfg, 0, sizeof(struct sde_hw_wb_qos_cfg)); + qos_cfg.danger_safe_en = true; + qos_cfg.danger_lut = + catalog->perf.danger_lut_tbl[SDE_QOS_LUT_USAGE_NRT]; + qos_cfg.safe_lut = + (u32) _sde_encoder_phys_wb_get_qos_lut( + &catalog->perf.sfe_lut_tbl[SDE_QOS_LUT_USAGE_NRT], 0); + qos_cfg.creq_lut = + _sde_encoder_phys_wb_get_qos_lut( + &catalog->perf.qos_lut_tbl[SDE_QOS_LUT_USAGE_NRT], 0); + + if (hw_wb->ops.setup_danger_safe_lut) + hw_wb->ops.setup_danger_safe_lut(hw_wb, &qos_cfg); + + if (hw_wb->ops.setup_creq_lut) + hw_wb->ops.setup_creq_lut(hw_wb, &qos_cfg); + + if (hw_wb->ops.setup_qos_ctrl) + hw_wb->ops.setup_qos_ctrl(hw_wb, &qos_cfg); +} + /** * sde_encoder_phys_setup_cdm - setup chroma down block * @phys_enc: Pointer to physical encoder @@ -710,6 +775,8 @@ static void sde_encoder_phys_wb_setup( sde_encoder_phys_wb_set_qos_remap(phys_enc); + sde_encoder_phys_wb_set_qos(phys_enc); + sde_encoder_phys_setup_cdm(phys_enc, fb, wb_enc->wb_fmt, wb_roi); sde_encoder_phys_wb_setup_fb(phys_enc, fb, wb_roi); -- GitLab From 8bc06d93ad6386b235002a35391abfade40dc4c7 Mon Sep 17 00:00:00 2001 From: Sujeev Dias Date: Mon, 30 Apr 2018 13:07:31 -0700 Subject: [PATCH 1543/1635] ARM: dts: msm: Update MHI configuration for sm8150 Based on client's requirements, update MHI configurations to disable automatic buffer allocation for DIAG, start IPCR channels automatically after probe, and enable automatic buffer allocations for IP_CTRL channel. CRs-Fixed: 2239849 Change-Id: I1fa145faaddbcfce6ddbf171fc76f3afe76b8952 Signed-off-by: Sujeev Dias --- arch/arm64/boot/dts/qcom/sm8150.dtsi | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sm8150.dtsi b/arch/arm64/boot/dts/qcom/sm8150.dtsi index 37c7f0b35201..26f7d758bafe 100644 --- a/arch/arm64/boot/dts/qcom/sm8150.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150.dtsi @@ -3373,13 +3373,13 @@ mhi,chan-cfg = <0 64 2 1 2 0 2 0 0>, <1 64 2 2 2 0 2 0 0>, <2 128 1 1 2 0 1 0 0>, <3 128 1 2 2 0 1 0 0>, - <4 64 1 1 2 0 2 0 0>, <5 64 3 2 2 0 2 0 0x8>, + <4 64 1 1 2 0 2 0 0>, <5 64 3 2 2 0 2 0 0>, <8 64 1 1 2 0 2 0 0>, <9 64 1 2 2 0 2 0 0>, <10 64 1 1 2 0 2 0 0>, <11 64 1 2 2 0 2 0 0>, <14 64 1 1 2 0 2 0 0>, <15 64 2 2 2 0 2 0 0>, <16 64 3 1 2 0 2 0 0>, <17 64 3 2 2 0 2 0 0>, - <18 64 1 1 2 0 2 0 0>, <19 64 1 2 2 0 2 0 0>, - <20 64 2 1 2 0 2 1 0>, <21 64 2 2 2 0 2 0 0x8>, + <18 64 1 1 2 0 2 0 0>, <19 64 1 2 2 0 2 0 8>, + <20 64 2 1 2 0 2 1 16>, <21 64 2 2 2 0 2 0 24>, <22 64 2 1 2 0 2 0 0>, <23 64 2 2 2 0 2 0 0>, <24 64 2 1 2 0 1 0 0>, <25 64 2 2 2 0 1 0 0>, <26 64 3 1 2 0 2 0 0>, <27 64 3 2 2 0 2 0 0>, -- GitLab From d061f6ab852d6b09e128e732e4a1b28777de2c62 Mon Sep 17 00:00:00 2001 From: Sudheer Papothi Date: Sat, 12 May 2018 06:17:39 +0530 Subject: [PATCH 1544/1635] ARM: dts: msm: Fix phandle for sound node on SM8150 CDP Use sound phandle instead of device node to update sound properties on SM8150 CDP. Change-Id: Ia0c43dec739a12764c62fac3271936f5d181b96b Signed-off-by: Sudheer Papothi --- arch/arm64/boot/dts/qcom/sm8150-cdp.dtsi | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sm8150-cdp.dtsi b/arch/arm64/boot/dts/qcom/sm8150-cdp.dtsi index 23bf63b97531..c8cbf4000dd1 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-cdp.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-cdp.dtsi @@ -81,11 +81,11 @@ linux,can-disable; }; }; +}; - sound-tavil { - qcom,model = "sm8150-tavil-cdp-snd-card"; - qcom,us-euro-gpios = <&tavil_us_euro_switch>; - }; +&snd_934x { + qcom,model = "sm8150-tavil-cdp-snd-card"; + qcom,us-euro-gpios = <&tavil_us_euro_switch>; }; &dsi_sharp_4k_dsc_cmd { -- GitLab From fd82bbcb2b242980a1a0cc6d15c6c895afc60fc9 Mon Sep 17 00:00:00 2001 From: Roman Gushchin Date: Tue, 10 Apr 2018 16:27:36 -0700 Subject: [PATCH 1545/1635] mm: introduce NR_INDIRECTLY_RECLAIMABLE_BYTES Patch series "indirectly reclaimable memory", v2. This patchset introduces the concept of indirectly reclaimable memory and applies it to fix the issue of when a big number of dentries with external names can significantly affect the MemAvailable value. This patch (of 3): Introduce a concept of indirectly reclaimable memory and adds the corresponding memory counter and /proc/vmstat item. Indirectly reclaimable memory is any sort of memory, used by the kernel (except of reclaimable slabs), which is actually reclaimable, i.e. will be released under memory pressure. The counter is in bytes, as it's not always possible to count such objects in pages. The name contains BYTES by analogy to NR_KERNEL_STACK_KB. Link: http://lkml.kernel.org/r/20180305133743.12746-2-guro@fb.com Signed-off-by: Roman Gushchin Reviewed-by: Andrew Morton Cc: Alexander Viro Cc: Michal Hocko Cc: Johannes Weiner Cc: Mel Gorman Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Git-Commit: eb59254608bc1d42c4c6afdcdce9c0d3ce02b318 Git-Repo: git://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git Change-Id: I6ea0d449210973c92f57f3b7f5173e1ec85c81f8 Signed-off-by: Vijayanand Jitta --- include/linux/mmzone.h | 1 + mm/vmstat.c | 1 + 2 files changed, 2 insertions(+) diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h index f0938257ee6d..f679f5268467 100644 --- a/include/linux/mmzone.h +++ b/include/linux/mmzone.h @@ -180,6 +180,7 @@ enum node_stat_item { NR_VMSCAN_IMMEDIATE, /* Prioritise for reclaim when writeback ends */ NR_DIRTIED, /* page dirtyings since bootup */ NR_WRITTEN, /* page writings since bootup */ + NR_INDIRECTLY_RECLAIMABLE_BYTES, /* measured in bytes */ NR_VM_NODE_STAT_ITEMS }; diff --git a/mm/vmstat.c b/mm/vmstat.c index f23151305209..218229251c21 100644 --- a/mm/vmstat.c +++ b/mm/vmstat.c @@ -1090,6 +1090,7 @@ const char * const vmstat_text[] = { "nr_vmscan_immediate_reclaim", "nr_dirtied", "nr_written", + "nr_indirectly_reclaimable", /* enum writeback_stat_item counters */ "nr_dirty_threshold", -- GitLab From d680316d79242b9499c5bbfd51657dc08439567f Mon Sep 17 00:00:00 2001 From: Roman Gushchin Date: Tue, 10 Apr 2018 16:27:40 -0700 Subject: [PATCH 1546/1635] mm: treat indirectly reclaimable memory as available in MemAvailable Adjust /proc/meminfo MemAvailable calculation by adding the amount of indirectly reclaimable memory (rounded to the PAGE_SIZE). Link: http://lkml.kernel.org/r/20180305133743.12746-4-guro@fb.com Signed-off-by: Roman Gushchin Reviewed-by: Andrew Morton Cc: Alexander Viro Cc: Michal Hocko Cc: Johannes Weiner Cc: Mel Gorman Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Git-Commit: 034ebf65c3c21d85b963d39f992258a64a85e3a9 Git-Repo: git://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git Change-Id: I32547afd6ffa8c7979aa1d5978a7b9aef84aff4a Signed-off-by: Vijayanand Jitta --- mm/page_alloc.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 73f61974b9db..7c275f6a990a 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -4558,6 +4558,13 @@ long si_mem_available(void) min(global_node_page_state(NR_SLAB_RECLAIMABLE) / 2, wmark_low); + /* + * Part of the kernel memory, which can be released under memory + * pressure. + */ + available += global_node_page_state(NR_INDIRECTLY_RECLAIMABLE_BYTES) >> + PAGE_SHIFT; + if (available < 0) available = 0; return available; -- GitLab From 7b5c388dfc97dc29434473445d34157c6d076fc5 Mon Sep 17 00:00:00 2001 From: Roman Gushchin Date: Tue, 10 Apr 2018 16:27:47 -0700 Subject: [PATCH 1547/1635] mm: treat indirectly reclaimable memory as free in overcommit logic Indirectly reclaimable memory can consume a significant part of total memory and it's actually reclaimable (it will be released under actual memory pressure). So, the overcommit logic should treat it as free. Otherwise, it's possible to cause random system-wide memory allocation failures by consuming a significant amount of memory by indirectly reclaimable memory, e.g. dentry external names. If overcommit policy GUESS is used, it might be used for denial of service attack under some conditions. The following program illustrates the approach. It causes the kernel to allocate an unreclaimable kmalloc-256 chunk for each stat() call, so that at some point the overcommit logic may start blocking large allocation system-wide. int main() { char buf[256]; unsigned long i; struct stat statbuf; buf[0] = '/'; for (i = 1; i < sizeof(buf); i++) buf[i] = '_'; for (i = 0; 1; i++) { sprintf(&buf[248], "%8lu", i); stat(buf, &statbuf); } return 0; } This patch in combination with related indirectly reclaimable memory patches closes this issue. Link: http://lkml.kernel.org/r/20180313130041.8078-1-guro@fb.com Signed-off-by: Roman Gushchin Reviewed-by: Andrew Morton Cc: Alexander Viro Cc: Michal Hocko Cc: Johannes Weiner Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Git-Commit: d79f7aa496fc94d763f67b833a1f36f4c171176f Git-Repo: git://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git Change-Id: I6daf49a77a687446135c5d21828932e28a79fc19 Signed-off-by: Vijayanand Jitta --- mm/util.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/mm/util.c b/mm/util.c index 34e57fae959d..547e04b5cfff 100644 --- a/mm/util.c +++ b/mm/util.c @@ -635,6 +635,13 @@ int __vm_enough_memory(struct mm_struct *mm, long pages, int cap_sys_admin) */ free += global_node_page_state(NR_SLAB_RECLAIMABLE); + /* + * Part of the kernel memory, which can be released + * under memory pressure. + */ + free += global_node_page_state( + NR_INDIRECTLY_RECLAIMABLE_BYTES) >> PAGE_SHIFT; + /* * Leave reserved pages. The pages are not for anonymous pages. */ -- GitLab From 013bf399ac2c4aaa3b8dea37f62aede2cb5c8066 Mon Sep 17 00:00:00 2001 From: Vijayanand Jitta Date: Wed, 18 Apr 2018 10:28:16 +0530 Subject: [PATCH 1548/1635] ion: Consider ion pool pages as indirectly reclaimable An issue is observed where mallocs are failing due to overcommit failure. The failure happens when there is high ION page pool since ION page pool is not considered reclaimable by the overcommit calculation code. This change considers ion pool pages as indirectly reclaimable and thus accounted as available memory in the overcommit calculation. Change-Id: I8d63209b8c19286e55c407459ff124fdc58fdcc2 Signed-off-by: Vijayanand Jitta --- drivers/staging/android/ion/ion_page_pool.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/staging/android/ion/ion_page_pool.c b/drivers/staging/android/ion/ion_page_pool.c index 0ddc663678c4..b1efb3958a87 100644 --- a/drivers/staging/android/ion/ion_page_pool.c +++ b/drivers/staging/android/ion/ion_page_pool.c @@ -48,6 +48,9 @@ static int ion_page_pool_add(struct ion_page_pool *pool, struct page *page) list_add_tail(&page->lru, &pool->low_items); pool->low_count++; } + + mod_node_page_state(page_pgdat(page), NR_INDIRECTLY_RECLAIMABLE_BYTES, + (1 << (PAGE_SHIFT + pool->order))); mutex_unlock(&pool->mutex); return 0; } @@ -67,6 +70,8 @@ static struct page *ion_page_pool_remove(struct ion_page_pool *pool, bool high) } list_del(&page->lru); + mod_node_page_state(page_pgdat(page), NR_INDIRECTLY_RECLAIMABLE_BYTES, + -(1 << (PAGE_SHIFT + pool->order))); return page; } -- GitLab From ba5a7d6fd2a7a80954b9e8c95f07fbfe6640880c Mon Sep 17 00:00:00 2001 From: Prateek Sood Date: Mon, 30 Apr 2018 15:19:29 +0530 Subject: [PATCH 1549/1635] edac: Check part number before parsing L1/L2 error Parse L1/L2 errors based on the part number. This will remove the need for keeping track of the number of cores in cluster, boot core etc. Change-Id: Idcaeff7ff1a82b8f52344588a5ab53f087bc439e Signed-off-by: Prateek Sood --- drivers/edac/kryo_arm64_edac.c | 32 ++++++++++++++++++++++++++++---- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/drivers/edac/kryo_arm64_edac.c b/drivers/edac/kryo_arm64_edac.c index 89cb0658be16..f7a1863bc7f1 100644 --- a/drivers/edac/kryo_arm64_edac.c +++ b/drivers/edac/kryo_arm64_edac.c @@ -46,8 +46,12 @@ module_param(poll_msec, int, 0444); #define L2_SILVER_BIT 0x1 #define L3_BIT 0x2 -#define L1_GOLD_DC_BIT 0x1 -#define L1_GOLD_IC_BIT 0x4 +#define QCOM_CPU_PART_KRYO4XX_GOLD 0x804 +#define QCOM_CPU_PART_KRYO4XX_SILVER_V1 0x803 +#define QCOM_CPU_PART_KRYO4XX_SILVER_V2 0x805 + +#define L1_GOLD_IC_BIT 0x1 +#define L1_GOLD_DC_BIT 0x4 #define L2_GOLD_BIT 0x8 #define L2_GOLD_TLB_BIT 0x2 @@ -258,8 +262,12 @@ static void kryo_parse_l1_l2_cache_error(u64 errxstatus, u64 errxmisc, struct edac_device_ctl_info *edev_ctl, int cpu) { int level = 0; + u32 part_num; - if (cpu <= 3) { + part_num = read_cpuid_part_number(); + switch (part_num) { + case QCOM_CPU_PART_KRYO4XX_SILVER_V1: + case QCOM_CPU_PART_KRYO4XX_SILVER_V2: switch (KRYO_ERRXMISC_LVL(errxmisc)) { case L1_SILVER_BIT: level = L1; @@ -267,8 +275,13 @@ static void kryo_parse_l1_l2_cache_error(u64 errxstatus, u64 errxmisc, case L2_SILVER_BIT: level = L2; break; + default: + edac_printk(KERN_CRIT, EDAC_CPU, + "silver cpu:%d unknown error location:%u\n", + cpu, KRYO_ERRXMISC_LVL(errxmisc)); } - } else { + break; + case QCOM_CPU_PART_KRYO4XX_GOLD: switch (KRYO_ERRXMISC_LVL_GOLD(errxmisc)) { case L1_GOLD_DC_BIT: case L1_GOLD_IC_BIT: @@ -278,8 +291,19 @@ static void kryo_parse_l1_l2_cache_error(u64 errxstatus, u64 errxmisc, case L2_GOLD_TLB_BIT: level = L2; break; + default: + edac_printk(KERN_CRIT, EDAC_CPU, + "gold cpu:%d unknown error location:%u\n", + cpu, KRYO_ERRXMISC_LVL_GOLD(errxmisc)); } + break; + default: + edac_printk(KERN_CRIT, EDAC_CPU, + "Error in matching cpu%d with part num:%u\n", + cpu, part_num); + return; } + switch (level) { case L1: if (KRYO_ERRXSTATUS_UE(errxstatus)) -- GitLab From 0110eb5cb672567d627954f7c2fce7f7a62612ef Mon Sep 17 00:00:00 2001 From: Salendarsingh Gaud Date: Thu, 10 May 2018 16:14:38 +0530 Subject: [PATCH 1550/1635] ARM: dts: msm: Add early mount partition details for sm6150 Add details of vendor partition to support early mount on sm6150. Change-Id: Ic53af58d586d2df615611167e7bc781ea7fb12af Signed-off-by: Salendarsingh Gaud --- arch/arm64/boot/dts/qcom/sm6150.dtsi | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sm6150.dtsi b/arch/arm64/boot/dts/qcom/sm6150.dtsi index 6ceba108843e..fac1e15aacf0 100644 --- a/arch/arm64/boot/dts/qcom/sm6150.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6150.dtsi @@ -334,6 +334,23 @@ soc: soc { }; + firmware: firmware { + android { + compatible = "android,firmware"; + fstab { + compatible = "android,fstab"; + vendor { + compatible = "android,vendor"; + dev = "/dev/block/platform/soc/7c4000.sdhci/by-name/vendor"; + type = "ext4"; + mnt_flags = "ro,barrier=1,discard"; + fsmgr_flags = "wait,slotselect,avb"; + status = "ok"; + }; + }; + }; + }; + reserved-memory { #address-cells = <2>; #size-cells = <2>; -- GitLab From 567794d3af12ac7af8f60c21969a54d6a61acd94 Mon Sep 17 00:00:00 2001 From: Sreelakshmi Gownipalli Date: Tue, 23 Jan 2018 13:11:41 -0800 Subject: [PATCH 1551/1635] diag: Protect the decrement of number of diag clients In diagchar_open() protect the decrement of number of diag clients so that there will be no race conditions while reading the value from other functions. Change-Id: I0e2fb5331eec9c7bba39e7d881b69559256833a3 Signed-off-by: Sreelakshmi Gownipalli --- drivers/char/diag/diagchar_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/char/diag/diagchar_core.c b/drivers/char/diag/diagchar_core.c index c2f394fcf8c9..ff53215026ca 100644 --- a/drivers/char/diag/diagchar_core.c +++ b/drivers/char/diag/diagchar_core.c @@ -370,8 +370,8 @@ static int diagchar_open(struct inode *inode, struct file *file) return -ENOMEM; fail: - mutex_unlock(&driver->diagchar_mutex); driver->num_clients--; + mutex_unlock(&driver->diagchar_mutex); pr_err_ratelimited("diag: Insufficient memory for new client"); return -ENOMEM; } -- GitLab From 3fbb2af9590adf5e17bcd32ffac1fdc8274ff63c Mon Sep 17 00:00:00 2001 From: Kiran Gunda Date: Mon, 7 May 2018 14:30:28 +0530 Subject: [PATCH 1552/1635] ARM: dts: msm: Add power grid regulator phandles for SM6150 Add secondary phandles to each of the PM640 and PM640L regulator devices which match the naming scheme used in the power grid hardware documentation. This should help to alleviate confusion between similarly named regulators on different PMICs (e.g. pm640_l1 and pm640l_l1 vs L1A and L1C). Also add tertiary phandles for VDD_CX, VDD_MX, and VDD_MMCX supplies which each serve the same purpose for several consumers. Change-Id: Ib976a506dcd26efa35c3bec59c39366d83b8ada1 Signed-off-by: Kiran Gunda --- .../boot/dts/qcom/sm6150-stub-regulator.dtsi | 212 +++++++++--------- 1 file changed, 100 insertions(+), 112 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sm6150-stub-regulator.dtsi b/arch/arm64/boot/dts/qcom/sm6150-stub-regulator.dtsi index cc5cf2746b83..02213050f589 100644 --- a/arch/arm64/boot/dts/qcom/sm6150-stub-regulator.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6150-stub-regulator.dtsi @@ -16,40 +16,44 @@ / { /* pm6150 S1 - VDD_CX supply */ + VDD_CX_LEVEL: pm6150_s1_level: regulator-pm6150-s1 { compatible = "qcom,stub-regulator"; regulator-name = "pm6150_s1_level"; qcom,hpm-min-load = <100000>; regulator-min-microvolt = ; - regulator-max-microvolt = ; + regulator-max-microvolt = ; }; + VDD_CX_LEVEL_AO: pm6150_s1_level_ao: regulator-pm6150-s1-level-ao { compatible = "qcom,stub-regulator"; regulator-name = "pm6150_s1_level_ao"; qcom,hpm-min-load = <100000>; regulator-min-microvolt = ; - regulator-max-microvolt = ; + regulator-max-microvolt = ; }; /* pm6150 S3 - VDD_MX supply */ - pm6150_s3_level: regulator-pm6150-s3 { + VDD_MX_LEVEL: + S3A_LEVEL: pm6150_s3_level: regulator-pm6150-s3 { compatible = "qcom,stub-regulator"; regulator-name = "pm6150_s3_level"; qcom,hpm-min-load = <100000>; regulator-min-microvolt = ; - regulator-max-microvolt = ; + regulator-max-microvolt = ; }; - pm6150_s3_level_ao: regulator-pm6150-s3-level-ao { + VDD_MX_LEVEL_AO: + S3A_LEVEL_AO: pm6150_s3_level_ao: regulator-pm6150-s3-level-ao { compatible = "qcom,stub-regulator"; regulator-name = "pm6150_s3_level_ao"; qcom,hpm-min-load = <100000>; regulator-min-microvolt = ; - regulator-max-microvolt = ; + regulator-max-microvolt = ; }; - pm6150l_s1: regulator-pm6150l-s1 { + S1C: pm6150l_s1: regulator-pm6150l-s1 { compatible = "qcom,stub-regulator"; regulator-name = "pm6150l_s1"; qcom,hpm-min-load = <100000>; @@ -57,218 +61,195 @@ regulator-max-microvolt = <1128000>; }; - pm6150l_s2: regulator-pm6150l-s2 { + S2C: pm6150l_s2: regulator-pm6150l-s2 { compatible = "qcom,stub-regulator"; regulator-name = "pm6150l_s2"; qcom,hpm-min-load = <100000>; - regulator-min-microvolt = <600000>; - regulator-max-microvolt = <600000>; + regulator-min-microvolt = <348000>; + regulator-max-microvolt = <1200000>; }; /* pm6150l S7 - VDD_MSS supply */ - pm6150l_s7_level: regulator-pm6150l-s7 { + VDD_MSS_LEVEL: + S7C_LEVEL: pm6150l_s7_level: regulator-pm6150l-s7 { compatible = "qcom,stub-regulator"; regulator-name = "pm6150l_s7_level"; qcom,hpm-min-load = <100000>; regulator-min-microvolt = ; - regulator-max-microvolt = ; + regulator-max-microvolt = ; }; - pm6150l_s7_level_ao: regulator-pm6150l-s7-level-ao { - compatible = "qcom,stub-regulator"; - regulator-name = "pm6150l_s7_level_ao"; - qcom,hpm-min-load = <100000>; - regulator-min-microvolt = ; - regulator-max-microvolt = ; - }; - - pm6150l_s8: regulator-pm6150l-s8 { + S8C: pm6150l_s8: regulator-pm6150l-s8 { compatible = "qcom,stub-regulator"; regulator-name = "pm6150l_s8"; qcom,hpm-min-load = <100000>; - regulator-min-microvolt = <1352000>; - regulator-max-microvolt = <1352000>; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1400000>; }; - pm6150_l1: regulator-pm6150-l1 { + L1A: pm6150_l1: regulator-pm6150-l1 { compatible = "qcom,stub-regulator"; regulator-name = "pm6150_l1"; qcom,hpm-min-load = <10000>; regulator-min-microvolt = <1200000>; - regulator-max-microvolt = <1200000>; + regulator-max-microvolt = <1252000>; }; - pm6150_l2: regulator-pm6150-l2 { + L2A: pm6150_l2: regulator-pm6150-l2 { compatible = "qcom,stub-regulator"; regulator-name = "pm6150_l2"; qcom,hpm-min-load = <10000>; regulator-min-microvolt = <1000000>; - regulator-max-microvolt = <1000000>; + regulator-max-microvolt = <1050000>; }; - pm6150_l3: regulator-pm6150-l3 { + L3A: pm6150_l3: regulator-pm6150-l3 { compatible = "qcom,stub-regulator"; regulator-name = "pm6150_l3"; qcom,hpm-min-load = <10000>; regulator-min-microvolt = <1000000>; - regulator-max-microvolt = <1000000>; + regulator-max-microvolt = <1060000>; }; - pm6150_l4: regulator-pm6150-l4 { + L4A: pm6150_l4: regulator-pm6150-l4 { compatible = "qcom,stub-regulator"; regulator-name = "pm6150_l4"; qcom,hpm-min-load = <10000>; - regulator-min-microvolt = <900000>; - regulator-max-microvolt = <928000>; + regulator-min-microvolt = <875000>; + regulator-max-microvolt = <975000>; }; - pm6150_l5: regulator-pm6150-l5 { + L5A: pm6150_l5: regulator-pm6150-l5 { compatible = "qcom,stub-regulator"; regulator-name = "pm6150_l5"; qcom,hpm-min-load = <10000>; - regulator-min-microvolt = <2700000>; - regulator-max-microvolt = <2704000>; + regulator-min-microvolt = <2500000>; + regulator-max-microvolt = <2970000>; }; - pm6150_l6: regulator-pm6150-l6 { + L6A: pm6150_l6: regulator-pm6150-l6 { compatible = "qcom,stub-regulator"; regulator-name = "pm6150_l6"; qcom,hpm-min-load = <10000>; regulator-min-microvolt = <600000>; - regulator-max-microvolt = <600000>; + regulator-max-microvolt = <650000>; }; /* pm6150 L7 - LPI_MX supply */ - pm6150_l7_level: regulator-pm6150-l7 { + L7A_LEVEL: pm6150_l7_level: regulator-pm6150-l7 { compatible = "qcom,stub-regulator"; regulator-name = "pm6150_l7_level"; qcom,hpm-min-load = <10000>; regulator-min-microvolt = ; - regulator-max-microvolt = ; - }; - - pm6150_l7_level_ao: regulator-pm6150-l7-level-ao { - compatible = "qcom,stub-regulator"; - regulator-name = "pm6150_l7_level_ao"; - qcom,hpm-min-load = <10000>; - regulator-min-microvolt = ; - regulator-max-microvolt = ; + regulator-max-microvolt = ; }; /* pm6150 L8 - LPI_CX supply */ - pm6150_l8_level: regulator-pm6150-l8 { + L8A_LEVEL: pm6150_l8_level: regulator-pm6150-l8 { compatible = "qcom,stub-regulator"; regulator-name = "pm6150_l8_level"; qcom,hpm-min-load = <10000>; regulator-min-microvolt = ; - regulator-max-microvolt = ; + regulator-max-microvolt = ; }; - pm6150_l8_level_ao: regulator-pm6150-l8_level_ao { - compatible = "qcom,stub-regulator"; - regulator-name = "pm6150_l8_level_ao"; - qcom,hpm-min-load = <10000>; - regulator-min-microvolt = ; - regulator-max-microvolt = ; - }; - - pm6150_l9: regulator-pm6150-l9 { + L9A: pm6150_l9: regulator-pm6150-l9 { compatible = "qcom,stub-regulator"; regulator-name = "pm6150_l9"; qcom,hpm-min-load = <10000>; - regulator-min-microvolt = <728000>; + regulator-min-microvolt = <400000>; regulator-max-microvolt = <728000>; }; - pm6150_l10: regulator-pm6150-l10 { + L10A: pm6150_l10: regulator-pm6150-l10 { compatible = "qcom,stub-regulator"; regulator-name = "pm6150_l10"; qcom,hpm-min-load = <10000>; regulator-min-microvolt = <1800000>; - regulator-max-microvolt = <1800000>; + regulator-max-microvolt = <1829000>; }; - pm6150_l11: regulator-pm6150-l11 { + L11A: pm6150_l11: regulator-pm6150-l11 { compatible = "qcom,stub-regulator"; regulator-name = "pm6150_l11"; qcom,hpm-min-load = <10000>; regulator-min-microvolt = <1800000>; - regulator-max-microvolt = <1800000>; + regulator-max-microvolt = <1890000>; }; - pm6150_l12: regulator-pm6150-l12 { + L12A: pm6150_l12: regulator-pm6150-l12 { compatible = "qcom,stub-regulator"; regulator-name = "pm6150_l12"; qcom,hpm-min-load = <10000>; regulator-min-microvolt = <1800000>; - regulator-max-microvolt = <1800000>; + regulator-max-microvolt = <1950000>; }; - pm6150_l13: regulator-pm6150-l13 { + L13A: pm6150_l13: regulator-pm6150-l13 { compatible = "qcom,stub-regulator"; regulator-name = "pm6150_l13"; qcom,hpm-min-load = <10000>; regulator-min-microvolt = <1800000>; - regulator-max-microvolt = <1800000>; + regulator-max-microvolt = <1900000>; }; - pm6150_l14: regulator-pm6150-l14 { + L14A: pm6150_l14: regulator-pm6150-l14 { compatible = "qcom,stub-regulator"; regulator-name = "pm6150_l14"; qcom,hpm-min-load = <10000>; regulator-min-microvolt = <1800000>; - regulator-max-microvolt = <1800000>; + regulator-max-microvolt = <1850000>; }; - pm6150_l15: regulator-pm6150-l15 { + L15A: pm6150_l15: regulator-pm6150-l15 { compatible = "qcom,stub-regulator"; regulator-name = "pm6150_l15"; qcom,hpm-min-load = <10000>; regulator-min-microvolt = <1800000>; - regulator-max-microvolt = <1800000>; + regulator-max-microvolt = <1900000>; }; - pm6150_l16: regulator-pm6150-l16 { + L16A: pm6150_l16: regulator-pm6150-l16 { compatible = "qcom,stub-regulator"; regulator-name = "pm6150_l16"; qcom,hpm-min-load = <10000>; - regulator-min-microvolt = <2700000>; - regulator-max-microvolt = <2704000>; + regulator-min-microvolt = <2430000>; + regulator-max-microvolt = <2970000>; }; - pm6150_l17: regulator-pm6150-l17 { + L17A: pm6150_l17: regulator-pm6150-l17 { compatible = "qcom,stub-regulator"; regulator-name = "pm6150_l17"; qcom,hpm-min-load = <10000>; - regulator-min-microvolt = <3100000>; - regulator-max-microvolt = <3128000>; + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <3230000>; }; - pm6150_l18: regulator-pm6150-l18 { + L18A: pm6150_l18: regulator-pm6150-l18 { compatible = "qcom,stub-regulator"; regulator-name = "pm6150_l18"; qcom,hpm-min-load = <10000>; regulator-min-microvolt = <3000000>; - regulator-max-microvolt = <3300000>; + regulator-max-microvolt = <3008000>; }; - pm6150_l19: regulator-pm6150-l19 { + L19A: pm6150_l19: regulator-pm6150-l19 { compatible = "qcom,stub-regulator"; regulator-name = "pm6150_l19"; qcom,hpm-min-load = <10000>; - regulator-min-microvolt = <2848000>; - regulator-max-microvolt = <2848000>; + regulator-min-microvolt = <2700000>; + regulator-max-microvolt = <3008000>; }; - pm6150l_l1: regulator-pm6150l-l1 { + L1C: pm6150l_l1: regulator-pm6150l-l1 { compatible = "qcom,stub-regulator"; regulator-name = "pm6150l_l1"; qcom,hpm-min-load = <10000>; regulator-min-microvolt = <1800000>; - regulator-max-microvolt = <1800000>; + regulator-max-microvolt = <1900000>; }; - pm6150l_l2: regulator-pm6150l-l2 { + L2C: pm6150l_l2: regulator-pm6150l-l2 { compatible = "qcom,stub-regulator"; regulator-name = "pm6150l_l2"; qcom,hpm-min-load = <10000>; @@ -276,82 +257,89 @@ regulator-max-microvolt = <1304000>; }; - pm6150l_l3: regulator-pm6150l-l3 { + L3C: pm6150l_l3: regulator-pm6150l-l3 { compatible = "qcom,stub-regulator"; regulator-name = "pm6150l_l3"; qcom,hpm-min-load = <10000>; - regulator-min-microvolt = <1200000>; - regulator-max-microvolt = <1250000>; + regulator-min-microvolt = <1232000>; + regulator-max-microvolt = <1260000>; }; - pm6150l_l4: regulator-pm6150l-l4 { + L4C: pm6150l_l4: regulator-pm6150l-l4 { compatible = "qcom,stub-regulator"; regulator-name = "pm6150l_l4"; qcom,hpm-min-load = <10000>; - regulator-min-microvolt = <1800000>; + regulator-min-microvolt = <1650000>; regulator-max-microvolt = <2950000>; }; - pm6150l_l5: regulator-pm6150l-l5 { + L5C: pm6150l_l5: regulator-pm6150l-l5 { compatible = "qcom,stub-regulator"; regulator-name = "pm6150l_l5"; qcom,hpm-min-load = <10000>; - regulator-min-microvolt = <1800000>; + regulator-min-microvolt = <1650000>; regulator-max-microvolt = <2950000>; }; - pm6150l_l6: regulator-pm6150l-l6 { + L6C: pm6150l_l6: regulator-pm6150l-l6 { compatible = "qcom,stub-regulator"; regulator-name = "pm6150l_l6"; qcom,hpm-min-load = <5000>; - regulator-min-microvolt = <1800000>; - regulator-max-microvolt = <2950000>; + regulator-min-microvolt = <1650000>; + regulator-max-microvolt = <3100000>; }; - pm6150l_l7: regulator-pm6150l-l7 { + L7C: pm6150l_l7: regulator-pm6150l-l7 { compatible = "qcom,stub-regulator"; regulator-name = "pm6150l_l7"; qcom,hpm-min-load = <10000>; - regulator-min-microvolt = <3008000>; - regulator-max-microvolt = <3008000>; + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <3312000>; }; - pm6150l_l8: regulator-pm6150l-l8 { + L8C: pm6150l_l8: regulator-pm6150l-l8 { compatible = "qcom,stub-regulator"; regulator-name = "pm6150l_l8"; qcom,hpm-min-load = <10000>; regulator-min-microvolt = <1800000>; - regulator-max-microvolt = <1800000>; + regulator-max-microvolt = <1900000>; }; - pm6150l_l9: regulator-pm6150l-l9 { + L9C: pm6150l_l9: regulator-pm6150l-l9 { compatible = "qcom,stub-regulator"; regulator-name = "pm6150l_l9"; qcom,hpm-min-load = <10000>; - regulator-min-microvolt = <2960000>; - regulator-max-microvolt = <2960000>; + regulator-min-microvolt = <2950000>; + regulator-max-microvolt = <3312000>; }; - pm6150l_l10: regulator-pm6150l-l10 { + L10C: pm6150l_l10: regulator-pm6150l-l10 { compatible = "qcom,stub-regulator"; regulator-name = "pm6150l_l10"; qcom,hpm-min-load = <10000>; - regulator-min-microvolt = <3304000>; - regulator-max-microvolt = <3304000>; + regulator-min-microvolt = <3200000>; + regulator-max-microvolt = <3312000>; }; - pm6150l_l11: regulator-pm6150l-l11 { + L11C: pm6150l_l11: regulator-pm6150l-l11 { compatible = "qcom,stub-regulator"; regulator-name = "pm6150l_l11"; qcom,hpm-min-load = <10000>; - regulator-min-microvolt = <2960000>; - regulator-max-microvolt = <2960000>; + regulator-min-microvolt = <2950000>; + regulator-max-microvolt = <3312000>; }; - pm6150l_bob: regulator-pm6150l-bob { + BOB: pm6150l_bob: regulator-pm6150l-bob { compatible = "qcom,stub-regulator"; regulator-name = "pm6150l_bob"; - regulator-min-microvolt = <3300000>; - regulator-max-microvolt = <3300000>; + regulator-min-microvolt = <3296000>; + regulator-max-microvolt = <3960000>; + }; + + BOB_AO: pm6150l_bob_ao: regulator-pm6150l-bob-ao { + compatible = "qcom,stub-regulator"; + regulator-name = "pm6150l_bob_ao"; + regulator-min-microvolt = <3296000>; + regulator-max-microvolt = <3960000>; }; }; -- GitLab From 296c1f722339700d69b73dc8c4c19cc1ae4f92bc Mon Sep 17 00:00:00 2001 From: Manaf Meethalavalappu Pallikunhi Date: Fri, 11 May 2018 15:36:20 +0530 Subject: [PATCH 1553/1635] defconfig: msm: enable thermal framework related drivers for QCS405 Enable thermal framework related drivers like of-thermal, cpu thermal, devfreq thermal, QMI TM, virtual sensor, regulator cooling device etc. for QCS405. Change-Id: I3293d67d90c1dd2198bc72c841f9322352b39e4d Signed-off-by: Manaf Meethalavalappu Pallikunhi --- arch/arm/configs/qcs405-perf_defconfig | 8 ++++++++ arch/arm/configs/qcs405_defconfig | 8 ++++++++ arch/arm64/configs/qcs405-perf_defconfig | 10 ++++++++++ arch/arm64/configs/qcs405_defconfig | 10 ++++++++++ 4 files changed, 36 insertions(+) diff --git a/arch/arm/configs/qcs405-perf_defconfig b/arch/arm/configs/qcs405-perf_defconfig index 56aa4d4932b7..e8482bb2fc19 100644 --- a/arch/arm/configs/qcs405-perf_defconfig +++ b/arch/arm/configs/qcs405-perf_defconfig @@ -252,6 +252,14 @@ CONFIG_SPI_SPIDEV=y CONFIG_PINCTRL_QCS405=y CONFIG_GPIOLIB=y CONFIG_THERMAL=y +CONFIG_THERMAL_GOV_USER_SPACE=y +CONFIG_THERMAL_GOV_LOW_LIMITS=y +CONFIG_CPU_THERMAL=y +CONFIG_DEVFREQ_THERMAL=y +CONFIG_THERMAL_TSENS=y +CONFIG_QTI_VIRTUAL_SENSOR=y +CONFIG_QTI_QMI_COOLING_DEVICE=y +CONFIG_REGULATOR_COOLING_DEVICE=y CONFIG_REGULATOR=y CONFIG_REGULATOR_FIXED_VOLTAGE=y CONFIG_REGULATOR_FAN53555=y diff --git a/arch/arm/configs/qcs405_defconfig b/arch/arm/configs/qcs405_defconfig index 05b2eaea44eb..3909ec1e118d 100644 --- a/arch/arm/configs/qcs405_defconfig +++ b/arch/arm/configs/qcs405_defconfig @@ -261,6 +261,14 @@ CONFIG_PINCTRL_QCS405=y CONFIG_GPIOLIB=y CONFIG_POWER_SUPPLY=y CONFIG_THERMAL=y +CONFIG_THERMAL_GOV_USER_SPACE=y +CONFIG_THERMAL_GOV_LOW_LIMITS=y +CONFIG_CPU_THERMAL=y +CONFIG_DEVFREQ_THERMAL=y +CONFIG_THERMAL_TSENS=y +CONFIG_QTI_VIRTUAL_SENSOR=y +CONFIG_QTI_QMI_COOLING_DEVICE=y +CONFIG_REGULATOR_COOLING_DEVICE=y CONFIG_REGULATOR=y CONFIG_REGULATOR_FIXED_VOLTAGE=y CONFIG_REGULATOR_FAN53555=y diff --git a/arch/arm64/configs/qcs405-perf_defconfig b/arch/arm64/configs/qcs405-perf_defconfig index 59b2034ba122..34e1507dc3a7 100644 --- a/arch/arm64/configs/qcs405-perf_defconfig +++ b/arch/arm64/configs/qcs405-perf_defconfig @@ -43,6 +43,7 @@ CONFIG_PM_WAKELOCKS_LIMIT=0 # CONFIG_PM_WAKELOCKS_GC is not set CONFIG_CPU_IDLE=y CONFIG_ARM_CPUIDLE=y +CONFIG_CPU_FREQ=y CONFIG_NET=y CONFIG_PACKET=y CONFIG_UNIX=y @@ -249,6 +250,15 @@ CONFIG_SLIMBUS=y CONFIG_SLIMBUS_MSM_NGD=y CONFIG_PINCTRL_QCS405=y CONFIG_THERMAL=y +CONFIG_THERMAL_WRITABLE_TRIPS=y +CONFIG_THERMAL_GOV_USER_SPACE=y +CONFIG_THERMAL_GOV_LOW_LIMITS=y +CONFIG_CPU_THERMAL=y +CONFIG_DEVFREQ_THERMAL=y +CONFIG_THERMAL_TSENS=y +CONFIG_QTI_VIRTUAL_SENSOR=y +CONFIG_QTI_QMI_COOLING_DEVICE=y +CONFIG_REGULATOR_COOLING_DEVICE=y CONFIG_MFD_SYSCON=y CONFIG_REGULATOR=y CONFIG_REGULATOR_FIXED_VOLTAGE=y diff --git a/arch/arm64/configs/qcs405_defconfig b/arch/arm64/configs/qcs405_defconfig index 969529846565..1f749635453e 100644 --- a/arch/arm64/configs/qcs405_defconfig +++ b/arch/arm64/configs/qcs405_defconfig @@ -49,6 +49,7 @@ CONFIG_PM_WAKELOCKS_LIMIT=0 CONFIG_PM_DEBUG=y CONFIG_CPU_IDLE=y CONFIG_ARM_CPUIDLE=y +CONFIG_CPU_FREQ=y CONFIG_NET=y CONFIG_PACKET=y CONFIG_UNIX=y @@ -259,6 +260,15 @@ CONFIG_SLIMBUS=y CONFIG_SLIMBUS_MSM_NGD=y CONFIG_PINCTRL_QCS405=y CONFIG_THERMAL=y +CONFIG_THERMAL_WRITABLE_TRIPS=y +CONFIG_THERMAL_GOV_USER_SPACE=y +CONFIG_THERMAL_GOV_LOW_LIMITS=y +CONFIG_CPU_THERMAL=y +CONFIG_DEVFREQ_THERMAL=y +CONFIG_THERMAL_TSENS=y +CONFIG_QTI_VIRTUAL_SENSOR=y +CONFIG_QTI_QMI_COOLING_DEVICE=y +CONFIG_REGULATOR_COOLING_DEVICE=y CONFIG_MFD_SYSCON=y CONFIG_REGULATOR=y CONFIG_REGULATOR_FIXED_VOLTAGE=y -- GitLab From a1def2c51f1b0a3f5a709eb633d4c87e4ecf769f Mon Sep 17 00:00:00 2001 From: Konstantin Dorfman Date: Thu, 10 May 2018 22:11:12 +0300 Subject: [PATCH 1554/1635] soc: qcom: spcom: fix uapi for SPU kernel-pil This change adds missing userspace type definition, fixing dependence. Change-Id: I5020c38948579a2a929175f535553f6ada009051 Signed-off-by: Konstantin Dorfman --- include/uapi/linux/spcom.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/include/uapi/linux/spcom.h b/include/uapi/linux/spcom.h index e8469f438af0..e1261b59593e 100644 --- a/include/uapi/linux/spcom.h +++ b/include/uapi/linux/spcom.h @@ -94,6 +94,13 @@ struct spcom_user_create_channel_command { char ch_name[SPCOM_CHANNEL_NAME_SIZE]; } __packed; +/* Command structure between userspace spcomlib and spcom driver, on write() */ +#define SPCOM_USER_RESTART_SP_CMD +struct spcom_user_restart_sp_command { + enum spcom_cmd_id cmd_id; + uint32_t arg; +} __packed; + /* maximum ION buf for send-modfied-command */ #define SPCOM_MAX_ION_BUF 4 -- GitLab From ac5b7607fe516e01c199d94f3cd76d58b9d3268b Mon Sep 17 00:00:00 2001 From: Ram Chandrasekar Date: Wed, 6 Dec 2017 12:22:24 -0700 Subject: [PATCH 1555/1635] qcom-cpufreq: Register cooling device in ready callback Thermal cooling device has to be registered when the policy for a CPU is ready. Cpufreq will get a callback when a cpufreq policy is ready and register CPU cooling device as a part of this callback, so that the CPU can be mitigated immediately if needed. Ignore cpu cooling device registration when there is platform cooling device available. Change-Id: I7cfb8598aa8ead4091a617da3faddf86ff0fe6a8 Signed-off-by: Ram Chandrasekar Signed-off-by: Manaf Meethalavalappu Pallikunhi --- drivers/cpufreq/qcom-cpufreq.c | 48 ++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/drivers/cpufreq/qcom-cpufreq.c b/drivers/cpufreq/qcom-cpufreq.c index 33ba7bf6ee2e..7f7626f29a79 100644 --- a/drivers/cpufreq/qcom-cpufreq.c +++ b/drivers/cpufreq/qcom-cpufreq.c @@ -27,10 +27,13 @@ #include #include #include +#include +#include #include static DEFINE_MUTEX(l2bw_lock); +static struct thermal_cooling_device *cdev[NR_CPUS]; static struct clk *cpu_clk[NR_CPUS]; static struct clk *l2_clk; static DEFINE_PER_CPU(struct cpufreq_frequency_table *, freq_table); @@ -306,6 +309,50 @@ static struct freq_attr *msm_freq_attr[] = { NULL, }; +static void msm_cpufreq_ready(struct cpufreq_policy *policy) +{ + struct device_node *np, *lmh_node; + unsigned int cpu = 0; + + if (cdev[policy->cpu]) + return; + + np = of_cpu_device_node_get(policy->cpu); + if (WARN_ON(!np)) + return; + + /* + * For now, just loading the cooling device; + * thermal DT code takes care of matching them. + */ + if (of_find_property(np, "#cooling-cells", NULL)) { + lmh_node = of_parse_phandle(np, "qcom,lmh-dcvs", 0); + if (lmh_node) { + of_node_put(lmh_node); + goto ready_exit; + } + + for_each_cpu(cpu, policy->related_cpus) { + + of_node_put(np); + np = of_cpu_device_node_get(cpu); + if (WARN_ON(!np)) + return; + + cdev[cpu] = of_cpufreq_cooling_register(np, policy); + if (IS_ERR(cdev[cpu])) { + pr_err( + "running cpufreq for CPU%d without cooling dev: %ld\n", + cpu, PTR_ERR(cdev[cpu])); + cdev[cpu] = NULL; + } + } + } + +ready_exit: + of_node_put(np); +} + static struct cpufreq_driver msm_cpufreq_driver = { /* lps calculations are handled here. */ .flags = CPUFREQ_STICKY | CPUFREQ_CONST_LOOPS | @@ -317,6 +364,7 @@ static struct cpufreq_driver msm_cpufreq_driver = { .get = msm_cpufreq_get_freq, .name = "msm", .attr = msm_freq_attr, + .ready = msm_cpufreq_ready, }; static struct cpufreq_frequency_table *cpufreq_parse_dt(struct device *dev, -- GitLab From f2d7bad0f6b873cb157754cf95caa4db7bbf5761 Mon Sep 17 00:00:00 2001 From: Manaf Meethalavalappu Pallikunhi Date: Mon, 16 Apr 2018 17:16:41 +0530 Subject: [PATCH 1556/1635] drivers: thermal: Update mitigation state reading logic from devicetree Thermal cooling device uses THERMAL_MAX_LIMIT macro so that users can define any mitigation state as an offset from max supported state for that cooling device. But the logic to get actual state from this offset config ignores if devicetree cooling device state is THERMAL_MAX_LIMIT minus max supported state for that cooling device. Update mitigation state calculation logic not accounted correctly. Change-Id: I8fbdbf19e44e4bfbac315afe4cf79d40501bda58 Signed-off-by: Manaf Meethalavalappu Pallikunhi --- drivers/thermal/thermal_core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c index f6a855c0b516..4b1d34d67db4 100644 --- a/drivers/thermal/thermal_core.c +++ b/drivers/thermal/thermal_core.c @@ -724,7 +724,7 @@ int thermal_zone_bind_cooling_device(struct thermal_zone_device *tz, * based on the MACRO determine the default state to use or the * offset from the max_state. */ - if (upper > (THERMAL_MAX_LIMIT - max_state)) { + if (upper >= (THERMAL_MAX_LIMIT - max_state)) { /* upper default max_state */ if (upper == THERMAL_NO_LIMIT) upper = max_state; @@ -732,7 +732,7 @@ int thermal_zone_bind_cooling_device(struct thermal_zone_device *tz, upper = max_state - (THERMAL_MAX_LIMIT - upper); } - if (lower > (THERMAL_MAX_LIMIT - max_state)) { + if (lower >= (THERMAL_MAX_LIMIT - max_state)) { /* lower default 0 */ if (lower == THERMAL_NO_LIMIT) lower = 0; -- GitLab From 52960c666ec2bbb492019d1706487eae86b5a8f5 Mon Sep 17 00:00:00 2001 From: Manaf Meethalavalappu Pallikunhi Date: Thu, 10 May 2018 20:10:48 +0530 Subject: [PATCH 1557/1635] ARM: dts: msm: Add regulator cooling device for QCS405 Add regulator cooling device for CX regulator for QCS405. The cooling device will be used to place voltage floor restriction. Change-Id: If349f69d9a53405d43f53e7386d4a8ed4b2c86f0 Signed-off-by: Manaf Meethalavalappu Pallikunhi --- arch/arm64/boot/dts/qcom/qcs405-regulator.dtsi | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/qcs405-regulator.dtsi b/arch/arm64/boot/dts/qcom/qcs405-regulator.dtsi index 3546fb08a5ed..5d2842fb2ad2 100644 --- a/arch/arm64/boot/dts/qcom/qcs405-regulator.dtsi +++ b/arch/arm64/boot/dts/qcom/qcs405-regulator.dtsi @@ -50,6 +50,14 @@ ; qcom,use-voltage-level; }; + + cx_cdev: cx-cdev-lvl { + compatible = "qcom,regulator-cooling-device"; + regulator-cdev-supply = <&pms405_s1_floor_level>; + regulator-levels = ; + #cooling-cells = <2>; + }; }; /* PMS405 S2 - VDD_LPI_CX supply */ -- GitLab From f1c7352403d3fbc5be2ecdcf098137692cfe5bcd Mon Sep 17 00:00:00 2001 From: Manaf Meethalavalappu Pallikunhi Date: Thu, 10 May 2018 20:12:19 +0530 Subject: [PATCH 1558/1635] ARM: dts: msm: Add QMI cooling devices for QCS405 Add remote QMI cooling devices like modem_pa, modem_proc, modem_current and vdd restriction for modem subsystem for QCS405. Change-Id: I316c71cef282a0d64e90f8374be8a207984a3506 Signed-off-by: Manaf Meethalavalappu Pallikunhi --- arch/arm64/boot/dts/qcom/qcs405-thermal.dtsi | 30 ++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/qcs405-thermal.dtsi b/arch/arm64/boot/dts/qcom/qcs405-thermal.dtsi index 63a49cd149ec..cd16e218f3c1 100644 --- a/arch/arm64/boot/dts/qcom/qcs405-thermal.dtsi +++ b/arch/arm64/boot/dts/qcom/qcs405-thermal.dtsi @@ -12,6 +12,36 @@ #include +&soc { + qmi-tmd-devices { + compatible = "qcom,qmi-cooling-devices"; + + modem { + qcom,instance-id = <0x0>; + + modem_pa: modem_pa { + qcom,qmi-dev-name = "pa"; + #cooling-cells = <2>; + }; + + modem_proc: modem_proc { + qcom,qmi-dev-name = "modem"; + #cooling-cells = <2>; + }; + + modem_current: modem_current { + qcom,qmi-dev-name = "modem_current"; + #cooling-cells = <2>; + }; + + modem_vdd: modem_vdd { + qcom,qmi-dev-name = "cpuv_restriction_cold"; + #cooling-cells = <2>; + }; + }; + }; +}; + &thermal_zones { aoss-usr { polling-delay-passive = <0>; -- GitLab From 881ea4ff85a7aa169f15378610db7ef3723da02b Mon Sep 17 00:00:00 2001 From: Manaf Meethalavalappu Pallikunhi Date: Thu, 10 May 2018 20:14:19 +0530 Subject: [PATCH 1559/1635] drivers: thermal: virtual-sensor: Add new virtual sensor for QCS405 Add new virtual sensor definition for cpuss-max-step for QCS405. This virtual sensor can be used to monitor the overall temperature of CPU cluster device. Change-Id: I4dd4362bec5e1120953610da27291f5edf572bc0 Signed-off-by: Manaf Meethalavalappu Pallikunhi --- drivers/thermal/qcom/qti_virtual_sensor.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/thermal/qcom/qti_virtual_sensor.c b/drivers/thermal/qcom/qti_virtual_sensor.c index 903d8066667f..31fcfde67a0b 100644 --- a/drivers/thermal/qcom/qti_virtual_sensor.c +++ b/drivers/thermal/qcom/qti_virtual_sensor.c @@ -110,6 +110,16 @@ static const struct virtual_sensor_data qti_virtual_sensors[] = { "gpuss-1-usr"}, .logic = VIRT_MAXIMUM, }, + { + .virt_zone_name = "cpuss-max-step", + .num_sensors = 5, + .sensor_names = {"cpuss-0-usr", + "cpuss-1-usr", + "cpuss-2-usr", + "cpuss-3-usr", + "mhm-usr"}, + .logic = VIRT_MAXIMUM, + }, }; int qti_virtual_sensor_register(struct device *dev) -- GitLab From 4a684f1bc70617e595956fd6bf125edfa34bc4af Mon Sep 17 00:00:00 2001 From: Manaf Meethalavalappu Pallikunhi Date: Thu, 10 May 2018 21:43:48 +0530 Subject: [PATCH 1560/1635] ARM: dts: msm: Add default thermal zone rules for QCS405 Add default thermal zone rules like cpu frequency mitigation, core isolate mitigation, vdd restriction at cold temperature etc. for QCS405. Change-Id: I2a288b74377e75cb808b6edd34eccbcd72df091b Signed-off-by: Manaf Meethalavalappu Pallikunhi --- arch/arm64/boot/dts/qcom/qcs405-cpu.dtsi | 4 + arch/arm64/boot/dts/qcom/qcs405-rumi.dtsi | 4 + arch/arm64/boot/dts/qcom/qcs405-thermal.dtsi | 171 +++++++++++++++++++ arch/arm64/boot/dts/qcom/qcs405.dtsi | 2 +- 4 files changed, 180 insertions(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/qcs405-cpu.dtsi b/arch/arm64/boot/dts/qcom/qcs405-cpu.dtsi index b34ce592856c..3f83fd04b6de 100644 --- a/arch/arm64/boot/dts/qcom/qcs405-cpu.dtsi +++ b/arch/arm64/boot/dts/qcom/qcs405-cpu.dtsi @@ -43,6 +43,7 @@ reg = <0x100>; enable-method = "psci"; next-level-cache = <&L2_1>; + #cooling-cells = <2>; L2_1: l2-cache { compatible = "arm,arch-cache"; cache-level = <2>; @@ -65,6 +66,7 @@ reg = <0x101>; enable-method = "psci"; next-level-cache = <&L2_1>; + #cooling-cells = <2>; L1_I_101: l1-icache { compatible = "arm,arch-cache"; qcom,dump-size = <0x8800>; @@ -81,6 +83,7 @@ reg = <0x102>; enable-method = "psci"; next-level-cache = <&L2_1>; + #cooling-cells = <2>; L1_I_102: l1-icache { compatible = "arm,arch-cache"; qcom,dump-size = <0x8800>; @@ -97,6 +100,7 @@ reg = <0x103>; enable-method = "psci"; next-level-cache = <&L2_1>; + #cooling-cells = <2>; L1_I_103: l1-icache { compatible = "arm,arch-cache"; qcom,dump-size = <0x8800>; diff --git a/arch/arm64/boot/dts/qcom/qcs405-rumi.dtsi b/arch/arm64/boot/dts/qcom/qcs405-rumi.dtsi index d9d3d53be1ec..12fdb0f555ce 100644 --- a/arch/arm64/boot/dts/qcom/qcs405-rumi.dtsi +++ b/arch/arm64/boot/dts/qcom/qcs405-rumi.dtsi @@ -81,6 +81,10 @@ rpm-standalone; }; +&thermal_zones { + /delete-node/ aoss-lowf; +}; + #include "qcs405-stub-regulator.dtsi" &sdhc_1 { diff --git a/arch/arm64/boot/dts/qcom/qcs405-thermal.dtsi b/arch/arm64/boot/dts/qcom/qcs405-thermal.dtsi index cd16e218f3c1..64559e4f8d32 100644 --- a/arch/arm64/boot/dts/qcom/qcs405-thermal.dtsi +++ b/arch/arm64/boot/dts/qcom/qcs405-thermal.dtsi @@ -182,4 +182,175 @@ }; }; }; + + cpuss-max-step { + polling-delay-passive = <50>; + polling-delay = <100>; + thermal-governor = "step_wise"; + trips { + cpu_trip:cpu-trip { + temperature = <85000>; + hysteresis = <0>; + type = "passive"; + }; + }; + cooling-maps { + cpu0_cdev { + trip = <&cpu_trip>; + cooling-device = + <&CPU0 THERMAL_NO_LIMIT + (THERMAL_MAX_LIMIT-1)>; + }; + cpu1_cdev { + trip = <&cpu_trip>; + cooling-device = + <&CPU1 THERMAL_NO_LIMIT + (THERMAL_MAX_LIMIT-1)>; + }; + cpu2_cdev { + trip = <&cpu_trip>; + cooling-device = + <&CPU2 THERMAL_NO_LIMIT + (THERMAL_MAX_LIMIT-1)>; + }; + cpu3_cdev { + trip = <&cpu_trip>; + cooling-device = + <&CPU3 THERMAL_NO_LIMIT + (THERMAL_MAX_LIMIT-1)>; + }; + }; + }; + + gpu-step { + polling-delay-passive = <250>; + polling-delay = <0>; + thermal-sensors = <&tsens0 6>; + thermal-governor = "step_wise"; + trips { + gpu_step_trip: gpu-step-trip { + temperature = <95000>; + hysteresis = <0>; + type = "passive"; + }; + }; + }; + + cpuss-0-step { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens0 1>; + thermal-governor = "step_wise"; + trips { + cpuss_0_step_trip: cpuss-0-step-trip { + temperature = <105000>; + hysteresis = <15000>; + type = "passive"; + }; + }; + cooling-maps { + cpu0_cdev { + trip = <&cpuss_0_step_trip>; + cooling-device = + <&CPU0 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + }; + }; + + cpuss-1-step { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens0 2>; + thermal-governor = "step_wise"; + trips { + cpuss_1_step_trip: cpuss-1-step-trip { + temperature = <105000>; + hysteresis = <15000>; + type = "passive"; + }; + }; + cooling-maps { + cpu1_cdev { + trip = <&cpuss_1_step_trip>; + cooling-device = + <&CPU1 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + }; + }; + + cpuss-2-step { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens0 3>; + thermal-governor = "step_wise"; + trips { + cpuss_2_step_trip: cpuss-2-step-trip { + temperature = <105000>; + hysteresis = <15000>; + type = "passive"; + }; + }; + cooling-maps { + cpu2_cdev { + trip = <&cpuss_2_step_trip>; + cooling-device = + <&CPU2 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + }; + }; + + cpuss-3-step { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens0 4>; + thermal-governor = "step_wise"; + trips { + cpuss_3_step_trip: cpuss-3-step-trip { + temperature = <105000>; + hysteresis = <15000>; + type = "passive"; + }; + }; + cooling-maps { + cpu3_cdev { + trip = <&cpuss_3_step_trip>; + cooling-device = + <&CPU3 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + }; + }; + + aoss-lowf { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "low_limits_floor"; + thermal-sensors = <&tsens0 0>; + tracks-low; + trips { + aoss_lowf: aoss-lowf { + temperature = <5000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + cooling-maps { + cpu0_cdev { + trip = <&aoss_lowf>; + cooling-device = <&CPU0 (THERMAL_MAX_LIMIT-2) + (THERMAL_MAX_LIMIT-2)>; + }; + cx_vdd_cdev { + trip = <&aoss_lowf>; + cooling-device = <&cx_cdev 0 0>; + }; + modem_vdd_cdev { + trip = <&aoss_lowf>; + cooling-device = <&modem_vdd 0 0>; + }; + }; + }; }; diff --git a/arch/arm64/boot/dts/qcom/qcs405.dtsi b/arch/arm64/boot/dts/qcom/qcs405.dtsi index 3d2bd22029c1..421bf53a57c4 100644 --- a/arch/arm64/boot/dts/qcom/qcs405.dtsi +++ b/arch/arm64/boot/dts/qcom/qcs405.dtsi @@ -658,10 +658,10 @@ }; #include "qcs405-gdsc.dtsi" -#include "qcs405-thermal.dtsi" #include "pms405.dtsi" #include "pms405-rpm-regulator.dtsi" #include "qcs405-regulator.dtsi" +#include "qcs405-thermal.dtsi" &gdsc_mdss { status = "ok"; -- GitLab From bbfc56f9b9df6b094c3e6028504b64d8feb8edca Mon Sep 17 00:00:00 2001 From: Mulu He Date: Fri, 27 Apr 2018 10:53:47 +0800 Subject: [PATCH 1561/1635] ARM: dts: msm: Mapping CTI2 events to GPIO channels for sm8150 Mapping CTI2 events to GPIO49 channels for sm8150. Change-Id: I244159222337166afe4654cf1d795fd1c70fa259 Signed-off-by: Mulu He --- arch/arm64/boot/dts/qcom/sm8150-coresight.dtsi | 3 +++ arch/arm64/boot/dts/qcom/sm8150-pinctrl.dtsi | 12 ++++++++++++ 2 files changed, 15 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sm8150-coresight.dtsi b/arch/arm64/boot/dts/qcom/sm8150-coresight.dtsi index 8247f89057c8..5da67a724097 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-coresight.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-coresight.dtsi @@ -1968,6 +1968,9 @@ clocks = <&clock_aop QDSS_CLK>; clock-names = "apb_pclk"; + qcom,cti-gpio-trigout = <4>; + pinctrl-names = "cti-trigout-pctrl"; + pinctrl-0 = <&trigout_a>; }; cti3: cti@6013000 { diff --git a/arch/arm64/boot/dts/qcom/sm8150-pinctrl.dtsi b/arch/arm64/boot/dts/qcom/sm8150-pinctrl.dtsi index 80d43a2cf622..618c6044d1e5 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-pinctrl.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-pinctrl.dtsi @@ -3926,5 +3926,17 @@ drive-strength = <2>; /* 2 MA */ }; }; + + trigout_a: trigout_a { + mux { + pins = "gpio49"; + function = "qdss_cti"; + }; + config { + pins = "gpio49"; + drive-strength = <2>; + bias-disable; + }; + }; }; }; -- GitLab From 47b0e369e5d0362ffffefed685c80e664ff6f06c Mon Sep 17 00:00:00 2001 From: Saranya Chidura Date: Wed, 21 Feb 2018 16:56:01 +0530 Subject: [PATCH 1562/1635] ARM: dts: msm: add qdss support to qcs405 Add QDSS device configuration on QCS405 platforms. Change-Id: I4b453c3ec65e92ee928257bc0e4640ebac7f5854 Signed-off-by: Saranya Chidura --- .../arm64/boot/dts/qcom/qcs405-coresight.dtsi | 1070 +++++++++++++++++ arch/arm64/boot/dts/qcom/qcs405.dtsi | 12 +- 2 files changed, 1077 insertions(+), 5 deletions(-) create mode 100644 arch/arm64/boot/dts/qcom/qcs405-coresight.dtsi diff --git a/arch/arm64/boot/dts/qcom/qcs405-coresight.dtsi b/arch/arm64/boot/dts/qcom/qcs405-coresight.dtsi new file mode 100644 index 000000000000..ff42137a9bc1 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/qcs405-coresight.dtsi @@ -0,0 +1,1070 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +&soc { + + replicator_qdss: replicator@6046000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b909>; + + reg = <0x6046000 0x1000>; + reg-names = "replicator-base"; + + coresight-name = "coresight-replicator-qdss"; + + clocks = <&clock_gcc QDSS_CLK>, + <&clock_gcc QDSS_A_CLK>; + clock-names = "apb_pclk", "core_a_clk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + replicator_out_tmc_etr: endpoint { + remote-endpoint= + <&tmc_etr_in_replicator>; + }; + }; + + port@1 { + reg = <0>; + replicator_in_tmc_etf: endpoint { + slave-mode; + remote-endpoint= + <&tmc_etf_out_replicator>; + }; + }; + }; + }; + + tmc_etr: tmc@6048000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b961>; + + reg = <0x6048000 0x1000>, + <0x6064000 0x15000>; + reg-names = "tmc-base", "bam-base"; + + arm,buffer-size = <0x400000>; + + coresight-name = "coresight-tmc-etr"; + coresight-ctis = <&cti0>; + + clocks = <&clock_gcc QDSS_CLK>, + <&clock_gcc QDSS_A_CLK>; + clock-names = "apb_pclk", "core_a_clk"; + + interrupts = ; + interrupt-names = "byte-cntr-irq"; + + port { + tmc_etr_in_replicator: endpoint { + slave-mode; + remote-endpoint = <&replicator_out_tmc_etr>; + }; + }; + }; + + tmc_etf: tmc@6047000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b961>; + + reg = <0x6047000 0x1000>; + reg-names = "tmc-base"; + + coresight-name = "coresight-tmc-etf"; + coresight-ctis = <&cti0>; + arm,default-sink; + + clocks = <&clock_gcc QDSS_CLK>, + <&clock_gcc QDSS_A_CLK>; + clock-names = "apb_pclk", "core_a_clk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + tmc_etf_out_replicator: endpoint { + remote-endpoint = + <&replicator_in_tmc_etf>; + }; + }; + + port@1 { + reg = <0>; + tmc_etf_in_funnel_merg: endpoint { + slave-mode; + remote-endpoint = + <&funnel_merg_out_tmc_etf>; + }; + }; + }; + + }; + + funnel_merg: funnel@6045000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b908>; + + reg = <0x6045000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-merg"; + + clocks = <&clock_gcc QDSS_CLK>, + <&clock_gcc QDSS_A_CLK>; + clock-names = "apb_pclk", "core_a_clk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + funnel_merg_out_tmc_etf: endpoint { + remote-endpoint = + <&tmc_etf_in_funnel_merg>; + }; + }; + + port@1 { + reg = <0>; + funnel_merg_in_funnel_in0: endpoint { + slave-mode; + remote-endpoint = + <&funnel_in0_out_funnel_merg>; + }; + }; + + port@2 { + reg = <1>; + funnel_merg_in_funnel_in1: endpoint { + slave-mode; + remote-endpoint = + <&funnel_in1_out_funnel_merg>; + }; + }; + + port@3 { + reg = <2>; + funnel_merg_in_funnel_in2: endpoint { + slave-mode; + remote-endpoint = + <&funnel_in2_out_funnel_merg>; + }; + }; + }; + }; + + funnel_in0: funnel@6041000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b908>; + + reg = <0x6041000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-in0"; + + clocks = <&clock_gcc QDSS_CLK>, + <&clock_gcc QDSS_A_CLK>; + clock-names = "apb_pclk", "core_a_clk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + funnel_in0_out_funnel_merg: endpoint { + remote-endpoint = + <&funnel_merg_in_funnel_in0>; + }; + }; + + port@1 { + reg = <0>; + funnel_in0_in_rpm_etm0: endpoint { + slave-mode; + remote-endpoint = + <&rpm_etm0_out_funnel_in0>; + }; + }; + + port@2 { + reg = <6>; + funnel_in0_in_funnel_qatb: endpoint { + slave-mode; + remote-endpoint = + <&funnel_qatb_out_funnel_in0>; + }; + }; + + port@3 { + reg = <7>; + funnel_in0_in_stm: endpoint { + slave-mode; + remote-endpoint = + <&stm_out_funnel_in0>; + }; + }; + }; + }; + + funnel_in1: funnel@6042000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b908>; + + reg = <0x6042000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-in1"; + + clocks = <&clock_gcc QDSS_CLK>, + <&clock_gcc QDSS_A_CLK>; + clock-names = "apb_pclk", "core_a_clk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + funnel_in1_out_funnel_merg: endpoint { + remote-endpoint = + <&funnel_merg_in_funnel_in1>; + }; + }; + port@1 { + reg = <3>; + funnel_in1_in_audio_etm0: endpoint { + slave-mode; + remote-endpoint = + <&audio_etm0_out_funnel_in1>; + }; + }; + port@2 { + reg = <4>; + funnel_in1_in_modem_etm0: endpoint { + slave-mode; + remote-endpoint = + <&modem_etm0_out_funnel_in1>; + }; + }; + }; + }; + + funnel_in2: funnel@6043000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b908>; + + reg = <0x6043000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-in2"; + + clocks = <&clock_gcc QDSS_CLK>, + <&clock_gcc QDSS_A_CLK>; + clock-names = "apb_pclk", "core_a_clk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + funnel_in2_out_funnel_merg: endpoint { + remote-endpoint = + <&funnel_merg_in_funnel_in2>; + }; + }; + + port@1 { + reg = <3>; + funnel_in2_in_turing_etm0: endpoint { + slave-mode; + remote-endpoint = + <&turing_etm0_out_funnel_in2>; + }; + }; + + port@2 { + reg = <7>; + funnel_in2_in_funnel_apss: endpoint { + slave-mode; + remote-endpoint = + <&funnel_apss_out_funnel_in2>; + }; + }; + }; + }; + + stm: stm@6002000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b962>; + + reg = <0x6002000 0x1000>, + <0x09000000 0x1000000>; + reg-names = "stm-base", "stm-stimulus-base"; + + coresight-name = "coresight-stm"; + + clocks = <&clock_gcc QDSS_CLK>, + <&clock_gcc QDSS_A_CLK>; + clock-names = "apb_pclk", "core_a_clk"; + + port { + stm_out_funnel_in0: endpoint { + remote-endpoint = <&funnel_in0_in_stm>; + }; + }; + }; + + tpda: tpda@6004000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b969>; + reg = <0x6004000 0x1000>; + reg-names = "tpda-base"; + + coresight-name = "coresight-tpda"; + + qcom,tpda-atid = <65>; + qcom,bc-elem-size = <10 32>, + <13 32>; + qcom,tc-elem-size = <13 32>; + qcom,dsb-elem-size = <0 32>, + <2 32>, + <3 32>, + <5 32>, + <6 32>, + <10 32>, + <11 32>, + <13 32>; + qcom,cmb-elem-size = <3 64>, + <7 64>, + <13 64>; + + clocks = <&clock_gcc QDSS_CLK>, + <&clock_gcc QDSS_A_CLK>; + clock-names = "apb_pclk", "core_a_clk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + tpda_out_funnel_qatb: endpoint { + remote-endpoint = + <&funnel_qatb_in_tpda>; + }; + }; + + port@1 { + reg = <0>; + tpda_in_tpdm_wcss: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_wcss_out_tpda>; + }; + }; + + port@2 { + reg = <7>; + tpda_in_tpdm_dcc: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_dcc_out_tpda>; + }; + }; + + port@3 { + reg = <9>; + tpda_in_tpdm_0_north: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_0_north_out_tpda>; + }; + }; + port@4 { + reg = <10>; + tpda_in_tpdm_1_south: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_1_south_out_tpda>; + }; + }; + + port@5 { + reg = <11>; + tpda_in_tpdm_2_center: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_2_center_out_tpda>; + }; + }; + + + port@6 { + reg = <12>; + tpda_in_tpdm_3_center: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_3_center_out_tpda>; + }; + }; + }; + }; + + tpdm_0_north: tpdm@6114000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + reg = <0x6114000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-0-north"; + + clocks = <&clock_gcc QDSS_CLK>, + <&clock_gcc QDSS_A_CLK>; + clock-names = "apb_pclk", "core_a_clk"; + + qcom,msr-fix-req; + + port { + tpdm_0_north_out_tpda: endpoint { + remote-endpoint = <&tpda_in_tpdm_0_north>; + }; + }; + }; + + tpdm_1_south: tpdm@6115000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + reg = <0x6115000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-1-south"; + + clocks = <&clock_gcc QDSS_CLK>, + <&clock_gcc QDSS_A_CLK>; + clock-names = "apb_pclk", "core_a_clk"; + + qcom,msr-fix-req; + + port { + tpdm_1_south_out_tpda: endpoint { + remote-endpoint = + <&tpda_in_tpdm_1_south>; + }; + }; + }; + + + tpdm_2_center: tpdm@6116000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + reg = <0x6116000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-2-center"; + + clocks = <&clock_gcc QDSS_CLK>, + <&clock_gcc QDSS_A_CLK>; + clock-names = "apb_pclk", "core_a_clk"; + + port { + tpdm_2_center_out_tpda: endpoint { + remote-endpoint = <&tpda_in_tpdm_2_center>; + }; + }; + }; + + + tpdm_3_center: tpdm@6117000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + reg = <0x6117000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-3-center"; + + clocks = <&clock_gcc QDSS_CLK>, + <&clock_gcc QDSS_A_CLK>; + clock-names = "apb_pclk", "core_a_clk"; + + port { + tpdm_3_center_out_tpda: endpoint { + remote-endpoint = <&tpda_in_tpdm_3_center>; + }; + }; + }; + + tpdm_dcc: tpdm@6178000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + reg = <0x6178000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-dcc"; + + clocks = <&clock_gcc QDSS_CLK>, + <&clock_gcc QDSS_A_CLK>; + clock-names = "apb_pclk", "core_a_clk"; + + qcom,msr-fix-req; + + port { + tpdm_dcc_out_tpda: endpoint { + remote-endpoint = <&tpda_in_tpdm_dcc>; + }; + }; + }; + + tpdm_wcss: tpdm@1440000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + reg = <0x1440000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-wcss"; + + clocks = <&clock_gcc QDSS_CLK>, + <&clock_gcc QDSS_A_CLK>; + clock-names = "apb_pclk", "core_a_clk"; + + port { + tpdm_wcss_out_tpda: endpoint { + remote-endpoint = <&tpda_in_tpdm_wcss>; + }; + }; + }; + + funnel_qatb: funnel@6005000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b908>; + + reg = <0x6005000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-qatb"; + + clocks = <&clock_gcc QDSS_CLK>, + <&clock_gcc QDSS_A_CLK>; + clock-names = "apb_pclk", "core_a_clk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + funnel_qatb_out_funnel_in0: endpoint { + remote-endpoint = + <&funnel_in0_in_funnel_qatb>; + }; + }; + + port@1 { + reg = <1>; + funnel_qatb_in_tpda: endpoint { + slave-mode; + remote-endpoint = + <&tpda_out_funnel_qatb>; + }; + }; + }; + }; + + cti_cpu0: cti@61b8000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x61b8000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-cpu0"; + cpu = <&CPU0>; + + clocks = <&clock_gcc QDSS_CLK>, + <&clock_gcc QDSS_A_CLK>; + clock-names = "apb_pclk", "core_a_clk"; + + }; + + cti_cpu1: cti@61b9000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x61b9000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-cpu1"; + cpu = <&CPU1>; + + clocks = <&clock_gcc QDSS_CLK>, + <&clock_gcc QDSS_A_CLK>; + clock-names = "apb_pclk", "core_a_clk"; + + }; + + cti_cpu2: cti@61ba000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x61ba000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-cpu2"; + cpu = <&CPU2>; + + clocks = <&clock_gcc QDSS_CLK>, + <&clock_gcc QDSS_A_CLK>; + clock-names = "apb_pclk", "core_a_clk"; + + }; + + cti_cpu3: cti@61bb000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x61bb000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-cpu3"; + cpu = <&CPU3>; + + clocks = <&clock_gcc QDSS_CLK>, + <&clock_gcc QDSS_A_CLK>; + clock-names = "apb_pclk", "core_a_clk"; + + }; + + cti0: cti@6010000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6010000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti0"; + + clocks = <&clock_gcc QDSS_CLK>, + <&clock_gcc QDSS_A_CLK>; + clock-names = "apb_pclk", "core_a_clk"; + + }; + + cti1: cti@6011000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6011000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti1"; + + clocks = <&clock_gcc QDSS_CLK>, + <&clock_gcc QDSS_A_CLK>; + clock-names = "apb_pclk", "core_a_clk"; + + }; + + cti2: cti@6012000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6012000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti2"; + + clocks = <&clock_gcc QDSS_CLK>, + <&clock_gcc QDSS_A_CLK>; + clock-names = "apb_pclk", "core_a_clk"; + + }; + + cti3: cti@6013000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6013000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti3"; + + clocks = <&clock_gcc QDSS_CLK>, + <&clock_gcc QDSS_A_CLK>; + clock-names = "apb_pclk", "core_a_clk"; + + }; + + cti4: cti@6014000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6014000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti4"; + + clocks = <&clock_gcc QDSS_CLK>, + <&clock_gcc QDSS_A_CLK>; + clock-names = "apb_pclk", "core_a_clk"; + + }; + + cti5: cti@6015000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6015000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti5"; + + clocks = <&clock_gcc QDSS_CLK>, + <&clock_gcc QDSS_A_CLK>; + clock-names = "apb_pclk", "core_a_clk"; + + }; + + cti6: cti@6016000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6016000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti6"; + + clocks = <&clock_gcc QDSS_CLK>, + <&clock_gcc QDSS_A_CLK>; + clock-names = "apb_pclk", "core_a_clk"; + + }; + + cti7: cti@6017000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6017000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti7"; + + clocks = <&clock_gcc QDSS_CLK>, + <&clock_gcc QDSS_A_CLK>; + clock-names = "apb_pclk", "core_a_clk"; + + }; + + cti8: cti@6018000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6018000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti8"; + + clocks = <&clock_gcc QDSS_CLK>, + <&clock_gcc QDSS_A_CLK>; + clock-names = "apb_pclk", "core_a_clk"; + + }; + + cti9: cti@6019000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6019000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti9"; + + clocks = <&clock_gcc QDSS_CLK>, + <&clock_gcc QDSS_A_CLK>; + clock-names = "apb_pclk", "core_a_clk"; + + }; + + cti10: cti@601a000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x601a000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti10"; + + clocks = <&clock_gcc QDSS_CLK>, + <&clock_gcc QDSS_A_CLK>; + clock-names = "apb_pclk", "core_a_clk"; + + }; + + cti11: cti@601b000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x601b000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti11"; + + clocks = <&clock_gcc QDSS_CLK>, + <&clock_gcc QDSS_A_CLK>; + clock-names = "apb_pclk", "core_a_clk"; + + }; + + cti12: cti@601c000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x601c000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti12"; + + clocks = <&clock_gcc QDSS_CLK>, + <&clock_gcc QDSS_A_CLK>; + clock-names = "apb_pclk", "core_a_clk"; + + }; + + cti13: cti@601d000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x601d000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti13"; + + clocks = <&clock_gcc QDSS_CLK>, + <&clock_gcc QDSS_A_CLK>; + clock-names = "apb_pclk", "core_a_clk"; + + }; + + cti14: cti@601e000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x601e000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti14"; + + clocks = <&clock_gcc QDSS_CLK>, + <&clock_gcc QDSS_A_CLK>; + clock-names = "apb_pclk", "core_a_clk"; + + }; + + cti15: cti@601f000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x601f000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti15"; + + clocks = <&clock_gcc QDSS_CLK>, + <&clock_gcc QDSS_A_CLK>; + clock-names = "apb_pclk", "core_a_clk"; + + }; + + rpm_etm0 { + compatible = "qcom,coresight-remote-etm"; + + coresight-name = "coresight-rpm-etm0"; + qcom,inst-id = <4>; + + port{ + rpm_etm0_out_funnel_in0: endpoint { + remote-endpoint = + <&funnel_in0_in_rpm_etm0>; + }; + }; + }; + + turing_etm0 { + compatible = "qcom,coresight-remote-etm"; + + coresight-name = "coresight-turing-etm0"; + qcom,inst-id = <13>; + + port{ + turing_etm0_out_funnel_in2: endpoint { + remote-endpoint = + <&funnel_in2_in_turing_etm0>; + }; + }; + }; + + modem_etm0 { + compatible = "qcom,coresight-remote-etm"; + + coresight-name = "coresight-modem-etm0"; + qcom,inst-id = <2>; + + port { + modem_etm0_out_funnel_in1: endpoint { + remote-endpoint = + <&funnel_in1_in_modem_etm0>; + }; + }; + }; + + audio_etm0 { + compatible = "qcom,coresight-remote-etm"; + + coresight-name = "coresight-audio-etm0"; + qcom,inst-id = <5>; + + port { + audio_etm0_out_funnel_in1: endpoint { + remote-endpoint = + <&funnel_in1_in_audio_etm0>; + }; + }; + }; + + etm0: etm@61bc000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb95d>; + + reg = <0x61bc000 0x1000>; + cpu = <&CPU0>; + + coresight-name = "coresight-etm0"; + + clocks = <&clock_gcc QDSS_CLK>, + <&clock_gcc QDSS_A_CLK>; + clock-names = "apb_pclk", "core_a_clk"; + + port { + etm0_out_funnel_apss: endpoint { + remote-endpoint = <&funnel_apss_in_etm0>; + }; + }; + }; + + etm1: etm@61bd000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb95d>; + + reg = <0x61bd000 0x1000>; + cpu = <&CPU1>; + + coresight-name = "coresight-etm1"; + + clocks = <&clock_gcc QDSS_CLK>, + <&clock_gcc QDSS_A_CLK>; + clock-names = "apb_pclk", "core_a_clk"; + + port { + etm1_out_funnel_apss: endpoint { + remote-endpoint = <&funnel_apss_in_etm1>; + }; + }; + }; + + etm2: etm@61be000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb95d>; + + reg = <0x61be000 0x1000>; + cpu = <&CPU2>; + + coresight-name = "coresight-etm2"; + + clocks = <&clock_gcc QDSS_CLK>, + <&clock_gcc QDSS_A_CLK>; + clock-names = "apb_pclk", "core_a_clk"; + + port { + etm2_out_funnel_apss: endpoint { + remote-endpoint = <&funnel_apss_in_etm2>; + }; + }; + }; + + etm3: etm@61bf000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb95d>; + + reg = <0x61bf000 0x1000>; + cpu = <&CPU3>; + + coresight-name = "coresight-etm3"; + + clocks = <&clock_gcc QDSS_CLK>, + <&clock_gcc QDSS_A_CLK>; + clock-names = "apb_pclk", "core_a_clk"; + + port { + etm3_out_funnel_apss: endpoint { + remote-endpoint = <&funnel_apss_in_etm3>; + }; + }; + }; + + funnel_apss: funnel@61a1000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b908>; + + reg = <0x61a1000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-apss"; + + clocks = <&clock_gcc QDSS_CLK>, + <&clock_gcc QDSS_A_CLK>; + clock-names = "apb_pclk", "core_a_clk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + funnel_apss_out_funnel_in2: endpoint { + remote-endpoint = + <&funnel_in2_in_funnel_apss>; + }; + }; + port@1 { + reg = <0>; + funnel_apss_in_etm0: endpoint { + slave-mode; + remote-endpoint = + <&etm0_out_funnel_apss>; + }; + }; + + port@2 { + reg = <1>; + funnel_apss_in_etm1: endpoint { + slave-mode; + remote-endpoint = + <&etm1_out_funnel_apss>; + }; + }; + + port@3 { + reg = <2>; + funnel_apss_in_etm2: endpoint { + slave-mode; + remote-endpoint = + <&etm2_out_funnel_apss>; + }; + }; + + port@4 { + reg = <3>; + funnel_apss_in_etm3: endpoint { + slave-mode; + remote-endpoint = + <&etm3_out_funnel_apss>; + }; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/qcs405.dtsi b/arch/arm64/boot/dts/qcom/qcs405.dtsi index c9ea22a9501b..dca65e6341db 100644 --- a/arch/arm64/boot/dts/qcom/qcs405.dtsi +++ b/arch/arm64/boot/dts/qcom/qcs405.dtsi @@ -273,12 +273,12 @@ }; - dcc: dcc@b3000 { - compatible = "qcom,dcc"; - reg = <0xb3000 0x1000>, - <0xb4000 0x2000>; + dcc: dcc_v2@b2000 { + compatible = "qcom,dcc_v2"; + reg = <0x000b2000 0x1000>, + <0x000bf800 0x800>; reg-names = "dcc-base", "dcc-ram-base"; - qcom,save-reg; + dcc-ram-offset = <0x400>; }; rpm_bus: qcom,rpm-smd { @@ -670,3 +670,5 @@ &gdsc_oxili_gx { status = "ok"; }; + +#include "qcs405-coresight.dtsi" -- GitLab From f579f0cddd7603c7abc725709afbe14f92efb683 Mon Sep 17 00:00:00 2001 From: Jayant Shekhar Date: Wed, 25 Apr 2018 14:40:07 +0530 Subject: [PATCH 1563/1635] fbdev: msm: Add snapshot of display framebuffer driver This is snapshot of the framebuffer driver as of msm-4.9 tip. Change-Id: I032f8af410b5263a695bab5981f072052d6168cf Signed-off-by: Jayant Shekhar --- .../devicetree/bindings/fb/adv7533.txt | 54 + .../devicetree/bindings/fb/lt8912.txt | 20 + .../devicetree/bindings/fb/mdss-dsi-panel.txt | 122 +- .../devicetree/bindings/fb/mdss-dsi.txt | 261 + .../devicetree/bindings/fb/mdss-edp.txt | 52 + .../devicetree/bindings/fb/mdss-mdp.txt | 898 ++ .../devicetree/bindings/fb/mdss-pll.txt | 32 +- .../bindings/fb/mdss-qpic-panel.txt | 25 + .../devicetree/bindings/fb/mdss-qpic.txt | 49 + .../devicetree/bindings/fb/mdss-rotator.txt | 78 + .../devicetree/bindings/fb/msm-hdmi-tx.txt | 116 + .../devicetree/bindings/fb/mxsfb.txt | 49 + .../devicetree/bindings/fb/sm501fb.txt | 34 + drivers/video/fbdev/Kconfig | 14 + drivers/video/fbdev/Makefile | 5 + drivers/video/fbdev/core/fbmem.c | 31 +- drivers/video/fbdev/msm/Kconfig | 137 + drivers/video/fbdev/msm/Makefile | 74 + drivers/video/fbdev/msm/dsi_host_v2.c | 1889 ++++ drivers/video/fbdev/msm/dsi_host_v2.h | 178 + drivers/video/fbdev/msm/dsi_io_v2.c | 389 + drivers/video/fbdev/msm/dsi_io_v2.h | 49 + drivers/video/fbdev/msm/dsi_status_6g.c | 188 + drivers/video/fbdev/msm/dsi_status_v2.c | 167 + drivers/video/fbdev/msm/dsi_v2.c | 616 ++ drivers/video/fbdev/msm/dsi_v2.h | 56 + drivers/video/fbdev/msm/mdp3.c | 2661 ++++++ drivers/video/fbdev/msm/mdp3.h | 292 + drivers/video/fbdev/msm/mdp3_ctrl.c | 3024 +++++++ drivers/video/fbdev/msm/mdp3_ctrl.h | 95 + drivers/video/fbdev/msm/mdp3_dma.c | 1290 +++ drivers/video/fbdev/msm/mdp3_dma.h | 395 + drivers/video/fbdev/msm/mdp3_hwio.h | 361 + drivers/video/fbdev/msm/mdp3_layer.c | 348 + drivers/video/fbdev/msm/mdp3_ppp.c | 1721 ++++ drivers/video/fbdev/msm/mdp3_ppp.h | 430 + drivers/video/fbdev/msm/mdp3_ppp_data.c | 1619 ++++ drivers/video/fbdev/msm/mdp3_ppp_hwio.c | 1365 +++ drivers/video/fbdev/msm/mdss.h | 617 ++ drivers/video/fbdev/msm/mdss_cec_core.c | 799 ++ drivers/video/fbdev/msm/mdss_cec_core.h | 105 + drivers/video/fbdev/msm/mdss_compat_utils.c | 4318 ++++++++++ drivers/video/fbdev/msm/mdss_compat_utils.h | 558 ++ drivers/video/fbdev/msm/mdss_dba_utils.c | 912 ++ drivers/video/fbdev/msm/mdss_dba_utils.h | 50 + drivers/video/fbdev/msm/mdss_debug.c | 1849 ++++ drivers/video/fbdev/msm/mdss_debug.h | 258 + drivers/video/fbdev/msm/mdss_debug_frc.c | 574 ++ drivers/video/fbdev/msm/mdss_debug_xlog.c | 812 ++ drivers/video/fbdev/msm/mdss_dsi.c | 4373 ++++++++++ drivers/video/fbdev/msm/mdss_dsi.h | 904 ++ drivers/video/fbdev/msm/mdss_dsi_clk.c | 1137 +++ drivers/video/fbdev/msm/mdss_dsi_clk.h | 279 + drivers/video/fbdev/msm/mdss_dsi_cmd.c | 793 ++ drivers/video/fbdev/msm/mdss_dsi_cmd.h | 139 + drivers/video/fbdev/msm/mdss_dsi_host.c | 3257 +++++++ drivers/video/fbdev/msm/mdss_dsi_panel.c | 2942 +++++++ drivers/video/fbdev/msm/mdss_dsi_phy.c | 904 ++ drivers/video/fbdev/msm/mdss_dsi_phy.h | 90 + drivers/video/fbdev/msm/mdss_dsi_phy_12nm.c | 124 + drivers/video/fbdev/msm/mdss_dsi_status.c | 275 + drivers/video/fbdev/msm/mdss_edp.c | 1268 +++ drivers/video/fbdev/msm/mdss_edp.h | 380 + drivers/video/fbdev/msm/mdss_edp_aux.c | 1337 +++ drivers/video/fbdev/msm/mdss_fb.c | 5180 +++++++++++ drivers/video/fbdev/msm/mdss_fb.h | 481 ++ drivers/video/fbdev/msm/mdss_hdmi_audio.c | 526 ++ drivers/video/fbdev/msm/mdss_hdmi_audio.h | 72 + drivers/video/fbdev/msm/mdss_hdmi_cec.c | 504 ++ drivers/video/fbdev/msm/mdss_hdmi_cec.h | 90 + drivers/video/fbdev/msm/mdss_hdmi_edid.c | 2491 ++++++ drivers/video/fbdev/msm/mdss_hdmi_edid.h | 47 + drivers/video/fbdev/msm/mdss_hdmi_hdcp.c | 1705 ++++ drivers/video/fbdev/msm/mdss_hdmi_hdcp.h | 64 + drivers/video/fbdev/msm/mdss_hdmi_hdcp2p2.c | 1108 +++ drivers/video/fbdev/msm/mdss_hdmi_mhl.h | 27 + drivers/video/fbdev/msm/mdss_hdmi_panel.c | 932 ++ drivers/video/fbdev/msm/mdss_hdmi_panel.h | 107 + drivers/video/fbdev/msm/mdss_hdmi_tx.c | 4641 ++++++++++ drivers/video/fbdev/msm/mdss_hdmi_tx.h | 141 + drivers/video/fbdev/msm/mdss_hdmi_util.c | 1694 ++++ drivers/video/fbdev/msm/mdss_hdmi_util.h | 514 ++ drivers/video/fbdev/msm/mdss_io_util.c | 552 ++ drivers/video/fbdev/msm/mdss_mdp.c | 5281 ++++++++++++ drivers/video/fbdev/msm/mdss_mdp.h | 1987 +++++ drivers/video/fbdev/msm/mdss_mdp_cdm.c | 395 + drivers/video/fbdev/msm/mdss_mdp_cdm.h | 70 + drivers/video/fbdev/msm/mdss_mdp_ctl.c | 6121 +++++++++++++ drivers/video/fbdev/msm/mdss_mdp_debug.c | 1520 ++++ drivers/video/fbdev/msm/mdss_mdp_debug.h | 96 + drivers/video/fbdev/msm/mdss_mdp_formats.h | 504 ++ drivers/video/fbdev/msm/mdss_mdp_hwio.h | 846 ++ drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c | 3784 ++++++++ drivers/video/fbdev/msm/mdss_mdp_intf_video.c | 2242 +++++ .../video/fbdev/msm/mdss_mdp_intf_writeback.c | 919 ++ drivers/video/fbdev/msm/mdss_mdp_layer.c | 2388 ++++++ drivers/video/fbdev/msm/mdss_mdp_overlay.c | 6919 +++++++++++++++ drivers/video/fbdev/msm/mdss_mdp_pipe.c | 3139 +++++++ drivers/video/fbdev/msm/mdss_mdp_pp.c | 7607 +++++++++++++++++ drivers/video/fbdev/msm/mdss_mdp_pp.h | 237 + .../fbdev/msm/mdss_mdp_pp_cache_config.c | 1503 ++++ .../fbdev/msm/mdss_mdp_pp_cache_config.h | 51 + drivers/video/fbdev/msm/mdss_mdp_pp_common.c | 87 + drivers/video/fbdev/msm/mdss_mdp_pp_common.h | 27 + drivers/video/fbdev/msm/mdss_mdp_pp_debug.c | 857 ++ drivers/video/fbdev/msm/mdss_mdp_pp_v1_7.c | 2117 +++++ drivers/video/fbdev/msm/mdss_mdp_pp_v3.c | 824 ++ .../video/fbdev/msm/mdss_mdp_splash_logo.c | 772 ++ .../video/fbdev/msm/mdss_mdp_splash_logo.h | 46 + drivers/video/fbdev/msm/mdss_mdp_trace.h | 482 ++ drivers/video/fbdev/msm/mdss_mdp_util.c | 1322 +++ drivers/video/fbdev/msm/mdss_mdp_wfd.c | 483 ++ drivers/video/fbdev/msm/mdss_mdp_wfd.h | 63 + drivers/video/fbdev/msm/mdss_panel.c | 986 +++ drivers/video/fbdev/msm/mdss_panel.h | 1212 +++ drivers/video/fbdev/msm/mdss_qpic.c | 823 ++ drivers/video/fbdev/msm/mdss_qpic.h | 103 + drivers/video/fbdev/msm/mdss_qpic_panel.c | 305 + drivers/video/fbdev/msm/mdss_qpic_panel.h | 136 + drivers/video/fbdev/msm/mdss_rotator.c | 3025 +++++++ .../video/fbdev/msm/mdss_rotator_internal.h | 247 + drivers/video/fbdev/msm/mdss_smmu.c | 923 ++ drivers/video/fbdev/msm/mdss_smmu.h | 319 + drivers/video/fbdev/msm/mdss_sync.c | 474 + drivers/video/fbdev/msm/mdss_sync.h | 146 + drivers/video/fbdev/msm/mdss_util.c | 271 + drivers/video/fbdev/msm/mdss_wb.c | 222 + drivers/video/fbdev/msm/mdss_wb.h | 25 + drivers/video/fbdev/msm/mhl_msc.c | 729 ++ drivers/video/fbdev/msm/mhl_msc.h | 61 + drivers/video/fbdev/msm/mhl_sii8334.c | 2097 +++++ drivers/video/fbdev/msm/msm_dba/Kconfig | 24 + drivers/video/fbdev/msm/msm_dba/Makefile | 4 + drivers/video/fbdev/msm/msm_dba/adv7533.c | 2143 +++++ drivers/video/fbdev/msm/msm_dba/msm_dba.c | 151 + .../video/fbdev/msm/msm_dba/msm_dba_debug.c | 362 + .../video/fbdev/msm/msm_dba/msm_dba_helpers.c | 445 + .../video/fbdev/msm/msm_dba/msm_dba_init.c | 130 + .../fbdev/msm/msm_dba/msm_dba_internal.h | 324 + drivers/video/fbdev/msm/msm_mdss_io_8974.c | 2744 ++++++ drivers/video/fbdev/msm/qpic_panel_ili_qvga.c | 235 + drivers/video/fbdev/msm/splash.h | 5279 ++++++++++++ include/linux/fb.h | 11 +- include/linux/mdss_io_util.h | 122 + include/linux/msm_hdmi.h | 93 + include/uapi/linux/msm_mdp.h | 5 + include/uapi/linux/msm_mdp_ext.h | 30 +- include/video/msm_dba.h | 608 ++ 148 files changed, 146572 insertions(+), 45 deletions(-) create mode 100644 Documentation/devicetree/bindings/fb/adv7533.txt create mode 100644 Documentation/devicetree/bindings/fb/lt8912.txt create mode 100644 Documentation/devicetree/bindings/fb/mdss-dsi.txt create mode 100644 Documentation/devicetree/bindings/fb/mdss-edp.txt create mode 100644 Documentation/devicetree/bindings/fb/mdss-mdp.txt create mode 100644 Documentation/devicetree/bindings/fb/mdss-qpic-panel.txt create mode 100644 Documentation/devicetree/bindings/fb/mdss-qpic.txt create mode 100644 Documentation/devicetree/bindings/fb/mdss-rotator.txt create mode 100644 Documentation/devicetree/bindings/fb/msm-hdmi-tx.txt create mode 100644 Documentation/devicetree/bindings/fb/mxsfb.txt create mode 100644 Documentation/devicetree/bindings/fb/sm501fb.txt create mode 100644 drivers/video/fbdev/msm/Kconfig create mode 100644 drivers/video/fbdev/msm/Makefile create mode 100644 drivers/video/fbdev/msm/dsi_host_v2.c create mode 100644 drivers/video/fbdev/msm/dsi_host_v2.h create mode 100644 drivers/video/fbdev/msm/dsi_io_v2.c create mode 100644 drivers/video/fbdev/msm/dsi_io_v2.h create mode 100644 drivers/video/fbdev/msm/dsi_status_6g.c create mode 100644 drivers/video/fbdev/msm/dsi_status_v2.c create mode 100644 drivers/video/fbdev/msm/dsi_v2.c create mode 100644 drivers/video/fbdev/msm/dsi_v2.h create mode 100644 drivers/video/fbdev/msm/mdp3.c create mode 100644 drivers/video/fbdev/msm/mdp3.h create mode 100644 drivers/video/fbdev/msm/mdp3_ctrl.c create mode 100644 drivers/video/fbdev/msm/mdp3_ctrl.h create mode 100644 drivers/video/fbdev/msm/mdp3_dma.c create mode 100644 drivers/video/fbdev/msm/mdp3_dma.h create mode 100644 drivers/video/fbdev/msm/mdp3_hwio.h create mode 100644 drivers/video/fbdev/msm/mdp3_layer.c create mode 100644 drivers/video/fbdev/msm/mdp3_ppp.c create mode 100644 drivers/video/fbdev/msm/mdp3_ppp.h create mode 100644 drivers/video/fbdev/msm/mdp3_ppp_data.c create mode 100644 drivers/video/fbdev/msm/mdp3_ppp_hwio.c create mode 100644 drivers/video/fbdev/msm/mdss.h create mode 100644 drivers/video/fbdev/msm/mdss_cec_core.c create mode 100644 drivers/video/fbdev/msm/mdss_cec_core.h create mode 100644 drivers/video/fbdev/msm/mdss_compat_utils.c create mode 100644 drivers/video/fbdev/msm/mdss_compat_utils.h create mode 100644 drivers/video/fbdev/msm/mdss_dba_utils.c create mode 100644 drivers/video/fbdev/msm/mdss_dba_utils.h create mode 100644 drivers/video/fbdev/msm/mdss_debug.c create mode 100644 drivers/video/fbdev/msm/mdss_debug.h create mode 100644 drivers/video/fbdev/msm/mdss_debug_frc.c create mode 100644 drivers/video/fbdev/msm/mdss_debug_xlog.c create mode 100644 drivers/video/fbdev/msm/mdss_dsi.c create mode 100644 drivers/video/fbdev/msm/mdss_dsi.h create mode 100644 drivers/video/fbdev/msm/mdss_dsi_clk.c create mode 100644 drivers/video/fbdev/msm/mdss_dsi_clk.h create mode 100644 drivers/video/fbdev/msm/mdss_dsi_cmd.c create mode 100644 drivers/video/fbdev/msm/mdss_dsi_cmd.h create mode 100644 drivers/video/fbdev/msm/mdss_dsi_host.c create mode 100644 drivers/video/fbdev/msm/mdss_dsi_panel.c create mode 100644 drivers/video/fbdev/msm/mdss_dsi_phy.c create mode 100644 drivers/video/fbdev/msm/mdss_dsi_phy.h create mode 100644 drivers/video/fbdev/msm/mdss_dsi_phy_12nm.c create mode 100644 drivers/video/fbdev/msm/mdss_dsi_status.c create mode 100644 drivers/video/fbdev/msm/mdss_edp.c create mode 100644 drivers/video/fbdev/msm/mdss_edp.h create mode 100644 drivers/video/fbdev/msm/mdss_edp_aux.c create mode 100644 drivers/video/fbdev/msm/mdss_fb.c create mode 100644 drivers/video/fbdev/msm/mdss_fb.h create mode 100644 drivers/video/fbdev/msm/mdss_hdmi_audio.c create mode 100644 drivers/video/fbdev/msm/mdss_hdmi_audio.h create mode 100644 drivers/video/fbdev/msm/mdss_hdmi_cec.c create mode 100644 drivers/video/fbdev/msm/mdss_hdmi_cec.h create mode 100644 drivers/video/fbdev/msm/mdss_hdmi_edid.c create mode 100644 drivers/video/fbdev/msm/mdss_hdmi_edid.h create mode 100644 drivers/video/fbdev/msm/mdss_hdmi_hdcp.c create mode 100644 drivers/video/fbdev/msm/mdss_hdmi_hdcp.h create mode 100644 drivers/video/fbdev/msm/mdss_hdmi_hdcp2p2.c create mode 100644 drivers/video/fbdev/msm/mdss_hdmi_mhl.h create mode 100644 drivers/video/fbdev/msm/mdss_hdmi_panel.c create mode 100644 drivers/video/fbdev/msm/mdss_hdmi_panel.h create mode 100644 drivers/video/fbdev/msm/mdss_hdmi_tx.c create mode 100644 drivers/video/fbdev/msm/mdss_hdmi_tx.h create mode 100644 drivers/video/fbdev/msm/mdss_hdmi_util.c create mode 100644 drivers/video/fbdev/msm/mdss_hdmi_util.h create mode 100644 drivers/video/fbdev/msm/mdss_io_util.c create mode 100644 drivers/video/fbdev/msm/mdss_mdp.c create mode 100644 drivers/video/fbdev/msm/mdss_mdp.h create mode 100644 drivers/video/fbdev/msm/mdss_mdp_cdm.c create mode 100644 drivers/video/fbdev/msm/mdss_mdp_cdm.h create mode 100644 drivers/video/fbdev/msm/mdss_mdp_ctl.c create mode 100644 drivers/video/fbdev/msm/mdss_mdp_debug.c create mode 100644 drivers/video/fbdev/msm/mdss_mdp_debug.h create mode 100644 drivers/video/fbdev/msm/mdss_mdp_formats.h create mode 100644 drivers/video/fbdev/msm/mdss_mdp_hwio.h create mode 100644 drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c create mode 100644 drivers/video/fbdev/msm/mdss_mdp_intf_video.c create mode 100644 drivers/video/fbdev/msm/mdss_mdp_intf_writeback.c create mode 100644 drivers/video/fbdev/msm/mdss_mdp_layer.c create mode 100644 drivers/video/fbdev/msm/mdss_mdp_overlay.c create mode 100644 drivers/video/fbdev/msm/mdss_mdp_pipe.c create mode 100644 drivers/video/fbdev/msm/mdss_mdp_pp.c create mode 100644 drivers/video/fbdev/msm/mdss_mdp_pp.h create mode 100644 drivers/video/fbdev/msm/mdss_mdp_pp_cache_config.c create mode 100644 drivers/video/fbdev/msm/mdss_mdp_pp_cache_config.h create mode 100644 drivers/video/fbdev/msm/mdss_mdp_pp_common.c create mode 100644 drivers/video/fbdev/msm/mdss_mdp_pp_common.h create mode 100644 drivers/video/fbdev/msm/mdss_mdp_pp_debug.c create mode 100644 drivers/video/fbdev/msm/mdss_mdp_pp_v1_7.c create mode 100644 drivers/video/fbdev/msm/mdss_mdp_pp_v3.c create mode 100644 drivers/video/fbdev/msm/mdss_mdp_splash_logo.c create mode 100644 drivers/video/fbdev/msm/mdss_mdp_splash_logo.h create mode 100644 drivers/video/fbdev/msm/mdss_mdp_trace.h create mode 100644 drivers/video/fbdev/msm/mdss_mdp_util.c create mode 100644 drivers/video/fbdev/msm/mdss_mdp_wfd.c create mode 100644 drivers/video/fbdev/msm/mdss_mdp_wfd.h create mode 100644 drivers/video/fbdev/msm/mdss_panel.c create mode 100644 drivers/video/fbdev/msm/mdss_panel.h create mode 100644 drivers/video/fbdev/msm/mdss_qpic.c create mode 100644 drivers/video/fbdev/msm/mdss_qpic.h create mode 100644 drivers/video/fbdev/msm/mdss_qpic_panel.c create mode 100644 drivers/video/fbdev/msm/mdss_qpic_panel.h create mode 100644 drivers/video/fbdev/msm/mdss_rotator.c create mode 100644 drivers/video/fbdev/msm/mdss_rotator_internal.h create mode 100644 drivers/video/fbdev/msm/mdss_smmu.c create mode 100644 drivers/video/fbdev/msm/mdss_smmu.h create mode 100644 drivers/video/fbdev/msm/mdss_sync.c create mode 100644 drivers/video/fbdev/msm/mdss_sync.h create mode 100644 drivers/video/fbdev/msm/mdss_util.c create mode 100644 drivers/video/fbdev/msm/mdss_wb.c create mode 100644 drivers/video/fbdev/msm/mdss_wb.h create mode 100644 drivers/video/fbdev/msm/mhl_msc.c create mode 100644 drivers/video/fbdev/msm/mhl_msc.h create mode 100644 drivers/video/fbdev/msm/mhl_sii8334.c create mode 100644 drivers/video/fbdev/msm/msm_dba/Kconfig create mode 100644 drivers/video/fbdev/msm/msm_dba/Makefile create mode 100644 drivers/video/fbdev/msm/msm_dba/adv7533.c create mode 100644 drivers/video/fbdev/msm/msm_dba/msm_dba.c create mode 100644 drivers/video/fbdev/msm/msm_dba/msm_dba_debug.c create mode 100644 drivers/video/fbdev/msm/msm_dba/msm_dba_helpers.c create mode 100644 drivers/video/fbdev/msm/msm_dba/msm_dba_init.c create mode 100644 drivers/video/fbdev/msm/msm_dba/msm_dba_internal.h create mode 100644 drivers/video/fbdev/msm/msm_mdss_io_8974.c create mode 100644 drivers/video/fbdev/msm/qpic_panel_ili_qvga.c create mode 100644 drivers/video/fbdev/msm/splash.h create mode 100644 include/linux/mdss_io_util.h create mode 100644 include/linux/msm_hdmi.h create mode 100644 include/video/msm_dba.h diff --git a/Documentation/devicetree/bindings/fb/adv7533.txt b/Documentation/devicetree/bindings/fb/adv7533.txt new file mode 100644 index 000000000000..b198f37f8fc6 --- /dev/null +++ b/Documentation/devicetree/bindings/fb/adv7533.txt @@ -0,0 +1,54 @@ +ADV7533 DSI to HDMI bridge + + +Required properties: +- compatible: Must be "adv7533" +- reg: Main I2C slave ID (for I2C host driver) +- adi,video-mode: Excepted a number and possible inputs are 0 to 3, while: + 3 = 1080p + 2 = 720p + 1 = 480p + 0 = 1080p pattern +- adi,main-addr: Main I2C slave ID +- adi,cec-dsi-addr: CEC DSI I2C slave ID + +Optional properties: +- adi,enable-audio: +- adi,disable-gpios: +- adi,irq-gpio: Main IRQ gpio mapping +- adi,hpd-irq-gpio: HPD IRQ gpio mapping +- adi,switch-gpio: DSI switch gpio mapping +- qcom,supply-names: Regulator names that supply 5v to bridge chip +- qcom,min-voltage-level Minimum voltage level to be supplied to bridge chip +- qcom,max-voltage-level Maximum voltage level to be supplied to bridge chip +- qcom,enable-load Load current to bridge chip when enabled +- qcom,disable-load Load current to bridge chip when disabled +- qcom,post-on-sleep Sleep time (ms) to indicate the sleep + time after the vreg is enabled + +Example: +&soc { + i2c@78b8000 { + adv7533@39 { + compatible = "adv7533"; + reg = <0x39>; + adi,video-mode = <3>; /* 3 = 1080p */ + adi,main-addr = <0x39>; + adi,cec-dsi-addr = <0x3C>; + adi,enable-audio; + pinctrl-names = "pmx_adv7533_active","pmx_adv7533_suspend"; + pinctrl-0 = <&adv7533_int_active &adv7533_hpd_int_active &adv7533_switch_active>; + pinctrl-1 = <&adv7533_int_suspend &adv7533_hpd_int_suspend &adv7533_switch_suspend>; + adi,irq-gpio = <&msm_gpio 31 0x2002>; + adi,hpd-irq-gpio = <&msm_gpio 20 0x2003>; + adi,switch-gpio = <&msm_gpio 32 0x0>; + hpd-5v-en-supply = <&adv_vreg>; + qcom,supply-names = "hpd-5v-en"; + qcom,min-voltage-level = <0>; + qcom,max-voltage-level = <0>; + qcom,enable-load = <0>; + qcom,disable-load = <0>; + qcom,post-on-sleep = <10>; + }; + }; +}; diff --git a/Documentation/devicetree/bindings/fb/lt8912.txt b/Documentation/devicetree/bindings/fb/lt8912.txt new file mode 100644 index 000000000000..daeb15fe3ab5 --- /dev/null +++ b/Documentation/devicetree/bindings/fb/lt8912.txt @@ -0,0 +1,20 @@ +LT8912 DSI to HDMI bridge + + +Required properties: +- compatible: Must be "lontium,lt8912" +- reg: Main I2C slave ID (for I2C host driver) + +Optional properties: +- qcom,hdmi-reset: Main reset gpio mapping + +Example: +&soc { + i2c@78b8000 { + lt8912@48 { + compatible = "lontium,lt8912"; + reg = <0x48>; + qcom,hdmi-reset = <&tlmm 64 0x0>; + }; + }; +}; diff --git a/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt b/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt index 608b4260a0ab..78566c9b9b36 100644 --- a/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt +++ b/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt @@ -1,4 +1,4 @@ -Qualcomm mdss-dsi-panel +Qualcomm Technologies, Inc. mdss-dsi-panel mdss-dsi-panel is a dsi panel device which supports panels that are compatible with MIPI display serial interface specification. @@ -12,6 +12,7 @@ Required properties: This property specifies the version for DSI HW that this panel will work with "qcom,dsi-panel-v2" = DSI V2.0 + "qcom,msm-dsi-v2" = DSI V2.0 - status: This property applies to DSI V2 panels only. This property should not be added for panels that work based on version "V6.0" @@ -37,8 +38,10 @@ Required properties: "display_2" = DISPLAY_2 - qcom,mdss-dsi-panel-timings: An array of length 12 that specifies the PHY timing settings for the panel. -- qcom,mdss-dsi-panel-timings-8996: An array of length 40 char that specifies the 8996 PHY lane - timing settings for the panel. +- qcom,mdss-dsi-panel-timings-phy-v2: An array of length 40 char that specifies the PHY version 2 + lane timing settings for the panel. +- qcom,mdss-dsi-panel-timings-phy-12nm: An array of length 8 char that specifies the 12nm DSI PHY + lane timing settings for the panel. - qcom,mdss-dsi-on-command: A byte stream formed by multiple dcs packets base on qcom dsi controller protocol. byte 0: dcs data type @@ -61,9 +64,39 @@ Required properties: transmitted byte 5, 6: 16 bits length in network byte order byte 7 and beyond: number byte of payload +- qcom,mdss-dsi-lp-mode-on: This is used to enable display low persistence mode. + A byte stream formed by multiple dcs packets base on + qcom dsi controller protocol. + byte 0: dcs data type + byte 1: set to indicate this is an individual packet + (no chain) + byte 2: virtual channel number + byte 3: expect ack from client (dcs read command) + byte 4: wait number of specified ms after dcs command + transmitted + byte 5, 6: 16 bits length in network byte order + byte 7 and beyond: number byte of payload +- qcom,mdss-dsi-lp-mode-off: This is used to disable display low persistence mode. + A byte stream formed by multiple dcs packets base on + qcom dsi controller protocol. + byte 0: dcs data type + byte 1: set to indicate this is an individual packet + (no chain) + byte 2: virtual channel number + byte 3: expect ack from client (dcs read command) + byte 4: wait number of specified ms after dcs command + transmitted + byte 5, 6: 16 bits length in network byte order + byte 7 and beyond: number byte of payload - qcom,mdss-dsi-post-panel-on-command: same as "qcom,mdss-dsi-on-command" except commands are sent after displaying an image. +- qcom,mdss-dsi-idle-on-command: same as "qcom,mdss-dsi-on-command". Set of DCS command + used for idle mode entry. + +- qcom,mdss-dsi-idle-off-command: same as "qcom,mdss-dsi-on-command". Set of DCS command + used for idle mode exit. + Note, if a short DCS packet(i.e packet with Byte 0:dcs data type as 05) mentioned in qcom,mdss-dsi-on-command/qcom,mdss-dsi-off-command stream fails to transmit, then 3 options can be tried. @@ -248,6 +281,35 @@ Optional properties: 60 = 60 frames per second (default) - qcom,mdss-dsi-panel-clockrate: A 64 bit value specifies the panel clock speed in Hz. 0 = default value. +- qcom,mdss-mdp-kickoff-threshold: This property can be used to define a region + (in terms of scanlines) where the +hardware is allowed + to trigger a data transfer from MDP to DSI. + If this property is used, the region must be defined setting + two values, the low and the high thresholds: + + Where following condition must be met: + low_threshold < high_threshold + These values will be used by the driver in such way that if + the Driver receives a request to kickoff a transfer (MDP to DSI), + the transfer will be triggered only if the following condition + is satisfied: + low_threshold < scanline < high_threshold + If the condition is not met, then the driver will delay the + transfer by the time defined in the following property: + "qcom,mdss-mdp-kickoff-delay". + So in order to use this property, the delay property must + be defined as well and greater than 0. +- qcom,mdss-mdp-kickoff-delay: This property defines the delay in microseconds that + the driver will delay before triggering an MDP transfer if the + thresholds defined by the following property are not met: + "qcom,mdss-mdp-kickoff-threshold". + So in order to use this property, the threshold property must + be defined as well. Note that this delay cannot be zero + and also should not be greater than +the fps window. + i.e. For 60fps value should not exceed +16666 uS. - qcom,mdss-mdp-transfer-time-us: Specifies the dsi transfer time for command mode panels in microseconds. Driver uses this number to adjust the clock rate according to the expected transfer time. @@ -275,14 +337,10 @@ Optional properties: to the physical width in the framebuffer information. - qcom,mdss-pan-physical-height-dimension: Specifies panel physical height in mm which corresponds to the physical height in the framebuffer information. -- qcom,mdss-dsi-mode-sel-gpio-state: String that specifies the lcd mode for panel - (such as single-port/dual-port), if qcom,panel-mode-gpio - binding is defined in dsi controller. - "dual_port" = Set GPIO to LOW - "single_port" = Set GPIO to HIGH +- qcom,mdss-dsi-panel-mode-gpio-state: String that specifies the mode state for panel if it is defined + in dsi controller. "high" = Set GPIO to HIGH "low" = Set GPIO to LOW - The default value is "dual_port". - qcom,mdss-tear-check-disable: Boolean to disable mdp tear check. Tear check is enabled by default to avoid tearing. Other tear-check properties are ignored if this property is present. The below tear check configuration properties can be individually tuned if @@ -330,6 +388,28 @@ Optional properties: 2A/2B command. - qcom,dcs-cmd-by-left: Boolean to indicate that dcs command are sent through the left DSI controller only in a dual-dsi configuration +- qcom,mdss-dsi-panel-hdr-enabled: Boolean to indicate HDR support in panel. +- qcom,mdss-dsi-panel-hdr-color-primaries: + Array of 8 unsigned integers denoting chromaticity of panel.These + values are specified in nits units. The value range is 0 through 50000. + To obtain real chromacity, these values should be divided by factor of + 50000. The structure of array is defined in below order + value 1: x value of white chromaticity of display panel + value 2: y value of white chromaticity of display panel + value 3: x value of red chromaticity of display panel + value 4: y value of red chromaticity of display panel + value 5: x value of green chromaticity of display panel + value 6: y value of green chromaticity of display panel + value 7: x value of blue chromaticity of display panel + value 8: y value of blue chromaticity of display panel +- qcom,mdss-dsi-panel-peak-brightness: Maximum brightness supported by panel.In absence of maximum value + typical value becomes peak brightness. Value is specified in nits units. + To obtail real peak brightness, this value should be divided by factor of + 10000. +- qcom,mdss-dsi-panel-blackness-level: Blackness level supported by panel. Blackness level is defined as + ratio of peak brightness to contrast. Value is specified in nits units. + To obtail real blackness level, this value should be divided by factor of + 10000. - qcom,mdss-dsi-lp11-init: Boolean used to enable the DSI clocks and data lanes (low power 11) before issuing hardware reset line. - qcom,mdss-dsi-init-delay-us: Delay in microseconds(us) before performing any DSI activity in lp11 @@ -424,7 +504,11 @@ Optional properties: fields in the supply entry, refer to the qcom,ctrl-supply-entries binding above. - qcom,config-select: Optional property to select default configuration. - +- qcom,panel-allow-phy-poweroff: A boolean property indicates that panel allows to turn off the phy power + supply during idle screen. A panel should able to handle the dsi lanes + in floating state(not LP00 or LP11) to turn on this property. Software + turns off PHY pmic power supply, phy ldo and DSI Lane ldo during + idle screen (footswitch control off) when this property is enabled. [[Optional config sub-nodes]] These subnodes provide different configurations for a given same panel. Default configuration can be chosen by specifying phandle of the selected subnode in the qcom,config-select. @@ -471,6 +555,7 @@ Optional properites: to a non-DSI interface. - qcom,bridge-name: A string to indicate the name of the bridge chip connected to DSI. qcom,bridge-name is required if qcom,dba-panel is defined for the panel. +- qcom,hdmi-mode: Indicates where current panel is HDMI mode, otherwise, it will be DVI mode. - qcom,adjust-timer-wakeup-ms: An integer value to indicate the timer delay(in ms) to accommodate s/w delay while configuring the event timer wakeup logic. @@ -493,6 +578,8 @@ Additional properties added to the second level nodes that represent timings pro Note, if a given optional qcom,* binding is not present, then the driver will configure the default values specified. +Note, all the "qcom,supply-*" properties have their definitions in mdss-dsi-txt. + Example: &mdss_mdp { dsi_sim_vid: qcom,mdss_dsi_sim_video { @@ -538,7 +625,6 @@ Example: qcom,mdss-dsi-underflow-color = <0xff>; qcom,mdss-dsi-bl-min-level = <1>; qcom,mdss-dsi-bl-max-level = < 15>; - qcom,mdss-brightness-max-level = <255>; qcom,mdss-dsi-interleave-mode = <0>; qcom,mdss-dsi-panel-type = "dsi_video_mode"; qcom,mdss-dsi-te-check-enable; @@ -568,19 +654,26 @@ Example: qcom,mdss-dsi-dma-trigger = <0>; qcom,mdss-dsi-panel-framerate = <60>; qcom,mdss-dsi-panel-clockrate = <424000000>; + qcom,mdss-mdp-kickoff-threshold = <11 2430>; + qcom,mdss-mdp-kickoff-delay = <1000>; qcom,mdss-mdp-transfer-time-us = <12500>; qcom,mdss-dsi-panel-timings = [7d 25 1d 00 37 33 22 27 1e 03 04 00]; - qcom,mdss-dsi-panel-timings-8996 = [23 20 06 09 05 03 04 a0 + qcom,mdss-dsi-panel-timings-phy-v2 = [23 20 06 09 05 03 04 a0 23 20 06 09 05 03 04 a0 23 20 06 09 05 03 04 a0 23 20 06 09 05 03 04 a0 23 2e 06 08 05 03 04 a0]; + qcom,mdss-dsi-panel-timings-phy-12nm = + [a9 4e 56 0b 8a 4d 0b d6]; qcom,mdss-dsi-on-command = [32 01 00 00 00 00 02 00 00 29 01 00 00 10 00 02 FF 99]; qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; qcom,mdss-dsi-off-command = [22 01 00 00 00 00 00]; qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-lp-mode-on = [32 01 00 00 00 00 02 00 00 + 29 01 00 00 10 00 02 FF 99]; + qcom,mdss-dsi-lp-mode-off = [22 01 00 00 00 00 00]; qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; qcom,mdss-dsi-pan-enable-dynamic-fps; qcom,mdss-dsi-pan-fps-update = "dfps_suspend_resume_mode"; @@ -592,7 +685,7 @@ Example: qcom,5v-boost-gpio = <&pm8994_gpios 14 0>; qcom,mdss-pan-physical-width-dimension = <60>; qcom,mdss-pan-physical-height-dimension = <140>; - qcom,mdss-dsi-mode-sel-gpio-state = "dsc_mode"; + qcom,mdss-dsi-panel-mode-gpio-state = "low"; qcom,mdss-tear-check-sync-cfg-height = <0xfff0>; qcom,mdss-tear-check-sync-init-val = <1280>; qcom,mdss-tear-check-sync-threshold-start = <4>; @@ -611,6 +704,7 @@ Example: qcom,suspend-ulps-enabled; qcom,panel-roi-alignment = <4 4 2 2 20 20>; qcom,esd-check-enabled; + qcom,panel-allow-phy-poweroff; qcom,mdss-dsi-panel-status-command = [06 01 00 01 05 00 02 0A 08]; qcom,mdss-dsi-panel-status-command-state = "dsi_lp_mode"; qcom,mdss-dsi-panel-status-check-mode = "reg_read"; @@ -682,6 +776,7 @@ Example: qcom,supply-max-voltage = <2800000>; qcom,supply-enable-load = <100000>; qcom,supply-disable-load = <100>; + qcom,supply-ulp-load = <100>; qcom,supply-pre-on-sleep = <0>; qcom,supply-post-on-sleep = <0>; qcom,supply-pre-off-sleep = <0>; @@ -695,6 +790,7 @@ Example: qcom,supply-max-voltage = <1800000>; qcom,supply-enable-load = <100000>; qcom,supply-disable-load = <100>; + qcom,supply-ulp-load = <100>; qcom,supply-pre-on-sleep = <0>; qcom,supply-post-on-sleep = <0>; qcom,supply-pre-off-sleep = <0>; diff --git a/Documentation/devicetree/bindings/fb/mdss-dsi.txt b/Documentation/devicetree/bindings/fb/mdss-dsi.txt new file mode 100644 index 000000000000..8b593a97ef0d --- /dev/null +++ b/Documentation/devicetree/bindings/fb/mdss-dsi.txt @@ -0,0 +1,261 @@ +Qualcomm Technologies, Inc. mdss-dsi + +mdss-dsi is the master DSI device which supports multiple DSI host controllers that +are compatible with MIPI display serial interface specification. + +Required properties: +- compatible: Must be "qcom,mdss-dsi" +- hw-config: Specifies the DSI host setup configuration + "hw-config" = "single_dsi" + "hw-config" = "dual_dsi" + "hw-config" = "split_dsi" +- ranges: The standard property which specifies the child address + space, parent address space and the length. +- vdda-supply: Phandle for vreg regulator device node. + +Bus Scaling Data: +- qcom,msm-bus,name: String property describing MDSS client. +- qcom, msm-bus,num-cases: This is the number of bus scaling use cases + defined in the vectors property. This must be + set to <2> for MDSS DSI driver where use-case 0 + is used to remove BW votes from the system. Use + case 1 is used to generate bandwidth requestes + when sending command packets. +- qcom,msm-bus,num-paths: This represents number of paths in each bus + scaling usecase. This value depends on number of + AXI master ports dedicated to MDSS for + particular chipset. +- qcom,msm-bus,vectors-KBps: A series of 4 cell properties, with a format + of (src, dst, ab, ib) which is defined at + Documentation/devicetree/bindings/arm/msm/msm_bus.txt. + DSI driver should always set average bandwidth + (ab) to 0 and always use instantaneous + bandwidth(ib) values. + +Optional properties: +- vcca-supply: Phandle for vcca regulator device node. +- qcom,-supply-entries: A node that lists the elements of the supply used by the + a particular "type" of DSI modulee. The module "types" + can be "core", "ctrl", and "phy". Within the same type, + there can be more than one instance of this binding, + in which case the entry would be appended with the + supply entry index. + e.g. qcom,ctrl-supply-entry@0 + -- qcom,supply-name: name of the supply (vdd/vdda/vddio) + -- qcom,supply-min-voltage: minimum voltage level (uV) + -- qcom,supply-max-voltage: maximum voltage level (uV) + -- qcom,supply-enable-load: load drawn (uA) from enabled supply + -- qcom,supply-disable-load: load drawn (uA) from disabled supply + -- qcom,supply-ulp-load: load drawn (uA) from supply in ultra-low power mode + -- qcom,supply-pre-on-sleep: time to sleep (ms) before turning on + -- qcom,supply-post-on-sleep: time to sleep (ms) after turning on + -- qcom,supply-pre-off-sleep: time to sleep (ms) before turning off + -- qcom,supply-post-off-sleep: time to sleep (ms) after turning off +- pll-src-config Specified the source PLL for the DSI + link clocks: + "PLL0" - Clocks sourced out of DSI PLL0 + "PLL1" - Clocks sourced out of DSI PLL1 + This property is only valid for + certain DSI hardware configurations + mentioned in the "hw-config" binding above. + For example, in split_dsi config, the clocks can + only be sourced out of PLL0. For + dual_dsi, both PLL would be active. + For single DSI, it is possible to + select either PLL. If no value is specified, + the default value for single DSI is set as PLL0. +- qcom,mmss-ulp-clamp-ctrl-offset: Specifies the offset for dsi ulps clamp control register. +- qcom,mmss-phyreset-ctrl-offset: Specifies the offset for dsi phy reset control register. +- qcom,dsi-clk-ln-recovery: Boolean which enables the clk lane recovery + +mdss-dsi-ctrl is a dsi controller device which is treated as a subnode of the mdss-dsi device. + +Required properties: +- compatible: Must be "qcom,mdss-dsi-ctrl" +- cell-index: Specifies the controller used among the two controllers. +- reg: Base address and length of the different register + regions(s) required for DSI device functionality. +- reg-names: A list of strings that map in order to the list of regs. + "dsi_ctrl" - MDSS DSI controller register region + "dsi_phy" - MDSS DSI PHY register region + "dsi_phy_regulator" - MDSS DSI PHY REGULATOR region + "mmss_misc_phys" - Register region for MMSS DSI clamps +- vdd-supply: Phandle for vdd regulator device node. +- vddio-supply: Phandle for vdd-io regulator device node. +- qcom,mdss-fb-map-prim: pHandle that specifies the framebuffer to which the + primary interface is mapped. +- qcom,mdss-mdp: pHandle that specifies the mdss-mdp device. +- qcom,platform-regulator-settings: An array of length 7 or 5 that specifies the PHY + regulator settings. It use 5 bytes for 8996 pll. +- qcom,platform-strength-ctrl: An array of length 2 or 10 that specifies the PHY + strengthCtrl settings. It use 10 bytes for 8996 pll. +- qcom,platform-lane-config: An array of length 45 or 20 that specifies the PHY + lane configuration settings. It use 20 bytes for 8996 pll. +- qcom,platform-bist-ctrl: An array of length 6 that specifies the PHY + BIST ctrl settings. +- qcom,dsi-pref-prim-pan: phandle that specifies the primary panel to be used + with the controller. + +Optional properties: +- label: A string used to describe the controller used. +- qcom,mdss-fb-map: pHandle that specifies the framebuffer to which the + interface is mapped. +- qcom,mdss-fb-map-sec: pHandle that specifies the framebuffer to which the + secondary interface is mapped. +- qcom,platform-enable-gpio: Specifies the panel lcd/display enable gpio. +- qcom,platform-reset-gpio: Specifies the panel reset gpio. +- qcom,platform-te-gpio: Specifies the gpio used for TE. +- qcom,platform-bklight-en-gpio: Specifies the gpio used to enable display back-light +- qcom,platform-mode-gpio: Select video/command mode of panel through gpio when it supports + both modes. +- qcom,platform-intf-mux-gpio: Select dsi/external(hdmi) interface through gpio when it supports + either dsi or external interface. +- pinctrl-names: List of names to assign mdss pin states defined in pinctrl device node + Refer to pinctrl-bindings.txt +- pinctrl-<0..n>: Lists phandles each pointing to the pin configuration node within a pin + controller. These pin configurations are installed in the pinctrl + device node. Refer to pinctrl-bindings.txt +- qcom,regulator-ldo-mode: Boolean to enable ldo mode for the dsi phy regulator +- qcom,null-insertion-enabled: Boolean to enable NULL packet insertion + feature for DSI controller. +- qcom,dsi-irq-line: Boolean specifies if DSI has a different irq line than mdp. +- qcom,lane-map: Specifies the data lane swap configuration. + "lane_map_0123" = <0 1 2 3> (default value) + "lane_map_3012" = <3 0 1 2> + "lane_map_2301" = <2 3 0 1> + "lane_map_1230" = <1 2 3 0> + "lane_map_0321" = <0 3 2 1> + "lane_map_1032" = <1 0 3 2> + "lane_map_2103" = <2 1 0 3> + "lane_map_3210" = <3 2 1 0> +- qcom,pluggable Boolean to enable hotplug feature. +- qcom,timing-db-mode: Boolean specifies dsi timing mode registers are supported or not. +- qcom,display-id A string indicates the display ID for the controller. + The possible values are: + - "primary" + - "secondary" + - "tertiary" +- qcom,bridge-index: Instance id of the bridge chip connected to DSI. qcom,bridge-index is + required if a bridge chip panel is used. + +Example: + mdss_dsi: qcom,mdss_dsi@0 { + compatible = "qcom,mdss-dsi"; + hw-config = "single_dsi"; + pll-src-config = "PLL0"; + #address-cells = <1>; + #size-cells = <1>; + vdda-supply = <&pm8226_l4>; + vcca-supply = <&pm8226_l28>; + reg = <0x1a98000 0x1a98000 0x25c + 0x1a98500 0x1a98500 0x280 + 0x1a98780 0x1a98780 0x30 + 0x193e000 0x193e000 0x30>; + + qcom,dsi-clk-ln-recovery; + + qcom,core-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + + qcom,core-supply-entry@0 { + reg = <0>; + qcom,supply-name = "gdsc"; + qcom,supply-min-voltage = <0>; + qcom,supply-max-voltage = <0>; + qcom,supply-enable-load = <0>; + qcom,supply-disable-load = <0>; + qcom,supply-ulp-load = <0>; + qcom,supply-pre-on-sleep = <0>; + qcom,supply-post-on-sleep = <0>; + qcom,supply-pre-off-sleep = <0>; + qcom,supply-post-off-sleep = <0>; + }; + }; + + qcom,phy-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + + qcom,phy-supply-entry@0 { + reg = <0>; + qcom,supply-name = "vddio"; + qcom,supply-min-voltage = <1800000>; + qcom,supply-max-voltage = <1800000>; + qcom,supply-enable-load = <100000>; + qcom,supply-disable-load = <100>; + qcom,supply-ulp-load = <100>; + qcom,supply-pre-on-sleep = <0>; + qcom,supply-post-on-sleep = <20>; + qcom,supply-pre-off-sleep = <0>; + qcom,supply-post-off-sleep = <0>; + }; + }; + + qcom,ctrl-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + + qcom,ctrl-supply-entry@0 { + reg = <0>; + qcom,supply-name = "vdda"; + qcom,supply-min-voltage = <1200000>; + qcom,supply-max-voltage = <1200000>; + qcom,supply-enable-load = <100000>; + qcom,supply-disable-load = <100>; + qcom,supply-ulp-load = <1000>; + qcom,supply-pre-on-sleep = <0>; + qcom,supply-post-on-sleep = <20>; + qcom,supply-pre-off-sleep = <0>; + qcom,supply-post-off-sleep = <0>; + }; + }; + + mdss_dsi0: mdss_dsi_ctrl0@fd922800 { + compatible = "qcom,mdss-dsi-ctrl"; + label = "MDSS DSI CTRL->0"; + cell-index = <0>; + reg = <0xfd922800 0x1f8>, + <0xfd922b00 0x2b0>, + <0xfd998780 0x30>, + <0xfd828000 0x108>; + reg-names = "dsi_ctrl", "dsi_phy", + "dsi_phy_regulator", "mmss_misc_phys"; + + vdd-supply = <&pm8226_l15>; + vddio-supply = <&pm8226_l8>; + qcom,mdss-fb-map-prim = <&mdss_fb0>; + qcom,mdss-mdp = <&mdss_mdp>; + + qcom,dsi-pref-prim-pan = <&dsi_tosh_720_vid>; + + qcom,platform-strength-ctrl = [ff 06]; + qcom,platform-bist-ctrl = [00 00 b1 ff 00 00]; + qcom,platform-regulator-settings = [07 09 03 00 20 00 01]; + qcom,platform-lane-config = [00 00 00 00 00 00 00 01 97 + 00 00 00 00 05 00 00 01 97 + 00 00 00 00 0a 00 00 01 97 + 00 00 00 00 0f 00 00 01 97 + 00 c0 00 00 00 00 00 01 bb]; + + qcom,mmss-ulp-clamp-ctrl-offset = <0x20>; + qcom,mmss-phyreset-ctrl-offset = <0x24>; + qcom,regulator-ldo-mode; + qcom,null-insertion-enabled; + qcom,timing-db-mode; + + pinctrl-names = "mdss_default", "mdss_sleep"; + pinctrl-0 = <&mdss_dsi_active>; + pinctrl-1 = <&mdss_dsi_suspend>; + qcom,platform-reset-gpio = <&msmgpio 25 1>; + qcom,platform-te-gpio = <&msmgpio 24 0>; + qcom,platform-enable-gpio = <&msmgpio 58 1>; + qcom,platform-bklight-en-gpio = <&msmgpio 86 0>; + qcom,platform-mode-gpio = <&msmgpio 7 0>; + qcom,platform-intf-mux-gpio = <&tlmm 115 0>; + qcom,dsi-irq-line; + qcom,lane-map = "lane_map_3012"; + qcom,display-id = "primary"; + qcom,bridge-index = <00>; + }; + }; diff --git a/Documentation/devicetree/bindings/fb/mdss-edp.txt b/Documentation/devicetree/bindings/fb/mdss-edp.txt new file mode 100644 index 000000000000..3d649e5a6a0e --- /dev/null +++ b/Documentation/devicetree/bindings/fb/mdss-edp.txt @@ -0,0 +1,52 @@ +Qualcomm Technologies, Inc. MDSS EDP + +MDSS EDP is a edp driver which supports panels that are compatible with +VESA EDP display interface specification. + +When configuring the optional properties for external backlight, one should also +configure the gpio that drives the pwm to it. + +Required properties +- compatible : Must be "qcom,mdss-edp". +- reg : Offset and length of the register set for the + device. +- reg-names : Names to refer to register sets related to this + device +- vdda-supply : Phandle for vdd regulator device node. +- gpio-panel-en : GPIO for supplying power to panel and backlight + driver. +- gpio-lvl-en : GPIO to enable HPD be received by host. +- status : A string that has to be set to "okay/ok" to enable + the driver. By default this property will be set to + "disable". Will be set to "ok/okay" status for + specific platforms. +- qcom,mdss-fb-map: pHandle that specifies the framebuffer to which the + interface is mapped. +- gpio-panel-hpd : gpio pin use for edp hpd + +Optional properties +- qcom,panel-lpg-channel : LPG channel for backlight. +- qcom,panel-pwm-period : PWM period in microseconds. + + +Optional properties: +- qcom,mdss-brightness-max-level: Specifies the max brightness level supported. + 255 = default value. + +Example: + mdss_edp: qcom,mdss_edp@fd923400 { + compatible = "qcom,mdss-edp"; + reg = <0xfd923400 0x700>, + <0xfd8c2000 0x1000>; + reg-names = "edp_base", "mmss_cc_base"; + vdda-supply = <&pm8941_l12>; + gpio-panel-en = <&msmgpio 58 0>; + gpio-lvl-en = <&msmgpio 91 0>; + qcom,panel-lpg-channel = <7>; /* LPG Channel 8 */ + qcom,panel-pwm-period = <53>; + status = "disable"; + qcom,mdss-fb-map = <&mdss_fb0>; + gpio-panel-hpd = <&msmgpio 102 0>; + }; + + diff --git a/Documentation/devicetree/bindings/fb/mdss-mdp.txt b/Documentation/devicetree/bindings/fb/mdss-mdp.txt new file mode 100644 index 000000000000..5624321b47d6 --- /dev/null +++ b/Documentation/devicetree/bindings/fb/mdss-mdp.txt @@ -0,0 +1,898 @@ +Qualcomm Technologies, Inc. MDSS MDP + +MDSS is Mobile Display SubSystem which implements Linux framebuffer APIs to +drive user interface to different panel interfaces. MDP driver is the core of +MDSS which manage all data paths to different panel interfaces. + +Required properties +- compatible : Must be "qcom,mdss_mdp" + - "qcom,mdss_mdp3" for mdp3 +- reg : offset and length of the register set for the device. +- reg-names : names to refer to register sets related to this device +- interrupts : Interrupt associated with MDSS. +- interrupt-controller: Mark the device node as an interrupt controller. + This is an empty, boolean property. +- #interrupt-cells: Should be one. The first cell is interrupt number. +- vdd-supply : Phandle for vdd regulator device node. +- qcom,max-clk-rate: Specify maximum MDP core clock rate in hz that this + device supports. +- qcom,mdss-pipe-vig-off: Array of offset for MDP source surface pipes of + type VIG, the offsets are calculated from + register "mdp_phys" defined in reg property. + The number of offsets defined here should + reflect the amount of VIG pipes that can be + active in MDP for this configuration. +- qcom,mdss-pipe-vig-fetch-id: Array of shared memory pool fetch ids + corresponding to the VIG pipe offsets defined in + previous property, the amount of fetch ids + defined should match the number of offsets + defined in property: qcom,mdss-pipe-vig-off +- qcom,mdss-pipe-vig-xin-id: Array of VBIF clients ids (xins) corresponding + to the respective VIG pipes. Number of xin ids + defined should match the number of offsets + defined in property: qcom,mdss-pipe-vig-off +- qcom,mdss-pipe-vig-clk-ctrl-off: Array of offsets describing clk control + offsets for dynamic clock gating. 1st value + in the array represents offset of the control + register. 2nd value represents bit offset within + control register and 3rd value represents bit + offset within status register. Number of tuples + defined should match the number of offsets + defined in property: qcom,mdss-pipe-vig-off +- qcom,mdss-pipe-rgb-off: Array of offsets for MDP source surface pipes of + type RGB, the offsets are calculated from + register "mdp_phys" defined in reg property. + The number of offsets defined here should + reflect the amount of RGB pipes that can be + active in MDP for this configuration. +- qcom,mdss-pipe-rgb-fetch-id: Array of shared memory pool fetch ids + corresponding to the RGB pipe offsets defined in + previous property, the amount of fetch ids + defined should match the number of offsets + defined in property: qcom,mdss-pipe-rgb-off +- qcom,mdss-pipe-rgb-xin-id: Array of VBIF clients ids (xins) corresponding + to the respective RGB pipes. Number of xin ids + defined should match the number of offsets + defined in property: qcom,mdss-pipe-rgb-off +- qcom,mdss-pipe-rgb-clk-ctrl-off: Array of offsets describing clk control + offsets for dynamic clock gating. 1st value + in the array represents offset of the control + register. 2nd value represents bit offset within + control register and 3rd value represents bit + offset within status register. Number of tuples + defined should match the number of offsets + defined in property: qcom,mdss-pipe-rgb-off +- qcom,mdss-pipe-dma-off: Array of offsets for MDP source surface pipes of + type DMA, the offsets are calculated from + register "mdp_phys" defined in reg property. + The number of offsets defined here should + reflect the amount of DMA pipes that can be + active in MDP for this configuration. +- qcom,mdss-pipe-dma-fetch-id: Array of shared memory pool fetch ids + corresponding to the DMA pipe offsets defined in + previous property, the amount of fetch ids + defined should match the number of offsets + defined in property: qcom,mdss-pipe-dma-off +- qcom,mdss-pipe-dma-xin-id: Array of VBIF clients ids (xins) corresponding + to the respective DMA pipes. Number of xin ids + defined should match the number of offsets + defined in property: qcom,mdss-pipe-dma-off +- qcom,mdss-pipe-dma-clk-ctrl-off: Array of offsets describing clk control + offsets for dynamic clock gating. 1st value + in the array represents offset of the control + register. 2nd value represents bit offset within + control register and 3rd value represents bit + offset within status register. Number of tuples + defined should match the number of offsets + defined in property: qcom,mdss-pipe-dma-off +- qcom,mdss-pipe-cursor-off: Array of offsets for MDP source surface pipes of + type cursor, the offsets are calculated from + register "mdp_phys" defined in reg property. + The number of offsets defined here should + reflect the amount of cursor pipes that can be + active in MDP for this configuration. Meant for + hardware that has hw cursors support as a + source pipe. +- qcom,mdss-pipe-cursor-xin-id: Array of VBIF clients ids (xins) corresponding + to the respective cursor pipes. Number of xin ids + defined should match the number of offsets + defined in property: qcom,mdss-pipe-cursor-off +- qcom,mdss-pipe-cursor-clk-ctrl-off: Array of offsets describing clk control + offsets for dynamic clock gating. 1st value + in the array represents offset of the control + register. 2nd value represents bit offset within + control register and 3rd value represents bit + offset within status register. Number of tuples + defined should match the number of offsets + defined in property: qcom,mdss-pipe-cursor-off +- qcom,mdss-ctl-off: Array of offset addresses for the available ctl + hw blocks within MDP, these offsets are + calculated from register "mdp_phys" defined in + reg property. The number of ctl offsets defined + here should reflect the number of control paths + that can be configured concurrently on MDP for + this configuration. +- qcom,mdss-wb-off: Array of offset addresses for the progammable + writeback blocks within MDP. The number of + offsets defined should match the number of ctl + blocks defined in property: qcom,mdss-ctl-off +- qcom,mdss-mixer-intf-off: Array of offset addresses for the available + mixer blocks that can drive data to panel + interfaces. + These offsets are be calculated from register + "mdp_phys" defined in reg property. + The number of offsets defined should reflect the + amount of mixers that can drive data to a panel + interface. +- qcom,mdss-dspp-off: Array of offset addresses for the available dspp + blocks. These offsets are calculated from + register "mdp_phys" defined in reg property. + The number of dspp blocks should match the + number of mixers driving data to interface + defined in property: qcom,mdss-mixer-intf-off +- qcom,mdss-pingpong-off: Array of offset addresses for the available + pingpong blocks. These offsets are calculated + from register "mdp_phys" defined in reg property. + The number of pingpong blocks should match the + number of mixers driving data to interface + defined in property: qcom,mdss-mixer-intf-off +- qcom,mdss-mixer-wb-off: Array of offset addresses for the available + mixer blocks that can be drive data to writeback + block. These offsets will be calculated from + register "mdp_phys" defined in reg property. + The number of writeback mixer offsets defined + should reflect the number of mixers that can + drive data to a writeback block. +- qcom,mdss-intf-off: Array of offset addresses for the available MDP + video interface blocks that can drive data to a + panel controller through timing engine. + The offsets are calculated from "mdp_phys" + defined in reg property. The number of offsets + defiend should reflect the number of progammable + interface blocks available in hardware. +- qcom,mdss-pref-prim-intf: A string which indicates the configured hardware + interface between MDP and the primary panel. + Individual panel controller drivers initialize + hardware based on this property. + Based on the interfaces supported at present, + possible values are: + - "dsi" + - "edp" + - "hdmi" + +Bus Scaling Data: +- qcom,msm-bus,name: String property describing MDSS client. +- qcom,msm-bus,num-cases: This is the the number of Bus Scaling use cases + defined in the vectors property. This must be + set to <3> for MDSS driver where use-case 0 is + used to take off MDSS BW votes from the system. + And use-case 1 & 2 are used in ping-pong fashion + to generate run-time BW requests. +- qcom,msm-bus,active-only: A boolean flag indicating if it is active only. +- qcom,msm-bus,num-paths: This represents the number of paths in each + Bus Scaling Usecase. This value depends on + how many number of AXI master ports are + dedicated to MDSS for particular chipset. This + value represents the RT + NRT AXI master ports. +- qcom,msm-bus,vectors-KBps: * A series of 4 cell properties, with a format + of (src, dst, ab, ib) which is defined at + Documentation/devicetree/bindings/arm/msm/msm_bus.txt + * Current values of src & dst are defined at + include/linux/msm-bus-board.h + src values allowed for MDSS are: + 22 = MSM_BUS_MASTER_MDP_PORT0 + 23 = MSM_BUS_MASTER_MDP_PORT1 + 25 = MSM_BUS_MASTER_ROTATOR + dst values allowed for MDSS are: + 512 = MSM_BUS_SLAVE_EBI_CH0 + ab: Represents aggregated bandwidth. + ib: Represents instantaneous bandwidth. + * Total number of 4 cell properties will be + (number of use-cases * number of paths). + * These values will be overridden by the driver + based on the run-time requirements. So initial + ab and ib values defined here are random and + bare no logic except for the use-case 0 where ab + and ib values needs to be 0. + * Define realtime vector properties followed by + non-realtime vector properties. + +- qcom,mdss-prefill-outstanding-buffer-bytes: The size of mdp outstanding buffer + in bytes. The buffer is filled during prefill + time and the buffer size shall be included in + prefill bandwidth calculation. +- qcom,mdss-prefill-y-buffer-bytes: The size of mdp y plane buffer in bytes. The + buffer is filled during prefill time when format + is YUV and the buffer size shall be included in + prefill bandwidth calculation. +- qcom,mdss-prefill-scaler-buffer-lines-bilinear: The value indicates how many lines + of scaler line buffer need to be filled during + prefill time. If bilinear scalar is enabled, then this + number of lines is used to determine how many bytes + of scaler buffer to be included in prefill bandwidth + calculation. +- qcom,mdss-prefill-scaler-buffer-lines-caf: The value indicates how many lines of + of scaler line buffer need to be filled during + prefill time. If CAF mode filter is enabled, then + this number of lines is used to determine how many + bytes of scaler buffer to be included in prefill + bandwidth calculation. +- qcom,mdss-prefill-post-scaler-buffer: The size of post scaler buffer in bytes. + The buffer is used to smooth the output of the + scaler. If the buffer is present in h/w, it is + filled during prefill time and the number of bytes + shall be included in prefill bandwidth calculation. +- qcom,mdss-prefill-pingpong-buffer-pixels: The size of pingpong buffer in pixels. + The buffer is used to keep pixels flowing to the + panel interface. If the vertical start position of a + layer is in the beginning of the active area, pingpong + buffer must be filled during prefill time to generate + starting lines. The number of bytes to be filled is + determined by the line width, starting position, + byte per pixel and scaling ratio, this number shall be + included in prefill bandwidth calculation. +- qcom,mdss-prefill-fbc-lines: The value indicates how many lines are required to fill + fbc buffer during prefill time if FBC (Frame Buffer + Compressor) is enabled. The number of bytes to be filled + is determined by the line width, bytes per pixel and + scaling ratio, this number shall be included in prefill bandwidth + calculation. +- qcom,max-mixer-width: Specify maximum MDP mixer width that the device supports. + This is a mandatory property, if not specified then + mdp probe will fail. + +Optional properties: +- batfet-supply : Phandle for battery FET regulator device node. +- vdd-cx-supply : Phandle for vdd CX regulator device node. +- qcom,vbif-settings : Array with key-value pairs of constant VBIF register + settings used to setup MDSS QoS for optimum performance. + The key used should be offset from "vbif_phys" register + defined in reg property. +- qcom,vbif-nrt-settings : The key used should be offset from "vbif_nrt_phys" + register defined in reg property. Refer qcom,vbif-settings + for a detailed description of this binding. +- qcom,mdp-settings : Array with key-value pairs of constant MDP register + settings used to setup MDSS QoS for best performance. + The key used should be offset from "mdp_phys" register + defined in reg property. +- qcom,mdss-smp-data: Array of shared memory pool data for dynamic SMP. There + should be only two values in this property. The first + value corresponds to the number of smp blocks and the + second is the size of each block present in the mdss + hardware. This property is optional for MDP hardware + with fix pixel latency ram. +- qcom,mdss-rot-block-size: The size of a memory block (in pixels) to be used + by the rotator. If this property is not specified, + then a default value of 128 pixels would be used. +- qcom,mdss-has-bwc: Boolean property to indicate the presence of bandwidth + compression feature in the rotator. +- qcom,mdss-has-non-scalar-rgb: Boolean property to indicate the presence of RGB + pipes which have no scaling support. +- qcom,mdss-has-decimation: Boolean property to indicate the presence of + decimation feature in fetch. +- qcom,mdss-has-fixed-qos-arbiter-enabled: Boolean property to indicate the + presence of rt/nrt feature. This feature enables + increased performance by prioritizing the real time + (rt) traffic over non real time (nrt) traffic to + access the memory. +- qcom,mdss-num-nrt-paths: Integer property represents the number of non-realtime + paths in each Bus Scaling Usecase. This value depends on + number of AXI ports are dedicated to non-realtime VBIF for + particular chipset. This property is mandatory when + "qcom,mdss-has-fixed-qos-arbiter-enabled" is enabled. + These paths must be defined after rt-paths in + "qcom,msm-bus,vectors-KBps" vector request. +- qcom,mdss-has-source-split: Boolean property to indicate if source split + feature is available or not. +- qcom,mdss-has-rotator-downscale: Boolean property to indicate if rotator + downscale feature is available or not. +- qcom,mdss-rot-downscale-min: This integer value indicates the Minimum + downscale factor supported by rotator. +- qcom,mdss-rot-downscale-max: This integer value indicates the Maximum + downscale factor supported by rotator. +- qcom,mdss-ad-off: Array of offset addresses for the available + Assertive Display (AD) blocks. These offsets + are calculated from the register "mdp_phys" + defined in reg property. The number of AD + offsets should be less than or equal to the + number of mixers driving interfaces defined in + property: qcom,mdss-mixer-intf-off. Assumes + that AD blocks are aligned with the mixer + offsets as well (i.e. the first mixer offset + corresponds to the same pathway as the first + AD offset). +- qcom,mdss-has-wb-ad: Boolean property to indicate assertive display feature + support on write back framebuffer. +- qcom,mdss-no-lut-read: Boolean property to indicate reading of LUT is + not supported. +- qcom,mdss-no-hist-vote Boolean property to indicate histogram reads + and histogram LUT writes do not need additional + bandwidth voting. +- qcom,mdss-mdp-wfd-mode: A string that specifies what is the mode of + writeback wfd block. + "intf" = Writeback wfd block is + connected to the interface mixer. + "shared" = Writeback block shared + between wfd and rotator. + "dedicated" = Dedicated writeback + block for wfd using writeback mixer. +- qcom,mdss-smp-mb-per-pipe: Maximum number of shared memory pool blocks + restricted for a source surface pipe. If this + property is not specified, no such restriction + would be applied. +- qcom,mdss-highest-bank-bit: Property to indicate tile format as opposed to usual + linear format. The value tells the GPU highest memory + bank bit used. +- qcom,mdss-pipe-rgb-fixed-mmb: Array of indexes describing fixed Memory Macro + Blocks (MMBs) for rgb pipes. First value denotes + total numbers of MMBs per pipe while values, if + any, following first one denotes indexes of MMBs + to that RGB pipe. +- qcom,mdss-pipe-vig-fixed-mmb: Array of indexes describing fixed Memory Macro + Blocks (MMBs) for vig pipes. First value denotes + total numbers of MMBs per pipe while values, if + any, following first one denotes indexes of MMBs + to that VIG pipe. +- qcom,mdss-pipe-sw-reset-off: Property to indicate offset to the register which + holds sw_reset bitmap for different MDSS + components. +- qcom,mdss-pipe-vig-sw-reset-map: Array of bit offsets for vig pipes within + sw_reset register bitmap. Number of offsets + defined should match the number of offsets + defined in property: qcom,mdss-pipe-vig-off +- qcom,mdss-pipe-rgb-sw-reset-map: Array of bit offsets for rgb pipes within + sw_reset register bitmap. Number of offsets + defined should match the number of offsets + defined in property: qcom,mdss-pipe-rgb-off +- qcom,mdss-pipe-dma-sw-reset-map: Array of bit offsets for dma pipes within + sw_reset register bitmap. Number of offsets + defined should match the number of offsets + defined in property: qcom,mdss-pipe-dma-off +- qcom,mdss-default-ot-wr-limit: This integer value indicates maximum number of pending + writes that can be allowed on each WR xin. + This value can be used to reduce the pending writes + limit and can be tuned to match performance + requirements depending upon system state. + Some platforms require a dynamic ot limiting in + some cases. Setting this default ot write limit + will enable this dynamic limiting for the write + operations in the platforms that require these + limits. +- qcom,mdss-default-ot-rd-limit: This integer value indicates the default number of pending + reads that can be allowed on each RD xin. + Some platforms require a dynamic ot limiting in + some cases. Setting this default ot read limit + will enable this dynamic limiting for the read + operations in the platforms that require these + limits. +- qcom,mdss-clk-levels: This array indicates the mdp core clock level selection + array. Core clock is calculated for each frame and + hence depending upon calculated value, clock rate + will be rounded up to the next level according to + this table. Order of entries need to be ordered in + ascending order. +- qcom,mdss-vbif-qos-rt-setting: This array is used to program vbif qos remapper register + priority for real time clients. +- qcom,mdss-vbif-qos-nrt-setting: This array is used to program vbif qos remapper register + priority for non real time clients. +- qcom,mdss-traffic-shaper-enabled: This boolean property enables traffic shaper functionality + for MDSS rotator which spread out rotator bandwidth request + so that rotator don't compete with other real time read + clients. +- qcom,mdss-dram-channels: This represents the number of channels in the + Bus memory controller. +- qcom,regs-dump-mdp: This array represents the registers offsets that + will be dumped from the mdp when the debug logging + is enabled; each entry in the table is an start and + end offset from the MDP address "mdp_phys", the + format of each entry is as follows: + + Ex: + <0x01000 0x01404> + Will dump the MDP registers + from the address: "mdp_phys + 0x01000" + to the address: "mdp_phys + 0x01404" +- qcom,regs-dump-names-mdp: This array represents the tag that will be used + for each of the entries defined within regs-dump. + Note that each tag matches with one of the + regs-dump entries in the same order as they + are defined. +- qcom,regs-dump-xin-id-mdp: Array of VBIF clients ids (xins) corresponding + to mdp block. Xin id property is not valid for mdp + internal blocks like ctl, lm, dspp. It should set + to 0xff for such blocks. + +Fudge Factors: Fudge factors are used to boost demand for + resources like bus bandswidth, clk rate etc. to + overcome system inefficiencies and avoid any + glitches. These fudge factors are expressed in + terms of numerator and denominator. First value + is numerator followed by denominator. They all + are optional but highly recommended. + Ex: + x = value to be fudged + a = numerator, default value is 1 + b = denominator, default value is 1 + FUDGE(x, a, b) = ((x * a) / b) +- qcom,mdss-ib-factor: This fudge factor is applied to calculated ib + values in default conditions. +- qcom,mdss-ib-factor-overlap: This fudge factor is applied to calculated ib + values when the overlap bandwidth is the + predominant value compared to prefill bandwidth + value. +- qcom,mdss-clk-factor: This fudge factor is applied to calculated mdp + clk rate in default conditions. + +- qcom,max-bandwidth-low-kbps: This value indicates the max bandwidth in KB + that can be supported without underflow. + This is a low bandwidth threshold which should + be applied in most scenarios to be safe from + underflows when unable to satisfy bandwidth + requirements. +- qcom,max-bandwidth-high-kbps: This value indicates the max bandwidth in KB + that can be supported without underflow. + This is a high bandwidth threshold which can be + applied in scenarios where panel interface can + be more tolerant to memory latency such as + command mode panels. +- qcom,max-bandwidth-per-pipe-kbps: A two dimensional array indicating the max + bandwidth in KB that a single pipe can support + without underflow for various usecases. The + first parameter indicates the usecase and the + second parameter gives the max bw allowed for + the usecase. Following are the enum values for + modes in different cases: + For default case, mode = 1 + camera usecase, mode = 2 + hflip usecase, mode = 4 + vflip usecase, mode = 8 + First parameter/mode value need to match enum, + mdss_mdp_max_bw_mode, present in + include/uapi/linux/msm_mdp.h. +- qcom,max-bw-settings: This two dimension array indicates the max bandwidth + in KB that has to be supported when particular + scenarios are involved such as camera, flip. + The first parameter indicate the + scenario/usecase and second parameter indicate + the maximum bandwidth for that usecase. + Following are the enum values for modes in different + cases: + For default case, mode = 1 + camera usecase, mode = 2 + hflip usecase, mode = 4 + vflip usecase, mode = 8 + First parameter/mode value need to match enum, + mdss_mdp_max_bw_mode, present in + include/uapi/linux/msm_mdp.h. + +- qcom,mdss-has-panic-ctrl: Boolean property to indicate if panic/robust signal + control feature is available or not. +- qcom,mdss-en-svs-high: Boolean property to indicate if this target needs to + enable the svs high voltage level for CX rail. +- qcom,mdss-pipe-vig-panic-ctrl-offsets: Array of panic/robust signal offsets + corresponding to the respective VIG pipes. + Number of signal offsets should match the + number of offsets defined in property: + qcom,mdss-pipe-vig-off +- qcom,mdss-pipe-rgb-panic-ctrl-offsets: Array of panic/robust signal offsets + corresponding to the respective RGB pipes. + Number of signal offsets should match the + number of offsets defined in property: + qcom,mdss-pipe-rgb-off +- qcom,mdss-pipe-dma-panic-ctrl-offsets: Array of panic/robust signal offsets + corresponding to the respective DMA pipes. + Number of signal offsets should match the + number of offsets defined in property: + qcom,mdss-pipe-dma-off +- qcom,mdss-per-pipe-panic-luts: Array to configure the panic/robust luts for + each rt and nrt clients. This property is + for the MDPv1.7 and above, which configures + the panic independently on each client. + Each element of the array corresponds to: + First element - panic for linear formats + Second element - panic for tile formats + Third element - robust for linear formats + Fourth element - robust for tile formats +- qcom,mdss-has-pingpong-split: Boolean property to indicate if destination + split feature is available or not in the target. +- qcom,mdss-slave-pingpong-off: Offset address for the extra TE block which needs + to be programmed when pingpong split feature is enabled. + Offset is calculated from the "mdp_phys" + register value. Mandatory when qcom,mdss-has-pingpong-split + is enabled. +- qcom,mdss-ppb-ctl-off: Array of offset addresses of ping pong buffer control registers. + The offsets are calculated from the "mdp_phys" base address + specified. The number of offsets should match the + number of ping pong buffers available in the hardware. + Mandatory when qcom,mdss-has-pingpong-split is enabled. +- qcom,mdss-ppb-cfg-off: Array of offset addresses of ping pong buffer config registers. + The offsets are calculated from the "mdp_phys" base address + specified. The number of offsets should match the + number of ping pong buffers available in the hardware. + Mandatory when qcom,mdss-has-pingpong-split is enabled. +- qcom,mdss-cdm-off: Array of offset addresses for the available + chroma down modules that can convert RGB data + to YUV before sending it to the interface + block. These offsets will be calculated from + register "mdp_phys" define in reg property. The + number of cdm offsets should reflect the number + of cdm blocks present in hardware. +- qcom,mdss-dsc-off: Array of offset addresses for the available + display stream compression module block. + These offsets will be calculated from + register "mdp_phys" define in reg property. The + number of dsc offsets should reflect the number + of dsc blocks present in hardware. +- qcom,max-pipe-width: This value specifies the maximum MDP SSPP width + the device supports. If not specified, a default value + of 2048 will be applied. +- qcom,mdss-reg-bus: Property to provide Bus scaling for register access for + MDP and DSI Blocks. + +- qcom,mdss-rot-reg-bus: Property to provide Bus scaling for register access for + Rotator Block. + +- qcom,mdss-hw-rt: Optional Property to request min vote on the bus. + Few Low tier targets expect min vote on the bus during SMMU + and TZ operations. use this handle to request the vote needed. + +Optional subnodes: +- mdss_fb: Child nodes representing the frame buffer virtual devices. + +Subnode properties: +- compatible : Must be "qcom,mdss-fb" +- cell-index : Index representing frame buffer +- qcom,mdss-mixer-swap: A boolean property that indicates if the mixer muxes + need to be swapped based on the target panel. + By default the property is not defined. +- qcom,memblock-reserve: Specifies the memory location and the size reserved + for the framebuffer used to display the splash screen. + This property is required whenever the continuous splash + screen feature is enabled for the corresponding + framebuffer device. It should be used for only 32bit + kernel. +- qcom,cont-splash-memory: Specifies the memory block region reserved for + continuous splash screen feature. This property should be + defined for corresponding framebuffer device if + "qcom,memblock-reserve" is not defined when continuous + splash screen feature is enabled. +- linux,contiguous-region: Phandle to the continuous memory region reserved for + frame-buffer or continuous splash screen. Size of this + region is dependent on the display panel resolution and + buffering scheme for frame-buffer node. Currently driver + uses double buffering. + + Example: Width = 1920, Height = 1080, BytesPerPixel = 4, + Number of frame-buffers reserved = 2. + Size = 1920*1080*4*2 = ROUND_1MB(15.8MB) = 16MB. +- qcom,mdss-fb-splash-logo-enabled: The boolean entry enables the framebuffer + driver to display the splash logo image. + It is independent of continuous splash + screen feature and has no relation with + qcom,cont-splash-enabled entry present in + panel configuration. +- qcom,mdss-idle-power-collapse-enabled: Boolean property that enables support + for mdss power collapse in idle + screen use cases with smart panels. +- qcom,boot-indication-enabled: Boolean property that enables turning on the blue + LED for notifying that the device is in boot + process. + +- qcom,mdss-pp-offets: A node that lists the offsets of post processing blocks + from base module. + -- qcom,mdss-mdss-sspp-igc-lut-off: This 32 bit value provides the + offset to the IGC lut rams from mdp_phys base. + -- qcom,mdss-sspp-vig-pcc-off: This 32 bit value provides the offset + to PCC block from the VIG pipe base address. + -- qcom,mdss-sspp-rgb-pcc-off: This 32 bit value provides the offset + to PCC block from the RGB pipe base address. + -- qcom,mdss-sspp-dma-pcc-off: This 32 bit value provides the offset + to PCC block from the DMA pipe base address. + -- qcom,mdss-dspp-pcc-off: This 32 bit value provides the offset + to PCC block from the DSPP pipe base address. + -- qcom,mdss-lm-pgc-off: This 32 bit value provides the offset + to PGC block from the layer mixer base address. + -- qcom,mdss-dspp-gamut-off: This 32 bit value provides the offset + to gamut block from DSPP base address. + -- qcom,mdss-dspp-pgc-off: This 32 bit value provides the offset to + PGC block from the DSPP base address. + +- qcom,mdss-scaler-offsets: A node that lists the offsets of scaler blocks + from base module. + -- qcom,mdss-vig-scaler-off: This 32 bit value provides the + offset to vig scaler from vig pipe base. + -- qcom,mdss-vig-scaler-lut-off: This 32 bit value provides the + offset to vig scaler lut from vig pipe base. + -- qcom,mdss-has-dest-scaler: Boolean property to indicate the + presence of destination scaler block. + -- qcom,mdss-dest-block-off: This 32 bit value provides the + offset from mdp base to destination scaler block. + -- qcom,mdss-dest-scaler-off: Array containing offsets of + destination scalar modules from the scaler block. + -- qcom,mdss-dest-scaler-lut-off: Array containing offsets of destination + scaler lut tables from scalar block. + +- qcom,mdss-has-separate-rotator: Boolean property to indicate support of + indpendent rotator. Indpendent rotator has + separate DMA pipe working in block mode only. + +- smmu_mdp_***: Child nodes representing the mdss smmu virtual devices. + Mandatory smmu v2 and not required for smmu v1. + +Subnode properties: +- compatible : Compatible name used in smmu v2. + smmu_v2 names should be: + "qcom,smmu_mdp_unsec" - smmu context bank device for + unsecure mdp domain. + "qcom,smmu_rot_unsec" - smmu context bank device for + unsecure rotation domain. + "qcom,smmu_mdp_sec" - smmu context bank device for + secure mdp domain. + "qcom,smmu_rot_sec" - smmu context bank device for + secure rotation domain. + "qcom,smmu_kms_unsec" - smmu context bank device for + unsecure mdp domain for KMS driver. + "qcom,smmu_nrt_unsec" - smmu context bank device for + unsecure rotation domain for KMS driver. + "qcom,smmu_kms_sec" - smmu context bank device for + secure mdp domain for KMS driver. + "qcom,smmu_nrt_sec" - smmu context bank device for + secure rotation domain for KMS driver. + "qcom,smmu_arm_mdp_unsec" - arm smmu context bank device for + unsecure mdp domain. + "qcom,smmu_arm_mdp_sec" - arm smmu context bank device for + secure mdp domain. +- gdsc-mmagic-mdss-supply: Phandle for mmagic mdss supply regulator device node. +- reg : offset and length of the register set for the device. +- reg-names : names to refer to register sets related to this device +- clocks: List of Phandles for clock device nodes + needed by the device. +- clock-names: List of clock names needed by the device. + +Subnode properties: +Required properties: +- compatible: Must be "qcom,mdss_wb" +- qcom,mdss_pan_res: Array containing two elements, width and height which + specifies size of writeback buffer. +- qcom,mdss_pan_bpp: Specifies bits per pixel for writeback buffer. +- qcom,mdss-fb-map: Specifies the handle for frame buffer. + +Example: + mdss_mdp: qcom,mdss_mdp@fd900000 { + compatible = "qcom,mdss_mdp"; + reg = <0xfd900000 0x22100>, + <0xfd924000 0x1000>, + <0xfd925000 0x1000>; + reg-names = "mdp_phys", "vbif_phys", "vbif_nrt_phys"; + interrupts = <0 72 0>; + interrupt-controller; + #interrupt-cells = <1>; + #address-cells = <1>; + #size-cells = <1>; + vdd-supply = <&gdsc_mdss>; + batfet-supply = <&pm8941_chg_batif>; + vdd-cx-supply = <&pm8841_s2_corner>; + + /* Bus Scale Settings */ + qcom,msm-bus,name = "mdss_mdp"; + qcom,msm-bus,num-cases = <3>; + qcom,msm-bus,num-paths = <2>; + qcom,mdss-dram-channels = <2>; + qcom,mdss-num-nrt-paths = <1>; + qcom,msm-bus,vectors-KBps = + <22 512 0 0>, <23 512 0 0>, + <22 512 0 6400000>, <23 512 0 6400000>, + <22 512 0 6400000>, <23 512 0 6400000>; + + /* Fudge factors */ + qcom,mdss-ab-factor = <2 1>; /* 2 times */ + qcom,mdss-ib-factor = <3 2>; /* 1.5 times */ + qcom,mdss-high-ib-factor = <2 1>; /* 2 times */ + qcom,mdss-clk-factor = <5 4>; /* 1.25 times */ + + /* Clock levels */ + qcom,mdss-clk-levels = <92310000, 177780000, 200000000>; + + /* VBIF QoS remapper settings*/ + qcom,mdss-vbif-qos-rt-setting = <2 2 2 2>; + qcom,mdss-vbif-qos-nrt-setting = <1 1 1 1>; + + qcom,max-bandwidth-low-kbps = <2300000>; + qcom,max-bandwidth-high-kbps = <3000000>; + qcom,max-bandwidth-per-pipe-kbps = <4 2100000>, + <8 1800000>; + qcom,max-bw-settings = <1 2300000>, + <2 1700000>, + <4 2300000>, + <8 2000000>; + + qcom,max-mixer-width = <2048>; + qcom,max-pipe-width = <2048>; + qcom,max-clk-rate = <320000000>; + qcom,vbif-settings = <0x0004 0x00000001>, + <0x00D8 0x00000707>; + qcom,vbif-nrt-settings = <0x0004 0x00000001>, + <0x00D8 0x00000707>; + qcom,mdp-settings = <0x02E0 0x000000AA>, + <0x02E4 0x00000055>; + qcom,mdss-pipe-vig-off = <0x00001200 0x00001600 + 0x00001A00>; + qcom,mdss-pipe-rgb-off = <0x00001E00 0x00002200 + 0x00002600>; + qcom,mdss-pipe-dma-off = <0x00002A00 0x00002E00>; + qcom,mdss-pipe-cursor-off = <0x00035000 0x00037000>; + qcom,mdss-dsc-off = <0x00081000 0x00081400>; + qcom,mdss-pipe-vig-fetch-id = <1 4 7>; + qcom,mdss-pipe-rgb-fetch-id = <16 17 18>; + qcom,mdss-pipe-dma-fetch-id = <10 13>; + qcom,mdss-pipe-rgb-fixed-mmb = <2 0 1>, + <2 2 3>, + <2 4 5>, + <2 6 7>; + qcom,mdss-pipe-vig-fixed-mmb = <1 8>, + <1 9>, + <1 10>, + <1 11>; + qcom,mdss-smp-data = <22 4096>; + qcom,mdss-rot-block-size = <64>; + qcom,mdss-rotator-ot-limit = <2>; + qcom,mdss-smp-mb-per-pipe = <2>; + qcom,mdss-pref-prim-intf = "dsi"; + qcom,mdss-has-non-scalar-rgb; + qcom,mdss-has-bwc; + qcom,mdss-has-decimation; + qcom,mdss-has-fixed-qos-arbiter-enabled; + qcom,mdss-has-source-split; + qcom,mdss-wfd-mode = "intf"; + qcom,mdss-no-lut-read; + qcom,mdss-no-hist-vote; + qcom,mdss-traffic-shaper-enabled; + qcom,mdss-has-rotator-downscale; + qcom,mdss-rot-downscale-min = <2>; + qcom,mdss-rot-downscale-max = <16>; + + qcom,mdss-has-pingpong-split; + qcom,mdss-pipe-vig-xin-id = <0 4 8>; + qcom,mdss-pipe-rgb-xin-id = <1 5 9>; + qcom,mdss-pipe-dma-xin-id = <2 10>; + qcom,mdss-pipe-cursor-xin-id = <7 7>; + + qcom,mdss-pipe-vig-clk-ctrl-offsets = <0x3AC 0 0>, + <0x3B4 0 0>, + <0x3BC 0 0>, + <0x3C4 0 0>; + + qcom,mdss-pipe-rgb-clk-ctrl-offsets = <0x3AC 4 8>, + <0x3B4 4 8>, + <0x3BC 4 8>, + <0x3C4 4 8>; + + qcom,mdss-pipe-dma-clk-ctrl-offsets = <0x3AC 8 12>, + <0x3B4 8 12>; + + qcom,mdss-per-pipe-panic-luts = <0x000f>, + <0xffff>, + <0xfffc>, + <0xff00>; + + qcom,mdss-has-panic-ctrl; + qcom,mdss-pipe-vig-panic-ctrl-offsets = <0 1 2 3>; + qcom,mdss-pipe-rgb-panic-ctrl-offsets = <4 5 6 7>; + qcom,mdss-pipe-dma-panic-ctrl-offsets = <8 9>; + + qcom,mdss-pipe-sw-reset-off = <0x0128>; + qcom,mdss-pipe-vig-sw-reset-map = <5 6 7 8>; + qcom,mdss-pipe-rgb-sw-reset-map = <9 10 11 12>; + qcom,mdss-pipe-dma-sw-reset-map = <13 14>; + + qcom,mdss-ctl-off = <0x00000600 0x00000700 0x00000800 + 0x00000900 0x0000A00>; + qcom,mdss-mixer-intf-off = <0x00003200 0x00003600 + 0x00003A00>; + qcom,mdss-mixer-wb-off = <0x00003E00 0x00004200>; + qcom,mdss-dspp-off = <0x00004600 0x00004A00 0x00004E00>; + qcom,mdss-pingpong-off = <0x00012D00 0x00012E00 0x00012F00>; + qcom,mdss-wb-off = <0x00011100 0x00013100 0x00015100 + 0x00017100 0x00019100>; + qcom,mdss-intf-off = <0x00021100 0x00021300 + 0x00021500 0x00021700>; + qcom,mdss-cdm-off = <0x0007A200>; + qcom,mdss-ppb-ctl-off = <0x0000420>; + qcom,mdss-ppb-cfg-off = <0x0000424>; + qcom,mdss-slave-pingpong-off = <0x00073000> + + /* buffer parameters to calculate prefill bandwidth */ + qcom,mdss-prefill-outstanding-buffer-bytes = <1024>; + qcom,mdss-prefill-y-buffer-bytes = <4096>; + qcom,mdss-prefill-scaler-buffer-lines-bilinear = <2>; + qcom,mdss-prefill-scaler-buffer-lines-caf = <4>; + qcom,mdss-prefill-post-scaler-buffer-pixels = <2048>; + qcom,mdss-prefill-pingpong-buffer-pixels = <5120>; + qcom,mdss-prefill-fbc-lines = <2>; + qcom,mdss-idle-power-collapse-enabled; + + qcom,regs-dump-xin-id-mdp = <0xff 0xff 0xff 0xff 0x0 0x0>; + mdss_fb0: qcom,mdss_fb_primary { + cell-index = <0>; + compatible = "qcom,mdss-fb"; + qcom,mdss-mixer-swap; + linux,contiguous-region = <&fb_mem>; + qcom,mdss-fb-splash-logo-enabled: + qcom,cont-splash-memory { + linux,contiguous-region = <&cont_splash_mem>; + }; + }; + + qcom,mdss-pp-offsets { + qcom,mdss-sspp-mdss-igc-lut-off = <0x3000>; + qcom,mdss-sspp-vig-pcc-off = <0x1580>; + qcom,mdss-sspp-rgb-pcc-off = <0x180>; + qcom,mdss-sspp-dma-pcc-off = <0x180>; + qcom,mdss-lm-pgc-off = <0x3C0>; + qcom,mdss-dspp-gamut-off = <0x1600>; + qcom,mdss-dspp-pcc-off = <0x1700>; + qcom,mdss-dspp-pgc-off = <0x17C0>; + }; + + qcom,mdss-scaler-offsets { + qcom,mdss-vig-scaler-off = <0xA00>; + qcom,mdss-vig-scaler-lut-off = <0xB00>; + qcom,mdss-has-dest-scaler; + qcom,mdss-dest-block-off = <0x00061000>; + qcom,mdss-dest-scaler-off = <0x800 0x1000>; + qcom,mdss-dest-scaler-lut-off = <0x900 0x1100>; + }; + + qcom,mdss-reg-bus { + /* Reg Bus Scale Settings */ + qcom,msm-bus,name = "mdss_reg"; + qcom,msm-bus,num-cases = <4>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,active-only; + qcom,msm-bus,vectors-KBps = + <1 590 0 0>, + <1 590 0 76800>, + <1 590 0 160000>, + <1 590 0 320000>; + }; + + qcom,mdss-hw-rt-bus { + /* hw-rt Bus Scale Settings */ + qcom,msm-bus,name = "mdss_hw_rt"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <22 512 0 0>, + <22 512 0 1000>; + }; + + smmu_mdp_sec: qcom,smmu_mdp_sec_cb { + compatible = "qcom,smmu_mdp_sec"; + iommus = <&mdp_smmu 1>; + reg = <0xd09000 0x000d00>, + reg-names = "mmu_cb"; + gdsc-mmagic-mdss-supply = <&gdsc_mmagic_mdss>; + clocks = <&clock_mmss clk_smmu_mdp_ahb_clk>, + <&clock_mmss clk_smmu_mdp_axi_clk>; + clock-names = "dummy_clk", "dummy_clk"; + }; + + qcom,mdss_wb_panel { + compatible = "qcom,mdss_wb"; + qcom,mdss_pan_res = <1280 720>; + qcom,mdss_pan_bpp = <24>; + qcom,mdss-fb-map = <&mdss_fb1>; + }; + + qcom,mdss-rot-reg-bus { + /* Reg Bus Scale Settings */ + qcom,msm-bus,name = "mdss_rot_reg"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,active-only; + qcom,msm-bus,vectors-KBps = + <1 590 0 0>, + <1 590 0 76800>; + }; + }; + diff --git a/Documentation/devicetree/bindings/fb/mdss-pll.txt b/Documentation/devicetree/bindings/fb/mdss-pll.txt index e92e4deb0469..6b9238c4bf30 100644 --- a/Documentation/devicetree/bindings/fb/mdss-pll.txt +++ b/Documentation/devicetree/bindings/fb/mdss-pll.txt @@ -1,24 +1,20 @@ -Qualcomm Technologies MDSS pll for DSI/EDP/HDMI +Qualcomm Technologies, Inc. MDSS pll for DSI/EDP/HDMI -mdss-pll is a pll controller device which supports pll devices that -are compatible with MIPI display serial interface specification, -HDMI and edp. +mdss-pll is a pll controller device which supports pll devices that are +compatiable with MIPI display serial interface specification, HDMI and edp. Required properties: -- compatible: Compatible name used in the driver - "qcom,mdss_dsi_pll_8916", "qcom,mdss_dsi_pll_8939", - "qcom,mdss_dsi_pll_8974", "qcom,mdss_dsi_pll_8994", - "qcom,mdss_dsi_pll_8994", "qcom,mdss_dsi_pll_8909", - "qcom,mdss_hdmi_pll", "qcom,mdss_hdmi_pll_8994", - "qcom,mdss_dsi_pll_8992", "qcom,mdss_hdmi_pll_8992", - "qcom,mdss_dsi_pll_8996", "qcom,mdss_hdmi_pll_8996", - "qcom,mdss_hdmi_pll_8996_v2", "qcom,mdss_dsi_pll_8996_v2", - "qcom,mdss_hdmi_pll_8996_v3", "qcom,mdss_hdmi_pll_8996_v3_1p8", - "qcom,mdss_edp_pll_8996_v3", "qcom,mdss_edp_pll_8996_v3_1p8", - "qcom,mdss_dsi_pll_10nm", "qcom,mdss_dp_pll_8998", - "qcom,mdss_hdmi_pll_8998", "qcom,mdss_dp_pll_10nm", - "qcom,mdss_dsi_pll_7nm", - "qcom,mdss_dp_pll_7nm". +- compatible: Compatible name used in the driver. Should be one of: + "qcom,mdss_dsi_pll_8916", "qcom,mdss_dsi_pll_8939", + "qcom,mdss_dsi_pll_8974", "qcom,mdss_dsi_pll_8994", + "qcom,mdss_dsi_pll_8994", "qcom,mdss_dsi_pll_8909", + "qcom,mdss_hdmi_pll", "qcom,mdss_hdmi_pll_8994", + "qcom,mdss_dsi_pll_8992", "qcom,mdss_hdmi_pll_8992", + "qcom,mdss_dsi_pll_8996", "qcom,mdss_hdmi_pll_8996", + "qcom,mdss_hdmi_pll_8996_v2", "qcom,mdss_dsi_pll_8996_v2", + "qcom,mdss_hdmi_pll_8996_v3", "qcom,mdss_dsi_pll_8952", + "qcom,mdss_dsi_pll_8937", "qcom,mdss_hdmi_pll_8996_v3_1p8", + "qcom,mdss_dsi_pll_8953" - cell-index: Specifies the controller used - reg: offset and length of the register set for the device. - reg-names : names to refer to register sets related to this device diff --git a/Documentation/devicetree/bindings/fb/mdss-qpic-panel.txt b/Documentation/devicetree/bindings/fb/mdss-qpic-panel.txt new file mode 100644 index 000000000000..8c11a438f5d8 --- /dev/null +++ b/Documentation/devicetree/bindings/fb/mdss-qpic-panel.txt @@ -0,0 +1,25 @@ +Qualcomm Technologies, Inc. mdss-qpic-panel + +mdss-qpic-panel is a panel device which can be driven by qpic. + +Required properties: +- compatible: Must be "qcom,mdss-qpic-panel" +- qcom,mdss-pan-res: A two dimensional array that specifies the panel + resolution. +- qcom,mdss-pan-bpp: Specifies the panel bits per pixel. +- qcom,refresh_rate: Panel refresh rate + +Optional properties: +- label: A string used as a descriptive name of the panel + + +Example: +/ { + qcom,mdss_lcdc_ili9341_qvga { + compatible = "qcom,mdss-qpic-panel"; + label = "ili qvga lcdc panel"; + qcom,mdss-pan-res = <240 320>; + qcom,mdss-pan-bpp = <18>; + qcom,refresh_rate = <60>; + }; +}; diff --git a/Documentation/devicetree/bindings/fb/mdss-qpic.txt b/Documentation/devicetree/bindings/fb/mdss-qpic.txt new file mode 100644 index 000000000000..16d5b3547bdc --- /dev/null +++ b/Documentation/devicetree/bindings/fb/mdss-qpic.txt @@ -0,0 +1,49 @@ +Qualcomm Technolgies, Inc. mdss-qpic + +mdss-qpic is a qpic controller device which supports dma transmission to MIPI +and LCDC panel. + +Required properties: +- compatible: must be "qcom,mdss_qpic" +- reg: offset and length of the register set for the device. +- reg-names : names to refer to register sets related to this device +- interrupts: IRQ line +- vdd-supply: Phandle for vdd regulator device node. +- avdd-supply: Phandle for avdd regulator device node. +- qcom,cs-gpio: Phandle for cs gpio device node. +- qcom,te-gpio: Phandle for te gpio device node. +- qcom,rst-gpio: Phandle for rst gpio device node. +- qcom,ad8-gpio: Phandle for ad8 gpio device node. +- qcom,bl-gpio: Phandle for backlight gpio device node. + +Optional properties: +- Refer to "Documentation/devicetree/bindings/arm/msm/msm_bus.txt" for +below Bus Scaling properties: + - qcom,msm-bus,name + - qcom,msm-bus,num-cases + - qcom,msm-bus,num-paths + - qcom,msm-bus,vectors-KBps + +Example: + qcom,msm_qpic@f9ac0000 { + compatible = "qcom,mdss_qpic"; + reg = <0xf9ac0000 0x24000>; + reg-names = "qpic_base"; + interrupts = <0 251 0>; + + qcom,msm-bus,name = "mdss_qpic"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + + qcom,msm-bus,vectors-KBps = + <91 512 0 0>, + <91 512 400000 800000>; + + vdd-supply = <&pm8019_l11>; + avdd-supply = <&pm8019_l14>; + qcom,cs-gpio = <&msmgpio 21 0>; + qcom,te-gpio = <&msmgpio 22 0>; + qcom,rst-gpio = <&msmgpio 23 0>; + qcom,ad8-gpio = <&msmgpio 20 0>; + qcom,bl-gpio = <&msmgpio 84 0>; + }; diff --git a/Documentation/devicetree/bindings/fb/mdss-rotator.txt b/Documentation/devicetree/bindings/fb/mdss-rotator.txt new file mode 100644 index 000000000000..5e077ac23819 --- /dev/null +++ b/Documentation/devicetree/bindings/fb/mdss-rotator.txt @@ -0,0 +1,78 @@ +QTI MDSS Rotator + +MDSS rotator is a rotator driver, which manages the rotator hw +block inside the Mobile Display Subsystem. + +Required properties +- compatible : Must be "qcom,mdss-rotator". +- qcom,mdss-wb-count: The number of writeback block + in the hardware +- -supply: Phandle for regulator device node. + +Bus Scaling Data: +- qcom,msm-bus,name: String property describing MDSS client. +- qcom,msm-bus,num-cases: This is the the number of Bus Scaling use cases + defined in the vectors property. This must be + set to <3> for MDSS driver where use-case 0 is + used to take off MDSS BW votes from the system. + And use-case 1 & 2 are used in ping-pong fashion + to generate run-time BW requests. +- qcom,msm-bus,num-paths: This represents the number of paths in each + Bus Scaling Usecase. This value depends on + how many number of AXI master ports are + dedicated to MDSS for particular chipset. +- qcom,msm-bus,vectors-KBps: * A series of 4 cell properties, with a format + of (src, dst, ab, ib) which is defined at + Documentation/devicetree/bindings/arm/msm/msm_bus.txt + * Current values of src & dst are defined at + include/linux/msm-bus-board.h + src values allowed for MDSS are: + 22 = MSM_BUS_MASTER_MDP_PORT0 + 23 = MSM_BUS_MASTER_MDP_PORT1 + 25 = MSM_BUS_MASTER_ROTATOR + dst values allowed for MDSS are: + 512 = MSM_BUS_SLAVE_EBI_CH0 + ab: Represents aggregated bandwidth. + ib: Represents instantaneous bandwidth. + * Total number of 4 cell properties will be + (number of use-cases * number of paths). + * These values will be overridden by the driver + based on the run-time requirements. So initial + ab and ib values defined here are random and + bare no logic except for the use-case 0 where ab + and ib values needs to be 0. + * Define realtime vector properties followed by + non-realtime vector properties. + +Optional properties +- qcom,mdss-has-reg-bus: Boolean property to indicate + if rotator needs to vote for register bus. This + property is needed starting 8996 +- qcom,mdss-has-ubwc: Boolean property to indicate + if the hw supports universal + bandwidth compression (ubwc) +- qcom,mdss-has-downscale Boolean property to indicate + if the hw supports downscale + +Example: + mdss_rotator: qcom,mdss_rotator { + compatible = "qcom,mdss_rotator"; + qcom,mdss-has-downscale; + qcom,mdss-has-ubwc; + qcom,mdss-wb-count = <2>; + + qcom,mdss-has-reg-bus; + /* Bus Scale Settings */ + qcom,msm-bus,name = "mdss_rotator"; + qcom,msm-bus,num-cases = <3>; + qcom,msm-bus,num-paths = <1>; + qcom,mdss-num-nrt-paths = <1>; + qcom,msm-bus,vectors-KBps = + <25 512 0 0>, + <25 512 0 6400000>, + <25 512 0 6400000>; + + vdd-supply = <&gdsc_mdss>; + gdsc-mmagic-mdss-supply = <&gdsc_mmagic_mdss>; + qcom,supply-names = "vdd", "gdsc-mmagic-mdss"; + }; diff --git a/Documentation/devicetree/bindings/fb/msm-hdmi-tx.txt b/Documentation/devicetree/bindings/fb/msm-hdmi-tx.txt new file mode 100644 index 000000000000..285a14f7ff69 --- /dev/null +++ b/Documentation/devicetree/bindings/fb/msm-hdmi-tx.txt @@ -0,0 +1,116 @@ +* Qualcomm Technologies, Inc. HDMI Tx + +Required properties: +- cell-index: hdmi tx controller index +- compatible: must be "qcom,hdmi-tx" +- reg: offset and length of the register regions(s) for the device. +- reg-names: a list of strings that map in order to the list of regs. + +- hpd-gdsc-supply: phandle to the mdss gdsc regulator device tree node. +- hpd-5v-supply: phandle to the 5V regulator device tree node. +- core-vdda-supply: phandle to the HDMI vdda regulator device tree node. +- core-vcc-supply: phandle to the HDMI vcc regulator device tree node. +- qcom,supply-names: a list of strings that map in order + to the list of supplies. +- qcom,min-voltage-level: specifies minimum voltage (uV) level + of supply(ies) mentioned above. +- qcom,max-voltage-level: specifies maximum voltage (uV) level + of supply(ies) mentioned above. +- qcom,enable-load: specifies the current (uA) that will be + drawn from the enabled supply(ies) mentioned above. +- qcom,disable-load: specifies the current (uA) that will be + drawn from the disabled supply(ies) mentioned above. + +- qcom,hdmi-tx-cec: gpio for Consumer Electronics Control (cec) line. +- qcom,hdmi-tx-ddc-clk: gpio for Display Data Channel (ddc) clock line. +- qcom,hdmi-tx-ddc-data: gpio for ddc data line. + +Optional properties: +- hpd-5v-en-supply: phandle to the 5V boost enable regulator device tree node. +- qcom,hdmi-tx-mux-sel: gpio required to toggle HDMI output between + docking station, type A, and liquid device, type D, ports. Required + property for liquid devices. +- qcom,hdmi-tx-ddc-mux-sel: gpio for ddc mux select. +- qcom,hdmi-tx-mux-en: gpio required to enable mux for HDMI output + on liquid devices. Required property for liquid devices. +- qcom,hdmi-tx-mux-lpm: gpio required for hdmi mux configuration + selection on liquid devices. Required property for liquid devices. +- qcom,conditional-power-on: Enables HPD conditionally on MTP targets. + Required property for MTP devices which are reworked to expose HDMI port. +- qcom,hdmi-tx-hpd: gpio required for HDMI hot-plug detect. Required on + platforms where companion chip is not used. +- pinctrl-names: a list of strings that map to the pinctrl states. +- pinctrl-0: list of phandles, each pointing at a pin configuration node. +... +- pinctrl-n: list of phandles, each pointing at a pin configuration node. +- qcom,conti-splash-enabled: Enables the hdmi continuous splash screen feature. + HDMI interface will remain powered on from LK to kernel with continuous + display of bootup logo. +- qcom,pluggable: boolean to enable hotplug feature. +- qcom,display-id: A string indicates the display ID for the controller. + The possible values are: + - "primary" + - "secondary" + - "tertiary" + +[Optional child nodes]: These nodes are for devices which are +dependent on HDMI Tx controller. If HDMI Tx controller is disabled then +these devices will be disabled as well. Ex. HDMI Audio Codec device. + +- qcom,msm-hdmi-audio-rx: Node for HDMI audio codec. +Required properties: +- compatible : "msm-hdmi-audio-codec-rx"; + +Example: + mdss_hdmi_tx: qcom,hdmi_tx@fd922100 { + cell-index = <0>; + compatible = "qcom,hdmi-tx"; + reg = <0xfd922100 0x35C>, + <0xfd922500 0x7C>, + <0xfc4b8000 0x60F0>, + <0xfe2a0000 0xFFF>; + reg-names = "core_physical", "phy_physical", "qfprom_physical", + "hdcp_physical"; + + hpd-gdsc-supply = <&gdsc_mdss>; + hpd-5v-supply = <&pm8941_mvs2>; + hpd-5v-en-supply = <&hdmi_vreg>; + core-vdda-supply = <&pm8941_l12>; + core-vcc-supply = <&pm8941_s3>; + qcom,supply-names = "hpd-gdsc", "hpd-5v", "hpd-5v-en", "core-vdda", "core-vcc"; + qcom,min-voltage-level = <0 0 0 1800000 1800000>; + qcom,max-voltage-level = <0 0 0 1800000 1800000>; + qcom,enable-load = <0 0 0 1800000 0>; + qcom,disable-load = <0 0 0 0 0>; + + qcom,hdmi-tx-ddc-mux-sel = <&pma8084_gpios 6 0>; + qcom,hdmi-tx-cec = <&msmgpio 31 0>; + qcom,hdmi-tx-ddc-clk = <&msmgpio 32 0>; + qcom,hdmi-tx-ddc-data = <&msmgpio 33 0>; + qcom,hdmi-tx-hpd = <&msmgpio 34 0>; + + qcom,hdmi-tx-mux-lpm = <&msmgpio 27 0>; + qcom,hdmi-tx-mux-en = <&msmgpio 83 0>; + qcom,hdmi-tx-mux-sel = <&msmgpio 85 0>; + + qcom,conditional-power-on; + qcom,pluggable; + qcom,display-id = "secondary"; + + qcom,msm-hdmi-audio-rx { + compatible = "qcom,msm-hdmi-audio-codec-rx"; + }; + pinctrl-names = "hdmi_hpd_active", "hdmi_ddc_active", + "hdmi_cec_active", "hdmi_active", + "hdmi_sleep"; + pinctrl-0 = <&mdss_hdmi_hpd_active &mdss_hdmi_ddc_suspend + &mdss_hdmi_cec_suspend>; + pinctrl-1 = <&mdss_hdmi_hpd_active &mdss_hdmi_ddc_active + &mdss_hdmi_cec_suspend>; + pinctrl-2 = <&mdss_hdmi_hpd_active &mdss_hdmi_cec_active + &mdss_hdmi_ddc_suspend>; + pinctrl-3 = <&mdss_hdmi_hpd_active &mdss_hdmi_ddc_active + &mdss_hdmi_cec_active>; + pinctrl-4 = <&mdss_hdmi_hpd_suspend &mdss_hdmi_ddc_suspend + &mdss_hdmi_cec_suspend>; + }; diff --git a/Documentation/devicetree/bindings/fb/mxsfb.txt b/Documentation/devicetree/bindings/fb/mxsfb.txt new file mode 100644 index 000000000000..96ec5179c8a0 --- /dev/null +++ b/Documentation/devicetree/bindings/fb/mxsfb.txt @@ -0,0 +1,49 @@ +* Freescale MXS LCD Interface (LCDIF) + +Required properties: +- compatible: Should be "fsl,-lcdif". Supported chips include + imx23 and imx28. +- reg: Address and length of the register set for lcdif +- interrupts: Should contain lcdif interrupts +- display : phandle to display node (see below for details) + +* display node + +Required properties: +- bits-per-pixel : <16> for RGB565, <32> for RGB888/666. +- bus-width : number of data lines. Could be <8>, <16>, <18> or <24>. + +Required sub-node: +- display-timings : Refer to binding doc display-timing.txt for details. + +Examples: + +lcdif@80030000 { + compatible = "fsl,imx28-lcdif"; + reg = <0x80030000 2000>; + interrupts = <38 86>; + + display: display { + bits-per-pixel = <32>; + bus-width = <24>; + + display-timings { + native-mode = <&timing0>; + timing0: timing0 { + clock-frequency = <33500000>; + hactive = <800>; + vactive = <480>; + hfront-porch = <164>; + hback-porch = <89>; + hsync-len = <10>; + vback-porch = <23>; + vfront-porch = <10>; + vsync-len = <10>; + hsync-active = <0>; + vsync-active = <0>; + de-active = <1>; + pixelclk-active = <0>; + }; + }; + }; +}; diff --git a/Documentation/devicetree/bindings/fb/sm501fb.txt b/Documentation/devicetree/bindings/fb/sm501fb.txt new file mode 100644 index 000000000000..9d9f0098092b --- /dev/null +++ b/Documentation/devicetree/bindings/fb/sm501fb.txt @@ -0,0 +1,34 @@ +* SM SM501 + +The SM SM501 is a LCD controller, with proper hardware, it can also +drive DVI monitors. + +Required properties: +- compatible : should be "smi,sm501". +- reg : contain two entries: + - First entry: System Configuration register + - Second entry: IO space (Display Controller register) +- interrupts : SMI interrupt to the cpu should be described here. +- interrupt-parent : the phandle for the interrupt controller that + services interrupts for this device. + +Optional properties: +- mode : select a video mode: + x[-][@] +- edid : verbatim EDID data block describing attached display. + Data from the detailed timing descriptor will be used to + program the display controller. +- little-endian: available on big endian systems, to + set different foreign endian. +- big-endian: available on little endian systems, to + set different foreign endian. + +Example for MPC5200: + display@1,0 { + compatible = "smi,sm501"; + reg = <1 0x00000000 0x00800000 + 1 0x03e00000 0x00200000>; + interrupts = <1 1 3>; + mode = "640x480-32@60"; + edid = [edid-data]; + }; diff --git a/drivers/video/fbdev/Kconfig b/drivers/video/fbdev/Kconfig index 5e58f5ec0a28..5dd7f6b3c45c 100644 --- a/drivers/video/fbdev/Kconfig +++ b/drivers/video/fbdev/Kconfig @@ -2334,6 +2334,19 @@ config FB_PRE_INIT_FB Select this option if display contents should be inherited as set by the bootloader. +config FB_MSM + tristate "MSM Framebuffer support" + depends on FB && ARCH_QCOM + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + select SYNC_FILE + ---help--- + The MSM driver implements a frame buffer interface to + provide access to the display hardware and provide + a way for users to display graphics + on connected display panels. + config FB_MX3 tristate "MX3 Framebuffer support" depends on FB && MX3_IPU @@ -2454,6 +2467,7 @@ config FB_SIMPLE source "drivers/video/fbdev/omap/Kconfig" source "drivers/video/fbdev/omap2/Kconfig" source "drivers/video/fbdev/mmp/Kconfig" +source "drivers/video/fbdev/msm/Kconfig" config FB_SH_MOBILE_MERAM tristate "SuperH Mobile MERAM read ahead support" diff --git a/drivers/video/fbdev/Makefile b/drivers/video/fbdev/Makefile index 8895536a20d6..653288d107c4 100644 --- a/drivers/video/fbdev/Makefile +++ b/drivers/video/fbdev/Makefile @@ -131,6 +131,11 @@ obj-$(CONFIG_FB_HYPERV) += hyperv_fb.o obj-$(CONFIG_FB_OPENCORES) += ocfb.o obj-$(CONFIG_FB_SM712) += sm712fb.o +ifeq ($(CONFIG_FB_MSM),y) +obj-y += msm/ +else +obj-$(CONFIG_MSM_DBA) += msm/msm_dba/ +endif # Platform or fallback drivers go here obj-$(CONFIG_FB_UVESA) += uvesafb.o obj-$(CONFIG_FB_VESA) += vesafb.o diff --git a/drivers/video/fbdev/core/fbmem.c b/drivers/video/fbdev/core/fbmem.c index f741ba8df01b..d914601f100f 100644 --- a/drivers/video/fbdev/core/fbmem.c +++ b/drivers/video/fbdev/core/fbmem.c @@ -1087,7 +1087,7 @@ fb_blank(struct fb_info *info, int blank) EXPORT_SYMBOL(fb_blank); static long do_fb_ioctl(struct fb_info *info, unsigned int cmd, - unsigned long arg) + unsigned long arg, struct file *file) { struct fb_ops *fb; struct fb_var_screeninfo var; @@ -1099,6 +1099,13 @@ static long do_fb_ioctl(struct fb_info *info, unsigned int cmd, void __user *argp = (void __user *)arg; long ret = 0; + memset(&var, 0, sizeof(var)); + memset(&fix, 0, sizeof(fix)); + memset(&con2fb, 0, sizeof(con2fb)); + memset(&cmap_from, 0, sizeof(cmap_from)); + memset(&cmap, 0, sizeof(cmap)); + memset(&event, 0, sizeof(event)); + switch (cmd) { case FBIOGET_VSCREENINFO: if (!lock_fb_info(info)) @@ -1217,7 +1224,9 @@ static long do_fb_ioctl(struct fb_info *info, unsigned int cmd, if (!lock_fb_info(info)) return -ENODEV; fb = info->fbops; - if (fb->fb_ioctl) + if (fb->fb_ioctl_v2) + ret = fb->fb_ioctl_v2(info, cmd, arg, file); + else if (fb->fb_ioctl) ret = fb->fb_ioctl(info, cmd, arg); else ret = -ENOTTY; @@ -1232,7 +1241,7 @@ static long fb_ioctl(struct file *file, unsigned int cmd, unsigned long arg) if (!info) return -ENODEV; - return do_fb_ioctl(info, cmd, arg); + return do_fb_ioctl(info, cmd, arg, file); } #ifdef CONFIG_COMPAT @@ -1263,7 +1272,7 @@ struct fb_cmap32 { }; static int fb_getput_cmap(struct fb_info *info, unsigned int cmd, - unsigned long arg) + unsigned long arg, struct file *file) { struct fb_cmap_user __user *cmap; struct fb_cmap32 __user *cmap32; @@ -1286,7 +1295,7 @@ static int fb_getput_cmap(struct fb_info *info, unsigned int cmd, put_user(compat_ptr(data), &cmap->transp)) return -EFAULT; - err = do_fb_ioctl(info, cmd, (unsigned long) cmap); + err = do_fb_ioctl(info, cmd, (unsigned long) cmap, file); if (!err) { if (copy_in_user(&cmap32->start, @@ -1331,7 +1340,7 @@ static int do_fscreeninfo_to_user(struct fb_fix_screeninfo *fix, } static int fb_get_fscreeninfo(struct fb_info *info, unsigned int cmd, - unsigned long arg) + unsigned long arg, struct file *file) { struct fb_fix_screeninfo fix; @@ -1360,20 +1369,22 @@ static long fb_compat_ioctl(struct file *file, unsigned int cmd, case FBIOPUT_CON2FBMAP: arg = (unsigned long) compat_ptr(arg); case FBIOBLANK: - ret = do_fb_ioctl(info, cmd, arg); + ret = do_fb_ioctl(info, cmd, arg, file); break; case FBIOGET_FSCREENINFO: - ret = fb_get_fscreeninfo(info, cmd, arg); + ret = fb_get_fscreeninfo(info, cmd, arg, file); break; case FBIOGETCMAP: case FBIOPUTCMAP: - ret = fb_getput_cmap(info, cmd, arg); + ret = fb_getput_cmap(info, cmd, arg, file); break; default: - if (fb->fb_compat_ioctl) + if (fb->fb_compat_ioctl_v2) + ret = fb->fb_compat_ioctl_v2(info, cmd, arg, file); + else if (fb->fb_compat_ioctl) ret = fb->fb_compat_ioctl(info, cmd, arg); break; } diff --git a/drivers/video/fbdev/msm/Kconfig b/drivers/video/fbdev/msm/Kconfig new file mode 100644 index 000000000000..e8f902bc0e19 --- /dev/null +++ b/drivers/video/fbdev/msm/Kconfig @@ -0,0 +1,137 @@ +source "drivers/video/fbdev/msm/msm_dba/Kconfig" + +if FB_MSM + +config FB_MSM_MDSS_COMMON + bool + +choice + prompt "MDP HW version" + default FB_MSM_MDP + +config FB_MSM_MDP + bool "MDP HW" + select FB_MSM_MDP_HW + ---help--- + The Mobile Display Processor (MDP) driver support devices which + contain MDP hardware block. + + Support for MSM MDP HW revision 2.2. + Say Y here if this is msm7201 variant platform. + +config FB_MSM_MDSS + bool "MDSS HW" + select SYNC_FILE + select FB_MSM_MDSS_COMMON + ---help--- + The Mobile Display Sub System (MDSS) driver supports devices which + contain MDSS hardware block. + + The MDSS driver implements frame buffer interface to provide access to + the display hardware and provide a way for users to display graphics + on connected display panels. + +config FB_MSM_MDP_NONE + bool "MDP HW None" + ---help--- + This is used for platforms without Mobile Display Sub System (MDSS). + mdm platform don't have MDSS hardware block. + + Say Y here if this is mdm platform. + +endchoice + +config FB_MSM_QPIC + bool + select FB_MSM_MDSS_COMMON + +config FB_MSM_QPIC_ILI_QVGA_PANEL + bool "Qpic MIPI ILI QVGA Panel" + select FB_MSM_QPIC + ---help--- + Support for MIPI ILI QVGA (240x320) panel ILI TECHNOLOGY 9341 + with on-chip full display RAM use parallel interface. + +config FB_MSM_QPIC_PANEL_DETECT + bool "Qpic Panel Detect" + select FB_MSM_QPIC_ILI_QVGA_PANEL + ---help--- + Support for Qpic panel auto detect. + +config FB_MSM_MDSS_WRITEBACK + bool "MDSS Writeback Panel" + ---help--- + The MDSS Writeback Panel provides support for routing the output of + MDSS frame buffer driver and MDP processing to memory. + +config FB_MSM_MDSS_HDMI_PANEL + bool "MDSS HDMI Tx Panel" + depends on FB_MSM_MDSS + select MSM_EXT_DISPLAY + default n + ---help--- + The MDSS HDMI Panel provides support for transmitting TMDS signals of + MDSS frame buffer data to connected hdmi compliant TVs, monitors etc. + +config FB_MSM_MDSS_HDMI_MHL_SII8334 + depends on FB_MSM_MDSS_HDMI_PANEL + bool 'MHL SII8334 support ' + default n + ---help--- + Support the HDMI to MHL conversion. + MHL (Mobile High-Definition Link) technology + uses USB connector to output HDMI content + +config FB_MSM_MDSS_MHL3 + depends on FB_MSM_MDSS_HDMI_PANEL + bool "MHL3 SII8620 Support" + default n + ---help--- + Support the SiliconImage 8620 MHL Tx transmitter that uses + USB connector to output HDMI content. Transmitter is an + i2c device acting as an HDMI to MHL bridge. Chip supports + MHL 3.0 standard. + +config FB_MSM_MDSS_DSI_CTRL_STATUS + tristate "DSI controller status check feature" + ---help--- + Check DSI controller status periodically (default period is 5 + seconds) by sending Bus-Turn-Around (BTA) command. If DSI controller + fails to acknowledge the BTA command, it sends PANEL_ALIVE=0 status + to HAL layer to reset the controller. + +config FB_MSM_MDSS_EDP_PANEL + depends on FB_MSM_MDSS + bool "MDSS eDP Panel" + ---help--- + The MDSS eDP Panel provides support for eDP host controller driver. + Which runs in Video mode only and is responsible for transmitting + frame buffer from host SOC to eDP display panel. + +config FB_MSM_MDSS_MDP3 + depends on FB_MSM_MDSS + bool "MDP3 display controller" + ---help--- + The MDP3 provides support for an older version display controller. + Included in latest display sub-system, known as MDSS. + +config FB_MSM_MDSS_XLOG_DEBUG + depends on FB_MSM_MDSS + bool "Enable MDSS debugging" + ---help--- + The MDSS debugging provides support to enable display debugging + features to: Dump MDSS registers during driver errors, panic + driver during fatal errors and enable some display-driver logging + into an internal buffer (this avoids logging overhead). + +config FB_MSM_MDSS_FRC_DEBUG + depends on DEBUG_FS && FB_MSM_MDSS + bool "Enable Video FRC debugging" + default n + ---help--- + The MDSS FRC debugging provides support to enable the deterministic + frame rate control (FRC) debugging features to: Collect video frame + statistics and check whether its output pattern matches expected + cadence. + +endif diff --git a/drivers/video/fbdev/msm/Makefile b/drivers/video/fbdev/msm/Makefile new file mode 100644 index 000000000000..81d4953828f0 --- /dev/null +++ b/drivers/video/fbdev/msm/Makefile @@ -0,0 +1,74 @@ +ccflags-y += -I$(src) + +obj-$(CONFIG_FB_MSM_MDSS_MHL3) += mhl3/ +obj-$(CONFIG_MSM_DBA) += msm_dba/ + +mdss-mdp3-objs = mdp3.o mdp3_layer.o mdp3_dma.o mdp3_ctrl.o dsi_status_v2.o +mdss-mdp3-objs += mdp3_ppp.o mdp3_ppp_hwio.o mdp3_ppp_data.o +obj-$(CONFIG_FB_MSM_MDSS_MDP3) += mdss-mdp3.o +ifeq ($(CONFIG_FB_MSM_MDSS_MDP3), y) +ccflags-y += -DTARGET_HW_MDSS_MDP3 +endif +mdss-mdp-objs := mdss_mdp.o mdss_mdp_ctl.o mdss_mdp_pipe.o mdss_mdp_util.o dsi_status_6g.o +mdss-mdp-objs += mdss_mdp_pp.o mdss_mdp_pp_debug.o mdss_mdp_pp_cache_config.o mdss_sync.o +mdss-mdp-objs += mdss_mdp_intf_video.o +mdss-mdp-objs += mdss_mdp_intf_cmd.o +mdss-mdp-objs += mdss_mdp_intf_writeback.o +mdss-mdp-objs += mdss_rotator.o +mdss-mdp-objs += mdss_mdp_overlay.o +mdss-mdp-objs += mdss_mdp_layer.o +mdss-mdp-objs += mdss_mdp_splash_logo.o +mdss-mdp-objs += mdss_mdp_cdm.o +mdss-mdp-objs += mdss_smmu.o +mdss-mdp-objs += mdss_mdp_wfd.o +mdss-mdp-objs += mdss_io_util.o +obj-$(CONFIG_FB_MSM_MDSS) += mdss-mdp.o +obj-$(CONFIG_FB_MSM_MDSS) += mdss_mdp_debug.o + +mdss-mdp-objs += mdss_mdp_pp_v1_7.o +mdss-mdp-objs += mdss_mdp_pp_v3.o +mdss-mdp-objs += mdss_mdp_pp_common.o + +ifeq ($(CONFIG_FB_MSM_MDSS),y) +obj-$(CONFIG_DEBUG_FS) += mdss_debug.o mdss_debug_xlog.o +endif + +ifeq ($(CONFIG_FB_MSM_MDSS_FRC_DEBUG),y) +obj-$(CONFIG_DEBUG_FS) += mdss_debug_frc.o +endif + +mdss-dsi-objs := mdss_dsi.o mdss_dsi_host.o mdss_dsi_cmd.o mdss_dsi_status.o +mdss-dsi-objs += mdss_dsi_panel.o +mdss-dsi-objs += msm_mdss_io_8974.o +mdss-dsi-objs += mdss_dsi_phy.o +mdss-dsi-objs += mdss_dsi_phy_12nm.o +mdss-dsi-objs += mdss_dsi_clk.o +obj-$(CONFIG_FB_MSM_MDSS) += mdss-dsi.o +obj-$(CONFIG_FB_MSM_MDSS) += mdss_panel.o + +ifneq ($(CONFIG_FB_MSM_MDSS_MDP3), y) +obj-$(CONFIG_FB_MSM_MDSS) += mdss_hdmi_util.o +obj-$(CONFIG_FB_MSM_MDSS) += mdss_hdmi_edid.o +obj-$(CONFIG_FB_MSM_MDSS) += mdss_cec_core.o +obj-$(CONFIG_FB_MSM_MDSS) += mdss_dba_utils.o +obj-$(CONFIG_FB_MSM_MDSS_EDP_PANEL) += mdss_edp.o +obj-$(CONFIG_FB_MSM_MDSS_EDP_PANEL) += mdss_edp_aux.o + +obj-$(CONFIG_FB_MSM_MDSS_HDMI_PANEL) += mdss_hdmi_tx.o +obj-$(CONFIG_FB_MSM_MDSS_HDMI_PANEL) += mdss_hdmi_panel.o +obj-$(CONFIG_FB_MSM_MDSS_HDMI_PANEL) += mdss_hdmi_hdcp.o +obj-$(CONFIG_FB_MSM_MDSS_HDMI_PANEL) += mdss_hdmi_hdcp2p2.o +obj-$(CONFIG_FB_MSM_MDSS_HDMI_PANEL) += mdss_hdmi_cec.o +obj-$(CONFIG_FB_MSM_MDSS_HDMI_PANEL) += mdss_hdmi_audio.o +obj-$(CONFIG_FB_MSM_MDSS_HDMI_MHL_SII8334) += mhl_sii8334.o mhl_msc.o +ccflags-y += -DTARGET_HW_MDSS_HDMI +endif + +obj-$(CONFIG_FB_MSM_MDSS_WRITEBACK) += mdss_wb.o + +mdss-qpic-objs := mdss_qpic.o mdss_fb.o mdss_qpic_panel.o mdss_sync.o +obj-$(CONFIG_FB_MSM_QPIC) += mdss-qpic.o +obj-$(CONFIG_FB_MSM_QPIC_ILI_QVGA_PANEL) += qpic_panel_ili_qvga.o + +obj-$(CONFIG_FB_MSM_MDSS) += mdss_fb.o mdss_util.o +obj-$(CONFIG_COMPAT) += mdss_compat_utils.o diff --git a/drivers/video/fbdev/msm/dsi_host_v2.c b/drivers/video/fbdev/msm/dsi_host_v2.c new file mode 100644 index 000000000000..58927a6d26c6 --- /dev/null +++ b/drivers/video/fbdev/msm/dsi_host_v2.c @@ -0,0 +1,1889 @@ +/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "dsi_v2.h" +#include "dsi_io_v2.h" +#include "dsi_host_v2.h" +#include "mdss_debug.h" +#include "mdp3.h" + +#define DSI_POLL_SLEEP_US 1000 +#define DSI_POLL_TIMEOUT_US 16000 +#define DSI_ESC_CLK_RATE 19200000 +#define DSI_DMA_CMD_TIMEOUT_MS 200 +#define VSYNC_PERIOD 17 +#define DSI_MAX_PKT_SIZE 10 +#define DSI_SHORT_PKT_DATA_SIZE 2 +#define DSI_MAX_BYTES_TO_READ 16 + +struct dsi_host_v2_private { + unsigned char *dsi_base; + size_t dsi_reg_size; + struct device dis_dev; + int clk_count; + int dsi_on; + + void (*debug_enable_clk)(int on); +}; + +static struct dsi_host_v2_private *dsi_host_private; +static int msm_dsi_clk_ctrl(struct mdss_panel_data *pdata, int enable); + +int msm_dsi_init(void) +{ + if (!dsi_host_private) { + dsi_host_private = kzalloc(sizeof(struct dsi_host_v2_private), + GFP_KERNEL); + if (!dsi_host_private) + return -ENOMEM; + + } + + return 0; +} + +void msm_dsi_deinit(void) +{ + kfree(dsi_host_private); + dsi_host_private = NULL; +} + +void msm_dsi_ack_err_status(unsigned char *ctrl_base) +{ + u32 status; + + status = MIPI_INP(ctrl_base + DSI_ACK_ERR_STATUS); + + if (status) { + MIPI_OUTP(ctrl_base + DSI_ACK_ERR_STATUS, status); + + /* Writing of an extra 0 needed to clear error bits */ + MIPI_OUTP(ctrl_base + DSI_ACK_ERR_STATUS, 0); + pr_err("%s: status=%x\n", __func__, status); + } +} + +void msm_dsi_timeout_status(unsigned char *ctrl_base) +{ + u32 status; + + status = MIPI_INP(ctrl_base + DSI_TIMEOUT_STATUS); + if (status & 0x0111) { + MIPI_OUTP(ctrl_base + DSI_TIMEOUT_STATUS, status); + pr_err("%s: status=%x\n", __func__, status); + } +} + +void msm_dsi_dln0_phy_err(unsigned char *ctrl_base) +{ + u32 status; + + status = MIPI_INP(ctrl_base + DSI_DLN0_PHY_ERR); + + if (status & 0x011111) { + MIPI_OUTP(ctrl_base + DSI_DLN0_PHY_ERR, status); + pr_err("%s: status=%x\n", __func__, status); + } +} + +void msm_dsi_fifo_status(unsigned char *ctrl_base) +{ + u32 status; + + status = MIPI_INP(ctrl_base + DSI_FIFO_STATUS); + + if (status & 0x44444489) { + MIPI_OUTP(ctrl_base + DSI_FIFO_STATUS, status); + pr_err("%s: status=%x\n", __func__, status); + } +} + +void msm_dsi_status(unsigned char *ctrl_base) +{ + u32 status; + + status = MIPI_INP(ctrl_base + DSI_STATUS); + + if (status & 0x80000000) { + MIPI_OUTP(ctrl_base + DSI_STATUS, status); + pr_err("%s: status=%x\n", __func__, status); + } +} + +void msm_dsi_error(unsigned char *ctrl_base) +{ + msm_dsi_ack_err_status(ctrl_base); + msm_dsi_timeout_status(ctrl_base); + msm_dsi_fifo_status(ctrl_base); + msm_dsi_status(ctrl_base); + msm_dsi_dln0_phy_err(ctrl_base); +} + +static void msm_dsi_set_irq_mask(struct mdss_dsi_ctrl_pdata *ctrl, u32 mask) +{ + u32 intr_ctrl; + + intr_ctrl = MIPI_INP(dsi_host_private->dsi_base + DSI_INT_CTRL); + intr_ctrl |= mask; + MIPI_OUTP(dsi_host_private->dsi_base + DSI_INT_CTRL, intr_ctrl); +} + +static void msm_dsi_clear_irq_mask(struct mdss_dsi_ctrl_pdata *ctrl, u32 mask) +{ + u32 intr_ctrl; + + intr_ctrl = MIPI_INP(dsi_host_private->dsi_base + DSI_INT_CTRL); + intr_ctrl &= ~mask; + MIPI_OUTP(dsi_host_private->dsi_base + DSI_INT_CTRL, intr_ctrl); +} + +static void msm_dsi_set_irq(struct mdss_dsi_ctrl_pdata *ctrl, u32 mask) +{ + unsigned long flags; + + spin_lock_irqsave(&ctrl->irq_lock, flags); + if (ctrl->dsi_irq_mask & mask) { + spin_unlock_irqrestore(&ctrl->irq_lock, flags); + return; + } + if (ctrl->dsi_irq_mask == 0) { + ctrl->mdss_util->enable_irq(ctrl->dsi_hw); + pr_debug("%s: IRQ Enable, mask=%x term=%x\n", __func__, + (int)ctrl->dsi_irq_mask, (int)mask); + } + + msm_dsi_set_irq_mask(ctrl, mask); + ctrl->dsi_irq_mask |= mask; + spin_unlock_irqrestore(&ctrl->irq_lock, flags); +} + +static void msm_dsi_clear_irq(struct mdss_dsi_ctrl_pdata *ctrl, u32 mask) +{ + unsigned long flags; + + spin_lock_irqsave(&ctrl->irq_lock, flags); + if (!(ctrl->dsi_irq_mask & mask)) { + spin_unlock_irqrestore(&ctrl->irq_lock, flags); + return; + } + ctrl->dsi_irq_mask &= ~mask; + if (ctrl->dsi_irq_mask == 0) { + ctrl->mdss_util->disable_irq(ctrl->dsi_hw); + pr_debug("%s: IRQ Disable, mask=%x term=%x\n", __func__, + (int)ctrl->dsi_irq_mask, (int)mask); + } + msm_dsi_clear_irq_mask(ctrl, mask); + spin_unlock_irqrestore(&ctrl->irq_lock, flags); +} + +irqreturn_t msm_dsi_isr_handler(int irq, void *ptr) +{ + u32 isr; + + struct mdss_dsi_ctrl_pdata *ctrl = + (struct mdss_dsi_ctrl_pdata *)ptr; + + spin_lock(&ctrl->mdp_lock); + + if (ctrl->dsi_irq_mask == 0) { + spin_unlock(&ctrl->mdp_lock); + return IRQ_HANDLED; + } + + isr = MIPI_INP(dsi_host_private->dsi_base + DSI_INT_CTRL); + MIPI_OUTP(dsi_host_private->dsi_base + DSI_INT_CTRL, isr); + + pr_debug("%s: isr=%x", __func__, isr); + + if (isr & DSI_INTR_ERROR) { + pr_err("%s: isr=%x %x", __func__, isr, (int)DSI_INTR_ERROR); + msm_dsi_error(dsi_host_private->dsi_base); + } + + if (isr & DSI_INTR_VIDEO_DONE) + complete(&ctrl->video_comp); + + if (isr & DSI_INTR_CMD_DMA_DONE) + complete(&ctrl->dma_comp); + + if (isr & DSI_INTR_BTA_DONE) + complete(&ctrl->bta_comp); + + if (isr & DSI_INTR_CMD_MDP_DONE) + complete(&ctrl->mdp_comp); + + spin_unlock(&ctrl->mdp_lock); + + return IRQ_HANDLED; +} + +int msm_dsi_irq_init(struct device *dev, int irq_no, + struct mdss_dsi_ctrl_pdata *ctrl) +{ + int ret; + u32 isr; + struct mdss_hw *dsi_hw; + + msm_dsi_ahb_ctrl(1); + isr = MIPI_INP(dsi_host_private->dsi_base + DSI_INT_CTRL); + isr &= ~DSI_INTR_ALL_MASK; + MIPI_OUTP(dsi_host_private->dsi_base + DSI_INT_CTRL, isr); + msm_dsi_ahb_ctrl(0); + + ret = devm_request_irq(dev, irq_no, msm_dsi_isr_handler, + IRQF_DISABLED, "DSI", ctrl); + if (ret) { + pr_err("%s request_irq() failed!\n", __func__); + return ret; + } + + dsi_hw = kzalloc(sizeof(struct mdss_hw), GFP_KERNEL); + if (!dsi_hw) + return -ENOMEM; + + ctrl->dsi_hw = dsi_hw; + + dsi_hw->irq_info = kzalloc(sizeof(struct irq_info), GFP_KERNEL); + if (!dsi_hw->irq_info) { + kfree(dsi_hw); + pr_err("no mem to save irq info: kzalloc fail\n"); + return -ENOMEM; + } + + dsi_hw->hw_ndx = MDSS_HW_DSI0; + dsi_hw->irq_info->irq = irq_no; + dsi_hw->irq_info->irq_mask = 0; + dsi_hw->irq_info->irq_ena = false; + dsi_hw->irq_info->irq_buzy = false; + + ctrl->mdss_util->register_irq(ctrl->dsi_hw); + ctrl->mdss_util->disable_irq(ctrl->dsi_hw); + + return 0; +} + +static void msm_dsi_get_cmd_engine(struct mdss_dsi_ctrl_pdata *ctrl) +{ + unsigned char *ctrl_base = dsi_host_private->dsi_base; + u32 dsi_ctrl; + + if (ctrl->panel_mode == DSI_VIDEO_MODE) { + dsi_ctrl = MIPI_INP(ctrl_base + DSI_CTRL); + MIPI_OUTP(ctrl_base + DSI_CTRL, dsi_ctrl | 0x04); + } +} + +static void msm_dsi_release_cmd_engine(struct mdss_dsi_ctrl_pdata *ctrl) +{ + unsigned char *ctrl_base = dsi_host_private->dsi_base; + u32 dsi_ctrl; + + if (ctrl->panel_mode == DSI_VIDEO_MODE) { + dsi_ctrl = MIPI_INP(ctrl_base + DSI_CTRL); + dsi_ctrl &= ~0x04; + MIPI_OUTP(ctrl_base + DSI_CTRL, dsi_ctrl); + } +} + +static int msm_dsi_wait4mdp_done(struct mdss_dsi_ctrl_pdata *ctrl) +{ + int rc; + unsigned long flag; + + spin_lock_irqsave(&ctrl->mdp_lock, flag); + reinit_completion(&ctrl->mdp_comp); + msm_dsi_set_irq(ctrl, DSI_INTR_CMD_MDP_DONE_MASK); + spin_unlock_irqrestore(&ctrl->mdp_lock, flag); + + rc = wait_for_completion_timeout(&ctrl->mdp_comp, + msecs_to_jiffies(VSYNC_PERIOD * 4)); + + if (rc == 0) { + pr_err("DSI wait 4 mdp done time out\n"); + rc = -ETIME; + } else if (!IS_ERR_VALUE(rc)) { + rc = 0; + } + + msm_dsi_clear_irq(ctrl, DSI_INTR_CMD_MDP_DONE_MASK); + + return rc; +} + +void msm_dsi_cmd_mdp_busy(struct mdss_dsi_ctrl_pdata *ctrl) +{ + int rc; + u32 dsi_status; + unsigned char *ctrl_base = dsi_host_private->dsi_base; + + if (ctrl->panel_mode == DSI_VIDEO_MODE) + return; + + dsi_status = MIPI_INP(ctrl_base + DSI_STATUS); + if (dsi_status & 0x04) { + pr_debug("dsi command engine is busy\n"); + rc = msm_dsi_wait4mdp_done(ctrl); + if (rc) + pr_err("Timed out waiting for mdp done"); + } +} + +static int msm_dsi_wait4video_done(struct mdss_dsi_ctrl_pdata *ctrl) +{ + int rc; + unsigned long flag; + + spin_lock_irqsave(&ctrl->mdp_lock, flag); + reinit_completion(&ctrl->video_comp); + msm_dsi_set_irq(ctrl, DSI_INTR_VIDEO_DONE_MASK); + spin_unlock_irqrestore(&ctrl->mdp_lock, flag); + + rc = wait_for_completion_timeout(&ctrl->video_comp, + msecs_to_jiffies(VSYNC_PERIOD * 4)); + + if (rc == 0) { + pr_err("DSI wait 4 video done time out\n"); + rc = -ETIME; + } else if (!IS_ERR_VALUE(rc)) { + rc = 0; + } + + msm_dsi_clear_irq(ctrl, DSI_INTR_VIDEO_DONE_MASK); + + return rc; +} + +static int msm_dsi_wait4video_eng_busy(struct mdss_dsi_ctrl_pdata *ctrl) +{ + int rc = 0; + u32 dsi_status; + unsigned char *ctrl_base = dsi_host_private->dsi_base; + + if (ctrl->panel_mode == DSI_CMD_MODE) + return rc; + + dsi_status = MIPI_INP(ctrl_base + DSI_STATUS); + if (dsi_status & 0x08) { + pr_debug("dsi command in video mode wait for active region\n"); + rc = msm_dsi_wait4video_done(ctrl); + /* delay 4-5 ms to skip BLLP */ + if (!rc) + usleep_range(4000, 5000); + } + return rc; +} + +void msm_dsi_host_init(struct mdss_panel_data *pdata) +{ + u32 dsi_ctrl, data; + unsigned char *ctrl_base = dsi_host_private->dsi_base; + struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL; + struct mipi_panel_info *pinfo; + + pr_debug("%s\n", __func__); + + ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata, + panel_data); + pinfo = &pdata->panel_info.mipi; + + + if (pinfo->mode == DSI_VIDEO_MODE) { + data = 0; + if (pinfo->pulse_mode_hsa_he) + data |= BIT(28); + if (pinfo->hfp_power_stop) + data |= BIT(24); + if (pinfo->hbp_power_stop) + data |= BIT(20); + if (pinfo->hsa_power_stop) + data |= BIT(16); + if (pinfo->eof_bllp_power_stop) + data |= BIT(15); + if (pinfo->bllp_power_stop) + data |= BIT(12); + data |= ((pinfo->traffic_mode & 0x03) << 8); + data |= ((pinfo->dst_format & 0x03) << 4); /* 2 bits */ + data |= (pinfo->vc & 0x03); + MIPI_OUTP(ctrl_base + DSI_VIDEO_MODE_CTRL, data); + + data = 0; + data |= ((pinfo->rgb_swap & 0x07) << 12); + if (pinfo->b_sel) + data |= BIT(8); + if (pinfo->g_sel) + data |= BIT(4); + if (pinfo->r_sel) + data |= BIT(0); + MIPI_OUTP(ctrl_base + DSI_VIDEO_MODE_DATA_CTRL, data); + } else if (pinfo->mode == DSI_CMD_MODE) { + data = 0; + data |= ((pinfo->interleave_max & 0x0f) << 20); + data |= ((pinfo->rgb_swap & 0x07) << 16); + if (pinfo->b_sel) + data |= BIT(12); + if (pinfo->g_sel) + data |= BIT(8); + if (pinfo->r_sel) + data |= BIT(4); + data |= (pinfo->dst_format & 0x0f); /* 4 bits */ + MIPI_OUTP(ctrl_base + DSI_COMMAND_MODE_MDP_CTRL, data); + + /* DSI_COMMAND_MODE_MDP_DCS_CMD_CTRL */ + data = pinfo->wr_mem_continue & 0x0ff; + data <<= 8; + data |= (pinfo->wr_mem_start & 0x0ff); + if (pinfo->insert_dcs_cmd) + data |= BIT(16); + MIPI_OUTP(ctrl_base + DSI_COMMAND_MODE_MDP_DCS_CMD_CTRL, + data); + } else + pr_err("%s: Unknown DSI mode=%d\n", __func__, pinfo->mode); + + dsi_ctrl = BIT(8) | BIT(2); /* clock enable & cmd mode */ + + if (pinfo->crc_check) + dsi_ctrl |= BIT(24); + if (pinfo->ecc_check) + dsi_ctrl |= BIT(20); + if (pinfo->data_lane3) + dsi_ctrl |= BIT(7); + if (pinfo->data_lane2) + dsi_ctrl |= BIT(6); + if (pinfo->data_lane1) + dsi_ctrl |= BIT(5); + if (pinfo->data_lane0) + dsi_ctrl |= BIT(4); + + /* from frame buffer, low power mode */ + /* DSI_COMMAND_MODE_DMA_CTRL */ + MIPI_OUTP(ctrl_base + DSI_COMMAND_MODE_DMA_CTRL, 0x14000000); + + data = 0; + if (pinfo->te_sel) + data |= BIT(31); + data |= pinfo->mdp_trigger << 4;/* cmd mdp trigger */ + data |= pinfo->dma_trigger; /* cmd dma trigger */ + data |= (pinfo->stream & 0x01) << 8; + MIPI_OUTP(ctrl_base + DSI_TRIG_CTRL, data); + + /* DSI_LAN_SWAP_CTRL */ + MIPI_OUTP(ctrl_base + DSI_LANE_SWAP_CTRL, ctrl_pdata->dlane_swap); + + /* clock out ctrl */ + data = pinfo->t_clk_post & 0x3f; /* 6 bits */ + data <<= 8; + data |= pinfo->t_clk_pre & 0x3f; /* 6 bits */ + /* DSI_CLKOUT_TIMING_CTRL */ + MIPI_OUTP(ctrl_base + DSI_CLKOUT_TIMING_CTRL, data); + + data = 0; + if (pinfo->rx_eot_ignore) + data |= BIT(4); + if (pinfo->tx_eot_append) + data |= BIT(0); + MIPI_OUTP(ctrl_base + DSI_EOT_PACKET_CTRL, data); + + + /* allow only ack-err-status to generate interrupt */ + /* DSI_ERR_INT_MASK0 */ + MIPI_OUTP(ctrl_base + DSI_ERR_INT_MASK0, 0x13ff3fe0); + + /* turn esc, byte, dsi, pclk, sclk, hclk on */ + MIPI_OUTP(ctrl_base + DSI_CLK_CTRL, 0x23f); + + dsi_ctrl |= BIT(0); /* enable dsi */ + MIPI_OUTP(ctrl_base + DSI_CTRL, dsi_ctrl); + + wmb(); /* ensure write is finished before progressing */ +} + +void dsi_set_tx_power_mode(int mode) +{ + u32 data; + unsigned char *ctrl_base = dsi_host_private->dsi_base; + + data = MIPI_INP(ctrl_base + DSI_COMMAND_MODE_DMA_CTRL); + + if (mode == 0) + data &= ~BIT(26); + else + data |= BIT(26); + + MIPI_OUTP(ctrl_base + DSI_COMMAND_MODE_DMA_CTRL, data); +} + +void msm_dsi_sw_reset(void) +{ + u32 dsi_ctrl; + unsigned char *ctrl_base = dsi_host_private->dsi_base; + + pr_debug("%s\n", __func__); + + dsi_ctrl = MIPI_INP(ctrl_base + DSI_CTRL); + dsi_ctrl &= ~0x01; + MIPI_OUTP(ctrl_base + DSI_CTRL, dsi_ctrl); + wmb(); /* ensure write is finished before progressing */ + + /* turn esc, byte, dsi, pclk, sclk, hclk on */ + MIPI_OUTP(ctrl_base + DSI_CLK_CTRL, 0x23f); + wmb(); /* ensure write is finished before progressing */ + + MIPI_OUTP(ctrl_base + DSI_SOFT_RESET, 0x01); + wmb(); /* ensure write is finished before progressing */ + MIPI_OUTP(ctrl_base + DSI_SOFT_RESET, 0x00); + wmb(); /* ensure write is finished before progressing */ +} + +void msm_dsi_controller_cfg(int enable) +{ + u32 dsi_ctrl, status; + unsigned char *ctrl_base = dsi_host_private->dsi_base; + + pr_debug("%s\n", __func__); + + /* Check for CMD_MODE_DMA_BUSY */ + if (readl_poll_timeout((ctrl_base + DSI_STATUS), + status, + ((status & 0x02) == 0), + DSI_POLL_SLEEP_US, DSI_POLL_TIMEOUT_US)) { + pr_err("%s: DSI status=%x failed\n", __func__, status); + pr_err("%s: Doing sw reset\n", __func__); + msm_dsi_sw_reset(); + } + + /* Check for x_HS_FIFO_EMPTY */ + if (readl_poll_timeout((ctrl_base + DSI_FIFO_STATUS), + status, + ((status & 0x11111000) == 0x11111000), + DSI_POLL_SLEEP_US, DSI_POLL_TIMEOUT_US)) + pr_err("%s: FIFO status=%x failed\n", __func__, status); + + /* Check for VIDEO_MODE_ENGINE_BUSY */ + if (readl_poll_timeout((ctrl_base + DSI_STATUS), + status, + ((status & 0x08) == 0), + DSI_POLL_SLEEP_US, DSI_POLL_TIMEOUT_US)) { + pr_err("%s: DSI status=%x\n", __func__, status); + pr_err("%s: Doing sw reset\n", __func__); + msm_dsi_sw_reset(); + } + + dsi_ctrl = MIPI_INP(ctrl_base + DSI_CTRL); + if (enable) + dsi_ctrl |= 0x01; + else + dsi_ctrl &= ~0x01; + + MIPI_OUTP(ctrl_base + DSI_CTRL, dsi_ctrl); + wmb(); /* ensure write is finished before progressing */ +} + +void msm_dsi_op_mode_config(int mode, struct mdss_panel_data *pdata) +{ + u32 dsi_ctrl; + unsigned char *ctrl_base = dsi_host_private->dsi_base; + + pr_debug("%s\n", __func__); + + dsi_ctrl = MIPI_INP(ctrl_base + DSI_CTRL); + + if (dsi_ctrl & DSI_VIDEO_MODE_EN) + dsi_ctrl &= ~(DSI_CMD_MODE_EN|DSI_EN); + else + dsi_ctrl &= ~(DSI_CMD_MODE_EN|DSI_VIDEO_MODE_EN|DSI_EN); + + if (mode == DSI_VIDEO_MODE) { + dsi_ctrl |= (DSI_VIDEO_MODE_EN|DSI_EN); + } else { + dsi_ctrl |= (DSI_CMD_MODE_EN|DSI_EN); + /* For Video mode panel, keep Video and Cmd mode ON */ + if (pdata->panel_info.type == MIPI_VIDEO_PANEL) + dsi_ctrl |= DSI_VIDEO_MODE_EN; + } + + pr_debug("%s: dsi_ctrl=%x\n", __func__, dsi_ctrl); + + MIPI_OUTP(ctrl_base + DSI_CTRL, dsi_ctrl); + wmb(); /* ensure write is finished before progressing */ +} + +int msm_dsi_cmd_dma_tx(struct mdss_dsi_ctrl_pdata *ctrl, + struct dsi_buf *tp) +{ + int len, rc; + unsigned long size, addr; + unsigned char *ctrl_base = dsi_host_private->dsi_base; + unsigned long flag; + + len = ALIGN(tp->len, 4); + size = ALIGN(tp->len, SZ_4K); + + tp->dmap = dma_map_single(&dsi_host_private->dis_dev, tp->data, size, + DMA_TO_DEVICE); + if (dma_mapping_error(&dsi_host_private->dis_dev, tp->dmap)) { + pr_err("%s: dmap mapp failed\n", __func__); + return -ENOMEM; + } + + addr = tp->dmap; + + msm_dsi_get_cmd_engine(ctrl); + + spin_lock_irqsave(&ctrl->mdp_lock, flag); + reinit_completion(&ctrl->dma_comp); + msm_dsi_set_irq(ctrl, DSI_INTR_CMD_DMA_DONE_MASK); + spin_unlock_irqrestore(&ctrl->mdp_lock, flag); + + MIPI_OUTP(ctrl_base + DSI_DMA_CMD_OFFSET, addr); + MIPI_OUTP(ctrl_base + DSI_DMA_CMD_LENGTH, len); + wmb(); /* ensure write is finished before progressing */ + + MIPI_OUTP(ctrl_base + DSI_CMD_MODE_DMA_SW_TRIGGER, 0x01); + wmb(); /* ensure write is finished before progressing */ + + rc = wait_for_completion_timeout(&ctrl->dma_comp, + msecs_to_jiffies(DSI_DMA_CMD_TIMEOUT_MS)); + if (rc == 0) { + pr_err("DSI command transaction time out\n"); + rc = -ETIME; + } else if (!IS_ERR_VALUE(rc)) { + rc = 0; + } + + dma_unmap_single(&dsi_host_private->dis_dev, tp->dmap, size, + DMA_TO_DEVICE); + tp->dmap = 0; + + msm_dsi_clear_irq(ctrl, DSI_INTR_CMD_DMA_DONE_MASK); + + msm_dsi_release_cmd_engine(ctrl); + + return rc; +} + +int msm_dsi_cmd_dma_rx(struct mdss_dsi_ctrl_pdata *ctrl, + struct dsi_buf *rp, int rlen) +{ + u32 *lp, data; + int i, off, cnt; + unsigned char *ctrl_base = dsi_host_private->dsi_base; + + lp = (u32 *)rp->data; + cnt = rlen; + cnt += 3; + cnt >>= 2; + + if (cnt > 4) + cnt = 4; /* 4 x 32 bits registers only */ + + off = DSI_RDBK_DATA0; + off += ((cnt - 1) * 4); + + for (i = 0; i < cnt; i++) { + data = (u32)MIPI_INP(ctrl_base + off); + *lp++ = ntohl(data); /* to network byte order */ + pr_debug("%s: data = 0x%x and ntohl(data) = 0x%x\n", + __func__, data, ntohl(data)); + off -= 4; + rp->len += sizeof(*lp); + } + + return rlen; +} + +static int msm_dsi_cmds_tx(struct mdss_dsi_ctrl_pdata *ctrl, + struct dsi_cmd_desc *cmds, int cnt) +{ + struct dsi_buf *tp; + struct dsi_cmd_desc *cm; + struct dsi_ctrl_hdr *dchdr; + int len; + int rc = 0; + + tp = &ctrl->tx_buf; + mdss_dsi_buf_init(tp); + cm = cmds; + len = 0; + while (cnt--) { + dchdr = &cm->dchdr; + mdss_dsi_buf_reserve(tp, len); + len = mdss_dsi_cmd_dma_add(tp, cm); + if (!len) { + pr_err("%s: failed to add cmd = 0x%x\n", + __func__, cm->payload[0]); + rc = -EINVAL; + goto dsi_cmds_tx_err; + } + + if (dchdr->last) { + tp->data = tp->start; /* begin of buf */ + rc = msm_dsi_wait4video_eng_busy(ctrl); + if (rc) { + pr_err("%s: wait4video_eng failed\n", __func__); + goto dsi_cmds_tx_err; + + } + + rc = msm_dsi_cmd_dma_tx(ctrl, tp); + if (IS_ERR_VALUE(len)) { + pr_err("%s: failed to call cmd_dma_tx for cmd = 0x%x\n", + __func__, cmds->payload[0]); + goto dsi_cmds_tx_err; + } + + if (dchdr->wait) + usleep_range(dchdr->wait * 1000, + dchdr->wait * 1000); + + mdss_dsi_buf_init(tp); + len = 0; + } + cm++; + } + +dsi_cmds_tx_err: + return rc; +} + +static int msm_dsi_parse_rx_response(struct dsi_buf *rp) +{ + int rc = 0; + unsigned char cmd; + + cmd = rp->data[0]; + switch (cmd) { + case DTYPE_ACK_ERR_RESP: + pr_debug("%s: rx ACK_ERR_PACLAGE\n", __func__); + rc = -EINVAL; + break; + case DTYPE_GEN_READ1_RESP: + case DTYPE_DCS_READ1_RESP: + mdss_dsi_short_read1_resp(rp); + break; + case DTYPE_GEN_READ2_RESP: + case DTYPE_DCS_READ2_RESP: + mdss_dsi_short_read2_resp(rp); + break; + case DTYPE_GEN_LREAD_RESP: + case DTYPE_DCS_LREAD_RESP: + mdss_dsi_long_read_resp(rp); + break; + default: + rc = -EINVAL; + pr_warn("%s: Unknown cmd received\n", __func__); + break; + } + + return rc; +} + +/* MIPI_DSI_MRPS, Maximum Return Packet Size */ +static char max_pktsize[2] = {0x00, 0x00}; /* LSB tx first, 10 bytes */ + +static struct dsi_cmd_desc pkt_size_cmd = { + {DTYPE_MAX_PKTSIZE, 1, 0, 0, 0, sizeof(max_pktsize)}, + max_pktsize, +}; + +static int msm_dsi_set_max_packet_size(struct mdss_dsi_ctrl_pdata *ctrl, + int size) +{ + struct dsi_buf *tp; + int rc; + + tp = &ctrl->tx_buf; + mdss_dsi_buf_init(tp); + max_pktsize[0] = size; + + rc = mdss_dsi_cmd_dma_add(tp, &pkt_size_cmd); + if (!rc) { + pr_err("%s: failed to add max_pkt_size\n", __func__); + return -EINVAL; + } + + rc = msm_dsi_wait4video_eng_busy(ctrl); + if (rc) { + pr_err("%s: failed to wait4video_eng\n", __func__); + return rc; + } + + rc = msm_dsi_cmd_dma_tx(ctrl, tp); + if (IS_ERR_VALUE(rc)) { + pr_err("%s: failed to tx max_pkt_size\n", __func__); + return rc; + } + pr_debug("%s: max_pkt_size=%d sent\n", __func__, size); + return rc; +} + +/* read data length is less than or equal to 10 bytes*/ +static int msm_dsi_cmds_rx_1(struct mdss_dsi_ctrl_pdata *ctrl, + struct dsi_cmd_desc *cmds, int rlen) +{ + int rc; + struct dsi_buf *tp, *rp; + + tp = &ctrl->tx_buf; + rp = &ctrl->rx_buf; + mdss_dsi_buf_init(rp); + mdss_dsi_buf_init(tp); + + rc = mdss_dsi_cmd_dma_add(tp, cmds); + if (!rc) { + pr_err("%s: dsi_cmd_dma_add failed\n", __func__); + rc = -EINVAL; + goto dsi_cmds_rx_1_error; + } + + rc = msm_dsi_wait4video_eng_busy(ctrl); + if (rc) { + pr_err("%s: wait4video_eng failed\n", __func__); + goto dsi_cmds_rx_1_error; + } + + rc = msm_dsi_cmd_dma_tx(ctrl, tp); + if (IS_ERR_VALUE(rc)) { + pr_err("%s: msm_dsi_cmd_dma_tx failed\n", __func__); + goto dsi_cmds_rx_1_error; + } + + if (rlen <= DSI_SHORT_PKT_DATA_SIZE) { + msm_dsi_cmd_dma_rx(ctrl, rp, rlen); + } else { + msm_dsi_cmd_dma_rx(ctrl, rp, rlen + DSI_HOST_HDR_SIZE); + rp->len = rlen + DSI_HOST_HDR_SIZE; + } + rc = msm_dsi_parse_rx_response(rp); + +dsi_cmds_rx_1_error: + if (rc) + rp->len = 0; + + return rc; +} + +/* read data length is more than 10 bytes, which requires multiple DSI read*/ +static int msm_dsi_cmds_rx_2(struct mdss_dsi_ctrl_pdata *ctrl, + struct dsi_cmd_desc *cmds, int rlen) +{ + int rc; + struct dsi_buf *tp, *rp; + int pkt_size, data_bytes, total; + + tp = &ctrl->tx_buf; + rp = &ctrl->rx_buf; + mdss_dsi_buf_init(rp); + pkt_size = DSI_MAX_PKT_SIZE; + data_bytes = MDSS_DSI_LEN; + total = 0; + + while (true) { + rc = msm_dsi_set_max_packet_size(ctrl, pkt_size); + if (rc) + break; + + mdss_dsi_buf_init(tp); + rc = mdss_dsi_cmd_dma_add(tp, cmds); + if (!rc) { + pr_err("%s: dsi_cmd_dma_add failed\n", __func__); + rc = -EINVAL; + break; + } + rc = msm_dsi_wait4video_eng_busy(ctrl); + if (rc) { + pr_err("%s: wait4video_eng failed\n", __func__); + break; + } + + rc = msm_dsi_cmd_dma_tx(ctrl, tp); + if (IS_ERR_VALUE(rc)) { + pr_err("%s: msm_dsi_cmd_dma_tx failed\n", __func__); + break; + } + + msm_dsi_cmd_dma_rx(ctrl, rp, DSI_MAX_BYTES_TO_READ); + + rp->data += DSI_MAX_BYTES_TO_READ - DSI_HOST_HDR_SIZE; + total += data_bytes; + if (total >= rlen) + break; + + data_bytes = DSI_MAX_BYTES_TO_READ - DSI_HOST_HDR_SIZE; + pkt_size += data_bytes; + } + + if (!rc) { + rp->data = rp->start; + rp->len = rlen + DSI_HOST_HDR_SIZE; + rc = msm_dsi_parse_rx_response(rp); + } + + if (rc) + rp->len = 0; + + return rc; +} + +int msm_dsi_cmds_rx(struct mdss_dsi_ctrl_pdata *ctrl, + struct dsi_cmd_desc *cmds, int rlen) +{ + int rc; + + if (rlen <= DSI_MAX_PKT_SIZE) + rc = msm_dsi_cmds_rx_1(ctrl, cmds, rlen); + else + rc = msm_dsi_cmds_rx_2(ctrl, cmds, rlen); + + return rc; +} + +void msm_dsi_cmdlist_tx(struct mdss_dsi_ctrl_pdata *ctrl, + struct dcs_cmd_req *req) +{ + int ret; + + ret = msm_dsi_cmds_tx(ctrl, req->cmds, req->cmds_cnt); + + if (req->cb) + req->cb(ret); +} + +void msm_dsi_cmdlist_rx(struct mdss_dsi_ctrl_pdata *ctrl, + struct dcs_cmd_req *req) +{ + struct dsi_buf *rp; + int len = 0; + + if (req->rbuf) { + rp = &ctrl->rx_buf; + len = msm_dsi_cmds_rx(ctrl, req->cmds, req->rlen); + memcpy(req->rbuf, rp->data, rp->len); + } else { + pr_err("%s: No rx buffer provided\n", __func__); + } + + if (req->cb) + req->cb(len); +} +int msm_dsi_cmdlist_commit(struct mdss_dsi_ctrl_pdata *ctrl, int from_mdp) +{ + struct dcs_cmd_req *req; + int dsi_on; + int ret = -EINVAL; + + mutex_lock(&ctrl->mutex); + dsi_on = dsi_host_private->dsi_on; + mutex_unlock(&ctrl->mutex); + if (!dsi_on) { + pr_err("try to send DSI commands while dsi is off\n"); + return ret; + } + + if (from_mdp) /* from mdp kickoff */ + mutex_lock(&ctrl->cmd_mutex); + req = mdss_dsi_cmdlist_get(ctrl, from_mdp); + + if (!req) { + mutex_unlock(&ctrl->cmd_mutex); + return ret; + } + /* + * mdss interrupt is generated in mdp core clock domain + * mdp clock need to be enabled to receive dsi interrupt + * also, axi bus bandwidth need since dsi controller will + * fetch dcs commands from axi bus + */ + mdp3_res_update(1, 1, MDP3_CLIENT_DMA_P); + msm_dsi_clk_ctrl(&ctrl->panel_data, 1); + + if (0 == (req->flags & CMD_REQ_LP_MODE)) + dsi_set_tx_power_mode(0); + + if (req->flags & CMD_REQ_RX) + msm_dsi_cmdlist_rx(ctrl, req); + else + msm_dsi_cmdlist_tx(ctrl, req); + + if (0 == (req->flags & CMD_REQ_LP_MODE)) + dsi_set_tx_power_mode(1); + + msm_dsi_clk_ctrl(&ctrl->panel_data, 0); + mdp3_res_update(0, 1, MDP3_CLIENT_DMA_P); + + if (from_mdp) /* from mdp kickoff */ + mutex_unlock(&ctrl->cmd_mutex); + return 0; +} + +static int msm_dsi_cal_clk_rate(struct mdss_panel_data *pdata, + u64 *bitclk_rate, + u32 *dsiclk_rate, + u32 *byteclk_rate, + u32 *pclk_rate) +{ + struct mdss_panel_info *pinfo; + struct mipi_panel_info *mipi; + u32 hbp, hfp, vbp, vfp, hspw, vspw, width, height; + int lanes; + u64 clk_rate; + + pinfo = &pdata->panel_info; + mipi = &pdata->panel_info.mipi; + + hbp = pdata->panel_info.lcdc.h_back_porch; + hfp = pdata->panel_info.lcdc.h_front_porch; + vbp = pdata->panel_info.lcdc.v_back_porch; + vfp = pdata->panel_info.lcdc.v_front_porch; + hspw = pdata->panel_info.lcdc.h_pulse_width; + vspw = pdata->panel_info.lcdc.v_pulse_width; + width = pdata->panel_info.xres; + height = pdata->panel_info.yres; + + lanes = 0; + if (mipi->data_lane0) + lanes++; + if (mipi->data_lane1) + lanes++; + if (mipi->data_lane2) + lanes++; + if (mipi->data_lane3) + lanes++; + if (lanes == 0) + return -EINVAL; + + *bitclk_rate = (width + hbp + hfp + hspw) * (height + vbp + vfp + vspw); + *bitclk_rate *= mipi->frame_rate; + *bitclk_rate *= pdata->panel_info.bpp; + do_div(*bitclk_rate, lanes); + clk_rate = *bitclk_rate; + + do_div(clk_rate, 8U); + *byteclk_rate = (u32) clk_rate; + *dsiclk_rate = *byteclk_rate * lanes; + *pclk_rate = *byteclk_rate * lanes * 8 / pdata->panel_info.bpp; + + pr_debug("dsiclk_rate=%u, byteclk=%u, pck_=%u\n", + *dsiclk_rate, *byteclk_rate, *pclk_rate); + return 0; +} + +static int msm_dsi_on(struct mdss_panel_data *pdata) +{ + int ret = 0, i; + u64 clk_rate; + struct mdss_panel_info *pinfo; + struct mipi_panel_info *mipi; + u32 hbp, hfp, vbp, vfp, hspw, vspw, width, height; + u32 ystride, bpp, data; + u32 dummy_xres, dummy_yres; + u64 bitclk_rate = 0 + u32 byteclk_rate = 0, pclk_rate = 0, dsiclk_rate = 0; + unsigned char *ctrl_base = dsi_host_private->dsi_base; + struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL; + + pr_debug("%s\n", __func__); + + pinfo = &pdata->panel_info; + + ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata, + panel_data); + + mutex_lock(&ctrl_pdata->mutex); + + + if (!pdata->panel_info.dynamic_switch_pending) { + for (i = 0; !ret && (i < DSI_MAX_PM); i++) { + ret = msm_mdss_enable_vreg( + ctrl_pdata->power_data[i].vreg_config, + ctrl_pdata->power_data[i].num_vreg, 1); + if (ret) { + pr_err("%s: failed to enable vregs for %s\n", + __func__, __mdss_dsi_pm_name(i)); + goto error_vreg; + } + } + } + + msm_dsi_ahb_ctrl(1); + msm_dsi_phy_sw_reset(dsi_host_private->dsi_base); + msm_dsi_phy_init(dsi_host_private->dsi_base, pdata); + + msm_dsi_cal_clk_rate(pdata, &bitclk_rate, &dsiclk_rate, + &byteclk_rate, &pclk_rate); + msm_dsi_clk_set_rate(DSI_ESC_CLK_RATE, dsiclk_rate, + byteclk_rate, pclk_rate); + msm_dsi_prepare_clocks(); + msm_dsi_clk_enable(); + + clk_rate = pdata->panel_info.clk_rate; + clk_rate = min(clk_rate, pdata->panel_info.clk_max); + + hbp = pdata->panel_info.lcdc.h_back_porch; + hfp = pdata->panel_info.lcdc.h_front_porch; + vbp = pdata->panel_info.lcdc.v_back_porch; + vfp = pdata->panel_info.lcdc.v_front_porch; + hspw = pdata->panel_info.lcdc.h_pulse_width; + vspw = pdata->panel_info.lcdc.v_pulse_width; + width = pdata->panel_info.xres; + height = pdata->panel_info.yres; + + mipi = &pdata->panel_info.mipi; + if (pdata->panel_info.type == MIPI_VIDEO_PANEL) { + dummy_xres = pdata->panel_info.lcdc.xres_pad; + dummy_yres = pdata->panel_info.lcdc.yres_pad; + + MIPI_OUTP(ctrl_base + DSI_VIDEO_MODE_ACTIVE_H, + ((hspw + hbp + width + dummy_xres) << 16 | + (hspw + hbp))); + MIPI_OUTP(ctrl_base + DSI_VIDEO_MODE_ACTIVE_V, + ((vspw + vbp + height + dummy_yres) << 16 | + (vspw + vbp))); + MIPI_OUTP(ctrl_base + DSI_VIDEO_MODE_TOTAL, + (vspw + vbp + height + dummy_yres + + vfp - 1) << 16 | (hspw + hbp + + width + dummy_xres + hfp - 1)); + + MIPI_OUTP(ctrl_base + DSI_VIDEO_MODE_HSYNC, (hspw << 16)); + MIPI_OUTP(ctrl_base + DSI_VIDEO_MODE_VSYNC, 0); + MIPI_OUTP(ctrl_base + DSI_VIDEO_MODE_VSYNC_VPOS, + (vspw << 16)); + + } else { /* command mode */ + if (mipi->dst_format == DSI_CMD_DST_FORMAT_RGB888) + bpp = 3; + else if (mipi->dst_format == DSI_CMD_DST_FORMAT_RGB666) + bpp = 3; + else if (mipi->dst_format == DSI_CMD_DST_FORMAT_RGB565) + bpp = 2; + else + bpp = 3; /* Default format set to RGB888 */ + + ystride = width * bpp + 1; + + data = (ystride << 16) | (mipi->vc << 8) | DTYPE_DCS_LWRITE; + MIPI_OUTP(ctrl_base + DSI_COMMAND_MODE_MDP_STREAM0_CTRL, + data); + MIPI_OUTP(ctrl_base + DSI_COMMAND_MODE_MDP_STREAM1_CTRL, + data); + + data = height << 16 | width; + MIPI_OUTP(ctrl_base + DSI_COMMAND_MODE_MDP_STREAM1_TOTAL, + data); + MIPI_OUTP(ctrl_base + DSI_COMMAND_MODE_MDP_STREAM0_TOTAL, + data); + } + + msm_dsi_sw_reset(); + msm_dsi_host_init(pdata); + + if (mipi->force_clk_lane_hs) { + u32 tmp; + + tmp = MIPI_INP(ctrl_base + DSI_LANE_CTRL); + tmp |= (1<<28); + MIPI_OUTP(ctrl_base + DSI_LANE_CTRL, tmp); + wmb(); /* ensure write is finished before progressing */ + } + + msm_dsi_op_mode_config(mipi->mode, pdata); + + msm_dsi_set_irq(ctrl_pdata, DSI_INTR_ERROR_MASK); + dsi_host_private->clk_count = 1; + dsi_host_private->dsi_on = 1; + +error_vreg: + if (ret) { + for (; i >= 0; i--) + msm_mdss_enable_vreg( + ctrl_pdata->power_data[i].vreg_config, + ctrl_pdata->power_data[i].num_vreg, 0); + } + + mutex_unlock(&ctrl_pdata->mutex); + return ret; +} + +static int msm_dsi_off(struct mdss_panel_data *pdata) +{ + int ret = 0, i; + struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL; + + if (pdata == NULL) { + pr_err("%s: Invalid input data\n", __func__); + ret = -EINVAL; + return ret; + } + + ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata, + panel_data); + + pr_debug("%s\n", __func__); + mutex_lock(&ctrl_pdata->mutex); + msm_dsi_clear_irq(ctrl_pdata, ctrl_pdata->dsi_irq_mask); + msm_dsi_controller_cfg(0); + msm_dsi_clk_set_rate(DSI_ESC_CLK_RATE, 0, 0, 0); + msm_dsi_clk_disable(); + msm_dsi_unprepare_clocks(); + msm_dsi_phy_off(dsi_host_private->dsi_base); + msm_dsi_ahb_ctrl(0); + + if (!pdata->panel_info.dynamic_switch_pending) { + for (i = DSI_MAX_PM - 1; i >= 0; i--) { + ret = msm_mdss_enable_vreg( + ctrl_pdata->power_data[i].vreg_config, + ctrl_pdata->power_data[i].num_vreg, 0); + if (ret) + pr_err("%s: failed to disable vregs for %s\n", + __func__, __mdss_dsi_pm_name(i)); + } + } + dsi_host_private->clk_count = 0; + dsi_host_private->dsi_on = 0; + + mutex_unlock(&ctrl_pdata->mutex); + + return ret; +} + +static int msm_dsi_cont_on(struct mdss_panel_data *pdata) +{ + struct mdss_panel_info *pinfo; + int ret = 0, i; + struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL; + + if (pdata == NULL) { + pr_err("%s: Invalid input data\n", __func__); + ret = -EINVAL; + return ret; + } + + + pr_debug("%s:\n", __func__); + + ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata, + panel_data); + + pinfo = &pdata->panel_info; + mutex_lock(&ctrl_pdata->mutex); + for (i = 0; !ret && (i < DSI_MAX_PM); i++) { + ret = msm_mdss_enable_vreg( + ctrl_pdata->power_data[i].vreg_config, + ctrl_pdata->power_data[i].num_vreg, 1); + if (ret) { + pr_err("%s: failed to enable vregs for %s\n", + __func__, __mdss_dsi_pm_name(i)); + goto error_vreg; + } + } + pinfo->panel_power_state = MDSS_PANEL_POWER_ON; + ret = mdss_dsi_panel_reset(pdata, 1); + if (ret) { + pr_err("%s: Panel reset failed\n", __func__); + mutex_unlock(&ctrl_pdata->mutex); + return ret; + } + + msm_dsi_ahb_ctrl(1); + msm_dsi_prepare_clocks(); + msm_dsi_clk_enable(); + msm_dsi_set_irq(ctrl_pdata, DSI_INTR_ERROR_MASK); + dsi_host_private->clk_count = 1; + dsi_host_private->dsi_on = 1; + +error_vreg: + if (ret) { + for (; i >= 0; i--) + msm_mdss_enable_vreg( + ctrl_pdata->power_data[i].vreg_config, + ctrl_pdata->power_data[i].num_vreg, 0); + } + + mutex_unlock(&ctrl_pdata->mutex); + return ret; +} + +static int msm_dsi_read_status(struct mdss_dsi_ctrl_pdata *ctrl) +{ + struct dcs_cmd_req cmdreq; + + memset(&cmdreq, 0, sizeof(cmdreq)); + cmdreq.cmds = ctrl->status_cmds.cmds; + cmdreq.cmds_cnt = ctrl->status_cmds.cmd_cnt; + cmdreq.flags = CMD_REQ_COMMIT | CMD_REQ_RX; + cmdreq.rlen = 1; + cmdreq.cb = NULL; + cmdreq.rbuf = ctrl->status_buf.data; + + return mdss_dsi_cmdlist_put(ctrl, &cmdreq); +} + + +/** + * msm_dsi_reg_status_check() - Check dsi panel status through reg read + * @ctrl_pdata: pointer to the dsi controller structure + * + * This function can be used to check the panel status through reading the + * status register from the panel. + * + * Return: positive value if the panel is in good state, negative value or + * zero otherwise. + */ +int msm_dsi_reg_status_check(struct mdss_dsi_ctrl_pdata *ctrl_pdata) +{ + int ret = 0; + + if (ctrl_pdata == NULL) { + pr_err("%s: Invalid input data\n", __func__); + return 0; + } + + pr_debug("%s: Checking Register status\n", __func__); + + msm_dsi_clk_ctrl(&ctrl_pdata->panel_data, 1); + + if (ctrl_pdata->status_cmds.link_state == DSI_HS_MODE) + dsi_set_tx_power_mode(0); + + ret = msm_dsi_read_status(ctrl_pdata); + + if (ctrl_pdata->status_cmds.link_state == DSI_HS_MODE) + dsi_set_tx_power_mode(1); + + if (ret == 0) { + if (!mdss_dsi_cmp_panel_reg(ctrl_pdata->status_buf, + ctrl_pdata->status_value, 0)) { + pr_err("%s: Read back value from panel is incorrect\n", + __func__); + ret = -EINVAL; + } else { + ret = 1; + } + } else { + pr_err("%s: Read status register returned error\n", __func__); + } + + msm_dsi_clk_ctrl(&ctrl_pdata->panel_data, 0); + pr_debug("%s: Read register done with ret: %d\n", __func__, ret); + + return ret; +} + +/** + * msm_dsi_bta_status_check() - Check dsi panel status through bta check + * @ctrl_pdata: pointer to the dsi controller structure + * + * This function can be used to check status of the panel using bta check + * for the panel. + * + * Return: positive value if the panel is in good state, negative value or + * zero otherwise. + */ +static int msm_dsi_bta_status_check(struct mdss_dsi_ctrl_pdata *ctrl_pdata) +{ + int ret = 0; + + if (ctrl_pdata == NULL) { + pr_err("%s: Invalid input data\n", __func__); + return 0; + } + + mutex_lock(&ctrl_pdata->cmd_mutex); + msm_dsi_clk_ctrl(&ctrl_pdata->panel_data, 1); + msm_dsi_cmd_mdp_busy(ctrl_pdata); + msm_dsi_set_irq(ctrl_pdata, DSI_INTR_BTA_DONE_MASK); + reinit_completion(&ctrl_pdata->bta_comp); + + /* BTA trigger */ + MIPI_OUTP(dsi_host_private->dsi_base + DSI_CMD_MODE_BTA_SW_TRIGGER, + 0x01); + wmb(); /* ensure write is finished before progressing */ + ret = wait_for_completion_killable_timeout(&ctrl_pdata->bta_comp, + HZ/10); + msm_dsi_clear_irq(ctrl_pdata, DSI_INTR_BTA_DONE_MASK); + msm_dsi_clk_ctrl(&ctrl_pdata->panel_data, 0); + mutex_unlock(&ctrl_pdata->cmd_mutex); + + if (ret <= 0) + pr_err("%s: DSI BTA error: %i\n", __func__, __LINE__); + + pr_debug("%s: BTA done with ret: %d\n", __func__, ret); + return ret; +} + +static void msm_dsi_debug_enable_clock(int on) +{ + if (dsi_host_private->debug_enable_clk) + dsi_host_private->debug_enable_clk(on); + + if (on) + msm_dsi_ahb_ctrl(1); + else + msm_dsi_ahb_ctrl(0); +} + +static int msm_dsi_debug_init(void) +{ + int rc; + + if (!mdss_res) + return 0; + + dsi_host_private->debug_enable_clk = + mdss_res->debug_inf.debug_enable_clock; + + mdss_res->debug_inf.debug_enable_clock = msm_dsi_debug_enable_clock; + + + rc = mdss_debug_register_base("dsi0", + dsi_host_private->dsi_base, + dsi_host_private->dsi_reg_size, + NULL); + + return rc; +} + +static int dsi_get_panel_cfg(char *panel_cfg) +{ + int rc; + struct mdss_panel_cfg *pan_cfg = NULL; + + if (!panel_cfg) + return MDSS_PANEL_INTF_INVALID; + + pan_cfg = mdp3_panel_intf_type(MDSS_PANEL_INTF_DSI); + if (IS_ERR(pan_cfg)) { + panel_cfg[0] = 0; + return PTR_ERR(pan_cfg); + } else if (!pan_cfg) { + panel_cfg[0] = 0; + return 0; + } + + pr_debug("%s:%d: cfg:[%s]\n", __func__, __LINE__, + pan_cfg->arg_cfg); + rc = strlcpy(panel_cfg, pan_cfg->arg_cfg, + MDSS_MAX_PANEL_LEN); + return rc; +} + +static struct device_node *dsi_pref_prim_panel( + struct platform_device *pdev) +{ + struct device_node *dsi_pan_node = NULL; + + pr_debug("%s:%d: Select primary panel from dt\n", + __func__, __LINE__); + dsi_pan_node = of_parse_phandle(pdev->dev.of_node, + "qcom,dsi-pref-prim-pan", 0); + if (!dsi_pan_node) + pr_err("%s:can't find panel phandle\n", __func__); + + return dsi_pan_node; +} + +/** + * dsi_find_panel_of_node(): find device node of dsi panel + * @pdev: platform_device of the dsi ctrl node + * @panel_cfg: string containing intf specific config data + * + * Function finds the panel device node using the interface + * specific configuration data. This configuration data is + * could be derived from the result of bootloader's GCDB + * panel detection mechanism. If such config data doesn't + * exist then this panel returns the default panel configured + * in the device tree. + * + * returns pointer to panel node on success, NULL on error. + */ +static struct device_node *dsi_find_panel_of_node( + struct platform_device *pdev, char *panel_cfg) +{ + int l; + char *panel_name; + struct device_node *dsi_pan_node = NULL, *mdss_node = NULL; + + if (!panel_cfg) + return NULL; + + l = strlen(panel_cfg); + if (!l) { + /* no panel cfg chg, parse dt */ + pr_debug("%s:%d: no cmd line cfg present\n", + __func__, __LINE__); + dsi_pan_node = dsi_pref_prim_panel(pdev); + } else { + if (panel_cfg[0] != '0') { + pr_err("%s:%d:ctrl id=[%d] not supported\n", + __func__, __LINE__, panel_cfg[0]); + return NULL; + } + /* + * skip first two chars '' and + * ':' to get to the panel name + */ + panel_name = panel_cfg + 2; + pr_debug("%s:%d:%s:%s\n", __func__, __LINE__, + panel_cfg, panel_name); + + mdss_node = of_parse_phandle(pdev->dev.of_node, + "qcom,mdss-mdp", 0); + + if (!mdss_node) { + pr_err("%s: %d: mdss_node null\n", + __func__, __LINE__); + return NULL; + } + dsi_pan_node = of_find_node_by_name(mdss_node, + panel_name); + if (!dsi_pan_node) { + pr_err("%s: invalid pan node\n", + __func__); + dsi_pan_node = dsi_pref_prim_panel(pdev); + } + } + return dsi_pan_node; +} + +static int msm_dsi_clk_ctrl(struct mdss_panel_data *pdata, int enable) +{ + u32 bitclk_rate = 0, byteclk_rate = 0, pclk_rate = 0, dsiclk_rate = 0; + struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL; + + pr_debug("%s:\n", __func__); + + ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata, + panel_data); + + mutex_lock(&ctrl_pdata->mutex); + + if (enable) { + dsi_host_private->clk_count++; + if (dsi_host_private->clk_count == 1) { + msm_dsi_ahb_ctrl(1); + msm_dsi_cal_clk_rate(pdata, &bitclk_rate, &dsiclk_rate, + &byteclk_rate, &pclk_rate); + msm_dsi_clk_set_rate(DSI_ESC_CLK_RATE, dsiclk_rate, + byteclk_rate, pclk_rate); + msm_dsi_prepare_clocks(); + msm_dsi_clk_enable(); + } + } else { + dsi_host_private->clk_count--; + if (dsi_host_private->clk_count == 0) { + msm_dsi_clear_irq(ctrl_pdata, ctrl_pdata->dsi_irq_mask); + msm_dsi_clk_set_rate(DSI_ESC_CLK_RATE, 0, 0, 0); + msm_dsi_clk_disable(); + msm_dsi_unprepare_clocks(); + msm_dsi_ahb_ctrl(0); + } + } + mutex_unlock(&ctrl_pdata->mutex); + return 0; +} + +void msm_dsi_ctrl_init(struct mdss_dsi_ctrl_pdata *ctrl) +{ + init_completion(&ctrl->dma_comp); + init_completion(&ctrl->mdp_comp); + init_completion(&ctrl->bta_comp); + init_completion(&ctrl->video_comp); + spin_lock_init(&ctrl->irq_lock); + spin_lock_init(&ctrl->mdp_lock); + mutex_init(&ctrl->mutex); + mutex_init(&ctrl->cmd_mutex); + complete(&ctrl->mdp_comp); + dsi_buf_alloc(&ctrl->tx_buf, SZ_4K); + dsi_buf_alloc(&ctrl->rx_buf, SZ_4K); + dsi_buf_alloc(&ctrl->status_buf, SZ_4K); + ctrl->cmdlist_commit = msm_dsi_cmdlist_commit; + ctrl->panel_mode = ctrl->panel_data.panel_info.mipi.mode; + + if (ctrl->status_mode == ESD_REG) + ctrl->check_status = msm_dsi_reg_status_check; + else if (ctrl->status_mode == ESD_BTA) + ctrl->check_status = msm_dsi_bta_status_check; + + if (ctrl->status_mode == ESD_MAX) { + pr_err("%s: Using default BTA for ESD check\n", __func__); + ctrl->check_status = msm_dsi_bta_status_check; + } +} + +static void msm_dsi_parse_lane_swap(struct device_node *np, char *dlane_swap) +{ + const char *data; + + *dlane_swap = DSI_LANE_MAP_0123; + data = of_get_property(np, "qcom,lane-map", NULL); + if (data) { + if (!strcmp(data, "lane_map_3012")) + *dlane_swap = DSI_LANE_MAP_3012; + else if (!strcmp(data, "lane_map_2301")) + *dlane_swap = DSI_LANE_MAP_2301; + else if (!strcmp(data, "lane_map_1230")) + *dlane_swap = DSI_LANE_MAP_1230; + else if (!strcmp(data, "lane_map_0321")) + *dlane_swap = DSI_LANE_MAP_0321; + else if (!strcmp(data, "lane_map_1032")) + *dlane_swap = DSI_LANE_MAP_1032; + else if (!strcmp(data, "lane_map_2103")) + *dlane_swap = DSI_LANE_MAP_2103; + else if (!strcmp(data, "lane_map_3210")) + *dlane_swap = DSI_LANE_MAP_3210; + } +} + +static int msm_dsi_probe(struct platform_device *pdev) +{ + struct dsi_interface intf; + char panel_cfg[MDSS_MAX_PANEL_LEN]; + struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL; + int rc = 0; + struct device_node *dsi_pan_node = NULL; + bool cmd_cfg_cont_splash = false; + struct resource *mdss_dsi_mres; + int i; + + pr_debug("%s\n", __func__); + + rc = msm_dsi_init(); + if (rc) + return rc; + + if (!pdev->dev.of_node) { + pr_err("%s: Device node is not accessible\n", __func__); + rc = -ENODEV; + goto error_no_mem; + } + pdev->id = 0; + + ctrl_pdata = platform_get_drvdata(pdev); + if (!ctrl_pdata) { + ctrl_pdata = devm_kzalloc(&pdev->dev, + sizeof(struct mdss_dsi_ctrl_pdata), GFP_KERNEL); + if (!ctrl_pdata) { + rc = -ENOMEM; + goto error_no_mem; + } + platform_set_drvdata(pdev, ctrl_pdata); + } + + ctrl_pdata->mdss_util = mdss_get_util_intf(); + if (mdp3_res->mdss_util == NULL) { + pr_err("Failed to get mdss utility functions\n"); + return -ENODEV; + } + + mdss_dsi_mres = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!mdss_dsi_mres) { + pr_err("%s:%d unable to get the MDSS reg resources", + __func__, __LINE__); + rc = -ENOMEM; + goto error_io_resource; + } else { + dsi_host_private->dsi_reg_size = resource_size(mdss_dsi_mres); + dsi_host_private->dsi_base = ioremap(mdss_dsi_mres->start, + dsi_host_private->dsi_reg_size); + if (!dsi_host_private->dsi_base) { + pr_err("%s:%d unable to remap dsi resources", + __func__, __LINE__); + rc = -ENOMEM; + goto error_io_resource; + } + } + + mdss_dsi_mres = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + if (!mdss_dsi_mres || mdss_dsi_mres->start == 0) { + pr_err("%s:%d unable to get the MDSS irq resources", + __func__, __LINE__); + rc = -ENODEV; + goto error_irq_resource; + } + + rc = of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev); + if (rc) { + dev_err(&pdev->dev, "%s: failed to add child nodes, rc=%d\n", + __func__, rc); + goto error_platform_pop; + } + + /* DSI panels can be different between controllers */ + rc = dsi_get_panel_cfg(panel_cfg); + if (!rc) + /* dsi panel cfg not present */ + pr_warn("%s:%d:dsi specific cfg not present\n", + __func__, __LINE__); + + /* find panel device node */ + dsi_pan_node = dsi_find_panel_of_node(pdev, panel_cfg); + if (!dsi_pan_node) { + pr_err("%s: can't find panel node %s\n", __func__, + panel_cfg); + goto error_pan_node; + } + + cmd_cfg_cont_splash = mdp3_panel_get_boot_cfg() ? true : false; + + rc = mdss_dsi_panel_init(dsi_pan_node, ctrl_pdata, cmd_cfg_cont_splash); + if (rc) { + pr_err("%s: dsi panel init failed\n", __func__); + goto error_pan_node; + } + + rc = dsi_ctrl_config_init(pdev, ctrl_pdata); + if (rc) { + dev_err(&pdev->dev, "%s: failed to parse mdss dtsi rc=%d\n", + __func__, rc); + goto error_pan_node; + } + + msm_dsi_parse_lane_swap(pdev->dev.of_node, &(ctrl_pdata->dlane_swap)); + + for (i = 0; i < DSI_MAX_PM; i++) { + rc = msm_dsi_io_init(pdev, &(ctrl_pdata->power_data[i])); + if (rc) { + dev_err(&pdev->dev, "%s: failed to init IO for %s\n", + __func__, __mdss_dsi_pm_name(i)); + goto error_io_init; + } + } + + pr_debug("%s: Dsi Ctrl->0 initialized\n", __func__); + + dsi_host_private->dis_dev = pdev->dev; + intf.on = msm_dsi_on; + intf.off = msm_dsi_off; + intf.cont_on = msm_dsi_cont_on; + intf.clk_ctrl = msm_dsi_clk_ctrl; + intf.op_mode_config = msm_dsi_op_mode_config; + intf.index = 0; + intf.private = NULL; + dsi_register_interface(&intf); + + msm_dsi_debug_init(); + + msm_dsi_ctrl_init(ctrl_pdata); + + rc = msm_dsi_irq_init(&pdev->dev, mdss_dsi_mres->start, + ctrl_pdata); + if (rc) { + dev_err(&pdev->dev, "%s: failed to init irq, rc=%d\n", + __func__, rc); + goto error_irq_init; + } + + rc = dsi_panel_device_register_v2(pdev, ctrl_pdata); + if (rc) { + pr_err("%s: dsi panel dev reg failed\n", __func__); + goto error_device_register; + } + pr_debug("%s success\n", __func__); + return 0; +error_device_register: + kfree(ctrl_pdata->dsi_hw->irq_info); + kfree(ctrl_pdata->dsi_hw); +error_irq_init: + for (i = DSI_MAX_PM - 1; i >= 0; i--) + msm_dsi_io_deinit(pdev, &(ctrl_pdata->power_data[i])); +error_io_init: + dsi_ctrl_config_deinit(pdev, ctrl_pdata); +error_pan_node: + of_node_put(dsi_pan_node); +error_platform_pop: + msm_dsi_clear_irq(ctrl_pdata, ctrl_pdata->dsi_irq_mask); +error_irq_resource: + if (dsi_host_private->dsi_base) { + iounmap(dsi_host_private->dsi_base); + dsi_host_private->dsi_base = NULL; + } +error_io_resource: + devm_kfree(&pdev->dev, ctrl_pdata); +error_no_mem: + msm_dsi_deinit(); + + return rc; +} + +static int msm_dsi_remove(struct platform_device *pdev) +{ + int i; + struct mdss_dsi_ctrl_pdata *ctrl_pdata = platform_get_drvdata(pdev); + + if (!ctrl_pdata) { + pr_err("%s: no driver data\n", __func__); + return -ENODEV; + } + + msm_dsi_clear_irq(ctrl_pdata, ctrl_pdata->dsi_irq_mask); + for (i = DSI_MAX_PM - 1; i >= 0; i--) + msm_dsi_io_deinit(pdev, &(ctrl_pdata->power_data[i])); + dsi_ctrl_config_deinit(pdev, ctrl_pdata); + iounmap(dsi_host_private->dsi_base); + dsi_host_private->dsi_base = NULL; + msm_dsi_deinit(); + devm_kfree(&pdev->dev, ctrl_pdata); + + return 0; +} + +static const struct of_device_id msm_dsi_v2_dt_match[] = { + {.compatible = "qcom,msm-dsi-v2"}, + {} +}; +MODULE_DEVICE_TABLE(of, msm_dsi_v2_dt_match); + +static struct platform_driver msm_dsi_v2_driver = { + .probe = msm_dsi_probe, + .remove = msm_dsi_remove, + .shutdown = NULL, + .driver = { + .name = "qcom,dsi-panel-v2", + .of_match_table = msm_dsi_v2_dt_match, + }, +}; + +static int msm_dsi_v2_register_driver(void) +{ + return platform_driver_register(&msm_dsi_v2_driver); +} + +static int __init msm_dsi_v2_driver_init(void) +{ + int ret; + + ret = msm_dsi_v2_register_driver(); + if (ret) { + pr_err("msm_dsi_v2_register_driver() failed!\n"); + return ret; + } + + return ret; +} +module_init(msm_dsi_v2_driver_init); + +static void __exit msm_dsi_v2_driver_cleanup(void) +{ + platform_driver_unregister(&msm_dsi_v2_driver); +} +module_exit(msm_dsi_v2_driver_cleanup); diff --git a/drivers/video/fbdev/msm/dsi_host_v2.h b/drivers/video/fbdev/msm/dsi_host_v2.h new file mode 100644 index 000000000000..d61bcf9ea7f2 --- /dev/null +++ b/drivers/video/fbdev/msm/dsi_host_v2.h @@ -0,0 +1,178 @@ +/* Copyright (c) 2012-2014, 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +#ifndef DSI_HOST_V2_H +#define DSI_HOST_V2_H + +#include + +#define DSI_INTR_ERROR_MASK BIT(25) +#define DSI_INTR_ERROR BIT(24) +#define DSI_INTR_BTA_DONE_MASK BIT(21) +#define DSI_INTR_BTA_DONE BIT(20) +#define DSI_INTR_VIDEO_DONE_MASK BIT(17) +#define DSI_INTR_VIDEO_DONE BIT(16) +#define DSI_INTR_CMD_MDP_DONE_MASK BIT(9) +#define DSI_INTR_CMD_MDP_DONE BIT(8) +#define DSI_INTR_CMD_DMA_DONE_MASK BIT(1) +#define DSI_INTR_CMD_DMA_DONE BIT(0) +#define DSI_INTR_ALL_MASK 0x2220202 + +#define DSI_BTA_TERM BIT(1) + +#define DSI_CTRL 0x0000 +#define DSI_STATUS 0x0004 +#define DSI_FIFO_STATUS 0x0008 +#define DSI_VIDEO_MODE_CTRL 0x000C +#define DSI_VIDEO_MODE_DATA_CTRL 0x001C +#define DSI_VIDEO_MODE_ACTIVE_H 0x0020 +#define DSI_VIDEO_MODE_ACTIVE_V 0x0024 +#define DSI_VIDEO_MODE_TOTAL 0x0028 +#define DSI_VIDEO_MODE_HSYNC 0x002C +#define DSI_VIDEO_MODE_VSYNC 0x0030 +#define DSI_VIDEO_MODE_VSYNC_VPOS 0x0034 +#define DSI_COMMAND_MODE_DMA_CTRL 0x0038 +#define DSI_COMMAND_MODE_MDP_CTRL 0x003C +#define DSI_COMMAND_MODE_MDP_DCS_CMD_CTRL 0x0040 +#define DSI_DMA_CMD_OFFSET 0x0044 +#define DSI_DMA_CMD_LENGTH 0x0048 +#define DSI_DMA_FIFO_CTRL 0x004C +#define DSI_COMMAND_MODE_MDP_STREAM0_CTRL 0x0054 +#define DSI_COMMAND_MODE_MDP_STREAM0_TOTAL 0x0058 +#define DSI_COMMAND_MODE_MDP_STREAM1_CTRL 0x005C +#define DSI_COMMAND_MODE_MDP_STREAM1_TOTAL 0x0060 +#define DSI_ACK_ERR_STATUS 0x0064 +#define DSI_RDBK_DATA0 0x0068 +#define DSI_RDBK_DATA1 0x006C +#define DSI_RDBK_DATA2 0x0070 +#define DSI_RDBK_DATA3 0x0074 +#define DSI_RDBK_DATATYPE0 0x0078 +#define DSI_RDBK_DATATYPE1 0x007C +#define DSI_TRIG_CTRL 0x0080 +#define DSI_EXT_MUX 0x0084 +#define DSI_EXT_TE_PULSE_DETECT_CTRL 0x0088 +#define DSI_CMD_MODE_DMA_SW_TRIGGER 0x008C +#define DSI_CMD_MODE_MDP_SW_TRIGGER 0x0090 +#define DSI_CMD_MODE_BTA_SW_TRIGGER 0x0094 +#define DSI_RESET_SW_TRIGGER 0x0098 +#define DSI_LANE_CTRL 0x00A8 +#define DSI_LANE_SWAP_CTRL 0x00AC +#define DSI_DLN0_PHY_ERR 0x00B0 +#define DSI_TIMEOUT_STATUS 0x00BC +#define DSI_CLKOUT_TIMING_CTRL 0x00C0 +#define DSI_EOT_PACKET 0x00C4 +#define DSI_EOT_PACKET_CTRL 0x00C8 +#define DSI_ERR_INT_MASK0 0x0108 +#define DSI_INT_CTRL 0x010c +#define DSI_SOFT_RESET 0x0114 +#define DSI_CLK_CTRL 0x0118 +#define DSI_CLK_STATUS 0x011C +#define DSI_PHY_SW_RESET 0x0128 +#define DSI_COMMAND_MODE_MDP_IDLE_CTRL 0x0190 +#define DSI_VERSION 0x01F0 + +#define DSI_DSIPHY_PLL_CTRL_0 0x0200 +#define DSI_DSIPHY_PLL_CTRL_1 0x0204 +#define DSI_DSIPHY_PLL_CTRL_2 0x0208 +#define DSI_DSIPHY_PLL_CTRL_3 0x020C +#define DSI_DSIPHY_PLL_CTRL_4 0x0210 +#define DSI_DSIPHY_PLL_CTRL_5 0x0214 +#define DSI_DSIPHY_PLL_CTRL_6 0x0218 +#define DSI_DSIPHY_PLL_CTRL_7 0x021C +#define DSI_DSIPHY_PLL_CTRL_8 0x0220 +#define DSI_DSIPHY_PLL_CTRL_9 0x0224 +#define DSI_DSIPHY_PLL_CTRL_10 0x0228 +#define DSI_DSIPHY_PLL_CTRL_11 0x022C +#define DSI_DSIPHY_PLL_CTRL_12 0x0230 +#define DSI_DSIPHY_PLL_CTRL_13 0x0234 +#define DSI_DSIPHY_PLL_CTRL_14 0x0238 +#define DSI_DSIPHY_PLL_CTRL_15 0x023C +#define DSI_DSIPHY_PLL_CTRL_16 0x0240 +#define DSI_DSIPHY_PLL_CTRL_17 0x0244 +#define DSI_DSIPHY_PLL_CTRL_18 0x0248 +#define DSI_DSIPHY_PLL_CTRL_19 0x024C +#define DSI_DSIPHY_ANA_CTRL0 0x0260 +#define DSI_DSIPHY_ANA_CTRL1 0x0264 +#define DSI_DSIPHY_ANA_CTRL2 0x0268 +#define DSI_DSIPHY_ANA_CTRL3 0x026C +#define DSI_DSIPHY_ANA_CTRL4 0x0270 +#define DSI_DSIPHY_ANA_CTRL5 0x0274 +#define DSI_DSIPHY_ANA_CTRL6 0x0278 +#define DSI_DSIPHY_ANA_CTRL7 0x027C +#define DSI_DSIPHY_PLL_RDY 0x0280 +#define DSI_DSIPHY_PLL_ANA_STATUS0 0x0294 +#define DSI_DSIPHY_PLL_ANA_STATUS1 0x0298 +#define DSI_DSIPHY_PLL_ANA_STATUS2 0x029C +#define DSI_DSIPHY_LN0_CFG0 0x0300 +#define DSI_DSIPHY_LN0_CFG1 0x0304 +#define DSI_DSIPHY_LN0_CFG2 0x0308 +#define DSI_DSIPHY_LN1_CFG0 0x0340 +#define DSI_DSIPHY_LN1_CFG1 0x0344 +#define DSI_DSIPHY_LN1_CFG2 0x0348 +#define DSI_DSIPHY_LN2_CFG0 0x0380 +#define DSI_DSIPHY_LN2_CFG1 0x0384 +#define DSI_DSIPHY_LN2_CFG2 0x0388 +#define DSI_DSIPHY_LN3_CFG0 0x03C0 +#define DSI_DSIPHY_LN3_CFG1 0x03C4 +#define DSI_DSIPHY_LN3_CFG2 0x03C8 +#define DSI_DSIPHY_LNCK_CFG0 0x0400 +#define DSI_DSIPHY_LNCK_CFG1 0x0404 +#define DSI_DSIPHY_LNCK_CFG2 0x0408 +#define DSI_DSIPHY_TIMING_CTRL_0 0x0440 +#define DSI_DSIPHY_TIMING_CTRL_1 0x0444 +#define DSI_DSIPHY_TIMING_CTRL_2 0x0448 +#define DSI_DSIPHY_TIMING_CTRL_3 0x044C +#define DSI_DSIPHY_TIMING_CTRL_4 0x0450 +#define DSI_DSIPHY_TIMING_CTRL_5 0x0454 +#define DSI_DSIPHY_TIMING_CTRL_6 0x0458 +#define DSI_DSIPHY_TIMING_CTRL_7 0x045C +#define DSI_DSIPHY_TIMING_CTRL_8 0x0460 +#define DSI_DSIPHY_TIMING_CTRL_9 0x0464 +#define DSI_DSIPHY_TIMING_CTRL_10 0x0468 +#define DSI_DSIPHY_TIMING_CTRL_11 0x046C +#define DSI_DSIPHY_CTRL_0 0x0470 +#define DSI_DSIPHY_CTRL_1 0x0474 +#define DSI_DSIPHY_CTRL_2 0x0478 +#define DSI_DSIPHY_CTRL_3 0x047C +#define DSI_DSIPHY_STRENGTH_CTRL_0 0x0480 +#define DSI_DSIPHY_STRENGTH_CTRL_1 0x0484 +#define DSI_DSIPHY_STRENGTH_CTRL_2 0x0488 +#define DSI_DSIPHY_LDO_CNTRL 0x04B0 +#define DSI_DSIPHY_REGULATOR_CTRL_0 0x0500 +#define DSI_DSIPHY_REGULATOR_CTRL_1 0x0504 +#define DSI_DSIPHY_REGULATOR_CTRL_2 0x0508 +#define DSI_DSIPHY_REGULATOR_CTRL_3 0x050C +#define DSI_DSIPHY_REGULATOR_CTRL_4 0x0510 +#define DSI_DSIPHY_REGULATOR_TEST 0x0514 +#define DSI_DSIPHY_REGULATOR_CAL_PWR_CFG 0x0518 +#define DSI_DSIPHY_CAL_HW_TRIGGER 0x0528 +#define DSI_DSIPHY_CAL_SW_CFG0 0x052C +#define DSI_DSIPHY_CAL_SW_CFG1 0x0530 +#define DSI_DSIPHY_CAL_SW_CFG2 0x0534 +#define DSI_DSIPHY_CAL_HW_CFG0 0x0538 +#define DSI_DSIPHY_CAL_HW_CFG1 0x053C +#define DSI_DSIPHY_CAL_HW_CFG2 0x0540 +#define DSI_DSIPHY_CAL_HW_CFG3 0x0544 +#define DSI_DSIPHY_CAL_HW_CFG4 0x0548 +#define DSI_DSIPHY_REGULATOR_CAL_STATUS0 0x0550 +#define DSI_DSIPHY_BIST_CTRL0 0x048C +#define DSI_DSIPHY_BIST_CTRL1 0x0490 +#define DSI_DSIPHY_BIST_CTRL2 0x0494 +#define DSI_DSIPHY_BIST_CTRL3 0x0498 +#define DSI_DSIPHY_BIST_CTRL4 0x049C +#define DSI_DSIPHY_BIST_CTRL5 0x04A0 + +#define DSI_EN BIT(0) +#define DSI_VIDEO_MODE_EN BIT(1) +#define DSI_CMD_MODE_EN BIT(2) + +#endif /* DSI_HOST_V2_H */ diff --git a/drivers/video/fbdev/msm/dsi_io_v2.c b/drivers/video/fbdev/msm/dsi_io_v2.c new file mode 100644 index 000000000000..71c1d1d7c2a7 --- /dev/null +++ b/drivers/video/fbdev/msm/dsi_io_v2.c @@ -0,0 +1,389 @@ +/* Copyright (c) 2013, 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +#include +#include +#include +#include +#include +#include +#include + + +#include "dsi_v2.h" +#include "dsi_io_v2.h" +#include "dsi_host_v2.h" + +struct msm_dsi_io_private { + struct clk *dsi_byte_clk; + struct clk *dsi_esc_clk; + struct clk *dsi_pixel_clk; + struct clk *dsi_ahb_clk; + struct clk *dsi_clk; + int msm_dsi_clk_on; + int msm_dsi_ahb_clk_on; +}; + +static struct msm_dsi_io_private *dsi_io_private; + +#define DSI_VDDA_VOLTAGE 1200000 + +void msm_dsi_ahb_ctrl(int enable) +{ + if (enable) { + dsi_io_private->msm_dsi_ahb_clk_on++; + if (dsi_io_private->msm_dsi_ahb_clk_on == 1) + clk_enable(dsi_io_private->dsi_ahb_clk); + } else { + dsi_io_private->msm_dsi_ahb_clk_on--; + if (dsi_io_private->msm_dsi_ahb_clk_on == 0) + clk_disable(dsi_io_private->dsi_ahb_clk); + } +} + +int msm_dsi_io_init(struct platform_device *pdev, struct mdss_module_power *mp) +{ + int rc; + + if (!dsi_io_private) { + dsi_io_private = kzalloc(sizeof(struct msm_dsi_io_private), + GFP_KERNEL); + if (!dsi_io_private) + return -ENOMEM; + } + + rc = msm_dsi_clk_init(pdev); + if (rc) { + pr_err("fail to initialize DSI clock\n"); + return rc; + } + + rc = msm_mdss_config_vreg(&pdev->dev, mp->vreg_config, + mp->num_vreg, 1); + if (rc) { + pr_err("fail to initialize DSI regulator\n"); + return rc; + } + + return 0; +} + +void msm_dsi_io_deinit(struct platform_device *pdev, + struct mdss_module_power *mp) +{ + if (dsi_io_private) { + msm_dsi_clk_deinit(); + msm_mdss_config_vreg(&pdev->dev, mp->vreg_config, + mp->num_vreg, 0); + kfree(dsi_io_private); + dsi_io_private = NULL; + } +} + +int msm_dsi_clk_init(struct platform_device *dev) +{ + int rc = 0; + + dsi_io_private->dsi_clk = clk_get(&dev->dev, "dsi_clk"); + if (IS_ERR(dsi_io_private->dsi_clk)) { + pr_err("can't find dsi core_clk\n"); + rc = PTR_ERR(dsi_io_private->dsi_clk); + dsi_io_private->dsi_clk = NULL; + return rc; + } + dsi_io_private->dsi_byte_clk = clk_get(&dev->dev, "byte_clk"); + if (IS_ERR(dsi_io_private->dsi_byte_clk)) { + pr_err("can't find dsi byte_clk\n"); + rc = PTR_ERR(dsi_io_private->dsi_byte_clk); + dsi_io_private->dsi_byte_clk = NULL; + return rc; + } + + dsi_io_private->dsi_esc_clk = clk_get(&dev->dev, "esc_clk"); + if (IS_ERR(dsi_io_private->dsi_esc_clk)) { + pr_err("can't find dsi esc_clk\n"); + rc = PTR_ERR(dsi_io_private->dsi_esc_clk); + dsi_io_private->dsi_esc_clk = NULL; + return rc; + } + + dsi_io_private->dsi_pixel_clk = clk_get(&dev->dev, "pixel_clk"); + if (IS_ERR(dsi_io_private->dsi_pixel_clk)) { + pr_err("can't find dsi pixel\n"); + rc = PTR_ERR(dsi_io_private->dsi_pixel_clk); + dsi_io_private->dsi_pixel_clk = NULL; + return rc; + } + + dsi_io_private->dsi_ahb_clk = clk_get(&dev->dev, "iface_clk"); + if (IS_ERR(dsi_io_private->dsi_ahb_clk)) { + pr_err("can't find dsi iface_clk\n"); + rc = PTR_ERR(dsi_io_private->dsi_ahb_clk); + dsi_io_private->dsi_ahb_clk = NULL; + return rc; + } + clk_prepare(dsi_io_private->dsi_ahb_clk); + + return 0; +} + +void msm_dsi_clk_deinit(void) +{ + if (dsi_io_private->dsi_clk) { + clk_put(dsi_io_private->dsi_clk); + dsi_io_private->dsi_clk = NULL; + } + if (dsi_io_private->dsi_byte_clk) { + clk_put(dsi_io_private->dsi_byte_clk); + dsi_io_private->dsi_byte_clk = NULL; + } + if (dsi_io_private->dsi_esc_clk) { + clk_put(dsi_io_private->dsi_esc_clk); + dsi_io_private->dsi_esc_clk = NULL; + } + if (dsi_io_private->dsi_pixel_clk) { + clk_put(dsi_io_private->dsi_pixel_clk); + dsi_io_private->dsi_pixel_clk = NULL; + } + if (dsi_io_private->dsi_ahb_clk) { + clk_unprepare(dsi_io_private->dsi_ahb_clk); + clk_put(dsi_io_private->dsi_ahb_clk); + dsi_io_private->dsi_ahb_clk = NULL; + } +} + +int msm_dsi_prepare_clocks(void) +{ + clk_prepare(dsi_io_private->dsi_clk); + clk_prepare(dsi_io_private->dsi_byte_clk); + clk_prepare(dsi_io_private->dsi_esc_clk); + clk_prepare(dsi_io_private->dsi_pixel_clk); + return 0; +} + +int msm_dsi_unprepare_clocks(void) +{ + clk_unprepare(dsi_io_private->dsi_clk); + clk_unprepare(dsi_io_private->dsi_esc_clk); + clk_unprepare(dsi_io_private->dsi_byte_clk); + clk_unprepare(dsi_io_private->dsi_pixel_clk); + return 0; +} + +int msm_dsi_clk_set_rate(unsigned long esc_rate, + unsigned long dsi_rate, + unsigned long byte_rate, + unsigned long pixel_rate) +{ + int rc; + + rc = clk_set_rate(dsi_io_private->dsi_clk, dsi_rate); + if (rc) { + pr_err("dsi_esc_clk - clk_set_rate failed =%d\n", rc); + return rc; + } + + rc = clk_set_rate(dsi_io_private->dsi_esc_clk, esc_rate); + if (rc) { + pr_err("dsi_esc_clk - clk_set_rate failed =%d\n", rc); + return rc; + } + + rc = clk_set_rate(dsi_io_private->dsi_byte_clk, byte_rate); + if (rc) { + pr_err("dsi_byte_clk - clk_set_rate faile = %dd\n", rc); + return rc; + } + + rc = clk_set_rate(dsi_io_private->dsi_pixel_clk, pixel_rate); + if (rc) { + pr_err("dsi_pixel_clk - clk_set_rate failed = %d\n", rc); + return rc; + } + return 0; +} + +int msm_dsi_clk_enable(void) +{ + if (dsi_io_private->msm_dsi_clk_on) { + pr_debug("dsi_clks on already\n"); + return 0; + } + + clk_enable(dsi_io_private->dsi_clk); + clk_enable(dsi_io_private->dsi_esc_clk); + clk_enable(dsi_io_private->dsi_byte_clk); + clk_enable(dsi_io_private->dsi_pixel_clk); + + dsi_io_private->msm_dsi_clk_on = 1; + return 0; +} + +int msm_dsi_clk_disable(void) +{ + if (dsi_io_private->msm_dsi_clk_on == 0) { + pr_debug("mdss_dsi_clks already OFF\n"); + return 0; + } + + clk_disable(dsi_io_private->dsi_clk); + clk_disable(dsi_io_private->dsi_byte_clk); + clk_disable(dsi_io_private->dsi_esc_clk); + clk_disable(dsi_io_private->dsi_pixel_clk); + + dsi_io_private->msm_dsi_clk_on = 0; + return 0; +} + +static void msm_dsi_phy_strength_init(unsigned char *ctrl_base, + struct mdss_dsi_phy_ctrl *pd) +{ + MIPI_OUTP(ctrl_base + DSI_DSIPHY_STRENGTH_CTRL_0, pd->strength[0]); + MIPI_OUTP(ctrl_base + DSI_DSIPHY_STRENGTH_CTRL_2, pd->strength[1]); +} + +static void msm_dsi_phy_ctrl_init(unsigned char *ctrl_base, + struct mdss_panel_data *pdata) +{ + MIPI_OUTP(ctrl_base + DSI_DSIPHY_CTRL_0, 0x5f); + MIPI_OUTP(ctrl_base + DSI_DSIPHY_CTRL_3, 0x10); +} + +static void msm_dsi_phy_regulator_init(unsigned char *ctrl_base, + struct mdss_dsi_phy_ctrl *pd) +{ + MIPI_OUTP(ctrl_base + DSI_DSIPHY_LDO_CNTRL, 0x25); + MIPI_OUTP(ctrl_base + DSI_DSIPHY_REGULATOR_CTRL_0, pd->regulator[0]); + MIPI_OUTP(ctrl_base + DSI_DSIPHY_REGULATOR_CTRL_1, pd->regulator[1]); + MIPI_OUTP(ctrl_base + DSI_DSIPHY_REGULATOR_CTRL_2, pd->regulator[2]); + MIPI_OUTP(ctrl_base + DSI_DSIPHY_REGULATOR_CTRL_3, pd->regulator[3]); + MIPI_OUTP(ctrl_base + DSI_DSIPHY_REGULATOR_CTRL_4, pd->regulator[4]); + MIPI_OUTP(ctrl_base + DSI_DSIPHY_REGULATOR_CAL_PWR_CFG, + pd->regulator[5]); + +} + +static int msm_dsi_phy_calibration(unsigned char *ctrl_base) +{ + int i = 0, term_cnt = 5000, ret = 0, cal_busy; + + MIPI_OUTP(ctrl_base + DSI_DSIPHY_CAL_SW_CFG2, 0x0); + MIPI_OUTP(ctrl_base + DSI_DSIPHY_CAL_HW_CFG1, 0x5a); + MIPI_OUTP(ctrl_base + DSI_DSIPHY_CAL_HW_CFG3, 0x10); + MIPI_OUTP(ctrl_base + DSI_DSIPHY_CAL_HW_CFG4, 0x01); + MIPI_OUTP(ctrl_base + DSI_DSIPHY_CAL_HW_CFG0, 0x01); + MIPI_OUTP(ctrl_base + DSI_DSIPHY_CAL_HW_TRIGGER, 0x01); + usleep_range(5000, 5100); /*per DSI controller spec*/ + MIPI_OUTP(ctrl_base + DSI_DSIPHY_CAL_HW_TRIGGER, 0x00); + + cal_busy = MIPI_INP(ctrl_base + DSI_DSIPHY_REGULATOR_CAL_STATUS0); + while (cal_busy & 0x10) { + i++; + if (i > term_cnt) { + ret = -EINVAL; + pr_err("%s error\n", __func__); + break; + } + cal_busy = MIPI_INP(ctrl_base + + DSI_DSIPHY_REGULATOR_CAL_STATUS0); + } + + return ret; +} + +static void msm_dsi_phy_lane_init(unsigned char *ctrl_base, + struct mdss_dsi_phy_ctrl *pd) +{ + int ln, index; + + /*CFG0, CFG1, CFG2, TEST_DATAPATH, TEST_STR0, TEST_STR1*/ + for (ln = 0; ln < 5; ln++) { + unsigned char *off = ctrl_base + 0x0300 + (ln * 0x40); + + index = ln * 6; + + MIPI_OUTP(off, pd->lanecfg[index]); + MIPI_OUTP(off + 4, pd->lanecfg[index + 1]); + MIPI_OUTP(off + 8, pd->lanecfg[index + 2]); + MIPI_OUTP(off + 12, pd->lanecfg[index + 3]); + MIPI_OUTP(off + 20, pd->lanecfg[index + 4]); + MIPI_OUTP(off + 24, pd->lanecfg[index + 5]); + } + wmb(); /* ensure write is finished before progressing */ +} + +static void msm_dsi_phy_timing_init(unsigned char *ctrl_base, + struct mdss_dsi_phy_ctrl *pd) +{ + int i, off = DSI_DSIPHY_TIMING_CTRL_0; + + for (i = 0; i < 12; i++) { + MIPI_OUTP(ctrl_base + off, pd->timing[i]); + off += 4; + } + wmb(); /* ensure write is finished before progressing */ +} + +static void msm_dsi_phy_bist_init(unsigned char *ctrl_base, + struct mdss_dsi_phy_ctrl *pd) +{ + MIPI_OUTP(ctrl_base + DSI_DSIPHY_BIST_CTRL4, pd->bistctrl[4]); + MIPI_OUTP(ctrl_base + DSI_DSIPHY_BIST_CTRL1, pd->bistctrl[1]); + MIPI_OUTP(ctrl_base + DSI_DSIPHY_BIST_CTRL0, pd->bistctrl[0]); + MIPI_OUTP(ctrl_base + DSI_DSIPHY_BIST_CTRL4, 0); + wmb(); /* ensure write is finished before progressing */ +} + +int msm_dsi_phy_init(unsigned char *ctrl_base, + struct mdss_panel_data *pdata) +{ + struct mdss_dsi_phy_ctrl *pd; + + pd = &(pdata->panel_info.mipi.dsi_phy_db); + + msm_dsi_phy_strength_init(ctrl_base, pd); + + msm_dsi_phy_ctrl_init(ctrl_base, pdata); + + msm_dsi_phy_regulator_init(ctrl_base, pd); + + msm_dsi_phy_calibration(ctrl_base); + + msm_dsi_phy_lane_init(ctrl_base, pd); + + msm_dsi_phy_timing_init(ctrl_base, pd); + + msm_dsi_phy_bist_init(ctrl_base, pd); + + return 0; +} + +void msm_dsi_phy_sw_reset(unsigned char *ctrl_base) +{ + /* start phy sw reset */ + MIPI_OUTP(ctrl_base + DSI_PHY_SW_RESET, 0x0001); + udelay(1000); /*per DSI controller spec*/ + wmb(); /* ensure write is finished before progressing */ + /* end phy sw reset */ + MIPI_OUTP(ctrl_base + DSI_PHY_SW_RESET, 0x0000); + udelay(100); /*per DSI controller spec*/ + wmb(); /* ensure write is finished before progressing */ +} + +void msm_dsi_phy_off(unsigned char *ctrl_base) +{ + MIPI_OUTP(ctrl_base + DSI_DSIPHY_PLL_CTRL_5, 0x05f); + MIPI_OUTP(ctrl_base + DSI_DSIPHY_REGULATOR_CTRL_0, 0x02); + MIPI_OUTP(ctrl_base + DSI_DSIPHY_CTRL_0, 0x00); + MIPI_OUTP(ctrl_base + DSI_DSIPHY_CTRL_1, 0x7f); + MIPI_OUTP(ctrl_base + DSI_CLK_CTRL, 0); +} diff --git a/drivers/video/fbdev/msm/dsi_io_v2.h b/drivers/video/fbdev/msm/dsi_io_v2.h new file mode 100644 index 000000000000..d0227ecc7b81 --- /dev/null +++ b/drivers/video/fbdev/msm/dsi_io_v2.h @@ -0,0 +1,49 @@ +/* Copyright (c) 2013, 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +#ifndef DSI_IO_V2_H +#define DSI_IO_V2_H + +#include "mdss_panel.h" + +void msm_dsi_ahb_ctrl(int enable); + +int msm_dsi_io_init(struct platform_device *dev, + struct mdss_module_power *mp); + +void msm_dsi_io_deinit(struct platform_device *dev, + struct mdss_module_power *mp); + +int msm_dsi_clk_init(struct platform_device *dev); + +void msm_dsi_clk_deinit(void); + +int msm_dsi_prepare_clocks(void); + +int msm_dsi_unprepare_clocks(void); + +int msm_dsi_clk_set_rate(unsigned long esc_rate, + unsigned long dsi_rate, + unsigned long byte_rate, + unsigned long pixel_rate); + +int msm_dsi_clk_enable(void); + +int msm_dsi_clk_disable(void); + +int msm_dsi_phy_init(unsigned char *ctrl_base, + struct mdss_panel_data *pdata); + +void msm_dsi_phy_sw_reset(unsigned char *ctrl_base); + +void msm_dsi_phy_off(unsigned char *ctrl_base); +#endif /* DSI_IO_V2_H */ diff --git a/drivers/video/fbdev/msm/dsi_status_6g.c b/drivers/video/fbdev/msm/dsi_status_6g.c new file mode 100644 index 000000000000..8a329026602c --- /dev/null +++ b/drivers/video/fbdev/msm/dsi_status_6g.c @@ -0,0 +1,188 @@ +/* Copyright (c) 2013-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include + +#include "mdss_dsi.h" +#include "mdss_mdp.h" +#include "mdss_debug.h" + +/* + * mdss_check_te_status() - Check the status of panel for TE based ESD. + * @ctrl_pdata : dsi controller data + * @pstatus_data : dsi status data + * @interval : duration in milliseconds for panel TE wait + * + * This function is called when the TE signal from the panel doesn't arrive + * after 'interval' milliseconds. If the TE IRQ is not ready, the workqueue + * gets re-scheduled. Otherwise, report the panel to be dead due to ESD attack. + */ +static bool mdss_check_te_status(struct mdss_dsi_ctrl_pdata *ctrl_pdata, + struct dsi_status_data *pstatus_data, uint32_t interval) +{ + bool ret; + + atomic_set(&ctrl_pdata->te_irq_ready, 0); + reinit_completion(&ctrl_pdata->te_irq_comp); + enable_irq(gpio_to_irq(ctrl_pdata->disp_te_gpio)); + /* Define TE interrupt timeout value as 3x(1/fps) */ + ret = wait_for_completion_timeout(&ctrl_pdata->te_irq_comp, + msecs_to_jiffies(interval)); + disable_irq(gpio_to_irq(ctrl_pdata->disp_te_gpio)); + pr_debug("%s: Panel TE check done with ret = %d\n", __func__, ret); + return ret; +} + +/* + * mdss_check_dsi_ctrl_status() - Check MDP5 DSI controller status periodically. + * @work : dsi controller status data + * @interval : duration in milliseconds to schedule work queue + * + * This function calls check_status API on DSI controller to send the BTA + * command. If DSI controller fails to acknowledge the BTA command, it sends + * the PANEL_ALIVE=0 status to HAL layer. + */ +void mdss_check_dsi_ctrl_status(struct work_struct *work, uint32_t interval) +{ + struct dsi_status_data *pstatus_data = NULL; + struct mdss_panel_data *pdata = NULL; + struct mipi_panel_info *mipi = NULL; + struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL; + struct mdss_overlay_private *mdp5_data = NULL; + struct mdss_mdp_ctl *ctl = NULL; + int ret = 0; + + pstatus_data = container_of(to_delayed_work(work), + struct dsi_status_data, check_status); + if (!pstatus_data || !(pstatus_data->mfd)) { + pr_err("%s: mfd not available\n", __func__); + return; + } + + pdata = dev_get_platdata(&pstatus_data->mfd->pdev->dev); + if (!pdata) { + pr_err("%s: Panel data not available\n", __func__); + return; + } + mipi = &pdata->panel_info.mipi; + + ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata, + panel_data); + if (!ctrl_pdata || (!ctrl_pdata->check_status && + (ctrl_pdata->status_mode != ESD_TE))) { + pr_err("%s: DSI ctrl or status_check callback not available\n", + __func__); + return; + } + + if (!pdata->panel_info.esd_rdy) { + pr_debug("%s: unblank not complete, reschedule check status\n", + __func__); + schedule_delayed_work(&pstatus_data->check_status, + msecs_to_jiffies(interval)); + return; + } + + mdp5_data = mfd_to_mdp5_data(pstatus_data->mfd); + ctl = mfd_to_ctl(pstatus_data->mfd); + + if (!ctl) { + pr_err("%s: Display is off\n", __func__); + return; + } + + if (ctrl_pdata->status_mode == ESD_TE) { + uint32_t fps = mdss_panel_get_framerate(&pdata->panel_info, + FPS_RESOLUTION_HZ); + uint32_t timeout = ((1000 / fps) + 1) * + MDSS_STATUS_TE_WAIT_MAX; + + if (mdss_check_te_status(ctrl_pdata, pstatus_data, timeout)) + goto sim; + else + goto status_dead; + } + + /* + * TODO: Because mdss_dsi_cmd_mdp_busy has made sure DMA to + * be idle in mdss_dsi_cmdlist_commit, it is not necessary + * to acquire ov_lock in case of video mode. Removing this + * lock to fix issues so that ESD thread would not block other + * overlay operations. Need refine this lock for command mode + * + * If Burst mode is enabled then we dont have to acquire ov_lock as + * command and data arbitration is possible in h/w + */ + + if ((mipi->mode == DSI_CMD_MODE) && !ctrl_pdata->burst_mode_enabled) + mutex_lock(&mdp5_data->ov_lock); + mutex_lock(&ctl->offlock); + + if (mdss_panel_is_power_off(pstatus_data->mfd->panel_power_state) || + pstatus_data->mfd->shutdown_pending) { + mutex_unlock(&ctl->offlock); + if ((mipi->mode == DSI_CMD_MODE) && + !ctrl_pdata->burst_mode_enabled) + mutex_unlock(&mdp5_data->ov_lock); + pr_err("%s: DSI turning off, avoiding panel status check\n", + __func__); + return; + } + + /* + * For the command mode panels, we return pan display + * IOCTL on vsync interrupt. So, after vsync interrupt comes + * and when DMA_P is in progress, if the panel stops responding + * and if we trigger BTA before DMA_P finishes, then the DSI + * FIFO will not be cleared since the DSI data bus control + * doesn't come back to the host after BTA. This may cause the + * display reset not to be proper. Hence, wait for DMA_P done + * for command mode panels before triggering BTA. + */ + if (ctl->ops.wait_pingpong && !ctrl_pdata->burst_mode_enabled) + ctl->ops.wait_pingpong(ctl, NULL); + + pr_debug("%s: DSI ctrl wait for ping pong done\n", __func__); + MDSS_XLOG(mipi->mode); + + mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON); + ret = ctrl_pdata->check_status(ctrl_pdata); + mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF); + + mutex_unlock(&ctl->offlock); + if ((mipi->mode == DSI_CMD_MODE) && !ctrl_pdata->burst_mode_enabled) + mutex_unlock(&mdp5_data->ov_lock); + + if (pstatus_data->mfd->panel_power_state == MDSS_PANEL_POWER_ON) { + if (ret > 0) + schedule_delayed_work(&pstatus_data->check_status, + msecs_to_jiffies(interval)); + else + goto status_dead; + } +sim: + if (pdata->panel_info.panel_force_dead) { + pr_debug("force_dead=%d\n", pdata->panel_info.panel_force_dead); + pdata->panel_info.panel_force_dead--; + if (!pdata->panel_info.panel_force_dead) + goto status_dead; + } + + return; + +status_dead: + mdss_fb_report_panel_dead(pstatus_data->mfd); +} diff --git a/drivers/video/fbdev/msm/dsi_status_v2.c b/drivers/video/fbdev/msm/dsi_status_v2.c new file mode 100644 index 000000000000..35b09849f3c8 --- /dev/null +++ b/drivers/video/fbdev/msm/dsi_status_v2.c @@ -0,0 +1,167 @@ +/* Copyright (c) 2013-2015, 2017-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#include +#include +#include +#include +#include +#include + +#include "mdss_dsi.h" +#include "mdp3_ctrl.h" + +/* + * mdp3_check_te_status() - Check the status of panel for TE based ESD. + * @ctrl_pdata : dsi controller data + * @pstatus_data : dsi status data + * @interval : duration in milliseconds for panel TE wait + * + * This function waits for TE signal from the panel for a maximum + * duration of 3 vsyncs. If timeout occurs, report the panel to be + * dead due to ESD attack. + * NOTE: The TE IRQ handling is linked to the ESD thread scheduling, + * i.e. rate of TE IRQs firing is bound by the ESD interval. + */ +static int mdp3_check_te_status(struct mdss_dsi_ctrl_pdata *ctrl_pdata, + struct dsi_status_data *pstatus_data, uint32_t interval) +{ + int ret; + + pr_debug("%s: Checking panel TE status\n", __func__); + + atomic_set(&ctrl_pdata->te_irq_ready, 0); + reinit_completion(&ctrl_pdata->te_irq_comp); + enable_irq(gpio_to_irq(ctrl_pdata->disp_te_gpio)); + + ret = wait_for_completion_timeout(&ctrl_pdata->te_irq_comp, + msecs_to_jiffies(interval)); + + disable_irq(gpio_to_irq(ctrl_pdata->disp_te_gpio)); + pr_debug("%s: Panel TE check done with ret = %d\n", __func__, ret); + + return ret; +} + +/* + * mdp3_check_dsi_ctrl_status() - Check MDP3 DSI controller status periodically. + * @work : dsi controller status data + * @interval : duration in milliseconds to schedule work queue + * + * This function calls check_status API on DSI controller to send the BTA + * command. If DSI controller fails to acknowledge the BTA command, it sends + * the PANEL_ALIVE=0 status to HAL layer. + */ +void mdp3_check_dsi_ctrl_status(struct work_struct *work, + uint32_t interval) +{ + struct dsi_status_data *pdsi_status = NULL; + struct mdss_panel_data *pdata = NULL; + struct mipi_panel_info *mipi = NULL; + struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL; + struct mdp3_session_data *mdp3_session = NULL; + int ret = 0; + + pdsi_status = container_of(to_delayed_work(work), + struct dsi_status_data, check_status); + + if (!pdsi_status || !(pdsi_status->mfd)) { + pr_err("%s: mfd not available\n", __func__); + return; + } + + pdata = dev_get_platdata(&pdsi_status->mfd->pdev->dev); + if (!pdata) { + pr_err("%s: Panel data not available\n", __func__); + return; + } + + mipi = &pdata->panel_info.mipi; + ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata, + panel_data); + + if (!ctrl_pdata || (!ctrl_pdata->check_status && + (ctrl_pdata->status_mode != ESD_TE))) { + pr_err("%s: DSI ctrl or status_check callback not available\n", + __func__); + return; + } + + if (!pdata->panel_info.esd_rdy) { + pr_err("%s: unblank not complete, reschedule check status\n", + __func__); + schedule_delayed_work(&pdsi_status->check_status, + msecs_to_jiffies(interval)); + return; + } + + mdp3_session = pdsi_status->mfd->mdp.private1; + if (!mdp3_session) { + pr_err("%s: Display is off\n", __func__); + return; + } + + if (mdp3_session->in_splash_screen) { + schedule_delayed_work(&pdsi_status->check_status, + msecs_to_jiffies(interval)); + pr_debug("%s: cont splash is on\n", __func__); + return; + } + + if (mipi->mode == DSI_CMD_MODE && + mipi->hw_vsync_mode && + mdss_dsi_is_te_based_esd(ctrl_pdata)) { + uint32_t fps = mdss_panel_get_framerate(&pdata->panel_info, + FPS_RESOLUTION_HZ); + uint32_t timeout = ((1000 / fps) + 1) * + MDSS_STATUS_TE_WAIT_MAX; + + if (mdp3_check_te_status(ctrl_pdata, pdsi_status, timeout) > 0) + goto sim; + goto status_dead; + } + + mutex_lock(&mdp3_session->lock); + if (!mdp3_session->status) { + pr_debug("%s: display off already\n", __func__); + mutex_unlock(&mdp3_session->lock); + return; + } + + if (mdp3_session->wait_for_dma_done) + ret = mdp3_session->wait_for_dma_done(mdp3_session); + mutex_unlock(&mdp3_session->lock); + + if (!ret) + ret = ctrl_pdata->check_status(ctrl_pdata); + else + pr_err("%s: wait_for_dma_done error\n", __func__); + + if (mdss_fb_is_power_on_interactive(pdsi_status->mfd)) { + if (ret > 0) + schedule_delayed_work(&pdsi_status->check_status, + msecs_to_jiffies(interval)); + else + goto status_dead; + } +sim: + if (pdata->panel_info.panel_force_dead) { + pr_debug("force_dead=%d\n", pdata->panel_info.panel_force_dead); + pdata->panel_info.panel_force_dead--; + if (!pdata->panel_info.panel_force_dead) + goto status_dead; + } + return; + +status_dead: + mdss_fb_report_panel_dead(pdsi_status->mfd); +} + diff --git a/drivers/video/fbdev/msm/dsi_v2.c b/drivers/video/fbdev/msm/dsi_v2.c new file mode 100644 index 000000000000..bfd29416cd1b --- /dev/null +++ b/drivers/video/fbdev/msm/dsi_v2.c @@ -0,0 +1,616 @@ +/* Copyright (c) 2012-2015, 2017-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +#include +#include +#include +#include +#include +#include +#include + +#include "dsi_v2.h" + +static struct dsi_interface dsi_intf; + +static int dsi_off(struct mdss_panel_data *pdata) +{ + int rc = 0; + + pr_debug("turn off dsi controller\n"); + if (dsi_intf.off) + rc = dsi_intf.off(pdata); + + if (rc) { + pr_err("mdss_dsi_off DSI failed %d\n", rc); + return rc; + } + return rc; +} + +static int dsi_on(struct mdss_panel_data *pdata) +{ + int rc = 0; + + pr_debug("%s DSI controller on\n", __func__); + if (dsi_intf.on) + rc = dsi_intf.on(pdata); + + if (rc) { + pr_err("mdss_dsi_on DSI failed %d\n", rc); + return rc; + } + return rc; +} + +static int dsi_update_pconfig(struct mdss_panel_data *pdata, + int mode) +{ + int ret = 0; + struct mdss_panel_info *pinfo = &pdata->panel_info; + struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL; + + if (!pdata) + return -ENODEV; + ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata, + panel_data); + + if (mode == DSI_CMD_MODE) { + pinfo->mipi.mode = DSI_CMD_MODE; + pinfo->type = MIPI_CMD_PANEL; + pinfo->mipi.vsync_enable = 1; + pinfo->mipi.hw_vsync_mode = 1; + } else { + pinfo->mipi.mode = DSI_VIDEO_MODE; + pinfo->type = MIPI_VIDEO_PANEL; + pinfo->mipi.vsync_enable = 0; + pinfo->mipi.hw_vsync_mode = 0; + } + + ctrl_pdata->panel_mode = pinfo->mipi.mode; + mdss_panel_get_dst_fmt(pinfo->bpp, pinfo->mipi.mode, + pinfo->mipi.pixel_packing, &(pinfo->mipi.dst_format)); + pinfo->cont_splash_enabled = 0; + + return ret; +} + +static int dsi_panel_handler(struct mdss_panel_data *pdata, int enable) +{ + int rc = 0; + struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL; + + pr_debug("%s enable=%d\n", __func__, enable); + if (!pdata) + return -ENODEV; + ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata, + panel_data); + + if (enable && + (pdata->panel_info.panel_power_state == MDSS_PANEL_POWER_OFF)) { + if (!pdata->panel_info.dynamic_switch_pending) { + mdss_dsi_panel_reset(pdata, 1); + rc = ctrl_pdata->on(pdata); + if (rc) + pr_err("%s panel on failed %d\n", __func__, rc); + } + pdata->panel_info.panel_power_state = MDSS_PANEL_POWER_ON; + if (pdata->panel_info.type == MIPI_CMD_PANEL) + mdss_dsi_set_tear_on(ctrl_pdata); + } else if (!enable && + (pdata->panel_info.panel_power_state == MDSS_PANEL_POWER_ON)) { + msm_dsi_sw_reset(); + if (dsi_intf.op_mode_config) + dsi_intf.op_mode_config(DSI_CMD_MODE, pdata); + if (pdata->panel_info.dynamic_switch_pending) { + pr_info("%s: switching to %s mode\n", __func__, + (pdata->panel_info.mipi.mode ? "video" : "command")); + if (pdata->panel_info.type == MIPI_CMD_PANEL) { + ctrl_pdata->switch_mode(pdata, DSI_VIDEO_MODE); + } else if (pdata->panel_info.type == MIPI_VIDEO_PANEL) { + ctrl_pdata->switch_mode(pdata, DSI_CMD_MODE); + mdss_dsi_set_tear_off(ctrl_pdata); + } + } + pdata->panel_info.panel_power_state = MDSS_PANEL_POWER_OFF; + if (!pdata->panel_info.dynamic_switch_pending) { + rc = ctrl_pdata->off(pdata); + mdss_dsi_panel_reset(pdata, 0); + } + } + return rc; +} + +static int dsi_splash_on(struct mdss_panel_data *pdata) +{ + int rc = 0; + + pr_debug("%s:\n", __func__); + + if (dsi_intf.cont_on) + rc = dsi_intf.cont_on(pdata); + + if (rc) { + pr_err("mdss_dsi_on DSI failed %d\n", rc); + return rc; + } + return rc; +} + +static int dsi_clk_ctrl(struct mdss_panel_data *pdata, int enable) +{ + int rc = 0; + + pr_debug("%s:\n", __func__); + + if (dsi_intf.clk_ctrl) + rc = dsi_intf.clk_ctrl(pdata, enable); + + return rc; +} + +static int dsi_event_handler(struct mdss_panel_data *pdata, + int event, void *arg) +{ + int rc = 0; + + if (!pdata) { + pr_err("%s: Invalid input data\n", __func__); + return -ENODEV; + } + + switch (event) { + case MDSS_EVENT_UNBLANK: + rc = dsi_on(pdata); + break; + case MDSS_EVENT_BLANK: + rc = dsi_off(pdata); + break; + case MDSS_EVENT_PANEL_ON: + rc = dsi_panel_handler(pdata, 1); + break; + case MDSS_EVENT_PANEL_OFF: + rc = dsi_panel_handler(pdata, 0); + break; + case MDSS_EVENT_CONT_SPLASH_BEGIN: + rc = dsi_splash_on(pdata); + break; + case MDSS_EVENT_PANEL_CLK_CTRL: + rc = dsi_clk_ctrl(pdata, + (int)(((struct dsi_panel_clk_ctrl *)arg)->state)); + break; + case MDSS_EVENT_DSI_UPDATE_PANEL_DATA: + rc = dsi_update_pconfig(pdata, (int)(unsigned long) arg); + break; + default: + pr_debug("%s: unhandled event=%d\n", __func__, event); + break; + } + return rc; +} + +static int dsi_parse_gpio(struct platform_device *pdev, + struct mdss_dsi_ctrl_pdata *ctrl_pdata) +{ + struct device_node *np = pdev->dev.of_node; + + ctrl_pdata->disp_en_gpio = of_get_named_gpio(np, + "qcom,platform-enable-gpio", 0); + + if (!gpio_is_valid(ctrl_pdata->disp_en_gpio)) + pr_err("%s:%d, Disp_en gpio not specified\n", + __func__, __LINE__); + + ctrl_pdata->rst_gpio = of_get_named_gpio(np, + "qcom,platform-reset-gpio", 0); + if (!gpio_is_valid(ctrl_pdata->rst_gpio)) + pr_err("%s:%d, reset gpio not specified\n", + __func__, __LINE__); + + ctrl_pdata->mode_gpio = -1; + if (ctrl_pdata->panel_data.panel_info.mode_gpio_state != + MODE_GPIO_NOT_VALID) { + ctrl_pdata->mode_gpio = of_get_named_gpio(np, + "qcom,platform-mode-gpio", 0); + if (!gpio_is_valid(ctrl_pdata->mode_gpio)) + pr_info("%s:%d, reset gpio not specified\n", + __func__, __LINE__); + } + + ctrl_pdata->bklt_en_gpio = of_get_named_gpio(np, + "qcom,platform-bklight-en-gpio", 0); + if (!gpio_is_valid(ctrl_pdata->bklt_en_gpio)) + pr_err("%s:%d, bklt_en gpio not specified\n", + __func__, __LINE__); + + return 0; +} + +static void mdss_dsi_put_dt_vreg_data(struct device *dev, + struct mdss_module_power *module_power) +{ + if (!module_power) { + pr_err("%s: invalid input\n", __func__); + return; + } + + if (module_power->vreg_config) { + devm_kfree(dev, module_power->vreg_config); + module_power->vreg_config = NULL; + } + module_power->num_vreg = 0; +} + +static int mdss_dsi_get_dt_vreg_data(struct device *dev, + struct mdss_module_power *mp, enum dsi_pm_type module) +{ + int i = 0, rc = 0; + u32 tmp = 0; + struct device_node *of_node = NULL, *supply_node = NULL; + const char *pm_supply_name = NULL; + struct device_node *supply_root_node = NULL; + + if (!dev || !mp) { + pr_err("%s: invalid input\n", __func__); + rc = -EINVAL; + return rc; + } + + of_node = dev->of_node; + + mp->num_vreg = 0; + pm_supply_name = __mdss_dsi_pm_supply_node_name(module); + supply_root_node = of_get_child_by_name(of_node, pm_supply_name); + if (!supply_root_node) { + pr_err("no supply entry present\n"); + goto novreg; + } + + for_each_child_of_node(supply_root_node, supply_node) { + mp->num_vreg++; + } + + if (mp->num_vreg == 0) { + pr_debug("%s: no vreg\n", __func__); + goto novreg; + } else { + pr_debug("%s: vreg found. count=%d\n", __func__, mp->num_vreg); + } + + mp->vreg_config = devm_kzalloc(dev, sizeof(struct mdss_vreg) * + mp->num_vreg, GFP_KERNEL); + if (!mp->vreg_config) { + rc = -ENOMEM; + goto error; + } + + for_each_child_of_node(supply_root_node, supply_node) { + const char *st = NULL; + /* vreg-name */ + rc = of_property_read_string(supply_node, + "qcom,supply-name", &st); + if (rc) { + pr_err("%s: error reading name. rc=%d\n", + __func__, rc); + goto error; + } + snprintf(mp->vreg_config[i].vreg_name, + ARRAY_SIZE((mp->vreg_config[i].vreg_name)), "%s", st); + /* vreg-min-voltage */ + rc = of_property_read_u32(supply_node, + "qcom,supply-min-voltage", &tmp); + if (rc) { + pr_err("%s: error reading min volt. rc=%d\n", + __func__, rc); + goto error; + } + mp->vreg_config[i].min_voltage = tmp; + + /* vreg-max-voltage */ + rc = of_property_read_u32(supply_node, + "qcom,supply-max-voltage", &tmp); + if (rc) { + pr_err("%s: error reading max volt. rc=%d\n", + __func__, rc); + goto error; + } + mp->vreg_config[i].max_voltage = tmp; + + /* enable-load */ + rc = of_property_read_u32(supply_node, + "qcom,supply-enable-load", &tmp); + if (rc) { + pr_err("%s: error reading enable load. rc=%d\n", + __func__, rc); + goto error; + } + mp->vreg_config[i].load[DSS_REG_MODE_ENABLE] = tmp; + + /* disable-load */ + rc = of_property_read_u32(supply_node, + "qcom,supply-disable-load", &tmp); + if (rc) { + pr_err("%s: error reading disable load. rc=%d\n", + __func__, rc); + goto error; + } + mp->vreg_config[i].load[DSS_REG_MODE_DISABLE] = tmp; + + /* ulp-load */ + rc = of_property_read_u32(supply_node, + "qcom,supply-ulp-load", &tmp); + if (rc) + pr_warn("%s: error reading ulp load. rc=%d\n", + __func__, rc); + + mp->vreg_config[i].load[DSS_REG_MODE_ULP] = (!rc ? tmp : + mp->vreg_config[i].load[DSS_REG_MODE_ENABLE]); + + /* pre-sleep */ + rc = of_property_read_u32(supply_node, + "qcom,supply-pre-on-sleep", &tmp); + if (rc) { + pr_debug("%s: error reading supply pre sleep value. rc=%d\n", + __func__, rc); + rc = 0; + } else { + mp->vreg_config[i].pre_on_sleep = tmp; + } + + rc = of_property_read_u32(supply_node, + "qcom,supply-pre-off-sleep", &tmp); + if (rc) { + pr_debug("%s: error reading supply pre sleep value. rc=%d\n", + __func__, rc); + rc = 0; + } else { + mp->vreg_config[i].pre_off_sleep = tmp; + } + + /* post-sleep */ + rc = of_property_read_u32(supply_node, + "qcom,supply-post-on-sleep", &tmp); + if (rc) { + pr_debug("%s: error reading supply post sleep value. rc=%d\n", + __func__, rc); + rc = 0; + } else { + mp->vreg_config[i].post_on_sleep = tmp; + } + + rc = of_property_read_u32(supply_node, + "qcom,supply-post-off-sleep", &tmp); + if (rc) { + pr_debug("%s: error reading supply post sleep value. rc=%d\n", + __func__, rc); + rc = 0; + } else { + mp->vreg_config[i].post_off_sleep = tmp; + } + + pr_debug("%s: %s min=%d, max=%d, enable=%d, disable=%d, ulp=%d, preonsleep=%d, postonsleep=%d, preoffsleep=%d, postoffsleep=%d\n", + __func__, + mp->vreg_config[i].vreg_name, + mp->vreg_config[i].min_voltage, + mp->vreg_config[i].max_voltage, + mp->vreg_config[i].load[DSS_REG_MODE_ENABLE] + mp->vreg_config[i].load[DSS_REG_MODE_DISABLE] + mp->vreg_config[i].load[DSS_REG_MODE_ULP] + mp->vreg_config[i].pre_on_sleep, + mp->vreg_config[i].post_on_sleep, + mp->vreg_config[i].pre_off_sleep, + mp->vreg_config[i].post_off_sleep + ); + ++i; + } + + return rc; + +error: + if (mp->vreg_config) { + devm_kfree(dev, mp->vreg_config); + mp->vreg_config = NULL; + } +novreg: + mp->num_vreg = 0; + + return rc; +} + +static int dsi_parse_phy(struct platform_device *pdev, + struct mdss_dsi_ctrl_pdata *ctrl_pdata) +{ + struct device_node *np = pdev->dev.of_node; + int i, len; + const char *data; + struct mdss_dsi_phy_ctrl *phy_db + = &(ctrl_pdata->panel_data.panel_info.mipi.dsi_phy_db); + + data = of_get_property(np, "qcom,platform-regulator-settings", &len); + if ((!data) || (len != 6)) { + pr_err("%s:%d, Unable to read Phy regulator settings", + __func__, __LINE__); + return -EINVAL; + } + for (i = 0; i < len; i++) + phy_db->regulator[i] = data[i]; + + data = of_get_property(np, "qcom,platform-strength-ctrl", &len); + if ((!data) || (len != 2)) { + pr_err("%s:%d, Unable to read Phy Strength ctrl settings", + __func__, __LINE__); + return -EINVAL; + } + phy_db->strength[0] = data[0]; + phy_db->strength[1] = data[1]; + + data = of_get_property(np, "qcom,platform-bist-ctrl", &len); + if ((!data) || (len != 6)) { + pr_err("%s:%d, Unable to read Phy Bist Ctrl settings", + __func__, __LINE__); + return -EINVAL; + } + for (i = 0; i < len; i++) + phy_db->bistctrl[i] = data[i]; + + data = of_get_property(np, "qcom,platform-lane-config", &len); + if ((!data) || (len != 30)) { + pr_err("%s:%d, Unable to read Phy lane configure settings", + __func__, __LINE__); + return -EINVAL; + } + for (i = 0; i < len; i++) + phy_db->lanecfg[i] = data[i]; + + return 0; +} + +void dsi_ctrl_config_deinit(struct platform_device *pdev, + struct mdss_dsi_ctrl_pdata *ctrl_pdata) +{ + int i; + + for (i = DSI_MAX_PM - 1; i >= 0; i--) { + mdss_dsi_put_dt_vreg_data(&pdev->dev, + &ctrl_pdata->power_data[i]); + } +} + +int dsi_ctrl_config_init(struct platform_device *pdev, + struct mdss_dsi_ctrl_pdata *ctrl_pdata) +{ + int rc = 0, i; + + for (i = 0; i < DSI_MAX_PM; i++) { + rc = mdss_dsi_get_dt_vreg_data(&pdev->dev, + &ctrl_pdata->power_data[i], i); + if (rc) { + DEV_ERR("%s: '%s' get_dt_vreg_data failed.rc=%d\n", + __func__, __mdss_dsi_pm_name(i), rc); + return rc; + } + } + + rc = dsi_parse_gpio(pdev, ctrl_pdata); + if (rc) { + pr_err("fail to parse panel GPIOs\n"); + return rc; + } + + rc = dsi_parse_phy(pdev, ctrl_pdata); + if (rc) { + pr_err("fail to parse DSI PHY settings\n"); + return rc; + } + + return 0; +} +int dsi_panel_device_register_v2(struct platform_device *dev, + struct mdss_dsi_ctrl_pdata *ctrl_pdata) +{ + struct mipi_panel_info *mipi; + int rc; + u8 lanes = 0, bpp; + u32 h_period, v_period; + struct mdss_panel_info *pinfo = &(ctrl_pdata->panel_data.panel_info); + + h_period = ((pinfo->lcdc.h_pulse_width) + + (pinfo->lcdc.h_back_porch) + + (pinfo->xres) + + (pinfo->lcdc.h_front_porch)); + + v_period = ((pinfo->lcdc.v_pulse_width) + + (pinfo->lcdc.v_back_porch) + + (pinfo->yres) + + (pinfo->lcdc.v_front_porch)); + + mipi = &pinfo->mipi; + + pinfo->type = + ((mipi->mode == DSI_VIDEO_MODE) + ? MIPI_VIDEO_PANEL : MIPI_CMD_PANEL); + + if (mipi->data_lane3) + lanes += 1; + if (mipi->data_lane2) + lanes += 1; + if (mipi->data_lane1) + lanes += 1; + if (mipi->data_lane0) + lanes += 1; + + if ((mipi->dst_format == DSI_CMD_DST_FORMAT_RGB888) + || (mipi->dst_format == DSI_VIDEO_DST_FORMAT_RGB888) + || (mipi->dst_format == DSI_VIDEO_DST_FORMAT_RGB666_LOOSE)) + bpp = 3; + else if ((mipi->dst_format == DSI_CMD_DST_FORMAT_RGB565) + || (mipi->dst_format == DSI_VIDEO_DST_FORMAT_RGB565)) + bpp = 2; + else + bpp = 3; /* Default format set to RGB888 */ + + if (pinfo->type == MIPI_VIDEO_PANEL && + !pinfo->clk_rate) { + h_period += pinfo->lcdc.xres_pad; + v_period += pinfo->lcdc.yres_pad; + + if (lanes > 0) { + pinfo->clk_rate = + ((h_period * v_period * (mipi->frame_rate) * bpp * 8) + / lanes); + } else { + pr_err("%s: forcing mdss_dsi lanes to 1\n", __func__); + pinfo->clk_rate = + (h_period * v_period + * (mipi->frame_rate) * bpp * 8); + } + } + + ctrl_pdata->panel_data.event_handler = dsi_event_handler; + + /* + * register in mdp driver + */ + rc = mdss_register_panel(dev, &(ctrl_pdata->panel_data)); + if (rc) { + dev_err(&dev->dev, "unable to register MIPI DSI panel\n"); + return rc; + } + + pr_debug("%s: Panal data initialized\n", __func__); + return 0; +} + +void dsi_register_interface(struct dsi_interface *intf) +{ + dsi_intf = *intf; +} + +int dsi_buf_alloc(struct dsi_buf *dp, int size) +{ + dp->start = kzalloc(size, GFP_KERNEL); + if (!dp->start) + return -ENOMEM; + + dp->end = dp->start + size; + dp->size = size; + + if ((int)dp->start & 0x07) { + pr_err("%s: buf NOT 8 bytes aligned\n", __func__); + return -EINVAL; + } + + dp->data = dp->start; + dp->len = 0; + return 0; +} + diff --git a/drivers/video/fbdev/msm/dsi_v2.h b/drivers/video/fbdev/msm/dsi_v2.h new file mode 100644 index 000000000000..2f6f4043cddc --- /dev/null +++ b/drivers/video/fbdev/msm/dsi_v2.h @@ -0,0 +1,56 @@ +/* Copyright (c) 2012-2014, 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef DSI_V2_H +#define DSI_V2_H + +#include +#include + +#include "mdss_dsi.h" +#include "mdss_panel.h" + +#define DSI_BUF_SIZE 1024 +#define DSI_MRPS 0x04 /* Maximum Return Packet Size */ + +struct dsi_interface { + int (*on)(struct mdss_panel_data *pdata); + int (*off)(struct mdss_panel_data *pdata); + int (*cont_on)(struct mdss_panel_data *pdata); + int (*clk_ctrl)(struct mdss_panel_data *pdata, int enable); + void (*op_mode_config)(int mode, struct mdss_panel_data *pdata); + int index; + void *private; +}; + +int dsi_panel_device_register_v2(struct platform_device *pdev, + struct mdss_dsi_ctrl_pdata *ctrl_pdata); + +void dsi_register_interface(struct dsi_interface *intf); + +int dsi_buf_alloc(struct dsi_buf *dp, int size); + +void dsi_set_tx_power_mode(int mode); + +void dsi_ctrl_config_deinit(struct platform_device *pdev, + struct mdss_dsi_ctrl_pdata *ctrl_pdata); + +int dsi_ctrl_config_init(struct platform_device *pdev, + struct mdss_dsi_ctrl_pdata *ctrl_pdata); + +struct mdss_panel_cfg *mdp3_panel_intf_type(int intf_val); + +int mdp3_panel_get_boot_cfg(void); + +void msm_dsi_sw_reset(void); +#endif /* DSI_V2_H */ diff --git a/drivers/video/fbdev/msm/mdp3.c b/drivers/video/fbdev/msm/mdp3.c new file mode 100644 index 000000000000..f85880dd8d76 --- /dev/null +++ b/drivers/video/fbdev/msm/mdp3.c @@ -0,0 +1,2661 @@ +/* Copyright (c) 2013-2018, The Linux Foundation. All rights reserved. + * Copyright (C) 2007 Google Incorporated + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#define pr_fmt(fmt) "%s: " fmt, __func__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include "mdp3.h" +#include "mdss_fb.h" +#include "mdp3_hwio.h" +#include "mdp3_ctrl.h" +#include "mdp3_ppp.h" +#include "mdss_debug.h" +#include "mdss_smmu.h" +#include "mdss.h" + +#ifndef EXPORT_COMPAT +#define EXPORT_COMPAT(x) +#endif + +#define AUTOSUSPEND_TIMEOUT_MS 100 +#define MISR_POLL_SLEEP 2000 +#define MISR_POLL_TIMEOUT 32000 +#define MDP3_REG_CAPTURED_DSI_PCLK_MASK 1 + +#define MDP_CORE_HW_VERSION 0x03050306 +struct mdp3_hw_resource *mdp3_res; + +#define MDP_BUS_VECTOR_ENTRY(ab_val, ib_val) \ + { \ + .src = MSM_BUS_MASTER_MDP_PORT0, \ + .dst = MSM_BUS_SLAVE_EBI_CH0, \ + .ab = (ab_val), \ + .ib = (ib_val), \ + } + +#define SET_BIT(value, bit_num) \ +{ \ + value[bit_num >> 3] |= (1 << (bit_num & 7)); \ +} + +#define MAX_BPP_SUPPORTED 4 + +static struct msm_bus_vectors mdp_bus_vectors[] = { + MDP_BUS_VECTOR_ENTRY(0, 0), + MDP_BUS_VECTOR_ENTRY(SZ_128M, SZ_256M), + MDP_BUS_VECTOR_ENTRY(SZ_256M, SZ_512M), +}; +static struct msm_bus_paths + mdp_bus_usecases[ARRAY_SIZE(mdp_bus_vectors)]; +static struct msm_bus_scale_pdata mdp_bus_scale_table = { + .usecase = mdp_bus_usecases, + .num_usecases = ARRAY_SIZE(mdp_bus_usecases), + .name = "mdp3", +}; + +struct mdp3_bus_handle_map mdp3_bus_handle[MDP3_BUS_HANDLE_MAX] = { + [MDP3_BUS_HANDLE] = { + .bus_vector = mdp_bus_vectors, + .usecases = mdp_bus_usecases, + .scale_pdata = &mdp_bus_scale_table, + .current_bus_idx = 0, + .handle = 0, + }, +}; + +static struct mdss_panel_intf pan_types[] = { + {"dsi", MDSS_PANEL_INTF_DSI}, +}; +static char mdss_mdp3_panel[MDSS_MAX_PANEL_LEN]; + +struct mdp3_iommu_domain_map mdp3_iommu_domains[MDP3_IOMMU_DOMAIN_MAX] = { + [MDP3_IOMMU_DOMAIN_UNSECURE] = { + .domain_type = MDP3_IOMMU_DOMAIN_UNSECURE, + .client_name = "mdp_ns", + .npartitions = 1, + .domain_idx = MDP3_IOMMU_DOMAIN_UNSECURE, + }, + [MDP3_IOMMU_DOMAIN_SECURE] = { + .domain_type = MDP3_IOMMU_DOMAIN_SECURE, + .client_name = "mdp_secure", + .npartitions = 1, + .domain_idx = MDP3_IOMMU_DOMAIN_SECURE, + }, +}; + +static irqreturn_t mdp3_irq_handler(int irq, void *ptr) +{ + int i = 0; + struct mdp3_hw_resource *mdata = (struct mdp3_hw_resource *)ptr; + u32 mdp_interrupt = 0; + u32 mdp_status = 0; + + spin_lock(&mdata->irq_lock); + if (!mdata->irq_mask) { + pr_err("spurious interrupt\n"); + spin_unlock(&mdata->irq_lock); + return IRQ_HANDLED; + } + mdp_status = MDP3_REG_READ(MDP3_REG_INTR_STATUS); + mdp_interrupt = mdp_status; + pr_debug("%s irq=%d\n", __func__, mdp_interrupt); + + mdp_interrupt &= mdata->irq_mask; + + while (mdp_interrupt && i < MDP3_MAX_INTR) { + if ((mdp_interrupt & 0x1) && mdata->callbacks[i].cb) + mdata->callbacks[i].cb(i, mdata->callbacks[i].data); + mdp_interrupt = mdp_interrupt >> 1; + i++; + } + MDP3_REG_WRITE(MDP3_REG_INTR_CLEAR, mdp_status); + + spin_unlock(&mdata->irq_lock); + + return IRQ_HANDLED; +} + +void mdp3_irq_enable(int type) +{ + unsigned long flag; + + pr_debug("%s type=%d\n", __func__, type); + spin_lock_irqsave(&mdp3_res->irq_lock, flag); + if (mdp3_res->irq_ref_count[type] > 0) { + pr_debug("interrupt %d already enabled\n", type); + spin_unlock_irqrestore(&mdp3_res->irq_lock, flag); + return; + } + + mdp3_res->irq_mask |= BIT(type); + MDP3_REG_WRITE(MDP3_REG_INTR_ENABLE, mdp3_res->irq_mask); + + mdp3_res->irq_ref_count[type] += 1; + spin_unlock_irqrestore(&mdp3_res->irq_lock, flag); +} + +void mdp3_irq_disable(int type) +{ + unsigned long flag; + + spin_lock_irqsave(&mdp3_res->irq_lock, flag); + mdp3_irq_disable_nosync(type); + spin_unlock_irqrestore(&mdp3_res->irq_lock, flag); +} + +void mdp3_irq_disable_nosync(int type) +{ + if (mdp3_res->irq_ref_count[type] <= 0) { + pr_debug("interrupt %d not enabled\n", type); + return; + } + mdp3_res->irq_ref_count[type] -= 1; + if (mdp3_res->irq_ref_count[type] == 0) { + mdp3_res->irq_mask &= ~BIT(type); + MDP3_REG_WRITE(MDP3_REG_INTR_ENABLE, mdp3_res->irq_mask); + } +} + +int mdp3_set_intr_callback(u32 type, struct mdp3_intr_cb *cb) +{ + unsigned long flag; + + pr_debug("interrupt %d callback\n", type); + spin_lock_irqsave(&mdp3_res->irq_lock, flag); + if (cb) + mdp3_res->callbacks[type] = *cb; + else + mdp3_res->callbacks[type].cb = NULL; + + spin_unlock_irqrestore(&mdp3_res->irq_lock, flag); + return 0; +} + +void mdp3_irq_register(void) +{ + unsigned long flag; + struct mdss_hw *mdp3_hw; + + pr_debug("%s\n", __func__); + mdp3_hw = &mdp3_res->mdp3_hw; + spin_lock_irqsave(&mdp3_res->irq_lock, flag); + mdp3_res->irq_ref_cnt++; + if (mdp3_res->irq_ref_cnt == 1) { + MDP3_REG_WRITE(MDP3_REG_INTR_ENABLE, mdp3_res->irq_mask); + mdp3_res->mdss_util->enable_irq(&mdp3_res->mdp3_hw); + } + spin_unlock_irqrestore(&mdp3_res->irq_lock, flag); +} + +void mdp3_irq_deregister(void) +{ + unsigned long flag; + bool irq_enabled = true; + struct mdss_hw *mdp3_hw; + + pr_debug("%s\n", __func__); + mdp3_hw = &mdp3_res->mdp3_hw; + spin_lock_irqsave(&mdp3_res->irq_lock, flag); + memset(mdp3_res->irq_ref_count, 0, sizeof(u32) * MDP3_MAX_INTR); + mdp3_res->irq_mask = 0; + MDP3_REG_WRITE(MDP3_REG_INTR_ENABLE, 0); + mdp3_res->irq_ref_cnt--; + /* This can happen if suspend is called first */ + if (mdp3_res->irq_ref_cnt < 0) { + irq_enabled = false; + mdp3_res->irq_ref_cnt = 0; + } + if (mdp3_res->irq_ref_cnt == 0 && irq_enabled) + mdp3_res->mdss_util->disable_irq_nosync(&mdp3_res->mdp3_hw); + spin_unlock_irqrestore(&mdp3_res->irq_lock, flag); +} + +void mdp3_irq_suspend(void) +{ + unsigned long flag; + bool irq_enabled = true; + struct mdss_hw *mdp3_hw; + + pr_debug("%s\n", __func__); + mdp3_hw = &mdp3_res->mdp3_hw; + spin_lock_irqsave(&mdp3_res->irq_lock, flag); + mdp3_res->irq_ref_cnt--; + if (mdp3_res->irq_ref_cnt < 0) { + irq_enabled = false; + mdp3_res->irq_ref_cnt = 0; + } + if (mdp3_res->irq_ref_cnt == 0 && irq_enabled) { + MDP3_REG_WRITE(MDP3_REG_INTR_ENABLE, 0); + mdp3_res->mdss_util->disable_irq_nosync(&mdp3_res->mdp3_hw); + } + spin_unlock_irqrestore(&mdp3_res->irq_lock, flag); +} + +static int mdp3_bus_scale_register(void) +{ + int i, j; + + if (!mdp3_res->bus_handle) { + pr_err("No bus handle\n"); + return -EINVAL; + } + for (i = 0; i < MDP3_BUS_HANDLE_MAX; i++) { + struct mdp3_bus_handle_map *bus_handle = + &mdp3_res->bus_handle[i]; + + if (!bus_handle->handle) { + int j; + struct msm_bus_scale_pdata *bus_pdata = + bus_handle->scale_pdata; + + for (j = 0; j < bus_pdata->num_usecases; j++) { + bus_handle->usecases[j].num_paths = 1; + bus_handle->usecases[j].vectors = + &bus_handle->bus_vector[j]; + } + + bus_handle->handle = + msm_bus_scale_register_client(bus_pdata); + if (!bus_handle->handle) { + pr_err("not able to get bus scale i=%d\n", i); + return -ENOMEM; + } + pr_debug("register bus_hdl=%x\n", + bus_handle->handle); + } + + for (j = 0; j < MDP3_CLIENT_MAX; j++) { + bus_handle->ab[j] = 0; + bus_handle->ib[j] = 0; + } + } + return 0; +} + +static void mdp3_bus_scale_unregister(void) +{ + int i; + + if (!mdp3_res->bus_handle) + return; + + for (i = 0; i < MDP3_BUS_HANDLE_MAX; i++) { + pr_debug("unregister index=%d bus_handle=%x\n", + i, mdp3_res->bus_handle[i].handle); + if (mdp3_res->bus_handle[i].handle) { + msm_bus_scale_unregister_client( + mdp3_res->bus_handle[i].handle); + mdp3_res->bus_handle[i].handle = 0; + } + } +} + +int mdp3_bus_scale_set_quota(int client, u64 ab_quota, u64 ib_quota) +{ + struct mdp3_bus_handle_map *bus_handle; + int cur_bus_idx; + int bus_idx; + int client_idx; + u64 total_ib = 0, total_ab = 0; + int i, rc; + + client_idx = MDP3_BUS_HANDLE; + + bus_handle = &mdp3_res->bus_handle[client_idx]; + cur_bus_idx = bus_handle->current_bus_idx; + + if (bus_handle->handle < 1) { + pr_err("invalid bus handle %d\n", bus_handle->handle); + return -EINVAL; + } + + bus_handle->ab[client] = ab_quota; + bus_handle->ib[client] = ib_quota; + + for (i = 0; i < MDP3_CLIENT_MAX; i++) { + total_ab += bus_handle->ab[i]; + total_ib += bus_handle->ib[i]; + } + + if ((total_ab | total_ib) == 0) { + bus_idx = 0; + } else { + int num_cases = bus_handle->scale_pdata->num_usecases; + struct msm_bus_vectors *vect = NULL; + + bus_idx = (cur_bus_idx % (num_cases - 1)) + 1; + + /* aligning to avoid performing updates for small changes */ + total_ab = ALIGN(total_ab, SZ_64M); + total_ib = ALIGN(total_ib, SZ_64M); + + vect = bus_handle->scale_pdata->usecase[cur_bus_idx].vectors; + if ((total_ab == vect->ab) && (total_ib == vect->ib)) { + pr_debug("skip bus scaling, no change in vectors\n"); + return 0; + } + + vect = bus_handle->scale_pdata->usecase[bus_idx].vectors; + vect->ab = total_ab; + vect->ib = total_ib; + + pr_debug("bus scale idx=%d ab=%llu ib=%llu\n", bus_idx, + vect->ab, vect->ib); + } + bus_handle->current_bus_idx = bus_idx; + rc = msm_bus_scale_client_update_request(bus_handle->handle, bus_idx); + + if (!rc && ab_quota != 0 && ib_quota != 0) { + bus_handle->restore_ab[client] = ab_quota; + bus_handle->restore_ib[client] = ib_quota; + } + + return rc; +} + +static int mdp3_clk_update(u32 clk_idx, u32 enable) +{ + int ret = 0; + struct clk *clk; + int count = 0; + + if (clk_idx >= MDP3_MAX_CLK || !mdp3_res->clocks[clk_idx]) + return -ENODEV; + + clk = mdp3_res->clocks[clk_idx]; + + if (enable) + mdp3_res->clock_ref_count[clk_idx]++; + else + mdp3_res->clock_ref_count[clk_idx]--; + + count = mdp3_res->clock_ref_count[clk_idx]; + if (count == 1 && enable) { + pr_debug("clk=%d en=%d\n", clk_idx, enable); + ret = clk_prepare(clk); + if (ret) { + pr_err("%s: Failed to prepare clock %d", + __func__, clk_idx); + mdp3_res->clock_ref_count[clk_idx]--; + return ret; + } + if (clk_idx == MDP3_CLK_MDP_CORE) + MDSS_XLOG(enable); + ret = clk_enable(clk); + if (ret) + pr_err("%s: clock enable failed %d\n", __func__, + clk_idx); + } else if (count == 0) { + pr_debug("clk=%d disable\n", clk_idx); + if (clk_idx == MDP3_CLK_MDP_CORE) + MDSS_XLOG(enable); + clk_disable(clk); + clk_unprepare(clk); + ret = 0; + } else if (count < 0) { + pr_err("clk=%d count=%d\n", clk_idx, count); + ret = -EINVAL; + } + return ret; +} + + + +int mdp3_clk_set_rate(int clk_type, unsigned long clk_rate, + int client) +{ + int ret = 0; + unsigned long rounded_rate; + struct clk *clk = mdp3_res->clocks[clk_type]; + + if (clk) { + mutex_lock(&mdp3_res->res_mutex); + rounded_rate = clk_round_rate(clk, clk_rate); + if (IS_ERR_VALUE(rounded_rate)) { + pr_err("unable to round rate err=%ld\n", rounded_rate); + mutex_unlock(&mdp3_res->res_mutex); + return -EINVAL; + } + if (clk_type == MDP3_CLK_MDP_SRC) { + if (client == MDP3_CLIENT_DMA_P) { + mdp3_res->dma_core_clk_request = rounded_rate; + } else if (client == MDP3_CLIENT_PPP) { + mdp3_res->ppp_core_clk_request = rounded_rate; + } else { + pr_err("unrecognized client=%d\n", client); + mutex_unlock(&mdp3_res->res_mutex); + return -EINVAL; + } + rounded_rate = max(mdp3_res->dma_core_clk_request, + mdp3_res->ppp_core_clk_request); + } + if (rounded_rate != clk_get_rate(clk)) { + ret = clk_set_rate(clk, rounded_rate); + if (ret) + pr_err("clk_set_rate failed ret=%d\n", ret); + else + pr_debug("mdp clk rate=%lu, client = %d\n", + rounded_rate, client); + } + mutex_unlock(&mdp3_res->res_mutex); + } else { + pr_err("mdp src clk not setup properly\n"); + ret = -EINVAL; + } + return ret; +} + +unsigned long mdp3_get_clk_rate(u32 clk_idx) +{ + unsigned long clk_rate = 0; + struct clk *clk; + + if (clk_idx >= MDP3_MAX_CLK) + return -ENODEV; + + clk = mdp3_res->clocks[clk_idx]; + + if (clk) { + mutex_lock(&mdp3_res->res_mutex); + clk_rate = clk_get_rate(clk); + mutex_unlock(&mdp3_res->res_mutex); + } + return clk_rate; +} + +static int mdp3_clk_register(char *clk_name, int clk_idx) +{ + struct clk *tmp; + + if (clk_idx >= MDP3_MAX_CLK) { + pr_err("invalid clk index %d\n", clk_idx); + return -EINVAL; + } + + tmp = devm_clk_get(&mdp3_res->pdev->dev, clk_name); + if (IS_ERR(tmp)) { + pr_err("unable to get clk: %s\n", clk_name); + return PTR_ERR(tmp); + } + + mdp3_res->clocks[clk_idx] = tmp; + + return 0; +} + +static int mdp3_clk_setup(void) +{ + int rc; + + rc = mdp3_clk_register("iface_clk", MDP3_CLK_AHB); + if (rc) + return rc; + + rc = mdp3_clk_register("bus_clk", MDP3_CLK_AXI); + if (rc) + return rc; + + rc = mdp3_clk_register("core_clk_src", MDP3_CLK_MDP_SRC); + if (rc) + return rc; + + rc = mdp3_clk_register("core_clk", MDP3_CLK_MDP_CORE); + if (rc) + return rc; + + rc = mdp3_clk_register("vsync_clk", MDP3_CLK_VSYNC); + if (rc) + return rc; + + rc = mdp3_clk_set_rate(MDP3_CLK_MDP_SRC, MDP_CORE_CLK_RATE_SVS, + MDP3_CLIENT_DMA_P); + if (rc) + pr_err("%s: Error setting max clock during probe\n", __func__); + return rc; +} + +static void mdp3_clk_remove(void) +{ + if (!IS_ERR_OR_NULL(mdp3_res->clocks[MDP3_CLK_AHB])) + clk_put(mdp3_res->clocks[MDP3_CLK_AHB]); + + if (!IS_ERR_OR_NULL(mdp3_res->clocks[MDP3_CLK_AXI])) + clk_put(mdp3_res->clocks[MDP3_CLK_AXI]); + + if (!IS_ERR_OR_NULL(mdp3_res->clocks[MDP3_CLK_MDP_SRC])) + clk_put(mdp3_res->clocks[MDP3_CLK_MDP_SRC]); + + if (!IS_ERR_OR_NULL(mdp3_res->clocks[MDP3_CLK_MDP_CORE])) + clk_put(mdp3_res->clocks[MDP3_CLK_MDP_CORE]); + + if (!IS_ERR_OR_NULL(mdp3_res->clocks[MDP3_CLK_VSYNC])) + clk_put(mdp3_res->clocks[MDP3_CLK_VSYNC]); + +} + +u64 mdp3_clk_round_off(u64 clk_rate) +{ + u64 clk_round_off = 0; + + if (clk_rate <= MDP_CORE_CLK_RATE_SVS) + clk_round_off = MDP_CORE_CLK_RATE_SVS; + else if (clk_rate <= MDP_CORE_CLK_RATE_SUPER_SVS) + clk_round_off = MDP_CORE_CLK_RATE_SUPER_SVS; + else + clk_round_off = MDP_CORE_CLK_RATE_MAX; + + pr_debug("clk = %llu rounded to = %llu\n", + clk_rate, clk_round_off); + return clk_round_off; +} + +int mdp3_clk_enable(int enable, int dsi_clk) +{ + int rc = 0; + int changed = 0; + + pr_debug("MDP CLKS %s\n", (enable ? "Enable" : "Disable")); + + mutex_lock(&mdp3_res->res_mutex); + + if (enable) { + if (mdp3_res->clk_ena == 0) + changed++; + mdp3_res->clk_ena++; + } else { + if (mdp3_res->clk_ena) { + mdp3_res->clk_ena--; + if (mdp3_res->clk_ena == 0) + changed++; + } else { + pr_err("Can not be turned off\n"); + } + } + pr_debug("%s: clk_ena=%d changed=%d enable=%d\n", + __func__, mdp3_res->clk_ena, changed, enable); + + if (changed) { + if (enable) + pm_runtime_get_sync(&mdp3_res->pdev->dev); + + rc = mdp3_clk_update(MDP3_CLK_AHB, enable); + rc |= mdp3_clk_update(MDP3_CLK_AXI, enable); + rc |= mdp3_clk_update(MDP3_CLK_MDP_SRC, enable); + rc |= mdp3_clk_update(MDP3_CLK_MDP_CORE, enable); + rc |= mdp3_clk_update(MDP3_CLK_VSYNC, enable); + + if (!enable) { + pm_runtime_mark_last_busy(&mdp3_res->pdev->dev); + pm_runtime_put_autosuspend(&mdp3_res->pdev->dev); + } + } + + mutex_unlock(&mdp3_res->res_mutex); + return rc; +} + +void mdp3_bus_bw_iommu_enable(int enable, int client) +{ + struct mdp3_bus_handle_map *bus_handle; + int client_idx; + u64 ab = 0, ib = 0; + int ref_cnt; + + client_idx = MDP3_BUS_HANDLE; + + bus_handle = &mdp3_res->bus_handle[client_idx]; + if (bus_handle->handle < 1) { + pr_err("invalid bus handle %d\n", bus_handle->handle); + return; + } + mutex_lock(&mdp3_res->res_mutex); + if (enable) + bus_handle->ref_cnt++; + else + if (bus_handle->ref_cnt) + bus_handle->ref_cnt--; + ref_cnt = bus_handle->ref_cnt; + mutex_unlock(&mdp3_res->res_mutex); + + if (enable) { + if (mdp3_res->allow_iommu_update) + mdp3_iommu_enable(client); + if (ref_cnt == 1) { + pm_runtime_get_sync(&mdp3_res->pdev->dev); + ab = bus_handle->restore_ab[client]; + ib = bus_handle->restore_ib[client]; + mdp3_bus_scale_set_quota(client, ab, ib); + } + } else { + if (ref_cnt == 0) { + mdp3_bus_scale_set_quota(client, 0, 0); + pm_runtime_mark_last_busy(&mdp3_res->pdev->dev); + pm_runtime_put_autosuspend(&mdp3_res->pdev->dev); + } + mdp3_iommu_disable(client); + } + + if (ref_cnt < 0) { + pr_err("Ref count < 0, bus client=%d, ref_cnt=%d", + client_idx, ref_cnt); + } +} + +void mdp3_calc_dma_res(struct mdss_panel_info *panel_info, u64 *clk_rate, + u64 *ab, u64 *ib, uint32_t bpp) +{ + u32 vtotal = mdss_panel_get_vtotal(panel_info); + u32 htotal = mdss_panel_get_htotal(panel_info, 0); + u64 clk = htotal * vtotal * panel_info->mipi.frame_rate; + + pr_debug("clk_rate for dma = %llu, bpp = %d\n", clk, bpp); + if (clk_rate) + *clk_rate = mdp3_clk_round_off(clk); + + /* ab and ib vote should be same for honest voting */ + if (ab || ib) { + *ab = clk * bpp; + *ib = *ab; + } +} + +int mdp3_res_update(int enable, int dsi_clk, int client) +{ + int rc = 0; + + if (enable) { + rc = mdp3_clk_enable(enable, dsi_clk); + if (rc < 0) { + pr_err("mdp3_clk_enable failed, enable=%d, dsi_clk=%d\n", + enable, dsi_clk); + goto done; + } + mdp3_irq_register(); + mdp3_bus_bw_iommu_enable(enable, client); + } else { + mdp3_bus_bw_iommu_enable(enable, client); + mdp3_irq_suspend(); + rc = mdp3_clk_enable(enable, dsi_clk); + if (rc < 0) { + pr_err("mdp3_clk_enable failed, enable=%d, dsi_clk=%d\n", + enable, dsi_clk); + goto done; + } + } + +done: + return rc; +} + +int mdp3_get_mdp_dsi_clk(void) +{ + int rc; + + mutex_lock(&mdp3_res->res_mutex); + rc = mdp3_clk_update(MDP3_CLK_DSI, 1); + mutex_unlock(&mdp3_res->res_mutex); + return rc; +} + +int mdp3_put_mdp_dsi_clk(void) +{ + int rc; + + mutex_lock(&mdp3_res->res_mutex); + rc = mdp3_clk_update(MDP3_CLK_DSI, 0); + mutex_unlock(&mdp3_res->res_mutex); + return rc; +} + +static int mdp3_irq_setup(void) +{ + int ret; + struct mdss_hw *mdp3_hw; + + mdp3_hw = &mdp3_res->mdp3_hw; + ret = devm_request_irq(&mdp3_res->pdev->dev, + mdp3_hw->irq_info->irq, + mdp3_irq_handler, + 0, "MDP", mdp3_res); + if (ret) { + pr_err("mdp request_irq() failed!\n"); + return ret; + } + disable_irq_nosync(mdp3_hw->irq_info->irq); + mdp3_res->irq_registered = true; + return 0; +} + +static int mdp3_get_iommu_domain(u32 type) +{ + if (type >= MDSS_IOMMU_MAX_DOMAIN) + return -EINVAL; + + if (!mdp3_res) + return -ENODEV; + + return mdp3_res->domains[type].domain_idx; +} + +static int mdp3_check_version(void) +{ + int rc; + + rc = mdp3_clk_enable(1, 0); + if (rc) { + pr_err("fail to turn on MDP core clks\n"); + return rc; + } + + mdp3_res->mdp_rev = MDP3_REG_READ(MDP3_REG_HW_VERSION); + + if (mdp3_res->mdp_rev != MDP_CORE_HW_VERSION) { + pr_err("mdp_hw_revision=%x mismatch\n", mdp3_res->mdp_rev); + rc = -ENODEV; + } + + rc = mdp3_clk_enable(0, 0); + if (rc) + pr_err("fail to turn off MDP core clks\n"); + + return rc; +} + +static int mdp3_hw_init(void) +{ + int i; + + for (i = MDP3_DMA_P; i < MDP3_DMA_MAX; i++) { + mdp3_res->dma[i].dma_sel = i; + mdp3_res->dma[i].capability = MDP3_DMA_CAP_ALL; + mdp3_res->dma[i].in_use = 0; + mdp3_res->dma[i].available = 1; + mdp3_res->dma[i].cc_vect_sel = 0; + mdp3_res->dma[i].lut_sts = 0; + mdp3_res->dma[i].hist_cmap = NULL; + mdp3_res->dma[i].gc_cmap = NULL; + mutex_init(&mdp3_res->dma[i].pp_lock); + } + mdp3_res->dma[MDP3_DMA_S].capability = MDP3_DMA_CAP_DITHER; + mdp3_res->dma[MDP3_DMA_E].available = 0; + + for (i = MDP3_DMA_OUTPUT_SEL_AHB; i < MDP3_DMA_OUTPUT_SEL_MAX; i++) { + mdp3_res->intf[i].cfg.type = i; + mdp3_res->intf[i].active = 0; + mdp3_res->intf[i].in_use = 0; + mdp3_res->intf[i].available = 1; + } + mdp3_res->intf[MDP3_DMA_OUTPUT_SEL_AHB].available = 0; + mdp3_res->intf[MDP3_DMA_OUTPUT_SEL_LCDC].available = 0; + mdp3_res->smart_blit_en = SMART_BLIT_RGB_EN | SMART_BLIT_YUV_EN; + mdp3_res->solid_fill_vote_en = false; + return 0; +} + +int mdp3_dynamic_clock_gating_ctrl(int enable) +{ + int rc = 0; + int cgc_cfg = 0; + /*Disable dynamic auto clock gating*/ + pr_debug("%s Status %s\n", __func__, (enable ? "ON":"OFF")); + rc = mdp3_clk_enable(1, 0); + if (rc) { + pr_err("fail to turn on MDP core clks\n"); + return rc; + } + cgc_cfg = MDP3_REG_READ(MDP3_REG_CGC_EN); + if (enable) { + cgc_cfg |= (BIT(10)); + cgc_cfg |= (BIT(18)); + MDP3_REG_WRITE(MDP3_REG_CGC_EN, cgc_cfg); + VBIF_REG_WRITE(MDP3_VBIF_REG_FORCE_EN, 0x0); + } else { + cgc_cfg &= ~(BIT(10)); + cgc_cfg &= ~(BIT(18)); + MDP3_REG_WRITE(MDP3_REG_CGC_EN, cgc_cfg); + VBIF_REG_WRITE(MDP3_VBIF_REG_FORCE_EN, 0x3); + } + + rc = mdp3_clk_enable(0, 0); + if (rc) + pr_err("fail to turn off MDP core clks\n"); + + return rc; +} + +/** + * mdp3_get_panic_lut_cfg() - calculate panic and robust lut mask + * @panel_width: Panel width + * + * DMA buffer has 16 fill levels. Which needs to configured as safe + * and panic levels based on panel resolutions. + * No. of fill levels used = ((panel active width * 8) / 512). + * Roundoff the fill levels if needed. + * half of the total fill levels used will be treated as panic levels. + * Roundoff panic levels if total used fill levels are odd. + * + * Sample calculation for 720p display: + * Fill levels used = (720 * 8) / 512 = 12.5 after round off 13. + * panic levels = 13 / 2 = 6.5 after roundoff 7. + * Panic mask = 0x3FFF (2 bits per level) + * Robust mask = 0xFF80 (1 bit per level) + */ +u64 mdp3_get_panic_lut_cfg(u32 panel_width) +{ + u32 fill_levels = (((panel_width * 8) / 512) + 1); + u32 panic_mask = 0; + u32 robust_mask = 0; + u32 i = 0; + u64 panic_config = 0; + u32 panic_levels = 0; + + panic_levels = fill_levels / 2; + if (fill_levels % 2) + panic_levels++; + + for (i = 0; i < panic_levels; i++) { + panic_mask |= (BIT((i * 2) + 1) | BIT(i * 2)); + robust_mask |= BIT(i); + } + panic_config = ~robust_mask; + panic_config = panic_config << 32; + panic_config |= panic_mask; + return panic_config; +} + +int mdp3_enable_panic_ctrl(void) +{ + int rc = 0; + + if (MDP3_REG_READ(MDP3_PANIC_ROBUST_CTRL) == 0) { + pr_err("%s: Enable Panic Control\n", __func__); + MDP3_REG_WRITE(MDP3_PANIC_ROBUST_CTRL, BIT(0)); + } + return rc; +} + +int mdp3_qos_remapper_setup(struct mdss_panel_data *panel) +{ + int rc = 0; + u64 panic_config = mdp3_get_panic_lut_cfg(panel->panel_info.xres); + + rc = mdp3_clk_update(MDP3_CLK_AHB, 1); + rc |= mdp3_clk_update(MDP3_CLK_AXI, 1); + rc |= mdp3_clk_update(MDP3_CLK_MDP_CORE, 1); + if (rc) { + pr_err("fail to turn on MDP core clks\n"); + return rc; + } + + if (!panel) + return -EINVAL; + /* Program MDP QOS Remapper */ + MDP3_REG_WRITE(MDP3_DMA_P_QOS_REMAPPER, 0x1A9); + MDP3_REG_WRITE(MDP3_DMA_P_WATERMARK_0, 0x0); + MDP3_REG_WRITE(MDP3_DMA_P_WATERMARK_1, 0x0); + MDP3_REG_WRITE(MDP3_DMA_P_WATERMARK_2, 0x0); + /* PANIC setting depends on panel width*/ + MDP3_REG_WRITE(MDP3_PANIC_LUT0, (panic_config & 0xFFFF)); + MDP3_REG_WRITE(MDP3_PANIC_LUT1, ((panic_config >> 16) & 0xFFFF)); + MDP3_REG_WRITE(MDP3_ROBUST_LUT, ((panic_config >> 32) & 0xFFFF)); + MDP3_REG_WRITE(MDP3_PANIC_ROBUST_CTRL, 0x1); + pr_debug("Panel width %d Panic Lut0 %x Lut1 %x Robust %x\n", + panel->panel_info.xres, + MDP3_REG_READ(MDP3_PANIC_LUT0), + MDP3_REG_READ(MDP3_PANIC_LUT1), + MDP3_REG_READ(MDP3_ROBUST_LUT)); + + rc = mdp3_clk_update(MDP3_CLK_AHB, 0); + rc |= mdp3_clk_update(MDP3_CLK_AXI, 0); + rc |= mdp3_clk_update(MDP3_CLK_MDP_CORE, 0); + if (rc) + pr_err("fail to turn off MDP core clks\n"); + return rc; +} + +static int mdp3_res_init(void) +{ + int rc = 0; + + rc = mdp3_irq_setup(); + if (rc) + return rc; + + rc = mdp3_clk_setup(); + if (rc) + return rc; + + mdp3_res->ion_client = msm_ion_client_create(mdp3_res->pdev->name); + if (IS_ERR_OR_NULL(mdp3_res->ion_client)) { + pr_err("msm_ion_client_create() return error (%pK)\n", + mdp3_res->ion_client); + mdp3_res->ion_client = NULL; + return -EINVAL; + } + mutex_init(&mdp3_res->iommu_lock); + + mdp3_res->domains = mdp3_iommu_domains; + mdp3_res->bus_handle = mdp3_bus_handle; + rc = mdp3_bus_scale_register(); + if (rc) { + pr_err("unable to register bus scaling\n"); + return rc; + } + + rc = mdp3_hw_init(); + + return rc; +} + +static void mdp3_res_deinit(void) +{ + struct mdss_hw *mdp3_hw; + int rc = 0; + + mdp3_hw = &mdp3_res->mdp3_hw; + mdp3_bus_scale_unregister(); + mutex_lock(&mdp3_res->iommu_lock); + if (mdp3_res->iommu_ref_cnt) { + mdp3_res->iommu_ref_cnt--; + if (mdp3_res->iommu_ref_cnt == 0) + rc = mdss_smmu_detach(mdss_res); + } else { + pr_err("iommu ref count %d\n", mdp3_res->iommu_ref_cnt); + } + mutex_unlock(&mdp3_res->iommu_lock); + + if (!IS_ERR_OR_NULL(mdp3_res->ion_client)) + ion_client_destroy(mdp3_res->ion_client); + + mdp3_clk_remove(); + + if (mdp3_res->irq_registered) + devm_free_irq(&mdp3_res->pdev->dev, + mdp3_hw->irq_info->irq, mdp3_res); +} + +static int mdp3_get_pan_intf(const char *pan_intf) +{ + int i, rc = MDSS_PANEL_INTF_INVALID; + + if (!pan_intf) + return rc; + + for (i = 0; i < ARRAY_SIZE(pan_types); i++) { + if (!strcmp(pan_intf, pan_types[i].name)) { + rc = pan_types[i].type; + break; + } + } + + return rc; +} + +static int mdp3_parse_dt_pan_intf(struct platform_device *pdev) +{ + int rc; + struct mdp3_hw_resource *mdata = platform_get_drvdata(pdev); + const char *prim_intf = NULL; + + rc = of_property_read_string(pdev->dev.of_node, + "qcom,mdss-pref-prim-intf", &prim_intf); + if (rc) + return -ENODEV; + + rc = mdp3_get_pan_intf(prim_intf); + if (rc < 0) { + mdata->pan_cfg.pan_intf = MDSS_PANEL_INTF_INVALID; + } else { + mdata->pan_cfg.pan_intf = rc; + rc = 0; + } + return rc; +} + +static int mdp3_get_pan_cfg(struct mdss_panel_cfg *pan_cfg) +{ + char *t = NULL; + char pan_intf_str[MDSS_MAX_PANEL_LEN]; + int rc, i, panel_len; + char pan_name[MDSS_MAX_PANEL_LEN]; + + if (!pan_cfg) + return -EINVAL; + + if (mdss_mdp3_panel[0] == '0') { + pan_cfg->lk_cfg = false; + } else if (mdss_mdp3_panel[0] == '1') { + pan_cfg->lk_cfg = true; + } else { + /* read from dt */ + pan_cfg->lk_cfg = true; + pan_cfg->pan_intf = MDSS_PANEL_INTF_INVALID; + return -EINVAL; + } + + /* skip lk cfg and delimiter; ex: "0:" */ + strlcpy(pan_name, &mdss_mdp3_panel[2], MDSS_MAX_PANEL_LEN); + t = strnstr(pan_name, ":", MDSS_MAX_PANEL_LEN); + if (!t) { + pr_err("%s: pan_name=[%s] invalid\n", + __func__, pan_name); + pan_cfg->pan_intf = MDSS_PANEL_INTF_INVALID; + return -EINVAL; + } + + for (i = 0; ((pan_name + i) < t) && (i < 4); i++) + pan_intf_str[i] = *(pan_name + i); + pan_intf_str[i] = 0; + pr_debug("%s:%d panel intf %s\n", __func__, __LINE__, pan_intf_str); + /* point to the start of panel name */ + t = t + 1; + strlcpy(&pan_cfg->arg_cfg[0], t, sizeof(pan_cfg->arg_cfg)); + pr_debug("%s:%d: t=[%s] panel name=[%s]\n", __func__, __LINE__, + t, pan_cfg->arg_cfg); + + panel_len = strlen(pan_cfg->arg_cfg); + if (!panel_len) { + pr_err("%s: Panel name is invalid\n", __func__); + pan_cfg->pan_intf = MDSS_PANEL_INTF_INVALID; + return -EINVAL; + } + + rc = mdp3_get_pan_intf(pan_intf_str); + pan_cfg->pan_intf = (rc < 0) ? MDSS_PANEL_INTF_INVALID : rc; + return 0; +} + +static int mdp3_get_cmdline_config(struct platform_device *pdev) +{ + int rc, len = 0; + int *intf_type; + char *panel_name; + struct mdss_panel_cfg *pan_cfg; + struct mdp3_hw_resource *mdata = platform_get_drvdata(pdev); + + mdata->pan_cfg.arg_cfg[MDSS_MAX_PANEL_LEN] = 0; + pan_cfg = &mdata->pan_cfg; + panel_name = &pan_cfg->arg_cfg[0]; + intf_type = &pan_cfg->pan_intf; + + /* reads from dt by default */ + pan_cfg->lk_cfg = true; + + len = strlen(mdss_mdp3_panel); + + if (len > 0) { + rc = mdp3_get_pan_cfg(pan_cfg); + if (!rc) { + pan_cfg->init_done = true; + return rc; + } + } + + rc = mdp3_parse_dt_pan_intf(pdev); + /* if pref pan intf is not present */ + if (rc) + pr_err("%s:unable to parse device tree for pan intf\n", + __func__); + else + pan_cfg->init_done = true; + + return rc; +} + + +int mdp3_irq_init(u32 irq_start) +{ + struct mdss_hw *mdp3_hw; + + mdp3_hw = &mdp3_res->mdp3_hw; + + mdp3_hw->irq_info = kzalloc(sizeof(struct irq_info), GFP_KERNEL); + if (!mdp3_hw->irq_info) + return -ENOMEM; + + mdp3_hw->hw_ndx = MDSS_HW_MDP; + mdp3_hw->irq_info->irq = irq_start; + mdp3_hw->irq_info->irq_mask = 0; + mdp3_hw->irq_info->irq_ena = false; + mdp3_hw->irq_info->irq_buzy = false; + + mdp3_res->mdss_util->register_irq(&mdp3_res->mdp3_hw); + return 0; +} + +static int mdp3_parse_dt(struct platform_device *pdev) +{ + struct resource *res; + struct property *prop = NULL; + bool panic_ctrl; + int rc; + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mdp_phys"); + if (!res) { + pr_err("unable to get MDP base address\n"); + return -EINVAL; + } + + mdp3_res->mdp_reg_size = resource_size(res); + mdp3_res->mdp_base = devm_ioremap(&pdev->dev, res->start, + mdp3_res->mdp_reg_size); + if (unlikely(!mdp3_res->mdp_base)) { + pr_err("unable to map MDP base\n"); + return -ENOMEM; + } + + pr_debug("MDP HW Base phy_Address=0x%x virt=0x%x\n", + (int) res->start, + (int) mdp3_res->mdp_base); + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "vbif_phys"); + if (!res) { + pr_err("unable to get VBIF base address\n"); + return -EINVAL; + } + + mdp3_res->vbif_reg_size = resource_size(res); + mdp3_res->vbif_base = devm_ioremap(&pdev->dev, res->start, + mdp3_res->vbif_reg_size); + if (unlikely(!mdp3_res->vbif_base)) { + pr_err("unable to map VBIF base\n"); + return -ENOMEM; + } + + pr_debug("VBIF HW Base phy_Address=0x%x virt=0x%x\n", + (int) res->start, + (int) mdp3_res->vbif_base); + + res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + if (!res) { + pr_err("unable to get MDSS irq\n"); + return -EINVAL; + } + rc = mdp3_irq_init(res->start); + if (rc) { + pr_err("%s: Error in irq initialization:rc=[%d]\n", + __func__, rc); + return rc; + } + + rc = mdp3_get_cmdline_config(pdev); + if (rc) { + pr_err("%s: Error in panel override:rc=[%d]\n", + __func__, rc); + kfree(mdp3_res->mdp3_hw.irq_info); + return rc; + } + + prop = of_find_property(pdev->dev.of_node, "batfet-supply", NULL); + mdp3_res->batfet_required = prop ? true : false; + + panic_ctrl = of_property_read_bool( + pdev->dev.of_node, "qcom,mdss-has-panic-ctrl"); + mdp3_res->dma[MDP3_DMA_P].has_panic_ctrl = panic_ctrl; + + mdp3_res->idle_pc_enabled = of_property_read_bool( + pdev->dev.of_node, "qcom,mdss-idle-power-collapse-enabled"); + + return 0; +} + +void msm_mdp3_cx_ctrl(int enable) +{ + int rc; + + if (!mdp3_res->vdd_cx) { + mdp3_res->vdd_cx = devm_regulator_get(&mdp3_res->pdev->dev, + "vdd-cx"); + if (IS_ERR_OR_NULL(mdp3_res->vdd_cx)) { + pr_debug("unable to get CX reg. rc=%d\n", + PTR_RET(mdp3_res->vdd_cx)); + mdp3_res->vdd_cx = NULL; + return; + } + } + + if (enable) { + rc = regulator_set_voltage( + mdp3_res->vdd_cx, + RPM_REGULATOR_CORNER_SVS_SOC, + RPM_REGULATOR_CORNER_SUPER_TURBO); + if (rc < 0) + goto vreg_set_voltage_fail; + + rc = regulator_enable(mdp3_res->vdd_cx); + if (rc) { + pr_err("Failed to enable regulator vdd_cx.\n"); + return; + } + } else { + rc = regulator_disable(mdp3_res->vdd_cx); + if (rc) { + pr_err("Failed to disable regulator vdd_cx.\n"); + return; + } + rc = regulator_set_voltage( + mdp3_res->vdd_cx, + RPM_REGULATOR_CORNER_NONE, + RPM_REGULATOR_CORNER_SUPER_TURBO); + if (rc < 0) + goto vreg_set_voltage_fail; + } + + return; +vreg_set_voltage_fail: + pr_err("Set vltg failed\n"); +} + +void mdp3_batfet_ctrl(int enable) +{ + int rc; + + if (!mdp3_res->batfet_required) + return; + + if (!mdp3_res->batfet) { + if (enable) { + mdp3_res->batfet = + devm_regulator_get(&mdp3_res->pdev->dev, + "batfet"); + if (IS_ERR_OR_NULL(mdp3_res->batfet)) { + pr_debug("unable to get batfet reg. rc=%d\n", + PTR_RET(mdp3_res->batfet)); + mdp3_res->batfet = NULL; + return; + } + } else { + pr_debug("Batfet regulator disable w/o enable\n"); + return; + } + } + + if (enable) + rc = regulator_enable(mdp3_res->batfet); + else + rc = regulator_disable(mdp3_res->batfet); + + if (rc < 0) + pr_err("%s: reg enable/disable failed", __func__); +} + +void mdp3_enable_regulator(int enable) +{ + mdp3_batfet_ctrl(enable); +} + +int mdp3_put_img(struct mdp3_img_data *data, int client) +{ + struct ion_client *iclient = mdp3_res->ion_client; + int dom = (mdp3_res->domains + MDP3_IOMMU_DOMAIN_UNSECURE)->domain_idx; + int dir = DMA_BIDIRECTIONAL; + + if (data->flags & MDP_MEMORY_ID_TYPE_FB) { + pr_info("%s fb mem buf=0x%pa\n", __func__, &data->addr); + fdput(data->srcp_f); + memset(&data->srcp_f, 0, sizeof(struct fd)); + } else if (!IS_ERR_OR_NULL(data->srcp_dma_buf)) { + pr_debug("ion hdl = %pK buf=0x%pa\n", data->srcp_dma_buf, + &data->addr); + if (!iclient) { + pr_err("invalid ion client\n"); + return -ENOMEM; + } + if (data->mapped) { + if (client == MDP3_CLIENT_PPP || + client == MDP3_CLIENT_DMA_P) + mdss_smmu_unmap_dma_buf(data->tab_clone, + dom, dir, data->srcp_dma_buf); + else + mdss_smmu_unmap_dma_buf(data->srcp_table, + dom, dir, data->srcp_dma_buf); + data->mapped = false; + } + if (!data->skip_detach) { + dma_buf_unmap_attachment(data->srcp_attachment, + data->srcp_table, + mdss_smmu_dma_data_direction(dir)); + dma_buf_detach(data->srcp_dma_buf, + data->srcp_attachment); + dma_buf_put(data->srcp_dma_buf); + data->srcp_dma_buf = NULL; + } + } else { + return -EINVAL; + } + if (client == MDP3_CLIENT_PPP || client == MDP3_CLIENT_DMA_P) { + kfree(data->tab_clone->sgl); + kfree(data->tab_clone); + } + return 0; +} + +int mdp3_get_img(struct msmfb_data *img, struct mdp3_img_data *data, int client) +{ + struct fd f; + int ret = -EINVAL; + int fb_num; + struct ion_client *iclient = mdp3_res->ion_client; + int dom = (mdp3_res->domains + MDP3_IOMMU_DOMAIN_UNSECURE)->domain_idx; + + data->flags = img->flags; + + if (img->flags & MDP_MEMORY_ID_TYPE_FB) { + f = fdget(img->memory_id); + if (f.file == NULL) { + pr_err("invalid framebuffer file (%d)\n", + img->memory_id); + return -EINVAL; + } + if (MAJOR(f.file->f_path.dentry->d_inode->i_rdev) == FB_MAJOR) { + fb_num = MINOR(f.file->f_path.dentry->d_inode->i_rdev); + ret = mdss_fb_get_phys_info(&data->addr, + &data->len, fb_num); + if (ret) { + pr_err("mdss_fb_get_phys_info() failed\n"); + fdput(f); + memset(&f, 0, sizeof(struct fd)); + } + } else { + pr_err("invalid FB_MAJOR\n"); + fdput(f); + ret = -EINVAL; + } + data->srcp_f = f; + if (!ret) + goto done; + } else if (iclient) { + data->srcp_dma_buf = dma_buf_get(img->memory_id); + if (IS_ERR(data->srcp_dma_buf)) { + pr_err("DMA : error on ion_import_fd\n"); + ret = PTR_ERR(data->srcp_dma_buf); + data->srcp_dma_buf = NULL; + return ret; + } + + data->srcp_attachment = + mdss_smmu_dma_buf_attach(data->srcp_dma_buf, + &mdp3_res->pdev->dev, dom); + if (IS_ERR(data->srcp_attachment)) { + ret = PTR_ERR(data->srcp_attachment); + goto err_put; + } + + data->srcp_table = + dma_buf_map_attachment(data->srcp_attachment, + mdss_smmu_dma_data_direction(DMA_BIDIRECTIONAL)); + if (IS_ERR(data->srcp_table)) { + ret = PTR_ERR(data->srcp_table); + goto err_detach; + } + + if (client == MDP3_CLIENT_PPP || + client == MDP3_CLIENT_DMA_P) { + data->tab_clone = + mdss_smmu_sg_table_clone(data->srcp_table, + GFP_KERNEL, true); + if (IS_ERR_OR_NULL(data->tab_clone)) { + if (!(data->tab_clone)) + ret = -EINVAL; + else + ret = PTR_ERR(data->tab_clone); + goto clone_err; + } + ret = mdss_smmu_map_dma_buf(data->srcp_dma_buf, + data->tab_clone, dom, + &data->addr, &data->len, + DMA_BIDIRECTIONAL); + } else { + ret = mdss_smmu_map_dma_buf(data->srcp_dma_buf, + data->srcp_table, dom, &data->addr, + &data->len, DMA_BIDIRECTIONAL); + } + + if (IS_ERR_VALUE(ret)) { + pr_err("smmu map dma buf failed: (%d)\n", ret); + goto err_unmap; + } + + data->mapped = true; + data->skip_detach = false; + } +done: + if (client == MDP3_CLIENT_PPP || client == MDP3_CLIENT_DMA_P) { + data->addr += data->tab_clone->sgl->length; + data->len -= data->tab_clone->sgl->length; + } + if (!ret && (img->offset < data->len)) { + data->addr += img->offset; + data->len -= img->offset; + + pr_debug("mem=%d ihdl=%pK buf=0x%pa len=0x%lx\n", + img->memory_id, data->srcp_dma_buf, + &data->addr, data->len); + + } else { + mdp3_put_img(data, client); + return -EINVAL; + } + return ret; + +clone_err: + dma_buf_unmap_attachment(data->srcp_attachment, data->srcp_table, + mdss_smmu_dma_data_direction(DMA_BIDIRECTIONAL)); +err_detach: + dma_buf_detach(data->srcp_dma_buf, data->srcp_attachment); +err_put: + dma_buf_put(data->srcp_dma_buf); + return ret; +err_unmap: + dma_buf_unmap_attachment(data->srcp_attachment, data->srcp_table, + mdss_smmu_dma_data_direction(DMA_BIDIRECTIONAL)); + dma_buf_detach(data->srcp_dma_buf, data->srcp_attachment); + dma_buf_put(data->srcp_dma_buf); + + if (client == MDP3_CLIENT_PPP || client == MDP3_CLIENT_DMA_P) { + kfree(data->tab_clone->sgl); + kfree(data->tab_clone); + } + return ret; + +} + +int mdp3_iommu_enable(int client) +{ + int rc = 0; + + mutex_lock(&mdp3_res->iommu_lock); + + if (mdp3_res->iommu_ref_cnt == 0) { + rc = mdss_smmu_attach(mdss_res); + if (rc) + rc = mdss_smmu_detach(mdss_res); + } + + if (!rc) + mdp3_res->iommu_ref_cnt++; + mutex_unlock(&mdp3_res->iommu_lock); + + pr_debug("client :%d total_ref_cnt: %d\n", + client, mdp3_res->iommu_ref_cnt); + return rc; +} + +int mdp3_iommu_disable(int client) +{ + int rc = 0; + + mutex_lock(&mdp3_res->iommu_lock); + if (mdp3_res->iommu_ref_cnt) { + mdp3_res->iommu_ref_cnt--; + + pr_debug("client :%d total_ref_cnt: %d\n", + client, mdp3_res->iommu_ref_cnt); + if (mdp3_res->iommu_ref_cnt == 0) + rc = mdss_smmu_detach(mdss_res); + } else { + pr_err("iommu ref count unbalanced for client %d\n", client); + } + mutex_unlock(&mdp3_res->iommu_lock); + + return rc; +} + +int mdp3_iommu_ctrl(int enable) +{ + int rc; + + if (mdp3_res->allow_iommu_update == false) + return 0; + + if (enable) + rc = mdp3_iommu_enable(MDP3_CLIENT_DSI); + else + rc = mdp3_iommu_disable(MDP3_CLIENT_DSI); + return rc; +} + +static int mdp3_init(struct msm_fb_data_type *mfd) +{ + int rc; + + rc = mdp3_ctrl_init(mfd); + if (rc) { + pr_err("mdp3 ctl init fail\n"); + return rc; + } + + rc = mdp3_ppp_res_init(mfd); + if (rc) + pr_err("mdp3 ppp res init fail\n"); + + return rc; +} + +u32 mdp3_fb_stride(u32 fb_index, u32 xres, int bpp) +{ + /* + * The adreno GPU hardware requires that the pitch be aligned to + * 32 pixels for color buffers, so for the cases where the GPU + * is writing directly to fb0, the framebuffer pitch + * also needs to be 32 pixel aligned + */ + + if (fb_index == 0) + return ALIGN(xres, 32) * bpp; + else + return xres * bpp; +} + +__ref int mdp3_parse_dt_splash(struct msm_fb_data_type *mfd) +{ + struct platform_device *pdev = mfd->pdev; + int len = 0, rc = 0; + u32 offsets[2]; + struct device_node *pnode, *child_node; + struct property *prop = NULL; + + mfd->splash_info.splash_logo_enabled = + of_property_read_bool(pdev->dev.of_node, + "qcom,mdss-fb-splash-logo-enabled"); + + prop = of_find_property(pdev->dev.of_node, "qcom,memblock-reserve", + &len); + if (!prop) { + pr_debug("Read memblock reserve settings for fb failed\n"); + pr_debug("Read cont-splash-memory settings\n"); + } + + if (len) { + len = len / sizeof(u32); + + rc = of_property_read_u32_array(pdev->dev.of_node, + "qcom,memblock-reserve", offsets, len); + if (rc) { + pr_err("error reading mem reserve settings for fb\n"); + rc = -EINVAL; + goto error; + } + } else { + child_node = of_get_child_by_name(pdev->dev.of_node, + "qcom,cont-splash-memory"); + if (!child_node) { + pr_err("splash mem child node is not present\n"); + rc = -EINVAL; + goto error; + } + + pnode = of_parse_phandle(child_node, "linux,contiguous-region", + 0); + if (pnode != NULL) { + const u32 *addr; + u64 size; + + addr = of_get_address(pnode, 0, &size, NULL); + if (!addr) { + pr_err("failed to parse the splash memory address\n"); + of_node_put(pnode); + rc = -EINVAL; + goto error; + } + offsets[0] = (u32) of_read_ulong(addr, 2); + offsets[1] = (u32) size; + of_node_put(pnode); + } else { + pr_err("mem reservation for splash screen fb not present\n"); + rc = -EINVAL; + goto error; + } + } + + if (!memblock_is_reserved(offsets[0])) { + pr_debug("failed to reserve memory for fb splash\n"); + rc = -EINVAL; + goto error; + } + + mdp3_res->splash_mem_addr = offsets[0]; + mdp3_res->splash_mem_size = offsets[1]; +error: + if (rc && mfd->panel_info->cont_splash_enabled) + pr_err("no rsvd mem found in DT for splash screen\n"); + else + rc = 0; + + return rc; +} + +void mdp3_release_splash_memory(struct msm_fb_data_type *mfd) +{ + /* Give back the reserved memory to the system */ + if (mdp3_res->splash_mem_addr) { + if ((mfd->panel.type == MIPI_VIDEO_PANEL) && + (mdp3_res->cont_splash_en)) { + mdss_smmu_unmap(MDSS_IOMMU_DOMAIN_UNSECURE, + mdp3_res->splash_mem_addr, + mdp3_res->splash_mem_size); + } + pr_debug("%s\n", __func__); + memblock_free(mdp3_res->splash_mem_addr, + mdp3_res->splash_mem_size); + free_bootmem_late(mdp3_res->splash_mem_addr, + mdp3_res->splash_mem_size); + mdp3_res->splash_mem_addr = 0; + } +} + +struct mdp3_dma *mdp3_get_dma_pipe(int capability) +{ + int i; + + for (i = MDP3_DMA_P; i < MDP3_DMA_MAX; i++) { + if (!mdp3_res->dma[i].in_use && mdp3_res->dma[i].available && + mdp3_res->dma[i].capability & capability) { + mdp3_res->dma[i].in_use = true; + return &mdp3_res->dma[i]; + } + } + return NULL; +} + +struct mdp3_intf *mdp3_get_display_intf(int type) +{ + int i; + + for (i = MDP3_DMA_OUTPUT_SEL_AHB; i < MDP3_DMA_OUTPUT_SEL_MAX; i++) { + if (!mdp3_res->intf[i].in_use && mdp3_res->intf[i].available && + mdp3_res->intf[i].cfg.type == type) { + mdp3_res->intf[i].in_use = true; + return &mdp3_res->intf[i]; + } + } + return NULL; +} + +static int mdp3_fb_mem_get_iommu_domain(void) +{ + if (!mdp3_res) + return -ENODEV; + return mdp3_res->domains[MDP3_IOMMU_DOMAIN_UNSECURE].domain_idx; +} + +int mdp3_get_cont_spash_en(void) +{ + return mdp3_res->cont_splash_en; +} + +static int mdp3_is_display_on(struct mdss_panel_data *pdata) +{ + int rc = 0; + u32 status; + + rc = mdp3_clk_enable(1, 0); + if (rc) { + pr_err("fail to turn on MDP core clks\n"); + return rc; + } + if (pdata->panel_info.type == MIPI_VIDEO_PANEL) { + status = MDP3_REG_READ(MDP3_REG_DSI_VIDEO_EN); + rc = status & 0x1; + } else { + status = MDP3_REG_READ(MDP3_REG_DMA_P_CONFIG); + status &= 0x180000; + rc = (status == 0x080000); + } + + mdp3_res->splash_mem_addr = MDP3_REG_READ(MDP3_REG_DMA_P_IBUF_ADDR); + + if (mdp3_clk_enable(0, 0)) + pr_err("fail to turn off MDP core clks\n"); + return rc; +} + +static int mdp3_continuous_splash_on(struct mdss_panel_data *pdata) +{ + struct mdss_panel_info *panel_info = &pdata->panel_info; + struct mdp3_bus_handle_map *bus_handle; + u64 ab = 0; + u64 ib = 0; + u64 mdp_clk_rate = 0; + int rc = 0; + + pr_debug("mdp3__continuous_splash_on\n"); + + bus_handle = &mdp3_res->bus_handle[MDP3_BUS_HANDLE]; + if (bus_handle->handle < 1) { + pr_err("invalid bus handle %d\n", bus_handle->handle); + return -EINVAL; + } + mdp3_calc_dma_res(panel_info, &mdp_clk_rate, &ab, &ib, panel_info->bpp); + + mdp3_clk_set_rate(MDP3_CLK_VSYNC, MDP_VSYNC_CLK_RATE, + MDP3_CLIENT_DMA_P); + mdp3_clk_set_rate(MDP3_CLK_MDP_SRC, mdp_clk_rate, + MDP3_CLIENT_DMA_P); + + rc = mdp3_bus_scale_set_quota(MDP3_CLIENT_DMA_P, ab, ib); + bus_handle->restore_ab[MDP3_CLIENT_DMA_P] = ab; + bus_handle->restore_ib[MDP3_CLIENT_DMA_P] = ib; + + rc = mdp3_res_update(1, 1, MDP3_CLIENT_DMA_P); + if (rc) { + pr_err("fail to enable clk\n"); + return rc; + } + + rc = mdp3_ppp_init(); + if (rc) { + pr_err("ppp init failed\n"); + goto splash_on_err; + } + + if (panel_info->type == MIPI_VIDEO_PANEL) + mdp3_res->intf[MDP3_DMA_OUTPUT_SEL_DSI_VIDEO].active = 1; + else + mdp3_res->intf[MDP3_DMA_OUTPUT_SEL_DSI_CMD].active = 1; + + mdp3_enable_regulator(true); + mdp3_res->cont_splash_en = 1; + return 0; + +splash_on_err: + if (mdp3_res_update(0, 1, MDP3_CLIENT_DMA_P)) + pr_err("%s: Unable to disable mdp3 clocks\n", __func__); + + return rc; +} + +static int mdp3_panel_register_done(struct mdss_panel_data *pdata) +{ + int rc = 0; + u64 ab = 0; u64 ib = 0; + u64 mdp_clk_rate = 0; + + /* Store max bandwidth supported in mdp res */ + mdp3_calc_dma_res(&pdata->panel_info, &mdp_clk_rate, &ab, &ib, + MAX_BPP_SUPPORTED); + do_div(ab, 1024); + mdp3_res->max_bw = ab+1; + + /* + * If idle pc feature is not enabled, then get a reference to the + * runtime device which will be released when device is turned off + */ + if (!mdp3_res->idle_pc_enabled || + pdata->panel_info.type != MIPI_CMD_PANEL) { + pm_runtime_get_sync(&mdp3_res->pdev->dev); + } + + if (pdata->panel_info.cont_splash_enabled) { + if (!mdp3_is_display_on(pdata)) { + pr_err("continuous splash, but bootloader is not\n"); + return 0; + } + rc = mdp3_continuous_splash_on(pdata); + } else { + if (mdp3_is_display_on(pdata)) { + pr_err("lk continuous splash, but kerenl not\n"); + rc = mdp3_continuous_splash_on(pdata); + } + } + /* + * We want to prevent iommu from being enabled if there is + * continue splash screen. This would have happened in + * res_update in continuous_splash_on without this flag. + */ + if (pdata->panel_info.cont_splash_enabled == false) + mdp3_res->allow_iommu_update = true; + + mdss_res->pdata = pdata; + return rc; +} + +/* mdp3_clear_irq() - Clear interrupt + * @ interrupt_mask : interrupt mask + * + * This function clear sync irq for command mode panel. + * When system is entering in idle screen state. + */ +void mdp3_clear_irq(u32 interrupt_mask) +{ + unsigned long flag; + u32 irq_status = 0; + + spin_lock_irqsave(&mdp3_res->irq_lock, flag); + irq_status = interrupt_mask & + MDP3_REG_READ(MDP3_REG_INTR_STATUS); + if (irq_status) + MDP3_REG_WRITE(MDP3_REG_INTR_CLEAR, irq_status); + spin_unlock_irqrestore(&mdp3_res->irq_lock, flag); + +} + +/* mdp3_autorefresh_disable() - Disable Auto refresh + * @ panel_info : pointer to panel configuration structure + * + * This function disable Auto refresh block for command mode panel. + */ +int mdp3_autorefresh_disable(struct mdss_panel_info *panel_info) +{ + if ((panel_info->type == MIPI_CMD_PANEL) && + (MDP3_REG_READ(MDP3_REG_AUTOREFRESH_CONFIG_P))) + MDP3_REG_WRITE(MDP3_REG_AUTOREFRESH_CONFIG_P, 0); + return 0; +} + +int mdp3_splash_done(struct mdss_panel_info *panel_info) +{ + if (panel_info->cont_splash_enabled) { + pr_err("continuous splash is on and splash done called\n"); + return -EINVAL; + } + mdp3_res->allow_iommu_update = true; + return 0; +} + +static int mdp3_debug_dump_stats_show(struct seq_file *s, void *v) +{ + struct mdp3_hw_resource *res = (struct mdp3_hw_resource *)s->private; + + seq_printf(s, "underrun: %08u\n", res->underrun_cnt); + + return 0; +} +DEFINE_MDSS_DEBUGFS_SEQ_FOPS(mdp3_debug_dump_stats); + +static void mdp3_debug_enable_clock(int on) +{ + if (on) + mdp3_clk_enable(1, 0); + else + mdp3_clk_enable(0, 0); +} + +static int mdp3_debug_init(struct platform_device *pdev) +{ + int rc; + struct mdss_data_type *mdata; + struct mdss_debug_data *mdd; + + mdata = devm_kzalloc(&pdev->dev, sizeof(*mdata), GFP_KERNEL); + if (!mdata) + return -ENOMEM; + + mdss_res = mdata; + mutex_init(&mdata->reg_lock); + mutex_init(&mdata->reg_bus_lock); + mutex_init(&mdata->bus_lock); + INIT_LIST_HEAD(&mdata->reg_bus_clist); + atomic_set(&mdata->sd_client_count, 0); + atomic_set(&mdata->active_intf_cnt, 0); + mdss_res->mdss_util = mdp3_res->mdss_util; + + mdata->debug_inf.debug_enable_clock = mdp3_debug_enable_clock; + mdata->mdp_rev = mdp3_res->mdp_rev; + + rc = mdss_debugfs_init(mdata); + if (rc) + return rc; + + mdd = mdata->debug_inf.debug_data; + if (!mdd) + return -EINVAL; + + debugfs_create_file("stat", 0644, mdd->root, mdp3_res, + &mdp3_debug_dump_stats_fops); + + rc = mdss_debug_register_base(NULL, mdp3_res->mdp_base, + mdp3_res->mdp_reg_size, NULL); + + return rc; +} + +static void mdp3_debug_deinit(struct platform_device *pdev) +{ + if (mdss_res) { + mdss_debugfs_remove(mdss_res); + devm_kfree(&pdev->dev, mdss_res); + mdss_res = NULL; + } +} + +static void mdp3_dma_underrun_intr_handler(int type, void *arg) +{ + struct mdp3_dma *dma = &mdp3_res->dma[MDP3_DMA_P]; + + mdp3_res->underrun_cnt++; + pr_err_ratelimited("display underrun detected count=%d\n", + mdp3_res->underrun_cnt); + ATRACE_INT("mdp3_dma_underrun_intr_handler", mdp3_res->underrun_cnt); + + if (dma->ccs_config.ccs_enable && !dma->ccs_config.ccs_dirty) { + dma->ccs_config.ccs_dirty = true; + schedule_work(&dma->underrun_work); + } +} + +uint32_t ppp_formats_supported[] = { + MDP_RGB_565, + MDP_BGR_565, + MDP_RGB_888, + MDP_BGR_888, + MDP_XRGB_8888, + MDP_ARGB_8888, + MDP_RGBA_8888, + MDP_BGRA_8888, + MDP_RGBX_8888, + MDP_Y_CBCR_H2V1, + MDP_Y_CBCR_H2V2, + MDP_Y_CBCR_H2V2_ADRENO, + MDP_Y_CBCR_H2V2_VENUS, + MDP_Y_CRCB_H2V1, + MDP_Y_CRCB_H2V2, + MDP_YCRYCB_H2V1, + MDP_BGRX_8888, +}; + +uint32_t dma_formats_supported[] = { + MDP_RGB_565, + MDP_RGB_888, + MDP_XRGB_8888, +}; + +static void __mdp3_set_supported_formats(void) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(ppp_formats_supported); i++) + SET_BIT(mdp3_res->ppp_formats, ppp_formats_supported[i]); + + for (i = 0; i < ARRAY_SIZE(dma_formats_supported); i++) + SET_BIT(mdp3_res->dma_formats, dma_formats_supported[i]); +} + +static void __update_format_supported_info(char *buf, int *cnt) +{ + int j; + size_t len = PAGE_SIZE; + int num_bytes = BITS_TO_BYTES(MDP_IMGTYPE_LIMIT1); +#define SPRINT(fmt, ...) \ + (*cnt += scnprintf(buf + *cnt, len - *cnt, fmt, ##__VA_ARGS__)) + + SPRINT("ppp_input_fmts="); + for (j = 0; j < num_bytes; j++) + SPRINT("%d,", mdp3_res->ppp_formats[j]); + SPRINT("\ndma_output_fmts="); + for (j = 0; j < num_bytes; j++) + SPRINT("%d,", mdp3_res->dma_formats[j]); + SPRINT("\n"); +#undef SPRINT +} + +static ssize_t mdp3_show_capabilities(struct device *dev, + struct device_attribute *attr, char *buf) +{ + size_t len = PAGE_SIZE; + int cnt = 0; + +#define SPRINT(fmt, ...) \ + (cnt += scnprintf(buf + cnt, len - cnt, fmt, ##__VA_ARGS__)) + + SPRINT("dma_pipes=%d\n", 1); + SPRINT("mdp_version=3\n"); + SPRINT("hw_rev=%d\n", 305); + SPRINT("pipe_count:%d\n", 1); + SPRINT("pipe_num:%d pipe_type:dma pipe_ndx:%d rects:%d ", 0, 1, 1); + SPRINT("pipe_is_handoff:%d display_id:%d\n", 0, 0); + __update_format_supported_info(buf, &cnt); + SPRINT("rgb_pipes=%d\n", 0); + SPRINT("vig_pipes=%d\n", 0); + SPRINT("dma_pipes=%d\n", 1); + SPRINT("blending_stages=%d\n", 1); + SPRINT("cursor_pipes=%d\n", 0); + SPRINT("max_cursor_size=%d\n", 0); + SPRINT("smp_count=%d\n", 0); + SPRINT("smp_size=%d\n", 0); + SPRINT("smp_mb_per_pipe=%d\n", 0); + SPRINT("max_downscale_ratio=%d\n", PPP_DOWNSCALE_MAX); + SPRINT("max_upscale_ratio=%d\n", PPP_UPSCALE_MAX); + SPRINT("max_pipe_bw=%u\n", mdp3_res->max_bw); + SPRINT("max_bandwidth_low=%u\n", mdp3_res->max_bw); + SPRINT("max_bandwidth_high=%u\n", mdp3_res->max_bw); + SPRINT("max_mdp_clk=%u\n", MDP_CORE_CLK_RATE_MAX); + SPRINT("clk_fudge_factor=%u,%u\n", CLK_FUDGE_NUM, CLK_FUDGE_DEN); + SPRINT("features=has_ppp\n"); + +#undef SPRINT + + return cnt; +} + +static DEVICE_ATTR(caps, 0444, mdp3_show_capabilities, NULL); + +static ssize_t mdp3_store_smart_blit(struct device *dev, + struct device_attribute *attr, const char *buf, size_t len) +{ + u32 data = -1; + ssize_t rc = 0; + + rc = kstrtoint(buf, 10, &data); + if (rc) { + pr_err("kstrtoint failed. rc=%d\n", rc); + return rc; + } + mdp3_res->smart_blit_en = data; + pr_debug("mdp3 smart blit RGB %s YUV %s\n", + (mdp3_res->smart_blit_en & SMART_BLIT_RGB_EN) ? + "ENABLED" : "DISABLED", + (mdp3_res->smart_blit_en & SMART_BLIT_YUV_EN) ? + "ENABLED" : "DISABLED"); + return len; +} + +static ssize_t mdp3_show_smart_blit(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t ret = 0; + + pr_debug("mdp3 smart blit RGB %s YUV %s\n", + (mdp3_res->smart_blit_en & SMART_BLIT_RGB_EN) ? + "ENABLED" : "DISABLED", + (mdp3_res->smart_blit_en & SMART_BLIT_YUV_EN) ? + "ENABLED" : "DISABLED"); + ret = snprintf(buf, PAGE_SIZE, "%d\n", mdp3_res->smart_blit_en); + return ret; +} + +static DEVICE_ATTR(smart_blit, 0664, + mdp3_show_smart_blit, mdp3_store_smart_blit); + +static struct attribute *mdp3_fs_attrs[] = { + &dev_attr_caps.attr, + &dev_attr_smart_blit.attr, + NULL +}; + +static struct attribute_group mdp3_fs_attr_group = { + .attrs = mdp3_fs_attrs +}; + +static int mdp3_register_sysfs(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + int rc; + + rc = sysfs_create_group(&dev->kobj, &mdp3_fs_attr_group); + + return rc; +} + +int mdp3_create_sysfs_link(struct device *dev) +{ + int rc; + + rc = sysfs_create_link_nowarn(&dev->kobj, + &mdp3_res->pdev->dev.kobj, "mdp"); + + return rc; +} + +int mdp3_misr_get(struct mdp_misr *misr_resp) +{ + int result = 0, ret = -1; + int crc = 0; + + pr_debug("%s CRC Capture on DSI\n", __func__); + switch (misr_resp->block_id) { + case DISPLAY_MISR_DSI0: + MDP3_REG_WRITE(MDP3_REG_DSI_VIDEO_EN, 0); + /* Sleep for one vsync after DSI video engine is disabled */ + msleep(20); + /* Enable DSI_VIDEO_0 MISR Block */ + MDP3_REG_WRITE(MDP3_REG_MODE_DSI_PCLK, 0x20); + /* Reset MISR Block */ + MDP3_REG_WRITE(MDP3_REG_MISR_RESET_DSI_PCLK, 1); + /* Clear MISR capture done bit */ + MDP3_REG_WRITE(MDP3_REG_CAPTURED_DSI_PCLK, 0); + /* Enable MDP DSI interface */ + MDP3_REG_WRITE(MDP3_REG_DSI_VIDEO_EN, 1); + ret = readl_poll_timeout(mdp3_res->mdp_base + + MDP3_REG_CAPTURED_DSI_PCLK, result, + result & MDP3_REG_CAPTURED_DSI_PCLK_MASK, + MISR_POLL_SLEEP, MISR_POLL_TIMEOUT); + MDP3_REG_WRITE(MDP3_REG_MODE_DSI_PCLK, 0); + if (ret == 0) { + /* Disable DSI MISR interface */ + MDP3_REG_WRITE(MDP3_REG_MODE_DSI_PCLK, 0x0); + crc = MDP3_REG_READ(MDP3_REG_MISR_CAPT_VAL_DSI_PCLK); + pr_debug("CRC Val %d\n", crc); + } else { + pr_err("CRC Read Timed Out\n"); + } + break; + + case DISPLAY_MISR_DSI_CMD: + /* Select DSI PCLK Domain */ + MDP3_REG_WRITE(MDP3_REG_SEL_CLK_OR_HCLK_TEST_BUS, 0x004); + /* Select Block id DSI_CMD */ + MDP3_REG_WRITE(MDP3_REG_MODE_DSI_PCLK, 0x10); + /* Reset MISR Block */ + MDP3_REG_WRITE(MDP3_REG_MISR_RESET_DSI_PCLK, 1); + /* Drive Data on Test Bus */ + MDP3_REG_WRITE(MDP3_REG_EXPORT_MISR_DSI_PCLK, 0); + /* Kikk off DMA_P */ + MDP3_REG_WRITE(MDP3_REG_DMA_P_START, 0x11); + /* Wait for DMA_P Done */ + ret = readl_poll_timeout(mdp3_res->mdp_base + + MDP3_REG_INTR_STATUS, result, + result & MDP3_INTR_DMA_P_DONE_BIT, + MISR_POLL_SLEEP, MISR_POLL_TIMEOUT); + if (ret == 0) { + crc = MDP3_REG_READ(MDP3_REG_MISR_CURR_VAL_DSI_PCLK); + pr_debug("CRC Val %d\n", crc); + } else { + pr_err("CRC Read Timed Out\n"); + } + break; + + default: + pr_err("%s CRC Capture not supported\n", __func__); + ret = -EINVAL; + break; + } + + misr_resp->crc_value[0] = crc; + pr_debug("%s, CRC Capture on DSI Param Block = 0x%x, CRC 0x%x\n", + __func__, misr_resp->block_id, misr_resp->crc_value[0]); + return ret; +} + +int mdp3_misr_set(struct mdp_misr *misr_req) +{ + int ret = 0; + + pr_debug("%s Parameters Block = %d Cframe Count = %d CRC = %d\n", + __func__, misr_req->block_id, misr_req->frame_count, + misr_req->crc_value[0]); + + switch (misr_req->block_id) { + case DISPLAY_MISR_DSI0: + pr_debug("In the case DISPLAY_MISR_DSI0\n"); + MDP3_REG_WRITE(MDP3_REG_SEL_CLK_OR_HCLK_TEST_BUS, 1); + MDP3_REG_WRITE(MDP3_REG_MODE_DSI_PCLK, 0x20); + MDP3_REG_WRITE(MDP3_REG_MISR_RESET_DSI_PCLK, 0x1); + break; + + case DISPLAY_MISR_DSI_CMD: + pr_debug("In the case DISPLAY_MISR_DSI_CMD\n"); + MDP3_REG_WRITE(MDP3_REG_SEL_CLK_OR_HCLK_TEST_BUS, 1); + MDP3_REG_WRITE(MDP3_REG_MODE_DSI_PCLK, 0x10); + MDP3_REG_WRITE(MDP3_REG_MISR_RESET_DSI_PCLK, 0x1); + break; + + default: + pr_err("%s CRC Capture not supported\n", __func__); + ret = -EINVAL; + break; + } + return ret; +} + +struct mdss_panel_cfg *mdp3_panel_intf_type(int intf_val) +{ + if (!mdp3_res || !mdp3_res->pan_cfg.init_done) + return ERR_PTR(-EPROBE_DEFER); + + if (mdp3_res->pan_cfg.pan_intf == intf_val) + return &mdp3_res->pan_cfg; + else + return NULL; +} +EXPORT_SYMBOL(mdp3_panel_intf_type); + +int mdp3_footswitch_ctrl(int enable) +{ + int rc = 0; + int active_cnt = 0; + + mutex_lock(&mdp3_res->fs_idle_pc_lock); + MDSS_XLOG(enable); + if (!mdp3_res->fs_ena && enable) { + rc = regulator_enable(mdp3_res->fs); + if (rc) { + pr_err("mdp footswitch ctrl enable failed\n"); + mutex_unlock(&mdp3_res->fs_idle_pc_lock); + return -EINVAL; + } + pr_debug("mdp footswitch ctrl enable success\n"); + mdp3_enable_regulator(true); + mdp3_res->fs_ena = true; + } else if (!enable && mdp3_res->fs_ena) { + active_cnt = atomic_read(&mdp3_res->active_intf_cnt); + if (active_cnt != 0) { + /* + * Turning off GDSC while overlays are still + * active. + */ + mdp3_res->idle_pc = true; + pr_debug("idle pc. active overlays=%d\n", + active_cnt); + } + mdp3_enable_regulator(false); + rc = regulator_disable(mdp3_res->fs); + if (rc) { + pr_err("mdp footswitch ctrl disable failed\n"); + mutex_unlock(&mdp3_res->fs_idle_pc_lock); + return -EINVAL; + } + mdp3_res->fs_ena = false; + pr_debug("mdp3 footswitch ctrl disable configured\n"); + } else { + pr_debug("mdp3 footswitch ctrl already configured\n"); + } + + mutex_unlock(&mdp3_res->fs_idle_pc_lock); + return rc; +} + +int mdp3_panel_get_intf_status(u32 disp_num, u32 intf_type) +{ + int rc = 0, status = 0; + + if (intf_type != MDSS_PANEL_INTF_DSI) + return 0; + + rc = mdp3_clk_enable(1, 0); + if (rc) { + pr_err("fail to turn on MDP core clks\n"); + return rc; + } + + status = (MDP3_REG_READ(MDP3_REG_DMA_P_CONFIG) & 0x180000); + /* DSI video mode or command mode */ + rc = (status == 0x180000) || (status == 0x080000); + + if (mdp3_clk_enable(0, 0)) + pr_err("fail to turn off MDP core clks\n"); + return rc; +} + +static int mdp3_probe(struct platform_device *pdev) +{ + int rc; + static struct msm_mdp_interface mdp3_interface = { + .init_fnc = mdp3_init, + .fb_mem_get_iommu_domain = mdp3_fb_mem_get_iommu_domain, + .panel_register_done = mdp3_panel_register_done, + .fb_stride = mdp3_fb_stride, + .check_dsi_status = mdp3_check_dsi_ctrl_status, + }; + + struct mdp3_intr_cb underrun_cb = { + .cb = mdp3_dma_underrun_intr_handler, + .data = NULL, + }; + + pr_debug("%s: START\n", __func__); + if (!pdev->dev.of_node) { + pr_err("MDP driver only supports device tree probe\n"); + return -ENOTSUPP; + } + + if (mdp3_res) { + pr_err("MDP already initialized\n"); + return -EINVAL; + } + + mdp3_res = devm_kzalloc(&pdev->dev, sizeof(struct mdp3_hw_resource), + GFP_KERNEL); + if (mdp3_res == NULL) + return -ENOMEM; + + pdev->id = 0; + mdp3_res->pdev = pdev; + mutex_init(&mdp3_res->res_mutex); + mutex_init(&mdp3_res->fs_idle_pc_lock); + spin_lock_init(&mdp3_res->irq_lock); + platform_set_drvdata(pdev, mdp3_res); + atomic_set(&mdp3_res->active_intf_cnt, 0); + mutex_init(&mdp3_res->reg_bus_lock); + INIT_LIST_HEAD(&mdp3_res->reg_bus_clist); + + mdp3_res->mdss_util = mdss_get_util_intf(); + if (mdp3_res->mdss_util == NULL) { + pr_err("Failed to get mdss utility functions\n"); + rc = -ENODEV; + goto get_util_fail; + } + mdp3_res->mdss_util->get_iommu_domain = mdp3_get_iommu_domain; + mdp3_res->mdss_util->iommu_attached = is_mdss_iommu_attached; + mdp3_res->mdss_util->iommu_ctrl = mdp3_iommu_ctrl; + mdp3_res->mdss_util->bus_scale_set_quota = mdp3_bus_scale_set_quota; + mdp3_res->mdss_util->panel_intf_type = mdp3_panel_intf_type; + mdp3_res->mdss_util->dyn_clk_gating_ctrl = + mdp3_dynamic_clock_gating_ctrl; + mdp3_res->mdss_util->panel_intf_type = mdp3_panel_intf_type; + mdp3_res->mdss_util->panel_intf_status = mdp3_panel_get_intf_status; + + if (mdp3_res->mdss_util->param_check(mdss_mdp3_panel)) { + mdp3_res->mdss_util->display_disabled = true; + mdp3_res->mdss_util->mdp_probe_done = true; + return 0; + } + + rc = mdp3_parse_dt(pdev); + if (rc) + goto probe_done; + + rc = mdp3_res_init(); + if (rc) { + pr_err("unable to initialize mdp3 resources\n"); + goto probe_done; + } + + mdp3_res->fs_ena = false; + mdp3_res->fs = devm_regulator_get(&pdev->dev, "vdd"); + if (IS_ERR_OR_NULL(mdp3_res->fs)) { + pr_err("unable to get mdss gdsc regulator\n"); + return -EINVAL; + } + + rc = mdp3_debug_init(pdev); + if (rc) { + pr_err("unable to initialize mdp debugging\n"); + goto probe_done; + } + + pm_runtime_set_autosuspend_delay(&pdev->dev, AUTOSUSPEND_TIMEOUT_MS); + if (mdp3_res->idle_pc_enabled) { + pr_debug("%s: Enabling autosuspend\n", __func__); + pm_runtime_use_autosuspend(&pdev->dev); + } + /* Enable PM runtime */ + pm_runtime_set_suspended(&pdev->dev); + pm_runtime_enable(&pdev->dev); + + if (!pm_runtime_enabled(&pdev->dev)) { + rc = mdp3_footswitch_ctrl(1); + if (rc) { + pr_err("unable to turn on FS\n"); + goto probe_done; + } + } + + rc = mdp3_check_version(); + if (rc) { + pr_err("mdp3 check version failed\n"); + goto probe_done; + } + rc = mdp3_register_sysfs(pdev); + if (rc) + pr_err("unable to register mdp sysfs nodes\n"); + + rc = mdss_fb_register_mdp_instance(&mdp3_interface); + if (rc) + pr_err("unable to register mdp instance\n"); + + rc = mdp3_set_intr_callback(MDP3_INTR_LCDC_UNDERFLOW, + &underrun_cb); + if (rc) + pr_err("unable to configure interrupt callback\n"); + + rc = mdss_smmu_init(mdss_res, &pdev->dev); + if (rc) + pr_err("mdss smmu init failed\n"); + + __mdp3_set_supported_formats(); + + mdp3_res->mdss_util->mdp_probe_done = true; + pr_debug("%s: END\n", __func__); + +probe_done: + if (IS_ERR_VALUE(rc)) + kfree(mdp3_res->mdp3_hw.irq_info); +get_util_fail: + if (IS_ERR_VALUE(rc)) { + mdp3_res_deinit(); + + if (mdp3_res->mdp_base) + devm_iounmap(&pdev->dev, mdp3_res->mdp_base); + + devm_kfree(&pdev->dev, mdp3_res); + mdp3_res = NULL; + + if (mdss_res) { + devm_kfree(&pdev->dev, mdss_res); + mdss_res = NULL; + } + } + + return rc; +} + +int mdp3_panel_get_boot_cfg(void) +{ + int rc; + + if (!mdp3_res || !mdp3_res->pan_cfg.init_done) + rc = -EPROBE_DEFER; + else if (mdp3_res->pan_cfg.lk_cfg) + rc = 1; + else + rc = 0; + return rc; +} + +static int mdp3_suspend_sub(void) +{ + mdp3_footswitch_ctrl(0); + return 0; +} + +static int mdp3_resume_sub(void) +{ + mdp3_footswitch_ctrl(1); + return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int mdp3_pm_suspend(struct device *dev) +{ + dev_dbg(dev, "Display pm suspend\n"); + MDSS_XLOG(XLOG_FUNC_ENTRY); + return mdp3_suspend_sub(); +} + +static int mdp3_pm_resume(struct device *dev) +{ + dev_dbg(dev, "Display pm resume\n"); + + /* + * It is possible that the runtime status of the mdp device may + * have been active when the system was suspended. Reset the runtime + * status to suspended state after a complete system resume. + */ + pm_runtime_disable(dev); + pm_runtime_set_suspended(dev); + pm_runtime_enable(dev); + + MDSS_XLOG(XLOG_FUNC_ENTRY); + return mdp3_resume_sub(); +} +#endif + +#if defined(CONFIG_PM) && !defined(CONFIG_PM_SLEEP) +static int mdp3_suspend(struct platform_device *pdev, pm_message_t state) +{ + pr_debug("Display suspend\n"); + + MDSS_XLOG(XLOG_FUNC_ENTRY); + return mdp3_suspend_sub(); +} + +static int mdp3_resume(struct platform_device *pdev) +{ + pr_debug("Display resume\n"); + + MDSS_XLOG(XLOG_FUNC_ENTRY); + return mdp3_resume_sub(); +} +#else +#define mdp3_suspend NULL +#define mdp3_resume NULL +#endif + +#ifdef CONFIG_PM +static int mdp3_runtime_resume(struct device *dev) +{ + bool device_on = true; + + dev_dbg(dev, "Display pm runtime resume, active overlay cnt=%d\n", + atomic_read(&mdp3_res->active_intf_cnt)); + + /* do not resume panels when coming out of idle power collapse */ + if (!mdp3_res->idle_pc) + device_for_each_child(dev, &device_on, mdss_fb_suspres_panel); + + MDSS_XLOG(XLOG_FUNC_ENTRY); + mdp3_footswitch_ctrl(1); + + return 0; +} + +static int mdp3_runtime_idle(struct device *dev) +{ + dev_dbg(dev, "Display pm runtime idle\n"); + + return 0; +} + +static int mdp3_runtime_suspend(struct device *dev) +{ + bool device_on = false; + + dev_dbg(dev, "Display pm runtime suspend, active overlay cnt=%d\n", + atomic_read(&mdp3_res->active_intf_cnt)); + + if (mdp3_res->clk_ena) { + pr_debug("Clk turned on...MDP suspend failed\n"); + return -EBUSY; + } + + MDSS_XLOG(XLOG_FUNC_ENTRY); + mdp3_footswitch_ctrl(0); + + /* do not suspend panels when going in to idle power collapse */ + if (!mdp3_res->idle_pc) + device_for_each_child(dev, &device_on, mdss_fb_suspres_panel); + + return 0; +} +#endif + +static const struct dev_pm_ops mdp3_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(mdp3_pm_suspend, + mdp3_pm_resume) + SET_RUNTIME_PM_OPS(mdp3_runtime_suspend, + mdp3_runtime_resume, + mdp3_runtime_idle) +}; + + +static int mdp3_remove(struct platform_device *pdev) +{ + struct mdp3_hw_resource *mdata = platform_get_drvdata(pdev); + + if (!mdata) + return -ENODEV; + pm_runtime_disable(&pdev->dev); + mdp3_bus_scale_unregister(); + mdp3_clk_remove(); + mdp3_debug_deinit(pdev); + return 0; +} + +static const struct of_device_id mdp3_dt_match[] = { + { .compatible = "qcom,mdss_mdp3",}, + {} +}; +MODULE_DEVICE_TABLE(of, mdp3_dt_match); +EXPORT_COMPAT("qcom,mdss_mdp3"); + +static struct platform_driver mdp3_driver = { + .probe = mdp3_probe, + .remove = mdp3_remove, + .suspend = mdp3_suspend, + .resume = mdp3_resume, + .shutdown = NULL, + .driver = { + .name = "mdp3", + .of_match_table = mdp3_dt_match, + .pm = &mdp3_pm_ops, + }, +}; + +static int __init mdp3_driver_init(void) +{ + int ret; + + ret = platform_driver_register(&mdp3_driver); + if (ret) { + pr_err("register mdp3 driver failed!\n"); + return ret; + } + + return 0; +} + +module_param_string(panel, mdss_mdp3_panel, MDSS_MAX_PANEL_LEN, 0600); +/* + * panel=:: + * where is "1"-lk/gcdb config or "0" non-lk/non-gcdb + * config; is dsi:0 + * is panel interface specific string + * Ex: This string is panel's device node name from DT + * for DSI interface + */ +MODULE_PARM_DESC(panel, "lk supplied panel selection string"); +module_init(mdp3_driver_init); diff --git a/drivers/video/fbdev/msm/mdp3.h b/drivers/video/fbdev/msm/mdp3.h new file mode 100644 index 000000000000..6fb39a73649d --- /dev/null +++ b/drivers/video/fbdev/msm/mdp3.h @@ -0,0 +1,292 @@ +/* Copyright (c) 2013-2014, 2016-2018, The Linux Foundation. All rights reserved. + * Copyright (C) 2007 Google Incorporated + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +#ifndef MDP3_H +#define MDP3_H + +#include +#include +#include +#include + +#include "mdss_dsi_clk.h" +#include "mdp3_dma.h" +#include "mdss_fb.h" +#include "mdss.h" + +#define MDP_VSYNC_CLK_RATE 19200000 +#define MDP_CORE_CLK_RATE_SVS 160000000 +#define MDP_CORE_CLK_RATE_SUPER_SVS 200000000 +#define MDP_CORE_CLK_RATE_MAX 307200000 + +#define CLK_FUDGE_NUM 12 +#define CLK_FUDGE_DEN 10 + +/* PPP cant work at SVS for panel res above qHD */ +#define SVS_MAX_PIXEL (540 * 960) + +#define KOFF_TIMEOUT_MS 84 +#define KOFF_TIMEOUT msecs_to_jiffies(KOFF_TIMEOUT_MS) +#define WAIT_DMA_TIMEOUT msecs_to_jiffies(84) + +/* + * MDP_DEINTERLACE & MDP_SHARPENING Flags are not valid for MDP3 + * so using them together for MDP_SMART_BLIT. + */ +#define MDP_SMART_BLIT 0xC0000000 + +#define BITS_PER_BYTE 8 +#define MDP_IMGTYPE_LIMIT1 0x100 +#define BITS_TO_BYTES(x) DIV_ROUND_UP(x, BITS_PER_BYTE) + +enum { + MDP3_CLK_AHB, + MDP3_CLK_AXI, + MDP3_CLK_MDP_SRC, + MDP3_CLK_MDP_CORE, + MDP3_CLK_VSYNC, + MDP3_CLK_DSI, + MDP3_MAX_CLK +}; + +enum { + MDP3_BUS_HANDLE, + MDP3_BUS_HANDLE_MAX, +}; + +enum { + MDP3_IOMMU_DOMAIN_UNSECURE, + MDP3_IOMMU_DOMAIN_SECURE, + MDP3_IOMMU_DOMAIN_MAX, +}; + +enum { + MDP3_IOMMU_CTX_MDP_0, + MDP3_IOMMU_CTX_MDP_1, + MDP3_IOMMU_CTX_MAX +}; + +/* Keep DSI entry in sync with mdss + * which is being used by DSI 6G + */ +enum { + MDP3_CLIENT_DMA_P, + MDP3_CLIENT_DSI = 1, + MDP3_CLIENT_PPP, + MDP3_CLIENT_IOMMU, + MDP3_CLIENT_MAX, +}; + +enum { + DI_PARTITION_NUM = 0, + DI_DOMAIN_NUM = 1, + DI_MAX, +}; + +struct mdp3_bus_handle_map { + struct msm_bus_vectors *bus_vector; + struct msm_bus_paths *usecases; + struct msm_bus_scale_pdata *scale_pdata; + int current_bus_idx; + int ref_cnt; + u64 restore_ab[MDP3_CLIENT_MAX]; + u64 restore_ib[MDP3_CLIENT_MAX]; + u64 ab[MDP3_CLIENT_MAX]; + u64 ib[MDP3_CLIENT_MAX]; + u32 handle; +}; + +struct mdp3_iommu_domain_map { + u32 domain_type; + char *client_name; + int npartitions; + int domain_idx; + struct iommu_domain *domain; +}; + +struct mdp3_iommu_ctx_map { + u32 ctx_type; + struct mdp3_iommu_domain_map *domain; + char *ctx_name; + struct device *ctx; + int attached; +}; + +struct mdp3_iommu_meta { + struct rb_node node; + struct ion_handle *handle; + struct rb_root iommu_maps; + struct kref ref; + struct sg_table *table; + struct dma_buf *dbuf; + int mapped_size; + unsigned long size; + dma_addr_t iova_addr; + unsigned long flags; +}; + +#define MDP3_MAX_INTR 28 + +struct mdp3_intr_cb { + void (*cb)(int type, void *); + void *data; +}; + +#define SMART_BLIT_RGB_EN 1 +#define SMART_BLIT_YUV_EN 2 + +struct mdp3_hw_resource { + struct platform_device *pdev; + u32 mdp_rev; + + struct mutex res_mutex; + + struct clk *clocks[MDP3_MAX_CLK]; + int clock_ref_count[MDP3_MAX_CLK]; + unsigned long dma_core_clk_request; + unsigned long ppp_core_clk_request; + struct mdss_hw mdp3_hw; + struct mdss_util_intf *mdss_util; + + char __iomem *mdp_base; + size_t mdp_reg_size; + + char __iomem *vbif_base; + size_t vbif_reg_size; + + struct mdp3_bus_handle_map *bus_handle; + + struct ion_client *ion_client; + struct mdp3_iommu_domain_map *domains; + struct mdp3_iommu_ctx_map *iommu_contexts; + unsigned int iommu_ref_cnt; + bool allow_iommu_update; + struct ion_handle *ion_handle; + struct mutex iommu_lock; + struct mutex fs_idle_pc_lock; + + struct mdp3_dma dma[MDP3_DMA_MAX]; + struct mdp3_intf intf[MDP3_DMA_OUTPUT_SEL_MAX]; + + struct rb_root iommu_root; + spinlock_t irq_lock; + u32 irq_ref_count[MDP3_MAX_INTR]; + u32 irq_mask; + int irq_ref_cnt; + struct mdp3_intr_cb callbacks[MDP3_MAX_INTR]; + u32 underrun_cnt; + + int irq_registered; + + unsigned long splash_mem_addr; + u32 splash_mem_size; + struct mdss_panel_cfg pan_cfg; + + int clk_prepare_count; + int cont_splash_en; + + bool batfet_required; + struct regulator *batfet; + struct regulator *vdd_cx; + struct regulator *fs; + bool fs_ena; + int clk_ena; + bool idle_pc_enabled; + bool idle_pc; + atomic_t active_intf_cnt; + u8 smart_blit_en; + bool solid_fill_vote_en; + struct list_head reg_bus_clist; + struct mutex reg_bus_lock; + + u32 max_bw; + + u8 ppp_formats[BITS_TO_BYTES(MDP_IMGTYPE_LIMIT1)]; + u8 dma_formats[BITS_TO_BYTES(MDP_IMGTYPE_LIMIT1)]; +}; + +struct mdp3_img_data { + dma_addr_t addr; + unsigned long len; + u32 offset; + u32 flags; + u32 padding; + int p_need; + struct ion_handle *srcp_ihdl; + u32 dir; + u32 domain; + bool mapped; + bool skip_detach; + struct fd srcp_f; + struct dma_buf *srcp_dma_buf; + struct dma_buf_attachment *srcp_attachment; + struct sg_table *srcp_table; + struct sg_table *tab_clone; +}; + +extern struct mdp3_hw_resource *mdp3_res; + +struct mdp3_dma *mdp3_get_dma_pipe(int capability); +struct mdp3_intf *mdp3_get_display_intf(int type); +void mdp3_irq_enable(int type); +void mdp3_irq_disable(int type); +void mdp3_irq_disable_nosync(int type); +int mdp3_set_intr_callback(u32 type, struct mdp3_intr_cb *cb); +void mdp3_irq_register(void); +void mdp3_irq_deregister(void); +int mdp3_clk_set_rate(int clk_type, unsigned long clk_rate, int client); +int mdp3_clk_enable(int enable, int dsi_clk); +int mdp3_res_update(int enable, int dsi_clk, int client); +int mdp3_bus_scale_set_quota(int client, u64 ab_quota, u64 ib_quota); +int mdp3_put_img(struct mdp3_img_data *data, int client); +int mdp3_get_img(struct msmfb_data *img, struct mdp3_img_data *data, + int client); +int mdp3_iommu_enable(int client); +int mdp3_iommu_disable(int client); +int mdp3_iommu_is_attached(void); +void mdp3_free(struct msm_fb_data_type *mfd); +int mdp3_parse_dt_splash(struct msm_fb_data_type *mfd); +void mdp3_release_splash_memory(struct msm_fb_data_type *mfd); +int mdp3_create_sysfs_link(struct device *dev); +int mdp3_get_cont_spash_en(void); +int mdp3_get_mdp_dsi_clk(void); +int mdp3_put_mdp_dsi_clk(void); + +int mdp3_misr_set(struct mdp_misr *misr_req); +int mdp3_misr_get(struct mdp_misr *misr_resp); +void mdp3_enable_regulator(int enable); +void mdp3_check_dsi_ctrl_status(struct work_struct *work, + uint32_t interval); +int mdp3_dynamic_clock_gating_ctrl(int enable); +int mdp3_footswitch_ctrl(int enable); +int mdp3_qos_remapper_setup(struct mdss_panel_data *panel); +int mdp3_splash_done(struct mdss_panel_info *panel_info); +int mdp3_autorefresh_disable(struct mdss_panel_info *panel_info); +u64 mdp3_clk_round_off(u64 clk_rate); + +void mdp3_calc_dma_res(struct mdss_panel_info *panel_info, u64 *clk_rate, + u64 *ab, u64 *ib, uint32_t bpp); +void mdp3_clear_irq(u32 interrupt_mask); +int mdp3_enable_panic_ctrl(void); + +int mdp3_layer_pre_commit(struct msm_fb_data_type *mfd, + struct file *file, struct mdp_layer_commit_v1 *commit); +int mdp3_layer_atomic_validate(struct msm_fb_data_type *mfd, + struct file *file, struct mdp_layer_commit_v1 *commit); + +#define MDP3_REG_WRITE(addr, val) writel_relaxed(val, mdp3_res->mdp_base + addr) +#define MDP3_REG_READ(addr) readl_relaxed(mdp3_res->mdp_base + addr) +#define VBIF_REG_WRITE(off, val) writel_relaxed(val, mdp3_res->vbif_base + off) +#define VBIF_REG_READ(off) readl_relaxed(mdp3_res->vbif_base + off) + +#endif /* MDP3_H */ diff --git a/drivers/video/fbdev/msm/mdp3_ctrl.c b/drivers/video/fbdev/msm/mdp3_ctrl.c new file mode 100644 index 000000000000..19c9a2bd4adb --- /dev/null +++ b/drivers/video/fbdev/msm/mdp3_ctrl.c @@ -0,0 +1,3024 @@ +/* Copyright (c) 2013-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#define pr_fmt(fmt) "%s: " fmt, __func__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mdp3_ctrl.h" +#include "mdp3.h" +#include "mdp3_ppp.h" +#include "mdss_smmu.h" +#include "mdss_sync.h" + +#define VSYNC_EXPIRE_TICK 4 + +static void mdp3_ctrl_pan_display(struct msm_fb_data_type *mfd); +static int mdp3_overlay_unset(struct msm_fb_data_type *mfd, int ndx); +static int mdp3_histogram_stop(struct mdp3_session_data *session, + u32 block); +static int mdp3_ctrl_clk_enable(struct msm_fb_data_type *mfd, int enable); +static int mdp3_ctrl_vsync_enable(struct msm_fb_data_type *mfd, int enable); +static int mdp3_ctrl_get_intf_type(struct msm_fb_data_type *mfd); +static int mdp3_ctrl_lut_read(struct msm_fb_data_type *mfd, + struct mdp_rgb_lut_data *cfg); +static int mdp3_ctrl_lut_config(struct msm_fb_data_type *mfd, + struct mdp_rgb_lut_data *cfg); +static void mdp3_ctrl_pp_resume(struct msm_fb_data_type *mfd); + +u32 mdp_lut_inverse16[MDP_LUT_SIZE] = { +0, 65536, 32768, 21845, 16384, 13107, 10923, 9362, 8192, 7282, 6554, 5958, +5461, 5041, 4681, 4369, 4096, 3855, 3641, 3449, 3277, 3121, 2979, 2849, 2731, +2621, 2521, 2427, 2341, 2260, 2185, 2114, 2048, 1986, 1928, 1872, 1820, 1771, +1725, 1680, 1638, 1598, 1560, 1524, 1489, 1456, 1425, 1394, 1365, 1337, 1311, +1285, 1260, 1237, 1214, 1192, 1170, 1150, 1130, 1111, 1092, 1074, 1057, 1040, +1024, 1008, 993, 978, 964, 950, 936, 923, 910, 898, 886, 874, 862, 851, 840, +830, 819, 809, 799, 790, 780, 771, 762, 753, 745, 736, 728, 720, 712, 705, 697, +690, 683, 676, 669, 662, 655, 649, 643, 636, 630, 624, 618, 612, 607, 601, 596, +590, 585, 580, 575, 570, 565, 560, 555, 551, 546, 542, 537, 533, 529, 524, 520, +516, 512, 508, 504, 500, 496, 493, 489, 485, 482, 478, 475, 471, 468, 465, 462, +458, 455, 452, 449, 446, 443, 440, 437, 434, 431, 428, 426, 423, 420, 417, 415, +412, 410, 407, 405, 402, 400, 397, 395, 392, 390, 388, 386, 383, 381, 379, 377, +374, 372, 370, 368, 366, 364, 362, 360, 358, 356, 354, 352, 350, 349, 347, 345, +343, 341, 340, 338, 336, 334, 333, 331, 329, 328, 326, 324, 323, 321, 320, 318, +317, 315, 314, 312, 311, 309, 308, 306, 305, 303, 302, 301, 299, 298, 297, 295, +294, 293, 291, 290, 289, 287, 286, 285, 284, 282, 281, 280, 279, 278, 277, 275, +274, 273, 272, 271, 270, 269, 267, 266, 265, 264, 263, 262, 261, 260, 259, 258, +257}; + +static void mdp3_bufq_init(struct mdp3_buffer_queue *bufq) +{ + bufq->count = 0; + bufq->push_idx = 0; + bufq->pop_idx = 0; +} + +void mdp3_bufq_deinit(struct mdp3_buffer_queue *bufq) +{ + int count = bufq->count; + + if (!count) + return; + + while (count-- && (bufq->pop_idx >= 0)) { + struct mdp3_img_data *data = &bufq->img_data[bufq->pop_idx]; + + bufq->pop_idx = (bufq->pop_idx + 1) % MDP3_MAX_BUF_QUEUE; + mdp3_put_img(data, MDP3_CLIENT_DMA_P); + } + bufq->count = 0; + bufq->push_idx = 0; + bufq->pop_idx = 0; +} + +int mdp3_bufq_push(struct mdp3_buffer_queue *bufq, + struct mdp3_img_data *data) +{ + if (bufq->count >= MDP3_MAX_BUF_QUEUE) { + pr_err("bufq full\n"); + return -EPERM; + } + + bufq->img_data[bufq->push_idx] = *data; + bufq->push_idx = (bufq->push_idx + 1) % MDP3_MAX_BUF_QUEUE; + bufq->count++; + return 0; +} + +static struct mdp3_img_data *mdp3_bufq_pop(struct mdp3_buffer_queue *bufq) +{ + struct mdp3_img_data *data; + + if (bufq->count == 0) + return NULL; + + data = &bufq->img_data[bufq->pop_idx]; + bufq->count--; + bufq->pop_idx = (bufq->pop_idx + 1) % MDP3_MAX_BUF_QUEUE; + return data; +} + +static int mdp3_bufq_count(struct mdp3_buffer_queue *bufq) +{ + return bufq->count; +} + +void mdp3_ctrl_notifier_register(struct mdp3_session_data *ses, + struct notifier_block *notifier) +{ + blocking_notifier_chain_register(&ses->notifier_head, notifier); +} + +void mdp3_ctrl_notifier_unregister(struct mdp3_session_data *ses, + struct notifier_block *notifier) +{ + blocking_notifier_chain_unregister(&ses->notifier_head, notifier); +} + +int mdp3_ctrl_notify(struct mdp3_session_data *ses, int event) +{ + return blocking_notifier_call_chain(&ses->notifier_head, event, ses); +} + +static void mdp3_dispatch_dma_done(struct kthread_work *work) +{ + struct mdp3_session_data *session; + int cnt = 0; + + pr_debug("%s\n", __func__); + session = container_of(work, struct mdp3_session_data, + dma_done_work); + if (!session) + return; + + cnt = atomic_read(&session->dma_done_cnt); + MDSS_XLOG(cnt); + while (cnt > 0) { + mdp3_ctrl_notify(session, MDP_NOTIFY_FRAME_DONE); + atomic_dec(&session->dma_done_cnt); + cnt--; + } +} + +static void mdp3_dispatch_clk_off(struct work_struct *work) +{ + struct mdp3_session_data *session; + int rc; + bool dmap_busy; + int retry_count = 2; + + pr_debug("%s\n", __func__); + MDSS_XLOG(XLOG_FUNC_ENTRY, __LINE__); + session = container_of(work, struct mdp3_session_data, + clk_off_work); + if (!session) + return; + + mutex_lock(&session->lock); + if (session->vsync_enabled || + atomic_read(&session->vsync_countdown) > 0) { + mutex_unlock(&session->lock); + pr_debug("%s: Ignoring clk shut down\n", __func__); + MDSS_XLOG(XLOG_FUNC_EXIT, __LINE__); + return; + } + + if (session->intf->active) { +retry_dma_done: + rc = wait_for_completion_timeout(&session->dma_completion, + WAIT_DMA_TIMEOUT); + if (rc <= 0) { + struct mdss_panel_data *panel; + + panel = session->panel; + pr_debug("cmd kickoff timed out (%d)\n", rc); + dmap_busy = session->dma->busy(); + if (dmap_busy) { + if (--retry_count) { + pr_err("dmap is busy, retry %d\n", + retry_count); + goto retry_dma_done; + } + pr_err("dmap is still busy, bug_on\n"); + WARN_ON(1); + } else { + pr_debug("dmap is not busy, continue\n"); + } + } + } + mdp3_ctrl_vsync_enable(session->mfd, 0); + mdp3_ctrl_clk_enable(session->mfd, 0); + MDSS_XLOG(XLOG_FUNC_EXIT, __LINE__); + mutex_unlock(&session->lock); +} + +static void mdp3_vsync_retire_handle_vsync(void *arg) +{ + struct mdp3_session_data *mdp3_session; + + mdp3_session = (struct mdp3_session_data *)arg; + + if (!mdp3_session) { + pr_warn("Invalid handle for vsync\n"); + return; + } + + schedule_work(&mdp3_session->retire_work); +} + +static void mdp3_vsync_retire_signal(struct msm_fb_data_type *mfd, int val) +{ + struct mdp3_session_data *mdp3_session; + + mdp3_session = (struct mdp3_session_data *)mfd->mdp.private1; + + mutex_lock(&mfd->mdp_sync_pt_data.sync_mutex); + if (mdp3_session->retire_cnt > 0) { + mdss_inc_timeline(mfd->mdp_sync_pt_data.timeline_retire, val); + mdp3_session->retire_cnt -= min(val, mdp3_session->retire_cnt); + } + mutex_unlock(&mfd->mdp_sync_pt_data.sync_mutex); +} + +static void mdp3_vsync_retire_work_handler(struct work_struct *work) +{ + struct mdp3_session_data *mdp3_session = + container_of(work, struct mdp3_session_data, retire_work); + + if (!mdp3_session) + return; + + mdp3_vsync_retire_signal(mdp3_session->mfd, 1); +} + +void mdp3_hist_intr_notify(struct mdp3_dma *dma) +{ + dma->hist_events++; + sysfs_notify_dirent(dma->hist_event_sd); + pr_debug("%s:: hist_events = %u\n", __func__, dma->hist_events); +} + +void vsync_notify_handler(void *arg) +{ + struct mdp3_session_data *session = (struct mdp3_session_data *)arg; + + session->vsync_time = ktime_get(); + MDSS_XLOG(ktime_to_ms(session->vsync_time)); + sysfs_notify_dirent(session->vsync_event_sd); +} + +void dma_done_notify_handler(void *arg) +{ + struct mdp3_session_data *session = (struct mdp3_session_data *)arg; + + atomic_inc(&session->dma_done_cnt); + kthread_queue_work(&session->worker, &session->dma_done_work); + complete_all(&session->dma_completion); +} + +void vsync_count_down(void *arg) +{ + struct mdp3_session_data *session = (struct mdp3_session_data *)arg; + + /* We are counting down to turn off clocks */ + if (atomic_read(&session->vsync_countdown) > 0) + atomic_dec(&session->vsync_countdown); + if (atomic_read(&session->vsync_countdown) == 0) + schedule_work(&session->clk_off_work); +} + +void mdp3_ctrl_reset_countdown(struct mdp3_session_data *session, + struct msm_fb_data_type *mfd) +{ + if (mdp3_ctrl_get_intf_type(mfd) == MDP3_DMA_OUTPUT_SEL_DSI_CMD) + atomic_set(&session->vsync_countdown, VSYNC_EXPIRE_TICK); +} + +static int mdp3_ctrl_vsync_enable(struct msm_fb_data_type *mfd, int enable) +{ + struct mdp3_session_data *mdp3_session; + struct mdp3_notification vsync_client; + struct mdp3_notification *arg = NULL; + bool mod_vsync_timer = false; + + pr_debug("%s =%d\n", __func__, enable); + mdp3_session = (struct mdp3_session_data *)mfd->mdp.private1; + if (!mdp3_session || !mdp3_session->panel || !mdp3_session->dma || + !mdp3_session->intf) + return -ENODEV; + + if (!mdp3_session->status) { + pr_debug("fb%d is not on yet", mfd->index); + return -EINVAL; + } + if (enable) { + vsync_client.handler = vsync_notify_handler; + vsync_client.arg = mdp3_session; + arg = &vsync_client; + } else if (atomic_read(&mdp3_session->vsync_countdown) > 0) { + /* + * Now that vsync is no longer needed we will + * shutdown dsi clocks as soon as cnt down == 0 + * for cmd mode panels + */ + vsync_client.handler = vsync_count_down; + vsync_client.arg = mdp3_session; + arg = &vsync_client; + enable = 1; + } + + if (enable) { + if (mdp3_session->status == 1 && + (mdp3_session->vsync_before_commit || + !mdp3_session->intf->active)) { + mod_vsync_timer = true; + } else if (!mdp3_session->clk_on) { + /* Enable clocks before enabling the vsync interrupt */ + mdp3_ctrl_reset_countdown(mdp3_session, mfd); + mdp3_ctrl_clk_enable(mfd, 1); + } + } + + mdp3_clk_enable(1, 0); + mdp3_session->dma->vsync_enable(mdp3_session->dma, arg); + mdp3_clk_enable(0, 0); + + /* + * Need to fake vsync whenever dsi interface is not + * active or when dsi clocks are currently off + */ + if (mod_vsync_timer) { + mod_timer(&mdp3_session->vsync_timer, + jiffies + msecs_to_jiffies(mdp3_session->vsync_period)); + } else if (!enable) { + del_timer(&mdp3_session->vsync_timer); + } + + return 0; +} + +void mdp3_vsync_timer_func(unsigned long arg) +{ + struct mdp3_session_data *session = (struct mdp3_session_data *)arg; + + if (session->status == 1 && (session->vsync_before_commit || + !session->intf->active)) { + pr_debug("%s trigger\n", __func__); + vsync_notify_handler(session); + mod_timer(&session->vsync_timer, + jiffies + msecs_to_jiffies(session->vsync_period)); + } +} + +static int mdp3_ctrl_async_blit_req(struct msm_fb_data_type *mfd, + void __user *p) +{ + struct mdp_async_blit_req_list req_list_header; + int rc, count; + void __user *p_req; + + if (copy_from_user(&req_list_header, p, sizeof(req_list_header))) + return -EFAULT; + p_req = p + sizeof(req_list_header); + count = req_list_header.count; + if (count < 0 || count >= MAX_BLIT_REQ) + return -EINVAL; + rc = mdp3_ppp_parse_req(p_req, &req_list_header, 1); + if (!rc) + rc = copy_to_user(p, &req_list_header, sizeof(req_list_header)); + return rc; +} + +static int mdp3_ctrl_blit_req(struct msm_fb_data_type *mfd, void __user *p) +{ + struct mdp_async_blit_req_list req_list_header; + int rc, count; + void __user *p_req; + + if (copy_from_user(&(req_list_header.count), p, + sizeof(struct mdp_blit_req_list))) + return -EFAULT; + p_req = p + sizeof(struct mdp_blit_req_list); + count = req_list_header.count; + if (count < 0 || count >= MAX_BLIT_REQ) + return -EINVAL; + req_list_header.sync.acq_fen_fd_cnt = 0; + rc = mdp3_ppp_parse_req(p_req, &req_list_header, 0); + return rc; +} + +static ssize_t mdp3_bl_show_event(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct fb_info *fbi = dev_get_drvdata(dev); + struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)fbi->par; + struct mdp3_session_data *mdp3_session = NULL; + int ret; + + if (!mfd || !mfd->mdp.private1) + return -EAGAIN; + + mdp3_session = (struct mdp3_session_data *)mfd->mdp.private1; + ret = scnprintf(buf, PAGE_SIZE, "%d\n", mdp3_session->bl_events); + return ret; +} + +static ssize_t mdp3_hist_show_event(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct fb_info *fbi = dev_get_drvdata(dev); + struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)fbi->par; + struct mdp3_session_data *mdp3_session = NULL; + struct mdp3_dma *dma = NULL; + int ret; + + if (!mfd || !mfd->mdp.private1) + return -EAGAIN; + + mdp3_session = (struct mdp3_session_data *)mfd->mdp.private1; + dma = (struct mdp3_dma *)mdp3_session->dma; + ret = scnprintf(buf, PAGE_SIZE, "%d\n", dma->hist_events); + return ret; +} + +static ssize_t mdp3_vsync_show_event(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct fb_info *fbi = dev_get_drvdata(dev); + struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)fbi->par; + struct mdp3_session_data *mdp3_session = NULL; + u64 vsync_ticks; + int rc; + + if (!mfd || !mfd->mdp.private1) + return -EAGAIN; + + mdp3_session = (struct mdp3_session_data *)mfd->mdp.private1; + + vsync_ticks = ktime_to_ns(mdp3_session->vsync_time); + + pr_debug("fb%d vsync=%llu\n", mfd->index, vsync_ticks); + rc = scnprintf(buf, PAGE_SIZE, "VSYNC=%llu\n", vsync_ticks); + return rc; +} + +static ssize_t mdp3_packpattern_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct fb_info *fbi = dev_get_drvdata(dev); + struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)fbi->par; + struct mdp3_session_data *mdp3_session = NULL; + int rc; + u32 pattern = 0; + + if (!mfd || !mfd->mdp.private1) + return -EAGAIN; + + mdp3_session = (struct mdp3_session_data *)mfd->mdp.private1; + + pattern = mdp3_session->dma->output_config.pack_pattern; + + /* If pattern was found to be 0 then get pattern for fb imagetype */ + if (!pattern) + pattern = mdp3_ctrl_get_pack_pattern(mfd->fb_imgType); + + pr_debug("fb%d pack_pattern c= %d.", mfd->index, pattern); + rc = scnprintf(buf, PAGE_SIZE, "packpattern=%d\n", pattern); + return rc; +} + +static ssize_t mdp3_dyn_pu_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct fb_info *fbi = dev_get_drvdata(dev); + struct msm_fb_data_type *mfd = fbi->par; + struct mdp3_session_data *mdp3_session = NULL; + int ret, state; + + if (!mfd || !mfd->mdp.private1) + return -EAGAIN; + + mdp3_session = (struct mdp3_session_data *)mfd->mdp.private1; + state = (mdp3_session->dyn_pu_state >= 0) ? + mdp3_session->dyn_pu_state : -1; + ret = scnprintf(buf, PAGE_SIZE, "%d", state); + return ret; +} + +static ssize_t mdp3_dyn_pu_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct fb_info *fbi = dev_get_drvdata(dev); + struct msm_fb_data_type *mfd = fbi->par; + struct mdp3_session_data *mdp3_session = NULL; + int ret, dyn_pu; + + if (!mfd || !mfd->mdp.private1) + return -EAGAIN; + + mdp3_session = (struct mdp3_session_data *)mfd->mdp.private1; + ret = kstrtoint(buf, 10, &dyn_pu); + if (ret) { + pr_err("Invalid input for partial update: ret = %d\n", ret); + return ret; + } + + mdp3_session->dyn_pu_state = dyn_pu; + sysfs_notify(&dev->kobj, NULL, "dyn_pu"); + return count; +} + +static DEVICE_ATTR(hist_event, 0444, mdp3_hist_show_event, NULL); +static DEVICE_ATTR(bl_event, 0444, mdp3_bl_show_event, NULL); +static DEVICE_ATTR(vsync_event, 0444, mdp3_vsync_show_event, NULL); +static DEVICE_ATTR(packpattern, 0444, mdp3_packpattern_show, NULL); +static DEVICE_ATTR(dyn_pu, 0664, mdp3_dyn_pu_show, + mdp3_dyn_pu_store); + +static struct attribute *generic_attrs[] = { + &dev_attr_packpattern.attr, + &dev_attr_dyn_pu.attr, + &dev_attr_hist_event.attr, + &dev_attr_bl_event.attr, + NULL, +}; + +static struct attribute *vsync_fs_attrs[] = { + &dev_attr_vsync_event.attr, + NULL, +}; + +static struct attribute_group vsync_fs_attr_group = { + .attrs = vsync_fs_attrs, +}; + +static struct attribute_group generic_attr_group = { + .attrs = generic_attrs, +}; + +static int mdp3_ctrl_clk_enable(struct msm_fb_data_type *mfd, int enable) +{ + struct mdp3_session_data *session; + struct mdss_panel_data *panel; + struct dsi_panel_clk_ctrl clk_ctrl; + int rc = 0; + + pr_debug("%s %d\n", __func__, enable); + + session = mfd->mdp.private1; + panel = session->panel; + + if (!panel->event_handler) + return 0; + + if ((enable && session->clk_on == 0) || + (!enable && session->clk_on == 1)) { + clk_ctrl.client = DSI_CLK_REQ_MDP_CLIENT; + clk_ctrl.state = enable; + rc = panel->event_handler(panel, + MDSS_EVENT_PANEL_CLK_CTRL, (void *)&clk_ctrl); + rc |= mdp3_res_update(enable, 1, MDP3_CLIENT_DMA_P); + } else { + pr_debug("enable = %d, clk_on=%d\n", enable, session->clk_on); + } + + session->clk_on = enable; + return rc; +} + +static int mdp3_ctrl_res_req_bus(struct msm_fb_data_type *mfd, int status) +{ + int rc = 0; + + if (status) { + u64 ab = 0; + u64 ib = 0; + + mdp3_calc_dma_res(mfd->panel_info, NULL, &ab, &ib, + ppp_bpp(mfd->fb_imgType)); + rc = mdp3_bus_scale_set_quota(MDP3_CLIENT_DMA_P, ab, ib); + } else { + rc = mdp3_bus_scale_set_quota(MDP3_CLIENT_DMA_P, 0, 0); + } + return rc; +} + +static int mdp3_ctrl_res_req_clk(struct msm_fb_data_type *mfd, int status) +{ + int rc = 0; + + if (status) { + u64 mdp_clk_rate = 0; + + mdp3_calc_dma_res(mfd->panel_info, &mdp_clk_rate, + NULL, NULL, 0); + + mdp3_clk_set_rate(MDP3_CLK_MDP_SRC, mdp_clk_rate, + MDP3_CLIENT_DMA_P); + mdp3_clk_set_rate(MDP3_CLK_VSYNC, MDP_VSYNC_CLK_RATE, + MDP3_CLIENT_DMA_P); + + rc = mdp3_res_update(1, 1, MDP3_CLIENT_DMA_P); + if (rc) { + pr_err("mdp3 clk enable fail\n"); + return rc; + } + } else { + rc = mdp3_res_update(0, 1, MDP3_CLIENT_DMA_P); + if (rc) + pr_err("mdp3 clk disable fail\n"); + } + return rc; +} + +static int mdp3_ctrl_get_intf_type(struct msm_fb_data_type *mfd) +{ + int type; + + switch (mfd->panel.type) { + case MIPI_VIDEO_PANEL: + type = MDP3_DMA_OUTPUT_SEL_DSI_VIDEO; + break; + case MIPI_CMD_PANEL: + type = MDP3_DMA_OUTPUT_SEL_DSI_CMD; + break; + case LCDC_PANEL: + type = MDP3_DMA_OUTPUT_SEL_LCDC; + break; + default: + type = MDP3_DMA_OUTPUT_SEL_MAX; + } + return type; +} + +int mdp3_ctrl_get_source_format(u32 imgType) +{ + int format; + + switch (imgType) { + case MDP_RGB_565: + format = MDP3_DMA_IBUF_FORMAT_RGB565; + break; + case MDP_RGB_888: + format = MDP3_DMA_IBUF_FORMAT_RGB888; + break; + case MDP_ARGB_8888: + case MDP_RGBA_8888: + format = MDP3_DMA_IBUF_FORMAT_XRGB8888; + break; + default: + format = MDP3_DMA_IBUF_FORMAT_UNDEFINED; + } + return format; +} + +int mdp3_ctrl_get_pack_pattern(u32 imgType) +{ + int packPattern = MDP3_DMA_OUTPUT_PACK_PATTERN_RGB; + + if (imgType == MDP_RGBA_8888 || imgType == MDP_RGB_888) + packPattern = MDP3_DMA_OUTPUT_PACK_PATTERN_BGR; + return packPattern; +} + +static int mdp3_ctrl_intf_init(struct msm_fb_data_type *mfd, + struct mdp3_intf *intf) +{ + int rc = 0; + struct mdp3_intf_cfg cfg; + struct mdp3_video_intf_cfg *video = &cfg.video; + struct mdss_panel_info *p = mfd->panel_info; + int h_back_porch = p->lcdc.h_back_porch; + int h_front_porch = p->lcdc.h_front_porch; + int w = p->xres; + int v_back_porch = p->lcdc.v_back_porch; + int v_front_porch = p->lcdc.v_front_porch; + int h = p->yres; + int h_sync_skew = p->lcdc.hsync_skew; + int h_pulse_width = p->lcdc.h_pulse_width; + int v_pulse_width = p->lcdc.v_pulse_width; + int hsync_period = h_front_porch + h_back_porch + w + h_pulse_width; + int vsync_period = v_front_porch + v_back_porch + h + v_pulse_width; + struct mdp3_session_data *mdp3_session; + + mdp3_session = (struct mdp3_session_data *)mfd->mdp.private1; + vsync_period *= hsync_period; + + cfg.type = mdp3_ctrl_get_intf_type(mfd); + if (cfg.type == MDP3_DMA_OUTPUT_SEL_DSI_VIDEO || + cfg.type == MDP3_DMA_OUTPUT_SEL_LCDC) { + video->hsync_period = hsync_period; + video->hsync_pulse_width = h_pulse_width; + video->vsync_period = vsync_period; + video->vsync_pulse_width = v_pulse_width * hsync_period; + video->display_start_x = h_back_porch + h_pulse_width; + video->display_end_x = hsync_period - h_front_porch - 1; + video->display_start_y = + (v_back_porch + v_pulse_width) * hsync_period; + video->display_end_y = + vsync_period - v_front_porch * hsync_period - 1; + video->active_start_x = video->display_start_x; + video->active_end_x = video->display_end_x; + video->active_h_enable = true; + video->active_start_y = video->display_start_y; + video->active_end_y = video->display_end_y; + video->active_v_enable = true; + video->hsync_skew = h_sync_skew; + video->hsync_polarity = 1; + video->vsync_polarity = 1; + video->de_polarity = 1; + video->underflow_color = p->lcdc.underflow_clr; + } else if (cfg.type == MDP3_DMA_OUTPUT_SEL_DSI_CMD) { + cfg.dsi_cmd.primary_dsi_cmd_id = 0; + cfg.dsi_cmd.secondary_dsi_cmd_id = 1; + cfg.dsi_cmd.dsi_cmd_tg_intf_sel = 0; + } else + return -EINVAL; + + if (!(mdp3_session->in_splash_screen)) { + if (intf->config) + rc = intf->config(intf, &cfg); + else + rc = -EINVAL; + } + return rc; +} + +static int mdp3_ctrl_dma_init(struct msm_fb_data_type *mfd, + struct mdp3_dma *dma) +{ + int rc; + struct mdss_panel_info *panel_info = mfd->panel_info; + struct fb_info *fbi = mfd->fbi; + struct fb_fix_screeninfo *fix; + struct fb_var_screeninfo *var; + struct mdp3_dma_output_config outputConfig; + struct mdp3_dma_source sourceConfig; + int frame_rate = mfd->panel_info->mipi.frame_rate; + int vbp, vfp, vspw; + int vtotal, vporch; + struct mdp3_notification dma_done_callback; + struct mdp3_tear_check te; + struct mdp3_session_data *mdp3_session; + + mdp3_session = (struct mdp3_session_data *)mfd->mdp.private1; + + vbp = panel_info->lcdc.v_back_porch; + vfp = panel_info->lcdc.v_front_porch; + vspw = panel_info->lcdc.v_pulse_width; + vporch = vbp + vfp + vspw; + vtotal = vporch + panel_info->yres; + + fix = &fbi->fix; + var = &fbi->var; + + sourceConfig.width = panel_info->xres; + sourceConfig.height = panel_info->yres; + sourceConfig.x = 0; + sourceConfig.y = 0; + sourceConfig.buf = mfd->iova; + sourceConfig.vporch = vporch; + sourceConfig.vsync_count = + MDP_VSYNC_CLK_RATE / (frame_rate * vtotal); + + outputConfig.dither_en = 0; + outputConfig.out_sel = mdp3_ctrl_get_intf_type(mfd); + outputConfig.bit_mask_polarity = 0; + outputConfig.color_components_flip = 0; + outputConfig.pack_align = MDP3_DMA_OUTPUT_PACK_ALIGN_LSB; + outputConfig.color_comp_out_bits = (MDP3_DMA_OUTPUT_COMP_BITS_8 << 4) | + (MDP3_DMA_OUTPUT_COMP_BITS_8 << 2)| + MDP3_DMA_OUTPUT_COMP_BITS_8; + + if (dma->update_src_cfg) { + /* configuration has been updated through PREPARE call */ + sourceConfig.format = dma->source_config.format; + sourceConfig.stride = dma->source_config.stride; + outputConfig.pack_pattern = dma->output_config.pack_pattern; + } else { + sourceConfig.format = + mdp3_ctrl_get_source_format(mfd->fb_imgType); + outputConfig.pack_pattern = + mdp3_ctrl_get_pack_pattern(mfd->fb_imgType); + sourceConfig.stride = fix->line_length; + } + + te.frame_rate = panel_info->mipi.frame_rate; + te.hw_vsync_mode = panel_info->mipi.hw_vsync_mode; + te.tear_check_en = panel_info->te.tear_check_en; + te.sync_cfg_height = panel_info->te.sync_cfg_height; + te.vsync_init_val = panel_info->te.vsync_init_val; + te.sync_threshold_start = panel_info->te.sync_threshold_start; + te.sync_threshold_continue = panel_info->te.sync_threshold_continue; + te.start_pos = panel_info->te.start_pos; + te.rd_ptr_irq = panel_info->te.rd_ptr_irq; + te.refx100 = panel_info->te.refx100; + + if (dma->dma_config) { + if (!panel_info->partial_update_enabled) { + dma->roi.w = sourceConfig.width; + dma->roi.h = sourceConfig.height; + dma->roi.x = sourceConfig.x; + dma->roi.y = sourceConfig.y; + } + rc = dma->dma_config(dma, &sourceConfig, &outputConfig, + mdp3_session->in_splash_screen); + } else { + pr_err("%s: dma config failed\n", __func__); + rc = -EINVAL; + } + + if (outputConfig.out_sel == MDP3_DMA_OUTPUT_SEL_DSI_CMD) { + if (dma->dma_sync_config) + rc = dma->dma_sync_config(dma, + &sourceConfig, &te); + else + rc = -EINVAL; + dma_done_callback.handler = dma_done_notify_handler; + dma_done_callback.arg = mfd->mdp.private1; + dma->dma_done_notifier(dma, &dma_done_callback); + } + + return rc; +} + +static int mdp3_ctrl_on(struct msm_fb_data_type *mfd) +{ + int rc = 0; + struct mdp3_session_data *mdp3_session; + struct mdss_panel_data *panel; + + pr_debug("%s\n", __func__); + mdp3_session = (struct mdp3_session_data *)mfd->mdp.private1; + if (!mdp3_session || !mdp3_session->panel || !mdp3_session->dma || + !mdp3_session->intf) { + pr_err("%s no device\n", __func__); + return -ENODEV; + } + mutex_lock(&mdp3_session->lock); + + MDSS_XLOG(XLOG_FUNC_ENTRY, __LINE__, mfd->panel_power_state); + panel = mdp3_session->panel; + /* make sure DSI host is initialized properly */ + if (panel) { + pr_debug("%s : dsi host init, power state = %d Splash %d\n", + __func__, mfd->panel_power_state, + mdp3_session->in_splash_screen); + if (mdss_fb_is_power_on_lp(mfd) || + mdp3_session->in_splash_screen) { + /* Turn on panel so that it can exit low power mode */ + mdp3_clk_enable(1, 0); + rc = panel->event_handler(panel, + MDSS_EVENT_LINK_READY, NULL); + rc |= panel->event_handler(panel, + MDSS_EVENT_UNBLANK, NULL); + rc |= panel->event_handler(panel, + MDSS_EVENT_PANEL_ON, NULL); + if (mdss_fb_is_power_on_ulp(mfd)) + rc |= mdp3_enable_panic_ctrl(); + mdp3_clk_enable(0, 0); + } + } + + if (mdp3_session->status) { + pr_debug("fb%d is on already\n", mfd->index); + MDSS_XLOG(XLOG_FUNC_EXIT, __LINE__, mfd->panel_power_state); + goto end; + } + + if (mdp3_session->intf->active) { + pr_debug("continuous splash screen, initialized already\n"); + mdp3_session->status = 1; + goto end; + } + + /* + * Get a reference to the runtime pm device. + * If idle pc feature is enabled, it will be released + * at end of this routine else, when device is turned off. + */ + pm_runtime_get_sync(&mdp3_res->pdev->dev); + + /* Increment the overlay active count */ + atomic_inc(&mdp3_res->active_intf_cnt); + mdp3_ctrl_notifier_register(mdp3_session, + &mdp3_session->mfd->mdp_sync_pt_data.notifier); + + /* request bus bandwidth before DSI DMA traffic */ + rc = mdp3_ctrl_res_req_bus(mfd, 1); + if (rc) { + pr_err("fail to request bus resource\n"); + goto on_error; + } + + rc = mdp3_dynamic_clock_gating_ctrl(0); + if (rc) { + pr_err("fail to disable dynamic clock gating\n"); + goto on_error; + } + mdp3_qos_remapper_setup(panel); + + rc = mdp3_ctrl_res_req_clk(mfd, 1); + if (rc) { + pr_err("fail to request mdp clk resource\n"); + goto on_error; + } + + if (panel->event_handler) { + rc = panel->event_handler(panel, MDSS_EVENT_LINK_READY, NULL); + rc |= panel->event_handler(panel, MDSS_EVENT_UNBLANK, NULL); + rc |= panel->event_handler(panel, MDSS_EVENT_PANEL_ON, NULL); + if (panel->panel_info.type == MIPI_CMD_PANEL) { + struct dsi_panel_clk_ctrl clk_ctrl; + + clk_ctrl.state = MDSS_DSI_CLK_ON; + clk_ctrl.client = DSI_CLK_REQ_MDP_CLIENT; + rc |= panel->event_handler(panel, + MDSS_EVENT_PANEL_CLK_CTRL, + (void *)&clk_ctrl); + } + } + if (rc) { + pr_err("fail to turn on the panel\n"); + goto on_error; + } + + rc = mdp3_ctrl_dma_init(mfd, mdp3_session->dma); + if (rc) { + pr_err("dma init failed\n"); + goto on_error; + } + + rc = mdp3_ppp_init(); + if (rc) { + pr_err("ppp init failed\n"); + goto on_error; + } + + rc = mdp3_ctrl_intf_init(mfd, mdp3_session->intf); + if (rc) { + pr_err("display interface init failed\n"); + goto on_error; + } + mdp3_session->clk_on = 1; + + mdp3_session->first_commit = true; + if (mfd->panel_info->panel_dead) + mdp3_session->esd_recovery = true; + + mdp3_session->status = 1; + + mdp3_ctrl_pp_resume(mfd); + MDSS_XLOG(XLOG_FUNC_EXIT, __LINE__, mfd->panel_power_state); +on_error: + if (rc || (mdp3_res->idle_pc_enabled && + (mfd->panel_info->type == MIPI_CMD_PANEL))) { + if (rc) { + pr_err("Failed to turn on fb%d\n", mfd->index); + atomic_dec(&mdp3_res->active_intf_cnt); + } + pm_runtime_put(&mdp3_res->pdev->dev); + } +end: + mutex_unlock(&mdp3_session->lock); + return rc; +} + +static int mdp3_ctrl_off(struct msm_fb_data_type *mfd) +{ + int rc = 0; + bool intf_stopped = true; + struct mdp3_session_data *mdp3_session; + struct mdss_panel_data *panel; + + pr_debug("%s\n", __func__); + mdp3_session = (struct mdp3_session_data *)mfd->mdp.private1; + if (!mdp3_session || !mdp3_session->panel || !mdp3_session->dma || + !mdp3_session->intf) { + pr_err("mdp3_ctrl_on no device"); + return -ENODEV; + } + + /* + * Keep a reference to the runtime pm until the overlay is turned + * off, and then release this last reference at the end. This will + * help in distinguishing between idle power collapse versus suspend + * power collapse + */ + pm_runtime_get_sync(&mdp3_res->pdev->dev); + + MDSS_XLOG(XLOG_FUNC_ENTRY, __LINE__, mdss_fb_is_power_on_ulp(mfd), + mfd->panel_power_state); + panel = mdp3_session->panel; + mutex_lock(&mdp3_session->lock); + + pr_debug("Requested power state = %d\n", mfd->panel_power_state); + if (mdss_fb_is_power_on_lp(mfd)) { + /* + * Transition to low power + * As display updates are expected in low power mode, + * keep the interface and clocks on. + */ + intf_stopped = false; + } else { + /* Transition to display off */ + if (!mdp3_session->status) { + pr_debug("fb%d is off already", mfd->index); + goto off_error; + } + if (panel && panel->set_backlight) + panel->set_backlight(panel, 0); + } + + /* + * While transitioning from interactive to low power, + * events need to be sent to the interface so that the + * panel can be configured in low power mode + */ + if (panel->event_handler) + rc = panel->event_handler(panel, MDSS_EVENT_BLANK, + (void *) (long int)mfd->panel_power_state); + if (rc) + pr_err("EVENT_BLANK error (%d)\n", rc); + + if (intf_stopped) { + if (!mdp3_session->clk_on) + mdp3_ctrl_clk_enable(mfd, 1); + /* PP related programming for ctrl off */ + mdp3_histogram_stop(mdp3_session, MDP_BLOCK_DMA_P); + mutex_lock(&mdp3_session->dma->pp_lock); + mdp3_session->dma->ccs_config.ccs_dirty = false; + mdp3_session->dma->lut_config.lut_dirty = false; + mutex_unlock(&mdp3_session->dma->pp_lock); + + rc = mdp3_session->dma->stop(mdp3_session->dma, + mdp3_session->intf); + if (rc) + pr_debug("fail to stop the MDP3 dma\n"); + /* Wait to ensure TG to turn off */ + msleep(20); + mfd->panel_info->cont_splash_enabled = 0; + + /* Disable Auto refresh once continuous splash disabled */ + mdp3_autorefresh_disable(mfd->panel_info); + mdp3_splash_done(mfd->panel_info); + + mdp3_irq_deregister(); + } + + if (panel->event_handler) + rc = panel->event_handler(panel, MDSS_EVENT_PANEL_OFF, + (void *) (long int)mfd->panel_power_state); + if (rc) + pr_err("EVENT_PANEL_OFF error (%d)\n", rc); + + if (intf_stopped) { + if (mdp3_session->clk_on) { + pr_debug("%s stop clock\n", __func__); + if (panel->event_handler && + (panel->panel_info.type == MIPI_CMD_PANEL)) { + struct dsi_panel_clk_ctrl clk_ctrl; + + clk_ctrl.state = MDSS_DSI_CLK_OFF; + clk_ctrl.client = DSI_CLK_REQ_MDP_CLIENT; + rc |= panel->event_handler(panel, + MDSS_EVENT_PANEL_CLK_CTRL, + (void *)&clk_ctrl); + } + + rc = mdp3_dynamic_clock_gating_ctrl(1); + rc = mdp3_res_update(0, 1, MDP3_CLIENT_DMA_P); + if (rc) + pr_err("mdp clock resource release failed\n"); + } + + mdp3_ctrl_notifier_unregister(mdp3_session, + &mdp3_session->mfd->mdp_sync_pt_data.notifier); + + mdp3_session->vsync_enabled = 0; + atomic_set(&mdp3_session->vsync_countdown, 0); + atomic_set(&mdp3_session->dma_done_cnt, 0); + mdp3_session->clk_on = 0; + mdp3_session->in_splash_screen = 0; + mdp3_res->solid_fill_vote_en = false; + mdp3_session->status = 0; + if (atomic_dec_return(&mdp3_res->active_intf_cnt) != 0) { + pr_warn("active_intf_cnt unbalanced\n"); + atomic_set(&mdp3_res->active_intf_cnt, 0); + } + /* + * Release the pm runtime reference held when + * idle pc feature is not enabled + */ + if (!mdp3_res->idle_pc_enabled || + (mfd->panel_info->type != MIPI_CMD_PANEL)) { + rc = pm_runtime_put(&mdp3_res->pdev->dev); + if (rc) + pr_err("%s: pm_runtime_put failed (rc %d)\n", + __func__, rc); + } + mdp3_bufq_deinit(&mdp3_session->bufq_out); + if (mdp3_session->overlay.id != MSMFB_NEW_REQUEST) { + mdp3_session->overlay.id = MSMFB_NEW_REQUEST; + mdp3_bufq_deinit(&mdp3_session->bufq_in); + } + } + + if (mdss_fb_is_power_on_ulp(mfd) && + (mfd->panel.type == MIPI_CMD_PANEL)) { + pr_debug("%s: Disable MDP3 clocks in ULP\n", __func__); + if (!mdp3_session->clk_on) + mdp3_ctrl_clk_enable(mfd, 1); + /* + * STOP DMA transfer first and signal vsync notification + * Before releasing the resource in ULP state. + */ + rc = mdp3_session->dma->stop(mdp3_session->dma, + mdp3_session->intf); + if (rc) + pr_warn("fail to stop the MDP3 dma in ULP\n"); + /* Wait to ensure TG to turn off */ + msleep(20); + /* + * Handle ULP request initiated from fb_pm_suspend. + * For ULP panel power state disabling vsync and set + * vsync_count to zero and Turn off MDP3 clocks + */ + atomic_set(&mdp3_session->vsync_countdown, 0); + mdp3_session->vsync_enabled = 0; + mdp3_ctrl_vsync_enable(mdp3_session->mfd, 0); + mdp3_ctrl_clk_enable(mdp3_session->mfd, 0); + } +off_error: + MDSS_XLOG(XLOG_FUNC_EXIT, __LINE__); + mutex_unlock(&mdp3_session->lock); + /* Release the last reference to the runtime device */ + pm_runtime_put(&mdp3_res->pdev->dev); + + return 0; +} + +int mdp3_ctrl_reset(struct msm_fb_data_type *mfd) +{ + int rc = 0; + struct mdp3_session_data *mdp3_session; + struct mdp3_dma *mdp3_dma; + struct mdss_panel_data *panel; + struct mdp3_notification vsync_client; + + pr_debug("%s\n", __func__); + mdp3_session = (struct mdp3_session_data *)mfd->mdp.private1; + if (!mdp3_session || !mdp3_session->panel || !mdp3_session->dma || + !mdp3_session->intf) { + pr_err("%s no device\n", __func__); + return -ENODEV; + } + + panel = mdp3_session->panel; + mdp3_dma = mdp3_session->dma; + mutex_lock(&mdp3_session->lock); + pr_debug("%s idle_pc %s FS_EN %s\n", + __func__, + mdp3_res->idle_pc ? "True":"False", + mdp3_res->fs_ena ? "True":"False"); + if (mdp3_res->idle_pc) { + mdp3_clk_enable(1, 0); + mdp3_dynamic_clock_gating_ctrl(0); + mdp3_qos_remapper_setup(panel); + } + + /*Map the splash addr for VIDEO mode panel before smmu attach*/ + if ((mfd->panel.type == MIPI_VIDEO_PANEL) && + (mdp3_session->in_splash_screen)) { + rc = mdss_smmu_map(MDSS_IOMMU_DOMAIN_UNSECURE, + mdp3_res->splash_mem_addr, + mdp3_res->splash_mem_addr, + mdp3_res->splash_mem_size, + IOMMU_READ | IOMMU_NOEXEC); + } + + rc = mdp3_iommu_enable(MDP3_CLIENT_DMA_P); + if (rc) { + pr_err("fail to attach dma iommu\n"); + if (mdp3_res->idle_pc) + mdp3_clk_enable(0, 0); + goto reset_error; + } + + vsync_client = mdp3_dma->vsync_client; + + mdp3_ctrl_intf_init(mfd, mdp3_session->intf); + mdp3_ctrl_dma_init(mfd, mdp3_dma); + mdp3_ppp_init(); + mdp3_ctrl_pp_resume(mfd); + if (vsync_client.handler) + mdp3_dma->vsync_enable(mdp3_dma, &vsync_client); + + if (!mdp3_res->idle_pc) { + mdp3_session->first_commit = true; + mfd->panel_info->cont_splash_enabled = 0; + mdp3_session->in_splash_screen = 0; + mdp3_splash_done(mfd->panel_info); + /* Disable Auto refresh */ + mdp3_autorefresh_disable(mfd->panel_info); + } else { + mdp3_res->idle_pc = false; + mdp3_clk_enable(0, 0); + mdp3_iommu_disable(MDP3_CLIENT_DMA_P); + } + +reset_error: + mutex_unlock(&mdp3_session->lock); + return rc; +} + +static int mdp3_overlay_get(struct msm_fb_data_type *mfd, + struct mdp_overlay *req) +{ + int rc = 0; + struct mdp3_session_data *mdp3_session = mfd->mdp.private1; + + mutex_lock(&mdp3_session->lock); + + if (mdp3_session->overlay.id == req->id) + *req = mdp3_session->overlay; + else + rc = -EINVAL; + + mutex_unlock(&mdp3_session->lock); + + return rc; +} + +static int mdp3_overlay_set(struct msm_fb_data_type *mfd, + struct mdp_overlay *req) +{ + int rc = 0; + struct mdp3_session_data *mdp3_session = mfd->mdp.private1; + struct mdp3_dma *dma = mdp3_session->dma; + struct fb_fix_screeninfo *fix; + struct fb_info *fbi = mfd->fbi; + int stride; + int format; + + fix = &fbi->fix; + stride = req->src.width * ppp_bpp(req->src.format); + format = mdp3_ctrl_get_source_format(req->src.format); + + + if (mdp3_session->overlay.id != req->id) + pr_err("overlay was not released, continue to recover\n"); + /* + * A change in overlay structure will always come with + * MSMFB_NEW_REQUEST for MDP3 + */ + if (req->id == MSMFB_NEW_REQUEST) { + mutex_lock(&mdp3_session->lock); + if (dma->source_config.stride != stride || + dma->source_config.format != format) { + dma->source_config.format = format; + dma->source_config.stride = stride; + dma->output_config.pack_pattern = + mdp3_ctrl_get_pack_pattern(req->src.format); + dma->update_src_cfg = true; + } + mdp3_session->overlay = *req; + mdp3_session->overlay.id = 1; + req->id = 1; + mutex_unlock(&mdp3_session->lock); + } + + return rc; +} + +static int mdp3_overlay_unset(struct msm_fb_data_type *mfd, int ndx) +{ + int rc = 0; + struct mdp3_session_data *mdp3_session = mfd->mdp.private1; + struct fb_info *fbi = mfd->fbi; + struct fb_fix_screeninfo *fix; + int format; + + fix = &fbi->fix; + format = mdp3_ctrl_get_source_format(mfd->fb_imgType); + mutex_lock(&mdp3_session->lock); + + if (mdp3_session->overlay.id == ndx && ndx == 1) { + mdp3_session->overlay.id = MSMFB_NEW_REQUEST; + mdp3_bufq_deinit(&mdp3_session->bufq_in); + } else { + rc = -EINVAL; + } + + mutex_unlock(&mdp3_session->lock); + + return rc; +} + +static int mdp3_overlay_queue_buffer(struct msm_fb_data_type *mfd, + struct msmfb_overlay_data *req) +{ + int rc; + bool is_panel_type_cmd = false; + struct mdp3_session_data *mdp3_session = mfd->mdp.private1; + struct msmfb_data *img = &req->data; + struct mdp3_img_data data; + struct mdp3_dma *dma = mdp3_session->dma; + + memset(&data, 0, sizeof(struct mdp3_img_data)); + if (mfd->panel.type == MIPI_CMD_PANEL) + is_panel_type_cmd = true; + if (is_panel_type_cmd) { + rc = mdp3_iommu_enable(MDP3_CLIENT_DMA_P); + if (rc) { + pr_err("fail to enable iommu\n"); + return rc; + } + } + rc = mdp3_get_img(img, &data, MDP3_CLIENT_DMA_P); + if (rc) { + pr_err("fail to get overlay buffer\n"); + goto err; + } + + if (data.len < dma->source_config.stride * dma->source_config.height) { + pr_err("buf size(0x%lx) is smaller than dma config(0x%x)\n", + data.len, (dma->source_config.stride * + dma->source_config.height)); + mdp3_put_img(&data, MDP3_CLIENT_DMA_P); + rc = -EINVAL; + goto err; + } + rc = mdp3_bufq_push(&mdp3_session->bufq_in, &data); + if (rc) { + pr_err("fail to queue the overlay buffer, buffer drop\n"); + mdp3_put_img(&data, MDP3_CLIENT_DMA_P); + goto err; + } + rc = 0; +err: + if (is_panel_type_cmd) + mdp3_iommu_disable(MDP3_CLIENT_DMA_P); + return rc; +} + +static int mdp3_overlay_play(struct msm_fb_data_type *mfd, + struct msmfb_overlay_data *req) +{ + struct mdp3_session_data *mdp3_session = mfd->mdp.private1; + int rc = 0; + + pr_debug("%s req id=%x mem_id=%d\n", + __func__, req->id, req->data.memory_id); + + mutex_lock(&mdp3_session->lock); + + if (mdp3_session->overlay.id == MSMFB_NEW_REQUEST) { + pr_err("overlay play without overlay set first\n"); + mutex_unlock(&mdp3_session->lock); + return -EINVAL; + } + + if (mdss_fb_is_power_on(mfd)) + rc = mdp3_overlay_queue_buffer(mfd, req); + else + rc = -EPERM; + + mutex_unlock(&mdp3_session->lock); + + return rc; +} + +bool update_roi(struct mdp3_rect oldROI, struct mdp_rect newROI) +{ + return ((newROI.x != oldROI.x) || (newROI.y != oldROI.y) || + (newROI.w != oldROI.w) || (newROI.h != oldROI.h)); +} + +bool is_roi_valid(struct mdp3_dma_source source_config, struct mdp_rect roi) +{ + return (roi.w > 0) && (roi.h > 0) && + (roi.x >= source_config.x) && + ((roi.x + roi.w) <= source_config.width) && + (roi.y >= source_config.y) && + ((roi.y + roi.h) <= source_config.height); +} + +static int mdp3_ctrl_display_commit_kickoff(struct msm_fb_data_type *mfd, + struct mdp_display_commit *cmt_data) +{ + struct mdp3_session_data *mdp3_session; + struct mdp3_img_data *data; + struct mdss_panel_info *panel_info; + int rc = 0; + static bool splash_done; + struct mdss_panel_data *panel; + + if (!mfd || !mfd->mdp.private1) + return -EINVAL; + + panel_info = mfd->panel_info; + mdp3_session = mfd->mdp.private1; + if (!mdp3_session || !mdp3_session->dma) + return -EINVAL; + + if (mdp3_bufq_count(&mdp3_session->bufq_in) == 0) { + pr_debug("no buffer in queue yet\n"); + return -EPERM; + } + + if (panel_info->partial_update_enabled && + is_roi_valid(mdp3_session->dma->source_config, + cmt_data->l_roi) && + update_roi(mdp3_session->dma->roi, cmt_data->l_roi)) { + mdp3_session->dma->roi.x = cmt_data->l_roi.x; + mdp3_session->dma->roi.y = cmt_data->l_roi.y; + mdp3_session->dma->roi.w = cmt_data->l_roi.w; + mdp3_session->dma->roi.h = cmt_data->l_roi.h; + mdp3_session->dma->update_src_cfg = true; + pr_debug("%s: ROI: x=%d y=%d w=%d h=%d\n", __func__, + mdp3_session->dma->roi.x, + mdp3_session->dma->roi.y, + mdp3_session->dma->roi.w, + mdp3_session->dma->roi.h); + } + + panel = mdp3_session->panel; + mutex_lock(&mdp3_res->fs_idle_pc_lock); + if (mdp3_session->in_splash_screen || + mdp3_res->idle_pc) { + pr_debug("%s: reset- in_splash = %d, idle_pc = %d", __func__, + mdp3_session->in_splash_screen, mdp3_res->idle_pc); + rc = mdp3_ctrl_reset(mfd); + if (rc) { + pr_err("fail to reset display\n"); + mutex_unlock(&mdp3_res->fs_idle_pc_lock); + return -EINVAL; + } + } + mutex_unlock(&mdp3_res->fs_idle_pc_lock); + + mutex_lock(&mdp3_session->lock); + + if (!mdp3_session->status) { + pr_err("%s, display off!\n", __func__); + mutex_unlock(&mdp3_session->lock); + return -EPERM; + } + + mdp3_ctrl_notify(mdp3_session, MDP_NOTIFY_FRAME_BEGIN); + data = mdp3_bufq_pop(&mdp3_session->bufq_in); + if (data) { + mdp3_ctrl_reset_countdown(mdp3_session, mfd); + mdp3_ctrl_clk_enable(mfd, 1); + if (mdp3_session->dma->update_src_cfg && + panel_info->partial_update_enabled) { + panel->panel_info.roi.x = mdp3_session->dma->roi.x; + panel->panel_info.roi.y = mdp3_session->dma->roi.y; + panel->panel_info.roi.w = mdp3_session->dma->roi.w; + panel->panel_info.roi.h = mdp3_session->dma->roi.h; + rc = mdp3_session->dma->update(mdp3_session->dma, + (void *)(int)data->addr, + mdp3_session->intf, (void *)panel); + } else { + rc = mdp3_session->dma->update(mdp3_session->dma, + (void *)(int)data->addr, + mdp3_session->intf, NULL); + } + /* This is for the previous frame */ + if (rc < 0) { + mdp3_ctrl_notify(mdp3_session, + MDP_NOTIFY_FRAME_TIMEOUT); + } else { + if (mdp3_ctrl_get_intf_type(mfd) == + MDP3_DMA_OUTPUT_SEL_DSI_VIDEO) { + mdp3_ctrl_notify(mdp3_session, + MDP_NOTIFY_FRAME_DONE); + } + } + mdp3_session->dma_active = 1; + init_completion(&mdp3_session->dma_completion); + mdp3_ctrl_notify(mdp3_session, MDP_NOTIFY_FRAME_FLUSHED); + mdp3_bufq_push(&mdp3_session->bufq_out, data); + } + + if (mdp3_bufq_count(&mdp3_session->bufq_out) > 1) { + mdp3_release_splash_memory(mfd); + data = mdp3_bufq_pop(&mdp3_session->bufq_out); + if (data) + mdp3_put_img(data, MDP3_CLIENT_DMA_P); + } + + if (mdp3_session->first_commit) { + /*wait to ensure frame is sent to panel*/ + if (panel_info->mipi.post_init_delay) + msleep(((1000 / panel_info->mipi.frame_rate) + 1) * + panel_info->mipi.post_init_delay); + else + msleep(1000 / panel_info->mipi.frame_rate); + mdp3_session->first_commit = false; + if (panel) + rc |= panel->event_handler(panel, + MDSS_EVENT_POST_PANEL_ON, NULL); + } + + mdp3_session->vsync_before_commit = 0; + if (!splash_done || mdp3_session->esd_recovery == true) { + if (panel && panel->set_backlight) + panel->set_backlight(panel, panel->panel_info.bl_max); + splash_done = true; + mdp3_session->esd_recovery = false; + } + + /* start vsync tick countdown for cmd mode if vsync isn't enabled */ + if (mfd->panel.type == MIPI_CMD_PANEL && !mdp3_session->vsync_enabled) + mdp3_ctrl_vsync_enable(mdp3_session->mfd, 0); + + mutex_unlock(&mdp3_session->lock); + + mdss_fb_update_notify_update(mfd); + + return 0; +} + +static int mdp3_map_pan_buff_immediate(struct msm_fb_data_type *mfd) +{ + int rc = 0; + unsigned long length; + dma_addr_t addr; + int domain = mfd->mdp.fb_mem_get_iommu_domain(); + + rc = mdss_smmu_map_dma_buf(mfd->fbmem_buf, mfd->fb_table, domain, + &addr, &length, DMA_BIDIRECTIONAL); + if (IS_ERR_VALUE(rc)) + goto err_unmap; + else + mfd->iova = addr; + + pr_debug("%s : smmu map dma buf VA: (%llx) MFD->iova %llx\n", + __func__, (u64) addr, (u64) mfd->iova); + return rc; + +err_unmap: + pr_err("smmu map dma buf failed: (%d)\n", rc); + dma_buf_unmap_attachment(mfd->fb_attachment, mfd->fb_table, + mdss_smmu_dma_data_direction(DMA_BIDIRECTIONAL)); + dma_buf_detach(mfd->fbmem_buf, mfd->fb_attachment); + dma_buf_put(mfd->fbmem_buf); + return rc; +} + +static void mdp3_ctrl_pan_display(struct msm_fb_data_type *mfd) +{ + struct fb_info *fbi; + struct mdp3_session_data *mdp3_session; + u32 offset; + int bpp; + struct mdss_panel_info *panel_info; + static bool splash_done; + struct mdss_panel_data *panel; + + int rc; + + pr_debug("%s\n", __func__); + if (!mfd || !mfd->mdp.private1) + return; + + panel_info = mfd->panel_info; + mdp3_session = (struct mdp3_session_data *)mfd->mdp.private1; + if (!mdp3_session || !mdp3_session->dma) + return; + + mutex_lock(&mdp3_res->fs_idle_pc_lock); + if (mdp3_session->in_splash_screen || + mdp3_res->idle_pc) { + pr_debug("%s: reset- in_splash = %d, idle_pc = %d", __func__, + mdp3_session->in_splash_screen, mdp3_res->idle_pc); + rc = mdp3_ctrl_reset(mfd); + if (rc) { + pr_err("fail to reset display\n"); + mutex_unlock(&mdp3_res->fs_idle_pc_lock); + return; + } + } + mutex_unlock(&mdp3_res->fs_idle_pc_lock); + + mutex_lock(&mdp3_session->lock); + + if (!mdp3_session->status) { + pr_err("%s, display off!\n", __func__); + goto pan_error; + } + + fbi = mfd->fbi; + + bpp = fbi->var.bits_per_pixel / 8; + offset = fbi->var.xoffset * bpp + + fbi->var.yoffset * fbi->fix.line_length; + + if (offset > fbi->fix.smem_len) { + pr_err("invalid fb offset=%u total length=%u\n", + offset, fbi->fix.smem_len); + goto pan_error; + } + + if (mfd->fbi->screen_base) { + mdp3_ctrl_reset_countdown(mdp3_session, mfd); + mdp3_ctrl_notify(mdp3_session, MDP_NOTIFY_FRAME_BEGIN); + mdp3_ctrl_clk_enable(mfd, 1); + if (mdp3_session->first_commit) { + rc = mdp3_map_pan_buff_immediate(mfd); + if (IS_ERR_VALUE(rc)) + goto pan_error; + } + rc = mdp3_session->dma->update(mdp3_session->dma, + (void *)(int)(mfd->iova + offset), + mdp3_session->intf, NULL); + /* This is for the previous frame */ + if (rc < 0) { + mdp3_ctrl_notify(mdp3_session, + MDP_NOTIFY_FRAME_TIMEOUT); + } else { + if (mdp3_ctrl_get_intf_type(mfd) == + MDP3_DMA_OUTPUT_SEL_DSI_VIDEO) { + mdp3_ctrl_notify(mdp3_session, + MDP_NOTIFY_FRAME_DONE); + } + } + mdp3_session->dma_active = 1; + init_completion(&mdp3_session->dma_completion); + mdp3_ctrl_notify(mdp3_session, MDP_NOTIFY_FRAME_FLUSHED); + } else { + pr_debug("%s no memory, stop interface", __func__); + mdp3_clk_enable(1, 0); + mdp3_session->dma->stop(mdp3_session->dma, mdp3_session->intf); + mdp3_clk_enable(0, 0); + } + + panel = mdp3_session->panel; + if (mdp3_session->first_commit) { + /*wait to ensure frame is sent to panel*/ + if (panel_info->mipi.post_init_delay) + msleep(((1000 / panel_info->mipi.frame_rate) + 1) * + panel_info->mipi.post_init_delay); + else + msleep(1000 / panel_info->mipi.frame_rate); + mdp3_session->first_commit = false; + if (panel) + panel->event_handler(panel, MDSS_EVENT_POST_PANEL_ON, + NULL); + } + + mdp3_session->vsync_before_commit = 0; + if (!splash_done || mdp3_session->esd_recovery == true) { + if (panel && panel->set_backlight) + panel->set_backlight(panel, panel->panel_info.bl_max); + splash_done = true; + mdp3_session->esd_recovery = false; + } + + +pan_error: + mutex_unlock(&mdp3_session->lock); +} + +static int mdp3_set_metadata(struct msm_fb_data_type *mfd, + struct msmfb_metadata *metadata_ptr) +{ + int ret = 0; + + switch (metadata_ptr->op) { + case metadata_op_crc: + ret = mdp3_ctrl_res_req_clk(mfd, 1); + if (ret) { + pr_err("failed to turn on mdp clks\n"); + return ret; + } + ret = mdp3_misr_set(&metadata_ptr->data.misr_request); + ret = mdp3_ctrl_res_req_clk(mfd, 0); + if (ret) { + pr_err("failed to release mdp clks\n"); + return ret; + } + break; + default: + pr_warn("Unsupported request to MDP SET META IOCTL.\n"); + ret = -EINVAL; + break; + } + return ret; +} + +static int mdp3_get_metadata(struct msm_fb_data_type *mfd, + struct msmfb_metadata *metadata) +{ + int ret = 0; + + switch (metadata->op) { + case metadata_op_frame_rate: + metadata->data.panel_frame_rate = + mfd->panel_info->mipi.frame_rate; + break; + case metadata_op_get_caps: + metadata->data.caps.mdp_rev = 305; + metadata->data.caps.rgb_pipes = 0; + metadata->data.caps.vig_pipes = 0; + metadata->data.caps.dma_pipes = 1; + break; + case metadata_op_crc: + ret = mdp3_ctrl_res_req_clk(mfd, 1); + if (ret) { + pr_err("failed to turn on mdp clks\n"); + return ret; + } + ret = mdp3_misr_get(&metadata->data.misr_request); + ret = mdp3_ctrl_res_req_clk(mfd, 0); + if (ret) { + pr_err("failed to release mdp clks\n"); + return ret; + } + break; + case metadata_op_get_ion_fd: + if (mfd->fb_ion_handle && mfd->fb_ion_client) { + get_dma_buf(mfd->fbmem_buf); + metadata->data.fbmem_ionfd = + ion_share_dma_buf_fd(mfd->fb_ion_client, + mfd->fb_ion_handle); + if (metadata->data.fbmem_ionfd < 0) { + dma_buf_put(mfd->fbmem_buf); + pr_err("fd allocation failed. fd = %d\n", + metadata->data.fbmem_ionfd); + } + } + break; + default: + pr_warn("Unsupported request to MDP GET META IOCTL.\n"); + ret = -EINVAL; + break; + } + return ret; +} + +int mdp3_validate_start_req(struct mdp_histogram_start_req *req) +{ + if (req->frame_cnt >= MDP_HISTOGRAM_FRAME_COUNT_MAX) { + pr_err("%s invalid req frame_cnt\n", __func__); + return -EINVAL; + } + if (req->bit_mask >= MDP_HISTOGRAM_BIT_MASK_MAX) { + pr_err("%s invalid req bit mask\n", __func__); + return -EINVAL; + } + if (req->block != MDP_BLOCK_DMA_P || + req->num_bins != MDP_HISTOGRAM_BIN_NUM) { + pr_err("mdp3_histogram_start invalid request\n"); + return -EINVAL; + } + return 0; +} + +int mdp3_validate_scale_config(struct mdp_bl_scale_data *data) +{ + if (data->scale > MDP_HISTOGRAM_BL_SCALE_MAX) { + pr_err("%s invalid bl_scale\n", __func__); + return -EINVAL; + } + if (data->min_lvl > MDP_HISTOGRAM_BL_LEVEL_MAX) { + pr_err("%s invalid bl_min_lvl\n", __func__); + return -EINVAL; + } + return 0; +} + +int mdp3_validate_csc_data(struct mdp_csc_cfg_data *data) +{ + int i; + bool mv_valid = false; + + for (i = 0; i < 9; i++) { + if (data->csc_data.csc_mv[i] >= + MDP_HISTOGRAM_CSC_MATRIX_MAX) + return -EINVAL; + if ((!mv_valid) && (data->csc_data.csc_mv[i] != 0)) + mv_valid = true; + } + if (!mv_valid) { + pr_err("%s: black screen data! csc_mv is all 0s\n", __func__); + return -EINVAL; + } + for (i = 0; i < 3; i++) { + if (data->csc_data.csc_pre_bv[i] >= + MDP_HISTOGRAM_CSC_VECTOR_MAX) + return -EINVAL; + if (data->csc_data.csc_post_bv[i] >= + MDP_HISTOGRAM_CSC_VECTOR_MAX) + return -EINVAL; + } + for (i = 0; i < 6; i++) { + if (data->csc_data.csc_pre_lv[i] >= + MDP_HISTOGRAM_CSC_VECTOR_MAX) + return -EINVAL; + if (data->csc_data.csc_post_lv[i] >= + MDP_HISTOGRAM_CSC_VECTOR_MAX) + return -EINVAL; + } + return 0; +} + +static int mdp3_histogram_start(struct mdp3_session_data *session, + struct mdp_histogram_start_req *req) +{ + int ret; + struct mdp3_dma_histogram_config histo_config; + + mutex_lock(&session->lock); + if (!session->status) { + mutex_unlock(&session->lock); + return -EPERM; + } + + pr_debug("%s\n", __func__); + + ret = mdp3_validate_start_req(req); + if (ret) { + mutex_unlock(&session->lock); + return ret; + } + + if (!session->dma->histo_op || + !session->dma->config_histo) { + pr_err("%s not supported\n", __func__); + mutex_unlock(&session->lock); + return -EINVAL; + } + + mutex_lock(&session->histo_lock); + + if (session->histo_status) { + pr_info("%s already started\n", __func__); + mutex_unlock(&session->histo_lock); + mutex_unlock(&session->lock); + return 0; + } + + mdp3_res_update(1, 0, MDP3_CLIENT_DMA_P); + ret = session->dma->histo_op(session->dma, MDP3_DMA_HISTO_OP_RESET); + if (ret) { + pr_err("%s reset error\n", __func__); + goto histogram_start_err; + } + + histo_config.frame_count = req->frame_cnt; + histo_config.bit_mask = req->bit_mask; + histo_config.auto_clear_en = 1; + histo_config.bit_mask_polarity = 0; + ret = session->dma->config_histo(session->dma, &histo_config); + if (ret) { + pr_err("%s error\n", __func__); + goto histogram_start_err; + } + + ret = session->dma->histo_op(session->dma, MDP3_DMA_HISTO_OP_START); + if (ret) { + pr_err("%s config error\n", __func__); + goto histogram_start_err; + } + + session->histo_status = 1; + +histogram_start_err: + mdp3_res_update(0, 0, MDP3_CLIENT_DMA_P); + mutex_unlock(&session->histo_lock); + mutex_unlock(&session->lock); + return ret; +} + +static int mdp3_histogram_stop(struct mdp3_session_data *session, + u32 block) +{ + int ret; + + pr_debug("%s\n", __func__); + + if (!session->dma->histo_op || block != MDP_BLOCK_DMA_P) { + pr_err("%s not supported\n", __func__); + return -EINVAL; + } + + mutex_lock(&session->histo_lock); + + if (!session->histo_status) { + pr_debug("%s already stopped!", __func__); + ret = 0; + goto histogram_stop_err; + } + + mdp3_clk_enable(1, 0); + ret = session->dma->histo_op(session->dma, MDP3_DMA_HISTO_OP_CANCEL); + mdp3_clk_enable(0, 0); + if (ret) + pr_err("%s error\n", __func__); + + session->histo_status = 0; + +histogram_stop_err: + mutex_unlock(&session->histo_lock); + return ret; +} + +static int mdp3_histogram_collect(struct mdp3_session_data *session, + struct mdp_histogram_data *hist) +{ + int ret; + struct mdp3_dma_histogram_data *mdp3_histo; + + pr_debug("%s\n", __func__); + if (!session->dma->get_histo) { + pr_err("%s not supported\n", __func__); + return -EINVAL; + } + + mutex_lock(&session->histo_lock); + + if (!session->histo_status) { + pr_debug("%s not started\n", __func__); + mutex_unlock(&session->histo_lock); + return -EPROTO; + } + + mutex_unlock(&session->histo_lock); + + if (!session->clk_on) { + pr_debug("mdp/dsi clock off currently\n"); + return -EPERM; + } + + mdp3_clk_enable(1, 0); + ret = session->dma->get_histo(session->dma); + mdp3_clk_enable(0, 0); + if (ret) { + pr_debug("%s error = %d\n", __func__, ret); + return ret; + } + + mdp3_histo = &session->dma->histo_data; + + ret = copy_to_user(hist->c0, mdp3_histo->r_data, + sizeof(uint32_t) * MDP_HISTOGRAM_BIN_NUM); + if (ret) + return ret; + + ret = copy_to_user(hist->c1, mdp3_histo->g_data, + sizeof(uint32_t) * MDP_HISTOGRAM_BIN_NUM); + if (ret) + return ret; + + ret = copy_to_user(hist->c2, mdp3_histo->b_data, + sizeof(uint32_t) * MDP_HISTOGRAM_BIN_NUM); + if (ret) + return ret; + + ret = copy_to_user(hist->extra_info, mdp3_histo->extra, + sizeof(uint32_t) * 2); + if (ret) + return ret; + + hist->bin_cnt = MDP_HISTOGRAM_BIN_NUM; + hist->block = MDP_BLOCK_DMA_P; + return ret; +} + +static int mdp3_bl_scale_config(struct msm_fb_data_type *mfd, + struct mdp_bl_scale_data *data) +{ + int ret = 0; + int curr_bl; + + mutex_lock(&mfd->bl_lock); + curr_bl = mfd->bl_level; + mfd->bl_scale = data->scale; + mfd->bl_min_lvl = data->min_lvl; + pr_debug("update scale = %d, min_lvl = %d\n", mfd->bl_scale, + mfd->bl_min_lvl); + + /* update current backlight to use new scaling*/ + mdss_fb_set_backlight(mfd, curr_bl); + mutex_unlock(&mfd->bl_lock); + return ret; +} + +static int mdp3_csc_config(struct mdp3_session_data *session, + struct mdp_csc_cfg_data *data) +{ + struct mdp3_dma_color_correct_config config; + struct mdp3_dma_ccs ccs; + int ret = -EINVAL; + + if (!data->csc_data.csc_mv || !data->csc_data.csc_pre_bv || + !data->csc_data.csc_post_bv || !data->csc_data.csc_pre_lv || + !data->csc_data.csc_post_lv) { + pr_err("%s : Invalid csc vectors", __func__); + return -EINVAL; + } + + mutex_lock(&session->lock); + mutex_lock(&session->dma->pp_lock); + session->dma->cc_vect_sel = (session->dma->cc_vect_sel + 1) % 2; + + config.ccs_enable = 1; + config.ccs_sel = session->dma->cc_vect_sel; + config.pre_limit_sel = session->dma->cc_vect_sel; + config.post_limit_sel = session->dma->cc_vect_sel; + config.pre_bias_sel = session->dma->cc_vect_sel; + config.post_bias_sel = session->dma->cc_vect_sel; + config.ccs_dirty = true; + + ccs.mv = data->csc_data.csc_mv; + ccs.pre_bv = data->csc_data.csc_pre_bv; + ccs.post_bv = data->csc_data.csc_post_bv; + ccs.pre_lv = data->csc_data.csc_pre_lv; + ccs.post_lv = data->csc_data.csc_post_lv; + + /* cache one copy of setting for suspend/resume reconfiguring */ + session->dma->ccs_cache = *data; + + mdp3_clk_enable(1, 0); + ret = session->dma->config_ccs(session->dma, &config, &ccs); + mdp3_clk_enable(0, 0); + mutex_unlock(&session->dma->pp_lock); + mutex_unlock(&session->lock); + return ret; +} + +static int mdp3_pp_ioctl(struct msm_fb_data_type *mfd, + void __user *argp) +{ + int ret = -EINVAL; + struct msmfb_mdp_pp mdp_pp; + struct mdp_lut_cfg_data *lut; + struct mdp3_session_data *mdp3_session; + + if (!mfd || !mfd->mdp.private1) + return -EINVAL; + + mdp3_session = mfd->mdp.private1; + + ret = copy_from_user(&mdp_pp, argp, sizeof(mdp_pp)); + if (ret) + return ret; + + switch (mdp_pp.op) { + case mdp_bl_scale_cfg: + ret = mdp3_validate_scale_config(&mdp_pp.data.bl_scale_data); + if (ret) { + pr_err("%s: invalid scale config\n", __func__); + break; + } + ret = mdp3_bl_scale_config(mfd, (struct mdp_bl_scale_data *) + &mdp_pp.data.bl_scale_data); + break; + case mdp_op_csc_cfg: + /* Checking state of dyn_pu before programming CSC block */ + if (mdp3_session->dyn_pu_state) { + pr_debug("Partial update feature is enabled.\n"); + return -EPERM; + } + ret = mdp3_validate_csc_data(&(mdp_pp.data.csc_cfg_data)); + if (ret) { + pr_err("%s: invalid csc data\n", __func__); + break; + } + ret = mdp3_csc_config(mdp3_session, + &(mdp_pp.data.csc_cfg_data)); + break; + case mdp_op_lut_cfg: + lut = &mdp_pp.data.lut_cfg_data; + if (lut->lut_type != mdp_lut_rgb) { + pr_err("Lut type %d is not supported", lut->lut_type); + return -EINVAL; + } + if (lut->data.rgb_lut_data.flags & MDP_PP_OPS_READ) + ret = mdp3_ctrl_lut_read(mfd, + &(lut->data.rgb_lut_data)); + else + ret = mdp3_ctrl_lut_config(mfd, + &(lut->data.rgb_lut_data)); + if (ret) + pr_err("RGB LUT ioctl failed\n"); + else + ret = copy_to_user(argp, &mdp_pp, sizeof(mdp_pp)); + break; + + default: + pr_err("Unsupported request to MDP_PP IOCTL.\n"); + ret = -EINVAL; + break; + } + if (!ret) + ret = copy_to_user(argp, &mdp_pp, sizeof(struct msmfb_mdp_pp)); + return ret; +} + +static int mdp3_histo_ioctl(struct msm_fb_data_type *mfd, u32 cmd, + void __user *argp) +{ + int ret = -ENOTSUPP; + struct mdp_histogram_data hist; + struct mdp_histogram_start_req hist_req; + u32 block; + struct mdp3_session_data *mdp3_session; + + if (!mfd || !mfd->mdp.private1) + return -EINVAL; + + mdp3_session = mfd->mdp.private1; + + switch (cmd) { + case MSMFB_HISTOGRAM_START: + ret = copy_from_user(&hist_req, argp, sizeof(hist_req)); + if (ret) + return ret; + + ret = mdp3_histogram_start(mdp3_session, &hist_req); + break; + + case MSMFB_HISTOGRAM_STOP: + ret = copy_from_user(&block, argp, sizeof(int)); + if (ret) + return ret; + + ret = mdp3_histogram_stop(mdp3_session, block); + break; + + case MSMFB_HISTOGRAM: + ret = copy_from_user(&hist, argp, sizeof(hist)); + if (ret) + return ret; + + ret = mdp3_histogram_collect(mdp3_session, &hist); + if (!ret) + ret = copy_to_user(argp, &hist, sizeof(hist)); + break; + default: + break; + } + return ret; +} + +static int mdp3_validate_lut_data(struct fb_cmap *cmap) +{ + u32 i = 0; + + if (!cmap || !cmap->red || !cmap->green || !cmap->blue) { + pr_err("Invalid arguments!\n"); + return -EINVAL; + } + + for (i = 0; i < MDP_LUT_SIZE; i++) { + if (cmap->red[i] > 0xFF || cmap->green[i] > 0xFF || + cmap->blue[i] > 0xFF) { + pr_err("LUT value over 255 (limit) at %d index\n", i); + return -EINVAL; + } + } + + return 0; +} + +static inline int mdp3_copy_lut_buffer(struct fb_cmap *dst, struct fb_cmap *src) +{ + if (!dst || !src || !dst->red || !dst->blue || !dst->green || + !src->red || !src->green || !src->blue) { + pr_err("Invalid params\n"); + return -EINVAL; + } + + dst->start = src->start; + dst->len = src->len; + + memcpy(dst->red, src->red, MDP_LUT_SIZE * sizeof(u16)); + memcpy(dst->green, src->green, MDP_LUT_SIZE * sizeof(u16)); + memcpy(dst->blue, src->blue, MDP_LUT_SIZE * sizeof(u16)); + return 0; +} + +static int mdp3_alloc_lut_buffer(struct platform_device *pdev, void **cmap) +{ + struct fb_cmap *map; + + map = devm_kzalloc(&pdev->dev, sizeof(struct fb_cmap), GFP_KERNEL); + if (map == NULL) + return -ENOMEM; + + memset(map, 0, sizeof(struct fb_cmap)); + + map->red = devm_kzalloc(&pdev->dev, MDP_LUT_SIZE * sizeof(u16), + GFP_KERNEL); + if (map->red == NULL) + goto exit_red; + + memset(map->red, 0, sizeof(u16) * MDP_LUT_SIZE); + + map->green = devm_kzalloc(&pdev->dev, MDP_LUT_SIZE * sizeof(u16), + GFP_KERNEL); + if (map->green == NULL) + goto exit_green; + + memset(map->green, 0, sizeof(u16) * MDP_LUT_SIZE); + + map->blue = devm_kzalloc(&pdev->dev, MDP_LUT_SIZE * sizeof(u16), + GFP_KERNEL); + if (map->blue == NULL) + goto exit_blue; + + memset(map->blue, 0, sizeof(u16) * MDP_LUT_SIZE); + + *cmap = map; + return 0; +exit_blue: + devm_kfree(&pdev->dev, map->green); +exit_green: + devm_kfree(&pdev->dev, map->red); +exit_red: + devm_kfree(&pdev->dev, map); + return -ENOMEM; +} + +static void mdp3_free_lut_buffer(struct platform_device *pdev, void **cmap) +{ + struct fb_cmap *map = (struct fb_cmap *)(*cmap); + + if (map == NULL) + return; + + devm_kfree(&pdev->dev, map->blue); + map->blue = NULL; + devm_kfree(&pdev->dev, map->green); + map->green = NULL; + devm_kfree(&pdev->dev, map->red); + map->red = NULL; + devm_kfree(&pdev->dev, map); + map = NULL; +} + +static int mdp3_lut_combine_gain(struct fb_cmap *cmap, struct mdp3_dma *dma) +{ + int i = 0; + u32 r = 0, g = 0, b = 0; + + if (!cmap || !dma || !dma->gc_cmap || !dma->hist_cmap || + !dma->gc_cmap->red || !dma->gc_cmap->green || + !dma->gc_cmap->blue || !dma->hist_cmap->red || + !dma->hist_cmap->green || !dma->hist_cmap->blue) { + pr_err("Invalid params\n"); + return -EINVAL; + } + + for (i = 1; i < MDP_LUT_SIZE; i++) { + r = MIN(dma->gc_cmap->red[i] * dma->hist_cmap->red[i] * + mdp_lut_inverse16[i], 0xFF0000); + g = MIN(dma->gc_cmap->green[i] * dma->hist_cmap->green[i] * + mdp_lut_inverse16[i], 0xFF0000); + b = MIN(dma->gc_cmap->blue[i] * dma->hist_cmap->blue[i] * + mdp_lut_inverse16[i], 0xFF0000); + + cmap->red[i] = (r >> 16) & 0xFF; + cmap->green[i] = (g >> 16) & 0xFF; + cmap->blue[i] = (b >> 16) & 0xFF; + } + return 0; +} + +/* Called from within pp_lock and session lock locked context */ +static int mdp3_ctrl_lut_update(struct msm_fb_data_type *mfd, + struct fb_cmap *cmap) +{ + int rc = 0; + struct mdp3_session_data *mdp3_session = mfd->mdp.private1; + struct mdp3_dma *dma; + struct mdp3_dma_lut_config lut_config; + + dma = mdp3_session->dma; + + if (!dma->config_lut) { + pr_err("Config LUT not defined!\n"); + return -EINVAL; + } + + lut_config.lut_enable = 7; + lut_config.lut_sel = mdp3_session->lut_sel; + lut_config.lut_position = 1; + lut_config.lut_dirty = true; + + if (!mdp3_session->status) { + pr_err("display off!\n"); + return -EPERM; + } + + mdp3_clk_enable(1, 0); + rc = dma->config_lut(dma, &lut_config, cmap); + mdp3_clk_enable(0, 0); + if (rc) + pr_err("%s failed\n", __func__); + + mdp3_session->lut_sel = (mdp3_session->lut_sel + 1) % 2; + return rc; +} + +static int mdp3_ctrl_lut_config(struct msm_fb_data_type *mfd, + struct mdp_rgb_lut_data *cfg) +{ + int rc = 0; + bool data_validated = false; + struct mdp3_session_data *mdp3_session = mfd->mdp.private1; + struct mdp3_dma *dma; + struct fb_cmap *cmap; + + dma = mdp3_session->dma; + + if ((cfg->cmap.start > MDP_LUT_SIZE) || + (cfg->cmap.len > MDP_LUT_SIZE) || + (cfg->cmap.start + cfg->cmap.len > MDP_LUT_SIZE)) { + pr_err("Invalid arguments.\n"); + return -EINVAL; + } + + rc = mdp3_alloc_lut_buffer(mfd->pdev, (void **) &cmap); + if (rc) { + pr_err("No memory\n"); + return -ENOMEM; + } + + mutex_lock(&mdp3_session->lock); + mutex_lock(&dma->pp_lock); + rc = copy_from_user(cmap->red + cfg->cmap.start, + cfg->cmap.red, sizeof(u16) * cfg->cmap.len); + rc |= copy_from_user(cmap->green + cfg->cmap.start, + cfg->cmap.green, sizeof(u16) * cfg->cmap.len); + rc |= copy_from_user(cmap->blue + cfg->cmap.start, + cfg->cmap.blue, sizeof(u16) * cfg->cmap.len); + if (rc) { + pr_err("Copying user data failed!\n"); + goto exit_err; + } + + switch (cfg->lut_type) { + case mdp_rgb_lut_gc: + if (cfg->flags & MDP_PP_OPS_DISABLE) { + if (dma->lut_sts & MDP3_LUT_GC_EN) + /* Free GC cmap cache since disabled */ + mdp3_free_lut_buffer(mfd->pdev, + (void **)&dma->gc_cmap); + dma->lut_sts &= ~MDP3_LUT_GC_EN; + } else if (!(dma->lut_sts & MDP3_LUT_GC_EN)) { + /* Check if values sent are valid */ + rc = mdp3_validate_lut_data(cmap); + if (rc) { + pr_err("Invalid GC LUT data\n"); + goto exit_err; + } + data_validated = true; + + /* Allocate GC cmap cache to store values */ + rc = mdp3_alloc_lut_buffer(mfd->pdev, + (void **)&dma->gc_cmap); + if (rc) { + pr_err("GC LUT config failed\n"); + goto exit_err; + } + dma->lut_sts |= MDP3_LUT_GC_EN; + } + /* + * Copy the GC values from userspace to maintain the + * correct values user intended to program in cache. + * The values programmed in HW might factor in presence + * of other LUT modifying features hence can be + * different from these user given values. + */ + if (dma->lut_sts & MDP3_LUT_GC_EN) { + /* Validate LUT data if not yet validated */ + if (!data_validated) { + rc = mdp3_validate_lut_data(cmap); + if (rc) { + pr_err("Invalid GC LUT data\n"); + goto exit_err; + } + } + rc = mdp3_copy_lut_buffer(dma->gc_cmap, cmap); + if (rc) { + pr_err("Could not store GC to cache\n"); + goto exit_err; + } + } + break; + case mdp_rgb_lut_hist: + if (cfg->flags & MDP_PP_OPS_DISABLE) { + if (dma->lut_sts & MDP3_LUT_HIST_EN) + /* Free HIST cmap cache since disabled */ + mdp3_free_lut_buffer(mfd->pdev, + (void **)&dma->hist_cmap); + dma->lut_sts &= ~MDP3_LUT_HIST_EN; + } else if (!(dma->lut_sts & MDP3_LUT_HIST_EN)) { + /* Check if values sent are valid */ + rc = mdp3_validate_lut_data(cmap); + if (rc) { + pr_err("Invalid HIST LUT data\n"); + goto exit_err; + } + data_validated = true; + + /* Allocate HIST cmap cache to store values */ + rc = mdp3_alloc_lut_buffer(mfd->pdev, + (void **)&dma->hist_cmap); + if (rc) { + pr_err("HIST LUT config failed\n"); + goto exit_err; + } + dma->lut_sts |= MDP3_LUT_HIST_EN; + } + /* + * Copy the HIST LUT values from userspace to maintain + * correct values user intended to program in cache. + * The values programmed in HW might factor in presence + * of other LUT modifying features hence can be + * different from these user given values. + */ + if (dma->lut_sts & MDP3_LUT_HIST_EN) { + /* Validate LUT data if not yet validated */ + if (!data_validated) { + rc = mdp3_validate_lut_data(cmap); + if (rc) { + pr_err("Invalid H LUT data\n"); + goto exit_err; + } + } + rc = mdp3_copy_lut_buffer(dma->hist_cmap, cmap); + if (rc) { + pr_err("Could not cache Hist LUT\n"); + goto exit_err; + } + } + break; + default: + pr_err("Invalid lut type: %u\n", cfg->lut_type); + rc = -EINVAL; + goto exit_err; + } + + /* + * In case both GC LUT and HIST LUT need to be programmed the gains + * of each the individual LUTs need to be applied onto a single LUT + * and applied in HW + */ + if ((dma->lut_sts & MDP3_LUT_HIST_EN) && + (dma->lut_sts & MDP3_LUT_GC_EN)) { + rc = mdp3_lut_combine_gain(cmap, dma); + if (rc) { + pr_err("Combining gains failed rc = %d\n", rc); + goto exit_err; + } + } + + rc = mdp3_ctrl_lut_update(mfd, cmap); + if (rc) + pr_err("Updating LUT failed! rc = %d\n", rc); +exit_err: + mutex_unlock(&dma->pp_lock); + mutex_unlock(&mdp3_session->lock); + mdp3_free_lut_buffer(mfd->pdev, (void **) &cmap); + return rc; +} + +static int mdp3_ctrl_lut_read(struct msm_fb_data_type *mfd, + struct mdp_rgb_lut_data *cfg) +{ + int rc = 0; + struct fb_cmap *cmap; + struct mdp3_session_data *mdp3_session = mfd->mdp.private1; + struct mdp3_dma *dma = mdp3_session->dma; + + switch (cfg->lut_type) { + case mdp_rgb_lut_gc: + if (!dma->gc_cmap) { + pr_err("GC not programmed\n"); + return -EPERM; + } + cmap = dma->gc_cmap; + break; + case mdp_rgb_lut_hist: + if (!dma->hist_cmap) { + pr_err("Hist LUT not programmed\n"); + return -EPERM; + } + cmap = dma->hist_cmap; + break; + default: + pr_err("Invalid lut type %u\n", cfg->lut_type); + return -EINVAL; + } + + cfg->cmap.start = cmap->start; + cfg->cmap.len = cmap->len; + + mutex_lock(&dma->pp_lock); + rc = copy_to_user(cfg->cmap.red, cmap->red, sizeof(u16) * + MDP_LUT_SIZE); + rc |= copy_to_user(cfg->cmap.green, cmap->green, sizeof(u16) * + MDP_LUT_SIZE); + rc |= copy_to_user(cfg->cmap.blue, cmap->blue, sizeof(u16) * + MDP_LUT_SIZE); + mutex_unlock(&dma->pp_lock); + return rc; +} + +/* Invoked from ctrl_on with session lock locked context */ +static void mdp3_ctrl_pp_resume(struct msm_fb_data_type *mfd) +{ + struct mdp3_session_data *mdp3_session; + struct mdp3_dma *dma; + struct fb_cmap *cmap; + int rc = 0; + + mdp3_session = mfd->mdp.private1; + dma = mdp3_session->dma; + + mutex_lock(&dma->pp_lock); + /* + * if dma->ccs_config.ccs_enable is set then DMA PP block was enabled + * via user space IOCTL. + * Then set dma->ccs_config.ccs_dirty flag + * Then PP block will be reconfigured when next kickoff comes. + */ + if (dma->ccs_config.ccs_enable) + dma->ccs_config.ccs_dirty = true; + + /* + * If gamma correction was enabled then we program the LUT registers + * with the last configuration data before suspend. If gamma correction + * is not enabled then we do not program anything. The LUT from + * histogram processing algorithms will program hardware based on new + * frame data if they are enabled. + */ + if (dma->lut_sts & MDP3_LUT_GC_EN) { + + rc = mdp3_alloc_lut_buffer(mfd->pdev, (void **)&cmap); + if (rc) { + pr_err("No memory for GC LUT, rc = %d\n", rc); + goto exit_err; + } + + if (dma->lut_sts & MDP3_LUT_HIST_EN) { + rc = mdp3_lut_combine_gain(cmap, dma); + if (rc) { + pr_err("Combining the gain failed rc=%d\n", rc); + goto exit_err; + } + } else { + rc = mdp3_copy_lut_buffer(cmap, dma->gc_cmap); + if (rc) { + pr_err("Updating GC failed rc = %d\n", rc); + goto exit_err; + } + } + + rc = mdp3_ctrl_lut_update(mfd, cmap); + if (rc) + pr_err("GC Lut update failed rc=%d\n", rc); +exit_err: + mdp3_free_lut_buffer(mfd->pdev, (void **)&cmap); + } + + mutex_unlock(&dma->pp_lock); +} + +static int mdp3_overlay_prepare(struct msm_fb_data_type *mfd, + struct mdp_overlay_list __user *user_ovlist) +{ + struct mdp_overlay_list ovlist; + struct mdp3_session_data *mdp3_session = mfd->mdp.private1; + struct mdp_overlay *req_list; + struct mdp_overlay *req; + int rc; + + if (!mdp3_session) + return -ENODEV; + + req = &mdp3_session->req_overlay; + + if (copy_from_user(&ovlist, user_ovlist, sizeof(ovlist))) + return -EFAULT; + + if (ovlist.num_overlays != 1) { + pr_err("OV_PREPARE failed: only 1 overlay allowed\n"); + return -EINVAL; + } + + if (copy_from_user(&req_list, ovlist.overlay_list, + sizeof(struct mdp_overlay *))) + return -EFAULT; + + if (copy_from_user(req, req_list, sizeof(*req))) + return -EFAULT; + + rc = mdp3_overlay_set(mfd, req); + if (!IS_ERR_VALUE(rc)) { + if (copy_to_user(req_list, req, sizeof(*req))) + return -EFAULT; + } + + if (put_user(IS_ERR_VALUE(rc) ? 0 : 1, + &user_ovlist->processed_overlays)) + return -EFAULT; + + return rc; +} + +static int mdp3_ctrl_ioctl_handler(struct msm_fb_data_type *mfd, + u32 cmd, void __user *argp) +{ + int rc = -EINVAL; + struct mdp3_session_data *mdp3_session; + struct msmfb_metadata metadata; + struct mdp_overlay *req = NULL; + struct msmfb_overlay_data ov_data; + int val; + + mdp3_session = (struct mdp3_session_data *)mfd->mdp.private1; + if (!mdp3_session) + return -ENODEV; + + req = &mdp3_session->req_overlay; + + if (!mdp3_session->status && cmd != MSMFB_METADATA_GET && + cmd != MSMFB_HISTOGRAM_STOP && cmd != MSMFB_HISTOGRAM) { + pr_err("%s, display off!\n", __func__); + return -EPERM; + } + + switch (cmd) { + case MSMFB_MDP_PP: + rc = mdp3_pp_ioctl(mfd, argp); + break; + case MSMFB_HISTOGRAM_START: + case MSMFB_HISTOGRAM_STOP: + case MSMFB_HISTOGRAM: + rc = mdp3_histo_ioctl(mfd, cmd, argp); + break; + + case MSMFB_VSYNC_CTRL: + case MSMFB_OVERLAY_VSYNC_CTRL: + if (!copy_from_user(&val, argp, sizeof(val))) { + mutex_lock(&mdp3_session->lock); + mdp3_session->vsync_enabled = val; + rc = mdp3_ctrl_vsync_enable(mfd, val); + mutex_unlock(&mdp3_session->lock); + } else { + pr_err("MSMFB_OVERLAY_VSYNC_CTRL failed\n"); + rc = -EFAULT; + } + break; + case MSMFB_ASYNC_BLIT: + mutex_lock(&mdp3_res->fs_idle_pc_lock); + if (mdp3_session->in_splash_screen || mdp3_res->idle_pc) { + pr_debug("%s: reset- in_splash = %d, idle_pc = %d", + __func__, mdp3_session->in_splash_screen, + mdp3_res->idle_pc); + mdp3_ctrl_reset(mfd); + } + mutex_unlock(&mdp3_res->fs_idle_pc_lock); + rc = mdp3_ctrl_async_blit_req(mfd, argp); + break; + case MSMFB_BLIT: + mutex_lock(&mdp3_res->fs_idle_pc_lock); + if (mdp3_session->in_splash_screen) + mdp3_ctrl_reset(mfd); + mutex_unlock(&mdp3_res->fs_idle_pc_lock); + rc = mdp3_ctrl_blit_req(mfd, argp); + break; + case MSMFB_METADATA_GET: + rc = copy_from_user(&metadata, argp, sizeof(metadata)); + if (!rc) + rc = mdp3_get_metadata(mfd, &metadata); + if (!rc) + rc = copy_to_user(argp, &metadata, sizeof(metadata)); + if (rc) + pr_err("mdp3_get_metadata failed (%d)\n", rc); + break; + case MSMFB_METADATA_SET: + rc = copy_from_user(&metadata, argp, sizeof(metadata)); + if (!rc) + rc = mdp3_set_metadata(mfd, &metadata); + if (rc) + pr_err("mdp3_set_metadata failed (%d)\n", rc); + break; + case MSMFB_OVERLAY_GET: + rc = copy_from_user(req, argp, sizeof(*req)); + if (!rc) { + rc = mdp3_overlay_get(mfd, req); + + if (!IS_ERR_VALUE(rc)) + rc = copy_to_user(argp, req, sizeof(*req)); + } + if (rc) + pr_err("OVERLAY_GET failed (%d)\n", rc); + break; + case MSMFB_OVERLAY_SET: + rc = copy_from_user(req, argp, sizeof(*req)); + if (!rc) { + rc = mdp3_overlay_set(mfd, req); + + if (!IS_ERR_VALUE(rc)) + rc = copy_to_user(argp, req, sizeof(*req)); + } + if (rc) + pr_err("OVERLAY_SET failed (%d)\n", rc); + break; + case MSMFB_OVERLAY_UNSET: + if (!IS_ERR_VALUE(copy_from_user(&val, argp, sizeof(val)))) + rc = mdp3_overlay_unset(mfd, val); + break; + case MSMFB_OVERLAY_PLAY: + rc = copy_from_user(&ov_data, argp, sizeof(ov_data)); + mutex_lock(&mdp3_res->fs_idle_pc_lock); + if (mdp3_session->in_splash_screen) + mdp3_ctrl_reset(mfd); + mutex_unlock(&mdp3_res->fs_idle_pc_lock); + if (!rc) + rc = mdp3_overlay_play(mfd, &ov_data); + if (rc) + pr_err("OVERLAY_PLAY failed (%d)\n", rc); + break; + case MSMFB_OVERLAY_PREPARE: + rc = mdp3_overlay_prepare(mfd, argp); + break; + default: + break; + } + return rc; +} + +int mdp3_wait_for_dma_done(struct mdp3_session_data *session) +{ + int rc = 0; + + if (session->dma_active) { + rc = wait_for_completion_timeout(&session->dma_completion, + KOFF_TIMEOUT); + if (rc > 0) { + session->dma_active = 0; + rc = 0; + } else if (rc == 0) { + rc = -ETIME; + } + } + return rc; +} + +static int mdp3_update_panel_info(struct msm_fb_data_type *mfd, int mode, + int dest_ctrl) +{ + int ret = 0; + struct mdp3_session_data *mdp3_session; + struct mdss_panel_data *panel; + u32 intf_type = 0; + + if (!mfd || !mfd->mdp.private1) + return -EINVAL; + + mdp3_session = mfd->mdp.private1; + panel = mdp3_session->panel; + + if (!panel->event_handler) + return 0; + ret = panel->event_handler(panel, MDSS_EVENT_DSI_UPDATE_PANEL_DATA, + (void *)(unsigned long)mode); + if (ret) + pr_err("Dynamic switch to %s mode failed!\n", + mode ? "command" : "video"); + if (mode == 1) + mfd->panel.type = MIPI_CMD_PANEL; + else + mfd->panel.type = MIPI_VIDEO_PANEL; + + if (mfd->panel.type != MIPI_VIDEO_PANEL) + mdp3_session->wait_for_dma_done = mdp3_wait_for_dma_done; + + intf_type = mdp3_ctrl_get_intf_type(mfd); + mdp3_session->intf->cfg.type = intf_type; + mdp3_session->intf->available = 1; + mdp3_session->intf->in_use = 1; + mdp3_res->intf[intf_type].in_use = 1; + + mdp3_intf_init(mdp3_session->intf); + + mdp3_session->dma->output_config.out_sel = intf_type; + mdp3_session->status = mdp3_session->intf->active; + + return 0; +} + +static int mdp3_vsync_retire_setup(struct msm_fb_data_type *mfd) +{ + struct mdp3_session_data *mdp3_session; + struct mdp3_notification retire_client; + char name[24]; + + mdp3_session = (struct mdp3_session_data *)mfd->mdp.private1; + + snprintf(name, sizeof(name), "mdss_fb%d_retire", mfd->index); + mfd->mdp_sync_pt_data.timeline_retire = mdss_create_timeline(name); + if (mfd->mdp_sync_pt_data.timeline_retire == NULL) { + pr_err("cannot vsync create time line"); + return -ENOMEM; + } + + /* Add retire vsync handler */ + retire_client.handler = mdp3_vsync_retire_handle_vsync; + retire_client.arg = mdp3_session; + + if (mdp3_session->dma) + mdp3_session->dma->retire_client = retire_client; + + INIT_WORK(&mdp3_session->retire_work, mdp3_vsync_retire_work_handler); + + return 0; +} + +int mdp3_ctrl_init(struct msm_fb_data_type *mfd) +{ + struct device *dev = mfd->fbi->dev; + struct msm_mdp_interface *mdp3_interface = &mfd->mdp; + struct mdp3_session_data *mdp3_session = NULL; + u32 intf_type = MDP3_DMA_OUTPUT_SEL_DSI_VIDEO; + int rc; + int splash_mismatch = 0; + struct sched_param sched = { .sched_priority = 16 }; + + pr_info("%s\n", __func__); + rc = mdp3_parse_dt_splash(mfd); + if (rc) + splash_mismatch = 1; + + mdp3_interface->on_fnc = mdp3_ctrl_on; + mdp3_interface->off_fnc = mdp3_ctrl_off; + mdp3_interface->do_histogram = NULL; + mdp3_interface->cursor_update = NULL; + mdp3_interface->dma_fnc = mdp3_ctrl_pan_display; + mdp3_interface->ioctl_handler = mdp3_ctrl_ioctl_handler; + mdp3_interface->kickoff_fnc = mdp3_ctrl_display_commit_kickoff; + mdp3_interface->pre_commit = mdp3_layer_pre_commit; + mdp3_interface->atomic_validate = mdp3_layer_atomic_validate; + mdp3_interface->lut_update = NULL; + mdp3_interface->configure_panel = mdp3_update_panel_info; + mdp3_interface->input_event_handler = NULL; + mdp3_interface->signal_retire_fence = NULL; + + mdp3_session = kzalloc(sizeof(struct mdp3_session_data), GFP_KERNEL); + if (!mdp3_session) + return -ENOMEM; + + mutex_init(&mdp3_session->lock); + INIT_WORK(&mdp3_session->clk_off_work, mdp3_dispatch_clk_off); + + kthread_init_worker(&mdp3_session->worker); + kthread_init_work(&mdp3_session->dma_done_work, mdp3_dispatch_dma_done); + + + mdp3_session->thread = kthread_run(kthread_worker_fn, + &mdp3_session->worker, + "mdp3_dispatch_dma_done"); + + if (IS_ERR(mdp3_session->thread)) { + pr_err("Can't initialize mdp3_dispatch_dma_done thread\n"); + rc = -ENODEV; + goto init_done; + } + + sched_setscheduler(mdp3_session->thread, SCHED_FIFO, &sched); + + atomic_set(&mdp3_session->vsync_countdown, 0); + mutex_init(&mdp3_session->histo_lock); + mdp3_session->dma = mdp3_get_dma_pipe(MDP3_DMA_CAP_ALL); + if (!mdp3_session->dma) { + rc = -ENODEV; + goto init_done; + } + + rc = mdp3_dma_init(mdp3_session->dma); + if (rc) { + pr_err("fail to init dma\n"); + goto init_done; + } + + intf_type = mdp3_ctrl_get_intf_type(mfd); + mdp3_session->intf = mdp3_get_display_intf(intf_type); + if (!mdp3_session->intf) { + rc = -ENODEV; + goto init_done; + } + rc = mdp3_intf_init(mdp3_session->intf); + if (rc) { + pr_err("fail to init interface\n"); + goto init_done; + } + + mdp3_session->dma->output_config.out_sel = intf_type; + mdp3_session->mfd = mfd; + mdp3_session->panel = dev_get_platdata(&mfd->pdev->dev); + mdp3_session->status = mdp3_session->intf->active; + mdp3_session->overlay.id = MSMFB_NEW_REQUEST; + mdp3_bufq_init(&mdp3_session->bufq_in); + mdp3_bufq_init(&mdp3_session->bufq_out); + mdp3_session->histo_status = 0; + mdp3_session->lut_sel = 0; + BLOCKING_INIT_NOTIFIER_HEAD(&mdp3_session->notifier_head); + + init_timer(&mdp3_session->vsync_timer); + mdp3_session->vsync_timer.function = mdp3_vsync_timer_func; + mdp3_session->vsync_timer.data = (u32)mdp3_session; + mdp3_session->vsync_period = 1000 / mfd->panel_info->mipi.frame_rate; + mfd->mdp.private1 = mdp3_session; + init_completion(&mdp3_session->dma_completion); + if (intf_type != MDP3_DMA_OUTPUT_SEL_DSI_VIDEO) + mdp3_session->wait_for_dma_done = mdp3_wait_for_dma_done; + + rc = sysfs_create_group(&dev->kobj, &vsync_fs_attr_group); + if (rc) { + pr_err("vsync sysfs group creation failed, ret=%d\n", rc); + goto init_done; + } + rc = sysfs_create_group(&dev->kobj, &generic_attr_group); + if (rc) { + pr_err("generic sysfs group creation failed, ret=%d\n", rc); + goto init_done; + } + + mdp3_session->vsync_event_sd = sysfs_get_dirent(dev->kobj.sd, + "vsync_event"); + if (!mdp3_session->vsync_event_sd) { + pr_err("vsync_event sysfs lookup failed\n"); + rc = -ENODEV; + goto init_done; + } + + mdp3_session->dma->hist_event_sd = sysfs_get_dirent(dev->kobj.sd, + "hist_event"); + if (!mdp3_session->dma->hist_event_sd) { + pr_err("hist_event sysfs lookup failed\n"); + rc = -ENODEV; + goto init_done; + } + + mdp3_session->bl_event_sd = sysfs_get_dirent(dev->kobj.sd, + "bl_event"); + if (!mdp3_session->bl_event_sd) { + pr_err("bl_event sysfs lookup failed\n"); + rc = -ENODEV; + goto init_done; + } + + rc = mdp3_create_sysfs_link(dev); + if (rc) + pr_warn("problem creating link to mdp sysfs\n"); + + /* Enable PM runtime */ + pm_runtime_set_suspended(&mdp3_res->pdev->dev); + pm_runtime_enable(&mdp3_res->pdev->dev); + + kobject_uevent(&dev->kobj, KOBJ_ADD); + pr_debug("vsync kobject_uevent(KOBJ_ADD)\n"); + + if (mdp3_get_cont_spash_en()) { + mdp3_session->clk_on = 1; + mdp3_session->in_splash_screen = 1; + mdp3_ctrl_notifier_register(mdp3_session, + &mdp3_session->mfd->mdp_sync_pt_data.notifier); + } + + /* + * Increment the overlay active count. + * This is needed to ensure that if idle power collapse kicks in + * right away, it would be handled correctly. + */ + atomic_inc(&mdp3_res->active_intf_cnt); + if (splash_mismatch) { + pr_err("splash memory mismatch, stop splash\n"); + mdp3_ctrl_off(mfd); + } + + mdp3_session->vsync_before_commit = true; + mdp3_session->dyn_pu_state = mfd->panel_info->partial_update_enabled; + + if (mfd->panel_info->mipi.dms_mode || + mfd->panel_info->type == MIPI_CMD_PANEL) { + rc = mdp3_vsync_retire_setup(mfd); + if (IS_ERR_VALUE(rc)) { + pr_err("unable to create vsync timeline\n"); + goto init_done; + } + } +init_done: + if (IS_ERR_VALUE(rc)) + kfree(mdp3_session); + + return rc; +} diff --git a/drivers/video/fbdev/msm/mdp3_ctrl.h b/drivers/video/fbdev/msm/mdp3_ctrl.h new file mode 100644 index 000000000000..b7b667b69a9a --- /dev/null +++ b/drivers/video/fbdev/msm/mdp3_ctrl.h @@ -0,0 +1,95 @@ +/* Copyright (c) 2013-2014, 2016-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef MDP3_CTRL_H +#define MDP3_CTRL_H + +#include +#include +#include +#include +#include + +#include "mdp3.h" +#include "mdp3_dma.h" +#include "mdss_fb.h" +#include "mdss_panel.h" + +#define MDP3_MAX_BUF_QUEUE 8 +#define MDP3_LUT_HIST_EN 0x001 +#define MDP3_LUT_GC_EN 0x002 + +struct mdp3_buffer_queue { + struct mdp3_img_data img_data[MDP3_MAX_BUF_QUEUE]; + int count; + int push_idx; + int pop_idx; +}; + +struct mdp3_session_data { + struct mutex lock; + int status; + struct mdp3_dma *dma; + struct mdss_panel_data *panel; + struct mdp3_intf *intf; + struct msm_fb_data_type *mfd; + ktime_t vsync_time; + struct timer_list vsync_timer; + int vsync_period; + struct kernfs_node *vsync_event_sd; + struct kernfs_node *bl_event_sd; + struct mdp_overlay overlay; + struct mdp_overlay req_overlay; + struct mdp3_buffer_queue bufq_in; + struct mdp3_buffer_queue bufq_out; + struct work_struct clk_off_work; + + struct kthread_work dma_done_work; + struct kthread_worker worker; + struct task_struct *thread; + + atomic_t dma_done_cnt; + int histo_status; + struct mutex histo_lock; + int lut_sel; + bool vsync_before_commit; + bool first_commit; + int clk_on; + struct blocking_notifier_head notifier_head; + + int vsync_enabled; + atomic_t vsync_countdown; /* Used to count down */ + bool in_splash_screen; + bool esd_recovery; + int dyn_pu_state; /* dynamic partial update status */ + u32 bl_events; + + bool dma_active; + struct completion dma_completion; + int (*wait_for_dma_done)(struct mdp3_session_data *session); + + /* For retire fence */ + struct mdss_timeline *vsync_timeline; + int retire_cnt; + struct work_struct retire_work; +}; + +void mdp3_bufq_deinit(struct mdp3_buffer_queue *bufq); +int mdp3_ctrl_init(struct msm_fb_data_type *mfd); +int mdp3_bufq_push(struct mdp3_buffer_queue *bufq, + struct mdp3_img_data *data); +int mdp3_ctrl_get_source_format(u32 imgType); +int mdp3_ctrl_get_pack_pattern(u32 imgType); +int mdp3_ctrl_reset(struct msm_fb_data_type *mfd); + +#endif /* MDP3_CTRL_H */ diff --git a/drivers/video/fbdev/msm/mdp3_dma.c b/drivers/video/fbdev/msm/mdp3_dma.c new file mode 100644 index 000000000000..8c36ad65694b --- /dev/null +++ b/drivers/video/fbdev/msm/mdp3_dma.c @@ -0,0 +1,1290 @@ +/* Copyright (c) 2013-2014, 2016-2018, The Linux Foundation. All rights reserved. + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +#include +#include + +#include "mdp3.h" +#include "mdp3_dma.h" +#include "mdp3_hwio.h" +#include "mdss_debug.h" + +#define DMA_STOP_POLL_SLEEP_US 1000 +#define DMA_STOP_POLL_TIMEOUT_US 200000 +#define DMA_HISTO_RESET_TIMEOUT_MS 40 +#define DMA_LUT_CONFIG_MASK 0xfffffbe8 +#define DMA_CCS_CONFIG_MASK 0xfffffc17 +#define HIST_WAIT_TIMEOUT(frame) ((75 * HZ * (frame)) / 1000) + +#define VSYNC_SELECT 0x024 +#define VSYNC_TOTAL_LINES_SHIFT 21 +#define VSYNC_COUNT_MASK 0x7ffff +#define VSYNC_THRESH_CONT_SHIFT 16 + +static void mdp3_vsync_intr_handler(int type, void *arg) +{ + struct mdp3_dma *dma = (struct mdp3_dma *)arg; + struct mdp3_notification vsync_client; + struct mdp3_notification retire_client; + unsigned int wait_for_next_vs; + + pr_debug("%s\n", __func__); + spin_lock(&dma->dma_lock); + vsync_client = dma->vsync_client; + retire_client = dma->retire_client; + wait_for_next_vs = !dma->vsync_status; + dma->vsync_status = 0; + if (wait_for_next_vs) + complete(&dma->vsync_comp); + spin_unlock(&dma->dma_lock); + if (vsync_client.handler) { + vsync_client.handler(vsync_client.arg); + } else { + if (wait_for_next_vs) + mdp3_irq_disable_nosync(type); + } + + if (retire_client.handler) + retire_client.handler(retire_client.arg); +} + +static void mdp3_dma_done_intr_handler(int type, void *arg) +{ + struct mdp3_dma *dma = (struct mdp3_dma *)arg; + struct mdp3_notification dma_client; + + pr_debug("%s\n", __func__); + spin_lock(&dma->dma_lock); + dma_client = dma->dma_notifier_client; + complete(&dma->dma_comp); + spin_unlock(&dma->dma_lock); + mdp3_irq_disable_nosync(type); + if (dma_client.handler) + dma_client.handler(dma_client.arg); +} + +static void mdp3_hist_done_intr_handler(int type, void *arg) +{ + struct mdp3_dma *dma = (struct mdp3_dma *)arg; + u32 isr, mask; + + isr = MDP3_REG_READ(MDP3_REG_DMA_P_HIST_INTR_STATUS); + mask = MDP3_REG_READ(MDP3_REG_DMA_P_HIST_INTR_ENABLE); + MDP3_REG_WRITE(MDP3_REG_DMA_P_HIST_INTR_CLEAR, isr); + + isr &= mask; + if (isr == 0) + return; + + if (isr & MDP3_DMA_P_HIST_INTR_HIST_DONE_BIT) { + spin_lock(&dma->histo_lock); + dma->histo_state = MDP3_DMA_HISTO_STATE_READY; + complete(&dma->histo_comp); + spin_unlock(&dma->histo_lock); + mdp3_hist_intr_notify(dma); + } + if (isr & MDP3_DMA_P_HIST_INTR_RESET_DONE_BIT) { + spin_lock(&dma->histo_lock); + dma->histo_state = MDP3_DMA_HISTO_STATE_IDLE; + complete(&dma->histo_comp); + spin_unlock(&dma->histo_lock); + } +} + +void mdp3_dma_callback_enable(struct mdp3_dma *dma, int type) +{ + int irq_bit; + + pr_debug("%s type=%d\n", __func__, type); + + if (dma->dma_sel == MDP3_DMA_P) { + if (type & MDP3_DMA_CALLBACK_TYPE_HIST_RESET_DONE) + mdp3_irq_enable(MDP3_INTR_DMA_P_HISTO); + + if (type & MDP3_DMA_CALLBACK_TYPE_HIST_DONE) + mdp3_irq_enable(MDP3_INTR_DMA_P_HISTO); + } + + if (dma->output_config.out_sel == MDP3_DMA_OUTPUT_SEL_DSI_VIDEO || + dma->output_config.out_sel == MDP3_DMA_OUTPUT_SEL_LCDC) { + if (type & MDP3_DMA_CALLBACK_TYPE_VSYNC) + mdp3_irq_enable(MDP3_INTR_LCDC_START_OF_FRAME); + } else if (dma->output_config.out_sel == MDP3_DMA_OUTPUT_SEL_DSI_CMD) { + if (type & MDP3_DMA_CALLBACK_TYPE_VSYNC) { + irq_bit = MDP3_INTR_SYNC_PRIMARY_LINE; + irq_bit += dma->dma_sel; + mdp3_irq_enable(irq_bit); + } + + if (type & MDP3_DMA_CALLBACK_TYPE_DMA_DONE) { + irq_bit = MDP3_INTR_DMA_P_DONE; + if (dma->dma_sel == MDP3_DMA_S) + irq_bit = MDP3_INTR_DMA_S_DONE; + mdp3_irq_enable(irq_bit); + } + } else { + pr_err("%s not supported interface\n", __func__); + } +} + +void mdp3_dma_callback_disable(struct mdp3_dma *dma, int type) +{ + int irq_bit; + + pr_debug("%s type=%d\n", __func__, type); + + if (dma->dma_sel == MDP3_DMA_P) { + if (type & MDP3_DMA_CALLBACK_TYPE_HIST_RESET_DONE) + mdp3_irq_disable(MDP3_INTR_DMA_P_HISTO); + + if (type & MDP3_DMA_CALLBACK_TYPE_HIST_DONE) + mdp3_irq_disable(MDP3_INTR_DMA_P_HISTO); + } + + if (dma->output_config.out_sel == MDP3_DMA_OUTPUT_SEL_DSI_VIDEO || + dma->output_config.out_sel == MDP3_DMA_OUTPUT_SEL_LCDC) { + if (type & MDP3_DMA_CALLBACK_TYPE_VSYNC) + mdp3_irq_disable(MDP3_INTR_LCDC_START_OF_FRAME); + } else if (dma->output_config.out_sel == MDP3_DMA_OUTPUT_SEL_DSI_CMD) { + if (type & MDP3_DMA_CALLBACK_TYPE_VSYNC) { + irq_bit = MDP3_INTR_SYNC_PRIMARY_LINE; + irq_bit += dma->dma_sel; + mdp3_irq_disable(irq_bit); + /* + * Clear read pointer interrupt before disabling clocks. + * Else pending ISR handling will result in NOC error + * since the clock will be disable after this point. + */ + mdp3_clear_irq(irq_bit); + } + + if (type & MDP3_DMA_CALLBACK_TYPE_DMA_DONE) { + irq_bit = MDP3_INTR_DMA_P_DONE; + if (dma->dma_sel == MDP3_DMA_S) + irq_bit = MDP3_INTR_DMA_S_DONE; + mdp3_irq_disable(irq_bit); + } + } +} + +static int mdp3_dma_callback_setup(struct mdp3_dma *dma) +{ + int rc = 0; + struct mdp3_intr_cb vsync_cb = { + .cb = mdp3_vsync_intr_handler, + .data = dma, + }; + + struct mdp3_intr_cb dma_cb = { + .cb = mdp3_dma_done_intr_handler, + .data = dma, + }; + + + struct mdp3_intr_cb hist_cb = { + .cb = mdp3_hist_done_intr_handler, + .data = dma, + }; + + if (dma->dma_sel == MDP3_DMA_P) + rc = mdp3_set_intr_callback(MDP3_INTR_DMA_P_HISTO, &hist_cb); + + if (dma->output_config.out_sel == MDP3_DMA_OUTPUT_SEL_DSI_VIDEO || + dma->output_config.out_sel == MDP3_DMA_OUTPUT_SEL_LCDC) + rc |= mdp3_set_intr_callback(MDP3_INTR_LCDC_START_OF_FRAME, + &vsync_cb); + else if (dma->output_config.out_sel == MDP3_DMA_OUTPUT_SEL_DSI_CMD) { + int irq_bit = MDP3_INTR_SYNC_PRIMARY_LINE; + + irq_bit += dma->dma_sel; + rc |= mdp3_set_intr_callback(irq_bit, &vsync_cb); + irq_bit = MDP3_INTR_DMA_P_DONE; + if (dma->dma_sel == MDP3_DMA_S) + irq_bit = MDP3_INTR_DMA_S_DONE; + rc |= mdp3_set_intr_callback(irq_bit, &dma_cb); + } else { + pr_err("%s not supported interface\n", __func__); + rc = -ENODEV; + } + + return rc; +} + +static void mdp3_dma_vsync_enable(struct mdp3_dma *dma, + struct mdp3_notification *vsync_client) +{ + unsigned long flag; + int updated = 0; + int cb_type = MDP3_DMA_CALLBACK_TYPE_VSYNC; + + pr_debug("%s\n", __func__); + + spin_lock_irqsave(&dma->dma_lock, flag); + if (vsync_client) { + if (dma->vsync_client.handler != vsync_client->handler) { + dma->vsync_client = *vsync_client; + updated = 1; + } + } else { + if (dma->vsync_client.handler) { + dma->vsync_client.handler = NULL; + dma->vsync_client.arg = NULL; + updated = 1; + } + } + spin_unlock_irqrestore(&dma->dma_lock, flag); + + if (updated) { + if (vsync_client && vsync_client->handler) + mdp3_dma_callback_enable(dma, cb_type); + else + mdp3_dma_callback_disable(dma, cb_type); + } +} + +static void mdp3_dma_done_notifier(struct mdp3_dma *dma, + struct mdp3_notification *dma_client) +{ + unsigned long flag; + + spin_lock_irqsave(&dma->dma_lock, flag); + if (dma_client) { + dma->dma_notifier_client = *dma_client; + } else { + dma->dma_notifier_client.handler = NULL; + dma->dma_notifier_client.arg = NULL; + } + spin_unlock_irqrestore(&dma->dma_lock, flag); +} + +int mdp3_dma_sync_config(struct mdp3_dma *dma, + struct mdp3_dma_source *source_config, struct mdp3_tear_check *te) +{ + u32 vsync_clk_speed_hz, vclks_line, cfg; + int porch = source_config->vporch; + int height = source_config->height; + int total_lines = height + porch; + int dma_sel = dma->dma_sel; + + vsync_clk_speed_hz = MDP_VSYNC_CLK_RATE; + + cfg = total_lines << VSYNC_TOTAL_LINES_SHIFT; + total_lines *= te->frame_rate; + + vclks_line = (total_lines) ? vsync_clk_speed_hz / total_lines : 0; + + cfg |= BIT(19); + if (te->hw_vsync_mode) + cfg |= BIT(20); + + if (te->refx100) { + vclks_line = vclks_line * te->frame_rate * + 100 / te->refx100; + } else { + pr_warn("refx100 cannot be zero! Use 6000 as default\n"); + vclks_line = vclks_line * te->frame_rate * + 100 / 6000; + } + + cfg |= (vclks_line & VSYNC_COUNT_MASK); + + MDP3_REG_WRITE(MDP3_REG_SYNC_CONFIG_0 + dma_sel, cfg); + MDP3_REG_WRITE(MDP3_REG_VSYNC_SEL, VSYNC_SELECT); + MDP3_REG_WRITE(MDP3_REG_PRIMARY_VSYNC_INIT_VAL + dma_sel, + te->vsync_init_val); + MDP3_REG_WRITE(MDP3_REG_PRIMARY_RD_PTR_IRQ, te->rd_ptr_irq); + MDP3_REG_WRITE(MDP3_REG_SYNC_THRESH_0 + dma_sel, + ((te->sync_threshold_continue << VSYNC_THRESH_CONT_SHIFT) | + te->sync_threshold_start)); + MDP3_REG_WRITE(MDP3_REG_PRIMARY_START_P0S + dma_sel, te->start_pos); + MDP3_REG_WRITE(MDP3_REG_TEAR_CHECK_EN, te->tear_check_en); + return 0; +} + +static int mdp3_dmap_config(struct mdp3_dma *dma, + struct mdp3_dma_source *source_config, + struct mdp3_dma_output_config *output_config, + bool splash_screen_active) +{ + u32 dma_p_cfg_reg, dma_p_size, dma_p_out_xy; + + dma_p_cfg_reg = source_config->format << 25; + if (output_config->dither_en) + dma_p_cfg_reg |= BIT(24); + dma_p_cfg_reg |= output_config->out_sel << 19; + dma_p_cfg_reg |= output_config->bit_mask_polarity << 18; + dma_p_cfg_reg |= output_config->color_components_flip << 14; + dma_p_cfg_reg |= output_config->pack_pattern << 8; + dma_p_cfg_reg |= output_config->pack_align << 7; + dma_p_cfg_reg |= output_config->color_comp_out_bits; + + dma_p_size = source_config->width | (source_config->height << 16); + dma_p_out_xy = source_config->x | (source_config->y << 16); + if (!splash_screen_active) { + MDP3_REG_WRITE(MDP3_REG_DMA_P_CONFIG, dma_p_cfg_reg); + MDP3_REG_WRITE(MDP3_REG_DMA_P_SIZE, dma_p_size); + MDP3_REG_WRITE(MDP3_REG_DMA_P_IBUF_ADDR, + (u32)source_config->buf); + MDP3_REG_WRITE(MDP3_REG_DMA_P_IBUF_Y_STRIDE, + source_config->stride); + MDP3_REG_WRITE(MDP3_REG_DMA_P_OUT_XY, dma_p_out_xy); + MDP3_REG_WRITE(MDP3_REG_DMA_P_FETCH_CFG, 0x40); + } + + dma->source_config = *source_config; + dma->output_config = *output_config; + + if (dma->output_config.out_sel != MDP3_DMA_OUTPUT_SEL_DSI_CMD) + mdp3_irq_enable(MDP3_INTR_LCDC_UNDERFLOW); + + mdp3_dma_callback_setup(dma); + return 0; +} + +static void mdp3_dmap_config_source(struct mdp3_dma *dma) +{ + struct mdp3_dma_source *source_config = &dma->source_config; + u32 dma_p_cfg_reg, dma_p_size; + + dma_p_cfg_reg = MDP3_REG_READ(MDP3_REG_DMA_P_CONFIG); + dma_p_cfg_reg &= ~MDP3_DMA_IBUF_FORMAT_MASK; + dma_p_cfg_reg |= source_config->format << 25; + dma_p_cfg_reg &= ~MDP3_DMA_PACK_PATTERN_MASK; + dma_p_cfg_reg |= dma->output_config.pack_pattern << 8; + + dma_p_size = dma->roi.w | (dma->roi.h << 16); + + MDP3_REG_WRITE(MDP3_REG_DMA_P_CONFIG, dma_p_cfg_reg); + MDP3_REG_WRITE(MDP3_REG_DMA_P_SIZE, dma_p_size); + MDP3_REG_WRITE(MDP3_REG_DMA_P_IBUF_Y_STRIDE, source_config->stride); +} + +static int mdp3_dmas_config(struct mdp3_dma *dma, + struct mdp3_dma_source *source_config, + struct mdp3_dma_output_config *output_config, + bool splash_screen_active) +{ + u32 dma_s_cfg_reg, dma_s_size, dma_s_out_xy; + + dma_s_cfg_reg = source_config->format << 25; + if (output_config->dither_en) + dma_s_cfg_reg |= BIT(24); + dma_s_cfg_reg |= output_config->out_sel << 19; + dma_s_cfg_reg |= output_config->bit_mask_polarity << 18; + dma_s_cfg_reg |= output_config->color_components_flip << 14; + dma_s_cfg_reg |= output_config->pack_pattern << 8; + dma_s_cfg_reg |= output_config->pack_align << 7; + dma_s_cfg_reg |= output_config->color_comp_out_bits; + + dma_s_size = source_config->width | (source_config->height << 16); + dma_s_out_xy = source_config->x | (source_config->y << 16); + + if (!splash_screen_active) { + MDP3_REG_WRITE(MDP3_REG_DMA_S_CONFIG, dma_s_cfg_reg); + MDP3_REG_WRITE(MDP3_REG_DMA_S_SIZE, dma_s_size); + MDP3_REG_WRITE(MDP3_REG_DMA_S_IBUF_ADDR, + (u32)source_config->buf); + MDP3_REG_WRITE(MDP3_REG_DMA_S_IBUF_Y_STRIDE, + source_config->stride); + MDP3_REG_WRITE(MDP3_REG_DMA_S_OUT_XY, dma_s_out_xy); + MDP3_REG_WRITE(MDP3_REG_SECONDARY_RD_PTR_IRQ, 0x10); + } + dma->source_config = *source_config; + dma->output_config = *output_config; + + mdp3_dma_callback_setup(dma); + return 0; +} + +static void mdp3_dmas_config_source(struct mdp3_dma *dma) +{ + struct mdp3_dma_source *source_config = &dma->source_config; + u32 dma_s_cfg_reg, dma_s_size; + + dma_s_cfg_reg = MDP3_REG_READ(MDP3_REG_DMA_S_CONFIG); + dma_s_cfg_reg &= ~MDP3_DMA_IBUF_FORMAT_MASK; + dma_s_cfg_reg |= source_config->format << 25; + + dma_s_size = source_config->width | (source_config->height << 16); + + MDP3_REG_WRITE(MDP3_REG_DMA_S_CONFIG, dma_s_cfg_reg); + MDP3_REG_WRITE(MDP3_REG_DMA_S_SIZE, dma_s_size); + MDP3_REG_WRITE(MDP3_REG_DMA_S_IBUF_Y_STRIDE, source_config->stride); +} + +static int mdp3_dmap_cursor_config(struct mdp3_dma *dma, + struct mdp3_dma_cursor *cursor) +{ + u32 cursor_size, cursor_pos, blend_param, trans_mask; + + cursor_size = cursor->width | (cursor->height << 16); + cursor_pos = cursor->x | (cursor->y << 16); + trans_mask = 0; + if (cursor->blend_config.mode == MDP3_DMA_CURSOR_BLEND_CONSTANT_ALPHA) { + blend_param = cursor->blend_config.constant_alpha << 24; + } else if (cursor->blend_config.mode == + MDP3_DMA_CURSOR_BLEND_COLOR_KEYING) { + blend_param = cursor->blend_config.transparent_color; + trans_mask = cursor->blend_config.transparency_mask; + } else { + blend_param = 0; + } + + MDP3_REG_WRITE(MDP3_REG_DMA_P_CURSOR_FORMAT, cursor->format); + MDP3_REG_WRITE(MDP3_REG_DMA_P_CURSOR_SIZE, cursor_size); + MDP3_REG_WRITE(MDP3_REG_DMA_P_CURSOR_BUF_ADDR, (u32)cursor->buf); + MDP3_REG_WRITE(MDP3_REG_DMA_P_CURSOR_POS, cursor_pos); + MDP3_REG_WRITE(MDP3_REG_DMA_P_CURSOR_BLEND_CONFIG, + cursor->blend_config.mode); + MDP3_REG_WRITE(MDP3_REG_DMA_P_CURSOR_BLEND_PARAM, blend_param); + MDP3_REG_WRITE(MDP3_REG_DMA_P_CURSOR_BLEND_TRANS_MASK, trans_mask); + dma->cursor = *cursor; + return 0; +} + +static int mdp3_dmap_ccs_config_internal(struct mdp3_dma *dma, + struct mdp3_dma_color_correct_config *config, + struct mdp3_dma_ccs *ccs) +{ + int i; + u32 addr; + + if (!ccs) + return -EINVAL; + + if (config->ccs_enable) { + addr = MDP3_REG_DMA_P_CSC_MV1; + if (config->ccs_sel) + addr = MDP3_REG_DMA_P_CSC_MV2; + for (i = 0; i < 9; i++) { + MDP3_REG_WRITE(addr, ccs->mv[i]); + addr += 4; + } + + addr = MDP3_REG_DMA_P_CSC_PRE_BV1; + if (config->pre_bias_sel) + addr = MDP3_REG_DMA_P_CSC_PRE_BV2; + for (i = 0; i < 3; i++) { + MDP3_REG_WRITE(addr, ccs->pre_bv[i]); + addr += 4; + } + + addr = MDP3_REG_DMA_P_CSC_POST_BV1; + if (config->post_bias_sel) + addr = MDP3_REG_DMA_P_CSC_POST_BV2; + for (i = 0; i < 3; i++) { + MDP3_REG_WRITE(addr, ccs->post_bv[i]); + addr += 4; + } + + addr = MDP3_REG_DMA_P_CSC_PRE_LV1; + if (config->pre_limit_sel) + addr = MDP3_REG_DMA_P_CSC_PRE_LV2; + for (i = 0; i < 6; i++) { + MDP3_REG_WRITE(addr, ccs->pre_lv[i]); + addr += 4; + } + + addr = MDP3_REG_DMA_P_CSC_POST_LV1; + if (config->post_limit_sel) + addr = MDP3_REG_DMA_P_CSC_POST_LV2; + for (i = 0; i < 6; i++) { + MDP3_REG_WRITE(addr, ccs->post_lv[i]); + addr += 4; + } + } + return 0; +} + +static void mdp3_ccs_update(struct mdp3_dma *dma, bool from_kickoff) +{ + u32 cc_config; + bool ccs_updated = false, lut_updated = false; + struct mdp3_dma_ccs ccs; + + cc_config = MDP3_REG_READ(MDP3_REG_DMA_P_COLOR_CORRECT_CONFIG); + + if (dma->ccs_config.ccs_dirty) { + cc_config &= DMA_CCS_CONFIG_MASK; + if (dma->ccs_config.ccs_enable) + cc_config |= BIT(3); + else + cc_config &= ~BIT(3); + cc_config |= dma->ccs_config.ccs_sel << 5; + cc_config |= dma->ccs_config.pre_bias_sel << 6; + cc_config |= dma->ccs_config.post_bias_sel << 7; + cc_config |= dma->ccs_config.pre_limit_sel << 8; + cc_config |= dma->ccs_config.post_limit_sel << 9; + /* + * CCS dirty flag should be reset when call is made from frame + * kickoff, or else upon resume the flag would be dirty and LUT + * config could call this function thereby causing no register + * programming for CCS, which will cause screen to go dark + */ + if (from_kickoff) + dma->ccs_config.ccs_dirty = false; + ccs_updated = true; + } + + if (dma->lut_config.lut_dirty) { + cc_config &= DMA_LUT_CONFIG_MASK; + cc_config |= dma->lut_config.lut_enable; + cc_config |= dma->lut_config.lut_position << 4; + cc_config |= dma->lut_config.lut_sel << 10; + dma->lut_config.lut_dirty = false; + lut_updated = true; + } + + if (ccs_updated && from_kickoff) { + ccs.mv = dma->ccs_cache.csc_data.csc_mv; + ccs.pre_bv = dma->ccs_cache.csc_data.csc_pre_bv; + ccs.post_bv = dma->ccs_cache.csc_data.csc_post_bv; + ccs.pre_lv = dma->ccs_cache.csc_data.csc_pre_lv; + ccs.post_lv = dma->ccs_cache.csc_data.csc_post_lv; + mdp3_dmap_ccs_config_internal(dma, &dma->ccs_config, &ccs); + } + + if (lut_updated || ccs_updated) { + MDP3_REG_WRITE(MDP3_REG_DMA_P_COLOR_CORRECT_CONFIG, cc_config); + /* + * Make sure ccs configuration update is done before continuing + * with the DMA transfer + */ + wmb(); /* ensure write is finished before progressing */ + } +} + +static int mdp3_dmap_ccs_config(struct mdp3_dma *dma, + struct mdp3_dma_color_correct_config *config, + struct mdp3_dma_ccs *ccs) +{ + mdp3_dmap_ccs_config_internal(dma, config, ccs); + + dma->ccs_config = *config; + + if (dma->output_config.out_sel != MDP3_DMA_OUTPUT_SEL_DSI_CMD) + mdp3_ccs_update(dma, false); + + return 0; +} + +static int mdp3_dmap_lut_config(struct mdp3_dma *dma, + struct mdp3_dma_lut_config *config, + struct fb_cmap *cmap) +{ + u32 addr, color; + int i; + + if (config->lut_enable && cmap) { + addr = MDP3_REG_DMA_P_CSC_LUT1; + if (config->lut_sel) + addr = MDP3_REG_DMA_P_CSC_LUT2; + + for (i = 0; i < MDP_LUT_SIZE; i++) { + color = cmap->green[i] & 0xff; + color |= (cmap->red[i] & 0xff) << 8; + color |= (cmap->blue[i] & 0xff) << 16; + MDP3_REG_WRITE(addr, color); + addr += 4; + } + } + + dma->lut_config = *config; + + if (dma->output_config.out_sel != MDP3_DMA_OUTPUT_SEL_DSI_CMD) + mdp3_ccs_update(dma, false); + + return 0; +} + +static int mdp3_dmap_histo_config(struct mdp3_dma *dma, + struct mdp3_dma_histogram_config *histo_config) +{ + unsigned long flag; + u32 histo_bit_mask = 0, histo_control = 0; + u32 histo_isr_mask = MDP3_DMA_P_HIST_INTR_HIST_DONE_BIT | + MDP3_DMA_P_HIST_INTR_RESET_DONE_BIT; + + spin_lock_irqsave(&dma->histo_lock, flag); + + if (histo_config->bit_mask_polarity) + histo_bit_mask = BIT(31); + histo_bit_mask |= histo_config->bit_mask; + + if (histo_config->auto_clear_en) + histo_control = BIT(0); + MDP3_REG_WRITE(MDP3_REG_DMA_P_HIST_FRAME_CNT, + histo_config->frame_count); + MDP3_REG_WRITE(MDP3_REG_DMA_P_HIST_BIT_MASK, histo_bit_mask); + MDP3_REG_WRITE(MDP3_REG_DMA_P_HIST_CONTROL, histo_control); + MDP3_REG_WRITE(MDP3_REG_DMA_P_HIST_INTR_ENABLE, histo_isr_mask); + + spin_unlock_irqrestore(&dma->histo_lock, flag); + + dma->histogram_config = *histo_config; + return 0; +} + +int dma_bpp(int format) +{ + int bpp; + + switch (format) { + case MDP3_DMA_IBUF_FORMAT_RGB888: + bpp = 3; + break; + case MDP3_DMA_IBUF_FORMAT_RGB565: + bpp = 2; + break; + case MDP3_DMA_IBUF_FORMAT_XRGB8888: + bpp = 4; + break; + default: + bpp = 0; + } + return bpp; +} + +static int mdp3_dmap_update(struct mdp3_dma *dma, void *buf, + struct mdp3_intf *intf, void *data) +{ + unsigned long flag; + int cb_type = MDP3_DMA_CALLBACK_TYPE_VSYNC; + struct mdss_panel_data *panel; + int rc = 0; + int retry_count = 2; + + ATRACE_BEGIN(__func__); + pr_debug("%s\n", __func__); + + if (dma->output_config.out_sel == MDP3_DMA_OUTPUT_SEL_DSI_CMD) { + cb_type = MDP3_DMA_CALLBACK_TYPE_DMA_DONE; + if (intf->active) { + ATRACE_BEGIN("mdp3_wait_for_dma_comp"); +retry_dma_done: + rc = wait_for_completion_timeout(&dma->dma_comp, + KOFF_TIMEOUT); + if (rc <= 0 && --retry_count) { + int vsync_status; + + vsync_status = (1 << MDP3_INTR_DMA_P_DONE) & + MDP3_REG_READ(MDP3_REG_INTR_STATUS); + if (!vsync_status) { + pr_err("%s: cmd timeout retry cnt %d\n", + __func__, retry_count); + goto retry_dma_done; + } + rc = -1; + } + ATRACE_END("mdp3_wait_for_dma_comp"); + } + } + if (dma->update_src_cfg) { + if (dma->output_config.out_sel == + MDP3_DMA_OUTPUT_SEL_DSI_VIDEO && intf->active) + pr_err("configuring dma source while it is active\n"); + dma->dma_config_source(dma); + if (data) { + panel = (struct mdss_panel_data *)data; + if (panel->event_handler) { + panel->event_handler(panel, + MDSS_EVENT_ENABLE_PARTIAL_ROI, NULL); + panel->event_handler(panel, + MDSS_EVENT_DSI_STREAM_SIZE, NULL); + } + } + dma->update_src_cfg = false; + } + mutex_lock(&dma->pp_lock); + if (dma->ccs_config.ccs_dirty) + mdp3_ccs_update(dma, true); + mutex_unlock(&dma->pp_lock); + spin_lock_irqsave(&dma->dma_lock, flag); + MDP3_REG_WRITE(MDP3_REG_DMA_P_IBUF_ADDR, (u32)(buf + + dma->roi.y * dma->source_config.stride + + dma->roi.x * dma_bpp(dma->source_config.format))); + dma->source_config.buf = (int)buf; + if (dma->output_config.out_sel == MDP3_DMA_OUTPUT_SEL_DSI_CMD) + MDP3_REG_WRITE(MDP3_REG_DMA_P_START, 1); + + if (!intf->active) { + pr_debug("%s start interface\n", __func__); + intf->start(intf); + } + + mb(); /* make sure everything is written before enable */ + dma->vsync_status = MDP3_REG_READ(MDP3_REG_INTR_STATUS) & + (1 << MDP3_INTR_LCDC_START_OF_FRAME); + init_completion(&dma->vsync_comp); + spin_unlock_irqrestore(&dma->dma_lock, flag); + + mdp3_dma_callback_enable(dma, cb_type); + pr_debug("%s wait for vsync_comp\n", __func__); + if (dma->output_config.out_sel == MDP3_DMA_OUTPUT_SEL_DSI_VIDEO) { + ATRACE_BEGIN("mdp3_wait_for_vsync_comp"); +retry_vsync: + rc = wait_for_completion_timeout(&dma->vsync_comp, + KOFF_TIMEOUT); + if (rc <= 0 && --retry_count) { + int vsync = MDP3_REG_READ(MDP3_REG_INTR_STATUS) & + (1 << MDP3_INTR_LCDC_START_OF_FRAME); + + if (!vsync) { + pr_err("%s trying again count = %d\n", + __func__, retry_count); + goto retry_vsync; + } + rc = -1; + } + ATRACE_END("mdp3_wait_for_vsync_comp"); + } + pr_debug("%s wait for vsync_comp out\n", __func__); + ATRACE_END(__func__); + return rc; +} + +static int mdp3_dmas_update(struct mdp3_dma *dma, void *buf, + struct mdp3_intf *intf, void *data) +{ + unsigned long flag; + int cb_type = MDP3_DMA_CALLBACK_TYPE_VSYNC; + + if (dma->output_config.out_sel == MDP3_DMA_OUTPUT_SEL_DSI_CMD) { + cb_type = MDP3_DMA_CALLBACK_TYPE_DMA_DONE; + if (intf->active) + wait_for_completion_killable(&dma->dma_comp); + } + + spin_lock_irqsave(&dma->dma_lock, flag); + MDP3_REG_WRITE(MDP3_REG_DMA_S_IBUF_ADDR, (u32)buf); + dma->source_config.buf = (int)buf; + if (dma->output_config.out_sel == MDP3_DMA_OUTPUT_SEL_DSI_CMD) + MDP3_REG_WRITE(MDP3_REG_DMA_S_START, 1); + + if (!intf->active) { + pr_debug("%s start interface\n", __func__); + intf->start(intf); + } + + wmb(); /* ensure write is finished before progressing */ + init_completion(&dma->vsync_comp); + spin_unlock_irqrestore(&dma->dma_lock, flag); + + mdp3_dma_callback_enable(dma, cb_type); + if (dma->output_config.out_sel == MDP3_DMA_OUTPUT_SEL_DSI_VIDEO) + wait_for_completion_killable(&dma->vsync_comp); + return 0; +} + +static int mdp3_dmap_cursor_update(struct mdp3_dma *dma, int x, int y) +{ + u32 cursor_pos; + + cursor_pos = x | (y << 16); + MDP3_REG_WRITE(MDP3_REG_DMA_P_CURSOR_POS, cursor_pos); + dma->cursor.x = x; + dma->cursor.y = y; + return 0; +} + +static int mdp3_dmap_histo_get(struct mdp3_dma *dma) +{ + int i, state, timeout, ret; + u32 addr; + unsigned long flag; + + spin_lock_irqsave(&dma->histo_lock, flag); + state = dma->histo_state; + spin_unlock_irqrestore(&dma->histo_lock, flag); + + if (state != MDP3_DMA_HISTO_STATE_START && + state != MDP3_DMA_HISTO_STATE_READY) { + pr_err("%s invalid state %d\n", __func__, state); + return -EINVAL; + } + + timeout = HIST_WAIT_TIMEOUT(dma->histogram_config.frame_count); + ret = wait_for_completion_killable_timeout(&dma->histo_comp, timeout); + + if (ret == 0) { + pr_debug("%s time out\n", __func__); + ret = -ETIMEDOUT; + } else if (ret < 0) { + pr_err("%s interrupted\n", __func__); + } + + if (ret < 0) + return ret; + + if (dma->histo_state != MDP3_DMA_HISTO_STATE_READY) { + pr_debug("%s dma shut down\n", __func__); + return -EPERM; + } + + addr = MDP3_REG_DMA_P_HIST_R_DATA; + for (i = 0; i < MDP_HISTOGRAM_BIN_NUM; i++) { + dma->histo_data.r_data[i] = MDP3_REG_READ(addr); + addr += 4; + } + + addr = MDP3_REG_DMA_P_HIST_G_DATA; + for (i = 0; i < MDP_HISTOGRAM_BIN_NUM; i++) { + dma->histo_data.g_data[i] = MDP3_REG_READ(addr); + addr += 4; + } + + addr = MDP3_REG_DMA_P_HIST_B_DATA; + for (i = 0; i < MDP_HISTOGRAM_BIN_NUM; i++) { + dma->histo_data.b_data[i] = MDP3_REG_READ(addr); + addr += 4; + } + + dma->histo_data.extra[0] = + MDP3_REG_READ(MDP3_REG_DMA_P_HIST_EXTRA_INFO_0); + dma->histo_data.extra[1] = + MDP3_REG_READ(MDP3_REG_DMA_P_HIST_EXTRA_INFO_1); + + spin_lock_irqsave(&dma->histo_lock, flag); + init_completion(&dma->histo_comp); + MDP3_REG_WRITE(MDP3_REG_DMA_P_HIST_START, 1); + wmb(); /* ensure write is finished before progressing */ + dma->histo_state = MDP3_DMA_HISTO_STATE_START; + spin_unlock_irqrestore(&dma->histo_lock, flag); + + return 0; +} + +static int mdp3_dmap_histo_start(struct mdp3_dma *dma) +{ + unsigned long flag; + + if (dma->histo_state != MDP3_DMA_HISTO_STATE_IDLE) + return -EINVAL; + + spin_lock_irqsave(&dma->histo_lock, flag); + + init_completion(&dma->histo_comp); + MDP3_REG_WRITE(MDP3_REG_DMA_P_HIST_START, 1); + wmb(); /* ensure write is finished before progressing */ + dma->histo_state = MDP3_DMA_HISTO_STATE_START; + + spin_unlock_irqrestore(&dma->histo_lock, flag); + + mdp3_dma_callback_enable(dma, MDP3_DMA_CALLBACK_TYPE_HIST_DONE); + return 0; + +} + +static int mdp3_dmap_histo_reset(struct mdp3_dma *dma) +{ + unsigned long flag; + int ret; + + spin_lock_irqsave(&dma->histo_lock, flag); + + init_completion(&dma->histo_comp); + + + MDP3_REG_WRITE(MDP3_REG_DMA_P_HIST_INTR_ENABLE, BIT(0)|BIT(1)); + MDP3_REG_WRITE(MDP3_REG_DMA_P_HIST_RESET_SEQ_START, 1); + wmb(); /* ensure write is finished before progressing */ + dma->histo_state = MDP3_DMA_HISTO_STATE_RESET; + + spin_unlock_irqrestore(&dma->histo_lock, flag); + + mdp3_dma_callback_enable(dma, MDP3_DMA_CALLBACK_TYPE_HIST_RESET_DONE); + ret = wait_for_completion_killable_timeout(&dma->histo_comp, + msecs_to_jiffies(DMA_HISTO_RESET_TIMEOUT_MS)); + + if (ret == 0) { + pr_err("%s timed out\n", __func__); + ret = -ETIMEDOUT; + } else if (ret < 0) { + pr_err("%s interrupted\n", __func__); + } else { + ret = 0; + } + mdp3_dma_callback_disable(dma, MDP3_DMA_CALLBACK_TYPE_HIST_RESET_DONE); + + return ret; +} + +static int mdp3_dmap_histo_stop(struct mdp3_dma *dma) +{ + unsigned long flag; + int cb_type = MDP3_DMA_CALLBACK_TYPE_HIST_RESET_DONE | + MDP3_DMA_CALLBACK_TYPE_HIST_DONE; + + spin_lock_irqsave(&dma->histo_lock, flag); + + MDP3_REG_WRITE(MDP3_REG_DMA_P_HIST_CANCEL_REQ, 1); + MDP3_REG_WRITE(MDP3_REG_DMA_P_HIST_INTR_ENABLE, 0); + wmb(); /* ensure write is finished before progressing */ + dma->histo_state = MDP3_DMA_HISTO_STATE_IDLE; + complete(&dma->histo_comp); + + spin_unlock_irqrestore(&dma->histo_lock, flag); + + mdp3_dma_callback_disable(dma, cb_type); + return 0; +} + +static int mdp3_dmap_histo_op(struct mdp3_dma *dma, u32 op) +{ + int ret; + + switch (op) { + case MDP3_DMA_HISTO_OP_START: + ret = mdp3_dmap_histo_start(dma); + break; + case MDP3_DMA_HISTO_OP_STOP: + case MDP3_DMA_HISTO_OP_CANCEL: + ret = mdp3_dmap_histo_stop(dma); + break; + case MDP3_DMA_HISTO_OP_RESET: + ret = mdp3_dmap_histo_reset(dma); + break; + default: + ret = -EINVAL; + } + return ret; +} + +bool mdp3_dmap_busy(void) +{ + u32 val; + + val = MDP3_REG_READ(MDP3_REG_DISPLAY_STATUS); + pr_err("%s DMAP Status %s\n", __func__, + (val & MDP3_DMA_P_BUSY_BIT) ? "BUSY":"IDLE"); + return val & MDP3_DMA_P_BUSY_BIT; +} + +/* + * During underrun DMA_P registers are reset. Reprogramming CSC to prevent + * black screen + */ +static void mdp3_dmap_underrun_worker(struct work_struct *work) +{ + struct mdp3_dma *dma; + + dma = container_of(work, struct mdp3_dma, underrun_work); + mutex_lock(&dma->pp_lock); + if (dma->ccs_config.ccs_enable && dma->ccs_config.ccs_dirty) { + dma->cc_vect_sel = (dma->cc_vect_sel + 1) % 2; + dma->ccs_config.ccs_sel = dma->cc_vect_sel; + dma->ccs_config.pre_limit_sel = dma->cc_vect_sel; + dma->ccs_config.post_limit_sel = dma->cc_vect_sel; + dma->ccs_config.pre_bias_sel = dma->cc_vect_sel; + dma->ccs_config.post_bias_sel = dma->cc_vect_sel; + mdp3_ccs_update(dma, true); + } + mutex_unlock(&dma->pp_lock); +} + +static int mdp3_dma_start(struct mdp3_dma *dma, struct mdp3_intf *intf) +{ + unsigned long flag; + int cb_type = MDP3_DMA_CALLBACK_TYPE_VSYNC; + u32 dma_start_offset = MDP3_REG_DMA_P_START; + + if (dma->dma_sel == MDP3_DMA_P) + dma_start_offset = MDP3_REG_DMA_P_START; + else if (dma->dma_sel == MDP3_DMA_S) + dma_start_offset = MDP3_REG_DMA_S_START; + else + return -EINVAL; + + spin_lock_irqsave(&dma->dma_lock, flag); + if (dma->output_config.out_sel == MDP3_DMA_OUTPUT_SEL_DSI_CMD) { + cb_type |= MDP3_DMA_CALLBACK_TYPE_DMA_DONE; + MDP3_REG_WRITE(dma_start_offset, 1); + } + + intf->start(intf); + wmb(); /* ensure write is finished before progressing */ + init_completion(&dma->vsync_comp); + spin_unlock_irqrestore(&dma->dma_lock, flag); + + if (dma->dma_sel == MDP3_DMA_P && dma->has_panic_ctrl) + MDP3_REG_WRITE(MDP3_PANIC_ROBUST_CTRL, BIT(0)); + + mdp3_dma_callback_enable(dma, cb_type); + pr_debug("%s wait for vsync in\n", __func__); + wait_for_completion_killable(&dma->vsync_comp); + pr_debug("%s wait for vsync out\n", __func__); + return 0; +} + +static int mdp3_dma_stop(struct mdp3_dma *dma, struct mdp3_intf *intf) +{ + int ret = 0; + u32 status, display_status_bit; + + if (dma->dma_sel == MDP3_DMA_P) + display_status_bit = BIT(6); + else if (dma->dma_sel == MDP3_DMA_S) + display_status_bit = BIT(7); + else + return -EINVAL; + + if (dma->dma_sel == MDP3_DMA_P && dma->has_panic_ctrl) + MDP3_REG_WRITE(MDP3_PANIC_ROBUST_CTRL, 0); + + if (dma->output_config.out_sel == MDP3_DMA_OUTPUT_SEL_DSI_VIDEO) + display_status_bit |= BIT(11); + + intf->stop(intf); + ret = readl_poll_timeout((mdp3_res->mdp_base + MDP3_REG_DISPLAY_STATUS), + status, + ((status & display_status_bit) == 0), + DMA_STOP_POLL_SLEEP_US, + DMA_STOP_POLL_TIMEOUT_US); + + mdp3_dma_callback_disable(dma, MDP3_DMA_CALLBACK_TYPE_VSYNC | + MDP3_DMA_CALLBACK_TYPE_DMA_DONE); + mdp3_irq_disable(MDP3_INTR_LCDC_UNDERFLOW); + + MDP3_REG_WRITE(MDP3_REG_INTR_ENABLE, 0); + MDP3_REG_WRITE(MDP3_REG_INTR_CLEAR, 0xfffffff); + + init_completion(&dma->dma_comp); + dma->vsync_client.handler = NULL; + return ret; +} + +int mdp3_dma_init(struct mdp3_dma *dma) +{ + int ret = 0; + + pr_debug("%s\n", __func__); + switch (dma->dma_sel) { + case MDP3_DMA_P: + dma->dma_config = mdp3_dmap_config; + dma->dma_sync_config = mdp3_dma_sync_config; + dma->dma_config_source = mdp3_dmap_config_source; + dma->config_cursor = mdp3_dmap_cursor_config; + dma->config_ccs = mdp3_dmap_ccs_config; + dma->config_histo = mdp3_dmap_histo_config; + dma->config_lut = mdp3_dmap_lut_config; + dma->update = mdp3_dmap_update; + dma->update_cursor = mdp3_dmap_cursor_update; + dma->get_histo = mdp3_dmap_histo_get; + dma->histo_op = mdp3_dmap_histo_op; + dma->vsync_enable = mdp3_dma_vsync_enable; + dma->dma_done_notifier = mdp3_dma_done_notifier; + dma->start = mdp3_dma_start; + dma->stop = mdp3_dma_stop; + dma->busy = mdp3_dmap_busy; + INIT_WORK(&dma->underrun_work, mdp3_dmap_underrun_worker); + break; + case MDP3_DMA_S: + dma->dma_config = mdp3_dmas_config; + dma->dma_sync_config = mdp3_dma_sync_config; + dma->dma_config_source = mdp3_dmas_config_source; + dma->config_cursor = NULL; + dma->config_ccs = NULL; + dma->config_histo = NULL; + dma->config_lut = NULL; + dma->update = mdp3_dmas_update; + dma->update_cursor = NULL; + dma->get_histo = NULL; + dma->histo_op = NULL; + dma->vsync_enable = mdp3_dma_vsync_enable; + dma->start = mdp3_dma_start; + dma->stop = mdp3_dma_stop; + break; + case MDP3_DMA_E: + default: + ret = -ENODEV; + break; + } + + spin_lock_init(&dma->dma_lock); + spin_lock_init(&dma->histo_lock); + init_completion(&dma->vsync_comp); + init_completion(&dma->dma_comp); + init_completion(&dma->histo_comp); + dma->vsync_client.handler = NULL; + dma->vsync_client.arg = NULL; + dma->histo_state = MDP3_DMA_HISTO_STATE_IDLE; + dma->update_src_cfg = false; + + memset(&dma->cursor, 0, sizeof(dma->cursor)); + memset(&dma->ccs_config, 0, sizeof(dma->ccs_config)); + memset(&dma->histogram_config, 0, sizeof(dma->histogram_config)); + + return ret; +} + +int lcdc_config(struct mdp3_intf *intf, struct mdp3_intf_cfg *cfg) +{ + u32 temp; + struct mdp3_video_intf_cfg *v = &cfg->video; + + temp = v->hsync_pulse_width | (v->hsync_period << 16); + MDP3_REG_WRITE(MDP3_REG_LCDC_HSYNC_CTL, temp); + MDP3_REG_WRITE(MDP3_REG_LCDC_VSYNC_PERIOD, v->vsync_period); + MDP3_REG_WRITE(MDP3_REG_LCDC_VSYNC_PULSE_WIDTH, v->vsync_pulse_width); + temp = v->display_start_x | (v->display_end_x << 16); + MDP3_REG_WRITE(MDP3_REG_LCDC_DISPLAY_HCTL, temp); + MDP3_REG_WRITE(MDP3_REG_LCDC_DISPLAY_V_START, v->display_start_y); + MDP3_REG_WRITE(MDP3_REG_LCDC_DISPLAY_V_END, v->display_end_y); + temp = v->active_start_x | (v->active_end_x); + if (v->active_h_enable) + temp |= BIT(31); + MDP3_REG_WRITE(MDP3_REG_LCDC_ACTIVE_HCTL, temp); + MDP3_REG_WRITE(MDP3_REG_LCDC_ACTIVE_V_START, v->active_start_y); + MDP3_REG_WRITE(MDP3_REG_LCDC_ACTIVE_V_END, v->active_end_y); + MDP3_REG_WRITE(MDP3_REG_LCDC_HSYNC_SKEW, v->hsync_skew); + temp = 0; + if (!v->hsync_polarity) + temp = BIT(0); + if (!v->vsync_polarity) + temp = BIT(1); + if (!v->de_polarity) + temp = BIT(2); + MDP3_REG_WRITE(MDP3_REG_LCDC_CTL_POLARITY, temp); + + return 0; +} + +int lcdc_start(struct mdp3_intf *intf) +{ + MDP3_REG_WRITE(MDP3_REG_LCDC_EN, BIT(0)); + wmb(); /* ensure write is finished before progressing */ + intf->active = true; + return 0; +} + +int lcdc_stop(struct mdp3_intf *intf) +{ + MDP3_REG_WRITE(MDP3_REG_LCDC_EN, 0); + wmb(); /* ensure write is finished before progressing */ + intf->active = false; + return 0; +} + +int dsi_video_config(struct mdp3_intf *intf, struct mdp3_intf_cfg *cfg) +{ + u32 temp; + struct mdp3_video_intf_cfg *v = &cfg->video; + + pr_debug("%s\n", __func__); + + temp = v->hsync_pulse_width | (v->hsync_period << 16); + MDP3_REG_WRITE(MDP3_REG_DSI_VIDEO_HSYNC_CTL, temp); + MDP3_REG_WRITE(MDP3_REG_DSI_VIDEO_VSYNC_PERIOD, v->vsync_period); + MDP3_REG_WRITE(MDP3_REG_DSI_VIDEO_VSYNC_PULSE_WIDTH, + v->vsync_pulse_width); + temp = v->display_start_x | (v->display_end_x << 16); + MDP3_REG_WRITE(MDP3_REG_DSI_VIDEO_DISPLAY_HCTL, temp); + MDP3_REG_WRITE(MDP3_REG_DSI_VIDEO_DISPLAY_V_START, v->display_start_y); + MDP3_REG_WRITE(MDP3_REG_DSI_VIDEO_DISPLAY_V_END, v->display_end_y); + temp = v->active_start_x | (v->active_end_x << 16); + if (v->active_h_enable) + temp |= BIT(31); + MDP3_REG_WRITE(MDP3_REG_DSI_VIDEO_ACTIVE_HCTL, temp); + + temp = v->active_start_y; + if (v->active_v_enable) + temp |= BIT(31); + MDP3_REG_WRITE(MDP3_REG_DSI_VIDEO_ACTIVE_V_START, temp); + MDP3_REG_WRITE(MDP3_REG_DSI_VIDEO_ACTIVE_V_END, v->active_end_y); + MDP3_REG_WRITE(MDP3_REG_DSI_VIDEO_HSYNC_SKEW, v->hsync_skew); + temp = 0; + if (!v->hsync_polarity) + temp |= BIT(0); + if (!v->vsync_polarity) + temp |= BIT(1); + if (!v->de_polarity) + temp |= BIT(2); + MDP3_REG_WRITE(MDP3_REG_DSI_VIDEO_CTL_POLARITY, temp); + + v->underflow_color |= 0x80000000; + MDP3_REG_WRITE(MDP3_REG_DSI_VIDEO_UNDERFLOW_CTL, v->underflow_color); + + return 0; +} + +int dsi_video_start(struct mdp3_intf *intf) +{ + pr_debug("%s\n", __func__); + MDP3_REG_WRITE(MDP3_REG_DSI_VIDEO_EN, BIT(0)); + wmb(); /* ensure write is finished before progressing */ + intf->active = true; + return 0; +} + +int dsi_video_stop(struct mdp3_intf *intf) +{ + pr_debug("%s\n", __func__); + MDP3_REG_WRITE(MDP3_REG_DSI_VIDEO_EN, 0); + wmb(); /* ensure write is finished before progressing */ + intf->active = false; + return 0; +} + +int dsi_cmd_config(struct mdp3_intf *intf, struct mdp3_intf_cfg *cfg) +{ + u32 id_map = 0; + u32 trigger_en = 0; + + if (cfg->dsi_cmd.primary_dsi_cmd_id) + id_map = BIT(0); + if (cfg->dsi_cmd.secondary_dsi_cmd_id) + id_map = BIT(4); + + if (cfg->dsi_cmd.dsi_cmd_tg_intf_sel) + trigger_en = BIT(4); + + MDP3_REG_WRITE(MDP3_REG_DSI_CMD_MODE_ID_MAP, id_map); + MDP3_REG_WRITE(MDP3_REG_DSI_CMD_MODE_TRIGGER_EN, trigger_en); + + return 0; +} + +int dsi_cmd_start(struct mdp3_intf *intf) +{ + intf->active = true; + return 0; +} + +int dsi_cmd_stop(struct mdp3_intf *intf) +{ + intf->active = false; + return 0; +} + +int mdp3_intf_init(struct mdp3_intf *intf) +{ + switch (intf->cfg.type) { + case MDP3_DMA_OUTPUT_SEL_LCDC: + intf->config = lcdc_config; + intf->start = lcdc_start; + intf->stop = lcdc_stop; + break; + case MDP3_DMA_OUTPUT_SEL_DSI_VIDEO: + intf->config = dsi_video_config; + intf->start = dsi_video_start; + intf->stop = dsi_video_stop; + break; + case MDP3_DMA_OUTPUT_SEL_DSI_CMD: + intf->config = dsi_cmd_config; + intf->start = dsi_cmd_start; + intf->stop = dsi_cmd_stop; + break; + + default: + return -EINVAL; + } + return 0; +} diff --git a/drivers/video/fbdev/msm/mdp3_dma.h b/drivers/video/fbdev/msm/mdp3_dma.h new file mode 100644 index 000000000000..24caedb931f7 --- /dev/null +++ b/drivers/video/fbdev/msm/mdp3_dma.h @@ -0,0 +1,395 @@ +/* Copyright (c) 2013-2014, 2016-2018, The Linux Foundation. All rights reserved. + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef MDP3_DMA_H +#define MDP3_DMA_H + +#include +#include +#include + +#define MDP_HISTOGRAM_BL_SCALE_MAX 1024 +#define MDP_HISTOGRAM_BL_LEVEL_MAX 255 +#define MDP_HISTOGRAM_FRAME_COUNT_MAX 0x20 +#define MDP_HISTOGRAM_BIT_MASK_MAX 0x4 +#define MDP_HISTOGRAM_CSC_MATRIX_MAX 0x2000 +#define MDP_HISTOGRAM_CSC_VECTOR_MAX 0x200 +#define MDP_HISTOGRAM_BIN_NUM 32 +#define MDP_LUT_SIZE 256 + +enum { + MDP3_DMA_P, + MDP3_DMA_S, + MDP3_DMA_E, + MDP3_DMA_MAX +}; + +enum { + MDP3_DMA_CAP_CURSOR = 0x1, + MDP3_DMA_CAP_COLOR_CORRECTION = 0x2, + MDP3_DMA_CAP_HISTOGRAM = 0x4, + MDP3_DMA_CAP_GAMMA_CORRECTION = 0x8, + MDP3_DMA_CAP_DITHER = 0x10, + MDP3_DMA_CAP_ALL = 0x1F +}; + +enum { + MDP3_DMA_OUTPUT_SEL_AHB, + MDP3_DMA_OUTPUT_SEL_DSI_CMD, + MDP3_DMA_OUTPUT_SEL_LCDC, + MDP3_DMA_OUTPUT_SEL_DSI_VIDEO, + MDP3_DMA_OUTPUT_SEL_MAX +}; + +enum { + MDP3_DMA_IBUF_FORMAT_RGB888, + MDP3_DMA_IBUF_FORMAT_RGB565, + MDP3_DMA_IBUF_FORMAT_XRGB8888, + MDP3_DMA_IBUF_FORMAT_UNDEFINED +}; + +enum { + MDP3_DMA_OUTPUT_PACK_PATTERN_RGB = 0x21, + MDP3_DMA_OUTPUT_PACK_PATTERN_RBG = 0x24, + MDP3_DMA_OUTPUT_PACK_PATTERN_BGR = 0x12, + MDP3_DMA_OUTPUT_PACK_PATTERN_BRG = 0x18, + MDP3_DMA_OUTPUT_PACK_PATTERN_GBR = 0x06, + MDP3_DMA_OUTPUT_PACK_PATTERN_GRB = 0x09, +}; + +enum { + MDP3_DMA_OUTPUT_PACK_ALIGN_LSB, + MDP3_DMA_OUTPUT_PACK_ALIGN_MSB +}; + +enum { + MDP3_DMA_OUTPUT_COMP_BITS_4, /*4 bits per color component*/ + MDP3_DMA_OUTPUT_COMP_BITS_5, + MDP3_DMA_OUTPUT_COMP_BITS_6, + MDP3_DMA_OUTPUT_COMP_BITS_8, +}; + +enum { + MDP3_DMA_CURSOR_FORMAT_ARGB888, +}; + +enum { + MDP3_DMA_COLOR_CORRECT_SET_1, + MDP3_DMA_COLOR_CORRECT_SET_2 +}; + +enum { + MDP3_DMA_LUT_POSITION_PRE, + MDP3_DMA_LUT_POSITION_POST +}; + +enum { + MDP3_DMA_LUT_DISABLE = 0x0, + MDP3_DMA_LUT_ENABLE_C0 = 0x01, + MDP3_DMA_LUT_ENABLE_C1 = 0x02, + MDP3_DMA_LUT_ENABLE_C2 = 0x04, + MDP3_DMA_LUT_ENABLE_ALL = 0x07, +}; + +enum { + MDP3_DMA_HISTOGRAM_BIT_MASK_NONE = 0X0, + MDP3_DMA_HISTOGRAM_BIT_MASK_ONE_MSB = 0x1, + MDP3_DMA_HISTOGRAM_BIT_MASK_TWO_MSB = 0x2, + MDP3_DMA_HISTOGRAM_BIT_MASK_THREE_MSB = 0x3 +}; + +enum { + MDP3_DMA_COLOR_FLIP_NONE, + MDP3_DMA_COLOR_FLIP_COMP1 = 0x1, + MDP3_DMA_COLOR_FLIP_COMP2 = 0x2, + MDP3_DMA_COLOR_FLIP_COMP3 = 0x4, +}; + +enum { + MDP3_DMA_CURSOR_BLEND_NONE = 0x0, + MDP3_DMA_CURSOR_BLEND_PER_PIXEL_ALPHA = 0x3, + MDP3_DMA_CURSOR_BLEND_CONSTANT_ALPHA = 0x5, + MDP3_DMA_CURSOR_BLEND_COLOR_KEYING = 0x9 +}; + +enum { + MDP3_DMA_HISTO_OP_START, + MDP3_DMA_HISTO_OP_STOP, + MDP3_DMA_HISTO_OP_CANCEL, + MDP3_DMA_HISTO_OP_RESET +}; + +enum { + MDP3_DMA_HISTO_STATE_UNKNOWN, + MDP3_DMA_HISTO_STATE_IDLE, + MDP3_DMA_HISTO_STATE_RESET, + MDP3_DMA_HISTO_STATE_START, + MDP3_DMA_HISTO_STATE_READY, +}; + +enum { + MDP3_DMA_CALLBACK_TYPE_VSYNC = 0x01, + MDP3_DMA_CALLBACK_TYPE_DMA_DONE = 0x02, + MDP3_DMA_CALLBACK_TYPE_HIST_RESET_DONE = 0x04, + MDP3_DMA_CALLBACK_TYPE_HIST_DONE = 0x08, +}; + +struct mdp3_dma_source { + u32 format; + int width; + int height; + int x; + int y; + dma_addr_t buf; + int stride; + int vsync_count; + int vporch; +}; + +struct mdp3_dma_output_config { + int dither_en; + u32 out_sel; + u32 bit_mask_polarity; + u32 color_components_flip; + u32 pack_pattern; + u32 pack_align; + u32 color_comp_out_bits; +}; + +struct mdp3_dma_cursor_blend_config { + u32 mode; + u32 transparent_color; /*color keying*/ + u32 transparency_mask; + u32 constant_alpha; +}; + +struct mdp3_dma_cursor { + int enable; /* enable cursor or not*/ + u32 format; + int width; + int height; + int x; + int y; + void *buf; + struct mdp3_dma_cursor_blend_config blend_config; +}; + +struct mdp3_dma_ccs { + u32 *mv; /*set1 matrix vector, 3x3 */ + u32 *pre_bv; /*pre-bias vector for set1, 1x3*/ + u32 *post_bv; /*post-bias vecotr for set1, */ + u32 *pre_lv; /*pre-limit vector for set 1, 1x6*/ + u32 *post_lv; +}; + +struct mdp3_dma_lut_config { + int lut_enable; + u32 lut_sel; + u32 lut_position; + bool lut_dirty; +}; + +struct mdp3_dma_color_correct_config { + int ccs_enable; + u32 post_limit_sel; + u32 pre_limit_sel; + u32 post_bias_sel; + u32 pre_bias_sel; + u32 ccs_sel; + bool ccs_dirty; +}; + +struct mdp3_dma_histogram_config { + int frame_count; + u32 bit_mask_polarity; + u32 bit_mask; + int auto_clear_en; +}; + +struct mdp3_dma_histogram_data { + u32 r_data[MDP_HISTOGRAM_BIN_NUM]; + u32 g_data[MDP_HISTOGRAM_BIN_NUM]; + u32 b_data[MDP_HISTOGRAM_BIN_NUM]; + u32 extra[2]; +}; + +struct mdp3_notification { + void (*handler)(void *arg); + void *arg; +}; + +struct mdp3_tear_check { + int frame_rate; + bool hw_vsync_mode; + u32 tear_check_en; + u32 sync_cfg_height; + u32 vsync_init_val; + u32 sync_threshold_start; + u32 sync_threshold_continue; + u32 start_pos; + u32 rd_ptr_irq; + u32 refx100; +}; + +struct mdp3_rect { + u32 x; + u32 y; + u32 w; + u32 h; +}; + +struct mdp3_intf; + +struct mdp3_dma { + u32 dma_sel; + u32 capability; + int in_use; + int available; + + spinlock_t dma_lock; + spinlock_t histo_lock; + struct completion vsync_comp; + struct completion dma_comp; + struct completion histo_comp; + struct kernfs_node *hist_event_sd; + struct mdp3_notification vsync_client; + struct mdp3_notification dma_notifier_client; + struct mdp3_notification retire_client; + + struct mdp3_dma_output_config output_config; + struct mdp3_dma_source source_config; + + struct mdp3_dma_cursor cursor; + struct mdp3_dma_color_correct_config ccs_config; + struct mdp_csc_cfg_data ccs_cache; + int cc_vect_sel; + + struct work_struct underrun_work; + struct mutex pp_lock; + + struct mdp3_dma_lut_config lut_config; + struct mdp3_dma_histogram_config histogram_config; + int histo_state; + struct mdp3_dma_histogram_data histo_data; + unsigned int vsync_status; + bool update_src_cfg; + bool has_panic_ctrl; + struct mdp3_rect roi; + + u32 lut_sts; + u32 hist_events; + struct fb_cmap *gc_cmap; + struct fb_cmap *hist_cmap; + + bool (*busy)(void); + + int (*dma_config)(struct mdp3_dma *dma, + struct mdp3_dma_source *source_config, + struct mdp3_dma_output_config *output_config, + bool splash_screen_active); + + int (*dma_sync_config)(struct mdp3_dma *dma, struct mdp3_dma_source + *source_config, struct mdp3_tear_check *te); + + void (*dma_config_source)(struct mdp3_dma *dma); + + int (*start)(struct mdp3_dma *dma, struct mdp3_intf *intf); + + int (*stop)(struct mdp3_dma *dma, struct mdp3_intf *intf); + + int (*config_cursor)(struct mdp3_dma *dma, + struct mdp3_dma_cursor *cursor); + + int (*config_ccs)(struct mdp3_dma *dma, + struct mdp3_dma_color_correct_config *config, + struct mdp3_dma_ccs *ccs); + + int (*config_lut)(struct mdp3_dma *dma, + struct mdp3_dma_lut_config *config, + struct fb_cmap *cmap); + + int (*update)(struct mdp3_dma *dma, + void *buf, struct mdp3_intf *intf, void *data); + + int (*update_cursor)(struct mdp3_dma *dma, int x, int y); + + int (*get_histo)(struct mdp3_dma *dma); + + int (*config_histo)(struct mdp3_dma *dma, + struct mdp3_dma_histogram_config *histo_config); + + int (*histo_op)(struct mdp3_dma *dma, u32 op); + + void (*vsync_enable)(struct mdp3_dma *dma, + struct mdp3_notification *vsync_client); + + void (*retire_enable)(struct mdp3_dma *dma, + struct mdp3_notification *retire_client); + + void (*dma_done_notifier)(struct mdp3_dma *dma, + struct mdp3_notification *dma_client); +}; + +struct mdp3_video_intf_cfg { + int hsync_period; + int hsync_pulse_width; + int vsync_period; + int vsync_pulse_width; + int display_start_x; + int display_end_x; + int display_start_y; + int display_end_y; + int active_start_x; + int active_end_x; + int active_h_enable; + int active_start_y; + int active_end_y; + int active_v_enable; + int hsync_skew; + int hsync_polarity; + int vsync_polarity; + int de_polarity; + int underflow_color; +}; + +struct mdp3_dsi_cmd_intf_cfg { + int primary_dsi_cmd_id; + int secondary_dsi_cmd_id; + int dsi_cmd_tg_intf_sel; +}; + +struct mdp3_intf_cfg { + u32 type; + struct mdp3_video_intf_cfg video; + struct mdp3_dsi_cmd_intf_cfg dsi_cmd; +}; + +struct mdp3_intf { + struct mdp3_intf_cfg cfg; + int active; + int available; + int in_use; + int (*config)(struct mdp3_intf *intf, struct mdp3_intf_cfg *cfg); + int (*start)(struct mdp3_intf *intf); + int (*stop)(struct mdp3_intf *intf); +}; + +int mdp3_dma_init(struct mdp3_dma *dma); + +int mdp3_intf_init(struct mdp3_intf *intf); + +void mdp3_dma_callback_enable(struct mdp3_dma *dma, int type); + +void mdp3_dma_callback_disable(struct mdp3_dma *dma, int type); + +void mdp3_hist_intr_notify(struct mdp3_dma *dma); +#endif /* MDP3_DMA_H */ diff --git a/drivers/video/fbdev/msm/mdp3_hwio.h b/drivers/video/fbdev/msm/mdp3_hwio.h new file mode 100644 index 000000000000..2e3d358cd19c --- /dev/null +++ b/drivers/video/fbdev/msm/mdp3_hwio.h @@ -0,0 +1,361 @@ +/* Copyright (c) 2013-2014, 2016, 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef MDP3_HWIO_H +#define MDP3_HWIO_H + +#include + +/*synchronization*/ +#define MDP3_REG_SYNC_CONFIG_0 0x0300 +#define MDP3_REG_SYNC_CONFIG_1 0x0304 +#define MDP3_REG_SYNC_CONFIG_2 0x0308 +#define MDP3_REG_SYNC_STATUS_0 0x030c +#define MDP3_REG_SYNC_STATUS_1 0x0310 +#define MDP3_REG_SYNC_STATUS_2 0x0314 +#define MDP3_REG_PRIMARY_VSYNC_OUT_CTRL 0x0318 +#define MDP3_REG_SECONDARY_VSYNC_OUT_CTRL 0x031c +#define MDP3_REG_EXTERNAL_VSYNC_OUT_CTRL 0x0320 +#define MDP3_REG_VSYNC_SEL 0x0324 +#define MDP3_REG_PRIMARY_VSYNC_INIT_VAL 0x0328 +#define MDP3_REG_SECONDARY_VSYNC_INIT_VAL 0x032c +#define MDP3_REG_EXTERNAL_VSYNC_INIT_VAL 0x0330 +#define MDP3_REG_AUTOREFRESH_CONFIG_P 0x034C +#define MDP3_REG_SYNC_THRESH_0 0x0200 +#define MDP3_REG_SYNC_THRESH_1 0x0204 +#define MDP3_REG_SYNC_THRESH_2 0x0208 +#define MDP3_REG_TEAR_CHECK_EN 0x020C +#define MDP3_REG_PRIMARY_START_P0S 0x0210 +#define MDP3_REG_SECONDARY_START_POS 0x0214 +#define MDP3_REG_EXTERNAL_START_POS 0x0218 + +/*interrupt*/ +#define MDP3_REG_INTR_ENABLE 0x0020 +#define MDP3_REG_INTR_STATUS 0x0024 +#define MDP3_REG_INTR_CLEAR 0x0028 + +#define MDP3_REG_PRIMARY_RD_PTR_IRQ 0x021C +#define MDP3_REG_SECONDARY_RD_PTR_IRQ 0x0220 + +/*operation control*/ +#define MDP3_REG_DMA_P_START 0x0044 +#define MDP3_REG_DMA_S_START 0x0048 +#define MDP3_REG_DMA_E_START 0x004c + +#define MDP3_REG_DISPLAY_STATUS 0x0038 + +#define MDP3_REG_HW_VERSION 0x0070 +#define MDP3_REG_SW_RESET 0x0074 +#define MDP3_REG_SEL_CLK_OR_HCLK_TEST_BUS 0x007C + +/*EBI*/ +#define MDP3_REG_EBI2_LCD0 0x003c +#define MDP3_REG_EBI2_LCD0_YSTRIDE 0x0050 + +/*clock control*/ +#define MDP3_REG_CGC_EN 0x0100 +#define MDP3_VBIF_REG_FORCE_EN 0x0004 + +/* QOS Remapper */ +#define MDP3_DMA_P_QOS_REMAPPER 0x90090 +#define MDP3_DMA_P_WATERMARK_0 0x90094 +#define MDP3_DMA_P_WATERMARK_1 0x90098 +#define MDP3_DMA_P_WATERMARK_2 0x9009C +#define MDP3_PANIC_ROBUST_CTRL 0x900A0 +#define MDP3_PANIC_LUT0 0x900A4 +#define MDP3_PANIC_LUT1 0x900A8 +#define MDP3_ROBUST_LUT 0x900AC + +/*danger safe*/ +#define MDP3_PANIC_ROBUST_CTRL 0x900A0 + +/*DMA_P*/ +#define MDP3_REG_DMA_P_CONFIG 0x90000 +#define MDP3_REG_DMA_P_SIZE 0x90004 +#define MDP3_REG_DMA_P_IBUF_ADDR 0x90008 +#define MDP3_REG_DMA_P_IBUF_Y_STRIDE 0x9000C +#define MDP3_REG_DMA_P_PROFILE_EN 0x90020 +#define MDP3_REG_DMA_P_OUT_XY 0x90010 +#define MDP3_REG_DMA_P_CURSOR_FORMAT 0x90040 +#define MDP3_REG_DMA_P_CURSOR_SIZE 0x90044 +#define MDP3_REG_DMA_P_CURSOR_BUF_ADDR 0x90048 +#define MDP3_REG_DMA_P_CURSOR_POS 0x9004c +#define MDP3_REG_DMA_P_CURSOR_BLEND_CONFIG 0x90060 +#define MDP3_REG_DMA_P_CURSOR_BLEND_PARAM 0x90064 +#define MDP3_REG_DMA_P_CURSOR_BLEND_TRANS_MASK 0x90068 +#define MDP3_REG_DMA_P_COLOR_CORRECT_CONFIG 0x90070 +#define MDP3_REG_DMA_P_CSC_BYPASS 0X93004 +#define MDP3_REG_DMA_P_CSC_MV1 0x93400 +#define MDP3_REG_DMA_P_CSC_MV2 0x93440 +#define MDP3_REG_DMA_P_CSC_PRE_BV1 0x93500 +#define MDP3_REG_DMA_P_CSC_PRE_BV2 0x93540 +#define MDP3_REG_DMA_P_CSC_POST_BV1 0x93580 +#define MDP3_REG_DMA_P_CSC_POST_BV2 0x935c0 +#define MDP3_REG_DMA_P_CSC_PRE_LV1 0x93600 +#define MDP3_REG_DMA_P_CSC_PRE_LV2 0x93640 +#define MDP3_REG_DMA_P_CSC_POST_LV1 0x93680 +#define MDP3_REG_DMA_P_CSC_POST_LV2 0x936c0 +#define MDP3_REG_DMA_P_CSC_LUT1 0x93800 +#define MDP3_REG_DMA_P_CSC_LUT2 0x93c00 +#define MDP3_REG_DMA_P_HIST_START 0x94000 +#define MDP3_REG_DMA_P_HIST_FRAME_CNT 0x94004 +#define MDP3_REG_DMA_P_HIST_BIT_MASK 0x94008 +#define MDP3_REG_DMA_P_HIST_RESET_SEQ_START 0x9400c +#define MDP3_REG_DMA_P_HIST_CONTROL 0x94010 +#define MDP3_REG_DMA_P_HIST_INTR_STATUS 0x94014 +#define MDP3_REG_DMA_P_HIST_INTR_CLEAR 0x94018 +#define MDP3_REG_DMA_P_HIST_INTR_ENABLE 0x9401c +#define MDP3_REG_DMA_P_HIST_STOP_REQ 0x94020 +#define MDP3_REG_DMA_P_HIST_CANCEL_REQ 0x94024 +#define MDP3_REG_DMA_P_HIST_EXTRA_INFO_0 0x94028 +#define MDP3_REG_DMA_P_HIST_EXTRA_INFO_1 0x9402c +#define MDP3_REG_DMA_P_HIST_R_DATA 0x94100 +#define MDP3_REG_DMA_P_HIST_G_DATA 0x94200 +#define MDP3_REG_DMA_P_HIST_B_DATA 0x94300 +#define MDP3_REG_DMA_P_FETCH_CFG 0x90074 +#define MDP3_REG_DMA_P_DCVS_CTRL 0x90080 +#define MDP3_REG_DMA_P_DCVS_STATUS 0x90084 + +/*DMA_S*/ +#define MDP3_REG_DMA_S_CONFIG 0xA0000 +#define MDP3_REG_DMA_S_SIZE 0xA0004 +#define MDP3_REG_DMA_S_IBUF_ADDR 0xA0008 +#define MDP3_REG_DMA_S_IBUF_Y_STRIDE 0xA000C +#define MDP3_REG_DMA_S_OUT_XY 0xA0010 + +/*DMA MASK*/ +#define MDP3_DMA_IBUF_FORMAT_MASK 0x06000000 +#define MDP3_DMA_PACK_PATTERN_MASK 0x00003f00 + +/*MISR*/ +#define MDP3_REG_MODE_CLK 0x000D0000 +#define MDP3_REG_MISR_RESET_CLK 0x000D0004 +#define MDP3_REG_EXPORT_MISR_CLK 0x000D0008 +#define MDP3_REG_MISR_CURR_VAL_CLK 0x000D000C +#define MDP3_REG_MODE_HCLK 0x000D0100 +#define MDP3_REG_MISR_RESET_HCLK 0x000D0104 +#define MDP3_REG_EXPORT_MISR_HCLK 0x000D0108 +#define MDP3_REG_MISR_CURR_VAL_HCLK 0x000D010C +#define MDP3_REG_MODE_DCLK 0x000D0200 +#define MDP3_REG_MISR_RESET_DCLK 0x000D0204 +#define MDP3_REG_EXPORT_MISR_DCLK 0x000D0208 +#define MDP3_REG_MISR_CURR_VAL_DCLK 0x000D020C +#define MDP3_REG_CAPTURED_DCLK 0x000D0210 +#define MDP3_REG_MISR_CAPT_VAL_DCLK 0x000D0214 +#define MDP3_REG_MODE_TVCLK 0x000D0300 +#define MDP3_REG_MISR_RESET_TVCLK 0x000D0304 +#define MDP3_REG_EXPORT_MISR_TVCLK 0x000D0308 +#define MDP3_REG_MISR_CURR_VAL_TVCLK 0x000D030C +#define MDP3_REG_CAPTURED_TVCLK 0x000D0310 +#define MDP3_REG_MISR_CAPT_VAL_TVCLK 0x000D0314 + +/* Select DSI operation type(CMD/VIDEO) */ +#define MDP3_REG_MODE_DSI_PCLK 0x000D0400 +#define MDP3_REG_MODE_DSI_PCLK_BLOCK_DSI_CMD 0x10 +#define MDP3_REG_MODE_DSI_PCLK_BLOCK_DSI_VIDEO1 0x20 +#define MDP3_REG_MODE_DSI_PCLK_BLOCK_DSI_VIDEO2 0x30 +/* RESET DSI MISR STATE */ +#define MDP3_REG_MISR_RESET_DSI_PCLK 0x000D0404 + +/* For reading MISR State(1) and driving data on test bus(0) */ +#define MDP3_REG_EXPORT_MISR_DSI_PCLK 0x000D0408 +/* Read MISR signature */ +#define MDP3_REG_MISR_CURR_VAL_DSI_PCLK 0x000D040C + +/* MISR status Bit0 (1) Capture Done */ +#define MDP3_REG_CAPTURED_DSI_PCLK 0x000D0410 +#define MDP3_REG_MISR_CAPT_VAL_DSI_PCLK 0x000D0414 +#define MDP3_REG_MISR_TESTBUS_CAPT_VAL 0x000D0600 + +/*interface*/ +#define MDP3_REG_LCDC_EN 0xE0000 +#define MDP3_REG_LCDC_HSYNC_CTL 0xE0004 +#define MDP3_REG_LCDC_VSYNC_PERIOD 0xE0008 +#define MDP3_REG_LCDC_VSYNC_PULSE_WIDTH 0xE000C +#define MDP3_REG_LCDC_DISPLAY_HCTL 0xE0010 +#define MDP3_REG_LCDC_DISPLAY_V_START 0xE0014 +#define MDP3_REG_LCDC_DISPLAY_V_END 0xE0018 +#define MDP3_REG_LCDC_ACTIVE_HCTL 0xE001C +#define MDP3_REG_LCDC_ACTIVE_V_START 0xE0020 +#define MDP3_REG_LCDC_ACTIVE_V_END 0xE0024 +#define MDP3_REG_LCDC_BORDER_COLOR 0xE0028 +#define MDP3_REG_LCDC_UNDERFLOW_CTL 0xE002C +#define MDP3_REG_LCDC_HSYNC_SKEW 0xE0030 +#define MDP3_REG_LCDC_TEST_CTL 0xE0034 +#define MDP3_REG_LCDC_CTL_POLARITY 0xE0038 +#define MDP3_REG_LCDC_TEST_COL_VAR1 0xE003C +#define MDP3_REG_LCDC_TEST_COL_VAR2 0xE0040 +#define MDP3_REG_LCDC_UFLOW_HIDING_CTL 0xE0044 +#define MDP3_REG_LCDC_LOST_PIXEL_CNT_VALUE 0xE0048 + +#define MDP3_REG_DSI_VIDEO_EN 0xF0000 +#define MDP3_REG_DSI_VIDEO_HSYNC_CTL 0xF0004 +#define MDP3_REG_DSI_VIDEO_VSYNC_PERIOD 0xF0008 +#define MDP3_REG_DSI_VIDEO_VSYNC_PULSE_WIDTH 0xF000C +#define MDP3_REG_DSI_VIDEO_DISPLAY_HCTL 0xF0010 +#define MDP3_REG_DSI_VIDEO_DISPLAY_V_START 0xF0014 +#define MDP3_REG_DSI_VIDEO_DISPLAY_V_END 0xF0018 +#define MDP3_REG_DSI_VIDEO_ACTIVE_HCTL 0xF001C +#define MDP3_REG_DSI_VIDEO_ACTIVE_V_START 0xF0020 +#define MDP3_REG_DSI_VIDEO_ACTIVE_V_END 0xF0024 +#define MDP3_REG_DSI_VIDEO_BORDER_COLOR 0xF0028 +#define MDP3_REG_DSI_VIDEO_UNDERFLOW_CTL 0xF002C +#define MDP3_REG_DSI_VIDEO_HSYNC_SKEW 0xF0030 +#define MDP3_REG_DSI_VIDEO_TEST_CTL 0xF0034 +#define MDP3_REG_DSI_VIDEO_CTL_POLARITY 0xF0038 +#define MDP3_REG_DSI_VIDEO_TEST_COL_VAR1 0xF003C +#define MDP3_REG_DSI_VIDEO_TEST_COL_VAR2 0xF0040 +#define MDP3_REG_DSI_VIDEO_UFLOW_HIDING_CTL 0xF0044 +#define MDP3_REG_DSI_VIDEO_LOST_PIXEL_CNT_VALUE 0xF0048 + +#define MDP3_REG_DSI_CMD_MODE_ID_MAP 0xF1000 +#define MDP3_REG_DSI_CMD_MODE_TRIGGER_EN 0xF1004 + +#define MDP3_PPP_CSC_PFMVn(n) (0x40400 + (4 * (n))) +#define MDP3_PPP_CSC_PRMVn(n) (0x40440 + (4 * (n))) +#define MDP3_PPP_CSC_PBVn(n) (0x40500 + (4 * (n))) +#define MDP3_PPP_CSC_PLVn(n) (0x40580 + (4 * (n))) + +#define MDP3_PPP_CSC_SFMVn(n) (0x40480 + (4 * (n))) +#define MDP3_PPP_CSC_SRMVn(n) (0x404C0 + (4 * (n))) +#define MDP3_PPP_CSC_SBVn(n) (0x40540 + (4 * (n))) +#define MDP3_PPP_CSC_SLVn(n) (0x405C0 + (4 * (n))) + +#define MDP3_PPP_SCALE_PHASEX_INIT 0x1013C +#define MDP3_PPP_SCALE_PHASEY_INIT 0x10140 +#define MDP3_PPP_SCALE_PHASEX_STEP 0x10144 +#define MDP3_PPP_SCALE_PHASEY_STEP 0x10148 + +#define MDP3_PPP_OP_MODE 0x10138 + +#define MDP3_PPP_PRE_LUT 0x40800 +#define MDP3_PPP_POST_LUT 0x40C00 +#define MDP3_PPP_LUTn(n) ((4 * (n))) + +#define MDP3_PPP_BG_EDGE_REP 0x101BC +#define MDP3_PPP_SRC_EDGE_REP 0x101B8 + +#define MDP3_PPP_STRIDE_MASK 0x3FFF +#define MDP3_PPP_STRIDE1_OFFSET 16 + +#define MDP3_PPP_XY_MASK 0x0FFF +#define MDP3_PPP_XY_OFFSET 16 + +#define MDP3_PPP_SRC_SIZE 0x10108 +#define MDP3_PPP_SRCP0_ADDR 0x1010C +#define MDP3_PPP_SRCP1_ADDR 0x10110 +#define MDP3_PPP_SRCP3_ADDR 0x10118 +#define MDP3_PPP_SRC_YSTRIDE1_ADDR 0x1011C +#define MDP3_PPP_SRC_YSTRIDE2_ADDR 0x10120 +#define MDP3_PPP_SRC_FORMAT 0x10124 +#define MDP3_PPP_SRC_UNPACK_PATTERN1 0x10128 +#define MDP3_PPP_SRC_UNPACK_PATTERN2 0x1012C + +#define MDP3_PPP_OUT_FORMAT 0x10150 +#define MDP3_PPP_OUT_PACK_PATTERN1 0x10154 +#define MDP3_PPP_OUT_PACK_PATTERN2 0x10158 +#define MDP3_PPP_OUT_SIZE 0x10164 +#define MDP3_PPP_OUTP0_ADDR 0x10168 +#define MDP3_PPP_OUTP1_ADDR 0x1016C +#define MDP3_PPP_OUTP3_ADDR 0x10174 +#define MDP3_PPP_OUT_YSTRIDE1_ADDR 0x10178 +#define MDP3_PPP_OUT_YSTRIDE2_ADDR 0x1017C +#define MDP3_PPP_OUT_XY 0x1019C + +#define MDP3_PPP_BGP0_ADDR 0x101C0 +#define MDP3_PPP_BGP1_ADDR 0x101C4 +#define MDP3_PPP_BGP3_ADDR 0x101C8 +#define MDP3_PPP_BG_YSTRIDE1_ADDR 0x101CC +#define MDP3_PPP_BG_YSTRIDE2_ADDR 0x101D0 +#define MDP3_PPP_BG_FORMAT 0x101D4 +#define MDP3_PPP_BG_UNPACK_PATTERN1 0x101D8 +#define MDP3_PPP_BG_UNPACK_PATTERN2 0x101DC + +#define MDP3_TFETCH_SOLID_FILL 0x20004 +#define MDP3_TFETCH_FILL_COLOR 0x20040 + +#define MDP3_PPP_BLEND_PARAM 0x1014C + +#define MDP3_PPP_BLEND_BG_ALPHA_SEL 0x70010 + +#define MDP3_PPP_ACTIVE BIT(0) + +/*interrupt mask*/ + +#define MDP3_INTR_DP0_ROI_DONE_BIT BIT(0) +#define MDP3_INTR_DP1_ROI_DONE_BIT BIT(1) +#define MDP3_INTR_DMA_S_DONE_BIT BIT(2) +#define MDP3_INTR_DMA_E_DONE_BIT BIT(3) +#define MDP3_INTR_DP0_TERMINAL_FRAME_DONE_BIT BIT(4) +#define MDP3_INTR_DP1_TERMINAL_FRAME_DONE_BIT BIT(5) +#define MDP3_INTR_DMA_TV_DONE_BIT BIT(6) +#define MDP3_INTR_TV_ENCODER_UNDER_RUN_BIT BIT(7) +#define MDP3_INTR_SYNC_PRIMARY_LINE_BIT BIT(8) +#define MDP3_INTR_SYNC_SECONDARY_LINE_BIT BIT(9) +#define MDP3_INTR_SYNC_EXTERNAL_LINE_BIT BIT(10) +#define MDP3_INTR_DP0_FETCH_DONE_BIT BIT(11) +#define MDP3_INTR_DP1_FETCH_DONE_BIT BIT(12) +#define MDP3_INTR_TV_OUT_FRAME_START_BIT BIT(13) +#define MDP3_INTR_DMA_P_DONE_BIT BIT(14) +#define MDP3_INTR_LCDC_START_OF_FRAME_BIT BIT(15) +#define MDP3_INTR_LCDC_UNDERFLOW_BIT BIT(16) +#define MDP3_INTR_DMA_P_LINE_BIT BIT(17) +#define MDP3_INTR_DMA_S_LINE_BIT BIT(18) +#define MDP3_INTR_DMA_E_LINE_BIT BIT(19) +#define MDP3_INTR_DMA_P_HISTO_BIT BIT(20) +#define MDP3_INTR_DTV_OUT_DONE_BIT BIT(21) +#define MDP3_INTR_DTV_OUT_START_OF_FRAME_BIT BIT(22) +#define MDP3_INTR_DTV_OUT_UNDERFLOW_BIT BIT(23) +#define MDP3_INTR_DTV_OUT_LINE_BIT BIT(24) +#define MDP3_INTR_DMA_P_AUTO_FREFRESH_START_BIT BIT(25) +#define MDP3_INTR_DMA_S_AUTO_FREFRESH_START_BIT BIT(26) +#define MDP3_INTR_QPIC_EOF_ENABLE_BIT BIT(27) + +enum { + MDP3_INTR_DP0_ROI_DONE, + MDP3_INTR_DP1_ROI_DONE, + MDP3_INTR_DMA_S_DONE, + MDP3_INTR_DMA_E_DONE, + MDP3_INTR_DP0_TERMINAL_FRAME_DONE, + MDP3_INTR_DP1_TERMINAL_FRAME_DONE, + MDP3_INTR_DMA_TV_DONE, + MDP3_INTR_TV_ENCODER_UNDER_RUN, + MDP3_INTR_SYNC_PRIMARY_LINE, + MDP3_INTR_SYNC_SECONDARY_LINE, + MDP3_INTR_SYNC_EXTERNAL_LINE, + MDP3_INTR_DP0_FETCH_DONE, + MDP3_INTR_DP1_FETCH_DONE, + MDP3_INTR_TV_OUT_FRAME_START, + MDP3_INTR_DMA_P_DONE, + MDP3_INTR_LCDC_START_OF_FRAME, + MDP3_INTR_LCDC_UNDERFLOW, + MDP3_INTR_DMA_P_LINE, + MDP3_INTR_DMA_S_LINE, + MDP3_INTR_DMA_E_LINE, + MDP3_INTR_DMA_P_HISTO, + MDP3_INTR_DTV_OUT_DONE, + MDP3_INTR_DTV_OUT_START_OF_FRAME, + MDP3_INTR_DTV_OUT_UNDERFLOW, + MDP3_INTR_DTV_OUT_LINE, + MDP3_INTR_DMA_P_AUTO_FREFRESH_START, + MDP3_INTR_DMA_S_AUTO_FREFRESH_START, + MDP3_INTR_QPIC_EOF_ENABLE, +}; + +#define MDP3_DMA_P_HIST_INTR_RESET_DONE_BIT BIT(0) +#define MDP3_DMA_P_HIST_INTR_HIST_DONE_BIT BIT(1) +#define MDP3_PPP_DONE MDP3_INTR_DP0_ROI_DONE + +#define MDP3_DMA_P_BUSY_BIT BIT(6) + +#endif /* MDP3_HWIO_H */ diff --git a/drivers/video/fbdev/msm/mdp3_layer.c b/drivers/video/fbdev/msm/mdp3_layer.c new file mode 100644 index 000000000000..0078466dc2a4 --- /dev/null +++ b/drivers/video/fbdev/msm/mdp3_layer.c @@ -0,0 +1,348 @@ +/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#define pr_fmt(fmt) "%s: " fmt, __func__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include "mdp3_ctrl.h" +#include "mdp3.h" +#include "mdp3_ppp.h" +#include "mdp3_ctrl.h" +#include "mdss_fb.h" +#include "mdss_sync.h" + +enum { + MDP3_RELEASE_FENCE = 0, + MDP3_RETIRE_FENCE, +}; + +static struct mdss_fence *__mdp3_create_fence(struct msm_fb_data_type *mfd, + struct msm_sync_pt_data *sync_pt_data, u32 fence_type, + int *fence_fd, int value) +{ + struct mdss_fence *sync_fence = NULL; + char fence_name[32]; + struct mdp3_session_data *mdp3_session; + + mdp3_session = (struct mdp3_session_data *)mfd->mdp.private1; + + if (fence_type == MDP3_RETIRE_FENCE) + snprintf(fence_name, sizeof(fence_name), "fb%d_retire", + mfd->index); + else + snprintf(fence_name, sizeof(fence_name), "fb%d_release", + mfd->index); + + if ((fence_type == MDP3_RETIRE_FENCE) && + (mfd->panel.type == MIPI_CMD_PANEL)) { + if (sync_pt_data->timeline_retire) { + value = sync_pt_data->timeline_retire->value + 1 + + mdp3_session->retire_cnt++; + sync_fence = mdss_fb_sync_get_fence( + sync_pt_data->timeline_retire, + fence_name, value); + + } else { + return ERR_PTR(-EPERM); + } + } else { + if (fence_type == MDP3_RETIRE_FENCE) + sync_fence = mdss_fb_sync_get_fence( + sync_pt_data->timeline_retire, + fence_name, value); + else + sync_fence = mdss_fb_sync_get_fence( + sync_pt_data->timeline, + fence_name, value); + } + + if (IS_ERR_OR_NULL(sync_fence)) { + pr_err("%s: unable to retrieve release fence\n", fence_name); + goto end; + } + + *fence_fd = mdss_get_sync_fence_fd(sync_fence); + if (*fence_fd < 0) { + pr_err("%s: get_unused_fd_flags failed error:0x%x\n", + fence_name, *fence_fd); + mdss_put_sync_fence(sync_fence); + sync_fence = NULL; + goto end; + } + pr_debug("%s:val=%d\n", mdss_get_sync_fence_name(sync_fence), value); +end: + return sync_fence; +} + +/* + * __handle_buffer_fences() - copy sync fences and return release + * fence to caller. + * + * This function copies all input sync fences to acquire fence array and + * returns release fences to caller. It acts like buff_sync ioctl. + */ +static int __mdp3_handle_buffer_fences(struct msm_fb_data_type *mfd, + struct mdp_layer_commit_v1 *commit, struct mdp_input_layer *layer_list) +{ + struct mdss_fence *fence, *release_fence, *retire_fence; + struct msm_sync_pt_data *sync_pt_data = NULL; + struct mdp_input_layer *layer; + int value; + + u32 acq_fen_count, i, ret = 0; + u32 layer_count = commit->input_layer_cnt; + + sync_pt_data = &mfd->mdp_sync_pt_data; + if (!sync_pt_data) { + pr_err("sync point data are NULL\n"); + return -EINVAL; + } + + i = mdss_fb_wait_for_fence(sync_pt_data); + if (i > 0) + pr_warn("%s: waited on %d active fences\n", + sync_pt_data->fence_name, i); + + mutex_lock(&sync_pt_data->sync_mutex); + for (i = 0, acq_fen_count = 0; i < layer_count; i++) { + layer = &layer_list[i]; + + if (layer->buffer.fence < 0) + continue; + + fence = mdss_get_fd_sync_fence(layer->buffer.fence); + if (!fence) { + pr_err("%s: sync fence get failed! fd=%d\n", + sync_pt_data->fence_name, layer->buffer.fence); + ret = -EINVAL; + goto sync_fence_err; + } else { + sync_pt_data->acq_fen[acq_fen_count++] = fence; + } + } + + sync_pt_data->acq_fen_cnt = acq_fen_count; + if (ret) + goto sync_fence_err; + + value = sync_pt_data->threshold + + atomic_read(&sync_pt_data->commit_cnt); + + release_fence = __mdp3_create_fence(mfd, sync_pt_data, + MDP3_RELEASE_FENCE, &commit->release_fence, value); + if (IS_ERR_OR_NULL(release_fence)) { + pr_err("unable to retrieve release fence\n"); + ret = PTR_ERR(release_fence); + goto release_fence_err; + } + + retire_fence = __mdp3_create_fence(mfd, sync_pt_data, + MDP3_RETIRE_FENCE, &commit->retire_fence, value); + if (IS_ERR_OR_NULL(retire_fence)) { + pr_err("unable to retrieve retire fence\n"); + ret = PTR_ERR(retire_fence); + goto retire_fence_err; + } + + mutex_unlock(&sync_pt_data->sync_mutex); + return ret; + +retire_fence_err: + put_unused_fd(commit->release_fence); + mdss_put_sync_fence(release_fence); +release_fence_err: + commit->retire_fence = -1; + commit->release_fence = -1; +sync_fence_err: + for (i = 0; i < sync_pt_data->acq_fen_cnt; i++) + mdss_put_sync_fence(sync_pt_data->acq_fen[i]); + sync_pt_data->acq_fen_cnt = 0; + + mutex_unlock(&sync_pt_data->sync_mutex); + + return ret; +} + +/* + * __map_layer_buffer() - map input layer buffer + * + */ +static int __mdp3_map_layer_buffer(struct msm_fb_data_type *mfd, + struct mdp_input_layer *input_layer) +{ + struct mdp3_session_data *mdp3_session = mfd->mdp.private1; + struct mdp3_dma *dma = mdp3_session->dma; + struct mdp_input_layer *layer = NULL; + struct mdp_layer_buffer *buffer; + struct msmfb_data img; + bool is_panel_type_cmd = false; + struct mdp3_img_data data; + int rc = 0; + + layer = &input_layer[0]; + buffer = &layer->buffer; + + /* current implementation only supports one plane mapping */ + if (buffer->planes[0].fd < 0) { + pr_err("invalid file descriptor for layer buffer\n"); + goto err; + } + + memset(&img, 0, sizeof(img)); + img.memory_id = buffer->planes[0].fd; + img.offset = buffer->planes[0].offset; + + memset(&data, 0, sizeof(struct mdp3_img_data)); + + if (mfd->panel.type == MIPI_CMD_PANEL) + is_panel_type_cmd = true; + if (is_panel_type_cmd) { + rc = mdp3_iommu_enable(MDP3_CLIENT_DMA_P); + if (rc) { + pr_err("fail to enable iommu\n"); + return rc; + } + } + + rc = mdp3_get_img(&img, &data, MDP3_CLIENT_DMA_P); + if (rc) { + pr_err("fail to get overlay buffer\n"); + goto err; + } + + if (data.len < dma->source_config.stride * dma->source_config.height) { + pr_err("buf size(0x%lx) is smaller than dma config(0x%x)\n", + data.len, (dma->source_config.stride * + dma->source_config.height)); + mdp3_put_img(&data, MDP3_CLIENT_DMA_P); + rc = -EINVAL; + goto err; + } + + rc = mdp3_bufq_push(&mdp3_session->bufq_in, &data); + if (rc) { + pr_err("fail to queue the overlay buffer, buffer drop\n"); + mdp3_put_img(&data, MDP3_CLIENT_DMA_P); + goto err; + } + rc = 0; +err: + if (is_panel_type_cmd) + mdp3_iommu_disable(MDP3_CLIENT_DMA_P); + return rc; +} + +int mdp3_layer_pre_commit(struct msm_fb_data_type *mfd, + struct file *file, struct mdp_layer_commit_v1 *commit) +{ + int ret; + struct mdp_input_layer *layer, *layer_list; + struct mdp3_session_data *mdp3_session; + struct mdp3_dma *dma; + int layer_count = commit->input_layer_cnt; + int stride, format; + + /* Handle NULL commit */ + if (!layer_count) { + pr_debug("Handle NULL commit\n"); + return 0; + } + + mdp3_session = mfd->mdp.private1; + dma = mdp3_session->dma; + + mutex_lock(&mdp3_session->lock); + + mdp3_bufq_deinit(&mdp3_session->bufq_in); + + layer_list = commit->input_layers; + layer = &layer_list[0]; + + stride = layer->buffer.width * ppp_bpp(layer->buffer.format); + format = mdp3_ctrl_get_source_format(layer->buffer.format); + pr_debug("stride:%d layer_width:%d", stride, layer->buffer.width); + + if ((dma->source_config.format != format) || + (dma->source_config.stride != stride)) { + dma->source_config.format = format; + dma->source_config.stride = stride; + dma->output_config.pack_pattern = + mdp3_ctrl_get_pack_pattern(layer->buffer.format); + dma->update_src_cfg = true; + } + mdp3_session->overlay.id = 1; + + ret = __mdp3_handle_buffer_fences(mfd, commit, layer_list); + if (ret) { + pr_err("Failed to handle buffer fences\n"); + mutex_unlock(&mdp3_session->lock); + return ret; + } + + ret = __mdp3_map_layer_buffer(mfd, layer); + if (ret) { + pr_err("Failed to map buffer\n"); + mutex_unlock(&mdp3_session->lock); + return ret; + } + + pr_debug("mdp3 precommit ret = %d\n", ret); + mutex_unlock(&mdp3_session->lock); + return ret; +} + +/* + * mdp3_layer_atomic_validate() - validate input layers + * @mfd: Framebuffer data structure for display + * @commit: Commit version-1 structure for display + * + * This function validates only input layers received from client. It + * does perform any validation for mdp_output_layer defined for writeback + * display. + */ +int mdp3_layer_atomic_validate(struct msm_fb_data_type *mfd, + struct file *file, struct mdp_layer_commit_v1 *commit) +{ + struct mdp3_session_data *mdp3_session; + + if (!mfd || !commit) { + pr_err("invalid input params\n"); + return -EINVAL; + } + + if (mdss_fb_is_power_off(mfd)) { + pr_err("display interface is in off state fb:%d\n", + mfd->index); + return -EPERM; + } + + mdp3_session = mfd->mdp.private1; + + if (mdp3_session->in_splash_screen) { + mdp3_ctrl_reset(mfd); + mdp3_session->in_splash_screen = 0; + } + + return 0; +} + diff --git a/drivers/video/fbdev/msm/mdp3_ppp.c b/drivers/video/fbdev/msm/mdp3_ppp.c new file mode 100644 index 000000000000..34f08230aa51 --- /dev/null +++ b/drivers/video/fbdev/msm/mdp3_ppp.c @@ -0,0 +1,1721 @@ +/* Copyright (c) 2007, 2013-2014, 2016-2018, The Linux Foundation. All rights reserved. + * Copyright (C) 2007 Google Incorporated + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "linux/proc_fs.h" +#include + +#include "mdss_fb.h" +#include "mdp3_ppp.h" +#include "mdp3_hwio.h" +#include "mdp3.h" +#include "mdss_debug.h" +#include "mdss_sync.h" + +#define MDP_IS_IMGTYPE_BAD(x) ((x) >= MDP_IMGTYPE_LIMIT) +#define MDP_RELEASE_BW_TIMEOUT 50 + +#define MDP_PPP_MAX_BPP 4 +#define MDP_PPP_DYNAMIC_FACTOR 3 +#define MDP_PPP_MAX_READ_WRITE 3 +#define MDP_PPP_MAX_WIDTH 0xFFF +#define ENABLE_SOLID_FILL 0x2 +#define DISABLE_SOLID_FILL 0x0 +#define BLEND_LATENCY 3 +#define CSC_LATENCY 1 + +#define YUV_BW_FUDGE_NUM 10 +#define YUV_BW_FUDGE_DEN 10 + +struct ppp_resource ppp_res; + +static const bool valid_fmt[MDP_IMGTYPE_LIMIT] = { + [MDP_RGB_565] = true, + [MDP_BGR_565] = true, + [MDP_RGB_888] = true, + [MDP_BGR_888] = true, + [MDP_BGRA_8888] = true, + [MDP_RGBA_8888] = true, + [MDP_ARGB_8888] = true, + [MDP_XRGB_8888] = true, + [MDP_RGBX_8888] = true, + [MDP_Y_CRCB_H2V2] = true, + [MDP_Y_CBCR_H2V2] = true, + [MDP_Y_CBCR_H2V2_ADRENO] = true, + [MDP_Y_CBCR_H2V2_VENUS] = true, + [MDP_YCRYCB_H2V1] = true, + [MDP_Y_CBCR_H2V1] = true, + [MDP_Y_CRCB_H2V1] = true, + [MDP_BGRX_8888] = true, +}; + +#define MAX_LIST_WINDOW 16 +#define MDP3_PPP_MAX_LIST_REQ 8 + +struct blit_req_list { + int count; + struct mdp_blit_req req_list[MAX_LIST_WINDOW]; + struct mdp3_img_data src_data[MAX_LIST_WINDOW]; + struct mdp3_img_data dst_data[MAX_LIST_WINDOW]; + struct mdss_fence *acq_fen[MDP_MAX_FENCE_FD]; + u32 acq_fen_cnt; + int cur_rel_fen_fd; + struct sync_pt *cur_rel_sync_pt; + struct mdss_fence *cur_rel_fence; + struct mdss_fence *last_rel_fence; +}; + +struct blit_req_queue { + struct blit_req_list req[MDP3_PPP_MAX_LIST_REQ]; + int count; + int push_idx; + int pop_idx; +}; + +struct ppp_status { + bool wait_for_pop; + struct completion ppp_comp; + struct completion pop_q_comp; + struct mutex req_mutex; /* Protect request queue */ + struct mutex config_ppp_mutex; /* Only one client configure register */ + struct msm_fb_data_type *mfd; + + struct kthread_work blit_work; + struct kthread_worker kworker; + struct task_struct *blit_thread; + struct blit_req_queue req_q; + + struct mdss_timeline *timeline; + + int timeline_value; + + struct timer_list free_bw_timer; + struct work_struct free_bw_work; + bool bw_update; + bool bw_on; + u32 mdp_clk; +}; + +static struct ppp_status *ppp_stat; +static bool is_blit_optimization_possible(struct blit_req_list *req, int indx); + +static inline u64 fudge_factor(u64 val, u32 numer, u32 denom) +{ + u64 result = (val * (u64)numer); + + do_div(result, denom); + return result; +} + +int ppp_get_bpp(uint32_t format, uint32_t fb_format) +{ + int bpp = -EINVAL; + + if (format == MDP_FB_FORMAT) + format = fb_format; + + bpp = ppp_bpp(format); + if (bpp <= 0) + pr_err("%s incorrect format %d\n", __func__, format); + return bpp; +} + +int mdp3_ppp_get_img(struct mdp_img *img, struct mdp_blit_req *req, + struct mdp3_img_data *data) +{ + struct msmfb_data fb_data; + uint32_t stride; + int bpp = ppp_bpp(img->format); + + if (bpp <= 0) { + pr_err("%s incorrect format %d\n", __func__, img->format); + return -EINVAL; + } + + if (img->width > MDP_PPP_MAX_WIDTH) { + pr_err("%s incorrect width %d\n", __func__, img->width); + return -EINVAL; + } + + fb_data.flags = img->priv; + fb_data.memory_id = img->memory_id; + fb_data.offset = 0; + + stride = img->width * bpp; + data->padding = 16 * stride; + + return mdp3_get_img(&fb_data, data, MDP3_CLIENT_PPP); +} + +/* Check format */ +int mdp3_ppp_verify_fmt(struct mdp_blit_req *req) +{ + if (MDP_IS_IMGTYPE_BAD(req->src.format) || + MDP_IS_IMGTYPE_BAD(req->dst.format)) { + pr_err("%s: Color format out of range\n", __func__); + return -EINVAL; + } + + if (!valid_fmt[req->src.format] || + !valid_fmt[req->dst.format]) { + pr_err("%s: Color format not supported\n", __func__); + return -EINVAL; + } + return 0; +} + +/* Check resolution */ +int mdp3_ppp_verify_res(struct mdp_blit_req *req) +{ + if ((req->src.width == 0) || (req->src.height == 0) || + (req->src_rect.w == 0) || (req->src_rect.h == 0) || + (req->dst.width == 0) || (req->dst.height == 0) || + (req->dst_rect.w == 0) || (req->dst_rect.h == 0)) { + pr_err("%s: Height/width can't be 0\n", __func__); + return -EINVAL; + } + + if (((req->src_rect.x + req->src_rect.w) > req->src.width) || + ((req->src_rect.y + req->src_rect.h) > req->src.height)) { + pr_err("%s: src roi larger than boundary\n", __func__); + return -EINVAL; + } + + if (((req->dst_rect.x + req->dst_rect.w) > req->dst.width) || + ((req->dst_rect.y + req->dst_rect.h) > req->dst.height)) { + pr_err("%s: dst roi larger than boundary\n", __func__); + return -EINVAL; + } + return 0; +} + +/* scaling range check */ +int mdp3_ppp_verify_scale(struct mdp_blit_req *req) +{ + u32 src_width, src_height, dst_width, dst_height; + + src_width = req->src_rect.w; + src_height = req->src_rect.h; + + if (req->flags & MDP_ROT_90) { + dst_width = req->dst_rect.h; + dst_height = req->dst_rect.w; + } else { + dst_width = req->dst_rect.w; + dst_height = req->dst_rect.h; + } + + switch (req->dst.format) { + case MDP_Y_CRCB_H2V2: + case MDP_Y_CBCR_H2V2: + src_width = (src_width / 2) * 2; + src_height = (src_height / 2) * 2; + dst_width = (dst_width / 2) * 2; + dst_height = (dst_height / 2) * 2; + break; + + case MDP_Y_CRCB_H2V1: + case MDP_Y_CBCR_H2V1: + case MDP_YCRYCB_H2V1: + src_width = (src_width / 2) * 2; + dst_width = (dst_width / 2) * 2; + break; + + default: + break; + } + + if (((MDP_SCALE_Q_FACTOR * dst_width) / src_width > + MDP_MAX_X_SCALE_FACTOR) + || ((MDP_SCALE_Q_FACTOR * dst_width) / src_width < + MDP_MIN_X_SCALE_FACTOR)) { + pr_err("%s: x req scale factor beyond capability\n", __func__); + return -EINVAL; + } + + if (((MDP_SCALE_Q_FACTOR * dst_height) / src_height > + MDP_MAX_Y_SCALE_FACTOR) + || ((MDP_SCALE_Q_FACTOR * dst_height) / src_height < + MDP_MIN_Y_SCALE_FACTOR)) { + pr_err("%s: y req scale factor beyond capability\n", __func__); + return -EINVAL; + } + return 0; +} + +/* operation check */ +int mdp3_ppp_verify_op(struct mdp_blit_req *req) +{ + /* + * MDP_DEINTERLACE & MDP_SHARPENING Flags are not valid for MDP3 + * so using them together for MDP_SMART_BLIT. + */ + if ((req->flags & MDP_SMART_BLIT) == MDP_SMART_BLIT) + return 0; + if (req->flags & MDP_DEINTERLACE) { + pr_err("\n%s(): deinterlace not supported", __func__); + return -EINVAL; + } + + if (req->flags & MDP_SHARPENING) { + pr_err("\n%s(): sharpening not supported", __func__); + return -EINVAL; + } + return 0; +} + +int mdp3_ppp_verify_req(struct mdp_blit_req *req) +{ + int rc; + + if (req == NULL) { + pr_err("%s: req == null\n", __func__); + return -EINVAL; + } + + rc = mdp3_ppp_verify_fmt(req); + rc |= mdp3_ppp_verify_res(req); + rc |= mdp3_ppp_verify_scale(req); + rc |= mdp3_ppp_verify_op(req); + + return rc; +} + +int mdp3_ppp_pipe_wait(void) +{ + int ret = 1; + + /* + * wait 200 ms for ppp operation to complete before declaring + * the MDP hung + */ + ret = wait_for_completion_timeout( + &ppp_stat->ppp_comp, msecs_to_jiffies(200)); + if (!ret) + pr_err("%s: Timed out waiting for the MDP.\n", + __func__); + + return ret; +} + +uint32_t mdp3_calc_tpval(struct ppp_img_desc *img, uint32_t old_tp) +{ + uint32_t tpVal; + uint8_t plane_tp; + + tpVal = 0; + if ((img->color_fmt == MDP_RGB_565) + || (img->color_fmt == MDP_BGR_565)) { + /* transparent color conversion into 24 bpp */ + plane_tp = (uint8_t) ((old_tp & 0xF800) >> 11); + tpVal |= ((plane_tp << 3) | ((plane_tp & 0x1C) >> 2)) << 16; + plane_tp = (uint8_t) (old_tp & 0x1F); + tpVal |= ((plane_tp << 3) | ((plane_tp & 0x1C) >> 2)) << 8; + + plane_tp = (uint8_t) ((old_tp & 0x7E0) >> 5); + tpVal |= ((plane_tp << 2) | ((plane_tp & 0x30) >> 4)); + } else { + /* 24bit RGB to RBG conversion */ + tpVal = (old_tp & 0xFF00) >> 8; + tpVal |= (old_tp & 0xFF) << 8; + tpVal |= (old_tp & 0xFF0000); + } + + return tpVal; +} + +static void mdp3_ppp_intr_handler(int type, void *arg) +{ + complete(&ppp_stat->ppp_comp); +} + +static int mdp3_ppp_callback_setup(void) +{ + int rc; + struct mdp3_intr_cb ppp_done_cb = { + .cb = mdp3_ppp_intr_handler, + .data = NULL, + }; + + rc = mdp3_set_intr_callback(MDP3_PPP_DONE, &ppp_done_cb); + return rc; +} + +void mdp3_ppp_kickoff(void) +{ + init_completion(&ppp_stat->ppp_comp); + mdp3_irq_enable(MDP3_PPP_DONE); + ppp_enable(); + ATRACE_BEGIN("mdp3_wait_for_ppp_comp"); + mdp3_ppp_pipe_wait(); + ATRACE_END("mdp3_wait_for_ppp_comp"); + mdp3_irq_disable(MDP3_PPP_DONE); +} + +struct bpp_info { + int bpp_num; + int bpp_den; + int bpp_pln; +}; + +int mdp3_get_bpp_info(int format, struct bpp_info *bpp) +{ + int rc = 0; + + switch (format) { + case MDP_RGB_565: + case MDP_BGR_565: + bpp->bpp_num = 2; + bpp->bpp_den = 1; + bpp->bpp_pln = 2; + break; + case MDP_RGB_888: + case MDP_BGR_888: + bpp->bpp_num = 3; + bpp->bpp_den = 1; + bpp->bpp_pln = 3; + break; + case MDP_BGRA_8888: + case MDP_RGBA_8888: + case MDP_ARGB_8888: + case MDP_XRGB_8888: + case MDP_RGBX_8888: + case MDP_BGRX_8888: + bpp->bpp_num = 4; + bpp->bpp_den = 1; + bpp->bpp_pln = 4; + break; + case MDP_Y_CRCB_H2V2: + case MDP_Y_CBCR_H2V2: + case MDP_Y_CBCR_H2V2_ADRENO: + case MDP_Y_CBCR_H2V2_VENUS: + bpp->bpp_num = 3; + bpp->bpp_den = 2; + bpp->bpp_pln = 1; + break; + case MDP_Y_CBCR_H2V1: + case MDP_Y_CRCB_H2V1: + bpp->bpp_num = 2; + bpp->bpp_den = 1; + bpp->bpp_pln = 1; + break; + case MDP_YCRYCB_H2V1: + bpp->bpp_num = 2; + bpp->bpp_den = 1; + bpp->bpp_pln = 2; + break; + default: + rc = -EINVAL; + } + return rc; +} + +bool mdp3_is_blend(struct mdp_blit_req *req) +{ + if ((req->transp_mask != MDP_TRANSP_NOP) || + (req->alpha < MDP_ALPHA_NOP) || + (req->src.format == MDP_ARGB_8888) || + (req->src.format == MDP_BGRA_8888) || + (req->src.format == MDP_RGBA_8888)) + return true; + return false; +} + +bool mdp3_is_scale(struct mdp_blit_req *req) +{ + if (req->flags & MDP_ROT_90) { + if (req->src_rect.w != req->dst_rect.h || + req->src_rect.h != req->dst_rect.w) + return true; + } else { + if (req->src_rect.h != req->dst_rect.h || + req->src_rect.w != req->dst_rect.w) + return true; + } + return false; +} + +u32 mdp3_clk_calc(struct msm_fb_data_type *mfd, + struct blit_req_list *lreq, u32 fps) +{ + int i, lcount = 0; + struct mdp_blit_req *req; + u64 mdp_clk_rate = 0; + u32 scale_x = 0, scale_y = 0, scale = 0; + u32 blend_l, csc_l; + + lcount = lreq->count; + + blend_l = 100 * BLEND_LATENCY; + csc_l = 100 * CSC_LATENCY; + + for (i = 0; i < lcount; i++) { + req = &(lreq->req_list[i]); + + if (req->flags & MDP_SMART_BLIT) + continue; + + if (mdp3_is_scale(req)) { + if (req->flags & MDP_ROT_90) { + scale_x = 100 * req->src_rect.h / + req->dst_rect.w; + scale_y = 100 * req->src_rect.w / + req->dst_rect.h; + } else { + scale_x = 100 * req->src_rect.w / + req->dst_rect.w; + scale_y = 100 * req->src_rect.h / + req->dst_rect.h; + } + scale = max(scale_x, scale_y); + } + scale = scale >= 100 ? scale : 100; + if (mdp3_is_blend(req)) + scale = max(scale, blend_l); + + if (!check_if_rgb(req->src.format)) + scale = max(scale, csc_l); + + mdp_clk_rate += (req->src_rect.w * req->src_rect.h * + scale / 100) * fps; + } + mdp_clk_rate += (ppp_res.solid_fill_pixel * fps); + mdp_clk_rate = fudge_factor(mdp_clk_rate, + CLK_FUDGE_NUM, CLK_FUDGE_DEN); + pr_debug("mdp_clk_rate for ppp = %llu\n", mdp_clk_rate); + mdp_clk_rate = mdp3_clk_round_off(mdp_clk_rate); + + return mdp_clk_rate; +} + +u64 mdp3_adjust_scale_factor(struct mdp_blit_req *req, u32 bw_req, int bpp) +{ + int src_h, src_w; + int dst_h, dst_w; + + src_h = req->src_rect.h; + src_w = req->src_rect.w; + + dst_h = req->dst_rect.h; + dst_w = req->dst_rect.w; + + if ((!(req->flags & MDP_ROT_90) && src_h == dst_h && + src_w == dst_w) || ((req->flags & MDP_ROT_90) && + src_h == dst_w && src_w == dst_h)) + return bw_req; + + bw_req = (bw_req + (bw_req * dst_h) / (4 * src_h)); + bw_req = (bw_req + (bw_req * dst_w) / (4 * src_w) + + (bw_req * dst_w) / (bpp * src_w)); + return bw_req; +} + +int mdp3_calc_ppp_res(struct msm_fb_data_type *mfd, + struct blit_req_list *lreq) +{ + struct mdss_panel_info *panel_info = mfd->panel_info; + int i, lcount = 0; + struct mdp_blit_req *req; + struct bpp_info bpp; + u64 old_solid_fill_pixel = 0; + u64 new_solid_fill_pixel = 0; + u64 src_read_bw = 0; + u32 bg_read_bw = 0; + u32 dst_write_bw = 0; + u64 honest_ppp_ab = 0; + u32 fps = 0; + int smart_blit_fg_indx = -1; + u32 smart_blit_bg_read_bw = 0; + + ATRACE_BEGIN(__func__); + lcount = lreq->count; + if (lcount == 0) { + pr_err("Blit with request count 0, continue to recover!!!\n"); + ATRACE_END(__func__); + return 0; + } + if (lreq->req_list[0].flags & MDP_SOLID_FILL) { + req = &(lreq->req_list[0]); + mdp3_get_bpp_info(req->dst.format, &bpp); + old_solid_fill_pixel = ppp_res.solid_fill_pixel; + new_solid_fill_pixel = req->dst_rect.w * req->dst_rect.h; + ppp_res.solid_fill_pixel += new_solid_fill_pixel; + ppp_res.solid_fill_byte += req->dst_rect.w * req->dst_rect.h * + bpp.bpp_num / bpp.bpp_den; + if ((old_solid_fill_pixel >= new_solid_fill_pixel) || + (mdp3_res->solid_fill_vote_en)) { + pr_debug("Last fill pixels are higher or fill_en %d\n", + mdp3_res->solid_fill_vote_en); + ATRACE_END(__func__); + return 0; + } + } + + for (i = 0; i < lcount; i++) { + /* Set Smart blit flag before BW calculation */ + is_blit_optimization_possible(lreq, i); + req = &(lreq->req_list[i]); + + if (req->fps > 0 && req->fps <= panel_info->mipi.frame_rate) { + if (fps == 0) + fps = req->fps; + else + fps = panel_info->mipi.frame_rate; + } + + mdp3_get_bpp_info(req->src.format, &bpp); + if (lreq->req_list[i].flags & MDP_SMART_BLIT) { + /* + * Flag for smart blit FG layer index + * If blit request at index "n" has + * MDP_SMART_BLIT flag set then it will be used as BG + * layer in smart blit and request at index "n+1" + * will be used as FG layer + */ + smart_blit_fg_indx = i + 1; + bg_read_bw = req->src_rect.w * req->src_rect.h * + bpp.bpp_num / bpp.bpp_den; + bg_read_bw = mdp3_adjust_scale_factor(req, + bg_read_bw, bpp.bpp_pln); + /* Cache read BW of smart blit BG layer */ + smart_blit_bg_read_bw = bg_read_bw; + } else { + src_read_bw = req->src_rect.w * req->src_rect.h * + bpp.bpp_num / bpp.bpp_den; + src_read_bw = mdp3_adjust_scale_factor(req, + src_read_bw, bpp.bpp_pln); + if (!(check_if_rgb(req->src.format))) { + src_read_bw = fudge_factor(src_read_bw, + YUV_BW_FUDGE_NUM, + YUV_BW_FUDGE_DEN); + } + mdp3_get_bpp_info(req->dst.format, &bpp); + + if (smart_blit_fg_indx == i) { + bg_read_bw = smart_blit_bg_read_bw; + smart_blit_fg_indx = -1; + } else { + if ((req->transp_mask != MDP_TRANSP_NOP) || + (req->alpha < MDP_ALPHA_NOP) || + (req->src.format == MDP_ARGB_8888) || + (req->src.format == MDP_BGRA_8888) || + (req->src.format == MDP_RGBA_8888)) { + bg_read_bw = req->dst_rect.w * + req->dst_rect.h * + bpp.bpp_num / bpp.bpp_den; + bg_read_bw = mdp3_adjust_scale_factor( + req, bg_read_bw, + bpp.bpp_pln); + } else { + bg_read_bw = 0; + } + } + dst_write_bw = req->dst_rect.w * req->dst_rect.h * + bpp.bpp_num / bpp.bpp_den; + honest_ppp_ab += (src_read_bw + bg_read_bw + + dst_write_bw); + } + } + + if (fps == 0) + fps = panel_info->mipi.frame_rate; + + if (lreq->req_list[0].flags & MDP_SOLID_FILL) { + honest_ppp_ab = ppp_res.solid_fill_byte * 4; + pr_debug("solid fill honest_ppp_ab %llu\n", honest_ppp_ab); + } else { + honest_ppp_ab += ppp_res.solid_fill_byte; + mdp3_res->solid_fill_vote_en = true; + } + + honest_ppp_ab = honest_ppp_ab * fps; + if (honest_ppp_ab != ppp_res.next_ab) { + ppp_res.next_ab = honest_ppp_ab; + ppp_res.next_ib = honest_ppp_ab; + ppp_stat->bw_update = true; + pr_debug("solid fill ab = %llx, total ab = %llx ", + (ppp_res.solid_fill_byte * fps), honest_ppp_ab); + pr_debug("(%d fps) Solid_fill_vote %d\n", + fps, mdp3_res->solid_fill_vote_en); + ATRACE_INT("mdp3_ppp_bus_quota", honest_ppp_ab); + } + ppp_res.clk_rate = mdp3_clk_calc(mfd, lreq, fps); + ATRACE_INT("mdp3_ppp_clk_rate", ppp_res.clk_rate); + ATRACE_END(__func__); + return 0; +} + +int mdp3_ppp_turnon(struct msm_fb_data_type *mfd, int on_off) +{ + uint64_t ab = 0, ib = 0; + int rate = 0; + int rc; + + if (on_off) { + rate = ppp_res.clk_rate; + ab = ppp_res.next_ab; + ib = ppp_res.next_ib; + } + mdp3_clk_set_rate(MDP3_CLK_MDP_SRC, rate, MDP3_CLIENT_PPP); + rc = mdp3_res_update(on_off, 0, MDP3_CLIENT_PPP); + if (rc < 0) { + pr_err("%s: mdp3_clk_enable failed\n", __func__); + return rc; + } + rc = mdp3_bus_scale_set_quota(MDP3_CLIENT_PPP, ab, ib); + if (rc < 0) { + mdp3_res_update(!on_off, 0, MDP3_CLIENT_PPP); + pr_err("%s: scale_set_quota failed\n", __func__); + return rc; + } + ppp_stat->bw_on = on_off; + ppp_stat->mdp_clk = MDP_CORE_CLK_RATE_SVS; + ppp_stat->bw_update = false; + return 0; +} + +void mdp3_start_ppp(struct ppp_blit_op *blit_op) +{ + /* Wait for the pipe to clear */ + if (MDP3_REG_READ(MDP3_REG_DISPLAY_STATUS) & + MDP3_PPP_ACTIVE) { + pr_err("ppp core is hung up on previous request\n"); + return; + } + config_ppp_op_mode(blit_op); + if (blit_op->solid_fill) { + MDP3_REG_WRITE(0x10138, 0x10000000); + MDP3_REG_WRITE(0x1014c, 0xffffffff); + MDP3_REG_WRITE(0x101b8, 0); + MDP3_REG_WRITE(0x101bc, 0); + MDP3_REG_WRITE(0x1013c, 0); + MDP3_REG_WRITE(0x10140, 0); + MDP3_REG_WRITE(0x10144, 0); + MDP3_REG_WRITE(0x10148, 0); + MDP3_REG_WRITE(MDP3_TFETCH_FILL_COLOR, + blit_op->solid_fill_color); + MDP3_REG_WRITE(MDP3_TFETCH_SOLID_FILL, + ENABLE_SOLID_FILL); + } else { + MDP3_REG_WRITE(MDP3_TFETCH_SOLID_FILL, + DISABLE_SOLID_FILL); + } + /* Skip PPP kickoff for SMART_BLIT BG layer */ + if (blit_op->mdp_op & MDPOP_SMART_BLIT) + pr_debug("Skip mdp3_ppp_kickoff\n"); + else + mdp3_ppp_kickoff(); + + if (!(blit_op->solid_fill)) { + ppp_res.solid_fill_pixel = 0; + ppp_res.solid_fill_byte = 0; + } +} + +static int solid_fill_workaround(struct mdp_blit_req *req, + struct ppp_blit_op *blit_op) +{ + /* Make width 2 when there is a solid fill of width 1, and make + * sure width does not become zero while trying to avoid odd width + */ + if (blit_op->dst.roi.width == 1) { + if (req->dst_rect.x + 2 > req->dst.width) { + pr_err("%s: Unable to handle solid fill of width 1", + __func__); + return -EINVAL; + } + blit_op->dst.roi.width = 2; + } + if (blit_op->src.roi.width == 1) { + if (req->src_rect.x + 2 > req->src.width) { + pr_err("%s: Unable to handle solid fill of width 1", + __func__); + return -EINVAL; + } + blit_op->src.roi.width = 2; + } + + /* Avoid odd width, as it could hang ppp during solid fill */ + blit_op->dst.roi.width = (blit_op->dst.roi.width / 2) * 2; + blit_op->src.roi.width = (blit_op->src.roi.width / 2) * 2; + + /* Set src format to RGBX, to avoid ppp hang issues */ + blit_op->src.color_fmt = MDP_RGBX_8888; + + /* Avoid RGBA format, as it could hang ppp during solid fill */ + if (blit_op->dst.color_fmt == MDP_RGBA_8888) + blit_op->dst.color_fmt = MDP_RGBX_8888; + return 0; +} + +static int mdp3_ppp_process_req(struct ppp_blit_op *blit_op, + struct mdp_blit_req *req, struct mdp3_img_data *src_data, + struct mdp3_img_data *dst_data) +{ + unsigned long srcp0_start, srcp0_len, dst_start, dst_len; + uint32_t dst_width, dst_height; + int ret = 0; + + srcp0_start = (unsigned long) src_data->addr; + srcp0_len = (unsigned long) src_data->len; + dst_start = (unsigned long) dst_data->addr; + dst_len = (unsigned long) dst_data->len; + + blit_op->dst.prop.width = req->dst.width; + blit_op->dst.prop.height = req->dst.height; + + blit_op->dst.color_fmt = req->dst.format; + blit_op->dst.p0 = (void *) dst_start; + blit_op->dst.p0 += req->dst.offset; + + blit_op->dst.roi.x = req->dst_rect.x; + blit_op->dst.roi.y = req->dst_rect.y; + blit_op->dst.roi.width = req->dst_rect.w; + blit_op->dst.roi.height = req->dst_rect.h; + + blit_op->src.roi.x = req->src_rect.x; + blit_op->src.roi.y = req->src_rect.y; + blit_op->src.roi.width = req->src_rect.w; + blit_op->src.roi.height = req->src_rect.h; + + blit_op->src.prop.width = req->src.width; + blit_op->src.prop.height = req->src.height; + blit_op->src.color_fmt = req->src.format; + + + blit_op->src.p0 = (void *) (srcp0_start + req->src.offset); + if (blit_op->src.color_fmt == MDP_Y_CBCR_H2V2_ADRENO) + blit_op->src.p1 = + (void *) ((uint32_t) blit_op->src.p0 + + ALIGN((ALIGN(req->src.width, 32) * + ALIGN(req->src.height, 32)), 4096)); + else if (blit_op->src.color_fmt == MDP_Y_CBCR_H2V2_VENUS) + blit_op->src.p1 = + (void *) ((uint32_t) blit_op->src.p0 + + ALIGN((ALIGN(req->src.width, 128) * + ALIGN(req->src.height, 32)), 4096)); + else + blit_op->src.p1 = (void *) ((uint32_t) blit_op->src.p0 + + req->src.width * req->src.height); + + if (req->flags & MDP_IS_FG) + blit_op->mdp_op |= MDPOP_LAYER_IS_FG; + + /* blending check */ + if (req->transp_mask != MDP_TRANSP_NOP) { + blit_op->mdp_op |= MDPOP_TRANSP; + blit_op->blend.trans_color = + mdp3_calc_tpval(&blit_op->src, req->transp_mask); + } else { + blit_op->blend.trans_color = 0; + } + + req->alpha &= 0xff; + if (req->alpha < MDP_ALPHA_NOP) { + blit_op->mdp_op |= MDPOP_ALPHAB; + blit_op->blend.const_alpha = req->alpha; + } else { + blit_op->blend.const_alpha = 0xff; + } + + /* rotation check */ + if (req->flags & MDP_FLIP_LR) + blit_op->mdp_op |= MDPOP_LR; + if (req->flags & MDP_FLIP_UD) + blit_op->mdp_op |= MDPOP_UD; + if (req->flags & MDP_ROT_90) + blit_op->mdp_op |= MDPOP_ROT90; + if (req->flags & MDP_DITHER) + blit_op->mdp_op |= MDPOP_DITHER; + + if (req->flags & MDP_BLEND_FG_PREMULT) + blit_op->mdp_op |= MDPOP_FG_PM_ALPHA; + + /* scale check */ + if (req->flags & MDP_ROT_90) { + dst_width = req->dst_rect.h; + dst_height = req->dst_rect.w; + } else { + dst_width = req->dst_rect.w; + dst_height = req->dst_rect.h; + } + + if ((blit_op->src.roi.width != dst_width) || + (blit_op->src.roi.height != dst_height)) + blit_op->mdp_op |= MDPOP_ASCALE; + + if (req->flags & MDP_BLUR) + blit_op->mdp_op |= MDPOP_ASCALE | MDPOP_BLUR; + + if (req->flags & MDP_SOLID_FILL) { + ret = solid_fill_workaround(req, blit_op); + if (ret) + return ret; + + blit_op->solid_fill_color = (req->const_color.g & 0xFF)| + (req->const_color.r & 0xFF) << 8 | + (req->const_color.b & 0xFF) << 16 | + (req->const_color.alpha & 0xFF) << 24; + blit_op->solid_fill = true; + } else { + blit_op->solid_fill = false; + } + + if (req->flags & MDP_SMART_BLIT) + blit_op->mdp_op |= MDPOP_SMART_BLIT; + + return ret; +} + +static void mdp3_ppp_tile_workaround(struct ppp_blit_op *blit_op, + struct mdp_blit_req *req) +{ + int dst_h, src_w, i; + uint32_t mdp_op = blit_op->mdp_op; + void *src_p0 = blit_op->src.p0; + void *src_p1 = blit_op->src.p1; + void *dst_p0 = blit_op->dst.p0; + + src_w = req->src_rect.w; + dst_h = blit_op->dst.roi.height; + /* bg tile fetching HW workaround */ + for (i = 0; i < (req->dst_rect.h / 16); i++) { + /* this tile size */ + blit_op->dst.roi.height = 16; + blit_op->src.roi.width = + (16 * req->src_rect.w) / req->dst_rect.h; + + /* if it's out of scale range... */ + if (((MDP_SCALE_Q_FACTOR * blit_op->dst.roi.height) / + blit_op->src.roi.width) > MDP_MAX_X_SCALE_FACTOR) + blit_op->src.roi.width = + (MDP_SCALE_Q_FACTOR * + blit_op->dst.roi.height) / + MDP_MAX_X_SCALE_FACTOR; + else if (((MDP_SCALE_Q_FACTOR * blit_op->dst.roi.height) / + blit_op->src.roi.width) < MDP_MIN_X_SCALE_FACTOR) + blit_op->src.roi.width = + (MDP_SCALE_Q_FACTOR * + blit_op->dst.roi.height) / + MDP_MIN_X_SCALE_FACTOR; + + mdp3_start_ppp(blit_op); + + /* next tile location */ + blit_op->dst.roi.y += 16; + blit_op->src.roi.x += blit_op->src.roi.width; + + /* this is for a remainder update */ + dst_h -= 16; + src_w -= blit_op->src.roi.width; + /* restore parameters that may have been overwritten */ + blit_op->mdp_op = mdp_op; + blit_op->src.p0 = src_p0; + blit_op->src.p1 = src_p1; + blit_op->dst.p0 = dst_p0; + } + + if ((dst_h < 0) || (src_w < 0)) + pr_err("msm_fb: mdp_blt_ex() unexpected result! line:%d\n", + __LINE__); + + /* remainder update */ + if ((dst_h > 0) && (src_w > 0)) { + u32 tmp_v; + + blit_op->dst.roi.height = dst_h; + blit_op->src.roi.width = src_w; + + if (((MDP_SCALE_Q_FACTOR * blit_op->dst.roi.height) / + blit_op->src.roi.width) > MDP_MAX_X_SCALE_FACTOR) { + tmp_v = (MDP_SCALE_Q_FACTOR * + blit_op->dst.roi.height) / + MDP_MAX_X_SCALE_FACTOR + + ((MDP_SCALE_Q_FACTOR * + blit_op->dst.roi.height) % + MDP_MAX_X_SCALE_FACTOR ? 1 : 0); + + /* move x location as roi width gets bigger */ + blit_op->src.roi.x -= tmp_v - blit_op->src.roi.width; + blit_op->src.roi.width = tmp_v; + } else if (((MDP_SCALE_Q_FACTOR * blit_op->dst.roi.height) / + blit_op->src.roi.width) < MDP_MIN_X_SCALE_FACTOR) { + tmp_v = (MDP_SCALE_Q_FACTOR * + blit_op->dst.roi.height) / + MDP_MIN_X_SCALE_FACTOR + + ((MDP_SCALE_Q_FACTOR * + blit_op->dst.roi.height) % + MDP_MIN_X_SCALE_FACTOR ? 1 : 0); + /* + * we don't move x location for continuity of + * source image + */ + blit_op->src.roi.width = tmp_v; + } + + + mdp3_start_ppp(blit_op); + } +} + +static int mdp3_ppp_blit(struct msm_fb_data_type *mfd, + struct mdp_blit_req *req, struct mdp3_img_data *src_data, + struct mdp3_img_data *dst_data) +{ + struct ppp_blit_op blit_op; + int ret = 0; + + memset(&blit_op, 0, sizeof(blit_op)); + + if (req->dst.format == MDP_FB_FORMAT) + req->dst.format = mfd->fb_imgType; + if (req->src.format == MDP_FB_FORMAT) + req->src.format = mfd->fb_imgType; + + if (mdp3_ppp_verify_req(req)) { + pr_err("%s: invalid image!\n", __func__); + return -EINVAL; + } + + ret = mdp3_ppp_process_req(&blit_op, req, src_data, dst_data); + if (ret) { + pr_err("%s: Failed to process the blit request", __func__); + return ret; + } + + if (((blit_op.mdp_op & (MDPOP_TRANSP | MDPOP_ALPHAB)) || + (req->src.format == MDP_ARGB_8888) || + (req->src.format == MDP_BGRA_8888) || + (req->src.format == MDP_RGBA_8888)) && + (blit_op.mdp_op & MDPOP_ROT90) && (req->dst_rect.w <= 16)) { + mdp3_ppp_tile_workaround(&blit_op, req); + } else { + mdp3_start_ppp(&blit_op); + } + + return 0; +} + +static int mdp3_ppp_blit_workaround(struct msm_fb_data_type *mfd, + struct mdp_blit_req *req, unsigned int remainder, + struct mdp3_img_data *src_data, + struct mdp3_img_data *dst_data) +{ + int ret; + struct mdp_blit_req splitreq; + int s_x_0, s_x_1, s_w_0, s_w_1, s_y_0, s_y_1, s_h_0, s_h_1; + int d_x_0, d_x_1, d_w_0, d_w_1, d_y_0, d_y_1, d_h_0, d_h_1; + + /* make new request as provide by user */ + splitreq = *req; + + /* break dest roi at width*/ + d_y_0 = d_y_1 = req->dst_rect.y; + d_h_0 = d_h_1 = req->dst_rect.h; + d_x_0 = req->dst_rect.x; + + if (remainder == 14 || remainder == 6) + d_w_1 = req->dst_rect.w / 2; + else + d_w_1 = (req->dst_rect.w - 1) / 2 - 1; + + d_w_0 = req->dst_rect.w - d_w_1; + d_x_1 = d_x_0 + d_w_0; + /* blit first region */ + if (((splitreq.flags & 0x07) == 0x07) || + ((splitreq.flags & 0x07) == 0x05) || + ((splitreq.flags & 0x07) == 0x02) || + ((splitreq.flags & 0x07) == 0x0)) { + + if (splitreq.flags & MDP_ROT_90) { + s_x_0 = s_x_1 = req->src_rect.x; + s_w_0 = s_w_1 = req->src_rect.w; + s_y_0 = req->src_rect.y; + s_h_1 = (req->src_rect.h * d_w_1) / + req->dst_rect.w; + s_h_0 = req->src_rect.h - s_h_1; + s_y_1 = s_y_0 + s_h_0; + if (d_w_1 >= 8 * s_h_1) { + s_h_1++; + s_y_1--; + } + } else { + s_y_0 = s_y_1 = req->src_rect.y; + s_h_0 = s_h_1 = req->src_rect.h; + s_x_0 = req->src_rect.x; + s_w_1 = (req->src_rect.w * d_w_1) / + req->dst_rect.w; + s_w_0 = req->src_rect.w - s_w_1; + s_x_1 = s_x_0 + s_w_0; + if (d_w_1 >= 8 * s_w_1) { + s_w_1++; + s_x_1--; + } + } + + splitreq.src_rect.h = s_h_0; + splitreq.src_rect.y = s_y_0; + splitreq.dst_rect.h = d_h_0; + splitreq.dst_rect.y = d_y_0; + splitreq.src_rect.x = s_x_0; + splitreq.src_rect.w = s_w_0; + splitreq.dst_rect.x = d_x_0; + splitreq.dst_rect.w = d_w_0; + } else { + if (splitreq.flags & MDP_ROT_90) { + s_x_0 = s_x_1 = req->src_rect.x; + s_w_0 = s_w_1 = req->src_rect.w; + s_y_0 = req->src_rect.y; + s_h_1 = (req->src_rect.h * d_w_0) / + req->dst_rect.w; + s_h_0 = req->src_rect.h - s_h_1; + s_y_1 = s_y_0 + s_h_0; + if (d_w_0 >= 8 * s_h_1) { + s_h_1++; + s_y_1--; + } + } else { + s_y_0 = s_y_1 = req->src_rect.y; + s_h_0 = s_h_1 = req->src_rect.h; + s_x_0 = req->src_rect.x; + s_w_1 = (req->src_rect.w * d_w_0) / + req->dst_rect.w; + s_w_0 = req->src_rect.w - s_w_1; + s_x_1 = s_x_0 + s_w_0; + if (d_w_0 >= 8 * s_w_1) { + s_w_1++; + s_x_1--; + } + } + splitreq.src_rect.h = s_h_0; + splitreq.src_rect.y = s_y_0; + splitreq.dst_rect.h = d_h_1; + splitreq.dst_rect.y = d_y_1; + splitreq.src_rect.x = s_x_0; + splitreq.src_rect.w = s_w_0; + splitreq.dst_rect.x = d_x_1; + splitreq.dst_rect.w = d_w_1; + } + + /* No need to split in height */ + ret = mdp3_ppp_blit(mfd, &splitreq, src_data, dst_data); + + if (ret) + return ret; + /* blit second region */ + if (((splitreq.flags & 0x07) == 0x07) || + ((splitreq.flags & 0x07) == 0x05) || + ((splitreq.flags & 0x07) == 0x02) || + ((splitreq.flags & 0x07) == 0x0)) { + splitreq.src_rect.h = s_h_1; + splitreq.src_rect.y = s_y_1; + splitreq.dst_rect.h = d_h_1; + splitreq.dst_rect.y = d_y_1; + splitreq.src_rect.x = s_x_1; + splitreq.src_rect.w = s_w_1; + splitreq.dst_rect.x = d_x_1; + splitreq.dst_rect.w = d_w_1; + } else { + splitreq.src_rect.h = s_h_1; + splitreq.src_rect.y = s_y_1; + splitreq.dst_rect.h = d_h_0; + splitreq.dst_rect.y = d_y_0; + splitreq.src_rect.x = s_x_1; + splitreq.src_rect.w = s_w_1; + splitreq.dst_rect.x = d_x_0; + splitreq.dst_rect.w = d_w_0; + } + + /* No need to split in height ... just width */ + return mdp3_ppp_blit(mfd, &splitreq, src_data, dst_data); +} + +int mdp3_ppp_start_blit(struct msm_fb_data_type *mfd, + struct mdp_blit_req *req, + struct mdp3_img_data *src_data, + struct mdp3_img_data *dst_data) +{ + int ret; + unsigned int remainder = 0, is_bpp_4 = 0; + + if (unlikely(req->src_rect.h == 0 || req->src_rect.w == 0)) { + pr_err("mdp_ppp: src img of zero size!\n"); + return -EINVAL; + } + if (unlikely(req->dst_rect.h == 0 || req->dst_rect.w == 0)) + return 0; + + /* MDP width split workaround */ + remainder = (req->dst_rect.w) % 16; + ret = ppp_get_bpp(req->dst.format, mfd->fb_imgType); + if (ret <= 0) { + pr_err("mdp_ppp: incorrect bpp!\n"); + return -EINVAL; + } + is_bpp_4 = (ret == 4) ? 1 : 0; + + if ((is_bpp_4 && (remainder == 6 || remainder == 14)) && + !(req->flags & MDP_SOLID_FILL)) + ret = mdp3_ppp_blit_workaround(mfd, req, remainder, + src_data, dst_data); + else + ret = mdp3_ppp_blit(mfd, req, src_data, dst_data); + return ret; +} + +void mdp3_ppp_wait_for_fence(struct blit_req_list *req) +{ + int i, ret = 0; + + ATRACE_BEGIN(__func__); + /* buf sync */ + for (i = 0; i < req->acq_fen_cnt; i++) { + ret = mdss_wait_sync_fence(req->acq_fen[i], + WAIT_FENCE_FINAL_TIMEOUT); + if (ret < 0) { + pr_err("%s: sync_fence_wait failed! ret = %x\n", + __func__, ret); + break; + } + mdss_put_sync_fence(req->acq_fen[i]); + } + ATRACE_END(__func__); + if (ret < 0) { + while (i < req->acq_fen_cnt) { + mdss_put_sync_fence(req->acq_fen[i]); + i++; + } + } + req->acq_fen_cnt = 0; +} + +void mdp3_ppp_signal_timeline(struct blit_req_list *req) +{ + mdss_inc_timeline(ppp_stat->timeline, 1); + MDSS_XLOG(ppp_stat->timeline->value, ppp_stat->timeline_value); + req->last_rel_fence = req->cur_rel_fence; + req->cur_rel_fence = 0; +} + + +static void mdp3_ppp_deinit_buf_sync(struct blit_req_list *req) +{ + int i; + + put_unused_fd(req->cur_rel_fen_fd); + mdss_put_sync_fence(req->cur_rel_fence); + req->cur_rel_fence = NULL; + req->cur_rel_fen_fd = 0; + ppp_stat->timeline_value--; + for (i = 0; i < req->acq_fen_cnt; i++) + mdss_put_sync_fence(req->acq_fen[i]); + req->acq_fen_cnt = 0; +} + +static int mdp3_ppp_handle_buf_sync(struct blit_req_list *req, + struct mdp_buf_sync *buf_sync) +{ + int i, fence_cnt = 0, ret = 0; + int acq_fen_fd[MDP_MAX_FENCE_FD]; + struct mdss_fence *fence; + + if ((buf_sync->acq_fen_fd_cnt > MDP_MAX_FENCE_FD) || + (ppp_stat->timeline == NULL)) + return -EINVAL; + + if (buf_sync->acq_fen_fd_cnt) + ret = copy_from_user(acq_fen_fd, buf_sync->acq_fen_fd, + buf_sync->acq_fen_fd_cnt * sizeof(int)); + if (ret) { + pr_err("%s: copy_from_user failed\n", __func__); + return ret; + } + for (i = 0; i < buf_sync->acq_fen_fd_cnt; i++) { + fence = mdss_get_fd_sync_fence(acq_fen_fd[i]); + if (fence == NULL) { + pr_info("%s: null fence! i=%d fd=%d\n", __func__, i, + acq_fen_fd[i]); + ret = -EINVAL; + break; + } + req->acq_fen[i] = fence; + } + fence_cnt = i; + if (ret) + goto buf_sync_err_1; + req->acq_fen_cnt = fence_cnt; + if (buf_sync->flags & MDP_BUF_SYNC_FLAG_WAIT) + mdp3_ppp_wait_for_fence(req); + + MDSS_XLOG(ppp_stat->timeline_value); + + /* create fence */ + req->cur_rel_fence = mdss_get_sync_fence(ppp_stat->timeline, + "ppp_fence", NULL, ppp_stat->timeline_value++); + if (req->cur_rel_fence == NULL) { + req->cur_rel_sync_pt = NULL; + pr_err("%s: cannot create fence\n", __func__); + ret = -ENOMEM; + goto buf_sync_err_2; + } + /* create fd */ + return ret; +buf_sync_err_2: + ppp_stat->timeline_value--; +buf_sync_err_1: + for (i = 0; i < fence_cnt; i++) + mdss_put_sync_fence(req->acq_fen[i]); + req->acq_fen_cnt = 0; + return ret; +} + +void mdp3_ppp_req_push(struct blit_req_queue *req_q, struct blit_req_list *req) +{ + int idx = req_q->push_idx; + + req_q->req[idx] = *req; + req_q->count++; + req_q->push_idx = (req_q->push_idx + 1) % MDP3_PPP_MAX_LIST_REQ; +} + +struct blit_req_list *mdp3_ppp_next_req(struct blit_req_queue *req_q) +{ + struct blit_req_list *req; + + if (req_q->count == 0) + return NULL; + req = &req_q->req[req_q->pop_idx]; + return req; +} + +void mdp3_ppp_req_pop(struct blit_req_queue *req_q) +{ + req_q->count--; + req_q->pop_idx = (req_q->pop_idx + 1) % MDP3_PPP_MAX_LIST_REQ; +} + +void mdp3_free_fw_timer_func(unsigned long arg) +{ + mdp3_res->solid_fill_vote_en = false; + schedule_work(&ppp_stat->free_bw_work); +} + +static void mdp3_free_bw_wq_handler(struct work_struct *work) +{ + struct msm_fb_data_type *mfd = ppp_stat->mfd; + + mutex_lock(&ppp_stat->config_ppp_mutex); + if (ppp_stat->bw_on) + mdp3_ppp_turnon(mfd, 0); + mutex_unlock(&ppp_stat->config_ppp_mutex); +} + +static bool is_hw_workaround_needed(struct mdp_blit_req req) +{ + bool result = false; + bool is_bpp_4 = false; + uint32_t remainder = 0; + uint32_t bpp = ppp_get_bpp(req.dst.format, ppp_stat->mfd->fb_imgType); + + /* MDP width split workaround */ + remainder = (req.dst_rect.w) % 16; + is_bpp_4 = (bpp == 4) ? 1 : 0; + if ((is_bpp_4 && (remainder == 6 || remainder == 14)) && + !(req.flags & MDP_SOLID_FILL)) + result = true; + + /* bg tile fetching HW workaround */ + if (((req.alpha < MDP_ALPHA_NOP) || + (req.transp_mask != MDP_TRANSP_NOP) || + (req.src.format == MDP_ARGB_8888) || + (req.src.format == MDP_BGRA_8888) || + (req.src.format == MDP_RGBA_8888)) && + (req.flags & MDP_ROT_90) && (req.dst_rect.w <= 16)) + result = true; + + return result; +} + +static bool is_roi_equal(struct mdp_blit_req req0, + struct mdp_blit_req req1) +{ + bool result = false; + struct mdss_panel_info *panel_info = ppp_stat->mfd->panel_info; + + /* + * Check req0 and req1 layer destination ROI and return true if + * they are equal. + */ + if ((req0.dst_rect.x == req1.dst_rect.x) && + (req0.dst_rect.y == req1.dst_rect.y) && + (req0.dst_rect.w == req1.dst_rect.w) && + (req0.dst_rect.h == req1.dst_rect.h)) + result = true; + /* + * Layers are source cropped and cropped layer width and hight are + * same panel width and height + */ + else if ((req0.dst_rect.w == req1.dst_rect.w) && + (req0.dst_rect.h == req1.dst_rect.h) && + (req0.dst_rect.w == panel_info->xres) && + (req0.dst_rect.h == panel_info->yres)) + result = true; + + return result; +} + +static bool is_scaling_needed(struct mdp_blit_req req) +{ + bool result = true; + + /* Return true if layer need scaling else return false */ + if ((req.src_rect.w == req.dst_rect.w) && + (req.src_rect.h == req.dst_rect.h)) + result = false; + return result; +} + +static bool is_blit_optimization_possible(struct blit_req_list *req, int indx) +{ + int next = indx + 1; + bool status = false; + struct mdp3_img_data tmp_data; + bool dst_roi_equal = false; + bool hw_woraround_active = false; + struct mdp_blit_req bg_req; + struct mdp_blit_req fg_req; + + if (!(mdp3_res->smart_blit_en)) { + pr_debug("Smart BLIT disabled from sysfs\n"); + return status; + } + if (next < req->count) { + bg_req = req->req_list[indx]; + fg_req = req->req_list[next]; + hw_woraround_active = is_hw_workaround_needed(bg_req); + dst_roi_equal = is_roi_equal(bg_req, fg_req); + /* + * Check userspace Smart BLIT Flag for current and next + * request Flag for smart blit FG layer index If blit + * request at index "n" has MDP_SMART_BLIT flag set then + * it will be used as BG layer in smart blit + * and request at index "n+1" will be used as FG layer + */ + if ((bg_req.flags & MDP_SMART_BLIT) && + (!(fg_req.flags & MDP_SMART_BLIT)) && + (!(hw_woraround_active))) + status = true; + /* + * Enable SMART blit between request 0(BG) & request 1(FG) when + * destination ROI of BG and FG layer are same, + * No scaling on BG layer + * No rotation on BG Layer. + * BG Layer color format is RGB and marked as MDP_IS_FG. + */ + else if ((mdp3_res->smart_blit_en & SMART_BLIT_RGB_EN) && + (indx == 0) && (dst_roi_equal) && + (bg_req.flags & MDP_IS_FG) && + (!(is_scaling_needed(bg_req))) && + (!(bg_req.flags & (MDP_ROT_90))) && + (check_if_rgb(bg_req.src.format)) && + (!(hw_woraround_active))) { + status = true; + req->req_list[indx].flags |= MDP_SMART_BLIT; + pr_debug("Optimize RGB Blit for Req Indx %d\n", indx); + } + /* + * Swap BG and FG layer to enable SMART blit between request + * 0(BG) & request 1(FG) when destination ROI of BG and FG + * layer are same, No scaling on FG and BG layer + * No rotation on FG Layer. BG Layer color format is YUV + */ + else if ((indx == 0) && + (mdp3_res->smart_blit_en & SMART_BLIT_YUV_EN) && + (!(fg_req.flags & (MDP_ROT_90))) && (dst_roi_equal) && + (!(check_if_rgb(bg_req.src.format))) && + (!(hw_woraround_active))) { + /* + * swap blit requests at index 0 and 1. YUV layer at + * index 0 is replaced with UI layer request present + * at index 1. Since UI layer will be in background + * set IS_FG flag and clear it from YUV layer flags + */ + if (!(is_scaling_needed(req->req_list[next]))) { + if (bg_req.flags & MDP_IS_FG) { + req->req_list[indx].flags &= + ~MDP_IS_FG; + req->req_list[next].flags |= MDP_IS_FG; + } + bg_req = req->req_list[next]; + req->req_list[next] = req->req_list[indx]; + req->req_list[indx] = bg_req; + + tmp_data = req->src_data[next]; + req->src_data[next] = req->src_data[indx]; + req->src_data[indx] = tmp_data; + + tmp_data = req->dst_data[next]; + req->dst_data[next] = req->dst_data[indx]; + req->dst_data[indx] = tmp_data; + status = true; + req->req_list[indx].flags |= MDP_SMART_BLIT; + pr_debug("Optimize YUV Blit for Req Indx %d\n", + indx); + } + } + } + return status; +} + +static void mdp3_ppp_blit_handler(struct kthread_work *work) +{ + struct msm_fb_data_type *mfd = ppp_stat->mfd; + struct blit_req_list *req; + int i, rc = 0; + bool smart_blit = false; + int smart_blit_fg_index = -1; + + mutex_lock(&ppp_stat->config_ppp_mutex); + req = mdp3_ppp_next_req(&ppp_stat->req_q); + if (!req) { + mutex_unlock(&ppp_stat->config_ppp_mutex); + return; + } + + if (!ppp_stat->bw_on) { + mdp3_ppp_turnon(mfd, 1); + if (rc < 0) { + mutex_unlock(&ppp_stat->config_ppp_mutex); + pr_err("%s: Enable ppp resources failed\n", __func__); + return; + } + } + while (req) { + mdp3_ppp_wait_for_fence(req); + mdp3_calc_ppp_res(mfd, req); + if (ppp_res.clk_rate != ppp_stat->mdp_clk) { + ppp_stat->mdp_clk = ppp_res.clk_rate; + mdp3_clk_set_rate(MDP3_CLK_MDP_SRC, + ppp_stat->mdp_clk, MDP3_CLIENT_PPP); + } + if (ppp_stat->bw_update) { + rc = mdp3_bus_scale_set_quota(MDP3_CLIENT_PPP, + ppp_res.next_ab, ppp_res.next_ib); + if (rc < 0) { + pr_err("%s: bw set quota failed\n", __func__); + return; + } + ppp_stat->bw_update = false; + } + ATRACE_BEGIN("mpd3_ppp_start"); + for (i = 0; i < req->count; i++) { + smart_blit = is_blit_optimization_possible(req, i); + if (smart_blit) + /* + * Blit request index of FG layer in + * smart blit + */ + smart_blit_fg_index = i + 1; + if (!(req->req_list[i].flags & MDP_NO_BLIT)) { + /* Do the actual blit. */ + if (!rc) { + rc = mdp3_ppp_start_blit(mfd, + &(req->req_list[i]), + &req->src_data[i], + &req->dst_data[i]); + } + /* Unmap blit source buffer */ + if (smart_blit == false) { + mdp3_put_img(&req->src_data[i], + MDP3_CLIENT_PPP); + } + if (smart_blit_fg_index == i) { + /* Unmap smart blit BG buffer */ + mdp3_put_img(&req->src_data[i - 1], + MDP3_CLIENT_PPP); + smart_blit_fg_index = -1; + } + mdp3_put_img(&req->dst_data[i], + MDP3_CLIENT_PPP); + smart_blit = false; + } + } + ATRACE_END("mdp3_ppp_start"); + /* Signal to release fence */ + mutex_lock(&ppp_stat->req_mutex); + mdp3_ppp_signal_timeline(req); + mdp3_ppp_req_pop(&ppp_stat->req_q); + req = mdp3_ppp_next_req(&ppp_stat->req_q); + if (ppp_stat->wait_for_pop) + complete(&ppp_stat->pop_q_comp); + mutex_unlock(&ppp_stat->req_mutex); + } + mod_timer(&ppp_stat->free_bw_timer, jiffies + + msecs_to_jiffies(MDP_RELEASE_BW_TIMEOUT)); + mutex_unlock(&ppp_stat->config_ppp_mutex); +} + +int mdp3_ppp_parse_req(void __user *p, + struct mdp_async_blit_req_list *req_list_header, + int async) +{ + struct blit_req_list *req; + struct blit_req_queue *req_q = &ppp_stat->req_q; + struct mdss_fence *fence = NULL; + int count, rc, idx, i; + + count = req_list_header->count; + + mutex_lock(&ppp_stat->req_mutex); + while (req_q->count >= MDP3_PPP_MAX_LIST_REQ) { + ppp_stat->wait_for_pop = true; + mutex_unlock(&ppp_stat->req_mutex); + rc = wait_for_completion_timeout( + &ppp_stat->pop_q_comp, 5 * HZ); + if (rc == 0) { + /* This will only occur if there is serious problem */ + pr_err("%s: timeout exiting queuing request\n", + __func__); + return -EBUSY; + } + mutex_lock(&ppp_stat->req_mutex); + ppp_stat->wait_for_pop = false; + } + idx = req_q->push_idx; + req = &req_q->req[idx]; + + if (copy_from_user(&req->req_list, p, + sizeof(struct mdp_blit_req) * count)) { + mutex_unlock(&ppp_stat->req_mutex); + return -EFAULT; + } + + rc = mdp3_ppp_handle_buf_sync(req, &req_list_header->sync); + if (rc < 0) { + pr_err("%s: Failed create sync point\n", __func__); + mutex_unlock(&ppp_stat->req_mutex); + return rc; + } + req->count = count; + + /* We need to grab ion handle while running in client thread */ + for (i = 0; i < count; i++) { + rc = mdp3_ppp_get_img(&req->req_list[i].src, + &req->req_list[i], &req->src_data[i]); + if (rc < 0 || req->src_data[i].len == 0) { + pr_err("mdp_ppp: couldn't retrieve src img from mem\n"); + goto parse_err_1; + } + + rc = mdp3_ppp_get_img(&req->req_list[i].dst, + &req->req_list[i], &req->dst_data[i]); + if (rc < 0 || req->dst_data[i].len == 0) { + mdp3_put_img(&req->src_data[i], MDP3_CLIENT_PPP); + pr_err("mdp_ppp: couldn't retrieve dest img from mem\n"); + goto parse_err_1; + } + } + + if (async) { + req->cur_rel_fen_fd = mdss_get_sync_fence_fd( + req->cur_rel_fence); + rc = copy_to_user(req_list_header->sync.rel_fen_fd, + &req->cur_rel_fen_fd, sizeof(int)); + if (rc) { + pr_err("%s:copy_to_user failed\n", __func__); + goto parse_err_2; + } + } else { + fence = req->cur_rel_fence; + } + + mdp3_ppp_req_push(req_q, req); + mutex_unlock(&ppp_stat->req_mutex); + kthread_queue_work(&ppp_stat->kworker, &ppp_stat->blit_work); + if (!async) { + /* wait for release fence */ + rc = mdss_wait_sync_fence(fence, + 5 * MSEC_PER_SEC); + if (rc < 0) + pr_err("%s: sync blit! rc = %x\n", __func__, rc); + + mdss_put_sync_fence(fence); + fence = NULL; + } + return 0; + +parse_err_2: + put_unused_fd(req->cur_rel_fen_fd); +parse_err_1: + for (i--; i >= 0; i--) { + mdp3_put_img(&req->src_data[i], MDP3_CLIENT_PPP); + mdp3_put_img(&req->dst_data[i], MDP3_CLIENT_PPP); + } + mdp3_ppp_deinit_buf_sync(req); + mutex_unlock(&ppp_stat->req_mutex); + return rc; +} + +int mdp3_ppp_res_init(struct msm_fb_data_type *mfd) +{ + int rc; + struct sched_param param = {.sched_priority = 16}; + const char timeline_name[] = "mdp3_ppp"; + + ppp_stat = kzalloc(sizeof(struct ppp_status), GFP_KERNEL); + if (!ppp_stat) + return -ENOMEM; + + /*Setup sync_pt timeline for ppp*/ + ppp_stat->timeline = mdss_create_timeline(timeline_name); + if (ppp_stat->timeline == NULL) { + pr_err("%s: cannot create time line\n", __func__); + return -ENOMEM; + } + ppp_stat->timeline_value = 1; + + kthread_init_worker(&ppp_stat->kworker); + kthread_init_work(&ppp_stat->blit_work, mdp3_ppp_blit_handler); + ppp_stat->blit_thread = kthread_run(kthread_worker_fn, + &ppp_stat->kworker, + "mdp3_ppp"); + + if (IS_ERR(ppp_stat->blit_thread)) { + rc = PTR_ERR(ppp_stat->blit_thread); + pr_err("ERROR: unable to start ppp blit thread,err = %d\n", + rc); + ppp_stat->blit_thread = NULL; + return rc; + } + if (sched_setscheduler(ppp_stat->blit_thread, SCHED_FIFO, ¶m)) + pr_warn("set priority failed for mdp3 blit thread\n"); + + INIT_WORK(&ppp_stat->free_bw_work, mdp3_free_bw_wq_handler); + init_completion(&ppp_stat->pop_q_comp); + mutex_init(&ppp_stat->req_mutex); + mutex_init(&ppp_stat->config_ppp_mutex); + init_timer(&ppp_stat->free_bw_timer); + ppp_stat->free_bw_timer.function = mdp3_free_fw_timer_func; + ppp_stat->free_bw_timer.data = 0; + ppp_stat->mfd = mfd; + mdp3_ppp_callback_setup(); + return 0; +} diff --git a/drivers/video/fbdev/msm/mdp3_ppp.h b/drivers/video/fbdev/msm/mdp3_ppp.h new file mode 100644 index 000000000000..1f8285138436 --- /dev/null +++ b/drivers/video/fbdev/msm/mdp3_ppp.h @@ -0,0 +1,430 @@ +/* Copyright (c) 2007, 2013, 2016, 2018, The Linux Foundation. All rights reserved. + * Copyright (C) 2007 Google Incorporated + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef MDP3_PPP_H +#define MDP3_PPP_H +#include "mdp3.h" +#include "mdss_fb.h" + +#define PPP_WRITEL(val, off) MDP3_REG_WRITE(off, val) + +#define MAX_BLIT_REQ 16 +#define PPP_UPSCALE_MAX 64 +#define PPP_BLUR_SCALE_MAX 128 +#define PPP_LUT_MAX 256 + +#define MDPOP_SMART_BLIT BIT(31) /* blit optimization flag */ + +/* MDP PPP Operations */ +#define MDPOP_NOP 0 +#define MDPOP_LR BIT(0) /* left to right flip */ +#define MDPOP_UD BIT(1) /* up and down flip */ +#define MDPOP_ROT90 BIT(2) /* rotate image to 90 degree */ +#define MDPOP_ROT180 (MDPOP_UD|MDPOP_LR) +#define MDPOP_ROT270 (MDPOP_ROT90|MDPOP_UD|MDPOP_LR) +#define MDPOP_ASCALE BIT(7) +#define MDPOP_ALPHAB BIT(8) /* enable alpha blending */ +#define MDPOP_TRANSP BIT(9) /* enable transparency */ +#define MDPOP_DITHER BIT(10) /* enable dither */ +#define MDPOP_SHARPENING BIT(11) /* enable sharpening */ +#define MDPOP_BLUR BIT(12) /* enable blur */ +#define MDPOP_FG_PM_ALPHA BIT(13) +#define MDPOP_LAYER_IS_FG BIT(14) + +#define MDPOP_ROTATION (MDPOP_ROT90|MDPOP_LR|MDPOP_UD) + +#define PPP_OP_CONVERT_YCBCR2RGB BIT(2) +#define PPP_OP_CONVERT_ON BIT(3) +#define PPP_OP_SCALE_X_ON BIT(0) +#define PPP_OP_SCALE_Y_ON BIT(1) +#define PPP_OP_ROT_ON BIT(8) +#define PPP_OP_ROT_90 BIT(9) +#define PPP_OP_FLIP_LR BIT(10) +#define PPP_OP_FLIP_UD BIT(11) +#define PPP_OP_BLEND_ON BIT(12) +#define PPP_OP_BLEND_CONSTANT_ALPHA BIT(14) +#define PPP_OP_BLEND_BG_ALPHA BIT(13) +#define PPP_OP_BLEND_EQ_REVERSE BIT(15) +#define PPP_OP_DITHER_EN BIT(16) +#define PPP_BLEND_CALPHA_TRNASP BIT(24) + +#define PPP_OP_BLEND_SRCPIXEL_ALPHA 0 +#define PPP_OP_BLEND_ALPHA_BLEND_NORMAL 0 +#define PPP_OP_BLEND_ALPHA_BLEND_REVERSE BIT(15) + +#define PPP_BLEND_BG_USE_ALPHA_SEL (1 << 0) +#define PPP_BLEND_BG_ALPHA_REVERSE (1 << 3) +#define PPP_BLEND_BG_SRCPIXEL_ALPHA (0 << 1) +#define PPP_BLEND_BG_DSTPIXEL_ALPHA (1 << 1) +#define PPP_BLEND_BG_CONSTANT_ALPHA (2 << 1) +#define PPP_BLEND_BG_CONST_ALPHA_VAL(x) ((x) << 24) +#define PPP_OP_BG_CHROMA_H2V1 BIT(25) + +#define CLR_G 0x0 +#define CLR_B 0x1 +#define CLR_R 0x2 +#define CLR_ALPHA 0x3 + +#define CLR_Y CLR_G +#define CLR_CB CLR_B +#define CLR_CR CLR_R + +/* from lsb to msb */ +#define PPP_GET_PACK_PATTERN(a, x, y, z, bit) \ + (((a)<<(bit*3))|((x)<<(bit*2))|((y)< + +#include "mdss_fb.h" +#include "mdp3_ppp.h" + +#define MDP_IS_IMGTYPE_BAD(x) ((x) >= MDP_IMGTYPE_LIMIT) + +/* bg_config_lut not needed since it is same as src */ +const uint32_t src_cfg_lut[MDP_IMGTYPE_LIMIT] = { + [MDP_RGB_565] = MDP_RGB_565_SRC_REG, + [MDP_BGR_565] = MDP_RGB_565_SRC_REG, + [MDP_RGB_888] = MDP_RGB_888_SRC_REG, + [MDP_BGR_888] = MDP_RGB_888_SRC_REG, + [MDP_BGRA_8888] = MDP_RGBX_8888_SRC_REG, + [MDP_RGBA_8888] = MDP_RGBX_8888_SRC_REG, + [MDP_ARGB_8888] = MDP_RGBX_8888_SRC_REG, + [MDP_XRGB_8888] = MDP_RGBX_8888_SRC_REG, + [MDP_RGBX_8888] = MDP_RGBX_8888_SRC_REG, + [MDP_Y_CRCB_H2V2] = MDP_Y_CBCR_H2V2_SRC_REG, + [MDP_Y_CBCR_H2V2] = MDP_Y_CBCR_H2V2_SRC_REG, + [MDP_Y_CBCR_H2V2_ADRENO] = MDP_Y_CBCR_H2V2_SRC_REG, + [MDP_Y_CBCR_H2V2_VENUS] = MDP_Y_CBCR_H2V2_SRC_REG, + [MDP_YCRYCB_H2V1] = MDP_YCRYCB_H2V1_SRC_REG, + [MDP_Y_CBCR_H2V1] = MDP_Y_CRCB_H2V1_SRC_REG, + [MDP_Y_CRCB_H2V1] = MDP_Y_CRCB_H2V1_SRC_REG, + [MDP_BGRX_8888] = MDP_RGBX_8888_SRC_REG, +}; + +const uint32_t out_cfg_lut[MDP_IMGTYPE_LIMIT] = { + [MDP_RGB_565] = MDP_RGB_565_DST_REG, + [MDP_BGR_565] = MDP_RGB_565_DST_REG, + [MDP_RGB_888] = MDP_RGB_888_DST_REG, + [MDP_BGR_888] = MDP_RGB_888_DST_REG, + [MDP_BGRA_8888] = MDP_RGBX_8888_DST_REG, + [MDP_RGBA_8888] = MDP_RGBX_8888_DST_REG, + [MDP_ARGB_8888] = MDP_RGBX_8888_DST_REG, + [MDP_XRGB_8888] = MDP_RGBX_8888_DST_REG, + [MDP_RGBX_8888] = MDP_RGBX_8888_DST_REG, + [MDP_Y_CRCB_H2V2] = MDP_Y_CBCR_H2V2_DST_REG, + [MDP_Y_CBCR_H2V2] = MDP_Y_CBCR_H2V2_DST_REG, + [MDP_Y_CBCR_H2V2_ADRENO] = MDP_Y_CBCR_H2V2_DST_REG, + [MDP_Y_CBCR_H2V2_VENUS] = MDP_Y_CBCR_H2V2_DST_REG, + [MDP_YCRYCB_H2V1] = MDP_YCRYCB_H2V1_DST_REG, + [MDP_Y_CBCR_H2V1] = MDP_Y_CRCB_H2V1_DST_REG, + [MDP_Y_CRCB_H2V1] = MDP_Y_CRCB_H2V1_DST_REG, + [MDP_BGRX_8888] = MDP_RGBX_8888_DST_REG, +}; + +const uint32_t pack_patt_lut[MDP_IMGTYPE_LIMIT] = { + [MDP_RGB_565] = PPP_GET_PACK_PATTERN(0, CLR_B, CLR_G, CLR_R, 8), + [MDP_BGR_565] = PPP_GET_PACK_PATTERN(0, CLR_R, CLR_G, CLR_B, 8), + [MDP_RGB_888] = PPP_GET_PACK_PATTERN(0, CLR_R, CLR_G, CLR_B, 8), + [MDP_BGR_888] = PPP_GET_PACK_PATTERN(0, CLR_B, CLR_G, CLR_R, 8), + [MDP_BGRA_8888] = PPP_GET_PACK_PATTERN(CLR_ALPHA, CLR_B, + CLR_G, CLR_R, 8), + [MDP_RGBA_8888] = PPP_GET_PACK_PATTERN(CLR_ALPHA, CLR_R, + CLR_G, CLR_B, 8), + [MDP_ARGB_8888] = PPP_GET_PACK_PATTERN(CLR_R, + CLR_G, CLR_B, CLR_ALPHA, 8), + [MDP_XRGB_8888] = PPP_GET_PACK_PATTERN(CLR_R, + CLR_G, CLR_B, CLR_ALPHA, 8), + [MDP_RGBX_8888] = PPP_GET_PACK_PATTERN(CLR_ALPHA, CLR_R, + CLR_G, CLR_B, 8), + [MDP_Y_CRCB_H2V2] = PPP_GET_PACK_PATTERN(0, 0, CLR_CR, CLR_CB, 8), + [MDP_Y_CBCR_H2V2] = PPP_GET_PACK_PATTERN(0, 0, CLR_CB, CLR_CR, 8), + [MDP_Y_CBCR_H2V2_ADRENO] = PPP_GET_PACK_PATTERN(0, 0, CLR_CB, + CLR_CR, 8), + [MDP_Y_CBCR_H2V2_VENUS] = PPP_GET_PACK_PATTERN(0, 0, CLR_CB, + CLR_CR, 8), + [MDP_YCRYCB_H2V1] = PPP_GET_PACK_PATTERN(CLR_Y, + CLR_CR, CLR_Y, CLR_CB, 8), + [MDP_Y_CBCR_H2V1] = PPP_GET_PACK_PATTERN(0, 0, CLR_CB, CLR_CR, 8), + [MDP_Y_CRCB_H2V1] = PPP_GET_PACK_PATTERN(0, 0, CLR_CR, CLR_CB, 8), + [MDP_BGRX_8888] = PPP_GET_PACK_PATTERN(CLR_ALPHA, CLR_B, + CLR_G, CLR_R, 8), +}; + +const uint32_t swapped_pack_patt_lut[MDP_IMGTYPE_LIMIT] = { + [MDP_RGB_565] = PPP_GET_PACK_PATTERN(0, CLR_B, CLR_G, CLR_R, 8), + [MDP_BGR_565] = PPP_GET_PACK_PATTERN(0, CLR_R, CLR_G, CLR_B, 8), + [MDP_RGB_888] = PPP_GET_PACK_PATTERN(0, CLR_B, CLR_G, CLR_R, 8), + [MDP_BGR_888] = PPP_GET_PACK_PATTERN(0, CLR_R, CLR_G, CLR_B, 8), + [MDP_BGRA_8888] = PPP_GET_PACK_PATTERN(CLR_ALPHA, CLR_R, + CLR_G, CLR_B, 8), + [MDP_RGBA_8888] = PPP_GET_PACK_PATTERN(CLR_ALPHA, CLR_B, + CLR_G, CLR_R, 8), + [MDP_ARGB_8888] = PPP_GET_PACK_PATTERN(CLR_ALPHA, CLR_B, + CLR_G, CLR_R, 8), + [MDP_XRGB_8888] = PPP_GET_PACK_PATTERN(CLR_ALPHA, CLR_B, + CLR_G, CLR_R, 8), + [MDP_RGBX_8888] = PPP_GET_PACK_PATTERN(CLR_ALPHA, CLR_B, + CLR_G, CLR_R, 8), + [MDP_Y_CRCB_H2V2] = PPP_GET_PACK_PATTERN(0, 0, CLR_CB, CLR_CR, 8), + [MDP_Y_CBCR_H2V2] = PPP_GET_PACK_PATTERN(0, 0, CLR_CR, CLR_CB, 8), + [MDP_Y_CBCR_H2V2_ADRENO] = PPP_GET_PACK_PATTERN(0, 0, CLR_CR, + CLR_CB, 8), + [MDP_Y_CBCR_H2V2_VENUS] = PPP_GET_PACK_PATTERN(0, 0, CLR_CR, + CLR_CB, 8), + [MDP_YCRYCB_H2V1] = PPP_GET_PACK_PATTERN(CLR_Y, + CLR_CB, CLR_Y, CLR_CR, 8), + [MDP_Y_CBCR_H2V1] = PPP_GET_PACK_PATTERN(0, 0, CLR_CR, CLR_CB, 8), + [MDP_Y_CRCB_H2V1] = PPP_GET_PACK_PATTERN(0, 0, CLR_CB, CLR_CR, 8), + [MDP_BGRX_8888] = PPP_GET_PACK_PATTERN(CLR_ALPHA, CLR_R, + CLR_G, CLR_B, 8), +}; + +const uint32_t dst_op_reg[MDP_IMGTYPE_LIMIT] = { + [MDP_Y_CRCB_H2V2] = PPP_OP_DST_CHROMA_420, + [MDP_Y_CBCR_H2V2] = PPP_OP_DST_CHROMA_420, + [MDP_Y_CBCR_H2V1] = PPP_OP_DST_CHROMA_H2V1, + [MDP_Y_CRCB_H2V1] = PPP_OP_DST_CHROMA_H2V1, + [MDP_YCRYCB_H2V1] = PPP_OP_DST_CHROMA_H2V1, +}; + +const uint32_t src_op_reg[MDP_IMGTYPE_LIMIT] = { + [MDP_Y_CRCB_H2V2] = PPP_OP_SRC_CHROMA_420 | PPP_OP_COLOR_SPACE_YCBCR, + [MDP_Y_CBCR_H2V2] = PPP_OP_SRC_CHROMA_420 | PPP_OP_COLOR_SPACE_YCBCR, + [MDP_Y_CBCR_H2V2_ADRENO] = PPP_OP_SRC_CHROMA_420 | + PPP_OP_COLOR_SPACE_YCBCR, + [MDP_Y_CBCR_H2V2_VENUS] = PPP_OP_SRC_CHROMA_420 | + PPP_OP_COLOR_SPACE_YCBCR, + [MDP_Y_CBCR_H2V1] = PPP_OP_SRC_CHROMA_H2V1, + [MDP_Y_CRCB_H2V1] = PPP_OP_SRC_CHROMA_H2V1, + [MDP_YCRYCB_H2V1] = PPP_OP_SRC_CHROMA_H2V1, +}; + +const uint32_t bytes_per_pixel[MDP_IMGTYPE_LIMIT] = { + [MDP_RGB_565] = 2, + [MDP_BGR_565] = 2, + [MDP_RGB_888] = 3, + [MDP_BGR_888] = 3, + [MDP_XRGB_8888] = 4, + [MDP_ARGB_8888] = 4, + [MDP_RGBA_8888] = 4, + [MDP_BGRA_8888] = 4, + [MDP_RGBX_8888] = 4, + [MDP_Y_CBCR_H2V1] = 1, + [MDP_Y_CBCR_H2V2] = 1, + [MDP_Y_CBCR_H2V2_ADRENO] = 1, + [MDP_Y_CBCR_H2V2_VENUS] = 1, + [MDP_Y_CRCB_H2V1] = 1, + [MDP_Y_CRCB_H2V2] = 1, + [MDP_YCRYCB_H2V1] = 2, + [MDP_BGRX_8888] = 4, +}; + +const bool per_pixel_alpha[MDP_IMGTYPE_LIMIT] = { + [MDP_BGRA_8888] = true, + [MDP_RGBA_8888] = true, + [MDP_ARGB_8888] = true, +}; + +const bool multi_plane[MDP_IMGTYPE_LIMIT] = { + [MDP_Y_CRCB_H2V2] = true, + [MDP_Y_CBCR_H2V2] = true, + [MDP_Y_CBCR_H2V1] = true, + [MDP_Y_CRCB_H2V1] = true, +}; + +/* lut default */ +uint32_t default_pre_lut_val[PPP_LUT_MAX] = { + 0x0, + 0x151515, + 0x1d1d1d, + 0x232323, + 0x272727, + 0x2b2b2b, + 0x2f2f2f, + 0x333333, + 0x363636, + 0x393939, + 0x3b3b3b, + 0x3e3e3e, + 0x404040, + 0x434343, + 0x454545, + 0x474747, + 0x494949, + 0x4b4b4b, + 0x4d4d4d, + 0x4f4f4f, + 0x515151, + 0x535353, + 0x555555, + 0x565656, + 0x585858, + 0x5a5a5a, + 0x5b5b5b, + 0x5d5d5d, + 0x5e5e5e, + 0x606060, + 0x616161, + 0x636363, + 0x646464, + 0x666666, + 0x676767, + 0x686868, + 0x6a6a6a, + 0x6b6b6b, + 0x6c6c6c, + 0x6e6e6e, + 0x6f6f6f, + 0x707070, + 0x717171, + 0x727272, + 0x747474, + 0x757575, + 0x767676, + 0x777777, + 0x787878, + 0x797979, + 0x7a7a7a, + 0x7c7c7c, + 0x7d7d7d, + 0x7e7e7e, + 0x7f7f7f, + 0x808080, + 0x818181, + 0x828282, + 0x838383, + 0x848484, + 0x858585, + 0x868686, + 0x878787, + 0x888888, + 0x898989, + 0x8a8a8a, + 0x8b8b8b, + 0x8c8c8c, + 0x8d8d8d, + 0x8e8e8e, + 0x8f8f8f, + 0x8f8f8f, + 0x909090, + 0x919191, + 0x929292, + 0x939393, + 0x949494, + 0x959595, + 0x969696, + 0x969696, + 0x979797, + 0x989898, + 0x999999, + 0x9a9a9a, + 0x9b9b9b, + 0x9c9c9c, + 0x9c9c9c, + 0x9d9d9d, + 0x9e9e9e, + 0x9f9f9f, + 0xa0a0a0, + 0xa0a0a0, + 0xa1a1a1, + 0xa2a2a2, + 0xa3a3a3, + 0xa4a4a4, + 0xa4a4a4, + 0xa5a5a5, + 0xa6a6a6, + 0xa7a7a7, + 0xa7a7a7, + 0xa8a8a8, + 0xa9a9a9, + 0xaaaaaa, + 0xaaaaaa, + 0xababab, + 0xacacac, + 0xadadad, + 0xadadad, + 0xaeaeae, + 0xafafaf, + 0xafafaf, + 0xb0b0b0, + 0xb1b1b1, + 0xb2b2b2, + 0xb2b2b2, + 0xb3b3b3, + 0xb4b4b4, + 0xb4b4b4, + 0xb5b5b5, + 0xb6b6b6, + 0xb6b6b6, + 0xb7b7b7, + 0xb8b8b8, + 0xb8b8b8, + 0xb9b9b9, + 0xbababa, + 0xbababa, + 0xbbbbbb, + 0xbcbcbc, + 0xbcbcbc, + 0xbdbdbd, + 0xbebebe, + 0xbebebe, + 0xbfbfbf, + 0xc0c0c0, + 0xc0c0c0, + 0xc1c1c1, + 0xc1c1c1, + 0xc2c2c2, + 0xc3c3c3, + 0xc3c3c3, + 0xc4c4c4, + 0xc5c5c5, + 0xc5c5c5, + 0xc6c6c6, + 0xc6c6c6, + 0xc7c7c7, + 0xc8c8c8, + 0xc8c8c8, + 0xc9c9c9, + 0xc9c9c9, + 0xcacaca, + 0xcbcbcb, + 0xcbcbcb, + 0xcccccc, + 0xcccccc, + 0xcdcdcd, + 0xcecece, + 0xcecece, + 0xcfcfcf, + 0xcfcfcf, + 0xd0d0d0, + 0xd0d0d0, + 0xd1d1d1, + 0xd2d2d2, + 0xd2d2d2, + 0xd3d3d3, + 0xd3d3d3, + 0xd4d4d4, + 0xd4d4d4, + 0xd5d5d5, + 0xd6d6d6, + 0xd6d6d6, + 0xd7d7d7, + 0xd7d7d7, + 0xd8d8d8, + 0xd8d8d8, + 0xd9d9d9, + 0xd9d9d9, + 0xdadada, + 0xdbdbdb, + 0xdbdbdb, + 0xdcdcdc, + 0xdcdcdc, + 0xdddddd, + 0xdddddd, + 0xdedede, + 0xdedede, + 0xdfdfdf, + 0xdfdfdf, + 0xe0e0e0, + 0xe0e0e0, + 0xe1e1e1, + 0xe1e1e1, + 0xe2e2e2, + 0xe3e3e3, + 0xe3e3e3, + 0xe4e4e4, + 0xe4e4e4, + 0xe5e5e5, + 0xe5e5e5, + 0xe6e6e6, + 0xe6e6e6, + 0xe7e7e7, + 0xe7e7e7, + 0xe8e8e8, + 0xe8e8e8, + 0xe9e9e9, + 0xe9e9e9, + 0xeaeaea, + 0xeaeaea, + 0xebebeb, + 0xebebeb, + 0xececec, + 0xececec, + 0xededed, + 0xededed, + 0xeeeeee, + 0xeeeeee, + 0xefefef, + 0xefefef, + 0xf0f0f0, + 0xf0f0f0, + 0xf1f1f1, + 0xf1f1f1, + 0xf2f2f2, + 0xf2f2f2, + 0xf2f2f2, + 0xf3f3f3, + 0xf3f3f3, + 0xf4f4f4, + 0xf4f4f4, + 0xf5f5f5, + 0xf5f5f5, + 0xf6f6f6, + 0xf6f6f6, + 0xf7f7f7, + 0xf7f7f7, + 0xf8f8f8, + 0xf8f8f8, + 0xf9f9f9, + 0xf9f9f9, + 0xfafafa, + 0xfafafa, + 0xfafafa, + 0xfbfbfb, + 0xfbfbfb, + 0xfcfcfc, + 0xfcfcfc, + 0xfdfdfd, + 0xfdfdfd, + 0xfefefe, + 0xfefefe, + 0xffffff, + 0xffffff, +}; + +uint32_t default_post_lut_val[PPP_LUT_MAX] = { + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x10101, + 0x10101, + 0x10101, + 0x10101, + 0x10101, + 0x10101, + 0x10101, + 0x10101, + 0x10101, + 0x10101, + 0x20202, + 0x20202, + 0x20202, + 0x20202, + 0x20202, + 0x20202, + 0x30303, + 0x30303, + 0x30303, + 0x30303, + 0x30303, + 0x40404, + 0x40404, + 0x40404, + 0x40404, + 0x40404, + 0x50505, + 0x50505, + 0x50505, + 0x50505, + 0x60606, + 0x60606, + 0x60606, + 0x70707, + 0x70707, + 0x70707, + 0x70707, + 0x80808, + 0x80808, + 0x80808, + 0x90909, + 0x90909, + 0xa0a0a, + 0xa0a0a, + 0xa0a0a, + 0xb0b0b, + 0xb0b0b, + 0xb0b0b, + 0xc0c0c, + 0xc0c0c, + 0xd0d0d, + 0xd0d0d, + 0xe0e0e, + 0xe0e0e, + 0xe0e0e, + 0xf0f0f, + 0xf0f0f, + 0x101010, + 0x101010, + 0x111111, + 0x111111, + 0x121212, + 0x121212, + 0x131313, + 0x131313, + 0x141414, + 0x151515, + 0x151515, + 0x161616, + 0x161616, + 0x171717, + 0x171717, + 0x181818, + 0x191919, + 0x191919, + 0x1a1a1a, + 0x1b1b1b, + 0x1b1b1b, + 0x1c1c1c, + 0x1c1c1c, + 0x1d1d1d, + 0x1e1e1e, + 0x1f1f1f, + 0x1f1f1f, + 0x202020, + 0x212121, + 0x212121, + 0x222222, + 0x232323, + 0x242424, + 0x242424, + 0x252525, + 0x262626, + 0x272727, + 0x272727, + 0x282828, + 0x292929, + 0x2a2a2a, + 0x2b2b2b, + 0x2c2c2c, + 0x2c2c2c, + 0x2d2d2d, + 0x2e2e2e, + 0x2f2f2f, + 0x303030, + 0x313131, + 0x323232, + 0x333333, + 0x333333, + 0x343434, + 0x353535, + 0x363636, + 0x373737, + 0x383838, + 0x393939, + 0x3a3a3a, + 0x3b3b3b, + 0x3c3c3c, + 0x3d3d3d, + 0x3e3e3e, + 0x3f3f3f, + 0x404040, + 0x414141, + 0x424242, + 0x434343, + 0x444444, + 0x464646, + 0x474747, + 0x484848, + 0x494949, + 0x4a4a4a, + 0x4b4b4b, + 0x4c4c4c, + 0x4d4d4d, + 0x4f4f4f, + 0x505050, + 0x515151, + 0x525252, + 0x535353, + 0x545454, + 0x565656, + 0x575757, + 0x585858, + 0x595959, + 0x5b5b5b, + 0x5c5c5c, + 0x5d5d5d, + 0x5e5e5e, + 0x606060, + 0x616161, + 0x626262, + 0x646464, + 0x656565, + 0x666666, + 0x686868, + 0x696969, + 0x6a6a6a, + 0x6c6c6c, + 0x6d6d6d, + 0x6f6f6f, + 0x707070, + 0x717171, + 0x737373, + 0x747474, + 0x767676, + 0x777777, + 0x797979, + 0x7a7a7a, + 0x7c7c7c, + 0x7d7d7d, + 0x7f7f7f, + 0x808080, + 0x828282, + 0x838383, + 0x858585, + 0x868686, + 0x888888, + 0x898989, + 0x8b8b8b, + 0x8d8d8d, + 0x8e8e8e, + 0x909090, + 0x919191, + 0x939393, + 0x959595, + 0x969696, + 0x989898, + 0x9a9a9a, + 0x9b9b9b, + 0x9d9d9d, + 0x9f9f9f, + 0xa1a1a1, + 0xa2a2a2, + 0xa4a4a4, + 0xa6a6a6, + 0xa7a7a7, + 0xa9a9a9, + 0xababab, + 0xadadad, + 0xafafaf, + 0xb0b0b0, + 0xb2b2b2, + 0xb4b4b4, + 0xb6b6b6, + 0xb8b8b8, + 0xbababa, + 0xbbbbbb, + 0xbdbdbd, + 0xbfbfbf, + 0xc1c1c1, + 0xc3c3c3, + 0xc5c5c5, + 0xc7c7c7, + 0xc9c9c9, + 0xcbcbcb, + 0xcdcdcd, + 0xcfcfcf, + 0xd1d1d1, + 0xd3d3d3, + 0xd5d5d5, + 0xd7d7d7, + 0xd9d9d9, + 0xdbdbdb, + 0xdddddd, + 0xdfdfdf, + 0xe1e1e1, + 0xe3e3e3, + 0xe5e5e5, + 0xe7e7e7, + 0xe9e9e9, + 0xebebeb, + 0xeeeeee, + 0xf0f0f0, + 0xf2f2f2, + 0xf4f4f4, + 0xf6f6f6, + 0xf8f8f8, + 0xfbfbfb, + 0xfdfdfd, + 0xffffff, +}; + +struct ppp_csc_table rgb2yuv = { + .fwd_matrix = { + 0x83, + 0x102, + 0x32, + 0xffb5, + 0xff6c, + 0xe1, + 0xe1, + 0xff45, + 0xffdc, + }, + .rev_matrix = { + 0x254, + 0x0, + 0x331, + 0x254, + 0xff38, + 0xfe61, + 0x254, + 0x409, + 0x0, + }, + .bv = { + 0x10, + 0x80, + 0x80, + }, + .lv = { + 0x10, + 0xeb, + 0x10, + 0xf0, + }, +}; + +struct ppp_csc_table default_table2 = { + .fwd_matrix = { + 0x5d, + 0x13a, + 0x20, + 0xffcd, + 0xff54, + 0xe1, + 0xe1, + 0xff35, + }, + .rev_matrix = { + 0x254, + 0x0, + 0x396, + 0x254, + 0xff94, + 0xfef0, + 0x254, + 0x43a, + 0x0, + }, + .bv = { + 0x10, + 0x80, + 0x80, + }, + .lv = { + 0x10, + 0xeb, + 0x10, + 0xf0, + }, +}; + +const struct ppp_table upscale_table[PPP_UPSCALE_MAX] = { + { 0x5fffc, 0x0 }, + { 0x50200, 0x7fc00000 }, + { 0x5fffc, 0xff80000d }, + { 0x50204, 0x7ec003f9 }, + { 0x5fffc, 0xfec0001c }, + { 0x50208, 0x7d4003f3 }, + { 0x5fffc, 0xfe40002b }, + { 0x5020c, 0x7b8003ed }, + { 0x5fffc, 0xfd80003c }, + { 0x50210, 0x794003e8 }, + { 0x5fffc, 0xfcc0004d }, + { 0x50214, 0x76c003e4 }, + { 0x5fffc, 0xfc40005f }, + { 0x50218, 0x73c003e0 }, + { 0x5fffc, 0xfb800071 }, + { 0x5021c, 0x708003de }, + { 0x5fffc, 0xfac00085 }, + { 0x50220, 0x6d0003db }, + { 0x5fffc, 0xfa000098 }, + { 0x50224, 0x698003d9 }, + { 0x5fffc, 0xf98000ac }, + { 0x50228, 0x654003d8 }, + { 0x5fffc, 0xf8c000c1 }, + { 0x5022c, 0x610003d7 }, + { 0x5fffc, 0xf84000d5 }, + { 0x50230, 0x5c8003d7 }, + { 0x5fffc, 0xf7c000e9 }, + { 0x50234, 0x580003d7 }, + { 0x5fffc, 0xf74000fd }, + { 0x50238, 0x534003d8 }, + { 0x5fffc, 0xf6c00112 }, + { 0x5023c, 0x4e8003d8 }, + { 0x5fffc, 0xf6800126 }, + { 0x50240, 0x494003da }, + { 0x5fffc, 0xf600013a }, + { 0x50244, 0x448003db }, + { 0x5fffc, 0xf600014d }, + { 0x50248, 0x3f4003dd }, + { 0x5fffc, 0xf5c00160 }, + { 0x5024c, 0x3a4003df }, + { 0x5fffc, 0xf5c00172 }, + { 0x50250, 0x354003e1 }, + { 0x5fffc, 0xf5c00184 }, + { 0x50254, 0x304003e3 }, + { 0x5fffc, 0xf6000195 }, + { 0x50258, 0x2b0003e6 }, + { 0x5fffc, 0xf64001a6 }, + { 0x5025c, 0x260003e8 }, + { 0x5fffc, 0xf6c001b4 }, + { 0x50260, 0x214003eb }, + { 0x5fffc, 0xf78001c2 }, + { 0x50264, 0x1c4003ee }, + { 0x5fffc, 0xf80001cf }, + { 0x50268, 0x17c003f1 }, + { 0x5fffc, 0xf90001db }, + { 0x5026c, 0x134003f3 }, + { 0x5fffc, 0xfa0001e5 }, + { 0x50270, 0xf0003f6 }, + { 0x5fffc, 0xfb4001ee }, + { 0x50274, 0xac003f9 }, + { 0x5fffc, 0xfcc001f5 }, + { 0x50278, 0x70003fb }, + { 0x5fffc, 0xfe4001fb }, + { 0x5027c, 0x34003fe }, +}; + +const struct ppp_table mdp_gaussian_blur_table[PPP_BLUR_SCALE_MAX] = { + /* max variance */ + { 0x5fffc, 0x20000080 }, + { 0x50280, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x50284, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x50288, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x5028c, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x50290, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x50294, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x50298, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x5029c, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x502a0, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x502a4, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x502a8, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x502ac, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x502b0, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x502b4, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x502b8, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x502bc, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x502c0, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x502c4, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x502c8, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x502cc, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x502d0, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x502d4, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x502d8, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x502dc, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x502e0, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x502e4, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x502e8, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x502ec, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x502f0, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x502f4, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x502f8, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x502fc, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x50300, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x50304, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x50308, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x5030c, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x50310, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x50314, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x50318, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x5031c, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x50320, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x50324, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x50328, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x5032c, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x50330, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x50334, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x50338, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x5033c, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x50340, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x50344, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x50348, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x5034c, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x50350, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x50354, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x50358, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x5035c, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x50360, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x50364, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x50368, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x5036c, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x50370, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x50374, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x50378, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x5037c, 0x20000080 }, +}; + +const struct ppp_table downscale_x_table_pt2topt4[] = { + { 0x5fffc, 0x740008c }, + { 0x50280, 0x33800088 }, + { 0x5fffc, 0x800008e }, + { 0x50284, 0x33400084 }, + { 0x5fffc, 0x8400092 }, + { 0x50288, 0x33000080 }, + { 0x5fffc, 0x9000094 }, + { 0x5028c, 0x3300007b }, + { 0x5fffc, 0x9c00098 }, + { 0x50290, 0x32400077 }, + { 0x5fffc, 0xa40009b }, + { 0x50294, 0x32000073 }, + { 0x5fffc, 0xb00009d }, + { 0x50298, 0x31c0006f }, + { 0x5fffc, 0xbc000a0 }, + { 0x5029c, 0x3140006b }, + { 0x5fffc, 0xc8000a2 }, + { 0x502a0, 0x31000067 }, + { 0x5fffc, 0xd8000a5 }, + { 0x502a4, 0x30800062 }, + { 0x5fffc, 0xe4000a8 }, + { 0x502a8, 0x2fc0005f }, + { 0x5fffc, 0xec000aa }, + { 0x502ac, 0x2fc0005b }, + { 0x5fffc, 0xf8000ad }, + { 0x502b0, 0x2f400057 }, + { 0x5fffc, 0x108000b0 }, + { 0x502b4, 0x2e400054 }, + { 0x5fffc, 0x114000b2 }, + { 0x502b8, 0x2e000050 }, + { 0x5fffc, 0x124000b4 }, + { 0x502bc, 0x2d80004c }, + { 0x5fffc, 0x130000b6 }, + { 0x502c0, 0x2d000049 }, + { 0x5fffc, 0x140000b8 }, + { 0x502c4, 0x2c800045 }, + { 0x5fffc, 0x150000b9 }, + { 0x502c8, 0x2c000042 }, + { 0x5fffc, 0x15c000bd }, + { 0x502cc, 0x2b40003e }, + { 0x5fffc, 0x16c000bf }, + { 0x502d0, 0x2a80003b }, + { 0x5fffc, 0x17c000bf }, + { 0x502d4, 0x2a000039 }, + { 0x5fffc, 0x188000c2 }, + { 0x502d8, 0x29400036 }, + { 0x5fffc, 0x19c000c4 }, + { 0x502dc, 0x28800032 }, + { 0x5fffc, 0x1ac000c5 }, + { 0x502e0, 0x2800002f }, + { 0x5fffc, 0x1bc000c7 }, + { 0x502e4, 0x2740002c }, + { 0x5fffc, 0x1cc000c8 }, + { 0x502e8, 0x26c00029 }, + { 0x5fffc, 0x1dc000c9 }, + { 0x502ec, 0x26000027 }, + { 0x5fffc, 0x1ec000cc }, + { 0x502f0, 0x25000024 }, + { 0x5fffc, 0x200000cc }, + { 0x502f4, 0x24800021 }, + { 0x5fffc, 0x210000cd }, + { 0x502f8, 0x23800020 }, + { 0x5fffc, 0x220000ce }, + { 0x502fc, 0x2300001d }, +}; + +static const struct ppp_table downscale_x_table_pt4topt6[] = { + { 0x5fffc, 0x740008c }, + { 0x50280, 0x33800088 }, + { 0x5fffc, 0x800008e }, + { 0x50284, 0x33400084 }, + { 0x5fffc, 0x8400092 }, + { 0x50288, 0x33000080 }, + { 0x5fffc, 0x9000094 }, + { 0x5028c, 0x3300007b }, + { 0x5fffc, 0x9c00098 }, + { 0x50290, 0x32400077 }, + { 0x5fffc, 0xa40009b }, + { 0x50294, 0x32000073 }, + { 0x5fffc, 0xb00009d }, + { 0x50298, 0x31c0006f }, + { 0x5fffc, 0xbc000a0 }, + { 0x5029c, 0x3140006b }, + { 0x5fffc, 0xc8000a2 }, + { 0x502a0, 0x31000067 }, + { 0x5fffc, 0xd8000a5 }, + { 0x502a4, 0x30800062 }, + { 0x5fffc, 0xe4000a8 }, + { 0x502a8, 0x2fc0005f }, + { 0x5fffc, 0xec000aa }, + { 0x502ac, 0x2fc0005b }, + { 0x5fffc, 0xf8000ad }, + { 0x502b0, 0x2f400057 }, + { 0x5fffc, 0x108000b0 }, + { 0x502b4, 0x2e400054 }, + { 0x5fffc, 0x114000b2 }, + { 0x502b8, 0x2e000050 }, + { 0x5fffc, 0x124000b4 }, + { 0x502bc, 0x2d80004c }, + { 0x5fffc, 0x130000b6 }, + { 0x502c0, 0x2d000049 }, + { 0x5fffc, 0x140000b8 }, + { 0x502c4, 0x2c800045 }, + { 0x5fffc, 0x150000b9 }, + { 0x502c8, 0x2c000042 }, + { 0x5fffc, 0x15c000bd }, + { 0x502cc, 0x2b40003e }, + { 0x5fffc, 0x16c000bf }, + { 0x502d0, 0x2a80003b }, + { 0x5fffc, 0x17c000bf }, + { 0x502d4, 0x2a000039 }, + { 0x5fffc, 0x188000c2 }, + { 0x502d8, 0x29400036 }, + { 0x5fffc, 0x19c000c4 }, + { 0x502dc, 0x28800032 }, + { 0x5fffc, 0x1ac000c5 }, + { 0x502e0, 0x2800002f }, + { 0x5fffc, 0x1bc000c7 }, + { 0x502e4, 0x2740002c }, + { 0x5fffc, 0x1cc000c8 }, + { 0x502e8, 0x26c00029 }, + { 0x5fffc, 0x1dc000c9 }, + { 0x502ec, 0x26000027 }, + { 0x5fffc, 0x1ec000cc }, + { 0x502f0, 0x25000024 }, + { 0x5fffc, 0x200000cc }, + { 0x502f4, 0x24800021 }, + { 0x5fffc, 0x210000cd }, + { 0x502f8, 0x23800020 }, + { 0x5fffc, 0x220000ce }, + { 0x502fc, 0x2300001d }, +}; + +static const struct ppp_table downscale_x_table_pt6topt8[] = { + { 0x5fffc, 0xfe000070 }, + { 0x50280, 0x4bc00068 }, + { 0x5fffc, 0xfe000078 }, + { 0x50284, 0x4bc00060 }, + { 0x5fffc, 0xfe000080 }, + { 0x50288, 0x4b800059 }, + { 0x5fffc, 0xfe000089 }, + { 0x5028c, 0x4b000052 }, + { 0x5fffc, 0xfe400091 }, + { 0x50290, 0x4a80004b }, + { 0x5fffc, 0xfe40009a }, + { 0x50294, 0x4a000044 }, + { 0x5fffc, 0xfe8000a3 }, + { 0x50298, 0x4940003d }, + { 0x5fffc, 0xfec000ac }, + { 0x5029c, 0x48400037 }, + { 0x5fffc, 0xff0000b4 }, + { 0x502a0, 0x47800031 }, + { 0x5fffc, 0xff8000bd }, + { 0x502a4, 0x4640002b }, + { 0x5fffc, 0xc5 }, + { 0x502a8, 0x45000026 }, + { 0x5fffc, 0x8000ce }, + { 0x502ac, 0x43800021 }, + { 0x5fffc, 0x10000d6 }, + { 0x502b0, 0x4240001c }, + { 0x5fffc, 0x18000df }, + { 0x502b4, 0x40800018 }, + { 0x5fffc, 0x24000e6 }, + { 0x502b8, 0x3f000014 }, + { 0x5fffc, 0x30000ee }, + { 0x502bc, 0x3d400010 }, + { 0x5fffc, 0x40000f5 }, + { 0x502c0, 0x3b80000c }, + { 0x5fffc, 0x50000fc }, + { 0x502c4, 0x39800009 }, + { 0x5fffc, 0x6000102 }, + { 0x502c8, 0x37c00006 }, + { 0x5fffc, 0x7000109 }, + { 0x502cc, 0x35800004 }, + { 0x5fffc, 0x840010e }, + { 0x502d0, 0x33800002 }, + { 0x5fffc, 0x9800114 }, + { 0x502d4, 0x31400000 }, + { 0x5fffc, 0xac00119 }, + { 0x502d8, 0x2f4003fe }, + { 0x5fffc, 0xc40011e }, + { 0x502dc, 0x2d0003fc }, + { 0x5fffc, 0xdc00121 }, + { 0x502e0, 0x2b0003fb }, + { 0x5fffc, 0xf400125 }, + { 0x502e4, 0x28c003fa }, + { 0x5fffc, 0x11000128 }, + { 0x502e8, 0x268003f9 }, + { 0x5fffc, 0x12c0012a }, + { 0x502ec, 0x244003f9 }, + { 0x5fffc, 0x1480012c }, + { 0x502f0, 0x224003f8 }, + { 0x5fffc, 0x1640012e }, + { 0x502f4, 0x200003f8 }, + { 0x5fffc, 0x1800012f }, + { 0x502f8, 0x1e0003f8 }, + { 0x5fffc, 0x1a00012f }, + { 0x502fc, 0x1c0003f8 }, +}; + +static const struct ppp_table downscale_x_table_pt8topt1[] = { + { 0x5fffc, 0x0 }, + { 0x50280, 0x7fc00000 }, + { 0x5fffc, 0xff80000d }, + { 0x50284, 0x7ec003f9 }, + { 0x5fffc, 0xfec0001c }, + { 0x50288, 0x7d4003f3 }, + { 0x5fffc, 0xfe40002b }, + { 0x5028c, 0x7b8003ed }, + { 0x5fffc, 0xfd80003c }, + { 0x50290, 0x794003e8 }, + { 0x5fffc, 0xfcc0004d }, + { 0x50294, 0x76c003e4 }, + { 0x5fffc, 0xfc40005f }, + { 0x50298, 0x73c003e0 }, + { 0x5fffc, 0xfb800071 }, + { 0x5029c, 0x708003de }, + { 0x5fffc, 0xfac00085 }, + { 0x502a0, 0x6d0003db }, + { 0x5fffc, 0xfa000098 }, + { 0x502a4, 0x698003d9 }, + { 0x5fffc, 0xf98000ac }, + { 0x502a8, 0x654003d8 }, + { 0x5fffc, 0xf8c000c1 }, + { 0x502ac, 0x610003d7 }, + { 0x5fffc, 0xf84000d5 }, + { 0x502b0, 0x5c8003d7 }, + { 0x5fffc, 0xf7c000e9 }, + { 0x502b4, 0x580003d7 }, + { 0x5fffc, 0xf74000fd }, + { 0x502b8, 0x534003d8 }, + { 0x5fffc, 0xf6c00112 }, + { 0x502bc, 0x4e8003d8 }, + { 0x5fffc, 0xf6800126 }, + { 0x502c0, 0x494003da }, + { 0x5fffc, 0xf600013a }, + { 0x502c4, 0x448003db }, + { 0x5fffc, 0xf600014d }, + { 0x502c8, 0x3f4003dd }, + { 0x5fffc, 0xf5c00160 }, + { 0x502cc, 0x3a4003df }, + { 0x5fffc, 0xf5c00172 }, + { 0x502d0, 0x354003e1 }, + { 0x5fffc, 0xf5c00184 }, + { 0x502d4, 0x304003e3 }, + { 0x5fffc, 0xf6000195 }, + { 0x502d8, 0x2b0003e6 }, + { 0x5fffc, 0xf64001a6 }, + { 0x502dc, 0x260003e8 }, + { 0x5fffc, 0xf6c001b4 }, + { 0x502e0, 0x214003eb }, + { 0x5fffc, 0xf78001c2 }, + { 0x502e4, 0x1c4003ee }, + { 0x5fffc, 0xf80001cf }, + { 0x502e8, 0x17c003f1 }, + { 0x5fffc, 0xf90001db }, + { 0x502ec, 0x134003f3 }, + { 0x5fffc, 0xfa0001e5 }, + { 0x502f0, 0xf0003f6 }, + { 0x5fffc, 0xfb4001ee }, + { 0x502f4, 0xac003f9 }, + { 0x5fffc, 0xfcc001f5 }, + { 0x502f8, 0x70003fb }, + { 0x5fffc, 0xfe4001fb }, + { 0x502fc, 0x34003fe }, +}; + +static const struct ppp_table *downscale_x_table[PPP_DOWNSCALE_MAX] = { + [PPP_DOWNSCALE_PT2TOPT4] = downscale_x_table_pt2topt4, + [PPP_DOWNSCALE_PT4TOPT6] = downscale_x_table_pt4topt6, + [PPP_DOWNSCALE_PT6TOPT8] = downscale_x_table_pt6topt8, + [PPP_DOWNSCALE_PT8TOPT1] = downscale_x_table_pt8topt1, +}; + +static const struct ppp_table downscale_y_table_pt2topt4[] = { + { 0x5fffc, 0x740008c }, + { 0x50300, 0x33800088 }, + { 0x5fffc, 0x800008e }, + { 0x50304, 0x33400084 }, + { 0x5fffc, 0x8400092 }, + { 0x50308, 0x33000080 }, + { 0x5fffc, 0x9000094 }, + { 0x5030c, 0x3300007b }, + { 0x5fffc, 0x9c00098 }, + { 0x50310, 0x32400077 }, + { 0x5fffc, 0xa40009b }, + { 0x50314, 0x32000073 }, + { 0x5fffc, 0xb00009d }, + { 0x50318, 0x31c0006f }, + { 0x5fffc, 0xbc000a0 }, + { 0x5031c, 0x3140006b }, + { 0x5fffc, 0xc8000a2 }, + { 0x50320, 0x31000067 }, + { 0x5fffc, 0xd8000a5 }, + { 0x50324, 0x30800062 }, + { 0x5fffc, 0xe4000a8 }, + { 0x50328, 0x2fc0005f }, + { 0x5fffc, 0xec000aa }, + { 0x5032c, 0x2fc0005b }, + { 0x5fffc, 0xf8000ad }, + { 0x50330, 0x2f400057 }, + { 0x5fffc, 0x108000b0 }, + { 0x50334, 0x2e400054 }, + { 0x5fffc, 0x114000b2 }, + { 0x50338, 0x2e000050 }, + { 0x5fffc, 0x124000b4 }, + { 0x5033c, 0x2d80004c }, + { 0x5fffc, 0x130000b6 }, + { 0x50340, 0x2d000049 }, + { 0x5fffc, 0x140000b8 }, + { 0x50344, 0x2c800045 }, + { 0x5fffc, 0x150000b9 }, + { 0x50348, 0x2c000042 }, + { 0x5fffc, 0x15c000bd }, + { 0x5034c, 0x2b40003e }, + { 0x5fffc, 0x16c000bf }, + { 0x50350, 0x2a80003b }, + { 0x5fffc, 0x17c000bf }, + { 0x50354, 0x2a000039 }, + { 0x5fffc, 0x188000c2 }, + { 0x50358, 0x29400036 }, + { 0x5fffc, 0x19c000c4 }, + { 0x5035c, 0x28800032 }, + { 0x5fffc, 0x1ac000c5 }, + { 0x50360, 0x2800002f }, + { 0x5fffc, 0x1bc000c7 }, + { 0x50364, 0x2740002c }, + { 0x5fffc, 0x1cc000c8 }, + { 0x50368, 0x26c00029 }, + { 0x5fffc, 0x1dc000c9 }, + { 0x5036c, 0x26000027 }, + { 0x5fffc, 0x1ec000cc }, + { 0x50370, 0x25000024 }, + { 0x5fffc, 0x200000cc }, + { 0x50374, 0x24800021 }, + { 0x5fffc, 0x210000cd }, + { 0x50378, 0x23800020 }, + { 0x5fffc, 0x220000ce }, + { 0x5037c, 0x2300001d }, +}; + +static const struct ppp_table downscale_y_table_pt4topt6[] = { + { 0x5fffc, 0x740008c }, + { 0x50300, 0x33800088 }, + { 0x5fffc, 0x800008e }, + { 0x50304, 0x33400084 }, + { 0x5fffc, 0x8400092 }, + { 0x50308, 0x33000080 }, + { 0x5fffc, 0x9000094 }, + { 0x5030c, 0x3300007b }, + { 0x5fffc, 0x9c00098 }, + { 0x50310, 0x32400077 }, + { 0x5fffc, 0xa40009b }, + { 0x50314, 0x32000073 }, + { 0x5fffc, 0xb00009d }, + { 0x50318, 0x31c0006f }, + { 0x5fffc, 0xbc000a0 }, + { 0x5031c, 0x3140006b }, + { 0x5fffc, 0xc8000a2 }, + { 0x50320, 0x31000067 }, + { 0x5fffc, 0xd8000a5 }, + { 0x50324, 0x30800062 }, + { 0x5fffc, 0xe4000a8 }, + { 0x50328, 0x2fc0005f }, + { 0x5fffc, 0xec000aa }, + { 0x5032c, 0x2fc0005b }, + { 0x5fffc, 0xf8000ad }, + { 0x50330, 0x2f400057 }, + { 0x5fffc, 0x108000b0 }, + { 0x50334, 0x2e400054 }, + { 0x5fffc, 0x114000b2 }, + { 0x50338, 0x2e000050 }, + { 0x5fffc, 0x124000b4 }, + { 0x5033c, 0x2d80004c }, + { 0x5fffc, 0x130000b6 }, + { 0x50340, 0x2d000049 }, + { 0x5fffc, 0x140000b8 }, + { 0x50344, 0x2c800045 }, + { 0x5fffc, 0x150000b9 }, + { 0x50348, 0x2c000042 }, + { 0x5fffc, 0x15c000bd }, + { 0x5034c, 0x2b40003e }, + { 0x5fffc, 0x16c000bf }, + { 0x50350, 0x2a80003b }, + { 0x5fffc, 0x17c000bf }, + { 0x50354, 0x2a000039 }, + { 0x5fffc, 0x188000c2 }, + { 0x50358, 0x29400036 }, + { 0x5fffc, 0x19c000c4 }, + { 0x5035c, 0x28800032 }, + { 0x5fffc, 0x1ac000c5 }, + { 0x50360, 0x2800002f }, + { 0x5fffc, 0x1bc000c7 }, + { 0x50364, 0x2740002c }, + { 0x5fffc, 0x1cc000c8 }, + { 0x50368, 0x26c00029 }, + { 0x5fffc, 0x1dc000c9 }, + { 0x5036c, 0x26000027 }, + { 0x5fffc, 0x1ec000cc }, + { 0x50370, 0x25000024 }, + { 0x5fffc, 0x200000cc }, + { 0x50374, 0x24800021 }, + { 0x5fffc, 0x210000cd }, + { 0x50378, 0x23800020 }, + { 0x5fffc, 0x220000ce }, + { 0x5037c, 0x2300001d }, +}; + +static const struct ppp_table downscale_y_table_pt6topt8[] = { + { 0x5fffc, 0xfe000070 }, + { 0x50300, 0x4bc00068 }, + { 0x5fffc, 0xfe000078 }, + { 0x50304, 0x4bc00060 }, + { 0x5fffc, 0xfe000080 }, + { 0x50308, 0x4b800059 }, + { 0x5fffc, 0xfe000089 }, + { 0x5030c, 0x4b000052 }, + { 0x5fffc, 0xfe400091 }, + { 0x50310, 0x4a80004b }, + { 0x5fffc, 0xfe40009a }, + { 0x50314, 0x4a000044 }, + { 0x5fffc, 0xfe8000a3 }, + { 0x50318, 0x4940003d }, + { 0x5fffc, 0xfec000ac }, + { 0x5031c, 0x48400037 }, + { 0x5fffc, 0xff0000b4 }, + { 0x50320, 0x47800031 }, + { 0x5fffc, 0xff8000bd }, + { 0x50324, 0x4640002b }, + { 0x5fffc, 0xc5 }, + { 0x50328, 0x45000026 }, + { 0x5fffc, 0x8000ce }, + { 0x5032c, 0x43800021 }, + { 0x5fffc, 0x10000d6 }, + { 0x50330, 0x4240001c }, + { 0x5fffc, 0x18000df }, + { 0x50334, 0x40800018 }, + { 0x5fffc, 0x24000e6 }, + { 0x50338, 0x3f000014 }, + { 0x5fffc, 0x30000ee }, + { 0x5033c, 0x3d400010 }, + { 0x5fffc, 0x40000f5 }, + { 0x50340, 0x3b80000c }, + { 0x5fffc, 0x50000fc }, + { 0x50344, 0x39800009 }, + { 0x5fffc, 0x6000102 }, + { 0x50348, 0x37c00006 }, + { 0x5fffc, 0x7000109 }, + { 0x5034c, 0x35800004 }, + { 0x5fffc, 0x840010e }, + { 0x50350, 0x33800002 }, + { 0x5fffc, 0x9800114 }, + { 0x50354, 0x31400000 }, + { 0x5fffc, 0xac00119 }, + { 0x50358, 0x2f4003fe }, + { 0x5fffc, 0xc40011e }, + { 0x5035c, 0x2d0003fc }, + { 0x5fffc, 0xdc00121 }, + { 0x50360, 0x2b0003fb }, + { 0x5fffc, 0xf400125 }, + { 0x50364, 0x28c003fa }, + { 0x5fffc, 0x11000128 }, + { 0x50368, 0x268003f9 }, + { 0x5fffc, 0x12c0012a }, + { 0x5036c, 0x244003f9 }, + { 0x5fffc, 0x1480012c }, + { 0x50370, 0x224003f8 }, + { 0x5fffc, 0x1640012e }, + { 0x50374, 0x200003f8 }, + { 0x5fffc, 0x1800012f }, + { 0x50378, 0x1e0003f8 }, + { 0x5fffc, 0x1a00012f }, + { 0x5037c, 0x1c0003f8 }, +}; + +static const struct ppp_table downscale_y_table_pt8topt1[] = { + { 0x5fffc, 0x0 }, + { 0x50300, 0x7fc00000 }, + { 0x5fffc, 0xff80000d }, + { 0x50304, 0x7ec003f9 }, + { 0x5fffc, 0xfec0001c }, + { 0x50308, 0x7d4003f3 }, + { 0x5fffc, 0xfe40002b }, + { 0x5030c, 0x7b8003ed }, + { 0x5fffc, 0xfd80003c }, + { 0x50310, 0x794003e8 }, + { 0x5fffc, 0xfcc0004d }, + { 0x50314, 0x76c003e4 }, + { 0x5fffc, 0xfc40005f }, + { 0x50318, 0x73c003e0 }, + { 0x5fffc, 0xfb800071 }, + { 0x5031c, 0x708003de }, + { 0x5fffc, 0xfac00085 }, + { 0x50320, 0x6d0003db }, + { 0x5fffc, 0xfa000098 }, + { 0x50324, 0x698003d9 }, + { 0x5fffc, 0xf98000ac }, + { 0x50328, 0x654003d8 }, + { 0x5fffc, 0xf8c000c1 }, + { 0x5032c, 0x610003d7 }, + { 0x5fffc, 0xf84000d5 }, + { 0x50330, 0x5c8003d7 }, + { 0x5fffc, 0xf7c000e9 }, + { 0x50334, 0x580003d7 }, + { 0x5fffc, 0xf74000fd }, + { 0x50338, 0x534003d8 }, + { 0x5fffc, 0xf6c00112 }, + { 0x5033c, 0x4e8003d8 }, + { 0x5fffc, 0xf6800126 }, + { 0x50340, 0x494003da }, + { 0x5fffc, 0xf600013a }, + { 0x50344, 0x448003db }, + { 0x5fffc, 0xf600014d }, + { 0x50348, 0x3f4003dd }, + { 0x5fffc, 0xf5c00160 }, + { 0x5034c, 0x3a4003df }, + { 0x5fffc, 0xf5c00172 }, + { 0x50350, 0x354003e1 }, + { 0x5fffc, 0xf5c00184 }, + { 0x50354, 0x304003e3 }, + { 0x5fffc, 0xf6000195 }, + { 0x50358, 0x2b0003e6 }, + { 0x5fffc, 0xf64001a6 }, + { 0x5035c, 0x260003e8 }, + { 0x5fffc, 0xf6c001b4 }, + { 0x50360, 0x214003eb }, + { 0x5fffc, 0xf78001c2 }, + { 0x50364, 0x1c4003ee }, + { 0x5fffc, 0xf80001cf }, + { 0x50368, 0x17c003f1 }, + { 0x5fffc, 0xf90001db }, + { 0x5036c, 0x134003f3 }, + { 0x5fffc, 0xfa0001e5 }, + { 0x50370, 0xf0003f6 }, + { 0x5fffc, 0xfb4001ee }, + { 0x50374, 0xac003f9 }, + { 0x5fffc, 0xfcc001f5 }, + { 0x50378, 0x70003fb }, + { 0x5fffc, 0xfe4001fb }, + { 0x5037c, 0x34003fe }, +}; + +static const struct ppp_table *downscale_y_table[PPP_DOWNSCALE_MAX] = { + [PPP_DOWNSCALE_PT2TOPT4] = downscale_y_table_pt2topt4, + [PPP_DOWNSCALE_PT4TOPT6] = downscale_y_table_pt4topt6, + [PPP_DOWNSCALE_PT6TOPT8] = downscale_y_table_pt6topt8, + [PPP_DOWNSCALE_PT8TOPT1] = downscale_y_table_pt8topt1, +}; + +void ppp_load_table(const struct ppp_table *table, int len) +{ + int i; + + for (i = 0; i < len; i++) + PPP_WRITEL(table[i].val, table[i].reg); +} + +void ppp_load_up_lut(void) +{ + ppp_load_table(upscale_table, + PPP_UPSCALE_MAX); +} + +void ppp_load_gaussian_lut(void) +{ + ppp_load_table(mdp_gaussian_blur_table, + PPP_BLUR_SCALE_MAX); +} + +void ppp_load_x_scale_table(int idx) +{ + ppp_load_table(downscale_x_table[idx], 64); +} + +void ppp_load_y_scale_table(int idx) +{ + ppp_load_table(downscale_y_table[idx], 64); +} + +uint32_t ppp_bpp(uint32_t type) +{ + if (MDP_IS_IMGTYPE_BAD(type)) + return 0; + return bytes_per_pixel[type]; +} + +uint32_t ppp_src_config(uint32_t type) +{ + if (MDP_IS_IMGTYPE_BAD(type)) + return 0; + return src_cfg_lut[type]; +} + +uint32_t ppp_out_config(uint32_t type) +{ + if (MDP_IS_IMGTYPE_BAD(type)) + return 0; + return out_cfg_lut[type]; +} + +uint32_t ppp_pack_pattern(uint32_t type, uint32_t yuv2rgb) +{ + if (MDP_IS_IMGTYPE_BAD(type)) + return 0; + if (yuv2rgb) + return swapped_pack_patt_lut[type]; + + return pack_patt_lut[type]; +} + +uint32_t ppp_dst_op_reg(uint32_t type) +{ + if (MDP_IS_IMGTYPE_BAD(type)) + return 0; + return dst_op_reg[type]; +} + +uint32_t ppp_src_op_reg(uint32_t type) +{ + if (MDP_IS_IMGTYPE_BAD(type)) + return 0; + return src_op_reg[type]; +} + +bool ppp_per_p_alpha(uint32_t type) +{ + if (MDP_IS_IMGTYPE_BAD(type)) + return 0; + return per_pixel_alpha[type]; +} + +bool ppp_multi_plane(uint32_t type) +{ + if (MDP_IS_IMGTYPE_BAD(type)) + return 0; + return multi_plane[type]; +} + +uint32_t *ppp_default_pre_lut(void) +{ + return default_pre_lut_val; +} + +uint32_t *ppp_default_post_lut(void) +{ + return default_post_lut_val; +} + +struct ppp_csc_table *ppp_csc_rgb2yuv(void) +{ + return &rgb2yuv; +} + +struct ppp_csc_table *ppp_csc_table2(void) +{ + return &default_table2; +} diff --git a/drivers/video/fbdev/msm/mdp3_ppp_hwio.c b/drivers/video/fbdev/msm/mdp3_ppp_hwio.c new file mode 100644 index 000000000000..15f240989b4b --- /dev/null +++ b/drivers/video/fbdev/msm/mdp3_ppp_hwio.c @@ -0,0 +1,1365 @@ +/* Copyright (c) 2007, 2012-2013, 2016-2018, The Linux Foundation. All rights reserved. + * Copyright (C) 2007 Google Incorporated + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include "linux/proc_fs.h" + +#include "mdss_fb.h" +#include "mdp3_ppp.h" +#include "mdp3_hwio.h" +#include "mdss_debug.h" + +/* SHIM Q Factor */ +#define PHI_Q_FACTOR 29 +#define PQF_PLUS_5 (PHI_Q_FACTOR + 5) /* due to 32 phases */ +#define PQF_PLUS_4 (PHI_Q_FACTOR + 4) +#define PQF_PLUS_2 (PHI_Q_FACTOR + 2) /* to get 4.0 */ +#define PQF_MINUS_2 (PHI_Q_FACTOR - 2) /* to get 0.25 */ +#define PQF_PLUS_5_PLUS_2 (PQF_PLUS_5 + 2) +#define PQF_PLUS_5_MINUS_2 (PQF_PLUS_5 - 2) + +enum { + LAYER_FG = 0, + LAYER_BG, + LAYER_FB, + LAYER_MAX, +}; + +static long long mdp_do_div(uint64_t num, uint64_t den) +{ + do_div(num, den); + return num; +} + +static int mdp_calc_scale_params(uint32_t org, uint32_t dim_in, + uint32_t dim_out, bool is_W, int32_t *phase_init_ptr, + uint32_t *phase_step_ptr) +{ + bool rpa_on = false; + int init_phase = 0; + uint64_t numer = 0; + uint64_t denom = 0; + int64_t point5 = 1; + int64_t one = 1; + int64_t k1, k2, k3, k4; /* linear equation coefficients */ + uint64_t int_mask; + uint64_t fract_mask; + uint64_t Os; + int64_t Osprime; + int64_t Od; + int64_t Odprime; + int64_t Oreq; + int64_t init_phase_temp; + int64_t delta; + uint32_t mult; + + /* + * The phase accumulator should really be rational for all cases in a + * general purpose polyphase scaler for a tiled architecture with + * non-zero * origin capability because there is no way to represent + * certain scale factors in fixed point regardless of precision. + * The error incurred in attempting to use fixed point is most + * eggregious for SF where 1/SF is an integral multiple of 1/3. + * + * Set the RPA flag for this dimension. + * + * In order for 1/SF (dim_in/dim_out) to be an integral multiple of + * 1/3, dim_out must be an integral multiple of 3. + */ + if (!(dim_out % 3)) { + mult = dim_out / 3; + rpa_on = (!(dim_in % mult)); + } + + numer = dim_out; + denom = dim_in; + + /* + * convert to U30.34 before division + * + * The K vectors carry 4 extra bits of precision + * and are rounded. + * + * We initially go 5 bits over then round by adding + * 1 and right shifting by 1 + * so final result is U31.33 + */ + numer <<= PQF_PLUS_5; + + /* now calculate the scale factor (aka k3) */ + k3 = ((mdp_do_div(numer, denom) + 1) >> 1); + + /* check scale factor for legal range [0.25 - 4.0] */ + if (((k3 >> 4) < (1LL << PQF_MINUS_2)) || + ((k3 >> 4) > (1LL << PQF_PLUS_2))) { + return -EINVAL; + } + + /* calculate inverse scale factor (aka k1) for phase init */ + numer = dim_in; + denom = dim_out; + numer <<= PQF_PLUS_5; + k1 = ((mdp_do_div(numer, denom) + 1) >> 1); + + /* + * calculate initial phase and ROI overfetch + */ + /* convert point5 & one to S39.24 (will always be positive) */ + point5 <<= (PQF_PLUS_4 - 1); + one <<= PQF_PLUS_4; + k2 = ((k1 - one) >> 1); + init_phase = (int)(k2 >> 4); + k4 = ((k3 - one) >> 1); + if (k3 != one) { + /* calculate the masks */ + fract_mask = one - 1; + int_mask = ~fract_mask; + + if (!rpa_on) { + /* + * FIXED POINT IMPLEMENTATION + */ + if (org) { + /* + * The complicated case; ROI origin != 0 + * init_phase needs to be adjusted + * OF is also position dependent + */ + + /* map (org - .5) into destination space */ + Os = ((uint64_t) org << 1) - 1; + Od = ((k3 * Os) >> 1) + k4; + + /* take the ceiling */ + Odprime = (Od & int_mask); + if (Odprime != Od) + Odprime += one; + + /* now map that back to source space */ + Osprime = (k1 * (Odprime >> PQF_PLUS_4)) + k2; + + /* then floor & decrement to calc the required + * starting coordinate + */ + Oreq = (Osprime & int_mask) - one; + + /* calculate initial phase */ + init_phase_temp = Osprime - Oreq; + delta = ((int64_t) (org) << PQF_PLUS_4) - Oreq; + init_phase_temp -= delta; + + /* limit to valid range before left shift */ + delta = (init_phase_temp & (1LL << 63)) ? + 4 : -4; + delta <<= PQF_PLUS_4; + while (abs((int)(init_phase_temp >> + PQF_PLUS_4)) > 4) + init_phase_temp += delta; + + /* + * right shift to account for extra bits of + * precision + */ + init_phase = (int)(init_phase_temp >> 4); + + } + } else { + /* + * RPA IMPLEMENTATION + * + * init_phase needs to be calculated in all RPA_on + * cases because it's a numerator, not a fixed + * point value. + */ + + /* map (org - .5) into destination space */ + Os = ((uint64_t) org << PQF_PLUS_4) - point5; + Od = mdp_do_div((dim_out * (Os + point5)), + dim_in); + Od -= point5; + + /* take the ceiling */ + Odprime = (Od & int_mask); + if (Odprime != Od) + Odprime += one; + + /* now map that back to source space */ + Osprime = + mdp_do_div((dim_in * (Odprime + point5)), + dim_out); + Osprime -= point5; + + /* + * then floor & decrement to calculate the required + * starting coordinate + */ + Oreq = (Osprime & int_mask) - one; + + /* calculate initial phase */ + init_phase_temp = Osprime - Oreq; + delta = ((int64_t) (org) << PQF_PLUS_4) - Oreq; + init_phase_temp -= delta; + + /* limit to valid range before the left shift */ + delta = (init_phase_temp & (1LL << 63)) ? 4 : -4; + delta <<= PQF_PLUS_4; + while (abs((int)(init_phase_temp >> PQF_PLUS_4)) > 4) + init_phase_temp += delta; + + /* + * right shift to account for extra bits of precision + */ + init_phase = (int)(init_phase_temp >> 4); + } + } + + /* return the scale parameters */ + *phase_init_ptr = init_phase; + *phase_step_ptr = (uint32_t) (k1 >> 4); + + return 0; +} + +static int scale_idx(int factor) +{ + int idx; + + if (factor > 80) + idx = PPP_DOWNSCALE_PT8TOPT1; + else if (factor > 60) + idx = PPP_DOWNSCALE_PT6TOPT8; + else if (factor > 40) + idx = PPP_DOWNSCALE_PT4TOPT6; + else + idx = PPP_DOWNSCALE_PT2TOPT4; + + return idx; +} + +inline int32_t comp_conv_rgb2yuv(int32_t comp, int32_t y_high, + int32_t y_low, int32_t c_high, int32_t c_low) +{ + if (comp < 0) + comp = 0; + if (comp > 255) + comp = 255; + + /* clamp */ + if (comp < y_low) + comp = y_low; + if (comp > y_high) + comp = y_high; + return comp; +} + +static uint32_t conv_rgb2yuv(uint32_t input_pixel, + uint16_t *matrix_vector, + uint16_t *bv, + uint16_t *clamp_vector) +{ + uint8_t input_C2, input_C0, input_C1; + uint32_t output; + int32_t comp_C2, comp_C1, comp_C0, temp; + int32_t temp1, temp2, temp3; + int32_t matrix[9]; + int32_t bias_vector[3]; + int32_t Y_low_limit, Y_high_limit, C_low_limit, C_high_limit; + int32_t i; + + input_C2 = (input_pixel >> 16) & 0xFF; + input_C1 = (input_pixel >> 8) & 0xFF; + input_C0 = (input_pixel >> 0) & 0xFF; + + comp_C0 = input_C0; + comp_C1 = input_C1; + comp_C2 = input_C2; + + for (i = 0; i < MDP_CSC_SIZE; i++) + matrix[i] = + ((int32_t) (((int32_t) matrix_vector[i]) << 20)) >> 20; + + bias_vector[0] = (int32_t) (bv[0] & 0xFF); + bias_vector[1] = (int32_t) (bv[1] & 0xFF); + bias_vector[2] = (int32_t) (bv[2] & 0xFF); + + Y_low_limit = (int32_t) clamp_vector[0]; + Y_high_limit = (int32_t) clamp_vector[1]; + C_low_limit = (int32_t) clamp_vector[2]; + C_high_limit = (int32_t) clamp_vector[3]; + + /* + * Color Conversion + * reorder input colors + */ + temp = comp_C2; + comp_C2 = comp_C1; + comp_C1 = comp_C0; + comp_C0 = temp; + + /* matrix multiplication */ + temp1 = comp_C0 * matrix[0] + comp_C1 * matrix[1] + + comp_C2 * matrix[2]; + temp2 = comp_C0 * matrix[3] + comp_C1 * matrix[4] + + comp_C2 * matrix[5]; + temp3 = comp_C0 * matrix[6] + comp_C1 * matrix[7] + + comp_C2 * matrix[8]; + + comp_C0 = temp1 + 0x100; + comp_C1 = temp2 + 0x100; + comp_C2 = temp3 + 0x100; + + /* take integer part */ + comp_C0 >>= 9; + comp_C1 >>= 9; + comp_C2 >>= 9; + + /* post bias (+) */ + comp_C0 += bias_vector[0]; + comp_C1 += bias_vector[1]; + comp_C2 += bias_vector[2]; + + /* limit pixel to 8-bit */ + comp_C0 = comp_conv_rgb2yuv(comp_C0, Y_high_limit, + Y_low_limit, C_high_limit, C_low_limit); + comp_C1 = comp_conv_rgb2yuv(comp_C1, Y_high_limit, + Y_low_limit, C_high_limit, C_low_limit); + comp_C2 = comp_conv_rgb2yuv(comp_C2, Y_high_limit, + Y_low_limit, C_high_limit, C_low_limit); + + output = (comp_C2 << 16) | (comp_C1 << 8) | comp_C0; + return output; +} + +inline void y_h_even_num(struct ppp_img_desc *img) +{ + img->roi.y = (img->roi.y / 2) * 2; + img->roi.height = (img->roi.height / 2) * 2; +} + +inline void x_w_even_num(struct ppp_img_desc *img) +{ + img->roi.x = (img->roi.x / 2) * 2; + img->roi.width = (img->roi.width / 2) * 2; +} + +bool check_if_rgb(int color) +{ + bool rgb = false; + + switch (color) { + case MDP_RGB_565: + case MDP_BGR_565: + case MDP_RGB_888: + case MDP_BGR_888: + case MDP_BGRA_8888: + case MDP_RGBA_8888: + case MDP_ARGB_8888: + case MDP_XRGB_8888: + case MDP_RGBX_8888: + case MDP_BGRX_8888: + rgb = true; + default: + break; + } + return rgb; +} + +uint8_t *mdp_adjust_rot_addr(struct ppp_blit_op *iBuf, + uint8_t *addr, uint32_t bpp, uint32_t uv, uint32_t layer) +{ + uint32_t ystride = 0; + uint32_t h_slice = 1; + uint32_t roi_width = 0; + uint32_t roi_height = 0; + uint32_t color_fmt = 0; + + if (layer == LAYER_BG) { + ystride = iBuf->bg.prop.width * bpp; + roi_width = iBuf->bg.roi.width; + roi_height = iBuf->bg.roi.height; + color_fmt = iBuf->bg.color_fmt; + } else { + ystride = iBuf->dst.prop.width * bpp; + roi_width = iBuf->dst.roi.width; + roi_height = iBuf->dst.roi.height; + color_fmt = iBuf->dst.color_fmt; + } + if (uv && ((color_fmt == MDP_Y_CBCR_H2V2) || + (color_fmt == MDP_Y_CRCB_H2V2))) + h_slice = 2; + + if (((iBuf->mdp_op & MDPOP_ROT90) == MDPOP_ROT90) ^ + ((iBuf->mdp_op & MDPOP_LR) == MDPOP_LR)) { + addr += (roi_width - MIN(16, roi_width)) * bpp; + } + if ((iBuf->mdp_op & MDPOP_UD) == MDPOP_UD) { + addr += ((roi_height - MIN(16, roi_height))/h_slice) * + ystride; + } + + return addr; +} + +void mdp_adjust_start_addr(struct ppp_blit_op *blit_op, + struct ppp_img_desc *img, int v_slice, + int h_slice, uint32_t layer) +{ + uint32_t bpp = ppp_bpp(img->color_fmt); + int x = img->roi.x; + int y = img->roi.y; + uint32_t width = img->prop.width; + + if (img->color_fmt == MDP_Y_CBCR_H2V2_ADRENO && layer == 0) + img->p0 += (x + y * ALIGN(width, 32)) * bpp; + else if (img->color_fmt == MDP_Y_CBCR_H2V2_VENUS && layer == 0) + img->p0 += (x + y * ALIGN(width, 128)) * bpp; + else + img->p0 += (x + y * width) * bpp; + if (layer != LAYER_FG) + img->p0 = mdp_adjust_rot_addr(blit_op, img->p0, bpp, 0, layer); + + if (img->p1) { + /* + * MDP_Y_CBCR_H2V2/MDP_Y_CRCB_H2V2 cosite for now + * we need to shift x direction same as y dir for offsite + */ + if ((img->color_fmt == MDP_Y_CBCR_H2V2_ADRENO || + img->color_fmt == MDP_Y_CBCR_H2V2_VENUS) + && layer == 0) + img->p1 += ((x / h_slice) * h_slice + ((y == 0) ? 0 : + (((y + 1) / v_slice - 1) * (ALIGN(width/2, 32) * 2)))) + * bpp; + else + img->p1 += ((x / h_slice) * h_slice + + ((y == 0) ? 0 : ((y + 1) / v_slice - 1) * width)) * bpp; + + if (layer != LAYER_FG) + img->p1 = mdp_adjust_rot_addr(blit_op, + img->p1, bpp, 0, layer); + } +} + +int load_ppp_lut(int tableType, uint32_t *lut) +{ + int i; + uint32_t base_addr; + + base_addr = tableType ? MDP3_PPP_POST_LUT : MDP3_PPP_PRE_LUT; + for (i = 0; i < PPP_LUT_MAX; i++) + PPP_WRITEL(lut[i], base_addr + MDP3_PPP_LUTn(i)); + + return 0; +} + +/* Configure Primary CSC Matrix */ +int load_primary_matrix(struct ppp_csc_table *csc) +{ + int i; + + for (i = 0; i < MDP_CSC_SIZE; i++) + PPP_WRITEL(csc->fwd_matrix[i], MDP3_PPP_CSC_PFMVn(i)); + + for (i = 0; i < MDP_CSC_SIZE; i++) + PPP_WRITEL(csc->rev_matrix[i], MDP3_PPP_CSC_PRMVn(i)); + + for (i = 0; i < MDP_BV_SIZE; i++) + PPP_WRITEL(csc->bv[i], MDP3_PPP_CSC_PBVn(i)); + + for (i = 0; i < MDP_LV_SIZE; i++) + PPP_WRITEL(csc->lv[i], MDP3_PPP_CSC_PLVn(i)); + + return 0; +} + +/* Load Secondary CSC Matrix */ +int load_secondary_matrix(struct ppp_csc_table *csc) +{ + int i; + + for (i = 0; i < MDP_CSC_SIZE; i++) + PPP_WRITEL(csc->fwd_matrix[i], MDP3_PPP_CSC_SFMVn(i)); + + for (i = 0; i < MDP_CSC_SIZE; i++) + PPP_WRITEL(csc->rev_matrix[i], MDP3_PPP_CSC_SRMVn(i)); + + for (i = 0; i < MDP_BV_SIZE; i++) + PPP_WRITEL(csc->bv[i], MDP3_PPP_CSC_SBVn(i)); + + for (i = 0; i < MDP_LV_SIZE; i++) + PPP_WRITEL(csc->lv[i], MDP3_PPP_CSC_SLVn(i)); + return 0; +} + +int load_csc_matrix(int matrix_type, struct ppp_csc_table *csc) +{ + if (matrix_type == CSC_PRIMARY_MATRIX) + return load_primary_matrix(csc); + + return load_secondary_matrix(csc); +} + +int config_ppp_src(struct ppp_img_desc *src, uint32_t yuv2rgb) +{ + uint32_t val; + + val = ((src->roi.height & MDP3_PPP_XY_MASK) << MDP3_PPP_XY_OFFSET) | + (src->roi.width & MDP3_PPP_XY_MASK); + PPP_WRITEL(val, MDP3_PPP_SRC_SIZE); + + PPP_WRITEL(src->p0, MDP3_PPP_SRCP0_ADDR); + PPP_WRITEL(src->p1, MDP3_PPP_SRCP1_ADDR); + PPP_WRITEL(src->p3, MDP3_PPP_SRCP3_ADDR); + + val = (src->stride0 & MDP3_PPP_STRIDE_MASK) | + ((src->stride1 & MDP3_PPP_STRIDE_MASK) << + MDP3_PPP_STRIDE1_OFFSET); + PPP_WRITEL(val, MDP3_PPP_SRC_YSTRIDE1_ADDR); + val = ((src->stride2 & MDP3_PPP_STRIDE_MASK) << + MDP3_PPP_STRIDE1_OFFSET); + PPP_WRITEL(val, MDP3_PPP_SRC_YSTRIDE2_ADDR); + + val = ppp_src_config(src->color_fmt); + val |= (src->roi.x % 2) ? PPP_SRC_BPP_ROI_ODD_X : 0; + val |= (src->roi.y % 2) ? PPP_SRC_BPP_ROI_ODD_Y : 0; + PPP_WRITEL(val, MDP3_PPP_SRC_FORMAT); + PPP_WRITEL(ppp_pack_pattern(src->color_fmt, yuv2rgb), + MDP3_PPP_SRC_UNPACK_PATTERN1); + return 0; +} + +int config_ppp_out(struct ppp_img_desc *dst, uint32_t yuv2rgb) +{ + uint32_t val; + bool pseudoplanr_output = false; + + switch (dst->color_fmt) { + case MDP_Y_CBCR_H2V2: + case MDP_Y_CRCB_H2V2: + case MDP_Y_CBCR_H2V1: + case MDP_Y_CRCB_H2V1: + pseudoplanr_output = true; + break; + default: + break; + } + val = ppp_out_config(dst->color_fmt); + if (pseudoplanr_output) + val |= PPP_DST_PLANE_PSEUDOPLN; + PPP_WRITEL(val, MDP3_PPP_OUT_FORMAT); + PPP_WRITEL(ppp_pack_pattern(dst->color_fmt, yuv2rgb), + MDP3_PPP_OUT_PACK_PATTERN1); + + val = ((dst->roi.height & MDP3_PPP_XY_MASK) << MDP3_PPP_XY_OFFSET) | + (dst->roi.width & MDP3_PPP_XY_MASK); + PPP_WRITEL(val, MDP3_PPP_OUT_SIZE); + + PPP_WRITEL(dst->p0, MDP3_PPP_OUTP0_ADDR); + PPP_WRITEL(dst->p1, MDP3_PPP_OUTP1_ADDR); + PPP_WRITEL(dst->p3, MDP3_PPP_OUTP3_ADDR); + + val = (dst->stride0 & MDP3_PPP_STRIDE_MASK) | + ((dst->stride1 & MDP3_PPP_STRIDE_MASK) << + MDP3_PPP_STRIDE1_OFFSET); + PPP_WRITEL(val, MDP3_PPP_OUT_YSTRIDE1_ADDR); + val = ((dst->stride2 & MDP3_PPP_STRIDE_MASK) << + MDP3_PPP_STRIDE1_OFFSET); + PPP_WRITEL(val, MDP3_PPP_OUT_YSTRIDE2_ADDR); + return 0; +} + +int config_ppp_background(struct ppp_img_desc *bg, uint32_t yuv2rgb) +{ + uint32_t val; + + PPP_WRITEL(bg->p0, MDP3_PPP_BGP0_ADDR); + PPP_WRITEL(bg->p1, MDP3_PPP_BGP1_ADDR); + PPP_WRITEL(bg->p3, MDP3_PPP_BGP3_ADDR); + + val = (bg->stride0 & MDP3_PPP_STRIDE_MASK) | + ((bg->stride1 & MDP3_PPP_STRIDE_MASK) << + MDP3_PPP_STRIDE1_OFFSET); + PPP_WRITEL(val, MDP3_PPP_BG_YSTRIDE1_ADDR); + val = ((bg->stride2 & MDP3_PPP_STRIDE_MASK) << + MDP3_PPP_STRIDE1_OFFSET); + PPP_WRITEL(val, MDP3_PPP_BG_YSTRIDE2_ADDR); + + PPP_WRITEL(ppp_src_config(bg->color_fmt), + MDP3_PPP_BG_FORMAT); + PPP_WRITEL(ppp_pack_pattern(bg->color_fmt, yuv2rgb), + MDP3_PPP_BG_UNPACK_PATTERN1); + return 0; +} + +void ppp_edge_rep_luma_pixel(struct ppp_blit_op *blit_op, + struct ppp_edge_rep *er) +{ + if (blit_op->mdp_op & MDPOP_ASCALE) { + + er->is_scale_enabled = 1; + + if (blit_op->mdp_op & MDPOP_ROT90) { + er->dst_roi_width = blit_op->dst.roi.height; + er->dst_roi_height = blit_op->dst.roi.width; + } else { + er->dst_roi_width = blit_op->dst.roi.width; + er->dst_roi_height = blit_op->dst.roi.height; + } + + /* + * Find out the luma pixels needed for scaling in the + * x direction (LEFT and RIGHT). Locations of pixels are + * relative to the ROI. Upper-left corner of ROI corresponds + * to coordinates (0,0). Also set the number of luma pixel + * to repeat. + */ + if (blit_op->src.roi.width > 3 * er->dst_roi_width) { + /* scale factor < 1/3 */ + er->luma_interp_point_right = + (blit_op->src.roi.width - 1); + } else if (blit_op->src.roi.width == 3 * er->dst_roi_width) { + /* scale factor == 1/3 */ + er->luma_interp_point_right = + (blit_op->src.roi.width - 1) + 1; + er->luma_repeat_right = 1; + } else if ((blit_op->src.roi.width > er->dst_roi_width) && + (blit_op->src.roi.width < 3 * er->dst_roi_width)) { + /* 1/3 < scale factor < 1 */ + er->luma_interp_point_left = -1; + er->luma_interp_point_right = + (blit_op->src.roi.width - 1) + 1; + er->luma_repeat_left = 1; + er->luma_repeat_right = 1; + } else if (blit_op->src.roi.width == er->dst_roi_width) { + /* scale factor == 1 */ + er->luma_interp_point_left = -1; + er->luma_interp_point_right = + (blit_op->src.roi.width - 1) + 2; + er->luma_repeat_left = 1; + er->luma_repeat_right = 2; + } else { + /* scale factor > 1 */ + er->luma_interp_point_left = -2; + er->luma_interp_point_right = + (blit_op->src.roi.width - 1) + 2; + er->luma_repeat_left = 2; + er->luma_repeat_right = 2; + } + + /* + * Find out the number of pixels needed for scaling in the + * y direction (TOP and BOTTOM). Locations of pixels are + * relative to the ROI. Upper-left corner of ROI corresponds + * to coordinates (0,0). Also set the number of luma pixel + * to repeat. + */ + if (blit_op->src.roi.height > 3 * er->dst_roi_height) { + er->luma_interp_point_bottom = + (blit_op->src.roi.height - 1); + } else if (blit_op->src.roi.height == 3 * er->dst_roi_height) { + er->luma_interp_point_bottom = + (blit_op->src.roi.height - 1) + 1; + er->luma_repeat_bottom = 1; + } else if ((blit_op->src.roi.height > er->dst_roi_height) && + (blit_op->src.roi.height < 3 * er->dst_roi_height)) { + er->luma_interp_point_top = -1; + er->luma_interp_point_bottom = + (blit_op->src.roi.height - 1) + 1; + er->luma_repeat_top = 1; + er->luma_repeat_bottom = 1; + } else if (blit_op->src.roi.height == er->dst_roi_height) { + er->luma_interp_point_top = -1; + er->luma_interp_point_bottom = + (blit_op->src.roi.height - 1) + 2; + er->luma_repeat_top = 1; + er->luma_repeat_bottom = 2; + } else { + er->luma_interp_point_top = -2; + er->luma_interp_point_bottom = + (blit_op->src.roi.height - 1) + 2; + er->luma_repeat_top = 2; + er->luma_repeat_bottom = 2; + } + } else { + /* + * Since no scaling needed, Tile Fetch does not require any + * more luma pixel than what the ROI contains. + */ + er->luma_interp_point_right = + (int32_t) (blit_op->src.roi.width - 1); + er->luma_interp_point_bottom = + (int32_t) (blit_op->src.roi.height - 1); + } + /* After adding the ROI offsets, we have locations of + * luma_interp_points relative to the image. + */ + er->luma_interp_point_left += (int32_t) (blit_op->src.roi.x); + er->luma_interp_point_right += (int32_t) (blit_op->src.roi.x); + er->luma_interp_point_top += (int32_t) (blit_op->src.roi.y); + er->luma_interp_point_bottom += (int32_t) (blit_op->src.roi.y); +} + +void ppp_edge_rep_chroma_pixel(struct ppp_blit_op *blit_op, + struct ppp_edge_rep *er) +{ + bool chroma_edge_enable = true; + uint32_t is_yuv_offsite_vertical = 0; + + /* find out which chroma pixels are needed for chroma upsampling. */ + switch (blit_op->src.color_fmt) { + case MDP_Y_CBCR_H2V1: + case MDP_Y_CRCB_H2V1: + case MDP_YCRYCB_H2V1: + er->chroma_interp_point_left = er->luma_interp_point_left >> 1; + er->chroma_interp_point_right = + (er->luma_interp_point_right + 1) >> 1; + er->chroma_interp_point_top = er->luma_interp_point_top; + er->chroma_interp_point_bottom = er->luma_interp_point_bottom; + break; + + case MDP_Y_CBCR_H2V2: + case MDP_Y_CBCR_H2V2_ADRENO: + case MDP_Y_CBCR_H2V2_VENUS: + case MDP_Y_CRCB_H2V2: + er->chroma_interp_point_left = er->luma_interp_point_left >> 1; + er->chroma_interp_point_right = + (er->luma_interp_point_right + 1) >> 1; + er->chroma_interp_point_top = + (er->luma_interp_point_top - 1) >> 1; + er->chroma_interp_point_bottom = + (er->luma_interp_point_bottom + 1) >> 1; + is_yuv_offsite_vertical = 1; + break; + + default: + chroma_edge_enable = false; + er->chroma_interp_point_left = er->luma_interp_point_left; + er->chroma_interp_point_right = er->luma_interp_point_right; + er->chroma_interp_point_top = er->luma_interp_point_top; + er->chroma_interp_point_bottom = er->luma_interp_point_bottom; + + break; + } + + if (chroma_edge_enable) { + /* Defines which chroma pixels belongs to the roi */ + switch (blit_op->src.color_fmt) { + case MDP_Y_CBCR_H2V1: + case MDP_Y_CRCB_H2V1: + case MDP_YCRYCB_H2V1: + er->chroma_bound_left = blit_op->src.roi.x / 2; + /* there are half as many chroma pixel as luma pixels */ + er->chroma_bound_right = + (blit_op->src.roi.width + + blit_op->src.roi.x - 1) / 2; + er->chroma_bound_top = blit_op->src.roi.y; + er->chroma_bound_bottom = + (blit_op->src.roi.height + blit_op->src.roi.y - 1); + break; + case MDP_Y_CBCR_H2V2: + case MDP_Y_CBCR_H2V2_ADRENO: + case MDP_Y_CBCR_H2V2_VENUS: + case MDP_Y_CRCB_H2V2: + /* + * cosite in horizontal dir, and offsite in vertical dir + * width of chroma ROI is 1/2 of size of luma ROI + * height of chroma ROI is 1/2 of size of luma ROI + */ + er->chroma_bound_left = blit_op->src.roi.x / 2; + er->chroma_bound_right = + (blit_op->src.roi.width + + blit_op->src.roi.x - 1) / 2; + er->chroma_bound_top = blit_op->src.roi.y / 2; + er->chroma_bound_bottom = + (blit_op->src.roi.height + + blit_op->src.roi.y - 1) / 2; + break; + + default: + /* + * If no valid chroma sub-sampling format specified, + * assume 4:4:4 ( i.e. fully sampled). + */ + er->chroma_bound_left = blit_op->src.roi.x; + er->chroma_bound_right = blit_op->src.roi.width + + blit_op->src.roi.x - 1; + er->chroma_bound_top = blit_op->src.roi.y; + er->chroma_bound_bottom = + (blit_op->src.roi.height + blit_op->src.roi.y - 1); + break; + } + + /* + * Knowing which chroma pixels are needed, and which chroma + * pixels belong to the ROI (i.e. available for fetching ), + * calculate how many chroma pixels Tile Fetch needs to + * duplicate. If any required chroma pixels falls outside + * of the ROI, Tile Fetch must obtain them by replicating + * pixels. + */ + if (er->chroma_bound_left > er->chroma_interp_point_left) + er->chroma_repeat_left = + er->chroma_bound_left - + er->chroma_interp_point_left; + else + er->chroma_repeat_left = 0; + + if (er->chroma_interp_point_right > er->chroma_bound_right) + er->chroma_repeat_right = + er->chroma_interp_point_right - + er->chroma_bound_right; + else + er->chroma_repeat_right = 0; + + if (er->chroma_bound_top > er->chroma_interp_point_top) + er->chroma_repeat_top = + er->chroma_bound_top - + er->chroma_interp_point_top; + else + er->chroma_repeat_top = 0; + + if (er->chroma_interp_point_bottom > er->chroma_bound_bottom) + er->chroma_repeat_bottom = + er->chroma_interp_point_bottom - + er->chroma_bound_bottom; + else + er->chroma_repeat_bottom = 0; + + if (er->is_scale_enabled && (blit_op->src.roi.height == 1) + && is_yuv_offsite_vertical) { + er->chroma_repeat_bottom = 3; + er->chroma_repeat_top = 0; + } + } +} + +int config_ppp_edge_rep(struct ppp_blit_op *blit_op) +{ + uint32_t reg = 0; + struct ppp_edge_rep er; + + memset(&er, 0, sizeof(er)); + + ppp_edge_rep_luma_pixel(blit_op, &er); + + /* + * After adding the ROI offsets, we have locations of + * chroma_interp_points relative to the image. + */ + er.chroma_interp_point_left = er.luma_interp_point_left; + er.chroma_interp_point_right = er.luma_interp_point_right; + er.chroma_interp_point_top = er.luma_interp_point_top; + er.chroma_interp_point_bottom = er.luma_interp_point_bottom; + + ppp_edge_rep_chroma_pixel(blit_op, &er); + /* ensure repeats are >=0 and no larger than 3 pixels */ + if ((er.chroma_repeat_left < 0) || (er.chroma_repeat_right < 0) || + (er.chroma_repeat_top < 0) || (er.chroma_repeat_bottom < 0)) + return -EINVAL; + if ((er.chroma_repeat_left > 3) || (er.chroma_repeat_right > 3) || + (er.chroma_repeat_top > 3) || (er.chroma_repeat_bottom > 3)) + return -EINVAL; + if ((er.luma_repeat_left < 0) || (er.luma_repeat_right < 0) || + (er.luma_repeat_top < 0) || (er.luma_repeat_bottom < 0)) + return -EINVAL; + if ((er.luma_repeat_left > 3) || (er.luma_repeat_right > 3) || + (er.luma_repeat_top > 3) || (er.luma_repeat_bottom > 3)) + return -EINVAL; + + reg |= (er.chroma_repeat_left & 3) << MDP_LEFT_CHROMA; + reg |= (er.chroma_repeat_right & 3) << MDP_RIGHT_CHROMA; + reg |= (er.chroma_repeat_top & 3) << MDP_TOP_CHROMA; + reg |= (er.chroma_repeat_bottom & 3) << MDP_BOTTOM_CHROMA; + reg |= (er.luma_repeat_left & 3) << MDP_LEFT_LUMA; + reg |= (er.luma_repeat_right & 3) << MDP_RIGHT_LUMA; + reg |= (er.luma_repeat_top & 3) << MDP_TOP_LUMA; + reg |= (er.luma_repeat_bottom & 3) << MDP_BOTTOM_LUMA; + PPP_WRITEL(reg, MDP3_PPP_SRC_EDGE_REP); + return 0; +} + +int config_ppp_bg_edge_rep(struct ppp_blit_op *blit_op) +{ + uint32_t reg = 0; + + switch (blit_op->dst.color_fmt) { + case MDP_Y_CBCR_H2V2: + case MDP_Y_CRCB_H2V2: + if (blit_op->dst.roi.y == 0) + reg |= BIT(MDP_TOP_CHROMA); + + if ((blit_op->dst.roi.y + blit_op->dst.roi.height) == + blit_op->dst.prop.height) { + reg |= BIT(MDP_BOTTOM_CHROMA); + } + + if (((blit_op->dst.roi.x + blit_op->dst.roi.width) == + blit_op->dst.prop.width) && + ((blit_op->dst.roi.width % 2) == 0)) + reg |= BIT(MDP_RIGHT_CHROMA); + break; + case MDP_Y_CBCR_H2V1: + case MDP_Y_CRCB_H2V1: + case MDP_YCRYCB_H2V1: + if (((blit_op->dst.roi.x + blit_op->dst.roi.width) == + blit_op->dst.prop.width) && + ((blit_op->dst.roi.width % 2) == 0)) + reg |= BIT(MDP_RIGHT_CHROMA); + break; + default: + break; + } + PPP_WRITEL(reg, MDP3_PPP_BG_EDGE_REP); + return 0; +} + +int config_ppp_lut(uint32_t *pppop_reg_ptr, int lut_c0_en, + int lut_c1_en, int lut_c2_en) +{ + if (lut_c0_en) + *pppop_reg_ptr |= MDP_LUT_C0_EN; + if (lut_c1_en) + *pppop_reg_ptr |= MDP_LUT_C1_EN; + if (lut_c2_en) + *pppop_reg_ptr |= MDP_LUT_C2_EN; + return 0; +} + +int config_ppp_scale(struct ppp_blit_op *blit_op, uint32_t *pppop_reg_ptr) +{ + struct ppp_img_desc *src = &blit_op->src; + struct ppp_img_desc *dst = &blit_op->dst; + uint32_t dstW, dstH; + uint32_t x_fac, y_fac; + uint32_t mdp_blur = 0; + uint32_t phase_init_x, phase_init_y, phase_step_x, phase_step_y; + int x_idx, y_idx; + + if (blit_op->mdp_op & MDPOP_ASCALE) { + if (blit_op->mdp_op & MDPOP_ROT90) { + dstW = dst->roi.height; + dstH = dst->roi.width; + } else { + dstW = dst->roi.width; + dstH = dst->roi.height; + } + *pppop_reg_ptr |= + (PPP_OP_SCALE_Y_ON | PPP_OP_SCALE_X_ON); + + mdp_blur = blit_op->mdp_op & MDPOP_BLUR; + + if ((dstW != src->roi.width) || + (dstH != src->roi.height) || mdp_blur) { + + /* + * Use source origin as 0 for computing initial + * phase and step size. Incorrect initial phase and + * step size value results in green line issue. + */ + mdp_calc_scale_params(0, + blit_op->src.roi.width, + dstW, 1, &phase_init_x, + &phase_step_x); + mdp_calc_scale_params(0, + blit_op->src.roi.height, + dstH, 0, &phase_init_y, + &phase_step_y); + + PPP_WRITEL(phase_init_x, MDP3_PPP_SCALE_PHASEX_INIT); + PPP_WRITEL(phase_init_y, MDP3_PPP_SCALE_PHASEY_INIT); + PPP_WRITEL(phase_step_x, MDP3_PPP_SCALE_PHASEX_STEP); + PPP_WRITEL(phase_step_y, MDP3_PPP_SCALE_PHASEY_STEP); + + + if (dstW > src->roi.width || dstH > src->roi.height) + ppp_load_up_lut(); + + if (mdp_blur) + ppp_load_gaussian_lut(); + + if (dstW <= src->roi.width) { + x_fac = (dstW * 100) / src->roi.width; + x_idx = scale_idx(x_fac); + ppp_load_x_scale_table(x_idx); + } + if (dstH <= src->roi.height) { + y_fac = (dstH * 100) / src->roi.height; + y_idx = scale_idx(y_fac); + ppp_load_y_scale_table(y_idx); + } + + } else { + blit_op->mdp_op &= ~(MDPOP_ASCALE); + } + } + config_ppp_edge_rep(blit_op); + config_ppp_bg_edge_rep(blit_op); + return 0; +} + +int config_ppp_csc(int src_color, int dst_color, uint32_t *pppop_reg_ptr) +{ + bool inputRGB, outputRGB; + + inputRGB = check_if_rgb(src_color); + outputRGB = check_if_rgb(dst_color); + + if ((!inputRGB) && (outputRGB)) + *pppop_reg_ptr |= PPP_OP_CONVERT_YCBCR2RGB | + PPP_OP_CONVERT_ON; + if ((inputRGB) && (!outputRGB)) + *pppop_reg_ptr |= PPP_OP_CONVERT_ON; + + return 0; +} + +int config_ppp_blend(struct ppp_blit_op *blit_op, + uint32_t *pppop_reg_ptr, + bool is_yuv_smart_blit, int smart_blit_bg_alpha) +{ + struct ppp_csc_table *csc; + uint32_t alpha, trans_color; + uint32_t val = 0; + int c_fmt = blit_op->src.color_fmt; + int bg_alpha; + + csc = ppp_csc_rgb2yuv(); + alpha = blit_op->blend.const_alpha; + trans_color = blit_op->blend.trans_color; + if (blit_op->mdp_op & MDPOP_FG_PM_ALPHA) { + if (ppp_per_p_alpha(c_fmt)) { + *pppop_reg_ptr |= PPP_OP_ROT_ON | + PPP_OP_BLEND_ON | + PPP_OP_BLEND_CONSTANT_ALPHA; + } else { + if ((blit_op->mdp_op & MDPOP_ALPHAB) + && (blit_op->blend.const_alpha == 0xff)) { + blit_op->mdp_op &= ~(MDPOP_ALPHAB); + } + + if ((blit_op->mdp_op & MDPOP_ALPHAB) + || (blit_op->mdp_op & MDPOP_TRANSP)) { + + *pppop_reg_ptr |= PPP_OP_ROT_ON | + PPP_OP_BLEND_ON | + PPP_OP_BLEND_CONSTANT_ALPHA | + PPP_OP_BLEND_ALPHA_BLEND_NORMAL; + } + } + + bg_alpha = PPP_BLEND_BG_USE_ALPHA_SEL | + PPP_BLEND_BG_ALPHA_REVERSE; + + if ((ppp_per_p_alpha(c_fmt)) && !(blit_op->mdp_op & + MDPOP_LAYER_IS_FG)) { + bg_alpha |= PPP_BLEND_BG_SRCPIXEL_ALPHA; + } else { + bg_alpha |= PPP_BLEND_BG_CONSTANT_ALPHA; + bg_alpha |= blit_op->blend.const_alpha << 24; + } + PPP_WRITEL(bg_alpha, MDP3_PPP_BLEND_BG_ALPHA_SEL); + + if (blit_op->mdp_op & MDPOP_TRANSP) + *pppop_reg_ptr |= PPP_BLEND_CALPHA_TRNASP; + } else if (ppp_per_p_alpha(c_fmt)) { + if (blit_op->mdp_op & MDPOP_LAYER_IS_FG) + *pppop_reg_ptr |= PPP_OP_ROT_ON | + PPP_OP_BLEND_ON | + PPP_OP_BLEND_CONSTANT_ALPHA; + else + *pppop_reg_ptr |= PPP_OP_ROT_ON | + PPP_OP_BLEND_ON | + PPP_OP_BLEND_SRCPIXEL_ALPHA; + PPP_WRITEL(0, MDP3_PPP_BLEND_BG_ALPHA_SEL); + } else { + if ((blit_op->mdp_op & MDPOP_ALPHAB) + && (blit_op->blend.const_alpha == 0xff)) { + blit_op->mdp_op &= + ~(MDPOP_ALPHAB); + } + + if ((blit_op->mdp_op & MDPOP_ALPHAB) + || (blit_op->mdp_op & MDPOP_TRANSP)) { + *pppop_reg_ptr |= PPP_OP_ROT_ON | + PPP_OP_BLEND_ON | + PPP_OP_BLEND_CONSTANT_ALPHA | + PPP_OP_BLEND_ALPHA_BLEND_NORMAL; + } + + if (blit_op->mdp_op & MDPOP_TRANSP) + *pppop_reg_ptr |= + PPP_BLEND_CALPHA_TRNASP; + if (is_yuv_smart_blit) { + *pppop_reg_ptr |= PPP_OP_ROT_ON | + PPP_OP_BLEND_ON | + PPP_OP_BLEND_BG_ALPHA | + PPP_OP_BLEND_EQ_REVERSE; + + if (smart_blit_bg_alpha < 0xFF) + bg_alpha = PPP_BLEND_BG_USE_ALPHA_SEL | + PPP_BLEND_BG_DSTPIXEL_ALPHA; + else + bg_alpha = PPP_BLEND_BG_USE_ALPHA_SEL | + PPP_BLEND_BG_DSTPIXEL_ALPHA | + PPP_BLEND_BG_CONSTANT_ALPHA; + + bg_alpha |= smart_blit_bg_alpha << 24; + PPP_WRITEL(bg_alpha, MDP3_PPP_BLEND_BG_ALPHA_SEL); + } else { + PPP_WRITEL(0, MDP3_PPP_BLEND_BG_ALPHA_SEL); + } + } + + if (*pppop_reg_ptr & PPP_OP_BLEND_ON) { + if (is_yuv_smart_blit) + config_ppp_background(&blit_op->bg, 1); + else + config_ppp_background(&blit_op->bg, 0); + + if (blit_op->dst.color_fmt == MDP_YCRYCB_H2V1) { + *pppop_reg_ptr |= PPP_OP_BG_CHROMA_H2V1; + if (blit_op->mdp_op & MDPOP_TRANSP) { + trans_color = conv_rgb2yuv(trans_color, + &csc->fwd_matrix[0], + &csc->bv[0], + &csc->lv[0]); + } + } + } + if (is_yuv_smart_blit) { + PPP_WRITEL(0, MDP3_PPP_BLEND_PARAM); + } else { + val = (alpha << MDP_BLEND_CONST_ALPHA); + val |= (trans_color & MDP_BLEND_TRASP_COL_MASK); + PP_WRITEL(val, MDP3_PPP_BLEND_PARAM); + } + return 0; +} + +int config_ppp_rotation(uint32_t mdp_op, uint32_t *pppop_reg_ptr) +{ + *pppop_reg_ptr |= PPP_OP_ROT_ON; + + if (mdp_op & MDPOP_ROT90) + *pppop_reg_ptr |= PPP_OP_ROT_90; + if (mdp_op & MDPOP_LR) + *pppop_reg_ptr |= PPP_OP_FLIP_LR; + if (mdp_op & MDPOP_UD) + *pppop_reg_ptr |= PPP_OP_FLIP_UD; + + return 0; +} + +int config_ppp_op_mode(struct ppp_blit_op *blit_op) +{ + uint32_t yuv2rgb; + uint32_t ppp_operation_reg = 0; + int sv_slice, sh_slice; + int dv_slice, dh_slice; + static struct ppp_img_desc bg_img_param; + static int bg_alpha; + static int bg_mdp_ops; + bool is_yuv_smart_blit = false; + + /* + * Detect YUV smart blit, + * Check cached BG image plane 0 address is not NILL and + * source color format is YUV than it is YUV smart blit + * mark is_yuv_smart_blit true. + */ + if ((bg_img_param.p0) && + (!(check_if_rgb(blit_op->src.color_fmt)))) + is_yuv_smart_blit = true; + + sv_slice = sh_slice = dv_slice = dh_slice = 1; + + ppp_operation_reg |= ppp_dst_op_reg(blit_op->dst.color_fmt); + switch (blit_op->dst.color_fmt) { + case MDP_Y_CBCR_H2V2: + case MDP_Y_CRCB_H2V2: + y_h_even_num(&blit_op->dst); + y_h_even_num(&blit_op->src); + dv_slice = 2; + /* fall-through */ + case MDP_Y_CBCR_H2V1: + case MDP_Y_CRCB_H2V1: + case MDP_YCRYCB_H2V1: + x_w_even_num(&blit_op->dst); + x_w_even_num(&blit_op->src); + dh_slice = 2; + break; + default: + break; + } + + ppp_operation_reg |= ppp_src_op_reg(blit_op->src.color_fmt); + switch (blit_op->src.color_fmt) { + case MDP_Y_CBCR_H2V2: + case MDP_Y_CBCR_H2V2_ADRENO: + case MDP_Y_CBCR_H2V2_VENUS: + case MDP_Y_CRCB_H2V2: + sh_slice = sv_slice = 2; + break; + case MDP_YCRYCB_H2V1: + x_w_even_num(&blit_op->dst); + x_w_even_num(&blit_op->src); + /* fall-through */ + case MDP_Y_CBCR_H2V1: + case MDP_Y_CRCB_H2V1: + sh_slice = 2; + break; + default: + break; + } + + config_ppp_csc(blit_op->src.color_fmt, + blit_op->dst.color_fmt, &ppp_operation_reg); + yuv2rgb = ppp_operation_reg & PPP_OP_CONVERT_YCBCR2RGB; + + if (blit_op->mdp_op & MDPOP_DITHER) + ppp_operation_reg |= PPP_OP_DITHER_EN; + + if (blit_op->mdp_op & MDPOP_ROTATION) + config_ppp_rotation(blit_op->mdp_op, &ppp_operation_reg); + + if (blit_op->src.color_fmt == MDP_Y_CBCR_H2V2_ADRENO) { + blit_op->src.stride0 = ALIGN(blit_op->src.prop.width, 32) * + ppp_bpp(blit_op->src.color_fmt); + blit_op->src.stride1 = 2 * ALIGN(blit_op->src.prop.width/2, 32); + } else if (blit_op->src.color_fmt == MDP_Y_CBCR_H2V2_VENUS) { + blit_op->src.stride0 = ALIGN(blit_op->src.prop.width, 128) * + ppp_bpp(blit_op->src.color_fmt); + blit_op->src.stride1 = blit_op->src.stride0; + } else { + blit_op->src.stride0 = blit_op->src.prop.width * + ppp_bpp(blit_op->src.color_fmt); + blit_op->src.stride1 = blit_op->src.stride0; + } + + blit_op->dst.stride0 = blit_op->dst.prop.width * + ppp_bpp(blit_op->dst.color_fmt); + + if (ppp_multi_plane(blit_op->dst.color_fmt)) { + blit_op->dst.p1 = blit_op->dst.p0; + blit_op->dst.p1 += blit_op->dst.prop.width * + blit_op->dst.prop.height * + ppp_bpp(blit_op->dst.color_fmt); + } else { + blit_op->dst.p1 = NULL; + } + + if ((bg_img_param.p0) && (!(blit_op->mdp_op & MDPOP_SMART_BLIT))) { + /* + * Use cached smart blit BG layer info in + * smart Blit FG request + */ + blit_op->bg = bg_img_param; + if (check_if_rgb(blit_op->bg.color_fmt)) { + blit_op->bg.p1 = 0; + blit_op->bg.stride1 = 0; + } + memset(&bg_img_param, 0, sizeof(bg_img_param)); + } else { + blit_op->bg = blit_op->dst; + } + /* Cache smart blit BG layer info */ + if (blit_op->mdp_op & MDPOP_SMART_BLIT) + bg_img_param = blit_op->src; + + /* Jumping from Y-Plane to Chroma Plane */ + /* first pixel addr calculation */ + mdp_adjust_start_addr(blit_op, &blit_op->src, sv_slice, + sh_slice, LAYER_FG); + mdp_adjust_start_addr(blit_op, &blit_op->bg, dv_slice, + dh_slice, LAYER_BG); + mdp_adjust_start_addr(blit_op, &blit_op->dst, dv_slice, + dh_slice, LAYER_FB); + + config_ppp_scale(blit_op, &ppp_operation_reg); + + config_ppp_blend(blit_op, &ppp_operation_reg, is_yuv_smart_blit, + bg_alpha); + + config_ppp_src(&blit_op->src, yuv2rgb); + config_ppp_out(&blit_op->dst, yuv2rgb); + + /* Cache Smart blit BG alpha adn MDP OP values */ + if (blit_op->mdp_op & MDPOP_SMART_BLIT) { + bg_alpha = blit_op->blend.const_alpha; + bg_mdp_ops = blit_op->mdp_op; + } else { + bg_alpha = 0; + bg_mdp_ops = 0; + } + pr_debug("BLIT FG Param Fmt %d (x %d,y %d,w %d,h %d), ", + blit_op->src.color_fmt, blit_op->src.prop.x, + blit_op->src.prop.y, blit_op->src.prop.width, + blit_op->src.prop.height); + pr_debug("ROI(x %d,y %d,w %d, h %d) ", + blit_op->src.roi.x, blit_op->src.roi.y, + blit_op->src.roi.width, blit_op->src.roi.height); + pr_debug("Addr_P0 %pK, Stride S0 %d Addr_P1 %pK, Stride S1 %d\n", + blit_op->src.p0, blit_op->src.stride0, + blit_op->src.p1, blit_op->src.stride1); + + if (blit_op->bg.p0 != blit_op->dst.p0) { + pr_debug("BLIT BG Param Fmt %d (x %d,y %d,w %d,h %d), ", + blit_op->bg.color_fmt, blit_op->bg.prop.x, + blit_op->bg.prop.y, blit_op->bg.prop.width, + blit_op->bg.prop.height); + pr_debug("ROI(x %d,y %d, w %d, h %d) ", + blit_op->bg.roi.x, blit_op->bg.roi.y, + blit_op->bg.roi.width, blit_op->bg.roi.height); + pr_debug("Addr %pK, Stride S0 %d Addr_P1 %pK, Stride S1 %d\n", + blit_op->bg.p0, blit_op->bg.stride0, + blit_op->bg.p1, blit_op->bg.stride1); + } + pr_debug("BLIT FB Param Fmt %d (x %d,y %d,w %d,h %d), ", + blit_op->dst.color_fmt, blit_op->dst.prop.x, + blit_op->dst.prop.y, blit_op->dst.prop.width, + blit_op->dst.prop.height); + pr_debug("ROI(x %d,y %d, w %d, h %d) ", + blit_op->dst.roi.x, blit_op->dst.roi.y, + blit_op->dst.roi.width, blit_op->dst.roi.height); + pr_debug("Addr %p, Stride S0 %d Addr_P1 %p, Stride S1 %d\n", + blit_op->dst.p0, blit_op->dst.stride0, + blit_op->dst.p1, blit_op->dst.stride1); + + PPP_WRITEL(ppp_operation_reg, MDP3_PPP_OP_MODE); + mb(); /* make sure everything is written before enable */ + MDSS_XLOG(ppp_operation_reg, blit_op->src.roi.x, blit_op->src.roi.y, + blit_op->src.roi.width, blit_op->src.roi.height); + MDSS_XLOG(blit_op->dst.roi.x, blit_op->dst.roi.y, + blit_op->dst.roi.width, blit_op->dst.roi.height); + return 0; +} + +void ppp_enable(void) +{ + PPP_WRITEL(0x1000, 0x30); + mb(); /* make sure everything is written before enable */ +} + +int mdp3_ppp_init(void) +{ + load_ppp_lut(LUT_PRE_TABLE, ppp_default_pre_lut()); + load_ppp_lut(LUT_POST_TABLE, ppp_default_post_lut()); + load_csc_matrix(CSC_PRIMARY_MATRIX, ppp_csc_rgb2yuv()); + load_csc_matrix(CSC_SECONDARY_MATRIX, ppp_csc_table2()); + return 0; +} diff --git a/drivers/video/fbdev/msm/mdss.h b/drivers/video/fbdev/msm/mdss.h new file mode 100644 index 000000000000..b7b8de427a96 --- /dev/null +++ b/drivers/video/fbdev/msm/mdss.h @@ -0,0 +1,617 @@ +/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef MDSS_H +#define MDSS_H + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "mdss_panel.h" + +#define MAX_DRV_SUP_MMB_BLKS 44 +#define MAX_DRV_SUP_PIPES 10 +#define MAX_CLIENT_NAME_LEN 20 + +#define MDSS_PINCTRL_STATE_DEFAULT "mdss_default" +#define MDSS_PINCTRL_STATE_SLEEP "mdss_sleep" + +enum mdss_mdp_clk_type { + MDSS_CLK_AHB, + MDSS_CLK_AXI, + MDSS_CLK_MDP_CORE, + MDSS_CLK_MDP_LUT, + MDSS_CLK_MDP_VSYNC, + MDSS_CLK_MNOC_AHB, + MDSS_CLK_THROTTLE_AXI, + MDSS_MAX_CLK +}; + +enum mdss_iommu_domain_type { + MDSS_IOMMU_DOMAIN_UNSECURE, + MDSS_IOMMU_DOMAIN_ROT_UNSECURE, + MDSS_IOMMU_DOMAIN_SECURE, + MDSS_IOMMU_DOMAIN_ROT_SECURE, + MDSS_IOMMU_MAX_DOMAIN +}; + +enum mdss_bus_vote_type { + VOTE_INDEX_DISABLE, + VOTE_INDEX_LOW, + VOTE_INDEX_MID, + VOTE_INDEX_HIGH, + VOTE_INDEX_MAX, +}; + +struct mdss_hw_settings { + char __iomem *reg; + u32 val; +}; + +struct mdss_max_bw_settings { + u32 mdss_max_bw_mode; + u32 mdss_max_bw_val; +}; + +struct mdss_debug_inf { + void *debug_data; + void (*debug_enable_clock)(int on); +}; + +struct mdss_perf_tune { + unsigned long min_mdp_clk; + u64 min_bus_vote; +}; + +#define MDSS_IRQ_SUSPEND -1 +#define MDSS_IRQ_RESUME 1 +#define MDSS_IRQ_REQ 0 + +struct mdss_intr { + /* requested intr */ + u32 req; + /* currently enabled intr */ + u32 curr; + int state; + spinlock_t lock; +}; + +struct simplified_prefill_factors { + u32 fmt_mt_nv12_factor; + u32 fmt_mt_factor; + u32 fmt_linear_factor; + u32 scale_factor; + u32 xtra_ff_factor; +}; + +struct mdss_prefill_data { + u32 ot_bytes; + u32 y_buf_bytes; + u32 y_scaler_lines_bilinear; + u32 y_scaler_lines_caf; + u32 post_scaler_pixels; + u32 pp_pixels; + u32 fbc_lines; + u32 ts_threshold; + u32 ts_end; + u32 ts_overhead; + struct mult_factor ts_rate; + struct simplified_prefill_factors prefill_factors; +}; + +struct mdss_mdp_dsc { + u32 num; + char __iomem *base; +}; + +enum mdss_hw_index { + MDSS_HW_MDP, + MDSS_HW_DSI0 = 1, + MDSS_HW_DSI1, + MDSS_HW_HDMI, + MDSS_HW_EDP, + MDSS_HW_MISC, + MDSS_MAX_HW_BLK +}; + +enum mdss_bus_clients { + MDSS_MDP_RT, + MDSS_DSI_RT, + MDSS_HW_RT, + MDSS_MDP_NRT, + MDSS_MAX_BUS_CLIENTS +}; + +struct mdss_pp_block_off { + u32 sspp_igc_lut_off; + u32 vig_pcc_off; + u32 rgb_pcc_off; + u32 dma_pcc_off; + u32 lm_pgc_off; + u32 dspp_gamut_off; + u32 dspp_pcc_off; + u32 dspp_pgc_off; +}; + +enum mdss_hw_quirk { + MDSS_QUIRK_BWCPANIC, + MDSS_QUIRK_ROTCDP, + MDSS_QUIRK_DOWNSCALE_HANG, + MDSS_QUIRK_DSC_RIGHT_ONLY_PU, + MDSS_QUIRK_DSC_2SLICE_PU_THRPUT, + MDSS_QUIRK_DMA_BI_DIR, + MDSS_QUIRK_FMT_PACK_PATTERN, + MDSS_QUIRK_NEED_SECURE_MAP, + MDSS_QUIRK_SRC_SPLIT_ALWAYS, + MDSS_QUIRK_HDR_SUPPORT_ENABLED, + MDSS_QUIRK_MDP_CLK_SET_RATE, + MDSS_QUIRK_MAX, +}; + +enum mdss_hw_capabilities { + MDSS_CAPS_YUV_CONFIG, + MDSS_CAPS_SCM_RESTORE_NOT_REQUIRED, + MDSS_CAPS_3D_MUX_UNDERRUN_RECOVERY_SUPPORTED, + MDSS_CAPS_MIXER_1_FOR_WB, + MDSS_CAPS_QSEED3, + MDSS_CAPS_DEST_SCALER, + MDSS_CAPS_10_BIT_SUPPORTED, + MDSS_CAPS_MAX, +}; + +enum mdss_qos_settings { + MDSS_QOS_PER_PIPE_IB, + MDSS_QOS_OVERHEAD_FACTOR, + MDSS_QOS_CDP, + MDSS_QOS_OTLIM, + MDSS_QOS_PER_PIPE_LUT, + MDSS_QOS_SIMPLIFIED_PREFILL, + MDSS_QOS_VBLANK_PANIC_CTRL, + MDSS_QOS_TS_PREFILL, + MDSS_QOS_REMAPPER, + MDSS_QOS_IB_NOCR, + MDSS_QOS_MAX, +}; + +enum mdss_mdp_pipe_type { + MDSS_MDP_PIPE_TYPE_INVALID = -1, + MDSS_MDP_PIPE_TYPE_VIG = 0, + MDSS_MDP_PIPE_TYPE_RGB, + MDSS_MDP_PIPE_TYPE_DMA, + MDSS_MDP_PIPE_TYPE_CURSOR, + MDSS_MDP_PIPE_TYPE_MAX, +}; + +struct reg_bus_client { + char name[MAX_CLIENT_NAME_LEN]; + short usecase_ndx; + u32 id; + struct list_head list; +}; + +struct mdss_smmu_client { + struct device *dev; + struct dma_iommu_mapping *mmu_mapping; + struct mdss_module_power mp; + struct reg_bus_client *reg_bus_clt; + bool domain_attached; + bool handoff_pending; + char __iomem *mmu_base; +}; + +struct mdss_mdp_qseed3_lut_tbl { + bool valid; + u32 *dir_lut; + u32 *cir_lut; + u32 *sep_lut; +}; + +struct mdss_scaler_block { + u32 vig_scaler_off; + u32 vig_scaler_lut_off; + u32 has_dest_scaler; + char __iomem *dest_base; + u32 ndest_scalers; + u32 *dest_scaler_off; + u32 *dest_scaler_lut_off; + struct mdss_mdp_qseed3_lut_tbl lut_tbl; + + /* + * Lock is mainly to serialize access to LUT. + * LUT values come asynchronously from userspace + * via ioctl. + */ + struct mutex scaler_lock; +}; + +struct mdss_data_type; + +struct mdss_smmu_ops { + int (*smmu_attach)(struct mdss_data_type *mdata); + int (*smmu_detach)(struct mdss_data_type *mdata); + int (*smmu_get_domain_id)(u32 type); + struct dma_buf_attachment * (*smmu_dma_buf_attach)( + struct dma_buf *dma_buf, struct device *devce, + int domain); + int (*smmu_map_dma_buf)(struct dma_buf *dma_buf, + struct sg_table *table, int domain, + dma_addr_t *iova, unsigned long *size, int dir); + void (*smmu_unmap_dma_buf)(struct sg_table *table, int domain, + int dir, struct dma_buf *dma_buf); + int (*smmu_dma_alloc_coherent)(struct device *dev, size_t size, + dma_addr_t *phys, dma_addr_t *iova, void **cpu_addr, + gfp_t gfp, int domain); + void (*smmu_dma_free_coherent)(struct device *dev, size_t size, + void *cpu_addr, dma_addr_t phys, dma_addr_t iova, + int domain); + int (*smmu_map)(int domain, phys_addr_t iova, phys_addr_t phys, int + gfp_order, int prot); + void (*smmu_unmap)(int domain, unsigned long iova, int gfp_order); + char * (*smmu_dsi_alloc_buf)(struct device *dev, int size, + dma_addr_t *dmap, gfp_t gfp); + int (*smmu_dsi_map_buffer)(phys_addr_t phys, unsigned int domain, + unsigned long size, dma_addr_t *dma_addr, + void *cpu_addr, int dir); + void (*smmu_dsi_unmap_buffer)(dma_addr_t dma_addr, int domain, + unsigned long size, int dir); + void (*smmu_deinit)(struct mdss_data_type *mdata); + struct sg_table * (*smmu_sg_table_clone)(struct sg_table *orig_table, + gfp_t gfp_mask, bool padding); +}; + +struct mdss_data_type { + u32 mdp_rev; + struct clk *mdp_clk[MDSS_MAX_CLK]; + struct regulator *fs; + struct regulator *venus; + struct regulator *vdd_cx; + bool batfet_required; + struct regulator *batfet; + bool en_svs_high; + u32 max_mdp_clk_rate; + struct mdss_util_intf *mdss_util; + struct mdss_panel_data *pdata; + unsigned long mdp_clk_rate; + + struct platform_device *pdev; + struct mdss_io_data mdss_io; + struct mdss_io_data vbif_io; + struct mdss_io_data vbif_nrt_io; + char __iomem *mdp_base; + + struct mdss_smmu_client mdss_smmu[MDSS_IOMMU_MAX_DOMAIN]; + struct mdss_smmu_ops smmu_ops; + struct mutex reg_lock; + + /* bitmap to track pipes that have BWC enabled */ + DECLARE_BITMAP(bwc_enable_map, MAX_DRV_SUP_PIPES); + /* bitmap to track hw workarounds */ + DECLARE_BITMAP(mdss_quirk_map, MDSS_QUIRK_MAX); + /* bitmap to track total mmbs in use */ + DECLARE_BITMAP(mmb_alloc_map, MAX_DRV_SUP_MMB_BLKS); + /* bitmap to track qos applicable settings */ + DECLARE_BITMAP(mdss_qos_map, MDSS_QOS_MAX); + /* bitmap to track hw capabilities/features */ + DECLARE_BITMAP(mdss_caps_map, MDSS_CAPS_MAX); + + u32 has_bwc; + /* values used when HW has a common panic/robust LUT */ + u32 default_panic_lut0; + u32 default_panic_lut1; + u32 default_robust_lut; + + /* values used when HW has panic/robust LUTs per pipe */ + u32 default_panic_lut_per_pipe_linear; + u32 default_panic_lut_per_pipe_tile; + u32 default_robust_lut_per_pipe_linear; + u32 default_robust_lut_per_pipe_tile; + + u32 has_decimation; + bool has_fixed_qos_arbiter_enabled; + bool has_panic_ctrl; + u32 wfd_mode; + u32 has_no_lut_read; + atomic_t sd_client_count; + u8 has_wb_ad; + u8 has_non_scalar_rgb; + bool has_src_split; + bool idle_pc_enabled; + bool has_pingpong_split; + bool has_pixel_ram; + bool needs_hist_vote; + bool has_ubwc; + bool has_wb_ubwc; + bool has_separate_rotator; + + u32 default_ot_rd_limit; + u32 default_ot_wr_limit; + + struct irq_domain *irq_domain; + u32 *mdp_irq_mask; + u32 mdp_hist_irq_mask; + u32 mdp_intf_irq_mask; + + int suspend_fs_ena; + u8 clk_ena; + u8 fs_ena; + u8 vsync_ena; + + struct notifier_block gdsc_cb; + + u32 res_init; + + u32 highest_bank_bit; + u32 smp_mb_cnt; + u32 smp_mb_size; + u32 smp_mb_per_pipe; + u32 pixel_ram_size; + + u32 rot_block_size; + + /* HW RT bus (AXI) */ + u32 hw_rt_bus_hdl; + u32 hw_rt_bus_ref_cnt; + + /* data bus (AXI) */ + u32 bus_hdl; + u32 bus_ref_cnt; + struct mutex bus_lock; + + /* register bus (AHB) */ + u32 reg_bus_hdl; + u32 reg_bus_usecase_ndx; + struct list_head reg_bus_clist; + struct mutex reg_bus_lock; + struct reg_bus_client *reg_bus_clt; + struct reg_bus_client *pp_reg_bus_clt; + + u32 axi_port_cnt; + u32 nrt_axi_port_cnt; + u32 bus_channels; + u32 curr_bw_uc_idx; + u32 ao_bw_uc_idx; /* active only idx */ + struct msm_bus_scale_pdata *bus_scale_table; + struct msm_bus_scale_pdata *reg_bus_scale_table; + struct msm_bus_scale_pdata *hw_rt_bus_scale_table; + u32 max_bw_low; + u32 max_bw_high; + u32 max_bw_per_pipe; + u32 *vbif_rt_qos; + u32 *vbif_nrt_qos; + u32 npriority_lvl; + u32 rot_dwnscale_min; + u32 rot_dwnscale_max; + + struct mult_factor ab_factor; + struct mult_factor ib_factor; + struct mult_factor ib_factor_overlap; + struct mult_factor clk_factor; + struct mult_factor per_pipe_ib_factor; + bool apply_post_scale_bytes; + bool hflip_buffer_reused; + + u32 disable_prefill; + u32 *clock_levels; + u32 nclk_lvl; + + u32 enable_gate; + u32 enable_bw_release; + u32 enable_rotator_bw_release; + u32 enable_cdp; + u32 serialize_wait4pp; + u32 wait4autorefresh; + u32 lines_before_active; + + struct mdss_hw_settings *hw_settings; + + int rects_per_sspp[MDSS_MDP_PIPE_TYPE_MAX]; + struct mdss_mdp_pipe *vig_pipes; + struct mdss_mdp_pipe *rgb_pipes; + struct mdss_mdp_pipe *dma_pipes; + struct mdss_mdp_pipe *cursor_pipes; + u32 nvig_pipes; + u32 nrgb_pipes; + u32 ndma_pipes; + u32 max_target_zorder; + u8 ncursor_pipes; + u32 max_cursor_size; + + u32 nppb_ctl; + u32 *ppb_ctl; + u32 nppb_cfg; + u32 *ppb_cfg; + char __iomem *slave_pingpong_base; + + struct mdss_mdp_mixer *mixer_intf; + struct mdss_mdp_mixer *mixer_wb; + u32 nmixers_intf; + u32 nmixers_wb; + u32 max_mixer_width; + u32 max_pipe_width; + + struct mdss_mdp_writeback *wb; + u32 nwb; + u32 *wb_offsets; + u32 nwb_offsets; + struct mutex wb_lock; + + struct mdss_mdp_ctl *ctl_off; + u32 nctl; + u32 ndspp; + + struct mdss_mdp_dp_intf *dp_off; + u32 ndp; + void *video_intf; + u32 nintf; + + struct mdss_mdp_ad *ad_off; + struct mdss_ad_info *ad_cfgs; + u32 nad_cfgs; + u32 nmax_concurrent_ad_hw; + struct workqueue_struct *ad_calc_wq; + u32 ad_debugen; + bool mem_retain; + + struct mdss_intr hist_intr; + + struct ion_client *iclient; + int iommu_attached; + + struct debug_bus *dbg_bus; + u32 dbg_bus_size; + struct vbif_debug_bus *vbif_dbg_bus; + u32 vbif_dbg_bus_size; + struct vbif_debug_bus *nrt_vbif_dbg_bus; + u32 nrt_vbif_dbg_bus_size; + struct mdss_debug_inf debug_inf; + bool mixer_switched; + struct mdss_panel_cfg pan_cfg; + struct mdss_prefill_data prefill_data; + u32 min_prefill_lines; /* this changes within different chipsets */ + u32 props; + + int handoff_pending; + bool idle_pc; + struct mdss_perf_tune perf_tune; + bool traffic_shaper_en; + int iommu_ref_cnt; + u32 latency_buff_per; + atomic_t active_intf_cnt; + bool has_rot_dwnscale; + bool regulator_notif_register; + + u64 ab[MDSS_MAX_BUS_CLIENTS]; + u64 ib[MDSS_MAX_BUS_CLIENTS]; + struct mdss_pp_block_off pp_block_off; + + struct mdss_mdp_cdm *cdm_off; + u32 ncdm; + struct mutex cdm_lock; + + struct mdss_mdp_dsc *dsc_off; + u32 ndsc; + + struct mdss_max_bw_settings *max_bw_settings; + u32 bw_mode_bitmap; + u32 max_bw_settings_cnt; + bool bw_limit_pending; + + struct mdss_max_bw_settings *max_per_pipe_bw_settings; + u32 mdss_per_pipe_bw_cnt; + u32 min_bw_per_pipe; + + u32 bcolor0; + u32 bcolor1; + u32 bcolor2; + struct mdss_scaler_block *scaler_off; + + u32 splash_intf_sel; + u32 splash_split_disp; + struct mult_factor bus_throughput_factor; +}; + +extern struct mdss_data_type *mdss_res; + +struct irq_info { + u32 irq; + u32 irq_mask; + u32 irq_wake_mask; + u32 irq_ena; + u32 irq_wake_ena; + u32 irq_buzy; +}; + +struct mdss_hw { + u32 hw_ndx; + void *ptr; + struct irq_info *irq_info; + irqreturn_t (*irq_handler)(int irq, void *ptr); +}; + +struct irq_info *mdss_intr_line(void); +void mdss_bus_bandwidth_ctrl(int enable); +int mdss_iommu_ctrl(int enable); +int mdss_bus_scale_set_quota(int client, u64 ab_quota, u64 ib_quota); +int mdss_update_reg_bus_vote(struct reg_bus_client *bus_client, + u32 usecase_ndx); +struct reg_bus_client *mdss_reg_bus_vote_client_create(char *client_name); +void mdss_reg_bus_vote_client_destroy(struct reg_bus_client *bus_client); + +struct mdss_util_intf { + bool mdp_probe_done; + int (*register_irq)(struct mdss_hw *hw); + void (*enable_irq)(struct mdss_hw *hw); + void (*disable_irq)(struct mdss_hw *hw); + void (*enable_wake_irq)(struct mdss_hw *hw); + void (*disable_wake_irq)(struct mdss_hw *hw); + void (*disable_irq_nosync)(struct mdss_hw *hw); + int (*irq_dispatch)(u32 hw_ndx, int irq, void *ptr); + int (*get_iommu_domain)(u32 type); + int (*iommu_attached)(void); + int (*iommu_ctrl)(int enable); + void (*iommu_lock)(void); + void (*iommu_unlock)(void); + void (*bus_bandwidth_ctrl)(int enable); + int (*bus_scale_set_quota)(int client, u64 ab_quota, u64 ib_quota); + int (*panel_intf_status)(u32 disp_num, u32 intf_type); + struct mdss_panel_cfg* (*panel_intf_type)(int intf_val); + int (*dyn_clk_gating_ctrl)(int enable); + bool (*param_check)(char *param_string); + bool display_disabled; +}; + +struct mdss_util_intf *mdss_get_util_intf(void); +bool mdss_get_irq_enable_state(struct mdss_hw *hw); + +static inline int mdss_get_sd_client_cnt(void) +{ + if (!mdss_res) + return 0; + else + return atomic_read(&mdss_res->sd_client_count); +} + +static inline void mdss_set_quirk(struct mdss_data_type *mdata, + enum mdss_hw_quirk bit) +{ + set_bit(bit, mdata->mdss_quirk_map); +} + +static inline bool mdss_has_quirk(struct mdss_data_type *mdata, + enum mdss_hw_quirk bit) +{ + return test_bit(bit, mdata->mdss_quirk_map); +} + +#define MDSS_VBIF_WRITE(mdata, offset, value, nrt_vbif) \ + (nrt_vbif ? mdss_reg_w(&mdata->vbif_nrt_io, offset, value, 0) :\ + mdss_reg_w(&mdata->vbif_io, offset, value, 0)) +#define MDSS_VBIF_READ(mdata, offset, nrt_vbif) \ + (nrt_vbif ? mdss_reg_r(&mdata->vbif_nrt_io, offset, 0) :\ + mdss_reg_r(&mdata->vbif_io, offset, 0)) +#define MDSS_REG_WRITE(mdata, offset, value) \ + mdss_reg_w(&mdata->mdss_io, offset, value, 0) +#define MDSS_REG_READ(mdata, offset) \ + mdss_reg_r(&mdata->mdss_io, offset, 0) + +#endif /* MDSS_H */ diff --git a/drivers/video/fbdev/msm/mdss_cec_core.c b/drivers/video/fbdev/msm/mdss_cec_core.c new file mode 100644 index 000000000000..23a3ce55c2d6 --- /dev/null +++ b/drivers/video/fbdev/msm/mdss_cec_core.c @@ -0,0 +1,799 @@ +/* Copyright (c) 2015-2016, 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#define pr_fmt(fmt) "%s: " fmt, __func__ + +#include +#include +#include +#include +#include +#include + +#include "mdss_fb.h" +#include "mdss_cec_core.h" + +#define CEC_ENABLE_MASK BIT(0) +#define CEC_WAKEUP_ENABLE_MASK BIT(1) + +struct cec_msg_node { + struct cec_msg msg; + struct list_head list; +}; + +struct cec_ctl { + bool enabled; + bool compliance_enabled; + bool cec_wakeup_en; + + u8 logical_addr; + + spinlock_t lock; + struct list_head msg_head; + struct cec_abstract_init_data init_data; + +}; + +static struct cec_ctl *cec_get_ctl(struct device *dev) +{ + struct fb_info *fbi; + struct msm_fb_data_type *mfd; + struct mdss_panel_info *pinfo; + + if (!dev) { + pr_err("invalid input\n"); + goto error; + } + + fbi = dev_get_drvdata(dev); + if (!fbi) { + pr_err("invalid fbi\n"); + goto error; + } + + mfd = fbi->par; + if (!mfd) { + pr_err("invalid mfd\n"); + goto error; + } + + pinfo = mfd->panel_info; + if (!pinfo) { + pr_err("invalid pinfo\n"); + goto error; + } + + return pinfo->cec_data; + +error: + return NULL; +} + +static int cec_msg_send(struct cec_ctl *ctl, struct cec_msg *msg) +{ + int ret = -EINVAL; + struct cec_ops *ops; + + if (!ctl || !msg) { + pr_err("invalid input\n"); + goto end; + } + + ops = ctl->init_data.ops; + + if (ops && ops->send_msg) + ret = ops->send_msg(ops->data, msg); +end: + return ret; +} + +static void cec_dump_msg(struct cec_ctl *ctl, struct cec_msg *msg) +{ + int i; + unsigned long flags; + + if (!ctl || !msg) { + pr_err("invalid input\n"); + return; + } + + spin_lock_irqsave(&ctl->lock, flags); + pr_debug("==%pS dump start ==\n", + __builtin_return_address(0)); + + pr_debug("cec: sender_id: %d\n", msg->sender_id); + pr_debug("cec: recvr_id: %d\n", msg->recvr_id); + + if (msg->frame_size < 2) { + pr_debug("cec: polling message\n"); + spin_unlock_irqrestore(&ctl->lock, flags); + return; + } + + pr_debug("cec: opcode: %02x\n", msg->opcode); + for (i = 0; i < msg->frame_size - 2; i++) + pr_debug("cec: operand(%2d) : %02x\n", i + 1, msg->operand[i]); + + pr_debug("==%pS dump end ==\n", + __builtin_return_address(0)); + spin_unlock_irqrestore(&ctl->lock, flags); +} + +static int cec_disable(struct cec_ctl *ctl) +{ + unsigned long flags; + int ret = -EINVAL; + struct cec_msg_node *msg_node, *tmp; + struct cec_ops *ops; + + if (!ctl) { + pr_err("Invalid input\n"); + goto end; + } + + spin_lock_irqsave(&ctl->lock, flags); + list_for_each_entry_safe(msg_node, tmp, &ctl->msg_head, list) { + list_del(&msg_node->list); + kfree(msg_node); + } + spin_unlock_irqrestore(&ctl->lock, flags); + + ops = ctl->init_data.ops; + + if (ops && ops->enable) + ret = ops->enable(ops->data, false); + + if (!ret) + ctl->enabled = false; + +end: + return ret; +} + +static int cec_enable(struct cec_ctl *ctl) +{ + int ret = -EINVAL; + struct cec_ops *ops; + + if (!ctl) { + pr_err("Invalid input\n"); + goto end; + } + + INIT_LIST_HEAD(&ctl->msg_head); + + ops = ctl->init_data.ops; + + if (ops && ops->enable) + ret = ops->enable(ops->data, true); + + if (!ret) + ctl->enabled = true; + +end: + return ret; +} + +static int cec_send_abort_opcode(struct cec_ctl *ctl, + struct cec_msg *in_msg, u8 reason_operand) +{ + int i = 0; + struct cec_msg out_msg; + + if (!ctl || !in_msg) { + pr_err("Invalid input\n"); + return -EINVAL; + } + + out_msg.sender_id = 0x4; + out_msg.recvr_id = in_msg->sender_id; + out_msg.opcode = 0x0; /* opcode for feature abort */ + out_msg.operand[i++] = in_msg->opcode; + out_msg.operand[i++] = reason_operand; + out_msg.frame_size = i + 2; + + return cec_msg_send(ctl, &out_msg); +} + +static int cec_msg_parser(struct cec_ctl *ctl, struct cec_msg *in_msg) +{ + int rc = 0, i = 0; + struct cec_msg out_msg; + + if (!ctl || !in_msg) { + pr_err("Invalid input\n"); + rc = -EINVAL; + goto end; + } + + pr_debug("in_msg->opcode = 0x%x\n", in_msg->opcode); + switch (in_msg->opcode) { + case CEC_MSG_SET_OSD_STRING: + /* Set OSD String */ + pr_debug("Recvd OSD Str=[0x%x]\n", + in_msg->operand[3]); + break; + case CEC_MSG_GIVE_PHYS_ADDR: + /* Give Phy Addr */ + pr_debug("Recvd a Give Phy Addr cmd\n"); + + out_msg.sender_id = 0x4; + /* Broadcast */ + out_msg.recvr_id = 0xF; + out_msg.opcode = 0x84; + out_msg.operand[i++] = 0x10; + out_msg.operand[i++] = 0x0; + out_msg.operand[i++] = 0x04; + out_msg.frame_size = i + 2; + + rc = cec_msg_send(ctl, &out_msg); + break; + case CEC_MSG_ABORT: + /* Abort */ + pr_debug("Recvd an abort cmd.\n"); + + /* reason = "Refused" */ + rc = cec_send_abort_opcode(ctl, in_msg, 0x04); + break; + case CEC_MSG_GIVE_OSD_NAME: + /* Give OSD name */ + pr_debug("Recvd 'Give OSD name' cmd.\n"); + + out_msg.sender_id = 0x4; + out_msg.recvr_id = in_msg->sender_id; + out_msg.opcode = 0x47; /* OSD Name */ + /* Display control byte */ + out_msg.operand[i++] = 0x0; + out_msg.operand[i++] = 'H'; + out_msg.operand[i++] = 'e'; + out_msg.operand[i++] = 'l'; + out_msg.operand[i++] = 'l'; + out_msg.operand[i++] = 'o'; + out_msg.operand[i++] = ' '; + out_msg.operand[i++] = 'W'; + out_msg.operand[i++] = 'o'; + out_msg.operand[i++] = 'r'; + out_msg.operand[i++] = 'l'; + out_msg.operand[i++] = 'd'; + out_msg.frame_size = i + 2; + + rc = cec_msg_send(ctl, &out_msg); + break; + case CEC_MSG_GIVE_POWER_STATUS: + /* Give Device Power status */ + pr_debug("Recvd a Power status message\n"); + + out_msg.sender_id = 0x4; + out_msg.recvr_id = in_msg->sender_id; + out_msg.opcode = 0x90; /* OSD String */ + out_msg.operand[i++] = 'H'; + out_msg.operand[i++] = 'e'; + out_msg.operand[i++] = 'l'; + out_msg.operand[i++] = 'l'; + out_msg.operand[i++] = 'o'; + out_msg.operand[i++] = ' '; + out_msg.operand[i++] = 'W'; + out_msg.operand[i++] = 'o'; + out_msg.operand[i++] = 'r'; + out_msg.operand[i++] = 'l'; + out_msg.operand[i++] = 'd'; + out_msg.frame_size = i + 2; + + rc = cec_msg_send(ctl, &out_msg); + break; + case CEC_MSG_ROUTE_CHANGE_CMD: + /* Routing Change cmd */ + case CEC_MSG_SET_STREAM_PATH: + /* Set Stream Path */ + pr_debug("Recvd Set Stream or Routing Change cmd\n"); + + out_msg.sender_id = 0x4; + out_msg.recvr_id = 0xF; /* broadcast this message */ + out_msg.opcode = 0x82; /* Active Source */ + out_msg.operand[i++] = 0x10; + out_msg.operand[i++] = 0x0; + out_msg.frame_size = i + 2; + + rc = cec_msg_send(ctl, &out_msg); + if (rc) + goto end; + + /* sending message */ + memset(&out_msg, 0x0, sizeof(struct cec_msg)); + i = 0; + out_msg.sender_id = 0x4; + out_msg.recvr_id = in_msg->sender_id; + out_msg.opcode = 0x04; /* opcode for Image View On */ + out_msg.frame_size = i + 2; + + rc = cec_msg_send(ctl, &out_msg); + break; + case CEC_MSG_USER_CTRL_PRESS: + /* User Control Pressed */ + pr_debug("User Control Pressed\n"); + break; + case CEC_MSG_USER_CTRL_RELEASE: + /* User Control Released */ + pr_debug("User Control Released\n"); + break; + default: + pr_debug("Recvd an unknown cmd = [%u]\n", + in_msg->opcode); + + /* reason = "Unrecognized opcode" */ + rc = cec_send_abort_opcode(ctl, in_msg, 0x0); + break; + } +end: + return rc; +} + +static int cec_msg_recv(void *data, struct cec_msg *msg) +{ + unsigned long flags; + struct cec_ctl *ctl = data; + struct cec_msg_node *msg_node; + int ret = 0; + + if (!ctl) { + pr_err("invalid input\n"); + ret = -EINVAL; + goto end; + } + + if (!ctl->enabled) { + pr_err("cec not enabled\n"); + ret = -ENODEV; + goto end; + } + + msg_node = kzalloc(sizeof(*msg_node), GFP_KERNEL); + if (!msg_node) { + ret = -ENOMEM; + goto end; + } + + msg_node->msg = *msg; + + pr_debug("CEC read frame done\n"); + cec_dump_msg(ctl, &msg_node->msg); + + spin_lock_irqsave(&ctl->lock, flags); + if (ctl->compliance_enabled) { + spin_unlock_irqrestore(&ctl->lock, flags); + + ret = cec_msg_parser(ctl, &msg_node->msg); + if (ret) + pr_err("msg parsing failed\n"); + + kfree(msg_node); + } else { + list_add_tail(&msg_node->list, &ctl->msg_head); + spin_unlock_irqrestore(&ctl->lock, flags); + + /* wake-up sysfs read_msg context */ + sysfs_notify(ctl->init_data.kobj, "cec", "rd_msg"); + } +end: + return ret; +} + +static ssize_t cec_rda_enable(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t ret = 0; + unsigned long flags; + struct cec_ctl *ctl = cec_get_ctl(dev); + + if (!ctl) { + pr_err("Invalid input\n"); + ret = -EINVAL; + goto end; + } + + spin_lock_irqsave(&ctl->lock, flags); + if (ctl->enabled) { + pr_debug("cec is enabled\n"); + ret = snprintf(buf, PAGE_SIZE, "%d\n", 1); + } else { + pr_err("cec is disabled\n"); + ret = snprintf(buf, PAGE_SIZE, "%d\n", 0); + } + spin_unlock_irqrestore(&ctl->lock, flags); +end: + return ret; +} + +static ssize_t cec_wta_enable(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int val; + bool cec_en; + ssize_t ret; + struct cec_ctl *ctl = cec_get_ctl(dev); + struct cec_ops *ops; + + if (!ctl) { + pr_err("Invalid input\n"); + ret = -EINVAL; + goto end; + } + + ops = ctl->init_data.ops; + + ret = kstrtoint(buf, 10, &val); + if (ret) { + pr_err("kstrtoint failed.\n"); + goto end; + } + + cec_en = (val & CEC_ENABLE_MASK) ? true : false; + + /* bit 1 is used for wakeup feature */ + if ((val & CEC_ENABLE_MASK) && (val & CEC_WAKEUP_ENABLE_MASK)) + ctl->cec_wakeup_en = true; + else + ctl->cec_wakeup_en = false; + + if (ops && ops->wakeup_en) + ops->wakeup_en(ops->data, ctl->cec_wakeup_en); + + if (ctl->enabled == cec_en) { + pr_debug("cec is already %s\n", + cec_en ? "enabled" : "disabled"); + goto bail; + } + + if (cec_en) + ret = cec_enable(ctl); + else + ret = cec_disable(ctl); + + if (ret) + goto end; + +bail: + ret = strnlen(buf, PAGE_SIZE); +end: + return ret; +} + +static ssize_t cec_rda_enable_compliance(struct device *dev, + struct device_attribute *attr, char *buf) +{ + unsigned long flags; + ssize_t ret; + struct cec_ctl *ctl = cec_get_ctl(dev); + + if (!ctl) { + pr_err("Invalid ctl\n"); + return -EINVAL; + } + + spin_lock_irqsave(&ctl->lock, flags); + ret = snprintf(buf, PAGE_SIZE, "%d\n", + ctl->compliance_enabled); + + spin_unlock_irqrestore(&ctl->lock, flags); + + return ret; +} + +static ssize_t cec_wta_enable_compliance(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int val; + ssize_t ret; + struct cec_ctl *ctl = cec_get_ctl(dev); + struct cec_ops *ops; + + if (!ctl) { + pr_err("Invalid ctl\n"); + ret = -EINVAL; + goto end; + } + + ops = ctl->init_data.ops; + + ret = kstrtoint(buf, 10, &val); + if (ret) { + pr_err("kstrtoint failed.\n"); + goto end; + } + + ctl->compliance_enabled = (val == 1) ? true : false; + + if (ctl->compliance_enabled) { + ret = cec_enable(ctl); + if (ret) + goto end; + + ctl->logical_addr = 0x4; + + if (ops && ops->wt_logical_addr) + ops->wt_logical_addr(ops->data, ctl->logical_addr); + + } else { + ctl->logical_addr = 0; + + ret = cec_disable(ctl); + if (ret) + goto end; + } + + ret = strnlen(buf, PAGE_SIZE); +end: + return ret; +} + +static ssize_t cec_rda_logical_addr(struct device *dev, + struct device_attribute *attr, char *buf) +{ + unsigned long flags; + ssize_t ret; + struct cec_ctl *ctl = cec_get_ctl(dev); + + if (!ctl) { + pr_err("Invalid ctl\n"); + return -EINVAL; + } + + spin_lock_irqsave(&ctl->lock, flags); + ret = snprintf(buf, PAGE_SIZE, "%d\n", ctl->logical_addr); + spin_unlock_irqrestore(&ctl->lock, flags); + + return ret; +} + +static ssize_t cec_wta_logical_addr(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int logical_addr; + unsigned long flags; + ssize_t ret = strnlen(buf, PAGE_SIZE); + struct cec_ctl *ctl = cec_get_ctl(dev); + struct cec_ops *ops; + + if (!ctl) { + pr_err("Invalid ctl\n"); + ret = -EINVAL; + goto end; + } + + ops = ctl->init_data.ops; + + ret = kstrtoint(buf, 10, &logical_addr); + if (ret) { + pr_err("kstrtoint failed\n"); + goto end; + } + + if (logical_addr < 0 || logical_addr > 15) { + pr_err("Invalid logical address\n"); + ret = -EINVAL; + goto end; + } + + spin_lock_irqsave(&ctl->lock, flags); + ctl->logical_addr = (u8)logical_addr; + if (ctl->enabled) { + if (ops && ops->wt_logical_addr) + ops->wt_logical_addr(ops->data, ctl->logical_addr); + } + spin_unlock_irqrestore(&ctl->lock, flags); +end: + return ret; +} + +static ssize_t cec_rda_msg(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int i = 0; + unsigned long flags; + struct cec_msg_node *msg_node, *tmp; + struct cec_ctl *ctl = cec_get_ctl(dev); + ssize_t ret; + + if (!ctl) { + pr_err("Invalid ctl\n"); + ret = -EINVAL; + goto end; + } + + if (!ctl->enabled) { + pr_err("cec not enabled\n"); + ret = -EINVAL; + goto end; + } + + spin_lock_irqsave(&ctl->lock, flags); + + if (ctl->compliance_enabled) { + spin_unlock_irqrestore(&ctl->lock, flags); + pr_err("Read no allowed in compliance mode\n"); + ret = -EPERM; + goto end; + } + + if (list_empty_careful(&ctl->msg_head)) { + spin_unlock_irqrestore(&ctl->lock, flags); + pr_err("CEC message queue is empty\n"); + ret = -EINVAL; + goto end; + } + + list_for_each_entry_safe(msg_node, tmp, &ctl->msg_head, list) { + if ((i + 1) * sizeof(struct cec_msg) > PAGE_SIZE) { + pr_debug("Overflowing PAGE_SIZE.\n"); + break; + } + + memcpy(buf + (i * sizeof(struct cec_msg)), &msg_node->msg, + sizeof(struct cec_msg)); + list_del(&msg_node->list); + kfree(msg_node); + i++; + } + + spin_unlock_irqrestore(&ctl->lock, flags); + + ret = i * sizeof(struct cec_msg); +end: + return ret; +} + +static ssize_t cec_wta_msg(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + ssize_t ret; + unsigned long flags; + struct cec_msg *msg = (struct cec_msg *)buf; + struct cec_ctl *ctl = cec_get_ctl(dev); + + if (!ctl) { + pr_err("Invalid ctl\n"); + ret = -EINVAL; + goto end; + } + + spin_lock_irqsave(&ctl->lock, flags); + if (ctl->compliance_enabled) { + spin_unlock_irqrestore(&ctl->lock, flags); + pr_err("Write not allowed in compliance mode\n"); + ret = -EPERM; + goto end; + } + + if (!ctl->enabled) { + spin_unlock_irqrestore(&ctl->lock, flags); + pr_err("CEC is not configed.\n"); + ret = -EPERM; + goto end; + } + spin_unlock_irqrestore(&ctl->lock, flags); + + if (msg->frame_size > MAX_OPERAND_SIZE) { + pr_err("msg frame too big!\n"); + ret = -EINVAL; + goto end; + } + ret = cec_msg_send(ctl, msg); + if (ret) { + pr_err("cec_msg_send failed\n"); + goto end; + } + + ret = sizeof(struct cec_msg); +end: + return ret; +} + +static DEVICE_ATTR(enable, 0644, cec_rda_enable, + cec_wta_enable); +static DEVICE_ATTR(enable_compliance, 0644, + cec_rda_enable_compliance, cec_wta_enable_compliance); +static DEVICE_ATTR(logical_addr, 0600, + cec_rda_logical_addr, cec_wta_logical_addr); +static DEVICE_ATTR(rd_msg, 0444, cec_rda_msg, NULL); +static DEVICE_ATTR(wr_msg, 0600, NULL, cec_wta_msg); + +static struct attribute *cec_fs_attrs[] = { + &dev_attr_enable.attr, + &dev_attr_enable_compliance.attr, + &dev_attr_logical_addr.attr, + &dev_attr_rd_msg.attr, + &dev_attr_wr_msg.attr, + NULL, +}; + +static struct attribute_group cec_fs_attr_group = { + .name = "cec", + .attrs = cec_fs_attrs, +}; + +/** + * cec_abstract_deinit() - Release CEC abstract module + * @input: CEC abstract data + * + * This API release all the resources allocated for this + * module. + * + * Return: 0 on success otherwise error code. + */ +int cec_abstract_deinit(void *input) +{ + struct cec_ctl *ctl = (struct cec_ctl *)input; + + if (!ctl) + return -EINVAL; + + sysfs_remove_group(ctl->init_data.kobj, &cec_fs_attr_group); + + kfree(ctl); + + return 0; +} + +/** + * cec_abstract_init() - Initialize CEC abstract module + * @init_data: data needed to initialize the CEC abstraction module + * + * This API will initialize the CEC abstract module which connects + * CEC client with CEC hardware. It creates sysfs nodes for client + * to read and write CEC messages. It interacts with hardware with + * provided operation function pointers. Also provides callback + * function pointers to let the hardware inform about incoming + * CEC message. + * + * Return: pinter to cec abstract data which needs to be passed + * as parameter with callback functions. + */ +void *cec_abstract_init(struct cec_abstract_init_data *init_data) +{ + struct cec_ctl *ctl = NULL; + int ret = 0; + + if (!init_data) { + pr_err("invalid input\n"); + ret = -EINVAL; + goto end; + } + + ctl = kzalloc(sizeof(*ctl), GFP_KERNEL); + if (!ctl) { + ret = -ENOMEM; + goto end; + } + + /* keep a copy of init data */ + ctl->init_data = *init_data; + + ret = sysfs_create_group(ctl->init_data.kobj, &cec_fs_attr_group); + if (ret) { + pr_err("cec sysfs group creation failed\n"); + goto end; + } + + spin_lock_init(&ctl->lock); + + /* provide callback function pointers */ + if (init_data->cbs) { + init_data->cbs->msg_recv_notify = cec_msg_recv; + init_data->cbs->data = ctl; + } + + return ctl; +end: + kfree(ctl); + return ERR_PTR(ret); +} + diff --git a/drivers/video/fbdev/msm/mdss_cec_core.h b/drivers/video/fbdev/msm/mdss_cec_core.h new file mode 100644 index 000000000000..f8196a0aa384 --- /dev/null +++ b/drivers/video/fbdev/msm/mdss_cec_core.h @@ -0,0 +1,105 @@ +/* Copyright (c) 2015-2016, 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __MDSS_CEC_CORE_H__ +#define __MDSS_CEC_CORE_H__ + +#define MAX_OPERAND_SIZE 14 + +/* total size: HEADER block (1) + opcode block (1) + operands (14) */ +#define MAX_CEC_FRAME_SIZE (MAX_OPERAND_SIZE + 2) + +/* CEC message set */ +#define CEC_MSG_SET_OSD_STRING 0x64 +#define CEC_MSG_GIVE_PHYS_ADDR 0x83 +#define CEC_MSG_ABORT 0xFF +#define CEC_MSG_GIVE_OSD_NAME 0x46 +#define CEC_MSG_GIVE_POWER_STATUS 0x8F +#define CEC_MSG_ROUTE_CHANGE_CMD 0x80 +#define CEC_MSG_SET_STREAM_PATH 0x86 +#define CEC_MSG_USER_CTRL_PRESS 0x44 +#define CEC_MSG_USER_CTRL_RELEASE 0x45 + +/** + * struct cec_msg - CEC message related data + * @sender_id: CEC message initiator's id + * @recvr_id: CEC message destination's id + * @opcode: CEC message opcode + * @operand: CEC message operands corresponding to opcode + * @frame_size: total CEC frame size + * @retransmit: number of re-tries to transmit message + * + * Basic CEC message structure used by both client and driver. + */ +struct cec_msg { + u8 sender_id; + u8 recvr_id; + u8 opcode; + u8 operand[MAX_OPERAND_SIZE]; + u8 frame_size; + u8 retransmit; +}; + +/** + * struct cec_ops - CEC operations function pointers + * @enable: function pointer to enable CEC + * @send_msg: function pointer to send CEC message + * @wt_logical_addr: function pointer to write logical address + * @wakeup_en: function pointer to enable wakeup feature + * @is_wakeup_en: function pointer to query wakeup feature state + * @device_suspend: function pointer to update device suspend state + * @data: pointer to the data needed to send with operation functions + * + * Defines all the operations that abstract module can call + * to programe the CEC driver. + */ +struct cec_ops { + int (*enable)(void *data, bool enable); + int (*send_msg)(void *data, + struct cec_msg *msg); + void (*wt_logical_addr)(void *data, u8 addr); + void (*wakeup_en)(void *data, bool en); + bool (*is_wakeup_en)(void *data); + void (*device_suspend)(void *data, bool suspend); + void *data; +}; + +/** + * struct cec_cbs - CEC callback function pointers + * @msg_recv_notify: function pointer called CEC driver to notify incoming msg + * @data: pointer to data needed to be send with the callback function + * + * Defines callback functions which CEC driver can callback to notify any + * change in the hardware. + */ +struct cec_cbs { + int (*msg_recv_notify)(void *data, struct cec_msg *msg); + void *data; +}; + +/** + * struct cec_abstract_init_data - initalization data for abstract module + * @ops: pointer to struct containing all operation function pointers + * @cbs: pointer to struct containing all callack function pointers + * @kobj: pointer to kobject instance associated with CEC driver. + * + * Defines initialization data needed by init API to initialize the module. + */ +struct cec_abstract_init_data { + struct cec_ops *ops; + struct cec_cbs *cbs; + struct kobject *kobj; +}; + +void *cec_abstract_init(struct cec_abstract_init_data *init_data); +int cec_abstract_deinit(void *input); +#endif /* __MDSS_CEC_CORE_H_*/ diff --git a/drivers/video/fbdev/msm/mdss_compat_utils.c b/drivers/video/fbdev/msm/mdss_compat_utils.c new file mode 100644 index 000000000000..a81f149f59ce --- /dev/null +++ b/drivers/video/fbdev/msm/mdss_compat_utils.c @@ -0,0 +1,4318 @@ +/* + * Copyright (c) 2013-2018, The Linux Foundation. All rights reserved. + * Copyright (C) 1994 Martin Schaller + * + * 2001 - Documented with DocBook + * - Brad Douglas + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include + +#include + +#include "mdss_fb.h" +#include "mdss_compat_utils.h" +#include "mdss_mdp_hwio.h" +#include "mdss_mdp.h" + +#define MSMFB_CURSOR32 _IOW(MSMFB_IOCTL_MAGIC, 130, struct fb_cursor32) +#define MSMFB_SET_LUT32 _IOW(MSMFB_IOCTL_MAGIC, 131, struct fb_cmap32) +#define MSMFB_HISTOGRAM32 _IOWR(MSMFB_IOCTL_MAGIC, 132,\ + struct mdp_histogram_data32) +#define MSMFB_GET_CCS_MATRIX32 _IOWR(MSMFB_IOCTL_MAGIC, 133, struct mdp_ccs32) +#define MSMFB_SET_CCS_MATRIX32 _IOW(MSMFB_IOCTL_MAGIC, 134, struct mdp_ccs32) +#define MSMFB_OVERLAY_SET32 _IOWR(MSMFB_IOCTL_MAGIC, 135,\ + struct mdp_overlay32) + +#define MSMFB_OVERLAY_GET32 _IOR(MSMFB_IOCTL_MAGIC, 140,\ + struct mdp_overlay32) +#define MSMFB_OVERLAY_BLT32 _IOWR(MSMFB_IOCTL_MAGIC, 142,\ + struct msmfb_overlay_blt32) +#define MSMFB_HISTOGRAM_START32 _IOR(MSMFB_IOCTL_MAGIC, 144,\ + struct mdp_histogram_start_req32) + +#define MSMFB_OVERLAY_3D32 _IOWR(MSMFB_IOCTL_MAGIC, 147,\ + struct msmfb_overlay_3d32) + +#define MSMFB_MIXER_INFO32 _IOWR(MSMFB_IOCTL_MAGIC, 148,\ + struct msmfb_mixer_info_req32) +#define MSMFB_MDP_PP32 _IOWR(MSMFB_IOCTL_MAGIC, 156, struct msmfb_mdp_pp32) +#define MSMFB_BUFFER_SYNC32 _IOW(MSMFB_IOCTL_MAGIC, 162, struct mdp_buf_sync32) +#define MSMFB_OVERLAY_PREPARE32 _IOWR(MSMFB_IOCTL_MAGIC, 169, \ + struct mdp_overlay_list32) +#define MSMFB_ATOMIC_COMMIT32 _IOWR(MDP_IOCTL_MAGIC, 128, compat_caddr_t) + +#define MSMFB_ASYNC_POSITION_UPDATE_32 _IOWR(MDP_IOCTL_MAGIC, 129, \ + struct mdp_position_update32) + +static int __copy_layer_pp_info_params(struct mdp_input_layer *layer, + struct mdp_input_layer32 *layer32); + +static unsigned int __do_compat_ioctl_nr(unsigned int cmd32) +{ + unsigned int cmd; + + switch (cmd32) { + case MSMFB_CURSOR32: + cmd = MSMFB_CURSOR; + break; + case MSMFB_SET_LUT32: + cmd = MSMFB_SET_LUT; + break; + case MSMFB_HISTOGRAM32: + cmd = MSMFB_HISTOGRAM; + break; + case MSMFB_GET_CCS_MATRIX32: + cmd = MSMFB_GET_CCS_MATRIX; + break; + case MSMFB_SET_CCS_MATRIX32: + cmd = MSMFB_SET_CCS_MATRIX; + break; + case MSMFB_OVERLAY_SET32: + cmd = MSMFB_OVERLAY_SET; + break; + case MSMFB_OVERLAY_GET32: + cmd = MSMFB_OVERLAY_GET; + break; + case MSMFB_OVERLAY_BLT32: + cmd = MSMFB_OVERLAY_BLT; + break; + case MSMFB_OVERLAY_3D32: + cmd = MSMFB_OVERLAY_3D; + break; + case MSMFB_MIXER_INFO32: + cmd = MSMFB_MIXER_INFO; + break; + case MSMFB_MDP_PP32: + cmd = MSMFB_MDP_PP; + break; + case MSMFB_BUFFER_SYNC32: + cmd = MSMFB_BUFFER_SYNC; + break; + case MSMFB_OVERLAY_PREPARE32: + cmd = MSMFB_OVERLAY_PREPARE; + break; + case MSMFB_ATOMIC_COMMIT32: + cmd = MSMFB_ATOMIC_COMMIT; + break; + case MSMFB_ASYNC_POSITION_UPDATE_32: + cmd = MSMFB_ASYNC_POSITION_UPDATE; + break; + default: + cmd = cmd32; + break; + } + + return cmd; +} + +static void __copy_atomic_commit_struct(struct mdp_layer_commit *commit, + struct mdp_layer_commit32 *commit32) +{ + unsigned int destsize = sizeof(commit->commit_v1.reserved); + unsigned int srcsize = sizeof(commit32->commit_v1.reserved); + unsigned int count = (destsize <= srcsize ? destsize : srcsize); + + commit->version = commit32->version; + commit->commit_v1.flags = commit32->commit_v1.flags; + commit->commit_v1.input_layer_cnt = + commit32->commit_v1.input_layer_cnt; + commit->commit_v1.left_roi = commit32->commit_v1.left_roi; + commit->commit_v1.right_roi = commit32->commit_v1.right_roi; + commit->commit_v1.bl_level = commit32->commit_v1.bl_level; + memcpy(&commit->commit_v1.reserved, &commit32->commit_v1.reserved, + count); +} + +static struct mdp_input_layer32 *__create_layer_list32( + struct mdp_layer_commit32 *commit32, + u32 layer_count) +{ + u32 buffer_size32; + struct mdp_input_layer32 *layer_list32; + int ret; + + buffer_size32 = sizeof(struct mdp_input_layer32) * layer_count; + + layer_list32 = kmalloc(buffer_size32, GFP_KERNEL); + if (!layer_list32) { + layer_list32 = ERR_PTR(-ENOMEM); + goto end; + } + + ret = copy_from_user(layer_list32, + compat_ptr(commit32->commit_v1.input_layers), + sizeof(struct mdp_input_layer32) * layer_count); + if (ret) { + pr_err("layer list32 copy from user failed, ptr %pK\n", + compat_ptr(commit32->commit_v1.input_layers)); + kfree(layer_list32); + ret = -EFAULT; + layer_list32 = ERR_PTR(ret); + } + +end: + return layer_list32; +} + +static int __copy_scale_params(struct mdp_input_layer *layer, + struct mdp_input_layer32 *layer32) +{ + struct mdp_scale_data *scale; + int ret; + + if (!(layer->flags & MDP_LAYER_ENABLE_PIXEL_EXT)) + return 0; + + scale = kmalloc(sizeof(struct mdp_scale_data), GFP_KERNEL); + if (!scale) { + ret = -ENOMEM; + goto end; + } + + /* scale structure size is same for compat and 64bit version */ + ret = copy_from_user(scale, compat_ptr(layer32->scale), + sizeof(struct mdp_scale_data)); + if (ret) { + kfree(scale); + pr_err("scale param copy from user failed, ptr %pK\n", + compat_ptr(layer32->scale)); + ret = -EFAULT; + } else { + layer->scale = scale; + } +end: + return ret; +} + +static struct mdp_input_layer *__create_layer_list( + struct mdp_layer_commit *commit, + struct mdp_input_layer32 *layer_list32, + u32 layer_count) +{ + int i, ret = 0; + u32 buffer_size; + struct mdp_input_layer *layer, *layer_list; + struct mdp_input_layer32 *layer32; + + buffer_size = sizeof(struct mdp_input_layer) * layer_count; + + layer_list = kmalloc(buffer_size, GFP_KERNEL); + if (!layer_list) { + layer_list = ERR_PTR(-ENOMEM); + goto end; + } + + commit->commit_v1.input_layers = layer_list; + + for (i = 0; i < layer_count; i++) { + layer = &layer_list[i]; + layer32 = &layer_list32[i]; + + layer->flags = layer32->flags; + layer->pipe_ndx = layer32->pipe_ndx; + layer->horz_deci = layer32->horz_deci; + layer->vert_deci = layer32->vert_deci; + layer->z_order = layer32->z_order; + layer->transp_mask = layer32->transp_mask; + layer->bg_color = layer32->bg_color; + layer->blend_op = layer32->blend_op; + layer->alpha = layer32->alpha; + layer->color_space = layer32->color_space; + layer->src_rect = layer32->src_rect; + layer->dst_rect = layer32->dst_rect; + layer->buffer = layer32->buffer; + memcpy(&layer->reserved, &layer32->reserved, + sizeof(layer->reserved)); + + layer->scale = NULL; + ret = __copy_scale_params(layer, layer32); + if (ret) + break; + + layer->pp_info = NULL; + ret = __copy_layer_pp_info_params(layer, layer32); + if (ret) + break; + } + + if (ret) { + for (i--; i >= 0; i--) { + kfree(layer_list[i].scale); + mdss_mdp_free_layer_pp_info(&layer_list[i]); + } + kfree(layer_list); + layer_list = ERR_PTR(ret); + } + +end: + return layer_list; +} + +static int __copy_to_user_atomic_commit(struct mdp_layer_commit *commit, + struct mdp_layer_commit32 *commit32, + struct mdp_input_layer32 *layer_list32, + unsigned long argp, u32 layer_count) +{ + int i, ret; + struct mdp_input_layer *layer_list; + + layer_list = commit->commit_v1.input_layers; + + for (i = 0; i < layer_count; i++) + layer_list32[i].error_code = layer_list[i].error_code; + + ret = copy_to_user(compat_ptr(commit32->commit_v1.input_layers), + layer_list32, + sizeof(struct mdp_input_layer32) * layer_count); + if (ret) + goto end; + + ret = copy_to_user(compat_ptr(commit32->commit_v1.output_layer), + commit->commit_v1.output_layer, + sizeof(struct mdp_output_layer)); + if (ret) + goto end; + + commit32->commit_v1.release_fence = + commit->commit_v1.release_fence; + commit32->commit_v1.retire_fence = + commit->commit_v1.retire_fence; + + ret = copy_to_user((void __user *)argp, commit32, + sizeof(struct mdp_layer_commit32)); + +end: + return ret; +} + +static int __compat_atomic_commit(struct fb_info *info, unsigned int cmd, + unsigned long argp, struct file *file) +{ + int ret, i; + struct mdp_layer_commit commit; + struct mdp_layer_commit32 commit32; + u32 layer_count; + struct mdp_input_layer *layer_list = NULL; + struct mdp_input_layer32 *layer_list32 = NULL; + struct mdp_output_layer *output_layer = NULL; + struct mdp_frc_info *frc_info = NULL; + + /* copy top level memory from 32 bit structure to kernel memory */ + ret = copy_from_user(&commit32, (void __user *)argp, + sizeof(struct mdp_layer_commit32)); + if (ret) { + pr_err("%s:copy_from_user failed, ptr %pK\n", __func__, + (void __user *)argp); + ret = -EFAULT; + return ret; + } + + memset(&commit, 0, sizeof(struct mdp_layer_commit)); + __copy_atomic_commit_struct(&commit, &commit32); + + if (commit32.commit_v1.output_layer) { + int buffer_size = sizeof(struct mdp_output_layer); + + output_layer = kzalloc(buffer_size, GFP_KERNEL); + if (!output_layer) + return -ENOMEM; + + ret = copy_from_user(output_layer, + compat_ptr(commit32.commit_v1.output_layer), + buffer_size); + if (ret) { + pr_err("fail to copy output layer from user, ptr %pK\n", + compat_ptr(commit32.commit_v1.output_layer)); + ret = -EFAULT; + goto layer_list_err; + } + + commit.commit_v1.output_layer = output_layer; + } + + layer_count = commit32.commit_v1.input_layer_cnt; + if (layer_count > MAX_LAYER_COUNT) { + ret = -EINVAL; + goto layer_list_err; + } else if (layer_count) { + /* + * allocate memory for layer list in 32bit domain and copy it + * from user + */ + layer_list32 = __create_layer_list32(&commit32, layer_count); + if (IS_ERR_OR_NULL(layer_list32)) { + ret = PTR_ERR(layer_list32); + goto layer_list_err; + } + + /* + * allocate memory for layer list in kernel memory domain and + * copy layer info from 32bit structures to kernel memory + */ + layer_list = __create_layer_list(&commit, layer_list32, + layer_count); + if (IS_ERR_OR_NULL(layer_list)) { + ret = PTR_ERR(layer_list); + goto layer_list_err; + } + } + + if (commit32.commit_v1.frc_info) { + int buffer_size = sizeof(struct mdp_frc_info); + + frc_info = kzalloc(buffer_size, GFP_KERNEL); + if (!frc_info) { + ret = -ENOMEM; + goto frc_err; + } + + ret = copy_from_user(frc_info, + compat_ptr(commit32.commit_v1.frc_info), + buffer_size); + if (ret) { + pr_err("fail to copy frc info from user, ptr %p\n", + compat_ptr(commit32.commit_v1.frc_info)); + kfree(frc_info); + ret = -EFAULT; + goto frc_err; + } + + commit.commit_v1.frc_info = frc_info; + } + + ret = mdss_fb_atomic_commit(info, &commit, file); + if (ret) + pr_err("atomic commit failed ret:%d\n", ret); + + if (layer_count) + __copy_to_user_atomic_commit(&commit, &commit32, layer_list32, + argp, layer_count); + + for (i = 0; i < layer_count; i++) { + kfree(layer_list[i].scale); + mdss_mdp_free_layer_pp_info(&layer_list[i]); + } + + kfree(frc_info); +frc_err: + kfree(layer_list); +layer_list_err: + kfree(layer_list32); + kfree(output_layer); + return ret; +} + +static int __copy_to_user_async_position_update( + struct mdp_position_update *update_pos, + struct mdp_position_update32 *update_pos32, + unsigned long argp, u32 layer_cnt) +{ + int ret; + + ret = copy_to_user(update_pos32->input_layers, + update_pos->input_layers, + sizeof(struct mdp_async_layer) * layer_cnt); + if (ret) + goto end; + + ret = copy_to_user((void __user *) argp, update_pos32, + sizeof(struct mdp_position_update32)); + +end: + return ret; +} + +static struct mdp_async_layer *__create_async_layer_list( + struct mdp_position_update32 *update_pos32, u32 layer_cnt) +{ + u32 buffer_size; + struct mdp_async_layer *layer_list; + int ret; + + buffer_size = sizeof(struct mdp_async_layer) * layer_cnt; + + layer_list = kmalloc(buffer_size, GFP_KERNEL); + if (!layer_list) { + layer_list = ERR_PTR(-ENOMEM); + goto end; + } + + ret = copy_from_user(layer_list, + update_pos32->input_layers, buffer_size); + if (ret) { + pr_err("layer list32 copy from user failed\n"); + kfree(layer_list); + layer_list = ERR_PTR(ret); + } + +end: + return layer_list; +} + +static int __compat_async_position_update(struct fb_info *info, + unsigned int cmd, unsigned long argp) +{ + struct mdp_position_update update_pos; + struct mdp_position_update32 update_pos32; + struct mdp_async_layer *layer_list = NULL; + u32 layer_cnt, ret; + + /* copy top level memory from 32 bit structure to kernel memory */ + ret = copy_from_user(&update_pos32, (void __user *)argp, + sizeof(struct mdp_position_update32)); + if (ret) { + pr_err("%s:copy_from_user failed\n", __func__); + return ret; + } + + update_pos.input_layer_cnt = update_pos32.input_layer_cnt; + layer_cnt = update_pos32.input_layer_cnt; + if ((!layer_cnt) || (layer_cnt > MAX_LAYER_COUNT)) { + pr_err("invalid async layers :%d to update\n", layer_cnt); + return -EINVAL; + } + + layer_list = __create_async_layer_list(&update_pos32, + layer_cnt); + if (IS_ERR_OR_NULL(layer_list)) + return PTR_ERR(layer_list); + + update_pos.input_layers = layer_list; + + ret = mdss_fb_async_position_update(info, &update_pos); + if (ret) + pr_err("async position update failed ret:%d\n", ret); + + ret = __copy_to_user_async_position_update(&update_pos, &update_pos32, + argp, layer_cnt); + if (ret) + pr_err("copy to user of async update position failed\n"); + + kfree(layer_list); + return ret; +} + +static int mdss_fb_compat_buf_sync(struct fb_info *info, unsigned int cmd, + unsigned long arg, struct file *file) +{ + struct mdp_buf_sync32 __user *buf_sync32; + struct mdp_buf_sync __user *buf_sync; + u32 data; + int ret; + + buf_sync = compat_alloc_user_space(sizeof(*buf_sync)); + if (!buf_sync) { + pr_err("%s:%u: compat alloc error [%zu] bytes\n", + __func__, __LINE__, sizeof(*buf_sync)); + return -EINVAL; + } + buf_sync32 = compat_ptr(arg); + + if (copy_in_user(&buf_sync->flags, &buf_sync32->flags, + 3 * sizeof(u32))) + return -EFAULT; + + if (get_user(data, &buf_sync32->acq_fen_fd) || + put_user(compat_ptr(data), &buf_sync->acq_fen_fd) || + get_user(data, &buf_sync32->rel_fen_fd) || + put_user(compat_ptr(data), &buf_sync->rel_fen_fd) || + get_user(data, &buf_sync32->retire_fen_fd) || + put_user(compat_ptr(data), &buf_sync->retire_fen_fd)) + return -EFAULT; + + ret = mdss_fb_do_ioctl(info, cmd, (unsigned long) buf_sync, file); + if (ret) { + pr_err("%s: failed %d\n", __func__, ret); + return ret; + } + + if (copy_in_user(compat_ptr(buf_sync32->rel_fen_fd), + buf_sync->rel_fen_fd, + sizeof(int))) + return -EFAULT; + if (copy_in_user(compat_ptr(buf_sync32->retire_fen_fd), + buf_sync->retire_fen_fd, + sizeof(int))) { + if (buf_sync->flags & MDP_BUF_SYNC_FLAG_RETIRE_FENCE) + return -EFAULT; + pr_debug("%s: no retire fence fd for wb\n", + __func__); + } + + return ret; +} + +static int __from_user_fb_cmap(struct fb_cmap __user *cmap, + struct fb_cmap32 __user *cmap32) +{ + __u32 data; + + if (copy_in_user(&cmap->start, &cmap32->start, 2 * sizeof(__u32))) + return -EFAULT; + + if (get_user(data, &cmap32->red) || + put_user(compat_ptr(data), &cmap->red) || + get_user(data, &cmap32->green) || + put_user(compat_ptr(data), &cmap->green) || + get_user(data, &cmap32->blue) || + put_user(compat_ptr(data), &cmap->blue) || + get_user(data, &cmap32->transp) || + put_user(compat_ptr(data), &cmap->transp)) + return -EFAULT; + + return 0; +} + +static int __to_user_fb_cmap(struct fb_cmap __user *cmap, + struct fb_cmap32 __user *cmap32) +{ + unsigned long data; + + if (copy_in_user(&cmap32->start, &cmap->start, 2 * sizeof(__u32))) + return -EFAULT; + + if (get_user(data, (unsigned long *) &cmap->red) || + put_user((compat_caddr_t) data, &cmap32->red) || + get_user(data, (unsigned long *) &cmap->green) || + put_user((compat_caddr_t) data, &cmap32->green) || + get_user(data, (unsigned long *) &cmap->blue) || + put_user((compat_caddr_t) data, &cmap32->blue) || + get_user(data, (unsigned long *) &cmap->transp) || + put_user((compat_caddr_t) data, &cmap32->transp)) + return -EFAULT; + + return 0; +} + +static int __from_user_fb_image(struct fb_image __user *image, + struct fb_image32 __user *image32) +{ + __u32 data; + + if (copy_in_user(&image->dx, &image32->dx, 6 * sizeof(u32)) || + copy_in_user(&image->depth, &image32->depth, sizeof(u8))) + return -EFAULT; + + if (get_user(data, &image32->data) || + put_user(compat_ptr(data), &image->data)) + return -EFAULT; + + if (__from_user_fb_cmap(&image->cmap, &image32->cmap)) + return -EFAULT; + + return 0; +} + +static int mdss_fb_compat_cursor(struct fb_info *info, unsigned int cmd, + unsigned long arg, struct file *file) +{ + struct fb_cursor32 __user *cursor32; + struct fb_cursor __user *cursor; + __u32 data; + int ret; + + cursor = compat_alloc_user_space(sizeof(*cursor)); + if (!cursor) { + pr_err("%s:%u: compat alloc error [%zu] bytes\n", + __func__, __LINE__, sizeof(*cursor)); + return -EINVAL; + } + cursor32 = compat_ptr(arg); + + if (copy_in_user(&cursor->set, &cursor32->set, 3 * sizeof(u16))) + return -EFAULT; + + if (get_user(data, &cursor32->mask) || + put_user(compat_ptr(data), &cursor->mask)) + return -EFAULT; + + if (copy_in_user(&cursor->hot, &cursor32->hot, sizeof(struct fbcurpos))) + return -EFAULT; + + if (__from_user_fb_image(&cursor->image, &cursor32->image)) + return -EFAULT; + + ret = mdss_fb_do_ioctl(info, cmd, (unsigned long) cursor, file); + return ret; +} + +static int mdss_fb_compat_set_lut(struct fb_info *info, unsigned long arg, + struct file *file) +{ + struct fb_cmap_user __user *cmap; + struct fb_cmap32 __user *cmap32; + __u32 data; + int ret; + + cmap = compat_alloc_user_space(sizeof(*cmap)); + cmap32 = compat_ptr(arg); + + if (copy_in_user(&cmap->start, &cmap32->start, 2 * sizeof(__u32))) + return -EFAULT; + + if (get_user(data, &cmap32->red) || + put_user(compat_ptr(data), &cmap->red) || + get_user(data, &cmap32->green) || + put_user(compat_ptr(data), &cmap->green) || + get_user(data, &cmap32->blue) || + put_user(compat_ptr(data), &cmap->blue) || + get_user(data, &cmap32->transp) || + put_user(compat_ptr(data), &cmap->transp)) + return -EFAULT; + + ret = mdss_fb_do_ioctl(info, MSMFB_SET_LUT, (unsigned long) cmap, file); + if (!ret) + pr_debug("%s: compat ioctl successful\n", __func__); + + return ret; +} + +static int __from_user_sharp_cfg( + struct mdp_sharp_cfg32 __user *sharp_cfg32, + struct mdp_sharp_cfg __user *sharp_cfg) +{ + if (copy_in_user(&sharp_cfg->flags, + &sharp_cfg32->flags, + sizeof(uint32_t)) || + copy_in_user(&sharp_cfg->strength, + &sharp_cfg32->strength, + sizeof(uint32_t)) || + copy_in_user(&sharp_cfg->edge_thr, + &sharp_cfg32->edge_thr, + sizeof(uint32_t)) || + copy_in_user(&sharp_cfg->smooth_thr, + &sharp_cfg32->smooth_thr, + sizeof(uint32_t)) || + copy_in_user(&sharp_cfg->noise_thr, + &sharp_cfg32->noise_thr, + sizeof(uint32_t))) + return -EFAULT; + + return 0; +} + +static int __to_user_sharp_cfg( + struct mdp_sharp_cfg32 __user *sharp_cfg32, + struct mdp_sharp_cfg __user *sharp_cfg) +{ + if (copy_in_user(&sharp_cfg32->flags, + &sharp_cfg->flags, + sizeof(uint32_t)) || + copy_in_user(&sharp_cfg32->strength, + &sharp_cfg->strength, + sizeof(uint32_t)) || + copy_in_user(&sharp_cfg32->edge_thr, + &sharp_cfg->edge_thr, + sizeof(uint32_t)) || + copy_in_user(&sharp_cfg32->smooth_thr, + &sharp_cfg->smooth_thr, + sizeof(uint32_t)) || + copy_in_user(&sharp_cfg32->noise_thr, + &sharp_cfg->noise_thr, + sizeof(uint32_t))) + return -EFAULT; + + return 0; +} + +static int __from_user_histogram_cfg( + struct mdp_histogram_cfg32 __user *hist_cfg32, + struct mdp_histogram_cfg __user *hist_cfg) +{ + if (copy_in_user(&hist_cfg->ops, + &hist_cfg32->ops, + sizeof(uint32_t)) || + copy_in_user(&hist_cfg->block, + &hist_cfg32->block, + sizeof(uint32_t)) || + copy_in_user(&hist_cfg->frame_cnt, + &hist_cfg32->frame_cnt, + sizeof(uint8_t)) || + copy_in_user(&hist_cfg->bit_mask, + &hist_cfg32->bit_mask, + sizeof(uint8_t)) || + copy_in_user(&hist_cfg->num_bins, + &hist_cfg32->num_bins, + sizeof(uint16_t))) + return -EFAULT; + + return 0; +} + +static int __to_user_histogram_cfg( + struct mdp_histogram_cfg32 __user *hist_cfg32, + struct mdp_histogram_cfg __user *hist_cfg) +{ + if (copy_in_user(&hist_cfg32->ops, + &hist_cfg->ops, + sizeof(uint32_t)) || + copy_in_user(&hist_cfg32->block, + &hist_cfg->block, + sizeof(uint32_t)) || + copy_in_user(&hist_cfg32->frame_cnt, + &hist_cfg->frame_cnt, + sizeof(uint8_t)) || + copy_in_user(&hist_cfg32->bit_mask, + &hist_cfg->bit_mask, + sizeof(uint8_t)) || + copy_in_user(&hist_cfg32->num_bins, + &hist_cfg->num_bins, + sizeof(uint16_t))) + return -EFAULT; + + return 0; +} + +static int __from_user_pcc_coeff( + struct mdp_pcc_coeff32 __user *pcc_coeff32, + struct mdp_pcc_coeff __user *pcc_coeff) +{ + if (copy_in_user(&pcc_coeff->c, + &pcc_coeff32->c, + sizeof(uint32_t)) || + copy_in_user(&pcc_coeff->r, + &pcc_coeff32->r, + sizeof(uint32_t)) || + copy_in_user(&pcc_coeff->g, + &pcc_coeff32->g, + sizeof(uint32_t)) || + copy_in_user(&pcc_coeff->b, + &pcc_coeff32->b, + sizeof(uint32_t)) || + copy_in_user(&pcc_coeff->rr, + &pcc_coeff32->rr, + sizeof(uint32_t)) || + copy_in_user(&pcc_coeff->gg, + &pcc_coeff32->gg, + sizeof(uint32_t)) || + copy_in_user(&pcc_coeff->bb, + &pcc_coeff32->bb, + sizeof(uint32_t)) || + copy_in_user(&pcc_coeff->rg, + &pcc_coeff32->rg, + sizeof(uint32_t)) || + copy_in_user(&pcc_coeff->gb, + &pcc_coeff32->gb, + sizeof(uint32_t)) || + copy_in_user(&pcc_coeff->rb, + &pcc_coeff32->rb, + sizeof(uint32_t)) || + copy_in_user(&pcc_coeff->rgb_0, + &pcc_coeff32->rgb_0, + sizeof(uint32_t)) || + copy_in_user(&pcc_coeff->rgb_1, + &pcc_coeff32->rgb_1, + sizeof(uint32_t))) + return -EFAULT; + + return 0; +} + +static int __to_user_pcc_coeff( + struct mdp_pcc_coeff32 __user *pcc_coeff32, + struct mdp_pcc_coeff __user *pcc_coeff) +{ + if (copy_in_user(&pcc_coeff32->c, + &pcc_coeff->c, + sizeof(uint32_t)) || + copy_in_user(&pcc_coeff32->r, + &pcc_coeff->r, + sizeof(uint32_t)) || + copy_in_user(&pcc_coeff32->g, + &pcc_coeff->g, + sizeof(uint32_t)) || + copy_in_user(&pcc_coeff32->b, + &pcc_coeff->b, + sizeof(uint32_t)) || + copy_in_user(&pcc_coeff32->rr, + &pcc_coeff->rr, + sizeof(uint32_t)) || + copy_in_user(&pcc_coeff32->gg, + &pcc_coeff->gg, + sizeof(uint32_t)) || + copy_in_user(&pcc_coeff32->bb, + &pcc_coeff->bb, + sizeof(uint32_t)) || + copy_in_user(&pcc_coeff32->rg, + &pcc_coeff->rg, + sizeof(uint32_t)) || + copy_in_user(&pcc_coeff32->gb, + &pcc_coeff->gb, + sizeof(uint32_t)) || + copy_in_user(&pcc_coeff32->rb, + &pcc_coeff->rb, + sizeof(uint32_t)) || + copy_in_user(&pcc_coeff32->rgb_0, + &pcc_coeff->rgb_0, + sizeof(uint32_t)) || + copy_in_user(&pcc_coeff32->rgb_1, + &pcc_coeff->rgb_1, + sizeof(uint32_t))) + return -EFAULT; + + return 0; +} + +static int __from_user_pcc_coeff_v17( + struct mdp_pcc_cfg_data32 __user *pcc_cfg32, + struct mdp_pcc_cfg_data __user *pcc_cfg) +{ + struct mdp_pcc_data_v1_7_32 pcc_cfg_payload32; + struct mdp_pcc_data_v1_7 pcc_cfg_payload; + + if (copy_from_user(&pcc_cfg_payload32, + compat_ptr(pcc_cfg32->cfg_payload), + sizeof(struct mdp_pcc_data_v1_7_32))) { + pr_err("failed to copy payload for pcc from user\n"); + return -EFAULT; + } + + memset(&pcc_cfg_payload, 0, sizeof(pcc_cfg_payload)); + pcc_cfg_payload.r.b = pcc_cfg_payload32.r.b; + pcc_cfg_payload.r.g = pcc_cfg_payload32.r.g; + pcc_cfg_payload.r.c = pcc_cfg_payload32.r.c; + pcc_cfg_payload.r.r = pcc_cfg_payload32.r.r; + pcc_cfg_payload.r.gb = pcc_cfg_payload32.r.gb; + pcc_cfg_payload.r.rb = pcc_cfg_payload32.r.rb; + pcc_cfg_payload.r.rg = pcc_cfg_payload32.r.rg; + pcc_cfg_payload.r.rgb = pcc_cfg_payload32.r.rgb; + + pcc_cfg_payload.g.b = pcc_cfg_payload32.g.b; + pcc_cfg_payload.g.g = pcc_cfg_payload32.g.g; + pcc_cfg_payload.g.c = pcc_cfg_payload32.g.c; + pcc_cfg_payload.g.r = pcc_cfg_payload32.g.r; + pcc_cfg_payload.g.gb = pcc_cfg_payload32.g.gb; + pcc_cfg_payload.g.rb = pcc_cfg_payload32.g.rb; + pcc_cfg_payload.g.rg = pcc_cfg_payload32.g.rg; + pcc_cfg_payload.g.rgb = pcc_cfg_payload32.g.rgb; + + pcc_cfg_payload.b.b = pcc_cfg_payload32.b.b; + pcc_cfg_payload.b.g = pcc_cfg_payload32.b.g; + pcc_cfg_payload.b.c = pcc_cfg_payload32.b.c; + pcc_cfg_payload.b.r = pcc_cfg_payload32.b.r; + pcc_cfg_payload.b.gb = pcc_cfg_payload32.b.gb; + pcc_cfg_payload.b.rb = pcc_cfg_payload32.b.rb; + pcc_cfg_payload.b.rg = pcc_cfg_payload32.b.rg; + pcc_cfg_payload.b.rgb = pcc_cfg_payload32.b.rgb; + + if (copy_to_user(pcc_cfg->cfg_payload, &pcc_cfg_payload, + sizeof(pcc_cfg_payload))) { + pr_err("failed to copy payload for pcc to user\n"); + return -EFAULT; + } + return 0; +} + +static int __from_user_pcc_cfg_data( + struct mdp_pcc_cfg_data32 __user *pcc_cfg32, + struct mdp_pcc_cfg_data __user *pcc_cfg) +{ + u32 version; + + if (copy_in_user(&pcc_cfg->block, + &pcc_cfg32->block, + sizeof(uint32_t)) || + copy_in_user(&pcc_cfg->ops, + &pcc_cfg32->ops, + sizeof(uint32_t)) || + copy_in_user(&pcc_cfg->version, + &pcc_cfg32->version, + sizeof(uint32_t))) + return -EFAULT; + + if (copy_from_user(&version, &pcc_cfg32->version, sizeof(u32))) { + pr_err("failed to copy version for pcc\n"); + return -EFAULT; + } + + switch (version) { + case mdp_pcc_v1_7: + if (__from_user_pcc_coeff_v17(pcc_cfg32, pcc_cfg)) { + pr_err("failed to copy pcc v17 data\n"); + return -EFAULT; + } + break; + default: + pr_debug("pcc version %d not supported use legacy\n", version); + if (__from_user_pcc_coeff( + compat_ptr((uintptr_t)&pcc_cfg32->r), + &pcc_cfg->r) || + __from_user_pcc_coeff( + compat_ptr((uintptr_t)&pcc_cfg32->g), + &pcc_cfg->g) || + __from_user_pcc_coeff( + compat_ptr((uintptr_t)&pcc_cfg32->b), + &pcc_cfg->b)) + return -EFAULT; + break; + } + return 0; +} + +static int __to_user_pcc_coeff_v1_7( + struct mdp_pcc_cfg_data32 __user *pcc_cfg32, + struct mdp_pcc_cfg_data __user *pcc_cfg) +{ + struct mdp_pcc_data_v1_7_32 pcc_cfg_payload32; + struct mdp_pcc_data_v1_7 pcc_cfg_payload; + + memset(&pcc_cfg_payload32, 0, sizeof(pcc_cfg_payload32)); + if (copy_from_user(&pcc_cfg_payload, + pcc_cfg->cfg_payload, + sizeof(struct mdp_pcc_data_v1_7))) { + pr_err("failed to copy payload for pcc from user\n"); + return -EFAULT; + } + + pcc_cfg_payload32.r.b = pcc_cfg_payload.r.b; + pcc_cfg_payload32.r.g = pcc_cfg_payload.r.g; + pcc_cfg_payload32.r.c = pcc_cfg_payload.r.c; + pcc_cfg_payload32.r.r = pcc_cfg_payload.r.r; + pcc_cfg_payload32.r.gb = pcc_cfg_payload.r.gb; + pcc_cfg_payload32.r.rb = pcc_cfg_payload.r.rb; + pcc_cfg_payload32.r.rg = pcc_cfg_payload.r.rg; + pcc_cfg_payload32.r.rgb = pcc_cfg_payload.r.rgb; + + pcc_cfg_payload32.g.b = pcc_cfg_payload.g.b; + pcc_cfg_payload32.g.g = pcc_cfg_payload.g.g; + pcc_cfg_payload32.g.c = pcc_cfg_payload.g.c; + pcc_cfg_payload32.g.r = pcc_cfg_payload.g.r; + pcc_cfg_payload32.g.gb = pcc_cfg_payload.g.gb; + pcc_cfg_payload32.g.rb = pcc_cfg_payload.g.rb; + pcc_cfg_payload32.g.rg = pcc_cfg_payload.g.rg; + pcc_cfg_payload32.g.rgb = pcc_cfg_payload.g.rgb; + + pcc_cfg_payload32.b.b = pcc_cfg_payload.b.b; + pcc_cfg_payload32.b.g = pcc_cfg_payload.b.g; + pcc_cfg_payload32.b.c = pcc_cfg_payload.b.c; + pcc_cfg_payload32.b.r = pcc_cfg_payload.b.r; + pcc_cfg_payload32.b.gb = pcc_cfg_payload.b.gb; + pcc_cfg_payload32.b.rb = pcc_cfg_payload.b.rb; + pcc_cfg_payload32.b.rg = pcc_cfg_payload.b.rg; + pcc_cfg_payload32.b.rgb = pcc_cfg_payload.b.rgb; + + if (copy_to_user(compat_ptr(pcc_cfg32->cfg_payload), + &pcc_cfg_payload32, + sizeof(pcc_cfg_payload32))) { + pr_err("failed to copy payload for pcc to user\n"); + return -EFAULT; + } + + return 0; +} + + +static int __to_user_pcc_cfg_data( + struct mdp_pcc_cfg_data32 __user *pcc_cfg32, + struct mdp_pcc_cfg_data __user *pcc_cfg) +{ + u32 version; + u32 ops; + + if (copy_from_user(&ops, &pcc_cfg->ops, sizeof(u32))) { + pr_err("failed to copy op for pcc\n"); + return -EFAULT; + } + + if (!(ops & MDP_PP_OPS_READ)) { + pr_debug("Read op is not set. Skipping compat copyback\n"); + return 0; + } + + if (copy_from_user(&version, &pcc_cfg->version, sizeof(u32))) { + pr_err("failed to copy version for pcc\n"); + return -EFAULT; + } + + switch (version) { + case mdp_pcc_v1_7: + if (__to_user_pcc_coeff_v1_7(pcc_cfg32, pcc_cfg)) { + pr_err("failed to copy pcc v1_7 data\n"); + return -EFAULT; + } + break; + default: + pr_debug("version invalid, fallback to legacy\n"); + + if (__to_user_pcc_coeff( + compat_ptr((uintptr_t)&pcc_cfg32->r), + &pcc_cfg->r) || + __to_user_pcc_coeff( + compat_ptr((uintptr_t)&pcc_cfg32->g), + &pcc_cfg->g) || + __to_user_pcc_coeff( + compat_ptr((uintptr_t)&pcc_cfg32->b), + &pcc_cfg->b)) + return -EFAULT; + break; + } + + return 0; +} + +static int __from_user_csc_cfg( + struct mdp_csc_cfg32 __user *csc_data32, + struct mdp_csc_cfg __user *csc_data) +{ + if (copy_in_user(&csc_data->flags, + &csc_data32->flags, + sizeof(uint32_t)) || + copy_in_user(&csc_data->csc_mv[0], + &csc_data32->csc_mv[0], + 9 * sizeof(uint32_t)) || + copy_in_user(&csc_data->csc_pre_bv[0], + &csc_data32->csc_pre_bv[0], + 3 * sizeof(uint32_t)) || + copy_in_user(&csc_data->csc_post_bv[0], + &csc_data32->csc_post_bv[0], + 3 * sizeof(uint32_t)) || + copy_in_user(&csc_data->csc_pre_lv[0], + &csc_data32->csc_pre_lv[0], + 6 * sizeof(uint32_t)) || + copy_in_user(&csc_data->csc_post_lv[0], + &csc_data32->csc_post_lv[0], + 6 * sizeof(uint32_t))) + return -EFAULT; + + return 0; +} +static int __to_user_csc_cfg( + struct mdp_csc_cfg32 __user *csc_data32, + struct mdp_csc_cfg __user *csc_data) +{ + if (copy_in_user(&csc_data32->flags, + &csc_data->flags, + sizeof(uint32_t)) || + copy_in_user(&csc_data32->csc_mv[0], + &csc_data->csc_mv[0], + 9 * sizeof(uint32_t)) || + copy_in_user(&csc_data32->csc_pre_bv[0], + &csc_data->csc_pre_bv[0], + 3 * sizeof(uint32_t)) || + copy_in_user(&csc_data32->csc_post_bv[0], + &csc_data->csc_post_bv[0], + 3 * sizeof(uint32_t)) || + copy_in_user(&csc_data32->csc_pre_lv[0], + &csc_data->csc_pre_lv[0], + 6 * sizeof(uint32_t)) || + copy_in_user(&csc_data32->csc_post_lv[0], + &csc_data->csc_post_lv[0], + 6 * sizeof(uint32_t))) + return -EFAULT; + + return 0; +} + +static int __from_user_csc_cfg_data( + struct mdp_csc_cfg_data32 __user *csc_cfg32, + struct mdp_csc_cfg_data __user *csc_cfg) +{ + if (copy_in_user(&csc_cfg->block, + &csc_cfg32->block, + sizeof(uint32_t))) + return -EFAULT; + + if (__from_user_csc_cfg( + compat_ptr((uintptr_t)&csc_cfg32->csc_data), + &csc_cfg->csc_data)) + return -EFAULT; + + return 0; +} + +static int __to_user_csc_cfg_data( + struct mdp_csc_cfg_data32 __user *csc_cfg32, + struct mdp_csc_cfg_data __user *csc_cfg) +{ + if (copy_in_user(&csc_cfg32->block, + &csc_cfg->block, + sizeof(uint32_t))) + return -EFAULT; + + if (__to_user_csc_cfg( + compat_ptr((uintptr_t)&csc_cfg32->csc_data), + &csc_cfg->csc_data)) + return -EFAULT; + + return 0; +} + +static int __from_user_igc_lut_data_v17( + struct mdp_igc_lut_data32 __user *igc_lut32, + struct mdp_igc_lut_data __user *igc_lut) +{ + struct mdp_igc_lut_data_v1_7_32 igc_cfg_payload_32; + struct mdp_igc_lut_data_v1_7 igc_cfg_payload; + + if (copy_from_user(&igc_cfg_payload_32, + compat_ptr(igc_lut32->cfg_payload), + sizeof(igc_cfg_payload_32))) { + pr_err("failed to copy payload from user for igc\n"); + return -EFAULT; + } + + memset(&igc_cfg_payload, 0, sizeof(igc_cfg_payload)); + igc_cfg_payload.c0_c1_data = compat_ptr(igc_cfg_payload_32.c0_c1_data); + igc_cfg_payload.c2_data = compat_ptr(igc_cfg_payload_32.c2_data); + igc_cfg_payload.len = igc_cfg_payload_32.len; + igc_cfg_payload.table_fmt = igc_cfg_payload_32.table_fmt; + if (copy_to_user(igc_lut->cfg_payload, &igc_cfg_payload, + sizeof(igc_cfg_payload))) { + pr_err("failed to copy payload to user for igc\n"); + return -EFAULT; + } + return 0; +} + +static int __from_user_igc_lut_data( + struct mdp_igc_lut_data32 __user *igc_lut32, + struct mdp_igc_lut_data __user *igc_lut) +{ + uint32_t data; + uint32_t version = mdp_igc_vmax; + int ret = 0; + + if (copy_in_user(&igc_lut->block, + &igc_lut32->block, + sizeof(uint32_t)) || + copy_in_user(&igc_lut->len, + &igc_lut32->len, + sizeof(uint32_t)) || + copy_in_user(&igc_lut->ops, + &igc_lut32->ops, + sizeof(uint32_t)) || + copy_in_user(&igc_lut->version, + &igc_lut32->version, + sizeof(uint32_t))) + return -EFAULT; + + if (get_user(version, &igc_lut32->version)) { + pr_err("failed to copy the version for IGC\n"); + return -EFAULT; + } + + switch (version) { + case mdp_igc_v1_7: + ret = __from_user_igc_lut_data_v17(igc_lut32, igc_lut); + if (ret) + pr_err("failed to copy payload for igc version %d ret %d\n", + version, ret); + break; + default: + pr_debug("version not supported fallback to legacy %d\n", + version); + if (get_user(data, &igc_lut32->c0_c1_data) || + put_user(compat_ptr(data), &igc_lut->c0_c1_data) || + get_user(data, &igc_lut32->c2_data) || + put_user(compat_ptr(data), &igc_lut->c2_data)) + return -EFAULT; + break; + } + return ret; +} + +static int __to_user_igc_lut_data( + struct mdp_igc_lut_data32 __user *igc_lut32, + struct mdp_igc_lut_data __user *igc_lut) +{ + unsigned long data; + + if (copy_in_user(&igc_lut32->block, + &igc_lut->block, + sizeof(uint32_t)) || + copy_in_user(&igc_lut32->len, + &igc_lut->len, + sizeof(uint32_t)) || + copy_in_user(&igc_lut32->ops, + &igc_lut->ops, + sizeof(uint32_t))) + return -EFAULT; + + if (get_user(data, (unsigned long *) &igc_lut->c0_c1_data) || + put_user((compat_caddr_t) data, &igc_lut32->c0_c1_data) || + get_user(data, (unsigned long *) &igc_lut->c2_data) || + put_user((compat_caddr_t) data, &igc_lut32->c2_data)) + return -EFAULT; + + return 0; +} + +static int __from_user_ar_gc_lut_data( + struct mdp_ar_gc_lut_data32 __user *ar_gc_data32, + struct mdp_ar_gc_lut_data __user *ar_gc_data) +{ + if (copy_in_user(&ar_gc_data->x_start, + &ar_gc_data32->x_start, + sizeof(uint32_t)) || + copy_in_user(&ar_gc_data->slope, + &ar_gc_data32->slope, + sizeof(uint32_t)) || + copy_in_user(&ar_gc_data->offset, + &ar_gc_data32->offset, + sizeof(uint32_t))) + return -EFAULT; + + return 0; +} + +static int __to_user_ar_gc_lut_data( + struct mdp_ar_gc_lut_data32 __user *ar_gc_data32, + struct mdp_ar_gc_lut_data __user *ar_gc_data) +{ + if (copy_in_user(&ar_gc_data32->x_start, + &ar_gc_data->x_start, + sizeof(uint32_t)) || + copy_in_user(&ar_gc_data32->slope, + &ar_gc_data->slope, + sizeof(uint32_t)) || + copy_in_user(&ar_gc_data32->offset, + &ar_gc_data->offset, + sizeof(uint32_t))) + return -EFAULT; + + return 0; +} + + +static int __from_user_pgc_lut_data_v1_7( + struct mdp_pgc_lut_data32 __user *pgc_lut32, + struct mdp_pgc_lut_data __user *pgc_lut) +{ + struct mdp_pgc_lut_data_v1_7_32 pgc_cfg_payload_32; + struct mdp_pgc_lut_data_v1_7 pgc_cfg_payload; + + if (copy_from_user(&pgc_cfg_payload_32, + compat_ptr(pgc_lut32->cfg_payload), + sizeof(pgc_cfg_payload_32))) { + pr_err("failed to copy from user the pgc32 payload\n"); + return -EFAULT; + } + memset(&pgc_cfg_payload, 0, sizeof(pgc_cfg_payload)); + pgc_cfg_payload.c0_data = compat_ptr(pgc_cfg_payload_32.c0_data); + pgc_cfg_payload.c1_data = compat_ptr(pgc_cfg_payload_32.c1_data); + pgc_cfg_payload.c2_data = compat_ptr(pgc_cfg_payload_32.c2_data); + pgc_cfg_payload.len = pgc_cfg_payload_32.len; + if (copy_to_user(pgc_lut->cfg_payload, &pgc_cfg_payload, + sizeof(pgc_cfg_payload))) { + pr_err("failed to copy to user pgc payload\n"); + return -EFAULT; + } + return 0; +} + +static int __from_user_pgc_lut_data_legacy( + struct mdp_pgc_lut_data32 __user *pgc_lut32, + struct mdp_pgc_lut_data __user *pgc_lut) +{ + struct mdp_ar_gc_lut_data32 __user *r_data_temp32; + struct mdp_ar_gc_lut_data32 __user *g_data_temp32; + struct mdp_ar_gc_lut_data32 __user *b_data_temp32; + struct mdp_ar_gc_lut_data __user *r_data_temp; + struct mdp_ar_gc_lut_data __user *g_data_temp; + struct mdp_ar_gc_lut_data __user *b_data_temp; + uint8_t num_r_stages, num_g_stages, num_b_stages; + int i; + + if (copy_from_user(&num_r_stages, + &pgc_lut32->num_r_stages, + sizeof(uint8_t)) || + copy_from_user(&num_g_stages, + &pgc_lut32->num_g_stages, + sizeof(uint8_t)) || + copy_from_user(&num_b_stages, + &pgc_lut32->num_b_stages, + sizeof(uint8_t))) + return -EFAULT; + + if (num_r_stages > GC_LUT_SEGMENTS || num_b_stages > GC_LUT_SEGMENTS + || num_r_stages > GC_LUT_SEGMENTS || !num_r_stages || !num_b_stages + || !num_g_stages) { + pr_err("invalid number of stages r_stages %d b_stages %d g_stages %d\n", + num_r_stages, num_b_stages, num_r_stages); + return -EFAULT; + } + + r_data_temp32 = compat_ptr((uintptr_t)pgc_lut32->r_data); + r_data_temp = pgc_lut->r_data; + + for (i = 0; i < num_r_stages; i++) { + if (__from_user_ar_gc_lut_data( + &r_data_temp32[i], + &r_data_temp[i])) + return -EFAULT; + } + + g_data_temp32 = compat_ptr((uintptr_t)pgc_lut32->g_data); + g_data_temp = pgc_lut->g_data; + + for (i = 0; i < num_g_stages; i++) { + if (__from_user_ar_gc_lut_data( + &g_data_temp32[i], + &g_data_temp[i])) + return -EFAULT; + } + + b_data_temp32 = compat_ptr((uintptr_t)pgc_lut32->b_data); + b_data_temp = pgc_lut->b_data; + + for (i = 0; i < num_b_stages; i++) { + if (__from_user_ar_gc_lut_data( + &b_data_temp32[i], + &b_data_temp[i])) + return -EFAULT; + } + return 0; +} + +static int __from_user_pgc_lut_data( + struct mdp_pgc_lut_data32 __user *pgc_lut32, + struct mdp_pgc_lut_data __user *pgc_lut) +{ + u32 version = mdp_pgc_vmax; + int ret = 0; + + if (copy_in_user(&pgc_lut->block, + &pgc_lut32->block, + sizeof(uint32_t)) || + copy_in_user(&pgc_lut->flags, + &pgc_lut32->flags, + sizeof(uint32_t)) || + copy_in_user(&pgc_lut->num_r_stages, + &pgc_lut32->num_r_stages, + sizeof(uint8_t)) || + copy_in_user(&pgc_lut->num_g_stages, + &pgc_lut32->num_g_stages, + sizeof(uint8_t)) || + copy_in_user(&pgc_lut->num_b_stages, + &pgc_lut32->num_b_stages, + sizeof(uint8_t)) || + copy_in_user(&pgc_lut->version, + &pgc_lut32->version, + sizeof(uint32_t))) + return -EFAULT; + if (copy_from_user(&version, &pgc_lut32->version, sizeof(u32))) { + pr_err("version copying failed\n"); + return -EFAULT; + } + switch (version) { + case mdp_pgc_v1_7: + ret = __from_user_pgc_lut_data_v1_7(pgc_lut32, pgc_lut); + if (ret) + pr_err("failed to copy pgc v17\n"); + break; + default: + pr_debug("version %d not supported fallback to legacy\n", + version); + ret = __from_user_pgc_lut_data_legacy(pgc_lut32, pgc_lut); + if (ret) + pr_err("copy from user pgc lut legacy failed ret %d\n", + ret); + break; + } + return ret; +} + +static int __to_user_pgc_lut_data( + struct mdp_pgc_lut_data32 __user *pgc_lut32, + struct mdp_pgc_lut_data __user *pgc_lut) +{ + struct mdp_ar_gc_lut_data32 __user *r_data_temp32; + struct mdp_ar_gc_lut_data32 __user *g_data_temp32; + struct mdp_ar_gc_lut_data32 __user *b_data_temp32; + struct mdp_ar_gc_lut_data __user *r_data_temp; + struct mdp_ar_gc_lut_data __user *g_data_temp; + struct mdp_ar_gc_lut_data __user *b_data_temp; + uint8_t num_r_stages, num_g_stages, num_b_stages; + int i; + + if (copy_in_user(&pgc_lut32->block, + &pgc_lut->block, + sizeof(uint32_t)) || + copy_in_user(&pgc_lut32->flags, + &pgc_lut->flags, + sizeof(uint32_t)) || + copy_in_user(&pgc_lut32->num_r_stages, + &pgc_lut->num_r_stages, + sizeof(uint8_t)) || + copy_in_user(&pgc_lut32->num_g_stages, + &pgc_lut->num_g_stages, + sizeof(uint8_t)) || + copy_in_user(&pgc_lut32->num_b_stages, + &pgc_lut->num_b_stages, + sizeof(uint8_t))) + return -EFAULT; + + if (copy_from_user(&num_r_stages, + &pgc_lut->num_r_stages, + sizeof(uint8_t)) || + copy_from_user(&num_g_stages, + &pgc_lut->num_g_stages, + sizeof(uint8_t)) || + copy_from_user(&num_b_stages, + &pgc_lut->num_b_stages, + sizeof(uint8_t))) + return -EFAULT; + + r_data_temp32 = compat_ptr((uintptr_t)pgc_lut32->r_data); + r_data_temp = pgc_lut->r_data; + for (i = 0; i < num_r_stages; i++) { + if (__to_user_ar_gc_lut_data( + &r_data_temp32[i], + &r_data_temp[i])) + return -EFAULT; + } + + g_data_temp32 = compat_ptr((uintptr_t)pgc_lut32->g_data); + g_data_temp = pgc_lut->g_data; + for (i = 0; i < num_g_stages; i++) { + if (__to_user_ar_gc_lut_data( + &g_data_temp32[i], + &g_data_temp[i])) + return -EFAULT; + } + + b_data_temp32 = compat_ptr((uintptr_t)pgc_lut32->b_data); + b_data_temp = pgc_lut->b_data; + for (i = 0; i < num_b_stages; i++) { + if (__to_user_ar_gc_lut_data( + &b_data_temp32[i], + &b_data_temp[i])) + return -EFAULT; + } + + return 0; +} + +static int __from_user_hist_lut_data_v1_7( + struct mdp_hist_lut_data32 __user *hist_lut32, + struct mdp_hist_lut_data __user *hist_lut) +{ + struct mdp_hist_lut_data_v1_7_32 hist_lut_cfg_payload32; + struct mdp_hist_lut_data_v1_7 hist_lut_cfg_payload; + + if (copy_from_user(&hist_lut_cfg_payload32, + compat_ptr(hist_lut32->cfg_payload), + sizeof(hist_lut_cfg_payload32))) { + pr_err("failed to copy the Hist Lut payload from userspace\n"); + return -EFAULT; + } + + memset(&hist_lut_cfg_payload, 0, sizeof(hist_lut_cfg_payload)); + hist_lut_cfg_payload.len = hist_lut_cfg_payload32.len; + hist_lut_cfg_payload.data = compat_ptr(hist_lut_cfg_payload32.data); + + if (copy_to_user(hist_lut->cfg_payload, + &hist_lut_cfg_payload, + sizeof(hist_lut_cfg_payload))) { + pr_err("Failed to copy to user hist lut cfg payload\n"); + return -EFAULT; + } + + return 0; +} + +static int __from_user_hist_lut_data( + struct mdp_hist_lut_data32 __user *hist_lut32, + struct mdp_hist_lut_data __user *hist_lut) +{ + uint32_t version = 0; + uint32_t data; + + if (copy_in_user(&hist_lut->block, + &hist_lut32->block, + sizeof(uint32_t)) || + copy_in_user(&hist_lut->version, + &hist_lut32->version, + sizeof(uint32_t)) || + copy_in_user(&hist_lut->hist_lut_first, + &hist_lut32->hist_lut_first, + sizeof(uint32_t)) || + copy_in_user(&hist_lut->ops, + &hist_lut32->ops, + sizeof(uint32_t)) || + copy_in_user(&hist_lut->len, + &hist_lut32->len, + sizeof(uint32_t))) + return -EFAULT; + + if (copy_from_user(&version, + &hist_lut32->version, + sizeof(uint32_t))) { + pr_err("failed to copy the version info\n"); + return -EFAULT; + } + + switch (version) { + case mdp_hist_lut_v1_7: + if (__from_user_hist_lut_data_v1_7(hist_lut32, hist_lut)) { + pr_err("failed to get hist lut data for version %d\n", + version); + return -EFAULT; + } + break; + default: + pr_debug("version invalid, fallback to legacy\n"); + if (get_user(data, &hist_lut32->data) || + put_user(compat_ptr(data), &hist_lut->data)) + return -EFAULT; + break; + } + + return 0; +} + +static int __to_user_hist_lut_data( + struct mdp_hist_lut_data32 __user *hist_lut32, + struct mdp_hist_lut_data __user *hist_lut) +{ + unsigned long data; + + if (copy_in_user(&hist_lut32->block, + &hist_lut->block, + sizeof(uint32_t)) || + copy_in_user(&hist_lut32->ops, + &hist_lut->ops, + sizeof(uint32_t)) || + copy_in_user(&hist_lut32->len, + &hist_lut->len, + sizeof(uint32_t))) + return -EFAULT; + + if (get_user(data, (unsigned long *) &hist_lut->data) || + put_user((compat_caddr_t) data, &hist_lut32->data)) + return -EFAULT; + + return 0; +} + +static int __from_user_rgb_lut_data( + struct mdp_rgb_lut_data32 __user *rgb_lut32, + struct mdp_rgb_lut_data __user *rgb_lut) +{ + if (copy_in_user(&rgb_lut->flags, &rgb_lut32->flags, + sizeof(uint32_t)) || + copy_in_user(&rgb_lut->lut_type, &rgb_lut32->lut_type, + sizeof(uint32_t))) + return -EFAULT; + + return __from_user_fb_cmap(&rgb_lut->cmap, &rgb_lut32->cmap); +} + +static int __to_user_rgb_lut_data( + struct mdp_rgb_lut_data32 __user *rgb_lut32, + struct mdp_rgb_lut_data __user *rgb_lut) +{ + if (copy_in_user(&rgb_lut32->flags, &rgb_lut->flags, + sizeof(uint32_t)) || + copy_in_user(&rgb_lut32->lut_type, &rgb_lut->lut_type, + sizeof(uint32_t))) + return -EFAULT; + + return __to_user_fb_cmap(&rgb_lut->cmap, &rgb_lut32->cmap); +} + +static int __from_user_lut_cfg_data( + struct mdp_lut_cfg_data32 __user *lut_cfg32, + struct mdp_lut_cfg_data __user *lut_cfg) +{ + uint32_t lut_type; + int ret = 0; + + if (copy_from_user(&lut_type, &lut_cfg32->lut_type, + sizeof(uint32_t))) + return -EFAULT; + + if (copy_in_user(&lut_cfg->lut_type, + &lut_cfg32->lut_type, + sizeof(uint32_t))) + return -EFAULT; + + switch (lut_type) { + case mdp_lut_igc: + ret = __from_user_igc_lut_data( + compat_ptr((uintptr_t)&lut_cfg32->data.igc_lut_data), + &lut_cfg->data.igc_lut_data); + break; + case mdp_lut_pgc: + ret = __from_user_pgc_lut_data( + compat_ptr((uintptr_t)&lut_cfg32->data.pgc_lut_data), + &lut_cfg->data.pgc_lut_data); + break; + case mdp_lut_hist: + ret = __from_user_hist_lut_data( + compat_ptr((uintptr_t)&lut_cfg32->data.hist_lut_data), + &lut_cfg->data.hist_lut_data); + break; + case mdp_lut_rgb: + ret = __from_user_rgb_lut_data( + compat_ptr((uintptr_t)&lut_cfg32->data.rgb_lut_data), + &lut_cfg->data.rgb_lut_data); + break; + default: + break; + } + + return ret; +} + +static int __to_user_lut_cfg_data( + struct mdp_lut_cfg_data32 __user *lut_cfg32, + struct mdp_lut_cfg_data __user *lut_cfg) +{ + uint32_t lut_type; + int ret = 0; + + if (copy_from_user(&lut_type, &lut_cfg->lut_type, + sizeof(uint32_t))) + return -EFAULT; + + if (copy_in_user(&lut_cfg32->lut_type, + &lut_cfg->lut_type, + sizeof(uint32_t))) + return -EFAULT; + + switch (lut_type) { + case mdp_lut_igc: + ret = __to_user_igc_lut_data( + compat_ptr((uintptr_t)&lut_cfg32->data.igc_lut_data), + &lut_cfg->data.igc_lut_data); + break; + case mdp_lut_pgc: + ret = __to_user_pgc_lut_data( + compat_ptr((uintptr_t)&lut_cfg32->data.pgc_lut_data), + &lut_cfg->data.pgc_lut_data); + break; + case mdp_lut_hist: + ret = __to_user_hist_lut_data( + compat_ptr((uintptr_t)&lut_cfg32->data.hist_lut_data), + &lut_cfg->data.hist_lut_data); + break; + case mdp_lut_rgb: + ret = __to_user_rgb_lut_data( + compat_ptr((uintptr_t)&lut_cfg32->data.rgb_lut_data), + &lut_cfg->data.rgb_lut_data); + break; + default: + break; + } + + return ret; +} + +static int __from_user_qseed_cfg( + struct mdp_qseed_cfg32 __user *qseed_data32, + struct mdp_qseed_cfg __user *qseed_data) +{ + uint32_t data; + + if (copy_in_user(&qseed_data->table_num, + &qseed_data32->table_num, + sizeof(uint32_t)) || + copy_in_user(&qseed_data->ops, + &qseed_data32->ops, + sizeof(uint32_t)) || + copy_in_user(&qseed_data->len, + &qseed_data32->len, + sizeof(uint32_t))) + return -EFAULT; + + if (get_user(data, &qseed_data32->data) || + put_user(compat_ptr(data), &qseed_data->data)) + return -EFAULT; + + return 0; +} + +static int __to_user_qseed_cfg( + struct mdp_qseed_cfg32 __user *qseed_data32, + struct mdp_qseed_cfg __user *qseed_data) +{ + unsigned long data; + + if (copy_in_user(&qseed_data32->table_num, + &qseed_data->table_num, + sizeof(uint32_t)) || + copy_in_user(&qseed_data32->ops, + &qseed_data->ops, + sizeof(uint32_t)) || + copy_in_user(&qseed_data32->len, + &qseed_data->len, + sizeof(uint32_t))) + return -EFAULT; + + if (get_user(data, (unsigned long *) &qseed_data->data) || + put_user((compat_caddr_t) data, &qseed_data32->data)) + return -EFAULT; + + return 0; +} + +static int __from_user_qseed_cfg_data( + struct mdp_qseed_cfg_data32 __user *qseed_cfg32, + struct mdp_qseed_cfg_data __user *qseed_cfg) +{ + if (copy_in_user(&qseed_cfg->block, + &qseed_cfg32->block, + sizeof(uint32_t))) + return -EFAULT; + + if (__from_user_qseed_cfg( + compat_ptr((uintptr_t)&qseed_cfg32->qseed_data), + &qseed_cfg->qseed_data)) + return -EFAULT; + + return 0; +} + +static int __to_user_qseed_cfg_data( + struct mdp_qseed_cfg_data32 __user *qseed_cfg32, + struct mdp_qseed_cfg_data __user *qseed_cfg) +{ + if (copy_in_user(&qseed_cfg32->block, + &qseed_cfg->block, + sizeof(uint32_t))) + return -EFAULT; + + if (__to_user_qseed_cfg( + compat_ptr((uintptr_t)&qseed_cfg32->qseed_data), + &qseed_cfg->qseed_data)) + return -EFAULT; + + return 0; +} + +static int __from_user_bl_scale_data( + struct mdp_bl_scale_data32 __user *bl_scale32, + struct mdp_bl_scale_data __user *bl_scale) +{ + if (copy_in_user(&bl_scale->min_lvl, + &bl_scale32->min_lvl, + sizeof(uint32_t)) || + copy_in_user(&bl_scale->scale, + &bl_scale32->scale, + sizeof(uint32_t))) + return -EFAULT; + + return 0; +} + +static int __from_user_pa_cfg( + struct mdp_pa_cfg32 __user *pa_data32, + struct mdp_pa_cfg __user *pa_data) +{ + if (copy_in_user(&pa_data->flags, + &pa_data32->flags, + sizeof(uint32_t)) || + copy_in_user(&pa_data->hue_adj, + &pa_data32->hue_adj, + sizeof(uint32_t)) || + copy_in_user(&pa_data->sat_adj, + &pa_data32->sat_adj, + sizeof(uint32_t)) || + copy_in_user(&pa_data->val_adj, + &pa_data32->val_adj, + sizeof(uint32_t)) || + copy_in_user(&pa_data->cont_adj, + &pa_data32->cont_adj, + sizeof(uint32_t))) + return -EFAULT; + + return 0; +} + +static int __to_user_pa_cfg( + struct mdp_pa_cfg32 __user *pa_data32, + struct mdp_pa_cfg __user *pa_data) +{ + if (copy_in_user(&pa_data32->flags, + &pa_data->flags, + sizeof(uint32_t)) || + copy_in_user(&pa_data32->hue_adj, + &pa_data->hue_adj, + sizeof(uint32_t)) || + copy_in_user(&pa_data32->sat_adj, + &pa_data->sat_adj, + sizeof(uint32_t)) || + copy_in_user(&pa_data32->val_adj, + &pa_data->val_adj, + sizeof(uint32_t)) || + copy_in_user(&pa_data32->cont_adj, + &pa_data->cont_adj, + sizeof(uint32_t))) + return -EFAULT; + + return 0; +} + +static int __from_user_pa_cfg_data( + struct mdp_pa_cfg_data32 __user *pa_cfg32, + struct mdp_pa_cfg_data __user *pa_cfg) +{ + if (copy_in_user(&pa_cfg->block, + &pa_cfg32->block, + sizeof(uint32_t))) + return -EFAULT; + if (__from_user_pa_cfg( + compat_ptr((uintptr_t)&pa_cfg32->pa_data), + &pa_cfg->pa_data)) + return -EFAULT; + + return 0; +} + +static int __to_user_pa_cfg_data( + struct mdp_pa_cfg_data32 __user *pa_cfg32, + struct mdp_pa_cfg_data __user *pa_cfg) +{ + if (copy_in_user(&pa_cfg32->block, + &pa_cfg->block, + sizeof(uint32_t))) + return -EFAULT; + if (__to_user_pa_cfg( + compat_ptr((uintptr_t)&pa_cfg32->pa_data), + &pa_cfg->pa_data)) + return -EFAULT; + + return 0; +} + +static int __from_user_mem_col_cfg( + struct mdp_pa_mem_col_cfg32 __user *mem_col_cfg32, + struct mdp_pa_mem_col_cfg __user *mem_col_cfg) +{ + if (copy_in_user(&mem_col_cfg->color_adjust_p0, + &mem_col_cfg32->color_adjust_p0, + sizeof(uint32_t)) || + copy_in_user(&mem_col_cfg->color_adjust_p1, + &mem_col_cfg32->color_adjust_p1, + sizeof(uint32_t)) || + copy_in_user(&mem_col_cfg->hue_region, + &mem_col_cfg32->hue_region, + sizeof(uint32_t)) || + copy_in_user(&mem_col_cfg->sat_region, + &mem_col_cfg32->sat_region, + sizeof(uint32_t)) || + copy_in_user(&mem_col_cfg->val_region, + &mem_col_cfg32->val_region, + sizeof(uint32_t))) + return -EFAULT; + + return 0; +} + +static int __to_user_mem_col_cfg( + struct mdp_pa_mem_col_cfg32 __user *mem_col_cfg32, + struct mdp_pa_mem_col_cfg __user *mem_col_cfg) +{ + if (copy_in_user(&mem_col_cfg32->color_adjust_p0, + &mem_col_cfg->color_adjust_p0, + sizeof(uint32_t)) || + copy_in_user(&mem_col_cfg32->color_adjust_p1, + &mem_col_cfg->color_adjust_p1, + sizeof(uint32_t)) || + copy_in_user(&mem_col_cfg32->hue_region, + &mem_col_cfg->hue_region, + sizeof(uint32_t)) || + copy_in_user(&mem_col_cfg32->sat_region, + &mem_col_cfg->sat_region, + sizeof(uint32_t)) || + copy_in_user(&mem_col_cfg32->val_region, + &mem_col_cfg->val_region, + sizeof(uint32_t))) + return -EFAULT; + + return 0; +} + +static int __from_user_pa_v2_data( + struct mdp_pa_v2_data32 __user *pa_v2_data32, + struct mdp_pa_v2_data __user *pa_v2_data) +{ + uint32_t data; + + if (copy_in_user(&pa_v2_data->flags, + &pa_v2_data32->flags, + sizeof(uint32_t)) || + copy_in_user(&pa_v2_data->global_hue_adj, + &pa_v2_data32->global_hue_adj, + sizeof(uint32_t)) || + copy_in_user(&pa_v2_data->global_sat_adj, + &pa_v2_data32->global_sat_adj, + sizeof(uint32_t)) || + copy_in_user(&pa_v2_data->global_val_adj, + &pa_v2_data32->global_val_adj, + sizeof(uint32_t)) || + copy_in_user(&pa_v2_data->global_cont_adj, + &pa_v2_data32->global_cont_adj, + sizeof(uint32_t)) || + copy_in_user(&pa_v2_data->six_zone_thresh, + &pa_v2_data32->six_zone_thresh, + sizeof(uint32_t)) || + copy_in_user(&pa_v2_data->six_zone_len, + &pa_v2_data32->six_zone_len, + sizeof(uint32_t))) + return -EFAULT; + + if (get_user(data, &pa_v2_data32->six_zone_curve_p0) || + put_user(compat_ptr(data), &pa_v2_data->six_zone_curve_p0) || + get_user(data, &pa_v2_data32->six_zone_curve_p1) || + put_user(compat_ptr(data), &pa_v2_data->six_zone_curve_p1)) + return -EFAULT; + + if (__from_user_mem_col_cfg( + compat_ptr((uintptr_t)&pa_v2_data32->skin_cfg), + &pa_v2_data->skin_cfg) || + __from_user_mem_col_cfg( + compat_ptr((uintptr_t)&pa_v2_data32->sky_cfg), + &pa_v2_data->sky_cfg) || + __from_user_mem_col_cfg( + compat_ptr((uintptr_t)&pa_v2_data32->fol_cfg), + &pa_v2_data->fol_cfg)) + return -EFAULT; + + return 0; +} + +static int __to_user_pa_v2_data( + struct mdp_pa_v2_data32 __user *pa_v2_data32, + struct mdp_pa_v2_data __user *pa_v2_data) +{ + unsigned long data; + + if (copy_in_user(&pa_v2_data32->flags, + &pa_v2_data->flags, + sizeof(uint32_t)) || + copy_in_user(&pa_v2_data32->global_hue_adj, + &pa_v2_data->global_hue_adj, + sizeof(uint32_t)) || + copy_in_user(&pa_v2_data32->global_sat_adj, + &pa_v2_data->global_sat_adj, + sizeof(uint32_t)) || + copy_in_user(&pa_v2_data32->global_val_adj, + &pa_v2_data->global_val_adj, + sizeof(uint32_t)) || + copy_in_user(&pa_v2_data32->global_cont_adj, + &pa_v2_data->global_cont_adj, + sizeof(uint32_t)) || + copy_in_user(&pa_v2_data32->six_zone_thresh, + &pa_v2_data->six_zone_thresh, + sizeof(uint32_t)) || + copy_in_user(&pa_v2_data32->six_zone_len, + &pa_v2_data->six_zone_len, + sizeof(uint32_t))) + return -EFAULT; + + if (get_user(data, (unsigned long *) &pa_v2_data->six_zone_curve_p0) || + put_user((compat_caddr_t) data, &pa_v2_data32->six_zone_curve_p0) || + get_user(data, (unsigned long *) &pa_v2_data->six_zone_curve_p1) || + put_user((compat_caddr_t) data, &pa_v2_data32->six_zone_curve_p1)) + return -EFAULT; + + if (__to_user_mem_col_cfg( + compat_ptr((uintptr_t)&pa_v2_data32->skin_cfg), + &pa_v2_data->skin_cfg) || + __to_user_mem_col_cfg( + compat_ptr((uintptr_t)&pa_v2_data32->sky_cfg), + &pa_v2_data->sky_cfg) || + __to_user_mem_col_cfg( + compat_ptr((uintptr_t)&pa_v2_data32->fol_cfg), + &pa_v2_data->fol_cfg)) + return -EFAULT; + + return 0; +} + +static inline void __from_user_pa_mem_col_data_v1_7( + struct mdp_pa_mem_col_data_v1_7_32 *mem_col_data32, + struct mdp_pa_mem_col_data_v1_7 *mem_col_data) +{ + mem_col_data->color_adjust_p0 = mem_col_data32->color_adjust_p0; + mem_col_data->color_adjust_p1 = mem_col_data32->color_adjust_p1; + mem_col_data->color_adjust_p2 = mem_col_data32->color_adjust_p2; + mem_col_data->blend_gain = mem_col_data32->blend_gain; + mem_col_data->sat_hold = mem_col_data32->sat_hold; + mem_col_data->val_hold = mem_col_data32->val_hold; + mem_col_data->hue_region = mem_col_data32->hue_region; + mem_col_data->sat_region = mem_col_data32->sat_region; + mem_col_data->val_region = mem_col_data32->val_region; +} + + +static int __from_user_pa_data_v1_7( + struct mdp_pa_v2_cfg_data32 __user *pa_v2_cfg32, + struct mdp_pa_v2_cfg_data __user *pa_v2_cfg) +{ + struct mdp_pa_data_v1_7_32 pa_cfg_payload32; + struct mdp_pa_data_v1_7 pa_cfg_payload; + + if (copy_from_user(&pa_cfg_payload32, + compat_ptr(pa_v2_cfg32->cfg_payload), + sizeof(pa_cfg_payload32))) { + pr_err("failed to copy the PA payload from userspace\n"); + return -EFAULT; + } + + memset(&pa_cfg_payload, 0, sizeof(pa_cfg_payload)); + pa_cfg_payload.mode = pa_cfg_payload32.mode; + pa_cfg_payload.global_hue_adj = pa_cfg_payload32.global_hue_adj; + pa_cfg_payload.global_sat_adj = pa_cfg_payload32.global_sat_adj; + pa_cfg_payload.global_val_adj = pa_cfg_payload32.global_val_adj; + pa_cfg_payload.global_cont_adj = pa_cfg_payload32.global_cont_adj; + + __from_user_pa_mem_col_data_v1_7(&pa_cfg_payload32.skin_cfg, + &pa_cfg_payload.skin_cfg); + __from_user_pa_mem_col_data_v1_7(&pa_cfg_payload32.sky_cfg, + &pa_cfg_payload.sky_cfg); + __from_user_pa_mem_col_data_v1_7(&pa_cfg_payload32.fol_cfg, + &pa_cfg_payload.fol_cfg); + + pa_cfg_payload.six_zone_thresh = pa_cfg_payload32.six_zone_thresh; + pa_cfg_payload.six_zone_adj_p0 = pa_cfg_payload32.six_zone_adj_p0; + pa_cfg_payload.six_zone_adj_p1 = pa_cfg_payload32.six_zone_adj_p1; + pa_cfg_payload.six_zone_sat_hold = pa_cfg_payload32.six_zone_sat_hold; + pa_cfg_payload.six_zone_val_hold = pa_cfg_payload32.six_zone_val_hold; + pa_cfg_payload.six_zone_len = pa_cfg_payload32.six_zone_len; + + pa_cfg_payload.six_zone_curve_p0 = + compat_ptr(pa_cfg_payload32.six_zone_curve_p0); + pa_cfg_payload.six_zone_curve_p1 = + compat_ptr(pa_cfg_payload32.six_zone_curve_p1); + + if (copy_to_user(pa_v2_cfg->cfg_payload, &pa_cfg_payload, + sizeof(pa_cfg_payload))) { + pr_err("Failed to copy to user pa cfg payload\n"); + return -EFAULT; + } + + return 0; +} + +static int __from_user_pa_v2_cfg_data( + struct mdp_pa_v2_cfg_data32 __user *pa_v2_cfg32, + struct mdp_pa_v2_cfg_data __user *pa_v2_cfg) +{ + uint32_t version; + + if (copy_in_user(&pa_v2_cfg->block, + &pa_v2_cfg32->block, + sizeof(uint32_t)) || + copy_in_user(&pa_v2_cfg->version, + &pa_v2_cfg32->version, + sizeof(uint32_t)) || + copy_in_user(&pa_v2_cfg->flags, + &pa_v2_cfg32->flags, + sizeof(uint32_t))) + return -EFAULT; + + if (copy_from_user(&version, + &pa_v2_cfg32->version, + sizeof(uint32_t))) { + pr_err("failed to copy the version info\n"); + return -EFAULT; + } + + switch (version) { + case mdp_pa_v1_7: + if (__from_user_pa_data_v1_7(pa_v2_cfg32, pa_v2_cfg)) { + pr_err("failed to get pa data for version %d\n", + version); + return -EFAULT; + } + break; + default: + pr_debug("version invalid, fallback to legacy\n"); + if (__from_user_pa_v2_data( + compat_ptr((uintptr_t)&pa_v2_cfg32->pa_v2_data), + &pa_v2_cfg->pa_v2_data)) + return -EFAULT; + break; + } + + return 0; +} + +static inline void __to_user_pa_mem_col_data_v1_7( + struct mdp_pa_mem_col_data_v1_7_32 *mem_col_data32, + struct mdp_pa_mem_col_data_v1_7 *mem_col_data) +{ + mem_col_data32->color_adjust_p0 = mem_col_data->color_adjust_p0; + mem_col_data32->color_adjust_p1 = mem_col_data->color_adjust_p1; + mem_col_data32->color_adjust_p2 = mem_col_data->color_adjust_p2; + mem_col_data32->blend_gain = mem_col_data->blend_gain; + mem_col_data32->sat_hold = mem_col_data->sat_hold; + mem_col_data32->val_hold = mem_col_data->val_hold; + mem_col_data32->hue_region = mem_col_data->hue_region; + mem_col_data32->sat_region = mem_col_data->sat_region; + mem_col_data32->val_region = mem_col_data->val_region; +} + +static int __to_user_pa_data_v1_7( + struct mdp_pa_v2_cfg_data32 __user *pa_v2_cfg32, + struct mdp_pa_v2_cfg_data __user *pa_v2_cfg) +{ + struct mdp_pa_data_v1_7_32 pa_cfg_payload32; + struct mdp_pa_data_v1_7 pa_cfg_payload; + + memset(&pa_cfg_payload32, 0, sizeof(pa_cfg_payload32)); + if (copy_from_user(&pa_cfg_payload, + pa_v2_cfg->cfg_payload, + sizeof(pa_cfg_payload))) { + pr_err("failed to copy the PA payload from userspace\n"); + return -EFAULT; + } + + pa_cfg_payload32.mode = pa_cfg_payload.mode; + pa_cfg_payload32.global_hue_adj = pa_cfg_payload.global_hue_adj; + pa_cfg_payload32.global_sat_adj = pa_cfg_payload.global_sat_adj; + pa_cfg_payload32.global_val_adj = pa_cfg_payload.global_val_adj; + pa_cfg_payload32.global_cont_adj = pa_cfg_payload.global_cont_adj; + + __to_user_pa_mem_col_data_v1_7(&pa_cfg_payload32.skin_cfg, + &pa_cfg_payload.skin_cfg); + __to_user_pa_mem_col_data_v1_7(&pa_cfg_payload32.sky_cfg, + &pa_cfg_payload.sky_cfg); + __to_user_pa_mem_col_data_v1_7(&pa_cfg_payload32.fol_cfg, + &pa_cfg_payload.fol_cfg); + + pa_cfg_payload32.six_zone_thresh = pa_cfg_payload.six_zone_thresh; + pa_cfg_payload32.six_zone_adj_p0 = pa_cfg_payload.six_zone_adj_p0; + pa_cfg_payload32.six_zone_adj_p1 = pa_cfg_payload.six_zone_adj_p1; + pa_cfg_payload32.six_zone_sat_hold = pa_cfg_payload.six_zone_sat_hold; + pa_cfg_payload32.six_zone_val_hold = pa_cfg_payload.six_zone_val_hold; + pa_cfg_payload32.six_zone_len = pa_cfg_payload.six_zone_len; + + if (copy_to_user(compat_ptr(pa_v2_cfg32->cfg_payload), + &pa_cfg_payload32, + sizeof(pa_cfg_payload32))) { + pr_err("Failed to copy to user pa cfg payload\n"); + return -EFAULT; + } + + return 0; +} + +static int __to_user_pa_v2_cfg_data( + struct mdp_pa_v2_cfg_data32 __user *pa_v2_cfg32, + struct mdp_pa_v2_cfg_data __user *pa_v2_cfg) +{ + uint32_t version = 0; + uint32_t flags = 0; + + if (copy_from_user(&version, + &pa_v2_cfg32->version, + sizeof(uint32_t))) + return -EFAULT; + + switch (version) { + case mdp_pa_v1_7: + if (copy_from_user(&flags, + &pa_v2_cfg32->flags, + sizeof(uint32_t))) { + pr_err("failed to get PA v1_7 flags\n"); + return -EFAULT; + } + + if (!(flags & MDP_PP_OPS_READ)) { + pr_debug("Read op not set. Skipping compat copyback\n"); + return 0; + } + + if (__to_user_pa_data_v1_7(pa_v2_cfg32, pa_v2_cfg)) { + pr_err("failed to set pa data for version %d\n", + version); + return -EFAULT; + } + break; + default: + pr_debug("version invalid, fallback to legacy\n"); + + if (copy_from_user(&flags, + &pa_v2_cfg32->pa_v2_data.flags, + sizeof(uint32_t))) { + pr_err("failed to get PAv2 flags\n"); + return -EFAULT; + } + + if (!(flags & MDP_PP_OPS_READ)) { + pr_debug("Read op not set. Skipping compat copyback\n"); + return 0; + } + + if (__to_user_pa_v2_data( + compat_ptr((uintptr_t)&pa_v2_cfg32->pa_v2_data), + &pa_v2_cfg->pa_v2_data)) + return -EFAULT; + break; + } + + return 0; +} + +static int __from_user_dither_cfg_data( + struct mdp_dither_cfg_data32 __user *dither_cfg32, + struct mdp_dither_cfg_data __user *dither_cfg) +{ + if (copy_in_user(&dither_cfg->block, + &dither_cfg32->block, + sizeof(uint32_t)) || + copy_in_user(&dither_cfg->flags, + &dither_cfg32->flags, + sizeof(uint32_t)) || + copy_in_user(&dither_cfg->g_y_depth, + &dither_cfg32->g_y_depth, + sizeof(uint32_t)) || + copy_in_user(&dither_cfg->r_cr_depth, + &dither_cfg32->r_cr_depth, + sizeof(uint32_t)) || + copy_in_user(&dither_cfg->b_cb_depth, + &dither_cfg32->b_cb_depth, + sizeof(uint32_t))) + return -EFAULT; + + return 0; +} + +static int __to_user_dither_cfg_data( + struct mdp_dither_cfg_data32 __user *dither_cfg32, + struct mdp_dither_cfg_data __user *dither_cfg) +{ + if (copy_in_user(&dither_cfg32->block, + &dither_cfg->block, + sizeof(uint32_t)) || + copy_in_user(&dither_cfg32->flags, + &dither_cfg->flags, + sizeof(uint32_t)) || + copy_in_user(&dither_cfg32->g_y_depth, + &dither_cfg->g_y_depth, + sizeof(uint32_t)) || + copy_in_user(&dither_cfg32->r_cr_depth, + &dither_cfg->r_cr_depth, + sizeof(uint32_t)) || + copy_in_user(&dither_cfg32->b_cb_depth, + &dither_cfg->b_cb_depth, + sizeof(uint32_t))) + return -EFAULT; + + return 0; +} + +static int __from_user_gamut_cfg_data_v17( + struct mdp_gamut_cfg_data32 __user *gamut_cfg32, + struct mdp_gamut_cfg_data __user *gamut_cfg) +{ + struct mdp_gamut_data_v1_7 gamut_cfg_payload; + struct mdp_gamut_data_v1_7_32 gamut_cfg_payload32; + u32 i = 0; + + if (copy_from_user(&gamut_cfg_payload32, + compat_ptr(gamut_cfg32->cfg_payload), + sizeof(gamut_cfg_payload32))) { + pr_err("failed to copy the gamut payload from userspace\n"); + return -EFAULT; + } + + memset(&gamut_cfg_payload, 0, sizeof(gamut_cfg_payload)); + gamut_cfg_payload.mode = gamut_cfg_payload32.mode; + for (i = 0; i < MDP_GAMUT_TABLE_NUM_V1_7; i++) { + gamut_cfg_payload.tbl_size[i] = + gamut_cfg_payload32.tbl_size[i]; + gamut_cfg_payload.c0_data[i] = + compat_ptr(gamut_cfg_payload32.c0_data[i]); + gamut_cfg_payload.c1_c2_data[i] = + compat_ptr(gamut_cfg_payload32.c1_c2_data[i]); + } + for (i = 0; i < MDP_GAMUT_SCALE_OFF_TABLE_NUM; i++) { + gamut_cfg_payload.tbl_scale_off_sz[i] = + gamut_cfg_payload32.tbl_scale_off_sz[i]; + gamut_cfg_payload.scale_off_data[i] = + compat_ptr(gamut_cfg_payload32.scale_off_data[i]); + } + if (copy_to_user(gamut_cfg->cfg_payload, &gamut_cfg_payload, + sizeof(gamut_cfg_payload))) { + pr_err("failed to copy the gamut payload to userspace\n"); + return -EFAULT; + } + return 0; +} + +static int __from_user_gamut_cfg_data( + struct mdp_gamut_cfg_data32 __user *gamut_cfg32, + struct mdp_gamut_cfg_data __user *gamut_cfg) +{ + uint32_t data, version; + int i; + + if (copy_in_user(&gamut_cfg->block, + &gamut_cfg32->block, + sizeof(uint32_t)) || + copy_in_user(&gamut_cfg->flags, + &gamut_cfg32->flags, + sizeof(uint32_t)) || + copy_in_user(&gamut_cfg->gamut_first, + &gamut_cfg32->gamut_first, + sizeof(uint32_t)) || + copy_in_user(&gamut_cfg->tbl_size[0], + &gamut_cfg32->tbl_size[0], + MDP_GAMUT_TABLE_NUM * sizeof(uint32_t)) || + copy_in_user(&gamut_cfg->version, + &gamut_cfg32->version, + sizeof(uint32_t))) + return 0; + + if (copy_from_user(&version, &gamut_cfg32->version, sizeof(u32))) { + pr_err("failed to copy the version info\n"); + return -EFAULT; + } + + switch (version) { + case mdp_gamut_v1_7: + if (__from_user_gamut_cfg_data_v17(gamut_cfg32, gamut_cfg)) { + pr_err("failed to get the gamut data for version %d\n", + version); + return -EFAULT; + } + break; + default: + pr_debug("version invalid fallback to legacy\n"); + /* The Gamut LUT data contains 3 static arrays for R, G, and B + * gamut data. Each these arrays contains pointers dynamic arrays + * which hold the gamut LUTs for R, G, and B. Must copy the array of + * pointers from 32 bit to 64 bit addresses. + */ + for (i = 0; i < MDP_GAMUT_TABLE_NUM; i++) { + if (get_user(data, &gamut_cfg32->r_tbl[i]) || + put_user(compat_ptr(data), &gamut_cfg->r_tbl[i])) + return -EFAULT; + } + + for (i = 0; i < MDP_GAMUT_TABLE_NUM; i++) { + if (get_user(data, &gamut_cfg32->g_tbl[i]) || + put_user(compat_ptr(data), &gamut_cfg->g_tbl[i])) + return -EFAULT; + } + + for (i = 0; i < MDP_GAMUT_TABLE_NUM; i++) { + if (get_user(data, &gamut_cfg32->b_tbl[i]) || + put_user(compat_ptr(data), &gamut_cfg->b_tbl[i])) + return -EFAULT; + } + break; + } + return 0; +} + +static int __to_user_gamut_cfg_data( + struct mdp_gamut_cfg_data32 __user *gamut_cfg32, + struct mdp_gamut_cfg_data __user *gamut_cfg) +{ + unsigned long data; + int i; + + if (copy_in_user(&gamut_cfg32->block, + &gamut_cfg->block, + sizeof(uint32_t)) || + copy_in_user(&gamut_cfg32->flags, + &gamut_cfg->flags, + sizeof(uint32_t)) || + copy_in_user(&gamut_cfg32->gamut_first, + &gamut_cfg->gamut_first, + sizeof(uint32_t)) || + copy_in_user(&gamut_cfg32->tbl_size[0], + &gamut_cfg->tbl_size[0], + MDP_GAMUT_TABLE_NUM * sizeof(uint32_t))) + return 0; + + for (i = 0; i < MDP_GAMUT_TABLE_NUM; i++) { + if (get_user(data, (unsigned long *) &gamut_cfg->r_tbl[i]) || + put_user((compat_caddr_t)data, &gamut_cfg32->r_tbl[i])) + return -EFAULT; + } + + for (i = 0; i < MDP_GAMUT_TABLE_NUM; i++) { + if (get_user(data, (unsigned long *) &gamut_cfg->g_tbl[i]) || + put_user((compat_caddr_t)data, &gamut_cfg32->g_tbl[i])) + return -EFAULT; + } + + for (i = 0; i < MDP_GAMUT_TABLE_NUM; i++) { + if (get_user(data, (unsigned long *) &gamut_cfg->b_tbl[i]) || + put_user((compat_caddr_t)data, &gamut_cfg32->g_tbl[i])) + return -EFAULT; + } + + return 0; +} + +static int __from_user_calib_config_data( + struct mdp_calib_config_data32 __user *calib_cfg32, + struct mdp_calib_config_data __user *calib_cfg) +{ + if (copy_in_user(&calib_cfg->ops, + &calib_cfg32->ops, + sizeof(uint32_t)) || + copy_in_user(&calib_cfg->addr, + &calib_cfg32->addr, + sizeof(uint32_t)) || + copy_in_user(&calib_cfg->data, + &calib_cfg32->data, + sizeof(uint32_t))) + return -EFAULT; + + return 0; +} + +static int __to_user_calib_config_data( + struct mdp_calib_config_data32 __user *calib_cfg32, + struct mdp_calib_config_data __user *calib_cfg) +{ + if (copy_in_user(&calib_cfg32->ops, + &calib_cfg->ops, + sizeof(uint32_t)) || + copy_in_user(&calib_cfg32->addr, + &calib_cfg->addr, + sizeof(uint32_t)) || + copy_in_user(&calib_cfg32->data, + &calib_cfg->data, + sizeof(uint32_t))) + return -EFAULT; + + return 0; +} + +static int __from_user_ad_init( + struct mdss_ad_init32 __user *ad_init32, + struct mdss_ad_init __user *ad_init) +{ + uint32_t data; + + if (copy_in_user(&ad_init->asym_lut[0], + &ad_init32->asym_lut[0], + 33 * sizeof(uint32_t)) || + copy_in_user(&ad_init->color_corr_lut[0], + &ad_init32->color_corr_lut[0], + 33 * sizeof(uint32_t)) || + copy_in_user(&ad_init->i_control[0], + &ad_init32->i_control[0], + 2 * sizeof(uint8_t)) || + copy_in_user(&ad_init->black_lvl, + &ad_init32->black_lvl, + sizeof(uint16_t)) || + copy_in_user(&ad_init->white_lvl, + &ad_init32->white_lvl, + sizeof(uint16_t)) || + copy_in_user(&ad_init->var, + &ad_init32->var, + sizeof(uint8_t)) || + copy_in_user(&ad_init->limit_ampl, + &ad_init32->limit_ampl, + sizeof(uint8_t)) || + copy_in_user(&ad_init->i_dither, + &ad_init32->i_dither, + sizeof(uint8_t)) || + copy_in_user(&ad_init->slope_max, + &ad_init32->slope_max, + sizeof(uint8_t)) || + copy_in_user(&ad_init->slope_min, + &ad_init32->slope_min, + sizeof(uint8_t)) || + copy_in_user(&ad_init->dither_ctl, + &ad_init32->dither_ctl, + sizeof(uint8_t)) || + copy_in_user(&ad_init->format, + &ad_init32->format, + sizeof(uint8_t)) || + copy_in_user(&ad_init->auto_size, + &ad_init32->auto_size, + sizeof(uint8_t)) || + copy_in_user(&ad_init->frame_w, + &ad_init32->frame_w, + sizeof(uint16_t)) || + copy_in_user(&ad_init->frame_h, + &ad_init32->frame_h, + sizeof(uint16_t)) || + copy_in_user(&ad_init->logo_v, + &ad_init32->logo_v, + sizeof(uint8_t)) || + copy_in_user(&ad_init->logo_h, + &ad_init32->logo_h, + sizeof(uint8_t)) || + copy_in_user(&ad_init->alpha, + &ad_init32->alpha, + sizeof(uint32_t)) || + copy_in_user(&ad_init->alpha_base, + &ad_init32->alpha_base, + sizeof(uint32_t)) || + copy_in_user(&ad_init->bl_lin_len, + &ad_init32->bl_lin_len, + sizeof(uint32_t)) || + copy_in_user(&ad_init->bl_att_len, + &ad_init32->bl_att_len, + sizeof(uint32_t))) + return -EFAULT; + + + if (get_user(data, &ad_init32->bl_lin) || + put_user(compat_ptr(data), &ad_init->bl_lin) || + get_user(data, &ad_init32->bl_lin_inv) || + put_user(compat_ptr(data), &ad_init->bl_lin_inv) || + get_user(data, &ad_init32->bl_att_lut) || + put_user(compat_ptr(data), &ad_init->bl_att_lut)) + return -EFAULT; + + return 0; +} + +static int __from_user_ad_cfg( + struct mdss_ad_cfg32 __user *ad_cfg32, + struct mdss_ad_cfg __user *ad_cfg) +{ + if (copy_in_user(&ad_cfg->mode, + &ad_cfg32->mode, + sizeof(uint32_t)) || + copy_in_user(&ad_cfg->al_calib_lut[0], + &ad_cfg32->al_calib_lut[0], + 33 * sizeof(uint32_t)) || + copy_in_user(&ad_cfg->backlight_min, + &ad_cfg32->backlight_min, + sizeof(uint16_t)) || + copy_in_user(&ad_cfg->backlight_max, + &ad_cfg32->backlight_max, + sizeof(uint16_t)) || + copy_in_user(&ad_cfg->backlight_scale, + &ad_cfg32->backlight_scale, + sizeof(uint16_t)) || + copy_in_user(&ad_cfg->amb_light_min, + &ad_cfg32->amb_light_min, + sizeof(uint16_t)) || + copy_in_user(&ad_cfg->filter[0], + &ad_cfg32->filter[0], + 2 * sizeof(uint16_t)) || + copy_in_user(&ad_cfg->calib[0], + &ad_cfg32->calib[0], + 4 * sizeof(uint16_t)) || + copy_in_user(&ad_cfg->strength_limit, + &ad_cfg32->strength_limit, + sizeof(uint8_t)) || + copy_in_user(&ad_cfg->t_filter_recursion, + &ad_cfg32->t_filter_recursion, + sizeof(uint8_t)) || + copy_in_user(&ad_cfg->stab_itr, + &ad_cfg32->stab_itr, + sizeof(uint16_t)) || + copy_in_user(&ad_cfg->bl_ctrl_mode, + &ad_cfg32->bl_ctrl_mode, + sizeof(uint32_t))) + return -EFAULT; + + return 0; +} + +static int __from_user_ad_init_cfg( + struct mdss_ad_init_cfg32 __user *ad_info32, + struct mdss_ad_init_cfg __user *ad_info) +{ + uint32_t op; + + if (copy_from_user(&op, &ad_info32->ops, + sizeof(uint32_t))) + return -EFAULT; + + if (copy_in_user(&ad_info->ops, + &ad_info32->ops, + sizeof(uint32_t))) + return -EFAULT; + + if (op & MDP_PP_AD_INIT) { + if (__from_user_ad_init( + compat_ptr((uintptr_t)&ad_info32->params.init), + &ad_info->params.init)) + return -EFAULT; + } else if (op & MDP_PP_AD_CFG) { + if (__from_user_ad_cfg( + compat_ptr((uintptr_t)&ad_info32->params.cfg), + &ad_info->params.cfg)) + return -EFAULT; + } else { + pr_err("Invalid AD init/config operation\n"); + return -EINVAL; + } + + return 0; +} + +static int __from_user_ad_input( + struct mdss_ad_input32 __user *ad_input32, + struct mdss_ad_input __user *ad_input) +{ + int mode; + + if (copy_from_user(&mode, + &ad_input32->mode, + sizeof(uint32_t))) + return -EFAULT; + + if (copy_in_user(&ad_input->mode, + &ad_input32->mode, + sizeof(uint32_t)) || + copy_in_user(&ad_input->output, + &ad_input32->output, + sizeof(uint32_t))) + return -EFAULT; + + switch (mode) { + case MDSS_AD_MODE_AUTO_BL: + case MDSS_AD_MODE_AUTO_STR: + if (copy_in_user(&ad_input->in.amb_light, + &ad_input32->in.amb_light, + sizeof(uint32_t))) + return -EFAULT; + break; + case MDSS_AD_MODE_TARG_STR: + case MDSS_AD_MODE_MAN_STR: + if (copy_in_user(&ad_input->in.strength, + &ad_input32->in.strength, + sizeof(uint32_t))) + return -EFAULT; + break; + case MDSS_AD_MODE_CALIB: + if (copy_in_user(&ad_input->in.calib_bl, + &ad_input32->in.calib_bl, + sizeof(uint32_t))) + return -EFAULT; + break; + } + + return 0; +} + +static int __to_user_ad_input( + struct mdss_ad_input32 __user *ad_input32, + struct mdss_ad_input __user *ad_input) +{ + int mode; + + if (copy_from_user(&mode, + &ad_input->mode, + sizeof(uint32_t))) + return -EFAULT; + + if (copy_in_user(&ad_input32->mode, + &ad_input->mode, + sizeof(uint32_t)) || + copy_in_user(&ad_input32->output, + &ad_input->output, + sizeof(uint32_t))) + return -EFAULT; + + switch (mode) { + case MDSS_AD_MODE_AUTO_BL: + case MDSS_AD_MODE_AUTO_STR: + if (copy_in_user(&ad_input32->in.amb_light, + &ad_input->in.amb_light, + sizeof(uint32_t))) + return -EFAULT; + break; + case MDSS_AD_MODE_TARG_STR: + case MDSS_AD_MODE_MAN_STR: + if (copy_in_user(&ad_input32->in.strength, + &ad_input->in.strength, + sizeof(uint32_t))) + return -EFAULT; + break; + case MDSS_AD_MODE_CALIB: + if (copy_in_user(&ad_input32->in.calib_bl, + &ad_input->in.calib_bl, + sizeof(uint32_t))) + return -EFAULT; + break; + } + + return 0; +} + +static int __from_user_calib_cfg( + struct mdss_calib_cfg32 __user *calib_cfg32, + struct mdss_calib_cfg __user *calib_cfg) +{ + if (copy_in_user(&calib_cfg->ops, + &calib_cfg32->ops, + sizeof(uint32_t)) || + copy_in_user(&calib_cfg->calib_mask, + &calib_cfg32->calib_mask, + sizeof(uint32_t))) + return -EFAULT; + + return 0; +} + +static int __from_user_calib_config_buffer( + struct mdp_calib_config_buffer32 __user *calib_buffer32, + struct mdp_calib_config_buffer __user *calib_buffer) +{ + uint32_t data; + + if (copy_in_user(&calib_buffer->ops, + &calib_buffer32->ops, + sizeof(uint32_t)) || + copy_in_user(&calib_buffer->size, + &calib_buffer32->size, + sizeof(uint32_t))) + return -EFAULT; + + if (get_user(data, &calib_buffer32->buffer) || + put_user(compat_ptr(data), &calib_buffer->buffer)) + return -EFAULT; + + return 0; +} + +static int __to_user_calib_config_buffer( + struct mdp_calib_config_buffer32 __user *calib_buffer32, + struct mdp_calib_config_buffer __user *calib_buffer) +{ + unsigned long data; + + if (copy_in_user(&calib_buffer32->ops, + &calib_buffer->ops, + sizeof(uint32_t)) || + copy_in_user(&calib_buffer32->size, + &calib_buffer->size, + sizeof(uint32_t))) + return -EFAULT; + + if (get_user(data, (unsigned long *) &calib_buffer->buffer) || + put_user((compat_caddr_t) data, &calib_buffer32->buffer)) + return -EFAULT; + + return 0; +} + +static int __from_user_calib_dcm_state( + struct mdp_calib_dcm_state32 __user *calib_dcm32, + struct mdp_calib_dcm_state __user *calib_dcm) +{ + if (copy_in_user(&calib_dcm->ops, + &calib_dcm32->ops, + sizeof(uint32_t)) || + copy_in_user(&calib_dcm->dcm_state, + &calib_dcm32->dcm_state, + sizeof(uint32_t))) + return -EFAULT; + + return 0; +} + +static u32 __pp_compat_size_igc(void) +{ + u32 alloc_size = 0; + /* When we have multiple versions pick largest struct size */ + alloc_size = sizeof(struct mdp_igc_lut_data_v1_7); + return alloc_size; +} + +static u32 __pp_compat_size_hist_lut(void) +{ + u32 alloc_size = 0; + /* When we have multiple versions pick largest struct size */ + alloc_size = sizeof(struct mdp_hist_lut_data_v1_7); + return alloc_size; +} + +static u32 __pp_compat_size_pgc(void) +{ + u32 tbl_sz_max = 0; + + tbl_sz_max = 3 * GC_LUT_SEGMENTS * sizeof(struct mdp_ar_gc_lut_data); + tbl_sz_max += sizeof(struct mdp_pgc_lut_data_v1_7); + return tbl_sz_max; +} + +static u32 __pp_compat_size_pcc(void) +{ + /* if new version of PCC is added return max struct size */ + return sizeof(struct mdp_pcc_data_v1_7); +} + +static u32 __pp_compat_size_pa(void) +{ + /* if new version of PA is added return max struct size */ + return sizeof(struct mdp_pa_data_v1_7); +} + +static u32 __pp_compat_size_gamut(void) +{ + return sizeof(struct mdp_gamut_data_v1_7); +} + +static int __pp_compat_alloc(struct msmfb_mdp_pp32 __user *pp32, + struct msmfb_mdp_pp __user **pp, + uint32_t op) +{ + uint32_t alloc_size = 0, lut_type, pgc_size = 0; + + alloc_size = sizeof(struct msmfb_mdp_pp); + switch (op) { + case mdp_op_lut_cfg: + if (copy_from_user(&lut_type, + &pp32->data.lut_cfg_data.lut_type, + sizeof(uint32_t))) + return -EFAULT; + + switch (lut_type) { + case mdp_lut_pgc: + + pgc_size = GC_LUT_SEGMENTS * + sizeof(struct mdp_ar_gc_lut_data); + alloc_size += __pp_compat_size_pgc(); + + *pp = compat_alloc_user_space(alloc_size); + if (*pp == NULL) + return -ENOMEM; + memset(*pp, 0, alloc_size); + + (*pp)->data.lut_cfg_data.data.pgc_lut_data.r_data = + (struct mdp_ar_gc_lut_data *) + ((unsigned long) *pp + + sizeof(struct msmfb_mdp_pp)); + (*pp)->data.lut_cfg_data.data.pgc_lut_data.g_data = + (struct mdp_ar_gc_lut_data *) + ((unsigned long) *pp + + sizeof(struct msmfb_mdp_pp) + + pgc_size); + (*pp)->data.lut_cfg_data.data.pgc_lut_data.b_data = + (struct mdp_ar_gc_lut_data *) + ((unsigned long) *pp + + sizeof(struct msmfb_mdp_pp) + + (2 * pgc_size)); + (*pp)->data.lut_cfg_data.data.pgc_lut_data.cfg_payload + = (void *)((unsigned long) *pp + + sizeof(struct msmfb_mdp_pp) + + (3 * pgc_size)); + break; + case mdp_lut_igc: + alloc_size += __pp_compat_size_igc(); + *pp = compat_alloc_user_space(alloc_size); + if (*pp == NULL) { + pr_err("failed to alloc from user size %d for igc\n", + alloc_size); + return -ENOMEM; + } + memset(*pp, 0, alloc_size); + (*pp)->data.lut_cfg_data.data.igc_lut_data.cfg_payload + = (void *)((unsigned long)(*pp) + + sizeof(struct msmfb_mdp_pp)); + break; + case mdp_lut_hist: + alloc_size += __pp_compat_size_hist_lut(); + *pp = compat_alloc_user_space(alloc_size); + if (*pp == NULL) { + pr_err("failed to alloc from user size %d for hist lut\n", + alloc_size); + return -ENOMEM; + } + memset(*pp, 0, alloc_size); + (*pp)->data.lut_cfg_data.data.hist_lut_data.cfg_payload + = (void *)((unsigned long)(*pp) + + sizeof(struct msmfb_mdp_pp)); + break; + default: + *pp = compat_alloc_user_space(alloc_size); + if (*pp == NULL) { + pr_err("failed to alloc from user size %d for lut_type %d\n", + alloc_size, lut_type); + return -ENOMEM; + } + memset(*pp, 0, alloc_size); + break; + } + break; + case mdp_op_pcc_cfg: + alloc_size += __pp_compat_size_pcc(); + *pp = compat_alloc_user_space(alloc_size); + if (*pp == NULL) { + pr_err("alloc from user size %d for pcc fail\n", + alloc_size); + return -ENOMEM; + } + memset(*pp, 0, alloc_size); + (*pp)->data.pcc_cfg_data.cfg_payload = + (void *)((unsigned long)(*pp) + + sizeof(struct msmfb_mdp_pp)); + break; + case mdp_op_gamut_cfg: + alloc_size += __pp_compat_size_gamut(); + *pp = compat_alloc_user_space(alloc_size); + if (*pp == NULL) { + pr_err("alloc from user size %d for pcc fail\n", + alloc_size); + return -ENOMEM; + } + memset(*pp, 0, alloc_size); + (*pp)->data.gamut_cfg_data.cfg_payload = + (void *)((unsigned long)(*pp) + + sizeof(struct msmfb_mdp_pp)); + break; + case mdp_op_pa_v2_cfg: + alloc_size += __pp_compat_size_pa(); + *pp = compat_alloc_user_space(alloc_size); + if (*pp == NULL) { + pr_err("alloc from user size %d for pcc fail\n", + alloc_size); + return -ENOMEM; + } + memset(*pp, 0, alloc_size); + (*pp)->data.pa_v2_cfg_data.cfg_payload = + (void *)((unsigned long)(*pp) + + sizeof(struct msmfb_mdp_pp)); + break; + default: + *pp = compat_alloc_user_space(alloc_size); + if (*pp == NULL) + return -ENOMEM; + memset(*pp, 0, alloc_size); + break; + } + return 0; +} + +static int mdss_compat_pp_ioctl(struct fb_info *info, unsigned int cmd, + unsigned long arg, struct file *file) +{ + uint32_t op; + int ret = 0; + struct msmfb_mdp_pp32 __user *pp32; + struct msmfb_mdp_pp __user *pp; + + pp32 = compat_ptr(arg); + if (copy_from_user(&op, &pp32->op, sizeof(uint32_t))) + return -EFAULT; + + ret = __pp_compat_alloc(pp32, &pp, op); + if (ret) + return ret; + + if (copy_in_user(&pp->op, &pp32->op, sizeof(uint32_t))) + return -EFAULT; + + switch (op) { + case mdp_op_pcc_cfg: + ret = __from_user_pcc_cfg_data( + compat_ptr((uintptr_t)&pp32->data.pcc_cfg_data), + &pp->data.pcc_cfg_data); + if (ret) + goto pp_compat_exit; + ret = mdss_fb_do_ioctl(info, cmd, (unsigned long) pp, file); + if (ret) + goto pp_compat_exit; + ret = __to_user_pcc_cfg_data( + compat_ptr((uintptr_t)&pp32->data.pcc_cfg_data), + &pp->data.pcc_cfg_data); + break; + case mdp_op_csc_cfg: + ret = __from_user_csc_cfg_data( + compat_ptr((uintptr_t)&pp32->data.csc_cfg_data), + &pp->data.csc_cfg_data); + if (ret) + goto pp_compat_exit; + ret = mdss_fb_do_ioctl(info, cmd, (unsigned long) pp, file); + if (ret) + goto pp_compat_exit; + ret = __to_user_csc_cfg_data( + compat_ptr((uintptr_t)&pp32->data.csc_cfg_data), + &pp->data.csc_cfg_data); + break; + case mdp_op_lut_cfg: + ret = __from_user_lut_cfg_data( + compat_ptr((uintptr_t)&pp32->data.lut_cfg_data), + &pp->data.lut_cfg_data); + if (ret) + goto pp_compat_exit; + ret = mdss_fb_do_ioctl(info, cmd, (unsigned long) pp, file); + if (ret) + goto pp_compat_exit; + ret = __to_user_lut_cfg_data( + compat_ptr((uintptr_t)&pp32->data.lut_cfg_data), + &pp->data.lut_cfg_data); + break; + case mdp_op_qseed_cfg: + ret = __from_user_qseed_cfg_data( + compat_ptr((uintptr_t)&pp32->data.qseed_cfg_data), + &pp->data.qseed_cfg_data); + if (ret) + goto pp_compat_exit; + ret = mdss_fb_do_ioctl(info, cmd, (unsigned long) pp, file); + if (ret) + goto pp_compat_exit; + ret = __to_user_qseed_cfg_data( + compat_ptr((uintptr_t)&pp32->data.qseed_cfg_data), + &pp->data.qseed_cfg_data); + break; + case mdp_bl_scale_cfg: + ret = __from_user_bl_scale_data( + compat_ptr((uintptr_t)&pp32->data.bl_scale_data), + &pp->data.bl_scale_data); + if (ret) + goto pp_compat_exit; + ret = mdss_fb_do_ioctl(info, cmd, (unsigned long) pp, file); + break; + case mdp_op_pa_cfg: + ret = __from_user_pa_cfg_data( + compat_ptr((uintptr_t)&pp32->data.pa_cfg_data), + &pp->data.pa_cfg_data); + if (ret) + goto pp_compat_exit; + ret = mdss_fb_do_ioctl(info, cmd, (unsigned long) pp, file); + if (ret) + goto pp_compat_exit; + ret = __to_user_pa_cfg_data( + compat_ptr((uintptr_t)&pp32->data.pa_cfg_data), + &pp->data.pa_cfg_data); + break; + case mdp_op_pa_v2_cfg: + ret = __from_user_pa_v2_cfg_data( + compat_ptr((uintptr_t)&pp32->data.pa_v2_cfg_data), + &pp->data.pa_v2_cfg_data); + if (ret) + goto pp_compat_exit; + ret = mdss_fb_do_ioctl(info, cmd, (unsigned long) pp, file); + if (ret) + goto pp_compat_exit; + ret = __to_user_pa_v2_cfg_data( + compat_ptr((uintptr_t)&pp32->data.pa_v2_cfg_data), + &pp->data.pa_v2_cfg_data); + break; + case mdp_op_dither_cfg: + ret = __from_user_dither_cfg_data( + compat_ptr((uintptr_t)&pp32->data.dither_cfg_data), + &pp->data.dither_cfg_data); + if (ret) + goto pp_compat_exit; + ret = mdss_fb_do_ioctl(info, cmd, (unsigned long) pp, file); + if (ret) + goto pp_compat_exit; + ret = __to_user_dither_cfg_data( + compat_ptr((uintptr_t)&pp32->data.dither_cfg_data), + &pp->data.dither_cfg_data); + break; + case mdp_op_gamut_cfg: + ret = __from_user_gamut_cfg_data( + compat_ptr((uintptr_t)&pp32->data.gamut_cfg_data), + &pp->data.gamut_cfg_data); + if (ret) + goto pp_compat_exit; + ret = mdss_fb_do_ioctl(info, cmd, (unsigned long) pp, file); + if (ret) + goto pp_compat_exit; + ret = __to_user_gamut_cfg_data( + compat_ptr((uintptr_t)&pp32->data.gamut_cfg_data), + &pp->data.gamut_cfg_data); + break; + case mdp_op_calib_cfg: + ret = __from_user_calib_config_data( + compat_ptr((uintptr_t)&pp32->data.calib_cfg), + &pp->data.calib_cfg); + if (ret) + goto pp_compat_exit; + ret = mdss_fb_do_ioctl(info, cmd, (unsigned long) pp, file); + if (ret) + goto pp_compat_exit; + ret = __to_user_calib_config_data( + compat_ptr((uintptr_t)&pp32->data.calib_cfg), + &pp->data.calib_cfg); + break; + case mdp_op_ad_cfg: + ret = __from_user_ad_init_cfg( + compat_ptr((uintptr_t)&pp32->data.ad_init_cfg), + &pp->data.ad_init_cfg); + if (ret) + goto pp_compat_exit; + ret = mdss_fb_do_ioctl(info, cmd, (unsigned long) pp, file); + break; + case mdp_op_ad_input: + ret = __from_user_ad_input( + compat_ptr((uintptr_t)&pp32->data.ad_input), + &pp->data.ad_input); + if (ret) + goto pp_compat_exit; + ret = mdss_fb_do_ioctl(info, cmd, (unsigned long) pp, file); + if (ret) + goto pp_compat_exit; + ret = __to_user_ad_input( + compat_ptr((uintptr_t)&pp32->data.ad_input), + &pp->data.ad_input); + break; + case mdp_op_calib_mode: + ret = __from_user_calib_cfg( + compat_ptr((uintptr_t)&pp32->data.mdss_calib_cfg), + &pp->data.mdss_calib_cfg); + if (ret) + goto pp_compat_exit; + ret = mdss_fb_do_ioctl(info, cmd, (unsigned long) pp, file); + break; + case mdp_op_calib_buffer: + ret = __from_user_calib_config_buffer( + compat_ptr((uintptr_t)&pp32->data.calib_buffer), + &pp->data.calib_buffer); + if (ret) + goto pp_compat_exit; + ret = mdss_fb_do_ioctl(info, cmd, (unsigned long) pp, file); + if (ret) + goto pp_compat_exit; + ret = __to_user_calib_config_buffer( + compat_ptr((uintptr_t)&pp32->data.calib_buffer), + &pp->data.calib_buffer); + break; + case mdp_op_calib_dcm_state: + ret = __from_user_calib_dcm_state( + compat_ptr((uintptr_t)&pp32->data.calib_dcm), + &pp->data.calib_dcm); + if (ret) + goto pp_compat_exit; + ret = mdss_fb_do_ioctl(info, cmd, (unsigned long) pp, file); + break; + default: + break; + } + +pp_compat_exit: + return ret; +} + +static int __from_user_pp_params(struct mdp_overlay_pp_params32 *ppp32, + struct mdp_overlay_pp_params *ppp) +{ + int ret = 0; + + if (copy_in_user(&ppp->config_ops, + &ppp32->config_ops, + sizeof(uint32_t))) + return -EFAULT; + + ret = __from_user_csc_cfg( + compat_ptr((uintptr_t)&ppp32->csc_cfg), + &ppp->csc_cfg); + if (ret) + return ret; + ret = __from_user_qseed_cfg( + compat_ptr((uintptr_t)&ppp32->qseed_cfg[0]), + &ppp->qseed_cfg[0]); + if (ret) + return ret; + ret = __from_user_qseed_cfg( + compat_ptr((uintptr_t)&ppp32->qseed_cfg[1]), + &ppp->qseed_cfg[1]); + if (ret) + return ret; + ret = __from_user_pa_cfg( + compat_ptr((uintptr_t)&ppp32->pa_cfg), + &ppp->pa_cfg); + if (ret) + return ret; + ret = __from_user_igc_lut_data( + compat_ptr((uintptr_t)&ppp32->igc_cfg), + &ppp->igc_cfg); + if (ret) + return ret; + ret = __from_user_sharp_cfg( + compat_ptr((uintptr_t)&ppp32->sharp_cfg), + &ppp->sharp_cfg); + if (ret) + return ret; + ret = __from_user_histogram_cfg( + compat_ptr((uintptr_t)&ppp32->hist_cfg), + &ppp->hist_cfg); + if (ret) + return ret; + ret = __from_user_hist_lut_data( + compat_ptr((uintptr_t)&ppp32->hist_lut_cfg), + &ppp->hist_lut_cfg); + if (ret) + return ret; + ret = __from_user_pa_v2_data( + compat_ptr((uintptr_t)&ppp32->pa_v2_cfg), + &ppp->pa_v2_cfg); + + return ret; +} + +static int __to_user_pp_params(struct mdp_overlay_pp_params *ppp, + struct mdp_overlay_pp_params32 *ppp32) +{ + int ret = 0; + + if (copy_in_user(&ppp32->config_ops, + &ppp->config_ops, + sizeof(uint32_t))) + return -EFAULT; + + ret = __to_user_csc_cfg( + compat_ptr((uintptr_t)&ppp32->csc_cfg), + &ppp->csc_cfg); + if (ret) + return ret; + ret = __to_user_qseed_cfg( + compat_ptr((uintptr_t)&ppp32->qseed_cfg[0]), + &ppp->qseed_cfg[0]); + if (ret) + return ret; + ret = __to_user_qseed_cfg( + compat_ptr((uintptr_t)&ppp32->qseed_cfg[1]), + &ppp->qseed_cfg[1]); + if (ret) + return ret; + ret = __to_user_pa_cfg( + compat_ptr((uintptr_t)&ppp32->pa_cfg), + &ppp->pa_cfg); + if (ret) + return ret; + ret = __to_user_igc_lut_data( + compat_ptr((uintptr_t)&ppp32->igc_cfg), + &ppp->igc_cfg); + if (ret) + return ret; + ret = __to_user_sharp_cfg( + compat_ptr((uintptr_t)&ppp32->sharp_cfg), + &ppp->sharp_cfg); + if (ret) + return ret; + ret = __to_user_histogram_cfg( + compat_ptr((uintptr_t)&ppp32->hist_cfg), + &ppp->hist_cfg); + if (ret) + return ret; + ret = __to_user_hist_lut_data( + compat_ptr((uintptr_t)&ppp32->hist_lut_cfg), + &ppp->hist_lut_cfg); + if (ret) + return ret; + ret = __to_user_pa_v2_data( + compat_ptr((uintptr_t)&ppp32->pa_v2_cfg), + &ppp->pa_v2_cfg); + + return ret; +} + +static int __from_user_hist_start_req( + struct mdp_histogram_start_req32 __user *hist_req32, + struct mdp_histogram_start_req __user *hist_req) +{ + if (copy_in_user(&hist_req->block, + &hist_req32->block, + sizeof(uint32_t)) || + copy_in_user(&hist_req->frame_cnt, + &hist_req32->frame_cnt, + sizeof(uint8_t)) || + copy_in_user(&hist_req->bit_mask, + &hist_req32->bit_mask, + sizeof(uint8_t)) || + copy_in_user(&hist_req->num_bins, + &hist_req32->num_bins, + sizeof(uint16_t))) + return -EFAULT; + + return 0; +} + +static int __from_user_hist_data( + struct mdp_histogram_data32 __user *hist_data32, + struct mdp_histogram_data __user *hist_data) +{ + uint32_t data; + + if (copy_in_user(&hist_data->block, + &hist_data32->block, + sizeof(uint32_t)) || + copy_in_user(&hist_data->bin_cnt, + &hist_data32->bin_cnt, + sizeof(uint32_t))) + return -EFAULT; + + if (get_user(data, &hist_data32->c0) || + put_user(compat_ptr(data), &hist_data->c0) || + get_user(data, &hist_data32->c1) || + put_user(compat_ptr(data), &hist_data->c1) || + get_user(data, &hist_data32->c2) || + put_user(compat_ptr(data), &hist_data->c2) || + get_user(data, &hist_data32->extra_info) || + put_user(compat_ptr(data), &hist_data->extra_info)) + return -EFAULT; + + return 0; +} + +static int __to_user_hist_data( + struct mdp_histogram_data32 __user *hist_data32, + struct mdp_histogram_data __user *hist_data) +{ + unsigned long data; + + if (copy_in_user(&hist_data32->block, + &hist_data->block, + sizeof(uint32_t)) || + copy_in_user(&hist_data32->bin_cnt, + &hist_data->bin_cnt, + sizeof(uint32_t))) + return -EFAULT; + + if (get_user(data, (unsigned long *) &hist_data->c0) || + put_user((compat_caddr_t) data, &hist_data32->c0) || + get_user(data, (unsigned long *) &hist_data->c1) || + put_user((compat_caddr_t) data, &hist_data32->c1) || + get_user(data, (unsigned long *) &hist_data->c2) || + put_user((compat_caddr_t) data, &hist_data32->c2) || + get_user(data, (unsigned long *) &hist_data->extra_info) || + put_user((compat_caddr_t) data, &hist_data32->extra_info)) + return -EFAULT; + + return 0; +} + +static int mdss_histo_compat_ioctl(struct fb_info *info, unsigned int cmd, + unsigned long arg, struct file *file) +{ + struct mdp_histogram_data __user *hist; + struct mdp_histogram_data32 __user *hist32; + struct mdp_histogram_start_req __user *hist_req; + struct mdp_histogram_start_req32 __user *hist_req32; + int ret = 0; + + switch (cmd) { + case MSMFB_HISTOGRAM_START: + hist_req32 = compat_ptr(arg); + hist_req = compat_alloc_user_space( + sizeof(struct mdp_histogram_start_req)); + if (!hist_req) { + pr_err("%s:%u: compat alloc error [%zu] bytes\n", + __func__, __LINE__, + sizeof(struct mdp_histogram_start_req)); + return -EINVAL; + } + memset(hist_req, 0, sizeof(struct mdp_histogram_start_req)); + ret = __from_user_hist_start_req(hist_req32, hist_req); + if (ret) + goto histo_compat_err; + ret = mdss_fb_do_ioctl(info, cmd, + (unsigned long) hist_req, file); + break; + case MSMFB_HISTOGRAM_STOP: + ret = mdss_fb_do_ioctl(info, cmd, arg, file); + break; + case MSMFB_HISTOGRAM: + hist32 = compat_ptr(arg); + hist = compat_alloc_user_space( + sizeof(struct mdp_histogram_data)); + if (!hist) { + pr_err("%s:%u: compat alloc error [%zu] bytes\n", + __func__, __LINE__, + sizeof(struct mdp_histogram_data)); + return -EINVAL; + } + memset(hist, 0, sizeof(struct mdp_histogram_data)); + ret = __from_user_hist_data(hist32, hist); + if (ret) + goto histo_compat_err; + ret = mdss_fb_do_ioctl(info, cmd, (unsigned long) hist, file); + if (ret) + goto histo_compat_err; + ret = __to_user_hist_data(hist32, hist); + break; + default: + break; + } + +histo_compat_err: + return ret; +} + +static int __copy_layer_pp_info_qseed_params( + struct mdp_overlay_pp_params *pp_info, + struct mdp_overlay_pp_params32 *pp_info32) +{ + pp_info->qseed_cfg[0].table_num = pp_info32->qseed_cfg[0].table_num; + pp_info->qseed_cfg[0].ops = pp_info32->qseed_cfg[0].ops; + pp_info->qseed_cfg[0].len = pp_info32->qseed_cfg[0].len; + pp_info->qseed_cfg[0].data = compat_ptr(pp_info32->qseed_cfg[0].data); + + pp_info->qseed_cfg[1].table_num = pp_info32->qseed_cfg[1].table_num; + pp_info->qseed_cfg[1].ops = pp_info32->qseed_cfg[1].ops; + pp_info->qseed_cfg[1].len = pp_info32->qseed_cfg[1].len; + pp_info->qseed_cfg[1].data = compat_ptr(pp_info32->qseed_cfg[1].data); + + return 0; +} + +static int __copy_layer_igc_lut_data_v1_7( + struct mdp_igc_lut_data_v1_7 *cfg_payload, + struct mdp_igc_lut_data_v1_7_32 __user *cfg_payload32) +{ + struct mdp_igc_lut_data_v1_7_32 local_cfg_payload32; + int ret = 0; + + ret = copy_from_user(&local_cfg_payload32, + cfg_payload32, + sizeof(struct mdp_igc_lut_data_v1_7_32)); + if (ret) { + pr_err("copy from user failed, IGC cfg payload = %pK\n", + cfg_payload32); + ret = -EFAULT; + goto exit; + } + + cfg_payload->table_fmt = local_cfg_payload32.table_fmt; + cfg_payload->len = local_cfg_payload32.len; + cfg_payload->c0_c1_data = compat_ptr(local_cfg_payload32.c0_c1_data); + cfg_payload->c2_data = compat_ptr(local_cfg_payload32.c2_data); + +exit: + return ret; +} + +static int __copy_layer_pp_info_igc_params( + struct mdp_overlay_pp_params *pp_info, + struct mdp_overlay_pp_params32 *pp_info32) +{ + void *cfg_payload = NULL; + uint32_t payload_size = 0; + int ret = 0; + + pp_info->igc_cfg.block = pp_info32->igc_cfg.block; + pp_info->igc_cfg.version = pp_info32->igc_cfg.version; + pp_info->igc_cfg.ops = pp_info32->igc_cfg.ops; + + if (pp_info->igc_cfg.version != 0) { + payload_size = __pp_compat_size_igc(); + + cfg_payload = kmalloc(payload_size, GFP_KERNEL); + if (!cfg_payload) { + ret = -ENOMEM; + goto exit; + } + } + + switch (pp_info->igc_cfg.version) { + case mdp_igc_v1_7: + ret = __copy_layer_igc_lut_data_v1_7(cfg_payload, + compat_ptr(pp_info32->igc_cfg.cfg_payload)); + if (ret) { + pr_err("compat copy of IGC cfg payload failed, ret %d\n", + ret); + kfree(cfg_payload); + cfg_payload = NULL; + goto exit; + } + break; + default: + pr_debug("No version set, fallback to legacy IGC version\n"); + pp_info->igc_cfg.len = pp_info32->igc_cfg.len; + pp_info->igc_cfg.c0_c1_data = + compat_ptr(pp_info32->igc_cfg.c0_c1_data); + pp_info->igc_cfg.c2_data = + compat_ptr(pp_info32->igc_cfg.c2_data); + kfree(cfg_payload); + cfg_payload = NULL; + break; + } +exit: + pp_info->igc_cfg.cfg_payload = cfg_payload; + return ret; +} + +static int __copy_layer_hist_lut_data_v1_7( + struct mdp_hist_lut_data_v1_7 *cfg_payload, + struct mdp_hist_lut_data_v1_7_32 __user *cfg_payload32) +{ + struct mdp_hist_lut_data_v1_7_32 local_cfg_payload32; + int ret = 0; + + ret = copy_from_user(&local_cfg_payload32, + cfg_payload32, + sizeof(struct mdp_hist_lut_data_v1_7_32)); + if (ret) { + pr_err("copy from user failed, hist lut cfg_payload = %pK\n", + cfg_payload32); + ret = -EFAULT; + goto exit; + } + + cfg_payload->len = local_cfg_payload32.len; + cfg_payload->data = compat_ptr(local_cfg_payload32.data); +exit: + return ret; +} + +static int __copy_layer_pp_info_hist_lut_params( + struct mdp_overlay_pp_params *pp_info, + struct mdp_overlay_pp_params32 *pp_info32) +{ + void *cfg_payload = NULL; + uint32_t payload_size = 0; + int ret = 0; + + pp_info->hist_lut_cfg.block = pp_info32->hist_lut_cfg.block; + pp_info->hist_lut_cfg.version = pp_info32->hist_lut_cfg.version; + pp_info->hist_lut_cfg.ops = pp_info32->hist_lut_cfg.ops; + pp_info->hist_lut_cfg.hist_lut_first = + pp_info32->hist_lut_cfg.hist_lut_first; + + if (pp_info->hist_lut_cfg.version != 0) { + payload_size = __pp_compat_size_hist_lut(); + + cfg_payload = kmalloc(payload_size, GFP_KERNEL); + if (!cfg_payload) { + ret = -ENOMEM; + goto exit; + } + } + + switch (pp_info->hist_lut_cfg.version) { + case mdp_hist_lut_v1_7: + ret = __copy_layer_hist_lut_data_v1_7(cfg_payload, + compat_ptr(pp_info32->hist_lut_cfg.cfg_payload)); + if (ret) { + pr_err("compat copy of Hist LUT cfg payload failed, ret %d\n", + ret); + kfree(cfg_payload); + cfg_payload = NULL; + goto exit; + } + break; + default: + pr_debug("version invalid, fallback to legacy\n"); + pp_info->hist_lut_cfg.len = pp_info32->hist_lut_cfg.len; + pp_info->hist_lut_cfg.data = + compat_ptr(pp_info32->hist_lut_cfg.data); + kfree(cfg_payload); + cfg_payload = NULL; + break; + } +exit: + pp_info->hist_lut_cfg.cfg_payload = cfg_payload; + return ret; +} + +static int __copy_layer_pa_data_v1_7( + struct mdp_pa_data_v1_7 *cfg_payload, + struct mdp_pa_data_v1_7_32 __user *cfg_payload32) +{ + struct mdp_pa_data_v1_7_32 local_cfg_payload32; + int ret = 0; + + ret = copy_from_user(&local_cfg_payload32, + cfg_payload32, + sizeof(struct mdp_pa_data_v1_7_32)); + if (ret) { + pr_err("copy from user failed, pa cfg_payload = %pK\n", + cfg_payload32); + ret = -EFAULT; + goto exit; + } + + cfg_payload->mode = local_cfg_payload32.mode; + cfg_payload->global_hue_adj = local_cfg_payload32.global_hue_adj; + cfg_payload->global_sat_adj = local_cfg_payload32.global_sat_adj; + cfg_payload->global_val_adj = local_cfg_payload32.global_val_adj; + cfg_payload->global_cont_adj = local_cfg_payload32.global_cont_adj; + + memcpy(&cfg_payload->skin_cfg, &local_cfg_payload32.skin_cfg, + sizeof(struct mdp_pa_mem_col_data_v1_7)); + memcpy(&cfg_payload->sky_cfg, &local_cfg_payload32.sky_cfg, + sizeof(struct mdp_pa_mem_col_data_v1_7)); + memcpy(&cfg_payload->fol_cfg, &local_cfg_payload32.fol_cfg, + sizeof(struct mdp_pa_mem_col_data_v1_7)); + + cfg_payload->six_zone_thresh = local_cfg_payload32.six_zone_thresh; + cfg_payload->six_zone_adj_p0 = local_cfg_payload32.six_zone_adj_p0; + cfg_payload->six_zone_adj_p1 = local_cfg_payload32.six_zone_adj_p1; + cfg_payload->six_zone_sat_hold = local_cfg_payload32.six_zone_sat_hold; + cfg_payload->six_zone_val_hold = local_cfg_payload32.six_zone_val_hold; + cfg_payload->six_zone_len = local_cfg_payload32.six_zone_len; + + cfg_payload->six_zone_curve_p0 = + compat_ptr(local_cfg_payload32.six_zone_curve_p0); + cfg_payload->six_zone_curve_p1 = + compat_ptr(local_cfg_payload32.six_zone_curve_p1); +exit: + return ret; +} + +static int __copy_layer_pp_info_pa_v2_params( + struct mdp_overlay_pp_params *pp_info, + struct mdp_overlay_pp_params32 *pp_info32) +{ + void *cfg_payload = NULL; + uint32_t payload_size = 0; + int ret = 0; + + pp_info->pa_v2_cfg_data.block = pp_info32->pa_v2_cfg_data.block; + pp_info->pa_v2_cfg_data.version = pp_info32->pa_v2_cfg_data.version; + pp_info->pa_v2_cfg_data.flags = pp_info32->pa_v2_cfg_data.flags; + + if (pp_info->pa_v2_cfg_data.version != 0) { + payload_size = __pp_compat_size_pa(); + + cfg_payload = kmalloc(payload_size, GFP_KERNEL); + if (!cfg_payload) { + ret = -ENOMEM; + goto exit; + } + } + + switch (pp_info->pa_v2_cfg_data.version) { + case mdp_pa_v1_7: + ret = __copy_layer_pa_data_v1_7(cfg_payload, + compat_ptr(pp_info32->pa_v2_cfg_data.cfg_payload)); + if (ret) { + pr_err("compat copy of PA cfg payload failed, ret %d\n", + ret); + kfree(cfg_payload); + cfg_payload = NULL; + goto exit; + } + break; + default: + pr_debug("version invalid\n"); + kfree(cfg_payload); + cfg_payload = NULL; + break; + } +exit: + pp_info->pa_v2_cfg_data.cfg_payload = cfg_payload; + return ret; +} + +static int __copy_layer_pp_info_legacy_pa_v2_params( + struct mdp_overlay_pp_params *pp_info, + struct mdp_overlay_pp_params32 *pp_info32) +{ + pp_info->pa_v2_cfg.global_hue_adj = + pp_info32->pa_v2_cfg.global_hue_adj; + pp_info->pa_v2_cfg.global_sat_adj = + pp_info32->pa_v2_cfg.global_sat_adj; + pp_info->pa_v2_cfg.global_val_adj = + pp_info32->pa_v2_cfg.global_val_adj; + pp_info->pa_v2_cfg.global_cont_adj = + pp_info32->pa_v2_cfg.global_cont_adj; + + memcpy(&pp_info->pa_v2_cfg.skin_cfg, + &pp_info32->pa_v2_cfg.skin_cfg, + sizeof(struct mdp_pa_mem_col_cfg)); + memcpy(&pp_info->pa_v2_cfg.sky_cfg, + &pp_info32->pa_v2_cfg.sky_cfg, + sizeof(struct mdp_pa_mem_col_cfg)); + memcpy(&pp_info->pa_v2_cfg.fol_cfg, + &pp_info32->pa_v2_cfg.fol_cfg, + sizeof(struct mdp_pa_mem_col_cfg)); + + pp_info->pa_v2_cfg.six_zone_thresh = + pp_info32->pa_v2_cfg.six_zone_thresh; + pp_info->pa_v2_cfg.six_zone_len = + pp_info32->pa_v2_cfg.six_zone_len; + + pp_info->pa_v2_cfg.six_zone_curve_p0 = + compat_ptr(pp_info32->pa_v2_cfg.six_zone_curve_p0); + pp_info->pa_v2_cfg.six_zone_curve_p1 = + compat_ptr(pp_info32->pa_v2_cfg.six_zone_curve_p1); + + return 0; +} + +static int __copy_layer_pp_info_pcc_params( + struct mdp_overlay_pp_params *pp_info, + struct mdp_overlay_pp_params32 *pp_info32) +{ + void *cfg_payload = NULL; + uint32_t payload_size = 0; + int ret = 0; + + pp_info->pcc_cfg_data.block = pp_info32->pcc_cfg_data.block; + pp_info->pcc_cfg_data.version = pp_info32->pcc_cfg_data.version; + pp_info->pcc_cfg_data.ops = pp_info32->pcc_cfg_data.ops; + + if (pp_info->pcc_cfg_data.version != 0) { + payload_size = __pp_compat_size_pcc(); + + cfg_payload = kmalloc(payload_size, GFP_KERNEL); + if (!cfg_payload) { + ret = -ENOMEM; + goto exit; + } + } + + switch (pp_info->pcc_cfg_data.version) { + case mdp_pcc_v1_7: + ret = copy_from_user(cfg_payload, + compat_ptr(pp_info32->pcc_cfg_data.cfg_payload), + sizeof(struct mdp_pcc_data_v1_7)); + if (ret) { + pr_err("compat copy of PCC cfg payload failed, ptr %pK\n", + compat_ptr( + pp_info32->pcc_cfg_data.cfg_payload)); + ret = -EFAULT; + kfree(cfg_payload); + cfg_payload = NULL; + goto exit; + } + break; + default: + pr_debug("version invalid, fallback to legacy\n"); + kfree(cfg_payload); + cfg_payload = NULL; + break; + } +exit: + pp_info->pcc_cfg_data.cfg_payload = cfg_payload; + return ret; +} + + +static int __copy_layer_pp_info_params(struct mdp_input_layer *layer, + struct mdp_input_layer32 *layer32) +{ + struct mdp_overlay_pp_params *pp_info; + struct mdp_overlay_pp_params32 pp_info32; + int ret = 0; + + if (!(layer->flags & MDP_LAYER_PP)) + return 0; + + ret = copy_from_user(&pp_info32, + compat_ptr(layer32->pp_info), + sizeof(struct mdp_overlay_pp_params32)); + if (ret) { + pr_err("pp info copy from user failed, pp_info %pK\n", + compat_ptr(layer32->pp_info)); + ret = -EFAULT; + goto exit; + } + + pp_info = kmalloc(sizeof(struct mdp_overlay_pp_params), GFP_KERNEL); + if (!pp_info) { + ret = -ENOMEM; + goto exit; + } + memset(pp_info, 0, sizeof(struct mdp_overlay_pp_params)); + + pp_info->config_ops = pp_info32.config_ops; + + memcpy(&pp_info->csc_cfg, &pp_info32.csc_cfg, + sizeof(struct mdp_csc_cfg)); + memcpy(&pp_info->sharp_cfg, &pp_info32.sharp_cfg, + sizeof(struct mdp_sharp_cfg)); + memcpy(&pp_info->hist_cfg, &pp_info32.hist_cfg, + sizeof(struct mdp_histogram_cfg)); + memcpy(&pp_info->pa_cfg, &pp_info32.pa_cfg, + sizeof(struct mdp_pa_cfg)); + + ret = __copy_layer_pp_info_qseed_params(pp_info, &pp_info32); + if (ret) { + pr_err("compat copy pp_info QSEED params failed, ret %d\n", + ret); + goto exit_pp_info; + } + ret = __copy_layer_pp_info_legacy_pa_v2_params(pp_info, &pp_info32); + if (ret) { + pr_err("compat copy pp_info Legacy PAv2 params failed, ret %d\n", + ret); + goto exit_pp_info; + } + ret = __copy_layer_pp_info_igc_params(pp_info, &pp_info32); + if (ret) { + pr_err("compat copy pp_info IGC params failed, ret %d\n", + ret); + goto exit_pp_info; + } + ret = __copy_layer_pp_info_hist_lut_params(pp_info, &pp_info32); + if (ret) { + pr_err("compat copy pp_info Hist LUT params failed, ret %d\n", + ret); + goto exit_igc; + } + ret = __copy_layer_pp_info_pa_v2_params(pp_info, &pp_info32); + if (ret) { + pr_err("compat copy pp_info PAv2 params failed, ret %d\n", + ret); + goto exit_hist_lut; + } + ret = __copy_layer_pp_info_pcc_params(pp_info, &pp_info32); + if (ret) { + pr_err("compat copy pp_info PCC params failed, ret %d\n", + ret); + goto exit_pa; + } + + layer->pp_info = pp_info; + + return ret; + +exit_pa: + kfree(pp_info->pa_v2_cfg_data.cfg_payload); +exit_hist_lut: + kfree(pp_info->hist_lut_cfg.cfg_payload); +exit_igc: + kfree(pp_info->igc_cfg.cfg_payload); +exit_pp_info: + kfree(pp_info); +exit: + return ret; +} + + +static int __to_user_mdp_overlay(struct mdp_overlay32 __user *ov32, + struct mdp_overlay __user *ov) +{ + int ret = 0; + + ret = copy_in_user(&ov32->src, &ov->src, sizeof(ov32->src)) || + copy_in_user(&ov32->src_rect, + &ov->src_rect, sizeof(ov32->src_rect)) || + copy_in_user(&ov32->dst_rect, + &ov->dst_rect, sizeof(ov32->dst_rect)); + if (ret) + return -EFAULT; + + ret |= put_user(ov->z_order, &ov32->z_order); + ret |= put_user(ov->is_fg, &ov32->is_fg); + ret |= put_user(ov->alpha, &ov32->alpha); + ret |= put_user(ov->blend_op, &ov32->blend_op); + ret |= put_user(ov->transp_mask, &ov32->transp_mask); + ret |= put_user(ov->flags, &ov32->flags); + ret |= put_user(ov->id, &ov32->id); + ret |= put_user(ov->priority, &ov32->priority); + if (ret) + return -EFAULT; + + ret = copy_in_user(&ov32->user_data, &ov->user_data, + sizeof(ov32->user_data)); + if (ret) + return -EFAULT; + + ret |= put_user(ov->horz_deci, &ov32->horz_deci); + ret |= put_user(ov->vert_deci, &ov32->vert_deci); + if (ret) + return -EFAULT; + + ret = __to_user_pp_params( + &ov->overlay_pp_cfg, + compat_ptr((uintptr_t) &ov32->overlay_pp_cfg)); + if (ret) + return -EFAULT; + + ret = copy_in_user(&ov32->scale, &ov->scale, + sizeof(struct mdp_scale_data)); + if (ret) + return -EFAULT; + + ret = put_user(ov->frame_rate, &ov32->frame_rate); + if (ret) + return -EFAULT; + + return 0; +} + + +static int __from_user_mdp_overlay(struct mdp_overlay *ov, + struct mdp_overlay32 __user *ov32) +{ + __u32 data; + + if (copy_in_user(&ov->src, &ov32->src, + sizeof(ov32->src)) || + copy_in_user(&ov->src_rect, &ov32->src_rect, + sizeof(ov32->src_rect)) || + copy_in_user(&ov->dst_rect, &ov32->dst_rect, + sizeof(ov32->dst_rect))) + return -EFAULT; + + if (get_user(data, &ov32->z_order) || + put_user(data, &ov->z_order) || + get_user(data, &ov32->is_fg) || + put_user(data, &ov->is_fg) || + get_user(data, &ov32->alpha) || + put_user(data, &ov->alpha) || + get_user(data, &ov32->blend_op) || + put_user(data, &ov->blend_op) || + get_user(data, &ov32->transp_mask) || + put_user(data, &ov->transp_mask) || + get_user(data, &ov32->flags) || + put_user(data, &ov->flags) || + get_user(data, &ov32->pipe_type) || + put_user(data, &ov->pipe_type) || + get_user(data, &ov32->id) || + put_user(data, &ov->id) || + get_user(data, &ov32->priority) || + put_user(data, &ov->priority)) + return -EFAULT; + + if (copy_in_user(&ov->user_data, &ov32->user_data, + sizeof(ov32->user_data))) + return -EFAULT; + + if (get_user(data, &ov32->horz_deci) || + put_user(data, &ov->horz_deci) || + get_user(data, &ov32->vert_deci) || + put_user(data, &ov->vert_deci)) + return -EFAULT; + + if (__from_user_pp_params( + compat_ptr((uintptr_t) &ov32->overlay_pp_cfg), + &ov->overlay_pp_cfg)) + return -EFAULT; + + if (copy_in_user(&ov->scale, &ov32->scale, + sizeof(struct mdp_scale_data))) + return -EFAULT; + + if (get_user(data, &ov32->frame_rate) || + put_user(data, &ov->frame_rate)) + return -EFAULT; + + return 0; +} + +static int __from_user_mdp_overlaylist(struct mdp_overlay_list *ovlist, + struct mdp_overlay_list32 *ovlist32, + struct mdp_overlay **to_list_head) +{ + __u32 i, ret; + unsigned long data, from_list_head; + struct mdp_overlay32 *iter; + + if (!to_list_head || !ovlist32 || !ovlist) { + pr_err("%s:%u: null error\n", __func__, __LINE__); + return -EINVAL; + } + + if (copy_in_user(&ovlist->num_overlays, &ovlist32->num_overlays, + sizeof(ovlist32->num_overlays))) + return -EFAULT; + + if (copy_in_user(&ovlist->flags, &ovlist32->flags, + sizeof(ovlist32->flags))) + return -EFAULT; + + if (copy_in_user(&ovlist->processed_overlays, + &ovlist32->processed_overlays, + sizeof(ovlist32->processed_overlays))) + return -EFAULT; + + if (get_user(data, &ovlist32->overlay_list)) { + ret = -EFAULT; + goto validate_exit; + } + for (i = 0; i < ovlist32->num_overlays; i++) { + if (get_user(from_list_head, (__u32 *)data + i)) { + ret = -EFAULT; + goto validate_exit; + } + + iter = compat_ptr(from_list_head); + if (__from_user_mdp_overlay(to_list_head[i], + (struct mdp_overlay32 *)(iter))) { + ret = -EFAULT; + goto validate_exit; + } + } + ovlist->overlay_list = to_list_head; + + return 0; + +validate_exit: + pr_err("%s: %u: copy error\n", __func__, __LINE__); + return -EFAULT; +} + +static int __to_user_mdp_overlaylist(struct mdp_overlay_list32 *ovlist32, + struct mdp_overlay_list *ovlist, + struct mdp_overlay **l_ptr) +{ + __u32 i, ret; + unsigned long data, data1; + struct mdp_overlay32 *temp; + struct mdp_overlay *l = l_ptr[0]; + + if (copy_in_user(&ovlist32->num_overlays, &ovlist->num_overlays, + sizeof(ovlist32->num_overlays))) + return -EFAULT; + + if (get_user(data, &ovlist32->overlay_list)) { + ret = -EFAULT; + pr_err("%s:%u: err\n", __func__, __LINE__); + goto validate_exit; + } + + for (i = 0; i < ovlist32->num_overlays; i++) { + if (get_user(data1, (__u32 *)data + i)) { + ret = -EFAULT; + goto validate_exit; + } + temp = compat_ptr(data1); + if (__to_user_mdp_overlay( + (struct mdp_overlay32 *) temp, + l + i)) { + ret = -EFAULT; + goto validate_exit; + } + } + + if (copy_in_user(&ovlist32->flags, &ovlist->flags, + sizeof(ovlist32->flags))) + return -EFAULT; + + if (copy_in_user(&ovlist32->processed_overlays, + &ovlist->processed_overlays, + sizeof(ovlist32->processed_overlays))) + return -EFAULT; + + return 0; + +validate_exit: + pr_err("%s: %u: copy error\n", __func__, __LINE__); + return -EFAULT; + +} + +void mdss_compat_align_list(void __user *total_mem_chunk, + struct mdp_overlay __user **list_ptr, u32 num_ov) +{ + int i = 0; + struct mdp_overlay __user *contig_overlays; + + contig_overlays = total_mem_chunk + sizeof(struct mdp_overlay_list) + + (num_ov * sizeof(struct mdp_overlay *)); + + for (i = 0; i < num_ov; i++) + list_ptr[i] = contig_overlays + i; +} + +static u32 __pp_sspp_size(void) +{ + u32 size = 0; + /* pick the largest of the revision when multiple revs are supported */ + size = sizeof(struct mdp_igc_lut_data_v1_7); + size += sizeof(struct mdp_pa_data_v1_7); + size += sizeof(struct mdp_pcc_data_v1_7); + size += sizeof(struct mdp_hist_lut_data_v1_7); + return size; +} + +static int __pp_sspp_set_offsets(struct mdp_overlay *ov) +{ + if (!ov) { + pr_err("invalid overlay pointer\n"); + return -EFAULT; + } + ov->overlay_pp_cfg.igc_cfg.cfg_payload = (void *)((unsigned long)ov + + sizeof(struct mdp_overlay)); + ov->overlay_pp_cfg.pa_v2_cfg_data.cfg_payload = + ov->overlay_pp_cfg.igc_cfg.cfg_payload + + sizeof(struct mdp_igc_lut_data_v1_7); + ov->overlay_pp_cfg.pcc_cfg_data.cfg_payload = + ov->overlay_pp_cfg.pa_v2_cfg_data.cfg_payload + + sizeof(struct mdp_pa_data_v1_7); + ov->overlay_pp_cfg.hist_lut_cfg.cfg_payload = + ov->overlay_pp_cfg.pcc_cfg_data.cfg_payload + + sizeof(struct mdp_pcc_data_v1_7); + return 0; +} + +int mdss_compat_overlay_ioctl(struct fb_info *info, unsigned int cmd, + unsigned long arg, struct file *file) +{ + struct mdp_overlay *ov, **layers_head; + struct mdp_overlay32 *ov32; + struct mdp_overlay_list __user *ovlist; + struct mdp_overlay_list32 __user *ovlist32; + size_t layers_refs_sz, layers_sz, prepare_sz; + void __user *total_mem_chunk; + uint32_t num_overlays; + uint32_t alloc_size = 0; + int ret; + + if (!info || !info->par) + return -EINVAL; + + + switch (cmd) { + case MSMFB_MDP_PP: + ret = mdss_compat_pp_ioctl(info, cmd, arg, file); + break; + case MSMFB_HISTOGRAM_START: + case MSMFB_HISTOGRAM_STOP: + case MSMFB_HISTOGRAM: + ret = mdss_histo_compat_ioctl(info, cmd, arg, file); + break; + case MSMFB_OVERLAY_GET: + alloc_size += sizeof(*ov) + __pp_sspp_size(); + ov = compat_alloc_user_space(alloc_size); + if (!ov) { + pr_err("%s:%u: compat alloc error [%zu] bytes\n", + __func__, __LINE__, sizeof(*ov)); + return -EINVAL; + } + ov32 = compat_ptr(arg); + ret = __pp_sspp_set_offsets(ov); + if (ret) { + pr_err("setting the pp offsets failed ret %d\n", ret); + return ret; + } + ret = __from_user_mdp_overlay(ov, ov32); + if (ret) + pr_err("%s: compat mdp overlay failed\n", __func__); + else + ret = mdss_fb_do_ioctl(info, cmd, + (unsigned long) ov, file); + ret = __to_user_mdp_overlay(ov32, ov); + break; + case MSMFB_OVERLAY_SET: + alloc_size += sizeof(*ov) + __pp_sspp_size(); + ov = compat_alloc_user_space(alloc_size); + if (!ov) { + pr_err("%s:%u: compat alloc error [%zu] bytes\n", + __func__, __LINE__, sizeof(*ov)); + return -EINVAL; + } + ret = __pp_sspp_set_offsets(ov); + if (ret) { + pr_err("setting the pp offsets failed ret %d\n", ret); + return ret; + } + ov32 = compat_ptr(arg); + ret = __from_user_mdp_overlay(ov, ov32); + if (ret) { + pr_err("%s: compat mdp overlay failed\n", __func__); + } else { + ret = mdss_fb_do_ioctl(info, cmd, + (unsigned long) ov, file); + ret = __to_user_mdp_overlay(ov32, ov); + } + break; + case MSMFB_OVERLAY_PREPARE: + ovlist32 = compat_ptr(arg); + if (get_user(num_overlays, &ovlist32->num_overlays)) { + pr_err("compat mdp prepare failed: invalid arg\n"); + return -EFAULT; + } + + if (num_overlays >= OVERLAY_MAX) { + pr_err("%s: No: of overlays exceeds max\n", __func__); + return -EINVAL; + } + + layers_sz = num_overlays * sizeof(struct mdp_overlay); + prepare_sz = sizeof(struct mdp_overlay_list); + layers_refs_sz = num_overlays * sizeof(struct mdp_overlay *); + + total_mem_chunk = compat_alloc_user_space( + prepare_sz + layers_refs_sz + layers_sz); + if (!total_mem_chunk) { + pr_err("%s:%u: compat alloc error [%zu] bytes\n", + __func__, __LINE__, + layers_refs_sz + layers_sz + prepare_sz); + return -EINVAL; + } + + layers_head = total_mem_chunk + prepare_sz; + mdss_compat_align_list(total_mem_chunk, layers_head, + num_overlays); + ovlist = (struct mdp_overlay_list *)total_mem_chunk; + + ret = __from_user_mdp_overlaylist(ovlist, ovlist32, + layers_head); + if (ret) { + pr_err("compat mdp overlaylist failed\n"); + } else { + ret = mdss_fb_do_ioctl(info, cmd, + (unsigned long) ovlist, file); + if (!ret) + ret = __to_user_mdp_overlaylist(ovlist32, + ovlist, layers_head); + } + break; + case MSMFB_OVERLAY_UNSET: + case MSMFB_OVERLAY_PLAY: + case MSMFB_OVERLAY_VSYNC_CTRL: + case MSMFB_METADATA_SET: + case MSMFB_METADATA_GET: + default: + pr_debug("%s: overlay ioctl cmd=[%u]\n", __func__, cmd); + ret = mdss_fb_do_ioctl(info, cmd, (unsigned long) arg, file); + break; + } + return ret; +} + +/* + * mdss_fb_compat_ioctl() - MDSS Framebuffer compat ioctl function + * @info: pointer to framebuffer info + * @cmd: ioctl command + * @arg: argument to ioctl + * + * This function adds the compat translation layer for framebuffer + * ioctls to allow 32-bit userspace call ioctls on the mdss + * framebuffer device driven in 64-bit kernel. + */ +int mdss_fb_compat_ioctl(struct fb_info *info, unsigned int cmd, + unsigned long arg, struct file *file) +{ + int ret; + + if (!info || !info->par) + return -EINVAL; + + cmd = __do_compat_ioctl_nr(cmd); + switch (cmd) { + case MSMFB_CURSOR: + ret = mdss_fb_compat_cursor(info, cmd, arg, file); + break; + case MSMFB_SET_LUT: + ret = mdss_fb_compat_set_lut(info, arg, file); + break; + case MSMFB_BUFFER_SYNC: + ret = mdss_fb_compat_buf_sync(info, cmd, arg, file); + break; + case MSMFB_ATOMIC_COMMIT: + ret = __compat_atomic_commit(info, cmd, arg, file); + break; + case MSMFB_ASYNC_POSITION_UPDATE: + ret = __compat_async_position_update(info, cmd, arg); + break; + case MSMFB_MDP_PP: + case MSMFB_HISTOGRAM_START: + case MSMFB_HISTOGRAM_STOP: + case MSMFB_HISTOGRAM: + case MSMFB_OVERLAY_GET: + case MSMFB_OVERLAY_SET: + case MSMFB_OVERLAY_UNSET: + case MSMFB_OVERLAY_PLAY: + case MSMFB_OVERLAY_VSYNC_CTRL: + case MSMFB_METADATA_SET: + case MSMFB_METADATA_GET: + case MSMFB_OVERLAY_PREPARE: + ret = mdss_compat_overlay_ioctl(info, cmd, arg, file); + break; + case MSMFB_NOTIFY_UPDATE: + case MSMFB_DISPLAY_COMMIT: + default: + ret = mdss_fb_do_ioctl(info, cmd, arg, file); + break; + } + + if (ret == -ENOTSUPP) + pr_err("%s: unsupported ioctl\n", __func__); + else if (ret) + pr_debug("%s: ioctl err cmd=%u ret=%d\n", __func__, cmd, ret); + + return ret; +} +EXPORT_SYMBOL(mdss_fb_compat_ioctl); diff --git a/drivers/video/fbdev/msm/mdss_compat_utils.h b/drivers/video/fbdev/msm/mdss_compat_utils.h new file mode 100644 index 000000000000..819106b6bf3d --- /dev/null +++ b/drivers/video/fbdev/msm/mdss_compat_utils.h @@ -0,0 +1,558 @@ +/* + * Copyright (c) 2014-2016, 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef MDSS_COMPAT_UTILS_H +#define MDSS_COMPAT_UTILS_H + +/* + * To allow proper structure padding for 64bit/32bit target + */ +#ifndef MDP_LAYER_COMMIT_V1_PAD +#ifdef __LP64 +#define MDP_LAYER_COMMIT_V1_PAD 2 +#else +#define MDP_LAYER_COMMIT_V1_PAD 3 +#endif +#endif + +struct mdp_buf_sync32 { + u32 flags; + u32 acq_fen_fd_cnt; + u32 session_id; + compat_caddr_t acq_fen_fd; + compat_caddr_t rel_fen_fd; + compat_caddr_t retire_fen_fd; +}; + +struct fb_cmap32 { + u32 start; + u32 len; + compat_caddr_t red; + compat_caddr_t green; + compat_caddr_t blue; + compat_caddr_t transp; +}; + +struct fb_image32 { + u32 dx; + u32 dy; + u32 width; + u32 height; + u32 fg_color; + u32 bg_color; + u8 depth; + compat_caddr_t data; + struct fb_cmap32 cmap; +}; + +struct fb_cursor32 { + u16 set; + u16 enable; + u16 rop; + compat_caddr_t mask; + struct fbcurpos hot; + struct fb_image32 image; +}; + +struct mdp_ccs32 { +}; + +struct msmfb_overlay_blt32 { +}; + +struct msmfb_overlay_3d32 { +}; + +struct msmfb_mixer_info_req32 { +}; + +struct msmfb_metadata32 { + uint32_t op; + uint32_t flags; + union { + struct mdp_misr misr_request; + struct mdp_blend_cfg blend_cfg; + struct mdp_mixer_cfg mixer_cfg; + uint32_t panel_frame_rate; + uint32_t video_info_code; + struct mdss_hw_caps caps; + uint8_t secure_en; + } data; +}; + +struct mdp_histogram_start_req32 { + uint32_t block; + uint8_t frame_cnt; + uint8_t bit_mask; + uint16_t num_bins; +}; + +struct mdp_histogram_data32 { + uint32_t block; + uint32_t bin_cnt; + compat_caddr_t c0; + compat_caddr_t c1; + compat_caddr_t c2; + compat_caddr_t extra_info; +}; + +struct mdp_pcc_coeff32 { + uint32_t c, r, g, b, rr, gg, bb, rg, gb, rb, rgb_0, rgb_1; +}; + +struct mdp_pcc_coeff_v1_7_32 { + uint32_t c, r, g, b, rg, gb, rb, rgb; +}; + +struct mdp_pcc_data_v1_7_32 { + struct mdp_pcc_coeff_v1_7_32 r, g, b; +}; +struct mdp_pcc_cfg_data32 { + uint32_t version; + uint32_t block; + uint32_t ops; + struct mdp_pcc_coeff32 r, g, b; + compat_caddr_t cfg_payload; +}; + +struct mdp_csc_cfg32 { + /* flags for enable CSC, toggling RGB,YUV input/output */ + uint32_t flags; + uint32_t csc_mv[9]; + uint32_t csc_pre_bv[3]; + uint32_t csc_post_bv[3]; + uint32_t csc_pre_lv[6]; + uint32_t csc_post_lv[6]; +}; + +struct mdp_csc_cfg_data32 { + uint32_t block; + struct mdp_csc_cfg32 csc_data; +}; + +struct mdp_bl_scale_data32 { + uint32_t min_lvl; + uint32_t scale; +}; + +struct mdp_pa_mem_col_cfg32 { + uint32_t color_adjust_p0; + uint32_t color_adjust_p1; + uint32_t hue_region; + uint32_t sat_region; + uint32_t val_region; +}; + +struct mdp_pa_v2_data32 { + /* Mask bits for PA features */ + uint32_t flags; + uint32_t global_hue_adj; + uint32_t global_sat_adj; + uint32_t global_val_adj; + uint32_t global_cont_adj; + struct mdp_pa_mem_col_cfg32 skin_cfg; + struct mdp_pa_mem_col_cfg32 sky_cfg; + struct mdp_pa_mem_col_cfg32 fol_cfg; + uint32_t six_zone_len; + uint32_t six_zone_thresh; + compat_caddr_t six_zone_curve_p0; + compat_caddr_t six_zone_curve_p1; +}; + +struct mdp_pa_mem_col_data_v1_7_32 { + uint32_t color_adjust_p0; + uint32_t color_adjust_p1; + uint32_t color_adjust_p2; + uint32_t blend_gain; + uint8_t sat_hold; + uint8_t val_hold; + uint32_t hue_region; + uint32_t sat_region; + uint32_t val_region; +}; + +struct mdp_pa_data_v1_7_32 { + uint32_t mode; + uint32_t global_hue_adj; + uint32_t global_sat_adj; + uint32_t global_val_adj; + uint32_t global_cont_adj; + struct mdp_pa_mem_col_data_v1_7_32 skin_cfg; + struct mdp_pa_mem_col_data_v1_7_32 sky_cfg; + struct mdp_pa_mem_col_data_v1_7_32 fol_cfg; + uint32_t six_zone_thresh; + uint32_t six_zone_adj_p0; + uint32_t six_zone_adj_p1; + uint8_t six_zone_sat_hold; + uint8_t six_zone_val_hold; + uint32_t six_zone_len; + compat_caddr_t six_zone_curve_p0; + compat_caddr_t six_zone_curve_p1; +}; + +struct mdp_pa_v2_cfg_data32 { + uint32_t version; + uint32_t block; + uint32_t flags; + struct mdp_pa_v2_data32 pa_v2_data; + compat_caddr_t cfg_payload; +}; + +struct mdp_pa_cfg32 { + uint32_t flags; + uint32_t hue_adj; + uint32_t sat_adj; + uint32_t val_adj; + uint32_t cont_adj; +}; + +struct mdp_pa_cfg_data32 { + uint32_t block; + struct mdp_pa_cfg32 pa_data; +}; + +struct mdp_igc_lut_data_v1_7_32 { + uint32_t table_fmt; + uint32_t len; + compat_caddr_t c0_c1_data; + compat_caddr_t c2_data; +}; + +struct mdp_rgb_lut_data32 { + uint32_t flags; + uint32_t lut_type; + struct fb_cmap32 cmap; +}; + +struct mdp_igc_lut_data32 { + uint32_t block; + uint32_t version; + uint32_t len, ops; + compat_caddr_t c0_c1_data; + compat_caddr_t c2_data; + compat_caddr_t cfg_payload; +}; + +struct mdp_hist_lut_data_v1_7_32 { + uint32_t len; + compat_caddr_t data; +}; + +struct mdp_hist_lut_data32 { + uint32_t block; + uint32_t version; + uint32_t hist_lut_first; + uint32_t ops; + uint32_t len; + compat_caddr_t data; + compat_caddr_t cfg_payload; +}; + +struct mdp_ar_gc_lut_data32 { + uint32_t x_start; + uint32_t slope; + uint32_t offset; +}; + +struct mdp_pgc_lut_data_v1_7_32 { + uint32_t len; + compat_caddr_t c0_data; + compat_caddr_t c1_data; + compat_caddr_t c2_data; +}; + +struct mdp_pgc_lut_data32 { + uint32_t version; + uint32_t block; + uint32_t flags; + uint8_t num_r_stages; + uint8_t num_g_stages; + uint8_t num_b_stages; + compat_caddr_t r_data; + compat_caddr_t g_data; + compat_caddr_t b_data; + compat_caddr_t cfg_payload; +}; + +struct mdp_lut_cfg_data32 { + uint32_t lut_type; + union { + struct mdp_igc_lut_data32 igc_lut_data; + struct mdp_pgc_lut_data32 pgc_lut_data; + struct mdp_hist_lut_data32 hist_lut_data; + struct mdp_rgb_lut_data32 rgb_lut_data; + } data; +}; + +struct mdp_qseed_cfg32 { + uint32_t table_num; + uint32_t ops; + uint32_t len; + compat_caddr_t data; +}; + +struct mdp_qseed_cfg_data32 { + uint32_t block; + struct mdp_qseed_cfg32 qseed_data; +}; + +struct mdp_dither_cfg_data32 { + uint32_t block; + uint32_t flags; + uint32_t g_y_depth; + uint32_t r_cr_depth; + uint32_t b_cb_depth; +}; + +struct mdp_gamut_data_v1_7_32 { + uint32_t mode; + uint32_t tbl_size[MDP_GAMUT_TABLE_NUM_V1_7]; + compat_caddr_t c0_data[MDP_GAMUT_TABLE_NUM_V1_7]; + compat_caddr_t c1_c2_data[MDP_GAMUT_TABLE_NUM_V1_7]; + uint32_t tbl_scale_off_sz[MDP_GAMUT_SCALE_OFF_TABLE_NUM]; + compat_caddr_t scale_off_data[MDP_GAMUT_SCALE_OFF_TABLE_NUM]; +}; + +struct mdp_gamut_cfg_data32 { + uint32_t block; + uint32_t flags; + uint32_t version; + uint32_t gamut_first; + uint32_t tbl_size[MDP_GAMUT_TABLE_NUM]; + compat_caddr_t r_tbl[MDP_GAMUT_TABLE_NUM]; + compat_caddr_t g_tbl[MDP_GAMUT_TABLE_NUM]; + compat_caddr_t b_tbl[MDP_GAMUT_TABLE_NUM]; + compat_caddr_t cfg_payload; +}; + +struct mdp_calib_config_data32 { + uint32_t ops; + uint32_t addr; + uint32_t data; +}; + +struct mdp_calib_config_buffer32 { + uint32_t ops; + uint32_t size; + compat_caddr_t buffer; +}; + +struct mdp_calib_dcm_state32 { + uint32_t ops; + uint32_t dcm_state; +}; + +struct mdss_ad_init32 { + uint32_t asym_lut[33]; + uint32_t color_corr_lut[33]; + uint8_t i_control[2]; + uint16_t black_lvl; + uint16_t white_lvl; + uint8_t var; + uint8_t limit_ampl; + uint8_t i_dither; + uint8_t slope_max; + uint8_t slope_min; + uint8_t dither_ctl; + uint8_t format; + uint8_t auto_size; + uint16_t frame_w; + uint16_t frame_h; + uint8_t logo_v; + uint8_t logo_h; + uint32_t alpha; + uint32_t alpha_base; + uint32_t bl_lin_len; + uint32_t bl_att_len; + compat_caddr_t bl_lin; + compat_caddr_t bl_lin_inv; + compat_caddr_t bl_att_lut; +}; + +struct mdss_ad_cfg32 { + uint32_t mode; + uint32_t al_calib_lut[33]; + uint16_t backlight_min; + uint16_t backlight_max; + uint16_t backlight_scale; + uint16_t amb_light_min; + uint16_t filter[2]; + uint16_t calib[4]; + uint8_t strength_limit; + uint8_t t_filter_recursion; + uint16_t stab_itr; + uint32_t bl_ctrl_mode; +}; + +/* ops uses standard MDP_PP_* flags */ +struct mdss_ad_init_cfg32 { + uint32_t ops; + union { + struct mdss_ad_init32 init; + struct mdss_ad_cfg32 cfg; + } params; +}; + +struct mdss_ad_input32 { + uint32_t mode; + union { + uint32_t amb_light; + uint32_t strength; + uint32_t calib_bl; + } in; + uint32_t output; +}; + +struct mdss_calib_cfg32 { + uint32_t ops; + uint32_t calib_mask; +}; + +struct mdp_histogram_cfg32 { + uint32_t ops; + uint32_t block; + uint8_t frame_cnt; + uint8_t bit_mask; + uint16_t num_bins; +}; + +struct mdp_sharp_cfg32 { + uint32_t flags; + uint32_t strength; + uint32_t edge_thr; + uint32_t smooth_thr; + uint32_t noise_thr; +}; + +struct mdp_overlay_pp_params32 { + uint32_t config_ops; + struct mdp_csc_cfg32 csc_cfg; + struct mdp_qseed_cfg32 qseed_cfg[2]; + struct mdp_pa_cfg32 pa_cfg; + struct mdp_pa_v2_data32 pa_v2_cfg; + struct mdp_igc_lut_data32 igc_cfg; + struct mdp_sharp_cfg32 sharp_cfg; + struct mdp_histogram_cfg32 hist_cfg; + struct mdp_hist_lut_data32 hist_lut_cfg; + struct mdp_pa_v2_cfg_data32 pa_v2_cfg_data; + struct mdp_pcc_cfg_data32 pcc_cfg_data; +}; + +struct msmfb_mdp_pp32 { + uint32_t op; + union { + struct mdp_pcc_cfg_data32 pcc_cfg_data; + struct mdp_csc_cfg_data32 csc_cfg_data; + struct mdp_lut_cfg_data32 lut_cfg_data; + struct mdp_qseed_cfg_data32 qseed_cfg_data; + struct mdp_bl_scale_data32 bl_scale_data; + struct mdp_pa_cfg_data32 pa_cfg_data; + struct mdp_pa_v2_cfg_data32 pa_v2_cfg_data; + struct mdp_dither_cfg_data32 dither_cfg_data; + struct mdp_gamut_cfg_data32 gamut_cfg_data; + struct mdp_calib_config_data32 calib_cfg; + struct mdss_ad_init_cfg32 ad_init_cfg; + struct mdss_calib_cfg32 mdss_calib_cfg; + struct mdss_ad_input32 ad_input; + struct mdp_calib_config_buffer32 calib_buffer; + struct mdp_calib_dcm_state32 calib_dcm; + } data; +}; + +struct mdp_overlay32 { + struct msmfb_img src; + struct mdp_rect src_rect; + struct mdp_rect dst_rect; + uint32_t z_order; /* stage number */ + uint32_t is_fg; /* control alpha & transp */ + uint32_t alpha; + uint32_t blend_op; + uint32_t transp_mask; + uint32_t flags; + uint32_t pipe_type; + uint32_t id; + uint8_t priority; + uint32_t user_data[6]; + uint32_t bg_color; + uint8_t horz_deci; + uint8_t vert_deci; + struct mdp_overlay_pp_params32 overlay_pp_cfg; + struct mdp_scale_data scale; + uint8_t color_space; + uint32_t frame_rate; +}; + +struct mdp_overlay_list32 { + uint32_t num_overlays; + compat_caddr_t overlay_list; + uint32_t flags; + uint32_t processed_overlays; +}; + +struct mdp_input_layer32 { + uint32_t flags; + uint32_t pipe_ndx; + uint8_t horz_deci; + uint8_t vert_deci; + uint8_t alpha; + uint16_t z_order; + uint32_t transp_mask; + uint32_t bg_color; + enum mdss_mdp_blend_op blend_op; + enum mdp_color_space color_space; + struct mdp_rect src_rect; + struct mdp_rect dst_rect; + compat_caddr_t scale; + struct mdp_layer_buffer buffer; + compat_caddr_t pp_info; + int error_code; + uint32_t reserved[6]; +}; + +struct mdp_output_layer32 { + uint32_t flags; + uint32_t writeback_ndx; + struct mdp_layer_buffer buffer; + enum mdp_color_space color_space; + uint32_t reserved[5]; +}; +struct mdp_layer_commit_v1_32 { + uint32_t flags; + int release_fence; + struct mdp_rect left_roi; + struct mdp_rect right_roi; + compat_caddr_t input_layers; + uint32_t input_layer_cnt; + compat_caddr_t output_layer; + int retire_fence; + compat_caddr_t dest_scaler; + uint32_t dest_scaler_cnt; + compat_caddr_t frc_info; + uint32_t bl_level; /* BL level to be updated in commit */ + uint32_t reserved[MDP_LAYER_COMMIT_V1_PAD]; +}; + +struct mdp_layer_commit32 { + uint32_t version; + union { + struct mdp_layer_commit_v1_32 commit_v1; + }; +}; + +struct mdp_position_update32 { + compat_caddr_t __user *input_layers; + uint32_t input_layer_cnt; +}; + +#endif diff --git a/drivers/video/fbdev/msm/mdss_dba_utils.c b/drivers/video/fbdev/msm/mdss_dba_utils.c new file mode 100644 index 000000000000..2758a5a7d234 --- /dev/null +++ b/drivers/video/fbdev/msm/mdss_dba_utils.c @@ -0,0 +1,912 @@ +/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#define pr_fmt(fmt) "%s: " fmt, __func__ + +#include