On Sat, 2018-11-24 at 16:47 +0100, Karol Herbst wrote: > why the nouveau_is_rpm_worker stuff? To prevent us from trying to grab a runtime PM reference in the runtime suspend/resume codepath without preventing us from using the aux channel in those code paths, since drm_dp_mst_topology_mgr_suspend() and drm_dp_mst_topology_mgr_resume() both need to be able to use the aux channel. Without that those functions will try to grab a runtime pm ref while runtime resume then deadlock. > On Sat, Nov 17, 2018 at 2:50 AM Lyude Paul <lyude@xxxxxxxxxx> wrote: > > Now that we have ->pre_transfer() and ->post_transfer() for DP AUX > > channel devices, we can implement these hooks in order to ensure that > > the GPU is actually woken up before AUX transactions happen. This fixes > > /dev/drm_dp_aux* not working while the GPU is suspended, along with some > > more rare issues where the GPU might runtime-suspend if the time between > > two DP AUX channel transactions ends up being longer then the runtime > > suspend delay (sometimes observed on KASAN kernels where everything is > > slow). > > > > Additionally, we add tracking for the current task that's running our > > runtime suspend/resume callbacks. We need this in order to avoid trying > > to grab a runtime power reference when nouveau uses the DP AUX channel > > for MST suspend/resume in it's runtime susped/resume callbacks. > > > > Signed-off-by: Lyude Paul <lyude@xxxxxxxxxx> > > --- > > drivers/gpu/drm/nouveau/nouveau_connector.c | 36 +++++++++++++++++++++ > > drivers/gpu/drm/nouveau/nouveau_drm.c | 12 ++++++- > > drivers/gpu/drm/nouveau/nouveau_drv.h | 8 +++++ > > 3 files changed, 55 insertions(+), 1 deletion(-) > > > > diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c > > b/drivers/gpu/drm/nouveau/nouveau_connector.c > > index fd80661dff92..d2e9752f2f91 100644 > > --- a/drivers/gpu/drm/nouveau/nouveau_connector.c > > +++ b/drivers/gpu/drm/nouveau/nouveau_connector.c > > @@ -1171,6 +1171,38 @@ nouveau_connector_hotplug(struct nvif_notify > > *notify) > > return NVIF_NOTIFY_KEEP; > > } > > > > +static int > > +nouveau_connector_aux_pre_xfer(struct drm_dp_aux *obj) > > +{ > > + struct nouveau_connector *nv_connector = > > + container_of(obj, typeof(*nv_connector), aux); > > + struct nouveau_drm *drm = nouveau_drm(nv_connector->base.dev); > > + int ret; > > + > > + if (nouveau_is_rpm_worker(drm)) > > + return 0; > > + > > + ret = pm_runtime_get_sync(drm->dev->dev); > > + if (ret < 0 && ret != -EAGAIN) > > + return ret; > > + > > + return 0; > > +} > > + > > +static void > > +nouveau_connector_aux_post_xfer(struct drm_dp_aux *obj) > > +{ > > + struct nouveau_connector *nv_connector = > > + container_of(obj, typeof(*nv_connector), aux); > > + struct nouveau_drm *drm = nouveau_drm(nv_connector->base.dev); > > + > > + if (nouveau_is_rpm_worker(drm)) > > + return; > > + > > + pm_runtime_mark_last_busy(drm->dev->dev); > > + pm_runtime_put_autosuspend(drm->dev->dev); > > +} > > + > > static ssize_t > > nouveau_connector_aux_xfer(struct drm_dp_aux *obj, struct drm_dp_aux_msg > > *msg) > > { > > @@ -1341,6 +1373,10 @@ nouveau_connector_create(struct drm_device *dev, > > int index) > > case DRM_MODE_CONNECTOR_DisplayPort: > > case DRM_MODE_CONNECTOR_eDP: > > nv_connector->aux.dev = dev->dev; > > + nv_connector->aux.pre_transfer = > > + nouveau_connector_aux_pre_xfer; > > + nv_connector->aux.post_transfer = > > + nouveau_connector_aux_post_xfer; > > nv_connector->aux.transfer = nouveau_connector_aux_xfer; > > ret = drm_dp_aux_register(&nv_connector->aux); > > if (ret) { > > diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c > > b/drivers/gpu/drm/nouveau/nouveau_drm.c > > index 2b2baf6e0e0d..4323e9e61c2e 100644 > > --- a/drivers/gpu/drm/nouveau/nouveau_drm.c > > +++ b/drivers/gpu/drm/nouveau/nouveau_drm.c > > @@ -859,6 +859,7 @@ nouveau_pmops_runtime_suspend(struct device *dev) > > { > > struct pci_dev *pdev = to_pci_dev(dev); > > struct drm_device *drm_dev = pci_get_drvdata(pdev); > > + struct nouveau_drm *drm = nouveau_drm(drm_dev); > > int ret; > > > > if (!nouveau_pmops_runtime()) { > > @@ -866,6 +867,8 @@ nouveau_pmops_runtime_suspend(struct device *dev) > > return -EBUSY; > > } > > > > + drm->rpm_task = current; > > + > > nouveau_switcheroo_optimus_dsm(); > > ret = nouveau_do_suspend(drm_dev, true); > > pci_save_state(pdev); > > @@ -873,6 +876,8 @@ nouveau_pmops_runtime_suspend(struct device *dev) > > pci_ignore_hotplug(pdev); > > pci_set_power_state(pdev, PCI_D3cold); > > drm_dev->switch_power_state = DRM_SWITCH_POWER_DYNAMIC_OFF; > > + > > + drm->rpm_task = NULL; > > return ret; > > } > > > > @@ -881,6 +886,7 @@ nouveau_pmops_runtime_resume(struct device *dev) > > { > > struct pci_dev *pdev = to_pci_dev(dev); > > struct drm_device *drm_dev = pci_get_drvdata(pdev); > > + struct nouveau_drm *drm = nouveau_drm(drm_dev); > > struct nvif_device *device = &nouveau_drm(drm_dev)->client.device; > > int ret; > > > > @@ -889,11 +895,13 @@ nouveau_pmops_runtime_resume(struct device *dev) > > return -EBUSY; > > } > > > > + drm->rpm_task = current; > > + > > pci_set_power_state(pdev, PCI_D0); > > pci_restore_state(pdev); > > ret = pci_enable_device(pdev); > > if (ret) > > - return ret; > > + goto out; > > pci_set_master(pdev); > > > > ret = nouveau_do_resume(drm_dev, true); > > @@ -905,6 +913,8 @@ nouveau_pmops_runtime_resume(struct device *dev) > > /* Monitors may have been connected / disconnected during suspend > > */ > > schedule_work(&nouveau_drm(drm_dev)->hpd_work); > > > > +out: > > + drm->rpm_task = NULL; > > return ret; > > } > > > > diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h > > b/drivers/gpu/drm/nouveau/nouveau_drv.h > > index 0b2191fa96f7..e8d4203ddfb4 100644 > > --- a/drivers/gpu/drm/nouveau/nouveau_drv.h > > +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h > > @@ -212,6 +212,8 @@ struct nouveau_drm { > > bool have_disp_power_ref; > > > > struct dev_pm_domain vga_pm_domain; > > + > > + struct task_struct *rpm_task; > > }; > > > > static inline struct nouveau_drm * > > @@ -231,6 +233,12 @@ int nouveau_pmops_suspend(struct device *); > > int nouveau_pmops_resume(struct device *); > > bool nouveau_pmops_runtime(void); > > > > +static inline bool > > +nouveau_is_rpm_worker(struct nouveau_drm *drm) > > +{ > > + return drm->rpm_task == current; > > +} > > + > > #include <nvkm/core/tegra.h> > > > > struct drm_device * > > -- > > 2.19.1 > > > > _______________________________________________ > > Nouveau mailing list > > Nouveau@xxxxxxxxxxxxxxxxxxxxx > > https://lists.freedesktop.org/mailman/listinfo/nouveau -- Cheers, Lyude Paul _______________________________________________ dri-devel mailing list dri-devel@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/dri-devel