aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBen Skeggs <bskeggs@redhat.com>2015-08-20 14:54:10 +1000
committerBen Skeggs <bskeggs@redhat.com>2015-08-28 12:40:19 +1000
commit56f67dc19623b6cd4db57ee07d6f0cad32bcd5af (patch)
tree55f4b766376d59272fab0df9b1682a21a5e3f1f0
parent2ebfa1bc6ff1a7cded8b662f507d34574ffcc2c6 (diff)
downloadlinux-stericsson-56f67dc19623b6cd4db57ee07d6f0cad32bcd5af.tar.gz
drm/nouveau/tmr: type-safe PTIMER-based delay/wait macros
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>
-rw-r--r--drivers/gpu/drm/nouveau/include/nvif/device.h22
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/subdev/timer.h57
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_abi16.c3
-rw-r--r--drivers/gpu/drm/nouveau/nvif/device.c6
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/timer/base.c57
5 files changed, 83 insertions, 62 deletions
diff --git a/drivers/gpu/drm/nouveau/include/nvif/device.h b/drivers/gpu/drm/nouveau/include/nvif/device.h
index 88553a741ab7..8bd60dd3b161 100644
--- a/drivers/gpu/drm/nouveau/include/nvif/device.h
+++ b/drivers/gpu/drm/nouveau/include/nvif/device.h
@@ -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>
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/timer.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/timer.h
index 2c27ce691939..b26ae6fa5ba7 100644
--- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/timer.h
+++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/timer.h
@@ -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))
diff --git a/drivers/gpu/drm/nouveau/nouveau_abi16.c b/drivers/gpu/drm/nouveau/nouveau_abi16.c
index 1bdde99155a0..c2ba0cc1521f 100644
--- a/drivers/gpu/drm/nouveau/nouveau_abi16.c
+++ b/drivers/gpu/drm/nouveau/nouveau_abi16.c
@@ -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;
diff --git a/drivers/gpu/drm/nouveau/nvif/device.c b/drivers/gpu/drm/nouveau/nvif/device.c
index 6f72244c52cd..837442c69a5d 100644
--- a/drivers/gpu/drm/nouveau/nvif/device.c
+++ b/drivers/gpu/drm/nouveau/nvif/device.c
@@ -24,6 +24,12 @@
#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)
{
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/timer/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/timer/base.c
index c59b2353683b..4c34e2bd0487 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/timer/base.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/timer/base.c
@@ -23,63 +23,6 @@
*/
#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)
{