* [Intel-gfx] [PATCH 12/28] drm/i915/gem: Build the reloc request first
From: Chris Wilson @ 2020-06-07 22:20 UTC (permalink / raw)
To: intel-gfx; +Cc: Chris Wilson
In-Reply-To: <20200607222108.14401-1-chris@chris-wilson.co.uk>
If we get interrupted in the middle of chaining up the relocation
entries, we will fail to submit the relocation batch. However, we will
report having already completed some of the relocations, and so the
reloc.presumed_offset will no longer match the batch contents, causing
confusion and invalid future batches. If we build the relocation request
packet first, we can always emit as far as we get up in the relocation
chain.
Fixes: 0e97fbb08055 ("drm/i915/gem: Use a single chained reloc batches for a single execbuf")
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
---
.../gpu/drm/i915/gem/i915_gem_execbuffer.c | 49 ++++++++++---------
.../i915/gem/selftests/i915_gem_execbuffer.c | 8 +--
2 files changed, 30 insertions(+), 27 deletions(-)
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c
index e012857be129..83cea2ea7c61 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c
@@ -1002,11 +1002,27 @@ static unsigned int reloc_bb_flags(const struct reloc_cache *cache)
return cache->gen > 5 ? 0 : I915_DISPATCH_SECURE;
}
-static int reloc_gpu_flush(struct reloc_cache *cache)
+static int reloc_gpu_emit(struct reloc_cache *cache)
{
struct i915_request *rq = cache->rq;
int err;
+ err = 0;
+ if (rq->engine->emit_init_breadcrumb)
+ err = rq->engine->emit_init_breadcrumb(rq);
+ if (!err)
+ err = rq->engine->emit_bb_start(rq,
+ rq->batch->node.start,
+ PAGE_SIZE,
+ reloc_bb_flags(cache));
+
+ return err;
+}
+
+static void reloc_gpu_flush(struct reloc_cache *cache)
+{
+ struct i915_request *rq = cache->rq;
+
if (cache->rq_vma) {
struct drm_i915_gem_object *obj = cache->rq_vma->obj;
@@ -1018,21 +1034,8 @@ static int reloc_gpu_flush(struct reloc_cache *cache)
i915_gem_object_unpin_map(obj);
}
- err = 0;
- if (rq->engine->emit_init_breadcrumb)
- err = rq->engine->emit_init_breadcrumb(rq);
- if (!err)
- err = rq->engine->emit_bb_start(rq,
- rq->batch->node.start,
- PAGE_SIZE,
- reloc_bb_flags(cache));
- if (err)
- i915_request_set_error_once(rq, err);
-
intel_gt_chipset_flush(rq->engine->gt);
i915_request_add(rq);
-
- return err;
}
static int reloc_move_to_gpu(struct i915_request *rq, struct i915_vma *vma)
@@ -1120,7 +1123,7 @@ __reloc_gpu_alloc(struct i915_execbuffer *eb, struct intel_engine_cs *engine)
err = i915_vma_move_to_active(batch, rq, 0);
i915_vma_unlock(batch);
if (err)
- goto skip_request;
+ goto err_request;
rq->batch = batch;
i915_vma_unpin(batch);
@@ -1133,8 +1136,6 @@ __reloc_gpu_alloc(struct i915_execbuffer *eb, struct intel_engine_cs *engine)
/* Return with batch mapping (cmd) still pinned */
goto out_pool;
-skip_request:
- i915_request_set_error_once(rq, err);
err_request:
i915_request_add(rq);
err_unpin:
@@ -1167,10 +1168,8 @@ static u32 *reloc_batch_grow(struct i915_execbuffer *eb,
if (unlikely(cache->rq_size + len >
PAGE_SIZE / sizeof(u32) - RELOC_TAIL)) {
err = reloc_gpu_chain(cache);
- if (unlikely(err)) {
- i915_request_set_error_once(cache->rq, err);
+ if (unlikely(err))
return ERR_PTR(err);
- }
}
GEM_BUG_ON(cache->rq_size + len >= PAGE_SIZE / sizeof(u32));
@@ -1493,13 +1492,17 @@ static int reloc_gpu_alloc(struct i915_execbuffer *eb)
static int reloc_gpu(struct i915_execbuffer *eb)
{
struct eb_vma *ev;
- int flush, err;
+ int err;
err = reloc_gpu_alloc(eb);
if (err)
return err;
GEM_BUG_ON(!eb->reloc_cache.rq);
+ err = reloc_gpu_emit(&eb->reloc_cache);
+ if (err)
+ goto out;
+
list_for_each_entry(ev, &eb->relocs, reloc_link) {
err = eb_reloc_vma(eb, ev, eb_reloc_entry);
if (err < 0)
@@ -1507,9 +1510,7 @@ static int reloc_gpu(struct i915_execbuffer *eb)
}
out:
- flush = reloc_gpu_flush(&eb->reloc_cache);
- if (!err)
- err = flush;
+ reloc_gpu_flush(&eb->reloc_cache);
return err;
}
diff --git a/drivers/gpu/drm/i915/gem/selftests/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/gem/selftests/i915_gem_execbuffer.c
index 50fe22d87ae1..faed6480a792 100644
--- a/drivers/gpu/drm/i915/gem/selftests/i915_gem_execbuffer.c
+++ b/drivers/gpu/drm/i915/gem/selftests/i915_gem_execbuffer.c
@@ -40,6 +40,10 @@ static int __igt_gpu_reloc(struct i915_execbuffer *eb,
if (err)
goto unpin_vma;
+ err = reloc_gpu_emit(&eb->reloc_cache);
+ if (err)
+ goto unpin_vma;
+
/* 8-Byte aligned */
err = __reloc_entry_gpu(eb, vma, offsets[0] * sizeof(u32), 0);
if (err)
@@ -64,9 +68,7 @@ static int __igt_gpu_reloc(struct i915_execbuffer *eb,
GEM_BUG_ON(!eb->reloc_cache.rq);
rq = i915_request_get(eb->reloc_cache.rq);
- err = reloc_gpu_flush(&eb->reloc_cache);
- if (err)
- goto put_rq;
+ reloc_gpu_flush(&eb->reloc_cache);
err = i915_gem_object_wait(obj, I915_WAIT_INTERRUPTIBLE, HZ / 2);
if (err) {
--
2.20.1
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx
^ permalink raw reply related
* [Intel-gfx] [PATCH 17/28] drm/i915/gem: Make relocations atomic within execbuf
From: Chris Wilson @ 2020-06-07 22:20 UTC (permalink / raw)
To: intel-gfx; +Cc: Chris Wilson
In-Reply-To: <20200607222108.14401-1-chris@chris-wilson.co.uk>
Although we may chide userspace for reusing the same batches
concurrently from multiple threads, at the same time we must be very
careful to only execute the batch and its relocations as supplied by the
user. If we are not careful, we may allow another thread to rewrite the
current batch with its own relocations. We must order the relocations
and their batch such that they are an atomic pair on the GPU, and that
the ioctl itself appears atomic to userspace. The order of execution may
be undetermined, but it will not be subverted.
We could do this by moving the relocations into the main request, if it
were not for the situation where we need a second engine to perform the
relocations for us. Instead, we use the dependency tracking to only
publish the write fence on the main request and not on the relocation
request, so that concurrent updates are queued after the batch has
consumed its relocations.
Testcase: igt/gem_exec_reloc/basic-concurrent
Fixes: ef398881d27d ("drm/i915/gem: Limit struct_mutex to eb_reserve")
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
---
.../gpu/drm/i915/gem/i915_gem_execbuffer.c | 92 ++++++++++++++-----
.../i915/gem/selftests/i915_gem_execbuffer.c | 11 ++-
2 files changed, 73 insertions(+), 30 deletions(-)
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c
index 8f3c1cf5af31..4a50371fe6e5 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c
@@ -5,6 +5,7 @@
*/
#include <linux/intel-iommu.h>
+#include <linux/dma-fence-proxy.h>
#include <linux/dma-resv.h>
#include <linux/sync_file.h>
#include <linux/uaccess.h>
@@ -259,6 +260,8 @@ struct i915_execbuffer {
bool has_fence : 1;
bool needs_unfenced : 1;
+ struct dma_fence *fence;
+
struct i915_request *rq;
struct i915_vma *rq_vma;
u32 *rq_cmd;
@@ -555,16 +558,6 @@ eb_add_vma(struct i915_execbuffer *eb,
ev->exec = entry;
ev->flags = entry->flags;
- if (eb->lut_size > 0) {
- ev->handle = entry->handle;
- hlist_add_head(&ev->node,
- &eb->buckets[hash_32(entry->handle,
- eb->lut_size)]);
- }
-
- if (entry->relocation_count)
- list_add_tail(&ev->reloc_link, &eb->relocs);
-
/*
* SNA is doing fancy tricks with compressing batch buffers, which leads
* to negative relocation deltas. Usually that works out ok since the
@@ -581,9 +574,21 @@ eb_add_vma(struct i915_execbuffer *eb,
if (eb->reloc_cache.has_fence)
ev->flags |= EXEC_OBJECT_NEEDS_FENCE;
+ INIT_LIST_HEAD(&ev->reloc_link);
+
eb->batch = ev;
}
+ if (entry->relocation_count)
+ list_add_tail(&ev->reloc_link, &eb->relocs);
+
+ if (eb->lut_size > 0) {
+ ev->handle = entry->handle;
+ hlist_add_head(&ev->node,
+ &eb->buckets[hash_32(entry->handle,
+ eb->lut_size)]);
+ }
+
if (eb_pin_vma(eb, entry, ev)) {
if (entry->offset != vma->node.start) {
entry->offset = vma->node.start | UPDATE;
@@ -923,6 +928,7 @@ static void reloc_cache_init(struct reloc_cache *cache,
cache->has_fence = cache->gen < 4;
cache->needs_unfenced = INTEL_INFO(i915)->unfenced_needs_alignment;
cache->node.flags = 0;
+ cache->fence = NULL;
}
#define RELOC_TAIL 4
@@ -1033,6 +1039,7 @@ static void reloc_gpu_flush(struct reloc_cache *cache)
}
intel_gt_chipset_flush(rq->engine->gt);
+ i915_request_get(rq);
i915_request_add(rq);
}
@@ -1338,16 +1345,6 @@ eb_reloc_entry(struct i915_execbuffer *eb,
if (offset == reloc->presumed_offset)
return 0;
- /*
- * If we write into the object, we need to force the synchronisation
- * barrier, either with an asynchronous clflush or if we executed the
- * patching using the GPU (though that should be serialised by the
- * timeline). To be completely sure, and since we are required to
- * do relocations we are already stalling, disable the user's opt
- * out of our synchronisation.
- */
- ev->flags &= ~EXEC_OBJECT_ASYNC;
-
err = __reloc_entry_gpu(eb, ev->vma, reloc->offset,
relocation_target(reloc, offset));
if (err)
@@ -1449,6 +1446,11 @@ static int reloc_move_to_gpu(struct reloc_cache *cache, struct eb_vma *ev)
obj->write_domain = I915_GEM_DOMAIN_RENDER;
obj->read_domains = I915_GEM_DOMAIN_RENDER;
+ ev->flags |= EXEC_OBJECT_ASYNC;
+
+ err = dma_resv_reserve_shared(vma->resv, 1);
+ if (err)
+ return err;
err = i915_request_await_object(rq, obj, true);
if (err)
@@ -1459,6 +1461,7 @@ static int reloc_move_to_gpu(struct reloc_cache *cache, struct eb_vma *ev)
return err;
dma_resv_add_excl_fence(vma->resv, &rq->fence);
+ dma_resv_add_shared_fence(vma->resv, cache->fence);
return 0;
}
@@ -1527,14 +1530,28 @@ static int reloc_gpu_alloc(struct i915_execbuffer *eb)
return __reloc_gpu_alloc(eb, engine);
}
+static void free_reloc_fence(struct i915_execbuffer *eb)
+{
+ struct dma_fence *f = fetch_and_zero(&eb->reloc_cache.fence);
+
+ dma_fence_signal(f);
+ dma_fence_put(f);
+}
+
static int reloc_gpu(struct i915_execbuffer *eb)
{
struct eb_vma *ev;
int err;
+ eb->reloc_cache.fence = __dma_fence_create_proxy(0, 0);
+ if (!eb->reloc_cache.fence)
+ return -ENOMEM;
+
err = reloc_gpu_alloc(eb);
- if (err)
+ if (err) {
+ free_reloc_fence(eb);
return err;
+ }
GEM_BUG_ON(!eb->reloc_cache.rq);
err = lock_relocs(eb);
@@ -1593,6 +1610,15 @@ static int eb_relocate(struct i915_execbuffer *eb)
return 0;
}
+static void eb_reloc_signal(struct i915_execbuffer *eb, struct i915_request *rq)
+{
+ dma_fence_proxy_set_real(eb->reloc_cache.fence, &rq->fence);
+ i915_request_put(eb->reloc_cache.rq);
+
+ dma_fence_put(eb->reloc_cache.fence);
+ eb->reloc_cache.fence = NULL;
+}
+
static int eb_move_to_gpu(struct i915_execbuffer *eb)
{
const unsigned int count = eb->buffer_count;
@@ -1873,10 +1899,15 @@ static int eb_parse_pipeline(struct i915_execbuffer *eb,
if (err)
goto err_commit_unlock;
- /* Wait for all writes (and relocs) into the batch to complete */
- err = i915_sw_fence_await_reservation(&pw->base.chain,
- pw->batch->resv, NULL, false,
- 0, I915_FENCE_GFP);
+ /* Wait for all writes (or relocs) into the batch to complete */
+ if (!eb->reloc_cache.fence || list_empty(&eb->batch->reloc_link))
+ err = i915_sw_fence_await_reservation(&pw->base.chain,
+ pw->batch->resv, NULL,
+ false, 0, I915_FENCE_GFP);
+ else
+ err = i915_sw_fence_await_dma_fence(&pw->base.chain,
+ &eb->reloc_cache.rq->fence,
+ 0, I915_FENCE_GFP);
if (err < 0)
goto err_commit_unlock;
@@ -2004,6 +2035,15 @@ static int eb_submit(struct i915_execbuffer *eb, struct i915_vma *batch)
{
int err;
+ if (eb->reloc_cache.fence) {
+ err = i915_request_await_dma_fence(eb->request,
+ &eb->reloc_cache.rq->fence);
+ if (err)
+ return err;
+
+ eb_reloc_signal(eb, eb->request);
+ }
+
err = eb_move_to_gpu(eb);
if (err)
return err;
@@ -2663,6 +2703,8 @@ i915_gem_do_execbuffer(struct drm_device *dev,
if (batch->private)
intel_gt_buffer_pool_put(batch->private);
err_vma:
+ if (eb.reloc_cache.fence)
+ eb_reloc_signal(&eb, eb.reloc_cache.rq);
if (eb.trampoline)
i915_vma_unpin(eb.trampoline);
eb_unpin_engine(&eb);
diff --git a/drivers/gpu/drm/i915/gem/selftests/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/gem/selftests/i915_gem_execbuffer.c
index 4f10b51f9a7e..62bba179b455 100644
--- a/drivers/gpu/drm/i915/gem/selftests/i915_gem_execbuffer.c
+++ b/drivers/gpu/drm/i915/gem/selftests/i915_gem_execbuffer.c
@@ -23,7 +23,6 @@ static int __igt_gpu_reloc(struct i915_execbuffer *eb,
const u64 mask =
GENMASK_ULL(eb->reloc_cache.use_64bit_reloc ? 63 : 31, 0);
const u32 *map = page_mask_bits(obj->mm.mapping);
- struct i915_request *rq;
struct eb_vma ev;
int err;
int i;
@@ -40,6 +39,9 @@ static int __igt_gpu_reloc(struct i915_execbuffer *eb,
if (err)
goto unpin_vma;
+ /* Single stage pipeline in the selftest */
+ eb->reloc_cache.fence = &eb->reloc_cache.rq->fence;
+
list_add(&ev.reloc_link, &eb->relocs);
err = lock_relocs(eb);
if (err)
@@ -71,8 +73,6 @@ static int __igt_gpu_reloc(struct i915_execbuffer *eb,
if (err)
goto unpin_vma;
- GEM_BUG_ON(!eb->reloc_cache.rq);
- rq = i915_request_get(eb->reloc_cache.rq);
reloc_gpu_flush(&eb->reloc_cache);
err = i915_gem_object_wait(obj, I915_WAIT_INTERRUPTIBLE, HZ / 2);
@@ -81,7 +81,7 @@ static int __igt_gpu_reloc(struct i915_execbuffer *eb,
goto put_rq;
}
- if (!i915_request_completed(rq)) {
+ if (!i915_request_completed(eb->reloc_cache.rq)) {
pr_err("%s: did not wait for relocations!\n", eb->engine->name);
err = -EINVAL;
goto put_rq;
@@ -100,7 +100,8 @@ static int __igt_gpu_reloc(struct i915_execbuffer *eb,
igt_hexdump(map, 4096);
put_rq:
- i915_request_put(rq);
+ i915_request_put(eb->reloc_cache.rq);
+ eb->reloc_cache.rq = NULL;
unpin_vma:
i915_vma_unpin(ev.vma);
return err;
--
2.20.1
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx
^ permalink raw reply related
* [Intel-gfx] [PATCH 28/28] drm/i915: Replace the priority boosting for the display with a deadline
From: Chris Wilson @ 2020-06-07 22:21 UTC (permalink / raw)
To: intel-gfx; +Cc: Chris Wilson
In-Reply-To: <20200607222108.14401-1-chris@chris-wilson.co.uk>
For a modeset/pageflip, there is a very precise deadline by which the
frame must be completed in order to hit the vblank and be shown. While
we don't pass along that exact information, we can at least inform the
scheduler that this request-chain needs to be completed asap.
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
---
drivers/gpu/drm/i915/display/intel_display.c | 2 +-
drivers/gpu/drm/i915/gem/i915_gem_object.h | 4 ++--
drivers/gpu/drm/i915/gem/i915_gem_wait.c | 21 ++++++++++----------
drivers/gpu/drm/i915/i915_priolist_types.h | 3 ---
4 files changed, 14 insertions(+), 16 deletions(-)
diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c
index 797e3573d392..5bb20f701a44 100644
--- a/drivers/gpu/drm/i915/display/intel_display.c
+++ b/drivers/gpu/drm/i915/display/intel_display.c
@@ -15964,7 +15964,7 @@ intel_prepare_plane_fb(struct drm_plane *_plane,
if (ret)
return ret;
- i915_gem_object_wait_priority(obj, 0, I915_PRIORITY_DISPLAY);
+ i915_gem_object_wait_deadline(obj, 0, ktime_get() /* next vblank? */);
i915_gem_object_flush_frontbuffer(obj, ORIGIN_DIRTYFB);
if (!new_plane_state->uapi.fence) { /* implicit fencing */
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_object.h b/drivers/gpu/drm/i915/gem/i915_gem_object.h
index 876c34982555..7bcd2661de4c 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_object.h
+++ b/drivers/gpu/drm/i915/gem/i915_gem_object.h
@@ -474,9 +474,9 @@ static inline void __start_cpu_write(struct drm_i915_gem_object *obj)
int i915_gem_object_wait(struct drm_i915_gem_object *obj,
unsigned int flags,
long timeout);
-int i915_gem_object_wait_priority(struct drm_i915_gem_object *obj,
+int i915_gem_object_wait_deadline(struct drm_i915_gem_object *obj,
unsigned int flags,
- int prio);
+ ktime_t deadline);
void __i915_gem_object_flush_frontbuffer(struct drm_i915_gem_object *obj,
enum fb_op_origin origin);
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_wait.c b/drivers/gpu/drm/i915/gem/i915_gem_wait.c
index cefbbb3d9b52..5224d4363ea3 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_wait.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_wait.c
@@ -93,17 +93,18 @@ i915_gem_object_wait_reservation(struct dma_resv *resv,
return timeout;
}
-static void __fence_set_priority(struct dma_fence *fence, int prio)
+static void __fence_set_deadline(struct dma_fence *fence, ktime_t deadline)
{
if (dma_fence_is_signaled(fence) || !dma_fence_is_i915(fence))
return;
local_bh_disable();
- i915_request_set_priority(to_request(fence), prio);
+ i915_request_set_deadline(to_request(fence),
+ i915_sched_to_ticks(deadline));
local_bh_enable(); /* kick the tasklets if queues were reprioritised */
}
-static void fence_set_priority(struct dma_fence *fence, int prio)
+static void fence_set_deadline(struct dma_fence *fence, ktime_t deadline)
{
/* Recurse once into a fence-array */
if (dma_fence_is_array(fence)) {
@@ -111,16 +112,16 @@ static void fence_set_priority(struct dma_fence *fence, int prio)
int i;
for (i = 0; i < array->num_fences; i++)
- __fence_set_priority(array->fences[i], prio);
+ __fence_set_deadline(array->fences[i], deadline);
} else {
- __fence_set_priority(fence, prio);
+ __fence_set_deadline(fence, deadline);
}
}
int
-i915_gem_object_wait_priority(struct drm_i915_gem_object *obj,
+i915_gem_object_wait_deadline(struct drm_i915_gem_object *obj,
unsigned int flags,
- int prio)
+ ktime_t deadline)
{
struct dma_fence *excl;
@@ -130,12 +131,12 @@ i915_gem_object_wait_priority(struct drm_i915_gem_object *obj,
int ret;
ret = dma_resv_get_fences_rcu(obj->base.resv,
- &excl, &count, &shared);
+ &excl, &count, &shared);
if (ret)
return ret;
for (i = 0; i < count; i++) {
- fence_set_priority(shared[i], prio);
+ fence_set_deadline(shared[i], deadline);
dma_fence_put(shared[i]);
}
@@ -145,7 +146,7 @@ i915_gem_object_wait_priority(struct drm_i915_gem_object *obj,
}
if (excl) {
- fence_set_priority(excl, prio);
+ fence_set_deadline(excl, deadline);
dma_fence_put(excl);
}
return 0;
diff --git a/drivers/gpu/drm/i915/i915_priolist_types.h b/drivers/gpu/drm/i915/i915_priolist_types.h
index 43a0ac45295f..ac6d9614ea23 100644
--- a/drivers/gpu/drm/i915/i915_priolist_types.h
+++ b/drivers/gpu/drm/i915/i915_priolist_types.h
@@ -20,9 +20,6 @@ enum {
/* A preemptive pulse used to monitor the health of each engine */
I915_PRIORITY_HEARTBEAT,
- /* Interactive workload, scheduled for immediate pageflipping */
- I915_PRIORITY_DISPLAY,
-
__I915_PRIORITY_KERNEL__
};
--
2.20.1
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx
^ permalink raw reply related
* [Intel-gfx] [PATCH 16/28] drm/i915: Unpeel awaits on a proxy fence
From: Chris Wilson @ 2020-06-07 22:20 UTC (permalink / raw)
To: intel-gfx; +Cc: Chris Wilson
In-Reply-To: <20200607222108.14401-1-chris@chris-wilson.co.uk>
If the real target for a proxy fence is known at the time we are
attaching our awaits, use the real target in preference to hooking up to
the proxy. If use the real target instead, we can optimize the awaits,
e.g. if it along the same engine, we can order the submission and avoid
the wait-for-completion.
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
---
drivers/gpu/drm/i915/i915_request.c | 155 ++++++++++++++++++++++++++
drivers/gpu/drm/i915/i915_scheduler.c | 41 +++++++
drivers/gpu/drm/i915/i915_scheduler.h | 3 +
3 files changed, 199 insertions(+)
diff --git a/drivers/gpu/drm/i915/i915_request.c b/drivers/gpu/drm/i915/i915_request.c
index 3bb7320249ae..f04f91b4d879 100644
--- a/drivers/gpu/drm/i915/i915_request.c
+++ b/drivers/gpu/drm/i915/i915_request.c
@@ -24,6 +24,7 @@
#include <linux/dma-fence-array.h>
#include <linux/dma-fence-chain.h>
+#include <linux/dma-fence-proxy.h>
#include <linux/irq_work.h>
#include <linux/prefetch.h>
#include <linux/sched.h>
@@ -461,6 +462,7 @@ static bool fatal_error(int error)
case 0: /* not an error! */
case -EAGAIN: /* innocent victim of a GT reset (__i915_request_reset) */
case -ETIMEDOUT: /* waiting for Godot (timer_i915_sw_fence_wake) */
+ case -EDEADLK: /* cyclic fence lockup (await_proxy) */
return false;
default:
return true;
@@ -1241,6 +1243,136 @@ i915_request_await_external(struct i915_request *rq, struct dma_fence *fence)
return err;
}
+struct await_proxy {
+ struct wait_queue_entry base;
+ struct i915_request *request;
+ struct dma_fence *fence;
+ struct timer_list timer;
+ struct work_struct work;
+ int (*attach)(struct await_proxy *ap);
+ void *data;
+};
+
+static void await_proxy_work(struct work_struct *work)
+{
+ struct await_proxy *ap = container_of(work, typeof(*ap), work);
+ struct i915_request *rq = ap->request;
+
+ del_timer_sync(&ap->timer);
+
+ if (ap->fence) {
+ int err = 0;
+
+ /*
+ * If the fence is external, we impose a 10s timeout.
+ * However, if the fence is internal, we skip a timeout in
+ * the belief that all fences are in-order (DAG, no cycles)
+ * and we can enforce forward progress by reset the GPU if
+ * necessary. A future fence, provided userspace, can trivially
+ * generate a cycle in the dependency graph, and so cause
+ * that entire cycle to become deadlocked and for no forward
+ * progress to either be made, and the driver being kept
+ * eternally awake.
+ */
+ if (dma_fence_is_i915(ap->fence) &&
+ !i915_sched_node_verify_dag(&rq->sched,
+ &to_request(ap->fence)->sched))
+ err = -EDEADLK;
+
+ if (!err) {
+ mutex_lock(&rq->context->timeline->mutex);
+ err = ap->attach(ap);
+ mutex_unlock(&rq->context->timeline->mutex);
+ }
+
+ /* Don't flag an error for co-dependent scheduling */
+ if (err == -EDEADLK) {
+ struct i915_sched_node *waiter =
+ &to_request(ap->fence)->sched;
+ struct i915_dependency *p;
+
+ for_each_waiter(p, rq) {
+ if (p->waiter == waiter &&
+ p->flags & I915_DEPENDENCY_WEAK) {
+ err = 0;
+ break;
+ }
+ }
+ }
+
+ if (err < 0)
+ i915_sw_fence_set_error_once(&rq->submit, err);
+ }
+
+ i915_sw_fence_complete(&rq->submit);
+
+ dma_fence_put(ap->fence);
+ kfree(ap);
+}
+
+static int
+await_proxy_wake(struct wait_queue_entry *entry,
+ unsigned int mode,
+ int flags,
+ void *fence)
+{
+ struct await_proxy *ap = container_of(entry, typeof(*ap), base);
+
+ ap->fence = dma_fence_get(fence);
+ schedule_work(&ap->work);
+
+ return 0;
+}
+
+static void
+await_proxy_timer(struct timer_list *t)
+{
+ struct await_proxy *ap = container_of(t, typeof(*ap), timer);
+
+ if (dma_fence_remove_proxy_listener(ap->base.private, &ap->base)) {
+ struct i915_request *rq = ap->request;
+
+ pr_notice("Asynchronous wait on unset proxy fence by %s:%s:%llx timed out\n",
+ rq->fence.ops->get_driver_name(&rq->fence),
+ rq->fence.ops->get_timeline_name(&rq->fence),
+ rq->fence.seqno);
+ i915_sw_fence_set_error_once(&rq->submit, -ETIMEDOUT);
+
+ schedule_work(&ap->work);
+ }
+}
+
+static int
+__i915_request_await_proxy(struct i915_request *rq,
+ struct dma_fence *fence,
+ unsigned long timeout,
+ int (*attach)(struct await_proxy *ap),
+ void *data)
+{
+ struct await_proxy *ap;
+
+ ap = kzalloc(sizeof(*ap), I915_FENCE_GFP);
+ if (!ap)
+ return -ENOMEM;
+
+ i915_sw_fence_await(&rq->submit);
+ mark_external(rq);
+
+ ap->base.private = fence;
+ ap->base.func = await_proxy_wake;
+ ap->request = rq;
+ INIT_WORK(&ap->work, await_proxy_work);
+ ap->attach = attach;
+ ap->data = data;
+
+ timer_setup(&ap->timer, await_proxy_timer, 0);
+ if (timeout)
+ mod_timer(&ap->timer, round_jiffies_up(jiffies + timeout));
+
+ dma_fence_add_proxy_listener(fence, &ap->base);
+ return 0;
+}
+
int
i915_request_await_execution(struct i915_request *rq,
struct dma_fence *fence,
@@ -1339,6 +1471,24 @@ i915_request_await_request(struct i915_request *to, struct i915_request *from)
return 0;
}
+static int await_proxy(struct await_proxy *ap)
+{
+ return i915_request_await_dma_fence(ap->request, ap->fence);
+}
+
+static int
+i915_request_await_proxy(struct i915_request *rq, struct dma_fence *fence)
+{
+ /*
+ * Wait until we know the real fence so that can optimise the
+ * inter-fence synchronisation.
+ */
+ return __i915_request_await_proxy(rq, fence,
+ i915_fence_context_timeout(rq->engine->i915,
+ fence->context),
+ await_proxy, NULL);
+}
+
int
i915_request_await_dma_fence(struct i915_request *rq, struct dma_fence *fence)
{
@@ -1346,6 +1496,9 @@ i915_request_await_dma_fence(struct i915_request *rq, struct dma_fence *fence)
unsigned int nchild = 1;
int ret;
+ /* Unpeel the proxy fence if the real target is already known */
+ fence = dma_fence_proxy_get_real(fence);
+
/*
* Note that if the fence-array was created in signal-on-any mode,
* we should *not* decompose it into its individual fences. However,
@@ -1385,6 +1538,8 @@ i915_request_await_dma_fence(struct i915_request *rq, struct dma_fence *fence)
if (dma_fence_is_i915(fence))
ret = i915_request_await_request(rq, to_request(fence));
+ else if (dma_fence_is_proxy(fence))
+ ret = i915_request_await_proxy(rq, fence);
else
ret = i915_request_await_external(rq, fence);
if (ret < 0)
diff --git a/drivers/gpu/drm/i915/i915_scheduler.c b/drivers/gpu/drm/i915/i915_scheduler.c
index cbb880b10c65..250832768279 100644
--- a/drivers/gpu/drm/i915/i915_scheduler.c
+++ b/drivers/gpu/drm/i915/i915_scheduler.c
@@ -469,6 +469,47 @@ int i915_sched_node_add_dependency(struct i915_sched_node *node,
return 0;
}
+bool i915_sched_node_verify_dag(struct i915_sched_node *waiter,
+ struct i915_sched_node *signaler)
+{
+ struct i915_dependency *dep, *p;
+ struct i915_dependency stack;
+ bool result = false;
+ LIST_HEAD(dfs);
+
+ if (list_empty(&waiter->waiters_list))
+ return true;
+
+ spin_lock_irq(&schedule_lock);
+
+ stack.signaler = signaler;
+ list_add(&stack.dfs_link, &dfs);
+
+ list_for_each_entry(dep, &dfs, dfs_link) {
+ struct i915_sched_node *node = dep->signaler;
+
+ if (node_signaled(node))
+ continue;
+
+ list_for_each_entry(p, &node->signalers_list, signal_link) {
+ if (p->signaler == waiter)
+ goto out;
+
+ if (list_empty(&p->dfs_link))
+ list_add_tail(&p->dfs_link, &dfs);
+ }
+ }
+
+ result = true;
+out:
+ list_for_each_entry_safe(dep, p, &dfs, dfs_link)
+ INIT_LIST_HEAD(&dep->dfs_link);
+
+ spin_unlock_irq(&schedule_lock);
+
+ return result;
+}
+
void i915_sched_node_fini(struct i915_sched_node *node)
{
struct i915_dependency *dep, *tmp;
diff --git a/drivers/gpu/drm/i915/i915_scheduler.h b/drivers/gpu/drm/i915/i915_scheduler.h
index 6f0bf00fc569..13432add8929 100644
--- a/drivers/gpu/drm/i915/i915_scheduler.h
+++ b/drivers/gpu/drm/i915/i915_scheduler.h
@@ -28,6 +28,9 @@
void i915_sched_node_init(struct i915_sched_node *node);
void i915_sched_node_reinit(struct i915_sched_node *node);
+bool i915_sched_node_verify_dag(struct i915_sched_node *waiter,
+ struct i915_sched_node *signal);
+
bool __i915_sched_node_add_dependency(struct i915_sched_node *node,
struct i915_sched_node *signal,
struct i915_dependency *dep,
--
2.20.1
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx
^ permalink raw reply related
* [Intel-gfx] [PATCH 14/28] dma-buf: Proxy fence, an unsignaled fence placeholder
From: Chris Wilson @ 2020-06-07 22:20 UTC (permalink / raw)
To: intel-gfx; +Cc: Chris Wilson
In-Reply-To: <20200607222108.14401-1-chris@chris-wilson.co.uk>
Often we need to create a fence for a future event that has not yet been
associated with a fence. We can store a proxy fence, a placeholder, in
the timeline and replace it later when the real fence is known. Any
listeners that attach to the proxy fence will automatically be signaled
when the real fence completes, and any future listeners will instead be
attach directly to the real fence avoiding any indirection overhead.
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Cc: Lionel Landwerlin <lionel.g.landwerlin@intel.com>
---
drivers/dma-buf/Makefile | 13 +-
drivers/dma-buf/dma-fence-private.h | 20 +
drivers/dma-buf/dma-fence-proxy.c | 306 +++++++++++
drivers/dma-buf/dma-fence.c | 4 +-
drivers/dma-buf/selftests.h | 1 +
drivers/dma-buf/st-dma-fence-proxy.c | 752 +++++++++++++++++++++++++++
include/linux/dma-fence-proxy.h | 38 ++
7 files changed, 1130 insertions(+), 4 deletions(-)
create mode 100644 drivers/dma-buf/dma-fence-private.h
create mode 100644 drivers/dma-buf/dma-fence-proxy.c
create mode 100644 drivers/dma-buf/st-dma-fence-proxy.c
create mode 100644 include/linux/dma-fence-proxy.h
diff --git a/drivers/dma-buf/Makefile b/drivers/dma-buf/Makefile
index 995e05f609ff..afaf6dadd9a3 100644
--- a/drivers/dma-buf/Makefile
+++ b/drivers/dma-buf/Makefile
@@ -1,6 +1,12 @@
# SPDX-License-Identifier: GPL-2.0-only
-obj-y := dma-buf.o dma-fence.o dma-fence-array.o dma-fence-chain.o \
- dma-resv.o seqno-fence.o
+obj-y := \
+ dma-buf.o \
+ dma-fence.o \
+ dma-fence-array.o \
+ dma-fence-chain.o \
+ dma-fence-proxy.o \
+ dma-resv.o \
+ seqno-fence.o
obj-$(CONFIG_DMABUF_HEAPS) += dma-heap.o
obj-$(CONFIG_DMABUF_HEAPS) += heaps/
obj-$(CONFIG_SYNC_FILE) += sync_file.o
@@ -10,6 +16,7 @@ obj-$(CONFIG_UDMABUF) += udmabuf.o
dmabuf_selftests-y := \
selftest.o \
st-dma-fence.o \
- st-dma-fence-chain.o
+ st-dma-fence-chain.o \
+ st-dma-fence-proxy.o
obj-$(CONFIG_DMABUF_SELFTESTS) += dmabuf_selftests.o
diff --git a/drivers/dma-buf/dma-fence-private.h b/drivers/dma-buf/dma-fence-private.h
new file mode 100644
index 000000000000..6924d28af0fa
--- /dev/null
+++ b/drivers/dma-buf/dma-fence-private.h
@@ -0,0 +1,20 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Fence mechanism for dma-buf and to allow for asynchronous dma access
+ *
+ * Copyright (C) 2012 Canonical Ltd
+ * Copyright (C) 2012 Texas Instruments
+ *
+ * Authors:
+ * Rob Clark <robdclark@gmail.com>
+ * Maarten Lankhorst <maarten.lankhorst@canonical.com>
+ */
+
+#ifndef DMA_FENCE_PRIVATE_H
+#define DMA_FENCE_PRIAVTE_H
+
+struct dma_fence;
+
+bool __dma_fence_enable_signaling(struct dma_fence *fence);
+
+#endif /* DMA_FENCE_PRIAVTE_H */
diff --git a/drivers/dma-buf/dma-fence-proxy.c b/drivers/dma-buf/dma-fence-proxy.c
new file mode 100644
index 000000000000..42674e92b0f9
--- /dev/null
+++ b/drivers/dma-buf/dma-fence-proxy.c
@@ -0,0 +1,306 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * dma-fence-proxy: placeholder unsignaled fence
+ *
+ * Copyright (C) 2017-2019 Intel Corporation
+ */
+
+#include <linux/dma-fence.h>
+#include <linux/dma-fence-proxy.h>
+#include <linux/export.h>
+#include <linux/irq_work.h>
+#include <linux/slab.h>
+
+#include "dma-fence-private.h"
+
+struct dma_fence_proxy {
+ struct dma_fence base;
+
+ struct dma_fence *real;
+ struct dma_fence_cb cb;
+ struct irq_work work;
+
+ wait_queue_head_t wq;
+};
+
+#ifdef CONFIG_DEBUG_LOCK_ALLOC
+#define same_lockclass(A, B) (A)->dep_map.key == (B)->dep_map.key
+#else
+#define same_lockclass(A, B) 0
+#endif
+
+static const char *proxy_get_driver_name(struct dma_fence *fence)
+{
+ struct dma_fence_proxy *p = container_of(fence, typeof(*p), base);
+ struct dma_fence *real = READ_ONCE(p->real);
+
+ return real ? real->ops->get_driver_name(real) : "proxy";
+}
+
+static const char *proxy_get_timeline_name(struct dma_fence *fence)
+{
+ struct dma_fence_proxy *p = container_of(fence, typeof(*p), base);
+ struct dma_fence *real = READ_ONCE(p->real);
+
+ return real ? real->ops->get_timeline_name(real) : "unset";
+}
+
+static void proxy_irq_work(struct irq_work *work)
+{
+ struct dma_fence_proxy *p = container_of(work, typeof(*p), work);
+
+ dma_fence_signal(&p->base);
+ dma_fence_put(&p->base);
+}
+
+static void proxy_callback(struct dma_fence *real, struct dma_fence_cb *cb)
+{
+ struct dma_fence_proxy *p = container_of(cb, typeof(*p), cb);
+
+ /* Signaled before enabling signalling callbacks? */
+ if (test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &p->base.flags)) {
+ dma_fence_put(&p->base);
+ return;
+ }
+
+ if (real->error)
+ dma_fence_set_error(&p->base, real->error);
+
+ /* Lower the height of the proxy chain -> single stack frame */
+ irq_work_queue(&p->work);
+}
+
+static bool proxy_enable_signaling(struct dma_fence *fence)
+{
+ struct dma_fence_proxy *p = container_of(fence, typeof(*p), base);
+ struct dma_fence *real = READ_ONCE(p->real);
+ bool ret = true;
+
+ if (real) {
+ spin_lock_nested(real->lock,
+ same_lockclass(&p->wq.lock, real->lock));
+ ret = __dma_fence_enable_signaling(real);
+ if (!ret && real->error)
+ dma_fence_set_error(&p->base, real->error);
+ spin_unlock(real->lock);
+ }
+
+ return ret;
+}
+
+static void proxy_release(struct dma_fence *fence)
+{
+ struct dma_fence_proxy *p = container_of(fence, typeof(*p), base);
+
+ dma_fence_put(p->real);
+ dma_fence_free(&p->base);
+}
+
+const struct dma_fence_ops dma_fence_proxy_ops = {
+ .get_driver_name = proxy_get_driver_name,
+ .get_timeline_name = proxy_get_timeline_name,
+ .enable_signaling = proxy_enable_signaling,
+ .wait = dma_fence_default_wait,
+ .release = proxy_release,
+};
+EXPORT_SYMBOL_GPL(dma_fence_proxy_ops);
+
+/**
+ * __dma_fence_create_proxy - Create an unset dma-fence
+ * @context: context number to use for proxy fence
+ * @seqno: sequence number to use for proxy fence
+ *
+ * __dma_fence_create_proxy() creates a new dma_fence stub that is initially
+ * unsignaled and may later be replaced with a real fence. Any listeners
+ * to the proxy fence will be signaled when the target fence signals its
+ * completion.
+ */
+struct dma_fence *__dma_fence_create_proxy(u64 context, u64 seqno)
+{
+ struct dma_fence_proxy *p;
+
+ p = kzalloc(sizeof(*p), GFP_KERNEL);
+ if (!p)
+ return NULL;
+
+ init_waitqueue_head(&p->wq);
+ dma_fence_init(&p->base, &dma_fence_proxy_ops, &p->wq.lock,
+ context, seqno);
+ init_irq_work(&p->work, proxy_irq_work);
+
+ return &p->base;
+}
+EXPORT_SYMBOL(__dma_fence_create_proxy);
+
+/**
+ * dma_fence_create_proxy - Create an unset dma-fence
+ *
+ * Wraps __dma_fence_create_proxy() to create a new proxy fence with the
+ * next available (unique) context id.
+ */
+struct dma_fence *dma_fence_create_proxy(void)
+{
+ return __dma_fence_create_proxy(dma_fence_context_alloc(1), 0);
+}
+EXPORT_SYMBOL(dma_fence_create_proxy);
+
+static void __wake_up_listeners(struct dma_fence_proxy *p)
+{
+ struct wait_queue_entry *wait, *next;
+
+ list_for_each_entry_safe(wait, next, &p->wq.head, entry) {
+ INIT_LIST_HEAD(&wait->entry);
+ wait->func(wait, TASK_NORMAL, 0, p->real);
+ }
+}
+
+static void set_proxy_callback(struct dma_fence *real, struct dma_fence_cb *cb)
+{
+ cb->func = proxy_callback;
+ list_add_tail(&cb->node, &real->cb_list);
+}
+
+static void proxy_assign(struct dma_fence *fence, struct dma_fence *real)
+{
+ struct dma_fence_proxy *p = container_of(fence, typeof(*p), base);
+ unsigned long flags;
+
+ if (WARN_ON(fence == real))
+ return;
+
+ if (WARN_ON(test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &fence->flags)))
+ return;
+
+ if (WARN_ON(p->real))
+ return;
+
+ spin_lock_irqsave(&p->wq.lock, flags);
+
+ if (unlikely(!real)) {
+ dma_fence_signal_locked(&p->base);
+ goto unlock;
+ }
+
+ p->real = dma_fence_get(real);
+
+ dma_fence_get(&p->base);
+ spin_lock_nested(real->lock, same_lockclass(&p->wq.lock, real->lock));
+ if (dma_fence_is_signaled_locked(real))
+ proxy_callback(real, &p->cb);
+ else if (test_bit(DMA_FENCE_FLAG_ENABLE_SIGNAL_BIT, &p->base.flags) &&
+ !__dma_fence_enable_signaling(real))
+ proxy_callback(real, &p->cb);
+ else
+ set_proxy_callback(real, &p->cb);
+ spin_unlock(real->lock);
+
+unlock:
+ __wake_up_listeners(p);
+ spin_unlock_irqrestore(&p->wq.lock, flags);
+}
+
+/**
+ * dma_fence_replace_proxy - Replace the proxy fence with the real target
+ * @slot: pointer to location of fence to update
+ * @fence: the new fence to store in @slot
+ *
+ * Once the real dma_fence is known, we can replace the proxy fence holder
+ * with a pointer to the real dma fence. Future listeners will attach to
+ * the real fence, avoiding any indirection overhead. Previous listeners
+ * will remain attached to the proxy fence, and be signaled in turn when
+ * the target fence completes.
+ */
+struct dma_fence *
+dma_fence_replace_proxy(struct dma_fence __rcu **slot, struct dma_fence *fence)
+{
+ struct dma_fence *old;
+
+ if (fence)
+ dma_fence_get(fence);
+
+ old = rcu_replace_pointer(*slot, fence, true);
+ if (old && dma_fence_is_proxy(old))
+ proxy_assign(old, fence);
+
+ return old;
+}
+EXPORT_SYMBOL(dma_fence_replace_proxy);
+
+/**
+ * dma_fence_proxy_set_real - Set the target of a proxy fence
+ * @fence: the proxy fence
+ * @real: the target fence.
+ *
+ */
+void dma_fence_proxy_set_real(struct dma_fence *fence, struct dma_fence *real)
+{
+ if (dma_fence_is_proxy(fence))
+ proxy_assign(fence, real);
+}
+EXPORT_SYMBOL(dma_fence_proxy_set_real);
+
+/**
+ * dma_fence_proxy_get_real - Query the target of a proxy fence
+ * @fence: the proxy fence
+ *
+ * Unpeel the proxy fence to see if it has been replaced with a real fence.
+ */
+struct dma_fence *dma_fence_proxy_get_real(struct dma_fence *fence)
+{
+ if (dma_fence_is_proxy(fence)) {
+ struct dma_fence_proxy *p =
+ container_of(fence, typeof(*p), base);
+
+ if (p->real)
+ fence = p->real;
+ }
+
+ return fence;
+}
+EXPORT_SYMBOL(dma_fence_proxy_get_real);
+
+void dma_fence_add_proxy_listener(struct dma_fence *fence,
+ struct wait_queue_entry *wait)
+{
+ if (dma_fence_is_proxy(fence)) {
+ struct dma_fence_proxy *p =
+ container_of(fence, typeof(*p), base);
+ unsigned long flags;
+
+ spin_lock_irqsave(&p->wq.lock, flags);
+ if (!p->real) {
+ list_add_tail(&wait->entry, &p->wq.head);
+ wait = NULL;
+ }
+ fence = p->real;
+ spin_unlock_irqrestore(&p->wq.lock, flags);
+ }
+
+ if (wait) {
+ INIT_LIST_HEAD(&wait->entry);
+ wait->func(wait, TASK_NORMAL, 0, fence);
+ }
+}
+EXPORT_SYMBOL(dma_fence_add_proxy_listener);
+
+bool dma_fence_remove_proxy_listener(struct dma_fence *fence,
+ struct wait_queue_entry *wait)
+{
+ bool ret = false;
+
+ if (dma_fence_is_proxy(fence)) {
+ struct dma_fence_proxy *p =
+ container_of(fence, typeof(*p), base);
+ unsigned long flags;
+
+ spin_lock_irqsave(&p->wq.lock, flags);
+ if (!list_empty(&wait->entry)) {
+ list_del_init(&wait->entry);
+ ret = true;
+ }
+ spin_unlock_irqrestore(&p->wq.lock, flags);
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL(dma_fence_remove_proxy_listener);
diff --git a/drivers/dma-buf/dma-fence.c b/drivers/dma-buf/dma-fence.c
index 656e9ac2d028..329bd033059f 100644
--- a/drivers/dma-buf/dma-fence.c
+++ b/drivers/dma-buf/dma-fence.c
@@ -19,6 +19,8 @@
#define CREATE_TRACE_POINTS
#include <trace/events/dma_fence.h>
+#include "dma-fence-private.h"
+
EXPORT_TRACEPOINT_SYMBOL(dma_fence_emit);
EXPORT_TRACEPOINT_SYMBOL(dma_fence_enable_signal);
EXPORT_TRACEPOINT_SYMBOL(dma_fence_signaled);
@@ -275,7 +277,7 @@ void dma_fence_free(struct dma_fence *fence)
}
EXPORT_SYMBOL(dma_fence_free);
-static bool __dma_fence_enable_signaling(struct dma_fence *fence)
+bool __dma_fence_enable_signaling(struct dma_fence *fence)
{
bool was_set;
diff --git a/drivers/dma-buf/selftests.h b/drivers/dma-buf/selftests.h
index bc8cea67bf1e..92d15bf50f64 100644
--- a/drivers/dma-buf/selftests.h
+++ b/drivers/dma-buf/selftests.h
@@ -12,3 +12,4 @@
selftest(sanitycheck, __sanitycheck__) /* keep first (igt selfcheck) */
selftest(dma_fence, dma_fence)
selftest(dma_fence_chain, dma_fence_chain)
+selftest(dma_fence_proxy, dma_fence_proxy)
diff --git a/drivers/dma-buf/st-dma-fence-proxy.c b/drivers/dma-buf/st-dma-fence-proxy.c
new file mode 100644
index 000000000000..c3f210bc4e60
--- /dev/null
+++ b/drivers/dma-buf/st-dma-fence-proxy.c
@@ -0,0 +1,752 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright © 2019 Intel Corporation
+ */
+
+#include <linux/delay.h>
+#include <linux/dma-fence.h>
+#include <linux/dma-fence-proxy.h>
+#include <linux/kernel.h>
+#include <linux/sched/signal.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+
+#include "selftest.h"
+
+static struct kmem_cache *slab_fences;
+
+static struct mock_fence {
+ struct dma_fence base;
+ spinlock_t lock;
+} *to_mock_fence(struct dma_fence *f) {
+ return container_of(f, struct mock_fence, base);
+}
+
+static const char *mock_name(struct dma_fence *f)
+{
+ return "mock";
+}
+
+static void mock_fence_release(struct dma_fence *f)
+{
+ kmem_cache_free(slab_fences, to_mock_fence(f));
+}
+
+static const struct dma_fence_ops mock_ops = {
+ .get_driver_name = mock_name,
+ .get_timeline_name = mock_name,
+ .release = mock_fence_release,
+};
+
+static struct dma_fence *mock_fence(void)
+{
+ struct mock_fence *f;
+
+ f = kmem_cache_alloc(slab_fences, GFP_KERNEL);
+ if (!f)
+ return NULL;
+
+ spin_lock_init(&f->lock);
+ dma_fence_init(&f->base, &mock_ops, &f->lock, 0, 0);
+
+ return &f->base;
+}
+
+static int sanitycheck(void *arg)
+{
+ struct dma_fence *f;
+
+ f = dma_fence_create_proxy();
+ if (!f)
+ return -ENOMEM;
+
+ dma_fence_signal(f);
+ dma_fence_put(f);
+
+ return 0;
+}
+
+struct fences {
+ struct dma_fence *real;
+ struct dma_fence *proxy;
+ struct dma_fence __rcu *slot;
+};
+
+static int create_fences(struct fences *f, bool attach)
+{
+ f->proxy = dma_fence_create_proxy();
+ if (!f->proxy)
+ return -ENOMEM;
+
+ RCU_INIT_POINTER(f->slot, f->proxy);
+
+ f->real = mock_fence();
+ if (!f->real) {
+ dma_fence_put(f->proxy);
+ return -ENOMEM;
+ }
+
+ if (attach)
+ dma_fence_replace_proxy(&f->slot, f->real);
+
+ return 0;
+}
+
+static void free_fences(struct fences *f)
+{
+ dma_fence_put(dma_fence_replace_proxy(&f->slot, NULL));
+
+ dma_fence_signal(f->real);
+ dma_fence_put(f->real);
+
+ dma_fence_signal(f->proxy);
+ dma_fence_put(f->proxy);
+}
+
+static int wrap_target(void *arg)
+{
+ struct fences f;
+ int err = -EINVAL;
+
+ if (create_fences(&f, false))
+ return -ENOMEM;
+
+ if (dma_fence_proxy_get_real(f.proxy) != f.proxy) {
+ pr_err("Unwrapped proxy fenced reported a target fence!\n");
+ goto err_free;
+ }
+
+ dma_fence_proxy_set_real(f.proxy, f.real);
+ rcu_assign_pointer(f.slot, dma_fence_get(f.real)); /* free_fences() */
+
+ if (dma_fence_proxy_get_real(f.proxy) != f.real) {
+ pr_err("Wrapped proxy fenced did not report the target fence!\n");
+ goto err_free;
+ }
+
+ err = 0;
+err_free:
+ free_fences(&f);
+ return err;
+}
+
+static int wrap_proxy(void *arg)
+{
+ struct fences f;
+ int err = -EINVAL;
+
+ if (create_fences(&f, true))
+ return -ENOMEM;
+
+ if (dma_fence_proxy_get_real(f.proxy) != f.real) {
+ pr_err("Wrapped proxy fenced did not report the target fence!\n");
+ goto err_free;
+ }
+
+ err = 0;
+err_free:
+ free_fences(&f);
+ return err;
+}
+
+static int wrap_signaling(void *arg)
+{
+ struct fences f;
+ int err = -EINVAL;
+
+ if (create_fences(&f, true))
+ return -ENOMEM;
+
+ if (dma_fence_is_signaled(f.proxy)) {
+ pr_err("Fence unexpectedly signaled on creation\n");
+ goto err_free;
+ }
+
+ if (dma_fence_signal(f.real)) {
+ pr_err("Fence reported being already signaled\n");
+ goto err_free;
+ }
+
+ if (!dma_fence_is_signaled(f.proxy)) {
+ pr_err("Fence not reporting signaled\n");
+ goto err_free;
+ }
+
+ err = 0;
+err_free:
+ free_fences(&f);
+ return err;
+}
+
+static int wrap_signaling_recurse(void *arg)
+{
+ struct fences f;
+ struct dma_fence *chain;
+ int err = -EINVAL;
+
+ if (create_fences(&f, false))
+ return -ENOMEM;
+
+ chain = dma_fence_create_proxy();
+ if (!chain) {
+ err = -ENOMEM;
+ goto err_free;
+ }
+
+ dma_fence_replace_proxy(&f.slot, chain);
+ dma_fence_put(dma_fence_replace_proxy(&f.slot, f.real));
+ dma_fence_put(chain);
+
+ /* f.real <- chain <- f.proxy */
+
+ if (dma_fence_is_signaled(f.proxy)) {
+ pr_err("Fence unexpectedly signaled on creation\n");
+ goto err_free;
+ }
+
+ if (dma_fence_signal(f.real)) {
+ pr_err("Fence reported being already signaled\n");
+ goto err_free;
+ }
+
+ if (!dma_fence_is_signaled(f.proxy)) {
+ pr_err("Fence not reporting signaled\n");
+ goto err_free;
+ }
+
+ err = 0;
+err_free:
+ free_fences(&f);
+ return err;
+}
+
+struct simple_cb {
+ struct dma_fence_cb cb;
+ bool seen;
+};
+
+static void simple_callback(struct dma_fence *f, struct dma_fence_cb *cb)
+{
+ /* Ensure the callback marker is visible, no excuses for missing it! */
+ smp_store_mb(container_of(cb, struct simple_cb, cb)->seen, true);
+}
+
+static int wrap_add_callback(void *arg)
+{
+ struct simple_cb cb = {};
+ struct fences f;
+ int err = -EINVAL;
+
+ if (create_fences(&f, true))
+ return -ENOMEM;
+
+ if (dma_fence_add_callback(f.proxy, &cb.cb, simple_callback)) {
+ pr_err("Failed to add callback, fence already signaled!\n");
+ goto err_free;
+ }
+
+ dma_fence_signal(f.real);
+ if (!cb.seen) {
+ pr_err("Callback failed!\n");
+ goto err_free;
+ }
+
+ err = 0;
+err_free:
+ free_fences(&f);
+ return err;
+}
+
+static int wrap_add_callback_recurse(void *arg)
+{
+ struct simple_cb cb = {};
+ struct dma_fence *chain;
+ struct fences f;
+ int err = -EINVAL;
+
+ if (create_fences(&f, false))
+ return -ENOMEM;
+
+ chain = dma_fence_create_proxy();
+ if (!chain) {
+ err = -ENOMEM;
+ goto err_free;
+ }
+
+ dma_fence_replace_proxy(&f.slot, chain);
+ dma_fence_put(dma_fence_replace_proxy(&f.slot, f.real));
+ dma_fence_put(chain);
+
+ /* f.real <- chain <- f.proxy */
+
+ if (dma_fence_add_callback(f.proxy, &cb.cb, simple_callback)) {
+ pr_err("Failed to add callback, fence already signaled!\n");
+ goto err_free;
+ }
+
+ dma_fence_signal(f.real);
+ if (!cb.seen) {
+ pr_err("Callback failed!\n");
+ goto err_free;
+ }
+
+ err = 0;
+err_free:
+ free_fences(&f);
+ return err;
+}
+
+static int wrap_late_add_callback(void *arg)
+{
+ struct simple_cb cb = {};
+ struct fences f;
+ int err = -EINVAL;
+
+ if (create_fences(&f, true))
+ return -ENOMEM;
+
+ dma_fence_signal(f.real);
+
+ if (!dma_fence_add_callback(f.proxy, &cb.cb, simple_callback)) {
+ pr_err("Added callback, but fence was already signaled!\n");
+ goto err_free;
+ }
+
+ dma_fence_signal(f.real);
+ if (cb.seen) {
+ pr_err("Callback called after failed attachment!\n");
+ goto err_free;
+ }
+
+ err = 0;
+err_free:
+ free_fences(&f);
+ return err;
+}
+
+static int wrap_early_add_callback(void *arg)
+{
+ struct simple_cb cb = {};
+ struct fences f;
+ int err = -EINVAL;
+
+ if (create_fences(&f, false))
+ return -ENOMEM;
+
+ if (dma_fence_add_callback(f.proxy, &cb.cb, simple_callback)) {
+ pr_err("Failed to add callback, fence already signaled!\n");
+ goto err_free;
+ }
+
+ dma_fence_replace_proxy(&f.slot, f.real);
+ dma_fence_signal(f.real);
+ if (!cb.seen) {
+ pr_err("Callback failed!\n");
+ goto err_free;
+ }
+
+ err = 0;
+err_free:
+ free_fences(&f);
+ return err;
+}
+
+static int wrap_early_add_callback_late(void *arg)
+{
+ struct simple_cb cb = {};
+ struct fences f;
+ int err = -EINVAL;
+
+ if (create_fences(&f, false))
+ return -ENOMEM;
+
+ dma_fence_signal(f.real);
+
+ if (dma_fence_add_callback(f.proxy, &cb.cb, simple_callback)) {
+ pr_err("Failed to add callback, fence already signaled!\n");
+ goto err_free;
+ }
+
+ dma_fence_replace_proxy(&f.slot, f.real);
+ dma_fence_signal(f.real);
+ if (!cb.seen) {
+ pr_err("Callback failed!\n");
+ goto err_free;
+ }
+
+ err = 0;
+err_free:
+ free_fences(&f);
+ return err;
+}
+
+static int wrap_early_add_callback_early(void *arg)
+{
+ struct simple_cb cb = {};
+ struct fences f;
+ int err = -EINVAL;
+
+ if (create_fences(&f, false))
+ return -ENOMEM;
+
+ if (dma_fence_add_callback(f.proxy, &cb.cb, simple_callback)) {
+ pr_err("Failed to add callback, fence already signaled!\n");
+ goto err_free;
+ }
+
+ dma_fence_replace_proxy(&f.slot, f.real);
+ dma_fence_signal(f.real);
+ if (!cb.seen) {
+ pr_err("Callback failed!\n");
+ goto err_free;
+ }
+
+ err = 0;
+err_free:
+ free_fences(&f);
+ return err;
+}
+
+static int wrap_rm_callback(void *arg)
+{
+ struct simple_cb cb = {};
+ struct fences f;
+ int err = -EINVAL;
+
+ if (create_fences(&f, true))
+ return -ENOMEM;
+
+ if (dma_fence_add_callback(f.proxy, &cb.cb, simple_callback)) {
+ pr_err("Failed to add callback, fence already signaled!\n");
+ goto err_free;
+ }
+
+ if (!dma_fence_remove_callback(f.proxy, &cb.cb)) {
+ pr_err("Failed to remove callback!\n");
+ goto err_free;
+ }
+
+ dma_fence_signal(f.real);
+ if (cb.seen) {
+ pr_err("Callback still signaled after removal!\n");
+ goto err_free;
+ }
+
+ err = 0;
+err_free:
+ free_fences(&f);
+ return err;
+}
+
+static int wrap_late_rm_callback(void *arg)
+{
+ struct simple_cb cb = {};
+ struct fences f;
+ int err = -EINVAL;
+
+ if (create_fences(&f, true))
+ return -ENOMEM;
+
+ if (dma_fence_add_callback(f.proxy, &cb.cb, simple_callback)) {
+ pr_err("Failed to add callback, fence already signaled!\n");
+ goto err_free;
+ }
+
+ dma_fence_signal(f.real);
+ if (!cb.seen) {
+ pr_err("Callback failed!\n");
+ goto err_free;
+ }
+
+ if (dma_fence_remove_callback(f.proxy, &cb.cb)) {
+ pr_err("Callback removal succeed after being executed!\n");
+ goto err_free;
+ }
+
+ err = 0;
+err_free:
+ free_fences(&f);
+ return err;
+}
+
+static int wrap_status(void *arg)
+{
+ struct fences f;
+ int err = -EINVAL;
+
+ if (create_fences(&f, true))
+ return -ENOMEM;
+
+ if (dma_fence_get_status(f.proxy)) {
+ pr_err("Fence unexpectedly has signaled status on creation\n");
+ goto err_free;
+ }
+
+ dma_fence_signal(f.real);
+ if (!dma_fence_get_status(f.proxy)) {
+ pr_err("Fence not reporting signaled status\n");
+ goto err_free;
+ }
+
+ err = 0;
+err_free:
+ free_fences(&f);
+ return err;
+}
+
+static int wrap_error(void *arg)
+{
+ struct fences f;
+ int err = -EINVAL;
+
+ if (create_fences(&f, true))
+ return -ENOMEM;
+
+ dma_fence_set_error(f.real, -EIO);
+
+ if (dma_fence_get_status(f.proxy)) {
+ pr_err("Fence unexpectedly has error status before signal\n");
+ goto err_free;
+ }
+
+ dma_fence_signal(f.real);
+ if (dma_fence_get_status(f.proxy) != -EIO) {
+ pr_err("Fence not reporting error status, got %d\n",
+ dma_fence_get_status(f.proxy));
+ goto err_free;
+ }
+
+ err = 0;
+err_free:
+ free_fences(&f);
+ return err;
+}
+
+static int wrap_wait(void *arg)
+{
+ struct fences f;
+ int err = -EINVAL;
+
+ if (create_fences(&f, true))
+ return -ENOMEM;
+
+ if (dma_fence_wait_timeout(f.proxy, false, 0) != 0) {
+ pr_err("Wait reported complete before being signaled\n");
+ goto err_free;
+ }
+
+ dma_fence_signal(f.real);
+
+ if (dma_fence_wait_timeout(f.proxy, false, 0) == 0) {
+ pr_err("Wait reported incomplete after being signaled\n");
+ goto err_free;
+ }
+
+ err = 0;
+err_free:
+ dma_fence_signal(f.real);
+ free_fences(&f);
+ return err;
+}
+
+struct wait_timer {
+ struct timer_list timer;
+ struct fences f;
+};
+
+static void wait_timer(struct timer_list *timer)
+{
+ struct wait_timer *wt = from_timer(wt, timer, timer);
+
+ dma_fence_signal(wt->f.real);
+}
+
+static int wrap_wait_timeout(void *arg)
+{
+ struct wait_timer wt;
+ int err = -EINVAL;
+
+ if (create_fences(&wt.f, true))
+ return -ENOMEM;
+
+ timer_setup_on_stack(&wt.timer, wait_timer, 0);
+
+ if (dma_fence_wait_timeout(wt.f.proxy, false, 1) != 0) {
+ pr_err("Wait reported complete before being signaled\n");
+ goto err_free;
+ }
+
+ mod_timer(&wt.timer, jiffies + 1);
+
+ if (dma_fence_wait_timeout(wt.f.proxy, false, 2) != 0) {
+ if (timer_pending(&wt.timer)) {
+ pr_notice("Timer did not fire within the jiffie!\n");
+ err = 0; /* not our fault! */
+ } else {
+ pr_err("Wait reported incomplete after timeout\n");
+ }
+ goto err_free;
+ }
+
+ err = 0;
+err_free:
+ del_timer_sync(&wt.timer);
+ destroy_timer_on_stack(&wt.timer);
+ dma_fence_signal(wt.f.real);
+ free_fences(&wt.f);
+ return err;
+}
+
+struct proxy_wait {
+ struct wait_queue_entry base;
+ struct dma_fence *fence;
+ bool seen;
+};
+
+static int proxy_wait_cb(struct wait_queue_entry *entry,
+ unsigned int mode, int flags, void *key)
+{
+ struct proxy_wait *p = container_of(entry, typeof(*p), base);
+
+ p->fence = key;
+ p->seen = true;
+
+ return 0;
+}
+
+static int wrap_listen_early(void *arg)
+{
+ struct proxy_wait wait = { .base.func = proxy_wait_cb };
+ struct fences f;
+ int err = -EINVAL;
+
+ if (create_fences(&f, false))
+ return -ENOMEM;
+
+ dma_fence_replace_proxy(&f.slot, f.real);
+ dma_fence_add_proxy_listener(f.proxy, &wait.base);
+
+ if (!wait.seen) {
+ pr_err("Proxy listener was not called after replace!\n");
+ err = -EINVAL;
+ goto err_free;
+ }
+
+ if (wait.fence != f.real) {
+ pr_err("Proxy listener was not passed the real fence!\n");
+ err = -EINVAL;
+ goto err_free;
+ }
+
+ err = 0;
+err_free:
+ dma_fence_signal(f.real);
+ free_fences(&f);
+ return err;
+}
+
+static int wrap_listen_late(void *arg)
+{
+ struct proxy_wait wait = { .base.func = proxy_wait_cb };
+ struct fences f;
+ int err = -EINVAL;
+
+ if (create_fences(&f, false))
+ return -ENOMEM;
+
+ dma_fence_add_proxy_listener(f.proxy, &wait.base);
+ dma_fence_replace_proxy(&f.slot, f.real);
+
+ if (!wait.seen) {
+ pr_err("Proxy listener was not called on replace!\n");
+ err = -EINVAL;
+ goto err_free;
+ }
+
+ if (wait.fence != f.real) {
+ pr_err("Proxy listener was not passed the real fence!\n");
+ err = -EINVAL;
+ goto err_free;
+ }
+
+ err = 0;
+err_free:
+ dma_fence_signal(f.real);
+ free_fences(&f);
+ return err;
+}
+
+static int wrap_listen_cancel(void *arg)
+{
+ struct proxy_wait wait = { .base.func = proxy_wait_cb };
+ struct fences f;
+ int err = -EINVAL;
+
+ if (create_fences(&f, false))
+ return -ENOMEM;
+
+ dma_fence_add_proxy_listener(f.proxy, &wait.base);
+ if (!dma_fence_remove_proxy_listener(f.proxy, &wait.base)) {
+ pr_err("Cancelling listener, already detached?\n");
+ err = -EINVAL;
+ goto err_free;
+ }
+ dma_fence_replace_proxy(&f.slot, f.real);
+
+ if (wait.seen) {
+ pr_err("Proxy listener was called after being removed!\n");
+ err = -EINVAL;
+ goto err_free;
+ }
+
+ if (dma_fence_remove_proxy_listener(f.proxy, &wait.base)) {
+ pr_err("Double listener cancellation!\n");
+ err = -EINVAL;
+ goto err_free;
+ }
+
+ err = 0;
+err_free:
+ dma_fence_signal(f.real);
+ free_fences(&f);
+ return err;
+}
+
+int dma_fence_proxy(void)
+{
+ static const struct subtest tests[] = {
+ SUBTEST(sanitycheck),
+ SUBTEST(wrap_target),
+ SUBTEST(wrap_proxy),
+ SUBTEST(wrap_signaling),
+ SUBTEST(wrap_signaling_recurse),
+ SUBTEST(wrap_add_callback),
+ SUBTEST(wrap_add_callback_recurse),
+ SUBTEST(wrap_late_add_callback),
+ SUBTEST(wrap_early_add_callback),
+ SUBTEST(wrap_early_add_callback_late),
+ SUBTEST(wrap_early_add_callback_early),
+ SUBTEST(wrap_rm_callback),
+ SUBTEST(wrap_late_rm_callback),
+ SUBTEST(wrap_status),
+ SUBTEST(wrap_error),
+ SUBTEST(wrap_wait),
+ SUBTEST(wrap_wait_timeout),
+ SUBTEST(wrap_listen_early),
+ SUBTEST(wrap_listen_late),
+ SUBTEST(wrap_listen_cancel),
+ };
+ int ret;
+
+ slab_fences = KMEM_CACHE(mock_fence,
+ SLAB_TYPESAFE_BY_RCU |
+ SLAB_HWCACHE_ALIGN);
+ if (!slab_fences)
+ return -ENOMEM;
+
+ ret = subtests(tests, NULL);
+
+ kmem_cache_destroy(slab_fences);
+
+ return ret;
+}
diff --git a/include/linux/dma-fence-proxy.h b/include/linux/dma-fence-proxy.h
new file mode 100644
index 000000000000..6a986b5bb009
--- /dev/null
+++ b/include/linux/dma-fence-proxy.h
@@ -0,0 +1,38 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * dma-fence-proxy: allows waiting upon unset and future fences
+ *
+ * Copyright (C) 2017 Intel Corporation
+ */
+
+#ifndef __LINUX_DMA_FENCE_PROXY_H
+#define __LINUX_DMA_FENCE_PROXY_H
+
+#include <linux/kernel.h>
+#include <linux/dma-fence.h>
+
+struct wait_queue_entry;
+
+extern const struct dma_fence_ops dma_fence_proxy_ops;
+
+struct dma_fence *__dma_fence_create_proxy(u64 context, u64 seqno);
+struct dma_fence *dma_fence_create_proxy(void);
+
+static inline bool dma_fence_is_proxy(struct dma_fence *fence)
+{
+ return fence->ops == &dma_fence_proxy_ops;
+}
+
+void dma_fence_proxy_set_real(struct dma_fence *fence, struct dma_fence *real);
+struct dma_fence *dma_fence_proxy_get_real(struct dma_fence *fence);
+
+struct dma_fence *
+dma_fence_replace_proxy(struct dma_fence __rcu **slot,
+ struct dma_fence *fence);
+
+void dma_fence_add_proxy_listener(struct dma_fence *fence,
+ struct wait_queue_entry *wait);
+bool dma_fence_remove_proxy_listener(struct dma_fence *fence,
+ struct wait_queue_entry *wait);
+
+#endif /* __LINUX_DMA_FENCE_PROXY_H */
--
2.20.1
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx
^ permalink raw reply related
* [Intel-gfx] [PATCH 05/28] drm/i915/selftests: Trim execlists runtime
From: Chris Wilson @ 2020-06-07 22:20 UTC (permalink / raw)
To: intel-gfx; +Cc: Chris Wilson
In-Reply-To: <20200607222108.14401-1-chris@chris-wilson.co.uk>
Reduce the smoke depth by trimming the number of contexts, repetitions
and wait times. This is in preparation for a less greedy scheduler that
tries to be fair across contexts, resulting in a great many more context
switches. A thousand context switches may be 50-100ms, causing us to
timeout as the HW is not fast enough to complete the deep smoketests.
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
---
drivers/gpu/drm/i915/gt/selftest_lrc.c | 66 ++++++--------------
drivers/gpu/drm/i915/selftests/igt_spinner.c | 4 +-
2 files changed, 21 insertions(+), 49 deletions(-)
diff --git a/drivers/gpu/drm/i915/gt/selftest_lrc.c b/drivers/gpu/drm/i915/gt/selftest_lrc.c
index e838e38a262c..f651bdf7f191 100644
--- a/drivers/gpu/drm/i915/gt/selftest_lrc.c
+++ b/drivers/gpu/drm/i915/gt/selftest_lrc.c
@@ -845,10 +845,11 @@ static int live_timeslice_preempt(void *arg)
{
struct intel_gt *gt = arg;
struct drm_i915_gem_object *obj;
+ struct intel_engine_cs *engine;
+ enum intel_engine_id id;
struct i915_vma *vma;
void *vaddr;
int err = 0;
- int count;
/*
* If a request takes too long, we would like to give other users
@@ -885,26 +886,21 @@ static int live_timeslice_preempt(void *arg)
if (err)
goto err_pin;
- for_each_prime_number_from(count, 1, 16) {
- struct intel_engine_cs *engine;
- enum intel_engine_id id;
-
- for_each_engine(engine, gt, id) {
- if (!intel_engine_has_preemption(engine))
- continue;
+ for_each_engine(engine, gt, id) {
+ if (!intel_engine_has_preemption(engine))
+ continue;
- memset(vaddr, 0, PAGE_SIZE);
+ memset(vaddr, 0, PAGE_SIZE);
- engine_heartbeat_disable(engine);
- err = slice_semaphore_queue(engine, vma, count);
- engine_heartbeat_enable(engine);
- if (err)
- goto err_pin;
+ engine_heartbeat_disable(engine);
+ err = slice_semaphore_queue(engine, vma, 5);
+ engine_heartbeat_enable(engine);
+ if (err)
+ goto err_pin;
- if (igt_flush_test(gt->i915)) {
- err = -EIO;
- goto err_pin;
- }
+ if (igt_flush_test(gt->i915)) {
+ err = -EIO;
+ goto err_pin;
}
}
@@ -1251,22 +1247,6 @@ static int live_timeslice_queue(void *arg)
intel_engine_flush_submission(engine);
} while (READ_ONCE(engine->execlists.pending[0]));
- if (!READ_ONCE(engine->execlists.timer.expires) &&
- execlists_active(&engine->execlists) == rq &&
- !i915_request_completed(rq)) {
- struct drm_printer p =
- drm_info_printer(gt->i915->drm.dev);
-
- GEM_TRACE_ERR("%s: Failed to enable timeslicing!\n",
- engine->name);
- intel_engine_dump(engine, &p,
- "%s\n", engine->name);
- GEM_TRACE_DUMP();
-
- memset(vaddr, 0xff, PAGE_SIZE);
- err = -EINVAL;
- }
-
/* Timeslice every jiffy, so within 2 we should signal */
if (i915_request_wait(rq, 0, slice_timeout(engine)) < 0) {
struct drm_printer p =
@@ -2671,16 +2651,8 @@ static int live_preempt_gang(void *arg)
/* Submit each spinner at increasing priority */
engine->schedule(rq, &attr);
-
- if (prio < attr.priority)
- break;
-
- if (prio <= I915_PRIORITY_MAX)
- continue;
-
- if (__igt_timeout(end_time, NULL))
- break;
- } while (1);
+ } while (prio <= I915_PRIORITY_MAX &&
+ !__igt_timeout(end_time, NULL));
pr_debug("%s: Preempt chain of %d requests\n",
engine->name, prio);
@@ -3248,7 +3220,7 @@ static int smoke_crescendo_thread(void *arg)
return err;
count++;
- } while (!__igt_timeout(end_time, NULL));
+ } while (count < smoke->ncontext && !__igt_timeout(end_time, NULL));
smoke->count = count;
return 0;
@@ -3324,7 +3296,7 @@ static int smoke_random(struct preempt_smoke *smoke, unsigned int flags)
count++;
}
- } while (!__igt_timeout(end_time, NULL));
+ } while (count < smoke->ncontext && !__igt_timeout(end_time, NULL));
pr_info("Submitted %lu random:%x requests across %d engines and %d contexts\n",
count, flags,
@@ -3337,7 +3309,7 @@ static int live_preempt_smoke(void *arg)
struct preempt_smoke smoke = {
.gt = arg,
.prng = I915_RND_STATE_INITIALIZER(i915_selftest.random_seed),
- .ncontext = 1024,
+ .ncontext = 256,
};
const unsigned int phase[] = { 0, BATCH };
struct igt_live_test t;
diff --git a/drivers/gpu/drm/i915/selftests/igt_spinner.c b/drivers/gpu/drm/i915/selftests/igt_spinner.c
index 699bfe0328fb..ec0ecb4e4ca6 100644
--- a/drivers/gpu/drm/i915/selftests/igt_spinner.c
+++ b/drivers/gpu/drm/i915/selftests/igt_spinner.c
@@ -221,8 +221,8 @@ bool igt_wait_for_spinner(struct igt_spinner *spin, struct i915_request *rq)
{
return !(wait_for_us(i915_seqno_passed(hws_seqno(spin, rq),
rq->fence.seqno),
- 10) &&
+ 100) &&
wait_for(i915_seqno_passed(hws_seqno(spin, rq),
rq->fence.seqno),
- 1000));
+ 50));
}
--
2.20.1
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx
^ permalink raw reply related
* [Intel-gfx] [PATCH 06/28] drm/i915/gt: Use virtual_engine during execlists_dequeue
From: Chris Wilson @ 2020-06-07 22:20 UTC (permalink / raw)
To: intel-gfx; +Cc: Chris Wilson
In-Reply-To: <20200607222108.14401-1-chris@chris-wilson.co.uk>
Rather than going back and forth between the rb_node entry and the
virtual_engine type, store the ve local and reuse it. As the
container_of conversion from rb_node to virtual_engine requires a
variable offset, performing that conversion just once shaves off a bit
of code.
v2: Keep a single virtual engine lookup, for typical use.
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
---
drivers/gpu/drm/i915/gt/intel_lrc.c | 217 +++++++++++++---------------
1 file changed, 104 insertions(+), 113 deletions(-)
diff --git a/drivers/gpu/drm/i915/gt/intel_lrc.c b/drivers/gpu/drm/i915/gt/intel_lrc.c
index db8a170b0e5c..ab1f3131b357 100644
--- a/drivers/gpu/drm/i915/gt/intel_lrc.c
+++ b/drivers/gpu/drm/i915/gt/intel_lrc.c
@@ -454,7 +454,7 @@ static int queue_prio(const struct intel_engine_execlists *execlists)
static inline bool need_preempt(const struct intel_engine_cs *engine,
const struct i915_request *rq,
- struct rb_node *rb)
+ struct virtual_engine *ve)
{
int last_prio;
@@ -491,9 +491,7 @@ static inline bool need_preempt(const struct intel_engine_cs *engine,
rq_prio(list_next_entry(rq, sched.link)) > last_prio)
return true;
- if (rb) {
- struct virtual_engine *ve =
- rb_entry(rb, typeof(*ve), nodes[engine->id].rb);
+ if (ve) {
bool preempt = false;
if (engine == ve->siblings[0]) { /* only preempt one sibling */
@@ -1811,6 +1809,35 @@ static bool virtual_matches(const struct virtual_engine *ve,
return true;
}
+static struct virtual_engine *
+first_virtual_engine(struct intel_engine_cs *engine)
+{
+ struct intel_engine_execlists *el = &engine->execlists;
+ struct rb_node *rb = rb_first_cached(&el->virtual);
+
+ while (rb) {
+ struct virtual_engine *ve =
+ rb_entry(rb, typeof(*ve), nodes[engine->id].rb);
+ struct i915_request *rq = READ_ONCE(ve->request);
+
+ if (!rq) { /* lazily cleanup after another engine handled rq */
+ rb_erase_cached(rb, &el->virtual);
+ RB_CLEAR_NODE(rb);
+ rb = rb_first_cached(&el->virtual);
+ continue;
+ }
+
+ if (!virtual_matches(ve, rq, engine)) {
+ rb = rb_next(rb);
+ continue;
+ }
+
+ return ve;
+ }
+
+ return NULL;
+}
+
static void virtual_xfer_breadcrumbs(struct virtual_engine *ve)
{
/*
@@ -1895,7 +1922,7 @@ static void defer_active(struct intel_engine_cs *engine)
static bool
need_timeslice(const struct intel_engine_cs *engine,
const struct i915_request *rq,
- const struct rb_node *rb)
+ struct virtual_engine *ve)
{
int hint;
@@ -1904,9 +1931,7 @@ need_timeslice(const struct intel_engine_cs *engine,
hint = engine->execlists.queue_priority_hint;
- if (rb) {
- const struct virtual_engine *ve =
- rb_entry(rb, typeof(*ve), nodes[engine->id].rb);
+ if (ve) {
const struct intel_engine_cs *inflight =
intel_context_inflight(&ve->context);
@@ -2057,7 +2082,8 @@ static void execlists_dequeue(struct intel_engine_cs *engine)
struct intel_engine_execlists * const execlists = &engine->execlists;
struct i915_request **port = execlists->pending;
struct i915_request ** const last_port = port + execlists->port_mask;
- struct i915_request * const *active;
+ struct i915_request * const *active = READ_ONCE(execlists->active);
+ struct virtual_engine *ve = first_virtual_engine(engine);
struct i915_request *last;
struct rb_node *rb;
bool submit = false;
@@ -2084,26 +2110,6 @@ static void execlists_dequeue(struct intel_engine_cs *engine)
* and context switches) submission.
*/
- for (rb = rb_first_cached(&execlists->virtual); rb; ) {
- struct virtual_engine *ve =
- rb_entry(rb, typeof(*ve), nodes[engine->id].rb);
- struct i915_request *rq = READ_ONCE(ve->request);
-
- if (!rq) { /* lazily cleanup after another engine handled rq */
- rb_erase_cached(rb, &execlists->virtual);
- RB_CLEAR_NODE(rb);
- rb = rb_first_cached(&execlists->virtual);
- continue;
- }
-
- if (!virtual_matches(ve, rq, engine)) {
- rb = rb_next(rb);
- continue;
- }
-
- break;
- }
-
/*
* If the queue is higher priority than the last
* request in the currently active context, submit afresh.
@@ -2111,10 +2117,7 @@ static void execlists_dequeue(struct intel_engine_cs *engine)
* the active context to interject the preemption request,
* i.e. we will retrigger preemption following the ack in case
* of trouble.
- */
- active = READ_ONCE(execlists->active);
-
- /*
+ *
* In theory we can skip over completed contexts that have not
* yet been processed by events (as those events are in flight):
*
@@ -2125,9 +2128,8 @@ static void execlists_dequeue(struct intel_engine_cs *engine)
* find itself trying to jump back into a context it has just
* completed and barf.
*/
-
if ((last = *active)) {
- if (need_preempt(engine, last, rb)) {
+ if (need_preempt(engine, last, ve)) {
if (i915_request_completed(last)) {
tasklet_hi_schedule(&execlists->tasklet);
return;
@@ -2158,7 +2160,7 @@ static void execlists_dequeue(struct intel_engine_cs *engine)
__unwind_incomplete_requests(engine);
last = NULL;
- } else if (need_timeslice(engine, last, rb) &&
+ } else if (need_timeslice(engine, last, ve) &&
timeslice_expired(execlists, last)) {
if (i915_request_completed(last)) {
tasklet_hi_schedule(&execlists->tasklet);
@@ -2212,110 +2214,99 @@ static void execlists_dequeue(struct intel_engine_cs *engine)
}
}
- while (rb) { /* XXX virtual is always taking precedence */
- struct virtual_engine *ve =
- rb_entry(rb, typeof(*ve), nodes[engine->id].rb);
+ while (ve) { /* XXX virtual is always taking precedence */
struct i915_request *rq;
spin_lock(&ve->base.active.lock);
rq = ve->request;
- if (unlikely(!rq)) { /* lost the race to a sibling */
- spin_unlock(&ve->base.active.lock);
- rb_erase_cached(rb, &execlists->virtual);
- RB_CLEAR_NODE(rb);
- rb = rb_first_cached(&execlists->virtual);
- continue;
- }
+ if (unlikely(!rq)) /* lost the race to a sibling */
+ goto unlock;
GEM_BUG_ON(rq != ve->request);
GEM_BUG_ON(rq->engine != &ve->base);
GEM_BUG_ON(rq->context != &ve->context);
- if (rq_prio(rq) >= queue_prio(execlists)) {
- if (!virtual_matches(ve, rq, engine)) {
- spin_unlock(&ve->base.active.lock);
- rb = rb_next(rb);
- continue;
- }
+ if (unlikely(rq_prio(rq) < queue_prio(execlists))) {
+ spin_unlock(&ve->base.active.lock);
+ break;
+ }
- if (last && !can_merge_rq(last, rq)) {
- spin_unlock(&ve->base.active.lock);
- start_timeslice(engine, rq_prio(rq));
- return; /* leave this for another sibling */
- }
+ GEM_BUG_ON(!virtual_matches(ve, rq, engine));
- ENGINE_TRACE(engine,
- "virtual rq=%llx:%lld%s, new engine? %s\n",
- rq->fence.context,
- rq->fence.seqno,
- i915_request_completed(rq) ? "!" :
- i915_request_started(rq) ? "*" :
- "",
- yesno(engine != ve->siblings[0]));
-
- WRITE_ONCE(ve->request, NULL);
- WRITE_ONCE(ve->base.execlists.queue_priority_hint,
- INT_MIN);
- rb_erase_cached(rb, &execlists->virtual);
- RB_CLEAR_NODE(rb);
+ if (last && !can_merge_rq(last, rq)) {
+ spin_unlock(&ve->base.active.lock);
+ start_timeslice(engine, rq_prio(rq));
+ return; /* leave this for another sibling */
+ }
- GEM_BUG_ON(!(rq->execution_mask & engine->mask));
- WRITE_ONCE(rq->engine, engine);
+ ENGINE_TRACE(engine,
+ "virtual rq=%llx:%lld%s, new engine? %s\n",
+ rq->fence.context,
+ rq->fence.seqno,
+ i915_request_completed(rq) ? "!" :
+ i915_request_started(rq) ? "*" :
+ "",
+ yesno(engine != ve->siblings[0]));
- if (engine != ve->siblings[0]) {
- u32 *regs = ve->context.lrc_reg_state;
- unsigned int n;
+ WRITE_ONCE(ve->request, NULL);
+ WRITE_ONCE(ve->base.execlists.queue_priority_hint,
+ INT_MIN);
- GEM_BUG_ON(READ_ONCE(ve->context.inflight));
+ rb = &ve->nodes[engine->id].rb;
+ rb_erase_cached(rb, &execlists->virtual);
+ RB_CLEAR_NODE(rb);
- if (!intel_engine_has_relative_mmio(engine))
- virtual_update_register_offsets(regs,
- engine);
+ GEM_BUG_ON(!(rq->execution_mask & engine->mask));
+ WRITE_ONCE(rq->engine, engine);
- if (!list_empty(&ve->context.signals))
- virtual_xfer_breadcrumbs(ve);
+ if (engine != ve->siblings[0]) {
+ u32 *regs = ve->context.lrc_reg_state;
+ unsigned int n;
- /*
- * Move the bound engine to the top of the list
- * for future execution. We then kick this
- * tasklet first before checking others, so that
- * we preferentially reuse this set of bound
- * registers.
- */
- for (n = 1; n < ve->num_siblings; n++) {
- if (ve->siblings[n] == engine) {
- swap(ve->siblings[n],
- ve->siblings[0]);
- break;
- }
- }
+ GEM_BUG_ON(READ_ONCE(ve->context.inflight));
- GEM_BUG_ON(ve->siblings[0] != engine);
- }
+ if (!intel_engine_has_relative_mmio(engine))
+ virtual_update_register_offsets(regs,
+ engine);
- if (__i915_request_submit(rq)) {
- submit = true;
- last = rq;
- }
- i915_request_put(rq);
+ if (!list_empty(&ve->context.signals))
+ virtual_xfer_breadcrumbs(ve);
/*
- * Hmm, we have a bunch of virtual engine requests,
- * but the first one was already completed (thanks
- * preempt-to-busy!). Keep looking at the veng queue
- * until we have no more relevant requests (i.e.
- * the normal submit queue has higher priority).
+ * Move the bound engine to the top of the list for
+ * future execution. We then kick this tasklet first
+ * before checking others, so that we preferentially
+ * reuse this set of bound registers.
*/
- if (!submit) {
- spin_unlock(&ve->base.active.lock);
- rb = rb_first_cached(&execlists->virtual);
- continue;
+ for (n = 1; n < ve->num_siblings; n++) {
+ if (ve->siblings[n] == engine) {
+ swap(ve->siblings[n],
+ ve->siblings[0]);
+ break;
+ }
}
+
+ GEM_BUG_ON(ve->siblings[0] != engine);
}
+ if (__i915_request_submit(rq)) {
+ submit = true;
+ last = rq;
+ }
+
+ i915_request_put(rq);
+unlock:
spin_unlock(&ve->base.active.lock);
- break;
+
+ /*
+ * Hmm, we have a bunch of virtual engine requests,
+ * but the first one was already completed (thanks
+ * preempt-to-busy!). Keep looking at the veng queue
+ * until we have no more relevant requests (i.e.
+ * the normal submit queue has higher priority).
+ */
+ ve = submit ? NULL : first_virtual_engine(engine);
}
while ((rb = rb_first_cached(&execlists->queue))) {
--
2.20.1
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx
^ permalink raw reply related
* [Intel-gfx] [PATCH 23/28] drm/i915: Restructure priority inheritance
From: Chris Wilson @ 2020-06-07 22:21 UTC (permalink / raw)
To: intel-gfx; +Cc: Chris Wilson
In-Reply-To: <20200607222108.14401-1-chris@chris-wilson.co.uk>
In anticipation of wanting to be able to call pi from underneath an
engine's active.lock, rework the priority inheritance to primarily work
along an engine's priority queue, delegating any other engine that the
chain may traverse to a worker. This reduces the global spinlock from
governing the entire priority inheritance depth-first search, to a small
lock around a single list.
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
---
drivers/gpu/drm/i915/i915_scheduler.c | 236 ++++++++++----------
drivers/gpu/drm/i915/i915_scheduler_types.h | 6 +-
2 files changed, 121 insertions(+), 121 deletions(-)
diff --git a/drivers/gpu/drm/i915/i915_scheduler.c b/drivers/gpu/drm/i915/i915_scheduler.c
index f9cd8baaefcd..320d3720ba34 100644
--- a/drivers/gpu/drm/i915/i915_scheduler.c
+++ b/drivers/gpu/drm/i915/i915_scheduler.c
@@ -17,7 +17,46 @@ static struct i915_global_scheduler {
struct kmem_cache *slab_priorities;
} global;
-static DEFINE_SPINLOCK(schedule_lock);
+static DEFINE_SPINLOCK(ipi_lock);
+static LIST_HEAD(ipi_list);
+
+static inline int rq_prio(const struct i915_request *rq)
+{
+ return READ_ONCE(rq->sched.attr.priority);
+}
+
+static void ipi_schedule(struct irq_work *wrk)
+{
+ rcu_read_lock();
+ do {
+ struct i915_dependency *p;
+ struct i915_request *rq;
+ unsigned long flags;
+ int prio;
+
+ spin_lock_irqsave(&ipi_lock, flags);
+ p = list_first_entry_or_null(&ipi_list, typeof(*p), ipi_link);
+ if (p) {
+ rq = container_of(p->signaler, typeof(*rq), sched);
+ list_del_init(&p->ipi_link);
+
+ prio = p->ipi_priority;
+ p->ipi_priority = I915_PRIORITY_INVALID;
+ }
+ spin_unlock_irqrestore(&ipi_lock, flags);
+ if (!p)
+ break;
+
+ if (i915_request_completed(rq))
+ continue;
+
+ if (prio > rq_prio(rq))
+ i915_request_set_priority(rq, prio);
+ } while (1);
+ rcu_read_unlock();
+}
+
+static DEFINE_IRQ_WORK(ipi_work, ipi_schedule);
static const struct i915_request *
node_to_request(const struct i915_sched_node *node)
@@ -126,42 +165,6 @@ void __i915_priolist_free(struct i915_priolist *p)
kmem_cache_free(global.slab_priorities, p);
}
-struct sched_cache {
- struct list_head *priolist;
-};
-
-static struct intel_engine_cs *
-sched_lock_engine(const struct i915_sched_node *node,
- struct intel_engine_cs *locked,
- struct sched_cache *cache)
-{
- const struct i915_request *rq = node_to_request(node);
- struct intel_engine_cs *engine;
-
- GEM_BUG_ON(!locked);
-
- /*
- * Virtual engines complicate acquiring the engine timeline lock,
- * as their rq->engine pointer is not stable until under that
- * engine lock. The simple ploy we use is to take the lock then
- * check that the rq still belongs to the newly locked engine.
- */
- while (locked != (engine = READ_ONCE(rq->engine))) {
- spin_unlock(&locked->active.lock);
- memset(cache, 0, sizeof(*cache));
- spin_lock(&engine->active.lock);
- locked = engine;
- }
-
- GEM_BUG_ON(locked != engine);
- return locked;
-}
-
-static inline int rq_prio(const struct i915_request *rq)
-{
- return rq->sched.attr.priority;
-}
-
static inline bool need_preempt(int prio, int active)
{
/*
@@ -216,25 +219,15 @@ static void kick_submission(struct intel_engine_cs *engine,
rcu_read_unlock();
}
-static void __i915_schedule(struct i915_sched_node *node, int prio)
+static void __i915_request_set_priority(struct i915_request *rq, int prio)
{
- struct intel_engine_cs *engine;
- struct i915_dependency *dep, *p;
- struct i915_dependency stack;
- struct sched_cache cache;
+ struct intel_engine_cs *engine = rq->engine;
+ struct i915_request *rn;
+ struct list_head *plist;
LIST_HEAD(dfs);
- /* Needed in order to use the temporary link inside i915_dependency */
- lockdep_assert_held(&schedule_lock);
- GEM_BUG_ON(prio == I915_PRIORITY_INVALID);
-
- if (node_signaled(node))
- return;
-
- prio = max(prio, node->attr.priority);
-
- stack.signaler = node;
- list_add(&stack.dfs_link, &dfs);
+ lockdep_assert_held(&engine->active.lock);
+ list_add(&rq->sched.dfs, &dfs);
/*
* Recursively bump all dependent priorities to match the new request.
@@ -254,66 +247,47 @@ static void __i915_schedule(struct i915_sched_node *node, int prio)
* end result is a topological list of requests in reverse order, the
* last element in the list is the request we must execute first.
*/
- list_for_each_entry(dep, &dfs, dfs_link) {
- struct i915_sched_node *node = dep->signaler;
+ list_for_each_entry(rq, &dfs, sched.dfs) {
+ struct i915_dependency *p;
- /* If we are already flying, we know we have no signalers */
- if (node_started(node))
- continue;
+ /* Also release any children on this engine that are ready */
+ GEM_BUG_ON(rq->engine != engine);
- /*
- * Within an engine, there can be no cycle, but we may
- * refer to the same dependency chain multiple times
- * (redundant dependencies are not eliminated) and across
- * engines.
- */
- list_for_each_entry(p, &node->signalers_list, signal_link) {
- GEM_BUG_ON(p == dep); /* no cycles! */
+ for_each_signaler(p, rq) {
+ struct i915_request *s =
+ container_of(p->signaler, typeof(*s), sched);
- if (node_signaled(p->signaler))
- continue;
+ GEM_BUG_ON(s == rq);
- if (prio > READ_ONCE(p->signaler->attr.priority))
- list_move_tail(&p->dfs_link, &dfs);
- }
- }
+ if (rq_prio(s) >= prio)
+ continue;
- /*
- * If we didn't need to bump any existing priorities, and we haven't
- * yet submitted this request (i.e. there is no potential race with
- * execlists_submit_request()), we can set our own priority and skip
- * acquiring the engine locks.
- */
- if (node->attr.priority == I915_PRIORITY_INVALID) {
- GEM_BUG_ON(!list_empty(&node->link));
- node->attr.priority = prio;
+ if (i915_request_completed(s))
+ continue;
- if (stack.dfs_link.next == stack.dfs_link.prev)
- return;
+ if (s->engine != rq->engine) {
+ spin_lock(&ipi_lock);
+ if (prio > p->ipi_priority) {
+ p->ipi_priority = prio;
+ list_move(&p->ipi_link, &ipi_list);
+ irq_work_queue(&ipi_work);
+ }
+ spin_unlock(&ipi_lock);
+ continue;
+ }
- __list_del_entry(&stack.dfs_link);
+ list_move_tail(&s->sched.dfs, &dfs);
+ }
}
- memset(&cache, 0, sizeof(cache));
- engine = node_to_request(node)->engine;
- spin_lock(&engine->active.lock);
-
- /* Fifo and depth-first replacement ensure our deps execute before us */
- engine = sched_lock_engine(node, engine, &cache);
- list_for_each_entry_safe_reverse(dep, p, &dfs, dfs_link) {
- INIT_LIST_HEAD(&dep->dfs_link);
-
- node = dep->signaler;
- engine = sched_lock_engine(node, engine, &cache);
- lockdep_assert_held(&engine->active.lock);
-
- /* Recheck after acquiring the engine->timeline.lock */
- if (prio <= node->attr.priority || node_signaled(node))
- continue;
+ plist = i915_sched_lookup_priolist(engine, prio);
- GEM_BUG_ON(node_to_request(node)->engine != engine);
+ /* Fifo and depth-first replacement ensure our deps execute first */
+ list_for_each_entry_safe_reverse(rq, rn, &dfs, sched.dfs) {
+ GEM_BUG_ON(rq->engine != engine);
- WRITE_ONCE(node->attr.priority, prio);
+ INIT_LIST_HEAD(&rq->sched.dfs);
+ WRITE_ONCE(rq->sched.attr.priority, prio);
/*
* Once the request is ready, it will be placed into the
@@ -323,32 +297,48 @@ static void __i915_schedule(struct i915_sched_node *node, int prio)
* any preemption required, be dealt with upon submission.
* See engine->submit_request()
*/
- if (list_empty(&node->link))
+ if (!i915_request_is_ready(rq))
continue;
- if (i915_request_in_priority_queue(node_to_request(node))) {
- if (!cache.priolist)
- cache.priolist =
- i915_sched_lookup_priolist(engine,
- prio);
- list_move_tail(&node->link, cache.priolist);
- }
+ if (i915_request_in_priority_queue(rq))
+ list_move_tail(&rq->sched.link, plist);
- /* Defer (tasklet) submission until after all of our updates. */
- kick_submission(engine, node_to_request(node), prio);
+ /* Defer (tasklet) submission until after all updates. */
+ kick_submission(engine, rq, prio);
}
-
- spin_unlock(&engine->active.lock);
}
void i915_request_set_priority(struct i915_request *rq, int prio)
{
- if (!intel_engine_has_scheduler(rq->engine))
+ struct intel_engine_cs *engine = READ_ONCE(rq->engine);
+ unsigned long flags;
+
+ if (!intel_engine_has_scheduler(engine))
return;
- spin_lock_irq(&schedule_lock);
- __i915_schedule(&rq->sched, prio);
- spin_unlock_irq(&schedule_lock);
+ /*
+ * Virtual engines complicate acquiring the engine timeline lock,
+ * as their rq->engine pointer is not stable until under that
+ * engine lock. The simple ploy we use is to take the lock then
+ * check that the rq still belongs to the newly locked engine.
+ */
+ spin_lock_irqsave(&engine->active.lock, flags);
+ while (engine != READ_ONCE(rq->engine)) {
+ spin_unlock(&engine->active.lock);
+ engine = READ_ONCE(rq->engine);
+ spin_lock(&engine->active.lock);
+ }
+
+ if (i915_request_completed(rq))
+ goto unlock;
+
+ if (prio <= rq_prio(rq))
+ goto unlock;
+
+ __i915_request_set_priority(rq, prio);
+
+unlock:
+ spin_unlock_irqrestore(&engine->active.lock, flags);
}
void i915_sched_node_init(struct i915_sched_node *node)
@@ -358,6 +348,7 @@ void i915_sched_node_init(struct i915_sched_node *node)
INIT_LIST_HEAD(&node->signalers_list);
INIT_LIST_HEAD(&node->waiters_list);
INIT_LIST_HEAD(&node->link);
+ INIT_LIST_HEAD(&node->dfs);
i915_sched_node_reinit(node);
}
@@ -396,7 +387,8 @@ bool __i915_sched_node_add_dependency(struct i915_sched_node *node,
spin_lock_irq(&signal->lock);
if (!node_signaled(signal)) {
- INIT_LIST_HEAD(&dep->dfs_link);
+ INIT_LIST_HEAD(&dep->ipi_link);
+ dep->ipi_priority = I915_PRIORITY_INVALID;
dep->signaler = signal;
dep->waiter = node;
dep->flags = flags;
@@ -505,6 +497,12 @@ void i915_sched_node_retire(struct i915_sched_node *node)
GEM_BUG_ON(dep->signaler != node);
+ if (unlikely(!list_empty(&dep->ipi_link))) {
+ spin_lock(&ipi_lock);
+ list_del(&dep->ipi_link);
+ spin_unlock(&ipi_lock);
+ }
+
w = READ_ONCE(dep->waiter);
if (w) {
spin_lock_nested(&w->lock, SINGLE_DEPTH_NESTING);
diff --git a/drivers/gpu/drm/i915/i915_scheduler_types.h b/drivers/gpu/drm/i915/i915_scheduler_types.h
index 3246430eb1c1..ce60577df2bf 100644
--- a/drivers/gpu/drm/i915/i915_scheduler_types.h
+++ b/drivers/gpu/drm/i915/i915_scheduler_types.h
@@ -63,7 +63,8 @@ struct i915_sched_node {
spinlock_t lock; /* protect the lists */
struct list_head signalers_list; /* those before us, we depend upon */
struct list_head waiters_list; /* those after us, they depend upon us */
- struct list_head link;
+ struct list_head link; /* guarded by engine->active.lock */
+ struct list_head dfs; /* guarded by engine->active.lock */
struct i915_sched_attr attr;
unsigned int flags;
#define I915_SCHED_HAS_EXTERNAL_CHAIN BIT(0)
@@ -75,11 +76,12 @@ struct i915_dependency {
struct i915_sched_node *waiter;
struct list_head signal_link;
struct list_head wait_link;
- struct list_head dfs_link;
+ struct list_head ipi_link;
unsigned long flags;
#define I915_DEPENDENCY_ALLOC BIT(0)
#define I915_DEPENDENCY_EXTERNAL BIT(1)
#define I915_DEPENDENCY_WEAK BIT(2)
+ int ipi_priority;
};
#define for_each_waiter(p__, rq__) \
--
2.20.1
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx
^ permalink raw reply related
* [Intel-gfx] [PATCH 07/28] drm/i915/gt: Decouple inflight virtual engines
From: Chris Wilson @ 2020-06-07 22:20 UTC (permalink / raw)
To: intel-gfx; +Cc: Chris Wilson
In-Reply-To: <20200607222108.14401-1-chris@chris-wilson.co.uk>
Once a virtual engine has been bound to a sibling, it will remain bound
until we finally schedule out the last active request. We can not rebind
the context to a new sibling while it is inflight as the context save
will conflict, hence we wait. As we cannot then use any other sibliing
while the context is inflight, only kick the bound sibling while it
inflight and upon scheduling out the kick the rest (so that we can swap
engines on timeslicing if the previously bound engine becomes
oversubscribed).
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
---
drivers/gpu/drm/i915/gt/intel_lrc.c | 30 +++++++++++++----------------
1 file changed, 13 insertions(+), 17 deletions(-)
diff --git a/drivers/gpu/drm/i915/gt/intel_lrc.c b/drivers/gpu/drm/i915/gt/intel_lrc.c
index ab1f3131b357..d98e37900171 100644
--- a/drivers/gpu/drm/i915/gt/intel_lrc.c
+++ b/drivers/gpu/drm/i915/gt/intel_lrc.c
@@ -1403,9 +1403,8 @@ execlists_schedule_in(struct i915_request *rq, int idx)
static void kick_siblings(struct i915_request *rq, struct intel_context *ce)
{
struct virtual_engine *ve = container_of(ce, typeof(*ve), context);
- struct i915_request *next = READ_ONCE(ve->request);
- if (next == rq || (next && next->execution_mask & ~rq->execution_mask))
+ if (READ_ONCE(ve->request))
tasklet_hi_schedule(&ve->base.execlists.tasklet);
}
@@ -1820,18 +1819,14 @@ first_virtual_engine(struct intel_engine_cs *engine)
rb_entry(rb, typeof(*ve), nodes[engine->id].rb);
struct i915_request *rq = READ_ONCE(ve->request);
- if (!rq) { /* lazily cleanup after another engine handled rq */
+ /* lazily cleanup after another engine handled rq */
+ if (!rq || !virtual_matches(ve, rq, engine)) {
rb_erase_cached(rb, &el->virtual);
RB_CLEAR_NODE(rb);
rb = rb_first_cached(&el->virtual);
continue;
}
- if (!virtual_matches(ve, rq, engine)) {
- rb = rb_next(rb);
- continue;
- }
-
return ve;
}
@@ -5469,7 +5464,6 @@ static void virtual_submission_tasklet(unsigned long data)
if (unlikely(!mask))
return;
- local_irq_disable();
for (n = 0; n < ve->num_siblings; n++) {
struct intel_engine_cs *sibling = READ_ONCE(ve->siblings[n]);
struct ve_node * const node = &ve->nodes[sibling->id];
@@ -5479,20 +5473,19 @@ static void virtual_submission_tasklet(unsigned long data)
if (!READ_ONCE(ve->request))
break; /* already handled by a sibling's tasklet */
+ spin_lock_irq(&sibling->active.lock);
+
if (unlikely(!(mask & sibling->mask))) {
if (!RB_EMPTY_NODE(&node->rb)) {
- spin_lock(&sibling->active.lock);
rb_erase_cached(&node->rb,
&sibling->execlists.virtual);
RB_CLEAR_NODE(&node->rb);
- spin_unlock(&sibling->active.lock);
}
- continue;
- }
- spin_lock(&sibling->active.lock);
+ goto unlock_engine;
+ }
- if (!RB_EMPTY_NODE(&node->rb)) {
+ if (unlikely(!RB_EMPTY_NODE(&node->rb))) {
/*
* Cheat and avoid rebalancing the tree if we can
* reuse this node in situ.
@@ -5532,9 +5525,12 @@ static void virtual_submission_tasklet(unsigned long data)
if (first && prio > sibling->execlists.queue_priority_hint)
tasklet_hi_schedule(&sibling->execlists.tasklet);
- spin_unlock(&sibling->active.lock);
+unlock_engine:
+ spin_unlock_irq(&sibling->active.lock);
+
+ if (intel_context_inflight(&ve->context))
+ break;
}
- local_irq_enable();
}
static void virtual_submit_request(struct i915_request *rq)
--
2.20.1
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx
^ permalink raw reply related
* [Intel-gfx] [PATCH 02/28] drm/i915/selftests: Make the hanging request non-preemptible
From: Chris Wilson @ 2020-06-07 22:20 UTC (permalink / raw)
To: intel-gfx; +Cc: Chris Wilson
In-Reply-To: <20200607222108.14401-1-chris@chris-wilson.co.uk>
In some of our hangtests, we try to reset an active engine while it is
spinning inside the recursive spinner. However, we also try to flood the
engine with requests that preempt the hang, and so should disable the
preemption to be sure that we reset the right request.
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
---
drivers/gpu/drm/i915/gt/selftest_hangcheck.c | 36 ++++++++++++++------
1 file changed, 26 insertions(+), 10 deletions(-)
diff --git a/drivers/gpu/drm/i915/gt/selftest_hangcheck.c b/drivers/gpu/drm/i915/gt/selftest_hangcheck.c
index 4aa4cc917d8b..035f363fb0f8 100644
--- a/drivers/gpu/drm/i915/gt/selftest_hangcheck.c
+++ b/drivers/gpu/drm/i915/gt/selftest_hangcheck.c
@@ -203,12 +203,12 @@ hang_create_request(struct hang *h, struct intel_engine_cs *engine)
*batch++ = lower_32_bits(hws_address(hws, rq));
*batch++ = upper_32_bits(hws_address(hws, rq));
*batch++ = rq->fence.seqno;
- *batch++ = MI_ARB_CHECK;
+ *batch++ = MI_NOOP;
memset(batch, 0, 1024);
batch += 1024 / sizeof(*batch);
- *batch++ = MI_ARB_CHECK;
+ *batch++ = MI_NOOP;
*batch++ = MI_BATCH_BUFFER_START | 1 << 8 | 1;
*batch++ = lower_32_bits(vma->node.start);
*batch++ = upper_32_bits(vma->node.start);
@@ -217,12 +217,12 @@ hang_create_request(struct hang *h, struct intel_engine_cs *engine)
*batch++ = 0;
*batch++ = lower_32_bits(hws_address(hws, rq));
*batch++ = rq->fence.seqno;
- *batch++ = MI_ARB_CHECK;
+ *batch++ = MI_NOOP;
memset(batch, 0, 1024);
batch += 1024 / sizeof(*batch);
- *batch++ = MI_ARB_CHECK;
+ *batch++ = MI_NOOP;
*batch++ = MI_BATCH_BUFFER_START | 1 << 8;
*batch++ = lower_32_bits(vma->node.start);
} else if (INTEL_GEN(gt->i915) >= 4) {
@@ -230,24 +230,24 @@ hang_create_request(struct hang *h, struct intel_engine_cs *engine)
*batch++ = 0;
*batch++ = lower_32_bits(hws_address(hws, rq));
*batch++ = rq->fence.seqno;
- *batch++ = MI_ARB_CHECK;
+ *batch++ = MI_NOOP;
memset(batch, 0, 1024);
batch += 1024 / sizeof(*batch);
- *batch++ = MI_ARB_CHECK;
+ *batch++ = MI_NOOP;
*batch++ = MI_BATCH_BUFFER_START | 2 << 6;
*batch++ = lower_32_bits(vma->node.start);
} else {
*batch++ = MI_STORE_DWORD_IMM | MI_MEM_VIRTUAL;
*batch++ = lower_32_bits(hws_address(hws, rq));
*batch++ = rq->fence.seqno;
- *batch++ = MI_ARB_CHECK;
+ *batch++ = MI_NOOP;
memset(batch, 0, 1024);
batch += 1024 / sizeof(*batch);
- *batch++ = MI_ARB_CHECK;
+ *batch++ = MI_NOOP;
*batch++ = MI_BATCH_BUFFER_START | 2 << 6;
*batch++ = lower_32_bits(vma->node.start);
}
@@ -866,13 +866,29 @@ static int __igt_reset_engines(struct intel_gt *gt,
count++;
if (rq) {
+ if (rq->fence.error != -EIO) {
+ pr_err("i915_reset_engine(%s:%s):"
+ " failed to reset request %llx:%lld\n",
+ engine->name, test_name,
+ rq->fence.context,
+ rq->fence.seqno);
+ i915_request_put(rq);
+
+ GEM_TRACE_DUMP();
+ intel_gt_set_wedged(gt);
+ err = -EIO;
+ break;
+ }
+
if (i915_request_wait(rq, 0, HZ / 5) < 0) {
struct drm_printer p =
drm_info_printer(gt->i915->drm.dev);
pr_err("i915_reset_engine(%s:%s):"
- " failed to complete request after reset\n",
- engine->name, test_name);
+ " failed to complete request %llx:%lld after reset\n",
+ engine->name, test_name,
+ rq->fence.context,
+ rq->fence.seqno);
intel_engine_dump(engine, &p,
"%s\n", engine->name);
i915_request_put(rq);
--
2.20.1
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx
^ permalink raw reply related
* Re: [PATCH v4 11/15] commit-graph: add --changed-paths option to write subcommand
From: SZEDER Gábor @ 2020-06-07 22:21 UTC (permalink / raw)
To: Garima Singh via GitGitGadget; +Cc: git, stolee, jonathantanmy, Garima Singh
In-Reply-To: <c8b86c383abdbbd31ba307eb7e79942ddde1b711.1586192395.git.gitgitgadget@gmail.com>
On Mon, Apr 06, 2020 at 04:59:51PM +0000, Garima Singh via GitGitGadget wrote:
> From: Garima Singh <garima.singh@microsoft.com>
>
> Add --changed-paths option to git commit-graph write. This option will
> allow users to compute information about the paths that have changed
> between a commit and its first parent, and write it into the commit graph
> file. If the option is passed to the write subcommand we set the
> COMMIT_GRAPH_WRITE_BLOOM_FILTERS flag and pass it down to the
> commit-graph logic.
>
> Helped-by: Derrick Stolee <dstolee@microsoft.com>
> Signed-off-by: Garima Singh <garima.singh@microsoft.com>
> ---
> Documentation/git-commit-graph.txt | 5 +++++
> builtin/commit-graph.c | 9 +++++++--
> 2 files changed, 12 insertions(+), 2 deletions(-)
>
> diff --git a/Documentation/git-commit-graph.txt b/Documentation/git-commit-graph.txt
> index 28d1fee5053..f4b13c005b8 100644
> --- a/Documentation/git-commit-graph.txt
> +++ b/Documentation/git-commit-graph.txt
> @@ -57,6 +57,11 @@ or `--stdin-packs`.)
> With the `--append` option, include all commits that are present in the
> existing commit-graph file.
> +
> +With the `--changed-paths` option, compute and write information about the
> +paths changed between a commit and it's first parent. This operation can
> +take a while on large repositories. It provides significant performance gains
> +for getting history of a directory or a file with `git log -- <path>`.
So 'git commit-graph write' only computes and writes changed path
Bloom filters if this option is specified. Though not mentioned in
the documentation or in the commit message, the negated
'--no-changed-paths' is supported as well, and it removes Bloom
filters from the commit-graph file. All this is quite reasonable.
However, the most important question is what happens when the
commit-graph file already contains Bloom filters and neither of these
options are specified on the command line. This isn't mentioned in
the docs or in the commit message, either, but as it is implemented in
this patch (i.e. COMMIT_GRAPH_WRITE_BLOOM_FILTERS is not passed from
the builtin to the commit-graph logic) all those existing Bloom
filters are removed from the commit-graph. Considering how expensive
it was to compute those Bloom filters this might not be the most
desirable behaviour.
This is important, because 'git commit-graph write' is not the only
command that writes the commit-graph file. 'git gc' does that by
default, too, and will wipe out any modified path Bloom filters while
doing so. Worse, the user doesn't even have to invoke 'git gc'
manually, because a lot of git commands invoke 'git gc --auto'.
$ git commit-graph write --reachable --changed-paths
$ ~/src/git/t/helper/test-tool read-graph |grep ^chunks
chunks: oid_fanout oid_lookup commit_metadata bloom_indexes bloom_data
$ git gc --quiet
$ ~/src/git/t/helper/test-tool read-graph |grep ^chunks
chunks: oid_fanout oid_lookup commit_metadata
Consequently, if users want to use modified path Bloom filters, then
they should avoid gc, both manual and auto, or they'll have to
re-generate the Bloom filters every once in a while. That is
definitely not the desired behaviour.
Now compare this e.g. to the behaviour of 'git update-index
--split-index' and '--untracked-cache': both of these options turn on
features that improve performance and write extra stuff to the index,
and after they did so all subsequent git commands updating the index
will keep writing that extra stuff, including 'git update-index'
itself even without those options, until it's finally invoked with the
corresponding '--no-...' option. I particularly like how
'--[no-]untracked-cache' and 'core.untrackedCache' work together and
warn when the given command line option goes against the configured
value, and I think the command line options and configuration
variables controlling modified path Bloom filters should behave
similarly.
> With the `--split` option, write the commit-graph as a chain of multiple
> commit-graph files stored in `<dir>/info/commit-graphs`. The new commits
> not already in the commit-graph are added in a new "tip" file. This file
> diff --git a/builtin/commit-graph.c b/builtin/commit-graph.c
> index d1ab6625f63..cacb5d04a80 100644
> --- a/builtin/commit-graph.c
> +++ b/builtin/commit-graph.c
> @@ -9,7 +9,7 @@
>
> static char const * const builtin_commit_graph_usage[] = {
> N_("git commit-graph verify [--object-dir <objdir>] [--shallow] [--[no-]progress]"),
> - N_("git commit-graph write [--object-dir <objdir>] [--append|--split] [--reachable|--stdin-packs|--stdin-commits] [--[no-]progress] <split options>"),
> + N_("git commit-graph write [--object-dir <objdir>] [--append|--split] [--reachable|--stdin-packs|--stdin-commits] [--changed-paths] [--[no-]progress] <split options>"),
> NULL
> };
>
> @@ -19,7 +19,7 @@ static const char * const builtin_commit_graph_verify_usage[] = {
> };
>
> static const char * const builtin_commit_graph_write_usage[] = {
> - N_("git commit-graph write [--object-dir <objdir>] [--append|--split] [--reachable|--stdin-packs|--stdin-commits] [--[no-]progress] <split options>"),
> + N_("git commit-graph write [--object-dir <objdir>] [--append|--split] [--reachable|--stdin-packs|--stdin-commits] [--changed-paths] [--[no-]progress] <split options>"),
> NULL
> };
>
> @@ -32,6 +32,7 @@ static struct opts_commit_graph {
> int split;
> int shallow;
> int progress;
> + int enable_changed_paths;
> } opts;
>
> static struct object_directory *find_odb(struct repository *r,
> @@ -135,6 +136,8 @@ static int graph_write(int argc, const char **argv)
> N_("start walk at commits listed by stdin")),
> OPT_BOOL(0, "append", &opts.append,
> N_("include all commits already in the commit-graph file")),
> + OPT_BOOL(0, "changed-paths", &opts.enable_changed_paths,
> + N_("enable computation for changed paths")),
> OPT_BOOL(0, "progress", &opts.progress, N_("force progress reporting")),
> OPT_BOOL(0, "split", &opts.split,
> N_("allow writing an incremental commit-graph file")),
> @@ -168,6 +171,8 @@ static int graph_write(int argc, const char **argv)
> flags |= COMMIT_GRAPH_WRITE_SPLIT;
> if (opts.progress)
> flags |= COMMIT_GRAPH_WRITE_PROGRESS;
> + if (opts.enable_changed_paths)
> + flags |= COMMIT_GRAPH_WRITE_BLOOM_FILTERS;
>
> read_replace_refs = 0;
> odb = find_odb(the_repository, opts.obj_dir);
> --
> gitgitgadget
>
^ permalink raw reply
* Re: [PATCH] net: tulip: Set PCI revision to match dec21143
From: Philippe Mathieu-Daudé @ 2020-06-07 22:17 UTC (permalink / raw)
To: Marek Vasut, qemu-devel, Sven Schnelle
Cc: Peter Maydell, Marek Vasut, Prasad J Pandit,
Marc-André Lureau, Paolo Bonzini
In-Reply-To: <20200418002552.343480-1-marek.vasut+renesas@gmail.com>
Hi Sven, could you review thiw one-line patch?
On 4/18/20 2:25 AM, Marek Vasut wrote:
> The tulip driver claims to emulate dec21143 and it does not emulate dec21142.
> The dec21142 and dec21143 can be discerned by the PCI revision register,
> where dec21142 reports value < 0x20 and dec21143 value >= 0x20. E.g. the
> U-Boot 'tulip' driver also only supports dec21143 and verifies that the
> PCI revision ID is >= 0x20, otherwise refuses to operate such a card.
>
> This patch sets the PCI revision ID to 0x20 to match the dec21143 and
> thus also permits e.g. U-Boot to work with the tulip emulation.
>
> Fixes: 34ea023d4b95 ("net: add tulip (dec21143) driver")
> Signed-off-by: Marek Vasut <marek.vasut+renesas@gmail.com>
> Cc: Marc-André Lureau <marcandre.lureau@redhat.com>
> Cc: Paolo Bonzini <pbonzini@redhat.com>
> Cc: Peter Maydell <peter.maydell@linaro.org>
> Cc: Prasad J Pandit <pjp@fedoraproject.org>
> Cc: Sven Schnelle <svens@stackframe.org>
> ---
> hw/net/tulip.c | 2 ++
> 1 file changed, 2 insertions(+)
>
> diff --git a/hw/net/tulip.c b/hw/net/tulip.c
> index 1295f51d07..ffb6c2479a 100644
> --- a/hw/net/tulip.c
> +++ b/hw/net/tulip.c
> @@ -962,6 +962,8 @@ static void pci_tulip_realize(PCIDevice *pci_dev, Error **errp)
>
> pci_conf = s->dev.config;
> pci_conf[PCI_INTERRUPT_PIN] = 1; /* interrupt pin A */
> + /* Anything with revision < 0x20 is DC21142, anything >= 0x20 is DC21143 */
> + pci_conf[PCI_REVISION_ID] = 0x20;
>
> s->eeprom = eeprom93xx_new(&pci_dev->qdev, 64);
> tulip_fill_eeprom(s);
>
^ permalink raw reply
* [PATCH v2] IMA: Add audit log for failure conditions
From: Lakshmi Ramasubramanian @ 2020-06-07 22:14 UTC (permalink / raw)
To: zohar, paul; +Cc: linux-integrity, linux-audit, linux-kernel
The final log statement in process_buffer_measurement() for failure
condition is at debug level. This does not log the message unless
the system log level is raised which would significantly increase
the messages in the system log. Change this log message to an audit
message for better triaging failures in the function.
ima_alloc_key_entry() does not log a message for failure condition.
Add an audit message for failure condition in this function.
Signed-off-by: Lakshmi Ramasubramanian <nramas@linux.microsoft.com>
---
security/integrity/ima/ima_main.c | 17 ++++++++++++-----
security/integrity/ima/ima_queue_keys.c | 4 ++++
2 files changed, 16 insertions(+), 5 deletions(-)
diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
index 800fb3bba418..1225198fceb1 100644
--- a/security/integrity/ima/ima_main.c
+++ b/security/integrity/ima/ima_main.c
@@ -739,6 +739,7 @@ void process_buffer_measurement(const void *buf, int size,
int pcr, const char *keyring)
{
int ret = 0;
+ const char *audit_cause = "ENOMEM";
struct ima_template_entry *entry = NULL;
struct integrity_iint_cache iint = {};
struct ima_event_data event_data = {.iint = &iint,
@@ -793,21 +794,27 @@ void process_buffer_measurement(const void *buf, int size,
iint.ima_hash->length = hash_digest_size[ima_hash_algo];
ret = ima_calc_buffer_hash(buf, size, iint.ima_hash);
- if (ret < 0)
+ if (ret < 0) {
+ audit_cause = "calc_buffer_hash";
goto out;
+ }
ret = ima_alloc_init_template(&event_data, &entry, template);
- if (ret < 0)
+ if (ret < 0) {
+ audit_cause = "alloc_init_template";
goto out;
+ }
ret = ima_store_template(entry, violation, NULL, buf, pcr);
-
- if (ret < 0)
+ if (ret < 0) {
+ audit_cause = "store_template";
ima_free_template_entry(entry);
+ }
out:
if (ret < 0)
- pr_devel("%s: failed, result: %d\n", __func__, ret);
+ integrity_audit_msg(AUDIT_INTEGRITY_PCR, NULL, eventname,
+ __func__, audit_cause, ret, 0);
return;
}
diff --git a/security/integrity/ima/ima_queue_keys.c b/security/integrity/ima/ima_queue_keys.c
index cb3e3f501593..fa606ce68f87 100644
--- a/security/integrity/ima/ima_queue_keys.c
+++ b/security/integrity/ima/ima_queue_keys.c
@@ -68,6 +68,7 @@ static struct ima_key_entry *ima_alloc_key_entry(struct key *keyring,
size_t payload_len)
{
int rc = 0;
+ const char *audit_cause = "ENOMEM";
struct ima_key_entry *entry;
entry = kzalloc(sizeof(*entry), GFP_KERNEL);
@@ -88,6 +89,9 @@ static struct ima_key_entry *ima_alloc_key_entry(struct key *keyring,
out:
if (rc) {
+ integrity_audit_msg(AUDIT_INTEGRITY_PCR, NULL,
+ keyring->description, __func__,
+ audit_cause, rc, 0);
ima_free_key_entry(entry);
entry = NULL;
}
--
2.27.0
^ permalink raw reply related
* Re: [Intel-gfx] [PATCH RESEND v3 1/3] drm/i915/dp_mst: Fix disabling MST on a port
From: Souza, Jose @ 2020-06-07 22:11 UTC (permalink / raw)
To: intel-gfx@lists.freedesktop.org, Deak, Imre
In-Reply-To: <20200605094801.17709-1-imre.deak@intel.com>
On Fri, 2020-06-05 at 12:48 +0300, Imre Deak wrote:
> Currently MST on a port can get enabled/disabled from the hotplug work
> and get disabled from the short pulse work in a racy way. Fix this by
> relying on the MST state checking in the hotplug work and just schedule
> a hotplug work from the short pulse handler if some problem happened
> during the MST interrupt handling.
>
> This removes the explicit MST disabling in case of an AUX failure, but
> if AUX fails, then probably the detection will also fail during the
> scheduled hotplug work and it's not guaranteed that we'll see
> intermittent errors anyway.
>
> While at it also simplify the error checking of the MST interrupt
> handler.
>
> v2:
> - Convert intel_dp_check_mst_status() to return bool. (Ville)
> - Change the intel_dp->is_mst check to an assert, since after this patch
> the condition can't change after we checked it previously.
> - Document the return value from intel_dp_check_mst_status().
> v3:
> - Remove the intel_dp->is_mst check from intel_dp_check_mst_status().
> There is no point in checking the same condition twice, even though
> there is a chance that the hotplug work running concurrently changes
> it.
>
> Cc: José Roberto de Souza <jose.souza@intel.com>
> Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
> Reviewed-by: José Roberto de Souza <jose.souza@intel.com> (v1)
> Signed-off-by: Imre Deak <imre.deak@intel.com>
> ---
> drivers/gpu/drm/i915/display/intel_dp.c | 66 ++++++++++---------------
> 1 file changed, 26 insertions(+), 40 deletions(-)
>
> diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c
> index 55fda074c0ad..42589cae766d 100644
> --- a/drivers/gpu/drm/i915/display/intel_dp.c
> +++ b/drivers/gpu/drm/i915/display/intel_dp.c
> @@ -5556,35 +5556,46 @@ static void intel_dp_handle_test_request(struct intel_dp *intel_dp)
> "Could not write test response to sink\n");
> }
>
> -static int
> +/**
> + * intel_dp_check_mst_status - service any pending MST interrupts, check link status
> + * @intel_dp: Intel DP struct
> + *
> + * Read any pending MST interrupts, call MST core to handle these and ack the
> + * interrupts. Check if the main and AUX link state is ok.
> + *
> + * Returns:
> + * - %true if pending interrupts were serviced (or no interrupts were
> + * pending) w/o detecting an error condition.
> + * - %false if an error condition - like AUX failure or a loss of link - is
> + * detected, which needs servicing from the hotplug work.
> + */
> +static bool
> intel_dp_check_mst_status(struct intel_dp *intel_dp)
> {
> struct drm_i915_private *i915 = dp_to_i915(intel_dp);
> - bool need_retrain = false;
> -
> - if (!intel_dp->is_mst)
> - return -EINVAL;
> + bool link_ok = true;
>
> drm_WARN_ON_ONCE(&i915->drm, intel_dp->active_mst_links < 0);
>
> for (;;) {
> u8 esi[DP_DPRX_ESI_LEN] = {};
> - bool bret, handled;
> + bool handled;
> int retry;
>
> - bret = intel_dp_get_sink_irq_esi(intel_dp, esi);
> - if (!bret) {
> + if (!intel_dp_get_sink_irq_esi(intel_dp, esi)) {
> drm_dbg_kms(&i915->drm,
> "failed to get ESI - device may have failed\n");
> - return -EINVAL;
> + link_ok = false;
> +
> + break;
> }
>
> /* check link status - esi[10] = 0x200c */
> - if (intel_dp->active_mst_links > 0 && !need_retrain &&
> + if (intel_dp->active_mst_links > 0 && link_ok &&
> !drm_dp_channel_eq_ok(&esi[10], intel_dp->lane_count)) {
> drm_dbg_kms(&i915->drm,
> "channel EQ not ok, retraining\n");
> - need_retrain = true;
> + link_ok = false;
> }
>
> drm_dbg_kms(&i915->drm, "got esi %3ph\n", esi);
> @@ -5604,7 +5615,7 @@ intel_dp_check_mst_status(struct intel_dp *intel_dp)
> }
> }
>
> - return need_retrain;
> + return link_ok;
> }
>
> static bool
> @@ -7255,35 +7266,10 @@ intel_dp_hpd_pulse(struct intel_digital_port *intel_dig_port, bool long_hpd)
> }
>
> if (intel_dp->is_mst) {
> - switch (intel_dp_check_mst_status(intel_dp)) {
> - case -EINVAL:
> - /*
> - * If we were in MST mode, and device is not
> - * there, get out of MST mode
> - */
> - drm_dbg_kms(&i915->drm,
> - "MST device may have disappeared %d vs %d\n",
> - intel_dp->is_mst,
> - intel_dp->mst_mgr.mst_state);
> - intel_dp->is_mst = false;
> - drm_dp_mst_topology_mgr_set_mst(&intel_dp->mst_mgr,
> - intel_dp->is_mst);
> -
> - return IRQ_NONE;
> - case 1:
> - return IRQ_NONE;
> - default:
> - break;
> - }
> - }
> -
> - if (!intel_dp->is_mst) {
> - bool handled;
> -
> - handled = intel_dp_short_pulse(intel_dp);
> -
> - if (!handled)
> + if (!intel_dp_check_mst_status(intel_dp))
> return IRQ_NONE;
> + } else if (!intel_dp_short_pulse(intel_dp)) {
> + return IRQ_NONE;
> }
>
Now it don't need the braces but this is minor.
Reviewed-by: José Roberto de Souza <jose.souza@intel.com>
> return IRQ_HANDLED;
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx
^ permalink raw reply
* [GIT PULL] Pin control bulk changes for the v5.8 cycle
From: Linus Walleij @ 2020-06-07 22:08 UTC (permalink / raw)
To: Linus Torvalds; +Cc: linux-kernel, open list:GPIO SUBSYSTEM
Hi Linus,
this is the bulk of pin control changes for the v5.8 kernel
cycle.
It's just really boring this time. Zero core changes. Just linear
development, cleanups and misc noncritical fixes. Some new
drivers for very new Qualcomm and Intel chips.
Please pull it in!
Yours,
Linus Walleij
The following changes since commit 8f3d9f354286745c751374f5f1fcafee6b3f3136:
Linux 5.7-rc1 (2020-04-12 12:35:55 -0700)
are available in the Git repository at:
git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-pinctrl.git
tags/pinctrl-v5.8-1
for you to fetch changes up to 94873f6b46f8c103759c28adc121a58022972d01:
pinctrl: sprd: Fix the incorrect pull-up definition (2020-06-04
00:15:20 +0200)
----------------------------------------------------------------
This is the bulk of pin control changes for the v5.8
kernel cycle.
New drivers:
- Intel Jasper Lake support.
- NXP Freescale i.MX8DXL support.
- Qualcomm SM8250 support.
- Renesas R8A7742 SH-PFC support.
Driver improvements:
- Severe cleanup and modernization of the MCP23s08 driver.
- Mediatek driver modularized.
- Setting config supported in the Meson driver.
- Wakeup support for the Broadcom BCM7211.
----------------------------------------------------------------
Amelie Delaunay (1):
pinctrl: stmfx: stmfx_pinconf_set doesn't require to get direction anymore
Andy Shevchenko (23):
pinctrl: sunrisepoint: Fix PAD lock register offset for SPT-H
pinctrl: baytrail: Enable pin configuration setting for GPIO chip
pinctrl: cherryview: Re-use data structures from pinctrl-intel.h (part 2)
pinctrl: cherryview: Use GENMASK() consistently
pinctrl: intel: Introduce common flags for GPIO mapping scheme
pinctrl: cannonlake: Use generic flag for special GPIO base treatment
pinctrl: icelake: Use generic flag for special GPIO base treatment
pinctrl: tigerlake: Use generic flag for special GPIO base treatment
pinctrl: intel: Introduce new flag to force GPIO base to be 0
pinctrl: intel: Add Intel Jasper Lake pin controller support
pinctrl: baytrail: Use platform_get_irq_optional() explicitly
pinctrl: mcp23s08: Get rid of legacy platform data
pinctrl: mcp23s08: Deduplicate IRQ chip filling
pinctrl: mcp23s08: Consolidate SPI and I²C code
pinctrl: mcp23s08: Drop unused parameter in mcp23s08_probe_one()
pinctrl: mcp23s08: Refactor mcp23s08_spi_regmap_init()
pinctrl: mcp23s08: Propagate error code from device_property_read_u32()
pinctrl: mcp23s08: Make use of device properties
pinctrl: mcp23s08: Use for_each_set_bit() and hweight_long()
pinctrl: mcp23s08: Split to three parts: core, I²C, SPI
pinctrl: lynxpoint: Use platform_get_irq_optional() explicitly
pinctrl: intel: Update description in struct intel_community
pinctrl: intel: Move npins closer to pin_base in struct intel_community
Anson Huang (2):
dt-bindings: arm: fsl-scu: Add imx8dxl pinctrl support
pinctrl: imx: Add imx8dxl driver
Arnd Bergmann (1):
pinctrl: mediatek: add pinctrl-mtk-common-v2 module license
Baolin Wang (1):
pinctrl: sprd: Fix the incorrect pull-up definition
Benjamin Gaignard (1):
dt-bindings: pinctrl: stm32: Add missing interrupts property
Bjorn Andersson (1):
dt-bindings: pinctrl: qcom: Add sm8250 pinctrl bindings
Christophe JAILLET (4):
pinctrl: imxl: Fix an error handling path in 'imx1_pinctrl_core_probe()'
pinctrl: freescale: imx: Fix an error handling path in
'imx_pinctrl_probe()'
pinctrl: freescale: imx: Use 'devm_of_iomap()' to avoid a
resource leak in case of error in 'imx_pinctrl_probe()'
pinctrl: pxa: pxa2xx: Remove 'pxa2xx_pinctrl_exit()' which is
unused and broken
Corentin Labbe (1):
pinctrl: sunxi: handle probe defferal
Dafna Hirschfeld (2):
pinctrl: rockchip: return ENOMEM instead of EINVAL if allocation fails
pinctrl: rockchip: fix memleak in rockchip_dt_node_to_map
Dejin Zheng (1):
pinctrl: fix several typos
Ding Xiang (1):
pinctrl: nomadik:remove unneeded variable
Florian Fainelli (4):
dt-bindings: pinctrl: Document 7211 compatible for brcm, bcm2835-gpio.txt
dt-bindings: pinctrl: Document optional BCM7211 wake-up interrupts
pinctrl: bcm2835: Match BCM7211 compatible string
pinctrl: bcm2835: Add support for wake-up interrupts
Geert Uytterhoeven (5):
MAINTAINERS: Add DT Bindings for Renesas Pin Function Controllers
pinctrl: rza1: Fix flag name in comment
pinctrl: equilibrium: Add architecture dependency
pinctrl: amd: Add ACPI dependency
MAINTAINERS: Renesas Pin Controllers are supported
Grace Kao (1):
pinctrl: cherryview: Add missing spinlock usage in chv_gpio_irq_handler
Jason Yan (3):
pinctrl: mcp23s08: add module license
pinctrl: rza1: Fix wrong array assignment of rza1l_swio_entries
pinctrl: bm1880: add pwm37 to bm1880_pctrl_groups
Johan Jonker (1):
dt-bindings: pinctrl: rockchip: update example
Jonathan Bakker (2):
pinctrl: samsung: Correct setting of eint wakeup mask on s5pv210
pinctrl: samsung: Save/restore eint_mask over suspend for EINT_TYPE GPIOs
Lad Prabhakar (2):
dt-bindings: pinctrl: sh-pfc: Document r8a7742 PFC support
pinctrl: sh-pfc: r8a7790: Add r8a7742 PFC support
Lars Povlsen (4):
pinctrl: ocelot: Always register GPIO driver
pinctrl: ocelot: Remove instance number from pin functions
pinctrl: ocelot: Fix GPIO interrupt decoding on Jaguar2
dt-bindings: pinctrl: ocelot: Add Sparx5 SoC support
Light Hsieh (2):
pinctrl: mediatek: make MediaTek pinctrl v2 driver ready for
buidling loadable module
pinctrl: mediatek: make MediaTek MT6765 pinctrl ready for
buiding loadable module
Linus Walleij (6):
pinctrl: ab8505: Define group for GPIO pin 50
pinctrl: db8500: Fix some old bugs
Merge tag 'sh-pfc-for-v5.8-tag1' of
git://git.kernel.org/.../geert/renesas-drivers into devel
Merge tag 'intel-pinctrl-v5.8-1' of
git://git.kernel.org/.../pinctrl/intel into devel
Merge tag 'samsung-pinctrl-5.8' of
https://git.kernel.org/.../pinctrl/samsung into devel
Merge tag 'sh-pfc-for-v5.8-tag2' of
git://git.kernel.org/.../geert/renesas-drivers into devel
Martin Blumenstingl (2):
pinctrl: meson: implement the gpio_chip get_direction callback
pinctrl: meson: wire up the gpio_chip's set_config callback
Paul Cercueil (1):
pinctrl: ingenic: Add irq_{request,release}_resources callbacks
Rikard Falkeborn (1):
pinctrl: rk805: Constify rk805_gpio_cfgs
Tiezhu Yang (2):
pinctrl: Fix return value about devm_platform_ioremap_resource()
pinctrl: at91-pio4: Add COMPILE_TEST support
Venkata Narendra Kumar Gutta (1):
pinctrl: qcom: Add sm8250 pinctrl driver.
YueHaibing (1):
pinctrl: qcom: Remove duplicated include from pinctrl-msm.c
yu kuai (1):
pinctrl: sirf: add missing put_device() call in sirfsoc_gpio_probe()
.../devicetree/bindings/arm/freescale/fsl,scu.txt | 6 +-
.../bindings/pinctrl/brcm,bcm2835-gpio.txt | 5 +-
.../bindings/pinctrl/mscc,ocelot-pinctrl.txt | 4 +-
.../bindings/pinctrl/qcom,sm8250-pinctrl.yaml | 147 +++
.../bindings/pinctrl/renesas,pfc-pinctrl.txt | 1 +
.../bindings/pinctrl/rockchip,pinctrl.txt | 4 +-
.../bindings/pinctrl/st,stm32-pinctrl.yaml | 3 +
MAINTAINERS | 3 +-
drivers/pinctrl/Kconfig | 17 +-
drivers/pinctrl/Makefile | 2 +
drivers/pinctrl/bcm/pinctrl-bcm281xx.c | 2 +-
drivers/pinctrl/bcm/pinctrl-bcm2835.c | 80 +-
drivers/pinctrl/freescale/Kconfig | 7 +
drivers/pinctrl/freescale/Makefile | 1 +
drivers/pinctrl/freescale/pinctrl-imx.c | 26 +-
drivers/pinctrl/freescale/pinctrl-imx1-core.c | 3 +-
drivers/pinctrl/freescale/pinctrl-imx8dxl.c | 193 +++
drivers/pinctrl/intel/Kconfig | 8 +
drivers/pinctrl/intel/Makefile | 1 +
drivers/pinctrl/intel/pinctrl-baytrail.c | 10 +-
drivers/pinctrl/intel/pinctrl-cannonlake.c | 58 +-
drivers/pinctrl/intel/pinctrl-cherryview.c | 282 ++--
drivers/pinctrl/intel/pinctrl-icelake.c | 30 +-
drivers/pinctrl/intel/pinctrl-intel.c | 22 +-
drivers/pinctrl/intel/pinctrl-intel.h | 27 +-
drivers/pinctrl/intel/pinctrl-jasperlake.c | 344 +++++
drivers/pinctrl/intel/pinctrl-lynxpoint.c | 10 +-
drivers/pinctrl/intel/pinctrl-sunrisepoint.c | 15 +-
drivers/pinctrl/intel/pinctrl-tigerlake.c | 32 +-
drivers/pinctrl/mediatek/Kconfig | 13 +-
drivers/pinctrl/mediatek/Makefile | 5 +-
drivers/pinctrl/mediatek/mtk-eint.c | 9 +
drivers/pinctrl/mediatek/pinctrl-mt6765.c | 4 +
drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.c | 28 +
drivers/pinctrl/mediatek/pinctrl-paris.c | 6 +
drivers/pinctrl/meson/pinctrl-meson.c | 14 +
drivers/pinctrl/nomadik/pinctrl-ab8505.c | 1 +
drivers/pinctrl/nomadik/pinctrl-nomadik-db8500.c | 6 +-
drivers/pinctrl/nomadik/pinctrl-nomadik.c | 4 +-
drivers/pinctrl/pinctrl-at91-pio4.c | 2 +-
drivers/pinctrl/pinctrl-bm1880.c | 1 +
drivers/pinctrl/pinctrl-ingenic.c | 21 +
drivers/pinctrl/pinctrl-lantiq.c | 2 +-
drivers/pinctrl/pinctrl-mcp23s08.c | 514 +-------
drivers/pinctrl/pinctrl-mcp23s08.h | 52 +
drivers/pinctrl/pinctrl-mcp23s08_i2c.c | 124 ++
drivers/pinctrl/pinctrl-mcp23s08_spi.c | 262 ++++
drivers/pinctrl/pinctrl-ocelot.c | 127 +-
drivers/pinctrl/pinctrl-rk805.c | 4 +-
drivers/pinctrl/pinctrl-rockchip.c | 11 +-
drivers/pinctrl/pinctrl-rza1.c | 4 +-
drivers/pinctrl/pinctrl-stmfx.c | 6 +-
drivers/pinctrl/pinctrl-sx150x.c | 2 +-
drivers/pinctrl/pxa/pinctrl-pxa2xx.c | 9 -
drivers/pinctrl/qcom/Kconfig | 9 +
drivers/pinctrl/qcom/Makefile | 1 +
drivers/pinctrl/qcom/pinctrl-msm.c | 1 -
drivers/pinctrl/qcom/pinctrl-sm8250.c | 1361 ++++++++++++++++++++
drivers/pinctrl/samsung/pinctrl-exynos.c | 82 +-
drivers/pinctrl/sh-pfc/Kconfig | 4 +
drivers/pinctrl/sh-pfc/Makefile | 1 +
drivers/pinctrl/sh-pfc/core.c | 6 +
drivers/pinctrl/sh-pfc/pfc-r8a7790.c | 744 ++++++-----
drivers/pinctrl/sh-pfc/pfc-sh7269.c | 5 +-
drivers/pinctrl/sh-pfc/sh_pfc.h | 1 +
drivers/pinctrl/sirf/pinctrl-sirf.c | 20 +-
drivers/pinctrl/sprd/pinctrl-sprd.c | 4 +-
drivers/pinctrl/sunxi/pinctrl-sun8i-a23-r.c | 7 +-
drivers/pinctrl/tegra/pinctrl-tegra-xusb.c | 2 +-
drivers/pinctrl/zte/pinctrl-zx.c | 2 +-
include/dt-bindings/pinctrl/pads-imx8dxl.h | 639 +++++++++
include/linux/spi/mcp23s08.h | 18 -
72 files changed, 4160 insertions(+), 1321 deletions(-)
create mode 100644
Documentation/devicetree/bindings/pinctrl/qcom,sm8250-pinctrl.yaml
create mode 100644 drivers/pinctrl/freescale/pinctrl-imx8dxl.c
create mode 100644 drivers/pinctrl/intel/pinctrl-jasperlake.c
create mode 100644 drivers/pinctrl/pinctrl-mcp23s08.h
create mode 100644 drivers/pinctrl/pinctrl-mcp23s08_i2c.c
create mode 100644 drivers/pinctrl/pinctrl-mcp23s08_spi.c
create mode 100644 drivers/pinctrl/qcom/pinctrl-sm8250.c
create mode 100644 include/dt-bindings/pinctrl/pads-imx8dxl.h
delete mode 100644 include/linux/spi/mcp23s08.h
^ permalink raw reply
* Re: Expressive limitation: (daddr,dport) <--> (daddr',dport')
From: Pablo Neira Ayuso @ 2020-06-07 22:08 UTC (permalink / raw)
To: Rick van Rein; +Cc: netfilter-devel
In-Reply-To: <5EDC7662.1070002@openfortress.nl>
Hi Rick,
On Sun, Jun 07, 2020 at 07:08:50AM +0200, Rick van Rein wrote:
> Hello,
>
> I seem to be running into an expressive limitation of nft while trying
> to do stateless translation. I prefer statelessness because it it is
> clearer for bidirectionality / peering, and saves lookup times.
>
> After nat64, I have a small set of IPv6 addresses and I would like to
> map their (daddr,dport) or better even (daddr,proto,dport) tuples to
> outgoing (daddr',dport'). Effectively, port forwarding for IPv6.
>
> Individual rules work, like this one side of a bidir portmap:
>
> nft add rule ip6 raw prerouting \
> ip6 daddr $PREFIX::64:75 \
> tcp dport 8080 \
> ip6 daddr set $PREFIX::100:20 \
> tcp dport set 80 \
> notrack
>
> I have problems doing this with the map construct, presumably because it
> does not atomically replace (daddr,dport) by (daddr',dport') but instead
> does two assignments with intermediate alterede state.
Right.
> This is bound to work in many cases, but it can give undesired
> crossover behaviours [namely between incoming IPs if they map to the
> same daddr' while coming from the same dport]:
>
> nft add rule ip6 raw prerouting \
> ip6 daddr set \
> ip6 daddr . tcp dport \
> map { $PREFIX::64:75 . 8080 : $PREFIX::100:20 } \
> tcp dport set \
> ip6 daddr . tcp dport \
> map { $PREFIX::100:20 . 8080 : 80 } \
So, you would consolidate this in one single rule? So there is one
single lookup to obtain the IP address and the destination port for
the stateless packet mangling.
> notrack
>
> So now I am wondering,
>
> 0. Is there a way to use maps as atomic setter for (daddr,dport)?
Not yet.
> 1. Can I reach back to the original value of a just-modified value?
You mean, the original header field that was just mangled? Like
matching on the former IP address before the mangling?
> 2. Is there a variable, or stack, to prepare with the old value?
But this is to achieve the atomic mangling that you describe above or
you have something else in mind? You would like to store the former IP
daddr in some scratchpad area that can be accessed later on, right?
Thanks.
^ permalink raw reply
* [PATCH v2] fs: ocfs2: fix spelling mistake and grammar
From: Keyur Patel @ 2020-06-07 22:07 UTC (permalink / raw)
To: mark, jlbec, joseph.qi, ocfs2-devel, linux-kernel; +Cc: iamkeyur96
In-Reply-To: <20200607212115.99278-1-iamkeyur96@gmail.com>
./ocfs2/mmap.c:65: bebongs ==> belongs
Signed-off-by: Keyur Patel <iamkeyur96@gmail.com>
---
fs/ocfs2/mmap.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/fs/ocfs2/mmap.c b/fs/ocfs2/mmap.c
index 3a44e461828a..39a77e903fdf 100644
--- a/fs/ocfs2/mmap.c
+++ b/fs/ocfs2/mmap.c
@@ -62,7 +62,7 @@ static vm_fault_t __ocfs2_page_mkwrite(struct file *file,
last_index = (size - 1) >> PAGE_SHIFT;
/*
- * There are cases that lead to the page no longer bebongs to the
+ * There are cases that lead to the page no longer belonging to the
* mapping.
* 1) pagecache truncates locally due to memory pressure.
* 2) pagecache truncates when another is taking EX lock against
--
2.26.2
^ permalink raw reply related
* How are you
From: Poan Saman @ 2020-06-07 22:07 UTC (permalink / raw)
To: netdev
Good Day,
I am Miss.Poan and It's my pleasure to come across your contact today,if you don't mind can we chat on Skype or googlehangout/whatsapp to know each other as I have something important to discuss with you.
Miss.Poan Saman
^ permalink raw reply
* [Ocfs2-devel] [PATCH v2] fs: ocfs2: fix spelling mistake and grammar
From: Keyur Patel @ 2020-06-07 22:07 UTC (permalink / raw)
To: mark, jlbec, joseph.qi, ocfs2-devel, linux-kernel; +Cc: iamkeyur96
In-Reply-To: <20200607212115.99278-1-iamkeyur96@gmail.com>
./ocfs2/mmap.c:65: bebongs ==> belongs
Signed-off-by: Keyur Patel <iamkeyur96@gmail.com>
---
fs/ocfs2/mmap.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/fs/ocfs2/mmap.c b/fs/ocfs2/mmap.c
index 3a44e461828a..39a77e903fdf 100644
--- a/fs/ocfs2/mmap.c
+++ b/fs/ocfs2/mmap.c
@@ -62,7 +62,7 @@ static vm_fault_t __ocfs2_page_mkwrite(struct file *file,
last_index = (size - 1) >> PAGE_SHIFT;
/*
- * There are cases that lead to the page no longer bebongs to the
+ * There are cases that lead to the page no longer belonging to the
* mapping.
* 1) pagecache truncates locally due to memory pressure.
* 2) pagecache truncates when another is taking EX lock against
--
2.26.2
^ permalink raw reply related
* [Buildroot] [PATCH v1] configs/raspberrypi*: bump kernel version to 676fd5a
From: Peter Seiderer @ 2020-06-07 22:01 UTC (permalink / raw)
To: buildroot
Now based on 4.19.126 (from 4.19.113).
Signed-off-by: Peter Seiderer <ps.report@gmx.net>
---
Notes:
- fixed compile with gcc-10.1.1 for me:
scripts/dtc/dtc-parser.tab.o:(.bss+0x10): multiple definition of `yylloc'; scripts/dtc/dtc-lexer.lex.o:(.bss+0x0): first defined here
---
configs/raspberrypi0_defconfig | 2 +-
configs/raspberrypi0w_defconfig | 2 +-
configs/raspberrypi2_defconfig | 2 +-
configs/raspberrypi3_64_defconfig | 2 +-
configs/raspberrypi3_defconfig | 2 +-
configs/raspberrypi3_qt5we_defconfig | 2 +-
configs/raspberrypi4_64_defconfig | 2 +-
configs/raspberrypi4_defconfig | 2 +-
configs/raspberrypi_defconfig | 2 +-
9 files changed, 9 insertions(+), 9 deletions(-)
diff --git a/configs/raspberrypi0_defconfig b/configs/raspberrypi0_defconfig
index da20eb4dae..6ad0efc284 100644
--- a/configs/raspberrypi0_defconfig
+++ b/configs/raspberrypi0_defconfig
@@ -9,7 +9,7 @@ BR2_TOOLCHAIN_BUILDROOT_CXX=y
BR2_LINUX_KERNEL=y
BR2_LINUX_KERNEL_CUSTOM_TARBALL=y
-BR2_LINUX_KERNEL_CUSTOM_TARBALL_LOCATION="$(call github,raspberrypi,linux,4f2a4cc501c428c940549f39d5562e60404ac4f7)/linux-4f2a4cc501c428c940549f39d5562e60404ac4f7.tar.gz"
+BR2_LINUX_KERNEL_CUSTOM_TARBALL_LOCATION="$(call github,raspberrypi,linux,676fd5a6f2a9b365da0e0371ef11acbb74cb69d5)/linux-676fd5a6f2a9b365da0e0371ef11acbb74cb69d5.tar.gz"
BR2_LINUX_KERNEL_DEFCONFIG="bcmrpi"
# Build the DTBs for A/B from the kernel sources: the zero is the same
diff --git a/configs/raspberrypi0w_defconfig b/configs/raspberrypi0w_defconfig
index 14a8853117..2023ee4fa5 100644
--- a/configs/raspberrypi0w_defconfig
+++ b/configs/raspberrypi0w_defconfig
@@ -9,7 +9,7 @@ BR2_TOOLCHAIN_BUILDROOT_CXX=y
BR2_LINUX_KERNEL=y
BR2_LINUX_KERNEL_CUSTOM_TARBALL=y
-BR2_LINUX_KERNEL_CUSTOM_TARBALL_LOCATION="$(call github,raspberrypi,linux,4f2a4cc501c428c940549f39d5562e60404ac4f7)/linux-4f2a4cc501c428c940549f39d5562e60404ac4f7.tar.gz"
+BR2_LINUX_KERNEL_CUSTOM_TARBALL_LOCATION="$(call github,raspberrypi,linux,676fd5a6f2a9b365da0e0371ef11acbb74cb69d5)/linux-676fd5a6f2a9b365da0e0371ef11acbb74cb69d5.tar.gz"
BR2_LINUX_KERNEL_DEFCONFIG="bcmrpi"
BR2_LINUX_KERNEL_DTS_SUPPORT=y
BR2_LINUX_KERNEL_INTREE_DTS_NAME="bcm2708-rpi-zero-w"
diff --git a/configs/raspberrypi2_defconfig b/configs/raspberrypi2_defconfig
index c45461d108..7990a2dcf0 100644
--- a/configs/raspberrypi2_defconfig
+++ b/configs/raspberrypi2_defconfig
@@ -12,7 +12,7 @@ BR2_PACKAGE_HOST_LINUX_HEADERS_CUSTOM_4_19=y
BR2_LINUX_KERNEL=y
BR2_LINUX_KERNEL_CUSTOM_TARBALL=y
-BR2_LINUX_KERNEL_CUSTOM_TARBALL_LOCATION="$(call github,raspberrypi,linux,4f2a4cc501c428c940549f39d5562e60404ac4f7)/linux-4f2a4cc501c428c940549f39d5562e60404ac4f7.tar.gz"
+BR2_LINUX_KERNEL_CUSTOM_TARBALL_LOCATION="$(call github,raspberrypi,linux,676fd5a6f2a9b365da0e0371ef11acbb74cb69d5)/linux-676fd5a6f2a9b365da0e0371ef11acbb74cb69d5.tar.gz"
BR2_LINUX_KERNEL_DEFCONFIG="bcm2709"
# Build the DTB from the kernel sources
diff --git a/configs/raspberrypi3_64_defconfig b/configs/raspberrypi3_64_defconfig
index 27bd5aa0bb..3be79a0f63 100644
--- a/configs/raspberrypi3_64_defconfig
+++ b/configs/raspberrypi3_64_defconfig
@@ -11,7 +11,7 @@ BR2_PACKAGE_HOST_LINUX_HEADERS_CUSTOM_4_19=y
BR2_LINUX_KERNEL=y
BR2_LINUX_KERNEL_CUSTOM_TARBALL=y
-BR2_LINUX_KERNEL_CUSTOM_TARBALL_LOCATION="$(call github,raspberrypi,linux,4f2a4cc501c428c940549f39d5562e60404ac4f7)/linux-4f2a4cc501c428c940549f39d5562e60404ac4f7.tar.gz"
+BR2_LINUX_KERNEL_CUSTOM_TARBALL_LOCATION="$(call github,raspberrypi,linux,676fd5a6f2a9b365da0e0371ef11acbb74cb69d5)/linux-676fd5a6f2a9b365da0e0371ef11acbb74cb69d5.tar.gz"
BR2_LINUX_KERNEL_DEFCONFIG="bcmrpi3"
# Build the DTB from the kernel sources
diff --git a/configs/raspberrypi3_defconfig b/configs/raspberrypi3_defconfig
index f001d8f845..a22589aa2e 100644
--- a/configs/raspberrypi3_defconfig
+++ b/configs/raspberrypi3_defconfig
@@ -11,7 +11,7 @@ BR2_PACKAGE_HOST_LINUX_HEADERS_CUSTOM_4_19=y
BR2_LINUX_KERNEL=y
BR2_LINUX_KERNEL_CUSTOM_TARBALL=y
-BR2_LINUX_KERNEL_CUSTOM_TARBALL_LOCATION="$(call github,raspberrypi,linux,4f2a4cc501c428c940549f39d5562e60404ac4f7)/linux-4f2a4cc501c428c940549f39d5562e60404ac4f7.tar.gz"
+BR2_LINUX_KERNEL_CUSTOM_TARBALL_LOCATION="$(call github,raspberrypi,linux,676fd5a6f2a9b365da0e0371ef11acbb74cb69d5)/linux-676fd5a6f2a9b365da0e0371ef11acbb74cb69d5.tar.gz"
BR2_LINUX_KERNEL_DEFCONFIG="bcm2709"
# Build the DTB from the kernel sources
diff --git a/configs/raspberrypi3_qt5we_defconfig b/configs/raspberrypi3_qt5we_defconfig
index d62e66d08b..3b2e5cd29a 100644
--- a/configs/raspberrypi3_qt5we_defconfig
+++ b/configs/raspberrypi3_qt5we_defconfig
@@ -12,7 +12,7 @@ BR2_PACKAGE_HOST_LINUX_HEADERS_CUSTOM_4_19=y
BR2_LINUX_KERNEL=y
BR2_LINUX_KERNEL_CUSTOM_TARBALL=y
-BR2_LINUX_KERNEL_CUSTOM_TARBALL_LOCATION="$(call github,raspberrypi,linux,4f2a4cc501c428c940549f39d5562e60404ac4f7)/linux-4f2a4cc501c428c940549f39d5562e60404ac4f7.tar.gz"
+BR2_LINUX_KERNEL_CUSTOM_TARBALL_LOCATION="$(call github,raspberrypi,linux,676fd5a6f2a9b365da0e0371ef11acbb74cb69d5)/linux-676fd5a6f2a9b365da0e0371ef11acbb74cb69d5.tar.gz"
BR2_LINUX_KERNEL_DEFCONFIG="bcm2709"
# Build the DTB from the kernel sources
diff --git a/configs/raspberrypi4_64_defconfig b/configs/raspberrypi4_64_defconfig
index 283ef4ba36..d3de09668f 100644
--- a/configs/raspberrypi4_64_defconfig
+++ b/configs/raspberrypi4_64_defconfig
@@ -11,7 +11,7 @@ BR2_PACKAGE_HOST_LINUX_HEADERS_CUSTOM_4_19=y
BR2_LINUX_KERNEL=y
BR2_LINUX_KERNEL_CUSTOM_TARBALL=y
-BR2_LINUX_KERNEL_CUSTOM_TARBALL_LOCATION="$(call github,raspberrypi,linux,4f2a4cc501c428c940549f39d5562e60404ac4f7)/linux-4f2a4cc501c428c940549f39d5562e60404ac4f7.tar.gz"
+BR2_LINUX_KERNEL_CUSTOM_TARBALL_LOCATION="$(call github,raspberrypi,linux,676fd5a6f2a9b365da0e0371ef11acbb74cb69d5)/linux-676fd5a6f2a9b365da0e0371ef11acbb74cb69d5.tar.gz"
BR2_LINUX_KERNEL_DEFCONFIG="bcm2711"
# Build the DTB from the kernel sources
diff --git a/configs/raspberrypi4_defconfig b/configs/raspberrypi4_defconfig
index c4a97f8f3c..943f955ce6 100644
--- a/configs/raspberrypi4_defconfig
+++ b/configs/raspberrypi4_defconfig
@@ -11,7 +11,7 @@ BR2_PACKAGE_HOST_LINUX_HEADERS_CUSTOM_4_19=y
BR2_LINUX_KERNEL=y
BR2_LINUX_KERNEL_CUSTOM_TARBALL=y
-BR2_LINUX_KERNEL_CUSTOM_TARBALL_LOCATION="$(call github,raspberrypi,linux,4f2a4cc501c428c940549f39d5562e60404ac4f7)/linux-4f2a4cc501c428c940549f39d5562e60404ac4f7.tar.gz"
+BR2_LINUX_KERNEL_CUSTOM_TARBALL_LOCATION="$(call github,raspberrypi,linux,676fd5a6f2a9b365da0e0371ef11acbb74cb69d5)/linux-676fd5a6f2a9b365da0e0371ef11acbb74cb69d5.tar.gz"
BR2_LINUX_KERNEL_DEFCONFIG="bcm2711"
# Build the DTB from the kernel sources
diff --git a/configs/raspberrypi_defconfig b/configs/raspberrypi_defconfig
index f07411b2e6..a0c83a5686 100644
--- a/configs/raspberrypi_defconfig
+++ b/configs/raspberrypi_defconfig
@@ -11,7 +11,7 @@ BR2_TOOLCHAIN_BUILDROOT_CXX=y
BR2_LINUX_KERNEL=y
BR2_LINUX_KERNEL_CUSTOM_TARBALL=y
-BR2_LINUX_KERNEL_CUSTOM_TARBALL_LOCATION="$(call github,raspberrypi,linux,4f2a4cc501c428c940549f39d5562e60404ac4f7)/linux-4f2a4cc501c428c940549f39d5562e60404ac4f7.tar.gz"
+BR2_LINUX_KERNEL_CUSTOM_TARBALL_LOCATION="$(call github,raspberrypi,linux,676fd5a6f2a9b365da0e0371ef11acbb74cb69d5)/linux-676fd5a6f2a9b365da0e0371ef11acbb74cb69d5.tar.gz"
BR2_LINUX_KERNEL_DEFCONFIG="bcmrpi"
# Build the DTBs for A/B, A+/B+ and compute module from the kernel sources
--
2.26.2
^ permalink raw reply related
* [Intel-gfx] ✗ Fi.CI.CHECKPATCH: warning for series starting with [1/3] drm/dp_mst: Fix the DDC I2C device unregistration of an MST port
From: Patchwork @ 2020-06-07 21:59 UTC (permalink / raw)
To: Imre Deak; +Cc: intel-gfx
In-Reply-To: <20200607212522.16935-1-imre.deak@intel.com>
== Series Details ==
Series: series starting with [1/3] drm/dp_mst: Fix the DDC I2C device unregistration of an MST port
URL : https://patchwork.freedesktop.org/series/78100/
State : warning
== Summary ==
$ dim checkpatch origin/drm-tip
be4cb6213842 drm/dp_mst: Fix the DDC I2C device unregistration of an MST port
-:13: WARNING:COMMIT_LOG_LONG_LINE: Possible unwrapped commit description (prefer a maximum 75 chars per line)
#13:
Note that atm, inconsistently, the parent of the I2C device is initially set to
total: 0 errors, 1 warnings, 0 checks, 14 lines checked
f183ac475a8b drm/dp_mst: Fix the DDC I2C device registration of an MST port
c3019da98129 drm/dp_mst: Fix flushing the delayed port/mstb destroy work
-:45: CHECK:COMPARISON_TO_NULL: Comparison to NULL could be written "!mgr->delayed_destroy_wq"
#45: FILE: drivers/gpu/drm/drm_dp_mst_topology.c:5191:
+ if (mgr->delayed_destroy_wq == NULL)
total: 0 errors, 0 warnings, 1 checks, 55 lines checked
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx
^ permalink raw reply
* [PATCH] kunit: kunit_config: Fix parsing of CONFIG options with space
From: Rikard Falkeborn @ 2020-06-07 21:57 UTC (permalink / raw)
To: linux-kselftest; +Cc: brendanhiggins, masahiroy, linux-kernel, Rikard Falkeborn
Commit 8b59cd81dc5e ("kbuild: ensure full rebuild when the compiler is
updated") introduced a new CONFIG option CONFIG_CC_VERSION_TEXT. On my
system, this is set to "gcc (GCC) 10.1.0" which breaks KUnit config
parsing which did not like the spaces in the string.
Fix this by updating the regex to allow strings containing spaces.
Fixes: 8b59cd81dc5e ("kbuild: ensure full rebuild when the compiler is updated")
Signed-off-by: Rikard Falkeborn <rikard.falkeborn@gmail.com>
---
Maybe it would have been sufficient to just use
CONFIG_PATTERN = r'^CONFIG_(\w+)=(.*)$' instead?
tools/testing/kunit/kunit_config.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/tools/testing/kunit/kunit_config.py b/tools/testing/kunit/kunit_config.py
index e75063d603b5..02ffc3a3e5dc 100644
--- a/tools/testing/kunit/kunit_config.py
+++ b/tools/testing/kunit/kunit_config.py
@@ -10,7 +10,7 @@ import collections
import re
CONFIG_IS_NOT_SET_PATTERN = r'^# CONFIG_(\w+) is not set$'
-CONFIG_PATTERN = r'^CONFIG_(\w+)=(\S+)$'
+CONFIG_PATTERN = r'^CONFIG_(\w+)=(\S+|".*")$'
KconfigEntryBase = collections.namedtuple('KconfigEntry', ['name', 'value'])
--
2.27.0
^ permalink raw reply related
* Re: packed structures used in socket options
From: Michael Tuexen @ 2020-06-07 21:55 UTC (permalink / raw)
To: linux-sctp
In-Reply-To: <CBFEFEF1-127A-4ADA-B438-B171B9E26282@lurchi.franken.de>
On 7. Jun 2020, at 23:35, Ivan Skytte Jørgensen <isj-sctp@i1.dk> wrote:
>
> On Sunday, 7 June 2020 22:21:41 CEST you wrote:
>> From: Michael Tuexen
>>> Sent: 07 June 2020 18:24
>>>> On 7. Jun 2020, at 19:14, David Laight <David.Laight@ACULAB.COM> wrote:
>>>>
>>>> From: Michael Tuexen <Michael.Tuexen@lurchi.franken.de>
>>>>> Sent: 07 June 2020 16:15
>>>>>> On 7. Jun 2020, at 15:53, David Laight <David.Laight@ACULAB.COM> wrote:
>>>>>>
>>>>>> From: Michael Tuexen
>>>>>>>
>>>>>>> since gcc uses -Werrordress-of-packed-member, I get warnings for my variant
>>>>>>> of packetdrill, which supports SCTP.
>>>>>>>
>>>>>>> Here is why:
>>>>>>>
>>>>>>>
>>>>>
>>> https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/include/uapi/linux/sctp.h?h=v5
>>>>>>> .7
>>>>>>> contains:
>>>>>>>
>>>>>>> struct sctp_paddrparams {
>>>>>>> sctp_assoc_t spp_assoc_id;
>>>>>>> struct sockaddr_storage spp_address;
>>>>>>> __u32 spp_hbinterval;
>>>>>>> __u16 spp_pathmaxrxt;
>>>>>>> __u32 spp_pathmtu;
>>>>>>> __u32 spp_sackdelay;
>>>>>>> __u32 spp_flags;
>>>>>>> __u32 spp_ipv6_flowlabel;
>>>>>>> __u8 spp_dscp;
>>>>>>> } __attribute__((packed, aligned(4)));
>>>>>>>
>>>>>>> This structure is only used in the IPPROTO_SCTP level socket option SCTP_PEER_ADDR_PARAMS.
>>>>>>> Why is it packed?
>>>>>>
>>>>>> I'm guessing 'to remove holes to avoid leaking kernel data'.
>>>>>>
>>>>>> The sctp socket api defines loads of structures that will have
>>>>>> holes in them if not packed.
>>>>>
>>>>> Hi David,
>>>>> I agree that they have holes and we should have done better. The
>>>>> kernel definitely should also not leak kernel data. However, the
>>>>> way to handle this shouldn't be packing. I guess it is too late
>>>>> to change this?
>>>>
>>>> Probably too late.
>>>> I've no idea how it got through the standards body either.
>>>> In fact, the standard may actually require the holes.
>>>
>>> No, it does not. Avoiding holes was not taken into account.
>>
>> It depends on whether the rfc that describes the sockops says
>> the structures 'look like this' or 'contain the following members'.
>>
>>> It should have been, but this was missed. Authors of all
>>> kernel implementation (FreeBSD, Linux, and Solaris) were involved.
>>
>> Sounds like none of the right people even looked at it.
>
> I was involved. At that time (September 2005) the SCTP API was still evolving (first finalized in 2011), and one of the major users of the API was 32-bit programs running on 64-bit kernel (on powerpc as I recall). When we realized that the structures were different between 32bit and 64bit we had to break the least number of programs, and the result were those ((packed)) structs so 32-bit programs wouldn't be broken and we didn't need a xxx_compat translation layer in the kernel.
Ahh, I see. Thanks for the explanation.
>
> I don't have access to TSVWG mailing list archive that far back but I found I wrote this summary here:
>
> On Sunday, 25 September 2005 21:36:05 CEST Ivan Skytte Jørgensen wrote:
>> I followed the discussion in tsvwg mailing list. My interpretation of the few
>> answers is that this is a "quality of implementation issue" and that padding
>> fields are allowed but won't get into the RFC because it is an implementation
>> issue.
>
>
> So RFC6458 allows padding but doesn't list them.
Yepp, that is my understanding (being a co-author).
>
>
> Incidentally, at that time (and perhaps still) sockaddr_storage had different alignement between 32-bit programs and 64-bit programs, and the multicast structures used in setsockopt() (group_req, group_source_req and group_filter) had/has the same problem.
If I remember it correctly, I tested (FreeBSD) stuff on Little Endian, Big Endian, 32-bit, 64-bit, but not
run one binary on another platform.
Best regards
Michael
>
>
> /isj
>
>
>
^ permalink raw reply
* [PATCH 2/2] irqchip: vic: Cut down the external API
From: Linus Walleij @ 2020-06-07 21:51 UTC (permalink / raw)
To: Thomas Gleixner, Marc Zyngier, Jason Cooper; +Cc: linux-kernel, Linus Walleij
In-Reply-To: <20200607215124.48638-1-linus.walleij@linaro.org>
There are registers and functions in the header file
that are only used inside the driver. Move these into
the driver.
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
---
drivers/irqchip/irq-vic.c | 5 ++++-
include/linux/irqchip/arm-vic.h | 9 ---------
2 files changed, 4 insertions(+), 10 deletions(-)
diff --git a/drivers/irqchip/irq-vic.c b/drivers/irqchip/irq-vic.c
index 927ff2c1bf67..bc235db8a4c5 100644
--- a/drivers/irqchip/irq-vic.c
+++ b/drivers/irqchip/irq-vic.c
@@ -27,7 +27,10 @@
#define VIC_IRQ_STATUS 0x00
#define VIC_FIQ_STATUS 0x04
+#define VIC_RAW_STATUS 0x08
#define VIC_INT_SELECT 0x0c /* 1 = FIQ, 0 = IRQ */
+#define VIC_INT_ENABLE 0x10 /* 1 = enable, 0 = disable */
+#define VIC_INT_ENABLE_CLEAR 0x14
#define VIC_INT_SOFT 0x18
#define VIC_INT_SOFT_CLEAR 0x1c
#define VIC_PROTECT 0x20
@@ -428,7 +431,7 @@ static void __init vic_init_st(void __iomem *base, unsigned int irq_start,
vic_register(base, 0, irq_start, vic_sources, 0, node);
}
-void __init __vic_init(void __iomem *base, int parent_irq, int irq_start,
+static void __init __vic_init(void __iomem *base, int parent_irq, int irq_start,
u32 vic_sources, u32 resume_sources,
struct device_node *node)
{
diff --git a/include/linux/irqchip/arm-vic.h b/include/linux/irqchip/arm-vic.h
index 2a4b6a5d8522..f2b11d1df23d 100644
--- a/include/linux/irqchip/arm-vic.h
+++ b/include/linux/irqchip/arm-vic.h
@@ -9,15 +9,6 @@
#include <linux/types.h>
-#define VIC_RAW_STATUS 0x08
-#define VIC_INT_ENABLE 0x10 /* 1 = enable, 0 = disable */
-#define VIC_INT_ENABLE_CLEAR 0x14
-
-struct device_node;
-struct pt_regs;
-
-void __vic_init(void __iomem *base, int parent_irq, int irq_start,
- u32 vic_sources, u32 resume_sources, struct device_node *node);
void vic_init(void __iomem *base, unsigned int irq_start, u32 vic_sources, u32 resume_sources);
#endif
--
2.25.4
^ permalink raw reply related
* [PATCH 1/2] irqchip: vic: Drop cascaded intialization call
From: Linus Walleij @ 2020-06-07 21:51 UTC (permalink / raw)
To: Thomas Gleixner, Marc Zyngier, Jason Cooper; +Cc: linux-kernel, Linus Walleij
We got rid of the last user of the cascaded intialization
from board files so drop this API.
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
---
drivers/irqchip/irq-vic.c | 21 ---------------------
include/linux/irqchip/arm-vic.h | 2 --
2 files changed, 23 deletions(-)
diff --git a/drivers/irqchip/irq-vic.c b/drivers/irqchip/irq-vic.c
index 3c87d925f74c..927ff2c1bf67 100644
--- a/drivers/irqchip/irq-vic.c
+++ b/drivers/irqchip/irq-vic.c
@@ -481,27 +481,6 @@ void __init vic_init(void __iomem *base, unsigned int irq_start,
__vic_init(base, 0, irq_start, vic_sources, resume_sources, NULL);
}
-/**
- * vic_init_cascaded() - initialise a cascaded vectored interrupt controller
- * @base: iomem base address
- * @parent_irq: the parent IRQ we're cascaded off
- * @vic_sources: bitmask of interrupt sources to allow
- * @resume_sources: bitmask of interrupt sources to allow for resume
- *
- * This returns the base for the new interrupts or negative on error.
- */
-int __init vic_init_cascaded(void __iomem *base, unsigned int parent_irq,
- u32 vic_sources, u32 resume_sources)
-{
- struct vic_device *v;
-
- v = &vic_devices[vic_id];
- __vic_init(base, parent_irq, 0, vic_sources, resume_sources, NULL);
- /* Return out acquired base */
- return v->irq;
-}
-EXPORT_SYMBOL_GPL(vic_init_cascaded);
-
#ifdef CONFIG_OF
static int __init vic_of_init(struct device_node *node,
struct device_node *parent)
diff --git a/include/linux/irqchip/arm-vic.h b/include/linux/irqchip/arm-vic.h
index a158b97242c7..2a4b6a5d8522 100644
--- a/include/linux/irqchip/arm-vic.h
+++ b/include/linux/irqchip/arm-vic.h
@@ -19,7 +19,5 @@ struct pt_regs;
void __vic_init(void __iomem *base, int parent_irq, int irq_start,
u32 vic_sources, u32 resume_sources, struct device_node *node);
void vic_init(void __iomem *base, unsigned int irq_start, u32 vic_sources, u32 resume_sources);
-int vic_init_cascaded(void __iomem *base, unsigned int parent_irq,
- u32 vic_sources, u32 resume_sources);
#endif
--
2.25.4
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.