Commit 70e67aae authored by Rob Clark's avatar Rob Clark Committed by Dmitry Baryshkov
Browse files

dma-buf/sw_sync: Add fence deadline support



This consists of simply storing the most recent deadline, and adding an
ioctl to retrieve the deadline.  This can be used in conjunction with
the SET_DEADLINE ioctl on a fence fd for testing.  Ie. create various
sw_sync fences, merge them into a fence-array, set deadline on the
fence-array and confirm that it is propagated properly to each fence.

v2: Switch UABI to express deadline as u64
v3: More verbose UAPI docs, show how to convert from timespec
v4: Better comments, track the soonest deadline, as a normal fence
    implementation would, return an error if no deadline set.

Signed-off-by: default avatarRob Clark <robdclark@chromium.org>
Reviewed-by: default avatarChristian König <christian.koenig@amd.com>
Acked-by: default avatarPekka Paalanen <pekka.paalanen@collabora.com>
Signed-off-by: default avatarDmitry Baryshkov <dmitry.baryshkov@linaro.org>
Link: https://patchwork.freedesktop.org/patch/msgid/20230823215458.203366-4-robdclark@gmail.com
parent 63ee4454
Loading
Loading
Loading
Loading
+82 −0
Original line number Diff line number Diff line
@@ -52,12 +52,33 @@ struct sw_sync_create_fence_data {
	__s32	fence; /* fd of new fence */
};

/**
 * struct sw_sync_get_deadline - get the deadline hint of a sw_sync fence
 * @deadline_ns: absolute time of the deadline
 * @pad:	must be zero
 * @fence_fd:	the sw_sync fence fd (in)
 *
 * Return the earliest deadline set on the fence.  The timebase for the
 * deadline is CLOCK_MONOTONIC (same as vblank).  If there is no deadline
 * set on the fence, this ioctl will return -ENOENT.
 */
struct sw_sync_get_deadline {
	__u64	deadline_ns;
	__u32	pad;
	__s32	fence_fd;
};

#define SW_SYNC_IOC_MAGIC	'W'

#define SW_SYNC_IOC_CREATE_FENCE	_IOWR(SW_SYNC_IOC_MAGIC, 0,\
		struct sw_sync_create_fence_data)

#define SW_SYNC_IOC_INC			_IOW(SW_SYNC_IOC_MAGIC, 1, __u32)
#define SW_SYNC_GET_DEADLINE		_IOWR(SW_SYNC_IOC_MAGIC, 2, \
		struct sw_sync_get_deadline)


#define SW_SYNC_HAS_DEADLINE_BIT	DMA_FENCE_FLAG_USER_BITS

static const struct dma_fence_ops timeline_fence_ops;

@@ -171,6 +192,22 @@ static void timeline_fence_timeline_value_str(struct dma_fence *fence,
	snprintf(str, size, "%d", parent->value);
}

static void timeline_fence_set_deadline(struct dma_fence *fence, ktime_t deadline)
{
	struct sync_pt *pt = dma_fence_to_sync_pt(fence);
	unsigned long flags;

	spin_lock_irqsave(fence->lock, flags);
	if (test_bit(SW_SYNC_HAS_DEADLINE_BIT, &fence->flags)) {
		if (ktime_before(deadline, pt->deadline))
			pt->deadline = deadline;
	} else {
		pt->deadline = deadline;
		__set_bit(SW_SYNC_HAS_DEADLINE_BIT, &fence->flags);
	}
	spin_unlock_irqrestore(fence->lock, flags);
}

static const struct dma_fence_ops timeline_fence_ops = {
	.get_driver_name = timeline_fence_get_driver_name,
	.get_timeline_name = timeline_fence_get_timeline_name,
@@ -179,6 +216,7 @@ static const struct dma_fence_ops timeline_fence_ops = {
	.release = timeline_fence_release,
	.fence_value_str = timeline_fence_value_str,
	.timeline_value_str = timeline_fence_timeline_value_str,
	.set_deadline = timeline_fence_set_deadline,
};

/**
@@ -387,6 +425,47 @@ static long sw_sync_ioctl_inc(struct sync_timeline *obj, unsigned long arg)
	return 0;
}

static int sw_sync_ioctl_get_deadline(struct sync_timeline *obj, unsigned long arg)
{
	struct sw_sync_get_deadline data;
	struct dma_fence *fence;
	unsigned long flags;
	struct sync_pt *pt;
	int ret = 0;

	if (copy_from_user(&data, (void __user *)arg, sizeof(data)))
		return -EFAULT;

	if (data.deadline_ns || data.pad)
		return -EINVAL;

	fence = sync_file_get_fence(data.fence_fd);
	if (!fence)
		return -EINVAL;

	pt = dma_fence_to_sync_pt(fence);
	if (!pt)
		return -EINVAL;

	spin_lock_irqsave(fence->lock, flags);
	if (test_bit(SW_SYNC_HAS_DEADLINE_BIT, &fence->flags)) {
		data.deadline_ns = ktime_to_ns(pt->deadline);
	} else {
		ret = -ENOENT;
	}
	spin_unlock_irqrestore(fence->lock, flags);

	dma_fence_put(fence);

	if (ret)
		return ret;

	if (copy_to_user((void __user *)arg, &data, sizeof(data)))
		return -EFAULT;

	return 0;
}

static long sw_sync_ioctl(struct file *file, unsigned int cmd,
			  unsigned long arg)
{
@@ -399,6 +478,9 @@ static long sw_sync_ioctl(struct file *file, unsigned int cmd,
	case SW_SYNC_IOC_INC:
		return sw_sync_ioctl_inc(obj, arg);

	case SW_SYNC_GET_DEADLINE:
		return sw_sync_ioctl_get_deadline(obj, arg);

	default:
		return -ENOTTY;
	}
+2 −0
Original line number Diff line number Diff line
@@ -55,11 +55,13 @@ static inline struct sync_timeline *dma_fence_parent(struct dma_fence *fence)
 * @base: base fence object
 * @link: link on the sync timeline's list
 * @node: node in the sync timeline's tree
 * @deadline: the earliest fence deadline hint
 */
struct sync_pt {
	struct dma_fence base;
	struct list_head link;
	struct rb_node node;
	ktime_t deadline;
};

extern const struct file_operations sw_sync_debugfs_fops;