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
parent
4f2dd78ff3
commit
695599f18d
|
@ -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 \
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
../shared-core/nouveau_notifier.c
|
|
@ -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
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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},
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue