drm/etnaviv: make it possible to allocate multiple events
authorChristian Gmeiner <christian.gmeiner@gmail.com>
Sun, 24 Sep 2017 13:15:20 +0000 (15:15 +0200)
committerLucas Stach <l.stach@pengutronix.de>
Tue, 10 Oct 2017 09:45:40 +0000 (11:45 +0200)
This makes it possible to allocate multiple events under the event
spinlock. This change is needed to support 'sync'-points.

Changes v2 -> v3:
- wait for the completion of all events
- use 10sec timeout regardless of the number of events
- removed validation if there are enough free events
- fixed return value evaluation of event_alloc(..) in etnaviv_gpu_submit(..)

Signed-off-by: Christian Gmeiner <christian.gmeiner@gmail.com>
Signed-off-by: Lucas Stach <l.stach@pengutronix.de>
drivers/gpu/drm/etnaviv/etnaviv_gpu.c

index 3b02814b9c525f242ada93a1e4ffacc0d6441f53..8d961bc238d4faa69687ef74f958c28ee354a63f 100644 (file)
@@ -1142,28 +1142,44 @@ int etnaviv_gpu_fence_sync_obj(struct etnaviv_gem_object *etnaviv_obj,
  * event management:
  */
 
-static unsigned int event_alloc(struct etnaviv_gpu *gpu)
+static int event_alloc(struct etnaviv_gpu *gpu, unsigned nr_events,
+       unsigned int *events)
 {
-       unsigned long ret, flags;
-       unsigned int event;
+       unsigned long flags, timeout = msecs_to_jiffies(10 * 10000);
+       unsigned i, acquired = 0;
 
-       ret = wait_for_completion_timeout(&gpu->event_free,
-                                         msecs_to_jiffies(10 * 10000));
-       if (!ret)
-               dev_err(gpu->dev, "wait_for_completion_timeout failed");
+       for (i = 0; i < nr_events; i++) {
+               unsigned long ret;
+
+               ret = wait_for_completion_timeout(&gpu->event_free, timeout);
+
+               if (!ret) {
+                       dev_err(gpu->dev, "wait_for_completion_timeout failed");
+                       goto out;
+               }
+
+               acquired++;
+               timeout = ret;
+       }
 
        spin_lock_irqsave(&gpu->event_spinlock, flags);
 
-       /* find first free event */
-       event = find_first_zero_bit(gpu->event_bitmap, ETNA_NR_EVENTS);
-       if (event < ETNA_NR_EVENTS)
+       for (i = 0; i < nr_events; i++) {
+               int event = find_first_zero_bit(gpu->event_bitmap, ETNA_NR_EVENTS);
+
+               events[i] = event;
                set_bit(event, gpu->event_bitmap);
-       else
-               event = ~0U;
+       }
 
        spin_unlock_irqrestore(&gpu->event_spinlock, flags);
 
-       return event;
+       return 0;
+
+out:
+       for (i = 0; i < acquired; i++)
+               complete(&gpu->event_free);
+
+       return -EBUSY;
 }
 
 static void event_free(struct etnaviv_gpu *gpu, unsigned int event)
@@ -1332,10 +1348,9 @@ int etnaviv_gpu_submit(struct etnaviv_gpu *gpu,
         *
         */
 
-       event = event_alloc(gpu);
-       if (unlikely(event == ~0U)) {
+       ret = event_alloc(gpu, 1, &event);
+       if (ret) {
                DRM_ERROR("no free event\n");
-               ret = -EBUSY;
                goto out_pm_put;
        }