diff --git a/drivers/gpu/drm/nouveau/nouveau_state.c b/drivers/gpu/drm/nouveau/nouveau_state.c index 93a2e83d0246..07691c2eceac 100644 --- a/drivers/gpu/drm/nouveau/nouveau_state.c +++ b/drivers/gpu/drm/nouveau/nouveau_state.c @@ -633,7 +633,10 @@ nouveau_card_init(struct drm_device *dev) break; } - if (dev_priv->card_type == NV_40) + if (dev_priv->card_type == NV_40 || + dev_priv->chipset == 0x31 || + dev_priv->chipset == 0x34 || + dev_priv->chipset == 0x36) nv31_mpeg_create(dev); else if (dev_priv->card_type == NV_50 && diff --git a/drivers/gpu/drm/nouveau/nv31_mpeg.c b/drivers/gpu/drm/nouveau/nv31_mpeg.c index 72e86660258d..6f06a0713f00 100644 --- a/drivers/gpu/drm/nouveau/nv31_mpeg.c +++ b/drivers/gpu/drm/nouveau/nv31_mpeg.c @@ -28,8 +28,30 @@ struct nv31_mpeg_engine { struct nouveau_exec_engine base; + atomic_t refcount; }; + +static int +nv31_mpeg_context_new(struct nouveau_channel *chan, int engine) +{ + struct nv31_mpeg_engine *pmpeg = nv_engine(chan->dev, engine); + + if (!atomic_add_unless(&pmpeg->refcount, 1, 1)) + return -EBUSY; + + chan->engctx[engine] = (void *)0xdeadcafe; + return 0; +} + +static void +nv31_mpeg_context_del(struct nouveau_channel *chan, int engine) +{ + struct nv31_mpeg_engine *pmpeg = nv_engine(chan->dev, engine); + atomic_dec(&pmpeg->refcount); + chan->engctx[engine] = NULL; +} + static int nv40_mpeg_context_new(struct nouveau_channel *chan, int engine) { @@ -121,7 +143,7 @@ nv31_mpeg_init(struct drm_device *dev, int engine) /* PMPEG init */ nv_wr32(dev, 0x00b32c, 0x00000000); nv_wr32(dev, 0x00b314, 0x00000100); - nv_wr32(dev, 0x00b220, 0x00000044); + nv_wr32(dev, 0x00b220, nv44_graph_class(dev) ? 0x00000044 : 0x00000031); nv_wr32(dev, 0x00b300, 0x02001ec1); nv_mask(dev, 0x00b32c, 0x00000001, 0x00000001); @@ -191,6 +213,10 @@ nv31_mpeg_isr_chid(struct drm_device *dev, u32 inst) unsigned long flags; int i; + /* hardcode drm channel id on nv3x, so swmthd lookup works */ + if (dev_priv->card_type < NV_40) + return 0; + spin_lock_irqsave(&dev_priv->channels.lock, flags); for (i = 0; i < dev_priv->engine.fifo.channels; i++) { if (!dev_priv->channels.ptr[i]) @@ -275,17 +301,24 @@ nv31_mpeg_destroy(struct drm_device *dev, int engine) int nv31_mpeg_create(struct drm_device *dev) { + struct drm_nouveau_private *dev_priv = dev->dev_private; struct nv31_mpeg_engine *pmpeg; pmpeg = kzalloc(sizeof(*pmpeg), GFP_KERNEL); if (!pmpeg) return -ENOMEM; + atomic_set(&pmpeg->refcount, 0); pmpeg->base.destroy = nv31_mpeg_destroy; pmpeg->base.init = nv31_mpeg_init; pmpeg->base.fini = nv31_mpeg_fini; - pmpeg->base.context_new = nv40_mpeg_context_new; - pmpeg->base.context_del = nv40_mpeg_context_del; + if (dev_priv->card_type < NV_40) { + pmpeg->base.context_new = nv31_mpeg_context_new; + pmpeg->base.context_del = nv31_mpeg_context_del; + } else { + pmpeg->base.context_new = nv40_mpeg_context_new; + pmpeg->base.context_del = nv40_mpeg_context_del; + } pmpeg->base.object_new = nv31_mpeg_object_new; /* ISR vector, PMC_ENABLE bit, and TILE regs are shared between