summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--linux-core/Makefile.kernel2
-rw-r--r--linux-core/drm_bo.c2
-rw-r--r--linux-core/drm_bo_move.c1
-rw-r--r--linux-core/drm_memory.c1
-rw-r--r--linux-core/i915_buffer.c68
-rw-r--r--linux-core/i915_drv.c8
l---------linux-core/i915_hwz.c1
-rw-r--r--shared-core/i915_dma.c156
-rw-r--r--shared-core/i915_drm.h33
-rw-r--r--shared-core/i915_drv.h77
-rw-r--r--shared-core/i915_hwz.c959
-rw-r--r--shared-core/i915_irq.c54
12 files changed, 1260 insertions, 102 deletions
diff --git a/linux-core/Makefile.kernel b/linux-core/Makefile.kernel
index ac77941e..aa3674b0 100644
--- a/linux-core/Makefile.kernel
+++ b/linux-core/Makefile.kernel
@@ -19,7 +19,7 @@ r128-objs := r128_drv.o r128_cce.o r128_state.o r128_irq.o
mga-objs := mga_drv.o mga_dma.o mga_state.o mga_warp.o mga_irq.o
i810-objs := i810_drv.o i810_dma.o
i915-objs := i915_drv.o i915_dma.o i915_irq.o i915_mem.o i915_fence.o \
- i915_buffer.o
+ i915_buffer.o i915_hwz.o
nouveau-objs := nouveau_drv.o nouveau_state.o nouveau_fifo.o nouveau_mem.o \
nouveau_object.o nouveau_irq.o nouveau_notifier.o \
nouveau_sgdma.o nouveau_dma.o \
diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c
index 4c2b1541..cb11dff4 100644
--- a/linux-core/drm_bo.c
+++ b/linux-core/drm_bo.c
@@ -504,6 +504,7 @@ void drm_bo_usage_deref_locked(struct drm_buffer_object ** bo)
drm_bo_destroy_locked(tmp_bo);
}
}
+EXPORT_SYMBOL(drm_bo_usage_deref_locked);
static void drm_bo_base_deref_locked(struct drm_file * file_priv,
struct drm_user_object * uo)
@@ -1490,6 +1491,7 @@ static int drm_buffer_object_validate(struct drm_buffer_object * bo,
return 0;
}
+EXPORT_SYMBOL(drm_buffer_object_validate);
static int drm_bo_handle_validate(struct drm_file *file_priv,
uint32_t handle,
diff --git a/linux-core/drm_bo_move.c b/linux-core/drm_bo_move.c
index 1a613916..21ab4bbb 100644
--- a/linux-core/drm_bo_move.c
+++ b/linux-core/drm_bo_move.c
@@ -151,6 +151,7 @@ void drm_mem_reg_iounmap(struct drm_device * dev, struct drm_bo_mem_reg * mem,
iounmap(virtual);
}
}
+EXPORT_SYMBOL(drm_mem_reg_iounmap);
static int drm_copy_io_page(void *dst, void *src, unsigned long page)
{
diff --git a/linux-core/drm_memory.c b/linux-core/drm_memory.c
index f68a3a3e..2f933c32 100644
--- a/linux-core/drm_memory.c
+++ b/linux-core/drm_memory.c
@@ -152,6 +152,7 @@ void *drm_realloc(void *oldpt, size_t oldsize, size_t size, int area)
}
return pt;
}
+EXPORT_SYMBOL(drm_realloc);
/**
* Allocate pages.
diff --git a/linux-core/i915_buffer.c b/linux-core/i915_buffer.c
index bf500cc6..84bd47fc 100644
--- a/linux-core/i915_buffer.c
+++ b/linux-core/i915_buffer.c
@@ -63,9 +63,50 @@ int i915_invalidate_caches(struct drm_device * dev, uint64_t flags)
return i915_emit_mi_flush(dev, flush_cmd);
}
+#define PRIV1_ORDER 8
+#define PRIV1_SIZE ((1 << PRIV1_ORDER) * PAGE_SIZE)
+
+int i915_init_priv1(struct drm_device * dev)
+{
+ drm_i915_private_t *dev_priv = dev->dev_private;
+ int ret;
+
+ if (dev_priv->priv1_addr)
+ return 0;
+
+ dev_priv->priv1_addr = __get_free_pages(__GFP_NOFAIL | __GFP_HIGH,
+ PRIV1_ORDER);
+
+ if (!dev_priv->priv1_addr) {
+ DRM_ERROR("Failed to get %lu bytes of physically "
+ "contiguous memory for PRIV1 type\n", PRIV1_SIZE);
+ return -ENOMEM;
+ } else
+ DRM_INFO("PRIV1 virtual 0x%lx physical 0x%lx\n",
+ dev_priv->priv1_addr,
+ virt_to_phys((void*)dev_priv->priv1_addr));
+
+ dev_priv->priv1_order = PRIV1_ORDER;
+
+ ret = drm_bo_init_mm(dev, DRM_BO_MEM_PRIV1,
+ virt_to_phys((void*)dev_priv->priv1_addr)
+ >> PAGE_SHIFT, (1 << dev_priv->priv1_order));
+
+ if (ret) {
+ DRM_ERROR("Failed to initialize PRIV1 memory manager\n");
+ free_pages(dev_priv->priv1_addr, dev_priv->priv1_order);
+ dev_priv->priv1_addr = 0;
+ return ret;
+ }
+
+ return 0;
+}
+
int i915_init_mem_type(struct drm_device * dev, uint32_t type,
struct drm_mem_type_manager * man)
{
+ drm_i915_private_t *dev_priv = dev->dev_private;
+
switch (type) {
case DRM_BO_MEM_LOCAL:
man->flags = _DRM_FLAG_MEMTYPE_MAPPABLE |
@@ -84,6 +125,7 @@ int i915_init_mem_type(struct drm_device * dev, uint32_t type,
man->flags = _DRM_FLAG_MEMTYPE_MAPPABLE |
_DRM_FLAG_MEMTYPE_CSELECT | _DRM_FLAG_NEEDS_IOREMAP;
man->drm_bus_maptype = _DRM_AGP;
+ i915_init_priv1(dev);
break;
case DRM_BO_MEM_PRIV0:
if (!(drm_core_has_AGP(dev) && dev->agp)) {
@@ -98,6 +140,19 @@ int i915_init_mem_type(struct drm_device * dev, uint32_t type,
_DRM_FLAG_MEMTYPE_FIXED | _DRM_FLAG_NEEDS_IOREMAP;
man->drm_bus_maptype = _DRM_AGP;
break;
+ case DRM_BO_MEM_PRIV1:
+ if (!dev_priv) {
+ DRM_ERROR("called without initialization\n");
+ return -EINVAL;
+ }
+ man->io_offset = 0;
+ man->io_size = (1 << dev_priv->priv1_order) << PAGE_SHIFT;
+ man->io_addr = (void*)dev_priv->priv1_addr;
+ man->io_addr -= virt_to_phys(man->io_addr);
+ man->flags = _DRM_FLAG_MEMTYPE_MAPPABLE |
+ _DRM_FLAG_MEMTYPE_FIXED;
+ man->drm_bus_maptype = _DRM_TTM;
+ break;
default:
DRM_ERROR("Unsupported memory type %u\n", (unsigned)type);
return -EINVAL;
@@ -108,6 +163,7 @@ int i915_init_mem_type(struct drm_device * dev, uint32_t type,
uint32_t i915_evict_mask(struct drm_buffer_object *bo)
{
switch (bo->mem.mem_type) {
+ case DRM_BO_MEM_PRIV1:
case DRM_BO_MEM_LOCAL:
case DRM_BO_MEM_TT:
return DRM_BO_FLAG_MEM_LOCAL;
@@ -129,14 +185,14 @@ static void i915_emit_copy_blit(struct drm_device * dev,
if (!dev_priv)
return;
- i915_kernel_lost_context(dev);
+ i915_kernel_lost_context(dev_priv, &dev_priv->ring);
while (pages > 0) {
cur_pages = pages;
if (cur_pages > 2048)
cur_pages = 2048;
pages -= cur_pages;
- BEGIN_LP_RING(6);
+ BEGIN_RING(&dev_priv->ring, 6);
OUT_RING(SRC_COPY_BLT_CMD | XY_SRC_COPY_BLT_WRITE_ALPHA |
XY_SRC_COPY_BLT_WRITE_RGB);
OUT_RING((stride & 0xffff) | (0xcc << 16) | (1 << 24) |
@@ -145,7 +201,7 @@ static void i915_emit_copy_blit(struct drm_device * dev,
OUT_RING(dst_offset);
OUT_RING(stride & 0xffff);
OUT_RING(src_offset);
- ADVANCE_LP_RING();
+ ADVANCE_RING();
}
return;
}
@@ -156,6 +212,9 @@ static int i915_move_blit(struct drm_buffer_object * bo,
struct drm_bo_mem_reg *old_mem = &bo->mem;
int dir = 0;
+ if (new_mem->mem_type == DRM_BO_MEM_PRIV1)
+ return -EINVAL;
+
if ((old_mem->mem_type == new_mem->mem_type) &&
(new_mem->mm_node->start <
old_mem->mm_node->start + old_mem->mm_node->size)) {
@@ -221,7 +280,8 @@ int i915_move(struct drm_buffer_object * bo,
{
struct drm_bo_mem_reg *old_mem = &bo->mem;
- if (old_mem->mem_type == DRM_BO_MEM_LOCAL) {
+ if (old_mem->mem_type == DRM_BO_MEM_LOCAL || old_mem->mem_type ==
+ DRM_BO_MEM_PRIV1) {
return drm_bo_move_memcpy(bo, evict, no_wait, new_mem);
} else if (new_mem->mem_type == DRM_BO_MEM_LOCAL) {
if (i915_move_flip(bo, evict, no_wait, new_mem))
diff --git a/linux-core/i915_drv.c b/linux-core/i915_drv.c
index e337e1d2..daf94eb2 100644
--- a/linux-core/i915_drv.c
+++ b/linux-core/i915_drv.c
@@ -52,8 +52,10 @@ static struct drm_fence_driver i915_fence_driver = {
#endif
#ifdef I915_HAVE_BUFFER
-static uint32_t i915_mem_prios[] = {DRM_BO_MEM_PRIV0, DRM_BO_MEM_TT, DRM_BO_MEM_LOCAL};
-static uint32_t i915_busy_prios[] = {DRM_BO_MEM_TT, DRM_BO_MEM_PRIV0, DRM_BO_MEM_LOCAL};
+static uint32_t i915_mem_prios[] = {DRM_BO_MEM_PRIV0, DRM_BO_MEM_TT,
+ DRM_BO_MEM_LOCAL, DRM_BO_MEM_PRIV1};
+static uint32_t i915_busy_prios[] = {DRM_BO_MEM_TT, DRM_BO_MEM_PRIV0,
+ DRM_BO_MEM_LOCAL, DRM_BO_MEM_PRIV1};
static struct drm_bo_driver i915_bo_driver = {
.mem_type_prio = i915_mem_prios,
@@ -81,6 +83,8 @@ static struct drm_driver driver = {
.load = i915_driver_load,
.firstopen = i915_driver_firstopen,
.lastclose = i915_driver_lastclose,
+ .open = i915_driver_open,
+ .postclose = i915_driver_postclose,
.preclose = i915_driver_preclose,
.device_is_agp = i915_driver_device_is_agp,
.vblank_wait = i915_driver_vblank_wait,
diff --git a/linux-core/i915_hwz.c b/linux-core/i915_hwz.c
new file mode 120000
index 00000000..6b3ccc07
--- /dev/null
+++ b/linux-core/i915_hwz.c
@@ -0,0 +1 @@
+../shared-core/i915_hwz.c \ No newline at end of file
diff --git a/shared-core/i915_dma.c b/shared-core/i915_dma.c
index 9f18feee..eee560e9 100644
--- a/shared-core/i915_dma.c
+++ b/shared-core/i915_dma.c
@@ -47,15 +47,14 @@
* 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)
+int i915_wait_ring(drm_i915_private_t *dev_priv, drm_i915_ring_buffer_t *ring,
+ int n, const char *caller)
{
- drm_i915_private_t *dev_priv = dev->dev_private;
- drm_i915_ring_buffer_t *ring = &(dev_priv->ring);
- u32 last_head = I915_READ(LP_RING + RING_HEAD) & HEAD_ADDR;
+ u32 last_head = I915_READ(ring->reg + RING_HEAD) & HEAD_ADDR;
int i;
for (i = 0; i < 10000; i++) {
- ring->head = I915_READ(LP_RING + RING_HEAD) & HEAD_ADDR;
+ ring->head = I915_READ(ring->reg + RING_HEAD) & HEAD_ADDR;
ring->space = ring->head - (ring->tail + 8);
if (ring->space < 0)
ring->space += ring->Size;
@@ -74,13 +73,11 @@ int i915_wait_ring(struct drm_device * dev, int n, const char *caller)
return -EBUSY;
}
-void i915_kernel_lost_context(struct drm_device * dev)
+void i915_kernel_lost_context(drm_i915_private_t * dev_priv,
+ drm_i915_ring_buffer_t *ring)
{
- drm_i915_private_t *dev_priv = dev->dev_private;
- drm_i915_ring_buffer_t *ring = &(dev_priv->ring);
-
- ring->head = I915_READ(LP_RING + RING_HEAD) & HEAD_ADDR;
- ring->tail = I915_READ(LP_RING + RING_TAIL) & TAIL_ADDR;
+ ring->head = I915_READ(ring->reg + RING_HEAD) & HEAD_ADDR;
+ ring->tail = I915_READ(ring->reg + RING_TAIL) & TAIL_ADDR;
ring->space = ring->head - (ring->tail + 8);
if (ring->space < 0)
ring->space += ring->Size;
@@ -105,12 +102,18 @@ static int i915_dma_cleanup(struct drm_device * dev)
if (dev_priv->ring.virtual_start) {
drm_core_ioremapfree(&dev_priv->ring.map, dev);
}
+ if (dev_priv->hwb_ring.virtual_start) {
+ drm_core_ioremapfree(&dev_priv->hwb_ring.map, dev);
+ }
if (dev_priv->status_page_dmah) {
drm_pci_free(dev, dev_priv->status_page_dmah);
/* Need to rewrite hardware status page */
I915_WRITE(0x02080, 0x1ffff000);
}
+
+ i915_bmp_free(dev);
+
if (dev_priv->status_gfx_addr) {
dev_priv->status_gfx_addr = 0;
drm_core_ioremapfree(&dev_priv->hws_map, dev);
@@ -125,6 +128,33 @@ static int i915_dma_cleanup(struct drm_device * dev)
return 0;
}
+int i915_init_ring(struct drm_device * dev, drm_i915_ring_buffer_t * ring,
+ unsigned start, unsigned end, unsigned size, u32 reg)
+{
+ ring->Start = start;
+ ring->End = end;
+ ring->Size = size;
+ ring->tail_mask = ring->Size - 1;
+
+ ring->map.offset = start;
+ ring->map.size = size;
+ ring->map.type = 0;
+ ring->map.flags = 0;
+ ring->map.mtrr = 0;
+
+ drm_core_ioremap(&ring->map, dev);
+
+ if (ring->map.handle == NULL) {
+ DRM_ERROR("can not ioremap virtual address for ring buffer\n");
+ return -ENOMEM;
+ }
+
+ ring->virtual_start = ring->map.handle;
+ ring->reg = reg;
+
+ return 0;
+}
+
static int i915_initialize(struct drm_device * dev,
drm_i915_private_t * dev_priv,
drm_i915_init_t * init)
@@ -150,29 +180,14 @@ static int i915_initialize(struct drm_device * dev,
dev_priv->sarea_priv = (drm_i915_sarea_t *)
((u8 *) dev_priv->sarea->handle + init->sarea_priv_offset);
- dev_priv->ring.Start = init->ring_start;
- dev_priv->ring.End = init->ring_end;
- 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);
-
- if (dev_priv->ring.map.handle == NULL) {
+ if (i915_init_ring(dev, &dev_priv->ring, init->ring_start,
+ init->ring_end, init->ring_size, LP_RING)) {
dev->dev_private = (void *)dev_priv;
i915_dma_cleanup(dev);
- DRM_ERROR("can not ioremap virtual address for"
- " ring buffer\n");
+ DRM_ERROR("Failed to initialize LP ring buffer\n");
return -ENOMEM;
}
- dev_priv->ring.virtual_start = dev_priv->ring.map.handle;
-
dev_priv->cpp = init->cpp;
dev_priv->sarea_priv->pf_current_page = 0;
@@ -365,7 +380,7 @@ static int i915_emit_cmds(struct drm_device * dev, int __user * buffer,
if ((dwords+1) * sizeof(int) >= dev_priv->ring.Size - 8)
return -EINVAL;
- BEGIN_LP_RING((dwords+1)&~1);
+ BEGIN_RING(&dev_priv->ring, (dwords+1)&~1);
for (i = 0; i < dwords;) {
int cmd, sz;
@@ -390,7 +405,7 @@ static int i915_emit_cmds(struct drm_device * dev, int __user * buffer,
if (dwords & 1)
OUT_RING(0);
- ADVANCE_LP_RING();
+ ADVANCE_RING();
return 0;
}
@@ -414,21 +429,21 @@ static int i915_emit_box(struct drm_device * dev,
}
if (IS_I965G(dev)) {
- BEGIN_LP_RING(4);
+ BEGIN_RING(&dev_priv->ring, 4);
OUT_RING(GFX_OP_DRAWRECT_INFO_I965);
OUT_RING((box.x1 & 0xffff) | (box.y1 << 16));
OUT_RING(((box.x2 - 1) & 0xffff) | ((box.y2 - 1) << 16));
OUT_RING(DR4);
- ADVANCE_LP_RING();
+ ADVANCE_RING();
} else {
- BEGIN_LP_RING(6);
+ BEGIN_RING(&dev_priv->ring, 6);
OUT_RING(GFX_OP_DRAWRECT_INFO);
OUT_RING(DR1);
OUT_RING((box.x1 & 0xffff) | (box.y1 << 16));
OUT_RING(((box.x2 - 1) & 0xffff) | ((box.y2 - 1) << 16));
OUT_RING(DR4);
OUT_RING(0);
- ADVANCE_LP_RING();
+ ADVANCE_RING();
}
return 0;
@@ -450,12 +465,12 @@ void i915_emit_breadcrumb(struct drm_device *dev)
dev_priv->sarea_priv->last_enqueue = dev_priv->counter;
- BEGIN_LP_RING(4);
+ BEGIN_RING(&dev_priv->ring, 4);
OUT_RING(CMD_STORE_DWORD_IDX);
- OUT_RING(20);
+ OUT_RING(16 << 2);
OUT_RING(dev_priv->counter);
OUT_RING(0);
- ADVANCE_LP_RING();
+ ADVANCE_RING();
}
@@ -467,14 +482,14 @@ int i915_emit_mi_flush(struct drm_device *dev, uint32_t flush)
flush_cmd |= flush;
- i915_kernel_lost_context(dev);
+ i915_kernel_lost_context(dev_priv, &dev_priv->ring);
- BEGIN_LP_RING(4);
+ BEGIN_RING(&dev_priv->ring, 4);
OUT_RING(flush_cmd);
OUT_RING(0);
OUT_RING(0);
OUT_RING(0);
- ADVANCE_LP_RING();
+ ADVANCE_RING();
return 0;
}
@@ -494,7 +509,7 @@ static int i915_dispatch_cmdbuffer(struct drm_device * dev,
return -EINVAL;
}
- i915_kernel_lost_context(dev);
+ i915_kernel_lost_context(dev_priv, &dev_priv->ring);
count = nbox ? nbox : 1;
@@ -532,7 +547,7 @@ static int i915_dispatch_batchbuffer(struct drm_device * dev,
return -EINVAL;
}
- i915_kernel_lost_context(dev);
+ i915_kernel_lost_context(dev_priv, &dev_priv->ring);
count = nbox ? nbox : 1;
@@ -545,7 +560,7 @@ static int i915_dispatch_batchbuffer(struct drm_device * dev,
}
if (dev_priv->use_mi_batchbuffer_start) {
- BEGIN_LP_RING(2);
+ BEGIN_RING(&dev_priv->ring, 2);
if (IS_I965G(dev)) {
OUT_RING(MI_BATCH_BUFFER_START | (2 << 6) | MI_BATCH_NON_SECURE_I965);
OUT_RING(batch->start);
@@ -553,15 +568,14 @@ static int i915_dispatch_batchbuffer(struct drm_device * dev,
OUT_RING(MI_BATCH_BUFFER_START | (2 << 6));
OUT_RING(batch->start | MI_BATCH_NON_SECURE);
}
- ADVANCE_LP_RING();
-
+ ADVANCE_RING();
} else {
- BEGIN_LP_RING(4);
+ BEGIN_RING(&dev_priv->ring, 4);
OUT_RING(MI_BATCH_BUFFER);
OUT_RING(batch->start | MI_BATCH_NON_SECURE);
OUT_RING(batch->start + batch->used - 4);
OUT_RING(0);
- ADVANCE_LP_RING();
+ ADVANCE_RING();
}
}
@@ -610,7 +624,7 @@ static void i915_do_dispatch_flip(struct drm_device * dev, int pipe, int sync)
DRM_DEBUG("pipe=%d current_page=%d dspbase=0x%x\n", pipe, current_page,
dspbase);
- BEGIN_LP_RING(4);
+ BEGIN_RING(&dev_priv->ring, 4);
OUT_RING(sync ? 0 :
(MI_WAIT_FOR_EVENT | (pipe ? MI_WAIT_FOR_PLANE_B_FLIP :
MI_WAIT_FOR_PLANE_A_FLIP)));
@@ -618,7 +632,7 @@ static void i915_do_dispatch_flip(struct drm_device * dev, int pipe, int sync)
(pipe ? DISPLAY_PLANE_B : DISPLAY_PLANE_A));
OUT_RING(dev_priv->sarea_priv->pitch * dev_priv->cpp);
OUT_RING(dspbase);
- ADVANCE_LP_RING();
+ ADVANCE_RING();
dev_priv->sarea_priv->pf_current_page &= ~(0x3 << shift);
dev_priv->sarea_priv->pf_current_page |= next_page << shift;
@@ -650,8 +664,9 @@ static 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, __FUNCTION__);
+ i915_kernel_lost_context(dev_priv, &dev_priv->ring);
+ return i915_wait_ring(dev_priv, &dev_priv->ring, dev_priv->ring.Size - 8,
+ __FUNCTION__);
}
static int i915_flush_ioctl(struct drm_device *dev, void *data,
@@ -944,7 +959,13 @@ void i915_driver_lastclose(struct drm_device * dev)
if (dev->dev_private) {
drm_i915_private_t *dev_priv = dev->dev_private;
i915_do_cleanup_pageflip(dev);
+ i915_bmp_free(dev);
i915_mem_takedown(&(dev_priv->agp_heap));
+
+ if (dev_priv->priv1_addr) {
+ free_pages(dev_priv->priv1_addr, dev_priv->priv1_order);
+ dev_priv->priv1_addr = 0;
+ }
}
i915_dma_cleanup(dev);
}
@@ -954,6 +975,7 @@ void i915_driver_preclose(struct drm_device * dev, struct drm_file *file_priv)
if (dev->dev_private) {
drm_i915_private_t *dev_priv = dev->dev_private;
i915_mem_release(dev, file_priv, dev_priv->agp_heap);
+ i915_hwz_free(dev, file_priv->driver_priv);
}
}
@@ -976,6 +998,7 @@ struct drm_ioctl_desc i915_ioctls[] = {
DRM_IOCTL_DEF(DRM_I915_VBLANK_SWAP, i915_vblank_swap, DRM_AUTH),
DRM_IOCTL_DEF(DRM_I915_MMIO, i915_mmio, DRM_AUTH),
DRM_IOCTL_DEF(DRM_I915_HWS_ADDR, i915_set_status_page, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_I915_HWZ, i915_hwz, DRM_AUTH),
};
int i915_max_ioctl = DRM_ARRAY_SIZE(i915_ioctls);
@@ -1003,3 +1026,32 @@ int i915_driver_firstopen(struct drm_device *dev)
#endif
return 0;
}
+
+int i915_driver_open(struct drm_device *dev, struct drm_file *filp_priv)
+{
+ drm_i915_private_t *dev_priv = dev->dev_private;
+
+ DRM_DEBUG("\n");
+
+ filp_priv->driver_priv = NULL;
+
+ if (!dev_priv || !dev_priv->bmp)
+ return 0;
+
+ filp_priv->driver_priv =
+ drm_calloc(1, sizeof(struct drm_i915_driver_file_fields),
+ DRM_MEM_FILES);
+
+ if (!filp_priv->driver_priv)
+ return -ENOMEM;
+
+ return 0;
+}
+
+void i915_driver_postclose(struct drm_device * dev, struct drm_file * filp_priv)
+{
+ DRM_DEBUG("\n");
+
+ drm_free(filp_priv->driver_priv,
+ sizeof(struct drm_i915_driver_file_fields), DRM_MEM_FILES);
+}
diff --git a/shared-core/i915_drm.h b/shared-core/i915_drm.h
index 3a90df6e..98ed9cbc 100644
--- a/shared-core/i915_drm.h
+++ b/shared-core/i915_drm.h
@@ -160,6 +160,7 @@ typedef struct _drm_i915_sarea {
#define DRM_I915_VBLANK_SWAP 0x0f
#define DRM_I915_MMIO 0x10
#define DRM_I915_HWS_ADDR 0x11
+#define DRM_I915_HWZ 0x12
#define DRM_IOCTL_I915_INIT DRM_IOW( DRM_COMMAND_BASE + DRM_I915_INIT, drm_i915_init_t)
#define DRM_IOCTL_I915_FLUSH DRM_IO ( DRM_COMMAND_BASE + DRM_I915_FLUSH)
@@ -177,6 +178,7 @@ typedef struct _drm_i915_sarea {
#define DRM_IOCTL_I915_SET_VBLANK_PIPE DRM_IOW( DRM_COMMAND_BASE + DRM_I915_SET_VBLANK_PIPE, drm_i915_vblank_pipe_t)
#define DRM_IOCTL_I915_GET_VBLANK_PIPE DRM_IOR( DRM_COMMAND_BASE + DRM_I915_GET_VBLANK_PIPE, drm_i915_vblank_pipe_t)
#define DRM_IOCTL_I915_VBLANK_SWAP DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_VBLANK_SWAP, drm_i915_vblank_swap_t)
+#define DRM_IOCTL_I915_HWZ DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_HWZ, drm_i915_hwz_t)
/* Asynchronous page flipping:
@@ -319,4 +321,35 @@ typedef struct drm_i915_hws_addr {
uint64_t addr;
} drm_i915_hws_addr_t;
+/* Hardware Zone Rendering Support:
+ */
+#define DRM_I915_HWZ_INIT 1
+#define DRM_I915_HWZ_ALLOC 2
+#define DRM_I915_HWZ_RENDER 3
+#define DRM_I915_HWZ_FREE 4
+
+typedef struct drm_i915_hwz {
+ unsigned int op;
+ union {
+ struct drm_i915_hwz_init {
+ unsigned int hwb_start;
+ unsigned int hwb_end;
+ unsigned int hwb_size;
+ } init;
+ struct drm_i915_hwz_alloc {
+ unsigned int num_buffers;
+ unsigned int num_cliprects;
+ uint64_t cliprects;
+ } alloc;
+ struct drm_i915_hwz_render {
+ unsigned int batch_start;
+ int DR1;
+ int DR4;
+ unsigned int static_state_start;
+ unsigned int static_state_size;
+ unsigned int wait_flips;
+ } render;
+ } arg;
+} drm_i915_hwz_t;
+
#endif /* _I915_DRM_H_ */
diff --git a/shared-core/i915_drv.h b/shared-core/i915_drv.h
index aff03bee..970eb0de 100644
--- a/shared-core/i915_drv.h
+++ b/shared-core/i915_drv.h
@@ -55,10 +55,11 @@
* - Support vertical blank on secondary display pipe
* 1.8: New ioctl for ARB_Occlusion_Query
* 1.9: Usable page flipping and triple buffering
+ * 1.10: Hardware Zone Rendering support
*/
#define DRIVER_MAJOR 1
#if defined(I915_HAVE_FENCE) && defined(I915_HAVE_BUFFER)
-#define DRIVER_MINOR 9
+#define DRIVER_MINOR 10
#else
#define DRIVER_MINOR 6
#endif
@@ -74,6 +75,7 @@ typedef struct _drm_i915_ring_buffer {
int tail;
int space;
drm_local_map_t map;
+ u32 reg;
} drm_i915_ring_buffer_t;
struct mem_block {
@@ -98,6 +100,7 @@ typedef struct drm_i915_private {
drm_i915_sarea_t *sarea_priv;
drm_i915_ring_buffer_t ring;
+ drm_i915_ring_buffer_t hwb_ring;
drm_dma_handle_t *status_page_dmah;
void *hw_status_page;
@@ -136,8 +139,32 @@ typedef struct drm_i915_private {
DRM_SPINTYPE swaps_lock;
drm_i915_vbl_swap_t vbl_swaps;
unsigned int swaps_pending;
+
+ int hwb_oom;
+
+ drm_dma_handle_t *bmp, **bmp_pool;
+
+ unsigned long priv1_addr;
+ unsigned priv1_order;
} drm_i915_private_t;
+#define VIRTUAL_BPL 0
+
+struct drm_i915_driver_file_fields {
+#if VIRTUAL_BPL
+ drm_buffer_object_t *bpl[3];
+#else
+ drm_dma_handle_t *bpl[3];
+#endif
+
+ drm_dma_handle_t *bmp, **bmp_pool, **bins[3];
+ struct drm_clip_rect **bin_rects;
+
+ unsigned int bpl_num, num_bpls, num_bins, num_rects;
+ unsigned int bin_cols, bin_rows, *bin_nrects;
+ unsigned short bin_x1, bin_x2, bin_y1, bin_y2;
+};
+
enum intel_chip_family {
CHIP_I8XX = 0x01,
CHIP_I9XX = 0x02,
@@ -149,7 +176,8 @@ extern struct drm_ioctl_desc i915_ioctls[];
extern int i915_max_ioctl;
/* i915_dma.c */
-extern void i915_kernel_lost_context(struct drm_device * dev);
+extern void i915_kernel_lost_context(drm_i915_private_t * dev_priv,
+ drm_i915_ring_buffer_t *ring);
extern int i915_driver_load(struct drm_device *, unsigned long flags);
extern void i915_driver_lastclose(struct drm_device * dev);
extern void i915_driver_preclose(struct drm_device *dev,
@@ -161,6 +189,10 @@ extern void i915_emit_breadcrumb(struct drm_device *dev);
extern void i915_dispatch_flip(struct drm_device * dev, int pipes, int sync);
extern int i915_emit_mi_flush(struct drm_device *dev, uint32_t flush);
extern int i915_driver_firstopen(struct drm_device *dev);
+extern int i915_driver_open(struct drm_device * dev, struct drm_file * filp_priv);
+extern void i915_driver_postclose(struct drm_device * dev, struct drm_file * filp_priv);
+extern int i915_init_ring(struct drm_device * dev, drm_i915_ring_buffer_t * ring,
+ unsigned start, unsigned end, unsigned size, u32 reg);
/* i915_irq.c */
extern int i915_irq_emit(struct drm_device *dev, void *data,
@@ -184,6 +216,13 @@ extern void i915_user_irq_off(drm_i915_private_t *dev_priv);
extern int i915_vblank_swap(struct drm_device *dev, void *data,
struct drm_file *file_priv);
+/* i915_hwz.c */
+extern int i915_hwz(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
+extern int i915_hwz_free(struct drm_device *dev, struct drm_file *filp_priv);
+extern void i915_bmp_free(struct drm_device *dev);
+
+
/* i915_mem.c */
extern int i915_mem_alloc(struct drm_device *dev, void *data,
struct drm_file *file_priv);
@@ -215,6 +254,7 @@ extern int i915_fence_has_irq(struct drm_device *dev, uint32_t class, uint32_t f
extern struct drm_ttm_backend *i915_create_ttm_backend_entry(struct drm_device *dev);
extern int i915_fence_types(struct drm_buffer_object *bo, uint32_t *type);
extern int i915_invalidate_caches(struct drm_device *dev, uint64_t buffer_flags);
+extern int i915_init_priv1(struct drm_device * dev);
extern int i915_init_mem_type(struct drm_device *dev, uint32_t type,
struct drm_mem_type_manager *man);
extern uint32_t i915_evict_mask(struct drm_buffer_object *bo);
@@ -231,18 +271,20 @@ extern int i915_move(struct drm_buffer_object *bo, int evict,
#define I915_VERBOSE 0
#define RING_LOCALS unsigned int outring, ringmask, outcount; \
+ drm_i915_ring_buffer_t *ringptr; \
volatile char *virt;
-#define BEGIN_LP_RING(n) do { \
+#define BEGIN_RING(ring, n) do { \
+ ringptr = (ring); \
if (I915_VERBOSE) \
- DRM_DEBUG("BEGIN_LP_RING(%d) in %s\n", \
- (n), __FUNCTION__); \
- if (dev_priv->ring.space < (n)*4) \
- i915_wait_ring(dev, (n)*4, __FUNCTION__); \
+ DRM_DEBUG("BEGIN_RING(%p, %d) in %s\n", \
+ ringptr, (n), __FUNCTION__); \
+ if (ringptr->space < (n)*4) \
+ i915_wait_ring(dev_priv, ringptr, (n)*4, __FUNCTION__); \
outcount = 0; \
- outring = dev_priv->ring.tail; \
- ringmask = dev_priv->ring.tail_mask; \
- virt = dev_priv->ring.virtual_start; \
+ outring = ringptr->tail; \
+ ringmask = ringptr->tail_mask; \
+ virt = ringptr->virtual_start; \
} while (0)
#define OUT_RING(n) do { \
@@ -253,14 +295,15 @@ extern int i915_move(struct drm_buffer_object *bo, int evict,
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(LP_RING + RING_TAIL, outring); \
+#define ADVANCE_RING() do { \
+ if (I915_VERBOSE) DRM_DEBUG("ADVANCE_RING %x\n", outring); \
+ ringptr->tail = outring; \
+ ringptr->space -= outcount * 4; \
+ I915_WRITE(ringptr->reg + RING_TAIL, outring); \
} while(0)
-extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller);
+extern int i915_wait_ring(drm_i915_private_t *dev_priv, drm_i915_ring_buffer_t
+ *ring, int n, const char *caller);
#define GFX_OP_USER_INTERRUPT ((0<<29)|(2<<23))
#define GFX_OP_BREAKPOINT_INTERRUPT ((0<<29)|(1<<23))
@@ -498,6 +541,6 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller);
#define BREADCRUMB_BITS 31
#define BREADCRUMB_MASK ((1U << BREADCRUMB_BITS) - 1)
-#define READ_BREADCRUMB(dev_priv) (((volatile u32*)(dev_priv->hw_status_page))[5])
+#define READ_BREADCRUMB(dev_priv) (((volatile u32*)(dev_priv->hw_status_page))[16])
#define READ_HWSP(dev_priv, reg) (((volatile u32*)(dev_priv->hw_status_page))[reg])
#endif
diff --git a/shared-core/i915_hwz.c b/shared-core/i915_hwz.c
new file mode 100644
index 00000000..5d2441c2
--- /dev/null
+++ b/shared-core/i915_hwz.c
@@ -0,0 +1,959 @@
+/*
+ Copyright (C) Aristocrat Technologies. 2007. All Rights Reserved.
+ Copyright (C) Intel Corp. 2007. All Rights Reserved.
+
+ Aristocrat and Intel funded Tungsten Graphics
+ (http://www.tungstengraphics.com) to support zone rendering in this
+ 3D driver.
+
+ 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 (including the
+ next paragraph) 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 COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS 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.
+
+ **********************************************************************/
+ /*
+ * Authors:
+ * Michel D�nzer <michel@tungstengraphics.com>
+ */
+
+#include "drmP.h"
+#include "drm.h"
+#include "i915_drm.h"
+#include "i915_drv.h"
+
+#define BIN_WIDTH 64
+#define BIN_HEIGHT 32
+#define BIN_HMASK ~(BIN_HEIGHT - 1)
+#define BIN_WMASK ~(BIN_WIDTH - 1)
+
+
+#define BMP_SIZE PAGE_SIZE
+#define BMP_POOL_SIZE ((BMP_SIZE - 32) / 4)
+
+void i915_bmp_free(struct drm_device *dev)
+{
+ drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+
+ if (dev_priv->bmp_pool) {
+ int i;
+
+ for (i = 0; i < BMP_POOL_SIZE; i++) {
+ if (!dev_priv->bmp_pool[i])
+ break;
+
+ drm_pci_free(dev, dev_priv->bmp_pool[i]);
+ }
+
+ drm_free(dev_priv->bmp_pool, BMP_POOL_SIZE *
+ sizeof(drm_dma_handle_t*), DRM_MEM_DRIVER);
+ dev_priv->bmp_pool = NULL;
+ }
+
+ if (dev_priv->bmp) {
+ drm_pci_free(dev, dev_priv->bmp);
+ dev_priv->bmp = NULL;
+ }
+
+ I915_WRITE(BMP_BUFFER, 0);
+
+ dev_priv->irq_enable_reg &= ~HWB_OOM_FLAG;
+ I915_WRITE(I915REG_INT_ENABLE_R, dev_priv->irq_enable_reg);
+
+ DRM_INFO("BMP freed\n");
+}
+
+
+static int i915_bmp_alloc(struct drm_device *dev)
+{
+ drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+ int i;
+ u32 *ring;
+
+ dev_priv->bmp = drm_pci_alloc(dev, BMP_SIZE, PAGE_SIZE, 0xffffffff);
+
+ if (!dev_priv->bmp) {
+ DRM_ERROR("Failed to allocate BMP ring buffer\n");
+ return -ENOMEM;
+ }
+
+ dev_priv->bmp_pool = drm_calloc(1, BMP_POOL_SIZE *
+ sizeof(drm_dma_handle_t*),
+ DRM_MEM_DRIVER);
+
+ if (!dev_priv->bmp_pool) {
+ DRM_ERROR("Failed to allocate BMP pool\n");
+ drm_pci_free(dev, dev_priv->bmp);
+ dev_priv->bmp = NULL;
+ return -ENOMEM;
+ }
+
+ for (i = 0, ring = dev_priv->bmp->vaddr; i < BMP_POOL_SIZE; i++) {
+ dev_priv->bmp_pool[i] = drm_pci_alloc(dev, PAGE_SIZE, PAGE_SIZE,
+ 0xffffffff);
+
+ if (!dev_priv->bmp_pool[i]) {
+ DRM_INFO("Failed to allocate page %d for BMP pool\n",
+ i);
+ break;
+ }
+
+ ring[i] = dev_priv->bmp_pool[i]->busaddr /*>> PAGE_SHIFT*/;
+ }
+
+ I915_WRITE(BMP_PUT, (i / 8) << BMP_OFFSET_SHIFT);
+ I915_WRITE(BMP_GET, 0 << BMP_OFFSET_SHIFT);
+
+ dev_priv->irq_enable_reg |= HWB_OOM_FLAG;
+ I915_WRITE(I915REG_INT_ENABLE_R, dev_priv->irq_enable_reg);
+
+ I915_WRITE(BMP_BUFFER, dev_priv->bmp->busaddr | BMP_PAGE_SIZE_4K |
+ ((BMP_SIZE / PAGE_SIZE - 1) << BMP_BUFFER_SIZE_SHIFT) |
+ BMP_ENABLE);
+
+ DRM_DEBUG("BMP allocated and initialized\n");
+
+ return 0;
+}
+
+#define BPL_ALIGN (16 * 1024)
+
+static int i915_bpl_alloc(struct drm_device *dev,
+ struct drm_i915_driver_file_fields *filp_priv,
+ int num_bins)
+{
+ int i, bpl_size = (8 * num_bins + PAGE_SIZE - 1) & PAGE_MASK;
+
+ if (num_bins <= 0) {
+ DRM_ERROR("Invalid num_bins=%d\n", num_bins);
+ return -EINVAL;
+ }
+
+ if (!filp_priv) {
+ DRM_ERROR("No driver storage associated with file handle\n");
+ return -EINVAL;
+ }
+
+#if !VIRTUAL_BPL
+ /* drm_pci_alloc can't handle alignment > size */
+ if (bpl_size < BPL_ALIGN)
+ bpl_size = BPL_ALIGN;
+#endif
+
+ for (i = 0; i < filp_priv->num_bpls; i++) {
+ if (filp_priv->bpl[i])
+ continue;
+#if VIRTUAL_BPL
+ if (drm_buffer_object_create(dev, bpl_size, drm_bo_type_kernel,
+ DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE |
+ DRM_BO_FLAG_MEM_TT,
+ DRM_BO_HINT_DONT_FENCE,
+ BPL_ALIGN / PAGE_SIZE, 0,
+ &filp_priv->bpl[i]))
+ filp_priv->bpl[i] = NULL;
+#else
+ filp_priv->bpl[i] = drm_pci_alloc(dev, bpl_size, BPL_ALIGN,
+ 0xffffffff);
+#endif
+ if (!filp_priv->bpl[i]) {
+ DRM_ERROR("Failed to allocate BPL %d\n", i);
+ return -ENOMEM;
+ }
+#if VIRTUAL_BPL
+ if (filp_priv->bpl[i]->offset & (0x7 << 29)) {
+ DRM_ERROR("BPL %d bus address 0x%lx high bits not 0\n",
+ i, filp_priv->bpl[i]->offset);
+ mutex_lock(&dev->struct_mutex);
+ drm_bo_usage_deref_locked(filp_priv->bpl[i]);
+ mutex_unlock(&dev->struct_mutex);
+ filp_priv->bpl[i] = NULL;
+ return -ENOMEM;
+ }
+
+ DRM_INFO("BPL %d offset=0x%lx\n", i, filp_priv->bpl[i]->offset);
+#endif
+ }
+
+ DRM_DEBUG("Allocated %d BPLs of %d bytes\n", filp_priv->num_bpls,
+ bpl_size);
+
+ return 0;
+}
+
+static void i915_bpl_free(struct drm_device *dev,
+ struct drm_i915_driver_file_fields *filp_priv)
+{
+ int i;
+
+ if (!filp_priv)
+ return;
+
+ for (i = 0; i < 3; i++) {
+ if (!filp_priv->bpl[i])
+ return;
+
+#if VIRTUAL_BPL
+ mutex_lock(&dev->struct_mutex);
+ drm_bo_usage_deref_locked(filp_priv->bpl[i]);
+ mutex_unlock(&dev->struct_mutex);
+#else
+ drm_pci_free(dev, filp_priv->bpl[i]);
+#endif
+
+ filp_priv->bpl[i] = NULL;
+ }
+}
+
+#define DEBUG_HWZ 0
+
+static void i915_bpl_print(struct drm_device *dev,
+ struct drm_i915_driver_file_fields *filp_priv, int i)
+{
+#if DEBUG_HWZ
+ u32 *bpl_vaddr;
+ int bpl_row;
+#if VIRTUAL_BPL
+ int ret;
+#endif
+
+ if (!filp_priv || !filp_priv->bpl[i])
+ return;
+
+#if VIRTUAL_BPL
+ ret = drm_mem_reg_ioremap(dev, &filp_priv->bpl[i]->mem,
+ (void*)&bpl_vaddr);
+
+ if (ret) {
+ DRM_ERROR("Failed to map BPL %d\n", i);
+ return;
+ }
+#else
+ bpl_vaddr = filp_priv->bpl[i]->vaddr;
+#endif
+
+ DRM_DEBUG("BPL %d contents:\n", i);
+
+ for (bpl_row = 0; bpl_row < filp_priv->bin_rows; bpl_row++) {
+ int bpl_col;
+
+ DRM_DEBUG("Row %d:", bpl_row);
+
+ for (bpl_col = 0; bpl_col < filp_priv->bin_cols; bpl_col++) {
+ u32 *bpl = (u32*)bpl_vaddr +
+ 2 * (bpl_row * filp_priv->bin_cols + bpl_col);
+ DRM_DEBUG(" %8p(0x%08x, 0x%08x)", bpl, bpl[0], bpl[1]);
+ }
+
+ DRM_DEBUG("\n");
+ }
+#if VIRTUAL_BPL
+ drm_mem_reg_iounmap(dev, &filp_priv->bpl[i]->mem, bpl_vaddr);
+#endif
+
+#endif /* DEBUG_HWZ */
+}
+
+static int i915_hwb_idle(struct drm_device *dev,
+ struct drm_i915_driver_file_fields *filp_priv,
+ unsigned bpl_num)
+{
+ drm_i915_private_t *dev_priv = dev->dev_private;
+#if DEBUG_HWZ
+ int i, firsttime = 1;
+#endif
+ int ret = 0;
+
+ if (i915_wait_ring(dev_priv, &dev_priv->hwb_ring,
+ dev_priv->hwb_ring.Size - 8, __FUNCTION__)) {
+ DRM_ERROR("Timeout waiting for HWB ring to go idle"
+ ", PRB head: %x tail: %x/%x HWB head: %x tail: %x/%x\n",
+ I915_READ(LP_RING + RING_HEAD) & HEAD_ADDR,
+ I915_READ(LP_RING + RING_TAIL) & HEAD_ADDR,
+ dev_priv->ring.tail,
+ I915_READ(HWB_RING + RING_HEAD) & HEAD_ADDR,
+ I915_READ(HWB_RING + RING_TAIL) & HEAD_ADDR,
+ dev_priv->hwb_ring.tail);
+ DRM_ERROR("ESR: 0x%x DMA_FADD_S: 0x%x IPEIR: 0x%x SCPD0: 0x%x "
+ "IIR: 0x%x\n", I915_READ(ESR), I915_READ(DMA_FADD_S),
+ I915_READ(IPEIR), I915_READ(SCPD0),
+ I915_READ(I915REG_INT_IDENTITY_R));
+ DRM_ERROR("BCPD: 0x%x BMCD: 0x%x BDCD: 0x%x BPCD: 0x%x\n"
+ "BINSCENE: 0x%x BINSKPD: 0x%x HWBSKPD: 0x%x\n", I915_READ(BCPD),
+ I915_READ(BMCD), I915_READ(BDCD), I915_READ(BPCD),
+ I915_READ(BINSCENE), I915_READ(BINSKPD), I915_READ(HWBSKPD));
+
+ ret = -EBUSY;
+ }
+
+#if DEBUG_HWZ
+ if (!filp_priv)
+ return ret;
+
+ if (ret)
+ bpl_num = (bpl_num - 1) % filp_priv->num_bpls;
+
+ i915_bpl_print(dev, filp_priv, bpl_num);
+
+ for (i = 0; i < filp_priv->num_bins; i++) {
+ u32 *bin;
+ int k;
+
+ if (!filp_priv->bins[bpl_num] || !filp_priv->bins[bpl_num][i])
+ continue;
+
+ bin = filp_priv->bins[bpl_num][i]->vaddr;
+
+ for (k = 0; k < 1024; k++) {
+ if (bin[k]) {
+ int j;
+
+ DRM_DEBUG("BPL %d bin %d busaddr=0x%x non-empty:\n",
+ bpl_num, i,
+ filp_priv->bins[bpl_num][i]->busaddr);
+
+ if (!firsttime)
+ break;
+
+ for (j = 0; j < 128; j++) {
+ u32 *data = filp_priv->bins[bpl_num][i]->vaddr +
+ j * 8 * 4;
+
+ if (data[0] || data[1] || data[2] || data[3] ||
+ data[4] || data[5] || data[6] || data[7])
+ DRM_DEBUG("%p: %8x %8x %8x %8x %8x %8x %8x %8x\n",
+ data, data[0], data[1], data[2], data[3],
+ data[4], data[5], data[6], data[7]);
+ }
+
+ firsttime = 0;
+
+ break;
+ }
+ }
+ }
+#endif
+
+ return ret;
+}
+
+static void i915_bin_free(struct drm_device *dev,
+ struct drm_i915_driver_file_fields *filp_priv)
+{
+ int i, j;
+
+ if (!filp_priv)
+ return;
+
+ i915_hwb_idle(dev, filp_priv, 0);
+
+ for (i = 0; i < filp_priv->num_bins; i++) {
+ if (!filp_priv->bin_rects || !filp_priv->bin_rects)
+ goto free_arrays;
+
+ for (j = 0; j < filp_priv->bin_nrects[i]; j++) {
+ drm_free(filp_priv->bin_rects[i],
+ filp_priv->bin_nrects[i] *
+ sizeof(struct drm_clip_rect),
+ DRM_MEM_DRIVER);
+ }
+
+free_arrays:
+ drm_free(filp_priv->bin_rects, filp_priv->num_bins *
+ sizeof(struct drm_clip_rect*), DRM_MEM_DRIVER);
+ filp_priv->bin_rects = NULL;
+
+ drm_free(filp_priv->bin_nrects, filp_priv->num_bins *
+ sizeof(unsigned int), DRM_MEM_DRIVER);
+ filp_priv->bin_nrects = NULL;
+ }
+
+ for (i = 0; i < 3; i++) {
+ if (!filp_priv->bins[i])
+ return;
+
+ for (j = 0; j < filp_priv->num_bins; j++)
+ drm_pci_free(dev, filp_priv->bins[i][j]);
+
+ drm_free(filp_priv->bins[i], filp_priv->num_bins *
+ sizeof(drm_dma_handle_t*), DRM_MEM_DRIVER);
+ filp_priv->bins[i] = NULL;
+ }
+}
+
+static int i915_bin_alloc(struct drm_device *dev,
+ struct drm_i915_driver_file_fields *filp_priv,
+ struct drm_clip_rect *cliprects,
+ unsigned int num_cliprects)
+{
+ int i, j;
+
+ if (!filp_priv) {
+ DRM_ERROR("No driver storage associated with file handle\n");
+ return -EINVAL;
+ }
+
+ filp_priv->bin_rects = drm_calloc(1, filp_priv->num_bins *
+ sizeof(struct drm_clip_rect*),
+ DRM_MEM_DRIVER);
+
+ if (!filp_priv->bin_rects) {
+ DRM_ERROR("Failed to allocate bin rects pool\n");
+ return -ENOMEM;
+ }
+
+ filp_priv->bin_nrects = drm_calloc(1, filp_priv->num_bins *
+ sizeof(unsigned int),
+ DRM_MEM_DRIVER);
+
+ if (!filp_priv->bin_nrects) {
+ DRM_ERROR("Failed to allocate bin nrects array\n");
+ return -ENOMEM;
+ }
+
+ filp_priv->num_rects = 0;
+
+ for (i = 0; i < filp_priv->num_bins; i++) {
+ unsigned short bin_row = i / filp_priv->bin_cols;
+ unsigned short bin_col = i % filp_priv->bin_cols;
+ unsigned short bin_y1 = max(filp_priv->bin_y1, (unsigned short)
+ ((filp_priv->bin_y1 + bin_row *
+ BIN_HEIGHT) & BIN_HMASK));
+ unsigned short bin_x1 = max(filp_priv->bin_x1, (unsigned short)
+ ((filp_priv->bin_x1 + bin_col *
+ BIN_WIDTH) & BIN_WMASK));
+ unsigned short bin_y2 = min(filp_priv->bin_y2 - 1,
+ ((bin_y1 + BIN_HEIGHT) & BIN_HMASK)
+ - 1);
+ unsigned short bin_x2 = min(filp_priv->bin_x2 - 1,
+ ((bin_x1 + BIN_WIDTH) & BIN_WMASK)
+ - 1);
+
+ for (j = 0; j < num_cliprects; j++) {
+ unsigned short x1 = max(bin_x1, cliprects[j].x1);
+ unsigned short x2 = min(bin_x2, cliprects[j].x2);
+ unsigned short y1 = max(bin_y1, cliprects[j].y1);
+ unsigned short y2 = min(bin_y2, cliprects[j].y2);
+ struct drm_clip_rect *rect;
+
+ if (x1 >= x2 || y1 >= y2)
+ continue;
+
+ filp_priv->bin_rects[i] =
+ drm_realloc(filp_priv->bin_rects[i],
+ filp_priv->bin_nrects[i] *
+ sizeof(struct drm_clip_rect),
+ (filp_priv->bin_nrects[i] + 1) *
+ sizeof(struct drm_clip_rect),
+ DRM_MEM_DRIVER);
+
+ rect = &filp_priv->bin_rects[i]
+ [filp_priv->bin_nrects[i]++];
+
+ rect->x1 = x1;
+ rect->x2 = x2;
+ rect->y1 = y1;
+ rect->y2 = y2;
+
+ DRM_DEBUG("Bin %d cliprect %d: (%d, %d) - (%d, %d)\n",
+ i, filp_priv->bin_nrects[i], x1, y1, x2, y2);
+
+ filp_priv->num_rects++;
+ }
+ }
+
+ for (i = 0; i < filp_priv->num_bpls; i++) {
+ filp_priv->bins[i] = drm_calloc(1, filp_priv->num_bins *
+ sizeof(drm_dma_handle_t*),
+ DRM_MEM_DRIVER);
+
+ if (!filp_priv->bins[i]) {
+ DRM_ERROR("Failed to allocate bin pool %d\n", i);
+ return -ENOMEM;
+ }
+
+ for (j = 0; j < filp_priv->num_bins; j++) {
+ filp_priv->bins[i][j] = drm_pci_alloc(dev, PAGE_SIZE,
+ PAGE_SIZE,
+ 0xffffffff);
+
+ if (!filp_priv->bins[i][j]) {
+ DRM_ERROR("Failed to allocate page for bin %d "
+ "of buffer %d\n", j, i);
+ return -ENOMEM;
+ }
+ }
+ }
+
+ DRM_INFO("Allocated %d times %d bins and %d cliprects\n",
+ filp_priv->num_bpls, filp_priv->num_bins, filp_priv->num_rects);
+
+ return 0;
+}
+
+static int i915_hwz_alloc(struct drm_device *dev,
+ struct drm_i915_driver_file_fields *filp_priv,
+ struct drm_i915_hwz_alloc *alloc)
+{
+ drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+ unsigned short x1 = dev_priv->sarea_priv->width - 1, x2 = 0;
+ unsigned short y1 = dev_priv->sarea_priv->height - 1, y2 = 0;
+ int bin_rows, bin_cols;
+ struct drm_clip_rect __user *cliprects;
+ int i, ret;
+
+ if (!dev_priv->bmp) {
+ DRM_DEBUG("HWZ not initialized\n");
+ return -EINVAL;
+ }
+
+ if (alloc->num_buffers > 3) {
+ DRM_ERROR("Only up to 3 buffers allowed\n");
+ return -EINVAL;
+ }
+
+ if (!filp_priv) {
+ DRM_ERROR("No driver storage associated with file handle\n");
+ return -EINVAL;
+ }
+
+ cliprects = drm_alloc(alloc->num_cliprects * sizeof(struct drm_clip_rect),
+ DRM_MEM_DRIVER);
+
+ if (!cliprects) {
+ DRM_ERROR("Failed to allocate memory to hold %u cliprects\n",
+ alloc->num_cliprects);
+ return -ENOMEM;
+ }
+
+ if (DRM_COPY_FROM_USER(cliprects,
+ (void*)(unsigned long)alloc->cliprects,
+ alloc->num_cliprects * sizeof(struct drm_clip_rect))) {
+ DRM_ERROR("DRM_COPY_TO_USER failed for %u cliprects\n",
+ alloc->num_cliprects);
+ return -EFAULT;
+ }
+
+ for (i = 0; i < alloc->num_cliprects; i++) {
+ x1 = min(x1, cliprects[i].x1);
+ x2 = max(x2, cliprects[i].x2);
+ y1 = min(y1, cliprects[i].y1);
+ y2 = max(y2, cliprects[i].y2);
+ }
+
+ x2 = min(x2, (unsigned short)(dev_priv->sarea_priv->width - 1));
+ if (y2 >= dev_priv->sarea_priv->height)
+ y2 = dev_priv->sarea_priv->height - 1;
+
+ bin_rows = (((y2 + BIN_HEIGHT - 1) & BIN_HMASK) -
+ (y1 & BIN_HMASK)) / BIN_HEIGHT;
+ bin_cols = (((x2 + BIN_WIDTH - 1) & BIN_WMASK) -
+ (x1 & BIN_WMASK)) / BIN_WIDTH;
+
+ if (bin_cols <= 0 || bin_rows <= 0) {
+ DRM_DEBUG("bin_cols=%d bin_rows=%d => nothing to allocate\n",
+ bin_cols, bin_rows);
+ return -EINVAL;
+ }
+
+ if (filp_priv->num_bpls != alloc->num_buffers ||
+ filp_priv->bin_rows != bin_rows ||
+ filp_priv->bin_cols != bin_cols) {
+ i915_bpl_free(dev, filp_priv);
+ }
+
+ filp_priv->bin_x1 = x1;
+ filp_priv->bin_x2 = x2;
+ filp_priv->bin_cols = bin_cols;
+ filp_priv->bin_y1 = y1;
+ filp_priv->bin_y2 = y2;
+ filp_priv->bin_rows = bin_rows;
+ filp_priv->num_bpls = alloc->num_buffers;
+
+ i915_bin_free(dev, filp_priv);
+
+ filp_priv->num_bins = bin_cols * bin_rows;
+
+ ret = i915_bin_alloc(dev, filp_priv, cliprects, alloc->num_cliprects);
+
+ drm_free(cliprects, alloc->num_cliprects * sizeof(struct drm_clip_rect),
+ DRM_MEM_DRIVER);
+
+ if (ret) {
+ DRM_ERROR("Failed to allocate bins\n");
+ i915_bpl_free(dev, filp_priv);
+ return ret;
+ }
+
+ ret = i915_bpl_alloc(dev, filp_priv, bin_cols * ((bin_rows + 3) & ~3));
+
+ if (ret) {
+ DRM_ERROR("Failed to allocate BPLs\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+int i915_hwz_free(struct drm_device *dev, struct drm_file *filp_priv)
+{
+ struct drm_i915_driver_file_fields *filp_i915priv;
+
+ if (!filp_priv || !filp_priv->driver_priv)
+ return 0;
+
+ filp_i915priv = filp_priv->driver_priv;
+
+ i915_bin_free(dev, filp_i915priv);
+ i915_bpl_free(dev, filp_i915priv);
+
+ return 0;
+}
+
+static int i915_bin_init(struct drm_device *dev,
+ struct drm_i915_driver_file_fields *filp_priv, int i)
+{
+ drm_i915_private_t *dev_priv = dev->dev_private;
+ u32 *bpl_vaddr;
+ int bpl_row;
+ drm_dma_handle_t **bins = filp_priv->bins[i];
+#if VIRTUAL_BPL
+ int ret;
+#endif
+
+ if (!bins) {
+ DRM_ERROR("Bins not allocated\n");
+ return -EINVAL;
+ }
+
+ if (!filp_priv) {
+ DRM_ERROR("No driver storage associated with file handle\n");
+ return -EINVAL;
+ }
+
+#if VIRTUAL_BPL
+ ret = drm_mem_reg_ioremap(dev, &filp_priv->bpl[i]->mem,
+ (void*)&bpl_vaddr);
+
+ if (ret) {
+ DRM_ERROR("Failed to map BPL %d\n", i);
+ return ret;
+ }
+#else
+ bpl_vaddr = filp_priv->bpl[i]->vaddr;
+#endif
+
+ for (bpl_row = 0; bpl_row < filp_priv->bin_rows; bpl_row += 4) {
+ int bpl_col;
+
+ for (bpl_col = 0; bpl_col < filp_priv->bin_cols; bpl_col++) {
+ u32 *bpl = (u32*)bpl_vaddr +
+ 2 * (bpl_row * filp_priv->bin_cols + 4 * bpl_col);
+ int j, num_bpls = filp_priv->bin_rows - bpl_row;
+
+ if (num_bpls > 4)
+ num_bpls = 4;
+
+ DRM_DEBUG("bpl_row=%d bpl_col=%d vaddr=%p => bpl=%p num_bpls = %d\n",
+ bpl_row, bpl_col, bpl_vaddr, bpl, num_bpls);
+
+ for (j = 0; j < num_bpls; j++) {
+ unsigned idx = (bpl_row + j) *
+ filp_priv->bin_cols + bpl_col;
+ drm_dma_handle_t *bin = bins[idx];
+
+ DRM_DEBUG("j=%d => idx=%u bpl=%p busaddr=0x%x\n",
+ j, idx, bpl, bin->busaddr);
+
+ *bpl++ = bin->busaddr;
+ *bpl++ = 1 << 2 | 1 << 0;
+ }
+ }
+ }
+
+#if VIRTUAL_BPL
+ drm_mem_reg_iounmap(dev, &filp_priv->bpl[i]->mem, bpl_vaddr);
+#else
+ flush_agp_cache();
+#endif
+
+ I915_WRITE(GFX_FLSH_CNTL, 1);
+
+ i915_bpl_print(dev, filp_priv, i);
+
+ DRM_DEBUG("BPL %d initialized for %d bins\n", i, filp_priv->bin_rows *
+ filp_priv->bin_cols);
+
+ return 0;
+}
+
+static int i915_hwz_render(struct drm_device *dev,
+ struct drm_i915_driver_file_fields *filp_priv,
+ struct drm_i915_hwz_render *render)
+{
+ drm_i915_private_t *dev_priv = dev->dev_private;
+ int ret, i;
+ int static_state_off = render->static_state_start -
+ virt_to_phys((void*)dev_priv->priv1_addr);
+ RING_LOCALS;
+
+ if (static_state_off < 0 || render->static_state_size <= 0 ||
+ static_state_off + 4 * render->static_state_size >
+ ((1 << dev_priv->priv1_order) * PAGE_SIZE)) {
+ DRM_ERROR("Invalid static indirect state\n");
+ return -EINVAL;
+ }
+
+ if (!filp_priv) {
+ DRM_ERROR("No driver storage associated with file handle\n");
+ return -EINVAL;
+ }
+
+ filp_priv->bpl_num = (filp_priv->bpl_num + 1) % filp_priv->num_bpls;
+
+ DRM_DEBUG("bpl_num = %d, batch_start = 0x%x\n", filp_priv->bpl_num,
+ render->batch_start);
+
+ if (dev_priv->hwb_ring.tail != (I915_READ(HWB_RING + RING_TAIL)
+ & TAIL_ADDR)) {
+ DRM_INFO("Refreshing context of HWB ring buffer\n");
+ i915_kernel_lost_context(dev_priv, &dev_priv->hwb_ring);
+ }
+
+ if (i915_hwb_idle(dev, filp_priv, filp_priv->bpl_num)) {
+ return -EBUSY;
+ }
+
+ ret = i915_bin_init(dev, filp_priv, filp_priv->bpl_num);
+
+ if (ret) {
+ DRM_ERROR("Failed to initialize BPL %d\n", filp_priv->bpl_num);
+ return ret;
+ }
+
+ /* Write the HWB command stream */
+ I915_WRITE(BINSCENE, (filp_priv->bin_rows - 1) << 16 |
+ (filp_priv->bin_cols - 1) << 10 | BS_MASK);
+ I915_WRITE(BINSKPD, (VIRTUAL_BPL<<7) | (1<<(7+16)));
+
+#if VIRTUAL_BPL
+ ret = drm_buffer_object_validate(filp_priv->bpl[filp_priv->bpl_num], 0, 0);
+
+ if (ret) {
+ DRM_ERROR("Failed to validate BPL %i\n", filp_priv->bpl_num);
+ return ret;
+ }
+
+ DRM_INFO("BPL %d validated to offset 0x%lx\n", filp_priv->bpl_num,
+ filp_priv->bpl[filp_priv->bpl_num]->offset);
+
+ I915_WRITE(BINCTL, filp_priv->bpl[filp_priv->bpl_num]->offset | BC_MASK);
+#else
+ I915_WRITE(BINCTL, filp_priv->bpl[filp_priv->bpl_num]->busaddr | BC_MASK);
+#endif
+
+ BEGIN_RING(&dev_priv->hwb_ring, 16);
+
+ OUT_RING(CMD_OP_BIN_CONTROL);
+ OUT_RING(0x5 << 4 | 0x6);
+ OUT_RING((filp_priv->bin_y1 & BIN_HMASK) << 16 |
+ (filp_priv->bin_x1 & BIN_WMASK));
+ OUT_RING((((filp_priv->bin_y2 + BIN_HEIGHT - 1) & BIN_HMASK) - 1) << 16 |
+ (((filp_priv->bin_x2 + BIN_WIDTH - 1) & BIN_WMASK) - 1));
+ OUT_RING(filp_priv->bin_y1 << 16 | filp_priv->bin_x1);
+ OUT_RING((filp_priv->bin_y2 - 1) << 16 | (filp_priv->bin_x2 - 1));
+
+ OUT_RING(GFX_OP_DRAWRECT_INFO);
+ OUT_RING(render->DR1);
+ OUT_RING((filp_priv->bin_y1 & BIN_HMASK) << 16 |
+ (filp_priv->bin_x1 & BIN_WMASK));
+ OUT_RING((((filp_priv->bin_y2 + BIN_HEIGHT - 1) & BIN_HMASK) - 1) << 16 |
+ (((filp_priv->bin_x2 + BIN_WIDTH - 1) & BIN_WMASK) - 1));
+ OUT_RING(render->DR4);
+
+ OUT_RING(GFX_OP_DESTBUFFER_VARS);
+ OUT_RING((0x8<<20) | (0x8<<16));
+
+ OUT_RING(GFX_OP_RASTER_RULES | (1<<5) | (2<<3));
+
+ OUT_RING(MI_BATCH_BUFFER_START | (2 << 6));
+ OUT_RING(render->batch_start | MI_BATCH_NON_SECURE);
+
+ ADVANCE_RING();
+
+#if DEBUG_HWZ
+ i915_hwb_idle(dev, filp_priv, filp_priv->bpl_num);
+#endif
+
+ BEGIN_RING(&dev_priv->hwb_ring, 2);
+ OUT_RING(CMD_MI_FLUSH | MI_END_SCENE | MI_SCENE_COUNT |
+ MI_NO_WRITE_FLUSH);
+ OUT_RING(0);
+ ADVANCE_RING();
+
+ /* Prepare the Scene Render List */
+ DRM_DEBUG("Emitting %d DWORDs of static indirect state\n",
+ render->static_state_size);
+
+ BEGIN_RING(&dev_priv->ring, (7 * filp_priv->num_rects + 20 +
+ (render->wait_flips ? 2 : 0) + 1) & ~1);
+
+ OUT_RING(GFX_OP_LOAD_INDIRECT | (0x3f<<8) | (0<<14) | 10);
+ OUT_RING(render->static_state_start | (1<<1) | (1<<0));
+ OUT_RING(render->static_state_size - 1);
+ OUT_RING(0);
+ OUT_RING(0);
+ OUT_RING(0);
+ OUT_RING(0);
+ OUT_RING(0);
+ OUT_RING(0);
+ OUT_RING(0);
+ OUT_RING(0);
+ OUT_RING(0);
+ OUT_RING(CMD_MI_FLUSH /*| MI_NO_WRITE_FLUSH*/);
+ OUT_RING(CMD_MI_LOAD_REGISTER_IMM);
+ OUT_RING(Cache_Mode_0);
+ OUT_RING(0x221 << 16 | 0x201);
+
+ if (render->wait_flips) {
+ OUT_RING(render->wait_flips & 0x1 ?
+ (MI_WAIT_FOR_EVENT | MI_WAIT_FOR_PLANE_A_FLIP) : 0);
+ OUT_RING(render->wait_flips & 0x2 ?
+ (MI_WAIT_FOR_EVENT | MI_WAIT_FOR_PLANE_B_FLIP) : 0);
+ }
+
+ for (i = 0; i < filp_priv->num_bins; i++) {
+ int j;
+
+ for (j = 0; j < filp_priv->bin_nrects[i]; j++) {
+ struct drm_clip_rect *rect = &filp_priv->bin_rects[i][j];
+
+ OUT_RING(GFX_OP_DRAWRECT_INFO);
+ OUT_RING(render->DR1);
+ OUT_RING(rect->y1 << 16 | rect->x1);
+ OUT_RING(rect->y2 << 16 | rect->x2);
+ OUT_RING(render->DR4);
+ OUT_RING(MI_BATCH_BUFFER_START);
+ OUT_RING(filp_priv->bins[filp_priv->bpl_num][i]->busaddr);
+ }
+ }
+
+ OUT_RING(CMD_MI_FLUSH | MI_END_SCENE | MI_SCENE_COUNT);
+ OUT_RING(CMD_MI_LOAD_REGISTER_IMM);
+ OUT_RING(Cache_Mode_0);
+ OUT_RING(0x221 << 16 | 0x20);
+
+ if (filp_priv->num_rects & 0x1)
+ OUT_RING(0);
+
+ i915_hwb_idle(dev, filp_priv, filp_priv->bpl_num);
+
+ ADVANCE_RING();
+
+ return ret;
+}
+
+static int i915_hwz_init(struct drm_device *dev, struct drm_i915_hwz_init *init)
+{
+ drm_i915_private_t *dev_priv = dev->dev_private;
+ int ret;
+ RING_LOCALS;
+
+ if (!dev_priv) {
+ DRM_ERROR("called without initialization\n");
+ return -EINVAL;
+ }
+
+ if (dev_priv->bmp) {
+ DRM_DEBUG("Already initialized\n");
+ return -EBUSY;
+ }
+
+ ret = i915_init_priv1(dev);
+
+ if (ret) {
+ DRM_ERROR("Failed to initialize PRIV1 memory type\n");
+ return ret;
+ }
+
+ if (i915_bmp_alloc(dev)) {
+ DRM_ERROR("Failed to allocate BMP\n");
+ return -ENOMEM;
+ }
+
+ if (i915_init_ring(dev, &dev_priv->hwb_ring, init->hwb_start,
+ init->hwb_end, init->hwb_size, HWB_RING)) {
+ DRM_ERROR("Failed to initialize HWB ring buffer\n");
+ return -ENOMEM;
+ }
+
+ DRM_DEBUG("Refreshing context of HWB ring buffer\n");
+ i915_kernel_lost_context(dev_priv, &dev_priv->hwb_ring);
+
+ I915_WRITE(BINSCENE, BS_MASK | BS_OP_LOAD);
+
+ BEGIN_RING(&dev_priv->hwb_ring, 2);
+ OUT_RING(CMD_MI_FLUSH);
+ OUT_RING(0);
+ ADVANCE_RING();
+
+ DRM_INFO("HWZ initialized\n");
+
+ return 0;
+}
+
+int i915_hwz(struct drm_device *dev, void *data, struct drm_file *file_priv)
+{
+ drm_i915_private_t *dev_priv = dev->dev_private;
+ struct drm_i915_driver_file_fields *file_i915priv;
+ drm_i915_hwz_t *hwz = data;
+
+ if (!dev_priv) {
+ DRM_ERROR("called with no initialization\n");
+ return -EINVAL;
+ }
+
+ if (dev_priv->hwb_oom) {
+ DRM_ERROR("HWB out of memory\n");
+ return -ENOMEM;
+ }
+
+ if (hwz->op == DRM_I915_HWZ_INIT) {
+ if (!file_priv->master) {
+ DRM_ERROR("Only master may initialize HWZ\n");
+ return -EINVAL;
+ }
+
+ return i915_hwz_init(dev, &hwz->arg.init);
+ }
+
+ if (hwz->op == DRM_I915_HWZ_FREE)
+ return i915_hwz_free(dev, file_priv);
+
+ file_i915priv = file_priv->driver_priv;
+
+ switch (hwz->op) {
+ case DRM_I915_HWZ_RENDER:
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
+ return i915_hwz_render(dev, file_i915priv, &hwz->arg.render);
+ case DRM_I915_HWZ_ALLOC:
+ return i915_hwz_alloc(dev, file_i915priv, &hwz->arg.alloc);
+ default:
+ DRM_ERROR("Invalid op 0x%x\n", hwz->op);
+ return -EINVAL;
+ }
+}
diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c
index 1056b3e6..916a72a9 100644
--- a/shared-core/i915_irq.c
+++ b/shared-core/i915_irq.c
@@ -31,10 +31,6 @@
#include "i915_drm.h"
#include "i915_drv.h"
-#define USER_INT_FLAG (1<<1)
-#define VSYNC_PIPEB_FLAG (1<<5)
-#define VSYNC_PIPEA_FLAG (1<<7)
-
#define MAX_NOPID ((u32)~0)
/**
@@ -173,7 +169,9 @@ static void i915_vblank_tasklet(struct drm_device *dev)
return;
}
- i915_kernel_lost_context(dev);
+ spin_unlock(&dev_priv->swaps_lock);
+
+ i915_kernel_lost_context(dev_priv, &dev_priv->ring);
upper[0] = upper[1] = 0;
slice[0] = max(sarea_priv->pipeA_h / nhits, 1);
@@ -221,7 +219,7 @@ static void i915_vblank_tasklet(struct drm_device *dev)
}
if (init_drawrect) {
- BEGIN_LP_RING(6);
+ BEGIN_RING(&dev_priv->ring, 6);
OUT_RING(GFX_OP_DRAWRECT_INFO);
OUT_RING(0);
@@ -230,7 +228,7 @@ static void i915_vblank_tasklet(struct drm_device *dev)
OUT_RING(sarea_priv->width | sarea_priv->height << 16);
OUT_RING(0);
- ADVANCE_LP_RING();
+ ADVANCE_RING();
sarea_priv->ctxOwner = DRM_KERNEL_CONTEXT;
@@ -252,7 +250,7 @@ static void i915_vblank_tasklet(struct drm_device *dev)
if (y1 >= y2)
continue;
- BEGIN_LP_RING(8);
+ BEGIN_RING(&dev_priv->ring, 8);
OUT_RING(cmd);
OUT_RING(pitchropcpp);
@@ -263,7 +261,7 @@ static void i915_vblank_tasklet(struct drm_device *dev)
OUT_RING(pitchropcpp & 0xffff);
OUT_RING(offsets[back]);
- ADVANCE_LP_RING();
+ ADVANCE_RING();
}
}
}
@@ -290,8 +288,8 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
pipea_stats = I915_READ(I915REG_PIPEASTAT);
pipeb_stats = I915_READ(I915REG_PIPEBSTAT);
- temp = I915_READ16(I915REG_INT_IDENTITY_R);
- temp &= (dev_priv->irq_enable_reg | USER_INT_FLAG);
+ temp = I915_READ(I915REG_INT_IDENTITY_R);
+ temp &= (dev_priv->irq_enable_reg | USER_INT_FLAG | HWB_OOM_FLAG);
#if 0
DRM_DEBUG("%s flag=%08x\n", __FUNCTION__, temp);
@@ -299,8 +297,8 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
if (temp == 0)
return IRQ_NONE;
- I915_WRITE16(I915REG_INT_IDENTITY_R, temp);
- (void) I915_READ16(I915REG_INT_IDENTITY_R);
+ I915_WRITE(I915REG_INT_IDENTITY_R, temp);
+ (void) I915_READ(I915REG_INT_IDENTITY_R);
DRM_READMEMORYBARRIER();
dev_priv->sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv);
@@ -341,6 +339,11 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
I915_VBLANK_CLEAR);
}
+ if ((temp & HWB_OOM_FLAG) && !dev_priv->hwb_oom) {
+ DRM_ERROR("HWB out of memory\n");
+ dev_priv->hwb_oom = TRUE;
+ }
+
return IRQ_HANDLED;
}
@@ -350,16 +353,16 @@ int i915_emit_irq(struct drm_device * dev)
drm_i915_private_t *dev_priv = dev->dev_private;
RING_LOCALS;
- i915_kernel_lost_context(dev);
+ i915_kernel_lost_context(dev_priv, &dev_priv->ring);
DRM_DEBUG("%s\n", __FUNCTION__);
i915_emit_breadcrumb(dev);
- BEGIN_LP_RING(2);
+ BEGIN_RING(&dev_priv->ring, 2);
OUT_RING(0);
OUT_RING(GFX_OP_USER_INTERRUPT);
- ADVANCE_LP_RING();
+ ADVANCE_RING();
return dev_priv->counter;
@@ -371,7 +374,7 @@ void i915_user_irq_on(drm_i915_private_t *dev_priv)
DRM_SPINLOCK(&dev_priv->user_irq_lock);
if (dev_priv->irq_enabled && (++dev_priv->user_irq_refcount == 1)){
dev_priv->irq_enable_reg |= USER_INT_FLAG;
- I915_WRITE16(I915REG_INT_ENABLE_R, dev_priv->irq_enable_reg);
+ I915_WRITE(I915REG_INT_ENABLE_R, dev_priv->irq_enable_reg);
}
DRM_SPINUNLOCK(&dev_priv->user_irq_lock);
@@ -382,12 +385,11 @@ void i915_user_irq_off(drm_i915_private_t *dev_priv)
DRM_SPINLOCK(&dev_priv->user_irq_lock);
if (dev_priv->irq_enabled && (--dev_priv->user_irq_refcount == 0)) {
// dev_priv->irq_enable_reg &= ~USER_INT_FLAG;
- // I915_WRITE16(I915REG_INT_ENABLE_R, dev_priv->irq_enable_reg);
+ // I915_WRITE(I915REG_INT_ENABLE_R, dev_priv->irq_enable_reg);
}
DRM_SPINUNLOCK(&dev_priv->user_irq_lock);
}
-
static int i915_wait_irq(struct drm_device * dev, int irq_nr)
{
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
@@ -499,7 +501,7 @@ static void i915_enable_interrupt (struct drm_device *dev)
if (dev_priv->vblank_pipe & DRM_I915_VBLANK_PIPE_B)
dev_priv->irq_enable_reg |= VSYNC_PIPEB_FLAG;
- I915_WRITE16(I915REG_INT_ENABLE_R, dev_priv->irq_enable_reg);
+ I915_WRITE(I915REG_INT_ENABLE_R, dev_priv->irq_enable_reg);
dev_priv->irq_enabled = 1;
}
@@ -688,8 +690,8 @@ void i915_driver_irq_preinstall(struct drm_device * dev)
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
I915_WRITE16(I915REG_HWSTAM, 0xeffe);
- I915_WRITE16(I915REG_INT_MASK_R, 0x0);
- I915_WRITE16(I915REG_INT_ENABLE_R, 0x0);
+ I915_WRITE(I915REG_INT_MASK_R, 0x0);
+ I915_WRITE(I915REG_INT_ENABLE_R, 0x0);
}
void i915_driver_irq_postinstall(struct drm_device * dev)
@@ -722,9 +724,9 @@ void i915_driver_irq_uninstall(struct drm_device * dev)
dev_priv->irq_enabled = 0;
I915_WRITE16(I915REG_HWSTAM, 0xffff);
- I915_WRITE16(I915REG_INT_MASK_R, 0xffff);
- I915_WRITE16(I915REG_INT_ENABLE_R, 0x0);
+ I915_WRITE(I915REG_INT_MASK_R, 0xffffffff);
+ I915_WRITE(I915REG_INT_ENABLE_R, 0x0);
- temp = I915_READ16(I915REG_INT_IDENTITY_R);
- I915_WRITE16(I915REG_INT_IDENTITY_R, temp);
+ temp = I915_READ(I915REG_INT_IDENTITY_R);
+ I915_WRITE(I915REG_INT_IDENTITY_R, temp);
}