diff options
-rw-r--r-- | shared-core/nouveau_drm.h | 2 | ||||
-rw-r--r-- | shared-core/nouveau_drv.h | 13 | ||||
-rw-r--r-- | shared-core/nouveau_fifo.c | 16 | ||||
-rw-r--r-- | shared-core/nouveau_state.c | 89 |
4 files changed, 88 insertions, 32 deletions
diff --git a/shared-core/nouveau_drm.h b/shared-core/nouveau_drm.h index 76fb3a17..1180a135 100644 --- a/shared-core/nouveau_drm.h +++ b/shared-core/nouveau_drm.h @@ -85,6 +85,8 @@ typedef struct drm_nouveau_getparam { } drm_nouveau_getparam_t; +#define NOUVEAU_SETPARAM_CMDBUF_LOCATION 1 +#define NOUVEAU_SETPARAM_CMDBUF_SIZE 2 typedef struct drm_nouveau_setparam { unsigned int param; unsigned int value; diff --git a/shared-core/nouveau_drv.h b/shared-core/nouveau_drv.h index d7014017..7af9c618 100644 --- a/shared-core/nouveau_drv.h +++ b/shared-core/nouveau_drv.h @@ -97,6 +97,13 @@ struct mem_block { drm_local_map_t *map; }; +struct nouveau_config { + struct { + int location; + int size; + } cmdbuf; +}; + typedef struct drm_nouveau_private { /* the card type, takes NV_* as values */ int card_type; @@ -111,9 +118,7 @@ typedef struct drm_nouveau_private { struct nouveau_object *fb_obj; struct nouveau_object *cmdbuf_obj; - int cmdbuf_location; - int cmdbuf_base; - int cmdbuf_ch_size; + int cmdbuf_ch_size; struct mem_block* cmdbuf_alloc; struct nouveau_fifo fifos[NV_MAX_FIFO_NUMBER]; @@ -123,6 +128,7 @@ typedef struct drm_nouveau_private { struct mem_block *fb_heap; struct mem_block *fb_nomap_heap; + struct nouveau_config config; } drm_nouveau_private_t; @@ -133,6 +139,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); /* 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 c0d54b33..67ee6c71 100644 --- a/shared-core/nouveau_fifo.c +++ b/shared-core/nouveau_fifo.c @@ -77,6 +77,15 @@ static int nouveau_fifo_init(drm_device_t* dev,drm_nouveau_fifo_init_t* init, DR int ret; drm_nouveau_private_t *dev_priv = dev->dev_private; + /* Init cmdbuf on first FIFO init, this is delayed until now to + * give the ddx a chance to configure the cmdbuf with SETPARAM + */ + if (!dev_priv->cmdbuf_alloc) { + ret = nouveau_dma_init(dev); + if (ret) + return ret; + } + /* * Alright, here is the full story * Nvidia cards have multiple hw fifo contexts (praise them for that, @@ -120,7 +129,7 @@ static int nouveau_fifo_init(drm_device_t* dev,drm_nouveau_fifo_init_t* init, DR return ret; /* then, the fifo itself */ - init->cmdbuf = dev_priv->cmdbuf_base; + init->cmdbuf = dev_priv->cmdbuf_alloc->start; init->cmdbuf += init->channel * dev_priv->cmdbuf_ch_size; init->cmdbuf_size = dev_priv->cmdbuf_ch_size; ret = drm_addmap(dev, init->cmdbuf, init->cmdbuf_size, _DRM_REGISTERS, @@ -157,8 +166,9 @@ void nouveau_fifo_cleanup(drm_device_t * dev, DRMFILE filp) DRM_DEBUG("%s: new cur_fifo is %d\n", __func__, i); dev_priv->cur_fifo = i; } - - nouveau_pfifo_init(dev); + + if (dev_priv->cmdbuf_alloc) + nouveau_pfifo_init(dev); // nouveau_fifo_enable(dev); } diff --git a/shared-core/nouveau_state.c b/shared-core/nouveau_state.c index 01ebbc8f..fbe94641 100644 --- a/shared-core/nouveau_state.c +++ b/shared-core/nouveau_state.c @@ -76,32 +76,6 @@ int nouveau_firstopen(struct drm_device *dev) 0, nouveau_mem_fb_amount(dev), NV_DMA_ACCESS_RW, NV_DMA_TARGET_VIDMEM); - /* allocate one buffer for all the fifos */ - dev_priv->cmdbuf_alloc = nouveau_mem_alloc(dev, 0, 1024*1024, NOUVEAU_MEM_FB, (DRMFILE)-2); - - if (dev_priv->cmdbuf_alloc->flags&NOUVEAU_MEM_AGP) { - dev_priv->cmdbuf_location = NV_DMA_TARGET_AGP; - dev_priv->cmdbuf_ch_size = NV03_FIFO_SIZE; - dev_priv->cmdbuf_base = dev_priv->cmdbuf_alloc->start; - dev_priv->cmdbuf_obj = nouveau_dma_object_create(dev, - dev_priv->cmdbuf_base, nouveau_fifo_number(dev)*NV03_FIFO_SIZE, - NV_DMA_ACCESS_RO, dev_priv->cmdbuf_location); - } else { /* NOUVEAU_MEM_FB */ - dev_priv->cmdbuf_location = NV_DMA_TARGET_VIDMEM; - dev_priv->cmdbuf_ch_size = NV03_FIFO_SIZE; - dev_priv->cmdbuf_base = dev_priv->cmdbuf_alloc->start; - dev_priv->cmdbuf_obj = nouveau_dma_object_create(dev, - dev_priv->cmdbuf_base - drm_get_resource_start(dev, 1), - nouveau_fifo_number(dev)*NV03_FIFO_SIZE, - NV_DMA_ACCESS_RO, dev_priv->cmdbuf_location); - } - - DRM_INFO("DMA command buffer is %dKiB at 0x%08x(%s)\n", - (nouveau_fifo_number(dev)*dev_priv->cmdbuf_ch_size)/1024, - dev_priv->cmdbuf_base, - dev_priv->cmdbuf_location == NV_DMA_TARGET_AGP ? "AGP" : "VRAM" - ); - return 0; } @@ -154,12 +128,27 @@ int nouveau_ioctl_getparam(DRM_IOCTL_ARGS) int nouveau_ioctl_setparam(DRM_IOCTL_ARGS) { DRM_DEVICE; + drm_nouveau_private_t *dev_priv = dev->dev_private; drm_nouveau_setparam_t setparam; DRM_COPY_FROM_USER_IOCTL(setparam, (drm_nouveau_setparam_t __user *)data, sizeof(setparam)); switch (setparam.param) { + case NOUVEAU_SETPARAM_CMDBUF_LOCATION: + switch (setparam.value) { + case NOUVEAU_MEM_AGP: + case NOUVEAU_MEM_FB: + break; + default: + DRM_ERROR("invalid CMDBUF_LOCATION value=%d\n", setparam.value); + return DRM_ERR(EINVAL); + } + dev_priv->config.cmdbuf.location = setparam.value; + break; + case NOUVEAU_SETPARAM_CMDBUF_SIZE: + dev_priv->config.cmdbuf.size = setparam.value; + break; default: DRM_ERROR("unknown parameter %d\n", setparam.param); return DRM_ERR(EINVAL); @@ -168,3 +157,51 @@ int nouveau_ioctl_setparam(DRM_IOCTL_ARGS) return 0; } +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; + + /* allocate one buffer for all the fifos */ + dev_priv->cmdbuf_alloc = nouveau_mem_alloc(dev, 0, 1024*1024, NOUVEAU_MEM_FB, (DRMFILE)-2); + + /* 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 = 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; +} + |