summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--shared-core/nouveau_drm.h29
-rw-r--r--shared-core/nouveau_drv.h13
-rw-r--r--shared-core/nouveau_fifo.c9
-rw-r--r--shared-core/nouveau_irq.c54
-rw-r--r--shared-core/nouveau_mem.c4
-rw-r--r--shared-core/nouveau_object.c234
-rw-r--r--shared-core/nouveau_reg.h8
-rw-r--r--shared-core/nouveau_state.c13
-rw-r--r--shared-core/nv40_graph.c1
9 files changed, 213 insertions, 152 deletions
diff --git a/shared-core/nouveau_drm.h b/shared-core/nouveau_drm.h
index 0f11c43a..8a1964ed 100644
--- a/shared-core/nouveau_drm.h
+++ b/shared-core/nouveau_drm.h
@@ -25,6 +25,8 @@
#ifndef __NOUVEAU_DRM_H__
#define __NOUVEAU_DRM_H__
+#define NOUVEAU_DRM_HEADER_PATCHLEVEL 4
+
typedef struct drm_nouveau_fifo_alloc {
int channel;
uint32_t put_base;
@@ -37,24 +39,18 @@ typedef struct drm_nouveau_fifo_alloc {
}
drm_nouveau_fifo_alloc_t;
-#define NV_DMA_CONTEXT_FLAGS_PATCH_ROP_AND 0x1
-#define NV_DMA_CONTEXT_FLAGS_PATCH_SRCCOPY 0x2
-#define NV_DMA_CONTEXT_FLAGS_CLIP_ENABLE 0x4
-#define NV_DMA_CONTEXT_FLAGS_MONO 0x8
-
typedef struct drm_nouveau_object_init {
uint32_t handle;
- int class;
- uint32_t flags;
- /* these are object handles */
- uint32_t dma0;
- uint32_t dma1;
- uint32_t dma_notifier;
+ int class;
}
drm_nouveau_object_init_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 {
uint32_t handle;
+ int class;
int access;
int target;
uint32_t offset;
@@ -80,8 +76,8 @@ typedef struct drm_nouveau_mem_alloc {
drm_nouveau_mem_alloc_t;
typedef struct drm_nouveau_mem_free {
- int flags;
uint64_t region_offset;
+ int flags;
}
drm_nouveau_mem_free_t;
@@ -91,9 +87,10 @@ drm_nouveau_mem_free_t;
#define NOUVEAU_GETPARAM_BUS_TYPE 5
#define NOUVEAU_GETPARAM_FB_PHYSICAL 6
#define NOUVEAU_GETPARAM_AGP_PHYSICAL 7
+#define NOUVEAU_GETPARAM_FB_SIZE 8
+#define NOUVEAU_GETPARAM_AGP_SIZE 9
typedef struct drm_nouveau_getparam {
- unsigned int param;
- unsigned int dummy;
+ uint64_t param;
uint64_t value;
}
drm_nouveau_getparam_t;
@@ -101,8 +98,8 @@ drm_nouveau_getparam_t;
#define NOUVEAU_SETPARAM_CMDBUF_LOCATION 1
#define NOUVEAU_SETPARAM_CMDBUF_SIZE 2
typedef struct drm_nouveau_setparam {
- unsigned int param;
- unsigned int value;
+ uint64_t param;
+ uint64_t value;
}
drm_nouveau_setparam_t;
diff --git a/shared-core/nouveau_drv.h b/shared-core/nouveau_drv.h
index 63721650..c3d19bb0 100644
--- a/shared-core/nouveau_drv.h
+++ b/shared-core/nouveau_drv.h
@@ -34,7 +34,7 @@
#define DRIVER_MAJOR 0
#define DRIVER_MINOR 0
-#define DRIVER_PATCHLEVEL 3
+#define DRIVER_PATCHLEVEL 4
#define NOUVEAU_FAMILY 0x0000FFFF
#define NOUVEAU_FLAGS 0xFFFF0000
@@ -70,9 +70,6 @@ struct nouveau_object
int engine;
};
-#define NV_DMA_TARGET_VIDMEM 0
-#define NV_DMA_TARGET_PCI 2
-#define NV_DMA_TARGET_AGP 3
struct nouveau_fifo
{
int used;
@@ -134,7 +131,9 @@ typedef struct drm_nouveau_private {
/* base physical adresses */
uint64_t fb_phys;
+ uint64_t fb_available_size;
uint64_t agp_phys;
+ uint64_t agp_available_size;
/* the mtrr covering the FB */
int fb_mtrr;
@@ -192,8 +191,10 @@ extern void nouveau_fifo_free(drm_device_t *dev, int channel);
/* nouveau_object.c */
extern void nouveau_object_cleanup(drm_device_t *dev, DRMFILE filp);
-extern struct nouveau_object *nouveau_dma_object_create(drm_device_t *dev,
- uint32_t offset, uint32_t size, int access, uint32_t target);
+extern struct nouveau_object *
+nouveau_dma_object_create(drm_device_t *dev, int class,
+ uint32_t offset, uint32_t size,
+ int access, int target);
extern int nouveau_ioctl_object_init(DRM_IOCTL_ARGS);
extern int nouveau_ioctl_dma_object_init(DRM_IOCTL_ARGS);
extern uint32_t nouveau_chip_instance_get(drm_device_t *dev, struct mem_block *mem);
diff --git a/shared-core/nouveau_fifo.c b/shared-core/nouveau_fifo.c
index fd5455bf..6f75a05b 100644
--- a/shared-core/nouveau_fifo.c
+++ b/shared-core/nouveau_fifo.c
@@ -239,11 +239,12 @@ nouveau_fifo_cmdbuf_alloc(struct drm_device *dev, int channel)
}
if (cb->flags & NOUVEAU_MEM_AGP) {
- cb_dma = nouveau_dma_object_create(dev,
- cb->start, cb->size,
+ cb_dma = nouveau_dma_object_create(dev, NV_CLASS_DMA_IN_MEMORY,
+ cb->start - dev_priv->agp_phys,
+ cb->size,
NV_DMA_ACCESS_RO, NV_DMA_TARGET_AGP);
} else if (dev_priv->card_type != NV_04) {
- cb_dma = nouveau_dma_object_create(dev,
+ cb_dma = nouveau_dma_object_create(dev, NV_CLASS_DMA_IN_MEMORY,
cb->start - drm_get_resource_start(dev, 1),
cb->size,
NV_DMA_ACCESS_RO, NV_DMA_TARGET_VIDMEM);
@@ -252,7 +253,7 @@ nouveau_fifo_cmdbuf_alloc(struct drm_device *dev, int channel)
* exact reason for existing :) PCI access to cmdbuf in
* VRAM.
*/
- cb_dma = nouveau_dma_object_create(dev,
+ cb_dma = nouveau_dma_object_create(dev, NV_CLASS_DMA_IN_MEMORY,
cb->start, cb->size,
NV_DMA_ACCESS_RO, NV_DMA_TARGET_PCI);
}
diff --git a/shared-core/nouveau_irq.c b/shared-core/nouveau_irq.c
index 51d4bae1..f6908492 100644
--- a/shared-core/nouveau_irq.c
+++ b/shared-core/nouveau_irq.c
@@ -136,7 +136,7 @@ static void nouveau_fifo_irq_handler(drm_device_t *dev)
uint32_t status, chmode, chstat, channel;
drm_nouveau_private_t *dev_priv = dev->dev_private;
- status = NV_READ(NV03_PMC_INTR_0);
+ status = NV_READ(NV03_PFIFO_INTR_0);
if (!status)
return;
chmode = NV_READ(NV04_PFIFO_MODE);
@@ -239,6 +239,30 @@ static void nouveau_nv04_context_switch(drm_device_t *dev)
}
#endif
+static void
+nouveau_graph_dump_trap_info(drm_device_t *dev)
+{
+ drm_nouveau_private_t *dev_priv = dev->dev_private;
+ uint32_t address;
+ uint32_t channel;
+ uint32_t method, subc, data;
+
+ address = NV_READ(0x400704);
+ data = NV_READ(0x400708);
+ channel = (address >> 20) & 0x1F;
+ subc = (address >> 16) & 0x7;
+ method = address & 0x1FFC;
+
+ DRM_ERROR("NV: nSource: 0x%08x, nStatus: 0x%08x\n",
+ NV_READ(0x400108), NV_READ(0x400104));
+ DRM_ERROR("NV: Channel %d/%d (class 0x%04x) -"
+ "Method 0x%04x, Data 0x%08x\n",
+ channel, subc,
+ NV_READ(0x400160+subc*4) & 0xFFFF,
+ method, data
+ );
+}
+
static void nouveau_pgraph_irq_handler(drm_device_t *dev)
{
uint32_t status;
@@ -256,9 +280,15 @@ static void nouveau_pgraph_irq_handler(drm_device_t *dev)
nsource = NV_READ(0x00400108);
DRM_DEBUG("nsource:0x%08x\tnstatus:0x%08x\n", nsource, nstatus);
- instance = NV_READ(0x00400158);
- notify = NV_READ(0x00400150) >> 16;
- DRM_DEBUG("instance:0x%08x\tnotify:0x%08x\n", nsource, nstatus);
+ /* if this wasn't NOTIFICATION_PENDING, dump extra trap info */
+ if (nsource & ~(1<<0)) {
+ nouveau_graph_dump_trap_info(dev);
+ } else {
+ instance = NV_READ(0x00400158);
+ notify = NV_READ(0x00400150) >> 16;
+ DRM_DEBUG("instance:0x%08x\tnotify:0x%08x\n",
+ nsource, nstatus);
+ }
status &= ~NV_PGRAPH_INTR_NOTIFY;
NV_WRITE(NV03_PGRAPH_INTR, NV_PGRAPH_INTR_NOTIFY);
@@ -289,9 +319,6 @@ static void nouveau_pgraph_irq_handler(drm_device_t *dev)
if (status & NV_PGRAPH_INTR_ERROR) {
uint32_t nsource, nstatus, instance;
- uint32_t address;
- uint32_t channel;
- uint32_t method, subc, data;
DRM_ERROR("NV: PGRAPH error interrupt\n");
@@ -302,18 +329,7 @@ static void nouveau_pgraph_irq_handler(drm_device_t *dev)
instance = NV_READ(0x00400158);
DRM_ERROR("instance:0x%08x\n", instance);
- address = NV_READ(0x400704);
- data = NV_READ(0x400708);
- channel = (address >> 20) & 0x1F;
- subc = (address >> 16) & 0x7;
- method = address & 0x1FFC;
- DRM_DEBUG("NV: 0x400704 = 0x%08x\n", address);
- DRM_ERROR("NV: Channel %d/%d (class 0x%04x) -"
- "Method 0x%04x, Data 0x%08x\n",
- channel, subc,
- NV_READ(0x400160+subc*4) & 0xFFFF,
- method, data
- );
+ nouveau_graph_dump_trap_info(dev);
status &= ~NV_PGRAPH_INTR_ERROR;
NV_WRITE(NV03_PGRAPH_INTR, NV_PGRAPH_INTR_ERROR);
diff --git a/shared-core/nouveau_mem.c b/shared-core/nouveau_mem.c
index 3b1f443c..f62d8615 100644
--- a/shared-core/nouveau_mem.c
+++ b/shared-core/nouveau_mem.c
@@ -335,7 +335,8 @@ int nouveau_mem_init(struct drm_device *dev)
if (init_heap(&dev_priv->agp_heap, info.aperture_base, info.aperture_size))
goto no_agp;
- dev_priv->agp_phys=info.aperture_base;
+ dev_priv->agp_phys = info.aperture_base;
+ dev_priv->agp_available_size = info.aperture_size;
}
no_agp:
@@ -346,6 +347,7 @@ no_agp:
* We don't want to allocate this... */
if (dev_priv->card_type >= NV_40)
fb_size -= dev_priv->ramin_size;
+ dev_priv->fb_available_size = fb_size;
DRM_DEBUG("Available VRAM: %dKiB\n", fb_size>>10);
if (fb_size>256*1024*1024) {
diff --git a/shared-core/nouveau_object.c b/shared-core/nouveau_object.c
index c11b05eb..b3c4b0e0 100644
--- a/shared-core/nouveau_object.c
+++ b/shared-core/nouveau_object.c
@@ -97,9 +97,6 @@ nouveau_object_handle_find(drm_device_t *dev, int fifo_num, uint32_t handle)
struct nouveau_fifo *fifo = &dev_priv->fifos[fifo_num];
struct nouveau_object *obj = fifo->objs;
- if (!handle)
- return NULL;
-
DRM_DEBUG("Looking for handle 0x%08x\n", handle);
while (obj) {
if (obj->handle == handle)
@@ -166,7 +163,7 @@ static int nouveau_hash_table_insert(drm_device_t* dev, int fifo,
o_ofs = ofs = nouveau_handle_hash(dev, obj->handle, fifo);
- while (NV_READ(ht_base + ofs)) {
+ while (NV_READ(ht_base + ofs) || NV_READ(ht_base + ofs + 4)) {
ofs += 8;
if (ofs == ht_end) ofs = ht_base;
if (ofs == o_ofs) {
@@ -284,17 +281,40 @@ static void nouveau_object_instance_free(drm_device_t *dev,
The method below creates a DMA object in instance RAM and returns a handle
to it that can be used to set up context objects.
*/
-struct nouveau_object *nouveau_dma_object_create(drm_device_t* dev,
- uint32_t offset, uint32_t size,
- int access, uint32_t target)
+
+struct nouveau_object *
+nouveau_dma_object_create(drm_device_t* dev, int class,
+ uint32_t offset, uint32_t size,
+ int access, int target)
{
drm_nouveau_private_t *dev_priv=dev->dev_private;
struct nouveau_object *obj;
uint32_t frame, adjust;
+ uint32_t pte_flags = 0;
DRM_DEBUG("offset:0x%08x, size:0x%08x, target:%d, access:%d\n",
offset, size, target, access);
+ switch (target) {
+ case NV_DMA_TARGET_AGP:
+ offset += dev_priv->agp_phys;
+ break;
+ default:
+ break;
+ }
+
+ switch (access) {
+ case NV_DMA_ACCESS_RO:
+ break;
+ case NV_DMA_ACCESS_WO:
+ case NV_DMA_ACCESS_RW:
+ pte_flags |= (1 << 1);
+ break;
+ default:
+ DRM_ERROR("invalid access mode=%d\n", access);
+ return NULL;
+ }
+
frame = offset & ~0x00000FFF;
adjust = offset & 0x00000FFF;
@@ -305,21 +325,16 @@ struct nouveau_object *nouveau_dma_object_create(drm_device_t* dev,
}
obj->engine = 0;
- obj->class = 0;
+ obj->class = class;
INSTANCE_WR(obj->instance, 0, ((1<<12) | (1<<13) |
(adjust << 20) |
(access << 14) |
(target << 16) |
- 0x3D /* DMA_IN_MEMORY */));
+ class));
INSTANCE_WR(obj->instance, 1, size-1);
- INSTANCE_WR(obj->instance, 2,
- frame | ((access != NV_DMA_ACCESS_RO) ? (1<<1) : 0));
- /* I don't actually know what this is, the DMA objects I see
- * in renouveau dumps usually have this as the same as +8
- */
- INSTANCE_WR(obj->instance, 3,
- frame | ((access != NV_DMA_ACCESS_RO) ? (1<<1) : 0));
+ INSTANCE_WR(obj->instance, 2, frame | pte_flags);
+ INSTANCE_WR(obj->instance, 3, frame | pte_flags);
return obj;
}
@@ -376,55 +391,13 @@ struct nouveau_object *nouveau_dma_object_create(drm_device_t* dev,
entry[5]:
set to 0?
*/
-static struct nouveau_object *nouveau_context_object_create(drm_device_t* dev,
- int class, uint32_t flags,
- struct nouveau_object *dma0,
- struct nouveau_object *dma1,
- struct nouveau_object *dma_notifier)
+static struct nouveau_object *
+nouveau_context_object_create(drm_device_t* dev, int class)
{
drm_nouveau_private_t *dev_priv=dev->dev_private;
struct nouveau_object *obj;
- uint32_t d0, d1, dn;
- uint32_t flags0,flags1,flags2;
- flags0=0;flags1=0;flags2=0;
-
- if (dev_priv->card_type >= NV_40) {
- if (flags & NV_DMA_CONTEXT_FLAGS_PATCH_ROP_AND)
- flags0 |= 0x02080000;
- else if (flags & NV_DMA_CONTEXT_FLAGS_PATCH_SRCCOPY)
- flags0 |= 0x02080000;
- if (flags & NV_DMA_CONTEXT_FLAGS_CLIP_ENABLE)
- flags0 |= 0x00020000;
-#ifdef __BIG_ENDIAN
- if (flags & NV_DMA_CONTEXT_FLAGS_MONO)
- flags1 |= 0x01000000;
- flags2 |= 0x01000000;
-#else
- if (flags & NV_DMA_CONTEXT_FLAGS_MONO)
- flags1 |= 0x02000000;
-#endif
- } else {
- if (flags & NV_DMA_CONTEXT_FLAGS_PATCH_ROP_AND)
- flags0 |= 0x01008000;
- else if (flags & NV_DMA_CONTEXT_FLAGS_PATCH_SRCCOPY)
- flags0 |= 0x01018000;
- if (flags & NV_DMA_CONTEXT_FLAGS_CLIP_ENABLE)
- flags0 |= 0x00002000;
-#ifdef __BIG_ENDIAN
- flags0 |= 0x00080000;
- if (flags & NV_DMA_CONTEXT_FLAGS_MONO)
- flags1 |= 0x00000001;
-#else
- if (flags & NV_DMA_CONTEXT_FLAGS_MONO)
- flags1 |= 0x00000002;
-#endif
- }
- DRM_DEBUG("class=%x, dma0=%08x, dma1=%08x, dman=%08x\n",
- class,
- dma0 ? dma0->handle : 0,
- dma1 ? dma1->handle : 0,
- dma_notifier ? dma_notifier->handle : 0);
+ DRM_DEBUG("class=%x\n", class);
obj = nouveau_instance_alloc(dev);
if (!obj) {
@@ -435,25 +408,37 @@ static struct nouveau_object *nouveau_context_object_create(drm_device_t* dev,
obj->engine = 1;
obj->class = class;
- d0 = dma0 ? nouveau_chip_instance_get(dev, dma0->instance) : 0;
- d1 = dma1 ? nouveau_chip_instance_get(dev, dma1->instance) : 0;
- dn = dma_notifier ?
- nouveau_chip_instance_get(dev, dma_notifier->instance) : 0;
-
- if (dev_priv->card_type >= NV_40) {
- INSTANCE_WR(obj->instance, 0, class | flags0);
- INSTANCE_WR(obj->instance, 1, dn | flags1);
- INSTANCE_WR(obj->instance, 2, d0 | flags2);
- INSTANCE_WR(obj->instance, 3, d1);
- INSTANCE_WR(obj->instance, 4, 0x00000000);
- INSTANCE_WR(obj->instance, 5, 0x00000000);
- INSTANCE_WR(obj->instance, 6, 0x00000000);
- INSTANCE_WR(obj->instance, 7, 0x00000000);
- } else {
- INSTANCE_WR(obj->instance, 0, class | flags0);
- INSTANCE_WR(obj->instance, 1, (dn << 16) | flags1);
- INSTANCE_WR(obj->instance, 2, d0 | (d1 << 16));
- INSTANCE_WR(obj->instance, 3, 0);
+ switch (class) {
+ case NV_CLASS_NULL:
+ INSTANCE_WR(obj->instance, 0, 0x00001030);
+ INSTANCE_WR(obj->instance, 1, 0xFFFFFFFF);
+ INSTANCE_WR(obj->instance, 2, 0x00000000);
+ INSTANCE_WR(obj->instance, 2, 0x00000000);
+ break;
+ default:
+ if (dev_priv->card_type >= NV_40) {
+ INSTANCE_WR(obj->instance, 0, obj->class);
+ INSTANCE_WR(obj->instance, 1, 0x00000000);
+#ifdef __BIG_ENDIAN
+ INSTANCE_WR(obj->instance, 2, 0x01000000);
+#else
+ INSTANCE_WR(obj->instance, 2, 0x00000000);
+#endif
+ INSTANCE_WR(obj->instance, 3, 0x00000000);
+ INSTANCE_WR(obj->instance, 4, 0x00000000);
+ INSTANCE_WR(obj->instance, 5, 0x00000000);
+ INSTANCE_WR(obj->instance, 6, 0x00000000);
+ INSTANCE_WR(obj->instance, 7, 0x00000000);
+ } else {
+#ifdef __BIG_ENDIAN
+ INSTANCE_WR(obj->instance, 0, obj->class | 0x00080000);
+#else
+ INSTANCE_WR(obj->instance, 0, obj->class);
+#endif
+ INSTANCE_WR(obj->instance, 1, 0x00000000);
+ INSTANCE_WR(obj->instance, 2, 0x00000000);
+ INSTANCE_WR(obj->instance, 3, 0x00000000);
+ }
}
return obj;
@@ -488,7 +473,7 @@ int nouveau_ioctl_object_init(DRM_IOCTL_ARGS)
{
DRM_DEVICE;
drm_nouveau_object_init_t init;
- struct nouveau_object *obj, *dma0, *dma1, *dman;
+ struct nouveau_object *obj;
int fifo;
fifo = nouveau_fifo_id_get(dev, filp);
@@ -506,30 +491,11 @@ int nouveau_ioctl_object_init(DRM_IOCTL_ARGS)
return DRM_ERR(EINVAL);
}
- dma0 = nouveau_object_handle_find(dev, fifo, init.dma0);
- if (init.dma0 && !dma0) {
- DRM_ERROR("context dma0 - invalid handle 0x%08x\n", init.dma0);
- return DRM_ERR(EINVAL);
- }
- dma1 = nouveau_object_handle_find(dev, fifo, init.dma1);
- if (init.dma1 && !dma1) {
- DRM_ERROR("context dma1 - invalid handle 0x%08x\n", init.dma0);
- return DRM_ERR(EINVAL);
- }
- dman = nouveau_object_handle_find(dev, fifo, init.dma_notifier);
- if (init.dma_notifier && !dman) {
- DRM_ERROR("context dman - invalid handle 0x%08x\n",
- init.dma_notifier);
- return DRM_ERR(EINVAL);
- }
-
- obj = nouveau_context_object_create(dev, init.class, init.flags,
- dma0, dma1, dman);
+ obj = nouveau_context_object_create(dev, init.class);
if (!obj)
return DRM_ERR(ENOMEM);
obj->handle = init.handle;
-
if (nouveau_hash_table_insert(dev, fifo, obj)) {
nouveau_object_free(dev, fifo, obj);
return DRM_ERR(ENOMEM);
@@ -540,6 +506,64 @@ 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;
@@ -554,14 +578,18 @@ int nouveau_ioctl_dma_object_init(DRM_IOCTL_ARGS)
DRM_COPY_FROM_USER_IOCTL(init, (drm_nouveau_dma_object_init_t __user *)
data, sizeof(init));
+ if (nouveau_dma_object_check_access(dev, &init))
+ return DRM_ERR(EPERM);
+
if (nouveau_object_handle_find(dev, fifo, init.handle)) {
DRM_ERROR("Channel %d: handle 0x%08x already exists\n",
fifo, init.handle);
return DRM_ERR(EINVAL);
}
- obj = nouveau_dma_object_create(dev, init.offset, init.size,
- init.access, init.target);
+ obj = nouveau_dma_object_create(dev, init.class,
+ init.offset, init.size,
+ init.access, init.target);
if (!obj)
return DRM_ERR(ENOMEM);
diff --git a/shared-core/nouveau_reg.h b/shared-core/nouveau_reg.h
index 966600cf..95de558b 100644
--- a/shared-core/nouveau_reg.h
+++ b/shared-core/nouveau_reg.h
@@ -32,12 +32,20 @@
# define NV40_RAMHT_CONTEXT_ENGINE_SHIFT 20
# define NV40_RAMHT_CONTEXT_INSTANCE_SHIFT 0
+/* DMA object defines */
#define NV_DMA_ACCESS_RW 0
#define NV_DMA_ACCESS_RO 1
#define NV_DMA_ACCESS_WO 2
#define NV_DMA_TARGET_VIDMEM 0
+#define NV_DMA_TARGET_PCI 2
#define NV_DMA_TARGET_AGP 3
+/* Some object classes we care about in the drm */
+#define NV_CLASS_DMA_FROM_MEMORY 0x00000002
+#define NV_CLASS_DMA_TO_MEMORY 0x00000003
+#define NV_CLASS_NULL 0x00000030
+#define NV_CLASS_DMA_IN_MEMORY 0x0000003D
+
#define NV03_FIFO_SIZE 0x8000UL
#define NV_MAX_FIFO_NUMBER 32
#define NV03_FIFO_REGS_SIZE 0x10000
diff --git a/shared-core/nouveau_state.c b/shared-core/nouveau_state.c
index f1f272e7..e1fc6330 100644
--- a/shared-core/nouveau_state.c
+++ b/shared-core/nouveau_state.c
@@ -181,8 +181,14 @@ int nouveau_ioctl_getparam(DRM_IOCTL_ARGS)
case NOUVEAU_GETPARAM_AGP_PHYSICAL:
getparam.value=dev_priv->agp_phys;
break;
+ case NOUVEAU_GETPARAM_FB_SIZE:
+ getparam.value=dev_priv->fb_available_size;
+ break;
+ case NOUVEAU_GETPARAM_AGP_SIZE:
+ getparam.value=dev_priv->agp_available_size;
+ break;
default:
- DRM_ERROR("unknown parameter %d\n", getparam.param);
+ DRM_ERROR("unknown parameter %lld\n", getparam.param);
return DRM_ERR(EINVAL);
}
@@ -207,7 +213,8 @@ int nouveau_ioctl_setparam(DRM_IOCTL_ARGS)
case NOUVEAU_MEM_FB:
break;
default:
- DRM_ERROR("invalid CMDBUF_LOCATION value=%d\n", setparam.value);
+ DRM_ERROR("invalid CMDBUF_LOCATION value=%lld\n",
+ setparam.value);
return DRM_ERR(EINVAL);
}
dev_priv->config.cmdbuf.location = setparam.value;
@@ -216,7 +223,7 @@ int nouveau_ioctl_setparam(DRM_IOCTL_ARGS)
dev_priv->config.cmdbuf.size = setparam.value;
break;
default:
- DRM_ERROR("unknown parameter %d\n", setparam.param);
+ DRM_ERROR("unknown parameter %lld\n", setparam.param);
return DRM_ERR(EINVAL);
}
diff --git a/shared-core/nv40_graph.c b/shared-core/nv40_graph.c
index 659767f2..082849d9 100644
--- a/shared-core/nv40_graph.c
+++ b/shared-core/nv40_graph.c
@@ -926,6 +926,7 @@ nv40_graph_init(drm_device_t *dev)
/* No idea what this is for.. */
dev_priv->fb_obj = nouveau_dma_object_create(dev,
+ NV_CLASS_DMA_IN_MEMORY,
0, nouveau_mem_fb_amount(dev),
NV_DMA_ACCESS_RW, NV_DMA_TARGET_VIDMEM);
pg0220_inst = nouveau_chip_instance_get(dev,