On Wed, Sep 16, 2026 at 10:22 AM Lyude Paul <[email protected]> wrote:
>
> OpenRM's runtime PM handling looks a bit different then nouveau's, one part
> in particular that differs from us: OpenRM actually consults GSP to ask
> whether the GPU should be allowed to enter Gc6 and/or GcOff before runtime
> suspending the GPU. In the event the card isn't ready, runtime suspend is
> simply delayed for a few seconds before retrying.
>
> Implement the command used for querying GSP about this,
> NV2080_CTRL_CMD_INTERNAL_GCX_ENTRY_PREREQUISITE, and check to ensure that
> the GPU is ready for runtime suspend in nouveau_pmops_runtime_suspend()
> using this query. If the GPU can't be runtime suspended, update the last
> busy counter of the device and then return -EBUSY from
> nouveau_pmops_runtime_suspend() - essentially delaying the runtime suspend
> process by whatever autosuspend_delay_ms is set to.
>
> Signed-off-by: Lyude Paul <[email protected]>
>
> ---

>
> diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/user.c 
> b/drivers/gpu/drm/nouveau/nvkm/engine/device/user.c
> index 23d11d8221cb6..c47d6daa9e5aa 100644
> --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/user.c
> +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/user.c
> @@ -27,6 +27,8 @@
>
>  #include <core/client.h>
>  #include <subdev/fb.h>
> +#include <subdev/gsp.h>
> +#include <subdev/gsp/priv.h>

Including a priv.h seems like a layering violation.

I think you should define a nvkm_gsp_gcx_ready and then call the r535
via a function pointer in nvkm_gsp_func.


>  #include <subdev/instmem.h>
>  #include <subdev/timer.h>
>
> @@ -189,6 +191,41 @@ nvkm_udevice_time(struct nvkm_udevice *udev, void *data, 
> u32 size)
>         return ret;
>  }
>
> +static int
> +nvkm_udevice_gcx_ready(struct nvkm_udevice *udev, void *data, u32 size)
> +{
> +       struct nvkm_object *object = &udev->object;
> +       struct nvkm_device *device = udev->device;
> +       struct nvkm_gsp *gsp = device->gsp;
> +       union {
> +               struct nv_device_gcx_ready_v0 v0;
> +       } *args = data;
> +       int ret = -ENOSYS;
> +
> +       /* XXX: We don't know any way of performing this check outside of 
> GSP, so just assume
> +        * things are ready for non-GSP clients.
> +        */
> +       if (!gsp) {
> +               args->v0.ready = NV_DEVICE_GC6_READY | NV_DEVICE_GCOFF_READY;
> +               return 0;
> +       }
> +
> +       nvif_ioctl(object, "device gcx ready size %d\n", size);
> +       ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false);
> +       if (!ret) {
> +               nvif_ioctl(object, "device gcx ready vers %d\n", 
> args->v0.version);
> +
> +               ret = r535_gsp_gcx_ready(gsp);
> +               if (ret < 0)
> +                       return ret;
> +
> +               args->v0.ready = ret;
> +               ret = 0;
> +       }
> +
> +       return ret;
> +}
> +
>  static int
>  nvkm_udevice_mthd(struct nvkm_object *object, u32 mthd, void *data, u32 size)
>  {
> @@ -199,6 +236,8 @@ nvkm_udevice_mthd(struct nvkm_object *object, u32 mthd, 
> void *data, u32 size)
>                 return nvkm_udevice_info(udev, data, size);
>         case NV_DEVICE_V0_TIME:
>                 return nvkm_udevice_time(udev, data, size);
> +       case NV_DEVICE_V0_GCX_READY:
> +               return nvkm_udevice_gcx_ready(udev, data, size);
>         default:
>                 break;
>         }
> +       return ret;
> +}
> +
>  int
>  r535_gsp_fini(struct nvkm_gsp *gsp, enum nvkm_suspend_state suspend)
>  {
> diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/r535/nvrm/gsp.h 
> b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/r535/nvrm/gsp.h
> index b6683a5bf870c..fd1170037c030 100644
> --- a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/r535/nvrm/gsp.h
> +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/r535/nvrm/gsp.h
> @@ -782,6 +782,13 @@ typedef struct 
> NV2080_CTRL_INTERNAL_INTR_GET_KERNEL_TABLE_PARAMS {
>
>  #define GSP_FW_HEAP_PARAM_CLIENT_ALLOC_SIZE      ((48 << 10) * 2048)   // 
> Support 2048 channels
>
> +#define NV2080_CTRL_CMD_INTERNAL_GCX_ENTRY_PREREQUISITE (0x2080a7d7)
> +
> +typedef struct NV2080_CTRL_INTERNAL_GCX_ENTRY_PREREQUISITE_PARAMS {
> +    NvBool bIsGC6Satisfied;
> +    NvBool bIsGCOFFSatisfied;
> +} NV2080_CTRL_INTERNAL_GCX_ENTRY_PREREQUISITE_PARAMS;

Have you confirmed this struct didn't change in r570,

Thanks,
Dave.

Reply via email to