Commit 1ad0510c authored by Rob Clark's avatar Rob Clark
Browse files

Merge tag 'dma-fence-deadline' into HEAD

This series adds a deadline hint to fences, so realtime deadlines
such as vblank can be communicated to the fence signaller for power/
frequency management decisions.

This is partially inspired by a trick i915 does, but implemented
via dma-fence for a couple of reasons:

1) To continue to be able to use the atomic helpers
2) To support cases where display and gpu are different drivers

See https://patchwork.freedesktop.org/series/93035/



This does not yet add any UAPI, although this will be needed in
a number of cases:

1) Workloads "ping-ponging" between CPU and GPU, where we don't
   want the GPU freq governor to interpret time stalled waiting
   for GPU as "idle" time
2) Cases where the compositor is waiting for fences to be signaled
   before issuing the atomic ioctl, for example to maintain 60fps
   cursor updates even when the GPU is not able to maintain that
   framerate.

Signed-off-by: default avatarRob Clark <robdclark@chromium.org>
parents 8559da8f d39e48ca
Loading
Loading
Loading
Loading
+14 −2
Original line number Diff line number Diff line
@@ -164,6 +164,12 @@ DMA Fence Signalling Annotations
.. kernel-doc:: drivers/dma-buf/dma-fence.c
   :doc: fence signalling annotation

DMA Fence Deadline Hints
~~~~~~~~~~~~~~~~~~~~~~~~

.. kernel-doc:: drivers/dma-buf/dma-fence.c
   :doc: deadline hints

DMA Fences Functions Reference
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

@@ -197,8 +203,8 @@ DMA Fence unwrap
.. kernel-doc:: include/linux/dma-fence-unwrap.h
   :internal:

DMA Fence uABI/Sync File
~~~~~~~~~~~~~~~~~~~~~~~~
DMA Fence Sync File
~~~~~~~~~~~~~~~~~~~

.. kernel-doc:: drivers/dma-buf/sync_file.c
   :export:
@@ -206,6 +212,12 @@ DMA Fence uABI/Sync File
.. kernel-doc:: include/linux/sync_file.h
   :internal:

DMA Fence Sync File uABI
~~~~~~~~~~~~~~~~~~~~~~~~

.. kernel-doc:: include/uapi/linux/sync_file.h
   :internal:

Indefinite DMA Fences
~~~~~~~~~~~~~~~~~~~~~

+11 −0
Original line number Diff line number Diff line
@@ -123,12 +123,23 @@ static void dma_fence_array_release(struct dma_fence *fence)
	dma_fence_free(fence);
}

static void dma_fence_array_set_deadline(struct dma_fence *fence,
					 ktime_t deadline)
{
	struct dma_fence_array *array = to_dma_fence_array(fence);
	unsigned i;

	for (i = 0; i < array->num_fences; ++i)
		dma_fence_set_deadline(array->fences[i], deadline);
}

const struct dma_fence_ops dma_fence_array_ops = {
	.get_driver_name = dma_fence_array_get_driver_name,
	.get_timeline_name = dma_fence_array_get_timeline_name,
	.enable_signaling = dma_fence_array_enable_signaling,
	.signaled = dma_fence_array_signaled,
	.release = dma_fence_array_release,
	.set_deadline = dma_fence_array_set_deadline,
};
EXPORT_SYMBOL(dma_fence_array_ops);

+12 −0
Original line number Diff line number Diff line
@@ -206,6 +206,17 @@ static void dma_fence_chain_release(struct dma_fence *fence)
	dma_fence_free(fence);
}


static void dma_fence_chain_set_deadline(struct dma_fence *fence,
					 ktime_t deadline)
{
	dma_fence_chain_for_each(fence, fence) {
		struct dma_fence *f = dma_fence_chain_contained(fence);

		dma_fence_set_deadline(f, deadline);
	}
}

const struct dma_fence_ops dma_fence_chain_ops = {
	.use_64bit_seqno = true,
	.get_driver_name = dma_fence_chain_get_driver_name,
@@ -213,6 +224,7 @@ const struct dma_fence_ops dma_fence_chain_ops = {
	.enable_signaling = dma_fence_chain_enable_signaling,
	.signaled = dma_fence_chain_signaled,
	.release = dma_fence_chain_release,
	.set_deadline = dma_fence_chain_set_deadline,
};
EXPORT_SYMBOL(dma_fence_chain_ops);

+59 −0
Original line number Diff line number Diff line
@@ -912,6 +912,65 @@ dma_fence_wait_any_timeout(struct dma_fence **fences, uint32_t count,
}
EXPORT_SYMBOL(dma_fence_wait_any_timeout);

/**
 * DOC: deadline hints
 *
 * In an ideal world, it would be possible to pipeline a workload sufficiently
 * that a utilization based device frequency governor could arrive at a minimum
 * frequency that meets the requirements of the use-case, in order to minimize
 * power consumption.  But in the real world there are many workloads which
 * defy this ideal.  For example, but not limited to:
 *
 * * Workloads that ping-pong between device and CPU, with alternating periods
 *   of CPU waiting for device, and device waiting on CPU.  This can result in
 *   devfreq and cpufreq seeing idle time in their respective domains and in
 *   result reduce frequency.
 *
 * * Workloads that interact with a periodic time based deadline, such as double
 *   buffered GPU rendering vs vblank sync'd page flipping.  In this scenario,
 *   missing a vblank deadline results in an *increase* in idle time on the GPU
 *   (since it has to wait an additional vblank period), sending a signal to
 *   the GPU's devfreq to reduce frequency, when in fact the opposite is what is
 *   needed.
 *
 * To this end, deadline hint(s) can be set on a &dma_fence via &dma_fence_set_deadline.
 * The deadline hint provides a way for the waiting driver, or userspace, to
 * convey an appropriate sense of urgency to the signaling driver.
 *
 * A deadline hint is given in absolute ktime (CLOCK_MONOTONIC for userspace
 * facing APIs).  The time could either be some point in the future (such as
 * the vblank based deadline for page-flipping, or the start of a compositor's
 * composition cycle), or the current time to indicate an immediate deadline
 * hint (Ie. forward progress cannot be made until this fence is signaled).
 *
 * Multiple deadlines may be set on a given fence, even in parallel.  See the
 * documentation for &dma_fence_ops.set_deadline.
 *
 * The deadline hint is just that, a hint.  The driver that created the fence
 * may react by increasing frequency, making different scheduling choices, etc.
 * Or doing nothing at all.
 */

/**
 * dma_fence_set_deadline - set desired fence-wait deadline hint
 * @fence:    the fence that is to be waited on
 * @deadline: the time by which the waiter hopes for the fence to be
 *            signaled
 *
 * Give the fence signaler a hint about an upcoming deadline, such as
 * vblank, by which point the waiter would prefer the fence to be
 * signaled by.  This is intended to give feedback to the fence signaler
 * to aid in power management decisions, such as boosting GPU frequency
 * if a periodic vblank deadline is approaching but the fence is not
 * yet signaled..
 */
void dma_fence_set_deadline(struct dma_fence *fence, ktime_t deadline)
{
	if (fence->ops->set_deadline && !dma_fence_is_signaled(fence))
		fence->ops->set_deadline(fence, deadline);
}
EXPORT_SYMBOL(dma_fence_set_deadline);

/**
 * dma_fence_describe - Dump fence describtion into seq_file
 * @fence: the 6fence to describe
+22 −0
Original line number Diff line number Diff line
@@ -684,6 +684,28 @@ long dma_resv_wait_timeout(struct dma_resv *obj, enum dma_resv_usage usage,
}
EXPORT_SYMBOL_GPL(dma_resv_wait_timeout);

/**
 * dma_resv_set_deadline - Set a deadline on reservation's objects fences
 * @obj: the reservation object
 * @usage: controls which fences to include, see enum dma_resv_usage.
 * @deadline: the requested deadline (MONOTONIC)
 *
 * May be called without holding the dma_resv lock.  Sets @deadline on
 * all fences filtered by @usage.
 */
void dma_resv_set_deadline(struct dma_resv *obj, enum dma_resv_usage usage,
			   ktime_t deadline)
{
	struct dma_resv_iter cursor;
	struct dma_fence *fence;

	dma_resv_iter_begin(&cursor, obj, usage);
	dma_resv_for_each_fence_unlocked(&cursor, fence) {
		dma_fence_set_deadline(fence, deadline);
	}
	dma_resv_iter_end(&cursor);
}
EXPORT_SYMBOL_GPL(dma_resv_set_deadline);

/**
 * dma_resv_test_signaled - Test if a reservation object's fences have been
Loading