struct nouveau_screen *nv_screen;
struct pipe_surface *frontbuffer;
- /* Bufmgr */
- struct {
- struct nouveau_channel *channel;
- struct nouveau_notifier *notify;
- struct nouveau_grobj *m2mf;
- uint32_t m2mf_src_ctxdma;
- uint32_t m2mf_dst_ctxdma;
- uint32_t next_sequence;
- } bo;
-
- /* Relocations */
- struct nouveau_bo *reloc_head;
-
/* Hardware context */
uint32_t *pushbuf;
struct nouveau_channel *channel;
int i;
nvchan->dma.base = nvchan->drm.put_base;
- nvchan->dma.cur = nvchan->dma.put = RING_SKIPS;
+ nvchan->dma.cur = nvchan->dma.put = 0;
nvchan->dma.max = (nvchan->drm.cmdbuf_size >> 2) - 2;
nvchan->dma.free = nvchan->dma.max - nvchan->dma.cur;
+ RING_SPACE_CH(chan, RING_SKIPS);
for (i = 0; i < RING_SKIPS; i++)
- nvchan->pushbuf[i] = 0x00000000;
+ OUT_RING_CH(chan, 0);
}
#define CHECK_TIMEOUT() do { \
}
static inline void
+nouveau_dma_space(struct nouveau_channel *chan, int size)
+{
+ struct nouveau_channel_priv *nvchan = nouveau_channel(chan);
+
+ if (nvchan->dma.free < size) {
+ if (nouveau_dma_wait(chan, size) && chan->hang_notify)
+ chan->hang_notify(chan);
+ }
+ nvchan->dma.free -= size;
+#ifdef NOUVEAU_DMA_DEBUG
+ nvchan->dma.push_free = size;
+#endif
+}
+
+static inline void
nouveau_dma_begin(struct nouveau_channel *chan, struct nouveau_grobj *grobj,
int method, int size, const char* file, int line)
{
struct nouveau_channel_priv *nvchan = nouveau_channel(chan);
- int push_size = size + 1;
+ (void)nvchan;
#ifdef NOUVEAU_DMA_TRACE
NOUVEAU_MSG("BEGIN_RING %d/%08x/%d/0x%04x/%d\n", nvchan->drm.channel,
sprintf(faulty,"%s:%d",file,line);
#endif
- if (nvchan->dma.free < push_size) {
- if (nouveau_dma_wait(chan, push_size) &&
- chan->hang_notify) {
- chan->hang_notify(chan);
- }
- }
- nvchan->dma.free -= push_size;
-#ifdef NOUVEAU_DMA_DEBUG
- nvchan->dma.push_free = push_size;
-#endif
-
+ nouveau_dma_space(chan, (size + 1));
nouveau_dma_out(chan, (size << 18) | (grobj->subc << 13) | method);
}
+#define RING_SPACE_CH(ch,sz) nouveau_dma_space((ch), (sz))
#define BEGIN_RING_CH(ch,gr,m,sz) nouveau_dma_begin((ch), (gr), (m), (sz), __FUNCTION__, __LINE__ )
#define OUT_RING_CH(ch, data) nouveau_dma_out((ch), (data))
#define OUT_RINGp_CH(ch,ptr,dwords) nouveau_dma_outp((ch), (void*)(ptr), \
#include "pipe/nouveau/nouveau_notifier.h"
#include "pipe/nouveau/nouveau_bo.h"
#include "pipe/nouveau/nouveau_resource.h"
+#include "pipe/nouveau/nouveau_pushbuf.h"
struct nouveau_device_priv {
struct nouveau_device base;
int nr_relocs;
};
-struct nouveau_pushbuf {
- struct nouveau_channel *channel;
- unsigned remaining;
- uint32_t *cur;
-};
-
struct nouveau_pushbuf_priv {
struct nouveau_pushbuf base;
struct nouveau_pushbuf *next;
int nr_buffers;
};
#define nouveau_pushbuf(n) ((struct nouveau_pushbuf_priv *)(n))
+
#define pbbo_to_ptr(o) ((uint64_t)(unsigned long)(o))
#define ptr_to_pbbo(h) ((struct nouveau_pushbuf_bo *)(unsigned long)(h))
#define pbrel_to_ptr(o) ((uint64_t)(unsigned long)(o))
NOUVEAU_ERR("AII wrap unhandled\n");
/*XXX: assumes subc 0 is populated */
- if (nvchan->dma.free < 2)
- WAIT_RING_CH(&nvchan->base, 2);
- nvchan->dma.free -= 2;
-#ifdef NOUVEAU_DMA_DEBUG
- nvchan->dma.push_free += 2;
-#endif
- OUT_RING_CH(&nvchan->base, 0x00040050);
- OUT_RING_CH(&nvchan->base, nvfence->sequence);
+ RING_SPACE_CH(fence->channel, 2);
+ OUT_RING_CH (fence->channel, 0x00040050);
+ OUT_RING_CH (fence->channel, nvfence->sequence);
if (nvchan->fence_tail) {
nouveau_fence(nvchan->fence_tail)->next = fence;
#define PB_RSVD_DWORDS 2
+static int
+nouveau_pushbuf_space(struct nouveau_channel *chan)
+{
+ struct nouveau_channel_priv *nvchan = nouveau_channel(chan);
+ struct nouveau_pushbuf_priv *nvpb;
+
+ nvpb = calloc(1, sizeof(struct nouveau_pushbuf_priv));
+ if (!nvpb)
+ return -ENOMEM;
+
+ while (nouveau_resource_alloc(nvchan->pb_heap, 0x2100, NULL,
+ &nvpb->res)) {
+ nouveau_fence_flush(chan);
+ }
+
+ nvpb->base.channel = chan;
+ nvpb->base.remaining = (nvpb->res->size / 4) - PB_RSVD_DWORDS;
+ nvpb->base.cur = &nvchan->pushbuf[nvpb->res->start/4];
+ nvchan->pb_tail = &nvpb->base;
+ nvchan->base.pushbuf = nvchan->pb_tail;
+
+ return 0;
+}
+
int
nouveau_pushbuf_init(struct nouveau_channel *chan)
{
nvchan->dma.max = (4096 / 4) - 2;
nvchan->dma.free = nvchan->dma.max - nvchan->dma.cur;
+ assert(!nouveau_pushbuf_space(chan));
+
return 0;
}
nouveau_pushbuf_flush(struct nouveau_channel *chan)
{
struct nouveau_channel_priv *nvchan = nouveau_channel(chan);
- struct nouveau_pushbuf_priv *nvpb = nouveau_pushbuf(nvchan->pb_tail);
+ struct nouveau_pushbuf_priv *nvpb = nouveau_pushbuf(chan->pushbuf);
struct nouveau_pushbuf_bo *pbbo;
struct nouveau_fence *fence = NULL;
int ret;
- if (!nvpb)
- goto out_realloc;
-
if (nvpb->base.remaining == (nvpb->res->size / 4) - PB_RSVD_DWORDS)
return 0;
nvchan->pb_tail = NULL;
nvpb->nr_buffers = 0;
/* Emit JMP to indirect pushbuf */
- if (nvchan->dma.free < 1)
- WAIT_RING_CH(chan, 1);
- nvchan->dma.free -= 1;
-#ifdef NOUVEAU_DMA_DEBUG
- nvchan->dma.push_free = 1;
-#endif
+ RING_SPACE_CH(chan, 1);
OUT_RING_CH(chan, 0x20000000 | nvpb->res->start);
/* Add JMP back to master pushbuf from indirect pushbuf */
FIRE_RING_CH(chan);
/* Allocate space for next push buffer */
-out_realloc:
- nvpb = calloc(1, sizeof(struct nouveau_pushbuf_priv));
- if (!nvpb)
- return -ENOMEM;
-
- while (nouveau_resource_alloc(nvchan->pb_heap, 0x2100, NULL,
- &nvpb->res)) {
- nouveau_fence_flush(chan);
- }
-
- nvpb->base.channel = chan;
- nvpb->base.remaining = (nvpb->res->size / 4) - PB_RSVD_DWORDS;
- nvpb->base.cur = &nvchan->pushbuf[nvpb->res->start/4];
- nvchan->pb_tail = &nvpb->base;
+ assert(!nouveau_pushbuf_space(chan));
return 0;
}
uint32_t *
nouveau_pipe_dma_beginp(struct nouveau_grobj *grobj, int mthd, int size)
{
- struct nouveau_channel_priv *nvchan = nouveau_channel(grobj->channel);
+ struct nouveau_channel *chan = grobj->channel;
uint32_t *pushbuf;
- if (!nvchan->pb_tail || nvchan->pb_tail->remaining < (size + 1))
- nouveau_pushbuf_flush(grobj->channel);
+ if (chan->pushbuf->remaining < (size + 1))
+ nouveau_pushbuf_flush(chan);
- pushbuf = nvchan->pb_tail->cur;
- nvchan->pb_tail->cur += (size + 1);
- nvchan->pb_tail->remaining -= (size + 1);
+ pushbuf = chan->pushbuf->cur;
+ chan->pushbuf->cur += (size + 1);
+ chan->pushbuf->remaining -= (size + 1);
(*pushbuf++) = ((grobj->subc << 13) | (size << 18) | mthd);
return pushbuf;
struct nouveau_device *device;
int id;
+ struct nouveau_pushbuf *pushbuf;
+
struct nouveau_grobj *vram;
struct nouveau_grobj *gart;
--- /dev/null
+/*
+ * Copyright 2007 Nouveau Project
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+ * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef __NOUVEAU_PUSHBUF_H__
+#define __NOUVEAU_PUSHBUF_H__
+
+struct nouveau_pushbuf {
+ struct nouveau_channel *channel;
+ unsigned remaining;
+ uint32_t *cur;
+};
+
+#endif