From 56f67dc19623b6cd4db57ee07d6f0cad32bcd5af Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:10 +1000 Subject: [PATCH] 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 --- drivers/gpu/drm/nouveau/include/nvif/device.h | 22 +++++++ .../drm/nouveau/include/nvkm/subdev/timer.h | 57 ++++++++++++++++++- drivers/gpu/drm/nouveau/nouveau_abi16.c | 3 +- drivers/gpu/drm/nouveau/nvif/device.c | 6 ++ .../gpu/drm/nouveau/nvkm/subdev/timer/base.c | 57 ------------------- 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 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 +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 -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) { -- 2.34.1