summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOwain Ainsworth <oga@cvs.openbsd.org>2009-03-05 23:13:20 +0000
committerOwain Ainsworth <oga@cvs.openbsd.org>2009-03-05 23:13:20 +0000
commit74bda0dc265c77d54121fd81eff2e117dd94b84f (patch)
treee37db4676fdd5bb625a63040b07b844b88f9bcff
parent858e68db6a84849e08604401cd78424b24e40935 (diff)
Demacro the inteldrm ring macros too, making them use bus_space_write
instead of assuming BUS_SPACE_LINEAR + bus_space_vaddr while i'm at it. Cleans things up nicely, and shaves a little bit of space, too.
-rw-r--r--sys/dev/pci/drm/i915_dma.c144
-rw-r--r--sys/dev/pci/drm/i915_drv.c91
-rw-r--r--sys/dev/pci/drm/i915_drv.h75
-rw-r--r--sys/dev/pci/drm/i915_irq.c3
4 files changed, 162 insertions, 151 deletions
diff --git a/sys/dev/pci/drm/i915_dma.c b/sys/dev/pci/drm/i915_dma.c
index bd607a30413..c70136ec840 100644
--- a/sys/dev/pci/drm/i915_dma.c
+++ b/sys/dev/pci/drm/i915_dma.c
@@ -31,44 +31,6 @@
#include "i915_drm.h"
#include "i915_drv.h"
-/* Really want an OS-independent resettable timer. Would like to have
- * this loop run for (eg) 3 sec, but have the timer reset every time
- * the head pointer changes, so that EBUSY only happens if the ring
- * actually stalls for (eg) 3 seconds.
- */
-int i915_wait_ring(struct drm_device * dev, int n, const char *caller)
-{
- drm_i915_private_t *dev_priv = dev->dev_private;
- drm_i915_ring_buffer_t *ring = &(dev_priv->ring);
- u_int32_t acthd_reg = IS_I965G(dev_priv) ? ACTHD_I965 : ACTHD;
- u_int32_t last_acthd = I915_READ(acthd_reg);
- u_int32_t acthd;
- u_int32_t last_head = I915_READ(PRB0_HEAD) & HEAD_ADDR;
- int i;
-
- for (i = 0; i < 100000; i++) {
- ring->head = I915_READ(PRB0_HEAD) & HEAD_ADDR;
- acthd = I915_READ(acthd_reg);
- ring->space = ring->head - (ring->tail + 8);
- if (ring->space < 0)
- ring->space += ring->Size;
- if (ring->space >= n)
- return 0;
-
- if (ring->head != last_head)
- i = 0;
- if (acthd != last_acthd)
- i = 0;
-
- last_head = ring->head;
- last_acthd = acthd;
- tsleep(dev_priv, PZERO | PCATCH, "i915wt",
- hz / 100);
- }
-
- return EBUSY;
-}
-
/**
* Sets up the hardware status page for devices that need a physical address
* in the register.
@@ -106,7 +68,8 @@ void i915_free_hws(drm_i915_private_t *dev_priv, bus_dma_tag_t dmat)
if (dev_priv->status_gfx_addr) {
dev_priv->status_gfx_addr = 0;
- drm_core_ioremapfree(&dev_priv->hws_map);
+ bus_space_unmap(dev_priv->bst, dev_priv->hws_map.bsh, 4 * 1024);
+ dev_priv->hws_map.bsh = NULL;
}
/* Need to rewrite hardware status page */
@@ -114,27 +77,15 @@ void i915_free_hws(drm_i915_private_t *dev_priv, bus_dma_tag_t dmat)
dev_priv->hw_status_page = NULL;
}
-void i915_kernel_lost_context(struct drm_device * dev)
-{
- drm_i915_private_t *dev_priv = dev->dev_private;
- drm_i915_ring_buffer_t *ring = &(dev_priv->ring);
-
- ring->head = I915_READ(PRB0_HEAD) & HEAD_ADDR;
- ring->tail = I915_READ(PRB0_TAIL) & TAIL_ADDR;
- ring->space = ring->head - (ring->tail + 8);
- if (ring->space < 0)
- ring->space += ring->Size;
-}
-
static int i915_dma_cleanup(struct drm_device * dev)
{
drm_i915_private_t *dev_priv = dev->dev_private;
- if (dev_priv->ring.virtual_start) {
- drm_core_ioremapfree(&dev_priv->ring.map);
- dev_priv->ring.virtual_start = NULL;
- dev_priv->ring.map.handle = NULL;
- dev_priv->ring.map.size = 0;
+ if (dev_priv->ring.bsh != NULL) {
+ bus_space_unmap(dev_priv->bst, dev_priv->ring.bsh,
+ dev_priv->ring.size);
+ dev_priv->ring.bsh = NULL;
+ dev_priv->ring.size = 0;
}
/* Clear the HWS virtual address at teardown */
@@ -146,7 +97,8 @@ static int i915_dma_cleanup(struct drm_device * dev)
static int i915_initialize(struct drm_device * dev, drm_i915_init_t * init)
{
- drm_i915_private_t *dev_priv = dev->dev_private;
+ drm_i915_private_t *dev_priv = dev->dev_private;
+ int ret;
dev_priv->sarea = drm_getsarea(dev);
if (!dev_priv->sarea) {
@@ -164,26 +116,16 @@ static int i915_initialize(struct drm_device * dev, drm_i915_init_t * init)
dev_priv->sarea_priv = NULL;
}
- dev_priv->ring.Size = init->ring_size;
- dev_priv->ring.tail_mask = dev_priv->ring.Size - 1;
-
- dev_priv->ring.map.offset = init->ring_start;
- dev_priv->ring.map.size = init->ring_size;
- dev_priv->ring.map.type = 0;
- dev_priv->ring.map.flags = 0;
- dev_priv->ring.map.mtrr = 0;
-
- drm_core_ioremap(&dev_priv->ring.map, dev);
+ dev_priv->ring.size = init->ring_size;
+ dev_priv->ring.tail_mask = dev_priv->ring.size - 1;
- if (dev_priv->ring.map.handle == NULL) {
+ if ((ret = bus_space_map(dev_priv->bst, init->ring_start,
+ init->ring_size, 0, &dev_priv->ring.bsh)) != 0) {
+ DRM_INFO("can't map ringbuffer\n");
i915_dma_cleanup(dev);
- DRM_ERROR("can not ioremap virtual address for"
- " ring buffer\n");
- return ENOMEM;
+ return (ret);
}
- dev_priv->ring.virtual_start = dev_priv->ring.map.handle;
-
/* Allow hardware batchbuffers unless told otherwise.
*/
dev_priv->allow_batchbuffer = 1;
@@ -202,9 +144,8 @@ static int i915_dma_resume(struct drm_device * dev)
return EINVAL;
}
- if (dev_priv->ring.map.handle == NULL) {
- DRM_ERROR("can not ioremap virtual address for"
- " ring buffer\n");
+ if (dev_priv->ring.bsh == NULL) {
+ DRM_ERROR("dma_resume without mapped ring buffer\n");
return ENOMEM;
}
@@ -333,9 +274,8 @@ static int i915_emit_cmds(struct drm_device *dev, int __user *buffer,
{
drm_i915_private_t *dev_priv = dev->dev_private;
int i;
- RING_LOCALS;
- if ((dwords+1) * sizeof(int) >= dev_priv->ring.Size - 8)
+ if ((dwords + 1) * sizeof(u_int32_t) >= dev_priv->ring.size - 8)
return EINVAL;
BEGIN_LP_RING((dwords+1)&~1);
@@ -374,7 +314,6 @@ static int i915_emit_box(struct drm_device * dev,
{
drm_i915_private_t *dev_priv = dev->dev_private;
struct drm_clip_rect box;
- RING_LOCALS;
if (DRM_COPY_FROM_USER_UNCHECKED(&box, &boxes[i], sizeof(box))) {
return EFAULT;
@@ -414,7 +353,6 @@ static int i915_emit_box(struct drm_device * dev,
void i915_emit_breadcrumb(struct drm_device *dev)
{
drm_i915_private_t *dev_priv = dev->dev_private;
- RING_LOCALS;
if (++dev_priv->counter > BREADCRUMB_MASK) {
dev_priv->counter = 1;
@@ -435,6 +373,7 @@ void i915_emit_breadcrumb(struct drm_device *dev)
static int i915_dispatch_cmdbuffer(struct drm_device * dev,
drm_i915_cmdbuffer_t * cmd)
{
+ struct drm_i915_private *dev_priv = dev->dev_private;
int nbox = cmd->num_cliprects;
int i = 0, count, ret;
@@ -443,7 +382,7 @@ static int i915_dispatch_cmdbuffer(struct drm_device * dev,
return EINVAL;
}
- i915_kernel_lost_context(dev);
+ inteldrm_update_ring(dev_priv);
count = nbox ? nbox : 1;
@@ -471,14 +410,13 @@ int i915_dispatch_batchbuffer(struct drm_device * dev,
struct drm_clip_rect __user *boxes = batch->cliprects;
int nbox = batch->num_cliprects;
int i = 0, count;
- RING_LOCALS;
if ((batch->start | batch->used) & 0x7) {
DRM_ERROR("alignment\n");
return EINVAL;
}
- i915_kernel_lost_context(dev);
+ inteldrm_update_ring(dev_priv);
count = nbox ? nbox : 1;
@@ -515,23 +453,17 @@ int i915_dispatch_batchbuffer(struct drm_device * dev,
return 0;
}
-int i915_quiescent(struct drm_device *dev)
-{
- drm_i915_private_t *dev_priv = dev->dev_private;
-
- i915_kernel_lost_context(dev);
- return i915_wait_ring(dev, dev_priv->ring.Size - 8, __func__);
-}
-
int i915_flush_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv)
{
- int ret;
+ drm_i915_private_t *dev_priv = dev->dev_private;
+ int ret;
LOCK_TEST_WITH_RETURN(dev, file_priv);
DRM_LOCK();
- ret = i915_quiescent(dev);
+ inteldrm_update_ring(dev_priv);
+ ret = inteldrm_wait_ring(dev_priv, dev_priv->ring.size - 8);
DRM_UNLOCK();
return (ret);
@@ -678,8 +610,9 @@ int i915_setparam(struct drm_device *dev, void *data,
int i915_set_status_page(struct drm_device *dev, void *data,
struct drm_file *file_priv)
{
- drm_i915_private_t *dev_priv = dev->dev_private;
- drm_i915_hws_addr_t *hws = data;
+ drm_i915_private_t *dev_priv = dev->dev_private;
+ drm_i915_hws_addr_t *hws = data;
+ int ret;
if (!I915_NEED_GFX_HWS(dev_priv))
return EINVAL;
@@ -693,20 +626,23 @@ int i915_set_status_page(struct drm_device *dev, void *data,
dev_priv->status_gfx_addr = hws->addr & (0x1ffff<<12);
dev_priv->hws_map.offset = dev->agp->base + hws->addr;
+ if (dev_priv->hws_map.offset > (dev->agp->base +
+ dev->agp->info.ai_aperture_size)) {
+ DRM_INFO("tried to map hws past end of aperture!\n");
+ return (EINVAL);
+ }
dev_priv->hws_map.size = 4*1024;
- dev_priv->hws_map.type = 0;
- dev_priv->hws_map.flags = 0;
- dev_priv->hws_map.mtrr = 0;
- drm_core_ioremap(&dev_priv->hws_map, dev);
- if (dev_priv->hws_map.handle == NULL) {
+ if ((ret = bus_space_map(dev_priv->bst, dev_priv->hws_map.offset,
+ dev_priv->hws_map.size, BUS_SPACE_MAP_LINEAR,
+ &dev_priv->hws_map.bsh)) != 0) {
+ DRM_INFO("can't hws page\n");
i915_dma_cleanup(dev);
dev_priv->status_gfx_addr = 0;
- DRM_ERROR("can not ioremap virtual address for"
- " G33 hw status page\n");
- return ENOMEM;
+ return (ret);
}
- dev_priv->hw_status_page = dev_priv->hws_map.handle;
+ dev_priv->hw_status_page = bus_space_vaddr(dev_priv->bst,
+ dev_priv->hws_map.bsh);
memset(dev_priv->hw_status_page, 0, PAGE_SIZE);
I915_WRITE(HWS_PGA, dev_priv->status_gfx_addr);
diff --git a/sys/dev/pci/drm/i915_drv.c b/sys/dev/pci/drm/i915_drv.c
index 96ec2ce995a..5b6c53e247b 100644
--- a/sys/dev/pci/drm/i915_drv.c
+++ b/sys/dev/pci/drm/i915_drv.c
@@ -2,6 +2,7 @@
* Created: Wed Feb 14 17:10:04 2001 by gareth@valinux.com
*/
/*-
+ * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas.
* Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
* All Rights Reserved.
*
@@ -131,7 +132,10 @@ inteldrm_attach(struct device *parent, struct device *self, void *aux)
PCI_PRODUCT(pa->pa_id), inteldrm_pciidlist);
dev_priv->flags = id_entry->driver_private;
dev_priv->pci_device = PCI_PRODUCT(pa->pa_id);
+
dev_priv->pc = pa->pa_pc;
+ dev_priv->dmat = pa->pa_dmat;
+ dev_priv->bst = pa->pa_memt;
/* Add register map (needed for suspend/resume) */
bar = vga_pci_bar_info((struct vga_pci_softc *)parent,
@@ -266,3 +270,90 @@ inteldrm_read_hws(struct drm_i915_private *dev_priv, int reg)
PAGE_SIZE, BUS_DMASYNC_PREREAD);
return (val);
}
+
+/*
+ * These five ring manipulation functions are protected by dev->dev_lock.
+ */
+int
+inteldrm_wait_ring(struct drm_i915_private *dev_priv, int n)
+{
+ struct inteldrm_ring *ring = &dev_priv->ring;
+ u_int32_t acthd_reg, acthd, last_acthd, last_head;
+ int i;
+
+ acthd_reg = IS_I965G(dev_priv) ? ACTHD_I965 : ACTHD;
+ last_head = I915_READ(PRB0_HEAD) & HEAD_ADDR;
+ last_acthd = I915_READ(acthd_reg);
+
+ /* ugh. Could really do with a proper, resettable timer here. */
+ for (i = 0; i < 100000; i++) {
+ ring->head = I915_READ(PRB0_HEAD) & HEAD_ADDR;
+ acthd = I915_READ(acthd_reg);
+ ring->space = ring->head - (ring->tail + 8);
+
+ INTELDRM_VPRINTF("%s: head: %x tail: %x space: %x\n", __func__,
+ ring->head, ring->tail, ring->space);
+ if (ring->space < 0)
+ ring->space += ring->size;
+ if (ring->space >= n)
+ return (0);
+
+ /* Only timeout if the ring isn't chewing away on something */
+ if (ring->head != last_head || acthd != last_acthd)
+ i = 0;
+
+ last_head = ring->head;
+ last_acthd = acthd;
+ tsleep(dev_priv, PZERO | PCATCH, "i915wt",
+ hz / 100);
+ }
+
+ return (EBUSY);
+}
+
+void
+inteldrm_begin_ring(struct drm_i915_private *dev_priv, int ncmd)
+{
+ INTELDRM_VPRINTF("%s: %d\n", __func__, ncmd);
+ if (dev_priv->ring.space < ncmd * 4)
+ inteldrm_wait_ring(dev_priv, ncmd * 4);
+ dev_priv->ring.wspace = 0;
+ dev_priv->ring.woffset = dev_priv->ring.tail;
+}
+
+void
+inteldrm_out_ring(struct drm_i915_private *dev_priv, u_int32_t cmd)
+{
+ INTELDRM_VPRINTF("%s: %x\n", __func__, cmd);
+ bus_space_write_4(dev_priv->bst, dev_priv->ring.bsh,
+ dev_priv->ring.woffset, cmd);
+ dev_priv->ring.wspace++;
+ /* deal with ring wrapping */
+ dev_priv->ring.woffset += 4;
+ dev_priv->ring.woffset &= dev_priv->ring.tail_mask;
+}
+
+void
+inteldrm_advance_ring(struct drm_i915_private *dev_priv)
+{
+ INTELDRM_VPRINTF("%s: %x, %x\n", __func__, dev_priv->ring.wspace,
+ dev_priv->ring.woffset);
+ dev_priv->ring.tail = dev_priv->ring.woffset;
+ dev_priv->ring.space -= dev_priv->ring.wspace * 4;
+ I915_WRITE(PRB0_TAIL, dev_priv->ring.woffset);
+}
+
+void
+inteldrm_update_ring(struct drm_i915_private *dev_priv)
+{
+ struct inteldrm_ring *ring = &dev_priv->ring;
+
+ ring->head = (I915_READ(PRB0_HEAD) & HEAD_ADDR);
+ ring->tail = (I915_READ(PRB0_TAIL) & TAIL_ADDR);
+ ring->space = ring->head - (ring->tail + 8);
+ if (ring->space < 0)
+ ring->space += ring->size;
+ INTELDRM_VPRINTF("%s: head: %x tail: %x space: %x\n", __func__,
+ ring->head, ring->tail, ring->space);
+}
+
diff --git a/sys/dev/pci/drm/i915_drv.h b/sys/dev/pci/drm/i915_drv.h
index e3e4cdfce81..518655c41d3 100644
--- a/sys/dev/pci/drm/i915_drv.h
+++ b/sys/dev/pci/drm/i915_drv.h
@@ -58,20 +58,23 @@ enum pipe {
#define DRIVER_MINOR 6
#define DRIVER_PATCHLEVEL 0
-typedef struct _drm_i915_ring_buffer {
- int tail_mask;
- unsigned long Size;
- u8 *virtual_start;
- int head;
- int tail;
- int space;
- drm_local_map_t map;
-} drm_i915_ring_buffer_t;
+struct inteldrm_ring {
+ u_int32_t *kva;
+ bus_space_handle_t bsh;
+ bus_size_t size;
+ u_int32_t head;
+ u_int32_t space;
+ u_int32_t tail;
+ u_int32_t tail_mask;
+ u_int32_t woffset;
+ u_int32_t wspace;
+};
typedef struct drm_i915_private {
struct device dev;
struct device *drmdev;
bus_dma_tag_t dmat;
+ bus_space_tag_t bst;
u_long flags;
u_int16_t pci_device;
@@ -85,7 +88,7 @@ typedef struct drm_i915_private {
drm_local_map_t *sarea;
drm_i915_sarea_t *sarea_priv;
- drm_i915_ring_buffer_t ring;
+ struct inteldrm_ring ring;
drm_local_map_t hws_map;
struct drm_dmamem *hws_dmamem;
void *hw_status_page;
@@ -213,9 +216,14 @@ typedef struct drm_i915_private {
#define CHIP_M 0x4000
#define CHIP_HWS 0x8000
- /* i915_dma.c */
u_int32_t inteldrm_read_hws(struct drm_i915_private *, int);
-extern void i915_kernel_lost_context(struct drm_device * dev);
+int inteldrm_wait_ring(struct drm_i915_private *dev, int n);
+void inteldrm_begin_ring(struct drm_i915_private *, int);
+void inteldrm_out_ring(struct drm_i915_private *, u_int32_t);
+void inteldrm_advance_ring(struct drm_i915_private *);
+void inteldrm_update_ring(struct drm_i915_private *);
+
+ /* i915_dma.c */
extern void i915_driver_lastclose(struct drm_device * dev);
extern void i915_driver_close(struct drm_device *dev,
struct drm_file *file_priv);
@@ -226,7 +234,6 @@ extern void i915_emit_breadcrumb(struct drm_device *dev);
extern int i915_driver_firstopen(struct drm_device *dev);
extern int i915_dispatch_batchbuffer(struct drm_device * dev,
drm_i915_batchbuffer_t * batch);
-extern int i915_quiescent(struct drm_device *dev);
int i915_init_phys_hws(drm_i915_private_t *, bus_dma_tag_t);
void i915_free_hws(drm_i915_private_t *, bus_dma_tag_t);
@@ -289,38 +296,16 @@ extern int i915_set_status_page(struct drm_device *, void *, struct drm_file *);
#define I915_WRITE8(reg,val) bus_space_write_1(dev_priv->regs->bst, \
dev_priv->regs->bsh, (reg), (val))
-#define I915_VERBOSE 0
-
-#define RING_LOCALS unsigned int outring, ringmask, outcount; \
- volatile char *virt;
-
-#define BEGIN_LP_RING(n) do { \
- if (I915_VERBOSE) \
- DRM_DEBUG("BEGIN_LP_RING(%d)\n", (n)); \
- if (dev_priv->ring.space < (n)*4) \
- i915_wait_ring(dev, (n)*4, __func__); \
- outcount = 0; \
- outring = dev_priv->ring.tail; \
- ringmask = dev_priv->ring.tail_mask; \
- virt = dev_priv->ring.virtual_start; \
-} while (0)
-
-#define OUT_RING(n) do { \
- if (I915_VERBOSE) DRM_DEBUG(" OUT_RING %x\n", (int)(n)); \
- *(volatile unsigned int *)(virt + outring) = (n); \
- outcount++; \
- outring += 4; \
- outring &= ringmask; \
-} while (0)
-
-#define ADVANCE_LP_RING() do { \
- if (I915_VERBOSE) DRM_DEBUG("ADVANCE_LP_RING %x\n", outring); \
- dev_priv->ring.tail = outring; \
- dev_priv->ring.space -= outcount * 4; \
- I915_WRITE(PRB0_TAIL, outring); \
-} while(0)
-
-extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller);
+#define INTELDRM_VERBOSE 0
+#if INTELDRM_VERBOSE > 0
+#define INTELDRM_VPRINTF(fmt, args...) DRM_INFO(fmt, ##args)
+#else
+#define INTELDRM_VPRINTF(fmt, args...)
+#endif
+
+#define BEGIN_LP_RING(n) inteldrm_begin_ring(dev_priv, n)
+#define OUT_RING(n) inteldrm_out_ring(dev_priv, n)
+#define ADVANCE_LP_RING() inteldrm_advance_ring(dev_priv)
/*
* The Bridge device's PCI config space has information about the
diff --git a/sys/dev/pci/drm/i915_irq.c b/sys/dev/pci/drm/i915_irq.c
index 9d6960ab024..0fbebf71413 100644
--- a/sys/dev/pci/drm/i915_irq.c
+++ b/sys/dev/pci/drm/i915_irq.c
@@ -245,9 +245,8 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
int i915_emit_irq(struct drm_device *dev)
{
drm_i915_private_t *dev_priv = dev->dev_private;
- RING_LOCALS;
- i915_kernel_lost_context(dev);
+ inteldrm_update_ring(dev_priv);
DRM_DEBUG("\n");