diff options
29 files changed, 943 insertions, 559 deletions
diff --git a/linux-core/drmP.h b/linux-core/drmP.h index ab17ba0e..297d8d60 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -878,6 +878,8 @@ struct drm_device { u32 *last_vblank; /* protected by dev->vbl_lock, used */ /* for wraparound handling */ u32 *vblank_offset; /* used to track how many vblanks */ + int *vblank_enabled; /* so we don't call enable more than + once per disable */ u32 *vblank_premodeset; /* were lost during modeset */ struct timer_list vblank_disable_timer; diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index 6b3d4e14..1f3c2d2c 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -287,7 +287,7 @@ int drm_bo_wait(struct drm_buffer_object *bo, int lazy, int ignore_signals, DRM_ASSERT_LOCKED(&bo->mutex); if (bo->fence) { - if (drm_fence_object_signaled(bo->fence, bo->fence_type, 0)) { + if (drm_fence_object_signaled(bo->fence, bo->fence_type)) { drm_fence_usage_deref_unlocked(&bo->fence); return 0; } @@ -354,7 +354,7 @@ static void drm_bo_cleanup_refs(struct drm_buffer_object *bo, int remove_all) DRM_FLAG_MASKED(bo->priv_flags, 0, _DRM_BO_FLAG_UNFENCED); if (bo->fence && drm_fence_object_signaled(bo->fence, - bo->fence_type, 0)) + bo->fence_type)) drm_fence_usage_deref_unlocked(&bo->fence); if (bo->fence && remove_all) @@ -559,7 +559,7 @@ void drm_putback_buffer_objects(struct drm_device *dev) list_del_init(&entry->lru); DRM_FLAG_MASKED(entry->priv_flags, 0, _DRM_BO_FLAG_UNFENCED); - DRM_WAKEUP(&entry->event_queue); + wake_up_all(&entry->event_queue); /* * FIXME: Might want to put back on head of list @@ -659,7 +659,7 @@ int drm_fence_buffer_objects(struct drm_device *dev, entry->fence_type = entry->new_fence_type; DRM_FLAG_MASKED(entry->priv_flags, 0, _DRM_BO_FLAG_UNFENCED); - DRM_WAKEUP(&entry->event_queue); + wake_up_all(&entry->event_queue); drm_bo_add_to_lru(entry); } mutex_unlock(&entry->mutex); @@ -1031,7 +1031,7 @@ static int drm_bo_quick_busy(struct drm_buffer_object *bo) BUG_ON(bo->priv_flags & _DRM_BO_FLAG_UNFENCED); if (fence) { - if (drm_fence_object_signaled(fence, bo->fence_type, 0)) { + if (drm_fence_object_signaled(fence, bo->fence_type)) { drm_fence_usage_deref_unlocked(&bo->fence); return 0; } @@ -1051,12 +1051,12 @@ static int drm_bo_busy(struct drm_buffer_object *bo) BUG_ON(bo->priv_flags & _DRM_BO_FLAG_UNFENCED); if (fence) { - if (drm_fence_object_signaled(fence, bo->fence_type, 0)) { + if (drm_fence_object_signaled(fence, bo->fence_type)) { drm_fence_usage_deref_unlocked(&bo->fence); return 0; } drm_fence_object_flush(fence, DRM_FENCE_TYPE_EXE); - if (drm_fence_object_signaled(fence, bo->fence_type, 0)) { + if (drm_fence_object_signaled(fence, bo->fence_type)) { drm_fence_usage_deref_unlocked(&bo->fence); return 0; } @@ -1248,7 +1248,7 @@ static int drm_buffer_object_map(struct drm_file *file_priv, uint32_t handle, mutex_unlock(&dev->struct_mutex); if (ret) { if (atomic_add_negative(-1, &bo->mapped)) - DRM_WAKEUP(&bo->event_queue); + wake_up_all(&bo->event_queue); } else drm_bo_fill_rep_arg(bo, rep); @@ -1305,7 +1305,7 @@ static void drm_buffer_user_object_unmap(struct drm_file *file_priv, BUG_ON(action != _DRM_REF_TYPE1); if (atomic_add_negative(-1, &bo->mapped)) - DRM_WAKEUP(&bo->event_queue); + wake_up_all(&bo->event_queue); } /* @@ -1363,7 +1363,7 @@ out_unlock: } drm_bo_add_to_lru(bo); if (bo->priv_flags & _DRM_BO_FLAG_UNFENCED) { - DRM_WAKEUP(&bo->event_queue); + wake_up_all(&bo->event_queue); DRM_FLAG_MASKED(bo->priv_flags, 0, _DRM_BO_FLAG_UNFENCED); } @@ -1441,13 +1441,21 @@ static int drm_buffer_object_validate(struct drm_buffer_object *bo, * We're switching command submission mechanism, * or cannot simply rely on the hardware serializing for us. * - * Wait for buffer idle. + * Insert a driver-dependant barrier or wait for buffer idle. */ if ((fence_class != bo->fence_class) || ((ftype ^ bo->fence_type) & bo->fence_type)) { - ret = drm_bo_wait(bo, 0, 0, no_wait); + ret = -EINVAL; + if (driver->command_stream_barrier) { + ret = driver->command_stream_barrier(bo, + fence_class, + ftype, + no_wait); + } + if (ret) + ret = drm_bo_wait(bo, 0, 0, no_wait); if (ret) return ret; @@ -1538,7 +1546,7 @@ static int drm_buffer_object_validate(struct drm_buffer_object *bo, } else { drm_bo_add_to_lru(bo); if (bo->priv_flags & _DRM_BO_FLAG_UNFENCED) { - DRM_WAKEUP(&bo->event_queue); + wake_up_all(&bo->event_queue); DRM_FLAG_MASKED(bo->priv_flags, 0, _DRM_BO_FLAG_UNFENCED); } diff --git a/linux-core/drm_fence.c b/linux-core/drm_fence.c index b2c4e9c9..9d80327f 100644 --- a/linux-core/drm_fence.c +++ b/linux-core/drm_fence.c @@ -30,6 +30,57 @@ #include "drmP.h" + +/* + * Convenience function to be called by fence::wait methods that + * need polling. + */ + +int drm_fence_wait_polling(struct drm_fence_object *fence, int lazy, + int interruptible, uint32_t mask, + unsigned long end_jiffies) +{ + struct drm_device *dev = fence->dev; + struct drm_fence_manager *fm = &dev->fm; + struct drm_fence_class_manager *fc = &fm->fence_class[fence->fence_class]; + uint32_t count = 0; + int ret; + + DECLARE_WAITQUEUE(entry, current); + add_wait_queue(&fc->fence_queue, &entry); + + ret = 0; + + for (;;) { + __set_current_state((interruptible) ? + TASK_INTERRUPTIBLE : + TASK_UNINTERRUPTIBLE); + if (drm_fence_object_signaled(fence, mask)) + break; + if (time_after_eq(jiffies, end_jiffies)) { + ret = -EBUSY; + break; + } + if (lazy) + schedule_timeout(1); + else if ((++count & 0x0F) == 0){ + __set_current_state(TASK_RUNNING); + schedule(); + __set_current_state((interruptible) ? + TASK_INTERRUPTIBLE : + TASK_UNINTERRUPTIBLE); + } + if (interruptible && signal_pending(current)) { + ret = -EAGAIN; + break; + } + } + __set_current_state(TASK_RUNNING); + remove_wait_queue(&fc->fence_queue, &entry); + return ret; +} +EXPORT_SYMBOL(drm_fence_wait_polling); + /* * Typically called by the IRQ handler. */ @@ -39,27 +90,14 @@ void drm_fence_handler(struct drm_device *dev, uint32_t fence_class, { int wake = 0; uint32_t diff; - uint32_t relevant; + uint32_t relevant_type; + uint32_t new_type; struct drm_fence_manager *fm = &dev->fm; struct drm_fence_class_manager *fc = &fm->fence_class[fence_class]; struct drm_fence_driver *driver = dev->driver->fence_driver; struct list_head *head; struct drm_fence_object *fence, *next; int found = 0; - int is_exe = (type & DRM_FENCE_TYPE_EXE); - int ge_last_exe; - - - diff = (sequence - fc->exe_flush_sequence) & driver->sequence_mask; - - if (fc->pending_exe_flush && is_exe && diff < driver->wrap_diff) - fc->pending_exe_flush = 0; - - diff = (sequence - fc->last_exe_flush) & driver->sequence_mask; - ge_last_exe = diff < driver->wrap_diff; - - if (is_exe && ge_last_exe) - fc->last_exe_flush = sequence; if (list_empty(&fc->ring)) return; @@ -72,7 +110,7 @@ void drm_fence_handler(struct drm_device *dev, uint32_t fence_class, } } - fc->pending_flush &= ~type; + fc->waiting_types &= ~type; head = (found) ? &fence->ring : &fc->ring; list_for_each_entry_safe_reverse(fence, next, head, ring) { @@ -81,64 +119,60 @@ void drm_fence_handler(struct drm_device *dev, uint32_t fence_class, if (error) { fence->error = error; - fence->signaled = fence->type; - fence->submitted_flush = fence->type; - fence->flush_mask = fence->type; + fence->signaled_types = fence->type; list_del_init(&fence->ring); wake = 1; break; } - if (is_exe) - type |= fence->native_type; + if (type & DRM_FENCE_TYPE_EXE) + type |= fence->native_types; - relevant = type & fence->type; + relevant_type = type & fence->type; + new_type = (fence->signaled_types | relevant_type) ^ + fence->signaled_types; - if ((fence->signaled | relevant) != fence->signaled) { - fence->signaled |= relevant; - fence->flush_mask |= relevant; - fence->submitted_flush |= relevant; + if (new_type) { + fence->signaled_types |= new_type; DRM_DEBUG("Fence 0x%08lx signaled 0x%08x\n", - fence->base.hash.key, fence->signaled); - wake = 1; - } + fence->base.hash.key, fence->signaled_types); + + if (driver->needed_flush) + fc->pending_flush |= driver->needed_flush(fence); - relevant = fence->flush_mask & - ~(fence->submitted_flush | fence->signaled); + if (new_type & fence->waiting_types) + wake = 1; + } - fc->pending_flush |= relevant; - fence->submitted_flush |= relevant; + fc->waiting_types |= fence->waiting_types & ~fence->signaled_types; - if (!(fence->type & ~fence->signaled)) { + if (!(fence->type & ~fence->signaled_types)) { DRM_DEBUG("Fence completely signaled 0x%08lx\n", fence->base.hash.key); list_del_init(&fence->ring); } - } /* - * Reinstate lost flush flags. + * Reinstate lost waiting types. */ - if ((fc->pending_flush & type) != type) { + if ((fc->waiting_types & type) != type) { head = head->prev; list_for_each_entry(fence, head, ring) { if (&fence->ring == &fc->ring) break; - diff = (fc->last_exe_flush - fence->sequence) & + diff = (fc->highest_waiting_sequence - fence->sequence) & driver->sequence_mask; if (diff > driver->wrap_diff) break; - - relevant = fence->submitted_flush & ~fence->signaled; - fc->pending_flush |= relevant; + + fc->waiting_types |= fence->waiting_types & ~fence->signaled_types; } } - if (wake) { - DRM_WAKEUP(&fc->fence_queue); - } + if (wake) + wake_up_all(&fc->fence_queue); } EXPORT_SYMBOL(drm_fence_handler); @@ -219,41 +253,28 @@ static void drm_fence_object_destroy(struct drm_file *priv, drm_fence_usage_deref_locked(&fence); } -int drm_fence_object_signaled(struct drm_fence_object *fence, - uint32_t mask, int poke_flush) +int drm_fence_object_signaled(struct drm_fence_object *fence, uint32_t mask) { unsigned long flags; int signaled; struct drm_device *dev = fence->dev; struct drm_fence_manager *fm = &dev->fm; struct drm_fence_driver *driver = dev->driver->fence_driver; - - if (poke_flush) - driver->poke_flush(dev, fence->fence_class); + + mask &= fence->type; read_lock_irqsave(&fm->lock, flags); - signaled = - (fence->type & mask & fence->signaled) == (fence->type & mask); + signaled = (mask & fence->signaled_types) == mask; read_unlock_irqrestore(&fm->lock, flags); - + if (!signaled && driver->poll) { + write_lock_irqsave(&fm->lock, flags); + driver->poll(dev, fence->fence_class, mask); + signaled = (mask & fence->signaled_types) == mask; + write_unlock_irqrestore(&fm->lock, flags); + } return signaled; } EXPORT_SYMBOL(drm_fence_object_signaled); -static void drm_fence_flush_exe(struct drm_fence_class_manager *fc, - struct drm_fence_driver *driver, - uint32_t sequence) -{ - uint32_t diff; - - if (!fc->pending_exe_flush) { - fc->exe_flush_sequence = sequence; - fc->pending_exe_flush = 1; - } else { - diff = (sequence - fc->exe_flush_sequence) & driver->sequence_mask; - if (diff < driver->wrap_diff) - fc->exe_flush_sequence = sequence; - } -} int drm_fence_object_flush(struct drm_fence_object *fence, uint32_t type) @@ -262,7 +283,10 @@ int drm_fence_object_flush(struct drm_fence_object *fence, struct drm_fence_manager *fm = &dev->fm; struct drm_fence_class_manager *fc = &fm->fence_class[fence->fence_class]; struct drm_fence_driver *driver = dev->driver->fence_driver; - unsigned long flags; + unsigned long irq_flags; + uint32_t saved_pending_flush; + uint32_t diff; + int call_flush; if (type & ~fence->type) { DRM_ERROR("Flush trying to extend fence type, " @@ -270,24 +294,36 @@ int drm_fence_object_flush(struct drm_fence_object *fence, return -EINVAL; } - write_lock_irqsave(&fm->lock, flags); - fence->flush_mask |= type; - if ((fence->submitted_flush & fence->signaled) - == fence->submitted_flush) { - if ((fence->type & DRM_FENCE_TYPE_EXE) && - !(fence->submitted_flush & DRM_FENCE_TYPE_EXE)) { - drm_fence_flush_exe(fc, driver, fence->sequence); - fence->submitted_flush |= DRM_FENCE_TYPE_EXE; - } else { - fc->pending_flush |= (fence->flush_mask & - ~fence->submitted_flush); - fence->submitted_flush = fence->flush_mask; - } - } - write_unlock_irqrestore(&fm->lock, flags); - driver->poke_flush(dev, fence->fence_class); + write_lock_irqsave(&fm->lock, irq_flags); + fence->waiting_types |= type; + fc->waiting_types |= fence->waiting_types; + diff = (fence->sequence - fc->highest_waiting_sequence) & + driver->sequence_mask; + + if (diff < driver->wrap_diff) + fc->highest_waiting_sequence = fence->sequence; + + /* + * fence->waiting_types has changed. Determine whether + * we need to initiate some kind of flush as a result of this. + */ + + saved_pending_flush = fc->pending_flush; + if (driver->needed_flush) + fc->pending_flush |= driver->needed_flush(fence); + + if (driver->poll) + driver->poll(dev, fence->fence_class, fence->waiting_types); + + call_flush = fc->pending_flush; + write_unlock_irqrestore(&fm->lock, irq_flags); + + if (call_flush && driver->flush) + driver->flush(dev, fence->fence_class); + return 0; } +EXPORT_SYMBOL(drm_fence_object_flush); /* * Make sure old fence objects are signaled before their fence sequences are @@ -299,90 +335,52 @@ void drm_fence_flush_old(struct drm_device *dev, uint32_t fence_class, { struct drm_fence_manager *fm = &dev->fm; struct drm_fence_class_manager *fc = &fm->fence_class[fence_class]; - struct drm_fence_driver *driver = dev->driver->fence_driver; - uint32_t old_sequence; - unsigned long flags; struct drm_fence_object *fence; + unsigned long irq_flags; + struct drm_fence_driver *driver = dev->driver->fence_driver; + int call_flush; + uint32_t diff; - write_lock_irqsave(&fm->lock, flags); - old_sequence = (sequence - driver->flush_diff) & driver->sequence_mask; - diff = (old_sequence - fc->last_exe_flush) & driver->sequence_mask; + write_lock_irqsave(&fm->lock, irq_flags); - if ((diff < driver->wrap_diff) && !fc->pending_exe_flush) { - fc->pending_exe_flush = 1; - fc->exe_flush_sequence = sequence - (driver->flush_diff / 2); - } - write_unlock_irqrestore(&fm->lock, flags); + list_for_each_entry_reverse(fence, &fc->ring, ring) { + diff = (sequence - fence->sequence) & driver->sequence_mask; + if (diff <= driver->flush_diff) + break; + + fence->waiting_types = fence->type; + fc->waiting_types |= fence->type; - mutex_lock(&dev->struct_mutex); - read_lock_irqsave(&fm->lock, flags); + if (driver->needed_flush) + fc->pending_flush |= driver->needed_flush(fence); + } + + if (driver->poll) + driver->poll(dev, fence_class, fc->waiting_types); - if (list_empty(&fc->ring)) { - read_unlock_irqrestore(&fm->lock, flags); - mutex_unlock(&dev->struct_mutex); - return; - } - fence = drm_fence_reference_locked(list_entry(fc->ring.next, struct drm_fence_object, ring)); - mutex_unlock(&dev->struct_mutex); - diff = (old_sequence - fence->sequence) & driver->sequence_mask; - read_unlock_irqrestore(&fm->lock, flags); - if (diff < driver->wrap_diff) - drm_fence_object_flush(fence, fence->type); - drm_fence_usage_deref_unlocked(&fence); -} -EXPORT_SYMBOL(drm_fence_flush_old); + call_flush = fc->pending_flush; + write_unlock_irqrestore(&fm->lock, irq_flags); -static int drm_fence_lazy_wait(struct drm_fence_object *fence, - int ignore_signals, - uint32_t mask) -{ - struct drm_device *dev = fence->dev; - struct drm_fence_manager *fm = &dev->fm; - struct drm_fence_class_manager *fc = &fm->fence_class[fence->fence_class]; - int signaled; - unsigned long _end = jiffies + 3*DRM_HZ; - int ret = 0; + if (call_flush && driver->flush) + driver->flush(dev, fence->fence_class); + + /* + * FIXME: Shold we implement a wait here for really old fences? + */ - do { - DRM_WAIT_ON(ret, fc->fence_queue, 3 * DRM_HZ, - (signaled = drm_fence_object_signaled(fence, mask, 1))); - if (signaled) - return 0; - if (time_after_eq(jiffies, _end)) - break; - } while (ret == -EINTR && ignore_signals); - if (drm_fence_object_signaled(fence, mask, 0)) - return 0; - if (time_after_eq(jiffies, _end)) - ret = -EBUSY; - if (ret) { - if (ret == -EBUSY) { - DRM_ERROR("Fence timeout. " - "GPU lockup or fence driver was " - "taken down. %d 0x%08x 0x%02x 0x%02x 0x%02x\n", - fence->fence_class, - fence->sequence, - fence->type, - mask, - fence->signaled); - DRM_ERROR("Pending exe flush %d 0x%08x\n", - fc->pending_exe_flush, - fc->exe_flush_sequence); - } - return ((ret == -EINTR) ? -EAGAIN : ret); - } - return 0; } +EXPORT_SYMBOL(drm_fence_flush_old); int drm_fence_object_wait(struct drm_fence_object *fence, int lazy, int ignore_signals, uint32_t mask) { struct drm_device *dev = fence->dev; struct drm_fence_driver *driver = dev->driver->fence_driver; + struct drm_fence_manager *fm = &dev->fm; + struct drm_fence_class_manager *fc = &fm->fence_class[fence->fence_class]; int ret = 0; - unsigned long _end; - int signaled; + unsigned long _end = 3 * DRM_HZ; if (mask & ~fence->type) { DRM_ERROR("Wait trying to extend fence type" @@ -391,58 +389,39 @@ int drm_fence_object_wait(struct drm_fence_object *fence, return -EINVAL; } - if (drm_fence_object_signaled(fence, mask, 0)) - return 0; + if (driver->wait) + return driver->wait(fence, lazy, !ignore_signals, mask); - _end = jiffies + 3 * DRM_HZ; drm_fence_object_flush(fence, mask); + if (driver->has_irq(dev, fence->fence_class, mask)) { + if (!ignore_signals) + ret = wait_event_interruptible_timeout + (fc->fence_queue, + drm_fence_object_signaled(fence, mask), + 3 * DRM_HZ); + else + ret = wait_event_timeout + (fc->fence_queue, + drm_fence_object_signaled(fence, mask), + 3 * DRM_HZ); + + if (unlikely(ret == -ERESTARTSYS)) + return -EAGAIN; + + if (unlikely(ret == 0)) + return -EBUSY; - if (lazy && driver->lazy_capable) { - - ret = drm_fence_lazy_wait(fence, ignore_signals, mask); - if (ret) - return ret; - - } else { - - if (driver->has_irq(dev, fence->fence_class, - DRM_FENCE_TYPE_EXE)) { - ret = drm_fence_lazy_wait(fence, ignore_signals, - DRM_FENCE_TYPE_EXE); - if (ret) - return ret; - } - - if (driver->has_irq(dev, fence->fence_class, - mask & ~DRM_FENCE_TYPE_EXE)) { - ret = drm_fence_lazy_wait(fence, ignore_signals, - mask); - if (ret) - return ret; - } - } - if (drm_fence_object_signaled(fence, mask, 0)) return 0; + } - /* - * Avoid kernel-space busy-waits. - */ - if (!ignore_signals) - return -EAGAIN; - - do { - schedule(); - signaled = drm_fence_object_signaled(fence, mask, 1); - } while (!signaled && !time_after_eq(jiffies, _end)); - - if (!signaled) - return -EBUSY; - - return 0; + return drm_fence_wait_polling(fence, lazy, !ignore_signals, mask, + _end); } EXPORT_SYMBOL(drm_fence_object_wait); + + int drm_fence_object_emit(struct drm_fence_object *fence, uint32_t fence_flags, uint32_t fence_class, uint32_t type) { @@ -452,26 +431,26 @@ int drm_fence_object_emit(struct drm_fence_object *fence, uint32_t fence_flags, struct drm_fence_class_manager *fc = &fm->fence_class[fence->fence_class]; unsigned long flags; uint32_t sequence; - uint32_t native_type; + uint32_t native_types; int ret; drm_fence_unring(dev, &fence->ring); ret = driver->emit(dev, fence_class, fence_flags, &sequence, - &native_type); + &native_types); if (ret) return ret; write_lock_irqsave(&fm->lock, flags); fence->fence_class = fence_class; fence->type = type; - fence->flush_mask = 0x00; - fence->submitted_flush = 0x00; - fence->signaled = 0x00; + fence->waiting_types = 0; + fence->signaled_types = 0; fence->sequence = sequence; - fence->native_type = native_type; + fence->native_types = native_types; if (list_empty(&fc->ring)) - fc->last_exe_flush = sequence - 1; + fc->highest_waiting_sequence = sequence - 1; list_add_tail(&fence->ring, &fc->ring); + fc->latest_queued_sequence = sequence; write_unlock_irqrestore(&fm->lock, flags); return 0; } @@ -500,9 +479,8 @@ static int drm_fence_object_init(struct drm_device *dev, uint32_t fence_class, INIT_LIST_HEAD(&fence->base.list); fence->fence_class = fence_class; fence->type = type; - fence->flush_mask = 0; - fence->submitted_flush = 0; - fence->signaled = 0; + fence->signaled_types = 0; + fence->waiting_types = 0; fence->sequence = 0; fence->dev = dev; write_unlock_irqrestore(&fm->lock, flags); @@ -577,8 +555,8 @@ void drm_fence_manager_init(struct drm_device *dev) for (i = 0; i < fm->num_classes; ++i) { fence_class = &fm->fence_class[i]; + memset(fence_class, 0, sizeof(*fence_class)); INIT_LIST_HEAD(&fence_class->ring); - fence_class->pending_flush = 0; DRM_INIT_WAITQUEUE(&fence_class->fence_queue); } @@ -598,7 +576,7 @@ void drm_fence_fill_arg(struct drm_fence_object *fence, arg->handle = fence->base.hash.key; arg->fence_class = fence->fence_class; arg->type = fence->type; - arg->signaled = fence->signaled; + arg->signaled = fence->signaled_types; arg->error = fence->error; arg->sequence = fence->sequence; read_unlock_irqrestore(&fm->lock, irq_flags); diff --git a/linux-core/drm_irq.c b/linux-core/drm_irq.c index d88269a4..cb279bcd 100644 --- a/linux-core/drm_irq.c +++ b/linux-core/drm_irq.c @@ -74,11 +74,18 @@ int drm_irq_by_busid(struct drm_device *dev, void *data, static void vblank_disable_fn(unsigned long arg) { struct drm_device *dev = (struct drm_device *)arg; + unsigned long irqflags; int i; - for (i = 0; i < dev->num_crtcs; i++) - if (atomic_read(&dev->vblank_refcount[i]) == 0) + for (i = 0; i < dev->num_crtcs; i++) { + spin_lock_irqsave(&dev->vbl_lock, irqflags); + if (atomic_read(&dev->vblank_refcount[i]) == 0 && + dev->vblank_enabled[i]) { dev->driver->disable_vblank(dev, i); + dev->vblank_enabled[i] = 0; + } + spin_unlock_irqrestore(&dev->vbl_lock, irqflags); + } } int drm_vblank_init(struct drm_device *dev, int num_crtcs) @@ -111,6 +118,11 @@ int drm_vblank_init(struct drm_device *dev, int num_crtcs) if (!dev->vblank_refcount) goto err; + dev->vblank_enabled = drm_calloc(num_crtcs, sizeof(int), + DRM_MEM_DRIVER); + if (!dev->vblank_enabled) + goto err; + dev->last_vblank = drm_calloc(num_crtcs, sizeof(u32), DRM_MEM_DRIVER); if (!dev->last_vblank) goto err; @@ -143,6 +155,8 @@ err: DRM_MEM_DRIVER); drm_free(dev->vblank_refcount, sizeof(*dev->vblank_refcount) * num_crtcs, DRM_MEM_DRIVER); + drm_free(dev->vblank_enabled, sizeof(*dev->vblank_enabled) * num_crtcs, + DRM_MEM_DRIVER); drm_free(dev->last_vblank, sizeof(*dev->last_vblank) * num_crtcs, DRM_MEM_DRIVER); drm_free(dev->vblank_premodeset, sizeof(*dev->vblank_premodeset) * @@ -357,14 +371,20 @@ EXPORT_SYMBOL(drm_update_vblank_count); */ int drm_vblank_get(struct drm_device *dev, int crtc) { + unsigned long irqflags; int ret = 0; + spin_lock_irqsave(&dev->vbl_lock, irqflags); /* Going from 0->1 means we have to enable interrupts again */ - if (atomic_add_return(1, &dev->vblank_refcount[crtc]) == 1) { + if (atomic_add_return(1, &dev->vblank_refcount[crtc]) == 1 && + !dev->vblank_enabled[crtc]) { ret = dev->driver->enable_vblank(dev, crtc); if (ret) atomic_dec(&dev->vblank_refcount[crtc]); + else + dev->vblank_enabled[crtc] = 1; } + spin_unlock_irqrestore(&dev->vbl_lock, irqflags); return ret; } @@ -382,8 +402,7 @@ void drm_vblank_put(struct drm_device *dev, int crtc) { /* Last user schedules interrupt disable */ if (atomic_dec_and_test(&dev->vblank_refcount[crtc])) - mod_timer(&dev->vblank_disable_timer, - round_jiffies_relative(DRM_HZ)); + mod_timer(&dev->vblank_disable_timer, jiffies + 5*DRM_HZ); } EXPORT_SYMBOL(drm_vblank_put); diff --git a/linux-core/drm_objects.h b/linux-core/drm_objects.h index 53fad3af..7b585c3e 100644 --- a/linux-core/drm_objects.h +++ b/linux-core/drm_objects.h @@ -147,12 +147,11 @@ struct drm_fence_object { struct list_head ring; int fence_class; - uint32_t native_type; + uint32_t native_types; uint32_t type; - uint32_t signaled; + uint32_t signaled_types; uint32_t sequence; - uint32_t flush_mask; - uint32_t submitted_flush; + uint32_t waiting_types; uint32_t error; }; @@ -161,10 +160,10 @@ struct drm_fence_object { struct drm_fence_class_manager { struct list_head ring; uint32_t pending_flush; + uint32_t waiting_types; wait_queue_head_t fence_queue; - int pending_exe_flush; - uint32_t last_exe_flush; - uint32_t exe_flush_sequence; + uint32_t highest_waiting_sequence; + uint32_t latest_queued_sequence; }; struct drm_fence_manager { @@ -176,19 +175,49 @@ struct drm_fence_manager { }; struct drm_fence_driver { + unsigned long *waiting_jiffies; uint32_t num_classes; uint32_t wrap_diff; uint32_t flush_diff; uint32_t sequence_mask; - int lazy_capable; + + /* + * Driver implemented functions: + * has_irq() : 1 if the hardware can update the indicated type_flags using an + * irq handler. 0 if polling is required. + * + * emit() : Emit a sequence number to the command stream. + * Return the sequence number. + * + * flush() : Make sure the flags indicated in fc->pending_flush will eventually + * signal for fc->highest_received_sequence and all preceding sequences. + * Acknowledge by clearing the flags fc->pending_flush. + * + * poll() : Call drm_fence_handler with any new information. + * + * needed_flush() : Given the current state of the fence->type flags and previusly + * executed or queued flushes, return the type_flags that need flushing. + * + * wait(): Wait for the "mask" flags to signal on a given fence, performing + * whatever's necessary to make this happen. + */ + int (*has_irq) (struct drm_device *dev, uint32_t fence_class, uint32_t flags); int (*emit) (struct drm_device *dev, uint32_t fence_class, uint32_t flags, uint32_t *breadcrumb, uint32_t *native_type); - void (*poke_flush) (struct drm_device *dev, uint32_t fence_class); + void (*flush) (struct drm_device *dev, uint32_t fence_class); + void (*poll) (struct drm_device *dev, uint32_t fence_class, + uint32_t types); + uint32_t (*needed_flush) (struct drm_fence_object *fence); + int (*wait) (struct drm_fence_object *fence, int lazy, + int interruptible, uint32_t mask); }; +extern int drm_fence_wait_polling(struct drm_fence_object *fence, int lazy, + int interruptible, uint32_t mask, + unsigned long end_jiffies); extern void drm_fence_handler(struct drm_device *dev, uint32_t fence_class, uint32_t sequence, uint32_t type, uint32_t error); @@ -199,7 +228,7 @@ extern void drm_fence_flush_old(struct drm_device *dev, uint32_t fence_class, extern int drm_fence_object_flush(struct drm_fence_object *fence, uint32_t type); extern int drm_fence_object_signaled(struct drm_fence_object *fence, - uint32_t type, int flush); + uint32_t type); extern void drm_fence_usage_deref_locked(struct drm_fence_object **fence); extern void drm_fence_usage_deref_unlocked(struct drm_fence_object **fence); extern struct drm_fence_object *drm_fence_reference_locked(struct drm_fence_object *src); @@ -575,6 +604,33 @@ struct drm_bo_driver { * ttm_cache_flush */ void (*ttm_cache_flush)(struct drm_ttm *ttm); + + /* + * command_stream_barrier + * + * @dev: The drm device. + * + * @bo: The buffer object to validate. + * + * @new_fence_class: The new fence class for the buffer object. + * + * @new_fence_type: The new fence type for the buffer object. + * + * @no_wait: whether this should give up and return -EBUSY + * if this operation would require sleeping + * + * Insert a command stream barrier that makes sure that the + * buffer is idle once the commands associated with the + * current validation are starting to execute. If an error + * condition is returned, or the function pointer is NULL, + * the drm core will force buffer idle + * during validation. + */ + + int (*command_stream_barrier) (struct drm_buffer_object *bo, + uint32_t new_fence_class, + uint32_t new_fence_type, + int no_wait); }; /* diff --git a/linux-core/i915_drv.c b/linux-core/i915_drv.c index 1f841642..64c805f5 100644 --- a/linux-core/i915_drv.c +++ b/linux-core/i915_drv.c @@ -40,17 +40,9 @@ static struct pci_device_id pciidlist[] = { }; #ifdef I915_HAVE_FENCE -static struct drm_fence_driver i915_fence_driver = { - .num_classes = 1, - .wrap_diff = (1U << (BREADCRUMB_BITS - 1)), - .flush_diff = (1U << (BREADCRUMB_BITS - 2)), - .sequence_mask = BREADCRUMB_MASK, - .lazy_capable = 1, - .emit = i915_fence_emit_sequence, - .poke_flush = i915_poke_flush, - .has_irq = i915_fence_has_irq, -}; +extern struct drm_fence_driver i915_fence_driver; #endif + #ifdef I915_HAVE_BUFFER static uint32_t i915_mem_prios[] = {DRM_BO_MEM_VRAM, DRM_BO_MEM_PRIV0, DRM_BO_MEM_TT, DRM_BO_MEM_LOCAL}; @@ -68,6 +60,7 @@ static struct drm_bo_driver i915_bo_driver = { .evict_flags = i915_evict_flags, .move = i915_move, .ttm_cache_flush = i915_flush_ttm, + .command_stream_barrier = NULL, }; #endif @@ -193,6 +186,7 @@ static void i915_save_vga(struct drm_device *dev) dev_priv->saveAR[i] = i915_read_ar(st01, i, 0); inb(st01); outb(dev_priv->saveAR_INDEX, VGA_AR_INDEX); + inb(st01); /* Graphics controller registers */ for (i = 0; i < 9; i++) @@ -258,6 +252,7 @@ static void i915_restore_vga(struct drm_device *dev) i915_write_ar(st01, i, dev_priv->saveAR[i], 0); inb(st01); /* switch back to index mode */ outb(dev_priv->saveAR_INDEX | 0x20, VGA_AR_INDEX); + inb(st01); /* VGA color palette registers */ outb(dev_priv->saveDACMASK, VGA_DACMASK); @@ -309,6 +304,7 @@ static int i915_suspend(struct drm_device *dev) dev_priv->saveDSPATILEOFF = I915_READ(DSPATILEOFF); } i915_save_palette(dev, PIPE_A); + dev_priv->savePIPEASTAT = I915_READ(I915REG_PIPEASTAT); /* Pipe & plane B info */ dev_priv->savePIPEBCONF = I915_READ(PIPEBCONF); @@ -336,6 +332,7 @@ static int i915_suspend(struct drm_device *dev) dev_priv->saveDSPBTILEOFF = I915_READ(DSPBTILEOFF); } i915_save_palette(dev, PIPE_B); + dev_priv->savePIPEBSTAT = I915_READ(I915REG_PIPEBSTAT); /* CRT state */ dev_priv->saveADPA = I915_READ(ADPA); @@ -362,12 +359,26 @@ static int i915_suspend(struct drm_device *dev) dev_priv->saveFBC_CONTROL2 = I915_READ(FBC_CONTROL2); dev_priv->saveFBC_CONTROL = I915_READ(FBC_CONTROL); + /* Interrupt state */ + dev_priv->saveIIR = I915_READ(I915REG_INT_IDENTITY_R); + dev_priv->saveIER = I915_READ(I915REG_INT_ENABLE_R); + dev_priv->saveIMR = I915_READ(I915REG_INT_MASK_R); + /* VGA state */ dev_priv->saveVCLK_DIVISOR_VGA0 = I915_READ(VCLK_DIVISOR_VGA0); dev_priv->saveVCLK_DIVISOR_VGA1 = I915_READ(VCLK_DIVISOR_VGA1); dev_priv->saveVCLK_POST_DIV = I915_READ(VCLK_POST_DIV); dev_priv->saveVGACNTRL = I915_READ(VGACNTRL); + /* Clock gating state */ + dev_priv->saveDSPCLK_GATE_D = I915_READ(DSPCLK_GATE_D); + + /* Cache mode state */ + dev_priv->saveCACHE_MODE_0 = I915_READ(CACHE_MODE_0); + + /* Memory Arbitration state */ + dev_priv->saveMI_ARB_STATE = I915_READ(MI_ARB_STATE); + /* Scratch space */ for (i = 0; i < 16; i++) { dev_priv->saveSWF0[i] = I915_READ(SWF0 + (i << 2)); @@ -433,9 +444,7 @@ static int i915_resume(struct drm_device *dev) I915_WRITE(DSPATILEOFF, dev_priv->saveDSPATILEOFF); } - if ((dev_priv->saveDPLL_A & DPLL_VCO_ENABLE) && - (dev_priv->saveDPLL_A & DPLL_VGA_MODE_DIS)) - I915_WRITE(PIPEACONF, dev_priv->savePIPEACONF); + I915_WRITE(PIPEACONF, dev_priv->savePIPEACONF); i915_restore_palette(dev, PIPE_A); /* Enable the plane */ @@ -477,10 +486,9 @@ static int i915_resume(struct drm_device *dev) I915_WRITE(DSPBTILEOFF, dev_priv->saveDSPBTILEOFF); } - if ((dev_priv->saveDPLL_B & DPLL_VCO_ENABLE) && - (dev_priv->saveDPLL_B & DPLL_VGA_MODE_DIS)) - I915_WRITE(PIPEBCONF, dev_priv->savePIPEBCONF); - i915_restore_palette(dev, PIPE_A); + I915_WRITE(PIPEBCONF, dev_priv->savePIPEBCONF); + + i915_restore_palette(dev, PIPE_B); /* Enable the plane */ I915_WRITE(DSPBCNTR, dev_priv->saveDSPBCNTR); I915_WRITE(DSPBBASE, I915_READ(DSPBBASE)); @@ -518,6 +526,15 @@ static int i915_resume(struct drm_device *dev) I915_WRITE(VCLK_POST_DIV, dev_priv->saveVCLK_POST_DIV); udelay(150); + /* Clock gating state */ + I915_WRITE (DSPCLK_GATE_D, dev_priv->saveDSPCLK_GATE_D); + + /* Cache mode state */ + I915_WRITE (CACHE_MODE_0, dev_priv->saveCACHE_MODE_0 | 0xffff0000); + + /* Memory arbitration state */ + I915_WRITE (MI_ARB_STATE, dev_priv->saveMI_ARB_STATE | 0xffff0000); + for (i = 0; i < 16; i++) { I915_WRITE(SWF0 + (i << 2), dev_priv->saveSWF0[i]); I915_WRITE(SWF10 + (i << 2), dev_priv->saveSWF1[i+7]); diff --git a/linux-core/i915_fence.c b/linux-core/i915_fence.c index 21d032b0..de64a4f2 100644 --- a/linux-core/i915_fence.c +++ b/linux-core/i915_fence.c @@ -35,60 +35,14 @@ #include "i915_drv.h" /* - * Implements an intel sync flush operation. + * Initiate a sync flush if it's not already pending. */ -static void i915_perform_flush(struct drm_device *dev) +static inline void i915_initiate_rwflush(struct drm_i915_private *dev_priv, + struct drm_fence_class_manager *fc) { - struct drm_i915_private *dev_priv = (struct drm_i915_private *) dev->dev_private; - struct drm_fence_manager *fm = &dev->fm; - struct drm_fence_class_manager *fc = &fm->fence_class[0]; - struct drm_fence_driver *driver = dev->driver->fence_driver; - uint32_t flush_flags = 0; - uint32_t flush_sequence = 0; - uint32_t i_status; - uint32_t diff; - uint32_t sequence; - int rwflush; - - if (!dev_priv) - return; - - if (fc->pending_exe_flush) { - sequence = READ_BREADCRUMB(dev_priv); - - /* - * First update fences with the current breadcrumb. - */ - - diff = (sequence - fc->last_exe_flush) & BREADCRUMB_MASK; - if (diff < driver->wrap_diff && diff != 0) { - drm_fence_handler(dev, 0, sequence, - DRM_FENCE_TYPE_EXE, 0); - } - - if (dev_priv->fence_irq_on && !fc->pending_exe_flush) { - i915_user_irq_off(dev_priv); - dev_priv->fence_irq_on = 0; - } else if (!dev_priv->fence_irq_on && fc->pending_exe_flush) { - i915_user_irq_on(dev_priv); - dev_priv->fence_irq_on = 1; - } - } - - if (dev_priv->flush_pending) { - i_status = READ_HWSP(dev_priv, 0); - if ((i_status & (1 << 12)) != - (dev_priv->saved_flush_status & (1 << 12))) { - flush_flags = dev_priv->flush_flags; - flush_sequence = dev_priv->flush_sequence; - dev_priv->flush_pending = 0; - drm_fence_handler(dev, 0, flush_sequence, flush_flags, 0); - } - } - - rwflush = fc->pending_flush & DRM_I915_FENCE_TYPE_RW; - if (rwflush && !dev_priv->flush_pending) { + if ((fc->pending_flush & DRM_I915_FENCE_TYPE_RW) && + !dev_priv->flush_pending) { dev_priv->flush_sequence = (uint32_t) READ_BREADCRUMB(dev_priv); dev_priv->flush_flags = fc->pending_flush; dev_priv->saved_flush_status = READ_HWSP(dev_priv, 0); @@ -96,36 +50,105 @@ static void i915_perform_flush(struct drm_device *dev) dev_priv->flush_pending = 1; fc->pending_flush &= ~DRM_I915_FENCE_TYPE_RW; } +} + +static inline void i915_report_rwflush(struct drm_device *dev, + struct drm_i915_private *dev_priv) +{ + if (unlikely(dev_priv->flush_pending)) { + + uint32_t flush_flags; + uint32_t i_status; + uint32_t flush_sequence; - if (dev_priv->flush_pending) { i_status = READ_HWSP(dev_priv, 0); if ((i_status & (1 << 12)) != (dev_priv->saved_flush_status & (1 << 12))) { flush_flags = dev_priv->flush_flags; flush_sequence = dev_priv->flush_sequence; dev_priv->flush_pending = 0; - drm_fence_handler(dev, 0, flush_sequence, flush_flags, 0); + drm_fence_handler(dev, 0, flush_sequence, + flush_flags, 0); } } +} + +static void i915_fence_flush(struct drm_device *dev, + uint32_t fence_class) +{ + struct drm_i915_private *dev_priv = + (struct drm_i915_private *) dev->dev_private; + struct drm_fence_manager *fm = &dev->fm; + struct drm_fence_class_manager *fc = &fm->fence_class[0]; + unsigned long irq_flags; + if (unlikely(!dev_priv)) + return; + + write_lock_irqsave(&fm->lock, irq_flags); + i915_initiate_rwflush(dev_priv, fc); + write_unlock_irqrestore(&fm->lock, irq_flags); } -void i915_poke_flush(struct drm_device *dev, uint32_t class) + +static void i915_fence_poll(struct drm_device *dev, uint32_t fence_class, + uint32_t waiting_types) { + drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; struct drm_fence_manager *fm = &dev->fm; - unsigned long flags; + struct drm_fence_class_manager *fc = &fm->fence_class[0]; + uint32_t sequence; + + if (unlikely(!dev_priv)) + return; + + /* + * First, report any executed sync flush: + */ + + i915_report_rwflush(dev, dev_priv); + + /* + * Report A new breadcrumb, and adjust IRQs. + */ + + if (waiting_types & DRM_FENCE_TYPE_EXE) { + + sequence = READ_BREADCRUMB(dev_priv); + drm_fence_handler(dev, 0, sequence, + DRM_FENCE_TYPE_EXE, 0); + + if (dev_priv->fence_irq_on && + !(fc->waiting_types & DRM_FENCE_TYPE_EXE)) { + i915_user_irq_off(dev_priv); + dev_priv->fence_irq_on = 0; + } else if (!dev_priv->fence_irq_on && + (fc->waiting_types & DRM_FENCE_TYPE_EXE)) { + i915_user_irq_on(dev_priv); + dev_priv->fence_irq_on = 1; + } + } + + /* + * There may be new RW flushes pending. Start them. + */ + + i915_initiate_rwflush(dev_priv, fc); + + /* + * And possibly, but unlikely, they finish immediately. + */ + + i915_report_rwflush(dev, dev_priv); - write_lock_irqsave(&fm->lock, flags); - i915_perform_flush(dev); - write_unlock_irqrestore(&fm->lock, flags); } -int i915_fence_emit_sequence(struct drm_device *dev, uint32_t class, +static int i915_fence_emit_sequence(struct drm_device *dev, uint32_t class, uint32_t flags, uint32_t *sequence, uint32_t *native_type) { - struct drm_i915_private *dev_priv = (struct drm_i915_private *) dev->dev_private; - if (!dev_priv) + drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; + if (unlikely(!dev_priv)) return -EINVAL; i915_emit_irq(dev); @@ -140,20 +163,109 @@ int i915_fence_emit_sequence(struct drm_device *dev, uint32_t class, void i915_fence_handler(struct drm_device *dev) { struct drm_fence_manager *fm = &dev->fm; + struct drm_fence_class_manager *fc = &fm->fence_class[0]; write_lock(&fm->lock); - i915_perform_flush(dev); + i915_fence_poll(dev, 0, fc->waiting_types); write_unlock(&fm->lock); } -int i915_fence_has_irq(struct drm_device *dev, uint32_t class, uint32_t flags) +/* + * We need a separate wait function since we need to poll for + * sync flushes. + */ + +static int i915_fence_wait(struct drm_fence_object *fence, + int lazy, int interruptible, uint32_t mask) { + struct drm_device *dev = fence->dev; + drm_i915_private_t *dev_priv = (struct drm_i915_private *) dev->dev_private; + struct drm_fence_manager *fm = &dev->fm; + struct drm_fence_class_manager *fc = &fm->fence_class[0]; + int ret; + unsigned long _end = jiffies + 3 * DRM_HZ; + + drm_fence_object_flush(fence, mask); + if (likely(interruptible)) + ret = wait_event_interruptible_timeout + (fc->fence_queue, drm_fence_object_signaled(fence, DRM_FENCE_TYPE_EXE), + 3 * DRM_HZ); + else + ret = wait_event_timeout + (fc->fence_queue, drm_fence_object_signaled(fence, DRM_FENCE_TYPE_EXE), + 3 * DRM_HZ); + + if (unlikely(ret == -ERESTARTSYS)) + return -EAGAIN; + + if (unlikely(ret == 0)) + return -EBUSY; + + if (likely(mask == DRM_FENCE_TYPE_EXE || + drm_fence_object_signaled(fence, mask))) + return 0; + /* - * We have an irq that tells us when we have a new breadcrumb. + * Remove this code snippet when fixed. HWSTAM doesn't let + * flush info through... */ - if (class == 0 && flags == DRM_FENCE_TYPE_EXE) - return 1; + if (unlikely(dev_priv && !dev_priv->irq_enabled)) { + unsigned long irq_flags; - return 0; + DRM_ERROR("X server disabled IRQs before releasing frame buffer.\n"); + msleep(100); + dev_priv->flush_pending = 0; + write_lock_irqsave(&fm->lock, irq_flags); + drm_fence_handler(dev, fence->fence_class, + fence->sequence, fence->type, 0); + write_unlock_irqrestore(&fm->lock, irq_flags); + } + + /* + * Poll for sync flush completion. + */ + + return drm_fence_wait_polling(fence, lazy, interruptible, mask, _end); } + +static uint32_t i915_fence_needed_flush(struct drm_fence_object *fence) +{ + uint32_t flush_flags = fence->waiting_types & + ~(DRM_FENCE_TYPE_EXE | fence->signaled_types); + + if (likely(flush_flags == 0 || + ((flush_flags & ~fence->native_types) == 0) || + (fence->signaled_types != DRM_FENCE_TYPE_EXE))) + return 0; + else { + struct drm_device *dev = fence->dev; + struct drm_i915_private *dev_priv = (struct drm_i915_private *) dev->dev_private; + struct drm_fence_driver *driver = dev->driver->fence_driver; + + if (unlikely(!dev_priv)) + return 0; + + if (dev_priv->flush_pending) { + uint32_t diff = (dev_priv->flush_sequence - fence->sequence) & + driver->sequence_mask; + + if (diff < driver->wrap_diff) + return 0; + } + } + return flush_flags; +} + +struct drm_fence_driver i915_fence_driver = { + .num_classes = 1, + .wrap_diff = (1U << (BREADCRUMB_BITS - 1)), + .flush_diff = (1U << (BREADCRUMB_BITS - 2)), + .sequence_mask = BREADCRUMB_MASK, + .has_irq = NULL, + .emit = i915_fence_emit_sequence, + .flush = i915_fence_flush, + .poll = i915_fence_poll, + .needed_flush = i915_fence_needed_flush, + .wait = i915_fence_wait, +}; diff --git a/linux-core/nouveau_buffer.c b/linux-core/nouveau_buffer.c index a652bb1d..11549317 100644 --- a/linux-core/nouveau_buffer.c +++ b/linux-core/nouveau_buffer.c @@ -294,5 +294,6 @@ struct drm_bo_driver nouveau_bo_driver = { .init_mem_type = nouveau_bo_init_mem_type, .evict_flags = nouveau_bo_evict_flags, .move = nouveau_bo_move, - .ttm_cache_flush= nouveau_bo_flush_ttm + .ttm_cache_flush= nouveau_bo_flush_ttm, + .command_stream_barrier = NULL }; diff --git a/linux-core/nouveau_fence.c b/linux-core/nouveau_fence.c index 4e624a7a..59dcf7d0 100644 --- a/linux-core/nouveau_fence.c +++ b/linux-core/nouveau_fence.c @@ -75,7 +75,7 @@ nouveau_fence_emit(struct drm_device *dev, uint32_t class, uint32_t flags, } static void -nouveau_fence_perform_flush(struct drm_device *dev, uint32_t class) +nouveau_fence_poll(struct drm_device *dev, uint32_t class, uint32_t waiting_types) { struct drm_nouveau_private *dev_priv = dev->dev_private; struct drm_fence_class_manager *fc = &dev->fm.fence_class[class]; @@ -83,42 +83,26 @@ nouveau_fence_perform_flush(struct drm_device *dev, uint32_t class) uint32_t pending_types = 0; DRM_DEBUG("class=%d\n", class); - - pending_types = fc->pending_flush | - ((fc->pending_exe_flush) ? DRM_FENCE_TYPE_EXE : 0); - DRM_DEBUG("pending: 0x%08x 0x%08x\n", pending_types, - fc->pending_flush); + DRM_DEBUG("pending: 0x%08x 0x%08x\n", waiting_types, fc->waiting_types); if (pending_types) { uint32_t sequence = NV_READ(chan->ref_cnt); DRM_DEBUG("got 0x%08x\n", sequence); - drm_fence_handler(dev, class, sequence, pending_types, 0); + drm_fence_handler(dev, class, sequence, waiting_types, 0); } } -static void -nouveau_fence_poke_flush(struct drm_device *dev, uint32_t class) -{ - struct drm_fence_manager *fm = &dev->fm; - unsigned long flags; - - DRM_DEBUG("class=%d\n", class); - - write_lock_irqsave(&fm->lock, flags); - nouveau_fence_perform_flush(dev, class); - write_unlock_irqrestore(&fm->lock, flags); -} - void nouveau_fence_handler(struct drm_device *dev, int channel) { struct drm_fence_manager *fm = &dev->fm; + struct drm_fence_class_manager *fc = &fm->fence_class[channel]; DRM_DEBUG("class=%d\n", channel); write_lock(&fm->lock); - nouveau_fence_perform_flush(dev, channel); + nouveau_fence_poll(dev, channel, fc->waiting_types); write_unlock(&fm->lock); } @@ -127,8 +111,10 @@ struct drm_fence_driver nouveau_fence_driver = { .wrap_diff = (1 << 30), .flush_diff = (1 << 29), .sequence_mask = 0xffffffffU, - .lazy_capable = 1, .has_irq = nouveau_fence_has_irq, .emit = nouveau_fence_emit, - .poke_flush = nouveau_fence_poke_flush + .flush = NULL, + .poll = nouveau_fence_poll, + .needed_flush = NULL, + .wait = NULL }; diff --git a/linux-core/via_fence.c b/linux-core/via_fence.c index b853df5c..20df4779 100644 --- a/linux-core/via_fence.c +++ b/linux-core/via_fence.c @@ -38,27 +38,21 @@ * DRM_VIA_FENCE_TYPE_ACCEL guarantees that all 2D & 3D rendering is complete. */ - -static uint32_t via_perform_flush(struct drm_device *dev, uint32_t class) +static void via_fence_poll(struct drm_device *dev, uint32_t class, + uint32_t waiting_types) { drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private; - struct drm_fence_class_manager *fc = &dev->fm.fence_class[class]; - uint32_t pending_flush_types = 0; uint32_t signaled_flush_types = 0; uint32_t status; if (class != 0) - return 0; + return; - if (!dev_priv) - return 0; + if (unlikely(!dev_priv)) + return; spin_lock(&dev_priv->fence_lock); - - pending_flush_types = fc->pending_flush | - ((fc->pending_exe_flush) ? DRM_FENCE_TYPE_EXE : 0); - - if (pending_flush_types) { + if (waiting_types) { /* * Take the idlelock. This guarantees that the next time a client tries @@ -77,7 +71,7 @@ static uint32_t via_perform_flush(struct drm_device *dev, uint32_t class) * Check if AGP command reader is idle. */ - if (pending_flush_types & DRM_FENCE_TYPE_EXE) + if (waiting_types & DRM_FENCE_TYPE_EXE) if (VIA_READ(0x41C) & 0x80000000) signaled_flush_types |= DRM_FENCE_TYPE_EXE; @@ -85,7 +79,7 @@ static uint32_t via_perform_flush(struct drm_device *dev, uint32_t class) * Check VRAM command queue empty and 2D + 3D engines idle. */ - if (pending_flush_types & DRM_VIA_FENCE_TYPE_ACCEL) { + if (waiting_types & DRM_VIA_FENCE_TYPE_ACCEL) { status = VIA_READ(VIA_REG_STATUS); if ((status & VIA_VR_QUEUE_BUSY) && !(status & (VIA_CMD_RGTR_BUSY | VIA_2D_ENG_BUSY | VIA_3D_ENG_BUSY))) @@ -93,9 +87,9 @@ static uint32_t via_perform_flush(struct drm_device *dev, uint32_t class) } if (signaled_flush_types) { - pending_flush_types &= ~signaled_flush_types; - if (!pending_flush_types && dev_priv->have_idlelock) { - drm_idlelock_release(&dev->primary->master->lock); + waiting_types &= ~signaled_flush_types; + if (!waiting_types && dev_priv->have_idlelock) { + drm_idlelock_release(&dev->lock); dev_priv->have_idlelock = 0; } drm_fence_handler(dev, 0, dev_priv->emit_0_sequence, @@ -105,8 +99,7 @@ static uint32_t via_perform_flush(struct drm_device *dev, uint32_t class) spin_unlock(&dev_priv->fence_lock); - return fc->pending_flush | - ((fc->pending_exe_flush) ? DRM_FENCE_TYPE_EXE : 0); + return; } @@ -114,8 +107,8 @@ static uint32_t via_perform_flush(struct drm_device *dev, uint32_t class) * Emit a fence sequence. */ -int via_fence_emit_sequence(struct drm_device * dev, uint32_t class, uint32_t flags, - uint32_t * sequence, uint32_t * native_type) +static int via_fence_emit_sequence(struct drm_device * dev, uint32_t class, uint32_t flags, + uint32_t * sequence, uint32_t * native_type) { drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private; int ret = 0; @@ -150,36 +143,6 @@ int via_fence_emit_sequence(struct drm_device * dev, uint32_t class, uint32_t fl } /** - * Manual poll (from the fence manager). - */ - -void via_poke_flush(struct drm_device * dev, uint32_t class) -{ - drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private; - struct drm_fence_manager *fm = &dev->fm; - unsigned long flags; - uint32_t pending_flush; - - if (!dev_priv) - return ; - - write_lock_irqsave(&fm->lock, flags); - pending_flush = via_perform_flush(dev, class); - if (pending_flush) - pending_flush = via_perform_flush(dev, class); - write_unlock_irqrestore(&fm->lock, flags); - - /* - * Kick the timer if there are more flushes pending. - */ - - if (pending_flush && !timer_pending(&dev_priv->fence_timer)) { - dev_priv->fence_timer.expires = jiffies + 1; - add_timer(&dev_priv->fence_timer); - } -} - -/** * No irq fence expirations implemented yet. * Although both the HQV engines and PCI dmablit engines signal * idle with an IRQ, we haven't implemented this yet. @@ -187,45 +150,20 @@ void via_poke_flush(struct drm_device * dev, uint32_t class) * unless the caller wanting to wait for a fence object has indicated a lazy wait. */ -int via_fence_has_irq(struct drm_device * dev, uint32_t class, - uint32_t flags) +static int via_fence_has_irq(struct drm_device * dev, uint32_t class, + uint32_t flags) { return 0; } -/** - * Regularly call the flush function. This enables lazy waits, so we can - * set lazy_capable. Lazy waits don't really care when the fence expires, - * so a timer tick delay should be fine. - */ - -void via_fence_timer(unsigned long data) -{ - struct drm_device *dev = (struct drm_device *) data; - drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private; - struct drm_fence_manager *fm = &dev->fm; - uint32_t pending_flush; - struct drm_fence_class_manager *fc = &dev->fm.fence_class[0]; - - if (!dev_priv) - return; - if (!fm->initialized) - goto out_unlock; - - via_poke_flush(dev, 0); - pending_flush = fc->pending_flush | - ((fc->pending_exe_flush) ? DRM_FENCE_TYPE_EXE : 0); - - /* - * disable timer if there are no more flushes pending. - */ - - if (!pending_flush && timer_pending(&dev_priv->fence_timer)) { - BUG_ON(dev_priv->have_idlelock); - del_timer(&dev_priv->fence_timer); - } - return; -out_unlock: - return; - -} +struct drm_fence_driver via_fence_driver = { + .num_classes = 1, + .wrap_diff = (1 << 30), + .flush_diff = (1 << 20), + .sequence_mask = 0xffffffffU, + .has_irq = via_fence_has_irq, + .emit = via_fence_emit_sequence, + .poll = via_fence_poll, + .needed_flush = NULL, + .wait = NULL +}; diff --git a/linux-core/xgi_drv.c b/linux-core/xgi_drv.c index 4f0b4ed0..f0225f89 100644 --- a/linux-core/xgi_drv.c +++ b/linux-core/xgi_drv.c @@ -37,16 +37,7 @@ static struct pci_device_id pciidlist[] = { xgi_PCI_IDS }; -static struct drm_fence_driver xgi_fence_driver = { - .num_classes = 1, - .wrap_diff = BEGIN_BEGIN_IDENTIFICATION_MASK, - .flush_diff = BEGIN_BEGIN_IDENTIFICATION_MASK - 1, - .sequence_mask = BEGIN_BEGIN_IDENTIFICATION_MASK, - .lazy_capable = 1, - .emit = xgi_fence_emit_sequence, - .poke_flush = xgi_poke_flush, - .has_irq = xgi_fence_has_irq -}; +extern struct drm_fence_driver xgi_fence_driver; int xgi_bootstrap(struct drm_device *, void *, struct drm_file *); diff --git a/linux-core/xgi_fence.c b/linux-core/xgi_fence.c index 9a75581a..63ed29ee 100644 --- a/linux-core/xgi_fence.c +++ b/linux-core/xgi_fence.c @@ -30,44 +30,37 @@ #include "xgi_misc.h" #include "xgi_cmdlist.h" -static uint32_t xgi_do_flush(struct drm_device * dev, uint32_t class) +static void xgi_fence_poll(struct drm_device * dev, uint32_t class, + uint32_t waiting_types) { struct xgi_info * info = dev->dev_private; - struct drm_fence_class_manager * fc = &dev->fm.fence_class[class]; - uint32_t pending_flush_types = 0; - uint32_t signaled_flush_types = 0; + uint32_t signaled_types = 0; if ((info == NULL) || (class != 0)) - return 0; + return; DRM_SPINLOCK(&info->fence_lock); - pending_flush_types = fc->pending_flush | - ((fc->pending_exe_flush) ? DRM_FENCE_TYPE_EXE : 0); - - if (pending_flush_types) { - if (pending_flush_types & DRM_FENCE_TYPE_EXE) { + if (waiting_types) { + if (waiting_types & DRM_FENCE_TYPE_EXE) { const u32 begin_id = le32_to_cpu(DRM_READ32(info->mmio_map, 0x2820)) & BEGIN_BEGIN_IDENTIFICATION_MASK; if (begin_id != info->complete_sequence) { info->complete_sequence = begin_id; - signaled_flush_types |= DRM_FENCE_TYPE_EXE; + signaled_types |= DRM_FENCE_TYPE_EXE; } } - if (signaled_flush_types) { + if (signaled_types) { drm_fence_handler(dev, 0, info->complete_sequence, - signaled_flush_types, 0); + signaled_types, 0); } } DRM_SPINUNLOCK(&info->fence_lock); - - return fc->pending_flush | - ((fc->pending_exe_flush) ? DRM_FENCE_TYPE_EXE : 0); } @@ -98,25 +91,13 @@ int xgi_fence_emit_sequence(struct drm_device * dev, uint32_t class, } -void xgi_poke_flush(struct drm_device * dev, uint32_t class) -{ - struct drm_fence_manager * fm = &dev->fm; - unsigned long flags; - - - write_lock_irqsave(&fm->lock, flags); - xgi_do_flush(dev, class); - write_unlock_irqrestore(&fm->lock, flags); -} - - void xgi_fence_handler(struct drm_device * dev) { struct drm_fence_manager * fm = &dev->fm; - + struct drm_fence_class_manager *fc = &fm->fence_class[0]; write_lock(&fm->lock); - xgi_do_flush(dev, 0); + xgi_fence_poll(dev, 0, fc->waiting_types); write_unlock(&fm->lock); } @@ -125,3 +106,17 @@ int xgi_fence_has_irq(struct drm_device *dev, uint32_t class, uint32_t flags) { return ((class == 0) && (flags == DRM_FENCE_TYPE_EXE)) ? 1 : 0; } + +struct drm_fence_driver xgi_fence_driver = { + .num_classes = 1, + .wrap_diff = BEGIN_BEGIN_IDENTIFICATION_MASK, + .flush_diff = BEGIN_BEGIN_IDENTIFICATION_MASK - 1, + .sequence_mask = BEGIN_BEGIN_IDENTIFICATION_MASK, + .has_irq = xgi_fence_has_irq, + .emit = xgi_fence_emit_sequence, + .flush = NULL, + .poll = xgi_fence_poll, + .needed_flush = NULL, + .wait = NULL +}; + diff --git a/shared-core/drm_pciids.txt b/shared-core/drm_pciids.txt index 7ef34dfd..c895d7f7 100644 --- a/shared-core/drm_pciids.txt +++ b/shared-core/drm_pciids.txt @@ -83,6 +83,7 @@ 0x1002 0x5460 CHIP_RV380|RADEON_IS_MOBILITY "ATI Radeon Mobility X300 M22" 0x1002 0x5462 CHIP_RV380|RADEON_IS_MOBILITY "ATI Radeon Mobility X600 SE M24C" 0x1002 0x5464 CHIP_RV380|RADEON_IS_MOBILITY "ATI FireGL M22 GL 5464" +0x1002 0x5657 CHIP_RV380|RADEON_NEW_MEMMAP "ATI Radeon RV370 X550XTX" 0x1002 0x5548 CHIP_R420|RADEON_NEW_MEMMAP "ATI Radeon R423 X800" 0x1002 0x5549 CHIP_R420|RADEON_NEW_MEMMAP "ATI Radeon R423 X800 Pro" 0x1002 0x554A CHIP_R420|RADEON_NEW_MEMMAP "ATI Radeon R423 X800 XT PE" @@ -236,6 +237,7 @@ 0x1002 0x7297 CHIP_RV560|RADEON_NEW_MEMMAP "ATI RV560" 0x1002 0x7834 CHIP_RS300|RADEON_IS_IGP|RADEON_NEW_MEMMAP "ATI Radeon RS350 9000/9100 IGP" 0x1002 0x7835 CHIP_RS300|RADEON_IS_IGP|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP "ATI Radeon RS350 Mobility IGP" +0x1002 0x791e CHIP_RS690|RADEON_IS_IGP|RADEON_NEW_MEMMAP|RADEON_IS_IGPGART "ATI Radeon RS690 X1250 IGP" [r128] 0x1002 0x4c45 0 "ATI Rage 128 Mobility LE (PCI)" diff --git a/shared-core/i915_dma.c b/shared-core/i915_dma.c index 0a3d82a0..3d489231 100644 --- a/shared-core/i915_dma.c +++ b/shared-core/i915_dma.c @@ -85,7 +85,70 @@ int i915_dma_cleanup(struct drm_device * dev) return 0; } -static int i915_initialize(struct drm_device * dev, drm_i915_init_t * init) + +#define DRI2_SAREA_BLOCK_TYPE(b) ((b) >> 16) +#define DRI2_SAREA_BLOCK_SIZE(b) ((b) & 0xffff) +#define DRI2_SAREA_BLOCK_NEXT(p) \ + ((void *) ((unsigned char *) (p) + \ + DRI2_SAREA_BLOCK_SIZE(*(unsigned int *) p))) + +#define DRI2_SAREA_BLOCK_END 0x0000 +#define DRI2_SAREA_BLOCK_LOCK 0x0001 +#define DRI2_SAREA_BLOCK_EVENT_BUFFER 0x0002 + +static int +setup_dri2_sarea(struct drm_device * dev, + struct drm_file *file_priv, + drm_i915_init_t * init) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + int ret; + unsigned int *p, *end, *next; + + mutex_lock(&dev->struct_mutex); + dev_priv->sarea_bo = + drm_lookup_buffer_object(file_priv, + init->sarea_handle, 1); + mutex_unlock(&dev->struct_mutex); + + if (!dev_priv->sarea_bo) { + DRM_ERROR("did not find sarea bo\n"); + return -EINVAL; + } + + ret = drm_bo_kmap(dev_priv->sarea_bo, 0, + dev_priv->sarea_bo->num_pages, + &dev_priv->sarea_kmap); + if (ret) { + DRM_ERROR("could not map sarea bo\n"); + return ret; + } + + p = dev_priv->sarea_kmap.virtual; + end = (void *) p + (dev_priv->sarea_bo->num_pages << PAGE_SHIFT); + while (p < end && DRI2_SAREA_BLOCK_TYPE(*p) != DRI2_SAREA_BLOCK_END) { + switch (DRI2_SAREA_BLOCK_TYPE(*p)) { + case DRI2_SAREA_BLOCK_LOCK: + dev->lock.hw_lock = (void *) (p + 1); + dev->sigdata.lock = dev->lock.hw_lock; + break; + } + next = DRI2_SAREA_BLOCK_NEXT(p); + if (next <= p || end < next) { + DRM_ERROR("malformed dri2 sarea: next is %p should be within %p-%p\n", + next, p, end); + return -EINVAL; + } + p = next; + } + + return 0; +} + + +static int i915_initialize(struct drm_device * dev, + struct drm_file *file_priv, + drm_i915_init_t * init) { struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv; @@ -163,6 +226,17 @@ static int i915_initialize(struct drm_device * dev, drm_i915_init_t * init) #ifdef I915_HAVE_BUFFER mutex_init(&dev_priv->cmdbuf_mutex); #endif + + if (init->func == I915_INIT_DMA2) { + ret = setup_dri2_sarea(dev, file_priv, init); + if (ret) { + i915_dma_cleanup(dev); + DRM_ERROR("could not set up dri2 sarea\n"); + return ret; + } + } + + return 0; } @@ -207,7 +281,8 @@ static int i915_dma_init(struct drm_device *dev, void *data, switch (init->func) { case I915_INIT_DMA: - retcode = i915_initialize(dev, init); + case I915_INIT_DMA2: + retcode = i915_initialize(dev, file_priv, init); break; case I915_CLEANUP_DMA: retcode = i915_dma_cleanup(dev); @@ -458,7 +533,8 @@ static int i915_dispatch_cmdbuffer(struct drm_device * dev, i915_emit_breadcrumb(dev); #ifdef I915_HAVE_FENCE - drm_fence_flush_old(dev, 0, dev_priv->counter); + if (unlikely((dev_priv->counter & 0xFF) == 0)) + drm_fence_flush_old(dev, 0, dev_priv->counter); #endif return 0; } @@ -512,7 +588,8 @@ static int i915_dispatch_batchbuffer(struct drm_device * dev, i915_emit_breadcrumb(dev); #ifdef I915_HAVE_FENCE - drm_fence_flush_old(dev, 0, dev_priv->counter); + if (unlikely((dev_priv->counter & 0xFF) == 0)) + drm_fence_flush_old(dev, 0, dev_priv->counter); #endif return 0; } @@ -587,7 +664,7 @@ void i915_dispatch_flip(struct drm_device * dev, int planes, int sync) i915_emit_breadcrumb(dev); #ifdef I915_HAVE_FENCE - if (!sync) + if (unlikely(!sync && ((dev_priv->counter & 0xFF) == 0))) drm_fence_flush_old(dev, 0, dev_priv->counter); #endif } @@ -1071,7 +1148,8 @@ static int i915_execbuffer(struct drm_device *dev, void *data, if (ret) goto out_err0; - sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv); + if (sarea_priv) + sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv); /* fence */ ret = drm_fence_buffer_objects(dev, NULL, fence_arg->flags, @@ -1085,7 +1163,7 @@ static int i915_execbuffer(struct drm_device *dev, void *data, fence_arg->handle = fence->base.hash.key; fence_arg->fence_class = fence->fence_class; fence_arg->type = fence->type; - fence_arg->signaled = fence->signaled; + fence_arg->signaled = fence->signaled_types; } } drm_fence_usage_deref_unlocked(&fence); @@ -1171,6 +1249,9 @@ static int i915_getparam(struct drm_device *dev, void *data, case I915_PARAM_LAST_DISPATCH: value = READ_BREADCRUMB(dev_priv); break; + case I915_PARAM_CHIPSET_ID: + value = dev->pci_device; + break; default: DRM_ERROR("Unknown parameter %d\n", param->param); return -EINVAL; @@ -1309,6 +1390,34 @@ static int i915_set_status_page(struct drm_device *dev, void *data, return 0; } +#if 0 /* FIXME DRI2 */ +void i915_driver_lastclose(struct drm_device * dev) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + + if (drm_getsarea(dev) && dev_priv->sarea_priv) + i915_do_cleanup_pageflip(dev); + if (dev_priv->agp_heap) + i915_mem_takedown(&(dev_priv->agp_heap)); + + if (dev_priv->sarea_kmap.virtual) { + drm_bo_kunmap(&dev_priv->sarea_kmap); + dev_priv->sarea_kmap.virtual = NULL; + dev->lock.hw_lock = NULL; + dev->sigdata.lock = NULL; + } + + if (dev_priv->sarea_bo) { + mutex_lock(&dev->struct_mutex); + drm_bo_usage_deref_locked(&dev_priv->sarea_bo); + mutex_unlock(&dev->struct_mutex); + dev_priv->sarea_bo = NULL; + } + + i915_dma_cleanup(dev); +} +#endif + struct drm_ioctl_desc i915_ioctls[] = { DRM_IOCTL_DEF(DRM_I915_INIT, i915_dma_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), DRM_IOCTL_DEF(DRM_I915_FLUSH, i915_flush_ioctl, DRM_AUTH), diff --git a/shared-core/i915_drm.h b/shared-core/i915_drm.h index d48d7665..6067fa02 100644 --- a/shared-core/i915_drm.h +++ b/shared-core/i915_drm.h @@ -43,7 +43,12 @@ typedef struct drm_i915_init { enum { I915_INIT_DMA = 0x01, I915_CLEANUP_DMA = 0x02, - I915_RESUME_DMA = 0x03 + I915_RESUME_DMA = 0x03, + + /* Since this struct isn't versioned, just used a new + * 'func' code to indicate the presence of dri2 sarea + * info. */ + I915_INIT_DMA2 = 0x04 } func; unsigned int mmio_offset; int sarea_priv_offset; @@ -61,6 +66,7 @@ typedef struct drm_i915_init { unsigned int depth_pitch; unsigned int cpp; unsigned int chipset; + unsigned int sarea_handle; } drm_i915_init_t; typedef struct drm_i915_sarea { @@ -232,6 +238,7 @@ typedef struct drm_i915_irq_wait { #define I915_PARAM_IRQ_ACTIVE 1 #define I915_PARAM_ALLOW_BATCHBUFFER 2 #define I915_PARAM_LAST_DISPATCH 3 +#define I915_PARAM_CHIPSET_ID 4 typedef struct drm_i915_getparam { int param; diff --git a/shared-core/i915_drv.h b/shared-core/i915_drv.h index 1432806d..f6c0005d 100644 --- a/shared-core/i915_drv.h +++ b/shared-core/i915_drv.h @@ -164,7 +164,11 @@ struct drm_i915_private { bool panel_wants_dither; struct drm_display_mode *panel_fixed_mode; - /* Register state */ + /* DRI2 sarea */ + struct drm_buffer_object *sarea_bo; + struct drm_bo_kmap_obj sarea_kmap; + + /* Register state */ u8 saveLBB; u32 saveDSPACNTR; u32 saveDSPBCNTR; @@ -183,6 +187,7 @@ struct drm_i915_private { u32 saveVBLANK_A; u32 saveVSYNC_A; u32 saveBCLRPAT_A; + u32 savePIPEASTAT; u32 saveDSPASTRIDE; u32 saveDSPASIZE; u32 saveDSPAPOS; @@ -203,6 +208,7 @@ struct drm_i915_private { u32 saveVBLANK_B; u32 saveVSYNC_B; u32 saveBCLRPAT_B; + u32 savePIPEBSTAT; u32 saveDSPBSTRIDE; u32 saveDSPBSIZE; u32 saveDSPBPOS; @@ -231,12 +237,18 @@ struct drm_i915_private { u32 saveFBC_LL_BASE; u32 saveFBC_CONTROL; u32 saveFBC_CONTROL2; + u32 saveIER; + u32 saveIIR; + u32 saveIMR; + u32 saveCACHE_MODE_0; + u32 saveDSPCLK_GATE_D; + u32 saveMI_ARB_STATE; u32 saveSWF0[16]; u32 saveSWF1[16]; u32 saveSWF2[3]; u8 saveMSR; u8 saveSR[8]; - u8 saveGR[24]; + u8 saveGR[25]; u8 saveAR_INDEX; u8 saveAR[20]; u8 saveDACMASK; @@ -312,15 +324,9 @@ extern void i915_mem_release(struct drm_device * dev, struct mem_block *heap); #ifdef I915_HAVE_FENCE /* i915_fence.c */ - - extern void i915_fence_handler(struct drm_device *dev); -extern int i915_fence_emit_sequence(struct drm_device *dev, uint32_t class, - uint32_t flags, - uint32_t *sequence, - uint32_t *native_type); -extern void i915_poke_flush(struct drm_device *dev, uint32_t class); -extern int i915_fence_has_irq(struct drm_device *dev, uint32_t class, uint32_t flags); +extern void i915_invalidate_reported_sequence(struct drm_device *dev); + #endif #ifdef I915_HAVE_BUFFER @@ -685,6 +691,10 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller); */ #define DMA_FADD_S 0x20d4 +/* Memory Interface Arbitration State + */ +#define MI_ARB_STATE 0x20e4 + /* Cache mode 0 reg. * - Manipulating render cache behaviour is central * to the concept of zone rendering, tuning this reg can help avoid @@ -695,6 +705,7 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller); * bit of interest either set or cleared. EG: (BIT<<16) | BIT to set. */ #define Cache_Mode_0 0x2120 +#define CACHE_MODE_0 0x2120 #define CM0_MASK_SHIFT 16 #define CM0_IZ_OPT_DISABLE (1<<6) #define CM0_ZR_OPT_DISABLE (1<<5) @@ -891,6 +902,8 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller); /** P1 value is 2 greater than this field */ # define VGA0_PD_P1_MASK (0x1f << 0) +#define DSPCLK_GATE_D 0x6200 + /* I830 CRTC registers */ #define HTOTAL_A 0x60000 #define HBLANK_A 0x60004 diff --git a/shared-core/mach64_irq.c b/shared-core/mach64_irq.c index 2d522a6c..57879e8d 100644 --- a/shared-core/mach64_irq.c +++ b/shared-core/mach64_irq.c @@ -71,11 +71,10 @@ irqreturn_t mach64_driver_irq_handler(DRM_IRQ_ARGS) u32 mach64_get_vblank_counter(struct drm_device * dev, int crtc) { const drm_mach64_private_t *const dev_priv = dev->dev_private; - - if (crtc != 0) { + + if (crtc != 0) return 0; - } - + return atomic_read(&dev_priv->vbl_received); } @@ -83,14 +82,15 @@ int mach64_enable_vblank(struct drm_device * dev, int crtc) { drm_mach64_private_t *dev_priv = dev->dev_private; u32 status = MACH64_READ(MACH64_CRTC_INT_CNTL); - + if (crtc != 0) { - DRM_ERROR("tried to enable vblank on non-existent crtc %d\n", crtc); - return 0; + DRM_ERROR("tried to enable vblank on non-existent crtc %d\n", + crtc); + return -EINVAL; } - + DRM_DEBUG("before enable vblank CRTC_INT_CTNL: 0x%08x\n", status); - + /* Turn on VBLANK interrupt */ MACH64_WRITE(MACH64_CRTC_INT_CNTL, MACH64_READ(MACH64_CRTC_INT_CNTL) | MACH64_CRTC_VBLANK_INT_EN); @@ -98,12 +98,31 @@ int mach64_enable_vblank(struct drm_device * dev, int crtc) return 0; } - void mach64_disable_vblank(struct drm_device * dev, int crtc) { + if (crtc != 0) { + DRM_ERROR("tried to disable vblank on non-existent crtc %d\n", + crtc); + return; + } + + /* + * FIXME: implement proper interrupt disable by using the vblank + * counter register (if available). + */ +} + +static void mach64_disable_vblank_local(struct drm_device * dev, int crtc) +{ drm_mach64_private_t *dev_priv = dev->dev_private; u32 status = MACH64_READ(MACH64_CRTC_INT_CNTL); + if (crtc != 0) { + DRM_ERROR("tried to disable vblank on non-existent crtc %d\n", + crtc); + return; + } + DRM_DEBUG("before disable vblank CRTC_INT_CTNL: 0x%08x\n", status); /* Disable and clear VBLANK interrupt */ @@ -111,8 +130,6 @@ void mach64_disable_vblank(struct drm_device * dev, int crtc) | MACH64_CRTC_VBLANK_INT); } -/* drm_dma.h hooks -*/ void mach64_driver_irq_preinstall(struct drm_device * dev) { drm_mach64_private_t *dev_priv = dev->dev_private; @@ -121,7 +138,7 @@ void mach64_driver_irq_preinstall(struct drm_device * dev) DRM_DEBUG("before install CRTC_INT_CTNL: 0x%08x\n", status); - mach64_disable_vblank(dev,0); + mach64_disable_vblank_local(dev, 0); } int mach64_driver_irq_postinstall(struct drm_device * dev) @@ -135,7 +152,7 @@ void mach64_driver_irq_uninstall(struct drm_device * dev) if (!dev_priv) return; - mach64_disable_vblank(dev, 0); + mach64_disable_vblank_local(dev, 0); DRM_DEBUG("after uninstall CRTC_INT_CTNL: 0x%08x\n", MACH64_READ(MACH64_CRTC_INT_CNTL)); diff --git a/shared-core/nouveau_fifo.c b/shared-core/nouveau_fifo.c index d00f1938..0daf9ac4 100644 --- a/shared-core/nouveau_fifo.c +++ b/shared-core/nouveau_fifo.c @@ -64,7 +64,6 @@ static int nouveau_fifo_instmem_configure(struct drm_device *dev) switch(dev_priv->card_type) { - case NV_50: case NV_40: switch (dev_priv->chipset) { case 0x47: diff --git a/shared-core/nouveau_mem.c b/shared-core/nouveau_mem.c index f4e641b9..3d376aed 100644 --- a/shared-core/nouveau_mem.c +++ b/shared-core/nouveau_mem.c @@ -393,7 +393,7 @@ nouveau_mem_init_ttm(struct drm_device *dev) } /* GART */ -#ifndef __powerpc__ +#if !defined(__powerpc__) && !defined(__ia64__) if (drm_device_is_agp(dev) && dev->agp) { if ((ret = nouveau_mem_init_agp(dev, 1))) DRM_ERROR("Error initialising AGP: %d\n", ret); @@ -462,7 +462,7 @@ int nouveau_mem_init(struct drm_device *dev) dev_priv->fb_nomap_heap=NULL; } -#ifndef __powerpc__ +#if !defined(__powerpc__) && !defined(__ia64__) /* Init AGP / NV50 PCIEGART */ if (drm_device_is_agp(dev) && dev->agp) { if ((ret = nouveau_mem_init_agp(dev, 0))) diff --git a/shared-core/nouveau_reg.h b/shared-core/nouveau_reg.h index a2506146..2f7d77cf 100644 --- a/shared-core/nouveau_reg.h +++ b/shared-core/nouveau_reg.h @@ -138,6 +138,7 @@ #define NV40_PFB_TLIMIT(i) (0x00100604 + (i*16)) #define NV40_PFB_TSIZE(i) (0x00100608 + (i*16)) #define NV40_PFB_TSTATUS(i) (0x0010060C + (i*16)) +#define NV40_PFB_UNK_800 0x00100800 #define NV04_PGRAPH_DEBUG_0 0x00400080 #define NV04_PGRAPH_DEBUG_1 0x00400084 @@ -334,19 +335,19 @@ #define NV04_PGRAPH_BLEND 0x00400824 #define NV04_PGRAPH_STORED_FMT 0x00400830 #define NV04_PGRAPH_PATT_COLORRAM 0x00400900 -#define NV40_PGRAPH_TILE0(i) 0x00400900 -#define NV40_PGRAPH_TLIMIT0(i) 0x00400904 -#define NV40_PGRAPH_TSIZE0(i) 0x00400908 -#define NV40_PGRAPH_TSTATUS0(i) 0x0040090C +#define NV40_PGRAPH_TILE0(i) (0x00400900 + (i*16)) +#define NV40_PGRAPH_TLIMIT0(i) (0x00400904 + (i*16)) +#define NV40_PGRAPH_TSIZE0(i) (0x00400908 + (i*16)) +#define NV40_PGRAPH_TSTATUS0(i) (0x0040090C + (i*16)) #define NV10_PGRAPH_TILE(i) (0x00400B00 + (i*16)) #define NV10_PGRAPH_TLIMIT(i) (0x00400B04 + (i*16)) #define NV10_PGRAPH_TSIZE(i) (0x00400B08 + (i*16)) #define NV10_PGRAPH_TSTATUS(i) (0x00400B0C + (i*16)) #define NV04_PGRAPH_U_RAM 0x00400D00 -#define NV47_PGRAPH_TILE0(i) 0x00400D00 -#define NV47_PGRAPH_TLIMIT0(i) 0x00400D04 -#define NV47_PGRAPH_TSIZE0(i) 0x00400D08 -#define NV47_PGRAPH_TSTATUS0(i) 0x00400D0C +#define NV47_PGRAPH_TILE0(i) (0x00400D00 + (i*16)) +#define NV47_PGRAPH_TLIMIT0(i) (0x00400D04 + (i*16)) +#define NV47_PGRAPH_TSIZE0(i) (0x00400D08 + (i*16)) +#define NV47_PGRAPH_TSTATUS0(i) (0x00400D0C + (i*16)) #define NV04_PGRAPH_V_RAM 0x00400D40 #define NV04_PGRAPH_W_RAM 0x00400D80 #define NV10_PGRAPH_COMBINER0_IN_ALPHA 0x00400E40 @@ -394,10 +395,10 @@ #define NV04_PGRAPH_DMA_B_OFFSET 0x00401098 #define NV04_PGRAPH_DMA_B_SIZE 0x0040109C #define NV04_PGRAPH_DMA_B_Y_SIZE 0x004010A0 -#define NV40_PGRAPH_TILE1(i) 0x00406900 -#define NV40_PGRAPH_TLIMIT1(i) 0x00406904 -#define NV40_PGRAPH_TSIZE1(i) 0x00406908 -#define NV40_PGRAPH_TSTATUS1(i) 0x0040690C +#define NV40_PGRAPH_TILE1(i) (0x00406900 + (i*16)) +#define NV40_PGRAPH_TLIMIT1(i) (0x00406904 + (i*16)) +#define NV40_PGRAPH_TSIZE1(i) (0x00406908 + (i*16)) +#define NV40_PGRAPH_TSTATUS1(i) (0x0040690C + (i*16)) /* It's a guess that this works on NV03. Confirmed on NV04, though */ diff --git a/shared-core/nouveau_state.c b/shared-core/nouveau_state.c index 7086a0ab..12162167 100644 --- a/shared-core/nouveau_state.c +++ b/shared-core/nouveau_state.c @@ -212,6 +212,7 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) engine->fifo.save_context = nv10_fifo_save_context; break; case 0x40: + case 0x60: engine->instmem.init = nv04_instmem_init; engine->instmem.takedown= nv04_instmem_takedown; engine->instmem.populate = nv04_instmem_populate; diff --git a/shared-core/nv20_graph.c b/shared-core/nv20_graph.c index 37a147b5..ad73ea91 100644 --- a/shared-core/nv20_graph.c +++ b/shared-core/nv20_graph.c @@ -804,7 +804,7 @@ void nv20_graph_takedown(struct drm_device *dev) int nv30_graph_init(struct drm_device *dev) { struct drm_nouveau_private *dev_priv = dev->dev_private; - uint32_t vramsz, tmp; +// uint32_t vramsz, tmp; int ret, i; NV_WRITE(NV03_PMC_ENABLE, NV_READ(NV03_PMC_ENABLE) & @@ -834,6 +834,7 @@ int nv30_graph_init(struct drm_device *dev) NV_WRITE(NV10_PGRAPH_DEBUG_4, 0x00008000); NV_WRITE(NV04_PGRAPH_LIMIT_VIOL_PIX, 0xf04bdff6); NV_WRITE(0x400B80, 0x1003d888); + NV_WRITE(0x400B84, 0x0c000000); NV_WRITE(0x400098, 0x00000000); NV_WRITE(0x40009C, 0x0005ad00); NV_WRITE(0x400B88, 0x62ff00ff); // suspiciously like PGRAPH_DEBUG_2 @@ -843,30 +844,47 @@ int nv30_graph_init(struct drm_device *dev) NV_WRITE(0x400ba0, 0x002f8685); NV_WRITE(0x400ba4, 0x00231f3f); NV_WRITE(0x4008a4, 0x40000020); - NV_WRITE(0x400B84, 0x0c000000); - NV_WRITE(NV04_PGRAPH_DEBUG_2, 0x62ff0f7f); + + if (dev_priv->chipset == 0x34) { + NV_WRITE(NV10_PGRAPH_RDI_INDEX, 0x00EA0004); + NV_WRITE(NV10_PGRAPH_RDI_DATA , 0x00200201); + NV_WRITE(NV10_PGRAPH_RDI_INDEX, 0x00EA0008); + NV_WRITE(NV10_PGRAPH_RDI_DATA , 0x00000008); + NV_WRITE(NV10_PGRAPH_RDI_INDEX, 0x00EA0000); + NV_WRITE(NV10_PGRAPH_RDI_DATA , 0x00000032); + NV_WRITE(NV10_PGRAPH_RDI_INDEX, 0x00E00004); + NV_WRITE(NV10_PGRAPH_RDI_DATA , 0x00000002); + } + NV_WRITE(0x4000c0, 0x00000016); /* copy tile info from PFB */ - for (i=0; i<NV10_PFB_TILE__SIZE; i++) { - NV_WRITE(NV10_PGRAPH_TILE(i), NV_READ(NV10_PFB_TILE(i))); - NV_WRITE(NV10_PGRAPH_TLIMIT(i), NV_READ(NV10_PFB_TLIMIT(i))); - NV_WRITE(NV10_PGRAPH_TSIZE(i), NV_READ(NV10_PFB_TSIZE(i))); - NV_WRITE(NV10_PGRAPH_TSTATUS(i), NV_READ(NV10_PFB_TSTATUS(i))); + for (i = 0; i < NV10_PFB_TILE__SIZE; i++) { + NV_WRITE(0x00400904 + i*0x10, NV_READ(NV10_PFB_TLIMIT(i))); + /* which is NV40_PGRAPH_TLIMIT0(i) ?? */ + NV_WRITE(0x00400908 + i*0x10, NV_READ(NV10_PFB_TSIZE(i))); + /* which is NV40_PGRAPH_TSIZE0(i) ?? */ + NV_WRITE(0x00400900 + i*0x10, NV_READ(NV10_PFB_TILE(i))); + /* which is NV40_PGRAPH_TILE0(i) ?? */ } NV_WRITE(NV10_PGRAPH_CTX_CONTROL, 0x10000100); NV_WRITE(NV10_PGRAPH_STATE , 0xFFFFFFFF); + NV_WRITE(0x0040075c , 0x00000001); NV_WRITE(NV04_PGRAPH_FIFO , 0x00000001); /* begin RAM config */ - vramsz = drm_get_resource_len(dev, 0) - 1; +// vramsz = drm_get_resource_len(dev, 0) - 1; NV_WRITE(0x4009A4, NV_READ(NV04_PFB_CFG0)); NV_WRITE(0x4009A8, NV_READ(NV04_PFB_CFG1)); - NV_WRITE(0x400750, 0x00EA0000); - NV_WRITE(0x400754, NV_READ(NV04_PFB_CFG0)); - NV_WRITE(0x400750, 0x00EA0004); - NV_WRITE(0x400754, NV_READ(NV04_PFB_CFG1)); + if (dev_priv->chipset != 0x34) { + NV_WRITE(0x400750, 0x00EA0000); + NV_WRITE(0x400754, NV_READ(NV04_PFB_CFG0)); + NV_WRITE(0x400750, 0x00EA0004); + NV_WRITE(0x400754, NV_READ(NV04_PFB_CFG1)); + } + +#if 0 NV_WRITE(0x400820, 0); NV_WRITE(0x400824, 0); NV_WRITE(0x400864, vramsz-1); @@ -885,6 +903,7 @@ int nv30_graph_init(struct drm_device *dev) NV_WRITE(NV03_PGRAPH_ABS_UCLIP_YMIN, 0); NV_WRITE(NV03_PGRAPH_ABS_UCLIP_XMAX, 0x7fff); NV_WRITE(NV03_PGRAPH_ABS_UCLIP_YMAX, 0x7fff); +#endif return 0; } diff --git a/shared-core/nv40_fb.c b/shared-core/nv40_fb.c index ceae8079..ae784cb8 100644 --- a/shared-core/nv40_fb.c +++ b/shared-core/nv40_fb.c @@ -11,6 +11,13 @@ nv40_fb_init(struct drm_device *dev) int num_tiles; int i; + /* This is strictly a NV4x register (don't know about NV5x). */ + /* The blob sets these to all kinds of values, and they mess up our setup. */ + /* I got value 0x52802 instead. For some cards the blob even sets it back to 0x1. */ + /* Note: the blob doesn't read this value, so i'm pretty sure this is safe for all cards. */ + /* Any idea what this is? */ + NV_WRITE(NV40_PFB_UNK_800, 0x1); + switch (dev_priv->chipset) { case 0x40: case 0x45: diff --git a/shared-core/nv40_graph.c b/shared-core/nv40_graph.c index fdf51519..6ef02bf9 100644 --- a/shared-core/nv40_graph.c +++ b/shared-core/nv40_graph.c @@ -1511,6 +1511,7 @@ nv40_graph_create_context(struct nouveau_channel *chan) ctx_init = nv4b_graph_context_init; break; case 0x4c: + case 0x67: ctx_size = NV4C_GRCTX_SIZE; ctx_init = nv4c_graph_context_init; break; @@ -2007,7 +2008,8 @@ nv40_graph_init(struct drm_device *dev) case 0x49: ctx_voodoo = nv49_4b_ctx_voodoo; break; case 0x4a: ctx_voodoo = nv4a_ctx_voodoo; break; case 0x4b: ctx_voodoo = nv49_4b_ctx_voodoo; break; - case 0x4c: ctx_voodoo = nv4c_ctx_voodoo; break; + case 0x4c: + case 0x67: ctx_voodoo = nv4c_ctx_voodoo; break; case 0x4e: ctx_voodoo = nv4e_ctx_voodoo; break; default: DRM_ERROR("Unknown ctx_voodoo for chipset 0x%02x\n", diff --git a/shared-core/radeon_cp.c b/shared-core/radeon_cp.c index f0e55105..f0eda664 100644 --- a/shared-core/radeon_cp.c +++ b/shared-core/radeon_cp.c @@ -825,11 +825,19 @@ static u32 RADEON_READ_MCIND(drm_radeon_private_t *dev_priv, int addr) return ret; } +static u32 RS690_READ_MCIND(drm_radeon_private_t *dev_priv, int addr) +{ + RADEON_WRITE(RS690_MC_INDEX, (addr & RS690_MC_INDEX_MASK)); + return RADEON_READ(RS690_MC_DATA); +} + u32 radeon_read_fb_location(drm_radeon_private_t *dev_priv) { if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV515) return RADEON_READ_MCIND(dev_priv, RV515_MC_FB_LOCATION); + else if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690) + return RS690_READ_MCIND(dev_priv, RS690_MC_FB_LOCATION); else if ((dev_priv->flags & RADEON_FAMILY_MASK) > CHIP_RV515) return RADEON_READ_MCIND(dev_priv, R520_MC_FB_LOCATION); else @@ -840,6 +848,8 @@ static void radeon_write_fb_location(drm_radeon_private_t *dev_priv, u32 fb_loc) { if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV515) RADEON_WRITE_MCIND(RV515_MC_FB_LOCATION, fb_loc); + else if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690) + RS690_WRITE_MCIND(RS690_MC_FB_LOCATION, fb_loc); else if ((dev_priv->flags & RADEON_FAMILY_MASK) > CHIP_RV515) RADEON_WRITE_MCIND(R520_MC_FB_LOCATION, fb_loc); else @@ -850,6 +860,8 @@ static void radeon_write_agp_location(drm_radeon_private_t *dev_priv, u32 agp_lo { if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV515) RADEON_WRITE_MCIND(RV515_MC_AGP_LOCATION, agp_loc); + else if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690) + RS690_WRITE_MCIND(RS690_MC_AGP_LOCATION, agp_loc); else if ((dev_priv->flags & RADEON_FAMILY_MASK) > CHIP_RV515) RADEON_WRITE_MCIND(R520_MC_AGP_LOCATION, agp_loc); else @@ -1362,6 +1374,74 @@ static void radeon_set_igpgart(drm_radeon_private_t * dev_priv, int on) } } +/* Enable or disable RS690 GART on the chip */ +static void radeon_set_rs690gart(drm_radeon_private_t * dev_priv, int on) +{ + u32 temp; + + if (on) { + DRM_DEBUG("programming rs690 gart %08X %08lX %08X\n", + dev_priv->gart_vm_start, + (long)dev_priv->gart_info.bus_addr, + dev_priv->gart_size); + + temp = RS690_READ_MCIND(dev_priv, RS690_MC_MISC_CNTL); + RS690_WRITE_MCIND(RS690_MC_MISC_CNTL, 0x5000); + + RS690_WRITE_MCIND(RS690_MC_AGP_SIZE, + RS690_MC_GART_EN | RS690_MC_AGP_SIZE_32MB); + + temp = RS690_READ_MCIND(dev_priv, RS690_MC_GART_FEATURE_ID); + RS690_WRITE_MCIND(RS690_MC_GART_FEATURE_ID, 0x42040800); + + RS690_WRITE_MCIND(RS690_MC_GART_BASE, + dev_priv->gart_info.bus_addr); + + temp = RS690_READ_MCIND(dev_priv, RS690_MC_AGP_MODE_CONTROL); + RS690_WRITE_MCIND(RS690_MC_AGP_MODE_CONTROL, 0x01400000); + + RS690_WRITE_MCIND(RS690_MC_AGP_BASE, + (unsigned int)dev_priv->gart_vm_start); + + dev_priv->gart_size = 32*1024*1024; + temp = (((dev_priv->gart_vm_start - 1 + dev_priv->gart_size) & + 0xffff0000) | (dev_priv->gart_vm_start >> 16)); + + RS690_WRITE_MCIND(RS690_MC_AGP_LOCATION, temp); + + temp = RS690_READ_MCIND(dev_priv, RS690_MC_AGP_SIZE); + RS690_WRITE_MCIND(RS690_MC_AGP_SIZE, + RS690_MC_GART_EN | RS690_MC_AGP_SIZE_32MB); + + do + { + temp = RS690_READ_MCIND(dev_priv, RS690_MC_GART_CACHE_CNTL); + if ((temp & RS690_MC_GART_CLEAR_STATUS) == + RS690_MC_GART_CLEAR_DONE) + break; + DRM_UDELAY(1); + } while(1); + + RS690_WRITE_MCIND(RS690_MC_GART_CACHE_CNTL, + RS690_MC_GART_CC_CLEAR); + do + { + temp = RS690_READ_MCIND(dev_priv, RS690_MC_GART_CACHE_CNTL); + if ((temp & RS690_MC_GART_CLEAR_STATUS) == + RS690_MC_GART_CLEAR_DONE) + break; + DRM_UDELAY(1); + } while(1); + + RS690_WRITE_MCIND(RS690_MC_GART_CACHE_CNTL, + RS690_MC_GART_CC_NO_CHANGE); + } + else + { + RS690_WRITE_MCIND(RS690_MC_AGP_SIZE, RS690_MC_GART_DIS); + } +} + static void radeon_set_pciegart(drm_radeon_private_t * dev_priv, int on) { u32 tmp = RADEON_READ_PCIE(dev_priv, RADEON_PCIE_TX_GART_CNTL); @@ -1396,6 +1476,12 @@ static void radeon_set_pcigart(drm_radeon_private_t * dev_priv, int on) { u32 tmp; + if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690) + { + radeon_set_rs690gart(dev_priv, on); + return; + } + if (dev_priv->flags & RADEON_IS_IGPGART) { radeon_set_igpgart(dev_priv, on); return; diff --git a/shared-core/radeon_drv.h b/shared-core/radeon_drv.h index 63877008..0c503257 100644 --- a/shared-core/radeon_drv.h +++ b/shared-core/radeon_drv.h @@ -129,6 +129,7 @@ enum radeon_family { CHIP_R420, CHIP_RV410, CHIP_RS400, + CHIP_RS690, CHIP_RV515, CHIP_R520, CHIP_RV530, @@ -503,6 +504,36 @@ extern int radeon_move(struct drm_buffer_object * bo, #define RADEON_IGPGART_ENABLE 0x38 #define RADEON_IGPGART_UNK_39 0x39 +#define RS690_MC_INDEX 0x78 +# define RS690_MC_INDEX_MASK 0x1ff +# define RS690_MC_INDEX_WR_EN (1 << 9) +# define RS690_MC_INDEX_WR_ACK 0x7f +#define RS690_MC_DATA 0x7c + +#define RS690_MC_MISC_CNTL 0x18 +#define RS690_MC_GART_FEATURE_ID 0x2b +#define RS690_MC_GART_BASE 0x2c +#define RS690_MC_GART_CACHE_CNTL 0x2e +# define RS690_MC_GART_CC_NO_CHANGE 0x0 +# define RS690_MC_GART_CC_CLEAR 0x1 +# define RS690_MC_GART_CLEAR_STATUS (1 << 1) +# define RS690_MC_GART_CLEAR_DONE (0 << 1) +# define RS690_MC_GART_CLEAR_PENDING (1 << 1) +#define RS690_MC_AGP_SIZE 0x38 +# define RS690_MC_GART_DIS 0x0 +# define RS690_MC_GART_EN 0x1 +# define RS690_MC_AGP_SIZE_32MB (0 << 1) +# define RS690_MC_AGP_SIZE_64MB (1 << 1) +# define RS690_MC_AGP_SIZE_128MB (2 << 1) +# define RS690_MC_AGP_SIZE_256MB (3 << 1) +# define RS690_MC_AGP_SIZE_512MB (4 << 1) +# define RS690_MC_AGP_SIZE_1GB (5 << 1) +# define RS690_MC_AGP_SIZE_2GB (6 << 1) +#define RS690_MC_AGP_MODE_CONTROL 0x39 +#define RS690_MC_FB_LOCATION 0x100 +#define RS690_MC_AGP_LOCATION 0x101 +#define RS690_MC_AGP_BASE 0x102 + #define R520_MC_IND_INDEX 0x70 #define R520_MC_IND_WR_EN (1<<24) #define R520_MC_IND_DATA 0x74 @@ -1114,8 +1145,8 @@ extern int radeon_move(struct drm_buffer_object * bo, #define RADEON_PCIGART_TABLE_SIZE (32*1024) -#define RADEON_READ(reg) DRM_READ32( dev_priv->mmio, (reg) ) -#define RADEON_WRITE(reg,val) DRM_WRITE32( dev_priv->mmio, (reg), (val) ) +#define RADEON_READ(reg) DRM_READ32( dev_priv->mmio, (reg) ) +#define RADEON_WRITE(reg,val) DRM_WRITE32( dev_priv->mmio, (reg), (val) ) #define RADEON_READ8(reg) DRM_READ8( dev_priv->mmio, (reg) ) #define RADEON_WRITE8(reg,val) DRM_WRITE8( dev_priv->mmio, (reg), (val) ) @@ -1148,6 +1179,13 @@ do { \ RADEON_WRITE(R520_MC_IND_INDEX, 0); \ } while (0) +#define RS690_WRITE_MCIND( addr, val ) \ +do { \ + RADEON_WRITE(RS690_MC_INDEX, RS690_MC_INDEX_WR_EN | ((addr) & RS690_MC_INDEX_MASK)); \ + RADEON_WRITE(RS690_MC_DATA, val); \ + RADEON_WRITE(RS690_MC_INDEX, RS690_MC_INDEX_WR_ACK); \ +} while (0) + #define CP_PACKET0( reg, n ) \ (RADEON_CP_PACKET0 | ((n) << 16) | ((reg) >> 2)) #define CP_PACKET0_TABLE( reg, n ) \ diff --git a/shared-core/via_drv.c b/shared-core/via_drv.c index a802e4ae..dd632c3d 100644 --- a/shared-core/via_drv.c +++ b/shared-core/via_drv.c @@ -40,17 +40,9 @@ static struct pci_device_id pciidlist[] = { #ifdef VIA_HAVE_FENCE -static struct drm_fence_driver via_fence_driver = { - .num_classes = 1, - .wrap_diff = (1 << 30), - .flush_diff = (1 << 20), - .sequence_mask = 0xffffffffU, - .lazy_capable = 1, - .emit = via_fence_emit_sequence, - .poke_flush = via_poke_flush, - .has_irq = via_fence_has_irq, -}; +extern struct drm_fence_driver via_fence_driver; #endif + #ifdef VIA_HAVE_BUFFER /** @@ -76,6 +68,8 @@ static struct drm_bo_driver via_bo_driver = { .init_mem_type = via_init_mem_type, .evict_flags = via_evict_flags, .move = NULL, + .ttm_cache_flush = NULL, + .command_stream_barrier = NULL }; #endif diff --git a/shared-core/via_drv.h b/shared-core/via_drv.h index 8dd4a727..941a2d77 100644 --- a/shared-core/via_drv.h +++ b/shared-core/via_drv.h @@ -196,17 +196,6 @@ extern void via_dmablit_handler(struct drm_device *dev, int engine, int from_irq extern void via_init_dmablit(struct drm_device *dev); #endif -#ifdef VIA_HAVE_FENCE -extern void via_fence_timer(unsigned long data); -extern void via_poke_flush(struct drm_device * dev, uint32_t class); -extern int via_fence_emit_sequence(struct drm_device * dev, uint32_t class, - uint32_t flags, - uint32_t * sequence, - uint32_t * native_type); -extern int via_fence_has_irq(struct drm_device * dev, uint32_t class, - uint32_t flags); -#endif - #ifdef VIA_HAVE_BUFFER extern struct drm_ttm_backend *via_create_ttm_backend_entry(struct drm_device *dev); extern int via_fence_types(struct drm_buffer_object *bo, uint32_t *fclass, diff --git a/shared-core/via_map.c b/shared-core/via_map.c index 11bfa551..54934367 100644 --- a/shared-core/via_map.c +++ b/shared-core/via_map.c @@ -69,9 +69,6 @@ static int via_do_init_map(struct drm_device * dev, drm_via_init_t * init) dev_priv->emit_0_sequence = 0; dev_priv->have_idlelock = 0; spin_lock_init(&dev_priv->fence_lock); - init_timer(&dev_priv->fence_timer); - dev_priv->fence_timer.function = &via_fence_timer; - dev_priv->fence_timer.data = (unsigned long) dev; #endif /* VIA_HAVE_FENCE */ dev->dev_private = (void *)dev_priv; #ifdef VIA_HAVE_BUFFER |