summaryrefslogtreecommitdiff
path: root/shared-core/nouveau_fifo.c
diff options
context:
space:
mode:
authorStephane Marchesin <marchesin@icps.u-strasbg.fr>2006-10-11 00:28:15 +0200
committerStephane Marchesin <marchesin@icps.u-strasbg.fr>2006-10-11 00:28:15 +0200
commitdd473411f889cc16af255437d2a61c616bcee695 (patch)
treeaf9cdf98624146b41bc8edc1856299fe1909d1b1 /shared-core/nouveau_fifo.c
parent22382bd8c540231641bfc75d778a50ddf1463783 (diff)
Context switching work.
Added preliminary support for context switches (triggers the interrupts, but hangs after the switch ; something's not quite right yet). Removed the PFIFO_REINIT ioctl. I hope it's that a good idea... Requires the upcoming commit to the DDX.
Diffstat (limited to 'shared-core/nouveau_fifo.c')
-rw-r--r--shared-core/nouveau_fifo.c308
1 files changed, 198 insertions, 110 deletions
diff --git a/shared-core/nouveau_fifo.c b/shared-core/nouveau_fifo.c
index ca7ddef6..de23f96d 100644
--- a/shared-core/nouveau_fifo.c
+++ b/shared-core/nouveau_fifo.c
@@ -44,23 +44,6 @@ int nouveau_fifo_number(drm_device_t* dev)
}
}
-/* setup the fifo enable register */
-static void nouveau_fifo_enable(drm_device_t* dev)
-{
- int i;
- unsigned enable_val=0;
- drm_nouveau_private_t *dev_priv = dev->dev_private;
-
- for(i=31;i>=0;i--)
- {
- enable_val<<=1;
- if (dev_priv->fifos[i].used)
- enable_val|=1;
- }
- DRM_DEBUG("enable_val=0x%08x\n", enable_val);
- NV_WRITE(NV03_FIFO_ENABLE,enable_val);
-}
-
/***********************************
* functions doing the actual work
***********************************/
@@ -70,12 +53,141 @@ static void nouveau_fifo_enable(drm_device_t* dev)
* voir nv_driver.c : NVPreInit
*/
-/* initializes a fifo */
-static int nouveau_fifo_init(drm_device_t* dev,drm_nouveau_fifo_init_t* init, DRMFILE filp)
+static void nouveau_fifo_init(drm_device_t* dev)
+{
+ drm_nouveau_private_t *dev_priv = dev->dev_private;
+
+ /* Init PFIFO - This is an exact copy of what's done in the Xorg ddx so far.
+ * We should be able to figure out what's happening from the
+ * resources available..
+ */
+
+ if (dev->irq_enabled)
+ nouveau_irq_postinstall(dev);
+
+ if (dev_priv->card_type >= NV_40)
+ NV_WRITE(NV_PGRAPH_NV40_UNK220, dev_priv->fb_obj->instance >> 4);
+
+ DRM_DEBUG("%s: setting FIFO %d active\n", __func__, dev_priv->cur_fifo);
+
+ NV_WRITE(NV_PFIFO_CACHES, 0x00000000);
+ NV_WRITE(NV_PFIFO_MODE, 0x00000000);
+
+ NV_WRITE(NV_PFIFO_CACH1_PSH0, 0x00000000);
+ NV_WRITE(NV_PFIFO_CACH1_PUL0, 0x00000000);
+ if (dev_priv->card_type >= NV_40)
+ NV_WRITE(NV_PFIFO_CACH1_PSH1, 0x00010000|dev_priv->cur_fifo);
+ else
+ NV_WRITE(NV_PFIFO_CACH1_PSH1, 0x00000100|dev_priv->cur_fifo);
+ NV_WRITE(NV_PFIFO_CACH1_DMAP, dev_priv->cur_fifo * dev_priv->cmdbuf_ch_size);
+ NV_WRITE(NV_PFIFO_CACH1_DMAG, dev_priv->cur_fifo * dev_priv->cmdbuf_ch_size);
+ NV_WRITE(NV_PFIFO_CACH1_DMAI, dev_priv->cmdbuf_obj->instance >> 4);
+ NV_WRITE(NV_PFIFO_CACH0_PSH0, 0x00000000);
+ NV_WRITE(NV_PFIFO_CACH0_PUL0, 0x00000000);
+ NV_WRITE(NV_PFIFO_SIZE , 0x0000FFFF);
+ NV_WRITE(NV_PFIFO_CACH1_HASH, 0x0000FFFF);
+ NV_WRITE(NV_PFIFO_RAMHT,
+ (0x03 << 24) /* search 128 */ |
+ ((dev_priv->objs.ht_bits - 9) << 16) |
+ (dev_priv->objs.ht_base >> 8)
+ );
+ dev_priv->ramfc_offset=0x11000;
+ dev_priv->ramro_offset=0x11200;
+ NV_WRITE(NV_PFIFO_RAMFC, dev_priv->ramfc_offset>>8); /* RAMIN+0x11000 0.5k */
+ NV_WRITE(NV_PFIFO_RAMRO, dev_priv->ramro_offset>>8); /* RAMIN+0x11200 0.5k */
+ NV_WRITE(NV_PFIFO_CACH0_PUL1, 0x00000001);
+ NV_WRITE(NV_PFIFO_CACH1_DMAC, 0x00000000);
+ NV_WRITE(NV_PFIFO_CACH1_DMAS, 0x00000000);
+ NV_WRITE(NV_PFIFO_CACH1_ENG, 0x00000000);
+#ifdef __BIG_ENDIAN
+ NV_WRITE(NV_PFIFO_CACH1_DMAF, NV_PFIFO_CACH1_DMAF_TRIG_112_BYTES|NV_PFIFO_CACH1_DMAF_SIZE_128_BYTES|NV_PFIFO_CACH1_DMAF_MAX_REQS_4|NV_PFIFO_CACH1_BIG_ENDIAN);
+#else
+ NV_WRITE(NV_PFIFO_CACH1_DMAF, NV_PFIFO_CACH1_DMAF_TRIG_112_BYTES|NV_PFIFO_CACH1_DMAF_SIZE_128_BYTES|NV_PFIFO_CACH1_DMAF_MAX_REQS_4);
+#endif
+ NV_WRITE(NV_PFIFO_CACH1_DMAPSH, 0x00000001);
+ NV_WRITE(NV_PFIFO_CACH1_PSH0, 0x00000001);
+ NV_WRITE(NV_PFIFO_CACH1_PUL0, 0x00000001);
+ NV_WRITE(NV_PFIFO_CACH1_PUL1, 0x00000001);
+
+ NV_WRITE(NV_PGRAPH_CTX_USER, 0x0);
+ NV_WRITE(NV_PGRAPH_CTX_SWITCH1, 0x19);
+ NV_WRITE(NV_PFIFO_DELAY_0, 0xff /* retrycount*/ );
+ if (dev_priv->card_type >= NV_40)
+ NV_WRITE(NV_PGRAPH_CTX_CONTROL, 0x00002001);
+ else
+ NV_WRITE(NV_PGRAPH_CTX_CONTROL, 0x10110000);
+
+ NV_WRITE(NV_PFIFO_DMA_TIMESLICE, 0x001fffff);
+ NV_WRITE(NV_PFIFO_CACHES, 0x00000001);
+
+ DRM_DEBUG("%s: CACHE1 GET/PUT readback %d/%d\n", __func__,
+ NV_READ(NV_PFIFO_CACH1_DMAG),
+ NV_READ(NV_PFIFO_CACH1_DMAP));
+
+ DRM_INFO("%s: OK\n", __func__);
+}
+
+static int nouveau_dma_init(struct drm_device *dev)
+{
+ drm_nouveau_private_t *dev_priv = dev->dev_private;
+ struct nouveau_config *config = &dev_priv->config;
+ struct mem_block *cb;
+ int cb_min_size = nouveau_fifo_number(dev) * NV03_FIFO_SIZE;
+
+ /* XXX this should be done earlier on init */
+ nouveau_hash_table_init(dev);
+
+ if (dev_priv->card_type >= NV_40)
+ dev_priv->fb_obj = nouveau_dma_object_create(dev,
+ 0, nouveau_mem_fb_amount(dev),
+ NV_DMA_ACCESS_RW, NV_DMA_TARGET_VIDMEM);
+
+ /* 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, (DRMFILE)-2);
+ /* Try defaults if that didn't succeed */
+ if (!cb) {
+ config->cmdbuf.location = NOUVEAU_MEM_FB;
+ config->cmdbuf.size = cb_min_size;
+ cb = nouveau_mem_alloc(dev, 0, config->cmdbuf.size,
+ config->cmdbuf.location, (DRMFILE)-2);
+ }
+ if (!cb) {
+ DRM_ERROR("Couldn't allocate DMA command buffer.\n");
+ return DRM_ERR(ENOMEM);
+ }
+
+ if (config->cmdbuf.location == NOUVEAU_MEM_AGP)
+ dev_priv->cmdbuf_obj = nouveau_dma_object_create(dev,
+ cb->start, cb->size, NV_DMA_ACCESS_RO, NV_DMA_TARGET_AGP);
+ else
+ dev_priv->cmdbuf_obj = nouveau_dma_object_create(dev,
+ cb->start - drm_get_resource_start(dev, 1),
+ cb->size, NV_DMA_ACCESS_RO, NV_DMA_TARGET_VIDMEM);
+ dev_priv->cmdbuf_ch_size = (uint32_t)cb->size / nouveau_fifo_number(dev);
+ dev_priv->cmdbuf_alloc = cb;
+
+ nouveau_fifo_init(dev);
+ DRM_INFO("DMA command buffer is %dKiB at 0x%08x(%s)\n",
+ (uint32_t)cb->size>>10, (uint32_t)cb->start,
+ config->cmdbuf.location == NOUVEAU_MEM_FB ? "VRAM" : "AGP");
+ DRM_INFO("FIFO size is %dKiB\n", dev_priv->cmdbuf_ch_size>>10);
+
+ return 0;
+}
+
+/* allocates and initializes a fifo for user space consumption */
+static int nouveau_fifo_alloc(drm_device_t* dev,drm_nouveau_fifo_alloc_t* init, DRMFILE filp)
{
int i;
int ret;
drm_nouveau_private_t *dev_priv = dev->dev_private;
+ uint32_t ctx_addr;
/* Init cmdbuf on first FIFO init, this is delayed until now to
* give the ddx a chance to configure the cmdbuf with SETPARAM
@@ -90,18 +202,15 @@ static int nouveau_fifo_init(drm_device_t* dev,drm_nouveau_fifo_init_t* init, DR
* Alright, here is the full story
* Nvidia cards have multiple hw fifo contexts (praise them for that,
* no complicated crash-prone context switches)
- * X always uses context 0 (0x00800000)
* We allocate a new context for each app and let it write to it directly
* (woo, full userspace command submission !)
* When there are no more contexts, you lost
*/
for(i=0;i<nouveau_fifo_number(dev);i++)
if (dev_priv->fifos[i].used==0)
- {
- dev_priv->fifos[i].used=1;
break;
- }
+ DRM_INFO("Allocating FIFO number %d\n", i);
/* no more fifos. you lost. */
if (i==nouveau_fifo_number(dev))
return DRM_ERR(EINVAL);
@@ -110,16 +219,49 @@ static int nouveau_fifo_init(drm_device_t* dev,drm_nouveau_fifo_init_t* init, DR
dev_priv->fifos[i].used=1;
dev_priv->fifos[i].filp=filp;
- /* enable the fifo */
- nouveau_fifo_enable(dev);
+ nouveau_wait_for_idle(dev);
+
+ /* disable the fifo caches */
+ NV_WRITE(NV_PFIFO_CACHES, 0x00000000);
+
+ // FIXME i*32 is true on nv04, what is it on >=nv10 ?
+ ctx_addr=NV_RAMIN+dev_priv->ramfc_offset+i*32;
+
+ // clear the first 2 RAMFC entries
+ // FIXME try to fill GET/PUT and see what that changes
+ NV_WRITE(ctx_addr,0x0);
+ NV_WRITE(ctx_addr+4,0x0);
+
+ // FIXME that's what is done in nvosdk, but that part of the code is buggy so...
+ // RAMFC + 8 = instoffset
+ NV_WRITE(ctx_addr+8,dev_priv->cmdbuf_obj->instance >> 4);
+
+ // RAMFC + 16 = defaultFetch
+ NV_WRITE(ctx_addr+16,NV_PFIFO_CACH1_DMAF_TRIG_112_BYTES|NV_PFIFO_CACH1_DMAF_SIZE_128_BYTES|NV_PFIFO_CACH1_DMAF_MAX_REQS_4);
+
+ /* enable the fifo dma operation */
+ NV_WRITE(NV_PFIFO_MODE,NV_READ(NV_PFIFO_MODE)|(1<<i));
+
+ // FIXME check if we need to refill the time quota with something like NV_WRITE(0x204C, 0x0003FFFF);
+
+ dev_priv->cur_fifo=i;
+ if (dev_priv->card_type >= NV_40)
+ NV_WRITE(NV_PFIFO_CACH1_PSH1, 0x00010000|dev_priv->cur_fifo);
+ else
+ NV_WRITE(NV_PFIFO_CACH1_PSH1, 0x00000100|dev_priv->cur_fifo);
- /* make the fifo available to user space */
init->channel = i;
init->put_base = i*dev_priv->cmdbuf_ch_size;
NV_WRITE(NV03_FIFO_REGS_DMAPUT(i), init->put_base);
NV_WRITE(NV03_FIFO_REGS_DMAGET(i), init->put_base);
+ NV_WRITE(NV_PFIFO_CACH1_DMAP, init->put_base);
+ NV_WRITE(NV_PFIFO_CACH1_DMAG, init->put_base);
+ /* reenable the fifo caches */
+ NV_WRITE(NV_PFIFO_CACHES, 0x00000001);
+
+ /* make the fifo available to user space */
/* first, the fifo control regs */
init->ctrl = dev_priv->mmio->offset + NV03_FIFO_REGS(i);
init->ctrl_size = NV03_FIFO_REGS_SIZE;
@@ -140,14 +282,29 @@ static int nouveau_fifo_init(drm_device_t* dev,drm_nouveau_fifo_init_t* init, DR
/* FIFO has no objects yet */
dev_priv->fifos[i].objs = NULL;
- DRM_DEBUG("%s: initialised FIFO %d\n", __func__, i);
- dev_priv->cur_fifo = i;
+ DRM_INFO("%s: initialised FIFO %d\n", __func__, i);
return 0;
}
-static void nouveau_pfifo_init(drm_device_t* dev);
+
+/* stops a fifo */
+void nouveau_fifo_free(drm_device_t* dev,int n)
+{
+ drm_nouveau_private_t *dev_priv = dev->dev_private;
+ dev_priv->fifos[n].used=0;
+ DRM_DEBUG("%s: freeing fifo %d\n", __func__, n);
+
+ /* disable the fifo caches */
+ NV_WRITE(NV_PFIFO_CACHES, 0x00000000);
+
+ NV_WRITE(NV_PFIFO_MODE,NV_READ(NV_PFIFO_MODE)&~(1<<n));
+ // FIXME XXX needs more code
+
+ /* reenable the fifo caches */
+ NV_WRITE(NV_PFIFO_CACHES, 0x00000001);
+}
/* cleanups all the fifos from filp */
-void nouveau_fifo_cleanup(drm_device_t * dev, DRMFILE filp)
+void nouveau_fifo_cleanup(drm_device_t* dev, DRMFILE filp)
{
int i;
drm_nouveau_private_t *dev_priv = dev->dev_private;
@@ -155,9 +312,10 @@ void nouveau_fifo_cleanup(drm_device_t * dev, DRMFILE filp)
DRM_DEBUG("clearing FIFO enables from filp\n");
for(i=0;i<nouveau_fifo_number(dev);i++)
if (dev_priv->fifos[i].filp==filp)
- dev_priv->fifos[i].used=0;
+ nouveau_fifo_free(dev,i);
- if (dev_priv->cur_fifo == i) {
+ /* check we still point at an active channel */
+ if (dev_priv->fifos[dev_priv->cur_fifo].used == 0) {
DRM_DEBUG("%s: cur_fifo is no longer owned.\n", __func__);
for (i=0;i<nouveau_fifo_number(dev);i++)
if (dev_priv->fifos[i].used) break;
@@ -167,9 +325,8 @@ void nouveau_fifo_cleanup(drm_device_t * dev, DRMFILE filp)
dev_priv->cur_fifo = i;
}
- if (dev_priv->cmdbuf_alloc)
- nouveau_pfifo_init(dev);
-// nouveau_fifo_enable(dev);
+/* if (dev_priv->cmdbuf_alloc)
+ nouveau_fifo_init(dev);*/
}
int nouveau_fifo_id_get(drm_device_t* dev, DRMFILE filp)
@@ -183,99 +340,30 @@ int nouveau_fifo_id_get(drm_device_t* dev, DRMFILE filp)
return -1;
}
-static void nouveau_pfifo_init(drm_device_t* dev)
-{
- drm_nouveau_private_t *dev_priv = dev->dev_private;
-
- /* Init PFIFO - This is an exact copy of what's done in the Xorg ddx so far.
- * We should be able to figure out what's happening from the
- * resources available..
- */
-
- if (dev->irq_enabled)
- nouveau_irq_postinstall(dev);
-
- if (dev_priv->card_type >= NV_40)
- NV_WRITE(NV_PGRAPH_NV40_UNK220, dev_priv->fb_obj->instance >> 4);
-
- DRM_DEBUG("%s: setting FIFO %d active\n", __func__, dev_priv->cur_fifo);
-
- NV_WRITE(NV_PFIFO_CACHES, 0x00000000);
- nouveau_fifo_enable(dev);
-
- NV_WRITE(NV_PFIFO_CACH1_PSH0, 0x00000000);
- NV_WRITE(NV_PFIFO_CACH1_PUL0, 0x00000000);
- if (dev_priv->card_type >= NV_40)
- NV_WRITE(NV_PFIFO_CACH1_PSH1, 0x00010000|dev_priv->cur_fifo);
- else
- NV_WRITE(NV_PFIFO_CACH1_PSH1, 0x00000100|dev_priv->cur_fifo);
- NV_WRITE(NV_PFIFO_CACH1_DMAP, dev_priv->cur_fifo * dev_priv->cmdbuf_ch_size);
- NV_WRITE(NV_PFIFO_CACH1_DMAG, dev_priv->cur_fifo * dev_priv->cmdbuf_ch_size);
- NV_WRITE(NV_PFIFO_CACH1_DMAI, dev_priv->cmdbuf_obj->instance >> 4);
- NV_WRITE(NV_PFIFO_CACH0_PSH0, 0x00000000);
- NV_WRITE(NV_PFIFO_CACH0_PUL0, 0x00000000);
- NV_WRITE(NV_PFIFO_SIZE , 0x0000FFFF);
- NV_WRITE(NV_PFIFO_CACH1_HASH, 0x0000FFFF);
- NV_WRITE(NV_PFIFO_RAMHT,
- (0x03 << 24) /* search 128 */ |
- ((dev_priv->objs.ht_bits - 9) << 16) |
- (dev_priv->objs.ht_base >> 8)
- );
- NV_WRITE(NV_PFIFO_RAMFC, 0x00000110); /* RAMIN+0x11000 0.5k */
- NV_WRITE(NV_PFIFO_RAMRO, 0x00000112); /* RAMIN+0x11200 0.5k */
- NV_WRITE(NV_PFIFO_CACH0_PUL1, 0x00000001);
- NV_WRITE(NV_PFIFO_CACH1_DMAC, 0x00000000);
- NV_WRITE(NV_PFIFO_CACH1_ENG, 0x00000000);
-#ifdef __BIG_ENDIAN
- NV_WRITE(NV_PFIFO_CACH1_DMAF, 0x800F0078);
-#else
- NV_WRITE(NV_PFIFO_CACH1_DMAF, 0x000F0078);
-#endif
- NV_WRITE(NV_PFIFO_CACH1_DMAS, 0x00000001);
- NV_WRITE(NV_PFIFO_CACH1_PSH0, 0x00000001);
- NV_WRITE(NV_PFIFO_CACH1_PUL0, 0x00000001);
- NV_WRITE(NV_PFIFO_CACH1_PUL1, 0x00000001);
-
- NV_WRITE(NV_PFIFO_CACHES, 0x00000001);
-
- DRM_DEBUG("%s: CACHE1 GET/PUT readback %d/%d\n", __func__,
- NV_READ(NV_PFIFO_CACH1_DMAG),
- NV_READ(NV_PFIFO_CACH1_DMAP));
-}
-
/***********************************
* ioctls wrapping the functions
***********************************/
-static int nouveau_ioctl_fifo_init(DRM_IOCTL_ARGS)
+static int nouveau_ioctl_fifo_alloc(DRM_IOCTL_ARGS)
{
DRM_DEVICE;
- drm_nouveau_fifo_init_t init;
+ drm_nouveau_fifo_alloc_t init;
int res;
- DRM_COPY_FROM_USER_IOCTL(init, (drm_nouveau_fifo_init_t __user *) data, sizeof(init));
+ DRM_COPY_FROM_USER_IOCTL(init, (drm_nouveau_fifo_alloc_t __user *) data, sizeof(init));
- res=nouveau_fifo_init(dev,&init,filp);
+ res=nouveau_fifo_alloc(dev,&init,filp);
if (!res)
- DRM_COPY_TO_USER_IOCTL((drm_nouveau_fifo_init_t __user *)data, init, sizeof(init));
+ DRM_COPY_TO_USER_IOCTL((drm_nouveau_fifo_alloc_t __user *)data, init, sizeof(init));
return res;
}
-static int nouveau_ioctl_fifo_reinit(DRM_IOCTL_ARGS)
-{
- DRM_DEVICE;
-
- nouveau_pfifo_init(dev);
- return 0;
-}
-
/***********************************
* finally, the ioctl table
***********************************/
drm_ioctl_desc_t nouveau_ioctls[] = {
- [DRM_IOCTL_NR(DRM_NOUVEAU_FIFO_INIT)] = {nouveau_ioctl_fifo_init, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_NOUVEAU_PFIFO_REINIT)] = {nouveau_ioctl_fifo_reinit, DRM_AUTH},
+ [DRM_IOCTL_NR(DRM_NOUVEAU_FIFO_ALLOC)] = {nouveau_ioctl_fifo_alloc, DRM_AUTH},
[DRM_IOCTL_NR(DRM_NOUVEAU_OBJECT_INIT)] = {nouveau_ioctl_object_init, DRM_AUTH},
[DRM_IOCTL_NR(DRM_NOUVEAU_DMA_OBJECT_INIT)] = {nouveau_ioctl_dma_object_init, DRM_AUTH},
[DRM_IOCTL_NR(DRM_NOUVEAU_MEM_ALLOC)] = {nouveau_ioctl_mem_alloc, DRM_AUTH},