Re: [PATCH 5/7] nouveau/gsp: fix vblank interrupts on GB20x

From: lyude

Date: Mon Aug 17 2026 - 18:59:19 EST


On Sat, 2026-08-15 at 03:57 +0400, Mohamed Ahmed wrote:
>
> +
> +static const struct nvkm_head_func
> +gb202_head = {
> + .state = r535_head_state,
> + .vblank_get = gb202_head_vblank_get,
> + .vblank_put = gb202_head_vblank_put,
> +};
> +

You should probably add these two as well:

.state = gv100_head_state,
.rgpos = gv100_head_rgpos,

I don't think they've actually changed in blackwell, but it's possible
maybe they do change in GB200x so you probably want to double check so
we don't lose precise vblank timestamps again.

>  static struct nvkm_conn *
>  r535_conn_new(struct nvkm_disp *disp, u32 id)
>  {
> @@ -1496,6 +1523,20 @@ r535_disp_intr(struct nvkm_inth *inth)
>   return IRQ_HANDLED;
>  }
>  
> +static irqreturn_t
> +gb202_disp_intr(struct nvkm_inth *inth)
> +{
> + struct nvkm_disp *disp = container_of(inth, typeof(*disp),
> engine.subdev.inth);
> + irqreturn_t ret = r535_disp_intr(inth);
> +
> + /* The FE interrupt vectors are message-based on NVD5.0. Re-
> arm the
> + * low-latency vector so it fires again for any event that
> latched
> + * while we were servicing.
> + */
> + nvkm_wr32(disp->engine.subdev.device, 0x611f34, 0x00000001);
> + return ret;
> +}
> +
>  static void
>  r535_disp_fini(struct nvkm_disp *disp, bool suspend)
>  {
> @@ -1568,7 +1609,9 @@ r535_disp_oneinit(struct nvkm_disp *disp)
>   struct nvkm_device *device = disp->engine.subdev.device;
>   struct nvkm_gsp *gsp = device->gsp;
>   const struct nvkm_rm_api *rmapi = gsp->rm->api;
> + const struct nvkm_rm_gpu *gpu = gsp->rm->gpu;
>   NV2080_CTRL_INTERNAL_DISPLAY_WRITE_INST_MEM_PARAMS *ctrl;
> + nvkm_inth_func intr_func;
>   unsigned long mask;
>   int ret, i;
>  
> @@ -1722,7 +1765,12 @@ r535_disp_oneinit(struct nvkm_disp *disp)
>   nvkm_gsp_rm_ctrl_done(&disp->rm.objcom, ctrl);
>  
>   for_each_set_bit(i, &disp->head.mask, disp->head.nr)
> {
> - ret = nvkm_head_new_(&r535_head, disp, i);
> + const struct nvkm_head_func *func =
> &r535_head;
> +
> + if (gpu->disp.class.root >= GB202_DISP)
> + func = &gb202_head;
> +
> + ret = nvkm_head_new_(func, disp, i);
>   if (ret)
>   return ret;
>   }
> @@ -1766,12 +1814,21 @@ r535_disp_oneinit(struct nvkm_disp *disp)
>   if (ret)
>   return ret;
>  
> - ret = nvkm_gsp_intr_stall(gsp, disp->engine.subdev.type,
> disp->engine.subdev.inst);
> + if (gpu->disp.class.root >= GB202_DISP) {
> + /* GB20x deliver head-timing interrupts on the
> display's
> + * separate low-latency vector (interrupt table
> instance 1).
> + */
> + ret = nvkm_gsp_intr_stall(gsp, disp-
> >engine.subdev.type, 1);
> + intr_func = gb202_disp_intr;
> + } else {
> + ret = nvkm_gsp_intr_stall(gsp, disp-
> >engine.subdev.type, disp->engine.subdev.inst);
> + intr_func = r535_disp_intr;
> + }
>   if (ret < 0)
>   return ret;
>  
>   ret = nvkm_inth_add(&device->vfn->intr, ret,
> NVKM_INTR_PRIO_NORMAL, &disp->engine.subdev,
> -     r535_disp_intr, &disp-
> >engine.subdev.inth);
> +     intr_func, &disp->engine.subdev.inth);
>   if (ret)
>   return ret;
>  
> diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/r570/gsp.c
> b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/r570/gsp.c
> index 996941c668ba..2590b22663cb 100644
> --- a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/r570/gsp.c
> +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/r570/gsp.c
> @@ -44,6 +44,14 @@ r570_gsp_xlat_mc_engine_idx(u32 mc_engine_idx,
> enum nvkm_subdev_type *ptype, int
>   *ptype = NVKM_ENGINE_DISP;
>   *pinst = 0;
>   return true;
> + case MC_ENGINE_IDX_DISP_LOW:
> + /* GB20x+ report a separate low-latency display
> vector, used
> + * for head-timing interrupts. Expose it as a second
> DISP
> + * interrupt instance.
> + */
> + *ptype = NVKM_ENGINE_DISP;
> + *pinst = 1;
> + return true;
>   case MC_ENGINE_IDX_CE0 ... MC_ENGINE_IDX_CE19:
>   *ptype = NVKM_ENGINE_CE;
>   *pinst = mc_engine_idx - MC_ENGINE_IDX_CE0;