diff mbox series

[1/2] drm/i915: Prevent HW access during init from SDVO TV get_modes hook

Message ID 20240206153910.1758057-2-imre.deak@intel.com (mailing list archive)
State New, archived
Headers show
Series drm/i915: Prevent HW access during init from connector hooks | expand

Commit Message

Imre Deak Feb. 6, 2024, 3:39 p.m. UTC
Prevent accessing the HW from the SDVO/TV get_modes connector hook.
Returning 0 from the hook will make the caller -
drm_helper_probe_single_connector_modes() - keep the previously detected
mode list of the connector.

Signed-off-by: Imre Deak <imre.deak@intel.com>
---
 drivers/gpu/drm/i915/display/intel_sdvo.c | 4 ++++
 1 file changed, 4 insertions(+)

Comments

Hogander, Jouni Feb. 7, 2024, 1:26 p.m. UTC | #1
On Tue, 2024-02-06 at 17:39 +0200, Imre Deak wrote:
> Prevent accessing the HW from the SDVO/TV get_modes connector hook.
> Returning 0 from the hook will make the caller -
> drm_helper_probe_single_connector_modes() - keep the previously
> detected
> mode list of the connector.

I don't see where this is done? Not sure if looking at wrong place, but
I see it tries using some override edid and in case that fails as well
uses drm_add_modes_noedid?

> 
> Signed-off-by: Imre Deak <imre.deak@intel.com>
> ---
>  drivers/gpu/drm/i915/display/intel_sdvo.c | 4 ++++
>  1 file changed, 4 insertions(+)
> 
> diff --git a/drivers/gpu/drm/i915/display/intel_sdvo.c
> b/drivers/gpu/drm/i915/display/intel_sdvo.c
> index 2571ef5a1b211..ccea0efbd136f 100644
> --- a/drivers/gpu/drm/i915/display/intel_sdvo.c
> +++ b/drivers/gpu/drm/i915/display/intel_sdvo.c
> @@ -2287,6 +2287,7 @@ static const struct drm_display_mode
> sdvo_tv_modes[] = {
>  static int intel_sdvo_get_tv_modes(struct drm_connector *connector)

I see intel_sdvo_get_tv_modes is called from intel_sdvo_get_modes. Why
there is no need to do the same in intel_sdvo_get_lvds_modes and
intel_sdvo_get_ddc_modes as well?

BR,

Jouni Högander

>  {
>         struct intel_sdvo *intel_sdvo =
> intel_attached_sdvo(to_intel_connector(connector));
> +       struct drm_i915_private *i915 = to_i915(intel_sdvo-
> >base.base.dev);
>         struct intel_sdvo_connector *intel_sdvo_connector =
>                 to_intel_sdvo_connector(connector);
>         const struct drm_connector_state *conn_state = connector-
> >state;
> @@ -2298,6 +2299,9 @@ static int intel_sdvo_get_tv_modes(struct
> drm_connector *connector)
>         DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n",
>                       connector->base.id, connector->name);
>  
> +       if (!intel_display_driver_check_access(i915))
> +               return 0;
> +
>         /*
>          * Read the list of supported input resolutions for the
> selected TV
>          * format.
Hogander, Jouni Feb. 7, 2024, 1:45 p.m. UTC | #2
On Wed, 2024-02-07 at 15:26 +0200, Hogander, Jouni wrote:
> On Tue, 2024-02-06 at 17:39 +0200, Imre Deak wrote:
> > Prevent accessing the HW from the SDVO/TV get_modes connector hook.
> > Returning 0 from the hook will make the caller -
> > drm_helper_probe_single_connector_modes() - keep the previously
> > detected
> > mode list of the connector.
> 
> I don't see where this is done? Not sure if looking at wrong place,
> but
> I see it tries using some override edid and in case that fails as
> well
> uses drm_add_modes_noedid?
> 
> > 
> > Signed-off-by: Imre Deak <imre.deak@intel.com>
> > ---
> >  drivers/gpu/drm/i915/display/intel_sdvo.c | 4 ++++
> >  1 file changed, 4 insertions(+)
> > 
> > diff --git a/drivers/gpu/drm/i915/display/intel_sdvo.c
> > b/drivers/gpu/drm/i915/display/intel_sdvo.c
> > index 2571ef5a1b211..ccea0efbd136f 100644
> > --- a/drivers/gpu/drm/i915/display/intel_sdvo.c
> > +++ b/drivers/gpu/drm/i915/display/intel_sdvo.c
> > @@ -2287,6 +2287,7 @@ static const struct drm_display_mode
> > sdvo_tv_modes[] = {
> >  static int intel_sdvo_get_tv_modes(struct drm_connector
> > *connector)
> 
> I see intel_sdvo_get_tv_modes is called from intel_sdvo_get_modes.
> Why
> there is no need to do the same in intel_sdvo_get_lvds_modes and
> intel_sdvo_get_ddc_modes as well?

It seems you are taking care of intel_svdo_get_ddc_modes in next patch.
Intel_svdo_get_lvds_modes doesn't touch the hw -> nothing to do there.

> 
> BR,
> 
> Jouni Högander
> 
> >  {
> >         struct intel_sdvo *intel_sdvo =
> > intel_attached_sdvo(to_intel_connector(connector));
> > +       struct drm_i915_private *i915 = to_i915(intel_sdvo-
> > > base.base.dev);
> >         struct intel_sdvo_connector *intel_sdvo_connector =
> >                 to_intel_sdvo_connector(connector);
> >         const struct drm_connector_state *conn_state = connector-
> > > state;
> > @@ -2298,6 +2299,9 @@ static int intel_sdvo_get_tv_modes(struct
> > drm_connector *connector)
> >         DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n",
> >                       connector->base.id, connector->name);
> >  
> > +       if (!intel_display_driver_check_access(i915))
> > +               return 0;
> > +
> >         /*
> >          * Read the list of supported input resolutions for the
> > selected TV
> >          * format.
>
Imre Deak Feb. 7, 2024, 2:10 p.m. UTC | #3
On Wed, Feb 07, 2024 at 03:45:15PM +0200, Hogander, Jouni wrote:
> On Wed, 2024-02-07 at 15:26 +0200, Hogander, Jouni wrote:
> > On Tue, 2024-02-06 at 17:39 +0200, Imre Deak wrote:
> > > Prevent accessing the HW from the SDVO/TV get_modes connector hook.
> > > Returning 0 from the hook will make the caller -
> > > drm_helper_probe_single_connector_modes() - keep the previously
> > > detected
> > > mode list of the connector.
> >
>
> > I don't see where this is done? Not sure if looking at wrong place,
> > but I see it tries using some override edid and in case that fails
> > as well uses drm_add_modes_noedid?

Some default and EDID override modes are also added to the connector
mode list, similarly to when the HW access in intel_sdvo_get_tv_modes()
fails (along with any modes specified via the kernel command line, which
happens unconditionally, see drm_helper_probe_add_cmdline_mode()).

All the modes detected by the encoder detect and the connector get_modes
hooks gets added to the drm_connector::probed_modes list. From this
__drm_helper_update_and_validate() will copy any new modes to the
drm_connector::modes list (which will be returned to user space/kernel
client). Thus, returning 0 from the above TV connector get_modes hook
will preserve the list of modes on the drm_connector::modes list from an
earlier encoder detect/connector get_modes call.

> >
> > >
> > > Signed-off-by: Imre Deak <imre.deak@intel.com>
> > > ---
> > >  drivers/gpu/drm/i915/display/intel_sdvo.c | 4 ++++
> > >  1 file changed, 4 insertions(+)
> > >
> > > diff --git a/drivers/gpu/drm/i915/display/intel_sdvo.c
> > > b/drivers/gpu/drm/i915/display/intel_sdvo.c
> > > index 2571ef5a1b211..ccea0efbd136f 100644
> > > --- a/drivers/gpu/drm/i915/display/intel_sdvo.c
> > > +++ b/drivers/gpu/drm/i915/display/intel_sdvo.c
> > > @@ -2287,6 +2287,7 @@ static const struct drm_display_mode
> > > sdvo_tv_modes[] = {
> > >  static int intel_sdvo_get_tv_modes(struct drm_connector
> > > *connector)
> >
> > I see intel_sdvo_get_tv_modes is called from intel_sdvo_get_modes.
> > Why
> > there is no need to do the same in intel_sdvo_get_lvds_modes and
> > intel_sdvo_get_ddc_modes as well?
> 
> It seems you are taking care of intel_svdo_get_ddc_modes in next patch.
> Intel_svdo_get_lvds_modes doesn't touch the hw -> nothing to do there.
> 
> >
> > BR,
> >
> > Jouni Högander
> >
> > >  {
> > >         struct intel_sdvo *intel_sdvo =
> > > intel_attached_sdvo(to_intel_connector(connector));
> > > +       struct drm_i915_private *i915 = to_i915(intel_sdvo-
> > > > base.base.dev);
> > >         struct intel_sdvo_connector *intel_sdvo_connector =
> > >                 to_intel_sdvo_connector(connector);
> > >         const struct drm_connector_state *conn_state = connector-
> > > > state;
> > > @@ -2298,6 +2299,9 @@ static int intel_sdvo_get_tv_modes(struct
> > > drm_connector *connector)
> > >         DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n",
> > >                       connector->base.id, connector->name);
> > >
> > > +       if (!intel_display_driver_check_access(i915))
> > > +               return 0;
> > > +
> > >         /*
> > >          * Read the list of supported input resolutions for the
> > > selected TV
> > >          * format.
> >
>
Imre Deak Feb. 7, 2024, 2:16 p.m. UTC | #4
On Wed, Feb 07, 2024 at 03:45:15PM +0200, Hogander, Jouni wrote:
> On Wed, 2024-02-07 at 15:26 +0200, Hogander, Jouni wrote:
> > On Tue, 2024-02-06 at 17:39 +0200, Imre Deak wrote:
> > > Prevent accessing the HW from the SDVO/TV get_modes connector hook.
> > > Returning 0 from the hook will make the caller -
> > > drm_helper_probe_single_connector_modes() - keep the previously
> > > detected
> > > mode list of the connector.
> >
> > I don't see where this is done? Not sure if looking at wrong place,
> > but
> > I see it tries using some override edid and in case that fails as
> > well
> > uses drm_add_modes_noedid?
> >
> > >
> > > Signed-off-by: Imre Deak <imre.deak@intel.com>
> > > ---
> > >  drivers/gpu/drm/i915/display/intel_sdvo.c | 4 ++++
> > >  1 file changed, 4 insertions(+)
> > >
> > > diff --git a/drivers/gpu/drm/i915/display/intel_sdvo.c
> > > b/drivers/gpu/drm/i915/display/intel_sdvo.c
> > > index 2571ef5a1b211..ccea0efbd136f 100644
> > > --- a/drivers/gpu/drm/i915/display/intel_sdvo.c
> > > +++ b/drivers/gpu/drm/i915/display/intel_sdvo.c
> > > @@ -2287,6 +2287,7 @@ static const struct drm_display_mode
> > > sdvo_tv_modes[] = {
> > >  static int intel_sdvo_get_tv_modes(struct drm_connector
> > > *connector)
> >
> > I see intel_sdvo_get_tv_modes is called from intel_sdvo_get_modes.
> > Why there is no need to do the same in intel_sdvo_get_lvds_modes and
> > intel_sdvo_get_ddc_modes as well?
> 
> It seems you are taking care of intel_svdo_get_ddc_modes in next patch.
> Intel_svdo_get_lvds_modes doesn't touch the hw -> nothing to do there.

Yes, all the connectors that read out an EDID - vs. the TV connector
which doesn't - is handled by the next patch. And yes, the connectors
which don't access the HW in the get_modes hook doesn't need this check.
Btw, I think all the connectors should work - eventually - in this way:
access the HW only in the encoder detect hook and from the get_modes
hook only return the detected mode list w/o accessing the HW. DP-SST and
HDMI do already the correct thing wrt. this.

> 
> >
> > BR,
> >
> > Jouni Högander
> >
> > >  {
> > >         struct intel_sdvo *intel_sdvo =
> > > intel_attached_sdvo(to_intel_connector(connector));
> > > +       struct drm_i915_private *i915 = to_i915(intel_sdvo-
> > > > base.base.dev);
> > >         struct intel_sdvo_connector *intel_sdvo_connector =
> > >                 to_intel_sdvo_connector(connector);
> > >         const struct drm_connector_state *conn_state = connector-
> > > > state;
> > > @@ -2298,6 +2299,9 @@ static int intel_sdvo_get_tv_modes(struct
> > > drm_connector *connector)
> > >         DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n",
> > >                       connector->base.id, connector->name);
> > >
> > > +       if (!intel_display_driver_check_access(i915))
> > > +               return 0;
> > > +
> > >         /*
> > >          * Read the list of supported input resolutions for the
> > > selected TV
> > >          * format.
> >
>
Hogander, Jouni Feb. 7, 2024, 3:35 p.m. UTC | #5
On Wed, 2024-02-07 at 16:16 +0200, Imre Deak wrote:
> On Wed, Feb 07, 2024 at 03:45:15PM +0200, Hogander, Jouni wrote:
> > On Wed, 2024-02-07 at 15:26 +0200, Hogander, Jouni wrote:
> > > On Tue, 2024-02-06 at 17:39 +0200, Imre Deak wrote:
> > > > Prevent accessing the HW from the SDVO/TV get_modes connector
> > > > hook.
> > > > Returning 0 from the hook will make the caller -
> > > > drm_helper_probe_single_connector_modes() - keep the previously
> > > > detected
> > > > mode list of the connector.
> > > 
> > > I don't see where this is done? Not sure if looking at wrong
> > > place,
> > > but
> > > I see it tries using some override edid and in case that fails as
> > > well
> > > uses drm_add_modes_noedid?
> > > 
> > > > 
> > > > Signed-off-by: Imre Deak <imre.deak@intel.com>
> > > > ---
> > > >  drivers/gpu/drm/i915/display/intel_sdvo.c | 4 ++++
> > > >  1 file changed, 4 insertions(+)
> > > > 
> > > > diff --git a/drivers/gpu/drm/i915/display/intel_sdvo.c
> > > > b/drivers/gpu/drm/i915/display/intel_sdvo.c
> > > > index 2571ef5a1b211..ccea0efbd136f 100644
> > > > --- a/drivers/gpu/drm/i915/display/intel_sdvo.c
> > > > +++ b/drivers/gpu/drm/i915/display/intel_sdvo.c
> > > > @@ -2287,6 +2287,7 @@ static const struct drm_display_mode
> > > > sdvo_tv_modes[] = {
> > > >  static int intel_sdvo_get_tv_modes(struct drm_connector
> > > > *connector)
> > > 
> > > I see intel_sdvo_get_tv_modes is called from
> > > intel_sdvo_get_modes.
> > > Why there is no need to do the same in intel_sdvo_get_lvds_modes
> > > and
> > > intel_sdvo_get_ddc_modes as well?
> > 
> > It seems you are taking care of intel_svdo_get_ddc_modes in next
> > patch.
> > Intel_svdo_get_lvds_modes doesn't touch the hw -> nothing to do
> > there.
> 
> Yes, all the connectors that read out an EDID - vs. the TV connector
> which doesn't - is handled by the next patch. And yes, the connectors
> which don't access the HW in the get_modes hook doesn't need this
> check.
> Btw, I think all the connectors should work - eventually - in this
> way:
> access the HW only in the encoder detect hook and from the get_modes
> hook only return the detected mode list w/o accessing the HW. DP-SST
> and
> HDMI do already the correct thing wrt. this.
> 

Thank you for the clarification.

Reviewed-by: Jouni Högander <jouni.hogander@intel.com>

> > 
> > > 
> > > BR,
> > > 
> > > Jouni Högander
> > > 
> > > >  {
> > > >         struct intel_sdvo *intel_sdvo =
> > > > intel_attached_sdvo(to_intel_connector(connector));
> > > > +       struct drm_i915_private *i915 = to_i915(intel_sdvo-
> > > > > base.base.dev);
> > > >         struct intel_sdvo_connector *intel_sdvo_connector =
> > > >                 to_intel_sdvo_connector(connector);
> > > >         const struct drm_connector_state *conn_state =
> > > > connector-
> > > > > state;
> > > > @@ -2298,6 +2299,9 @@ static int intel_sdvo_get_tv_modes(struct
> > > > drm_connector *connector)
> > > >         DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n",
> > > >                       connector->base.id, connector->name);
> > > > 
> > > > +       if (!intel_display_driver_check_access(i915))
> > > > +               return 0;
> > > > +
> > > >         /*
> > > >          * Read the list of supported input resolutions for the
> > > > selected TV
> > > >          * format.
> > > 
> >
Imre Deak Feb. 7, 2024, 3:49 p.m. UTC | #6
On Wed, Feb 07, 2024 at 04:10:28PM +0200, Imre Deak wrote:
> On Wed, Feb 07, 2024 at 03:45:15PM +0200, Hogander, Jouni wrote:
> > On Wed, 2024-02-07 at 15:26 +0200, Hogander, Jouni wrote:
> > > On Tue, 2024-02-06 at 17:39 +0200, Imre Deak wrote:
> > > > Prevent accessing the HW from the SDVO/TV get_modes connector hook.
> > > > Returning 0 from the hook will make the caller -
> > > > drm_helper_probe_single_connector_modes() - keep the previously
> > > > detected
> > > > mode list of the connector.
> > >
> >
> > > I don't see where this is done? Not sure if looking at wrong place,
> > > but I see it tries using some override edid and in case that fails
> > > as well uses drm_add_modes_noedid?
> 
> Some default and EDID override modes are also added to the connector
> mode list, similarly to when the HW access in intel_sdvo_get_tv_modes()
> fails (along with any modes specified via the kernel command line, which
> happens unconditionally, see drm_helper_probe_add_cmdline_mode()).
> 
> All the modes detected by the encoder detect and the connector get_modes
> hooks gets added to the drm_connector::probed_modes list. From this
> __drm_helper_update_and_validate() will copy any new modes to the
> drm_connector::modes list (which will be returned to user space/kernel
> client). Thus, returning 0 from the above TV connector get_modes hook
> will preserve the list of modes on the drm_connector::modes list from an
> earlier encoder detect/connector get_modes call.

Drat, I realized the above is not quite correct. All the modes on
drm_connector:modes will be flagged as MODE_STALE and removed by
drm_mode_prune_invalid(). This means if get_modes() returns 0 only the
default/override modes will be returned, not the ones detected in an
earlier detect/get_modes call. I think this is ok, matching the case
where HW access fails, but needs at least a clarficiation in the
comment. Thanks for questioning it..

> 
> > >
> > > >
> > > > Signed-off-by: Imre Deak <imre.deak@intel.com>
> > > > ---
> > > >  drivers/gpu/drm/i915/display/intel_sdvo.c | 4 ++++
> > > >  1 file changed, 4 insertions(+)
> > > >
> > > > diff --git a/drivers/gpu/drm/i915/display/intel_sdvo.c
> > > > b/drivers/gpu/drm/i915/display/intel_sdvo.c
> > > > index 2571ef5a1b211..ccea0efbd136f 100644
> > > > --- a/drivers/gpu/drm/i915/display/intel_sdvo.c
> > > > +++ b/drivers/gpu/drm/i915/display/intel_sdvo.c
> > > > @@ -2287,6 +2287,7 @@ static const struct drm_display_mode
> > > > sdvo_tv_modes[] = {
> > > >  static int intel_sdvo_get_tv_modes(struct drm_connector
> > > > *connector)
> > >
> > > I see intel_sdvo_get_tv_modes is called from intel_sdvo_get_modes.
> > > Why
> > > there is no need to do the same in intel_sdvo_get_lvds_modes and
> > > intel_sdvo_get_ddc_modes as well?
> > 
> > It seems you are taking care of intel_svdo_get_ddc_modes in next patch.
> > Intel_svdo_get_lvds_modes doesn't touch the hw -> nothing to do there.
> > 
> > >
> > > BR,
> > >
> > > Jouni Högander
> > >
> > > >  {
> > > >         struct intel_sdvo *intel_sdvo =
> > > > intel_attached_sdvo(to_intel_connector(connector));
> > > > +       struct drm_i915_private *i915 = to_i915(intel_sdvo-
> > > > > base.base.dev);
> > > >         struct intel_sdvo_connector *intel_sdvo_connector =
> > > >                 to_intel_sdvo_connector(connector);
> > > >         const struct drm_connector_state *conn_state = connector-
> > > > > state;
> > > > @@ -2298,6 +2299,9 @@ static int intel_sdvo_get_tv_modes(struct
> > > > drm_connector *connector)
> > > >         DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n",
> > > >                       connector->base.id, connector->name);
> > > >
> > > > +       if (!intel_display_driver_check_access(i915))
> > > > +               return 0;
> > > > +
> > > >         /*
> > > >          * Read the list of supported input resolutions for the
> > > > selected TV
> > > >          * format.
> > >
> >
diff mbox series

Patch

diff --git a/drivers/gpu/drm/i915/display/intel_sdvo.c b/drivers/gpu/drm/i915/display/intel_sdvo.c
index 2571ef5a1b211..ccea0efbd136f 100644
--- a/drivers/gpu/drm/i915/display/intel_sdvo.c
+++ b/drivers/gpu/drm/i915/display/intel_sdvo.c
@@ -2287,6 +2287,7 @@  static const struct drm_display_mode sdvo_tv_modes[] = {
 static int intel_sdvo_get_tv_modes(struct drm_connector *connector)
 {
 	struct intel_sdvo *intel_sdvo = intel_attached_sdvo(to_intel_connector(connector));
+	struct drm_i915_private *i915 = to_i915(intel_sdvo->base.base.dev);
 	struct intel_sdvo_connector *intel_sdvo_connector =
 		to_intel_sdvo_connector(connector);
 	const struct drm_connector_state *conn_state = connector->state;
@@ -2298,6 +2299,9 @@  static int intel_sdvo_get_tv_modes(struct drm_connector *connector)
 	DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n",
 		      connector->base.id, connector->name);
 
+	if (!intel_display_driver_check_access(i915))
+		return 0;
+
 	/*
 	 * Read the list of supported input resolutions for the selected TV
 	 * format.