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.
main
Stephane Marchesin 2006-10-11 00:28:15 +02:00
parent 22382bd8c5
commit dd473411f8
6 changed files with 412 additions and 184 deletions

View File

@ -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__ */

View File

@ -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);

View File

@ -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},

View File

@ -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_type<NV_40)
NV_WRITE(NV04_PGRAPH_INTEN, 0);
else
NV_WRITE(NV40_PGRAPH_INTEN, 0);
NV_WRITE(NV_PGRAPH_INTSTAT, 0xFFFFFFFF);
#if 0
/* Disable/Clear CRTC0/1 interrupts */
@ -70,9 +73,19 @@ void nouveau_irq_postinstall(drm_device_t *dev)
NV_WRITE(NV_PFIFO_INTSTAT, 0xFFFFFFFF);
/* Enable PGRAPH interrupts */
NV_WRITE(NV_PGRAPH_INTEN,
if (dev_priv->card_type<NV_40)
NV_WRITE(NV04_PGRAPH_INTEN,
NV_PGRAPH_INTR_NOTIFY |
NV_PGRAPH_INTR_MISSING_HW |
NV_PGRAPH_INTR_CONTEXT_SWITCH |
NV_PGRAPH_INTR_BUFFER_NOTIFY |
NV_PGRAPH_INTR_ERROR
);
else
NV_WRITE(NV40_PGRAPH_INTEN,
NV_PGRAPH_INTR_NOTIFY |
NV_PGRAPH_INTR_MISSING_HW |
NV_PGRAPH_INTR_CONTEXT_SWITCH |
NV_PGRAPH_INTR_BUFFER_NOTIFY |
NV_PGRAPH_INTR_ERROR
);
@ -97,7 +110,10 @@ void nouveau_irq_uninstall(drm_device_t *dev)
/* Disable PFIFO interrupts */
NV_WRITE(NV_PFIFO_INTEN, 0);
/* Disable PGRAPH interrupts */
NV_WRITE(NV_PGRAPH_INTEN, 0);
if (dev_priv->card_type<NV_40)
NV_WRITE(NV04_PGRAPH_INTEN, 0);
else
NV_WRITE(NV40_PGRAPH_INTEN, 0);
#if 0
/* Disable CRTC0/1 interrupts */
NV_WRITE(NV_CRTC0_INTEN, 0);
@ -107,15 +123,16 @@ void nouveau_irq_uninstall(drm_device_t *dev)
NV_WRITE(NV_PMC_INTEN, 0);
}
void nouveau_fifo_irq_handler(drm_nouveau_private_t *dev_priv)
static void nouveau_fifo_irq_handler(drm_device_t *dev)
{
uint32_t status, chmode, chstat;
drm_nouveau_private_t *dev_priv = dev->dev_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;i<nouveau_fifo_number(dev);i++)
if ((dev_priv->fifos[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<<i)))
{
pending|=(1<<i);
NV_WRITE(NV_PFIFO_DMA,pending);
}
max++;
}
nouveau_wait_for_idle(dev);
#if 1
/* 2-channel commute */
// NV_WRITE(NV_PFIFO_CACH1_PSH1,channel|0x100);
if (channel==0)
channel=1;
else
channel=0;
// dev_priv->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;
}

View File

@ -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))

View File

@ -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);
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 (!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;
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;
}