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

From: Mohamed Ahmed

Date: Tue Aug 18 2026 - 16:02:26 EST


On Tue, Aug 18, 2026 at 2:59 AM <lyude@xxxxxxxxxx> wrote:
>
> 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.
>
The head state changed actually (but RG position didn't), so adding
this in would be a regression. I have some work to wire it up properly
(part of VRR bringup) but I wasn't sure whether to include it in this
series or not. We don't have precise vblank timestamps for anything
GSP atm and everything falls back to the interrupt path, so it would
technically be a new feature rather than fix ups.
> > 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;
>