diff options
Diffstat (limited to 'shared-core')
29 files changed, 1495 insertions, 966 deletions
diff --git a/shared-core/drm_pciids.txt b/shared-core/drm_pciids.txt index 126974d0..4bd690b2 100644 --- a/shared-core/drm_pciids.txt +++ b/shared-core/drm_pciids.txt @@ -510,8 +510,9 @@ 0x10de 0x0091 NV_40 "GeForce 7800 GTX" 0x10de 0x0092 NV_40 "GeForce 7800 GT" 0x10de 0x0093 NV_40 "GeForce 7800 GS" +0x10de 0x0095 NV_40 "GeForce 7800 SLI" 0x10de 0x0098 NV_40 "GeForce Go 7800" -0x10de 0x0099 NV_40 "GE Force Go 7800 GTX" +0x10de 0x0099 NV_40 "GeForce Go 7800 GTX" 0x10de 0x009d NV_40 "Quadro FX4500" 0x10de 0x00a0 NV_04 "Aladdin TNT2" 0x10de 0x00c0 NV_40 "GeForce 6800 GS" @@ -547,13 +548,16 @@ 0x10de 0x0113 NV_11 "Quadro2 MXR/EX/Go" 0x10de 0x0140 NV_40 "GeForce 6600 GT" 0x10de 0x0141 NV_40 "GeForce 6600" -0x10de 0x0142 NV_40 "GeForce 6600 PCIe" +0x10de 0x0142 NV_40 "GeForce 6600 LE" +0x10de 0x0143 NV_40 "GeForce 6600 VE" 0x10de 0x0144 NV_40 "GeForce Go 6600" 0x10de 0x0145 NV_40 "GeForce 6610 XL" 0x10de 0x0146 NV_40 "Geforce Go 6600TE/6200TE" +0x10de 0x0147 NV_40 "GeForce 6700 XL" 0x10de 0x0148 NV_40 "GeForce Go 6600" 0x10de 0x0149 NV_40 "GeForce Go 6600 GT" 0x10de 0x014a NV_40 "Quadro NVS 440" +0x10de 0x014c NV_40 "Quadro FX 550" 0x10de 0x014d NV_17 "Quadro FX 550" 0x10de 0x014e NV_40 "Quadro FX 540" 0x10de 0x014f NV_40 "GeForce 6200" @@ -561,6 +565,7 @@ 0x10de 0x0151 NV_15 "GeForce2 Ti" 0x10de 0x0152 NV_15 "GeForce2 Ultra, Bladerunner" 0x10de 0x0153 NV_15 "Quadro2 Pro" +0x10de 0x0160 NV_44 "GeForce 6500" 0x10de 0x0161 NV_44 "GeForce 6200 TurboCache(TM)" 0x10de 0x0162 NV_44 "GeForce 6200 SE TurboCache (TM)" 0x10de 0x0163 NV_44 "GeForce 6200 LE" @@ -569,6 +574,7 @@ 0x10de 0x0166 NV_44 "GeForce Go 6400" 0x10de 0x0167 NV_44 "GeForce Go 6200 TurboCache" 0x10de 0x0168 NV_44 "GeForce Go 6200 TurboCache" +0x10de 0x0169 NV_44 "GeForce 6250" 0x10de 0x0170 NV_17 "GeForce4 MX 460" 0x10de 0x0171 NV_17 "GeForce4 MX 440" 0x10de 0x0172 NV_17 "GeForce4 MX 420" @@ -601,11 +607,16 @@ 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 0x01d3 NV_44 "Geforce 7300 SE" 0x10de 0x01d6 NV_44 "GeForce Go 7200" 0x10de 0x01d7 NV_44 "Quadro NVS 110M / GeForce Go 7300" 0x10de 0x01d8 NV_44 "GeForce Go 7400" +0x10de 0x01d9 NV_44 "GeForce Go 7400 GS" 0x10de 0x01da NV_44 "Quadro NVS 110M" +0x10de 0x01db NV_44 "Quadro NVS 120M" 0x10de 0x01dc NV_44 "Quadro FX 350M" +0x10de 0x01dd NV_44 "GeForce 7500 LE" +0x10de 0x01de NV_44 "Quadro FX 350" 0x10de 0x01df NV_44 "GeForce 7300 GS" 0x10de 0x01f0 NV_17|NV_NFORCE2 "GeForce4 MX - nForce GPU" 0x10de 0x0200 NV_20 "GeForce3" @@ -617,9 +628,12 @@ 0x10de 0x0215 NV_40 "GeForce 6800 GT" 0x10de 0x0218 NV_40 "GeForce 6800 XT" 0x10de 0x0221 NV_44 "GeForce 6200" +0x10de 0x0222 NV_44 "GeForce 6200 A-LE" 0x10de 0x0240 NV_44 "GeForce 6150" +0x10de 0x0241 NV_44 "GeForce 6150 LE" 0x10de 0x0242 NV_44 "GeForce 6100" -0x10de 0x0244 NV_44 "GeForce 6150 Go" +0x10de 0x0244 NV_44 "GeForce Go 6150" +0x10de 0x0247 NV_44 "GeForce Go 6100" 0x10de 0x0250 NV_25 "GeForce4 Ti 4600" 0x10de 0x0251 NV_25 "GeForce4 Ti 4400" 0x10de 0x0252 NV_25 "GeForce4 Ti" @@ -700,7 +714,15 @@ 0x10de 0x0391 NV_40 "GeForce 7600 GT" 0x10de 0x0392 NV_40 "GeForce 7600 GS" 0x10de 0x0393 NV_40 "GeForce 7300 GT" +0x10de 0x0394 NV_40 "GeForce 7600 LE" +0x10de 0x0395 NV_40 "GeForce 7300 GT" +0x10de 0x0397 NV_40 "GeForce Go 7700" 0x10de 0x0398 NV_40 "GeForce Go 7600" +0x10de 0x0399 NV_40 "GeForce Go 7600 GT" +0x10de 0x039a NV_40 "Quadro NVS 300M" +0x10de 0x039b NV_40 "GeForce Go 7900 SE" +0x10de 0x039c NV_40 "Quadro FX 550M" +0x10de 0x039e NV_40 "Quadro FX 560" 0x10de 0x03d0 NV_44 "GeForce 6100 nForce 430" 0x10de 0x03d1 NV_44 "GeForce 6100 nForce 405" 0x10de 0x03d2 NV_44 "GeForce 6100 nForce 400" diff --git a/shared-core/i915_dma.c b/shared-core/i915_dma.c index 5d227d8b..9f18feee 100644 --- a/shared-core/i915_dma.c +++ b/shared-core/i915_dma.c @@ -546,9 +546,15 @@ static int i915_dispatch_batchbuffer(struct drm_device * dev, if (dev_priv->use_mi_batchbuffer_start) { BEGIN_LP_RING(2); - OUT_RING(MI_BATCH_BUFFER_START | (2 << 6)); - OUT_RING(batch->start | MI_BATCH_NON_SECURE); + if (IS_I965G(dev)) { + OUT_RING(MI_BATCH_BUFFER_START | (2 << 6) | MI_BATCH_NON_SECURE_I965); + OUT_RING(batch->start); + } else { + OUT_RING(MI_BATCH_BUFFER_START | (2 << 6)); + OUT_RING(batch->start | MI_BATCH_NON_SECURE); + } ADVANCE_LP_RING(); + } else { BEGIN_LP_RING(4); OUT_RING(MI_BATCH_BUFFER); diff --git a/shared-core/i915_drv.h b/shared-core/i915_drv.h index e641fdc6..528f7b3a 100644 --- a/shared-core/i915_drv.h +++ b/shared-core/i915_drv.h @@ -364,6 +364,8 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller); #define MI_BATCH_BUFFER_END (0xA<<23) #define MI_BATCH_NON_SECURE (1) +#define MI_BATCH_NON_SECURE_I965 (1<<8) + #define MI_WAIT_FOR_EVENT ((0x3<<23)) #define MI_WAIT_FOR_PLANE_B_FLIP (1<<6) #define MI_WAIT_FOR_PLANE_A_FLIP (1<<2) diff --git a/shared-core/nouveau_dma.c b/shared-core/nouveau_dma.c new file mode 100644 index 00000000..ab502e6a --- /dev/null +++ b/shared-core/nouveau_dma.c @@ -0,0 +1,177 @@ +/* + * 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_dma.h" + +#define SKIPS 8 + +int +nouveau_dma_channel_init(struct drm_device *dev) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_drm_channel *dchan = &dev_priv->channel; + struct nouveau_gpuobj *gpuobj = NULL; + struct mem_block *pushbuf; + int grclass, ret, i; + + DRM_DEBUG("\n"); + + pushbuf = nouveau_mem_alloc(dev, 0, 0x8000, + NOUVEAU_MEM_FB | NOUVEAU_MEM_MAPPED, + (struct drm_file *)-2); + if (!pushbuf) { + DRM_ERROR("Failed to allocate DMA push buffer\n"); + return -ENOMEM; + } + + /* Allocate channel */ + ret = nouveau_fifo_alloc(dev, &dchan->chan, (struct drm_file *)-2, + pushbuf, NvDmaFB, NvDmaTT); + if (ret) { + DRM_ERROR("Error allocating GPU channel: %d\n", ret); + return ret; + } + DRM_DEBUG("Using FIFO channel %d\n", dchan->chan->id); + + /* Map push buffer */ + drm_core_ioremap(dchan->chan->pushbuf_mem->map, dev); + if (!dchan->chan->pushbuf_mem->map->handle) { + DRM_ERROR("Failed to ioremap push buffer\n"); + return -EINVAL; + } + dchan->pushbuf = (void*)dchan->chan->pushbuf_mem->map->handle; + + /* Initialise DMA vars */ + dchan->max = (dchan->chan->pushbuf_mem->size >> 2) - 2; + dchan->put = dchan->chan->pushbuf_base >> 2; + dchan->cur = dchan->put; + dchan->free = dchan->max - dchan->cur; + + /* Insert NOPS for SKIPS */ + dchan->free -= SKIPS; + dchan->push_free = SKIPS; + for (i=0; i<SKIPS; i++) + OUT_RING(0); + + /* NV_MEMORY_TO_MEMORY_FORMAT requires a notifier */ + if ((ret = nouveau_notifier_alloc(dchan->chan, NvNotify0, 1, + &dchan->notify0_offset))) { + DRM_ERROR("Error allocating NvNotify0: %d\n", ret); + return ret; + } + + /* We use NV_MEMORY_TO_MEMORY_FORMAT for buffer moves */ + if (dev_priv->card_type < NV_50) grclass = NV_MEMORY_TO_MEMORY_FORMAT; + else grclass = NV50_MEMORY_TO_MEMORY_FORMAT; + if ((ret = nouveau_gpuobj_gr_new(dchan->chan, grclass, &gpuobj))) { + DRM_ERROR("Error creating NvM2MF: %d\n", ret); + return ret; + } + + if ((ret = nouveau_gpuobj_ref_add(dev, dchan->chan, NvM2MF, + gpuobj, NULL))) { + DRM_ERROR("Error referencing NvM2MF: %d\n", ret); + return ret; + } + dchan->m2mf_dma_source = NvDmaFB; + dchan->m2mf_dma_destin = NvDmaFB; + + BEGIN_RING(NvSubM2MF, NV_MEMORY_TO_MEMORY_FORMAT_NAME, 1); + OUT_RING (NvM2MF); + BEGIN_RING(NvSubM2MF, NV_MEMORY_TO_MEMORY_FORMAT_SET_DMA_NOTIFY, 1); + OUT_RING (NvNotify0); + BEGIN_RING(NvSubM2MF, NV_MEMORY_TO_MEMORY_FORMAT_SET_DMA_SOURCE, 2); + OUT_RING (dchan->m2mf_dma_source); + OUT_RING (dchan->m2mf_dma_destin); + FIRE_RING(); + + return 0; +} + +void +nouveau_dma_channel_takedown(struct drm_device *dev) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_drm_channel *dchan = &dev_priv->channel; + + DRM_DEBUG("\n"); + + if (dchan->chan) { + nouveau_fifo_free(dchan->chan); + dchan->chan = NULL; + } +} + +#define RING_SKIPS 8 + +#define READ_GET() ((NV_READ(NV03_FIFO_REGS_DMAGET(dchan->chan->id)) - \ + dchan->chan->pushbuf_base) >> 2) +#define WRITE_PUT(val) do { \ + NV_WRITE(NV03_FIFO_REGS_DMAPUT(dchan->chan->id), \ + ((val) << 2) + dchan->chan->pushbuf_base); \ +} while(0) + +int +nouveau_dma_wait(struct drm_device *dev, int size) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_drm_channel *dchan = &dev_priv->channel; + uint32_t get; + + while (dchan->free < size) { + get = READ_GET(); + + if (dchan->put >= get) { + dchan->free = dchan->max - dchan->cur; + + if (dchan->free < size) { + dchan->push_free = 1; + OUT_RING(0x20000000|dchan->chan->pushbuf_base); + if (get <= RING_SKIPS) { + /*corner case - will be idle*/ + if (dchan->put <= RING_SKIPS) + WRITE_PUT(RING_SKIPS + 1); + + do { + get = READ_GET(); + } while (get <= RING_SKIPS); + } + + WRITE_PUT(RING_SKIPS); + dchan->cur = dchan->put = RING_SKIPS; + dchan->free = get - (RING_SKIPS + 1); + } + } else { + dchan->free = get - dchan->cur - 1; + } + } + + return 0; +} + diff --git a/shared-core/nouveau_dma.h b/shared-core/nouveau_dma.h new file mode 100644 index 00000000..5e51c1c4 --- /dev/null +++ b/shared-core/nouveau_dma.h @@ -0,0 +1,98 @@ +/* + * 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. + * + */ + +#ifndef __NOUVEAU_DMA_H__ +#define __NOUVEAU_DMA_H__ + +typedef enum { + NvSubM2MF = 0, +} nouveau_subchannel_id_t; + +typedef enum { + NvM2MF = 0x80039001, + NvDmaFB = 0x8003d001, + NvDmaTT = 0x8003d002, + NvNotify0 = 0x8003d003 +} nouveau_object_handle_t; + +#define NV_MEMORY_TO_MEMORY_FORMAT 0x00000039 +#define NV_MEMORY_TO_MEMORY_FORMAT_NAME 0x00000000 +#define NV_MEMORY_TO_MEMORY_FORMAT_SET_REF 0x00000050 +#define NV_MEMORY_TO_MEMORY_FORMAT_NOP 0x00000100 +#define NV_MEMORY_TO_MEMORY_FORMAT_NOTIFY 0x00000104 +#define NV_MEMORY_TO_MEMORY_FORMAT_NOTIFY_STYLE_WRITE 0x00000000 +#define NV_MEMORY_TO_MEMORY_FORMAT_NOTIFY_STYLE_WRITE_LE_AWAKEN 0x00000001 +#define NV_MEMORY_TO_MEMORY_FORMAT_SET_DMA_NOTIFY 0x00000180 +#define NV_MEMORY_TO_MEMORY_FORMAT_SET_DMA_SOURCE 0x00000184 +#define NV_MEMORY_TO_MEMORY_FORMAT_OFFSET_IN 0x0000030c + +#define NV50_MEMORY_TO_MEMORY_FORMAT 0x00005039 +#define NV50_MEMORY_TO_MEMORY_FORMAT_UNK200 0x00000200 +#define NV50_MEMORY_TO_MEMORY_FORMAT_UNK21C 0x0000021c +#define NV50_MEMORY_TO_MEMORY_FORMAT_OFFSET_IN_HIGH 0x00000238 +#define NV50_MEMORY_TO_MEMORY_FORMAT_OFFSET_OUT_HIGH 0x0000023c + +#define BEGIN_RING(subc, mthd, cnt) do { \ + int push_size = (cnt) + 1; \ + if (dchan->push_free) { \ + DRM_ERROR("prior packet incomplete: %d\n", dchan->push_free); \ + break; \ + } \ + if (dchan->free < push_size) { \ + if (nouveau_dma_wait(dev, push_size)) { \ + DRM_ERROR("FIFO timeout\n"); \ + break; \ + } \ + } \ + dchan->free -= push_size; \ + dchan->push_free = push_size; \ + OUT_RING(((cnt)<<18) | ((subc)<<15) | mthd); \ +} while(0) + +#define OUT_RING(data) do { \ + if (dchan->push_free == 0) { \ + DRM_ERROR("no space left in packet\n"); \ + break; \ + } \ + dchan->pushbuf[dchan->cur++] = (data); \ + dchan->push_free--; \ +} while(0) + +#define FIRE_RING() do { \ + if (dchan->push_free) { \ + DRM_ERROR("packet incomplete: %d\n", dchan->push_free); \ + break; \ + } \ + if (dchan->cur != dchan->put) { \ + DRM_MEMORYBARRIER(); \ + dchan->put = dchan->cur; \ + NV_WRITE(NV03_FIFO_REGS_DMAPUT(dchan->chan->id), \ + (dchan->put<<2)); \ + } \ +} while(0) + +#endif + diff --git a/shared-core/nouveau_drm.h b/shared-core/nouveau_drm.h index 4016f004..bfc9bd4b 100644 --- a/shared-core/nouveau_drm.h +++ b/shared-core/nouveau_drm.h @@ -25,9 +25,9 @@ #ifndef __NOUVEAU_DRM_H__ #define __NOUVEAU_DRM_H__ -#define NOUVEAU_DRM_HEADER_PATCHLEVEL 9 +#define NOUVEAU_DRM_HEADER_PATCHLEVEL 10 -struct drm_nouveau_fifo_alloc { +struct drm_nouveau_channel_alloc { uint32_t fb_ctxdma_handle; uint32_t tt_ctxdma_handle; @@ -44,6 +44,10 @@ struct drm_nouveau_fifo_alloc { int notifier_size; }; +struct drm_nouveau_channel_free { + int channel; +}; + struct drm_nouveau_grobj_alloc { int channel; uint32_t handle; @@ -53,7 +57,7 @@ struct drm_nouveau_grobj_alloc { #define NOUVEAU_MEM_ACCESS_RO 1 #define NOUVEAU_MEM_ACCESS_WO 2 #define NOUVEAU_MEM_ACCESS_RW 3 -struct drm_nouveau_notifier_alloc { +struct drm_nouveau_notifierobj_alloc { int channel; uint32_t handle; int count; @@ -61,6 +65,11 @@ struct drm_nouveau_notifier_alloc { uint32_t offset; }; +struct drm_nouveau_gpuobj_free { + int channel; + uint32_t handle; +}; + #define NOUVEAU_MEM_FB 0x00000001 #define NOUVEAU_MEM_AGP 0x00000002 #define NOUVEAU_MEM_FB_ACCEPTABLE 0x00000004 @@ -95,6 +104,7 @@ struct drm_nouveau_mem_free { #define NOUVEAU_GETPARAM_FB_SIZE 8 #define NOUVEAU_GETPARAM_AGP_SIZE 9 #define NOUVEAU_GETPARAM_PCI_PHYSICAL 10 +#define NOUVEAU_GETPARAM_CHIPSET_ID 11 struct drm_nouveau_getparam { uint64_t param; uint64_t value; @@ -141,13 +151,16 @@ struct drm_nouveau_sarea { unsigned int nbox; }; -#define DRM_NOUVEAU_FIFO_ALLOC 0x00 -#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 -#define DRM_NOUVEAU_SETPARAM 0x06 +#define DRM_NOUVEAU_CARD_INIT 0x00 +#define DRM_NOUVEAU_GETPARAM 0x01 +#define DRM_NOUVEAU_SETPARAM 0x02 +#define DRM_NOUVEAU_CHANNEL_ALLOC 0x03 +#define DRM_NOUVEAU_CHANNEL_FREE 0x04 +#define DRM_NOUVEAU_GROBJ_ALLOC 0x05 +#define DRM_NOUVEAU_NOTIFIEROBJ_ALLOC 0x06 +#define DRM_NOUVEAU_GPUOBJ_FREE 0x07 +#define DRM_NOUVEAU_MEM_ALLOC 0x08 +#define DRM_NOUVEAU_MEM_FREE 0x09 #endif /* __NOUVEAU_DRM_H__ */ diff --git a/shared-core/nouveau_drv.h b/shared-core/nouveau_drv.h index dd323a0b..b7459b1b 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 9 +#define DRIVER_PATCHLEVEL 10 #define NOUVEAU_FAMILY 0x0000FFFF #define NOUVEAU_FLAGS 0xFFFF0000 @@ -67,8 +67,7 @@ enum nouveau_flags { #define NVOBJ_FLAG_ZERO_FREE (1 << 2) #define NVOBJ_FLAG_FAKE (1 << 3) struct nouveau_gpuobj { - struct nouveau_gpuobj *next; - struct nouveau_gpuobj *prev; + struct list_head list; int im_channel; struct mem_block *im_pramin; @@ -80,10 +79,13 @@ struct nouveau_gpuobj { uint32_t engine; uint32_t class; + + void (*dtor)(struct drm_device *, struct nouveau_gpuobj *); + void *priv; }; struct nouveau_gpuobj_ref { - struct nouveau_gpuobj_ref *next; + struct list_head list; struct nouveau_gpuobj *gpuobj; uint32_t instance; @@ -92,8 +94,11 @@ struct nouveau_gpuobj_ref { int handle; }; -struct nouveau_fifo +struct nouveau_channel { + struct drm_device *dev; + int id; + /* owner of this fifo */ struct drm_file *file_priv; /* mapping of the fifo itself */ @@ -126,7 +131,23 @@ struct nouveau_fifo struct nouveau_gpuobj_ref *ramin; /* Private instmem */ struct mem_block *ramin_heap; /* Private PRAMIN heap */ struct nouveau_gpuobj_ref *ramht; /* Hash table */ - struct nouveau_gpuobj_ref *ramht_refs; /* Objects referenced by RAMHT */ + struct list_head ramht_refs; /* Objects referenced by RAMHT */ +}; + +struct nouveau_drm_channel { + struct nouveau_channel *chan; + + /* DMA state */ + int max, put, cur, free; + int push_free; + volatile uint32_t *pushbuf; + + /* Notifiers */ + uint32_t notify0_offset; + + /* Buffer moves */ + uint32_t m2mf_dma_source; + uint32_t m2mf_dma_destin; }; struct nouveau_config { @@ -136,57 +157,64 @@ struct nouveau_config { } cmdbuf; }; -struct nouveau_engine_func { - struct { - void *priv; +struct nouveau_instmem_engine { + void *priv; - int (*init)(struct drm_device *dev); - void (*takedown)(struct drm_device *dev); + int (*init)(struct drm_device *dev); + void (*takedown)(struct drm_device *dev); - int (*populate)(struct drm_device *, struct nouveau_gpuobj *, - uint32_t *size); - void (*clear)(struct drm_device *, struct nouveau_gpuobj *); - int (*bind)(struct drm_device *, struct nouveau_gpuobj *); - int (*unbind)(struct drm_device *, struct nouveau_gpuobj *); - } instmem; + int (*populate)(struct drm_device *, struct nouveau_gpuobj *, + uint32_t *size); + void (*clear)(struct drm_device *, struct nouveau_gpuobj *); + int (*bind)(struct drm_device *, struct nouveau_gpuobj *); + int (*unbind)(struct drm_device *, struct nouveau_gpuobj *); +}; - struct { - int (*init)(struct drm_device *dev); - void (*takedown)(struct drm_device *dev); - } mc; +struct nouveau_mc_engine { + int (*init)(struct drm_device *dev); + void (*takedown)(struct drm_device *dev); +}; - struct { - int (*init)(struct drm_device *dev); - uint64_t (*read)(struct drm_device *dev); - void (*takedown)(struct drm_device *dev); - } timer; +struct nouveau_timer_engine { + int (*init)(struct drm_device *dev); + void (*takedown)(struct drm_device *dev); + uint64_t (*read)(struct drm_device *dev); +}; - struct { - int (*init)(struct drm_device *dev); - void (*takedown)(struct drm_device *dev); - } fb; +struct nouveau_fb_engine { + int (*init)(struct drm_device *dev); + void (*takedown)(struct drm_device *dev); +}; - struct { - int (*init)(struct drm_device *); - void (*takedown)(struct drm_device *); +struct nouveau_fifo_engine { + void *priv; - int (*create_context)(struct drm_device *, int channel); - void (*destroy_context)(struct drm_device *, int channel); - int (*load_context)(struct drm_device *, int channel); - int (*save_context)(struct drm_device *, int channel); - } graph; + int (*init)(struct drm_device *); + void (*takedown)(struct drm_device *); - struct { - void *priv; + int (*create_context)(struct nouveau_channel *); + void (*destroy_context)(struct nouveau_channel *); + int (*load_context)(struct nouveau_channel *); + int (*save_context)(struct nouveau_channel *); +}; - int (*init)(struct drm_device *); - void (*takedown)(struct drm_device *); +struct nouveau_pgraph_engine { + int (*init)(struct drm_device *); + void (*takedown)(struct drm_device *); - int (*create_context)(struct drm_device *, int channel); - void (*destroy_context)(struct drm_device *, int channel); - int (*load_context)(struct drm_device *, int channel); - int (*save_context)(struct drm_device *, int channel); - } fifo; + int (*create_context)(struct nouveau_channel *); + void (*destroy_context)(struct nouveau_channel *); + int (*load_context)(struct nouveau_channel *); + int (*save_context)(struct nouveau_channel *); +}; + +struct nouveau_engine { + struct nouveau_instmem_engine instmem; + struct nouveau_mc_engine mc; + struct nouveau_timer_engine timer; + struct nouveau_fb_engine fb; + struct nouveau_pgraph_engine graph; + struct nouveau_fifo_engine fifo; }; struct drm_nouveau_private { @@ -207,9 +235,10 @@ 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_channel *fifos[NV_MAX_FIFO_NUMBER]; - struct nouveau_engine_func Engine; + struct nouveau_engine Engine; + struct nouveau_drm_channel channel; /* RAMIN configuration, RAMFC, RAMHT and RAMRO offsets */ struct nouveau_gpuobj *ramht; @@ -259,96 +288,135 @@ struct drm_nouveau_private { struct nouveau_config config; - struct nouveau_gpuobj *gpuobj_all; + struct list_head gpuobj_list; }; +#define NOUVEAU_CHECK_INITIALISED_WITH_RETURN do { \ + struct drm_nouveau_private *nv = dev->dev_private; \ + if (nv->init_state != NOUVEAU_CARD_INIT_DONE) { \ + DRM_ERROR("called without init\n"); \ + return -EINVAL; \ + } \ +} while(0) + +#define NOUVEAU_GET_USER_CHANNEL_WITH_RETURN(id,cl,ch) do { \ + struct drm_nouveau_private *nv = dev->dev_private; \ + if (!nouveau_fifo_owner(dev, (cl), (id))) { \ + DRM_ERROR("pid %d doesn't own channel %d\n", \ + DRM_CURRENTPID, (id)); \ + return -EPERM; \ + } \ + (ch) = nv->fifos[(id)]; \ +} while(0) + /* nouveau_state.c */ -extern void nouveau_preclose(struct drm_device * dev, - struct drm_file *file_priv); -extern int nouveau_load(struct drm_device *dev, unsigned long flags); -extern int nouveau_firstopen(struct drm_device *dev); -extern void nouveau_lastclose(struct drm_device *dev); -extern int nouveau_unload(struct drm_device *dev); -extern int nouveau_ioctl_getparam(struct drm_device *dev, void *data, struct drm_file *file_priv); -extern int nouveau_ioctl_setparam(struct drm_device *dev, void *data, struct drm_file *file_priv); -extern void nouveau_wait_for_idle(struct drm_device *dev); -extern int nouveau_ioctl_card_init(struct drm_device *dev, void *data, struct drm_file *file_priv); +extern void nouveau_preclose(struct drm_device *dev, struct drm_file *); +extern int nouveau_load(struct drm_device *, unsigned long flags); +extern int nouveau_firstopen(struct drm_device *); +extern void nouveau_lastclose(struct drm_device *); +extern int nouveau_unload(struct drm_device *); +extern int nouveau_ioctl_getparam(struct drm_device *, void *data, + struct drm_file *); +extern int nouveau_ioctl_setparam(struct drm_device *, void *data, + struct drm_file *); +extern void nouveau_wait_for_idle(struct drm_device *); +extern int nouveau_card_init(struct drm_device *); +extern int nouveau_ioctl_card_init(struct drm_device *, void *data, + struct drm_file *); /* nouveau_mem.c */ -extern int nouveau_mem_init_heap(struct mem_block **, - uint64_t start, uint64_t size); +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, - struct drm_file *file_priv); -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(struct drm_file *file_priv, - struct mem_block *heap); -extern int nouveau_ioctl_mem_alloc(struct drm_device *dev, void *data, struct drm_file *file_priv); -extern int nouveau_ioctl_mem_free(struct drm_device *dev, void *data, struct drm_file *file_priv); -extern struct mem_block* nouveau_mem_alloc(struct drm_device *dev, + struct drm_file *); +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 *); +extern void nouveau_mem_release(struct drm_file *, struct mem_block *heap); +extern int nouveau_ioctl_mem_alloc(struct drm_device *, void *data, + struct drm_file *); +extern int nouveau_ioctl_mem_free(struct drm_device *, void *data, + struct drm_file *); +extern struct mem_block* nouveau_mem_alloc(struct drm_device *, int alignment, uint64_t size, - int flags, - struct drm_file *file_priv); -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); + int flags, struct drm_file *); +extern void nouveau_mem_free(struct drm_device *dev, struct mem_block*); +extern int nouveau_mem_init(struct drm_device *); +extern void nouveau_mem_close(struct drm_device *); /* nouveau_notifier.c */ -extern int nouveau_notifier_init_channel(struct drm_device *, int channel, - struct drm_file *file_priv); -extern void nouveau_notifier_takedown_channel(struct drm_device *, int channel); -extern int nouveau_notifier_alloc(struct drm_device *, int channel, - uint32_t handle, int cout, uint32_t *offset); -extern int nouveau_ioctl_notifier_alloc(struct drm_device *dev, void *data, struct drm_file *file_priv); +extern int nouveau_notifier_init_channel(struct nouveau_channel *); +extern void nouveau_notifier_takedown_channel(struct nouveau_channel *); +extern int nouveau_notifier_alloc(struct nouveau_channel *, uint32_t handle, + int cout, uint32_t *offset); +extern int nouveau_ioctl_notifier_alloc(struct drm_device *, void *data, + struct drm_file *); +extern int nouveau_ioctl_notifier_free(struct drm_device *, void *data, + struct drm_file *); /* nouveau_fifo.c */ -extern int nouveau_fifo_init(struct drm_device *dev); -extern int nouveau_fifo_number(struct drm_device *dev); -extern int nouveau_fifo_ctx_size(struct drm_device *dev); -extern void nouveau_fifo_cleanup(struct drm_device *dev, - struct drm_file *file_priv); -extern int nouveau_fifo_owner(struct drm_device *dev, - struct drm_file *file_priv, int channel); -extern void nouveau_fifo_free(struct drm_device *dev, int channel); +extern int nouveau_fifo_init(struct drm_device *); +extern int nouveau_fifo_number(struct drm_device *); +extern int nouveau_fifo_ctx_size(struct drm_device *); +extern void nouveau_fifo_cleanup(struct drm_device *, struct drm_file *); +extern int nouveau_fifo_owner(struct drm_device *, struct drm_file *, + int channel); +extern int nouveau_fifo_alloc(struct drm_device *dev, + struct nouveau_channel **chan, + struct drm_file *file_priv, + struct mem_block *pushbuf, + uint32_t fb_ctxdma, uint32_t tt_ctxdma); +extern void nouveau_fifo_free(struct nouveau_channel *); /* nouveau_object.c */ -extern void nouveau_gpuobj_takedown(struct drm_device *dev); -extern int nouveau_gpuobj_channel_init(struct drm_device *, int channel, +extern int nouveau_gpuobj_early_init(struct drm_device *); +extern int nouveau_gpuobj_init(struct drm_device *); +extern void nouveau_gpuobj_takedown(struct drm_device *); +extern void nouveau_gpuobj_late_takedown(struct drm_device *); +extern int nouveau_gpuobj_channel_init(struct nouveau_channel *, uint32_t vram_h, uint32_t tt_h); -extern void nouveau_gpuobj_channel_takedown(struct drm_device *, int channel); -extern int nouveau_gpuobj_new(struct drm_device *, int channel, int size, int align, - uint32_t flags, struct nouveau_gpuobj **); +extern void nouveau_gpuobj_channel_takedown(struct nouveau_channel *); +extern int nouveau_gpuobj_new(struct drm_device *, struct nouveau_channel *, + int size, int align, uint32_t flags, + struct nouveau_gpuobj **); extern int nouveau_gpuobj_del(struct drm_device *, struct nouveau_gpuobj **); -extern int nouveau_gpuobj_ref_add(struct drm_device *, int channel, uint32_t handle, - struct nouveau_gpuobj *, +extern int nouveau_gpuobj_ref_add(struct drm_device *, struct nouveau_channel *, + uint32_t handle, struct nouveau_gpuobj *, struct nouveau_gpuobj_ref **); -extern int nouveau_gpuobj_ref_del(struct drm_device *, struct nouveau_gpuobj_ref **); -extern int nouveau_gpuobj_new_ref(struct drm_device *, int chan_obj, int chan_ref, +extern int nouveau_gpuobj_ref_del(struct drm_device *, + struct nouveau_gpuobj_ref **); +extern int nouveau_gpuobj_ref_find(struct nouveau_channel *, uint32_t handle, + struct nouveau_gpuobj_ref **ref_ret); +extern int nouveau_gpuobj_new_ref(struct drm_device *, + struct nouveau_channel *alloc_chan, + struct nouveau_channel *ref_chan, uint32_t handle, int size, int align, uint32_t flags, struct nouveau_gpuobj_ref **); -extern int nouveau_gpuobj_new_fake(struct drm_device *, uint32_t offset, +extern int nouveau_gpuobj_new_fake(struct drm_device *, + uint32_t p_offset, uint32_t b_offset, uint32_t size, uint32_t flags, - struct nouveau_gpuobj**, + struct nouveau_gpuobj **, struct nouveau_gpuobj_ref**); -extern int nouveau_gpuobj_dma_new(struct drm_device *, int channel, int class, - uint64_t offset, uint64_t size, - int access, int target, - struct nouveau_gpuobj **); -extern int nouveau_gpuobj_gart_dma_new(struct drm_device *, int channel, +extern int nouveau_gpuobj_dma_new(struct nouveau_channel *, int class, + uint64_t offset, uint64_t size, int access, + int target, struct nouveau_gpuobj **); +extern int nouveau_gpuobj_gart_dma_new(struct nouveau_channel *, uint64_t offset, uint64_t size, int access, struct nouveau_gpuobj **, uint32_t *o_ret); -extern int nouveau_gpuobj_gr_new(struct drm_device *, int channel, int class, +extern int nouveau_gpuobj_gr_new(struct nouveau_channel *, int class, struct nouveau_gpuobj **); -extern int nouveau_ioctl_grobj_alloc(struct drm_device *dev, void *data, struct drm_file *file_priv); +extern int nouveau_ioctl_grobj_alloc(struct drm_device *, void *data, + struct drm_file *); +extern int nouveau_ioctl_gpuobj_free(struct drm_device *, void *data, + struct drm_file *); /* nouveau_irq.c */ extern irqreturn_t nouveau_irq_handler(DRM_IRQ_ARGS); -extern void nouveau_irq_preinstall(struct drm_device*); -extern void nouveau_irq_postinstall(struct drm_device*); -extern void nouveau_irq_uninstall(struct drm_device*); +extern void nouveau_irq_preinstall(struct drm_device *); +extern void nouveau_irq_postinstall(struct drm_device *); +extern void nouveau_irq_uninstall(struct drm_device *); /* nouveau_sgdma.c */ extern int nouveau_sgdma_init(struct drm_device *); @@ -357,132 +425,138 @@ extern struct drm_ttm_backend *nouveau_sgdma_init_ttm(struct drm_device *); extern int nouveau_sgdma_nottm_hack_init(struct drm_device *); extern void nouveau_sgdma_nottm_hack_takedown(struct drm_device *); +/* nouveau_dma.c */ +extern int nouveau_dma_channel_init(struct drm_device *); +extern void nouveau_dma_channel_takedown(struct drm_device *); +extern int nouveau_dma_wait(struct drm_device *, int size); + /* nv04_fb.c */ -extern int nv04_fb_init(struct drm_device *dev); -extern void nv04_fb_takedown(struct drm_device *dev); +extern int nv04_fb_init(struct drm_device *); +extern void nv04_fb_takedown(struct drm_device *); /* nv10_fb.c */ -extern int nv10_fb_init(struct drm_device *dev); -extern void nv10_fb_takedown(struct drm_device *dev); +extern int nv10_fb_init(struct drm_device *); +extern void nv10_fb_takedown(struct drm_device *); /* nv40_fb.c */ -extern int nv40_fb_init(struct drm_device *dev); -extern void nv40_fb_takedown(struct drm_device *dev); +extern int nv40_fb_init(struct drm_device *); +extern void nv40_fb_takedown(struct drm_device *); /* nv04_fifo.c */ -extern int nv04_fifo_create_context(struct drm_device *dev, int channel); -extern void nv04_fifo_destroy_context(struct drm_device *dev, int channel); -extern int nv04_fifo_load_context(struct drm_device *dev, int channel); -extern int nv04_fifo_save_context(struct drm_device *dev, int channel); +extern int nv04_fifo_create_context(struct nouveau_channel *); +extern void nv04_fifo_destroy_context(struct nouveau_channel *); +extern int nv04_fifo_load_context(struct nouveau_channel *); +extern int nv04_fifo_save_context(struct nouveau_channel *); /* nv10_fifo.c */ -extern int nv10_fifo_create_context(struct drm_device *dev, int channel); -extern void nv10_fifo_destroy_context(struct drm_device *dev, int channel); -extern int nv10_fifo_load_context(struct drm_device *dev, int channel); -extern int nv10_fifo_save_context(struct drm_device *dev, int channel); +extern int nv10_fifo_create_context(struct nouveau_channel *); +extern void nv10_fifo_destroy_context(struct nouveau_channel *); +extern int nv10_fifo_load_context(struct nouveau_channel *); +extern int nv10_fifo_save_context(struct nouveau_channel *); /* nv40_fifo.c */ -extern int nv40_fifo_create_context(struct drm_device *, int channel); -extern void nv40_fifo_destroy_context(struct drm_device *, int channel); -extern int nv40_fifo_load_context(struct drm_device *, int channel); -extern int nv40_fifo_save_context(struct drm_device *, int channel); +extern int nv40_fifo_init(struct drm_device *); +extern int nv40_fifo_create_context(struct nouveau_channel *); +extern void nv40_fifo_destroy_context(struct nouveau_channel *); +extern int nv40_fifo_load_context(struct nouveau_channel *); +extern int nv40_fifo_save_context(struct nouveau_channel *); /* nv50_fifo.c */ extern int nv50_fifo_init(struct drm_device *); extern void nv50_fifo_takedown(struct drm_device *); -extern int nv50_fifo_create_context(struct drm_device *, int channel); -extern void nv50_fifo_destroy_context(struct drm_device *, int channel); -extern int nv50_fifo_load_context(struct drm_device *, int channel); -extern int nv50_fifo_save_context(struct drm_device *, int channel); +extern int nv50_fifo_create_context(struct nouveau_channel *); +extern void nv50_fifo_destroy_context(struct nouveau_channel *); +extern int nv50_fifo_load_context(struct nouveau_channel *); +extern int nv50_fifo_save_context(struct nouveau_channel *); /* nv04_graph.c */ -extern void nouveau_nv04_context_switch(struct drm_device *dev); -extern int nv04_graph_init(struct drm_device *dev); -extern void nv04_graph_takedown(struct drm_device *dev); -extern int nv04_graph_create_context(struct drm_device *dev, int channel); -extern void nv04_graph_destroy_context(struct drm_device *dev, int channel); -extern int nv04_graph_load_context(struct drm_device *dev, int channel); -extern int nv04_graph_save_context(struct drm_device *dev, int channel); +extern void nouveau_nv04_context_switch(struct drm_device *); +extern int nv04_graph_init(struct drm_device *); +extern void nv04_graph_takedown(struct drm_device *); +extern int nv04_graph_create_context(struct nouveau_channel *); +extern void nv04_graph_destroy_context(struct nouveau_channel *); +extern int nv04_graph_load_context(struct nouveau_channel *); +extern int nv04_graph_save_context(struct nouveau_channel *); /* nv10_graph.c */ -extern void nouveau_nv10_context_switch(struct drm_device *dev); -extern int nv10_graph_init(struct drm_device *dev); -extern void nv10_graph_takedown(struct drm_device *dev); -extern int nv10_graph_create_context(struct drm_device *dev, int channel); -extern void nv10_graph_destroy_context(struct drm_device *dev, int channel); -extern int nv10_graph_load_context(struct drm_device *dev, int channel); -extern int nv10_graph_save_context(struct drm_device *dev, int channel); +extern void nouveau_nv10_context_switch(struct drm_device *); +extern int nv10_graph_init(struct drm_device *); +extern void nv10_graph_takedown(struct drm_device *); +extern int nv10_graph_create_context(struct nouveau_channel *); +extern void nv10_graph_destroy_context(struct nouveau_channel *); +extern int nv10_graph_load_context(struct nouveau_channel *); +extern int nv10_graph_save_context(struct nouveau_channel *); /* nv20_graph.c */ -extern void nouveau_nv20_context_switch(struct drm_device *dev); -extern int nv20_graph_init(struct drm_device *dev); -extern void nv20_graph_takedown(struct drm_device *dev); -extern int nv20_graph_create_context(struct drm_device *dev, int channel); -extern void nv20_graph_destroy_context(struct drm_device *dev, int channel); -extern int nv20_graph_load_context(struct drm_device *dev, int channel); -extern int nv20_graph_save_context(struct drm_device *dev, int channel); +extern void nouveau_nv20_context_switch(struct drm_device *); +extern int nv20_graph_init(struct drm_device *); +extern void nv20_graph_takedown(struct drm_device *); +extern int nv20_graph_create_context(struct nouveau_channel *); +extern void nv20_graph_destroy_context(struct nouveau_channel *); +extern int nv20_graph_load_context(struct nouveau_channel *); +extern int nv20_graph_save_context(struct nouveau_channel *); /* nv30_graph.c */ -extern int nv30_graph_init(struct drm_device *dev); -extern void nv30_graph_takedown(struct drm_device *dev); -extern int nv30_graph_create_context(struct drm_device *, int channel); -extern void nv30_graph_destroy_context(struct drm_device *, int channel); -extern int nv30_graph_load_context(struct drm_device *, int channel); -extern int nv30_graph_save_context(struct drm_device *, int channel); +extern int nv30_graph_init(struct drm_device *); +extern void nv30_graph_takedown(struct drm_device *); +extern int nv30_graph_create_context(struct nouveau_channel *); +extern void nv30_graph_destroy_context(struct nouveau_channel *); +extern int nv30_graph_load_context(struct nouveau_channel *); +extern int nv30_graph_save_context(struct nouveau_channel *); /* nv40_graph.c */ extern int nv40_graph_init(struct drm_device *); extern void nv40_graph_takedown(struct drm_device *); -extern int nv40_graph_create_context(struct drm_device *, int channel); -extern void nv40_graph_destroy_context(struct drm_device *, int channel); -extern int nv40_graph_load_context(struct drm_device *, int channel); -extern int nv40_graph_save_context(struct drm_device *, int channel); +extern int nv40_graph_create_context(struct nouveau_channel *); +extern void nv40_graph_destroy_context(struct nouveau_channel *); +extern int nv40_graph_load_context(struct nouveau_channel *); +extern int nv40_graph_save_context(struct nouveau_channel *); /* nv50_graph.c */ extern int nv50_graph_init(struct drm_device *); extern void nv50_graph_takedown(struct drm_device *); -extern int nv50_graph_create_context(struct drm_device *, int channel); -extern void nv50_graph_destroy_context(struct drm_device *, int channel); -extern int nv50_graph_load_context(struct drm_device *, int channel); -extern int nv50_graph_save_context(struct drm_device *, int channel); +extern int nv50_graph_create_context(struct nouveau_channel *); +extern void nv50_graph_destroy_context(struct nouveau_channel *); +extern int nv50_graph_load_context(struct nouveau_channel *); +extern int nv50_graph_save_context(struct nouveau_channel *); /* nv04_instmem.c */ -extern int nv04_instmem_init(struct drm_device *dev); -extern void nv04_instmem_takedown(struct drm_device *dev); -extern int nv04_instmem_populate(struct drm_device*, struct nouveau_gpuobj*, +extern int nv04_instmem_init(struct drm_device *); +extern void nv04_instmem_takedown(struct drm_device *); +extern int nv04_instmem_populate(struct drm_device *, struct nouveau_gpuobj *, uint32_t *size); -extern void nv04_instmem_clear(struct drm_device*, struct nouveau_gpuobj*); -extern int nv04_instmem_bind(struct drm_device*, struct nouveau_gpuobj*); -extern int nv04_instmem_unbind(struct drm_device*, struct nouveau_gpuobj*); +extern void nv04_instmem_clear(struct drm_device *, struct nouveau_gpuobj *); +extern int nv04_instmem_bind(struct drm_device *, struct nouveau_gpuobj *); +extern int nv04_instmem_unbind(struct drm_device *, struct nouveau_gpuobj *); /* nv50_instmem.c */ -extern int nv50_instmem_init(struct drm_device *dev); -extern void nv50_instmem_takedown(struct drm_device *dev); -extern int nv50_instmem_populate(struct drm_device*, struct nouveau_gpuobj*, +extern int nv50_instmem_init(struct drm_device *); +extern void nv50_instmem_takedown(struct drm_device *); +extern int nv50_instmem_populate(struct drm_device *, struct nouveau_gpuobj *, uint32_t *size); -extern void nv50_instmem_clear(struct drm_device*, struct nouveau_gpuobj*); -extern int nv50_instmem_bind(struct drm_device*, struct nouveau_gpuobj*); -extern int nv50_instmem_unbind(struct drm_device*, struct nouveau_gpuobj*); +extern void nv50_instmem_clear(struct drm_device *, struct nouveau_gpuobj *); +extern int nv50_instmem_bind(struct drm_device *, struct nouveau_gpuobj *); +extern int nv50_instmem_unbind(struct drm_device *, struct nouveau_gpuobj *); /* nv04_mc.c */ -extern int nv04_mc_init(struct drm_device *dev); -extern void nv04_mc_takedown(struct drm_device *dev); +extern int nv04_mc_init(struct drm_device *); +extern void nv04_mc_takedown(struct drm_device *); /* nv40_mc.c */ -extern int nv40_mc_init(struct drm_device *dev); -extern void nv40_mc_takedown(struct drm_device *dev); +extern int nv40_mc_init(struct drm_device *); +extern void nv40_mc_takedown(struct drm_device *); /* nv50_mc.c */ -extern int nv50_mc_init(struct drm_device *dev); -extern void nv50_mc_takedown(struct drm_device *dev); +extern int nv50_mc_init(struct drm_device *); +extern void nv50_mc_takedown(struct drm_device *); /* nv04_timer.c */ -extern int nv04_timer_init(struct drm_device *dev); -extern uint64_t nv04_timer_read(struct drm_device *dev); -extern void nv04_timer_takedown(struct drm_device *dev); +extern int nv04_timer_init(struct drm_device *); +extern uint64_t nv04_timer_read(struct drm_device *); +extern void nv04_timer_takedown(struct drm_device *); extern long nouveau_compat_ioctl(struct file *file, unsigned int cmd, - unsigned long arg); + unsigned long arg); #if defined(__powerpc__) #define NV_READ(reg) in_be32((void __iomem *)(dev_priv->mmio)->handle + (reg) ) diff --git a/shared-core/nouveau_fifo.c b/shared-core/nouveau_fifo.c index e5d3ab3c..f0c2a556 100644 --- a/shared-core/nouveau_fifo.c +++ b/shared-core/nouveau_fifo.c @@ -120,6 +120,10 @@ int nouveau_fifo_init(struct drm_device *dev) NV_WRITE(NV03_PMC_ENABLE, NV_READ(NV03_PMC_ENABLE) | NV_PMC_ENABLE_PFIFO); + /* Enable PFIFO error reporting */ + NV_WRITE(NV03_PFIFO_INTR_0, 0xFFFFFFFF); + NV_WRITE(NV03_PFIFO_INTR_EN_0, 0xFFFFFFFF); + NV_WRITE(NV03_PFIFO_CACHES, 0x00000000); ret = nouveau_fifo_instmem_configure(dev); @@ -186,72 +190,47 @@ int nouveau_fifo_init(struct drm_device *dev) } static int -nouveau_fifo_cmdbuf_alloc(struct drm_device *dev, int channel) +nouveau_fifo_pushbuf_ctxdma_init(struct nouveau_channel *chan) { + struct drm_device *dev = chan->dev; struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_fifo *chan = dev_priv->fifos[channel]; - struct nouveau_config *config = &dev_priv->config; - struct mem_block *cb; - int cb_min_size = max(NV03_FIFO_SIZE,PAGE_SIZE); + struct mem_block *pb = chan->pushbuf_mem; struct nouveau_gpuobj *pushbuf = NULL; int ret; - /* Defaults for unconfigured values */ - if (!config->cmdbuf.location) - config->cmdbuf.location = NOUVEAU_MEM_FB; - if (!config->cmdbuf.size || config->cmdbuf.size < cb_min_size) - config->cmdbuf.size = cb_min_size; - - cb = nouveau_mem_alloc(dev, 0, config->cmdbuf.size, - config->cmdbuf.location | NOUVEAU_MEM_MAPPED, - (struct drm_file *)-2); - if (!cb) { - DRM_ERROR("Couldn't allocate DMA command buffer.\n"); - return -ENOMEM; - } - - if (cb->flags & NOUVEAU_MEM_AGP) { - ret = nouveau_gpuobj_gart_dma_new(dev, channel, - cb->start, cb->size, + if (pb->flags & NOUVEAU_MEM_AGP) { + ret = nouveau_gpuobj_gart_dma_new(chan, pb->start, pb->size, NV_DMA_ACCESS_RO, &pushbuf, &chan->pushbuf_base); } else - if (cb->flags & NOUVEAU_MEM_PCI) { - ret = nouveau_gpuobj_dma_new(dev, channel, - NV_CLASS_DMA_IN_MEMORY, - cb->start, cb->size, + if (pb->flags & NOUVEAU_MEM_PCI) { + ret = nouveau_gpuobj_dma_new(chan, NV_CLASS_DMA_IN_MEMORY, + pb->start, pb->size, NV_DMA_ACCESS_RO, NV_DMA_TARGET_PCI_NONLINEAR, &pushbuf); chan->pushbuf_base = 0; } 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); + ret = nouveau_gpuobj_dma_new(chan, NV_CLASS_DMA_IN_MEMORY, + pb->start, pb->size, + NV_DMA_ACCESS_RO, + NV_DMA_TARGET_VIDMEM, &pushbuf); chan->pushbuf_base = 0; } else { /* NV04 cmdbuf hack, from original ddx.. not sure of it's * exact reason for existing :) PCI access to cmdbuf in * VRAM. */ - 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); + ret = nouveau_gpuobj_dma_new(chan, NV_CLASS_DMA_IN_MEMORY, + pb->start + + drm_get_resource_start(dev, 1), + pb->size, NV_DMA_ACCESS_RO, + NV_DMA_TARGET_PCI, &pushbuf); chan->pushbuf_base = 0; } - if (ret) { - nouveau_mem_free(dev, cb); - DRM_ERROR("Error creating push buffer ctxdma: %d\n", ret); - return ret; - } - - if ((ret = nouveau_gpuobj_ref_add(dev, channel, 0, pushbuf, + if ((ret = nouveau_gpuobj_ref_add(dev, chan, 0, pushbuf, &chan->pushbuf))) { DRM_ERROR("Error referencing push buffer ctxdma: %d\n", ret); if (pushbuf != dev_priv->gart_info.sg_ctxdma) @@ -259,19 +238,42 @@ nouveau_fifo_cmdbuf_alloc(struct drm_device *dev, int channel) return ret; } - chan->pushbuf_mem = cb; return 0; } +static struct mem_block * +nouveau_fifo_user_pushbuf_alloc(struct drm_device *dev) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_config *config = &dev_priv->config; + struct mem_block *pb; + int pb_min_size = max(NV03_FIFO_SIZE,PAGE_SIZE); + + /* Defaults for unconfigured values */ + if (!config->cmdbuf.location) + config->cmdbuf.location = NOUVEAU_MEM_FB; + if (!config->cmdbuf.size || config->cmdbuf.size < pb_min_size) + config->cmdbuf.size = pb_min_size; + + pb = nouveau_mem_alloc(dev, 0, config->cmdbuf.size, + config->cmdbuf.location | NOUVEAU_MEM_MAPPED, + (struct drm_file *)-2); + if (!pb) + DRM_ERROR("Couldn't allocate DMA push buffer.\n"); + + return pb; +} + /* allocates and initializes a fifo for user space consumption */ -int nouveau_fifo_alloc(struct drm_device *dev, int *chan_ret, - struct drm_file *file_priv, - uint32_t vram_handle, uint32_t tt_handle) +int +nouveau_fifo_alloc(struct drm_device *dev, struct nouveau_channel **chan_ret, + struct drm_file *file_priv, struct mem_block *pushbuf, + uint32_t vram_handle, uint32_t tt_handle) { int ret; struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_engine_func *engine = &dev_priv->Engine; - struct nouveau_fifo *chan; + struct nouveau_engine *engine = &dev_priv->Engine; + struct nouveau_channel *chan; int channel; /* @@ -283,44 +285,44 @@ int nouveau_fifo_alloc(struct drm_device *dev, int *chan_ret, * When there are no more contexts, you lost */ 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 -EINVAL; - (*chan_ret) = channel; - dev_priv->fifos[channel] = drm_calloc(1, sizeof(struct nouveau_fifo), + dev_priv->fifos[channel] = drm_calloc(1, sizeof(struct nouveau_channel), DRM_MEM_DRIVER); if (!dev_priv->fifos[channel]) return -ENOMEM; dev_priv->fifo_alloc_count++; chan = dev_priv->fifos[channel]; + chan->dev = dev; + chan->id = channel; chan->file_priv = file_priv; + chan->pushbuf_mem = pushbuf; DRM_INFO("Allocating FIFO number %d\n", channel); - /* Setup channel's default objects */ - ret = nouveau_gpuobj_channel_init(dev, channel, vram_handle, tt_handle); + /* Allocate space for per-channel fixed notifier memory */ + ret = nouveau_notifier_init_channel(chan); if (ret) { - nouveau_fifo_free(dev, channel); + nouveau_fifo_free(chan); return ret; } - /* allocate a command buffer, and create a dma object for the gpu */ - ret = nouveau_fifo_cmdbuf_alloc(dev, channel); + /* Setup channel's default objects */ + ret = nouveau_gpuobj_channel_init(chan, vram_handle, tt_handle); if (ret) { - nouveau_fifo_free(dev, channel); + nouveau_fifo_free(chan); return ret; } - /* Allocate space for per-channel fixed notifier memory */ - ret = nouveau_notifier_init_channel(dev, channel, file_priv); + /* Create a dma object for the push buffer */ + ret = nouveau_fifo_pushbuf_ctxdma_init(chan); if (ret) { - nouveau_fifo_free(dev, channel); + nouveau_fifo_free(chan); return ret; } @@ -333,16 +335,16 @@ int nouveau_fifo_alloc(struct drm_device *dev, int *chan_ret, NV_WRITE(NV04_PFIFO_CACHE1_PULL0, 0x00000000); /* Create a graphics context for new channel */ - ret = engine->graph.create_context(dev, channel); + ret = engine->graph.create_context(chan); if (ret) { - nouveau_fifo_free(dev, channel); + nouveau_fifo_free(chan); return ret; } /* Construct inital RAMFC for new channel */ - ret = engine->fifo.create_context(dev, channel); + ret = engine->fifo.create_context(chan); if (ret) { - nouveau_fifo_free(dev, channel); + nouveau_fifo_free(chan); return ret; } @@ -359,30 +361,17 @@ int nouveau_fifo_alloc(struct drm_device *dev, int *chan_ret, * other case, the GPU will handle this when it switches contexts. */ if (dev_priv->fifo_alloc_count == 1) { - ret = engine->fifo.load_context(dev, channel); + ret = engine->fifo.load_context(chan); if (ret) { - nouveau_fifo_free(dev, channel); + nouveau_fifo_free(chan); return ret; } - ret = engine->graph.load_context(dev, channel); + ret = engine->graph.load_context(chan); if (ret) { - nouveau_fifo_free(dev, channel); + nouveau_fifo_free(chan); 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, @@ -395,32 +384,28 @@ int nouveau_fifo_alloc(struct drm_device *dev, int *chan_ret, NV_WRITE(NV03_PFIFO_CACHES, 1); DRM_INFO("%s: initialised FIFO %d\n", __func__, channel); + *chan_ret = chan; return 0; } /* stops a fifo */ -void nouveau_fifo_free(struct drm_device *dev, int channel) +void nouveau_fifo_free(struct nouveau_channel *chan) { + struct drm_device *dev = chan->dev; struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_engine_func *engine = &dev_priv->Engine; - struct nouveau_fifo *chan = dev_priv->fifos[channel]; - - if (!chan) { - DRM_ERROR("Freeing non-existant channel %d\n", channel); - return; - } + struct nouveau_engine *engine = &dev_priv->Engine; - DRM_INFO("%s: freeing fifo %d\n", __func__, channel); + DRM_INFO("%s: freeing fifo %d\n", __func__, chan->id); /* disable the fifo caches */ NV_WRITE(NV03_PFIFO_CACHES, 0x00000000); // FIXME XXX needs more code - engine->fifo.destroy_context(dev, channel); + engine->fifo.destroy_context(chan); /* Cleanup PGRAPH state */ - engine->graph.destroy_context(dev, channel); + engine->graph.destroy_context(chan); /* reenable the fifo caches */ NV_WRITE(NV03_PFIFO_CACHES, 0x00000001); @@ -432,12 +417,12 @@ void nouveau_fifo_free(struct drm_device *dev, int channel) chan->pushbuf_mem = NULL; } - nouveau_notifier_takedown_channel(dev, channel); - /* Destroy objects belonging to the channel */ - nouveau_gpuobj_channel_takedown(dev, channel); + nouveau_gpuobj_channel_takedown(chan); + + nouveau_notifier_takedown_channel(chan); - dev_priv->fifos[channel] = NULL; + dev_priv->fifos[chan->id] = NULL; dev_priv->fifo_alloc_count--; drm_free(chan, sizeof(*chan), DRM_MEM_DRIVER); } @@ -445,14 +430,16 @@ void nouveau_fifo_free(struct drm_device *dev, int channel) /* cleanups all the fifos from file_priv */ void nouveau_fifo_cleanup(struct drm_device *dev, struct drm_file *file_priv) { - int i; struct drm_nouveau_private *dev_priv = dev->dev_private; + int i; DRM_DEBUG("clearing FIFO enables from file_priv\n"); - for(i=0;i<nouveau_fifo_number(dev);i++) - if (dev_priv->fifos[i] && - dev_priv->fifos[i]->file_priv==file_priv) - nouveau_fifo_free(dev,i); + for(i = 0; i < nouveau_fifo_number(dev); i++) { + struct nouveau_channel *chan = dev_priv->fifos[i]; + + if (chan && chan->file_priv == file_priv) + nouveau_fifo_free(chan); + } } int @@ -472,24 +459,31 @@ nouveau_fifo_owner(struct drm_device *dev, struct drm_file *file_priv, * ioctls wrapping the functions ***********************************/ -static int nouveau_ioctl_fifo_alloc(struct drm_device *dev, void *data, struct drm_file *file_priv) +static int nouveau_ioctl_fifo_alloc(struct drm_device *dev, void *data, + struct drm_file *file_priv) { struct drm_nouveau_private *dev_priv = dev->dev_private; - struct drm_nouveau_fifo_alloc *init = data; + struct drm_nouveau_channel_alloc *init = data; struct drm_map_list *entry; - struct nouveau_fifo *chan; + struct nouveau_channel *chan; + struct mem_block *pushbuf; int res; + NOUVEAU_CHECK_INITIALISED_WITH_RETURN; + if (init->fb_ctxdma_handle == ~0 || init->tt_ctxdma_handle == ~0) return -EINVAL; - res = nouveau_fifo_alloc(dev, &init->channel, file_priv, + pushbuf = nouveau_fifo_user_pushbuf_alloc(dev); + if (!pushbuf) + return -ENOMEM; + + res = nouveau_fifo_alloc(dev, &chan, file_priv, pushbuf, init->fb_ctxdma_handle, init->tt_ctxdma_handle); if (res) return res; - chan = dev_priv->fifos[init->channel]; - + init->channel = chan->id; init->put_base = chan->pushbuf_base; /* make the fifo available to user space */ @@ -523,18 +517,34 @@ static int nouveau_ioctl_fifo_alloc(struct drm_device *dev, void *data, struct d return 0; } +static int nouveau_ioctl_fifo_free(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + struct drm_nouveau_channel_free *cfree = data; + struct nouveau_channel *chan; + + NOUVEAU_CHECK_INITIALISED_WITH_RETURN; + NOUVEAU_GET_USER_CHANNEL_WITH_RETURN(cfree->channel, file_priv, chan); + + nouveau_fifo_free(chan); + return 0; +} + /*********************************** * finally, the ioctl table ***********************************/ struct drm_ioctl_desc nouveau_ioctls[] = { - DRM_IOCTL_DEF(DRM_NOUVEAU_FIFO_ALLOC, nouveau_ioctl_fifo_alloc, DRM_AUTH), + DRM_IOCTL_DEF(DRM_NOUVEAU_CARD_INIT, nouveau_ioctl_card_init, DRM_AUTH), + DRM_IOCTL_DEF(DRM_NOUVEAU_GETPARAM, nouveau_ioctl_getparam, DRM_AUTH), + DRM_IOCTL_DEF(DRM_NOUVEAU_SETPARAM, nouveau_ioctl_setparam, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + DRM_IOCTL_DEF(DRM_NOUVEAU_CHANNEL_ALLOC, nouveau_ioctl_fifo_alloc, DRM_AUTH), + DRM_IOCTL_DEF(DRM_NOUVEAU_CHANNEL_FREE, nouveau_ioctl_fifo_free, DRM_AUTH), DRM_IOCTL_DEF(DRM_NOUVEAU_GROBJ_ALLOC, nouveau_ioctl_grobj_alloc, DRM_AUTH), - DRM_IOCTL_DEF(DRM_NOUVEAU_NOTIFIER_ALLOC, nouveau_ioctl_notifier_alloc, DRM_AUTH), + DRM_IOCTL_DEF(DRM_NOUVEAU_NOTIFIEROBJ_ALLOC, nouveau_ioctl_notifier_alloc, DRM_AUTH), + DRM_IOCTL_DEF(DRM_NOUVEAU_GPUOBJ_FREE, nouveau_ioctl_gpuobj_free, DRM_AUTH), DRM_IOCTL_DEF(DRM_NOUVEAU_MEM_ALLOC, nouveau_ioctl_mem_alloc, DRM_AUTH), DRM_IOCTL_DEF(DRM_NOUVEAU_MEM_FREE, nouveau_ioctl_mem_free, DRM_AUTH), - DRM_IOCTL_DEF(DRM_NOUVEAU_GETPARAM, nouveau_ioctl_getparam, DRM_AUTH), - DRM_IOCTL_DEF(DRM_NOUVEAU_SETPARAM, nouveau_ioctl_setparam, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), }; int nouveau_max_ioctl = DRM_ARRAY_SIZE(nouveau_ioctls); diff --git a/shared-core/nouveau_irq.c b/shared-core/nouveau_irq.c index f7baf89e..d8a2c1b8 100644 --- a/shared-core/nouveau_irq.c +++ b/shared-core/nouveau_irq.c @@ -40,33 +40,6 @@ void nouveau_irq_preinstall(struct drm_device *dev) { struct drm_nouveau_private *dev_priv = dev->dev_private; - DRM_DEBUG("IRQ: preinst\n"); - - if (!dev_priv) { - DRM_ERROR("AIII, no dev_priv\n"); - return; - } - if (!dev_priv->mmio) { - DRM_ERROR("AIII, no dev_priv->mmio\n"); - return; - } - - /* Disable/Clear PFIFO interrupts */ - NV_WRITE(NV03_PFIFO_INTR_EN_0, 0); - NV_WRITE(NV03_PFIFO_INTR_0, 0xFFFFFFFF); - /* Disable/Clear PGRAPH interrupts */ - if (dev_priv->card_type<NV_40) - NV_WRITE(NV03_PGRAPH_INTR_EN, 0); - else - NV_WRITE(NV40_PGRAPH_INTR_EN, 0); - NV_WRITE(NV03_PGRAPH_INTR, 0xFFFFFFFF); -#if 0 - /* Disable/Clear CRTC0/1 interrupts */ - NV_WRITE(NV_CRTC0_INTEN, 0); - NV_WRITE(NV_CRTC0_INTSTAT, NV_CRTC_INTR_VBLANK); - NV_WRITE(NV_CRTC1_INTEN, 0); - NV_WRITE(NV_CRTC1_INTSTAT, NV_CRTC_INTR_VBLANK); -#endif /* Master disable */ NV_WRITE(NV03_PMC_INTR_EN_0, 0); } @@ -75,34 +48,6 @@ void nouveau_irq_postinstall(struct drm_device *dev) { struct drm_nouveau_private *dev_priv = dev->dev_private; - if (!dev_priv) { - DRM_ERROR("AIII, no dev_priv\n"); - return; - } - if (!dev_priv->mmio) { - DRM_ERROR("AIII, no dev_priv->mmio\n"); - return; - } - - DRM_DEBUG("IRQ: postinst\n"); - - /* Enable PFIFO error reporting */ - 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, 0xFFFFFFFF); - else - NV_WRITE(NV40_PGRAPH_INTR_EN, 0xFFFFFFFF); - NV_WRITE(NV03_PGRAPH_INTR, 0xFFFFFFFF); - -#if 0 - /* Enable CRTC0/1 interrupts */ - NV_WRITE(NV_CRTC0_INTEN, NV_CRTC_INTR_VBLANK); - NV_WRITE(NV_CRTC1_INTEN, NV_CRTC_INTR_VBLANK); -#endif - /* Master enable */ NV_WRITE(NV03_PMC_INTR_EN_0, NV_PMC_INTR_EN_0_MASTER_ENABLE); } @@ -111,29 +56,6 @@ void nouveau_irq_uninstall(struct drm_device *dev) { struct drm_nouveau_private *dev_priv = dev->dev_private; - if (!dev_priv) { - DRM_ERROR("AIII, no dev_priv\n"); - return; - } - if (!dev_priv->mmio) { - DRM_ERROR("AIII, no dev_priv->mmio\n"); - return; - } - - DRM_DEBUG("IRQ: uninst\n"); - - /* Disable PFIFO interrupts */ - NV_WRITE(NV03_PFIFO_INTR_EN_0, 0); - /* Disable PGRAPH interrupts */ - if (dev_priv->card_type<NV_40) - NV_WRITE(NV03_PGRAPH_INTR_EN, 0); - else - NV_WRITE(NV40_PGRAPH_INTR_EN, 0); -#if 0 - /* Disable CRTC0/1 interrupts */ - NV_WRITE(NV_CRTC0_INTEN, 0); - NV_WRITE(NV_CRTC1_INTEN, 0); -#endif /* Master disable */ NV_WRITE(NV03_PMC_INTR_EN_0, 0); } @@ -150,12 +72,10 @@ static void nouveau_fifo_irq_handler(struct drm_device *dev) chstat = NV_READ(NV04_PFIFO_DMA); channel=NV_READ(NV03_PFIFO_CACHE1_PUSH1)&(nouveau_fifo_number(dev)-1); - DRM_DEBUG("NV: PFIFO interrupt! Channel=%d, INTSTAT=0x%08x/MODE=0x%08x/PEND=0x%08x\n", channel, status, chmode, chstat); - if (status & NV_PFIFO_INTR_CACHE_ERROR) { uint32_t c1get, c1method, c1data; - DRM_ERROR("NV: PFIFO error interrupt\n"); + DRM_ERROR("PFIFO error interrupt\n"); c1get = NV_READ(NV03_PFIFO_CACHE1_GET) >> 2; if (dev_priv->card_type < NV_40) { @@ -167,17 +87,17 @@ static void nouveau_fifo_irq_handler(struct drm_device *dev) c1data = NV_READ(NV40_PFIFO_CACHE1_DATA(c1get)); } - DRM_ERROR("NV: Channel %d/%d - Method 0x%04x, Data 0x%08x\n", - channel, (c1method >> 13) & 7, - c1method & 0x1ffc, c1data - ); + DRM_ERROR("Channel %d/%d - Method 0x%04x, Data 0x%08x\n", + channel, (c1method >> 13) & 7, c1method & 0x1ffc, + c1data); status &= ~NV_PFIFO_INTR_CACHE_ERROR; NV_WRITE(NV03_PFIFO_INTR_0, NV_PFIFO_INTR_CACHE_ERROR); } if (status & NV_PFIFO_INTR_DMA_PUSHER) { - DRM_INFO("NV: PFIFO DMA pusher interrupt\n"); + DRM_ERROR("PFIFO DMA pusher interrupt: ch%d, 0x%08x\n", + channel, NV_READ(NV04_PFIFO_CACHE1_DMA_GET)); status &= ~NV_PFIFO_INTR_DMA_PUSHER; NV_WRITE(NV03_PFIFO_INTR_0, NV_PFIFO_INTR_DMA_PUSHER); @@ -191,7 +111,7 @@ static void nouveau_fifo_irq_handler(struct drm_device *dev) } if (status) { - DRM_INFO("NV: unknown PFIFO interrupt. status=0x%08x\n", status); + DRM_ERROR("Unhandled PFIFO interrupt: status=0x%08x\n", status); NV_WRITE(NV03_PFIFO_INTR_0, status); } @@ -301,6 +221,62 @@ nouveau_print_bitfield_names(uint32_t value, printk(" (unknown bits 0x%08x)", value); } +static int +nouveau_graph_trapped_channel(struct drm_device *dev, int *channel_ret) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + int channel; + + if (dev_priv->card_type < NV_40) { + channel = (NV_READ(0x400704) >> 20) & 0x1f; + } else + if (dev_priv->card_type < NV_50) { + uint32_t cur_grctx = (NV_READ(0x40032C) & 0xfffff) << 4; + + /* 0x400704 *sometimes* contains a sensible channel ID, but + * mostly not.. for now lookup which channel owns the active + * PGRAPH context. Probably a better way, but this'll do + * for now. + */ + for (channel = 0; channel < 32; channel++) { + if (dev_priv->fifos[channel] == NULL) + continue; + if (cur_grctx == + dev_priv->fifos[channel]->ramin_grctx->instance) + break; + } + if (channel == 32) { + DRM_ERROR("AIII, unable to determine active channel " + "from PGRAPH context 0x%08x\n", cur_grctx); + return -EINVAL; + } + } else { + uint32_t cur_grctx = (NV_READ(0x40032C) & 0xfffff) << 12; + + for (channel = 0; channel < 128; channel++) { + if (dev_priv->fifos[channel] == NULL) + continue; + if (cur_grctx == + dev_priv->fifos[channel]->ramin_grctx->instance) + break; + } + if (channel == 128) { + DRM_ERROR("AIII, unable to determine active channel " + "from PGRAPH context 0x%08x\n", cur_grctx); + return -EINVAL; + } + } + + if (channel > nouveau_fifo_number(dev) || + dev_priv->fifos[channel] == NULL) { + DRM_ERROR("AIII, invalid/inactive channel id %d\n", channel); + return -EINVAL; + } + + *channel_ret = channel; + return 0; +} + static void nouveau_graph_dump_trap_info(struct drm_device *dev) { @@ -310,8 +286,10 @@ nouveau_graph_dump_trap_info(struct drm_device *dev) uint32_t method, subc, data; uint32_t nsource, nstatus; + if (nouveau_graph_trapped_channel(dev, &channel)) + channel = -1; + address = NV_READ(0x400704); - channel = (address >> 20) & 0x1F; subc = (address >> 16) & 0x7; method = address & 0x1FFC; data = NV_READ(0x400708); @@ -331,77 +309,31 @@ nouveau_graph_dump_trap_info(struct drm_device *dev) ARRAY_SIZE(nouveau_nstatus_names)); printk("\n"); - DRM_ERROR("NV: Channel %d/%d (class 0x%04x) - " - "Method 0x%04x, Data 0x%08x\n", - channel, subc, class, method, data - ); + DRM_ERROR("Channel %d/%d (class 0x%04x) - Method 0x%04x, Data 0x%08x\n", + channel, subc, class, method, data); } static void nouveau_pgraph_irq_handler(struct drm_device *dev) { - uint32_t status; struct drm_nouveau_private *dev_priv = dev->dev_private; + uint32_t status, nsource; status = NV_READ(NV03_PGRAPH_INTR); if (!status) return; + nsource = NV_READ(NV03_PGRAPH_NSOURCE); if (status & NV_PGRAPH_INTR_NOTIFY) { - uint32_t nsource, nstatus, instance, notify; - DRM_DEBUG("NV: PGRAPH notify interrupt\n"); + DRM_DEBUG("PGRAPH notify interrupt\n"); - nstatus = NV_READ(NV03_PGRAPH_NSTATUS); - nsource = NV_READ(NV03_PGRAPH_NSOURCE); - DRM_DEBUG("nsource:0x%08x\tnstatus:0x%08x\n", nsource, nstatus); - - /* if this wasn't NOTIFICATION_PENDING, dump extra trap info */ - if (nsource & ~(1<<0)) { - nouveau_graph_dump_trap_info(dev); - } else { - instance = NV_READ(0x00400158); - notify = NV_READ(0x00400150) >> 16; - DRM_DEBUG("instance:0x%08x\tnotify:0x%08x\n", - instance, notify); - } + nouveau_graph_dump_trap_info(dev); status &= ~NV_PGRAPH_INTR_NOTIFY; NV_WRITE(NV03_PGRAPH_INTR, NV_PGRAPH_INTR_NOTIFY); } - if (status & NV_PGRAPH_INTR_BUFFER_NOTIFY) { - uint32_t nsource, nstatus, instance, notify; - DRM_DEBUG("NV: PGRAPH buffer notify interrupt\n"); - - nstatus = NV_READ(NV03_PGRAPH_NSTATUS); - nsource = NV_READ(NV03_PGRAPH_NSOURCE); - DRM_DEBUG("nsource:0x%08x\tnstatus:0x%08x\n", nsource, nstatus); - - instance = NV_READ(0x00400158); - notify = NV_READ(0x00400150) >> 16; - DRM_DEBUG("instance:0x%08x\tnotify:0x%08x\n", instance, notify); - - status &= ~NV_PGRAPH_INTR_BUFFER_NOTIFY; - NV_WRITE(NV03_PGRAPH_INTR, NV_PGRAPH_INTR_BUFFER_NOTIFY); - } - - if (status & NV_PGRAPH_INTR_MISSING_HW) { - DRM_ERROR("NV: PGRAPH missing hw interrupt\n"); - - status &= ~NV_PGRAPH_INTR_MISSING_HW; - NV_WRITE(NV03_PGRAPH_INTR, NV_PGRAPH_INTR_MISSING_HW); - } - if (status & NV_PGRAPH_INTR_ERROR) { - uint32_t nsource, nstatus, instance; - - DRM_ERROR("NV: PGRAPH error interrupt\n"); - - nstatus = NV_READ(NV03_PGRAPH_NSTATUS); - nsource = NV_READ(NV03_PGRAPH_NSOURCE); - DRM_ERROR("nsource:0x%08x\tnstatus:0x%08x\n", nsource, nstatus); - - instance = NV_READ(0x00400158); - DRM_ERROR("instance:0x%08x\n", instance); + DRM_ERROR("PGRAPH error interrupt\n"); nouveau_graph_dump_trap_info(dev); @@ -411,7 +343,7 @@ static void nouveau_pgraph_irq_handler(struct drm_device *dev) if (status & NV_PGRAPH_INTR_CONTEXT_SWITCH) { uint32_t channel=NV_READ(NV03_PFIFO_CACHE1_PUSH1)&(nouveau_fifo_number(dev)-1); - DRM_INFO("NV: PGRAPH context switch interrupt channel %x\n",channel); + DRM_DEBUG("PGRAPH context switch interrupt channel %x\n",channel); switch(dev_priv->card_type) { case NV_04: @@ -428,7 +360,7 @@ static void nouveau_pgraph_irq_handler(struct drm_device *dev) nouveau_nv20_context_switch(dev); break; default: - DRM_INFO("NV: Context switch not implemented\n"); + DRM_ERROR("Context switch not implemented\n"); break; } @@ -437,7 +369,7 @@ static void nouveau_pgraph_irq_handler(struct drm_device *dev) } if (status) { - DRM_INFO("NV: Unknown PGRAPH interrupt! STAT=0x%08x\n", status); + DRM_ERROR("Unhandled PGRAPH interrupt: STAT=0x%08x\n", status); NV_WRITE(NV03_PGRAPH_INTR, status); } @@ -447,6 +379,7 @@ static void nouveau_pgraph_irq_handler(struct drm_device *dev) static void nouveau_crtc_irq_handler(struct drm_device *dev, int crtc) { struct drm_nouveau_private *dev_priv = dev->dev_private; + if (crtc&1) { NV_WRITE(NV_CRTC0_INTSTAT, NV_CRTC_INTR_VBLANK); } @@ -466,16 +399,16 @@ irqreturn_t nouveau_irq_handler(DRM_IRQ_ARGS) if (!status) return IRQ_NONE; - DRM_DEBUG("PMC INTSTAT: 0x%08x\n", status); - if (status & NV_PMC_INTR_0_PFIFO_PENDING) { nouveau_fifo_irq_handler(dev); status &= ~NV_PMC_INTR_0_PFIFO_PENDING; } + if (status & NV_PMC_INTR_0_PGRAPH_PENDING) { nouveau_pgraph_irq_handler(dev); status &= ~NV_PMC_INTR_0_PGRAPH_PENDING; } + if (status & NV_PMC_INTR_0_CRTCn_PENDING) { nouveau_crtc_irq_handler(dev, (status>>24)&3); status &= ~NV_PMC_INTR_0_CRTCn_PENDING; diff --git a/shared-core/nouveau_mem.c b/shared-core/nouveau_mem.c index a7044c94..419522f4 100644 --- a/shared-core/nouveau_mem.c +++ b/shared-core/nouveau_mem.c @@ -411,7 +411,7 @@ int nouveau_mem_init(struct drm_device *dev) struct drm_scatter_gather sgreq; DRM_DEBUG("Allocating sg memory for PCI DMA\n"); - sgreq.size = 4 << 20; //4MB of PCI scatter-gather zone + sgreq.size = 16 << 20; //4MB of PCI scatter-gather zone if (drm_sg_alloc(dev, &sgreq)) { DRM_ERROR("Unable to allocate 4MB of scatter-gather" @@ -549,14 +549,10 @@ void nouveau_mem_free(struct drm_device* dev, struct mem_block* block) int nouveau_ioctl_mem_alloc(struct drm_device *dev, void *data, struct drm_file *file_priv) { - struct drm_nouveau_private *dev_priv = dev->dev_private; struct drm_nouveau_mem_alloc *alloc = data; struct mem_block *block; - if (!dev_priv) { - DRM_ERROR("%s called with no initialization\n", __FUNCTION__); - return -EINVAL; - } + NOUVEAU_CHECK_INITIALISED_WITH_RETURN; block=nouveau_mem_alloc(dev, alloc->alignment, alloc->size, alloc->flags, file_priv); @@ -575,6 +571,8 @@ int nouveau_ioctl_mem_free(struct drm_device *dev, void *data, struct drm_file * struct drm_nouveau_mem_free *memfree = data; struct mem_block *block; + NOUVEAU_CHECK_INITIALISED_WITH_RETURN; + block=NULL; if (memfree->flags & NOUVEAU_MEM_FB) block = find_block(dev_priv->fb_heap, memfree->offset); diff --git a/shared-core/nouveau_notifier.c b/shared-core/nouveau_notifier.c index 24a306e8..31547aae 100644 --- a/shared-core/nouveau_notifier.c +++ b/shared-core/nouveau_notifier.c @@ -30,23 +30,25 @@ #include "nouveau_drv.h" int -nouveau_notifier_init_channel(struct drm_device *dev, int channel, - struct drm_file *file_priv) +nouveau_notifier_init_channel(struct nouveau_channel *chan) { + struct drm_device *dev = chan->dev; struct drm_nouveau_private *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 && dev_priv->gart_info.type != NOUVEAU_GART_SGDMA) flags = NOUVEAU_MEM_AGP | NOUVEAU_MEM_FB_ACCEPTABLE; + else if ( dev_priv->pci_heap ) + flags = NOUVEAU_MEM_PCI; else flags = NOUVEAU_MEM_FB; flags |= NOUVEAU_MEM_MAPPED; + DRM_DEBUG("Allocating notifier block in %d\n", flags); chan->notifier_block = nouveau_mem_alloc(dev, 0, PAGE_SIZE, flags, - file_priv); + (struct drm_file *)-2); if (!chan->notifier_block) return -ENOMEM; @@ -59,25 +61,33 @@ nouveau_notifier_init_channel(struct drm_device *dev, int channel, } void -nouveau_notifier_takedown_channel(struct drm_device *dev, int channel) +nouveau_notifier_takedown_channel(struct nouveau_channel *chan) { - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_fifo *chan = dev_priv->fifos[channel]; + struct drm_device *dev = chan->dev; if (chan->notifier_block) { nouveau_mem_free(dev, chan->notifier_block); chan->notifier_block = NULL; } - /*XXX: heap destroy */ + nouveau_mem_takedown(&chan->notifier_heap); +} + +static void +nouveau_notifier_gpuobj_dtor(struct drm_device *dev, + struct nouveau_gpuobj *gpuobj) +{ + DRM_DEBUG("\n"); + + if (gpuobj->priv) + nouveau_mem_free_block(gpuobj->priv); } int -nouveau_notifier_alloc(struct drm_device *dev, int channel, uint32_t handle, +nouveau_notifier_alloc(struct nouveau_channel *chan, uint32_t handle, int count, uint32_t *b_offset) { - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_fifo *chan = dev_priv->fifos[channel]; + struct drm_device *dev = chan->dev; struct nouveau_gpuobj *nobj = NULL; struct mem_block *mem; uint32_t offset; @@ -85,14 +95,14 @@ nouveau_notifier_alloc(struct drm_device *dev, int channel, uint32_t handle, if (!chan->notifier_heap) { DRM_ERROR("Channel %d doesn't have a notifier heap!\n", - channel); + chan->id); return -EINVAL; } mem = nouveau_mem_alloc_block(chan->notifier_heap, 32, 0, - chan->file_priv); + (struct drm_file *)-2); if (!mem) { - DRM_ERROR("Channel %d notifier block full\n", channel); + DRM_ERROR("Channel %d notifier block full\n", chan->id); return -ENOMEM; } mem->flags = NOUVEAU_MEM_NOTIFIER; @@ -102,21 +112,25 @@ nouveau_notifier_alloc(struct drm_device *dev, int channel, uint32_t handle, target = NV_DMA_TARGET_VIDMEM; } else if (chan->notifier_block->flags & NOUVEAU_MEM_AGP) { target = NV_DMA_TARGET_AGP; + } else if (chan->notifier_block->flags & NOUVEAU_MEM_PCI) { + target = NV_DMA_TARGET_PCI_NONLINEAR; } else { DRM_ERROR("Bad DMA target, flags 0x%08x!\n", chan->notifier_block->flags); return -EINVAL; } - if ((ret = nouveau_gpuobj_dma_new(dev, channel, NV_CLASS_DMA_IN_MEMORY, + if ((ret = nouveau_gpuobj_dma_new(chan, 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; } + nobj->dtor = nouveau_notifier_gpuobj_dtor; + nobj->priv = mem; - if ((ret = nouveau_gpuobj_ref_add(dev, channel, handle, nobj, NULL))) { + if ((ret = nouveau_gpuobj_ref_add(dev, chan, handle, nobj, NULL))) { nouveau_gpuobj_del(dev, &nobj); nouveau_mem_free_block(mem); DRM_ERROR("Error referencing notifier ctxdma: %d\n", ret); @@ -128,19 +142,17 @@ nouveau_notifier_alloc(struct drm_device *dev, int channel, uint32_t handle, } int -nouveau_ioctl_notifier_alloc(struct drm_device *dev, void *data, struct drm_file *file_priv) +nouveau_ioctl_notifier_alloc(struct drm_device *dev, void *data, + struct drm_file *file_priv) { - struct drm_nouveau_notifier_alloc *na = data; + struct drm_nouveau_notifierobj_alloc *na = data; + struct nouveau_channel *chan; int ret; - if (!nouveau_fifo_owner(dev, file_priv, na->channel)) { - DRM_ERROR("pid %d doesn't own channel %d\n", - DRM_CURRENTPID, na->channel); - return -EPERM; - } + NOUVEAU_CHECK_INITIALISED_WITH_RETURN; + NOUVEAU_GET_USER_CHANNEL_WITH_RETURN(na->channel, file_priv, chan); - ret = nouveau_notifier_alloc(dev, na->channel, na->handle, - na->count, &na->offset); + ret = nouveau_notifier_alloc(chan, na->handle, na->count, &na->offset); if (ret) return ret; diff --git a/shared-core/nouveau_object.c b/shared-core/nouveau_object.c index e8b12bb7..e0cb334f 100644 --- a/shared-core/nouveau_object.c +++ b/shared-core/nouveau_object.c @@ -72,6 +72,8 @@ nouveau_ramht_hash_handle(struct drm_device *dev, int channel, uint32_t handle) uint32_t hash = 0; int i; + DRM_DEBUG("ch%d handle=0x%08x\n", channel, handle); + for (i=32;i>0;i-=dev_priv->ramht_bits) { hash ^= (handle & ((1 << dev_priv->ramht_bits) - 1)); handle >>= dev_priv->ramht_bits; @@ -80,7 +82,7 @@ nouveau_ramht_hash_handle(struct drm_device *dev, int channel, uint32_t handle) hash ^= channel << (dev_priv->ramht_bits - 4); hash <<= 3; - DRM_DEBUG("ch%d handle=0x%08x hash=0x%08x\n", channel, handle, hash); + DRM_DEBUG("hash=0x%08x\n", hash); return hash; } @@ -100,7 +102,7 @@ static int nouveau_ramht_insert(struct drm_device *dev, struct nouveau_gpuobj_ref *ref) { struct drm_nouveau_private *dev_priv=dev->dev_private; - struct nouveau_fifo *chan = dev_priv->fifos[ref->channel]; + struct nouveau_channel *chan = dev_priv->fifos[ref->channel]; struct nouveau_gpuobj *ramht = chan->ramht ? chan->ramht->gpuobj : NULL; struct nouveau_gpuobj *gpuobj = ref->gpuobj; uint32_t ctx, co, ho; @@ -131,6 +133,8 @@ nouveau_ramht_insert(struct drm_device *dev, struct nouveau_gpuobj_ref *ref) ref->channel, co, ref->handle, ctx); INSTANCE_WR(ramht, (co + 0)/4, ref->handle); INSTANCE_WR(ramht, (co + 4)/4, ctx); + + list_add_tail(&ref->list, &chan->ramht_refs); return 0; } DRM_DEBUG("collision ch%d 0x%08x: h=0x%08x\n", @@ -149,7 +153,7 @@ static void nouveau_ramht_remove(struct drm_device *dev, struct nouveau_gpuobj_ref *ref) { struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_fifo *chan = dev_priv->fifos[ref->channel]; + struct nouveau_channel *chan = dev_priv->fifos[ref->channel]; struct nouveau_gpuobj *ramht = chan->ramht ? chan->ramht->gpuobj : NULL; uint32_t co, ho; @@ -167,6 +171,8 @@ nouveau_ramht_remove(struct drm_device *dev, struct nouveau_gpuobj_ref *ref) INSTANCE_RD(ramht, (co + 4))); INSTANCE_WR(ramht, (co + 0)/4, 0x00000000); INSTANCE_WR(ramht, (co + 4)/4, 0x00000000); + + list_del(&ref->list); return; } @@ -180,34 +186,30 @@ nouveau_ramht_remove(struct drm_device *dev, struct nouveau_gpuobj_ref *ref) } int -nouveau_gpuobj_new(struct drm_device *dev, int channel, int size, int align, - uint32_t flags, struct nouveau_gpuobj **gpuobj_ret) +nouveau_gpuobj_new(struct drm_device *dev, struct nouveau_channel *chan, + int size, int align, uint32_t flags, + struct nouveau_gpuobj **gpuobj_ret) { struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_engine_func *engine = &dev_priv->Engine; - struct nouveau_fifo *chan = NULL; + struct nouveau_engine *engine = &dev_priv->Engine; struct nouveau_gpuobj *gpuobj; struct mem_block *pramin = NULL; int ret; DRM_DEBUG("ch%d size=%d align=%d flags=0x%08x\n", - channel, size, align, flags); + chan ? chan->id : -1, size, align, flags); if (!dev_priv || !gpuobj_ret || *gpuobj_ret != NULL) return -EINVAL; - if (channel >= 0) { - if (channel > nouveau_fifo_number(dev)) - return -EINVAL; - chan = dev_priv->fifos[channel]; - } - gpuobj = drm_calloc(1, sizeof(*gpuobj), DRM_MEM_DRIVER); if (!gpuobj) return -ENOMEM; DRM_DEBUG("gpuobj %p\n", gpuobj); gpuobj->flags = flags; - gpuobj->im_channel = channel; + gpuobj->im_channel = chan ? chan->id : -1; + + list_add_tail(&gpuobj->list, &dev_priv->gpuobj_list); /* Choose between global instmem heap, and per-channel private * instmem heap. On <NV50 allow requests for private instmem @@ -260,24 +262,64 @@ nouveau_gpuobj_new(struct drm_device *dev, int channel, int size, int align, INSTANCE_WR(gpuobj, i/4, 0); } - if (dev_priv->gpuobj_all) { - gpuobj->next = dev_priv->gpuobj_all; - gpuobj->next->prev = gpuobj; + *gpuobj_ret = gpuobj; + return 0; +} + +int +nouveau_gpuobj_early_init(struct drm_device *dev) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + + DRM_DEBUG("\n"); + + INIT_LIST_HEAD(&dev_priv->gpuobj_list); + + return 0; +} + +int +nouveau_gpuobj_init(struct drm_device *dev) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + int ret; + + DRM_DEBUG("\n"); + + if (dev_priv->card_type < NV_50) { + if ((ret = nouveau_gpuobj_new_fake(dev, dev_priv->ramht_offset, + ~0, dev_priv->ramht_size, + NVOBJ_FLAG_ZERO_ALLOC | + NVOBJ_FLAG_ALLOW_NO_REFS, + &dev_priv->ramht, NULL))) + return ret; } - dev_priv->gpuobj_all = gpuobj; - *gpuobj_ret = gpuobj; return 0; } -void nouveau_gpuobj_takedown(struct drm_device *dev) +void +nouveau_gpuobj_takedown(struct drm_device *dev) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + + DRM_DEBUG("\n"); + + nouveau_gpuobj_del(dev, &dev_priv->ramht); +} + +void +nouveau_gpuobj_late_takedown(struct drm_device *dev) { struct drm_nouveau_private *dev_priv = dev->dev_private; struct nouveau_gpuobj *gpuobj = NULL; + struct list_head *entry, *tmp; DRM_DEBUG("\n"); - while ((gpuobj = dev_priv->gpuobj_all)) { + list_for_each_safe(entry, tmp, &dev_priv->gpuobj_list) { + gpuobj = list_entry(entry, struct nouveau_gpuobj, list); + DRM_ERROR("gpuobj %p still exists at takedown, refs=%d\n", gpuobj, gpuobj->refcount); gpuobj->refcount = 0; @@ -285,10 +327,11 @@ void nouveau_gpuobj_takedown(struct drm_device *dev) } } -int nouveau_gpuobj_del(struct drm_device *dev, struct nouveau_gpuobj **pgpuobj) +int +nouveau_gpuobj_del(struct drm_device *dev, struct nouveau_gpuobj **pgpuobj) { struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_engine_func *engine = &dev_priv->Engine; + struct nouveau_engine *engine = &dev_priv->Engine; struct nouveau_gpuobj *gpuobj; DRM_DEBUG("gpuobj %p\n", pgpuobj ? *pgpuobj : NULL); @@ -302,7 +345,16 @@ int nouveau_gpuobj_del(struct drm_device *dev, struct nouveau_gpuobj **pgpuobj) return -EINVAL; } - engine->instmem.clear(dev, gpuobj); + if (gpuobj->dtor) + gpuobj->dtor(dev, gpuobj); + + if (gpuobj->im_backing) { + if (gpuobj->flags & NVOBJ_FLAG_FAKE) + drm_free(gpuobj->im_backing, + sizeof(*gpuobj->im_backing), DRM_MEM_DRIVER); + else + engine->instmem.clear(dev, gpuobj); + } if (gpuobj->im_pramin) { if (gpuobj->flags & NVOBJ_FLAG_FAKE) @@ -312,12 +364,7 @@ int nouveau_gpuobj_del(struct drm_device *dev, struct nouveau_gpuobj **pgpuobj) nouveau_mem_free_block(gpuobj->im_pramin); } - if (gpuobj->next) - gpuobj->next->prev = gpuobj->prev; - if (gpuobj->prev) - gpuobj->prev->next = gpuobj->next; - else - dev_priv->gpuobj_all = gpuobj->next; + list_del(&gpuobj->list); *pgpuobj = NULL; drm_free(gpuobj, sizeof(*gpuobj), DRM_MEM_DRIVER); @@ -325,7 +372,8 @@ int nouveau_gpuobj_del(struct drm_device *dev, struct nouveau_gpuobj **pgpuobj) } static int -nouveau_gpuobj_instance_get(struct drm_device *dev, int channel, +nouveau_gpuobj_instance_get(struct drm_device *dev, + struct nouveau_channel *chan, struct nouveau_gpuobj *gpuobj, uint32_t *inst) { struct drm_nouveau_private *dev_priv = dev->dev_private; @@ -337,15 +385,15 @@ nouveau_gpuobj_instance_get(struct drm_device *dev, int channel, return 0; } - if ((channel > 0) && gpuobj->im_channel != channel) { + if (chan && gpuobj->im_channel != chan->id) { DRM_ERROR("Channel mismatch: obj %d, ref %d\n", - gpuobj->im_channel, channel); + gpuobj->im_channel, chan->id); return -EINVAL; } /* NV50 channel-local instance */ - if (channel > 0) { - cpramin = dev_priv->fifos[channel]->ramin->gpuobj; + if (chan > 0) { + cpramin = chan->ramin->gpuobj; *inst = gpuobj->im_pramin->start - cpramin->im_pramin->start; return 0; } @@ -371,29 +419,25 @@ nouveau_gpuobj_instance_get(struct drm_device *dev, int channel, } int -nouveau_gpuobj_ref_add(struct drm_device *dev, int channel, uint32_t handle, - struct nouveau_gpuobj *gpuobj, struct nouveau_gpuobj_ref **ref_ret) +nouveau_gpuobj_ref_add(struct drm_device *dev, struct nouveau_channel *chan, + uint32_t handle, struct nouveau_gpuobj *gpuobj, + struct nouveau_gpuobj_ref **ref_ret) { struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_fifo *chan = NULL; struct nouveau_gpuobj_ref *ref; uint32_t instance; int ret; - DRM_DEBUG("ch%d h=0x%08x gpuobj=%p\n", channel, handle, gpuobj); + DRM_DEBUG("ch%d h=0x%08x gpuobj=%p\n", + chan ? chan->id : -1, handle, gpuobj); if (!dev_priv || !gpuobj || (ref_ret && *ref_ret != NULL)) return -EINVAL; - if (channel >= 0) { - if (channel > nouveau_fifo_number(dev)) - return -EINVAL; - chan = dev_priv->fifos[channel]; - } else - if (!ref_ret) + if (!chan && !ref_ret) return -EINVAL; - ret = nouveau_gpuobj_instance_get(dev, channel, gpuobj, &instance); + ret = nouveau_gpuobj_instance_get(dev, chan, gpuobj, &instance); if (ret) return ret; @@ -401,7 +445,7 @@ nouveau_gpuobj_ref_add(struct drm_device *dev, int channel, uint32_t handle, if (!ref) return -ENOMEM; ref->gpuobj = gpuobj; - ref->channel = channel; + ref->channel = chan ? chan->id : -1; ref->instance = instance; if (!ref_ret) { @@ -412,9 +456,6 @@ nouveau_gpuobj_ref_add(struct drm_device *dev, int channel, uint32_t handle, 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; @@ -452,8 +493,9 @@ int nouveau_gpuobj_ref_del(struct drm_device *dev, struct nouveau_gpuobj_ref **p } int -nouveau_gpuobj_new_ref(struct drm_device *dev, int oc, int rc, uint32_t handle, - int size, int align, uint32_t flags, +nouveau_gpuobj_new_ref(struct drm_device *dev, + struct nouveau_channel *oc, struct nouveau_channel *rc, + uint32_t handle, int size, int align, uint32_t flags, struct nouveau_gpuobj_ref **ref) { struct nouveau_gpuobj *gpuobj = NULL; @@ -470,28 +512,29 @@ nouveau_gpuobj_new_ref(struct drm_device *dev, int oc, int rc, uint32_t handle, return 0; } -static int -nouveau_gpuobj_ref_find(struct drm_device *dev, int channel, uint32_t handle, +int +nouveau_gpuobj_ref_find(struct nouveau_channel *chan, uint32_t handle, struct nouveau_gpuobj_ref **ref_ret) { - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_fifo *chan = dev_priv->fifos[channel]; - struct nouveau_gpuobj_ref *ref = chan->ramht_refs; + struct nouveau_gpuobj_ref *ref; + struct list_head *entry, *tmp; + + list_for_each_safe(entry, tmp, &chan->ramht_refs) { + ref = list_entry(entry, struct nouveau_gpuobj_ref, list); - while (ref) { if (ref->handle == handle) { if (ref_ret) *ref_ret = ref; return 0; } - ref = ref->next; } return -EINVAL; } int -nouveau_gpuobj_new_fake(struct drm_device *dev, uint32_t offset, uint32_t size, +nouveau_gpuobj_new_fake(struct drm_device *dev, uint32_t p_offset, + uint32_t b_offset, uint32_t size, uint32_t flags, struct nouveau_gpuobj **pgpuobj, struct nouveau_gpuobj_ref **pref) { @@ -499,8 +542,8 @@ nouveau_gpuobj_new_fake(struct drm_device *dev, uint32_t offset, uint32_t size, struct nouveau_gpuobj *gpuobj = NULL; int i; - DRM_DEBUG("offset=0x%08x size=0x%08x flags=0x%08x\n", - offset, size, flags); + DRM_DEBUG("p_offset=0x%08x b_offset=0x%08x size=0x%08x flags=0x%08x\n", + p_offset, b_offset, size, flags); gpuobj = drm_calloc(1, sizeof(*gpuobj), DRM_MEM_DRIVER); if (!gpuobj) @@ -509,14 +552,29 @@ nouveau_gpuobj_new_fake(struct drm_device *dev, uint32_t offset, uint32_t size, 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 -ENOMEM; + list_add_tail(&gpuobj->list, &dev_priv->gpuobj_list); + + if (p_offset != ~0) { + gpuobj->im_pramin = drm_calloc(1, sizeof(struct mem_block), + DRM_MEM_DRIVER); + if (!gpuobj->im_pramin) { + nouveau_gpuobj_del(dev, &gpuobj); + return -ENOMEM; + } + gpuobj->im_pramin->start = p_offset; + gpuobj->im_pramin->size = size; + } + + if (b_offset != ~0) { + gpuobj->im_backing = drm_calloc(1, sizeof(struct mem_block), + DRM_MEM_DRIVER); + if (!gpuobj->im_backing) { + nouveau_gpuobj_del(dev, &gpuobj); + return -ENOMEM; + } + gpuobj->im_backing->start = b_offset; + gpuobj->im_backing->size = size; } - gpuobj->im_pramin->start = offset; - gpuobj->im_pramin->size = size; if (gpuobj->flags & NVOBJ_FLAG_ZERO_ALLOC) { for (i = 0; i < gpuobj->im_pramin->size; i += 4) @@ -524,7 +582,7 @@ nouveau_gpuobj_new_fake(struct drm_device *dev, uint32_t offset, uint32_t size, } if (pref) { - if ((i = nouveau_gpuobj_ref_add(dev, -1, 0, gpuobj, pref))) { + if ((i = nouveau_gpuobj_ref_add(dev, NULL, 0, gpuobj, pref))) { nouveau_gpuobj_del(dev, &gpuobj); return i; } @@ -577,10 +635,11 @@ nouveau_gpuobj_class_instmem_size(struct drm_device *dev, int class) to it that can be used to set up context objects. */ int -nouveau_gpuobj_dma_new(struct drm_device *dev, int channel, int class, - uint64_t offset, uint64_t size, int access, int target, - struct nouveau_gpuobj **gpuobj) +nouveau_gpuobj_dma_new(struct nouveau_channel *chan, int class, + uint64_t offset, uint64_t size, int access, + int target, struct nouveau_gpuobj **gpuobj) { + struct drm_device *dev = chan->dev; struct drm_nouveau_private *dev_priv = dev->dev_private; int ret; uint32_t is_scatter_gather = 0; @@ -591,7 +650,7 @@ nouveau_gpuobj_dma_new(struct drm_device *dev, int channel, int class, DRM_DEBUG("ch%d class=0x%04x offset=0x%llx size=0x%llx\n", - channel, class, offset, size); + chan->id, class, offset, size); DRM_DEBUG("access=%d target=%d\n", access, target); switch (target) { @@ -608,7 +667,7 @@ nouveau_gpuobj_dma_new(struct drm_device *dev, int channel, int class, break; } - ret = nouveau_gpuobj_new(dev, channel, + ret = nouveau_gpuobj_new(dev, chan, is_scatter_gather ? ((page_count << 2) + 12) : nouveau_gpuobj_class_instmem_size(dev, class), 16, NVOBJ_FLAG_ZERO_ALLOC | NVOBJ_FLAG_ZERO_FREE, @@ -711,19 +770,19 @@ nouveau_gpuobj_dma_new(struct drm_device *dev, int channel, int class, } int -nouveau_gpuobj_gart_dma_new(struct drm_device *dev, int channel, +nouveau_gpuobj_gart_dma_new(struct nouveau_channel *chan, uint64_t offset, uint64_t size, int access, struct nouveau_gpuobj **gpuobj, uint32_t *o_ret) { + struct drm_device *dev = chan->dev; struct drm_nouveau_private *dev_priv = dev->dev_private; int ret; if (dev_priv->gart_info.type == NOUVEAU_GART_AGP || (dev_priv->card_type >= NV_50 && dev_priv->gart_info.type == NOUVEAU_GART_SGDMA)) { - ret = nouveau_gpuobj_dma_new(dev, channel, - NV_CLASS_DMA_IN_MEMORY, + ret = nouveau_gpuobj_dma_new(chan, NV_CLASS_DMA_IN_MEMORY, offset, size, access, NV_DMA_TARGET_AGP, gpuobj); if (o_ret) @@ -798,15 +857,16 @@ nouveau_gpuobj_gart_dma_new(struct drm_device *dev, int channel, set to 0? */ int -nouveau_gpuobj_gr_new(struct drm_device *dev, int channel, int class, +nouveau_gpuobj_gr_new(struct nouveau_channel *chan, int class, struct nouveau_gpuobj **gpuobj) { + struct drm_device *dev = chan->dev; struct drm_nouveau_private *dev_priv = dev->dev_private; int ret; - DRM_DEBUG("ch%d class=0x%04x\n", channel, class); + DRM_DEBUG("ch%d class=0x%04x\n", chan->id, class); - ret = nouveau_gpuobj_new(dev, channel, + ret = nouveau_gpuobj_new(dev, chan, nouveau_gpuobj_class_instmem_size(dev, class), 16, NVOBJ_FLAG_ZERO_ALLOC | NVOBJ_FLAG_ZERO_FREE, @@ -847,14 +907,14 @@ nouveau_gpuobj_gr_new(struct drm_device *dev, int channel, int class, } static int -nouveau_gpuobj_channel_init_pramin(struct drm_device *dev, int channel) +nouveau_gpuobj_channel_init_pramin(struct nouveau_channel *chan) { + struct drm_device *dev = chan->dev; struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_fifo *chan = dev_priv->fifos[channel]; struct nouveau_gpuobj *pramin = NULL; int size, base, ret; - DRM_DEBUG("ch%d\n", channel); + DRM_DEBUG("ch%d\n", chan->id); /* Base amount for object storage (4KiB enough?) */ size = 0x1000; @@ -876,8 +936,8 @@ nouveau_gpuobj_channel_init_pramin(struct drm_device *dev, int channel) } 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->id, size, base); + ret = nouveau_gpuobj_new_ref(dev, NULL, NULL, 0, size, 0x1000, 0, &chan->ramin); if (ret) { DRM_ERROR("Error allocating channel PRAMIN: %d\n", ret); @@ -897,21 +957,23 @@ nouveau_gpuobj_channel_init_pramin(struct drm_device *dev, int channel) } int -nouveau_gpuobj_channel_init(struct drm_device *dev, int channel, +nouveau_gpuobj_channel_init(struct nouveau_channel *chan, uint32_t vram_h, uint32_t tt_h) { + struct drm_device *dev = chan->dev; struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_fifo *chan = dev_priv->fifos[channel]; struct nouveau_gpuobj *vram = NULL, *tt = NULL; int ret, i; - DRM_DEBUG("ch%d vram=0x%08x tt=0x%08x\n", channel, vram_h, tt_h); + INIT_LIST_HEAD(&chan->ramht_refs); + + DRM_DEBUG("ch%d vram=0x%08x tt=0x%08x\n", chan->id, 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); + ret = nouveau_gpuobj_channel_init_pramin(chan); if (ret) return ret; } @@ -922,7 +984,7 @@ nouveau_gpuobj_channel_init(struct drm_device *dev, int channel, vm_offset = (dev_priv->chipset & 0xf0) == 0x50 ? 0x1400 : 0x200; vm_offset += chan->ramin->gpuobj->im_pramin->start; - if ((ret = nouveau_gpuobj_new_fake(dev, vm_offset, 0x4000, + if ((ret = nouveau_gpuobj_new_fake(dev, vm_offset, ~0, 0x4000, 0, &chan->vm_pd, NULL))) return ret; for (i=0; i<0x4000; i+=8) { @@ -930,7 +992,7 @@ nouveau_gpuobj_channel_init(struct drm_device *dev, int channel, INSTANCE_WR(chan->vm_pd, (i+4)/4, 0xdeadcafe); } - if ((ret = nouveau_gpuobj_ref_add(dev, -1, 0, + if ((ret = nouveau_gpuobj_ref_add(dev, NULL, 0, dev_priv->gart_info.sg_ctxdma, &chan->vm_gart_pt))) return ret; @@ -941,12 +1003,12 @@ nouveau_gpuobj_channel_init(struct drm_device *dev, int channel, /* RAMHT */ if (dev_priv->card_type < NV_50) { - ret = nouveau_gpuobj_ref_add(dev, -1, 0, dev_priv->ramht, + ret = nouveau_gpuobj_ref_add(dev, NULL, 0, dev_priv->ramht, &chan->ramht); if (ret) return ret; } else { - ret = nouveau_gpuobj_new_ref(dev, channel, channel, 0, + ret = nouveau_gpuobj_new_ref(dev, chan, chan, 0, 0x8000, 16, NVOBJ_FLAG_ZERO_ALLOC, &chan->ramht); @@ -955,7 +1017,7 @@ nouveau_gpuobj_channel_init(struct drm_device *dev, int channel, } /* VRAM ctxdma */ - if ((ret = nouveau_gpuobj_dma_new(dev, channel, NV_CLASS_DMA_IN_MEMORY, + if ((ret = nouveau_gpuobj_dma_new(chan, NV_CLASS_DMA_IN_MEMORY, 0, dev_priv->fb_available_size, NV_DMA_ACCESS_RW, NV_DMA_TARGET_VIDMEM, &vram))) { @@ -963,20 +1025,19 @@ nouveau_gpuobj_channel_init(struct drm_device *dev, int channel, return ret; } - if ((ret = nouveau_gpuobj_ref_add(dev, channel, vram_h, vram, NULL))) { + if ((ret = nouveau_gpuobj_ref_add(dev, chan, vram_h, vram, NULL))) { DRM_ERROR("Error referencing VRAM ctxdma: %d\n", ret); return ret; } /* TT memory ctxdma */ if (dev_priv->gart_info.type != NOUVEAU_GART_NONE) { - ret = nouveau_gpuobj_gart_dma_new(dev, channel, 0, + ret = nouveau_gpuobj_gart_dma_new(chan, 0, dev_priv->gart_info.aper_size, NV_DMA_ACCESS_RW, &tt, NULL); } else if (dev_priv->pci_heap) { - ret = nouveau_gpuobj_dma_new(dev, channel, - NV_CLASS_DMA_IN_MEMORY, + ret = nouveau_gpuobj_dma_new(chan, NV_CLASS_DMA_IN_MEMORY, 0, dev->sg->pages * PAGE_SIZE, NV_DMA_ACCESS_RW, NV_DMA_TARGET_PCI_NONLINEAR, &tt); @@ -990,7 +1051,7 @@ nouveau_gpuobj_channel_init(struct drm_device *dev, int channel, return ret; } - ret = nouveau_gpuobj_ref_add(dev, channel, tt_h, tt, NULL); + ret = nouveau_gpuobj_ref_add(dev, chan, tt_h, tt, NULL); if (ret) { DRM_ERROR("Error referencing TT ctxdma: %d\n", ret); return ret; @@ -1000,18 +1061,20 @@ nouveau_gpuobj_channel_init(struct drm_device *dev, int channel, } void -nouveau_gpuobj_channel_takedown(struct drm_device *dev, int channel) +nouveau_gpuobj_channel_takedown(struct nouveau_channel *chan) { - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_fifo *chan = dev_priv->fifos[channel]; + struct drm_device *dev = chan->dev; + struct list_head *entry, *tmp; struct nouveau_gpuobj_ref *ref; - DRM_DEBUG("ch%d\n", channel); + DRM_DEBUG("ch%d\n", chan->id); + + list_for_each_safe(entry, tmp, &chan->ramht_refs) { + ref = list_entry(entry, struct nouveau_gpuobj_ref, list); - while ((ref = chan->ramht_refs)) { - chan->ramht_refs = ref->next; nouveau_gpuobj_ref_del(dev, &ref); } + nouveau_gpuobj_ref_del(dev, &chan->ramht); nouveau_gpuobj_del(dev, &chan->vm_pd); @@ -1024,35 +1087,33 @@ nouveau_gpuobj_channel_takedown(struct drm_device *dev, int channel) } -int nouveau_ioctl_grobj_alloc(struct drm_device *dev, void *data, struct drm_file *file_priv) +int nouveau_ioctl_grobj_alloc(struct drm_device *dev, void *data, + struct drm_file *file_priv) { + struct nouveau_channel *chan; struct drm_nouveau_grobj_alloc *init = data; struct nouveau_gpuobj *gr = NULL; int ret; - if (!nouveau_fifo_owner(dev, file_priv, init->channel)) { - DRM_ERROR("pid %d doesn't own channel %d\n", - DRM_CURRENTPID, init->channel); - return -EINVAL; - } + NOUVEAU_CHECK_INITIALISED_WITH_RETURN; + NOUVEAU_GET_USER_CHANNEL_WITH_RETURN(init->channel, file_priv, chan); //FIXME: check args, only allow trusted objects to be created if (init->handle == ~0) return -EINVAL; - if (nouveau_gpuobj_ref_find(dev, init->channel, init->handle, NULL) == - 0) + + if (nouveau_gpuobj_ref_find(chan, init->handle, NULL) == 0) return -EEXIST; - ret = nouveau_gpuobj_gr_new(dev, init->channel, init->class, &gr); + ret = nouveau_gpuobj_gr_new(chan, init->class, &gr); if (ret) { DRM_ERROR("Error creating gr object: %d (%d/0x%08x)\n", ret, init->channel, init->handle); return ret; } - if ((ret = nouveau_gpuobj_ref_add(dev, init->channel, init->handle, - gr, NULL))) { + if ((ret = nouveau_gpuobj_ref_add(dev, chan, 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); @@ -1062,3 +1123,21 @@ int nouveau_ioctl_grobj_alloc(struct drm_device *dev, void *data, struct drm_fil return 0; } +int nouveau_ioctl_gpuobj_free(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + struct drm_nouveau_gpuobj_free *objfree = data; + struct nouveau_gpuobj_ref *ref; + struct nouveau_channel *chan; + int ret; + + NOUVEAU_CHECK_INITIALISED_WITH_RETURN; + NOUVEAU_GET_USER_CHANNEL_WITH_RETURN(objfree->channel, file_priv, chan); + + if ((ret = nouveau_gpuobj_ref_find(chan, objfree->handle, &ref))) + return ret; + nouveau_gpuobj_ref_del(dev, &ref); + + return 0; +} + diff --git a/shared-core/nouveau_reg.h b/shared-core/nouveau_reg.h index 47d54b2a..65614627 100644 --- a/shared-core/nouveau_reg.h +++ b/shared-core/nouveau_reg.h @@ -80,6 +80,16 @@ #define NV40_PMC_1708 0x00001708 #define NV40_PMC_170C 0x0000170C +/* probably PMC ? */ +#define NV50_PUNK_BAR0_PRAMIN 0x00001700 +#define NV50_PUNK_BAR_CFG_BASE 0x00001704 +#define NV50_PUNK_BAR_CFG_BASE_VALID (1<<30) +#define NV50_PUNK_BAR1_CTXDMA 0x00001708 +#define NV50_PUNK_BAR1_CTXDMA_VALID (1<<31) +#define NV50_PUNK_BAR3_CTXDMA 0x0000170C +#define NV50_PUNK_BAR3_CTXDMA_VALID (1<<31) +#define NV50_PUNK_UNK1710 0x00001710 + #define NV04_PTIMER_INTR_0 0x00009100 #define NV04_PTIMER_INTR_EN_0 0x00009140 #define NV04_PTIMER_NUMERATOR 0x00009200 diff --git a/shared-core/nouveau_state.c b/shared-core/nouveau_state.c index f45f2783..d885f7c6 100644 --- a/shared-core/nouveau_state.c +++ b/shared-core/nouveau_state.c @@ -93,7 +93,7 @@ static uint64_t nouveau_stub_timer_read(struct drm_device *dev) { return 0; } static int nouveau_init_engine_ptrs(struct drm_device *dev) { struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_engine_func *engine = &dev_priv->Engine; + struct nouveau_engine *engine = &dev_priv->Engine; switch (dev_priv->chipset & 0xf0) { case 0x00: @@ -224,7 +224,7 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) 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.init = nv40_fifo_init; engine->fifo.takedown = nouveau_stub_takedown; engine->fifo.create_context = nv40_fifo_create_context; engine->fifo.destroy_context = nv40_fifo_destroy_context; @@ -267,12 +267,18 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) return 0; } -static int nouveau_card_init(struct drm_device *dev) +int +nouveau_card_init(struct drm_device *dev) { struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_engine_func *engine; + struct nouveau_engine *engine; int ret; + DRM_DEBUG("prev state = %d\n", dev_priv->init_state); + + if (dev_priv->init_state == NOUVEAU_CARD_INIT_DONE) + return 0; + /* Map any PCI resources we need on the card */ ret = nouveau_init_card_mappings(dev); if (ret) return ret; @@ -290,6 +296,9 @@ static int nouveau_card_init(struct drm_device *dev) engine = &dev_priv->Engine; dev_priv->init_state = NOUVEAU_CARD_INIT_FAILED; + ret = nouveau_gpuobj_early_init(dev); + if (ret) return ret; + /* Initialise instance memory, must happen before mem_init so we * know exactly how much VRAM we're able to use for "normal" * purposes. @@ -301,6 +310,9 @@ static int nouveau_card_init(struct drm_device *dev) ret = nouveau_mem_init(dev); if (ret) return ret; + ret = nouveau_gpuobj_init(dev); + if (ret) return ret; + /* Parse BIOS tables / Run init tables? */ /* PMC */ @@ -323,8 +335,17 @@ static int nouveau_card_init(struct drm_device *dev) ret = engine->fifo.init(dev); if (ret) return ret; + /* this call irq_preinstall, register irq handler and + * call irq_postinstall + */ + ret = drm_irq_install(dev); + if (ret) return ret; + /* what about PVIDEO/PCRTC/PRAMDAC etc? */ + ret = nouveau_dma_channel_init(dev); + if (ret) return ret; + dev_priv->init_state = NOUVEAU_CARD_INIT_DONE; return 0; } @@ -332,9 +353,13 @@ static int nouveau_card_init(struct drm_device *dev) static void nouveau_card_takedown(struct drm_device *dev) { struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_engine_func *engine = &dev_priv->Engine; + struct nouveau_engine *engine = &dev_priv->Engine; + + DRM_DEBUG("prev state = %d\n", dev_priv->init_state); if (dev_priv->init_state != NOUVEAU_CARD_INIT_DOWN) { + nouveau_dma_channel_takedown(dev); + engine->fifo.takedown(dev); engine->graph.takedown(dev); engine->fb.takedown(dev); @@ -349,6 +374,10 @@ static void nouveau_card_takedown(struct drm_device *dev) nouveau_mem_close(dev); engine->instmem.takedown(dev); + drm_irq_uninstall(dev); + + nouveau_gpuobj_late_takedown(dev); + dev_priv->init_state = NOUVEAU_CARD_INIT_DOWN; } } @@ -368,14 +397,6 @@ void nouveau_preclose(struct drm_device *dev, struct drm_file *file_priv) /* first module load, setup the mmio/fb mapping */ int nouveau_firstopen(struct drm_device *dev) { - int ret; - - ret = nouveau_card_init(dev); - if (ret) { - DRM_ERROR("nouveau_card_init() failed! (%d)\n", ret); - return ret; - } - return 0; } @@ -395,15 +416,6 @@ int nouveau_load(struct drm_device *dev, unsigned long flags) dev_priv->init_state = NOUVEAU_CARD_INIT_DOWN; dev->dev_private = (void *)dev_priv; - -#if 0 - ret = nouveau_card_init(dev); - if (ret) { - DRM_ERROR("nouveau_card_init() failed! (%d)\n", ret); - return ret; - } -#endif - return 0; } @@ -427,12 +439,24 @@ int nouveau_unload(struct drm_device *dev) return 0; } +int +nouveau_ioctl_card_init(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + return nouveau_card_init(dev); +} + int nouveau_ioctl_getparam(struct drm_device *dev, void *data, struct drm_file *file_priv) { struct drm_nouveau_private *dev_priv = dev->dev_private; struct drm_nouveau_getparam *getparam = data; + NOUVEAU_CHECK_INITIALISED_WITH_RETURN; + switch (getparam->param) { + case NOUVEAU_GETPARAM_CHIPSET_ID: + getparam->value = dev_priv->chipset; + break; case NOUVEAU_GETPARAM_PCI_VENDOR: getparam->value=dev->pci_vendor; break; @@ -481,6 +505,8 @@ int nouveau_ioctl_setparam(struct drm_device *dev, void *data, struct drm_file * struct drm_nouveau_private *dev_priv = dev->dev_private; struct drm_nouveau_setparam *setparam = data; + NOUVEAU_CHECK_INITIALISED_WITH_RETURN; + switch (setparam->param) { case NOUVEAU_SETPARAM_CMDBUF_LOCATION: switch (setparam->value) { @@ -526,6 +552,7 @@ void nouveau_wait_for_idle(struct drm_device *dev) uint32_t status; do { uint32_t pmc_e = NV_READ(NV03_PMC_ENABLE); + (void)pmc_e; status = NV_READ(NV04_PGRAPH_STATUS); if (!status) break; diff --git a/shared-core/nv04_fifo.c b/shared-core/nv04_fifo.c index 564efd0b..d750ced8 100644 --- a/shared-core/nv04_fifo.c +++ b/shared-core/nv04_fifo.c @@ -36,13 +36,13 @@ #define NV04_RAMFC__SIZE 32 int -nv04_fifo_create_context(struct drm_device *dev, int channel) +nv04_fifo_create_context(struct nouveau_channel *chan) { + struct drm_device *dev = chan->dev; struct drm_nouveau_private *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), + if ((ret = nouveau_gpuobj_new_fake(dev, NV04_RAMFC(chan->id), ~0, NV04_RAMFC__SIZE, NVOBJ_FLAG_ZERO_ALLOC | NVOBJ_FLAG_ZERO_FREE, @@ -62,30 +62,29 @@ nv04_fifo_create_context(struct drm_device *dev, int channel) 0)); /* enable the fifo dma operation */ - NV_WRITE(NV04_PFIFO_MODE,NV_READ(NV04_PFIFO_MODE)|(1<<channel)); + NV_WRITE(NV04_PFIFO_MODE,NV_READ(NV04_PFIFO_MODE) | (1<<chan->id)); return 0; } void -nv04_fifo_destroy_context(struct drm_device *dev, int channel) +nv04_fifo_destroy_context(struct nouveau_channel *chan) { + struct drm_device *dev = chan->dev; struct drm_nouveau_private *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)); + + NV_WRITE(NV04_PFIFO_MODE, NV_READ(NV04_PFIFO_MODE)&~(1<<chan->id)); - if (chan->ramfc) - nouveau_gpuobj_ref_del(dev, &chan->ramfc); + nouveau_gpuobj_ref_del(dev, &chan->ramfc); } int -nv04_fifo_load_context(struct drm_device *dev, int channel) +nv04_fifo_load_context(struct nouveau_channel *chan) { + struct drm_device *dev = chan->dev; struct drm_nouveau_private *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(NV03_PFIFO_CACHE1_PUSH1, (1<<8) | chan->id); NV_WRITE(NV04_PFIFO_CACHE1_DMA_GET, RAMFC_RD(DMA_GET)); NV_WRITE(NV04_PFIFO_CACHE1_DMA_PUT, RAMFC_RD(DMA_PUT)); @@ -107,10 +106,10 @@ nv04_fifo_load_context(struct drm_device *dev, int channel) } int -nv04_fifo_save_context(struct drm_device *dev, int channel) +nv04_fifo_save_context(struct nouveau_channel *chan) { + struct drm_device *dev = chan->dev; struct drm_nouveau_private *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); diff --git a/shared-core/nv04_graph.c b/shared-core/nv04_graph.c index e35e3071..050f6e81 100644 --- a/shared-core/nv04_graph.c +++ b/shared-core/nv04_graph.c @@ -336,14 +336,13 @@ void nouveau_nv04_context_switch(struct drm_device *dev) NV_WRITE(NV04_PGRAPH_FIFO,0x1); } -int nv04_graph_create_context(struct drm_device *dev, int channel) { - struct drm_nouveau_private *dev_priv = dev->dev_private; - DRM_DEBUG("nv04_graph_context_create %d\n", channel); +int nv04_graph_create_context(struct nouveau_channel *chan) { + DRM_DEBUG("nv04_graph_context_create %d\n", chan->id); - memset(dev_priv->fifos[channel]->pgraph_ctx, 0, sizeof(dev_priv->fifos[channel]->pgraph_ctx)); + memset(chan->pgraph_ctx, 0, sizeof(chan->pgraph_ctx)); //dev_priv->fifos[channel].pgraph_ctx_user = channel << 24; - dev_priv->fifos[channel]->pgraph_ctx[0] = 0x0001ffff; + chan->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,17 +350,17 @@ int nv04_graph_create_context(struct drm_device *dev, int channel) { return 0; } -void nv04_graph_destroy_context(struct drm_device *dev, int channel) +void nv04_graph_destroy_context(struct nouveau_channel *chan) { } -int nv04_graph_load_context(struct drm_device *dev, int channel) +int nv04_graph_load_context(struct nouveau_channel *chan) { DRM_ERROR("stub!\n"); return 0; } -int nv04_graph_save_context(struct drm_device *dev, int channel) +int nv04_graph_save_context(struct nouveau_channel *chan) { DRM_ERROR("stub!\n"); return 0; @@ -376,6 +375,10 @@ int nv04_graph_init(struct drm_device *dev) { NV_WRITE(NV03_PMC_ENABLE, NV_READ(NV03_PMC_ENABLE) | NV_PMC_ENABLE_PGRAPH); + /* Enable PGRAPH interrupts */ + NV_WRITE(NV03_PGRAPH_INTR, 0xFFFFFFFF); + NV_WRITE(NV03_PGRAPH_INTR_EN, 0xFFFFFFFF); + // 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; diff --git a/shared-core/nv04_instmem.c b/shared-core/nv04_instmem.c index 35b20abd..5e0f6f4e 100644 --- a/shared-core/nv04_instmem.c +++ b/shared-core/nv04_instmem.c @@ -93,13 +93,6 @@ int nv04_instmem_init(struct drm_device *dev) 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. */ @@ -117,9 +110,6 @@ int nv04_instmem_init(struct drm_device *dev) void nv04_instmem_takedown(struct drm_device *dev) { - struct drm_nouveau_private *dev_priv = dev->dev_private; - - nouveau_gpuobj_del(dev, &dev_priv->ramht); } int @@ -139,7 +129,6 @@ nv04_instmem_clear(struct drm_device *dev, struct nouveau_gpuobj *gpuobj) 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; } } diff --git a/shared-core/nv04_mc.c b/shared-core/nv04_mc.c index 1d998851..eee0c50c 100644 --- a/shared-core/nv04_mc.c +++ b/shared-core/nv04_mc.c @@ -13,8 +13,6 @@ nv04_mc_init(struct drm_device *dev) */ NV_WRITE(NV03_PMC_ENABLE, 0xFFFFFFFF); - NV_WRITE(NV03_PMC_INTR_EN_0, 0); - return 0; } diff --git a/shared-core/nv10_fifo.c b/shared-core/nv10_fifo.c index 7b9c665b..c86725d2 100644 --- a/shared-core/nv10_fifo.c +++ b/shared-core/nv10_fifo.c @@ -33,17 +33,17 @@ 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(c) (dev_priv->ramfc_offset + ((c) * NV10_RAMFC__SIZE)) #define NV10_RAMFC__SIZE ((dev_priv->chipset) >= 0x17 ? 64 : 32) int -nv10_fifo_create_context(struct drm_device *dev, int channel) +nv10_fifo_create_context(struct nouveau_channel *chan) { + struct drm_device *dev = chan->dev; struct drm_nouveau_private *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), + if ((ret = nouveau_gpuobj_new_fake(dev, NV10_RAMFC(chan->id), ~0, NV10_RAMFC__SIZE, NVOBJ_FLAG_ZERO_ALLOC | NVOBJ_FLAG_ZERO_FREE, @@ -65,30 +65,29 @@ nv10_fifo_create_context(struct drm_device *dev, int channel) 0); /* enable the fifo dma operation */ - NV_WRITE(NV04_PFIFO_MODE,NV_READ(NV04_PFIFO_MODE)|(1<<channel)); + NV_WRITE(NV04_PFIFO_MODE,NV_READ(NV04_PFIFO_MODE)|(1<<chan->id)); return 0; } void -nv10_fifo_destroy_context(struct drm_device *dev, int channel) +nv10_fifo_destroy_context(struct nouveau_channel *chan) { + struct drm_device *dev = chan->dev; struct drm_nouveau_private *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)); + NV_WRITE(NV04_PFIFO_MODE, NV_READ(NV04_PFIFO_MODE)&~(1<<chan->id)); - if (chan->ramfc) - nouveau_gpuobj_ref_del(dev, &chan->ramfc); + nouveau_gpuobj_ref_del(dev, &chan->ramfc); } int -nv10_fifo_load_context(struct drm_device *dev, int channel) +nv10_fifo_load_context(struct nouveau_channel *chan) { + struct drm_device *dev = chan->dev; struct drm_nouveau_private *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(NV03_PFIFO_CACHE1_PUSH1 , 0x00000100 | chan->id); NV_WRITE(NV04_PFIFO_CACHE1_DMA_GET , RAMFC_RD(DMA_GET)); NV_WRITE(NV04_PFIFO_CACHE1_DMA_PUT , RAMFC_RD(DMA_PUT)); @@ -124,10 +123,10 @@ nv10_fifo_load_context(struct drm_device *dev, int channel) } int -nv10_fifo_save_context(struct drm_device *dev, int channel) +nv10_fifo_save_context(struct nouveau_channel *chan) { + struct drm_device *dev = chan->dev; struct drm_nouveau_private *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)); diff --git a/shared-core/nv10_graph.c b/shared-core/nv10_graph.c index 930fcbdf..53b93758 100644 --- a/shared-core/nv10_graph.c +++ b/shared-core/nv10_graph.c @@ -544,29 +544,52 @@ static int nv10_graph_ctx_regs_find_offset(struct drm_device *dev, int reg) return -1; } -static void restore_ctx_regs(struct drm_device *dev, int channel) +int nv10_graph_load_context(struct nouveau_channel *chan) { + struct drm_device *dev = chan->dev; struct drm_nouveau_private *dev_priv = dev->dev_private; - 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]); + NV_WRITE(nv10_graph_ctx_regs[i], chan->pgraph_ctx[i]); if (dev_priv->chipset>=0x17) { for (j = 0; j < sizeof(nv17_graph_ctx_regs)/sizeof(nv17_graph_ctx_regs[0]); i++,j++) - NV_WRITE(nv17_graph_ctx_regs[j], fifo->pgraph_ctx[i]); + NV_WRITE(nv17_graph_ctx_regs[j], chan->pgraph_ctx[i]); } - nouveau_wait_for_idle(dev); + + return 0; +} + +int nv10_graph_save_context(struct nouveau_channel *chan) +{ + struct drm_device *dev = chan->dev; + struct drm_nouveau_private *dev_priv = dev->dev_private; + int i, j; + + for (i = 0; i < sizeof(nv10_graph_ctx_regs)/sizeof(nv10_graph_ctx_regs[0]); i++) + chan->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++) + chan->pgraph_ctx[i] = NV_READ(nv17_graph_ctx_regs[j]); + } + + return 0; } void nouveau_nv10_context_switch(struct drm_device *dev) { struct drm_nouveau_private *dev_priv = dev->dev_private; - int channel, channel_old, i, j; + struct nouveau_channel *next, *last; + int chid; + + chid = NV_READ(NV03_PFIFO_CACHE1_PUSH1)&(nouveau_fifo_number(dev)-1); + next = dev_priv->fifos[chid]; - channel=NV_READ(NV03_PFIFO_CACHE1_PUSH1)&(nouveau_fifo_number(dev)-1); - channel_old = (NV_READ(NV10_PGRAPH_CTX_USER) >> 24) & (nouveau_fifo_number(dev)-1); + chid = (NV_READ(NV10_PGRAPH_CTX_USER) >> 24) & (nouveau_fifo_number(dev)-1); + last = dev_priv->fifos[chid]; - DRM_INFO("NV: PGRAPH context switch interrupt channel %x -> %x\n",channel_old, channel); + DRM_INFO("NV: PGRAPH context switch interrupt channel %x -> %x\n", + last->id, next->id); NV_WRITE(NV04_PGRAPH_FIFO,0x0); #if 0 @@ -574,14 +597,7 @@ void nouveau_nv10_context_switch(struct drm_device *dev) NV_WRITE(NV_PFIFO_CACH1_PUL1, 0x00000000); NV_WRITE(NV_PFIFO_CACHES, 0x00000000); #endif - - // 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]); - 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]); - } + nv10_graph_save_context(last); nouveau_wait_for_idle(dev); @@ -589,15 +605,12 @@ void nouveau_nv10_context_switch(struct drm_device *dev) NV_WRITE(NV10_PGRAPH_CTX_USER, (NV_READ(NV10_PGRAPH_CTX_USER) & 0xffffff) | (0x1f << 24)); nouveau_wait_for_idle(dev); - // restore PGRAPH context -#if 1 - restore_ctx_regs(dev, channel); -#endif + + nv10_graph_load_context(next); NV_WRITE(NV10_PGRAPH_CTX_CONTROL, 0x10010100); - NV_WRITE(NV10_PGRAPH_CTX_USER, channel << 24); + NV_WRITE(NV10_PGRAPH_CTX_USER, next->id << 24); NV_WRITE(NV10_PGRAPH_FFINTFC_ST2, NV_READ(NV10_PGRAPH_FFINTFC_ST2)&0xCFFFFFFF); - #if 0 NV_WRITE(NV_PFIFO_CACH1_PUL0, 0x00000001); NV_WRITE(NV_PFIFO_CACH1_PUL1, 0x00000001); @@ -609,16 +622,17 @@ void nouveau_nv10_context_switch(struct drm_device *dev) #define NV_WRITE_CTX(reg, val) do { \ int offset = nv10_graph_ctx_regs_find_offset(dev, reg); \ if (offset > 0) \ - fifo->pgraph_ctx[offset] = val; \ + chan->pgraph_ctx[offset] = val; \ } while (0) -int nv10_graph_create_context(struct drm_device *dev, int channel) { + +int nv10_graph_create_context(struct nouveau_channel *chan) { + struct drm_device *dev = chan->dev; struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_fifo *fifo = dev_priv->fifos[channel]; uint32_t tmp, vramsz; - DRM_DEBUG("nv10_graph_context_create %d\n", channel); + DRM_DEBUG("nv10_graph_context_create %d\n", chan->id); - memset(fifo->pgraph_ctx, 0, sizeof(fifo->pgraph_ctx)); + memset(chan->pgraph_ctx, 0, sizeof(chan->pgraph_ctx)); /* per channel init from ddx */ tmp = NV_READ(NV10_PGRAPH_SURFACE) & 0x0007ff00; @@ -654,7 +668,7 @@ int nv10_graph_create_context(struct drm_device *dev, int channel) { /* for the first channel init the regs */ if (dev_priv->fifo_alloc_count == 0) - restore_ctx_regs(dev, channel); + nv10_graph_load_context(chan); //XXX should be saved/restored for each fifo @@ -663,22 +677,10 @@ int nv10_graph_create_context(struct drm_device *dev, int channel) { return 0; } -void nv10_graph_destroy_context(struct drm_device *dev, int channel) +void nv10_graph_destroy_context(struct nouveau_channel *chan) { } -int nv10_graph_load_context(struct drm_device *dev, int channel) -{ - DRM_ERROR("stub!\n"); - return 0; -} - -int nv10_graph_save_context(struct drm_device *dev, int channel) -{ - DRM_ERROR("stub!\n"); - return 0; -} - int nv10_graph_init(struct drm_device *dev) { struct drm_nouveau_private *dev_priv = dev->dev_private; int i; @@ -688,8 +690,8 @@ int nv10_graph_init(struct drm_device *dev) { NV_WRITE(NV03_PMC_ENABLE, NV_READ(NV03_PMC_ENABLE) | NV_PMC_ENABLE_PGRAPH); - NV_WRITE(NV03_PGRAPH_INTR_EN, 0x00000000); NV_WRITE(NV03_PGRAPH_INTR , 0xFFFFFFFF); + NV_WRITE(NV03_PGRAPH_INTR_EN, 0xFFFFFFFF); NV_WRITE(NV04_PGRAPH_DEBUG_0, 0xFFFFFFFF); NV_WRITE(NV04_PGRAPH_DEBUG_0, 0x00000000); diff --git a/shared-core/nv20_graph.c b/shared-core/nv20_graph.c index 1670c527..c163daf9 100644 --- a/shared-core/nv20_graph.c +++ b/shared-core/nv20_graph.c @@ -29,39 +29,36 @@ #define NV20_GRCTX_SIZE (3529*4) -int nv20_graph_create_context(struct drm_device *dev, int channel) { - struct drm_nouveau_private *dev_priv = - (struct drm_nouveau_private *)dev->dev_private; - struct nouveau_fifo *chan = dev_priv->fifos[channel]; +int nv20_graph_create_context(struct nouveau_channel *chan) { + struct drm_device *dev = chan->dev; + struct drm_nouveau_private *dev_priv = dev->dev_private; unsigned int ctx_size = NV20_GRCTX_SIZE; int ret; - if ((ret = nouveau_gpuobj_new_ref(dev, channel, -1, 0, ctx_size, 16, + if ((ret = nouveau_gpuobj_new_ref(dev, chan, NULL, 0, ctx_size, 16, NVOBJ_FLAG_ZERO_ALLOC, &chan->ramin_grctx))) return ret; /* Initialise default context values */ - INSTANCE_WR(chan->ramin_grctx->gpuobj, 10, channel<<24); /* CTX_USER */ + INSTANCE_WR(chan->ramin_grctx->gpuobj, 10, chan->id<<24); /* CTX_USER */ - INSTANCE_WR(dev_priv->ctx_table->gpuobj, channel, + INSTANCE_WR(dev_priv->ctx_table->gpuobj, chan->id, chan->ramin_grctx->instance >> 4); return 0; } -void nv20_graph_destroy_context(struct drm_device *dev, int channel) { +void nv20_graph_destroy_context(struct nouveau_channel *chan) { + struct drm_device *dev = chan->dev; struct drm_nouveau_private *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); + nouveau_gpuobj_ref_del(dev, &chan->ramin_grctx); - INSTANCE_WR(dev_priv->ctx_table->gpuobj, channel, 0); + INSTANCE_WR(dev_priv->ctx_table->gpuobj, chan->id, 0); } static void nv20_graph_rdi(struct drm_device *dev) { - struct drm_nouveau_private *dev_priv = - (struct drm_nouveau_private *)dev->dev_private; + struct drm_nouveau_private *dev_priv = dev->dev_private; int i; NV_WRITE(NV10_PGRAPH_RDI_INDEX, 0x2c80000); @@ -73,13 +70,12 @@ static void nv20_graph_rdi(struct drm_device *dev) { /* Save current context (from PGRAPH) into the channel's context */ -int nv20_graph_save_context(struct drm_device *dev, int channel) { - struct drm_nouveau_private *dev_priv = - (struct drm_nouveau_private *)dev->dev_private; - struct nouveau_fifo *chan = dev_priv->fifos[channel]; +int nv20_graph_save_context(struct nouveau_channel *chan) { + struct drm_device *dev = chan->dev; + struct drm_nouveau_private *dev_priv = dev->dev_private; uint32_t instance; - instance = INSTANCE_RD(dev_priv->ctx_table->gpuobj, channel); + instance = INSTANCE_RD(dev_priv->ctx_table->gpuobj, chan->id); if (!instance) { return -EINVAL; } @@ -94,20 +90,19 @@ int nv20_graph_save_context(struct drm_device *dev, int channel) { /* Restore the context for a specific channel into PGRAPH */ -int nv20_graph_load_context(struct drm_device *dev, int channel) { - struct drm_nouveau_private *dev_priv = - (struct drm_nouveau_private *)dev->dev_private; - struct nouveau_fifo *chan = dev_priv->fifos[channel]; +int nv20_graph_load_context(struct nouveau_channel *chan) { + struct drm_device *dev = chan->dev; + struct drm_nouveau_private *dev_priv = dev->dev_private; uint32_t instance; - instance = INSTANCE_RD(dev_priv->ctx_table->gpuobj, channel); + instance = INSTANCE_RD(dev_priv->ctx_table->gpuobj, chan->id); if (!instance) { return -EINVAL; } 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_CTX_USER, chan->id << 24); NV_WRITE(NV10_PGRAPH_CHANNEL_CTX_SIZE, instance); NV_WRITE(NV10_PGRAPH_CHANNEL_CTX_POINTER, 1 /* restore ctx */); return 0; @@ -116,27 +111,32 @@ int nv20_graph_load_context(struct drm_device *dev, int channel) { void nouveau_nv20_context_switch(struct drm_device *dev) { struct drm_nouveau_private *dev_priv = dev->dev_private; - int channel, channel_old; + struct nouveau_channel *next, *last; + int chid; + + chid = NV_READ(NV03_PFIFO_CACHE1_PUSH1)&(nouveau_fifo_number(dev)-1); + next = dev_priv->fifos[chid]; - channel=NV_READ(NV03_PFIFO_CACHE1_PUSH1)&(nouveau_fifo_number(dev)-1); - channel_old = (NV_READ(NV10_PGRAPH_CTX_USER) >> 24) & (nouveau_fifo_number(dev)-1); + chid = (NV_READ(NV10_PGRAPH_CTX_USER) >> 24) & (nouveau_fifo_number(dev)-1); + last = dev_priv->fifos[chid]; - DRM_DEBUG("NV: PGRAPH context switch interrupt channel %x -> %x\n",channel_old, channel); + DRM_DEBUG("NV: PGRAPH context switch interrupt channel %x -> %x\n", + last->id, next->id); NV_WRITE(NV04_PGRAPH_FIFO,0x0); - nv20_graph_save_context(dev, channel_old); + nv20_graph_save_context(last); nouveau_wait_for_idle(dev); NV_WRITE(NV10_PGRAPH_CTX_CONTROL, 0x10000000); - nv20_graph_load_context(dev, channel); + nv20_graph_load_context(next); nouveau_wait_for_idle(dev); - if ((NV_READ(NV10_PGRAPH_CTX_USER) >> 24) != channel) - DRM_ERROR("nouveau_nv20_context_switch : wrong channel restored %x %x!!!\n", channel, NV_READ(NV10_PGRAPH_CTX_USER) >> 24); + if ((NV_READ(NV10_PGRAPH_CTX_USER) >> 24) != next->id) + DRM_ERROR("nouveau_nv20_context_switch : wrong channel restored %x %x!!!\n", next->id, NV_READ(NV10_PGRAPH_CTX_USER) >> 24); NV_WRITE(NV10_PGRAPH_CTX_CONTROL, 0x10010100); NV_WRITE(NV10_PGRAPH_FFINTFC_ST2, NV_READ(NV10_PGRAPH_FFINTFC_ST2)&0xCFFFFFFF); @@ -157,7 +157,7 @@ int nv20_graph_init(struct drm_device *dev) { /* Create Context Pointer Table */ dev_priv->ctx_table_size = 32 * 4; - if ((ret = nouveau_gpuobj_new_ref(dev, -1, -1, 0, + if ((ret = nouveau_gpuobj_new_ref(dev, NULL, NULL, 0, dev_priv->ctx_table_size, 16, NVOBJ_FLAG_ZERO_ALLOC, &dev_priv->ctx_table))) @@ -169,8 +169,8 @@ int nv20_graph_init(struct drm_device *dev) { //XXX need to be done and save/restore for each fifo ??? nv20_graph_rdi(dev); - NV_WRITE(NV03_PGRAPH_INTR_EN, 0x00000000); NV_WRITE(NV03_PGRAPH_INTR , 0xFFFFFFFF); + NV_WRITE(NV03_PGRAPH_INTR_EN, 0xFFFFFFFF); NV_WRITE(NV04_PGRAPH_DEBUG_0, 0xFFFFFFFF); NV_WRITE(NV04_PGRAPH_DEBUG_0, 0x00000000); diff --git a/shared-core/nv30_graph.c b/shared-core/nv30_graph.c index 4ed2e2ba..161f3154 100644 --- a/shared-core/nv30_graph.c +++ b/shared-core/nv30_graph.c @@ -100,11 +100,10 @@ static void nv30_graph_context_init(struct drm_device *dev, struct nouveau_gpuob } -int nv30_graph_create_context(struct drm_device *dev, int channel) +int nv30_graph_create_context(struct nouveau_channel *chan) { - struct drm_nouveau_private *dev_priv = - (struct drm_nouveau_private *)dev->dev_private; - struct nouveau_fifo *chan = dev_priv->fifos[channel]; + struct drm_device *dev = chan->dev; + struct drm_nouveau_private *dev_priv = dev->dev_private; void (*ctx_init)(struct drm_device *, struct nouveau_gpuobj *); unsigned int ctx_size; int ret; @@ -116,7 +115,7 @@ int nv30_graph_create_context(struct drm_device *dev, int channel) break; } - if ((ret = nouveau_gpuobj_new_ref(dev, channel, -1, 0, ctx_size, 16, + if ((ret = nouveau_gpuobj_new_ref(dev, chan, NULL, 0, ctx_size, 16, NVOBJ_FLAG_ZERO_ALLOC, &chan->ramin_grctx))) return ret; @@ -124,23 +123,22 @@ int nv30_graph_create_context(struct drm_device *dev, int channel) /* Initialise default context values */ ctx_init(dev, chan->ramin_grctx->gpuobj); - INSTANCE_WR(chan->ramin_grctx->gpuobj, 10, channel<<24); /* CTX_USER */ - INSTANCE_WR(dev_priv->ctx_table->gpuobj, channel, + INSTANCE_WR(chan->ramin_grctx->gpuobj, 10, chan->id<<24); /* CTX_USER */ + INSTANCE_WR(dev_priv->ctx_table->gpuobj, chan->id, chan->ramin_grctx->instance >> 4); return 0; } -void nv30_graph_destroy_context(struct drm_device *dev, int channel) +void nv30_graph_destroy_context(struct nouveau_channel *chan) { - struct drm_nouveau_private *dev_priv = - (struct drm_nouveau_private *)dev->dev_private; - struct nouveau_fifo *chan = dev_priv->fifos[channel]; + struct drm_device *dev = chan->dev; + struct drm_nouveau_private *dev_priv = dev->dev_private; if (chan->ramin_grctx) nouveau_gpuobj_ref_del(dev, &chan->ramin_grctx); - INSTANCE_WR(dev_priv->ctx_table->gpuobj, channel, 0); + INSTANCE_WR(dev_priv->ctx_table->gpuobj, chan->id, 0); } static int @@ -161,10 +159,10 @@ nouveau_graph_wait_idle(struct drm_device *dev) return 0; } -int nv30_graph_load_context(struct drm_device *dev, int channel) +int nv30_graph_load_context(struct nouveau_channel *chan) { + struct drm_device *dev = chan->dev; struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_fifo *chan = dev_priv->fifos[channel]; uint32_t inst; if (!chan->ramin_grctx) @@ -178,10 +176,10 @@ int nv30_graph_load_context(struct drm_device *dev, int channel) return nouveau_graph_wait_idle(dev); } -int nv30_graph_save_context(struct drm_device *dev, int channel) +int nv30_graph_save_context(struct nouveau_channel *chan) { + struct drm_device *dev = chan->dev; struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_fifo *chan = dev_priv->fifos[channel]; uint32_t inst; if (!chan->ramin_grctx) @@ -197,8 +195,7 @@ int nv30_graph_save_context(struct drm_device *dev, int channel) int nv30_graph_init(struct drm_device *dev) { - struct drm_nouveau_private *dev_priv = - (struct drm_nouveau_private *)dev->dev_private; + struct drm_nouveau_private *dev_priv = dev->dev_private; uint32_t vramsz, tmp; int ret, i; @@ -209,7 +206,7 @@ int nv30_graph_init(struct drm_device *dev) /* Create Context Pointer Table */ dev_priv->ctx_table_size = 32 * 4; - if ((ret = nouveau_gpuobj_new_ref(dev, -1, -1, 0, + if ((ret = nouveau_gpuobj_new_ref(dev, NULL, NULL, 0, dev_priv->ctx_table_size, 16, NVOBJ_FLAG_ZERO_ALLOC, &dev_priv->ctx_table))) @@ -218,8 +215,8 @@ int nv30_graph_init(struct drm_device *dev) 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); + NV_WRITE(NV03_PGRAPH_INTR_EN, 0xFFFFFFFF); NV_WRITE(NV04_PGRAPH_DEBUG_0, 0xFFFFFFFF); NV_WRITE(NV04_PGRAPH_DEBUG_0, 0x00000000); diff --git a/shared-core/nv40_fifo.c b/shared-core/nv40_fifo.c index ecb1d21e..ce3f8fdd 100644 --- a/shared-core/nv40_fifo.c +++ b/shared-core/nv40_fifo.c @@ -37,13 +37,13 @@ #define NV40_RAMFC__SIZE 128 int -nv40_fifo_create_context(struct drm_device *dev, int channel) +nv40_fifo_create_context(struct nouveau_channel *chan) { + struct drm_device *dev = chan->dev; struct drm_nouveau_private *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), + if ((ret = nouveau_gpuobj_new_fake(dev, NV40_RAMFC(chan->id), ~0, NV40_RAMFC__SIZE, NVOBJ_FLAG_ZERO_ALLOC | NVOBJ_FLAG_ZERO_FREE, @@ -68,27 +68,27 @@ nv40_fifo_create_context(struct drm_device *dev, int channel) RAMFC_WR(DMA_TIMESLICE , 0x0001FFFF); /* enable the fifo dma operation */ - NV_WRITE(NV04_PFIFO_MODE,NV_READ(NV04_PFIFO_MODE)|(1<<channel)); + NV_WRITE(NV04_PFIFO_MODE,NV_READ(NV04_PFIFO_MODE)|(1<<chan->id)); return 0; } void -nv40_fifo_destroy_context(struct drm_device *dev, int channel) +nv40_fifo_destroy_context(struct nouveau_channel *chan) { + struct drm_device *dev = chan->dev; struct drm_nouveau_private *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)); + NV_WRITE(NV04_PFIFO_MODE, NV_READ(NV04_PFIFO_MODE)&~(1<<chan->id)); if (chan->ramfc) nouveau_gpuobj_ref_del(dev, &chan->ramfc); } int -nv40_fifo_load_context(struct drm_device *dev, int channel) +nv40_fifo_load_context(struct nouveau_channel *chan) { + struct drm_device *dev = chan->dev; struct drm_nouveau_private *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)); @@ -135,7 +135,7 @@ nv40_fifo_load_context(struct drm_device *dev, int channel) NV_WRITE(NV04_PFIFO_DMA_TIMESLICE, tmp); /* Set channel active, and in DMA mode */ - NV_WRITE(NV03_PFIFO_CACHE1_PUSH1 , 0x00010000 | channel); + NV_WRITE(NV03_PFIFO_CACHE1_PUSH1 , 0x00010000 | chan->id); /* 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); @@ -144,10 +144,10 @@ nv40_fifo_load_context(struct drm_device *dev, int channel) } int -nv40_fifo_save_context(struct drm_device *dev, int channel) +nv40_fifo_save_context(struct nouveau_channel *chan) { + struct drm_device *dev = chan->dev; struct drm_nouveau_private *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)); @@ -193,3 +193,16 @@ nv40_fifo_save_context(struct drm_device *dev, int channel) return 0; } +int +nv40_fifo_init(struct drm_device *dev) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + int ret; + + if ((ret = nouveau_fifo_init(dev))) + return ret; + + NV_WRITE(NV04_PFIFO_DMA_TIMESLICE, 0x2101ffff); + return 0; +} + diff --git a/shared-core/nv40_graph.c b/shared-core/nv40_graph.c index 441dbae7..c1464bc2 100644 --- a/shared-core/nv40_graph.c +++ b/shared-core/nv40_graph.c @@ -1224,11 +1224,10 @@ nv4e_graph_context_init(struct drm_device *dev, struct nouveau_gpuobj *ctx) } int -nv40_graph_create_context(struct drm_device *dev, int channel) +nv40_graph_create_context(struct nouveau_channel *chan) { - struct drm_nouveau_private *dev_priv = - (struct drm_nouveau_private *)dev->dev_private; - struct nouveau_fifo *chan = dev_priv->fifos[channel]; + struct drm_device *dev = chan->dev; + struct drm_nouveau_private *dev_priv = dev->dev_private; void (*ctx_init)(struct drm_device *, struct nouveau_gpuobj *); unsigned int ctx_size; int ret; @@ -1272,7 +1271,7 @@ nv40_graph_create_context(struct drm_device *dev, int channel) break; } - if ((ret = nouveau_gpuobj_new_ref(dev, channel, -1, 0, ctx_size, 16, + if ((ret = nouveau_gpuobj_new_ref(dev, chan, NULL, 0, ctx_size, 16, NVOBJ_FLAG_ZERO_ALLOC, &chan->ramin_grctx))) return ret; @@ -1284,13 +1283,9 @@ nv40_graph_create_context(struct drm_device *dev, int channel) } void -nv40_graph_destroy_context(struct drm_device *dev, int channel) +nv40_graph_destroy_context(struct nouveau_channel *chan) { - struct drm_nouveau_private *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); + nouveau_gpuobj_ref_del(chan->dev, &chan->ramin_grctx); } static int @@ -1327,10 +1322,9 @@ nv40_graph_transfer_context(struct drm_device *dev, uint32_t inst, int save) *XXX: fails sometimes, not sure why.. */ int -nv40_graph_save_context(struct drm_device *dev, int channel) +nv40_graph_save_context(struct nouveau_channel *chan) { - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_fifo *chan = dev_priv->fifos[channel]; + struct drm_device *dev = chan->dev; uint32_t inst; if (!chan->ramin_grctx) @@ -1344,10 +1338,10 @@ nv40_graph_save_context(struct drm_device *dev, int channel) * XXX: fails sometimes.. not sure why */ int -nv40_graph_load_context(struct drm_device *dev, int channel) +nv40_graph_load_context(struct nouveau_channel *chan) { + struct drm_device *dev = chan->dev; struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_fifo *chan = dev_priv->fifos[channel]; uint32_t inst; int ret; @@ -1642,8 +1636,8 @@ nv40_graph_init(struct drm_device *dev) /* No context present currently */ NV_WRITE(NV40_PGRAPH_CTXCTL_CUR, 0x00000000); - NV_WRITE(NV03_PGRAPH_INTR_EN, 0x00000000); NV_WRITE(NV03_PGRAPH_INTR , 0xFFFFFFFF); + NV_WRITE(NV40_PGRAPH_INTR_EN, 0xFFFFFFFF); NV_WRITE(NV04_PGRAPH_DEBUG_0, 0xFFFFFFFF); NV_WRITE(NV04_PGRAPH_DEBUG_0, 0x00000000); diff --git a/shared-core/nv40_mc.c b/shared-core/nv40_mc.c index 8bb6b083..c7db9023 100644 --- a/shared-core/nv40_mc.c +++ b/shared-core/nv40_mc.c @@ -14,8 +14,6 @@ nv40_mc_init(struct drm_device *dev) */ NV_WRITE(NV03_PMC_ENABLE, 0xFFFFFFFF); - NV_WRITE(NV03_PMC_INTR_EN_0, 0); - switch (dev_priv->chipset) { case 0x44: case 0x46: /* G72 */ diff --git a/shared-core/nv50_fifo.c b/shared-core/nv50_fifo.c index f7b98220..71b89d6d 100644 --- a/shared-core/nv50_fifo.c +++ b/shared-core/nv50_fifo.c @@ -30,7 +30,6 @@ typedef struct { struct nouveau_gpuobj_ref *thingo; - struct nouveau_gpuobj_ref *dummyctx; } nv50_fifo_priv; #define IS_G80 ((dev_priv->chipset & 0xf0) == 0x50) @@ -47,7 +46,7 @@ nv50_fifo_init_thingo(struct drm_device *dev) INSTANCE_WR(thingo->gpuobj, 0, 0x7e); INSTANCE_WR(thingo->gpuobj, 1, 0x7e); - for (i = 0; i <NV_MAX_FIFO_NUMBER; i++, fi) { + for (i = 1; i < 127; i++, fi) { if (dev_priv->fifos[i]) { INSTANCE_WR(thingo->gpuobj, fi, i); fi++; @@ -60,10 +59,10 @@ nv50_fifo_init_thingo(struct drm_device *dev) } static int -nv50_fifo_channel_enable(struct drm_device *dev, int channel) +nv50_fifo_channel_enable(struct drm_device *dev, int channel, int nt) { struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_fifo *chan = dev_priv->fifos[channel]; + struct nouveau_channel *chan = dev_priv->fifos[channel]; DRM_DEBUG("ch%d\n", channel); @@ -83,7 +82,7 @@ nv50_fifo_channel_enable(struct drm_device *dev, int channel) NV50_PFIFO_CTX_TABLE_CHANNEL_ENABLED); } - nv50_fifo_init_thingo(dev); + if (!nt) nv50_fifo_init_thingo(dev); return 0; } @@ -120,6 +119,17 @@ nv50_fifo_init_reset(struct drm_device *dev) } static void +nv50_fifo_init_intr(struct drm_device *dev) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + + DRM_DEBUG("\n"); + + NV_WRITE(NV03_PFIFO_INTR_0, 0xFFFFFFFF); + NV_WRITE(NV03_PFIFO_INTR_EN_0, 0xFFFFFFFF); +} + +static void nv50_fifo_init_context_table(struct drm_device *dev) { int i; @@ -145,18 +155,9 @@ static int nv50_fifo_init_regs(struct drm_device *dev) { struct drm_nouveau_private *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); @@ -164,13 +165,9 @@ nv50_fifo_init_regs(struct drm_device *dev) 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)); - } + /* Enable dummy channels setup by nv50_instmem.c */ + nv50_fifo_channel_enable(dev, 0, 1); + nv50_fifo_channel_enable(dev, 127, 1); return 0; } @@ -190,13 +187,15 @@ nv50_fifo_init(struct drm_device *dev) dev_priv->Engine.fifo.priv = priv; nv50_fifo_init_reset(dev); + nv50_fifo_init_intr(dev); - if ((ret = nouveau_gpuobj_new_ref(dev, -1, -1, 0, (128+2)*4, 0x1000, + if ((ret = nouveau_gpuobj_new_ref(dev, NULL, NULL, 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); @@ -218,31 +217,30 @@ nv50_fifo_takedown(struct drm_device *dev) 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(struct drm_device *dev, int channel) +nv50_fifo_create_context(struct nouveau_channel *chan) { + struct drm_device *dev = chan->dev; struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_fifo *chan = dev_priv->fifos[channel]; struct nouveau_gpuobj *ramfc = NULL; int ret; - DRM_DEBUG("ch%d\n", channel); + DRM_DEBUG("ch%d\n", chan->id); if (IS_G80) { uint32_t ramfc_offset = chan->ramin->gpuobj->im_pramin->start; - if ((ret = nouveau_gpuobj_new_fake(dev, ramfc_offset, 0x100, + if ((ret = nouveau_gpuobj_new_fake(dev, ramfc_offset, ~0, 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, + if ((ret = nouveau_gpuobj_new_ref(dev, chan, NULL, 0, 0x100, 256, NVOBJ_FLAG_ZERO_ALLOC | NVOBJ_FLAG_ZERO_FREE, @@ -266,15 +264,15 @@ nv50_fifo_create_context(struct drm_device *dev, int channel) INSTANCE_WR(ramfc, 0x4c/4, chan->pushbuf_mem->size - 1); if (!IS_G80) { - INSTANCE_WR(chan->ramin->gpuobj, 0, channel); + INSTANCE_WR(chan->ramin->gpuobj, 0, chan->id); 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); + if ((ret = nv50_fifo_channel_enable(dev, chan->id, 0))) { + DRM_ERROR("error enabling ch%d: %d\n", chan->id, ret); nouveau_gpuobj_ref_del(dev, &chan->ramfc); return ret; } @@ -283,25 +281,29 @@ nv50_fifo_create_context(struct drm_device *dev, int channel) } void -nv50_fifo_destroy_context(struct drm_device *dev, int channel) +nv50_fifo_destroy_context(struct nouveau_channel *chan) { - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_fifo *chan = dev_priv->fifos[channel]; + struct drm_device *dev = chan->dev; - DRM_DEBUG("ch%d\n", channel); + DRM_DEBUG("ch%d\n", chan->id); + + nv50_fifo_channel_disable(dev, chan->id, 0); + + /* Dummy channel, also used on ch 127 */ + if (chan->id == 0) + nv50_fifo_channel_disable(dev, 127, 0); - nv50_fifo_channel_disable(dev, channel, 0); nouveau_gpuobj_ref_del(dev, &chan->ramfc); } int -nv50_fifo_load_context(struct drm_device *dev, int channel) +nv50_fifo_load_context(struct nouveau_channel *chan) { + struct drm_device *dev = chan->dev; struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_fifo *chan = dev_priv->fifos[channel]; struct nouveau_gpuobj *ramfc = chan->ramfc->gpuobj; - DRM_DEBUG("ch%d\n", channel); + DRM_DEBUG("ch%d\n", chan->id); /*XXX: incomplete, only touches the regs that NV does */ @@ -319,14 +321,14 @@ nv50_fifo_load_context(struct drm_device *dev, int channel) NV_WRITE(0x3410, INSTANCE_RD(ramfc, 0x98/4)); } - NV_WRITE(NV03_PFIFO_CACHE1_PUSH1, channel | (1<<16)); + NV_WRITE(NV03_PFIFO_CACHE1_PUSH1, chan->id | (1<<16)); return 0; } int -nv50_fifo_save_context(struct drm_device *dev, int channel) +nv50_fifo_save_context(struct nouveau_channel *chan) { - DRM_DEBUG("ch%d\n", channel); + DRM_DEBUG("ch%d\n", chan->id); DRM_ERROR("stub!\n"); return 0; } diff --git a/shared-core/nv50_graph.c b/shared-core/nv50_graph.c index 8df5df25..e5bbf65e 100644 --- a/shared-core/nv50_graph.c +++ b/shared-core/nv50_graph.c @@ -45,6 +45,16 @@ nv50_graph_init_reset(struct drm_device *dev) } static void +nv50_graph_init_intr(struct drm_device *dev) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + + DRM_DEBUG("\n"); + NV_WRITE(NV03_PGRAPH_INTR, 0xffffffff); + NV_WRITE(NV40_PGRAPH_INTR_EN, 0xffffffff); +} + +static void nv50_graph_init_regs__nv(struct drm_device *dev) { struct drm_nouveau_private *dev_priv = dev->dev_private; @@ -59,7 +69,6 @@ nv50_graph_init_regs__nv(struct drm_device *dev) NV_WRITE(0x402000, 0xc0000000); NV_WRITE(0x400108, 0xffffffff); - NV_WRITE(0x400100, 0xffffffff); NV_WRITE(0x400824, 0x00004000); NV_WRITE(0x400500, 0x00010001); @@ -174,6 +183,7 @@ nv50_graph_init(struct drm_device *dev) DRM_DEBUG("\n"); nv50_graph_init_reset(dev); + nv50_graph_init_intr(dev); nv50_graph_init_regs__nv(dev); nv50_graph_init_regs(dev); nv50_graph_init_ctxctl(dev); @@ -188,17 +198,18 @@ nv50_graph_takedown(struct drm_device *dev) } int -nv50_graph_create_context(struct drm_device *dev, int channel) +nv50_graph_create_context(struct nouveau_channel *chan) { + struct drm_device *dev = chan->dev; struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_fifo *chan = dev_priv->fifos[channel]; + struct nouveau_engine *engine = &dev_priv->Engine; struct nouveau_gpuobj *ramin = chan->ramin->gpuobj; int grctx_size = 0x60000, hdr; int ret; - DRM_DEBUG("ch%d\n", channel); + DRM_DEBUG("ch%d\n", chan->id); - if ((ret = nouveau_gpuobj_new_ref(dev, channel, -1, 0, + if ((ret = nouveau_gpuobj_new_ref(dev, chan, NULL, 0, grctx_size, 0x1000, NVOBJ_FLAG_ZERO_ALLOC | NVOBJ_FLAG_ZERO_FREE, @@ -214,17 +225,22 @@ nv50_graph_create_context(struct drm_device *dev, int channel) INSTANCE_WR(ramin, (hdr + 0x10)/4, 0); INSTANCE_WR(ramin, (hdr + 0x14)/4, 0x00010000); + if ((ret = engine->graph.load_context(chan))) { + DRM_ERROR("Error hacking up initial context: %d\n", ret); + return ret; + } + return 0; } void -nv50_graph_destroy_context(struct drm_device *dev, int channel) +nv50_graph_destroy_context(struct nouveau_channel *chan) { + struct drm_device *dev = chan->dev; struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_fifo *chan = dev_priv->fifos[channel]; int i, hdr; - DRM_DEBUG("ch%d\n", channel); + DRM_DEBUG("ch%d\n", chan->id); hdr = IS_G80 ? 0x200 : 0x20; for (i=hdr; i<hdr+24; i+=4) @@ -266,14 +282,14 @@ nv50_graph_transfer_context(struct drm_device *dev, uint32_t inst, int save) } int -nv50_graph_load_context(struct drm_device *dev, int channel) +nv50_graph_load_context(struct nouveau_channel *chan) { + struct drm_device *dev = chan->dev; struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_fifo *chan = dev_priv->fifos[channel]; uint32_t inst = ((chan->ramin->instance >> 12) | (1<<31)); int ret; (void)ret; - DRM_DEBUG("ch%d\n", channel); + DRM_DEBUG("ch%d\n", chan->id); #if 0 if ((ret = nv50_graph_transfer_context(dev, inst, 0))) @@ -288,13 +304,12 @@ nv50_graph_load_context(struct drm_device *dev, int channel) } int -nv50_graph_save_context(struct drm_device *dev, int channel) +nv50_graph_save_context(struct nouveau_channel *chan) { - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_fifo *chan = dev_priv->fifos[channel]; + struct drm_device *dev = chan->dev; uint32_t inst = ((chan->ramin->instance >> 12) | (1<<31)); - DRM_DEBUG("ch%d\n", channel); + DRM_DEBUG("ch%d\n", chan->id); return nv50_graph_transfer_context(dev, inst, 1); } diff --git a/shared-core/nv50_instmem.c b/shared-core/nv50_instmem.c index c26b1db5..1eeb54df 100644 --- a/shared-core/nv50_instmem.c +++ b/shared-core/nv50_instmem.c @@ -31,118 +31,162 @@ typedef struct { uint32_t save1700[5]; /* 0x1700->0x1710 */ + + struct nouveau_gpuobj_ref *pramin_pt; + struct nouveau_gpuobj_ref *pramin_bar; } 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) +/*NOTE: - Assumes 0x1700 already covers the correct MiB of PRAMIN + */ +#define BAR0_WI32(g,o,v) do { \ + uint32_t offset; \ + if ((g)->im_backing) { \ + offset = (g)->im_backing->start; \ + } else { \ + offset = chan->ramin->gpuobj->im_backing->start; \ + offset += (g)->im_pramin->start; \ + } \ + offset += (o); \ + NV_WRITE(NV_RAMIN + (offset & 0xfffff), (v)); \ +} while(0) + int nv50_instmem_init(struct drm_device *dev) { struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_channel *chan; + uint32_t c_offset, c_size, c_ramfc, c_vmpd, c_base, pt_size; nv50_instmem_priv *priv; - uint32_t rv, pt, pts, cb, cb0, cb1, unk, as; - uint32_t i, v; - int ret; + int ret, i; + uint32_t v; priv = drm_calloc(1, sizeof(*priv), DRM_MEM_DRIVER); if (!priv) return -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. + /* Reserve the last MiB of VRAM, we should probably try to avoid + * setting up the below tables over the top of the VBIOS image at + * some point. */ - 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); - } + dev_priv->ramin_rsvd_vram = 1 << 20; + c_offset = nouveau_mem_fb_amount(dev) - dev_priv->ramin_rsvd_vram; + c_size = 128 << 10; + c_vmpd = ((dev_priv->chipset & 0xf0) == 0x50) ? 0x1400 : 0x200; + c_ramfc = ((dev_priv->chipset & 0xf0) == 0x50) ? 0x0 : 0x20; + c_base = c_vmpd + 0x4000; + pt_size = NV50_INSTMEM_PT_SIZE(dev_priv->ramin->size); + + DRM_DEBUG(" Rsvd VRAM base: 0x%08x\n", c_offset); + DRM_DEBUG(" VBIOS image: 0x%08x\n", (NV_READ(0x619f04)&~0xff)<<8); + DRM_DEBUG(" Aperture size: %d MiB\n", + (uint32_t)dev_priv->ramin->size >> 20); + DRM_DEBUG(" PT size: %d KiB\n", pt_size >> 10); + + NV_WRITE(NV50_PUNK_BAR0_PRAMIN, (c_offset >> 16)); + + /* Create a fake channel, and use it as our "dummy" channels 0/127. + * The main reason for creating a channel is so we can use the gpuobj + * code. However, it's probably worth noting that NVIDIA also setup + * their channels 0/127 with the same values they configure here. + * So, there may be some other reason for doing this. + * + * Have to create the entire channel manually, as the real channel + * creation code assumes we have PRAMIN access, and we don't until + * we're done here. + */ + chan = drm_calloc(1, sizeof(*chan), DRM_MEM_DRIVER); + if (!chan) + return -ENOMEM; + chan->id = 0; + chan->dev = dev; + chan->file_priv = (struct drm_file *)-2; + dev_priv->fifos[0] = dev_priv->fifos[127] = chan; - /* 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); - } + /* Channel's PRAMIN object + heap */ + if ((ret = nouveau_gpuobj_new_fake(dev, 0, c_offset, 128<<10, 0, + NULL, &chan->ramin))) + return ret; - /* Points at CB0 */ - NV_WRITE(0x170c, (((cb0 - cb)>>4)|(1<<31))); + if (nouveau_mem_init_heap(&chan->ramin_heap, c_base, c_size - c_base)) + return -ENOMEM; + + /* RAMFC + zero channel's PRAMIN up to start of VM pagedir */ + if ((ret = nouveau_gpuobj_new_fake(dev, c_ramfc, c_offset + c_ramfc, + 0x4000, 0, NULL, &chan->ramfc))) + return ret; + + for (i = 0; i < c_vmpd; i += 4) + BAR0_WI32(chan->ramin->gpuobj, i, 0); + + /* VM page directory */ + if ((ret = nouveau_gpuobj_new_fake(dev, c_vmpd, c_offset + c_vmpd, + 0x4000, 0, &chan->vm_pd, NULL))) + return ret; + for (i = 0; i < 0x4000; i += 8) { + BAR0_WI32(chan->vm_pd, i + 0x00, 0x00000000); + BAR0_WI32(chan->vm_pd, i + 0x04, 0x00000000); + } - /* Confirm it all worked, should be able to read back the page table's - * PTEs from the PRAMIN BAR + /* PRAMIN page table, cheat and map into VM at 0x0000000000. + * We map the entire fake channel into the start of 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 -EINVAL; + if ((ret = nouveau_gpuobj_new_ref(dev, chan, NULL, 0, pt_size, 0x1000, + 0, &priv->pramin_pt))) + return ret; + + for (i = 0, v = c_offset; i < pt_size; i+=8, v+=0x1000) { + if (v < (c_offset + c_size)) + BAR0_WI32(priv->pramin_pt->gpuobj, i + 0, v | 1); + else + BAR0_WI32(priv->pramin_pt->gpuobj, i + 0, 0x00000009); + BAR0_WI32(priv->pramin_pt->gpuobj, i + 4, 0x00000000); } - /* 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 -ENOMEM; + BAR0_WI32(chan->vm_pd, 0x00, priv->pramin_pt->instance | 0x63); + BAR0_WI32(chan->vm_pd, 0x04, 0x00000000); + + /* DMA object for PRAMIN BAR */ + if ((ret = nouveau_gpuobj_new_ref(dev, chan, chan, 0, 6*4, 16, 0, + &priv->pramin_bar))) + return ret; + BAR0_WI32(priv->pramin_bar->gpuobj, 0x00, 0x7fc00000); + BAR0_WI32(priv->pramin_bar->gpuobj, 0x04, dev_priv->ramin->size - 1); + BAR0_WI32(priv->pramin_bar->gpuobj, 0x08, 0x00000000); + BAR0_WI32(priv->pramin_bar->gpuobj, 0x0c, 0x00000000); + BAR0_WI32(priv->pramin_bar->gpuobj, 0x10, 0x00000000); + BAR0_WI32(priv->pramin_bar->gpuobj, 0x14, 0x00000000); + + /* Poke the relevant regs, and pray it works :) */ + NV_WRITE(NV50_PUNK_BAR_CFG_BASE, (chan->ramin->instance >> 12)); + NV_WRITE(NV50_PUNK_UNK1710, 0); + NV_WRITE(NV50_PUNK_BAR_CFG_BASE, (chan->ramin->instance >> 12) | + NV50_PUNK_BAR_CFG_BASE_VALID); + NV_WRITE(NV50_PUNK_BAR1_CTXDMA, 0); + NV_WRITE(NV50_PUNK_BAR3_CTXDMA, (priv->pramin_bar->instance >> 4) | + NV50_PUNK_BAR3_CTXDMA_VALID); + + /* Assume that praying isn't enough, check that we can re-read the + * entire fake channel back from the PRAMIN BAR */ + for (i = 0; i < c_size; i+=4) { + if (NV_READ(NV_RAMIN + i) != NV_RI32(i)) { + DRM_ERROR("Error reading back PRAMIN at 0x%08x\n", i); + return -EINVAL; + } } - 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; + /* Global PRAMIN heap */ + if (nouveau_mem_init_heap(&dev_priv->ramin_heap, + c_size, dev_priv->ramin->size - c_size)) { + dev_priv->ramin_heap = NULL; + DRM_ERROR("Failed to init RAMIN heap\n"); + } - /*XXX: probably incorrect, but needed to make hash func "work" */ + /*XXX: 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); @@ -154,8 +198,11 @@ nv50_instmem_takedown(struct drm_device *dev) { struct drm_nouveau_private *dev_priv = dev->dev_private; nv50_instmem_priv *priv = dev_priv->Engine.instmem.priv; + struct nouveau_channel *chan = dev_priv->fifos[0]; int i; + DRM_DEBUG("\n"); + if (!priv) return; @@ -163,6 +210,20 @@ nv50_instmem_takedown(struct drm_device *dev) for (i = 0x1700; i <= 0x1710; i+=4) NV_WRITE(i, priv->save1700[(i-0x1700)/4]); + nouveau_gpuobj_ref_del(dev, &priv->pramin_bar); + nouveau_gpuobj_ref_del(dev, &priv->pramin_pt); + + /* Destroy dummy channel */ + if (chan) { + nouveau_gpuobj_del(dev, &chan->vm_pd); + nouveau_gpuobj_ref_del(dev, &chan->ramfc); + nouveau_gpuobj_ref_del(dev, &chan->ramin); + nouveau_mem_takedown(&chan->ramin_heap); + + dev_priv->fifos[0] = dev_priv->fifos[127] = NULL; + drm_free(chan, sizeof(*chan), DRM_MEM_DRIVER); + } + dev_priv->Engine.instmem.priv = NULL; drm_free(priv, sizeof(*priv), DRM_MEM_DRIVER); } @@ -205,6 +266,7 @@ int nv50_instmem_bind(struct drm_device *dev, struct nouveau_gpuobj *gpuobj) { struct drm_nouveau_private *dev_priv = dev->dev_private; + nv50_instmem_priv *priv = dev_priv->Engine.instmem.priv; uint32_t pte, pte_end, vram; if (!gpuobj->im_backing || !gpuobj->im_pramin || gpuobj->im_bound) @@ -217,19 +279,14 @@ nv50_instmem_bind(struct drm_device *dev, struct nouveau_gpuobj *gpuobj) 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); + INSTANCE_WR(priv->pramin_pt->gpuobj, (pte + 0)/4, vram | 1); + INSTANCE_WR(priv->pramin_pt->gpuobj, (pte + 4)/4, 0x00000000); pte += 8; vram += NV50_INSTMEM_PAGE_SIZE; @@ -243,6 +300,7 @@ int nv50_instmem_unbind(struct drm_device *dev, struct nouveau_gpuobj *gpuobj) { struct drm_nouveau_private *dev_priv = dev->dev_private; + nv50_instmem_priv *priv = dev_priv->Engine.instmem.priv; uint32_t pte, pte_end; if (gpuobj->im_bound == 0) @@ -251,8 +309,8 @@ nv50_instmem_unbind(struct drm_device *dev, struct nouveau_gpuobj *gpuobj) 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); + INSTANCE_WR(priv->pramin_pt->gpuobj, (pte + 0)/4, 0x00000009); + INSTANCE_WR(priv->pramin_pt->gpuobj, (pte + 4)/4, 0x00000000); pte += 8; } diff --git a/shared-core/nv50_mc.c b/shared-core/nv50_mc.c index 952dea9f..b111826b 100644 --- a/shared-core/nv50_mc.c +++ b/shared-core/nv50_mc.c @@ -34,6 +34,7 @@ nv50_mc_init(struct drm_device *dev) struct drm_nouveau_private *dev_priv = dev->dev_private; NV_WRITE(NV03_PMC_ENABLE, 0xFFFFFFFF); + return 0; } |