18e458fe2SChris Wilson /* SPDX-License-Identifier: MIT */
28e458fe2SChris Wilson 
38e458fe2SChris Wilson /*
48e458fe2SChris Wilson  * Copyright © 2019 Intel Corporation
58e458fe2SChris Wilson  */
68e458fe2SChris Wilson 
78e458fe2SChris Wilson #ifndef I915_SW_FENCE_WORK_H
88e458fe2SChris Wilson #define I915_SW_FENCE_WORK_H
98e458fe2SChris Wilson 
108e458fe2SChris Wilson #include <linux/dma-fence.h>
118e458fe2SChris Wilson #include <linux/spinlock.h>
128e458fe2SChris Wilson #include <linux/workqueue.h>
138e458fe2SChris Wilson 
148e458fe2SChris Wilson #include "i915_sw_fence.h"
158e458fe2SChris Wilson 
168e458fe2SChris Wilson struct dma_fence_work;
178e458fe2SChris Wilson 
188e458fe2SChris Wilson struct dma_fence_work_ops {
198e458fe2SChris Wilson 	const char *name;
20*dc194184SJason Ekstrand 	void (*work)(struct dma_fence_work *f);
218e458fe2SChris Wilson 	void (*release)(struct dma_fence_work *f);
228e458fe2SChris Wilson };
238e458fe2SChris Wilson 
248e458fe2SChris Wilson struct dma_fence_work {
258e458fe2SChris Wilson 	struct dma_fence dma;
268e458fe2SChris Wilson 	spinlock_t lock;
278e458fe2SChris Wilson 
288e458fe2SChris Wilson 	struct i915_sw_fence chain;
298e458fe2SChris Wilson 	struct i915_sw_dma_fence_cb cb;
308e458fe2SChris Wilson 
318e458fe2SChris Wilson 	struct work_struct work;
328e458fe2SChris Wilson 	const struct dma_fence_work_ops *ops;
338e458fe2SChris Wilson };
348e458fe2SChris Wilson 
3592581f9fSChris Wilson enum {
3692581f9fSChris Wilson 	DMA_FENCE_WORK_IMM = DMA_FENCE_FLAG_USER_BITS,
3792581f9fSChris Wilson };
3892581f9fSChris Wilson 
398e458fe2SChris Wilson void dma_fence_work_init(struct dma_fence_work *f,
408e458fe2SChris Wilson 			 const struct dma_fence_work_ops *ops);
418e458fe2SChris Wilson int dma_fence_work_chain(struct dma_fence_work *f, struct dma_fence *signal);
428e458fe2SChris Wilson 
dma_fence_work_commit(struct dma_fence_work * f)438e458fe2SChris Wilson static inline void dma_fence_work_commit(struct dma_fence_work *f)
448e458fe2SChris Wilson {
458e458fe2SChris Wilson 	i915_sw_fence_commit(&f->chain);
468e458fe2SChris Wilson }
478e458fe2SChris Wilson 
4892581f9fSChris Wilson /**
4992581f9fSChris Wilson  * dma_fence_work_commit_imm: Commit the fence, and if possible execute locally.
5092581f9fSChris Wilson  * @f: the fenced worker
5192581f9fSChris Wilson  *
5292581f9fSChris Wilson  * Instead of always scheduling a worker to execute the callback (see
5392581f9fSChris Wilson  * dma_fence_work_commit()), we try to execute the callback immediately in
5492581f9fSChris Wilson  * the local context. It is required that the fence be committed before it
5592581f9fSChris Wilson  * is published, and that no other threads try to tamper with the number
5692581f9fSChris Wilson  * of asynchronous waits on the fence (or else the callback will be
5792581f9fSChris Wilson  * executed in the wrong context, i.e. not the callers).
5892581f9fSChris Wilson  */
dma_fence_work_commit_imm(struct dma_fence_work * f)5992581f9fSChris Wilson static inline void dma_fence_work_commit_imm(struct dma_fence_work *f)
6092581f9fSChris Wilson {
6192581f9fSChris Wilson 	if (atomic_read(&f->chain.pending) <= 1)
6292581f9fSChris Wilson 		__set_bit(DMA_FENCE_WORK_IMM, &f->dma.flags);
6392581f9fSChris Wilson 
6492581f9fSChris Wilson 	dma_fence_work_commit(f);
6592581f9fSChris Wilson }
6692581f9fSChris Wilson 
678e458fe2SChris Wilson #endif /* I915_SW_FENCE_WORK_H */
68