From dd473411f889cc16af255437d2a61c616bcee695 Mon Sep 17 00:00:00 2001 From: Stephane Marchesin Date: Wed, 11 Oct 2006 00:28:15 +0200 Subject: 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. --- shared-core/nouveau_drm.h | 19 ++- shared-core/nouveau_drv.h | 5 +- shared-core/nouveau_fifo.c | 308 ++++++++++++++++++++++++++++---------------- shared-core/nouveau_irq.c | 122 ++++++++++++++++-- shared-core/nouveau_reg.h | 83 +++++++++++- shared-core/nouveau_state.c | 59 ++------- 6 files changed, 412 insertions(+), 184 deletions(-) (limited to 'shared-core') diff --git a/shared-core/nouveau_drm.h b/shared-core/nouveau_drm.h index 1180a135..ed87f5c4 100644 --- a/shared-core/nouveau_drm.h +++ b/shared-core/nouveau_drm.h @@ -25,7 +25,7 @@ #ifndef __NOUVEAU_DRM_H__ #define __NOUVEAU_DRM_H__ -typedef struct drm_nouveau_fifo_init { +typedef struct drm_nouveau_fifo_alloc { int channel; uint32_t put_base; /* FIFO control regs */ @@ -35,7 +35,7 @@ typedef struct drm_nouveau_fifo_init { drm_handle_t cmdbuf; int cmdbuf_size; } -drm_nouveau_fifo_init_t; +drm_nouveau_fifo_alloc_t; typedef struct drm_nouveau_object_init { uint32_t handle; @@ -122,14 +122,13 @@ typedef struct drm_nouveau_sarea { } drm_nouveau_sarea_t; -#define DRM_NOUVEAU_FIFO_INIT 0x00 -#define DRM_NOUVEAU_PFIFO_REINIT 0x01 -#define DRM_NOUVEAU_OBJECT_INIT 0x02 -#define DRM_NOUVEAU_DMA_OBJECT_INIT 0x03 // We don't want this eventually.. -#define DRM_NOUVEAU_MEM_ALLOC 0x04 -#define DRM_NOUVEAU_MEM_FREE 0x05 -#define DRM_NOUVEAU_GETPARAM 0x06 -#define DRM_NOUVEAU_SETPARAM 0x07 +#define DRM_NOUVEAU_FIFO_ALLOC 0x00 +#define DRM_NOUVEAU_OBJECT_INIT 0x01 +#define DRM_NOUVEAU_DMA_OBJECT_INIT 0x02 // We don't want this eventually.. +#define DRM_NOUVEAU_MEM_ALLOC 0x03 +#define DRM_NOUVEAU_MEM_FREE 0x04 +#define DRM_NOUVEAU_GETPARAM 0x05 +#define DRM_NOUVEAU_SETPARAM 0x06 #endif /* __NOUVEAU_DRM_H__ */ diff --git a/shared-core/nouveau_drv.h b/shared-core/nouveau_drv.h index 7af9c618..007bdd6a 100644 --- a/shared-core/nouveau_drv.h +++ b/shared-core/nouveau_drv.h @@ -123,6 +123,9 @@ typedef struct drm_nouveau_private { struct nouveau_fifo fifos[NV_MAX_FIFO_NUMBER]; struct nouveau_object_store objs; + /* RAMFC and RAMRO offsets */ + uint32_t ramfc_offset; + uint32_t ramro_offset; struct mem_block *agp_heap; struct mem_block *fb_heap; @@ -139,7 +142,7 @@ extern int nouveau_firstopen(struct drm_device *dev); extern int nouveau_unload(struct drm_device *dev); extern int nouveau_ioctl_getparam(DRM_IOCTL_ARGS); extern int nouveau_ioctl_setparam(DRM_IOCTL_ARGS); -extern int nouveau_dma_init(struct drm_device *dev); +extern void nouveau_wait_for_idle(struct drm_device *dev); /* nouveau_mem.c */ extern uint64_t nouveau_mem_fb_amount(struct drm_device *dev); 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;ififos[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<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<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;ififos[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;ififos[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}, diff --git a/shared-core/nouveau_irq.c b/shared-core/nouveau_irq.c index 5088edac..9cd2c77f 100644 --- a/shared-core/nouveau_irq.c +++ b/shared-core/nouveau_irq.c @@ -46,7 +46,10 @@ void nouveau_irq_preinstall(drm_device_t *dev) NV_WRITE(NV_PFIFO_INTEN, 0); NV_WRITE(NV_PFIFO_INTSTAT, 0xFFFFFFFF); /* Disable/Clear PGRAPH interrupts */ - NV_WRITE(NV_PGRAPH_INTEN, 0); + if (dev_priv->card_typecard_typecard_typedev_private; status = NV_READ(NV_PFIFO_INTSTAT); if (!status) return; chmode = NV_READ(NV_PFIFO_MODE); - chstat = NV_READ(0x2508); + chstat = NV_READ(NV_PFIFO_DMA); DRM_DEBUG("NV: PFIFO interrupt! INTSTAT=0x%08x/MODE=0x%08x/PEND=0x%08x\n", status, chmode, chstat); @@ -136,9 +153,73 @@ void nouveau_fifo_irq_handler(drm_nouveau_private_t *dev_priv) NV_WRITE(NV_PMC_INTSTAT, NV_PMC_INTSTAT_PFIFO_PENDING); } -void nouveau_pgraph_irq_handler(drm_nouveau_private_t *dev_priv) +static void nouveau_nv04_context_switch(drm_device_t *dev) +{ + drm_nouveau_private_t *dev_priv = dev->dev_private; + uint32_t channel,i; + uint32_t max=0; + NV_WRITE(NV_PGRAPH_FIFO,0x0); + channel=NV_READ(NV_PFIFO_CACH1_PSH1)&(nouveau_fifo_number(dev)-1); + //DRM_INFO("raw PFIFO_CACH1_PHS1 reg is %x\n",NV_READ(NV_PFIFO_CACH1_PSH1)); + //DRM_INFO("currently on channel %d\n",channel); + for (i=0;ififos[i].used)&&(i!=channel)) { + uint32_t put,get,pending; + //put=NV_READ(dev_priv->ramfc_offset+i*32); + //get=NV_READ(dev_priv->ramfc_offset+4+i*32); + put=NV_READ(NV03_FIFO_REGS_DMAPUT(i)); + get=NV_READ(NV03_FIFO_REGS_DMAGET(i)); + pending=NV_READ(NV_PFIFO_DMA); + //DRM_INFO("Channel %d (put/get %x/%x)\n",i,put,get); + /* mark all pending channels as such */ + if ((put!=get)&!(pending&(1<cur_fifo=channel; + NV_WRITE(0x2050,channel|0x100); +#endif + //NV_WRITE(NV_PFIFO_CACH1_PSH1,max|0x100); + //NV_WRITE(0x2050,max|0x100); + + NV_WRITE(NV_PGRAPH_FIFO,0x1); + +} + +static void nouveau_nv10_context_switch(drm_device_t *dev) +{ + drm_nouveau_private_t *dev_priv = dev->dev_private; + int channel; + + channel=NV_READ(NV_PFIFO_CACH1_PSH1)&(nouveau_fifo_number(dev)-1); + /* 2-channel commute */ + if (channel==0) + channel=1; + else + channel=0; + dev_priv->cur_fifo=channel; + + NV_WRITE(NV_PGRAPH_CTX_USER, (NV_READ(NV_PGRAPH_CTX_USER)&0xE0FFFFFF)|(dev_priv->cur_fifo<<24)); + NV_WRITE(NV_PGRAPH_CTX_CONTROL, 0x10010100); + NV_WRITE(NV_PGRAPH_FFINTFC_ST2, NV_READ(NV_PGRAPH_FFINTFC_ST2)&0xCFFFFFFF); +} + +static void nouveau_pgraph_irq_handler(drm_device_t *dev) { uint32_t status; + drm_nouveau_private_t *dev_priv = dev->dev_private; status = NV_READ(NV_PGRAPH_INTSTAT); if (!status) @@ -190,6 +271,26 @@ void nouveau_pgraph_irq_handler(drm_nouveau_private_t *dev_priv) NV_WRITE(NV_PGRAPH_INTSTAT, NV_PGRAPH_INTR_ERROR); } + if (status & NV_PGRAPH_INTR_CONTEXT_SWITCH) { + uint32_t channel=NV_READ(NV_PFIFO_CACH1_PSH1)&(nouveau_fifo_number(dev)-1); + DRM_INFO("NV: PGRAPH context switch interrupt channel %x\n",channel); + switch(dev_priv->card_type) + { + case NV_04: + nouveau_nv04_context_switch(dev); + break; + case NV_10: + nouveau_nv10_context_switch(dev); + break; + default: + DRM_INFO("NV: Context switch not implemented\n"); + break; + } + + status &= ~NV_PGRAPH_INTR_CONTEXT_SWITCH; + NV_WRITE(NV_PGRAPH_INTSTAT, NV_PGRAPH_INTR_CONTEXT_SWITCH); + } + if (status) { DRM_INFO("NV: Unknown PGRAPH interrupt! STAT=0x%08x\n", status); NV_WRITE(NV_PGRAPH_INTSTAT, status); @@ -198,8 +299,9 @@ void nouveau_pgraph_irq_handler(drm_nouveau_private_t *dev_priv) NV_WRITE(NV_PMC_INTSTAT, NV_PMC_INTSTAT_PGRAPH_PENDING); } -void nouveau_crtc_irq_handler(drm_nouveau_private_t *dev_priv, int crtc) +static void nouveau_crtc_irq_handler(drm_device_t *dev, int crtc) { + drm_nouveau_private_t *dev_priv = dev->dev_private; if (crtc&1) { NV_WRITE(NV_CRTC0_INTSTAT, NV_CRTC_INTR_VBLANK); } @@ -220,15 +322,15 @@ irqreturn_t nouveau_irq_handler(DRM_IRQ_ARGS) DRM_DEBUG("PMC INTSTAT: 0x%08x\n", status); if (status & NV_PMC_INTSTAT_PFIFO_PENDING) { - nouveau_fifo_irq_handler(dev_priv); + nouveau_fifo_irq_handler(dev); status &= ~NV_PMC_INTSTAT_PFIFO_PENDING; } if (status & NV_PMC_INTSTAT_PGRAPH_PENDING) { - nouveau_pgraph_irq_handler(dev_priv); + nouveau_pgraph_irq_handler(dev); status &= ~NV_PMC_INTSTAT_PGRAPH_PENDING; } if (status & NV_PMC_INTSTAT_CRTCn_PENDING) { - nouveau_crtc_irq_handler(dev_priv, (status>>24)&3); + nouveau_crtc_irq_handler(dev, (status>>24)&3); status &= ~NV_PMC_INTSTAT_CRTCn_PENDING; } diff --git a/shared-core/nouveau_reg.h b/shared-core/nouveau_reg.h index 42c5b851..2b723c76 100644 --- a/shared-core/nouveau_reg.h +++ b/shared-core/nouveau_reg.h @@ -15,8 +15,8 @@ # define NV10_FIFO_DATA_RAM_AMOUNT_MB_MASK 0xfff00000 # define NV10_FIFO_DATA_RAM_AMOUNT_MB_SHIFT 20 -#define NV03_STATUS 0x004006b0 -#define NV04_STATUS 0x00400700 +#define NV03_PGRAPH_STATUS 0x004006b0 +#define NV04_PGRAPH_STATUS 0x00400700 #define NV_RAMIN 0x00700000 @@ -55,16 +55,24 @@ # define NV_PMC_INTEN_MASTER_ENABLE (1<< 0) #define NV_PGRAPH_INTSTAT 0x00400100 -#define NV_PGRAPH_INTEN 0x00400140 +#define NV04_PGRAPH_INTEN 0x00400140 +#define NV40_PGRAPH_INTEN 0x0040013C # define NV_PGRAPH_INTR_NOTIFY (1<< 0) # define NV_PGRAPH_INTR_MISSING_HW (1<< 4) +# define NV_PGRAPH_INTR_CONTEXT_SWITCH (1<<12) # define NV_PGRAPH_INTR_BUFFER_NOTIFY (1<<16) # define NV_PGRAPH_INTR_ERROR (1<<20) +#define NV_PGRAPH_CTX_CONTROL 0x00400144 #define NV_PGRAPH_NV40_UNK220 0x00400220 # define NV_PGRAPH_NV40_UNK220_FB_INSTANCE +#define NV_PGRAPH_CTX_USER 0x00400148 +#define NV_PGRAPH_CTX_SWITCH1 0x0040014C +#define NV_PGRAPH_FIFO 0x00400720 +#define NV_PGRAPH_FFINTFC_ST2 0x00400764 /* It's a guess that this works on NV03. Confirmed on NV04, though */ -#define NV03_FIFO_ENABLE 0x00002504 +#define NV_PFIFO_DELAY_0 0x00002040 +#define NV_PFIFO_DMA_TIMESLICE 0x00002044 #define NV_PFIFO_INTSTAT 0x00002100 #define NV_PFIFO_INTEN 0x00002140 # define NV_PFIFO_INTR_ERROR (1<<0) @@ -73,14 +81,78 @@ #define NV_PFIFO_RAMRO 0x00002218 #define NV_PFIFO_CACHES 0x00002500 #define NV_PFIFO_MODE 0x00002504 +#define NV_PFIFO_DMA 0x00002508 #define NV_PFIFO_SIZE 0x0000250c #define NV_PFIFO_CACH0_PSH0 0x00003000 #define NV_PFIFO_CACH0_PUL0 0x00003050 #define NV_PFIFO_CACH0_PUL1 0x00003054 #define NV_PFIFO_CACH1_PSH0 0x00003200 #define NV_PFIFO_CACH1_PSH1 0x00003204 -#define NV_PFIFO_CACH1_DMAS 0x00003220 +#define NV_PFIFO_CACH1_DMAPSH 0x00003220 #define NV_PFIFO_CACH1_DMAF 0x00003224 +# define NV_PFIFO_CACH1_DMAF_TRIG_8_BYTES 0x00000000 +# define NV_PFIFO_CACH1_DMAF_TRIG_8_BYTES 0x00000000 +# define NV_PFIFO_CACH1_DMAF_TRIG_16_BYTES 0x00000008 +# define NV_PFIFO_CACH1_DMAF_TRIG_24_BYTES 0x00000010 +# define NV_PFIFO_CACH1_DMAF_TRIG_32_BYTES 0x00000018 +# define NV_PFIFO_CACH1_DMAF_TRIG_40_BYTES 0x00000020 +# define NV_PFIFO_CACH1_DMAF_TRIG_48_BYTES 0x00000028 +# define NV_PFIFO_CACH1_DMAF_TRIG_56_BYTES 0x00000030 +# define NV_PFIFO_CACH1_DMAF_TRIG_64_BYTES 0x00000038 +# define NV_PFIFO_CACH1_DMAF_TRIG_72_BYTES 0x00000040 +# define NV_PFIFO_CACH1_DMAF_TRIG_80_BYTES 0x00000048 +# define NV_PFIFO_CACH1_DMAF_TRIG_88_BYTES 0x00000050 +# define NV_PFIFO_CACH1_DMAF_TRIG_96_BYTES 0x00000058 +# define NV_PFIFO_CACH1_DMAF_TRIG_104_BYTES 0x00000060 +# define NV_PFIFO_CACH1_DMAF_TRIG_112_BYTES 0x00000068 +# define NV_PFIFO_CACH1_DMAF_TRIG_120_BYTES 0x00000070 +# define NV_PFIFO_CACH1_DMAF_TRIG_128_BYTES 0x00000078 +# define NV_PFIFO_CACH1_DMAF_TRIG_136_BYTES 0x00000080 +# define NV_PFIFO_CACH1_DMAF_TRIG_144_BYTES 0x00000088 +# define NV_PFIFO_CACH1_DMAF_TRIG_152_BYTES 0x00000090 +# define NV_PFIFO_CACH1_DMAF_TRIG_160_BYTES 0x00000098 +# define NV_PFIFO_CACH1_DMAF_TRIG_168_BYTES 0x000000A0 +# define NV_PFIFO_CACH1_DMAF_TRIG_176_BYTES 0x000000A8 +# define NV_PFIFO_CACH1_DMAF_TRIG_184_BYTES 0x000000B0 +# define NV_PFIFO_CACH1_DMAF_TRIG_192_BYTES 0x000000B8 +# define NV_PFIFO_CACH1_DMAF_TRIG_200_BYTES 0x000000C0 +# define NV_PFIFO_CACH1_DMAF_TRIG_208_BYTES 0x000000C8 +# define NV_PFIFO_CACH1_DMAF_TRIG_216_BYTES 0x000000D0 +# define NV_PFIFO_CACH1_DMAF_TRIG_224_BYTES 0x000000D8 +# define NV_PFIFO_CACH1_DMAF_TRIG_232_BYTES 0x000000E0 +# define NV_PFIFO_CACH1_DMAF_TRIG_240_BYTES 0x000000E8 +# define NV_PFIFO_CACH1_DMAF_TRIG_248_BYTES 0x000000F0 +# define NV_PFIFO_CACH1_DMAF_TRIG_256_BYTES 0x000000F8 +# define NV_PFIFO_CACH1_DMAF_SIZE 0x0000E000 +# define NV_PFIFO_CACH1_DMAF_SIZE_32_BYTES 0x00000000 +# define NV_PFIFO_CACH1_DMAF_SIZE_64_BYTES 0x00002000 +# define NV_PFIFO_CACH1_DMAF_SIZE_96_BYTES 0x00004000 +# define NV_PFIFO_CACH1_DMAF_SIZE_128_BYTES 0x00006000 +# define NV_PFIFO_CACH1_DMAF_SIZE_160_BYTES 0x00008000 +# define NV_PFIFO_CACH1_DMAF_SIZE_192_BYTES 0x0000A000 +# define NV_PFIFO_CACH1_DMAF_SIZE_224_BYTES 0x0000C000 +# define NV_PFIFO_CACH1_DMAF_SIZE_256_BYTES 0x0000E000 +# define NV_PFIFO_CACH1_DMAF_MAX_REQS 0x001F0000 +# define NV_PFIFO_CACH1_DMAF_MAX_REQS_0 0x00000000 +# define NV_PFIFO_CACH1_DMAF_MAX_REQS_1 0x00010000 +# define NV_PFIFO_CACH1_DMAF_MAX_REQS_2 0x00020000 +# define NV_PFIFO_CACH1_DMAF_MAX_REQS_3 0x00030000 +# define NV_PFIFO_CACH1_DMAF_MAX_REQS_4 0x00040000 +# define NV_PFIFO_CACH1_DMAF_MAX_REQS_5 0x00050000 +# define NV_PFIFO_CACH1_DMAF_MAX_REQS_6 0x00060000 +# define NV_PFIFO_CACH1_DMAF_MAX_REQS_7 0x00070000 +# define NV_PFIFO_CACH1_DMAF_MAX_REQS_8 0x00080000 +# define NV_PFIFO_CACH1_DMAF_MAX_REQS_9 0x00090000 +# define NV_PFIFO_CACH1_DMAF_MAX_REQS_10 0x000A0000 +# define NV_PFIFO_CACH1_DMAF_MAX_REQS_11 0x000B0000 +# define NV_PFIFO_CACH1_DMAF_MAX_REQS_12 0x000C0000 +# define NV_PFIFO_CACH1_DMAF_MAX_REQS_13 0x000D0000 +# define NV_PFIFO_CACH1_DMAF_MAX_REQS_14 0x000E0000 +# define NV_PFIFO_CACH1_DMAF_MAX_REQS_15 0x000F0000 +# define NV_PFIFO_CACH1_ENDIAN 0x80000000 +# define NV_PFIFO_CACH1_LITTLE_ENDIAN 0x7FFFFFFF +# define NV_PFIFO_CACH1_BIG_ENDIAN 0x80000000 +#define NV_PFIFO_CACH1_DMAS 0x00003228 #define NV_PFIFO_CACH1_DMAI 0x0000322c #define NV_PFIFO_CACH1_DMAC 0x00003230 #define NV_PFIFO_CACH1_DMAP 0x00003240 @@ -101,3 +173,4 @@ #define NV03_FIFO_CMD_JUMP_OFFSET_MASK 0x1ffffffc #define NV03_FIFO_CMD_REWIND (NV03_FIFO_CMD_JUMP | (0 & NV03_FIFO_CMD_JUMP_OFFSET_MASK)) + diff --git a/shared-core/nouveau_state.c b/shared-core/nouveau_state.c index 6c5cc153..a015a0fe 100644 --- a/shared-core/nouveau_state.c +++ b/shared-core/nouveau_state.c @@ -150,55 +150,18 @@ int nouveau_ioctl_setparam(DRM_IOCTL_ARGS) return 0; } -int nouveau_dma_init(struct drm_device *dev) +/* waits for idle */ +void nouveau_wait_for_idle(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; - - 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); + drm_nouveau_private_t *dev_priv=dev->dev_private; + switch(dev_priv->card_type) + { + case NV_03: + while(NV_READ(NV03_PGRAPH_STATUS)); + break; + default: + while(NV_READ(NV04_PGRAPH_STATUS)); + break; } - - 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; - - 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; } -- cgit v1.2.3