Merge tag 'drm-next-2019-05-09' of git://anongit.freedesktop.org/drm/drm

Pull drm updates from Dave Airlie:
 "This has two exciting community drivers for ARM Mali accelerators.
  Since ARM has never been open source friendly on the GPU side of the
  house, the community has had to create open source drivers for the
  Mali GPUs. Lima covers the older t4xx and panfrost the newer 6xx/7xx
  series. Well done to all involved and hopefully this will help ARM
  head in the right direction.

  There is also now the ability if you don't have any of the legacy
  drivers enabled (pre-KMS) to remove all the pre-KMS support code from
  the core drm, this saves 10% or so in codesize on my machine.

  i915 also enable Icelake/Elkhart Lake Gen11 GPUs by default, vboxvideo
  moves out of staging.

  There are also some rcar-du patches which crossover with media tree
  but all should be acked by Mauro.

  Summary:

  uapi changes:
   - Colorspace connector property
   - fourcc - new YUV formts
   - timeline sync objects initially merged
   - expose FB_DAMAGE_CLIPS to atomic userspace

  new drivers:
   - vboxvideo: moved out of staging
   - aspeed: ASPEED SoC BMC chip display support
   - lima: ARM Mali4xx GPU acceleration driver support
   - panfrost: ARM Mali6xx/7xx Midgard/Bitfrost acceleration driver support

  core:
   - component helper docs
   - unplugging fixes
   - devm device init
   - MIPI/DSI rate control
   - shmem backed gem objects
   - connector, display_info, edid_quirks cleanups
   - dma_buf fence chain support
   - 64-bit dma-fence seqno comparison fixes
   - move initial fb config code to core
   - gem fence array helpers for Lima
   - ability to remove legacy support code if no drivers requires it (removes 10% of drm.ko size)
   - lease fixes

  ttm:
   - unified DRM_FILE_PAGE_OFFSET handling
   - Account for kernel allocations in kernel zone only

  panel:
   - OSD070T1718-19TS panel support
   - panel-tpo-td028ttec1 backlight support
   - Ronbo RB070D30 MIPI/DSI
   - Feiyang FY07024DI26A30-D MIPI-DSI panel
   - Rocktech jh057n00900 MIPI-DSI panel

  i915:
   - Comet Lake (Gen9) PCI IDs
   - Updated Icelake PCI IDs
   - Elkhartlake (Gen11) support
   - DP MST property addtions
   - plane and watermark fixes
   - Icelake port sync and VEBOX disable fixes
   - struct_mutex usage reduction
   - Icelake gamma fix
   - GuC reset fixes
   - make mmap more asynchronous
   - sound display power well race fixes
   - DDI/MIPI-DSI clocks for Icelake
   - Icelake RPS frequency changing support
   - Icelake workarounds

  amdgpu:
   - Use HMM for userptr
   - vega20 experimental smu11 support
   - RAS support for vega20
   - BACO support for vega12 + fixes for vega20
   - reworked IH interrupt handling
   - amdkfd RAS support
   - Freesync improvements
   - initial timeline sync object support
   - DC Z ordering fixes
   - NV12 planes support
   - colorspace properties for planes=
   - eDP opts if eDP already initialized

  nouveau:
   - misc fixes

  etnaviv:
   - misc fixes

  msm:
   - GPU zap shader support expansion
   - robustness ABI addition

  exynos:
   - Logging cleanups

  tegra:
   - Shared reset fix
   - CPU cache maintenance fix

  cirrus:
   - driver rewritten using simple helpers

  meson:
   - G12A support

  vmwgfx:
   - Resource dirtying management improvements
   - Userspace logging improvements

  virtio:
   - PRIME fixes

  rockchip:
   - rk3066 hdmi support

  sun4i:
   - DSI burst mode support

  vc4:
   - load tracker to detect underflow

  v3d:
   - v3d v4.2 support

  malidp:
   - initial Mali D71 support in komeda driver

  tfp410:
   - omap related improvement

  omapdrm:
   - drm bridge/panel support
   - drop some omap specific panels

  rcar-du:
   - Display writeback support"

* tag 'drm-next-2019-05-09' of git://anongit.freedesktop.org/drm/drm: (1507 commits)
  drm/msm/a6xx: No zap shader is not an error
  drm/cma-helper: Fix drm_gem_cma_free_object()
  drm: Fix timestamp docs for variable refresh properties.
  drm/komeda: Mark the local functions as static
  drm/komeda: Fixed warning: Function parameter or member not described
  drm/komeda: Expose bus_width to Komeda-CORE
  drm/komeda: Add sysfs attribute: core_id and config_id
  drm: add non-desktop quirk for Valve HMDs
  drm/panfrost: Show stored feature registers
  drm/panfrost: Don't scream about deferred probe
  drm/panfrost: Disable PM on probe failure
  drm/panfrost: Set DMA masks earlier
  drm/panfrost: Add sanity checks to submit IOCTL
  drm/etnaviv: initialize idle mask before querying the HW db
  drm: introduce a capability flag for syncobj timeline support
  drm: report consistent errors when checking syncobj capibility
  drm/nouveau/nouveau: forward error generated while resuming objects tree
  drm/nouveau/fb/ramgk104: fix spelling mistake "sucessfully" -> "successfully"
  drm/nouveau/i2c: Disable i2c bus access after ->fini()
  drm/nouveau: Remove duplicate ACPI_VIDEO_NOTIFY_PROBE definition
  ...
This commit is contained in:
Linus Torvalds
2019-05-08 21:35:19 -07:00
1012 changed files with 63845 additions and 24075 deletions

View File

@@ -61,6 +61,7 @@ struct syncobj_wait_entry {
struct task_struct *task;
struct dma_fence *fence;
struct dma_fence_cb fence_cb;
u64 point;
};
static void syncobj_wait_syncobj_func(struct drm_syncobj *syncobj,
@@ -95,6 +96,8 @@ EXPORT_SYMBOL(drm_syncobj_find);
static void drm_syncobj_fence_add_wait(struct drm_syncobj *syncobj,
struct syncobj_wait_entry *wait)
{
struct dma_fence *fence;
if (wait->fence)
return;
@@ -103,11 +106,15 @@ static void drm_syncobj_fence_add_wait(struct drm_syncobj *syncobj,
* have the lock, try one more time just to be sure we don't add a
* callback when a fence has already been set.
*/
if (syncobj->fence)
wait->fence = dma_fence_get(
rcu_dereference_protected(syncobj->fence, 1));
else
fence = dma_fence_get(rcu_dereference_protected(syncobj->fence, 1));
if (!fence || dma_fence_chain_find_seqno(&fence, wait->point)) {
dma_fence_put(fence);
list_add_tail(&wait->node, &syncobj->cb_list);
} else if (!fence) {
wait->fence = dma_fence_get_stub();
} else {
wait->fence = fence;
}
spin_unlock(&syncobj->lock);
}
@@ -122,6 +129,44 @@ static void drm_syncobj_remove_wait(struct drm_syncobj *syncobj,
spin_unlock(&syncobj->lock);
}
/**
* drm_syncobj_add_point - add new timeline point to the syncobj
* @syncobj: sync object to add timeline point do
* @chain: chain node to use to add the point
* @fence: fence to encapsulate in the chain node
* @point: sequence number to use for the point
*
* Add the chain node as new timeline point to the syncobj.
*/
void drm_syncobj_add_point(struct drm_syncobj *syncobj,
struct dma_fence_chain *chain,
struct dma_fence *fence,
uint64_t point)
{
struct syncobj_wait_entry *cur, *tmp;
struct dma_fence *prev;
dma_fence_get(fence);
spin_lock(&syncobj->lock);
prev = drm_syncobj_fence_get(syncobj);
/* You are adding an unorder point to timeline, which could cause payload returned from query_ioctl is 0! */
if (prev && prev->seqno >= point)
DRM_ERROR("You are adding an unorder point to timeline!\n");
dma_fence_chain_init(chain, prev, fence, point);
rcu_assign_pointer(syncobj->fence, &chain->base);
list_for_each_entry_safe(cur, tmp, &syncobj->cb_list, node)
syncobj_wait_syncobj_func(syncobj, cur);
spin_unlock(&syncobj->lock);
/* Walk the chain once to trigger garbage collection */
dma_fence_chain_for_each(fence, prev);
dma_fence_put(prev);
}
EXPORT_SYMBOL(drm_syncobj_add_point);
/**
* drm_syncobj_replace_fence - replace fence in a sync object.
* @syncobj: Sync object to replace fence in
@@ -145,10 +190,8 @@ void drm_syncobj_replace_fence(struct drm_syncobj *syncobj,
rcu_assign_pointer(syncobj->fence, fence);
if (fence != old_fence) {
list_for_each_entry_safe(cur, tmp, &syncobj->cb_list, node) {
list_del_init(&cur->node);
list_for_each_entry_safe(cur, tmp, &syncobj->cb_list, node)
syncobj_wait_syncobj_func(syncobj, cur);
}
}
spin_unlock(&syncobj->lock);
@@ -171,6 +214,8 @@ static void drm_syncobj_assign_null_handle(struct drm_syncobj *syncobj)
dma_fence_put(fence);
}
/* 5s default for wait submission */
#define DRM_SYNCOBJ_WAIT_FOR_SUBMIT_TIMEOUT 5000000000ULL
/**
* drm_syncobj_find_fence - lookup and reference the fence in a sync object
* @file_private: drm file private pointer
@@ -191,16 +236,58 @@ int drm_syncobj_find_fence(struct drm_file *file_private,
struct dma_fence **fence)
{
struct drm_syncobj *syncobj = drm_syncobj_find(file_private, handle);
int ret = 0;
struct syncobj_wait_entry wait;
u64 timeout = nsecs_to_jiffies64(DRM_SYNCOBJ_WAIT_FOR_SUBMIT_TIMEOUT);
int ret;
if (!syncobj)
return -ENOENT;
*fence = drm_syncobj_fence_get(syncobj);
if (!*fence) {
drm_syncobj_put(syncobj);
if (*fence) {
ret = dma_fence_chain_find_seqno(fence, point);
if (!ret)
return 0;
dma_fence_put(*fence);
} else {
ret = -EINVAL;
}
drm_syncobj_put(syncobj);
if (!(flags & DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT))
return ret;
memset(&wait, 0, sizeof(wait));
wait.task = current;
wait.point = point;
drm_syncobj_fence_add_wait(syncobj, &wait);
do {
set_current_state(TASK_INTERRUPTIBLE);
if (wait.fence) {
ret = 0;
break;
}
if (timeout == 0) {
ret = -ETIME;
break;
}
if (signal_pending(current)) {
ret = -ERESTARTSYS;
break;
}
timeout = schedule_timeout(timeout);
} while (1);
__set_current_state(TASK_RUNNING);
*fence = wait.fence;
if (wait.node.next)
drm_syncobj_remove_wait(syncobj, &wait);
return ret;
}
EXPORT_SYMBOL(drm_syncobj_find_fence);
@@ -592,6 +679,80 @@ drm_syncobj_fd_to_handle_ioctl(struct drm_device *dev, void *data,
&args->handle);
}
static int drm_syncobj_transfer_to_timeline(struct drm_file *file_private,
struct drm_syncobj_transfer *args)
{
struct drm_syncobj *timeline_syncobj = NULL;
struct dma_fence *fence;
struct dma_fence_chain *chain;
int ret;
timeline_syncobj = drm_syncobj_find(file_private, args->dst_handle);
if (!timeline_syncobj) {
return -ENOENT;
}
ret = drm_syncobj_find_fence(file_private, args->src_handle,
args->src_point, args->flags,
&fence);
if (ret)
goto err;
chain = kzalloc(sizeof(struct dma_fence_chain), GFP_KERNEL);
if (!chain) {
ret = -ENOMEM;
goto err1;
}
drm_syncobj_add_point(timeline_syncobj, chain, fence, args->dst_point);
err1:
dma_fence_put(fence);
err:
drm_syncobj_put(timeline_syncobj);
return ret;
}
static int
drm_syncobj_transfer_to_binary(struct drm_file *file_private,
struct drm_syncobj_transfer *args)
{
struct drm_syncobj *binary_syncobj = NULL;
struct dma_fence *fence;
int ret;
binary_syncobj = drm_syncobj_find(file_private, args->dst_handle);
if (!binary_syncobj)
return -ENOENT;
ret = drm_syncobj_find_fence(file_private, args->src_handle,
args->src_point, args->flags, &fence);
if (ret)
goto err;
drm_syncobj_replace_fence(binary_syncobj, fence);
dma_fence_put(fence);
err:
drm_syncobj_put(binary_syncobj);
return ret;
}
int
drm_syncobj_transfer_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_private)
{
struct drm_syncobj_transfer *args = data;
int ret;
if (!drm_core_check_feature(dev, DRIVER_SYNCOBJ_TIMELINE))
return -EOPNOTSUPP;
if (args->pad)
return -EINVAL;
if (args->dst_point)
ret = drm_syncobj_transfer_to_timeline(file_private, args);
else
ret = drm_syncobj_transfer_to_binary(file_private, args);
return ret;
}
static void syncobj_wait_fence_func(struct dma_fence *fence,
struct dma_fence_cb *cb)
{
@@ -604,13 +765,27 @@ static void syncobj_wait_fence_func(struct dma_fence *fence,
static void syncobj_wait_syncobj_func(struct drm_syncobj *syncobj,
struct syncobj_wait_entry *wait)
{
struct dma_fence *fence;
/* This happens inside the syncobj lock */
wait->fence = dma_fence_get(rcu_dereference_protected(syncobj->fence,
lockdep_is_held(&syncobj->lock)));
fence = rcu_dereference_protected(syncobj->fence,
lockdep_is_held(&syncobj->lock));
dma_fence_get(fence);
if (!fence || dma_fence_chain_find_seqno(&fence, wait->point)) {
dma_fence_put(fence);
return;
} else if (!fence) {
wait->fence = dma_fence_get_stub();
} else {
wait->fence = fence;
}
wake_up_process(wait->task);
list_del_init(&wait->node);
}
static signed long drm_syncobj_array_wait_timeout(struct drm_syncobj **syncobjs,
void __user *user_points,
uint32_t count,
uint32_t flags,
signed long timeout,
@@ -618,12 +793,27 @@ static signed long drm_syncobj_array_wait_timeout(struct drm_syncobj **syncobjs,
{
struct syncobj_wait_entry *entries;
struct dma_fence *fence;
uint64_t *points;
uint32_t signaled_count, i;
entries = kcalloc(count, sizeof(*entries), GFP_KERNEL);
if (!entries)
points = kmalloc_array(count, sizeof(*points), GFP_KERNEL);
if (points == NULL)
return -ENOMEM;
if (!user_points) {
memset(points, 0, count * sizeof(uint64_t));
} else if (copy_from_user(points, user_points,
sizeof(uint64_t) * count)) {
timeout = -EFAULT;
goto err_free_points;
}
entries = kcalloc(count, sizeof(*entries), GFP_KERNEL);
if (!entries) {
timeout = -ENOMEM;
goto err_free_points;
}
/* Walk the list of sync objects and initialize entries. We do
* this up-front so that we can properly return -EINVAL if there is
* a syncobj with a missing fence and then never have the chance of
@@ -631,9 +821,13 @@ static signed long drm_syncobj_array_wait_timeout(struct drm_syncobj **syncobjs,
*/
signaled_count = 0;
for (i = 0; i < count; ++i) {
struct dma_fence *fence;
entries[i].task = current;
entries[i].fence = drm_syncobj_fence_get(syncobjs[i]);
if (!entries[i].fence) {
entries[i].point = points[i];
fence = drm_syncobj_fence_get(syncobjs[i]);
if (!fence || dma_fence_chain_find_seqno(&fence, points[i])) {
dma_fence_put(fence);
if (flags & DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT) {
continue;
} else {
@@ -642,7 +836,13 @@ static signed long drm_syncobj_array_wait_timeout(struct drm_syncobj **syncobjs,
}
}
if (dma_fence_is_signaled(entries[i].fence)) {
if (fence)
entries[i].fence = fence;
else
entries[i].fence = dma_fence_get_stub();
if ((flags & DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE) ||
dma_fence_is_signaled(entries[i].fence)) {
if (signaled_count == 0 && idx)
*idx = i;
signaled_count++;
@@ -675,7 +875,8 @@ static signed long drm_syncobj_array_wait_timeout(struct drm_syncobj **syncobjs,
if (!fence)
continue;
if (dma_fence_is_signaled(fence) ||
if ((flags & DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE) ||
dma_fence_is_signaled(fence) ||
(!entries[i].fence_cb.func &&
dma_fence_add_callback(fence,
&entries[i].fence_cb,
@@ -720,6 +921,9 @@ cleanup_entries:
}
kfree(entries);
err_free_points:
kfree(points);
return timeout;
}
@@ -730,7 +934,7 @@ cleanup_entries:
*
* Calculate the timeout in jiffies from an absolute time in sec/nsec.
*/
static signed long drm_timeout_abs_to_jiffies(int64_t timeout_nsec)
signed long drm_timeout_abs_to_jiffies(int64_t timeout_nsec)
{
ktime_t abs_timeout, now;
u64 timeout_ns, timeout_jiffies64;
@@ -754,23 +958,38 @@ static signed long drm_timeout_abs_to_jiffies(int64_t timeout_nsec)
return timeout_jiffies64 + 1;
}
EXPORT_SYMBOL(drm_timeout_abs_to_jiffies);
static int drm_syncobj_array_wait(struct drm_device *dev,
struct drm_file *file_private,
struct drm_syncobj_wait *wait,
struct drm_syncobj **syncobjs)
struct drm_syncobj_timeline_wait *timeline_wait,
struct drm_syncobj **syncobjs, bool timeline)
{
signed long timeout = drm_timeout_abs_to_jiffies(wait->timeout_nsec);
signed long timeout = 0;
uint32_t first = ~0;
timeout = drm_syncobj_array_wait_timeout(syncobjs,
wait->count_handles,
wait->flags,
timeout, &first);
if (timeout < 0)
return timeout;
wait->first_signaled = first;
if (!timeline) {
timeout = drm_timeout_abs_to_jiffies(wait->timeout_nsec);
timeout = drm_syncobj_array_wait_timeout(syncobjs,
NULL,
wait->count_handles,
wait->flags,
timeout, &first);
if (timeout < 0)
return timeout;
wait->first_signaled = first;
} else {
timeout = drm_timeout_abs_to_jiffies(timeline_wait->timeout_nsec);
timeout = drm_syncobj_array_wait_timeout(syncobjs,
u64_to_user_ptr(timeline_wait->points),
timeline_wait->count_handles,
timeline_wait->flags,
timeout, &first);
if (timeout < 0)
return timeout;
timeline_wait->first_signaled = first;
}
return 0;
}
@@ -856,13 +1075,48 @@ drm_syncobj_wait_ioctl(struct drm_device *dev, void *data,
return ret;
ret = drm_syncobj_array_wait(dev, file_private,
args, syncobjs);
args, NULL, syncobjs, false);
drm_syncobj_array_free(syncobjs, args->count_handles);
return ret;
}
int
drm_syncobj_timeline_wait_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_private)
{
struct drm_syncobj_timeline_wait *args = data;
struct drm_syncobj **syncobjs;
int ret = 0;
if (!drm_core_check_feature(dev, DRIVER_SYNCOBJ_TIMELINE))
return -EOPNOTSUPP;
if (args->flags & ~(DRM_SYNCOBJ_WAIT_FLAGS_WAIT_ALL |
DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT |
DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE))
return -EINVAL;
if (args->count_handles == 0)
return -EINVAL;
ret = drm_syncobj_array_find(file_private,
u64_to_user_ptr(args->handles),
args->count_handles,
&syncobjs);
if (ret < 0)
return ret;
ret = drm_syncobj_array_wait(dev, file_private,
NULL, args, syncobjs, true);
drm_syncobj_array_free(syncobjs, args->count_handles);
return ret;
}
int
drm_syncobj_reset_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_private)
@@ -928,3 +1182,138 @@ drm_syncobj_signal_ioctl(struct drm_device *dev, void *data,
return ret;
}
int
drm_syncobj_timeline_signal_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_private)
{
struct drm_syncobj_timeline_array *args = data;
struct drm_syncobj **syncobjs;
struct dma_fence_chain **chains;
uint64_t *points;
uint32_t i, j;
int ret;
if (!drm_core_check_feature(dev, DRIVER_SYNCOBJ_TIMELINE))
return -EOPNOTSUPP;
if (args->pad != 0)
return -EINVAL;
if (args->count_handles == 0)
return -EINVAL;
ret = drm_syncobj_array_find(file_private,
u64_to_user_ptr(args->handles),
args->count_handles,
&syncobjs);
if (ret < 0)
return ret;
points = kmalloc_array(args->count_handles, sizeof(*points),
GFP_KERNEL);
if (!points) {
ret = -ENOMEM;
goto out;
}
if (!u64_to_user_ptr(args->points)) {
memset(points, 0, args->count_handles * sizeof(uint64_t));
} else if (copy_from_user(points, u64_to_user_ptr(args->points),
sizeof(uint64_t) * args->count_handles)) {
ret = -EFAULT;
goto err_points;
}
chains = kmalloc_array(args->count_handles, sizeof(void *), GFP_KERNEL);
if (!chains) {
ret = -ENOMEM;
goto err_points;
}
for (i = 0; i < args->count_handles; i++) {
chains[i] = kzalloc(sizeof(struct dma_fence_chain), GFP_KERNEL);
if (!chains[i]) {
for (j = 0; j < i; j++)
kfree(chains[j]);
ret = -ENOMEM;
goto err_chains;
}
}
for (i = 0; i < args->count_handles; i++) {
struct dma_fence *fence = dma_fence_get_stub();
drm_syncobj_add_point(syncobjs[i], chains[i],
fence, points[i]);
dma_fence_put(fence);
}
err_chains:
kfree(chains);
err_points:
kfree(points);
out:
drm_syncobj_array_free(syncobjs, args->count_handles);
return ret;
}
int drm_syncobj_query_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_private)
{
struct drm_syncobj_timeline_array *args = data;
struct drm_syncobj **syncobjs;
uint64_t __user *points = u64_to_user_ptr(args->points);
uint32_t i;
int ret;
if (!drm_core_check_feature(dev, DRIVER_SYNCOBJ_TIMELINE))
return -EOPNOTSUPP;
if (args->pad != 0)
return -EINVAL;
if (args->count_handles == 0)
return -EINVAL;
ret = drm_syncobj_array_find(file_private,
u64_to_user_ptr(args->handles),
args->count_handles,
&syncobjs);
if (ret < 0)
return ret;
for (i = 0; i < args->count_handles; i++) {
struct dma_fence_chain *chain;
struct dma_fence *fence;
uint64_t point;
fence = drm_syncobj_fence_get(syncobjs[i]);
chain = to_dma_fence_chain(fence);
if (chain) {
struct dma_fence *iter, *last_signaled = NULL;
dma_fence_chain_for_each(iter, fence) {
if (!iter)
break;
dma_fence_put(last_signaled);
last_signaled = dma_fence_get(iter);
if (!to_dma_fence_chain(last_signaled)->prev_seqno)
/* It is most likely that timeline has
* unorder points. */
break;
}
point = dma_fence_is_signaled(last_signaled) ?
last_signaled->seqno :
to_dma_fence_chain(last_signaled)->prev_seqno;
dma_fence_put(last_signaled);
} else {
point = 0;
}
ret = copy_to_user(&points[i], &point, sizeof(uint64_t));
ret = ret ? -EFAULT : 0;
if (ret)
break;
}
drm_syncobj_array_free(syncobjs, args->count_handles);
return ret;
}