Commit 1ec14ad3 authored by Chris Wilson's avatar Chris Wilson

drm/i915: Implement GPU semaphores for inter-ring synchronisation on SNB

The bulk of the change is to convert the growing list of rings into an
array so that the relationship between the rings and the semaphore sync
registers can be easily computed.
Signed-off-by: default avatarChris Wilson <chris@chris-wilson.co.uk>
parent 340479aa
......@@ -339,10 +339,10 @@ static int i915_gem_request_info(struct seq_file *m, void *data)
return ret;
count = 0;
if (!list_empty(&dev_priv->render_ring.request_list)) {
if (!list_empty(&dev_priv->ring[RCS].request_list)) {
seq_printf(m, "Render requests:\n");
list_for_each_entry(gem_request,
&dev_priv->render_ring.request_list,
&dev_priv->ring[RCS].request_list,
list) {
seq_printf(m, " %d @ %d\n",
gem_request->seqno,
......@@ -350,10 +350,10 @@ static int i915_gem_request_info(struct seq_file *m, void *data)
}
count++;
}
if (!list_empty(&dev_priv->bsd_ring.request_list)) {
if (!list_empty(&dev_priv->ring[VCS].request_list)) {
seq_printf(m, "BSD requests:\n");
list_for_each_entry(gem_request,
&dev_priv->bsd_ring.request_list,
&dev_priv->ring[VCS].request_list,
list) {
seq_printf(m, " %d @ %d\n",
gem_request->seqno,
......@@ -361,10 +361,10 @@ static int i915_gem_request_info(struct seq_file *m, void *data)
}
count++;
}
if (!list_empty(&dev_priv->blt_ring.request_list)) {
if (!list_empty(&dev_priv->ring[BCS].request_list)) {
seq_printf(m, "BLT requests:\n");
list_for_each_entry(gem_request,
&dev_priv->blt_ring.request_list,
&dev_priv->ring[BCS].request_list,
list) {
seq_printf(m, " %d @ %d\n",
gem_request->seqno,
......@@ -398,15 +398,14 @@ static int i915_gem_seqno_info(struct seq_file *m, void *data)
struct drm_info_node *node = (struct drm_info_node *) m->private;
struct drm_device *dev = node->minor->dev;
drm_i915_private_t *dev_priv = dev->dev_private;
int ret;
int ret, i;
ret = mutex_lock_interruptible(&dev->struct_mutex);
if (ret)
return ret;
i915_ring_seqno_info(m, &dev_priv->render_ring);
i915_ring_seqno_info(m, &dev_priv->bsd_ring);
i915_ring_seqno_info(m, &dev_priv->blt_ring);
for (i = 0; i < I915_NUM_RINGS; i++)
i915_ring_seqno_info(m, &dev_priv->ring[i]);
mutex_unlock(&dev->struct_mutex);
......@@ -419,7 +418,7 @@ static int i915_interrupt_info(struct seq_file *m, void *data)
struct drm_info_node *node = (struct drm_info_node *) m->private;
struct drm_device *dev = node->minor->dev;
drm_i915_private_t *dev_priv = dev->dev_private;
int ret;
int ret, i;
ret = mutex_lock_interruptible(&dev->struct_mutex);
if (ret)
......@@ -458,9 +457,8 @@ static int i915_interrupt_info(struct seq_file *m, void *data)
}
seq_printf(m, "Interrupts received: %d\n",
atomic_read(&dev_priv->irq_received));
i915_ring_seqno_info(m, &dev_priv->render_ring);
i915_ring_seqno_info(m, &dev_priv->bsd_ring);
i915_ring_seqno_info(m, &dev_priv->blt_ring);
for (i = 0; i < I915_NUM_RINGS; i++)
i915_ring_seqno_info(m, &dev_priv->ring[i]);
mutex_unlock(&dev->struct_mutex);
return 0;
......@@ -503,13 +501,7 @@ static int i915_hws_info(struct seq_file *m, void *data)
volatile u32 *hws;
int i;
switch ((uintptr_t)node->info_ent->data) {
case RING_RENDER: ring = &dev_priv->render_ring; break;
case RING_BSD: ring = &dev_priv->bsd_ring; break;
case RING_BLT: ring = &dev_priv->blt_ring; break;
default: return -EINVAL;
}
ring = &dev_priv->ring[(uintptr_t)node->info_ent->data];
hws = (volatile u32 *)ring->status_page.page_addr;
if (hws == NULL)
return 0;
......@@ -569,17 +561,11 @@ static int i915_ringbuffer_data(struct seq_file *m, void *data)
struct intel_ring_buffer *ring;
int ret;
switch ((uintptr_t)node->info_ent->data) {
case RING_RENDER: ring = &dev_priv->render_ring; break;
case RING_BSD: ring = &dev_priv->bsd_ring; break;
case RING_BLT: ring = &dev_priv->blt_ring; break;
default: return -EINVAL;
}
ret = mutex_lock_interruptible(&dev->struct_mutex);
if (ret)
return ret;
ring = &dev_priv->ring[(uintptr_t)node->info_ent->data];
if (!ring->obj) {
seq_printf(m, "No ringbuffer setup\n");
} else {
......@@ -603,21 +589,20 @@ static int i915_ringbuffer_info(struct seq_file *m, void *data)
drm_i915_private_t *dev_priv = dev->dev_private;
struct intel_ring_buffer *ring;
switch ((uintptr_t)node->info_ent->data) {
case RING_RENDER: ring = &dev_priv->render_ring; break;
case RING_BSD: ring = &dev_priv->bsd_ring; break;
case RING_BLT: ring = &dev_priv->blt_ring; break;
default: return -EINVAL;
}
ring = &dev_priv->ring[(uintptr_t)node->info_ent->data];
if (ring->size == 0)
return 0;
return 0;
seq_printf(m, "Ring %s:\n", ring->name);
seq_printf(m, " Head : %08x\n", I915_READ_HEAD(ring) & HEAD_ADDR);
seq_printf(m, " Tail : %08x\n", I915_READ_TAIL(ring) & TAIL_ADDR);
seq_printf(m, " Size : %08x\n", ring->size);
seq_printf(m, " Active : %08x\n", intel_ring_get_active_head(ring));
seq_printf(m, " NOPID : %08x\n", I915_READ_NOPID(ring));
if (IS_GEN6(dev)) {
seq_printf(m, " Sync 0 : %08x\n", I915_READ_SYNC_0(ring));
seq_printf(m, " Sync 1 : %08x\n", I915_READ_SYNC_1(ring));
}
seq_printf(m, " Control : %08x\n", I915_READ_CTL(ring));
seq_printf(m, " Start : %08x\n", I915_READ_START(ring));
......@@ -1177,15 +1162,15 @@ static struct drm_info_list i915_debugfs_list[] = {
{"i915_gem_seqno", i915_gem_seqno_info, 0},
{"i915_gem_fence_regs", i915_gem_fence_regs_info, 0},
{"i915_gem_interrupt", i915_interrupt_info, 0},
{"i915_gem_hws", i915_hws_info, 0, (void *)RING_RENDER},
{"i915_gem_hws_blt", i915_hws_info, 0, (void *)RING_BLT},
{"i915_gem_hws_bsd", i915_hws_info, 0, (void *)RING_BSD},
{"i915_ringbuffer_data", i915_ringbuffer_data, 0, (void *)RING_RENDER},
{"i915_ringbuffer_info", i915_ringbuffer_info, 0, (void *)RING_RENDER},
{"i915_bsd_ringbuffer_data", i915_ringbuffer_data, 0, (void *)RING_BSD},
{"i915_bsd_ringbuffer_info", i915_ringbuffer_info, 0, (void *)RING_BSD},
{"i915_blt_ringbuffer_data", i915_ringbuffer_data, 0, (void *)RING_BLT},
{"i915_blt_ringbuffer_info", i915_ringbuffer_info, 0, (void *)RING_BLT},
{"i915_gem_hws", i915_hws_info, 0, (void *)RCS},
{"i915_gem_hws_blt", i915_hws_info, 0, (void *)BCS},
{"i915_gem_hws_bsd", i915_hws_info, 0, (void *)VCS},
{"i915_ringbuffer_data", i915_ringbuffer_data, 0, (void *)RCS},
{"i915_ringbuffer_info", i915_ringbuffer_info, 0, (void *)RCS},
{"i915_bsd_ringbuffer_data", i915_ringbuffer_data, 0, (void *)VCS},
{"i915_bsd_ringbuffer_info", i915_ringbuffer_info, 0, (void *)VCS},
{"i915_blt_ringbuffer_data", i915_ringbuffer_data, 0, (void *)BCS},
{"i915_blt_ringbuffer_info", i915_ringbuffer_info, 0, (void *)BCS},
{"i915_batchbuffers", i915_batchbuffer_info, 0},
{"i915_error_state", i915_error_state, 0},
{"i915_rstdby_delays", i915_rstdby_delays, 0},
......
......@@ -49,6 +49,8 @@
static int i915_init_phys_hws(struct drm_device *dev)
{
drm_i915_private_t *dev_priv = dev->dev_private;
struct intel_ring_buffer *ring = LP_RING(dev_priv);
/* Program Hardware Status Page */
dev_priv->status_page_dmah =
drm_pci_alloc(dev, PAGE_SIZE, PAGE_SIZE);
......@@ -57,11 +59,10 @@ static int i915_init_phys_hws(struct drm_device *dev)
DRM_ERROR("Can not allocate hardware status page\n");
return -ENOMEM;
}
dev_priv->render_ring.status_page.page_addr
= dev_priv->status_page_dmah->vaddr;
ring->status_page.page_addr = dev_priv->status_page_dmah->vaddr;
dev_priv->dma_status_page = dev_priv->status_page_dmah->busaddr;
memset(dev_priv->render_ring.status_page.page_addr, 0, PAGE_SIZE);
memset(ring->status_page.page_addr, 0, PAGE_SIZE);
if (INTEL_INFO(dev)->gen >= 4)
dev_priv->dma_status_page |= (dev_priv->dma_status_page >> 28) &
......@@ -79,13 +80,15 @@ static int i915_init_phys_hws(struct drm_device *dev)
static void i915_free_hws(struct drm_device *dev)
{
drm_i915_private_t *dev_priv = dev->dev_private;
struct intel_ring_buffer *ring = LP_RING(dev_priv);
if (dev_priv->status_page_dmah) {
drm_pci_free(dev, dev_priv->status_page_dmah);
dev_priv->status_page_dmah = NULL;
}
if (dev_priv->render_ring.status_page.gfx_addr) {
dev_priv->render_ring.status_page.gfx_addr = 0;
if (ring->status_page.gfx_addr) {
ring->status_page.gfx_addr = 0;
drm_core_ioremapfree(&dev_priv->hws_map, dev);
}
......@@ -97,7 +100,7 @@ void i915_kernel_lost_context(struct drm_device * dev)
{
drm_i915_private_t *dev_priv = dev->dev_private;
struct drm_i915_master_private *master_priv;
struct intel_ring_buffer *ring = &dev_priv->render_ring;
struct intel_ring_buffer *ring = LP_RING(dev_priv);
/*
* We should never lose context on the ring with modesetting
......@@ -123,6 +126,8 @@ void i915_kernel_lost_context(struct drm_device * dev)
static int i915_dma_cleanup(struct drm_device * dev)
{
drm_i915_private_t *dev_priv = dev->dev_private;
int i;
/* Make sure interrupts are disabled here because the uninstall ioctl
* may not have been called from userspace and after dev_private
* is freed, it's too late.
......@@ -131,9 +136,8 @@ static int i915_dma_cleanup(struct drm_device * dev)
drm_irq_uninstall(dev);
mutex_lock(&dev->struct_mutex);
intel_cleanup_ring_buffer(&dev_priv->render_ring);
intel_cleanup_ring_buffer(&dev_priv->bsd_ring);
intel_cleanup_ring_buffer(&dev_priv->blt_ring);
for (i = 0; i < I915_NUM_RINGS; i++)
intel_cleanup_ring_buffer(&dev_priv->ring[i]);
mutex_unlock(&dev->struct_mutex);
/* Clear the HWS virtual address at teardown */
......@@ -147,6 +151,7 @@ static int i915_initialize(struct drm_device * dev, drm_i915_init_t * init)
{
drm_i915_private_t *dev_priv = dev->dev_private;
struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv;
struct intel_ring_buffer *ring = LP_RING(dev_priv);
master_priv->sarea = drm_getsarea(dev);
if (master_priv->sarea) {
......@@ -157,24 +162,24 @@ static int i915_initialize(struct drm_device * dev, drm_i915_init_t * init)
}
if (init->ring_size != 0) {
if (dev_priv->render_ring.obj != NULL) {
if (ring->obj != NULL) {
i915_dma_cleanup(dev);
DRM_ERROR("Client tried to initialize ringbuffer in "
"GEM mode\n");
return -EINVAL;
}
dev_priv->render_ring.size = init->ring_size;
ring->size = init->ring_size;
dev_priv->render_ring.map.offset = init->ring_start;
dev_priv->render_ring.map.size = init->ring_size;
dev_priv->render_ring.map.type = 0;
dev_priv->render_ring.map.flags = 0;
dev_priv->render_ring.map.mtrr = 0;
ring->map.offset = init->ring_start;
ring->map.size = init->ring_size;
ring->map.type = 0;
ring->map.flags = 0;
ring->map.mtrr = 0;
drm_core_ioremap_wc(&dev_priv->render_ring.map, dev);
drm_core_ioremap_wc(&ring->map, dev);
if (dev_priv->render_ring.map.handle == NULL) {
if (ring->map.handle == NULL) {
i915_dma_cleanup(dev);
DRM_ERROR("can not ioremap virtual address for"
" ring buffer\n");
......@@ -182,7 +187,7 @@ static int i915_initialize(struct drm_device * dev, drm_i915_init_t * init)
}
}
dev_priv->render_ring.virtual_start = dev_priv->render_ring.map.handle;
ring->virtual_start = ring->map.handle;
dev_priv->cpp = init->cpp;
dev_priv->back_offset = init->back_offset;
......@@ -201,12 +206,10 @@ static int i915_initialize(struct drm_device * dev, drm_i915_init_t * init)
static int i915_dma_resume(struct drm_device * dev)
{
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
struct intel_ring_buffer *ring = LP_RING(dev_priv);
struct intel_ring_buffer *ring;
DRM_DEBUG_DRIVER("%s\n", __func__);
ring = &dev_priv->render_ring;
if (ring->map.handle == NULL) {
DRM_ERROR("can not ioremap virtual address for"
" ring buffer\n");
......@@ -326,7 +329,7 @@ static int i915_emit_cmds(struct drm_device * dev, int *buffer, int dwords)
drm_i915_private_t *dev_priv = dev->dev_private;
int i, ret;
if ((dwords+1) * sizeof(int) >= dev_priv->render_ring.size - 8)
if ((dwords+1) * sizeof(int) >= LP_RING(dev_priv)->size - 8)
return -EINVAL;
for (i = 0; i < dwords;) {
......@@ -565,13 +568,12 @@ static int i915_dispatch_flip(struct drm_device * dev)
return 0;
}
static int i915_quiescent(struct drm_device * dev)
static int i915_quiescent(struct drm_device *dev)
{
drm_i915_private_t *dev_priv = dev->dev_private;
struct intel_ring_buffer *ring = LP_RING(dev->dev_private);
i915_kernel_lost_context(dev);
return intel_wait_ring_buffer(&dev_priv->render_ring,
dev_priv->render_ring.size - 8);
return intel_wait_ring_buffer(ring, ring->size - 8);
}
static int i915_flush_ioctl(struct drm_device *dev, void *data,
......@@ -828,7 +830,7 @@ static int i915_set_status_page(struct drm_device *dev, void *data,
{
drm_i915_private_t *dev_priv = dev->dev_private;
drm_i915_hws_addr_t *hws = data;
struct intel_ring_buffer *ring = &dev_priv->render_ring;
struct intel_ring_buffer *ring = LP_RING(dev_priv);
if (!I915_NEED_GFX_HWS(dev))
return -EINVAL;
......@@ -1978,7 +1980,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
if (!IS_I945G(dev) && !IS_I945GM(dev))
pci_enable_msi(dev->pdev);
spin_lock_init(&dev_priv->user_irq_lock);
spin_lock_init(&dev_priv->irq_lock);
spin_lock_init(&dev_priv->error_lock);
dev_priv->trace_irq_seqno = 0;
......
......@@ -487,11 +487,11 @@ int i915_reset(struct drm_device *dev, u8 flags)
!dev_priv->mm.suspended) {
dev_priv->mm.suspended = 0;
dev_priv->render_ring.init(&dev_priv->render_ring);
dev_priv->ring[RCS].init(&dev_priv->ring[RCS]);
if (HAS_BSD(dev))
dev_priv->bsd_ring.init(&dev_priv->bsd_ring);
dev_priv->ring[VCS].init(&dev_priv->ring[VCS]);
if (HAS_BLT(dev))
dev_priv->blt_ring.init(&dev_priv->blt_ring);
dev_priv->ring[BCS].init(&dev_priv->ring[BCS]);
mutex_unlock(&dev->struct_mutex);
drm_irq_uninstall(dev);
......
......@@ -269,9 +269,7 @@ typedef struct drm_i915_private {
} *gmbus;
struct pci_dev *bridge_dev;
struct intel_ring_buffer render_ring;
struct intel_ring_buffer bsd_ring;
struct intel_ring_buffer blt_ring;
struct intel_ring_buffer ring[I915_NUM_RINGS];
uint32_t next_seqno;
drm_dma_handle_t *status_page_dmah;
......@@ -290,19 +288,15 @@ typedef struct drm_i915_private {
int page_flipping;
atomic_t irq_received;
/** Protects user_irq_refcount and irq_mask_reg */
spinlock_t user_irq_lock;
u32 trace_irq_seqno;
/* protects the irq masks */
spinlock_t irq_lock;
/** Cached value of IMR to avoid reads in updating the bitfield */
u32 irq_mask_reg;
u32 pipestat[2];
/** splitted irq regs for graphics and display engine on Ironlake,
irq_mask_reg is still used for display irq. */
u32 gt_irq_mask_reg;
u32 gt_irq_enable_reg;
u32 de_irq_enable_reg;
u32 pch_irq_mask_reg;
u32 pch_irq_enable_reg;
u32 irq_mask;
u32 gt_irq_mask;
u32 pch_irq_mask;
u32 hotplug_supported_mask;
struct work_struct hotplug_work;
......@@ -1104,7 +1098,8 @@ int __must_check i915_mutex_lock_interruptible(struct drm_device *dev);
int __must_check i915_gem_object_wait_rendering(struct drm_i915_gem_object *obj,
bool interruptible);
void i915_gem_object_move_to_active(struct drm_i915_gem_object *obj,
struct intel_ring_buffer *ring);
struct intel_ring_buffer *ring,
u32 seqno);
/**
* Returns true if seq1 is later than seq2.
......@@ -1272,6 +1267,17 @@ extern void intel_display_print_error_state(struct seq_file *m,
struct intel_display_error_state *error);
#endif
#define LP_RING(d) (&((struct drm_i915_private *)(d))->ring[RCS])
#define BEGIN_LP_RING(n) \
intel_ring_begin(LP_RING(dev_priv), (n))
#define OUT_RING(x) \
intel_ring_emit(LP_RING(dev_priv), x)
#define ADVANCE_LP_RING() \
intel_ring_advance(LP_RING(dev_priv))
/**
* Lock test for when it's just for synchronization of ring access.
*
......@@ -1279,8 +1285,7 @@ extern void intel_display_print_error_state(struct seq_file *m,
* has access to the ring.
*/
#define RING_LOCK_TEST_WITH_RETURN(dev, file) do { \
if (((drm_i915_private_t *)dev->dev_private)->render_ring.obj \
== NULL) \
if (LP_RING(dev->dev_private)->obj == NULL) \
LOCK_TEST_WITH_RETURN(dev, file); \
} while (0)
......@@ -1366,15 +1371,6 @@ i915_write(struct drm_i915_private *dev_priv, u32 reg, u64 val, int len)
}
}
#define BEGIN_LP_RING(n) \
intel_ring_begin(&dev_priv->render_ring, (n))
#define OUT_RING(x) \
intel_ring_emit(&dev_priv->render_ring, x)
#define ADVANCE_LP_RING() \
intel_ring_advance(&dev_priv->render_ring)
/**
* Reads a dword out of the status page, which is written to from the command
* queue by automatic updates, MI_REPORT_HEAD, MI_STORE_DATA_INDEX, or
......@@ -1391,7 +1387,7 @@ i915_write(struct drm_i915_private *dev_priv, u32 reg, u64 val, int len)
* The area from dword 0x20 to 0x3ff is available for driver usage.
*/
#define READ_HWSP(dev_priv, reg) (((volatile u32 *)\
(dev_priv->render_ring.status_page.page_addr))[reg])
(LP_RING(dev_priv)->status_page.page_addr))[reg])
#define READ_BREADCRUMB(dev_priv) READ_HWSP(dev_priv, I915_BREADCRUMB_INDEX)
#define I915_GEM_HWS_INDEX 0x20
#define I915_BREADCRUMB_INDEX 0x21
......
......@@ -1561,11 +1561,11 @@ i915_gem_object_put_pages_gtt(struct drm_i915_gem_object *obj)
void
i915_gem_object_move_to_active(struct drm_i915_gem_object *obj,
struct intel_ring_buffer *ring)
struct intel_ring_buffer *ring,
u32 seqno)
{
struct drm_device *dev = obj->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
uint32_t seqno = i915_gem_next_request_seqno(dev, ring);
BUG_ON(ring == NULL);
obj->ring = ring;
......@@ -1679,7 +1679,8 @@ i915_gem_process_flushing_list(struct drm_device *dev,
obj->base.write_domain = 0;
list_del_init(&obj->gpu_write_list);
i915_gem_object_move_to_active(obj, ring);
i915_gem_object_move_to_active(obj, ring,
i915_gem_next_request_seqno(dev, ring));
trace_i915_gem_object_change_domain(obj,
obj->base.read_domains,
......@@ -1804,10 +1805,10 @@ void i915_gem_reset(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
struct drm_i915_gem_object *obj;
int i;
i915_gem_reset_ring_lists(dev_priv, &dev_priv->render_ring);
i915_gem_reset_ring_lists(dev_priv, &dev_priv->bsd_ring);
i915_gem_reset_ring_lists(dev_priv, &dev_priv->blt_ring);
for (i = 0; i < I915_NUM_RINGS; i++)
i915_gem_reset_ring_lists(dev_priv, &dev_priv->ring[i]);
/* Remove anything from the flushing lists. The GPU cache is likely
* to be lost on reset along with the data, so simply move the
......@@ -1846,6 +1847,7 @@ i915_gem_retire_requests_ring(struct drm_device *dev,
{
drm_i915_private_t *dev_priv = dev->dev_private;
uint32_t seqno;
int i;
if (!ring->status_page.page_addr ||
list_empty(&ring->request_list))
......@@ -1854,6 +1856,11 @@ i915_gem_retire_requests_ring(struct drm_device *dev,
WARN_ON(i915_verify_lists(dev));
seqno = ring->get_seqno(ring);
for (i = 0; i < I915_NUM_RINGS; i++)
if (seqno >= ring->sync_seqno[i])
ring->sync_seqno[i] = 0;
while (!list_empty(&ring->request_list)) {
struct drm_i915_gem_request *request;
......@@ -1892,7 +1899,7 @@ i915_gem_retire_requests_ring(struct drm_device *dev,
if (unlikely (dev_priv->trace_irq_seqno &&
i915_seqno_passed(dev_priv->trace_irq_seqno, seqno))) {
ring->user_irq_put(ring);
ring->irq_put(ring);
dev_priv->trace_irq_seqno = 0;
}
......@@ -1903,6 +1910,7 @@ void
i915_gem_retire_requests(struct drm_device *dev)
{
drm_i915_private_t *dev_priv = dev->dev_private;
int i;
if (!list_empty(&dev_priv->mm.deferred_free_list)) {
struct drm_i915_gem_object *obj, *next;
......@@ -1918,9 +1926,8 @@ i915_gem_retire_requests(struct drm_device *dev)
i915_gem_free_object_tail(obj);
}
i915_gem_retire_requests_ring(dev, &dev_priv->render_ring);
i915_gem_retire_requests_ring(dev, &dev_priv->bsd_ring);
i915_gem_retire_requests_ring(dev, &dev_priv->blt_ring);
for (i = 0; i < I915_NUM_RINGS; i++)
i915_gem_retire_requests_ring(dev, &dev_priv->ring[i]);
}
static void
......@@ -1942,9 +1949,9 @@ i915_gem_retire_work_handler(struct work_struct *work)
i915_gem_retire_requests(dev);
if (!dev_priv->mm.suspended &&
(!list_empty(&dev_priv->render_ring.request_list) ||
!list_empty(&dev_priv->bsd_ring.request_list) ||
!list_empty(&dev_priv->blt_ring.request_list)))
(!list_empty(&dev_priv->ring[RCS].request_list) ||
!list_empty(&dev_priv->ring[VCS].request_list) ||
!list_empty(&dev_priv->ring[BCS].request_list)))
queue_delayed_work(dev_priv->wq, &dev_priv->mm.retire_work, HZ);
mutex_unlock(&dev->struct_mutex);
}
......@@ -1993,7 +2000,7 @@ i915_do_wait_request(struct drm_device *dev, uint32_t seqno,
trace_i915_gem_request_wait_begin(dev, seqno);
ring->waiting_seqno = seqno;
ring->user_irq_get(ring);
ring->irq_get(ring);
if (interruptible)
ret = wait_event_interruptible(ring->irq_queue,
i915_seqno_passed(ring->get_seqno(ring), seqno)
......@@ -2003,7 +2010,7 @@ i915_do_wait_request(struct drm_device *dev, uint32_t seqno,
i915_seqno_passed(ring->get_seqno(ring), seqno)
|| atomic_read(&dev_priv->mm.wedged));
ring->user_irq_put(ring);
ring->irq_put(ring);
ring->waiting_seqno = 0;
trace_i915_gem_request_wait_end(dev, seqno);
......@@ -2159,7 +2166,7 @@ i915_gpu_idle(struct drm_device *dev)
{
drm_i915_private_t *dev_priv = dev->dev_private;
bool lists_empty;
int ret;
int ret, i;
lists_empty = (list_empty(&dev_priv->mm.flushing_list) &&
list_empty(&dev_priv->mm.active_list));
......@@ -2167,17 +2174,11 @@ i915_gpu_idle(struct drm_device *dev)
return 0;
/* Flush everything onto the inactive list. */
ret = i915_ring_idle(dev, &dev_priv->render_ring);
if (ret)
return ret;
ret = i915_ring_idle(dev, &dev_priv->bsd_ring);
if (ret)
return ret;
ret = i915_ring_idle(dev, &dev_priv->blt_ring);
if (ret)
return ret;
for (i = 0; i < I915_NUM_RINGS; i++) {
ret = i915_ring_idle(dev, &dev_priv->ring[i]);
if (ret)
return ret;
}
return 0;
}
......@@ -3153,11 +3154,11 @@ i915_gem_ring_throttle(struct drm_device *dev, struct drm_file *file)
* generation is designed to be run atomically and so is
* lockless.
*/
ring->user_irq_get(ring);
ring->irq_get(ring);
ret = wait_event_interruptible(ring->irq_queue,
i915_seqno_passed(ring->get_seqno(ring), seqno)
|| atomic_read(&dev_priv->mm.wedged));
ring->user_irq_put(ring);
ring->irq_put(ring);
if (ret == 0 && atomic_read(&dev_priv->mm.wedged))
ret = -EIO;
......@@ -3584,9 +3585,9 @@ i915_gem_init_ringbuffer(struct drm_device *dev)
return 0;
cleanup_bsd_ring:
intel_cleanup_ring_buffer(&dev_priv->bsd_ring);
intel_cleanup_ring_buffer(&dev_priv->ring[VCS]);
cleanup_render_ring:
intel_cleanup_ring_buffer(&dev_priv->render_ring);
intel_cleanup_ring_buffer(&dev_priv->ring[RCS]);
return ret;
}
......@@ -3594,10 +3595,10 @@ void
i915_gem_cleanup_ringbuffer(struct drm_device *dev)
{
drm_i915_private_t *dev_priv = dev->dev_private;
int i;
intel_cleanup_ring_buffer(&dev_priv->render_ring);
intel_cleanup_ring_buffer(&dev_priv->bsd_ring);
intel_cleanup_ring_buffer(&dev_priv->blt_ring);
for (i = 0; i < I915_NUM_RINGS; i++)
intel_cleanup_ring_buffer(&dev_priv->ring[i]);
}
int
......@@ -3605,7 +3606,7 @@ i915_gem_entervt_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv)
{
drm_i915_private_t *dev_priv = dev->dev_private;
int ret;
int ret, i;
if (drm_core_check_feature(dev, DRIVER_MODESET))
return 0;
......@@ -3625,14 +3626,12 @@ i915_gem_entervt_ioctl(struct drm_device *dev, void *data,
}
BUG_ON(!list_empty(&dev_priv->mm.active_list));
BUG_ON(!list_empty(&dev_priv->render_ring.active_list));
BUG_ON(!list_empty(&dev_priv->bsd_ring.active_list));
BUG_ON(!list_empty(&dev_priv->blt_ring.active_list));
BUG_ON(!list_empty(&dev_priv->mm.flushing_list));
BUG_ON(!list_empty(&dev_priv->mm.inactive_list));
BUG_ON(!list_empty(&dev_priv->render_ring.request_list));
BUG_ON(!list_empty(&dev_priv->bsd_ring.request_list));
BUG_ON(!list_empty(&dev_priv->blt_ring.request_list));
for (i = 0; i < I915_NUM_RINGS; i++) {
BUG_ON(!list_empty(&dev_priv->ring[i].active_list));
BUG_ON(!list_empty(&dev_priv->ring[i].request_list));
}
mutex_unlock(&dev->struct_mutex);
ret = drm_irq_install(dev);
......@@ -3695,9 +3694,8 @@ i915_gem_load(struct drm_device *dev)
INIT_LIST_HEAD(&dev_priv->mm.fence_list);
INIT_LIST_HEAD(&dev_priv->mm.deferred_free_list);
INIT_LIST_HEAD(&dev_priv->mm.gtt_list);
init_ring_lists(&dev_priv->render_ring);
init_ring_lists(&dev_priv->bsd_ring);
init_ring_lists(&dev_priv->blt_ring);
for (i = 0; i < I915_NUM_RINGS; i++)
init_ring_lists(&dev_priv->ring[i]);
for (i = 0; i < 16; i++)
INIT_LIST_HEAD(&dev_priv->fence_regs[i].lru_list);
INIT_DELAYED_WORK(&dev_priv->mm.retire_work,
......
......@@ -632,23 +632,59 @@ i915_gem_execbuffer_flush(struct drm_device *dev,
uint32_t flush_rings)
{
drm_i915_private_t *dev_priv = dev->dev_private;
int i;
if (flush_domains & I915_GEM_DOMAIN_CPU)
intel_gtt_chipset_flush();
if ((flush_domains | invalidate_domains) & I915_GEM_GPU_DOMAINS) {
if (flush_rings & RING_RENDER)
i915_gem_flush_ring(dev, &dev_priv->render_ring,
invalidate_domains, flush_domains);
if (flush_rings & RING_BSD)
i915_gem_flush_ring(dev, &dev_priv->bsd_ring,
invalidate_domains, flush_domains);
if (flush_rings & RING_BLT)
i915_gem_flush_ring(dev, &dev_priv->blt_ring,
invalidate_domains, flush_domains);
for (i = 0; i < I915_NUM_RINGS; i++)
if (flush_rings & (1 << i))
i915_gem_flush_ring(dev, &dev_priv->ring[i],
invalidate_domains,
flush_domains);
}
}
static int
i915_gem_execbuffer_sync_rings(struct drm_i915_gem_object *obj,
struct intel_ring_buffer *to)
{
struct intel_ring_buffer *from = obj->ring;
u32 seqno;
int ret, idx;
if (from == NULL || to == from)
return 0;
if (INTEL_INFO(obj->base.dev)->gen < 6)
return i915_gem_object_wait_rendering(obj, true);
idx = intel_ring_sync_index(from, to);
seqno = obj->last_rendering_seqno;
if (seqno <= from->sync_seqno[idx])
return 0;
if (seqno == from->outstanding_lazy_request) {
struct drm_i915_gem_request *request;
request = kzalloc(sizeof(*request), GFP_KERNEL);
if (request == NULL)
return -ENOMEM;
ret = i915_add_request(obj->base.dev, NULL, request, from);
if (ret) {
kfree(request);
return ret;
}
seqno = request->seqno;
}
from->sync_seqno[idx] = seqno;
return intel_ring_sync(to, from, seqno - 1);
}
static int
i915_gem_execbuffer_move_to_gpu(struct intel_ring_buffer *ring,
......@@ -678,12 +714,9 @@ i915_gem_execbuffer_move_to_gpu(struct intel_ring_buffer *ring,
}
list_for_each_entry(obj, objects, exec_list) {
/* XXX replace with semaphores */
if (obj->ring && ring != obj->ring) {
ret = i915_gem_object_wait_rendering(obj, true);
if (ret)
return ret;
}
ret = i915_gem_execbuffer_sync_rings(obj, ring);
if (ret)
return ret;
}
return 0;
......@@ -769,7 +802,8 @@ i915_gem_execbuffer_wait_for_flips(struct intel_ring_buffer *ring,
static void
i915_gem_execbuffer_move_to_active(struct list_head *objects,
struct intel_ring_buffer *ring)
struct intel_ring_buffer *ring,
u32 seqno)
{
struct drm_i915_gem_object *obj;
......@@ -778,7 +812,7 @@ i915_gem_execbuffer_move_to_active(struct list_head *objects,
obj->base.write_domain = obj->base.pending_write_domain;
obj->fenced_gpu_access = obj->pending_fenced_gpu_access;
i915_gem_object_move_to_active(obj, ring);
i915_gem_object_move_to_active(obj, ring, seqno);
if (obj->base.write_domain) {
obj->dirty = 1;
obj->pending_gpu_write = true;
......@@ -833,6 +867,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
struct drm_clip_rect *cliprects = NULL;
struct intel_ring_buffer *ring;
u32 exec_start, exec_len;
u32 seqno;
int ret, i;
if (!i915_gem_check_execbuffer(args)) {
......@@ -851,21 +886,21 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
switch (args->flags & I915_EXEC_RING_MASK) {
case I915_EXEC_DEFAULT:
case I915_EXEC_RENDER:
ring = &dev_priv->render_ring;
ring = &dev_priv->ring[RCS];
break;
case I915_EXEC_BSD:
if (!HAS_BSD(dev)) {
DRM_ERROR("execbuf with invalid ring (BSD)\n");
return -EINVAL;
}
ring = &dev_priv->bsd_ring;
ring = &dev_priv->ring[VCS];
break;
case I915_EXEC_BLT:
if (!HAS_BLT(dev)) {
DRM_ERROR("execbuf with invalid ring (BLT)\n");
return -EINVAL;
}
ring = &dev_priv->blt_ring;
ring = &dev_priv->ring[BCS];
break;
default:
DRM_ERROR("execbuf with unknown ring: %d\n",
......@@ -879,7 +914,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
}
if (args->num_cliprects != 0) {
if (ring != &dev_priv->render_ring) {
if (ring != &dev_priv->ring[RCS]) {
DRM_ERROR("clip rectangles are only valid with the render ring\n");
return -EINVAL;
}
......@@ -972,6 +1007,21 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
if (ret)
goto err;
seqno = i915_gem_next_request_seqno(dev, ring);
for (i = 0; i < I915_NUM_RINGS-1; i++) {
if (seqno < ring->sync_seqno[i]) {
/* The GPU can not handle its semaphore value wrapping,
* so every billion or so execbuffers, we need to stall
* the GPU in order to reset the counters.
*/
ret = i915_gpu_idle(dev);
if (ret)
goto err;
BUG_ON(ring->sync_seqno[i]);
}
}
exec_start = batch_obj->gtt_offset + args->batch_start_offset;
exec_len = args->batch_len;
if (cliprects) {
......@@ -992,7 +1042,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
goto err;
}
i915_gem_execbuffer_move_to_active(&objects, ring);
i915_gem_execbuffer_move_to_active(&objects, ring, seqno);
i915_gem_execbuffer_retire_commands(dev, file, ring);
err:
......
This diff is collapsed.
......@@ -176,6 +176,11 @@
#define MI_BATCH_NON_SECURE (1)
#define MI_BATCH_NON_SECURE_I965 (1<<8)
#define MI_BATCH_BUFFER_START MI_INSTR(0x31, 0)
#define MI_SEMAPHORE_MBOX MI_INSTR(0x16, 1) /* gen6+ */
#define MI_SEMAPHORE_GLOBAL_GTT (1<<22)
#define MI_SEMAPHORE_UPDATE (1<<21)
#define MI_SEMAPHORE_COMPARE (1<<20)
#define MI_SEMAPHORE_REGISTER (1<<18)
/*
* 3D instructions used by the kernel
*/
......@@ -276,9 +281,12 @@
#define RING_HEAD(base) ((base)+0x34)
#define RING_START(base) ((base)+0x38)
#define RING_CTL(base) ((base)+0x3c)
#define RING_SYNC_0(base) ((base)+0x40)
#define RING_SYNC_1(base) ((base)+0x44)
#define RING_HWS_PGA(base) ((base)+0x80)
#define RING_HWS_PGA_GEN6(base) ((base)+0x2080)
#define RING_ACTHD(base) ((base)+0x74)
#define RING_NOPID(base) ((base)+0x94)
#define TAIL_ADDR 0x001FFFF8
#define HEAD_WRAP_COUNT 0xFFE00000
#define HEAD_WRAP_ONE 0x00200000
......@@ -293,6 +301,7 @@
#define RING_INVALID 0x00000000
#define RING_WAIT_I8XX (1<<0) /* gen2, PRBx_HEAD */
#define RING_WAIT (1<<11) /* gen3+, PRBx_CTL */
#define RING_WAIT_SEMAPHORE (1<<10) /* gen6+ */
#if 0
#define PRB0_TAIL 0x02030
#define PRB0_HEAD 0x02034
......@@ -347,6 +356,14 @@
# define VS_TIMER_DISPATCH (1 << 6)
# define MI_FLUSH_ENABLE (1 << 11)
#define GFX_MODE 0x02520
#define GFX_RUN_LIST_ENABLE (1<<15)
#define GFX_TLB_INVALIDATE_ALWAYS (1<<13)
#define GFX_SURFACE_FAULT_ENABLE (1<<12)
#define GFX_REPLAY_MODE (1<<11)
#define GFX_PSMI_GRANULARITY (1<<10)
#define GFX_PPGTT_ENABLE (1<<9)
#define SCPD0 0x0209c /* 915+ only */
#define IER 0x020a0
#define IIR 0x020a4
......@@ -498,7 +515,7 @@
#define GEN6_BSD_SLEEP_PSMI_CONTROL_IDLE_INDICATOR (1 << 3)
#define GEN6_BSD_IMR 0x120a8
#define GEN6_BSD_IMR_USER_INTERRUPT (1 << 12)
#define GEN6_BSD_USER_INTERRUPT (1 << 12)
#define GEN6_BSD_RNCID 0x12198
......
......@@ -1998,7 +1998,7 @@ static void intel_clear_scanline_wait(struct drm_device *dev)
/* Can't break the hang on i8xx */
return;
ring = &dev_priv->render_ring;
ring = LP_RING(dev_priv);
tmp = I915_READ_CTL(ring);
if (tmp & RING_WAIT)
I915_WRITE_CTL(ring, tmp);
......@@ -5124,7 +5124,7 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
obj = intel_fb->obj;
mutex_lock(&dev->struct_mutex);
ret = intel_pin_and_fence_fb_obj(dev, obj, &dev_priv->render_ring);
ret = intel_pin_and_fence_fb_obj(dev, obj, LP_RING(dev_priv));
if (ret)
goto cleanup_work;
......
......@@ -273,14 +273,8 @@ void intel_opregion_enable_asle(struct drm_device *dev)
struct opregion_asle *asle = dev_priv->opregion.asle;
if (asle) {
if (IS_MOBILE(dev)) {
unsigned long irqflags;
spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags);
if (IS_MOBILE(dev))
intel_enable_asle(dev);
spin_unlock_irqrestore(&dev_priv->user_irq_lock,
irqflags);
}
asle->tche = ASLE_ALS_EN | ASLE_BLC_EN | ASLE_PFIT_EN |
ASLE_PFMB_EN;
......
......@@ -221,7 +221,7 @@ static int intel_overlay_do_wait_request(struct intel_overlay *overlay,
int ret;
BUG_ON(overlay->last_flip_req);
ret = i915_add_request(dev, NULL, request, &dev_priv->render_ring);
ret = i915_add_request(dev, NULL, request, LP_RING(dev_priv));
if (ret) {
kfree(request);
return ret;
......@@ -230,7 +230,7 @@ static int intel_overlay_do_wait_request(struct intel_overlay *overlay,
overlay->flip_tail = tail;
ret = i915_do_wait_request(dev,
overlay->last_flip_req, true,
&dev_priv->render_ring);
LP_RING(dev_priv));
if (ret)
return ret;
......@@ -364,7 +364,7 @@ static int intel_overlay_continue(struct intel_overlay *overlay,
OUT_RING(flip_addr);
ADVANCE_LP_RING();
ret = i915_add_request(dev, NULL, request, &dev_priv->render_ring);
ret = i915_add_request(dev, NULL, request, LP_RING(dev_priv));
if (ret) {
kfree(request);
return ret;
......@@ -454,7 +454,7 @@ static int intel_overlay_recover_from_interrupt(struct intel_overlay *overlay,
return 0;
ret = i915_do_wait_request(dev, overlay->last_flip_req,
interruptible, &dev_priv->render_ring);
interruptible, LP_RING(dev_priv));
if (ret)
return ret;
......
This diff is collapsed.
#ifndef _INTEL_RINGBUFFER_H_
#define _INTEL_RINGBUFFER_H_
enum {
RCS = 0x0,
VCS,
BCS,
I915_NUM_RINGS,
};
struct intel_hw_status_page {
u32 __iomem *page_addr;
unsigned int gfx_addr;
......@@ -21,7 +28,10 @@ struct intel_hw_status_page {
#define I915_READ_CTL(ring) I915_RING_READ(RING_CTL(ring->mmio_base))
#define I915_WRITE_CTL(ring, val) I915_WRITE(RING_CTL(ring->mmio_base), val)
struct drm_i915_gem_execbuffer2;
#define I915_READ_NOPID(ring) I915_RING_READ(RING_NOPID(ring->mmio_base))
#define I915_READ_SYNC_0(ring) I915_RING_READ(RING_SYNC_0(ring->mmio_base))
#define I915_READ_SYNC_1(ring) I915_RING_READ(RING_SYNC_1(ring->mmio_base))
struct intel_ring_buffer {
const char *name;
enum intel_ring_id {
......@@ -42,9 +52,10 @@ struct intel_ring_buffer {
u32 irq_seqno; /* last seq seem at irq time */
u32 waiting_seqno;
int user_irq_refcount;
void (*user_irq_get)(struct intel_ring_buffer *ring);
void (*user_irq_put)(struct intel_ring_buffer *ring);
u32 sync_seqno[I915_NUM_RINGS-1];
u32 irq_refcount;
void (*irq_get)(struct intel_ring_buffer *ring);
void (*irq_put)(struct intel_ring_buffer *ring);
int (*init)(struct intel_ring_buffer *ring);
......@@ -98,6 +109,25 @@ struct intel_ring_buffer {
void *private;
};
static inline u32
intel_ring_sync_index(struct intel_ring_buffer *ring,
struct intel_ring_buffer *other)
{
int idx;
/*
* cs -> 0 = vcs, 1 = bcs
* vcs -> 0 = bcs, 1 = cs,
* bcs -> 0 = cs, 1 = vcs.
*/
idx = (other - ring) - 1;
if (idx < 0)
idx += I915_NUM_RINGS;
return idx;
}
static inline u32
intel_read_status_page(struct intel_ring_buffer *ring,
int reg)
......@@ -119,6 +149,9 @@ static inline void intel_ring_emit(struct intel_ring_buffer *ring,
void intel_ring_advance(struct intel_ring_buffer *ring);
u32 intel_ring_get_seqno(struct intel_ring_buffer *ring);
int intel_ring_sync(struct intel_ring_buffer *ring,
struct intel_ring_buffer *to,
u32 seqno);
int intel_init_render_ring_buffer(struct drm_device *dev);
int intel_init_bsd_ring_buffer(struct drm_device *dev);
......
......@@ -1245,10 +1245,11 @@ intel_tv_detect_type (struct intel_tv *intel_tv)
int type;
/* Disable TV interrupts around load detect or we'll recurse */
spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags);
i915_disable_pipestat(dev_priv, 0, PIPE_HOTPLUG_INTERRUPT_ENABLE |
spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
i915_disable_pipestat(dev_priv, 0,
PIPE_HOTPLUG_INTERRUPT_ENABLE |
PIPE_HOTPLUG_TV_INTERRUPT_ENABLE);
spin_unlock_irqrestore(&dev_priv->user_irq_lock, irqflags);
spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
save_tv_dac = tv_dac = I915_READ(TV_DAC);
save_tv_ctl = tv_ctl = I915_READ(TV_CTL);
......@@ -1301,10 +1302,11 @@ intel_tv_detect_type (struct intel_tv *intel_tv)
I915_WRITE(TV_CTL, save_tv_ctl);
/* Restore interrupt config */
spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags);
i915_enable_pipestat(dev_priv, 0, PIPE_HOTPLUG_INTERRUPT_ENABLE |
spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
i915_enable_pipestat(dev_priv, 0,
PIPE_HOTPLUG_INTERRUPT_ENABLE |
PIPE_HOTPLUG_TV_INTERRUPT_ENABLE);
spin_unlock_irqrestore(&dev_priv->user_irq_lock, irqflags);
spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
return type;
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment