On Fri, 22 Jul 2022, Ankit Nautiyal <ankit.k.nauti...@intel.com> wrote:
> DSC capabilities are given in bytes 11-13 of VSDB (i.e. bytes 8-10 of
> SCDS). Since minimum length of Data block is 7, all bytes greater than 7
> must be read only after checking the length of the data block.
>
> This patch adds check for data block length before reading relavant DSC
> bytes. It also corrects min DSC BPC to 8, and minor refactoring for
> better readability, and proper log messages.

I think this patch tries to do too much at once. Please split it up. One
thing per patch.

I think the logging is excessive, and what logging remains should use
drm_dbg_kms() instead of DRM_DEBUG_KMS().

Further comments inline.

>
> Signed-off-by: Ankit Nautiyal <ankit.k.nauti...@intel.com>
> ---
>  drivers/gpu/drm/drm_edid.c | 124 +++++++++++++++++++++++--------------
>  1 file changed, 77 insertions(+), 47 deletions(-)
>
> diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
> index bbc25e3b7220..f683a8d5fd31 100644
> --- a/drivers/gpu/drm/drm_edid.c
> +++ b/drivers/gpu/drm/drm_edid.c
> @@ -5703,12 +5703,58 @@ static void drm_parse_ycbcr420_deep_color_info(struct 
> drm_connector *connector,
>       hdmi->y420_dc_modes = dc_mask;
>  }
>  
> +static void drm_parse_dsc_slice_info(u8 dsc_max_slices,
> +                                  struct drm_hdmi_dsc_cap *hdmi_dsc)

Arguments should always be in the order: context, destination, source.

> +{
> +     switch (dsc_max_slices) {
> +     case 1:
> +             hdmi_dsc->max_slices = 1;
> +             hdmi_dsc->clk_per_slice = 340;
> +             break;
> +     case 2:
> +             hdmi_dsc->max_slices = 2;
> +             hdmi_dsc->clk_per_slice = 340;
> +             break;
> +     case 3:
> +             hdmi_dsc->max_slices = 4;
> +             hdmi_dsc->clk_per_slice = 340;
> +             break;
> +     case 4:
> +             hdmi_dsc->max_slices = 8;
> +             hdmi_dsc->clk_per_slice = 340;
> +             break;
> +     case 5:
> +             hdmi_dsc->max_slices = 8;
> +             hdmi_dsc->clk_per_slice = 400;
> +             break;
> +     case 6:
> +             hdmi_dsc->max_slices = 12;
> +             hdmi_dsc->clk_per_slice = 400;
> +             break;
> +     case 7:
> +             hdmi_dsc->max_slices = 16;
> +             hdmi_dsc->clk_per_slice = 400;
> +             break;
> +     case 0:
> +     default:
> +             hdmi_dsc->max_slices = 0;
> +             hdmi_dsc->clk_per_slice = 0;
> +     }
> +}
> +
>  /* Sink Capability Data Structure */
>  static void drm_parse_hdmi_forum_scds(struct drm_connector *connector,
>                                     const u8 *hf_scds)
>  {
>       struct drm_display_info *display = &connector->display_info;
>       struct drm_hdmi_info *hdmi = &display->hdmi;
> +     u8 db_length = hf_scds[0] & 0x1F;

There's cea_db_payload_len() for this, and you can use that directly
instead of caching the value to a local variable.

> +     u8 dsc_max_frl_rate;
> +     u8 dsc_max_slices;

These two are local to a tiny if block and should be declared there.

> +     struct drm_hdmi_dsc_cap *hdmi_dsc = &hdmi->dsc_cap;
> +
> +     if (db_length < 7 || db_length > 31)
> +             return;

Both cea_db_is_hdmi_forum_vsdb() and cea_db_is_hdmi_forum_scdb() check
the payload is >= 7 bytes before this one even gets called.

There's no reason to not parse the first 31 bytes if the length is > 31
bytes. That condition just breaks future compatibility for no reason.

>  
>       display->has_hdmi_infoframe = true;
>  
> @@ -5749,17 +5795,25 @@ static void drm_parse_hdmi_forum_scds(struct 
> drm_connector *connector,
>  
>       if (hf_scds[7]) {
>               u8 max_frl_rate;
> -             u8 dsc_max_frl_rate;
> -             u8 dsc_max_slices;
> -             struct drm_hdmi_dsc_cap *hdmi_dsc = &hdmi->dsc_cap;
>  
> -             DRM_DEBUG_KMS("hdmi_21 sink detected. parsing edid\n");
>               max_frl_rate = (hf_scds[7] & DRM_EDID_MAX_FRL_RATE_MASK) >> 4;
> +             if (max_frl_rate)
> +                     DRM_DEBUG_KMS("HDMI2.1 FRL support detected\n");
> +
>               drm_get_max_frl_rate(max_frl_rate, &hdmi->max_lanes,
>                                    &hdmi->max_frl_rate_per_lane);
> +
> +             drm_parse_ycbcr420_deep_color_info(connector, hf_scds);
> +     }
> +
> +     if (db_length < 11)
> +             return;
> +
> +     if (hf_scds[11]) {

Matter of taste, but I'd probably make these

        if (cea_db_payload_len(hf_scds) >= 11 && hf_scds[11])

and drop the early returns, and add a single (or very few) debug logging
call at the end.

>               hdmi_dsc->v_1p2 = hf_scds[11] & DRM_EDID_DSC_1P2;
>  
>               if (hdmi_dsc->v_1p2) {
> +                     DRM_DEBUG_KMS("HDMI DSC1.2 support detected\n");
>                       hdmi_dsc->native_420 = hf_scds[11] & 
> DRM_EDID_DSC_NATIVE_420;
>                       hdmi_dsc->all_bpp = hf_scds[11] & DRM_EDID_DSC_ALL_BPP;
>  
> @@ -5770,52 +5824,28 @@ static void drm_parse_hdmi_forum_scds(struct 
> drm_connector *connector,
>                       else if (hf_scds[11] & DRM_EDID_DSC_10BPC)
>                               hdmi_dsc->bpc_supported = 10;
>                       else
> -                             hdmi_dsc->bpc_supported = 0;
> -
> -                     dsc_max_frl_rate = (hf_scds[12] & 
> DRM_EDID_DSC_MAX_FRL_RATE_MASK) >> 4;
> -                     drm_get_max_frl_rate(dsc_max_frl_rate, 
> &hdmi_dsc->max_lanes,
> -                                          &hdmi_dsc->max_frl_rate_per_lane);
> -                     hdmi_dsc->total_chunk_kbytes = hf_scds[13] & 
> DRM_EDID_DSC_TOTAL_CHUNK_KBYTES;
> -
> -                     dsc_max_slices = hf_scds[12] & DRM_EDID_DSC_MAX_SLICES;
> -                     switch (dsc_max_slices) {
> -                     case 1:
> -                             hdmi_dsc->max_slices = 1;
> -                             hdmi_dsc->clk_per_slice = 340;
> -                             break;
> -                     case 2:
> -                             hdmi_dsc->max_slices = 2;
> -                             hdmi_dsc->clk_per_slice = 340;
> -                             break;
> -                     case 3:
> -                             hdmi_dsc->max_slices = 4;
> -                             hdmi_dsc->clk_per_slice = 340;
> -                             break;
> -                     case 4:
> -                             hdmi_dsc->max_slices = 8;
> -                             hdmi_dsc->clk_per_slice = 340;
> -                             break;
> -                     case 5:
> -                             hdmi_dsc->max_slices = 8;
> -                             hdmi_dsc->clk_per_slice = 400;
> -                             break;
> -                     case 6:
> -                             hdmi_dsc->max_slices = 12;
> -                             hdmi_dsc->clk_per_slice = 400;
> -                             break;
> -                     case 7:
> -                             hdmi_dsc->max_slices = 16;
> -                             hdmi_dsc->clk_per_slice = 400;
> -                             break;
> -                     case 0:
> -                     default:
> -                             hdmi_dsc->max_slices = 0;
> -                             hdmi_dsc->clk_per_slice = 0;
> -                     }

Splitting this to a separate function should be a non-functional prep
patch.

BR,
Jani.

> +                             /* Supports min 8 BPC if DSC1.2 is supported*/
> +                             hdmi_dsc->bpc_supported = 8;
>               }
>       }
>  
> -     drm_parse_ycbcr420_deep_color_info(connector, hf_scds);
> +     if (db_length < 12)
> +             return;
> +
> +     if (hdmi_dsc->v_1p2 && hf_scds[12]) {
> +             dsc_max_slices = hf_scds[12] & DRM_EDID_DSC_MAX_SLICES;
> +             drm_parse_dsc_slice_info(dsc_max_slices, hdmi_dsc);
> +
> +             dsc_max_frl_rate = (hf_scds[12] & 
> DRM_EDID_DSC_MAX_FRL_RATE_MASK) >> 4;
> +             drm_get_max_frl_rate(dsc_max_frl_rate, &hdmi_dsc->max_lanes,
> +                                  &hdmi_dsc->max_frl_rate_per_lane);
> +     }
> +
> +     if (db_length < 13)
> +             return;
> +
> +     if (hdmi_dsc->v_1p2 && hf_scds[13])
> +             hdmi_dsc->total_chunk_kbytes = hf_scds[13] & 
> DRM_EDID_DSC_TOTAL_CHUNK_KBYTES;
>  }
>  
>  static void drm_parse_hdmi_deep_color_info(struct drm_connector *connector,

-- 
Jani Nikula, Intel Open Source Graphics Center

Reply via email to