mirror of
https://github.com/torvalds/linux.git
synced 2024-12-18 09:02:17 +00:00
drm/nv40/gr: rewrite/split context takedown functions
It's completely pointless to save the PGRAPH context when destroying a channel, so don't bother. This commit should also fix kernel.org bug 39422, where the DRM channel state was incorrectly being saved because we left PGRAPH FIFO access enabled while running the ctxprog. Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
This commit is contained in:
parent
9717f3d953
commit
12a30e267c
@ -35,89 +35,6 @@ struct nv40_graph_engine {
|
||||
u32 grctx_size;
|
||||
};
|
||||
|
||||
static struct nouveau_channel *
|
||||
nv40_graph_channel(struct drm_device *dev)
|
||||
{
|
||||
struct drm_nouveau_private *dev_priv = dev->dev_private;
|
||||
struct nouveau_gpuobj *grctx;
|
||||
uint32_t inst;
|
||||
int i;
|
||||
|
||||
inst = nv_rd32(dev, NV40_PGRAPH_CTXCTL_CUR);
|
||||
if (!(inst & NV40_PGRAPH_CTXCTL_CUR_LOADED))
|
||||
return NULL;
|
||||
inst = (inst & NV40_PGRAPH_CTXCTL_CUR_INSTANCE) << 4;
|
||||
|
||||
for (i = 0; i < dev_priv->engine.fifo.channels; i++) {
|
||||
if (!dev_priv->channels.ptr[i])
|
||||
continue;
|
||||
|
||||
grctx = dev_priv->channels.ptr[i]->engctx[NVOBJ_ENGINE_GR];
|
||||
if (grctx && grctx->pinst == inst)
|
||||
return dev_priv->channels.ptr[i];
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int
|
||||
nv40_graph_transfer_context(struct drm_device *dev, uint32_t inst, int save)
|
||||
{
|
||||
uint32_t old_cp, tv = 1000, tmp;
|
||||
int i;
|
||||
|
||||
old_cp = nv_rd32(dev, NV20_PGRAPH_CHANNEL_CTX_POINTER);
|
||||
nv_wr32(dev, NV20_PGRAPH_CHANNEL_CTX_POINTER, inst);
|
||||
|
||||
tmp = nv_rd32(dev, NV40_PGRAPH_CTXCTL_0310);
|
||||
tmp |= save ? NV40_PGRAPH_CTXCTL_0310_XFER_SAVE :
|
||||
NV40_PGRAPH_CTXCTL_0310_XFER_LOAD;
|
||||
nv_wr32(dev, NV40_PGRAPH_CTXCTL_0310, tmp);
|
||||
|
||||
tmp = nv_rd32(dev, NV40_PGRAPH_CTXCTL_0304);
|
||||
tmp |= NV40_PGRAPH_CTXCTL_0304_XFER_CTX;
|
||||
nv_wr32(dev, NV40_PGRAPH_CTXCTL_0304, tmp);
|
||||
|
||||
nouveau_wait_for_idle(dev);
|
||||
|
||||
for (i = 0; i < tv; i++) {
|
||||
if (nv_rd32(dev, NV40_PGRAPH_CTXCTL_030C) == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
nv_wr32(dev, NV20_PGRAPH_CHANNEL_CTX_POINTER, old_cp);
|
||||
|
||||
if (i == tv) {
|
||||
uint32_t ucstat = nv_rd32(dev, NV40_PGRAPH_CTXCTL_UCODE_STAT);
|
||||
NV_ERROR(dev, "Failed: Instance=0x%08x Save=%d\n", inst, save);
|
||||
NV_ERROR(dev, "IP: 0x%02x, Opcode: 0x%08x\n",
|
||||
ucstat >> NV40_PGRAPH_CTXCTL_UCODE_STAT_IP_SHIFT,
|
||||
ucstat & NV40_PGRAPH_CTXCTL_UCODE_STAT_OP_MASK);
|
||||
NV_ERROR(dev, "0x40030C = 0x%08x\n",
|
||||
nv_rd32(dev, NV40_PGRAPH_CTXCTL_030C));
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
nv40_graph_unload_context(struct drm_device *dev)
|
||||
{
|
||||
uint32_t inst;
|
||||
int ret;
|
||||
|
||||
inst = nv_rd32(dev, NV40_PGRAPH_CTXCTL_CUR);
|
||||
if (!(inst & NV40_PGRAPH_CTXCTL_CUR_LOADED))
|
||||
return 0;
|
||||
inst &= NV40_PGRAPH_CTXCTL_CUR_INSTANCE;
|
||||
|
||||
ret = nv40_graph_transfer_context(dev, inst, 1);
|
||||
|
||||
nv_wr32(dev, NV40_PGRAPH_CTXCTL_CUR, inst);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
nv40_graph_context_new(struct nouveau_channel *chan, int engine)
|
||||
{
|
||||
@ -163,16 +80,16 @@ nv40_graph_context_del(struct nouveau_channel *chan, int engine)
|
||||
struct nouveau_gpuobj *grctx = chan->engctx[engine];
|
||||
struct drm_device *dev = chan->dev;
|
||||
struct drm_nouveau_private *dev_priv = dev->dev_private;
|
||||
u32 inst = 0x01000000 | (grctx->pinst >> 4);
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
|
||||
nv04_graph_fifo_access(dev, false);
|
||||
|
||||
/* Unload the context if it's the currently active one */
|
||||
if (nv40_graph_channel(dev) == chan)
|
||||
nv40_graph_unload_context(dev);
|
||||
|
||||
nv04_graph_fifo_access(dev, true);
|
||||
nv_mask(dev, 0x400720, 0x00000000, 0x00000001);
|
||||
if (nv_rd32(dev, 0x40032c) == inst)
|
||||
nv_mask(dev, 0x40032c, 0x01000000, 0x00000000);
|
||||
if (nv_rd32(dev, 0x400330) == inst)
|
||||
nv_mask(dev, 0x400330, 0x01000000, 0x00000000);
|
||||
nv_mask(dev, 0x400720, 0x00000001, 0x00000001);
|
||||
spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
|
||||
|
||||
/* Free the context resources */
|
||||
@ -431,7 +348,18 @@ nv40_graph_init(struct drm_device *dev, int engine)
|
||||
static int
|
||||
nv40_graph_fini(struct drm_device *dev, int engine)
|
||||
{
|
||||
nv40_graph_unload_context(dev);
|
||||
u32 inst = nv_rd32(dev, 0x40032c);
|
||||
if (inst & 0x01000000) {
|
||||
nv_wr32(dev, 0x400720, 0x00000000);
|
||||
nv_wr32(dev, 0x400784, inst);
|
||||
nv_mask(dev, 0x400310, 0x00000020, 0x00000020);
|
||||
nv_mask(dev, 0x400304, 0x00000001, 0x00000001);
|
||||
if (!nv_wait(dev, 0x400300, 0x00000001, 0x00000000)) {
|
||||
u32 insn = nv_rd32(dev, 0x400308);
|
||||
NV_ERROR(dev, "PGRAPH: ctxprog timeout 0x%08x\n", insn);
|
||||
}
|
||||
nv_mask(dev, 0x40032c, 0x01000000, 0x00000000);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user