Commit a8eaebc6 authored by Ben Skeggs's avatar Ben Skeggs
Browse files

drm/nouveau: remove nouveau_gpuobj_ref completely, replace with sanity


Reviewed-by: default avatarFrancisco Jerez <currojerez@riseup.net>
Signed-off-by: default avatarBen Skeggs <bskeggs@redhat.com>
parent de3a6c0a
......@@ -70,14 +70,8 @@ nouveau_channel_pushbuf_ctxdma_init(struct nouveau_channel *chan)
chan->pushbuf_base = pb->bo.mem.mm_node->start << PAGE_SHIFT;
}
ret = nouveau_gpuobj_ref_add(dev, chan, 0, pushbuf, &chan->pushbuf);
if (ret) {
NV_ERROR(dev, "Error referencing pushbuf ctxdma: %d\n", ret);
if (pushbuf != dev_priv->gart_info.sg_ctxdma)
nouveau_gpuobj_del(dev, &pushbuf);
return ret;
}
nouveau_gpuobj_ref(pushbuf, &chan->pushbuf);
nouveau_gpuobj_ref(NULL, &pushbuf);
return 0;
}
......@@ -308,7 +302,7 @@ nouveau_channel_free(struct nouveau_channel *chan)
spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
/* Release the channel's resources */
nouveau_gpuobj_ref_del(dev, &chan->pushbuf);
nouveau_gpuobj_ref(NULL, &chan->pushbuf);
if (chan->pushbuf_bo) {
nouveau_bo_unmap(chan->pushbuf_bo);
nouveau_bo_unpin(chan->pushbuf_bo);
......
......@@ -28,6 +28,7 @@
#include "drm.h"
#include "nouveau_drv.h"
#include "nouveau_dma.h"
#include "nouveau_ramht.h"
void
nouveau_dma_pre_init(struct nouveau_channel *chan)
......@@ -58,26 +59,27 @@ nouveau_dma_init(struct nouveau_channel *chan)
{
struct drm_device *dev = chan->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_gpuobj *m2mf = NULL;
struct nouveau_gpuobj *nvsw = NULL;
struct nouveau_gpuobj *obj = NULL;
int ret, i;
/* Create NV_MEMORY_TO_MEMORY_FORMAT for buffer moves */
ret = nouveau_gpuobj_gr_new(chan, dev_priv->card_type < NV_50 ?
0x0039 : 0x5039, &m2mf);
0x0039 : 0x5039, &obj);
if (ret)
return ret;
ret = nouveau_gpuobj_ref_add(dev, chan, NvM2MF, m2mf, NULL);
ret = nouveau_ramht_insert(chan, NvM2MF, obj);
nouveau_gpuobj_ref(NULL, &obj);
if (ret)
return ret;
/* Create an NV_SW object for various sync purposes */
ret = nouveau_gpuobj_sw_new(chan, NV_SW, &nvsw);
ret = nouveau_gpuobj_sw_new(chan, NV_SW, &obj);
if (ret)
return ret;
ret = nouveau_gpuobj_ref_add(dev, chan, NvSw, nvsw, NULL);
ret = nouveau_ramht_insert(chan, NvSw, obj);
nouveau_gpuobj_ref(NULL, &obj);
if (ret)
return ret;
......
......@@ -133,7 +133,6 @@ enum nouveau_flags {
#define NVOBJ_ENGINE_DISPLAY 2
#define NVOBJ_ENGINE_INT 0xdeadbeef
#define NVOBJ_FLAG_ALLOW_NO_REFS (1 << 0)
#define NVOBJ_FLAG_ZERO_ALLOC (1 << 1)
#define NVOBJ_FLAG_ZERO_FREE (1 << 2)
#define NVOBJ_FLAG_FAKE (1 << 3)
......@@ -141,7 +140,6 @@ struct nouveau_gpuobj {
struct drm_device *dev;
struct list_head list;
struct nouveau_channel *im_channel;
struct drm_mm_node *im_pramin;
struct nouveau_bo *im_backing;
uint32_t im_backing_start;
......@@ -162,16 +160,6 @@ struct nouveau_gpuobj {
void *priv;
};
struct nouveau_gpuobj_ref {
struct list_head list;
struct nouveau_gpuobj *gpuobj;
uint32_t instance;
struct nouveau_channel *channel;
int handle;
};
struct nouveau_channel {
struct drm_device *dev;
int id;
......@@ -197,33 +185,32 @@ struct nouveau_channel {
} fence;
/* DMA push buffer */
struct nouveau_gpuobj_ref *pushbuf;
struct nouveau_bo *pushbuf_bo;
uint32_t pushbuf_base;
struct nouveau_gpuobj *pushbuf;
struct nouveau_bo *pushbuf_bo;
uint32_t pushbuf_base;
/* Notifier memory */
struct nouveau_bo *notifier_bo;
struct drm_mm notifier_heap;
/* PFIFO context */
struct nouveau_gpuobj_ref *ramfc;
struct nouveau_gpuobj_ref *cache;
struct nouveau_gpuobj *ramfc;
struct nouveau_gpuobj *cache;
/* PGRAPH context */
/* XXX may be merge 2 pointers as private data ??? */
struct nouveau_gpuobj_ref *ramin_grctx;
struct nouveau_gpuobj *ramin_grctx;
void *pgraph_ctx;
/* NV50 VM */
struct nouveau_gpuobj *vm_pd;
struct nouveau_gpuobj_ref *vm_gart_pt;
struct nouveau_gpuobj_ref *vm_vram_pt[NV50_VM_VRAM_NR];
struct nouveau_gpuobj *vm_pd;
struct nouveau_gpuobj *vm_gart_pt;
struct nouveau_gpuobj *vm_vram_pt[NV50_VM_VRAM_NR];
/* Objects */
struct nouveau_gpuobj_ref *ramin; /* Private instmem */
struct drm_mm ramin_heap; /* Private PRAMIN heap */
struct nouveau_gpuobj_ref *ramht; /* Hash table */
struct list_head ramht_refs; /* Objects referenced by RAMHT */
struct nouveau_gpuobj *ramin; /* Private instmem */
struct drm_mm ramin_heap; /* Private PRAMIN heap */
struct nouveau_ramht *ramht; /* Hash table */
/* GPU object info for stuff used in-kernel (mm_enabled) */
uint32_t m2mf_ntfy;
......@@ -301,7 +288,7 @@ struct nouveau_fb_engine {
struct nouveau_fifo_engine {
int channels;
struct nouveau_gpuobj_ref *playlist[2];
struct nouveau_gpuobj *playlist[2];
int cur_playlist;
int (*init)(struct drm_device *);
......@@ -339,7 +326,7 @@ struct nouveau_pgraph_engine {
int grctx_size;
/* NV2x/NV3x context table (0x400780) */
struct nouveau_gpuobj_ref *ctx_table;
struct nouveau_gpuobj *ctx_table;
int (*init)(struct drm_device *);
void (*takedown)(struct drm_device *);
......@@ -555,7 +542,7 @@ struct drm_nouveau_private {
spinlock_t context_switch_lock;
/* RAMIN configuration, RAMFC, RAMHT and RAMRO offsets */
struct nouveau_gpuobj *ramht;
struct nouveau_ramht *ramht;
uint32_t ramin_rsvd_vram;
uint32_t ramht_offset;
uint32_t ramht_size;
......@@ -764,24 +751,12 @@ extern void nouveau_gpuobj_channel_takedown(struct nouveau_channel *);
extern int nouveau_gpuobj_new(struct drm_device *, struct nouveau_channel *,
uint32_t size, int align, uint32_t flags,
struct nouveau_gpuobj **);
extern int nouveau_gpuobj_del(struct drm_device *, struct nouveau_gpuobj **);
extern int nouveau_gpuobj_ref_add(struct drm_device *, struct nouveau_channel *,
uint32_t handle, struct nouveau_gpuobj *,
struct nouveau_gpuobj_ref **);
extern int nouveau_gpuobj_ref_del(struct drm_device *,
struct nouveau_gpuobj_ref **);
extern int nouveau_gpuobj_ref_find(struct nouveau_channel *, uint32_t handle,
struct nouveau_gpuobj_ref **ref_ret);
extern int nouveau_gpuobj_new_ref(struct drm_device *,
struct nouveau_channel *alloc_chan,
struct nouveau_channel *ref_chan,
uint32_t handle, uint32_t size, int align,
uint32_t flags, struct nouveau_gpuobj_ref **);
extern void nouveau_gpuobj_ref(struct nouveau_gpuobj *,
struct nouveau_gpuobj **);
extern int nouveau_gpuobj_new_fake(struct drm_device *,
uint32_t p_offset, uint32_t b_offset,
uint32_t size, uint32_t flags,
struct nouveau_gpuobj **,
struct nouveau_gpuobj_ref**);
struct nouveau_gpuobj **);
extern int nouveau_gpuobj_dma_new(struct nouveau_channel *, int class,
uint64_t offset, uint64_t size, int access,
int target, struct nouveau_gpuobj **);
......
......@@ -35,6 +35,7 @@
#include "nouveau_drm.h"
#include "nouveau_drv.h"
#include "nouveau_reg.h"
#include "nouveau_ramht.h"
#include <linux/ratelimit.h>
/* needed for hotplug irq */
......@@ -106,15 +107,16 @@ nouveau_fifo_swmthd(struct nouveau_channel *chan, uint32_t addr, uint32_t data)
const int mthd = addr & 0x1ffc;
if (mthd == 0x0000) {
struct nouveau_gpuobj_ref *ref = NULL;
struct nouveau_gpuobj *gpuobj;
if (nouveau_gpuobj_ref_find(chan, data, &ref))
gpuobj = nouveau_ramht_find(chan, data);
if (!gpuobj)
return false;
if (ref->gpuobj->engine != NVOBJ_ENGINE_SW)
if (gpuobj->engine != NVOBJ_ENGINE_SW)
return false;
chan->sw_subchannel[subc] = ref->gpuobj->class;
chan->sw_subchannel[subc] = gpuobj->class;
nv_wr32(dev, NV04_PFIFO_CACHE1_ENGINE, nv_rd32(dev,
NV04_PFIFO_CACHE1_ENGINE) & ~(0xf << subc * 4));
return true;
......@@ -357,7 +359,7 @@ nouveau_graph_chid_from_grctx(struct drm_device *dev)
if (!chan || !chan->ramin_grctx)
continue;
if (inst == chan->ramin_grctx->instance)
if (inst == chan->ramin_grctx->pinst)
break;
}
} else {
......@@ -369,7 +371,7 @@ nouveau_graph_chid_from_grctx(struct drm_device *dev)
if (!chan || !chan->ramin)
continue;
if (inst == chan->ramin->instance)
if (inst == chan->ramin->vinst)
break;
}
}
......@@ -625,7 +627,7 @@ nv50_pfb_vm_trap(struct drm_device *dev, int display, const char *name)
if (!chan || !chan->ramin)
continue;
if (trap[1] == chan->ramin->instance >> 12)
if (trap[1] == chan->ramin->vinst >> 12)
break;
}
NV_INFO(dev, "%s - VM: Trapped %s at %02x%04x%04x status %08x %08x channel %d\n",
......
......@@ -28,6 +28,7 @@
#include "drmP.h"
#include "drm.h"
#include "nouveau_drv.h"
#include "nouveau_ramht.h"
int
nouveau_notifier_init_channel(struct nouveau_channel *chan)
......@@ -146,11 +147,11 @@ nouveau_notifier_alloc(struct nouveau_channel *chan, uint32_t handle,
nobj->dtor = nouveau_notifier_gpuobj_dtor;
nobj->priv = mem;
ret = nouveau_gpuobj_ref_add(dev, chan, handle, nobj, NULL);
ret = nouveau_ramht_insert(chan, handle, nobj);
nouveau_gpuobj_ref(NULL, &nobj);
if (ret) {
nouveau_gpuobj_del(dev, &nobj);
drm_mm_put_block(mem);
NV_ERROR(dev, "Error referencing notifier ctxdma: %d\n", ret);
NV_ERROR(dev, "Error adding notifier to ramht: %d\n", ret);
return ret;
}
......
......@@ -90,7 +90,7 @@ nouveau_gpuobj_new(struct drm_device *dev, struct nouveau_channel *chan,
NV_DEBUG(dev, "gpuobj %p\n", gpuobj);
gpuobj->dev = dev;
gpuobj->flags = flags;
gpuobj->im_channel = chan;
gpuobj->refcount = 1;
list_add_tail(&gpuobj->list, &dev_priv->gpuobj_list);
......@@ -108,7 +108,7 @@ nouveau_gpuobj_new(struct drm_device *dev, struct nouveau_channel *chan,
ret = engine->instmem.populate(dev, gpuobj, &size);
if (ret) {
nouveau_gpuobj_del(dev, &gpuobj);
nouveau_gpuobj_ref(NULL, &gpuobj);
return ret;
}
}
......@@ -119,14 +119,14 @@ nouveau_gpuobj_new(struct drm_device *dev, struct nouveau_channel *chan,
gpuobj->im_pramin = drm_mm_get_block(gpuobj->im_pramin, size, align);
if (!gpuobj->im_pramin) {
nouveau_gpuobj_del(dev, &gpuobj);
nouveau_gpuobj_ref(NULL, &gpuobj);
return -ENOMEM;
}
if (!chan) {
ret = engine->instmem.bind(dev, gpuobj);
if (ret) {
nouveau_gpuobj_del(dev, &gpuobj);
nouveau_gpuobj_ref(NULL, &gpuobj);
return ret;
}
}
......@@ -134,13 +134,13 @@ nouveau_gpuobj_new(struct drm_device *dev, struct nouveau_channel *chan,
/* calculate the various different addresses for the object */
if (chan) {
gpuobj->pinst = gpuobj->im_pramin->start +
chan->ramin->gpuobj->im_pramin->start;
chan->ramin->im_pramin->start;
if (dev_priv->card_type < NV_50) {
gpuobj->cinst = gpuobj->pinst;
} else {
gpuobj->cinst = gpuobj->im_pramin->start;
gpuobj->vinst = gpuobj->im_pramin->start +
chan->ramin->gpuobj->im_backing_start;
chan->ramin->im_backing_start;
}
} else {
gpuobj->pinst = gpuobj->im_pramin->start;
......@@ -156,6 +156,7 @@ nouveau_gpuobj_new(struct drm_device *dev, struct nouveau_channel *chan,
engine->instmem.flush(dev);
}
*gpuobj_ret = gpuobj;
return 0;
}
......@@ -176,20 +177,23 @@ int
nouveau_gpuobj_init(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_gpuobj *ramht = NULL;
int ret;
NV_DEBUG(dev, "\n");
if (dev_priv->card_type < NV_50) {
ret = nouveau_gpuobj_new_fake(dev,
dev_priv->ramht_offset, ~0, dev_priv->ramht_size,
NVOBJ_FLAG_ZERO_ALLOC | NVOBJ_FLAG_ALLOW_NO_REFS,
&dev_priv->ramht, NULL);
if (ret)
return ret;
}
if (dev_priv->card_type >= NV_50)
return 0;
return 0;
ret = nouveau_gpuobj_new_fake(dev, dev_priv->ramht_offset, ~0,
dev_priv->ramht_size,
NVOBJ_FLAG_ZERO_ALLOC, &ramht);
if (ret)
return ret;
ret = nouveau_ramht_new(dev, ramht, &dev_priv->ramht);
nouveau_gpuobj_ref(NULL, &ramht);
return ret;
}
void
......@@ -199,7 +203,7 @@ nouveau_gpuobj_takedown(struct drm_device *dev)
NV_DEBUG(dev, "\n");
nouveau_gpuobj_del(dev, &dev_priv->ramht);
nouveau_ramht_ref(NULL, &dev_priv->ramht, NULL);
}
void
......@@ -216,29 +220,21 @@ nouveau_gpuobj_late_takedown(struct drm_device *dev)
NV_ERROR(dev, "gpuobj %p still exists at takedown, refs=%d\n",
gpuobj, gpuobj->refcount);
gpuobj->refcount = 0;
nouveau_gpuobj_del(dev, &gpuobj);
gpuobj->refcount = 1;
nouveau_gpuobj_ref(NULL, &gpuobj);
}
}
int
nouveau_gpuobj_del(struct drm_device *dev, struct nouveau_gpuobj **pgpuobj)
static int
nouveau_gpuobj_del(struct nouveau_gpuobj *gpuobj)
{
struct drm_device *dev = gpuobj->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_engine *engine = &dev_priv->engine;
struct nouveau_gpuobj *gpuobj;
int i;
NV_DEBUG(dev, "gpuobj %p\n", pgpuobj ? *pgpuobj : NULL);
if (!dev_priv || !pgpuobj || !(*pgpuobj))
return -EINVAL;
gpuobj = *pgpuobj;
if (gpuobj->refcount != 0) {
NV_ERROR(dev, "gpuobj refcount is %d\n", gpuobj->refcount);
return -EINVAL;
}
NV_DEBUG(dev, "gpuobj %p\n", gpuobj);
if (gpuobj->im_pramin && (gpuobj->flags & NVOBJ_FLAG_ZERO_FREE)) {
for (i = 0; i < gpuobj->im_pramin->size; i += 4)
......@@ -261,181 +257,26 @@ nouveau_gpuobj_del(struct drm_device *dev, struct nouveau_gpuobj **pgpuobj)
list_del(&gpuobj->list);
*pgpuobj = NULL;
kfree(gpuobj);
return 0;
}
static int
nouveau_gpuobj_instance_get(struct drm_device *dev,
struct nouveau_channel *chan,
struct nouveau_gpuobj *gpuobj, uint32_t *inst)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_gpuobj *cpramin;
/* <NV50 use PRAMIN address everywhere */
if (dev_priv->card_type < NV_50) {
*inst = gpuobj->im_pramin->start;
if (gpuobj->im_channel) {
cpramin = gpuobj->im_channel->ramin->gpuobj;
*inst += cpramin->im_pramin->start;
}
return 0;
}
/* NV50 channel-local instance */
if (chan) {
*inst = gpuobj->im_pramin->start;
return 0;
}
/* NV50 global (VRAM) instance */
if (!gpuobj->im_channel) {
/* ...from global heap */
if (!gpuobj->im_backing) {
NV_ERROR(dev, "AII, no VRAM backing gpuobj\n");
return -EINVAL;
}
*inst = gpuobj->im_backing_start;
return 0;
} else {
/* ...from local heap */
cpramin = gpuobj->im_channel->ramin->gpuobj;
*inst = cpramin->im_backing_start + gpuobj->im_pramin->start;
return 0;
}
return -EINVAL;
}
int
nouveau_gpuobj_ref_add(struct drm_device *dev, struct nouveau_channel *chan,
uint32_t handle, struct nouveau_gpuobj *gpuobj,
struct nouveau_gpuobj_ref **ref_ret)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_gpuobj_ref *ref;
uint32_t instance;
int ret;
NV_DEBUG(dev, "ch%d h=0x%08x gpuobj=%p\n",
chan ? chan->id : -1, handle, gpuobj);
if (!dev_priv || !gpuobj || (ref_ret && *ref_ret != NULL))
return -EINVAL;
if (!chan && !ref_ret)
return -EINVAL;
if (gpuobj->engine == NVOBJ_ENGINE_SW && !gpuobj->im_pramin) {
/* sw object */
instance = 0x40;
} else {
ret = nouveau_gpuobj_instance_get(dev, chan, gpuobj, &instance);
if (ret)
return ret;
}
ref = kzalloc(sizeof(*ref), GFP_KERNEL);
if (!ref)
return -ENOMEM;
INIT_LIST_HEAD(&ref->list);
ref->gpuobj = gpuobj;
ref->channel = chan;
ref->instance = instance;
if (!ref_ret) {
ref->handle = handle;
ret = nouveau_ramht_insert(dev, ref);
if (ret) {
kfree(ref);
return ret;
}
} else {
ref->handle = ~0;
*ref_ret = ref;
}
ref->gpuobj->refcount++;
return 0;
}
int nouveau_gpuobj_ref_del(struct drm_device *dev, struct nouveau_gpuobj_ref **pref)
{
struct nouveau_gpuobj_ref *ref;
NV_DEBUG(dev, "ref %p\n", pref ? *pref : NULL);
if (!dev || !pref || *pref == NULL)
return -EINVAL;
ref = *pref;
if (ref->handle != ~0)
nouveau_ramht_remove(dev, ref);
if (ref->gpuobj) {
ref->gpuobj->refcount--;
if (ref->gpuobj->refcount == 0) {
if (!(ref->gpuobj->flags & NVOBJ_FLAG_ALLOW_NO_REFS))
nouveau_gpuobj_del(dev, &ref->gpuobj);
}
}
*pref = NULL;
kfree(ref);
return 0;
}
int
nouveau_gpuobj_new_ref(struct drm_device *dev,
struct nouveau_channel *oc, struct nouveau_channel *rc,
uint32_t handle, uint32_t size, int align,
uint32_t flags, struct nouveau_gpuobj_ref **ref)
void
nouveau_gpuobj_ref(struct nouveau_gpuobj *ref, struct nouveau_gpuobj **ptr)
{
struct nouveau_gpuobj *gpuobj = NULL;
int ret;
if (ref)
ref->refcount++;
ret = nouveau_gpuobj_new(dev, oc, size, align, flags, &gpuobj);
if (ret)
return ret;
if (*ptr && --(*ptr)->refcount == 0)
nouveau_gpuobj_del(*ptr);
ret = nouveau_gpuobj_ref_add(dev, rc, handle, gpuobj, ref);
if (ret) {
nouveau_gpuobj_del(dev, &gpuobj);
return ret;
}
return 0;
}
int
nouveau_gpuobj_ref_find(struct nouveau_channel *chan, uint32_t handle,
struct nouveau_gpuobj_ref **ref_ret)
{
struct nouveau_gpuobj_ref *ref;
struct list_head *entry, *tmp;
list_for_each_safe(entry, tmp, &chan->ramht_refs) {
ref = list_entry(entry, struct nouveau_gpuobj_ref, list);
if (ref->handle == handle) {
if (ref_ret)
*ref_ret = ref;
return 0;
}
}
return -EINVAL;
*ptr = ref;
}
int
nouveau_gpuobj_new_fake(struct drm_device *dev, uint32_t p_offset,
uint32_t b_offset, uint32_t size,
uint32_t flags, struct nouveau_gpuobj **pgpuobj,
struct nouveau_gpuobj_ref **pref)
uint32_t flags, struct nouveau_gpuobj **pgpuobj)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_gpuobj *gpuobj = NULL;
......@@ -450,8 +291,8 @@ nouveau_gpuobj_new_fake(struct drm_device *dev, uint32_t p_offset,
return -ENOMEM;
NV_DEBUG(dev, "gpuobj %p\n", gpuobj);
gpuobj->dev = dev;
gpuobj->im_channel = NULL;
gpuobj->flags = flags | NVOBJ_FLAG_FAKE;
gpuobj->refcount = 1;