summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--shared-core/nouveau_drm.h2
-rw-r--r--shared-core/nouveau_drv.h13
-rw-r--r--shared-core/nouveau_fifo.c16
-rw-r--r--shared-core/nouveau_state.c89
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;
+}
+