OSDN Git Service

nouveau: intrusive drm interface changes
authorBen Skeggs <skeggsb@gmail.com>
Wed, 28 Feb 2007 04:14:08 +0000 (15:14 +1100)
committerBen Skeggs <skeggsb@gmail.com>
Wed, 28 Feb 2007 04:41:53 +0000 (15:41 +1100)
graphics objects:
- No longer takes flags/dmaobj parameters, requires some major changes
  to the ddx to setup the object through the FIFO.  This change is
  likely to cause breakages on some cards (tested on NV05,NV28,NV35,
  NV40 and NV4E).
dma objects:
- now takes a "class" parameter, not really used yet but we may need
  it at some point.
- parameters are checked, so clients can't randomly create DMA objects
  pointing at whatever they feel like.
misc:
- Added FB_SIZE/AGP_SIZE getparams
- Read PFIFO_INTR in PFIFO irq handler, not PMC_INTR
- Dump PGRAPH trap info on PGRAPH_INTR_NOTIFY if NSOURCE isn't
  NOTIFICATION_PENDING.

shared-core/nouveau_drm.h
shared-core/nouveau_drv.h
shared-core/nouveau_fifo.c
shared-core/nouveau_irq.c
shared-core/nouveau_mem.c
shared-core/nouveau_object.c
shared-core/nouveau_reg.h
shared-core/nouveau_state.c
shared-core/nv40_graph.c

index 0f11c43..8a1964e 100644 (file)
@@ -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;
 
index 6372165..c3d19bb 100644 (file)
@@ -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);
index fd5455b..6f75a05 100644 (file)
@@ -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);
        }
index 51d4bae..f690849 100644 (file)
@@ -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);
index 3b1f443..f62d861 100644 (file)
@@ -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) {
index c11b05e..b3c4b0e 100644 (file)
@@ -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);
 
index 966600c..95de558 100644 (file)
 #    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
index f1f272e..e1fc633 100644 (file)
@@ -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);
        }
 
index 659767f..082849d 100644 (file)
@@ -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,