Re: [PATCH] WIP: drm/dp_mst: Add support for dumping topology ref histories from debugfs

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hey - so, the original issue here was that payloads were not always deleted
when we expected them to be - correct?

If I'm remembering that correctly, then (and I'm not 100% sure on this yet) I
might already have noticed something very possibly wonky in how we handle
payload allocations currently, that I found while working on the non-atomic
removal branch that I linked to you in my previous response. Basically, in the
step1() function it looks like that we follow this general flow with updating
payloads:

 * Loop through proposed payloads and compare to previously programmed
   payloads
    - If a payload has a different allocation then it previously did, update the
      payload
    - If the payload is new, create it
    - If a payload no longer has an allocation, remove the payload

At first glance this seems totally correct - but I'm not actually entirely
convinced it is? Particularly because it seems like the order in which we do
creation/deletion of payloads is totally arbitrary. To explain what I mean by
that, consider a state transition like this:

vcpi_slots=15 vcpi_slots=35 vcpi_slots=14
| 1 | 2 |xxxxxxxx|

Let's say we want to increase payload #1 from 15 to 50, and disable payload #2
in the same atomic commit on DRM's side. If the order we update payloads is
entirely arbitrary, we could end up doing this:

 * Increase VCPI slots payload #1 from 15->50 (total VCPI slots=99, overflow!)
 * Decrease VCPI slots payload #2 from 35->0  (total VCPI slots=50)

Notice on the first step, we've technically overflowed the available number of
VCPI slots in the payload table. This is still before step 2 though, and I
could be totally wrong here - perhaps this is entirely OK in the real world,
and we're allowed to overflow VC slots as long as we repair the issue before
step 2. But so far I can't seem to find anything in the DP 2.0 spec that
explicitly states this would be OK - which makes me think we might fail some
payload allocations if we don't always ensure we avoid overflows in between VC
payload table changes. Note that avoiding overflows would be as simple as just
making sure we send all VC payload table changes that free VC slots before
sending any that take new slots.

Again - I haven't actually confirmed this yet and am hoping to test stuff like
this very soon as I'm pretty close finishing up the initial attempt at
removing the non-atomic MST code in the DRM helpers now. If my theory ends up
being correct here, I can fix this in my rewrite of the MST payload management
code. But I figured it might be worth mentioning in the mean time in case you
think it might be relevant to the problem here :).

On Wed, 2022-01-12 at 16:47 -0500, Lyude Paul wrote:
> (CC'ing this to dri-devel, since this is basically patch review)
> 
> Alright - so first off sorry about the broken debugging patch! I thought I
> had
> tested that but I guess I hadn't tested it well enough, I'll get it fixed
> asap, but feel free to try getting to it before I do.
> 
> As for this patch… (comments below)
> 
> On Mon, 2021-12-20 at 02:17 +0000, Lin, Wayne wrote:
> > [AMD Official Use Only]
> > 
> > Hi Lyude,
> > 
> > No rush and thanks for your time! : )
> > Just want to help clarify what I mean that "registering a callback
> > function"
> > for CSN of disconnecting
> > stream sink device (not mst branch case). Attach below the tentative patch
> > that I planned to do. Thanks so much!
> > 
> > Regards,
> > Wayne
> > ---
> >  .../display/amdgpu_dm/amdgpu_dm_mst_types.c   | 53 +++++++++++++++++++
> >  drivers/gpu/drm/drm_dp_mst_topology.c         | 16 +++++-
> >  include/drm/drm_dp_mst_helper.h               |  1 +
> >  3 files changed, 68 insertions(+), 2 deletions(-)
> > 
> > diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c
> > b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c
> > index cc34a35d0bcb..d7343c64908c 100644
> > --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c
> > +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c
> > @@ -472,8 +472,61 @@ dm_dp_add_mst_connector(struct
> > drm_dp_mst_topology_mgr
> > *mgr,
> >         return connector;
> >  }
> > 
> > +void dm_dp_notify_csn_disconnection(struct drm_connector *connector)
> > +{
> > +       struct amdgpu_dm_connector *aconnector =
> > +               to_amdgpu_dm_connector(connector);
> > +       struct dc_sink *dc_sink = aconnector->dc_sink;
> > +       struct dc_link *dc_link = aconnector->dc_link;
> > +       struct amdgpu_device *adev = drm_to_adev(ddev);
> > +
> > +       ASSERT(dc_link);
> > +
> > +       if (dc_sink) {
> > +               mutex_lock(&adev->dm.dc_lock);
> > +
> > +               /*clear the remote sink of the link*/
> > +               dc_link_remove_remote_sink(dc_link, dc_sink);
> > +               dc_sink_release(dc_sink);
> > +               aconnector->dc_sink = NULL;
> > +
> > +               mutex_unlock(&adev->dm.dc_lock);
> > +       }
> > +}
> > +
> >  static const struct drm_dp_mst_topology_cbs dm_mst_cbs = {
> >         .add_connector = dm_dp_add_mst_connector,
> > +       .notify_csn_disconnection = dm_dp_notify_csn_disconnection,
> >  };
> 
> I still don't really think this is a good idea. This seems like it's just
> adding another hotplugging path to the code in order to avoid sending
> hotplugs
> for non-endpoint devices. In addition to the drm_connector issues I
> mentioned
> before, we also really need to stop doing any kind of payload maintence in
> hotplugging paths. The reality is any kind of payload maintanence we do
> outside of normal modesetting paths is a relic from legacy modesetting that
> I'm dropping ASAP (more on this below), and we can't keep adding to it
> because
> it dramatically complicates maintanence as well.
> 
> Sorry for repeating this point so often but - the biggest issue too is I'm
> still not sure what it is we're even avoiding here. We know resources aren't
> released consistently, and that we're able to reproduce the behavior with
> repeated hotplugs. We also know that if we skip sending certain hotplug
> events, that fixes the issue. And we know we can workaround it by adding a
> special case for forcing a payload release in DC. But none of those actually
> tell us exactly what piece of code is leaking and why, which means that any
> workarounds we're putting in to avoid this mysterious guilty section of code
> we don't entirely understand either - which means we're just adding more
> code
> in that no one actually fully understands. This just ends up making
> maintence
> difficult because every change in code nearby workarounds like this has to
> strugle to try to figure out said workarounds in order to avoid breaking
> things.
> 
> I'm actually currently running into these "later" issues right now, as
> recently I've (-actively-, finally!!!) been working on trying to remove as
> much non-atomic MST as I can because. As it turns out - a huge amount of the
> payload maintanence code just isn't needed at all when we stop caring about
> non-atomic drivers and stick everything in atomic state structs. Step 1 for
> updating updating the payload table, e.g. drm_dp_update_payload_part1(), is
> a
> great example of how messy things have become. Here's a small sample of some
> of the stuff I've seen from just that one function so far that either just
> don't make sense here or is totally redundant. I should note that a lot of
> these things also come from patches I reviwed, but didn't really look at as
> closely as I should have because I was swamped at work, some are historical
> artifacts, and others are less-than-ideal patches I got wrote myself when I
> was first started working on MST and didn't know the code as well as I do
> now:
> 
>  * We try to avoid some sort of userspace issue by using
>    drm_dp_mst_port_downstream_of_branch() to avoid releasing payloads for a
>    branch if we can't prove it's downstream of the top of the topology. This
>    seems to workaround either a userspace bug. This is a redundant, since
>    that's what topology refs are already supposed to be doing to the extent
> is
>    reasonably possibly. It's also unfortunately racy solution because we
> have
>    to be able to handle the situation where a connector is removed from
> under
>    us. That can happen at any time, including _immediately_ after we call
>    drm_dp_mst_port_downstream_of_branch() - rendering the call not really
>    useful.
>  * If we fail to validate the sink in drm_dp_update_payload_part, we don't
>    update the payload table. I think at best this solution is racy and not
>    useful, at worst it leaves us with a payload table that doesn't match
> what
>    we attempted to set in the atomic state - which at worst brings us into
>    undefined territory where we're just plain out of sync with the reality
> in
>    hw.
>  * Actually fun fact - mgr->payloads and mgr->proposed_vcpis both can and
>    definitely should be removed entirely. All of the info for mgr->payloads
>    could just be in the atomic state, because that + the magic of atomic
> state
>    duplication means we'll also have an accurate view of the previous
> state's
>    payload allocations: which renders mgr->proposed_vcpis redundant.
> 
> Apologies for the long explanation again, but I hope that explains my point
> here a bit. I'm going to be trying to get to moving amdgpu's DSC code out of
> amdgpu and into DRM helpers as well soon, so I'm really determined to clean
> stuff up beforehand as every time I've done so it's become substantially
> easier to make changes to this code. Things used to be even worse before I
> started cleaning things up 2 or 3 years ago, where simple changes would end
> up
> getting me stuck spending hours trying to dig through lockdep or memory
> manegement issues. As well, I would be entirely unsurprised if bugs like
> this
> very payload leak we're working on just disappear once we've gotten rid of
> all
> the extraneous workarounds and state tracking here - especially with how
> many
> special cases we have for maintaining the payload table right now. That's
> certainly ended up being the case in the past with a number of other
> difficult
> to track down issues I've dealt with in MST.
> 
> Anyhow. I've been way more productive this year then last because I had over
> a
> month off work and am finally not super burnt out from my job, and so far
> I've
> been making progress on the payload state cleanup far faster then I was last
> year :). I think if you can't figure out where the leak is coming from even
> once I get the debugging patches I mentioned fixed up, it might be a good
> idea
> for us to try again after I've got some of this code cleaned up. I've got a
> currently WIP branch here:
> 
> https://gitlab.freedesktop.org/lyudess/linux/-/commit/624dd68fa804e64b5b2060e4735d7317090692b5
> 
> > 
> >  void amdgpu_dm_initialize_dp_connector(struct amdgpu_display_manager *dm,
> > diff --git a/drivers/gpu/drm/drm_dp_mst_topology.c
> > b/drivers/gpu/drm/drm_dp_mst_topology.c
> > index 857c5d15e81d..a70e26c5d084 100644
> > --- a/drivers/gpu/drm/drm_dp_mst_topology.c
> > +++ b/drivers/gpu/drm/drm_dp_mst_topology.c
> > @@ -2508,6 +2508,7 @@ drm_dp_mst_handle_conn_stat(struct drm_dp_mst_branch
> > *mstb,
> >         u8 new_pdt;
> >         bool new_mcs;
> >         bool dowork = false, create_connector = false;
> > +       bool notify_unplug_event = false;
> > 
> >         port = drm_dp_get_port(mstb, conn_stat->port_number);
> >         if (!port)
> > @@ -2520,6 +2521,9 @@ drm_dp_mst_handle_conn_stat(struct drm_dp_mst_branch
> > *mstb,
> >                          * port, so just throw the port out and make sure
> > we
> >                          * reprobe the link address of it's parent MSTB
> >                          */
> > +                       /* should also consider notify_unplug_event here.
> > +                        * but it's not a normal case for products in the
> > market
> > +                        */
> >                         drm_dp_mst_topology_unlink_port(mgr, port);
> >                         mstb->link_address_sent = false;
> >                         dowork = true;
> > @@ -2541,10 +2545,14 @@ drm_dp_mst_handle_conn_stat(struct
> > drm_dp_mst_branch
> > *mstb,
> >         port->ddps = conn_stat->displayport_device_plug_status;
> > 
> >         if (old_ddps != port->ddps) {
> > -               if (port->ddps && !port->input)
> > +               if (port->ddps && !port->input) {
> >                         drm_dp_send_enum_path_resources(mgr, mstb, port);
> > -               else
> > +               } else {
> >                         port->full_pbn = 0;
> > +                       if (port->connector &&
> > +                               drm_dp_mst_is_end_device(port->pdt, port-
> > > mcs))
> > +                               notify_unplug_event = true;
> > +               }
> >         }
> > 
> >         new_pdt = port->input ? DP_PEER_DEVICE_NONE : conn_stat-
> > > peer_device_type;
> > @@ -2557,11 +2565,15 @@ drm_dp_mst_handle_conn_stat(struct
> > drm_dp_mst_branch
> > *mstb,
> >                 dowork = false;
> >         }
> > 
> > +       if (notify_unplug_event && mgr->cbs->notify_csn_disconnection)
> > +               mgr->cbs->notify_csn_disconnection(port->connector);
> > +
> >         if (port->connector)
> >                 drm_modeset_unlock(&mgr->base.lock);
> >         else if (create_connector)
> >                 drm_dp_mst_port_add_connector(mstb, port);
> > 
> > +
> >  out:
> >         drm_dp_mst_topology_put_port(port);
> >         if (dowork)
> > diff --git a/include/drm/drm_dp_mst_helper.h
> > b/include/drm/drm_dp_mst_helper.h
> > index 78044ac5b59b..ff9e47729841 100644
> > --- a/include/drm/drm_dp_mst_helper.h
> > +++ b/include/drm/drm_dp_mst_helper.h
> > @@ -525,6 +525,7 @@ struct drm_dp_mst_topology_cbs {
> >          * IRQ pulse handler.
> >          */
> >         void (*poll_hpd_irq)(struct drm_dp_mst_topology_mgr *mgr);
> > +       void (*notify_csn_disconnection)(struct drm_connector *connector);
> >  };
> > 
> >  #define DP_MAX_PAYLOAD (sizeof(unsigned long) * 8)
> > --
> > 2.31.0
> > 
> > > -----Original Message-----
> > > From: Lin, Wayne
> > > Sent: Wednesday, December 8, 2021 11:39 AM
> > > To: 'Lyude Paul' <lyude@xxxxxxxxxx>
> > > Subject: RE: [PATCH] WIP: drm/dp_mst: Add support for dumping topology
> > > ref
> > > histories from debugfs
> > > 
> > > No worries Lyude!
> > > Thanks for keeping helping on this. Take your time : )
> > > 
> > > > -----Original Message-----
> > > > From: Lyude Paul <lyude@xxxxxxxxxx>
> > > > Sent: Wednesday, December 8, 2021 7:05 AM
> > > > To: Lin, Wayne <Wayne.Lin@xxxxxxx>
> > > > Subject: Re: [PATCH] WIP: drm/dp_mst: Add support for dumping topology
> > > > ref histories from debugfs
> > > > 
> > > > Sorry! I will try to get to this tomorrow, if not then sometime this
> > > > week.
> > > > 
> > > > On Tue, 2021-11-30 at 08:41 +0000, Lin, Wayne wrote:
> > > > > [Public]
> > > > > 
> > > > > Hi Lyude,
> > > > > 
> > > > > Finally have some bandwidth to get back to this problem!
> > > > > I roughly went through this patch and I'm just aware that we already
> > > > > have such kind of convenient tool for a while.
> > > > > I think it's definitely useful for us to track port/mstb reference
> > > > > count issues and I'll start to embrace this feature for cleaning up
> > > > > those issues. Thank you Lyude!
> > > > > 
> > > > > However, I think the issue that I was trying to fix is not related
> > > > > to what you suggested:
> > > > > " The idea here is that if stream resources aren't being released,
> > > > > my guess would be that we're not dropping topology references for
> > > > > the port which means the connector never goes away."
> > > > > The issue I was trying to fix is about releasing
> > > > > dc_link->remote_sinks while receiving a CSN message notifying the
> > > > > connection status of a sst connector of a port changed from
> > > > > connected to disconnected. Not the connection status changed of a
> > > > > mst
> > > > > branch device.
> > > > > e.g.
> > > > > src - 1st_mstb - 2nd_mstb - sst_monitor => src - 1st_mstb
> > > > > (disconnect) 2nd_mstb - sst_monitor
> > > > > 
> > > > > In above case, after receiving CSN, we will put topology references
> > > > > of 2nd mstb and its port which is connected with the sst monitor. As
> > > > > the result of that, we can call
> > > > > drm_dp_delayed_destroy_port() to unregister and put the drm
> > > > > connector.
> > > > > 
> > > > > However, in below case:
> > > > > e.g.
> > > > > src - 1st_mstb - sst_monitor => src - 1st_mstb (disconnect)
> > > > > sst_monitor
> > > > > 
> > > > > In this case, which is the case having problem, it definitely won't
> > > > > decrease the topology references count of the port which was
> > > > > connected to the sst monitor to zero since the port is still
> > > > > existing in the topology. Same as the malloc reference since the
> > > > > port can't get destroyed. Hence, the port still exists  and we won't
> > > > > call
> > > > > drm_dp_delayed_destroy_port() to unregister and put the drm
> > > > > connector.
> > > > > I looked up the code and drm_dp_delayed_destroy_port() seems like
> > > > > the only place to call drm_connector_put() which means we can't put
> > > > > reference count of drm connector under this case and can't release
> > > > > dc_sink resource by destroying drm connector.
> > > > > 
> > > > > I would also like to point out that this resource (remote_sinks) is
> > > > > specific to different stream sinks. So if we're trying to release
> > > > > this dc_sink resource by destroying the drm connector, it conflicts
> > > > > the idea that you suggested before that we should always keep the
> > > > > drm connector until it's no longer reachable in the topology.
> > > > > Releasing dc_sink should be binding with the disconnection event.
> > > > > 
> > > > > I understand your concern that we should not just easily change the
> > > > > logic here since it's the result after solving tons of bugs before
> > > > > and might cause other side effect. So, just my 2 cents, what I'm
> > > > > thinking is to register a callback function for our driver to notify
> > > > > us that the remote sink is detached. This just aligns our flow
> > > > > handling long HPD event of legacy (sst) DP.
> > > > > For sst case, once we detect long HPD event indicating the monitor
> > > > > is detached, we will immediately try to release the
> > > > > dc_link->local_sink and fire hotplug event to upper layer. Same as
> > > > > here, once receives a CSN message notifying a drm connector is
> > > > > changed from connected to disconnected, trigger the callback
> > > > > function and we can try to release the dc_sink resource.
> > > > > 
> > > > > Would like to know your thought and insight please : )
> > > > > 
> > > > > Btw, I got some errors and warnings while building and have some
> > > > > code adjustments as below : ) Thank you Lyude for your always kindly
> > > > > help!!
> > > > > 
> > > > > Regards,
> > > > > Wayne
> > > > > > -----Original Message-----
> > > > > > From: Lyude Paul <lyude@xxxxxxxxxx>
> > > > > > Sent: Wednesday, November 3, 2021 7:15 AM
> > > > > > To: Lin, Wayne <Wayne.Lin@xxxxxxx>
> > > > > > Subject: [PATCH] WIP: drm/dp_mst: Add support for dumping topology
> > > > > > ref histories from debugfs
> > > > > > 
> > > > > > TODO:
> > > > > > * Implement support for i915
> > > > > > * Finish writing this commit message
> > > > > > * ???
> > > > > > * profit
> > > > > > 
> > > > > > Signed-off-by: Lyude Paul <lyude@xxxxxxxxxx>
> > > > > > ---
> > > > > > 
> > > > > > Hey wayne! SO-hopefully if I did this correctly then this should
> > > > > > just work on amdgpu. What this patch should do is add a debugfs
> > > > > > file to amdgpu called "amdgpu_dp_mst_topology_refs", and when you
> > > > > > read the file it should print out the topology reference history
> > > > > > of every MSTB and Port in memory, along with how many times we've
> > > > > > hit the codepath in each backtrace. An example:
> > > > > > 
> > > > > > Port DP-5 (0000000005c37748) topology ref history:
> > > > > >   1 gets (last at    58.468973):
> > > > > >      drm_dp_send_link_address+0x6a5/0xa00 [drm_kms_helper]
> > > > > >      drm_dp_check_and_send_link_address+0xad/0xd0 [drm_kms_helper]
> > > > > >      drm_dp_mst_link_probe_work+0x14e/0x1a0 [drm_kms_helper]
> > > > > >      process_one_work+0x1e3/0x390
> > > > > >      worker_thread+0x50/0x3a0
> > > > > >      kthread+0x124/0x150
> > > > > >      ret_from_fork+0x1f/0x30
> > > > > >   1 puts (last at    58.469357):
> > > > > >      drm_dp_mst_topology_put_port+0x6a/0x210 [drm_kms_helper]
> > > > > >      drm_dp_send_link_address+0x39e/0xa00 [drm_kms_helper]
> > > > > >      drm_dp_check_and_send_link_address+0xad/0xd0 [drm_kms_helper]
> > > > > >      drm_dp_mst_link_probe_work+0x14e/0x1a0 [drm_kms_helper]
> > > > > >      process_one_work+0x1e3/0x390
> > > > > >      worker_thread+0x50/0x3a0
> > > > > >      kthread+0x124/0x150
> > > > > >      ret_from_fork+0x1f/0x30
> > > > > > 
> > > > > > The idea here is that if stream resources aren't being released,
> > > > > > my guess would be that we're not dropping topology references for
> > > > > > the port which means the connector never goes away. So, if that's
> > > > > > really the case then once we unplug the offending connector we
> > > > > > should be able to find a pair of gets/puts for the offending
> > > > > > leaked connector where the get/put count doesn't match up. Also,
> > > > > > if the frame count on the backtrace isn't long enough you can
> > > > > > increase the value of STACK_DEPTH in
> > > > > > drivers/gpu/drm/drm_dp_mst_topology.c and recompile to get more
> > > > > > frames.
> > > > > > 
> > > > > > To enable this, first enable CONFIG_EXPERT for your kernel which
> > > > > > will unhide CONFIG_DRM_DEBUG_DP_MST_TOPOLOGY_REFS. Then just
> > > > > > enable CONFIG_DRM_DEBUG_DP_MST_TOPOLOGY_REFS, recompile, and it
> > > > > > should be good to go.
> > > > > > 
> > > > > > Let me know if this works for you, and hopefully this should tell
> > > > > > us exactly what the problem actually is here.
> > > > > > 
> > > > > >  .../amd/display/amdgpu_dm/amdgpu_dm_debugfs.c |  35 ++++
> > > > > >  drivers/gpu/drm/drm_dp_mst_topology.c         | 173
> > > > > > ++++++++++++++----
> > > > > >  drivers/gpu/drm/nouveau/nouveau_debugfs.c     |  35 ++++
> > > > > >  include/drm/drm_dp_mst_helper.h               |  18 ++
> > > > > >  4 files changed, 228 insertions(+), 33 deletions(-)
> > > > > > 
> > > > > > 
> > > > > > diff --git
> > > > > > a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c
> > > > > > b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c
> > > > > > index 1a68a674913c..1a14732c52b4 100644
> > > > > > --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c
> > > > > > +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c
> > > > > > @@ -3063,6 +3063,37 @@ static int mst_topo_show(struct seq_file
> > > > > > *m, void
> > > > > > *unused)
> > > > > >       return 0;
> > > > > >  }
> > > > > > 
> > > > > > +#ifdef CONFIG_DRM_DEBUG_DP_MST_TOPOLOGY_REFS
> > > > > > +static int mst_topology_ref_dump_show(struct seq_file *m, void
> > > > > > +*unused) {
> > > > > > +     struct amdgpu_device *adev = (struct amdgpu_device
> > > > > > +*)m->private;
> > > > > > +     struct drm_device *dev = adev_to_drm(adev);
> > > > > > +     struct drm_connector *connector;
> > > > > > +     struct drm_connector_list_iter conn_iter;
> > > > > > +     struct amdgpu_dm_connector *aconnector;
> > > > > > +
> > > > > > +     drm_connector_list_iter_begin(dev, &conn_iter);
> > > > > > +     drm_for_each_connector_iter(connector, &conn_iter) {
> > > > > > +             if (connector->connector_type !=
> > > > > > DRM_MODE_CONNECTOR_DisplayPort)
> > > > > > +                     continue;
> > > > > > +
> > > > > > +             aconnector = to_amdgpu_dm_connector(connector);
> > > > > > +
> > > > > > +             /* Ensure we're only dumping the topology of a root
> > > > > > +mst node
> > > > > > */
> > > > > > +             if (!aconnector->mst_mgr.max_payloads)
> > > > > > +                     continue;
> > > > > > +
> > > > > > +             seq_printf(m, "\nMST topology for connector %d\n",
> > > > > > aconnector->connector_id);
> > > > > > +             drm_dp_mst_dump_topology_refs(m,
> > > > > > +&aconnector->mst_mgr);
> > > > > > +     }
> > > > > > +     drm_connector_list_iter_end(&conn_iter);
> > > > > > +
> > > > > > +     return 0;
> > > > > > +}
> > > > > > +
> > > > > > +DEFINE_SHOW_ATTRIBUTE(mst_topology_ref_dump);
> > > > > > +#endif
> > > > > > +
> > > > > >  /*
> > > > > >   * Sets trigger hpd for MST topologies.
> > > > > >   * All connected connectors will be rediscovered and re started
> > > > > > as needed if val of 1 is sent.
> > > > > > @@ -3299,6 +3330,10 @@ void dtn_debugfs_init(struct amdgpu_device
> > > > > > *adev)
> > > > > > 
> > > > > >       debugfs_create_file("amdgpu_mst_topology", 0444, root,
> > > > > >                           adev, &mst_topo_fops);
> > > > > > +#ifdef CONFIG_DRM_DEBUG_DP_MST_TOPOLOGY_REFS
> > > > > > +     debugfs_create_file("amdgpu_dp_mst_topology_refs", 0444,
> > > > > > +root, adev,
> > > > > > +                         &mst_topology_ref_dump_fops); #endif
> > > > > >       debugfs_create_file("amdgpu_dm_dtn_log", 0644, root, adev,
> > > > > >                           &dtn_log_fops);
> > > > > > 
> > > > > > diff --git a/drivers/gpu/drm/drm_dp_mst_topology.c
> > > > > > b/drivers/gpu/drm/drm_dp_mst_topology.c
> > > > > > index 1aa8702383d4..0159828c494d 100644
> > > > > > --- a/drivers/gpu/drm/drm_dp_mst_topology.c
> > > > > > +++ b/drivers/gpu/drm/drm_dp_mst_topology.c
> > > > > > @@ -1366,23 +1366,6 @@ static int drm_dp_mst_wait_tx_reply(struct
> > > > > > drm_dp_mst_branch *mstb,
> > > > > >       return ret;
> > > > > >  }
> > > > > > 
> > > > > > -static struct drm_dp_mst_branch *drm_dp_add_mst_branch_device(u8
> > > > > > lct, u8
> > > > > > *rad) -{
> > > > > > -     struct drm_dp_mst_branch *mstb;
> > > > > > -
> > > > > > -     mstb = kzalloc(sizeof(*mstb), GFP_KERNEL);
> > > > > > -     if (!mstb)
> > > > > > -             return NULL;
> > > > > > -
> > > > > > -     mstb->lct = lct;
> > > > > > -     if (lct > 1)
> > > > > > -             memcpy(mstb->rad, rad, lct / 2);
> > > > > > -     INIT_LIST_HEAD(&mstb->ports);
> > > > > > -     kref_init(&mstb->topology_kref);
> > > > > > -     kref_init(&mstb->malloc_kref);
> > > > > > -     return mstb;
> > > > > > -}
> > > > > > -
> > > > > >  static void drm_dp_free_mst_branch_device(struct kref *kref)  {
> > > > > >       struct drm_dp_mst_branch *mstb = @@ -1642,12 +1625,20 @@
> > > > > > topology_ref_type_to_str(enum drm_dp_mst_topology_ref_type type)
> > > > > >               return "put";
> > > > > >  }
> > > > > > 
> > > > > > +static const char *topology_ref_history_type_to_str(enum
> > > > > > +drm_dp_mst_topology_history_type type) {
> > > > > > +     if (type == DRM_DP_MST_TOPOLOGY_HISTORY_PORT)
> > > > > > +             return "Port";
> > > > > > +     else
> > > > > > +             return "MSTB";
> > > > > > +}
> > > > > > +
> > > > > >  static void
> > > > > > -__dump_topology_ref_history(struct
> > > > > > drm_dp_mst_topology_ref_history *history,
> > > > > > -                         void *ptr, const char *type_str)
> > > > > > +dump_topology_ref_history(struct drm_dp_mst_topology_ref_history
> > > > > > +*history, struct drm_printer p)
> > > > > >  {
> > > > > > -     struct drm_printer p = drm_debug_printer(DBG_PREFIX);
> > > > > > +     char *connector_name = NULL;
> > > > > >       char *buf = kzalloc(PAGE_SIZE, GFP_KERNEL);
> > > > > > +     void *ptr;
> > > > > >       int i;
> > > > > > 
> > > > > >       if (!buf)
> > > > > > @@ -1656,14 +1647,29 @@ __dump_topology_ref_history(struct
> > > > > > drm_dp_mst_topology_ref_history *history,
> > > > > >       if (!history->len)
> > > > > >               goto out;
> > > > > > 
> > > > > > +     /* Get a pointer to the actual MSTB/port so we can the
> > > > > > +memory
> > > > > > address to the kernel log */
> > > > > > +     if (history->type == DRM_DP_MST_TOPOLOGY_HISTORY_PORT)
> > > > > > +             ptr = container_of(history, struct drm_dp_mst_port,
> > > > > > topology_ref_history);
> > > > > > +     else
> > > > > > +             ptr = container_of(history, struct
> > > > > > +drm_dp_mst_branch, topology_ref_history);
> > > > > > +
> > > > > >       /* First, sort the list so that it goes from oldest to
> > > > > > newest
> > > > > >        * reference entry
> > > > > >        */
> > > > > >       sort(history->entries, history->len,
> > > > > > sizeof(*history->entries),
> > > > > >            topology_ref_history_cmp, NULL);
> > > > > > 
> > > > > > -     drm_printf(&p, "%s (%p) topology count reached 0, dumping
> > > > > > history:\n",
> > > > > > -                type_str, ptr);
> > > > > > +     if (history->type == DRM_DP_MST_TOPOLOGY_HISTORY_PORT) {
> > > > > > +             struct drm_dp_mst_port *port = ptr;
> > > > > > +
> > > > > > +             if (port->connector)
> > > > > > +                     connector_name = port->connector->name;
> > > > > > +     }
> > > > > > +     if (connector_name)
> > > > > > +             drm_printf(&p, "Port %s (%p) topology ref
> > > > > > +history:\n",
> > > > > > connector_name, ptr);
> > > > > > +     else
> > > > > > +             drm_printf(&p, "%s (%p) topology ref history:\n",
> > > > > > +
> > > > > > +topology_ref_history_type_to_str(history->type),
> > > > > > ptr);
> > > > > > 
> > > > > >       for (i = 0; i < history->len; i++) {
> > > > > >               const struct drm_dp_mst_topology_ref_entry *entry =
> > > > > > @@
> > > > > > -
> > > > > > 1682,24 +1688,92 @@ __dump_topology_ref_history(struct
> > > > > > drm_dp_mst_topology_ref_history *history,
> > > > > >                          ts_nsec, rem_nsec / 1000, buf);
> > > > > >       }
> > > > > > 
> > > > > > -     /* Now free the history, since this is the only time we
> > > > > > expose it */
> > > > > > -     kfree(history->entries);
> > > > > >  out:
> > > > > >       kfree(buf);
> > > > > >  }
> > > > > > 
> > > > > > +/**
> > > > > > + * drm_dp_mst_dump_topology_refs - helper function for dumping
> > > > > > +the topology ref history
> > > > > > + * @m: File to print to
> > > > > > + * @mgr: &struct drm_dp_mst_topology_mgr to use
> > > > > > + *
> > > > > > + * Prints the topology ref history of all ports and MSTBs on @mgr
> > > > > > +that are still in memory,
> > > > > > + * regardless of whether they're actually still reachable through
> > > > > > +the topology or not. Only enabled
> > > > > > + * when %CONFIG_DRM_DEBUG_DP_MST_TOPOLOGY_REFS is enabled. Can be
> > > > > > +implemented by drivers to assist
> > > > > > + * with debugging leaks in the DP MST helpers.
> > > > > > + */
> > > > > > +void drm_dp_mst_dump_topology_refs(struct seq_file *m, struct
> > > > > > +drm_dp_mst_topology_mgr *mgr) {
> > > > > > +     struct drm_dp_mst_topology_ref_history *history;
> > > > > > +     struct drm_printer p = drm_seq_file_printer(m);
> > > > > > +
> > > > > > +     mutex_lock(&mgr->topology_ref_history_lock);
> > > > > > +     list_for_each_entry(history,
> > > > > > +&mgr->topology_ref_history_list,
> > > > > > +node)
> > > > > > +             dump_topology_ref_history(history, p);
> > > > > > +     mutex_unlock(&mgr->topology_ref_history_lock);
> > > > > > +}
> > > > > > +EXPORT_SYMBOL(drm_dp_mst_dump_topology_refs);
> > > > > > +
> > > > > > +static void
> > > > > > +__init_topology_ref_history(struct
> > > > > > +drm_dp_mst_topology_ref_history
> > > > > > *history,
> > > > > > +                         struct drm_dp_mst_topology_mgr *mgr,
> > > > > > +                         enum drm_dp_mst_topology_history_type
> > > > > > +type) {
> > > > > > +     history->type = type;
> > > > > > +     INIT_LIST_HEAD(&history->node);
> > > > > > +
> > > > > > +     mutex_lock(&mgr->topology_ref_history_lock);
> > > > > > +     list_add(&history->node, &mgr->topology_ref_history_list);
> > > > > > +     mutex_unlock(&mgr->topology_ref_history_lock);
> > > > > > +}
> > > > > > +
> > > > > > +static void
> > > > > > +__destroy_topology_ref_history(struct
> > > > > > +drm_dp_mst_topology_ref_history
> > > > > > *history,
> > > > > > +                            struct drm_dp_mst_topology_mgr *mgr)
> > > > > > +{
> > > > > > +     mutex_lock(&mgr->topology_ref_history_lock);
> > > > > > +     list_del(&mgr->topology_ref_history_list);
> > > > > > +     mutex_unlock(&mgr->topology_ref_history_lock);
> > > > > > +
> > > > > > +     kfree(history->entries);
> > > > > > +}
> > > > > > +
> > > > > > +static __always_inline void
> > > > > > +init_port_topology_history(struct drm_dp_mst_topology_mgr *mgr,
> > > > > > +struct drm_dp_mst_port *port) {
> > > > > > +     __init_topology_ref_history(&port->topology_ref_history,
> > > > > > +mgr,
> > > > > > +
> > > > > > +DRM_DP_MST_TOPOLOGY_HISTORY_PORT);
> > > > > > +}
> > > > > > +
> > > > > > +static __always_inline void
> > > > > > +init_mstb_topology_history(struct drm_dp_mst_topology_mgr *mgr,
> > > > > > +struct drm_dp_mst_branch *mstb) {
> > > > > > +     __init_topology_ref_history(&mstb->topology_ref_history,
> > > > > > +mgr,
> > > > > > +
> > > > > > +DRM_DP_MST_TOPOLOGY_HISTORY_MSTB);
> > > > > > +}
> > > > > > +
> > > > > > +static __always_inline void
> > > > > > +destroy_port_topology_history(struct drm_dp_mst_port *port) {
> > > > > > +     __destroy_topology_ref_history(&port->topology_ref_history,
> > > > > > +port->mgr); }
> > > > > > +
> > > > > > +static __always_inline void
> > > > > > +destroy_mstb_topology_history(struct drm_dp_mst_branch *mstb) {
> > > > > > +     __destroy_topology_ref_history(&mstb->topology_ref_history,
> > > > > > +mstb->mgr); }
> > > > > > +
> > > > > >  static __always_inline void
> > > > > >  dump_mstb_topology_history(struct drm_dp_mst_branch *mstb)  {
> > > > > > -     __dump_topology_ref_history(&mstb->topology_ref_history,
> > > > > > mstb,
> > > > > > -                                 "MSTB");
> > > > > > +     dump_topology_ref_history(&mstb->topology_ref_history,
> > > > > > +drm_debug_printer(DBG_PREFIX));
> > > > > >  }
> > > > > > 
> > > > > >  static __always_inline void
> > > > > >  dump_port_topology_history(struct drm_dp_mst_port *port)  {
> > > > > > -     __dump_topology_ref_history(&port->topology_ref_history,
> > > > > > port,
> > > > > > -                                 "Port");
> > > > > > +     dump_topology_ref_history(&port->topology_ref_history,
> > > > > > +drm_debug_printer(DBG_PREFIX));
> > > > > >  }
> > > > > > 
> > > > > >  static __always_inline void
> > > > > > @@ -1729,6 +1803,14 @@ topology_ref_history_unlock(struct
> > > > > > drm_dp_mst_topology_mgr *mgr)  }  #else  static inline void
> > > > > > +init_port_topology_history(struct drm_dp_mst_topology_mgr *mgr,
> > > > > > +struct drm_dp_mst_port *port); static inline void
> > > > > Should also add the bracket, otherwise will get warnings.
> > > > > => static inline void init_port_topology_history(struct
> > > > > drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_port *port) {};
> > > > > 
> > > > > > +init_mstb_topology_history(struct drm_dp_mst_topology_mgr *mgr,
> > > > > > +struct drm_dp_mst_branch *mstb); static inline void
> > > > > Same as above
> > > > > => static inline void init_mstb_topology_history(struct
> > > > > drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_branch *mstb) {};
> > > > > 
> > > > > > +destroy_port_topology_history(struct drm_dp_mst_topology_mgr
> > > > > > +*mgr, struct drm_dp_mst_port *port); static inline void
> > > > > destroy_port_topology_history() takes one parameter only which is
> > > > > port.
> > > > > => destroy_port_topology_history(struct drm_dp_mst_port *port) {};
> > > > > 
> > > > > > +destroy_mstb_topology_history(struct drm_dp_mst_topology_mgr
> > > > > > +*mgr, struct drm_dp_mst_branch *mstb); static inline void
> > > > > destroy_mstb_topology_history() takes one parameter only which is
> > > > > mstb => destroy_mstb_topology_history(struct drm_dp_mst_branch
> > > > > *mstb) {};
> > > > > 
> > > > > >  topology_ref_history_lock(struct drm_dp_mst_topology_mgr *mgr) {}
> > > > > > static inline void  topology_ref_history_unlock(struct
> > > > > > drm_dp_mst_topology_mgr *mgr) {} @@ -1740,6 +1822,25 @@
> > > > > > dump_port_topology_history(struct drm_dp_mst_port *port) {}
> > > > > > #define save_port_topology_ref(port, type)  #endif
> > > > > > 
> > > > > > +static struct drm_dp_mst_branch *
> > > > > > +drm_dp_add_mst_branch_device(struct drm_dp_mst_topology_mgr *mgr,
> > > > > > +u8 lct, u8 *rad) {
> > > > > > +     struct drm_dp_mst_branch *mstb;
> > > > > > +
> > > > > > +     mstb = kzalloc(sizeof(*mstb), GFP_KERNEL);
> > > > > > +     if (!mstb)
> > > > > > +             return NULL;
> > > > > > +
> > > > > > +     mstb->lct = lct;
> > > > > > +     if (lct > 1)
> > > > > > +             memcpy(mstb->rad, rad, lct / 2);
> > > > > > +     INIT_LIST_HEAD(&mstb->ports);
> > > > > > +     kref_init(&mstb->topology_kref);
> > > > > > +     kref_init(&mstb->malloc_kref);
> > > > > > +     init_mstb_topology_history(mgr, mstb);
> > > > > > +     return mstb;
> > > > > > +}
> > > > > > +
> > > > > >  static void drm_dp_destroy_mst_branch_device(struct kref *kref)
> > > > > > {
> > > > > >       struct drm_dp_mst_branch *mstb = @@ -1747,6 +1848,7 @@
> > > > > > static void drm_dp_destroy_mst_branch_device(struct
> > > > > > kref *kref)
> > > > > >       struct drm_dp_mst_topology_mgr *mgr = mstb->mgr;
> > > > > > 
> > > > > >       dump_mstb_topology_history(mstb);
> > > > > > +     destroy_mstb_topology_history(mstb);
> > > > > > 
> > > > > >       INIT_LIST_HEAD(&mstb->destroy_next);
> > > > > > 
> > > > > > @@ -1856,6 +1958,7 @@ static void drm_dp_destroy_port(struct kref
> > > > > > *kref)
> > > > > >       struct drm_dp_mst_topology_mgr *mgr = port->mgr;
> > > > > > 
> > > > > >       dump_port_topology_history(port);
> > > > > > +     destroy_port_topology_history(port);
> > > > > > 
> > > > > >       /* There's nothing that needs locking to destroy an input
> > > > > > port yet */
> > > > > >       if (port->input) {
> > > > > > @@ -2135,7 +2238,7 @@ drm_dp_port_set_pdt(struct drm_dp_mst_port
> > > > > > *port, u8 new_pdt,
> > > > > >                       ret = drm_dp_mst_register_i2c_bus(port);
> > > > > >               } else {
> > > > > >                       lct = drm_dp_calculate_rad(port, rad);
> > > > > > -                     mstb = drm_dp_add_mst_branch_device(lct,
> > > > > > rad);
> > > > > > +                     mstb = drm_dp_add_mst_branch_device(mgr,
> > > > > > +lct, rad);
> > > > > >                       if (!mstb) {
> > > > > >                               ret = -ENOMEM;
> > > > > >                               drm_err(mgr->dev, "Failed to create
> > > > > > MSTB for port %p", port); @@ -2366,6 +2469,8 @@
> > > > > > drm_dp_mst_add_port(struct drm_device *dev,
> > > > > >        */
> > > > > >       drm_dp_mst_get_mstb_malloc(mstb);
> > > > > > 
> > > > > > +     init_port_topology_history(mgr, port);
> > > > > > +
> > > > > >       return port;
> > > > > >  }
> > > > > > 
> > > > > > @@ -3745,7 +3850,7 @@ int drm_dp_mst_topology_mgr_set_mst(struct
> > > > > > drm_dp_mst_topology_mgr *mgr, bool ms
> > > > > >               }
> > > > > > 
> > > > > >               /* add initial branch device at LCT 1 */
> > > > > > -             mstb = drm_dp_add_mst_branch_device(1, NULL);
> > > > > > +             mstb = drm_dp_add_mst_branch_device(mgr, 1, NULL);
> > > > > >               if (mstb == NULL) {
> > > > > >                       ret = -ENOMEM;
> > > > > >                       goto out_unlock; @@ -5512,14 +5617,16 @@ int
> > > > > > drm_dp_mst_topology_mgr_init(struct
> > > > > > drm_dp_mst_topology_mgr *mgr,
> > > > > >       mutex_init(&mgr->delayed_destroy_lock);
> > > > > >       mutex_init(&mgr->up_req_lock);
> > > > > >       mutex_init(&mgr->probe_lock); -#if
> > > > > > IS_ENABLED(CONFIG_DRM_DEBUG_DP_MST_TOPOLOGY_REFS)
> > > > > > -     mutex_init(&mgr->topology_ref_history_lock);
> > > > > > -#endif
> > > > > >       INIT_LIST_HEAD(&mgr->tx_msg_downq);
> > > > > >       INIT_LIST_HEAD(&mgr->destroy_port_list);
> > > > > >       INIT_LIST_HEAD(&mgr->destroy_branch_device_list);
> > > > > >       INIT_LIST_HEAD(&mgr->up_req_list);
> > > > > > 
> > > > > > +#if IS_ENABLED(CONFIG_DRM_DEBUG_DP_MST_TOPOLOGY_REFS)
> > > > > > +     mutex_init(&mgr->topology_ref_history_lock);
> > > > > > +     INIT_LIST_HEAD(&mgr->topology_ref_history_list);
> > > > > > +#endif
> > > > > > +
> > > > > >       /*
> > > > > >        * delayed_destroy_work will be queued on a dedicated WQ, so
> > > > > > that any
> > > > > >        * requeuing will be also flushed when deiniting the
> > > > > > topology manager.
> > > > > > diff --git a/drivers/gpu/drm/nouveau/nouveau_debugfs.c
> > > > > > b/drivers/gpu/drm/nouveau/nouveau_debugfs.c
> > > > > > index 1cbe01048b93..53ec7c1daada 100644
> > > > > > --- a/drivers/gpu/drm/nouveau/nouveau_debugfs.c
> > > > > > +++ b/drivers/gpu/drm/nouveau/nouveau_debugfs.c
> > > > > > @@ -29,9 +29,13 @@
> > > > > >   */
> > > > > > 
> > > > > >  #include <linux/debugfs.h>
> > > > > > +#include <drm/drm_dp_mst_helper.h> #include <drm/drm_encoder.h>
> > > > > >  #include <nvif/class.h>
> > > > > >  #include <nvif/if0001.h>
> > > > > > +#include <nouveau_encoder.h>
> > > > > >  #include "nouveau_debugfs.h"
> > > > > > +#include "nouveau_display.h"
> > > > > >  #include "nouveau_drv.h"
> > > > > > 
> > > > > >  static int
> > > > > > @@ -68,6 +72,34 @@ nouveau_debugfs_strap_peek(struct seq_file *m,
> > > > > > void
> > > > > > *data)
> > > > > >       return 0;
> > > > > >  }
> > > > > > 
> > > > > > +#ifdef CONFIG_DRM_DEBUG_DP_MST_TOPOLOGY_REFS
> > > > > > +static int nouveau_debugfs_mst_topology_history(struct seq_file
> > > > > > +*m, void *data) {
> > > > > > +     struct drm_info_node *node = m->private;
> > > > > > +     struct drm_device *dev = node->minor->dev;
> > > > > > +     struct drm_encoder *encoder;
> > > > > > +     struct nouveau_display *disp = nouveau_display(dev);
> > > > > > +
> > > > > > +     if (disp->disp.object.oclass < GF110_DISP)
> > > > > > +             return -EINVAL;
> > > > > > +
> > > > > > +     drm_for_each_encoder(encoder, dev) {
> > > > > > +             struct nv50_mstm *mstm;
> > > > > > +
> > > > > > +             /* We need the real encoder for each MST mgr */
> > > > > > +             if (encoder->encoder_type != DRM_MODE_ENCODER_TMDS)
> > > > > > +                     continue;
> > > > > > +             mstm = nouveau_encoder(encoder)->dp.mstm;
> > > > > > +             if (!mstm)
> > > > > > +                     continue;
> > > > > > +
> > > > > > +             seq_printf(m, "MSTM on %s:\n", encoder->name);
> > > > > > +             drm_dp_mst_dump_topology_refs(m, &mstm->mgr);
> > > > > > +     }
> > > > > > +     return 0;
> > > > > > +}
> > > > > > +#endif
> > > > > > +
> > > > > >  static int
> > > > > >  nouveau_debugfs_pstate_get(struct seq_file *m, void *data)  { @@
> > > > > > -213,6
> > > > > > +245,9 @@ static const struct file_operations
> > > > > > nouveau_pstate_fops = {  static struct drm_info_list
> > > > > > nouveau_debugfs_list[] = {
> > > > > >       { "vbios.rom",  nouveau_debugfs_vbios_image, 0, NULL },
> > > > > >       { "strap_peek", nouveau_debugfs_strap_peek, 0, NULL },
> > > > > > +#ifdef CONFIG_DRM_DEBUG_DP_MST_TOPOLOGY_REFS
> > > > > > +     { "dp_mst_topology_refs",
> > > > > > +nouveau_debugfs_mst_topology_history, 0, NULL }, #endif
> > > > > >  };
> > > > > >  #define NOUVEAU_DEBUGFS_ENTRIES ARRAY_SIZE(nouveau_debugfs_list)
> > > > > > 
> > > > > > diff --git a/include/drm/drm_dp_mst_helper.h
> > > > > > b/include/drm/drm_dp_mst_helper.h index 78044ac5b59b..e3a73d8d97c0
> > > > > > 100644
> > > > > > --- a/include/drm/drm_dp_mst_helper.h
> > > > > > +++ b/include/drm/drm_dp_mst_helper.h
> > > > > > @@ -35,6 +35,11 @@ enum drm_dp_mst_topology_ref_type {
> > > > > >       DRM_DP_MST_TOPOLOGY_REF_PUT,
> > > > > >  };
> > > > > > 
> > > > > > +enum drm_dp_mst_topology_history_type {
> > > > > > +     DRM_DP_MST_TOPOLOGY_HISTORY_PORT,
> > > > > > +     DRM_DP_MST_TOPOLOGY_HISTORY_MSTB, };
> > > > > > +
> > > > > >  struct drm_dp_mst_topology_ref_history {
> > > > > >       struct drm_dp_mst_topology_ref_entry {
> > > > > >               enum drm_dp_mst_topology_ref_type type; @@ -43,6
> > > > > > +48,9 @@ struct drm_dp_mst_topology_ref_history {
> > > > > >               depot_stack_handle_t backtrace;
> > > > > >       } *entries;
> > > > > >       int len;
> > > > > > +
> > > > > > +     enum drm_dp_mst_topology_history_type type;
> > > > > > +     struct list_head node;
> > > > > >  };
> > > > > >  #endif /* IS_ENABLED(CONFIG_DRM_DEBUG_DP_MST_TOPOLOGY_REFS) */
> > > > > > 
> > > > > > @@ -769,6 +777,12 @@ struct drm_dp_mst_topology_mgr {
> > > > > >        * &drm_dp_mst_branch.topology_ref_history.
> > > > > >        */
> > > > > >       struct mutex topology_ref_history_lock;
> > > > > > +
> > > > > > +     /**
> > > > > > +      * @topology_ref_history_list: contains a list of topology
> > > > > > +ref
> > > > > > histories for any MSTBs or
> > > > > > +      * ports that are still in memory
> > > > > > +      */
> > > > > > +     struct list_head topology_ref_history_list;
> > > > > >  #endif
> > > > > >  };
> > > > > > 
> > > > > > @@ -873,6 +887,10 @@ void drm_dp_mst_put_port_malloc(struct
> > > > > > drm_dp_mst_port *port);
> > > > > > 
> > > > > >  struct drm_dp_aux *drm_dp_mst_dsc_aux_for_port(struct
> > > > > > drm_dp_mst_port *port);
> > > > > > 
> > > > > > +#ifdef CONFIG_DRM_DEBUG_DP_MST_TOPOLOGY_REFS
> > > > > > +void drm_dp_mst_dump_topology_refs(struct seq_file *m, struct
> > > > > > +drm_dp_mst_topology_mgr *mgr); #endif
> > > > > > +
> > > > > >  extern const struct drm_private_state_funcs
> > > > > > drm_dp_mst_topology_state_funcs;
> > > > > > 
> > > > > >  /**
> > > > > > --
> > > > > > 2.31.1
> > > > > 
> > > > 
> > > > --
> > > > Cheers,
> > > >  Lyude Paul (she/her)
> > > >  Software Engineer at Red Hat
> > 
> 

-- 
Cheers, Lyude Paul (she/her) Software Engineer at Red Hat




[Index of Archives]     [Linux DRI Users]     [Linux Intel Graphics]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [XFree86]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [XFree86]
  Powered by Linux