[PATCH RFC 061/111] staging: etnaviv: ensure that we retire all pending events

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



From: Russell King <rmk+kernel@xxxxxxxxxxxxxxxx>

If we queue up multiple buffers, each with their own event, where the
first buffer takes a while to execute, but subsequent buffers do not,
we can end up receiving multiple events simultaneously.  (eg, 0, 1, 2).

In this case, we only look at event 2, which updates the last fence,
and then free event 2, leaving events 0 and 1 still allocated.  If this
is allowed to continue, eventually we consume all events, and we have
no further way to progress.

However, we have to bear in mind that we could end up with events in
other orders.  For example, we could have three buffers committed at
different times:

- buffer 0 is committed, getting event 0.
- buffer 1 is committed, getting event 1.
- buffer 0 completes, signalling event 0.
- we process event 0, and freeing it.
- buffer 2 is committed, is small, getting event 0.
- buffer 1 completes, signalling event 1.
- buffer 2 completes, signalling event 0 as well.
- we process both event 0 and event 1.  We must note that the fence from
  event 0 completed, and must not overwrite it with the fence from event 1.

Signed-off-by: Russell King <rmk+kernel@xxxxxxxxxxxxxxxx>
---
 drivers/staging/etnaviv/etnaviv_gpu.c | 31 +++++++++++++++++++++++++------
 1 file changed, 25 insertions(+), 6 deletions(-)

diff --git a/drivers/staging/etnaviv/etnaviv_gpu.c b/drivers/staging/etnaviv/etnaviv_gpu.c
index cd308976dec9..4cd84740eac8 100644
--- a/drivers/staging/etnaviv/etnaviv_gpu.c
+++ b/drivers/staging/etnaviv/etnaviv_gpu.c
@@ -891,20 +891,39 @@ static irqreturn_t irq_handler(int irq, void *data)
 	u32 intr = gpu_read(gpu, VIVS_HI_INTR_ACKNOWLEDGE);
 
 	if (intr != 0) {
+		int event;
+
 		dev_dbg(gpu->dev, "intr 0x%08x\n", intr);
 
-		if (intr & VIVS_HI_INTR_ACKNOWLEDGE_AXI_BUS_ERROR)
+		if (intr & VIVS_HI_INTR_ACKNOWLEDGE_AXI_BUS_ERROR) {
 			dev_err(gpu->dev, "AXI bus error\n");
-		else {
-			uint8_t event = __fls(intr);
+			intr &= ~VIVS_HI_INTR_ACKNOWLEDGE_AXI_BUS_ERROR;
+		}
+
+		while ((event = ffs(intr)) != 0) {
+			event -= 1;
+
+			intr &= ~(1 << event);
 
 			dev_dbg(gpu->dev, "event %u\n", event);
-			gpu->retired_fence = gpu->event[event].fence;
-			gpu->last_ring_pos = gpu->event[event].ring_pos;
+			/*
+			 * Events can be processed out of order.  Eg,
+			 * - allocate and queue event 0
+			 * - allocate event 1
+			 * - event 0 completes, we process it
+			 * - allocate and queue event 0
+			 * - event 1 and event 0 complete
+			 * we can end up processing event 0 first, then 1.
+			 */
+			if (fence_after(gpu->event[event].fence, gpu->retired_fence)) {
+				gpu->retired_fence = gpu->event[event].fence;
+				gpu->last_ring_pos = gpu->event[event].ring_pos;
+			}
 			event_free(gpu, event);
-			etnaviv_gpu_retire(gpu);
 		}
 
+		etnaviv_gpu_retire(gpu);
+
 		ret = IRQ_HANDLED;
 	}
 
-- 
2.1.4

_______________________________________________
dri-devel mailing list
dri-devel@xxxxxxxxxxxxxxxxxxxxx
http://lists.freedesktop.org/mailman/listinfo/dri-devel





[Index of Archives]     [Linux DRI Users]     [Linux Intel Graphics]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [XFree86]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [XFree86]
  Powered by Linux