nouveau: Nuke DMA_OBJECT_INIT ioctl (bumps interface to 0.0.7)

For various reasons, this ioctl was a bad idea.

At channel creation we now automatically create DMA objects covering
available VRAM and GART memory, where the client used to do this themselves.

However, there is still a need to be able to create DMA objects pointing at
specific areas of memory (ie. notifiers).  Each channel is now allocated a
small amount of memory from which a client can suballocate things (such as
notifiers), and have a DMA object created which covers the suballocated area.
The NOTIFIER_ALLOC ioctl exposes this functionality.
main
Ben Skeggs 2007-06-24 19:03:35 +10:00
parent 4f2dd78ff3
commit 695599f18d
9 changed files with 321 additions and 146 deletions

View File

@ -21,7 +21,7 @@ i810-objs := i810_drv.o i810_dma.o
i915-objs := i915_drv.o i915_dma.o i915_irq.o i915_mem.o i915_fence.o \
i915_buffer.o
nouveau-objs := nouveau_drv.o nouveau_state.o nouveau_fifo.o nouveau_mem.o \
nouveau_object.o nouveau_irq.o \
nouveau_object.o nouveau_irq.o nouveau_notifier.o \
nv04_timer.o \
nv04_mc.o nv40_mc.o \
nv04_fb.o nv10_fb.o nv40_fb.o \

View File

@ -0,0 +1 @@
../shared-core/nouveau_notifier.c

View File

@ -25,9 +25,12 @@
#ifndef __NOUVEAU_DRM_H__
#define __NOUVEAU_DRM_H__
#define NOUVEAU_DRM_HEADER_PATCHLEVEL 6
#define NOUVEAU_DRM_HEADER_PATCHLEVEL 7
typedef struct drm_nouveau_fifo_alloc {
uint32_t fb_ctxdma_handle;
uint32_t tt_ctxdma_handle;
int channel;
uint32_t put_base;
/* FIFO control regs */
@ -36,29 +39,30 @@ typedef struct drm_nouveau_fifo_alloc {
/* DMA command buffer */
drm_handle_t cmdbuf;
int cmdbuf_size;
/* Notifier memory */
drm_handle_t notifier;
int notifier_size;
}
drm_nouveau_fifo_alloc_t;
typedef struct drm_nouveau_object_init {
typedef struct drm_nouveau_grobj_alloc {
int channel;
uint32_t handle;
int class;
}
drm_nouveau_object_init_t;
drm_nouveau_grobj_alloc_t;
#define NOUVEAU_MEM_ACCESS_RO 1
#define NOUVEAU_MEM_ACCESS_WO 2
#define NOUVEAU_MEM_ACCESS_RW 3
typedef struct drm_nouveau_dma_object_init {
typedef struct drm_nouveau_notifier_alloc {
int channel;
uint32_t handle;
int class;
int access;
int target;
int count;
uint32_t offset;
int size;
}
drm_nouveau_dma_object_init_t;
drm_nouveau_notifier_alloc_t;
#define NOUVEAU_MEM_FB 0x00000001
#define NOUVEAU_MEM_AGP 0x00000002
@ -68,7 +72,7 @@ drm_nouveau_dma_object_init_t;
#define NOUVEAU_MEM_USER_BACKED 0x00000020
#define NOUVEAU_MEM_MAPPED 0x00000040
#define NOUVEAU_MEM_INSTANCE 0x00000080 /* internal */
#define NOUVEAU_MEM_NOTIFIER 0x00000100 /* internal */
typedef struct drm_nouveau_mem_alloc {
int flags;
int alignment;
@ -141,8 +145,8 @@ typedef struct drm_nouveau_sarea {
drm_nouveau_sarea_t;
#define DRM_NOUVEAU_FIFO_ALLOC 0x00
#define DRM_NOUVEAU_OBJECT_INIT 0x01
#define DRM_NOUVEAU_DMA_OBJECT_INIT 0x02
#define DRM_NOUVEAU_GROBJ_ALLOC 0x01
#define DRM_NOUVEAU_NOTIFIER_ALLOC 0x02
#define DRM_NOUVEAU_MEM_ALLOC 0x03
#define DRM_NOUVEAU_MEM_FREE 0x04
#define DRM_NOUVEAU_GETPARAM 0x05

View File

@ -34,7 +34,7 @@
#define DRIVER_MAJOR 0
#define DRIVER_MINOR 0
#define DRIVER_PATCHLEVEL 6
#define DRIVER_PATCHLEVEL 7
#define NOUVEAU_FAMILY 0x0000FFFF
#define NOUVEAU_FLAGS 0xFFFF0000
@ -84,6 +84,10 @@ struct nouveau_fifo
struct mem_block *cmdbuf_mem;
struct nouveau_object *cmdbuf_obj;
uint32_t pushbuf_base;
/* notifier memory */
struct mem_block *notifier_block;
struct mem_block *notifier_heap;
drm_local_map_t *notifier_map;
/* PGRAPH context, for cards that keep it in RAMIN */
struct mem_block *ramin_grctx;
/* objects belonging to this fifo */
@ -197,6 +201,12 @@ extern void nouveau_wait_for_idle(struct drm_device *dev);
extern int nouveau_ioctl_card_init(DRM_IOCTL_ARGS);
/* nouveau_mem.c */
extern int nouveau_mem_init_heap(struct mem_block **,
uint64_t start, uint64_t size);
extern struct mem_block *nouveau_mem_alloc_block(struct mem_block *,
uint64_t size, int align2,
DRMFILE);
extern void nouveau_mem_free_block(struct mem_block *);
extern uint64_t nouveau_mem_fb_amount(struct drm_device *dev);
extern void nouveau_mem_release(DRMFILE filp, struct mem_block *heap);
extern int nouveau_ioctl_mem_alloc(DRM_IOCTL_ARGS);
@ -216,6 +226,13 @@ extern void nouveau_instmem_w32(drm_nouveau_private_t *dev_priv,
struct mem_block *mem, int index,
uint32_t val);
/* nouveau_notifier.c */
extern int nouveau_notifier_init_channel(drm_device_t *, int channel, DRMFILE);
extern void nouveau_notifier_takedown_channel(drm_device_t *, int channel);
extern int nouveau_notifier_alloc(drm_device_t *, int channel,
uint32_t handle, int cout, uint32_t *offset);
extern int nouveau_ioctl_notifier_alloc(DRM_IOCTL_ARGS);
/* nouveau_fifo.c */
extern int nouveau_fifo_init(drm_device_t *dev);
extern int nouveau_fifo_number(drm_device_t *dev);
@ -225,7 +242,13 @@ extern int nouveau_fifo_owner(drm_device_t *dev, DRMFILE filp, int channel);
extern void nouveau_fifo_free(drm_device_t *dev, int channel);
/* nouveau_object.c */
extern int nouveau_object_init_channel(drm_device_t *, int channel,
uint32_t vram_handle,
uint32_t tt_handle);
extern void nouveau_object_takedown_channel(drm_device_t *dev, int channel);
extern void nouveau_object_cleanup(drm_device_t *dev, int channel);
extern int nouveau_ht_object_insert(drm_device_t *, int channel,
uint32_t handle, struct nouveau_object *);
extern struct nouveau_object *
nouveau_object_gr_create(drm_device_t *dev, int channel, int class);
extern struct nouveau_object *
@ -233,8 +256,7 @@ nouveau_object_dma_create(drm_device_t *dev, int channel, int class,
uint32_t offset, uint32_t size,
int access, int target);
extern void nouveau_object_free(drm_device_t *dev, struct nouveau_object *obj);
extern int nouveau_ioctl_object_init(DRM_IOCTL_ARGS);
extern int nouveau_ioctl_dma_object_init(DRM_IOCTL_ARGS);
extern int nouveau_ioctl_grobj_alloc(DRM_IOCTL_ARGS);
extern uint32_t nouveau_chip_instance_get(drm_device_t *dev, struct mem_block *mem);
/* nouveau_irq.c */

View File

@ -241,7 +241,8 @@ nouveau_fifo_cmdbuf_alloc(struct drm_device *dev, int channel)
}
/* allocates and initializes a fifo for user space consumption */
static int nouveau_fifo_alloc(drm_device_t* dev, int *chan_ret, DRMFILE filp)
int nouveau_fifo_alloc(drm_device_t* dev, int *chan_ret, DRMFILE filp,
uint32_t vram_handle, uint32_t tt_handle)
{
int ret;
drm_nouveau_private_t *dev_priv = dev->dev_private;
@ -282,6 +283,20 @@ static int nouveau_fifo_alloc(drm_device_t* dev, int *chan_ret, DRMFILE filp)
return ret;
}
/* Setup channel's default objects */
ret = nouveau_object_init_channel(dev, channel, vram_handle, tt_handle);
if (ret) {
nouveau_fifo_free(dev, channel);
return ret;
}
/* Allocate space for per-channel fixed notifier memory */
ret = nouveau_notifier_init_channel(dev, channel, filp);
if (ret) {
nouveau_fifo_free(dev, channel);
return ret;
}
nouveau_wait_for_idle(dev);
/* disable the fifo caches */
@ -370,6 +385,8 @@ void nouveau_fifo_free(drm_device_t* dev, int channel)
if (chan->cmdbuf_mem)
nouveau_mem_free(dev, chan->cmdbuf_mem);
nouveau_notifier_takedown_channel(dev, channel);
/* Destroy objects belonging to the channel */
nouveau_object_cleanup(dev, channel);
@ -408,30 +425,42 @@ static int nouveau_ioctl_fifo_alloc(DRM_IOCTL_ARGS)
{
DRM_DEVICE;
drm_nouveau_private_t *dev_priv = dev->dev_private;
struct nouveau_fifo *chan;
drm_nouveau_fifo_alloc_t init;
int res;
DRM_COPY_FROM_USER_IOCTL(init, (drm_nouveau_fifo_alloc_t __user *) data,
sizeof(init));
res = nouveau_fifo_alloc(dev, &init.channel, filp);
res = nouveau_fifo_alloc(dev, &init.channel, filp,
init.fb_ctxdma_handle,
init.tt_ctxdma_handle);
if (res)
return res;
chan = &dev_priv->fifos[init.channel];
init.put_base = dev_priv->fifos[init.channel].pushbuf_base;
init.put_base = chan->pushbuf_base;
/* make the fifo available to user space */
/* first, the fifo control regs */
init.ctrl = dev_priv->mmio->offset + NV03_FIFO_REGS(init.channel);
init.ctrl_size = NV03_FIFO_REGS_SIZE;
res = drm_addmap(dev, init.ctrl, init.ctrl_size, _DRM_REGISTERS,
0, &dev_priv->fifos[init.channel].regs);
0, &chan->regs);
if (res != 0)
return res;
/* pass back FIFO map info to the caller */
init.cmdbuf = dev_priv->fifos[init.channel].cmdbuf_mem->start;
init.cmdbuf_size = dev_priv->fifos[init.channel].cmdbuf_mem->size;
init.cmdbuf = chan->cmdbuf_mem->start;
init.cmdbuf_size = chan->cmdbuf_mem->size;
/* and the notifier block */
init.notifier = chan->notifier_block->start;
init.notifier_size = chan->notifier_block->size;
res = drm_addmap(dev, init.notifier, init.notifier_size, _DRM_REGISTERS,
0, &chan->notifier_map);
if (res != 0)
return res;
DRM_COPY_TO_USER_IOCTL((drm_nouveau_fifo_alloc_t __user *)data,
init, sizeof(init));
@ -444,8 +473,8 @@ static int nouveau_ioctl_fifo_alloc(DRM_IOCTL_ARGS)
drm_ioctl_desc_t nouveau_ioctls[] = {
[DRM_IOCTL_NR(DRM_NOUVEAU_FIFO_ALLOC)] = {nouveau_ioctl_fifo_alloc, DRM_AUTH},
[DRM_IOCTL_NR(DRM_NOUVEAU_OBJECT_INIT)] = {nouveau_ioctl_object_init, DRM_AUTH},
[DRM_IOCTL_NR(DRM_NOUVEAU_DMA_OBJECT_INIT)] = {nouveau_ioctl_dma_object_init, DRM_AUTH},
[DRM_IOCTL_NR(DRM_NOUVEAU_GROBJ_ALLOC)] = {nouveau_ioctl_grobj_alloc, DRM_AUTH},
[DRM_IOCTL_NR(DRM_NOUVEAU_NOTIFIER_ALLOC)] = {nouveau_ioctl_notifier_alloc, DRM_AUTH},
[DRM_IOCTL_NR(DRM_NOUVEAU_MEM_ALLOC)] = {nouveau_ioctl_mem_alloc, DRM_AUTH},
[DRM_IOCTL_NR(DRM_NOUVEAU_MEM_FREE)] = {nouveau_ioctl_mem_free, DRM_AUTH},
[DRM_IOCTL_NR(DRM_NOUVEAU_GETPARAM)] = {nouveau_ioctl_getparam, DRM_AUTH},

View File

@ -77,8 +77,8 @@ out:
return p;
}
static struct mem_block *alloc_block(struct mem_block *heap, uint64_t size,
int align2, DRMFILE filp)
struct mem_block *nouveau_mem_alloc_block(struct mem_block *heap, uint64_t size,
int align2, DRMFILE filp)
{
struct mem_block *p;
uint64_t mask = (1 << align2) - 1;
@ -106,7 +106,7 @@ static struct mem_block *find_block(struct mem_block *heap, uint64_t start)
return NULL;
}
static void free_block(struct mem_block *p)
void nouveau_mem_free_block(struct mem_block *p)
{
p->filp = NULL;
@ -132,7 +132,8 @@ static void free_block(struct mem_block *p)
/* Initialize. How to check for an uninitialized heap?
*/
static int init_heap(struct mem_block **heap, uint64_t start, uint64_t size)
int nouveau_mem_init_heap(struct mem_block **heap, uint64_t start,
uint64_t size)
{
struct mem_block *blocks = drm_alloc(sizeof(*blocks), DRM_MEM_BUFS);
@ -331,7 +332,9 @@ int nouveau_mem_init(struct drm_device *dev)
goto no_agp;
}
if (init_heap(&dev_priv->agp_heap, info.aperture_base, info.aperture_size))
if (nouveau_mem_init_heap(&dev_priv->agp_heap,
info.aperture_base,
info.aperture_size))
goto no_agp;
dev_priv->agp_phys = info.aperture_base;
@ -357,12 +360,19 @@ no_agp:
if (fb_size>256*1024*1024) {
/* On cards with > 256Mb, you can't map everything.
* So we create a second FB heap for that type of memory */
if (init_heap(&dev_priv->fb_heap, drm_get_resource_start(dev,1), 256*1024*1024))
if (nouveau_mem_init_heap(&dev_priv->fb_heap,
drm_get_resource_start(dev,1),
256*1024*1024))
return DRM_ERR(ENOMEM);
if (init_heap(&dev_priv->fb_nomap_heap, drm_get_resource_start(dev,1)+256*1024*1024, fb_size-256*1024*1024))
if (nouveau_mem_init_heap(&dev_priv->fb_nomap_heap,
drm_get_resource_start(dev,1) +
256*1024*1024,
fb_size-256*1024*1024))
return DRM_ERR(ENOMEM);
} else {
if (init_heap(&dev_priv->fb_heap, drm_get_resource_start(dev,1), fb_size))
if (nouveau_mem_init_heap(&dev_priv->fb_heap,
drm_get_resource_start(dev,1),
fb_size))
return DRM_ERR(ENOMEM);
dev_priv->fb_nomap_heap=NULL;
}
@ -397,21 +407,25 @@ struct mem_block* nouveau_mem_alloc(struct drm_device *dev, int alignment, uint6
if (flags&NOUVEAU_MEM_AGP) {
type=NOUVEAU_MEM_AGP;
block = alloc_block(dev_priv->agp_heap, size, alignment, filp);
block = nouveau_mem_alloc_block(dev_priv->agp_heap, size,
alignment, filp);
if (block) goto alloc_ok;
}
if (flags&(NOUVEAU_MEM_FB|NOUVEAU_MEM_FB_ACCEPTABLE)) {
type=NOUVEAU_MEM_FB;
if (!(flags&NOUVEAU_MEM_MAPPED)) {
block = alloc_block(dev_priv->fb_nomap_heap, size, alignment, filp);
block = nouveau_mem_alloc_block(dev_priv->fb_nomap_heap,
size, alignment, filp);
if (block) goto alloc_ok;
}
block = alloc_block(dev_priv->fb_heap, size, alignment, filp);
block = nouveau_mem_alloc_block(dev_priv->fb_heap, size,
alignment, filp);
if (block) goto alloc_ok;
}
if (flags&NOUVEAU_MEM_AGP_ACCEPTABLE) {
type=NOUVEAU_MEM_AGP;
block = alloc_block(dev_priv->agp_heap, size, alignment, filp);
block = nouveau_mem_alloc_block(dev_priv->agp_heap, size,
alignment, filp);
if (block) goto alloc_ok;
}
@ -432,7 +446,7 @@ alloc_ok:
ret = drm_addmap(dev, block->start, block->size,
_DRM_FRAME_BUFFER, 0, &block->map);
if (ret) {
free_block(block);
nouveau_mem_free_block(block);
return NULL;
}
}
@ -446,7 +460,7 @@ void nouveau_mem_free(struct drm_device* dev, struct mem_block* block)
DRM_INFO("freeing 0x%llx\n", block->start);
if (block->flags&NOUVEAU_MEM_MAPPED)
drm_rmmap(dev, block->map);
free_block(block);
nouveau_mem_free_block(block);
}
static void
@ -549,8 +563,8 @@ int nouveau_instmem_init(struct drm_device *dev)
* the space that was reserved for RAMHT/FC/RO.
*/
offset = dev_priv->ramfc_offset + dev_priv->ramfc_size;
ret = init_heap(&dev_priv->ramin_heap,
offset, dev_priv->ramin_size - offset);
ret = nouveau_mem_init_heap(&dev_priv->ramin_heap,
offset, dev_priv->ramin_size - offset);
if (ret) {
dev_priv->ramin_heap = NULL;
DRM_ERROR("Failed to init RAMIN heap\n");
@ -570,7 +584,8 @@ struct mem_block *nouveau_instmem_alloc(struct drm_device *dev,
return NULL;
}
block = alloc_block(dev_priv->ramin_heap, size, align, (DRMFILE)-2);
block = nouveau_mem_alloc_block(dev_priv->ramin_heap, size, align,
(DRMFILE)-2);
if (block) {
block->flags = NOUVEAU_MEM_INSTANCE;
DRM_DEBUG("instance(size=%d, align=%d) alloc'd at 0x%08x\n",
@ -583,7 +598,7 @@ struct mem_block *nouveau_instmem_alloc(struct drm_device *dev,
void nouveau_instmem_free(struct drm_device *dev, struct mem_block *block)
{
if (dev && block) {
free_block(block);
nouveau_mem_free_block(block);
}
}

View File

@ -0,0 +1,154 @@
/*
* Copyright (C) 2007 Ben Skeggs.
*
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial
* portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
#include "drmP.h"
#include "drm.h"
#include "nouveau_drv.h"
int
nouveau_notifier_init_channel(drm_device_t *dev, int channel, DRMFILE filp)
{
drm_nouveau_private_t *dev_priv = dev->dev_private;
struct nouveau_fifo *chan = &dev_priv->fifos[channel];
int flags, ret;
/*TODO: PCI notifier blocks */
if (dev_priv->agp_heap)
flags = NOUVEAU_MEM_AGP | NOUVEAU_MEM_FB_ACCEPTABLE;
else
flags = NOUVEAU_MEM_FB;
chan->notifier_block = nouveau_mem_alloc(dev, 0, PAGE_SIZE, flags,filp);
if (!chan->notifier_block)
return DRM_ERR(ENOMEM);
ret = nouveau_mem_init_heap(&chan->notifier_heap,
0, chan->notifier_block->size);
if (ret)
return ret;
return 0;
}
void
nouveau_notifier_takedown_channel(drm_device_t *dev, int channel)
{
drm_nouveau_private_t *dev_priv = dev->dev_private;
struct nouveau_fifo *chan = &dev_priv->fifos[channel];
if (chan->notifier_block) {
nouveau_mem_free(dev, chan->notifier_block);
chan->notifier_block = NULL;
}
/*XXX: heap destroy */
}
int
nouveau_notifier_alloc(drm_device_t *dev, int channel, uint32_t handle,
int count, uint32_t *b_offset)
{
drm_nouveau_private_t *dev_priv = dev->dev_private;
struct nouveau_fifo *chan = &dev_priv->fifos[channel];
struct nouveau_object *obj;
struct mem_block *mem;
uint32_t offset;
int target;
if (!chan->notifier_heap) {
DRM_ERROR("Channel %d doesn't have a notifier heap!\n",
channel);
return DRM_ERR(EINVAL);
}
mem = nouveau_mem_alloc_block(chan->notifier_heap, 32, 0, chan->filp);
if (!mem) {
DRM_ERROR("Channel %d notifier block full\n", channel);
return DRM_ERR(ENOMEM);
}
mem->flags = NOUVEAU_MEM_NOTIFIER;
offset = chan->notifier_block->start + mem->start;
if (chan->notifier_block->flags & NOUVEAU_MEM_FB) {
offset -= drm_get_resource_start(dev, 1);
target = NV_DMA_TARGET_VIDMEM;
} else if (chan->notifier_block->flags & NOUVEAU_MEM_AGP) {
offset -= dev_priv->agp_phys;
target = NV_DMA_TARGET_AGP;
} else {
DRM_ERROR("Bad DMA target, flags 0x%08x!\n",
chan->notifier_block->flags);
return DRM_ERR(EINVAL);
}
obj = nouveau_object_dma_create(dev, channel, NV_CLASS_DMA_IN_MEMORY,
offset, mem->size, NV_DMA_ACCESS_RW,
target);
if (!obj) {
nouveau_mem_free_block(mem);
DRM_ERROR("Error creating notifier ctxdma\n");
return DRM_ERR(ENOMEM);
}
obj->handle = handle;
if (nouveau_ht_object_insert(dev, channel, handle, obj)) {
nouveau_object_free(dev, obj);
nouveau_mem_free_block(mem);
DRM_ERROR("Error inserting notifier ctxdma into RAMHT\n");
return DRM_ERR(ENOMEM);
}
*b_offset = mem->start;
return 0;
}
int
nouveau_ioctl_notifier_alloc(DRM_IOCTL_ARGS)
{
DRM_DEVICE;
drm_nouveau_notifier_alloc_t na;
int ret;
DRM_COPY_FROM_USER_IOCTL(na, (drm_nouveau_notifier_alloc_t __user*)data,
sizeof(na));
if (!nouveau_fifo_owner(dev, filp, na.channel)) {
DRM_ERROR("pid %d doesn't own channel %d\n",
DRM_CURRENTPID, na.channel);
return DRM_ERR(EPERM);
}
ret = nouveau_notifier_alloc(dev, na.channel, na.handle,
na.count, &na.offset);
if (ret)
return ret;
DRM_COPY_TO_USER_IOCTL((drm_nouveau_notifier_alloc_t __user*)data,
na, sizeof(na));
return 0;
}

View File

@ -153,13 +153,13 @@ nouveau_ht_handle_hash(drm_device_t *dev, int channel, uint32_t handle)
return hash << 3;
}
static int
int
nouveau_ht_object_insert(drm_device_t* dev, int channel, uint32_t handle,
struct nouveau_object *obj)
{
drm_nouveau_private_t *dev_priv=dev->dev_private;
int ht_base = NV_RAMIN + dev_priv->ramht_offset;
int ht_end = ht_base + dev_priv->ramht_size;
/* int ht_end = ht_base + dev_priv->ramht_size; */
int o_ofs, ofs;
obj->handle = handle;
@ -461,6 +461,54 @@ nouveau_object_free(drm_device_t *dev, struct nouveau_object *obj)
drm_free(obj, sizeof(struct nouveau_object), DRM_MEM_DRIVER);
}
int
nouveau_object_init_channel(drm_device_t *dev, int channel,
uint32_t vram_handle,
uint32_t tt_handle)
{
drm_nouveau_private_t *dev_priv = dev->dev_private;
struct nouveau_object *gpuobj;
int ret;
/* VRAM ctxdma */
gpuobj = nouveau_object_dma_create(dev, channel, NV_CLASS_DMA_IN_MEMORY,
0, dev_priv->fb_available_size,
NV_DMA_ACCESS_RW,
NV_DMA_TARGET_VIDMEM);
if (!gpuobj) {
DRM_ERROR("Error creating VRAM ctxdma: %d\n", DRM_ERR(ENOMEM));
return DRM_ERR(ENOMEM);
}
ret = nouveau_ht_object_insert(dev, channel, vram_handle, gpuobj);
if (ret) {
DRM_ERROR("Error referencing VRAM ctxdma: %d\n", ret);
return ret;
}
/* non-AGP unimplemented */
if (dev_priv->agp_heap == NULL)
return 0;
/* GART ctxdma */
gpuobj = nouveau_object_dma_create(dev, channel, NV_CLASS_DMA_IN_MEMORY,
0, dev_priv->agp_available_size,
NV_DMA_ACCESS_RW,
NV_DMA_TARGET_AGP);
if (!gpuobj) {
DRM_ERROR("Error creating TT ctxdma: %d\n", DRM_ERR(ENOMEM));
return DRM_ERR(ENOMEM);
}
ret = nouveau_ht_object_insert(dev, channel, tt_handle, gpuobj);
if (ret) {
DRM_ERROR("Error referencing TT ctxdma: %d\n", ret);
return ret;
}
return 0;
}
void nouveau_object_cleanup(drm_device_t *dev, int channel)
{
drm_nouveau_private_t *dev_priv=dev->dev_private;
@ -470,13 +518,13 @@ void nouveau_object_cleanup(drm_device_t *dev, int channel)
}
}
int nouveau_ioctl_object_init(DRM_IOCTL_ARGS)
int nouveau_ioctl_grobj_alloc(DRM_IOCTL_ARGS)
{
DRM_DEVICE;
drm_nouveau_object_init_t init;
drm_nouveau_grobj_alloc_t init;
struct nouveau_object *obj;
DRM_COPY_FROM_USER_IOCTL(init, (drm_nouveau_object_init_t __user *)
DRM_COPY_FROM_USER_IOCTL(init, (drm_nouveau_grobj_alloc_t __user *)
data, sizeof(init));
if (!nouveau_fifo_owner(dev, filp, init.channel)) {
@ -505,100 +553,3 @@ int nouveau_ioctl_object_init(DRM_IOCTL_ARGS)
return 0;
}
static int
nouveau_dma_object_check_access(drm_device_t *dev,
drm_nouveau_dma_object_init_t *init)
{
drm_nouveau_private_t *dev_priv = dev->dev_private;
uint64_t limit;
/* Check for known DMA object classes */
switch (init->class) {
case NV_CLASS_DMA_IN_MEMORY:
case NV_CLASS_DMA_FROM_MEMORY:
case NV_CLASS_DMA_TO_MEMORY:
break;
default:
DRM_ERROR("invalid class = 0x%x\n", init->class);
return DRM_ERR(EPERM);
}
/* Check access mode, and translate to NV_DMA_ACCESS_* */
switch (init->access) {
case NOUVEAU_MEM_ACCESS_RO:
init->access = NV_DMA_ACCESS_RO;
break;
case NOUVEAU_MEM_ACCESS_WO:
init->access = NV_DMA_ACCESS_WO;
break;
case NOUVEAU_MEM_ACCESS_RW:
init->access = NV_DMA_ACCESS_RW;
break;
default:
DRM_ERROR("invalid access mode = %d\n", init->access);
return DRM_ERR(EPERM);
}
/* Check that request is within the allowed limits of "target" */
switch (init->target) {
case NOUVEAU_MEM_FB:
limit = dev_priv->fb_available_size;
init->target = NV_DMA_TARGET_VIDMEM;
break;
case NOUVEAU_MEM_AGP:
limit = dev_priv->agp_available_size;
init->target = NV_DMA_TARGET_AGP;
break;
default:
DRM_ERROR("invalid target = 0x%x\n", init->target);
return DRM_ERR(EPERM);
}
if ((init->offset > limit) || (init->offset + init->size) > limit) {
DRM_ERROR("access out of allowed range (%d,0x%08x,0x%08x)\n",
init->target, init->offset, init->size);
return DRM_ERR(EPERM);
}
return 0;
}
int nouveau_ioctl_dma_object_init(DRM_IOCTL_ARGS)
{
DRM_DEVICE;
drm_nouveau_dma_object_init_t init;
struct nouveau_object *obj;
DRM_COPY_FROM_USER_IOCTL(init, (drm_nouveau_dma_object_init_t __user *)
data, sizeof(init));
if (!nouveau_fifo_owner(dev, filp, init.channel)) {
DRM_ERROR("pid %d doesn't own channel %d\n",
DRM_CURRENTPID, init.channel);
return DRM_ERR(EINVAL);
}
if (nouveau_dma_object_check_access(dev, &init))
return DRM_ERR(EPERM);
if (nouveau_object_handle_find(dev, init.channel, init.handle)) {
DRM_ERROR("Channel %d: handle 0x%08x already exists\n",
init.channel, init.handle);
return DRM_ERR(EINVAL);
}
obj = nouveau_object_dma_create(dev, init.channel, init.class,
init.offset, init.size,
init.access, init.target);
if (!obj)
return DRM_ERR(ENOMEM);
obj->handle = init.handle;
if (nouveau_ht_object_insert(dev, init.channel, init.handle, obj)) {
nouveau_object_free(dev, obj);
return DRM_ERR(ENOMEM);
}
return 0;
}

View File

@ -260,9 +260,9 @@ void nouveau_preclose(drm_device_t * dev, DRMFILE filp)
{
drm_nouveau_private_t *dev_priv = dev->dev_private;
nouveau_fifo_cleanup(dev, filp);
nouveau_mem_release(filp,dev_priv->fb_heap);
nouveau_mem_release(filp,dev_priv->agp_heap);
nouveau_fifo_cleanup(dev, filp);
}
/* first module load, setup the mmio/fb mapping */
@ -282,7 +282,6 @@ int nouveau_firstopen(struct drm_device *dev)
int nouveau_load(struct drm_device *dev, unsigned long flags)
{
drm_nouveau_private_t *dev_priv;
int ret;
if (flags==NV_UNKNOWN)
return DRM_ERR(EINVAL);