drm/nouveau/tmr: type-safe PTIMER-based delay/wait macros
authorBen Skeggs <bskeggs@redhat.com>
Thu, 20 Aug 2015 04:54:10 +0000 (14:54 +1000)
committerBen Skeggs <bskeggs@redhat.com>
Fri, 28 Aug 2015 02:40:19 +0000 (12:40 +1000)
These require an explicit struct nvkm_device pointer, unlike the previous
macros which take a void *, and work for (almost) anything derived from
nvkm_object by using some heuristics.

These macros are more general than the previous ones, and can be used to
handle PTIMER-based busy-waits (will be used in later devinit fixes) as
well as more complicated wait conditions.

Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
drivers/gpu/drm/nouveau/include/nvif/device.h
drivers/gpu/drm/nouveau/include/nvkm/subdev/timer.h
drivers/gpu/drm/nouveau/nouveau_abi16.c
drivers/gpu/drm/nouveau/nvif/device.c
drivers/gpu/drm/nouveau/nvkm/subdev/timer/base.c

index 88553a741ab7f4b84289b8975776ac2885103d49..8bd60dd3b1615cf317bdd2cbbbed0db739e69420 100644 (file)
@@ -25,6 +25,28 @@ void nvif_device_fini(struct nvif_device *);
 int  nvif_device_new(struct nvif_object *, u32 handle, u32 oclass,
                     void *, u32, struct nvif_device **);
 void nvif_device_ref(struct nvif_device *, struct nvif_device **);
+u64  nvif_device_time(struct nvif_device *);
+
+/* Delay based on GPU time (ie. PTIMER).
+ *
+ * Will return -ETIMEDOUT unless the loop was terminated with 'break',
+ * where it will return the number of nanoseconds taken instead.
+ */
+#define nvif_nsec(d,n,cond...) ({                                              \
+       struct nvif_device *_device = (d);                                     \
+       u64 _nsecs = (n), _time0 = nvif_device_time(_device);                  \
+       s64 _taken = 0;                                                        \
+                                                                               \
+       do {                                                                   \
+               cond                                                           \
+       } while (_taken = nvif_device_time(_device) - _time0, _taken < _nsecs);\
+                                                                               \
+       if (_taken >= _nsecs)                                                  \
+               _taken = -ETIMEDOUT;                                           \
+       _taken;                                                                \
+})
+#define nvif_usec(d,u,cond...) nvif_nsec((d), (u) * 1000, ##cond)
+#define nvif_msec(d,m,cond...) nvif_usec((d), (m) * 1000, ##cond)
 
 /*XXX*/
 #include <subdev/bios.h>
index 2c27ce69193905b5b8ebf8b2d3ac3bbfc15b15e0..b26ae6fa5ba7c1bb39709bc6309b14de622e9271 100644 (file)
@@ -16,12 +16,63 @@ nvkm_alarm_init(struct nvkm_alarm *alarm,
        alarm->func = func;
 }
 
-bool nvkm_timer_wait_eq(void *, u64 nsec, u32 addr, u32 mask, u32 data);
-bool nvkm_timer_wait_ne(void *, u64 nsec, u32 addr, u32 mask, u32 data);
-bool nvkm_timer_wait_cb(void *, u64 nsec, bool (*func)(void *), void *data);
 void nvkm_timer_alarm(void *, u32 nsec, struct nvkm_alarm *);
 void nvkm_timer_alarm_cancel(void *, struct nvkm_alarm *);
 
+/* Delay based on GPU time (ie. PTIMER).
+ *
+ * Will return -ETIMEDOUT unless the loop was terminated with 'break',
+ * where it will return the number of nanoseconds taken instead.
+ *
+ * NVKM_DELAY can be passed for 'cond' to disable the timeout warning,
+ * which is useful for unconditional delay loops.
+ */
+#define NVKM_DELAY _warn = false;
+#define nvkm_nsec(d,n,cond...) ({                                              \
+       struct nvkm_device *_device = (d);                                     \
+       struct nvkm_timer *_tmr = _device->timer;                              \
+       u64 _nsecs = (n), _time0 = _tmr->read(_tmr);                           \
+       s64 _taken = 0;                                                        \
+       bool _warn = true;                                                    \
+                                                                               \
+       do {                                                                   \
+               cond                                                           \
+       } while (_taken = _tmr->read(_tmr) - _time0, _taken < _nsecs);         \
+                                                                               \
+       if (_taken >= _nsecs) {                                                \
+               if (_warn) {                                                   \
+                       dev_warn(_device->dev, "timeout at %s:%d/%s()!\n",     \
+                                __FILE__, __LINE__, __func__);                \
+               }                                                              \
+               _taken = -ETIMEDOUT;                                           \
+       }                                                                      \
+       _taken;                                                                \
+})
+#define nvkm_usec(d,u,cond...) nvkm_nsec((d), (u) * 1000, ##cond)
+#define nvkm_msec(d,m,cond...) nvkm_usec((d), (m) * 1000, ##cond)
+
+#define nvkm_timer_wait_eq(o,n,a,m,v) ({                                       \
+       struct nvkm_device *__device = nv_device(o);                           \
+       nvkm_nsec(__device, (n),                                               \
+               if ((nvkm_rd32(__device, (a)) & (m)) == (v))                   \
+                       break;                                                 \
+       ) >= 0;                                                                \
+})
+#define nvkm_timer_wait_ne(o,n,a,m,v) ({                                       \
+       struct nvkm_device *__device = nv_device(o);                           \
+       nvkm_nsec(__device, (n),                                               \
+               if ((nvkm_rd32(__device, (a)) & (m)) != (v))                   \
+                       break;                                                 \
+       ) >= 0;                                                                \
+})
+#define nvkm_timer_wait_cb(o,n,c,d) ({                                         \
+       struct nvkm_device *__device = nv_device(o);                           \
+       nvkm_nsec(__device, (n),                                               \
+               if (c(d))                                                      \
+                       break;                                                 \
+       ) >= 0;                                                                \
+})
+
 #define NV_WAIT_DEFAULT 2000000000ULL
 #define nv_wait(o,a,m,v)                                                       \
        nvkm_timer_wait_eq((o), NV_WAIT_DEFAULT, (a), (m), (v))
index 1bdde99155a0b8f20588f4f1e6470f4a03504f9d..c2ba0cc1521f64ccad788a92052d610e0c251e76 100644 (file)
@@ -164,7 +164,6 @@ nouveau_abi16_ioctl_getparam(ABI16_IOCTL_ARGS)
        struct nouveau_cli *cli = nouveau_cli(file_priv);
        struct nouveau_drm *drm = nouveau_drm(dev);
        struct nvif_device *device = &drm->device;
-       struct nvkm_timer *tmr = nvxx_timer(device);
        struct nvkm_gr *gr = nvxx_gr(device);
        struct drm_nouveau_getparam *getparam = data;
 
@@ -206,7 +205,7 @@ nouveau_abi16_ioctl_getparam(ABI16_IOCTL_ARGS)
                getparam->value = 0; /* deprecated */
                break;
        case NOUVEAU_GETPARAM_PTIMER_TIME:
-               getparam->value = tmr->read(tmr);
+               getparam->value = nvif_device_time(device);
                break;
        case NOUVEAU_GETPARAM_HAS_BO_USAGE:
                getparam->value = 1;
index 6f72244c52cd89294c241d2e8d2ff5aaa764970d..837442c69a5d2e31d7a152e1e5a5b7126872d0c2 100644 (file)
 
 #include <nvif/device.h>
 
+u64
+nvif_device_time(struct nvif_device *device)
+{
+       return nvxx_timer(device)->read(nvxx_timer(device));
+}
+
 void
 nvif_device_fini(struct nvif_device *device)
 {
index c59b2353683b8c1be99fc847450781378c967fec..4c34e2bd0487db63d0ba2cad83ad1c4f689eccad 100644 (file)
  */
 #include <subdev/timer.h>
 
-bool
-nvkm_timer_wait_eq(void *obj, u64 nsec, u32 addr, u32 mask, u32 data)
-{
-       struct nvkm_timer *ptimer = nvkm_timer(obj);
-       struct nvkm_device *device = ptimer->subdev.device;
-       u64 time0;
-
-       time0 = ptimer->read(ptimer);
-       do {
-               if (nv_iclass(obj, NV_SUBDEV_CLASS)) {
-                       if ((nvkm_rd32(device, addr) & mask) == data)
-                               return true;
-               } else {
-                       if ((nv_ro32(obj, addr) & mask) == data)
-                               return true;
-               }
-       } while (ptimer->read(ptimer) - time0 < nsec);
-
-       return false;
-}
-
-bool
-nvkm_timer_wait_ne(void *obj, u64 nsec, u32 addr, u32 mask, u32 data)
-{
-       struct nvkm_timer *ptimer = nvkm_timer(obj);
-       struct nvkm_device *device = ptimer->subdev.device;
-       u64 time0;
-
-       time0 = ptimer->read(ptimer);
-       do {
-               if (nv_iclass(obj, NV_SUBDEV_CLASS)) {
-                       if ((nvkm_rd32(device, addr) & mask) != data)
-                               return true;
-               } else {
-                       if ((nv_ro32(obj, addr) & mask) != data)
-                               return true;
-               }
-       } while (ptimer->read(ptimer) - time0 < nsec);
-
-       return false;
-}
-
-bool
-nvkm_timer_wait_cb(void *obj, u64 nsec, bool (*func)(void *), void *data)
-{
-       struct nvkm_timer *ptimer = nvkm_timer(obj);
-       u64 time0;
-
-       time0 = ptimer->read(ptimer);
-       do {
-               if (func(data) == true)
-                       return true;
-       } while (ptimer->read(ptimer) - time0 < nsec);
-
-       return false;
-}
-
 void
 nvkm_timer_alarm(void *obj, u32 nsec, struct nvkm_alarm *alarm)
 {