summaryrefslogtreecommitdiff
path: root/shared-core
diff options
context:
space:
mode:
Diffstat (limited to 'shared-core')
-rw-r--r--shared-core/drm_pciids.txt10
-rw-r--r--shared-core/i915_irq.c2
-rw-r--r--shared-core/nouveau_drm.h43
-rw-r--r--shared-core/nouveau_drv.h319
-rw-r--r--shared-core/nouveau_fifo.c518
-rw-r--r--shared-core/nouveau_irq.c41
-rw-r--r--shared-core/nouveau_mem.c310
-rw-r--r--shared-core/nouveau_notifier.c151
-rw-r--r--shared-core/nouveau_object.c1097
-rw-r--r--shared-core/nouveau_reg.h38
-rw-r--r--shared-core/nouveau_state.c272
-rw-r--r--shared-core/nv04_fifo.c130
-rw-r--r--shared-core/nv04_graph.c27
-rw-r--r--shared-core/nv04_instmem.c165
-rw-r--r--shared-core/nv10_fifo.c161
-rw-r--r--shared-core/nv10_graph.c25
-rw-r--r--shared-core/nv20_graph.c78
-rw-r--r--shared-core/nv30_graph.c109
-rw-r--r--shared-core/nv40_fifo.c195
-rw-r--r--shared-core/nv40_graph.c684
-rw-r--r--shared-core/nv50_fifo.c333
-rw-r--r--shared-core/nv50_graph.c301
-rw-r--r--shared-core/nv50_instmem.c262
-rw-r--r--shared-core/nv50_mc.c42
-rw-r--r--shared-core/r300_cmdbuf.c1
-rw-r--r--shared-core/r300_reg.h8
-rw-r--r--shared-core/radeon_irq.c9
-rw-r--r--shared-core/sis_drv.h8
28 files changed, 4081 insertions, 1258 deletions
diff --git a/shared-core/drm_pciids.txt b/shared-core/drm_pciids.txt
index ba02aa89..126974d0 100644
--- a/shared-core/drm_pciids.txt
+++ b/shared-core/drm_pciids.txt
@@ -211,6 +211,8 @@
0x1039 0x6300 0 "SiS 630"
0x1039 0x6330 SIS_CHIP_315 "SiS 661"
0x1039 0x7300 0 "SiS 730"
+0x18CA 0x0040 SIS_CHIP_315 "Volari V3XT/V5/V8"
+0x18CA 0x0042 SIS_CHIP_315 "Volari Unknown"
[tdfx]
0x121a 0x0003 0 "3dfx Voodoo Banshee"
@@ -594,6 +596,9 @@
0x10de 0x018d NV_17 "GeForce4 448 Go"
0x10de 0x0191 NV_50 "GeForce 8800 GTX"
0x10de 0x0193 NV_50 "GeForce 8800 GTS"
+0x10de 0x0194 NV_50 "GeForce 8800 Ultra"
+0x10de 0x019d NV_50 "Quadro FX 5600"
+0x10de 0x019e NV_50 "Quadro FX 4600"
0x10de 0x01a0 NV_11|NV_NFORCE "GeForce2 MX Integrated Graphics"
0x10de 0x01d1 NV_44 "GeForce 7300 LE"
0x10de 0x01d6 NV_44 "GeForce Go 7200"
@@ -700,6 +705,11 @@
0x10de 0x03d1 NV_44 "GeForce 6100 nForce 405"
0x10de 0x03d2 NV_44 "GeForce 6100 nForce 400"
0x10de 0x03d5 NV_44 "GeForce 6100 nForce 420"
+0x10de 0x0400 NV_50 "GeForce 8600 GTS"
+0x10de 0x0402 NV_50 "GeForce 8600 GT"
+0x10de 0x0421 NV_50 "GeForce 8500 GT"
+0x10de 0x0422 NV_50 "GeForce 8400 GS"
+0x10de 0x0423 NV_50 "GeForce 8300 GS"
0x12d2 0x0008 NV_03 "NV1"
0x12d2 0x0009 NV_03 "DAC64"
0x12d2 0x0018 NV_03 "Riva128"
diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c
index dc00f983..2f6a6b95 100644
--- a/shared-core/i915_irq.c
+++ b/shared-core/i915_irq.c
@@ -719,7 +719,7 @@ void i915_driver_irq_postinstall(drm_device_t * dev)
INIT_LIST_HEAD(&dev_priv->vbl_swaps.head);
dev_priv->swaps_pending = 0;
- dev_priv->user_irq_lock = SPIN_LOCK_UNLOCKED;
+ spin_lock_init(&dev_priv->user_irq_lock);
dev_priv->user_irq_refcount = 0;
i915_enable_interrupt(dev);
diff --git a/shared-core/nouveau_drm.h b/shared-core/nouveau_drm.h
index 1e7322e0..78ab9508 100644
--- a/shared-core/nouveau_drm.h
+++ b/shared-core/nouveau_drm.h
@@ -25,9 +25,12 @@
#ifndef __NOUVEAU_DRM_H__
#define __NOUVEAU_DRM_H__
-#define NOUVEAU_DRM_HEADER_PATCHLEVEL 6
+#define NOUVEAU_DRM_HEADER_PATCHLEVEL 9
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,49 +39,54 @@ 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
#define NOUVEAU_MEM_FB_ACCEPTABLE 0x00000004
#define NOUVEAU_MEM_AGP_ACCEPTABLE 0x00000008
-#define NOUVEAU_MEM_PINNED 0x00000010
-#define NOUVEAU_MEM_USER_BACKED 0x00000020
-#define NOUVEAU_MEM_MAPPED 0x00000040
-#define NOUVEAU_MEM_INSTANCE 0x00000080 /* internal */
+#define NOUVEAU_MEM_PCI 0x00000010
+#define NOUVEAU_MEM_PCI_ACCEPTABLE 0x00000020
+#define NOUVEAU_MEM_PINNED 0x00000040
+#define NOUVEAU_MEM_USER_BACKED 0x00000080
+#define NOUVEAU_MEM_MAPPED 0x00000100
+#define NOUVEAU_MEM_INSTANCE 0x00000200 /* internal */
+#define NOUVEAU_MEM_NOTIFIER 0x00000400 /* internal */
typedef struct drm_nouveau_mem_alloc {
int flags;
int alignment;
uint64_t size; // in bytes
- uint64_t region_offset;
+ uint64_t offset;
+ drm_handle_t map_handle;
}
drm_nouveau_mem_alloc_t;
typedef struct drm_nouveau_mem_free {
- uint64_t region_offset;
+ uint64_t offset;
int flags;
}
drm_nouveau_mem_free_t;
@@ -91,6 +99,7 @@ drm_nouveau_mem_free_t;
#define NOUVEAU_GETPARAM_AGP_PHYSICAL 7
#define NOUVEAU_GETPARAM_FB_SIZE 8
#define NOUVEAU_GETPARAM_AGP_SIZE 9
+#define NOUVEAU_GETPARAM_PCI_PHYSICAL 10
typedef struct drm_nouveau_getparam {
uint64_t param;
uint64_t value;
@@ -141,8 +150,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
diff --git a/shared-core/nouveau_drv.h b/shared-core/nouveau_drv.h
index debee8e4..99ddb586 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 6
+#define DRIVER_PATCHLEVEL 9
#define NOUVEAU_FAMILY 0x0000FFFF
#define NOUVEAU_FLAGS 0xFFFF0000
@@ -50,6 +50,7 @@ struct mem_block {
DRMFILE filp; /* 0: free, -1: heap, other: real files */
int flags;
drm_local_map_t *map;
+ drm_handle_t map_handle;
};
enum nouveau_flags {
@@ -57,39 +58,71 @@ enum nouveau_flags {
NV_NFORCE2 =0x20000000
};
-struct nouveau_object
-{
- struct nouveau_object *next;
- struct nouveau_object *prev;
- int channel;
+#define NVOBJ_ENGINE_SW 0
+#define NVOBJ_ENGINE_GR 1
+#define NVOBJ_ENGINE_INT 0xdeadbeef
- struct mem_block *instance;
- uint32_t ht_loc;
+#define NVOBJ_FLAG_ALLOW_NO_REFS (1 << 0)
+#define NVOBJ_FLAG_ZERO_ALLOC (1 << 1)
+#define NVOBJ_FLAG_ZERO_FREE (1 << 2)
+#define NVOBJ_FLAG_FAKE (1 << 3)
+typedef struct nouveau_gpuobj {
+ struct nouveau_gpuobj *next;
+ struct nouveau_gpuobj *prev;
- uint32_t handle;
- int class;
- int engine;
-};
+ int im_channel;
+ struct mem_block *im_pramin;
+ struct mem_block *im_backing;
+ int im_bound;
+
+ uint32_t flags;
+ int refcount;
+
+ uint32_t engine;
+ uint32_t class;
+} nouveau_gpuobj_t;
+
+typedef struct nouveau_gpuobj_ref {
+ struct nouveau_gpuobj_ref *next;
+
+ nouveau_gpuobj_t *gpuobj;
+ uint32_t instance;
+
+ int channel;
+ int handle;
+} nouveau_gpuobj_ref_t;
struct nouveau_fifo
{
- int used;
/* owner of this fifo */
DRMFILE filp;
/* mapping of the fifo itself */
drm_local_map_t *map;
/* mapping of the regs controling the fifo */
drm_local_map_t *regs;
- /* dma object for the command buffer itself */
- struct mem_block *cmdbuf_mem;
- struct nouveau_object *cmdbuf_obj;
- /* PGRAPH context, for cards that keep it in RAMIN */
- struct mem_block *ramin_grctx;
- /* objects belonging to this fifo */
- struct nouveau_object *objs;
-
- /* XXX dynamic alloc ? */
- uint32_t pgraph_ctx [340];
+
+ /* DMA push buffer */
+ nouveau_gpuobj_ref_t *pushbuf;
+ struct mem_block *pushbuf_mem;
+ uint32_t pushbuf_base;
+
+ /* Notifier memory */
+ struct mem_block *notifier_block;
+ struct mem_block *notifier_heap;
+ drm_local_map_t *notifier_map;
+
+ /* PFIFO context */
+ nouveau_gpuobj_ref_t *ramfc;
+
+ /* PGRAPH context */
+ nouveau_gpuobj_ref_t *ramin_grctx;
+ uint32_t pgraph_ctx [340]; /* XXX dynamic alloc ? */
+
+ /* Objects */
+ nouveau_gpuobj_ref_t *ramin; /* Private instmem */
+ struct mem_block *ramin_heap; /* Private PRAMIN heap */
+ nouveau_gpuobj_ref_t *ramht; /* Hash table */
+ nouveau_gpuobj_ref_t *ramht_refs; /* Objects referenced by RAMHT */
};
struct nouveau_config {
@@ -99,34 +132,65 @@ struct nouveau_config {
} cmdbuf;
};
-struct nouveau_engine_func {
+typedef struct nouveau_engine_func {
struct {
- int (*Init)(drm_device_t *dev);
- void (*Takedown)(drm_device_t *dev);
- } Mc;
+ void *priv;
+
+ int (*init)(drm_device_t *dev);
+ void (*takedown)(drm_device_t *dev);
+
+ int (*populate)(drm_device_t *, nouveau_gpuobj_t *,
+ uint32_t *size);
+ void (*clear)(drm_device_t *, nouveau_gpuobj_t *);
+ int (*bind)(drm_device_t *, nouveau_gpuobj_t *);
+ int (*unbind)(drm_device_t *, nouveau_gpuobj_t *);
+ } instmem;
struct {
- int (*Init)(drm_device_t *dev);
- void (*Takedown)(drm_device_t *dev);
- } Timer;
+ int (*init)(drm_device_t *dev);
+ void (*takedown)(drm_device_t *dev);
+ } mc;
struct {
- int (*Init)(drm_device_t *dev);
- void (*Takedown)(drm_device_t *dev);
- } Fb;
+ int (*init)(drm_device_t *dev);
+ void (*takedown)(drm_device_t *dev);
+ } timer;
struct {
- int (*Init)(drm_device_t *dev);
- void (*Takedown)(drm_device_t *dev);
- } Graph;
+ int (*init)(drm_device_t *dev);
+ void (*takedown)(drm_device_t *dev);
+ } fb;
struct {
- int (*Init)(drm_device_t *dev);
- void (*Takedown)(drm_device_t *dev);
- } Fifo;
-};
+ int (*init)(drm_device_t *);
+ void (*takedown)(drm_device_t *);
+
+ int (*create_context)(drm_device_t *, int channel);
+ void (*destroy_context)(drm_device_t *, int channel);
+ int (*load_context)(drm_device_t *, int channel);
+ int (*save_context)(drm_device_t *, int channel);
+ } graph;
+
+ struct {
+ void *priv;
+
+ int (*init)(drm_device_t *);
+ void (*takedown)(drm_device_t *);
+
+ int (*create_context)(drm_device_t *, int channel);
+ void (*destroy_context)(drm_device_t *, int channel);
+ int (*load_context)(drm_device_t *, int channel);
+ int (*save_context)(drm_device_t *, int channel);
+ } fifo;
+} nouveau_engine_func_t;
typedef struct drm_nouveau_private {
+ enum {
+ NOUVEAU_CARD_INIT_DOWN,
+ NOUVEAU_CARD_INIT_DONE,
+ NOUVEAU_CARD_INIT_FAILED
+ } init_state;
+
/* the card type, takes NV_* as values */
int card_type;
/* exact chipset, derived from NV_PMC_BOOT_0 */
@@ -138,12 +202,13 @@ typedef struct drm_nouveau_private {
drm_local_map_t *ramin; /* NV40 onwards */
int fifo_alloc_count;
- struct nouveau_fifo fifos[NV_MAX_FIFO_NUMBER];
+ struct nouveau_fifo *fifos[NV_MAX_FIFO_NUMBER];
struct nouveau_engine_func Engine;
/* RAMIN configuration, RAMFC, RAMHT and RAMRO offsets */
- uint32_t ramin_size;
+ nouveau_gpuobj_t *ramht;
+ uint32_t ramin_rsvd_vram;
uint32_t ramht_offset;
uint32_t ramht_size;
uint32_t ramht_bits;
@@ -165,12 +230,15 @@ typedef struct drm_nouveau_private {
struct mem_block *fb_heap;
struct mem_block *fb_nomap_heap;
struct mem_block *ramin_heap;
+ struct mem_block *pci_heap;
/* context table pointed to be NV_PGRAPH_CHANNEL_CTX_TABLE (0x400780) */
uint32_t ctx_table_size;
- struct mem_block *ctx_table;
+ nouveau_gpuobj_ref_t *ctx_table;
struct nouveau_config config;
+
+ nouveau_gpuobj_t *gpuobj_all;
}
drm_nouveau_private_t;
@@ -186,6 +254,13 @@ 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_takedown(struct mem_block **heap);
+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);
@@ -194,16 +269,13 @@ extern struct mem_block* nouveau_mem_alloc(struct drm_device *dev, int alignment
extern void nouveau_mem_free(struct drm_device* dev, struct mem_block*);
extern int nouveau_mem_init(struct drm_device *dev);
extern void nouveau_mem_close(struct drm_device *dev);
-extern int nouveau_instmem_init(struct drm_device *dev);
-extern struct mem_block* nouveau_instmem_alloc(struct drm_device *dev,
- uint32_t size, uint32_t align);
-extern void nouveau_instmem_free(struct drm_device *dev,
- struct mem_block *block);
-extern uint32_t nouveau_instmem_r32(drm_nouveau_private_t *dev_priv,
- struct mem_block *mem, int index);
-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);
@@ -214,17 +286,28 @@ 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 void nouveau_object_cleanup(drm_device_t *dev, int channel);
-extern struct nouveau_object *
-nouveau_object_gr_create(drm_device_t *dev, int channel, int class);
-extern struct nouveau_object *
-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 uint32_t nouveau_chip_instance_get(drm_device_t *dev, struct mem_block *mem);
+extern void nouveau_gpuobj_takedown(drm_device_t *dev);
+extern int nouveau_gpuobj_channel_init(drm_device_t *, int channel,
+ uint32_t vram_h, uint32_t tt_h);
+extern void nouveau_gpuobj_channel_takedown(drm_device_t *, int channel);
+extern int nouveau_gpuobj_new(drm_device_t *, int channel, int size, int align,
+ uint32_t flags, nouveau_gpuobj_t **);
+extern int nouveau_gpuobj_del(drm_device_t *, nouveau_gpuobj_t **);
+extern int nouveau_gpuobj_ref_add(drm_device_t *, int channel, uint32_t handle,
+ nouveau_gpuobj_t *, nouveau_gpuobj_ref_t **);
+extern int nouveau_gpuobj_ref_del(drm_device_t *, nouveau_gpuobj_ref_t **);
+extern int nouveau_gpuobj_new_ref(drm_device_t *, int chan_obj, int chan_ref,
+ uint32_t handle, int size, int align,
+ uint32_t flags, nouveau_gpuobj_ref_t **);
+extern int nouveau_gpuobj_new_fake(drm_device_t *, uint32_t offset,
+ uint32_t size, uint32_t flags,
+ nouveau_gpuobj_t**, nouveau_gpuobj_ref_t**);
+extern int nouveau_gpuobj_dma_new(drm_device_t *, int channel, int class,
+ uint64_t offset, uint64_t size,
+ int access, int target, nouveau_gpuobj_t **);
+extern int nouveau_gpuobj_gr_new(drm_device_t *, int channel, int class,
+ nouveau_gpuobj_t **);
+extern int nouveau_ioctl_grobj_alloc(DRM_IOCTL_ARGS);
/* nouveau_irq.c */
extern irqreturn_t nouveau_irq_handler(DRM_IRQ_ARGS);
@@ -244,35 +327,100 @@ extern void nv10_fb_takedown(drm_device_t *dev);
extern int nv40_fb_init(drm_device_t *dev);
extern void nv40_fb_takedown(drm_device_t *dev);
+/* nv04_fifo.c */
+extern int nv04_fifo_create_context(drm_device_t *dev, int channel);
+extern void nv04_fifo_destroy_context(drm_device_t *dev, int channel);
+extern int nv04_fifo_load_context(drm_device_t *dev, int channel);
+extern int nv04_fifo_save_context(drm_device_t *dev, int channel);
+
+/* nv10_fifo.c */
+extern int nv10_fifo_create_context(drm_device_t *dev, int channel);
+extern void nv10_fifo_destroy_context(drm_device_t *dev, int channel);
+extern int nv10_fifo_load_context(drm_device_t *dev, int channel);
+extern int nv10_fifo_save_context(drm_device_t *dev, int channel);
+
+/* nv40_fifo.c */
+extern int nv40_fifo_create_context(drm_device_t *, int channel);
+extern void nv40_fifo_destroy_context(drm_device_t *, int channel);
+extern int nv40_fifo_load_context(drm_device_t *, int channel);
+extern int nv40_fifo_save_context(drm_device_t *, int channel);
+
+/* nv50_fifo.c */
+extern int nv50_fifo_init(drm_device_t *);
+extern void nv50_fifo_takedown(drm_device_t *);
+extern int nv50_fifo_create_context(drm_device_t *, int channel);
+extern void nv50_fifo_destroy_context(drm_device_t *, int channel);
+extern int nv50_fifo_load_context(drm_device_t *, int channel);
+extern int nv50_fifo_save_context(drm_device_t *, int channel);
+
/* nv04_graph.c */
extern void nouveau_nv04_context_switch(drm_device_t *dev);
-extern int nv04_graph_init(drm_device_t *dev);
+extern int nv04_graph_init(drm_device_t *dev);
extern void nv04_graph_takedown(drm_device_t *dev);
-extern int nv04_graph_context_create(drm_device_t *dev, int channel);
+extern int nv04_graph_create_context(drm_device_t *dev, int channel);
+extern void nv04_graph_destroy_context(drm_device_t *dev, int channel);
+extern int nv04_graph_load_context(drm_device_t *dev, int channel);
+extern int nv04_graph_save_context(drm_device_t *dev, int channel);
/* nv10_graph.c */
extern void nouveau_nv10_context_switch(drm_device_t *dev);
-extern int nv10_graph_init(drm_device_t *dev);
+extern int nv10_graph_init(drm_device_t *dev);
extern void nv10_graph_takedown(drm_device_t *dev);
-extern int nv10_graph_context_create(drm_device_t *dev, int channel);
+extern int nv10_graph_create_context(drm_device_t *dev, int channel);
+extern void nv10_graph_destroy_context(drm_device_t *dev, int channel);
+extern int nv10_graph_load_context(drm_device_t *dev, int channel);
+extern int nv10_graph_save_context(drm_device_t *dev, int channel);
/* nv20_graph.c */
extern void nouveau_nv20_context_switch(drm_device_t *dev);
-extern int nv20_graph_init(drm_device_t *dev);
+extern int nv20_graph_init(drm_device_t *dev);
extern void nv20_graph_takedown(drm_device_t *dev);
-extern int nv20_graph_context_create(drm_device_t *dev, int channel);
+extern int nv20_graph_create_context(drm_device_t *dev, int channel);
+extern void nv20_graph_destroy_context(drm_device_t *dev, int channel);
+extern int nv20_graph_load_context(drm_device_t *dev, int channel);
+extern int nv20_graph_save_context(drm_device_t *dev, int channel);
/* nv30_graph.c */
-extern int nv30_graph_init(drm_device_t *dev);
+extern int nv30_graph_init(drm_device_t *dev);
extern void nv30_graph_takedown(drm_device_t *dev);
-extern int nv30_graph_context_create(drm_device_t *dev, int channel);
+extern int nv30_graph_create_context(drm_device_t *, int channel);
+extern void nv30_graph_destroy_context(drm_device_t *, int channel);
+extern int nv30_graph_load_context(drm_device_t *, int channel);
+extern int nv30_graph_save_context(drm_device_t *, int channel);
/* nv40_graph.c */
-extern int nv40_graph_init(drm_device_t *dev);
-extern void nv40_graph_takedown(drm_device_t *dev);
-extern int nv40_graph_context_create(drm_device_t *dev, int channel);
-extern void nv40_graph_context_save_current(drm_device_t *dev);
-extern void nv40_graph_context_restore(drm_device_t *dev, int channel);
+extern int nv40_graph_init(drm_device_t *);
+extern void nv40_graph_takedown(drm_device_t *);
+extern int nv40_graph_create_context(drm_device_t *, int channel);
+extern void nv40_graph_destroy_context(drm_device_t *, int channel);
+extern int nv40_graph_load_context(drm_device_t *, int channel);
+extern int nv40_graph_save_context(drm_device_t *, int channel);
+
+/* nv50_graph.c */
+extern int nv50_graph_init(drm_device_t *);
+extern void nv50_graph_takedown(drm_device_t *);
+extern int nv50_graph_create_context(drm_device_t *, int channel);
+extern void nv50_graph_destroy_context(drm_device_t *, int channel);
+extern int nv50_graph_load_context(drm_device_t *, int channel);
+extern int nv50_graph_save_context(drm_device_t *, int channel);
+
+/* nv04_instmem.c */
+extern int nv04_instmem_init(drm_device_t *dev);
+extern void nv04_instmem_takedown(drm_device_t *dev);
+extern int nv04_instmem_populate(drm_device_t*, nouveau_gpuobj_t*,
+ uint32_t *size);
+extern void nv04_instmem_clear(drm_device_t*, nouveau_gpuobj_t*);
+extern int nv04_instmem_bind(drm_device_t*, nouveau_gpuobj_t*);
+extern int nv04_instmem_unbind(drm_device_t*, nouveau_gpuobj_t*);
+
+/* nv50_instmem.c */
+extern int nv50_instmem_init(drm_device_t *dev);
+extern void nv50_instmem_takedown(drm_device_t *dev);
+extern int nv50_instmem_populate(drm_device_t*, nouveau_gpuobj_t*,
+ uint32_t *size);
+extern void nv50_instmem_clear(drm_device_t*, nouveau_gpuobj_t*);
+extern int nv50_instmem_bind(drm_device_t*, nouveau_gpuobj_t*);
+extern int nv50_instmem_unbind(drm_device_t*, nouveau_gpuobj_t*);
/* nv04_mc.c */
extern int nv04_mc_init(drm_device_t *dev);
@@ -282,6 +430,10 @@ extern void nv04_mc_takedown(drm_device_t *dev);
extern int nv40_mc_init(drm_device_t *dev);
extern void nv40_mc_takedown(drm_device_t *dev);
+/* nv50_mc.c */
+extern int nv50_mc_init(drm_device_t *dev);
+extern void nv50_mc_takedown(drm_device_t *dev);
+
/* nv04_timer.c */
extern int nv04_timer_init(drm_device_t *dev);
extern void nv04_timer_takedown(drm_device_t *dev);
@@ -297,8 +449,17 @@ extern long nouveau_compat_ioctl(struct file *filp, unsigned int cmd,
#define NV_WRITE(reg,val) DRM_WRITE32( dev_priv->mmio, (reg), (val) )
#endif
-#define INSTANCE_WR(mem,ofs,val) nouveau_instmem_w32(dev_priv,(mem),(ofs),(val))
-#define INSTANCE_RD(mem,ofs) nouveau_instmem_r32(dev_priv,(mem),(ofs))
+/* PRAMIN access */
+#if defined(__powerpc__)
+#define NV_RI32(o) in_be32((void __iomem *)(dev_priv->ramin)->handle+(o))
+#define NV_WI32(o,v) out_be32((void __iomem*)(dev_priv->ramin)->handle+(o), (v))
+#else
+#define NV_RI32(o) DRM_READ32(dev_priv->ramin, (o))
+#define NV_WI32(o,v) DRM_WRITE32(dev_priv->ramin, (o), (v))
+#endif
+
+#define INSTANCE_RD(o,i) NV_RI32((o)->im_pramin->start + ((i)<<2))
+#define INSTANCE_WR(o,i,v) NV_WI32((o)->im_pramin->start + ((i)<<2), (v))
#endif /* __NOUVEAU_DRV_H__ */
diff --git a/shared-core/nouveau_fifo.c b/shared-core/nouveau_fifo.c
index 8e66ca2e..7114a931 100644
--- a/shared-core/nouveau_fifo.c
+++ b/shared-core/nouveau_fifo.c
@@ -39,6 +39,8 @@ int nouveau_fifo_number(drm_device_t* dev)
case NV_04:
case NV_05:
return 16;
+ case NV_50:
+ return 128;
default:
return 32;
}
@@ -83,6 +85,8 @@ static int nouveau_fifo_instmem_configure(drm_device_t *dev)
case NV_50:
case NV_40:
NV_WRITE(NV40_PFIFO_RAMFC, 0x30002);
+ if((dev_priv->chipset == 0x49) || (dev_priv->chipset == 0x4b))
+ NV_WRITE(0x2230,0x00000001);
break;
case NV_44:
NV_WRITE(NV40_PFIFO_RAMFC, ((nouveau_mem_fb_amount(dev)-512*1024+dev_priv->ramfc_offset)>>16) |
@@ -184,10 +188,12 @@ static int
nouveau_fifo_cmdbuf_alloc(struct drm_device *dev, int channel)
{
drm_nouveau_private_t *dev_priv = dev->dev_private;
+ struct nouveau_fifo *chan = dev_priv->fifos[channel];
struct nouveau_config *config = &dev_priv->config;
struct mem_block *cb;
- struct nouveau_object *cb_dma = NULL;
int cb_min_size = max(NV03_FIFO_SIZE,PAGE_SIZE);
+ nouveau_gpuobj_t *pushbuf = NULL;
+ int ret;
/* Defaults for unconfigured values */
if (!config->cmdbuf.location)
@@ -204,263 +210,61 @@ nouveau_fifo_cmdbuf_alloc(struct drm_device *dev, int channel)
}
if (cb->flags & NOUVEAU_MEM_AGP) {
- cb_dma = nouveau_object_dma_create(dev, channel,
+ DRM_DEBUG("Creating CB in AGP memory\n");
+ ret = nouveau_gpuobj_dma_new(dev, channel,
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_object_dma_create(dev, channel,
+ cb->start, cb->size,
+ NV_DMA_ACCESS_RO, NV_DMA_TARGET_AGP, &pushbuf);
+ } else if ( cb->flags & NOUVEAU_MEM_PCI) {
+ DRM_DEBUG("Creating CB in PCI memory\n");
+ ret = nouveau_gpuobj_dma_new(dev, channel,
NV_CLASS_DMA_IN_MEMORY,
- cb->start - drm_get_resource_start(dev, 1),
+ cb->start,
cb->size,
- NV_DMA_ACCESS_RO, NV_DMA_TARGET_VIDMEM);
+ NV_DMA_ACCESS_RO, NV_DMA_TARGET_PCI_NONLINEAR, &pushbuf);
+ } else if (dev_priv->card_type != NV_04) {
+ ret = nouveau_gpuobj_dma_new
+ (dev, channel, NV_CLASS_DMA_IN_MEMORY,
+ cb->start,
+ cb->size, NV_DMA_ACCESS_RO, NV_DMA_TARGET_VIDMEM,
+ &pushbuf);
} else {
/* NV04 cmdbuf hack, from original ddx.. not sure of it's
* exact reason for existing :) PCI access to cmdbuf in
* VRAM.
*/
- cb_dma = nouveau_object_dma_create(dev, channel,
- NV_CLASS_DMA_IN_MEMORY,
- cb->start, cb->size,
- NV_DMA_ACCESS_RO, NV_DMA_TARGET_PCI);
+ ret = nouveau_gpuobj_dma_new
+ (dev, channel, NV_CLASS_DMA_IN_MEMORY,
+ cb->start + drm_get_resource_start(dev, 1),
+ cb->size, NV_DMA_ACCESS_RO,
+ NV_DMA_TARGET_PCI, &pushbuf);
}
- if (!cb_dma) {
+ if (ret) {
nouveau_mem_free(dev, cb);
- DRM_ERROR("Failed to alloc DMA object for command buffer\n");
- return DRM_ERR(ENOMEM);
+ DRM_ERROR("Error creating push buffer ctxdma: %d\n", ret);
+ return ret;
}
- dev_priv->fifos[channel].cmdbuf_mem = cb;
- dev_priv->fifos[channel].cmdbuf_obj = cb_dma;
- return 0;
-}
-
-#define RAMFC_WR(offset, val) NV_WRITE(fifoctx + NV04_RAMFC_##offset, (val))
-static void nouveau_nv04_context_init(drm_device_t *dev, int channel)
-{
- drm_nouveau_private_t *dev_priv = dev->dev_private;
- struct nouveau_object *cb_obj;
- uint32_t fifoctx, ctx_size = 32;
- int i;
-
- cb_obj = dev_priv->fifos[channel].cmdbuf_obj;
-
- fifoctx=NV_RAMIN+dev_priv->ramfc_offset+channel*ctx_size;
-
- // clear the fifo context
- for(i=0;i<ctx_size/4;i++)
- NV_WRITE(fifoctx+4*i,0x0);
-
- RAMFC_WR(DMA_INSTANCE , nouveau_chip_instance_get(dev, cb_obj->instance));
-
- RAMFC_WR(DMA_FETCH, NV_PFIFO_CACHE1_DMA_FETCH_TRIG_112_BYTES |
- NV_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES |
- NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_4 |
-#ifdef __BIG_ENDIAN
- NV_PFIFO_CACHE1_BIG_ENDIAN |
-#endif
- 0x00000000);
-}
-#undef RAMFC_WR
-
-#define RAMFC_WR(offset, val) NV_WRITE(fifoctx + NV10_RAMFC_##offset, (val))
-static void nouveau_nv10_context_init(drm_device_t *dev, int channel)
-{
- drm_nouveau_private_t *dev_priv = dev->dev_private;
- struct nouveau_object *cb_obj;
- uint32_t fifoctx;
- int ctx_size = nouveau_fifo_ctx_size(dev);
- int i;
- cb_obj = dev_priv->fifos[channel].cmdbuf_obj;
- fifoctx = NV_RAMIN + dev_priv->ramfc_offset + channel*ctx_size;
-
- for (i=0;i<ctx_size;i+=4)
- NV_WRITE(fifoctx + i, 0);
-
- /* Fill entries that are seen filled in dumps of nvidia driver just
- * after channel's is put into DMA mode
- */
-
- RAMFC_WR(DMA_INSTANCE , nouveau_chip_instance_get(dev,
- cb_obj->instance));
-
- RAMFC_WR(DMA_FETCH, NV_PFIFO_CACHE1_DMA_FETCH_TRIG_112_BYTES |
- NV_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES |
- NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_4 |
-#ifdef __BIG_ENDIAN
- NV_PFIFO_CACHE1_BIG_ENDIAN |
-#endif
- 0x00000000);
-}
-
-static void nouveau_nv30_context_init(drm_device_t *dev, int channel)
-{
- drm_nouveau_private_t *dev_priv = dev->dev_private;
- struct nouveau_fifo *chan = &dev_priv->fifos[channel];
- struct nouveau_object *cb_obj;
- uint32_t fifoctx, grctx_inst, cb_inst, ctx_size = 64;
- int i;
-
- cb_obj = dev_priv->fifos[channel].cmdbuf_obj;
- cb_inst = nouveau_chip_instance_get(dev, chan->cmdbuf_obj->instance);
- grctx_inst = nouveau_chip_instance_get(dev, chan->ramin_grctx);
- fifoctx = NV_RAMIN + dev_priv->ramfc_offset + channel * ctx_size;
-
- for (i = 0; i < ctx_size; i += 4)
- NV_WRITE(fifoctx + i, 0);
-
- RAMFC_WR(REF_CNT, NV_READ(NV10_PFIFO_CACHE1_REF_CNT));
- RAMFC_WR(DMA_INSTANCE, cb_inst);
- RAMFC_WR(DMA_STATE, NV_READ(NV04_PFIFO_CACHE1_DMA_STATE));
- RAMFC_WR(DMA_FETCH, NV_PFIFO_CACHE1_DMA_FETCH_TRIG_128_BYTES |
- NV_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES |
- NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_8 |
-#ifdef __BIG_ENDIAN
- NV_PFIFO_CACHE1_BIG_ENDIAN |
-#endif
- 0x00000000);
-
- RAMFC_WR(ENGINE, NV_READ(NV04_PFIFO_CACHE1_ENGINE));
- RAMFC_WR(PULL1_ENGINE, NV_READ(NV04_PFIFO_CACHE1_PULL1));
- RAMFC_WR(ACQUIRE_VALUE, NV_READ(NV10_PFIFO_CACHE1_ACQUIRE_VALUE));
- RAMFC_WR(ACQUIRE_TIMESTAMP, NV_READ(NV10_PFIFO_CACHE1_ACQUIRE_TIMESTAMP));
- RAMFC_WR(ACQUIRE_TIMEOUT, NV_READ(NV10_PFIFO_CACHE1_ACQUIRE_TIMEOUT));
- RAMFC_WR(SEMAPHORE, NV_READ(NV10_PFIFO_CACHE1_SEMAPHORE));
-}
-
-#if 0
-static void nouveau_nv10_context_save(drm_device_t *dev)
-{
- drm_nouveau_private_t *dev_priv = dev->dev_private;
- uint32_t fifoctx;
- int channel;
-
- channel = NV_READ(NV03_PFIFO_CACHE1_PUSH1) & (nouveau_fifo_number(dev)-1);
- fifoctx = NV_RAMIN + dev_priv->ramfc_offset + channel*64;
-
- RAMFC_WR(DMA_PUT , NV_READ(NV04_PFIFO_CACHE1_DMA_PUT));
- RAMFC_WR(DMA_GET , NV_READ(NV04_PFIFO_CACHE1_DMA_GET));
- RAMFC_WR(REF_CNT , NV_READ(NV10_PFIFO_CACHE1_REF_CNT));
- RAMFC_WR(DMA_INSTANCE , NV_READ(NV04_PFIFO_CACHE1_DMA_INSTANCE));
- RAMFC_WR(DMA_STATE , NV_READ(NV04_PFIFO_CACHE1_DMA_STATE));
- RAMFC_WR(DMA_FETCH , NV_READ(NV04_PFIFO_CACHE1_DMA_FETCH));
- RAMFC_WR(ENGINE , NV_READ(NV04_PFIFO_CACHE1_ENGINE));
- RAMFC_WR(PULL1_ENGINE , NV_READ(NV04_PFIFO_CACHE1_PULL1));
- RAMFC_WR(ACQUIRE_VALUE , NV_READ(NV10_PFIFO_CACHE1_ACQUIRE_VALUE));
- RAMFC_WR(ACQUIRE_TIMESTAMP, NV_READ(NV10_PFIFO_CACHE1_ACQUIRE_TIMESTAMP));
- RAMFC_WR(ACQUIRE_TIMEOUT , NV_READ(NV10_PFIFO_CACHE1_ACQUIRE_TIMEOUT));
- RAMFC_WR(SEMAPHORE , NV_READ(NV10_PFIFO_CACHE1_SEMAPHORE));
- RAMFC_WR(DMA_SUBROUTINE , NV_READ(NV10_PFIFO_CACHE1_DMA_SUBROUTINE));
-}
-#endif
-#undef RAMFC_WR
-
-#define RAMFC_WR(offset, val) NV_WRITE(fifoctx + NV40_RAMFC_##offset, (val))
-static void nouveau_nv40_context_init(drm_device_t *dev, int channel)
-{
- drm_nouveau_private_t *dev_priv = dev->dev_private;
- struct nouveau_fifo *chan = &dev_priv->fifos[channel];
- uint32_t fifoctx, cb_inst, grctx_inst;
- int i;
-
- cb_inst = nouveau_chip_instance_get(dev, chan->cmdbuf_obj->instance);
- grctx_inst = nouveau_chip_instance_get(dev, chan->ramin_grctx);
- fifoctx = NV_RAMIN + dev_priv->ramfc_offset + channel*128;
- for (i=0;i<128;i+=4)
- NV_WRITE(fifoctx + i, 0);
-
- /* Fill entries that are seen filled in dumps of nvidia driver just
- * after channel's is put into DMA mode
- */
- RAMFC_WR(DMA_INSTANCE , cb_inst);
- RAMFC_WR(DMA_FETCH , NV_PFIFO_CACHE1_DMA_FETCH_TRIG_128_BYTES |
- NV_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES |
- NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_8 |
-#ifdef __BIG_ENDIAN
- NV_PFIFO_CACHE1_BIG_ENDIAN |
-#endif
- 0x30000000 /* no idea.. */);
- RAMFC_WR(GRCTX_INSTANCE, grctx_inst);
- RAMFC_WR(DMA_TIMESLICE , 0x0001FFFF);
-}
-
-static void nouveau_nv40_context_save(drm_device_t *dev)
-{
- drm_nouveau_private_t *dev_priv = dev->dev_private;
- uint32_t fifoctx;
- int channel;
-
- channel = NV_READ(NV03_PFIFO_CACHE1_PUSH1) & (nouveau_fifo_number(dev)-1);
- fifoctx = NV_RAMIN + dev_priv->ramfc_offset + channel*128;
-
- RAMFC_WR(DMA_PUT , NV_READ(NV04_PFIFO_CACHE1_DMA_PUT));
- RAMFC_WR(DMA_GET , NV_READ(NV04_PFIFO_CACHE1_DMA_GET));
- RAMFC_WR(REF_CNT , NV_READ(NV10_PFIFO_CACHE1_REF_CNT));
- RAMFC_WR(DMA_INSTANCE , NV_READ(NV04_PFIFO_CACHE1_DMA_INSTANCE));
- RAMFC_WR(DMA_DCOUNT , NV_READ(NV10_PFIFO_CACHE1_DMA_DCOUNT));
- RAMFC_WR(DMA_STATE , NV_READ(NV04_PFIFO_CACHE1_DMA_STATE));
- RAMFC_WR(DMA_FETCH , NV_READ(NV04_PFIFO_CACHE1_DMA_FETCH));
- RAMFC_WR(ENGINE , NV_READ(NV04_PFIFO_CACHE1_ENGINE));
- RAMFC_WR(PULL1_ENGINE , NV_READ(NV04_PFIFO_CACHE1_PULL1));
- RAMFC_WR(ACQUIRE_VALUE , NV_READ(NV10_PFIFO_CACHE1_ACQUIRE_VALUE));
- RAMFC_WR(ACQUIRE_TIMESTAMP, NV_READ(NV10_PFIFO_CACHE1_ACQUIRE_TIMESTAMP));
- RAMFC_WR(ACQUIRE_TIMEOUT , NV_READ(NV10_PFIFO_CACHE1_ACQUIRE_TIMEOUT));
- RAMFC_WR(SEMAPHORE , NV_READ(NV10_PFIFO_CACHE1_SEMAPHORE));
- RAMFC_WR(DMA_SUBROUTINE , NV_READ(NV04_PFIFO_CACHE1_DMA_GET));
- RAMFC_WR(GRCTX_INSTANCE , NV_READ(NV40_PFIFO_GRCTX_INSTANCE));
- RAMFC_WR(DMA_TIMESLICE , NV_READ(NV04_PFIFO_DMA_TIMESLICE) & 0x1FFFF);
- RAMFC_WR(UNK_40 , NV_READ(NV40_PFIFO_UNK32E4));
-}
-#undef RAMFC_WR
-
-/* This function should load values from RAMFC into PFIFO, but for now
- * it just clobbers PFIFO with what nouveau_fifo_alloc used to setup
- * unconditionally.
- */
-static void
-nouveau_fifo_context_restore(drm_device_t *dev, int channel)
-{
- drm_nouveau_private_t *dev_priv = dev->dev_private;
- struct nouveau_fifo *chan = &dev_priv->fifos[channel];
- uint32_t cb_inst;
-
- cb_inst = nouveau_chip_instance_get(dev, chan->cmdbuf_obj->instance);
-
- // FIXME check if we need to refill the time quota with something like NV_WRITE(0x204C, 0x0003FFFF);
-
- if (dev_priv->card_type >= NV_40)
- NV_WRITE(NV03_PFIFO_CACHE1_PUSH1, 0x00010000|channel);
- else
- NV_WRITE(NV03_PFIFO_CACHE1_PUSH1, 0x00000100|channel);
-
- NV_WRITE(NV04_PFIFO_CACHE1_DMA_PUT, 0 /*RAMFC_DMA_PUT*/);
- NV_WRITE(NV04_PFIFO_CACHE1_DMA_GET, 0 /*RAMFC_DMA_GET*/);
- NV_WRITE(NV04_PFIFO_CACHE1_DMA_INSTANCE, cb_inst);
- NV_WRITE(NV04_PFIFO_SIZE , 0x0000FFFF);
- NV_WRITE(NV04_PFIFO_CACHE1_HASH, 0x0000FFFF);
-
- NV_WRITE(NV04_PFIFO_CACHE0_PULL1, 0x00000001);
- NV_WRITE(NV04_PFIFO_CACHE1_DMA_CTL, 0x00000000);
- NV_WRITE(NV04_PFIFO_CACHE1_DMA_STATE, 0x00000000);
- NV_WRITE(NV04_PFIFO_CACHE1_ENGINE, 0x00000000);
+ if ((ret = nouveau_gpuobj_ref_add(dev, channel, 0, pushbuf,
+ &chan->pushbuf))) {
+ DRM_ERROR("Error referencing push buffer ctxdma: %d\n", ret);
+ return ret;
+ }
- NV_WRITE(NV04_PFIFO_CACHE1_DMA_FETCH, NV_PFIFO_CACHE1_DMA_FETCH_TRIG_112_BYTES |
- NV_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES |
- NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_4 |
-#ifdef __BIG_ENDIAN
- NV_PFIFO_CACHE1_BIG_ENDIAN |
-#endif
- 0x00000000);
+ dev_priv->fifos[channel]->pushbuf_base = 0;
+ dev_priv->fifos[channel]->pushbuf_mem = cb;
+ return 0;
}
/* 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;
- struct nouveau_object *cb_obj;
+ nouveau_engine_func_t *engine = &dev_priv->Engine;
+ struct nouveau_fifo *chan;
int channel;
/*
@@ -471,21 +275,33 @@ static int nouveau_fifo_alloc(drm_device_t* dev, int *chan_ret, DRMFILE filp)
* (woo, full userspace command submission !)
* When there are no more contexts, you lost
*/
- for(channel=0; channel<nouveau_fifo_number(dev); channel++)
- if (dev_priv->fifos[channel].used==0)
+ for(channel=0; channel<nouveau_fifo_number(dev); channel++) {
+ if ((dev_priv->card_type == NV_50) && (channel == 0))
+ continue;
+ if (dev_priv->fifos[channel] == NULL)
break;
+ }
/* no more fifos. you lost. */
if (channel==nouveau_fifo_number(dev))
return DRM_ERR(EINVAL);
(*chan_ret) = channel;
+ dev_priv->fifos[channel] = drm_calloc(1, sizeof(struct nouveau_fifo),
+ DRM_MEM_DRIVER);
+ if (!dev_priv->fifos[channel])
+ return DRM_ERR(ENOMEM);
+ dev_priv->fifo_alloc_count++;
+ chan = dev_priv->fifos[channel];
+ chan->filp = filp;
+
DRM_INFO("Allocating FIFO number %d\n", channel);
- /* that fifo is used */
- dev_priv->fifos[channel].used = 1;
- dev_priv->fifos[channel].filp = filp;
- /* FIFO has no objects yet */
- dev_priv->fifos[channel].objs = NULL;
+ /* Setup channel's default objects */
+ ret = nouveau_gpuobj_channel_init(dev, channel, vram_handle, tt_handle);
+ if (ret) {
+ nouveau_fifo_free(dev, channel);
+ return ret;
+ }
/* allocate a command buffer, and create a dma object for the gpu */
ret = nouveau_fifo_cmdbuf_alloc(dev, channel);
@@ -493,7 +309,13 @@ static int nouveau_fifo_alloc(drm_device_t* dev, int *chan_ret, DRMFILE filp)
nouveau_fifo_free(dev, channel);
return ret;
}
- cb_obj = dev_priv->fifos[channel].cmdbuf_obj;
+
+ /* 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);
@@ -503,85 +325,67 @@ static int nouveau_fifo_alloc(drm_device_t* dev, int *chan_ret, DRMFILE filp)
NV_WRITE(NV03_PFIFO_CACHE1_PUSH0, 0x00000000);
NV_WRITE(NV04_PFIFO_CACHE1_PULL0, 0x00000000);
- /* Construct inital RAMFC for new channel */
- switch(dev_priv->card_type)
- {
- case NV_04:
- case NV_05:
- nv04_graph_context_create(dev, channel);
- nouveau_nv04_context_init(dev, channel);
- break;
- case NV_10:
- case NV_17:
- nv10_graph_context_create(dev, channel);
- nouveau_nv10_context_init(dev, channel);
- break;
- case NV_20:
- ret = nv20_graph_context_create(dev, channel);
- if (ret) {
- nouveau_fifo_free(dev, channel);
- return ret;
- }
- nouveau_nv10_context_init(dev, channel);
- break;
- case NV_30:
- ret = nv30_graph_context_create(dev, channel);
- if (ret) {
- nouveau_fifo_free(dev, channel);
- return ret;
- }
- nouveau_nv30_context_init(dev, channel);
- break;
- case NV_40:
- case NV_44:
- case NV_50:
- ret = nv40_graph_context_create(dev, channel);
- if (ret) {
- nouveau_fifo_free(dev, channel);
- return ret;
- }
- nouveau_nv40_context_init(dev, channel);
- break;
+ /* Create a graphics context for new channel */
+ ret = engine->graph.create_context(dev, channel);
+ if (ret) {
+ nouveau_fifo_free(dev, channel);
+ return ret;
}
- /* enable the fifo dma operation */
- NV_WRITE(NV04_PFIFO_MODE,NV_READ(NV04_PFIFO_MODE)|(1<<channel));
+ /* Construct inital RAMFC for new channel */
+ ret = engine->fifo.create_context(dev, channel);
+ if (ret) {
+ nouveau_fifo_free(dev, channel);
+ return ret;
+ }
/* setup channel's default get/put values */
- NV_WRITE(NV03_FIFO_REGS_DMAPUT(channel), 0);
- NV_WRITE(NV03_FIFO_REGS_DMAGET(channel), 0);
+ if (dev_priv->card_type < NV_50) {
+ NV_WRITE(NV03_FIFO_REGS_DMAPUT(channel), chan->pushbuf_base);
+ NV_WRITE(NV03_FIFO_REGS_DMAGET(channel), chan->pushbuf_base);
+ } else {
+ NV_WRITE(NV50_FIFO_REGS_DMAPUT(channel), chan->pushbuf_base);
+ NV_WRITE(NV50_FIFO_REGS_DMAGET(channel), chan->pushbuf_base);
+ }
/* If this is the first channel, setup PFIFO ourselves. For any
* other case, the GPU will handle this when it switches contexts.
*/
- if (dev_priv->fifo_alloc_count == 0) {
- nouveau_fifo_context_restore(dev, channel);
- if (dev_priv->card_type >= NV_30) {
- struct nouveau_fifo *chan;
- uint32_t inst;
-
- chan = &dev_priv->fifos[channel];
- inst = nouveau_chip_instance_get(dev,
- chan->ramin_grctx);
-
- /* see comments in nv40_graph_context_restore() */
- NV_WRITE(NV10_PGRAPH_CHANNEL_CTX_SIZE, inst);
- if (dev_priv->card_type >= NV_40) {
- NV_WRITE(0x40032C, inst | 0x01000000);
- NV_WRITE(NV40_PFIFO_GRCTX_INSTANCE, inst);
- }
+ if (dev_priv->fifo_alloc_count == 1) {
+ ret = engine->fifo.load_context(dev, channel);
+ if (ret) {
+ nouveau_fifo_free(dev, channel);
+ return ret;
+ }
+
+ ret = engine->graph.load_context(dev, channel);
+ if (ret) {
+ nouveau_fifo_free(dev, channel);
+ return ret;
+ }
+
+ /* Temporary hack, to avoid breaking Xv on cards where the
+ * initial context value for 0x400710 doesn't have these bits
+ * set. Proper fix would be to find which object+method is
+ * responsible for modifying this state.
+ */
+ if (dev_priv->chipset >= 0x10 && dev_priv->chipset < 0x50) {
+ uint32_t tmp;
+ tmp = NV_READ(NV10_PGRAPH_SURFACE) & 0x0007ff00;
+ NV_WRITE(NV10_PGRAPH_SURFACE, tmp);
+ tmp = NV_READ(NV10_PGRAPH_SURFACE) | 0x00020100;
+ NV_WRITE(NV10_PGRAPH_SURFACE, tmp);
}
}
- NV_WRITE(NV04_PFIFO_CACHE1_DMA_PUSH, 0x00000001);
+ NV_WRITE(NV04_PFIFO_CACHE1_DMA_PUSH,
+ NV_READ(NV04_PFIFO_CACHE1_DMA_PUSH) | 1);
NV_WRITE(NV03_PFIFO_CACHE1_PUSH0, 0x00000001);
NV_WRITE(NV04_PFIFO_CACHE1_PULL0, 0x00000001);
NV_WRITE(NV04_PFIFO_CACHE1_PULL1, 0x00000001);
/* reenable the fifo caches */
- NV_WRITE(NV03_PFIFO_CACHES, 0x00000001);
-
- dev_priv->fifo_alloc_count++;
+ NV_WRITE(NV03_PFIFO_CACHES, 1);
DRM_INFO("%s: initialised FIFO %d\n", __func__, channel);
return 0;
@@ -591,50 +395,44 @@ static int nouveau_fifo_alloc(drm_device_t* dev, int *chan_ret, DRMFILE filp)
void nouveau_fifo_free(drm_device_t* dev, int channel)
{
drm_nouveau_private_t *dev_priv = dev->dev_private;
- struct nouveau_fifo *chan = &dev_priv->fifos[channel];
- int i;
- int ctx_size = nouveau_fifo_ctx_size(dev);
+ nouveau_engine_func_t *engine = &dev_priv->Engine;
+ struct nouveau_fifo *chan = dev_priv->fifos[channel];
+
+ if (!chan) {
+ DRM_ERROR("Freeing non-existant channel %d\n", channel);
+ return;
+ }
- chan->used = 0;
DRM_INFO("%s: freeing fifo %d\n", __func__, channel);
/* disable the fifo caches */
NV_WRITE(NV03_PFIFO_CACHES, 0x00000000);
- NV_WRITE(NV04_PFIFO_MODE, NV_READ(NV04_PFIFO_MODE)&~(1<<channel));
// FIXME XXX needs more code
-
- /* Clean RAMFC */
- for (i=0;i<ctx_size;i+=4) {
- DRM_DEBUG("RAMFC +%02x: 0x%08x\n", i, NV_READ(NV_RAMIN +
- dev_priv->ramfc_offset +
- channel*ctx_size + i));
- NV_WRITE(NV_RAMIN + dev_priv->ramfc_offset +
- channel*ctx_size + i, 0);
- }
+
+ engine->fifo.destroy_context(dev, channel);
/* Cleanup PGRAPH state */
- if (dev_priv->card_type >= NV_40)
- nouveau_instmem_free(dev, chan->ramin_grctx);
- else if (dev_priv->card_type >= NV_30) {
- }
- else if (dev_priv->card_type >= NV_20) {
- /* clear ctx table */
- INSTANCE_WR(dev_priv->ctx_table, channel, 0);
- nouveau_instmem_free(dev, chan->ramin_grctx);
- }
+ engine->graph.destroy_context(dev, channel);
/* reenable the fifo caches */
NV_WRITE(NV03_PFIFO_CACHES, 0x00000001);
- /* Deallocate command buffer */
- if (chan->cmdbuf_mem)
- nouveau_mem_free(dev, chan->cmdbuf_mem);
+ /* Deallocate push buffer */
+ nouveau_gpuobj_ref_del(dev, &chan->pushbuf);
+ if (chan->pushbuf_mem) {
+ nouveau_mem_free(dev, chan->pushbuf_mem);
+ chan->pushbuf_mem = NULL;
+ }
+
+ nouveau_notifier_takedown_channel(dev, channel);
/* Destroy objects belonging to the channel */
- nouveau_object_cleanup(dev, channel);
+ nouveau_gpuobj_channel_takedown(dev, channel);
+ dev_priv->fifos[channel] = NULL;
dev_priv->fifo_alloc_count--;
+ drm_free(chan, sizeof(*chan), DRM_MEM_DRIVER);
}
/* cleanups all the fifos from filp */
@@ -645,7 +443,7 @@ void nouveau_fifo_cleanup(drm_device_t* dev, DRMFILE filp)
DRM_DEBUG("clearing FIFO enables from filp\n");
for(i=0;i<nouveau_fifo_number(dev);i++)
- if (dev_priv->fifos[i].used && dev_priv->fifos[i].filp==filp)
+ if (dev_priv->fifos[i] && dev_priv->fifos[i]->filp==filp)
nouveau_fifo_free(dev,i);
}
@@ -656,9 +454,9 @@ nouveau_fifo_owner(drm_device_t *dev, DRMFILE filp, int channel)
if (channel >= nouveau_fifo_number(dev))
return 0;
- if (dev_priv->fifos[channel].used == 0)
+ if (dev_priv->fifos[channel] == NULL)
return 0;
- return (dev_priv->fifos[channel].filp == filp);
+ return (dev_priv->fifos[channel]->filp == filp);
}
/***********************************
@@ -670,30 +468,52 @@ static int nouveau_ioctl_fifo_alloc(DRM_IOCTL_ARGS)
DRM_DEVICE;
drm_nouveau_private_t *dev_priv = dev->dev_private;
drm_nouveau_fifo_alloc_t init;
+ drm_map_list_t *entry;
+ struct nouveau_fifo *chan;
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);
+ if (init.fb_ctxdma_handle == ~0 || init.tt_ctxdma_handle == ~0)
+ return DRM_ERR(EINVAL);
+
+ 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];
- /* this should probably disappear in the next abi break? */
- init.put_base = 0;
+ 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;
+ init.ctrl = dev_priv->mmio->offset;
+ if (dev_priv->card_type < NV_50) {
+ init.ctrl += NV03_FIFO_REGS(init.channel);
+ init.ctrl_size = NV03_FIFO_REGS_SIZE;
+ } else {
+ init.ctrl += NV50_FIFO_REGS(init.channel);
+ init.ctrl_size = NV50_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;
+ entry = drm_find_matching_map(dev, chan->regs);
+ if (!entry)
+ return DRM_ERR(EINVAL);
+ init.ctrl = entry->user_token;
+
/* 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->pushbuf_mem->map_handle;
+ init.cmdbuf_size = chan->pushbuf_mem->size;
+
+ /* and the notifier block */
+ init.notifier = chan->notifier_block->map_handle;
+ init.notifier_size = chan->notifier_block->size;
DRM_COPY_TO_USER_IOCTL((drm_nouveau_fifo_alloc_t __user *)data,
init, sizeof(init));
@@ -706,8 +526,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},
diff --git a/shared-core/nouveau_irq.c b/shared-core/nouveau_irq.c
index 8de6e705..b4102dd8 100644
--- a/shared-core/nouveau_irq.c
+++ b/shared-core/nouveau_irq.c
@@ -87,34 +87,14 @@ void nouveau_irq_postinstall(drm_device_t *dev)
DRM_DEBUG("IRQ: postinst\n");
/* Enable PFIFO error reporting */
- NV_WRITE(NV03_PFIFO_INTR_EN_0 ,
- NV_PFIFO_INTR_CACHE_ERROR |
- NV_PFIFO_INTR_RUNOUT |
- NV_PFIFO_INTR_RUNOUT_OVERFLOW |
- NV_PFIFO_INTR_DMA_PUSHER |
- NV_PFIFO_INTR_DMA_PT |
- NV_PFIFO_INTR_SEMAPHORE |
- NV_PFIFO_INTR_ACQUIRE_TIMEOUT
- );
+ NV_WRITE(NV03_PFIFO_INTR_EN_0, 0xFFFFFFFF);
NV_WRITE(NV03_PFIFO_INTR_0, 0xFFFFFFFF);
/* Enable PGRAPH interrupts */
if (dev_priv->card_type<NV_40)
- NV_WRITE(NV03_PGRAPH_INTR_EN,
- NV_PGRAPH_INTR_NOTIFY |
- NV_PGRAPH_INTR_MISSING_HW |
- NV_PGRAPH_INTR_CONTEXT_SWITCH |
- NV_PGRAPH_INTR_BUFFER_NOTIFY |
- NV_PGRAPH_INTR_ERROR
- );
+ NV_WRITE(NV03_PGRAPH_INTR_EN, 0xFFFFFFFF);
else
- NV_WRITE(NV40_PGRAPH_INTR_EN,
- NV_PGRAPH_INTR_NOTIFY |
- NV_PGRAPH_INTR_MISSING_HW |
- NV_PGRAPH_INTR_CONTEXT_SWITCH |
- NV_PGRAPH_INTR_BUFFER_NOTIFY |
- NV_PGRAPH_INTR_ERROR
- );
+ NV_WRITE(NV40_PGRAPH_INTR_EN, 0xFFFFFFFF);
NV_WRITE(NV03_PGRAPH_INTR, 0xFFFFFFFF);
#if 0
@@ -271,22 +251,25 @@ 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 channel, class;
uint32_t method, subc, data;
address = NV_READ(0x400704);
- data = NV_READ(0x400708);
channel = (address >> 20) & 0x1F;
subc = (address >> 16) & 0x7;
method = address & 0x1FFC;
+ data = NV_READ(0x400708);
+ if (dev_priv->card_type < NV_50) {
+ class = NV_READ(0x400160 + subc*4) & 0xFFFF;
+ } else {
+ class = NV_READ(0x400814);
+ }
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
+ channel, subc, class, method, data
);
}
@@ -314,7 +297,7 @@ static void nouveau_pgraph_irq_handler(drm_device_t *dev)
instance = NV_READ(0x00400158);
notify = NV_READ(0x00400150) >> 16;
DRM_DEBUG("instance:0x%08x\tnotify:0x%08x\n",
- nsource, nstatus);
+ instance, notify);
}
status &= ~NV_PGRAPH_INTR_NOTIFY;
diff --git a/shared-core/nouveau_mem.c b/shared-core/nouveau_mem.c
index a5343b99..79d1bb87 100644
--- a/shared-core/nouveau_mem.c
+++ b/shared-core/nouveau_mem.c
@@ -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);
@@ -188,7 +189,7 @@ void nouveau_mem_release(DRMFILE filp, struct mem_block *heap)
/*
* Cleanup everything
*/
-static void nouveau_mem_takedown(struct mem_block **heap)
+void nouveau_mem_takedown(struct mem_block **heap)
{
struct mem_block *p;
@@ -210,6 +211,10 @@ void nouveau_mem_close(struct drm_device *dev)
drm_nouveau_private_t *dev_priv = dev->dev_private;
nouveau_mem_takedown(&dev_priv->agp_heap);
nouveau_mem_takedown(&dev_priv->fb_heap);
+ if ( dev_priv->pci_heap )
+ {
+ nouveau_mem_takedown(&dev_priv->pci_heap);
+ }
}
/* returns the amount of FB ram in bytes */
@@ -282,8 +287,10 @@ int nouveau_mem_init(struct drm_device *dev)
{
drm_nouveau_private_t *dev_priv = dev->dev_private;
uint32_t fb_size;
+ drm_scatter_gather_t sgreq;
dev_priv->agp_phys=0;
dev_priv->fb_phys=0;
+ sgreq . size = 4 << 20; //4MB of PCI scatter-gather zone
/* init AGP */
dev_priv->agp_heap=NULL;
@@ -331,14 +338,36 @@ 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,
+ 0, info.aperture_size))
goto no_agp;
dev_priv->agp_phys = info.aperture_base;
dev_priv->agp_available_size = info.aperture_size;
+ goto have_agp;
}
+
no_agp:
+ if ( dev_priv->card_type >= NV_50 ) goto no_pci;
+
+ dev_priv->pci_heap = NULL;
+ DRM_DEBUG("Allocating sg memory for PCI DMA\n");
+ if ( drm_sg_alloc(dev, &sgreq) )
+ {
+ DRM_ERROR("Unable to allocate 4MB of scatter-gather pages for PCI DMA!");
+ goto no_pci;
+ }
+
+ if ( nouveau_mem_init_heap(&dev_priv->pci_heap, 0,
+ dev->sg->pages * PAGE_SIZE))
+ {
+ DRM_ERROR("Unable to initialize pci_heap!");
+ goto no_pci;
+ }
+
+no_pci:
+have_agp:
/* setup a mtrr over the FB */
dev_priv->fb_mtrr = drm_mtrr_add(drm_get_resource_start(dev, 1),
nouveau_mem_fb_amount(dev),
@@ -350,19 +379,21 @@ no_agp:
/* On at least NV40, RAMIN is actually at the end of vram.
* We don't want to allocate this... */
if (dev_priv->card_type >= NV_40)
- fb_size -= dev_priv->ramin_size;
+ fb_size -= dev_priv->ramin_rsvd_vram;
dev_priv->fb_available_size = fb_size;
DRM_DEBUG("Available VRAM: %dKiB\n", fb_size>>10);
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,
+ 0, 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,
+ 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, 0, fb_size))
return DRM_ERR(ENOMEM);
dev_priv->fb_nomap_heap=NULL;
}
@@ -395,25 +426,40 @@ struct mem_block* nouveau_mem_alloc(struct drm_device *dev, int alignment, uint6
if (size & (~PAGE_MASK))
size = ((size/PAGE_SIZE) + 1) * PAGE_SIZE;
- if (flags&NOUVEAU_MEM_AGP) {
- type=NOUVEAU_MEM_AGP;
- block = 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);
- if (block) goto alloc_ok;
- }
- block = 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);
- if (block) goto alloc_ok;
- }
+
+#define NOUVEAU_MEM_ALLOC_AGP {\
+ type=NOUVEAU_MEM_AGP;\
+ block = nouveau_mem_alloc_block(dev_priv->agp_heap, size,\
+ alignment, filp);\
+ if (block) goto alloc_ok;\
+ }
+
+#define NOUVEAU_MEM_ALLOC_PCI {\
+ type = NOUVEAU_MEM_PCI;\
+ block = nouveau_mem_alloc_block(dev_priv->pci_heap, size, alignment, filp);\
+ if ( block ) goto alloc_ok;\
+ }
+
+#define NOUVEAU_MEM_ALLOC_FB {\
+ type=NOUVEAU_MEM_FB;\
+ if (!(flags&NOUVEAU_MEM_MAPPED)) {\
+ block = nouveau_mem_alloc_block(dev_priv->fb_nomap_heap,\
+ size, alignment, filp); \
+ if (block) goto alloc_ok;\
+ }\
+ block = nouveau_mem_alloc_block(dev_priv->fb_heap, size,\
+ alignment, filp);\
+ if (block) goto alloc_ok;\
+ }
+
+
+ if (flags&NOUVEAU_MEM_FB) NOUVEAU_MEM_ALLOC_FB
+ if (flags&NOUVEAU_MEM_AGP) NOUVEAU_MEM_ALLOC_AGP
+ if (flags&NOUVEAU_MEM_PCI) NOUVEAU_MEM_ALLOC_PCI
+ if (flags&NOUVEAU_MEM_FB_ACCEPTABLE) NOUVEAU_MEM_ALLOC_FB
+ if (flags&NOUVEAU_MEM_AGP_ACCEPTABLE) NOUVEAU_MEM_ALLOC_AGP
+ if (flags&NOUVEAU_MEM_PCI_ACCEPTABLE) NOUVEAU_MEM_ALLOC_PCI
+
return NULL;
@@ -422,19 +468,32 @@ alloc_ok:
if (flags&NOUVEAU_MEM_MAPPED)
{
- int ret;
+ drm_map_list_t *entry;
+ int ret = 0;
block->flags|=NOUVEAU_MEM_MAPPED;
if (type == NOUVEAU_MEM_AGP)
- ret = drm_addmap(dev, block->start - dev->agp->base, block->size,
- _DRM_AGP, 0, &block->map);
- else
ret = drm_addmap(dev, block->start, block->size,
- _DRM_FRAME_BUFFER, 0, &block->map);
+ _DRM_AGP, 0, &block->map);
+ else if (type == NOUVEAU_MEM_FB)
+ ret = drm_addmap(dev, block->start + dev_priv->fb_phys,
+ block->size, _DRM_FRAME_BUFFER,
+ 0, &block->map);
+ else if (type == NOUVEAU_MEM_PCI)
+ ret = drm_addmap(dev, block->start, block->size,
+ _DRM_SCATTER_GATHER, 0, &block->map);
+
if (ret) {
- free_block(block);
+ nouveau_mem_free_block(block);
+ return NULL;
+ }
+
+ entry = drm_find_matching_map(dev, block->map);
+ if (!entry) {
+ nouveau_mem_free_block(block);
return NULL;
}
+ block->map_handle = entry->user_token;
}
DRM_INFO("allocated 0x%llx\n", block->start);
@@ -446,177 +505,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);
-}
-
-static void
-nouveau_instmem_determine_amount(struct drm_device *dev)
-{
- drm_nouveau_private_t *dev_priv = dev->dev_private;
- int i;
-
- /* Figure out how much instance memory we need */
- switch (dev_priv->card_type) {
- case NV_40:
- /* We'll want more instance memory than this on some NV4x cards.
- * There's a 16MB aperture to play with that maps onto the end
- * of vram. For now, only reserve a small piece until we know
- * more about what each chipset requires.
- */
- dev_priv->ramin_size = (1*1024* 1024);
- break;
- default:
- /*XXX: what *are* the limits on <NV40 cards?, and does RAMIN
- * exist in vram on those cards as well?
- */
- dev_priv->ramin_size = (512*1024);
- break;
- }
- DRM_DEBUG("RAMIN size: %dKiB\n", dev_priv->ramin_size>>10);
-
- /* Clear all of it, except the BIOS image that's in the first 64KiB */
- if (dev_priv->ramin) {
- for (i=(64*1024); i<dev_priv->ramin_size; i+=4)
- DRM_WRITE32(dev_priv->ramin, i, 0x00000000);
- } else {
- for (i=(64*1024); i<dev_priv->ramin_size; i+=4)
- DRM_WRITE32(dev_priv->mmio, NV_RAMIN + i, 0x00000000);
- }
-}
-
-static void
-nouveau_instmem_configure_fixed_tables(struct drm_device *dev)
-{
- drm_nouveau_private_t *dev_priv = dev->dev_private;
-
- /* FIFO hash table (RAMHT)
- * use 4k hash table at RAMIN+0x10000
- * TODO: extend the hash table
- */
- dev_priv->ramht_offset = 0x10000;
- dev_priv->ramht_bits = 9;
- dev_priv->ramht_size = (1 << dev_priv->ramht_bits);
- DRM_DEBUG("RAMHT offset=0x%x, size=%d\n", dev_priv->ramht_offset,
- dev_priv->ramht_size);
-
- /* FIFO runout table (RAMRO) - 512k at 0x11200 */
- dev_priv->ramro_offset = 0x11200;
- dev_priv->ramro_size = 512;
- DRM_DEBUG("RAMRO offset=0x%x, size=%d\n", dev_priv->ramro_offset,
- dev_priv->ramro_size);
-
- /* FIFO context table (RAMFC)
- * NV40 : Not sure exactly how to position RAMFC on some cards,
- * 0x30002 seems to position it at RAMIN+0x20000 on these
- * cards. RAMFC is 4kb (32 fifos, 128byte entries).
- * Others: Position RAMFC at RAMIN+0x11400
- */
- switch(dev_priv->card_type)
- {
- case NV_50:
- case NV_40:
- case NV_44:
- dev_priv->ramfc_offset = 0x20000;
- dev_priv->ramfc_size = nouveau_fifo_number(dev) *
- nouveau_fifo_ctx_size(dev);
- break;
- case NV_30:
- case NV_20:
- case NV_17:
- case NV_10:
- case NV_04:
- case NV_03:
- default:
- dev_priv->ramfc_offset = 0x11400;
- dev_priv->ramfc_size = nouveau_fifo_number(dev) *
- nouveau_fifo_ctx_size(dev);
- break;
- }
- DRM_DEBUG("RAMFC offset=0x%x, size=%d\n", dev_priv->ramfc_offset,
- dev_priv->ramfc_size);
-}
-
-int nouveau_instmem_init(struct drm_device *dev)
-{
- drm_nouveau_private_t *dev_priv = dev->dev_private;
- uint32_t offset;
- int ret = 0;
-
- nouveau_instmem_determine_amount(dev);
- nouveau_instmem_configure_fixed_tables(dev);
-
- /* Create a heap to manage RAMIN allocations, we don't allocate
- * 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);
- if (ret) {
- dev_priv->ramin_heap = NULL;
- DRM_ERROR("Failed to init RAMIN heap\n");
- }
-
- return ret;
-}
-
-struct mem_block *nouveau_instmem_alloc(struct drm_device *dev,
- uint32_t size, uint32_t align)
-{
- drm_nouveau_private_t *dev_priv = dev->dev_private;
- struct mem_block *block;
-
- if (!dev_priv->ramin_heap) {
- DRM_ERROR("instmem alloc called without init\n");
- return NULL;
- }
-
- block = 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",
- size, (1<<align), (uint32_t)block->start);
- }
-
- return block;
-}
-
-void nouveau_instmem_free(struct drm_device *dev, struct mem_block *block)
-{
- if (dev && block) {
- free_block(block);
- }
-}
-
-uint32_t nouveau_instmem_r32(drm_nouveau_private_t *dev_priv,
- struct mem_block *mem, int index)
-{
- uint32_t ofs = (uint32_t)mem->start + (index<<2);
-
- if (dev_priv->ramin) {
-#if defined(__powerpc__)
- return in_be32((void __iomem *)(dev_priv->ramin)->handle + ofs);
-#else
- return DRM_READ32(dev_priv->ramin, ofs);
-#endif
- } else {
- return NV_READ(NV_RAMIN+ofs);
- }
-}
-
-void nouveau_instmem_w32(drm_nouveau_private_t *dev_priv,
- struct mem_block *mem, int index, uint32_t val)
-{
- uint32_t ofs = (uint32_t)mem->start + (index<<2);
-
- if (dev_priv->ramin) {
-#if defined(__powerpc__)
- out_be32((void __iomem *)(dev_priv->ramin)->handle + ofs, val);
-#else
- DRM_WRITE32(dev_priv->ramin, ofs, val);
-#endif
- } else {
- NV_WRITE(NV_RAMIN+ofs, val);
- }
+ nouveau_mem_free_block(block);
}
/*
@@ -641,7 +530,8 @@ int nouveau_ioctl_mem_alloc(DRM_IOCTL_ARGS)
block=nouveau_mem_alloc(dev, alloc.alignment, alloc.size, alloc.flags, filp);
if (!block)
return DRM_ERR(ENOMEM);
- alloc.region_offset=block->start;
+ alloc.map_handle=block->map_handle;
+ alloc.offset=block->start;
alloc.flags=block->flags;
DRM_COPY_TO_USER_IOCTL((drm_nouveau_mem_alloc_t __user *) data, alloc, sizeof(alloc));
@@ -661,9 +551,11 @@ int nouveau_ioctl_mem_free(DRM_IOCTL_ARGS)
block=NULL;
if (memfree.flags&NOUVEAU_MEM_FB)
- block = find_block(dev_priv->fb_heap, memfree.region_offset);
+ block = find_block(dev_priv->fb_heap, memfree.offset);
else if (memfree.flags&NOUVEAU_MEM_AGP)
- block = find_block(dev_priv->agp_heap, memfree.region_offset);
+ block = find_block(dev_priv->agp_heap, memfree.offset);
+ else if (memfree.flags&NOUVEAU_MEM_PCI)
+ block = find_block(dev_priv->pci_heap, memfree.offset);
if (!block)
return DRM_ERR(EFAULT);
if (block->filp != filp)
diff --git a/shared-core/nouveau_notifier.c b/shared-core/nouveau_notifier.c
new file mode 100644
index 00000000..7d892064
--- /dev/null
+++ b/shared-core/nouveau_notifier.c
@@ -0,0 +1,151 @@
+/*
+ * 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;
+ flags |= NOUVEAU_MEM_MAPPED;
+
+ 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];
+ nouveau_gpuobj_t *nobj = NULL;
+ struct mem_block *mem;
+ uint32_t offset;
+ int target, ret;
+
+ 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) {
+ target = NV_DMA_TARGET_VIDMEM;
+ } else if (chan->notifier_block->flags & NOUVEAU_MEM_AGP) {
+ target = NV_DMA_TARGET_AGP;
+ } else {
+ DRM_ERROR("Bad DMA target, flags 0x%08x!\n",
+ chan->notifier_block->flags);
+ return DRM_ERR(EINVAL);
+ }
+
+ if ((ret = nouveau_gpuobj_dma_new(dev, channel, NV_CLASS_DMA_IN_MEMORY,
+ offset, mem->size,
+ NV_DMA_ACCESS_RW, target, &nobj))) {
+ nouveau_mem_free_block(mem);
+ DRM_ERROR("Error creating notifier ctxdma: %d\n", ret);
+ return ret;
+ }
+
+ if ((ret = nouveau_gpuobj_ref_add(dev, channel, handle, nobj, NULL))) {
+ nouveau_gpuobj_del(dev, &nobj);
+ nouveau_mem_free_block(mem);
+ DRM_ERROR("Error referencing notifier ctxdma: %d\n", ret);
+ return ret;
+ }
+
+ *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;
+}
+
diff --git a/shared-core/nouveau_object.c b/shared-core/nouveau_object.c
index e36568c6..16b38e95 100644
--- a/shared-core/nouveau_object.c
+++ b/shared-core/nouveau_object.c
@@ -35,79 +35,6 @@
#include "nouveau_drv.h"
#include "nouveau_drm.h"
-/* TODO
- * - Check object class, deny unsafe objects (add card-specific versioning?)
- * - Get rid of DMA object creation, this should be wrapped by MM routines.
- */
-
-/* Translate a RAMIN offset into a value the card understands, will be useful
- * in the future when we can access more instance ram which isn't mapped into
- * the PRAMIN aperture
- */
-uint32_t
-nouveau_chip_instance_get(drm_device_t *dev, struct mem_block *mem)
-{
- uint32_t inst = (uint32_t)mem->start >> 4;
- DRM_DEBUG("****** on-chip instance for 0x%016llx = 0x%08x\n",
- mem->start, inst);
- return inst;
-}
-
-static void
-nouveau_object_link(drm_device_t *dev, struct nouveau_object *obj)
-{
- drm_nouveau_private_t *dev_priv=dev->dev_private;
- struct nouveau_fifo *chan = &dev_priv->fifos[obj->channel];
-
- if (!chan->objs) {
- chan->objs = obj;
- return;
- }
-
- obj->prev = NULL;
- obj->next = chan->objs;
-
- chan->objs->prev = obj;
- chan->objs = obj;
-}
-
-static void
-nouveau_object_unlink(drm_device_t *dev, struct nouveau_object *obj)
-{
- drm_nouveau_private_t *dev_priv=dev->dev_private;
- struct nouveau_fifo *chan = &dev_priv->fifos[obj->channel];
-
- if (obj->prev == NULL) {
- if (obj->next)
- obj->next->prev = NULL;
- chan->objs = obj->next;
- } else if (obj->next == NULL) {
- if (obj->prev)
- obj->prev->next = NULL;
- } else {
- obj->prev->next = obj->next;
- obj->next->prev = obj->prev;
- }
-}
-
-static struct nouveau_object *
-nouveau_object_handle_find(drm_device_t *dev, int channel, uint32_t handle)
-{
- drm_nouveau_private_t *dev_priv=dev->dev_private;
- struct nouveau_fifo *chan = &dev_priv->fifos[channel];
- struct nouveau_object *obj = chan->objs;
-
- DRM_DEBUG("Looking for handle 0x%08x\n", handle);
- while (obj) {
- if (obj->handle == handle)
- return obj;
- obj = obj->next;
- }
-
- DRM_DEBUG("...couldn't find handle\n");
- return NULL;
-}
-
/* NVidia uses context objects to drive drawing operations.
Context objects can be selected into 8 subchannels in the FIFO,
@@ -139,7 +66,7 @@ nouveau_object_handle_find(drm_device_t *dev, int channel, uint32_t handle)
is given as:
*/
static uint32_t
-nouveau_ht_handle_hash(drm_device_t *dev, int channel, uint32_t handle)
+nouveau_ramht_hash_handle(drm_device_t *dev, int channel, uint32_t handle)
{
drm_nouveau_private_t *dev_priv=dev->dev_private;
uint32_t hash = 0;
@@ -149,120 +76,477 @@ nouveau_ht_handle_hash(drm_device_t *dev, int channel, uint32_t handle)
hash ^= (handle & ((1 << dev_priv->ramht_bits) - 1));
handle >>= dev_priv->ramht_bits;
}
- hash ^= channel << (dev_priv->ramht_bits - 4);
- return hash << 3;
+ if (dev_priv->card_type < NV_50)
+ hash ^= channel << (dev_priv->ramht_bits - 4);
+ hash <<= 3;
+
+ DRM_DEBUG("ch%d handle=0x%08x hash=0x%08x\n", channel, handle, hash);
+ return hash;
+}
+
+static int
+nouveau_ramht_entry_valid(drm_device_t *dev, nouveau_gpuobj_t *ramht,
+ uint32_t offset)
+{
+ drm_nouveau_private_t *dev_priv=dev->dev_private;
+ uint32_t ctx = INSTANCE_RD(ramht, (offset + 4)/4);
+
+ if (dev_priv->card_type < NV_40)
+ return ((ctx & NV_RAMHT_CONTEXT_VALID) != 0);
+ return (ctx != 0);
}
static int
-nouveau_ht_object_insert(drm_device_t* dev, int channel, uint32_t handle,
- struct nouveau_object *obj)
+nouveau_ramht_insert(drm_device_t* dev, nouveau_gpuobj_ref_t *ref)
{
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 o_ofs, ofs;
-
- obj->handle = handle;
- o_ofs = ofs = nouveau_ht_handle_hash(dev, channel, obj->handle);
-
- while (NV_READ(ht_base + ofs) || NV_READ(ht_base + ofs + 4)) {
- ofs += 8;
- if (ofs == dev_priv->ramht_size) ofs = 0;
- if (ofs == o_ofs) {
- DRM_ERROR("no free hash table entries\n");
- return 1;
+ struct nouveau_fifo *chan = dev_priv->fifos[ref->channel];
+ nouveau_gpuobj_t *ramht = chan->ramht ? chan->ramht->gpuobj : NULL;
+ nouveau_gpuobj_t *gpuobj = ref->gpuobj;
+ uint32_t ctx, co, ho;
+
+ if (!ramht) {
+ DRM_ERROR("No hash table!\n");
+ return DRM_ERR(EINVAL);
+ }
+
+ if (dev_priv->card_type < NV_40) {
+ ctx = NV_RAMHT_CONTEXT_VALID | (ref->instance >> 4) |
+ (ref->channel << NV_RAMHT_CONTEXT_CHANNEL_SHIFT) |
+ (gpuobj->engine << NV_RAMHT_CONTEXT_ENGINE_SHIFT);
+ } else
+ if (dev_priv->card_type < NV_50) {
+ ctx = (ref->instance >> 4) |
+ (ref->channel << NV40_RAMHT_CONTEXT_CHANNEL_SHIFT) |
+ (gpuobj->engine << NV40_RAMHT_CONTEXT_ENGINE_SHIFT);
+ } else {
+ ctx = (ref->instance >> 4) |
+ (gpuobj->engine << NV40_RAMHT_CONTEXT_ENGINE_SHIFT);
+ }
+
+ co = ho = nouveau_ramht_hash_handle(dev, ref->channel, ref->handle);
+ do {
+ if (!nouveau_ramht_entry_valid(dev, ramht, co)) {
+ DRM_DEBUG("insert ch%d 0x%08x: h=0x%08x, c=0x%08x\n",
+ ref->channel, co, ref->handle, ctx);
+ INSTANCE_WR(ramht, (co + 0)/4, ref->handle);
+ INSTANCE_WR(ramht, (co + 4)/4, ctx);
+ return 0;
}
+ DRM_DEBUG("collision ch%d 0x%08x: h=0x%08x\n",
+ ref->channel, co, INSTANCE_RD(ramht, co/4));
+
+ co += 8;
+ if (co >= dev_priv->ramht_size)
+ co = 0;
+ } while (co != ho);
+
+ DRM_ERROR("RAMHT space exhausted. ch=%d\n", ref->channel);
+ return DRM_ERR(ENOMEM);
+}
+
+static void
+nouveau_ramht_remove(drm_device_t* dev, nouveau_gpuobj_ref_t *ref)
+{
+ drm_nouveau_private_t *dev_priv = dev->dev_private;
+ struct nouveau_fifo *chan = dev_priv->fifos[ref->channel];
+ nouveau_gpuobj_t *ramht = chan->ramht ? chan->ramht->gpuobj : NULL;
+ uint32_t co, ho;
+
+ if (!ramht) {
+ DRM_ERROR("No hash table!\n");
+ return;
}
- ofs += ht_base;
- DRM_DEBUG("Channel %d - Handle 0x%08x at 0x%08x\n",
- channel, obj->handle, ofs);
+ co = ho = nouveau_ramht_hash_handle(dev, ref->channel, ref->handle);
+ do {
+ if (nouveau_ramht_entry_valid(dev, ramht, co) &&
+ (ref->handle == INSTANCE_RD(ramht, (co/4)))) {
+ DRM_DEBUG("remove ch%d 0x%08x: h=0x%08x, c=0x%08x\n",
+ ref->channel, co, ref->handle,
+ INSTANCE_RD(ramht, (co + 4)));
+ INSTANCE_WR(ramht, (co + 0)/4, 0x00000000);
+ INSTANCE_WR(ramht, (co + 4)/4, 0x00000000);
+ return;
+ }
+
+ co += 8;
+ if (co >= dev_priv->ramht_size)
+ co = 0;
+ } while (co != ho);
- NV_WRITE(NV_RAMHT_HANDLE_OFFSET + ofs, obj->handle);
- if (dev_priv->card_type >= NV_40)
- NV_WRITE(NV_RAMHT_CONTEXT_OFFSET + ofs,
- (channel << NV40_RAMHT_CONTEXT_CHANNEL_SHIFT) |
- (obj->engine << NV40_RAMHT_CONTEXT_ENGINE_SHIFT) |
- nouveau_chip_instance_get(dev, obj->instance)
- );
+ DRM_ERROR("RAMHT entry not found. ch=%d, handle=0x%08x\n",
+ ref->channel, ref->handle);
+}
+
+int
+nouveau_gpuobj_new(drm_device_t *dev, int channel, int size, int align,
+ uint32_t flags, nouveau_gpuobj_t **gpuobj_ret)
+{
+ drm_nouveau_private_t *dev_priv = dev->dev_private;
+ nouveau_engine_func_t *engine = &dev_priv->Engine;
+ struct nouveau_fifo *chan = NULL;
+ nouveau_gpuobj_t *gpuobj;
+ struct mem_block *pramin = NULL;
+ int ret;
+
+ DRM_DEBUG("ch%d size=%d align=%d flags=0x%08x\n",
+ channel, size, align, flags);
+
+ if (!dev_priv || !gpuobj_ret || *gpuobj_ret != NULL)
+ return DRM_ERR(EINVAL);
+
+ if (channel >= 0) {
+ if (channel > nouveau_fifo_number(dev))
+ return DRM_ERR(EINVAL);
+ chan = dev_priv->fifos[channel];
+ }
+
+ gpuobj = drm_calloc(1, sizeof(*gpuobj), DRM_MEM_DRIVER);
+ if (!gpuobj)
+ return DRM_ERR(ENOMEM);
+ DRM_DEBUG("gpuobj %p\n", gpuobj);
+ gpuobj->flags = flags;
+ gpuobj->im_channel = channel;
+
+ /* Choose between global instmem heap, and per-channel private
+ * instmem heap. On <NV50 allow requests for private instmem
+ * to be satisfied from global heap if no per-channel area
+ * available.
+ */
+ if (chan) {
+ if (chan->ramin_heap) {
+ DRM_DEBUG("private heap\n");
+ pramin = chan->ramin_heap;
+ } else
+ if (dev_priv->card_type < NV_50) {
+ DRM_DEBUG("global heap fallback\n");
+ pramin = dev_priv->ramin_heap;
+ }
+ } else {
+ DRM_DEBUG("global heap\n");
+ pramin = dev_priv->ramin_heap;
+ }
+
+ if (!pramin) {
+ DRM_ERROR("No PRAMIN heap!\n");
+ return DRM_ERR(EINVAL);
+ }
+
+ if (!chan && (ret = engine->instmem.populate(dev, gpuobj, &size))) {
+ nouveau_gpuobj_del(dev, &gpuobj);
+ return ret;
+ }
+
+ /* Allocate a chunk of the PRAMIN aperture */
+ gpuobj->im_pramin = nouveau_mem_alloc_block(pramin, size,
+ drm_order(align),
+ (DRMFILE)-2);
+ if (!gpuobj->im_pramin) {
+ nouveau_gpuobj_del(dev, &gpuobj);
+ return DRM_ERR(ENOMEM);
+ }
+ gpuobj->im_pramin->flags = NOUVEAU_MEM_INSTANCE;
+
+ if (!chan && (ret = engine->instmem.bind(dev, gpuobj))) {
+ nouveau_gpuobj_del(dev, &gpuobj);
+ return ret;
+ }
+
+ if (gpuobj->flags & NVOBJ_FLAG_ZERO_ALLOC) {
+ int i;
+
+ for (i = 0; i < gpuobj->im_pramin->size; i += 4)
+ INSTANCE_WR(gpuobj, i/4, 0);
+ }
+
+ if (dev_priv->gpuobj_all) {
+ gpuobj->next = dev_priv->gpuobj_all;
+ gpuobj->next->prev = gpuobj;
+ }
+ dev_priv->gpuobj_all = gpuobj;
+
+ *gpuobj_ret = gpuobj;
+ return 0;
+}
+
+void nouveau_gpuobj_takedown(drm_device_t *dev)
+{
+ drm_nouveau_private_t *dev_priv = dev->dev_private;
+ nouveau_gpuobj_t *gpuobj = NULL;
+
+ DRM_DEBUG("\n");
+
+ while ((gpuobj = dev_priv->gpuobj_all)) {
+ DRM_ERROR("gpuobj %p still exists at takedown, refs=%d\n",
+ gpuobj, gpuobj->refcount);
+ gpuobj->refcount = 0;
+ nouveau_gpuobj_del(dev, &gpuobj);
+ }
+}
+
+int nouveau_gpuobj_del(drm_device_t *dev, nouveau_gpuobj_t **pgpuobj)
+{
+ drm_nouveau_private_t *dev_priv = dev->dev_private;
+ nouveau_engine_func_t *engine = &dev_priv->Engine;
+ nouveau_gpuobj_t *gpuobj;
+
+ DRM_DEBUG("gpuobj %p\n", pgpuobj ? *pgpuobj : NULL);
+
+ if (!dev_priv || !pgpuobj || !(*pgpuobj))
+ return DRM_ERR(EINVAL);
+ gpuobj = *pgpuobj;
+
+ if (gpuobj->refcount != 0) {
+ DRM_ERROR("gpuobj refcount is %d\n", gpuobj->refcount);
+ return DRM_ERR(EINVAL);
+ }
+
+ engine->instmem.clear(dev, gpuobj);
+
+ if (gpuobj->im_pramin) {
+ if (gpuobj->flags & NVOBJ_FLAG_FAKE)
+ drm_free(gpuobj->im_pramin, sizeof(*gpuobj->im_pramin),
+ DRM_MEM_DRIVER);
+ else
+ nouveau_mem_free_block(gpuobj->im_pramin);
+ }
+
+ if (gpuobj->next)
+ gpuobj->next->prev = gpuobj->prev;
+ if (gpuobj->prev)
+ gpuobj->prev->next = gpuobj->next;
else
- NV_WRITE(NV_RAMHT_CONTEXT_OFFSET + ofs,
- NV_RAMHT_CONTEXT_VALID |
- (channel << NV_RAMHT_CONTEXT_CHANNEL_SHIFT) |
- (obj->engine << NV_RAMHT_CONTEXT_ENGINE_SHIFT) |
- nouveau_chip_instance_get(dev, obj->instance)
- );
-
- obj->ht_loc = ofs;
+ dev_priv->gpuobj_all = gpuobj->next;
+
+ *pgpuobj = NULL;
+ drm_free(gpuobj, sizeof(*gpuobj), DRM_MEM_DRIVER);
return 0;
}
-static void nouveau_hash_table_remove(drm_device_t* dev,
- struct nouveau_object *obj)
+static int
+nouveau_gpuobj_instance_get(drm_device_t *dev, int channel,
+ nouveau_gpuobj_t *gpuobj, uint32_t *inst)
{
drm_nouveau_private_t *dev_priv = dev->dev_private;
+ nouveau_gpuobj_t *cpramin;
+
+ /* <NV50 use PRAMIN address everywhere */
+ if (dev_priv->card_type < NV_50) {
+ *inst = gpuobj->im_pramin->start;
+ return 0;
+ }
- DRM_DEBUG("Remove handle 0x%08x at 0x%08x from HT\n",
- obj->handle, obj->ht_loc);
- if (obj->ht_loc) {
- DRM_DEBUG("... HT entry was: 0x%08x/0x%08x\n",
- NV_READ(obj->ht_loc), NV_READ(obj->ht_loc+4));
- NV_WRITE(obj->ht_loc , 0x00000000);
- NV_WRITE(obj->ht_loc+4, 0x00000000);
+ if ((channel > 0) && gpuobj->im_channel != channel) {
+ DRM_ERROR("Channel mismatch: obj %d, ref %d\n",
+ gpuobj->im_channel, channel);
+ return DRM_ERR(EINVAL);
+ }
+
+ /* NV50 channel-local instance */
+ if (channel > 0) {
+ cpramin = dev_priv->fifos[channel]->ramin->gpuobj;
+ *inst = gpuobj->im_pramin->start - cpramin->im_pramin->start;
+ return 0;
}
+
+ /* NV50 global (VRAM) instance */
+ if (gpuobj->im_channel < 0) {
+ /* ...from global heap */
+ if (!gpuobj->im_backing) {
+ DRM_ERROR("AII, no VRAM backing gpuobj\n");
+ return DRM_ERR(EINVAL);
+ }
+ *inst = gpuobj->im_backing->start;
+ return 0;
+ } else {
+ /* ...from local heap */
+ cpramin = dev_priv->fifos[gpuobj->im_channel]->ramin->gpuobj;
+ *inst = cpramin->im_backing->start +
+ (gpuobj->im_pramin->start - cpramin->im_pramin->start);
+ return 0;
+ }
+
+ return DRM_ERR(EINVAL);
}
-static struct nouveau_object *
-nouveau_object_instance_alloc(drm_device_t* dev, int channel)
+int
+nouveau_gpuobj_ref_add(drm_device_t *dev, int channel, uint32_t handle,
+ nouveau_gpuobj_t *gpuobj, nouveau_gpuobj_ref_t **ref_ret)
{
- drm_nouveau_private_t *dev_priv=dev->dev_private;
- struct nouveau_object *obj;
+ drm_nouveau_private_t *dev_priv = dev->dev_private;
+ struct nouveau_fifo *chan = NULL;
+ nouveau_gpuobj_ref_t *ref;
+ uint32_t instance;
+ int ret;
+
+ DRM_DEBUG("ch%d h=0x%08x gpuobj=%p\n", channel, handle, gpuobj);
+
+ if (!dev_priv || !gpuobj || (ref_ret && *ref_ret != NULL))
+ return DRM_ERR(EINVAL);
+
+ if (channel >= 0) {
+ if (channel > nouveau_fifo_number(dev))
+ return DRM_ERR(EINVAL);
+ chan = dev_priv->fifos[channel];
+ } else
+ if (!ref_ret)
+ return DRM_ERR(EINVAL);
+
+ ret = nouveau_gpuobj_instance_get(dev, channel, gpuobj, &instance);
+ if (ret)
+ return ret;
- /* Create object struct */
- obj = drm_calloc(1, sizeof(struct nouveau_object), DRM_MEM_DRIVER);
- if (!obj) {
- DRM_ERROR("couldn't alloc memory for object\n");
- return NULL;
+ ref = drm_calloc(1, sizeof(*ref), DRM_MEM_DRIVER);
+ if (!ref)
+ return DRM_ERR(ENOMEM);
+ ref->gpuobj = gpuobj;
+ ref->channel = channel;
+ ref->instance = instance;
+
+ if (!ref_ret) {
+ ref->handle = handle;
+
+ ret = nouveau_ramht_insert(dev, ref);
+ if (ret) {
+ drm_free(ref, sizeof(*ref), DRM_MEM_DRIVER);
+ return ret;
+ }
+
+ ref->next = chan->ramht_refs;
+ chan->ramht_refs = ref;
+ } else {
+ ref->handle = ~0;
+ *ref_ret = ref;
}
- /* Allocate instance memory */
- obj->instance = nouveau_instmem_alloc(dev,
- (dev_priv->card_type >= NV_40 ? 32 : 16), 4);
- if (!obj->instance) {
- DRM_ERROR("couldn't alloc RAMIN for object\n");
- drm_free(obj, sizeof(struct nouveau_object), DRM_MEM_DRIVER);
- return NULL;
+ ref->gpuobj->refcount++;
+ return 0;
+}
+
+int nouveau_gpuobj_ref_del(drm_device_t *dev, nouveau_gpuobj_ref_t **pref)
+{
+ nouveau_gpuobj_ref_t *ref;
+
+ DRM_DEBUG("ref %p\n", pref ? *pref : NULL);
+
+ if (!dev || !pref || *pref == NULL)
+ return DRM_ERR(EINVAL);
+ ref = *pref;
+
+ if (ref->handle != ~0)
+ nouveau_ramht_remove(dev, ref);
+
+ if (ref->gpuobj) {
+ ref->gpuobj->refcount--;
+
+ if (ref->gpuobj->refcount == 0) {
+ if (!(ref->gpuobj->flags & NVOBJ_FLAG_ALLOW_NO_REFS))
+ nouveau_gpuobj_del(dev, &ref->gpuobj);
+ }
}
- /* Bind object to channel */
- obj->channel = channel;
- obj->handle = ~0;
- nouveau_object_link(dev, obj);
+ *pref = NULL;
+ drm_free(ref, sizeof(ref), DRM_MEM_DRIVER);
+ return 0;
+}
+
+int
+nouveau_gpuobj_new_ref(drm_device_t *dev, int oc, int rc, uint32_t handle,
+ int size, int align, uint32_t flags,
+ nouveau_gpuobj_ref_t **ref)
+{
+ nouveau_gpuobj_t *gpuobj = NULL;
+ int ret;
- return obj;
+ if ((ret = nouveau_gpuobj_new(dev, oc, size, align, flags, &gpuobj)))
+ return ret;
+
+ if ((ret = nouveau_gpuobj_ref_add(dev, rc, handle, gpuobj, ref))) {
+ nouveau_gpuobj_del(dev, &gpuobj);
+ return ret;
+ }
+
+ return 0;
}
-static void
-nouveau_object_instance_free(drm_device_t *dev, struct nouveau_object *obj)
+static int
+nouveau_gpuobj_ref_find(drm_device_t *dev, int channel, uint32_t handle,
+ nouveau_gpuobj_ref_t **ref_ret)
{
- drm_nouveau_private_t *dev_priv=dev->dev_private;
+ drm_nouveau_private_t *dev_priv = dev->dev_private;
+ struct nouveau_fifo *chan = dev_priv->fifos[channel];
+ nouveau_gpuobj_ref_t *ref = chan->ramht_refs;
+
+ while (ref) {
+ if (ref->handle == handle) {
+ if (ref_ret)
+ *ref_ret = ref;
+ return 0;
+ }
+ ref = ref->next;
+ }
+
+ return DRM_ERR(EINVAL);
+}
+
+int
+nouveau_gpuobj_new_fake(drm_device_t *dev, uint32_t offset, uint32_t size,
+ uint32_t flags, nouveau_gpuobj_t **pgpuobj,
+ nouveau_gpuobj_ref_t **pref)
+{
+ drm_nouveau_private_t *dev_priv = dev->dev_private;
+ nouveau_gpuobj_t *gpuobj = NULL;
int i;
- /* Unbind object from channel */
- nouveau_object_unlink(dev, obj);
+ DRM_DEBUG("offset=0x%08x size=0x%08x flags=0x%08x\n",
+ offset, size, flags);
+
+ gpuobj = drm_calloc(1, sizeof(*gpuobj), DRM_MEM_DRIVER);
+ if (!gpuobj)
+ return DRM_ERR(ENOMEM);
+ DRM_DEBUG("gpuobj %p\n", gpuobj);
+ gpuobj->im_channel = -1;
+ gpuobj->flags = flags | NVOBJ_FLAG_FAKE;
+
+ gpuobj->im_pramin = drm_calloc(1, sizeof(struct mem_block),
+ DRM_MEM_DRIVER);
+ if (!gpuobj->im_pramin) {
+ nouveau_gpuobj_del(dev, &gpuobj);
+ return DRM_ERR(ENOMEM);
+ }
+ gpuobj->im_pramin->start = offset;
+ gpuobj->im_pramin->size = size;
- /* Clean RAMIN entry */
- DRM_DEBUG("Instance entry for 0x%08x"
- "(engine %d, class 0x%x) before destroy:\n",
- obj->handle, obj->engine, obj->class);
- for (i=0; i<(obj->instance->size/4); i++) {
- DRM_DEBUG(" +0x%02x: 0x%08x\n", (i*4),
- INSTANCE_RD(obj->instance, i));
- INSTANCE_WR(obj->instance, i, 0x00000000);
+ if (gpuobj->flags & NVOBJ_FLAG_ZERO_ALLOC) {
+ for (i = 0; i < gpuobj->im_pramin->size; i += 4)
+ INSTANCE_WR(gpuobj, i/4, 0);
}
- /* Free RAMIN */
- nouveau_instmem_free(dev, obj->instance);
+ if (pref) {
+ if ((i = nouveau_gpuobj_ref_add(dev, -1, 0, gpuobj, pref))) {
+ nouveau_gpuobj_del(dev, &gpuobj);
+ return i;
+ }
+ }
+
+ if (pgpuobj)
+ *pgpuobj = gpuobj;
+ return 0;
+}
+
+
+static int
+nouveau_gpuobj_class_instmem_size(drm_device_t *dev, int class)
+{
+ drm_nouveau_private_t *dev_priv = dev->dev_private;
+
+ /*XXX: dodgy hack for now */
+ if (dev_priv->card_type >= NV_50)
+ return 24;
+ if (dev_priv->card_type >= NV_40)
+ return 32;
+ return 16;
}
/*
@@ -278,76 +562,147 @@ nouveau_object_instance_free(drm_device_t *dev, struct nouveau_object *obj)
17:16 target: 0 NV memory, 1 NV memory tiled, 2 PCI, 3 AGP
31:20 dma adjust (bits 0-11 of the address)
entry[1]
- dma limit
- entry[2]
+ dma limit (size of transfer)
+ entry[X]
1 0 readonly, 1 readwrite
- 31:12 dma frame address (bits 12-31 of the address)
+ 31:12 dma frame address of the page (bits 12-31 of the address)
+ entry[N]
+ page table terminator, same value as the first pte, as does nvidia
+ rivatv uses 0xffffffff
- Non linear page tables seem to need a list of frame addresses afterwards,
- the rivatv project has some info on this.
+ Non linear page tables need a list of frame addresses afterwards,
+ the rivatv project has some info on this.
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_object_dma_create(drm_device_t* dev, int channel, int class,
- uint32_t offset, uint32_t size,
- int access, int target)
+int
+nouveau_gpuobj_dma_new(drm_device_t *dev, int channel, int class,
+ uint64_t offset, uint64_t size, int access, int target,
+ nouveau_gpuobj_t **gpuobj)
{
- 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);
+ drm_nouveau_private_t *dev_priv = dev->dev_private;
+ int ret;
+ uint32_t is_scatter_gather = 0;
+
+ DRM_DEBUG("ch%d class=0x%04x offset=0x%llx size=0x%llx\n",
+ channel, class, offset, size);
+ DRM_DEBUG("access=%d target=%d\n", access, target);
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;
+ case NV_DMA_TARGET_AGP:
+ offset += dev_priv->agp_phys;
+ break;
+ case NV_DMA_TARGET_PCI_NONLINEAR:
+ /*assume the "offset" is a virtual memory address*/
+ is_scatter_gather = 1;
+ /*put back the right value*/
+ target = NV_DMA_TARGET_PCI;
+ break;
+ default:
+ break;
+ }
+
+ ret = nouveau_gpuobj_new(dev, channel,
+ is_scatter_gather ? ((((size + PAGE_SIZE - 1) / PAGE_SIZE) << 2) + 12) : nouveau_gpuobj_class_instmem_size(dev, class),
+ 16,
+ NVOBJ_FLAG_ZERO_ALLOC | NVOBJ_FLAG_ZERO_FREE,
+ gpuobj);
+ if (ret) {
+ DRM_ERROR("Error creating gpuobj: %d\n", ret);
+ return ret;
}
- frame = offset & ~0x00000FFF;
- adjust = offset & 0x00000FFF;
-
- obj = nouveau_object_instance_alloc(dev, channel);
- if (!obj) {
- DRM_ERROR("couldn't allocate DMA object\n");
- return obj;
+ if (dev_priv->card_type < NV_50) {
+ uint32_t frame, adjust, pte_flags = 0;
+ adjust = offset & 0x00000fff;
+ if (access != NV_DMA_ACCESS_RO)
+ pte_flags |= (1<<1);
+
+ if ( ! is_scatter_gather )
+ {
+ frame = offset & ~0x00000fff;
+
+ INSTANCE_WR(*gpuobj, 0, ((1<<12) | (1<<13) |
+ (adjust << 20) |
+ (access << 14) |
+ (target << 16) |
+ class));
+ INSTANCE_WR(*gpuobj, 1, size - 1);
+ INSTANCE_WR(*gpuobj, 2, frame | pte_flags);
+ INSTANCE_WR(*gpuobj, 3, frame | pte_flags);
+ }
+ else
+ {
+ uint32_t instance_offset;
+ uint64_t bus_addr;
+ size = (uint32_t) size;
+
+ DRM_DEBUG("Creating PCI DMA object using virtual zone starting at %#llx, size %d\n", offset, (uint32_t)size);
+ INSTANCE_WR(*gpuobj, 0, ((1<<12) | (0<<13) |
+ (adjust << 20) |
+ (access << 14) |
+ (target << 16) |
+ class));
+ INSTANCE_WR(*gpuobj, 1, size-1);
+
+ offset += dev->sg->virtual;
+
+ /*write starting at the third dword*/
+ instance_offset = 2;
+
+ /*for each PAGE, get its bus address, fill in the page table entry, and advance*/
+ while ( size > 0 ) {
+ bus_addr = vmalloc_to_page(offset);
+ if ( ! bus_addr )
+ {
+ DRM_ERROR("Couldn't map virtual address %#llx to a page number\n", offset);
+ nouveau_gpuobj_del(dev, gpuobj);
+ return DRM_ERR(ENOMEM);
+ }
+ bus_addr = (uint64_t) page_address(bus_addr);
+ if ( ! bus_addr )
+ {
+ DRM_ERROR("Couldn't find page address for address %#llx\n", offset);
+ nouveau_gpuobj_del(dev, gpuobj);
+ return DRM_ERR(ENOMEM);
+ }
+ bus_addr |= (offset & ~PAGE_MASK);
+ bus_addr = virt_to_bus((void *)bus_addr);
+ if ( ! bus_addr )
+ {
+ DRM_ERROR("Couldn't get bus address for %#llx\n", offset);
+ nouveau_gpuobj_del(dev, gpuobj);
+ return DRM_ERR(ENOMEM);
+ }
+
+ /*if ( bus_addr >= 1 << 32 )
+ {
+ DRM_ERROR("Bus address %#llx is over 32 bits, Nvidia cards cannot address it !\n", bus_addr);
+ nouveau_gpuobj_del(dev, gpuobj);
+ return DRM_ERR(EINVAL);
+ }*/
+
+ frame = (uint32_t) bus_addr & ~0x00000FFF;
+ INSTANCE_WR(*gpuobj, instance_offset, frame | pte_flags);
+ offset += PAGE_SIZE;
+ instance_offset ++;
+ size -= PAGE_SIZE;
+ }
+
+ }
+ } else {
+ INSTANCE_WR(*gpuobj, 0, 0x00190000 | class);
+ INSTANCE_WR(*gpuobj, 1, offset + size - 1);
+ INSTANCE_WR(*gpuobj, 2, offset);
+ INSTANCE_WR(*gpuobj, 5, 0x00010000);
}
- obj->engine = 0;
- obj->class = class;
-
- INSTANCE_WR(obj->instance, 0, ((1<<12) | (1<<13) |
- (adjust << 20) |
- (access << 14) |
- (target << 16) |
- class));
- INSTANCE_WR(obj->instance, 1, size-1);
- INSTANCE_WR(obj->instance, 2, frame | pte_flags);
- INSTANCE_WR(obj->instance, 3, frame | pte_flags);
-
- return obj;
+ (*gpuobj)->engine = NVOBJ_ENGINE_SW;
+ (*gpuobj)->class = class;
+ return 0;
}
-
/* Context objects in the instance RAM have the following structure.
* On NV40 they are 32 byte long, on NV30 and smaller 16 bytes.
@@ -399,177 +754,221 @@ nouveau_object_dma_create(drm_device_t* dev, int channel, int class,
entry[5]:
set to 0?
*/
-struct nouveau_object *
-nouveau_object_gr_create(drm_device_t* dev, int channel, int class)
+int
+nouveau_gpuobj_gr_new(drm_device_t *dev, int channel, int class,
+ nouveau_gpuobj_t **gpuobj)
{
- drm_nouveau_private_t *dev_priv=dev->dev_private;
- struct nouveau_object *obj;
-
- DRM_DEBUG("class=%x\n", class);
-
- obj = nouveau_object_instance_alloc(dev, channel);
- if (!obj) {
- DRM_ERROR("couldn't allocate context object\n");
- return obj;
+ drm_nouveau_private_t *dev_priv = dev->dev_private;
+ int ret;
+
+ DRM_DEBUG("ch%d class=0x%04x\n", channel, class);
+
+ ret = nouveau_gpuobj_new(dev, channel,
+ nouveau_gpuobj_class_instmem_size(dev, class),
+ 16,
+ NVOBJ_FLAG_ZERO_ALLOC | NVOBJ_FLAG_ZERO_FREE,
+ gpuobj);
+ if (ret) {
+ DRM_ERROR("Error creating gpuobj: %d\n", ret);
+ return ret;
}
- obj->engine = 1;
- obj->class = class;
-
+ if (dev_priv->card_type >= NV_50) {
+ INSTANCE_WR(*gpuobj, 0, class);
+ INSTANCE_WR(*gpuobj, 5, 0x00010000);
+ } else {
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);
+ INSTANCE_WR(*gpuobj, 0, 0x00001030);
+ INSTANCE_WR(*gpuobj, 1, 0xFFFFFFFF);
break;
default:
if (dev_priv->card_type >= NV_40) {
- INSTANCE_WR(obj->instance, 0, obj->class);
- INSTANCE_WR(obj->instance, 1, 0x00000000);
+ INSTANCE_WR(*gpuobj, 0, class);
#ifdef __BIG_ENDIAN
- INSTANCE_WR(obj->instance, 2, 0x01000000);
-#else
- INSTANCE_WR(obj->instance, 2, 0x00000000);
+ INSTANCE_WR(*gpuobj, 2, 0x01000000);
#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);
+ INSTANCE_WR(*gpuobj, 0, class | 0x00080000);
#else
- INSTANCE_WR(obj->instance, 0, obj->class);
+ INSTANCE_WR(*gpuobj, 0, class);
#endif
- INSTANCE_WR(obj->instance, 1, 0x00000000);
- INSTANCE_WR(obj->instance, 2, 0x00000000);
- INSTANCE_WR(obj->instance, 3, 0x00000000);
}
}
+ }
- return obj;
-}
-
-void
-nouveau_object_free(drm_device_t *dev, struct nouveau_object *obj)
-{
- nouveau_object_instance_free(dev, obj);
- if (obj->handle != ~0)
- nouveau_hash_table_remove(dev, obj);
- drm_free(obj, sizeof(struct nouveau_object), DRM_MEM_DRIVER);
+ (*gpuobj)->engine = NVOBJ_ENGINE_GR;
+ (*gpuobj)->class = class;
+ return 0;
}
-void nouveau_object_cleanup(drm_device_t *dev, int channel)
+static int
+nouveau_gpuobj_channel_init_pramin(drm_device_t *dev, int channel)
{
- drm_nouveau_private_t *dev_priv=dev->dev_private;
+ drm_nouveau_private_t *dev_priv = dev->dev_private;
+ struct nouveau_fifo *chan = dev_priv->fifos[channel];
+ nouveau_gpuobj_t *pramin = NULL;
+ int size, base, ret;
+
+ DRM_DEBUG("ch%d\n", channel);
+
+ /* Base amount for object storage (4KiB enough?) */
+ size = 0x1000;
+ base = 0;
+
+ /* PGRAPH context */
+
+ if (dev_priv->card_type == NV_50) {
+ /* Various fixed table thingos */
+ size += 0x1400; /* mostly unknown stuff */
+ size += 0x4000; /* vm pd */
+ base = 0x6000;
+ /* RAMHT, not sure about setting size yet, 32KiB to be safe */
+ size += 0x8000;
+ /* RAMFC */
+ size += 0x1000;
+ /* PGRAPH context */
+ size += 0x60000;
+ }
- while (dev_priv->fifos[channel].objs) {
- nouveau_object_free(dev, dev_priv->fifos[channel].objs);
+ DRM_DEBUG("ch%d PRAMIN size: 0x%08x bytes, base alloc=0x%08x\n",
+ channel, size, base);
+ ret = nouveau_gpuobj_new_ref(dev, -1, -1, 0, size, 0x1000, 0,
+ &chan->ramin);
+ if (ret) {
+ DRM_ERROR("Error allocating channel PRAMIN: %d\n", ret);
+ return ret;
+ }
+ pramin = chan->ramin->gpuobj;
+
+ ret = nouveau_mem_init_heap(&chan->ramin_heap,
+ pramin->im_pramin->start + base, size);
+ if (ret) {
+ DRM_ERROR("Error creating PRAMIN heap: %d\n", ret);
+ nouveau_gpuobj_ref_del(dev, &chan->ramin);
+ return ret;
}
+
+ return 0;
}
-int nouveau_ioctl_object_init(DRM_IOCTL_ARGS)
+int
+nouveau_gpuobj_channel_init(drm_device_t *dev, int channel,
+ uint32_t vram_h, uint32_t tt_h)
{
- DRM_DEVICE;
- drm_nouveau_object_init_t init;
- struct nouveau_object *obj;
-
- DRM_COPY_FROM_USER_IOCTL(init, (drm_nouveau_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);
+ drm_nouveau_private_t *dev_priv = dev->dev_private;
+ struct nouveau_fifo *chan = dev_priv->fifos[channel];
+ nouveau_gpuobj_t *vram = NULL, *tt = NULL;
+ int ret;
+
+ DRM_DEBUG("ch%d vram=0x%08x tt=0x%08x\n", channel, vram_h, tt_h);
+
+ /* Reserve a block of PRAMIN for the channel
+ *XXX: maybe on <NV50 too at some point
+ */
+ if (0 || dev_priv->card_type == NV_50) {
+ ret = nouveau_gpuobj_channel_init_pramin(dev, channel);
+ if (ret)
+ return ret;
}
- //FIXME: check args, only allow trusted objects to be created
-
- 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);
+ /* RAMHT */
+ if (dev_priv->card_type < NV_50) {
+ ret = nouveau_gpuobj_ref_add(dev, -1, 0, dev_priv->ramht,
+ &chan->ramht);
+ if (ret)
+ return ret;
+ } else {
+ ret = nouveau_gpuobj_new_ref(dev, channel, channel, 0,
+ 0x8000, 16,
+ NVOBJ_FLAG_ZERO_ALLOC,
+ &chan->ramht);
+ if (ret)
+ return ret;
}
- obj = nouveau_object_gr_create(dev, init.channel, init.class);
- if (!obj)
- return DRM_ERR(ENOMEM);
+ /* VRAM ctxdma */
+ if ((ret = nouveau_gpuobj_dma_new(dev, channel, NV_CLASS_DMA_IN_MEMORY,
+ 0, dev_priv->fb_available_size,
+ NV_DMA_ACCESS_RW,
+ NV_DMA_TARGET_VIDMEM, &vram))) {
+ DRM_ERROR("Error creating VRAM ctxdma: %d\n", ret);
+ return ret;
+ }
- if (nouveau_ht_object_insert(dev, init.channel, init.handle, obj)) {
- nouveau_object_free(dev, obj);
- return DRM_ERR(ENOMEM);
+ if ((ret = nouveau_gpuobj_ref_add(dev, channel, vram_h, vram, NULL))) {
+ DRM_ERROR("Error referencing VRAM ctxdma: %d\n", ret);
+ return ret;
}
+ if (dev_priv->agp_heap) {
+ /* AGPGART ctxdma */
+ if ((ret = nouveau_gpuobj_dma_new(dev, channel, NV_CLASS_DMA_IN_MEMORY,
+ 0, dev_priv->agp_available_size,
+ NV_DMA_ACCESS_RW,
+ NV_DMA_TARGET_AGP, &tt))) {
+ DRM_ERROR("Error creating AGP TT ctxdma: %d\n", DRM_ERR(ENOMEM));
+ return DRM_ERR(ENOMEM);
+ }
+
+ ret = nouveau_gpuobj_ref_add(dev, channel, tt_h, tt, NULL);
+ if (ret) {
+ DRM_ERROR("Error referencing AGP TT ctxdma: %d\n", ret);
+ return ret;
+ }
+ }
+ else {
+ if (dev_priv -> card_type >= NV_50 ) return 0; /*no PCIGART for NV50*/
+
+ /*PCI*/
+ if((ret = nouveau_gpuobj_dma_new(dev, channel, NV_CLASS_DMA_IN_MEMORY,
+ 0, dev->sg->pages * PAGE_SIZE,
+ NV_DMA_ACCESS_RW,
+ NV_DMA_TARGET_PCI_NONLINEAR, &tt))) {
+ DRM_ERROR("Error creating PCI TT ctxdma: %d\n", DRM_ERR(ENOMEM));
+ return 0; //this is noncritical
+ }
+
+ ret = nouveau_gpuobj_ref_add(dev, channel, tt_h, tt, NULL);
+ if (ret) {
+ DRM_ERROR("Error referencing PCI TT ctxdma: %d\n", ret);
+ return ret;
+ }
+ }
return 0;
}
-static int
-nouveau_dma_object_check_access(drm_device_t *dev,
- drm_nouveau_dma_object_init_t *init)
+void
+nouveau_gpuobj_channel_takedown(drm_device_t *dev, int channel)
{
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);
- }
+ struct nouveau_fifo *chan = dev_priv->fifos[channel];
+ nouveau_gpuobj_ref_t *ref;
- /* 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);
- }
+ DRM_DEBUG("ch%d\n", channel);
- /* 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);
+ while ((ref = chan->ramht_refs)) {
+ chan->ramht_refs = ref->next;
+ nouveau_gpuobj_ref_del(dev, &ref);
}
+ nouveau_gpuobj_ref_del(dev, &chan->ramht);
- 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);
- }
+ if (chan->ramin_heap)
+ nouveau_mem_takedown(&chan->ramin_heap);
+ if (chan->ramin)
+ nouveau_gpuobj_ref_del(dev, &chan->ramin);
- return 0;
}
-int nouveau_ioctl_dma_object_init(DRM_IOCTL_ARGS)
+int nouveau_ioctl_grobj_alloc(DRM_IOCTL_ARGS)
{
DRM_DEVICE;
- drm_nouveau_dma_object_init_t init;
- struct nouveau_object *obj;
+ drm_nouveau_grobj_alloc_t init;
+ nouveau_gpuobj_t *gr = NULL;
+ int ret;
- DRM_COPY_FROM_USER_IOCTL(init, (drm_nouveau_dma_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)) {
@@ -578,25 +977,25 @@ int nouveau_ioctl_dma_object_init(DRM_IOCTL_ARGS)
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);
+ //FIXME: check args, only allow trusted objects to be created
+
+ if (init.handle == ~0)
return DRM_ERR(EINVAL);
- }
+ if (nouveau_gpuobj_ref_find(dev, init.channel, init.handle, NULL) == 0)
+ return DRM_ERR(EEXIST);
- obj = nouveau_object_dma_create(dev, init.channel, init.class,
- init.offset, init.size,
- init.access, init.target);
- if (!obj)
- return DRM_ERR(ENOMEM);
+ if ((ret = nouveau_gpuobj_gr_new(dev, init.channel, init.class, &gr))) {
+ DRM_ERROR("Error creating gr object: %d (%d/0x%08x)\n",
+ ret, init.channel, init.handle);
+ return ret;
+ }
- obj->handle = init.handle;
- if (nouveau_ht_object_insert(dev, init.channel, init.handle, obj)) {
- nouveau_object_free(dev, obj);
- return DRM_ERR(ENOMEM);
+ if ((ret = nouveau_gpuobj_ref_add(dev, init.channel, init.handle,
+ gr, NULL))) {
+ DRM_ERROR("Error referencing gr object: %d (%d/0x%08x\n)",
+ ret, init.channel, init.handle);
+ nouveau_gpuobj_del(dev, &gr);
+ return ret;
}
return 0;
diff --git a/shared-core/nouveau_reg.h b/shared-core/nouveau_reg.h
index ea4a2f6b..a66d2d34 100644
--- a/shared-core/nouveau_reg.h
+++ b/shared-core/nouveau_reg.h
@@ -39,6 +39,8 @@
#define NV_DMA_TARGET_VIDMEM 0
#define NV_DMA_TARGET_PCI 2
#define NV_DMA_TARGET_AGP 3
+/*The following is not a real value used by nvidia cards, it's changed by nouveau_object_dma_create*/
+#define NV_DMA_TARGET_PCI_NONLINEAR 8
/* Some object classes we care about in the drm */
#define NV_CLASS_DMA_FROM_MEMORY 0x00000002
@@ -47,11 +49,15 @@
#define NV_CLASS_DMA_IN_MEMORY 0x0000003D
#define NV03_FIFO_SIZE 0x8000UL
-#define NV_MAX_FIFO_NUMBER 32
+#define NV_MAX_FIFO_NUMBER 128
#define NV03_FIFO_REGS_SIZE 0x10000
#define NV03_FIFO_REGS(i) (0x00800000+i*NV03_FIFO_REGS_SIZE)
# define NV03_FIFO_REGS_DMAPUT(i) (NV03_FIFO_REGS(i)+0x40)
# define NV03_FIFO_REGS_DMAGET(i) (NV03_FIFO_REGS(i)+0x44)
+#define NV50_FIFO_REGS_SIZE 0x2000
+#define NV50_FIFO_REGS(i) (0x00c00000+i*NV50_FIFO_REGS_SIZE)
+# define NV50_FIFO_REGS_DMAPUT(i) (NV50_FIFO_REGS(i)+0x40)
+# define NV50_FIFO_REGS_DMAGET(i) (NV50_FIFO_REGS(i)+0x44)
#define NV03_PMC_BOOT_0 0x00000000
#define NV03_PMC_INTR_0 0x00000100
@@ -135,6 +141,17 @@
#define NV10_PGRAPH_CTX_CACHE4 0x004001C0
#define NV04_PGRAPH_CTX_CACHE4 0x004001E0
#define NV10_PGRAPH_CTX_CACHE5 0x004001E0
+#define NV40_PGRAPH_CTXCTL_0304 0x00400304
+#define NV40_PGRAPH_CTXCTL_0304_XFER_CTX 0x00000001
+#define NV40_PGRAPH_CTXCTL_0310 0x00400310
+#define NV40_PGRAPH_CTXCTL_0310_XFER_SAVE 0x00000020
+#define NV40_PGRAPH_CTXCTL_0310_XFER_LOAD 0x00000040
+#define NV40_PGRAPH_CTXCTL_030C 0x0040030c
+#define NV40_PGRAPH_CTXCTL_UCODE_INDEX 0x00400324
+#define NV40_PGRAPH_CTXCTL_UCODE_DATA 0x00400328
+#define NV40_PGRAPH_CTXCTL_CUR 0x0040032c
+#define NV40_PGRAPH_CTXCTL_CUR_LOADED 0x01000000
+#define NV40_PGRAPH_CTXCTL_CUR_INST_MASK 0x000FFFFF
#define NV03_PGRAPH_ABS_X_RAM 0x00400400
#define NV03_PGRAPH_ABS_Y_RAM 0x00400480
#define NV03_PGRAPH_X_MISC 0x00400500
@@ -230,7 +247,11 @@
#define NV10_PGRAPH_SCALED_FORMAT 0x00400778
#define NV10_PGRAPH_CHANNEL_CTX_TABLE 0x00400780
#define NV10_PGRAPH_CHANNEL_CTX_SIZE 0x00400784
+#define NV20_PGRAPH_CHANNEL_CTX_POINTER 0x00400784
#define NV10_PGRAPH_CHANNEL_CTX_POINTER 0x00400788
+#define NV20_PGRAPH_CHANNEL_CTX_XFER 0x00400788
+#define NV20_PGRAPH_CHANNEL_CTX_XFER_LOAD 0x00000001
+#define NV20_PGRAPH_CHANNEL_CTX_XFER_SAVE 0x00000002
#define NV04_PGRAPH_PATT_COLOR0 0x00400800
#define NV04_PGRAPH_PATT_COLOR1 0x00400804
#define NV04_PGRAPH_PATTERN 0x00400808
@@ -317,6 +338,12 @@
#define NV04_PFIFO_MODE 0x00002504
#define NV04_PFIFO_DMA 0x00002508
#define NV04_PFIFO_SIZE 0x0000250c
+#define NV50_PFIFO_CTX_TABLE(c) (0x2600+(c)*4)
+#define NV50_PFIFO_CTX_TABLE__SIZE 128
+#define NV50_PFIFO_CTX_TABLE_CHANNEL_ENABLED (1<<31)
+#define NV50_PFIFO_CTX_TABLE_UNK30_BAD (1<<30)
+#define NV50_PFIFO_CTX_TABLE_INSTANCE_MASK_G80 0x0FFFFFFF
+#define NV50_PFIFO_CTX_TABLE_INSTANCE_MASK_G84 0x00FFFFFF
#define NV03_PFIFO_CACHE0_PUSH0 0x00003000
#define NV03_PFIFO_CACHE0_PULL0 0x00003040
#define NV04_PFIFO_CACHE0_PULL0 0x00003050
@@ -404,7 +431,7 @@
#define NV10_PFIFO_CACHE1_SEMAPHORE 0x0000326C
#define NV03_PFIFO_CACHE1_GET 0x00003270
#define NV04_PFIFO_CACHE1_ENGINE 0x00003280
-#define NV10_PFIFO_CACHE1_DMA_DCOUNT 0x000032A0
+#define NV04_PFIFO_CACHE1_DMA_DCOUNT 0x000032A0
#define NV40_PFIFO_GRCTX_INSTANCE 0x000032E0
#define NV40_PFIFO_UNK32E4 0x000032E4
#define NV04_PFIFO_CACHE1_METHOD(i) (0x00003800+(i*8))
@@ -427,7 +454,10 @@
#define NV04_RAMFC_DMA_PUT 0x00
#define NV04_RAMFC_DMA_GET 0x04
#define NV04_RAMFC_DMA_INSTANCE 0x08
+#define NV04_RAMFC_DMA_STATE 0x0C
#define NV04_RAMFC_DMA_FETCH 0x10
+#define NV04_RAMFC_ENGINE 0x14
+#define NV04_RAMFC_PULL1_ENGINE 0x18
#define NV10_RAMFC_DMA_PUT 0x00
#define NV10_RAMFC_DMA_GET 0x04
@@ -462,6 +492,6 @@
#define NV40_RAMFC_UNK_40 0x40
#define NV40_RAMFC_UNK_44 0x44
#define NV40_RAMFC_UNK_48 0x48
-#define NV40_RAMFC_2088 0x4C
-#define NV40_RAMFC_3300 0x50
+#define NV40_RAMFC_UNK_4C 0x4C
+#define NV40_RAMFC_UNK_50 0x50
diff --git a/shared-core/nouveau_state.c b/shared-core/nouveau_state.c
index e7930b9e..fe3db168 100644
--- a/shared-core/nouveau_state.c
+++ b/shared-core/nouveau_state.c
@@ -51,6 +51,7 @@ static int nouveau_init_card_mappings(drm_device_t *dev)
DRM_DEBUG("regs mapped ok at 0x%lx\n", dev_priv->mmio->offset);
/* map larger RAMIN aperture on NV40 cards */
+ dev_priv->ramin = NULL;
if (dev_priv->card_type >= NV_40) {
int ramin_resource = 2;
if (drm_get_resource_len(dev, ramin_resource) == 0)
@@ -66,12 +67,26 @@ static int nouveau_init_card_mappings(drm_device_t *dev)
"limited instance memory available\n");
dev_priv->ramin = NULL;
}
- } else
- dev_priv->ramin = NULL;
+ }
+
+ /* On older cards (or if the above failed), create a map covering
+ * the BAR0 PRAMIN aperture */
+ if (!dev_priv->ramin) {
+ ret = drm_addmap(dev,
+ drm_get_resource_start(dev, 0) + NV_RAMIN,
+ (1*1024*1024),
+ _DRM_REGISTERS, _DRM_READ_ONLY,
+ &dev_priv->ramin);
+ if (ret) {
+ DRM_ERROR("Failed to map BAR0 PRAMIN: %d\n", ret);
+ return ret;
+ }
+ }
return 0;
}
+static int nouveau_stub_init(drm_device_t *dev) { return 0; }
static void nouveau_stub_takedown(drm_device_t *dev) {}
static int nouveau_init_engine_ptrs(drm_device_t *dev)
{
@@ -80,66 +95,162 @@ static int nouveau_init_engine_ptrs(drm_device_t *dev)
switch (dev_priv->chipset & 0xf0) {
case 0x00:
- engine->Mc.Init = nv04_mc_init;
- engine->Mc.Takedown = nv04_mc_takedown;
- engine->Timer.Init = nv04_timer_init;
- engine->Timer.Takedown = nv04_timer_takedown;
- engine->Fb.Init = nv04_fb_init;
- engine->Fb.Takedown = nv04_fb_takedown;
- engine->Graph.Init = nv04_graph_init;
- engine->Graph.Takedown = nv04_graph_takedown;
- engine->Fifo.Init = nouveau_fifo_init;
- engine->Fifo.Takedown = nouveau_stub_takedown;
+ engine->instmem.init = nv04_instmem_init;
+ engine->instmem.takedown= nv04_instmem_takedown;
+ engine->instmem.populate = nv04_instmem_populate;
+ engine->instmem.clear = nv04_instmem_clear;
+ engine->instmem.bind = nv04_instmem_bind;
+ engine->instmem.unbind = nv04_instmem_unbind;
+ engine->mc.init = nv04_mc_init;
+ engine->mc.takedown = nv04_mc_takedown;
+ engine->timer.init = nv04_timer_init;
+ engine->timer.takedown = nv04_timer_takedown;
+ engine->fb.init = nv04_fb_init;
+ engine->fb.takedown = nv04_fb_takedown;
+ engine->graph.init = nv04_graph_init;
+ engine->graph.takedown = nv04_graph_takedown;
+ engine->graph.create_context = nv04_graph_create_context;
+ engine->graph.destroy_context = nv04_graph_destroy_context;
+ engine->graph.load_context = nv04_graph_load_context;
+ engine->graph.save_context = nv04_graph_save_context;
+ engine->fifo.init = nouveau_fifo_init;
+ engine->fifo.takedown = nouveau_stub_takedown;
+ engine->fifo.create_context = nv04_fifo_create_context;
+ engine->fifo.destroy_context = nv04_fifo_destroy_context;
+ engine->fifo.load_context = nv04_fifo_load_context;
+ engine->fifo.save_context = nv04_fifo_save_context;
break;
case 0x10:
- engine->Mc.Init = nv04_mc_init;
- engine->Mc.Takedown = nv04_mc_takedown;
- engine->Timer.Init = nv04_timer_init;
- engine->Timer.Takedown = nv04_timer_takedown;
- engine->Fb.Init = nv10_fb_init;
- engine->Fb.Takedown = nv10_fb_takedown;
- engine->Graph.Init = nv10_graph_init;
- engine->Graph.Takedown = nv10_graph_takedown;
- engine->Fifo.Init = nouveau_fifo_init;
- engine->Fifo.Takedown = nouveau_stub_takedown;
+ engine->instmem.init = nv04_instmem_init;
+ engine->instmem.takedown= nv04_instmem_takedown;
+ engine->instmem.populate = nv04_instmem_populate;
+ engine->instmem.clear = nv04_instmem_clear;
+ engine->instmem.bind = nv04_instmem_bind;
+ engine->instmem.unbind = nv04_instmem_unbind;
+ engine->mc.init = nv04_mc_init;
+ engine->mc.takedown = nv04_mc_takedown;
+ engine->timer.init = nv04_timer_init;
+ engine->timer.takedown = nv04_timer_takedown;
+ engine->fb.init = nv10_fb_init;
+ engine->fb.takedown = nv10_fb_takedown;
+ engine->graph.init = nv10_graph_init;
+ engine->graph.takedown = nv10_graph_takedown;
+ engine->graph.create_context = nv10_graph_create_context;
+ engine->graph.destroy_context = nv10_graph_destroy_context;
+ engine->graph.load_context = nv10_graph_load_context;
+ engine->graph.save_context = nv10_graph_save_context;
+ engine->fifo.init = nouveau_fifo_init;
+ engine->fifo.takedown = nouveau_stub_takedown;
+ engine->fifo.create_context = nv10_fifo_create_context;
+ engine->fifo.destroy_context = nv10_fifo_destroy_context;
+ engine->fifo.load_context = nv10_fifo_load_context;
+ engine->fifo.save_context = nv10_fifo_save_context;
break;
case 0x20:
- engine->Mc.Init = nv04_mc_init;
- engine->Mc.Takedown = nv04_mc_takedown;
- engine->Timer.Init = nv04_timer_init;
- engine->Timer.Takedown = nv04_timer_takedown;
- engine->Fb.Init = nv10_fb_init;
- engine->Fb.Takedown = nv10_fb_takedown;
- engine->Graph.Init = nv20_graph_init;
- engine->Graph.Takedown = nv20_graph_takedown;
- engine->Fifo.Init = nouveau_fifo_init;
- engine->Fifo.Takedown = nouveau_stub_takedown;
+ engine->instmem.init = nv04_instmem_init;
+ engine->instmem.takedown= nv04_instmem_takedown;
+ engine->instmem.populate = nv04_instmem_populate;
+ engine->instmem.clear = nv04_instmem_clear;
+ engine->instmem.bind = nv04_instmem_bind;
+ engine->instmem.unbind = nv04_instmem_unbind;
+ engine->mc.init = nv04_mc_init;
+ engine->mc.takedown = nv04_mc_takedown;
+ engine->timer.init = nv04_timer_init;
+ engine->timer.takedown = nv04_timer_takedown;
+ engine->fb.init = nv10_fb_init;
+ engine->fb.takedown = nv10_fb_takedown;
+ engine->graph.init = nv20_graph_init;
+ engine->graph.takedown = nv20_graph_takedown;
+ engine->graph.create_context = nv20_graph_create_context;
+ engine->graph.destroy_context = nv20_graph_destroy_context;
+ engine->graph.load_context = nv20_graph_load_context;
+ engine->graph.save_context = nv20_graph_save_context;
+ engine->fifo.init = nouveau_fifo_init;
+ engine->fifo.takedown = nouveau_stub_takedown;
+ engine->fifo.create_context = nv10_fifo_create_context;
+ engine->fifo.destroy_context = nv10_fifo_destroy_context;
+ engine->fifo.load_context = nv10_fifo_load_context;
+ engine->fifo.save_context = nv10_fifo_save_context;
break;
case 0x30:
- engine->Mc.Init = nv04_mc_init;
- engine->Mc.Takedown = nv04_mc_takedown;
- engine->Timer.Init = nv04_timer_init;
- engine->Timer.Takedown = nv04_timer_takedown;
- engine->Fb.Init = nv10_fb_init;
- engine->Fb.Takedown = nv10_fb_takedown;
- engine->Graph.Init = nv30_graph_init;
- engine->Graph.Takedown = nv30_graph_takedown;
- engine->Fifo.Init = nouveau_fifo_init;
- engine->Fifo.Takedown = nouveau_stub_takedown;
+ engine->instmem.init = nv04_instmem_init;
+ engine->instmem.takedown= nv04_instmem_takedown;
+ engine->instmem.populate = nv04_instmem_populate;
+ engine->instmem.clear = nv04_instmem_clear;
+ engine->instmem.bind = nv04_instmem_bind;
+ engine->instmem.unbind = nv04_instmem_unbind;
+ engine->mc.init = nv04_mc_init;
+ engine->mc.takedown = nv04_mc_takedown;
+ engine->timer.init = nv04_timer_init;
+ engine->timer.takedown = nv04_timer_takedown;
+ engine->fb.init = nv10_fb_init;
+ engine->fb.takedown = nv10_fb_takedown;
+ engine->graph.init = nv30_graph_init;
+ engine->graph.takedown = nv30_graph_takedown;
+ engine->graph.create_context = nv30_graph_create_context;
+ engine->graph.destroy_context = nv30_graph_destroy_context;
+ engine->graph.load_context = nv30_graph_load_context;
+ engine->graph.save_context = nv30_graph_save_context;
+ engine->fifo.init = nouveau_fifo_init;
+ engine->fifo.takedown = nouveau_stub_takedown;
+ engine->fifo.create_context = nv10_fifo_create_context;
+ engine->fifo.destroy_context = nv10_fifo_destroy_context;
+ engine->fifo.load_context = nv10_fifo_load_context;
+ engine->fifo.save_context = nv10_fifo_save_context;
break;
case 0x40:
- engine->Mc.Init = nv40_mc_init;
- engine->Mc.Takedown = nv40_mc_takedown;
- engine->Timer.Init = nv04_timer_init;
- engine->Timer.Takedown = nv04_timer_takedown;
- engine->Fb.Init = nv40_fb_init;
- engine->Fb.Takedown = nv40_fb_takedown;
- engine->Graph.Init = nv40_graph_init;
- engine->Graph.Takedown = nv40_graph_takedown;
- engine->Fifo.Init = nouveau_fifo_init;
- engine->Fifo.Takedown = nouveau_stub_takedown;
+ engine->instmem.init = nv04_instmem_init;
+ engine->instmem.takedown= nv04_instmem_takedown;
+ engine->instmem.populate = nv04_instmem_populate;
+ engine->instmem.clear = nv04_instmem_clear;
+ engine->instmem.bind = nv04_instmem_bind;
+ engine->instmem.unbind = nv04_instmem_unbind;
+ engine->mc.init = nv40_mc_init;
+ engine->mc.takedown = nv40_mc_takedown;
+ engine->timer.init = nv04_timer_init;
+ engine->timer.takedown = nv04_timer_takedown;
+ engine->fb.init = nv40_fb_init;
+ engine->fb.takedown = nv40_fb_takedown;
+ engine->graph.init = nv40_graph_init;
+ engine->graph.takedown = nv40_graph_takedown;
+ engine->graph.create_context = nv40_graph_create_context;
+ engine->graph.destroy_context = nv40_graph_destroy_context;
+ engine->graph.load_context = nv40_graph_load_context;
+ engine->graph.save_context = nv40_graph_save_context;
+ engine->fifo.init = nouveau_fifo_init;
+ engine->fifo.takedown = nouveau_stub_takedown;
+ engine->fifo.create_context = nv40_fifo_create_context;
+ engine->fifo.destroy_context = nv40_fifo_destroy_context;
+ engine->fifo.load_context = nv40_fifo_load_context;
+ engine->fifo.save_context = nv40_fifo_save_context;
break;
case 0x50:
+ case 0x80: /* gotta love NVIDIA's consistency.. */
+ engine->instmem.init = nv50_instmem_init;
+ engine->instmem.takedown= nv50_instmem_takedown;
+ engine->instmem.populate = nv50_instmem_populate;
+ engine->instmem.clear = nv50_instmem_clear;
+ engine->instmem.bind = nv50_instmem_bind;
+ engine->instmem.unbind = nv50_instmem_unbind;
+ engine->mc.init = nv50_mc_init;
+ engine->mc.takedown = nv50_mc_takedown;
+ engine->timer.init = nouveau_stub_init;
+ engine->timer.takedown = nouveau_stub_takedown;
+ engine->fb.init = nouveau_stub_init;
+ engine->fb.takedown = nouveau_stub_takedown;
+ engine->graph.init = nv50_graph_init;
+ engine->graph.takedown = nv50_graph_takedown;
+ engine->graph.create_context = nv50_graph_create_context;
+ engine->graph.destroy_context = nv50_graph_destroy_context;
+ engine->graph.load_context = nv50_graph_load_context;
+ engine->graph.save_context = nv50_graph_save_context;
+ engine->fifo.init = nv50_fifo_init;
+ engine->fifo.takedown = nv50_fifo_takedown;
+ engine->fifo.create_context = nv50_fifo_create_context;
+ engine->fifo.destroy_context = nv50_fifo_destroy_context;
+ engine->fifo.load_context = nv50_fifo_load_context;
+ engine->fifo.save_context = nv50_fifo_save_context;
+ break;
default:
DRM_ERROR("NV%02x unsupported\n", dev_priv->chipset);
return 1;
@@ -169,12 +280,13 @@ static int nouveau_card_init(drm_device_t *dev)
ret = nouveau_init_engine_ptrs(dev);
if (ret) return ret;
engine = &dev_priv->Engine;
+ dev_priv->init_state = NOUVEAU_CARD_INIT_FAILED;
/* Initialise instance memory, must happen before mem_init so we
* know exactly how much VRAM we're able to use for "normal"
* purposes.
*/
- ret = nouveau_instmem_init(dev);
+ ret = engine->instmem.init(dev);
if (ret) return ret;
/* Setup the memory manager */
@@ -184,38 +296,59 @@ static int nouveau_card_init(drm_device_t *dev)
/* Parse BIOS tables / Run init tables? */
/* PMC */
- ret = engine->Mc.Init(dev);
+ ret = engine->mc.init(dev);
if (ret) return ret;
/* PTIMER */
- ret = engine->Timer.Init(dev);
+ ret = engine->timer.init(dev);
if (ret) return ret;
/* PFB */
- ret = engine->Fb.Init(dev);
+ ret = engine->fb.init(dev);
if (ret) return ret;
/* PGRAPH */
- ret = engine->Graph.Init(dev);
+ ret = engine->graph.init(dev);
if (ret) return ret;
/* PFIFO */
- ret = engine->Fifo.Init(dev);
+ ret = engine->fifo.init(dev);
if (ret) return ret;
/* what about PVIDEO/PCRTC/PRAMDAC etc? */
+ dev_priv->init_state = NOUVEAU_CARD_INIT_DONE;
return 0;
}
+static void nouveau_card_takedown(drm_device_t *dev)
+{
+ drm_nouveau_private_t *dev_priv = dev->dev_private;
+ nouveau_engine_func_t *engine = &dev_priv->Engine;
+
+ if (dev_priv->init_state != NOUVEAU_CARD_INIT_DOWN) {
+ engine->fifo.takedown(dev);
+ engine->graph.takedown(dev);
+ engine->fb.takedown(dev);
+ engine->timer.takedown(dev);
+ engine->mc.takedown(dev);
+ nouveau_gpuobj_takedown(dev);
+ nouveau_mem_close(dev);
+ engine->instmem.takedown(dev);
+
+ dev_priv->init_state = NOUVEAU_CARD_INIT_DOWN;
+ }
+}
+
/* here a client dies, release the stuff that was allocated for its filp */
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);
+ nouveau_mem_release(filp,dev_priv->pci_heap);
}
/* first module load, setup the mmio/fb mapping */
@@ -235,18 +368,17 @@ 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);
- dev_priv = drm_alloc(sizeof(drm_nouveau_private_t), DRM_MEM_DRIVER);
+ dev_priv = drm_calloc(1, sizeof(*dev_priv), DRM_MEM_DRIVER);
if (!dev_priv)
return DRM_ERR(ENOMEM);
- memset(dev_priv, 0, sizeof(drm_nouveau_private_t));
dev_priv->card_type=flags&NOUVEAU_FAMILY;
dev_priv->flags=flags&NOUVEAU_FLAGS;
+ dev_priv->init_state = NOUVEAU_CARD_INIT_DOWN;
dev->dev_private = (void *)dev_priv;
@@ -264,6 +396,9 @@ int nouveau_load(struct drm_device *dev, unsigned long flags)
void nouveau_lastclose(struct drm_device *dev)
{
drm_nouveau_private_t *dev_priv = dev->dev_private;
+
+ nouveau_card_takedown(dev);
+
if(dev_priv->fb_mtrr>0)
{
drm_mtrr_del(dev_priv->fb_mtrr, drm_get_resource_start(dev, 1),nouveau_mem_fb_amount(dev), DRM_MTRR_WC);
@@ -308,6 +443,15 @@ int nouveau_ioctl_getparam(DRM_IOCTL_ARGS)
case NOUVEAU_GETPARAM_AGP_PHYSICAL:
getparam.value=dev_priv->agp_phys;
break;
+ case NOUVEAU_GETPARAM_PCI_PHYSICAL:
+ if ( dev -> sg )
+ getparam.value=(uint64_t) dev->sg->virtual;
+ else
+ {
+ DRM_ERROR("Requested PCIGART address, while no PCIGART was created\n");
+ return DRM_ERR(EINVAL);
+ }
+ break;
case NOUVEAU_GETPARAM_FB_SIZE:
getparam.value=dev_priv->fb_available_size;
break;
@@ -338,6 +482,8 @@ int nouveau_ioctl_setparam(DRM_IOCTL_ARGS)
switch (setparam.value) {
case NOUVEAU_MEM_AGP:
case NOUVEAU_MEM_FB:
+ case NOUVEAU_MEM_PCI:
+ case NOUVEAU_MEM_AGP | NOUVEAU_MEM_PCI_ACCEPTABLE:
break;
default:
DRM_ERROR("invalid CMDBUF_LOCATION value=%lld\n",
@@ -366,6 +512,8 @@ void nouveau_wait_for_idle(struct drm_device *dev)
case NV_03:
while(NV_READ(NV03_PGRAPH_STATUS));
break;
+ case NV_50:
+ break;
default:
while(NV_READ(NV04_PGRAPH_STATUS));
break;
diff --git a/shared-core/nv04_fifo.c b/shared-core/nv04_fifo.c
new file mode 100644
index 00000000..e2e934d7
--- /dev/null
+++ b/shared-core/nv04_fifo.c
@@ -0,0 +1,130 @@
+/*
+ * 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"
+
+#define RAMFC_WR(offset,val) INSTANCE_WR(chan->ramfc->gpuobj, \
+ NV04_RAMFC_##offset/4, (val))
+#define RAMFC_RD(offset) INSTANCE_RD(chan->ramfc->gpuobj, \
+ NV04_RAMFC_##offset/4)
+#define NV04_RAMFC(c) (dev_priv->ramfc_offset + ((c) * NV04_RAMFC__SIZE))
+#define NV04_RAMFC__SIZE 32
+
+int
+nv04_fifo_create_context(drm_device_t *dev, int channel)
+{
+ drm_nouveau_private_t *dev_priv = dev->dev_private;
+ struct nouveau_fifo *chan = dev_priv->fifos[channel];
+ int ret;
+
+ if ((ret = nouveau_gpuobj_new_fake(dev, NV04_RAMFC(channel),
+ NV04_RAMFC__SIZE,
+ NVOBJ_FLAG_ZERO_ALLOC |
+ NVOBJ_FLAG_ZERO_FREE,
+ NULL, &chan->ramfc)))
+ return ret;
+
+ /* Setup initial state */
+ RAMFC_WR(DMA_PUT, chan->pushbuf_base);
+ RAMFC_WR(DMA_GET, chan->pushbuf_base);
+ RAMFC_WR(DMA_INSTANCE, chan->pushbuf->instance >> 4);
+ RAMFC_WR(DMA_FETCH, (NV_PFIFO_CACHE1_DMA_FETCH_TRIG_128_BYTES |
+ NV_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES |
+ NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_8 |
+#ifdef __BIG_ENDIAN
+ NV_PFIFO_CACHE1_BIG_ENDIAN |
+#endif
+ 0));
+
+ /* enable the fifo dma operation */
+ NV_WRITE(NV04_PFIFO_MODE,NV_READ(NV04_PFIFO_MODE)|(1<<channel));
+ return 0;
+}
+
+void
+nv04_fifo_destroy_context(drm_device_t *dev, int channel)
+{
+ drm_nouveau_private_t *dev_priv = dev->dev_private;
+ struct nouveau_fifo *chan = dev_priv->fifos[channel];
+
+ NV_WRITE(NV04_PFIFO_MODE, NV_READ(NV04_PFIFO_MODE)&~(1<<channel));
+
+ if (chan->ramfc)
+ nouveau_gpuobj_ref_del(dev, &chan->ramfc);
+}
+
+int
+nv04_fifo_load_context(drm_device_t *dev, int channel)
+{
+ drm_nouveau_private_t *dev_priv = dev->dev_private;
+ struct nouveau_fifo *chan = dev_priv->fifos[channel];
+ uint32_t tmp;
+
+ NV_WRITE(NV03_PFIFO_CACHE1_PUSH1, (1<<8) | channel);
+
+ NV_WRITE(NV04_PFIFO_CACHE1_DMA_GET, RAMFC_RD(DMA_GET));
+ NV_WRITE(NV04_PFIFO_CACHE1_DMA_PUT, RAMFC_RD(DMA_PUT));
+
+ tmp = RAMFC_RD(DMA_INSTANCE);
+ NV_WRITE(NV04_PFIFO_CACHE1_DMA_INSTANCE, tmp & 0xFFFF);
+ NV_WRITE(NV04_PFIFO_CACHE1_DMA_DCOUNT, tmp >> 16);
+
+ NV_WRITE(NV04_PFIFO_CACHE1_DMA_STATE, RAMFC_RD(DMA_STATE));
+ NV_WRITE(NV04_PFIFO_CACHE1_DMA_FETCH, RAMFC_RD(DMA_FETCH));
+ NV_WRITE(NV04_PFIFO_CACHE1_ENGINE, RAMFC_RD(ENGINE));
+ NV_WRITE(NV04_PFIFO_CACHE1_PULL1, RAMFC_RD(PULL1_ENGINE));
+
+ /* Reset NV04_PFIFO_CACHE1_DMA_CTL_AT_INFO to INVALID */
+ tmp = NV_READ(NV04_PFIFO_CACHE1_DMA_CTL) & ~(1<<31);
+ NV_WRITE(NV04_PFIFO_CACHE1_DMA_CTL, tmp);
+
+ return 0;
+}
+
+int
+nv04_fifo_save_context(drm_device_t *dev, int channel)
+{
+ drm_nouveau_private_t *dev_priv = dev->dev_private;
+ struct nouveau_fifo *chan = dev_priv->fifos[channel];
+ uint32_t tmp;
+
+ RAMFC_WR(DMA_PUT, NV04_PFIFO_CACHE1_DMA_PUT);
+ RAMFC_WR(DMA_GET, NV04_PFIFO_CACHE1_DMA_GET);
+
+ tmp = NV_READ(NV04_PFIFO_CACHE1_DMA_DCOUNT) << 16;
+ tmp |= NV_READ(NV04_PFIFO_CACHE1_DMA_INSTANCE);
+ RAMFC_WR(DMA_INSTANCE, tmp);
+
+ RAMFC_WR(DMA_STATE, NV_READ(NV04_PFIFO_CACHE1_DMA_STATE));
+ RAMFC_WR(DMA_FETCH, NV_READ(NV04_PFIFO_CACHE1_DMA_FETCH));
+ RAMFC_WR(ENGINE, NV_READ(NV04_PFIFO_CACHE1_ENGINE));
+ RAMFC_WR(PULL1_ENGINE, NV_READ(NV04_PFIFO_CACHE1_PULL1));
+
+ return 0;
+}
+
diff --git a/shared-core/nv04_graph.c b/shared-core/nv04_graph.c
index 0cd4d3b8..df23d279 100644
--- a/shared-core/nv04_graph.c
+++ b/shared-core/nv04_graph.c
@@ -309,7 +309,7 @@ void nouveau_nv04_context_switch(drm_device_t *dev)
for (i = 0; i<sizeof(nv04_graph_ctx_regs)/sizeof(nv04_graph_ctx_regs[0]); i++)
for (j = 0; j<nv04_graph_ctx_regs[i].number; j++)
{
- dev_priv->fifos[channel_old].pgraph_ctx[index] = NV_READ(nv04_graph_ctx_regs[i].reg+j*4);
+ dev_priv->fifos[channel_old]->pgraph_ctx[index] = NV_READ(nv04_graph_ctx_regs[i].reg+j*4);
index++;
}
@@ -321,7 +321,7 @@ void nouveau_nv04_context_switch(drm_device_t *dev)
for (i = 0; i<sizeof(nv04_graph_ctx_regs)/sizeof(nv04_graph_ctx_regs[0]); i++)
for (j = 0; j<nv04_graph_ctx_regs[i].number; j++)
{
- NV_WRITE(nv04_graph_ctx_regs[i].reg+j*4, dev_priv->fifos[channel].pgraph_ctx[index]);
+ NV_WRITE(nv04_graph_ctx_regs[i].reg+j*4, dev_priv->fifos[channel]->pgraph_ctx[index]);
index++;
}
@@ -336,14 +336,14 @@ void nouveau_nv04_context_switch(drm_device_t *dev)
NV_WRITE(NV04_PGRAPH_FIFO,0x1);
}
-int nv04_graph_context_create(drm_device_t *dev, int channel) {
+int nv04_graph_create_context(drm_device_t *dev, int channel) {
drm_nouveau_private_t *dev_priv = dev->dev_private;
DRM_DEBUG("nv04_graph_context_create %d\n", channel);
- memset(dev_priv->fifos[channel].pgraph_ctx, 0, sizeof(dev_priv->fifos[channel].pgraph_ctx));
+ memset(dev_priv->fifos[channel]->pgraph_ctx, 0, sizeof(dev_priv->fifos[channel]->pgraph_ctx));
//dev_priv->fifos[channel].pgraph_ctx_user = channel << 24;
- dev_priv->fifos[channel].pgraph_ctx[0] = 0x0001ffff;
+ dev_priv->fifos[channel]->pgraph_ctx[0] = 0x0001ffff;
/* is it really needed ??? */
//dev_priv->fifos[channel].pgraph_ctx[1] = NV_READ(NV_PGRAPH_DEBUG_4);
//dev_priv->fifos[channel].pgraph_ctx[2] = NV_READ(0x004006b0);
@@ -351,6 +351,21 @@ int nv04_graph_context_create(drm_device_t *dev, int channel) {
return 0;
}
+void nv04_graph_destroy_context(drm_device_t *dev, int channel)
+{
+}
+
+int nv04_graph_load_context(drm_device_t *dev, int channel)
+{
+ DRM_ERROR("stub!\n");
+ return 0;
+}
+
+int nv04_graph_save_context(drm_device_t *dev, int channel)
+{
+ DRM_ERROR("stub!\n");
+ return 0;
+}
int nv04_graph_init(drm_device_t *dev) {
drm_nouveau_private_t *dev_priv = dev->dev_private;
@@ -364,7 +379,7 @@ int nv04_graph_init(drm_device_t *dev) {
// check the context is big enough
for ( i = 0 ; i<sizeof(nv04_graph_ctx_regs)/sizeof(nv04_graph_ctx_regs[0]); i++)
sum+=nv04_graph_ctx_regs[i].number;
- if ( sum*4>sizeof(dev_priv->fifos[0].pgraph_ctx) )
+ if ( sum*4>sizeof(dev_priv->fifos[0]->pgraph_ctx) )
DRM_ERROR("pgraph_ctx too small\n");
NV_WRITE(NV03_PGRAPH_INTR_EN, 0x00000000);
diff --git a/shared-core/nv04_instmem.c b/shared-core/nv04_instmem.c
new file mode 100644
index 00000000..ac7d4347
--- /dev/null
+++ b/shared-core/nv04_instmem.c
@@ -0,0 +1,165 @@
+#include "drmP.h"
+#include "drm.h"
+#include "nouveau_drv.h"
+
+static void
+nv04_instmem_determine_amount(struct drm_device *dev)
+{
+ drm_nouveau_private_t *dev_priv = dev->dev_private;
+ int i;
+
+ /* Figure out how much instance memory we need */
+ switch (dev_priv->card_type) {
+ case NV_40:
+ /* We'll want more instance memory than this on some NV4x cards.
+ * There's a 16MB aperture to play with that maps onto the end
+ * of vram. For now, only reserve a small piece until we know
+ * more about what each chipset requires.
+ */
+ dev_priv->ramin_rsvd_vram = (1*1024* 1024);
+ break;
+ default:
+ /*XXX: what *are* the limits on <NV40 cards?, and does RAMIN
+ * exist in vram on those cards as well?
+ */
+ dev_priv->ramin_rsvd_vram = (512*1024);
+ break;
+ }
+ DRM_DEBUG("RAMIN size: %dKiB\n", dev_priv->ramin_rsvd_vram>>10);
+
+ /* Clear all of it, except the BIOS image that's in the first 64KiB */
+ for (i=(64*1024); i<dev_priv->ramin_rsvd_vram; i+=4)
+ NV_WI32(i, 0x00000000);
+}
+
+static void
+nv04_instmem_configure_fixed_tables(struct drm_device *dev)
+{
+ drm_nouveau_private_t *dev_priv = dev->dev_private;
+
+ /* FIFO hash table (RAMHT)
+ * use 4k hash table at RAMIN+0x10000
+ * TODO: extend the hash table
+ */
+ dev_priv->ramht_offset = 0x10000;
+ dev_priv->ramht_bits = 9;
+ dev_priv->ramht_size = (1 << dev_priv->ramht_bits);
+ DRM_DEBUG("RAMHT offset=0x%x, size=%d\n", dev_priv->ramht_offset,
+ dev_priv->ramht_size);
+
+ /* FIFO runout table (RAMRO) - 512k at 0x11200 */
+ dev_priv->ramro_offset = 0x11200;
+ dev_priv->ramro_size = 512;
+ DRM_DEBUG("RAMRO offset=0x%x, size=%d\n", dev_priv->ramro_offset,
+ dev_priv->ramro_size);
+
+ /* FIFO context table (RAMFC)
+ * NV40 : Not sure exactly how to position RAMFC on some cards,
+ * 0x30002 seems to position it at RAMIN+0x20000 on these
+ * cards. RAMFC is 4kb (32 fifos, 128byte entries).
+ * Others: Position RAMFC at RAMIN+0x11400
+ */
+ switch(dev_priv->card_type)
+ {
+ case NV_40:
+ case NV_44:
+ dev_priv->ramfc_offset = 0x20000;
+ dev_priv->ramfc_size = nouveau_fifo_number(dev) *
+ nouveau_fifo_ctx_size(dev);
+ break;
+ case NV_30:
+ case NV_20:
+ case NV_17:
+ case NV_10:
+ case NV_04:
+ case NV_03:
+ default:
+ dev_priv->ramfc_offset = 0x11400;
+ dev_priv->ramfc_size = nouveau_fifo_number(dev) *
+ nouveau_fifo_ctx_size(dev);
+ break;
+ }
+ DRM_DEBUG("RAMFC offset=0x%x, size=%d\n", dev_priv->ramfc_offset,
+ dev_priv->ramfc_size);
+}
+
+int nv04_instmem_init(struct drm_device *dev)
+{
+ drm_nouveau_private_t *dev_priv = dev->dev_private;
+ uint32_t offset;
+ int ret = 0;
+
+ nv04_instmem_determine_amount(dev);
+ nv04_instmem_configure_fixed_tables(dev);
+
+ if ((ret = nouveau_gpuobj_new_fake(dev, dev_priv->ramht_offset,
+ dev_priv->ramht_size,
+ NVOBJ_FLAG_ZERO_ALLOC |
+ NVOBJ_FLAG_ALLOW_NO_REFS,
+ &dev_priv->ramht, NULL)))
+ return ret;
+
+ /* Create a heap to manage RAMIN allocations, we don't allocate
+ * the space that was reserved for RAMHT/FC/RO.
+ */
+ offset = dev_priv->ramfc_offset + dev_priv->ramfc_size;
+ ret = nouveau_mem_init_heap(&dev_priv->ramin_heap,
+ offset, dev_priv->ramin_rsvd_vram - offset);
+ if (ret) {
+ dev_priv->ramin_heap = NULL;
+ DRM_ERROR("Failed to init RAMIN heap\n");
+ }
+
+ return ret;
+}
+
+void
+nv04_instmem_takedown(drm_device_t *dev)
+{
+ drm_nouveau_private_t *dev_priv = dev->dev_private;
+
+ nouveau_gpuobj_del(dev, &dev_priv->ramht);
+}
+
+int
+nv04_instmem_populate(drm_device_t *dev, nouveau_gpuobj_t *gpuobj, uint32_t *sz)
+{
+ if (gpuobj->im_backing)
+ return DRM_ERR(EINVAL);
+
+ return 0;
+}
+
+void
+nv04_instmem_clear(drm_device_t *dev, nouveau_gpuobj_t *gpuobj)
+{
+ drm_nouveau_private_t *dev_priv = dev->dev_private;
+
+ if (gpuobj && gpuobj->im_backing) {
+ if (gpuobj->im_bound)
+ dev_priv->Engine.instmem.unbind(dev, gpuobj);
+ nouveau_mem_free(dev, gpuobj->im_backing);
+ gpuobj->im_backing = NULL;
+ }
+}
+
+int
+nv04_instmem_bind(drm_device_t *dev, nouveau_gpuobj_t *gpuobj)
+{
+ if (!gpuobj->im_pramin || gpuobj->im_bound)
+ return DRM_ERR(EINVAL);
+
+ gpuobj->im_bound = 1;
+ return 0;
+}
+
+int
+nv04_instmem_unbind(drm_device_t *dev, nouveau_gpuobj_t *gpuobj)
+{
+ if (gpuobj->im_bound == 0)
+ return DRM_ERR(EINVAL);
+
+ gpuobj->im_bound = 0;
+ return 0;
+}
+
diff --git a/shared-core/nv10_fifo.c b/shared-core/nv10_fifo.c
new file mode 100644
index 00000000..2d8d5a0d
--- /dev/null
+++ b/shared-core/nv10_fifo.c
@@ -0,0 +1,161 @@
+/*
+ * 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"
+
+
+#define RAMFC_WR(offset,val) INSTANCE_WR(chan->ramfc->gpuobj, \
+ NV10_RAMFC_##offset/4, (val))
+#define RAMFC_RD(offset) INSTANCE_RD(chan->ramfc->gpuobj, \
+ NV10_RAMFC_##offset/4)
+#define NV10_RAMFC(c) (dev_priv->ramfc_offset + NV10_RAMFC__SIZE)
+#define NV10_RAMFC__SIZE ((dev_priv->chipset) >= 0x17 ? 64 : 32)
+
+int
+nv10_fifo_create_context(drm_device_t *dev, int channel)
+{
+ drm_nouveau_private_t *dev_priv = dev->dev_private;
+ struct nouveau_fifo *chan = dev_priv->fifos[channel];
+ int ret;
+
+ if ((ret = nouveau_gpuobj_new_fake(dev, NV10_RAMFC(channel),
+ NV10_RAMFC__SIZE,
+ NVOBJ_FLAG_ZERO_ALLOC |
+ NVOBJ_FLAG_ZERO_FREE,
+ NULL, &chan->ramfc)))
+ return ret;
+
+ /* Fill entries that are seen filled in dumps of nvidia driver just
+ * after channel's is put into DMA mode
+ */
+ RAMFC_WR(DMA_PUT , chan->pushbuf_base);
+ RAMFC_WR(DMA_GET , chan->pushbuf_base);
+ RAMFC_WR(DMA_INSTANCE , chan->pushbuf->instance >> 4);
+ RAMFC_WR(DMA_FETCH , NV_PFIFO_CACHE1_DMA_FETCH_TRIG_128_BYTES |
+ NV_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES |
+ NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_8 |
+#ifdef __BIG_ENDIAN
+ NV_PFIFO_CACHE1_BIG_ENDIAN |
+#endif
+ 0);
+
+ /* enable the fifo dma operation */
+ NV_WRITE(NV04_PFIFO_MODE,NV_READ(NV04_PFIFO_MODE)|(1<<channel));
+ return 0;
+}
+
+void
+nv10_fifo_destroy_context(drm_device_t *dev, int channel)
+{
+ drm_nouveau_private_t *dev_priv = dev->dev_private;
+ struct nouveau_fifo *chan = dev_priv->fifos[channel];
+
+ NV_WRITE(NV04_PFIFO_MODE, NV_READ(NV04_PFIFO_MODE)&~(1<<channel));
+
+ if (chan->ramfc)
+ nouveau_gpuobj_ref_del(dev, &chan->ramfc);
+}
+
+int
+nv10_fifo_load_context(drm_device_t *dev, int channel)
+{
+ drm_nouveau_private_t *dev_priv = dev->dev_private;
+ struct nouveau_fifo *chan = dev_priv->fifos[channel];
+ uint32_t tmp;
+
+ NV_WRITE(NV03_PFIFO_CACHE1_PUSH1 , 0x00000100 | channel);
+
+ NV_WRITE(NV04_PFIFO_CACHE1_DMA_GET , RAMFC_RD(DMA_GET));
+ NV_WRITE(NV04_PFIFO_CACHE1_DMA_PUT , RAMFC_RD(DMA_PUT));
+ NV_WRITE(NV10_PFIFO_CACHE1_REF_CNT , RAMFC_RD(REF_CNT));
+
+ tmp = RAMFC_RD(DMA_INSTANCE);
+ NV_WRITE(NV04_PFIFO_CACHE1_DMA_INSTANCE , tmp & 0xFFFF);
+ NV_WRITE(NV04_PFIFO_CACHE1_DMA_DCOUNT , tmp >> 16);
+
+ NV_WRITE(NV04_PFIFO_CACHE1_DMA_STATE , RAMFC_RD(DMA_STATE));
+ NV_WRITE(NV04_PFIFO_CACHE1_DMA_FETCH , RAMFC_RD(DMA_FETCH));
+ NV_WRITE(NV04_PFIFO_CACHE1_ENGINE , RAMFC_RD(ENGINE));
+ NV_WRITE(NV04_PFIFO_CACHE1_PULL1 , RAMFC_RD(PULL1_ENGINE));
+
+ if (dev_priv->chipset >= 0x17) {
+ NV_WRITE(NV10_PFIFO_CACHE1_ACQUIRE_VALUE,
+ RAMFC_RD(ACQUIRE_VALUE));
+ NV_WRITE(NV10_PFIFO_CACHE1_ACQUIRE_TIMESTAMP,
+ RAMFC_RD(ACQUIRE_TIMESTAMP));
+ NV_WRITE(NV10_PFIFO_CACHE1_ACQUIRE_TIMEOUT,
+ RAMFC_RD(ACQUIRE_TIMEOUT));
+ NV_WRITE(NV10_PFIFO_CACHE1_SEMAPHORE,
+ RAMFC_RD(SEMAPHORE));
+ NV_WRITE(NV10_PFIFO_CACHE1_DMA_SUBROUTINE,
+ RAMFC_RD(DMA_SUBROUTINE));
+ }
+
+ /* Reset NV04_PFIFO_CACHE1_DMA_CTL_AT_INFO to INVALID */
+ tmp = NV_READ(NV04_PFIFO_CACHE1_DMA_CTL) & ~(1<<31);
+ NV_WRITE(NV04_PFIFO_CACHE1_DMA_CTL, tmp);
+
+ return 0;
+}
+
+int
+nv10_fifo_save_context(drm_device_t *dev, int channel)
+{
+ drm_nouveau_private_t *dev_priv = dev->dev_private;
+ struct nouveau_fifo *chan = dev_priv->fifos[channel];
+ uint32_t tmp;
+
+ RAMFC_WR(DMA_PUT , NV_READ(NV04_PFIFO_CACHE1_DMA_PUT));
+ RAMFC_WR(DMA_GET , NV_READ(NV04_PFIFO_CACHE1_DMA_GET));
+ RAMFC_WR(REF_CNT , NV_READ(NV10_PFIFO_CACHE1_REF_CNT));
+
+ tmp = NV_READ(NV04_PFIFO_CACHE1_DMA_INSTANCE) & 0xFFFF;
+ tmp |= (NV_READ(NV04_PFIFO_CACHE1_DMA_DCOUNT) << 16);
+ RAMFC_WR(DMA_INSTANCE , tmp);
+
+ RAMFC_WR(DMA_STATE , NV_READ(NV04_PFIFO_CACHE1_DMA_STATE));
+ RAMFC_WR(DMA_FETCH , NV_READ(NV04_PFIFO_CACHE1_DMA_FETCH));
+ RAMFC_WR(ENGINE , NV_READ(NV04_PFIFO_CACHE1_ENGINE));
+ RAMFC_WR(PULL1_ENGINE , NV_READ(NV04_PFIFO_CACHE1_PULL1));
+
+ if (dev_priv->chipset >= 0x17) {
+ RAMFC_WR(ACQUIRE_VALUE,
+ NV_READ(NV10_PFIFO_CACHE1_ACQUIRE_VALUE));
+ RAMFC_WR(ACQUIRE_TIMESTAMP,
+ NV_READ(NV10_PFIFO_CACHE1_ACQUIRE_TIMESTAMP));
+ RAMFC_WR(ACQUIRE_TIMEOUT,
+ NV_READ(NV10_PFIFO_CACHE1_ACQUIRE_TIMEOUT));
+ RAMFC_WR(SEMAPHORE,
+ NV_READ(NV10_PFIFO_CACHE1_SEMAPHORE));
+ RAMFC_WR(DMA_SUBROUTINE,
+ NV_READ(NV04_PFIFO_CACHE1_DMA_GET));
+ }
+
+ return 0;
+}
+
diff --git a/shared-core/nv10_graph.c b/shared-core/nv10_graph.c
index fb189709..c544afac 100644
--- a/shared-core/nv10_graph.c
+++ b/shared-core/nv10_graph.c
@@ -547,7 +547,7 @@ static int nv10_graph_ctx_regs_find_offset(drm_device_t *dev, int reg)
static void restore_ctx_regs(drm_device_t *dev, int channel)
{
drm_nouveau_private_t *dev_priv = dev->dev_private;
- struct nouveau_fifo *fifo = &dev_priv->fifos[channel];
+ struct nouveau_fifo *fifo = dev_priv->fifos[channel];
int i, j;
for (i = 0; i < sizeof(nv10_graph_ctx_regs)/sizeof(nv10_graph_ctx_regs[0]); i++)
NV_WRITE(nv10_graph_ctx_regs[i], fifo->pgraph_ctx[i]);
@@ -577,10 +577,10 @@ void nouveau_nv10_context_switch(drm_device_t *dev)
// save PGRAPH context
for (i = 0; i < sizeof(nv10_graph_ctx_regs)/sizeof(nv10_graph_ctx_regs[0]); i++)
- dev_priv->fifos[channel_old].pgraph_ctx[i] = NV_READ(nv10_graph_ctx_regs[i]);
+ dev_priv->fifos[channel_old]->pgraph_ctx[i] = NV_READ(nv10_graph_ctx_regs[i]);
if (dev_priv->chipset>=0x17) {
for (j = 0; j < sizeof(nv17_graph_ctx_regs)/sizeof(nv17_graph_ctx_regs[0]); i++,j++)
- dev_priv->fifos[channel_old].pgraph_ctx[i] = NV_READ(nv17_graph_ctx_regs[j]);
+ dev_priv->fifos[channel_old]->pgraph_ctx[i] = NV_READ(nv17_graph_ctx_regs[j]);
}
nouveau_wait_for_idle(dev);
@@ -611,9 +611,9 @@ void nouveau_nv10_context_switch(drm_device_t *dev)
if (offset > 0) \
fifo->pgraph_ctx[offset] = val; \
} while (0)
-int nv10_graph_context_create(drm_device_t *dev, int channel) {
+int nv10_graph_create_context(drm_device_t *dev, int channel) {
drm_nouveau_private_t *dev_priv = dev->dev_private;
- struct nouveau_fifo *fifo = &dev_priv->fifos[channel];
+ struct nouveau_fifo *fifo = dev_priv->fifos[channel];
uint32_t tmp, vramsz;
DRM_DEBUG("nv10_graph_context_create %d\n", channel);
@@ -663,6 +663,21 @@ int nv10_graph_context_create(drm_device_t *dev, int channel) {
return 0;
}
+void nv10_graph_destroy_context(drm_device_t *dev, int channel)
+{
+}
+
+int nv10_graph_load_context(drm_device_t *dev, int channel)
+{
+ DRM_ERROR("stub!\n");
+ return 0;
+}
+
+int nv10_graph_save_context(drm_device_t *dev, int channel)
+{
+ DRM_ERROR("stub!\n");
+ return 0;
+}
int nv10_graph_init(drm_device_t *dev) {
drm_nouveau_private_t *dev_priv = dev->dev_private;
diff --git a/shared-core/nv20_graph.c b/shared-core/nv20_graph.c
index 7190fc84..06d7e440 100644
--- a/shared-core/nv20_graph.c
+++ b/shared-core/nv20_graph.c
@@ -29,28 +29,36 @@
#define NV20_GRCTX_SIZE (3529*4)
-int nv20_graph_context_create(drm_device_t *dev, int channel) {
+int nv20_graph_create_context(drm_device_t *dev, int channel) {
drm_nouveau_private_t *dev_priv =
(drm_nouveau_private_t *)dev->dev_private;
- struct nouveau_fifo *chan = &dev_priv->fifos[channel];
+ struct nouveau_fifo *chan = dev_priv->fifos[channel];
unsigned int ctx_size = NV20_GRCTX_SIZE;
- int i;
+ int ret;
- /* Alloc and clear RAMIN to store the context */
- chan->ramin_grctx = nouveau_instmem_alloc(dev, ctx_size, 4);
- if (!chan->ramin_grctx)
- return DRM_ERR(ENOMEM);
- for (i=0; i<ctx_size; i+=4)
- INSTANCE_WR(chan->ramin_grctx, i/4, 0x00000000);
+ if ((ret = nouveau_gpuobj_new_ref(dev, channel, -1, 0, ctx_size, 16,
+ NVOBJ_FLAG_ZERO_ALLOC,
+ &chan->ramin_grctx)))
+ return ret;
/* Initialise default context values */
- INSTANCE_WR(chan->ramin_grctx, 10, channel << 24); /* CTX_USER */
-
- INSTANCE_WR(dev_priv->ctx_table, channel, nouveau_chip_instance_get(dev, chan->ramin_grctx));
+ INSTANCE_WR(chan->ramin_grctx->gpuobj, 10, channel<<24); /* CTX_USER */
+ INSTANCE_WR(dev_priv->ctx_table->gpuobj, channel,
+ chan->ramin_grctx->instance >> 4);
return 0;
}
+void nv20_graph_destroy_context(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->ramin_grctx)
+ nouveau_gpuobj_ref_del(dev, &chan->ramin_grctx);
+
+ INSTANCE_WR(dev_priv->ctx_table->gpuobj, channel, 0);
+}
+
static void nv20_graph_rdi(drm_device_t *dev) {
drm_nouveau_private_t *dev_priv =
(drm_nouveau_private_t *)dev->dev_private;
@@ -65,40 +73,44 @@ static void nv20_graph_rdi(drm_device_t *dev) {
/* Save current context (from PGRAPH) into the channel's context
*/
-static void nv20_graph_context_save_current(drm_device_t *dev, int channel) {
+int nv20_graph_save_context(drm_device_t *dev, int channel) {
drm_nouveau_private_t *dev_priv =
(drm_nouveau_private_t *)dev->dev_private;
+ struct nouveau_fifo *chan = dev_priv->fifos[channel];
uint32_t instance;
- instance = INSTANCE_RD(dev_priv->ctx_table, channel);
+ instance = INSTANCE_RD(dev_priv->ctx_table->gpuobj, channel);
if (!instance) {
- return;
+ return DRM_ERR(EINVAL);
}
- if (instance != nouveau_chip_instance_get(dev, dev_priv->fifos[channel].ramin_grctx))
- DRM_ERROR("nv20_graph_context_save_current : bad instance\n");
+ if (instance != (chan->ramin_grctx->instance >> 4))
+ DRM_ERROR("nv20_graph_save_context : bad instance\n");
NV_WRITE(NV10_PGRAPH_CHANNEL_CTX_SIZE, instance);
NV_WRITE(NV10_PGRAPH_CHANNEL_CTX_POINTER, 2 /* save ctx */);
+ return 0;
}
/* Restore the context for a specific channel into PGRAPH
*/
-static void nv20_graph_context_restore(drm_device_t *dev, int channel) {
+int nv20_graph_load_context(drm_device_t *dev, int channel) {
drm_nouveau_private_t *dev_priv =
(drm_nouveau_private_t *)dev->dev_private;
+ struct nouveau_fifo *chan = dev_priv->fifos[channel];
uint32_t instance;
- instance = INSTANCE_RD(dev_priv->ctx_table, channel);
+ instance = INSTANCE_RD(dev_priv->ctx_table->gpuobj, channel);
if (!instance) {
- return;
+ return DRM_ERR(EINVAL);
}
- if (instance != nouveau_chip_instance_get(dev, dev_priv->fifos[channel].ramin_grctx))
- DRM_ERROR("nv20_graph_context_restore_current : bad instance\n");
+ if (instance != (chan->ramin_grctx->instance >> 4))
+ DRM_ERROR("nv20_graph_load_context_current : bad instance\n");
NV_WRITE(NV10_PGRAPH_CTX_USER, channel << 24);
NV_WRITE(NV10_PGRAPH_CHANNEL_CTX_SIZE, instance);
NV_WRITE(NV10_PGRAPH_CHANNEL_CTX_POINTER, 1 /* restore ctx */);
+ return 0;
}
void nouveau_nv20_context_switch(drm_device_t *dev)
@@ -113,13 +125,13 @@ void nouveau_nv20_context_switch(drm_device_t *dev)
NV_WRITE(NV04_PGRAPH_FIFO,0x0);
- nv20_graph_context_save_current(dev, channel_old);
+ nv20_graph_save_context(dev, channel_old);
nouveau_wait_for_idle(dev);
NV_WRITE(NV10_PGRAPH_CTX_CONTROL, 0x10000000);
- nv20_graph_context_restore(dev, channel);
+ nv20_graph_load_context(dev, channel);
nouveau_wait_for_idle(dev);
@@ -135,8 +147,8 @@ void nouveau_nv20_context_switch(drm_device_t *dev)
int nv20_graph_init(drm_device_t *dev) {
drm_nouveau_private_t *dev_priv =
(drm_nouveau_private_t *)dev->dev_private;
- int i;
uint32_t tmp, vramsz;
+ int ret, i;
NV_WRITE(NV03_PMC_ENABLE, NV_READ(NV03_PMC_ENABLE) &
~NV_PMC_ENABLE_PGRAPH);
@@ -145,14 +157,14 @@ int nv20_graph_init(drm_device_t *dev) {
/* Create Context Pointer Table */
dev_priv->ctx_table_size = 32 * 4;
- dev_priv->ctx_table = nouveau_instmem_alloc(dev, dev_priv->ctx_table_size, 4);
- if (!dev_priv->ctx_table)
- return DRM_ERR(ENOMEM);
-
- for (i=0; i< dev_priv->ctx_table_size; i+=4)
- INSTANCE_WR(dev_priv->ctx_table, i/4, 0x00000000);
-
- NV_WRITE(NV10_PGRAPH_CHANNEL_CTX_TABLE, nouveau_chip_instance_get(dev, dev_priv->ctx_table));
+ if ((ret = nouveau_gpuobj_new_ref(dev, -1, -1, 0,
+ dev_priv->ctx_table_size, 16,
+ NVOBJ_FLAG_ZERO_ALLOC,
+ &dev_priv->ctx_table)))
+ return ret;
+
+ NV_WRITE(NV10_PGRAPH_CHANNEL_CTX_TABLE,
+ dev_priv->ctx_table->instance >> 4);
//XXX need to be done and save/restore for each fifo ???
nv20_graph_rdi(dev);
diff --git a/shared-core/nv30_graph.c b/shared-core/nv30_graph.c
index f4faadd8..a83ad714 100644
--- a/shared-core/nv30_graph.c
+++ b/shared-core/nv30_graph.c
@@ -16,7 +16,7 @@
* contexts are taken from dumps just after the 3D object is
* created.
*/
-static void nv30_graph_context_init(drm_device_t *dev, struct mem_block *ctx)
+static void nv30_graph_context_init(drm_device_t *dev, nouveau_gpuobj_t *ctx)
{
drm_nouveau_private_t *dev_priv = dev->dev_private;
int i;
@@ -100,14 +100,14 @@ static void nv30_graph_context_init(drm_device_t *dev, struct mem_block *ctx)
}
-int nv30_graph_context_create(drm_device_t *dev, int channel)
+int nv30_graph_create_context(drm_device_t *dev, int channel)
{
drm_nouveau_private_t *dev_priv =
(drm_nouveau_private_t *)dev->dev_private;
- struct nouveau_fifo *chan = &dev_priv->fifos[channel];
- void (*ctx_init)(drm_device_t *, struct mem_block *);
+ struct nouveau_fifo *chan = dev_priv->fifos[channel];
+ void (*ctx_init)(drm_device_t *, nouveau_gpuobj_t *);
unsigned int ctx_size;
- int i;
+ int ret;
switch (dev_priv->chipset) {
default:
@@ -116,28 +116,91 @@ int nv30_graph_context_create(drm_device_t *dev, int channel)
break;
}
- /* Alloc and clear RAMIN to store the context */
- chan->ramin_grctx = nouveau_instmem_alloc(dev, ctx_size, 4);
- if (!chan->ramin_grctx)
- return DRM_ERR(ENOMEM);
- for (i=0; i<ctx_size; i+=4)
- INSTANCE_WR(chan->ramin_grctx, i/4, 0x00000000);
+ if ((ret = nouveau_gpuobj_new_ref(dev, channel, -1, 0, ctx_size, 16,
+ NVOBJ_FLAG_ZERO_ALLOC,
+ &chan->ramin_grctx)))
+ return ret;
/* Initialise default context values */
- ctx_init(dev, chan->ramin_grctx);
+ ctx_init(dev, chan->ramin_grctx->gpuobj);
- INSTANCE_WR(chan->ramin_grctx, 10, channel << 24); /* CTX_USER */
- INSTANCE_WR(dev_priv->ctx_table, channel, nouveau_chip_instance_get(dev, chan->ramin_grctx));
+ INSTANCE_WR(chan->ramin_grctx->gpuobj, 10, channel<<24); /* CTX_USER */
+ INSTANCE_WR(dev_priv->ctx_table->gpuobj, channel,
+ chan->ramin_grctx->instance >> 4);
return 0;
}
+void nv30_graph_destroy_context(drm_device_t *dev, int channel)
+{
+ drm_nouveau_private_t *dev_priv =
+ (drm_nouveau_private_t *)dev->dev_private;
+ struct nouveau_fifo *chan = dev_priv->fifos[channel];
+
+ if (chan->ramin_grctx)
+ nouveau_gpuobj_ref_del(dev, &chan->ramin_grctx);
+
+ INSTANCE_WR(dev_priv->ctx_table->gpuobj, channel, 0);
+}
+
+static int
+nouveau_graph_wait_idle(drm_device_t *dev)
+{
+ drm_nouveau_private_t *dev_priv = dev->dev_private;
+ int tv = 1000;
+
+ while (tv--) {
+ if (NV_READ(0x400700) == 0)
+ break;
+ }
+
+ if (NV_READ(0x400700)) {
+ DRM_ERROR("timeout!\n");
+ return DRM_ERR(EBUSY);
+ }
+ return 0;
+}
+
+int nv30_graph_load_context(drm_device_t *dev, int channel)
+{
+ drm_nouveau_private_t *dev_priv = dev->dev_private;
+ struct nouveau_fifo *chan = dev_priv->fifos[channel];
+ uint32_t inst;
+
+ if (!chan->ramin_grctx)
+ return DRM_ERR(EINVAL);
+ inst = chan->ramin_grctx->instance >> 4;
+
+ NV_WRITE(NV20_PGRAPH_CHANNEL_CTX_POINTER, inst);
+ NV_WRITE(NV20_PGRAPH_CHANNEL_CTX_XFER,
+ NV20_PGRAPH_CHANNEL_CTX_XFER_LOAD);
+
+ return nouveau_graph_wait_idle(dev);
+}
+
+int nv30_graph_save_context(drm_device_t *dev, int channel)
+{
+ drm_nouveau_private_t *dev_priv = dev->dev_private;
+ struct nouveau_fifo *chan = dev_priv->fifos[channel];
+ uint32_t inst;
+
+ if (!chan->ramin_grctx)
+ return DRM_ERR(EINVAL);
+ inst = chan->ramin_grctx->instance >> 4;
+
+ NV_WRITE(NV20_PGRAPH_CHANNEL_CTX_POINTER, inst);
+ NV_WRITE(NV20_PGRAPH_CHANNEL_CTX_XFER,
+ NV20_PGRAPH_CHANNEL_CTX_XFER_SAVE);
+
+ return nouveau_graph_wait_idle(dev);
+}
+
int nv30_graph_init(drm_device_t *dev)
{
drm_nouveau_private_t *dev_priv =
(drm_nouveau_private_t *)dev->dev_private;
uint32_t vramsz, tmp;
- int i;
+ int ret, i;
NV_WRITE(NV03_PMC_ENABLE, NV_READ(NV03_PMC_ENABLE) &
~NV_PMC_ENABLE_PGRAPH);
@@ -146,14 +209,14 @@ int nv30_graph_init(drm_device_t *dev)
/* Create Context Pointer Table */
dev_priv->ctx_table_size = 32 * 4;
- dev_priv->ctx_table = nouveau_instmem_alloc(dev, dev_priv->ctx_table_size, 4);
- if (!dev_priv->ctx_table)
- return DRM_ERR(ENOMEM);
-
- for (i=0; i< dev_priv->ctx_table_size; i+=4)
- INSTANCE_WR(dev_priv->ctx_table, i/4, 0x00000000);
-
- NV_WRITE(NV10_PGRAPH_CHANNEL_CTX_TABLE, nouveau_chip_instance_get(dev, dev_priv->ctx_table));
+ if ((ret = nouveau_gpuobj_new_ref(dev, -1, -1, 0,
+ dev_priv->ctx_table_size, 16,
+ NVOBJ_FLAG_ZERO_ALLOC,
+ &dev_priv->ctx_table)))
+ return ret;
+
+ NV_WRITE(NV10_PGRAPH_CHANNEL_CTX_TABLE,
+ dev_priv->ctx_table->instance >> 4);
NV_WRITE(NV03_PGRAPH_INTR_EN, 0x00000000);
NV_WRITE(NV03_PGRAPH_INTR , 0xFFFFFFFF);
diff --git a/shared-core/nv40_fifo.c b/shared-core/nv40_fifo.c
new file mode 100644
index 00000000..818a9024
--- /dev/null
+++ b/shared-core/nv40_fifo.c
@@ -0,0 +1,195 @@
+/*
+ * 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 "nouveau_drv.h"
+#include "nouveau_drm.h"
+
+
+#define RAMFC_WR(offset,val) INSTANCE_WR(chan->ramfc->gpuobj, \
+ NV40_RAMFC_##offset/4, (val))
+#define RAMFC_RD(offset) INSTANCE_RD(chan->ramfc->gpuobj, \
+ NV40_RAMFC_##offset/4)
+#define NV40_RAMFC(c) (dev_priv->ramfc_offset + ((c)*NV40_RAMFC__SIZE))
+#define NV40_RAMFC__SIZE 128
+
+int
+nv40_fifo_create_context(drm_device_t *dev, int channel)
+{
+ drm_nouveau_private_t *dev_priv = dev->dev_private;
+ struct nouveau_fifo *chan = dev_priv->fifos[channel];
+ int ret;
+
+ if ((ret = nouveau_gpuobj_new_fake(dev, NV40_RAMFC(channel),
+ NV40_RAMFC__SIZE,
+ NVOBJ_FLAG_ZERO_ALLOC |
+ NVOBJ_FLAG_ZERO_FREE,
+ NULL, &chan->ramfc)))
+ return ret;
+
+ /* Fill entries that are seen filled in dumps of nvidia driver just
+ * after channel's is put into DMA mode
+ */
+ RAMFC_WR(DMA_PUT , chan->pushbuf_base);
+ RAMFC_WR(DMA_GET , chan->pushbuf_base);
+ RAMFC_WR(DMA_INSTANCE , chan->pushbuf->instance >> 4);
+ RAMFC_WR(DMA_FETCH , NV_PFIFO_CACHE1_DMA_FETCH_TRIG_128_BYTES |
+ NV_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES |
+ NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_8 |
+#ifdef __BIG_ENDIAN
+ NV_PFIFO_CACHE1_BIG_ENDIAN |
+#endif
+ 0x30000000 /* no idea.. */);
+ RAMFC_WR(DMA_SUBROUTINE, 0);
+ RAMFC_WR(GRCTX_INSTANCE, chan->ramin_grctx->instance >> 4);
+ RAMFC_WR(DMA_TIMESLICE , 0x0001FFFF);
+
+ /* enable the fifo dma operation */
+ NV_WRITE(NV04_PFIFO_MODE,NV_READ(NV04_PFIFO_MODE)|(1<<channel));
+ return 0;
+}
+
+void
+nv40_fifo_destroy_context(drm_device_t *dev, int channel)
+{
+ drm_nouveau_private_t *dev_priv = dev->dev_private;
+ struct nouveau_fifo *chan = dev_priv->fifos[channel];
+
+ NV_WRITE(NV04_PFIFO_MODE, NV_READ(NV04_PFIFO_MODE)&~(1<<channel));
+
+ if (chan->ramfc)
+ nouveau_gpuobj_ref_del(dev, &chan->ramfc);
+}
+
+int
+nv40_fifo_load_context(drm_device_t *dev, int channel)
+{
+ drm_nouveau_private_t *dev_priv = dev->dev_private;
+ struct nouveau_fifo *chan = dev_priv->fifos[channel];
+ uint32_t tmp, tmp2;
+
+ NV_WRITE(NV04_PFIFO_CACHE1_DMA_GET , RAMFC_RD(DMA_GET));
+ NV_WRITE(NV04_PFIFO_CACHE1_DMA_PUT , RAMFC_RD(DMA_PUT));
+ NV_WRITE(NV10_PFIFO_CACHE1_REF_CNT , RAMFC_RD(REF_CNT));
+ NV_WRITE(NV04_PFIFO_CACHE1_DMA_INSTANCE , RAMFC_RD(DMA_INSTANCE));
+ NV_WRITE(NV04_PFIFO_CACHE1_DMA_DCOUNT , RAMFC_RD(DMA_DCOUNT));
+ NV_WRITE(NV04_PFIFO_CACHE1_DMA_STATE , RAMFC_RD(DMA_STATE));
+
+ /* No idea what 0x2058 is.. */
+ tmp = RAMFC_RD(DMA_FETCH);
+ tmp2 = NV_READ(0x2058) & 0xFFF;
+ tmp2 |= (tmp & 0x30000000);
+ NV_WRITE(0x2058, tmp2);
+ tmp &= ~0x30000000;
+ NV_WRITE(NV04_PFIFO_CACHE1_DMA_FETCH , tmp);
+
+ NV_WRITE(NV04_PFIFO_CACHE1_ENGINE , RAMFC_RD(ENGINE));
+ NV_WRITE(NV04_PFIFO_CACHE1_PULL1 , RAMFC_RD(PULL1_ENGINE));
+ NV_WRITE(NV10_PFIFO_CACHE1_ACQUIRE_VALUE , RAMFC_RD(ACQUIRE_VALUE));
+ NV_WRITE(NV10_PFIFO_CACHE1_ACQUIRE_TIMESTAMP, RAMFC_RD(ACQUIRE_TIMESTAMP));
+ NV_WRITE(NV10_PFIFO_CACHE1_ACQUIRE_TIMEOUT , RAMFC_RD(ACQUIRE_TIMEOUT));
+ NV_WRITE(NV10_PFIFO_CACHE1_SEMAPHORE , RAMFC_RD(SEMAPHORE));
+ NV_WRITE(NV10_PFIFO_CACHE1_DMA_SUBROUTINE , RAMFC_RD(DMA_SUBROUTINE));
+ NV_WRITE(NV40_PFIFO_GRCTX_INSTANCE , RAMFC_RD(GRCTX_INSTANCE));
+ NV_WRITE(0x32e4, RAMFC_RD(UNK_40));
+ /* NVIDIA does this next line twice... */
+ NV_WRITE(0x32e8, RAMFC_RD(UNK_44));
+ NV_WRITE(0x2088, RAMFC_RD(UNK_4C));
+ NV_WRITE(0x3300, RAMFC_RD(UNK_50));
+
+ /* not sure what part is PUT, and which is GET.. never seen a non-zero
+ * value appear in a mmio-trace yet..
+ */
+#if 0
+ tmp = NV_READ(UNK_84);
+ NV_WRITE(NV_PFIFO_CACHE1_GET, tmp ???);
+ NV_WRITE(NV_PFIFO_CACHE1_PUT, tmp ???);
+#endif
+
+ /* Don't clobber the TIMEOUT_ENABLED flag when restoring from RAMFC */
+ tmp = NV_READ(NV04_PFIFO_DMA_TIMESLICE) & ~0x1FFFF;
+ tmp |= RAMFC_RD(DMA_TIMESLICE) & 0x1FFFF;
+ NV_WRITE(NV04_PFIFO_DMA_TIMESLICE, tmp);
+
+ /* Set channel active, and in DMA mode */
+ NV_WRITE(NV03_PFIFO_CACHE1_PUSH1 , 0x00010000 | channel);
+ /* Reset DMA_CTL_AT_INFO to INVALID */
+ tmp = NV_READ(NV04_PFIFO_CACHE1_DMA_CTL) & ~(1<<31);
+ NV_WRITE(NV04_PFIFO_CACHE1_DMA_CTL, tmp);
+
+ return 0;
+}
+
+int
+nv40_fifo_save_context(drm_device_t *dev, int channel)
+{
+ drm_nouveau_private_t *dev_priv = dev->dev_private;
+ struct nouveau_fifo *chan = dev_priv->fifos[channel];
+ uint32_t tmp;
+
+ RAMFC_WR(DMA_PUT , NV_READ(NV04_PFIFO_CACHE1_DMA_PUT));
+ RAMFC_WR(DMA_GET , NV_READ(NV04_PFIFO_CACHE1_DMA_GET));
+ RAMFC_WR(REF_CNT , NV_READ(NV10_PFIFO_CACHE1_REF_CNT));
+ RAMFC_WR(DMA_INSTANCE , NV_READ(NV04_PFIFO_CACHE1_DMA_INSTANCE));
+ RAMFC_WR(DMA_DCOUNT , NV_READ(NV04_PFIFO_CACHE1_DMA_DCOUNT));
+ RAMFC_WR(DMA_STATE , NV_READ(NV04_PFIFO_CACHE1_DMA_STATE));
+
+ tmp = NV_READ(NV04_PFIFO_CACHE1_DMA_FETCH);
+ tmp |= NV_READ(0x2058) & 0x30000000;
+ RAMFC_WR(DMA_FETCH , tmp);
+
+ RAMFC_WR(ENGINE , NV_READ(NV04_PFIFO_CACHE1_ENGINE));
+ RAMFC_WR(PULL1_ENGINE , NV_READ(NV04_PFIFO_CACHE1_PULL1));
+ RAMFC_WR(ACQUIRE_VALUE , NV_READ(NV10_PFIFO_CACHE1_ACQUIRE_VALUE));
+ tmp = NV_READ(NV10_PFIFO_CACHE1_ACQUIRE_TIMESTAMP);
+ RAMFC_WR(ACQUIRE_TIMESTAMP, tmp);
+ RAMFC_WR(ACQUIRE_TIMEOUT , NV_READ(NV10_PFIFO_CACHE1_ACQUIRE_TIMEOUT));
+ RAMFC_WR(SEMAPHORE , NV_READ(NV10_PFIFO_CACHE1_SEMAPHORE));
+
+ /* NVIDIA read 0x3228 first, then write DMA_GET here.. maybe something
+ * more involved depending on the value of 0x3228?
+ */
+ RAMFC_WR(DMA_SUBROUTINE , NV_READ(NV04_PFIFO_CACHE1_DMA_GET));
+
+ RAMFC_WR(GRCTX_INSTANCE , NV_READ(NV40_PFIFO_GRCTX_INSTANCE));
+
+ /* No idea what the below is for exactly, ripped from a mmio-trace */
+ RAMFC_WR(UNK_40 , NV_READ(NV40_PFIFO_UNK32E4));
+
+ /* NVIDIA do this next line twice.. bug? */
+ RAMFC_WR(UNK_44 , NV_READ(0x32e8));
+ RAMFC_WR(UNK_4C , NV_READ(0x2088));
+ RAMFC_WR(UNK_50 , NV_READ(0x3300));
+
+#if 0 /* no real idea which is PUT/GET in UNK_48.. */
+ tmp = NV_READ(NV04_PFIFO_CACHE1_GET);
+ tmp |= (NV_READ(NV04_PFIFO_CACHE1_PUT) << 16);
+ RAMFC_WR(UNK_48 , tmp);
+#endif
+
+ return 0;
+}
+
diff --git a/shared-core/nv40_graph.c b/shared-core/nv40_graph.c
index 792734ed..94d76505 100644
--- a/shared-core/nv40_graph.c
+++ b/shared-core/nv40_graph.c
@@ -1,7 +1,32 @@
+/*
+ * 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"
-#include "nouveau_drm.h"
/* The sizes are taken from the difference between the start of two
* grctx addresses while running the nvidia driver. Probably slightly
@@ -11,7 +36,9 @@
#define NV40_GRCTX_SIZE (175*1024)
#define NV43_GRCTX_SIZE (70*1024)
#define NV46_GRCTX_SIZE (70*1024) /* probably ~64KiB */
+#define NV49_GRCTX_SIZE (164640)
#define NV4A_GRCTX_SIZE (64*1024)
+#define NV4B_GRCTX_SIZE (164640)
#define NV4C_GRCTX_SIZE (25*1024)
#define NV4E_GRCTX_SIZE (25*1024)
@@ -19,13 +46,14 @@
* contexts are taken from dumps just after the 3D object is
* created.
*/
-static void nv40_graph_context_init(drm_device_t *dev, struct mem_block *ctx)
+static void
+nv40_graph_context_init(drm_device_t *dev, nouveau_gpuobj_t *ctx)
{
drm_nouveau_private_t *dev_priv = dev->dev_private;
int i;
/* Always has the "instance address" of itself at offset 0 */
- INSTANCE_WR(ctx, 0x00000/4, nouveau_chip_instance_get(dev, ctx));
+ INSTANCE_WR(ctx, 0x00000/4, ctx->im_pramin->start);
/* unknown */
INSTANCE_WR(ctx, 0x00024/4, 0x0000ffff);
INSTANCE_WR(ctx, 0x00028/4, 0x0000ffff);
@@ -160,12 +188,12 @@ static void nv40_graph_context_init(drm_device_t *dev, struct mem_block *ctx)
}
static void
-nv43_graph_context_init(drm_device_t *dev, struct mem_block *ctx)
+nv43_graph_context_init(drm_device_t *dev, nouveau_gpuobj_t *ctx)
{
drm_nouveau_private_t *dev_priv = dev->dev_private;
int i;
- INSTANCE_WR(ctx, 0x00000/4, nouveau_chip_instance_get(dev, ctx));
+ INSTANCE_WR(ctx, 0x00000/4, ctx->im_pramin->start);
INSTANCE_WR(ctx, 0x00024/4, 0x0000ffff);
INSTANCE_WR(ctx, 0x00028/4, 0x0000ffff);
INSTANCE_WR(ctx, 0x00030/4, 0x00000001);
@@ -275,12 +303,13 @@ nv43_graph_context_init(drm_device_t *dev, struct mem_block *ctx)
INSTANCE_WR(ctx, i/4, 0x3f800000);
};
-static void nv46_graph_context_init(drm_device_t *dev, struct mem_block *ctx)
+static void
+nv46_graph_context_init(drm_device_t *dev, nouveau_gpuobj_t *ctx)
{
drm_nouveau_private_t *dev_priv = dev->dev_private;
int i;
- INSTANCE_WR(ctx, 0x00000/4, nouveau_chip_instance_get(dev, ctx));
+ INSTANCE_WR(ctx, 0x00000/4, ctx->im_pramin->start);
INSTANCE_WR(ctx, 0x00040/4, 0x0000ffff);
INSTANCE_WR(ctx, 0x00044/4, 0x0000ffff);
INSTANCE_WR(ctx, 0x0004c/4, 0x00000001);
@@ -425,12 +454,236 @@ static void nv46_graph_context_init(drm_device_t *dev, struct mem_block *ctx)
INSTANCE_WR(ctx, i/4, 0x3f800000);
}
-static void nv4a_graph_context_init(drm_device_t *dev, struct mem_block *ctx)
+static void
+nv49_graph_context_init(drm_device_t *dev, nouveau_gpuobj_t *ctx)
{
drm_nouveau_private_t *dev_priv = dev->dev_private;
int i;
- INSTANCE_WR(ctx, 0x00000/4, nouveau_chip_instance_get(dev, ctx));
+ INSTANCE_WR(ctx, 0x00000/4, ctx->im_pramin->start);
+ INSTANCE_WR(ctx, 0x00004/4, 0x0000c040);
+ INSTANCE_WR(ctx, 0x00008/4, 0x0000c040);
+ INSTANCE_WR(ctx, 0x0000c/4, 0x0000c040);
+ INSTANCE_WR(ctx, 0x00010/4, 0x0000c040);
+ INSTANCE_WR(ctx, 0x00014/4, 0x0000c040);
+ INSTANCE_WR(ctx, 0x00018/4, 0x0000c040);
+ INSTANCE_WR(ctx, 0x0001c/4, 0x0000c040);
+ INSTANCE_WR(ctx, 0x00020/4, 0x0000c040);
+ INSTANCE_WR(ctx, 0x000c4/4, 0x0000ffff);
+ INSTANCE_WR(ctx, 0x000c8/4, 0x0000ffff);
+ INSTANCE_WR(ctx, 0x000d0/4, 0x00000001);
+ INSTANCE_WR(ctx, 0x001bc/4, 0x20010001);
+ INSTANCE_WR(ctx, 0x001c0/4, 0x0f73ef00);
+ INSTANCE_WR(ctx, 0x001c8/4, 0x02008821);
+ INSTANCE_WR(ctx, 0x00218/4, 0x00000040);
+ INSTANCE_WR(ctx, 0x0021c/4, 0x00000040);
+ INSTANCE_WR(ctx, 0x00220/4, 0x00000040);
+ INSTANCE_WR(ctx, 0x00228/4, 0x00000040);
+ INSTANCE_WR(ctx, 0x00234/4, 0x80000000);
+ INSTANCE_WR(ctx, 0x00238/4, 0x80000000);
+ INSTANCE_WR(ctx, 0x0023c/4, 0x80000000);
+ INSTANCE_WR(ctx, 0x00240/4, 0x80000000);
+ INSTANCE_WR(ctx, 0x00244/4, 0x80000000);
+ INSTANCE_WR(ctx, 0x00248/4, 0x80000000);
+ INSTANCE_WR(ctx, 0x0024c/4, 0x80000000);
+ INSTANCE_WR(ctx, 0x00250/4, 0x80000000);
+ INSTANCE_WR(ctx, 0x00270/4, 0x0b0b0b0c);
+ INSTANCE_WR(ctx, 0x003e0/4, 0x00040000);
+ INSTANCE_WR(ctx, 0x003f0/4, 0x55555555);
+ INSTANCE_WR(ctx, 0x003f4/4, 0x55555555);
+ INSTANCE_WR(ctx, 0x003f8/4, 0x55555555);
+ INSTANCE_WR(ctx, 0x003fc/4, 0x55555555);
+ INSTANCE_WR(ctx, 0x00428/4, 0x00000008);
+ INSTANCE_WR(ctx, 0x0043c/4, 0x00001010);
+ INSTANCE_WR(ctx, 0x00460/4, 0x00000111);
+ INSTANCE_WR(ctx, 0x00464/4, 0x00000111);
+ INSTANCE_WR(ctx, 0x00468/4, 0x00000111);
+ INSTANCE_WR(ctx, 0x0046c/4, 0x00000111);
+ INSTANCE_WR(ctx, 0x00470/4, 0x00000111);
+ INSTANCE_WR(ctx, 0x00474/4, 0x00000111);
+ INSTANCE_WR(ctx, 0x00478/4, 0x00000111);
+ INSTANCE_WR(ctx, 0x0047c/4, 0x00000111);
+ INSTANCE_WR(ctx, 0x00480/4, 0x00000111);
+ INSTANCE_WR(ctx, 0x00484/4, 0x00000111);
+ INSTANCE_WR(ctx, 0x00488/4, 0x00000111);
+ INSTANCE_WR(ctx, 0x0048c/4, 0x00000111);
+ INSTANCE_WR(ctx, 0x00490/4, 0x00000111);
+ INSTANCE_WR(ctx, 0x00494/4, 0x00000111);
+ INSTANCE_WR(ctx, 0x00498/4, 0x00000111);
+ INSTANCE_WR(ctx, 0x0049c/4, 0x00000111);
+ INSTANCE_WR(ctx, 0x004f4/4, 0x00000111);
+ INSTANCE_WR(ctx, 0x004f8/4, 0x00080060);
+ INSTANCE_WR(ctx, 0x00514/4, 0x00000080);
+ INSTANCE_WR(ctx, 0x00518/4, 0xffff0000);
+ INSTANCE_WR(ctx, 0x0051c/4, 0x00000001);
+ INSTANCE_WR(ctx, 0x00530/4, 0x46400000);
+ INSTANCE_WR(ctx, 0x00540/4, 0xffff0000);
+ INSTANCE_WR(ctx, 0x00544/4, 0x88888888);
+ INSTANCE_WR(ctx, 0x00548/4, 0x88888888);
+ INSTANCE_WR(ctx, 0x0054c/4, 0x88888888);
+ INSTANCE_WR(ctx, 0x00550/4, 0x88888888);
+ INSTANCE_WR(ctx, 0x00554/4, 0x88888888);
+ INSTANCE_WR(ctx, 0x00558/4, 0x88888888);
+ INSTANCE_WR(ctx, 0x0055c/4, 0x88888888);
+ INSTANCE_WR(ctx, 0x00560/4, 0x88888888);
+ INSTANCE_WR(ctx, 0x00564/4, 0x88888888);
+ INSTANCE_WR(ctx, 0x00568/4, 0x88888888);
+ INSTANCE_WR(ctx, 0x0056c/4, 0x88888888);
+ INSTANCE_WR(ctx, 0x00570/4, 0x88888888);
+ INSTANCE_WR(ctx, 0x00574/4, 0x88888888);
+ INSTANCE_WR(ctx, 0x00578/4, 0x88888888);
+ INSTANCE_WR(ctx, 0x0057c/4, 0x88888888);
+ INSTANCE_WR(ctx, 0x00580/4, 0x88888888);
+ INSTANCE_WR(ctx, 0x00594/4, 0x0fff0000);
+ INSTANCE_WR(ctx, 0x00598/4, 0x0fff0000);
+ INSTANCE_WR(ctx, 0x005a0/4, 0x00011100);
+ INSTANCE_WR(ctx, 0x005bc/4, 0x07ff0000);
+ INSTANCE_WR(ctx, 0x005c0/4, 0x07ff0000);
+ INSTANCE_WR(ctx, 0x005c4/4, 0x07ff0000);
+ INSTANCE_WR(ctx, 0x005c8/4, 0x07ff0000);
+ INSTANCE_WR(ctx, 0x005cc/4, 0x07ff0000);
+ INSTANCE_WR(ctx, 0x005d0/4, 0x07ff0000);
+ INSTANCE_WR(ctx, 0x005d4/4, 0x07ff0000);
+ INSTANCE_WR(ctx, 0x005d8/4, 0x07ff0000);
+ INSTANCE_WR(ctx, 0x005dc/4, 0x07ff0000);
+ INSTANCE_WR(ctx, 0x005e0/4, 0x07ff0000);
+ INSTANCE_WR(ctx, 0x005e4/4, 0x07ff0000);
+ INSTANCE_WR(ctx, 0x005e8/4, 0x07ff0000);
+ INSTANCE_WR(ctx, 0x005ec/4, 0x07ff0000);
+ INSTANCE_WR(ctx, 0x005f0/4, 0x07ff0000);
+ INSTANCE_WR(ctx, 0x005f4/4, 0x07ff0000);
+ INSTANCE_WR(ctx, 0x005f8/4, 0x07ff0000);
+ INSTANCE_WR(ctx, 0x00604/4, 0x4b7fffff);
+ INSTANCE_WR(ctx, 0x0062c/4, 0x30201000);
+ INSTANCE_WR(ctx, 0x00630/4, 0x70605040);
+ INSTANCE_WR(ctx, 0x00634/4, 0xb8a89888);
+ INSTANCE_WR(ctx, 0x00638/4, 0xf8e8d8c8);
+ INSTANCE_WR(ctx, 0x0064c/4, 0x40100000);
+ INSTANCE_WR(ctx, 0x00668/4, 0x0000ffff);
+ INSTANCE_WR(ctx, 0x0069c/4, 0x435185d6);
+ INSTANCE_WR(ctx, 0x006a0/4, 0x2155b699);
+ INSTANCE_WR(ctx, 0x006a4/4, 0xfedcba98);
+ INSTANCE_WR(ctx, 0x006a8/4, 0x00000098);
+ INSTANCE_WR(ctx, 0x006b8/4, 0xffffffff);
+ INSTANCE_WR(ctx, 0x006bc/4, 0x00ff7000);
+ INSTANCE_WR(ctx, 0x006c0/4, 0x0000ffff);
+ INSTANCE_WR(ctx, 0x006d0/4, 0x00ff0000);
+ INSTANCE_WR(ctx, 0x0070c/4, 0x00ffff00);
+ for (i=0x00750; i<=0x0078c; i+=4)
+ INSTANCE_WR(ctx, i/4, 0x00018488);
+ for (i=0x00790; i<=0x007cc; i+=4)
+ INSTANCE_WR(ctx, i/4, 0x00028202);
+ for (i=0x00810; i<=0x0084c; i+=4)
+ INSTANCE_WR(ctx, i/4, 0x0000aae4);
+ for (i=0x00850; i<=0x0088c; i+=4)
+ INSTANCE_WR(ctx, i/4, 0x01012000);
+ for (i=0x00890; i<=0x008cc; i+=4)
+ INSTANCE_WR(ctx, i/4, 0x00080008);
+ for (i=0x00910; i<=0x0094c; i+=4)
+ INSTANCE_WR(ctx, i/4, 0x00100008);
+ for (i=0x009a0; i<=0x009ac; i+=4)
+ INSTANCE_WR(ctx, i/4, 0x0001bc80);
+ for (i=0x009b0; i<=0x009bc; i+=4)
+ INSTANCE_WR(ctx, i/4, 0x00000202);
+ for (i=0x009d0; i<=0x009dc; i+=4)
+ INSTANCE_WR(ctx, i/4, 0x00000008);
+ for (i=0x009f0; i<=0x009fc; i+=4)
+ INSTANCE_WR(ctx, i/4, 0x00080008);
+ INSTANCE_WR(ctx, 0x00a10/4, 0x00000002);
+ INSTANCE_WR(ctx, 0x00a44/4, 0x00000421);
+ INSTANCE_WR(ctx, 0x00a48/4, 0x030c30c3);
+ INSTANCE_WR(ctx, 0x00a54/4, 0x3e020200);
+ INSTANCE_WR(ctx, 0x00a58/4, 0x00ffffff);
+ INSTANCE_WR(ctx, 0x00a5c/4, 0x20103f00);
+ INSTANCE_WR(ctx, 0x00a68/4, 0x00040000);
+ INSTANCE_WR(ctx, 0x00aa0/4, 0x00008100);
+ INSTANCE_WR(ctx, 0x00b2c/4, 0x00000001);
+ INSTANCE_WR(ctx, 0x00b70/4, 0x00001001);
+ INSTANCE_WR(ctx, 0x00b7c/4, 0x00000003);
+ INSTANCE_WR(ctx, 0x00b80/4, 0x00888001);
+ INSTANCE_WR(ctx, 0x00bb0/4, 0xffffffff);
+ INSTANCE_WR(ctx, 0x00bb4/4, 0xffffffff);
+ INSTANCE_WR(ctx, 0x00bb8/4, 0xffffffff);
+ INSTANCE_WR(ctx, 0x00bbc/4, 0xffffffff);
+ INSTANCE_WR(ctx, 0x00bc0/4, 0xffffffff);
+ INSTANCE_WR(ctx, 0x00bc4/4, 0xffffffff);
+ INSTANCE_WR(ctx, 0x00bc8/4, 0xffffffff);
+ INSTANCE_WR(ctx, 0x00bcc/4, 0xffffffff);
+ INSTANCE_WR(ctx, 0x00bd0/4, 0xffffffff);
+ INSTANCE_WR(ctx, 0x00bd4/4, 0xffffffff);
+ INSTANCE_WR(ctx, 0x00bd8/4, 0xffffffff);
+ INSTANCE_WR(ctx, 0x00bdc/4, 0xffffffff);
+ INSTANCE_WR(ctx, 0x00be0/4, 0xffffffff);
+ INSTANCE_WR(ctx, 0x00be4/4, 0xffffffff);
+ INSTANCE_WR(ctx, 0x00be8/4, 0xffffffff);
+ INSTANCE_WR(ctx, 0x00bec/4, 0xffffffff);
+ INSTANCE_WR(ctx, 0x00bf0/4, 0xffffffff);
+ INSTANCE_WR(ctx, 0x00bf4/4, 0xffffffff);
+ INSTANCE_WR(ctx, 0x00bf8/4, 0xffffffff);
+ INSTANCE_WR(ctx, 0x00bfc/4, 0xffffffff);
+ INSTANCE_WR(ctx, 0x00c00/4, 0xffffffff);
+ INSTANCE_WR(ctx, 0x00c04/4, 0xffffffff);
+ INSTANCE_WR(ctx, 0x00c08/4, 0xffffffff);
+ INSTANCE_WR(ctx, 0x00c0c/4, 0xffffffff);
+ INSTANCE_WR(ctx, 0x00c10/4, 0xffffffff);
+ INSTANCE_WR(ctx, 0x00c14/4, 0xffffffff);
+ INSTANCE_WR(ctx, 0x00c18/4, 0xffffffff);
+ INSTANCE_WR(ctx, 0x00c1c/4, 0xffffffff);
+ INSTANCE_WR(ctx, 0x00c20/4, 0xffffffff);
+ INSTANCE_WR(ctx, 0x00c24/4, 0xffffffff);
+ INSTANCE_WR(ctx, 0x00c28/4, 0xffffffff);
+ INSTANCE_WR(ctx, 0x00c2c/4, 0xffffffff);
+ INSTANCE_WR(ctx, 0x00c54/4, 0x00000005);
+ INSTANCE_WR(ctx, 0x00c60/4, 0x0000ffff);
+ INSTANCE_WR(ctx, 0x00c7c/4, 0x00005555);
+ INSTANCE_WR(ctx, 0x00c80/4, 0x00005555);
+ INSTANCE_WR(ctx, 0x00c84/4, 0x00005555);
+ INSTANCE_WR(ctx, 0x00c88/4, 0x00005555);
+ INSTANCE_WR(ctx, 0x00c8c/4, 0x00005555);
+ INSTANCE_WR(ctx, 0x00c90/4, 0x00005555);
+ INSTANCE_WR(ctx, 0x00c94/4, 0x00005555);
+ INSTANCE_WR(ctx, 0x00c98/4, 0x00005555);
+ INSTANCE_WR(ctx, 0x00c9c/4, 0x00000001);
+ INSTANCE_WR(ctx, 0x00cd4/4, 0x00000001);
+ INSTANCE_WR(ctx, 0x00cd8/4, 0x08e00001);
+ INSTANCE_WR(ctx, 0x00cdc/4, 0x000e3000);
+ for(i=0x030a0; i<=0x03118; i+=8)
+ INSTANCE_WR(ctx, i/4, 0x3f800000);
+ for(i=0x098a0; i<=0x0ba90; i+=24)
+ INSTANCE_WR(ctx, i/4, 0x00000001);
+ for(i=0x0baa0; i<=0x0be90; i+=16)
+ INSTANCE_WR(ctx, i/4, 0x3f800000);
+ for(i=0x0e2e0; i<=0x0fff0; i+=24)
+ INSTANCE_WR(ctx, i/4, 0x00000001);
+ for(i=0x10008; i<=0x104d0; i+=24)
+ INSTANCE_WR(ctx, i/4, 0x00000001);
+ for(i=0x104e0; i<=0x108d0; i+=16)
+ INSTANCE_WR(ctx, i/4, 0x3f800000);
+ for(i=0x12d20; i<=0x14f10; i+=24)
+ INSTANCE_WR(ctx, i/4, 0x00000001);
+ for(i=0x14f20; i<=0x15310; i+=16)
+ INSTANCE_WR(ctx, i/4, 0x3f800000);
+ for(i=0x17760; i<=0x19950; i+=24)
+ INSTANCE_WR(ctx, i/4, 0x00000001);
+ for(i=0x19960; i<=0x19d50; i+=16)
+ INSTANCE_WR(ctx, i/4, 0x3f800000);
+ for(i=0x1c1a0; i<=0x1e390; i+=24)
+ INSTANCE_WR(ctx, i/4, 0x00000001);
+ for(i=0x1e3a0; i<=0x1e790; i+=16)
+ INSTANCE_WR(ctx, i/4, 0x3f800000);
+ for(i=0x20be0; i<=0x22dd0; i+=24)
+ INSTANCE_WR(ctx, i/4, 0x00000001);
+ for(i=0x22de0; i<=0x231d0; i+=16)
+ INSTANCE_WR(ctx, i/4, 0x3f800000);
+}
+
+static void
+nv4a_graph_context_init(drm_device_t *dev, nouveau_gpuobj_t *ctx)
+{
+ drm_nouveau_private_t *dev_priv = dev->dev_private;
+ int i;
+
+ INSTANCE_WR(ctx, 0x00000/4, ctx->im_pramin->start);
INSTANCE_WR(ctx, 0x00024/4, 0x0000ffff);
INSTANCE_WR(ctx, 0x00028/4, 0x0000ffff);
INSTANCE_WR(ctx, 0x00030/4, 0x00000001);
@@ -541,13 +794,228 @@ static void nv4a_graph_context_init(drm_device_t *dev, struct mem_block *ctx)
INSTANCE_WR(ctx, i/4, 0x3f800000);
}
+static void
+nv4b_graph_context_init(drm_device_t *dev, nouveau_gpuobj_t *ctx)
+{
+ drm_nouveau_private_t *dev_priv = dev->dev_private;
+ int i;
-static void nv4c_graph_context_init(drm_device_t *dev, struct mem_block *ctx)
+ INSTANCE_WR(ctx, 0x00000/4, ctx->im_pramin->start);
+ INSTANCE_WR(ctx, 0x00004/4, 0x0000c040);
+ INSTANCE_WR(ctx, 0x00008/4, 0x0000c040);
+ INSTANCE_WR(ctx, 0x0000c/4, 0x0000c040);
+ INSTANCE_WR(ctx, 0x00010/4, 0x0000c040);
+ INSTANCE_WR(ctx, 0x00014/4, 0x0000c040);
+ INSTANCE_WR(ctx, 0x00018/4, 0x0000c040);
+ INSTANCE_WR(ctx, 0x0001c/4, 0x0000c040);
+ INSTANCE_WR(ctx, 0x00020/4, 0x0000c040);
+ INSTANCE_WR(ctx, 0x000c4/4, 0x0000ffff);
+ INSTANCE_WR(ctx, 0x000c8/4, 0x0000ffff);
+ INSTANCE_WR(ctx, 0x000d0/4, 0x00000001);
+ INSTANCE_WR(ctx, 0x001bc/4, 0x20010001);
+ INSTANCE_WR(ctx, 0x001c0/4, 0x0f73ef00);
+ INSTANCE_WR(ctx, 0x001c8/4, 0x02008821);
+ INSTANCE_WR(ctx, 0x00218/4, 0x00000040);
+ INSTANCE_WR(ctx, 0x0021c/4, 0x00000040);
+ INSTANCE_WR(ctx, 0x00220/4, 0x00000040);
+ INSTANCE_WR(ctx, 0x00228/4, 0x00000040);
+ INSTANCE_WR(ctx, 0x00234/4, 0x80000000);
+ INSTANCE_WR(ctx, 0x00238/4, 0x80000000);
+ INSTANCE_WR(ctx, 0x0023c/4, 0x80000000);
+ INSTANCE_WR(ctx, 0x00240/4, 0x80000000);
+ INSTANCE_WR(ctx, 0x00244/4, 0x80000000);
+ INSTANCE_WR(ctx, 0x00248/4, 0x80000000);
+ INSTANCE_WR(ctx, 0x0024c/4, 0x80000000);
+ INSTANCE_WR(ctx, 0x00250/4, 0x80000000);
+ INSTANCE_WR(ctx, 0x00270/4, 0x0b0b0b0c);
+ INSTANCE_WR(ctx, 0x003e0/4, 0x00040000);
+ INSTANCE_WR(ctx, 0x003f0/4, 0x55555555);
+ INSTANCE_WR(ctx, 0x003f4/4, 0x55555555);
+ INSTANCE_WR(ctx, 0x003f8/4, 0x55555555);
+ INSTANCE_WR(ctx, 0x003fc/4, 0x55555555);
+ INSTANCE_WR(ctx, 0x00428/4, 0x00000008);
+ INSTANCE_WR(ctx, 0x0043c/4, 0x00001010);
+ INSTANCE_WR(ctx, 0x00460/4, 0x00000111);
+ INSTANCE_WR(ctx, 0x00464/4, 0x00000111);
+ INSTANCE_WR(ctx, 0x00468/4, 0x00000111);
+ INSTANCE_WR(ctx, 0x0046c/4, 0x00000111);
+ INSTANCE_WR(ctx, 0x00470/4, 0x00000111);
+ INSTANCE_WR(ctx, 0x00474/4, 0x00000111);
+ INSTANCE_WR(ctx, 0x00478/4, 0x00000111);
+ INSTANCE_WR(ctx, 0x0047c/4, 0x00000111);
+ INSTANCE_WR(ctx, 0x00480/4, 0x00000111);
+ INSTANCE_WR(ctx, 0x00484/4, 0x00000111);
+ INSTANCE_WR(ctx, 0x00488/4, 0x00000111);
+ INSTANCE_WR(ctx, 0x0048c/4, 0x00000111);
+ INSTANCE_WR(ctx, 0x00490/4, 0x00000111);
+ INSTANCE_WR(ctx, 0x00494/4, 0x00000111);
+ INSTANCE_WR(ctx, 0x00498/4, 0x00000111);
+ INSTANCE_WR(ctx, 0x0049c/4, 0x00000111);
+ INSTANCE_WR(ctx, 0x004f4/4, 0x00000111);
+ INSTANCE_WR(ctx, 0x004f8/4, 0x00080060);
+ INSTANCE_WR(ctx, 0x00514/4, 0x00000080);
+ INSTANCE_WR(ctx, 0x00518/4, 0xffff0000);
+ INSTANCE_WR(ctx, 0x0051c/4, 0x00000001);
+ INSTANCE_WR(ctx, 0x00530/4, 0x46400000);
+ INSTANCE_WR(ctx, 0x00540/4, 0xffff0000);
+ INSTANCE_WR(ctx, 0x00544/4, 0x88888888);
+ INSTANCE_WR(ctx, 0x00548/4, 0x88888888);
+ INSTANCE_WR(ctx, 0x0054c/4, 0x88888888);
+ INSTANCE_WR(ctx, 0x00550/4, 0x88888888);
+ INSTANCE_WR(ctx, 0x00554/4, 0x88888888);
+ INSTANCE_WR(ctx, 0x00558/4, 0x88888888);
+ INSTANCE_WR(ctx, 0x0055c/4, 0x88888888);
+ INSTANCE_WR(ctx, 0x00560/4, 0x88888888);
+ INSTANCE_WR(ctx, 0x00564/4, 0x88888888);
+ INSTANCE_WR(ctx, 0x00568/4, 0x88888888);
+ INSTANCE_WR(ctx, 0x0056c/4, 0x88888888);
+ INSTANCE_WR(ctx, 0x00570/4, 0x88888888);
+ INSTANCE_WR(ctx, 0x00574/4, 0x88888888);
+ INSTANCE_WR(ctx, 0x00578/4, 0x88888888);
+ INSTANCE_WR(ctx, 0x0057c/4, 0x88888888);
+ INSTANCE_WR(ctx, 0x00580/4, 0x88888888);
+ INSTANCE_WR(ctx, 0x00594/4, 0x0fff0000);
+ INSTANCE_WR(ctx, 0x00598/4, 0x0fff0000);
+ INSTANCE_WR(ctx, 0x005a0/4, 0x00011100);
+ INSTANCE_WR(ctx, 0x005bc/4, 0x07ff0000);
+ INSTANCE_WR(ctx, 0x005c0/4, 0x07ff0000);
+ INSTANCE_WR(ctx, 0x005c4/4, 0x07ff0000);
+ INSTANCE_WR(ctx, 0x005c8/4, 0x07ff0000);
+ INSTANCE_WR(ctx, 0x005cc/4, 0x07ff0000);
+ INSTANCE_WR(ctx, 0x005d0/4, 0x07ff0000);
+ INSTANCE_WR(ctx, 0x005d4/4, 0x07ff0000);
+ INSTANCE_WR(ctx, 0x005d8/4, 0x07ff0000);
+ INSTANCE_WR(ctx, 0x005dc/4, 0x07ff0000);
+ INSTANCE_WR(ctx, 0x005e0/4, 0x07ff0000);
+ INSTANCE_WR(ctx, 0x005e4/4, 0x07ff0000);
+ INSTANCE_WR(ctx, 0x005e8/4, 0x07ff0000);
+ INSTANCE_WR(ctx, 0x005ec/4, 0x07ff0000);
+ INSTANCE_WR(ctx, 0x005f0/4, 0x07ff0000);
+ INSTANCE_WR(ctx, 0x005f4/4, 0x07ff0000);
+ INSTANCE_WR(ctx, 0x005f8/4, 0x07ff0000);
+ INSTANCE_WR(ctx, 0x00604/4, 0x4b7fffff);
+ INSTANCE_WR(ctx, 0x0062c/4, 0x30201000);
+ INSTANCE_WR(ctx, 0x00630/4, 0x70605040);
+ INSTANCE_WR(ctx, 0x00634/4, 0xb8a89888);
+ INSTANCE_WR(ctx, 0x00638/4, 0xf8e8d8c8);
+ INSTANCE_WR(ctx, 0x0064c/4, 0x40100000);
+ INSTANCE_WR(ctx, 0x00668/4, 0x0000ffff);
+ INSTANCE_WR(ctx, 0x0069c/4, 0x435185d6);
+ INSTANCE_WR(ctx, 0x006a0/4, 0x2155b699);
+ INSTANCE_WR(ctx, 0x006a4/4, 0xfedcba98);
+ INSTANCE_WR(ctx, 0x006a8/4, 0x00000098);
+ INSTANCE_WR(ctx, 0x006b8/4, 0xffffffff);
+ INSTANCE_WR(ctx, 0x006bc/4, 0x00ff7000);
+ INSTANCE_WR(ctx, 0x006c0/4, 0x0000ffff);
+ INSTANCE_WR(ctx, 0x006d0/4, 0x00ff0000);
+ INSTANCE_WR(ctx, 0x0070c/4, 0x00ffff00);
+ for (i=0x00750; i<=0x0078c; i+=4)
+ INSTANCE_WR(ctx, i/4, 0x00018488);
+ for (i=0x00790; i<=0x007cc; i+=4)
+ INSTANCE_WR(ctx, i/4, 0x00028202);
+ for (i=0x00810; i<=0x0084c; i+=4)
+ INSTANCE_WR(ctx, i/4, 0x0000aae4);
+ for (i=0x00850; i<=0x0088c; i+=4)
+ INSTANCE_WR(ctx, i/4, 0x01012000);
+ for (i=0x00890; i<=0x008cc; i+=4)
+ INSTANCE_WR(ctx, i/4, 0x00080008);
+ for (i=0x00910; i<=0x0094c; i+=4)
+ INSTANCE_WR(ctx, i/4, 0x00100008);
+ for (i=0x009a0; i<=0x009ac; i+=4)
+ INSTANCE_WR(ctx, i/4, 0x0001bc80);
+ for (i=0x009b0; i<=0x009bc; i+=4)
+ INSTANCE_WR(ctx, i/4, 0x00000202);
+ for (i=0x009d0; i<=0x009dc; i+=4)
+ INSTANCE_WR(ctx, i/4, 0x00000008);
+ for (i=0x009f0; i<=0x009fc; i+=4)
+ INSTANCE_WR(ctx, i/4, 0x00080008);
+ INSTANCE_WR(ctx, 0x00a10/4, 0x00000002);
+ INSTANCE_WR(ctx, 0x00a44/4, 0x00000421);
+ INSTANCE_WR(ctx, 0x00a48/4, 0x030c30c3);
+ INSTANCE_WR(ctx, 0x00a54/4, 0x3e020200);
+ INSTANCE_WR(ctx, 0x00a58/4, 0x00ffffff);
+ INSTANCE_WR(ctx, 0x00a5c/4, 0x20103f00);
+ INSTANCE_WR(ctx, 0x00a68/4, 0x00040000);
+ INSTANCE_WR(ctx, 0x00aa0/4, 0x00008100);
+ INSTANCE_WR(ctx, 0x00b2c/4, 0x00000001);
+ INSTANCE_WR(ctx, 0x00b70/4, 0x00001001);
+ INSTANCE_WR(ctx, 0x00b7c/4, 0x00000003);
+ INSTANCE_WR(ctx, 0x00b80/4, 0x00888001);
+ INSTANCE_WR(ctx, 0x00bb0/4, 0xffffffff);
+ INSTANCE_WR(ctx, 0x00bb4/4, 0xffffffff);
+ INSTANCE_WR(ctx, 0x00bb8/4, 0xffffffff);
+ INSTANCE_WR(ctx, 0x00bbc/4, 0xffffffff);
+ INSTANCE_WR(ctx, 0x00bc0/4, 0xffffffff);
+ INSTANCE_WR(ctx, 0x00bc4/4, 0xffffffff);
+ INSTANCE_WR(ctx, 0x00bc8/4, 0xffffffff);
+ INSTANCE_WR(ctx, 0x00bcc/4, 0xffffffff);
+ INSTANCE_WR(ctx, 0x00bd0/4, 0xffffffff);
+ INSTANCE_WR(ctx, 0x00bd4/4, 0xffffffff);
+ INSTANCE_WR(ctx, 0x00bd8/4, 0xffffffff);
+ INSTANCE_WR(ctx, 0x00bdc/4, 0xffffffff);
+ INSTANCE_WR(ctx, 0x00be0/4, 0xffffffff);
+ INSTANCE_WR(ctx, 0x00be4/4, 0xffffffff);
+ INSTANCE_WR(ctx, 0x00be8/4, 0xffffffff);
+ INSTANCE_WR(ctx, 0x00bec/4, 0xffffffff);
+ INSTANCE_WR(ctx, 0x00bf0/4, 0xffffffff);
+ INSTANCE_WR(ctx, 0x00bf4/4, 0xffffffff);
+ INSTANCE_WR(ctx, 0x00bf8/4, 0xffffffff);
+ INSTANCE_WR(ctx, 0x00bfc/4, 0xffffffff);
+ INSTANCE_WR(ctx, 0x00c00/4, 0xffffffff);
+ INSTANCE_WR(ctx, 0x00c04/4, 0xffffffff);
+ INSTANCE_WR(ctx, 0x00c08/4, 0xffffffff);
+ INSTANCE_WR(ctx, 0x00c0c/4, 0xffffffff);
+ INSTANCE_WR(ctx, 0x00c10/4, 0xffffffff);
+ INSTANCE_WR(ctx, 0x00c14/4, 0xffffffff);
+ INSTANCE_WR(ctx, 0x00c18/4, 0xffffffff);
+ INSTANCE_WR(ctx, 0x00c1c/4, 0xffffffff);
+ INSTANCE_WR(ctx, 0x00c20/4, 0xffffffff);
+ INSTANCE_WR(ctx, 0x00c24/4, 0xffffffff);
+ INSTANCE_WR(ctx, 0x00c28/4, 0xffffffff);
+ INSTANCE_WR(ctx, 0x00c2c/4, 0xffffffff);
+ INSTANCE_WR(ctx, 0x00c54/4, 0x00000005);
+ INSTANCE_WR(ctx, 0x00c60/4, 0x0000ffff);
+ INSTANCE_WR(ctx, 0x00c7c/4, 0x00005555);
+ INSTANCE_WR(ctx, 0x00c80/4, 0x00005555);
+ INSTANCE_WR(ctx, 0x00c84/4, 0x00005555);
+ INSTANCE_WR(ctx, 0x00c88/4, 0x00005555);
+ INSTANCE_WR(ctx, 0x00c8c/4, 0x00005555);
+ INSTANCE_WR(ctx, 0x00c90/4, 0x00005555);
+ INSTANCE_WR(ctx, 0x00c94/4, 0x00005555);
+ INSTANCE_WR(ctx, 0x00c98/4, 0x00005555);
+ INSTANCE_WR(ctx, 0x00c9c/4, 0x00000001);
+ INSTANCE_WR(ctx, 0x00cd4/4, 0x00000001);
+ INSTANCE_WR(ctx, 0x00cd8/4, 0x08e00001);
+ INSTANCE_WR(ctx, 0x00cdc/4, 0x000e3000);
+ for(i=0x030a0; i<=0x03118; i+=8)
+ INSTANCE_WR(ctx, i/4, 0x3f800000);
+ for(i=0x098a0; i<=0x0ba90; i+=24)
+ INSTANCE_WR(ctx, i/4, 0x00000001);
+ for(i=0x0baa0; i<=0x0be90; i+=16)
+ INSTANCE_WR(ctx, i/4, 0x3f800000);
+ for(i=0x0e2e0; i<=0x0fff0; i+=24)
+ INSTANCE_WR(ctx, i/4, 0x00000001);
+ for(i=0x10008; i<=0x104d0; i+=24)
+ INSTANCE_WR(ctx, i/4, 0x00000001);
+ for(i=0x104e0; i<=0x108d0; i+=16)
+ INSTANCE_WR(ctx, i/4, 0x3f800000);
+ for(i=0x12d20; i<=0x14f10; i+=24)
+ INSTANCE_WR(ctx, i/4, 0x00000001);
+ for(i=0x14f20; i<=0x15310; i+=16)
+ INSTANCE_WR(ctx, i/4, 0x3f800000);
+ for(i=0x17760; i<=0x19950; i+=24)
+ INSTANCE_WR(ctx, i/4, 0x00000001);
+ for(i=0x19960; i<=0x19d50; i+=16)
+ INSTANCE_WR(ctx, i/4, 0x3f800000);
+}
+
+static void
+nv4c_graph_context_init(drm_device_t *dev, nouveau_gpuobj_t *ctx)
{
drm_nouveau_private_t *dev_priv = dev->dev_private;
int i;
- INSTANCE_WR(ctx, 0x00000/4, nouveau_chip_instance_get(dev, ctx));
+ INSTANCE_WR(ctx, 0x00000/4, ctx->im_pramin->start);
INSTANCE_WR(ctx, 0x00024/4, 0x0000ffff);
INSTANCE_WR(ctx, 0x00028/4, 0x0000ffff);
INSTANCE_WR(ctx, 0x00030/4, 0x00000001);
@@ -648,12 +1116,13 @@ static void nv4c_graph_context_init(drm_device_t *dev, struct mem_block *ctx)
INSTANCE_WR(ctx, i/4, 0x3f800000);
}
-static void nv4e_graph_context_init(drm_device_t *dev, struct mem_block *ctx)
+static void
+nv4e_graph_context_init(drm_device_t *dev, nouveau_gpuobj_t *ctx)
{
drm_nouveau_private_t *dev_priv = dev->dev_private;
int i;
- INSTANCE_WR(ctx, 0x00000/4, nouveau_chip_instance_get(dev, ctx));
+ INSTANCE_WR(ctx, 0x00000/4, ctx->im_pramin->start);
INSTANCE_WR(ctx, 0x00024/4, 0x0000ffff);
INSTANCE_WR(ctx, 0x00028/4, 0x0000ffff);
INSTANCE_WR(ctx, 0x00030/4, 0x00000001);
@@ -755,14 +1224,14 @@ static void nv4e_graph_context_init(drm_device_t *dev, struct mem_block *ctx)
}
int
-nv40_graph_context_create(drm_device_t *dev, int channel)
+nv40_graph_create_context(drm_device_t *dev, int channel)
{
drm_nouveau_private_t *dev_priv =
(drm_nouveau_private_t *)dev->dev_private;
- struct nouveau_fifo *chan = &dev_priv->fifos[channel];
- void (*ctx_init)(drm_device_t *, struct mem_block *);
+ struct nouveau_fifo *chan = dev_priv->fifos[channel];
+ void (*ctx_init)(drm_device_t *, nouveau_gpuobj_t *);
unsigned int ctx_size;
- int i;
+ int ret;
switch (dev_priv->chipset) {
case 0x40:
@@ -777,10 +1246,18 @@ nv40_graph_context_create(drm_device_t *dev, int channel)
ctx_size = NV46_GRCTX_SIZE;
ctx_init = nv46_graph_context_init;
break;
+ case 0x49:
+ ctx_size = NV49_GRCTX_SIZE;
+ ctx_init = nv49_graph_context_init;
+ break;
case 0x4a:
ctx_size = NV4A_GRCTX_SIZE;
ctx_init = nv4a_graph_context_init;
break;
+ case 0x4b:
+ ctx_size = NV4B_GRCTX_SIZE;
+ ctx_init = nv4b_graph_context_init;
+ break;
case 0x4c:
ctx_size = NV4C_GRCTX_SIZE;
ctx_init = nv4c_graph_context_init;
@@ -795,102 +1272,108 @@ nv40_graph_context_create(drm_device_t *dev, int channel)
break;
}
- /* Alloc and clear RAMIN to store the context */
- chan->ramin_grctx = nouveau_instmem_alloc(dev, ctx_size, 4);
- if (!chan->ramin_grctx)
- return DRM_ERR(ENOMEM);
- for (i=0; i<ctx_size; i+=4)
- INSTANCE_WR(chan->ramin_grctx, i/4, 0x00000000);
+ if ((ret = nouveau_gpuobj_new_ref(dev, channel, -1, 0, ctx_size, 16,
+ NVOBJ_FLAG_ZERO_ALLOC,
+ &chan->ramin_grctx)))
+ return ret;
/* Initialise default context values */
- ctx_init(dev, chan->ramin_grctx);
+ ctx_init(dev, chan->ramin_grctx->gpuobj);
return 0;
}
-/* Save current context (from PGRAPH) into the channel's context
- *XXX: fails sometimes, not sure why..
- */
void
-nv40_graph_context_save_current(drm_device_t *dev)
+nv40_graph_destroy_context(drm_device_t *dev, int channel)
{
- drm_nouveau_private_t *dev_priv =
- (drm_nouveau_private_t *)dev->dev_private;
- uint32_t instance;
- int i;
+ drm_nouveau_private_t *dev_priv = dev->dev_private;
+ struct nouveau_fifo *chan = dev_priv->fifos[channel];
- NV_WRITE(NV04_PGRAPH_FIFO, 0);
+ if (chan->ramin_grctx)
+ nouveau_gpuobj_ref_del(dev, &chan->ramin_grctx);
+}
- instance = NV_READ(0x40032C) & 0xFFFFF;
- if (!instance) {
- NV_WRITE(NV04_PGRAPH_FIFO, 1);
- return;
- }
+static int
+nv40_graph_transfer_context(drm_device_t *dev, uint32_t inst, int save)
+{
+ drm_nouveau_private_t *dev_priv = dev->dev_private;
+ uint32_t old_cp, tv = 1000;
+ int i;
- NV_WRITE(0x400784, instance);
- NV_WRITE(0x400310, NV_READ(0x400310) | 0x20);
- NV_WRITE(0x400304, 1);
- /* just in case, we don't want to spin in-kernel forever */
- for (i=0; i<1000; i++) {
- if (NV_READ(0x40030C) == 0)
+ old_cp = NV_READ(NV20_PGRAPH_CHANNEL_CTX_POINTER);
+ NV_WRITE(NV20_PGRAPH_CHANNEL_CTX_POINTER, inst);
+ NV_WRITE(NV40_PGRAPH_CTXCTL_0310,
+ save ? NV40_PGRAPH_CTXCTL_0310_XFER_SAVE :
+ NV40_PGRAPH_CTXCTL_0310_XFER_LOAD);
+ NV_WRITE(NV40_PGRAPH_CTXCTL_0304, NV40_PGRAPH_CTXCTL_0304_XFER_CTX);
+
+ for (i = 0; i < tv; i++) {
+ if (NV_READ(NV40_PGRAPH_CTXCTL_030C) == 0)
break;
}
- if (i==1000) {
- DRM_ERROR("failed to save current grctx to ramin\n");
- DRM_ERROR("instance = 0x%08x\n", NV_READ(0x40032C));
- DRM_ERROR("0x40030C = 0x%08x\n", NV_READ(0x40030C));
- NV_WRITE(NV04_PGRAPH_FIFO, 1);
- return;
+ NV_WRITE(NV20_PGRAPH_CHANNEL_CTX_POINTER, old_cp);
+
+ if (i == tv) {
+ DRM_ERROR("failed: inst=0x%08x save=%d\n", inst, save);
+ DRM_ERROR("0x40030C = 0x%08x\n",
+ NV_READ(NV40_PGRAPH_CTXCTL_030C));
+ return DRM_ERR(EBUSY);
}
- NV_WRITE(NV04_PGRAPH_FIFO, 1);
+ return 0;
+}
+
+/* Save current context (from PGRAPH) into the channel's context
+ *XXX: fails sometimes, not sure why..
+ */
+int
+nv40_graph_save_context(drm_device_t *dev, int channel)
+{
+ drm_nouveau_private_t *dev_priv = dev->dev_private;
+ struct nouveau_fifo *chan = dev_priv->fifos[channel];
+ uint32_t inst;
+
+ if (!chan->ramin_grctx)
+ return DRM_ERR(EINVAL);
+ inst = chan->ramin_grctx->instance >> 4;
+
+ return nv40_graph_transfer_context(dev, inst, 1);
}
/* Restore the context for a specific channel into PGRAPH
* XXX: fails sometimes.. not sure why
*/
-void
-nv40_graph_context_restore(drm_device_t *dev, int channel)
+int
+nv40_graph_load_context(drm_device_t *dev, int channel)
{
- drm_nouveau_private_t *dev_priv =
- (drm_nouveau_private_t *)dev->dev_private;
- struct nouveau_fifo *chan = &dev_priv->fifos[channel];
- uint32_t instance;
- int i;
-
- instance = nouveau_chip_instance_get(dev, chan->ramin_grctx);
+ drm_nouveau_private_t *dev_priv = dev->dev_private;
+ struct nouveau_fifo *chan = dev_priv->fifos[channel];
+ uint32_t inst;
+ int ret;
- NV_WRITE(NV04_PGRAPH_FIFO, 0);
- NV_WRITE(0x400784, instance);
- NV_WRITE(0x400310, NV_READ(0x400310) | 0x40);
- NV_WRITE(0x400304, 1);
- /* just in case, we don't want to spin in-kernel forever */
- for (i=0; i<1000; i++) {
- if (NV_READ(0x40030C) == 0)
- break;
- }
- if (i==1000) {
- DRM_ERROR("failed to restore grctx for ch%d to PGRAPH\n",
- channel);
- DRM_ERROR("instance = 0x%08x\n", instance);
- DRM_ERROR("0x40030C = 0x%08x\n", NV_READ(0x40030C));
- NV_WRITE(NV04_PGRAPH_FIFO, 1);
- return;
- }
+ if (!chan->ramin_grctx)
+ return DRM_ERR(EINVAL);
+ inst = chan->ramin_grctx->instance >> 4;
+ ret = nv40_graph_transfer_context(dev, inst, 0);
+ if (ret)
+ return ret;
/* 0x40032C, no idea of it's exact function. Could simply be a
* record of the currently active PGRAPH context. It's currently
* unknown as to what bit 24 does. The nv ddx has it set, so we will
* set it here too.
*/
- NV_WRITE(0x40032C, instance | 0x01000000);
+ NV_WRITE(NV20_PGRAPH_CHANNEL_CTX_POINTER, inst);
+ NV_WRITE(NV40_PGRAPH_CTXCTL_CUR,
+ (inst & NV40_PGRAPH_CTXCTL_CUR_INST_MASK) |
+ NV40_PGRAPH_CTXCTL_CUR_LOADED);
/* 0x32E0 records the instance address of the active FIFO's PGRAPH
* context. If at any time this doesn't match 0x40032C, you will
* recieve PGRAPH_INTR_CONTEXT_SWITCH
*/
- NV_WRITE(NV40_PFIFO_GRCTX_INSTANCE, instance);
- NV_WRITE(NV04_PGRAPH_FIFO, 1);
+ NV_WRITE(NV40_PFIFO_GRCTX_INSTANCE, inst);
+ return 0;
}
/* Some voodoo that makes context switching work without the binary driver
@@ -1007,6 +1490,39 @@ static uint32_t nv46_ctx_voodoo[] = {
0x00600009, 0x00700005, 0x00700006, 0x0060000e, ~0
};
+//this is used for nv49 and nv4b
+static uint32_t nv49_4b_ctx_voodoo[] ={
+ 0x00400564, 0x00400505, 0x00408165, 0x00408206, 0x00409e68, 0x00200020,
+ 0x0060000a, 0x00700080, 0x00104042, 0x00200020, 0x0060000a, 0x00700000,
+ 0x001040c5, 0x00400f26, 0x00401068, 0x0060000d, 0x0070008f, 0x0070000e,
+ 0x00408d68, 0x004015e6, 0x007000a0, 0x00700080, 0x0040180f, 0x00700000,
+ 0x00200029, 0x0060000a, 0x0011814d, 0x00110158, 0x00105401, 0x0020003a,
+ 0x00100051, 0x001040c5, 0x0010c1c4, 0x001041c9, 0x0010c1dc, 0x00150210,
+ 0x0012c225, 0x00108238, 0x0010823e, 0x001242c0, 0x00200040, 0x00100280,
+ 0x00128100, 0x00128120, 0x00128143, 0x0011415f, 0x0010815c, 0x0010c140,
+ 0x00104029, 0x00110400, 0x00104d12, 0x00500060, 0x004071e6, 0x00200118,
+ 0x0060000a, 0x00200020, 0x00100620, 0x00154650, 0x00104668, 0x0017466d,
+ 0x0011068b, 0x00168691, 0x001046ae, 0x001046b0, 0x001206b4, 0x001046c4,
+ 0x001146c6, 0x00200022, 0x001006cc, 0x001246f0, 0x002000c0, 0x00100700,
+ 0x0010c3d7, 0x001043e1, 0x00500060, 0x00200290, 0x0060000a, 0x00104800,
+ 0x00108901, 0x00124920, 0x0020001f, 0x00100940, 0x00140965, 0x00144a00,
+ 0x00104a19, 0x0010ca1c, 0x00110b00, 0x00200028, 0x00100b08, 0x00134c2e,
+ 0x0010cd00, 0x0010cd04, 0x00120d08, 0x00104d80, 0x00104e00, 0x0012d600,
+ 0x00105c00, 0x00104f06, 0x00105406, 0x00105709, 0x00200340, 0x0060000a,
+ 0x00300000, 0x00200680, 0x00406a0f, 0x00200684, 0x00800001, 0x00200b88,
+ 0x0060000a, 0x00209540, 0x0040708a, 0x00201350, 0x00800041, 0x00407c0f,
+ 0x00600006, 0x00407ce6, 0x00700080, 0x002000a2, 0x0060000a, 0x00104280,
+ 0x00200340, 0x0060000a, 0x00200004, 0x00800001, 0x0070008e, 0x00408d68,
+ 0x0040020f, 0x00600006, 0x00409e68, 0x00600007, 0x0070000f, 0x0070000e,
+ 0x00408d68, 0x0091a880, 0x00901ffe, 0x10940000, 0x00200020, 0x0060000b,
+ 0x00500069, 0x0060000c, 0x00401568, 0x00700000, 0x00200001, 0x0040910e,
+ 0x00200021, 0x0060000a, 0x00409b0d, 0x00104a40, 0x00104a50, 0x00104a60,
+ 0x00104a70, 0x00104a80, 0x00104a90, 0x00104aa0, 0x00104ab0, 0x00407e0e,
+ 0x0040130f, 0x00408568, 0x0040a006, 0x0040a105, 0x00600009, 0x00700005,
+ 0x00700006, 0x0060000e, ~0
+};
+
+
static uint32_t nv4a_ctx_voodoo[] = {
0x00400889, 0x00200000, 0x0060000a, 0x00200000, 0x00300000, 0x00800001,
0x00700009, 0x0060000e, 0x00400d64, 0x00400d05, 0x00409965, 0x00409e06,
@@ -1100,7 +1616,9 @@ nv40_graph_init(drm_device_t *dev)
case 0x40: ctx_voodoo = nv40_ctx_voodoo; break;
case 0x43: ctx_voodoo = nv43_ctx_voodoo; break;
case 0x46: ctx_voodoo = nv46_ctx_voodoo; break;
+ case 0x49: ctx_voodoo = nv49_4b_ctx_voodoo; break;
case 0x4a: ctx_voodoo = nv4a_ctx_voodoo; break;
+ case 0x4b: ctx_voodoo = nv49_4b_ctx_voodoo; break;
case 0x4e: ctx_voodoo = nv4e_ctx_voodoo; break;
default:
DRM_ERROR("Unknown ctx_voodoo for chipset 0x%02x\n",
@@ -1114,15 +1632,15 @@ nv40_graph_init(drm_device_t *dev)
DRM_DEBUG("Loading context-switch voodoo\n");
i = 0;
- NV_WRITE(0x400324, 0);
+ NV_WRITE(NV40_PGRAPH_CTXCTL_UCODE_INDEX, 0);
while (ctx_voodoo[i] != ~0) {
- NV_WRITE(0x400328, ctx_voodoo[i]);
+ NV_WRITE(NV40_PGRAPH_CTXCTL_UCODE_DATA, ctx_voodoo[i]);
i++;
}
}
/* No context present currently */
- NV_WRITE(0x40032C, 0x00000000);
+ NV_WRITE(NV40_PGRAPH_CTXCTL_CUR, 0x00000000);
NV_WRITE(NV03_PGRAPH_INTR_EN, 0x00000000);
NV_WRITE(NV03_PGRAPH_INTR , 0xFFFFFFFF);
diff --git a/shared-core/nv50_fifo.c b/shared-core/nv50_fifo.c
new file mode 100644
index 00000000..ee1fb887
--- /dev/null
+++ b/shared-core/nv50_fifo.c
@@ -0,0 +1,333 @@
+/*
+ * 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"
+
+typedef struct {
+ nouveau_gpuobj_ref_t *thingo;
+ nouveau_gpuobj_ref_t *dummyctx;
+} nv50_fifo_priv;
+
+#define IS_G80 ((dev_priv->chipset & 0xf0) == 0x50)
+
+static void
+nv50_fifo_init_thingo(drm_device_t *dev)
+{
+ drm_nouveau_private_t *dev_priv = dev->dev_private;
+ nv50_fifo_priv *priv = dev_priv->Engine.fifo.priv;
+ nouveau_gpuobj_ref_t *thingo = priv->thingo;
+ int i, fi=2;
+
+ DRM_DEBUG("\n");
+
+ INSTANCE_WR(thingo->gpuobj, 0, 0x7e);
+ INSTANCE_WR(thingo->gpuobj, 1, 0x7e);
+ for (i = 0; i <NV_MAX_FIFO_NUMBER; i++, fi) {
+ if (dev_priv->fifos[i]) {
+ INSTANCE_WR(thingo->gpuobj, fi, i);
+ fi++;
+ }
+ }
+
+ NV_WRITE(0x32f4, thingo->instance >> 12);
+ NV_WRITE(0x32ec, fi);
+ NV_WRITE(0x2500, 0x101);
+}
+
+static int
+nv50_fifo_channel_enable(drm_device_t *dev, int channel)
+{
+ drm_nouveau_private_t *dev_priv = dev->dev_private;
+ struct nouveau_fifo *chan = dev_priv->fifos[channel];
+
+ DRM_DEBUG("ch%d\n", channel);
+
+ if (IS_G80) {
+ if (!chan->ramin)
+ return DRM_ERR(EINVAL);
+
+ NV_WRITE(NV50_PFIFO_CTX_TABLE(channel),
+ (chan->ramin->instance >> 12) |
+ NV50_PFIFO_CTX_TABLE_CHANNEL_ENABLED);
+ } else {
+ if (!chan->ramfc)
+ return DRM_ERR(EINVAL);
+
+ NV_WRITE(NV50_PFIFO_CTX_TABLE(channel),
+ (chan->ramfc->instance >> 8) |
+ NV50_PFIFO_CTX_TABLE_CHANNEL_ENABLED);
+ }
+
+ nv50_fifo_init_thingo(dev);
+ return 0;
+}
+
+static void
+nv50_fifo_channel_disable(drm_device_t *dev, int channel, int nt)
+{
+ drm_nouveau_private_t *dev_priv = dev->dev_private;
+
+ DRM_DEBUG("ch%d, nt=%d\n", channel, nt);
+
+ if (IS_G80) {
+ NV_WRITE(NV50_PFIFO_CTX_TABLE(channel),
+ NV50_PFIFO_CTX_TABLE_INSTANCE_MASK_G80);
+ } else {
+ NV_WRITE(NV50_PFIFO_CTX_TABLE(channel),
+ NV50_PFIFO_CTX_TABLE_INSTANCE_MASK_G84);
+ }
+
+ if (!nt) nv50_fifo_init_thingo(dev);
+}
+
+static void
+nv50_fifo_init_reset(drm_device_t *dev)
+{
+ drm_nouveau_private_t *dev_priv = dev->dev_private;
+ uint32_t pmc_e;
+
+ DRM_DEBUG("\n");
+
+ pmc_e = NV_READ(NV03_PMC_ENABLE);
+ NV_WRITE(NV03_PMC_ENABLE, pmc_e & ~NV_PMC_ENABLE_PFIFO);
+ pmc_e = NV_READ(NV03_PMC_ENABLE);
+ NV_WRITE(NV03_PMC_ENABLE, pmc_e | NV_PMC_ENABLE_PFIFO);
+}
+
+static void
+nv50_fifo_init_context_table(drm_device_t *dev)
+{
+ int i;
+
+ DRM_DEBUG("\n");
+
+ for (i = 0; i < NV50_PFIFO_CTX_TABLE__SIZE; i++)
+ nv50_fifo_channel_disable(dev, i, 1);
+ nv50_fifo_init_thingo(dev);
+}
+
+static void
+nv50_fifo_init_regs__nv(drm_device_t *dev)
+{
+ drm_nouveau_private_t *dev_priv = dev->dev_private;
+
+ DRM_DEBUG("\n");
+
+ NV_WRITE(0x250c, 0x6f3cfc34);
+}
+
+static int
+nv50_fifo_init_regs(drm_device_t *dev)
+{
+ drm_nouveau_private_t *dev_priv = dev->dev_private;
+ nv50_fifo_priv *priv = dev_priv->Engine.fifo.priv;
+ int ret;
+
+ DRM_DEBUG("\n");
+
+ if ((ret = nouveau_gpuobj_new_ref(dev, -1, -1, 0, 0x1000,
+ 0x1000,
+ NVOBJ_FLAG_ZERO_ALLOC |
+ NVOBJ_FLAG_ZERO_FREE,
+ &priv->dummyctx)))
+ return ret;
+
+ NV_WRITE(0x2500, 0);
+ NV_WRITE(0x3250, 0);
+ NV_WRITE(0x3220, 0);
+ NV_WRITE(0x3204, 0);
+ NV_WRITE(0x3210, 0);
+ NV_WRITE(0x3270, 0);
+
+ if (IS_G80) {
+ NV_WRITE(0x2600, (priv->dummyctx->instance>>8) | (1<<31));
+ NV_WRITE(0x27fc, (priv->dummyctx->instance>>8) | (1<<31));
+ } else {
+ NV_WRITE(0x2600, (priv->dummyctx->instance>>12) | (1<<31));
+ NV_WRITE(0x27fc, (priv->dummyctx->instance>>12) | (1<<31));
+ }
+
+ return 0;
+}
+
+int
+nv50_fifo_init(drm_device_t *dev)
+{
+ drm_nouveau_private_t *dev_priv = dev->dev_private;
+ nv50_fifo_priv *priv;
+ int ret;
+
+ DRM_DEBUG("\n");
+
+ priv = drm_calloc(1, sizeof(*priv), DRM_MEM_DRIVER);
+ if (!priv)
+ return DRM_ERR(ENOMEM);
+ dev_priv->Engine.fifo.priv = priv;
+
+ nv50_fifo_init_reset(dev);
+
+ if ((ret = nouveau_gpuobj_new_ref(dev, -1, -1, 0, (128+2)*4, 0x1000,
+ NVOBJ_FLAG_ZERO_ALLOC,
+ &priv->thingo))) {
+ DRM_ERROR("error creating thingo: %d\n", ret);
+ return ret;
+ }
+ nv50_fifo_init_context_table(dev);
+
+ nv50_fifo_init_regs__nv(dev);
+ if ((ret = nv50_fifo_init_regs(dev)))
+ return ret;
+
+ return 0;
+}
+
+void
+nv50_fifo_takedown(drm_device_t *dev)
+{
+ drm_nouveau_private_t *dev_priv = dev->dev_private;
+ nv50_fifo_priv *priv = dev_priv->Engine.fifo.priv;
+
+ DRM_DEBUG("\n");
+
+ if (!priv)
+ return;
+
+ nouveau_gpuobj_ref_del(dev, &priv->thingo);
+ nouveau_gpuobj_ref_del(dev, &priv->dummyctx);
+
+ dev_priv->Engine.fifo.priv = NULL;
+ drm_free(priv, sizeof(*priv), DRM_MEM_DRIVER);
+}
+
+int
+nv50_fifo_create_context(drm_device_t *dev, int channel)
+{
+ drm_nouveau_private_t *dev_priv = dev->dev_private;
+ struct nouveau_fifo *chan = dev_priv->fifos[channel];
+ nouveau_gpuobj_t *ramfc = NULL;
+ int ret;
+
+ DRM_DEBUG("ch%d\n", channel);
+
+ if (IS_G80) {
+ uint32_t ramfc_offset = chan->ramin->gpuobj->im_pramin->start;
+ if ((ret = nouveau_gpuobj_new_fake(dev, ramfc_offset, 0x100,
+ NVOBJ_FLAG_ZERO_ALLOC |
+ NVOBJ_FLAG_ZERO_FREE,
+ &ramfc, &chan->ramfc)))
+ return ret;
+ } else {
+ if ((ret = nouveau_gpuobj_new_ref(dev, channel, -1, 0, 0x100,
+ 256,
+ NVOBJ_FLAG_ZERO_ALLOC |
+ NVOBJ_FLAG_ZERO_FREE,
+ &chan->ramfc)))
+ return ret;
+ ramfc = chan->ramfc->gpuobj;
+ }
+
+ INSTANCE_WR(ramfc, 0x48/4, chan->pushbuf->instance >> 4);
+ INSTANCE_WR(ramfc, 0x80/4, (0xc << 24) | (chan->ramht->instance >> 4));
+ INSTANCE_WR(ramfc, 0x3c/4, 0x000f0078); /* fetch? */
+ INSTANCE_WR(ramfc, 0x44/4, 0x2101ffff);
+ INSTANCE_WR(ramfc, 0x60/4, 0x7fffffff);
+ INSTANCE_WR(ramfc, 0x10/4, 0x00000000);
+ INSTANCE_WR(ramfc, 0x08/4, 0x00000000);
+ INSTANCE_WR(ramfc, 0x40/4, 0x00000000);
+ INSTANCE_WR(ramfc, 0x50/4, 0x2039b2e0);
+ INSTANCE_WR(ramfc, 0x54/4, 0x000f0000);
+ INSTANCE_WR(ramfc, 0x7c/4, 0x30000001);
+ INSTANCE_WR(ramfc, 0x78/4, 0x00000000);
+ INSTANCE_WR(ramfc, 0x4c/4, 0x00007fff);
+
+ if (!IS_G80) {
+ INSTANCE_WR(chan->ramin->gpuobj, 0, channel);
+ INSTANCE_WR(chan->ramin->gpuobj, 1, chan->ramfc->instance);
+
+ INSTANCE_WR(ramfc, 0x88/4, 0x3d520); /* some vram addy >> 10 */
+ INSTANCE_WR(ramfc, 0x98/4, chan->ramin->instance >> 12);
+ }
+
+ if ((ret = nv50_fifo_channel_enable(dev, channel))) {
+ DRM_ERROR("error enabling ch%d: %d\n", channel, ret);
+ nouveau_gpuobj_ref_del(dev, &chan->ramfc);
+ return ret;
+ }
+
+ return 0;
+}
+
+void
+nv50_fifo_destroy_context(drm_device_t *dev, int channel)
+{
+ drm_nouveau_private_t *dev_priv = dev->dev_private;
+ struct nouveau_fifo *chan = dev_priv->fifos[channel];
+
+ DRM_DEBUG("ch%d\n", channel);
+
+ nv50_fifo_channel_disable(dev, channel, 0);
+ nouveau_gpuobj_ref_del(dev, &chan->ramfc);
+}
+
+int
+nv50_fifo_load_context(drm_device_t *dev, int channel)
+{
+ drm_nouveau_private_t *dev_priv = dev->dev_private;
+ struct nouveau_fifo *chan = dev_priv->fifos[channel];
+ nouveau_gpuobj_t *ramfc = chan->ramfc->gpuobj;
+
+ DRM_DEBUG("ch%d\n", channel);
+
+ /*XXX: incomplete, only touches the regs that NV does */
+
+ NV_WRITE(0x3244, 0);
+ NV_WRITE(0x3240, 0);
+
+ NV_WRITE(0x3224, INSTANCE_RD(ramfc, 0x3c/4));
+ NV_WRITE(NV04_PFIFO_CACHE1_DMA_INSTANCE, INSTANCE_RD(ramfc, 0x48/4));
+ NV_WRITE(0x3234, INSTANCE_RD(ramfc, 0x4c/4));
+ NV_WRITE(0x3254, 1);
+ NV_WRITE(NV03_PFIFO_RAMHT, INSTANCE_RD(ramfc, 0x80/4));
+
+ if (!IS_G80) {
+ NV_WRITE(0x340c, INSTANCE_RD(ramfc, 0x88/4));
+ NV_WRITE(0x3410, INSTANCE_RD(ramfc, 0x98/4));
+ }
+
+ NV_WRITE(NV03_PFIFO_CACHE1_PUSH1, channel | (1<<16));
+ return 0;
+}
+
+int
+nv50_fifo_save_context(drm_device_t *dev, int channel)
+{
+ DRM_DEBUG("ch%d\n", channel);
+ DRM_ERROR("stub!\n");
+ return 0;
+}
+
diff --git a/shared-core/nv50_graph.c b/shared-core/nv50_graph.c
new file mode 100644
index 00000000..271ed733
--- /dev/null
+++ b/shared-core/nv50_graph.c
@@ -0,0 +1,301 @@
+/*
+ * 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"
+
+#define IS_G80 ((dev_priv->chipset & 0xf0) == 0x50)
+
+static void
+nv50_graph_init_reset(drm_device_t *dev)
+{
+ drm_nouveau_private_t *dev_priv = dev->dev_private;
+ uint32_t pmc_e;
+
+ DRM_DEBUG("\n");
+
+ pmc_e = NV_READ(NV03_PMC_ENABLE);
+ NV_WRITE(NV03_PMC_ENABLE, pmc_e & ~NV_PMC_ENABLE_PGRAPH);
+ pmc_e = NV_READ(NV03_PMC_ENABLE);
+ NV_WRITE(NV03_PMC_ENABLE, pmc_e | NV_PMC_ENABLE_PGRAPH);
+}
+
+static void
+nv50_graph_init_regs__nv(drm_device_t *dev)
+{
+ drm_nouveau_private_t *dev_priv = dev->dev_private;
+
+ DRM_DEBUG("\n");
+
+ NV_WRITE(0x400804, 0xc0000000);
+ NV_WRITE(0x406800, 0xc0000000);
+ NV_WRITE(0x400c04, 0xc0000000);
+ NV_WRITE(0x401804, 0xc0000000);
+ NV_WRITE(0x405018, 0xc0000000);
+ NV_WRITE(0x402000, 0xc0000000);
+
+ NV_WRITE(0x400108, 0xffffffff);
+ NV_WRITE(0x400100, 0xffffffff);
+
+ NV_WRITE(0x400824, 0x00004000);
+ NV_WRITE(0x400500, 0x00010001);
+}
+
+static void
+nv50_graph_init_regs(drm_device_t *dev)
+{
+ drm_nouveau_private_t *dev_priv = dev->dev_private;
+
+ DRM_DEBUG("\n");
+
+ NV_WRITE(NV04_PGRAPH_DEBUG_3, (1<<2) /* HW_CONTEXT_SWITCH_ENABLED */);
+}
+
+static uint32_t nv84_ctx_voodoo[] = {
+ 0x0070008e, 0x0070009c, 0x00200020, 0x00600008, 0x0050004c, 0x00400e89,
+ 0x00200000, 0x00600007, 0x00300000, 0x00c000ff, 0x00200000, 0x008000ff,
+ 0x00700009, 0x0041634d, 0x00402944, 0x00402905, 0x0040290d, 0x00413e06,
+ 0x00600005, 0x004015c5, 0x00600011, 0x0040270b, 0x004021c5, 0x00700000,
+ 0x00700081, 0x00600004, 0x0050004a, 0x00216f40, 0x00600007, 0x00c02801,
+ 0x0020002e, 0x00800001, 0x005000cb, 0x0090ffff, 0x0091ffff, 0x00200020,
+ 0x00600008, 0x0050004c, 0x00600009, 0x00413e45, 0x0041594d, 0x0070009d,
+ 0x00402dcf, 0x0070009f, 0x0050009f, 0x00402ac0, 0x00200200, 0x00600008,
+ 0x00402a4f, 0x00402ac0, 0x004030cc, 0x00700081, 0x00200000, 0x00600006,
+ 0x00700000, 0x00111bfc, 0x00700083, 0x00300000, 0x00216f40, 0x00600007,
+ 0x00c00b01, 0x0020001e, 0x00800001, 0x005000cb, 0x00c000ff, 0x00700080,
+ 0x00700083, 0x00200047, 0x00600006, 0x0011020a, 0x00200480, 0x00600007,
+ 0x00300000, 0x00c000ff, 0x00c800ff, 0x00414907, 0x00202916, 0x008000ff,
+ 0x0040508c, 0x005000cb, 0x00a0023f, 0x00200040, 0x00600006, 0x0070000f,
+ 0x00170202, 0x0011020a, 0x00200032, 0x0010020d, 0x001c0242, 0x00120302,
+ 0x00140402, 0x00180500, 0x00130509, 0x00150550, 0x00110605, 0x0020000f,
+ 0x00100607, 0x00110700, 0x00110900, 0x00120902, 0x00110a00, 0x00160b02,
+ 0x00120b28, 0x00140b2b, 0x00110c01, 0x00111400, 0x00111405, 0x00111407,
+ 0x00111409, 0x0011140b, 0x002000cb, 0x00101500, 0x0040790f, 0x0040794b,
+ 0x00214d40, 0x00600007, 0x0020043e, 0x008800ff, 0x0070008f, 0x0040798c,
+ 0x005000cb, 0x00000000, 0x0020002b, 0x00101a05, 0x00131c00, 0x00121c04,
+ 0x00141c20, 0x00111c25, 0x00131c40, 0x00121c44, 0x00141c60, 0x00111c65,
+ 0x00131c80, 0x00121c84, 0x00141ca0, 0x00111ca5, 0x00131cc0, 0x00121cc4,
+ 0x00141ce0, 0x00111ce5, 0x00131f00, 0x00191f40, 0x0040a1e0, 0x002001ed,
+ 0x00600006, 0x00200044, 0x00102080, 0x001120c6, 0x001520c9, 0x001920d0,
+ 0x00122100, 0x00122103, 0x00162200, 0x00122207, 0x00112280, 0x00112300,
+ 0x00112302, 0x00122380, 0x0011238b, 0x00112394, 0x0011239c, 0x0040bee1,
+ 0x00200254, 0x00600006, 0x00200044, 0x00102480, 0x0040af0f, 0x0040af4b,
+ 0x00214d40, 0x00600007, 0x0020043e, 0x008800ff, 0x0070008f, 0x0040af8c,
+ 0x005000cb, 0x00000000, 0x001124c6, 0x001524c9, 0x001924d0, 0x00122500,
+ 0x00122503, 0x00162600, 0x00122607, 0x00112680, 0x00112700, 0x00112702,
+ 0x00122780, 0x0011278b, 0x00112794, 0x0011279c, 0x0040d1e2, 0x002002bb,
+ 0x00600006, 0x00200044, 0x00102880, 0x001128c6, 0x001528c9, 0x001928d0,
+ 0x00122900, 0x00122903, 0x00162a00, 0x00122a07, 0x00112a80, 0x00112b00,
+ 0x00112b02, 0x00122b80, 0x00112b8b, 0x00112b94, 0x00112b9c, 0x0040eee3,
+ 0x00200322, 0x00600006, 0x00200044, 0x00102c80, 0x0040df0f, 0x0040df4b,
+ 0x00214d40, 0x00600007, 0x0020043e, 0x008800ff, 0x0070008f, 0x0040df8c,
+ 0x005000cb, 0x00000000, 0x00112cc6, 0x00152cc9, 0x00192cd0, 0x00122d00,
+ 0x00122d03, 0x00162e00, 0x00122e07, 0x00112e80, 0x00112f00, 0x00112f02,
+ 0x00122f80, 0x00112f8b, 0x00112f94, 0x00112f9c, 0x004101e4, 0x00200389,
+ 0x00600006, 0x00200044, 0x00103080, 0x001130c6, 0x001530c9, 0x001930d0,
+ 0x00123100, 0x00123103, 0x00163200, 0x00123207, 0x00113280, 0x00113300,
+ 0x00113302, 0x00123380, 0x0011338b, 0x00113394, 0x0011339c, 0x00411ee5,
+ 0x002003f0, 0x00600006, 0x00200044, 0x00103480, 0x00410f0f, 0x00410f4b,
+ 0x00214d40, 0x00600007, 0x0020043e, 0x008800ff, 0x0070008f, 0x00410f8c,
+ 0x005000cb, 0x00000000, 0x001134c6, 0x001534c9, 0x001934d0, 0x00123500,
+ 0x00123503, 0x00163600, 0x00123607, 0x00113680, 0x00113700, 0x00113702,
+ 0x00123780, 0x0011378b, 0x00113794, 0x0011379c, 0x00000000, 0x0041250f,
+ 0x005000cb, 0x00214d40, 0x00600007, 0x0020043e, 0x008800ff, 0x005000cb,
+ 0x00412887, 0x0060000a, 0x00000000, 0x00413700, 0x007000a0, 0x00700080,
+ 0x00200480, 0x00600007, 0x00200004, 0x00c000ff, 0x008000ff, 0x005000cb,
+ 0x00700000, 0x00200000, 0x00600006, 0x00111bfe, 0x0041594d, 0x00700000,
+ 0x00200000, 0x00600006, 0x00111bfe, 0x00700080, 0x0070001d, 0x0040114d,
+ 0x00700081, 0x00600004, 0x0050004a, 0x00414388, 0x0060000b, 0x00200000,
+ 0x00600006, 0x00700000, 0x0041590b, 0x00111bfd, 0x0040424d, 0x00202916,
+ 0x008000fd, 0x005000cb, 0x00c00002, 0x00200480, 0x00600007, 0x00200160,
+ 0x00800002, 0x005000cb, 0x00c01802, 0x002027b6, 0x00800002, 0x005000cb,
+ 0x00404e4d, 0x0060000b, 0x0041574d, 0x00700001, 0x005000cf, 0x00700003,
+ 0x00415e06, 0x00415f05, 0x0060000d, 0x00700005, 0x0070000d, 0x00700006,
+ 0x0070000b, 0x0070000e, 0x0070001c, 0x0060000c, ~0
+};
+
+static void
+nv50_graph_init_ctxctl(drm_device_t *dev)
+{
+ drm_nouveau_private_t *dev_priv = dev->dev_private;
+ uint32_t *voodoo;
+
+ DRM_DEBUG("\n");
+
+ switch (dev_priv->chipset) {
+ case 0x84:
+ voodoo = nv84_ctx_voodoo;
+ break;
+ default:
+ DRM_ERROR("no voodoo for chipset NV%02x\n", dev_priv->chipset);
+ break;
+ }
+
+ if (voodoo) {
+ NV_WRITE(NV40_PGRAPH_CTXCTL_UCODE_INDEX, 0);
+ while (*voodoo != ~0) {
+ NV_WRITE(NV40_PGRAPH_CTXCTL_UCODE_DATA, *voodoo);
+ voodoo++;
+ }
+ }
+
+ NV_WRITE(0x400320, 4);
+ NV_WRITE(NV40_PGRAPH_CTXCTL_CUR, 0);
+ NV_WRITE(NV20_PGRAPH_CHANNEL_CTX_POINTER, 0);
+}
+
+int
+nv50_graph_init(drm_device_t *dev)
+{
+ DRM_DEBUG("\n");
+
+ nv50_graph_init_reset(dev);
+ nv50_graph_init_regs__nv(dev);
+ nv50_graph_init_regs(dev);
+ nv50_graph_init_ctxctl(dev);
+
+ return 0;
+}
+
+void
+nv50_graph_takedown(drm_device_t *dev)
+{
+ DRM_DEBUG("\n");
+}
+
+int
+nv50_graph_create_context(drm_device_t *dev, int channel)
+{
+ drm_nouveau_private_t *dev_priv = dev->dev_private;
+ struct nouveau_fifo *chan = dev_priv->fifos[channel];
+ nouveau_gpuobj_t *ramin = chan->ramin->gpuobj;
+ int grctx_size = 0x60000, hdr;
+ int ret;
+
+ DRM_DEBUG("ch%d\n", channel);
+
+ if ((ret = nouveau_gpuobj_new_ref(dev, channel, -1, 0,
+ grctx_size, 0x1000,
+ NVOBJ_FLAG_ZERO_ALLOC |
+ NVOBJ_FLAG_ZERO_FREE,
+ &chan->ramin_grctx)))
+ return ret;
+
+ hdr = IS_G80 ? 0x200 : 0x20;
+ INSTANCE_WR(ramin, (hdr + 0x00)/4, 0x00190002);
+ INSTANCE_WR(ramin, (hdr + 0x04)/4, chan->ramin_grctx->instance +
+ grctx_size - 1);
+ INSTANCE_WR(ramin, (hdr + 0x08)/4, chan->ramin_grctx->instance);
+ INSTANCE_WR(ramin, (hdr + 0x0c)/4, 0);
+ INSTANCE_WR(ramin, (hdr + 0x10)/4, 0);
+ INSTANCE_WR(ramin, (hdr + 0x14)/4, 0x00010000);
+
+ return 0;
+}
+
+void
+nv50_graph_destroy_context(drm_device_t *dev, int channel)
+{
+ drm_nouveau_private_t *dev_priv = dev->dev_private;
+ struct nouveau_fifo *chan = dev_priv->fifos[channel];
+ int i, hdr;
+
+ DRM_DEBUG("ch%d\n", channel);
+
+ hdr = IS_G80 ? 0x200 : 0x20;
+ for (i=hdr; i<hdr+24; i+=4)
+ INSTANCE_WR(chan->ramin->gpuobj, i/4, 0);
+
+ nouveau_gpuobj_ref_del(dev, &chan->ramin_grctx);
+}
+
+static int
+nv50_graph_transfer_context(drm_device_t *dev, uint32_t inst, int save)
+{
+ drm_nouveau_private_t *dev_priv = dev->dev_private;
+ uint32_t old_cp, tv = 20000;
+ int i;
+
+ DRM_DEBUG("inst=0x%08x, save=%d\n", inst, save);
+
+ old_cp = NV_READ(NV20_PGRAPH_CHANNEL_CTX_POINTER);
+ NV_WRITE(NV20_PGRAPH_CHANNEL_CTX_POINTER, inst | (1<<31));
+ NV_WRITE(0x400824, NV_READ(0x400824) |
+ (save ? NV40_PGRAPH_CTXCTL_0310_XFER_SAVE :
+ NV40_PGRAPH_CTXCTL_0310_XFER_LOAD));
+ NV_WRITE(NV40_PGRAPH_CTXCTL_0304, NV40_PGRAPH_CTXCTL_0304_XFER_CTX);
+
+ for (i = 0; i < tv; i++) {
+ if (NV_READ(NV40_PGRAPH_CTXCTL_030C) == 0)
+ break;
+ }
+ NV_WRITE(NV20_PGRAPH_CHANNEL_CTX_POINTER, old_cp);
+
+ if (i == tv) {
+ DRM_ERROR("failed: inst=0x%08x save=%d\n", inst, save);
+ DRM_ERROR("0x40030C = 0x%08x\n",
+ NV_READ(NV40_PGRAPH_CTXCTL_030C));
+ return DRM_ERR(EBUSY);
+ }
+
+ return 0;
+}
+
+int
+nv50_graph_load_context(drm_device_t *dev, int channel)
+{
+ drm_nouveau_private_t *dev_priv = dev->dev_private;
+ struct nouveau_fifo *chan = dev_priv->fifos[channel];
+ uint32_t inst = ((chan->ramin->instance >> 12) | (1<<31));
+ int ret;
+
+ DRM_DEBUG("ch%d\n", channel);
+
+#if 0
+ if ((ret = nv50_graph_transfer_context(dev, inst, 0)))
+ return ret;
+#endif
+
+ NV_WRITE(NV20_PGRAPH_CHANNEL_CTX_POINTER, inst);
+ NV_WRITE(0x400320, 4);
+ NV_WRITE(NV40_PGRAPH_CTXCTL_CUR, inst);
+
+ return 0;
+}
+
+int
+nv50_graph_save_context(drm_device_t *dev, int channel)
+{
+ drm_nouveau_private_t *dev_priv = dev->dev_private;
+ struct nouveau_fifo *chan = dev_priv->fifos[channel];
+ uint32_t inst = ((chan->ramin->instance >> 12) | (1<<31));
+
+ DRM_DEBUG("ch%d\n", channel);
+
+ return nv50_graph_transfer_context(dev, inst, 1);
+}
+
diff --git a/shared-core/nv50_instmem.c b/shared-core/nv50_instmem.c
new file mode 100644
index 00000000..81c60829
--- /dev/null
+++ b/shared-core/nv50_instmem.c
@@ -0,0 +1,262 @@
+/*
+ * 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"
+
+typedef struct {
+ uint32_t save1700[5]; /* 0x1700->0x1710 */
+} nv50_instmem_priv;
+
+#define NV50_INSTMEM_PAGE_SHIFT 12
+#define NV50_INSTMEM_PAGE_SIZE (1 << NV50_INSTMEM_PAGE_SHIFT)
+#define NV50_INSTMEM_RSVD_SIZE (64 * 1024)
+#define NV50_INSTMEM_PT_SIZE(a) (((a) >> 12) << 3)
+
+int
+nv50_instmem_init(drm_device_t *dev)
+{
+ drm_nouveau_private_t *dev_priv = dev->dev_private;
+ nv50_instmem_priv *priv;
+ uint32_t rv, pt, pts, cb, cb0, cb1, unk, as;
+ uint32_t i, v;
+ int ret;
+
+ priv = drm_calloc(1, sizeof(*priv), DRM_MEM_DRIVER);
+ if (!priv)
+ return DRM_ERR(ENOMEM);
+ dev_priv->Engine.instmem.priv = priv;
+
+ /* Save current state */
+ for (i = 0x1700; i <= 0x1710; i+=4)
+ priv->save1700[(i-0x1700)/4] = NV_READ(i);
+
+ as = dev_priv->ramin->size;
+ rv = nouveau_mem_fb_amount(dev) - (1*1024*1024);
+ pt = rv + 0xd0000;
+ pts = NV50_INSTMEM_PT_SIZE(as);
+ cb = rv + 0xc8000;
+ if ((dev_priv->chipset & 0xf0) != 0x50) {
+ unk = cb + 0x4200;
+ cb0 = cb + 0x4240;
+ cb1 = cb + 0x278;
+ } else {
+ unk = cb + 0x5400;
+ cb0 = cb + 0x5440;
+ cb1 = cb + 0x1478;
+ }
+
+ DRM_DEBUG("PRAMIN config:\n");
+ DRM_DEBUG(" Rsvd VRAM base: 0x%08x\n", rv);
+ DRM_DEBUG(" Aperture size: %i MiB\n", as >> 20);
+ DRM_DEBUG(" PT base: 0x%08x\n", pt);
+ DRM_DEBUG(" PT size: %d KiB\n", pts >> 10);
+ DRM_DEBUG(" BIOS image: 0x%08x\n", (NV_READ(0x619f04)&~0xff)<<8);
+ DRM_DEBUG(" Config base: 0x%08x\n", cb);
+ DRM_DEBUG(" ctxdma Config0: 0x%08x\n", cb0);
+ DRM_DEBUG(" Config1: 0x%08x\n", cb1);
+
+ /* Map first MiB of reserved vram into BAR0 PRAMIN aperture */
+ NV_WRITE(0x1700, (rv>>16));
+ /* Poke some regs.. */
+ NV_WRITE(0x1704, (cb>>12));
+ NV_WRITE(0x1710, (((unk-cb)>>4))|(1<<31));
+ NV_WRITE(0x1704, (cb>>12)|(1<<30));
+
+ /* CB0, some DMA object, NFI what it points at... Needed however,
+ * or the PRAMIN aperture doesn't operate as expected.
+ */
+ NV_WRITE(NV_RAMIN + (cb0 - rv) + 0x00, 0x7fc00000);
+ NV_WRITE(NV_RAMIN + (cb0 - rv) + 0x04, 0xe1ffffff);
+ NV_WRITE(NV_RAMIN + (cb0 - rv) + 0x08, 0xe0000000);
+ NV_WRITE(NV_RAMIN + (cb0 - rv) + 0x0c, 0x01000001);
+ NV_WRITE(NV_RAMIN + (cb0 - rv) + 0x10, 0x00000000);
+ NV_WRITE(NV_RAMIN + (cb0 - rv) + 0x14, 0x00000000);
+
+ /* CB1, points at PRAMIN PT */
+ NV_WRITE(NV_RAMIN + (cb1 - rv) + 0, pt | 0x63);
+ NV_WRITE(NV_RAMIN + (cb1 - rv) + 4, 0x00000000);
+
+ /* Zero PRAMIN page table */
+ v = NV_RAMIN + (pt - rv);
+ for (i = v; i < v + pts; i += 8) {
+ NV_WRITE(i + 0x00, 0x00000009);
+ NV_WRITE(i + 0x04, 0x00000000);
+ }
+
+ /* Map page table into PRAMIN aperture */
+ for (i = pt; i < pt + pts; i += 0x1000) {
+ uint32_t pte = NV_RAMIN + (pt-rv) + (((i-pt) >> 12) << 3);
+ DRM_DEBUG("PRAMIN PTE = 0x%08x @ 0x%08x\n", i, pte);
+ NV_WRITE(pte + 0x00, i | 1);
+ NV_WRITE(pte + 0x04, 0x00000000);
+ }
+
+ /* Points at CB0 */
+ NV_WRITE(0x170c, (((cb0 - cb)>>4)|(1<<31)));
+
+ /* Confirm it all worked, should be able to read back the page table's
+ * PTEs from the PRAMIN BAR
+ */
+ NV_WRITE(0x1700, pt >> 16);
+ if (NV_READ(0x700000) != NV_RI32(0)) {
+ DRM_ERROR("Failed to init PRAMIN page table\n");
+ return DRM_ERR(EINVAL);
+ }
+
+ /* Create a heap to manage PRAMIN aperture allocations */
+ ret = nouveau_mem_init_heap(&dev_priv->ramin_heap, pts, as-pts);
+ if (ret) {
+ DRM_ERROR("Failed to init PRAMIN heap\n");
+ return DRM_ERR(ENOMEM);
+ }
+ DRM_DEBUG("NV50: PRAMIN setup ok\n");
+
+ /* Don't alloc the last MiB of VRAM, probably too much, but be safe
+ * at least for now.
+ */
+ dev_priv->ramin_rsvd_vram = 1*1024*1024;
+
+ /*XXX: probably incorrect, but needed to make hash func "work" */
+ dev_priv->ramht_offset = 0x10000;
+ dev_priv->ramht_bits = 9;
+ dev_priv->ramht_size = (1 << dev_priv->ramht_bits);
+ return 0;
+}
+
+void
+nv50_instmem_takedown(drm_device_t *dev)
+{
+ drm_nouveau_private_t *dev_priv = dev->dev_private;
+ nv50_instmem_priv *priv = dev_priv->Engine.instmem.priv;
+ int i;
+
+ if (!priv)
+ return;
+
+ /* Restore state from before init */
+ for (i = 0x1700; i <= 0x1710; i+=4)
+ NV_WRITE(i, priv->save1700[(i-0x1700)/4]);
+
+ dev_priv->Engine.instmem.priv = NULL;
+ drm_free(priv, sizeof(*priv), DRM_MEM_DRIVER);
+}
+
+int
+nv50_instmem_populate(drm_device_t *dev, nouveau_gpuobj_t *gpuobj, uint32_t *sz)
+{
+ if (gpuobj->im_backing)
+ return DRM_ERR(EINVAL);
+
+ *sz = (*sz + (NV50_INSTMEM_PAGE_SIZE-1)) & ~(NV50_INSTMEM_PAGE_SIZE-1);
+ if (*sz == 0)
+ return DRM_ERR(EINVAL);
+
+ gpuobj->im_backing = nouveau_mem_alloc(dev, NV50_INSTMEM_PAGE_SIZE,
+ *sz, NOUVEAU_MEM_FB,
+ (DRMFILE)-2);
+ if (!gpuobj->im_backing) {
+ DRM_ERROR("Couldn't allocate vram to back PRAMIN pages\n");
+ return DRM_ERR(ENOMEM);
+ }
+
+ return 0;
+}
+
+void
+nv50_instmem_clear(drm_device_t *dev, nouveau_gpuobj_t *gpuobj)
+{
+ drm_nouveau_private_t *dev_priv = dev->dev_private;
+
+ if (gpuobj && gpuobj->im_backing) {
+ if (gpuobj->im_bound)
+ dev_priv->Engine.instmem.unbind(dev, gpuobj);
+ nouveau_mem_free(dev, gpuobj->im_backing);
+ gpuobj->im_backing = NULL;
+ }
+}
+
+int
+nv50_instmem_bind(drm_device_t *dev, nouveau_gpuobj_t *gpuobj)
+{
+ drm_nouveau_private_t *dev_priv = dev->dev_private;
+ uint32_t pte, pte_end, vram;
+
+ if (!gpuobj->im_backing || !gpuobj->im_pramin || gpuobj->im_bound)
+ return DRM_ERR(EINVAL);
+
+ DRM_DEBUG("st=0x%0llx sz=0x%0llx\n",
+ gpuobj->im_pramin->start, gpuobj->im_pramin->size);
+
+ pte = (gpuobj->im_pramin->start >> 12) << 3;
+ pte_end = ((gpuobj->im_pramin->size >> 12) << 3) + pte;
+ vram = gpuobj->im_backing->start;
+
+ if (pte == pte_end) {
+ DRM_ERROR("WARNING: badness in bind() pte calc\n");
+ pte_end++;
+ }
+
+ DRM_DEBUG("pramin=0x%llx, pte=%d, pte_end=%d\n",
+ gpuobj->im_pramin->start, pte, pte_end);
+ DRM_DEBUG("first vram page: 0x%llx\n",
+ gpuobj->im_backing->start);
+
+ while (pte < pte_end) {
+ NV_WI32(pte + 0, vram | 1);
+ NV_WI32(pte + 4, 0x00000000);
+
+ pte += 8;
+ vram += NV50_INSTMEM_PAGE_SIZE;
+ }
+
+ gpuobj->im_bound = 1;
+ return 0;
+}
+
+int
+nv50_instmem_unbind(drm_device_t *dev, nouveau_gpuobj_t *gpuobj)
+{
+ drm_nouveau_private_t *dev_priv = dev->dev_private;
+ uint32_t pte, pte_end;
+
+ if (gpuobj->im_bound == 0)
+ return DRM_ERR(EINVAL);
+
+ pte = (gpuobj->im_pramin->start >> 12) << 3;
+ pte_end = ((gpuobj->im_pramin->size >> 12) << 3) + pte;
+ while (pte < pte_end) {
+ NV_WI32(pte + 0, 0x00000000);
+ NV_WI32(pte + 4, 0x00000000);
+ pte += 8;
+ }
+
+ gpuobj->im_bound = 0;
+ return 0;
+}
+
diff --git a/shared-core/nv50_mc.c b/shared-core/nv50_mc.c
new file mode 100644
index 00000000..7f7537f0
--- /dev/null
+++ b/shared-core/nv50_mc.c
@@ -0,0 +1,42 @@
+/*
+ * 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
+nv50_mc_init(drm_device_t *dev)
+{
+ drm_nouveau_private_t *dev_priv = dev->dev_private;
+
+ NV_WRITE(NV03_PMC_ENABLE, 0xFFFFFFFF);
+ return 0;
+}
+
+void nv50_mc_takedown(drm_device_t *dev)
+{
+}
diff --git a/shared-core/r300_cmdbuf.c b/shared-core/r300_cmdbuf.c
index c02334a2..0cd5d7e2 100644
--- a/shared-core/r300_cmdbuf.c
+++ b/shared-core/r300_cmdbuf.c
@@ -156,6 +156,7 @@ void r300_init_reg_flags(void)
ADD_RANGE(0x21DC, 1);
ADD_RANGE(R300_VAP_UNKNOWN_221C, 1);
ADD_RANGE(R300_VAP_CLIP_X_0, 4);
+ ADD_RANGE(R300_VAP_PVS_WAITIDLE, 1);
ADD_RANGE(R300_VAP_UNKNOWN_2288, 1);
ADD_RANGE(R300_VAP_OUTPUT_VTX_FMT_0, 2);
ADD_RANGE(R300_VAP_PVS_CNTL_1, 3);
diff --git a/shared-core/r300_reg.h b/shared-core/r300_reg.h
index 3ce09c16..e59919be 100644
--- a/shared-core/r300_reg.h
+++ b/shared-core/r300_reg.h
@@ -336,13 +336,15 @@ USE OR OTHER DEALINGS IN THE SOFTWARE.
* The meaning of the two UNKNOWN fields is obviously not known. However,
* experiments so far have shown that both *must* point to an instruction
* inside the vertex program, otherwise the GPU locks up.
+ *
* fglrx usually sets CNTL_3_UNKNOWN to the end of the program and
- * CNTL_1_UNKNOWN points to instruction where last write to position takes
- * place.
+ * R300_PVS_CNTL_1_POS_END_SHIFT points to instruction where last write to
+ * position takes place.
+ *
* Most likely this is used to ignore rest of the program in cases
* where group of verts arent visible. For some reason this "section"
* is sometimes accepted other instruction that have no relationship with
- *position calculations.
+ * position calculations.
*/
#define R300_VAP_PVS_CNTL_1 0x22D0
# define R300_PVS_CNTL_1_PROGRAM_START_SHIFT 0
diff --git a/shared-core/radeon_irq.c b/shared-core/radeon_irq.c
index 5151b4d6..a4be86e3 100644
--- a/shared-core/radeon_irq.c
+++ b/shared-core/radeon_irq.c
@@ -72,10 +72,14 @@ irqreturn_t radeon_driver_irq_handler(DRM_IRQ_ARGS)
/* Only consider the bits we're interested in - others could be used
* outside the DRM
*/
- stat = radeon_acknowledge_irqs(dev_priv, dev_priv->irq_enable_reg);
+ stat = radeon_acknowledge_irqs(dev_priv, (RADEON_SW_INT_TEST_ACK |
+ RADEON_CRTC_VBLANK_STAT |
+ RADEON_CRTC2_VBLANK_STAT));
if (!stat)
return IRQ_NONE;
+ stat &= dev_priv->irq_enable_reg;
+
/* SW interrupt */
if (stat & RADEON_SW_INT_TEST) {
DRM_WAKEUP(&dev_priv->swi_queue);
@@ -265,7 +269,8 @@ void radeon_driver_irq_preinstall(drm_device_t * dev)
/* Clear bits if they're already high */
radeon_acknowledge_irqs(dev_priv, (RADEON_SW_INT_TEST_ACK |
- RADEON_CRTC_VBLANK_STAT));
+ RADEON_CRTC_VBLANK_STAT |
+ RADEON_CRTC2_VBLANK_STAT));
}
void radeon_driver_irq_postinstall(drm_device_t * dev)
diff --git a/shared-core/sis_drv.h b/shared-core/sis_drv.h
index 006d148c..ec572ad4 100644
--- a/shared-core/sis_drv.h
+++ b/shared-core/sis_drv.h
@@ -33,11 +33,11 @@
#define DRIVER_AUTHOR "SIS, Tungsten Graphics"
#define DRIVER_NAME "sis"
-#define DRIVER_DESC "SIS 300/630/540"
-#define DRIVER_DATE "20060619"
+#define DRIVER_DESC "SIS 300/630/540 and XGI V3XE/V5/V8"
+#define DRIVER_DATE "20070626"
#define DRIVER_MAJOR 1
-#define DRIVER_MINOR 2
-#define DRIVER_PATCHLEVEL 1
+#define DRIVER_MINOR 3
+#define DRIVER_PATCHLEVEL 0
enum sis_family {
SIS_OTHER = 0,